From 9712eedf5adc5acc564d6d647ced80cfc6abad3f Mon Sep 17 00:00:00 2001 From: J980419xq <1908393204@qq.com> Date: Mon, 25 Apr 2022 20:06:07 -0700 Subject: [PATCH 01/44] docker --- mininet/mininet/lxc_container.py | 54 ++++++++++---- .../playbooks/configure-lxd-no-clustering.yml | 41 ++--------- .../provision/playbooks/install-lxd.yml | 71 +++++++++++-------- setup.py | 2 +- 4 files changed, 90 insertions(+), 78 deletions(-) diff --git a/mininet/mininet/lxc_container.py b/mininet/mininet/lxc_container.py index 933e8c74..58c0719f 100644 --- a/mininet/mininet/lxc_container.py +++ b/mininet/mininet/lxc_container.py @@ -204,11 +204,12 @@ def configureContainer(self, adminbr="admin-br", wait=True): cmds = [] # configure the container to have # an admin IP address - cmds.append("lxc exec {} -- ifconfig admin {}".format(self.name, self.admin_ip)) + #cmds.append("lxc exec {} -- ifconfig admin {}".format(self.name, self.admin_ip)) + #cmds.append("docker exec -it {} ifconfig eth0 {}".format(self.name, self.admin_ip)) + cmds.append("{}=$(docker inspect -f '{{{{.State.Pid}}}}' {})".format(self.name,self.name)) + cmds.append("ip netns exec ${} ip addr add {} dev admin".format(self.name,self.admin_ip)) # a public key - cmds.append("lxc exec {} -- bash -c 'echo \"{}\" >> /root/.ssh/authorized_keys'".format(self.name, self.pub_id)) - # a ssh server - cmds.append("lxc exec {} -- service ssh start".format(self.name)) + #cmds.append("lxc exec {} -- bash -c 'echo \"{}\" >> /root/.ssh/authorized_keys'".format(self.name, self.pub_id)) cmd = ';'.join(cmds) if wait: @@ -224,8 +225,8 @@ def createMasterAdminNetwork(cls, master, brname="admin-br", ip="192.168.42.1/24 cmd = ";".join(cmds) master.cmd(cmd) - import re + import re def _findNameIP(self, name): """ Resolves name to IP as seen by the eyeball @@ -312,6 +313,8 @@ def connectToAdminNetwork(self, master, target, link_id, admin_br, wait=True, ** # locally # DSA - TODO - XXX beurk bridge2 = None cmds = self.createContainerLinkCommandList(target, master, link_id, vxlan_name, bridge1=admin_br, bridge2=None) + #if target!=master: + # cmds.append("ifconfig admin_br {}".format(self.admin_ip)) cmd = ';'.join(cmds) if wait: @@ -343,18 +346,31 @@ def createContainer(self, **params): info ("create container ({} {} {}) ".format(self.image, self.cpu, self.memory)) cmds = [] # initialise the container - cmd = "lxc init {} {} < /dev/null ".format(self.image, self.name) + #cmd = "lxc init {} {} < /dev/null ".format(self.image, self.name) + cmd = "docker run --privileged -itd --name {} --net=none {}".format(self.name, self.image) info ("{}\n".format(cmd)) cmds.append(cmd) # limit resources if self.cpu: - cmds.append("lxc config set {} limits.cpu {}".format(self.name, self.cpu)) + #cmds.append("lxc config set {} limits.cpu {}".format(self.name, self.cpu)) + cmds.append("docker container update --cpuset-cpus={} {}".format(self.cpu, self.name)) if self.memory: - cmds.append("lxc config set {} limits.memory {}".format(self.name, self.memory)) + #cmds.append("lxc config set {} limits.memory {}".format(self.name, self.memory)) + cmds.append("docker container update -m {} {}".format(self.memory, self.name)) # start the container - cmds.append("lxc start {}".format(self.name)) + #cmds.append("lxc start {}".format(self.name)) + cmds.append("docker start {}".format(self.name)) + if self.image=="switch": + cmds.append("docker exec {} bash -c 'export PATH=$PATH:/usr/local/share/openvswitch/scripts;ovs-ctl start'".format(self.name)) + cmds.append("docker exec {} mkdir /root/.ssh".format(self.name)) + cmds.append("docker exec {} bash -c 'echo \"{}\" >> /root/.ssh/authorized_keys'".format(self.name, self.pub_id)) + # a ssh server + #cmds.append("lxc exec {} -- service ssh start".format(self.name)) + cmds.append("docker exec -itd {} service ssh start".format(self.name)) + + cmd = ";".join(cmds) self.targetSsh.sendCmd(cmd) @@ -382,9 +398,22 @@ def addContainerInterface(self, intfName, devicename=None, brname=None, wait=Tru brname = genIntfName() cmds = [] cmds.append("brctl addbr {}".format(brname)) - cmds.append("lxc network attach {} {} {} {}".format(brname, self.name, devicename, intfName)) + cmds.append("ip link add {} type veth peer name {}".format("veth"+devicename,devicename)) + cmds.append("brctl addif {} {}".format(brname,devicename)) + cmds.append("ip link set up {}".format(devicename)) + cmds.append("{}=$(docker inspect -f '{{{{.State.Pid}}}}' {})".format(self.name,self.name)) + cmds.append("ln -s /proc/{}/ns/net /var/run/netns/${}".format("$"+self.name,self.name)) + cmds.append("ip link set {} netns ${}".format("veth"+devicename,self.name)) + cmds.append("ip netns exec ${} ip link set dev {} name {}".format(self.name,"veth"+devicename,intfName)) + cmds.append("ip netns exec ${} ip link set {} up".format(self.name,intfName)) + #cmds.append("lxc network attach {} {} {} {}".format(brname, self.name, devicename, intfName)) + #cmds.append("lxc network attach {} {} {} {}".format(brname, self.name, devicename, intfName)) + #cmds.append("docker network connect {} {}".format(brname, container_id)) + #cmds.append("docker network create -d bridge {} -o com.docker.network.bridge.name={}".format(brname, brname)) + #cmds.append("docker network connect {} {}".format(brname, self.name)) cmds.append("ip link set up {}".format(brname)) - + cmds.append("iptables -A FORWARD -o {} -j ACCEPT".format(brname)) + cmds.append("iptables -A FORWARD -i {} -j ACCEPT".format(brname)) cmd = ";".join(cmds) if wait: @@ -517,7 +546,8 @@ def terminate( self ): cmds = [] # destroy the container - cmds.append("lxc delete {} --force".format(self.name)) + #cmds.append("lxc delete {} --force".format(self.name)) + cmds.append("docker rm -f {}".format(self.name)) # remove all locally made devices for device in self.devices: diff --git a/mininet/mininet/provision/playbooks/configure-lxd-no-clustering.yml b/mininet/mininet/provision/playbooks/configure-lxd-no-clustering.yml index cf1a47c9..d3c284a3 100644 --- a/mininet/mininet/provision/playbooks/configure-lxd-no-clustering.yml +++ b/mininet/mininet/provision/playbooks/configure-lxd-no-clustering.yml @@ -1,44 +1,16 @@ --- - -- hosts : all - remote_user: root - tasks : - - name : lxd configuration - expect: - echo : yes - command : lxd init - timeout : 20 - responses: - (?i)Would you like to use LXD clustering? : "no" - (?i)Do you want to configure a new storage pool? : "yes" - (?i)Name of the new storage pool : "default" - (?i)Name of the storage backend to use : "zfs" - (?i)Create a new BTRFS pool? : "yes" - (?i)Create a new ZFS pool : "yes" - (?i)Would you like to use an existing block device? : "no" - (?i)Would you like to use an existing empty block device : "no" - (?i)Would you like to connect to a MAAS server? : "no" - (?i)Size in GB of the new loop device : "15GB" - (?i)Would you like to configure LXD to use an existing bridge or host interface?: "no" - (?i)Would you like to create a new local network bridge? : "no" - (?i)Would you like LXD to be available over the network : "no" - (?i)Would you like the LXD server to be available over the network : "no" - (?i)Would you like stale cached images to be updated automatically? : "no" - (?i)Would you like a YAML : "no" - - - hosts : all remote_user: root tasks : - name : distribute switch image copy : - src : ~/switch.tar.gz - dest : ~/switch.tar.gz + src : ~/switch.tar + dest : ~/switch.tar - name : distribute ubuntu image copy : - src : ~/ubuntu.tar.gz - dest : ~/ubuntu.tar.gz + src : ~/ubuntu.tar + dest : ~/ubuntu.tar # - name : distribute debian image # copy : @@ -65,11 +37,10 @@ remote_user: root tasks : - name : create switch image - command: lxc image import ~/switch.tar.gz --alias switch --public + command: docker load -i ~/switch.tar - name : create ubuntu18.04 image -- alias ubuntu - command: lxc image import ~/ubuntu.tar.gz --alias ubuntu --public - + command: docker load -i ~/ubuntu.tar # - name : create debian10 image -- alias debian # command: lxc image import ~/debian.tar.gz --alias debian --public diff --git a/mininet/mininet/provision/playbooks/install-lxd.yml b/mininet/mininet/provision/playbooks/install-lxd.yml index cb19c264..28f2bf53 100644 --- a/mininet/mininet/provision/playbooks/install-lxd.yml +++ b/mininet/mininet/provision/playbooks/install-lxd.yml @@ -1,27 +1,3 @@ ---- -# -- hosts : master - remote_user: root - tasks : - - - name : Download switch - get_url: - url : http://www-sop.inria.fr/members/Damien.Saucez/images/switch.tar.gz - dest: ~/switch.tar.gz - mode: 0666 - - - name : Download ubuntu18:04 - get_url: - url : http://www-sop.inria.fr/members/Damien.Saucez/images/ubuntu.tar.gz - dest: ~/ubuntu.tar.gz - mode: 0666 - -# - name : Download Debian:10 -# get_url: -# url : http://www-sop.inria.fr/members/Damien.Saucez/images/debian.tar.gz -# dest: ~/debian.tar.gz -# mode: 0666 - - hosts : all remote_user: root tasks : @@ -29,6 +5,18 @@ apt : update_cache: true name : python3-pip + - name: install basice packages + apt : name={{item}} state=present + with_items: + - aptitude + - apt-transport-https + - ca-certificates + - curl + - python3-setuptools + - python3-dev + - build-essential + - iptables + - software-properties-common # - name: install python-pip # apt : @@ -62,14 +50,37 @@ # apt: # name: btrfs-tools - - name: install lxd - apt: - name: lxd +# - name: install lxd +# apt: +# name: lxd - - name: install lxd-client - apt : - name: lxd-client +# - name: install lxd-client +# apt : +# name: lxd-client - name: install ryu apt: name: python3-ryu + + - name: "Check if Docker-CE is installed" + package_facts: + manager: "auto" + + - name: install Docker CE repos (1/3) + apt_key: + url: https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg + state: present + when: "'docker-ce' not in ansible_facts.packages" + + - name: install Docker CE repos (2/3) + shell: add-apt-repository "deb [arch=amd64] https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu $(lsb_release -cs) stable" + when: "'docker-ce' not in ansible_facts.packages" + + - name: install Docker CE repos (3/3) + apt: + update_cache: yes + when: "'docker-ce' not in ansible_facts.packages" + + - name: install Docker CE + apt: name=docker-ce state=present + when: "'docker-ce' not in ansible_facts.packages" diff --git a/setup.py b/setup.py index 21d2f4be..f4ae0201 100644 --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ #install mininet system("mininet/util/install.sh -a") -system("sudo pip3 install git+git://github.com/Giuseppe1992/mapping_distrinet-1.git") +system("sudo pip3 install git+https://github.com/Giuseppe1992/mapping_distrinet-1.git") setup( name='Distrinet', From 0822ef8e3fb17859229113a91959eee5a6dc686d Mon Sep 17 00:00:00 2001 From: J980419xq <62777661+J980419xq@users.noreply.github.com> Date: Wed, 27 Apr 2022 12:01:58 +0800 Subject: [PATCH 02/44] Add files via upload --- ...345\233\276\347\211\207_20220427115156.png" | Bin 0 -> 12140 bytes ...45\233\276\347\211\207_202204271151561.png" | Bin 0 -> 10274 bytes ...45\233\276\347\211\207_202204271151562.png" | Bin 0 -> 164643 bytes ...45\233\276\347\211\207_202204271151563.png" | Bin 0 -> 158585 bytes ...45\233\276\347\211\207_202204271151564.png" | Bin 0 -> 13992 bytes 5 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 "\345\276\256\344\277\241\345\233\276\347\211\207_20220427115156.png" create mode 100644 "\345\276\256\344\277\241\345\233\276\347\211\207_202204271151561.png" create mode 100644 "\345\276\256\344\277\241\345\233\276\347\211\207_202204271151562.png" create mode 100644 "\345\276\256\344\277\241\345\233\276\347\211\207_202204271151563.png" create mode 100644 "\345\276\256\344\277\241\345\233\276\347\211\207_202204271151564.png" diff --git "a/\345\276\256\344\277\241\345\233\276\347\211\207_20220427115156.png" "b/\345\276\256\344\277\241\345\233\276\347\211\207_20220427115156.png" new file mode 100644 index 0000000000000000000000000000000000000000..f998b4340f8b2a0053b83842bfa5f61955f1adae GIT binary patch literal 12140 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 literal 0 HcmV?d00001 diff --git "a/\345\276\256\344\277\241\345\233\276\347\211\207_202204271151561.png" "b/\345\276\256\344\277\241\345\233\276\347\211\207_202204271151561.png" new file mode 100644 index 0000000000000000000000000000000000000000..9c41921548fead55e7102f1084a733150ab71910 GIT binary patch literal 10274 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

$&E^HbQ3hZ=r8pgOkzLWcDgVWLp^|4ELi^ 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 literal 0 HcmV?d00001 diff --git "a/\345\276\256\344\277\241\345\233\276\347\211\207_202204271151564.png" "b/\345\276\256\344\277\241\345\233\276\347\211\207_202204271151564.png" new file mode 100644 index 0000000000000000000000000000000000000000..18e3e5646d402e0af10e461b9f6a278c295fff58 GIT binary patch literal 13992 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 Nob+3%QlMeL{{V2Eb3*_C literal 0 HcmV?d00001 From caf7543a7ffb8a7fec2a4b64ec5fcbbaae5e49a8 Mon Sep 17 00:00:00 2001 From: J980419xq <62777661+J980419xq@users.noreply.github.com> Date: Wed, 27 Apr 2022 12:02:59 +0800 Subject: [PATCH 03/44] =?UTF-8?q?Delete=20=E5=BE=AE=E4=BF=A1=E5=9B=BE?= =?UTF-8?q?=E7=89=87=5F20220427115156.png?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...\345\233\276\347\211\207_20220427115156.png" | Bin 12140 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 "\345\276\256\344\277\241\345\233\276\347\211\207_20220427115156.png" diff --git "a/\345\276\256\344\277\241\345\233\276\347\211\207_20220427115156.png" "b/\345\276\256\344\277\241\345\233\276\347\211\207_20220427115156.png" deleted file mode 100644 index f998b4340f8b2a0053b83842bfa5f61955f1adae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12140 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 From 0b36510e46fbab7cd002f9bea499ed080e03eca7 Mon Sep 17 00:00:00 2001 From: J980419xq <62777661+J980419xq@users.noreply.github.com> Date: Wed, 27 Apr 2022 12:03:17 +0800 Subject: [PATCH 04/44] =?UTF-8?q?Delete=20=E5=BE=AE=E4=BF=A1=E5=9B=BE?= =?UTF-8?q?=E7=89=87=5F202204271151564.png?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...345\233\276\347\211\207_202204271151564.png" | Bin 13992 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 "\345\276\256\344\277\241\345\233\276\347\211\207_202204271151564.png" diff --git "a/\345\276\256\344\277\241\345\233\276\347\211\207_202204271151564.png" "b/\345\276\256\344\277\241\345\233\276\347\211\207_202204271151564.png" deleted file mode 100644 index 18e3e5646d402e0af10e461b9f6a278c295fff58..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13992 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 Nob+3%QlMeL{{V2Eb3*_C From e9df6367e204dad62febdb183c8e64fc70bd5920 Mon Sep 17 00:00:00 2001 From: J980419xq <62777661+J980419xq@users.noreply.github.com> Date: Wed, 27 Apr 2022 12:03:28 +0800 Subject: [PATCH 05/44] =?UTF-8?q?Delete=20=E5=BE=AE=E4=BF=A1=E5=9B=BE?= =?UTF-8?q?=E7=89=87=5F202204271151563.png?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...45\233\276\347\211\207_202204271151563.png" | Bin 158585 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 "\345\276\256\344\277\241\345\233\276\347\211\207_202204271151563.png" diff --git "a/\345\276\256\344\277\241\345\233\276\347\211\207_202204271151563.png" "b/\345\276\256\344\277\241\345\233\276\347\211\207_202204271151563.png" deleted file mode 100644 index a0117de42c568f359dca33e7089198f928d40684..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 158585 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 Mh&>W56xQ|nKN0vF#{d8T literal 0 HcmV?d00001 diff --git a/images/master.png b/images/master.png new file mode 100755 index 0000000000000000000000000000000000000000..e8e475a18d4af785cc47327757f1c5937db75462 GIT binary patch literal 164643 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

bJwM?HXj_Ok@!8w|et02u9fd^@>xqoU6cg+|%! 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

RotlOHS5K9l`OM`f&SjV%B#4 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

*AwhXvYQ*a? zK?pq=J-L3LkFjEEh-Uvp=Z`!$Ecc$OoM5c`)l+g}Eaxf`2SYr#=p2&wu65>471fux zB$MOgi(PYmxO8`?f<_N@?+(vR&YQ`8X^iAVxO>3TR=Fvok&u8-D4GJ3hKTii>>Z*u z#^6}zT*W;!xVvKp-V9o-15Ys+CNZ2?je&B`M%z6n`=Z=k>b~o+QoZ3xlPz9|ZY{sR z?W=1m?a=(?2UdN%?V|Ie8fSj8*2Z1@nQZ^)@Jc(n!K&eXVzwjIVSV7nx&^Fc>!;+& zTj=*a`jp7P9p=TMXnBony|-M^5-YZj`Po`m#H_0?B^fT!j}XJe!5+*;`Tst%?p?ov)0;0;?h!MLXI^-O7z^=#+ z`V}Z9pU`2XZ>$Q`lkYiL7mO?$;T;`YzbSSryhqRe3g?xl*kE0#`it$}CGR66=2Cmu zyDmm+FIk&*Qf%iLy#`F5=P zLLG-yrAG}CI1SToq$0d--t|O)SmaNIOmt+ll`51F5T}W8C?n&I?KSuo3!vn#@!sN} z_4DGC1PrzHw9G}`x=|EIb&;7DtYRt?av_RGX;U9)5k_WhfGSK9qKn?ym17t0m_+8V zv--qfB|ore+RO*nSGmebC->{HkH~vF=Mg=Vt*eA7jNDT9ZX%U5v)I##Zm7}qV{Ez< zG;X7uW2i*X5K#K*Z~{d&9yExg4?6qD?XKwroCz}%aXLSM(=+sh{H;_sIMtR;vtdjQ zT7@pZ1Ofh7T)$zOi;1SjUZjc&Lozv^(6I9?3_xuip;>z zuy;j}5R@TWeFxvhoK5x&C?XRrlaw%FFjnYvO3USVT8B%VyWB^SVQ01=I&NC(J?-%Mc%UPa_2| z1su3tnpAWk=5&MvH?Um}CgM{+cXTPeGBY0O=CJ5>4y7H;PNl`*36Mu3mt+al{kSGG zyqD-GQgsY-<1*~VHf1t7KRJKB;6N_B^OBrfyK^b!B->f?=Vvd-q@}9R`l^$5OqRHy zWl(Ph&m9ORO3?{YEj8kj%Stsb->6`Sq<*bxS=(YN=QX}UN5qiZ6~Z;2%9^CTZYvk{ zH`a^Xq~f$TrNP1U=JXz$N&gVAcAmu;=%?V6s3HOCjIR#joNWZ@MKfRH_u4y2iMs*U}=gMHp8eD!>s|GTMM86}zH)*M4@r@dMx^9ZFXPyJ0-B;%)GyHrbHGtRDtBIZA{Ot5 zDLS74tq5Dw0<6D9CC6zzQLQRctjN1^C2A2Y?<;dK%ApK*Bu&varkDa{1aPmr$An%{ zohjeD9(~FbOCENRySYn>E~F7V1jIAohzaNnOo6FhPG?w+^FxeJNbs7p z6Wmk)$}4x7u5)YwI)F=d z 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

9%6ch=+Nv9zurr$P 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[Egk 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 z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| 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Ⓢ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 +# e1000-devel Mailing List +# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 +# +################################################################################ diff --git a/openflow/datapath/linux-2.6/Modules.mk b/openflow/datapath/linux-2.6/Modules.mk new file mode 100644 index 00000000..8c854a0e --- /dev/null +++ b/openflow/datapath/linux-2.6/Modules.mk @@ -0,0 +1,32 @@ +ofdatapath_sources += \ + linux-2.6/compat-2.6/genetlink-openflow.c \ + linux-2.6/compat-2.6/random32.c +ofdatapath_headers += \ + linux-2.6/compat-2.6/compat26.h \ + linux-2.6/compat-2.6/include/asm-generic/bug.h \ + linux-2.6/compat-2.6/include/linux/dmi.h \ + linux-2.6/compat-2.6/include/linux/icmp.h \ + linux-2.6/compat-2.6/include/linux/if_arp.h \ + linux-2.6/compat-2.6/include/linux/ip.h \ + linux-2.6/compat-2.6/include/linux/ipv6.h \ + linux-2.6/compat-2.6/include/linux/jiffies.h \ + linux-2.6/compat-2.6/include/linux/lockdep.h \ + linux-2.6/compat-2.6/include/linux/mutex.h \ + linux-2.6/compat-2.6/include/linux/netfilter_ipv4.h \ + linux-2.6/compat-2.6/include/linux/netlink.h \ + linux-2.6/compat-2.6/include/linux/random.h \ + linux-2.6/compat-2.6/include/linux/rculist.h \ + linux-2.6/compat-2.6/include/linux/skbuff.h \ + linux-2.6/compat-2.6/include/linux/tcp.h \ + linux-2.6/compat-2.6/include/linux/timer.h \ + linux-2.6/compat-2.6/include/linux/types.h \ + linux-2.6/compat-2.6/include/linux/udp.h \ + linux-2.6/compat-2.6/include/linux/workqueue.h \ + linux-2.6/compat-2.6/include/net/checksum.h \ + linux-2.6/compat-2.6/include/net/genetlink.h \ + linux-2.6/compat-2.6/include/net/netlink.h + +#dist_modules += veth +#build_modules += $(if $(BUILD_VETH),veth) +veth_sources = linux-2.6/compat-2.6/veth.c +veth_headers = diff --git a/openflow/datapath/linux-2.6/compat-2.6/compat26.h b/openflow/datapath/linux-2.6/compat-2.6/compat26.h new file mode 100644 index 00000000..37f6a4f8 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/compat26.h @@ -0,0 +1,31 @@ +#ifndef __COMPAT26_H +#define __COMPAT26_H 1 + +#include + +#if defined(CONFIG_PREEMPT) && LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21) +#error "CONFIG_PREEMPT is broken with 2.6.x before 2.6.21--see commit 4498121ca3, \"[NET]: Handle disabled preemption in gfp_any()\"" +#endif + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23) +/*---------------------------------------------------------------------------- + * In 2.6.24, a namespace argument became required for dev_get_by_name. */ + +#define dev_get_by_name(net, name) \ + dev_get_by_name((name)) + +#define dev_get_by_index(net, ifindex) \ + dev_get_by_index((ifindex)) + +#endif /* linux kernel <= 2.6.23 */ + + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22) +/*---------------------------------------------------------------------------- + * In 2.6.23, the last argument was dropped from kmem_cache_create. */ +#define kmem_cache_create(n, s, a, f, c) \ + kmem_cache_create((n), (s), (a), (f), (c), NULL) + +#endif /* linux kernel <= 2.6.22 */ + +#endif /* compat26.h */ diff --git a/openflow/datapath/linux-2.6/compat-2.6/genetlink-brcompat.c b/openflow/datapath/linux-2.6/compat-2.6/genetlink-brcompat.c new file mode 100644 index 00000000..f30996ce --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/genetlink-brcompat.c @@ -0,0 +1,20 @@ +#include "net/genetlink.h" + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) + +/* We fix grp->id to 32 so that it doesn't collide with any of the multicast + * groups selected by openflow_mod, which uses groups 16 through 31. Collision + * isn't fatal--multicast listeners should check that the family is the one + * that they want and discard others--but it wastes time and memory to receive + * unwanted messages. */ +int genl_register_mc_group(struct genl_family *family, + struct genl_multicast_group *grp) +{ + grp->id = 32; + grp->family = family; + + return 0; +} + +#endif /* kernel < 2.6.23 */ diff --git a/openflow/datapath/linux-2.6/compat-2.6/genetlink-openflow.c b/openflow/datapath/linux-2.6/compat-2.6/genetlink-openflow.c new file mode 100644 index 00000000..9e09215f --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/genetlink-openflow.c @@ -0,0 +1,22 @@ +#include "net/genetlink.h" + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) + +/* We use multicast groups 16 through 31 to avoid colliding with the multicast + * group selected by brcompat_mod, which uses groups 32. Collision isn't + * fatal--multicast listeners should check that the family is the one that they + * want and discard others--but it wastes time and memory to receive unwanted + * messages. */ +int genl_register_mc_group(struct genl_family *family, + struct genl_multicast_group *grp) +{ + /* This code is called single-threaded. */ + static unsigned int next_id = 0; + grp->id = next_id++ % 16 + 16; + grp->family = family; + + return 0; +} + +#endif /* kernel < 2.6.23 */ diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/asm-generic/bug.h b/openflow/datapath/linux-2.6/compat-2.6/include/asm-generic/bug.h new file mode 100644 index 00000000..bd0a1714 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/asm-generic/bug.h @@ -0,0 +1,20 @@ +#ifndef __ASM_GENERIC_BUG_WRAPPER_H +#define __ASM_GENERIC_BUG_WRAPPER_H + +#include_next + +#ifndef WARN_ON_ONCE +#define WARN_ON_ONCE(condition) ({ \ + static int __warned; \ + int __ret_warn_once = !!(condition); \ + \ + if (unlikely(__ret_warn_once) && !__warned) { \ + WARN_ON(1); \ + __warned = 1; \ + } \ + unlikely(__ret_warn_once); \ +}) + +#endif + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/dmi.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/dmi.h new file mode 100644 index 00000000..52916fec --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/dmi.h @@ -0,0 +1,114 @@ +#ifndef __LINUX_DMI_WRAPPER_H +#define __LINUX_DMI_WRAPPER_H 1 + +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23) + +#include_next + +#else /* linux version >= 2.6.23 */ + +#ifndef __DMI_H__ +#define __DMI_H__ + +#include + +enum dmi_field { + DMI_NONE, + DMI_BIOS_VENDOR, + DMI_BIOS_VERSION, + DMI_BIOS_DATE, + DMI_SYS_VENDOR, + DMI_PRODUCT_NAME, + DMI_PRODUCT_VERSION, + DMI_PRODUCT_SERIAL, + DMI_PRODUCT_UUID, + DMI_BOARD_VENDOR, + DMI_BOARD_NAME, + DMI_BOARD_VERSION, + DMI_BOARD_SERIAL, + DMI_BOARD_ASSET_TAG, + DMI_CHASSIS_VENDOR, + DMI_CHASSIS_TYPE, + DMI_CHASSIS_VERSION, + DMI_CHASSIS_SERIAL, + DMI_CHASSIS_ASSET_TAG, + DMI_STRING_MAX, +}; + +enum dmi_device_type { + DMI_DEV_TYPE_ANY = 0, + DMI_DEV_TYPE_OTHER, + DMI_DEV_TYPE_UNKNOWN, + DMI_DEV_TYPE_VIDEO, + DMI_DEV_TYPE_SCSI, + DMI_DEV_TYPE_ETHERNET, + DMI_DEV_TYPE_TOKENRING, + DMI_DEV_TYPE_SOUND, + DMI_DEV_TYPE_IPMI = -1, + DMI_DEV_TYPE_OEM_STRING = -2 +}; + +struct dmi_header { + u8 type; + u8 length; + u16 handle; +}; + +/* + * DMI callbacks for problem boards + */ +struct dmi_strmatch { + u8 slot; + char *substr; +}; + +struct dmi_system_id { + int (*callback)(struct dmi_system_id *); + const char *ident; + struct dmi_strmatch matches[4]; + void *driver_data; +}; + +#define DMI_MATCH(a, b) { a, b } + +struct dmi_device { + struct list_head list; + int type; + const char *name; + void *device_data; /* Type specific data */ +}; + +/* No CONFIG_DMI before 2.6.16 */ +#if defined(CONFIG_DMI) || defined(CONFIG_X86_32) + +extern int dmi_check_system(struct dmi_system_id *list); +extern char * dmi_get_system_info(int field); +extern struct dmi_device * dmi_find_device(int type, const char *name, + struct dmi_device *from); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) +extern void dmi_scan_machine(void); +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17) +extern int dmi_get_year(int field); +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) +extern int dmi_name_in_vendors(char *str); +#endif + +#else + +static inline int dmi_check_system(struct dmi_system_id *list) { return 0; } +static inline char * dmi_get_system_info(int field) { return NULL; } +static inline struct dmi_device * dmi_find_device(int type, const char *name, + struct dmi_device *from) { return NULL; } +static inline int dmi_get_year(int year) { return 0; } +static inline int dmi_name_in_vendors(char *s) { return 0; } + +#endif + +#endif /* __DMI_H__ */ + +#endif /* linux kernel < 2.6.22 */ + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/icmp.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/icmp.h new file mode 100644 index 00000000..89b354e4 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/icmp.h @@ -0,0 +1,13 @@ +#ifndef __LINUX_ICMP_WRAPPER_H +#define __LINUX_ICMP_WRAPPER_H 1 + +#include_next + +#ifndef HAVE_SKBUFF_HEADER_HELPERS +static inline struct icmphdr *icmp_hdr(const struct sk_buff *skb) +{ + return (struct icmphdr *)skb_transport_header(skb); +} +#endif + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/if_arp.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/if_arp.h new file mode 100644 index 00000000..3ec9ea7a --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/if_arp.h @@ -0,0 +1,16 @@ +#ifndef __LINUX_IF_ARP_WRAPPER_H +#define __LINUX_IF_ARP_WRAPPER_H 1 + + +#include_next + +#ifndef HAVE_SKBUFF_HEADER_HELPERS +#include + +static inline struct arphdr *arp_hdr(const struct sk_buff *skb) +{ + return (struct arphdr *)skb_network_header(skb); +} +#endif /* !HAVE_SKBUFF_HEADER_HELPERS */ + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/ip.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/ip.h new file mode 100644 index 00000000..36765396 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/ip.h @@ -0,0 +1,18 @@ +#ifndef __LINUX_IP_WRAPPER_H +#define __LINUX_IP_WRAPPER_H 1 + +#include_next + +#ifndef HAVE_SKBUFF_HEADER_HELPERS +static inline struct iphdr *ip_hdr(const struct sk_buff *skb) +{ + return (struct iphdr *)skb_network_header(skb); +} + +static inline unsigned int ip_hdrlen(const struct sk_buff *skb) +{ + return ip_hdr(skb)->ihl * 4; +} +#endif /* !HAVE_SKBUFF_HEADER_HELPERS */ + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/ipv6.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/ipv6.h new file mode 100644 index 00000000..25a5431a --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/ipv6.h @@ -0,0 +1,13 @@ +#ifndef __LINUX_IPV6_WRAPPER_H +#define __LINUX_IPV6_WRAPPER_H 1 + +#include_next + +#ifndef HAVE_SKBUFF_HEADER_HELPERS +static inline struct ipv6hdr *ipv6_hdr(const struct sk_buff *skb) +{ + return (struct ipv6hdr *)skb_network_header(skb); +} +#endif + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/jiffies.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/jiffies.h new file mode 100644 index 00000000..3286e634 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/jiffies.h @@ -0,0 +1,26 @@ +#ifndef __LINUX_JIFFIES_WRAPPER_H +#define __LINUX_JIFFIES_WRAPPER_H 1 + +#include_next + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) + +/* Same as above, but does so with platform independent 64bit types. + * These must be used when utilizing jiffies_64 (i.e. return value of + * get_jiffies_64() */ +#define time_after64(a,b) \ + (typecheck(__u64, a) && \ + typecheck(__u64, b) && \ + ((__s64)(b) - (__s64)(a) < 0)) +#define time_before64(a,b) time_after64(b,a) + +#define time_after_eq64(a,b) \ + (typecheck(__u64, a) && \ + typecheck(__u64, b) && \ + ((__s64)(a) - (__s64)(b) >= 0)) +#define time_before_eq64(a,b) time_after_eq64(b,a) + +#endif /* linux kernel < 2.6.19 */ + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/lockdep.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/lockdep.h new file mode 100644 index 00000000..1c839423 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/lockdep.h @@ -0,0 +1,450 @@ +/* + * Runtime locking correctness validator + * + * Copyright (C) 2006,2007 Red Hat, Inc., Ingo Molnar + * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra + * + * see Documentation/lockdep-design.txt for more details. + */ +#ifndef __LINUX_LOCKDEP_WRAPPER_H +#define __LINUX_LOCKDEP_WRAPPER_H + +#include_next + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) + +struct task_struct; +struct lockdep_map; + +#ifdef CONFIG_LOCKDEP + +#include +#include +#include +#include + +/* + * Lock-class usage-state bits: + */ +enum lock_usage_bit +{ + LOCK_USED = 0, + LOCK_USED_IN_HARDIRQ, + LOCK_USED_IN_SOFTIRQ, + LOCK_ENABLED_SOFTIRQS, + LOCK_ENABLED_HARDIRQS, + LOCK_USED_IN_HARDIRQ_READ, + LOCK_USED_IN_SOFTIRQ_READ, + LOCK_ENABLED_SOFTIRQS_READ, + LOCK_ENABLED_HARDIRQS_READ, + LOCK_USAGE_STATES +}; + +/* + * Usage-state bitmasks: + */ +#define LOCKF_USED (1 << LOCK_USED) +#define LOCKF_USED_IN_HARDIRQ (1 << LOCK_USED_IN_HARDIRQ) +#define LOCKF_USED_IN_SOFTIRQ (1 << LOCK_USED_IN_SOFTIRQ) +#define LOCKF_ENABLED_HARDIRQS (1 << LOCK_ENABLED_HARDIRQS) +#define LOCKF_ENABLED_SOFTIRQS (1 << LOCK_ENABLED_SOFTIRQS) + +#define LOCKF_ENABLED_IRQS (LOCKF_ENABLED_HARDIRQS | LOCKF_ENABLED_SOFTIRQS) +#define LOCKF_USED_IN_IRQ (LOCKF_USED_IN_HARDIRQ | LOCKF_USED_IN_SOFTIRQ) + +#define LOCKF_USED_IN_HARDIRQ_READ (1 << LOCK_USED_IN_HARDIRQ_READ) +#define LOCKF_USED_IN_SOFTIRQ_READ (1 << LOCK_USED_IN_SOFTIRQ_READ) +#define LOCKF_ENABLED_HARDIRQS_READ (1 << LOCK_ENABLED_HARDIRQS_READ) +#define LOCKF_ENABLED_SOFTIRQS_READ (1 << LOCK_ENABLED_SOFTIRQS_READ) + +#define LOCKF_ENABLED_IRQS_READ \ + (LOCKF_ENABLED_HARDIRQS_READ | LOCKF_ENABLED_SOFTIRQS_READ) +#define LOCKF_USED_IN_IRQ_READ \ + (LOCKF_USED_IN_HARDIRQ_READ | LOCKF_USED_IN_SOFTIRQ_READ) + +#define MAX_LOCKDEP_SUBCLASSES 8UL + +/* + * Lock-classes are keyed via unique addresses, by embedding the + * lockclass-key into the kernel (or module) .data section. (For + * static locks we use the lock address itself as the key.) + */ +struct lockdep_subclass_key { + char __one_byte; +} __attribute__ ((__packed__)); + +struct lock_class_key { + struct lockdep_subclass_key subkeys[MAX_LOCKDEP_SUBCLASSES]; +}; + +/* + * The lock-class itself: + */ +struct lock_class { + /* + * class-hash: + */ + struct list_head hash_entry; + + /* + * global list of all lock-classes: + */ + struct list_head lock_entry; + + struct lockdep_subclass_key *key; + unsigned int subclass; + + /* + * IRQ/softirq usage tracking bits: + */ + unsigned long usage_mask; + struct stack_trace usage_traces[LOCK_USAGE_STATES]; + + /* + * These fields represent a directed graph of lock dependencies, + * to every node we attach a list of "forward" and a list of + * "backward" graph nodes. + */ + struct list_head locks_after, locks_before; + + /* + * Generation counter, when doing certain classes of graph walking, + * to ensure that we check one node only once: + */ + unsigned int version; + + /* + * Statistics counter: + */ + unsigned long ops; + + const char *name; + int name_version; + +#ifdef CONFIG_LOCK_STAT + unsigned long contention_point[4]; +#endif +}; + +#ifdef CONFIG_LOCK_STAT +struct lock_time { + s64 min; + s64 max; + s64 total; + unsigned long nr; +}; + +enum bounce_type { + bounce_acquired_write, + bounce_acquired_read, + bounce_contended_write, + bounce_contended_read, + nr_bounce_types, + + bounce_acquired = bounce_acquired_write, + bounce_contended = bounce_contended_write, +}; + +struct lock_class_stats { + unsigned long contention_point[4]; + struct lock_time read_waittime; + struct lock_time write_waittime; + struct lock_time read_holdtime; + struct lock_time write_holdtime; + unsigned long bounces[nr_bounce_types]; +}; + +struct lock_class_stats lock_stats(struct lock_class *class); +void clear_lock_stats(struct lock_class *class); +#endif + +/* + * Map the lock object (the lock instance) to the lock-class object. + * This is embedded into specific lock instances: + */ +struct lockdep_map { + struct lock_class_key *key; + struct lock_class *class_cache; + const char *name; +#ifdef CONFIG_LOCK_STAT + int cpu; +#endif +}; + +/* + * Every lock has a list of other locks that were taken after it. + * We only grow the list, never remove from it: + */ +struct lock_list { + struct list_head entry; + struct lock_class *class; + struct stack_trace trace; + int distance; +}; + +/* + * We record lock dependency chains, so that we can cache them: + */ +struct lock_chain { + struct list_head entry; + u64 chain_key; +}; + +struct held_lock { + /* + * One-way hash of the dependency chain up to this point. We + * hash the hashes step by step as the dependency chain grows. + * + * We use it for dependency-caching and we skip detection + * passes and dependency-updates if there is a cache-hit, so + * it is absolutely critical for 100% coverage of the validator + * to have a unique key value for every unique dependency path + * that can occur in the system, to make a unique hash value + * as likely as possible - hence the 64-bit width. + * + * The task struct holds the current hash value (initialized + * with zero), here we store the previous hash value: + */ + u64 prev_chain_key; + struct lock_class *class; + unsigned long acquire_ip; + struct lockdep_map *instance; + +#ifdef CONFIG_LOCK_STAT + u64 waittime_stamp; + u64 holdtime_stamp; +#endif + /* + * The lock-stack is unified in that the lock chains of interrupt + * contexts nest ontop of process context chains, but we 'separate' + * the hashes by starting with 0 if we cross into an interrupt + * context, and we also keep do not add cross-context lock + * dependencies - the lock usage graph walking covers that area + * anyway, and we'd just unnecessarily increase the number of + * dependencies otherwise. [Note: hardirq and softirq contexts + * are separated from each other too.] + * + * The following field is used to detect when we cross into an + * interrupt context: + */ + int irq_context; + int trylock; + int read; + int check; + int hardirqs_off; +}; + +/* + * Initialization, self-test and debugging-output methods: + */ +extern void lockdep_init(void); +extern void lockdep_info(void); +extern void lockdep_reset(void); +extern void lockdep_reset_lock(struct lockdep_map *lock); +extern void lockdep_free_key_range(void *start, unsigned long size); + +extern void lockdep_off(void); +extern void lockdep_on(void); + +/* + * These methods are used by specific locking variants (spinlocks, + * rwlocks, mutexes and rwsems) to pass init/acquire/release events + * to lockdep: + */ + +extern void lockdep_init_map(struct lockdep_map *lock, const char *name, + struct lock_class_key *key, int subclass); + +/* + * Reinitialize a lock key - for cases where there is special locking or + * special initialization of locks so that the validator gets the scope + * of dependencies wrong: they are either too broad (they need a class-split) + * or they are too narrow (they suffer from a false class-split): + */ +#define lockdep_set_class(lock, key) \ + lockdep_init_map(&(lock)->dep_map, #key, key, 0) +#define lockdep_set_class_and_name(lock, key, name) \ + lockdep_init_map(&(lock)->dep_map, name, key, 0) +#define lockdep_set_class_and_subclass(lock, key, sub) \ + lockdep_init_map(&(lock)->dep_map, #key, key, sub) +#define lockdep_set_subclass(lock, sub) \ + lockdep_init_map(&(lock)->dep_map, #lock, \ + (lock)->dep_map.key, sub) + +/* + * Acquire a lock. + * + * Values for "read": + * + * 0: exclusive (write) acquire + * 1: read-acquire (no recursion allowed) + * 2: read-acquire with same-instance recursion allowed + * + * Values for check: + * + * 0: disabled + * 1: simple checks (freeing, held-at-exit-time, etc.) + * 2: full validation + */ +extern void lock_acquire(struct lockdep_map *lock, unsigned int subclass, + int trylock, int read, int check, unsigned long ip); + +extern void lock_release(struct lockdep_map *lock, int nested, + unsigned long ip); + +# define INIT_LOCKDEP .lockdep_recursion = 0, + +#define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0) + +#else /* !LOCKDEP */ + +static inline void lockdep_off(void) +{ +} + +static inline void lockdep_on(void) +{ +} + +# define lock_acquire(l, s, t, r, c, i) do { } while (0) +# define lock_release(l, n, i) do { } while (0) +# define lockdep_init() do { } while (0) +# define lockdep_info() do { } while (0) +# define lockdep_init_map(lock, name, key, sub) do { (void)(key); } while (0) +# define lockdep_set_class(lock, key) do { (void)(key); } while (0) +# define lockdep_set_class_and_name(lock, key, name) \ + do { (void)(key); } while (0) +#define lockdep_set_class_and_subclass(lock, key, sub) \ + do { (void)(key); } while (0) +#define lockdep_set_subclass(lock, sub) do { } while (0) + +# define INIT_LOCKDEP +# define lockdep_reset() do { debug_locks = 1; } while (0) +# define lockdep_free_key_range(start, size) do { } while (0) +/* + * The class key takes no space if lockdep is disabled: + */ +struct lock_class_key { }; + +#define lockdep_depth(tsk) (0) + +#endif /* !LOCKDEP */ + +#ifdef CONFIG_LOCK_STAT + +extern void lock_contended(struct lockdep_map *lock, unsigned long ip); +extern void lock_acquired(struct lockdep_map *lock); + +#define LOCK_CONTENDED(_lock, try, lock) \ +do { \ + if (!try(_lock)) { \ + lock_contended(&(_lock)->dep_map, _RET_IP_); \ + lock(_lock); \ + } \ + lock_acquired(&(_lock)->dep_map); \ +} while (0) + +#else /* CONFIG_LOCK_STAT */ + +#define lock_contended(lockdep_map, ip) do {} while (0) +#define lock_acquired(lockdep_map) do {} while (0) + +#define LOCK_CONTENDED(_lock, try, lock) \ + lock(_lock) + +#endif /* CONFIG_LOCK_STAT */ + +#if defined(CONFIG_TRACE_IRQFLAGS) && defined(CONFIG_GENERIC_HARDIRQS) +extern void early_init_irq_lock_class(void); +#else +static inline void early_init_irq_lock_class(void) +{ +} +#endif + +#ifdef CONFIG_TRACE_IRQFLAGS +extern void early_boot_irqs_off(void); +extern void early_boot_irqs_on(void); +extern void print_irqtrace_events(struct task_struct *curr); +#else +static inline void early_boot_irqs_off(void) +{ +} +static inline void early_boot_irqs_on(void) +{ +} +static inline void print_irqtrace_events(struct task_struct *curr) +{ +} +#endif + +/* + * For trivial one-depth nesting of a lock-class, the following + * global define can be used. (Subsystems with multiple levels + * of nesting should define their own lock-nesting subclasses.) + */ +#define SINGLE_DEPTH_NESTING 1 + +/* + * Map the dependency ops to NOP or to real lockdep ops, depending + * on the per lock-class debug mode: + */ + +#ifdef CONFIG_DEBUG_LOCK_ALLOC +# ifdef CONFIG_PROVE_LOCKING +# define spin_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 2, i) +# else +# define spin_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 1, i) +# endif +# define spin_release(l, n, i) lock_release(l, n, i) +#else +# define spin_acquire(l, s, t, i) do { } while (0) +# define spin_release(l, n, i) do { } while (0) +#endif + +#ifdef CONFIG_DEBUG_LOCK_ALLOC +# ifdef CONFIG_PROVE_LOCKING +# define rwlock_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 2, i) +# define rwlock_acquire_read(l, s, t, i) lock_acquire(l, s, t, 2, 2, i) +# else +# define rwlock_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 1, i) +# define rwlock_acquire_read(l, s, t, i) lock_acquire(l, s, t, 2, 1, i) +# endif +# define rwlock_release(l, n, i) lock_release(l, n, i) +#else +# define rwlock_acquire(l, s, t, i) do { } while (0) +# define rwlock_acquire_read(l, s, t, i) do { } while (0) +# define rwlock_release(l, n, i) do { } while (0) +#endif + +#ifdef CONFIG_DEBUG_LOCK_ALLOC +# ifdef CONFIG_PROVE_LOCKING +# define mutex_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 2, i) +# else +# define mutex_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 1, i) +# endif +# define mutex_release(l, n, i) lock_release(l, n, i) +#else +# define mutex_acquire(l, s, t, i) do { } while (0) +# define mutex_release(l, n, i) do { } while (0) +#endif + +#ifdef CONFIG_DEBUG_LOCK_ALLOC +# ifdef CONFIG_PROVE_LOCKING +# define rwsem_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 2, i) +# define rwsem_acquire_read(l, s, t, i) lock_acquire(l, s, t, 1, 2, i) +# else +# define rwsem_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 1, i) +# define rwsem_acquire_read(l, s, t, i) lock_acquire(l, s, t, 1, 1, i) +# endif +# define rwsem_release(l, n, i) lock_release(l, n, i) +#else +# define rwsem_acquire(l, s, t, i) do { } while (0) +# define rwsem_acquire_read(l, s, t, i) do { } while (0) +# define rwsem_release(l, n, i) do { } while (0) +#endif + +#endif /* linux kernel < 2.6.18 */ + +#endif /* __LINUX_LOCKDEP_WRAPPER_H */ diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/mutex.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/mutex.h new file mode 100644 index 00000000..cb5b2738 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/mutex.h @@ -0,0 +1,59 @@ +#ifndef __LINUX_MUTEX_WRAPPER_H +#define __LINUX_MUTEX_WRAPPER_H + + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) + +#include + +struct mutex { + struct semaphore sema; +}; + +#define mutex_init(mutex) init_MUTEX(&mutex->sema) +#define mutex_destroy(mutex) do { } while (0) + +#define __MUTEX_INITIALIZER(name) \ + __SEMAPHORE_INITIALIZER(name,1) + +#define DEFINE_MUTEX(mutexname) \ + struct mutex mutexname = { __MUTEX_INITIALIZER(mutexname.sema) } + +/* + * See kernel/mutex.c for detailed documentation of these APIs. + * Also see Documentation/mutex-design.txt. + */ +static inline void mutex_lock(struct mutex *lock) +{ + down(&lock->sema); +} + +static inline int mutex_lock_interruptible(struct mutex *lock) +{ + return down_interruptible(&lock->sema); +} + +#define mutex_lock_nested(lock, subclass) mutex_lock(lock) +#define mutex_lock_interruptible_nested(lock, subclass) mutex_lock_interruptible(lock) + +/* + * NOTE: mutex_trylock() follows the spin_trylock() convention, + * not the down_trylock() convention! + */ +static inline int mutex_trylock(struct mutex *lock) +{ + return !down_trylock(&lock->sema); +} + +static inline void mutex_unlock(struct mutex *lock) +{ + up(&lock->sema); +} +#else + +#include_next + +#endif /* linux version < 2.6.16 */ + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/netdevice.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/netdevice.h new file mode 100644 index 00000000..7abeb3bf --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/netdevice.h @@ -0,0 +1,10 @@ +#ifndef __LINUX_NETDEVICE_WRAPPER_H +#define __LINUX_NETDEVICE_WRAPPER_H 1 + +#include_next + +#ifndef to_net_dev +#define to_net_dev(class) container_of(class, struct net_device, class_dev) +#endif + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/netfilter_bridge.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/netfilter_bridge.h new file mode 100644 index 00000000..1c8183c8 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/netfilter_bridge.h @@ -0,0 +1,24 @@ +#ifndef __LINUX_NETFILTER_BRIDGE_WRAPPER_H +#define __LINUX_NETFILTER_BRIDGE_WRAPPER_H + +#include_next + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) + +#include +#include + +static inline unsigned int nf_bridge_encap_header_len(const struct sk_buff *skb) +{ + switch (skb->protocol) { + case __constant_htons(ETH_P_8021Q): + return VLAN_HLEN; + default: + return 0; + } +} + +#endif /* linux version < 2.6.22 */ + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/netfilter_ipv4.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/netfilter_ipv4.h new file mode 100644 index 00000000..ed8a5d94 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/netfilter_ipv4.h @@ -0,0 +1,19 @@ +#ifndef __LINUX_NETFILTER_IPV4_WRAPPER_H +#define __LINUX_NETFILTER_IPV4_WRAPPER_H 1 + +#include_next + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) + +#ifdef __KERNEL__ + +#define NF_INET_PRE_ROUTING NF_IP_PRE_ROUTING +#define NF_INET_POST_ROUTING NF_IP_POST_ROUTING +#define NF_INET_FORWARD NF_IP_FORWARD + +#endif /* __KERNEL__ */ + +#endif /* linux kernel < 2.6.25 */ + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/netlink.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/netlink.h new file mode 100644 index 00000000..c5f83bd0 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/netlink.h @@ -0,0 +1,24 @@ +#ifndef __LINUX_NETLINK_WRAPPER_H +#define __LINUX_NETLINK_WRAPPER_H 1 + +#include +#include_next +#include + +#include + +#ifndef NLMSG_DEFAULT_SIZE +#define NLMSG_DEFAULT_SIZE (NLMSG_GOODSIZE - NLMSG_HDRLEN) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) +#define nlmsg_new(s, f) nlmsg_new_proper((s), (f)) +static inline struct sk_buff *nlmsg_new_proper(int size, gfp_t flags) +{ + return alloc_skb(size, flags); +} + +#endif /* linux kernel < 2.6.19 */ + + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/random.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/random.h new file mode 100644 index 00000000..4e4932c9 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/random.h @@ -0,0 +1,17 @@ +#ifndef __LINUX_RANDOM_WRAPPER_H +#define __LINUX_RANDOM_WRAPPER_H 1 + +#include_next + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) + +#ifdef __KERNEL__ +u32 random32(void); +void srandom32(u32 seed); +#endif /* __KERNEL__ */ + +#endif /* linux kernel < 2.6.19 */ + + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/rculist.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/rculist.h new file mode 100644 index 00000000..4164c0e9 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/rculist.h @@ -0,0 +1,12 @@ +#ifndef __LINUX_RCULIST_WRAPPER_H +#define __LINUX_RCULIST_WRAPPER_H + +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) +#include_next +#else +/* Prior to 2.6.26, the contents of rculist.h were part of list.h. */ +#include +#endif + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/skbuff.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/skbuff.h new file mode 100644 index 00000000..55d32eb1 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/skbuff.h @@ -0,0 +1,137 @@ +#ifndef __LINUX_SKBUFF_WRAPPER_H +#define __LINUX_SKBUFF_WRAPPER_H 1 + +#include_next + +#include + +#ifndef HAVE_SKB_COPY_FROM_LINEAR_DATA_OFFSET +static inline void skb_copy_from_linear_data_offset(const struct sk_buff *skb, + const int offset, void *to, + const unsigned int len) +{ + memcpy(to, skb->data + offset, len); +} + +static inline void skb_copy_to_linear_data_offset(struct sk_buff *skb, + const int offset, + const void *from, + const unsigned int len) +{ + memcpy(skb->data + offset, from, len); +} + +#endif /* !HAVE_SKB_COPY_FROM_LINEAR_DATA_OFFSET */ + + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) +static inline int __skb_cow(struct sk_buff *skb, unsigned int headroom, + int cloned) +{ + int delta = 0; + + if (headroom < NET_SKB_PAD) + headroom = NET_SKB_PAD; + if (headroom > skb_headroom(skb)) + delta = headroom - skb_headroom(skb); + + if (delta || cloned) + return pskb_expand_head(skb, ALIGN(delta, NET_SKB_PAD), 0, + GFP_ATOMIC); + return 0; +} + +static inline int skb_cow_head(struct sk_buff *skb, unsigned int headroom) +{ + return __skb_cow(skb, headroom, skb_header_cloned(skb)); +} +#endif /* linux < 2.6.23 */ + + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17) +/* Emulate Linux 2.6.17 and later behavior, in which kfree_skb silently ignores + * null pointer arguments. */ +#define kfree_skb(skb) kfree_skb_maybe_null(skb) +static inline void kfree_skb_maybe_null(struct sk_buff *skb) +{ + if (likely(skb != NULL)) + (kfree_skb)(skb); +} +#endif + + +#ifndef CHECKSUM_PARTIAL +/* Note that CHECKSUM_PARTIAL is not implemented, but this allows us to at + * least test against it: see update_csum() in forward.c. */ +#define CHECKSUM_PARTIAL 3 +#endif +#ifndef CHECKSUM_COMPLETE +#define CHECKSUM_COMPLETE CHECKSUM_HW +#endif + +#ifdef HAVE_MAC_RAW +#define mac_header mac.raw +#define network_header nh.raw +#endif + +#ifndef HAVE_SKBUFF_HEADER_HELPERS +static inline unsigned char *skb_transport_header(const struct sk_buff *skb) +{ + return skb->h.raw; +} + +static inline void skb_reset_transport_header(struct sk_buff *skb) +{ + skb->h.raw = skb->data; +} + +static inline void skb_set_transport_header(struct sk_buff *skb, + const int offset) +{ + skb->h.raw = skb->data + offset; +} + +static inline unsigned char *skb_network_header(const struct sk_buff *skb) +{ + return skb->nh.raw; +} + +static inline void skb_set_network_header(struct sk_buff *skb, const int offset) +{ + skb->nh.raw = skb->data + offset; +} + +static inline unsigned char *skb_mac_header(const struct sk_buff *skb) +{ + return skb->mac.raw; +} + +static inline void skb_reset_mac_header(struct sk_buff *skb) +{ + skb->mac_header = skb->data; +} + +static inline void skb_set_mac_header(struct sk_buff *skb, const int offset) +{ + skb->mac.raw = skb->data + offset; +} + +static inline int skb_transport_offset(const struct sk_buff *skb) +{ + return skb_transport_header(skb) - skb->data; +} + +static inline int skb_network_offset(const struct sk_buff *skb) +{ + return skb_network_header(skb) - skb->data; +} + +static inline void skb_copy_to_linear_data(struct sk_buff *skb, + const void *from, + const unsigned int len) +{ + memcpy(skb->data, from, len); +} +#endif /* !HAVE_SKBUFF_HEADER_HELPERS */ + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/tcp.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/tcp.h new file mode 100644 index 00000000..6fad1933 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/tcp.h @@ -0,0 +1,18 @@ +#ifndef __LINUX_TCP_WRAPPER_H +#define __LINUX_TCP_WRAPPER_H 1 + +#include_next + +#ifndef HAVE_SKBUFF_HEADER_HELPERS +static inline struct tcphdr *tcp_hdr(const struct sk_buff *skb) +{ + return (struct tcphdr *)skb_transport_header(skb); +} + +static inline unsigned int tcp_hdrlen(const struct sk_buff *skb) +{ + return tcp_hdr(skb)->doff * 4; +} +#endif /* !HAVE_SKBUFF_HEADER_HELPERS */ + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/timer.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/timer.h new file mode 100644 index 00000000..6c3a9b0f --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/timer.h @@ -0,0 +1,96 @@ +#ifndef __LINUX_TIMER_WRAPPER_H +#define __LINUX_TIMER_WRAPPER_H 1 + +#include_next + +#include + +#ifndef RHEL_RELEASE_VERSION +#define RHEL_RELEASE_VERSION(X,Y) ( 0 ) +#endif +#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) && \ + (!defined(RHEL_RELEASE_CODE) || \ + (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(5,1)))) + +extern unsigned long volatile jiffies; + +/** + * __round_jiffies - function to round jiffies to a full second + * @j: the time in (absolute) jiffies that should be rounded + * @cpu: the processor number on which the timeout will happen + * + * __round_jiffies() rounds an absolute time in the future (in jiffies) + * up or down to (approximately) full seconds. This is useful for timers + * for which the exact time they fire does not matter too much, as long as + * they fire approximately every X seconds. + * + * By rounding these timers to whole seconds, all such timers will fire + * at the same time, rather than at various times spread out. The goal + * of this is to have the CPU wake up less, which saves power. + * + * The exact rounding is skewed for each processor to avoid all + * processors firing at the exact same time, which could lead + * to lock contention or spurious cache line bouncing. + * + * The return value is the rounded version of the @j parameter. + */ +static inline unsigned long __round_jiffies(unsigned long j, int cpu) +{ + int rem; + unsigned long original = j; + + /* + * We don't want all cpus firing their timers at once hitting the + * same lock or cachelines, so we skew each extra cpu with an extra + * 3 jiffies. This 3 jiffies came originally from the mm/ code which + * already did this. + * The skew is done by adding 3*cpunr, then round, then subtract this + * extra offset again. + */ + j += cpu * 3; + + rem = j % HZ; + + /* + * If the target jiffie is just after a whole second (which can happen + * due to delays of the timer irq, long irq off times etc etc) then + * we should round down to the whole second, not up. Use 1/4th second + * as cutoff for this rounding as an extreme upper bound for this. + */ + if (rem < HZ/4) /* round down */ + j = j - rem; + else /* round up */ + j = j - rem + HZ; + + /* now that we have rounded, subtract the extra skew again */ + j -= cpu * 3; + + if (j <= jiffies) /* rounding ate our timeout entirely; */ + return original; + return j; +} + + +/** + * round_jiffies - function to round jiffies to a full second + * @j: the time in (absolute) jiffies that should be rounded + * + * round_jiffies() rounds an absolute time in the future (in jiffies) + * up or down to (approximately) full seconds. This is useful for timers + * for which the exact time they fire does not matter too much, as long as + * they fire approximately every X seconds. + * + * By rounding these timers to whole seconds, all such timers will fire + * at the same time, rather than at various times spread out. The goal + * of this is to have the CPU wake up less, which saves power. + * + * The return value is the rounded version of the @j parameter. + */ +static inline unsigned long round_jiffies(unsigned long j) +{ + return __round_jiffies(j, 0); // FIXME +} + +#endif /* linux kernel < 2.6.20 */ + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/types.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/types.h new file mode 100644 index 00000000..c1f375eb --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/types.h @@ -0,0 +1,14 @@ +#ifndef __LINUX_TYPES_WRAPPER_H +#define __LINUX_TYPES_WRAPPER_H 1 + +#include_next + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + +typedef __u16 __bitwise __sum16; +typedef __u32 __bitwise __wsum; + +#endif /* linux kernel < 2.6.20 */ + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/udp.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/udp.h new file mode 100644 index 00000000..6fe4721b --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/udp.h @@ -0,0 +1,13 @@ +#ifndef __LINUX_UDP_WRAPPER_H +#define __LINUX_UDP_WRAPPER_H 1 + +#include_next + +#ifndef HAVE_SKBUFF_HEADER_HELPERS +static inline struct udphdr *udp_hdr(const struct sk_buff *skb) +{ + return (struct udphdr *)skb_transport_header(skb); +} +#endif /* HAVE_SKBUFF_HEADER_HELPERS */ + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/workqueue.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/workqueue.h new file mode 100644 index 00000000..1ac3b6ec --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/workqueue.h @@ -0,0 +1,42 @@ +#ifndef __LINUX_WORKQUEUE_WRAPPER_H +#define __LINUX_WORKQUEUE_WRAPPER_H 1 + +#include_next + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + +#ifdef __KERNEL__ +/* + * initialize a work-struct's func and data pointers: + */ +#undef PREPARE_WORK +#define PREPARE_WORK(_work, _func) \ + do { \ + (_work)->func = (void(*)(void*)) _func; \ + (_work)->data = _work; \ + } while (0) + +/* + * initialize all of a work-struct: + */ +#undef INIT_WORK +#define INIT_WORK(_work, _func) \ + do { \ + INIT_LIST_HEAD(&(_work)->entry); \ + (_work)->pending = 0; \ + PREPARE_WORK((_work), (_func)); \ + init_timer(&(_work)->timer); \ + } while (0) + +#endif /* __KERNEL__ */ + +#endif /* linux kernel < 2.6.20 */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) +/* There is no equivalent to cancel_work_sync() so just flush all + * pending work. */ +#define cancel_work_sync(_work) flush_scheduled_work() +#endif + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/net/checksum.h b/openflow/datapath/linux-2.6/compat-2.6/include/net/checksum.h new file mode 100644 index 00000000..c64c6bd0 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/net/checksum.h @@ -0,0 +1,16 @@ +#ifndef __NET_CHECKSUM_WRAPPER_H +#define __NET_CHECKSUM_WRAPPER_H 1 + +#include_next + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + +static inline __wsum csum_unfold(__sum16 n) +{ + return (__force __wsum)n; +} + +#endif /* linux kernel < 2.6.20 */ + +#endif /* checksum.h */ diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/net/genetlink.h b/openflow/datapath/linux-2.6/compat-2.6/include/net/genetlink.h new file mode 100644 index 00000000..57a47316 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/net/genetlink.h @@ -0,0 +1,123 @@ +#ifndef __NET_GENERIC_NETLINK_WRAPPER_H +#define __NET_GENERIC_NETLINK_WRAPPER_H 1 + + +#include +#include_next + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) + +#include + +/*---------------------------------------------------------------------------- + * In 2.6.23, registering of multicast groups was added. Our compatability + * layer just supports registering a single group, since that's all we + * need. + */ + +/** + * struct genl_multicast_group - generic netlink multicast group + * @name: name of the multicast group, names are per-family + * @id: multicast group ID, assigned by the core, to use with + * genlmsg_multicast(). + * @list: list entry for linking + * @family: pointer to family, need not be set before registering + */ +struct genl_multicast_group +{ + struct genl_family *family; /* private */ + struct list_head list; /* private */ + char name[GENL_NAMSIZ]; + u32 id; +}; + +int genl_register_mc_group(struct genl_family *family, + struct genl_multicast_group *grp); +#endif /* linux kernel < 2.6.23 */ + + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) +/** + * genlmsg_msg_size - length of genetlink message not including padding + * @payload: length of message payload + */ +static inline int genlmsg_msg_size(int payload) +{ + return GENL_HDRLEN + payload; +} + +/** + * genlmsg_total_size - length of genetlink message including padding + * @payload: length of message payload + */ +static inline int genlmsg_total_size(int payload) +{ + return NLMSG_ALIGN(genlmsg_msg_size(payload)); +} + +#define genlmsg_multicast(s, p, g, f) \ + genlmsg_multicast_flags((s), (p), (g), (f)) + +static inline int genlmsg_multicast_flags(struct sk_buff *skb, u32 pid, + unsigned int group, gfp_t flags) +{ + int err; + + NETLINK_CB(skb).dst_group = group; + + err = netlink_broadcast(genl_sock, skb, pid, group, flags); + if (err > 0) + err = 0; + + return err; +} +#endif /* linux kernel < 2.6.19 */ + + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + +#define genlmsg_put(skb, p, seq, fam, flg, c) \ + genlmsg_put((skb), (p), (seq), (fam)->id, (fam)->hdrsize, \ + (flg), (c), (fam)->version) + +/** + * genlmsg_put_reply - Add generic netlink header to a reply message + * @skb: socket buffer holding the message + * @info: receiver info + * @family: generic netlink family + * @flags: netlink message flags + * @cmd: generic netlink command + * + * Returns pointer to user specific header + */ +static inline void *genlmsg_put_reply(struct sk_buff *skb, + struct genl_info *info, struct genl_family *family, + int flags, u8 cmd) +{ + return genlmsg_put(skb, info->snd_pid, info->snd_seq, family, + flags, cmd); +} + +/** + * genlmsg_reply - reply to a request + * @skb: netlink message to be sent back + * @info: receiver information + */ +static inline int genlmsg_reply(struct sk_buff *skb, struct genl_info *info) +{ + return genlmsg_unicast(skb, info->snd_pid); +} + +/** + * genlmsg_new - Allocate a new generic netlink message + * @payload: size of the message payload + * @flags: the type of memory to allocate. + */ +static inline struct sk_buff *genlmsg_new(size_t payload, gfp_t flags) +{ + return nlmsg_new(genlmsg_total_size(payload), flags); +} +#endif /* linux kernel < 2.6.20 */ + +#endif /* genetlink.h */ diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/net/netlink.h b/openflow/datapath/linux-2.6/compat-2.6/include/net/netlink.h new file mode 100644 index 00000000..e0d594d7 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/net/netlink.h @@ -0,0 +1,22 @@ +#ifndef __NET_NETLINK_WRAPPER_H +#define __NET_NETLINK_WRAPPER_H 1 + +#include_next + +#ifndef HAVE_NLA_NUL_STRING +#define NLA_NUL_STRING NLA_STRING + +static inline int VERIFY_NUL_STRING(struct nlattr *attr) +{ + return (!attr || (nla_len(attr) + && memchr(nla_data(attr), '\0', nla_len(attr))) + ? 0 : EINVAL); +} +#else +static inline int VERIFY_NUL_STRING(struct nlattr *attr) +{ + return 0; +} +#endif /* !HAVE_NLA_NUL_STRING */ + +#endif /* net/netlink.h */ diff --git a/openflow/datapath/linux-2.6/compat-2.6/random32.c b/openflow/datapath/linux-2.6/compat-2.6/random32.c new file mode 100644 index 00000000..981b55c1 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/random32.c @@ -0,0 +1,146 @@ +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) + +/* + This is a maximally equidistributed combined Tausworthe generator + based on code from GNU Scientific Library 1.5 (30 Jun 2004) + + x_n = (s1_n ^ s2_n ^ s3_n) + + s1_{n+1} = (((s1_n & 4294967294) <<12) ^ (((s1_n <<13) ^ s1_n) >>19)) + s2_{n+1} = (((s2_n & 4294967288) << 4) ^ (((s2_n << 2) ^ s2_n) >>25)) + s3_{n+1} = (((s3_n & 4294967280) <<17) ^ (((s3_n << 3) ^ s3_n) >>11)) + + The period of this generator is about 2^88. + + From: P. L'Ecuyer, "Maximally Equidistributed Combined Tausworthe + Generators", Mathematics of Computation, 65, 213 (1996), 203--213. + + This is available on the net from L'Ecuyer's home page, + + http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme.ps + ftp://ftp.iro.umontreal.ca/pub/simulation/lecuyer/papers/tausme.ps + + There is an erratum in the paper "Tables of Maximally + Equidistributed Combined LFSR Generators", Mathematics of + Computation, 68, 225 (1999), 261--269: + http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme2.ps + + ... the k_j most significant bits of z_j must be non- + zero, for each j. (Note: this restriction also applies to the + computer code given in [4], but was mistakenly not mentioned in + that paper.) + + This affects the seeding procedure by imposing the requirement + s1 > 1, s2 > 7, s3 > 15. + +*/ + +#include +#include +#include +#include +#include + +#include "compat26.h" + +struct rnd_state { + u32 s1, s2, s3; +}; + +static struct rnd_state net_rand_state[NR_CPUS]; + +static u32 __random32(struct rnd_state *state) +{ +#define TAUSWORTHE(s,a,b,c,d) ((s&c)<>b) + + state->s1 = TAUSWORTHE(state->s1, 13, 19, 4294967294UL, 12); + state->s2 = TAUSWORTHE(state->s2, 2, 25, 4294967288UL, 4); + state->s3 = TAUSWORTHE(state->s3, 3, 11, 4294967280UL, 17); + + return (state->s1 ^ state->s2 ^ state->s3); +} + +static void __set_random32(struct rnd_state *state, unsigned long s) +{ + if (s == 0) + s = 1; /* default seed is 1 */ + +#define LCG(n) (69069 * n) + state->s1 = LCG(s); + state->s2 = LCG(state->s1); + state->s3 = LCG(state->s2); + + /* "warm it up" */ + __random32(state); + __random32(state); + __random32(state); + __random32(state); + __random32(state); + __random32(state); +} + +/** + * random32 - pseudo random number generator + * + * A 32 bit pseudo-random number is generated using a fast + * algorithm suitable for simulation. This algorithm is NOT + * considered safe for cryptographic use. + */ +u32 random32(void) +{ + return __random32(&net_rand_state[smp_processor_id()]); +} +EXPORT_SYMBOL(random32); + +/** + * srandom32 - add entropy to pseudo random number generator + * @seed: seed value + * + * Add some additional seeding to the random32() pool. + * Note: this pool is per cpu so it only affects current CPU. + */ +void srandom32(u32 entropy) +{ + struct rnd_state *state = &net_rand_state[smp_processor_id()]; + __set_random32(state, state->s1 ^ entropy); +} +EXPORT_SYMBOL(srandom32); + +static int __init random32_reseed(void); + +/* + * Generate some initially weak seeding values to allow + * to start the random32() engine. + */ +int __init random32_init(void) +{ + int i; + + for (i = 0; i < NR_CPUS; i++) { + struct rnd_state *state = &net_rand_state[i]; + __set_random32(state, i + jiffies); + } + random32_reseed(); + return 0; +} + +/* + * Generate better values after random number generator + * is fully initalized. + */ +static int __init random32_reseed(void) +{ + int i; + unsigned long seed; + + for (i = 0; i < NR_CPUS; i++) { + struct rnd_state *state = &net_rand_state[i]; + + get_random_bytes(&seed, sizeof(seed)); + __set_random32(state, seed); + } + return 0; +} + +#endif /* kernel < 2.6.19 */ diff --git a/openflow/datapath/linux-2.6/compat-2.6/veth.c b/openflow/datapath/linux-2.6/compat-2.6/veth.c new file mode 100644 index 00000000..3cda3365 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/veth.c @@ -0,0 +1,537 @@ +/* veth driver port to Linux 2.6.18 */ + +/* + * drivers/net/veth.c + * + * Copyright (C) 2007, 2009 OpenVZ http://openvz.org, SWsoft Inc + * + * Author: Pavel Emelianov + * Ethtool interface from: Eric W. Biederman + * + */ + +#include +#include +#include +#include + +#include +#include + +#define DRV_NAME "veth" +#define DRV_VERSION "1.0" + +struct veth_net_stats { + unsigned long rx_packets; + unsigned long tx_packets; + unsigned long rx_bytes; + unsigned long tx_bytes; + unsigned long tx_dropped; +}; + +struct veth_priv { + struct net_device *peer; + struct net_device *dev; + struct list_head list; + struct veth_net_stats *stats; + unsigned ip_summed; + struct net_device_stats dev_stats; +}; + +static LIST_HEAD(veth_list); + +/* + * ethtool interface + */ + +static struct { + const char string[ETH_GSTRING_LEN]; +} ethtool_stats_keys[] = { + { "peer_ifindex" }, +}; + +static int veth_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + cmd->supported = 0; + cmd->advertising = 0; + cmd->speed = SPEED_10000; + cmd->duplex = DUPLEX_FULL; + cmd->port = PORT_TP; + cmd->phy_address = 0; + cmd->transceiver = XCVR_INTERNAL; + cmd->autoneg = AUTONEG_DISABLE; + cmd->maxtxpkt = 0; + cmd->maxrxpkt = 0; + return 0; +} + +static void veth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + strcpy(info->driver, DRV_NAME); + strcpy(info->version, DRV_VERSION); + strcpy(info->fw_version, "N/A"); +} + +static void veth_get_strings(struct net_device *dev, u32 stringset, u8 *buf) +{ + switch(stringset) { + case ETH_SS_STATS: + memcpy(buf, ðtool_stats_keys, sizeof(ethtool_stats_keys)); + break; + } +} + +static void veth_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + struct veth_priv *priv; + + priv = netdev_priv(dev); + data[0] = priv->peer->ifindex; +} + +static u32 veth_get_rx_csum(struct net_device *dev) +{ + struct veth_priv *priv; + + priv = netdev_priv(dev); + return priv->ip_summed == CHECKSUM_UNNECESSARY; +} + +static int veth_set_rx_csum(struct net_device *dev, u32 data) +{ + struct veth_priv *priv; + + priv = netdev_priv(dev); + priv->ip_summed = data ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE; + return 0; +} + +static u32 veth_get_tx_csum(struct net_device *dev) +{ + return (dev->features & NETIF_F_NO_CSUM) != 0; +} + +static int veth_set_tx_csum(struct net_device *dev, u32 data) +{ + if (data) + dev->features |= NETIF_F_NO_CSUM; + else + dev->features &= ~NETIF_F_NO_CSUM; + return 0; +} + +static struct ethtool_ops veth_ethtool_ops = { + .get_settings = veth_get_settings, + .get_drvinfo = veth_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_rx_csum = veth_get_rx_csum, + .set_rx_csum = veth_set_rx_csum, + .get_tx_csum = veth_get_tx_csum, + .set_tx_csum = veth_set_tx_csum, + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, + .get_strings = veth_get_strings, + .get_ethtool_stats = veth_get_ethtool_stats, +}; + +/* + * xmit + */ + +static int veth_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct net_device *rcv = NULL; + struct veth_priv *priv, *rcv_priv; + struct veth_net_stats *stats; + int length, cpu; + + skb_orphan(skb); + + priv = netdev_priv(dev); + rcv = priv->peer; + rcv_priv = netdev_priv(rcv); + + cpu = smp_processor_id(); + stats = per_cpu_ptr(priv->stats, cpu); + + if (!(rcv->flags & IFF_UP)) + goto outf; + + skb->dev = rcv; + skb->pkt_type = PACKET_HOST; + skb->protocol = eth_type_trans(skb, rcv); + if (dev->features & NETIF_F_NO_CSUM) + skb->ip_summed = rcv_priv->ip_summed; + + dst_release(skb->dst); + skb->dst = NULL; + secpath_reset(skb); + nf_reset(skb); + + length = skb->len; + + stats->tx_bytes += length; + stats->tx_packets++; + + stats = per_cpu_ptr(rcv_priv->stats, cpu); + stats->rx_bytes += length; + stats->rx_packets++; + + netif_rx(skb); + return 0; + +outf: + kfree_skb(skb); + stats->tx_dropped++; + return 0; +} + +/* + * general routines + */ + +static struct net_device_stats *veth_get_stats(struct net_device *dev) +{ + struct veth_priv *priv; + struct net_device_stats *dev_stats; + int cpu; + struct veth_net_stats *stats; + + priv = netdev_priv(dev); + dev_stats = &priv->dev_stats; + + dev_stats->rx_packets = 0; + dev_stats->tx_packets = 0; + dev_stats->rx_bytes = 0; + dev_stats->tx_bytes = 0; + dev_stats->tx_dropped = 0; + + for_each_online_cpu(cpu) { + stats = per_cpu_ptr(priv->stats, cpu); + + dev_stats->rx_packets += stats->rx_packets; + dev_stats->tx_packets += stats->tx_packets; + dev_stats->rx_bytes += stats->rx_bytes; + dev_stats->tx_bytes += stats->tx_bytes; + dev_stats->tx_dropped += stats->tx_dropped; + } + + return dev_stats; +} + +static int veth_open(struct net_device *dev) +{ + struct veth_priv *priv; + + priv = netdev_priv(dev); + if (priv->peer == NULL) + return -ENOTCONN; + + if (priv->peer->flags & IFF_UP) { + netif_carrier_on(dev); + netif_carrier_on(priv->peer); + } + return 0; +} + +static int veth_dev_init(struct net_device *dev) +{ + struct veth_net_stats *stats; + struct veth_priv *priv; + + stats = alloc_percpu(struct veth_net_stats); + if (stats == NULL) + return -ENOMEM; + + priv = netdev_priv(dev); + priv->stats = stats; + return 0; +} + +static void veth_dev_free(struct net_device *dev) +{ + struct veth_priv *priv; + + priv = netdev_priv(dev); + free_percpu(priv->stats); + free_netdev(dev); +} + +static void veth_setup(struct net_device *dev) +{ + ether_setup(dev); + + dev->hard_start_xmit = veth_xmit; + dev->get_stats = veth_get_stats; + dev->open = veth_open; + dev->ethtool_ops = &veth_ethtool_ops; + dev->features |= NETIF_F_LLTX; + dev->init = veth_dev_init; + dev->destructor = veth_dev_free; +} + +static void veth_change_state(struct net_device *dev) +{ + struct net_device *peer; + struct veth_priv *priv; + + priv = netdev_priv(dev); + peer = priv->peer; + + if (netif_carrier_ok(peer)) { + if (!netif_carrier_ok(dev)) + netif_carrier_on(dev); + } else { + if (netif_carrier_ok(dev)) + netif_carrier_off(dev); + } +} + +static int veth_device_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct net_device *dev = ptr; + + if (dev->open != veth_open) + goto out; + + switch (event) { + case NETDEV_CHANGE: + veth_change_state(dev); + break; + } +out: + return NOTIFY_DONE; +} + +static struct notifier_block veth_notifier_block __read_mostly = { + .notifier_call = veth_device_event, +}; + +/* + * netlink interface + */ + +static int veth_newlink(const char *devname, const char *peername) +{ + int err; + const char *names[2]; + struct net_device *devs[2]; + int i; + + names[0] = devname; + names[1] = peername; + devs[0] = devs[1] = NULL; + + for (i = 0; i < 2; i++) { + struct net_device *dev; + + err = -ENOMEM; + devs[i] = alloc_netdev(sizeof(struct veth_priv), + names[i], veth_setup); + if (!devs[i]) { + goto err; + } + + dev = devs[i]; + + if (strchr(dev->name, '%')) { + err = dev_alloc_name(dev, dev->name); + if (err < 0) + goto err; + } + random_ether_addr(dev->dev_addr); + + err = register_netdevice(dev); + if (err < 0) + goto err; + + netif_carrier_off(dev); + } + + /* + * tie the devices together + */ + + for (i = 0; i < 2; i++) { + struct veth_priv *priv = netdev_priv(devs[i]); + priv->dev = devs[i]; + priv->peer = devs[!i]; + if (!i) + list_add(&priv->list, &veth_list); + else + INIT_LIST_HEAD(&priv->list); + } + return 0; + +err: + for (i = 0; i < 2; i++) { + if (devs[i]) { + if (devs[i]->reg_state != NETREG_UNINITIALIZED) + unregister_netdevice(devs[i]); + else + free_netdev(devs[i]); + } + } + return err; +} + +static void veth_dellink(struct net_device *dev) +{ + struct veth_priv *priv; + struct net_device *peer; + + priv = netdev_priv(dev); + peer = priv->peer; + + if (!list_empty(&priv->list)) + list_del(&priv->list); + + priv = netdev_priv(peer); + if (!list_empty(&priv->list)) + list_del(&priv->list); + + unregister_netdevice(dev); + unregister_netdevice(peer); +} + +/* + * sysfs + */ + +/* + * "show" function for the veth_pairs attribute. + * The class parameter is ignored. + */ +static ssize_t veth_show_veth_pairs(struct class *cls, char *buffer) +{ + int res = 0; + struct veth_priv *priv; + + list_for_each_entry(priv, &veth_list, list) { + if (res > (PAGE_SIZE - (IFNAMSIZ * 2 + 1))) { + /* not enough space for another interface name */ + if ((PAGE_SIZE - res) > 10) + res = PAGE_SIZE - 10; + res += sprintf(buffer + res, "++more++"); + break; + } + res += sprintf(buffer + res, "%s,%s ", + priv->dev->name, priv->peer->name); + } + res += sprintf(buffer + res, "\n"); + res++; + return res; +} + +/* + * "store" function for the veth_pairs attribute. This is what + * creates and deletes veth pairs. + * + * The class parameter is ignored. + * + */ +static ssize_t veth_store_veth_pairs(struct class *cls, const char *buffer, + size_t count) +{ + int c = *buffer++; + int retval; + printk("1\n"); + if (c == '+') { + char devname[IFNAMSIZ + 1] = ""; + char peername[IFNAMSIZ + 1] = ""; + char *comma = strchr(buffer, ','); + printk("2\n"); + if (!comma) + goto err_no_cmd; + strncat(devname, buffer, + min_t(int, sizeof devname, comma - buffer)); + strncat(peername, comma + 1, + min_t(int, sizeof peername, strcspn(comma + 1, "\n"))); + printk("3 '%s' '%s'\n", devname, peername); + if (!dev_valid_name(devname) || !dev_valid_name(peername)) + goto err_no_cmd; + printk("4\n"); + rtnl_lock(); + retval = veth_newlink(devname, peername); + rtnl_unlock(); + return retval ? retval : count; + } else if (c == '-') { + struct net_device *dev; + + rtnl_lock(); + dev = dev_get_by_name(buffer); + if (!dev) + retval = -ENODEV; + else if (dev->init != veth_dev_init) + retval = -EINVAL; + else { + veth_dellink(dev); + retval = count; + } + rtnl_unlock(); + + return retval; + } + +err_no_cmd: + printk(KERN_ERR DRV_NAME ": no command found in veth_pairs. Use +ifname,peername or -ifname.\n"); + return -EPERM; +} + +/* class attribute for veth_pairs file. This ends up in /sys/class/net */ +static CLASS_ATTR(veth_pairs, S_IWUSR | S_IRUGO, + veth_show_veth_pairs, veth_store_veth_pairs); + +static struct class *netdev_class; + +/* + * Initialize sysfs. This sets up the veth_pairs file in + * /sys/class/net. + */ +int veth_create_sysfs(void) +{ + struct net_device *dev = dev_get_by_name("lo"); + if (!dev) + return -ESRCH; + netdev_class = dev->class_dev.class; + if (!netdev_class) + return -ENODEV; + + return class_create_file(netdev_class, &class_attr_veth_pairs); +} + +/* + * Remove /sys/class/net/veth_pairs. + */ +void veth_destroy_sysfs(void) +{ + class_remove_file(netdev_class, &class_attr_veth_pairs); +} + + + +/* + * init/fini + */ + +static __init int veth_init(void) +{ + int retval = veth_create_sysfs(); + if (retval) + return retval; + register_netdevice_notifier(&veth_notifier_block); + return 0; +} + +static __exit void veth_exit(void) +{ + unregister_netdevice_notifier(&veth_notifier_block); +} + +module_init(veth_init); +module_exit(veth_exit); + +MODULE_DESCRIPTION("Virtual Ethernet Tunnel"); +MODULE_LICENSE("GPL v2"); diff --git a/openflow/datapath/linux-2.6/config/config-linux-2.6.23-rc9-kvm b/openflow/datapath/linux-2.6/config/config-linux-2.6.23-rc9-kvm new file mode 100644 index 00000000..f287cf72 --- /dev/null +++ b/openflow/datapath/linux-2.6/config/config-linux-2.6.23-rc9-kvm @@ -0,0 +1,1408 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.23-rc9 +# Fri Oct 19 15:08:37 2007 +# +CONFIG_X86_32=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_CLOCKSOURCE_WATCHDOG=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_SEMAPHORE_SLEEPERS=y +CONFIG_X86=y +CONFIG_MMU=y +CONFIG_ZONE_DMA=y +CONFIG_QUICKLIST=y +CONFIG_GENERIC_ISA_DMA=y +CONFIG_GENERIC_IOMAP=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_DMI=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +# CONFIG_USER_NS is not set +# CONFIG_AUDIT is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_CPUSETS is not set +CONFIG_SYSFS_DEPRECATED=y +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +# CONFIG_EMBEDDED is not set +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_KALLSYMS_EXTRA_PASS=y +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +CONFIG_LBD=y +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_LSF=y +# CONFIG_BLK_DEV_BSG is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + +# +# Processor type and features +# +# CONFIG_TICK_ONESHOT is not set +# CONFIG_NO_HZ is not set +# CONFIG_HIGH_RES_TIMERS is not set +CONFIG_SMP=y +CONFIG_X86_PC=y +# CONFIG_X86_ELAN is not set +# CONFIG_X86_VOYAGER is not set +# CONFIG_X86_NUMAQ is not set +# CONFIG_X86_SUMMIT is not set +# CONFIG_X86_BIGSMP is not set +# CONFIG_X86_VISWS is not set +# CONFIG_X86_GENERICARCH is not set +# CONFIG_X86_ES7000 is not set +# CONFIG_PARAVIRT is not set +# CONFIG_M386 is not set +CONFIG_M486=y +# CONFIG_M586 is not set +# CONFIG_M586TSC is not set +# CONFIG_M586MMX is not set +# CONFIG_M686 is not set +# CONFIG_MPENTIUMII is not set +# CONFIG_MPENTIUMIII is not set +# CONFIG_MPENTIUMM is not set +# CONFIG_MCORE2 is not set +# CONFIG_MPENTIUM4 is not set +# CONFIG_MK6 is not set +# CONFIG_MK7 is not set +# CONFIG_MK8 is not set +# CONFIG_MCRUSOE is not set +# CONFIG_MEFFICEON is not set +# CONFIG_MWINCHIPC6 is not set +# CONFIG_MWINCHIP2 is not set +# CONFIG_MWINCHIP3D is not set +# CONFIG_MGEODEGX1 is not set +# CONFIG_MGEODE_LX is not set +# CONFIG_MCYRIXIII is not set +# CONFIG_MVIAC3_2 is not set +# CONFIG_MVIAC7 is not set +CONFIG_X86_GENERIC=y +CONFIG_X86_CMPXCHG=y +CONFIG_X86_L1_CACHE_SHIFT=7 +CONFIG_X86_XADD=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_X86_PPRO_FENCE=y +CONFIG_X86_F00F_BUG=y +CONFIG_X86_WP_WORKS_OK=y +CONFIG_X86_INVLPG=y +CONFIG_X86_BSWAP=y +CONFIG_X86_POPAD_OK=y +CONFIG_X86_ALIGNMENT_16=y +CONFIG_X86_INTEL_USERCOPY=y +CONFIG_X86_MINIMUM_CPU_FAMILY=4 +# CONFIG_HPET_TIMER is not set +CONFIG_NR_CPUS=8 +# CONFIG_SCHED_SMT is not set +CONFIG_SCHED_MC=y +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_PREEMPT_BKL=y +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_IO_APIC=y +# CONFIG_X86_MCE is not set +CONFIG_VM86=y +# CONFIG_TOSHIBA is not set +# CONFIG_I8K is not set +# CONFIG_X86_REBOOTFIXUPS is not set +# CONFIG_MICROCODE is not set +# CONFIG_X86_MSR is not set +# CONFIG_X86_CPUID is not set + +# +# Firmware Drivers +# +# CONFIG_EDD is not set +# CONFIG_DELL_RBU is not set +# CONFIG_DCDBAS is not set +CONFIG_DMIID=y +# CONFIG_NOHIGHMEM is not set +CONFIG_HIGHMEM4G=y +# CONFIG_HIGHMEM64G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_HIGHMEM=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_SPARSEMEM_STATIC=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_NR_QUICK=1 +CONFIG_VIRT_TO_BUS=y +# CONFIG_HIGHPTE is not set +# CONFIG_MATH_EMULATION is not set +# CONFIG_MTRR is not set +CONFIG_IRQBALANCE=y +CONFIG_SECCOMP=y +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +# CONFIG_KEXEC is not set +# CONFIG_CRASH_DUMP is not set +CONFIG_PHYSICAL_START=0x100000 +# CONFIG_RELOCATABLE is not set +CONFIG_PHYSICAL_ALIGN=0x100000 +CONFIG_HOTPLUG_CPU=y +CONFIG_COMPAT_VDSO=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y + +# +# Power management options (ACPI, APM) +# +CONFIG_PM=y +# CONFIG_PM_LEGACY is not set +# CONFIG_PM_DEBUG is not set +CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_SLEEP=y +CONFIG_SUSPEND_SMP_POSSIBLE=y +CONFIG_SUSPEND=y +CONFIG_HIBERNATION_SMP_POSSIBLE=y +# CONFIG_HIBERNATION is not set +# CONFIG_ACPI is not set +CONFIG_APM=y +# CONFIG_APM_IGNORE_USER_SUSPEND is not set +# CONFIG_APM_DO_ENABLE is not set +# CONFIG_APM_CPU_IDLE is not set +# CONFIG_APM_DISPLAY_BLANK is not set +# CONFIG_APM_ALLOW_INTS is not set +# CONFIG_APM_REAL_MODE_POWER_OFF is not set + +# +# CPU Frequency scaling +# +# CONFIG_CPU_FREQ is not set + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +CONFIG_PCI=y +# CONFIG_PCI_GOBIOS is not set +# CONFIG_PCI_GOMMCONFIG is not set +# CONFIG_PCI_GODIRECT is not set +CONFIG_PCI_GOANY=y +CONFIG_PCI_BIOS=y +CONFIG_PCI_DIRECT=y +# CONFIG_PCIEPORTBUS is not set +CONFIG_ARCH_SUPPORTS_MSI=y +# CONFIG_PCI_MSI is not set +# CONFIG_PCI_DEBUG is not set +CONFIG_HT_IRQ=y +CONFIG_ISA_DMA_API=y +CONFIG_ISA=y +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SCx200 is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set +# CONFIG_HOTPLUG_PCI is not set + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_MISC=m + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +CONFIG_XFRM=y +CONFIG_XFRM_USER=m +CONFIG_XFRM_SUB_POLICY=y +CONFIG_XFRM_MIGRATE=y +CONFIG_NET_KEY=m +CONFIG_NET_KEY_MIGRATE=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_ASK_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +# CONFIG_IP_ROUTE_VERBOSE is not set +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INET_TUNNEL=m +CONFIG_INET_XFRM_MODE_TRANSPORT=m +CONFIG_INET_XFRM_MODE_TUNNEL=m +CONFIG_INET_XFRM_MODE_BEET=m +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_BIC=m +CONFIG_TCP_CONG_CUBIC=y +CONFIG_TCP_CONG_WESTWOOD=m +CONFIG_TCP_CONG_HTCP=m +CONFIG_TCP_CONG_HSTCP=m +CONFIG_TCP_CONG_HYBLA=m +CONFIG_TCP_CONG_VEGAS=m +CONFIG_TCP_CONG_SCALABLE=m +CONFIG_TCP_CONG_LP=m +CONFIG_TCP_CONG_VENO=m +CONFIG_TCP_CONG_YEAH=m +CONFIG_TCP_CONG_ILLINOIS=m +# CONFIG_DEFAULT_BIC is not set +CONFIG_DEFAULT_CUBIC=y +# CONFIG_DEFAULT_HTCP is not set +# CONFIG_DEFAULT_VEGAS is not set +# CONFIG_DEFAULT_WESTWOOD is not set +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_TCP_CONG="cubic" +CONFIG_TCP_MD5SIG=y +# CONFIG_IP_VS is not set +CONFIG_IPV6=m +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +# CONFIG_IPV6_MIP6 is not set +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET6_TUNNEL=m +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=m +CONFIG_IPV6_TUNNEL=m +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_NETWORK_SECMARK=y +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_BRIDGE_NETFILTER=y + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +CONFIG_NETFILTER_NETLINK_LOG=m +CONFIG_NF_CONNTRACK_ENABLED=m +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CT_ACCT=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_GRE=m +CONFIG_NF_CT_PROTO_SCTP=m +# CONFIG_NF_CT_PROTO_UDPLITE is not set +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_PPTP=m +CONFIG_NF_CONNTRACK_SANE=m +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_NETLINK=m +CONFIG_NETFILTER_XTABLES=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set +# CONFIG_NETFILTER_XT_TARGET_TRACE is not set +CONFIG_NETFILTER_XT_TARGET_SECMARK=m +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_DCCP=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_SCTP=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +# CONFIG_NETFILTER_XT_MATCH_U32 is not set +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m + +# +# IP: Netfilter Configuration +# +CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +# CONFIG_IP_NF_QUEUE is not set +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_IPRANGE=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_MATCH_ADDRTYPE=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_NF_NAT=m +CONFIG_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_SAME=m +CONFIG_NF_NAT_SNMP_BASIC=m +CONFIG_NF_NAT_PROTO_GRE=m +CONFIG_NF_NAT_FTP=m +CONFIG_NF_NAT_IRC=m +CONFIG_NF_NAT_TFTP=m +CONFIG_NF_NAT_AMANDA=m +CONFIG_NF_NAT_PPTP=m +CONFIG_NF_NAT_H323=m +CONFIG_NF_NAT_SIP=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_TARGET_CLUSTERIP=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m + +# +# IPv6: Netfilter Configuration (EXPERIMENTAL) +# +CONFIG_NF_CONNTRACK_IPV6=m +# CONFIG_IP6_NF_QUEUE is not set +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_OWNER=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_AH=m +CONFIG_IP6_NF_MATCH_MH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_HL=m +CONFIG_IP6_NF_RAW=m + +# +# DECnet: Netfilter Configuration +# +# CONFIG_DECNET_NF_GRABULATOR is not set + +# +# Bridge: Netfilter Configuration +# +# CONFIG_BRIDGE_NF_EBTABLES is not set +CONFIG_IP_DCCP=m +CONFIG_INET_DCCP_DIAG=m +CONFIG_IP_DCCP_ACKVEC=y + +# +# DCCP CCIDs Configuration (EXPERIMENTAL) +# +CONFIG_IP_DCCP_CCID2=m +# CONFIG_IP_DCCP_CCID2_DEBUG is not set +CONFIG_IP_DCCP_CCID3=m +CONFIG_IP_DCCP_TFRC_LIB=m +# CONFIG_IP_DCCP_CCID3_DEBUG is not set +CONFIG_IP_DCCP_CCID3_RTO=100 + +# +# DCCP Kernel Hacking +# +# CONFIG_IP_DCCP_DEBUG is not set +CONFIG_IP_SCTP=m +# CONFIG_SCTP_DBG_MSG is not set +# CONFIG_SCTP_DBG_OBJCNT is not set +# CONFIG_SCTP_HMAC_NONE is not set +# CONFIG_SCTP_HMAC_SHA1 is not set +CONFIG_SCTP_HMAC_MD5=y +CONFIG_TIPC=m +CONFIG_TIPC_ADVANCED=y +CONFIG_TIPC_ZONES=3 +CONFIG_TIPC_CLUSTERS=1 +CONFIG_TIPC_NODES=255 +CONFIG_TIPC_SLAVE_NODES=0 +CONFIG_TIPC_PORTS=8191 +CONFIG_TIPC_LOG=0 +# CONFIG_TIPC_DEBUG is not set +CONFIG_ATM=m +CONFIG_ATM_CLIP=m +# CONFIG_ATM_CLIP_NO_ICMP is not set +CONFIG_ATM_LANE=m +# CONFIG_ATM_MPOA is not set +CONFIG_ATM_BR2684=m +CONFIG_ATM_BR2684_IPFILTER=y +CONFIG_BRIDGE=m +CONFIG_VLAN_8021Q=m +CONFIG_DECNET=m +# CONFIG_DECNET_ROUTER is not set +CONFIG_LLC=m +CONFIG_LLC2=m +CONFIG_IPX=m +CONFIG_IPX_INTERN=y +CONFIG_ATALK=m +CONFIG_DEV_APPLETALK=m +# CONFIG_LTPC is not set +# CONFIG_COPS is not set +CONFIG_IPDDP=m +CONFIG_IPDDP_ENCAP=y +CONFIG_IPDDP_DECAP=y +CONFIG_X25=m +CONFIG_LAPB=m +CONFIG_ECONET=m +CONFIG_ECONET_AUNUDP=y +CONFIG_ECONET_NATIVE=y +CONFIG_WAN_ROUTER=m + +# +# QoS and/or fair queueing +# +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_FIFO=y + +# +# Queueing/Scheduling +# +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_ATM=m +CONFIG_NET_SCH_PRIO=m +# CONFIG_NET_SCH_RR is not set +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_SCH_INGRESS=m + +# +# Classification +# +CONFIG_NET_CLS=y +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_CLS_U32_PERF=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +CONFIG_NET_EMATCH_CMP=m +CONFIG_NET_EMATCH_NBYTE=m +CONFIG_NET_EMATCH_U32=m +CONFIG_NET_EMATCH_META=m +CONFIG_NET_EMATCH_TEXT=m +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=m +CONFIG_NET_ACT_GACT=m +CONFIG_GACT_PROB=y +CONFIG_NET_ACT_MIRRED=m +CONFIG_NET_ACT_IPT=m +CONFIG_NET_ACT_PEDIT=m +CONFIG_NET_ACT_SIMP=m +# CONFIG_NET_CLS_POLICE is not set +CONFIG_NET_CLS_IND=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +CONFIG_AF_RXRPC=m +# CONFIG_AF_RXRPC_DEBUG is not set +CONFIG_RXKAD=m +CONFIG_FIB_RULES=y + +# +# Wireless +# +# CONFIG_CFG80211 is not set +# CONFIG_WIRELESS_EXT is not set +# CONFIG_MAC80211 is not set +# CONFIG_IEEE80211 is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +CONFIG_CONNECTOR=m +# CONFIG_MTD is not set +CONFIG_PARPORT=m +CONFIG_PARPORT_PC=m +# CONFIG_PARPORT_SERIAL is not set +# CONFIG_PARPORT_PC_FIFO is not set +# CONFIG_PARPORT_PC_SUPERIO is not set +# CONFIG_PARPORT_GSC is not set +# CONFIG_PARPORT_AX88796 is not set +# CONFIG_PARPORT_1284 is not set +# CONFIG_PNP is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_NBD=m +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=m +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_MISC_DEVICES=y +# CONFIG_IBM_ASM is not set +# CONFIG_PHANTOM is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +# CONFIG_BLK_DEV_HD_IDE is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_IDE_TASK_IOCTL is not set +CONFIG_IDE_PROC_FS=y + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=y +# CONFIG_BLK_DEV_CMD640 is not set +CONFIG_BLK_DEV_IDEPCI=y +# CONFIG_IDEPCI_SHARE_IRQ is not set +CONFIG_IDEPCI_PCIBUS_ORDER=y +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_GENERIC is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_IDEDMA_PCI is not set +# CONFIG_IDE_ARM is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_BLK_DEV_IDEDMA is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_DMA is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_IEEE1394 is not set +# CONFIG_I2O is not set +# CONFIG_MACINTOSH_DRIVERS is not set +CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set +# CONFIG_IFB is not set +CONFIG_DUMMY=m +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +CONFIG_TUN=m +# CONFIG_ARCNET is not set +# CONFIG_PHYLIB is not set +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_NET_TULIP is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +CONFIG_PCNET32=y +# CONFIG_PCNET32_NAPI is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_AC3200 is not set +# CONFIG_APRICOT is not set +# CONFIG_B44 is not set +# CONFIG_FORCEDETH is not set +# CONFIG_CS89x0 is not set +# CONFIG_DGRS is not set +# CONFIG_EEPRO100 is not set +# CONFIG_E100 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +CONFIG_NE2K_PCI=y +CONFIG_8139CP=y +# CONFIG_8139TOO is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_SC92031 is not set +# CONFIG_NET_POCKET is not set +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set +# CONFIG_TR is not set + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set +# CONFIG_WAN is not set +CONFIG_ATM_DRIVERS=y +# CONFIG_ATM_DUMMY is not set +# CONFIG_ATM_TCP is not set +# CONFIG_ATM_LANAI is not set +# CONFIG_ATM_ENI is not set +# CONFIG_ATM_FIRESTREAM is not set +# CONFIG_ATM_ZATM is not set +# CONFIG_ATM_NICSTAR is not set +# CONFIG_ATM_IDT77252 is not set +# CONFIG_ATM_AMBASSADOR is not set +# CONFIG_ATM_HORIZON is not set +# CONFIG_ATM_IA is not set +# CONFIG_ATM_FORE200E_MAYBE is not set +# CONFIG_ATM_HE is not set +# CONFIG_FDDI is not set +CONFIG_HIPPI=y +# CONFIG_ROADRUNNER is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_LIFEBOOK=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_APPLETOUCH is not set +# CONFIG_MOUSE_INPORT is not set +# CONFIG_MOUSE_LOGIBM is not set +# CONFIG_MOUSE_PC110PAD is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PARKBD is not set +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_PRINTER is not set +# CONFIG_PPDEV is not set +# CONFIG_TIPAR is not set +# CONFIG_IPMI_HANDLER is not set +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_NOWAYOUT=y + +# +# Watchdog Device Drivers +# +CONFIG_SOFT_WATCHDOG=y +# CONFIG_ACQUIRE_WDT is not set +# CONFIG_ADVANTECH_WDT is not set +# CONFIG_ALIM1535_WDT is not set +# CONFIG_ALIM7101_WDT is not set +# CONFIG_SC520_WDT is not set +# CONFIG_EUROTECH_WDT is not set +# CONFIG_IB700_WDT is not set +# CONFIG_IBMASR is not set +# CONFIG_WAFER_WDT is not set +# CONFIG_I6300ESB_WDT is not set +# CONFIG_ITCO_WDT is not set +# CONFIG_SC1200_WDT is not set +# CONFIG_PC87413_WDT is not set +# CONFIG_60XX_WDT is not set +# CONFIG_SBC8360_WDT is not set +# CONFIG_CPU5_WDT is not set +# CONFIG_SMSC37B787_WDT is not set +# CONFIG_W83627HF_WDT is not set +# CONFIG_W83697HF_WDT is not set +# CONFIG_W83877F_WDT is not set +# CONFIG_W83977F_WDT is not set +# CONFIG_MACHZ_WDT is not set +# CONFIG_SBC_EPX_C3_WATCHDOG is not set + +# +# ISA-based Watchdog Cards +# +# CONFIG_PCWATCHDOG is not set +# CONFIG_MIXCOMWD is not set +# CONFIG_WDT is not set + +# +# PCI-based Watchdog Cards +# +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_WDTPCI is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_SONYPI is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_MWAVE is not set +# CONFIG_PC8736x_GPIO is not set +# CONFIG_NSC_GPIO is not set +# CONFIG_CS5535_GPIO is not set +CONFIG_RAW_DRIVER=m +CONFIG_MAX_RAW_DEVS=256 +# CONFIG_HANGCHECK_TIMER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set +CONFIG_DEVPORT=y +# CONFIG_I2C is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ABITUGURU3 is not set +# CONFIG_SENSORS_K8TEMP is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_CORETEMP is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_HDAPS is not set +# CONFIG_SENSORS_APPLESMC is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DVB_CORE is not set +# CONFIG_DAB is not set + +# +# Graphics support +# +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_VGASTATE is not set +CONFIG_VIDEO_OUTPUT_CONTROL=m +# CONFIG_FB is not set + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +# CONFIG_VGACON_SOFT_SCROLLBACK is not set +# CONFIG_VIDEO_SELECT is not set +# CONFIG_MDA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y + +# +# Sound +# +# CONFIG_SOUND is not set +CONFIG_HID_SUPPORT=y +# CONFIG_HID is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +# CONFIG_USB is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set +# CONFIG_MMC is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_INFINIBAND is not set +# CONFIG_EDAC is not set +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# +# CONFIG_AUXDISPLAY is not set +CONFIG_VIRTUALIZATION=y +# CONFIG_KVM is not set + +# +# Userspace I/O +# +# CONFIG_UIO is not set + +# +# File systems +# +# CONFIG_EXT2_FS is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +CONFIG_ROMFS_FS=m +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set +CONFIG_GENERIC_ACL=y + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=y +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +CONFIG_CONFIGFS_FS=m + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_ECRYPT_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_CRAMFS=m +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_SUNRPC_BIND34 is not set +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# Distributed Lock Manager +# +# CONFIG_DLM is not set +CONFIG_INSTRUMENTATION=y +# CONFIG_PROFILING is not set +# CONFIG_KPROBES is not set + +# +# Kernel hacking +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +# CONFIG_PRINTK_TIME is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +CONFIG_DEBUG_SLAB=y +CONFIG_DEBUG_SLAB_LEAK=y +CONFIG_DEBUG_RT_MUTEXES=y +CONFIG_DEBUG_PI_LIST=y +# CONFIG_RT_MUTEX_TESTER is not set +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_MUTEXES=y +CONFIG_DEBUG_LOCK_ALLOC=y +CONFIG_PROVE_LOCKING=y +CONFIG_LOCKDEP=y +CONFIG_LOCK_STAT=y +# CONFIG_DEBUG_LOCKDEP is not set +CONFIG_TRACE_IRQFLAGS=y +CONFIG_DEBUG_SPINLOCK_SLEEP=y +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +CONFIG_STACKTRACE=y +CONFIG_DEBUG_KOBJECT=y +CONFIG_DEBUG_HIGHMEM=y +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_VM=y +CONFIG_DEBUG_LIST=y +CONFIG_FRAME_POINTER=y +CONFIG_FORCED_INLINING=y +CONFIG_RCU_TORTURE_TEST=m +# CONFIG_FAULT_INJECTION is not set +CONFIG_EARLY_PRINTK=y +CONFIG_DEBUG_STACKOVERFLOW=y +# CONFIG_DEBUG_STACK_USAGE is not set +CONFIG_DEBUG_PAGEALLOC=y +CONFIG_DEBUG_RODATA=y +CONFIG_4KSTACKS=y +CONFIG_X86_FIND_SMP_CONFIG=y +CONFIG_X86_MPPARSE=y +CONFIG_DOUBLEFAULT=y + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_KEYS_DEBUG_PROC_KEYS is not set +# CONFIG_SECURITY is not set +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_HASH=m +CONFIG_CRYPTO_MANAGER=m +CONFIG_CRYPTO_HMAC=m +# CONFIG_CRYPTO_XCBC is not set +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +CONFIG_CRYPTO_GF128MUL=m +# CONFIG_CRYPTO_ECB is not set +CONFIG_CRYPTO_CBC=m +CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_LRW=m +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_FCRYPT=m +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_TWOFISH_586 is not set +# CONFIG_CRYPTO_SERPENT is not set +CONFIG_CRYPTO_AES=m +# CONFIG_CRYPTO_AES_586 is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +CONFIG_CRYPTO_TEA=m +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_DEFLATE=m +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_TEST is not set +CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_DEV_PADLOCK is not set +# CONFIG_CRYPTO_DEV_GEODE is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_CRC_CCITT=m +CONFIG_CRC16=m +CONFIG_CRC_ITU_T=m +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=m +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=m +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=m +CONFIG_TEXTSEARCH_BM=m +CONFIG_TEXTSEARCH_FSM=m +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_PENDING_IRQ=y +CONFIG_X86_SMP=y +CONFIG_X86_HT=y +CONFIG_X86_BIOS_REBOOT=y +CONFIG_X86_TRAMPOLINE=y +CONFIG_KTIME_SCALAR=y diff --git a/openflow/datapath/openflow-ext.c b/openflow/datapath/openflow-ext.c new file mode 100644 index 00000000..e9f87a8b --- /dev/null +++ b/openflow/datapath/openflow-ext.c @@ -0,0 +1,83 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#include "openflow/openflow-ext.h" + +#include "chain.h" +#include "datapath.h" +#include "table.h" +#include "private-msg.h" + +/*** + * Copy the new dp_desc out of the passed message + */ + +int +recv_of_set_dp_desc(struct datapath *dp, const struct sender * sender, + const struct openflow_extension_header *ofexth) +{ + struct openflow_ext_set_dp_desc * set_dp_desc = (struct openflow_ext_set_dp_desc * ) + ofexth; + memcpy(dp->dp_desc, set_dp_desc->dp_desc, DESC_STR_LEN); + dp->dp_desc[DESC_STR_LEN-1] = 0; // force null for safety + return 0; +} + + +int +openflow_ext_recv_msg(struct sw_chain *chain, const struct sender *sender, + const void *ofph) +{ + int error = 0; + const struct openflow_queue_command_header *ofexth = ofph; + + switch (ntohl(ofexth->header.subtype)) { + /**** added here as a place holder + * case OFP_EXT_QUEUE_MODIFY: { + * recv_of_exp_queue_modify(dp,sender,oh); + * return 0; + * } + * case OFP_EXT_QUEUE_DELETE: { + * recv_of_exp_queue_delete(dp,sender,oh); + * return 0; + * } + */ + case OFP_EXT_SET_DESC: + return recv_of_set_dp_desc(chain->dp,sender,ofexth); + default: + VLOG_ERR("Received unknown command of type %d", + ntohl(ofexth->header.subtype)); + return -EINVAL; + } + + return error; +} diff --git a/openflow/datapath/openflow-ext.h b/openflow/datapath/openflow-ext.h new file mode 100644 index 00000000..83edfc01 --- /dev/null +++ b/openflow/datapath/openflow-ext.h @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#ifndef OPENFLOW_EXT_H_ +#define OPENFLOW_EXT_H_ + +int openflow_ext_recv_msg(struct sw_chain *, const struct sender *, const void *); + +#endif diff --git a/openflow/datapath/private-msg.c b/openflow/datapath/private-msg.c new file mode 100644 index 00000000..96110ebf --- /dev/null +++ b/openflow/datapath/private-msg.c @@ -0,0 +1,137 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#include "openflow/private-ext.h" + +#include "chain.h" +#include "datapath.h" +#include "table.h" +#include "private-msg.h" + +struct emerg_flow_context { + struct sw_chain *chain; +}; + +static void flush_working(struct sw_chain *); +static int protection_callback(struct sw_flow *, void *); +static void do_protection(struct sw_chain *); + +static void +flush_working(struct sw_chain *chain) +{ + struct sw_flow_key key; + int num_deleted = 0; + + memset(&key, 0, sizeof(key)); + key.wildcards = OFPFW_ALL; + num_deleted = chain_delete(chain, &key, OFPP_NONE, 0, 0, 0); +} + +static int +protection_callback(struct sw_flow *flow, void *private_) +{ + struct emerg_flow_context *private + = (struct emerg_flow_context *)private_; + struct sw_flow_actions *actions = flow->sf_acts; + struct ofp_match match; + struct sw_flow *tgtflow = NULL; + int error = 0; + + tgtflow = flow_alloc(actions->actions_len, GFP_ATOMIC); + if (tgtflow == NULL) { + return -ENOMEM; + } + + /* Dup w/o idle and hard timeout. */ + memset(&match, 0, sizeof(match)); + flow_fill_match(&match, &flow->key); + flow_extract_match(&tgtflow->key, &match); + /* Fill out flow. */ + tgtflow->priority = flow->priority; + tgtflow->idle_timeout = OFP_FLOW_PERMANENT; + tgtflow->hard_timeout = OFP_FLOW_PERMANENT; + tgtflow->send_flow_rem = flow->send_flow_rem; + tgtflow->emerg_flow = 0; + flow_setup_actions(tgtflow, actions->actions, actions->actions_len); + + error = chain_insert(private->chain, tgtflow, 0); + if (error) + flow_free(tgtflow); + + return error; +} + +static void +do_protection(struct sw_chain *chain) +{ + struct emerg_flow_context private; + struct sw_flow_key key; + struct sw_table_position position; + struct sw_table *table = chain->emerg_table; + int error = 0; + + memset(&private, 0, sizeof(private)); + private.chain = chain; + memset(&key, 0, sizeof(key)); + key.wildcards = OFPFW_ALL; + memset(&position, 0, sizeof(position)); + + error = table->iterate(table, &key, OFPP_NONE, + &position, protection_callback, &private); +} + +int +private_recv_msg(struct sw_chain *chain, const struct sender *sender, + const void *ofph) +{ + int error = 0; + struct private_vxhdr *vxhdr = (struct private_vxhdr *)ofph; + struct private_vxopt *vxopt = (struct private_vxopt *)(vxhdr + 1); + + switch (ntohs(vxopt->pvo_type)) { + case PRIVATEOPT_PROTOCOL_STATS_REQUEST: + case PRIVATEOPT_PROTOCOL_STATS_REPLY: + break; + case PRIVATEOPT_EMERG_FLOW_PROTECTION: + flush_working(chain); + do_protection(chain); + break; + case PRIVATEOPT_EMERG_FLOW_RESTORATION: + /* Nothing to do because we assume that a re-connected + * controller will do flush current working flow table. */ + break; + default: + error = -EINVAL; + } + + return error; +} diff --git a/openflow/datapath/private-msg.h b/openflow/datapath/private-msg.h new file mode 100644 index 00000000..246aa541 --- /dev/null +++ b/openflow/datapath/private-msg.h @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#ifndef PRIVATE_MSG_H_ +#define PRIVATE_MSG_H_ + +int private_recv_msg(struct sw_chain *, const struct sender *, const void *); + +#endif diff --git a/openflow/datapath/table-hash.c b/openflow/datapath/table-hash.c new file mode 100644 index 00000000..8e5a97b7 --- /dev/null +++ b/openflow/datapath/table-hash.c @@ -0,0 +1,489 @@ +/* + * Distributed under the terms of the GNU GPL version 2. + * Copyright (c) 2007, 2008, 2009 The Board of Trustees of The Leland + * Stanford Junior University + */ + +#include "table.h" +#include "crc32.h" +#include "flow.h" +#include "datapath.h" + +#include +#include +#include +#include +#include + +static void *kmem_alloc(size_t); +static void *kmem_zalloc(size_t); +static void kmem_free(void *, size_t); + +struct sw_table_hash { + struct sw_table swt; + struct crc32 crc32; + unsigned int n_flows; + unsigned int bucket_mask; /* Number of buckets minus 1. */ + struct sw_flow **buckets; +}; + +static struct sw_flow **find_bucket(struct sw_table *swt, + const struct sw_flow_key *key) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + unsigned int crc = crc32_calculate(&th->crc32, key, + offsetof(struct sw_flow_key, wildcards)); + return &th->buckets[crc & th->bucket_mask]; +} + +static struct sw_flow *table_hash_lookup(struct sw_table *swt, + const struct sw_flow_key *key) +{ + struct sw_flow *flow = *find_bucket(swt, key); + return flow && flow_keys_equal(&flow->key, key) ? flow : NULL; +} + +static int table_hash_insert(struct sw_table *swt, struct sw_flow *flow) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + struct sw_flow **bucket; + int retval; + + if (flow->key.wildcards != 0) + return 0; + + bucket = find_bucket(swt, &flow->key); + if (*bucket == NULL) { + th->n_flows++; + rcu_assign_pointer(*bucket, flow); + retval = 1; + } else { + struct sw_flow *old_flow = *bucket; + if (flow_keys_equal(&old_flow->key, &flow->key)) { + rcu_assign_pointer(*bucket, flow); + flow_deferred_free(old_flow); + retval = 1; + } else { + retval = 0; + } + } + return retval; +} + +static int table_hash_modify(struct sw_table *swt, + const struct sw_flow_key *key, uint16_t priority, int strict, + const struct ofp_action_header *actions, size_t actions_len) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + unsigned int count = 0; + + if (key->wildcards == 0) { + struct sw_flow **bucket = find_bucket(swt, key); + struct sw_flow *flow = *bucket; + if (flow && flow_matches_desc(&flow->key, key, strict) + && (!strict || (flow->priority == priority))) { + flow_replace_acts(flow, actions, actions_len); + count = 1; + } + } else { + unsigned int i; + + for (i = 0; i <= th->bucket_mask; i++) { + struct sw_flow **bucket = &th->buckets[i]; + struct sw_flow *flow = *bucket; + if (flow && flow_matches_desc(&flow->key, key, strict) + && (!strict || (flow->priority == priority))) { + flow_replace_acts(flow, actions, actions_len); + count++; + } + } + } + return count; +} + +static int table_hash_has_conflict(struct sw_table *swt, + const struct sw_flow_key *key, + uint16_t priority, int strict) +{ + struct sw_table_hash *th = (struct sw_table_hash *)swt; + + if (key->wildcards == 0) { + struct sw_flow **bucket = find_bucket(swt, key); + struct sw_flow *flow = *bucket; + if (flow && flow_matches_2desc(&flow->key, key,strict) + && (flow->priority == priority)) { + return true; + } + } else { + unsigned int i; + + for (i = 0; i <= th->bucket_mask; i++) { + struct sw_flow **bucket = &th->buckets[i]; + struct sw_flow *flow = *bucket; + if (flow && flow_matches_2desc(&flow->key, key, strict) + && (flow->priority == priority)) { + return true; + } + } + } + return false; +} + +/* Caller must update n_flows. */ +static int do_delete(struct datapath *dp, struct sw_flow **bucket, + struct sw_flow *flow, enum ofp_flow_removed_reason reason) +{ + dp_send_flow_end(dp, flow, reason); + rcu_assign_pointer(*bucket, NULL); + flow_deferred_free(flow); + return 1; +} + +/* Returns number of deleted flows. We can ignore the priority + * argument, since all exact-match entries are the same (highest) + * priority. */ +static int table_hash_delete(struct datapath *dp, struct sw_table *swt, + const struct sw_flow_key *key, uint16_t out_port, + uint16_t priority, int strict) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + unsigned int count = 0; + + if (key->wildcards == 0) { + struct sw_flow **bucket = find_bucket(swt, key); + struct sw_flow *flow = *bucket; + if (flow && flow_keys_equal(&flow->key, key) + && flow_has_out_port(flow, out_port)) + count = do_delete(dp, bucket, flow, OFPRR_DELETE); + } else { + unsigned int i; + + for (i = 0; i <= th->bucket_mask; i++) { + struct sw_flow **bucket = &th->buckets[i]; + struct sw_flow *flow = *bucket; + if (flow && flow_matches_desc(&flow->key, key, strict) + && flow_has_out_port(flow, out_port)) + count += do_delete(dp, bucket, flow, OFPRR_DELETE); + } + } + th->n_flows -= count; + return count; +} + +static int table_hash_timeout(struct datapath *dp, struct sw_table *swt) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + unsigned int i; + int count = 0; + + if (mutex_lock_interruptible(&dp_mutex)) + return 0; + for (i = 0; i <= th->bucket_mask; i++) { + struct sw_flow **bucket = &th->buckets[i]; + struct sw_flow *flow = *bucket; + if (flow) { + int reason = flow_timeout(flow); + if (reason >= 0) { + count += do_delete(dp, bucket, flow, reason); + } + } + } + th->n_flows -= count; + mutex_unlock(&dp_mutex); + + return count; +} + +static void table_hash_destroy(struct sw_table *swt) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + unsigned int i; + for (i = 0; i <= th->bucket_mask; i++) + if (th->buckets[i]) + flow_free(th->buckets[i]); + kmem_free(th->buckets, (th->bucket_mask + 1) * sizeof *th->buckets); + kfree(th); +} + +static int table_hash_iterate(struct sw_table *swt, + const struct sw_flow_key *key, uint16_t out_port, + struct sw_table_position *position, + int (*callback)(struct sw_flow *, void *private), + void *private) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + + if (position->private[0] > th->bucket_mask) + return 0; + + if (key->wildcards == 0) { + struct sw_flow *flow; + int error; + + flow = table_hash_lookup(swt, key); + if (!flow || !flow_has_out_port(flow, out_port)) + return 0; + + error = callback(flow, private); + if (!error) + position->private[0] = -1; + return error; + } else { + int i; + + for (i = position->private[0]; i <= th->bucket_mask; i++) { + struct sw_flow *flow = th->buckets[i]; + if (flow && flow_matches_1wild(&flow->key, key) + && flow_has_out_port(flow, out_port)) { + int error = callback(flow, private); + if (error) { + position->private[0] = i; + return error; + } + } + } + return 0; + } +} +static void table_hash_stats(struct sw_table *swt, + struct sw_table_stats *stats) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + stats->name = "hash"; + stats->wildcards = 0; /* No wildcards are supported. */ + stats->n_flows = th->n_flows; + stats->max_flows = th->bucket_mask + 1; + stats->n_lookup = swt->n_lookup; + stats->n_matched = swt->n_matched; +} + +struct sw_table *table_hash_create(unsigned int polynomial, + unsigned int n_buckets) +{ + struct sw_table_hash *th; + struct sw_table *swt; + + th = kzalloc(sizeof *th, GFP_KERNEL); + if (th == NULL) + return NULL; + + BUG_ON(n_buckets & (n_buckets - 1)); + th->buckets = kmem_zalloc(n_buckets * sizeof *th->buckets); + if (th->buckets == NULL) { + printk(KERN_EMERG "failed to allocate %u buckets\n", + n_buckets); + kfree(th); + return NULL; + } + th->bucket_mask = n_buckets - 1; + + swt = &th->swt; + swt->lookup = table_hash_lookup; + swt->insert = table_hash_insert; + swt->has_conflict = table_hash_has_conflict; + swt->delete = table_hash_delete; + swt->timeout = table_hash_timeout; + swt->destroy = table_hash_destroy; + swt->iterate = table_hash_iterate; + swt->stats = table_hash_stats; + + crc32_init(&th->crc32, polynomial); + th->n_flows = 0; + + return swt; +} + +/* Double-hashing table. */ + +struct sw_table_hash2 { + struct sw_table swt; + struct sw_table *subtable[2]; +}; + +static struct sw_flow *table_hash2_lookup(struct sw_table *swt, + const struct sw_flow_key *key) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + int i; + + for (i = 0; i < 2; i++) { + struct sw_flow *flow = *find_bucket(t2->subtable[i], key); + if (flow && flow_keys_equal(&flow->key, key)) + return flow; + } + return NULL; +} + +static int table_hash2_insert(struct sw_table *swt, struct sw_flow *flow) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + + if (table_hash_insert(t2->subtable[0], flow)) + return 1; + return table_hash_insert(t2->subtable[1], flow); +} + +static int table_hash2_modify(struct sw_table *swt, + const struct sw_flow_key *key, uint16_t priority, int strict, + const struct ofp_action_header *actions, size_t actions_len) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + return (table_hash_modify(t2->subtable[0], key, priority, strict, + actions, actions_len) + + table_hash_modify(t2->subtable[1], key, priority, strict, + actions, actions_len)); +} + +static int table_hash2_has_conflict(struct sw_table *swt, + const struct sw_flow_key *key, + uint16_t priority, int strict) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + return (table_hash_has_conflict(t2->subtable[0], key, priority, strict) || + table_hash_has_conflict(t2->subtable[1], key, priority, strict)); +} + +static int table_hash2_delete(struct datapath *dp, struct sw_table *swt, + const struct sw_flow_key *key, + uint16_t out_port, + uint16_t priority, int strict) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + return (table_hash_delete(dp, t2->subtable[0], key, out_port, + priority, strict) + + table_hash_delete(dp, t2->subtable[1], key, out_port, + priority, strict)); +} + +static int table_hash2_timeout(struct datapath *dp, struct sw_table *swt) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + return (table_hash_timeout(dp, t2->subtable[0]) + + table_hash_timeout(dp, t2->subtable[1])); +} + +static void table_hash2_destroy(struct sw_table *swt) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + table_hash_destroy(t2->subtable[0]); + table_hash_destroy(t2->subtable[1]); + kfree(t2); +} + +static int table_hash2_iterate(struct sw_table *swt, + const struct sw_flow_key *key, uint16_t out_port, + struct sw_table_position *position, + int (*callback)(struct sw_flow *, void *), + void *private) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + int i; + + for (i = position->private[1]; i < 2; i++) { + int error = table_hash_iterate(t2->subtable[i], key, out_port, + position, callback, private); + if (error) { + return error; + } + position->private[0] = 0; + position->private[1]++; + } + return 0; +} + +static void table_hash2_stats(struct sw_table *swt, + struct sw_table_stats *stats) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + struct sw_table_stats substats[2]; + int i; + + for (i = 0; i < 2; i++) + table_hash_stats(t2->subtable[i], &substats[i]); + stats->name = "hash2"; + stats->wildcards = 0; /* No wildcards are supported. */ + stats->n_flows = substats[0].n_flows + substats[1].n_flows; + stats->max_flows = substats[0].max_flows + substats[1].max_flows; + stats->n_lookup = swt->n_lookup; + stats->n_matched = swt->n_matched; +} + +struct sw_table *table_hash2_create(unsigned int poly0, unsigned int buckets0, + unsigned int poly1, unsigned int buckets1) + +{ + struct sw_table_hash2 *t2; + struct sw_table *swt; + + t2 = kzalloc(sizeof *t2, GFP_KERNEL); + if (t2 == NULL) + return NULL; + + t2->subtable[0] = table_hash_create(poly0, buckets0); + if (t2->subtable[0] == NULL) + goto out_free_t2; + + t2->subtable[1] = table_hash_create(poly1, buckets1); + if (t2->subtable[1] == NULL) + goto out_free_subtable0; + + swt = &t2->swt; + swt->lookup = table_hash2_lookup; + swt->insert = table_hash2_insert; + swt->modify = table_hash2_modify; + swt->has_conflict = table_hash2_has_conflict; + swt->delete = table_hash2_delete; + swt->timeout = table_hash2_timeout; + swt->destroy = table_hash2_destroy; + swt->iterate = table_hash2_iterate; + swt->stats = table_hash2_stats; + + return swt; + +out_free_subtable0: + table_hash_destroy(t2->subtable[0]); +out_free_t2: + kfree(t2); + return NULL; +} + +/* From fs/xfs/linux-2.4/kmem.c. */ + +static void * +kmem_alloc(size_t size) +{ + void *ptr; + +#ifdef KMALLOC_MAX_SIZE + if (size > KMALLOC_MAX_SIZE) + return NULL; +#endif + ptr = kmalloc(size, GFP_KERNEL); + if (!ptr) { + ptr = vmalloc(size); + if (ptr) + printk(KERN_NOTICE "openflow: used vmalloc for %lu " + "bytes\n", (unsigned long)size); + } + return ptr; +} + +static void * +kmem_zalloc(size_t size) +{ + void *ptr = kmem_alloc(size); + if (ptr) + memset(ptr, 0, size); + return ptr; +} + +static void +kmem_free(void *ptr, size_t size) +{ + if (((unsigned long)ptr < VMALLOC_START) || + ((unsigned long)ptr >= VMALLOC_END)) { + kfree(ptr); + } else { + vfree(ptr); + } +} diff --git a/openflow/datapath/table-linear.c b/openflow/datapath/table-linear.c new file mode 100644 index 00000000..79a95dfb --- /dev/null +++ b/openflow/datapath/table-linear.c @@ -0,0 +1,233 @@ +/* + * Distributed under the terms of the GNU GPL version 2. + * Copyright (c) 2007, 2008, 2009 The Board of Trustees of The Leland + * Stanford Junior University + */ + +#include "table.h" +#include "flow.h" +#include "datapath.h" + +#include +#include +#include + +struct sw_table_linear { + struct sw_table swt; + + unsigned int max_flows; + unsigned int n_flows; + struct list_head flows; + struct list_head iter_flows; + unsigned long int next_serial; +}; + +static struct sw_flow *table_linear_lookup(struct sw_table *swt, + const struct sw_flow_key *key) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + struct sw_flow *flow; + list_for_each_entry_rcu (flow, &tl->flows, node) { + if (flow_matches_1wild(key, &flow->key)) + return flow; + } + return NULL; +} + +static int table_linear_insert(struct sw_table *swt, struct sw_flow *flow) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + struct sw_flow *f; + + + /* Loop through the existing list of entries. New entries will + * always be placed behind those with equal priority. Just replace + * any flows that match exactly. + */ + list_for_each_entry (f, &tl->flows, node) { + if (f->priority == flow->priority + && f->key.wildcards == flow->key.wildcards + && flow_matches_2wild(&f->key, &flow->key)) { + flow->serial = f->serial; + list_replace_rcu(&f->node, &flow->node); + list_replace_rcu(&f->iter_node, &flow->iter_node); + flow_deferred_free(f); + return 1; + } + + if (f->priority < flow->priority) + break; + } + + /* Make sure there's room in the table. */ + if (tl->n_flows >= tl->max_flows) { + return 0; + } + tl->n_flows++; + + /* Insert the entry immediately in front of where we're pointing. */ + flow->serial = tl->next_serial++; + list_add_tail_rcu(&flow->node, &f->node); + list_add_rcu(&flow->iter_node, &tl->iter_flows); + return 1; +} + +static int table_linear_modify(struct sw_table *swt, + const struct sw_flow_key *key, uint16_t priority, int strict, + const struct ofp_action_header *actions, size_t actions_len) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + struct sw_flow *flow; + unsigned int count = 0; + + list_for_each_entry (flow, &tl->flows, node) { + if (flow_matches_desc(&flow->key, key, strict) + && (!strict || (flow->priority == priority))) { + flow_replace_acts(flow, actions, actions_len); + count++; + } + } + return count; +} + +static int table_linear_has_conflict(struct sw_table *swt, + const struct sw_flow_key *key, uint16_t priority, int strict) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + struct sw_flow *flow; + + list_for_each_entry (flow, &tl->flows, node) { + if (flow_matches_2desc(&flow->key, key, strict) + && (flow->priority == priority)) { + return true; + } + } + return false; +} + +static int do_delete(struct datapath *dp, struct sw_table *swt, + struct sw_flow *flow, enum ofp_flow_removed_reason reason) +{ + dp_send_flow_end(dp, flow, reason); + list_del_rcu(&flow->node); + list_del_rcu(&flow->iter_node); + flow_deferred_free(flow); + return 1; +} + +static int table_linear_delete(struct datapath *dp, struct sw_table *swt, + const struct sw_flow_key *key, uint16_t out_port, + uint16_t priority, int strict) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + struct sw_flow *flow; + unsigned int count = 0; + + list_for_each_entry (flow, &tl->flows, node) { + if (flow_matches_desc(&flow->key, key, strict) + && flow_has_out_port(flow, out_port) + && (!strict || (flow->priority == priority))) + count += do_delete(dp, swt, flow, OFPRR_DELETE); + } + tl->n_flows -= count; + return count; +} + +static int table_linear_timeout(struct datapath *dp, struct sw_table *swt) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + struct sw_flow *flow; + int count = 0; + + if (mutex_lock_interruptible(&dp_mutex)) + return 0; + list_for_each_entry (flow, &tl->flows, node) { + int reason = flow_timeout(flow); + if (reason >= 0) { + count += do_delete(dp, swt, flow, reason); + } + } + tl->n_flows -= count; + mutex_unlock(&dp_mutex); + return count; +} + +static void table_linear_destroy(struct sw_table *swt) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + + while (!list_empty(&tl->flows)) { + struct sw_flow *flow = list_entry(tl->flows.next, + struct sw_flow, node); + list_del(&flow->node); + flow_free(flow); + } + kfree(tl); +} + +static int table_linear_iterate(struct sw_table *swt, + const struct sw_flow_key *key, uint16_t out_port, + struct sw_table_position *position, + int (*callback)(struct sw_flow *, void *), + void *private) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + struct sw_flow *flow; + unsigned long start; + + start = position->private[0]; + list_for_each_entry (flow, &tl->iter_flows, iter_node) { + if (flow->serial >= start + && flow_matches_2wild(key, &flow->key) + && flow_has_out_port(flow, out_port)) { + int error = callback(flow, private); + if (error) { + position->private[0] = flow->serial; + return error; + } + } + } + return 0; +} + +static void table_linear_stats(struct sw_table *swt, + struct sw_table_stats *stats) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + stats->name = "linear"; + stats->wildcards = OFPFW_ALL; + stats->n_flows = tl->n_flows; + stats->max_flows = tl->max_flows; + stats->n_lookup = swt->n_lookup; + stats->n_matched = swt->n_matched; +} + + +struct sw_table *table_linear_create(unsigned int max_flows) +{ + struct sw_table_linear *tl; + struct sw_table *swt; + + tl = kzalloc(sizeof *tl, GFP_KERNEL); + if (tl == NULL) + return NULL; + + swt = &tl->swt; + swt->lookup = table_linear_lookup; + swt->insert = table_linear_insert; + swt->modify = table_linear_modify; + swt->has_conflict = table_linear_has_conflict; + swt->delete = table_linear_delete; + swt->timeout = table_linear_timeout; + swt->destroy = table_linear_destroy; + swt->iterate = table_linear_iterate; + swt->stats = table_linear_stats; + + tl->max_flows = max_flows; + tl->n_flows = 0; + INIT_LIST_HEAD(&tl->flows); + INIT_LIST_HEAD(&tl->iter_flows); + tl->next_serial = 0; + + return swt; +} diff --git a/openflow/datapath/table.h b/openflow/datapath/table.h new file mode 100644 index 00000000..1cc90a01 --- /dev/null +++ b/openflow/datapath/table.h @@ -0,0 +1,119 @@ +/* Individual switching tables. Generally grouped together in a chain (see + * chain.h). */ + +#ifndef TABLE_H +#define TABLE_H 1 + +#include + +struct sw_flow; +struct sw_flow_key; +struct ofp_action_header; +struct datapath; + +/* Table statistics. */ +struct sw_table_stats { + const char *name; /* Human-readable name. */ + uint32_t wildcards; /* Bitmap of OFPFW_* wildcards that are + supported by the table. */ + unsigned int n_flows; /* Number of active flows. */ + unsigned int max_flows; /* Flow capacity. */ + unsigned long int n_lookup; /* Number of packets looked up. */ + unsigned long int n_matched; /* Number of packets that have hit. */ +}; + +/* Position within an iteration of a sw_table. + * + * The contents are private to the table implementation, except that a position + * initialized to all-zero-bits represents the start of a table. */ +struct sw_table_position { + unsigned long private[4]; +}; + +/* A single table of flows. + * + * All functions, except destroy, must be called holding the + * rcu_read_lock. destroy must be fully serialized. + */ +struct sw_table { + /* The number of packets that have been looked up and matched, + * respecitvely. To make these 100% accurate, they should be atomic. + * However, we're primarily concerned about speed. */ + unsigned long long n_lookup; + unsigned long long n_matched; + + /* Searches 'table' for a flow matching 'key', which must not have any + * wildcard fields. Returns the flow if successful, a null pointer + * otherwise. */ + struct sw_flow *(*lookup)(struct sw_table *table, + const struct sw_flow_key *key); + + /* Inserts 'flow' into 'table', replacing any duplicate flow. Returns + * 0 if successful or a negative error. Error can be due to an + * over-capacity table or because the flow is not one of the kind that + * the table accepts. + * + * If successful, 'flow' becomes owned by 'table', otherwise it is + * retained by the caller. */ + int (*insert)(struct sw_table *table, struct sw_flow *flow); + + /* Modifies the actions in 'table' that match 'key'. If 'strict' + * set, wildcards and priority must match. Returns the number of flows + * that were modified. */ + int (*modify)(struct sw_table *table, const struct sw_flow_key *key, + uint16_t priority, int strict, + const struct ofp_action_header *actions, size_t actions_len); + + /* Checks whether 'table' has an equal priotiry entry of thethat conflicts + * with 'key'. If 'strict' is set, wildcards must match. + * Returns the number of flows that were modified. */ + int (*has_conflict)(struct sw_table *table, const struct sw_flow_key *key, + uint16_t priority, int strict); + + /* Deletes from 'table' any and all flows that match 'key' from + * 'table'. If 'out_port' is not OFPP_NONE, then matching entries + * must have that port as an argument for an output action. If + * 'strict' is set, wildcards and priority must match. Returns the + * number of flows that were deleted. */ + int (*delete)(struct datapath *dp, struct sw_table *table, + const struct sw_flow_key *key, + uint16_t out_port, uint16_t priority, int strict); + + /* Performs timeout processing on all the flow entries in 'table'. + * Returns the number of flow entries deleted through expiration. */ + int (*timeout)(struct datapath *dp, struct sw_table *table); + + /* Destroys 'table', which must not have any users. */ + void (*destroy)(struct sw_table *table); + + /* Iterates through the flow entries in 'table', passing each one + * matches 'key' and output port 'out_port' to 'callback'. The + * callback function should return 0 to continue iteration or a + * nonzero error code to stop. The iterator function returns either + * 0 if the table iteration completed or the value returned by the + * callback function otherwise. + * + * The iteration starts at 'position', which may be initialized to + * all-zero-bits to iterate from the beginning of the table. If the + * iteration terminates due to an error from the callback function, + * 'position' is updated to a value that can be passed back to the + * iterator function to continue iteration later from the same position + * that caused the error (assuming that that flow entry has not been + * deleted in the meantime). */ + int (*iterate)(struct sw_table *table, + const struct sw_flow_key *key, uint16_t out_port, + struct sw_table_position *position, + int (*callback)(struct sw_flow *flow, void *private), + void *private); + + /* Dumps statistics for 'table' into 'stats'. */ + void (*stats)(struct sw_table *table, struct sw_table_stats *stats); +}; + +struct sw_table *table_hash_create(unsigned int polynomial, + unsigned int n_buckets); +struct sw_table *table_hash2_create(unsigned int poly0, unsigned int buckets0, + unsigned int poly1, unsigned int buckets1); +struct sw_table *table_linear_create(unsigned int max_flows); + +#endif /* table.h */ diff --git a/openflow/debian/.gitignore b/openflow/debian/.gitignore new file mode 100644 index 00000000..1df6fba1 --- /dev/null +++ b/openflow/debian/.gitignore @@ -0,0 +1,38 @@ +*.debhelper +*.debhelper.log +*.substvars +/automake.mk +/control +/corekeeper +/files +/nicira-switch +/openflow +/openflow-common +/openflow-common.copyright +/openflow-controller +/openflow-datapath-source +/openflow-dbg +/openflow-monitor +/openflow-monitor.copyright +/openflow-monitor.default +/openflow-monitor.dirs +/openflow-monitor.init +/openflow-monitor.install +/openflow-pki +/openflow-pki-server +/openflow-switch +/openflow-switch-config +/openflow-switch.copyright +/openflow-switchui +/openflow-switchui.copyright +/openflow-switchui.default +/openflow-switchui.dirs +/openflow-switchui.init +/openflow-switchui.install +/openflow-wdt +/openflow-wdt.copyright +/openflow-wdt.default +/openflow-wdt.dirs +/openflow-wdt.init +/openflow-wdt.install +/rules.ext diff --git a/openflow/debian/changelog b/openflow/debian/changelog new file mode 100644 index 00000000..235187e5 --- /dev/null +++ b/openflow/debian/changelog @@ -0,0 +1,23 @@ +openflow (1.0.0) unstable; urgency=low + + * Development version + + -- OpenFlow team Thu, 31 Dec 2009 23:59:59 -0800 + +openflow (0.9.0-rev1) unstable; urgency=low + + * Development version. + + -- OpenFlow team Fri, 04 Sep 2009 12:00:00 -0800 + +openflow (0.8.9-rev4) unstable; urgency=low + + * Develoment version. + + -- OpenFlow team Tue, 15 Sep 2009 12:00:00 -0800 + +openflow (0.8.1) unstable; urgency=low + + * Development version. + + -- OpenFlow team Mon, 19 Nov 2007 14:57:52 -0800 diff --git a/openflow/debian/commands/reconfigure b/openflow/debian/commands/reconfigure new file mode 100755 index 00000000..a9610524 --- /dev/null +++ b/openflow/debian/commands/reconfigure @@ -0,0 +1,128 @@ +#! /usr/bin/perl + +use POSIX; +use strict; +use warnings; + +my $default = '/etc/default/openflow-switch'; + +my (%config) = load_config($default); +if (@ARGV) { + foreach my $arg (@ARGV) { + my ($key, $value) = $arg =~ /^([^=]+)=(.*)/ + or die "bad argument '$arg'\n"; + if ($value ne '') { + $config{$key} = $value; + } else { + delete $config{$key}; + } + } + save_config($default, %config); +} +print "$_=$config{$_}\n" foreach sort(keys(%config)); + +sub load_config { + my ($file) = @_; + + # Get the list of the variables that the shell sets automatically. + my (%auto_vars) = read_vars("set -a && env"); + + # Get the variables from $default. + my (%config) = read_vars("set -a && . '$default' && env"); + + # Subtract. + delete @config{keys %auto_vars}; + + return %config; +} + +sub read_vars { + my ($cmd) = @_; + local @ENV; + if (!open(VARS, '-|', $cmd)) { + print STDERR "$cmd: failed to execute: $!\n"; + return (); + } + my (%config); + while () { + my ($var, $value) = /^([^=]+)=(.*)$/ or next; + $config{$var} = $value; + } + close(VARS); + return %config; +} + +sub shell_escape { + local $_ = $_[0]; + if ($_ eq '') { + return '""'; + } elsif (m&^[-a-zA-Z0-9:./%^_+,]*$&) { + return $_; + } else { + s/'/'\\''/; + return "'$_'"; + } +} + +sub shell_assign { + my ($var, $value) = @_; + return $var . '=' . shell_escape($value); +} + +sub save_config { + my ($file, %config) = @_; + my (@lines); + if (open(FILE, '<', $file)) { + @lines = ; + chomp @lines; + close(FILE); + } + + # Replace all existing variable assignments. + for (my ($i) = 0; $i <= $#lines; $i++) { + local $_ = $lines[$i]; + my ($var, $value) = /^\s*([^=#]+)=(.*)$/ or next; + if (exists($config{$var})) { + $lines[$i] = shell_assign($var, $config{$var}); + delete $config{$var}; + } else { + $lines[$i] = "#$lines[$i]"; + } + } + + # Find a place to put any remaining variable assignments. + VAR: + for my $var (keys(%config)) { + my $assign = shell_assign($var, $config{$var}); + + # Replace the last commented-out variable assignment to $var, if any. + for (my ($i) = $#lines; $i >= 0; $i--) { + local $_ = $lines[$i]; + if (/^\s*#\s*$var=/) { + $lines[$i] = $assign; + next VAR; + } + } + + # Find a place to add the var: after the final commented line + # just after a line that contains "$var:". + for (my ($i) = 0; $i <= $#lines; $i++) { + if ($lines[$i] =~ /^\s*#\s*$var:/) { + for (my ($j) = $i + 1; $j <= $#lines; $j++) { + if ($lines[$j] !~ /^\s*#/) { + splice(@lines, $j, 0, $assign); + next VAR; + } + } + } + } + + # Just append it. + push(@lines, $assign); + } + + open(NEWFILE, '>', "$file.tmp") or die "$file.tmp: create: $!\n"; + print NEWFILE join('', map("$_\n", @lines)); + close(NEWFILE); + rename("$file.tmp", $file) or die "$file.tmp: rename to $file: $!\n"; +} diff --git a/openflow/debian/commands/update b/openflow/debian/commands/update new file mode 100755 index 00000000..545e3c23 --- /dev/null +++ b/openflow/debian/commands/update @@ -0,0 +1,4 @@ +#! /bin/sh +set -e +apt-get update -qy +apt-get upgrade -qy diff --git a/openflow/debian/compat b/openflow/debian/compat new file mode 100644 index 00000000..7ed6ff82 --- /dev/null +++ b/openflow/debian/compat @@ -0,0 +1 @@ +5 diff --git a/openflow/debian/control.in b/openflow/debian/control.in new file mode 100644 index 00000000..2e14410d --- /dev/null +++ b/openflow/debian/control.in @@ -0,0 +1,93 @@ +Source: openflow +Section: net +Priority: extra +Maintainer: OpenFlow Team +Build-Depends: debhelper (>= 5), autoconf (>= 2.60), automake1.10 | automake1.11 | automake (>= 1.10), libssl-dev, pkg-config (>= 0.21), po-debconf, bzip2, openssl, libncurses5-dev, libpcre3-dev +Standards-Version: 3.7.3 + +Package: openflow-datapath-source +Architecture: all +Depends: module-assistant, bzip2, debhelper (>= 5.0.37) +Suggests: openflow-switch +Description: Source code for OpenFlow datapath Linux module + This package provides the OpenFlow datapath module source code that + is needed by the kernel-based OpenFlow switch. The kernel module can + be built from it using module-assistant or make-kpkg. README.Debian + in this package provides further instructions. + . + OpenFlow is a protocol for flow-based control over network switching. + +Package: openflow-common +Architecture: any +Depends: ${shlibs:Depends}, openssl +Description: OpenFlow common components + openflow-common provides components required by both openflow-switch + and openflow-controller. + . + OpenFlow is a protocol for flow-based control over network switching. + +Package: openflow-switch +Architecture: any +Suggests: openflow-datapath-module +Depends: ${shlibs:Depends}, ${misc:Depends}, openflow-common, dhcp3-client, module-init-tools, dmidecode, procps, debianutils +Description: OpenFlow switch implementations + openflow-switch provides the userspace components and utilities for + the OpenFlow kernel-based switch. + . + OpenFlow is a protocol for flow-based control over network switching. + +Package: openflow-switch-config +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, openflow-switch, libwww-perl, libdigest-sha1-perl +Description: OpenFlow switch implementations + openflow-switch-config provides a utility for interactively configuring + the OpenFlow switch provided in the openflow-switch package. + . + OpenFlow is a protocol for flow-based control over network switching. + +Package: openflow-pki +Architecture: all +Depends: ${shlibs:Depends}, ${misc:Depends}, openflow-common +Description: OpenFlow public key infrastructure + openflow-pki provides PKI (public key infrastructure) support for + OpenFlow switches and controllers, reducing the risk of + man-in-the-middle attacks on the OpenFlow network infrastructure. + . + OpenFlow is a protocol for flow-based control over network switching. + +Package: openflow-pki-server +Architecture: all +Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, openflow-pki, apache2 +Description: OpenFlow public key infrastructure (HTTP server support) + openflow-pki-server provides HTTP access to the OpenFlow PKI (public + key infrastructure) maintained on the local machine by the + openflow-pki package. This HTTP access is needed for secure and + convenient OpenFlow switch setup using the ofp-switch-setup program + in the openflow-switch package. + . + OpenFlow is a protocol for flow-based control over network switching. + +Package: openflow-controller +Architecture: any +Depends: ${shlibs:Depends}, openflow-common, openflow-pki +Description: OpenFlow controller implementation + The OpenFlow controller enables OpenFlow switches that connect to it + to act as MAC-learning Ethernet switches. + . + OpenFlow is a protocol for flow-based control over network switching. + +Package: corekeeper +Architecture: all +Depends: tmpreaper +Description: Core file centralizer and reaper + The corekeeper package configures the system to dump all core files to + /var/log/core. It also deletes core files older than 7 days. + +Package: openflow-dbg +Architecture: any +Depends: ${shlibs:Depends} +Description: Debug symbols for OpenFlow packages + This package contains the debug symbols for all the other openflow-* + packages. Install it to debug one of them or to examine a core dump + produced by one of them. + diff --git a/openflow/debian/control.modules.in b/openflow/debian/control.modules.in new file mode 100644 index 00000000..cc149cac --- /dev/null +++ b/openflow/debian/control.modules.in @@ -0,0 +1,19 @@ +Source: openflow +Section: net +Priority: extra +Maintainer: OpenFlow Team +Build-Depends: debhelper (>= 5.0.37) +Standards-Version: 3.7.3 + +Package: openflow-datapath-module-_KVERS_ +Architecture: any +Recommends: kernel-image-_KVERS_, openflow-switch +Provides: openflow-datapath-module +Description: OpenFlow Linux datapath kernel module + This package contains the OpenFlow loadable datapath kernel modules for + the kernel-image-_KVERS_ package. + . + If you compiled a custom kernel, you will most likely need to compile + a custom version of this module as well. The openflow-datapath-source + package has been provided for this purpose. Refer to README.Debian + provided in that package for further instructions. diff --git a/openflow/debian/copyright b/openflow/debian/copyright new file mode 100644 index 00000000..b369ec39 --- /dev/null +++ b/openflow/debian/copyright @@ -0,0 +1,38 @@ +Upstream Authors: + + The Board of Trustees of The Leland Stanford Junior University + +Copyright: + + Copyright (C) 2008 The Board of Trustees of The Leland Stanford + Junior University + +License: + + We are making the OpenFlow specification and associated documentation + (Software) available for public use and benefit with the expectation + that others will use, modify and enhance the Software and contribute + those enhancements back to the community. However, since we would like + to make the Software available for broadest use, with as few + restrictions as possible permission is hereby granted, free of charge, + to any person obtaining a copy of this Software to deal in the Software + under the copyrights without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + The name and trademarks of copyright holder(s) may NOT be used in + advertising or publicity pertaining to the Software or any derivatives + without specific, written prior permission. + diff --git a/openflow/debian/corekeeper.cron.daily b/openflow/debian/corekeeper.cron.daily new file mode 100755 index 00000000..badc192d --- /dev/null +++ b/openflow/debian/corekeeper.cron.daily @@ -0,0 +1,5 @@ +#! /bin/sh + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin + +tmpreaper 7d --mtime --all /var/log/core diff --git a/openflow/debian/corekeeper.init b/openflow/debian/corekeeper.init new file mode 100755 index 00000000..27d62a12 --- /dev/null +++ b/openflow/debian/corekeeper.init @@ -0,0 +1,63 @@ +#!/bin/sh +# +# Example init.d script with LSB support. +# +# Please read this init.d carefully and modify the sections to +# adjust it to the program you want to run. +# +# Copyright (c) 2007 Javier Fernandez-Sanguino +# +# This is free software; you may redistribute it and/or modify +# it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2, +# or (at your option) any later version. +# +# This is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License with +# the Debian operating system, in /usr/share/common-licenses/GPL; if +# not, write to the Free Software Foundation, Inc., 59 Temple Place, +# Suite 330, Boston, MA 02111-1307 USA +# +### BEGIN INIT INFO +# Provides: corekeeper +# Required-Start: +# Required-Stop: +# Should-Start: $syslog +# Should-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Configure core file dump location +### END INIT INFO + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin + +. /lib/lsb/init-functions + +set -e + +case "$1" in + start) + log_daemon_msg "Initializing core dump location..." + if echo "/var/log/core/core.%e.%t" > /proc/sys/kernel/core_pattern + then + log_progress_msg "success" + log_end_msg 0 + exit 0 + else + log_end_msg 1 + exit 1 + fi + ;; + stop|restart|force-reload|status|reload) + exit 0 + ;; + *) + N=/etc/init.d/$NAME + echo "Usage: $N {start|stop|restart|force-reload|status}" >&2 + exit 1 + ;; +esac diff --git a/openflow/debian/dirs b/openflow/debian/dirs new file mode 100644 index 00000000..ca882bbb --- /dev/null +++ b/openflow/debian/dirs @@ -0,0 +1,2 @@ +usr/bin +usr/sbin diff --git a/openflow/debian/ofp-switch-setup b/openflow/debian/ofp-switch-setup new file mode 100755 index 00000000..5a999ab4 --- /dev/null +++ b/openflow/debian/ofp-switch-setup @@ -0,0 +1,615 @@ +#! /usr/bin/perl + +use POSIX; +use Debconf::Client::ConfModule ':all'; +use HTTP::Request; +use LWP::UserAgent; +use Digest::SHA1 'sha1_hex'; +use strict; +use warnings; + +# XXX should support configuring SWITCH_NETMASK and SWITCH_GATEWAY +# when the mode is in-band. + +my $debconf_owner = 'openflow-switch'; + +my $default = '/etc/default/openflow-switch'; +my $template = '/usr/share/openflow/switch/default.template'; +my $etc = '/etc/openflow-switch'; +my $rundir = '/var/run'; +my $privkey_file = "$etc/of0-privkey.pem"; +my $req_file = "$etc/of0-req.pem"; +my $cert_file = "$etc/of0-cert.pem"; +my $cacert_file = "$etc/cacert.pem"; +my $ofp_discover_pidfile = "$rundir/ofp-discover.pid"; + +my $ua = LWP::UserAgent->new; +$ua->timeout(10); +$ua->env_proxy; + +system("/etc/init.d/openflow-switch stop 1>&2"); +kill_ofp_discover(); + +version('2.0'); +capb('backup'); +title('OpenFlow Switch Setup'); + +my (%netdevs) = find_netdevs(); +db_subst('netdevs', 'choices', + join(', ', map($netdevs{$_}, sort(keys(%netdevs))))); +db_set('netdevs', join(', ', grep(!/IP/, values(%netdevs)))); + +my %oldconfig; +if (-e $default) { + %oldconfig = load_config($default); + + my (%map) = + (NETDEVS => sub { + db_set('netdevs', join(', ', map($netdevs{$_}, + grep(exists $netdevs{$_}, split)))) + }, + MODE => sub { + db_set('mode', + $_ eq 'in-band' || $_ eq 'out-of-band' ? $_ : 'discovery') + }, + SWITCH_IP => sub { db_set('switch-ip', $_) }, + CONTROLLER => sub { db_set('controller-vconn', $_) }, + PRIVKEY => sub { $privkey_file = $_ }, + CERT => sub { $cert_file = $_ }, + CACERT => sub { $cacert_file = $_ }, + ); + + for my $key (keys(%map)) { + local $_ = $oldconfig{$key}; + &{$map{$key}}() if defined && !/^\s*$/; + } +} elsif (-e $template) { + %oldconfig = load_config($template); +} + +my $cacert_preverified = -e $cacert_file; +my ($req, $req_fingerprint); + +my %options; + +my (@states) = + (sub { + # User backed up from first dialog box. + exit(10); + }, + sub { + # Prompt for ports to include in switch. + db_input('netdevs'); + return; + }, + sub { + # Validate the chosen ports. + my (@netdevs) = split(', ', db_get('netdevs')); + if (!@netdevs) { + # No ports chosen. Disable switch. + db_input('no-netdevs'); + return 'prev' if db_go(); + return 'done'; + } elsif (my (@conf_netdevs) = grep(/IP/, @netdevs)) { + # Point out that some ports have configured IP addresses. + db_subst('configured-netdevs', 'configured-netdevs', + join(', ', @conf_netdevs)); + db_input('configured-netdevs'); + return; + } else { + # Otherwise proceed. + return 'skip'; + } + }, + sub { + # Discovery or in-band or out-of-band controller? + db_input('mode'); + return; + }, + sub { + return 'skip' if db_get('mode') ne 'discovery'; + for (;;) { + # Notify user that we are going to do discovery. + db_input('discover'); + return 'prev' if db_go(); + print STDERR "Please wait up to 30 seconds for discovery...\n"; + + # Make sure that there's no running discovery process. + kill_ofp_discover(); + + # Do discovery. + %options = (); + open(DISCOVER, '-|', 'ofp-discover --timeout=30 --pidfile ' + . join(' ', netdev_names())); + while () { + chomp; + if (my ($name, $value) = /^([^=]+)=(.*)$/) { + if ($value =~ /^"(.*)"$/) { + $value = $1; + $value =~ s/\\([0-7][0-7][0-7])/chr($1)/ge; + } else { + $value =~ s/^(0x[[:xdigit:]]+)$/hex($1)/e; + $value = '' if $value eq 'empty'; + next if $value eq 'null'; # Shouldn't happen. + } + $options{$name} = $value; + } + last if /^$/; + } + + # Check results. + my $vconn = $options{'ofp-controller-vconn'}; + my $pki_uri = $options{'ofp-pki-uri'}; + return 'next' + if (defined($vconn) + && is_valid_vconn($vconn) + && (!is_ssl_vconn($vconn) || defined($pki_uri))); + + # Try again? + kill_ofp_discover(); + db_input('discovery-failure'); + db_go(); + } + }, + sub { + return 'skip' if db_get('mode') ne 'discovery'; + + my $vconn = $options{'ofp-controller-vconn'}; + my $pki_uri = $options{'ofp-pki-uri'}; + db_subst('discovery-success', 'controller-vconn', $vconn); + db_subst('discovery-success', + 'pki-uri', is_ssl_vconn($vconn) ? $pki_uri : "no PKI in use"); + db_input('discovery-success'); + return 'prev' if db_go(); + db_set('controller-vconn', $vconn); + db_set('pki-uri', $pki_uri); + return 'next'; + }, + sub { + return 'skip' if db_get('mode') ne 'in-band'; + for (;;) { + db_input('switch-ip'); + return 'prev' if db_go(); + + my $ip = db_get('switch-ip'); + return 'next' if $ip =~ /^dhcp|\d+\.\d+.\d+.\d+$/i; + + db_input('switch-ip-error'); + db_go(); + } + }, + sub { + return 'skip' if db_get('mode') eq 'discovery'; + for (;;) { + my $old_vconn = db_get('controller-vconn'); + db_input('controller-vconn'); + return 'prev' if db_go(); + + my $vconn = db_get('controller-vconn'); + if (is_valid_vconn($vconn)) { + if ($old_vconn ne $vconn || db_get('pki-uri') eq '') { + db_set('pki-uri', pki_host_to_uri($2)); + } + return 'next'; + } + + db_input('controller-vconn-error'); + db_go(); + } + }, + sub { + return 'skip' if !ssl_enabled(); + + if (! -e $privkey_file) { + my $old_umask = umask(077); + run_cmd("ofp-pki req $etc/of0 >&2 2>/dev/null"); + chmod(0644, $req_file) or die "$req_file: chmod: $!\n"; + umask($old_umask); + } + + if (! -e $cert_file) { + open(REQ, '<', $req_file) or die "$req_file: open: $!\n"; + $req = join('', ); + close(REQ); + $req_fingerprint = sha1_hex($req); + } + return 'skip'; + }, + sub { + return 'skip' if !ssl_enabled(); + return 'skip' if -e $cacert_file && -e $cert_file; + + db_input('pki-uri'); + return 'prev' if db_go(); + return; + }, + sub { + return 'skip' if !ssl_enabled(); + return 'skip' if -e $cacert_file; + + my $pki_uri = db_get('pki-uri'); + if ($pki_uri !~ /:/) { + $pki_uri = pki_host_to_uri($pki_uri); + } else { + # Trim trailing slashes. + $pki_uri =~ s%/+$%%; + } + db_set('pki-uri', $pki_uri); + + my $url = "$pki_uri/controllerca/cacert.pem"; + my $response = $ua->get($url, ':content_file' => $cacert_file); + if ($response->is_success) { + return 'next'; + } + + db_subst('fetch-cacert-failed', 'url', $url); + db_subst('fetch-cacert-failed', 'error', $response->status_line); + db_subst('fetch-cacert-failed', 'pki-uri', $pki_uri); + db_input('fetch-cacert-failed'); + db_go(); + return 'prev'; + }, + sub { + return 'skip' if !ssl_enabled(); + return 'skip' if -e $cert_file; + + for (;;) { + db_set('send-cert-req', 'yes'); + db_input('send-cert-req'); + return 'prev' if db_go(); + return 'next' if db_get('send-cert-req') eq 'no'; + + my $pki_uri = db_get('pki-uri'); + my ($pki_base_uri) = $pki_uri =~ m%^([^/]+://[^/]+)/%; + my $url = "$pki_base_uri/cgi-bin/ofp-pki-cgi"; + my $response = $ua->post($url, {'type' => 'switch', + 'req' => $req}); + return 'next' if $response->is_success; + + db_subst('send-cert-req-failed', 'url', $url); + db_subst('send-cert-req-failed', 'error', + $response->status_line); + db_subst('send-cert-req-failed', 'pki-uri', $pki_uri); + db_input('send-cert-req-failed'); + db_go(); + } + }, + sub { + return 'skip' if !ssl_enabled(); + return 'skip' if $cacert_preverified; + + my ($cacert_fingerprint) = x509_fingerprint($cacert_file); + db_subst('verify-controller-ca', 'fingerprint', $cacert_fingerprint); + db_input('verify-controller-ca'); + return 'prev' if db_go(); + return 'next' if db_get('verify-controller-ca') eq 'yes'; + unlink($cacert_file); + return 'prev'; + }, + sub { + return 'skip' if !ssl_enabled(); + return 'skip' if -e $cert_file; + + for (;;) { + db_set('fetch-switch-cert', 'yes'); + db_input('fetch-switch-cert'); + return 'prev' if db_go(); + exit(1) if db_get('fetch-switch-cert') eq 'no'; + + my $pki_uri = db_get('pki-uri'); + my $url = "$pki_uri/switchca/certs/$req_fingerprint-cert.pem"; + my $response = $ua->get($url, ':content_file' => $cert_file); + if ($response->is_success) { + return 'next'; + } + + db_subst('fetch-switch-cert-failed', 'url', $url); + db_subst('fetch-switch-cert-failed', 'error', + $response->status_line); + db_subst('fetch-switch-cert-failed', 'pki-uri', $pki_uri); + db_input('fetch-switch-cert-failed'); + db_go(); + } + }, + sub { + db_input('complete'); + db_go(); + return; + }, + sub { + return 'done'; + }, +); + +my $state = 1; +my $direction = 1; +for (;;) { + my $ret = &{$states[$state]}(); + $ret = db_go() ? 'prev' : 'next' if !defined $ret; + if ($ret eq 'next') { + $direction = 1; + } elsif ($ret eq 'prev') { + $direction = -1; + } elsif ($ret eq 'skip') { + # Nothing to do. + } elsif ($ret eq 'done') { + last; + } else { + die "unknown ret $ret"; + } + $state += $direction; +} + +my %config = %oldconfig; +$config{NETDEVS} = join(' ', netdev_names()); +$config{MODE} = db_get('mode'); +if (db_get('mode') eq 'in-band') { + $config{SWITCH_IP} = db_get('switch-ip'); +} +if (db_get('mode') ne 'discovery') { + $config{CONTROLLER} = db_get('controller-vconn'); +} +$config{PRIVKEY} = $privkey_file; +$config{CERT} = $cert_file; +$config{CACERT} = $cacert_file; +save_config($default, %config); + +dup2(2, 1); # Get stdout back. +kill_ofp_discover(); +system("/etc/init.d/openflow-switch start"); + +sub ssl_enabled { + return is_ssl_vconn(db_get('controller-vconn')); +} + +sub db_subst { + my ($question, $key, $value) = @_; + $question = "$debconf_owner/$question"; + my ($ret, $seen) = subst($question, $key, $value); + if ($ret && $ret != 30) { + die "Error substituting $value for $key in debconf question " + . "$question: $seen"; + } +} + +sub db_set { + my ($question, $value) = @_; + $question = "$debconf_owner/$question"; + my ($ret, $seen) = set($question, $value); + if ($ret && $ret != 30) { + die "Error setting debconf question $question to $value: $seen"; + } +} + +sub db_get { + my ($question) = @_; + $question = "$debconf_owner/$question"; + my ($ret, $seen) = get($question); + if ($ret) { + die "Error getting debconf question $question answer: $seen"; + } + return $seen; +} + +sub db_fset { + my ($question, $flag, $value) = @_; + $question = "$debconf_owner/$question"; + my ($ret, $seen) = fset($question, $flag, $value); + if ($ret && $ret != 30) { + die "Error setting debconf question $question flag $flag to $value: " + . "$seen"; + } +} + +sub db_fget { + my ($question, $flag) = @_; + $question = "$debconf_owner/$question"; + my ($ret, $seen) = fget($question, $flag); + if ($ret) { + die "Error getting debconf question $question flag $flag: $seen"; + } + return $seen; +} + +sub db_input { + my ($question) = @_; + db_fset($question, "seen", "false"); + + $question = "$debconf_owner/$question"; + my ($ret, $seen) = input('high', $question); + if ($ret && $ret != 30) { + die "Error requesting debconf question $question: $seen"; + } + return $ret; +} + +sub db_go { + my ($ret, $seen) = go(); + if (!defined($ret)) { + exit(1); # Cancel button was pushed. + } + if ($ret && $ret != 30) { + die "Error asking debconf questions: $seen"; + } + return $ret; +} + +sub run_cmd { + my ($cmd) = @_; + return if system($cmd) == 0; + + if ($? == -1) { + die "$cmd: failed to execute: $!\n"; + } elsif ($? & 127) { + die sprintf("$cmd: child died with signal %d, %s coredump\n", + ($? & 127), ($? & 128) ? 'with' : 'without'); + } else { + die sprintf("$cmd: child exited with value %d\n", $? >> 8); + } +} + +sub x509_fingerprint { + my ($file) = @_; + my $cmd = "openssl x509 -noout -in $file -fingerprint"; + open(OPENSSL, '-|', $cmd) or die "$cmd: failed to execute: $!\n"; + my $line = ; + close(OPENSSL); + my ($fingerprint) = $line =~ /SHA1 Fingerprint=(.*)/; + return $line if !defined $fingerprint; + $fingerprint =~ s/://g; + return $fingerprint; +} + +sub find_netdevs { + my ($netdev, %netdevs); + open(IFCONFIG, "/sbin/ifconfig -a|") or die "ifconfig failed: $!"; + while () { + if (my ($nd) = /^([^\s]+)/) { + $netdev = $nd; + $netdevs{$netdev} = "$netdev"; + if (my ($hwaddr) = /HWaddr (\S+)/) { + $netdevs{$netdev} .= " (MAC: $hwaddr)"; + } + } elsif (my ($ip4) = /^\s*inet addr:(\S+)/) { + $netdevs{$netdev} .= " (IP: $ip4)"; + } elsif (my ($ip6) = /^\s*inet6 addr:(\S+)/) { + $netdevs{$netdev} .= " (IPv6: $ip6)"; + } + } + foreach my $nd (keys(%netdevs)) { + delete $netdevs{$nd} if $nd eq 'lo' || $nd =~ /^wmaster/; + } + close(IFCONFIG); + return %netdevs; +} + +sub load_config { + my ($file) = @_; + + # Get the list of the variables that the shell sets automatically. + my (%auto_vars) = read_vars("set -a && env"); + + # Get the variables from $default. + my (%config) = read_vars("set -a && . '$default' && env"); + + # Subtract. + delete @config{keys %auto_vars}; + + return %config; +} + +sub read_vars { + my ($cmd) = @_; + local @ENV; + if (!open(VARS, '-|', $cmd)) { + print STDERR "$cmd: failed to execute: $!\n"; + return (); + } + my (%config); + while () { + my ($var, $value) = /^([^=]+)=(.*)$/ or next; + $config{$var} = $value; + } + close(VARS); + return %config; +} + +sub shell_escape { + local $_ = $_[0]; + if ($_ eq '') { + return '""'; + } elsif (m&^[-a-zA-Z0-9:./%^_+,]*$&) { + return $_; + } else { + s/'/'\\''/; + return "'$_'"; + } +} + +sub shell_assign { + my ($var, $value) = @_; + return $var . '=' . shell_escape($value); +} + +sub save_config { + my ($file, %config) = @_; + my (@lines); + if (open(FILE, '<', $file)) { + @lines = ; + chomp @lines; + close(FILE); + } + + # Replace all existing variable assignments. + for (my ($i) = 0; $i <= $#lines; $i++) { + local $_ = $lines[$i]; + my ($var, $value) = /^\s*([^=#]+)=(.*)$/ or next; + if (exists($config{$var})) { + $lines[$i] = shell_assign($var, $config{$var}); + delete $config{$var}; + } else { + $lines[$i] = "#$lines[$i]"; + } + } + + # Find a place to put any remaining variable assignments. + VAR: + for my $var (keys(%config)) { + my $assign = shell_assign($var, $config{$var}); + + # Replace the last commented-out variable assignment to $var, if any. + for (my ($i) = $#lines; $i >= 0; $i--) { + local $_ = $lines[$i]; + if (/^\s*#\s*$var=/) { + $lines[$i] = $assign; + next VAR; + } + } + + # Find a place to add the var: after the final commented line + # just after a line that contains "$var:". + for (my ($i) = 0; $i <= $#lines; $i++) { + if ($lines[$i] =~ /^\s*#\s*$var:/) { + for (my ($j) = $i + 1; $j <= $#lines; $j++) { + if ($lines[$j] !~ /^\s*#/) { + splice(@lines, $j, 0, $assign); + next VAR; + } + } + } + } + + # Just append it. + push(@lines, $assign); + } + + open(NEWFILE, '>', "$file.tmp") or die "$file.tmp: create: $!\n"; + print NEWFILE join('', map("$_\n", @lines)); + close(NEWFILE); + rename("$file.tmp", $file) or die "$file.tmp: rename to $file: $!\n"; +} + +sub pki_host_to_uri { + my ($pki_host) = @_; + return "http://$pki_host/openflow/pki"; +} + +sub kill_ofp_discover { + # Delegate this to a subprocess because there is no portable way + # to invoke fcntl(F_GETLK) from Perl. + system("ofp-kill --force $ofp_discover_pidfile"); +} + +sub netdev_names { + return map(/^(\S+)/, split(', ', db_get('netdevs'))); +} + +sub is_valid_vconn { + my ($vconn) = @_; + return scalar($vconn =~ /^(tcp|ssl):([^:]+)(:.*)?/); +} + +sub is_ssl_vconn { + my ($vconn) = @_; + return scalar($vconn =~ /^ssl:/); +} diff --git a/openflow/debian/ofp-switch-setup.8 b/openflow/debian/ofp-switch-setup.8 new file mode 100644 index 00000000..50904cfb --- /dev/null +++ b/openflow/debian/ofp-switch-setup.8 @@ -0,0 +1,41 @@ +.TH ofp-switch-setup 8 "June 2008" "OpenFlow" "OpenFlow Manual" + +.SH NAME +ofp\-switch\-setup \- interactive setup for OpenFlow switch + +.SH SYNOPSIS +.B ofp\-switch\-setup + +.SH DESCRIPTION +The \fBofp\-switch\-setup\fR program is an interactive program that +assists the system administrator in configuring an OpenFlow switch, +including the underlying public key infrastructure (PKI). + +.SH OPTIONS +ofp\-switch\-setup does not accept any command-line options. + +.SH FILES +.IP /etc/default/openflow-switch +Main configuration file for OpenFlow switch. + +.IP /etc/openflow-switch/cacert.pem +Default location of CA certificate for OpenFlow controllers. + +.IP /etc/openflow-switch/of0-cert.pem +Default location of certificate for the OpenFlow switch's private key. + +.IP /etc/openflow-switch/of0-privkey.pem +Default location of the OpenFlow switch's private key. This file +should be readable only by \fBroot\fR. + +.IP /etc/openflow-switch/of0-req.pem +Default location of certificate request for the OpenFlow switch's +certificate. This file is not used after the signed certificate +(typically \fB/etc/openflow-switch/of0-cert.pem\fR, above) has been +obtained from the OpenFlow PKI server. + +.SH "SEE ALSO" + +.BR ofp-pki (8), +.BR dpctl (8), +.BR secchan (8) diff --git a/openflow/debian/openflow-common.dirs b/openflow/debian/openflow-common.dirs new file mode 100644 index 00000000..527fe313 --- /dev/null +++ b/openflow/debian/openflow-common.dirs @@ -0,0 +1 @@ +var/log/openflow diff --git a/openflow/debian/openflow-common.install b/openflow/debian/openflow-common.install new file mode 100644 index 00000000..eed7413e --- /dev/null +++ b/openflow/debian/openflow-common.install @@ -0,0 +1,3 @@ +_debian/utilities/ofp-parse-leaks usr/bin +_debian/utilities/ofp-pki usr/sbin +_debian/utilities/vlogconf usr/sbin diff --git a/openflow/debian/openflow-common.manpages b/openflow/debian/openflow-common.manpages new file mode 100644 index 00000000..fbb88201 --- /dev/null +++ b/openflow/debian/openflow-common.manpages @@ -0,0 +1,2 @@ +_debian/utilities/vlogconf.8 +_debian/utilities/ofp-pki.8 diff --git a/openflow/debian/openflow-controller.README.Debian b/openflow/debian/openflow-controller.README.Debian new file mode 100644 index 00000000..19d5cb9b --- /dev/null +++ b/openflow/debian/openflow-controller.README.Debian @@ -0,0 +1,10 @@ +README.Debian for openflow-controller +------------------------------------- + +* To (re)configure the controller, edit /etc/default/openflow-controller + and run "/etc/init.d/openflow-controller restart". + +* To enable OpenFlow switches to automatically discover the location + of the controller, you must install and configure a DHCP server. + The secchan(8) manpage (found in the openflow-switch package) gives + a working example configuration file for the ISC DHCP server. diff --git a/openflow/debian/openflow-controller.default b/openflow/debian/openflow-controller.default new file mode 100644 index 00000000..3b84b62a --- /dev/null +++ b/openflow/debian/openflow-controller.default @@ -0,0 +1,33 @@ +# This is a POSIX shell fragment -*- sh -*- + +# LISTEN: What OpenFlow connection methods should the controller listen on? +# +# This is a space-delimited list of connection methods: +# +# * "pssl:[PORT]": Listen for SSL connections on the specified PORT +# (default: 6633). The private key, certificate, and CA certificate +# must be specified below. +# +# * "pctp:[PORT]": Listen for TCP connections on the specified PORT +# (default: 6633). Not recommended for security reasons. +# +# * "nl:DP_IDX": Listen on local datapath DP_IDX. Used only if this +# machine is also an OpenFlow switch and not running the secure +# channel, and only if you know what you're doing. +# +LISTEN="pssl:" + +# PRIVKEY: Name of file containing controller's private key. +# Required if SSL enabled. +PRIVKEY=/etc/openflow-controller/privkey.pem + +# CERT: Name of file containing certificate for private key. +# Required if SSL enabled. +CERT=/etc/openflow-controller/cert.pem + +# CACERT: Name of file containing switch CA certificate. +# Required if SSL enabled. +CACERT=/etc/openflow-controller/cacert.pem + +# Additional options to pass to controller, e.g. "--hub" +DAEMON_OPTS="" diff --git a/openflow/debian/openflow-controller.dirs b/openflow/debian/openflow-controller.dirs new file mode 100644 index 00000000..0a19a9fc --- /dev/null +++ b/openflow/debian/openflow-controller.dirs @@ -0,0 +1 @@ +etc/openflow-controller diff --git a/openflow/debian/openflow-controller.init b/openflow/debian/openflow-controller.init new file mode 100755 index 00000000..121fd76b --- /dev/null +++ b/openflow/debian/openflow-controller.init @@ -0,0 +1,269 @@ +#!/bin/sh +# +# Copyright (c) 2007 Javier Fernandez-Sanguino +# +# This is free software; you may redistribute it and/or modify +# it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2, +# or (at your option) any later version. +# +# This is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License with +# the Debian operating system, in /usr/share/common-licenses/GPL; if +# not, write to the Free Software Foundation, Inc., 59 Temple Place, +# Suite 330, Boston, MA 02111-1307 USA +# +### BEGIN INIT INFO +# Provides: openflow-controller +# Required-Start: $network $local_fs +# Required-Stop: +# Should-Start: $named +# Should-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: OpenFlow controller +### END INIT INFO + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin + +DAEMON=/usr/sbin/controller # Introduce the server's location here +NAME=controller # Introduce the short server's name here +DESC=controller # Introduce a short description here +LOGDIR=/var/log/openflow # Log directory to use + +PIDFILE=/var/run/$NAME.pid + +test -x $DAEMON || exit 0 + +. /lib/lsb/init-functions + +# Default options, these can be overriden by the information +# at /etc/default/$NAME +DAEMON_OPTS="" # Additional options given to the server + +DODTIME=10 # Time to wait for the server to die, in seconds + # If this value is set too low you might not + # let some servers to die gracefully and + # 'restart' will not work + +LOGFILE=$LOGDIR/$NAME.log # Server logfile +#DAEMONUSER= # User to run the daemons as. If this value + # is set start-stop-daemon will chuid the server + +# Include defaults if available +default=/etc/default/openflow-controller +if [ -f $default ] ; then + . $default +fi + +# Check that the user exists (if we set a user) +# Does the user exist? +if [ -n "$DAEMONUSER" ] ; then + if getent passwd | grep -q "^$DAEMONUSER:"; then + # Obtain the uid and gid + DAEMONUID=`getent passwd |grep "^$DAEMONUSER:" | awk -F : '{print $3}'` + DAEMONGID=`getent passwd |grep "^$DAEMONUSER:" | awk -F : '{print $4}'` + else + log_failure_msg "The user $DAEMONUSER, required to run $NAME does not exist." + exit 1 + fi +fi + + +set -e + +running_pid() { +# Check if a given process pid's cmdline matches a given name + pid=$1 + name=$2 + [ -z "$pid" ] && return 1 + [ ! -d /proc/$pid ] && return 1 + cmd=`cat /proc/$pid/cmdline | tr "\000" "\n"|head -n 1 |cut -d : -f 1` + # Is this the expected server + [ "$cmd" != "$name" ] && return 1 + return 0 +} + +running() { +# Check if the process is running looking at /proc +# (works for all users) + + # No pidfile, probably no daemon present + [ ! -f "$PIDFILE" ] && return 1 + pid=`cat $PIDFILE` + running_pid $pid $DAEMON || return 1 + return 0 +} + +start_server() { + if [ -z "$LISTEN" ]; then + echo "$default: No connection methods configured, controller disabled" >&2 + exit 0 + fi + + SSL_OPTS= + case $LISTEN in + *ssl*) + : ${PRIVKEY:=/etc/openflow-controller/privkey.pem} + : ${CERT:=/etc/openflow-controller/cert.pem} + : ${CACERT:=/etc/openflow-controller/cacert.pem} + if test ! -e "$PRIVKEY" || test ! -e "$CERT" || + test ! -e "$CACERT"; then + if test ! -e "$PRIVKEY"; then + echo "$PRIVKEY: private key missing" >&2 + fi + if test ! -e "$CERT"; then + echo "$CERT: certificate for private key missing" >&2 + fi + if test ! -e "$CACERT"; then + echo "$CACERT: CA certificate missing" >&2 + fi + exit 1 + fi + SSL_OPTS="--private-key=$PRIVKEY --certificate=$CERT --ca-cert=$CACERT" + ;; + esac + +# Start the process using the wrapper + if [ -z "$DAEMONUSER" ] ; then + start-stop-daemon --start --pidfile $PIDFILE \ + --exec $DAEMON -- --detach --pidfile=$PIDFILE \ + $LISTEN $DAEMON_OPTS $SSL_OPTS + errcode=$? + else +# if we are using a daemonuser then change the user id + start-stop-daemon --start --quiet --pidfile $PIDFILE \ + --chuid $DAEMONUSER --exec $DAEMON -- \ + --detach --pidfile=$PIDFILE $LISTEN $DAEMON_OPTS \ + $SSL_OPTS + errcode=$? + fi + return $errcode +} + +stop_server() { +# Stop the process using the wrapper + if [ -z "$DAEMONUSER" ] ; then + start-stop-daemon --stop --quiet --pidfile $PIDFILE \ + --exec $DAEMON + errcode=$? + else +# if we are using a daemonuser then look for process that match + start-stop-daemon --stop --quiet --pidfile $PIDFILE \ + --user $DAEMONUSER --exec $DAEMON + errcode=$? + fi + + return $errcode +} + +reload_server() { + [ ! -f "$PIDFILE" ] && return 1 + pid=`cat $PIDFILE` # This is the daemon's pid + # Send a SIGHUP + kill -1 $pid + return $? +} + +force_stop() { +# Force the process to die killing it manually + [ ! -e "$PIDFILE" ] && return + if running ; then + kill -15 $pid + # Is it really dead? + sleep "$DIETIME"s + if running ; then + kill -9 $pid + sleep "$DIETIME"s + if running ; then + echo "Cannot kill $NAME (pid=$pid)!" + exit 1 + fi + fi + fi + rm -f $PIDFILE +} + + +case "$1" in + start) + log_daemon_msg "Starting $DESC " "$NAME" + # Check if it's running first + if running ; then + log_progress_msg "apparently already running" + log_end_msg 0 + exit 0 + fi + if start_server && running ; then + # It's ok, the server started and is running + log_end_msg 0 + else + # Either we could not start it or it is not running + # after we did + # NOTE: Some servers might die some time after they start, + # this code does not try to detect this and might give + # a false positive (use 'status' for that) + log_end_msg 1 + fi + ;; + stop) + log_daemon_msg "Stopping $DESC" "$NAME" + if running ; then + # Only stop the server if we see it running + stop_server + log_end_msg $? + else + # If it's not running don't do anything + log_progress_msg "apparently not running" + log_end_msg 0 + exit 0 + fi + ;; + force-stop) + # First try to stop gracefully the program + $0 stop + if running; then + # If it's still running try to kill it more forcefully + log_daemon_msg "Stopping (force) $DESC" "$NAME" + force_stop + log_end_msg $? + fi + ;; + restart|force-reload) + log_daemon_msg "Restarting $DESC" "$NAME" + stop_server + # Wait some sensible amount, some server need this + [ -n "$DIETIME" ] && sleep $DIETIME + start_server + running + log_end_msg $? + ;; + status) + + log_daemon_msg "Checking status of $DESC" "$NAME" + if running ; then + log_progress_msg "running" + log_end_msg 0 + else + log_progress_msg "apparently not running" + log_end_msg 1 + exit 1 + fi + ;; + # Use this if the daemon cannot reload + reload) + log_warning_msg "Reloading $NAME daemon: not implemented, as the daemon" + log_warning_msg "cannot re-read the config file (use restart)." + ;; + *) + N=/etc/init.d/$NAME + echo "Usage: $N {start|stop|force-stop|restart|force-reload|status}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/openflow/debian/openflow-controller.install b/openflow/debian/openflow-controller.install new file mode 100644 index 00000000..3932ab6a --- /dev/null +++ b/openflow/debian/openflow-controller.install @@ -0,0 +1 @@ +_debian/controller/controller usr/sbin diff --git a/openflow/debian/openflow-controller.manpages b/openflow/debian/openflow-controller.manpages new file mode 100644 index 00000000..3fbaaeaf --- /dev/null +++ b/openflow/debian/openflow-controller.manpages @@ -0,0 +1 @@ +_debian/controller/controller.8 diff --git a/openflow/debian/openflow-controller.postinst b/openflow/debian/openflow-controller.postinst new file mode 100755 index 00000000..93e39116 --- /dev/null +++ b/openflow/debian/openflow-controller.postinst @@ -0,0 +1,52 @@ +#!/bin/sh +# postinst script for openflow-controller +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `configure' +# * `abort-upgrade' +# * `abort-remove' `in-favour' +# +# * `abort-remove' +# * `abort-deconfigure' `in-favour' +# `removing' +# +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + configure) + cd /etc/openflow-controller + if ! test -e cacert.pem; then + ln -s /usr/share/openflow/pki/switchca/cacert.pem cacert.pem + fi + if ! test -e privkey.pem || ! test -e cert.pem; then + oldumask=$(umask) + umask 077 + ofp-pki req+sign tmp controller >/dev/null + mv tmp-privkey.pem privkey.pem + mv tmp-cert.pem cert.pem + mv tmp-req.pem req.pem + chmod go+r cert.pem req.pem + umask $oldumask + fi + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +#DEBHELPER# + +exit 0 + + diff --git a/openflow/debian/openflow-datapath-module-_KVERS_.postinst.modules.in b/openflow/debian/openflow-datapath-module-_KVERS_.postinst.modules.in new file mode 100755 index 00000000..6974e13a --- /dev/null +++ b/openflow/debian/openflow-datapath-module-_KVERS_.postinst.modules.in @@ -0,0 +1,25 @@ +#!/bin/sh +# postinst script for #PACKAGE# +# +# see: dh_installdeb(1) + +set -e + +depmod -a + +#DEBHELPER# + +# If the switch is running, restart it. This ensures that we are using the +# latest kernel module, because the init script will unload and reload the +# module. +# +# (Ideally we'd only want to do this if this package corresponds to the +# running kernel, but I don't know a reliable way to check.) +INIT=/etc/init.d/openflow-switch +if test -x $INIT && $INIT status; then + $INIT restart || true +fi + +exit 0 + + diff --git a/openflow/debian/openflow-datapath-source.README.Debian b/openflow/debian/openflow-datapath-source.README.Debian new file mode 100644 index 00000000..59965df9 --- /dev/null +++ b/openflow/debian/openflow-datapath-source.README.Debian @@ -0,0 +1,31 @@ +OpenFlow for Debian +------------------- + +* How do I build this module the Debian way? + + - Building with module-assistant: + + $ module-assistant auto-install openflow + or + $ m-a a-i openflow + + If kernel source or headers are in a non-standard directory, add + the option -k /path/to/kernel/source with the correct path. + + - Building with make-kpkg + + $ cd /usr/src/ + $ tar jxvf openflow.tar.bz2 + $ cd /usr/src/kernel-source-2.6.9 + $ make-kpkg --added-modules=openflow modules + + - Building without make-kpkg + + $ cd /usr/src/ + $ tar jxvf openflow.tar.bz2 + $ cd modules/openflow + $ fakeroot debian/rules kdist_image + + If you run this as root, fakeroot is not needed. + + -- OpenFlow Team , Thu, 12 Jun 2008 16:42:38 -0700 diff --git a/openflow/debian/openflow-datapath-source.copyright b/openflow/debian/openflow-datapath-source.copyright new file mode 100644 index 00000000..f7bcdda3 --- /dev/null +++ b/openflow/debian/openflow-datapath-source.copyright @@ -0,0 +1,16 @@ +Upstream Authors: + + The Board of Trustees of The Leland Stanford Junior University + +Copyright: + + Copyright (C) 2008 The Board of Trustees of The Leland Stanford + Junior University + +License: + + Files in the datapath/ and its sub-directories are covered under the GNU + General Public License Version 2. + + On Debian systems, the complete text of the GNU General + Public License can be found in `/usr/share/common-licenses/GPL'. diff --git a/openflow/debian/openflow-datapath-source.dirs b/openflow/debian/openflow-datapath-source.dirs new file mode 100644 index 00000000..4ddf234a --- /dev/null +++ b/openflow/debian/openflow-datapath-source.dirs @@ -0,0 +1 @@ +usr/src/modules/openflow-datapath/debian diff --git a/openflow/debian/openflow-datapath-source.install b/openflow/debian/openflow-datapath-source.install new file mode 100644 index 00000000..a74f13dc --- /dev/null +++ b/openflow/debian/openflow-datapath-source.install @@ -0,0 +1,6 @@ +debian/changelog usr/src/modules/openflow-datapath/debian +debian/control usr/src/modules/openflow-datapath/debian +debian/compat usr/src/modules/openflow-datapath/debian +debian/*.modules.in usr/src/modules/openflow-datapath/debian +debian/rules usr/src/modules/openflow-datapath/debian +_debian/openflow.tar.gz usr/src/modules/openflow-datapath diff --git a/openflow/debian/openflow-pki-server.apache2 b/openflow/debian/openflow-pki-server.apache2 new file mode 100644 index 00000000..a341c508 --- /dev/null +++ b/openflow/debian/openflow-pki-server.apache2 @@ -0,0 +1 @@ +Alias /openflow/pki/ /usr/share/openflow/pki/ diff --git a/openflow/debian/openflow-pki-server.dirs b/openflow/debian/openflow-pki-server.dirs new file mode 100644 index 00000000..7307777b --- /dev/null +++ b/openflow/debian/openflow-pki-server.dirs @@ -0,0 +1 @@ +etc/apache2/sites-available diff --git a/openflow/debian/openflow-pki-server.install b/openflow/debian/openflow-pki-server.install new file mode 100644 index 00000000..cd530ca4 --- /dev/null +++ b/openflow/debian/openflow-pki-server.install @@ -0,0 +1 @@ +_debian/utilities/ofp-pki-cgi usr/lib/cgi-bin diff --git a/openflow/debian/openflow-pki-server.postinst b/openflow/debian/openflow-pki-server.postinst new file mode 100755 index 00000000..d161a98a --- /dev/null +++ b/openflow/debian/openflow-pki-server.postinst @@ -0,0 +1,44 @@ +#!/bin/sh +# postinst script for openflow +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `configure' +# * `abort-upgrade' +# * `abort-remove' `in-favour' +# +# * `abort-remove' +# * `abort-deconfigure' `in-favour' +# `removing' +# +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package + +case "$1" in + configure) + # Enable site under Apache. + a2ensite openflow-pki >/dev/null + if command -v invoke-rc.d >/dev/null 2>&1; then + invoke-rc.d apache2 force-reload || : + else + [ -x /etc/init.d/apache2 ] && /etc/init.d/apache2 force-reload || : + fi + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +#DEBHELPER# + +exit 0 + + diff --git a/openflow/debian/openflow-pki.postinst b/openflow/debian/openflow-pki.postinst new file mode 100755 index 00000000..5cf6515d --- /dev/null +++ b/openflow/debian/openflow-pki.postinst @@ -0,0 +1,41 @@ +#!/bin/sh +# postinst script for openflow +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `configure' +# * `abort-upgrade' +# * `abort-remove' `in-favour' +# +# * `abort-remove' +# * `abort-deconfigure' `in-favour' +# `removing' +# +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package + +case "$1" in + configure) + # Create certificate authorities. + if test ! -d /usr/share/openflow/pki; then + ofp-pki init + fi + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +#DEBHELPER# + +exit 0 + + diff --git a/openflow/debian/openflow-switch-config.dirs b/openflow/debian/openflow-switch-config.dirs new file mode 100644 index 00000000..881ded8a --- /dev/null +++ b/openflow/debian/openflow-switch-config.dirs @@ -0,0 +1 @@ +/usr/share/lintian/overrides diff --git a/openflow/debian/openflow-switch-config.install b/openflow/debian/openflow-switch-config.install new file mode 100644 index 00000000..75c50083 --- /dev/null +++ b/openflow/debian/openflow-switch-config.install @@ -0,0 +1 @@ +debian/ofp-switch-setup usr/sbin diff --git a/openflow/debian/openflow-switch-config.manpages b/openflow/debian/openflow-switch-config.manpages new file mode 100644 index 00000000..e176dad9 --- /dev/null +++ b/openflow/debian/openflow-switch-config.manpages @@ -0,0 +1 @@ +debian/ofp-switch-setup.8 diff --git a/openflow/debian/openflow-switch-config.overrides b/openflow/debian/openflow-switch-config.overrides new file mode 100644 index 00000000..4ac77aba --- /dev/null +++ b/openflow/debian/openflow-switch-config.overrides @@ -0,0 +1 @@ +debconf-is-not-a-registry diff --git a/openflow/debian/openflow-switch-config.templates b/openflow/debian/openflow-switch-config.templates new file mode 100644 index 00000000..78761097 --- /dev/null +++ b/openflow/debian/openflow-switch-config.templates @@ -0,0 +1,228 @@ +Template: openflow-switch/netdevs +Type: multiselect +_Choices: ${choices} +_Description: OpenFlow switch network devices: + Choose the network devices that should become part of the OpenFlow + switch. At least two devices must be selected for this machine to be + a useful switch. Unselecting all network devices will disable the + OpenFlow switch entirely. + . + The network devices that you select should not be configured with IP + or IPv6 addresses, even if the switch contacts the controller over + one of the selected network devices. This is because a running + OpenFlow switch takes over network devices at a low level: they + become part of the switch and cannot be used for other purposes. + +Template: openflow-switch/no-netdevs +Type: error +_Description: No network devices were selected. + No network devices were selected for inclusion in the OpenFlow switch. + The switch will be disabled. + +Template: openflow-switch/configured-netdevs +Type: note +_Description: Some Network Devices Have IP or IPv6 Addresses + The following network devices selected to be part of the OpenFlow switch + have IP or IPv6 addresses configured: + . + ${configured-netdevs} + . + This is usually a mistake, even if the switch contacts the controller over + one of the selected network devices. This is because a running + OpenFlow switch takes over network devices at a low level: they + become part of the switch and cannot be used for other purposes. + . + If this is an unintentional mistake, move back and fix the selection, + or de-configure the IP or IPv6 from these network devices. + +Template: openflow-switch/mode +Type: select +_Choices: discovery, in-band, out-of-band +Default: discovery +_Description: Switch-to-controller access method: + The OpenFlow switch must be able to contact the OpenFlow controller over + the network. It can do so in one of three ways: + . + discovery: A single network is used for OpenFlow traffic and other + data traffic; that is, the switch contacts the controller over one of + the network devices selected as OpenFlow switch network devices in + the previous question. The switch automatically determines the + location of the controller using a DHCP request with an + OpenFlow-specific vendor option. This is the most common case. + . + in-band: As above, but the location of the controller is manually + configured. + . + out-of-band: OpenFlow traffic uses a network separate from the data traffic + that it controls. If this is the case, the control network must already + be configured on a network device other than one of those selected as + an OpenFlow switch netdev in the previous question. + +Template: openflow-switch/discover +Type: note +_Description: Preparing to discover controller. + The setup program will now attempt to discover the OpenFlow controller. + Controller discovery may take up to 30 seconds. Please be patient. + . + See secchan(8) for instructions on how to configure a DHCP server for + controller discovery. + +Template: openflow-switch/discovery-failure +Type: error +_Description: Controller discovery failed. + The controller's location could not be determined automatically. + . + Ensure that the OpenFlow DHCP server is properly configured. See + secchan(8) for instructions on how to configure a DHCP server for + controller discovery. + +Template: openflow-switch/discovery-success +Type: boolean +Default: true +_Description: Use discovered settings? + Controller discovery obtained the following settings: + . + Controller location: ${controller-vconn} + . + PKI URL: ${pki-uri} + . + Please verify that these settings are correct. + +Template: openflow-switch/switch-ip +Type: string +Default: dhcp +_Description: Switch IP address: + For in-band communication with the controller, the OpenFlow switch must + be able to determine its own IP address. Its IP address may be configured + statically or dynamically. + . + For static configuration, specify the switch's IP address as a string. + . + For dynamic configuration with DHCP (the most common case), specify "dhcp". + Configuration with DHCP will only work reliably if the network topology + allows the switch to contact the DHCP server before it connects to the + OpenFlow controller. + +Template: openflow-switch/switch-ip-error +Type: error +_Description: The switch IP address is invalid. + The switch IP address must specified as "dhcp" or a valid IP address in + dotted-octet form (e.g. "1.2.3.4"). + +Template: openflow-switch/controller-vconn +Type: string +_Description: Controller location: + Specify how the OpenFlow switch should connect to the OpenFlow controller. + The value should be in form "ssl:HOST[:PORT]" to connect to the controller + over SSL (recommended for security) or "tcp:HOST[:PORT]" to connect over + cleartext TCP. + +Template: openflow-switch/controller-vconn-error +Type: error +_Description: The controller location is invalid. + The controller location must be specifed as "ssl:HOST[:PORT]" to + connect to the controller over SSL (recommended for security) or + "tcp:HOST[:PORT]" to connect over cleartext TCP. + +Template: openflow-switch/pki-uri +Type: string +_Description: OpenFlow PKI server host name or URL: + Specify a URL to the OpenFlow public key infrastructure (PKI). If a + host name or IP address is specified in place of a URL, then + http:///openflow/pki/ will be used, + where is the specified host name or IP address. + . + The OpenFlow PKI is usually on the same machine as the OpenFlow + controller. + . + The setup process will connect to the OpenFlow PKI server over + HTTP, using the system's configured default HTTP proxy (if any). + +Template: openflow-switch/fetch-cacert-failed +Type: error +_Description: The switch CA certificate could not be retrieved. + Retrieval of ${url} failed, with the following status: "${error}". + . + Ensure that the OpenFlow PKI server is correctly configured and + available at ${pki-uri}. If the system is configured to use an HTTP + proxy, also make sure that the HTTP proxy is available and that the + PKI server can be reached through it. + +Template: openflow-switch/verify-controller-ca +Type: select +_Choices: yes, no +Default: yes +_Description: Is ${fingerprint} the controller CA's fingerprint? + If a man-in-the-middle attack is possible in your network + environment, check that the controller CA's fingerprint is really + ${fingerprint}. Answer "yes" if it matches, "no" if + there is a discrepancy. + . + If a man-in-the-middle attack is not a concern, there is no need to + verify the fingerprint. Simply answer "yes". + +Template: openflow-switch/send-cert-req +Type: select +_Choices: yes, no +Default: yes +_Description: Send certificate request to switch CA? + Before it can connect to the controller over SSL, the OpenFlow + switch's key must be signed by the switch certificate authority (CA) + located on the OpenFlow PKI server, which is usually collocated with + the OpenFlow controller. A signing request can be sent to the PKI + server now. + . + Answer "yes" to send a signing request to the switch CA now. This is + ordinarily the correct choice. There is no harm in sending a given + signing request more than once. + . + Answer "no" to skip sending a signing request to the switch CA. + Unless the request has already been sent to the switch CA, manual + sending of the request and signing will be necessary. + +Template: openflow-switch/send-cert-req-failed +Type: error +_Description: The certificate request could not be sent. + Posting to ${url} failed, with the following status: "${error}". + . + Ensure that the OpenFlow PKI server is correctly configured and + available at ${pki-uri}. + +Template: openflow-switch/fetch-switch-cert +Type: select +_Choices: yes, no +_Description: Fetch signed switch certificate from PKI server? + Before it can connect to the controller over SSL, the OpenFlow + switch's key must be signed by the switch certificate authority (CA) + located on the OpenFlow PKI server, which is usually collocated with + the OpenFlow controller. + . + At this point, a signing request has been sent to the switch CA (or + sending a request has been manually skipped), but the signed + certificate has not yet been retrieved. Manual action may need to be + taken at the PKI server to approve the signing request. + . + Answer "yes" to attempt to retrieve the signed switch certificate + from the switch CA. If the switch certificate request has been + signed at the PKI server, this is the correct choice. + . + Answer "no" to postpone switch configuration. The configuration + process must be restarted later, when the switch certificate request + has been signed. + +Template: openflow-switch/fetch-switch-cert-failed +Type: error +_Description: Signed switch certificate could not be retrieved. + The signed switch certificate could not be retrieved from the switch + CA: retrieval of ${url} failed, with the following status: "${error}". + . + This probably indicates that the switch's certificate request has not + yet been signed. If this is the problem, it may be fixed by signing + the certificate request at ${pki-uri}, then trying to fetch the + signed switch certificate again. + +Template: openflow-switch/complete +Type: note +_Description: OpenFlow Switch Setup Finished + Setup of this OpenFlow switch is finished. Complete the setup procedure + to enable the switch. diff --git a/openflow/debian/openflow-switch.README.Debian b/openflow/debian/openflow-switch.README.Debian new file mode 100644 index 00000000..d9a931c1 --- /dev/null +++ b/openflow/debian/openflow-switch.README.Debian @@ -0,0 +1,18 @@ +README.Debian for openflow-switch +--------------------------------- + +* The switch must be configured before it can be used. To configure + it interactively, install the openflow-switch-config package and run + the ofp-switch-setup program. Alternatively, edit + /etc/default/openflow-switch by hand, then start the switch manually + with "/etc/init.d/openflow-switch start". + +* To use the Linux kernel-based switch implementation, you will need + to build and install the OpenFlow kernel module. To do so, install + the openflow-datapath-source package, then follow the instructions + given in /usr/share/doc/openflow-datapath-source/README.Debian + +* This package does not yet support the userspace datapath-based + switch implementation. + + -- Ben Pfaff , Tue, 6 Jan 2009 13:52:33 -0800 diff --git a/openflow/debian/openflow-switch.dirs b/openflow/debian/openflow-switch.dirs new file mode 100644 index 00000000..a53002ff --- /dev/null +++ b/openflow/debian/openflow-switch.dirs @@ -0,0 +1,2 @@ +/etc/openflow-switch +/usr/share/openflow/switch diff --git a/openflow/debian/openflow-switch.init b/openflow/debian/openflow-switch.init new file mode 100755 index 00000000..cd518a71 --- /dev/null +++ b/openflow/debian/openflow-switch.init @@ -0,0 +1,437 @@ +#! /bin/sh +# +# /etc/init.d/openflow-switch +# +# Written by Miquel van Smoorenburg . +# Modified for Debian by Ian Murdock . +# Further changes by Javier Fernandez-Sanguino +# Modified for openflow-switch. +# +# Version: @(#)skeleton 1.9 26-Feb-2001 miquels@cistron.nl +# +### BEGIN INIT INFO +# Provides: openflow-switch +# Required-Start: $network $named $remote_fs $syslog +# Required-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: OpenFlow switch +### END INIT INFO + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +DAEMON=/usr/sbin/secchan +NAME=secchan +DESC=secchan + +test -x $DAEMON || exit 0 + +NICIRA_OUI="002320" + +LOGDIR=/var/log/openflow +PIDFILE=/var/run/$NAME.pid +DHCLIENT_PIDFILE=/var/run/dhclient.of0.pid +DODTIME=1 # Time to wait for the server to die, in seconds + # If this value is set too low you might not + # let some servers to die gracefully and + # 'restart' will not work + +# Include secchan defaults if available +unset NETDEVS +unset MODE +unset SWITCH_IP +unset CONTROLLER +unset PRIVKEY +unset CERT +unset CACERT +unset CACERT_MODE +unset MGMT_VCONNS +unset COMMANDS +unset DAEMON_OPTS +unset CORE_LIMIT +unset DATAPATH_ID +default=/etc/default/openflow-switch +if [ -f $default ] ; then + . $default +fi + +set -e + +running_pid() +{ + # Check if a given process pid's cmdline matches a given name + pid=$1 + name=$2 + [ -z "$pid" ] && return 1 + [ ! -d /proc/$pid ] && return 1 + cmd=`cat /proc/$pid/cmdline | tr "\000" "\n"|head -n 1 |cut -d : -f 1` + # Is this the expected child? + case $cmd in + $name|*/$name) + return 0 + ;; + *) + return 1 + ;; + esac +} + +running() +{ +# Check if the process is running looking at /proc +# (works for all users) + + # No pidfile, probably no daemon present + [ ! -f "$PIDFILE" ] && return 1 + # Obtain the pid and check it against the binary name + pid=`cat $PIDFILE` + running_pid $pid $NAME || return 1 + return 0 +} + +force_stop() { +# Forcefully kill the process + [ ! -f "$PIDFILE" ] && return + if running ; then + kill -15 $pid + # Is it really dead? + [ -n "$DODTIME" ] && sleep "$DODTIME"s + if running ; then + kill -9 $pid + [ -n "$DODTIME" ] && sleep "$DODTIME"s + if running ; then + echo "Cannot kill $NAME (pid=$pid)!" + exit 1 + fi + fi + fi + rm -f $PIDFILE + return 0 +} + +must_succeed() { + echo -n "$1: " + shift + if "$@"; then + echo "success." + else + echo " ERROR." + exit 1 + fi +} + +check_op() { + echo -n "$1: " + shift + if "$@"; then + echo "success." + else + echo " ERROR." + fi +} + +configure_ssl() { + if (test "$CACERT_MODE" != secure && test "$CACERT_MODE" != bootstrap) \ + || test ! -e "$PRIVKEY" || test ! -e "$CERT" \ + || (test ! -e "$CACERT" && test "$CACERT_MODE" != bootstrap); then + if test "$CACERT_MODE" != secure && test "$CACERT_MODE" != bootstrap + then + echo "CACERT_MODE is not set to 'secure' or 'bootstrap'" + fi + if test ! -e "$PRIVKEY"; then + echo "$PRIVKEY: private key missing" >&2 + fi + if test ! -e "$CERT"; then + echo "$CERT: certificate for private key missing" >&2 + fi + if test ! -e "$CACERT" && test "$CACERT_MODE" != bootstrap; then + echo "$CACERT: CA certificate missing (and CA certificate bootstrapping not enabled)" >&2 + fi + echo "Run ofp-switch-setup (in the openflow-switch-config package) or edit /etc/default/openflow-switch to configure" >&2 + if test "$MODE" = discovery; then + echo "You may also delete or rename $PRIVKEY to disable SSL requirement" >&2 + fi + exit 1 + fi + + SSL_OPTS="--private-key=$PRIVKEY --certificate=$CERT" + if test ! -e "$CACERT" && test "$CACERT_MODE" = bootstrap; then + SSL_OPTS="$SSL_OPTS --bootstrap-ca-cert=$CACERT" + else + SSL_OPTS="$SSL_OPTS --ca-cert=$CACERT" + fi +} + +check_int_var() { + eval value=\$$1 + if test -n "$value"; then + if expr "X$value" : 'X[0-9][0-9]*$'; then + if test $value -lt $2; then + echo "warning: The $1 option may not be set to a value below $2, treating as $2" >&2 + eval $1=$2 + fi + else + echo "warning: The $1 option must be set to a number, ignoring" >&2 + unset $1 + fi + fi +} + +check_new_option() { + case $DAEMON_OPTS in + *$1*) + echo "warning: The $1 option in DAEMON_OPTS may now be set with the $2 variable in $default. The setting in DAEMON_OPTS will override the $2 variable, which will prevent the switch UI from configuring $1." >&2 + ;; + esac +} + +case "$1" in + start) + if test -z "$NETDEVS"; then + echo "$default: No network devices configured, switch disabled" >&2 + echo "Run ofp-switch-setup (in the openflow-switch-config package) or edit /etc/default/openflow-switch to configure" >&2 + exit 0 + fi + if test "$MODE" = discovery; then + unset CONTROLLER + elif test "$MODE" = in-band || test "$MODE" = out-of-band; then + if test -z "$CONTROLLER"; then + echo "$default: No controller configured and not configured for discovery, switch disabled" >&2 + echo "Run ofp-switch-setup (in the openflow-switch-config package) or edit /etc/default/openflow-switch to configure" >&2 + exit 0 + fi + else + echo "$default: MODE must set to 'discovery', 'in-band', or 'out-of-band'" >&2 + echo "Run ofp-switch-setup (in the openflow-switch-config package) or edit /etc/default/openflow-switch to configure" >&2 + exit 1 + fi + : ${PRIVKEY:=/etc/openflow-switch/of0-privkey.pem} + : ${CERT:=/etc/openflow-switch/of0-cert.pem} + : ${CACERT:=/etc/openflow-switch/cacert.pem} + case $CONTROLLER in + '') + # Discovery mode. + if test -e "$PRIVKEY"; then + configure_ssl + fi + ;; + tcp:*) + ;; + ssl:*) + configure_ssl + ;; + *) + echo "$default: CONTROLLER must be in the form 'ssl:HOST[:PORT]' or 'tcp:HOST[:PORT]' when not in discovery mode" >&2 + echo "Run ofp-switch-setup (in the openflow-switch-config package) or edit /etc/default/openflow-switch to configure" >&2 + exit 1 + esac + case $DISCONNECTED_MODE in + ''|switch|drop) ;; + *) echo "$default: warning: DISCONNECTED_MODE is not 'switch' or 'drop'" >&2 ;; + esac + + check_int_var RATE_LIMIT 100 + check_int_var INACTIVITY_PROBE 5 + check_int_var MAX_BACKOFF 1 + + check_new_option --fail DISCONNECTED_MODE + check_new_option --stp STP + check_new_option --rate-limit RATE_LIMIT + check_new_option --inactivity INACTIVITY_PROBE + check_new_option --max-backoff MAX_BACKOFF + case $DAEMON_OPTS in + *--rate-limit*) + echo "$default: --rate-limit may now be set with RATE_LIMIT" >&2 + esac + + echo -n "Loading openflow_mod: " + if grep -q '^openflow_mod$' /proc/modules; then + echo "already loaded, nothing to do." + elif modprobe openflow_mod; then + echo "success." + else + echo "ERROR." + echo "openflow_mod has probably not been built for this kernel." + if ! test -d /usr/share/doc/openflow-datapath-source; then + echo "Install the openflow-datapath-source package, then read" + echo "/usr/share/doc/openflow-datapath-source/README.Debian" + else + echo "For instructions, read" + echo "/usr/share/doc/openflow-datapath-source/README.Debian" + fi + exit 1 + fi + + for netdev in $NETDEVS; do + check_op "Removing IP address from $netdev" ifconfig $netdev 0.0.0.0 + done + + must_succeed "Adding datapath" dpctl adddp nl:0 + for netdev in $NETDEVS; do + must_succeed "Adding $netdev to datapath" dpctl addif nl:0 $netdev + done + + xx='[0-9abcdefABCDEF][0-9abcdefABCDEF]' + case $DATAPATH_ID in + '') + # Check if the DMI System UUID contains a Nicira mac address + # that should be used for this datapath. The UUID is assumed + # to be RFC 4122 compliant. + DMIDECODE=`which dmidecode` + if [ -n $DMIDECODE ]; then + UUID_MAC=`$DMIDECODE -s system-uuid | cut -d'-' -f 5` + case $UUID_MAC in + $NICIRA_OUI*) + ifconfig of0 down + must_succeed "Setting of0 MAC address to $UUID_MAC" ifconfig of0 hw ether $UUID_MAC + ifconfig of0 up + ;; + esac + fi + ;; + $xx:$xx:$xx:$xx:$xx:$xx) + ifconfig of0 down + must_succeed "Setting of0 MAC address to $DATAPATH_ID" ifconfig of0 hw ether $DATAPATH_ID + ifconfig of0 up + ;; + *) + echo "DATAPATH_ID is not a valid MAC address in the form XX:XX:XX:XX:XX:XX, ignoring" >&2 + ;; + esac + + if test "$MODE" = in-band; then + if test "$SWITCH_IP" = dhcp; then + must_succeed "Temporarily disabling of0" ifconfig of0 down + else + COMMAND="ifconfig of0 $SWITCH_IP" + if test -n "$SWITCH_NETMASK"; then + COMMAND="$COMMAND netmask $SWITCH_NETMASK" + fi + must_succeed "Configuring of0: $COMMAND" $COMMAND + if test -n "$SWITCH_GATEWAY"; then + # This can fail because the route already exists, + # so we don't insist that it succeed. + COMMAND="route add default gw $SWITCH_GATEWAY" + check_op "Adding default route: $COMMAND" $COMMAND + fi + fi + else + must_succeed "Disabling of0" ifconfig of0 down + fi + + if test -n "$CORE_LIMIT"; then + check_op "Setting core limit to $CORE_LIMIT" ulimit -c "$CORE_LIMIT" + fi + + # Compose secchan options. + set -- + set -- "$@" --verbose=ANY:console:emer --verbose=ANY:syslog:err + set -- "$@" --log-file + set -- "$@" --detach --pidfile=$PIDFILE + for vconn in $MGMT_VCONNS; do + set -- "$@" --listen="$vconn" + done + if test -n "$MONITOR_VCONN"; then + set -- "$@" --monitor="$MONITOR_VCONN" + fi + if test -n "$COMMANDS"; then + set -- "$@" --command-acl="$COMMANDS" + fi + case $STP in + yes) set -- "$@" --stp ;; + no) set -- "$@" --no-stp ;; + esac + case $DISCONNECTED_MODE in + switch) set -- "$@" --fail=open ;; + drop) set -- "$@" --fail=closed ;; + esac + if test -n "$RATE_LIMIT"; then + set -- "$@" --rate-limit=$RATE_LIMIT + fi + if test -n "$INACTIVITY_PROBE"; then + set -- "$@" --inactivity-probe=$INACTIVITY_PROBE + fi + if test -n "$MAX_BACKOFF"; then + set -- "$@" --max-backoff=$MAX_BACKOFF + fi + set -- "$@" $SSL_OPTS $DAEMON_OPTS + if test "$MODE" = out-of-band; then + set -- "$@" --out-of-band + fi + set -- "$@" nl:0 "$CONTROLLER" + echo -n "Starting $DESC: " + start-stop-daemon --start --quiet --pidfile $PIDFILE \ + --exec $DAEMON -- "$@" + if running; then + echo "$NAME." + else + echo " ERROR." + fi + + if test "$MODE" = in-band && test "$SWITCH_IP" = dhcp; then + echo -n "Starting dhclient on of0: " + start-stop-daemon --start --quiet --pidfile $DHCLIENT_PIDFILE \ + --exec /sbin/dhclient -- -q -pf $DHCLIENT_PIDFILE of0 + if running; then + echo "dhclient." + else + echo " ERROR." + fi + fi + ;; + stop) + if test -e /var/run/dhclient.of0.pid; then + echo -n "Stopping dhclient on of0: " + start-stop-daemon --stop --quiet --oknodo \ + --pidfile $DHCLIENT_PIDFILE --exec /sbin/dhclient + echo "dhclient." + fi + + echo -n "Stopping $DESC: " + start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE \ + --exec $DAEMON + echo "$NAME." + + for netdev in $NETDEVS; do + check_op "Removing $netdev from datapath" dpctl delif nl:0 $netdev + done + check_op "Deleting datapath" dpctl deldp nl:0 + check_op "Unloading kernel module" modprobe -r openflow_mod + ;; + force-stop) + echo -n "Forcefully stopping $DESC: " + force_stop + if ! running; then + echo "$NAME." + else + echo " ERROR." + fi + ;; + reload) + ;; + force-reload) + start-stop-daemon --stop --test --quiet --pidfile \ + $PIDFILE --exec $DAEMON \ + && $0 restart \ + || exit 0 + ;; + restart) + $0 stop || true + $0 start + ;; + status) + echo -n "$NAME is " + if running ; then + echo "running" + else + echo " not running." + exit 1 + fi + ;; + *) + N=/etc/init.d/$NAME + echo "Usage: $N {start|stop|restart|force-reload|status|force-stop}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/openflow/debian/openflow-switch.install b/openflow/debian/openflow-switch.install new file mode 100644 index 00000000..b325e3cc --- /dev/null +++ b/openflow/debian/openflow-switch.install @@ -0,0 +1,6 @@ +_debian/secchan/ofprotocol usr/sbin +_debian/utilities/dpctl usr/sbin +_debian/utilities/ofp-discover usr/sbin +_debian/utilities/ofp-kill usr/sbin +debian/openflow/usr/share/openflow/commands/* usr/share/openflow/commands +debian/commands/* usr/share/openflow/commands diff --git a/openflow/debian/openflow-switch.logrotate b/openflow/debian/openflow-switch.logrotate new file mode 100644 index 00000000..b2136907 --- /dev/null +++ b/openflow/debian/openflow-switch.logrotate @@ -0,0 +1,11 @@ +/var/log/openflow/secchan.log { + daily + compress + create 640 root adm + delaycompress + missingok + rotate 30 + postrotate + vlogconf --target /var/run/secchan.pid --reopen + endscript +} diff --git a/openflow/debian/openflow-switch.manpages b/openflow/debian/openflow-switch.manpages new file mode 100644 index 00000000..dd636ac8 --- /dev/null +++ b/openflow/debian/openflow-switch.manpages @@ -0,0 +1,4 @@ +_debian/secchan/ofprotocol.8 +_debian/utilities/ofp-discover.8 +_debian/utilities/ofp-kill.8 +_debian/utilities/dpctl.8 diff --git a/openflow/debian/openflow-switch.postinst b/openflow/debian/openflow-switch.postinst new file mode 100755 index 00000000..4f96db3a --- /dev/null +++ b/openflow/debian/openflow-switch.postinst @@ -0,0 +1,51 @@ +#!/bin/sh +# postinst script for openflow-switch +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `configure' +# * `abort-upgrade' +# * `abort-remove' `in-favour' +# +# * `abort-remove' +# * `abort-deconfigure' `in-favour' +# `removing' +# +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + configure) + DEFAULT=/etc/default/openflow-switch + TEMPLATE=/usr/share/openflow/switch/default.template + if ! test -e $DEFAULT; then + cp $TEMPLATE $DEFAULT + else + for var in $(awk -F'[ :]' '/^# [_A-Z0-9]+:/{print $2}' $TEMPLATE) + do + if ! grep $var $DEFAULT >/dev/null 2>&1; then + echo >> $DEFAULT + sed -n "/$var:/,/$var=/p" $TEMPLATE >> $DEFAULT + fi + done + fi + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +#DEBHELPER# + +exit 0 + + diff --git a/openflow/debian/openflow-switch.postrm b/openflow/debian/openflow-switch.postrm new file mode 100755 index 00000000..20bab0e0 --- /dev/null +++ b/openflow/debian/openflow-switch.postrm @@ -0,0 +1,43 @@ +#!/bin/sh +# postrm script for openflow-switch +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `remove' +# * `purge' +# * `upgrade' +# * `failed-upgrade' +# * `abort-install' +# * `abort-install' +# * `abort-upgrade' +# * `disappear' +# +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + purge) + rm -f /etc/default/openflow-switch + ;; + + remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) + ;; + + *) + echo "postrm called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 + + diff --git a/openflow/debian/openflow-switch.template b/openflow/debian/openflow-switch.template new file mode 100644 index 00000000..f3f641e8 --- /dev/null +++ b/openflow/debian/openflow-switch.template @@ -0,0 +1,169 @@ +# This is a POSIX shell fragment -*- sh -*- + +# To configure the secure channel, fill in the following properly and +# uncomment them. Afterward, the secure channel will come up +# automatically at boot time. It can be started immediately with +# /etc/init.d/openflow-switch start +# Alternatively, use the ofp-switch-setup program (from the +# openflow-switch-config package) to do everything automatically. + +# NETDEVS: Which network devices should the OpenFlow switch include? +# +# List the network devices that should become part of the OpenFlow +# switch, separated by spaces. At least two devices must be selected +# for this machine to be a useful switch. Unselecting all network +# devices will disable the OpenFlow switch entirely. +# +# The network devices that you select should not be configured with IP +# or IPv6 addresses, even if the switch contacts the controller over +# one of the selected network devices. This is because a running +# OpenFlow switch takes over network devices at a low level: they +# become part of the switch and cannot be used for other purposes. +#NETDEVS="" + +# MODE: The OpenFlow switch has three modes that determine how it +# reaches the controller: +# +# * in-band with discovery: A single network is used for OpenFlow +# traffic and other data traffic; that is, the switch contacts the +# controller over one of the network devices selected as OpenFlow +# switch ports. The switch automatically determines the location of +# the controller using a DHCP request with an OpenFlow-specific +# vendor option. This is the most common case. +# +# * in-band: As above, but the location of the controller is manually +# configured. +# +# * out-of-band: OpenFlow traffic uses a network separate from the +# data traffic that it controls. If this is the case, the control +# network must already be configured on a network device other than +# one of those selected as an OpenFlow switch port in the previous +# question. +# +# Set MODE to 'discovery', 'in-band', or 'out-of-band' for these +# respective cases. +MODE=discovery + +# SWITCH_IP: In 'in-band' mode, the switch's IP address may be +# configured statically or dynamically: +# +# * For static configuration, specify the switch's IP address as a +# string. In this case you may also set SWITCH_NETMASK and +# SWITCH_GATEWAY appropriately (see below). +# +# * For dynamic configuration with DHCP (the most common case), +# specify "dhcp". Configuration with DHCP will only work reliably +# if the network topology allows the switch to contact the DHCP +# server before it connects to the OpenFlow controller. +# +# This setting has no effect unless MODE is set to 'in-band'. +SWITCH_IP=dhcp + +# SWITCH_NETMASK: IP netmask to use in 'in-band' mode when the switch +# IP address is not 'dhcp'. +#SWITCH_NETMASK=255.255.255.0 + +# SWITCH_GATEWAY: IP gateway to use in 'in-band' mode when the switch +# IP address is not 'dhcp'. +#SWITCH_GATEWAY=192.168.1.1 + +# CONTROLLER: Location of controller. +# One of the following formats: +# tcp:HOST[:PORT] via TCP to PORT (default: 6633) on HOST +# ssl:HOST[:PORT] via SSL to PORT (default: 6633) on HOST +# The default below assumes that the controller is running locally. +# This setting has no effect when MODE is set to 'discovery'. +#CONTROLLER="tcp:127.0.0.1" + +# PRIVKEY: Name of file containing switch's private key. +# Required if SSL enabled. +#PRIVKEY=/etc/openflow-switch/of0-privkey.pem + +# CERT: Name of file containing certificate for private key. +# Required if SSL enabled. +#CERT=/etc/openflow-switch/of0-cert.pem + +# CACERT: Name of file containing controller CA certificate. +# Required if SSL enabled. +#CACERT=/etc/openflow-switch/cacert.pem + +# CACERT_MODE: Two modes are available: +# +# * secure: The controller CA certificate named in CACERT above must exist. +# (You must copy it manually from the PKI server or another trusted source.) +# +# * bootstrap: If the controller CA certificate named in CACERT above does +# not exist, the switch will obtain it from the controller the first time +# it connects and save a copy to the file named in CACERT. This is insecure, +# in the same way that initial connections with ssh are insecure, but +# it is convenient. +# +# Set CACERT_MODE to 'secure' or 'bootstrap' for these respective cases. +#CACERT_MODE=secure + +# MGMT_VCONNS: List of vconns (space-separated) on which secchan +# should listen for management connections from dpctl, etc. +# openflow-switchui by default connects to +# unix:/var/run/secchan.mgmt, so do not disable this if you want to +# use openflow-switchui. +MGMT_VCONNS="punix:/var/run/secchan.mgmt" + +# MONITOR_VCONN: Name of vconn on which secchan should listen for +# monitoring connections from dpctl. +MONITOR_VCONN="punix:/var/run/secchan.monitor" + +# COMMANDS: Access control list for the commands that can be executed +# remotely over the OpenFlow protocol, as a comma-separated list of +# shell glob patterns. Negative patterns (beginning with !) act as a +# blacklist. To be executable, a command name must match one positive +# pattern and not match any negative patterns. +#COMMANDS="reboot,update" + +# DISCONNECTED_MODE: Switch behavior when attempts to connect to the +# controller repeatedly fail, either 'switch', to act as an L2 switch +# in this case, or 'drop', to drop all packets (except those necessary +# to connect to the controller). If unset, the default is 'drop'. +#DISCONNECTED_MODE=switch + +# STP: Enable or disabled 802.1D-1998 Spanning Tree Protocol. Set to +# 'yes' to enable STP, 'no' to disable it. If unset, secchan's +# current default is 'no' (but this may change in the future). +#STP=no + +# RATE_LIMIT: Maximum number of received frames, that do not match any +# existing switch flow, to forward up to the controller per second. +# The valid range is 100 and up. If unset, this rate will not be +# limited. +#RATE_LIMIT=1000 + +# INACTIVITY_PROBE: The maximum number of seconds of inactivity on the +# controller connection before secchan sends an inactivity probe +# message to the controller. The valid range is 5 and up. If unset, +# secchan defaults to 15 seconds. +#INACTIVITY_PROBE=5 + +# MAX_BACKOFF: The maximum time that secchan will wait between +# attempts to connect to the controller. The valid range is 1 and up. +# If unset, secchan defaults to 15 seconds. +#MAX_BACKOFF=15 + +# DAEMON_OPTS: Additional options to pass to secchan, e.g. "--fail=open" +DAEMON_OPTS="" + +# CORE_LIMIT: Maximum size for core dumps. +# +# Leaving this unset will use the system default. Setting it to 0 +# will disable core dumps. Setting it to "unlimited" will dump all +# core files regardless of size. +#CORE_LIMIT=unlimited + +# DATAPATH_ID: Identifier for this switch. +# +# By default, the switch checks if the DMI System UUID contains a Nicira +# mac address to use as a datapath ID. If not, then the switch generates +# a new, random datapath ID every time it starts up. By setting this +# value, the supplied datapath ID will always be used. +# +# Set DATAPATH_ID to a MAC address in the form XX:XX:XX:XX:XX:XX where each +# X is a hexadecimal digit (0-9 or a-f). +#DATAPATH_ID=XX:XX:XX:XX:XX:XX diff --git a/openflow/debian/po/POTFILES.in b/openflow/debian/po/POTFILES.in new file mode 100644 index 00000000..e3ea07e3 --- /dev/null +++ b/openflow/debian/po/POTFILES.in @@ -0,0 +1 @@ +[type: gettext/rfc822deb] openflow-switch-config.templates diff --git a/openflow/debian/rules b/openflow/debian/rules new file mode 100755 index 00000000..539c8f3d --- /dev/null +++ b/openflow/debian/rules @@ -0,0 +1,163 @@ +#!/usr/bin/make -f +# -*- makefile -*- +# Sample debian/rules that uses debhelper. +# +# This file was originally written by Joey Hess and Craig Small. +# As a special exception, when this file is copied by dh-make into a +# dh-make output file, you may use that output file without restriction. +# This special exception was added by Craig Small in version 0.37 of dh-make. +# +# Modified to make a template file for a multi-binary package with separated +# build-arch and build-indep targets by Bill Allombert 2001 + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +# This has to be exported to make some magic below work. +export DH_OPTIONS + +# prefix of the target package name +PACKAGE=openflow-datapath-module +# modifieable for experiments or debugging m-a +MA_DIR ?= /usr/share/modass +# load generic variable handling +-include $(MA_DIR)/include/generic.make +# load default rules +-include $(MA_DIR)/include/common-rules.make + +-include debian/rules.ext + +DATAPATH_CONFIGURE_OPTS = --enable-snat + +# Official build number. Leave set to 0 if not an official build. +BUILD_NUMBER = 0 + +configure: configure-stamp +configure-stamp: + dh_testdir + test -e configure || ./boot.sh + test -d _debian || mkdir _debian + cd _debian && ( \ + test -e Makefile || \ + ../configure --prefix=/usr --localstatedir=/var --enable-ssl \ + --with-build-number=$(BUILD_NUMBER) \ + $(DATAPATH_CONFIGURE_OPTS)) + $(ext_configure) + touch configure-stamp + +#Architecture +build: build-arch build-indep + +build-arch: build-arch-stamp +build-arch-stamp: configure-stamp + $(MAKE) -C _debian + $(ext_build_arch) + touch $@ + +build-indep: build-indep-stamp +build-indep-stamp: configure-stamp + $(MAKE) -C _debian dist distdir=openflow + $(ext_build_indep) + touch $@ + +clean: + dh_testdir + dh_testroot + rm -f build-arch-stamp build-indep-stamp configure-stamp + rm -rf _debian + [ ! -f Makefile ] || $(MAKE) distclean + $(ext_clean) + dh_clean + debconf-updatepo + +MAJOR=$(shell echo $(KVERS) | sed -e 's/\(...\).*/\1/') +ifeq ($(MAJOR),2.6) +KO=k +l2x=l26 +dpdir=datapath/linux-2.6 +else +KO= +l2x=l24 +dpdir=datapath/linux-2.4 +endif + +kdist_clean: + dh_clean + rm -rf openflow + +kdist_config: prep-deb-files + +binary-modules: DSTDIR = $(CURDIR)/debian/$(PKGNAME)/lib/modules/$(KVERS) +binary-modules: prep-deb-files + dh_testdir + dh_testroot + dh_clean -k + tar xzf openflow.tar.gz + cd openflow && ./configure --with-$(l2x)=$(KSRC) $(DATAPATH_CONFIGURE_OPTS) --with-build-number=$(BUILD_NUMBER) + cd openflow && $(MAKE) -C $(dpdir) + install -d -m755 $(DSTDIR) + install -m644 openflow/$(dpdir)/*_mod.$(KO)o $(DSTDIR)/ + dh_installdocs + dh_installchangelogs + dh_compress + dh_fixperms + dh_installdeb + dh_gencontrol + dh_md5sums + dh_builddeb --destdir=$(DEB_DESTDIR) + +install: install-indep install-arch +install-indep: build-indep + dh_testdir + dh_testroot + dh_clean -k -i + dh_installdirs -i + dh_install -i + cd debian/openflow-datapath-source/usr/src && tar -c modules | bzip2 -9 > openflow-datapath.tar.bz2 && rm -rf modules + install -m644 debian/openflow-pki-server.apache2 debian/openflow-pki-server/etc/apache2/sites-available/openflow-pki + install -m1777 -d debian/corekeeper/var/log/core + $(ext_install_indep) + +install-arch: build-arch + dh_testdir + dh_testroot + dh_clean -k -s + dh_installdirs -s + $(MAKE) -C _debian DESTDIR=$(CURDIR)/debian/openflow install + cp debian/openflow-switch-config.overrides debian/openflow-switch-config/usr/share/lintian/overrides/openflow-switch-config + cp debian/openflow-switch.template debian/openflow-switch/usr/share/openflow/switch/default.template + dh_install -s + $(ext_install_arch) + +# Must not depend on anything. This is to be called by +# binary-arch/binary-indep +# in another 'make' thread. +binary-common: + dh_testdir + dh_testroot + dh_installchangelogs + dh_installdocs + dh_installexamples + dh_installdebconf + dh_installlogrotate + dh_installinit + dh_installcron + dh_installman + dh_link + dh_strip --dbg-package=openflow-dbg + dh_compress + dh_fixperms -X var/log/core + dh_perl + dh_makeshlibs + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb +binary-indep: install-indep + $(MAKE) -f debian/rules DH_OPTIONS=-i binary-common +binary-arch: install-arch + $(MAKE) -f debian/rules DH_OPTIONS=-s binary-common + +binary: binary-arch binary-indep +.PHONY: build clean binary-indep binary-arch binary install install-indep install-arch configure diff --git a/openflow/doc/of-spec/.gitignore b/openflow/doc/of-spec/.gitignore new file mode 100644 index 00000000..7723a762 --- /dev/null +++ b/openflow/doc/of-spec/.gitignore @@ -0,0 +1,8 @@ +/*.aux +/*.log +/*.out +/*.pdf +/*.ps +/define +/enum +/struct diff --git a/openflow/doc/of-spec/Makefile b/openflow/doc/of-spec/Makefile new file mode 100644 index 00000000..0e4c9462 --- /dev/null +++ b/openflow/doc/of-spec/Makefile @@ -0,0 +1,40 @@ +TARGET=openflow-spec-v1.0.0 + +BIBTEX := bibtex +TGIF := tgif +XFIG := xfig +GNUPLOT:= gnuplot + +SOURCES=openflow-spec-v1.0.0.tex\ + appendix.tex + +all: $(TARGET).ps +pdf: all + +$(TARGET).pdf: Makefile $(SOURCES) + ./make_latex_input.pl + texi2pdf $(TARGET).tex + +color: $(TARGET).pdf + pdflatex $(TARGET).tex + pdftops $(TARGET).pdf + +$(TARGET).ps: $(TARGET).pdf + pdftops $(TARGET).pdf + +%.pdf : %.fig #Makefile + fig2dev -L pdf -b 1 $< $@ + +%.eps : %.dia #Makefile + dia --nosplash -e $@ $< + +%.eps : %.obj + TMPDIR=/tmp $(TGIF) -print -eps $< + + +%.pdf : %.eps #Makefile + epstopdf $< + +clean: + rm -f *.aux *.log *.out *.bbl *.blg *~ *.bak $(TARGET).ps $(TARGET).pdf + rm -rf define enum struct diff --git a/openflow/doc/of-spec/README b/openflow/doc/of-spec/README new file mode 100644 index 00000000..a010f5dd --- /dev/null +++ b/openflow/doc/of-spec/README @@ -0,0 +1,3 @@ +To build the latest OpenFlow specification, you should just be able to +type "make". For this to work, you'll need to have the texinfo and +"listings.sty" packages installed. diff --git a/openflow/doc/of-spec/appendix.tex b/openflow/doc/of-spec/appendix.tex new file mode 100755 index 00000000..ffac6bbb --- /dev/null +++ b/openflow/doc/of-spec/appendix.tex @@ -0,0 +1,429 @@ +%\appendix +\section{Appendix A: The OpenFlow Protocol} +The heart of the OpenFlow spec is the set of structures used for OpenFlow Protocol messages. +\\\\ +The structures, defines, and enumerations described below are derived from the file \verb|include/openflow/openflow.h|, which is part of the standard OpenFlow distribution. All structures are packed with padding and 8-byte aligned, as checked by the assertion statements. All OpenFlow messages are sent in big-endian format. + +\subsection{OpenFlow Header} +Each OpenFlow message begins with the OpenFlow header: + +\input{struct/ofp_header} +The version specifies the OpenFlow protocol version being used. During the current draft phase of the OpenFlow Protocol, the most significant bit will be set to indicate an experimental version and the lower bits will indicate a revision number. The current version is \input{define/OFP_VERSION}. The final version for a Type 0 switch will be 0x00. The length field indicates the total length of the message, so no additional framing is used to distinguish one frame from the next. The type can have the following values: + +\input{enum/ofp_type} + +\subsection{Common Structures} +This section describes structures used by multiple messages. + +\subsubsection{Port Structures} +Physical ports are described with the following structure: + +\input{struct/ofp_phy_port} +The \verb|port_no| field is a value the datapath associates with a physical port. The \verb|hw_addr| field typically is the MAC address for the port; \verb|OFP_MAX_ETH_ALEN| is 6. The name field is a null-terminated string containing a human-readable name for the interface. The value of \verb|OFP_MAX_PORT_NAME_LEN| is 16. +\\\\ +The \verb|config| field describes spanning tree and administrative settings with the following structure: + +\input{enum/ofp_port_config} +The port config bits indicate whether a port has been administratively brought down, options for handling 802.1D spanning tree packets, and how to handle incoming and outgoing packets. These bits, configured over multiple switches, enable an OpenFlow network to safely flood packets along either a custom or 802.1D spanning tree. +\\\\ +The controller may set \verb|OFPPFL_NO_STP| to 0 to enable STP on a port or to 1 to disable STP on a port. (The latter corresponds to the Disabled STP port state.) The default is switch implementation-defined; the OpenFlow reference implementation by default sets this bit to 0 (enabling STP). +\\\\ +When \verb|OFPPFL_NO_STP| is 0, STP controls the \verb|OFPPFL_NO_FLOOD| and \verb|OFPPFL_STP_*| bits directly. \verb|OFPPFL_NO_FLOOD| is set to 0 when the STP port state is Forwarding, otherwise to 1. The bits in \verb|OFPPFL_STP_MASK| are set to one of the other \verb|OFPPFL_STP_*| values according to the current STP port state. +\\\\ +When the port flags are changed by STP, the switch sends an \verb|OFPT_PORT_STATUS| message to notify the controller of the change. The \verb|OFPPFL_NO_RECV|, \verb|OFPPFL_NO_RECV_STP|, \verb|OFPPFL_NO_FWD|, and \verb|OFPPFL_NO_PACKET_IN| bits in the OpenFlow port flags may be useful for the controller to implement STP, although they interact poorly with in-band control. +\\\\ +The \verb|state| field describes the spanning tree state and whether a physical link is present, with the following structure: + +\input{enum/ofp_port_state} +All port state bits are read-only, representing spanning tree and physical link state. +\\\\ +The port numbers use the following conventions: + +\input{enum/ofp_port} +The \verb|curr|, \verb|advertised|, \verb|supported|, and \verb|peer| fields indicate link modes (10M to 10G full and half-duplex), link type (copper/fiber) and link features (autonegotiation and pause). Port features are represent by the following structure: + +\input{enum/ofp_port_features} +Multiple of these flags may be set simultaneously. + +\subsubsection{\qosupd{Queue Structures}} +\label{cts:qos} +\qosupd{An OpenFlow switch provides limited Quality-of-Service support + (QoS) through a simple queuing +mechanism. One (or more) queues can attach to a port and be used to map flows +on it. Flows mapped to a specific queue will be treated according to +that queue's configuration (e.g. min rate). +\\\\ +A queue is described by the} \verb|ofp_packet_queue| \qosupd{structure: +\input{struct/ofp_packet_queue} +Each queue is further described by a set of properties, each of a +specific type and configuration. +\input{enum/ofp_queue_properties} +Each queue property description starts with a common header: +\input{struct/ofp_queue_prop_header} +Currently, there is only a minimum-rate type queue, described by the} +\verb|ofp_queue_prop_min_rate| \qosupd{structure: +\input{struct/ofp_queue_prop_min_rate}} + +\subsubsection{Flow Match Structures} +When describing a flow entry, the following structure is used: + +\input{struct/ofp_match} +The \verb|wildcards| field has a number of flags that may be set: + +\input{enum/ofp_flow_wildcards} +If no wildcards are set, then the \verb|ofp_match| exactly describes a flow, over the entire OpenFlow 12-tuple. On the other extreme, if all the wildcard flags are set, then every flow will match. +\\\\ +The source and destination netmasks are each specified with a 6-bit number in the wildcard description. It is interpreted similar to the CIDR suffix, but with the opposite meaning, since this is being used to indicate which bits in the IP address should be treated as ``wild". For example, a CIDR suffix of "24" means to use a netmask of ``255.255.255.0". However, a wildcard mask value of ``24" means that the least-significant 24-bits are wild, so it forms a netmask of ``255.0.0.0". + +\subsubsection{Flow Action Structures} +A number of actions may be associated with flows or packets. The currently defined action types are: + +\input{enum/ofp_action_type} +Output \qosupd{and enqueue} actions are described in Section \ref{ft:actions}, while Field-Modify actions are described in Table \ref{table:field modify actions}. An action definition contains the action type, length, and any associated data: + +\input{struct/ofp_action_header} +An \verb|action_output| has the following fields: + +\input{struct/ofp_action_output} +The \verb|max_len| indicates the maximum amount of data from a packet that should be sent when the port is \verb|OFPP_CONTROLLER|. If \verb|max_len| is zero, the switch must send a zero-size \verb|packet_in| message. The \verb|port| specifies the physical port from which packets should be sent. + \\\\ +\qosupd{The enqueue action maps a flow to an already-configured queue, regardless of the TOS and VLAN PCP bits. + The packet should not change after an enqueue action. If the switch + needs to set the TOS/PCP bits for internal handling, the original values + should be restored before sending the packet out. +\\\\ +A switch may support only queues that are tied to specific PCP/TOS +bits. In that case, we cannot map an arbitrary flow to a specific +queue, therefore the action ENQUEUE is not supported. The user can +still use these queues and map +flows to them by setting the relevant fields (TOS, VLAN PCP). +\\\\ +The enqueue action has the following fields: + +\input{struct/ofp_action_enqueue}} +An \verb|action_vlan_vid| has the following fields: + +\input{struct/ofp_action_vlan_vid} +The \verb|vlan_vid| field is 16 bits long, when an actual VLAN id is only 12 bits. The value \verb|0xffff| is used to indicate that no VLAN id was set. +\\\\ +An \verb|action_vlan_pcp| has the following fields: + +\input{struct/ofp_action_vlan_pcp} +The \verb|vlan_pcp| field is 8 bits long, but only the lower 3 bits have meaning. +\\\\ +An \verb|action_strip_vlan| takes no arguments and consists only of a generic \verb|ofp_action_header|. This action strips the VLAN tag if one is present. +\\\\ +An \verb|action_dl_addr| has the following fields: + +\input{struct/ofp_action_dl_addr} +The \verb|dl_addr| field is the MAC address to set. +\\\\ +An \verb|action_nw_addr| has the following fields: + +\input{struct/ofp_action_nw_addr} +The \verb|nw_addr| field is the IP address to set. +\\\\ +An \verb|action_nw_tos| has the following fields: + +\input{struct/ofp_action_nw_tos} +The \verb|nw_tos| field is the 6 upper bits of the ToS field to set, in the original bit positions (shifted to the left by 2). +\\\\ +An \verb|action_tp_port| has the following fields: + +\input{struct/ofp_action_tp_port} +The \verb|tp_port| field is the TCP/UDP/other port to set. +\\\\ +An \verb|action_vendor| has the following fields: + +\input{struct/ofp_action_vendor_header} +The \verb|vendor| field is the Vendor ID, which takes the same form as in struct \verb|ofp_vendor|. + +\subsection{Controller-to-Switch Messages} + +\subsubsection{Handshake} +\label{cts:handshake} +Upon TLS session establishment, the controller sends an \verb|OFPT_FEATURES_REQUEST| message. This message does not contain a body beyond the OpenFlow header. The switch responds with an \verb|OFPT_FEATURES_REPLY| message: + +\input{struct/ofp_switch_features} +The \verb|datapath_id| field uniquely identifies a datapath. The lower 48 bits are intended for the switch MAC address, while the top 16 bits are up to the implementer. An example use of the top 16 bits would be a VLAN ID to distinguish multiple virtual switch instances on a single physical switch. This field should be treated as an opaque bit string by controllers. +\\\\ +The \verb|n_tables| field describes the number of tables supported by the switch, each of which can have a different set of supported wildcard bits and number of entries. When the controller and switch first communicate, the controller will find out how many tables the switch supports from the Features Reply. If it wishes to understand the size, types, and order in which tables are consulted, the controller sends a \verb|OFPST_TABLE| stats request. A switch must return these tables in the order the packets traverse the tables, with all exact-match tables listed before all tables with wildcards. +\\\\ +The \verb|capabilities| field uses the following flags: + +\input{enum/ofp_capabilities} +The \verb|actions| field is a bitmap of actions supported by the switch. The list of actions is found in Section~\ref{ft:actions}; all actions marked Required must be supported. Vendor actions should \emph{not} be reported via this bitmask. The bitmask uses the values from \verb|ofp_action_type| as the number of bits to shift left for an associated action. For example, \verb|OFPAT_SET_DL_VLAN| would use the flag \verb|0x00000002|. +\\\\ +The \verb|ports| field is an array of \verb|ofp_phy_port| structures that describe all the physical ports in the system that support OpenFlow. The number of port elements is inferred from the length field in the OpenFlow header. + +\subsubsection{Switch Configuration} +The controller is able to set and query configuration parameters in the switch with the \verb|OFPT_SET_CONFIG| and \verb|OFPT_GET_CONFIG_REQUEST| messages, respectively. The switch responds to a configuration request with an \verb|OFPT_GET_CONFIG_REPLY| message; it does not reply to a request to set the configuration. +\\\\ +There is no body for \verb|OFPT_GET_CONFIG_REQUEST| beyond the OpenFlow header. The \verb|OFPT_SET_CONFIG| and \verb|OFPT_GET_CONFIG_REPLY| use the following: + +\input{struct/ofp_switch_config} +The configuration flags include the following: + +\input{enum/ofp_config_flags} +The \verb|OFPC_FRAG_*| flags indicate whether IP fragments should be treated normally, dropped, or reassembled. ``Normal" handling of fragments means that an attempt should be made to pass the fragments through the OpenFlow tables. If any field is not present (e.g., the TCP/UDP ports didn't fit), then the packet should not match any entry that has that field set. +\\\\ +The \verb|miss_send_len| field defines the number of bytes of each packet sent to the controller as a result of both flow table misses and flow table hits with the controller as the destination. If this field equals 0, the switch must send a zero-size \verb|packet_in| message. + +\subsubsection{Modify State Messages} +\paragraph{Modify Flow Entry Message} +Modifications to the flow table from the controller are done with the \verb|OFPT_FLOW_MOD| message: + +\input{struct/ofp_flow_mod} +The \verb|cookie| field is an opaque data value that is set by the +controller. It is not used in any matching functions, and thus does not +need to reside in hardware. The value -1 (0xffffffffffffffff) is +reserved and must not be used. It is required that when \verb|command| is +\verb|OFPC_MODIFY| or \verb|OFPC_MODIFY_STRICT| that matched flows have +their \verb|cookie| field updated appropriately. +\\\\ +The \verb|command| field must be one of the following: + +\input{enum/ofp_flow_mod_command} +The differences between \verb|OFPFC_MODIFY| and \verb|OFPFC_MODIFY_STRICT| are explained in Section \ref{flow_table:sec_chan:flow_mod} and differences between \verb|OFPFC_DELETE| and \verb|OFPFC_DELETE_STRICT| are explained in Section \ref{flow_table:sec_chan:flow_removal}. +\\\\ +The \verb|idle_timeout| and \verb|hard_timeout| fields control how quickly flows expire. +\\\\ +If the \verb|idle_timeout| is set and the \verb|hard_timeout| is zero, the entry must expire after \verb|idle_timeout| seconds with no received traffic. If the \verb|idle_timeout| is zero and the \verb|hard_timeout| is set, the entry must expire in \verb|hard_timeout| seconds regardless of whether or not packets are hitting the entry. +\\\\ +If both \verb|idle_timeout| and \verb|hard_timeout| are set, the flow will timeout after \verb|idle_timeout| seconds with no traffic, or \verb|hard_timeout| seconds, whichever comes first. If both \verb|idle_timeout| and \verb|hard_timeout| are zero, the entry is considered permanent and will never time out. It can still be removed with a \verb|flow_mod| message of type \verb|OFPFC_DELETE|. +\\\\ +The \verb|priority| field is only relevant for flow entries with wildcard fields. The priority field indicates table priority, where higher numbers are higher priorities; the switch must keep the highest-priority wildcard entries in the lowest-numbered (fastest) wildcard table, to ensure correctness. It is the responsibility of each switch implementer to ensure that exact entries always match before wildcards entries, regardless of the table configuration. +\\\\ +The \verb|buffer_id| refers to a buffered packet sent by the \verb|OFPT_PACKET_IN| message. +\\\\ +The \verb|out_port| field optionally filters the scope of DELETE and DELETE\_STRICT messages by output port. If \verb|out_port| contains a value other than \verb|OFPP_NONE|, it introduces a constraint when matching. This constraint is that the rule must contain an output action directed at that port. Other constraints such as \verb|ofp_match| structs and priorities are still used; this is purely an \emph{additional} constraint. Note that to disable output port filtering, \verb|out_port| must be set to \verb|OFPP_NONE|, since 0 is a valid port id. This field is ignored by ADD, MODIFY, and MODIFY\_STRICT messages. +\\\\ +The \verb|flags| field may include the follow flags: + +\input{enum/ofp_flow_mod_flags} +When the \verb|OFPFF_SEND_FLOW_REM| flag is set, the switch must send a flow removed message when the flow expires. The default is for the switch to not send flow removed messages for newly added flows. +\\\\ +When the \verb|OFPFF_CHECK_OVERLAP| flag is set, the switch must check that there are no conflicting entries with the same priority. If there is one, the flow mod fails and an error code is returned. +\\\\ +When the \verb|OFPFF_EMERG_| flag is set, the switch must consider this flow entry as an emergency entry, and only use it for forwarding when disconnected from the controller. + +\paragraph{Port Modification Message} +The controller uses the \verb|OFPT_PORT_MOD| message to modify the behavior of the physical port: + +\input{struct/ofp_port_mod} +The \verb|mask| field is used to select bits in the \verb|config| field to change. The \verb|advertise| field has no mask; all port features change together. + +\subsubsection{\qosupd{Queue Configuration Messages}} +\qosupd{Queue configuration takes place outside the OpenFlow protocol, either + through a command line tool or through an external dedicated configuration +protocol. +\\\\ +The controller can query the switch for configured queues on a port +using the following structure: +\input{struct/ofp_queue_get_config_request} +The switch replies back with an} \verb|ofp_queue_get_config_reply| \qosupd{command, containing +a list of configured queues. + +\input{struct/ofp_queue_get_config_reply} +} + +\subsubsection{Read State Messages} +While the system is running, the datapath may be queried about its current state using the \verb|OFPT_STATS_REQUEST| message: + +\input{struct/ofp_stats_request} +The switch responds with one or more \verb|OFPT_STATS_REPLY| messages: + +\input{struct/ofp_stats_reply} +The only value defined for \verb|flags| in a reply is whether more replies will follow this one - this has the value \verb|0x0001|. To ease implementation, the switch is allowed to send replies with no additional entries. However, it must always send another reply following a message with the �more� flag set. The transaction ids (xid) of replies must always match the request that prompted them. +\\\\ +In both the request and response, the \verb|type| field specifies the kind of information being passed and determines how the \verb|body| field is interpreted: + +\input{enum/ofp_stats_types} + +\paragraph{Description Statistics} +Information about the switch manufacturer, hardware revision, software revision, serial number, and a description field is available from the \verb|OFPST_DESC| stats request type: + +\input{struct/ofp_desc_stats} +Each entry is ASCII formatted and padded on the right with null bytes (\textbackslash0). \verb|DESC_STR_LEN| is \input{define/DESC_STR_LEN}and \verb|SERIAL_NUM_LEN| is \input{define/SERIAL_NUM_LEN}. Note: \footnote{Added to address concerns raised in \url{https://mailman.stanford.edu/pipermail/openflow-spec/2009-September/000504.html}} the \verb|dp_desc| field is a free-form string to describe the datapath for debugging purposes, e.g., ``switch3 in room 3120''. As such, it is not guaranteed to be unique and should not be used as the primary identifier for the datapath---use the \verb|datapath_id| field from the switch features instead (\S~\ref{cts:handshake}). + +\paragraph{Individual Flow Statistics} +Information about individual flows is requested with the \verb|OFPST_FLOW| stats request type: + +\input{struct/ofp_flow_stats_request} +The \verb|match| field contains a description of the flows that should be matched and may contain wildcards. This field's matching behavior is described in Section \ref{flow_table:sec_chan:flow_add}. +\\\\ +The \verb|table_id| field indicates the index of a single table to read, or \verb|0xff| for all tables. +\\\\ +The \verb|out_port| field optionally filters by output port. If \verb|out_port| contains a value other than \verb|OFPP_NONE|, it introduces a constraint when matching. This constraint is that the rule must contain an output action directed at that port. Other constraints such as \verb|ofp_match| structs are still used; this is purely an \emph{additional} constraint. Note that to disable output port filtering, \verb|out_port| must be set to \verb|OFPP_NONE|, since 0 is a valid port id. +\\\\ +The \verb|body| of the reply consists of an array of the following: + +\input{struct/ofp_flow_stats} +The fields consist of those provided in the \verb|flow_mod| that created these, plus the table into which the entry was inserted, the packet count, and the byte count. +\\\\ +\label{flow_duration_info}The \verb|duration_sec| and \verb|duration_nsec| fields indicate the elapsed time the flow has been installed in the switch. The total duration in nanoseconds can be computed as $\verb|duration_sec|*10^{9}$ + \verb|duration_nsec|. Implementations are required to provide millisecond precision; higher precision is encouraged where available. + +\paragraph{Aggregate Flow Statistics} +Aggregate information about multiple flows is requested with the \verb|OFPST_AGGREGATE| stats request type: + +\input{struct/ofp_aggregate_stats_request} +The \verb|match| field contains a description of the flows that should be matched and may contain wildcards. This field's matching behavior is described in Section \ref{flow_table:sec_chan:flow_add}. +\\\\ +The \verb|table_id| field indicates the index of a single table to read, or \verb|0xff| for all tables. +\\\\ +The \verb|out_port| field optionally filters by output port. If \verb|out_port| contains a value other than \verb|OFPP_NONE|, it introduces a constraint when matching. This constraint is that the rule must contain an output action directed at that port. Other constraints such as \verb|ofp_match| structs are still used; this is purely an \emph{additional} constraint. Note that to disable output port filtering, \verb|out_port| must be set to \verb|OFPP_NONE|, since 0 is a valid port id. +\\\\ +The \verb|body| of the reply consists of the following: + +\input{struct/ofp_aggregate_stats_reply} + +\paragraph{Table Statistics} +Information about tables is requested with the \verb|OFPST_TABLE| stats request type. The request does not contain any data in the body. +\\\\ +The body of the reply consists of an array of the following: + +\input{struct/ofp_table_stats} +The \verb|body| contains a \verb|wildcards| field, which indicates the fields for which that particular table supports wildcarding. For example, a direct look-up hash table would have that field set to zero, while a sequentially searched table would have it set to \verb|OFPFW_ALL|. The entries are returned in the order that packets traverse the tables. +\\\\ +\verb|OFP_MAX_TABLE_NAME_LEN| is \input{define/OFP_MAX_TABLE_NAME_LEN}. + +\paragraph{Port Statistics} +Information about physical ports is requested with the \verb|OFPST_PORT| stats request type: + +\input{struct/ofp_port_stats_request} +The \verb|port_no| field optionally filters the stats request to the given port. To request all port statistics, \verb|port_no| must be set to \verb|OFPP_NONE|. +\\\\ +The \verb|body| of the reply consists of an array of the following: + +\input{struct/ofp_port_stats} +The switch should return a value of -1 for unavailable counters. + +\paragraph{\qosupd{Queue Statistics}} +\qosupd{The} \verb|OFPST_QUEUE| \qosupd{stats request message provides + queue statistics for one or more ports. + The request body consists of a} \verb|port_no| \qosupd{field +identifying the port and a} \verb|queue_id|. \verb|OFPP_ALL| +\qosupd{refers to all ports, while} \verb|OFPQ_ALL| \qosupd{refers to all queues configured +at a port. + +\input{struct/ofp_queue_stats_request} +The body of the reply consists of an array of +the following structure: + +\input{struct/ofp_queue_stats}} + +\paragraph{Vendor Statistics} +Vendor-specific stats messages are requested with the \verb|OFPST_VENDOR| stats type. The first four bytes of the message are the vendor identifier. The rest of the body is vendor-defined. +\\\\ +The \verb|vendor| field is a 32-bit value that uniquely identifies the vendor. If the most significant byte is zero, the next three bytes are the vendor's IEEE OUI. If vendor does not have (or wish to use) their OUI, they should contact the OpenFlow consortium to obtain one. + +\subsubsection{Send Packet Message} +When the controller wishes to send a packet out through the datapath, it uses the \verb|OFPT_PACKET_OUT| message: + +\input{struct/ofp_packet_out} +The \verb|buffer_id| is the same given in the \verb|ofp_packet_in| message. If the \verb|buffer_id| is -1, then the packet data is included in the data array. If \verb|OFPP_TABLE| is specified as the output port of an action, the \verb|in_port| in the \verb|packet_out| message is used in the flow table lookup. + +\subsubsection{Barrier Message} +When the controller wants to ensure message dependencies have been met or wants to receive notifications for completed operations, it may use an \verb|OFPT_BARRIER_REQUEST| message. This message has no body. Upon receipt, the switch must finish processing all previously-received messages before executing any messages beyond the Barrier Request. When such processing is complete, the switch must send an \verb|OFPT_BARRIER_REPLY| message with the \verb|xid| of the original request. + +\subsection{Asynchronous Messages} +\subsubsection{Packet-In Message} +When packets are received by the datapath and sent to the controller, they use the \verb|OFPT_PACKET_IN| message: + +\input{struct/ofp_packet_in} +The \verb|buffer_id| is an opaque value used by the datapath to identify a buffered packet. When a packet is buffered, some number of bytes from the message will be included in the data portion of the message. If the packet is sent because of a ``send to controller'' action, then \verb|max_len| bytes from the \verb|action_output| of the flow setup request are sent. If the packet is sent because of a flow table miss, then at least \verb|miss_send_len| bytes from the \verb|OFPT_SET_CONFIG| message are sent. The default \verb|miss_send_len| is \input{define/OFP_DEFAULT_MISS_SEND_LEN}bytes. If the packet is not buffered, the entire packet is included in the data portion, and the \verb|buffer_id| is -1. +\\\\ +Switches that implement buffering are expected to expose, through documentation, both the amount of available buffering, and the length of time before buffers may be reused. A switch must gracefully handle the case where a buffered \verb|packet_in| message yields no response from the controller. A switch should prevent a buffer from being reused until it has been handled by the controller, or some amount of time (indicated in documentation) has passed. +\\\\ +The reason field can be any of these values: + +\input{enum/ofp_packet_in_reason} + +\subsubsection{Flow Removed Message} +If the controller has requested to be notified when flows time out, the datapath does this with the \verb|OFPT_FLOW_REMOVED| message: + +\input{struct/ofp_flow_removed} +The \verb|match|, \verb|cookie|, and \verb|priority| fields are the same as those used in the flow setup request. +\\\\ +The \verb|reason| field is one of the following: + +\input{enum/ofp_flow_removed_reason} +The \verb|duration_sec| and \verb|duration_nsec| fields are described in Section \ref{flow_duration_info}. +\\\\ +The \verb|idle_timeout| field is directly copied from the flow mod that created this entry. +\\\\ +With the above three fields, one can find both the amount of time the flow was active, as well as the amount of time the flow received traffic. +\\\\ +The \verb|packet_count| and \verb|byte_count| indicate the number of packets and bytes that were associated with this flow, respectively. + +\subsubsection{Port Status Message} +As physical ports are added, modified, and removed from the datapath, the controller needs to be informed with the \verb|OFPT_PORT_STATUS| message: + +\input{struct/ofp_port_status} +The \verb|status| can be one of the following values: + +\input{enum/ofp_port_reason} + +\subsubsection{Error Message} +There are times that the switch needs to notify the controller of a problem. This is done with the \verb|OFPT_ERROR_MSG| message: + +\input{struct/ofp_error_msg} +The \verb|type| value indicates the high-level type of error. The \verb|code| value is interpreted based on the type. The \verb|data| is variable length and interpreted based on the \verb|type| and \verb|code|; in most cases this is the message that caused the problem. +\\\\ +Error codes ending in \verb|_EPERM| correspond to a permissions error generated by an entity between a controller and switch, such as an OpenFlow hypervisor. +\\\\ +Currently defined error types are: + +\input{enum/ofp_error_type} +For the \verb|OFPET_HELLO_FAILED| error \verb|type|, the following \verb|code|s are currently defined: + +\input{enum/ofp_hello_failed_code} +The \verb|data| field contains an ASCII text string that adds detail on why the error occurred. +\\\\ +For the \verb|OFPET_BAD_REQUEST| error \verb|type|, the following \verb|code|s are currently defined: + +\input{enum/ofp_bad_request_code} +The \verb|data| field contains at least 64 bytes of the failed request. +\\\\ +For the \verb|OFPET_BAD_ACTION| error \verb|type|, the following \verb|code|s are currently defined: + +\input{enum/ofp_bad_action_code} +The \verb|data| field contains at least 64 bytes of the failed request. +\\\\ +For the \verb|OFPET_FLOW_MOD_FAILED| error \verb|type|, the following \verb|code|s are currently defined: + +\input{enum/ofp_flow_mod_failed_code} +The \verb|data| field contains at least 64 bytes of the failed request. +\\\\ +For the \verb|OFPET_PORT_MOD_FAILED| error \verb|type|, the following \verb|code|s are currently defined: + +\input{enum/ofp_port_mod_failed_code} +The \verb|data| field contains at least 64 bytes of the failed request. +\\\\ +For the \verb|OFPET_QUEUE_OP_FAILED| error \verb|type|, the following \verb|code|s are currently defined: + +\input{enum/ofp_queue_op_failed_code} +The \verb|data| field contains at least 64 bytes of the failed request. +\\\\ +If the error message is in response to a specific message from the controller, e.g., \verb|OFPET_BAD_REQUEST|, \verb|OFPET_BAD_ACTION|, or \verb|OFPET_FLOW_MOD_FAILED|, then the \verb|xid| field of the header should match that of the offending message. + +\subsection{Symmetric Messages} +\subsubsection{Hello} +The \verb|OFPT_HELLO| message has no body; that is, it consists only of an OpenFlow header. Implementations must be prepared to receive a hello message that includes a body, ignoring its contents, to allow for later extensions. + +\subsubsection{Echo Request} +An Echo Request message consists of an OpenFlow header plus an arbitrary-length data field. The data field might be a message timestamp to check latency, various lengths to measure bandwidth, or zero-size to verify liveness between the switch and controller. + +\subsubsection{Echo Reply} +An Echo Reply message consists of an OpenFlow header plus the unmodified data field of an echo request message. +\\\\ +In an OpenFlow protocol implementation divided into multiple layers, the echo request/reply logic should be implemented in the "deepest" practical layer. For example, in the OpenFlow reference implementation that includes a userspace process that relays to a kernel module, echo request/reply is implemented in the kernel module. Receiving a correctly formatted echo reply then shows a greater likelihood of correct end-to-end functionality than if the echo request/reply were implemented in the userspace process, as well as providing more accurate end-to-end latency timing. + +\subsubsection{Vendor} +The Vendor message is defined as follows: + +\input{struct/ofp_vendor_header} +The \verb|vendor| field is a 32-bit value that uniquely identifies the vendor. If the most significant byte is zero, the next three bytes are the vendor's IEEE OUI. If vendor does not have (or wish to use) their OUI, they should contact the OpenFlow consortium to obtain one. The rest of the body is uninterpreted. +\\\\ +If a switch does not understand a vendor extension, it must send an \verb|OFPT_ERROR| message with a \verb|OFPBRC_BAD_VENDOR| error code and \verb|OFPET_BAD_REQUEST| error type. + diff --git a/openflow/doc/of-spec/credits.tex b/openflow/doc/of-spec/credits.tex new file mode 100644 index 00000000..eb917c70 --- /dev/null +++ b/openflow/doc/of-spec/credits.tex @@ -0,0 +1,22 @@ +\section{Appendix B: Credits} + +Current Maintainer: Brandon Heller (brandonh@stanford.edu). +\\\\ +Spec contributions, in alphabetical order: +\\\\ +Ben Pfaff, +Brandon Heller, +Dan Talayco, +David Erickson, +Glen Gibb, +Guido Appenzeller, +Jean Tourrilhes, +Justin Pettit, +KK Yap, +Martin Casado, +Masayoshi Kobayashi, +Nick McKeown, +Peter Balland, +Reid Price, +Rob Sherwood, +Yiannis Yiakoumis. \ No newline at end of file diff --git a/openflow/doc/of-spec/figure_flow_table_secchan.png b/openflow/doc/of-spec/figure_flow_table_secchan.png new file mode 100755 index 0000000000000000000000000000000000000000..a21dde001128e353fb0a172fd4b6551931467604 GIT binary patch literal 67886 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 3~M{>^b~jIm2Vp1dl%!TTqD_` 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 + + + + ActiveLayerIndex + 0 + ApplicationVersion + + com.omnigroup.OmniGrafflePro + 138.12.0.121252 + + AutoAdjust + + BackgroundGraphic + + Bounds + {{0, 0}, {1188, 733}} + Class + SolidGraphic + ID + 2 + Style + + shadow + + Draws + NO + + stroke + + Draws + NO + + + + CanvasOrigin + {0, 0} + ColumnAlign + 1 + ColumnSpacing + 36 + CreationDate + 2009-11-19 17:13:27 -0800 + Creator + brandonh + DisplayScale + 1 0/72 in = 1.0000 in + GraphDocumentVersion + 6 + GraphicsList + + + Class + LineGraphic + Head + + ID + 88 + Position + 0.57036429643630981 + + ID + 102 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {584.932, 656.613} + {584.977, 688.774} + + Style + + stroke + + HeadArrow + 0 + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 42 + Info + 2 + + + + Class + LineGraphic + Head + + ID + 88 + Position + 0.84439820051193237 + + ID + 101 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {458.932, 674.613} + {458.658, 688.774} + + Style + + stroke + + HeadArrow + 0 + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 41 + Info + 1 + + + + Class + LineGraphic + Head + + ID + 67 + Position + 0.93292379379272461 + + ID + 100 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {242.932, 336.714} + {255.646, 688.774} + + Style + + stroke + + HeadArrow + FilledArrow + HopLines + + HopType + 1 + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 93 + Info + 3 + + + + Class + LineGraphic + Head + + ID + 93 + Info + 4 + + ID + 94 + Points + + {125.932, 336.714} + {143.932, 336.714} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 92 + + + + Bounds + {{143.932, 300.714}, {99, 72}} + Class + ShapedGraphic + ID + 93 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Rectangle + Style + + stroke + + Pattern + 1 + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 Set IP source, destination from within ARP packet} + + VFlip + YES + + + Bounds + {{17.9318, 282.714}, {108, 108}} + Class + ShapedGraphic + ID + 92 + Line + + ID + 19 + Position + 0.51827484369277954 + RotationType + 0 + + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Diamond + Style + + stroke + + Pattern + 1 + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 Eth type = 0x0806?} + VerticalPad + 0 + + + + Class + LineGraphic + Head + + ID + 53 + Info + 3 + + ID + 88 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {629.932, 494.613} + {386.932, 688.774} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 37 + Info + 3 + + + + Bounds + {{447.932, 175.932}, {72, 14}} + Class + ShapedGraphic + FitText + Vertical + Flow + Resize + ID + 83 + Shape + Rectangle + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Pad + 0 + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 no} + VerticalPad + 0 + + + + Bounds + {{509.932, 85.932}, {72, 14}} + Class + ShapedGraphic + FitText + Vertical + Flow + Resize + ID + 82 + Shape + Rectangle + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Pad + 0 + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 yes} + VerticalPad + 0 + + + + Class + LineGraphic + ID + 81 + Points + + {515.932, 108.932} + {566.932, 108.932} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 73 + Info + 3 + + + + Class + LineGraphic + ID + 80 + Points + + {461.932, 162.932} + {461.932, 216.932} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 73 + + + + Bounds + {{407.932, 54.932}, {108, 108}} + Class + ShapedGraphic + ID + 73 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Diamond + Style + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 decision} + VerticalPad + 0 + + + + Class + LineGraphic + Head + + ID + 19 + Position + 0.11005332320928574 + + ID + 71 + OrthogonalBarAutomatic + + OrthogonalBarPosition + 0.0 + Points + + {197.932, 206.932} + {71.9318, 248.668} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 1 + Info + 2 + + + + Class + LineGraphic + Head + + ID + 53 + + ID + 67 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {71.9318, 548.613} + {278.932, 688.774} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 18 + Info + 1 + + + + Class + LineGraphic + Head + + ID + 53 + + ID + 63 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {332.932, 549.113} + {332.932, 661.774} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 47 + + + + Bounds + {{278.932, 661.774}, {108, 54}} + Class + ShapedGraphic + ID + 53 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Rectangle + Style + + stroke + + Width + 3 + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\b\fs24 \cf0 Packet Lookup +\b0 Use assigned header fields} + + VFlip + YES + + + Class + LineGraphic + Head + + ID + 39 + + ID + 50 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {386.932, 494.613} + {404.932, 494.613} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 47 + + + + Class + LineGraphic + Head + + ID + 47 + + ID + 49 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {242.932, 494.613} + {278.932, 494.613} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 35 + + + + Class + LineGraphic + Head + + ID + 35 + + ID + 48 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {125.932, 494.613} + {143.932, 494.613} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 18 + + + + Class + LineGraphic + Head + + ID + 41 + + ID + 45 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {458.932, 548.613} + {458.932, 566.613} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 39 + + + + Class + LineGraphic + Head + + ID + 42 + + ID + 44 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {512.932, 620.613} + {539.932, 620.613} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 41 + + + + Class + LineGraphic + Head + + ID + 37 + + ID + 43 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {512.932, 494.613} + {539.932, 494.613} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 39 + + + + Bounds + {{539.932, 584.613}, {90, 72}} + Class + ShapedGraphic + ID + 42 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Rectangle + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 Use ICMP type and code for L4 fields} + + VFlip + YES + + + Bounds + {{404.932, 566.613}, {108, 108}} + Class + ShapedGraphic + ID + 41 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Diamond + Style + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 IP Proto = \ +1?} + VerticalPad + 0 + + + + Bounds + {{404.932, 440.613}, {108, 108}} + Class + ShapedGraphic + ID + 39 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Diamond + Style + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 IP Proto = \ +6 or 7?} + VerticalPad + 0 + + + + Bounds + {{539.932, 458.613}, {90, 72}} + Class + ShapedGraphic + ID + 37 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Rectangle + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 Use UDP/TCP source and destination for L4 fields} + + VFlip + YES + + + Bounds + {{143.932, 458.613}, {99, 72}} + Class + ShapedGraphic + ID + 35 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Rectangle + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 Set IP source, destination, protocol, and ToS fields} + + VFlip + YES + + + Bounds + {{278.932, 440.613}, {108, 108}} + Class + ShapedGraphic + ID + 47 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Diamond + Style + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 Not IP Fragment?} + VerticalPad + 0 + + + + Class + LineGraphic + Head + + ID + 18 + + ID + 19 + Points + + {71.9318, 224.932} + {71.9318, 440.613} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 6 + + + + Bounds + {{17.9318, 440.613}, {108, 108}} + Class + ShapedGraphic + ID + 18 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Diamond + Style + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 Eth type = 0x0800?} + VerticalPad + 0 + + + + Class + LineGraphic + Head + + ID + 1 + + ID + 17 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {125.932, 170.932} + {143.932, 170.932} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 6 + + + + Class + LineGraphic + Head + + ID + 6 + + ID + 16 + Points + + {71.9318, 98.932} + {71.9318, 116.932} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 7 + + + + Bounds + {{8.93179, 8.93201}, {126, 90}} + Class + ShapedGraphic + ID + 7 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Rectangle + Style + + stroke + + Width + 3 + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\b\fs24 \cf0 Initialize Headers +\b0 \ +Set input port, Ethernet source, destination, and type;\ +set all others to zero} + + + + Bounds + {{17.9318, 116.932}, {108, 108}} + Class + ShapedGraphic + ID + 6 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Diamond + Style + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 Eth type = 0x8100?} + VerticalPad + 0 + + + + Bounds + {{143.932, 134.932}, {108, 72}} + Class + ShapedGraphic + ID + 1 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Rectangle + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 Set VLAN ID and PCP. Use encapsulated Eth type for next Eth type check} + + VFlip + YES + + + GridInfo + + ShowsGrid + YES + + GuidesLocked + NO + GuidesVisible + YES + HPages + 1 + ImageCounter + 1 + KeepToScale + + Layers + + + Lock + NO + Name + Layer 1 + Print + YES + View + YES + + + LayoutInfo + + Animate + NO + circoMinDist + 18 + circoSeparation + 0.0 + layoutEngine + dot + neatoSeparation + 0.0 + twopiSeparation + 0.0 + + LinksVisible + YES + MagnetsVisible + NO + MasterSheets + + ModificationDate + 2009-12-16 14:42:02 -0800 + Modifier + brandonh + NotesVisible + NO + Orientation + 2 + OriginVisible + NO + PageBreaks + YES + PrintInfo + + NSBottomMargin + + float + 41 + + NSLeftMargin + + float + 18 + + NSOrientation + + int + 1 + + NSPaperName + + string + eleven_by_seventeen + + NSPaperSize + + size + {1224, 792} + + NSRightMargin + + float + 18 + + NSTopMargin + + float + 18 + + + PrintOnePage + + QuickLookPreview + + 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 + +qSeZg3KM+lp1mCFsp41mJI+c9ZghTrVdC/PGpibp8N9ueoqKWc6QE6f6rBoVuOjNNNT + /vXueHv3cCbpuRl5DNZ3+AhGgfKn35VfBGYCz6muyPvRkuJJHnEBFXnhMfcxFs850/lh + 2YXM3YVqdLFrWHLv0iVjg4DDlI5YMwzsDxWsYZjqkvFqnfUUS7HMj32b5tc04tt4+BPP + 3REWfVtpNV3TtcxXunKsCuxQunIMg3ocurWYtg6ofcXrCsz3qf6mYgolMeExrBIIPvI1 + VumyTiBXmT7aJVyjCx7l8VQKY5e0H4HjsxxckjsaiUKLF30fKcldi7tKsigYCru0k0qt + Xg26sgJFY5KNdJT4KdmEH8Ogt8xPr37hVCrJa/kVF5aTYSjsUtefYKHtHWhL6apgUqYT + v5J/l2ezgB5+pIn0kudmQpDXhQjrMJum+DAMvEc+6RJ9+3/P6L6+CmVuZHN0cmVhbQpl + bmRvYmoKNiAwIG9iagozNzM1CmVuZG9iagozIDAgb2JqCjw8IC9UeXBlIC9QYWdlIC9Q + YXJlbnQgNCAwIFIgL1Jlc291cmNlcyA3IDAgUiAvQ29udGVudHMgNSAwIFIgL01lZGlh + Qm94IFswIDAgMTE4OCA3MzNdCj4+CmVuZG9iago3IDAgb2JqCjw8IC9Qcm9jU2V0IFsg + L1BERiAvVGV4dCAvSW1hZ2VCIC9JbWFnZUMgL0ltYWdlSSBdIC9Db2xvclNwYWNlIDw8 + IC9DczEgOCAwIFIKL0NzMiAzNyAwIFIgPj4gL0ZvbnQgPDwgL0YxLjAgMzggMCBSIC9G + Mi4wIDM5IDAgUiA+PiAvWE9iamVjdCA8PCAvSW0xMiAzMSAwIFIKL0ltNiAxOSAwIFIg + L0ltMyAxMyAwIFIgL0ltMSA5IDAgUiAvSW00IDE1IDAgUiAvSW0xMCAyNyAwIFIgL0lt + OSAyNSAwIFIgL0ltMTEKMjkgMCBSIC9JbTE0IDM1IDAgUiAvSW0yIDExIDAgUiAvSW01 + IDE3IDAgUiAvSW0xMyAzMyAwIFIgL0ltNyAyMSAwIFIgL0ltOAoyMyAwIFIgPj4gPj4K + ZW5kb2JqCjMxIDAgb2JqCjw8IC9MZW5ndGggMzIgMCBSIC9UeXBlIC9YT2JqZWN0IC9T + dWJ0eXBlIC9JbWFnZSAvV2lkdGggMjYwIC9IZWlnaHQgMjYwIC9Db2xvclNwYWNlCjQw + IDAgUiAvU01hc2sgNDEgMCBSIC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxh + dGVEZWNvZGUgPj4Kc3RyZWFtCngB7dAxAQAAAMKg9U/taQmIQGHAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDgAwMYXQABCmVuZHN0cmVhbQplbmRvYmoKMzIgMCBvYmoKOTA4CmVuZG9iagoxOSAw + IG9iago8PCAvTGVuZ3RoIDIwIDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1h + Z2UgL1dpZHRoIDI0MiAvSGVpZ2h0IDE4OCAvQ29sb3JTcGFjZQo0MyAwIFIgL1NNYXNr + IDQ0IDAgUiAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+ + CnN0cmVhbQp4Ae3QAQ0AAADCoPdP7ewBESgMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwY+MBVGAAEKZW5kc3RyZWFtCmVuZG9iagoyMCAwIG9iago2MTgKZW5kb2Jq + CjEzIDAgb2JqCjw8IC9MZW5ndGggMTQgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBl + IC9JbWFnZSAvV2lkdGggMzAwIC9IZWlnaHQgMjI4IC9Db2xvclNwYWNlCjQ2IDAgUiAv + U01hc2sgNDcgMCBSIC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNv + ZGUgPj4Kc3RyZWFtCngB7dAxAQAAAMKg9U9tCj+IQGHAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAwGtgIb0AAQplbmRzdHJlYW0KZW5kb2JqCjE0IDAgb2JqCjkxOAplbmRvYmoK + OSAwIG9iago8PCAvTGVuZ3RoIDEwIDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAv + SW1hZ2UgL1dpZHRoIDI2MCAvSGVpZ2h0IDE4OCAvQ29sb3JTcGFjZQo0OSAwIFIgL1NN + YXNrIDUwIDAgUiAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2Rl + ID4+CnN0cmVhbQp4Ae3QMQEAAADCoPVPbQo/iEBhwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGPgODDzuAAEKZW5kc3RyZWFtCmVuZG9iagoxMCAwIG9iago2NjMKZW5kb2JqCjE1 + IDAgb2JqCjw8IC9MZW5ndGggMTYgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9J + bWFnZSAvV2lkdGggMjYwIC9IZWlnaHQgMjYwIC9Db2xvclNwYWNlCjQwIDAgUiAvU01h + c2sgNTIgMCBSIC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUg + Pj4Kc3RyZWFtCngB7dAxAQAAAMKg9U/taQmIQGHAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDgAwMYXQAB + CmVuZHN0cmVhbQplbmRvYmoKMTYgMCBvYmoKOTA4CmVuZG9iagoyNyAwIG9iago8PCAv + TGVuZ3RoIDI4IDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRo + IDIyNCAvSGVpZ2h0IDE4OCAvQ29sb3JTcGFjZQo1NCAwIFIgL1NNYXNrIDU1IDAgUiAv + Qml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4 + Ae3QAQ0AAADCoPdPbQ43iEBhwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDDwNDDtjwABCmVuZHN0cmVhbQplbmRvYmoKMjggMCBvYmoKNTc0CmVuZG9iagoy + NSAwIG9iago8PCAvTGVuZ3RoIDI2IDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAv + SW1hZ2UgL1dpZHRoIDI2MCAvSGVpZ2h0IDI2MCAvQ29sb3JTcGFjZQo0MCAwIFIgL1NN + YXNrIDU3IDAgUiAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2Rl + ID4+CnN0cmVhbQp4Ae3QMQEAAADCoPVP7WkJiEBhwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg4AMDGF0A + AQplbmRzdHJlYW0KZW5kb2JqCjI2IDAgb2JqCjkwOAplbmRvYmoKMjkgMCBvYmoKPDwg + L0xlbmd0aCAzMCAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUgL0ltYWdlIC9XaWR0 + aCAyNjQgL0hlaWdodCAxNTYgL0NvbG9yU3BhY2UKNTkgMCBSIC9TTWFzayA2MCAwIFIg + L0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0K + eAHt0AENAAAAwqD3T20PBxEoDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMDA/8AA4q8A + AQplbmRzdHJlYW0KZW5kb2JqCjMwIDAgb2JqCjU2MgplbmRvYmoKMzUgMCBvYmoKPDwg + L0xlbmd0aCAzNiAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUgL0ltYWdlIC9XaWR0 + aCAyNDIgL0hlaWdodCAxODggL0NvbG9yU3BhY2UKNjIgMCBSIC9TTWFzayA2MyAwIFIg + L0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0K + eAHt0AENAAAAwqD3T+3sAREoDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + PjAVRgABCmVuZHN0cmVhbQplbmRvYmoKMzYgMCBvYmoKNjE4CmVuZG9iagoxMSAwIG9i + ago8PCAvTGVuZ3RoIDEyIDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2Ug + L1dpZHRoIDI2MCAvSGVpZ2h0IDI2MCAvQ29sb3JTcGFjZQo0MCAwIFIgL1NNYXNrIDY1 + IDAgUiAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0 + cmVhbQp4Ae3QMQEAAADCoPVP7WkJiEBhwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg4AMDGF0AAQplbmRz + dHJlYW0KZW5kb2JqCjEyIDAgb2JqCjkwOAplbmRvYmoKMTcgMCBvYmoKPDwgL0xlbmd0 + aCAxOCAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUgL0ltYWdlIC9XaWR0aCAyNjAg + L0hlaWdodCAyNjAgL0NvbG9yU3BhY2UKNDAgMCBSIC9TTWFzayA2NyAwIFIgL0JpdHNQ + ZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAHt0DEB + AAAAwqD1T+1pCYhAYcCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYOADAxhdAAEKZW5kc3RyZWFtCmVuZG9i + agoxOCAwIG9iago5MDgKZW5kb2JqCjMzIDAgb2JqCjw8IC9MZW5ndGggMzQgMCBSIC9U + eXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMjYwIC9IZWlnaHQgMjYw + IC9Db2xvclNwYWNlCjY5IDAgUiAvU01hc2sgNzAgMCBSIC9CaXRzUGVyQ29tcG9uZW50 + IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7dAxAQAAAMKg9U/taQmI + QGHAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDgAwMYXQABCmVuZHN0cmVhbQplbmRvYmoKMzQgMCBvYmoK + OTA4CmVuZG9iagoyMSAwIG9iago8PCAvTGVuZ3RoIDIyIDAgUiAvVHlwZSAvWE9iamVj + dCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRoIDIyNCAvSGVpZ2h0IDE4OCAvQ29sb3JTcGFj + ZQo1NCAwIFIgL1NNYXNrIDcyIDAgUiAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIg + L0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae3QAQ0AAADCoPdPbQ43iEBhwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDDwNDDtjwABCmVuZHN0cmVhbQplbmRv + YmoKMjIgMCBvYmoKNTc0CmVuZG9iagoyMyAwIG9iago8PCAvTGVuZ3RoIDI0IDAgUiAv + VHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRoIDI2MCAvSGVpZ2h0IDI2 + MCAvQ29sb3JTcGFjZQo0MCAwIFIgL1NNYXNrIDc0IDAgUiAvQml0c1BlckNvbXBvbmVu + dCA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae3QMQEAAADCoPVP7WkJ + iEBhwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBg4AMDGF0AAQplbmRzdHJlYW0KZW5kb2JqCjI0IDAgb2Jq + CjkwOAplbmRvYmoKNDQgMCBvYmoKPDwgL0xlbmd0aCA0NSAwIFIgL1R5cGUgL1hPYmpl + Y3QgL1N1YnR5cGUgL0ltYWdlIC9XaWR0aCAyNDIgL0hlaWdodCAxODggL0NvbG9yU3Bh + Y2UKL0RldmljZUdyYXkgL0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURl + Y29kZSA+PgpzdHJlYW0KeAHtne9vEtkax21LocAAQ0sHyo8LDlAYkLIjKG2pCw0ExVKt + VVxcW1KdapZKRY1EsrUupiqR+KN1bbRGa9dYjbqNNY0as5r7r93nUHP3SnHd+46zPd8X + RpKanM98n/M5U3xxtmwhIU+APAHyBMgTwPcJNGCd/+u5A2njn2nCLH+uvBFA/gb4Oi1Q + ikTNGEckAgQE/y3oCu86rFgiaVmPFKN8XrJEIoa6APsbzJ95m5vFACuVyeRyOUVRCqwC + C4Zly2TSlhZE/dfMCLgJZhlwAZZSKJUqmlZjF5pWKZUK4JYB9DrzV0a7Agz9Il6FUqVW + t7ZpNO3tDKPFKAzT3q7RtLWq1SqlAjFDzzDatZFRw6hgxEsDLaPVdej1BqPRhFGMRoNe + 36HTMkBNV5ihZoRcQ9oVYNjAcgp4ARdYTWaLZStrxSrsVovFbAJugAZmSo62c23kBrSH + JVIoWN3G6PRAy1rtnQ4nx7lcbkzicnGc09Fpt7JArdcxbWqoWSpB/tpYMlQMwC1yhUqt + 0epNFtbWybm2ebxenue3YxNYrNfr2ebiOm2sxaTXatQqBbTcLKox11AxSEtWATaYWbvT + 7fHyvh07Az29kCAWQSvtCezc4eO9HrfTzpoNFWQZ6KtGyQ1QcYuMUqo1OoPZ6nB38f5A + T3BXKNwfiUSimASW2h8O7Qr2BPx8l9thNRt0GrWSkrVAydVjvV6xHIC1BouN8/D+7mCo + PxrbEx9IDO7DJoOJgfieWLQ/FOz28x7OZkEtK+W1SkbEMNM0AJttnNcX6AtHdu8d3D98 + MHk4hVEOJw8O7x/cuzsS7gv4vJwNDTatgJI3jDUMtbhFrmxl9GYr1+XvDUXjiQOHUkdH + 02PHBWEckwjC8bH06NHUoQOJeDTU6+/irGY904pK3jDWDY1wMkHFOhPr8Ph6w7GBoeSR + 0THhZOZUdvJ0DpOcnsyeypwUxkaPJIcGYuFen8fBmnRQMpxQ1RsZDTXsYkZvsbv5QCiW + GE6NHDuRyebOnc9fKGCTC/nz53LZzIljI6nhRCwU4N12i55BOxnG+svXrgqxqk1rYp1d + /r4oAKeFzOTZfGFq+lLxMjYpXpqeKuTPTmaENCBH+/xdTtakbVPVJBZLKVrTYba5+e5w + fCiVHp/I5QvTxZmrpetlbHK9dHWmOF3I5ybG06mheLibd9vMHRqakoo3dCwSSxVoqDs9 + /mBkMDkiTJzJTxWvlMo3b8/ewSazt2+WS1eKU/kzE8JIcjAS9Hs60VgrpKCuqqkWSWTK + Vq2RdXoD3+8+cOTYT7n81OVr5Vtzd+fv31/AJPfvz9+du1W+dnkqn/vp2JEDu78PeJ2s + UduqlElqEMuVsI2tLr6nf++h0RNZAC7dmL1778HDxcdLmOTx4sMH9+7O3igBcvbE6KG9 + /T28ywobWSmvQQyq1nT8y77NB0OdGsucLfxy7cbc/MKjpSdPl59hkuWnT5YeLczP3bj2 + S+FsZiwFY+3bZv9XhwZkvaFjOJxUGrSNd+yK7f9RyOYvzpRn5x8s/rb8/MXLV5jk5Yvn + y78tPpifLc9czGeFH/fHdu1AG1mDZF29j4GYBmKHNxDaMzx6Mlcolm7dXVh88uzlq5XX + q5jk9cqrl8+eLC7cvVUqFnInR4f3hAJeBxDTNYkpul2/FcQVjh9MZ879PFOeu/cIgFdW + 36xhkzerK4D86N5ceebnc5n0wXgY1LVV305TtTqm1O0Glvuup38gOTZx/uLVm78+WFp+ + sbK69vbde0zy7u3a6sqL5aUHv968evH8xFhyoL/nO441tKu/QswYWY7vjSQOH8/mL5Vu + zT988vz312tv33/AJu/frr3+/fmTh/O3Spfy2eOHE5FenmONzNeJ4XAC4h+EyQvF67fv + LT59sfIGgP/4iEn++PD+7ZuVF08X792+XrwwKfyAiF3WbxIPpoTThcvlufuPl1++XnsH + wJ8wycc/Prxbe/1y+fH9ufLlwmkBjqevEcMviy2UmjFWOq5B/G8s8umvib/43qehqRle + q+GVy709GN2XGs9Bx3cWlp69Wl17/+HjJyx4YZGfPn54v7b66tnSwh3oODee2hcNbnfD + Sxe8WDc3EWLSMZlqHPYy2cfEXP/zLQg5nch5jIO2yBsIeecib5nkNwnyuxMWtiZvmeQt + k7xlkm99yPdc9a9r4mriauJq4mriauLq+nsC5HQipxM5ncjpRE6n+nNz9YqIq4mriauJ + q4mrq81Yf5+Jq4mriauJq4mr68/N1SsiriauJq4mriaurjZj/X0mriauJq4mriaurj83 + V6+IuJq4mriauJq4utqM9feZuJq4mriauJq4uv7cXL0i4mriauJq4mri6moz1t9n4mri + auJq4mri6vpzc/WKiKuJq4mriauJq6vNWH+fiauJq4mriauJq+vPzdUrIq4mriauJq4m + rq42Y/19Jq4mriauJq4mrq4/N1eviLiauJq4mrj6n+3qTXej1ZZvEP/zbi37gnhT3Uy3 + 2W4f3HQ3TG66W0Q3302xm+02YNGmu/FZJNl0t3pvvpvbxXDFJIOu9fbDRebJEWHiTH6q + eKVUvnl79g42mb19s1y6UpzKn5kQRpJwjbkfXerNwCWi4g33mDeJpRSt6TDb3Hx3OD6U + So9P5PKF6eLM1dL1Mja5Xro6U5wu5HMT4+nUUDzczbtt5g4NTUnFTdX3mDehq9vbtCbW + 2eXviyaGU2khM3k2X5iavlS8jE2Kl6anCvmzkxkhnRpORPv8XU7WpG1DF7fXJFaisba7 + +UAoBsgjx05ksrlz5/MXCtjkQv78uVw2c+LYCADHQgHebUdDraxBDBcgS6QKWqMzsQ6P + rzccGxhKHhkdE05mTmUnT+cwyenJ7KnMSWFs9EhyaCAW7vV5HKxJp6EVUklz4xeXAW/Z + 0tAoEsOJ3MrozVauy98bisYTBw6ljo6mx44LwjgmEYTjY+nRo6lDBxLxaKjX38VZzXqm + FSoGcW0gho0sg5K1BrON8/oCfeHI7r2D+4cPJg+nMMrh5MHh/YN7d0fCfQGfl7OZDVqo + WIa2cQ1iVLIakC02zsP7u4Oh/mhsT3wgMbgPmwwmBuJ7YtH+ULDbz3s4mwWA0S4WbyRG + Yw0lU4CsM5itDncX7w/0BHeFwv2RSCSKSWCp/eHQrmBPwM93uR1Ws0EHwBRUvGGo0UZu + ahbDXKtQy2bW7nR7vLxvx85ATy8kiEXQSnsCO3f4eK/H7bSzaKTVKpjpWhUDMZQsaZFX + kPUmC2vr5FzbPF4vz/PbsQks1uv1bHNxnTbWYtJXgOUtEqi4ehvDl/VQMiBL5Qqluo3R + 6U1mC2u1dzqcHOdyuTGJy8VxTken3cpazCa9jmlTKxVyOJlEG7yF/ncCSoa5hpYpJd2q + YbR6gxGoLVtZK1Zht1qA1mjQaxlNK62koGE00zUq/owMgy2DmunWNoDWdeiB22jCKEZg + 1XfoALcNeBVyGYz014C3NFRaBn1VmFVqNVBr2tsZRotRGKa9XQO0arWqwgvSqgBXHcaf + /8utgixqhpqBWU4plEoVTauxC02rlEoFJYd+UcGwhxsbagPDXEPLyF9oO7dIZYAtpyhK + gVVgwbBsmUwKuNAv4v06MNLXOjNAAzVgVyLFKJ+XLEG0zaJv8laUjZgbm5qaRAgb2wBs + E6r3L/v9vJtR0RVq9PMQ+JdYZX3VlT8B5L9Qf+cv8PMY5+8Qkp8hT4A8AfIEyBOo1yfw + HxfQr7EKZW5kc3RyZWFtCmVuZG9iago0NSAwIG9iagoyNzk1CmVuZG9iago2NyAwIG9i + ago8PCAvTGVuZ3RoIDY4IDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2Ug + L1dpZHRoIDI2MCAvSGVpZ2h0IDI2MCAvQ29sb3JTcGFjZQovRGV2aWNlR3JheSAvQml0 + c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae3d + /1NSWRQA8L4o8k1ERVSSlaJscSC0MFOyNBq/t1oOI30znDKjRi0dWkfLKdQpsfJL5bjm + aE7soJlp6qhtu7P/2p77sEwXFBXeu/fC+SUNSvh47rnvPeCcPXvCERYIC4QFwgJhgbBA + WCAsgJHAXhT7IJgvMHpgLD2U1WcPAPv3IwYI+CuWfjgWP8bz69+/PyIiIhIC/vBIhJAC + WgAAAM+ex4uC4PEQBMMQIqmAkgAB8KL4fL5AIBQKBPBFFDhEwLIIiVRgCBgBgVAkEkdD + iEUioYBRCA0EIIAk4PH5QpFYIomRxkJIYyQSsUjI5/NQKlCfCR6CKBCIlkhj42SyBAiZ + LC5WKokGhagQQFglEEAOSONkCYlJCiaSEhNkcVLIBQH9CB4CvkCEBORJihRlqgoiVZmi + SJIjBZGAT3kmrBIIRZLYeHnSAaXqkPpIGsQR9SGV8kCSPD5WAuuBaoTvBGJJrCxRoVSp + 0zTpWt2xYzptuiZNrVIqEmWxEjHVCD8IYuISklOQgFafecKQlWU4kanXIoWU5IS4GJoR + fiKQK5QH0zS6TEN2rjEPwpibbcjUadIOKhVymhHWCOLlil/UR7UZhlPGs+fOF0KcP3fW + eMqQoT2q/kUhj6c2E34iSFSkqjW649nGfFNRaXkFRHlpkSnfmH1cp1GnKhJpRVhPcFij + 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 + a7jf3NLSfL/BVme9aq4oMZ0m8qrRVlmAbt+YCfosY0HxhSrL9dpb9ba7d231t2qvW6ou + FBcYs/QEXjjzh+B/CDAnNTe/sKzSbLlWY62ttdZcs5grywrzc2HeKHnXDv0j2ICQehgQ + cs6Yissrq8wWCHNVZXmx6UwOIkgl7fKpvwQbEdQa3fFsY76pqLS8AqK8tMiUb8w+rtOo + KSZYhyCHyclHtRmGU8az584XQpw/d9Z4ypChPQrTh+VkXUT3PwvQPdcKI0zQVh5M0+gy + Ddm5xjwIY262IVOnSTuoZEZxE/Q6wvYI1iEkJKeo1GkarT7zhCEry3AiU6/VpKlVKckJ + ayPZcX1xfbtPe/39f2QCTNFOVCiRQrpWd+yYTpuOBJSKRJhATdKrSeufnn/ffUeAUeLx + 8qQDStUh9ZE0iCPqQyrlgSR5PMxepngheJBWEQQiiTROJk9SpChTVRCpyhRFklwWJ4WJ + 9Hi/y8S/3/Xm9/IgRAlEYqSQkJikYCIpMQEJiEVoDDnGb7TZ/Mn5e+sqAl8oipZIY+Nk + sgQImSwuViqJhnUQCgTfdwceHxTEEkmMNBZCGiOBHBDy+bwQyAKULZAJMCUxkhfFFwhF + InE0hFgkEgr4UbxIGMOO7zvO/E11f+7HIEQwCny+QCAUCgR8PiMApSA0CFAq7INUgLEv + 4MCLguBBBsAqAAFvw3b9cSXwPigVGIYIBBEZEeEBCJkk8PzK9noYGAnkAQF/ReCvc5cP + GZ60R4L5Ypf/WfifhwXCAmGBsEBYICwQFggLBFbgP0gqPFwKZW5kc3RyZWFtCmVuZG9i + ago2OCAwIG9iagozNzExCmVuZG9iago3MCAwIG9iago8PCAvTGVuZ3RoIDcxIDAgUiAv + VHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRoIDI2MCAvSGVpZ2h0IDI2 + MCAvQ29sb3JTcGFjZQovRGV2aWNlR3JheSAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0 + ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae2d+VsUx9bHXdiRYdVhVRBFQRRQzCiK + gEQQQVAgcQEjChoRXFAxEL0oj4orwYvixUB4JRdRiaAoatTXJ//aPVXd1V09U70NPTM9 + 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 + 2tbeeaXrWlfXlY72ttafj9XV8vECcSwwdQSZ9YnLPXPsDgUlFdUHf2psPtN2sf3y5faL + 5880Nx09VFPB5Rf4IAJ72YzqNu/4fs++H+samk61nDl7trXlVFND/YH95buEM0fJKYvy + taDlgJv2OZ4dhH2RUMHbll9cVllzsL7heNOJE43Hj9YfrKkqK863wYmjpKKNh9KwXceQ + QOCizQjC9qKS8qqaA4fq6uvrDv1YU1VeUrSdRuDFPoIcRgmElLR12bl5O4pLyyv3V9fU + VO+r3FNaXJC3OXtdWkqih3alyL1xI5/bQcjI2mTbVlBcsrtsz56y0l07C7bZNmVlrIaj + d2MiIYLsg1aAYNIQEpNXrc3MzrXl5RcW7dxZWJCfZ8vNzly7CiPwDYHMth+AQBSjNWHF + yrT09dmbNtu25m3dYtu8MXt9elrqigSwAl9GIBFL1vik5NS09MwNWTlwZW3IBALJSfHW + aO4gbp8QyAqWgKbIiKilsYjC6jXp6RkZ6WvTVgOBhNilUT6PQBRLYeGRMcuAworklalw + rUxekRQftywmMty7FtTYn7TaUzwmBMBxJ5aIqJhl1viExCS4EuPjrMtioiIscBi7z0kj + RyQ8hODQMEtEZDRgsMbGWgFAdGSEJSw0eC4gIN0hMCgEKIRHRkZFwxUVGRFuWRIaArIA + DhHzIR/B0Qa4J8gSUKQVKAAGS3h4uMUStiQUbACMAM4gnwMIOEvw8/cPCAwKBgz4CgEA + gQH+cITYIsXjYuS4et9zsARkChhDEL4CMQBsBEon5nhfU+Xf8UJMAWPwDwiAzx8sAAGY + G/2A57IQU1i0ePFiP3TBVwxgjvQDwTh4DKjt+ILvhZ/NpRtoN7nmUrPn2zpPYJ7APIF5 + AvME5gnME/AKAv8Df6F/1QplbmRzdHJlYW0KZW5kb2JqCjcxIDAgb2JqCjY4MjQKZW5k + b2JqCjc0IDAgb2JqCjw8IC9MZW5ndGggNzUgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0 + eXBlIC9JbWFnZSAvV2lkdGggMjYwIC9IZWlnaHQgMjYwIC9Db2xvclNwYWNlCi9EZXZp + Y2VHcmF5IC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4K + c3RyZWFtCngB7d3/U1JZFADwvijyTURFVJKVomxxILQwU7I0Gr+3Wg4jfTOcMqNGLR1a + R8sp1Cmx8kvluOZoTuygmWnqqG27s//anvuwTBcUFd6798L5JQ1K+Hjuue894Jw9e8IR + FggLhAXCAmGBsEBYICyAkcBeFPsgmC8wemAsPZTVZw8A+/cjBgj4K5Z+OBY/xvPr378/ + IiIiEgL+8EiEkAJaAAAAz57Hi4Lg8RAEwxAiqYCSAAHwovh8vkAgFAoE8EUUOETAsgiJ + VGAIGAGBUCQSR0OIRSKhgFEIDQQggCTg8flCkVgiiZHGQkhjJBKxSMjn81AqUJ8JHoIo + EIiWSGPjZLIECJksLlYqiQaFqBBAWCUQQA5I42QJiUkKJpISE2RxUsgFAf0IHgK+QIQE + 5EmKFGWqCiJVmaJIkiMFkYBPeSasEghFkth4edIBpeqQ+kgaxBH1IZXyQJI8PlYC64Fq + hO8EYkmsLFGhVKnTNOla3bFjOm26Jk2tUioSZbESMdUIPwhi4hKSU5CAVp95wpCVZTiR + qdcihZTkhLgYmhF+IpArlAfTNLpMQ3auMQ/CmJttyNRp0g4qFXKaEdYI4uWKX9RHtRmG + U8az584XQpw/d9Z4ypChPar+RSGPpzYTfiJIVKSqNbrj2cZ8U1FpeQVEeWmRKd+YfVyn + UacqEmlFWE9wWKM35JwxFZdXVpktEOaqyvJi05kcg15zmFqEdQQqRJCbX1hWabZcq7HW + 1lprrlnMlWWF+bkIQUVnJmwgSNdnGQuKL1RZrtfeqrfdvWurv1V73VJ1objAmKVPpxNh + I0HGydOmkgrzVWudreF+c0tL8/0GW531qrmixHT6ZAaVCP8nyDOVVFbX3LQ1Nttb29rb + 21rtzY22mzXVlSWmPCoRvBGUXrTcqLv3wN7W8dTR1eV42tFmf3Cv7oblYimVCN4Iyi5d + tt5uaGntcHQ/d/b2Op93OzpaWxpuWy9fKqMQwRdBfaO9/Um382XfwODgQN9LZ/eTdntj + PZUIvgjuNNkfOZ696H89NAwx9Lr/xTPHI3vTHQoRvBNcsd5pevi4s+fV4NDI6BjE6MjQ + 4KuezscPAeEKZcvBB0Gtren3ji5n35vh0fEJF8TE+Ojwmz5nV8fvTbZauhA2J+h/OzI2 + 4XJPTk1Nul0TYyNv+ylE2JSgt3/o3fgH99T0DMT0lPvD+Luh/l7aMmFzgoGhd+9d7o8z + s3MQszMf3a7374YGKEPYkmDCNTn9eW5+AWJ+7vP0pGuCNgQ/CKY+zX5ZWFyCWFz4Mvtp + ijaErQn+BIL5haWl5ZWV5aWlhXlA+JOqTPCLYG5+cWn5KxPLS4vzc3Qh+E2w8vXrX9++ + /fX16wptCNsgAIG//0YKlCFsi+BvJmhD2AEBpAJVmbBdgn8gIBdoQtgJAWUIOyOgCmGn + BBQh7JyAGoTdEFCCsDsCKhB2SvDvv2h7REH8FrlzAmoQdkNACcLuCKhA2C0BBQi7JyAe + IRAEhCMEhoBohEAREIwQOAJiEQJJQChCYAmIRAg0AYEIgScgDiEYBIQhBIeAKIRgERCE + EDwCYhCCSUAIQnAJiEAINgEBCMEnwB6BDQLMEdghwBqBLQKMEdgjwBaBTQJMEdglwBKB + bQIMEdgnwA6BCwLMELghwAqBKwKMELgjwAaBSwJMELglwAKBawIMELgn4BwBBwKOEfAg + 4BQBFwIOEfAh4AwBJwKOEPAi4AQBNwIOEPAjYB0BRwKWEfAkYBUBVwIWEfAlYA0BZwKW + EPAmYAUBdwIWEPAnCDoCCQRBRiCDIKgIpBAEEYEcgqAhkEQQJASyCIKDwAwK4QvFMXGJ + CtXh9IyTeaayS1c8zf56ocfZBLR2Qn2NVqCnD3w82fM55X/++Zez+P4I/Pqs9Fov900m + NHkIBEAgV6SSQLCdTEhlGtqvDrnwiQBDgyIio2BKBkOg0TNZcNnKtHzEMgtQ+m2VCavt + SZk25vI4mPQB405gBJIPBDQ3KTKKD1MyEqAzvkafddpUCh1w76Cul9gSbImAerSWmk5n + 6TXQ1T8BJn3A4Bs0Ask7AqwEGBoEBLJkJRAYjKaSi/gT+INwscRkhF7uamUyTPoQwQgk + mIDk3cCzEsQx8YkpB4/qDLkFJZUWa33TQ6yzYMvl8LCp3mqpLCnINeiOHkxBkw08q8Gr + wY80kCtUadrjOflFFdU3bjfaH3c5ofEndjvCz1uRz5oAPVof2xtv36iuKMrPOa5NUynk + myYCMogSRktlSbASMrLPFF4w19Q12B91MgQuzDbFnwl8LAfUlLLf2fnI3lBXY75QeCY7 + A1ZDkkwaLUQVweti2AubAlSDOPkBVZoOikFZ1dWb91raHT19b6H3KWr5iNFxwXoCbwio + M+f7d2/7ehztLfduXq0qg5KgS1MdQHsDzD/ybrBvXyRPIPakQWZ2fjEUA9uD1ifPXr0Z + GXdN4k3gHWHSNT7y5tWzJ60PbFASivOzMz2JIBbwIvft81IQVpcC7ItQDSANys3X6xrt + Hd0vBofHPrinsc4C74Vxdtr9YWx48EV3h72x7rq5HBIBVYSEWJ+LARmgpZCYcuhXffbZ + ogpLra25zdHTPzQ64f74+csCPgfIGxeC5/uNhXHhy+eP7onRof4eR1uzrdZSUXQ2W//r + oZREZjF4LQhQDuDgICYeKmJ6Zk5BadW1Ww2QBi9f/zHumpqZW4Dep5icI3gn2LgclpcW + 5mamXON/vH4JidBw61pVaUFOZjpUxfgYOETwWhCQASoHyalHtCfQUqipv9/69HkfSoPV + lYDHaZIvgvUITHdSWA2QCH3Pn7ber69Bi+GE9khqskwKBcGXQZRAzJQDnSGv8LdqK1oK + zgGoBpOffqTB94Tz/UC4vOX7o2N6UqJE+DQJFWHAiRaDtfq3wjy0M0BBgMMkHwZwuhTN + GBzLyiuEcnC3ub2zFyqiZynA6fLa2TKXT3Szn72KAA8UNSdlFgNUxd7O9ua7UBAK87KO + eYoiHCp62xz37gsbQD0Ir4VwTdwT3hv3gEH4GCl8rAwnEOFzJrQYwufOq4shxK+hrF5S + DeFraVAQ0KsLIX1NldkdQ/3aevg1Ftgdw6+1MQj7YX8M6ddcmQNmQAjp1973hN+DgVYD + HCl5MiGegHdhrF07C+hAF5IQgkRAUiYEjYAchCASkIIQVAIyEIJMQAJC0AnwR2CBAHcE + VgjwRmCJAGcE1gjwRWCRAFcEVgnwRGCZAEcE1gnwQ+CAADcETgjwQuCIACcEzgjwQeCQ + ABcETgnwQOCYAAcEzgm4R8CAgGsELAi4RcCEgEsEbAi4Q8CIgCsErAi4QcCMgAsE7AjY + R8CQgG0ELAnYRcCUgE0EbAnYQ8CYgC0ErAnYQcCcgA0E7AmCj0AAQbARiCAILgIhBMFE + IIYgeAgEEQQLgSiC4CAQRhAMBOIIAo9AIEGgEYgkCCwCoQSBRCCWIHAIBBMECoFogsAg + EE4QCATiCXaPQAHBbhGoINgdAiUEu0GghmDnCBQR7BbBr67x0B1ZCA1hoQmm17a48IFt + rmOnn5VGmUAJwW4ygRqCnSNQRLBTBKoIdoZAGcH2EQCAaQG7srQ4P/dp6k9okj7Q29Xx + e5Ot9sqlMlPeyYz0wyoF6peP+Y7w84603d2BQoJtZgL0bP72DTXBpSgLUEZsIxOgdzcI + 0EewDYTlr0ws05YFfmfC7PzC0tLyysry0tLCPIxLoKMcrpXGrZcDmmrxZWFxCWJx4Qua + GEHFjrBG4M9ycE1Of56bX4CYn/s8PUkfgR8I713ujzOzcxCzMx/dMDeEguOCn7Ng65oA + o37GP7inpmcgpqfcH8Zhfgzxh0YbCbbIBGf/25GxCZd7cmpq0u2aGBt5C3OECD86/D/B + Vgh9b4ZHxydcEBPjo8Nv+qgk8IkAI+AePu7seTU4NDI6BjE6MjT4qqfz8cOmO1ZyzxG8 + ZYHvmoCGwNkfOZ696H89NAwx9Lr/xTPHIzsQXCb2NMkXga9MuGytb7S3P+l2vuwbGBwc + 6Hvp7H7Sbm+sp5LAN8LthpbWDkf3c2dvr/N5t6OjtaXhNqUE3hFKL1pu1N17YG/reOro + 6nI87WizP7hXd8NysZTQ6wW+F4LnFm+HzSWV1TU3bY3N9ta29va2Vntzo+1mTXVlCaUE + 3jLhtKmkwnzVWmdruN/c0tJ8v8FWZ71qrigxnSbyqtFWWYBu35gJ+ixjQfGFKsv12lv1 + trt3bfW3aq9bqi4UFxiz9AReOPOH4H8IMCc1N7+wrNJsuVZjra211lyzmCvLCvNzYd4o + edcO/SPYgJB6GBByzpiKyyurzBYIc1VlebHpTA4iSCXt8qm/BBsR1Brd8WxjvqmotLwC + ory0yJRvzD6u06gpJliHIIfJyUe1GYZTxrPnzhdCnD931njKkKE9CtOH5WRdRPc/C9A9 + 1wojTNBWHkzT6DIN2bnGPAhjbrYhU6dJO6hkRnET9DrC9gjWISQkp6jUaRqtPvOEISvL + cCJTr9WkqVUpyQlrI9lxfXF9u097/f1/ZAJM0U5UKJFCulZ37JhOm44ElIpEmEBN0qtJ + 65+ef999R4BR4vHypANK1SH1kTSII+pDKuWBJHk8zF6meCF4kFYRBCKJNE4mT1KkKFNV + EKnKFEWSXBYnhYn0eL/LxL/f9eb38iBECURipJCQmKRgIikxAQmIRWgMOcZvtNn8yfl7 + 6yoCXyiKlkhj42SyBAiZLC5WKomGdRAKBN93Bx4fFMQSSYw0FkIaI4EcEPL5vBDIApQt + kAkwJTGSF8UXCEUicTSEWCQSCvhRvEgYw47vO878TXV/7scgRDAKfL5AIBQKBHw+IwCl + IDQIUCrsg1SAsS/gwIuC4EEGwCoAAW/Ddv1xJfA+KBUYhggEERkR4QEImSTw/Mr2ehgY + CeQBAX9F4K9zlw8ZnrRHgvlil/9Z+J+HBcICYYGwQFggLBAWCAsEVuA/SCo8XAplbmRz + dHJlYW0KZW5kb2JqCjc1IDAgb2JqCjM3MTEKZW5kb2JqCjYwIDAgb2JqCjw8IC9MZW5n + dGggNjEgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMjY0 + IC9IZWlnaHQgMTU2IC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5IC9CaXRzUGVyQ29tcG9u + ZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7Z3bT1NZFIeFll7o + nZ6209PT0gv0RhEKhHKJRayiYBWJaBslpKaMqabKjAOBMAwMGsTUYUAJQQjDxSAGCAFD + kBAx/muzdlvHIwW8zLwcZv0eCC9Nuj6+tfY5POx14gQGCSABJIAEkMC/IpB17PKNOKD+ + 7E/hHYN8qiYbivsaHGkGPB6fz885ZoGSeDyC5IssUiLwCAGBQCgUpSLmeNJlCIUCARTG + T6M4wgrSDgSCgBAQ50ogUqlUxvlAEaSWXDGUJQQWSRSHtgeRIU0BGEhlcrlCoVQdkygV + CrlcJiUsPpI4bFCkMIALAEEuV6ry1BRFabRaHeej1WqgFHWeSimXAwpCgihxsBFpDCIx + UFCq1JRGp9PTtMHAMEaOh2EMBprW63QaSg0opBKx6HAQKQxEBrlCBRD0NGM0mc0Wq9XG + +VitFrPZZGSAhYZSKeREicOMyCKzATCADGqNjmZMZqut0O5wulxut7uIw4Gv73I5HfZC + m9VsYmidRg1KpEEc0BkwI3MEBIOK0tJMvqXA7nR7ik+WlHq9ZRyP11tacrLY43baCyz5 + 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 + uVyhUKqOSZQKhVwuAwhiQiFlw2crxNLHxcfWIEoQEiLCAiKVSmWcDxRBagEGon8oHNIU + KRxEiWR3AAuBkNAgEXM8qSpEQqEATEiqAKPhUBk+kkih4PH5IMbxCpTEg+lIIHyBwmcs + yCcgvGOQVCXJn1/JIEUi+RM+cczCKg5/RQJIAAkgASTwPQT+Bp5VVMAKZW5kc3RyZWFt + CmVuZG9iago2MSAwIG9iagoyMjk5CmVuZG9iago1MCAwIG9iago8PCAvTGVuZ3RoIDUx + IDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRoIDI2MCAvSGVp + Z2h0IDE4OCAvQ29sb3JTcGFjZQovRGV2aWNlR3JheSAvQml0c1BlckNvbXBvbmVudCA4 + IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae2d+1NS+RvHvaDI7QCKgFyC + DqBcRPYEhooGDAzmLS9pi6WOhjZhGNnExKxZOJZMjJm2Ol6mzJys0dbJxqmm2Zr9177P + wdidFLfm+9tpn/cPjT/QzHlevp/X54O/nJwcDBJAAkgACSCBHyGQ+5PlR2b++zMwe94/ + yWd8/pklD0b7e8zjfziYH+ZmsQp+qrBYMBSN43sY0gQOxi9ks4sOwmF0vg7BZhfCrxRA + fIfCVwIFBYUwPofL5fF4fD5fwPDACDAIl8spKqI5/DsFGkE+bAAAgPH5AoIQikTinyAi + kZAgBECCCxgOKByzEGkE0AGagIAQisXFJRJJaalUKmN0pNLSUomkpFgsFhICmgJ0ARYi + OwS6BXQJaAIimF8qk5cpFEqVSs3oqFRKhaJMLpMCB1GaAlSBhpDlXEgjABHw+EAAAMD0 + ao1We5LUMTzkSa1WowYSgAEo8Hm0FrJDyKVdwOZACcQlUrkC5id1hvIKo8lkNlsYG7PZ + ZDJWlBt0JHBQyKUlYqgCh02b8WgRoAaAoIgnEIolMoVaS+rLTeZKq81GUdQpBgce32az + VppN5XpSq1bIJGKhAJpQwMqyDVAD0CE3jUCpIQ1Gi9VG2atPO2vrIC6Ghn72Wufpajtl + s1qMBlKjTEPgghizFCEXalDE5RNiiVyp0VVYqiiHs9bV4PZ4fT6fn7GBh/d63A2uWqeD + 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 + dGggMjYwIC9IZWlnaHQgMjYwIC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5IC9CaXRzUGVy + Q29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7d3/U1JZ + FADwvijyTURFVJKVomxxILQwU7I0Gr+3Wg4jfTOcMqNGLR1aR8sp1Cmx8kvluOZoTuyg + mWnqqG27s//anvuwTBcUFd6798L5JQ1K+Hjuue894Jw9e8IRFggLhAXCAmGBsEBYICyA + kcBeFPsgmC8wemAsPZTVZw8A+/cjBgj4K5Z+OBY/xvPr378/IiIiEgL+8EiEkAJaAAAA + z57Hi4Lg8RAEwxAiqYCSAAHwovh8vkAgFAoE8EUUOETAsgiJVGAIGAGBUCQSR0OIRSKh + gFEIDQQggCTg8flCkVgiiZHGQkhjJBKxSMjn81AqUJ8JHoIoEIiWSGPjZLIECJksLlYq + iQaFqBBAWCUQQA5I42QJiUkKJpISE2RxUsgFAf0IHgK+QIQE5EmKFGWqCiJVmaJIkiMF + kYBPeSasEghFkth4edIBpeqQ+kgaxBH1IZXyQJI8PlYC64FqhO8EYkmsLFGhVKnTNOla + 3bFjOm26Jk2tUioSZbESMdUIPwhi4hKSU5CAVp95wpCVZTiRqdcihZTkhLgYmhF+IpAr + lAfTNLpMQ3auMQ/CmJttyNRp0g4qFXKaEdYI4uWKX9RHtRmGU8az584XQpw/d9Z4ypCh + Par+RSGPpzYTfiJIVKSqNbrj2cZ8U1FpeQVEeWmRKd+YfVynUacqEmlFWE9wWKM35Jwx + FZdXVpktEOaqyvJi05kcg15zmFqEdQQqRJCbX1hWabZcq7HW1lprrlnMlWWF+bkIQUVn + JmwgSNdnGQuKL1RZrtfeqrfdvWurv1V73VJ1objAmKVPpxNhI0HGydOmkgrzVWudreF+ + c0tL8/0GW531qrmixHT6ZAaVCP8nyDOVVFbX3LQ1Nttb29rb21rtzY22mzXVlSWmPCoR + vBGUXrTcqLv3wN7W8dTR1eV42tFmf3Cv7oblYimVCN4Iyi5dtt5uaGntcHQ/d/b2Op93 + OzpaWxpuWy9fKqMQwRdBfaO9/Um382XfwODgQN9LZ/eTdntjPZUIvgjuNNkfOZ696H89 + NAwx9Lr/xTPHI3vTHQoRvBNcsd5pevi4s+fV4NDI6BjE6MjQ4KuezscPAeEKZcvBB0Gt + ren3ji5n35vh0fEJF8TE+Ojwmz5nV8fvTbZauhA2J+h/OzI24XJPTk1Nul0TYyNv+ylE + 2JSgt3/o3fgH99T0DMT0lPvD+Luh/l7aMmFzgoGhd+9d7o8zs3MQszMf3a7374YGKEPY + kmDCNTn9eW5+AWJ+7vP0pGuCNgQ/CKY+zX5ZWFyCWFz4MvtpijaErQn+BIL5haWl5ZWV + 5aWlhXlA+JOqTPCLYG5+cWn5KxPLS4vzc3Qh+E2w8vXrX9++/fX16wptCNsgAIG//0YK + lCFsi+BvJmhD2AEBpAJVmbBdgn8gIBdoQtgJAWUIOyOgCmGnBBQh7JyAGoTdEFCCsDsC + KhB2SvDvv2h7REH8FrlzAmoQdkNACcLuCKhA2C0BBQi7JyAeIRAEhCMEhoBohEAREIwQ + OAJiEQJJQChCYAmIRAg0AYEIgScgDiEYBIQhBIeAKIRgERCEEDwCYhCCSUAIQnAJiEAI + NgEBCMEnwB6BDQLMEdghwBqBLQKMEdgjwBaBTQJMEdglwBKBbQIMEdgnwA6BCwLMELgh + wAqBKwKMELgjwAaBSwJMELglwAKBawIMELgn4BwBBwKOEfAg4BQBFwIOEfAh4AwBJwKO + EPAi4AQBNwIOEPAjYB0BRwKWEfAkYBUBVwIWEfAlYA0BZwKWEPAmYAUBdwIWEPAnCDoC + CQRBRiCDIKgIpBAEEYEcgqAhkEQQJASyCIKDwAwK4QvFMXGJCtXh9IyTeaayS1c8zf56 + ocfZBLR2Qn2NVqCnD3w82fM55X/++Zez+P4I/Pqs9Fov900mNHkIBEAgV6SSQLCdTEhl + GtqvDrnwiQBDgyIio2BKBkOg0TNZcNnKtHzEMgtQ+m2VCavtSZk25vI4mPQB405gBJIP + BDQ3KTKKD1MyEqAzvkafddpUCh1w76Cul9gSbImAerSWmk5n6TXQ1T8BJn3A4Bs0Ask7 + AqwEGBoEBLJkJRAYjKaSi/gT+INwscRkhF7uamUyTPoQwQgkmIDk3cCzEsQx8YkpB4/q + DLkFJZUWa33TQ6yzYMvl8LCp3mqpLCnINeiOHkxBkw08q8GrwY80kCtUadrjOflFFdU3 + bjfaH3c5ofEndjvCz1uRz5oAPVof2xtv36iuKMrPOa5NUynkmyYCMogSRktlSbASMrLP + FF4w19Q12B91MgQuzDbFnwl8LAfUlLLf2fnI3lBXY75QeCY7A1ZDkkwaLUQVweti2Aub + AlSDOPkBVZoOikFZ1dWb91raHT19b6H3KWr5iNFxwXoCbwioM+f7d2/7ehztLfduXq0q + g5KgS1MdQHsDzD/ybrBvXyRPIPakQWZ2fjEUA9uD1ifPXr0ZGXdN4k3gHWHSNT7y5tWz + J60PbFASivOzMz2JIBbwIvft81IQVpcC7ItQDSANys3X6xrtHd0vBofHPrinsc4C74Vx + dtr9YWx48EV3h72x7rq5HBIBVYSEWJ+LARmgpZCYcuhXffbZogpLra25zdHTPzQ64f74 + +csCPgfIGxeC5/uNhXHhy+eP7onRof4eR1uzrdZSUXQ2W//roZREZjF4LQhQDuDgICYe + KmJ6Zk5BadW1Ww2QBi9f/zHumpqZW4Dep5icI3gn2LgclpcW5mamXON/vH4JidBw61pV + aUFOZjpUxfgYOETwWhCQASoHyalHtCfQUqipv9/69HkfSoPVlYDHaZIvgvUITHdSWA2Q + CH3Pn7ber69Bi+GE9khqskwKBcGXQZRAzJQDnSGv8LdqK1oKzgGoBpOffqTB94Tz/UC4 + vOX7o2N6UqJE+DQJFWHAiRaDtfq3wjy0M0BBgMMkHwZwuhTNGBzLyiuEcnC3ub2zFyqi + ZynA6fLa2TKXT3Szn72KAA8UNSdlFgNUxd7O9ua7UBAK87KOeYoiHCp62xz37gsbQD0I + r4VwTdwT3hv3gEH4GCl8rAwnEOFzJrQYwufOq4shxK+hrF5SDeFraVAQ0KsLIX1Nldkd + Q/3aevg1Ftgdw6+1MQj7YX8M6ddcmQNmQAjp1973hN+DgVYDHCl5MiGegHdhrF07C+hA + F5IQgkRAUiYEjYAchCASkIIQVAIyEIJMQAJC0AnwR2CBAHcEVgjwRmCJAGcE1gjwRWCR + AFcEVgnwRGCZAEcE1gnwQ+CAADcETgjwQuCIACcEzgjwQeCQABcETgnwQOCYAAcEzgm4 + R8CAgGsELAi4RcCEgEsEbAi4Q8CIgCsErAi4QcCMgAsE7AjYR8CQgG0ELAnYRcCUgE0E + bAnYQ8CYgC0ErAnYQcCcgA0E7AmCj0AAQbARiCAILgIhBMFEIIYgeAgEEQQLgSiC4CAQ + RhAMBOIIAo9AIEGgEYgkCCwCoQSBRCCWIHAIBBMECoFogsAgEE4QCATiCXaPQAHBbhGo + INgdAiUEu0GghmDnCBQR7BbBr67x0B1ZCA1hoQmm17a48IFtrmOnn5VGmUAJwW4ygRqC + nSNQRLBTBKoIdoZAGcH2EQCAaQG7srQ4P/dp6k9okj7Q29Xxe5Ot9sqlMlPeyYz0wyoF + 6peP+Y7w84603d2BQoJtZgL0bP72DTXBpSgLUEZsIxOgdzcI0EewDYTlr0ws05YFfmfC + 7PzC0tLyysry0tLCPIxLoKMcrpXGrZcDmmrxZWFxCWJx4QuaGEHFjrBG4M9ycE1Of56b + X4CYn/s8PUkfgR8I713ujzOzcxCzMx/dMDeEguOCn7Ng65oAo37GP7inpmcgpqfcH8Zh + fgzxh0YbCbbIBGf/25GxCZd7cmpq0u2aGBt5C3OECD86/D/BVgh9b4ZHxydcEBPjo8Nv + +qgk8IkAI+AePu7seTU4NDI6BjE6MjT4qqfz8cOmO1ZyzxG8ZYHvmoCGwNkfOZ696H89 + NAwx9Lr/xTPHIzsQXCb2NMkXga9MuGytb7S3P+l2vuwbGBwc6Hvp7H7Sbm+sp5LAN8Lt + hpbWDkf3c2dvr/N5t6OjtaXhNqUE3hFKL1pu1N17YG/reOro6nI87WizP7hXd8NysZTQ + 6wW+F4LnFm+HzSWV1TU3bY3N9ta29va2Vntzo+1mTXVlCaUE3jLhtKmkwnzVWmdruN/c + 0tJ8v8FWZ71qrigxnSbyqtFWWYBu35gJ+ixjQfGFKsv12lv1trt3bfW3aq9bqi4UFxiz + 9AReOPOH4H8IMCc1N7+wrNJsuVZjra211lyzmCvLCvNzYd4oedcO/SPYgJB6GBByzpiK + yyurzBYIc1VlebHpTA4iSCXt8qm/BBsR1Brd8WxjvqmotLwCory0yJRvzD6u06gpJliH + IIfJyUe1GYZTxrPnzhdCnD931njKkKE9CtOH5WRdRPc/C9A91wojTNBWHkzT6DIN2bnG + PAhjbrYhU6dJO6hkRnET9DrC9gjWISQkp6jUaRqtPvOEISvLcCJTr9WkqVUpyQlrI9lx + fXF9u097/f1/ZAJM0U5UKJFCulZ37JhOm44ElIpEmEBN0qtJ65+ef999R4BR4vHypANK + 1SH1kTSII+pDKuWBJHk8zF6meCF4kFYRBCKJNE4mT1KkKFNVEKnKFEWSXBYnhYn0eL/L + xL/f9eb38iBECURipJCQmKRgIikxAQmIRWgMOcZvtNn8yfl76yoCXyiKlkhj42SyBAiZ + LC5WKomGdRAKBN93Bx4fFMQSSYw0FkIaI4EcEPL5vBDIApQtkAkwJTGSF8UXCEUicTSE + WCQSCvhRvEgYw47vO878TXV/7scgRDAKfL5AIBQKBHw+IwClIDQIUCrsg1SAsS/gwIuC + 4EEGwCoAAW/Ddv1xJfA+KBUYhggEERkR4QEImSTw/Mr2ehgYCeQBAX9F4K9zlw8ZnrRH + gvlil/9Z+J+HBcICYYGwQFggLBAWCAsEVuA/SCo8XAplbmRzdHJlYW0KZW5kb2JqCjUz + IDAgb2JqCjM3MTEKZW5kb2JqCjU3IDAgb2JqCjw8IC9MZW5ndGggNTggMCBSIC9UeXBl + IC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMjYwIC9IZWlnaHQgMjYwIC9D + b2xvclNwYWNlCi9EZXZpY2VHcmF5IC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAv + RmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7d3/U1JZFADwvijyTURFVJKVomxxILQwU7I0 + Gr+3Wg4jfTOcMqNGLR1aR8sp1Cmx8kvluOZoTuygmWnqqG27s//anvuwTBcUFd6798L5 + JQ1K+Hjuue894Jw9e8IRFggLhAXCAmGBsEBYICyAkcBeFPsgmC8wemAsPZTVZw8A+/cj + Bgj4K5Z+OBY/xvPr378/IiIiEgL+8EiEkAJaAAAAz57Hi4Lg8RAEwxAiqYCSAAHwovh8 + vkAgFAoE8EUUOETAsgiJVGAIGAGBUCQSR0OIRSKhgFEIDQQggCTg8flCkVgiiZHGQkhj + JBKxSMjn81AqUJ8JHoIoEIiWSGPjZLIECJksLlYqiQaFqBBAWCUQQA5I42QJiUkKJpIS + E2RxUsgFAf0IHgK+QIQE5EmKFGWqCiJVmaJIkiMFkYBPeSasEghFkth4edIBpeqQ+kga + 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 + 4BPAJ4BP4J88gf8Cx7sMUAplbmRzdHJlYW0KZW5kb2JqCjczIDAgb2JqCjI1MTQKZW5k + b2JqCjY1IDAgb2JqCjw8IC9MZW5ndGggNjYgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0 + eXBlIC9JbWFnZSAvV2lkdGggMjYwIC9IZWlnaHQgMjYwIC9Db2xvclNwYWNlCi9EZXZp + Y2VHcmF5IC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4K + c3RyZWFtCngB7d3/U1JZFADwvijyTURFVJKVomxxILQwU7I0Gr+3Wg4jfTOcMqNGLR1a + R8sp1Cmx8kvluOZoTuygmWnqqG27s//anvuwTBcUFd6798L5JQ1K+Hjuue894Jw9e8IR + FggLhAXCAmGBsEBYICyAkcBeFPsgmC8wemAsPZTVZw8A+/cjBgj4K5Z+OBY/xvPr378/ + IiIiEgL+8EiEkAJaAAAAz57Hi4Lg8RAEwxAiqYCSAAHwovh8vkAgFAoE8EUUOETAsgiJ + VGAIGAGBUCQSR0OIRSKhgFEIDQQggCTg8flCkVgiiZHGQkhjJBKxSMjn81AqUJ8JHoIo + EIiWSGPjZLIECJksLlYqiQaFqBBAWCUQQA5I42QJiUkKJpISE2RxUsgFAf0IHgK+QIQE + 5EmKFGWqCiJVmaJIkiMFkYBPeSasEghFkth4edIBpeqQ+kgaxBH1IZXyQJI8PlYC64Fq + hO8EYkmsLFGhVKnTNOla3bFjOm26Jk2tUioSZbESMdUIPwhi4hKSU5CAVp95wpCVZTiR + qdcihZTkhLgYmhF+IpArlAfTNLpMQ3auMQ/CmJttyNRp0g4qFXKaEdYI4uWKX9RHtRmG + U8az584XQpw/d9Z4ypChPar+RSGPpzYTfiJIVKSqNbrj2cZ8U1FpeQVEeWmRKd+YfVyn + UacqEmlFWE9wWKM35JwxFZdXVpktEOaqyvJi05kcg15zmFqEdQQqRJCbX1hWabZcq7HW + 1lprrlnMlWWF+bkIQUVnJmwgSNdnGQuKL1RZrtfeqrfdvWurv1V73VJ1objAmKVPpxNh + I0HGydOmkgrzVWudreF+c0tL8/0GW531qrmixHT6ZAaVCP8nyDOVVFbX3LQ1Nttb29rb + 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 + ory0yJRvzD6u06gpJliHIIfJyUe1GYZTxrPnzhdCnD931njKkKE9CtOH5WRdRPc/C9A9 + 1wojTNBWHkzT6DIN2bnGPAhjbrYhU6dJO6hkRnET9DrC9gjWISQkp6jUaRqtPvOEISvL + cCJTr9WkqVUpyQlrI9lxfXF9u097/f1/ZAJM0U5UKJFCulZ37JhOm44ElIpEmEBN0qtJ + 65+ef999R4BR4vHypANK1SH1kTSII+pDKuWBJHk8zF6meCF4kFYRBCKJNE4mT1KkKFNV + EKnKFEWSXBYnhYn0eL/LxL/f9eb38iBECURipJCQmKRgIikxAQmIRWgMOcZvtNn8yfl7 + 6yoCXyiKlkhj42SyBAiZLC5WKomGdRAKBN93Bx4fFMQSSYw0FkIaI4EcEPL5vBDIApQt + kAkwJTGSF8UXCEUicTSEWCQSCvhRvEgYw47vO878TXV/7scgRDAKfL5AIBQKBHw+IwCl + IDQIUCrsg1SAsS/gwIuC4EEGwCoAAW/Ddv1xJfA+KBUYhggEERkR4QEImSTw/Mr2ehgY + CeQBAX9F4K9zlw8ZnrRHgvlil/9Z+J+HBcICYYGwQFggLBAWCAsEVuA/SCo8XAplbmRz + dHJlYW0KZW5kb2JqCjY2IDAgb2JqCjM3MTEKZW5kb2JqCjU1IDAgb2JqCjw8IC9MZW5n + dGggNTYgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMjI0 + IC9IZWlnaHQgMTg4IC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5IC9CaXRzUGVyQ29tcG9u + ZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7Z3tTxPpGodBCqXt + 9A3aaenLtkxb2mkp3bHFUgrbNm14RxSErbtC0KpZWJDV2EgWdTGsEokiuBBeosgS0YBL + wBAlRs351849hbNGGNRNTmbH5v59IGaCmeea3309U/rlycnB4BPAJ4BPAJ/A//cJ5H5F + +UfkwHXkQ/IEnQ/rPALL/gLMXTZgEonyv5qIRLBgFvVziBm6XbQCsbhwNxLBZm+BYnEB + VAGQnyHco8vPLwA0iVQqk8kIgpALOLA8WKRUKiksZBk/Tcji5cFUAhygEXKFQqlSqQUe + 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 + tNhpnz9YE43XN7W2tXd0diUFm67Ojva21qb6eLQm6PfRdotRB8fbS9nj3z863jAnJxcO + gC9gT7gHQKud9jKBqnAklqhraGxuaT0u0LS2NDc21CVikXBVgPHSdivgsafbFxzkA0AR + FEgAoN5osTk9FUwgGArXRqKxeDyeEGRgYbFopDYcCgaYCo/TZjHqAY+A+kT76/tfgVK5 + km3QQjlcHq+P8VceC4aqIWEBhl1XKHis0s/4vB6Xg2KHU62E6eSqD/qDAsWFsgygwWyl + 7GW0u9zr8zEMc1SggaX5fN5yN11mp6xmQwZPViiG+g72xxoIgBKZXKEuJvUGs8VK2Rxl + ThdNu90eQcbtpmmXs8xho6wWs0FPFqsVcpkE8A7sLuz3hFAgbDHQIKFQFWlIncFoAkZr + KWUTcKhSK7CZjAYdqSlSKQhoj51Ojvr2AGFEpVChqqgYEPUlBqA0mQUbE5AZSvQAVwx0 + cpkUhvMwvJzcTIPwlsgQKtVqYNRotSSpE2xIUqvVAJtarczQwdaSwdv38tv7GjsDKMqH + CoFQRsgVCqVKpRZ4VCqlQiEnZNAdWx64dySXGw8mFBpkdxlWw0KJFCBlBEHIBRxYHixS + KpUAHHTH0h2Ox24yu4SACIwAmYlEsNlboJhlyxd9li6zjbKER/Ly8kQs5FcSQMtjq/tk + d3sWsiVmGNnfh8D/FHB215j5Ccv+G+FL/gG//9XkS3jwd/AJ4BPAJ4BP4J88gf8Cx7sM + UAplbmRzdHJlYW0KZW5kb2JqCjU2IDAgb2JqCjI1MTQKZW5kb2JqCjQxIDAgb2JqCjw8 + IC9MZW5ndGggNDIgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lk + dGggMjYwIC9IZWlnaHQgMjYwIC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5IC9CaXRzUGVy + Q29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7d3/U1JZ + FADwvijyTURFVJKVomxxILQwU7I0Gr+3Wg4jfTOcMqNGLR1aR8sp1Cmx8kvluOZoTuyg + mWnqqG27s//anvuwTBcUFd6798L5JQ1K+Hjuue894Jw9e8IRFggLhAXCAmGBsEBYICyA + kcBeFPsgmC8wemAsPZTVZw8A+/cjBgj4K5Z+OBY/xvPr378/IiIiEgL+8EiEkAJaAAAA + z57Hi4Lg8RAEwxAiqYCSAAHwovh8vkAgFAoE8EUUOETAsgiJVGAIGAGBUCQSR0OIRSKh + gFEIDQQggCTg8flCkVgiiZHGQkhjJBKxSMjn81AqUJ8JHoIoEIiWSGPjZLIECJksLlYq + iQaFqBBAWCUQQA5I42QJiUkKJpISE2RxUsgFAf0IHgK+QIQE5EmKFGWqCiJVmaJIkiMF + kYBPeSasEghFkth4edIBpeqQ+kgaxBH1IZXyQJI8PlYC64FqhO8EYkmsLFGhVKnTNOla + 3bFjOm26Jk2tUioSZbESMdUIPwhi4hKSU5CAVp95wpCVZTiRqdcihZTkhLgYmhF+IpAr + lAfTNLpMQ3auMQ/CmJttyNRp0g4qFXKaEdYI4uWKX9RHtRmGU8az584XQpw/d9Z4ypCh + Par+RSGPpzYTfiJIVKSqNbrj2cZ8U1FpeQVEeWmRKd+YfVynUacqEmlFWE9wWKM35Jwx + FZdXVpktEOaqyvJi05kcg15zmFqEdQQqRJCbX1hWabZcq7HW1lprrlnMlWWF+bkIQUVn + JmwgSNdnGQuKL1RZrtfeqrfdvWurv1V73VJ1objAmKVPpxNhI0HGydOmkgrzVWudreF+ + c0tL8/0GW531qrmixHT6ZAaVCP8nyDOVVFbX3LQ1Nttb29rb21rtzY22mzXVlSWmPCoR + vBGUXrTcqLv3wN7W8dTR1eV42tFmf3Cv7oblYimVCN4Iyi5dtt5uaGntcHQ/d/b2Op93 + OzpaWxpuWy9fKqMQwRdBfaO9/Um382XfwODgQN9LZ/eTdntjPZUIvgjuNNkfOZ696H89 + NAwx9Lr/xTPHI3vTHQoRvBNcsd5pevi4s+fV4NDI6BjE6MjQ4KuezscPAeEKZcvBB0Gt + ren3ji5n35vh0fEJF8TE+Ojwmz5nV8fvTbZauhA2J+h/OzI24XJPTk1Nul0TYyNv+ylE + 2JSgt3/o3fgH99T0DMT0lPvD+Luh/l7aMmFzgoGhd+9d7o8zs3MQszMf3a7374YGKEPY + kmDCNTn9eW5+AWJ+7vP0pGuCNgQ/CKY+zX5ZWFyCWFz4MvtpijaErQn+BIL5haWl5ZWV + 5aWlhXlA+JOqTPCLYG5+cWn5KxPLS4vzc3Qh+E2w8vXrX9++/fX16wptCNsgAIG//0YK + lCFsi+BvJmhD2AEBpAJVmbBdgn8gIBdoQtgJAWUIOyOgCmGnBBQh7JyAGoTdEFCCsDsC + KhB2SvDvv2h7REH8FrlzAmoQdkNACcLuCKhA2C0BBQi7JyAeIRAEhCMEhoBohEAREIwQ + OAJiEQJJQChCYAmIRAg0AYEIgScgDiEYBIQhBIeAKIRgERCEEDwCYhCCSUAIQnAJiEAI + NgEBCMEnwB6BDQLMEdghwBqBLQKMEdgjwBaBTQJMEdglwBKBbQIMEdgnwA6BCwLMELgh + wAqBKwKMELgjwAaBSwJMELglwAKBawIMELgn4BwBBwKOEfAg4BQBFwIOEfAh4AwBJwKO + EPAi4AQBNwIOEPAjYB0BRwKWEfAkYBUBVwIWEfAlYA0BZwKWEPAmYAUBdwIWEPAnCDoC + CQRBRiCDIKgIpBAEEYEcgqAhkEQQJASyCIKDwAwK4QvFMXGJCtXh9IyTeaayS1c8zf56 + ocfZBLR2Qn2NVqCnD3w82fM55X/++Zez+P4I/Pqs9Fov900mNHkIBEAgV6SSQLCdTEhl + GtqvDrnwiQBDgyIio2BKBkOg0TNZcNnKtHzEMgtQ+m2VCavtSZk25vI4mPQB405gBJIP + BDQ3KTKKD1MyEqAzvkafddpUCh1w76Cul9gSbImAerSWmk5n6TXQ1T8BJn3A4Bs0Ask7 + AqwEGBoEBLJkJRAYjKaSi/gT+INwscRkhF7uamUyTPoQwQgkmIDk3cCzEsQx8YkpB4/q + DLkFJZUWa33TQ6yzYMvl8LCp3mqpLCnINeiOHkxBkw08q8GrwY80kCtUadrjOflFFdU3 + bjfaH3c5ofEndjvCz1uRz5oAPVof2xtv36iuKMrPOa5NUynkmyYCMogSRktlSbASMrLP + FF4w19Q12B91MgQuzDbFnwl8LAfUlLLf2fnI3lBXY75QeCY7A1ZDkkwaLUQVweti2Aub + AlSDOPkBVZoOikFZ1dWb91raHT19b6H3KWr5iNFxwXoCbwioM+f7d2/7ehztLfduXq0q + g5KgS1MdQHsDzD/ybrBvXyRPIPakQWZ2fjEUA9uD1ifPXr0ZGXdN4k3gHWHSNT7y5tWz + J60PbFASivOzMz2JIBbwIvft81IQVpcC7ItQDSANys3X6xrtHd0vBofHPrinsc4C74Vx + dtr9YWx48EV3h72x7rq5HBIBVYSEWJ+LARmgpZCYcuhXffbZogpLra25zdHTPzQ64f74 + +csCPgfIGxeC5/uNhXHhy+eP7onRof4eR1uzrdZSUXQ2W//roZREZjF4LQhQDuDgICYe + KmJ6Zk5BadW1Ww2QBi9f/zHumpqZW4Dep5icI3gn2LgclpcW5mamXON/vH4JidBw61pV + aUFOZjpUxfgYOETwWhCQASoHyalHtCfQUqipv9/69HkfSoPVlYDHaZIvgvUITHdSWA2Q + CH3Pn7ber69Bi+GE9khqskwKBcGXQZRAzJQDnSGv8LdqK1oKzgGoBpOffqTB94Tz/UC4 + vOX7o2N6UqJE+DQJFWHAiRaDtfq3wjy0M0BBgMMkHwZwuhTNGBzLyiuEcnC3ub2zFyqi + ZynA6fLa2TKXT3Szn72KAA8UNSdlFgNUxd7O9ua7UBAK87KOeYoiHCp62xz37gsbQD0I + r4VwTdwT3hv3gEH4GCl8rAwnEOFzJrQYwufOq4shxK+hrF5SDeFraVAQ0KsLIX1Nldkd + Q/3aevg1Ftgdw6+1MQj7YX8M6ddcmQNmQAjp1973hN+DgVYDHCl5MiGegHdhrF07C+hA + F5IQgkRAUiYEjYAchCASkIIQVAIyEIJMQAJC0AnwR2CBAHcEVgjwRmCJAGcE1gjwRWCR + AFcEVgnwRGCZAEcE1gnwQ+CAADcETgjwQuCIACcEzgjwQeCQABcETgnwQOCYAAcEzgm4 + R8CAgGsELAi4RcCEgEsEbAi4Q8CIgCsErAi4QcCMgAsE7AjYR8CQgG0ELAnYRcCUgE0E + bAnYQ8CYgC0ErAnYQcCcgA0E7AmCj0AAQbARiCAILgIhBMFEIIYgeAgEEQQLgSiC4CAQ + RhAMBOIIAo9AIEGgEYgkCCwCoQSBRCCWIHAIBBMECoFogsAgEE4QCATiCXaPQAHBbhGo + INgdAiUEu0GghmDnCBQR7BbBr67x0B1ZCA1hoQmm17a48IFtrmOnn5VGmUAJwW4ygRqC + nSNQRLBTBKoIdoZAGcH2EQCAaQG7srQ4P/dp6k9okj7Q29Xxe5Ot9sqlMlPeyYz0wyoF + 6peP+Y7w84603d2BQoJtZgL0bP72DTXBpSgLUEZsIxOgdzcI0EewDYTlr0ws05YFfmfC + 7PzC0tLyysry0tLCPIxLoKMcrpXGrZcDmmrxZWFxCWJx4QuaGEHFjrBG4M9ycE1Of56b + X4CYn/s8PUkfgR8I713ujzOzcxCzMx/dMDeEguOCn7Ng65oAo37GP7inpmcgpqfcH8Zh + fgzxh0YbCbbIBGf/25GxCZd7cmpq0u2aGBt5C3OECD86/D/BVgh9b4ZHxydcEBPjo8Nv + +qgk8IkAI+AePu7seTU4NDI6BjE6MjT4qqfz8cOmO1ZyzxG8ZYHvmoCGwNkfOZ696H89 + NAwx9Lr/xTPHIzsQXCb2NMkXga9MuGytb7S3P+l2vuwbGBwc6Hvp7H7Sbm+sp5LAN8Lt + hpbWDkf3c2dvr/N5t6OjtaXhNqUE3hFKL1pu1N17YG/reOro6nI87WizP7hXd8NysZTQ + 6wW+F4LnFm+HzSWV1TU3bY3N9ta29va2Vntzo+1mTXVlCaUE3jLhtKmkwnzVWmdruN/c + 0tJ8v8FWZ71qrigxnSbyqtFWWYBu35gJ+ixjQfGFKsv12lv1trt3bfW3aq9bqi4UFxiz + 9AReOPOH4H8IMCc1N7+wrNJsuVZjra211lyzmCvLCvNzYd4oedcO/SPYgJB6GBByzpiK + yyurzBYIc1VlebHpTA4iSCXt8qm/BBsR1Brd8WxjvqmotLwCory0yJRvzD6u06gpJliH + IIfJyUe1GYZTxrPnzhdCnD931njKkKE9CtOH5WRdRPc/C9A91wojTNBWHkzT6DIN2bnG + PAhjbrYhU6dJO6hkRnET9DrC9gjWISQkp6jUaRqtPvOEISvLcCJTr9WkqVUpyQlrI9lx + fXF9u097/f1/ZAJM0U5UKJFCulZ37JhOm44ElIpEmEBN0qtJ65+ef999R4BR4vHypANK + 1SH1kTSII+pDKuWBJHk8zF6meCF4kFYRBCKJNE4mT1KkKFNVEKnKFEWSXBYnhYn0eL/L + xL/f9eb38iBECURipJCQmKRgIikxAQmIRWgMOcZvtNn8yfl76yoCXyiKlkhj42SyBAiZ + LC5WKomGdRAKBN93Bx4fFMQSSYw0FkIaI4EcEPL5vBDIApQtkAkwJTGSF8UXCEUicTSE + WCQSCvhRvEgYw47vO878TXV/7scgRDAKfL5AIBQKBHw+IwClIDQIUCrsg1SAsS/gwIuC + 4EEGwCoAAW/Ddv1xJfA+KBUYhggEERkR4QEImSTw/Mr2ehgYCeQBAX9F4K9zlw8ZnrRH + gvlil/9Z+J+HBcICYYGwQFggLBAWCAsEVuA/SCo8XAplbmRzdHJlYW0KZW5kb2JqCjQy + IDAgb2JqCjM3MTEKZW5kb2JqCjQ3IDAgb2JqCjw8IC9MZW5ndGggNDggMCBSIC9UeXBl + IC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMzAwIC9IZWlnaHQgMjI4IC9D + b2xvclNwYWNlCi9EZXZpY2VHcmF5IC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAv + RmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7dn9T5P31wdwpKUPUPpAn0YppQ9YSi1CgVAe + YhE7UbAOiWgbJaSmzlRTZXMQCGMwNIipY+AIQQgDMYgBQtAQJETI/rX7XKBzB8rZ/b3v + 70/tOT9sO3tHk88r53yuq21GBhcLsAALsAALsEASgVNpWUkgqP8FRplfS5Qm9fXEmQBA + +XzJPjuJRGKxOCsNC44tEgls/+p1OFAiQUkikUplhyVPg/p8VKlUIoHDiz9zfZmgJP8W + Vk+AkghK8uwcKIVCkZsWBQcVzpsth6NLweuA68RVFIbqsxQ4KXKVSpVKrUmjUqtUSmWu + QvD6onXSxXVIBTMFUEqlWpOn1el0eoPBmBZlMOjhuNo8jVqpBC5BSxit5JP1mUomBym1 + RqvTG435JlNBgdlcmAZlNhcUmEz5RqNepwUuRY5cdjLWIZUwVEqVBqDyTeZCi9Vqs9sd + aVF2u81qtRSawUuv06iUwmidNFmnhLsKqGCotHqjyWyx2h2nnSWu0lK3230mxQuOWFrq + KnGedtitFrPJqNfCaH3GSrKFcK9nSQQqjc5gMhfZip0ut6fsbHmF11uZBuX1VpSfLfO4 + Xc5iW5HZZNBpBCxJFlxZx14YYKy+UBlNhbbiEren3FtVXeOrrasXqiGF6+CAdbW+muoq + b7nHXVJsKzQZv2IdG6xTmbCB8hyYKqPJ4nC6y7xVNbX15/znmy4EAt+mfAUCF5rO+8/V + 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 + FeIgG7YieVDIVoiDbNiK5EEhWyEOsmErkgeFbIU4yIatSB4UshXiIBu2InlQyFaIg2zY + iuRBIVshDrJhK5IHhf+ZlUyhMZgdbm994Go4+qh/JPHy1eLbtc2tj7t7e/vo703BZn9v + b/fj1uba28VXLxMj/Y+i4auBeq/bYTZoFLIs0amMf1Zm1slWn9LB6hNhlflPqYyMf7Ha + T+nJ2t/f3/tvWsHfl8r1f7UKhqIP+4afT8wsLK9ufNje2f20l/L1aXdn+8PG6vLCzMTz + 4b6H0VDwH/dV0h0ssJd66y4Eb96J9w6N/T49/+bd+uYWYKVB7Wxvba6/ezM//fvYUG/8 + zs3ghTpvqb3g4G5PYqXWg1VFbVPrjciDnwZHf5uaW4TBer+1/XEn5evj9tZ7GKvFuanf + Rgd/ehC50dpUWwFWejU8B49b5aj1Jpur3He+5XpX7PHAk8TkzJ9LK2sbmx+20qA+bG6s + rSz9OTOZeDLwONZ1veW8r9xlM+nVOUmtVDqTteRsjf9Se+e97r7hsfGp2YU3K6vrG5vv + U742N9ZXV94szE6Njw33dd/rbL/krzlbYjXpVCdZ5Rc5PdXnmttuReM9g08TE9NzC0vL + 71bX1lO+1lbfLS8tzE1PJJ4O9sSjt9qaz1V7nEX5Sa3Eshyl9hvL6TNV9YFgKBL7oX9o + 9MXk9Oz866XltyspX2+Xl17Pz05Pvhgd6v8hFhEeg1VnTlu+0SpzZOKj95VYmq3MMxY6 + Sr21cGF13o33DIw8ezExNTM3v7D4OuVrcWF+bmZq4sWzkYGe+N1OuK5qvaWOQmOeMlua + zCoXPhDaXeU1/uZr4Uisu/fnkWeJ8cmp6ZlXsylfr2ampybHE89Gfu7tjkXC15r9NeUu + O3wczE1iJZLIczV6k9XpEZaw43b0PmANPx1LjE9Mvvwj5evl5MR4YuzpMFDdj97uEFbQ + 47Sa9JpcuUR0dAdFElmOWpdvgW8afI2X20JdgNXTPzj8ZHTseSIN6vnY6JPhwf4eoOoK + tV1u9MG3DJZ8HbwyJLHKgss9z2i2lZRVNwRa28Nd0Vj8x97+gV+Gfh1Jg/p16JeB/t4f + 47FoV7i9NdBQXVZiM8N1Ba8MR+fqVGYWXO6whEXF7gqf/+KV9tDtyPf3492Pe3r7+tOg + +np7HnfH738fuR1qv3LR76twFxfBCsLVnpWJv77KACuJXKHSwWA5PZV1jRdb2zrCnZHo + vdiD+MNH3Slfjx7GH8TuRSOd4Y621ouNdZUeJ4yVTqWQS5JYiYUl1OjzCx2usqo6f+By + 8FpH6FZnV+RONHo35SsavRPp6rwV6rgWvBzw11WVuRyF+TBWsILi43MlypLCYGkNJgtg + VfoaGgPNLcG29us3bobCaVChmzeut7cFW5oDjQ2+SqCymAxaGCspXFdHdjAjM1MMT8Jc + tc5oKnK4PBXVvgZ/U6D5UsuVYPDqdylfV4PBKy2XmgNN/gZfdYXH5SgyGXXqXHgKijOP + vDJkwIUlhsGCLQQsi8PpLvNW1dTWn/Ofb7oQCHyb8hUIXGg67z9XX1tT5S1zO2GqjDrY + QBirYysoWImyJLJsxQFWoa24xO0p91ZV1/hq6+qFakjhOjhgXa2vprrKW+5xlxTbCg+o + FNkySZIVhF8nvmIZTOYiW7HT5faUnS2v8Hor06C83orys2Uet8tZbCsymwwwVZ+pjq3g + wWDBFgqTpdbqjSazxWp3nHaWuEpL3W73mRQvOGJpqavEedpht1rMJqNeqxaoYAOP3+zw + A9gpGKwDrBylSqPTG/NN5kKL1Wqz2x1pUXa7zWq1FJpN+Ua9TqNS5nymOvYUFH4sPMSS + yOQ5MFoaLXCBl6mgwGwuTIMymwsKTOAEUFoNDFWOHO4qmKqkVH9jwR6CFnDlaXU6nd5g + MKZFGQx6OK42D6BACoaKoso4dThZWRKpTA5cuUqlSqXWpFGpVSqlMheg5ILU4VQdfQ/9 + ++d6wBIuLUFLJnhBKRSK3LQoOKhwXnCS/S11wgIeegmjdciVJZFIBTGh5GlQhyeVSaUS + mKiDkYKr6sSh+qJ1yCUSi2HA0q/g2CK40QWof5FCXsKfgBKlSR2e9uCf/0unv+8ueC6m + Zf0DgP+TBViABViABVjgq8D/AOqBT24KZW5kc3RyZWFtCmVuZG9iago0OCAwIG9iagoz + ODc3CmVuZG9iago3NiAwIG9iago8PCAvTGVuZ3RoIDc3IDAgUiAvTiAzIC9BbHRlcm5h + dGUgL0RldmljZVJHQiAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAGtk89r + 02Acxp+0Q4fOCXPzIAg5OPBQpbQFfyDYtetGN+lK263VW5ukTbVJQ5JWWzz0HxC8CepB + 8bLD9Kx4UQTx4kEmongV8eJlhzEYIz5JTOvB4cVvefN++uR5v++b7/u+QHinahitEABN + t83CYkqsXL0mHvyCCRziL4GZqmQZc/n8FVr2ie1PENxXm2fcXPeNXZy7u5nYftT7funp + xcP7DArkSZMTAkKEwnTD56TLNZ9LLt+0DZse1WVJrcrk2+SIWSqkyevkyYbPz12u+fzO + 5a7UcMd+Jkd1uakDoXHyeVmxJHKSrMqWpJGZRwhpWpv5wxvUT0uGybHhj+RTbl3YM3pH + gcv36H890ipvgY1nwPGfI22W3mNfgRfdkba149VKOPnNqsdjXjrhyGPgQN9xtmaAcc69 + t+Y4uynH2ePcY0zy8o7UMbuelwsU3gP/+u9/s58d+MA8DG+P/s5+XTxXFHgyANZeAUsU + HrLN8lunHgArSaA4QCgeD5pfQ1pY56KkGLapiJVYorzoSf/vobU63Csvpvic0Gu5FfYn + 2H4Ydr4UsNUtZgKuNxeyAcvV+eWA+2o6F3DdXCgEfL26lA9Y0VeLARst7+z/nis19CtW + Zujpq6Vy4Dc7hdWAb7SXh35ZmR+uTW/l3Pvk5Wza2eH6UYQEBQZsmOxFVBDjHSyDBfXP + JUchN83jOEbIvFnXBq7yZ9jKLW+/022jZzYbqi3O8VYqETGrS2cjYiwavYBfakqyNwpl + bmRzdHJlYW0KZW5kb2JqCjc3IDAgb2JqCjU2NQplbmRvYmoKNDMgMCBvYmoKWyAvSUND + QmFzZWQgNzYgMCBSIF0KZW5kb2JqCjc4IDAgb2JqCjw8IC9MZW5ndGggNzkgMCBSIC9O + IDMgL0FsdGVybmF0ZSAvRGV2aWNlUkdCIC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0 + cmVhbQp4Aa2Tz2vTYBzGn7RDh84Jc/MgCDk48FCltAV/INi160Y36UrbrdVbm6RNtUlD + klZbPPQfELwJ6kHxssP0rHhRBPHiQSaieBXx4mWHMRgjPklM68HhxW9583765Hm/75vv + +75AeKdqGK0QAE23zcJiSqxcvSYe/IIJHOIvgZmqZBlz+fwVWvaJ7U8Q3FebZ9xc941d + nLu7mdh+1Pt+6enFw/sMCuRJkxMCQoTCdMPnpMs1n0su37QNmx7VZUmtyuTb5IhZKqTJ + 6+TJhs/PXa75/M7lrtRwx34mR3W5qQOhcfJ5WbEkcpKsypakkZlHCGlam/nDG9RPS4bJ + seGP5FNuXdgzekeBy/fofz3SKm+BjWfA8Z8jbZbeY1+BF92RtrXj1Uo4+c2qx2NeOuHI + Y+BA33G2ZoBxzr235ji7KcfZ49xjTPLyjtQxu56XCxTeA//673+znx34wDwMb4/+zn5d + PFcUeDIA1l4BSxQess3yW6ceACtJoDhAKB4Pml9DWljnoqQYtqmIlViivOhJ/++htTrc + Ky+m+JzQa7kV9ifYfhh2vhSw1S1mAq43F7IBy9X55YD7ajoXcN1cKAR8vbqUD1jRV4sB + Gy3v7P+eKzX0K1Zm6OmrpXLgNzuF1YBvtJeHflmZH65Nb+Xc++TlbNrZ4fpRhAQFBmyY + 7EVUEOMdLIMF9c8lRyE3zeM4Rsi8WdcGrvJn2Motb7/TbaNnNhuqLc7xVioRMatLZyNi + LBq9gF9qSrI3CmVuZHN0cmVhbQplbmRvYmoKNzkgMCBvYmoKNTY1CmVuZG9iago1OSAw + IG9iagpbIC9JQ0NCYXNlZCA3OCAwIFIgXQplbmRvYmoKODAgMCBvYmoKPDwgL0xlbmd0 + aCA4MSAwIFIgL04gMyAvQWx0ZXJuYXRlIC9EZXZpY2VSR0IgL0ZpbHRlciAvRmxhdGVE + ZWNvZGUgPj4Kc3RyZWFtCngBrZPPa9NgHMaftEOHzglz8yAIOTjwUKW0BX8g2LXrRjfp + Stut1VubpE21SUOSVls89B8QvAnqQfGyw/SseFEE8eJBJqJ4FfHiZYcxGCM+SUzrweHF + b3nzfvrkeb/vm+/7vkB4p2oYrRAATbfNwmJKrFy9Jh78ggkc4i+BmapkGXP5/BVa9ont + TxDcV5tn3Fz3jV2cu7uZ2H7U+37p6cXD+wwK5EmTEwJChMJ0w+ekyzWfSy7ftA2bHtVl + Sa3K5NvkiFkqpMnr5MmGz89drvn8zuWu1HDHfiZHdbmpA6Fx8nlZsSRykqzKlqSRmUcI + aVqb+cMb1E9Lhsmx4Y/kU25d2DN6R4HL9+h/PdIqb4GNZ8DxnyNtlt5jX4EX3ZG2tePV + Sjj5zarHY1464chj4EDfcbZmgHHOvbfmOLspx9nj3GNM8vKO1DG7npcLFN4D//rvf7Of + HfjAPAxvj/7Ofl08VxR4MgDWXgFLFB6yzfJbpx4AK0mgOEAoHg+aX0NaWOeipBi2qYiV + WKK86En/76G1OtwrL6b4nNBruRX2J9h+GHa+FLDVLWYCrjcXsgHL1fnlgPtqOhdw3Vwo + BHy9upQPWNFXiwEbLe/s/54rNfQrVmbo6aulcuA3O4XVgG+0l4d+WZkfrk1v5dz75OVs + 2tnh+lGEBAUGbJjsRVQQ4x0sgwX1zyVHITfN4zhGyLxZ1wau8mfYyi1vv9Nto2c2G6ot + zvFWKhExq0tnI2IsGr2AX2pKsjcKZW5kc3RyZWFtCmVuZG9iago4MSAwIG9iago1NjUK + ZW5kb2JqCjU0IDAgb2JqClsgL0lDQ0Jhc2VkIDgwIDAgUiBdCmVuZG9iago4MiAwIG9i + ago8PCAvTGVuZ3RoIDgzIDAgUiAvTiAzIC9BbHRlcm5hdGUgL0RldmljZVJHQiAvRmls + dGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAGtk89r02Acxp+0Q4fOCXPzIAg5OPBQ + pbQFfyDYtetGN+lK263VW5ukTbVJQ5JWWzz0HxC8CepB8bLD9Kx4UQTx4kEmongV8eJl + hzEYIz5JTOvB4cVvefN++uR5v++b7/u+QHinahitEABNt83CYkqsXL0mHvyCCRziL4GZ + qmQZc/n8FVr2ie1PENxXm2fcXPeNXZy7u5nYftT7funpxcP7DArkSZMTAkKEwnTD56TL + NZ9LLt+0DZse1WVJrcrk2+SIWSqkyevkyYbPz12u+fzO5a7UcMd+Jkd1uakDoXHyeVmx + JHKSrMqWpJGZRwhpWpv5wxvUT0uGybHhj+RTbl3YM3pHgcv36H890ipvgY1nwPGfI22W + 3mNfgRfdkba149VKOPnNqsdjXjrhyGPgQN9xtmaAcc69t+Y4uynH2ePcY0zy8o7UMbue + lwsU3gP/+u9/s58d+MA8DG+P/s5+XTxXFHgyANZeAUsUHrLN8lunHgArSaA4QCgeD5pf + Q1pY56KkGLapiJVYorzoSf/vobU63Csvpvic0Gu5FfYn2H4Ydr4UsNUtZgKuNxeyAcvV + +eWA+2o6F3DdXCgEfL26lA9Y0VeLARst7+z/nis19CtWZujpq6Vy4Dc7hdWAb7SXh35Z + mR+uTW/l3Pvk5Wza2eH6UYQEBQZsmOxFVBDjHSyDBfXPJUchN83jOEbIvFnXBq7yZ9jK + LW+/022jZzYbqi3O8VYqETGrS2cjYiwavYBfakqyNwplbmRzdHJlYW0KZW5kb2JqCjgz + IDAgb2JqCjU2NQplbmRvYmoKNjIgMCBvYmoKWyAvSUNDQmFzZWQgODIgMCBSIF0KZW5k + b2JqCjg0IDAgb2JqCjw8IC9MZW5ndGggODUgMCBSIC9OIDMgL0FsdGVybmF0ZSAvRGV2 + aWNlUkdCIC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Aa2Tz2vTYBzGn7RD + h84Jc/MgCDk48FCltAV/INi160Y36UrbrdVbm6RNtUlDklZbPPQfELwJ6kHxssP0rHhR + BPHiQSaieBXx4mWHMRgjPklM68HhxW9583765Hm/75vv+75AeKdqGK0QAE23zcJiSqxc + vSYe/IIJHOIvgZmqZBlz+fwVWvaJ7U8Q3FebZ9xc941dnLu7mdh+1Pt+6enFw/sMCuRJ + kxMCQoTCdMPnpMs1n0su37QNmx7VZUmtyuTb5IhZKqTJ6+TJhs/PXa75/M7lrtRwx34m + R3W5qQOhcfJ5WbEkcpKsypakkZlHCGlam/nDG9RPS4bJseGP5FNuXdgzekeBy/fofz3S + Km+BjWfA8Z8jbZbeY1+BF92RtrXj1Uo4+c2qx2NeOuHIY+BA33G2ZoBxzr235ji7KcfZ + 49xjTPLyjtQxu56XCxTeA//673+znx34wDwMb4/+zn5dPFcUeDIA1l4BSxQess3yW6ce + ACtJoDhAKB4Pml9DWljnoqQYtqmIlViivOhJ/++htTrcKy+m+JzQa7kV9ifYfhh2vhSw + 1S1mAq43F7IBy9X55YD7ajoXcN1cKAR8vbqUD1jRV4sBGy3v7P+eKzX0K1Zm6OmrpXLg + NzuF1YBvtJeHflmZH65Nb+Xc++TlbNrZ4fpRhAQFBmyY7EVUEOMdLIMF9c8lRyE3zeM4 + Rsi8WdcGrvJn2Motb7/TbaNnNhuqLc7xVioRMatLZyNiLBq9gF9qSrI3CmVuZHN0cmVh + bQplbmRvYmoKODUgMCBvYmoKNTY1CmVuZG9iago0NiAwIG9iagpbIC9JQ0NCYXNlZCA4 + NCAwIFIgXQplbmRvYmoKODYgMCBvYmoKPDwgL0xlbmd0aCA4NyAwIFIgL04gMyAvQWx0 + ZXJuYXRlIC9EZXZpY2VSR0IgL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB + rZPPa9NgHMaftEOHzglz8yAIOTjwUKW0BX8g2LXrRjfpStut1VubpE21SUOSVls89B8Q + vAnqQfGyw/SseFEE8eJBJqJ4FfHiZYcxGCM+SUzrweHFb3nzfvrkeb/vm+/7vkB4p2oY + rRAATbfNwmJKrFy9Jh78ggkc4i+BmapkGXP5/BVa9ontTxDcV5tn3Fz3jV2cu7uZ2H7U + +37p6cXD+wwK5EmTEwJChMJ0w+ekyzWfSy7ftA2bHtVlSa3K5NvkiFkqpMnr5MmGz89d + rvn8zuWu1HDHfiZHdbmpA6Fx8nlZsSRykqzKlqSRmUcIaVqb+cMb1E9Lhsmx4Y/kU25d + 2DN6R4HL9+h/PdIqb4GNZ8DxnyNtlt5jX4EX3ZG2tePVSjj5zarHY1464chj4EDfcbZm + gHHOvbfmOLspx9nj3GNM8vKO1DG7npcLFN4D//rvf7OfHfjAPAxvj/7Ofl08VxR4MgDW + XgFLFB6yzfJbpx4AK0mgOEAoHg+aX0NaWOeipBi2qYiVWKK86En/76G1OtwrL6b4nNBr + uRX2J9h+GHa+FLDVLWYCrjcXsgHL1fnlgPtqOhdw3VwoBHy9upQPWNFXiwEbLe/s/54r + NfQrVmbo6aulcuA3O4XVgG+0l4d+WZkfrk1v5dz75OVs2tnh+lGEBAUGbJjsRVQQ4x0s + gwX1zyVHITfN4zhGyLxZ1wau8mfYyi1vv9Nto2c2G6otzvFWKhExq0tnI2IsGr2AX2pK + sjcKZW5kc3RyZWFtCmVuZG9iago4NyAwIG9iago1NjUKZW5kb2JqCjQ5IDAgb2JqClsg + L0lDQ0Jhc2VkIDg2IDAgUiBdCmVuZG9iago4OCAwIG9iago8PCAvTGVuZ3RoIDg5IDAg + UiAvTiAzIC9BbHRlcm5hdGUgL0RldmljZVJHQiAvRmlsdGVyIC9GbGF0ZURlY29kZSA+ + PgpzdHJlYW0KeAGFlE1IFGEYx/+zjQSxBtGXCMXQwSRUJgtSAtP1K1O2ZdVMCWKdfXed + HGenmd0tRSKE6Jh1jC5WRIeITuGhQ6c6RASZdYmgo0UQBV4itv87k7tjVL4wM795nv/7 + fL3DAFWPUo5jRTRgys67yd6Ydnp0TNv8GlWoRhRcKcNzOhKJAZ+plc/1a/UtFGlZapSx + 1vs2fKt2mRBQNCp3ZAM+LHk84OOSL+SdPDVnJBsTqTTZITe4Q8lO8i3y1myIx0OcFp4B + VLVTkzMcl3EiO8gtRSMrYz4g63batMnvpT3tGVPUsN/INzkL2rjy/UDbHmDTi4ptzAMe + 3AN211Vs9TXAzhFg8VDF9j3pz0fZ9crLHGr2wynRGGv6UCp9rwM23wB+Xi+VftwulX7e + YQ7W8dQyCm7R17Iw5SUQ1BvsZvzkGv2Lg558VQuwwDmObAH6rwA3PwL7HwLbHwOJamCo + FZHLbDe48uIi5wJ05pxp18xO5LVmXT+idfBohdZnG00NWsqyNN/laa7whFsU6SZMWQXO + 2V/beI8Ke3iQT/YXuSS87t+szKVTXZwlmtjWp7To6iY3kO9nzJ4+cj2v9xm3Zzhg5YCZ + 7xsKOHLKtuI8F6mJ1Njj8ZNkxldUJx+T85A85xUHZUzffi51IkGupT05meuXml3c2z4z + McQzkqxYMxOd8d/8xi0kZd591Nx1LP+bZ22RZxiFBQETNu82NCTRixga4cBFDhl6TCpM + WqVf0GrCw+RflRYS5V0WFb1Y4Z4Vf895FLhbxj+FWBxzDeUImv5O/6Iv6wv6Xf3zfG2h + vuKZc8+axqtrXxlXZpbVyLhBjTK+rCmIb7DaDnotZGmd4hX05JX1jeHqMvZ8bdmjyRzi + anw11KUIZWrEOOPJrmX3RbLFN+HnW8v2r+lR+3z2SU0l17K6eGYp+nw2XA1r/7OrYNKy + q/DkjZAuPGuh7lUPqn1qi9oKTT2mtqttahffjqoD5R3DnJWJC6zbZfUp9mBjmt7KSVdm + i+Dfwi+G/6VeYQvXNDT5D024uYxpCd8R3DZwh5T/w1+zAw3eCmVuZHN0cmVhbQplbmRv + YmoKODkgMCBvYmoKNzkyCmVuZG9iago4IDAgb2JqClsgL0lDQ0Jhc2VkIDg4IDAgUiBd + CmVuZG9iago5MCAwIG9iago8PCAvTGVuZ3RoIDkxIDAgUiAvTiAzIC9BbHRlcm5hdGUg + L0RldmljZVJHQiAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAGtk89r02Ac + xp+0Q4fOCXPzIAg5OPBQpbQFfyDYtetGN+lK263VW5ukTbVJQ5JWWzz0HxC8CepB8bLD + 9Kx4UQTx4kEmongV8eJlhzEYIz5JTOvB4cVvefN++uR5v++b7/u+QHinahitEABNt83C + YkqsXL0mHvyCCRziL4GZqmQZc/n8FVr2ie1PENxXm2fcXPeNXZy7u5nYftT7funpxcP7 + DArkSZMTAkKEwnTD56TLNZ9LLt+0DZse1WVJrcrk2+SIWSqkyevkyYbPz12u+fzO5a7U + cMd+Jkd1uakDoXHyeVmxJHKSrMqWpJGZRwhpWpv5wxvUT0uGybHhj+RTbl3YM3pHgcv3 + 6H890ipvgY1nwPGfI22W3mNfgRfdkba149VKOPnNqsdjXjrhyGPgQN9xtmaAcc69t+Y4 + uynH2ePcY0zy8o7UMbuelwsU3gP/+u9/s58d+MA8DG+P/s5+XTxXFHgyANZeAUsUHrLN + 8lunHgArSaA4QCgeD5pfQ1pY56KkGLapiJVYorzoSf/vobU63Csvpvic0Gu5FfYn2H4Y + dr4UsNUtZgKuNxeyAcvV+eWA+2o6F3DdXCgEfL26lA9Y0VeLARst7+z/nis19CtWZujp + q6Vy4Dc7hdWAb7SXh35ZmR+uTW/l3Pvk5Wza2eH6UYQEBQZsmOxFVBDjHSyDBfXPJUch + N83jOEbIvFnXBq7yZ9jKLW+/022jZzYbqi3O8VYqETGrS2cjYiwavYBfakqyNwplbmRz + dHJlYW0KZW5kb2JqCjkxIDAgb2JqCjU2NQplbmRvYmoKNjkgMCBvYmoKWyAvSUNDQmFz + ZWQgOTAgMCBSIF0KZW5kb2JqCjkyIDAgb2JqCjw8IC9MZW5ndGggOTMgMCBSIC9OIDMg + L0FsdGVybmF0ZSAvRGV2aWNlUkdCIC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVh + bQp4Aa2Tz2vTYBzGn7RDh84Jc/MgCDk48FCltAV/INi160Y36UrbrdVbm6RNtUlDklZb + PPQfELwJ6kHxssP0rHhRBPHiQSaieBXx4mWHMRgjPklM68HhxW9583765Hm/75vv+75A + eKdqGK0QAE23zcJiSqxcvSYe/IIJHOIvgZmqZBlz+fwVWvaJ7U8Q3FebZ9xc941dnLu7 + mdh+1Pt+6enFw/sMCuRJkxMCQoTCdMPnpMs1n0su37QNmx7VZUmtyuTb5IhZKqTJ6+TJ + hs/PXa75/M7lrtRwx34mR3W5qQOhcfJ5WbEkcpKsypakkZlHCGlam/nDG9RPS4bJseGP + 5FNuXdgzekeBy/fofz3SKm+BjWfA8Z8jbZbeY1+BF92RtrXj1Uo4+c2qx2NeOuHIY+BA + 33G2ZoBxzr235ji7KcfZ49xjTPLyjtQxu56XCxTeA//673+znx34wDwMb4/+zn5dPFcU + eDIA1l4BSxQess3yW6ceACtJoDhAKB4Pml9DWljnoqQYtqmIlViivOhJ/++htTrcKy+m + +JzQa7kV9ifYfhh2vhSw1S1mAq43F7IBy9X55YD7ajoXcN1cKAR8vbqUD1jRV4sBGy3v + 7P+eKzX0K1Zm6OmrpXLgNzuF1YBvtJeHflmZH65Nb+Xc++TlbNrZ4fpRhAQFBmyY7EVU + EOMdLIMF9c8lRyE3zeM4Rsi8WdcGrvJn2Motb7/TbaNnNhuqLc7xVioRMatLZyNiLBq9 + gF9qSrI3CmVuZHN0cmVhbQplbmRvYmoKOTMgMCBvYmoKNTY1CmVuZG9iago0MCAwIG9i + agpbIC9JQ0NCYXNlZCA5MiAwIFIgXQplbmRvYmoKOTQgMCBvYmoKPDwgL0xlbmd0aCA5 + NSAwIFIgL04gMSAvQWx0ZXJuYXRlIC9EZXZpY2VHcmF5IC9GaWx0ZXIgL0ZsYXRlRGVj + b2RlID4+CnN0cmVhbQp4AYVST0gUURz+zTYShIhBhXiIdwoJlSmsrKDadnVZlW1bldKi + GGffuqOzM9Ob2TXFkwRdojx1D6JjdOzQoZuXosCsS9cgqSAIPHXo+83s6iiEb3k73/v9 + /X7fe0RtnabvOylBVHNDlSulp25OTYuDHylFHdROWKYV+OlicYyx67mSv7vX1mfS2LLe + x7V2+/Y9tZVlYCHqLba3EPohkWYAH5mfKGWAs8Adlq/YPgE8WA6sGvAjogMPmrkw09Gc + dKWyLZFT5qIoKq9iO0mu+/m5xr6LtYmD/lyPZtaOvbPqqtFM1LT3RKG8D65EGc9fVPZs + NRSnDeOcSEMaKfKu1d8rTMcRkSsQSgZSNWS5n2pOnXXgdRi7XbqT4/j2EKU+yWCoibXp + spkdhX0AdirL7BDwBejxsmIP54F7Yf9bUcOTwCdhP2SHedatH/YXrlPge4Q9NeDOFK7F + 8dqKH14tAUP3VCNojHNNxNPXOXOkiO8x1BmY90Y5pgsxd5aqEzeAO2EfWapmCrFd+67q + Je57AnfT4zvRmzkLXKAcSXKxFdkU0DwJWBR9i7BJDjw+zh5V4HeomMAcuYnczSj3HtUR + G2ejUoFWeo1Xxk/jufHF+GVsGM+Afqx213t8/+njFXXXtj48+Y163DmuvZ0bVWFWcWUL + 3f/HMoSP2Sc5psHToVlYa9h25A+azEywDCjEfwU+l/qSE1Xc1e7tuEUSzFA+LGwluktU + binU6j2DSqwcK9gAdnCSxCxaHLhTa7o5eHfYInpt+U1XsuuG/vr2evva8h5tyqgpKBPN + s0RmlLFbo+TdeNv9ZpERnzg6vue9ilrJ/klFED+FOVoq8hRV9FZQ1sRvZw5+G7Z+XD+l + 5/VB/TwJPa2f0a/ooxG+DHRJz8JzUR+jSfCwaSHiEqCKgzPUTlRjjQPiKfHytFtkkf0P + QBn9ZgplbmRzdHJlYW0KZW5kb2JqCjk1IDAgb2JqCjcwNAplbmRvYmoKMzcgMCBvYmoK + WyAvSUNDQmFzZWQgOTQgMCBSIF0KZW5kb2JqCjQgMCBvYmoKPDwgL1R5cGUgL1BhZ2Vz + IC9NZWRpYUJveCBbMCAwIDYxMiA3OTJdIC9Db3VudCAxIC9LaWRzIFsgMyAwIFIgXSA+ + PgplbmRvYmoKOTYgMCBvYmoKPDwgL1R5cGUgL0NhdGFsb2cgL091dGxpbmVzIDIgMCBS + IC9QYWdlcyA0IDAgUiAvVmVyc2lvbiAvMS40ID4+CmVuZG9iagoyIDAgb2JqCjw8IC9M + YXN0IDk3IDAgUiAvRmlyc3QgOTggMCBSID4+CmVuZG9iago5OCAwIG9iago8PCAvQ291 + bnQgMCAvRGVzdCBbIDMgMCBSIC9YWVogMCA3MzMgMCBdIC9UaXRsZSAoQ2FudmFzIDEp + ID4+CmVuZG9iago5NyAwIG9iago8PCAvQ291bnQgMCAvRGVzdCBbIDMgMCBSIC9YWVog + MCA3MzMgMCBdIC9UaXRsZSAoQ2FudmFzIDEpID4+CmVuZG9iago5OSAwIG9iago8PCAv + TGVuZ3RoIDEwMCAwIFIgL0xlbmd0aDEgMTU3MDQgL0ZpbHRlciAvRmxhdGVEZWNvZGUg + Pj4Kc3RyZWFtCngBvXt5YFXFufjMnPWeu+/7lpu7Zd8XEsglJIRdFoUEiYZ9UWQRA1jg + RWWNiAqyCIjgwhLUhBAlSLHUgoi1CiqoqLVWoHRJbfvQ10Luzfvm3IDQ9vXnH/31njtz + 5szMmeX7vvm2mYMwQkiFmhCDYpNnT5zbv+Tu+yDnXYSwYXLjAt9jv+23A9K/Qoi5d9rc + 6bP1v/rZOwhxwxCSVNPvXTxtd48V6mprEQq/PWPqxCn/fem+nQgV+6CNohmQIaUIULcY + ylHqjNkLFn3xoWkePC+B59P3zpk88cpff/cGQiVQB82aPXHRXHGL9Dd47oRn330TZ0+t + b1y8GJ4/geeUuXPuX8C1chfguRuem+fOnzr3x4/cl4tQ6WoY3/uQh+GiPxUkeTn1L6Nk + 5WQVghiWg3cEJCokhJTQhhppkFanNyBkRMhktiArstkdTtf3bbqRx+vzpwRSUTAUjkTT + UHpGZhbKzsnN+77O/7dU/g9omTuGdNxRFOGakIPNRl6Eej6FcJ7eE3f0XOJOIl1ids+f + mTJo7DANJFFRjo6hx9A21Ip4tBfSEXQX2oJO4VnoMJ6AOtA57EFZQDMs6kTD0Lu4p+cM + moZegPoL0JtoIzoAsIug2cgMpetwsOdBeI5BehJa3vMcSkUlaCU6ikqh1XWoq2dfz0Eo + HY3uQC1oP7z/cxwgB1hjzys9F5CIRkGby6HkTM+wnlZkQBmoEo2E3OXoDRxkzvfMQDZU + BqPbjp5Fu9BP0R/ww7ijZ0ZPY8/pnq8QgVIXGgPXUtyBv2Ja2ZU923t+15MASERQGvTa + gDag56H9VriOAflU43vwArwBbyQx8jDpYFdw1kQc4BBFNXANQnPQaoDAYXQc/QX9DX9D + bIyOWcCc6Cns+W+gmaEwSzqTqagRrlVwrYM5HcE8zsED8Ei8FD+FN+IPSRq5g9SShWQR + ucSMYCYwi5kP2fvZdm4tt4VXJr7tOdJzsucskJsb3Ynmo2UwuzfRaXQFXcUMtOXCQVyG + K/FdcDXhbeQw3oUPk5H4GD5NWvCX+Gv8Db5GOKIiZpJOFpANZD95k7zHzGQ2Mk8zXzLf + sv04wu3iLvJB4bPEpMSaxHs9ZT1f9fwVuICI/ICZSjQC3Y0mwmznogL0XzCLl+FqBawd + RyfQKfn6GrtQF/orQAF4BXbgPDwcrhH4NjwNz8Q78OtwvSGP5TsCiCAKoidW4iJjyCQy + mzSRs6SJcTJpzBBmPNMK19vMOeYac43lWCNrZmvYwWgtO5vdCtdudi/bzr7PlXL9uBHc + WK6JW8OtZSZzZ7hz/DJ+Hd/Of8P/SYgIw4Q5wlrAzimg2Z/esjhYnAqjz0P3ocm4Ck9C + mwAbu/BE1AzUNQWvBnjNRZGeemYZU0NygBreQD8Cat2KlqI1zAS0q+cTpgV9DJRyL7Ta + hPawlcjNbQbsPIxygIp6r1g0LRoJh4KpgRS/z+txu5wOu81qMZuMBr1OrVJKClHgOZYh + GGVUBwY2+NpCDW1sKDBoUCZ9DkyEjIk3ZTS0+SBr4K112nz0vYlQdEvNGNSc9nc1Y8ma + sRs1sc5XjsozM3zVAV/bL6oCvk48flQtpB+rCtT52rrk9HA5/YScVkPa74cXfNW2GVW+ + Ntzgq24b2DijubqhKjMDH44BOKTMDMo4YkhJG25DAyYunWGDG61R3eYIVFW32QOQhjIm + WD1xStvIUbXVVU6/vw7yIGt0LfSRmTGzDcaJHlVNCUx5tDOGJjXQ1MQJtW3MxLo20kDb + 0qe3WQNVbdYHL9q+f7yeql57U2EbCQ6cOLV5YFus4VEALn1soE8T18LT0DE+aJasqKtt + wyt6B0HHOAtGSoc7NVBNx9Uwy9emCFQGZjTPagDgotG17Y6YozowsaquDY2sbbfH7PJD + ZsZh27IyP8z+cGb/zP70Xua3LUvef/NIMv+DY/RuW3b8V3AfOvoGADDtKTAYxtnmmyx3 + EoDBltBoaglqnlwCcIJfHYZpzoTxDGgjQDNMsI0LDp7Y1jTm+jBmVCUH1zCrql1hd9A5 + NFTWQf2GZl0fwBTU1wV8zd8iQGGg6w+35kzszeGDum8RLaSIvkErbXji9XSjDBiY9Qxb + YAbFb6OMU3gO2KpvyoBnCho65jZTW97QkbX+Nl8dZHSCfBzaiRQjaw9gvK6uE/es6ERV + 7sNIgZi774LiDEpqM6ugf3jIzICMND+ksjJ8A2HWAymt+Jp9zYOnNPsG+mYAMbFB+Q4F + U5vrsgGCY2oBTuh26DFW57yRnFpX1wfayabtwCtQvbkOWpjV2wLc5azsOFTKyRgKWAmN + rB1V29ZU5WyLVdUBFoB8j42sbTsGlFtXB7Vyb4wURrx0pq13zHkw5tw0KM9PtjIG2oAm + 6pqbaZtjagP+tmPNzc5mut6Sz50Y/X1GrDejE9EqMPHqTtw0Et6FW8DvpBkBf8APw6qj + MC0Akr5OUZ2o8F9DuOjGuOHNYhhtkQzhkn8ThEt/CIT7/CAIl90Y6S0QLocxl1EI9/3P + QbjfLRCu+NcQjt0YNwyyP4w2JkO48t8E4QE/BMJVPwjC1TdGeguEB8KYqymEa/5zEB50 + C4QH/2sID7kxbhjkUBjtEBnCw/5NEB7+QyA84gdB+LYbI70FwiNhzLdRCI/6z0F49C0Q + HvOvIXz7jXHDIO+A0d4uQ3jsvwnC434IhGt/EITrboz0FgiPhzHXUQjf+Z+D8ISbIAwK + byVC7GmwvRgwKSs60Zj0TiRmg/CDIOrAwD0NgT5Dmvm8E7EQEKSFz9Hr8AZCY9Nfh1Y4 + uOfk5uv9+jCESnZdZ/evuaNXB3Syw68dhFoYtSRO4yZ0HmzVzJgFBTTSFFHSWa0OoUCa + gkS7dvJUW/oI3ZXh5fGuEdVTqy6hiuFdH3Xl5liLiosKC0LhQGG+2cQLLdUuLSazzzU0 + nlHdkZkmKIXz7yzsMEMX0EcrRLQPBoViRpzGSBx0gKcgO8tN8dMO0kdcGR6/0XxuTnG+ + OdB65sx5MDTp+/Ajs2RYpMesArbizWDIEOIyMAwijIRhoow92/YRqiivKOdWZaUv1R3H + 9TgfB/AHWxJZW+iMoQkU6/mUdXFbkBasunkx6yoODxTNhVrOVSioDSXMHFuJ0lPj1jUe + t33UFe9CFV0VMNEBi2MFyKkO4aAjpAhyIYvGFkEmZIhgpwgpHQ8pq8ocwUYCkV1yRZCe + hSgdfphG8u8hVI+sFr1OIH5fOKQvKDb4DUX6AhJIIXqT1ZLPxJY0jFuW+HUisWxmRSMu + bN696OVnN2QPeoXbcvFA4t3E5z9J/PFXR3DZlVY88OrFv+LRV3BZ4mzii89W/DwJo+Mw + wbPcerDAAgdE3InzYyqWFVSssIlDUo2CTur42Xgpqqi48ovcHGNhP1ycrw/oj/9sa2jd + Mea7ZmPd7qv3Md9RUIPNhthsbjuk1GhCLEVBJFEN8H7DwPMC4TEniGBHChJ5QMl9w6gE + lunE1lfxJrX4ktSJaw9y2hqNDMRvr5THL9Aey+Pl+tJSrDeUwr8UEMQu1Z3Q5uZgvQLr + /YU4Xw8I15MXE4X4vfha8sSWDz8EE3RNfGGCw3e1Meu6734m8ZxMBmh4z2dsgNuBnCiM + 9sVKFzqwVQyKYXutfSVahVcrhBpR8of9hRqNiTkpFDq5cKFJzUTJQ54S/RyrRMql1Fxr + tCYiDzBeumTo6EUPZtt033ZdSSK8y1Ca3QWjTCI+GHL5tBbEcyGf1hPBIXNqBLmMkOIR + E8Es49X5IzhoCUeQ2wARi4WIjHOsK0+i/aGHHsL1gHuLORAKhwDbDKyb/DzWbALUI71O + pgNYR4EU3mwCMqg52q4L9F++uV3qd9fYWR1Ylfj9qcTn/ZfiYQ89tmz3gtZnH+N2/G35 + HTnjE79NdN+ZGbl04WeJD3EumMzK1/GUq1/85OH7Tm7dtpr6YjD4Eygem4Dex8SKOKWd + lCj7qErVQ9R3kLHsJHJIkJaoO9Qn1AxRYLWmD9KyChVRiwjN0Yglipc0+hqdDKYrXbqL + FHGASsBkqaEU1+fm1GMzTwQeroDBWFTsL2Szqy/Wjst0Z52surxmc/dlrumZAYmOY0e2 + Tv4cb8Wb/vjyq+BmQ5U9H7MOoC0l+Cfy0M9jNWPxOMV4bZ1xCp6quEc707gwqBis+5G9 + MTA/eH94Se6SvNX2Vb5V4dVZq3O32NU1Yp4Y1JBgnrJQr8/gCj2ctTBDTUpAuV15SFMS + nZMtljgh/aqpJLugJl8ePqD2e/xS9CZJsRfHhWlZLp/BwqgtmaYIUqVrIlgyiBHEuyFi + vSSCzVnWCFKnQSS4uAhmfBDdtLwBxUkcU37Yi0fDTWkUDhUWAM7BlAdgWahJD7hPhbxi + 8sLKpkceXrBp2uoXW1Y89PzG7YlX0267fPa931WFRtbl3524fCbx5ZIHmdiKCSNXrhw/ + dX68bNXKR5/Y8PDc58nO9JFNOy99+uTKMdmZ0cIpO48m/vb1J/91GNyZBH0NPL2T9QPe + jag05kYBLXB1Y5qOFyWzzNoN0hQdMHfToiW9zB3Qep29A3/X/SOHh5HTNfr1QKcG49ln + vQUPnz17Rj0yLY8TVOffuWdQo5UbBdyaoAnol+wcpkiWW+GYGfvQLwQfzyKHQiB2UTHB + XzFa5vfluu/KUfbwrngc2IAZeAAEds61LtZ4rYsp2rs3MWb/ftredqBhK3ca2vOh7bGa + iGGQsdY4Vf2AmpupWqwiIVGrU5u1SoXNbFArWZ9uHJUvvnecqTw2aHN1XjyFYRQ+W4nC + keLN9dn9KR/6Jw9KSpyuEbrvhtO1nt11hXLGrq6K+CW9VeZTQO16g8wDHHYPK7qDLs7b + HzkEW3/sYZ39sV2ECIiArvaHgLnj+iCABxlkNPOCBpsDBUUVOCkkAyl0leCukycTrVfO + nugat7yhtL3q/pGplsgDq/bEUrn206fZU1j4qnXW8qb6h5Y93jrvtpRg/4GTnlhS/TDM + 3AM+874g/wiSYN2cj40chGvxDMysZjazW6R9UqeiU+IjIAcFnsdEVCggkpDA4bWYYX0m + SQoaIM/EcUHg4Fip5BiFxPIcVhIMAtQjiJ24LqYA1xKvkBgOnvbGDGo1UAq3A++Q7Cr1 + Lv/auwBm9hFXbMPjcbssqQdW2VCFFQTu8LjM3isoewfeUKovzZZF8FCwgNljzjb2eN2q + LBvIZJrBQAZzvC69t+4qXXm5AAFooB7YJFZiI0htxs8EMLPuy64VXxHz+Y3xI8++S54g + 46lAYCZfHYA7E4NkaIzvOc/N4y4i8KOjA7EyJ7cZb+IYL/ayD+NV3BojN0ZkVrr1ejPf + x82o+pgVHuLx2JlcUqbL1Tt8ily73evb5Z817WZ6uEIlAHA6EP6Q0CU1gD7IZQ0aQ5qg + M6S0KPKQ2qTLwwa9Vie44IlDTB7GhGUkmyoPaQ0QiQ4+D7MYIioHQBxQgZCMacZDQDAi + tgaysCwFgGyKi4rzgZnK2oGuuMgfYD24QP+m/0T7p4lv//zN5/f39bzpWN+a+LgHvXLx + pddxTYS7mDh/ZN3uxPuJE4lE4if76p68/MzRbb/AL+Hq07+W5fiLQDeTAVJq8GNPj3lX + 6TcZSJ6o9GgJ8lhFMdfocKiDGrvdcc7fuCYJg7i8JlBFvALWJag+IWzRB80hXuAEVmAE + InC8pBNhthaIFAZlHhZMwMflhZBG5xWkM6FkryMBv57x+0DrMQkkisnpqf0XDClzaD/9 + c+LZt8kYnL1nY+22xMp4a4s5PKfu0TE1WI+zrm3hjB+/mTjzu6OJdnkOoDuyXTAHuqMy + IpYqeFhWyXhA5VOIHkkpqohKRRA/k5QpHBpGDCK7WtOJlQf9G69PqJzO6MoFusyT8qui + nCIWpmf0m/363oBb2ezuDUx691lmybU3iZc72pGobEloWqFr+Mk6LNsCDwrgqDY6CkXv + KPh7sEMp9ywpO/E46PnzXlDKPVP95x86DLQy17rfJWfi2SfljlrjU2gfpyBaD30wyAq+ + LlDgqeqblQ77JFTVJ7AxZASd7dSpU7JCi2XeOBTqcyg3ZgRNmHhYTmQcAiZBDtl5oROP + OehvpCt3xBW6TEfoQH2niQqYPBgFZv/2k+Ry9yho7i+t0NlmhHgrtGcEuVxXhYcCQ8AK + xoLtzMeYM2IXY1I6VeNwLfMR/oz5SPmZSmIlVl1NVhJ2FNlMSFSKqEukEnUNGUcaiRCc + opYIYwBVXakyMLxIZQ/Lcp14W0wteRklH1dhEld7DZDzmhHZTY1zZXEEI7xgv1JaCn/b + BTrqpN1BeY3BWjp09OIDalUnbukgmFCQt7QTwqzihmc9GGeXHl/FJe+5Oah+/jw8v36e + 0a/AflB1C4oKwSAALcusD2zGbrwbP48dR9lE/YnEeO4N7ui1EHv+6gBmcubphdei7MeZ + RV8UdD8j0yDIIC5Nxr2EGmOmYlwCmg+YIWFcg2sJB/AmdFJWWT+myjERQdQykoR5EbAC + Za9yrENF+ey2mKRAdqVqp59O9gZevqNYoTwxSaQw0dJSFrjoqqUn6ERwPbBFPeAew3/7 + 78mlo1/GtW+QPjDo8ezuqwPYF6/dCeOj8pKul79CWgIbZWKscKZqpmGx6kEDO8hUa5ph + etDECqJHr9NJWKOlq0gSCW9QsQqTKZd1WLQKWEBmyz9ZQHE9gD65fnSweoDjyzqg0U/V + Gh5WegDUHLj584oKW8nG438698tE3kmmaVHl/YkFeO3KPdzRL95+qSe+gT3cx5tg5j9B + x9oBcF0kwzWMnooZBPVgPIirw7XcTG6KaREnWo7AxpcdObErVhnw+0INhnmGB0yMweM1 + ucyM32MxsSFDatCDFAqn4FGSkMsp+oJmb9DC5GpnOh1RMRQMS/ZI9Jx/Y5LHJ1cB8APQ + cD4Chb+8vCKenE5pr+CnEqweMJFORRKG2RTI82L8eVRx4wUP9mLQ4axm4N3ZmOr0MHem + Zu3z8/tOSzhOkr17Z78/e9LYcZzAKA1ZVyQVqxKmlD6YKDvJuOauf6bUk5DIrty74sv3 + 5gfmN524PTrQ5DeWj/32iVxnvBlg0tBzlv0OZFo27A0lYndFteFAKFSkKfTXhCaFHtQs + TFXcI9o01iCp08zQtKQwkqZPSmqKxLAu20pTdna6q4+JYfukK3KIpBH1qSneSE6O3ha0 + DhaDEUeeN6gfjILZ9ty8nf5ZvRwS1GOZ6cuCzwB2Gg03CUCK+ax4fv08WSAMj2TpvUgk + IRLKDPJgEzMZKB1lZsk3Lk1Mx26jNx05zbZ0bLfhTDYdKcLKdBxU4ixIC1GIPAYXFFog + ktVonU6WkFQu9ppNoFJRnQrgTAUjRYEM6sKCVGo6JS0psJesFhkXZhMbAKO6GGOPUDD5 + 6twJ7UOHPXfyZ6PWYsO13+ABR7S5d55v2zq+7PR7G0etTTzz+8Qft21jyHB8fumI9b5+ + Oxfl5wUzMwonHHor8eW3jRX3PzXp3jxfTnZK2fTjVz5Y++gfWSXlzX5YV8B3wbdSEHNg + 3oMEwooK4GjoGmGCHHuNt4tUSaK+EmrvXul1Z8j8VlZxgQWBinsqoX8noeeOtl79C6eB + xUrXQUvPp1w2tG1GFlQeC1i5MFeiYyREuD46hYWxWEyKoMphw0GT3Wrb6d+Y5BzDk2hL + yrWuinKwybDsS6AgA2Yh+xqYkB378YLyug/jd+a+M3hlYm1i7YrBZAB3tHvBzlk7X77r + WWZt98nEn9cnvsPSeqxlSmGuYP9zRTAeHj0eq3oC78Qkhm/HxILxIu4SJtPZGdxqlrFH + SBA8MCyiWiWHOcLwoE1yrChSPk+YHRzCO3i7sA6gYgewgOpYWgr/pPoIymM5qI9gS64a + DnwOFERg7DEQCBhOUsCeMOG5VSL4ceSIrkVUP2/efAWhTh2sA+a968v45Q/jvwUW6Ga/ + vgoTorBk0Oiez+XdXy3s65ejL2IlaTlY0oHccoXzB+lmKmbphFLRoFIwzjwhVeHWqdxl + 6SQrWnaojJTlpQUNOoETXeEUq6sTNwMq3F4h7M5SEnehslwoL3eZhGja3lRHP2fUNUQb + LrH37fdjvBmI4zDehJJiv3c5XYgfv44Z0CRB46DLiDKWrK6sLtkTYk36GCJFxeYUhO1B + XKT1I5vH6UcWn8mP/SmomPiRw231g20EEV0rvX6F5PKoT5WXR1+swVrwx/DmW8yNfjif + siw9eBXyoAsNaJrhUJjeqDlabMSa+SPurtvkn5E3e1LuGNzRz6x65MHHyvzSXu5/nj/a + +IA1qPLo0zJC9WkWRfF7SzYefX1z8/vjMwbvftLs4jVqV/Z0fK+YYcucMGZY2pi3tg0a + tCW+2ZXCMCtUfGUgNmjWq6s3vmDEFyh9w+kA5jQ7AjnAa7Mnlr3HjrfY9ootNmaIqN9m + YhgT73YIajdoF4LTadWFDZgJE73DLYWtdpe7EwsH/fOX9kIXWFX5cLDg/5mWXoDsYlBl + lkJIY9SFkvq5HZ5AP/fL+rnSog6Bfg6RwsaHqH7u/yf6uWzOIUtSOwewJiGYT0FHCnUo + XyDnvra26uYve2lIzur1cx+xt3r+dOSDq9jwkYsd0fbx5Ef2zt656/M1C8+ewPmX4GhD + Hw5gUNJznuni3gQ91o0WxvKKNTWacZo97D4nFxRNROsGe9ztFowScVuVXJYxSxfVGxxe + ZRjMT+8q//zKm6cfvwBaZRc1UfRgbSWtVJsLzh1hbFPC3FwQITsJIckphmCC8JcpxkBJ + oddJAd5IK9UoCum0UGGBIf+79buW7tr94Op9uHlMTt+Xn6t4ac7BxNVvfonvvvzxqZ// + 7PQ7pLjAM5S4r/bbOLkWZ179HR4H621Qz3nWwQ4GjyqcYsKq2OLN4tOOPV6G0xAtZzJr + DFqzKaaKmcSoAw9VvsacxG8xJ52fiJ8qznk/CVy2Xg4oT+pPGsgEkfOnarda3KmlvCBY + /G6XILktyqCw2bXHdcj1sYsNWrRghdsllaDXhLXuMOcIp2YJYbs9FP7Iv7s+CaD4BVmW + fRSXLVGQ5bAI628IM+DLuhvOvYEowHIMHGXBHMt7Q3qdQWfUmXQsrwqmOFND4G9wh7DH + rbAKIaQ0a0LgIgs4/JDFQSTagK7UOohkESavS1l4paWnPYTn1aN5YM9SPcFi9ntgJVLz + ToPBDcDLBh/Kl1WHFB50x45zJUUGXfc33BObH7s9x3RAuC139OL+o99O/A7bfo29ysiQ + l5fs5XCArbnnjlH3Dnnu+RP1RTVlT2aNdOmAF4LBjysToQcGPnywGX9OeSAGXCBi5T4A + D9vwWLrg5iU3g7WmUouaN0h2YM4atT5qNQgGrcarIZpuk91m7/ZPX9YLwfrS41S/090s + wCpkj5CBui5B9ckCkuHN1GULV2F+4auBig59qtVlV472tXe0b9zIVRZMIOQFgu94ZV33 + FGb7ur0yb+6bKGMuA614USacADsUG15kGiwOVtSKdYrVqn3Ove594d3ph53KmMhYUqKa + 41IKsF+Wj7rtksEtabOErCzOxWRZsjKjnCNHpQmr+4XCLnt2zk0L5EpXKaWA+IVvey0+ + 4L6wUmS0J5dKRiDi8Cj1qUFdKOAJhVDEAZFeqQF/mUalDrpTQjjsjAKfUBlA6CeZ7vfu + XNmPby3MB6OW96eEwvm9SorMWVP1wB4QOAF7uQYIYkyW3JVfuLt8buLUy3/QHFKH+z7y + fizEFG1Z+kriGhZex1Uv/NcbA4Mblrx5W0biDFvZLzBgVXfeu43nt704KFy+fuwXo0f+ + DxgrapyV2HWs/e6trx5tnbycZMp4Xg4Cj/IUC/h3M2DViFbBKobZsPEB4QFRNKqJETZg + 9G5eMKskdVQCDcIcRRbQIToxf9A/KclTrqvEVBuWOUoppp5RBCaHXvZVUyEC1hP1XvOQ + Wt4Ryx/38G/HZB725K6a+1oH92b881H+0ufrdsRHkecbi2u3nou/TemQwCk7hMtAMNM9 + rKKYS7jIAnHyjETVJqDbqMAAw1a0fD+S4/Hy4zfIDhyRspkaoI7H5Yfgx6ZdO8cdfVee + exPMndo5SpAoU+oI7iNiO4EFZuXHcdO5xfwiYRV3mDnFnIfdJo4XRUHBkOXkKSBKhpSC + OwxOa8Kyn20AqIkCHKvieIXIURcO6HkMLwm8xDvUsPMRRUpwgLX7Jx3GlqSEpwArB4Xm + ElVhwCatoJIdQ6CKDKgsPwXDzZZezy3VHdOJ5aLs2wJ2MB/gifMVsGQFfaDpZfzepcQ0 + fOBSon3zy6CM7ccnE3Pik4irOUFP0GK0BiLq82NQNAZY7N0zI1HY6WK5m0AG9nHSPE7a + 9IE1HR3J7S5oA+DPB9kaFEIrYmWCKGh4rVW0aqzasBgGFjrIPlY5XakKBCWHO2CXCGsN + +t1Wt5oXEO90BRmjFAFE6aOmTozbHVEQxDgGMiYrCIvDHo50YvXNRHRBdwXcqL2DAVsd + FN8u4LXX3alJijL3UpT1unYChNVLVzdRWHusoG5e04iM1PLnpn4yIu3IPcNnPX3IEZ07 + bU8Hm73lttS+FakDx47Zfvu6eDG5fM/IdbvjT5Ijs/OG7nifUp5Md0wX8Bk7aBx3xXIP + 8Sd5wvImPmxq5BcInElFTDadm4Np2pSSQ3A4kCqqcLhwli1qR3YnqH63LI+kSElqczCv + LrqVlVwi1C433zQVukaAx4P3F+z05fuHtcy4MDLjkDtnWSw6pCTT2YH3wPjvGv3suOfo + WplUPkVtqSycNzP+PgwWMF0G+5N+0JNU4K+zoydi+VvETbqnLS+ye8Xdun2WTvFt8WP2 + oua3JlUfkXfbBJXboLQLdruZhLUOpyJshuPFnVgB2lKvNLzVQki6MjOQlQ0pjQqQXHoS + woIVUpwaUpJJFUJYB5FoAeWI0UBEbTI5SgelKNUgG8PJnSoDbF4RP2gOskL0qxU5w15/ + cdOm5+Fwb3fif75IdGPDb/gFWLt7011Pdbfvv8CcT/whcSURT7yC07tBYY1RnagxcQcb + hKlrUApaEMvYJ+6xkojoc+k1vNssaHmN26VM0ZCwzZEqZemy/NEUrT2Qusp/NDk9WIgX + kriRBTxFTO+ejsviRJwjxIaQEybGWSDCdk0IMVZ5TvKMqIWZmjTvZXYNtibOT9InHLik + chrUZX2AvLUnOPD1I9VBiBNZrUWxO3/0WuLQgq2LR+eUdSz+8IOmCQeOTNm6ZNxu5sC6 + wZFy2JaLJ57bdHehZ3D8i951TNbDGtSj22KhMBNSFzM1LKsRdUSj0CtUYZGSoV4SHUZM + dT5kNxg7cTUsrKQ4pnOU3XYVwyuOx49TFxE1HnpXEyW9G/JYH1iz3/zCPZzNrXPqVq+H + pXK4aBth3mBI6/z4FrouYO+NeY0dCrI3G2fFHi9RbOE2GZ42bTFvSeMjqcFwkX+gvya1 + Jjw2dVx4Wur00GLVYvViTWNgQeqC4ILQbs/eDCMDqhCXyWYZkcPstLps5kxTVkSrnAme + lqIgCaaoJTbdaHvL5TYKrDtra7oyW1BodERA2f5sh9dmsYWt/SIhIRxx5Gq8YV0/FM6y + 5+S239Df6E6MLL9LdZCi0y3NhrjXI0EtKcpSkq6IYTiThMzggvBrvH6kCAl+DF4IP/jq + IOU2QJ7TZPNjnzbFj/wpGrUYlvw4FFRI4JXwIz4KkUfv8lNPRNK6SjroZS99kugp+QOZ + UP+bLOZvdkWAKmS1CP/oiwDCCYXxN2Kwau+ULX3D9z++pv+Czw7/5Z4BpIUL9Xt62szq + yIiFb1bO/PSX35wU8CE8cnzOuHF3VqeC5puSNvihLT9eN35G37yaEbGBaXajOzuj+qnH + T3+6k/wN+Lm15xui4MYDdxj9qjpLOqaBff6KWJC1lFoZXiPpHcCuYWc+iswas5bxMoTp + toB3H3S7Xuspfqtul02ZNOz86eIXZElLNTp6GOG6vRgqpOrd3tf27w+Zc9Uek3dAeNn4 + J5/kxifObohXlxiVmKxTiA9NJyc2yPK+qedr5pewnuFDB+C7fTpNb5uIwiia7Ea7KcIv + ZD4GYYs4jYR4tcQB77IJNhuYZFlSVKV0OHCUDvaD69qA7N6g5A/oT+7HVJRTgkj6Q2/x + dASKZb0a9ln1QVziyHnkx1XBjhYSKJi+4eKYTOraj5eOLmjYO/4Zorl2ZkfftNufHr2G + fOKg6xM+z+B2sdlIhX2xZTVsiwKmhAcKg5WrmGZxhfQOOc68JZwS35JOKZXThFniVGmm + slFYLDZKi5UrhGalROuSGmYhWsQx4yKWCPBLtgyXsY/jx1lewWJGSUC5UHEIXMJKRpA0 + gCTYRdkmMuxxiSiOKxHeprKrqfp9s5fk73wlIFDBWQIehKGjwEvCRQ0wYxQ1qFRKbpUu + Hf7gPelQwBlxOIHxaMxoAHNX4FmOVuQFBXyTAr7nR2MaA8syShVMW3416XrRLT1ug0Mz + Nqq7nJATq8DvciOH+l7mzZsHGoyT5DvpoRol6DAfv3fmnQ8+60icOnL+wyOJn8PmSQcz + rPswU3PtDNO3+2cAUOgEHGfMV5BUokJ6gql3H4OBvQyeHl3KpieUeBBDhtLX4WuQ6ymx + N0V3O5zYChoTVZo8v/3ub58lNuPFlxLfJRIX8GI2O7EKL+bi1+Kf4fWJ+0gQSBDaMycG + yzYGlaDvxO5rNq+27bExVC8sMQwy1BqmCwuZhcJa0xa0mdti3mzZbN2L9lp0g9BQc431 + lJmt4t7iyCpuN9qN93B7rVxqhLOZrRbQW80qpdYtaqjAtTgBieDearWaba2qxy0gdz9K + GlCwRTr8gu0W5CXJF5xfeXBGCTRG6tvH1NllMIPDzzLbYLXaONhUB0q0gcufooPeRLgD + 5HNz5lHfF87nGQKHbyhzKaQGZVExnOABbDCM/2TokUmV25u2h6Ke7DRdXraO66dJLHgX + HNVs9vTEk4k/vJKY1sGLL6h5v018KpUd0b2FeZjCCvx8TAesVwXsFtwbqyzmB6FxqBaP + 46ejGXg6v5BTYI7nozAwTPcywFjGpBS0Y9hnLgWSkgSun+BQMUPohkb7DaVDFsnythec + FZEPjMg7w/KusLyfgeuLsb/Qb8awAYULyI/iHUy/+BrS3N2E31/HoF0b4rAiB4M+BHYs + s0i2Y51gM06MFTkv2tH39qwbDFqvXvIDLpyeqM37D2atz/+Bf3qv5+QG6zsHtm2vlgrK + O+V/1Lit6MK5Of+XfRuEM24C+Er+wc4lxg74/aO163333ZPXzsl6PKVK1Nnw2oa7teXf + Ij0croHfydsMP/3+nijjg+DxR4AHTHPhB3c+mojCp2j4r1O7u5RP3ihJliNUwBlQJSkF + NJaiFgitNM3ej2IQjkMogDAcwlAItN7X7EtoAqS3c2ORB77bGg/hRUi3sl/L756iZXwL + rIqTcp1WuHdAeQOU+yHdAmna5mgWoTK4l0AYBO264N4XwnJ8Ei2Hsia4r4F2ltM8CLRu + I2lBa6CMjsMKz03QngGelRDMEAogAK6BHgvgS7CVqAXbcD+8lqSQexkPfN+0nOXZ9VwK + t5x7m7vKG/g+/FuCS5gvdINC/J2in2K7NE26rLxd5VHNUhvUk9RPaJAmRbNDc1U7X3tB + l6aX9OP1HYZJhu3GPOPDxgtJ+EJfc4DG7gHblCAdXPXw9d5lSQWciGKBSoYkNngoQ+Mr + a2+rHpk+aOq9jVMXzJw8EWoQCPDrmYqmJlN/F8Pqgva1oPkZYEfVBFKR2iNOOKvgA303 + FayyMHxFFoVv0uheTy44DgpRESpGJfAFVRUaKH8vNhgNkb8KG4Fuk79bGw3fot2BxtJl + isbD110TYNTHgL7k86GD4YxoBYRCCOnp/W2Ai93oCQg7ITBoJn4ULYawBsLTENgbqX3w + dBg/2s6KsdfxYuTAQ2JK1nu7ye61SUrvB2AOdezwfmr7+ghsxqnRV9jerkaK/hLeiZ9F + U5AXvwievwfh67YI3noweq+3AYr2obkQmiAwcozxvnZPnvcNnIGC4N734hDysPg1729y + M70XczsJbve+Ge5k4fZTDzzFtN5j7h3en7ine9+AsD9Z1BKFGq9597nv9W7wdOKt7d71 + 1Cht9z6ZvD3ghldf886ObvJOyZXLh23qJPvbvaVQPjam9BaV+L2F7gve7HCniOE50z3M + m5b7C28qvAjVfNBoMKb3utwbvH2gyOOuDveBcAS34G0oDW9rDw7xvg5JmO7BwdGSTZ34 + RwcHRXKDnfjBWNGgyKbooHAwOswbjA4MhyE99m1huXCn0F/IE9LhAzNQUAWnYBINok7U + iCpREsH10Ilfaq/w8kfwflQBYNl/ELaOYYv8Fchkj+CX5cyXD4msSEQkmjp7fgWbphiB + Sb6/A8gSI0i8xsspvhO/DGd6adbLMS8sKYxYuUAHlErPyNIYESwSIKo2/Fgnj1ZYGits + FYZ++tKBVf9X1CCXXI+pRvx//GzY3bYJviVpa3HXwWc7kOhx112vC77F/8dvwQNQYWpl + OtVkDjbOnTVN/gwpUD21Ab5Ganu0ET4La5rk8x2YNbf3G6tQw6TJM+h3MBOnts0NTK1q + mxWo8h1olN+j2TcVT6PFjYGqA2ha9e21B6bFpla1N8Yaq+Ezo7qDkyrn19/S15obfc2v + /Cd9VdLG5tO+Jsnv/V1f9bR4Eu2rnvZVT/uaFJsk90VBUD1zTOX9C4A64VMl+FQoMqZt + 8KjxtfBFXl1VJ95Nv196AP0v45Ji0wplbmRzdHJlYW0KZW5kb2JqCjEwMCAwIG9iagox + MDk3NwplbmRvYmoKMTAxIDAgb2JqCjw8IC9UeXBlIC9Gb250RGVzY3JpcHRvciAvQXNj + ZW50IDc3MCAvQ2FwSGVpZ2h0IDY4NCAvRGVzY2VudCAtMjMwIC9GbGFncyAzMgovRm9u + dEJCb3ggWzAgLTIyMSA3NjggNzM3XSAvRm9udE5hbWUgL1pCWE9FUCtIZWx2ZXRpY2Eg + L0l0YWxpY0FuZ2xlIDAgL1N0ZW1WCjAgL01heFdpZHRoIDE1MDAgL1hIZWlnaHQgNTEz + IC9Gb250RmlsZTIgOTkgMCBSID4+CmVuZG9iagoxMDIgMCBvYmoKWyAyNzggMCAwIDAg + MCAwIDAgMCAwIDAgMCAwIDI3OCAwIDI3OCAyNzggNTU2IDU1NiAwIDAgNTU2IDAgNTU2 + IDU1NiA1NTYgMAowIDI3OCAwIDU4NCAwIDU1NiAwIDY2NyAwIDcyMiA3MjIgNjY3IDYx + MSAwIDAgMjc4IDAgMCA1NTYgODMzIDcyMiAwIDY2NyAwCjcyMiA2NjcgNjExIDcyMiA2 + NjcgMCAwIDAgMCAwIDAgMCAwIDAgMCA1NTYgMCA1MDAgNTU2IDU1NiAyNzggNTU2IDU1 + NiAyMjIKMCA1MDAgMjIyIDgzMyA1NTYgNTU2IDU1NiAwIDMzMyA1MDAgMjc4IDU1NiAw + IDcyMiA1MDAgNTAwIDUwMCAwIDAgMCAwIDAgMAowIDAgMCAwIDAgMCAwIDAgMCAwIDAg + MCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAw + CjAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAg + MCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAKMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAw + IDAgMCAwIDAgMCA1MDAgXQplbmRvYmoKMzggMCBvYmoKPDwgL1R5cGUgL0ZvbnQgL1N1 + YnR5cGUgL1RydWVUeXBlIC9CYXNlRm9udCAvWkJYT0VQK0hlbHZldGljYSAvRm9udERl + c2NyaXB0b3IKMTAxIDAgUiAvV2lkdGhzIDEwMiAwIFIgL0ZpcnN0Q2hhciAzMiAvTGFz + dENoYXIgMjIyIC9FbmNvZGluZyAvTWFjUm9tYW5FbmNvZGluZwo+PgplbmRvYmoKMTAz + IDAgb2JqCjw8IC9MZW5ndGggMTA0IDAgUiAvTGVuZ3RoMSA4Njg0IC9GaWx0ZXIgL0Zs + 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 + pVjbU66bbL8ty7Q9UlZhG8ugvDHb6EwSB2x7ym6yPbBZyflFliLudwVwZMx2nywO2HZT + /3dtUgrujDTcGBGDm5WBrtuviOX7A8yDB2wDrnTbQmqIktbW7Vpm63K5bW0zA5g2ZvPK + zQ7YGjOO2RrkocdsUmSg0kjvJS4FcVFk2BzXIduUyAipcm0p3mZ3Ndqs1H/OfXfZclzX + 2GZmBXDvo/VTslz1GXeVBvCcMoYsCKgslkdEb8bj+EvSZyYuoGv73fvrMwkz7hizbSIx + sr9+SllagD0txdn2Z9RnbKZQSiGNwvwAtkk54k5xkThfnCpmi5liuugQU8QkMUEVp9Kp + YlRRKo1KpaLlrmJUoEoIhP8qZcs2mSDoZCGQwdMbECWuIxtExRDJXOlFAgNzICDAzYmr + qkxVcTP07tqab/jrUTJ7arK/+pHjnvyZ0Oq/i16G+/dZO/1FciRs7Zws/f9F+qqpfUPL + mv0ta860K99TnJ6+Hvqs4t+2ij57bVhot4+eWSMXyG/2exb29svS1+df4+yr8Z9x1thH + W5R2Xytul4tbnDWj0O5p6xhtl/pqxlqkFvl7Sef+Zk89bUc0yMWxtk6OVe/5hrE8cmf1 + 8ljNSruvjdUkFzfLYzXJYzXJYzVLzcpY2dmeJa3V8L9upOJhCmVuZHN0cmVhbQplbmRv + YmoKMTA0IDAgb2JqCjU2NzcKZW5kb2JqCjEwNSAwIG9iago8PCAvVHlwZSAvRm9udERl + c2NyaXB0b3IgL0FzY2VudCA3NzAgL0NhcEhlaWdodCA2ODQgL0Rlc2NlbnQgLTIzMCAv + RmxhZ3MgMzIKL0ZvbnRCQm94IFsxMCAtMjA5IDY1NSA3MzRdIC9Gb250TmFtZSAvQk5G + UEVKK0hlbHZldGljYS1Cb2xkIC9JdGFsaWNBbmdsZQowIC9TdGVtViAwIC9NYXhXaWR0 + aCAxNTAwIC9YSGVpZ2h0IDUxMyAvRm9udEZpbGUyIDEwMyAwIFIgPj4KZW5kb2JqCjEw + NiAwIG9iagpbIDI3OCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAw + IDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwCjAgMCAwIDAgMCA3MjIgMjc4IDAg + MCA2MTEgMCAwIDAgNjY3IDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgNTU2 + IDAKNTU2IDYxMSA1NTYgMCAwIDAgMjc4IDAgNTU2IDI3OCAwIDYxMSA2MTEgNjExIDAg + Mzg5IDU1NiAzMzMgNjExIDAgMCAwIDAgNTAwCl0KZW5kb2JqCjM5IDAgb2JqCjw8IC9U + eXBlIC9Gb250IC9TdWJ0eXBlIC9UcnVlVHlwZSAvQmFzZUZvbnQgL0JORlBFSitIZWx2 + ZXRpY2EtQm9sZCAvRm9udERlc2NyaXB0b3IKMTA1IDAgUiAvV2lkdGhzIDEwNiAwIFIg + L0ZpcnN0Q2hhciAzMiAvTGFzdENoYXIgMTIyIC9FbmNvZGluZyAvTWFjUm9tYW5FbmNv + ZGluZwo+PgplbmRvYmoKMSAwIG9iago8PCAvVGl0bGUgKFVudGl0bGVkKSAvQXV0aG9y + IChicmFuZG9uaCkgL0NyZWF0b3IgKE9tbmlHcmFmZmxlIFByb2Zlc3Npb25hbCkKL1By + b2R1Y2VyIChNYWMgT1MgWCAxMC41LjggUXVhcnR6IFBERkNvbnRleHQpIC9DcmVhdGlv + bkRhdGUgKEQ6MjAwOTEyMTYyMjQyMDlaMDAnMDAnKQovTW9kRGF0ZSAoRDoyMDA5MTIx + NjIyNDIwOVowMCcwMCcpID4+CmVuZG9iagp4cmVmCjAgMTA3CjAwMDAwMDAwMDAgNjU1 + MzUgZiAKMDAwMDA5NjU1OCAwMDAwMCBuIAowMDAwMDc3OTE1IDAwMDAwIG4gCjAwMDAw + MDM4NTEgMDAwMDAgbiAKMDAwMDA3Nzc1MiAwMDAwMCBuIAowMDAwMDAwMDIyIDAwMDAw + IG4gCjAwMDAwMDM4MzEgMDAwMDAgbiAKMDAwMDAwMzk1NiAwMDAwMCBuIAowMDAwMDc1 + NDAxIDAwMDAwIG4gCjAwMDAwMDczNDQgMDAwMDAgbiAKMDAwMDAwODE4OSAwMDAwMCBu + IAowMDAwMDEyNzk0IDAwMDAwIG4gCjAwMDAwMTM4ODUgMDAwMDAgbiAKMDAwMDAwNjIy + MyAwMDAwMCBuIAowMDAwMDA3MzI0IDAwMDAwIG4gCjAwMDAwMDgyMDkgMDAwMDAgbiAK + MDAwMDAwOTMwMCAwMDAwMCBuIAowMDAwMDEzOTA1IDAwMDAwIG4gCjAwMDAwMTQ5OTYg + MDAwMDAgbiAKMDAwMDAwNTQwMiAwMDAwMCBuIAowMDAwMDA2MjAzIDAwMDAwIG4gCjAw + MDAwMTYxMjcgMDAwMDAgbiAKMDAwMDAxNjg4NCAwMDAwMCBuIAowMDAwMDE2OTA0IDAw + MDAwIG4gCjAwMDAwMTc5OTUgMDAwMDAgbiAKMDAwMDAxMDA5NyAwMDAwMCBuIAowMDAw + MDExMTg4IDAwMDAwIG4gCjAwMDAwMDkzMjAgMDAwMDAgbiAKMDAwMDAxMDA3NyAwMDAw + MCBuIAowMDAwMDExMjA4IDAwMDAwIG4gCjAwMDAwMTE5NTMgMDAwMDAgbiAKMDAwMDAw + NDI5MSAwMDAwMCBuIAowMDAwMDA1MzgyIDAwMDAwIG4gCjAwMDAwMTUwMTYgMDAwMDAg + biAKMDAwMDAxNjEwNyAwMDAwMCBuIAowMDAwMDExOTczIDAwMDAwIG4gCjAwMDAwMTI3 + NzQgMDAwMDAgbiAKMDAwMDA3NzcxNSAwMDAwMCBuIAowMDAwMDg5OTM3IDAwMDAwIG4g + CjAwMDAwOTYzNzYgMDAwMDAgbiAKMDAwMDA3Njg1MCAwMDAwMCBuIAowMDAwMDYyMTU4 + IDAwMDAwIG4gCjAwMDAwNjYwNDMgMDAwMDAgbiAKMDAwMDA3MDgyNCAwMDAwMCBuIAow + MDAwMDE4MDE1IDAwMDAwIG4gCjAwMDAwMjA5ODQgMDAwMDAgbiAKMDAwMDA3MzcyNCAw + MDAwMCBuIAowMDAwMDY2MDY0IDAwMDAwIG4gCjAwMDAwNzAxMTUgMDAwMDAgbiAKMDAw + MDA3NDQ0OSAwMDAwMCBuIAowMDAwMDM4MzMwIDAwMDAwIG4gCjAwMDAwNDE1NDEgMDAw + MDAgbiAKMDAwMDA0NTAyMiAwMDAwMCBuIAowMDAwMDQ4OTA3IDAwMDAwIG4gCjAwMDAw + NzIyNzQgMDAwMDAgbiAKMDAwMDA1OTQ0OSAwMDAwMCBuIAowMDAwMDYyMTM3IDAwMDAw + IG4gCjAwMDAwNDg5MjggMDAwMDAgbiAKMDAwMDA1MjgxMyAwMDAwMCBuIAowMDAwMDcx + NTQ5IDAwMDAwIG4gCjAwMDAwMzU4MzYgMDAwMDAgbiAKMDAwMDAzODMwOSAwMDAwMCBu + IAowMDAwMDcyOTk5IDAwMDAwIG4gCjAwMDAwNDE1NjIgMDAwMDAgbiAKMDAwMDA0NTAw + MSAwMDAwMCBuIAowMDAwMDU1NTQzIDAwMDAwIG4gCjAwMDAwNTk0MjggMDAwMDAgbiAK + MDAwMDAyMTAwNSAwMDAwMCBuIAowMDAwMDI0ODkwIDAwMDAwIG4gCjAwMDAwNzYxMjUg + MDAwMDAgbiAKMDAwMDAyNDkxMSAwMDAwMCBuIAowMDAwMDMxOTA5IDAwMDAwIG4gCjAw + MDAwNTI4MzQgMDAwMDAgbiAKMDAwMDA1NTUyMiAwMDAwMCBuIAowMDAwMDMxOTMwIDAw + MDAwIG4gCjAwMDAwMzU4MTUgMDAwMDAgbiAKMDAwMDA3MDEzNiAwMDAwMCBuIAowMDAw + MDcwODA0IDAwMDAwIG4gCjAwMDAwNzA4NjEgMDAwMDAgbiAKMDAwMDA3MTUyOSAwMDAw + MCBuIAowMDAwMDcxNTg2IDAwMDAwIG4gCjAwMDAwNzIyNTQgMDAwMDAgbiAKMDAwMDA3 + MjMxMSAwMDAwMCBuIAowMDAwMDcyOTc5IDAwMDAwIG4gCjAwMDAwNzMwMzYgMDAwMDAg + biAKMDAwMDA3MzcwNCAwMDAwMCBuIAowMDAwMDczNzYxIDAwMDAwIG4gCjAwMDAwNzQ0 + MjkgMDAwMDAgbiAKMDAwMDA3NDQ4NiAwMDAwMCBuIAowMDAwMDc1MzgxIDAwMDAwIG4g + CjAwMDAwNzU0MzcgMDAwMDAgbiAKMDAwMDA3NjEwNSAwMDAwMCBuIAowMDAwMDc2MTYy + IDAwMDAwIG4gCjAwMDAwNzY4MzAgMDAwMDAgbiAKMDAwMDA3Njg4NyAwMDAwMCBuIAow + MDAwMDc3Njk1IDAwMDAwIG4gCjAwMDAwNzc4MzUgMDAwMDAgbiAKMDAwMDA3ODA0MSAw + MDAwMCBuIAowMDAwMDc3OTYzIDAwMDAwIG4gCjAwMDAwNzgxMTkgMDAwMDAgbiAKMDAw + MDA4OTE4OCAwMDAwMCBuIAowMDAwMDg5MjExIDAwMDAwIG4gCjAwMDAwODk0MzIgMDAw + MDAgbiAKMDAwMDA5MDExNCAwMDAwMCBuIAowMDAwMDk1ODgzIDAwMDAwIG4gCjAwMDAw + OTU5MDUgMDAwMDAgbiAKMDAwMDA5NjEzMyAwMDAwMCBuIAp0cmFpbGVyCjw8IC9TaXpl + IDEwNyAvUm9vdCA5NiAwIFIgL0luZm8gMSAwIFIgL0lEIFsgPDE3ZDJjNDJhMzE3NDJh + NTgyMWQxNTc1OWQwMGFhYWE5Pgo8MTdkMmM0MmEzMTc0MmE1ODIxZDE1NzU5ZDAwYWFh + YTk+IF0gPj4Kc3RhcnR4cmVmCjk2NzczCiUlRU9GCjEgMCBvYmoKPDwvQXV0aG9yIChi + cmFuZG9uaCkvQ3JlYXRpb25EYXRlIChEOjIwMDkxMTIwMDExMzAwWikvQ3JlYXRvciAo + T21uaUdyYWZmbGUgUHJvZmVzc2lvbmFsIDUuMi4xKS9Nb2REYXRlIChEOjIwMDkxMjE2 + MjI0MjAwWikvUHJvZHVjZXIgKE1hYyBPUyBYIDEwLjUuOCBRdWFydHogUERGQ29udGV4 + dCkvVGl0bGUgKGhlYWRlcl9wYXJzaW5nX2Zsb3djaGFydC5ncmFmZmxlKT4+CmVuZG9i + agp4cmVmCjEgMQowMDAwMDk5MDczIDAwMDAwIG4gCnRyYWlsZXIKPDwvSUQgWzwxN2Qy + YzQyYTMxNzQyYTU4MjFkMTU3NTlkMDBhYWFhOT4gPDE3ZDJjNDJhMzE3NDJhNTgyMWQx + NTc1OWQwMGFhYWE5Pl0gL0luZm8gMSAwIFIgL1ByZXYgOTY3NzMgL1Jvb3QgOTYgMCBS + IC9TaXplIDEwNz4+CnN0YXJ0eHJlZgo5OTI5OQolJUVPRgo= + + QuickLookThumbnail + + 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 + AAASmwAAT0AAAFOAAAIzMwACMzMAAjMzZGVzYwAAAAAAAAAOU2NlcHRyZSBYMjRXRwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABtbHVjAAAAAAAAABIAAAAMbmJOTwAAABoA + AADocHRQVAAAABoAAADoc3ZTRQAAABoAAADoZmlGSQAAABoAAADoZGFESwAAABoAAADo + emhDTgAAABoAAADoZnJGUgAAABoAAADoamFKUAAAABoAAADoZW5VUwAAABoAAADocGxQ + TAAAABoAAADocHRCUgAAABoAAADoZXNFUwAAABoAAADoemhUVwAAABoAAADocnVSVQAA + ABoAAADoa29LUgAAABoAAADoZGVERQAAABoAAADobmxOTAAAABoAAADoaXRJVAAAABoA + AADoAFMAYwBlAHAAdAByAGUAIABYADIANABXAEcAAG1tb2QAAAAAAABOFAAAJAQAAABF + w6htgAAAAAAAAAAAAAAAAAAAAAB0ZXh0AAAAAENvcHlyaWdodCBBcHBsZSwgSW5jLiwg + MjAwOQA= + + ReadOnly + NO + RowAlign + 1 + RowSpacing + 36 + SheetTitle + Canvas 1 + SmartAlignmentGuidesActive + YES + SmartDistanceGuidesActive + YES + UniqueID + 1 + UseEntirePage + + VPages + 1 + WindowInfo + + CurrentSheet + 0 + ExpandedCanvases + + + name + Canvas 1 + + + FitInWindow + + Frame + {{94, 4}, {1714, 1174}} + ListView + + OutlineWidth + 142 + RightSidebar + + ShowRuler + + Sidebar + + SidebarWidth + 120 + VisibleRegion + {{0, -16}, {1187.25, 766.937}} + Zoom + 1.3299663066864014 + ZoomValues + + + Canvas 1 + 0.0 + 1 + + + + saveQuickLookFiles + YES + + diff --git a/openflow/doc/of-spec/make_latex_input.pl b/openflow/doc/of-spec/make_latex_input.pl new file mode 100755 index 00000000..7a1c48b7 --- /dev/null +++ b/openflow/doc/of-spec/make_latex_input.pl @@ -0,0 +1,117 @@ +#!/usr/bin/perl -w + +use strict; + +sub handle_comment { + my ($comment) = @_; + + my $next_line; + do { + $next_line = ; + chomp $next_line; + $comment .= $next_line . "\n"; + } until ( $next_line =~ m/\*\// ); + + return $comment; +} + +sub handle_define { + my ( $var, $val ) = @_; + open( OUTFILE, ">define/$var" ); + print OUTFILE $val; + close(OUTFILE); +} + +sub handle_multiline { + my ( $dir, $filename, $line_orig, $last_comment ) = @_; + + open( OUTFILE, ">$dir/$filename" ); + + #print OUTFILE "\\scriptsize\n"; + print OUTFILE "\\begin{footnotesize}\n"; + print OUTFILE "\\begin{verbatim}\n"; + + #print OUTFILE "\\begin{lstlisting}[frame=htb]{$filename}\n"; + print OUTFILE $last_comment; + print OUTFILE $line_orig; + my $next_line; + do { + + $next_line = ; + chomp $next_line; + + print OUTFILE $next_line . "\n"; + + } until ( $next_line eq '};' ); + + # add assertion line for structs + if ( $dir eq 'struct' ) { + $next_line = ; + print OUTFILE $next_line; + } + print OUTFILE "\\end{verbatim}\n"; + + #print OUTFILE "\\end{lstlisting}\n"; + print OUTFILE "\\end{footnotesize}\n"; + close(OUTFILE); +} + +#---------------------------------------- +use File::Path; + +foreach my $type ( 'enum', 'struct', 'define' ) { + if ( -d $type ) { + rmtree($type); + } + mkdir $type; +} + +open( INFILE, "<../../include/openflow/openflow.h" ); + +my $last_comment; +while () { + + # Good practice to store $_ value because + # subsequent operations may change it. + my ($line) = $_; + my $line_orig = $line; + my @line_split = split ' ', $line; + + if ( not defined( $line_split[0] ) ) { + $last_comment = ''; + } + + # Handle single-line comment + elsif ( $line =~ m/^\/\*.*\*\// ) { + $last_comment = $line; + + #print $last_comment; + } + + # Handle multi-line comment + elsif ( $line =~ m/^\/\*/ ) { + $last_comment = handle_comment($line_orig); + + #print $last_comment; + } + + # Handle define + elsif ( $line_split[0] eq '#define' ) { + handle_define( $line_split[1], $line_split[2] ); + $last_comment = ''; + } + + # Handle enum + elsif ( $line_split[0] eq 'enum' ) { + handle_multiline( 'enum', $line_split[1], $line_orig, $last_comment ); + $last_comment = ''; + } + + # Handle struct + elsif ( $line_split[0] eq 'struct' ) { + handle_multiline( 'struct', $line_split[1], $line_orig, $last_comment ); + $last_comment = ''; + } + +} +print "completed\n"; diff --git a/openflow/doc/of-spec/openflow-spec-v1.0.0.tex b/openflow/doc/of-spec/openflow-spec-v1.0.0.tex new file mode 100644 index 00000000..56dca85c --- /dev/null +++ b/openflow/doc/of-spec/openflow-spec-v1.0.0.tex @@ -0,0 +1,418 @@ +\documentclass[10pt]{article} +\usepackage{amsmath} +\usepackage{listings} +\usepackage{hyperref} +\usepackage{fancyhdr} +\usepackage{graphicx} +\usepackage{tabularx} +\usepackage{color} + +\hbadness=10000 % No "underfull hbox" messages + +\begin{document} + +%\lstset{language=C} + +% Define the OpenFlow version here +\newcommand{\ofversion}{1.0.0} + +\pagestyle{fancy} +\fancyhead{} +\lhead{OpenFlow Switch Specification} +%\chead{DO NOT BUILD A SWITCH FROM THIS SPECIFICATION!} +\rhead{Version \ofversion} +\renewcommand{\headrulewidth}{0.4pt} +\renewcommand{\footrulewidth}{0.4pt} + +\fontfamily{cmr} % what about cmss? +\selectfont + +\newcommand{\qosupd}[1]{{#1}} +%\newcommand{\qosupd}[1]{{\color{blue} #1}} + +\title{OpenFlow Switch Specification} +\author{Version \ofversion{} ( Wire Protocol \input{define/OFP_VERSION})} +\date{\today} +\maketitle + +\section{Introduction} +This document describes the requirements of an OpenFlow Switch. We recommend that you read the latest version of the OpenFlow whitepaper before reading this specification. The whitepaper is available on the OpenFlow Consortium website (\url{http://OpenFlowSwitch.org}). This specification covers the components and the basic functions of the switch, and the OpenFlow protocol to manage an OpenFlow switch from a remote controller. +\\\\ +Version 1.0 of this document will be the first for which official vendor support is expected. Versions before 1.0 will be marked ``Draft", and will include the header: ``Do not build a switch from this specification!" We hope to generate feedback prior to Version 1.0 from switch designers and network researchers, so that the set of features defined in Version 1.0 enables production deployments on a variety of vendor hardware. + +\begin{figure}[htbp] +\centering +\includegraphics[height=2.5in]{figure_flow_table_secchan.png} +\caption{An OpenFlow switch communicates with a controller over a secure connection using the OpenFlow protocol.} +\label{fig:flow table and controller} +\end{figure} + +\section{Switch Components} +An OpenFlow Switch consists of a \emph{flow table}, which performs packet lookup and forwarding, and a \emph{secure channel} to an external controller (Figure \ref{fig:flow table and controller}). The controller manages the switch over the secure channel using the OpenFlow protocol. +\\\\ +The flow table contains a set of flow entries (header values to match packets against), activity counters, and a set of zero or more actions to apply to matching packets. All packets processed by the switch are compared against the flow table. If a matching entry is found, any actions for that entry are performed on the packet (e.g., the action might be to forward a packet out a specified port). If no match is found, the packet is forwarded to the controller over the secure channel. The controller is responsible for determining how to handle packets without valid flow entries, and it manages the switch flow table by adding and removing flow entries. +\\\\ +Flow entries may forward packets to one or more OpenFlow ports. In general, these are physical ports, but the protocol does not preclude abstractions like port aggregations or VLAN traffic on a port appearing as an OpenFlow port. OpenFlow ports have limited state such as ``up'', ``down'' and whether spanning tree flood packets should be forwarded out the port. Additional configuration of ports may handled by the OpenFlow configuration protocol. There are several OpenFlow virtual ports used to indicate, for example, flooding or the ingress port (see \ref{ft:actions}). + +\section{Flow Table} +This section describes the components of flow table entries and the process by which incoming packets are matched against flow table entries. + +\begin{table}[hbp] +\centering +\begin{tabular}{|c|c|c|} +\hline +Header Fields & Counters & Actions\\ +\hline +\end{tabular} +\caption{A flow entry consists of header fields, counters, and actions.} +\label{table:flow entry} +\end{table} + +Each flow table entry (see Table \ref{table:flow entry}) contains: +\begin{itemize} +\item \textbf{header fields} to match against packets +\item \textbf{counters} to update for matching packet +\item \textbf{actions} to apply to matching packets +\end{itemize} + +\subsection{Header Fields} +\begin{table}[hbp] +\centering +\footnotesize +\begin{tabularx}{\textwidth}{ |X|X|X|X|X|X|X|X|X|X|X|X| } +\hline +Ingress Port & +Ether source & +Ether dst & +Ether type & +VLAN id & +VLAN priority & +IP src & +IP dst & +IP proto & +IP ToS bits & +TCP/ UDP src port & +TCP/ UDP dst port +\\ +\hline +\end{tabularx} +\caption{Fields from packets used to match against flow entries.} +\label{table:header fields} +\end{table} + +Table \ref{table:header fields} shows the header fields an incoming packet is compared against. Each entry contains a specific value, or ANY, which matches any value. If the switch supports subnet masks on the IP source and/or destination fields, these can more precisely specify matches. The fields in the OpenFlow 12-tuple are listed in Table \ref{table:header fields} and details on the properties of each field are described in Table \ref{table:header field details}. +\\\\ +\begin{table}[hbp] +\centering +\footnotesize +\begin{tabularx}{\textwidth}{ |X|X|X|X| } +\hline Field & Bits & When applicable & Notes \\ +\hline Ingress Port & (Implementation dependent) & All packets & Numerical representation of incoming port, starting at 1. \\ +\hline Ethernet source address & 48 & All packets on enabled ports & \\ +\hline Ethernet destination address & 48 & All packets on enabled ports & \\ +\hline Ethernet type & 16 & All packets on enabled ports & An OpenFlow switch is required to match the type in both standard Ethernet and 802.2 with a SNAP header and OUI of 0x000000. The special value of 0x05FF is used to match all 802.3 packets without SNAP headers. \\ +\hline VLAN id & 12 & All packets of Ethernet type 0x8100 & \\ +\hline VLAN priority & 3 & All packets of Ethernet type 0x8100 & VLAN PCP field \\ +\hline IP source address & 32 & All IP and ARP packets & Can be subnet masked \\ +\hline IP destination address & 32 & All IP and ARP packets & Can be subnet masked \\ +\hline IP protocol & 8 & All IP and IP over Ethernet, ARP packets & Only the lower 8 bits of the ARP opcode are used \\ +\hline IP ToS bits & 6 & All IP packets & Specify as 8-bit value and place ToS in upper 6 bits. \\ +\hline Transport source port / ICMP Type & 16 & All TCP, UDP, and ICMP packets & Only lower 8 bits used for ICMP Type \\ +\hline Transport destination port / ICMP Code & 16 & All TCP, UDP, and ICMP packets & Only lower 8 bits used for ICMP Code \\ +\hline +\end{tabularx} +\caption{Field lengths and the way they must be applied to flow entries.} +\label{table:header field details} +\end{table}Switch designers are free to implement the internals in any way convenient provided that correct functionality is preserved. For example, while a flow may have multiple forward actions, each specifying a different port, a switch designer may choose to implement this as a single bitmask within the hardware forwarding table. + +\subsection{Counters} + +Counters are maintained per-table, per-flow, \qosupd{per-port and + per queue}. OpenFlow-compliant counters may be implemented in software and maintained by polling hardware counters with more limited ranges. +\\\\ +Table \ref{table:counters} contains the required set of counters. Duration refers to the time the flow has been installed in the switch. The Receive Errors field includes all explicitly specified errors, including frame, overrun, and CRC errors, plus any others. Counters wrap around with no overflow indicator. In this document, the phrase byte refers to 8-bit octets. +\begin{table}[!hbp] +\centering +\footnotesize +%\begin{tabularx}{\textwidth}{ |X|X| } +\begin{tabular}{ |l|c| } +\hline Counter & Bits \\ +\hline \multicolumn{2}{|c|}{Per Table} \\ +\hline Active Entries & 32 \\ +\hline Packet Lookups & 64 \\ +\hline Packet Matches & 64 \\ +\hline \multicolumn{2}{|c|}{Per Flow} \\ +\hline Received Packets & 64 \\ +\hline Received Bytes & 64 \\ +\hline Duration (seconds) & 32 \\ +\hline Duration (nanoseconds) & 32 \\ +\hline \multicolumn{2}{|c|}{Per Port} \\ +\hline Received Packets & 64 \\ +\hline Transmitted Packets & 64 \\ +\hline Received Bytes & 64 \\ +\hline Transmitted Bytes & 64 \\ +\hline Receive Drops & 64 \\ +\hline Transmit Drops & 64 \\ +\hline Receive Errors & 64 \\ +\hline Transmit Errors & 64 \\ +\hline Receive Frame Alignment Errors & 64 \\ +\hline Receive Overrun Errors & 64 \\ +\hline Receive CRC Errors & 64 \\ +\hline Collisions & 64 \\ +\hline \multicolumn{2}{|c|}{\qosupd{Per Queue}} \\ +\hline \qosupd{Transmit Packets} & \qosupd{64} \\ +\hline \qosupd{Transmit Bytes} & \qosupd{64} \\ +\hline \qosupd{Transmit Overrun Errors} & \qosupd{64}\\ +\hline +\end{tabular} +\caption{Required list of counters for use in statistics messages.} +\label{table:counters} +\end{table} + +\subsection{Actions} +\label{ft:actions} +Each flow entry is associated with zero or more actions that dictate how the switch handles matching packets. If no forward actions are present, the packet is dropped. Action lists for \emph{inserted} flow entries MUST be processed in the order specified. However, there is no packet output ordering guaranteed within a port. For example, an action list may result in two packets sent to two different VLANs on a single port. These two packets may be arbitrarily re-ordered, but the packet bodies must match those generated from a sequential execution of the actions. +\\\\ +A switch may reject a flow entry if it cannot process the action list in the order specified, in which case it should immediately return an unsupported flow error (see \ref{unsupported_flow}). Ordering within a port may vary between vendor switch implementations. +\\\\ +A switch is not required to support all action types --- just those marked ``Required Actions'' below. When connecting to the controller, a switch indicates which of the ``Optional Actions'' it supports. OpenFlow-compliant switches come in two types: \emph{OpenFlow-only}, and \emph{OpenFlow-enabled}. +\\\\ +OpenFlow-only switches support only the required actions below, while OpenFlow-enabled switches, routers, and access points may also support the \textbf{NORMAL} action. Either type of switch can also support the \textbf{FLOOD} action. +\\\\ +\textbf{Required Action:} \textit{Forward}. +OpenFlow switches must support forwarding the packet to physical ports and the following virtual ones: +\begin{itemize} +\item \textbf{ALL:} Send the packet out all interfaces, not including the incoming interface. +\item \textbf{CONTROLLER:} Encapsulate and send the packet to the controller. +\item \textbf{LOCAL:} Send the packet to the switchÕs local networking stack. +\item \textbf{TABLE:} Perform actions in flow table. Only for packet-out messages. +\item \textbf{IN\_PORT:} Send the packet out the input port. +\end{itemize} +\textbf{Optional Action:} \textit{Forward}. +The switch may optionally support the following virtual ports: +\begin{itemize} +\item \textbf{NORMAL:} Process the packet using the traditional forwarding path supported by the switch (i.e., traditional L2, VLAN, and L3 processing.) The switch may check the VLAN field to determine whether or not to forward the packet along the normal processing route. If the switch cannot forward entries for the OpenFlow-specific VLAN back to the normal processing route, it must indicate that it does not support this action. +\item \textbf{FLOOD:} Flood the packet along the minimum spanning tree, not including the incoming interface. +\end{itemize} +The controller will only ask the switch to send to multiple physical ports simultaneously if the switch indicates it supports this behavior in the initial handshake (see section \ref{cts:handshake}). +\\\\ +\textbf{\qosupd{Optional Action:}} \emph{\qosupd{Enqueue}}. \qosupd{The enqueue action forwards +a packet through a queue attached to a port. Forwarding behavior is +dictated by the configuration of the queue and is used to provide +basic Quality-of-Service (QoS) support (see section \ref{cts:qos}).} +\\\\ +\textbf{Required Action:} \emph{Drop}. A flow-entry with no specified action indicates that all matching packets should be dropped. +\\\\ +\textbf{Optional Action:} \emph{Modify-Field}. While not strictly required, the actions shown in Table \ref{table:field modify actions} greatly increase the usefulness of an OpenFlow implementation. To aid integration with existing networks, we suggest that VLAN modification actions be supported. + +\begin{table}[hbp] +\centering +\footnotesize +\begin{tabularx}{\linewidth}{ |X|X|X| } +\hline +Action & Associated Data & Description \\ +\hline +Set VLAN ID & +12 bits & +If no VLAN is present, a new header is added with the specified VLAN ID and priority of zero. + +If a VLAN header already exists, the VLAN ID is replaced with the specified value. \\ +\hline +Set VLAN priority & +3 bits & +If no VLAN is present, a new header is added with the specified priority and a VLAN ID of zero. + +If a VLAN header already exists, the priority field is replaced with the specified value. \\ +\hline +Strip VLAN header & +- & +Strip VLAN header if present. \\ +\hline +Modify Ethernet source MAC address & +48 bits: Value with which to replace existing source MAC address & +Replace the existing Ethernet source MAC address with the new value \\ +\hline +Modify Ethernet destination MAC address & +48 bits: Value with which to replace existing destination MAC address & +Replace the existing Ethernet destination MAC address with the new value. \\ +\hline +Modify IPv4 source address & +32 bits: Value with which to replace existing IPv4 source address & +Replace the existing IP source address with new value and update the IP checksum (and TCP/UDP +checksum if applicable). + +This action is only applicable to IPv4 packets. \\ +\hline +Modify IPv4 destination address & +32 bits: Value with which to replace existing IPv4 destination address & +Replace the existing IP destination address with new value and update the IP checksum (and TCP/UDP checksum if applicable). + +This action is only applied to IPv4 packets. \\ +\hline +Modify IPv4 ToS bits & +6 bits: Value with which to replace existing IPv4 ToS field & +Replace the existing IP ToS field. +This action is only applied to IPv4 packets. \\ +\hline +Modify transport source port & +16 bits: Value with which to replace existing TCP or UDP source port & +Replace the existing TCP/UDP source port with new value and update the TCP/UDP checksum. + +This action is only applicable to TCP and UDP packets.\\ +\hline +Modify transport destination port & +16 bits: Value with which to replace existing TCP or UDP destination port & +Replace the existing TCP/UDP destination port with new value and update the TCP/UDP checksum + +This action is only applied to TCP and UDP packets.\\ +\hline +\end{tabularx} +\caption{Field-modify actions.} +\label{table:field modify actions} +\end{table} + +\subsection{Matching} +\begin{figure}[!htb] +\centering +\includegraphics[height=1.85in]{packet_flow_flowchart} +\caption{Packet flow in an OpenFlow switch. As discussed in Section \ref{flow_table:stp_support}, support for 802.1D is optional.} +\label{fig:packet_flow} +\end{figure} + +\begin{figure}[!htb] +\centering +\includegraphics[height=2.9in]{header_parsing_flowchart} +\caption{Flowchart showing how header fields are parsed for matching.} +\label{fig:header_parsing} +\end{figure} + +On receipt of a packet, an OpenFlow Switch performs the functions shown in Figure \ref{fig:packet_flow}. Header fields used for the table lookup depend on the packet type as described below (and shown in Figure \ref{fig:header_parsing}). + +\begin{itemize} +\item Rules specifying an ingress port are matched against the physical port that received the packet. +\item The Ethernet headers as specified in Table \ref{table:header fields} are used for all packets. +\item If the packet is a VLAN (Ethernet type 0x8100), the VLAN ID and PCP fields are used in the lookup. +\item (Optional) For ARP packets (Ethernet type equal to 0x0806), the lookup fields may also include the contained IP source and destination fields. +\item For IP packets (Ethernet type equal to 0x0800), the lookup fields also include those in the IP header. +\item For IP packets that are TCP or UDP (IP protocol is equal to 6 or 17), the lookup includes the transport ports. +\item For IP packets that are ICMP (IP prototcol is equal to 1), the lookup includes the Type and Code fields. +\item For IP packets with nonzero fragment offset or More Fragments bit set, the transport ports are set to zero for the lookup. +\end{itemize} +A packet matches a flow table entry if the values in the header fields used for the lookup (as defined above) match those defined in the flow table. If a flow table field has a value of ANY, it matches all possible values in the header. +\\\\ +To handle the various Ethernet framing types, matching the Ethernet type is handled in a slightly different manner. If the packet is an Ethernet II frame, the Ethernet type is handled in the expected way. If the packet is an 802.3 frame with a SNAP header and Organizationally Unique Identifier (OUI) of 0x000000, the SNAP protocol id is matched against the flowÕs Ethernet type. A flow entry that specifies an Ethernet type of 0x05FF, matches all Ethernet 802.2 frames without a SNAP header and those with SNAP headers that do not have an OUI of 0x000000. +\\\\ +Packets are matched against flow entries based on prioritization. An entry that specifies an exact match (i.e., it has no wildcards) is always the highest priority. All wildcard entries have a priority associated with them. Higher priority entries must match before lower priority ones. If multiple entries have the same priority, the switch is free to choose any ordering. Higher numbers have higher priorities. +\\\\ +For each packet that matches a flow entry, the associated counters for that entry are updated. If no matching entry can be found for a packet, the packet is sent to the controller over the secure channel. + +\section{Secure Channel} +The secure channel is the interface that connects each OpenFlow switch to a controller. Through this interface, the controller configures and manages the switch, receives events from the switch, and send packets out the switch. +\\\\ +Between the datapath and the secure channel, the interface is implementation-specific, however all secure channel messages must be formatted according to the OpenFlow protocol. +\\\\ +Support for multiple simultaneous controllers is currently undefined. + +\subsection{OpenFlow Protocol Overview} +The OpenFlow protocol supports three message types, \emph{controller-to-switch}, \emph{asynchronous}, and \emph{symmetric}, each with multiple sub-types. Controller-to-switch messages are initiated by the controller and used to directly manage or inspect the state of the switch. Asynchronous messages are initiated by the switch and used to update the controller of network events and changes to the switch state. Symmetric messages are initiated by either the switch or the controller and sent without solicitation. The message types used by OpenFlow are described below. + +\subsubsection{Controller-to-Switch} +Controller/switch messages are initiated by the controller and may or may not require a response from the switch. +\\\\ +\textbf{Features:} Upon Transport Layer Security (TLS) session establishment, the controller sends a features request message to the switch. The switch must reply with a features reply that specifies the capabilities supported by the switch. +\\\\ +\textbf{Configuration:} The controller is able to set and query configuration parameters in the switch. The switch only responds to a query from the controller. +\\\\ +\textbf{Modify-State:} Modify-State messages are sent by the controller to manage state on the switches. Their primary purpose is to add/delete and modify flows in the flow tables and to set switch port properties. +\\\\ +\textbf{Read-State:} Read-State messages are used by the controller to collect statistics from the switchÕs flow-tables, ports and the individual flow entries. +\\\\\ +\textbf{Send-Packet}: These are used by the controller to send packets out of a specified port on the switch. +\\\\ +\textbf{Barrier}: Barrier request/reply messages are used by the controller to ensure message dependencies have been met or to receive notifications for completed operations. + +\subsubsection{Asynchronous} +Asynchronous messages are sent without the controller soliciting them from a switch. Switches send asynchronous messages to the controller to denote a packet arrival, switch state change, or error. The four main asynchronous message types are described below. +\\\\ +\textbf{Packet-in:} For all packets that do not have a matching flow entry, a packet-in event is sent to the controller (or if a packet matches an entry with a ``send to controller" action). If the switch has sufficient memory to buffer packets that are sent to the controller, the packet-in events contain some fraction of the packet header (by default \input{define/OFP_DEFAULT_MISS_SEND_LEN} bytes) and a buffer ID to be used by the controller when it is ready for the switch to forward the packet. Switches that do not support internal buffering (or have run out of internal buffering) must send the full packet to the controller as part of the event. +\\\\ +\textbf{Flow-Removed:} When a flow entry is added to the switch by a flow modify message, an idle timeout value indicates when the entry should be removed due to a lack of activity, as well as a hard timeout value that indicates when the entry should be removed, regardless of activity. The flow modify message also specifies whether the switch should send a flow removed message to the controller when the flow expires. Flow modify messages which delete flows may also cause flow removed messages. +\\\\ +\textbf{Port-status:} The switch is expected to send port-status messages to the controller as port configuration state changes. These events include change in port status (for example, if it was brought down directly by a user) or a change in port status as specified by 802.1D (see Section \ref{flow_table:stp_support} for a description of 802.1D support requirements). +\\\\ +\textbf{Error:} The switch is able to notify the controller of problems using error messages. + +\subsubsection{Symmetric} +Symmetric messages are sent without solicitation, in either direction. +\\\\ +\textbf{Hello:} Hello messages are exchanged between the switch and controller upon connection startup. +\\\\ +\textbf{Echo:} Echo request/reply messages can be sent from either the switch or the controller, and must return an echo reply. They can be used to indicate the latency, bandwidth, and/or liveness of a controller-switch connection. +\\\\ +\textbf{Vendor:} Vendor messages provide a standard way for OpenFlow switches to offer additional functionality within the OpenFlow message type space. This is a staging area for features meant for future OpenFlow revisions. + +\subsection{Connection Setup} +The switch must be able to establish the communication at a user-configurable (but otherwise fixed) IP address, using a user-specified port. Traffic to and from the secure channel is not checked against the flow table. Therefore, the switch must identify incoming traffic as local before checking it against the flow table. Future versions of the protocol specification will describe a dynamic controller discovery protocol in which the IP address and port for communicating with the controller is determined at runtime. +\\\\ +When an OpenFlow connection is first established, each side of the connection must immediately send an \verb|OFPT_HELLO| message with the \verb|version| field set to the highest OpenFlow protocol version supported by the sender. Upon receipt of this message, the recipient may calculate the OpenFlow protocol version to be used as the smaller of the version number that it sent and the one that it received. +\\\\ +If the negotiated version is supported by the recipient, then the connection proceeds. Otherwise, the recipient must reply with an \verb|OFPT_ERROR| message with a \verb|type| field of \verb|OFPET_HELLO_FAILED|, a \verb|code| field of \verb| OFPHFC_COMPATIBLE|, and optionally an ASCII string explaining the situation in \verb|data|, and then terminate the connection. + +\subsection{Connection Interruption} +In the case that a switch loses contact with the controller, as a result of a echo request timeout, TLS session timeout, or other disconnection, it should attempt to contact one or more backup controllers. The ordering of the controller IP addresses is not specified by the protocol. +\\\\ +If some number of attempts to contact a controller (zero or more) fail, the switch must enter ``emergency mode'' and immediately reset the current TCP connection. In emergency mode, the matching process is dictated by the emergency flow table entries (those marked with the emergency bit when added to the switch). All normal entries are deleted when entering emergency mode. +\\\\ +Upon connecting to a controller again, the emergency flow entries remain. The controller then has the option of deleting all flow entries, if desired. +\\\\ +The first time a switch starts up, it is considered to be in emergency mode. Configuration of the default set of flow entries is outside the scope of the OpenFlow protocol. + +\subsection{Encryption} +The switch and controller communicate through a TLS connection. The TLS connection is initiated by the switch on startup to the controller's server, which is located by default on TCP port \input{define/OFP_TCP_PORT}. The switch and controller mutually authenticate by exchanging certificates signed by a site-specific private key. Each switch must be user-configurable with one certificate for authenticating the controller (controller certificate) and the other for authenticating to the controller (switch certificate). + +\subsection{Spanning Tree} +\label{flow_table:stp_support} +OpenFlow switches may optionally support 802.1D Spanning Tree Protocol. Those switches that do support it are expected to process all 802.1D packets locally before performing flow lookup. A switch that implements STP must set the \verb|OFPC_STP| bit in the 'capabilities' field of its \verb|OFPT_FEATURES_REPLY| message. A switch that implements STP must make it available on all of its physical ports, but it need not implement it on virtual ports (e.g. \verb|OFPP_LOCAL|). +\\\\ +Port status, as specified by the spanning tree protocol, is then used to limit packets forwarded to the \verb|OFP_FLOOD| port to only those ports along the spanning tree. Port changes as a result of the spanning tree are sent to the controller via port-update messages. Note that forward actions that specify the outgoing port or \verb|OFP_ALL| ignore the port status set by the spanning tree protocol. Packets received on ports that are disabled by spanning tree must follow the normal flow table processing path. +\\\\ +Switches that do not support 802.1D spanning tree must allow the controller to specify the port status for packet flooding through the port-mod messages. + +\subsection{Flow Table Modification Messages} +\label{flow_table:sec_chan:flow_add} +\label{flow_table:sec_chan:flow_mod} +\label{flow_table:sec_chan:flow_removal} +Flow table modification messages can have the following types: +\input{enum/ofp_flow_mod_command} +For ADD requests with the \verb|OFPFF_CHECK_OVERLAP| flag set, the switch must first check for any overlapping flow entries. Two flow entries overlap if a single packet may match both, and both entries have the same priority. If an overlap conflict exists between an existing flow entry and the ADD request, the switch must refuse the addition and respond with an \verb|ofp_error_msg| with \verb|OFPET_FLOW_MOD_FAILED| type and \verb|OFPFMFC_OVERLAP| code. +\\\\ +For valid (non-overlapping) ADD requests, or those with no overlap checking, the switch must insert the flow entry at the lowest numbered table for which the switch supports all wildcards set in the \verb|flow_match| struct, and for which the priority would be observed during the matching process. If a flow entry with identical header fields and priority already resides in any table, then that entry, including its counters, must be removed, and the new flow entry added. +\\\\ +If a switch cannot find any table in which to add the incoming flow entry, the switch should send an \verb|ofp_error_msg| with \verb|OFPET_FLOW_MOD_FAILED| type and \verb|OFPFMFC_ALL_TABLES_FULL| code. +\\\\ +If the action list in a flow mod message references a port that will never be valid on a switch, the switch must return an \verb|ofp_error_msg| with \verb|OFPET_BAD_ACTION| type and \verb|OFPBAC_BAD_OUT_PORT| code. If the referenced port may be valid in the future, e.g. when a linecard is added to a chassis switch, or a port is dynamically added to a software switch, the switch may either silently drop packets sent to the referenced port, or immediately return an \verb|OFPBAC_BAD_OUT_PORT| error and refuse the flow mod. +\\\\ +For MODIFY requests, if a flow entry with identical header fields does not current reside in any table, the MODIFY acts like an ADD, and the new flow entry must be inserted with zeroed counters. Otherwise, the actions field is changed on the existing entry and its counters and idle time fields are left unchanged. +\\\\ +For DELETE requests, if no flow entry matches, no error is recorded, and no flow table modification occurs. If flow entries match, and must be deleted, then each normal entry with the \verb|OFPFF_SEND_FLOW_REM| flag set should generate a flow removed message. Deleted emergency flow entries generate no flow removed messages. +\\\\ +MODIFY and DELETE flow mod commands have corresponding \_STRICT versions. Without \_STRICT appended, the wildcards are active and all flows that match the description are modified or removed. If \_STRICT is appended, all fields, including the wildcards and priority, are strictly matched against the entry, and only an identical flow is modified or removed. For example, if a message to remove entries is sent that has all the wildcard flags set, the DELETE command would delete all flows from all tables, while the DELETE\_STRICT command would only delete a rule that applies to all packets at the specified priority. +\\\\ +For non-strict MODIFY and DELETE commands that contain wildcards, a match will occur when a flow entry exactly matches or is more specific than the description in the flow\_mod command. For example, if a DELETE command says to delete all flows with a destination port of 80, then a flow entry that is all wildcards will not be deleted. However, a DELETE command that is all wildcards will delete an entry that matches all port 80 traffic. This same interpretation of mixed wildcard and exact header fields also applies to individual and aggregate flows stats. +\\\\ +DELETE and DELETE\_STRICT commands can be optionally filtered by output port. If the \verb|out_port| field contains a value other than \verb|OFPP_NONE|, it introduces a constraint when matching. This constraint is that the rule must contain an output action directed at that port. This field is ignored by ADD, MODIFY, and MODIFY\_STRICT messages. +\\\\ +Emergency flow mod messages must have timeout values set to zero. Otherwise, the switch must refuse the addition and respond with an \verb|ofp_error_msg| with \verb|OFPET_FLOW_MOD_FAILED| type and \verb|OFPFMFC_BAD_EMERG_TIMEOUT| code. +\\\\ +\label{unsupported_flow}If a switch cannot process the action list for any flow mod message in the order specified, it MUST immediately return an \verb|OFPET_FLOW_MOD_FAILED| : +\verb|OFPFMFC_UNSUPPORTED| error and reject the flow. + +\subsection{Flow Removal} + +Each flow entry has an \verb|idle_timeout| and a \verb|hard_timeout| associated with it. If no packet has matched the rule in the last \verb|idle_timeout| seconds, or it has been \verb|hard_timeout| seconds since the flow was inserted, the switch removes the entry and sends a flow removed message. In addition, the controller is able to actively remove entries by sending a flow message with the \verb|DELETE| or \verb|DELETE_STRICT| command. Like the message used to add the entry, a removal message contains a description, which may include wild cards. + +\input{appendix} + +\input{credits} + +\end{document} diff --git a/openflow/doc/of-spec/packet_flow_flowchart.graffle b/openflow/doc/of-spec/packet_flow_flowchart.graffle new file mode 100644 index 00000000..57a76098 --- /dev/null +++ b/openflow/doc/of-spec/packet_flow_flowchart.graffle @@ -0,0 +1,1887 @@ + + + + + ActiveLayerIndex + 0 + ApplicationVersion + + com.omnigroup.OmniGraffle + 138.12.0.121252 + + AutoAdjust + + BackgroundGraphic + + Bounds + {{0, 0}, {756, 553}} + Class + SolidGraphic + ID + 2 + Style + + shadow + + Draws + NO + + stroke + + Draws + NO + + + + CanvasOrigin + {0, 0} + ColumnAlign + 1 + ColumnSpacing + 36 + CreationDate + 2009-11-20 14:54:05 -0800 + Creator + brandonh + DisplayScale + 1 0/72 in = 1 0/72 in + GraphDocumentVersion + 6 + GraphicsList + + + Class + LineGraphic + Head + + ID + 50 + + ID + 67 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {104.25, 130.5} + {141.75, 130.5} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 66 + + + + Bounds + {{5.25, 99}, {99, 63}} + Class + ShapedGraphic + ID + 66 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Rectangle + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 Packet in from network} + + VFlip + YES + + + Bounds + {{470.5, 317.375}, {30.1875, 14}} + Class + ShapedGraphic + FitText + Vertical + Flow + Resize + ID + 64 + Shape + Rectangle + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Pad + 0 + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 no} + VerticalPad + 0 + + + + Bounds + {{470.5, 192.5}, {30.1875, 14}} + Class + ShapedGraphic + FitText + Vertical + Flow + Resize + ID + 63 + Shape + Rectangle + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Pad + 0 + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 no} + VerticalPad + 0 + + + + Bounds + {{521.062, 277}, {30.1875, 14}} + Class + ShapedGraphic + FitText + Vertical + Flow + Resize + ID + 62 + Shape + Rectangle + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Pad + 0 + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 yes} + VerticalPad + 0 + + + + Class + LineGraphic + Head + + ID + 55 + Position + 0.46666735410690308 + + ID + 61 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {514.5, 268.5} + {535.5, 130.5} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 52 + Info + 3 + + + + Bounds + {{514.5, 105.438}, {30.1875, 14}} + Class + ShapedGraphic + FitText + Vertical + Flow + Resize + ID + 60 + Shape + Rectangle + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Pad + 0 + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 yes} + VerticalPad + 0 + + + + Class + LineGraphic + Head + + ID + 53 + + ID + 57 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {460.5, 322.5} + {460.5, 345} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 52 + Info + 1 + + + + Class + LineGraphic + Head + + ID + 52 + + ID + 56 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {460.5, 184.5} + {460.5, 214.5} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + Pattern + 2 + TailArrow + 0 + + + Tail + + ID + 47 + + + + Class + LineGraphic + Head + + ID + 54 + + ID + 55 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {514.5, 130.5} + {559.5, 130.5} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 47 + Info + 3 + + + + Bounds + {{559.5, 99}, {99, 63}} + Class + ShapedGraphic + ID + 54 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Rectangle + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 Apply actions} + + VFlip + YES + + + Bounds + {{411, 345}, {99, 63}} + Class + ShapedGraphic + ID + 53 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Rectangle + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 Send to controller via Secure Channel} + + VFlip + YES + + + Bounds + {{406.5, 214.5}, {108, 108}} + Class + ShapedGraphic + ID + 52 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Diamond + Style + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 Match table N?} + VerticalPad + 0 + + + + Class + LineGraphic + Head + + ID + 35 + Info + 4 + + ID + 51 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {240.75, 130.5} + {271.5, 130.5} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 50 + Info + 3 + + + + Bounds + {{141.75, 99}, {99, 63}} + Class + ShapedGraphic + ID + 50 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Rectangle + Style + + stroke + + Pattern + 1 + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 Optional\ +802.1d STP processing} + + VFlip + YES + + + Class + LineGraphic + Head + + ID + 47 + + ID + 49 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {370.5, 130.5} + {406.5, 130.5} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 35 + + + + Bounds + {{271.5, 99}, {99, 63}} + Class + ShapedGraphic + ID + 35 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Rectangle + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 Parse header fields\ +(see below)} + + VFlip + YES + + + Bounds + {{406.5, 76.5}, {108, 108}} + Class + ShapedGraphic + ID + 47 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Diamond + Style + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 Match table 0?} + VerticalPad + 0 + + + + GridInfo + + GuidesLocked + NO + GuidesVisible + YES + HPages + 1 + ImageCounter + 1 + KeepToScale + + Layers + + + Lock + NO + Name + Layer 1 + Print + YES + View + YES + + + LayoutInfo + + Animate + NO + circoMinDist + 18 + circoSeparation + 0.0 + layoutEngine + dot + neatoSeparation + 0.0 + twopiSeparation + 0.0 + + LinksVisible + NO + MagnetsVisible + NO + MasterSheets + + ModificationDate + 2009-11-20 15:11:07 -0800 + Modifier + brandonh + NotesVisible + NO + Orientation + 2 + OriginVisible + NO + PageBreaks + YES + PrintInfo + + NSBottomMargin + + float + 41 + + NSLeftMargin + + float + 18 + + NSOrientation + + int + 1 + + NSPaperSize + + size + {792, 612} + + NSRightMargin + + float + 18 + + NSTopMargin + + float + 18 + + + PrintOnePage + + QuickLookPreview + + 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 + ago8PCAvUHJvY1NldCBbIC9QREYgL1RleHQgL0ltYWdlQiAvSW1hZ2VDIC9JbWFnZUkg + XSAvQ29sb3JTcGFjZSA8PCAvQ3MyIDIzIDAgUgovQ3MxIDggMCBSID4+IC9Gb250IDw8 + IC9GMS4wIDI0IDAgUiA+PiAvWE9iamVjdCA8PCAvSW0xIDkgMCBSIC9JbTYgMTkgMCBS + Ci9JbTQgMTUgMCBSIC9JbTUgMTcgMCBSIC9JbTMgMTMgMCBSIC9JbTIgMTEgMCBSIC9J + bTcgMjEgMCBSID4+ID4+CmVuZG9iago5IDAgb2JqCjw8IC9MZW5ndGggMTAgMCBSIC9U + eXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMjYwIC9IZWlnaHQgMjYw + IC9Db2xvclNwYWNlCjI1IDAgUiAvU01hc2sgMjYgMCBSIC9CaXRzUGVyQ29tcG9uZW50 + IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7dAxAQAAAMKg9U/taQmI + QGHAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDgAwMYXQABCmVuZHN0cmVhbQplbmRvYmoKMTAgMCBvYmoK + OTA4CmVuZG9iagoxOSAwIG9iago8PCAvTGVuZ3RoIDIwIDAgUiAvVHlwZSAvWE9iamVj + dCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRoIDI0MiAvSGVpZ2h0IDE3MCAvQ29sb3JTcGFj + ZQoyOCAwIFIgL1NNYXNrIDI5IDAgUiAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIg + L0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae3QMQEAAADCoPVPbQo/iEBhwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwa+AwPiKwABCmVuZHN0cmVhbQplbmRvYmoKMjAgMCBvYmoK + NTYyCmVuZG9iagoxNSAwIG9iago8PCAvTGVuZ3RoIDE2IDAgUiAvVHlwZSAvWE9iamVj + dCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRoIDI2MCAvSGVpZ2h0IDI2MCAvQ29sb3JTcGFj + ZQoyNSAwIFIgL1NNYXNrIDMxIDAgUiAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIg + L0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae3QMQEAAADCoPVP7WkJiEBhwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBg4AMDGF0AAQplbmRzdHJlYW0KZW5kb2JqCjE2IDAgb2JqCjkwOAplbmRvYmoK + MTcgMCBvYmoKPDwgL0xlbmd0aCAxOCAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUg + L0ltYWdlIC9XaWR0aCAyNDIgL0hlaWdodCAxNzAgL0NvbG9yU3BhY2UKMjggMCBSIC9T + TWFzayAzMyAwIFIgL0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29k + ZSA+PgpzdHJlYW0KeAHt0DEBAAAAwqD1T20KP4hAYcCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGvgMD4isAAQplbmRzdHJlYW0KZW5kb2JqCjE4IDAgb2JqCjU2MgplbmRvYmoK + MTMgMCBvYmoKPDwgL0xlbmd0aCAxNCAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUg + L0ltYWdlIC9XaWR0aCAyNDIgL0hlaWdodCAxNzAgL0NvbG9yU3BhY2UKMzUgMCBSIC9T + TWFzayAzNiAwIFIgL0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29k + ZSA+PgpzdHJlYW0KeAHt0DEBAAAAwqD1T20KP4hAYcCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGvgMD4isAAQplbmRzdHJlYW0KZW5kb2JqCjE0IDAgb2JqCjU2MgplbmRvYmoK + MTEgMCBvYmoKPDwgL0xlbmd0aCAxMiAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUg + L0ltYWdlIC9XaWR0aCAyNDIgL0hlaWdodCAxNzAgL0NvbG9yU3BhY2UKMjggMCBSIC9T + TWFzayAzOCAwIFIgL0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29k + ZSA+PgpzdHJlYW0KeAHt0DEBAAAAwqD1T20KP4hAYcCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGvgMD4isAAQplbmRzdHJlYW0KZW5kb2JqCjEyIDAgb2JqCjU2MgplbmRvYmoK + MjEgMCBvYmoKPDwgL0xlbmd0aCAyMiAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUg + L0ltYWdlIC9XaWR0aCAyNDIgL0hlaWdodCAxNzAgL0NvbG9yU3BhY2UKMjggMCBSIC9T + TWFzayA0MCAwIFIgL0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29k + ZSA+PgpzdHJlYW0KeAHt0DEBAAAAwqD1T20KP4hAYcCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGvgMD4isAAQplbmRzdHJlYW0KZW5kb2JqCjIyIDAgb2JqCjU2MgplbmRvYmoK + NDAgMCBvYmoKPDwgL0xlbmd0aCA0MSAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUg + L0ltYWdlIC9XaWR0aCAyNDIgL0hlaWdodCAxNzAgL0NvbG9yU3BhY2UKL0RldmljZUdy + YXkgL0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJl + YW0KeAHtnf9PU9cbx/lS6Lfb215ob8ttu5ZbCr0tpbsCVkAHBIIi4BcUVzchaNUMBnYa + G5uhDsOU2CiCg/AlioyIBhwBQ5AQNZ9/7fOcYrZRim6/9azP+wfiTTB5Xuf9nPc5vSR9 + srJQuAK4ArgCuAL0rkA21fpX6w6kOX8plzL9VXkOgPwD8B1aoFQo8iiWQgEIBP5L0Ane + Hdh8pVK1IzVF+lSyUpkPdgH2F5g/8ebl5QOsWqPRarUMw+ioEhQMZWs0apWKUH+emQDn + Qi8DLsAyOpbVGwwcdTIY9CyrA24NQO8w79PaCWDwl/DqWD3HFRQajSYTz5spEs+bTEZj + YQHH6VkdYQafobVTIxOHicGE1wC0vNlSJAhWm81OkWw2qyAUWcw8UBsSzGAzQU4R2glg + 2MBaBngBF1jtDqezWHRRJbHY6XTYgRuggZnRku2cGjmb7GGlGgzmCnmLALSiy11a5pEk + r9dHibxeSfKUlbpdIlALFr6QA5vVSpJfe00GiwFYpdXpOaNZsDvFklLJW+4PBGRZPkCN + oNhAwF/ulUpLRKddMBs5vQ5czlOk6GuwGEJLkwC2OkS3x+cPyJXVB4M1taA6KkQqrQke + rK6UA36fxy06rAlkDcRXCpOzwWKVhmE5o8XqcJX5KuSqYE3dkfqGxqampmZKBKU2NtQf + qasJVskVvjKXw2oxciyjUYHJyW29Y7EWgM1WZ4nkl6sO1dU3Nrcca21r7zhBjTra21qP + tTQ31tcdqpL9UomTuMxqU5lMiKGnDQDsKJEClcHDDU1Hj3ec7DzTdS5Ekc51nek82XH8 + aFPD4WBlQCohjW3Qgcl72hqaOl+lZQt4weGSKqpq65tb20+fDX3f3dN7KRy+TInC4Uu9 + Pd3fh86ebm9trq+tqpBcDoEvICbvaevsHDiZwGKLXSzzV9Y2tLSd6jrf3Ru+2vfjwOC1 + CCW6NjjwY9/VcG/3+a5TbS0NtZX+MtFuAZPhhEreyKSpYRfzgtPtk4P1Le2doQsXr/QN + RG7cjN6KUaNb0Zs3IgN9Vy5eCHW2t9QHZZ/bKfBkJ0Nb7752JYj1hWa76KmoOtwMwD3h + vsHr0djQnbvD96jR8N07Q7Ho9cG+cA8gNx+uqvCIdnOhPiVxvpoxGIscJT75UEPrqVDP + 5f5INHZneOT+6MM4NXo4en9k+E4sGum/3BM61dpwSPaVOIqMBkadv8djRb5aR5q61F9V + 19TRdSHc/1N0aPjX0fjjJ+NPqdH4k8fx0V+Hh6I/9YcvdHU01VX5S0lb69QQXUldrVBq + 2AKzTfQEgt8cPX3+4g+R6NC9B/GxicmpmZlZSjQzMzU5MRZ/cG8oGvnh4vnTR78JBjyi + zVzAapQpiLUsbGOXV65pPH62+8oAAI8+Gp+cnns2/2KBEr2YfzY3PTn+aBSQB650nz3e + WCN7XbCRWW0KYohqY9FX7vJKaOpQb9/12C8PHk1MzT5fWHy59IoSLb1cXHg+OzXx6MEv + set9vSFo68py91dFRgjrPR7D4aQ3km1cfaTl5Hfhgejtkfj41Nz870uvl1feUKKV5ddL + v8/PTY3HR25HB8LfnWw5Uk02spGEdfI+BmIDEJcFgvXHOruvRmLDo2OTs/OLr1berK6t + U6K11TcrrxbnZyfHRodjkavdncfqg4EyIDakJGYMJqEYgquh9UxP342fR+IT088BeHX9 + 7QY1eru+CsjPpyfiIz/f6Os509oA0VUsmAxMKo8ZzmQVpa9rGtu6evtv3r7/+Le5haXl + 1fWNzXdblOjd5sb66vLSwtxvj+/fvtnf29XWWPO1JFpN3D7EvE2U5Nqm9nOXBqJ3R8em + ni2+/mNtY3NrmxptbW6s/fF68dnU2Ojd6MClc+1NtbIk2vj9ieFwAuJvw4O3hh8+mZ5/ + ubz6FoDff6BE77e3Nt+uLr+cn37ycPjWYPhbQux1fZG4IxS+FrsXn5h5sbSytvEOgD9S + og/vt99trK0svZiZiN+LXQvD8bQfMXxYVDEcb0t4nIL4f1To4+eJd733yc7Ng2s1XLl8 + B+qaT4QuR8Djp7MLr96sb2xtf/hIBS8U+fHD9tbG+ptXC7NPwePI5dCJ5roDPrh0wcU6 + LxeJ0WPsahr2Mu5jTK6/vQXB0wnPYxpiC28geOfCWyZ+ksDPTlSkNd4y8ZaJt0x864Pv + udI/rjGrMasxqzGrMasxq9NvBfB0wtMJTyc8nfB0Sr9sTq4IsxqzGrMasxqzOjkZ0+8Z + sxqzGrMasxqzOv2yObkizGrMasxqzGrM6uRkTL9nzGrMasxqzGrM6vTL5uSKMKsxqzGr + Masxq5OTMf2eMasxqzGrMasxq9Mvm5MrwqzGrMasxqzGrE5OxvR7xqzGrMasxqzGrE6/ + bE6uCLMasxqzGrMaszo5GdPvGbMasxqzGrP6v53VGfdtzllfIP7vfWP3LuKM+lb2TPvm + /YybrpBxEzQyb0pKpk3CUWTctCOFMuMmWmXe1LKMm0yXm3HTB8lMzQybMJlpU0Qzb1Js + Jk4DzryJz2RweyZN9c7KuMntQExM1uj0ZHa7Q3R7fP6AXFl9MFhDZt7XUSFSaU3wYHWl + HPD7PG6RDDHn9DDFPH/vGPMsIM5R5ClV2gSyYHeKJaWSt9wfCMiyfIAaQbGBgL/cK5WW + iE67kADWqpR5ipzkod7wsh5MBmS1VsdyhbxFsDucostdWuaRJK/XR4m8XknylJW6XaLT + YRcsfCHH6rQww1yxZ1I9+esEmAx9DS4zrKHAyJsFqw2oncWiiyqJxU6gtVkFM28sMLAM + OEx6OoXFn5ChsTVgs6GgEKAtRQJw2+wUyQasQpEFcAuBV6fVQEvvB5yVnXAZ4ivBrOc4 + oDaaTDxvpkg8bzIZgZbj9AleCK0E8K7Jg3/+wS2BrMgDm4FZy+hYVm8wcNTJYNCzrI7R + gr/EYNjDOdmpgaGvwWWSX2Q7q9QawNYyDKOjSlAwlK3RqAEX/CW8+wOT+NphBmigBuyE + 1BTpU8lKQpun+CJvIrIJc05ubq6CYFMrgM0l9n7W37/t5wQ1+X0Q/E+qtFN14mf2vvv3 + T9Zd/4Dfp1i7UPABVwBXAFcAV4CyFfg/bog27wplbmRzdHJlYW0KZW5kb2JqCjQxIDAg + b2JqCjIzMjAKZW5kb2JqCjMxIDAgb2JqCjw8IC9MZW5ndGggMzIgMCBSIC9UeXBlIC9Y + T2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMjYwIC9IZWlnaHQgMjYwIC9Db2xv + clNwYWNlCi9EZXZpY2VHcmF5IC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxh + dGVEZWNvZGUgPj4Kc3RyZWFtCngB7d3/U1JZFADwvijyTURFVJKVomxxILQwU7I0Gr+3 + Wg4jfTOcMqNGLR1aR8sp1Cmx8kvluOZoTuygmWnqqG27s//anvuwTBcUFd6798L5JQ1K + +Hjuue894Jw9e8IRFggLhAXCAmGBsEBYICyAkcBeFPsgmC8wemAsPZTVZw8A+/cjBgj4 + K5Z+OBY/xvPr378/IiIiEgL+8EiEkAJaAAAAz57Hi4Lg8RAEwxAiqYCSAAHwovh8vkAg + FAoE8EUUOETAsgiJVGAIGAGBUCQSR0OIRSKhgFEIDQQggCTg8flCkVgiiZHGQkhjJBKx + SMjn81AqUJ8JHoIoEIiWSGPjZLIECJksLlYqiQaFqBBAWCUQQA5I42QJiUkKJpISE2Rx + UsgFAf0IHgK+QIQE5EmKFGWqCiJVmaJIkiMFkYBPeSasEghFkth4edIBpeqQ+kgaxBH1 + IZXyQJI8PlYC64FqhO8EYkmsLFGhVKnTNOla3bFjOm26Jk2tUioSZbESMdUIPwhi4hKS + U5CAVp95wpCVZTiRqdcihZTkhLgYmhF+IpArlAfTNLpMQ3auMQ/CmJttyNRp0g4qFXKa + EdYI4uWKX9RHtRmGU8az584XQpw/d9Z4ypChPar+RSGPpzYTfiJIVKSqNbrj2cZ8U1Fp + eQVEeWmRKd+YfVynUacqEmlFWE9wWKM35JwxFZdXVpktEOaqyvJi05kcg15zmFqEdQQq + RJCbX1hWabZcq7HW1lprrlnMlWWF+bkIQUVnJmwgSNdnGQuKL1RZrtfeqrfdvWurv1V7 + 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 + 1lyzmCvLCvNzYd4oedcO/SPYgJB6GBByzpiKyyurzBYIc1VlebHpTA4iSCXt8qm/BBsR + 1Brd8WxjvqmotLwCory0yJRvzD6u06gpJliHIIfJyUe1GYZTxrPnzhdCnD931njKkKE9 + CtOH5WRdRPc/C9A91wojTNBWHkzT6DIN2bnGPAhjbrYhU6dJO6hkRnET9DrC9gjWISQk + p6jUaRqtPvOEISvLcCJTr9WkqVUpyQlrI9lxfXF9u097/f1/ZAJM0U5UKJFCulZ37JhO + m44ElIpEmEBN0qtJ65+ef999R4BR4vHypANK1SH1kTSII+pDKuWBJHk8zF6meCF4kFYR + BCKJNE4mT1KkKFNVEKnKFEWSXBYnhYn0eL/LxL/f9eb38iBECURipJCQmKRgIikxAQmI + RWgMOcZvtNn8yfl76yoCXyiKlkhj42SyBAiZLC5WKomGdRAKBN93Bx4fFMQSSYw0FkIa + I4EcEPL5vBDIApQtkAkwJTGSF8UXCEUicTSEWCQSCvhRvEgYw47vO878TXV/7scgRDAK + fL5AIBQKBHw+IwClIDQIUCrsg1SAsS/gwIuC4EEGwCoAAW/Ddv1xJfA+KBUYhggEERkR + 4QEImSTw/Mr2ehgYCeQBAX9F4K9zlw8ZnrRHgvlil/9Z+J+HBcICYYGwQFggLBAWCAsE + VuA/SCo8XAplbmRzdHJlYW0KZW5kb2JqCjMyIDAgb2JqCjM3MTEKZW5kb2JqCjI5IDAg + b2JqCjw8IC9MZW5ndGggMzAgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFn + ZSAvV2lkdGggMjQyIC9IZWlnaHQgMTcwIC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5IC9C + aXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB + 7Z3/T1PXG8f5Uui329teaG/LbbuWWwq9LaW7AlZABwSCIuAXFFc3IWjVDAZ2GhuboQ7D + lNgogoPwJYqMiAYcAUOQEDWff+3znGK2UYpuv/Wsz/sH4k0weV7n/Zz3Ob0kfbKyULgC + uAK4ArgC9K5ANtX6V+sOpDl/KZcy/VV5DoD8A/AdWqBUKPIolkIBCAT+S9AJ3h3YfKVS + tSM1RfpUslKZD3YB9heYP/Hm5eUDrFqj0Wq1DMPoqBIUDGVrNGqVilB/npkA50IvAy7A + MjqW1RsMHHUyGPQsqwNuDUDvMO/T2glg8Jfw6lg9xxUUGo0mE8+bKRLPm0xGY2EBx+lZ + HWEGn6G1UyMTh4nBhNcAtLzZUiQIVpvNTpFsNqsgFFnMPFAbEsxgM0FOEdoJYNjAWgZ4 + ARdY7Q6ns1h0USWx2Ol02IEboIGZ0ZLtnBo5m+xhpRoM5gp5iwC0ostdWuaRJK/XR4m8 + XknylJW6XSJQCxa+kAOb1UqSX3tNBosBWKXV6TmjWbA7xZJSyVvuDwRkWT5AjaDYQMBf + 7pVKS0SnXTAbOb0OXM5TpOhrsBhCS5MAtjpEt8fnD8iV1QeDNbWgOipEKq0JHqyulAN+ + n8ctOqwJZA3EVwqTs8FilYZhOaPF6nCV+SrkqmBN3ZH6hsampqZmSgSlNjbUH6mrCVbJ + Fb4yl8NqMXIso1GBycltvWOxFoDNVmeJ5JerDtXVNza3HGtta+84QY062ttaj7U0N9bX + HaqS/VKJk7jMalOZTIihpw0A7CiRApXBww1NR493nOw803UuRJHOdZ3pPNlx/GhTw+Fg + ZUAqIY1t0IHJe9oamjpfpWULeMHhkiqqauubW9tPnw19393TeykcvkyJwuFLvT3d34fO + nm5vba6vraqQXA6BLyAm72nr7Bw4mcBii10s81fWNrS0neo6390bvtr348DgtQglujY4 + 8GPf1XBv9/muU20tDbWV/jLRbgGT4YRK3sikqWEX84LT7ZOD9S3tnaELF6/0DURu3Ize + ilGjW9GbNyIDfVcuXgh1trfUB2Wf2ynwZCdDW+++diWI9YVmu+ipqDrcDMA94b7B69HY + 0J27w/eo0fDdO0Ox6PXBvnAPIDcfrqrwiHZzoT4lcb6aMRiLHCU++VBD66lQz+X+SDR2 + Z3jk/ujDODV6OHp/ZPhOLBrpv9wTOtXacEj2lTiKjAZGnb/HY0W+WkeautRfVdfU0XUh + 3P9TdGj419H44yfjT6nR+JPH8dFfh4eiP/WHL3R1NNVV+UtJW+vUEF1JXa1QatgCs030 + BILfHD19/uIPkejQvQfxsYnJqZmZWUo0MzM1OTEWf3BvKBr54eL500e/CQY8os1cwGqU + KYi1LGxjl1euaTx+tvvKAACPPhqfnJ57Nv9igRK9mH82Nz05/mgUkAeudJ893lgje12w + kVltCmKIamPRV+7ySmjqUG/f9dgvDx5NTM0+X1h8ufSKEi29XFx4Pjs18ejBL7Hrfb0h + aOvKcvdXRUYI6z0ew+GkN5JtXH2k5eR34YHo7ZH4+NTc/O9Lr5dX3lCileXXS7/Pz02N + x0duRwfC351sOVJNNrKRhHXyPgZiAxCXBYL1xzq7r0Ziw6Njk7Pzi69W3qyurVOitdU3 + K68W52cnx0aHY5Gr3Z3H6oOBMiA2pCRmDCahGIKrofVMT9+Nn0fiE9PPAXh1/e0GNXq7 + vgrIz6cn4iM/3+jrOdPaANFVLJgMTCqPGc5kFaWvaxrbunr7b96+//i3uYWl5dX1jc13 + W5To3ebG+ury0sLcb4/v377Z39vV1ljztSRaTdw+xLxNlOTapvZzlwaid0fHpp4tvv5j + bWNza5sabW1urP3xevHZ1Njo3ejApXPtTbWyJNr4/YnhcALib8ODt4YfPpmef7m8+haA + 33+gRO+3tzbfri6/nJ9+8nD41mD4W0LsdX2RuCMUvha7F5+YebG0srbxDoA/UqIP77ff + baytLL2YmYjfi10Lw/G0HzF8WFQxHG9LeJyC+H9U6OPniXe998nOzYNrNVy5fAfqmk+E + LkfA46ezC6/erG9sbX/4SAUvFPnxw/bWxvqbVwuzT8HjyOXQiea6Az64dMHFOi8XidFj + 7Goa9jLuY0yuv70FwdMJz2MaYgtvIHjnwlsmfpLAz05UpDXeMvGWibdMfOuD77nSP64x + qzGrMasxqzGrMavTbwXwdMLTCU8nPJ3wdEq/bE6uCLMasxqzGrMaszo5GdPvGbMasxqz + GrMaszr9sjm5IsxqzGrMasxqzOrkZEy/Z8xqzGrMasxqzOr0y+bkijCrMasxqzGrMauT + kzH9njGrMasxqzGrMavTL5uTK8KsxqzGrMasxqxOTsb0e8asxqzGrMasxqxOv2xOrgiz + GrMasxqzGrM6ORnT7xmzGrMasxqz+r+d1Rn3bc5ZXyD+731j9y7ijPpW9kz75v2Mm66Q + cRM0Mm9KSqZNwlFk3LQjhTLjJlpl3tSyjJtMl5tx0wfJTM0MmzCZaVNEM29SbCZOA868 + ic9kcHsmTfXOyrjJ7UBMTNbo9GR2u0N0e3z+gFxZfTBYQ2be11EhUmlN8GB1pRzw+zxu + kQwx5/QwxTx/7xjzLCDOUeQpVdoEsmB3iiWlkrfcHwjIsnyAGkGxgYC/3CuVlohOu5AA + 1qqUeYqc5KHe8LIeTAZktVbHcoW8RbA7nKLLXVrmkSSv10eJvF5J8pSVul2i02EXLHwh + x+q0MMNcsWdSPfnrBJgMfQ0uM6yhwMibBasNqJ3FoosqicVOoLVZBTNvLDCwDDhMejqF + xZ+QobE1YLOhoBCgLUUCcNvsFMkGrEKRBXALgVen1UBL7weclZ1wGeIrwaznOKA2mkw8 + b6ZIPG8yGYGW4/QJXgitBPCuyYN//sEtgazIA5uBWcvoWFZvMHDUyWDQs6yO0YK/xGDY + wznZqYGhr8Flkl9kO6vUGsDWMgyjo0pQMJSt0agBF/wlvPsDk/jaYQZooAbshNQU6VPJ + SkKbp/gibyKyCXNObm6ugmBTK4DNJfZ+1t+/7ecENfl9EPxPqrRTdeJn9r7790/WXf+A + 36dYu1DwAVcAVwBXAFeAshX4P26INu8KZW5kc3RyZWFtCmVuZG9iagozMCAwIG9iagoy + MzIwCmVuZG9iagozOCAwIG9iago8PCAvTGVuZ3RoIDM5IDAgUiAvVHlwZSAvWE9iamVj + dCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRoIDI0MiAvSGVpZ2h0IDE3MCAvQ29sb3JTcGFj + ZQovRGV2aWNlR3JheSAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIgL0ZsYXRlRGVj + b2RlID4+CnN0cmVhbQp4Ae2d/09T1xvH+VLot9vbXmhvy227llsKvS2luwJWQAcEgiLg + FxRXNyFo1QwGdhobm6EOw5TYKIKD8CWKjIgGHAFDkBA1n3/t85xitlGKbr/1rM/7B+JN + MHle5/2c9zm9JH2yslC4ArgCuAK4AvSuQDbV+lfrDqQ5fymXMv1VeQ6A/APwHVqgVCjy + KJZCAQgE/kvQCd4d2HylUrUjNUX6VLJSmQ92AfYXmD/x5uXlA6xao9FqtQzD6KgSFAxl + azRqlYpQf56ZAOdCLwMuwDI6ltUbDBx1Mhj0LKsDbg1A7zDv09oJYPCX8OpYPccVFBqN + JhPPmykSz5tMRmNhAcfpWR1hBp+htVMjE4eJwYTXALS82VIkCFabzU6RbDarIBRZzDxQ + GxLMYDNBThHaCWDYwFoGeAEXWO0Op7NYdFElsdjpdNiBG6CBmdGS7ZwaOZvsYaUaDOYK + eYsAtKLLXVrmkSSv10eJvF5J8pSVul0iUAsWvpADm9VKkl97TQaLAVil1ek5o1mwO8WS + Uslb7g8EZFk+QI2g2EDAX+6VSktEp10wGzm9DlzOU6Toa7AYQkuTALY6RLfH5w/IldUH + gzW1oDoqRCqtCR6srpQDfp/HLTqsCWQNxFcKk7PBYpWGYTmjxepwlfkq5KpgTd2R+obG + pqamZkoEpTY21B+pqwlWyRW+MpfDajFyLKNRgcnJbb1jsRaAzVZnieSXqw7V1Tc2txxr + bWvvOEGNOtrbWo+1NDfW1x2qkv1SiZO4zGpTmUyIoacNAOwokQKVwcMNTUePd5zsPNN1 + LkSRznWd6TzZcfxoU8PhYGVAKiGNbdCByXvaGpo6X6VlC3jB4ZIqqmrrm1vbT58Nfd/d + 03spHL5MicLhS7093d+Hzp5ub22ur62qkFwOgS8gJu9p6+wcOJnAYotdLPNX1ja0tJ3q + Ot/dG77a9+PA4LUIJbo2OPBj39Vwb/f5rlNtLQ21lf4y0W4Bk+GESt7IpKlhF/OC0+2T + g/Ut7Z2hCxev9A1EbtyM3opRo1vRmzciA31XLl4Idba31Adln9sp8GQnQ1vvvnYliPWF + Zrvoqag63AzAPeG+wevR2NCdu8P3qNHw3TtDsej1wb5wDyA3H66q8Ih2c6E+JXG+mjEY + ixwlPvlQQ+upUM/l/kg0dmd45P7owzg1ejh6f2T4Tiwa6b/cEzrV2nBI9pU4iowGRp2/ + x2NFvlpHmrrUX1XX1NF1Idz/U3Ro+NfR+OMn40+p0fiTx/HRX4eHoj/1hy90dTTVVflL + SVvr1BBdSV2tUGrYArNN9ASC3xw9ff7iD5Ho0L0H8bGJyamZmVlKNDMzNTkxFn9wbyga + +eHi+dNHvwkGPKLNXMBqlCmItSxsY5dXrmk8frb7ygAAjz4an5yeezb/YoESvZh/Njc9 + Of5oFJAHrnSfPd5YI3tdsJFZbQpiiGpj0Vfu8kpo6lBv3/XYLw8eTUzNPl9YfLn0ihIt + vVxceD47NfHowS+x6329IWjrynL3V0VGCOs9HsPhpDeSbVx9pOXkd+GB6O2R+PjU3Pzv + S6+XV95QopXl10u/z89NjcdHbkcHwt+dbDlSTTaykYR18j4GYgMQlwWC9cc6u69GYsOj + Y5Oz84uvVt6srq1TorXVNyuvFudnJ8dGh2ORq92dx+qDgTIgNqQkZgwmoRiCq6H1TE/f + jZ9H4hPTzwF4df3tBjV6u74KyM+nJ+IjP9/o6znT2gDRVSyYDEwqjxnOZBWlr2sa27p6 + +2/evv/4t7mFpeXV9Y3Nd1uU6N3mxvrq8tLC3G+P79++2d/b1dZY87UkWk3cPsS8TZTk + 2qb2c5cGondHx6aeLb7+Y21jc2ubGm1tbqz98Xrx2dTY6N3owKVz7U21siTa+P2J4XAC + 4m/Dg7eGHz6Znn+5vPoWgN9/oETvt7c2364uv5yffvJw+NZg+FtC7HV9kbgjFL4Wuxef + mHmxtLK28Q6AP1KiD++3322srSy9mJmI34tdC8PxtB8xfFhUMRxvS3icgvh/VOjj54l3 + vffJzs2DazVcuXwH6ppPhC5HwOOnswuv3qxvbG1/+EgFLxT58cP21sb6m1cLs0/B48jl + 0InmugM+uHTBxTovF4nRY+xqGvYy7mNMrr+9BcHTCc9jGmILbyB458JbJn6SwM9OVKQ1 + 3jLxlom3THzrg++50j+uMasxqzGrMasxqzGr028F8HTC0wlPJzyd8HRKv2xOrgizGrMa + sxqzGrM6ORnT7xmzGrMasxqzGrM6/bI5uSLMasxqzGrMaszq5GRMv2fMasxqzGrMaszq + 9Mvm5IowqzGrMasxqzGrk5Mx/Z4xqzGrMasxqzGr0y+bkyvCrMasxqzGrMasTk7G9HvG + rMasxqzGrMasTr9sTq4IsxqzGrMasxqzOjkZ0+8ZsxqzGrMas/q/ndUZ923OWV8g/u99 + Y/cu4oz6VvZM++b9jJuukHETNDJvSkqmTcJRZNy0I4Uy4yZaZd7UsoybTJebcdMHyUzN + DJswmWlTRDNvUmwmTgPOvInPZHB7Jk31zsq4ye1ATEzW6PRkdrtDdHt8/oBcWX0wWENm + 3tdRIVJpTfBgdaUc8Ps8bpEMMef0MMU8f+8Y8ywgzlHkKVXaBLJgd4olpZK33B8IyLJ8 + gBpBsYGAv9wrlZaITruQANaqlHmKnOSh3vCyHkwGZLVWx3KFvEWwO5yiy11a5pEkr9dH + ibxeSfKUlbpdotNhFyx8IcfqtDDDXLFnUj356wSYDH0NLjOsocDImwWrDaidxaKLKonF + TqC1WQUzbywwsAw4THo6hcWfkKGxNWCzoaAQoC1FAnDb7BTJBqxCkQVwC4FXp9VAS+8H + nJWdcBniK8Gs5zigNppMPG+mSDxvMhmBluP0CV4IrQTwrsmDf/7BLYGsyAObgVnL6FhW + bzBw1Mlg0LOsjtGCv8Rg2MM52amBoa/BZZJfZDur1BrA1jIMo6NKUDCUrdGoARf8Jbz7 + A5P42mEGaKAG7ITUFOlTyUpCm6f4Im8isglzTm5uroJgUyuAzSX2ftbfv+3nBDX5fRD8 + T6q0U3XiZ/a++/dP1l3/gN+nWLtQ8AFXAFcAVwBXgLIV+D9uiDbvCmVuZHN0cmVhbQpl + bmRvYmoKMzkgMCBvYmoKMjMyMAplbmRvYmoKMzMgMCBvYmoKPDwgL0xlbmd0aCAzNCAw + IFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUgL0ltYWdlIC9XaWR0aCAyNDIgL0hlaWdo + dCAxNzAgL0NvbG9yU3BhY2UKL0RldmljZUdyYXkgL0JpdHNQZXJDb21wb25lbnQgOCAv + RmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAHtnf9PU9cbx/lS6Lfb215ob8tt + u5ZbCr0tpbsCVkAHBIIi4BcUVzchaNUMBnYaG5uhDsOU2CiCg/AlioyIBhwBQ5AQNZ9/ + 7fOcYrZRim6/9azP+wfiTTB5Xuf9nPc5vSR9srJQuAK4ArgCuAL0rkA21fpX6w6kOX8p + lzL9VXkOgPwD8B1aoFQo8iiWQgEIBP5L0AneHdh8pVK1IzVF+lSyUpkPdgH2F5g/8ebl + 5QOsWqPRarUMw+ioEhQMZWs0apWKUH+emQDnQi8DLsAyOpbVGwwcdTIY9CyrA24NQO8w + 79PaCWDwl/DqWD3HFRQajSYTz5spEs+bTEZjYQHH6VkdYQafobVTIxOHicGE1wC0vNlS + JAhWm81OkWw2qyAUWcw8UBsSzGAzQU4R2glg2MBaBngBF1jtDqezWHRRJbHY6XTYgRug + gZnRku2cGjmb7GGlGgzmCnmLALSiy11a5pEkr9dHibxeSfKUlbpdIlALFr6QA5vVSpJf + e00GiwFYpdXpOaNZsDvFklLJW+4PBGRZPkCNoNhAwF/ulUpLRKddMBs5vQ5czlOk6Guw + GEJLkwC2OkS3x+cPyJXVB4M1taA6KkQqrQkerK6UA36fxy06rAlkDcRXCpOzwWKVhmE5 + o8XqcJX5KuSqYE3dkfqGxqampmZKBKU2NtQfqasJVskVvjKXw2oxciyjUYHJyW29Y7EW + gM1WZ4nkl6sO1dU3Nrcca21r7zhBjTra21qPtTQ31tcdqpL9UomTuMxqU5lMiKGnDQDs + KJEClcHDDU1Hj3ec7DzTdS5Ekc51nek82XH8aFPD4WBlQCohjW3Qgcl72hqaOl+lZQt4 + weGSKqpq65tb20+fDX3f3dN7KRy+TInC4Uu9Pd3fh86ebm9trq+tqpBcDoEvICbvaevs + HDiZwGKLXSzzV9Y2tLSd6jrf3Ru+2vfjwOC1CCW6NjjwY9/VcG/3+a5TbS0NtZX+MtFu + AZPhhEreyKSpYRfzgtPtk4P1Le2doQsXr/QNRG7cjN6KUaNb0Zs3IgN9Vy5eCHW2t9QH + ZZ/bKfBkJ0Nb7752JYj1hWa76KmoOtwMwD3hvsHr0djQnbvD96jR8N07Q7Ho9cG+cA8g + Nx+uqvCIdnOhPiVxvpoxGIscJT75UEPrqVDP5f5INHZneOT+6MM4NXo4en9k+E4sGum/ + 3BM61dpwSPaVOIqMBkadv8djRb5aR5q61F9V19TRdSHc/1N0aPjX0fjjJ+NPqdH4k8fx + 0V+Hh6I/9YcvdHU01VX5S0lb69QQXUldrVBq2AKzTfQEgt8cPX3+4g+R6NC9B/Gxicmp + mZlZSjQzMzU5MRZ/cG8oGvnh4vnTR78JBjyizVzAapQpiLUsbGOXV65pPH62+8oAAI8+ + Gp+cnns2/2KBEr2YfzY3PTn+aBSQB650nz3eWCN7XbCRWW0KYohqY9FX7vJKaOpQb9/1 + 2C8PHk1MzT5fWHy59IoSLb1cXHg+OzXx6MEvset9vSFo68py91dFRgjrPR7D4aQ3km1c + faTl5Hfhgejtkfj41Nz870uvl1feUKKV5ddLv8/PTY3HR25HB8LfnWw5Uk02spGEdfI+ + BmIDEJcFgvXHOruvRmLDo2OTs/OLr1berK6tU6K11TcrrxbnZyfHRodjkavdncfqg4Ey + IDakJGYMJqEYgquh9UxP342fR+IT088BeHX97QY1eru+CsjPpyfiIz/f6Os509oA0VUs + mAxMKo8ZzmQVpa9rGtu6evtv3r7/+Le5haXl1fWNzXdblOjd5sb66vLSwtxvj+/fvtnf + 29XWWPO1JFpN3D7EvE2U5Nqm9nOXBqJ3R8emni2+/mNtY3NrmxptbW6s/fF68dnU2Ojd + 6MClc+1NtbIk2vj9ieFwAuJvw4O3hh8+mZ5/ubz6FoDff6BE77e3Nt+uLr+cn37ycPjW + YPhbQux1fZG4IxS+FrsXn5h5sbSytvEOgD9Sog/vt99trK0svZiZiN+LXQvD8bQfMXxY + VDEcb0t4nIL4f1To4+eJd733yc7Ng2s1XLl8B+qaT4QuR8Djp7MLr96sb2xtf/hIBS8U + +fHD9tbG+ptXC7NPwePI5dCJ5roDPrh0wcU6LxeJ0WPsahr2Mu5jTK6/vQXB0wnPYxpi + C28geOfCWyZ+ksDPTlSkNd4y8ZaJt0x864PvudI/rjGrMasxqzGrMasxq9NvBfB0wtMJ + Tyc8nfB0Sr9sTq4IsxqzGrMasxqzOjkZ0+8ZsxqzGrMasxqzOv2yObkizGrMasxqzGrM + 6uRkTL9nzGrMasxqzGrM6vTL5uSKMKsxqzGrMasxq5OTMf2eMasxqzGrMasxq9Mvm5Mr + wqzGrMasxqzGrE5OxvR7xqzGrMasxqzGrE6/bE6uCLMasxqzGrMaszo5GdPvGbMasxqz + GrP6v53VGfdtzllfIP7vfWP3LuKM+lb2TPvm/YybrpBxEzQyb0pKpk3CUWTctCOFMuMm + WmXe1LKMm0yXm3HTB8lMzQybMJlpU0Qzb1JsJk4DzryJz2RweyZN9c7KuMntQExM1uj0 + ZHa7Q3R7fP6AXFl9MFhDZt7XUSFSaU3wYHWlHPD7PG6RDDHn9DDFPH/vGPMsIM5R5ClV + 2gSyYHeKJaWSt9wfCMiyfIAaQbGBgL/cK5WWiE67kADWqpR5ipzkod7wsh5MBmS1Vsdy + hbxFsDucostdWuaRJK/XR4m8XknylJW6XaLTYRcsfCHH6rQww1yxZ1I9+esEmAx9DS4z + rKHAyJsFqw2oncWiiyqJxU6gtVkFM28sMLAMOEx6OoXFn5ChsTVgs6GgEKAtRQJw2+wU + yQasQpEFcAuBV6fVQEvvB5yVnXAZ4ivBrOc4oDaaTDxvpkg8bzIZgZbj9AleCK0E8K7J + g3/+wS2BrMgDm4FZy+hYVm8wcNTJYNCzrI7Rgr/EYNjDOdmpgaGvwWWSX2Q7q9QawNYy + DKOjSlAwlK3RqAEX/CW8+wOT+NphBmigBuyE1BTpU8lKQpun+CJvIrIJc05ubq6CYFMr + gM0l9n7W37/t5wQ1+X0Q/E+qtFN14mf2vvv3T9Zd/4Dfp1i7UPABVwBXAFcAV4CyFfg/ + bog27wplbmRzdHJlYW0KZW5kb2JqCjM0IDAgb2JqCjIzMjAKZW5kb2JqCjI2IDAgb2Jq + Cjw8IC9MZW5ndGggMjcgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAv + V2lkdGggMjYwIC9IZWlnaHQgMjYwIC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5IC9CaXRz + UGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7d3/ + U1JZFADwvijyTURFVJKVomxxILQwU7I0Gr+3Wg4jfTOcMqNGLR1aR8sp1Cmx8kvluOZo + TuygmWnqqG27s//anvuwTBcUFd6798L5JQ1K+Hjuue894Jw9e8IRFggLhAXCAmGBsEBY + ICyAkcBeFPsgmC8wemAsPZTVZw8A+/cjBgj4K5Z+OBY/xvPr378/IiIiEgL+8EiEkAJa + AAAAz57Hi4Lg8RAEwxAiqYCSAAHwovh8vkAgFAoE8EUUOETAsgiJVGAIGAGBUCQSR0OI + RSKhgFEIDQQggCTg8flCkVgiiZHGQkhjJBKxSMjn81AqUJ8JHoIoEIiWSGPjZLIECJks + LlYqiQaFqBBAWCUQQA5I42QJiUkKJpISE2RxUsgFAf0IHgK+QIQE5EmKFGWqCiJVmaJI + kiMFkYBPeSasEghFkth4edIBpeqQ+kgaxBH1IZXyQJI8PlYC64FqhO8EYkmsLFGhVKnT + NOla3bFjOm26Jk2tUioSZbESMdUIPwhi4hKSU5CAVp95wpCVZTiRqdcihZTkhLgYmhF+ + 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 + N8LthpbWDkf3c2dvr/N5t6OjtaXhNqUE3hFKL1pu1N17YG/reOro6nI87WizP7hXd8Ny + sZTQ6wW+F4LnFm+HzSWV1TU3bY3N9ta29va2Vntzo+1mTXVlCaUE3jLhtKmkwnzVWmdr + uN/c0tJ8v8FWZ71qrigxnSbyqtFWWYBu35gJ+ixjQfGFKsv12lv1trt3bfW3aq9bqi4U + Fxiz9AReOPOH4H8IMCc1N7+wrNJsuVZjra211lyzmCvLCvNzYd4oedcO/SPYgJB6GBBy + zpiKyyurzBYIc1VlebHpTA4iSCXt8qm/BBsR1Brd8WxjvqmotLwCory0yJRvzD6u06gp + JliHIIfJyUe1GYZTxrPnzhdCnD931njKkKE9CtOH5WRdRPc/C9A91wojTNBWHkzT6DIN + 2bnGPAhjbrYhU6dJO6hkRnET9DrC9gjWISQkp6jUaRqtPvOEISvLcCJTr9WkqVUpyQlr + I9lxfXF9u097/f1/ZAJM0U5UKJFCulZ37JhOm44ElIpEmEBN0qtJ65+ef999R4BR4vHy + pANK1SH1kTSII+pDKuWBJHk8zF6meCF4kFYRBCKJNE4mT1KkKFNVEKnKFEWSXBYnhYn0 + eL/LxL/f9eb38iBECURipJCQmKRgIikxAQmIRWgMOcZvtNn8yfl76yoCXyiKlkhj42Sy + BAiZLC5WKomGdRAKBN93Bx4fFMQSSYw0FkIaI4EcEPL5vBDIApQtkAkwJTGSF8UXCEUi + cTSEWCQSCvhRvEgYw47vO878TXV/7scgRDAKfL5AIBQKBHw+IwClIDQIUCrsg1SAsS/g + wIuC4EEGwCoAAW/Ddv1xJfA+KBUYhggEERkR4QEImSTw/Mr2ehgYCeQBAX9F4K9zlw8Z + nrRHgvlil/9Z+J+HBcICYYGwQFggLBAWCAsEVuA/SCo8XAplbmRzdHJlYW0KZW5kb2Jq + CjI3IDAgb2JqCjM3MTEKZW5kb2JqCjM2IDAgb2JqCjw8IC9MZW5ndGggMzcgMCBSIC9U + eXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMjQyIC9IZWlnaHQgMTcw + IC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5IC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRl + 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 + d8WApwNg7RWwTOERxyzfdfIhsJoEigOEEgkxgh7Swj4XFdV0LFWuxucqS770/x56u8uz + 8mOSzwljPbfK+TzHd9PJlwTbvWJGcKO1mBVcry2sCO5r6ZzghrVYELxRW84LVo1yUbDZ + 9u/+71qpoV+1M0NPXytVhN/qFsqCb3dWhv66ujDcm9HOed+Tn7PlZIf7RxEKVJhwYHGW + UUUcc6iADQ3uJVchN83rOEbIvNnWB57yZzjqpn/e6Y65ZbWamiPP86tUo3LWUC5H5Xgs + dg2/AEmasesKZW5kc3RyZWFtCmVuZG9iago0MyAwIG9iago1NjMKZW5kb2JqCjM1IDAg + b2JqClsgL0lDQ0Jhc2VkIDQyIDAgUiBdCmVuZG9iago0NCAwIG9iago8PCAvTGVuZ3Ro + IDQ1IDAgUiAvTiAzIC9BbHRlcm5hdGUgL0RldmljZVJHQiAvRmlsdGVyIC9GbGF0ZURl + Y29kZSA+PgpzdHJlYW0KeAGtkz9oE1Ecx7+XFC1YI7TVQSjcYMEhakg66GSaNC1pJQ35 + 00S39HLJpeYux90ltsEhg6uzgzqIS4eiq8VFEcTFoSiiuDq4dOkgBSnn9+58iYPFxR+8 + e598832/37vfeweED2um2Q4B0A3HKiyl5OrNW/LJLziFKY4ZTNQU25zP52/Qckz8+ATJ + ++vDJS/XpmonIntXHu9v7KbvPS+/OGaRkCMWCwJSlMJ0M+Ckx+sBlzy+45gOPZrHilar + k++So1apkCZvkyPNgL16kfWA33ncU5re2s/kmFFvGUBonHy1rtoKOUnW6raik5lHCul6 + h/nDO9QvKqbFteGP5AteXzgzts4A1x/Q/3qkVd8CO8+Ac/sjbZbeqa/Abm+kHRz6vZJm + vtmNRNxPJ51+Apzou+7BWWCctY/WXPdnynWPWHuMSV7eV7pWz/dyg9J74F+/g3cOsgN7 + zMPwz+jvHPTFd8WApwNg7RWwTOERxyzfdfIhsJoEigOEEgkxgh7Swj4XFdV0LFWuxucq + S770/x56u8uz8mOSzwljPbfK+TzHd9PJlwTbvWJGcKO1mBVcry2sCO5r6ZzghrVYELxR + W84LVo1yUbDZ9u/+71qpoV+1M0NPXytVhN/qFsqCb3dWhv66ujDcm9HOed+Tn7PlZIf7 + RxEKVJhwYHGWUUUcc6iADQ3uJVchN83rOEbIvNnWB57yZzjqpn/e6Y65ZbWamiPP86tU + o3LWUC5H5Xgsdg2/AEmasesKZW5kc3RyZWFtCmVuZG9iago0NSAwIG9iago1NjMKZW5k + b2JqCjI1IDAgb2JqClsgL0lDQ0Jhc2VkIDQ0IDAgUiBdCmVuZG9iago0NiAwIG9iago8 + PCAvTGVuZ3RoIDQ3IDAgUiAvTiAzIC9BbHRlcm5hdGUgL0RldmljZVJHQiAvRmlsdGVy + IC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAGFlE1IFGEYx/+zjQSxBtGXCMXQwSRUJgtS + AtP1K1O2ZdVMCWKdfXedHGenmd0tRSKE6Jh1jC5WRIeITuGhQ6c6RASZdYmgo0UQBV4i + tv87k7tjVL4wM795nv/7fL3DAFWPUo5jRTRgys67yd6Ydnp0TNv8GlWoRhRcKcNzOhKJ + AZ+plc/1a/UtFGlZapSx1vs2fKt2mRBQNCp3ZAM+LHk84OOSL+SdPDVnJBsTqTTZITe4 + Q8lO8i3y1myIx0OcFp4BVLVTkzMcl3EiO8gtRSMrYz4g63batMnvpT3tGVPUsN/INzkL + 2rjy/UDbHmDTi4ptzAMe3AN211Vs9TXAzhFg8VDF9j3pz0fZ9crLHGr2wynRGGv6UCp9 + rwM23wB+Xi+VftwulX7eYQ7W8dQyCm7R17Iw5SUQ1BvsZvzkGv2Lg558VQuwwDmObAH6 + rwA3PwL7HwLbHwOJamCoFZHLbDe48uIi5wJ05pxp18xO5LVmXT+idfBohdZnG00NWsqy + NN/laa7whFsU6SZMWQXO2V/beI8Ke3iQT/YXuSS87t+szKVTXZwlmtjWp7To6iY3kO9n + zJ4+cj2v9xm3Zzhg5YCZ7xsKOHLKtuI8F6mJ1Njj8ZNkxldUJx+T85A85xUHZUzffi51 + IkGupT05meuXml3c2z4zMcQzkqxYMxOd8d/8xi0kZd591Nx1LP+bZ22RZxiFBQETNu82 + NCTRixga4cBFDhl6TCpMWqVf0GrCw+RflRYS5V0WFb1Y4Z4Vf895FLhbxj+FWBxzDeUI + mv5O/6Iv6wv6Xf3zfG2hvuKZc8+axqtrXxlXZpbVyLhBjTK+rCmIb7DaDnotZGmd4hX0 + 5JX1jeHqMvZ8bdmjyRzianw11KUIZWrEOOPJrmX3RbLFN+HnW8v2r+lR+3z2SU0l17K6 + eGYp+nw2XA1r/7OrYNKyq/DkjZAuPGuh7lUPqn1qi9oKTT2mtqttahffjqoD5R3DnJWJ + C6zbZfUp9mBjmt7KSVdmi+Dfwi+G/6VeYQvXNDT5D024uYxpCd8R3DZwh5T/w1+zAw3e + CmVuZHN0cmVhbQplbmRvYmoKNDcgMCBvYmoKNzkyCmVuZG9iago4IDAgb2JqClsgL0lD + Q0Jhc2VkIDQ2IDAgUiBdCmVuZG9iago0OCAwIG9iago8PCAvTGVuZ3RoIDQ5IDAgUiAv + TiAzIC9BbHRlcm5hdGUgL0RldmljZVJHQiAvRmlsdGVyIC9GbGF0ZURlY29kZSA+Pgpz + dHJlYW0KeAGtkz9oE1Ecx7+XFC1YI7TVQSjcYMEhakg66GSaNC1pJQ3500S39HLJpeYu + x90ltsEhg6uzgzqIS4eiq8VFEcTFoSiiuDq4dOkgBSnn9+58iYPFxR+8e598832/37vf + eweED2um2Q4B0A3HKiyl5OrNW/LJLziFKY4ZTNQU25zP52/Qckz8+ATJ++vDJS/Xpmon + IntXHu9v7KbvPS+/OGaRkCMWCwJSlMJ0M+Ckx+sBlzy+45gOPZrHilark++So1apkCZv + kyPNgL16kfWA33ncU5re2s/kmFFvGUBonHy1rtoKOUnW6raik5lHCul6h/nDO9QvKqbF + teGP5AteXzgzts4A1x/Q/3qkVd8CO8+Ac/sjbZbeqa/Abm+kHRz6vZJmvtmNRNxPJ51+ + Apzou+7BWWCctY/WXPdnynWPWHuMSV7eV7pWz/dyg9J74F+/g3cOsgN7zMPwz+jvHPTF + d8WApwNg7RWwTOERxyzfdfIhsJoEigOEEgkxgh7Swj4XFdV0LFWuxucqS770/x56u8uz + 8mOSzwljPbfK+TzHd9PJlwTbvWJGcKO1mBVcry2sCO5r6ZzghrVYELxRW84LVo1yUbDZ + 9u/+71qpoV+1M0NPXytVhN/qFsqCb3dWhv66ujDcm9HOed+Tn7PlZIf7RxEKVJhwYHGW + UUUcc6iADQ3uJVchN83rOEbIvNnWB57yZzjqpn/e6Y65ZbWamiPP86tUo3LWUC5H5Xgs + dg2/AEmasesKZW5kc3RyZWFtCmVuZG9iago0OSAwIG9iago1NjMKZW5kb2JqCjI4IDAg + b2JqClsgL0lDQ0Jhc2VkIDQ4IDAgUiBdCmVuZG9iago1MCAwIG9iago8PCAvTGVuZ3Ro + IDUxIDAgUiAvTiAxIC9BbHRlcm5hdGUgL0RldmljZUdyYXkgL0ZpbHRlciAvRmxhdGVE + ZWNvZGUgPj4Kc3RyZWFtCngBhVJPSBRRHP7NNhKEiEGFeIh3CgmVKaysoNp2dVmVbVuV + 0qIYZ9+6o7Mz05vZNcWTBF2iPHUPomN07NChm5eiwKxL1yCpIAg8dej7zezqKIRveTvf + +/39ft97RG2dpu87KUFUc0OVK6Wnbk5Ni4MfKUUd1E5YphX46WJxjLHruZK/u9fWZ9LY + st7HtXb79j21lWVgIeottrcQ+iGRZgAfmZ8oZYCzwB2Wr9g+ATxYDqwa8COiAw+auTDT + 0Zx0pbItkVPmoigqr2I7Sa77+bnGvou1iYP+XI9m1o69s+qq0UzUtPdEobwPrkQZz19U + 9mw1FKcN45xIQxop8q7V3ytMxxGRKxBKBlI1ZLmfak6ddeB1GLtdupPj+PYQpT7JYKiJ + temymR2FfQB2KsvsEPAF6PGyYg/ngXth/1tRw5PAJ2E/ZId51q0f9heuU+B7hD014M4U + rsXx2oofXi0BQ/dUI2iMc03E09c5c6SI7zHUGZj3RjmmCzF3lqoTN4A7YR9ZqmYKsV37 + ruol7nsCd9PjO9GbOQtcoBxJcrEV2RTQPAlYFH2LsEkOPD7OHlXgd6iYwBy5idzNKPce + 1REbZ6NSgVZ6jVfGT+O58cX4ZWwYz4B+rHbXe3z/6eMVdde2Pjz5jXrcOa69nRtVYVZx + ZQvd/8cyhI/ZJzmmwdOhWVhr2HbkD5rMTLAMKMR/BT6X+pITVdzV7u24RRLMUD4sbCW6 + S1RuKdTqPYNKrBwr2AB2cJLELFocuFNrujl4d9giem35TVey64b++vZ6+9ryHm3KqCko + E82zRGaUsVuj5N142/1mkRGfODq+572KWsn+SUUQP4U5WiryFFX0VlDWxG9nDn4btn5c + P6Xn9UH9PAk9rZ/Rr+ijEb4MdEnPwnNRH6NJ8LBpIeISoIqDM9ROVGONA+Ip8fK0W2SR + /Q9AGf1mCmVuZHN0cmVhbQplbmRvYmoKNTEgMCBvYmoKNzA0CmVuZG9iagoyMyAwIG9i + agpbIC9JQ0NCYXNlZCA1MCAwIFIgXQplbmRvYmoKNCAwIG9iago8PCAvVHlwZSAvUGFn + ZXMgL01lZGlhQm94IFswIDAgNjEyIDc5Ml0gL0NvdW50IDEgL0tpZHMgWyAzIDAgUiBd + ID4+CmVuZG9iago1MiAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvT3V0bGluZXMgMiAw + IFIgL1BhZ2VzIDQgMCBSIC9WZXJzaW9uIC8xLjQgPj4KZW5kb2JqCjIgMCBvYmoKPDwg + L0xhc3QgNTMgMCBSIC9GaXJzdCA1NCAwIFIgPj4KZW5kb2JqCjU0IDAgb2JqCjw8IC9D + b3VudCAwIC9EZXN0IFsgMyAwIFIgL1hZWiAwIDU1MyAwIF0gL1RpdGxlIChDYW52YXMg + MSkgPj4KZW5kb2JqCjUzIDAgb2JqCjw8IC9Db3VudCAwIC9EZXN0IFsgMyAwIFIgL1hZ + WiAwIDU1MyAwIF0gL1RpdGxlIChDYW52YXMgMSkgPj4KZW5kb2JqCjU1IDAgb2JqCjw8 + IC9MZW5ndGggNTYgMCBSIC9MZW5ndGgxIDE0NTA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2Rl + ID4+CnN0cmVhbQp4Ab17eWBVxfX/zN3fvu97Xt6WfSchgTxCFrZEFpUECSZAICAoIEZB + oFGBQEQUkUXAXVnFhBDlAYVSDCLWKlpxwb2Ctbapbb+oLZD7vmfuCxGs3/78o7++++7M + 3Lnz5p45c+aczzl3HsIIISVqRTSKTpvbOO+Nz49+BDWvI4T101oWeh/449DHofwZQvSc + GfNmztV99vJrCLFjEJIrZ85ZNGNeZ+VvENLUIuS/q7mpcfr/PP+XcoRyTkMfBc1QIU/i + hyGUK8B1cvPchXe9wKlnwHUaXD8757ZpjTuf7XoSrkn76+c23jVPeED+T4TykuHae2vj + 3KYJi5rb4Rr6REnzbrt9IeNgH4TrZrheOG9B07xf3ndrNlwDzfSbUIfhIB8lFDmp9G+T + RGOEKJo0YxDL8VJ7Qi58ZEiOFIkipEqVWoOQVjdQAQW9wWgyW6w2O3I4XW6PF/mS/MmB + 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 + u+quNIW44P/js/AOaNBUlkos6/6WebNnSFv7/RVNDbDDv/P+FvirRetUr3ff7HnkBtlT + 3jB1WjPJG5s65/mbyjtn+8u9+1qk3/3o9gxyu8Vfvg/NqLi+dt+MaFN5V0u0pYL8xWH/ + 1LIF9dc8a/XAsxaU/cSzykhnC8izpkq/+9Gz6sntqeRZ9eRZ9eRZU6NTpWcRFlTMmlB2 + +0KQTtj+D9vvwxM6R46bVAv/cqkrj+Ht5D8Bd6D/BVDOTaIKZW5kc3RyZWFtCmVuZG9i + ago1NiAwIG9iagoxMDA3MQplbmRvYmoKNTcgMCBvYmoKPDwgL1R5cGUgL0ZvbnREZXNj + cmlwdG9yIC9Bc2NlbnQgNzcwIC9DYXBIZWlnaHQgNjg0IC9EZXNjZW50IC0yMzAgL0Zs + YWdzIDMyCi9Gb250QkJveCBbNSAtMjIxIDc2OCA3MzddIC9Gb250TmFtZSAvQk5OUkxV + K0hlbHZldGljYSAvSXRhbGljQW5nbGUgMCAvU3RlbVYKMCAvTWF4V2lkdGggMTUwMCAv + WEhlaWdodCA1MTMgL0ZvbnRGaWxlMiA1NSAwIFIgPj4KZW5kb2JqCjU4IDAgb2JqClsg + Mjc4IDAgMCAwIDAgMCAwIDAgMzMzIDMzMyAwIDAgMCAwIDI3OCAwIDU1NiA1NTYgNTU2 + IDAgMCAwIDAgMCA1NTYgMCAwIDAKMCAwIDAgNTU2IDAgNjY3IDAgNzIyIDAgMCAwIDAg + MCAwIDAgMCAwIDgzMyA3MjIgNzc4IDY2NyAwIDAgNjY3IDYxMSAwIDAgMAowIDAgMCAw + IDAgMCAwIDAgMCA1NTYgNTU2IDUwMCA1NTYgNTU2IDI3OCA1NTYgNTU2IDIyMiAwIDUw + MCAyMjIgODMzIDU1NiA1NTYKNTU2IDAgMzMzIDUwMCAyNzggNTU2IDUwMCA3MjIgMCA1 + MDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMAowIDAgMCAwIDAg + MCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAw + IDAgMCAwIDAgMCAwCjAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAg + MCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAKMCAwIDAgMCAwIDAgMCA1 + MDAgXQplbmRvYmoKMjQgMCBvYmoKPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1RydWVU + eXBlIC9CYXNlRm9udCAvQk5OUkxVK0hlbHZldGljYSAvRm9udERlc2NyaXB0b3IKNTcg + MCBSIC9XaWR0aHMgNTggMCBSIC9GaXJzdENoYXIgMzIgL0xhc3RDaGFyIDIyMiAvRW5j + b2RpbmcgL01hY1JvbWFuRW5jb2RpbmcKPj4KZW5kb2JqCjEgMCBvYmoKPDwgL1RpdGxl + IChVbnRpdGxlZCkgL0F1dGhvciAoYnJhbmRvbmgpIC9DcmVhdG9yIChPbW5pR3JhZmZs + ZSkgL1Byb2R1Y2VyIChNYWMgT1MgWCAxMC41LjggUXVhcnR6IFBERkNvbnRleHQpCi9D + cmVhdGlvbkRhdGUgKEQ6MjAwOTExMjAyMzExMTVaMDAnMDAnKSAvTW9kRGF0ZSAoRDoy + MDA5MTEyMDIzMTExNVowMCcwMCcpCj4+CmVuZG9iagp4cmVmCjAgNTkKMDAwMDAwMDAw + MCA2NTUzNSBmIAowMDAwMDQ0NDU1IDAwMDAwIG4gCjAwMDAwMzMxOTAgMDAwMDAgbiAK + MDAwMDAwMTYyNCAwMDAwMCBuIAowMDAwMDMzMDI3IDAwMDAwIG4gCjAwMDAwMDAwMjIg + MDAwMDAgbiAKMDAwMDAwMTYwNCAwMDAwMCBuIAowMDAwMDAxNzI4IDAwMDAwIG4gCjAw + MDAwMzE0MDMgMDAwMDAgbiAKMDAwMDAwMTk2MSAwMDAwMCBuIAowMDAwMDAzMDUxIDAw + MDAwIG4gCjAwMDAwMDY0NzcgMDAwMDAgbiAKMDAwMDAwNzIyMiAwMDAwMCBuIAowMDAw + MDA1NzEyIDAwMDAwIG4gCjAwMDAwMDY0NTcgMDAwMDAgbiAKMDAwMDAwMzgzNiAwMDAw + MCBuIAowMDAwMDA0OTI3IDAwMDAwIG4gCjAwMDAwMDQ5NDcgMDAwMDAgbiAKMDAwMDAw + NTY5MiAwMDAwMCBuIAowMDAwMDAzMDcxIDAwMDAwIG4gCjAwMDAwMDM4MTYgMDAwMDAg + biAKMDAwMDAwNzI0MiAwMDAwMCBuIAowMDAwMDA3OTg3IDAwMDAwIG4gCjAwMDAwMzI5 + OTAgMDAwMDAgbiAKMDAwMDA0NDI4MCAwMDAwMCBuIAowMDAwMDMwNDUxIDAwMDAwIG4g + CjAwMDAwMjE5NzMgMDAwMDAgbiAKMDAwMDAyNTg1OCAwMDAwMCBuIAowMDAwMDMyMTI1 + IDAwMDAwIG4gCjAwMDAwMTQ0MjggMDAwMDAgbiAKMDAwMDAxNjkyMiAwMDAwMCBuIAow + MDAwMDEwNTIyIDAwMDAwIG4gCjAwMDAwMTQ0MDcgMDAwMDAgbiAKMDAwMDAxOTQ1OCAw + MDAwMCBuIAowMDAwMDIxOTUyIDAwMDAwIG4gCjAwMDAwMjk3MjggMDAwMDAgbiAKMDAw + MDAyNTg3OSAwMDAwMCBuIAowMDAwMDI5MDIxIDAwMDAwIG4gCjAwMDAwMTY5NDMgMDAw + MDAgbiAKMDAwMDAxOTQzNyAwMDAwMCBuIAowMDAwMDA4MDA3IDAwMDAwIG4gCjAwMDAw + MTA1MDEgMDAwMDAgbiAKMDAwMDAyOTA0MiAwMDAwMCBuIAowMDAwMDI5NzA4IDAwMDAw + IG4gCjAwMDAwMjk3NjUgMDAwMDAgbiAKMDAwMDAzMDQzMSAwMDAwMCBuIAowMDAwMDMw + NDg4IDAwMDAwIG4gCjAwMDAwMzEzODMgMDAwMDAgbiAKMDAwMDAzMTQzOSAwMDAwMCBu + IAowMDAwMDMyMTA1IDAwMDAwIG4gCjAwMDAwMzIxNjIgMDAwMDAgbiAKMDAwMDAzMjk3 + MCAwMDAwMCBuIAowMDAwMDMzMTEwIDAwMDAwIG4gCjAwMDAwMzMzMTYgMDAwMDAgbiAK + MDAwMDAzMzIzOCAwMDAwMCBuIAowMDAwMDMzMzk0IDAwMDAwIG4gCjAwMDAwNDM1NTYg + MDAwMDAgbiAKMDAwMDA0MzU3OCAwMDAwMCBuIAowMDAwMDQzNzk4IDAwMDAwIG4gCnRy + YWlsZXIKPDwgL1NpemUgNTkgL1Jvb3QgNTIgMCBSIC9JbmZvIDEgMCBSIC9JRCBbIDw0 + MjZkMDljZjFjMDY3M2I0NTU4MGUzOGJlY2FkZWY4OD4KPDQyNmQwOWNmMWMwNjczYjQ1 + NTgwZTM4YmVjYWRlZjg4PiBdID4+CnN0YXJ0eHJlZgo0NDY1NwolJUVPRgoxIDAgb2Jq + Cjw8L0F1dGhvciAoYnJhbmRvbmgpL0NyZWF0aW9uRGF0ZSAoRDoyMDA5MTEyMDIyNTQw + MFopL0NyZWF0b3IgKE9tbmlHcmFmZmxlIDUuMi4xKS9Nb2REYXRlIChEOjIwMDkxMTIw + MjMxMTAwWikvUHJvZHVjZXIgKE1hYyBPUyBYIDEwLjUuOCBRdWFydHogUERGQ29udGV4 + dCkvVGl0bGUgKHBhY2tldF9mbG93X2Zsb3djaGFydCk+PgplbmRvYmoKeHJlZgoxIDEK + MDAwMDA0NTk5NSAwMDAwMCBuIAp0cmFpbGVyCjw8L0lEIFs8NDI2ZDA5Y2YxYzA2NzNi + NDU1ODBlMzhiZWNhZGVmODg+IDw0MjZkMDljZjFjMDY3M2I0NTU4MGUzOGJlY2FkZWY4 + OD5dIC9JbmZvIDEgMCBSIC9QcmV2IDQ0NjU3IC9Sb290IDUyIDAgUiAvU2l6ZSA1OT4+ + CnN0YXJ0eHJlZgo0NjE5NwolJUVPRgo= + + QuickLookThumbnail + + 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 + Yy4sIDIwMDkA + + ReadOnly + NO + RowAlign + 1 + RowSpacing + 36 + SheetTitle + Canvas 1 + SmartAlignmentGuidesActive + YES + SmartDistanceGuidesActive + YES + UniqueID + 1 + UseEntirePage + + VPages + 1 + WindowInfo + + CurrentSheet + 0 + ExpandedCanvases + + + name + Canvas 1 + + + FitInWindow + + Frame + {{759, 198}, {710, 887}} + ListView + + OutlineWidth + 142 + RightSidebar + + ShowRuler + + Sidebar + + SidebarWidth + 120 + VisibleRegion + {{0, -204}, {754.688, 962.062}} + Zoom + 0.76190477609634399 + ZoomValues + + + Canvas 1 + 0.0 + 1 + + + + saveQuickLookFiles + YES + + diff --git a/openflow/hw-lib/automake.mk b/openflow/hw-lib/automake.mk new file mode 100644 index 00000000..204e1217 --- /dev/null +++ b/openflow/hw-lib/automake.mk @@ -0,0 +1,28 @@ +# +# Hardware library dependency file definitions. +# + +if NF2 +# +# NetFPGA hardware library +# +noinst_LIBRARIES += hw-lib/libnf2.a + +hw_lib_libnf2_a_SOURCES = \ + hw-lib/nf2/hw_flow.c \ + hw-lib/nf2/hw_flow.h \ + hw-lib/nf2/nf2_lib.c \ + hw-lib/nf2/nf2_lib.h \ + hw-lib/nf2/nf2_drv.c \ + hw-lib/nf2/nf2_drv.h \ + hw-lib/nf2/nf2.h \ + hw-lib/nf2/debug.h \ + hw-lib/nf2/reg_defines_openflow_switch.h \ + hw-lib/nf2/nf2util.c \ + hw-lib/nf2/nf2util.h + +hw_lib_nf2_a_CPPFLAGS = $(AM_CPPFLAGS) $(OF_CPP_FLAGS) -DHWTABLE_NO_DEBUG +hw_lib_nf2_a_CPPFLAGS += -I hw-lib/nf2 +hw_lib_nf2_a_CPPFLAGS += -I $(HW_SYSTEM)/include + +endif diff --git a/openflow/hw-lib/nf2/README b/openflow/hw-lib/nf2/README new file mode 100644 index 00000000..7e111b30 --- /dev/null +++ b/openflow/hw-lib/nf2/README @@ -0,0 +1,56 @@ +NetFPGA Hardware Table + Date - 03/09/10 +---------------------------------------- + +This library creates and maintains a single software table that contains all +the flows that are currently held in the NetFPGA card. The card itself splits +exact match flows into SRAM and wildcard match flows into TCAMs. Currently +there are 24 usable wildcard flow entries and 32,768 available exact match +entries. The exact match table is hashed so actual available entries will be +varied. + +Installation +---------------------------------------- + +First build OpenFlow ensuring you include the directive to build the +openflow_netfpga hardware table in your configure statement: + + % ./configure --enable-hw-lib=nf2 + +For further help regarding building OpenFlow please see the INSTALL file in +the OpenFlow root directory. + +Platform support +---------------- + +OpenFlow v1.0 with NetFPGA hardware table has been tested on CentOS5.4 +(Linux 2.6.18), which is the officially supported platform of NetFPGA. + +Running +---------------------------------------- + +Use nf2_download to download the openflow_switch.bit file that is located in +the /datapath/hwtable_nf2 folder: + + % nf2_download -r /hw-lib/nf2/openflow_switch.bit + +'-r' option enables PHY interrupt for its link status changing, and OpenFlow +switch can detect it. + +Run ofdatapth with indicating *all* the NetFPGA interfaces: + + % /udatapath/ofdatapath punix:/var/run/test \ + -i nf2c0,nf2c1,nf2c2,nf2c3 + +At this point your OpenFlow switch should be ready to go. +The way you start up ofprotocol is as same as you do for software reference +switch. + +Known Issues +---------------------------------------- +* There is currently no support for priority amongst wildcard-match entries. + +Contact +------- +e-mail: openflow-discuss@lists.stanford.edu +www: http://openflowswitch.org/ diff --git a/openflow/hw-lib/nf2/debug.h b/openflow/hw-lib/nf2/debug.h new file mode 100644 index 00000000..9cb2b10d --- /dev/null +++ b/openflow/hw-lib/nf2/debug.h @@ -0,0 +1,105 @@ + +#ifndef OF_HW_DEBUG_H +#define OF_HW_DEBUG_H 1 + +#include +#include + +#if !defined(HWTABLE_NO_DEBUG) +extern int of_hw_debug; +#define dbg_send(mod, lvl, fmt, args...) \ + if (of_hw_debug >= (lvl)) fprintf(stderr, fmt, ##args) + +#define DBG_LVL_NONE -1 /* All output off */ +#define DBG_LVL_ERROR 0 /* Default value */ +#define DBG_LVL_ALWAYS 0 /* For requested dump output */ +#define DBG_LVL_WARN 1 +#define DBG_LVL_VERBOSE 2 +#define DBG_LVL_VVERB 3 /* Include success indications */ + +/* Sorry for the lazy syntax here. */ +#define DBG_CHECK(lvl) (((lvl) >= 0) && (of_hw_debug >= (lvl))) +#define DBG_ERROR(fmt, args...) dbg_send(0, DBG_LVL_ERROR, fmt, ##args) +#define DBG_ALWAYS(fmt, args...) dbg_send(0, DBG_LVL_ALWAYS, fmt, ##args) +#define DBG_WARN(fmt, args...) dbg_send(0, DBG_LVL_WARN, fmt, ##args) +#define DBG_VERBOSE(fmt, args...) dbg_send(0, DBG_LVL_VERBOSE, fmt, ##args) +#define DBG_VVERB(fmt, args...) dbg_send(0, DBG_LVL_VVERB, fmt, ##args) +#define DBG_NONE(fmt, args...) +/* Same as DEBUG_ALWAYS */ +#define DEBUGK(fmt, args...) dbg_send(0, DBG_LVL_ALWAYS, fmt, ##args) + +#define REPORT_ERROR(str) \ + DBG_ERROR("ERROR: %s:%d. %s\n", __FUNCTION__, __LINE__, str) + +/* Default debugging location string */ +#define ANNOUNCE_LOCATION DBG_VVERB("%s: %d\n", __FUNCTION__, __LINE__) +#define DBG_INCR(cnt) (++(cnt)) + +/* Should assert return? Not presently */ +#define ASSERT(cond) \ + if (!(cond)) DBG_ERROR("ASSERTION %s IN %s FAILED LINE %d\n", \ + #cond, __FUNCTION__, __LINE__) + +/* DEBUG for HW flow lists */ +#define HW_FLOW_MAGIC 0xba5eba11 +#define HW_FLOW_MAKE_VALID(hf) (hf)->magic = HW_FLOW_MAGIC +#define HW_FLOW_IS_VALID(hf) \ + (((hf) != NULL) && ((hf)->magic == HW_FLOW_MAGIC)) + +/* + * Carry out an operation and check for error, optionally returning + * from the calling routine. To avoid compiler + * warnings in routines with void return, we give two macros. + * + * WARNING: This check uses rv != 0 (not just rv < 0). + */ + +#define TRY(op, str) do { \ + int rv; \ + if (((rv = (op)) < 0)) { \ + DBG_ERROR("ERROR %d: %s\n", rv, str); \ + return rv; \ + } else { \ + DBG_NONE("%s: success\n", str); \ + } \ + } while (0) + +#define TRY_NR(op, str) do { \ + int rv; \ + if (((rv = (op)) != 0)) { \ + DBG_ERROR("ERROR %d: %s\n", rv, str); \ + } else { \ + DBG_NONE("%s: success\n", str); \ + } \ + } while (0) + +#else /* No debugging */ + +#define DBG_CHECK(lvl) 0 +#define ANNOUNCE_LOCATION +#define ACT_STRING(action) "" +#define DBG_INCR(cnt) +#define DBG_ERROR(fmt, args...) +#define DBG_ALWAYS(fmt, args...) +#define DBG_WARN(fmt, args...) +#define DBG_VERBOSE(fmt, args...) +#define DBG_VVERB(fmt, args...) +#define DBG_NONE(fmt, args...) +#define DEBUGK(fmt, args...) +#define REPORT_ERROR(str) + +#define ASSERT(cond) + +#define HW_FLOW_MAKE_VALID(hf) +#define HW_FLOW_IS_VALID(hf) 1 + +#define TRY(op, str) do { \ + int rv; \ + if (((rv = (op)) != 0)) return rv; \ + } while (0) + +#define TRY_NR(op, str) (void)op + +#endif /* !defined(HWTABLE_NO_DEBUG) */ + +#endif /* OF_HW_DEBUG_H */ diff --git a/openflow/hw-lib/nf2/hw_flow.c b/openflow/hw-lib/nf2/hw_flow.c new file mode 100644 index 00000000..d59a7713 --- /dev/null +++ b/openflow/hw-lib/nf2/hw_flow.c @@ -0,0 +1,514 @@ +/*- + * Copyright (c) 2008, 2009, 2010 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#include + +#include +#include "list.h" +#include "udatapath/switch-flow.h" +#include "udatapath/datapath.h" +#include "reg_defines_openflow_switch.h" +#include "nf2util.h" +#include "hw_flow.h" +#include "nf2_drv.h" +#include "nf2_lib.h" +#include "debug.h" + +struct nf2_flowtable { + struct of_hw_driver hw_driver; + unsigned int max_flows; + unsigned int num_flows; + struct list flows; + struct list iter_flows; + unsigned long int next_serial; +}; + +static struct sw_flow *nf2_lookup_flowtable(struct sw_table *, + const struct sw_flow_key *); +static int nf2_install_flow(struct sw_table *, struct sw_flow *); +static int nf2_modify_flow(struct sw_table *, const struct sw_flow_key *, + uint16_t, int, const struct ofp_action_header *, + size_t); +static int do_uninstall(struct sw_flow *, struct list *); +static int nf2_has_conflict(struct sw_table *, const struct sw_flow_key *, + uint16_t, int); +static int nf2_uninstall_flow_wrap(struct datapath *, struct sw_table *, + const struct sw_flow_key *, uint16_t, + uint16_t, int); +static int nf2_uninstall_flow(struct datapath *, struct sw_table *, + const struct sw_flow_key *, uint16_t, + uint16_t, int, int); +static void nf2_flow_timeout(struct sw_table *, struct list *); + +static void nf2_destroy_flowtable(struct sw_table *); +static int nf2_iterate_flowtable(struct sw_table *, + const struct sw_flow_key *, + uint16_t, struct sw_table_position *, + int (*)(struct sw_flow *, void *), void *); +static void nf2_get_flowstats(struct sw_table *, struct sw_table_stats *); +static int nf2_get_portstats(of_hw_driver_t *, int, struct ofp_port_stats *); + +#if !defined(HWTABLE_NO_DEBUG) +int of_hw_debug = DBG_LVL_WARN; +#endif + +#define DELETE_FLOW 0 +#define KEEP_FLOW 1 + +static struct sw_flow * +nf2_lookup_flowtable(struct sw_table *flowtab, const struct sw_flow_key *key) +{ + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + struct sw_flow *flow; + + LIST_FOR_EACH(flow, struct sw_flow, node, &nf2flowtab->flows) { + if (flow_matches_1wild(key, &flow->key)) { + return flow; + } + } + + return NULL; +} + +static int +nf2_install_flow(struct sw_table *flowtab, struct sw_flow *flow) +{ + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + + /* Delete flows that match exactly. */ + nf2_uninstall_flow(NULL, flowtab, &flow->key, OFPP_NONE, + flow->priority, true, KEEP_FLOW); + + if (nf2_are_actions_supported(flow)) { + if (nf2_build_and_write_flow(flow)) { + /* Not successful */ + return 0; + } + } else { + /* Unsupported actions or no device. */ + return 0; + } + + nf2flowtab->num_flows++; + list_push_front(&nf2flowtab->flows, &flow->node); + list_push_front(&nf2flowtab->iter_flows, &flow->iter_node); + + return 1; +} + +static int +nf2_modify_flow(struct sw_table *flowtab, const struct sw_flow_key *key, + uint16_t priority, int strict, + const struct ofp_action_header *actions, size_t actions_len) +{ + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + struct sw_flow *flow; + unsigned int count = 0; + + LIST_FOR_EACH(flow, struct sw_flow, node, &nf2flowtab->flows) { + if (flow_matches_desc(&flow->key, key, strict) + && (!strict || flow->priority == priority)) { + flow_replace_acts(flow, actions, actions_len); + if (nf2_are_actions_supported(flow)) { + count += nf2_modify_acts(flow); + } + } else { + return 0; + } + } + + return count; +} + +static int +nf2_has_conflict(struct sw_table *flowtab, const struct sw_flow_key *key, + uint16_t priority, int strict) +{ + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + struct sw_flow *flow; + + LIST_FOR_EACH(flow, struct sw_flow, node, &nf2flowtab->flows) { + + if (flow_matches_2desc(&flow->key, key, strict) + && (flow->priority == priority)) { + return true; + } + } + + return false; +} + +static int +do_uninstall(struct sw_flow *flow, struct list *deleted) +{ + if (flow != NULL && flow->private != NULL) { + list_remove(&flow->node); + list_remove(&flow->iter_node); + list_push_back(deleted, &flow->node); + return 1; + } + + return 0; +} + +static int +nf2_uninstall_flow_wrap(struct datapath *dpinst, struct sw_table *flowtab, + const struct sw_flow_key *key, uint16_t out_port, + uint16_t priority, int strict) +{ + return nf2_uninstall_flow(dpinst, flowtab, key, out_port, + priority, strict, DELETE_FLOW); +} + +static int +nf2_uninstall_flow(struct datapath *dpinst, struct sw_table *flowtab, + const struct sw_flow_key *key, uint16_t out_port, + uint16_t priority, int strict, int keep_flow) +{ + struct nf2device *dev; + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + struct sw_flow *flow, *n; + struct nf2_flow *nf2flow; + unsigned int count = 0; + struct list deleted; + list_init(&deleted); + + dev = nf2_get_net_device(); + if (dev == NULL) + return 0; + + LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &nf2flowtab->flows) { + if (flow_matches_desc(&flow->key, key, strict) + && (!strict || flow->priority == priority) + && flow_has_out_port(flow, out_port)) { + nf2flow = flow->private; + + if (nf2flow != NULL) { + flow->packet_count + += nf2_get_packet_count(dev, + nf2flow); + flow->byte_count += nf2_get_byte_count(dev, + nf2flow); + } + count += do_uninstall(flow, &deleted); + if (keep_flow == KEEP_FLOW) { + /* Delete private in sw_flow here */ + nf2_delete_private(flow->private); + } + } + } + nf2flowtab->num_flows -= count; + + nf2_free_net_device(dev); + + if (keep_flow == DELETE_FLOW) { + /* Notify DP of deleted flows and delete the flow */ + LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &deleted) { + dp_send_flow_end(dpinst, flow, flow->reason); + list_remove(&flow->node); + nf2_delete_private(flow->private); + flow_free(flow); + } + } + + return count; +} + +static void +nf2_flow_timeout(struct sw_table *flowtab, struct list *deleted) +{ + struct nf2device *dev; + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + struct sw_flow *flow, *n; + struct nf2_flow *nf2flow; + int num_uninst_flows = 0; + uint64_t num_forw_packets = 0; + uint64_t now = time_msec(); + + dev = nf2_get_net_device(); + if (dev == NULL) { + DBG_ERROR("Could not open NetFPGA device\n"); + return; + } + + /* LOCK; */ + /* FIXME */ + LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &nf2flowtab->flows) { + nf2flow = flow->private; + if (nf2flow != NULL) { + num_forw_packets = flow->packet_count + + nf2_get_packet_count(dev, nf2flow); + flow->byte_count += nf2_get_byte_count(dev, nf2flow); + } + if (num_forw_packets > flow->packet_count) { + flow->packet_count = num_forw_packets; + flow->used = now; + } + + if (flow_timeout(flow)) { + num_uninst_flows += do_uninstall(flow, deleted); + nf2_delete_private(flow->private); + } + } + + /* UNLOCK; */ + + nf2_clear_watchdog(dev); + nf2_free_net_device(dev); + + nf2flowtab->num_flows -= num_uninst_flows; +} + +static void +nf2_destroy_flowtable(struct sw_table *flowtab) +{ + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + struct nf2_flow *nf2flow = NULL; + + if (nf2flowtab == NULL) + return; + + while (!list_is_empty(&nf2flowtab->flows)) { + struct sw_flow *flow + = CONTAINER_OF(list_front(&nf2flowtab->flows), + struct sw_flow, node); + list_remove(&flow->node); + if (flow->private) { + nf2flow = (struct nf2_flow *)flow->private; + + if (nf2flow->type == NF2_TABLE_EXACT) { + nf2_add_free_exact(nf2flow); + } else if (nf2flow->type == NF2_TABLE_WILDCARD) { + nf2_add_free_wildcard(nf2flow); + } + flow->private = NULL; + } + flow_free(flow); + } + free(nf2flowtab); + + nf2_destroy_exact_freelist(); + nf2_destroy_wildcard_freelist(); +} + +static int +nf2_iterate_flowtable(struct sw_table *flowtab, const struct sw_flow_key *key, + uint16_t out_port, struct sw_table_position *position, + int (*callback) (struct sw_flow *, void *), + void *private) +{ + unsigned long start; + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + struct sw_flow *flow; + int error = 0; + + start = ~position->private[0]; + LIST_FOR_EACH(flow, struct sw_flow, iter_node, &nf2flowtab->iter_flows) { + if (flow->serial <= start + && flow_matches_2wild(key, &flow->key) + && flow_has_out_port(flow, out_port)) { + error = callback(flow, private); + if (error != 0) { + position->private[0] = ~flow->serial; + return error; + } + } + } + + return error; +} + +static void +nf2_get_flowstats(struct sw_table *flowtab, struct sw_table_stats *stats) +{ + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + struct nf2device *dev; + unsigned long int num_matched = 0; + unsigned long int num_missed = 0; + + dev = nf2_get_net_device(); + if (dev == NULL) { + DBG_VERBOSE("Could not open NetFPGA device\n"); + } else { + num_matched = nf2_get_matched_count(dev); + num_missed = nf2_get_missed_count(dev); + nf2_free_net_device(dev); + } + + stats->name = "nf2"; + stats->wildcards = OPENFLOW_WILDCARD_TABLE_SIZE + - RESERVED_FOR_CPU2NETFPGA; + stats->n_flows = nf2flowtab->num_flows; + stats->max_flows = nf2flowtab->max_flows; + stats->n_lookup = num_matched + num_missed; + stats->n_matched = num_matched; +} + +static int +nf2_get_portstats(of_hw_driver_t *hw_drv, int of_port, + struct ofp_port_stats *stats) +{ + int nf2_port; + struct nf2_port_info *nf2portinfo; + struct nf2device *dev; + + if ((of_port > NF2_PORT_NUM) || (of_port <= 0)) { + return 1; + } + nf2_port = of_port - 1; + + nf2portinfo = calloc(1, sizeof(struct nf2_port_info)); + if (nf2portinfo == NULL) { + return 1; + } + + dev = nf2_get_net_device(); + if (dev == NULL) { + free(nf2portinfo); + return 1; + } + + if (nf2_get_port_info(dev, nf2_port, nf2portinfo)) { + nf2_free_net_device(dev); + free(nf2portinfo); + return 1; + } + + stats->rx_packets = (uint64_t)(nf2portinfo->rx_q_num_pkts_stored); + stats->rx_dropped = (uint64_t)(nf2portinfo->rx_q_num_pkts_dropped_full + + nf2portinfo->rx_q_num_pkts_dropped_bad); + stats->rx_bytes = (uint64_t)(nf2portinfo->rx_q_num_bytes_pushed); + stats->tx_packets = (uint64_t)(nf2portinfo->tx_q_num_pkts_sent); + stats->tx_bytes = (uint64_t)(nf2portinfo->tx_q_num_bytes_pushed); + + /* Not supported */ + stats->tx_dropped = -1; + stats->rx_errors = -1; + stats->tx_errors = -1; + stats->rx_frame_err = -1; + stats->rx_over_err = -1; + stats->rx_crc_err = -1; + stats->collisions = -1; + + nf2_free_net_device(dev); + free(nf2portinfo); + return 0; +} + +/* + * Create and initialize a new hardware datapath object + */ + +of_hw_driver_t * +new_of_hw_driver(struct datapath *dp) +{ + struct sw_table *sw_tab; + of_hw_driver_t *hw_drv; + struct nf2device *dev; + struct nf2_flowtable *nf2flowtab; + + dev = nf2_get_net_device(); + if (dev == NULL) { + return NULL; + } + nf2_reset_card(dev); + nf2_free_net_device(dev); + + nf2flowtab = calloc(1, sizeof(*nf2flowtab)); + if (nf2flowtab == NULL) { + return NULL; + } + + /* These all point to the same place */ + hw_drv = &nf2flowtab->hw_driver; + sw_tab = &hw_drv->sw_table; + + sw_tab->n_lookup = 0; + sw_tab->n_matched = 0; + + /* Fill out the function pointers */ + sw_tab->lookup = nf2_lookup_flowtable; + sw_tab->insert = nf2_install_flow; + sw_tab->modify = nf2_modify_flow; + sw_tab->has_conflict = nf2_has_conflict; + + sw_tab->delete = nf2_uninstall_flow_wrap; + sw_tab->timeout = nf2_flow_timeout; + + sw_tab->destroy = nf2_destroy_flowtable; + sw_tab->iterate = nf2_iterate_flowtable; + sw_tab->stats = nf2_get_flowstats; + + nf2flowtab->max_flows = OPENFLOW_NF2_EXACT_TABLE_SIZE + + OPENFLOW_WILDCARD_TABLE_SIZE - RESERVED_FOR_CPU2NETFPGA; + nf2flowtab->num_flows = 0; + list_init(&nf2flowtab->flows); + list_init(&nf2flowtab->iter_flows); + nf2flowtab->next_serial = 0; + + if (nf2_init_wildcard_freelist()) { + DBG_ERROR("Could not create wildcard freelist\n"); + free(nf2flowtab); + return NULL; + } + if (nf2_write_static_wildcard()) { + DBG_ERROR("Could not create wildcard freelist\n"); + free(nf2flowtab); + return NULL; + } + if (nf2_init_exact_freelist()) { + DBG_ERROR("Could not create exact freelist\n"); + free(nf2flowtab); + return NULL; + } + + hw_drv->table_stats_get = NULL; + hw_drv->port_stats_get = nf2_get_portstats; + hw_drv->flow_stats_get = NULL; + hw_drv->aggregate_stats_get = NULL; + + hw_drv->port_add = NULL; + hw_drv->port_remove = NULL; + hw_drv->port_link_get = NULL; + hw_drv->port_enable_set = NULL; + hw_drv->port_enable_get = NULL; + hw_drv->port_queue_config = NULL; + hw_drv->port_queue_remove = NULL; + hw_drv->port_change_register = NULL; + + hw_drv->packet_send = NULL; + hw_drv->packet_receive_register = NULL; + + hw_drv->ioctl = NULL; + + return hw_drv; +} diff --git a/openflow/hw-lib/nf2/hw_flow.h b/openflow/hw-lib/nf2/hw_flow.h new file mode 100644 index 00000000..96e0320f --- /dev/null +++ b/openflow/hw-lib/nf2/hw_flow.h @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 2008, 2009, 2010 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#ifndef HWTABLE_NF2_NF2_FLOWTABLE_ +#define HWTABLE_NF2_NF2_FLOWTABLE_ + +#define RESERVED_FOR_CPU2NETFPGA 8 + +struct nf2_flow { + struct list node; + uint32_t pos; + uint32_t type; + uint32_t hw_packet_count; + uint32_t hw_byte_count; +}; + +enum nf2_of_table_type { + NF2_TABLE_EXACT, + NF2_TABLE_WILDCARD +}; + +/* Remove the commentout of the following 'define' line + * if you want to enable NetFPGA watchdog timer capability. + */ +/* #define NF2_WATCHDOG 1 */ + +#endif diff --git a/openflow/hw-lib/nf2/nf2.h b/openflow/hw-lib/nf2/nf2.h new file mode 100644 index 00000000..519f52da --- /dev/null +++ b/openflow/hw-lib/nf2/nf2.h @@ -0,0 +1,452 @@ +/* **************************************************************************** + * $Id: nf2.h 5575 2009-05-13 18:44:26Z grg $ + * + * Module: nf2.h + * Project: NetFPGA 2 Linux Kernel Driver + * Description: Header file for kernel driver + * + * Change history: + * + */ + +#ifndef _NF2_H +#define _NF2_H 1 + +#define NF2_DEV_NAME "nf2" + +/* Include for socket IOCTLs */ +#include + +/* Maximum number of interfaces */ +#ifndef MAX_IFACE +#define MAX_IFACE 4 +#endif + +/* + * Register names and locations. + * + * Note that these names are not necessarily identical to + * those in NF2/hw/common/src/defines + */ + +/* CPCI registers */ +#define CPCI_REG_ID 0x000 +#define CPCI_REG_BOARD_ID 0x004 +#define CPCI_REG_CTRL 0x008 +#define CPCI_REG_RESET 0x00c +#define CPCI_REG_ERROR 0x010 +#define CPCI_REG_DUMMY 0x020 +#define CPCI_REG_INTERRUPT_MASK 0x040 +#define CPCI_REG_INTERRUPT_STATUS 0x044 +#define CPCI_REG_PROG_DATA 0x100 +#define CPCI_REG_PROG_STATUS 0x104 +#define CPCI_REG_PROG_CTRL 0x108 +#define CPCI_REG_DMA_I_ADDR 0x140 +#define CPCI_REG_DMA_E_ADDR 0x144 +#define CPCI_REG_DMA_I_SIZE 0x148 +#define CPCI_REG_DMA_E_SIZE 0x14c +#define CPCI_REG_DMA_I_CTRL 0x150 +#define CPCI_REG_DMA_E_CTRL 0x154 +#define CPCI_REG_DMA_MAX_XFER_TIME 0x180 +#define CPCI_REG_DMA_MAX_RETRIES 0x184 +#define CPCI_REG_CNET_MAX_XFER_TIME 0x188 +#define CPCI_REG_DMA_I_PKT_CNT 0x400 +#define CPCI_REG_DMA_E_PKT_CNT 0x404 +#define CPCI_REG_CPCI_REG_RD_CNT 0x408 +#define CPCI_REG_CPCI_REG_WR_CNT 0x40c +#define CPCI_REG_CNET_REG_RD_CNT 0x410 +#define CPCI_REG_CNET_REG_WR_CNT 0x414 + +#define CPCI_REG_N_CLK_COUNT 0x500 +#define CPCI_REG_P_MAX 0x504 +#define CPCI_REG_N_EXP 0x508 +#define CPCI_REG_P_CLK_CTR 0x510 +#define CPCI_REG_RESET_CTR 0x520 + + + +/* Base address for CNET registers */ +#define CNET_REG_BASE 0x400000 + + +/* Added by nweaver for building memory manipulation + utilities */ +/* 2 MB SRAM size on current board, MAX and SIZE will + need to be changed if upgraded to 4 MB SRAMs */ +#define SRAM_SIZE 0x200000 + +#define SRAM_1_BASE 0x800000 +#define SRAM_1_MAX 0x9FFFFF + +#define SRAM_2_BASE 0xC00000 +#define SRAM_2_MAX 0xDFFFFF +/* end nweaver addition */ + + +/* Device ID registers */ +#define NF2_DEVICE_ID 0x0400000 +#define NF2_REVISION 0x0400004 +#define NF2_DEVICE_STR 0x0400008 + + +/* CNET registers */ +#define CNET_REG_ID (CNET_REG_BASE + 0x000) +#define CNET_REG_CTRL (CNET_REG_BASE + 0x004) +#define CNET_REG_RESET (CNET_REG_BASE + 0x008) +#define CNET_REG_ERROR (CNET_REG_BASE + 0x00C) +#define CNET_REG_ENABLE (CNET_REG_BASE + 0x010) +#define CNET_REG_WR_SRAM1_EOP (CNET_REG_BASE + 0x0F0) +#define CNET_REG_RD_SRAM1_EOP (CNET_REG_BASE + 0x0F4) +#define CNET_REG_WR_SRAM2_EOP (CNET_REG_BASE + 0x0F8) +#define CNET_REG_RD_SRAM2_EOP (CNET_REG_BASE + 0x0FC) +#define CNET_REG_MF_STATUS_0 (CNET_REG_BASE + 0x100) +#define CNET_REG_MF_TX_PKTS_SENT_0 (CNET_REG_BASE + 0x104) +#define CNET_REG_MF_RX_PKTS_RCVD_0 (CNET_REG_BASE + 0x108) +#define CNET_REG_MF_RX_PKTS_LOST_0 (CNET_REG_BASE + 0x10C) +#define CNET_REG_MAC_CONFIG_0 (CNET_REG_BASE + 0x110) +#define CNET_REG_MF_STATUS_1 (CNET_REG_BASE + 0x140) +#define CNET_REG_MF_TX_PKTS_SENT_1 (CNET_REG_BASE + 0x144) +#define CNET_REG_MF_RX_PKTS_RCVD_1 (CNET_REG_BASE + 0x148) +#define CNET_REG_MF_RX_PKTS_LOST_1 (CNET_REG_BASE + 0x14C) +#define CNET_REG_MAC_CONFIG_1 (CNET_REG_BASE + 0x150) +#define CNET_REG_MF_STATUS_2 (CNET_REG_BASE + 0x180) +#define CNET_REG_MF_TX_PKTS_SENT_2 (CNET_REG_BASE + 0x184) +#define CNET_REG_MF_RX_PKTS_RCVD_2 (CNET_REG_BASE + 0x188) +#define CNET_REG_MF_RX_PKTS_LOST_2 (CNET_REG_BASE + 0x18C) +#define CNET_REG_MAC_CONFIG_2 (CNET_REG_BASE + 0x190) +#define CNET_REG_MF_STATUS_3 (CNET_REG_BASE + 0x1C0) +#define CNET_REG_MF_TX_PKTS_SENT_3 (CNET_REG_BASE + 0x1C4) +#define CNET_REG_MF_RX_PKTS_RCVD_3 (CNET_REG_BASE + 0x1C8) +#define CNET_REG_MF_RX_PKTS_LOST_3 (CNET_REG_BASE + 0x1CC) +#define CNET_REG_MAC_CONFIG_3 (CNET_REG_BASE + 0x1D0) +#define CNET_REG_RXQ_NUM_PKTS_0 (CNET_REG_BASE + 0x200) +#define CNET_REG_RXQ_POINTERS_0 (CNET_REG_BASE + 0x204) +#define CNET_REG_RXQ_NUM_PKTS_1 (CNET_REG_BASE + 0x240) +#define CNET_REG_RXQ_POINTERS_1 (CNET_REG_BASE + 0x244) +#define CNET_REG_RXQ_NUM_PKTS_2 (CNET_REG_BASE + 0x280) +#define CNET_REG_RXQ_POINTERS_2 (CNET_REG_BASE + 0x284) +#define CNET_REG_RXQ_NUM_PKTS_3 (CNET_REG_BASE + 0x2C0) +#define CNET_REG_RXQ_POINTERS_3 (CNET_REG_BASE + 0x2C4) + +#define CNET_REG_MF_RX_PKTS_LOST_BAD_FCS_0 (CNET_REG_BASE + 0x114) +#define CNET_REG_MF_RX_PKTS_LOST_FULL_FIFO_0 (CNET_REG_BASE+0x118) +#define CNET_REG_MF_RX_GOOD_PKTS_RCVD_0 (CNET_REG_BASE+0x11C) +#define CNET_REG_MF_RX_GOOD_BYTES_RCVD_0 (CNET_REG_BASE+0x120) +#define CNET_REG_MF_TX_BYTES_SENT_0 (CNET_REG_BASE+0x124) +#define CNET_REG_MF_RX_PKTS_LOST_BAD_FCS_1 (CNET_REG_BASE+0x154) +#define CNET_REG_MF_RX_PKTS_LOST_FULL_FIFO_1 (CNET_REG_BASE+0x158) +#define CNET_REG_MF_RX_GOOD_PKTS_RCVD_1 (CNET_REG_BASE+0x15C) +#define CNET_REG_MF_RX_GOOD_BYTES_RCVD_1 (CNET_REG_BASE+0x160) +#define CNET_REG_MF_TX_BYTES_SENT_1 (CNET_REG_BASE+0x164) +#define CNET_REG_MF_RX_PKTS_LOST_BAD_FCS_2 (CNET_REG_BASE+0x194) +#define CNET_REG_MF_RX_PKTS_LOST_FULL_FIFO_2 (CNET_REG_BASE+0x198) +#define CNET_REG_MF_RX_GOOD_PKTS_RCVD_2 (CNET_REG_BASE+0x19C) +#define CNET_REG_MF_RX_GOOD_BYTES_RCVD_2 (CNET_REG_BASE+0x1A0) +#define CNET_REG_MF_TX_BYTES_SENT_2 (CNET_REG_BASE+0x1A4) +#define CNET_REG_MF_RX_PKTS_LOST_BAD_FCS_3 (CNET_REG_BASE+0x1D4) +#define CNET_REG_MF_RX_PKTS_LOST_FULL_FIFO_3 (CNET_REG_BASE+0x1D8) +#define CNET_REG_MF_RX_GOOD_PKTS_RCVD_3 (CNET_REG_BASE+0x1DC) +#define CNET_REG_MF_RX_GOOD_BYTES_RCVD_3 (CNET_REG_BASE+0x1E0) +#define CNET_REG_MF_TX_BYTES_SENT_3 (CNET_REG_BASE+0x1E4) + +#define CNET_MAC_CLK_CHK_CTRL (CNET_REG_BASE + 0xF00) +#define CNET_MAC_CLK_CHK_CNT_VALUE (CNET_REG_BASE + 0xF04) + + +/* Base address for CNET PHY registers */ +#define PHY_REG_BASE 0x600000 + +#define PHY_REG_CMD (PHY_REG_BASE) +#define PHY_REG_STATUS (PHY_REG_BASE) + +/* + * CPCI register masks + */ + +/* ID Masks */ +#define ID_VERSION 0x00FFFFFF +#define ID_REVISION 0xFF000000 + +/* Board ID Masks */ +#define BOARD_ID 0x00000F00 +#define BOARD_ID_CONTROL 0x00000001 + +/* Control masks */ +#define CTRL_CNET_RESET 0x00000100 +#define CTRL_LED 0x00000001 + +/* RESET masks */ +#define RESET_CPCI 0x00000001 + +/* Error masks */ +#define ERR_CNET_READ_TIMEOUT 0x02000000 +#define ERR_CNET_ERROR 0x01000000 +#define ERR_PROG_BUF_OVERFLOW 0x00020000 +#define ERR_PROG_ERROR 0x00010000 +#define ERR_DMA_TIMEOUT 0x00000400 +#define ERR_DMA_RETRY_CNT_EXPIRED 0x00000200 +#define ERR_DMA_BUF_OVERFLOW 0x00000100 +#define ERR_DMA_RD_SIZE_ERROR 0x00000040 +#define ERR_DMA_WR_SIZE_ERROR 0x00000020 +#define ERR_DMA_RD_ADDR_ERROR 0x00000010 +#define ERR_DMA_WR_ADDR_ERROR 0x00000008 +#define ERR_DMA_RD_MAC_ERROR 0x00000004 +#define ERR_DMA_WR_MAC_ERROR 0x00000002 +#define ERR_DMA_FATAL_ERROR 0x00000001 + +#define ERR_DMA_SETUP_ERROR ( ERR_DMA_WR_MAC_ERROR | \ + ERR_DMA_RD_MAC_ERROR | \ + ERR_DMA_WR_ADDR_ERROR | \ + ERR_DMA_RD_ADDR_ERROR | \ + ERR_DMA_WR_SIZE_ERROR | \ + ERR_DMA_RD_SIZE_ERROR ) + + +/* Interrupt masks */ +#define INT_DMA_RX_COMPLETE 0x80000000 +#define INT_DMA_TX_COMPLETE 0x40000000 +#define INT_PHY_INTERRUPT 0x20000000 +#define INT_PKT_AVAIL 0x00000100 +#define INT_CNET_ERROR 0x00000020 +#define INT_CNET_READ_TIMEOUT 0x00000010 +#define INT_PROG_ERROR 0x00000008 +#define INT_DMA_TRANSFER_ERROR 0x00000004 +#define INT_DMA_SETUP_ERROR 0x00000002 +#define INT_DMA_FATAL_ERROR 0x00000001 + +#define INT_UNKNOWN ~(INT_DMA_RX_COMPLETE | \ + INT_DMA_TX_COMPLETE | \ + INT_PHY_INTERRUPT | \ + INT_PKT_AVAIL | \ + INT_CNET_ERROR | \ + INT_CNET_READ_TIMEOUT | \ + INT_PROG_ERROR | \ + INT_DMA_TRANSFER_ERROR | \ + INT_DMA_SETUP_ERROR | \ + INT_DMA_FATAL_ERROR) + +/* Programming status */ +#define PROG_INIT 0x00010000 +#define PROG_DONE 0x00000100 +#define PROG_FIFO_EMPTY 0x00000002 +#define PROG_IN_PROGRESS 0x00000001 + +/* Programming control */ +#define PROG_CTRL_RESET 0x00000001 + +/* DMA control */ +#define DMA_CTRL_MAC 0x00000300 +#define DMA_CTRL_OWNER 0x00000001 + +/* + * CNET register masks + */ + +/* Reset masks */ +#define CNET_RESET_MAC 0x0000000F +#define CNET_RESET_MAC_3 0x00000008 +#define CNET_RESET_MAC_2 0x00000004 +#define CNET_RESET_MAC_1 0x00000002 +#define CNET_RESET_MAC_0 0x00000001 + +/* Error masks */ +#define CNET_ERROR_TX_UNDERRUN_MAC 0x000000F0 +#define CNET_ERROR_TX_UNDERRUN_MAC_3 0x00000080 +#define CNET_ERROR_TX_UNDERRUN_MAC_2 0x00000040 +#define CNET_ERROR_TX_UNDERRUN_MAC_1 0x00000020 +#define CNET_ERROR_TX_UNDERRUN_MAC_0 0x00000010 +#define CNET_ERROR_TX_OVERRUN_MAC 0x0000000F +#define CNET_ERROR_TX_OVERRUN_MAC_3 0x00000008 +#define CNET_ERROR_TX_OVERRUN_MAC_2 0x00000004 +#define CNET_ERROR_TX_OVERRUN_MAC_1 0x00000002 +#define CNET_ERROR_TX_OVERRUN_MAC_0 0x00000001 + +/* Enable masks */ +#define CNET_ENABLE_RX_FIFO 0x0000F000 +#define CNET_ENABLE_RX_FIFO_3 0x00008000 +#define CNET_ENABLE_RX_FIFO_2 0x00004000 +#define CNET_ENABLE_RX_FIFO_1 0x00002000 +#define CNET_ENABLE_RX_FIFO_0 0x00001000 +#define CNET_ENABLE_TX_MAC 0x00000F00 +#define CNET_ENABLE_TX_MAC_3 0x00000800 +#define CNET_ENABLE_TX_MAC_2 0x00000400 +#define CNET_ENABLE_TX_MAC_1 0x00000200 +#define CNET_ENABLE_TX_MAC_0 0x00000100 +#define CNET_ENABLE_DEBUG_TRISTATE 0x00000004 +#define CNET_ENABLE_INGRESS_ARBITER 0x00000002 +#define CNET_ENABLE_RX_DMA 0x00000001 + +/* MF Status masks */ +#define CNET_MF_STATUS_RX_FIFO_EMPTY 0x02000000 +#define CNET_MF_STATUS_RX_PKT_AVAIL 0x01000000 +#define CNET_MF_STATUS_RX_NUM_PKTS 0x00FF0000 +#define CNET_MF_STATUS_TX_FIFO_FULL 0x00000200 +#define CNET_MF_STATUS_TX_FIFO_NO_MAX_PKT 0x00000100 +#define CNET_MF_STATUS_TX_NUM_PKTS 0x000000FF + +/* MAC Config masks */ +#define CNET_MAC_CFG_FULL_DUPLEX 0x00000020 +#define CNET_MAC_CFG_TX_FCS_SUPPLIED 0x00000010 +#define CNET_MAC_CFG_RX_WANT_FCS 0x00000008 +#define CNET_MAC_CFG_JUMBO_ENABLE 0x00000004 + +#define CNET_MAC_CFG_SPEED 0x00000002 +#define CNET_MAC_CFG_1000_MBPS 0x00000002 +#define CNET_MAC_CFG_100_MBPS 0x00000001 +#define CNET_MAC_CFG_10_MBPS 0x00000000 + +#define CNET_RXQ_WR_PTR 0x00FF0000 +#define CNET_RXQ_RD_PTR 0x000000FF + + +/* Phy register masks */ +#define PHY_RD_WR 0x80000000 +#define PHY_PHY 0x03000000 +#define PHY_ADDR 0x001F0000 +#define PHY_DATA 0x0000FFFF + +#define PHY_DONE 0x80000000 +#define PHY_DONE_CNT 0x001F0000 + +/* Defines to calculate register values */ +/* CPCI Funcs */ +#define NF2_GET_VERSION(x) (x & 0xFFFFFF) +#define NF2_GET_REVISION(x) ((x & 0xFF000000) >> 24) + +#define NF2_GET_BOARD_ID(x) ((x & BOARD_ID) >> 8) +#define NF2_GET_CONTROL(x) (x & BOARD_ID_CONTROL) + +#define NF2_GET_CNET_RESET(x) ((x & CTRL_CNET_RESET) >> 8) +#define NF2_GET_LED(x) (x & CTRL_LED) + +#define NF2_GET_RESET(x) (x & RESET_CPCI) + +#define NF2_GET_CNET_READ_TIMEOUT(x) ((x & ERR_CNET_READ_TIMEOUT) >> 25) +#define NF2_GET_CNET_ERROR(x) ((x & ERR_CNET_ERROR) >> 24) +#define NF2_GET_PROG_BUF_OVERFLOW(x) ((x & ERR_PROG_BUF_OVERFLOW) >> 12) +#define NF2_GET_PROG_ERROR(x) ((x & ERR_PROG_ERROR) >> 11) +#define NF2_GET_DMA_TIMEOUT(x) ((x & ERR_DMA_TIMEOUT) >> 10) +#define NF2_GET_DMA_RETRY_CNT_EXPIRED(x) \ + ((x & ERR_DMA_RETRY_CNT_EXPIRED) >> 9) +#define NF2_GET_DMA_BUF_OVERFLOW(x) ((x & ERR_DMA_BUF_OVERFLOW) >> 8) +#define NF2_GET_DMA_RD_SIZE_ERROR(x) ((x & ERR_DMA_RD_SIZE_ERROR) >> 6) +#define NF2_GET_DMA_WR_SIZE_ERROR(x) ((x & ERR_DMA_WR_SIZE_ERROR) >> 5) +#define NF2_GET_DMA_RD_ADDR_ERROR(x) ((x & ERR_DMA_RD_ADDR_ERROR) >> 4) +#define NF2_GET_DMA_WR_ADDR_ERROR(x) ((x & ERR_DMA_WR_ADDR_ERROR) >> 3) +#define NF2_GET_DMA_RD_MAC_ERROR(x) ((x & ERR_DMA_RD_MAC_ERROR) >> 2) +#define NF2_GET_DMA_WR_MAC_ERROR(x) ((x & ERR_DMA_WR_MAC_ERROR) >> 1) +#define NF2_GET_DMA_FATAL_ERROR(x) (x & ERR_DMA_FATAL_ERROR) + +#define NF2_GET_INT_DMA_TX_COMPLETE(x) ((x & INT_DMA_TX_COMPLETE) >> 31) +#define NF2_GET_INT_DMA_RX_COMPLETE(x) ((x & INT_DMA_RX_COMPLETE) >> 30) +#define NF2_GET_INT_PHY_INTERRUPT(x) ((x & INT_PHY_INTERRUPT) >> 29) +#define NF2_GET_INT_PKT_AVAIL(x) ((x & INT_PKT_AVAIL) >> 8) +#define NF2_GET_INT_CNET_ERROR(x) ((x & INT_CNET_ERROR) >> 5) +#define NF2_GET_INT_CNET_READ_TIMEOUT(x) \ + ((x & INT_CNET_READ_TIMEOUT) >> 4) +#define NF2_GET_INT_PROG_ERROR(x) ((x & INT_PROG_ERROR) >> 3) +#define NF2_GET_INT_DMA_TRANSFER_ERROR(x) \ + ((x & INT_DMA_TRANSFER_ERROR) >> 2) +#define NF2_GET_INT_DMA_SETUP_ERROR(x) ((x & INT_DMA_SETUP_ERROR) >> 1) +#define NF2_GET_INT_DMA_FATAL_ERROR(x) (x & INT_DMA_FATAL_ERROR) + +#define NF2_GET_PROG_INIT(x) ((x & PROG_INIT) >> 16) +#define NF2_GET_PROG_DONE(x) ((x & PROG_DONE) >> 8) +#define NF2_GET_PROG_FIFO_EMPTY(x) ((x & PROG_FIFO_EMPTY) >> 1) +#define NF2_GET_PROG_IN_PROGRESS(x) (x & PROG_IN_PROGRESS) + +#define NF2_GET_DMA_CTRL_MAC(x) ((x & DMA_CTRL_MAC) >> 8) +#define NF2_GET_DMA_CTRL_OWNER(x) (x & DMA_CTRL_OWNER) + +#define NF2_SET_DMA_CTRL_MAC(x) (x << 8) + + +/* CNET Funcs */ +#define NF2_GET_CNET_VERSION(x) ((x & 0xFFFF0000) >> 16) +#define NF2_GET_CNET_DEVICE_ID(x) (x & 0xFFFF) + +#define NF2_GET_CNET_RESET_MAC(x) (x & CNET_RESET_MAC) + +#define NF2_GET_CNET_ERROR_TX_UNDERRUN_MAC(x) \ + ((x & CNET_ERROR_TX_UNDERRUN_MAC) >> 4) +#define NF2_GET_CNET_ERROR_TX_OVERRUN_MAC(x) \ + (x & CNET_ERROR_TX_OVERRUN_MAC) + +#define NF2_GET_CNET_ENABLE_RX_FIFO(x) ((x & CNET_ENABLE_RX_FIFO) >> 12) +#define NF2_GET_CNET_ENABLE_TX_MAC(x) ((x & CNET_ENABLE_TX_MAC) >> 8) +#define NF2_GET_CNET_ENABLE_DEBUG_TRISTATE(x) \ + ((x & CNET_ENABLE_DEBUG_TRISTATE) >> 2) +#define NF2_GET_CNET_ENABLE_INGRESS_ARBITER(x) \ + ((x & CNET_ENABLE_INGRESS_ARBITER) >> 1) +#define NF2_GET_CNET_ENABLE_RX_DMA(x) (x & CNET_ENABLE_RX_DMA) + +#define NF2_GET_CNET_MF_STATUS_RX_FIFO_EMPTY(x) \ + ((x & CNET_MF_STATUS_RX_FIFO_EMPTY) >> 25) +#define NF2_GET_CNET_MF_STATUS_RX_PKT_AVAIL(x) \ + ((x & CNET_MF_STATUS_RX_PKT_AVAIL) >> 24) +#define NF2_GET_CNET_MF_STATUS_RX_NUM_PKTS(x) \ + ((x & CNET_MF_STATUS_RX_NUM_PKTS) >> 16) +#define NF2_GET_CNET_MF_STATUS_TX_FIFO_FULL(x) \ + ((x & CNET_MF_STATUS_TX_FIFO_FULL) >> 9) +#define NF2_GET_CNET_MF_STATUS_TX_FIFO_NO_MAX_PKT(x) \ + ((x & CNET_MF_STATUS_TX_FIFO_NO_MAX_PKT) >> 8) +#define NF2_GET_CNET_MF_STATUS_TX_NUM_PKTS(x) \ + (x & CNET_MF_STATUS_TX_NUM_PKTS) + +#define NF2_GET_CNET_MAC_CFG_FULL_DUPLEX(x) \ + ((x & CNET_MAC_CFG_FULL_DUPLEX) >> 5) +#define NF2_GET_CNET_MAC_CFG_TX_FCS_SUPPLIED(x) \ + ((x & CNET_MAC_CFG_TX_FCS_SUPPLIED) >> 4) +#define NF2_GET_CNET_MAC_CFG_RX_WANT_FCS(x) \ + ((x & CNET_MAC_CFG_RX_WANT_FCS) >> 3) +#define NF2_GET_CNET_MAC_CFG_JUMBO_ENABLE(x) \ + ((x & CNET_MAC_CFG_JUMBO_ENABLE) >> 2) +#define NF2_GET_CNET_MAC_CFG_SPEED(x) \ + (x & CNET_MAC_CFG_SPEED) + +#define NF2_GET_CNET_RXQ_WR_PTR(x) ((x & CNET_RXQ_WR_PTR) >> 16) +#define NF2_GET_CNET_RXQ_RD_PTR(x) (x & CNET_RXQ_RD_PTR) + + +/* PHY functions */ +#define NF2_SET_PHY_IS_READ(x) (x << 31) +#define NF2_SET_PHY_SELECT(x) (x << 24) +#define NF2_SET_PHY_ADDR(x) (x << 16) +#define NF2_SET_PHY_DATA(x) (x) + +#define NF2_GET_PHY_DATA(x) (x & PHY_DATA) +#define NF2_GET_PHY_DONE(x) ((x & PHY_DONE) >> 31) +#define NF2_GET_PHY_DONE_CNT(x) ((x & PHY_DONE_CNT) >> 16) + + +/* + * IOCTLs + */ +#define SIOCREGREAD SIOCDEVPRIVATE +#define SIOCREGWRITE (SIOCDEVPRIVATE + 1) + + +/* MDIO registers */ +#define MDIO_0_AUX_STATUS 0x04c0064 +#define MDIO_0_INTR_STATUS 0x04c0068 +#define MDIO_0_INTR_MASK 0x04c006c + + +/* MDIO address delta between each phy base address */ +#define ADDRESS_DELTA 0x80 + + +/* MDIO bit positions */ +#define INTR_LINK_STATUS_POS 0x2 +#define AUX_LINK_STATUS_POS 0x4 + + +/* + * Structure for transferring register data via an IOCTL + */ +struct nf2reg { + unsigned int reg; + unsigned int val; +}; + +#endif diff --git a/openflow/hw-lib/nf2/nf2_drv.c b/openflow/hw-lib/nf2/nf2_drv.c new file mode 100644 index 00000000..36f3de1a --- /dev/null +++ b/openflow/hw-lib/nf2/nf2_drv.c @@ -0,0 +1,847 @@ +/*- + * Copyright (c) 2008, 2009, 2010 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#include +#include +#include + +#include "udatapath/switch-flow.h" +#include "udatapath/table.h" +#include "timeval.h" +#include "reg_defines_openflow_switch.h" +#include "nf2.h" +#include "nf2util.h" +#include "hw_flow.h" +#include "nf2_drv.h" +#include "nf2_lib.h" +#include "debug.h" + +static void log_entry(nf2_of_entry_wrap *); +static void log_entry_raw(nf2_of_entry_wrap *); +static void log_mask(nf2_of_mask_wrap *); +static void log_mask_raw(nf2_of_mask_wrap *); +static void log_action(nf2_of_action_wrap *); +static void log_action_raw(nf2_of_action_wrap *); +static void log_watchdog_info(struct nf2device *); +static void nf2_get_all_ports_info_addr(struct nf2_all_ports_info_addr *); + +static void +log_entry(nf2_of_entry_wrap *entry) +{ + int i; + + DBG_VERBOSE("log entry\n"); +#ifdef HWTABLE_NO_DEBUG + return; +#else + + // Log the physical source port + DBG_VERBOSE("E psrc[%i] ", entry->entry.src_port / 2); + + // Log the link layer source + DBG_VERBOSE("dlsrc["); + for (i = 5; i > 0; --i) { + DBG_VERBOSE("%0X:", entry->entry.eth_src[i]); + } + DBG_VERBOSE("%0X] ", entry->entry.eth_src[0]); + + // Log the link layer dest + DBG_VERBOSE("dldst["); + for (i = 5; i > 0; --i) { + DBG_VERBOSE("%0X:", entry->entry.eth_dst[i]); + } + DBG_VERBOSE("%0X] ", entry->entry.eth_dst[0]); + + // Log the link layer type + DBG_VERBOSE("dltype[%0X] ", entry->entry.eth_type); + + // Log the link layer vlan + DBG_VERBOSE("dlvlan[%0X] ", entry->entry.vlan_id); + + // Log the network source + DBG_VERBOSE("nwsrc["); + DBG_VERBOSE("%0i.", (entry->entry.ip_src >> 24) & 0xFF); + DBG_VERBOSE("%0i.", (entry->entry.ip_src >> 16) & 0xFF); + DBG_VERBOSE("%0i.", (entry->entry.ip_src >> 8) & 0xFF); + DBG_VERBOSE("%0i", entry->entry.ip_src & 0xFF); + DBG_VERBOSE("] "); + + // Log the network dest + DBG_VERBOSE("nwdst["); + DBG_VERBOSE("%0i.", (entry->entry.ip_dst >> 24) & 0xFF); + DBG_VERBOSE("%0i.", (entry->entry.ip_dst >> 16) & 0xFF); + DBG_VERBOSE("%0i.", (entry->entry.ip_dst >> 8) & 0xFF); + DBG_VERBOSE("%0i", entry->entry.ip_dst & 0xFF); + DBG_VERBOSE("] "); + + // Log the network TOS + DBG_VERBOSE("nwtos[0x%0X] ", entry->entry.ip_tos); + + // Log the transport source port + DBG_VERBOSE("tsrc[%i] ", entry->entry.transp_src); + + // Log the transport dest port + DBG_VERBOSE("tdst[%i]\n", entry->entry.transp_dst); +#endif +} + +static void +log_entry_raw(nf2_of_entry_wrap *entry) +{ +#ifdef HWTABLE_NO_DEBUG + return; +#else + int i; + unsigned char *c; + + DBG_VERBOSE("E "); + c = (unsigned char *)entry; + for (i = 0; i < sizeof(nf2_of_entry_wrap); ++i) { + if (!(i % 4)) { + DBG_VERBOSE(" "); + } + DBG_VERBOSE("%02x", c[i]); + } + DBG_VERBOSE("\n"); +#endif +} + +static void +log_mask(nf2_of_mask_wrap *mask) +{ +#ifdef HWTABLE_NO_DEBUG + return; +#else + int i; + + // Log the physical source port + DBG_VERBOSE("M psrc[%0X] ", mask->entry.src_port / 2); + + // Log the link layer source + DBG_VERBOSE("dlsrc["); + for (i = 5; i > 0; --i) { + DBG_VERBOSE("%0X:", mask->entry.eth_src[i]); + } + DBG_VERBOSE("%0X] ", mask->entry.eth_src[0]); + + // Log the link layer dest + DBG_VERBOSE("dldst["); + for (i = 5; i > 0; --i) { + DBG_VERBOSE("%0X:", mask->entry.eth_dst[i]); + } + DBG_VERBOSE("%0X] ", mask->entry.eth_dst[0]); + + // Log the link layer type + DBG_VERBOSE("dltype[%0X] ", mask->entry.eth_type); + + // Log the link layer vlan + DBG_VERBOSE("dlvlan[%0X] ", mask->entry.vlan_id); + + // Log the network source + DBG_VERBOSE("nwsrc["); + DBG_VERBOSE("%0X.", (mask->entry.ip_src >> 24) & 0xFF); + DBG_VERBOSE("%0X.", (mask->entry.ip_src >> 16) & 0xFF); + DBG_VERBOSE("%0X.", (mask->entry.ip_src >> 8) & 0xFF); + DBG_VERBOSE("%0X", mask->entry.ip_src & 0xFF); + DBG_VERBOSE("] "); + + // Log the network dest + DBG_VERBOSE("nwdst["); + DBG_VERBOSE("%0X.", (mask->entry.ip_dst >> 24) & 0xFF); + DBG_VERBOSE("%0X.", (mask->entry.ip_dst >> 16) & 0xFF); + DBG_VERBOSE("%0X.", (mask->entry.ip_dst >> 8) & 0xFF); + DBG_VERBOSE("%0X", mask->entry.ip_dst & 0xFF); + DBG_VERBOSE("] "); + + // Log the network TOS + DBG_VERBOSE("nwtos[0x%0X] ", mask->entry.ip_tos); + + // Log the transport source port + DBG_VERBOSE("tsrc[%0X] ", mask->entry.transp_src); + + // Log the transport dest port + DBG_VERBOSE("tdst[%0X]\n", mask->entry.transp_dst); +#endif +} + +static void +log_mask_raw(nf2_of_mask_wrap *mask) +{ +#ifdef HWTABLE_NO_DEBUG + return; +#else + int i; + unsigned char *c; + + DBG_VERBOSE("M "); + c = (unsigned char *)mask; + for (i = 0; i < sizeof(nf2_of_mask_wrap); ++i) { + if (!(i % 4)) { + DBG_VERBOSE(" "); + } + DBG_VERBOSE("%02x", c[i]); + } + DBG_VERBOSE("\n"); +#endif +} + +static void +log_action(nf2_of_action_wrap *action) +{ +#ifdef HWTABLE_NO_DEBUG + return; +#else + int i; + + DBG_VERBOSE("A Output P["); + for (i = 0; i < 4; ++i) { + if (action->action.forward_bitmask & (1 << (i * 2))) { + DBG_VERBOSE("%i", i); + } + } + DBG_VERBOSE("] CPU["); + for (i = 0; i < 4; ++i) { + if (action->action.forward_bitmask & (1 << (1 + (i * 2)))) { + DBG_VERBOSE("%i", i); + } + } + DBG_VERBOSE("]\n"); + + // Log the link layer source + if (action->action.nf2_action_flag & (1 << OFPAT_SET_DL_SRC)) { + DBG_VERBOSE("A Modify: dlsrc: new value ["); + for (i = 5; i > 0; --i) { + DBG_VERBOSE("%0X:", action->action.eth_src[i]); + } + DBG_VERBOSE("%0X]\n", action->action.eth_src[0]); + } + + // Log the link layer dest + if (action->action.nf2_action_flag & (1 << OFPAT_SET_DL_DST)) { + DBG_VERBOSE("A Modify: dldst: new value ["); + for (i = 5; i > 0; --i) { + DBG_VERBOSE("%0X:", action->action.eth_dst[i]); + } + DBG_VERBOSE("%0X]\n", action->action.eth_dst[0]); + } + + // Log the link layer vlan id + if (action->action.nf2_action_flag & (1 << OFPAT_SET_VLAN_VID)) { + DBG_VERBOSE("A Modify: dlvlanid: new value [%0X]\n", + action->action.vlan_id); + } + + // Log the link layer vlan pcp + if (action->action.nf2_action_flag & (1 << OFPAT_SET_VLAN_PCP)) { + DBG_VERBOSE("A Modify: dlvlanpcp: new value [%0X]\n", + action->action.vlan_pcp); + } + + // Log the link layer vlan strip + if (action->action.nf2_action_flag & (1 << OFPAT_STRIP_VLAN)) { + DBG_VERBOSE("A Modify: dlvlan strip\n"); + } + + // Log the network source + if (action->action.nf2_action_flag & (1 << OFPAT_SET_NW_SRC)) { + DBG_VERBOSE("A Modify: nwsrc: new value ["); + DBG_VERBOSE("%0i.", (action->action.ip_src >> 24) & 0xFF); + DBG_VERBOSE("%0i.", (action->action.ip_src >> 16) & 0xFF); + DBG_VERBOSE("%0i.", (action->action.ip_src >> 8) & 0xFF); + DBG_VERBOSE("%0i", action->action.ip_src & 0xFF); + DBG_VERBOSE("]\n"); + } + + // Log the network dest + if (action->action.nf2_action_flag & (1 << OFPAT_SET_NW_DST)) { + DBG_VERBOSE("A Modify: nwdst: new value ["); + DBG_VERBOSE("%0i.", (action->action.ip_dst >> 24) & 0xFF); + DBG_VERBOSE("%0i.", (action->action.ip_dst >> 16) & 0xFF); + DBG_VERBOSE("%0i.", (action->action.ip_dst >> 8) & 0xFF); + DBG_VERBOSE("%0i", action->action.ip_dst & 0xFF); + DBG_VERBOSE("]\n"); + } + + // Log the network TOS + if (action->action.nf2_action_flag & (1 << OFPAT_SET_NW_TOS)) { + DBG_VERBOSE("A Modify: nwtos: new value [%0X]\n", + action->action.ip_tos & 0xFF); + } + + // Log the transport source port + if (action->action.nf2_action_flag & (1 << OFPAT_SET_TP_SRC)) { + DBG_VERBOSE("A Modify: tsrc: new value [%0X]\n", + action->action.transp_src); + } + + // Log the transport dest port + if (action->action.nf2_action_flag & (1 << OFPAT_SET_TP_DST)) { + DBG_VERBOSE("A Modify: tdst: new value [%0X]\n", + action->action.transp_dst); + } +#endif +} + +static void +log_action_raw(nf2_of_action_wrap *action) +{ +#ifdef HWTABLE_NO_DEBUG + return; +#else + int i; + unsigned char *c; + + DBG_VERBOSE("A "); + c = (unsigned char *)action; + for (i = 0; i < sizeof(nf2_of_action_wrap); ++i) { + if (!(i % 4)) { + DBG_VERBOSE(" "); + } + DBG_VERBOSE("%02x", c[i]); + } + DBG_VERBOSE("\n"); +#endif +} + +void +nf2_reset_card(struct nf2device *dev) +{ + volatile unsigned int val; + + /* If we are operating on a NetFPGA enabled box, reset the card */ + readReg(dev, CPCI_REG_CTRL, (void *)&val); + val |= 0x100; + writeReg(dev, CPCI_REG_CTRL, val); + DBG_VERBOSE("Reset the NetFPGA.\n"); + sleep(2); +} + +void +nf2_clear_watchdog(struct nf2device *dev) +{ + volatile unsigned int enable_status; + +#ifndef NF2_WATCHDOG + return; +#endif + log_watchdog_info(dev); + + readReg(dev, WDT_ENABLE_FLG_REG, (void *)&enable_status); + enable_status &= 0x1; + + if (enable_status == WATCHDOG_DISABLE) { + enable_status = WATCHDOG_ENABLE; + writeReg(dev, WDT_ENABLE_FLG_REG, enable_status); + } +} + +/* Write a wildcard entry to the specified device and row. The row consists of + * the actual entry, its mask that specifies wildcards, as well as the action(s) + * to be taken if the row is matched + */ +int +nf2_write_of_wildcard(struct nf2device *dev, int row, + nf2_of_entry_wrap *entry, nf2_of_mask_wrap *mask, + nf2_of_action_wrap *action) +{ + int i; + unsigned int val; + + DBG_VERBOSE("** Begin wildcard entry write to row: %i\n", row); + log_entry(entry); + log_mask(mask); + log_action(action); + log_entry_raw(entry); + log_mask_raw(mask); + log_action_raw(action); + + for (i = 0; i < NF2_OF_ENTRY_WORD_LEN; ++i) { + writeReg(dev, + OPENFLOW_WILDCARD_LOOKUP_CMP_0_REG + + (4 * i), entry->raw[i]); + } + + for (i = 0; i < NF2_OF_MASK_WORD_LEN; ++i) { + writeReg(dev, + OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_0_REG + + (4 * i), mask->raw[i]); + } + + for (i = 0; i < NF2_OF_ACTION_WORD_LEN; ++i) { + writeReg(dev, + OPENFLOW_WILDCARD_LOOKUP_ACTION_0_REG + + (4 * i), action->raw[i]); + } + + // Reset the stats for the row + val = 0; + writeReg(dev, + OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG + (4 * row), + val); + writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG + (4 * row), + val); + writeReg(dev, + OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_0_REG + (4 * row), + val); + writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_WRITE_ADDR_REG, row); + + DBG_VERBOSE("** End wildcard entry write to row: %i time(msec): %llu\n", + row, time_msec()); + + return 0; +} + +int +nf2_write_of_exact(struct nf2device *dev, int row, + nf2_of_entry_wrap *entry, nf2_of_action_wrap *action) +{ + int i; + unsigned int val; + unsigned int index = row << 7; + + DBG_VERBOSE("** Begin exact match entry write to row: %i\n", row); + log_entry(entry); + log_action(action); + log_entry_raw(entry); + log_action_raw(action); + + for (i = 0; i < NF2_OF_ENTRY_WORD_LEN; ++i) { + writeReg(dev, SRAM_BASE_ADDR + index + + (4 * i), entry->raw[i]); + } + + // blank out the counters + val = 0; + for (i = 0; i < NF2_OF_EXACT_COUNTERS_WORD_LEN; ++i) { + writeReg(dev, SRAM_BASE_ADDR + index + + sizeof(nf2_of_entry_wrap) + + (4 * i), val); + } + + // write the actions + for (i = 0; i < NF2_OF_ACTION_WORD_LEN; ++i) { + writeReg(dev, SRAM_BASE_ADDR + index + + sizeof(nf2_of_entry_wrap) + + sizeof(nf2_of_exact_counters_wrap) + + (4 * i), action->raw[i]); + } + + DBG_VERBOSE + ("** End exact match entry write to row: %i time(msec): %llu\n", + row, time_msec()); + + return 0; +} + +/* Write wildcard action(s) to the specified device and row. */ +int +nf2_modify_write_of_wildcard(struct nf2device *dev, int row, + nf2_of_entry_wrap *entry, nf2_of_mask_wrap *mask, + nf2_of_action_wrap *action) +{ + int i; + unsigned int bytes_reg_val; + unsigned int pkts_reg_val; + unsigned int last_reg_val; + + DBG_VERBOSE("** Begin wildcard modified action write to row: %i\n", + row); + log_entry(entry); + log_mask(mask); + log_action(action); + log_entry_raw(entry); + log_mask_raw(mask); + log_action_raw(action); + + writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_READ_ADDR_REG, row); + readReg(dev, + OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG + (4 * row), + &bytes_reg_val); + readReg(dev, + OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG + (4 * row), + &pkts_reg_val); + readReg(dev, + OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_0_REG + (4 * row), + &last_reg_val); + + for (i = 0; i < NF2_OF_ENTRY_WORD_LEN; ++i) { + writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_CMP_0_REG + + (4 * i), entry->raw[i]); + } + + for (i = 0; i < NF2_OF_MASK_WORD_LEN; ++i) { + writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_0_REG + + (4 * i), mask->raw[i]); + } + + for (i = 0; i < NF2_OF_ACTION_WORD_LEN; ++i) { + writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_ACTION_0_REG + + (4 * i), action->raw[i]); + } + + writeReg(dev, + OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG + (4 * row), + bytes_reg_val); + writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG + (4 * row), + pkts_reg_val); + writeReg(dev, + OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_0_REG + (4 * row), + last_reg_val); + writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_WRITE_ADDR_REG, row); + + DBG_VERBOSE + ("** End wildcard modified action write to row: %i time(msec): %llu\n", + row, time_msec()); + DBG_VERBOSE(" Bytes hit count: %d\n", bytes_reg_val); + DBG_VERBOSE(" Pkts hit count: %d\n", pkts_reg_val); + DBG_VERBOSE(" Last seen : %d\n", last_reg_val); + + return 0; +} + +int +nf2_modify_write_of_exact(struct nf2device *dev, int row, + nf2_of_action_wrap *action) +{ + int i; + unsigned int index = row << 7; + + DBG_VERBOSE("** Begin exact match modified action write to row: %i\n", + row); + log_action(action); + log_action_raw(action); + + // write the actions + for (i = 0; i < NF2_OF_ACTION_WORD_LEN; ++i) { + writeReg(dev, SRAM_BASE_ADDR + index + + sizeof(nf2_of_entry_wrap) + + sizeof(nf2_of_exact_counters_wrap) + + (4 * i), action->raw[i]); + } + + DBG_VERBOSE + ("** End exact match modified action write to row: %i time(msec): %llu\n", + row, time_msec()); + + return 0; +} + +unsigned int +nf2_get_exact_packet_count(struct nf2device *dev, int row) +{ + unsigned int val = 0; + unsigned int index = 0; + + /* TODO: Need to scrape data from all 4 registers + * in the case of a wildcarded source port and + * forward all action type + */ + nf2_of_exact_counters_wrap counters; + memset(&counters, 0, sizeof(nf2_of_exact_counters_wrap)); + + // build the index to our counters + index = row << 7; + + // Read the first word into our struct, to not disturb the byte count + readReg(dev, + SRAM_BASE_ADDR + index + sizeof(nf2_of_entry_wrap), + &counters.raw[0]); + val = counters.counters.pkt_count; + + DBG_VERBOSE + ("** Exact match packet count(delta) row: %i count: %i time(msec): %llu\n", + row, val, time_msec()); + + return val; +} + +unsigned int +nf2_get_exact_byte_count(struct nf2device *dev, int row) +{ + unsigned int val = 0; + unsigned int index = 0; + + /* TODO: Need to scrape data from all 4 registers + * in the case of a wildcarded source port and + * forward all action type + */ + nf2_of_exact_counters_wrap counters; + memset(&counters, 0, sizeof(nf2_of_exact_counters_wrap)); + + // build the index to our counters + index = row << 7; + + // Read the second word into our struct, to not disturb the packet count + readReg(dev, SRAM_BASE_ADDR + index + + sizeof(nf2_of_entry_wrap) + 4, &counters.raw[1]); + val = counters.counters.byte_count; + + DBG_VERBOSE + ("** Exact match byte count(delta) row: %i count: %i time(msec): %llu\n", + row, val, time_msec()); + + return val; +} + +unsigned int +nf2_get_wildcard_packet_count(struct nf2device *dev, int row) +{ + unsigned int val = 0; + + writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_READ_ADDR_REG, row); + readReg(dev, OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG + + (4 * row), &val); + + DBG_VERBOSE + ("** Wildcard packet count(sum) row: %i count: %i time(msec): %llu\n", + row, val, time_msec()); + + return val; +} + +unsigned int +nf2_get_wildcard_byte_count(struct nf2device *dev, int row) +{ + unsigned int val = 0; + + writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_READ_ADDR_REG, row); + readReg(dev, OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG + + (4 * row), &val); + + DBG_VERBOSE + ("** Wildcard byte count(sum) row: %i count: %i time(msec): %llu\n", + row, val, time_msec()); + + return val; +} + +unsigned long int +nf2_get_matched_count(struct nf2device *dev) +{ + unsigned int val_wild = 0; + unsigned int val_exact = 0; + + readReg(dev, OPENFLOW_LOOKUP_WILDCARD_HITS_REG, &val_wild); + readReg(dev, OPENFLOW_LOOKUP_EXACT_HITS_REG, &val_exact); + + DBG_VERBOSE("** Wildcard Matched count: %i time(msec): %llu\n", + val_wild, time_msec()); + DBG_VERBOSE("** Exact Matched count: %i time(msec): %llu\n", + val_exact, time_msec()); + + return ((unsigned long int)(val_wild + val_exact)); +} + +unsigned long int +nf2_get_missed_count(struct nf2device *dev) +{ + unsigned int val_wild = 0; + unsigned int val_exact = 0; + + readReg(dev, OPENFLOW_LOOKUP_WILDCARD_MISSES_REG, &val_wild); + readReg(dev, OPENFLOW_LOOKUP_EXACT_MISSES_REG, &val_exact); + + DBG_VERBOSE("** Wildcard Missed count: %i time(msec): %llu\n", + val_wild, time_msec()); + DBG_VERBOSE("** Exact Missed count: %i time(msec): %llu\n", + val_exact, time_msec()); + + return ((unsigned long int)(val_wild + val_exact)); +} + +static void +log_watchdog_info(struct nf2device *dev) +{ +#ifdef HWTABLE_NO_DEBUG + return; +#else +#define CLK_CYCLE 8 + unsigned int nf2wdtinfo; + unsigned int elapsed_time; + readReg(dev, WDT_COUNTER_REG, &nf2wdtinfo); + elapsed_time = nf2wdtinfo * CLK_CYCLE / 1000000; + DBG_VVERB + ("%u (msec) passed since the watchdog counter has been cleared last time\n", + elapsed_time); + DBG_VVERB("NetFPGA WDT now clearing\n"); +#endif +} + +static void +nf2_get_all_ports_info_addr(struct nf2_all_ports_info_addr *nf2addr) +{ + nf2addr->rx_q_num_pkts_stored_reg[0] + = MAC_GRP_0_RX_QUEUE_NUM_PKTS_STORED_REG; + nf2addr->rx_q_num_pkts_dropped_full_reg[0] + = MAC_GRP_0_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG; + nf2addr->rx_q_num_pkts_dropped_bad_reg[0] + = MAC_GRP_0_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG; + nf2addr->rx_q_num_words_pushed_reg[0] + = MAC_GRP_0_RX_QUEUE_NUM_WORDS_PUSHED_REG; + nf2addr->rx_q_num_bytes_pushed_reg[0] + = MAC_GRP_0_RX_QUEUE_NUM_BYTES_PUSHED_REG; + nf2addr->rx_q_num_pkts_dequeued_reg[0] + = MAC_GRP_0_RX_QUEUE_NUM_PKTS_DEQUEUED_REG; + nf2addr->rx_q_num_pkts_in_queue_reg[0] + = MAC_GRP_0_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG; + nf2addr->tx_q_num_pkts_in_queue_reg[0] + = MAC_GRP_0_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG; + nf2addr->tx_q_num_pkts_sent_reg[0] + = MAC_GRP_0_TX_QUEUE_NUM_PKTS_SENT_REG; + nf2addr->tx_q_num_words_pushed_reg[0] + = MAC_GRP_0_TX_QUEUE_NUM_WORDS_PUSHED_REG; + nf2addr->tx_q_num_bytes_pushed_reg[0] + = MAC_GRP_0_TX_QUEUE_NUM_BYTES_PUSHED_REG; + nf2addr->tx_q_num_pkts_enqueued_reg[0] + = MAC_GRP_0_TX_QUEUE_NUM_PKTS_ENQUEUED_REG; + + nf2addr->rx_q_num_pkts_stored_reg[1] + = MAC_GRP_1_RX_QUEUE_NUM_PKTS_STORED_REG; + nf2addr->rx_q_num_pkts_dropped_full_reg[1] + = MAC_GRP_1_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG; + nf2addr->rx_q_num_pkts_dropped_bad_reg[1] + = MAC_GRP_1_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG; + nf2addr->rx_q_num_words_pushed_reg[1] + = MAC_GRP_1_RX_QUEUE_NUM_WORDS_PUSHED_REG; + nf2addr->rx_q_num_bytes_pushed_reg[1] + = MAC_GRP_1_RX_QUEUE_NUM_BYTES_PUSHED_REG; + nf2addr->rx_q_num_pkts_dequeued_reg[1] + = MAC_GRP_1_RX_QUEUE_NUM_PKTS_DEQUEUED_REG; + nf2addr->rx_q_num_pkts_in_queue_reg[1] + = MAC_GRP_1_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG; + nf2addr->tx_q_num_pkts_in_queue_reg[1] + = MAC_GRP_1_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG; + nf2addr->tx_q_num_pkts_sent_reg[1] + = MAC_GRP_1_TX_QUEUE_NUM_PKTS_SENT_REG; + nf2addr->tx_q_num_words_pushed_reg[1] + = MAC_GRP_1_TX_QUEUE_NUM_WORDS_PUSHED_REG; + nf2addr->tx_q_num_bytes_pushed_reg[1] + = MAC_GRP_1_TX_QUEUE_NUM_BYTES_PUSHED_REG; + nf2addr->tx_q_num_pkts_enqueued_reg[1] + = MAC_GRP_1_TX_QUEUE_NUM_PKTS_ENQUEUED_REG; + + nf2addr->rx_q_num_pkts_stored_reg[2] + = MAC_GRP_2_RX_QUEUE_NUM_PKTS_STORED_REG; + nf2addr->rx_q_num_pkts_dropped_full_reg[2] + = MAC_GRP_2_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG; + nf2addr->rx_q_num_pkts_dropped_bad_reg[2] + = MAC_GRP_2_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG; + nf2addr->rx_q_num_words_pushed_reg[2] + = MAC_GRP_2_RX_QUEUE_NUM_WORDS_PUSHED_REG; + nf2addr->rx_q_num_bytes_pushed_reg[2] + = MAC_GRP_2_RX_QUEUE_NUM_BYTES_PUSHED_REG; + nf2addr->rx_q_num_pkts_dequeued_reg[2] + = MAC_GRP_2_RX_QUEUE_NUM_PKTS_DEQUEUED_REG; + nf2addr->rx_q_num_pkts_in_queue_reg[2] + = MAC_GRP_2_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG; + nf2addr->tx_q_num_pkts_in_queue_reg[2] + = MAC_GRP_2_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG; + nf2addr->tx_q_num_pkts_sent_reg[2] + = MAC_GRP_2_TX_QUEUE_NUM_PKTS_SENT_REG; + nf2addr->tx_q_num_words_pushed_reg[2] + = MAC_GRP_2_TX_QUEUE_NUM_WORDS_PUSHED_REG; + nf2addr->tx_q_num_bytes_pushed_reg[2] + = MAC_GRP_2_TX_QUEUE_NUM_BYTES_PUSHED_REG; + nf2addr->tx_q_num_pkts_enqueued_reg[2] + = MAC_GRP_2_TX_QUEUE_NUM_PKTS_ENQUEUED_REG; + + nf2addr->rx_q_num_pkts_stored_reg[3] + = MAC_GRP_3_RX_QUEUE_NUM_PKTS_STORED_REG; + nf2addr->rx_q_num_pkts_dropped_full_reg[3] + = MAC_GRP_3_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG; + nf2addr->rx_q_num_pkts_dropped_bad_reg[3] + = MAC_GRP_3_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG; + nf2addr->rx_q_num_words_pushed_reg[3] + = MAC_GRP_3_RX_QUEUE_NUM_WORDS_PUSHED_REG; + nf2addr->rx_q_num_bytes_pushed_reg[3] + = MAC_GRP_3_RX_QUEUE_NUM_BYTES_PUSHED_REG; + nf2addr->rx_q_num_pkts_dequeued_reg[3] + = MAC_GRP_3_RX_QUEUE_NUM_PKTS_DEQUEUED_REG; + nf2addr->rx_q_num_pkts_in_queue_reg[3] + = MAC_GRP_3_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG; + nf2addr->tx_q_num_pkts_in_queue_reg[3] + = MAC_GRP_3_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG; + nf2addr->tx_q_num_pkts_sent_reg[3] + = MAC_GRP_3_TX_QUEUE_NUM_PKTS_SENT_REG; + nf2addr->tx_q_num_words_pushed_reg[3] + = MAC_GRP_3_TX_QUEUE_NUM_WORDS_PUSHED_REG; + nf2addr->tx_q_num_bytes_pushed_reg[3] + = MAC_GRP_3_TX_QUEUE_NUM_BYTES_PUSHED_REG; + nf2addr->tx_q_num_pkts_enqueued_reg[3] + = MAC_GRP_3_TX_QUEUE_NUM_PKTS_ENQUEUED_REG; +} + +int +nf2_get_port_info(struct nf2device *dev, int nf_port, + struct nf2_port_info *nf2portinfo) +{ + struct nf2_all_ports_info_addr *nf2addr; + + if ((nf_port >= NF2_PORT_NUM) || (nf_port < 0)) { + DBG_ERROR("Illegal port number\n"); + return 1; + } + + nf2addr = calloc(1, sizeof(struct nf2_all_ports_info_addr)); + if (nf2addr == NULL) { + DBG_ERROR("Could not allocate memory for port information gathering\n"); + return 1; + } + nf2_get_all_ports_info_addr(nf2addr); + + readReg(dev, nf2addr->rx_q_num_pkts_stored_reg[nf_port], + &(nf2portinfo->rx_q_num_pkts_stored)); + readReg(dev, nf2addr->rx_q_num_pkts_dropped_full_reg[nf_port], + &(nf2portinfo->rx_q_num_pkts_dropped_full)); + readReg(dev, nf2addr->rx_q_num_pkts_dropped_bad_reg[nf_port], + &(nf2portinfo->rx_q_num_pkts_dropped_bad)); + readReg(dev, nf2addr->rx_q_num_words_pushed_reg[nf_port], + &(nf2portinfo->rx_q_num_words_pushed)); + readReg(dev, nf2addr->rx_q_num_bytes_pushed_reg[nf_port], + &(nf2portinfo->rx_q_num_bytes_pushed)); + readReg(dev, nf2addr->rx_q_num_pkts_dequeued_reg[nf_port], + &(nf2portinfo->rx_q_num_pkts_dequeued)); + readReg(dev, nf2addr->rx_q_num_pkts_in_queue_reg[nf_port], + &(nf2portinfo->rx_q_num_pkts_in_queue)); + readReg(dev, nf2addr->tx_q_num_pkts_in_queue_reg[nf_port], + &(nf2portinfo->tx_q_num_pkts_in_queue)); + readReg(dev, nf2addr->tx_q_num_pkts_sent_reg[nf_port], + &(nf2portinfo->tx_q_num_pkts_sent)); + readReg(dev, nf2addr->tx_q_num_words_pushed_reg[nf_port], + &(nf2portinfo->tx_q_num_words_pushed)); + readReg(dev, nf2addr->tx_q_num_bytes_pushed_reg[nf_port], + &(nf2portinfo->tx_q_num_bytes_pushed)); + readReg(dev, nf2addr->tx_q_num_pkts_enqueued_reg[nf_port], + &(nf2portinfo->tx_q_num_pkts_enqueued)); + free(nf2addr); + return 0; +} diff --git a/openflow/hw-lib/nf2/nf2_drv.h b/openflow/hw-lib/nf2/nf2_drv.h new file mode 100644 index 00000000..6f961267 --- /dev/null +++ b/openflow/hw-lib/nf2/nf2_drv.h @@ -0,0 +1,150 @@ +/*- + * Copyright (c) 2008, 2009, 2010 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#ifndef HATABLE_NF2_NF2_OPENFLOW_H_ +#define HATABLE_NF2_NF2_OPENFLOW_H_ + +#define OPENFLOW_NF2_EXACT_TABLE_SIZE 32768 +#define WATCHDOG_ENABLE 1 +#define WATCHDOG_DISABLE 0 + +#pragma pack(push) /* push current alignment to stack */ +#pragma pack(1) /* set alignment to 1 byte boundary */ + +#define NF2_OF_ENTRY_WORD_LEN 8 +struct nf2_of_entry { + uint16_t transp_dst; + uint16_t transp_src; + uint8_t ip_proto; + uint32_t ip_dst; + uint32_t ip_src; + uint16_t eth_type; + uint8_t eth_dst[6]; + uint8_t eth_src[6]; + uint8_t src_port; + uint8_t ip_tos; + uint16_t vlan_id; + uint8_t pad; +}; + +typedef union nf2_of_entry_wrap { + struct nf2_of_entry entry; + uint32_t raw[NF2_OF_ENTRY_WORD_LEN]; +} nf2_of_entry_wrap; + +typedef nf2_of_entry_wrap nf2_of_mask_wrap; +#define NF2_OF_MASK_WORD_LEN 8 + +struct nf2_of_action { + uint16_t forward_bitmask; + uint16_t nf2_action_flag; + uint16_t vlan_id; + uint8_t vlan_pcp; + uint8_t eth_src[6]; + uint8_t eth_dst[6]; + uint32_t ip_src; + uint32_t ip_dst; + uint8_t ip_tos; + uint16_t transp_src; + uint16_t transp_dst; + uint8_t reserved[18]; +}; + +#define NF2_OF_ACTION_WORD_LEN 10 +typedef union nf2_of_action_wrap { + struct nf2_of_action action; + uint32_t raw[10]; +} nf2_of_action_wrap; + +struct nf2_of_exact_counters { + uint32_t pkt_count:25; + uint8_t last_seen:7; + uint32_t byte_count; +}; + +#define NF2_OF_EXACT_COUNTERS_WORD_LEN 2 +typedef union nf2_of_exact_counters_wrap { + struct nf2_of_exact_counters counters; + uint32_t raw[NF2_OF_EXACT_COUNTERS_WORD_LEN]; +} nf2_of_exact_counters_wrap; + +#define NF2_PORT_NUM 4 +struct nf2_all_ports_info_addr { + unsigned int rx_q_num_pkts_stored_reg[NF2_PORT_NUM]; + unsigned int rx_q_num_pkts_dropped_full_reg[NF2_PORT_NUM]; + unsigned int rx_q_num_pkts_dropped_bad_reg[NF2_PORT_NUM]; + unsigned int rx_q_num_words_pushed_reg[NF2_PORT_NUM]; + unsigned int rx_q_num_bytes_pushed_reg[NF2_PORT_NUM]; + unsigned int rx_q_num_pkts_dequeued_reg[NF2_PORT_NUM]; + unsigned int rx_q_num_pkts_in_queue_reg[NF2_PORT_NUM]; + unsigned int tx_q_num_pkts_in_queue_reg[NF2_PORT_NUM]; + unsigned int tx_q_num_pkts_sent_reg[NF2_PORT_NUM]; + unsigned int tx_q_num_words_pushed_reg[NF2_PORT_NUM]; + unsigned int tx_q_num_bytes_pushed_reg[NF2_PORT_NUM]; + unsigned int tx_q_num_pkts_enqueued_reg[NF2_PORT_NUM]; +}; + +struct nf2_port_info { + uint32_t rx_q_num_pkts_stored; + uint32_t rx_q_num_pkts_dropped_full; + uint32_t rx_q_num_pkts_dropped_bad; + uint32_t rx_q_num_words_pushed; + uint32_t rx_q_num_bytes_pushed; + uint32_t rx_q_num_pkts_dequeued; + uint32_t rx_q_num_pkts_in_queue; + uint32_t tx_q_num_pkts_in_queue; + uint32_t tx_q_num_pkts_sent; + uint32_t tx_q_num_words_pushed; + uint32_t tx_q_num_bytes_pushed; + uint32_t tx_q_num_pkts_enqueued; +}; + +#pragma pack(pop) /* XXX: Restore original alignment from stack */ + +void nf2_reset_card(struct nf2device *); +void nf2_clear_watchdog(struct nf2device *); +int nf2_write_of_wildcard(struct nf2device *, int, nf2_of_entry_wrap *, + nf2_of_mask_wrap *, nf2_of_action_wrap *); +int nf2_write_of_exact(struct nf2device *, int, nf2_of_entry_wrap *, + nf2_of_action_wrap *); +int nf2_modify_write_of_wildcard(struct nf2device *, int, nf2_of_entry_wrap *, + nf2_of_mask_wrap *, nf2_of_action_wrap *); +int nf2_modify_write_of_exact(struct nf2device *, int, nf2_of_action_wrap *); +unsigned int nf2_get_exact_packet_count(struct nf2device *, int); +unsigned int nf2_get_exact_byte_count(struct nf2device *, int); +unsigned int nf2_get_wildcard_packet_count(struct nf2device *, int); +unsigned int nf2_get_wildcard_byte_count(struct nf2device *, int); +unsigned long int nf2_get_matched_count(struct nf2device *); +unsigned long int nf2_get_missed_count(struct nf2device *); +int nf2_get_port_info(struct nf2device *, int, struct nf2_port_info *); + +#endif diff --git a/openflow/hw-lib/nf2/nf2_lib.c b/openflow/hw-lib/nf2/nf2_lib.c new file mode 100644 index 00000000..972d91bd --- /dev/null +++ b/openflow/hw-lib/nf2/nf2_lib.c @@ -0,0 +1,1049 @@ +/*- + * Copyright (c) 2008, 2009, 2010 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#include +#include + +#include "list.h" +#include "udatapath/crc32.h" +#include "udatapath/switch-flow.h" +#include "udatapath/table.h" +#include "reg_defines_openflow_switch.h" +#include "nf2.h" +#include "nf2util.h" +#include "hw_flow.h" +#include "nf2_drv.h" +#include "nf2_lib.h" +#include "debug.h" + +#define DEFAULT_IFACE "nf2c0" + +#define MAX_INT_32 0xFFFFFFFF +#define PORT_BASE 1 + +#define VID_BITMASK 0x0FFF +#define PCP_BITSHIFT 13 +#define PCP_BITMASK 0xE000 +#define TOS_BITMASK 0xFC + +struct list wildcard_free_list; +struct nf2_flow *exact_free_list[OPENFLOW_NF2_EXACT_TABLE_SIZE]; + +static uint32_t make_nw_wildcard(int); +static struct nf2_flow *get_free_exact(nf2_of_entry_wrap *); +static struct nf2_flow *get_free_wildcard(void); +static int is_action_forward_all(struct sw_flow *); +static void populate_action_output(nf2_of_action_wrap *, nf2_of_entry_wrap *, + uint8_t *); +static void populate_action_set_dl_src(nf2_of_action_wrap *, uint8_t *); +static void populate_action_set_dl_dst(nf2_of_action_wrap *, uint8_t *); +static void populate_action_set_nw_src(nf2_of_action_wrap *, uint8_t *); +static void populate_action_set_nw_dst(nf2_of_action_wrap *, uint8_t *); +static void populate_action_set_tp_src(nf2_of_action_wrap *, uint8_t *); +static void populate_action_set_tp_dst(nf2_of_action_wrap *, uint8_t *); +static void populate_action_set_nw_tos(nf2_of_action_wrap *, uint8_t *); +static void populate_action_set_vlan_vid(nf2_of_action_wrap *, uint8_t *); +static void populate_action_set_vlan_pcp(nf2_of_action_wrap *, uint8_t *); +static void populate_action_strip_vlan(nf2_of_action_wrap *); + +int iface_chk_done = 0; +int net_iface = 0; + +struct nf2device * +nf2_get_net_device(void) +{ + struct nf2device *dev; + dev = calloc(1, sizeof(struct nf2device)); + dev->device_name = DEFAULT_IFACE; + + if (iface_chk_done) { + dev->net_iface = net_iface; + } else { + if (check_iface(dev)) { + iface_chk_done = 0; + return NULL; + } else { + iface_chk_done = 1; + net_iface = dev->net_iface; + } + } + + if (openDescriptor(dev)) { + return NULL; + } + return dev; +} + +void +nf2_free_net_device(struct nf2device *dev) +{ + if (dev == NULL){ + return; + } + + closeDescriptor(dev); + free(dev); +} + +/* Checks to see if the actions requested by the flow are capable of being + * done in the NF2 hardware. Returns 1 if yes, 0 for no. + */ +int +nf2_are_actions_supported(struct sw_flow *flow) +{ + struct sw_flow_actions *sfa; + size_t actions_len; + uint8_t *p; + + sfa = flow->sf_acts; + actions_len = sfa->actions_len; + p = (uint8_t *)sfa->actions; + + while (actions_len > 0) { + struct ofp_action_header *ah = (struct ofp_action_header *)p; + struct ofp_action_output *oa = (struct ofp_action_output *)p; + size_t len = ntohs(ah->len); + + DBG_VERBOSE("Action Support Chk: Len of this action: %i\n", + len); + DBG_VERBOSE("Action Support Chk: Len of actions : %i\n", + actions_len); + + // All the modify actions are supported. + // Each of them can be specified once otherwise overwritten. + // Output action happens last. + if (!(ntohs(ah->type) == OFPAT_OUTPUT + || ntohs(ah->type) == OFPAT_SET_DL_SRC + || ntohs(ah->type) == OFPAT_SET_DL_DST + + || ntohs(ah->type) == OFPAT_SET_NW_SRC + || ntohs(ah->type) == OFPAT_SET_NW_DST + + || ntohs(ah->type) == OFPAT_SET_NW_TOS + + || ntohs(ah->type) == OFPAT_SET_TP_SRC + || ntohs(ah->type) == OFPAT_SET_TP_DST + + || ntohs(ah->type) == OFPAT_SET_VLAN_VID + || ntohs(ah->type) == OFPAT_SET_VLAN_PCP + || ntohs(ah->type) == OFPAT_STRIP_VLAN)) { + DBG_VERBOSE + ("Flow action type %#0x not supported in hardware\n", + ntohs(ah->type)); + return 0; + } + // Only support ports 1-4(incl. IN_PORT), ALL, FLOOD. + // Let CONTROLLER/LOCAL fall through + if ((ntohs(ah->type) == OFPAT_OUTPUT) + && (!((ntohs(oa->port) >= PORT_BASE) + && (ntohs(oa->port) <= MAX_IFACE)) + && !(ntohs(oa->port) == OFPP_ALL) + && !(ntohs(oa->port) == OFPP_FLOOD) + && !(ntohs(oa->port) == OFPP_IN_PORT))) { + DBG_VERBOSE + ("Flow action output port %#0x is not supported in hardware\n", + ntohs(oa->port)); + return 0; + } + p += len; + actions_len -= len; + } + + return 1; +} + +/* Write all 0's out to an exact entry position. */ +void +nf2_clear_of_exact(uint32_t pos) +{ + nf2_of_entry_wrap entry; + nf2_of_action_wrap action; + struct nf2device *dev = NULL; + + memset(&entry, 0, sizeof(nf2_of_entry_wrap)); + memset(&action, 0, sizeof(nf2_of_action_wrap)); + + dev = nf2_get_net_device(); + if (dev == NULL) { + DBG_ERROR("Could not open NetFPGA device\n"); + return; + } + nf2_write_of_exact(dev, pos, &entry, &action); + nf2_free_net_device(dev); +} + +/* + * Write all 0's out to a wildcard entry position + */ +void +nf2_clear_of_wildcard(uint32_t pos) +{ + nf2_of_entry_wrap entry; + nf2_of_mask_wrap mask; + nf2_of_action_wrap action; + struct nf2device *dev = NULL; + + memset(&entry, 0, sizeof(nf2_of_entry_wrap)); + memset(&mask, 0, sizeof(nf2_of_mask_wrap)); + memset(&action, 0, sizeof(nf2_of_action_wrap)); + + dev = nf2_get_net_device(); + if (dev == NULL) { + DBG_ERROR("Could not open NetFPGA device\n"); + return; + } + nf2_write_of_wildcard(dev, pos, &entry, &mask, &action); + nf2_free_net_device(dev); +} + +int +nf2_init_exact_freelist(void) +{ + struct nf2_flow *sfw = NULL; + int i; + + for (i = 0; i < (OPENFLOW_NF2_EXACT_TABLE_SIZE); ++i) { + sfw = calloc(1, sizeof(struct nf2_flow)); + if (sfw == NULL) { + return 1; + } + sfw->pos = i; + sfw->type = NF2_TABLE_EXACT; + nf2_add_free_exact(sfw); + sfw = NULL; + } + + return 0; +} + +int +nf2_init_wildcard_freelist(void) +{ + struct nf2_flow *sfw = NULL; + int i; + list_init(&wildcard_free_list); + + for (i = 0; i < (OPENFLOW_WILDCARD_TABLE_SIZE - RESERVED_FOR_CPU2NETFPGA); ++i) { + sfw = calloc(1, sizeof(struct nf2_flow)); + if (sfw == NULL) { + return 1; + } + sfw->pos = i; + sfw->type = NF2_TABLE_WILDCARD; + nf2_add_free_wildcard(sfw); + sfw = NULL; + } + + return 0; +} + +/* Called when the table is being deleted. */ +void +nf2_destroy_exact_freelist(void) +{ + struct nf2_flow *sfw = NULL; + int i; + + for (i = 0; i < (OPENFLOW_NF2_EXACT_TABLE_SIZE); ++i) { + sfw = exact_free_list[i]; + if (sfw) { + free(sfw); + } + sfw = NULL; + } +} + +/* Called when the table is being deleted. */ +void +nf2_destroy_wildcard_freelist(void) +{ + struct nf2_flow *sfw = NULL; + + while (!list_is_empty(&wildcard_free_list)) { + sfw = CONTAINER_OF(list_front(&wildcard_free_list), struct nf2_flow, node); + list_remove(&sfw->node); + free(sfw); + } +} + +/* Setup the wildcard table by adding static flows that will handle + * misses by sending them up to the cpu ports, and handle packets coming + * back down from the cpu by sending them out the corresponding port. + */ +int +nf2_write_static_wildcard(void) +{ + nf2_of_entry_wrap entry; + nf2_of_mask_wrap mask; + nf2_of_action_wrap action; + int i; + struct nf2device *dev; + + dev = nf2_get_net_device(); + if (dev == NULL) + return 1; + + memset(&entry, 0x00, sizeof(nf2_of_entry_wrap)); + memset(&mask, 0xFF, sizeof(nf2_of_mask_wrap)); + // Only non-wildcard section is the source port + mask.entry.src_port = 0; + memset(&action, 0, sizeof(nf2_of_action_wrap)); + + // write the catch all entries to send to the cpu + for (i = 0; i < 4; ++i) { + entry.entry.src_port = i * 2; + action.action.forward_bitmask = 0x1 << ((i * 2) + 1); + nf2_write_of_wildcard(dev, (OPENFLOW_WILDCARD_TABLE_SIZE - 4) + + i, &entry, &mask, &action); + } + + // write the entries to send out packets coming from the cpu + for (i = 0; i < 4; ++i) { + entry.entry.src_port = (i * 2) + 1; + action.action.forward_bitmask = 0x1 << (i * 2); + nf2_write_of_wildcard(dev, (OPENFLOW_WILDCARD_TABLE_SIZE - 8) + + i, &entry, &mask, &action); + } + + nf2_free_net_device(dev); + return 0; +} + +/* Populate a nf2_of_entry_wrap with entries from a struct sw_flow. */ +void +nf2_populate_of_entry(nf2_of_entry_wrap *key, struct sw_flow *flow) +{ + int vlan_vid; + int vlan_pcp; + int i; + + key->entry.transp_dst = ntohs(flow->key.flow.tp_dst); + key->entry.transp_src = ntohs(flow->key.flow.tp_src); + key->entry.ip_proto = flow->key.flow.nw_proto; + key->entry.ip_dst = ntohl(flow->key.flow.nw_dst); + key->entry.ip_src = ntohl(flow->key.flow.nw_src); + key->entry.eth_type = ntohs(flow->key.flow.dl_type); + // Blame Jad for applying endian'ness to character arrays + for (i = 0; i < 6; ++i) { + key->entry.eth_dst[i] = flow->key.flow.dl_dst[5 - i]; + } + for (i = 0; i < 6; ++i) { + key->entry.eth_src[i] = flow->key.flow.dl_src[5 - i]; + } + key->entry.src_port = (ntohs(flow->key.flow.in_port) - PORT_BASE) * 2; + key->entry.ip_tos = TOS_BITMASK & flow->key.flow.nw_tos; + if (ntohs(flow->key.flow.dl_vlan) == 0xffff) { + key->entry.vlan_id = 0xffff; + } else { + vlan_vid = VID_BITMASK & ntohs(flow->key.flow.dl_vlan); + vlan_pcp = PCP_BITMASK + & ((uint16_t)(flow->key.flow.dl_vlan_pcp) << PCP_BITSHIFT); + key->entry.vlan_id = vlan_pcp | vlan_vid; + } +} + +static uint32_t +make_nw_wildcard(int n_wild_bits) +{ + n_wild_bits &= (1u << OFPFW_NW_SRC_BITS) - 1; + return n_wild_bits < 32 ? ((1u << n_wild_bits) - 1) : 0xFFFFFFFF; +} + +/* Populate a nf2_of_mask_wrap with entries from a struct sw_flow's wildcards. */ +void +nf2_populate_of_mask(nf2_of_mask_wrap *mask, struct sw_flow *flow) +{ + int vlan_vid = 0; + int vlan_pcp = 0; + int i; + + if (OFPFW_IN_PORT & flow->key.wildcards) { + mask->entry.src_port = 0xFF; + } + if (OFPFW_DL_VLAN & flow->key.wildcards) { + vlan_vid = VID_BITMASK; + } + if (OFPFW_DL_VLAN_PCP & flow->key.wildcards) { + vlan_pcp = 0xF000; + } + mask->entry.vlan_id = vlan_pcp | vlan_vid; + if (OFPFW_DL_SRC & flow->key.wildcards) { + for (i = 0; i < 6; ++i) { + mask->entry.eth_src[i] = 0xFF; + } + } + if (OFPFW_DL_DST & flow->key.wildcards) { + for (i = 0; i < 6; ++i) { + mask->entry.eth_dst[i] = 0xFF; + } + } + if (OFPFW_DL_TYPE & flow->key.wildcards) + mask->entry.eth_type = 0xFFFF; + if ((OFPFW_NW_SRC_ALL & flow->key.wildcards) + || (OFPFW_NW_SRC_MASK & flow->key.wildcards)) + mask->entry.ip_src = make_nw_wildcard + (flow->key.wildcards >> OFPFW_NW_SRC_SHIFT); + if ((OFPFW_NW_DST_ALL & flow->key.wildcards) + || (OFPFW_NW_DST_MASK & flow->key.wildcards)) + mask->entry.ip_dst = make_nw_wildcard + (flow->key.wildcards >> OFPFW_NW_DST_SHIFT); + if (OFPFW_NW_PROTO & flow->key.wildcards) + mask->entry.ip_proto = 0xFF; + if (OFPFW_TP_SRC & flow->key.wildcards) + mask->entry.transp_src = 0xFFFF; + if (OFPFW_TP_DST & flow->key.wildcards) + mask->entry.transp_dst = 0xFFFF; + if (OFPFW_NW_TOS & flow->key.wildcards) + mask->entry.ip_tos = TOS_BITMASK; + + mask->entry.pad = 0x00; +} + +static void +populate_action_output(nf2_of_action_wrap *action, nf2_of_entry_wrap *entry, + uint8_t *flowact) +{ + uint16_t port = 0; + struct ofp_action_output *actout = (struct ofp_action_output *)flowact; + int i; + + port = ntohs(actout->port); + DBG_VERBOSE("Action Type: %i Output Port: %i\n", + ntohs(actout->type), port); + + if ((port >= PORT_BASE) && (port <= MAX_IFACE)) { + // Bitmask for output port(s), evens are phys odds cpu + action->action.forward_bitmask + |= (1 << ((port - PORT_BASE) * 2)); + DBG_VERBOSE("Output Port: %i Forward Bitmask: %x\n", + port, action->action.forward_bitmask); + } else if (port == OFPP_IN_PORT) { + // Send out to input port + action->action.forward_bitmask + |= (1 << (entry->entry.src_port)); + DBG_VERBOSE("Output Port = Input Port Forward Bitmask: %x\n", + action->action.forward_bitmask); + } else if (port == OFPP_ALL || port == OFPP_FLOOD) { + // Send out all ports except the source + for (i = 0; i < 4; ++i) { + if ((i * 2) != entry->entry.src_port) { + // Bitmask for output port(s), evens are + // phys odds cpu + action->action.forward_bitmask + |= (1 << (i * 2)); + DBG_VERBOSE + ("Output Port: %i Forward Bitmask: %x\n", + port, action->action.forward_bitmask); + } + } + } +} + +static void +populate_action_set_dl_src(nf2_of_action_wrap *action, uint8_t *flowact) +{ + struct ofp_action_dl_addr *actdl = (struct ofp_action_dl_addr *)flowact; + int i; + + for (i = 0; i < 6; ++i) { + action->action.eth_src[5 - i] = actdl->dl_addr[i]; + } + action->action.nf2_action_flag |= (1 << OFPAT_SET_DL_SRC); +} + +static void +populate_action_set_dl_dst(nf2_of_action_wrap *action, uint8_t *flowact) +{ + struct ofp_action_dl_addr *actdl = (struct ofp_action_dl_addr *)flowact; + int i; + + for (i = 0; i < 6; ++i) { + action->action.eth_dst[5 - i] = actdl->dl_addr[i]; + } + action->action.nf2_action_flag |= (1 << OFPAT_SET_DL_DST); +} + +static void +populate_action_set_nw_src(nf2_of_action_wrap *action, uint8_t *flowact) +{ + struct ofp_action_nw_addr *actnw = (struct ofp_action_nw_addr *)flowact; + action->action.ip_src = ntohl(actnw->nw_addr); + action->action.nf2_action_flag |= (1 << OFPAT_SET_NW_SRC); +} + +static void +populate_action_set_nw_dst(nf2_of_action_wrap *action, uint8_t *flowact) +{ + struct ofp_action_nw_addr *actnw = (struct ofp_action_nw_addr *)flowact; + action->action.ip_dst = ntohl(actnw->nw_addr); + action->action.nf2_action_flag |= (1 << OFPAT_SET_NW_DST); +} + +static void +populate_action_set_nw_tos(nf2_of_action_wrap *action, uint8_t *flowact) +{ + struct ofp_action_nw_tos *actnwtos = (struct ofp_action_nw_tos *)flowact; + action->action.ip_tos = actnwtos->nw_tos; + action->action.nf2_action_flag |= (1 << OFPAT_SET_NW_TOS); +} + +static void +populate_action_set_tp_src(nf2_of_action_wrap *action, uint8_t *flowact) +{ + struct ofp_action_tp_port *acttp = (struct ofp_action_tp_port *)flowact; + action->action.transp_src = ntohs(acttp->tp_port); + action->action.nf2_action_flag |= (1 << OFPAT_SET_TP_SRC); +} + +static void +populate_action_set_tp_dst(nf2_of_action_wrap *action, uint8_t *flowact) +{ + struct ofp_action_tp_port *acttp = (struct ofp_action_tp_port *)flowact; + action->action.transp_dst = ntohs(acttp->tp_port); + action->action.nf2_action_flag |= (1 << OFPAT_SET_TP_DST); +} + +static void +populate_action_set_vlan_vid(nf2_of_action_wrap *action, uint8_t *flowact) +{ + struct ofp_action_vlan_vid *actvlan = (struct ofp_action_vlan_vid *)flowact; + action->action.vlan_id = ntohs(actvlan->vlan_vid) & VID_BITMASK; + action->action.nf2_action_flag |= (1 << OFPAT_SET_VLAN_VID); +} + +static void +populate_action_set_vlan_pcp(nf2_of_action_wrap *action, uint8_t *flowact) +{ + struct ofp_action_vlan_pcp *actvlan = (struct ofp_action_vlan_pcp *)flowact; + action->action.vlan_pcp = actvlan->vlan_pcp; + action->action.nf2_action_flag |= (1 << OFPAT_SET_VLAN_PCP); +} + +static void +populate_action_strip_vlan(nf2_of_action_wrap *action) +{ + action->action.nf2_action_flag |= (1 << OFPAT_STRIP_VLAN); +} + +/* Populate an nf2_of_action_wrap. */ +void +nf2_populate_of_action(nf2_of_action_wrap *action, nf2_of_entry_wrap *entry, + struct sw_flow *flow) +{ + struct sw_flow_actions *sfa; + size_t actions_len; + uint8_t *p; + + sfa = flow->sf_acts; + actions_len = sfa->actions_len; + p = (uint8_t *)sfa->actions; + + // zero it out for now + memset(action, 0, sizeof(nf2_of_action_wrap)); + action->action.nf2_action_flag = 0; + + while (actions_len > 0) { + struct ofp_action_header *acth = (struct ofp_action_header *)p; + size_t len = ntohs(acth->len); + + DBG_VERBOSE("Action Populate: Len of this action: %i\n", len); + DBG_VERBOSE("Action Populate: Len of actions : %i\n", + actions_len); + + if (acth->type == htons(OFPAT_OUTPUT)) { + populate_action_output(action, entry, p); + } else if (acth->type == htons(OFPAT_SET_DL_SRC)) { + populate_action_set_dl_src(action, p); + } else if (acth->type == htons(OFPAT_SET_DL_DST)) { + populate_action_set_dl_dst(action, p); + } else if (acth->type == htons(OFPAT_SET_NW_SRC)) { + populate_action_set_nw_src(action, p); + } else if (acth->type == htons(OFPAT_SET_NW_DST)) { + populate_action_set_nw_dst(action, p); + } else if (acth->type == htons(OFPAT_SET_NW_TOS)) { + populate_action_set_nw_tos(action, p); + } else if (acth->type == htons(OFPAT_SET_TP_SRC)) { + populate_action_set_tp_src(action, p); + } else if (acth->type == htons(OFPAT_SET_TP_DST)) { + populate_action_set_tp_dst(action, p); + } else if (acth->type == htons(OFPAT_SET_VLAN_VID)) { + populate_action_set_vlan_vid(action, p); + } else if (acth->type == htons(OFPAT_SET_VLAN_PCP)) { + populate_action_set_vlan_pcp(action, p); + } else if (acth->type == htons(OFPAT_STRIP_VLAN)) { + populate_action_strip_vlan(action); + } + + p += len; + actions_len -= len; + } +} + +/* Add a free hardware entry back to the exact pool. */ +void +nf2_add_free_exact(struct nf2_flow *sfw) +{ + // clear the node entry + list_init(&sfw->node); + + // Critical section, adding to the actual list + exact_free_list[sfw->pos] = sfw; +} + +/* Add a free hardware entry back to the wildcard pool. */ +void +nf2_add_free_wildcard(struct nf2_flow *sfw) +{ + // clear the hw values + sfw->hw_packet_count = 0; + sfw->hw_byte_count = 0; + + // Critical section, adding to the actual list + list_insert(&wildcard_free_list, &sfw->node); +} + +/* Hashes the entry to find where it should exist in the exact table + * returns NULL on failure + */ +static struct nf2_flow * +get_free_exact(nf2_of_entry_wrap *entry) +{ + unsigned int poly1 = 0x04C11DB7; + unsigned int poly2 = 0x1EDC6F41; + struct nf2_flow *sfw = NULL; + unsigned int hash = 0x0; + unsigned int index = 0x0; + struct crc32 crc; + + crc32_init(&crc, poly1); + hash = crc32_calculate(&crc, entry, sizeof(nf2_of_entry_wrap)); + + // the bottom 15 bits of hash == the index into the table + index = 0x7FFF & hash; + + // if this index is free, grab it + sfw = exact_free_list[index]; + exact_free_list[index] = NULL; + + if (sfw != NULL) { + return sfw; + } + // try the second index + crc32_init(&crc, poly2); + hash = crc32_calculate(&crc, entry, sizeof(nf2_of_entry_wrap)); + // the bottom 15 bits of hash == the index into the table + index = 0x7FFF & hash; + + // if this index is free, grab it + sfw = exact_free_list[index]; + exact_free_list[index] = NULL; + + // return whether its good or not + return sfw; +} + +/* Get the first free position in the wildcard hardware table + * to write into. + */ +static struct nf2_flow * +get_free_wildcard(void) +{ + struct nf2_flow *sfw = NULL; + + // Critical section, pulling the first available from the list + if (list_is_empty(&wildcard_free_list)) { + // empty :( + sfw = NULL; + } else { + sfw = CONTAINER_OF(list_front(&wildcard_free_list), struct nf2_flow, node); + list_remove(&sfw->node); + list_init(&sfw->node); + } + + return sfw; +} + +/* Retrieves the type of table this flow should go into. */ +int +nf2_get_table_type(struct sw_flow *flow) +{ + if (flow->key.wildcards != 0) { + DBG_VERBOSE("--- TABLE TYPE: WILDCARD ---\n"); + return NF2_TABLE_WILDCARD; + } else { + DBG_VERBOSE("--- TABLE TYPE: EXACT ---\n"); + return NF2_TABLE_EXACT; + } +} + +/* Returns 1 if this flow contains an action outputting to all ports except + * input port, 0 otherwise. We support OFPP_ALL and OFPP_FLOOD actions, however + * since we do not perform the spanning tree protocol (STP) then OFPP_FLOOD is + * equivalent to OFPP_ALL. + */ +static int +is_action_forward_all(struct sw_flow *flow) +{ + struct sw_flow_actions *sfa; + size_t actions_len; + uint8_t *p; + + sfa = flow->sf_acts; + actions_len = sfa->actions_len; + p = (uint8_t *)sfa->actions; + + while (actions_len > 0) { + struct ofp_action_header *ah = (struct ofp_action_header *)p; + struct ofp_action_output *oa = (struct ofp_action_output *)p; + size_t len = ntohs(ah->len); + + DBG_VERBOSE("Fwd Action Chk: Action type: %x\n", + ntohs(ah->type)); + DBG_VERBOSE("Fwd Action Chk: Output port: %x\n", + ntohs(oa->port)); + DBG_VERBOSE("Fwd Action Chk: Len of this action: %i\n", len); + DBG_VERBOSE("Fwd Action Chk: Len of actions : %i\n", + actions_len); + // Currently only support the output port(s) action + if (ntohs(ah->type) == OFPAT_OUTPUT + && (ntohs(oa->port) == OFPP_ALL + || ntohs(oa->port) == OFPP_FLOOD)) { + return 1; + } + p += len; + actions_len -= len; + } + + return 0; +} + +/* Attempts to build and write the flow to hardware. + * Returns 0 on success, 1 on failure. + */ +int +nf2_build_and_write_flow(struct sw_flow *flow) +{ + struct nf2_flow *sfw = NULL; + struct nf2_flow *sfw_next = NULL; + struct nf2device *dev; + int num_entries = 0; + int i, table_type; + nf2_of_entry_wrap key; + nf2_of_mask_wrap mask; + nf2_of_action_wrap action; + + memset(&key, 0, sizeof(nf2_of_entry_wrap)); + memset(&mask, 0, sizeof(nf2_of_mask_wrap)); + memset(&action, 0, sizeof(nf2_of_action_wrap)); + + dev = nf2_get_net_device(); + if (dev == NULL) { + return 1; + } + + table_type = nf2_get_table_type(flow); + switch (table_type) { + default: + break; + + case NF2_TABLE_EXACT: + DBG_VERBOSE("---Exact Entry---\n"); + nf2_populate_of_entry(&key, flow); + nf2_populate_of_action(&action, &key, flow); + sfw = get_free_exact(&key); + if (sfw == NULL) { + DBG_VERBOSE + ("Collision getting free exact match entry\n"); + // collision + nf2_free_net_device(dev); + return 1; + } + // set the active bit on this entry + key.entry.pad = 0x80; + nf2_write_of_exact(dev, sfw->pos, &key, &action); + flow->private = (void *)sfw; + break; + + case NF2_TABLE_WILDCARD: + DBG_VERBOSE("---Wildcard Entry---\n"); + // if action is all out and source port is wildcarded + if ((is_action_forward_all(flow)) && + (flow->key.wildcards & OFPFW_IN_PORT)) { + DBG_VERBOSE("Grab four wildcard tables\n"); + if (!(sfw = get_free_wildcard())) { + DBG_VERBOSE("No free wildcard entries found."); + // no free entries + nf2_free_net_device(dev); + return 1; + } + // try to get 3 more positions + for (i = 0; i < 3; ++i) { + if (!(sfw_next = get_free_wildcard())) { + break; + } + list_insert(&sfw->node, &sfw_next->node); + ++num_entries; + } + + if (num_entries < 3) { + // failed to get enough entries, return them and exit + nf2_delete_private((void *)sfw); + nf2_free_net_device(dev); + return 1; + } + + nf2_populate_of_entry(&key, flow); + nf2_populate_of_mask(&mask, flow); + + // set first entry's src port to 0, remove wildcard mask on src + key.entry.src_port = 0; + mask.entry.src_port = 0; + nf2_populate_of_action(&action, &key, flow); + nf2_write_of_wildcard(dev, sfw->pos, &key, &mask, + &action); + + i = 1; + sfw_next = CONTAINER_OF(list_front(&sfw->node), + struct nf2_flow, node); + // walk through and write the remaining 3 entries + while (sfw_next != sfw) { + key.entry.src_port = i * 2; + nf2_populate_of_action(&action, &key, flow); + nf2_write_of_wildcard(dev, sfw_next->pos, &key, + &mask, &action); + sfw_next = CONTAINER_OF(list_front(&sfw_next->node), + struct nf2_flow, node); + ++i; + } + flow->private = (void *)sfw; + } else { + /* Get a free position here, and write to it */ + if ((sfw = get_free_wildcard())) { + nf2_populate_of_entry(&key, flow); + nf2_populate_of_mask(&mask, flow); + nf2_populate_of_action(&action, &key, flow); + if (nf2_write_of_wildcard + (dev, sfw->pos, &key, &mask, &action)) { + // failure writing to hardware + nf2_add_free_wildcard(sfw); + DBG_VERBOSE + ("Failure writing to hardware\n"); + nf2_free_net_device(dev); + return 1; + } else { + // success writing to hardware, store the position + flow->private = (void *)sfw; + } + } else { + // hardware is full, return 0 + DBG_VERBOSE("No free wildcard entries found."); + nf2_free_net_device(dev); + return 1; + } + } + break; + } + + nf2_free_net_device(dev); + return 0; +} + +void +nf2_delete_private(void *private) +{ + struct nf2_flow *sfw = (struct nf2_flow *)private; + struct nf2_flow *sfw_next; + struct list *next; + + switch (sfw->type) { + default: + break; + + case NF2_TABLE_EXACT: + nf2_clear_of_exact(sfw->pos); + nf2_add_free_exact(sfw); + break; + + case NF2_TABLE_WILDCARD: + while (!list_is_empty(&sfw->node)) { + next = sfw->node.next; + sfw_next = CONTAINER_OF(list_front(&sfw->node), struct nf2_flow, node); + list_remove(&sfw_next->node); + list_init(&sfw_next->node); + // Immediately zero out the entry in hardware + nf2_clear_of_wildcard(sfw_next->pos); + // add it back to the pool + nf2_add_free_wildcard(sfw_next); + } + // zero the core entry + nf2_clear_of_wildcard(sfw->pos); + // add back the core entry + nf2_add_free_wildcard(sfw); + break; + } +} + +int +nf2_modify_acts(struct sw_flow *flow) +{ + struct nf2_flow *sfw = (struct nf2_flow *)flow->private; + struct nf2device *dev; + nf2_of_entry_wrap key; + nf2_of_mask_wrap mask; + nf2_of_action_wrap action; + + memset(&key, 0, sizeof(nf2_of_entry_wrap)); + memset(&mask, 0, sizeof(nf2_of_mask_wrap)); + memset(&action, 0, sizeof(nf2_of_action_wrap)); + + dev = nf2_get_net_device(); + if (dev == NULL) + return 0; + + switch (sfw->type) { + default: + break; + + case NF2_TABLE_EXACT: + nf2_populate_of_entry(&key, flow); + nf2_populate_of_action(&action, &key, flow); + key.entry.pad = 0x80; + nf2_modify_write_of_exact(dev, sfw->pos, &action); + break; + + case NF2_TABLE_WILDCARD: + if (flow->key.wildcards & OFPFW_IN_PORT) { + nf2_free_net_device(dev); + return 0; + } + nf2_populate_of_entry(&key, flow); + nf2_populate_of_mask(&mask, flow); + nf2_populate_of_action(&action, &key, flow); + nf2_modify_write_of_wildcard(dev, sfw->pos, + &key, &mask, &action); + break; + } + + nf2_free_net_device(dev); + return 1; +} + +uint64_t +nf2_get_packet_count(struct nf2device *dev, struct nf2_flow *sfw) +{ + uint32_t count = 0; + uint32_t hw_count = 0; + uint64_t total = 0; + struct nf2_flow *sfw_next = NULL; + + switch (sfw->type) { + default: + break; + + case NF2_TABLE_EXACT: + // Get delta value + total = nf2_get_exact_packet_count(dev, sfw->pos); + break; + + case NF2_TABLE_WILDCARD: + sfw_next = sfw; + do { + // Get sum value + hw_count = nf2_get_wildcard_packet_count(dev, + sfw_next->pos); + if (hw_count >= sfw_next->hw_packet_count) { + count = hw_count - sfw_next->hw_packet_count; + sfw_next->hw_packet_count = hw_count; + } else { + // wrapping occurred + count = (MAX_INT_32 - sfw_next->hw_packet_count) + + hw_count; + sfw_next->hw_packet_count = hw_count; + } + total += count; + + if(!list_is_empty(&sfw_next->node)){ + sfw_next = CONTAINER_OF(list_front(&sfw_next->node), + struct nf2_flow, node); + } + } while (sfw_next != sfw); + break; + } + + return total; +} + +uint64_t +nf2_get_byte_count(struct nf2device *dev, struct nf2_flow *sfw) +{ + uint32_t count = 0; + uint32_t hw_count = 0; + uint64_t total = 0; + struct nf2_flow *sfw_next = NULL; + + switch (sfw->type) { + default: + break; + + case NF2_TABLE_EXACT: + // Get delta value + total = nf2_get_exact_byte_count(dev, sfw->pos); + break; + + case NF2_TABLE_WILDCARD: + sfw_next = sfw; + do { + // Get sum value + hw_count = nf2_get_wildcard_byte_count(dev, + sfw_next->pos); + if (hw_count >= sfw_next->hw_byte_count) { + count = hw_count - sfw_next->hw_byte_count; + sfw_next->hw_byte_count = hw_count; + } else { + // wrapping occurred + count = (MAX_INT_32 - sfw_next->hw_byte_count) + + hw_count; + sfw_next->hw_byte_count = hw_count; + } + + total += count; + + if(!list_is_empty(&sfw_next->node)) { + sfw_next = CONTAINER_OF(list_front(&sfw_next->node), + struct nf2_flow, node); + } + } while (sfw_next != sfw); + break; + } + + return total; +} diff --git a/openflow/hw-lib/nf2/nf2_lib.h b/openflow/hw-lib/nf2/nf2_lib.h new file mode 100644 index 00000000..cc75b2c6 --- /dev/null +++ b/openflow/hw-lib/nf2/nf2_lib.h @@ -0,0 +1,59 @@ +/*- + * Copyright (c) 2008, 2009, 2010 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#ifndef HWTABLE_NF2_NF2_LIB_H_ +#define HWTABLE_NF2_NF2_LIB_H_ + +struct nf2device *nf2_get_net_device(void); +void nf2_free_net_device(struct nf2device *); +int nf2_are_actions_supported(struct sw_flow *); +void nf2_clear_of_exact(uint32_t); +void nf2_clear_of_wildcard(uint32_t); +int nf2_init_exact_freelist(void); +int nf2_init_wildcard_freelist(void); +void nf2_destroy_exact_freelist(void); +void nf2_destroy_wildcard_freelist(void); +int nf2_write_static_wildcard(void); +void nf2_populate_of_entry(nf2_of_entry_wrap *, struct sw_flow *); +void nf2_populate_of_mask(nf2_of_mask_wrap *, struct sw_flow *); +void nf2_populate_of_action(nf2_of_action_wrap *, nf2_of_entry_wrap *, + struct sw_flow *); +void nf2_add_free_exact(struct nf2_flow *); +void nf2_add_free_wildcard(struct nf2_flow *); +int nf2_get_table_type(struct sw_flow *); +int nf2_build_and_write_flow(struct sw_flow *); +void nf2_delete_private(void *); +int nf2_modify_acts(struct sw_flow *); +uint64_t nf2_get_packet_count(struct nf2device *, struct nf2_flow *); +uint64_t nf2_get_byte_count(struct nf2device *, struct nf2_flow *); + +#endif diff --git a/openflow/hw-lib/nf2/nf2util.c b/openflow/hw-lib/nf2/nf2util.c new file mode 100644 index 00000000..fd3b500e --- /dev/null +++ b/openflow/hw-lib/nf2/nf2util.c @@ -0,0 +1,400 @@ +/* **************************************************************************** + * $Id: nf2util.c 3764 2008-05-22 06:48:34Z grg $ + * + * Module: nf2util.c + * Project: NetFPGA 2 Linux Kernel Driver + * Description: Utility functions for user mode programs + * + * Change history: + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include "nf2.h" +#include "nf2util.h" + +#include "reg_defines_openflow_switch.h" + +#define MD5_LEN 4 + +/* Function declarations */ +static int readRegNet(struct nf2device *nf2, unsigned reg, unsigned *val); +static int readRegFile(struct nf2device *nf2, unsigned reg, unsigned *val); +static int writeRegNet(struct nf2device *nf2, unsigned reg, unsigned val); +static int writeRegFile(struct nf2device *nf2, unsigned reg, unsigned val); + +/* Local variables */ +unsigned cpci_version = -1; +unsigned cpci_revision = -1; +unsigned nf2_device_id = -1; +unsigned nf2_revision = -1; +unsigned nf2_cpci_version = -1; +unsigned nf2_cpci_revision = -1; +char nf2_device_str[DEVICE_STR_LEN] = ""; + +/* + * readReg - read a register + */ +int readReg(struct nf2device *nf2, unsigned reg, unsigned *val) +{ + if (nf2->net_iface) + { + return readRegNet(nf2, reg, val); + } + else + { + return readRegFile(nf2, reg, val); + } +} + +/* + * readRegNet - read a register, using a network socket + */ +static int readRegNet(struct nf2device *nf2, unsigned reg, unsigned *val) +{ + struct ifreq ifreq; + struct nf2reg nf2reg; + int ret; + + nf2reg.reg = reg; + + /* Set up the ifreq structure */ + ifreq.ifr_data = (char *)&nf2reg; + strncpy(ifreq.ifr_ifrn.ifrn_name, nf2->device_name, IFNAMSIZ); + /*if (setsockopt(nf2->fd, SOL_SOCKET, SO_BINDTODEVICE, + (char *)&ifreq, sizeof(ifreq)) < 0) { + perror("sendpacket: setting SO_BINDTODEVICE"); + return -1; + } */ + + /* Call the ioctl */ + if ((ret = ioctl(nf2->fd, SIOCREGREAD, &ifreq)) == 0) + { + *val = nf2reg.val; + return 0; + } + else + { + perror("sendpacket: ioctl failed"); + return -1; + } +} + +/* + * readRegFile - read a register, using a file descriptor + */ +static int readRegFile(struct nf2device *nf2, unsigned reg, unsigned *val) +{ + struct nf2reg nf2reg; + int ret; + + nf2reg.reg = reg; + + /* Call the ioctl */ + if ((ret = ioctl(nf2->fd, SIOCREGREAD, &nf2reg)) == 0) + { + *val = nf2reg.val; + return 0; + } + else + { + perror("sendpacket: ioctl failed"); + return -1; + } +} + + +/* + * writeReg - write a register + */ +int writeReg(struct nf2device *nf2, unsigned reg, unsigned val) +{ + if (nf2->net_iface) + { + return writeRegNet(nf2, reg, val); + } + else + { + return writeRegFile(nf2, reg, val); + } +} + + +/* + * writeRegNet - write a register, using a network socket + */ +static int writeRegNet(struct nf2device *nf2, unsigned reg, unsigned val) +{ + struct ifreq ifreq; + struct nf2reg nf2reg; + int ret; + + nf2reg.reg = reg; + nf2reg.val = val; + + /* Set up the ifreq structure */ + ifreq.ifr_data = (char *)&nf2reg; + strncpy(ifreq.ifr_ifrn.ifrn_name, nf2->device_name, IFNAMSIZ); + /*if (setsockopt(nf2->fd, SOL_SOCKET, SO_BINDTODEVICE, + (char *)&ifreq, sizeof(ifreq)) < 0) { + perror("sendpacket: setting SO_BINDTODEVICE"); + return -1; + } */ + + /* Call the ioctl */ + if ((ret = ioctl(nf2->fd, SIOCREGWRITE, &ifreq)) == 0) + { + return 0; + } + else + { + perror("sendpacket: ioctl failed"); + return -1; + } +} + + +/* + * writeRegFile - write a register, using a file descriptor + */ +static int writeRegFile(struct nf2device *nf2, unsigned reg, unsigned val) +{ + struct nf2reg nf2reg; + int ret; + + nf2reg.reg = reg; + nf2reg.val = val; + + /* Call the ioctl */ + if ((ret = ioctl(nf2->fd, SIOCREGWRITE, &nf2reg)) == 0) + { + return 0; + } + else + { + perror("sendpacket: ioctl failed"); + return -1; + } +} + +/* + * Check the iface name to make sure we can find the interface + */ +int check_iface(struct nf2device *nf2) +{ + struct stat buf; + char filename[PATHLEN]; + + /* See if we can find the interface name as a network device */ + + /* Test the length first of all */ + if (strlen(nf2->device_name) > IFNAMSIZ) + { + fprintf(stderr, "Interface name is too long: %s\n", nf2->device_name); + return -1; + } + + /* Check for /sys/class/net/iface_name */ + strcpy(filename, "/sys/class/net/"); + strcat(filename, nf2->device_name); + if (stat(filename, &buf) == 0) + { + nf2->net_iface = 1; + return 0; + } + + /* Check for /dev/iface_name */ + strcpy(filename, "/dev/"); + strcat(filename, nf2->device_name); + if (stat(filename, &buf) == 0) + { + nf2->net_iface = 0; + return 0; + } + + fprintf(stderr, "Can't find device: %s\n", nf2->device_name); + return -1; +} + +/* + * Open the descriptor associated with the device name + */ +int openDescriptor(struct nf2device *nf2) +{ + struct ifreq ifreq; + char filename[PATHLEN]; + struct sockaddr_in address; + int i; + struct sockaddr_in *sin = (struct sockaddr_in *) &ifreq.ifr_addr; + int found = 0; + + if (nf2->net_iface) + { + /* Open a network socket */ + nf2->fd = socket(AF_INET, SOCK_DGRAM, 0); + if (nf2->fd == -1) + { + perror("socket: creating socket"); + return -1; + } + else + { + /* Root can bind to a network interface. + Non-root has to bind to a network address. */ + if (geteuid() == 0) + { + strncpy(ifreq.ifr_ifrn.ifrn_name, nf2->device_name, IFNAMSIZ); + if (setsockopt(nf2->fd, SOL_SOCKET, SO_BINDTODEVICE, + (char *)&ifreq, sizeof(ifreq)) < 0) { + perror("setsockopt: setting SO_BINDTODEVICE"); + return -1; + } + + } + else + { + /* Attempt to find the IP address for the interface */ + for (i = 1; ; i++) + { + /* Find interface number i*/ + ifreq.ifr_ifindex = i; + if (ioctl (nf2->fd, SIOCGIFNAME, &ifreq) < 0) + break; + + /* Check if we've found the correct interface */ + if (strcmp(ifreq.ifr_name, nf2->device_name) != 0) + continue; + + /* If we get to here we've found the IP */ + found = 1; + break; + } + + /* Verify that we found the interface */ + if (!found) + { + fprintf(stderr, "Can't find device: %s\n", nf2->device_name); + return -1; + } + + /* Attempt to get the IP address associated with the interface */ + if (ioctl (nf2->fd, SIOCGIFADDR, &ifreq) < 0) + { + perror("ioctl: calling SIOCGIFADDR"); + + fprintf(stderr, "Unable to find IP address for device: %s\n", nf2->device_name); + fprintf(stderr, "Either run this program as root or ask an administrator\n"); + fprintf(stderr, "to assign an IP address to the device\n"); + return -1; + } + + /* Set the addres and attempt to bind to the socket */ + address.sin_family = AF_INET; + address.sin_addr.s_addr = sin->sin_addr.s_addr; + address.sin_port = htons(0); + if (bind(nf2->fd,(struct sockaddr *)&address,sizeof(address)) == -1) { + perror("bind: binding"); + return -1; + } + } + } + } + else + { + strcpy(filename, "/dev/"); + strcat(filename, nf2->device_name); + nf2->fd = fileno(fopen(filename, "w+")); + if (nf2->fd == -1) + { + perror("fileno: creating descriptor"); + return -1; + } + } + + return 0; +} + +/* + * Close the descriptor associated with the device name + */ +int closeDescriptor(struct nf2device *nf2) +{ + if (nf2->net_iface) + { + close(nf2->fd); + } + else + { + close(nf2->fd); + } + + return 0; +} + +/* + * Read the version info from the Virtex and CPCI + */ +void nf2_read_info(struct nf2device *nf2) +{ + int i; + int md5_good = 1; + unsigned md5[MD5_LEN]; + unsigned cpci_id; + unsigned nf2_cpci_id; + + // Read the CPCI version/revision + readReg(nf2, CPCI_REG_ID, &cpci_id); + cpci_version = cpci_id & 0xffffff; + cpci_revision = cpci_id >> 24; + + // Verify the MD5 checksum of the device ID block + for (i = 0; i < MD5_LEN; i++) { + readReg(nf2, DEV_ID_MD5_0_REG + i * 4, &md5[i]); + } + md5_good &= md5[0] == DEV_ID_MD5_VALUE_0; + md5_good &= md5[1] == DEV_ID_MD5_VALUE_1; + md5_good &= md5[2] == DEV_ID_MD5_VALUE_2; + md5_good &= md5[3] == DEV_ID_MD5_VALUE_3; + + // Process only if the MD5 sum is good + if (md5_good) { + // Read the version and revision + readReg(nf2, DEV_ID_DEVICE_ID_REG, &nf2_device_id); + readReg(nf2, DEV_ID_REVISION_REG, &nf2_revision); + readReg(nf2, DEV_ID_CPCI_ID_REG, &nf2_cpci_id); + nf2_cpci_version = nf2_cpci_id & 0xffffff; + nf2_cpci_revision = nf2_cpci_id >> 24; + + // Read the version string + for (i = 0; i < (DEVICE_STR_LEN / 4) - 2; i++) + { + readReg(nf2, DEV_ID_DEV_STR_0_REG + i * 4, (unsigned *)(nf2_device_str + i * 4)); + + // Perform byte swapping if necessary + *(unsigned *)(nf2_device_str + i * 4) = ntohl(*(unsigned *)(nf2_device_str + i * 4)); + } + nf2_device_str[DEVICE_STR_LEN - 1] = '\0'; + } +} + +/* + * Print out a test string + */ +void printHello (struct nf2device *nf2, int *val) +{ + printf ("Hello world. Name=%s val=%d\n", nf2->device_name, *val); + *val = 10; +} diff --git a/openflow/hw-lib/nf2/nf2util.h b/openflow/hw-lib/nf2/nf2util.h new file mode 100644 index 00000000..88d3c159 --- /dev/null +++ b/openflow/hw-lib/nf2/nf2util.h @@ -0,0 +1,46 @@ +/* **************************************************************************** + * $Id: nf2util.h 3764 2008-05-22 06:48:34Z grg $ + * + * Module: nf2util.h + * Project: NetFPGA 2 Linux Kernel Driver + * Description: Header file for kernel driver + * + * Change history: + * + */ + +#ifndef _NF2UTIL_H +#define _NF2UTIL_H 1 + +#define PATHLEN 80 +#define DEVICE_STR_LEN 100 + + +/* + * Structure to represent an nf2 device to a user mode programs + */ +struct nf2device { + char *device_name; + int fd; + int net_iface; +}; + +/* Function declarations */ + +int readReg(struct nf2device *nf2, unsigned reg, unsigned *val); +int writeReg(struct nf2device *nf2, unsigned reg, unsigned val); +int check_iface(struct nf2device *nf2); +int openDescriptor(struct nf2device *nf2); +int closeDescriptor(struct nf2device *nf2); +void nf2_read_info(struct nf2device *nf2); +void printHello (struct nf2device *nf2, int *val); + +extern unsigned cpci_version; +extern unsigned cpci_revision; +extern unsigned nf2_device_id; +extern unsigned nf2_revision; +extern unsigned nf2_cpci_version; +extern unsigned nf2_cpci_revision; +extern char nf2_device_str[DEVICE_STR_LEN]; + +#endif diff --git a/openflow/hw-lib/nf2/reg_defines_openflow_switch.h b/openflow/hw-lib/nf2/reg_defines_openflow_switch.h new file mode 100644 index 00000000..0056f882 --- /dev/null +++ b/openflow/hw-lib/nf2/reg_defines_openflow_switch.h @@ -0,0 +1,767 @@ +/******************************************************** +* +* C register defines file for openflow_switch +* +********************************************************/ + +#ifndef _REG_DEFINES_ +#define _REG_DEFINES_ + +/* ========= Constants ========= */ + +// ===== File: lib/verilog/core/common/xml/global.xml ===== + +// Maximum number of phy ports +#define MAX_PHY_PORTS 4 + +// PCI address bus width +#define PCI_ADDR_WIDTH 32 + +// PCI data bus width +#define PCI_DATA_WIDTH 32 + +// PCI byte enable bus width +#define PCI_BE_WIDTH 4 + +// CPCI--CNET address bus width. This is byte addresses even though bottom bits are zero. +#define CPCI_CNET_ADDR_WIDTH 27 + +// CPCI--CNET data bus width +#define CPCI_CNET_DATA_WIDTH 32 + +// CPCI--NF2 address bus width. This is byte addresses even though bottom bits are zero. +#define CPCI_NF2_ADDR_WIDTH 27 + +// CPCI--NF2 data bus width +#define CPCI_NF2_DATA_WIDTH 32 + +// DMA data bus width +#define DMA_DATA_WIDTH 32 + +// DMA control bus width +#define DMA_CTRL_WIDTH 4 + +// CPCI debug bus width +#define CPCI_DEBUG_DATA_WIDTH 29 + +// SRAM address width +#define SRAM_ADDR_WIDTH 19 + +// SRAM data width +#define SRAM_DATA_WIDTH 36 + +// DRAM address width +#define DRAM_ADDR_WIDTH 24 + +// ===== File: lib/verilog/core/common/xml/nf_defines.xml ===== + +// Clock period of 125 MHz clock in ns +#define FAST_CLK_PERIOD 8 + +// Clock period of 62.5 MHz clock in ns +#define SLOW_CLK_PERIOD 16 + +// Header value used by the IO queues +#define IO_QUEUE_STAGE_NUM 0xff + +// Data path data width +#define DATA_WIDTH 64 + +// Data path control width +#define CTRL_WIDTH 8 + +// ===== File: projects/openflow_switch/include/output_port_lookup.xml ===== + +#define FAST_CLOCK_PERIOD 8 + +// ===== File: projects/openflow_switch/include/vlan_remover.xml ===== + +#define VLAN_CTRL_WORD 0x42 + +#define VLAN_ETHERTYPE 0x8100 + +// ===== File: lib/verilog/core/output_queues/bram_output_queues/xml/bram_output_queues.xml ===== + +#define NUM_OUTPUT_QUEUES 8 + +// ===== File: projects/openflow_switch/include/opl_processor.xml ===== + +#define NF2_OFPAT_OUTPUT 0x0001 + +#define NF2_OFPAT_SET_VLAN_VID 0x0002 + +#define NF2_OFPAT_SET_VLAN_PCP 0x0004 + +#define NF2_OFPAT_STRIP_VLAN 0x0008 + +#define NF2_OFPAT_SET_DL_SRC 0x0010 + +#define NF2_OFPAT_SET_DL_DST 0x0020 + +#define NF2_OFPAT_SET_NW_SRC 0x0040 + +#define NF2_OFPAT_SET_NW_DST 0x0080 + +#define NF2_OFPAT_SET_TP_SRC 0x0100 + +#define NF2_OFPAT_SET_TP_DST 0x0200 + +// ===== File: projects/openflow_switch/include/wildcard_match.xml ===== + +#define OPENFLOW_WILDCARD_TABLE_SIZE 32 + +#define OPENFLOW_WILDCARD_NUM_DATA_WORDS_USED 10 + +#define OPENFLOW_WILDCARD_NUM_CMP_WORDS_USED 8 + +// ===== File: lib/verilog/core/utils/xml/device_id_reg.xml ===== + +// Total number of registers +#define DEV_ID_NUM_REGS 32 + +// Number of non string registers +#define DEV_ID_NON_DEV_STR_REGS 7 + +// Device description length (in words, not chars) +#define DEV_ID_DEV_STR_WORD_LEN 25 + +// Device description length (in bytes/chars) +#define DEV_ID_DEV_STR_BYTE_LEN 100 + +// Device description length (in bits) +#define DEV_ID_DEV_STR_BIT_LEN 800 + +// Length of MD5 sum (bits) +#define DEV_ID_MD5SUM_LENGTH 128 + +// MD5 sum of the string "device_id.v" +#define DEV_ID_MD5_VALUE 0x4071736d8a603d2b4d55f62989a73c95 +#define DEV_ID_MD5_VALUE_0 0x4071736d +#define DEV_ID_MD5_VALUE_1 0x8a603d2b +#define DEV_ID_MD5_VALUE_2 0x4d55f629 +#define DEV_ID_MD5_VALUE_3 0x89a73c95 + +// ===== File: projects/openflow_switch/include/header_parser.xml ===== + +#define ETH_TYPE_IP 0x0800 + +#define IP_PROTO_TCP 0x06 + +#define IP_PROTO_UDP 0x11 + +#define IP_PROTO_ICMP 0x01 + +// ===== File: projects/openflow_switch/include/watchdog.xml ===== + +#define WDT_CPCI_REG_CTRL 0x00000008 + +// ===== File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml ===== + +// TX queue disable bit +#define MAC_GRP_TX_QUEUE_DISABLE_BIT_NUM 0 + +// RX queue disable bit +#define MAC_GRP_RX_QUEUE_DISABLE_BIT_NUM 1 + +// Reset MAC bit +#define MAC_GRP_RESET_MAC_BIT_NUM 2 + +// MAC TX queue disable bit +#define MAC_GRP_MAC_DISABLE_TX_BIT_NUM 3 + +// MAC RX queue disable bit +#define MAC_GRP_MAC_DISABLE_RX_BIT_NUM 4 + +// MAC disable jumbo TX bit +#define MAC_GRP_MAC_DIS_JUMBO_TX_BIT_NUM 5 + +// MAC disable jumbo RX bit +#define MAC_GRP_MAC_DIS_JUMBO_RX_BIT_NUM 6 + +// MAC disable crc check disable bit +#define MAC_GRP_MAC_DIS_CRC_CHECK_BIT_NUM 7 + +// MAC disable crc generate bit +#define MAC_GRP_MAC_DIS_CRC_GEN_BIT_NUM 8 + +// ===== File: projects/openflow_switch/include/match_arbiter.xml ===== + +#define OPENFLOW_ENTRY_TRANSP_DST_WIDTH 16 + +#define OPENFLOW_ENTRY_TRANSP_DST_POS 0 + +#define OPENFLOW_ENTRY_TRANSP_SRC_WIDTH 16 + +#define OPENFLOW_ENTRY_TRANSP_SRC_POS 16 + +#define OPENFLOW_ENTRY_IP_PROTO_WIDTH 8 + +#define OPENFLOW_ENTRY_IP_PROTO_POS 32 + +#define OPENFLOW_ENTRY_IP_DST_WIDTH 32 + +#define OPENFLOW_ENTRY_IP_DST_POS 40 + +#define OPENFLOW_ENTRY_IP_SRC_WIDTH 32 + +#define OPENFLOW_ENTRY_IP_SRC_POS 72 + +#define OPENFLOW_ENTRY_ETH_TYPE_WIDTH 16 + +#define OPENFLOW_ENTRY_ETH_TYPE_POS 104 + +#define OPENFLOW_ENTRY_ETH_DST_WIDTH 48 + +#define OPENFLOW_ENTRY_ETH_DST_POS 120 + +#define OPENFLOW_ENTRY_ETH_SRC_WIDTH 48 + +#define OPENFLOW_ENTRY_ETH_SRC_POS 168 + +#define OPENFLOW_ENTRY_SRC_PORT_WIDTH 8 + +#define OPENFLOW_ENTRY_SRC_PORT_POS 216 + +#define OPENFLOW_ENTRY_VLAN_ID_WIDTH 16 + +#define OPENFLOW_ENTRY_VLAN_ID_POS 224 + +#define OPENFLOW_ENTRY_WIDTH 240 + +// The actionfield is composed of a bitmask specifying actions to take and arguments. +#define OPENFLOW_ACTION_WIDTH 320 + +// Ports to forward on +#define OPENFLOW_FORWARD_BITMASK_WIDTH 16 + +#define OPENFLOW_FORWARD_BITMASK_POS 0 + +#define OPENFLOW_NF2_ACTION_FLAG_WIDTH 16 + +#define OPENFLOW_NF2_ACTION_FLAG_POS 16 + +// Vlan ID to be replaced +#define OPENFLOW_SET_VLAN_VID_WIDTH 16 + +#define OPENFLOW_SET_VLAN_VID_POS 32 + +// Vlan priority to be replaced +#define OPENFLOW_SET_VLAN_PCP_WIDTH 8 + +#define OPENFLOW_SET_VLAN_PCP_POS 48 + +// Source MAC address to be replaced +#define OPENFLOW_SET_DL_SRC_WIDTH 48 + +#define OPENFLOW_SET_DL_SRC_POS 56 + +// Destination MAC address to be replaced +#define OPENFLOW_SET_DL_DST_WIDTH 48 + +#define OPENFLOW_SET_DL_DST_POS 104 + +// Source network address to be replaced +#define OPENFLOW_SET_NW_SRC_WIDTH 32 + +#define OPENFLOW_SET_NW_SRC_POS 152 + +// Destination network address to be replaced +#define OPENFLOW_SET_NW_DST_WIDTH 32 + +#define OPENFLOW_SET_NW_DST_POS 184 + +// Source transport port to be replaced +#define OPENFLOW_SET_TP_SRC_WIDTH 16 + +#define OPENFLOW_SET_TP_SRC_POS 216 + +// Destination transport port to be replaced +#define OPENFLOW_SET_TP_DST_WIDTH 16 + +#define OPENFLOW_SET_TP_DST_POS 232 + +// ===== File: projects/openflow_switch/include/exact_match.xml ===== + +#define OPENFLOW_EXACT_ENTRY_PKT_COUNTER_WIDTH 25 + +#define OPENFLOW_EXACT_ENTRY_PKT_COUNTER_POS 0 + +#define OPENFLOW_EXACT_ENTRY_LAST_SEEN_WIDTH 7 + +#define OPENFLOW_EXACT_ENTRY_LAST_SEEN_POS 25 + +#define OPENFLOW_EXACT_ENTRY_BYTE_COUNTER_WIDTH 32 + +#define OPENFLOW_EXACT_ENTRY_BYTE_COUNTER_POS 32 + +#define OPENFLOW_EXACT_ENTRY_HDR_BASE_POS 0x00000000 + +#define OPENFLOW_EXACT_ENTRY_COUNTERS_POS 0x00000008 + +#define OPENFLOW_EXACT_ENTRY_ACTION_BASE_POS 0x0000000a + +// ------------------------------------- +// Modules +// ------------------------------------- + +// Module tags +#define CORE_BASE_ADDR 0x0000000 +#define DEV_ID_BASE_ADDR 0x0400000 +#define MDIO_BASE_ADDR 0x0440000 +#define DMA_BASE_ADDR 0x0500000 +#define MAC_GRP_0_BASE_ADDR 0x0600000 +#define MAC_GRP_1_BASE_ADDR 0x0640000 +#define MAC_GRP_2_BASE_ADDR 0x0680000 +#define MAC_GRP_3_BASE_ADDR 0x06c0000 +#define CPU_QUEUE_0_BASE_ADDR 0x0700000 +#define CPU_QUEUE_1_BASE_ADDR 0x0740000 +#define CPU_QUEUE_2_BASE_ADDR 0x0780000 +#define CPU_QUEUE_3_BASE_ADDR 0x07c0000 +#define SRAM_BASE_ADDR 0x1000000 +#define UDP_BASE_ADDR 0x2000000 +#define OPENFLOW_LOOKUP_BASE_ADDR 0x2000000 +#define IN_ARB_BASE_ADDR 0x2000100 +#define VLAN_REMOVER_BASE_ADDR 0x2000200 +#define OPL_PROCESSOR_BASE_ADDR 0x2000240 +#define HEADER_PARSER_BASE_ADDR 0x2000280 +#define MATCH_ARBITER_BASE_ADDR 0x20002c0 +#define BRAM_OQ_BASE_ADDR 0x2000300 +#define WDT_BASE_ADDR 0x2000400 +#define EXACT_MATCH_BASE_ADDR 0x2000500 +#define OPENFLOW_WILDCARD_LOOKUP_BASE_ADDR 0x2001000 +#define DRAM_BASE_ADDR 0x4000000 + +#define CPU_QUEUE_OFFSET 0x0040000 +#define MAC_GRP_OFFSET 0x0040000 + +/* ========== Registers ========== */ + +// Name: device_id (DEV_ID) +// Description: Device identification +// File: lib/verilog/core/utils/xml/device_id_reg.xml +#define DEV_ID_MD5_0_REG 0x0400000 +#define DEV_ID_MD5_1_REG 0x0400004 +#define DEV_ID_MD5_2_REG 0x0400008 +#define DEV_ID_MD5_3_REG 0x040000c +#define DEV_ID_DEVICE_ID_REG 0x0400010 +#define DEV_ID_REVISION_REG 0x0400014 +#define DEV_ID_CPCI_ID_REG 0x0400018 +#define DEV_ID_DEV_STR_0_REG 0x040001c +#define DEV_ID_DEV_STR_1_REG 0x0400020 +#define DEV_ID_DEV_STR_2_REG 0x0400024 +#define DEV_ID_DEV_STR_3_REG 0x0400028 +#define DEV_ID_DEV_STR_4_REG 0x040002c +#define DEV_ID_DEV_STR_5_REG 0x0400030 +#define DEV_ID_DEV_STR_6_REG 0x0400034 +#define DEV_ID_DEV_STR_7_REG 0x0400038 +#define DEV_ID_DEV_STR_8_REG 0x040003c +#define DEV_ID_DEV_STR_9_REG 0x0400040 +#define DEV_ID_DEV_STR_10_REG 0x0400044 +#define DEV_ID_DEV_STR_11_REG 0x0400048 +#define DEV_ID_DEV_STR_12_REG 0x040004c +#define DEV_ID_DEV_STR_13_REG 0x0400050 +#define DEV_ID_DEV_STR_14_REG 0x0400054 +#define DEV_ID_DEV_STR_15_REG 0x0400058 +#define DEV_ID_DEV_STR_16_REG 0x040005c +#define DEV_ID_DEV_STR_17_REG 0x0400060 +#define DEV_ID_DEV_STR_18_REG 0x0400064 +#define DEV_ID_DEV_STR_19_REG 0x0400068 +#define DEV_ID_DEV_STR_20_REG 0x040006c +#define DEV_ID_DEV_STR_21_REG 0x0400070 +#define DEV_ID_DEV_STR_22_REG 0x0400074 +#define DEV_ID_DEV_STR_23_REG 0x0400078 +#define DEV_ID_DEV_STR_24_REG 0x040007c + +// Name: mdio (MDIO) +// Description: MDIO interface +// File: lib/verilog/core/io/mdio/xml/mdio.xml +#define MDIO_PHY_0_CONTROL_REG 0x0440000 +#define MDIO_PHY_0_STATUS_REG 0x0440004 +#define MDIO_PHY_0_PHY_ID_0_REG 0x0440008 +#define MDIO_PHY_0_PHY_ID_1_REG 0x044000c +#define MDIO_PHY_0_AUTONEGOTIATION_ADVERT_REG 0x0440010 +#define MDIO_PHY_0_AUTONEG_LINK_PARTNER_BASE_PAGE_ABILITY_REG 0x0440014 +#define MDIO_PHY_0_AUTONEG_EXPANSION_REG 0x0440018 +#define MDIO_PHY_0_AUTONEG_NEXT_PAGE_TX_REG 0x044001c +#define MDIO_PHY_0_AUTONEG_LINK_PARTNER_RCVD_NEXT_PAGE_REG 0x0440020 +#define MDIO_PHY_0_MASTER_SLAVE_CTRL_REG 0x0440024 +#define MDIO_PHY_0_MASTER_SLAVE_STATUS_REG 0x0440028 +#define MDIO_PHY_0_PSE_CTRL_REG 0x044002c +#define MDIO_PHY_0_PSE_STATUS_REG 0x0440030 +#define MDIO_PHY_0_MMD_ACCESS_CTRL_REG 0x0440034 +#define MDIO_PHY_0_MMD_ACCESS_STATUS_REG 0x0440038 +#define MDIO_PHY_0_EXTENDED_STATUS_REG 0x044003c +#define MDIO_PHY_1_CONTROL_REG 0x0440080 +#define MDIO_PHY_1_STATUS_REG 0x0440084 +#define MDIO_PHY_1_PHY_ID_0_REG 0x0440088 +#define MDIO_PHY_1_PHY_ID_1_REG 0x044008c +#define MDIO_PHY_1_AUTONEGOTIATION_ADVERT_REG 0x0440090 +#define MDIO_PHY_1_AUTONEG_LINK_PARTNER_BASE_PAGE_ABILITY_REG 0x0440094 +#define MDIO_PHY_1_AUTONEG_EXPANSION_REG 0x0440098 +#define MDIO_PHY_1_AUTONEG_NEXT_PAGE_TX_REG 0x044009c +#define MDIO_PHY_1_AUTONEG_LINK_PARTNER_RCVD_NEXT_PAGE_REG 0x04400a0 +#define MDIO_PHY_1_MASTER_SLAVE_CTRL_REG 0x04400a4 +#define MDIO_PHY_1_MASTER_SLAVE_STATUS_REG 0x04400a8 +#define MDIO_PHY_1_PSE_CTRL_REG 0x04400ac +#define MDIO_PHY_1_PSE_STATUS_REG 0x04400b0 +#define MDIO_PHY_1_MMD_ACCESS_CTRL_REG 0x04400b4 +#define MDIO_PHY_1_MMD_ACCESS_STATUS_REG 0x04400b8 +#define MDIO_PHY_1_EXTENDED_STATUS_REG 0x04400bc +#define MDIO_PHY_2_CONTROL_REG 0x0440100 +#define MDIO_PHY_2_STATUS_REG 0x0440104 +#define MDIO_PHY_2_PHY_ID_0_REG 0x0440108 +#define MDIO_PHY_2_PHY_ID_1_REG 0x044010c +#define MDIO_PHY_2_AUTONEGOTIATION_ADVERT_REG 0x0440110 +#define MDIO_PHY_2_AUTONEG_LINK_PARTNER_BASE_PAGE_ABILITY_REG 0x0440114 +#define MDIO_PHY_2_AUTONEG_EXPANSION_REG 0x0440118 +#define MDIO_PHY_2_AUTONEG_NEXT_PAGE_TX_REG 0x044011c +#define MDIO_PHY_2_AUTONEG_LINK_PARTNER_RCVD_NEXT_PAGE_REG 0x0440120 +#define MDIO_PHY_2_MASTER_SLAVE_CTRL_REG 0x0440124 +#define MDIO_PHY_2_MASTER_SLAVE_STATUS_REG 0x0440128 +#define MDIO_PHY_2_PSE_CTRL_REG 0x044012c +#define MDIO_PHY_2_PSE_STATUS_REG 0x0440130 +#define MDIO_PHY_2_MMD_ACCESS_CTRL_REG 0x0440134 +#define MDIO_PHY_2_MMD_ACCESS_STATUS_REG 0x0440138 +#define MDIO_PHY_2_EXTENDED_STATUS_REG 0x044013c +#define MDIO_PHY_3_CONTROL_REG 0x0440180 +#define MDIO_PHY_3_STATUS_REG 0x0440184 +#define MDIO_PHY_3_PHY_ID_0_REG 0x0440188 +#define MDIO_PHY_3_PHY_ID_1_REG 0x044018c +#define MDIO_PHY_3_AUTONEGOTIATION_ADVERT_REG 0x0440190 +#define MDIO_PHY_3_AUTONEG_LINK_PARTNER_BASE_PAGE_ABILITY_REG 0x0440194 +#define MDIO_PHY_3_AUTONEG_EXPANSION_REG 0x0440198 +#define MDIO_PHY_3_AUTONEG_NEXT_PAGE_TX_REG 0x044019c +#define MDIO_PHY_3_AUTONEG_LINK_PARTNER_RCVD_NEXT_PAGE_REG 0x04401a0 +#define MDIO_PHY_3_MASTER_SLAVE_CTRL_REG 0x04401a4 +#define MDIO_PHY_3_MASTER_SLAVE_STATUS_REG 0x04401a8 +#define MDIO_PHY_3_PSE_CTRL_REG 0x04401ac +#define MDIO_PHY_3_PSE_STATUS_REG 0x04401b0 +#define MDIO_PHY_3_MMD_ACCESS_CTRL_REG 0x04401b4 +#define MDIO_PHY_3_MMD_ACCESS_STATUS_REG 0x04401b8 +#define MDIO_PHY_3_EXTENDED_STATUS_REG 0x04401bc + +#define MDIO_PHY_GROUP_BASE_ADDR 0x0440000 +#define MDIO_PHY_GROUP_INST_OFFSET 0x0000080 + +// Name: dma (DMA) +// Description: DMA transfer module +// File: lib/verilog/core/dma/xml/dma.xml + +// Name: nf2_mac_grp (MAC_GRP_0) +// Description: Ethernet MAC group +// File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml +#define MAC_GRP_0_CONTROL_REG 0x0600000 +#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0600004 +#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_STORED_REG 0x0600008 +#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG 0x060000c +#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG 0x0600010 +#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_DEQUEUED_REG 0x0600014 +#define MAC_GRP_0_RX_QUEUE_NUM_WORDS_PUSHED_REG 0x0600018 +#define MAC_GRP_0_RX_QUEUE_NUM_BYTES_PUSHED_REG 0x060001c +#define MAC_GRP_0_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0600020 +#define MAC_GRP_0_TX_QUEUE_NUM_PKTS_ENQUEUED_REG 0x0600024 +#define MAC_GRP_0_TX_QUEUE_NUM_PKTS_SENT_REG 0x0600028 +#define MAC_GRP_0_TX_QUEUE_NUM_WORDS_PUSHED_REG 0x060002c +#define MAC_GRP_0_TX_QUEUE_NUM_BYTES_PUSHED_REG 0x0600030 + +// Name: nf2_mac_grp (MAC_GRP_1) +// Description: Ethernet MAC group +// File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml +#define MAC_GRP_1_CONTROL_REG 0x0640000 +#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0640004 +#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_STORED_REG 0x0640008 +#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG 0x064000c +#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG 0x0640010 +#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_DEQUEUED_REG 0x0640014 +#define MAC_GRP_1_RX_QUEUE_NUM_WORDS_PUSHED_REG 0x0640018 +#define MAC_GRP_1_RX_QUEUE_NUM_BYTES_PUSHED_REG 0x064001c +#define MAC_GRP_1_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0640020 +#define MAC_GRP_1_TX_QUEUE_NUM_PKTS_ENQUEUED_REG 0x0640024 +#define MAC_GRP_1_TX_QUEUE_NUM_PKTS_SENT_REG 0x0640028 +#define MAC_GRP_1_TX_QUEUE_NUM_WORDS_PUSHED_REG 0x064002c +#define MAC_GRP_1_TX_QUEUE_NUM_BYTES_PUSHED_REG 0x0640030 + +// Name: nf2_mac_grp (MAC_GRP_2) +// Description: Ethernet MAC group +// File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml +#define MAC_GRP_2_CONTROL_REG 0x0680000 +#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0680004 +#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_STORED_REG 0x0680008 +#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG 0x068000c +#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG 0x0680010 +#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_DEQUEUED_REG 0x0680014 +#define MAC_GRP_2_RX_QUEUE_NUM_WORDS_PUSHED_REG 0x0680018 +#define MAC_GRP_2_RX_QUEUE_NUM_BYTES_PUSHED_REG 0x068001c +#define MAC_GRP_2_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0680020 +#define MAC_GRP_2_TX_QUEUE_NUM_PKTS_ENQUEUED_REG 0x0680024 +#define MAC_GRP_2_TX_QUEUE_NUM_PKTS_SENT_REG 0x0680028 +#define MAC_GRP_2_TX_QUEUE_NUM_WORDS_PUSHED_REG 0x068002c +#define MAC_GRP_2_TX_QUEUE_NUM_BYTES_PUSHED_REG 0x0680030 + +// Name: nf2_mac_grp (MAC_GRP_3) +// Description: Ethernet MAC group +// File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml +#define MAC_GRP_3_CONTROL_REG 0x06c0000 +#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x06c0004 +#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_STORED_REG 0x06c0008 +#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG 0x06c000c +#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG 0x06c0010 +#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_DEQUEUED_REG 0x06c0014 +#define MAC_GRP_3_RX_QUEUE_NUM_WORDS_PUSHED_REG 0x06c0018 +#define MAC_GRP_3_RX_QUEUE_NUM_BYTES_PUSHED_REG 0x06c001c +#define MAC_GRP_3_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x06c0020 +#define MAC_GRP_3_TX_QUEUE_NUM_PKTS_ENQUEUED_REG 0x06c0024 +#define MAC_GRP_3_TX_QUEUE_NUM_PKTS_SENT_REG 0x06c0028 +#define MAC_GRP_3_TX_QUEUE_NUM_WORDS_PUSHED_REG 0x06c002c +#define MAC_GRP_3_TX_QUEUE_NUM_BYTES_PUSHED_REG 0x06c0030 + +// Name: cpu_dma_queue (CPU_QUEUE_0) +// Description: CPU DMA queue +// File: lib/verilog/core/io_queues/cpu_dma_queue/xml/cpu_dma_queue.xml + +// Name: cpu_dma_queue (CPU_QUEUE_1) +// Description: CPU DMA queue +// File: lib/verilog/core/io_queues/cpu_dma_queue/xml/cpu_dma_queue.xml + +// Name: cpu_dma_queue (CPU_QUEUE_2) +// Description: CPU DMA queue +// File: lib/verilog/core/io_queues/cpu_dma_queue/xml/cpu_dma_queue.xml + +// Name: cpu_dma_queue (CPU_QUEUE_3) +// Description: CPU DMA queue +// File: lib/verilog/core/io_queues/cpu_dma_queue/xml/cpu_dma_queue.xml + +// Name: SRAM (SRAM) +// Description: SRAM + +// Name: openflow_output_port_lookup (OPENFLOW_LOOKUP) +// Description: Output Port Lookup for OpenFlow hardware datapath +// File: projects/openflow_switch/include/output_port_lookup.xml +#define OPENFLOW_LOOKUP_WILDCARD_MISSES_REG 0x2000000 +#define OPENFLOW_LOOKUP_WILDCARD_HITS_REG 0x2000004 +#define OPENFLOW_LOOKUP_EXACT_MISSES_REG 0x2000008 +#define OPENFLOW_LOOKUP_EXACT_HITS_REG 0x200000c +#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_0_REG 0x2000010 +#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_1_REG 0x2000014 +#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_2_REG 0x2000018 +#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_3_REG 0x200001c +#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_4_REG 0x2000020 +#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_5_REG 0x2000024 +#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_6_REG 0x2000028 +#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_7_REG 0x200002c +#define OPENFLOW_LOOKUP_DUMY_SOFTWARE_0_REG 0x2000030 +#define OPENFLOW_LOOKUP_DUMY_SOFTWARE_1_REG 0x2000034 +#define OPENFLOW_LOOKUP_TIMER_REG 0x2000038 + +// Name: in_arb (IN_ARB) +// Description: Round-robin input arbiter +// File: lib/verilog/core/input_arbiter/rr_input_arbiter/xml/rr_input_arbiter.xml +#define IN_ARB_NUM_PKTS_SENT_REG 0x2000100 +#define IN_ARB_LAST_PKT_WORD_0_HI_REG 0x2000104 +#define IN_ARB_LAST_PKT_WORD_0_LO_REG 0x2000108 +#define IN_ARB_LAST_PKT_CTRL_0_REG 0x200010c +#define IN_ARB_LAST_PKT_WORD_1_HI_REG 0x2000110 +#define IN_ARB_LAST_PKT_WORD_1_LO_REG 0x2000114 +#define IN_ARB_LAST_PKT_CTRL_1_REG 0x2000118 +#define IN_ARB_STATE_REG 0x200011c + +// Name: vlan_remover (VLAN_REMOVER) +// Description: Remove vlan tag and ethtype if ethtype is vlan, and store them into module header +// File: projects/openflow_switch/include/vlan_remover.xml + +// Name: opl_processor (OPL_PROCESSOR) +// Description: opl_processor +// File: projects/openflow_switch/include/opl_processor.xml + +// Name: header_parser (HEADER_PARSER) +// Description: Chop ether/IP/UDP-TCP header into 11 tuples +// File: projects/openflow_switch/include/header_parser.xml + +// Name: match_arbiter (MATCH_ARBITER) +// Description: Arbitration between exact and wildcard lookups results +// File: projects/openflow_switch/include/match_arbiter.xml + +// Name: bram_output_queues (BRAM_OQ) +// Description: BRAM-based output queues +// File: lib/verilog/core/output_queues/bram_output_queues/xml/bram_output_queues.xml +#define BRAM_OQ_DISABLE_QUEUES_REG 0x2000300 +#define BRAM_OQ_QUEUE_0_NUM_PKT_BYTES_RECEIVED_REG 0x2000380 +#define BRAM_OQ_QUEUE_0_NUM_PKTS_RECEIVED_REG 0x2000384 +#define BRAM_OQ_QUEUE_0_NUM_PKTS_DROPPED_REG 0x2000388 +#define BRAM_OQ_QUEUE_0_NUM_WORDS_IN_QUEUE_REG 0x200038c +#define BRAM_OQ_QUEUE_1_NUM_PKT_BYTES_RECEIVED_REG 0x2000390 +#define BRAM_OQ_QUEUE_1_NUM_PKTS_RECEIVED_REG 0x2000394 +#define BRAM_OQ_QUEUE_1_NUM_PKTS_DROPPED_REG 0x2000398 +#define BRAM_OQ_QUEUE_1_NUM_WORDS_IN_QUEUE_REG 0x200039c +#define BRAM_OQ_QUEUE_2_NUM_PKT_BYTES_RECEIVED_REG 0x20003a0 +#define BRAM_OQ_QUEUE_2_NUM_PKTS_RECEIVED_REG 0x20003a4 +#define BRAM_OQ_QUEUE_2_NUM_PKTS_DROPPED_REG 0x20003a8 +#define BRAM_OQ_QUEUE_2_NUM_WORDS_IN_QUEUE_REG 0x20003ac +#define BRAM_OQ_QUEUE_3_NUM_PKT_BYTES_RECEIVED_REG 0x20003b0 +#define BRAM_OQ_QUEUE_3_NUM_PKTS_RECEIVED_REG 0x20003b4 +#define BRAM_OQ_QUEUE_3_NUM_PKTS_DROPPED_REG 0x20003b8 +#define BRAM_OQ_QUEUE_3_NUM_WORDS_IN_QUEUE_REG 0x20003bc +#define BRAM_OQ_QUEUE_4_NUM_PKT_BYTES_RECEIVED_REG 0x20003c0 +#define BRAM_OQ_QUEUE_4_NUM_PKTS_RECEIVED_REG 0x20003c4 +#define BRAM_OQ_QUEUE_4_NUM_PKTS_DROPPED_REG 0x20003c8 +#define BRAM_OQ_QUEUE_4_NUM_WORDS_IN_QUEUE_REG 0x20003cc +#define BRAM_OQ_QUEUE_5_NUM_PKT_BYTES_RECEIVED_REG 0x20003d0 +#define BRAM_OQ_QUEUE_5_NUM_PKTS_RECEIVED_REG 0x20003d4 +#define BRAM_OQ_QUEUE_5_NUM_PKTS_DROPPED_REG 0x20003d8 +#define BRAM_OQ_QUEUE_5_NUM_WORDS_IN_QUEUE_REG 0x20003dc +#define BRAM_OQ_QUEUE_6_NUM_PKT_BYTES_RECEIVED_REG 0x20003e0 +#define BRAM_OQ_QUEUE_6_NUM_PKTS_RECEIVED_REG 0x20003e4 +#define BRAM_OQ_QUEUE_6_NUM_PKTS_DROPPED_REG 0x20003e8 +#define BRAM_OQ_QUEUE_6_NUM_WORDS_IN_QUEUE_REG 0x20003ec +#define BRAM_OQ_QUEUE_7_NUM_PKT_BYTES_RECEIVED_REG 0x20003f0 +#define BRAM_OQ_QUEUE_7_NUM_PKTS_RECEIVED_REG 0x20003f4 +#define BRAM_OQ_QUEUE_7_NUM_PKTS_DROPPED_REG 0x20003f8 +#define BRAM_OQ_QUEUE_7_NUM_WORDS_IN_QUEUE_REG 0x20003fc + +#define BRAM_OQ_QUEUE_GROUP_BASE_ADDR 0x2000380 +#define BRAM_OQ_QUEUE_GROUP_INST_OFFSET 0x0000010 + +// Name: watchdog (WDT) +// Description: Watchdog timer +// File: projects/openflow_switch/include/watchdog.xml +#define WDT_ENABLE_FLG_REG 0x2000400 +#define WDT_COUNTER_REG 0x2000404 + +// Name: exact_match (EXACT_MATCH) +// Description: exact match lookup +// File: projects/openflow_switch/include/exact_match.xml + +// Name: wildcard_match (OPENFLOW_WILDCARD_LOOKUP) +// Description: wildcard match lookup +// File: projects/openflow_switch/include/wildcard_match.xml +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_0_REG 0x2001000 +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_1_REG 0x2001004 +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_2_REG 0x2001008 +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_3_REG 0x200100c +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_4_REG 0x2001010 +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_5_REG 0x2001014 +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_6_REG 0x2001018 +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_7_REG 0x200101c +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_8_REG 0x2001020 +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_9_REG 0x2001024 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_0_REG 0x2001028 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_1_REG 0x200102c +#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_2_REG 0x2001030 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_3_REG 0x2001034 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_4_REG 0x2001038 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_5_REG 0x200103c +#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_6_REG 0x2001040 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_7_REG 0x2001044 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_0_REG 0x2001048 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_1_REG 0x200104c +#define OPENFLOW_WILDCARD_LOOKUP_CMP_2_REG 0x2001050 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_3_REG 0x2001054 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_4_REG 0x2001058 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_5_REG 0x200105c +#define OPENFLOW_WILDCARD_LOOKUP_CMP_6_REG 0x2001060 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_7_REG 0x2001064 +#define OPENFLOW_WILDCARD_LOOKUP_READ_ADDR_REG 0x2001068 +#define OPENFLOW_WILDCARD_LOOKUP_WRITE_ADDR_REG 0x200106c +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG 0x2001070 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_1_REG 0x2001074 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_2_REG 0x2001078 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_3_REG 0x200107c +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_4_REG 0x2001080 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_5_REG 0x2001084 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_6_REG 0x2001088 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_7_REG 0x200108c +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_8_REG 0x2001090 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_9_REG 0x2001094 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_10_REG 0x2001098 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_11_REG 0x200109c +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_12_REG 0x20010a0 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_13_REG 0x20010a4 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_14_REG 0x20010a8 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_15_REG 0x20010ac +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_16_REG 0x20010b0 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_17_REG 0x20010b4 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_18_REG 0x20010b8 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_19_REG 0x20010bc +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_20_REG 0x20010c0 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_21_REG 0x20010c4 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_22_REG 0x20010c8 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_23_REG 0x20010cc +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_24_REG 0x20010d0 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_25_REG 0x20010d4 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_26_REG 0x20010d8 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_27_REG 0x20010dc +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_28_REG 0x20010e0 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_29_REG 0x20010e4 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_30_REG 0x20010e8 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_31_REG 0x20010ec +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG 0x20010f0 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_1_REG 0x20010f4 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_2_REG 0x20010f8 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_3_REG 0x20010fc +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_4_REG 0x2001100 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_5_REG 0x2001104 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_6_REG 0x2001108 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_7_REG 0x200110c +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_8_REG 0x2001110 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_9_REG 0x2001114 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_10_REG 0x2001118 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_11_REG 0x200111c +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_12_REG 0x2001120 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_13_REG 0x2001124 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_14_REG 0x2001128 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_15_REG 0x200112c +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_16_REG 0x2001130 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_17_REG 0x2001134 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_18_REG 0x2001138 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_19_REG 0x200113c +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_20_REG 0x2001140 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_21_REG 0x2001144 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_22_REG 0x2001148 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_23_REG 0x200114c +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_24_REG 0x2001150 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_25_REG 0x2001154 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_26_REG 0x2001158 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_27_REG 0x200115c +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_28_REG 0x2001160 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_29_REG 0x2001164 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_30_REG 0x2001168 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_31_REG 0x200116c +#define OPENFLOW_WILDCARD_LOOKUP_DUMMY_1_REG 0x2001170 +#define OPENFLOW_WILDCARD_LOOKUP_DUMMY_2_REG 0x2001174 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_0_REG 0x2001178 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_1_REG 0x200117c +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_2_REG 0x2001180 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_3_REG 0x2001184 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_4_REG 0x2001188 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_5_REG 0x200118c +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_6_REG 0x2001190 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_7_REG 0x2001194 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_8_REG 0x2001198 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_9_REG 0x200119c +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_10_REG 0x20011a0 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_11_REG 0x20011a4 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_12_REG 0x20011a8 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_13_REG 0x20011ac +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_14_REG 0x20011b0 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_15_REG 0x20011b4 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_16_REG 0x20011b8 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_17_REG 0x20011bc +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_18_REG 0x20011c0 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_19_REG 0x20011c4 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_20_REG 0x20011c8 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_21_REG 0x20011cc +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_22_REG 0x20011d0 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_23_REG 0x20011d4 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_24_REG 0x20011d8 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_25_REG 0x20011dc +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_26_REG 0x20011e0 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_27_REG 0x20011e4 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_28_REG 0x20011e8 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_29_REG 0x20011ec +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_30_REG 0x20011f0 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_31_REG 0x20011f4 + +// Name: DRAM (DRAM) +// Description: DRAM + +#endif diff --git a/openflow/hw-lib/skeleton/debug.h b/openflow/hw-lib/skeleton/debug.h new file mode 100644 index 00000000..d6a8f8af --- /dev/null +++ b/openflow/hw-lib/skeleton/debug.h @@ -0,0 +1,106 @@ + +#ifndef OF_HW_DEBUG_H +#define OF_HW_DEBUG_H 1 + +#include +#include + +#if !defined(HWTABLE_NO_DEBUG) +extern int of_hw_debug; +#define dbg_send(mod, lvl, fmt, args...) \ + if (of_hw_debug >= (lvl)) fprintf(stderr, fmt, ##args) +#endif + +#define DBG_LVL_NONE -1 /* All output off */ +#define DBG_LVL_ERROR 0 /* Default value */ +#define DBG_LVL_ALWAYS 0 /* For requested dump output */ +#define DBG_LVL_WARN 1 +#define DBG_LVL_VERBOSE 2 +#define DBG_LVL_VVERB 3 /* Include success indications */ + +/* Sorry for the lazy syntax here. */ +#define DBG_CHECK(lvl) (((lvl) >= 0) && (of_hw_debug >= (lvl))) +#define DBG_ERROR(fmt, args...) dbg_send(0, DBG_LVL_ERROR, fmt, ##args) +#define DBG_ALWAYS(fmt, args...) dbg_send(0, DBG_LVL_ALWAYS, fmt, ##args) +#define DBG_WARN(fmt, args...) dbg_send(0, DBG_LVL_WARN, fmt, ##args) +#define DBG_VERBOSE(fmt, args...) dbg_send(0, DBG_LVL_VERBOSE, fmt, ##args) +#define DBG_VVERB(fmt, args...) dbg_send(0, DBG_LVL_VVERB, fmt, ##args) +#define DBG_NONE(fmt, args...) +/* Same as DEBUG_ALWAYS */ +#define DEBUGK(fmt, args...) dbg_send(0, DBG_LVL_ALWAYS, fmt, ##args) + +#define REPORT_ERROR(str) \ + DBG_ERROR("ERROR: %s:%d. %s\n", __FUNCTION__, __LINE__, str) + +/* Default debugging location string */ +#define ANNOUNCE_LOCATION DBG_VVERB("%s: %d\n", __FUNCTION__, __LINE__) +#define DBG_INCR(cnt) (++(cnt)) + +/* Should assert return? Not presently */ +#define ASSERT(cond) \ + if (!(cond)) DBG_ERROR("ASSERTION %s IN %s FAILED LINE %d\n", \ + #cond, __FUNCTION__, __LINE__) + +/* DEBUG for HW flow lists */ +#define HW_FLOW_MAGIC 0xba5eba11 +#define HW_FLOW_MAKE_VALID(hf) (hf)->magic = HW_FLOW_MAGIC +#define HW_FLOW_IS_VALID(hf) \ + (((hf) != NULL) && ((hf)->magic == HW_FLOW_MAGIC)) + +/* + * Carry out an operation and check for error, optionally returning + * from the calling routine. To avoid compiler + * warnings in routines with void return, we give two macros. + * + * WARNING: This check uses rv != 0 (not just rv < 0). + */ + +#define TRY(op, str) do { \ + int rv; \ + if (((rv = (op)) < 0)) { \ + DBG_ERROR("ERROR %d: %s\n", rv, str); \ + return rv; \ + } else { \ + DBG_NONE("%s: success\n", str); \ + } \ + } while (0) + +#define TRY_NR(op, str) do { \ + int rv; \ + if (((rv = (op)) != 0)) { \ + DBG_ERROR("ERROR %d: %s\n", rv, str); \ + } else { \ + DBG_NONE("%s: success\n", str); \ + } \ + } while (0) + +#else /* No debugging */ + +#define DBG_CHECK(lvl) 0 +#define ANNOUNCE_LOCATION +#define ACT_STRING(action) "" +#define DBG_INCR(cnt) +#define DBG_ERROR(fmt, args...) +#define DBG_ALWAYS(fmt, args...) +#define DBG_WARN(fmt, args...) +#define DBG_VERBOSE(fmt, args...) +#define DBG_VVERB(fmt, args...) +#define DBG_NONE(fmt, args...) +#define DEBUGK(fmt, args...) +#define REPORT_ERROR(str) + +#define ASSERT(cond) + +#define HW_FLOW_MAKE_VALID(hf) +#define HW_FLOW_IS_VALID(hf) 1 + +#define TRY(op, str) do { \ + int rv; \ + if (((rv = (op)) != 0)) return rv; \ + } while (0) + +#define TRY_NR(op, str) (void)op + +#endif /* !defined(HWTABLE_NO_DEBUG) */ + +#endif /* OF_HW_DEBUG_H */ diff --git a/openflow/hw-lib/skeleton/hw_drv.c b/openflow/hw-lib/skeleton/hw_drv.c new file mode 100644 index 00000000..0ecd5909 --- /dev/null +++ b/openflow/hw-lib/skeleton/hw_drv.c @@ -0,0 +1,309 @@ +/* + * Skeleton hardware datapath, internal implemenation + * + */ +#include + +#include +#include + +#include "list.h" + +#include "os.h" +#include "debug.h" +#include "of_hw_platform.h" +#include "hw_drv.h" +#include "hw_flow.h" +#include "port.h" +#include "txrx.h" +#include "udatapath/switch-flow.h" + +/**************************************************************** + * + * Hardware resource management section + * + ****************************************************************/ + +static int global_init_done = 0; +int of_hw_drv_instances = 0; + +#if !defined(HWTABLE_NO_DEBUG) +int of_hw_debug = DBG_LVL_WARN; +#endif + +/* Internal initialization of HW datapath structures */ +static int +hw_drv_global_init(int init_hw) +{ + HW_DRV_MUTEX_INIT; + of_hw_ports_init(); + + if (init_hw) { /* Do hardware initialization */ + TRY(PLATFORM_INIT(), "PLATFORM INIT"); + TRY_NR(of_hw_fp_setup(), "global FP setup"); + } + + global_init_done = 1; + return 0; +} + +/* Skeleton capabilities structure */ +static of_hw_driver_caps_t of_hw_caps = { + .flags = , + .max_flows = , + .wc_supported = OFPFW_ALL, + .actions_supported = OFPAT_XXX, + .ofpc_flags = OFPC_XXX +}; + +/* Initialize the internal HW datapath structure */ +static int +hw_drv_int_init(of_hw_driver_int_t *hw_int, struct datapath *dp) +{ + static int dp_idx = 0; + + /* Fill in caps object */ + memcpy(&hw_int->hw_driver.caps, &of_hw_caps, sizeof(of_hw_caps)); + hw_int->dp = dp; + hw_int->dp_idx = dp_idx++; + + hw_int->n_flows = 0; + list_init(&hw_int->flows); + list_init(&hw_int->iter_flows); + hw_int->next_serial = 0; + + return 0; +} + +/**************************************************************** + * + * Driver functions + * + ****************************************************************/ + +/* + * of_hw_ioctl + * + * HW IOCTL function + */ + +static int +of_hw_ioctl(of_hw_driver_t *hw_drv, uint32_t op, void **io_param, + int *io_len UNUSED) +{ + int val; + of_hw_driver_int_t *hw_int; + int rv = 0; + + hw_int = (of_hw_driver_int_t *)hw_drv; + + switch (op) { + case OF_HW_IOCTL_TABLE_DEBUG_SET: + val = *(int *)(*io_param); + DBG_WARN("Changing table debug value to %d\n", val); + /* FIXME: Use HW driver for debug level? */ + hw_int->table_debug_level = val; + of_hw_debug = val; + break; + case OF_HW_IOCTL_PORT_DEBUG_SET: + val = *(int *)(*io_param); + DBG_WARN("Changing port debug value to %d\n", val); + hw_int->port_debug_level = val; + break; + case OF_HW_IOCTL_BYTE_PKT_CNTR_SET: + val = *(int *)(*io_param); + if ((val != OF_HW_CNTR_PACKETS) && + (val != OF_HW_CNTR_BYTES)) { + DBG_ERROR("Bad byte/pkt counters select value %d\n", val); + } else { + hw_int->stat_sel = val; + } + break; + default: + rv = -1; /* Change to UNSUPPORTED */ + break; + } + + return 0; +} + +static void +of_hw_table_destroy(struct sw_table *table) +{ + of_hw_driver_int_t *hw_int; + + hw_int = (of_hw_driver_int_t *)table; + if (hw_int != NULL && hw_int->dp != NULL) { + DBG_WARN("Table destroy called for dp idx %d\n", + hw_int->dp_idx); + } else { + DBG_ERROR("Table destroy called on NULL dp\n"); + } + + delete_of_hw_driver(&hw_int->hw_driver); +} + +static int +of_hw_table_iterate(struct sw_table *table, + const struct sw_flow_key *key, uint16_t out_port, + struct sw_table_position *position, + int (*callback)(struct sw_flow *flow, void *private), + void *private) +{ + + of_hw_driver_int_t *hw_int; + struct sw_flow *flow; + unsigned long start; + + hw_int = (of_hw_driver_int_t *)table; + if (hw_int != NULL) { + start = ~position->private[0]; + LIST_FOR_EACH (flow, struct sw_flow, iter_node, &hw_int->iter_flows) { + if (flow->serial <= start + && flow_matches_2wild(key, &flow->key) + && flow_has_out_port(flow, out_port)) { + int error; + + /* Update stats as that's what's generally used */ + TRY_NR(of_hw_sw_flow_stat_update(flow, NULL, false), + "sw flow stat update"); + error = callback(flow, private); + if (error) { + position->private[0] = ~(flow->serial - 1); + return error; + } + } + } + } else { + DBG_ERROR("Table iterate called on NULL driver or SW flow table\n"); + return -1; + } + + return 0; +} + +static const char *hw_drv_name = "HW FlowDriver"; + +static void +of_hw_sw_table_stats(struct sw_table *table, struct sw_table_stats *stats) +{ + of_hw_driver_int_t *hw_int; + unsigned long matched = 0; + unsigned long missed = 0; + + hw_int = (of_hw_driver_int_t *)table; + stats->name = hw_drv_name; + stats->wildcards = OFPFW_ALL; + stats->n_flows = hw_int->n_flows; + stats->max_flows = of_hw_caps.max_flows; + /* FIXME: Collect stats */ + TRY_NR(of_hw_table_stats_update(hw_int, &matched, &missed), + "of_hw_table_stats_update"); + stats->n_lookup = missed + matched; + stats->n_matched = matched; +} + +static int +of_hw_table_stats_get(of_hw_driver_t *hw_drv, struct ofp_table_stats *stats) +{ + DBG_WARN("TABLE STATS FIXME\n"); + return 0; +} + +/* + * Create and initialize a new hardware datapath object + */ + +of_hw_driver_t * +new_of_hw_driver(struct datapath *dp) +{ + struct sw_table *sw_tab; + of_hw_driver_t *hw_drv; + of_hw_driver_int_t *hw_int; + + if (!global_init_done) { + if (hw_drv_global_init(1) < 0) { + REPORT_ERROR("HW driver global init failed\n"); + return NULL; + } + } + hw_int = ALLOC(sizeof(*hw_int)); + if (hw_int == NULL) { + REPORT_ERROR("Could not allocate HW driver\n"); + return NULL; + } + memset(hw_int, 0, sizeof(*hw_int)); + + if (hw_drv_int_init(hw_int, dp) < 0) { + FREE(hw_int); + return NULL; + } + + + /* These all point to the same place */ + hw_drv = &hw_int->hw_driver; + sw_tab = &hw_drv->sw_table; + + sw_tab->n_lookup = 0; + sw_tab->n_matched = 0; + + /* Fill out the function pointers */ + sw_tab->lookup = of_hw_flow_lookup; + sw_tab->insert = of_hw_flow_install; + sw_tab->modify = of_hw_flow_modify; + sw_tab->delete = of_hw_flow_delete; + sw_tab->timeout = of_hw_flow_timeout; + + sw_tab->destroy = of_hw_table_destroy; + sw_tab->iterate = of_hw_table_iterate; + sw_tab->stats = of_hw_sw_table_stats; + + hw_drv->table_stats_get =of_hw_table_stats_get; + hw_drv->port_stats_get = of_hw_port_stats_get; + hw_drv->flow_stats_get = NULL; + hw_drv->aggregate_stats_get = NULL; + + hw_drv->port_add = of_hw_port_add; + hw_drv->port_remove = of_hw_port_remove; + hw_drv->port_link_get = of_hw_port_link_get; + hw_drv->port_enable_set = of_hw_port_enable_set; + hw_drv->port_enable_get = of_hw_port_enable_get; + hw_drv->port_queue_config = of_hw_port_queue_config; + hw_drv->port_queue_remove = of_hw_port_queue_remove; + hw_drv->port_change_register = of_hw_port_change_register; + + hw_drv->packet_send = of_hw_packet_send; + hw_drv->packet_receive_register = of_hw_packet_receive_register; + + hw_drv->ioctl = of_hw_ioctl; + + ++of_hw_drv_instances; + + return hw_drv; +} + +/* + * Deallocate a hardware datapath object + * If clear_hw is set, the HW structures related to the + * datapath are also cleared. + * + * In general, clear_hw should be set for now. + */ +void +delete_of_hw_driver(of_hw_driver_t *hw_drv) +{ + int idx; + of_hw_driver_int_t *hw_int; + + hw_int = (of_hw_driver_int_t *)hw_drv; + + /* Clear the port table of ownership for this dp */ + FOREACH_DP_PORT(idx, hw_drv) { + of_hw_ports[idx].owner = NULL; + } + + of_hw_flow_remove_all(hw_int); + + FREE(hw_drv); + --of_hw_drv_instances; +} diff --git a/openflow/hw-lib/skeleton/hw_drv.h b/openflow/hw-lib/skeleton/hw_drv.h new file mode 100644 index 00000000..7e6ecb0e --- /dev/null +++ b/openflow/hw-lib/skeleton/hw_drv.h @@ -0,0 +1,97 @@ +#ifndef OF_HW_DRV_H +#define OF_HW_DRV_H 1 + +#include +#include "of_hw_platform.h" +#include "list.h" + +/**************************************************************** + * + * High Level Design Notes + * + * Hardware tables are managed field_control_t and entry_control_t + * structures in hw_flow.h; these roughly mirror the HW structure + * and are preallocated. + * + * The glue between these and SW flows are provided by the HW flow + * objects (also in hw_flow.h) which are dynamically allocated and + * logically extend the SW flow object. + * + * A linear table of HW flow objects is maintained, mostly drawn + * from the existing table-linear.c implementation in udatapath. + * + */ + +/**************************************************************** + * Hardware independent port mapping macros + ****************************************************************/ + +/* Map ports using software data structures and DP check; independent of HW */ +#define OF_PORT_IN_DP(_hwdrv, _i) (((_i) < OF_HW_MAX_PORT) && \ + (of_hw_ports[_i].owner == (of_hw_driver_t *)(_hwdrv))) + +#define OF_PORT_TO_HW_PORT(_hwdrv, _i) \ + (OF_PORT_IN_DP(_hwdrv, _i) ? of_hw_ports[_i].port : -1) + +/* TBD: Define flow tracking objects */ + +/**************************************************************** + * + * Hardware datapath internal control structure + * Extends generic hardware datapath structure + * (which currently extends software table structure) + * + ****************************************************************/ + +/* Counts the number of instances */ +extern int of_hw_drv_instances; + +typedef struct of_hw_driver_int { + of_hw_driver_t hw_driver; + struct datapath *dp; /* Owning datapath */ + + /* Maintain a linked list of flows for tracking */ + struct list flows; /* The main list */ + struct list iter_flows; /* For iteration operation */ + unsigned long int next_serial; + + /* Callback function for received packets. */ + of_packet_in_f rx_handler; + void *rx_cookie; + + /* Callback function for port change notification */ + of_port_change_f port_change; + void *port_change_cookie; + + /* Lock object? */ + + // struct list sw_flows; + // struct list iter_sw_flows; + // struct sw_flow *iter_state; /* Place tracker for interrupted iterations */ + + /* Stats */ + uint32_t n_flows; /* Current number of flows in table */ + uint32_t n_inserts; /* Total inserts */ + uint32_t rx_pkt_alloc_failures; + uint32_t insert_errors; + + /* Configuration */ + /* Port bitmap of ports in DP by device */ + FIXME port_bitmap; + FIXME flood_bitmap; + int stat_sel; /* Packets or bytes */ + int dp_idx; /* In HW dp, but not SW dp */ + + int table_debug_level; + int port_debug_level; +} of_hw_driver_int_t; + +/* HW_DRV_MUTEX object ? */ + +#define HW_DRV_MUTEX_INIT /* TBD */ +#define HW_DRV_LOCK /* TBD */ +#define HW_DRV_UNLOCK /* TBD */ + +#define HW_INT(hw_drv) ((of_hw_driver_int_t *)hw_drv) + +#endif /* OF_HW_DRV_H */ diff --git a/openflow/hw-lib/skeleton/hw_flow.c b/openflow/hw-lib/skeleton/hw_flow.c new file mode 100644 index 00000000..2f9d6eca --- /dev/null +++ b/openflow/hw-lib/skeleton/hw_flow.c @@ -0,0 +1,708 @@ +/* + * Functions related to hardware flow processing; this is the glue + * and administration between upper level flow operations and lower + * level field processor operations. + */ + +#include +#include +#include + +#include "os.h" +#include "debug.h" +#include "hw_drv.h" +#include "port.h" +#include "hw_flow.h" +#include "udatapath/switch-flow.h" +#include "udatapath/datapath.h" +#include "lib/packets.h" + +static field_control_t field_control; + +/**************************************************************** + * + * SW/HW flow correlation book keeping routines + * + ****************************************************************/ + +/* Allocate and initialize a HW flow control structure. */ +static hw_flow_t * +hw_flow_create(struct sw_flow *flow) +{ + hw_flow_t *hw_flow; + + if ((hw_flow = ALLOC(sizeof(*hw_flow))) != NULL) { + memset(hw_flow, 0, sizeof(*hw_flow)); + HW_FLOW_MAKE_VALID(hw_flow); + hw_flow->flow = flow; + flow->private = (void *)hw_flow; + } + + return hw_flow; +} + +/* Remove an FP entry from a device */ +static int +HW_entry_remove(entry_control_t *entry) +{ + FIXME; + + return 0; +} + +/**************************************************************** + * + * Flow stats operations + * + ****************************************************************/ + +/* + * Read and convert the stats for an FP entry; maintains state + * of last counter value read and accumulates differences. + * + * Assumes mutex held. + */ +static int +entry_stat_update(entry_control_t *ent, int *used) +{ + unsigned long int cur_counter; + + FIXME_get_current_stats(cur_counter); + + ent->total_counter += cur_counter - ent->last_counter; + ent->last_counter = cur_counter; + + if (used != NULL) { + *used |= (ent->used_check != cur_counter); + ent->used_check = cur_counter; + } + + return 0; +} + +/* + * Get the stats for an OF (SW) flow object from HW tables + * NOTE: This will clear any existing value from the flow + * counters; if SW table counters need to be added in, that + * should be done after this calculation. + * + * If used is non-NULL, it will be filled with a boolean + * indication of whether the flow's counters have changed + * from their current state. + * + * Assumes mutex held. + * + * If force_sync is true, will sync SW counters with HW first + */ +int +of_hw_sw_flow_stat_update(struct sw_flow *flow, int *used, int force_sync) +{ + entry_control_t *ent; + hw_flow_t *hw_flow; + int idx; + + if (used != NULL) { + *used = false; + } + hw_flow = (hw_flow_t *)(flow->private); + if (!HW_FLOW_IS_VALID(hw_flow)) { + DBG_ERROR("BAD HW FLOW OBJECT %p for flow %p\n", hw_flow, flow); + return -1; + } + ASSERT(hw_flow->entry_count <= HW_FLOWS_PER_FLOW_MAX); + + if (force_sync) { + FIXME_sync_hw_stats(); + } + + /* FIXME: Will this accumulate and clear HW counters? */ + hw_flow->hw_byte_count = hw_flow->hw_packet_count = 0; + for (idx = 0; idx < hw_flow->entry_count; idx++) { + ent = hw_flow->entry_list[idx]; + + if (entry_stat_update(ent, used) < 0) { + DBG_WARN("Warning: could not get stats for flow\n"); + continue; + } + FIXME_update proper hw_flow counters; + } + flow->packet_count = hw_flow->hw_packet_count; + flow->byte_count = hw_flow->hw_byte_count; + + return 0; +} + +/* Read all the stats from the chip and update counters in flow tab */ +/* Index 0 holds default rule that indicates a missed count */ +/* ASSUMES LOCK HELD */ +int +of_hw_table_stats_update(of_hw_driver_int_t *hw_drv, unsigned long *matched, + unsigned long *missed) +{ + struct sw_flow *flow, *n; + of_hw_driver_int_t *hw_int; + + hw_int = (of_hw_driver_int_t *)hw_drv; + *matched = 0; + *missed = 0; + + if (STATS_BYTES(hw_int->stat_sel)) { /* Lookup count not supported */ + return -1; + } + + LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &hw_int->flows) { + if (flow->private != NULL) { + TRY_NR(of_hw_sw_flow_stat_update(flow, NULL, false), + "update flow stat"); + *matched += flow->packet_count; + } + } + + /* + * FIXME: To get missed stats, query entry 0 of HW table. + * This isn't really correct if there are entries in the SW datapath + * + * FIXME: If there are multiple data paths, should have one + * default entry qualifying on ports in that datapath with + * another entry dropping any packets on other ports. + */ + { + field_control_t *fc; + entry_control_t *ent; + + fc = &field_control; + ent = &fc->entry_list[0]; + ASSERT(ent->in_use); + TRY_NR(entry_stat_update(ent, NULL), "tab: entry_stat_update"); + *missed += ent->total_counter; + } + + return 0; +} + +/* + * Remove the FP entry or entries associated to a SW flow from the HW; + * + */ +static int +hw_flow_remove(struct sw_flow *flow) +{ + field_control_t *fc; + entry_control_t *ent; + hw_flow_t *hw_flow; + int idx; + +#if 0 /* Do not remove entries (debugging) */ + return 0; +#endif + + if (flow == NULL) { + return 0; + } + + hw_flow = (hw_flow_t *)(flow->private); + DBG_VERBOSE("Removing hw flow %p, flow %p\n", hw_flow, flow); + if (!HW_FLOW_IS_VALID(hw_flow)) { + return 0; + } + ASSERT(hw_flow->entry_count <= HW_FLOWS_PER_FLOW_MAX); + + TRY_NR(of_hw_sw_flow_stat_update(flow, NULL, true), + "rmv flow stat update"); + for (idx = 0; idx < hw_flow->entry_count; idx++) { + ent = hw_flow->entry_list[idx]; + ASSERT(ent != NULL); + + TRY_NR(HW_entry_remove(ent), "HW_entry_remove"); + hw_flow->entry_list[idx] = NULL; + } + FREE(hw_flow); + flow->private = NULL; + + return 0; +} + + +/**************************************************************** + * + * Important support routines related to FP setup, actions, flows + * + ****************************************************************/ + +/* ASSERT: of_port belongs to datapath */ +static void +add_dport_to_extra(of_hw_driver_int_t *hw_int, int of_port, + hw_flow_extra_t *extra) +{ + ASSERT(OF_PORT_IN_DP(hw_int, of_port)); + + extra->dest_port = MAP_OF_PORT_TO_HW_PORT(hw_int, of_port); + FIXME_update extra->dest_count if appropriate; +} + +/* Set up flood/all bitmaps + * NOTE: Assumes source port is not wildcarded. + */ +static void +mcast_bitmaps_set(of_hw_driver_int_t *hw_int, hw_flow_extra_t *extra, + int dest_port) +{ + FIXME; +} + +/* + * Validate actions for a flow relative to HW capabilities; + * + * Bool: true means supported, false not supported + * + * Accumulate additional info about the flow in extra. Specifically, + * this determines the output ports on each physical device related + * to the flow. + * + * FIXME: No-flood ports are currently not specified + */ + +static int +actions_supported_check(of_hw_driver_int_t *hw_int, + const struct sw_flow_key *key, + const struct ofp_action_header *actions, + size_t actions_len, + hw_flow_extra_t *extra) +{ + uint8_t *p; + int src_port; /* Port in host order */ + int dest_port; /* Port in host order */ + int action; + int src_is_wc = false; /* Is source wildcarded? */ + + ANNOUNCE_LOCATION; + ASSERT(extra != NULL); + + FIXME("probably needs work for your platform"); + + p = (uint8_t *)actions; + src_port = ntohs(key->flow.in_port); + + src_is_wc = key->wildcards & OFPFW_IN_PORT; + if (!src_is_wc) { + if (OF_PORT_IN_DP(hw_int, src_port)) { + extra->source_port = MAP_TO_HW_PORT(hw_int, src_port); + } else { + DBG_WARN("Source port %d not in DP %d\n", src_port, + hw_int->dp_idx); + return false; + } + } else { + extra->source_port = -1; + if (of_hw_drv_instances > 1) { + DBG_WARN("Source port WC not supported w/ multi-DP\n"); + return false; /* Not currently supported w/ multiple datapaths */ + } + /* NOTE/FIXME: Source wildcard with multiple output ports requires + * using a per-port hardware flow rule to allow filtering of + * the source port. (Currently not supported and checked below.) + */ + } + + while (actions_len > 0) { + struct ofp_action_header *ah = (struct ofp_action_header *)p; + struct ofp_action_output *oa = (struct ofp_action_output *)p; + size_t len = ntohs(ah->len); + + action = ntohs(ah->type); + DBG_VVERB("action chk %d\n", action); + /* Currently supported: output port(s) action */ + if ((action < 0) || (action > ACTION_LAST)) { + DBG_WARN("Unknown action id %d\n", action); + return false; + } + + if (action_map[action] == ACTION_NOT_SUPPORTED) { + DBG_WARN("Action %d not supported\n", action); + return false; + } + + /* Support front panel ports plus IN_PORT, ALL, FLOOD. */ + if ((action == OFPAT_OUTPUT) || (action == OFPAT_ENQUEUE)) { + /* FIXME: For now, using the fact that enqueue and output + * actions are the same at the start of the structure + */ + dest_port = ntohs(oa->port); + if (dest_port == OFPP_TABLE) { /* Unsupported */ + DBG_WARN("Warning: TABLE output action seen\n"); + return false; + } else if (OF_PORT_IN_DP(hw_int, dest_port)) { + add_dport_to_extra(hw_int, dest_port, extra); + } else if ((dest_port == OFPP_FLOOD) || (dest_port == OFPP_ALL)) { + mcast_bitmaps_set(hw_int, extra, dest_port); + } else if (dest_port == OFPP_IN_PORT) { + if (src_is_wc) { + DBG_WARN("Warning: IN_PORT action on source wildcard\n"); + return false; + } + add_dport_to_extra(hw_int, src_port, extra); + } else if (dest_port == OFPP_CONTROLLER) { + /* Controller/local are implemented with a "copy to CPU" + * action and a special reason code; Don't count as output port + */ + extra->local_reason |= CPU_REASON_TO_CONTROLLER; + } else if (dest_port == OFPP_LOCAL) { + extra->local_reason |= CPU_REASON_TO_LOCAL; + } else { /* NORMAL */ + // DBG_WARN("Output action to port 0x%x not supported\n", + // dest_port); + // return false; /* FIXME: Ignore bad ports for now */ + } + if (action == OFPAT_ENQUEUE) { + uint32 qid; + struct ofp_action_enqueue *ea; + ea = (struct ofp_action_enqueue *)p; + qid = ntohl(ea->queue_id); + if ((extra->cosq = of_hw_qid_find(dest_port, qid)) < 0) { + DBG_WARN("Warning: qid %d, port %d, map to cos failed\n", + qid, dest_port); + } + } + } + p += len; + actions_len -= len; + } + + if (src_is_wc && (extra->dest_count > 1)) { + DBG_WARN("Warning: multi dest w/ src wildcard\n"); + return false; + } + + DBG_VERBOSE("Actions supported\n"); + return true; +} + +/**************************************************************** + * + * FP Table management and manipulation routines + * + ****************************************************************/ + +/* + * Functions related to hardware flow table manipulation and maintenance + */ + +/* Set up field control structure; should be idempotent */ +static void +field_control_init(void) +{ + field_control_t *fc; + int idx; + + fc = &field_control; + fc->entry_count = 0; + for (idx = 0; idx < FIELD_ENTRY_MAX; idx++) { + fc->entry_list[idx].in_use = 0; + fc->entry_list[idx].hw_flow = NULL; + fc->entry_list[idx].index = idx; + fc->entry_list[idx].last_counter = 0; + fc->entry_list[idx].counter_last_check = 0; + fc->entry_list[idx].total_counter = 0; + } +} + +/* Alloc HW entry control structure, add qualification, actions and install */ +static int +hw_entry_install(of_hw_driver_int_t *hw_int, + struct sw_flow *flow, hw_flow_t *hw_flow, + hw_flow_extra_t *extra) +{ + + /* Install HW entry */ + FIXME; +} + +/* + * hw_flow_install + * + * Install HW table entries corresponding to the given SW flow + */ +static int +hw_flow_install(of_hw_driver_int_t *hw_int, struct sw_flow *flow, + hw_flow_extra_t *extra) +{ + hw_flow_t *hw_flow; + + /* Allocate the HW flow object */ + if ((hw_flow = hw_flow_create(flow)) == NULL) { + DBG_ERROR("failed to create hw flow struct\n"); + return -1; + } + + DBG_VERBOSE("hw flow install: sw %p. hw %p\n", flow, hw_flow); + TRY(hw_entry_install(hw_int, 0, flow, hw_flow, extra), + "local entry"); + + return 0; +} + +/**************************************************************** + * + * The driver APIs + * + ****************************************************************/ + +/* + * Install a flow. + * + * First, check that the flow is supported; simultaneously, build + * up the "extra" information needed by the hardware for its installation. + * This includes bitmaps of the ports to which the packet will be + * forwarded (on local and remote devices if appropriate). + * + * Then look to see if the flow should overwrite an existing entry. + * If so, just remove that entry. + * + * Then call hw_flow_install which does all the actual HW changes + * based on the flow and on extra. + */ + +/* NOTE: Returns 1 if flow installed, not normal error code */ +int +of_hw_flow_install(struct sw_table *sw_tab, struct sw_flow *flow) +{ + hw_flow_extra_t extra; + of_hw_driver_int_t *hw_int; + int hw_rc = 0; + int sw_insert_done = 0; + struct sw_flow *f; + + hw_int = (of_hw_driver_int_t *)sw_tab; + + DBG_VERBOSE("flow install %p\n", flow); + memset(&extra, 0, sizeof(extra)); + extra.cosq = -1; + + if (!actions_supported_check(hw_int, &flow->key, flow->sf_acts->actions, + flow->sf_acts->actions_len, &extra)) { + /* Unsupported actions */ + DBG_VERBOSE("HW install failed: Unsupported actions\n"); + return 0; + } + + /* LOCK; */ + /* Go through list looking for matching flows */ + LIST_FOR_EACH (f, struct sw_flow, node, &hw_int->flows) { + if (f->priority == flow->priority + && f->key.wildcards == flow->key.wildcards + && flow_matches_2wild(&f->key, &flow->key)) { + /* Just remove the HW flow; install other below */ + TRY_NR(hw_flow_remove(f), "hw_flow_remove for replace"); + flow->serial = f->serial; + list_replace(&flow->node, &f->node); + list_replace(&flow->iter_node, &f->iter_node); + sw_insert_done = 1; + flow_free(f); + break; + } + if (f->priority < flow->priority) { + break; + } + } + + /* ASSERT: sw_insert_done OR f points to insertion point for flow */ + + hw_rc = hw_flow_install(hw_int, flow, &extra); + + if (hw_rc < 0) { + hw_int->insert_errors++; + if (sw_insert_done) { /* Remove from SW list */ + list_remove(&flow->node); + list_remove(&flow->iter_node); + flow_free(flow); + hw_int->n_flows--; + } + } else { + hw_int->n_flows++; + hw_int->n_inserts++; + if (!sw_insert_done) { + flow->serial = hw_int->next_serial++; + list_insert(&f->node, &flow->node); + list_push_front(&hw_int->iter_flows, &flow->iter_node); + } + } + /* UNLOCK */ + + if (hw_rc < 0) { + DBG_WARN("Could not install flow in HW\n"); + if (sw_insert_done) { /* Remove from SW list */ + DBG_WARN("Removed matching flow but could not replace in HW\n"); + } + return 0; + } + + return 1; +} + +/* FIXME: Change API to return list of deleted flows? */ +/* Would make this easier */ +/* Remove a flow or flows from the HW and SW tracking tables */ +int +of_hw_flow_delete(struct datapath *dp, struct sw_table *sw_tab, + const struct sw_flow_key *key, uint16_t out_port, + uint16_t priority, int strict) +{ + of_hw_driver_int_t *hw_int = (of_hw_driver_int_t *)sw_tab; + struct sw_flow *flow, *n; + int count = 0; + struct list deleted; + + DBG_VERBOSE("delete: dp %p, idx %d, key %p, out 0x%x, prio %d, strict %d\n", + dp, hw_int->dp_idx, key, out_port, priority, strict); + + list_init(&deleted); + + /* LOCK; */ + LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &hw_int->flows) { + if (flow_matches_desc(&flow->key, key, strict) + && flow_has_out_port(flow, out_port) + && (!strict || (flow->priority == priority))) { + TRY_NR(hw_flow_remove(flow), "hw flow remove"); + list_remove(&flow->node); + list_remove(&flow->iter_node); + list_push_back(&deleted, &flow->node); + count++; + } + } + /* UNLOCK; */ + + /* Notify DP of deleted flows */ + LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &deleted) { + dp_send_flow_end(dp, flow, flow->reason); + list_remove(&flow->node); + flow_free(flow); + } + + return count; +} + + +/* + * Modify an existing flow + * + * We chicken out and just de-install/re-install in HW + */ +int +of_hw_flow_modify(struct sw_table *sw_tab, const struct sw_flow_key *key, + uint16_t priority, int strict, + const struct ofp_action_header *actions, size_t actions_len) +{ + of_hw_driver_int_t *hw_int = (of_hw_driver_int_t *)sw_tab; + struct sw_flow *flow; + int count = 0; + hw_flow_extra_t extra; + + memset(&extra, 0, sizeof(extra)); + extra.cosq = -1; +#if defined(PLATFORM_HAS_REMOTES) + extra.new_vid = -1; + extra.new_pcp = -1; +#endif + + if (!actions_supported_check(hw_int, &flow->key, actions, + actions_len, &extra)) { + /* Unsupported actions */ + DBG_VERBOSE("Mod actions-supported failed: Unsupported actions\n"); + return 0; + } + + /* LOCK; */ + LIST_FOR_EACH (flow, struct sw_flow, node, &hw_int->flows) { + if (flow_matches_desc(&flow->key, key, strict) + && (!strict || (flow->priority == priority))) { + /* Change the flow, de-install from HW and re-install */ + TRY_NR(hw_flow_remove(flow), "hw_flow_remove modify"); + flow_replace_acts(flow, actions, actions_len); + TRY_NR(hw_flow_install(hw_int, flow, &extra), + "hw_flow_install modify"); + /* FIXME: Clear stats on flow if updated? */ + count++; + } + } + /* UNLOCK; */ + + return count; +} + +/* + * Update stats + * Call sw tracking table timeout + * Iterate the deleted object list and call HW flow remove + */ +void +of_hw_flow_timeout(struct sw_table *sw_tab, struct list *deleted) +{ + of_hw_driver_int_t *hw_int = (of_hw_driver_int_t *)sw_tab; + struct sw_flow *flow, *n; + int used; + uint64_t now = time_msec(); + + /* LOCK; */ + /* FIXME */ + LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &hw_int->flows) { + if (of_hw_sw_flow_stat_update(flow, &used, false) == 0) { + if (used) { + flow->used = now; + } else { + if (flow_timeout(flow)) { + DBG_VERBOSE("Flow %p expired\n", flow); + list_remove(&flow->node); + list_remove(&flow->iter_node); + list_push_back(deleted, &flow->node); + ASSERT(flow->private != NULL); + TRY_NR(hw_flow_remove(flow), "hw flow remove, timeout"); + hw_int->n_flows--; + } + } + } + } + + /* UNLOCK; */ +} + +struct sw_flow * +of_hw_flow_lookup(struct sw_table *sw_tab, const struct sw_flow_key *key) +{ + of_hw_driver_int_t *hw_int = (of_hw_driver_int_t *)sw_tab; + struct sw_flow *flow; + + LIST_FOR_EACH (flow, struct sw_flow, node, &hw_int->flows) { + if (flow_matches_1wild(key, &flow->key)) + return flow; + } + return NULL; +} + +int +of_hw_flow_stats_get(of_hw_driver_t *hw_drv, struct ofp_match match, + struct ofp_flow_stats **stats, int *count) +{ + DBG_WARN("FIXME FLOW STATS GET\n"); + return 0; +} + +int +of_hw_aggregate_stats_get(struct ofp_match match, + struct ofp_aggregate_stats_reply *stats) +{ + DBG_WARN("FIXME AGGREGATE STATS GET\n"); + return 0; +} + +void +of_hw_flow_remove_all(of_hw_driver_int_t *hw_int) +{ + struct sw_flow *flow, *n; + + /* FIXME: Other de-init? Keep count of DPs? */ + LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &hw_int->flows) { + TRY_NR(hw_flow_remove(flow), "hw_flow_remove all"); + list_remove(&flow->node); + list_remove(&flow->iter_node); + } +} diff --git a/openflow/hw-lib/skeleton/hw_flow.h b/openflow/hw-lib/skeleton/hw_flow.h new file mode 100644 index 00000000..7c801c60 --- /dev/null +++ b/openflow/hw-lib/skeleton/hw_flow.h @@ -0,0 +1,111 @@ +#ifndef SAMPLE_PLATFORM_HW_FLOW_H +#define SAMPLE_PLATFORM_HW_FLOW_H 1 + +/* + * Hardware Flow operations: The glue between software flows and + * actual hardware table entries. + */ + +#include +#include + +#include "of_hw_platform.h" + +/* DEBUG for HW flow lists */ +#define HW_FLOW_MAGIC 0xba5eba11 +#define HW_FLOW_MAKE_VALID(hf) (hf)->magic = HW_FLOW_MAGIC +#define HW_FLOW_IS_VALID(hf) \ + (((hf) != NULL) && ((hf)->magic == HW_FLOW_MAGIC)) + +/* Some flows require multiple HW entries */ +#define HW_FLOWS_PER_FLOW_MAX (2) + +/* The glue between SW flows and HW entries */ +typedef struct hw_flow { + struct sw_flow *flow; /* Corresponding SW flow */ + of_hw_driver_t *hw_drv; /* DP for this flow; MAY BE NULL for internal */ + int entry_count; /* SW flow may require multiple HW table entries */ + entry_control_t *entry_list[HW_FLOWS_PER_FLOW_MAX]; + uint32 hw_packet_count; + uint32 hw_byte_count; + uint32 magic; /* DEBUG */ +} hw_flow_t; + +/* Extra info needed by hardware about flow entry; + * determined during supported check; all in host order + * + * For smac, dmac, vid and priority, if these are changed at ingress + * and a remote rule is necessary, the remote rule must have the + * rewrite values to match. This is indicated if value is not -1. + */ +typedef struct hw_flow_extra_s { + int source_port; /* If single source port, what is it */ + int dest_port; /* If one dest port, what is it */ + /* If multi dest ports, one pbmp per device */ + FIXME dports; + int dest_count; /* Drop (0), unicast (1), multicast (>1) */ + uint32 local_reason; /* Why forwarded to CPU */ + int cosq; /* For enqueue action */ +} hw_flow_extra_t; + +/* Driver functions */ +extern int of_hw_flow_install(struct sw_table *flowtab, struct sw_flow *flow); +extern int of_hw_flow_modify(struct sw_table *flowtab, + const struct sw_flow_key *key, uint16_t priority, int strict, + const struct ofp_action_header *actions, size_t actions_len); +extern int of_hw_flow_delete(struct datapath *dp, struct sw_table *flowtab, + const struct sw_flow_key *key, uint16_t out_port, + uint16_t priority, int strict); +extern void of_hw_flow_timeout(struct sw_table *flowtab, + struct list *deleted); +extern struct sw_flow *of_hw_flow_lookup(struct sw_table *flowtab, + const struct sw_flow_key *key); + + +extern int of_hw_sw_flow_stat_update(struct sw_flow *flow, int *used, + int force_sync); +extern int of_hw_flow_stats_get(of_hw_driver_t *hw_drv, struct ofp_match, + struct ofp_flow_stats **stats, int *count); +extern int of_hw_aggregate_stats_get(struct ofp_match, + struct ofp_aggregate_stats_reply *stats); + +/* Controls a single FP (HW table flow) entry */ +struct entry_control_s { + /* These must be persistent; update fp_entry_remove if you change this */ + int index; /* This entry-s index in field_control list */ + + int in_use; + hw_flow_t *hw_flow; + + /* + * HW specific info + */ + FIXME; + + unsigned long int used_check; /* Last counter; for checking if used */ + unsigned long int last_counter; /* pkts or bytes, see stat_sel above */ + unsigned long int counter_last_check; /* Track entry usage by cntr */ + unsigned long int total_counter; /* FIXME: u64? */ +}; + +/* Driver associated with a HW entry */ +#define HW_ENTRY_DRIVER(ent) ((ent)->hw_flow->hw_drv) + +/* FP control structure */ +struct field_control_s { + /* HW Specific info */ + FIXME; + int entry_count; /* How many entries in use */ + entry_control_t entry_list[FIELD_ENTRY_MAX]; /* Instantiation of entries */ +}; + +/* FIXME: Do we need reference counts on stat objects? */ + +extern int of_hw_fp_setup(void); +extern int of_hw_table_stats_update(of_hw_driver_int_t *hw_drv, + unsigned long *matched, unsigned long *missed); + +extern void of_hw_flow_remove_all(of_hw_driver_int_t *hw_int); + + +#endif /* SAMPLE_PLATFORM_HW_FLOW_H */ diff --git a/openflow/hw-lib/skeleton/of_hw_platform.h b/openflow/hw-lib/skeleton/of_hw_platform.h new file mode 100644 index 00000000..11a3364c --- /dev/null +++ b/openflow/hw-lib/skeleton/of_hw_platform.h @@ -0,0 +1,38 @@ +#ifndef HW_LIB_SKELETON_PLATFORM_H +#define HW_LIB_SKELETON_PLATFORM_H 1 + +#if defined(OF_HW_DP_MAIN) +#define P printf +#else +#define P printf +#endif + +/* + * General Hardware Switch platform defines + * + * Also includes platform specific definitions based on make defines + */ + +#define OF_HW_MAX_PORT 64 + +/* Reasons that a packet is being forwarded to the controller; */ +#define CPU_REASON_DEFAULT (1 << 0) +#define CPU_REASON_TO_CONTROLLER (1 << 1) +#define CPU_REASON_TO_LOCAL (1 << 2) + +#define EXACT_MATCH_PRIORITY TBD + +/**************************************************************** + * + * Platform specific defines and linkage + * + * Implicitly we have a "driver" for the board which includes + * hardware specific information including HW to OF port mapping + * + ****************************************************************/ + +#if defined(OF_SAMPLE_PLAT) +#include "sample_plat.h" +#endif + +#endif /* HW_LIB_SKELETON_PLATFORM_H */ diff --git a/openflow/hw-lib/skeleton/os.h b/openflow/hw-lib/skeleton/os.h new file mode 100644 index 00000000..268daa97 --- /dev/null +++ b/openflow/hw-lib/skeleton/os.h @@ -0,0 +1,29 @@ + +/* + * OS abstractions + */ + +#ifndef OF_HW_OS_H +#define OF_HW_OS_H 1 + +#include + +#define ALLOC(bytes) malloc(bytes) +#define FREE(ptr) free(ptr) + +#define PKT_ALLOC(bytes) TBD +#define PKT_FREE(ptr) TBD + +#define MUTEX_DECLARE(name) TBD +#define MUTEX_INIT(name) TBD +#define MUTEX_LOCK(name) TBD +#define MUTEX_UNLOCK(name) TBD + +#define TIME_NOW(time) TBD +#define TIME_DIFF(diff, early, late) TBD + +/* FIXME */ +#include +#define os_pkt_free(pkt) ofpbuf_delete(pkt) + +#endif /* OF_HW_OS_H */ diff --git a/openflow/hw-lib/skeleton/port.c b/openflow/hw-lib/skeleton/port.c new file mode 100644 index 00000000..7d8c5e3b --- /dev/null +++ b/openflow/hw-lib/skeleton/port.c @@ -0,0 +1,497 @@ +/* + * Port related HW datapath functions + */ + +#include +#include + +#include "xtoxll.h" +#include "hw_drv.h" +#include "of_hw_platform.h" +#include "port.h" +#include "debug.h" + +/* Single set of HW port objects managed here; indexed by OF port num */ +of_hw_port_t of_hw_ports[OF_HW_MAX_PORT]; + +/* Check if hw DP and port are valid and if port belongs to the DP */ +#define CHECK_PORT(_drv, _p) do { \ + if ((_drv) == NULL) return -1; \ + if (((_p) < 1) || ((_p) > OF_HW_MAX_PORT)) { \ + REPORT_ERROR("bad port number"); \ + return -1; \ + } \ + if (!(OF_PORT_IN_DP(((of_hw_driver_int_t *)(_drv)), (_p)))) { \ + REPORT_ERROR("DP does not own port"); \ + return -1; \ + } \ +} while (0) + + +/* + * Queue configuration section + * + * Port queue: Per port structure for queue related information + * Queue map: Indicated queue is mapped and what OF qid its mapped to as + * well as queue properties (min-bw). Indexed by OF port number; + * per port instance of array + * + */ + +typedef struct queue_map_s { + int in_use; + uint32_t qid; /* OF queue name */ + int min_bw; /* OF value, tenths of a percent */ +} queue_map_t; + +typedef struct port_queue_s { + int speed; /* In Mbps */ + queue_map_t queue_map[NUM_COS_QUEUES]; +} port_queue_t; + +static port_queue_t port_queue[OF_HW_MAX_PORT]; + +/* Return the cos for the queue matching qid if found; else -1. + * Assumes lock held + */ +static int +qid_find(int of_port, uint32_t qid) +{ + struct queue_map_s *qm; + int cosq; + + qm = port_queue[of_port].queue_map; + for (cosq = 0; cosq < NUM_COS_QUEUES; cosq++) { + if (qm[cosq].in_use && (qid == qm[cosq].qid)) { + return cosq; + } + } + + return -1; +} + +/* Return the cos for the queue matching qid if found; else -1. + * Assumes lock held + */ +int +of_hw_qid_find(int of_port, uint32_t qid) +{ + int cosq; + + /* LOCK */ + cosq = qid_find(of_port, qid); + /* UNLOCK */ + + return cosq; +} + +/* + * Map an OF qid to a COS queue index; if not present, add it if possible + * Assumes lock held + */ +static int +qid_find_add(int of_port, uint32_t qid) +{ + struct queue_map_s *qm; + int cosq; + + cosq = qid_find(of_port, qid); + if (cosq >= 0) { + return cosq; + } + + /* Not found; add queue */ + for (cosq = 0; cosq < NUM_COS_QUEUES; cosq++) { + qm = port_queue[of_port].queue_map; + if (!qm[cosq].in_use) { + qm[cosq].in_use = true; + qm[cosq].qid = qid; + return cosq; + } + } + + return -1; +} + +/* + * Port speed has changed; requires queue b/w to change + */ +static void +port_speed_change_reconfig(of_hw_driver_int_t *hw_int, int of_port) +{ + int cosq; + struct queue_map_s *qm; + int rv; + + /* LOCK */ + for (cosq = 0; cosq < NUM_COS_QUEUES; cosq++) { + qm = port_queue[of_port].queue_map; + if (qm[cosq].in_use) { + /* FIXME: Calc and program values for HW for min-bw */ + if (rv < 0) { + DBG_ERROR("ERROR: Set min BW for queue on port %d " + "link change\n", of_port); + } + } + } + /* UNLOCK */ +} + + +/* Internal handler for port link status changes */ + +/* FIXME */ +static void +of_hw_linkscan_handler(...) +{ + int of_port; + of_hw_driver_int_t *hw_int; + + /* Assumes speed, linkstatus from HW */ + /* Map port to internal port object */ + of_port = HW_MAP_TO_PORT(); + if ((of_port < 0) || (of_port > OF_HW_MAX_PORT)) { + return; + } + + /* LOCK */ + hw_int = (of_hw_driver_int_t *)(of_hw_ports[of_port].owner); + if (hw_int != NULL) { + if (port_queue[of_port].speed != speed) { + port_queue[of_port].speed = speed; + port_speed_change_reconfig(hw_int, of_port); + } + } + /* Record in local struct */ + of_hw_ports[of_port].link = linkstatus != 0; + if ((hw_int != NULL) && (hw_int->port_change != NULL)) { + hw_int->port_change(of_port, linkstatus != 0, + hw_int->port_change_cookie); + } + /* UNLOCK */ +} + +static int linkscan_registered; + +/* + * of_hw_ports_init + * Set up hardware port map + */ +void +of_hw_ports_init(void) +{ + int i; + + for (i = 0; i < OF_HW_MAX_PORT; i++) { + of_hw_ports[i].owner = NULL; + of_hw_ports[i].port = MAP_OF_PORT_TO_HW_PORT(i); + } + + /* FIXME: REGISTER FOR LINK CHANGE CALLBACK */ + /* Always register linkscan handler */ + linkscan_registered = 1; + + /* Get current link status for each port; ignore errors for bad ports */ + for (i = 0; i < OF_HW_MAX_PORT; i++) { + /* FIXME */ + HW_LINK_STATUS_GET(of_hw_ports[i].port, &of_hw_ports[i].link); + } +} + + +#define HTON64 htonll + +/* Get port stats into a standard openflow port stats structure */ +int +of_hw_port_stats_get(of_hw_driver_t *hw_drv, int of_port, + struct ofp_port_stats *stats) +{ + uint64 v1, v2; + + CHECK_PORT(hw_drv, of_port); + + +#if 0 /* FIXME; Get stats from HW */ + HW_STAT(of_port, snmpIfInNUcastPkts, &v1); + HW_STAT(of_port, snmpIfInUcastPkts, &v2); + v1 += v2; + stats->rx_packets = HTON64(v1); + HW_STAT(of_port, snmpIfOutNUcastPkts, &v1); + HW_STAT(of_port, snmpIfOutUcastPkts, &v2); + v1 += v2; + stats->tx_packets = HTON64(v1); + HW_STAT(of_port, snmpIfInOctets, &v1); + stats->rx_bytes = HTON64(v1); + HW_STAT(of_port, snmpIfOutOctets, &v1); + stats->tx_bytes = HTON64(v1); + HW_STAT(of_port, snmpIfInDiscards, &v1); + stats->rx_dropped = HTON64(v1); + HW_STAT(of_port, snmpIfOutDiscards, &v1); + stats->tx_dropped = HTON64(v1); + HW_STAT(of_port, snmpIfInErrors, &v1); + stats->rx_errors = HTON64(v1); + HW_STAT(of_port, snmpIfOutErrors, &v1); + stats->tx_errors = HTON64(v1); +#endif + + v1 = UINT64_C(0xffffffffffffffff); + stats->rx_frame_err = HTON64(v1); + stats->rx_over_err = HTON64(v1); + stats->rx_crc_err = HTON64(v1); + stats->collisions = HTON64(v1); + + return 0; +} + +/* + * port_add/remove(table, port) + * + * The indicated port has been added to/removed from the datapath + * Add also maps the of_port number to the hw_port indicated + * + * SPEC CHANGE: If of_port passed is less than 0, use the passed + * port name to determine the port number and attach to that value; + * + * Returns the of_port number or -1 on error + */ +int +of_hw_port_add(of_hw_driver_t *hw_drv, int of_port, const char *hw_name) +{ + int hw_idx; + of_hw_port_t *port_ctl; + of_hw_driver_int_t *hw_int; + + if (hw_drv == NULL) { + return -1; + } + + hw_idx = hw_port_name_to_index(hw_name); + if (of_port < 0) { + of_port = hw_idx + 1; + } else if (hw_idx + 1 != of_port) { + DBG_WARN("Add Port: OF port %d does not match name %s\n", + of_port, hw_name); + } + + if (of_port >= OF_HW_MAX_PORT) { + DBG_ERROR("Add Port: Bad port number %d\n", of_port); + return -1; + } + + hw_int = (of_hw_driver_int_t *)hw_drv; + port_ctl = &of_hw_ports[of_port]; + + HW_DRV_LOCK; + if (port_ctl->owner == NULL) { + port_ctl->owner = hw_drv; + /* FIXME: port bitmaps in HW structure */ + } else if (port_ctl->owner != hw_drv) { + DBG_ERROR("Add Port: OF port %d owned by other DP\n", of_port); + } else { + DBG_WARN("Add Port: OF port %d already added\n", of_port); + } + HW_DRV_UNLOCK; + + return of_port; +} + +int +of_hw_port_remove(of_hw_driver_t *hw_drv, of_port_t of_port) +{ + of_hw_port_t *port_ctl; + of_hw_driver_int_t *hw_int; + int rc = 0; + + if (hw_drv == NULL) { + return -1; + } + + if ((of_port < 1) || (of_port >= OF_HW_MAX_PORT)) { + DBG_ERROR("Remove Port: Bad port number %d\n", of_port); + return -1; + } + + hw_int = (of_hw_driver_int_t *)hw_drv; + port_ctl = &of_hw_ports[of_port]; + + HW_DRV_LOCK; + if (port_ctl->owner == NULL) { + DBG_WARN("Remove Port: OF port %d already free\n", of_port); + } else if (port_ctl->owner != hw_drv) { + DBG_ERROR("Remove Port: OF port %d owned by other DP\n", of_port); + rc = -1; + } else { + port_ctl->owner = NULL; + } + /* FIXME UPDATE HW port bitmaps in hw_int */ + HW_DRV_UNLOCK; + + return rc; +} + + +/* + * port_link_get(table, port) + * port_enable_set(table, port, enable) + * port_enable_get(table, port) + * + * Get/set the indicated properties of a port. Only real ports + * set with port_add are supported. + */ +int +of_hw_port_link_get(of_hw_driver_t *hw_drv, int of_port) +{ + int rc; + int link; + + CHECK_PORT(hw_drv, of_port); + + if (linkscan_registered) { + return of_hw_ports[of_port].link; + } + + if ((rc = HW_LINK_GET(of_hw_ports[of_port].port, &link)) < 0) { + DBG_ERROR("link_get: error %d port %d\n", rc, of_port); + /* Return link down on error */ + return 0; + } + + return link ? 1 : 0; +} + +int +of_hw_port_enable_set(of_hw_driver_t *hw_drv, int of_port, int enable) +{ + int rc; + + CHECK_PORT(hw_drv, of_port); + + if ((rc = HW_PORT_ENABLE_SET(of_hw_ports[of_port].port, enable)) < 0) { + DBG_ERROR("of_hw_port_enable_set: error %d port %d\n", + rc, of_port); + return rc; + } + + return 0; +} + +int +of_hw_port_enable_get(of_hw_driver_t *hw_drv, int of_port) +{ + int rc; + int enable; + + CHECK_PORT(hw_drv, of_port); + + if ((rc = HW_PORT_ENABLE_GET(of_hw_ports[of_port].port, &enable)) < 0) { + DBG_ERROR("of_hw_port_enable_get: error %d port %d\n", + rc, of_port); + return rc; + } + + return enable ? 1 : 0; +} + + +/* + * port_change_register + * + * Register a callback function to receive port change notifications + * from ports in this datapath; only one callback per datapath is + * supported. + */ +int +of_hw_port_change_register(of_hw_driver_t *hw_drv, of_port_change_f callback, + void *cookie) +{ + of_hw_driver_int_t *dp_int; + + dp_int = (of_hw_driver_int_t *)hw_drv; + dp_int->port_change = callback; + dp_int->port_change_cookie = cookie; + + return 0; +} + +/* + * Init COS queue setup. The queues number is fixed at 8. Deficit + * round robin is the discipline, initially with all equal weights. + * As queues are configured with min bandwidth reservations, the + * weights are adjusted to ensure the requested targets. + * + * For now, these are device generic; may need to specialize in the + * future. + */ + +int +of_hw_cos_setup(int num_cos) +{ + /* FIXME: Set up COS queues */ + + return 0; +} + +/* + * Add and/or configure an output queue on a port. + * + * If qid exists, update. If not, look for an unreferenced queue and + * set the qid to that value. + * + * Note that when a port state changes, may need to re-configure + * the bandwidth values for the port's queues. + */ + +int +of_hw_port_queue_config(of_hw_driver_t *hw_drv, int of_port, uint32_t qid, + int min_bw) /* In tenths of a percent */ +{ + int min_kbps; + of_hw_driver_int_t *hw_int; + int cosq; + struct queue_map_s *qm; + int rv; + + hw_int = (of_hw_driver_int_t *)hw_drv; + + CHECK_PORT(hw_int, of_port); + + /* LOCK */ + /* Get the current bandwidth of the port (cached?) */ + if ((cosq = qid_find_add(of_port, qid)) < 0) { + DBG_ERROR("Could not add queue: of port %d, qid %d\n", of_port, qid); + /* UNLOCK */ + return -1; + } + qm = &port_queue[of_port].queue_map[qid]; + qm->min_bw = min_bw; + + HW_SET_MIN_BW(...); + /* UNLOCK */ + + return (rv != 0) ? -1 : 0; +} + +/* Remove a queue from a port; this potentially affects the queue + * configuration otherwise we would not worry about it here. + * Return -1 if not found; 0 on success + */ + +int +of_hw_port_queue_remove(of_hw_driver_t *hw_drv, int of_port, uint32_t qid) +{ + int cosq; + + (void)hw_drv; + /* LOCK */ + if ((cosq = qid_find(of_port, qid)) == -1) { + /* UNLOCK */ + return -1; + } + + /* Do we need to update stats or DRR weights or anything? */ + + port_queue[of_port].queue_map[cosq].in_use = false; + + /* UNLOCK */ + return 0; +} diff --git a/openflow/hw-lib/skeleton/port.h b/openflow/hw-lib/skeleton/port.h new file mode 100644 index 00000000..dd2c0828 --- /dev/null +++ b/openflow/hw-lib/skeleton/port.h @@ -0,0 +1,45 @@ +#ifndef OF_HW_PORT_H +#define OF_HW_PORT_H 1 + +#include +#include +#include "of_hw_platform.h" + +#define NUM_COS_QUEUES 8 + +/* Define port mapping object indexed by OF number */ +typedef struct of_hw_port_s { + of_hw_driver_t *owner; /* Owner of this port */ + int port; /* Physical port number on device */ + int link; /* Link state */ + /* TBD: Keep track of link state and don't transmit if down? */ + /* Add other physical info here as needed */ +} of_hw_port_t; + +extern of_hw_port_t of_hw_ports[OF_HW_MAX_PORT]; + +#define FOREACH_DP_PORT(_idx, _drv) \ + for (_idx = 0; _idx < OF_HW_MAX_PORT; _idx++) \ + if (of_hw_ports[_idx].owner == (of_hw_driver_t *)(_drv)) + +extern int of_hw_cos_setup(int num_cos); +extern int of_hw_qid_find(int of_port, uint32_t qid); + +extern void of_hw_ports_init(void); +extern int of_hw_port_stats_get(of_hw_driver_t *hw_drv, int of_port, + struct ofp_port_stats *stats); +extern int of_hw_port_add(of_hw_driver_t *hw_drv, int of_port, + const char *hw_name); +extern int of_hw_port_remove(of_hw_driver_t *hw_drv, of_port_t of_port); +extern int of_hw_port_link_get(of_hw_driver_t *hw_drv, int of_port); +extern int of_hw_port_enable_set(of_hw_driver_t *hw_drv, int of_port, + int enable); +extern int of_hw_port_enable_get(of_hw_driver_t *hw_drv, int of_port); +extern int of_hw_port_queue_config(of_hw_driver_t *hw_drv, int of_port, + uint32_t qid, int min_bw); /* In tenths of a percent */ +extern int of_hw_port_queue_remove(of_hw_driver_t *hw_drv, int of_port, + uint32_t qid); +extern int of_hw_port_change_register(of_hw_driver_t *hw_drv, + of_port_change_f callback, void *cookie); + +#endif /* OF_HW_PORT_H */ diff --git a/openflow/hw-lib/skeleton/sample_plat.c b/openflow/hw-lib/skeleton/sample_plat.c new file mode 100644 index 00000000..17f3747b --- /dev/null +++ b/openflow/hw-lib/skeleton/sample_plat.c @@ -0,0 +1,82 @@ +/* + * sample_plat.c + * + * FIXME: Standard confidential header + * + * $Id: $ + */ + +/* + * Sample hardware initialization functions + */ + +#include "debug.h" +#include "of_hw_platform.h" + +#if defined(SAMPLE_PLAT) + +#include "port.h" + +/* sample_plat_port_setup + * + * Set up linkscan and necessary spanning tree for ports + * Disable VLAN dropping + */ +static int +sample_plat_port_setup(...) +{ + + return 0; +} + +#if defined(OF_HW_DP_MAIN) && defined(SAMPLE_HW_PLAT) + +/* If defined, need to do init here */ + +/* + * sample_plat_pre_init + * + * Turn off everything that might cause problems during init + */ + +static int +sample_plat_pre_init(void) +{ + /* bring system down to known state */ + return 0; +} + +/* + */ +int +sample_plat_init(void) +{ + /* Init system */ + + /* First, clear out everything */ + sample_plat_pre_init(); + + /* ... */ + + sample_plat_port_setup(...); + + return 0; +} + +/* FIXME: Deal with initial FP setup */ + +#else /* Not stand alone init; Other code does init */ + +int +sample_plat_init(void) +{ + DBG_WARN("sample_plat_init\n"); + + TRY(sample_plat_port_setup(...), "sample plat init port setup"); + + return 0; +} + +#endif + +#endif /* SAMPLE_PLAT */ diff --git a/openflow/hw-lib/skeleton/sample_plat.h b/openflow/hw-lib/skeleton/sample_plat.h new file mode 100644 index 00000000..3d88eb01 --- /dev/null +++ b/openflow/hw-lib/skeleton/sample_plat.h @@ -0,0 +1,61 @@ +#ifndef SAMPLE_PLAT_H +#define SAMPLE_PLAT_H 1 + + +#include +#include +#include + +#include + +#define OF_HW_MAX_PORTS 4 + +static inline int +of_port_to_hw_port(int of_port) +{ + return of_port - 1; +} + + +/* Map port to OF port number */ +static inline int +of_hw_port_to_of_port(int port) +{ + if ((port < 0) || (port > 3)) { + return -1; + } + + return port + 1; +} + +#define _IS_DIGIT(c) ((c) >= '0' && (c) <= '9') + +/* Map name to hw port number: N => N-1 + ge0 => 0 where "ge" can be any string and 0 can be any number +*/ + +static inline int +hw_port_name_to_index(const char *name) +{ + + if (_IS_DIGIT(name[0])) { + /* Treat as 1-based, OF number */ + i = strtoul(&name[0], NULL, 10); + return i - 1; + } + + len = strlen(name); + for (idx = 0; idx < len && !_IS_DIGIT(name[idx]); idx++) ; + + if ((idx < len) && _IS_DIGIT(name[idx])) { + i = strtoul(&name[idx], NULL, 10); + return i; + } + + return -1; +} +#undef _IS_DIGIT + + + +#endif /* SAMPLE_PLAT_H */ diff --git a/openflow/hw-lib/skeleton/txrx.c b/openflow/hw-lib/skeleton/txrx.c new file mode 100644 index 00000000..950d839f --- /dev/null +++ b/openflow/hw-lib/skeleton/txrx.c @@ -0,0 +1,129 @@ +/* + * Transmit and receive related functions for hardware platforms + */ + +#include +#include "os.h" +#include "hw_drv.h" +#include "txrx.h" +#include "port.h" +#include "debug.h" +#include "of_hw_platform.h" + +static int pkt_count, failures, prev_success, free_count, error_free; +static void +tx_pkt_callback(...) +{ + of_packet_t *of_pkt = cookie; + + /* os_pkt_free(of_pkt->os_pkt); */ + FREE(of_pkt); + /* ... */ + ++free_count; +} + +/* + * tx_packet_send(table, of_port, pkt, flags) + * + * Send packet to an openflow port. + * + * Proposed flags: + * APPLY_FLOW_TABLE: If set, and if the hardware supports + * it, send the packet through the flow table with the source + * port being the local CPU port. (Would be nice to have + * a flexible source port indicated; could hide in flags...) + * + * Assumes buffer in pkt struct can be used for sending data + * + * + */ +int +of_hw_packet_send(of_hw_driver_t *hw_drv, int of_port, of_packet_t *pkt, + uint32_t flags) +{ + /* FIXME: Code to prepare and send pkt */ + return 0; +} + +/* Callback function registered with HW */ +static int +of_hw_rx(...) +{ + /* Sample RX handler */ + int of_port; + of_hw_driver_int_t *hw_drv; + of_packet_t *of_pkt; + int pkt_len; + + /* map receive port to of_port */ + /* map received packet to of_pkt */ + /* Call callback */ + + of_port = of_hw_port_to_of_port(receive_port); + if (of_port < 0) { + return hw_not_handled; + } + + /* LOCK */ + hw_drv = (of_hw_driver_int_t *)(of_hw_ports[of_port].owner); + if ((hw_drv == NULL) || (hw_drv->rx_handler == NULL)) { + /* UNLOCK */ + return hw_not_handled; + } + + of_pkt = ALLOC(sizeof(of_packet_t)); + if (of_pkt == NULL) { + ++hw_drv->rx_pkt_alloc_failures; + /* UNLOCK */ + return hw_not_handled; + } + pkt_len = pkt->tot_len; + + /* FIXME: FOR NOW, COPY DATA INTO NEW BUFFER; */ + of_pkt->data = ALLOC(pkt_len); + if (of_pkt->data == NULL) { + FREE(of_pkt); + /* UNLOCK */ + return hw_not_handled; + } + + /* Handle VLAN tagging if needed */ + /* Coy pkt data appropriately */ + + /* FIXME: Determine reason (dflt rule or directed) */ + /* FIXME: Return code interpretation? */ + /* OFPR_NO_MATCH, No matching flow. */ + /* OFPR_ACTION Action explicitly output to controller. */ + hw_drv->rx_handler(of_port, of_pkt, 0, hw_drv->rx_cookie); + /* UNLOCK */ + + return hw_handled; +} + +static int rx_registered = 0; + +/* + * packet_receive_register + * + * Register a callback function to receive packets from ports in + * this datapath + */ +int +of_hw_packet_receive_register(of_hw_driver_t *hw_drv, + of_packet_in_f callback, void *cookie) +{ + of_hw_driver_int_t *dp_int; + int rv; + + /* Register for link status changes */ + if (!rx_registered) { + /* Set up low level pkt receive for callback */ + rx_registered = 1; + } + + dp_int = (of_hw_driver_int_t *)hw_drv; + dp_int->rx_handler = callback; + dp_int->rx_cookie = cookie; + + return 0; +} diff --git a/openflow/hw-lib/skeleton/txrx.h b/openflow/hw-lib/skeleton/txrx.h new file mode 100644 index 00000000..1aef9026 --- /dev/null +++ b/openflow/hw-lib/skeleton/txrx.h @@ -0,0 +1,12 @@ +#ifndef OF_HW_TXRX_H +#define OF_HW_TXRX_H 1 + +#include +#include + +extern int of_hw_packet_send(of_hw_driver_t *hw_drv, int of_port, + of_packet_t *pkt, uint32_t flags); +extern int of_hw_packet_receive_register(of_hw_driver_t *hw_drv, + of_packet_in_f callback, void *cookie); + +#endif /* OF_HW_TXRX_H */ diff --git a/openflow/include/.gitignore b/openflow/include/.gitignore new file mode 100644 index 00000000..b336cc7c --- /dev/null +++ b/openflow/include/.gitignore @@ -0,0 +1,2 @@ +/Makefile +/Makefile.in diff --git a/openflow/include/automake.mk b/openflow/include/automake.mk new file mode 100644 index 00000000..581c1085 --- /dev/null +++ b/openflow/include/automake.mk @@ -0,0 +1 @@ +include include/openflow/automake.mk diff --git a/openflow/include/openflow/automake.mk b/openflow/include/openflow/automake.mk new file mode 100644 index 00000000..3c45b082 --- /dev/null +++ b/openflow/include/openflow/automake.mk @@ -0,0 +1,5 @@ +noinst_HEADERS += \ + include/openflow/nicira-ext.h \ + include/openflow/private-ext.h \ + include/openflow/openflow.h \ + include/openflow/openflow-netlink.h diff --git a/openflow/include/openflow/nicira-ext.h b/openflow/include/openflow/nicira-ext.h new file mode 100644 index 00000000..727864a6 --- /dev/null +++ b/openflow/include/openflow/nicira-ext.h @@ -0,0 +1,195 @@ +/* + * Distributed under the terms of the GNU GPL version 2. + * Copyright (c) 2008 Nicira Networks + */ + +#ifndef OPENFLOW_NICIRA_EXT_H +#define OPENFLOW_NICIRA_EXT_H 1 + +#include "openflow/openflow.h" + +#define NICIRA_OUI_STR "002320" + +/* The following vendor extensions, proposed by Nicira Networks, are not yet + * ready for standardization (and may never be), so they are not included in + * openflow.h. */ + +#define NX_VENDOR_ID 0x00002320 + +enum nicira_type { + /* Switch status request. The request body is an ASCII string that + * specifies a prefix of the key names to include in the output; if it is + * the null string, then all key-value pairs are included. */ + NXT_STATUS_REQUEST, + + /* Switch status reply. The reply body is an ASCII string of key-value + * pairs in the form "key=value\n". */ + NXT_STATUS_REPLY, + + /* Configure an action. Most actions do not require configuration + * beyond that supplied in the actual action call. */ + NXT_ACT_SET_CONFIG, + + /* Get configuration of action. */ + NXT_ACT_GET_CONFIG, + + /* Remote command execution. The request body is a sequence of strings + * delimited by null bytes. The first string is a command name. + * Subsequent strings are command arguments. */ + NXT_COMMAND_REQUEST, + + /* Remote command execution reply, sent when the command's execution + * completes. The reply body is struct nx_command_reply. */ + NXT_COMMAND_REPLY, + + /* Configure whether Flow End messages should be sent. */ + NXT_FLOW_END_CONFIG, + + /* Sent by switch when a flow ends. These messages are turned into + * ofp_flow_removed and NetFlow messages in user-space. */ + NXT_FLOW_END +}; + +struct nicira_header { + struct ofp_header header; + uint32_t vendor; /* NX_VENDOR_ID. */ + uint32_t subtype; /* One of NXT_* above. */ +}; +OFP_ASSERT(sizeof(struct nicira_header) == sizeof(struct ofp_vendor_header) + 4); + + +enum nx_snat_command { + NXSC_ADD, + NXSC_DELETE +}; + +/* Configuration for source-NATing */ +struct nx_snat_config { + uint8_t command; /* One of NXSC_*. */ + uint8_t pad[3]; + uint16_t port; /* Physical switch port. */ + uint16_t mac_timeout; /* Time to cache MAC addresses of SNAT'd hosts + in seconds. 0 uses the default value. */ + + /* Range of IP addresses to impersonate. Set both values to the + * same to support a single address. */ + uint32_t ip_addr_start; + uint32_t ip_addr_end; + + /* Range of transport ports that should be used as new source port. A + * value of zero, let's the switch choose.*/ + uint16_t tcp_start; + uint16_t tcp_end; + uint16_t udp_start; + uint16_t udp_end; + + /* MAC address to use for ARP requests for a SNAT IP address that + * comes in on a different interface than 'port'. A value of all + * zeros silently drops those ARP requests. Requests that arrive + * on 'port' get a response with the mac address of the datapath + * device. */ + uint8_t mac_addr[OFP_ETH_ALEN]; + uint8_t pad2[2]; +}; +OFP_ASSERT(sizeof(struct nx_snat_config) == 32); + +/* Action configuration. Not all actions require separate configuration. */ +struct nx_act_config { + struct nicira_header header; + uint16_t type; /* One of OFPAT_* */ + uint8_t pad[2]; + union { + struct nx_snat_config snat[0]; + }; /* Array of action configurations. The number + is inferred from the length field in the + header. */ +}; +OFP_ASSERT(sizeof(struct nx_act_config) == 20); + + +enum nx_action_subtype { + NXAST_SNAT /* Source-NAT */ +}; + +/* Action structure for NXAST_SNAT. */ +struct nx_action_snat { + uint16_t type; /* OFPAT_VENDOR. */ + uint16_t len; /* Length is 8. */ + uint32_t vendor; /* NX_VENDOR_ID. */ + uint16_t subtype; /* NXAST_SNAT. */ + uint16_t port; /* Output port--it must be previously + configured. */ + uint8_t pad[4]; +}; +OFP_ASSERT(sizeof(struct nx_action_snat) == 16); + +/* Header for Nicira-defined actions. */ +struct nx_action_header { + uint16_t type; /* OFPAT_VENDOR. */ + uint16_t len; /* Length is 8. */ + uint32_t vendor; /* NX_VENDOR_ID. */ + uint16_t subtype; /* NXAST_*. */ + uint8_t pad[6]; +}; +OFP_ASSERT(sizeof(struct nx_action_header) == 16); + +/* Status bits for NXT_COMMAND_REPLY. */ +enum { + NXT_STATUS_EXITED = 1 << 31, /* Exited normally. */ + NXT_STATUS_SIGNALED = 1 << 30, /* Exited due to signal. */ + NXT_STATUS_UNKNOWN = 1 << 29, /* Exited for unknown reason. */ + NXT_STATUS_COREDUMP = 1 << 28, /* Exited with core dump. */ + NXT_STATUS_ERROR = 1 << 27, /* Command could not be executed. */ + NXT_STATUS_STARTED = 1 << 26, /* Command was started. */ + NXT_STATUS_EXITSTATUS = 0xff, /* Exit code mask if NXT_STATUS_EXITED. */ + NXT_STATUS_TERMSIG = 0xff, /* Signal number if NXT_STATUS_SIGNALED. */ +}; + +/* NXT_COMMAND_REPLY. */ +struct nx_command_reply { + struct nicira_header nxh; + uint32_t status; /* Status bits defined above. */ + /* Followed by any number of bytes of process output. */ +}; +OFP_ASSERT(sizeof(struct nx_command_reply) == 20); + +enum nx_flow_end_reason { + NXFER_IDLE_TIMEOUT, /* Flow idle time exceeded idle_timeout. */ + NXFER_HARD_TIMEOUT, /* Time exceeded hard_timeout. */ + NXFER_DELETE, /* Flow was removed by delete command. */ + NXFER_EJECT /* Flow was ejected. */ +}; + +struct nx_flow_end_config { + struct nicira_header header; + uint8_t enable; /* Set to 1 to enable Flow End message + generation. 0 to disable. */ + uint8_t pad[3]; +}; +OFP_ASSERT(sizeof(struct nx_flow_end_config) == 20); + +struct nx_flow_end { + struct nicira_header header; + struct ofp_match match; /* Description of fields. */ + uint64_t cookie; /* Opaque controller-issued identifier. */ + + uint16_t priority; /* Priority level of flow entry. */ + uint8_t reason; /* One of NXFER_*. */ + + uint8_t tcp_flags; /* Union of seen TCP flags. */ + uint8_t ip_tos; /* IP TOS value. */ + + uint8_t send_flow_exp; /* Send flow expiry to controller. */ + + uint16_t idle_timeout; /* Idle time before discarding (seconds). */ + + uint64_t init_time; /* Time flow started in milliseconds. */ + uint64_t used_time; /* Time entry was last used in milliseconds. */ + uint64_t end_time; /* Time flow ended in milliseconds. */ + + uint64_t packet_count; + uint64_t byte_count; +}; +OFP_ASSERT(sizeof(struct nx_flow_end) == 112); + +#endif /* openflow/nicira-ext.h */ diff --git a/openflow/include/openflow/of_hw_api.h b/openflow/include/openflow/of_hw_api.h new file mode 100644 index 00000000..2dca1900 --- /dev/null +++ b/openflow/include/openflow/of_hw_api.h @@ -0,0 +1,313 @@ +/* Copyright (c) 2008, 2009, 2010 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#if !defined(OF_HW_API_H) +#define OF_HW_API_H + +/* + * OpenFlow hardware API definition + * + * This header file provides an abstraction of the flow table and + * port operations that can be used to build a driver for hardware + * that implements the OpenFlow protocol. + * + * Currently this driver depends (extends) the sw_table defined + * in the udatapath/table.h file. Hopefully that file will be + * moved up to library status to support kernel and userspace + * implementations. + * + */ + +#include +#include /* For sw_table */ + +/* REQUIRES: + * struct sw_table defined + * TBD: We could remove this restriction; it's mainly so that + * current chain.c operations can work. It also allows + * pointer coersion between the two types. + * + * Eventually, sw_table may be extended to include everything in + * this driver. + * + * pointer to struct datapath + */ + +/**************** basic types ****************/ + +typedef uint32_t of_port_t; +typedef struct of_hw_driver of_hw_driver_t; + +/**************** packet ****************/ + +/* The OpenFlow hardware packet abstraction */ +typedef void *os_pkt_t; /* OS representation of packet */ + +/* Requires monolithic packet data */ +typedef struct of_packet_s { + unsigned char *data; /* Pointer to packet data */ + int length; /* Length in bytes */ + os_pkt_t os_pkt; /* OS specific representation */ +} of_packet_t; + +/* Init an of_packet struct from an ofp_buffer struct */ +#define OF_PKT_INIT(pkt, ofp_buf) do { \ + (pkt)->data = (ofp_buf)->data; \ + (pkt)->length = (ofp_buf)->size; \ + (pkt)->os_pkt = (ofp_buf); \ + } while (0) + +/**************** callback protos ****************/ + +/* packet in callback function prototype */ +typedef int (*of_packet_in_f)(of_port_t port, + of_packet_t *packet, + int reason, + void *cookie); + +typedef void (*of_port_change_f)(of_port_t port, + int state, + void *cookie); + +/**************************************************************** + * + * Hardware Driver + * + ****************************************************************/ + +/* Hardware capabilities structure */ +typedef struct of_hw_driver_caps { + /* Proposed Flags: + * COUNT_PKTS_OR_BYTES Can count either pkts or bytes, not both + * INTERNAL_PRI Support internal priority mapping, and thus + * normal enqueuing action + * LOCAL_CPU_THRU_TABLE Can send packets from the CPU through + * the flow table + */ + uint32_t flags; + + /* Number of fully qualified flows supported (approx) */ + int max_flows; + uint32_t wc_supported; /* Bitmap of OFPFW_* supported wildcards */ + uint32_t actions_supported; /* Bitmap of OFPAT_* supported actions */ + uint32_t ofpc_flags; /* Bitmap of ofp_capabilities flags */ +} of_hw_driver_caps_t; + +enum of_hw_driver_flags { + OF_HW_DRV_COUNT_PKTS_OR_BYTES = 1 << 0, + OF_HW_DRV_INTERNAL_PRI = 1 << 1, + OF_HW_DRV_CPU_PKTS_THRU_TABLE = 1 << 2 +}; + +/**************** Constructor/Destructor ****************/ + +extern of_hw_driver_t *new_of_hw_driver(struct datapath *dp); +extern void delete_of_hw_driver(of_hw_driver_t *hw_drv); + +/* TBD: Add a HW/DP init function? */ + +/**************** HW DataPath Driver Structure ****************/ +/* Extends sw_table */ +struct of_hw_driver { + + /* + * Notes on sw_table inheritance: + * + * See above as well + * + * n_lookup and n_matched are not dynamically updated, but the + * call to table_stats_update should set them + */ + struct sw_table sw_table; + + /* HW datapath capabilities structure */ + of_hw_driver_caps_t caps; + + /* OPTIONAL + * init(table, flags) + * + * Initialize necessary hardware and software to run + * the switching table. Must be called prior to any other calls + * into the table (except maybe some ioctls?). + * + * Proposed flags include: + * BYTES/PACKETS: If COUNT_PKTS_OR_BYTES, which to count by default + * REATTACH: Inidicates HW was running, don't re-initialize HW + * + */ + int (*init)(of_hw_driver_t *hw_drv, uint32_t flags); + + /* + * table_stats_get(table, stats) + * port_stats_get(port, stats) + * flow_stats_get(flow_desc, stats) + * aggregate_stats_get(flow_desc, stats) + * + * Fill out the stats object(s) for this table/port/flow(s)/set of flows + * + * Returns 0 on success. + * + * For all but flow_stats, the routine fills out a pre-allocated + * stats structure. For flow stats, an array of stats is allocated + * by the called routine with *count elements. It must be freed by + * the caller. + * + * (Optional? If count is NULL for flow_stats_get, find a single + * match with exactly the given ofp_match.) + */ + int (*table_stats_get)(of_hw_driver_t *hw_drv, struct + ofp_table_stats *stats); + int (*port_stats_get)(of_hw_driver_t *hw_drv, int of_port, + struct ofp_port_stats *stats); + int (*flow_stats_get)(of_hw_driver_t *hw_drv, struct ofp_match, + struct ofp_flow_stats **stats, int *count); + int (*aggregate_stats_get)(struct ofp_match, + struct ofp_aggregate_stats_reply *stats); + + /* + * port_add/remove(table, port) + * + * The indicated port has been added to/removed from the datapath + * Add also maps the of_port number to the hw_port indicated + */ + int (*port_add)(of_hw_driver_t *hw_drv, int of_port, const char *hw_name); + int (*port_remove)(of_hw_driver_t *hw_drv, of_port_t port); + + /* + * port_link_get(table, port) + * port_enable_set(table, port, enable) + * port_enable_get(table, port) + * + * Get/set the indicated properties of a port. Only real ports + * set with port_add are supported. + */ + int (*port_link_get)(of_hw_driver_t *hw_drv, int of_port); + int (*port_enable_set)(of_hw_driver_t *hw_drv, int of_port, int enable); + int (*port_enable_get)(of_hw_driver_t *hw_drv, int of_port); + + /* + * port_queue_config(drv, port, qid, min-bw) + * port_queue_remove(drv, port, qid) + * + * Port queue control. Config will add the queue if not present + */ + int (*port_queue_config)(of_hw_driver_t *hw_drv, int of_port, + uint32_t qid, int min_bw); + int (*port_queue_remove)(of_hw_driver_t *hw_drv, int of_port, + uint32_t qid); + + /* + * port_change_register + * + * Register a callback function to receive port change notifications + * from ports in this datapath + */ + int (*port_change_register)(of_hw_driver_t *hw_drv, + of_port_change_f callback, void *cookie); + + /* + * packet_send(table, of_port, pkt, flags) + * + * Send packet to an openflow port. + * + * Proposed flags: + * APPLY_FLOW_TABLE: If set, and if the hardware supports + * it, send the packet through the flow table with the source + * port being the local CPU port. (Would be nice to have + * a flexible source port indicated; could hide in flags...) + * + * TBD: Owner of pkt and pkt->data after call; sync/async. + */ + int (*packet_send)(of_hw_driver_t *hw_drv, int of_port, of_packet_t *pkt, + uint32_t flags); + + /* + * packet_receive_register + * + * Register a callback function to receive packets from ports in + * this datapath + * + * TBD: Semantics for owning packets and return codes so indicating. + */ + int (*packet_receive_register)(of_hw_driver_t *hw_drv, + of_packet_in_f callback, void *cookie); + + /* OPTIONAL + * ioctl(table, request, io_param) + * + * Execute an ioctl on the table. A few ioctls are predefined, + * but most will be implementation specific. + * Returns 0 on success or an implementation specific other code. + * + * io_param is an input/output parameter whose value may be + * returned to the caller. + * io_len is the length of io_param in bytes. + * On input, the *io_param pointer may clobbered, so the caller must + * maintain it for deallocation if necessary. + * On output, when used -- which depends on the operation -- + * the *io_param is a pointer to a buffer allocated by the ioctl + * routine, but owned by the calling routine. + * + * Question: Should a full I/O buffer be supported? + * ioctl(table, op, in_buf, in_len, out_buf, out_len); or + * ioctl(table, op, io_buf, io_len); where buf/len set on output. + * + * Proposed operations: + * Set debug level + * Clear port/flow/table stats + * Select packet or byte counter collection + */ + int (*ioctl)(of_hw_driver_t *hw_drv, uint32_t op, void **io_param, + int *io_len); + +}; + +/**************** IOCTL values ****************/ + +enum of_hw_ioctl_e { + OF_HW_IOCTL_TABLE_DEBUG_SET = 1, + OF_HW_IOCTL_PORT_DEBUG_SET = 2, + OF_HW_IOCTL_BYTE_PKT_CNTR_SET = 3 +}; + +/* Values for OF_HW_IOCTL_BYTE_PKT_CNTR_SET */ +#define OF_HW_CNTR_PACKETS 0 +#define OF_HW_CNTR_BYTES 1 + +enum of_hw_error_e { + OF_HW_OKAY = 0, + OF_HW_ERROR = -1, + OF_HW_PORT_DOWN = -2 +}; + +#endif /* OF_HW_API_H */ diff --git a/openflow/include/openflow/openflow-ext.h b/openflow/include/openflow/openflow-ext.h new file mode 100644 index 00000000..581d49a5 --- /dev/null +++ b/openflow/include/openflow/openflow-ext.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2009 The Board of Trustees of The Leland + * Stanford Junior University + */ + +#ifndef OPENFLOW_OPENFLOW_EXT_H +#define OPENFLOW_OPENFLOW_EXT_H 1 + +#include "openflow/openflow.h" + +/* + * The following are vendor extensions from OpenFlow. This is a + * means of allowing the introduction of non-standardized + * proposed code. + * + * Structures in this file are 64-bit aligned in size. + */ + +#define OPENFLOW_VENDOR_ID 0x000026e1 + +enum ofp_extension_commands { /* Queue configuration commands */ + /* Queue Commands */ + OFP_EXT_QUEUE_MODIFY, /* Add and/or modify */ + OFP_EXT_QUEUE_DELETE, /* Remove a queue */ + OFP_EXT_SET_DESC, /* Set ofp_desc_stat->dp_desc */ + + OFP_EXT_COUNT +}; + +struct ofp_extension_header { + struct ofp_header header; + uint32_t vendor; /* OPENFLOW_VENDOR_ID. */ + uint32_t subtype; /* One of ofp_extension_commands */ +}; +OFP_ASSERT(sizeof(struct ofp_extension_header) == 16); + +/**************************************************************** + * + * OpenFlow Queue Configuration Operations + * + ****************************************************************/ + +struct openflow_queue_command_header { + struct ofp_extension_header header; + uint16_t port; /* Port for operations */ + uint8_t pad[6]; /* Align to 64-bits */ + uint8_t body[0]; /* Body of ofp_queue objects for op. */ +}; +OFP_ASSERT(sizeof(struct openflow_queue_command_header) == 24); + +/* NOTE + * Bug number: TBD. + * The definitions for openflow_queue_error_code conflict with + * those for ofp_queue_op_failed_code defined in openflow.h. + * This will be addressed after the release of OpenFlow 1.0. + * The error codes below for openflow_queue_error_code may be + * removed at that time. + */ +/* + * Entries for 'code' in ofp_error_msg with error 'type' + * OFPET_QUEUE_OP_FAILED + */ +enum openflow_queue_error_code { + OFQ_ERR_NONE, /* Success */ + OFQ_ERR_FAIL, /* Unspecified failure */ + OFQ_ERR_NOT_FOUND, /* Queue not found */ + OFQ_ERR_DISCIPLINE, /* Discipline not supported */ + OFQ_ERR_BW_UNAVAIL, /* Bandwidth unavailable */ + OFQ_ERR_QUEUE_UNAVAIL, /* Queue unavailable */ + OFQ_ERR_COUNT /* Last please */ +}; + +#define OPENFLOW_QUEUE_ERROR_STRINGS_DEF { \ + "Success", /* OFQ_ERR_NONE */ \ + "Unspecified failure", /* OFQ_ERR_FAIL */ \ + "Queue not found", /* OFQ_ERR_NOT_FOUND */ \ + "Discipline not supported", /* OFQ_ERR_DISCIPLINE */ \ + "Bandwidth unavailable", /* OFQ_ERR_BW_UNAVAIL */ \ + "Queue unavailable" /* OFQ_ERR_QUEUE_UNAVAIL */ \ +} + +extern char *openflow_queue_error_strings[]; + +struct openflow_ext_set_dp_desc { + struct ofp_extension_header header; + char dp_desc[DESC_STR_LEN]; +}; +OFP_ASSERT(sizeof(struct openflow_ext_set_dp_desc) == 272); + +#define ofq_error_string(rv) (((rv) < OFQ_ERR_COUNT) && ((rv) >= 0) ? \ + openflow_queue_error_strings[rv] : "Unknown error code") + +/**************************************************************** + * + * Unsupported, but potential extended queue properties + * + ****************************************************************/ + +#if 0 + +enum ofp_queue_prop_ext { + OFPQT_EXT_MAX_RATE = OFPQT_MIN + 1, /* maximum rate limit */ + OFPQT_EXT_BUF_ALLOC, /* buffer alloc config */ + OFPQT_EXT_SCHED_WEIGHT /* schedule weight config */ + OFPQT_EXT_COUNT /* Last please */ +}; + +#define OPENFLOW_QUEUE_PROP_STRINGS_DEF { \ + "No property specified" /* OFPQT_NONE */ \ + "Minimum Rate", /* OFPQT_MIN */ \ + "Maximum Rate", /* OFQ_PROP_MAX_RATE */ \ + "Buffer alloc weight", /* OFQ_PROP_BUF_ALLOC */ \ + "Scheduling weight" /* OFQ_PROP_SCHED_WEIGHT */ \ +} +extern char *openflow_queue_prop_strings[]; + +#define ofq_prop_string(val) (((val) < OFPQT_EXT_COUNT) && ((val) >= 0) ? \ + openflow_queue_prop_strings[val] : "Unknown property value") + +/* These are all the same a min-rate queue property description */ +/* Max-Rate queue property description */ +struct ofp_queue_prop_max_rate { + struct ofp_queue_prop_header prop_header; /* prop: OFPQT_MIN, len: 16 */ + uint16_t rate; /* in 1/10 of a percent of port BW */ + uint8_t pad[6]; /* 64-bit alignment */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_prop_max_rate) == 16); + +/* Buffer alloc weight queue property description */ +struct ofp_queue_prop_buf_alloc { + struct ofp_queue_prop_header prop_header; /* prop: OFPQT_MIN, len: 16 */ + uint16_t alloc_val; /* 0 disabled; 1 min; 0xffff max */ + uint8_t pad[6]; /* 64-bit alignment */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_prop_buf_alloc) == 16); + +/* Max-Rate queue property description */ +struct ofp_queue_prop_sched_weight { + struct ofp_queue_prop_header prop_header; /* prop: OFPQT_MIN, len: 16 */ + uint16_t weight; /* discipline specific; 0 disabled; 1 min; 0xffff max */ + uint8_t pad[6]; /* 64-bit alignment */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_prop_sched_weight) == 16); + +#endif + + + +#endif /* OPENFLOW_OPENFLOW_EXT_H */ diff --git a/openflow/include/openflow/openflow-netlink.h b/openflow/include/openflow/openflow-netlink.h new file mode 100644 index 00000000..931e6972 --- /dev/null +++ b/openflow/include/openflow/openflow-netlink.h @@ -0,0 +1,69 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#ifndef OPENFLOW_OPENFLOW_NETLINK_H +#define OPENFLOW_OPENFLOW_NETLINK_H 1 + +#define DP_GENL_FAMILY_NAME "OpenFlow" + +/* Attributes that can be attached to the datapath's netlink messages. */ +enum { + DP_GENL_A_UNSPEC, + DP_GENL_A_DP_IDX, /* Datapath device index. */ + DP_GENL_A_PORTNAME, /* Device name for datapath port. */ + DP_GENL_A_MC_GROUP, /* Generic netlink multicast group. */ + DP_GENL_A_OPENFLOW, /* OpenFlow packet. */ + DP_GENL_A_DP_NAME, /* Datapath device name. */ + + __DP_GENL_A_MAX, + DP_GENL_A_MAX = __DP_GENL_A_MAX - 1 +}; + +/* Commands that can be executed on the datapath's netlink interface. */ +enum dp_genl_command { + DP_GENL_C_UNSPEC, + DP_GENL_C_ADD_DP, /* Create datapath. */ + DP_GENL_C_DEL_DP, /* Destroy datapath. */ + DP_GENL_C_QUERY_DP, /* Get multicast group for datapath. */ + DP_GENL_C_ADD_PORT, /* Add port to datapath. */ + DP_GENL_C_DEL_PORT, /* Remove port from datapath. */ + DP_GENL_C_OPENFLOW, /* Encapsulated OpenFlow protocol. */ + + __DP_GENL_C_MAX, + DP_GENL_C_MAX = __DP_GENL_C_MAX - 1 +}; + +/* Maximum number of datapaths. */ +#define DP_MAX 256 + +#endif /* openflow/openflow-netlink.h */ diff --git a/openflow/include/openflow/openflow.h b/openflow/include/openflow/openflow.h new file mode 100644 index 00000000..c0b5090d --- /dev/null +++ b/openflow/include/openflow/openflow.h @@ -0,0 +1,970 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +/* OpenFlow: protocol between controller and datapath. */ + +#ifndef OPENFLOW_OPENFLOW_H +#define OPENFLOW_OPENFLOW_H 1 + +#ifdef __KERNEL__ +#include +#else +#include +#endif + +#ifdef SWIG +#define OFP_ASSERT(EXPR) /* SWIG can't handle OFP_ASSERT. */ +#elif !defined(__cplusplus) +/* Build-time assertion for use in a declaration context. */ +#define OFP_ASSERT(EXPR) \ + extern int (*build_assert(void))[ sizeof(struct { \ + unsigned int build_assert_failed : (EXPR) ? 1 : -1; })] +#else /* __cplusplus */ +#define OFP_ASSERT(_EXPR) typedef int build_assert_failed[(_EXPR) ? 1 : -1] +#endif /* __cplusplus */ + +#ifndef SWIG +#define OFP_PACKED __attribute__((packed)) +#else +#define OFP_PACKED /* SWIG doesn't understand __attribute. */ +#endif + +/* Version number: + * Non-experimental versions released: 0x01 + * Experimental versions released: 0x81 -- 0x99 + */ +/* The most significant bit being set in the version field indicates an + * experimental OpenFlow version. + */ +#define OFP_VERSION 0x01 + +#define OFP_MAX_TABLE_NAME_LEN 32 +#define OFP_MAX_PORT_NAME_LEN 16 + +#define OFP_TCP_PORT 6633 +#define OFP_SSL_PORT 6633 + +#define OFP_ETH_ALEN 6 /* Bytes in an Ethernet address. */ + +/* Port numbering. Physical ports are numbered starting from 1. */ +enum ofp_port { + /* Maximum number of physical switch ports. */ + OFPP_MAX = 0xff00, + + /* Fake output "ports". */ + OFPP_IN_PORT = 0xfff8, /* Send the packet out the input port. This + virtual port must be explicitly used + in order to send back out of the input + port. */ + OFPP_TABLE = 0xfff9, /* Perform actions in flow table. + NB: This can only be the destination + port for packet-out messages. */ + OFPP_NORMAL = 0xfffa, /* Process with normal L2/L3 switching. */ + OFPP_FLOOD = 0xfffb, /* All physical ports except input port and + those disabled by STP. */ + OFPP_ALL = 0xfffc, /* All physical ports except input port. */ + OFPP_CONTROLLER = 0xfffd, /* Send to controller. */ + OFPP_LOCAL = 0xfffe, /* Local openflow "port". */ + OFPP_NONE = 0xffff /* Not associated with a physical port. */ +}; + +enum ofp_type { + /* Immutable messages. */ + OFPT_HELLO, /* Symmetric message */ + OFPT_ERROR, /* Symmetric message */ + OFPT_ECHO_REQUEST, /* Symmetric message */ + OFPT_ECHO_REPLY, /* Symmetric message */ + OFPT_VENDOR, /* Symmetric message */ + + /* Switch configuration messages. */ + OFPT_FEATURES_REQUEST, /* Controller/switch message */ + OFPT_FEATURES_REPLY, /* Controller/switch message */ + OFPT_GET_CONFIG_REQUEST, /* Controller/switch message */ + OFPT_GET_CONFIG_REPLY, /* Controller/switch message */ + OFPT_SET_CONFIG, /* Controller/switch message */ + + /* Asynchronous messages. */ + OFPT_PACKET_IN, /* Async message */ + OFPT_FLOW_REMOVED, /* Async message */ + OFPT_PORT_STATUS, /* Async message */ + + /* Controller command messages. */ + OFPT_PACKET_OUT, /* Controller/switch message */ + OFPT_FLOW_MOD, /* Controller/switch message */ + OFPT_PORT_MOD, /* Controller/switch message */ + + /* Statistics messages. */ + OFPT_STATS_REQUEST, /* Controller/switch message */ + OFPT_STATS_REPLY, /* Controller/switch message */ + + /* Barrier messages. */ + OFPT_BARRIER_REQUEST, /* Controller/switch message */ + OFPT_BARRIER_REPLY, /* Controller/switch message */ + + /* Queue Configuration messages. */ + OFPT_QUEUE_GET_CONFIG_REQUEST, /* Controller/switch message */ + OFPT_QUEUE_GET_CONFIG_REPLY /* Controller/switch message */ + +}; + +/* Header on all OpenFlow packets. */ +struct ofp_header { + uint8_t version; /* OFP_VERSION. */ + uint8_t type; /* One of the OFPT_ constants. */ + uint16_t length; /* Length including this ofp_header. */ + uint32_t xid; /* Transaction id associated with this packet. + Replies use the same id as was in the request + to facilitate pairing. */ +}; +OFP_ASSERT(sizeof(struct ofp_header) == 8); + +/* OFPT_HELLO. This message has an empty body, but implementations must + * ignore any data included in the body, to allow for future extensions. */ +struct ofp_hello { + struct ofp_header header; +}; + +#define OFP_DEFAULT_MISS_SEND_LEN 128 + +enum ofp_config_flags { + /* Handling of IP fragments. */ + OFPC_FRAG_NORMAL = 0, /* No special handling for fragments. */ + OFPC_FRAG_DROP = 1, /* Drop fragments. */ + OFPC_FRAG_REASM = 2, /* Reassemble (only if OFPC_IP_REASM set). */ + OFPC_FRAG_MASK = 3 +}; + +/* Switch configuration. */ +struct ofp_switch_config { + struct ofp_header header; + uint16_t flags; /* OFPC_* flags. */ + uint16_t miss_send_len; /* Max bytes of new flow that datapath should + send to the controller. */ +}; +OFP_ASSERT(sizeof(struct ofp_switch_config) == 12); + +/* Capabilities supported by the datapath. */ +enum ofp_capabilities { + OFPC_FLOW_STATS = 1 << 0, /* Flow statistics. */ + OFPC_TABLE_STATS = 1 << 1, /* Table statistics. */ + OFPC_PORT_STATS = 1 << 2, /* Port statistics. */ + OFPC_STP = 1 << 3, /* 802.1d spanning tree. */ + OFPC_RESERVED = 1 << 4, /* Reserved, must be zero. */ + OFPC_IP_REASM = 1 << 5, /* Can reassemble IP fragments. */ + OFPC_QUEUE_STATS = 1 << 6, /* Queue statistics. */ + OFPC_ARP_MATCH_IP = 1 << 7 /* Match IP addresses in ARP pkts. */ +}; + +/* Flags to indicate behavior of the physical port. These flags are + * used in ofp_phy_port to describe the current configuration. They are + * used in the ofp_port_mod message to configure the port's behavior. + */ +enum ofp_port_config { + OFPPC_PORT_DOWN = 1 << 0, /* Port is administratively down. */ + + OFPPC_NO_STP = 1 << 1, /* Disable 802.1D spanning tree on port. */ + OFPPC_NO_RECV = 1 << 2, /* Drop all packets except 802.1D spanning + tree packets. */ + OFPPC_NO_RECV_STP = 1 << 3, /* Drop received 802.1D STP packets. */ + OFPPC_NO_FLOOD = 1 << 4, /* Do not include this port when flooding. */ + OFPPC_NO_FWD = 1 << 5, /* Drop packets forwarded to port. */ + OFPPC_NO_PACKET_IN = 1 << 6 /* Do not send packet-in msgs for port. */ +}; + +/* Current state of the physical port. These are not configurable from + * the controller. + */ +enum ofp_port_state { + OFPPS_LINK_DOWN = 1 << 0, /* No physical link present. */ + + /* The OFPPS_STP_* bits have no effect on switch operation. The + * controller must adjust OFPPC_NO_RECV, OFPPC_NO_FWD, and + * OFPPC_NO_PACKET_IN appropriately to fully implement an 802.1D spanning + * tree. */ + OFPPS_STP_LISTEN = 0 << 8, /* Not learning or relaying frames. */ + OFPPS_STP_LEARN = 1 << 8, /* Learning but not relaying frames. */ + OFPPS_STP_FORWARD = 2 << 8, /* Learning and relaying frames. */ + OFPPS_STP_BLOCK = 3 << 8, /* Not part of spanning tree. */ + OFPPS_STP_MASK = 3 << 8 /* Bit mask for OFPPS_STP_* values. */ +}; + +/* Features of physical ports available in a datapath. */ +enum ofp_port_features { + OFPPF_10MB_HD = 1 << 0, /* 10 Mb half-duplex rate support. */ + OFPPF_10MB_FD = 1 << 1, /* 10 Mb full-duplex rate support. */ + OFPPF_100MB_HD = 1 << 2, /* 100 Mb half-duplex rate support. */ + OFPPF_100MB_FD = 1 << 3, /* 100 Mb full-duplex rate support. */ + OFPPF_1GB_HD = 1 << 4, /* 1 Gb half-duplex rate support. */ + OFPPF_1GB_FD = 1 << 5, /* 1 Gb full-duplex rate support. */ + OFPPF_10GB_FD = 1 << 6, /* 10 Gb full-duplex rate support. */ + OFPPF_COPPER = 1 << 7, /* Copper medium. */ + OFPPF_FIBER = 1 << 8, /* Fiber medium. */ + OFPPF_AUTONEG = 1 << 9, /* Auto-negotiation. */ + OFPPF_PAUSE = 1 << 10, /* Pause. */ + OFPPF_PAUSE_ASYM = 1 << 11 /* Asymmetric pause. */ +}; + +/* Description of a physical port */ +struct ofp_phy_port { + uint16_t port_no; + uint8_t hw_addr[OFP_ETH_ALEN]; + char name[OFP_MAX_PORT_NAME_LEN]; /* Null-terminated */ + + uint32_t config; /* Bitmap of OFPPC_* flags. */ + uint32_t state; /* Bitmap of OFPPS_* flags. */ + + /* Bitmaps of OFPPF_* that describe features. All bits zeroed if + * unsupported or unavailable. */ + uint32_t curr; /* Current features. */ + uint32_t advertised; /* Features being advertised by the port. */ + uint32_t supported; /* Features supported by the port. */ + uint32_t peer; /* Features advertised by peer. */ +}; +OFP_ASSERT(sizeof(struct ofp_phy_port) == 48); + +/* Switch features. */ +struct ofp_switch_features { + struct ofp_header header; + uint64_t datapath_id; /* Datapath unique ID. The lower 48-bits are for + a MAC address, while the upper 16-bits are + implementer-defined. */ + + uint32_t n_buffers; /* Max packets buffered at once. */ + + uint8_t n_tables; /* Number of tables supported by datapath. */ + uint8_t pad[3]; /* Align to 64-bits. */ + + /* Features. */ + uint32_t capabilities; /* Bitmap of support "ofp_capabilities". */ + uint32_t actions; /* Bitmap of supported "ofp_action_type"s. */ + + /* Port info.*/ + struct ofp_phy_port ports[0]; /* Port definitions. The number of ports + is inferred from the length field in + the header. */ +}; +OFP_ASSERT(sizeof(struct ofp_switch_features) == 32); + +/* What changed about the physical port */ +enum ofp_port_reason { + OFPPR_ADD, /* The port was added. */ + OFPPR_DELETE, /* The port was removed. */ + OFPPR_MODIFY /* Some attribute of the port has changed. */ +}; + +/* A physical port has changed in the datapath */ +struct ofp_port_status { + struct ofp_header header; + uint8_t reason; /* One of OFPPR_*. */ + uint8_t pad[7]; /* Align to 64-bits. */ + struct ofp_phy_port desc; +}; +OFP_ASSERT(sizeof(struct ofp_port_status) == 64); + +/* Modify behavior of the physical port */ +struct ofp_port_mod { + struct ofp_header header; + uint16_t port_no; + uint8_t hw_addr[OFP_ETH_ALEN]; /* The hardware address is not + configurable. This is used to + sanity-check the request, so it must + be the same as returned in an + ofp_phy_port struct. */ + + uint32_t config; /* Bitmap of OFPPC_* flags. */ + uint32_t mask; /* Bitmap of OFPPC_* flags to be changed. */ + + uint32_t advertise; /* Bitmap of "ofp_port_features"s. Zero all + bits to prevent any action taking place. */ + uint8_t pad[4]; /* Pad to 64-bits. */ +}; +OFP_ASSERT(sizeof(struct ofp_port_mod) == 32); + +/* Why is this packet being sent to the controller? */ +enum ofp_packet_in_reason { + OFPR_NO_MATCH, /* No matching flow. */ + OFPR_ACTION /* Action explicitly output to controller. */ +}; + +/* Packet received on port (datapath -> controller). */ +struct ofp_packet_in { + struct ofp_header header; + uint32_t buffer_id; /* ID assigned by datapath. */ + uint16_t total_len; /* Full length of frame. */ + uint16_t in_port; /* Port on which frame was received. */ + uint8_t reason; /* Reason packet is being sent (one of OFPR_*) */ + uint8_t pad; + uint8_t data[0]; /* Ethernet frame, halfway through 32-bit word, + so the IP header is 32-bit aligned. The + amount of data is inferred from the length + field in the header. Because of padding, + offsetof(struct ofp_packet_in, data) == + sizeof(struct ofp_packet_in) - 2. */ +}; +OFP_ASSERT(sizeof(struct ofp_packet_in) == 20); + +enum ofp_action_type { + OFPAT_OUTPUT, /* Output to switch port. */ + OFPAT_SET_VLAN_VID, /* Set the 802.1q VLAN id. */ + OFPAT_SET_VLAN_PCP, /* Set the 802.1q priority. */ + OFPAT_STRIP_VLAN, /* Strip the 802.1q header. */ + OFPAT_SET_DL_SRC, /* Ethernet source address. */ + OFPAT_SET_DL_DST, /* Ethernet destination address. */ + OFPAT_SET_NW_SRC, /* IP source address. */ + OFPAT_SET_NW_DST, /* IP destination address. */ + OFPAT_SET_NW_TOS, /* IP ToS (DSCP field, 6 bits). */ + OFPAT_SET_TP_SRC, /* TCP/UDP source port. */ + OFPAT_SET_TP_DST, /* TCP/UDP destination port. */ + OFPAT_ENQUEUE, /* Output to queue. */ + OFPAT_VENDOR = 0xffff +}; + +/* Action structure for OFPAT_OUTPUT, which sends packets out 'port'. + * When the 'port' is the OFPP_CONTROLLER, 'max_len' indicates the max + * number of bytes to send. A 'max_len' of zero means no bytes of the + * packet should be sent.*/ +struct ofp_action_output { + uint16_t type; /* OFPAT_OUTPUT. */ + uint16_t len; /* Length is 8. */ + uint16_t port; /* Output port. */ + uint16_t max_len; /* Max length to send to controller. */ +}; +OFP_ASSERT(sizeof(struct ofp_action_output) == 8); + +/* The VLAN id is 12 bits, so we can use the entire 16 bits to indicate + * special conditions. All ones is used to match that no VLAN id was + * set. */ +#define OFP_VLAN_NONE 0xffff + +/* Action structure for OFPAT_SET_VLAN_VID. */ +struct ofp_action_vlan_vid { + uint16_t type; /* OFPAT_SET_VLAN_VID. */ + uint16_t len; /* Length is 8. */ + uint16_t vlan_vid; /* VLAN id. */ + uint8_t pad[2]; +}; +OFP_ASSERT(sizeof(struct ofp_action_vlan_vid) == 8); + +/* Action structure for OFPAT_SET_VLAN_PCP. */ +struct ofp_action_vlan_pcp { + uint16_t type; /* OFPAT_SET_VLAN_PCP. */ + uint16_t len; /* Length is 8. */ + uint8_t vlan_pcp; /* VLAN priority. */ + uint8_t pad[3]; +}; +OFP_ASSERT(sizeof(struct ofp_action_vlan_pcp) == 8); + +/* Action structure for OFPAT_SET_DL_SRC/DST. */ +struct ofp_action_dl_addr { + uint16_t type; /* OFPAT_SET_DL_SRC/DST. */ + uint16_t len; /* Length is 16. */ + uint8_t dl_addr[OFP_ETH_ALEN]; /* Ethernet address. */ + uint8_t pad[6]; +}; +OFP_ASSERT(sizeof(struct ofp_action_dl_addr) == 16); + +/* Action structure for OFPAT_SET_NW_SRC/DST. */ +struct ofp_action_nw_addr { + uint16_t type; /* OFPAT_SET_TW_SRC/DST. */ + uint16_t len; /* Length is 8. */ + uint32_t nw_addr; /* IP address. */ +}; +OFP_ASSERT(sizeof(struct ofp_action_nw_addr) == 8); + +/* Action structure for OFPAT_SET_TP_SRC/DST. */ +struct ofp_action_tp_port { + uint16_t type; /* OFPAT_SET_TP_SRC/DST. */ + uint16_t len; /* Length is 8. */ + uint16_t tp_port; /* TCP/UDP port. */ + uint8_t pad[2]; +}; +OFP_ASSERT(sizeof(struct ofp_action_tp_port) == 8); + +/* Action structure for OFPAT_SET_NW_TOS. */ +struct ofp_action_nw_tos { + uint16_t type; /* OFPAT_SET_TW_SRC/DST. */ + uint16_t len; /* Length is 8. */ + uint8_t nw_tos; /* IP ToS (DSCP field, 6 bits). */ + uint8_t pad[3]; +}; +OFP_ASSERT(sizeof(struct ofp_action_nw_tos) == 8); + +/* Action header for OFPAT_VENDOR. The rest of the body is vendor-defined. */ +struct ofp_action_vendor_header { + uint16_t type; /* OFPAT_VENDOR. */ + uint16_t len; /* Length is a multiple of 8. */ + uint32_t vendor; /* Vendor ID, which takes the same form + as in "struct ofp_vendor_header". */ +}; +OFP_ASSERT(sizeof(struct ofp_action_vendor_header) == 8); + +/* Action header that is common to all actions. The length includes the + * header and any padding used to make the action 64-bit aligned. + * NB: The length of an action *must* always be a multiple of eight. */ +struct ofp_action_header { + uint16_t type; /* One of OFPAT_*. */ + uint16_t len; /* Length of action, including this + header. This is the length of action, + including any padding to make it + 64-bit aligned. */ + uint8_t pad[4]; +}; +OFP_ASSERT(sizeof(struct ofp_action_header) == 8); + +/* Send packet (controller -> datapath). */ +struct ofp_packet_out { + struct ofp_header header; + uint32_t buffer_id; /* ID assigned by datapath (-1 if none). */ + uint16_t in_port; /* Packet's input port (OFPP_NONE if none). */ + uint16_t actions_len; /* Size of action array in bytes. */ + struct ofp_action_header actions[0]; /* Actions. */ + /* uint8_t data[0]; */ /* Packet data. The length is inferred + from the length field in the header. + (Only meaningful if buffer_id == -1.) */ +}; +OFP_ASSERT(sizeof(struct ofp_packet_out) == 16); + +enum ofp_flow_mod_command { + OFPFC_ADD, /* New flow. */ + OFPFC_MODIFY, /* Modify all matching flows. */ + OFPFC_MODIFY_STRICT, /* Modify entry strictly matching wildcards */ + OFPFC_DELETE, /* Delete all matching flows. */ + OFPFC_DELETE_STRICT /* Strictly match wildcards and priority. */ +}; + +/* Flow wildcards. */ +enum ofp_flow_wildcards { + OFPFW_IN_PORT = 1 << 0, /* Switch input port. */ + OFPFW_DL_VLAN = 1 << 1, /* VLAN id. */ + OFPFW_DL_SRC = 1 << 2, /* Ethernet source address. */ + OFPFW_DL_DST = 1 << 3, /* Ethernet destination address. */ + OFPFW_DL_TYPE = 1 << 4, /* Ethernet frame type. */ + OFPFW_NW_PROTO = 1 << 5, /* IP protocol. */ + OFPFW_TP_SRC = 1 << 6, /* TCP/UDP source port. */ + OFPFW_TP_DST = 1 << 7, /* TCP/UDP destination port. */ + + /* IP source address wildcard bit count. 0 is exact match, 1 ignores the + * LSB, 2 ignores the 2 least-significant bits, ..., 32 and higher wildcard + * the entire field. This is the *opposite* of the usual convention where + * e.g. /24 indicates that 8 bits (not 24 bits) are wildcarded. */ + OFPFW_NW_SRC_SHIFT = 8, + OFPFW_NW_SRC_BITS = 6, + OFPFW_NW_SRC_MASK = ((1 << OFPFW_NW_SRC_BITS) - 1) << OFPFW_NW_SRC_SHIFT, + OFPFW_NW_SRC_ALL = 32 << OFPFW_NW_SRC_SHIFT, + + /* IP destination address wildcard bit count. Same format as source. */ + OFPFW_NW_DST_SHIFT = 14, + OFPFW_NW_DST_BITS = 6, + OFPFW_NW_DST_MASK = ((1 << OFPFW_NW_DST_BITS) - 1) << OFPFW_NW_DST_SHIFT, + OFPFW_NW_DST_ALL = 32 << OFPFW_NW_DST_SHIFT, + + OFPFW_DL_VLAN_PCP = 1 << 20, /* VLAN priority. */ + OFPFW_NW_TOS = 1 << 21, /* IP ToS (DSCP field, 6 bits). */ + + /* Wildcard all fields. */ + OFPFW_ALL = ((1 << 22) - 1) +}; + +/* The wildcards for ICMP type and code fields use the transport source + * and destination port fields, respectively. */ +#define OFPFW_ICMP_TYPE OFPFW_TP_SRC +#define OFPFW_ICMP_CODE OFPFW_TP_DST + +/* Values below this cutoff are 802.3 packets and the two bytes + * following MAC addresses are used as a frame length. Otherwise, the + * two bytes are used as the Ethernet type. + */ +#define OFP_DL_TYPE_ETH2_CUTOFF 0x0600 + +/* Value of dl_type to indicate that the frame does not include an + * Ethernet type. + */ +#define OFP_DL_TYPE_NOT_ETH_TYPE 0x05ff + +/* The VLAN id is 12-bits, so we can use the entire 16 bits to indicate + * special conditions. All ones indicates that no VLAN id was set. + */ +#define OFP_VLAN_NONE 0xffff + +/* Fields to match against flows */ +struct ofp_match { + uint32_t wildcards; /* Wildcard fields. */ + uint16_t in_port; /* Input switch port. */ + uint8_t dl_src[OFP_ETH_ALEN]; /* Ethernet source address. */ + uint8_t dl_dst[OFP_ETH_ALEN]; /* Ethernet destination address. */ + uint16_t dl_vlan; /* Input VLAN id. */ + uint8_t dl_vlan_pcp; /* Input VLAN priority. */ + uint8_t pad1[1]; /* Align to 64-bits */ + uint16_t dl_type; /* Ethernet frame type. */ + uint8_t nw_tos; /* IP ToS (actually DSCP field, 6 bits). */ + uint8_t nw_proto; /* IP protocol or lower 8 bits of + * ARP opcode. */ + uint8_t pad2[2]; /* Align to 64-bits */ + uint32_t nw_src; /* IP source address. */ + uint32_t nw_dst; /* IP destination address. */ + uint16_t tp_src; /* TCP/UDP source port. */ + uint16_t tp_dst; /* TCP/UDP destination port. */ +}; +OFP_ASSERT(sizeof(struct ofp_match) == 40); + +/* The match fields for ICMP type and code use the transport source and + * destination port fields, respectively. */ +#define icmp_type tp_src +#define icmp_code tp_dst + +/* Value used in "idle_timeout" and "hard_timeout" to indicate that the entry + * is permanent. */ +#define OFP_FLOW_PERMANENT 0 + +/* By default, choose a priority in the middle. */ +#define OFP_DEFAULT_PRIORITY 0x8000 + +enum ofp_flow_mod_flags { + OFPFF_SEND_FLOW_REM = 1 << 0, /* Send flow removed message when flow + * expires or is deleted. */ + OFPFF_CHECK_OVERLAP = 1 << 1, /* Check for overlapping entries first. */ + OFPFF_EMERG = 1 << 2 /* Remark this is for emergency. */ +}; + +/* Flow setup and teardown (controller -> datapath). */ +struct ofp_flow_mod { + struct ofp_header header; + struct ofp_match match; /* Fields to match */ + uint64_t cookie; /* Opaque controller-issued identifier. */ + + /* Flow actions. */ + uint16_t command; /* One of OFPFC_*. */ + uint16_t idle_timeout; /* Idle time before discarding (seconds). */ + uint16_t hard_timeout; /* Max time before discarding (seconds). */ + uint16_t priority; /* Priority level of flow entry. */ + uint32_t buffer_id; /* Buffered packet to apply to (or -1). + Not meaningful for OFPFC_DELETE*. */ + uint16_t out_port; /* For OFPFC_DELETE* commands, require + matching entries to include this as an + output port. A value of OFPP_NONE + indicates no restriction. */ + uint16_t flags; /* One of OFPFF_*. */ + struct ofp_action_header actions[0]; /* The action length is inferred + from the length field in the + header. */ +}; +OFP_ASSERT(sizeof(struct ofp_flow_mod) == 72); + +/* Why was this flow removed? */ +enum ofp_flow_removed_reason { + OFPRR_IDLE_TIMEOUT, /* Flow idle time exceeded idle_timeout. */ + OFPRR_HARD_TIMEOUT, /* Time exceeded hard_timeout. */ + OFPRR_DELETE /* Evicted by a DELETE flow mod. */ +}; + +/* Flow removed (datapath -> controller). */ +struct ofp_flow_removed { + struct ofp_header header; + struct ofp_match match; /* Description of fields. */ + uint64_t cookie; /* Opaque controller-issued identifier. */ + + uint16_t priority; /* Priority level of flow entry. */ + uint8_t reason; /* One of OFPRR_*. */ + uint8_t pad[1]; /* Align to 32-bits. */ + + uint32_t duration_sec; /* Time flow was alive in seconds. */ + uint32_t duration_nsec; /* Time flow was alive in nanoseconds beyond + duration_sec. */ + uint16_t idle_timeout; /* Idle timeout from original flow mod. */ + uint8_t pad2[2]; /* Align to 64-bits. */ + uint64_t packet_count; + uint64_t byte_count; +}; +OFP_ASSERT(sizeof(struct ofp_flow_removed) == 88); + +/* Values for 'type' in ofp_error_message. These values are immutable: they + * will not change in future versions of the protocol (although new values may + * be added). */ +enum ofp_error_type { + OFPET_HELLO_FAILED, /* Hello protocol failed. */ + OFPET_BAD_REQUEST, /* Request was not understood. */ + OFPET_BAD_ACTION, /* Error in action description. */ + OFPET_FLOW_MOD_FAILED, /* Problem modifying flow entry. */ + OFPET_PORT_MOD_FAILED, /* Port mod request failed. */ + OFPET_QUEUE_OP_FAILED /* Queue operation failed. */ +}; + +/* ofp_error_msg 'code' values for OFPET_HELLO_FAILED. 'data' contains an + * ASCII text string that may give failure details. */ +enum ofp_hello_failed_code { + OFPHFC_INCOMPATIBLE, /* No compatible version. */ + OFPHFC_EPERM /* Permissions error. */ +}; + +/* ofp_error_msg 'code' values for OFPET_BAD_REQUEST. 'data' contains at least + * the first 64 bytes of the failed request. */ +enum ofp_bad_request_code { + OFPBRC_BAD_VERSION, /* ofp_header.version not supported. */ + OFPBRC_BAD_TYPE, /* ofp_header.type not supported. */ + OFPBRC_BAD_STAT, /* ofp_stats_request.type not supported. */ + OFPBRC_BAD_VENDOR, /* Vendor not supported (in ofp_vendor_header + * or ofp_stats_request or ofp_stats_reply). */ + OFPBRC_BAD_SUBTYPE, /* Vendor subtype not supported. */ + OFPBRC_EPERM, /* Permissions error. */ + OFPBRC_BAD_LEN, /* Wrong request length for type. */ + OFPBRC_BUFFER_EMPTY, /* Specified buffer has already been used. */ + OFPBRC_BUFFER_UNKNOWN /* Specified buffer does not exist. */ +}; + +/* ofp_error_msg 'code' values for OFPET_BAD_ACTION. 'data' contains at least + * the first 64 bytes of the failed request. */ +enum ofp_bad_action_code { + OFPBAC_BAD_TYPE, /* Unknown action type. */ + OFPBAC_BAD_LEN, /* Length problem in actions. */ + OFPBAC_BAD_VENDOR, /* Unknown vendor id specified. */ + OFPBAC_BAD_VENDOR_TYPE, /* Unknown action type for vendor id. */ + OFPBAC_BAD_OUT_PORT, /* Problem validating output action. */ + OFPBAC_BAD_ARGUMENT, /* Bad action argument. */ + OFPBAC_EPERM, /* Permissions error. */ + OFPBAC_TOO_MANY, /* Can't handle this many actions. */ + OFPBAC_BAD_QUEUE /* Problem validating output queue. */ +}; + +/* ofp_error_msg 'code' values for OFPET_FLOW_MOD_FAILED. 'data' contains + * at least the first 64 bytes of the failed request. */ +enum ofp_flow_mod_failed_code { + OFPFMFC_ALL_TABLES_FULL, /* Flow not added because of full tables. */ + OFPFMFC_OVERLAP, /* Attempted to add overlapping flow with + * CHECK_OVERLAP flag set. */ + OFPFMFC_EPERM, /* Permissions error. */ + OFPFMFC_BAD_EMERG_TIMEOUT, /* Flow not added because of non-zero idle/hard + * timeout. */ + OFPFMFC_BAD_COMMAND, /* Unknown command. */ + OFPFMFC_UNSUPPORTED /* Unsupported action list - cannot process in + * the order specified. */ +}; + +/* ofp_error_msg 'code' values for OFPET_PORT_MOD_FAILED. 'data' contains + * at least the first 64 bytes of the failed request. */ +enum ofp_port_mod_failed_code { + OFPPMFC_BAD_PORT, /* Specified port does not exist. */ + OFPPMFC_BAD_HW_ADDR, /* Specified hardware address is wrong. */ +}; + +/* ofp_error msg 'code' values for OFPET_QUEUE_OP_FAILED. 'data' contains + * at least the first 64 bytes of the failed request */ +enum ofp_queue_op_failed_code { + OFPQOFC_BAD_PORT, /* Invalid port (or port does not exist). */ + OFPQOFC_BAD_QUEUE, /* Queue does not exist. */ + OFPQOFC_EPERM /* Permissions error. */ +}; + +/* OFPT_ERROR: Error message (datapath -> controller). */ +struct ofp_error_msg { + struct ofp_header header; + + uint16_t type; + uint16_t code; + uint8_t data[0]; /* Variable-length data. Interpreted based + on the type and code. */ +}; +OFP_ASSERT(sizeof(struct ofp_error_msg) == 12); + +enum ofp_stats_types { + /* Description of this OpenFlow switch. + * The request body is empty. + * The reply body is struct ofp_desc_stats. */ + OFPST_DESC, + + /* Individual flow statistics. + * The request body is struct ofp_flow_stats_request. + * The reply body is an array of struct ofp_flow_stats. */ + OFPST_FLOW, + + /* Aggregate flow statistics. + * The request body is struct ofp_aggregate_stats_request. + * The reply body is struct ofp_aggregate_stats_reply. */ + OFPST_AGGREGATE, + + /* Flow table statistics. + * The request body is empty. + * The reply body is an array of struct ofp_table_stats. */ + OFPST_TABLE, + + /* Physical port statistics. + * The request body is struct ofp_port_stats_request. + * The reply body is an array of struct ofp_port_stats. */ + OFPST_PORT, + + /* Queue statistics for a port + * The request body defines the port + * The reply body is an array of struct ofp_queue_stats */ + OFPST_QUEUE, + + /* Vendor extension. + * The request and reply bodies begin with a 32-bit vendor ID, which takes + * the same form as in "struct ofp_vendor_header". The request and reply + * bodies are otherwise vendor-defined. */ + OFPST_VENDOR = 0xffff +}; + +struct ofp_stats_request { + struct ofp_header header; + uint16_t type; /* One of the OFPST_* constants. */ + uint16_t flags; /* OFPSF_REQ_* flags (none yet defined). */ + uint8_t body[0]; /* Body of the request. */ +}; +OFP_ASSERT(sizeof(struct ofp_stats_request) == 12); + +enum ofp_stats_reply_flags { + OFPSF_REPLY_MORE = 1 << 0 /* More replies to follow. */ +}; + +struct ofp_stats_reply { + struct ofp_header header; + uint16_t type; /* One of the OFPST_* constants. */ + uint16_t flags; /* OFPSF_REPLY_* flags. */ + uint8_t body[0]; /* Body of the reply. */ +}; +OFP_ASSERT(sizeof(struct ofp_stats_reply) == 12); + +#define DESC_STR_LEN 256 +#define SERIAL_NUM_LEN 32 +/* Body of reply to OFPST_DESC request. Each entry is a NULL-terminated + * ASCII string. */ +struct ofp_desc_stats { + char mfr_desc[DESC_STR_LEN]; /* Manufacturer description. */ + char hw_desc[DESC_STR_LEN]; /* Hardware description. */ + char sw_desc[DESC_STR_LEN]; /* Software description. */ + char serial_num[SERIAL_NUM_LEN]; /* Serial number. */ + char dp_desc[DESC_STR_LEN]; /* Human readable description of datapath. */ +}; +OFP_ASSERT(sizeof(struct ofp_desc_stats) == 1056); + +/* Body for ofp_stats_request of type OFPST_FLOW. */ +struct ofp_flow_stats_request { + struct ofp_match match; /* Fields to match. */ + uint8_t table_id; /* ID of table to read (from ofp_table_stats), + 0xff for all tables or 0xfe for emergency. */ + uint8_t pad; /* Align to 32 bits. */ + uint16_t out_port; /* Require matching entries to include this + as an output port. A value of OFPP_NONE + indicates no restriction. */ +}; +OFP_ASSERT(sizeof(struct ofp_flow_stats_request) == 44); + +/* Body of reply to OFPST_FLOW request. */ +struct ofp_flow_stats { + uint16_t length; /* Length of this entry. */ + uint8_t table_id; /* ID of table flow came from. */ + uint8_t pad; + struct ofp_match match; /* Description of fields. */ + uint32_t duration_sec; /* Time flow has been alive in seconds. */ + uint32_t duration_nsec; /* Time flow has been alive in nanoseconds beyond + duration_sec. */ + uint16_t priority; /* Priority of the entry. Only meaningful + when this is not an exact-match entry. */ + uint16_t idle_timeout; /* Number of seconds idle before expiration. */ + uint16_t hard_timeout; /* Number of seconds before expiration. */ + uint8_t pad2[6]; /* Align to 64-bits. */ + uint64_t cookie; /* Opaque controller-issued identifier. */ + uint64_t packet_count; /* Number of packets in flow. */ + uint64_t byte_count; /* Number of bytes in flow. */ + struct ofp_action_header actions[0]; /* Actions. */ +}; +OFP_ASSERT(sizeof(struct ofp_flow_stats) == 88); + +/* Body for ofp_stats_request of type OFPST_AGGREGATE. */ +struct ofp_aggregate_stats_request { + struct ofp_match match; /* Fields to match. */ + uint8_t table_id; /* ID of table to read (from ofp_table_stats) + 0xff for all tables or 0xfe for emergency. */ + uint8_t pad; /* Align to 32 bits. */ + uint16_t out_port; /* Require matching entries to include this + as an output port. A value of OFPP_NONE + indicates no restriction. */ +}; +OFP_ASSERT(sizeof(struct ofp_aggregate_stats_request) == 44); + +/* Body of reply to OFPST_AGGREGATE request. */ +struct ofp_aggregate_stats_reply { + uint64_t packet_count; /* Number of packets in flows. */ + uint64_t byte_count; /* Number of bytes in flows. */ + uint32_t flow_count; /* Number of flows. */ + uint8_t pad[4]; /* Align to 64 bits. */ +}; +OFP_ASSERT(sizeof(struct ofp_aggregate_stats_reply) == 24); + +/* Body of reply to OFPST_TABLE request. */ +struct ofp_table_stats { + uint8_t table_id; /* Identifier of table. Lower numbered tables + are consulted first. */ + uint8_t pad[3]; /* Align to 32-bits. */ + char name[OFP_MAX_TABLE_NAME_LEN]; + uint32_t wildcards; /* Bitmap of OFPFW_* wildcards that are + supported by the table. */ + uint32_t max_entries; /* Max number of entries supported. */ + uint32_t active_count; /* Number of active entries. */ + uint64_t lookup_count; /* Number of packets looked up in table. */ + uint64_t matched_count; /* Number of packets that hit table. */ +}; +OFP_ASSERT(sizeof(struct ofp_table_stats) == 64); + +/* Body for ofp_stats_request of type OFPST_PORT. */ +struct ofp_port_stats_request { + uint16_t port_no; /* OFPST_PORT message must request statistics + * either for a single port (specified in + * port_no) or for all ports (if port_no == + * OFPP_NONE). */ + uint8_t pad[6]; +}; +OFP_ASSERT(sizeof(struct ofp_port_stats_request) == 8); + +/* Body of reply to OFPST_PORT request. If a counter is unsupported, set + * the field to all ones. */ +struct ofp_port_stats { + uint16_t port_no; + uint8_t pad[6]; /* Align to 64-bits. */ + uint64_t rx_packets; /* Number of received packets. */ + uint64_t tx_packets; /* Number of transmitted packets. */ + uint64_t rx_bytes; /* Number of received bytes. */ + uint64_t tx_bytes; /* Number of transmitted bytes. */ + uint64_t rx_dropped; /* Number of packets dropped by RX. */ + uint64_t tx_dropped; /* Number of packets dropped by TX. */ + uint64_t rx_errors; /* Number of receive errors. This is a super-set + of more specific receive errors and should be + greater than or equal to the sum of all + rx_*_err values. */ + uint64_t tx_errors; /* Number of transmit errors. This is a super-set + of more specific transmit errors and should be + greater than or equal to the sum of all + tx_*_err values (none currently defined.) */ + uint64_t rx_frame_err; /* Number of frame alignment errors. */ + uint64_t rx_over_err; /* Number of packets with RX overrun. */ + uint64_t rx_crc_err; /* Number of CRC errors. */ + uint64_t collisions; /* Number of collisions. */ +}; +OFP_ASSERT(sizeof(struct ofp_port_stats) == 104); + +/* Vendor extension. */ +struct ofp_vendor_header { + struct ofp_header header; /* Type OFPT_VENDOR. */ + uint32_t vendor; /* Vendor ID: + * - MSB 0: low-order bytes are IEEE OUI. + * - MSB != 0: defined by OpenFlow + * consortium. */ + /* Vendor-defined arbitrary additional data. */ +}; +OFP_ASSERT(sizeof(struct ofp_vendor_header) == 12); + +/* All ones is used to indicate all queues in a port (for stats retrieval). */ +#define OFPQ_ALL 0xffffffff + +/* Min rate > 1000 means not configured. */ +#define OFPQ_MIN_RATE_UNCFG 0xffff + +enum ofp_queue_properties { + OFPQT_NONE = 0, /* No property defined for queue (default). */ + OFPQT_MIN_RATE, /* Minimum datarate guaranteed. */ + /* Other types should be added here + * (i.e. max rate, precedence, etc). */ +}; + +/* Common description for a queue. */ +struct ofp_queue_prop_header { + uint16_t property; /* One of OFPQT_. */ + uint16_t len; /* Length of property, including this header. */ + uint8_t pad[4]; /* 64-bit alignemnt. */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_prop_header) == 8); + +/* Min-Rate queue property description. */ +struct ofp_queue_prop_min_rate { + struct ofp_queue_prop_header prop_header; /* prop: OFPQT_MIN, len: 16. */ + uint16_t rate; /* In 1/10 of a percent; >1000 -> disabled. */ + uint8_t pad[6]; /* 64-bit alignment */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_prop_min_rate) == 16); + +/* Full description for a queue. */ +struct ofp_packet_queue { + uint32_t queue_id; /* id for the specific queue. */ + uint16_t len; /* Length in bytes of this queue desc. */ + uint8_t pad[2]; /* 64-bit alignment. */ + struct ofp_queue_prop_header properties[0]; /* List of properties. */ +}; +OFP_ASSERT(sizeof(struct ofp_packet_queue) == 8); + +/* Query for port queue configuration. */ +struct ofp_queue_get_config_request { + struct ofp_header header; + uint16_t port; /* Port to be queried. Should refer + to a valid physical port (i.e. < OFPP_MAX) */ + uint8_t pad[2]; /* 32-bit alignment. */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_get_config_request) == 12); + +/* Queue configuration for a given port. */ +struct ofp_queue_get_config_reply { + struct ofp_header header; + uint16_t port; + uint8_t pad[6]; + struct ofp_packet_queue queues[0]; /* List of configured queues. */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_get_config_reply) == 16); + +/* OFPAT_ENQUEUE action struct: send packets to given queue on port. */ +struct ofp_action_enqueue { + uint16_t type; /* OFPAT_ENQUEUE. */ + uint16_t len; /* Len is 16. */ + uint16_t port; /* Port that queue belongs. Should + refer to a valid physical port + (i.e. < OFPP_MAX) or OFPP_IN_PORT. */ + uint8_t pad[6]; /* Pad for 64-bit alignment. */ + uint32_t queue_id; /* Where to enqueue the packets. */ +}; +OFP_ASSERT(sizeof(struct ofp_action_enqueue) == 16); + +struct ofp_queue_stats_request { + uint16_t port_no; /* All ports if OFPT_ALL. */ + uint8_t pad[2]; /* Align to 32-bits. */ + uint32_t queue_id; /* All queues if OFPQ_ALL. */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_stats_request) == 8); + +struct ofp_queue_stats { + uint16_t port_no; + uint8_t pad[2]; /* Align to 32-bits. */ + uint32_t queue_id; /* Queue i.d */ + uint64_t tx_bytes; /* Number of transmitted bytes. */ + uint64_t tx_packets; /* Number of transmitted packets. */ + uint64_t tx_errors; /* Number of packets dropped due to overrun. */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_stats) == 32); + +#endif /* openflow/openflow.h */ diff --git a/openflow/include/openflow/private-ext.h b/openflow/include/openflow/private-ext.h new file mode 100644 index 00000000..61fc8fb0 --- /dev/null +++ b/openflow/include/openflow/private-ext.h @@ -0,0 +1,68 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#ifndef OPENFLOW_PRIVATE_EXT_H_ +#define OPENFLOW_PRIVATE_EXT_H_ + +#ifdef __KERNEL__ +#include +#endif + +#include "openflow/openflow.h" + +/* + * The following PRIVATE vendor extensions are just sample and may never be + * ready for standardization, so they are not included in openflow.h. + * + * As a sample, we use private OUI (AC-DE-48) for PRIVATE vendor ID. + */ + +#define PRIVATE_VENDOR_ID 0x00acde48 +#define PRIVATEOPT_PROTOCOL_STATS_REQUEST 0x0001 +#define PRIVATEOPT_PROTOCOL_STATS_REPLY 0x0002 +#define PRIVATEOPT_EMERG_FLOW_PROTECTION 0x0003 +#define PRIVATEOPT_EMERG_FLOW_RESTORATION 0x0004 + +struct private_vxhdr { + struct ofp_header ofp_hdr; /* protocol header */ + uint32_t ofp_vxid; /* vendor extenion ID */ +} __attribute__ ((__packed__)); + +/* TLV encoding */ +struct private_vxopt { + uint16_t pvo_type; /* type of vendor extension option */ + uint16_t pvo_len; /* length of value (octet) */ + /* followed by value */ + /* uint8_t pvo_value[0]; */ +} __attribute__ ((__packed__)); + +#endif diff --git a/openflow/m4/libopenflow.m4 b/openflow/m4/libopenflow.m4 new file mode 100644 index 00000000..58014ed5 --- /dev/null +++ b/openflow/m4/libopenflow.m4 @@ -0,0 +1,168 @@ +# -*- autoconf -*- + +# Copyright (c) 2008 The Board of Trustees of The Leland Stanford +# Junior University +# +# We are making the OpenFlow specification and associated documentation +# (Software) available for public use and benefit with the expectation +# that others will use, modify and enhance the Software and contribute +# those enhancements back to the community. However, since we would +# like to make the Software available for broadest use, with as few +# restrictions as possible permission is hereby granted, free of +# charge, to any person obtaining a copy of this Software to deal in +# the Software under the copyrights without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# The name and trademarks of copyright holder(s) may NOT be used in +# advertising or publicity pertaining to the Software or any +# derivatives without specific, written prior permission. + +dnl Checks for --enable-ndebug and defines NDEBUG if it is specified. +AC_DEFUN([OFP_CHECK_NDEBUG], + [AC_ARG_ENABLE( + [ndebug], + [AC_HELP_STRING([--enable-ndebug], + [Disable debugging features for max performance])], + [case "${enableval}" in + (yes) ndebug=true ;; + (no) ndebug=false ;; + (*) AC_MSG_ERROR([bad value ${enableval} for --enable-ndebug]) ;; + esac], + [ndebug=false]) + AM_CONDITIONAL([NDEBUG], [test x$ndebug = xtrue])]) + +dnl Checks for Netlink support. +AC_DEFUN([OFP_CHECK_NETLINK], + [AC_CHECK_HEADER([linux/netlink.h], + [HAVE_NETLINK=yes], + [HAVE_NETLINK=no], + [#include + #include + ]) + AM_CONDITIONAL([HAVE_NETLINK], [test "$HAVE_NETLINK" = yes]) + if test "$HAVE_NETLINK" = yes; then + AC_DEFINE([HAVE_NETLINK], [1], + [Define to 1 if Netlink protocol is available.]) + fi]) + +dnl Checks for OpenSSL, if --enable-ssl is passed in. +AC_DEFUN([OFP_CHECK_OPENSSL], + [AC_ARG_ENABLE( + [ssl], + [AC_HELP_STRING([--enable-ssl], + [Enable ssl support (requires libssl)])], + [case "${enableval}" in + (yes) ssl=true ;; + (no) ssl=false ;; + (*) AC_MSG_ERROR([bad value ${enableval} for --enable-ssl]) ;; + esac], + [ssl=false]) + + if test "$ssl" = true; then + dnl Make sure that pkg-config is installed. + m4_pattern_forbid([PKG_CHECK_MODULES]) + PKG_CHECK_MODULES([SSL], [libssl], + [HAVE_OPENSSL=yes], + [HAVE_OPENSSL=no + AC_MSG_WARN([Cannot find libssl: + + $SSL_PKG_ERRORS + + OpenFlow will not support SSL connections.])]) + + fi + AM_CONDITIONAL([HAVE_OPENSSL], [test "$HAVE_OPENSSL" = yes]) + if test "$HAVE_OPENSSL" = yes; then + AC_DEFINE([HAVE_OPENSSL], [1], [Define to 1 if OpenSSL is installed.]) + fi]) + +dnl Checks for libraries needed by lib/fault.c. +AC_DEFUN([OFP_CHECK_FAULT_LIBS], + [AC_CHECK_LIB([dl], [dladdr], [FAULT_LIBS=-ldl]) + AC_SUBST([FAULT_LIBS])]) + +dnl Checks for libraries needed by lib/socket-util.c. +AC_DEFUN([OFP_CHECK_SOCKET_LIBS], + [AC_CHECK_LIB([socket], [connect]) + AC_SEARCH_LIBS([gethostbyname], [resolv], [RESOLVER_LIBS=-lresolv])]) + +dnl Checks for the directory in which to store the PKI. +AC_DEFUN([OFP_CHECK_PKIDIR], + [AC_ARG_WITH( + [pkidir], + AC_HELP_STRING([--with-pkidir=DIR], + [PKI hierarchy directory [[DATADIR/openflow/pki]]]), + [PKIDIR=$withval], + [PKIDIR='${pkgdatadir}/pki']) + AC_SUBST([PKIDIR])]) + +dnl Checks for the directory in which to store pidfiles. +AC_DEFUN([OFP_CHECK_RUNDIR], + [AC_ARG_WITH( + [rundir], + AC_HELP_STRING([--with-rundir=DIR], + [directory used for pidfiles [[LOCALSTATEDIR/run]]]), + [RUNDIR=$withval], + [RUNDIR='${localstatedir}/run']) + AC_SUBST([RUNDIR])]) + +dnl Checks for the directory in which to store logs. +AC_DEFUN([OFP_CHECK_LOGDIR], + [AC_ARG_WITH( + [logdir], + AC_HELP_STRING([--with-logdir=DIR], + [directory used for logs [[LOCALSTATEDIR/log/PACKAGE]]]), + [LOGDIR=$withval], + [LOGDIR='${localstatedir}/log/${PACKAGE}']) + AC_SUBST([LOGDIR])]) + +dnl Checks for __malloc_hook, etc., supported by glibc. +AC_DEFUN([OFP_CHECK_MALLOC_HOOKS], + [AC_CACHE_CHECK( + [whether libc supports hooks for malloc and related functions], + [ofp_cv_malloc_hooks], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [#include + ], + [(void) __malloc_hook; + (void) __realloc_hook; + (void) __free_hook;])], + [ofp_cv_malloc_hooks=yes], + [ofp_cv_malloc_hooks=no])]) + if test $ofp_cv_malloc_hooks = yes; then + AC_DEFINE([HAVE_MALLOC_HOOKS], [1], + [Define to 1 if you have __malloc_hook, __realloc_hook, and + __free_hook in .]) + fi]) + +dnl Runs the checks required to include the headers in include/ and +dnl link against lib/libopenflow.a. +AC_DEFUN([OFP_CHECK_LIBOPENFLOW], + [AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS]) + AC_REQUIRE([OFP_CHECK_NDEBUG]) + AC_REQUIRE([OFP_CHECK_NETLINK]) + AC_REQUIRE([OFP_CHECK_OPENSSL]) + AC_REQUIRE([OFP_CHECK_FAULT_LIBS]) + AC_REQUIRE([OFP_CHECK_SOCKET_LIBS]) + AC_REQUIRE([OFP_CHECK_PKIDIR]) + AC_REQUIRE([OFP_CHECK_RUNDIR]) + AC_REQUIRE([OFP_CHECK_LOGDIR]) + AC_REQUIRE([OFP_CHECK_MALLOC_HOOKS]) + AC_CHECK_FUNCS([strlcpy])]) + diff --git a/openflow/m4/nx-build.m4 b/openflow/m4/nx-build.m4 new file mode 100644 index 00000000..d681cecc --- /dev/null +++ b/openflow/m4/nx-build.m4 @@ -0,0 +1,71 @@ +# -*- autoconf -*- + +# Copyright (c) 2008 The Board of Trustees of The Leland Stanford +# Junior University +# +# We are making the OpenFlow specification and associated documentation +# (Software) available for public use and benefit with the expectation +# that others will use, modify and enhance the Software and contribute +# those enhancements back to the community. However, since we would +# like to make the Software available for broadest use, with as few +# restrictions as possible permission is hereby granted, free of +# charge, to any person obtaining a copy of this Software to deal in +# the Software under the copyrights without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# The name and trademarks of copyright holder(s) may NOT be used in +# advertising or publicity pertaining to the Software or any +# derivatives without specific, written prior permission. + +dnl NX_BUILDNR +dnl +dnl If --with-build-number=NUMBER is used, substitutes a Makefile +dnl variable BUILDNR with NUMBER, and sets a C preprocessor variable +dnl BUILDNR to "+buildNUMBER". +dnl +dnl Otherwise, if --with-build-number is not used, substitutes BUILDNR +dnl with 0 and sets C preprocessor variable BUILDNR to "". +AC_DEFUN([NX_BUILDNR], + [AC_ARG_WITH( + [build-number], + [AS_HELP_STRING([--with-build-number=NUMBER], + [Official build number (default is none)])]) + AC_MSG_CHECKING([build number]) + case $with_build_number in # ( + [[0-9]] | \ + [[0-9]][[0-9]] | \ + [[0-9]][[0-9]][[0-9]] | \ + [[0-9]][[0-9]][[0-9]][[0-9]] | \ + [[0-9]][[0-9]][[0-9]][[0-9]][[0-9]]) + BUILDNR=$with_build_number + buildnr='"+build'$BUILDNR'"' + AC_MSG_RESULT([$with_build_number]) + ;; # ( + ''|no) + BUILDNR=0 + buildnr='""' + AC_MSG_RESULT([none]) + ;; # ( + *) + AC_MSG_ERROR([invalid build number $with_build_number]) + ;; + esac + AC_SUBST([BUILDNR]) + AC_DEFINE_UNQUOTED([BUILDNR], [$buildnr], + [Official build number as a VERSION suffix string, e.g. "+build123", + or "" if this is not an official build.])]) diff --git a/openflow/regress/CREDITS b/openflow/regress/CREDITS new file mode 100644 index 00000000..987380af --- /dev/null +++ b/openflow/regress/CREDITS @@ -0,0 +1,22 @@ +Credit goes to those who contributed code to the regression suite. Unless +otherwise noted, the contributors are at Stanford University. + + +Test writers/editors: + Clay Collier + David Erickson + Mikio Hara (NEC) + Brandon Heller + Peyman Kazemian + Masayoshi Kobayashi (NEC) + Bob Lantz + Brandon Nefcy + Rob Sherwood (Deutsche Telekom R&D Labs) + Jean Tourrilhes (HP Labs) + Tatsuya Yabe (NEC) + Yiannis Yiakoumis + +Supporting libraries: + Adam Covington + Glen Gibb + Jad Naous diff --git a/openflow/regress/INSTALL b/openflow/regress/INSTALL new file mode 100644 index 00000000..4ddad72f --- /dev/null +++ b/openflow/regress/INSTALL @@ -0,0 +1,264 @@ + Installation Instructions for OpenFlow Reference Tests + +This document describes how to install and execute the OpenFlow reference test +suite, which provides an automated way to verify that an OpenFlow switch +adheres to the OpenFlow Protocol. Out of the box, tests work with the OpenFlow +Reference Linux Switch, but can support other platforms by defining custom +setup and teardown scripts. Additional tests verify the reference learning +Ethernet switch controller included with the OpenFlow Reference Linux Switch. + +Please send any comments to: + + + +=== Prerequisites === + +The tests require no other packets to be sent on the testing interfaces. +Built-in programs like avahi-daemon and/or network-manager may send packets, +causing the tests to report failure. The simplest way to remove these packets +is to disable the ipv6 module and reboot, as well as remove avahi-daemon. + +All test configurations require the following Perl modules: + perl-Convert-Binary-C + perl-Data-HexDump + perl-Net-Pcap (perl-Net-Pcap-0.16-1) + perl-Net-RawIP.i386 (perl-Net-RawIP-0.23-1) + perl-Error.noarch (perl-Error-0.17012-1) + +These packages can be installed from source via www.cpan.org, or you can use +pre-built packages (much faster!). + +The code has been tested on CentOS 5.1/5.2, Ubuntu Hardy Heron, and Debian +Unstable under the following configurations. + +** Config 1 - Four virtual Ethernet loopback pairs + +To set these up, you must have a kernel version >= 2.6.24 and the veth kernel +module compiled. + +To set up link pairs, you must also have iproute installed. + +Scripts to simplify this are included in bin/: +-bin/veth_setup.pl +-bin/veth_teardown.pl + +Before running any veth tests, make sure to run bin/veth_setup.pl, which will +create interfaces veth{0..7}. The usual ports of eth{1..8} are remapped to these +ports via the file veth.map in /bin/. To remove these interfaces, run +bin/veth_teardown.pl + +** Config 2 - Two quad-port Ethernet NICs connected by physical loopback cables + +Assign ports as eth{1..8} and connect cables as: + eth1 to eth5 + eth2 to eth6 + eth3 to eth7 + eth4 to eth8 + +** Config 3 - Four local ethernet ports connected to external switch + +A third configuration is to use four ports of Ethernet on the test machine, +connected to an external switch. To do this, you must provide custom setup +and teardown scripts that enable/disable OpenFlow on the external switch via +SSH, telnet, or SNMP. See the scripts in bin/ for examples of how to create +these. + +** Config 4 - One quad-port Ethernet NIC connected to a NetFPGA + +This testing configuration is used to verify the NetFPGA's OpenFlow +functionality. It requires 4 ports of Ethernet connected to corresponding ports +on the NetFPGA in the following arrangement: + eth1 to nf2c0 + eth2 to nf2c1 + eth3 to nf2c2 + eth4 to nf2c3 + +This test also assumes that you have correctly installed the NetFPGA ahead of +time. For further information about the NetFPGA please see +http://www.netfpga.org/ + +Of particular note, by default installing the NetFPGA also puts the +NF2/lib/Perl5 directory into your PERL5LIB environment variable, this must be +removed else the tests will fail. Ensure that your PERL5LIB only contains the +path set by the env_vars file that will be discussed later in this document. + + +=== Ubuntu Quickstart === + +Follow these instructions to quickly create a VM or physical machine with +OpenFlow that runs the tests. + +Ubuntu is recommended because it is based on Debian sources and has a recent +kernel version - which removes the need for some steps. + +If installing as a VM, you'll need to install VMWare Server (Windows/Linux, +free) or VMWare Fusion (Mac, $$$). + +Download the Ubuntu 8.04 Desktop or Server ISO, and install Ubuntu. + +If you prefer, install VMWare Tools to enable better mouse and display support. +Alternately, install SSH and use it for the rest of the instructions: + sudo apt-get install ssh +Install GCC, which is required for OpenFlow: + sudo apt-get install gcc +Download and untar OpenFlow v0.8.1 + wget http://openflowswitch.org/downloads/openflow-v0.8.1.tar.gz + tar xzf openflow-v0.8.1.tar.gz +Build OpenFlow user-space and kernel-space switches: + cd openflow-v0.8.1 + ./configure --with-l26=/lib/modules/`uname -r` + make + sudo make install +Now, download and untar the OpenFlow Test Suite: + wget http://openflowswitch.org/downloads/openflow-test-v0.8.1-r2.tar.gz +Install required packages for the test suite: + sudo apt-get install liberror-perl libio-interface-perl liblist-moreutils-perl libpcap0.8-dev +Download the following: + wget http://search.cpan.org/CPAN/authors/id/S/SA/SAPER/Net-Pcap-0.14.tar.gz + wget http://search.cpan.org/CPAN/authors/id/S/SZ/SZABGAB/Net-RawIP-0.21.tar.gz + wget http://search.cpan.org/CPAN/authors/id/M/MH/MHX/Convert-Binary-C-0.71.tar.gz + wget http://search.cpan.org/CPAN/authors/id/F/FT/FTASSIN/Data-HexDump-0.02.tar.gz +For each package: + tar xzf + cd + perl Makefile.PL + make + make install +Remove avahi-daemon, which often causes tests to fail by sending out messages: + sudo apt-get remove avahi-daemon +Create a root password, to be used later: + sudo passwd root + +From here, skip to the Running The Tests section below. + + +=== CentOS 5.2 === + +First, download and verify you can build the current version of OpenFlow. + +Install the RPMForge repository: + wget http://dag.wieers.com/rpm/packages/rpmforge-release/rpmforge-release-0.3.6-1.el5.rf.i386.rpm + rpm -Uhv rpmforge-release-0.3.6-1.el5.rf.i386.rpm + +Install Perl packages: + yum -y install perl-Convert-Binary-C perl-Data-HexDump perl-Net-Pcap perl-Net-RawIP.i386 perl-Error.noarch + +To run tests with Veth pairs, you'll need to upgrade to a newer version of the kernel. + +Install iproute: + yum -y install iproute + +From here, skip to the Running The Tests section below. + +=== Debian Install === + +These instructions derive from http://netfpga.org/netfpgawiki/index.php/Ubuntu_Compatibility + +Some instructions may no longer be necessary. + +*The version of libnet-pcap-perl that Debian and Ubuntu 6.06/7.04/7.10 provides is ANCIENT (version 0.04). The latest stable version is 0.14. No newer version is available as a package, so we must build it ourselves. +*The version of libpcap that Debian and Ubuntu 7.04 provides by default is old (version 0.72). The latest stable version is 0.9.8. Fortunately, the package manager has a newer version called "libpcap0.8" that is really version 0.9.5 +*Remove old packages / install new ones + +May not be necessary: + apt-get remove libpcap0.7 libpcap0.7-dev libpcap-dev libnet-pcap-perl + +Will be necessary: + apt-get install liberror-perl libio-interface-perl liblist-moreutils-perl libpcap0.8 libpcap0.8-dev psmisc +Listed individually: + apt-get install liberror-perl + apt-get install libio-interface-perl (Used to manually build a newer version of Net::PCap) + apt-get install liblist-moreutils-perl (Used to manually build a newer version of Net::RawIP) + apt-get install libpcap0.8 + apt-get install libpcap0.8-dev + apt-get install psmisc (Used to get killall) + +Required packages have Debian versions at packages.debian.org, however these packages may not be the newest, or not exist at all. libnet-rawip-perl and libnet-pacp-perl may work, but have not been tested. We'll manually install these two packages: +http://search.cpan.org/~saper/Net-Pcap-0.14/Pcap.pm +http://search.cpan.org/~szabgab/Net-RawIP-0.21/lib/Net/RawIP.pm +http://search.cpan.org/dist/Convert-Binary-C/lib/Convert/Binary/C.pm +http://search.cpan.org/dist/Data-HexDump/lib/Data/HexDump.pm + +Download the following: + wget http://search.cpan.org/CPAN/authors/id/S/SA/SAPER/Net-Pcap-0.14.tar.gz + wget http://search.cpan.org/CPAN/authors/id/S/SZ/SZABGAB/Net-RawIP-0.21.tar.gz + wget http://search.cpan.org/CPAN/authors/id/M/MH/MHX/Convert-Binary-C-0.71.tar.gz + wget http://search.cpan.org/CPAN/authors/id/F/FT/FTASSIN/Data-HexDump-0.02.tar.gz +For each package: + tar xzf + cd + perl Makefile.PL + make + make install + +Install if you want to use veth pairs: + apt-get install iproute + +=== Running the Tests === + +In the sections below, {platform} refers to: +user +user_veth +kmod +kmod_veth +nf2 + +First copy the env_vars file to your home directory: + cd ~/ + cp /regress/scripts/env_vars . + +Update the OF_ROOT (openflow) environment variable to point to your OpenFlow +directory in your setup. These exports can also be added to your ~/.bashrc +file to load automatically: + vim env_vars + +Enter a root shell session, or set up sudo. The perl-Net-RawIP library requires +root access to bind to ports. + su + +Source the environment variables: + source env_vars + +For a setup with virtual ethernet pairs, set them up: + veth_setup.pl + +Verify your setup by running regression tests on your platform of choice: + of_{platform}_test.pl +For the user-space switch, the tests should show pass for all scripts except +the _X_controller ones. For the kernel-space switch, all tests should pass. + +To see more options for the regression script, type: + of_{platform}_test.pl --help + +== Writing Your Own Tests == + +Look at an example controller test: + vim /regress/projects/learning_switch/regress/test_unicast_unknown/run.pl + +Look at an example black box switch test: + vim /regress/projects/black_box/regress/test_hello/run.pl + +To run an individual test (learning switch example): + cd /regres/projects/learning_switch/regress/test_unicast_unknown + of_{platform}_setup.pl; ./run.pl; of_{platform}_teardown.pl + +To see traffic when running a black box test, use tcpdump. Secchan and the +Perl code use the loopback interface to communicate, and you can snoop on this: + tcpdump -X -i lo -s 256 + +It can be convenient to run your test in isolation, without setup and teardown +automatically called. To set up the OF kmod and interfaces, run: + of_{platform}_setup.pl + +To remove the OF kmod cleanly, run: + of_{platform}_teardown.pl +Note that the kmod refuses removal until the interfaces and datapaths have been removed. + +== Reporting Bugs == + +Please report problems to: +openflow-discuss@openflowswitch.org + +or post them directly to our bug tracking system: + +http://www.openflowswitch.org/bugs/openflow diff --git a/openflow/regress/LICENSE b/openflow/regress/LICENSE new file mode 100644 index 00000000..b9e21768 --- /dev/null +++ b/openflow/regress/LICENSE @@ -0,0 +1,30 @@ +Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior +University + + +We are making the OpenFlow tests and associated documentation (Software) +available for public use and benefit with the expectation that others will +use, modify and enhance the Software and contribute those enhancements back +to the community. However, since we would like to make the Software +available for broadest use, with as few restrictions as possible permission +is hereby granted, free of charge, to any person obtaining a copy of this +Software) to deal in the Software under the copyrights without restriction, +including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +The name and trademarks of copyright holder(s) may NOT be used in +advertising or publicity pertaining to the Software or any derivatives +without specific, written prior permission. diff --git a/openflow/regress/README b/openflow/regress/README new file mode 100644 index 00000000..a27967fb --- /dev/null +++ b/openflow/regress/README @@ -0,0 +1,329 @@ + OpenFlow Reference Tests + +What's here? +------------ + +This distribution includes: + + - 55+ "black box" tests to verify that an OF switch conforms to the + OF protocol 0x01 + + - 7 tests to verify that the reference controller acts as a learning + Ethernet switch + +The tests are intended to simplify the process of creating an OF switch +that conforms to spec. + +Please see INSTALL for instruction on installing and running the tests. + +Changelog +--------------- +1.0.0-r1 + - Added Open vSwitch scripts : kernel + user + interface maps + - Added VETH scripts for Open vSwitch : kernel + user + - Updated HP-ProCurve scipts : 5400/3500 and 6600 + - Assorted fixes to libraries : + accept port > 10 + accept vlan interfaces + more explicit error messages + - Assorted fixes to tests : + test_switch_config/ -> add delay + test_forward_broadcast_exact_port/ -> run for allports + test_set_n_match_nw_tos/ -> fixup nw_tos usage + test_set_nw_dst/ -> cleanup + test_failover_startup/ -> argv parsing was broken + - Add new test : test_set_dl_nw_flip -> flip dl & nw addresses + - Add new command line options : no_vlan, no_slicing and no_barrier, + no_emerg + - Add ability to run a single test with --testPath + - New debugging function : dpctl_show_flows + +1.0.0 + - all tests updated to OpenFlow wire protocol 0x01 + - added tests for new features in the OpenFlow 1.0.0 spec + +0.9.0 + - all tests updated to OpenFlow wire protocol 0x98 + +v0.8.2 + - Added support for the NetFPGA + - Integrated the tests into the OpenFlow directory structure + +v0.8.1-r2 + - refactored code to make new test ports easier + - fixed documentation bug in test_LLC + - changed all interfaces IPs to 192.168.20X.X to not conflict with the + IP addrs typically assigned via DHCP by home routers + - added easy support for testing user-space switch with physical ports + - added easy support for user-space switch with virtual ports + +v0.8.1-r1 + - added instructions for Debian install + - fixed timing bug in packet_out + +v0.8.1-r0 + - all tests updated to OF spec v0.8.1 + - added black box test switch_config + - fixed timing dependence in learning switch tests + +v0.2.1 + - initial release for OF spec v0.5.1, code tested for ref OF code v0.2.1 + +Platform support +---------------- + +The code is written in Perl5, and should in theory work on any system. +It has been tested with CentOS 5.4, Ubuntu 9.10, Fedora Core 12, and Debian Unstable. + +Learning Switch Tests +---------------- + +Two tests currently fail with OF Reference v0.8.1: + +-Unicast, send to self: the switch is forwarding packets with source and destination on the same port to that port instead of dropping it. + +-Unicast, hub connected:the switch is forwarding traffic to the same port it has came out of, although the source and destination are on the same port and switch already knows about that. + +Both failing tests can be re-activated by changing +projects/learning_switch/regress/tests.txt + +=== Unicast, unknown dest === +:; Name: test_unicast_unknown +:; Owner: Peyman +:; Description +::send packet out p0 to unknown MAC addr +::verify unmodified packet received at p1..p3 +::verify counters incremented + +=== Unicast, known dest === +:; Name: test_unicast_known +:; Owner: Peyman +:; Description: Send to known unicast address, verify switch sent to only one port +::send out p0 to p1 +::verify received at p1..p3 +::send out p1 to p0 +::verify received at p0, NOT p2, p3 +::send out p2 to p0 +::verify received at p0, NOT p1, p3 +::send out p3 to p0 +::verify received at p0, NOT p1, p2 +::verify counters + +=== Broadcast === +:; Name: test_broadcast +:; Owner: Peyman +:; Description: Send to broadcast address, verify received on all ports +::send out p0 to all +::verify received at p1..p3 +::send out p0 to all, again +::verify received at p1..p3, again +::repeat for each port +::verify counters + +=== Unicast, send to self === +:; Name: test_unicast_self +:; Owner: Peyman +:; Description: Send to self, verify dropped + +=== Unicast, change attachment point === +:; Name: test_unicast_move +:; Owner: Peyman +:; Description: Send normal unicast, but then change attachment point (one MAC sent from multiple ports), verify that new location is used +::send form host A at p0 to p1 +::verify received at p1..p3 +::send from p1 to host A +::verify received at p0, NOT p1, p2, p3 +::(original p0 has now moves to p2) +::send from host A (currently at p2) to p1 +::verify received at p1, NOT p0, p2, p3 +::send from p1 to Host A (currently at p2) +::verify received p2, NOT p0, p1, p3 + +=== Unicast, hub connected === +:; Name: test_hub_connected +:; Owner: Peyman +:; Description: if a port connects to a hub, we may receive traffic for which the sender and receiver are connected to the same port. This traffic should be dropped. + +=== Unicast, multiple hosts per port === +:; Name: test_unicast_multiple_hosts +:; Owner: Peyman +:; Description: assume each port is connected to a switch, so that each port receives traffic from multiple MAC addresses - say, 20 per port. Other than multiple MAC addrs per port, this is just like test_unicast_known. Each port sends to a host at a different port. + + +Black Box Tests +---------------- + +One test currently fails with the OF Reference v0.8.1 kmod: + +-LLC: Pkt is forwarded to the controller, when it should be dropped. + +Two tests are currently failing with the OF Reference v0.8.1 user-space switch: + +-test_forward_exact_controller +-test_forward_wildcard_controller + +All failing tests can be re-activated by changing +projects/black_box/regress/tests.txt + +== Basic Functionality == + +=== Hello === +:; Name: test_hello +:; Owner: Brandon Heller +:; Description: send hello packet to switch, verify reply with correct params + +=== Send from Switch to Controller === +:; Name: test_packet_in +:; Owner: Brandon Heller +:; Description: send packet from switch to SC, verify it is received at the controller + +=== Send from Controller to Switch === +:; Name: test_packet_out +:; Owner: Brandon Heller +:; Description: send packet to switch on secure chan for each output port, ensure packet received at proper ports. + +=== Switch Config === +:; Name: test_switch_config +:; Owner: Brandon Heller +:; Description: verify default switch config, set config, verify that config has changed +:; Status: done + +=== Flow Expired === +:; Name: test_flow_expired +:; Owner: Brandon Heller +:; Description: send add flow message for short timeout, verify no error message received, plus flow timeout message received within time bounds +::send a second add flow message and keep it active with packets; verify that flow expires only if idle + +=== Miss Send Length === +:; Name: test_miss_send_length +:; Owner: Brandon Heller +:; Description: get the miss send length from the hello message, then send a packet to switch, verify correct length for forwarded chunk of packet + +== Modify State Tests == + +=== Forward Any Port === +:; Name: test_forward_any_port +:; Owner: Brandon Heller +:; Description: add a flow mod with all wildcards set, and ensure that all packets get diverted to the specified port. + +=== Forward Exact Port === +:; Name: test_forward_exact_port +:; Owner: Brandon Heller +:; Description: add an exact flow entry, verify a packet is forwarded to the correct port, for all port combinations + +=== Forward Exact ALL === +:; Name: test_forward_exact_all +:; Owner: Brandon Nefcy +:; Description: add an exact flow entry, verify a packet is sent out all ports, for all port combinations +:; Implementation: One packet is sent in to eth0, eth1, eth2, and eth3. An exact match flow entry is set up for each, with the expected action to be flooding the packet out on all ports except the input port. + +=== Forward Exact Controller === +:; Name: test_forward_exact_controller +:; Owner: Brandon Nefcy +:; Description: add an exact flow entry, verify a packet is forwarded to the secure channel +:; Implementation: One packet is sent in on each of eth0, eth1, eth2, and eth3. Test behavior expects to see each packet arrive via the secchan. + +=== Forward Wildcard Port === +:; Name: test_forward_wildcard_port +:; Owner: Brandon Nefcy +:; Description: Test each individual wildcard field. verify a matching packet is forwarded to the correct port, for all port combinations, and a mismatching packet is sent to secchan +:; Implementation: For each possible single-input-port to single-output-port combination flows are set up, one at a time, where each flow is wildcarded on a single field, with enough flows rotated in to test every wildcard field. For each, a matching packet is sent in and expected on the appropriate output port, and a mismatching packet is sent in and expected on the secchan output + +=== Forward Wildcard ALL === +:; Name: test_forward_wildcard_all +:; Owner: Brandon Nefcy +:; Description: same as test_forward_wildcard_port, but instead of sending from one input to one output, sends from one input to all outputs. +:; Implementation: Combination of test_foward_wildcard_port and test_forward_exact_all + +=== Forward Wildcard Controller === +:; Name: test_forward_wildcard_controller +:; Owner: Brandon Nefcy +:; Description: Combination of test_forward_wildcard_port and test_forward_exact_controller. Tests various single wildcard flows where matching packets and mismatching packets are both sent to secchan. +:; Status: Checked in, working, but with limitations as mentioned in test_forward_wildcard_port + +=== Forward After Expiration === +:; Name: test_forward_after_expiration +:; Owner: Brandon Nefcy +:; Description: insert short-lived flow, use it to forward packet, wait until expiration, send packet again, verify nothing received and counters zeroed +:; Implementation: An exact match flow entry is inserted for a specific input port -> output port combination (ie eth0->eth1), a packet is sent to match this entry with the test expecting the appropriate output behavior. The test waits for the flow entry to expire and verifies the expiration via a secchan flow expiration message, then proceeds to re-send the same packet from before, expecting a secchan OFPR_NO_MATCH message. The above is repeated for all combinations of input port -> output port. + +=== Overlapping Flow Entries === +:; Name: test_forward_overlapping_flow_entries +:; Owner: Brandon Nefcy +:; Description: insert both wildcard and exact match flow entries that overlap, verify that the exact match takes precedence +:; Implementation: One packet is sent in on eth0, eth1, eth2, and eth3. Before each packet is sent, two flow entries are set up, one where the entire flow is wildcarded and the action is to send to secchan, and another where the flow is set up to be an exact-match for the packet about to be sent and the action is to flood the packet. The test verifies that the sent packets are flooded out, and no secchan messages are received other than the flows expiring. + +=== Delete === +:; Name: test_delete +:; Owner: Masa +:; Description: insert two flow entries (one wildcard entry and one exact entry where the exact one is covered by the wildcard one). Send packets to verify they are forwarded correctly. Then delete the wildcard entry with DELETE (not strict) -- both the wildcard and the exeact entries should be deleted. To check this, send a packet matching to the exact entry to verify it gets sent to contoller. Re-insert the entry and verify that counters are zeroed. +::; Note -- Counter reading has not been implemented yet so the last part is not verified (5/2/2008) +:; Status: Done (rewritten with clean format) + +=== Delete Strict === +:; Name: test_delete_strict +:; Owner: Masa +:; Description: insert two flow entries (one wildcard entry and one exact entry where the exact one is covered by the wildcard one. The output ports of these two entries are different). Send packets to verify they are forwarded correctly. Then delete the wildcard entry with DELETE_STRICT (not strict) -- only the wildcard entry should be deleted (the exeact entry should not be deleted). To check this, send a packet matching to the exact entry to verify it gets forwarded. +:; Status: Done (rewritten with clean format) + +== Unusual Data == + +=== IP Options === +:; Name: test_ip_options +:; Owner: Masa +:; Description: suggested by Nicira. +::;(1) Create a flow entry that matches to a UDP flow coming from port eth7 (action = forward to port eth8). +::;(2) Send UDP packets with IP time stamp option (ip_hdr_len=7) to port eth7. +::;(3) To see whether the packet comes out from port eth8. +::; As of May 2, 2008, test succeeded. + +=== IP Protocol === +:; Name: test_ip_protocol +:; Owner: Masa +:; Description: +:: Added by Masa +:: see if src/dst port fields are used for matching only for TCP/UDP packets +:: As of May 2, 2008, the result is the following. Even if protocol is not TCP nor UDP, port number fields seems used for matching. Only when protocol number is specified to zero, port number fields are not used for matching.. It seems a strange behavior. +:; Status: Done (rewritten w/ clean format) +:; Note : TCP checksum (in TCP header) is not calculated due to lack of NF2::TCP library (but OF switch won't check it anyway). + +=== IP Offset > Pkt Len === +:; Name: test_ip_offset +:; Owner: Masa +:; Description: +:: possible security risk, shouldn't be an issue +:: suggested by Nicira +:: Create a flow entry. Send several packets matching the entry but whose IP Offset > Pkt Len. Verify all the packets are forwarded to the specified port (specified by the flow entry). + +=== TCP Options === +:; Name: test_tcp_options +:; Owner: Masa +:; Description: +:: See if TCP options affect operation +:: Install a TCP flow entry. Sent a TCP pkt that matches to the installed entry but has TCP option. Verify the packet is forwarded to the specified port. +:; Note : TCP checksum (in TCP header) is not calculated due to lack of NF2::TCP library (but OF switch won't check it anyway). + +=== LLC === +:; Name: test_llc +:; Owner: Masa +:; Description: see LLC packet format; adds 5B to Eth packet +::; Install a flow entry (exact match to an IP flow). Send an IP packet that matches to the installed entry and has the following Ethernet LLC/SNAP header. Verify it is forwarded to the specified port. +:::; Dst MAC (6 byte) +:::; Src MAC (6 byte) +:::; Length (2 byte) = data length from LLC header to the end of IP packet +:::; LLC header (3 byte) = 0xAA 0xAA 0x03 (always this value for IP packets) +:::; SNAP header(5 byte) = OUI(3B)+Type(2B)=0x000000 + 0x0800(IP) (always this value for IP packets) +:::; IP Packet +:; NOTE: It fails (pkt is forwarded to the controller) as of June 11, 2008. + + +Bugs/Shortcomings +----------------- + +- test_llc and test_ip_protocol are not actually run when enabled in a tests.txt file + +Contact +------- + +e-mail: openflow-discuss@openflowswitch.org +www: http://openflowswitch.org/ diff --git a/openflow/regress/bin/eth.map b/openflow/regress/bin/eth.map new file mode 100644 index 00000000..689ad0f0 --- /dev/null +++ b/openflow/regress/bin/eth.map @@ -0,0 +1,8 @@ +eth1:eth1 +eth2:eth2 +eth3:eth3 +eth4:eth4 +eth5:eth5 +eth6:eth6 +eth7:eth7 +eth8:eth8 diff --git a/openflow/regress/bin/nf2.map b/openflow/regress/bin/nf2.map new file mode 100644 index 00000000..797b3896 --- /dev/null +++ b/openflow/regress/bin/nf2.map @@ -0,0 +1,8 @@ +eth1:eth1 +eth2:eth2 +eth3:eth3 +eth4:eth4 +eth5:nf2c0 +eth6:nf2c1 +eth7:nf2c2 +eth8:nf2c3 diff --git a/openflow/regress/bin/of_hp_eth.map b/openflow/regress/bin/of_hp_eth.map new file mode 100644 index 00000000..4f652145 --- /dev/null +++ b/openflow/regress/bin/of_hp_eth.map @@ -0,0 +1,8 @@ +eth1:eth10 +eth2:eth11 +eth3:eth12 +eth4:eth13 +eth5:eth10 +eth6:eth11 +eth7:eth12 +eth8:eth13 diff --git a/openflow/regress/bin/of_hp_setup.pl b/openflow/regress/bin/of_hp_setup.pl new file mode 100755 index 00000000..213376c6 --- /dev/null +++ b/openflow/regress/bin/of_hp_setup.pl @@ -0,0 +1,86 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use OF::OFUtil; +use Test::TestLib; +use Time::HiRes qw(usleep); + +my $mapFile; +my $of_hp_switch_ip; +my $of_hp_vlan; +my $of_hp_controller; +my $of_hp_listener; +my $of_hp_community; + +# Process command line options +# Don't fail on unrecognised options, those failures are tricky +# to diagnose. For example projects/controller_disconnect sets --emerg +# Jean II +Getopt::Long::Configure( 'pass_through' ); +GetOptions( "map=s" => \$mapFile, ); +Getopt::Long::Configure( 'default' ); + +# If not specified on command line, use environment variable. +# Try specific first, then try generic - Jean II +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_HP_MAP_ETH'})) ) { + $mapFile = "$ENV{OFT_HP_MAP_ETH}"; +} +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_MAP_ETH'})) ) { + $mapFile = "$ENV{OFT_MAP_ETH}"; +} + +if ( defined($mapFile) ) { + nftest_process_iface_map($mapFile); +} + +setup_pcap_interfaces(); + +# Get HP switch address and configuration - Jean II +if (defined($ENV{'OFT_HP_SWITCH_IP'})) { + $of_hp_switch_ip = $ENV{'OFT_HP_SWITCH_IP'}; +} else { + $of_hp_switch_ip = "10.10.10.1"; +} +if (defined($ENV{'OFT_HP_VLAN'})) { + $of_hp_vlan = $ENV{'OFT_HP_VLAN'}; +} else { + $of_hp_vlan = 18; +} +if (defined($ENV{'OFT_HP_CONTROLLER'})) { + $of_hp_controller = $ENV{'OFT_HP_CONTROLLER'}; +} else { + my $of_port = get_of_port(); + $of_hp_controller = "tcp:10.10.10.2:$of_port"; +} +if (defined($ENV{'OFT_HP_LISTENER'})) { + # Transform into a passive string + ($proto, $host, $port) = split(/:/,$ENV{'OFT_HP_LISTENER'}); + $of_hp_listener = "p$proto:$port"; +} +if (defined($ENV{'OFT_HP_COMMUNITY'})) { + $of_hp_community = $ENV{'OFT_HP_COMMUNITY'}; +} else { + $of_hp_community = 'public'; +} + + +# disable OpenFlow module to make sure it restarts +`snmpset -v2c -c ${of_hp_community} ${of_hp_switch_ip} iso.org.dod.internet.private.enterprises.11.2.14.11.5.1.7.1.35.1.1.2.${of_hp_vlan} i 2`; + +# Make sure the snmp commands don't coalesce +usleep(200000); + +# set OpenFlow Controller string +`snmpset -v2c -c ${of_hp_community} ${of_hp_switch_ip} iso.org.dod.internet.private.enterprises.11.2.14.11.5.1.7.1.35.1.1.3.${of_hp_vlan} s ${of_hp_controller}`; + +# set OpenFlow Listener string +if (defined($of_hp_listener)) { + `snmpset -v2c -c ${of_hp_community} ${of_hp_switch_ip} iso.org.dod.internet.private.enterprises.11.2.14.11.5.1.7.1.35.1.1.4.${of_hp_vlan} s ${of_hp_listener}`; +} + +# enable OpenFlow module +`snmpset -v2c -c ${of_hp_community} ${of_hp_switch_ip} iso.org.dod.internet.private.enterprises.11.2.14.11.5.1.7.1.35.1.1.2.${of_hp_vlan} i 1`; + +# Starting OpenFlow takes time, give switch a bit of time... +usleep(900000); diff --git a/openflow/regress/bin/of_hp_teardown.pl b/openflow/regress/bin/of_hp_teardown.pl new file mode 100755 index 00000000..0365ce67 --- /dev/null +++ b/openflow/regress/bin/of_hp_teardown.pl @@ -0,0 +1,50 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use OF::OFUtil; +use Test::TestLib; + +my $mapFile; +my $of_hp_switch_ip; +my $of_hp_community; + +# Process command line options +unless ( GetOptions( "map=s" => \$mapFile, ) ) { + print "unrecognized option\n"; + exit 1; +} + +# If not specified on command line, use environment variable. +# Try specific first, then try generic - Jean II +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_HP_MAP_ETH'})) ) { + $mapFile = "$ENV{OFT_HP_MAP_ETH}"; +} +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_MAP_ETH'})) ) { + $mapFile = "$ENV{OFT_MAP_ETH}"; +} + +if ( defined($mapFile) ) { + nftest_process_iface_map($mapFile); +} + +# Get HP switch address - Jean II +if (defined($ENV{'OFT_HP_SWITCH_IP'})) { + $of_hp_switch_ip = $ENV{'OFT_HP_SWITCH_IP'}; +} else { + $of_hp_switch_ip = "10.10.10.1"; +} +if (defined($ENV{'OFT_HP_VLAN'})) { + $of_hp_vlan = $ENV{'OFT_HP_VLAN'}; +} else { + $of_hp_vlan = 18; +} +if (defined($ENV{'OFT_HP_COMMUNITY'})) { + $of_hp_community = $ENV{'OFT_HP_COMMUNITY'}; +} else { + $of_hp_community = 'public'; +} + +# disable OpenFlow module +`snmpset -v2c -c ${of_hp_community} ${of_hp_switch_ip} iso.org.dod.internet.private.enterprises.11.2.14.11.5.1.7.1.35.1.1.2.${of_hp_vlan} i 2`; + diff --git a/openflow/regress/bin/of_hp_test.pl b/openflow/regress/bin/of_hp_test.pl new file mode 100755 index 00000000..d6c3233f --- /dev/null +++ b/openflow/regress/bin/of_hp_test.pl @@ -0,0 +1,62 @@ +#!/usr/bin/perl -w + +############################################################################## +# +# Wrapper for running OpenFlow regression tests against ProCurve 3500/5400 +# Jean Tourrilhes - HP-Labs - copyright 2009-2010 +# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ +# +############################################################################## + +use OF::Base; +use Test::RegressTest; +use strict; +use OF::OFUtil; + +# check vars are set. +check_OF_vars_set(); + +sub INT_Handler { + my $signame = shift; + print "\nNo interrupt handler implemented yet...\n"; + print "\nExited with SIG$signame\n"; + exit(1); +} + +# For the 5406zl and 3500yl... + +# HP switch starts at port 1 == 'A1' or 1 == '1' +# Test need extra delay due to slow controller socket +# Add more idle time due to stat resolution +# byte count is not available - Jean II +push @ARGV, "--root=$ENV{'OFT_ROOT'}", "--common-st-args=hp", "--controller=".$ENV{'OFT_HP_CONTROLLER'}, "--port_base=1", "--send_delay=300000", "--base_idle=2", "--ignore_byte_count"; + +# Use a single random port instead of all four +push @ARGV, "--less_ports"; + +# For QinQ, you will need the premium license... +push @ARGV, "--no_vlan"; + +# The hardware can not support slicing +push @ARGV, "--no_slicing"; + +# The hardware can not support barrier +push @ARGV, "--no_barrier"; + +# The hardware can not support emergency flow table +push @ARGV, "--no_emerg"; + +# Check for listener +if ( defined($ENV{'OFT_HP_LISTENER'}) ) { + push @ARGV, "--listener=$ENV{OFT_HP_LISTENER}"; +} + +# Check for specific MAP file... +if ( defined($ENV{'OFT_HP_MAP_ETH'}) ) { + push @ARGV, "--map=$ENV{OFT_HP_MAP_ETH}"; +} + +# Other configuration is through Environment Variables, See of_hp_setup.pl +# Jean II + +run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_hp_test_6600.pl b/openflow/regress/bin/of_hp_test_6600.pl new file mode 100755 index 00000000..e141def5 --- /dev/null +++ b/openflow/regress/bin/of_hp_test_6600.pl @@ -0,0 +1,62 @@ +#!/usr/bin/perl -w + +############################################################################## +# +# Wrapper for running OpenFlow regression tests against ProCurve 6600 +# Jean Tourrilhes - HP-Labs - copyright 2009-2010 +# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ +# +############################################################################## + +use OF::Base; +use Test::RegressTest; +use strict; +use OF::OFUtil; + +# check vars are set. +check_OF_vars_set(); + +sub INT_Handler { + my $signame = shift; + print "\nNo interrupt handler implemented yet...\n"; + print "\nExited with SIG$signame\n"; + exit(1); +} + +# For the 6600... + +# HP switch starts at port 25 == '1' +# Test need extra delay due to slow controller socket +# Add more idle time due to stat resolution +# byte count is not available - Jean II +push @ARGV, "--root=$ENV{'OFT_ROOT'}", "--common-st-args=hp", "--controller=".$ENV{'OFT_HP_CONTROLLER'}, "--port_base=25", "--send_delay=650000", "--base_idle=3", "--ignore_byte_count"; + +# Use a single random port instead of all four +push @ARGV, "--less_ports"; + +# For QinQ, you will need the premium license... +push @ARGV, "--no_vlan"; + +# The hardware can not support slicing +push @ARGV, "--no_slicing"; + +# The hardware can not support barrier +push @ARGV, "--no_barrier"; + +# The hardware can not support emergency flow table +push @ARGV, "--no_emerg"; + +# Check for listener +if ( defined($ENV{'OFT_HP_LISTENER'}) ) { + push @ARGV, "--listener=$ENV{OFT_HP_LISTENER}"; +} + +# Check for specific MAP file... +if ( defined($ENV{'OFT_HP_MAP_ETH'}) ) { + push @ARGV, "--map=$ENV{OFT_HP_MAP_ETH}"; +} + +# Other configuration is through Environment Variables, See of_hp_setup.pl +# Jean II + +run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_kmod_setup.pl b/openflow/regress/bin/of_kmod_setup.pl new file mode 100755 index 00000000..fc3ef4ba --- /dev/null +++ b/openflow/regress/bin/of_kmod_setup.pl @@ -0,0 +1,22 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use OF::OFUtil; +use Test::TestLib; + +my $mapFile, $controller; + +# Process command line options +unless ( GetOptions( "map=s" => \$mapFile, + "emerg" => \$emerg, + "controller=s", \$controller) ) { + print "unrecognized option\n"; + exit 1; +} + +if ( defined($mapFile) ) { + nftest_process_iface_map($mapFile); +} + +setup_kmod($controller, $emerg); diff --git a/openflow/regress/bin/of_kmod_teardown.pl b/openflow/regress/bin/of_kmod_teardown.pl new file mode 100755 index 00000000..4fa7dbfa --- /dev/null +++ b/openflow/regress/bin/of_kmod_teardown.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use OF::OFUtil; +use Test::TestLib; + +my $mapFile; + +# Process command line options +unless ( GetOptions( "map=s" => \$mapFile, ) ) { + print "unrecognized option\n"; + exit 1; +} + +if ( defined($mapFile) ) { + nftest_process_iface_map($mapFile); +} + +teardown_kmod(); diff --git a/openflow/regress/bin/of_kmod_test.pl b/openflow/regress/bin/of_kmod_test.pl new file mode 100755 index 00000000..6ce99411 --- /dev/null +++ b/openflow/regress/bin/of_kmod_test.pl @@ -0,0 +1,27 @@ +#!/usr/bin/perl -w + +############################################################################## +# +# Wrapper for OpenFlow regression tests +# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ +# +############################################################################## + +use OF::Base; +use Test::RegressTest; +use strict; +use OF::OFUtil; + +# check vars are set. +check_OF_vars_set(); + +sub INT_Handler { + my $signame = shift; + print "\nNo interrupt handler implemented yet...\n"; + print "\nExited with SIG$signame\n"; + exit(1); +} + +push (@ARGV, "--root=$ENV{'OFT_ROOT'}", "--map=$ENV{'OFT_ROOT'}/bin/eth.map", "--port_base=1", "--common-st-args=kmod"); + +run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_kmod_veth_setup.pl b/openflow/regress/bin/of_kmod_veth_setup.pl new file mode 100755 index 00000000..79a37733 --- /dev/null +++ b/openflow/regress/bin/of_kmod_veth_setup.pl @@ -0,0 +1,26 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use OF::OFUtil; +use Test::TestLib; + +my ($mapFile, $controller); + +# Process command line options +unless ( GetOptions( "map=s" => \$mapFile, + "emerg" => \$emerg, + "controller=s", \$controller) ) { + print "unrecognized option\n"; + exit 1; +} + +if ( defined($mapFile) ) { + nftest_process_iface_map($mapFile); +} +#else, use pre-defined veth map +else { + nftest_process_iface_map("$ENV{'OFT_ROOT'}/bin/veth.map"); +} + +setup_kmod($controller, $emerg); diff --git a/openflow/regress/bin/of_kmod_veth_teardown.pl b/openflow/regress/bin/of_kmod_veth_teardown.pl new file mode 100755 index 00000000..52b57927 --- /dev/null +++ b/openflow/regress/bin/of_kmod_veth_teardown.pl @@ -0,0 +1,24 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use OF::OFUtil; +use Test::TestLib; + +my $mapFile; + +# Process command line options +unless ( GetOptions( "map=s" => \$mapFile, ) ) { + print "unrecognized option\n"; + exit 1; +} + +if ( defined($mapFile) ) { + nftest_process_iface_map($mapFile); +} +#else, use pre-defined veth map +else { + nftest_process_iface_map("$ENV{'OFT_ROOT'}/bin/veth.map"); +} + +teardown_kmod(); diff --git a/openflow/regress/bin/of_kmod_veth_test.pl b/openflow/regress/bin/of_kmod_veth_test.pl new file mode 100755 index 00000000..0f08edbb --- /dev/null +++ b/openflow/regress/bin/of_kmod_veth_test.pl @@ -0,0 +1,27 @@ +#!/usr/bin/perl -w + +############################################################################## +# +# Wrapper for OpenFlow regression tests +# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ +# +############################################################################## + +use OF::Base; +use Test::RegressTest; +use strict; +use OF::OFUtil; + +# check vars are set. +check_OF_vars_set(); + +sub INT_Handler { + my $signame = shift; + print "\nNo interrupt handler implemented yet...\n"; + print "\nExited with SIG$signame\n"; + exit(1); +} + +push (@ARGV, "--map=$ENV{'OFT_ROOT'}/bin/veth.map", "--root=$ENV{'OFT_ROOT'}", "--port_base=1", "--common-st-args=kmod_veth"); + +run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_nf2_setup.pl b/openflow/regress/bin/of_nf2_setup.pl new file mode 100755 index 00000000..34fe3351 --- /dev/null +++ b/openflow/regress/bin/of_nf2_setup.pl @@ -0,0 +1,26 @@ +#!/usr/bin/perl -w + +use Getopt::Long; +use Data::Dumper; + +use OF::OFUtil; +use Test::TestLib; + +my ($mapFile, $controller); + +print "Calling of_nf2_setup.pl\n"; +print Dumper(@ARGV) . "\n"; + +# Process command line options +unless ( GetOptions( "map=s" => \$mapFile, + "emerg" => \$emerg, + "controller=s", \$controller) ) { + print "unrecognized option\n"; + exit 1; +} + +if ( defined($mapFile) ) { + nftest_process_iface_map($mapFile); +} + +setup_NF2($controller, $emerg); diff --git a/openflow/regress/bin/of_nf2_teardown.pl b/openflow/regress/bin/of_nf2_teardown.pl new file mode 100755 index 00000000..286a87cf --- /dev/null +++ b/openflow/regress/bin/of_nf2_teardown.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use OF::OFUtil; +use Test::TestLib; + +my $mapFile; + +# Process command line options +unless ( GetOptions( "map=s" => \$mapFile, ) ) { + print "unrecognized option\n"; + exit 1; +} + +if ( defined($mapFile) ) { + nftest_process_iface_map($mapFile); +} + +teardown_NF2(); diff --git a/openflow/regress/bin/of_nf2_test.pl b/openflow/regress/bin/of_nf2_test.pl new file mode 100755 index 00000000..0704e99a --- /dev/null +++ b/openflow/regress/bin/of_nf2_test.pl @@ -0,0 +1,28 @@ +#!/usr/bin/perl -w + +############################################################################## +# +# Wrapper for OpenFlow regression tests +# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ +# +############################################################################## + +use OF::Base; +use Test::RegressTest; +use strict; +use OF::OFUtil; + +# check vars are set. +check_OF_vars_set(); + +sub INT_Handler { + my $signame = shift; + print "\nNo interrupt handler implemented yet...\n"; + print "\nExited with SIG$signame\n"; + exit(1); +} + +push (@ARGV, "--root=$ENV{'OFT_ROOT'}", "--map=$ENV{'OFT_ROOT'}/bin/nf2.map", "--port_base=1", "--common-st-args=nf2"); +push @ARGV, "--no_slicing"; + +run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_ovs_eth.map b/openflow/regress/bin/of_ovs_eth.map new file mode 100644 index 00000000..120ee51d --- /dev/null +++ b/openflow/regress/bin/of_ovs_eth.map @@ -0,0 +1,8 @@ +eth1:eth10.91 +eth2:eth10.92 +eth3:eth10.93 +eth4:eth10.94 +eth5:eth11.91 +eth6:eth11.92 +eth7:eth11.93 +eth8:eth11.94 diff --git a/openflow/regress/bin/of_ovs_setup.pl b/openflow/regress/bin/of_ovs_setup.pl new file mode 100755 index 00000000..ca2cc93f --- /dev/null +++ b/openflow/regress/bin/of_ovs_setup.pl @@ -0,0 +1,76 @@ +#!/usr/bin/perl -w +# Jean Tourrilhes - HP-Labs + +use Getopt::Long; + +use OF::OFUtil; +use Test::TestLib; + +my $mapFile; + +# The map file is necessary. It assing the real interface to the +# fictious names used by the test suite. +# eth1->eth4 are capture interfaces used to send/receive probe packets +# eth5->eth8 are configured to run the OpenFlow switch +# Jean II + +# Process command line options +# Don't fail on unrecognised options, those failures are tricky +# to diagnose. For example projects/controller_disconnect sets --emerg +# Jean II +Getopt::Long::Configure( 'pass_through' ); +GetOptions( "map=s" => \$mapFile, ); +Getopt::Long::Configure( 'default' ); + +# If not specified on command line, use enviroment variable. +# Try specific first, then try generic - Jean II +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_OVS_MAP_ETH'})) ) { + $mapFile = "$ENV{OFT_OVS_MAP_ETH}"; +} +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_MAP_ETH'})) ) { + $mapFile = "$ENV{OFT_MAP_ETH}"; +} + +# Set up the mappings +if ( defined($mapFile) ) { + nftest_process_iface_map($mapFile); +} + +# Debug... +#for ( my $i = 1 ; $i <= 8 ; $i++ ) { +# my $iface = nftest_get_iface("eth$i"); +# print "iface($i) = $iface\n"; +#} + +# Start capturing on eth1->eth4 +setup_pcap_interfaces(); + +# Get the directly where Open vSwitch resides +my $ovs_dir = $ENV{'OFT_OVS_ROOT'}; +my $of_port = get_of_port(); + +# Setup the kernel module +`insmod ${ovs_dir}/datapath/linux-2.6/openvswitch_mod.ko`; +`${ovs_dir}/utilities/ovs-dpctl add-dp dp0`; + +# Not needed after 0.99.2 +#for ( my $i = 5 ; $i <= 8 ; $i++ ) { +# my $iface = nftest_get_iface("eth$i"); +# `${ovs_dir}/utilities/ovs-dpctl add-if dp0 $iface`; +#} + +# create command line arguments containing all four ports +my $if_string = ''; +for ( my $i = 5 ; $i <= 7 ; $i++ ) { + $if_string .= nftest_get_iface("eth$i") . ','; +} +$if_string .= nftest_get_iface("eth8"); + +# create Open vSwitch openflow switch on four ports eth5->eth9 +system("${ovs_dir}/utilities/ovs-openflowd dp0 --ports=${if_string} tcp:127.0.0.1:${of_port} --listen=ptcp:6634 --fail=closed --inactivity-probe=999999 &"); + +# For 0.99.0, you'll need to manually add ports as above +#system("${ovs_dir}/utilities/ovs-openflowd dp0 tcp:127.0.0.1:${of_port} --listen=ptcp:6634 --fail=closed --inactivity-probe=999999 &"); + +# Up to 0.90.6, you would use secchan, after that you need to use ovs-openflowd +#system("${ovs_dir}/secchan/secchan dp0 tcp:127.0.0.1:${of_port} --listen=ptcp:6634 --fail=closed --inactivity-probe=999999 &"); diff --git a/openflow/regress/bin/of_ovs_teardown.pl b/openflow/regress/bin/of_ovs_teardown.pl new file mode 100755 index 00000000..303eb4ad --- /dev/null +++ b/openflow/regress/bin/of_ovs_teardown.pl @@ -0,0 +1,59 @@ +#!/usr/bin/perl -w +# Jean Tourrilhes - HP-Labs + +use Getopt::Long; + +use OF::OFUtil; +use Test::TestLib; + +my $mapFile; + +# Process command line options +unless ( GetOptions( "map=s" => \$mapFile, ) ) { + print "unrecognized option\n"; + exit 1; +} + +# If not specified on command line, use enviroment variable. +# Try specific first, then try generic - Jean II +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_OVS_MAP_ETH'})) ) { + $mapFile = "$ENV{OFT_OVS_MAP_ETH}"; +} +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_MAP_ETH'})) ) { + $mapFile = "$ENV{OFT_MAP_ETH}"; +} + +if ( defined($mapFile) ) { + nftest_process_iface_map($mapFile); +} + +# Get the directly where Open vSwitch resides +my $ovs_dir = $ENV{'OFT_OVS_ROOT'}; + +# Start by killing secchan or ovs-openflowd +`killall secchan`; +`killall ovs-openflowd`; + +# check if openflow kernel module loaded +my $of_kmod_loaded = `lsmod | grep openvswitch_mod`; +if ( $of_kmod_loaded eq "" ) { exit 0; } + +print "tearing down interfaces and datapaths\n"; + +# remove interfaces from openflow +for ( my $i = 5 ; $i <= 8 ; $i++ ) { + my $iface = nftest_get_iface("eth$i"); + `${ovs_dir}/utilities/ovs-dpctl del-if dp0 $iface`; +} + +`${ovs_dir}/utilities/ovs-dpctl del-dp dp0`; + +my $of_kmod_removed = `rmmod openvswitch_mod`; +if ( $of_kmod_removed ne "" ) { + die "failed to remove kernel module... please fix!\n"; +} + +$of_kmod_loaded = `lsmod | grep openvswitch_mod`; +if ( $of_kmod_loaded ne "" ) { + die "failed to remove kernel module... please fix!\n"; +} diff --git a/openflow/regress/bin/of_ovs_test.pl b/openflow/regress/bin/of_ovs_test.pl new file mode 100755 index 00000000..a842aa64 --- /dev/null +++ b/openflow/regress/bin/of_ovs_test.pl @@ -0,0 +1,54 @@ +#!/usr/bin/perl -w + +############################################################################## +# +# Wrapper for running OpenFlow regression tests against Open vSwitch +# Jean Tourrilhes - HP-Labs - copyright 2009-2010 +# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ +# +############################################################################## + +use OF::Base; +use Test::RegressTest; +use strict; +use OF::OFUtil; + +# check vars are set. +check_OF_vars_set(); + +sub INT_Handler { + my $signame = shift; + print "\nNo interrupt handler implemented yet...\n"; + print "\nExited with SIG$signame\n"; + exit(1); +} + +# For Open vSwitch + +# Open vSwitch starts at port 1 +# Get a bit of speedup by tweaking send_delay and base_idle +# Jean II +my $of_port = get_of_port(); +push @ARGV, "--root=$ENV{'OFT_ROOT'}", "--common-st-args=ovs", "--controller=tcp:localhost:$of_port,tcp:localhost:$of_port", "--listener=tcp:127.0.0.1:6634", "--port_base=1", "--send_delay=2000", "--base_idle=2"; + +# Use a single random port instead of all four +push @ARGV, "--less_ports"; + +# Don't bother with VLAN if we go outside the box, too many issues... +#push @ARGV, "--no_vlan"; + +# Don't bother with QoS currently, it's broken... +push @ARGV, "--no_slicing"; + +# The bother with emergency flow table tests, it's not supported... +push @ARGV, "--no_emerg"; + +# Don't forget to configure the OVS_ROOT environment variable +# Jean II + +# Check for specific MAP file... +if ( defined($ENV{'OFT_OVS_MAP_ETH'}) ) { + push @ARGV, "--map=$ENV{OFT_OVS_MAP_ETH}"; +} + +run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_ovs_user_setup.pl b/openflow/regress/bin/of_ovs_user_setup.pl new file mode 100755 index 00000000..aa31cff6 --- /dev/null +++ b/openflow/regress/bin/of_ovs_user_setup.pl @@ -0,0 +1,60 @@ +#!/usr/bin/perl -w +# Jean Tourrilhes - HP-Labs + +use Getopt::Long; + +use OF::OFUtil; +use Test::TestLib; + +my $mapFile; + +# The map file is necessary. It assing the real interface to the +# fictious names used by the test suite. +# eth1->eth4 are capture interfaces used to send/receive probe packets +# eth5->eth8 are configured to run the OpenFlow switch +# Jean II + +# Process command line options +# Don't fail on unrecognised options, those failures are tricky +# to diagnose. For example projects/controller_disconnect sets --emerg +# Jean II +Getopt::Long::Configure( 'pass_through' ); +GetOptions( "map=s" => \$mapFile, ); +Getopt::Long::Configure( 'default' ); + +# If not specified on command line, use enviroment variable. +# Try specific first, then try generic - Jean II +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_OVS_MAP_ETH'})) ) { + $mapFile = "$ENV{OFT_OVS_MAP_ETH}"; +} +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_MAP_ETH'})) ) { + $mapFile = "$ENV{OFT_MAP_ETH}"; +} + +# Set up the mappings +if ( defined($mapFile) ) { + nftest_process_iface_map($mapFile); +} + +# Debug... +#for ( my $i = 1 ; $i <= 8 ; $i++ ) { +# my $iface = nftest_get_iface("eth$i"); +# print "iface($i) = $iface\n"; +#} + +# Start capturing on eth1->eth4 +setup_pcap_interfaces(); + +# Get the directly where Open vSwitch resides +my $ovs_dir = $ENV{'OFT_OVS_ROOT'}; +my $of_port = get_of_port(); + +# create command line arguments containing all four ports +my $if_string = ''; +for ( my $i = 5 ; $i <= 7 ; $i++ ) { + $if_string .= nftest_get_iface("eth$i") . ','; +} +$if_string .= nftest_get_iface("eth8"); + +# create userspace Open vSwitch openflow switch on four ports +system("${ovs_dir}/utilities/ovs-openflowd netdev\@br0 --ports=${if_string} tcp:127.0.0.1:${of_port} --listen=ptcp:6634 --fail=closed --inactivity-probe=999999 &"); diff --git a/openflow/regress/bin/of_ovs_user_teardown.pl b/openflow/regress/bin/of_ovs_user_teardown.pl new file mode 100755 index 00000000..81124624 --- /dev/null +++ b/openflow/regress/bin/of_ovs_user_teardown.pl @@ -0,0 +1,34 @@ +#!/usr/bin/perl -w +# Jean Tourrilhes - HP-Labs + +use Getopt::Long; + +use OF::OFUtil; +use Test::TestLib; + +my $mapFile; + +# Process command line options +unless ( GetOptions( "map=s" => \$mapFile, ) ) { + print "unrecognized option\n"; + exit 1; +} + +# If not specified on command line, use enviroment variable. +# Try specific first, then try generic - Jean II +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_OVS_MAP_ETH'})) ) { + $mapFile = "$ENV{OFT_OVS_MAP_ETH}"; +} +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_MAP_ETH'})) ) { + $mapFile = "$ENV{OFT_MAP_ETH}"; +} + +if ( defined($mapFile) ) { + nftest_process_iface_map($mapFile); +} + +# Get the directly where Open vSwitch resides +my $ovs_dir = $ENV{'OFT_OVS_ROOT'}; + +# Just kill ovs-openflowd +`killall ovs-openflowd`; diff --git a/openflow/regress/bin/of_ovs_user_test.pl b/openflow/regress/bin/of_ovs_user_test.pl new file mode 100755 index 00000000..e726e556 --- /dev/null +++ b/openflow/regress/bin/of_ovs_user_test.pl @@ -0,0 +1,50 @@ +#!/usr/bin/perl -w + +############################################################################## +# +# Wrapper for OpenFlow regression tests +# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ +# +############################################################################## + +use OF::Base; +use Test::RegressTest; +use strict; +use OF::OFUtil; + +# check vars are set. +check_OF_vars_set(); + +sub INT_Handler { + my $signame = shift; + print "\nNo interrupt handler implemented yet...\n"; + print "\nExited with SIG$signame\n"; + exit(1); +} + +# For Open vSwitch + +# Open vSwitch starts at port 1 +# Get a bit of speedup by tweaking send_delay and base_idle +# Jean II +my $of_port = get_of_port(); +push @ARGV, "--root=$ENV{'OFT_ROOT'}", "--common-st-args=ovs_user", "--controller=tcp:localhost:$of_port,tcp:localhost:$of_port", "--listener=tcp:127.0.0.1:6634", "--port_base=1", "--send_delay=2000", "--base_idle=2"; + +# Use a single random port instead of all four +push @ARGV, "--less_ports"; + +# Don't bother with QoS currently, it's broken... +push @ARGV, "--no_slicing"; + +# The bother with emergency flow table tests, it's not supported... +push @ARGV, "--no_emerg"; + +# Don't forget to configure the OVS_ROOT environment variable +# Jean II + +# Check for specific MAP file... +if ( defined($ENV{'OFT_OVS_MAP_ETH'}) ) { + push @ARGV, "--map=$ENV{OFT_OVS_MAP_ETH}"; +} + +run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_ovs_user_veth_test.pl b/openflow/regress/bin/of_ovs_user_veth_test.pl new file mode 100755 index 00000000..93a7a5df --- /dev/null +++ b/openflow/regress/bin/of_ovs_user_veth_test.pl @@ -0,0 +1,47 @@ +#!/usr/bin/perl -w + +############################################################################## +# +# Wrapper for running OpenFlow regression tests against Open vSwitch +# using veth +# Jean Tourrilhes - HP-Labs - copyright 2009-2010 +# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ +# +############################################################################## + +use OF::Base; +use Test::RegressTest; +use strict; +use OF::OFUtil; + +# check vars are set. +check_OF_vars_set(); + +sub INT_Handler { + my $signame = shift; + print "\nNo interrupt handler implemented yet...\n"; + print "\nExited with SIG$signame\n"; + exit(1); +} + +# For Open vSwitch + +# Open vSwitch starts at port 1 +# Get a bit of speedup by tweaking send_delay and base_idle +# Jean II +my $of_port = get_of_port(); +push @ARGV, "--root=$ENV{'OFT_ROOT'}", "--common-st-args=ovs_user", "--controller=tcp:localhost:$of_port,tcp:localhost:$of_port", "--listener=tcp:127.0.0.1:6634", "--port_base=1", "--send_delay=2000", "--base_idle=2", "--map=$ENV{'OFT_ROOT'}/bin/veth.map"; + +# Use a single random port instead of all four +push @ARGV, "--less_ports"; + +# Don't bother with QoS currently, it's broken... +push @ARGV, "--no_slicing"; + +# The bother with emergency flow table tests, it's not supported... +push @ARGV, "--no_emerg"; + +# Don't forget to configure the OVS_ROOT environment variable +# Jean II + +run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_ovs_veth_test.pl b/openflow/regress/bin/of_ovs_veth_test.pl new file mode 100755 index 00000000..4f09714a --- /dev/null +++ b/openflow/regress/bin/of_ovs_veth_test.pl @@ -0,0 +1,47 @@ +#!/usr/bin/perl -w + +############################################################################## +# +# Wrapper for running OpenFlow regression tests against Open vSwitch +# using veth +# Jean Tourrilhes - HP-Labs - copyright 2009-2010 +# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ +# +############################################################################## + +use OF::Base; +use Test::RegressTest; +use strict; +use OF::OFUtil; + +# check vars are set. +check_OF_vars_set(); + +sub INT_Handler { + my $signame = shift; + print "\nNo interrupt handler implemented yet...\n"; + print "\nExited with SIG$signame\n"; + exit(1); +} + +# For Open vSwitch + +# Open vSwitch starts at port 1 +# Get a bit of speedup by tweaking send_delay and base_idle +# Jean II +my $of_port = get_of_port(); +push @ARGV, "--root=$ENV{'OFT_ROOT'}", "--common-st-args=ovs", "--controller=tcp:localhost:$of_port,tcp:localhost:$of_port", "--listener=tcp:127.0.0.1:6634", "--port_base=1", "--send_delay=2000", "--base_idle=2", "--map=$ENV{'OFT_ROOT'}/bin/veth.map"; + +# Use a single random port instead of all four +push @ARGV, "--less_ports"; + +# Don't bother with QoS currently, it's broken... +push @ARGV, "--no_slicing"; + +# The bother with emergency flow table tests, it's not supported... +push @ARGV, "--no_emerg"; + +# Don't forget to configure the OVS_ROOT environment variable +# Jean II + +run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_user_setup.pl b/openflow/regress/bin/of_user_setup.pl new file mode 100755 index 00000000..5ff86039 --- /dev/null +++ b/openflow/regress/bin/of_user_setup.pl @@ -0,0 +1,22 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use OF::OFUtil; +use Test::TestLib; + +my ($mapFile, $controller); + +# Process command line options +unless ( GetOptions( "map=s" => \$mapFile, + "emerg" => \$emerg, + "controller=s", \$controller) ) { + print "unrecognized option\n"; + exit 1; +} + +if ( defined($mapFile) ) { + nftest_process_iface_map($mapFile); +} + +setup_user($controller, $emerg); diff --git a/openflow/regress/bin/of_user_teardown.pl b/openflow/regress/bin/of_user_teardown.pl new file mode 100755 index 00000000..760d7e25 --- /dev/null +++ b/openflow/regress/bin/of_user_teardown.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use OF::OFUtil; +use Test::TestLib; + +my $mapFile; + +# Process command line options +unless ( GetOptions( "map=s" => \$mapFile, ) ) { + print "unrecognized option\n"; + exit 1; +} + +if ( defined($mapFile) ) { + nftest_process_iface_map($mapFile); +} + +teardown_user(); diff --git a/openflow/regress/bin/of_user_test.pl b/openflow/regress/bin/of_user_test.pl new file mode 100755 index 00000000..1fb19ea0 --- /dev/null +++ b/openflow/regress/bin/of_user_test.pl @@ -0,0 +1,27 @@ +#!/usr/bin/perl -w + +############################################################################## +# +# Wrapper for OpenFlow regression tests +# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ +# +############################################################################## + +use OF::Base; +use Test::RegressTest; +use strict; +use OF::OFUtil; + +# check vars are set. +check_OF_vars_set(); + +sub INT_Handler { + my $signame = shift; + print "\nNo interrupt handler implemented yet...\n"; + print "\nExited with SIG$signame\n"; + exit(1); +} + +push (@ARGV, "--root=$ENV{'OFT_ROOT'}", "--map=$ENV{'OFT_ROOT'}/bin/eth.map", "--port_base=1", "--common-st-args=user"); + +run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_user_veth_setup.pl b/openflow/regress/bin/of_user_veth_setup.pl new file mode 100755 index 00000000..d5ae5edc --- /dev/null +++ b/openflow/regress/bin/of_user_veth_setup.pl @@ -0,0 +1,26 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use OF::OFUtil; +use Test::TestLib; + +my ($mapFile, $controller); + +# Process command line options +unless ( GetOptions( "map=s" => \$mapFile, + "emerg" => \$emerg, + "controller=s", \$controller) ) { + print "unrecognized option\n"; + exit 1; +} + +if ( defined($mapFile) ) { + nftest_process_iface_map($mapFile); +} +#else, use pre-defined veth map +else { + nftest_process_iface_map("$ENV{'OFT_ROOT'}/bin/veth.map"); +} + +setup_user($controller, $emerg); diff --git a/openflow/regress/bin/of_user_veth_teardown.pl b/openflow/regress/bin/of_user_veth_teardown.pl new file mode 100755 index 00000000..7d14c89c --- /dev/null +++ b/openflow/regress/bin/of_user_veth_teardown.pl @@ -0,0 +1,24 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use OF::OFUtil; +use Test::TestLib; + +my $mapFile; + +# Process command line options +unless ( GetOptions( "map=s" => \$mapFile, ) ) { + print "unrecognized option\n"; + exit 1; +} + +if ( defined($mapFile) ) { + nftest_process_iface_map($mapFile); +} +#else, use pre-defined veth map +else { + nftest_process_iface_map("$ENV{'OFT_ROOT'}/bin/veth.map"); +} + +teardown_user(); diff --git a/openflow/regress/bin/of_user_veth_test.pl b/openflow/regress/bin/of_user_veth_test.pl new file mode 100755 index 00000000..63551f98 --- /dev/null +++ b/openflow/regress/bin/of_user_veth_test.pl @@ -0,0 +1,27 @@ +#!/usr/bin/perl -w + +############################################################################## +# +# Wrapper for OpenFlow regression tests +# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ +# +############################################################################## + +use OF::Base; +use Test::RegressTest; +use strict; +use OF::OFUtil; + +# check vars are set. +check_OF_vars_set(); + +sub INT_Handler { + my $signame = shift; + print "\nNo interrupt handler implemented yet...\n"; + print "\nExited with SIG$signame\n"; + exit(1); +} + +push( @ARGV, "--map=$ENV{'OFT_ROOT'}/bin/veth.map", "--root=$ENV{'OFT_ROOT'}", "--port_base=1", "--common-st-args=user_veth"); + +run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/veth.map b/openflow/regress/bin/veth.map new file mode 100644 index 00000000..bb1c1b09 --- /dev/null +++ b/openflow/regress/bin/veth.map @@ -0,0 +1,8 @@ +eth1:veth0 +eth2:veth2 +eth3:veth4 +eth4:veth6 +eth5:veth1 +eth6:veth3 +eth7:veth5 +eth8:veth7 diff --git a/openflow/regress/bin/veth_setup.pl b/openflow/regress/bin/veth_setup.pl new file mode 100755 index 00000000..11e746e8 --- /dev/null +++ b/openflow/regress/bin/veth_setup.pl @@ -0,0 +1,10 @@ +#!/usr/bin/perl -w + +`/sbin/modprobe veth`; +for (my $i = 0; $i < 4; $i++) { + `/sbin/ip link add type veth`; +} + +for (my $i = 0; $i < 8; $i++) { + `sudo /sbin/ifconfig veth$i 192.168.1$i.1 netmask 255.255.255.0`; +} diff --git a/openflow/regress/bin/veth_teardown.pl b/openflow/regress/bin/veth_teardown.pl new file mode 100755 index 00000000..ad103756 --- /dev/null +++ b/openflow/regress/bin/veth_teardown.pl @@ -0,0 +1,4 @@ +#!/usr/bin/perl -w + +`/sbin/rmmod veth`; + diff --git a/openflow/regress/projects/black_box/regress/common/setup b/openflow/regress/projects/black_box/regress/common/setup new file mode 100755 index 00000000..8836cf7b --- /dev/null +++ b/openflow/regress/projects/black_box/regress/common/setup @@ -0,0 +1,47 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use Test::TestLib; +use OF::OFUtil; + +my $mapFile; +my $platform; +my $args; + +# Process command line options +unless ( + GetOptions ( + "map=s" => \$mapFile, + "common-st-args=s" => \$platform, + ) +) +{ + print "invalid command format\n"; + exit(1); +} + +if (defined($mapFile)) { + $args = "--map=$mapFile"; +} + +if (!defined($platform)) { + print "no platform defined\n"; + exit(1); +} +else { + print "platform = $platform\n"; +} + +my $filename = "of_${platform}_setup.pl"; + +# exit if of_${platform}_setup.pl not in path +if (-e "$ENV{'OFT_ROOT'}/bin/$filename") { + #system("$filename " . $args . " 2> /dev/null > /dev/null"); + system("$ENV{'OFT_ROOT'}/bin/$filename " . $args ); + #setup_kmod(); + exit (0); +} else { + print "couldn't find setup file $filename\n"; + exit (1); +} diff --git a/openflow/regress/projects/black_box/regress/common/teardown b/openflow/regress/projects/black_box/regress/common/teardown new file mode 100755 index 00000000..6f1f8391 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/common/teardown @@ -0,0 +1,47 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use Test::TestLib; +use OF::OFUtil; + +my $mapFile; +my $platform; +my $args; + +# Process command line options +unless ( + GetOptions ( + "map=s" => \$mapFile, + "common-st-args=s" => \$platform, + ) +) +{ + print "invalid command format\n"; + exit(1); +} + +if (defined($mapFile)) { + $args = "--map=$mapFile"; +} + +if (!defined($platform)) { + print "no platform defined\n"; + exit(1); +} +else { + print "platform = $platform\n"; +} + +my $filename = "of_${platform}_teardown.pl"; + +# exit if of_${platform}_setup.pl not in path +if (-e "$ENV{'OFT_ROOT'}/bin/$filename") { + #system("$filename " . $args . " 2> /dev/null > /dev/null"); + system("$ENV{'OFT_ROOT'}/bin/$filename " . $args ); + #teardown_kmod(); + exit (0); +} else { + print "couldn't find setup file $filename\n"; + exit (1); +} diff --git a/openflow/regress/projects/black_box/regress/test_add_flow_latency/run.pl b/openflow/regress/projects/black_box/regress/test_add_flow_latency/run.pl new file mode 100755 index 00000000..91ec09af --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_add_flow_latency/run.pl @@ -0,0 +1,47 @@ +#!/usr/bin/perl -w +# test_add_flow_latency + +use strict; +use OF::Includes; + +sub my_test { + + my ($sock) = @_; + + my $pkt_args = { + DA => "00:00:00:00:00:01", + SA => "00:00:00:00:00:02", + src_ip => "192.168.200.40", + dst_ip => "192.168.201.40", + ttl => 64, + len => 60 + }; + + my $test_pkt = new NF2::UDP_pkt(%$pkt_args); + + my $wildcards = 0x0; + my $in_port = 1; + my $out_port = 2; + my $max_idle = 0; + my $flags = 0x0; # don't send flow expiry + + my $flow_mod_pkt = create_flow_mod_from_udp($ofp,$test_pkt,$in_port,$out_port,$max_idle,$flags,$wildcards); + + print $sock $flow_mod_pkt; + usleep(1000000); + + + my $cnt = 0; + my $start_time = [gettimeofday()]; + for( $cnt = 0;$cnt < 1000; $cnt++){ + nftest_send( nftest_get_iface( "eth" . ($in_port+1)),$test_pkt->packed ); + nftest_expect( nftest_get_iface( "eth" . ($out_port+1)),$test_pkt->packed ); + } + my $time_elapse = tv_interval($start_time); + my $latency = $time_elapse*1000/1000; + print "Latency is $latency ms"; + + } + + +run_black_box_test( \&my_test); diff --git a/openflow/regress/projects/black_box/regress/test_barrier/run.pl b/openflow/regress/projects/black_box/regress/test_barrier/run.pl new file mode 100755 index 00000000..87b91153 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_barrier/run.pl @@ -0,0 +1,52 @@ +#!/usr/bin/perl -w +# test_barrier + +use strict; +use OF::Includes; + +sub my_test { + my ($sock, $options_ref) = @_; + + if ( not defined( $$options_ref{'no_barrier'} ) ) { + my $in_port = $$options_ref{'port_base'}; + my $out_port = $in_port + 1; + + # RUOK? + send_get_config_request($ofp, $sock, 0xdeadbeef); + wait_for_get_config_reply($ofp, $sock, 0xdeadbeef); + + my $base_packet = get_default_black_box_pkt($in_port, $out_port); + + my $wildcards = 0x0000; + my $flags = $enums{'OFPFF_CHECK_OVERLAP'}; + my $max_idle = 0x0; + my $packet = create_flow_mod_from_udp($ofp, $base_packet, $in_port, $out_port, $max_idle, $flags, $wildcards); + + # FOO + print $sock $packet; + + my $wildcards = 0x03fe; + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; + my $packet = create_flow_mod_from_udp($ofp, $base_packet, $in_port, $out_port, $max_idle, $flags, $wildcards); + + # BAR + print $sock $packet; + + my $wildcards = 0x03fd; + my $flags = 0x0000; + my $packet = create_flow_mod_from_udp($ofp, $base_packet, $in_port, $out_port, $max_idle, $flags, $wildcards); + + # BAZ + print $sock $packet; + + # SYNC + enter_barrier($ofp, $sock, 0x12345678); + wait_for_barrier_exit($ofp, $sock, 0x12345678); + + # RUOK? + send_get_config_request($ofp, $sock, 0xcafe2009); + wait_for_get_config_reply($ofp, $sock, 0xcafe2009); + } +} + +run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_cookie_flow_expired/run.pl b/openflow/regress/projects/black_box/regress/test_cookie_flow_expired/run.pl new file mode 100755 index 00000000..5a300ad9 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_cookie_flow_expired/run.pl @@ -0,0 +1,39 @@ +#!/usr/bin/perl -w +# test_flow_expired + +use strict; +use OF::Includes; + +sub my_test { + + my ($sock, $options_ref) = @_; + + my $in_port = $$options_ref{'port_base'}; + my $out_port = $in_port + 1; + + my $test_pkt = get_default_black_box_pkt( $in_port, $out_port); + + my $max_idle = 0x1; # second before flow expiration + my $wildcards = 0x0; # exact match + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry + my $cookie = 0x123456; + # Create a flow mod with a flow cookie + my $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, + $max_idle, $flags, $wildcards, undef, undef, undef, + undef, $cookie ); + + #print HexDump($pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + + my $pkt_len = 0; + my $pkt_total = 0; + wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, + $pkt_total, undef, $cookie ); + +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_cookie_flow_stats/run.pl b/openflow/regress/projects/black_box/regress/test_cookie_flow_stats/run.pl new file mode 100755 index 00000000..705146b1 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_cookie_flow_stats/run.pl @@ -0,0 +1,151 @@ +#!/usr/bin/perl -w +# test_flow_stats + +use strict; +use OF::Includes; + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + my $port_base = $$options_ref{'port_base'}; + + my $cookie = 0x123456; + + my $hdr_args = { + version => get_of_ver(), + type => $enums{'OFPT_STATS_REQUEST'}, + length => $ofp->sizeof('ofp_stats_request') + + $ofp->sizeof('ofp_flow_stats_request'), + # should generate automatically! + xid => 0x00000000 + }; + + my $match_args = { + wildcards => 0x2003ef, + in_port => 0, + dl_src => [], + dl_dst => [], + dl_vlan => 0, + dl_type => 0x800, + nw_tos => 0, + nw_src => (NF2::IP_hdr::getIP('192.168.200.1'))[0], + nw_dst => (NF2::IP_hdr::getIP('192.168.201.2'))[0], + nw_proto => 0, + tp_src => 0, + tp_dst => 0 + }; + + my $stats_request_args = { + header => $hdr_args, + type => $enums{'OFPST_FLOW'}, + flags => 0 + }; + + my $body_args = { + match => $match_args, + table_id => 0xff, #match all tables + out_port => $enums{'OFPP_NONE'}, + }; + + my $body = $ofp->pack('ofp_flow_stats_request', $body_args ); + + my $stats_request = $ofp->pack( 'ofp_stats_request', $stats_request_args ); + + my $mesg = $stats_request . $body; + + # Send 'stats_request' message + print $sock $mesg; + + # Should add timeout here - will crash if no reply + my $recvd_mesg; + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; + + # Inspect message + my $msg_size = length($recvd_mesg); + + my $msg = $ofp->unpack( 'ofp_stats_reply', $recvd_mesg ); + + #print HexDump ($recvd_mesg); + print Dumper($msg); + + # Verify fields + verify_header( $msg, 'OFPT_STATS_REPLY', $msg_size ); + + #---------------------- + + # add flow mod, send pkt + { + + my $in_port_offset = 0; + my $out_port_offset = 1; + my $wildcards = 0x2003ef, + my $wait = 5; + + #$$options_ref{'send_delay'} = 5; + + forward_simple ( $ofp, $sock, $options_ref, $in_port_offset, + $out_port_offset, $wildcards, 'any', 1, undef, undef, $cookie); + +# my $in_port = $in_port_offset + $$options_ref{'port_base'}; +# my $out_port = $out_port_offset + $$options_ref{'port_base'}; +# +# my $test_pkt = get_default_black_box_pkt_len( $in_port, $out_port, $$options_ref{'pkt_len'} ); +# my $flow_mod_pkt = +# create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $wait, $wildcards ); +# +# print $sock $flow_mod_pkt; +# +# # Give OF switch time to process the flow mod +# usleep($$options_ref{'send_delay'}); +# +# nftest_send( "eth" . ($in_port_offset + 1), $test_pkt->packed ); + } + + sleep .1; + + + # Send 'stats_request' message + print $sock $mesg; + + # Should add timeout here - will crash if no reply + my $recvd_mesg; + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; + + # Inspect message + my $msg_size = length($recvd_mesg); + + my $msg = $ofp->unpack( 'ofp_stats_reply', $recvd_mesg ); + + # Strip off the header from the received message + $recvd_mesg = substr($recvd_mesg, $ofp->sizeof('ofp_stats_reply')); + + # Unpack each of the ofp_flow_stats messages + my $flow_stats_len = $ofp->sizeof('ofp_flow_stats'); + while (length($recvd_mesg) > 0) { + if (length($recvd_mesg) < $flow_stats_len) {\ + die "Error: Partial flow stats message received"; + } + my $flow_stats = $ofp->unpack('ofp_flow_stats', $recvd_mesg); + + push @{$msg->{'body'}}, $flow_stats; + $recvd_mesg = substr($recvd_mesg, $flow_stats->{'length'}); + } + + #print HexDump ($recvd_mesg); + print Dumper($msg); + + # Verify fields + verify_header( $msg, 'OFPT_STATS_REPLY', $msg_size ); + + # Verify the cookie + compare( "stats_reply cookie", $msg->{'body'}->[0]->{'cookie'}, '==', $cookie ); + + + #wait_for_flow_expired_all( $ofp, $sock, $options_ref ); + + +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_delete/run.pl b/openflow/regress/projects/black_box/regress/test_delete/run.pl new file mode 100755 index 00000000..7b594682 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_delete/run.pl @@ -0,0 +1,172 @@ +#!/usr/bin/perl -w +# test_delete + +use strict; +use OF::Includes; + +sub send_expect_exact_with_wildcard { + + my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $out_port2_offset, $max_idle, $pkt_len ) = @_; + + my $in_port = $in_port_offset + $$options_ref{'port_base'}; + my $out_port = $out_port_offset + $$options_ref{'port_base'}; + my $out_port2 = $out_port2_offset + $$options_ref{'port_base'}; + + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + src_port => 70, + dst_port => 80 + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + my $test_pkt_args2 = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + src_port => 170, + dst_port => 180 + }; + my $test_pkt2 = new NF2::UDP_pkt(%$test_pkt_args2); + + # Flow entry -- exact match, $out_port + my $wildcards = 0x0; # exact match + my $flags = 0x0; # don't send flow expiry + my $flow_mod_exact_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); + + # 2nd flow entry -- wildcard match, $out_port2 + $wildcards = $enums{'OFPFW_TP_SRC'} | $enums{'OFPFW_TP_DST'}; # wildcard match (don't care udp src/dst ports) + print "wildcards = $wildcards\n"; + my $flow_mod_wildcard_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port2, $max_idle, $flags, $wildcards ); + + #print HexDump($flow_mod_exact_pkt); + #print HexDump($flow_mod_wildcard_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_exact_pkt; + print "sent flow_mod message (create exact match entry)\n"; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + + print $sock $flow_mod_wildcard_pkt; + print "sent flow_mod message (create wildcard entry)\n"; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + + # Check what's on the switch + #dpctl_show_flows($options_ref); + + # Send a packet - ensure packet comes out desired port + print "Verify packets are forwarded correctly\n"; + nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt->packed ); + nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); + + nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt2->packed ); + nftest_expect( "eth" . ( $out_port2_offset + 1 ), $test_pkt2->packed ); + + print "sent two packets\n"; +} + +sub delete_send_expect { + + my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $out_port2_offset, $max_idle, $pkt_len ) = @_; + + my $in_port = $in_port_offset + $$options_ref{'port_base'}; + my $out_port = $out_port_offset + $$options_ref{'port_base'}; + my $out_port2 = $out_port2_offset + $$options_ref{'port_base'}; + + # in_port refers to the flow mod entry's input + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + src_port => 70, + dst_port => 80 + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + my $test_pkt_args2 = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + src_port => 170, + dst_port => 180 + }; + my $test_pkt2 = new NF2::UDP_pkt(%$test_pkt_args2); + + my $wildcards = $enums{'OFPFW_TP_SRC'} | $enums{'OFPFW_TP_DST'}; # wildcard match (don't care udp src/dst ports) + my $flags = 0x0; # don't send flow expiry + my $flow_mod_wildcard_pkt = + create_flow_mod_from_udp_action( $ofp, $test_pkt2, $in_port, $out_port2, $max_idle, + $flags, $wildcards, "OFPFC_DELETE" ); + + #print HexDump($flow_mod_exact_pkt); + #print HexDump($flow_mod_wildcard_pkt); + + # Send 'flow_mod' message (delete wildcard entry without STRICT) + print $sock $flow_mod_wildcard_pkt; + print "sent flow_mod message (delete wildcard entry)\n"; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + # Give extra time, wildcard delete takes more time - Jean II + usleep($$options_ref{'send_delay'}); + + # Check what's on the switch + #dpctl_show_flows($options_ref); + + # Send a packet + print "Verify packets are forwarded correctly i.e., fwded to contoller\n"; + nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt->packed ); + nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt2->packed ); + + # both pkts should go to the controller + wait_for_one_packet_in( $ofp, $sock, $pkt_len, $test_pkt->packed ); + wait_for_one_packet_in( $ofp, $sock, $pkt_len, $test_pkt2->packed ); + +} + +sub test_delete { + + my ( $ofp, $sock, $options_ref, $i, $j, $o_port2, $wildcards ) = @_; + + my $max_idle = $$options_ref{'max_idle'}; + my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_total = $$options_ref{'pkt_total'}; + + print "sending from $i to $j & $i to $o_port2 -- both should match\n"; + send_expect_exact_with_wildcard( $ofp, $sock, $options_ref, $i, $j, $o_port2, $max_idle, $pkt_len ); + + # wait for switch to process last packets + usleep($$options_ref{'send_delay'}); + + print "delete wildcard entry (without STRICT) and send packets again\n"; + delete_send_expect( $ofp, $sock, $options_ref, $i, $j, $o_port2, $max_idle, $pkt_len ); +} + +sub my_test { + + my ($sock, $options_ref) = @_; + + # send from every port to every other port + for_all_port_triplets( $ofp, $sock, $options_ref, \&test_delete, 0x0); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_delete_send_flow_exp/run.pl b/openflow/regress/projects/black_box/regress/test_delete_send_flow_exp/run.pl new file mode 100755 index 00000000..6e093fcc --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_delete_send_flow_exp/run.pl @@ -0,0 +1,104 @@ +#!/usr/bin/perl -w +# test_delete + +use strict; +use OF::Includes; + +sub my_test { + + my ($sock, $options_ref) = @_; + + my $in_port = $$options_ref{'port_base'}; + my $out_port = $in_port + 1; + + my $test_pkt = get_default_black_box_pkt( $in_port, $out_port, $$options_ref{'pkt_len'} ); + + my $max_idle = 0x0; # second before flow expiration -- never time out + my $wildcards = 0x0; # exact match + # Create a flow mod without expiry + my $flags = 0x0; # don't send flow expiry + my $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); + print "send flow mode without expiry\n"; + print $sock $flow_mod_pkt; + + # Delete the flow and verify that we don't see an expiry + $flow_mod_pkt = + create_flow_mod_from_udp_action( $ofp, $test_pkt, $in_port, $out_port, $max_idle, + $flags, $wildcards, "OFPFC_DELETE" ); + print $sock $flow_mod_pkt; + + my $sel = IO::Select->new($sock); + if ($sel->can_read(2)) { + print "Error: was not expecting a message from the switch\n"; + exit 1; + } + + # Create a flow mod with expiry + $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry + $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); + print "send flow mode with expiry\n"; + print $sock $flow_mod_pkt; + + # Delete the flow and verify that we do see an expiry + $flags = 0x0; # Reset the flags to zero. Should not matter as it + # should only depend on the flags when the flow was installed. + $flow_mod_pkt = + create_flow_mod_from_udp_action( $ofp, $test_pkt, $in_port, $out_port, $max_idle, + $flags, $wildcards, "OFPFC_DELETE" ); + print $sock $flow_mod_pkt; + + my $pkt_len = 0; + my $pkt_total = 0; + wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); + + # Redo the same test with a few packets to make sure stats are correct + # Jean II + + # Create a flow mod with expiry + $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry + $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); + print "send flow mode with expiry and with 3 packets\n"; + print $sock $flow_mod_pkt; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + usleep($$options_ref{'send_delay'}); + + # Send 3 packets, because first packet can be "special" - Jean II + # We should be using $options{'pkt_total'}, but that is stuck at 1 + nftest_send("eth" . ($in_port), $test_pkt->packed); + nftest_send("eth" . ($in_port), $test_pkt->packed); + nftest_send("eth" . ($in_port), $test_pkt->packed); + + # expect 3 packets + print "expect 3 packets\n"; + nftest_expect("eth" . ($out_port), $test_pkt->packed); + nftest_expect("eth" . ($out_port), $test_pkt->packed); + nftest_expect("eth" . ($out_port), $test_pkt->packed); + + # Wait for stats to refresh + sleep($$options_ref{'max_idle'}); + #dpctl_show_flows($options_ref); + + # Delete the flow and verify that we do see an expiry + $flags = 0x0; # Reset the flags to zero. Should not matter as it + # should only depend on the flags when the flow was installed. + $flow_mod_pkt = + create_flow_mod_from_udp_action( $ofp, $test_pkt, $in_port, $out_port, $max_idle, + $flags, $wildcards, "OFPFC_DELETE" ); + print $sock $flow_mod_pkt; + + # And now check the stats in the flow removed message... + my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_total = 3; + wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); + + + +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_delete_strict/run.pl b/openflow/regress/projects/black_box/regress/test_delete_strict/run.pl new file mode 100755 index 00000000..8290dae9 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_delete_strict/run.pl @@ -0,0 +1,175 @@ +#!/usr/bin/perl -w +# test_delete_strict + +use strict; +use OF::Includes; + +sub send_expect_exact_with_wildcard { + + my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $out_port2_offset, $max_idle, $pkt_len ) = @_; + + my $in_port = $in_port_offset + $$options_ref{'port_base'}; + my $out_port = $out_port_offset + $$options_ref{'port_base'}; + my $out_port2 = $out_port2_offset + $$options_ref{'port_base'}; + + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + src_port => 70, + dst_port => 80 + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + my $test_pkt_args2 = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + src_port => 170, + dst_port => 180 + }; + my $test_pkt2 = new NF2::UDP_pkt(%$test_pkt_args2); + + # Flow entry -- exact match, $out_port + my $wildcards = 0x0; # exact match + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; + my $flow_mod_exact_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); + + # 2nd flow entry -- wildcard match, $out_port2 + $wildcards = $enums{'OFPFW_TP_SRC'} | $enums{'OFPFW_TP_DST'}; # wildcard match (don't care udp src/dst ports) + my $flow_mod_wildcard_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port2, $max_idle, $flags, $wildcards ); + + #print HexDump($flow_mod_exact_pkt); + #print HexDump($flow_mod_wildcard_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_exact_pkt; + print "sent flow_mod message (create exact match entry)\n"; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + + print $sock $flow_mod_wildcard_pkt; + print "sent flow_mod message (create wildcard entry)\n"; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + + # Check what's on the switch + #dpctl_show_flows($options_ref); + + # Send a packet - ensure packet comes out desired port + print "Verify packets are forwarded correctly\n"; + nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt->packed ); + nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); + + nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt2->packed ); + nftest_expect( "eth" . ( $out_port2_offset + 1 ), $test_pkt2->packed ); +} + +sub delete_strict_send_expect { + + my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $out_port2_offset, $max_idle, $pkt_len ) = @_; + + my $in_port = $in_port_offset + $$options_ref{'port_base'}; + my $out_port = $out_port_offset + $$options_ref{'port_base'}; + my $out_port2 = $out_port2_offset + $$options_ref{'port_base'}; + + # in_port refers to the flow mod entry's input + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + src_port => 70, + dst_port => 80 + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + my $test_pkt_args2 = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + src_port => 170, + dst_port => 180 + }; + my $test_pkt2 = new NF2::UDP_pkt(%$test_pkt_args2); + + my $wildcards = $enums{'OFPFW_TP_SRC'} | $enums{'OFPFW_TP_DST'}; # wildcard match (don't care udp src/dst ports) + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; + my $flow_mod_wildcard_pkt = + + # delete_strict_from_udp( $ofp, $test_pkt, $in_port, $out_port2, $wildcards ); + create_flow_mod_from_udp_action( $ofp, $test_pkt, $in_port, $out_port2, $max_idle, $flags, $wildcards, + 'OFPFC_DELETE_STRICT' ); + + #print HexDump($flow_mod_exact_pkt); + #print HexDump($flow_mod_wildcard_pkt); + + # Send 'flow_mod' message (delete wildcard entry with STRICT) + print $sock $flow_mod_wildcard_pkt; + print "sent flow_mod message (delete (strict) wildcard entry)\n"; + + # Expect a flow expire due to the delete + wait_for_flow_expired_readone( $ofp, $sock, $options_ref, $pkt_len, 1 ); + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + # Give extra time, delete takes more time - Jean II + usleep($$options_ref{'send_delay'}); + + # Check what's on the switch + #dpctl_show_flows($options_ref); + + # Send a packet + print + "Verify packets are forwarded correctly i.e., one fwded to contoller and one (exact match) fwd to the specified port\n"; + nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt->packed ); + nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); + + nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt2->packed ); + wait_for_one_packet_in( $ofp, $sock, $pkt_len, $test_pkt2->packed ); +} + +sub test_delete_strict { + + my ( $ofp, $sock, $options_ref, $i, $j, $o_port2, $wildcards ) = @_; + + my $max_idle = $$options_ref{'max_idle'}; + my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_total = $$options_ref{'pkt_total'}; + + print "sending from $i to $j & $i to $o_port2 -- both should match\n"; + send_expect_exact_with_wildcard( $ofp, $sock, $options_ref, $i, $j, $o_port2, $max_idle, $pkt_len ); + + # wait for switch to process last packets + usleep($$options_ref{'send_delay'}); + + print "delete wildcard entry (with STRICT) \n"; + print "sending from $i to $j & $i to $o_port2 "; + delete_strict_send_expect( $ofp, $sock, $options_ref, $i, $j, $o_port2, $max_idle, $pkt_len ); + wait_for_flow_expired_readone( $ofp, $sock, $options_ref, $pkt_len, 2 ); +} + +sub my_test { + + my ($sock, $options_ref) = @_; + + # send from every port to every other port + for_all_port_triplets( $ofp, $sock, $options_ref, \&test_delete_strict, 0x0); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_drop_exact/run.pl b/openflow/regress/projects/black_box/regress/test_drop_exact/run.pl new file mode 100755 index 00000000..98180d18 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_drop_exact/run.pl @@ -0,0 +1,54 @@ +#!/usr/bin/perl -w +# test_drop_exact + +use strict; +use OF::Includes; + +#sub drop_simple { +# +# my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $wildcards, $nowait ) = @_; +# +# my $in_port = $in_port_offset + $$options_ref{'port_base'}; +# my $out_port = $out_port_offset + $$options_ref{'port_base'}; +# # print "drop_simple : ports = ".($in_port).",".($out_port); +# +# my $test_pkt = get_default_black_box_pkt_len( $in_port, $out_port, $$options_ref{'pkt_len'} ); +# +# #print HexDump ( $test_pkt->packed ); +# +# my $flow_mod_pkt = +# create_flow_drop_from_udp_action( $ofp, $test_pkt, $in_port, $out_port, $$options_ref{'max_idle'}, $wildcards, 'drop' ); +# +# #print HexDump($flow_mod_pkt); +# #print Dumper($flow_mod_pkt); +# +# # Send 'flow_mod' message +# syswrite( $sock, $flow_mod_pkt ); +# print "sent flow_mod message\n"; +# +# # Give OF switch time to process the flow mod +# usleep($$options_ref{'send_delay'}); +# +# nftest_send( "eth" . ($in_port_offset + 1), $test_pkt->packed); +# +# # We should expect no message at all on any port ! - Jean II +# +# if (not defined($nowait)) { +# print "wait \n"; +# wait_for_flow_expired_all( $ofp, $sock, $options_ref ); +# } +#} + +sub drop_port { + + forward_simple(@_, 'drop'); +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_port_pairs( $ofp, $sock, $options_ref, \&drop_port, 0x0); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_failover_close/run.pl b/openflow/regress/projects/black_box/regress/test_failover_close/run.pl new file mode 100755 index 00000000..06fd9a71 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_failover_close/run.pl @@ -0,0 +1,68 @@ +#!/usr/bin/perl -w + +# Simple two-controller failover test +# +# For this test to work, the switch must be set up to use our +# two "controllers", e.g. +# +# ofprotocol --controller=tcp:127.0.0.1:6633,tcp:127.0.0.1:6634 +# +# If you use different ports than the defaults, then you must +# pass the --controller option into this script as well. +# +# Failover test 2: Controller is fine, but closes connection +# +# For this test, we accept the Hello sequence and then close +# the socket. Then we listen for a failover connection on the +# second socket. +# + +use strict; +use OF::Includes; + +# Save ARGV for future reference +my @ARGS = @ARGV; + +my $test = "Failover test 2 (connection closed)"; + +print "$test phase 1: calling run_black_box_test with @ARGV\n"; + +# Start up, say Hello, and close connection +sub close_failover_test_phase_1 { + my ($sock) = @_; + print "$test: Got socket $sock\n"; + print "$test: Finished Hello sequence on first controller\n"; + print "$test: Closing socket\n"; + $sock->close(); +} + +run_black_box_test( \&close_failover_test_phase_1, \@ARGV, 1); # 1 -> don't exit + +# Now, attempt to open up the second controller connection, and +# hope that we fail over + +# Restore ARGV +@ARGV = @ARGS; + +# If no controllers specified, use default +if (not "@ARGV" =~ "--controller") { + push( @ARGV, "--controller=" . nftest_default_controllers() ); +} + +# Replace --controller=foo,bar with --controller=bar so that +# run_black_box_test() will use bar's port rather than foo's +for (my $i = 0; $i < @ARGV; $i++) { + if ($ARGV[$i] =~ /controller=[^,]*,([^\s]+)/ ) { + print "failover_startup: got controller $1\n"; + $ARGV[$i] = "--controller=$1"; + } +} + + +sub close_failover_test_phase_2 { + print "$test: Failover to second controller succeeded\n"; +} + +print "$test: Calling run_black_box_test with @ARGV\n"; +run_black_box_test( \&close_failover_test_phase_2, \@ARGV ); # do exit this time + diff --git a/openflow/regress/projects/black_box/regress/test_failover_startup/run.pl b/openflow/regress/projects/black_box/regress/test_failover_startup/run.pl new file mode 100755 index 00000000..7bfee7aa --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_failover_startup/run.pl @@ -0,0 +1,53 @@ +#!/usr/bin/perl + +# Simple two-controller failover test +# +# For this test to work, the switch must be set up to use our +# two "controllers", e.g. +# +# ofprotocol --controller=tcp:127.0.0.1:6633,tcp:127.0.0.1:6634 +# +# If you use different ports than the defaults, then you must +# pass the --controller option into this script as well. +# +# Failover Test 1: Startup Failover +# +# For this test, we listen on the second controller port rather +# than the first. +# + +use strict; +use OF::Includes; +use Getopt::Long; + +my $test="Failover test 1 (startup failover)"; + +my $controllers; + +# Remove '--controller' from the option list... - Jean II +Getopt::Long::Configure( 'pass_through' ); +GetOptions( + "controller=s" => \$controllers +); +if (!defined($controllers)) +{ + # If no controllers specified, use default + $controllers = nftest_default_controllers(); +} +Getopt::Long::Configure( 'default' ); + +# Get controller +my @controller_array = split(/,/, $controllers); +my $failover_controller = @controller_array[1]; + +# Push back a controller string +push( @ARGV, "--controller=$failover_controller" ); + +print "$test: Calling run_black_box_test with @ARGV\n"; + +sub startup_failover_test { + print "$test: Failed over successfully\n"; +} + +run_black_box_test( \&startup_failover_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_failover_stop_responding/run.pl b/openflow/regress/projects/black_box/regress/test_failover_stop_responding/run.pl new file mode 100755 index 00000000..50a4a475 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_failover_stop_responding/run.pl @@ -0,0 +1,65 @@ +#!/usr/bin/perl -w + +# Simple two-controller failover test +# +# For this test to work, the switch must be set up to use our +# two "controllers", e.g. +# +# ofprotocol --controller=tcp:127.0.0.1:6633,tcp:127.0.0.1:6634 +# +# If you use different ports than the defaults, then you must +# pass the --controller option into this script as well. +# +# Failover test 3: Controller is fine, but stops responding +# +# For this test, we accept the Hello sequence on the first port +# but then listen for a failover connection on the second port. +# + +use strict; +use OF::Includes; + +# Save ARGV for future reference +my @ARGS = @ARGV; + +my $test="Failover test 3 (controller stops responding)"; + +print "$test phase 1: calling run_black_box_test with @ARGV\n"; + +# Start up, say Hello, and close connection +sub stop_responding_test_phase_1 { + my ($sock) = @_; + print "$test: Got socket $sock\n"; + print "$test: Finished Hello sequence on first controller\n"; + print "$test: Not closing socket\n"; + print "$test: Invoking phase 2\n"; + stop_responding_phase_2(); +} + +run_black_box_test( \&stop_responding_test_phase_1, \@ARGV, 1); # 1 -> don't exit + +sub stop_responding_phase_2 { + + # Now, attempt to open up the second controller connection, and + # hope that we fail over + + # Restore ARGV + @ARGV = @ARGS; + + # If no controllers specified, use default + if (not "@ARGV" =~ "--controller") { + push( @ARGV, "--controller=" . nftest_default_controllers() ); + } + + # Replace --controller=foo,bar with --controller=bar so that + # run_black_box_test() will use bar's port rather than foo's + for (my $i = 0; $i < @ARGV; $i++) { + if ($ARGV[$i] =~ /controller=[^,]*,([^\s]+)/ ) { + print "$test: got controller $1\n"; + $ARGV[$i] = "--controller=$1"; + } + } + + print "$test: Calling run_black_box_test with @ARGV\n"; + run_black_box_test( \&close_failover_test_phase_2, \@ARGV ); # do exit this time +} diff --git a/openflow/regress/projects/black_box/regress/test_flow_expired/run.pl b/openflow/regress/projects/black_box/regress/test_flow_expired/run.pl new file mode 100755 index 00000000..97ea35cc --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_flow_expired/run.pl @@ -0,0 +1,34 @@ +#!/usr/bin/perl -w +# test_flow_expired + +use strict; +use OF::Includes; + +sub my_test { + + my ($sock, $options_ref) = @_; + + my $in_port = $$options_ref{'port_base'}; + my $out_port = $in_port + 1; + + my $test_pkt = get_default_black_box_pkt( $in_port, $out_port); + + my $max_idle = 0x1; # second before flow expiration + my $wildcards = 0x0; # exact match + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry + my $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); + + #print HexDump($pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + + my $pkt_len = 0; + my $pkt_total = 0; + wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); + +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_flow_expired_idle_timeout/run.pl b/openflow/regress/projects/black_box/regress/test_flow_expired_idle_timeout/run.pl new file mode 100755 index 00000000..5fa74924 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_flow_expired_idle_timeout/run.pl @@ -0,0 +1,34 @@ +#!/usr/bin/perl -w +# test_flow_expired + +use strict; +use OF::Includes; + +sub my_test { + + my ($sock, $options_ref) = @_; + + my $in_port = $$options_ref{'port_base'}; + my $out_port = $in_port + 1; + + my $test_pkt = get_default_black_box_pkt( $in_port, $out_port); + + my $max_idle = 0x1; # second before flow expiration + my $wildcards = 0x0; # exact match + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; + my $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); + + #print HexDump($pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + + my $pkt_len = 0; + my $pkt_total = 0; + wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total, $max_idle ); + +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_flow_expired_precision/run.pl b/openflow/regress/projects/black_box/regress/test_flow_expired_precision/run.pl new file mode 100755 index 00000000..798f6b89 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_flow_expired_precision/run.pl @@ -0,0 +1,66 @@ +#!/usr/bin/perl -w +# test_flow_expired +# This test checks if the flow duration time is in a reasonable range. +# This test assumes a reference switch as a target. +# The switch polls flow expiration every 1 sec with jitter, +# so we should expect 1sec difference for flow_duration. + +use strict; +use OF::Includes; + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + my $in_port = $$options_ref{'port_base'}; + my $out_port = $in_port + 1; + + my $test_pkt = get_default_black_box_pkt( $in_port, $out_port ); + + my $max_idle = 0x1; # second before flow expiration + my $wildcards = 0x0; # exact match + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry + my $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, + $flags, $wildcards ); + + #print HexDump($pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + + my $pkt_len = 0; + my $pkt_total = 0; + + my $read_size = 1512; + + my $recvd_mesg; + sysread( $sock, $recvd_mesg, $read_size ) + || die "Failed to receive ofp_flow_removed message: $!"; + + # Inspect message + my $msg_size = length($recvd_mesg); + my $expected_size = $ofp->sizeof('ofp_flow_removed'); + compare( "ofp_flow_removed msg size", + length($recvd_mesg), '==', $expected_size ); + + my $msg = $ofp->unpack( 'ofp_flow_removed', $recvd_mesg ); + + print Dumper($msg); + + my $sample_period = 1; + + compare( "ofp_flow_removed packet_count", + $$msg{'packet_count'}, '==', $pkt_total ); + print "Duretion_sec : $$msg{'duration_sec'} sec\n"; + print "Duration_nsec: $$msg{'duration_nsec'} nano sec\n"; + + if (($$msg{'duration_sec'} < $max_idle) + || ($$msg{'duration_sec'} > ($max_idle + $sample_period))) { + die "Error, duration_sec out of acceptable range"; + } + +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_flow_expired_send_flow_exp/run.pl b/openflow/regress/projects/black_box/regress/test_flow_expired_send_flow_exp/run.pl new file mode 100755 index 00000000..4a47caef --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_flow_expired_send_flow_exp/run.pl @@ -0,0 +1,44 @@ +#!/usr/bin/perl -w +# test_flow_expired + +use strict; +use OF::Includes; +use IO::Select; + +sub my_test { + + my ($sock, $options_ref) = @_; + + my $in_port = $$options_ref{'port_base'}; + my $out_port = $in_port + 1; + + my $test_pkt = get_default_black_box_pkt( $in_port, $out_port); + + my $max_idle = 0x1; # second before flow expiration + my $wildcards = 0x0; # exact match + # Create a flow mod without expiry + my $flags = 0x0; # don't send flow expiry + my $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); + print $sock $flow_mod_pkt; + + my $sel = IO::Select->new($sock); + if ($sel->can_read(2 * $max_idle)) { + print "Error: was not expecting a message from the switch\n"; + exit 1; + } + + # Create a flow mod with expiry + $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry + $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); + print $sock $flow_mod_pkt; + + my $pkt_len = 0; + my $pkt_total = 0; + wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); + +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_flow_mod_check/run.pl b/openflow/regress/projects/black_box/regress/test_flow_mod_check/run.pl new file mode 100755 index 00000000..1c0b7f76 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_flow_mod_check/run.pl @@ -0,0 +1,83 @@ +#!/usr/bin/perl -w +# test_flow_mod_check + +use strict; +use OF::Includes; + +sub wait_for_flow_overlap_error { + my ($ofp, $sock, $flow_mod_pkt) = @_; + my $rcvd_msg; + + sysread($sock, $rcvd_msg, 1512); + + my $msg_size = length($rcvd_msg); + my $expected_size = $ofp->sizeof('ofp_error_msg') + length($flow_mod_pkt); + compare("msg size", $msg_size, '==', $expected_size); + + my $msg = $ofp->unpack('ofp_error_msg', $rcvd_msg); + verify_header($msg, 'OFPT_ERROR', $msg_size); + + compare("error type", $$msg{'type'}, '==', $enums{'OFPET_FLOW_MOD_FAILED'}); + compare("error code", $$msg{'code'}, '==', $enums{'OFPFMFC_OVERLAP'}); +} + +sub my_test { + my ($sock, $options_ref) = @_; + + my $in_port = $$options_ref{'port_base'}; + my $out_port_1 = $in_port + 1; + my $out_port_2 = $in_port + 2; + my $out_port_3 = $in_port + 3; + + my $test_pkt = get_default_black_box_pkt($in_port, $out_port_1); + + + my $wildcards = 0x0c0; + my $flags = $enums{'OFPFF_CHECK_OVERLAP'}; + my $max_idle = 0x0; # never expire + my $flow_mod_pkt = create_flow_mod_from_udp($ofp, $test_pkt, $in_port, $out_port_1, $max_idle, $flags, $wildcards); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + + # change the wildcard and send again. this should fail + $wildcards = 0x0c1; + my $flags = $enums{'OFPFF_CHECK_OVERLAP'}; + $flow_mod_pkt = create_flow_mod_from_udp($ofp, $test_pkt, $in_port+1, $out_port_2, $max_idle, $flags, $wildcards); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + + wait_for_flow_overlap_error($ofp, $sock, $flow_mod_pkt); + + # Start with coarse granularity flow + # edge-case bug reported by Justin + # https://mailman.stanford.edu/pipermail/openflow-dev/2009-November/000529.html + $wildcards = 0x0c1; + $flags = 0x0; + $flow_mod_pkt = create_flow_mod_from_udp($ofp, $test_pkt, $in_port, $out_port_1, $max_idle, $flags, $wildcards); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + + # change the wildcard and send again. this should fail + $wildcards = 0x0c0; + $flags = $enums{'OFPFF_CHECK_OVERLAP'}; + $flow_mod_pkt = create_flow_mod_from_udp($ofp, $test_pkt, $in_port+1, $out_port_2, $max_idle, $flags, $wildcards); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + + wait_for_flow_overlap_error($ofp, $sock, $flow_mod_pkt); + + + +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_flow_mod_latency/run-port3.pl b/openflow/regress/projects/black_box/regress/test_flow_mod_latency/run-port3.pl new file mode 100644 index 00000000..204873b7 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_flow_mod_latency/run-port3.pl @@ -0,0 +1,136 @@ +#!/usr/bin/perl -w +# test_flow_mod_latency +# +# Don't include this test as part of the official test suite, +# as it is not supposed to pass... +# +# Run it like this : +# ./bin/of_hp_test.pl --testPath=black_box/regress/test_flow_mod_latency/run.pl +# +# Check the number of packets received : +# tcpdump -p -i eth11 -w stanford.test.log +# tcpdump -r stanford.test.log | wc +# +# On the HP, it requires increasing the SW rate limiter : +# openflow 9 sw-rate 5000 +# +# Jean II + +use strict; +use OF::Includes; + +sub forward_flow_mod_latency { + + my ($sock, $options_ref) = @_; + my $in_port = $$options_ref{'port_base'}; + my $out_port = $in_port + 1; + my $fallback_port = $out_port + 1; + + my $len = $$options_ref{'pkt_len'}; + my $wildcards = 0x0; # exact match + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; + my $pkt_args; + my $test_pkt; + my $flow_mod_pkt; + my $i; + + if (1) { + # Create a flow mod to track all packets sent to the controller + # We create a wildcard on both transport port, that sends + # packets to the controller - Jean II + $pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $len, + src_port => 0, + dst_port => 0 + }; + $test_pkt = new NF2::UDP_pkt(%$pkt_args); + $wildcards = $enums{'OFPFW_TP_SRC'} | $enums{'OFPFW_TP_DST'}; + print"wildcards = $wildcards\n"; + # Full experiment is around 15s + $flow_mod_pkt = create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $fallback_port, 25, $flags, $wildcards ); + syswrite( $sock, $flow_mod_pkt ); + print "sent flow_mod message with wildcard\n"; + + # Make sure the flow mod is properly inserted and the + # OpenFlow instance properly started. The OpenFlow instance + # takes time to get started, we want to make sure this is + # not a factor. Jean II + sleep(1); + + # No more wildcards + $wildcards = 0x0; # exact match + } + + # Let's create 100 sequencial connections - Jean II + for ( my $c = 0 ; $c < 100 ; $c++ ) { + + # Packets for creating the flow mod + $pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $len, + src_port => 2000 + $c, + dst_port => 4000 + $c + }; + $test_pkt = new NF2::UDP_pkt(%$pkt_args); + + # Let's create a long lived flow mod + $flow_mod_pkt = create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, 20, $flags, $wildcards ); + + # Send 'flow_mod' message + syswrite( $sock, $flow_mod_pkt ); + print "sent flow_mod message for connection $c\n"; + + # Test packet to be sent - should match flow mod + $pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $len, + src_port => 2000 + $c, + dst_port => 4000 + $c + }; + $test_pkt = new NF2::UDP_pkt(%$pkt_args); + + # For this test, the TCAM is much slower. Wait a bit more + # to get more interesting results. I also increased pkt count. + # Jean II + usleep(20000); + + # Max in SW is around 5000 pkts/sec + # Note : default rate limiter value is 100 pkts/sec, which is + # one packet every 10s, so you can't run at default value + # Send 15 packets as a short burst over 60ms + for ($i = 0 ; $i < 15 ; $i++ ) { + + # Wait 4 ms between packets + usleep(4000); + + # Send test packet + nftest_send( "eth" . ($in_port), $test_pkt->packed ); + + # This does not block, so we are good... + nftest_expect( "eth" . ($out_port), $test_pkt->packed ); + } + + # We don't wait for flow expiry, that's too long waiting - Jean II + } + + # Wait for stats to refresh + # For most flow mod, we should be about half life, which means + # they have not expired yet, and have already got stats a few time. + sleep(6); + dpctl_show_flows($options_ref); +} + +run_black_box_test( \&forward_flow_mod_latency, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_flow_mod_latency/run.pl b/openflow/regress/projects/black_box/regress/test_flow_mod_latency/run.pl new file mode 100755 index 00000000..49789383 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_flow_mod_latency/run.pl @@ -0,0 +1,129 @@ +#!/usr/bin/perl -w +# test_flow_mod_latency +# +# Don't include this test as part of the official test suite, +# as it is not supposed to pass... +# +# Run it like this : +# ./bin/of_hp_test.pl --testPath=black_box/regress/test_flow_mod_latency/run.pl +# +# Check the number of packets received : +# tcpdump -p -i eth11 -w stanford.test.log +# tcpdump -r stanford.test.log | wc +# +# On the HP, it requires increasing the SW rate limiter : +# openflow 9 sw-rate 5000 +# +# Jean II + +use strict; +use OF::Includes; + +sub forward_flow_mod_latency { + + my ($sock, $options_ref) = @_; + my $in_port = $$options_ref{'port_base'}; + my $out_port = $in_port + 1; + + my $len = $$options_ref{'pkt_len'}; + my $wildcards = 0x0; # exact match + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; + my $pkt_args; + my $test_pkt; + my $flow_mod_pkt; + my $i; + + if (1) { + # Create a flow mod to track all packets sent to the controller + # We create a wildcard on both transport port, that sends + # packets to the controller - Jean II + $pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $len, + src_port => 0, + dst_port => 0 + }; + $test_pkt = new NF2::UDP_pkt(%$pkt_args); + $wildcards = $enums{'OFPFW_TP_SRC'} | $enums{'OFPFW_TP_DST'}; + print"wildcards = $wildcards\n"; + $flow_mod_pkt = create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $enums{'OFPP_CONTROLLER'}, 20, $flags, $wildcards ); + syswrite( $sock, $flow_mod_pkt ); + print "sent flow_mod message with wildcard\n"; + + # Make sure the flow mod is properly inserted and the + # OpenFlow instance properly started. The OpenFlow instance + # takes time to get started, we want to make sure this is + # not a factor. Jean II + sleep(1); + + # No more wildcards + $wildcards = 0x0; # exact match + } + + # Let's create 100 sequencial connections - Jean II + for ( my $c = 0 ; $c < 100 ; $c++ ) { + + # Packets for creating the flow mod + $pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $len, + src_port => 2000 + $c, + dst_port => 4000 + $c + }; + $test_pkt = new NF2::UDP_pkt(%$pkt_args); + + # Let's create a long lived flow mod + $flow_mod_pkt = create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, 15, $flags, $wildcards ); + + # Send 'flow_mod' message + syswrite( $sock, $flow_mod_pkt ); + print "sent flow_mod message for connection $c\n"; + + # Test packet to be sent - should match flow mod + $pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $len, + src_port => 2000 + $c, + dst_port => 4000 + $c + }; + $test_pkt = new NF2::UDP_pkt(%$pkt_args); + + # Max in SW is around 5000 pkts/sec + # Note : default rate limiter value is 100 pkts/sec, which is + # one packet every 10s, so you can't run at default value + # Send 5 packets as a short burst over 20ms + for ($i = 0 ; $i < 5 ; $i++ ) { + + # Wait 4 ms between packets + usleep(4000); + + # Send test packet + nftest_send( "eth" . ($in_port), $test_pkt->packed ); + + # This does not block, so we are good... + nftest_expect( "eth" . ($out_port), $test_pkt->packed ); + } + + # We don't wait for flow expiry, that's too long waiting - Jean II + } + + # Wait for stats to refresh + # For most flow mod, we should be about half life, which means + # they have not expired yet, and have already got stats a few time. + sleep(6); + dpctl_show_flows($options_ref); +} + +run_black_box_test( \&forward_flow_mod_latency, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_flow_stats/run.pl b/openflow/regress/projects/black_box/regress/test_flow_stats/run.pl new file mode 100755 index 00000000..eeea50a6 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_flow_stats/run.pl @@ -0,0 +1,145 @@ +#!/usr/bin/perl -w +# test_flow_stats + +use strict; +use OF::Includes; + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + my $port_base = $$options_ref{'port_base'}; + + my $hdr_args = { + version => get_of_ver(), + type => $enums{'OFPT_STATS_REQUEST'}, + length => $ofp->sizeof('ofp_stats_request') + $ofp->sizeof('ofp_flow_stats_request'), # should generate automatically! + xid => 0x00000000 + }; + + my $match_args = { + wildcards => 0x3ef, + in_port => 0, + dl_src => [], + dl_dst => [], + dl_vlan => 0, + dl_type => 0x800, + nw_src => (NF2::IP_hdr::getIP('192.168.200.1'))[0], + nw_dst => (NF2::IP_hdr::getIP('192.168.201.2'))[0], + nw_proto => 0, + tp_src => 0, + tp_dst => 0 + }; + + my $stats_request_args = { + header => $hdr_args, + type => $enums{'OFPST_FLOW'}, + flags => 0 + }; + + my $body_args = { + match => $match_args, + table_id => 0xff, #match all tables + out_port => $enums{'OFPP_NONE'}, + }; + + my $body = $ofp->pack('ofp_flow_stats_request', $body_args ); + + my $stats_request = $ofp->pack( 'ofp_stats_request', $stats_request_args ); + + my $mesg = $stats_request . $body; + + # Send 'stats_request' message + print $sock $mesg; + + # Should add timeout here - will crash if no reply + my $recvd_mesg; + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; + + # Inspect message + my $msg_size = length($recvd_mesg); + + my $msg = $ofp->unpack( 'ofp_stats_reply', $recvd_mesg ); + + #print HexDump ($recvd_mesg); + print Dumper($msg); + + # Verify fields + verify_header( $msg, 'OFPT_STATS_REPLY', $msg_size ); + + #---------------------- + + # add flow mod, send pkt + { + + my $in_port_offset = 0; + my $out_port_offset = 1; + my $wildcards = 0x3ef; + my $wait = 5; + + #$$options_ref{'send_delay'} = 5; + + forward_simple ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $wildcards, 'any', 1); + +# my $in_port = $in_port_offset + $$options_ref{'port_base'}; +# my $out_port = $out_port_offset + $$options_ref{'port_base'}; +# +# my $test_pkt = get_default_black_box_pkt_len( $in_port, $out_port, $$options_ref{'pkt_len'} ); +# my $flow_mod_pkt = +# create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $wait, $wildcards ); +# +# print $sock $flow_mod_pkt; +# +# # Give OF switch time to process the flow mod +# usleep($$options_ref{'send_delay'}); +# +# nftest_send( "eth" . ($in_port_offset + 1), $test_pkt->packed ); + } + + sleep .1; + + + # Send 'stats_request' message + print $sock $mesg; + + # Should add timeout here - will crash if no reply + my $recvd_mesg; + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; + + # Inspect message + my $msg_size = length($recvd_mesg); + + my $msg = $ofp->unpack( 'ofp_stats_reply', $recvd_mesg ); + + # Strip off the header from the received message + $recvd_mesg = substr($recvd_mesg, $ofp->sizeof('ofp_stats_reply')); + + # Unpack each of the ofp_flow_stats messages + my $flow_stats_len = $ofp->sizeof('ofp_flow_stats'); + while (length($recvd_mesg) > 0) { + if (length($recvd_mesg) < $flow_stats_len) {\ + die "Error: Partial flow stats message received"; + } + my $flow_stats = $ofp->unpack('ofp_flow_stats', $recvd_mesg); + + push @{$msg->{'body'}}, $flow_stats; + $recvd_mesg = substr($recvd_mesg, $flow_stats->{'length'}); + } + + #print HexDump ($recvd_mesg); + print Dumper($msg); + + # Verify fields + verify_header( $msg, 'OFPT_STATS_REPLY', $msg_size ); + + # Ensure that we got back one ofp_flow_stats body + compare( "stats_reply flow_stats count", scalar(@{$msg->{'body'}}), '==', 1 ); + + + #wait_for_flow_expired_all( $ofp, $sock, $options_ref ); + + +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_flow_stats_precision/run.pl b/openflow/regress/projects/black_box/regress/test_flow_stats_precision/run.pl new file mode 100755 index 00000000..06dc1ae5 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_flow_stats_precision/run.pl @@ -0,0 +1,191 @@ +#!/usr/bin/perl -w +# test_flow_stats +# This test assumes a lightly loaded switch that can measure and reply to +# flow stats requests within 500ms of receiving the request. + +use strict; +use OF::Includes; + +sub my_test { + + my ( $sock, $options_ref ) = @_; + my $time_threshold = 500000000; + my $port_base = $$options_ref{'port_base'}; + + my $hdr_args = { + version => get_of_ver(), + type => $enums{'OFPT_STATS_REQUEST'}, + length => $ofp->sizeof('ofp_stats_request') + + $ofp->sizeof('ofp_flow_stats_request') + , # should generate automatically! + xid => 0x00000000 + }; + + my $match_args = { + wildcards => 0x3ef, + in_port => 0, + dl_src => [], + dl_dst => [], + dl_vlan => 0, + dl_type => 0x800, + nw_src => ( NF2::IP_hdr::getIP("192.168.200.1") )[0], + nw_dst => ( NF2::IP_hdr::getIP("192.168.201.2") )[0], + nw_proto => 0, + tp_src => 0, + tp_dst => 0 + }; + + my $stats_request_args = { + header => $hdr_args, + type => $enums{'OFPST_FLOW'}, + flags => 0 + }; + + my $body_args = { + match => $match_args, + table_id => 0xff, #match all tables + out_port => $enums{'OFPP_NONE'}, + }; + + my $body = $ofp->pack( 'ofp_flow_stats_request', $body_args ); + + my $stats_request = $ofp->pack( 'ofp_stats_request', $stats_request_args ); + + my $mesg = $stats_request . $body; + + # Send 'stats_request' message + print $sock $mesg; + + # Should add timeout here - will crash if no reply + my $recvd_mesg; + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; + + # Inspect message + my $msg_size = length($recvd_mesg); + + my $msg = $ofp->unpack( 'ofp_stats_reply', $recvd_mesg ); + + #print HexDump ($recvd_mesg); + print Dumper($msg); + + # Verify fields + verify_header( $msg, 'OFPT_STATS_REPLY', $msg_size ); + + #---------------------- + + # add flow mod, send pkt + { + my $in_port_offset = 0; + my $out_port_offset = 1; + my $wildcards = 0x3ef; + my $wait = 5; + + forward_simple( $ofp, $sock, $options_ref, $in_port_offset, + $out_port_offset, $wildcards, 'any', 1 ); + } + + sleep .1; + + # Send 'stats_request' message + print $sock $mesg; + + # Should add timeout here - will crash if no reply + my $recvd_mesg; + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; + + # Inspect message + my $msg_size = length($recvd_mesg); + + my $msg = $ofp->unpack( 'ofp_stats_reply', $recvd_mesg ); + + # Strip off the header from the received message + $recvd_mesg = substr( $recvd_mesg, $ofp->sizeof('ofp_stats_reply') ); + + # Unpack each of the ofp_flow_stats messages + my $flow_stats_len = $ofp->sizeof('ofp_flow_stats'); + while ( length($recvd_mesg) > 0 ) { + if ( length($recvd_mesg) < $flow_stats_len ) { + die "Error: Partial flow stats message received"; + } + my $flow_stats = $ofp->unpack( 'ofp_flow_stats', $recvd_mesg ); + + push @{ $msg->{'body'} }, $flow_stats; + $recvd_mesg = substr( $recvd_mesg, $flow_stats->{'length'} ); + } + + #print HexDump ($recvd_mesg); + print Dumper($msg); + + # Verify fields + verify_header( $msg, 'OFPT_STATS_REPLY', $msg_size ); + + # Ensure that we got back one ofp_flow_stats body + compare( + "stats_reply flow_stats count", + scalar( @{ $msg->{'body'} } ), + '==', 1 + ); + if ( $msg->{'body'}[0]->{'duration_sec'} != 0 ) { + die "Error, duration_sec out of acceptable range"; + } + if ( $msg->{'body'}[0]->{'duration_nsec'} < 100000000 + || $msg->{'body'}[0]->{'duration_nsec'} > (100000000+$time_threshold) ) + { + die "Error, duration_nsec out of acceptable range"; + } + + # Sleep 1 more second to test duration_sec + sleep 1.0; + + # Send 'stats_request' message + print $sock $mesg; + + # Should add timeout here - will crash if no reply + my $recvd_mesg; + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; + + # Inspect message + my $msg_size = length($recvd_mesg); + + my $msg = $ofp->unpack( 'ofp_stats_reply', $recvd_mesg ); + + # Strip off the header from the received message + $recvd_mesg = substr( $recvd_mesg, $ofp->sizeof('ofp_stats_reply') ); + + # Unpack each of the ofp_flow_stats messages + my $flow_stats_len = $ofp->sizeof('ofp_flow_stats'); + while ( length($recvd_mesg) > 0 ) { + if ( length($recvd_mesg) < $flow_stats_len ) { + die "Error: Partial flow stats message received"; + } + my $flow_stats = $ofp->unpack( 'ofp_flow_stats', $recvd_mesg ); + + push @{ $msg->{'body'} }, $flow_stats; + $recvd_mesg = substr( $recvd_mesg, $flow_stats->{'length'} ); + } + + #print HexDump ($recvd_mesg); + print Dumper($msg); + + # Verify fields + verify_header( $msg, 'OFPT_STATS_REPLY', $msg_size ); + + # Ensure that we got back one ofp_flow_stats body + compare( + "stats_reply flow_stats count", + scalar( @{ $msg->{'body'} } ), + '==', 1 + ); + if ( $msg->{'body'}[0]->{'duration_sec'} != 1 ) { + die "Error, duration_sec out of acceptable range"; + } + if ( $msg->{'body'}[0]->{'duration_nsec'} < 100000000 + || $msg->{'body'}[0]->{'duration_nsec'} > (100000000+$time_threshold) ) + { + die "Error, duration_nsec out of acceptable range"; + } + +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_forward_after_expiration/run.pl b/openflow/regress/projects/black_box/regress/test_forward_after_expiration/run.pl new file mode 100755 index 00000000..347051ca --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_after_expiration/run.pl @@ -0,0 +1,111 @@ +#!/usr/bin/perl -w +# test_forward_after_expiration + +use strict; +use OF::Includes; + +sub send_expect_exact { + + my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset ) = @_; + + my $in_port = $in_port_offset + $$options_ref{'port_base'}; + my $out_port = $out_port_offset + $$options_ref{'port_base'}; + + my $test_pkt = get_default_black_box_pkt_len( $in_port, $out_port, $$options_ref{'pkt_len'} ); + + #print HexDump ( $test_pkt->packed ); + + my $wildcards = 0x0; # exact match + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; + + my $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, + $$options_ref{'max_idle'}, $flags, $wildcards ); + + #print HexDump($flow_mod_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent flow_mod message\n"; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + + # Send a packet - ensure packet comes out desired port + nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt->packed ); + nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); +} + +sub send_expect_secchan_nomatch { + + my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len ) = @_; + + my $in_port = $in_port_offset + $$options_ref{'port_base'}; + my $out_port = $out_port_offset + $$options_ref{'port_base'}; + + my $test_pkt2 = get_default_black_box_pkt_len( $in_port, $out_port, $$options_ref{'pkt_len'} ); + + print "sending out eth" + . ( $in_port_offset + 1 ) + . ", expecting response on secchan due to no flow matching\n"; + + # Send a packet - ensure packet comes out desired port + nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt2->packed ); + + my $recvd_mesg; + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; + + # Inspect message + my $msg_size = length($recvd_mesg); + my $expected_size = $ofp->offsetof( 'ofp_packet_in', 'data' ) + length( $test_pkt2->packed ); + compare( "msg size", $msg_size, '==', $expected_size ); + + my $msg = $ofp->unpack( 'ofp_packet_in', $recvd_mesg ); + + #print HexDump ($recvd_mesg); + #print Dumper($msg); + + # Verify fields + + print "Verifying secchan message for packet sent in to eth" . ( $in_port_offset + 1 ) . "\n"; + + verify_header( $msg, 'OFPT_PACKET_IN', $msg_size ); + + compare( "total len", $$msg{'total_len'}, '==', length( $test_pkt2->packed ) ); + compare( "in_port", $$msg{'in_port'}, '==', $in_port ); + compare( "reason", $$msg{'reason'}, '==', $enums{'OFPR_NO_MATCH'} ); + + # verify packet was unchanged! + my $recvd_pkt_data = substr( $recvd_mesg, $ofp->offsetof( 'ofp_packet_in', 'data' ) ); + if ( $recvd_pkt_data ne $test_pkt2->packed ) { + die "ERROR: sending from eth" + . $in_port + 1 + . " received packet data didn't match packet sent\n"; + } + +} + +sub test_forward_after_expiration { + + my ( $ofp, $sock, $options_ref, $i, $j, $wildcards ) = @_; + + my $max_idle = $$options_ref{'max_idle'}; + my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_total = $$options_ref{'pkt_total'}; + + send_expect_exact( $ofp, $sock, $options_ref, $i, $j); + print "waiting for flow to expire\n"; + wait_for_flow_expired_all( $ofp, $sock, $options_ref ); + usleep($$options_ref{'send_delay'}); + send_expect_secchan_nomatch( $ofp, $sock, $options_ref, $i, $j); +} + +sub my_test { + + my ($sock, $options_ref) = @_; + + # send from every port to every other port + for_all_port_pairs( $ofp, $sock, $options_ref, \&test_forward_after_expiration, 0x0); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_any_port/run.pl b/openflow/regress/projects/black_box/regress/test_forward_any_port/run.pl new file mode 100755 index 00000000..83c07e1d --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_any_port/run.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl -w +# test_forward_any_port + +use strict; +use OF::Includes; + +sub forward_any { + + forward_simple(@_, 'any'); +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_any, 0xfffff); +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_forward_bandwidth_fixed/run.pl b/openflow/regress/projects/black_box/regress/test_forward_bandwidth_fixed/run.pl new file mode 100755 index 00000000..44ac6ec9 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_bandwidth_fixed/run.pl @@ -0,0 +1,83 @@ +#!/usr/bin/perl -w +# test_forward_bandwidth_fixed + +use strict; +use OF::Includes; + +my $pkt_len = 1512; +my $pkt_total = 1000; +my $max_idle = 2; + +sub send_expect_exact { + + my ( $ofp, $sock, $in_port, $out_port, $max_idle, $pkt_len ) = @_; + my %delta; + + # in_port refers to the flow mod entry's input + + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + src_port => 1, + dst_port => 0 + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + #print HexDump ( $test_pkt->packed ); + + my $wildcards = 0x0; # exact match + #my $wildcards = 0x2; # only wildcard the vlan + #my $wildcards = 0x2FF; # exact match + #my $wildcards = 0x3FE; # exact match on switch in port + #my $wildcards = 0x3DF; # exact match on src ip + #my $wildcards = 0x1; # exact match on eth src/dest/eth frame/ipsrcdest/128ipproto/256port source + #my $wildcards = 0x3BF; # exact match on dest ip + #my $wildcards = 0x3FD; # exact match on vlan + #my $wildcards = 0x3FB; # exact match on ether source + #my $wildcards = 0x3F7; # exact match on ether dest + my $flags = 0x0; # don't send flow expiry + + my $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, + $max_idle, $flags, $wildcards ); + + #print HexDump($flow_mod_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent flow_mod message\n"; + + usleep(200000); + my @start_time = gettimeofday(); + for (my $k = 0; $k < $pkt_total; $k++) { + send_and_count( nftest_get_iface( "eth" . ( $in_port + 1 ) ), + $test_pkt->packed, \%delta ); + expect_and_count( nftest_get_iface( "eth" . ( $out_port + 1 ) ), + $test_pkt->packed, \%delta ); + } + (my $second, my $micro) = tv_interval(\@start_time); + my $time_elapsed = ($second + $micro * 1e-6); + my $bw_result = ($pkt_total * $pkt_len * 8) / $time_elapsed; + print "PACKET LENGTH: $pkt_len \n"; + print "PACKETS SENT: $pkt_total\n"; + print "TIME ELAPSED: $time_elapsed \n"; + print "RESULTING BW: $bw_result bits/sec \n"; + +} + +sub my_test { + + my ($sock, $options_ref) = @_; + + my $inport = 0; + my $outport = 1; + print "Checking forwarding bandwidth from $inport to $outport\n"; + send_expect_exact( $ofp, $sock, $inport, $outport, $max_idle, $pkt_len ); + wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); +} + +run_black_box_test( \&my_test ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_bandwidth_random/run.pl b/openflow/regress/projects/black_box/regress/test_forward_bandwidth_random/run.pl new file mode 100755 index 00000000..4fa05282 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_bandwidth_random/run.pl @@ -0,0 +1,84 @@ +#!/usr/bin/perl -w +# test_forward_bandwidth_fixed + +use strict; +use OF::Includes; + +my $pkt_total = 1000; +my $max_idle = 2; + +# Maximum and minimum packet sizes +my $min_length = 64; +my $max_length = 1512; + +sub send_expect_exact { + + my ( $ofp, $sock, $in_port, $out_port, $max_idle) = @_; + my %delta; + + # in_port refers to the flow mod entry's input + + my @packets; + my $bytes = 0; + for (my $i = 0; $i < $pkt_total; $i++) { + my $pkt_len = int(rand($max_length - $min_length)) + $min_length; + $bytes += $pkt_len; + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port + 1 ), + dst_ip => "192.168.201." . ( $out_port + 1 ), + ttl => 64, + len => $pkt_len, + src_port => 1, + dst_port => 0 + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + push @packets, $test_pkt; + } + + + my $wildcards = 0x1; # wild card on input port + my $flags = 0x0; # don't send flow expiry + + my $test_pkt = pop @packets; + my $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, + $max_idle, $flags, $wildcards ); + push @packets, $test_pkt; + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent flow_mod message\n"; + + usleep(200000); + my @start_time = gettimeofday(); + for (my $k = 0; $k < $pkt_total; $k++) { + my $packet = pop @packets; + my $randport = int(rand(2)); + send_and_count( nftest_get_iface( "eth" . ( $randport + 1 ) ), + $packet->packed, \%delta ); + expect_and_count( nftest_get_iface( "eth" . ( $out_port + 1 ) ), + $packet->packed, \%delta ); + } + (my $second, my $micro) = tv_interval(\@start_time); + my $time_elapsed = ($second + $micro * 1e-6); + my $bw_result = ($bytes * 8) / $time_elapsed; + print "PACKETS SENT: $pkt_total\n"; + print "BYTES SENT: $bytes\n"; + print "TIME ELAPSED: $time_elapsed \n"; + print "RESULTING BW: $bw_result bits/sec \n"; + return $bytes; +} + +sub my_test { + + my ($sock, $options_ref) = @_; + + my $inport = 0; + my $outport = 3; + my $bytes_sent = send_expect_exact( $ofp, $sock, $inport, $outport, $max_idle ); + wait_for_flow_expired_total_bytes( $ofp, $sock, $options_ref, $bytes_sent, $pkt_total ); +} + +run_black_box_test( \&my_test ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_broadcast_exact_port/run.pl b/openflow/regress/projects/black_box/regress/test_forward_broadcast_exact_port/run.pl new file mode 100755 index 00000000..03bf655b --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_broadcast_exact_port/run.pl @@ -0,0 +1,64 @@ +#!/usr/bin/perl -w +# test_forward_exact_port + +use strict; +use OF::Includes; + +sub forward_broadcast { + + my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $wildcards, $type, $nowait ) = @_; + + my $in_port = $in_port_offset + $$options_ref{'port_base'}; + my $out_port; + + $out_port = $out_port_offset + $$options_ref{'port_base'}; + + my $len = $$options_ref{'pkt_len'}; + my $pkt_args = { + DA => "FF:FF:FF:FF:FF:FF", + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168." . ( $in_port ) . "." . ( $out_port ), + dst_ip => "255.255.255.255", + ttl => 64, + len => $len, + src_port => 1, + dst_port => 0 + }; + my $test_pkt = new NF2::UDP_pkt(%$pkt_args); + + my $flow_mod_pkt; + + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; + $flow_mod_pkt = create_flow_mod_from_udp($ofp, $test_pkt, $in_port, $out_port, $$options_ref{'max_idle'}, $flags, $wildcards); + + # Send 'flow_mod' message + syswrite( $sock, $flow_mod_pkt ); + print "sent flow_mod message\n"; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + + nftest_send( "eth" . ($in_port_offset + 1), $test_pkt->packed ); + + # expect single packet + print "expect single packet\n"; + nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); + + print "wait \n"; + wait_for_flow_expired_all( $ofp, $sock, $options_ref ); +} + + +sub forward_port { + + forward_broadcast(@_, 'port'); +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_port, 0x0); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_all/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_all/run.pl new file mode 100755 index 00000000..052ebbeb --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_exact_all/run.pl @@ -0,0 +1,30 @@ +#!/usr/bin/perl -w +# test_forward_exact_all + +use strict; +use OF::Includes; + +sub forward_all { + + forward_simple(@_, 'all'); +} + +sub forward_all_vlan { + my $vlan_id = 0xa5f3; + #[15:13] priority, [11:0] vlan id + #The value was chosen at random + forward_simple(@_, 'all', undef, undef, $vlan_id); +} + + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_ports( $ofp, $sock, $options_ref, \&forward_all, 0x0); + if ( not defined( $$options_ref{'no_vlan'} ) ) { + for_all_ports( $ofp, $sock, $options_ref, \&forward_all_vlan, 0x0); + } +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_arp_all/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_arp_all/run.pl new file mode 100755 index 00000000..0f44f91f --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_exact_arp_all/run.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl -w +# test_forward_exact_arp_all + +use strict; +use OF::Includes; + +sub forward_all { + + forward_simple_arp(@_, 'all', 0); # 0: fool_flg = off +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_ports( $ofp, $sock, $options_ref, \&forward_all, 0x0); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_arp_controller/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_arp_controller/run.pl new file mode 100755 index 00000000..e7de7bad --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_exact_arp_controller/run.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl -w +# test_forward_exact_arp_controller + +use strict; +use OF::Includes; + +sub forward_controller { + + forward_simple_arp(@_, 'controller', 0); # 0: fool_flg = off +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_ports( $ofp, $sock, $options_ref, \&forward_controller, 0x0); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_arp_fool/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_arp_fool/run.pl new file mode 100755 index 00000000..076dfc42 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_exact_arp_fool/run.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl -w +# test_forward_exact_arp_fool + +use strict; +use OF::Includes; + +sub forward_port { + + forward_simple_arp(@_, 'port', 1); # 1: fool_flg=on +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_port, 0x0); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_arp_port/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_arp_port/run.pl new file mode 100755 index 00000000..b0af883e --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_exact_arp_port/run.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl -w +# test_forward_exact_arp_port + +use strict; +use OF::Includes; + +sub forward_port { + + forward_simple_arp(@_, 'port', 0); # 0: fool_flg = off +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_port, 0x0); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_controller/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_controller/run.pl new file mode 100755 index 00000000..e0888d16 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_exact_controller/run.pl @@ -0,0 +1,32 @@ +#!/usr/bin/perl -w +# test_forward_exact_controller + +use strict; +use OF::Includes; + +use strict; +use OF::Includes; + +sub forward_controller { + + forward_simple(@_, 'controller'); +} + +sub forward_controller_vlan { + my $vlan_id = 0xc123; + #[15:13] priority, [11:0] vlan id + #The value was chosen at random + forward_simple(@_, 'controller', undef, undef, $vlan_id); +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_ports( $ofp, $sock, $options_ref, \&forward_controller, 0x0); + if ( not defined( $$options_ref{'no_vlan'} ) ) { + for_all_ports( $ofp, $sock, $options_ref, \&forward_controller_vlan, 0x0); + } +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_all/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_all/run.pl new file mode 100755 index 00000000..3b1f6bfd --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_all/run.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl -w +# test_forward_exact_icmp_all + +use strict; +use OF::Includes; + +sub forward_all { + + forward_simple_icmp(@_, 'all', 0); # 0: fool_flg = off +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_ports( $ofp, $sock, $options_ref, \&forward_all, 0x0); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_controller/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_controller/run.pl new file mode 100755 index 00000000..c07debe8 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_controller/run.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl -w +# test_forward_exact_icmp_controller + +use strict; +use OF::Includes; + +sub forward_controller { + + forward_simple_icmp(@_, 'controller', 0); # 0: fool_flg = off +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_ports( $ofp, $sock, $options_ref, \&forward_controller, 0x0); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_fool/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_fool/run.pl new file mode 100755 index 00000000..dee5a6c2 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_fool/run.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl -w +# test_forward_exact_icmp_fool + +use strict; +use OF::Includes; + +sub forward_port { + + forward_simple_icmp(@_, 'port', 1); # 1: fool_flg=on +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_port, 0x0); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_port/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_port/run.pl new file mode 100755 index 00000000..100bc3ad --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_port/run.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl -w +# test_forward_exact_icmp_port + +use strict; +use OF::Includes; + +sub forward_port { + + forward_simple_icmp(@_, 'port', 0); # 0: fool_flg = off +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_port, 0x0); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_modify_action/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_modify_action/run.pl new file mode 100755 index 00000000..805c9ad9 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_exact_modify_action/run.pl @@ -0,0 +1,42 @@ +#!/usr/bin/perl -w +# test_forward_exact_modify_action + +use strict; +use OF::Includes; + +sub forward_port { + + my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, + $wildcards ) = @_; + + my @chg_field; + if ( not defined( $$options_ref{'no_vlan'} ) ) { + @chg_field = ('vlan_vid', 'vlan_pcp', 'dl_src', 'dl_dst', 'nw_src', 'nw_dst', 'tp_src', 'tp_dst'); + } else { + @chg_field = ('dl_src', 'dl_dst', 'nw_src', 'nw_dst', 'tp_src', 'tp_dst'); + } + foreach (@chg_field) { + forward_simple(@_, 'port', undef, $_ ); + } +} + +sub forward_port_vlan { + my @chg_field = ('strip_vlan', 'vlan_vid', 'vlan_pcp', 'dl_src', 'dl_dst', 'nw_src', 'nw_dst', 'tp_src', 'tp_dst'); + my $vlan = 0x65a1; + #[15:13]:vlan_pcp, [11:0]:vlan_vid + #The value was chosen at random + foreach (@chg_field) { + forward_simple(@_, 'port', undef, $_, $vlan ); + } +} +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_port, 0x0); + if ( not defined( $$options_ref{'no_vlan'} ) ) { + for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_port_vlan, 0x0); + } +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_port/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_port/run.pl new file mode 100755 index 00000000..c3fc215f --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_exact_port/run.pl @@ -0,0 +1,27 @@ +#!/usr/bin/perl -w +# test_forward_exact_port + +use strict; +use OF::Includes; + +sub forward_unicast_port { + forward_simple(@_, 'port'); +} + +sub forward_unicast_vlan_port { + my $vlan_id = 0xea5a; + #[15:13] priority, [11:0] vlan id + #The value was chosen at random + forward_simple(@_, 'port', undef, undef, $vlan_id); +} + +sub my_test { + my ($sock, $options_ref) = @_; + + for_all_port_pairs($ofp, $sock, $options_ref, \&forward_unicast_port, 0x0); + if ( not defined( $$options_ref{'no_vlan'} ) ) { + for_all_port_pairs($ofp, $sock, $options_ref, \&forward_unicast_vlan_port, 0x0); + } +} + +run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_forward_overlapping_flow_entries/run.pl b/openflow/regress/projects/black_box/regress/test_forward_overlapping_flow_entries/run.pl new file mode 100755 index 00000000..6ed870e6 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_overlapping_flow_entries/run.pl @@ -0,0 +1,86 @@ +#!/usr/bin/perl -w +# test_forward_overlapping_flow_entries + +use strict; +use OF::Includes; + +sub send_expect_multi_flow { + + my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len ) = @_; + + my $in_port = $in_port_offset + $$options_ref{'port_base'}; + my $out_port = $out_port_offset + $$options_ref{'port_base'}; + + my $test_pkt = get_default_black_box_pkt_len( $in_port, $out_port, $pkt_len ); + + #print HexDump ( $test_pkt->packed ); + + my $wildcards = 0x0; # exact match + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; + + my $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, + $enums{'OFPP_ALL'}, $max_idle, $flags, $wildcards ); + + #print HexDump($flow_mod_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent exact match flow_mod message\n"; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + + $wildcards = 0x1fffff; # wildcard everything + + # (send to controller) + $flow_mod_pkt = create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, + $enums{'OFPP_CONTROLLER'}, 2, $flags, $wildcards ); + + #print HexDump($flow_mod_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent wildcard match flow_mod message\n"; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + + # Send a packet - ensure packet comes out desired port + nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt->packed ); + + for ( my $k = 0 ; $k < $$options_ref{'num_ports'}; $k++ ) { + if ( $k != $in_port_offset ) { + nftest_expect( "eth" . ( $k + 1 ), $test_pkt->packed ); + } + } +} + +sub my_test { + + my ($sock, $options_ref) = @_; + + #my $max_idle = $$options_ref{'max_idle'}; + my $max_idle = 5; + my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_total = $$options_ref{'pkt_total'}; + + my $num_ports = $$options_ref{'num_ports'}; + + my $j = 0; + + # send from every port, receive on every port except the send port + #for ( my $i = 0 ; $i < $num_ports ; $i++ ) { + my $i = 0; + my $j = ($i + 1) % $num_ports; + print "sending from $i to (all ports but $i)\n"; + send_expect_multi_flow( $ofp, $sock, $options_ref, $i, $j, $max_idle, $pkt_len ); + print "waiting for first flow to expire\n"; + wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, 0 ); + print "waiting for second flow to expire\n"; + wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); + #} +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_all/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_all/run.pl new file mode 100755 index 00000000..51a504b8 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_wildcard_all/run.pl @@ -0,0 +1,172 @@ +#!/usr/bin/perl -w +# test_forward_wildcard_all + +use strict; +use OF::Includes; + +sub forward_wc_all { + + forward_simple(@_, 'all'); +} + +sub forward_wc_all_vlan { + my $vlan_id = 0x25ae; + #[15:13] priority, [11:0] vlan id + #The value was chosen at random + forward_simple(@_, 'all', undef, undef, $vlan_id); +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_all); + if ( not defined( $$options_ref{'no_vlan'} ) ) { + for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_all_vlan); + } +} + +run_black_box_test( \&my_test, \@ARGV ); + +#sub send_expect_exact { +# +# my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $wildcards ) = @_; +# +# my $in_port = $in_port_offset + $$options_ref{'port_base'}; +# my $out_port = $enums{'OFPP_ALL'}; # all physical ports except the input +# +# printf( "Wildcards are: %04x\n", $wildcards ); +# +# # in_port refers to the flow mod entry's input +# +# # This packet will always match +# my $test_pkt = get_default_black_box_pkt_len( $in_port, $out_port, $$options_ref{'pkt_len'} ); +# +# # This packet will always miss +# my $test_pkt2 = get_default_black_box_pkt_len( $in_port + 5, $out_port + 5, $$options_ref{'pkt_len'} ); +# +# print HexDump ( $test_pkt->packed ); +# print HexDump ( $test_pkt2->packed ); +# +# my $flow_mod_pkt = +# create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $$options_ref{'max_idle'}, $wildcards ); +# +# #print HexDump($flow_mod_pkt); +# +# # Send 'flow_mod' message +# print $sock $flow_mod_pkt; +# print "sent flow_mod message\n"; +# +# # Give OF switch time to process the flow mod +# usleep($$options_ref{'send_delay'}); +# +# # Send a packet - ensure packet comes out desired port +# nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt->packed ); +# +# for ( my $k = 0 ; $k < $$options_ref{'num_ports'} ; $k++ ) { +# if ( $k != $in_port_offset ) { +# nftest_expect( "eth" . ( $k + 1 ), $test_pkt->packed ); +# } +# } +# +# print "Matching packet sent\n"; +# +# #nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt2->packed ); +# +## #print "Non-matching packet sent\n"; +## my $recvd_mesg; +## sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; +## +## # Inspect message +## my $msg_size = length($recvd_mesg); +## my $expected_size = $ofp->offsetof( 'ofp_packet_in', 'data' ) + length( $test_pkt2->packed ); +## +## print HexDump ($recvd_mesg); +## +## #print "Comparing sizes $msg_size and $expected_size\n"; +## compare( "msg size", $msg_size, '==', $expected_size ); +## +## my $msg = $ofp->unpack( 'ofp_packet_in', $recvd_mesg ); +## +## #print HexDump ($recvd_mesg); +## #print Dumper($msg); +## +## # Verify fields +## verify_header( $msg, 'OFPT_PACKET_IN', $msg_size ); +## +## compare( "total len", $$msg{'total_len'}, '==', length( $test_pkt2->packed ) ); +## compare( "in_port", $$msg{'in_port'}, '==', $in_port ); +## compare( "reason", $$msg{'reason'}, '==', $enums{'OFPR_NO_MATCH'} ); +## +## # verify packet was unchanged! +## my $recvd_pkt_data = substr( $recvd_mesg, $ofp->offsetof( 'ofp_packet_in', 'data' ) ); +## if ( $recvd_pkt_data ne $test_pkt2->packed ) { +## die "ERROR: received packet data didn't match packet sent\n"; +## } +# +#} +# +#sub my_test { +# +# my ( $sock, $options_ref ) = @_; +# my $j = $enums{'OFPP_FLOOD'}; +# +# my $max_idle = $$options_ref{'max_idle'}; +# my $pkt_len = $$options_ref{'pkt_len'}; +# my $pkt_total = $$options_ref{'pkt_total'}; +# +# # send from every port to every other port +# for ( my $i = 0 ; $i < 4 ; $i++ ) { +# +# print "sending from $i to $j\n"; +# +# #Very hackish, but basically iterate through the possibilities for +# #wildcarding one at a time. +# print "wildcards 0x0001 : IN_PORT\n"; +# send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0001 ); +# wait_for_flow_expired_all( $ofp, $sock, $options_ref ); +# +# #DL_VLAN fixed at 0xffff currently. +# #print "wildcards 0x0002 : DL_VLAN\n"; +# #send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0002); +# #wait_for_flow_expired_all( $ofp, $sock, $options_ref ); +# +# print "wildcards 0x0004 : DL_SRC\n"; +# send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0004 ); +# wait_for_flow_expired_all( $ofp, $sock, $options_ref ); +# +# print "wildcards 0x0008 : DL_DST\n"; +# send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0008 ); +# wait_for_flow_expired_all( $ofp, $sock, $options_ref ); +# +# #DL_TYPE fixed at 0x0800 currently. +# #print "wildcards 0x0010 : DL_TYPE\n"; +# #send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0010); +# #wait_for_flow_expired_all( $ofp, $sock, $options_ref ); +# +# print "wildcards 0x0020 : NW_SRC\n"; +# send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0020 ); +# wait_for_flow_expired_all( $ofp, $sock, $options_ref ); +# +# print "wildcards 0x0040 : NW_DST\n"; +# send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0040 ); +# wait_for_flow_expired_all( $ofp, $sock, $options_ref ); +# +# #NW_PROTO fixed at 17 currently. +# #print "wildcards 0x0080 : NW_PROTO\n"; +# #send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0080); +# #wait_for_flow_expired_all( $ofp, $sock, $options_ref ); +# +# print "wildcards 0x0100 : TP_SRC\n"; +# send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0100 ); +# wait_for_flow_expired_all( $ofp, $sock, $options_ref ); +# +# print "wildcards 0x0200 : TP_SRC\n"; +# send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0200 ); +# wait_for_flow_expired_all( $ofp, $sock, $options_ref ); +# +# } +#} +# +#run_black_box_test( \&my_test, \@ARGV ); +# diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_all/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_all/run.pl new file mode 100755 index 00000000..ccebe303 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_all/run.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl -w +# test_forward_wildcard_arp_all + +use strict; +use OF::Includes; + +sub forward_wc_all { + + forward_simple_arp(@_, 'all', 0); # 0: fool_flg = off +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_all); +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_controller/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_controller/run.pl new file mode 100755 index 00000000..90e8b5ad --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_controller/run.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl -w +# test_forward_wildcard_arp_controller + +use strict; +use OF::Includes; + +sub forward_wc_controller { + + forward_simple_arp(@_, 'controller', 0); # 0: fool_flg = off +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_controller); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_fool/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_fool/run.pl new file mode 100755 index 00000000..0b4d5249 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_fool/run.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl -w +# test_forward_wildcard_arp_port + +use strict; +use OF::Includes; + +sub forward_wc_port { + forward_simple_arp(@_, 'port', 1); # 1: fool_flg = on +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_port); +} + +run_black_box_test( \&my_test, \@ARGV ); + + diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_port/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_port/run.pl new file mode 100755 index 00000000..ef8cb8ab --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_port/run.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl -w +# test_forward_wildcard_arp_port + +use strict; +use OF::Includes; + +sub forward_wc_port { + forward_simple_arp(@_, 'port', 0); # 0: fool_flg = off +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_port); +} + +run_black_box_test( \&my_test, \@ARGV ); + + diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_controller/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_controller/run.pl new file mode 100755 index 00000000..125c5071 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_wildcard_controller/run.pl @@ -0,0 +1,30 @@ +#!/usr/bin/perl -w +# test_forward_wildcard_controller + +use strict; +use OF::Includes; + +sub forward_wc_controller { + + forward_simple(@_, 'controller'); +} + +sub forward_wc_controller_vlan { + my $vlan_id = 0x4abc; + #[15:13] priority, [11:0] vlan id + #The value was chosen at random + forward_simple(@_, 'controller', undef, undef, $vlan_id); +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_controller); + if ( not defined( $$options_ref{'no_vlan'} ) ) { + for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_controller_vlan); + } +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_all/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_all/run.pl new file mode 100755 index 00000000..7ccdea0b --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_all/run.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl -w +# test_forward_wildcard_icmp_all + +use strict; +use OF::Includes; + +sub forward_wc_all { + + forward_simple_icmp(@_, 'all', 0); # 0: fool_flg = off +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_all); +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_controller/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_controller/run.pl new file mode 100755 index 00000000..21a0c608 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_controller/run.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl -w +# test_forward_wildcard_icmp_controller + +use strict; +use OF::Includes; + +sub forward_wc_controller { + + forward_simple_icmp(@_, 'controller', 0); # 0: fool_flg = off +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_controller); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_fool/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_fool/run.pl new file mode 100755 index 00000000..eacfb9d5 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_fool/run.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl -w +# test_forward_wildcard_icmp_port + +use strict; +use OF::Includes; + +sub forward_wc_port { + forward_simple_icmp(@_, 'port', 1); # 1: fool_flg = on +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_port); +} + +run_black_box_test( \&my_test, \@ARGV ); + + diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_port/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_port/run.pl new file mode 100755 index 00000000..c428a9e5 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_port/run.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl -w +# test_forward_wildcard_icmp_port + +use strict; +use OF::Includes; + +sub forward_wc_port { + forward_simple_icmp(@_, 'port', 0); # 0: fool_flg = off +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_port); +} + +run_black_box_test( \&my_test, \@ARGV ); + + diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_modify_action/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_modify_action/run.pl new file mode 100755 index 00000000..ca32aaaf --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_wildcard_modify_action/run.pl @@ -0,0 +1,35 @@ +#!/usr/bin/perl -w +# test_forward_wildcard_modify_action + +use strict; +use OF::Includes; + +sub forward_wc_port { + my @chg_field = ('vlan_vid', 'vlan_pcp','dl_src', 'dl_dst', 'nw_src', 'nw_dst', 'tp_src', 'tp_dst'); + foreach (@chg_field) { + forward_simple(@_, 'port', undef, $_ ); + } +} + + +sub forward_wc_port_vlan { + my @chg_field = ('strip_vlan', 'vlan_vid','vlan_pcp','dl_src', 'dl_dst', 'nw_src', 'nw_dst', 'tp_src', 'tp_dst'); + my $vlan_id = 0xa344; + #The value was chosen at random + foreach (@chg_field) { + forward_simple(@_, 'port', undef, $_, $vlan_id); + } +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_port); + if ( not defined( $$options_ref{'no_vlan'} ) ) { + for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_port_vlan); + } +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_port/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_port/run.pl new file mode 100755 index 00000000..934da7cc --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_wildcard_port/run.pl @@ -0,0 +1,97 @@ +#!/usr/bin/perl -w +# test_forward_wildcard_port + +use strict; +use OF::Includes; + +sub forward_wc_port { + + forward_simple(@_, 'port'); +} + +sub forward_wc_port_vlan { + my $vlan_id = 0x8ea5; + #[15:13] priority, [11:0] vlan id + #The value was chosen at random + forward_simple(@_, 'port', undef, undef, $vlan_id); +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_port); + if ( not defined( $$options_ref{'no_vlan'} ) ) { + for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_port_vlan); + } +} + +run_black_box_test( \&my_test, \@ARGV ); + +#sub send_expect_exact { +# +# my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len, $wildcards ) = @_; +# +# my $in_port = $in_port_offset + $$options_ref{'port_base'}; +# my $out_port = $out_port_offset + $$options_ref{'port_base'}; +# +# printf( "Wildcards are: %04x\n", $wildcards ); +# +# # This packet will always match +# my $test_pkt = get_default_black_box_pkt_len( $in_port, $out_port, $pkt_len ); +# +# # This packet will always miss +# my $test_pkt2 = get_default_black_box_pkt_len( $in_port + 5, $out_port + 5, $pkt_len ); +# +# #print HexDump ( $test_pkt->packed ); +# +# my $flow_mod_pkt = +# create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $wildcards ); +# +# #print HexDump($flow_mod_pkt); +# +# # Send 'flow_mod' message +# print $sock $flow_mod_pkt; +# print "sent flow_mod message\n"; +# +# # Give OF switch time to process the flow mod +# usleep($$options_ref{'send_delay'}); +# +# # Send a packet - ensure packet comes out desired port +# nftest_send( "eth" . ($in_port_offset + 1), $test_pkt->packed ); +# nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); +# print "Matching packet sent\n"; +# +# nftest_send( "eth" . ($in_port_offset + 1), $test_pkt2->packed ); +# +# print "Non-matching packet sent\n"; +# my $recvd_mesg; +# sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; +# +# # Inspect message +# my $msg_size = length($recvd_mesg); +# my $expected_size = $ofp->offsetof( 'ofp_packet_in', 'data' ) + length( $test_pkt2->packed ); +# +# #print "Comparing sizes $msg_size and $expected_size\n"; +# compare( "msg size", $msg_size, '==', $expected_size ); +# +# my $msg = $ofp->unpack( 'ofp_packet_in', $recvd_mesg ); +# +# #print HexDump ($recvd_mesg); +# #print Dumper($msg); +# +# # Verify fields +# verify_header( $msg, 'OFPT_PACKET_IN', $msg_size ); +# +# compare( "total len", $$msg{'total_len'}, '==', length( $test_pkt2->packed ) ); +# compare( "in_port", $$msg{'in_port'}, '==', $in_port ); +# compare( "reason", $$msg{'reason'}, '==', $enums{'OFPR_NO_MATCH'} ); +# +# # verify packet was unchanged! +# my $recvd_pkt_data = substr( $recvd_mesg, $ofp->offsetof( 'ofp_packet_in', 'data' ) ); +# if ( $recvd_pkt_data ne $test_pkt2->packed ) { +# die "ERROR: received packet data didn't match packet sent\n"; +# } +# +#} + diff --git a/openflow/regress/projects/black_box/regress/test_hello/run.pl b/openflow/regress/projects/black_box/regress/test_hello/run.pl new file mode 100755 index 00000000..e1bbdb23 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_hello/run.pl @@ -0,0 +1,16 @@ +#!/usr/bin/perl -w +# test_hello + +use strict; +require OF::Includes; + +sub my_test { + + my ($sock, $options_ref) = @_; + + + + # hello sequence automatically done by test harness! +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_ip_offset/run.pl b/openflow/regress/projects/black_box/regress/test_ip_offset/run.pl new file mode 100755 index 00000000..0aa567b3 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_ip_offset/run.pl @@ -0,0 +1,85 @@ +#!/usr/bin/perl -w +# test_ip_offset + +use strict; +use OF::Includes; + +sub send_expect_exact { + + my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len ) = @_; + + my $in_port = $in_port_offset + $$options_ref{'port_base'}; + my $out_port = $out_port_offset + $$options_ref{'port_base'}; + + # in_port refers to the flow mod entry's input + + my $test_pkt_frag_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + frag => 0x2fff, # IP_frag > IP_len + src_port => 1, + dst_port => 0 + }; + my $test_pkt_frag = new NF2::UDP_pkt(%$test_pkt_frag_args); + + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + frag => 0, + src_port => 0, + dst_port => 0 + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + #print HexDump ( $test_pkt->packed ); + + my $wildcards = 0x0; # exact match + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; + + my $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); + + #print HexDump($flow_mod_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent flow_mod message\n"; + usleep($$options_ref{'send_delay'}); + + # Send a packet - ensure packet comes out desired port + nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt_frag->packed ); + nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt_frag->packed ); +} + +sub test_ip_offset { + + my ( $ofp, $sock, $options_ref, $i, $j, $wildcards ) = @_; + + my $max_idle = $$options_ref{'max_idle'}; + my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_total = $$options_ref{'pkt_total'}; + + my $port_base = $$options_ref{'port_base'}; + my $num_ports = $$options_ref{'num_ports'}; + + send_expect_exact( $ofp, $sock, $options_ref, $i, $j, $max_idle, $pkt_len ); + wait_for_flow_expired_all( $ofp, $sock, $options_ref ); +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + # send from every port to every other port + for_all_port_pairs( $ofp, $sock, $options_ref, \&test_ip_offset, 0x0); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_ip_options/run.pl b/openflow/regress/projects/black_box/regress/test_ip_options/run.pl new file mode 100755 index 00000000..ce8f9266 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_ip_options/run.pl @@ -0,0 +1,76 @@ +#!/usr/bin/perl -w +# test_ip_options + +use strict; +use OF::Includes; + +sub send_expect_exact { + + my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len ) = @_; + + my $in_port = $in_port_offset + $$options_ref{'port_base'}; + my $out_port = $out_port_offset + $$options_ref{'port_base'}; + + # in_port refers to the flow mod entry's input + my @ipopt = ( 0x44, 0x08, 0x08, 0x00, 0x11, 0x22, 0x33, 0x44 ); #IP timestamp option + my $num_ipopt = @ipopt; + + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + ip_hdr_len => 5 + ( $#ipopt + 1 ) / 4, + ip_options => \@ipopt, + src_port => 1, + dst_port => 0 + + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + #print ("pkt_len = $pkt_len\n"); + #print HexDump ( $test_pkt->packed ); + + my $wildcards = 0x0; # exact match + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; + + my $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); + #print HexDump($flow_mod_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent flow_mod message\n"; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + + # Send a packet - ensure packet comes out desired port + nftest_send("eth" . ( $in_port_offset + 1 ), $test_pkt->packed ); + nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); +} + +sub test_ip_options { + + my ( $ofp, $sock, $options_ref, $i, $j, $wildcards ) = @_; + + my $max_idle = $$options_ref{'max_idle'}; + #my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_len = 68; + my $pkt_total = $$options_ref{'pkt_total'}; + + send_expect_exact( $ofp, $sock, $options_ref, $i, $j, $max_idle, $pkt_len ); + wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); +} + +sub my_test { + + my ($sock, $options_ref) = @_; + + # send from every port to every other port + for_all_port_pairs( $ofp, $sock, $options_ref, \&test_ip_options, 0x0); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_ip_protocol/case-c.pl b/openflow/regress/projects/black_box/regress/test_ip_protocol/case-c.pl new file mode 100755 index 00000000..4637c860 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_ip_protocol/case-c.pl @@ -0,0 +1,150 @@ +#!/usr/bin/perl -w +# test_ip_protocol (case c, not TCP nor UDP) + +use strict; +use OF::Includes; + +sub send_expect_exact { + + my ( $ofp, $sock, $in_port, $out_port, $max_idle, $pkt_len ) = @_; + + # in_port refers to the flow mod entry's input + + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + src_port => 70, + dst_port => 80 + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + ## Change protocol field + my $iphdr=$test_pkt->{'IP_hdr'}; + $$iphdr->proto(0x13); # overwrite protocol filed in IP header + + #print HexDump ( $test_pkt->packed ); + + my $wildcards = 0x0; # exact match + + my $flow_mod_pkt = + create_flow_mod_from_pseudo_tcp( $ofp, $test_pkt, $in_port, $out_port, + $max_idle, $wildcards ); + + #print HexDump($flow_mod_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent flow_mod message\n"; + usleep(100000); + + # Send a packet - ensure packet comes out desired port + nftest_send( "eth" . ( $in_port + 1 ), + $test_pkt->packed ); + nftest_expect( "eth" . ( $out_port + 1 ), + $test_pkt->packed ); +} + +sub test_ip_protocol { + + my ( $ofp, $sock, $options_ref, $i, $j, $wildcards ) = @_; + + my $max_idle = $$options_ref{'max_idle'}; + my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_total = $$options_ref{'pkt_total'}; + + send_expect_exact( $ofp, $sock, $i, $j, $max_idle, $pkt_len ); + wait_for_flow_expired_all( $ofp, $sock, $options_ref ); +} + +sub my_test { + + my ($sock, $options_ref) = @_; + + # send from every port to every other port + for_all_port_pairs( $ofp, $sock, $options_ref, \&test_ip_protocol, 0x0); +} + +sub create_flow_mod_from_pseudo_tcp { + + my ( $ofp, $udp_pkt, $in_port, $out_port, $max_idle, $wildcards ) = @_; + + my $hdr_args = { + version => get_of_ver(), + type => $enums{'OFPT_FLOW_MOD'}, + length => $ofp->sizeof('ofp_flow_mod') + $ofp->sizeof('ofp_action'), + xid => 0x0000000 + }; + + # might be cleaner to convert the exported colon-hex MAC addrs + #print ${$udp_pkt->{Ethernet_hdr}}->SA . "\n"; + #print ${$test_pkt->{Ethernet_hdr}}->SA . "\n"; + my $ref_to_eth_hdr = ( $udp_pkt->{'Ethernet_hdr'} ); + my $ref_to_ip_hdr = ( $udp_pkt->{'IP_hdr'} ); + + # pointer to array + my $eth_hdr_bytes = $$ref_to_eth_hdr->{'bytes'}; + my $ip_hdr_bytes = $$ref_to_ip_hdr->{'bytes'}; + my @dst_mac_subarray = @{$eth_hdr_bytes}[ 0 .. 5 ]; + my @src_mac_subarray = @{$eth_hdr_bytes}[ 6 .. 11 ]; + + my @src_ip_subarray = @{$ip_hdr_bytes}[ 12 .. 15 ]; + my @dst_ip_subarray = @{$ip_hdr_bytes}[ 16 .. 19 ]; + + my $src_ip = + ( ( 2**24 ) * $src_ip_subarray[0] + ( 2**16 ) * $src_ip_subarray[1] + + ( 2**8 ) * $src_ip_subarray[2] + $src_ip_subarray[3] ); + + my $dst_ip = + ( ( 2**24 ) * $dst_ip_subarray[0] + ( 2**16 ) * $dst_ip_subarray[1] + + ( 2**8 ) * $dst_ip_subarray[2] + $dst_ip_subarray[3] ); + + # read IP_header protocol field + my $iph = $udp_pkt->{'IP_hdr'}; + my $proto = $$iph->proto(); + + my $match_args = { + wildcards => $wildcards, + in_port => $in_port, + dl_src => \@src_mac_subarray, + dl_dst => \@dst_mac_subarray, + dl_vlan => 0xffff, + dl_type => 0x0800, + nw_src => $src_ip, + nw_dst => $dst_ip, + nw_proto => $proto, #any protocol + tp_src => ${ $udp_pkt->{UDP_pdu} }->SrcPort, + tp_dst => ${ $udp_pkt->{UDP_pdu} }->DstPort + }; + + my $action_output_args = { + max_len => 0, # send entire packet + port => $out_port + }; + print "My Out Port: ${out_port}\n"; + + my $action_args = { + type => $enums{'OFPAT_OUTPUT'}, + arg => { output => $action_output_args } + }; + my $action = $ofp->pack( 'ofp_action', $action_args ); + + my $flow_mod_args = { + header => $hdr_args, + match => $match_args, + command => $enums{'OFPFC_ADD'}, + max_idle => $max_idle, + buffer_id => 0x0000, + group_id => 0 + }; + my $flow_mod = $ofp->pack( 'ofp_flow_mod', $flow_mod_args ); + + my $flow_mod_pkt = $flow_mod . $action; + + return $flow_mod_pkt; +} + +run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_ip_protocol/case-d.pl b/openflow/regress/projects/black_box/regress/test_ip_protocol/case-d.pl new file mode 100755 index 00000000..4f71280e --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_ip_protocol/case-d.pl @@ -0,0 +1,152 @@ +#!/usr/bin/perl -w +# test_ip_protocol (case d, not TCP nor UDP, but specify src port=0, dst port=0); + +use strict; +use OF::Includes; + +sub send_expect_exact { + + my ( $ofp, $sock, $in_port, $out_port, $max_idle, $pkt_len ) = @_; + + # in_port refers to the flow mod entry's input + + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + src_port => 70, + dst_port => 80 + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + ## Change protoco field + my $iphdr=$test_pkt->{'IP_hdr'}; + $$iphdr->proto(0x13); # overwrite protocol filed in IP header + + #print HexDump ( $test_pkt->packed ); + + my $wildcards = 0x0; # exact match + + my $flow_mod_pkt = + create_flow_mod_from_ip( $ofp, $test_pkt, $in_port, $out_port, + $max_idle, $wildcards, 0, 0); + + #print HexDump($flow_mod_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent flow_mod message\n"; + usleep(100000); + + + # Send a packet - ensure packet comes out desired port + nftest_send( "eth" . ( $in_port + 1 ), + $test_pkt->packed ); + nftest_expect( "eth" . ( $out_port + 1 ), + $test_pkt->packed ); +} + + +sub my_test { + + my ($sock, $options_ref) = @_; + + my $max_idle = $$options_ref{'max_idle'}; + my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_total = $$options_ref{'pkt_total'}; + + # send from every port to every other port + for ( my $i = 0 ; $i < 4 ; $i++ ) { + for ( my $j = 0 ; $j < 4 ; $j++ ) { + if ( $i != $j ) { + print "sending from $i to $j\n"; + send_expect_exact( $ofp, $sock, $i, $j, $max_idle, $pkt_len ); + wait_for_flow_expired_all( $ofp, $sock, $options_ref ); + } + } + } +} + +sub create_flow_mod_from_ip { + + my ( $ofp, $udp_pkt, $in_port, $out_port, $max_idle, $wildcards, $s_port, $d_port ) = @_; + + my $hdr_args = { + version => get_of_ver(), + type => $enums{'OFPT_FLOW_MOD'}, + length => $ofp->sizeof('ofp_flow_mod') + $ofp->sizeof('ofp_action'), + xid => 0x0000000 + }; + + # might be cleaner to convert the exported colon-hex MAC addrs + #print ${$udp_pkt->{Ethernet_hdr}}->SA . "\n"; + #print ${$test_pkt->{Ethernet_hdr}}->SA . "\n"; + my $ref_to_eth_hdr = ( $udp_pkt->{'Ethernet_hdr'} ); + my $ref_to_ip_hdr = ( $udp_pkt->{'IP_hdr'} ); + + # pointer to array + my $eth_hdr_bytes = $$ref_to_eth_hdr->{'bytes'}; + my $ip_hdr_bytes = $$ref_to_ip_hdr->{'bytes'}; + my @dst_mac_subarray = @{$eth_hdr_bytes}[ 0 .. 5 ]; + my @src_mac_subarray = @{$eth_hdr_bytes}[ 6 .. 11 ]; + + my @src_ip_subarray = @{$ip_hdr_bytes}[ 12 .. 15 ]; + my @dst_ip_subarray = @{$ip_hdr_bytes}[ 16 .. 19 ]; + + my $src_ip = + ( ( 2**24 ) * $src_ip_subarray[0] + ( 2**16 ) * $src_ip_subarray[1] + + ( 2**8 ) * $src_ip_subarray[2] + $src_ip_subarray[3] ); + + my $dst_ip = + ( ( 2**24 ) * $dst_ip_subarray[0] + ( 2**16 ) * $dst_ip_subarray[1] + + ( 2**8 ) * $dst_ip_subarray[2] + $dst_ip_subarray[3] ); + + # read IP_header protocol field + my $iph = $udp_pkt->{'IP_hdr'}; + my $proto = $$iph->proto(); + + my $match_args = { + wildcards => $wildcards, + in_port => $in_port, + dl_src => \@src_mac_subarray, + dl_dst => \@dst_mac_subarray, + dl_vlan => 0xffff, + dl_type => 0x0800, + nw_src => $src_ip, + nw_dst => $dst_ip, + nw_proto => $proto, #any protocol + tp_src => $s_port, + tp_dst => $d_port + }; + + my $action_output_args = { + max_len => 0, # send entire packet + port => $out_port + }; + print "My Out Port: ${out_port}\n"; + + my $action_args = { + type => $enums{'OFPAT_OUTPUT'}, + arg => { output => $action_output_args } + }; + my $action = $ofp->pack( 'ofp_action', $action_args ); + + my $flow_mod_args = { + header => $hdr_args, + match => $match_args, + command => $enums{'OFPFC_ADD'}, + max_idle => $max_idle, + buffer_id => 0x0000, + group_id => 0 + }; + my $flow_mod = $ofp->pack( 'ofp_flow_mod', $flow_mod_args ); + + my $flow_mod_pkt = $flow_mod . $action; + + return $flow_mod_pkt; +} + +run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_ip_protocol/case-e.pl b/openflow/regress/projects/black_box/regress/test_ip_protocol/case-e.pl new file mode 100755 index 00000000..47d1227c --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_ip_protocol/case-e.pl @@ -0,0 +1,152 @@ +#!/usr/bin/perl -w +# test_ip_protocol (case e, not TCP nor UDP, but specify src port!=0, dst port!=0); + +use strict; +use OF::Includes; + +sub send_expect_exact { + + my ( $ofp, $sock, $in_port, $out_port, $max_idle, $pkt_len ) = @_; + + # in_port refers to the flow mod entry's input + + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + src_port => 70, + dst_port => 80 + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + ## Change protoco field + my $iphdr=$test_pkt->{'IP_hdr'}; + $$iphdr->proto(0x13); # overwrite protocol filed in IP header + + #print HexDump ( $test_pkt->packed ); + + my $wildcards = 0x0; # exact match + + my $flow_mod_pkt = + create_flow_mod_from_ip( $ofp, $test_pkt, $in_port, $out_port, + $max_idle, $wildcards, 3, 4); + + #print HexDump($flow_mod_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent flow_mod message\n"; + usleep(100000); + + + # Send a packet - ensure packet comes out desired port + nftest_send( "eth" . ( $in_port + 1 ), + $test_pkt->packed ); + nftest_expect( "eth" . ( $out_port + 1 ), + $test_pkt->packed ); +} + + +sub my_test { + + my ($sock, $options_ref) = @_; + + my $max_idle = $$options_ref{'max_idle'}; + my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_total = $$options_ref{'pkt_total'}; + + # send from every port to every other port + for ( my $i = 0 ; $i < 4 ; $i++ ) { + for ( my $j = 0 ; $j < 4 ; $j++ ) { + if ( $i != $j ) { + print "sending from $i to $j\n"; + send_expect_exact( $ofp, $sock, $i, $j, $max_idle, $pkt_len ); + wait_for_flow_expired_all( $ofp, $sock, $options_ref ); + } + } + } +} + +sub create_flow_mod_from_ip { + + my ( $ofp, $udp_pkt, $in_port, $out_port, $max_idle, $wildcards, $s_port, $d_port ) = @_; + + my $hdr_args = { + version => get_of_ver(), + type => $enums{'OFPT_FLOW_MOD'}, + length => $ofp->sizeof('ofp_flow_mod') + $ofp->sizeof('ofp_action'), + xid => 0x0000000 + }; + + # might be cleaner to convert the exported colon-hex MAC addrs + #print ${$udp_pkt->{Ethernet_hdr}}->SA . "\n"; + #print ${$test_pkt->{Ethernet_hdr}}->SA . "\n"; + my $ref_to_eth_hdr = ( $udp_pkt->{'Ethernet_hdr'} ); + my $ref_to_ip_hdr = ( $udp_pkt->{'IP_hdr'} ); + + # pointer to array + my $eth_hdr_bytes = $$ref_to_eth_hdr->{'bytes'}; + my $ip_hdr_bytes = $$ref_to_ip_hdr->{'bytes'}; + my @dst_mac_subarray = @{$eth_hdr_bytes}[ 0 .. 5 ]; + my @src_mac_subarray = @{$eth_hdr_bytes}[ 6 .. 11 ]; + + my @src_ip_subarray = @{$ip_hdr_bytes}[ 12 .. 15 ]; + my @dst_ip_subarray = @{$ip_hdr_bytes}[ 16 .. 19 ]; + + my $src_ip = + ( ( 2**24 ) * $src_ip_subarray[0] + ( 2**16 ) * $src_ip_subarray[1] + + ( 2**8 ) * $src_ip_subarray[2] + $src_ip_subarray[3] ); + + my $dst_ip = + ( ( 2**24 ) * $dst_ip_subarray[0] + ( 2**16 ) * $dst_ip_subarray[1] + + ( 2**8 ) * $dst_ip_subarray[2] + $dst_ip_subarray[3] ); + + # read IP_header protocol field + my $iph = $udp_pkt->{'IP_hdr'}; + my $proto = $$iph->proto(); + + my $match_args = { + wildcards => $wildcards, + in_port => $in_port, + dl_src => \@src_mac_subarray, + dl_dst => \@dst_mac_subarray, + dl_vlan => 0xffff, + dl_type => 0x0800, + nw_src => $src_ip, + nw_dst => $dst_ip, + nw_proto => $proto, #any protocol + tp_src => $s_port, + tp_dst => $d_port + }; + + my $action_output_args = { + max_len => 0, # send entire packet + port => $out_port + }; + print "My Out Port: ${out_port}\n"; + + my $action_args = { + type => $enums{'OFPAT_OUTPUT'}, + arg => { output => $action_output_args } + }; + my $action = $ofp->pack( 'ofp_action', $action_args ); + + my $flow_mod_args = { + header => $hdr_args, + match => $match_args, + command => $enums{'OFPFC_ADD'}, + max_idle => $max_idle, + buffer_id => 0x0000, + group_id => 0 + }; + my $flow_mod = $ofp->pack( 'ofp_flow_mod', $flow_mod_args ); + + my $flow_mod_pkt = $flow_mod . $action; + + return $flow_mod_pkt; +} + +run_black_box_test(\&my_test); diff --git a/openflow/regress/projects/black_box/regress/test_ip_protocol/case-tcp.pl b/openflow/regress/projects/black_box/regress/test_ip_protocol/case-tcp.pl new file mode 100755 index 00000000..98117252 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_ip_protocol/case-tcp.pl @@ -0,0 +1,153 @@ +#!/usr/bin/perl -w +# test_ip_protocol (tcp) + +use strict; +use OF::Includes; + +sub send_expect_exact { + + my ( $ofp, $sock, $in_port, $out_port, $max_idle, $pkt_len ) = @_; + + # in_port refers to the flow mod entry's input + + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + src_port => 70, + dst_port => 80 + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + ## Make packet TCP (assuming only tcp src port, tcp dst port fields are used) + my $iphdr = $test_pkt->{'IP_hdr'}; + $$iphdr->proto(6); # overwrite protocol filed in IP header + + #print HexDump ( $test_pkt->packed ); + + my $wildcards = 0x0; # exact match + + my $flow_mod_pkt = + create_flow_mod_from_pseudo_tcp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, + $wildcards ); + + #print HexDump($flow_mod_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent flow_mod message\n"; + usleep(100000); + + # Send a packet - ensure packet comes out desired port + nftest_send( "eth" . ( $in_port + 1 ), $test_pkt->packed ); + nftest_expect( "eth" . ( $out_port + 1 ), $test_pkt->packed ); +} + +sub my_test { + + my ($sock, $options_ref) = @_; + + my $max_idle = $$options_ref{'max_idle'}; + my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_total = $$options_ref{'pkt_total'}; + + # send from every port to every other port + for ( my $i = 0 ; $i < 4 ; $i++ ) { + for ( my $j = 0 ; $j < 4 ; $j++ ) { + if ( $i != $j ) { + print "sending from $i to $j\n"; + send_expect_exact( $ofp, $sock, $i, $j, $max_idle, $pkt_len ); + wait_for_flow_expired_all( $ofp, $sock, $options_ref ); + } + } + } +} + +sub create_flow_mod_from_pseudo_tcp { + + my ( $ofp, $udp_pkt, $in_port, $out_port, $max_idle, $wildcards ) = @_; + + my $hdr_args = { + version => get_of_ver(), + type => $enums{'OFPT_FLOW_MOD'}, + length => $ofp->sizeof('ofp_flow_mod') + $ofp->sizeof('ofp_action'), + xid => 0x0000000 + }; + + # might be cleaner to convert the exported colon-hex MAC addrs + #print ${$udp_pkt->{Ethernet_hdr}}->SA . "\n"; + #print ${$test_pkt->{Ethernet_hdr}}->SA . "\n"; + my $ref_to_eth_hdr = ( $udp_pkt->{'Ethernet_hdr'} ); + my $ref_to_ip_hdr = ( $udp_pkt->{'IP_hdr'} ); + + # pointer to array + my $eth_hdr_bytes = $$ref_to_eth_hdr->{'bytes'}; + my $ip_hdr_bytes = $$ref_to_ip_hdr->{'bytes'}; + my @dst_mac_subarray = @{$eth_hdr_bytes}[ 0 .. 5 ]; + my @src_mac_subarray = @{$eth_hdr_bytes}[ 6 .. 11 ]; + + my @src_ip_subarray = @{$ip_hdr_bytes}[ 12 .. 15 ]; + my @dst_ip_subarray = @{$ip_hdr_bytes}[ 16 .. 19 ]; + + my $src_ip = + ( ( 2**24 ) * $src_ip_subarray[0] + + ( 2**16 ) * $src_ip_subarray[1] + + ( 2**8 ) * $src_ip_subarray[2] + + $src_ip_subarray[3] ); + + my $dst_ip = + ( ( 2**24 ) * $dst_ip_subarray[0] + + ( 2**16 ) * $dst_ip_subarray[1] + + ( 2**8 ) * $dst_ip_subarray[2] + + $dst_ip_subarray[3] ); + + # read IP_header protocol field + my $iph = $udp_pkt->{'IP_hdr'}; + my $proto = $$iph->proto(); + + my $match_args = { + wildcards => $wildcards, + in_port => $in_port, + dl_src => \@src_mac_subarray, + dl_dst => \@dst_mac_subarray, + dl_vlan => 0xffff, + dl_type => 0x0800, + nw_src => $src_ip, + nw_dst => $dst_ip, + nw_proto => $proto, #any protocol + tp_src => ${ $udp_pkt->{UDP_pdu} }->SrcPort, + tp_dst => ${ $udp_pkt->{UDP_pdu} }->DstPort + }; + + my $action_output_args = { + max_len => 0, # send entire packet + port => $out_port + }; + print "My Out Port: ${out_port}\n"; + + my $action_args = { + type => $enums{'OFPAT_OUTPUT'}, + arg => { output => $action_output_args } + }; + my $action = $ofp->pack( 'ofp_action', $action_args ); + + my $flow_mod_args = { + header => $hdr_args, + match => $match_args, + command => $enums{'OFPFC_ADD'}, + max_idle => $max_idle, + buffer_id => 0x0000, + group_id => 0 + }; + my $flow_mod = $ofp->pack( 'ofp_flow_mod', $flow_mod_args ); + + my $flow_mod_pkt = $flow_mod . $action; + + return $flow_mod_pkt; +} + +run_black_box_test( \&my_test, \@ARGV); + diff --git a/openflow/regress/projects/black_box/regress/test_ip_protocol/case-udp.pl b/openflow/regress/projects/black_box/regress/test_ip_protocol/case-udp.pl new file mode 100755 index 00000000..5f59ad32 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_ip_protocol/case-udp.pl @@ -0,0 +1,67 @@ +#!/usr/bin/perl -w +# test_ip_protocol (udp) + +use strict; +use OF::Includes; + +sub send_expect_exact { + + my ( $ofp, $sock, $in_port, $out_port, $max_idle, $pkt_len ) = @_; + + # in_port refers to the flow mod entry's input + + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + src_port => 70, + dst_port => 80 + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + #print HexDump ( $test_pkt->packed ); + + my $wildcards = 0x0; # exact match + my $flags = 0x0; # don't send flow expiry + + my $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, + $max_idle, $flags, $wildcards ); + + #print HexDump($flow_mod_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent flow_mod message\n"; + usleep(100000); + + # Send a packet - ensure packet comes out desired port + nftest_send( "eth" . ( $in_port + 1 ), $test_pkt->packed ); + nftest_expect( "eth" . ( $out_port + 1 ), $test_pkt->packed ); +} + +sub my_test { + + my ($sock, $options_ref) = @_; + + my $max_idle = $$options_ref{'max_idle'}; + my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_total = $$options_ref{'pkt_total'}; + + # send from every port to every other port + for ( my $i = 0 ; $i < 4 ; $i++ ) { + for ( my $j = 0 ; $j < 4 ; $j++ ) { + if ( $i != $j ) { + print "sending from $i to $j\n"; + send_expect_exact( $ofp, $sock, $i, $j, $max_idle, $pkt_len ); + wait_for_flow_expired_all( $ofp, $sock, $options_ref ); + } + } + } +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_llc/run.pl b/openflow/regress/projects/black_box/regress/test_llc/run.pl new file mode 100755 index 00000000..761f878d --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_llc/run.pl @@ -0,0 +1,128 @@ +#!/usr/bin/perl -w +# test_llc (use $EthFMT = "LLC") +# if you want to test DIX format, use use $EthFMT = "DIX" + +use strict; +use OF::Includes; + +## choose one from "DIX" or "LLC"; +#my $EthFMT = "DIX"; +my $EthFMT = "LLC"; + +my $pkt_len_llc = 68; +my $pkt_len_dix = 60; + +my $pkt_len; +if ( $EthFMT eq "LLC" ) { + $pkt_len = $pkt_len_llc; + print "test for LLC\n"; +} +else { + $pkt_len = $pkt_len_dix; + print "test for DIX\n"; +} + +sub send_expect_exact_oneshot { + + my ( $ofp, $sock, $in_port, $out_port, $max_idle, $pkt_len ) = @_; + + my $test_pkt_llc_ip = new NF2::PDU($pkt_len_llc); + @{ $test_pkt_llc_ip->{'bytes'} }[ 0 .. ( $pkt_len_llc - 1 ) ] = ( + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, # dst mac 6byte (02:02:02:02:02:02) + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, # src mac 6byte (04:04:04:04:04:04) + 0x00, 0x36, # 2byte (Length=54byte=0x0036) + 0xAA, 0xAA, 0x03, #LLC # 3byte (always this value) + 0x00, 0x00, 0x00, #SNAP(OUI) # 3byte (always this value) + 0x08, 0x00, #SNAP(PID) # 2byte (0x0800 = IP) + 0x45, 0x00, 0x00, 0x2E, # 46 byte + 0x00, 0x00, 0x40, 0x00, # + 0x40, 0x11, 0xB8, 0x1E, # TTL=64, proto=UDP(0x11) + 0xC0, 0xA8, 0xC9, 0x28, # SrcIP= 192.168.201.40 + 0xC0, 0xA8, 0xC8, 0x28, # DstIP= 192.168.200.40 + 0x00, 0x46, 0x00, 0x50, # SrcPort=70, DstPort=80 + 0x00, 0x1A, 0xCD, 0x3F, # .. + 0xAE, 0xA5, 0x7F, 0x87, + 0xEE, 0x67, 0x72, 0xA7, + 0x17, 0x91, 0xFE, 0x10, + 0xBD, 0xFA, 0xC0, 0xC2, + 0x8B, 0xA7 + ); + + my $test_pkt_dix_ip = new NF2::PDU($pkt_len_dix); + @{ $test_pkt_dix_ip->{'bytes'} }[ 0 .. ( $pkt_len_dix - 1 ) ] = ( + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, # dst mac 6byte (02:02:02:02:02:02) + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, # src mac 6byte (04:04:04:04:04:04) + 0x08, 0x00, + 0x45, 0x00, 0x00, 0x2E, # 46 byte + 0x00, 0x00, 0x40, 0x00, # + 0x40, 0x11, 0xB8, 0x1E, # TTL=64, proto=UDP(0x11) + 0xC0, 0xA8, 0xC9, 0x28, # SrcIP= 192.168.201.40 + 0xC0, 0xA8, 0xC8, 0x28, # DstIP= 192.168.200.40 + 0x00, 0x46, 0x00, 0x50, # SrcPort=70, DstPort=80 + 0x00, 0x1A, 0xCD, 0x3F, # .. + 0xAE, 0xA5, 0x7F, 0x87, + 0xEE, 0x67, 0x72, 0xA7, + 0x17, 0x91, 0xFE, 0x10, + 0xBD, 0xFA, 0xC0, 0xC2, + 0x8B, 0xA7 + ); + + # Create Test Packet (only to call "create_flow_mod_from_udp") + # which should match test_pkt_llc_ip or test_pkt_dix packet + my $test_pkt_args = { + DA => "02:02:02:02:02:02", + SA => "04:04:04:04:04:04", + src_ip => "192.168.201.40", + dst_ip => "192.168.200.40", + ttl => 64, + len => $pkt_len, + src_port => 70, + dst_port => 80 + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + my $wildcards = 0x0; # exact match + my $flags = 0x0; # don't send flow expiry + my $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); + + #print HexDump($flow_mod_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent flow_mod message\n"; + usleep(100000); + + # Send a packet - ensure packet comes out desired port + if ( $EthFMT eq "LLC" ) { + nftest_send( "eth" . ( $in_port + 1 ), $test_pkt_llc_ip->packed ); + nftest_expect( "eth" . ( $out_port + 1 ), $test_pkt_llc_ip->packed ); + } + else { + nftest_send( "eth" . ( $in_port + 1 ), $test_pkt_dix_ip->packed ); + nftest_expect( "eth" . ( $out_port + 1 ), $test_pkt_dix_ip->packed ); + } +} + +sub my_test { + + my ($sock, $options_ref) = @_; + + my $max_idle = $$options_ref{'max_idle'}; + #my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_total = $$options_ref{'pkt_total'}; + + # send from every port to every other port + for ( my $i = 0 ; $i < 4 ; $i++ ) { + for ( my $j = 0 ; $j < 4 ; $j++ ) { + if ( $i != $j ) { + print "sending from $i to $j\n"; + send_expect_exact_oneshot( $ofp, $sock, $i, $j, $max_idle, $pkt_len ); + wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); + } + } + } +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_miss_send_length/run.pl b/openflow/regress/projects/black_box/regress/test_miss_send_length/run.pl new file mode 100755 index 00000000..d787a624 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_miss_send_length/run.pl @@ -0,0 +1,79 @@ +#!/usr/bin/perl -w +# test_packet_in +# Send a packet of size 256B, and ensure that it gets reduced to 128B + +use strict; +use OF::Includes; + +sub verify_packet_in { + my ($sock, $options_ref, $miss_send_len, $pktsiz, $expected_pktsiz) = @_; + + my $in_port = $$options_ref{'port_base'}; + my $out_port = $in_port + 1; + + # Give OF switch time to process the set_config + usleep($$options_ref{'send_delay'}); + + my $pkt = get_default_black_box_pkt_len($in_port, $out_port, $pktsiz); + nftest_send('eth1', $pkt->packed); + print "Sent test packet for len ".$miss_send_len."...\n"; + + my $rcvd_msg; + sysread($sock, $rcvd_msg, 1512) || die "Failed to receive message: $!"; + + # Inspect message + my $msg_size = length($rcvd_msg); + compare("msg size", $msg_size, '==', $expected_pktsiz); + + my $msg = $ofp->unpack('ofp_packet_in', $rcvd_msg); + #print HexDump ($rcvd_msg); + #print Dumper($msg); + + # Verify fields + verify_header($msg, 'OFPT_PACKET_IN', $msg_size); + + # total len should be full length of original sent frame + compare("total len", $$msg{'total_len'}, '==', length($pkt->packed)); + compare("in_port", $$msg{'in_port'}, '==', $in_port); + compare("reason", $$msg{'reason'}, '==', $enums{'OFPR_NO_MATCH'}); + + # verify packet was unchanged! + my $rcvd_pkt_data = substr($rcvd_msg, $ofp->offsetof('ofp_packet_in', 'data')); + + # trim to MISS_SEND_LEN + my $pkt_trimmed = substr($pkt->packed, 0, $miss_send_len); + if ($rcvd_pkt_data ne $pkt_trimmed) { + die "ERROR: received packet data didn't match packet sent\n"; + } +} + +sub my_test { + my ($sock, $options_ref) = @_; + + my $miss_send_len = get_of_miss_send_len_default(); + my $pktsiz = 63; + my $expected_pktsiz = 8 + 10 + $pktsiz; + verify_packet_in($sock, $options_ref, $miss_send_len, $pktsiz, $expected_pktsiz); + + $miss_send_len = 0; + $pktsiz = 67; + $expected_pktsiz = 8 + 10; + set_config($ofp, $sock, $options_ref, 1, $miss_send_len); + verify_packet_in($sock, $options_ref, $miss_send_len, $pktsiz, $expected_pktsiz); + + $miss_send_len = 127; + $pktsiz = 259; + $expected_pktsiz = 8 + 10 + $miss_send_len; + set_config($ofp, $sock, $options_ref, 1, $miss_send_len); + verify_packet_in($sock, $options_ref, $miss_send_len, $pktsiz, $expected_pktsiz); + + $miss_send_len = 65535; + $pktsiz = 1500 - 8 - 10; + $expected_pktsiz = 1500; + set_config($ofp, $sock, $options_ref, 1, $miss_send_len); + verify_packet_in($sock, $options_ref, $miss_send_len, $pktsiz, $expected_pktsiz); + + set_config($ofp, $sock, $options_ref, 1, get_of_miss_send_len_default()); +} + +run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_packet_in/run.pl b/openflow/regress/projects/black_box/regress/test_packet_in/run.pl new file mode 100755 index 00000000..7ddfb830 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_packet_in/run.pl @@ -0,0 +1,45 @@ +#!/usr/bin/perl -w +# test_packet_in + +use strict; +use OF::Includes; + +sub my_test { + + my ($sock, $options_ref) = @_; + + my $in_port = $$options_ref{'port_base'}; + my $out_port = $in_port + 1; + + my $pkt = get_default_black_box_pkt( $in_port, $out_port); + nftest_send('eth1', $pkt->packed ); + print "Sent test packet...\n"; + + my $recvd_mesg; + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; + + # Inspect message + my $msg_size = length($recvd_mesg); + my $expected_size = $ofp->offsetof( 'ofp_packet_in', 'data' ) + length( $pkt->packed ); + compare( "msg size", $msg_size, '==', $expected_size ); + + my $msg = $ofp->unpack( 'ofp_packet_in', $recvd_mesg ); + + #print HexDump ($recvd_mesg); + #print Dumper($msg); + + # Verify fields + verify_header( $msg, 'OFPT_PACKET_IN', $msg_size ); + + compare( "total len", $$msg{'total_len'}, '==', length( $pkt->packed ) ); + compare( "in_port", $$msg{'in_port'}, '==', $in_port ); + compare( "reason", $$msg{'reason'}, '==', $enums{'OFPR_NO_MATCH'} ); + + # verify packet was unchanged! + my $recvd_pkt_data = substr( $recvd_mesg, $ofp->offsetof( 'ofp_packet_in', 'data' ) ); + if ( $recvd_pkt_data ne $pkt->packed ) { + die "ERROR: received packet data didn't match packet sent\n"; + } +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_packet_out/run.pl b/openflow/regress/projects/black_box/regress/test_packet_out/run.pl new file mode 100755 index 00000000..4d872ac8 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_packet_out/run.pl @@ -0,0 +1,53 @@ +#!/usr/bin/perl -w +# test_packet_out + +use strict; +use OF::Includes; + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + my $port_base = $$options_ref{'port_base'}; + my $in_port = $port_base; + my $out_port = $in_port + 1; + + my $pkt = get_default_black_box_pkt( $in_port, $out_port ); + + my $hdr_args = { + version => get_of_ver(), + type => $enums{'OFPT_PACKET_OUT'}, + length => $ofp->sizeof('ofp_packet_out') + + $ofp->sizeof('ofp_action_output') + + length( $pkt->packed ), # should generate automatically! + xid => 0x0000abcd + }; + my $packet_out_args = { + header => $hdr_args, + buffer_id => -1, # data included in this packet + in_port => $enums{'OFPP_NONE'}, + actions_len => $ofp->sizeof('ofp_action_output') + }; + my $packet_out = $ofp->pack( 'ofp_packet_out', $packet_out_args ); + my $action_output_args = { + type => $enums{'OFPAT_OUTPUT'}, + len => $ofp->sizeof('ofp_action_output'), + port => $port_base, # send out eth1 + max_len => get_of_miss_send_len_default() + }; + my $action_output = $ofp->pack( 'ofp_action_output', $action_output_args ); + + my $pkt_sent = $packet_out . $action_output . $pkt->packed; + + # Send 'packet_out' message + print $sock $pkt_sent; + + nftest_expect( 'eth1', $pkt->packed ); + + # Wait for packet to be forwarded out + sleep(.1); + +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_port_stats/run.pl b/openflow/regress/projects/black_box/regress/test_port_stats/run.pl new file mode 100755 index 00000000..5c321c8d --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_port_stats/run.pl @@ -0,0 +1,132 @@ +#!/usr/bin/perl -w +# test_port_stats + +use strict; +use OF::Includes; + +sub forward_any { + forward_simple(@_, 'any'); +} + +sub my_test { + my ($sock, $options_ref) = @_; + + my $port_base = $$options_ref{'port_base'}; + my $num_ports = $$options_ref{'num_ports'}; + + my $hdr_args = { + version => get_of_ver(), + type => $enums{'OFPT_STATS_REQUEST'}, + length => $ofp->sizeof('ofp_stats_request') + $ofp->sizeof('ofp_port_stats_request'), # should generate automatically! + xid => 0x00000000 + }; + + my $stats_reqhdr_args = { + header => $hdr_args, + type => $enums{'OFPST_PORT'}, + flags => 0 + }; + + my $stats_all_ports_reqbody_args = { + port_no => $enums{'OFPP_NONE'}, + }; + my $stats_single_port_reqbody_args = { + port_no => 1, + }; + my $stats_invalid_port_reqbody_args = { + port_no => 32768, + }; + + my $stats_reqhead = $ofp->pack('ofp_stats_request', $stats_reqhdr_args); + my $stats_all_ports_reqbody = $ofp->pack('ofp_port_stats_request', $stats_all_ports_reqbody_args); + my $stats_single_port_reqbody = $ofp->pack('ofp_port_stats_request', $stats_single_port_reqbody_args); + my $stats_invalid_port_reqbody = $ofp->pack('ofp_port_stats_request', $stats_invalid_port_reqbody_args); + my $stats_all_ports_reqmsg = $stats_reqhead . $stats_all_ports_reqbody; + my $stats_single_port_reqmsg = $stats_reqhead . $stats_single_port_reqbody; + my $stats_invalid_port_reqmsg = $stats_reqhead . $stats_invalid_port_reqbody; + + my $stats_rephdr_args = { + version => get_of_ver(), + type => $enums{'OFPT_STATS_REPLY'}, + length => $ofp->sizeof('ofp_stats_reply'), # should generate automatically! + xid => 0x00000000 + }; + + my $stats_repbody_args = { + header => $stats_rephdr_args, + type => $enums{'OFPST_PORT'}, + flags => 0 + }; + + my $stats_repbody; + for (my $i = $port_base; $i < $port_base + $num_ports; $i++ ) { + my $body_args = { + port_no => $port_base, + rx_count => 0, + tx_count => 0, + drop_count => 0 + }; + $stats_repbody .= $ofp->pack('ofp_port_stats', $body_args); + } + + my $stats_repmsg = $ofp->pack('ofp_stats_reply', $stats_repbody_args) . $stats_repbody; + my $rcvd_msg; + + # Send 'stats_request' for single port + print $sock $stats_single_port_reqmsg; + # Should add timeout here - will crash if no reply + sysread($sock, $rcvd_msg, 1512) || die "Failed to receive message: $!"; + + # Send 'stats_request' for invalid port + print $sock $stats_invalid_port_reqmsg; + # Should add timeout here - will crash if no reply + sysread($sock, $rcvd_msg, 1512) || die "Failed to receive message: $!"; + + # Send 'stats_request' for all ports + print $sock $stats_all_ports_reqmsg; + # Should add timeout here - will crash if no reply + sysread($sock, $rcvd_msg, 1512) || die "Failed to receive message: $!"; + + # Inspect message + my $msg_size = length($rcvd_msg); + my $expected_size = $ofp->sizeof('ofp_stats_reply') + 4 * $ofp->sizeof('ofp_port_stats'); + + # Removed this compare because varying numbers of ports may be activated + # compare("msg size", $msg_size, '==', $expected_size); + my $msg = $ofp->unpack('ofp_stats_reply', $rcvd_msg); + #print HexDump($rcvd_msg); + #print Dumper($msg); + + # Verify fields + verify_header($msg, 'OFPT_STATS_REPLY', $msg_size); + compare("type", $$msg{'type'}, '==', $enums{'OFPST_PORT'}); + compare("flags", $$msg{'flags'}, '==', 0); + +# if ($rcvd_msg ne $stats_reply) { +# die "stats reply is not what was expected" +# } + + # TODO: Look at each received port_stats field, to ensure they equal zero... + + # Send data plane packets + for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_any, 0x1fffff); + + # TODO: Look at each received port_stats field, to ensure correct counters + + # Send 'stats_request' for all ports + print $sock $stats_all_ports_reqmsg; + # Should add timeout here - will crash if no reply + sysread($sock, $rcvd_msg, 1512) || die "Failed to receive message: $!"; + + # Send 'stats_request' for invalid port + print $sock $stats_invalid_port_reqmsg; + # Should add timeout here - will crash if no reply + sysread($sock, $rcvd_msg, 1512) || die "Failed to receive message: $!"; + + # Send 'stats_request' for single port + print $sock $stats_single_port_reqmsg; + # Should add timeout here - will crash if no reply + sysread($sock, $rcvd_msg, 1512) || die "Failed to receive message: $!"; +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_queue_config/run.pl b/openflow/regress/projects/black_box/regress/test_queue_config/run.pl new file mode 100755 index 00000000..e3f512ee --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_queue_config/run.pl @@ -0,0 +1,52 @@ +#!/usr/bin/perl -w +# test_queue_config + +use strict; +use OF::Includes; + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + if ( not defined( $$options_ref{'no_slicing'} ) ) { + my $port_base = $$options_ref{'port_base'}; + my $num_ports = $$options_ref{'num_ports'}; + + # for each port, + + for (my $i = 1; $i <= $num_ports; $i++){ + + my $hdr_args = { + version => get_of_ver(), + type => $enums{'OFPT_QUEUE_GET_CONFIG_REQUEST'}, + length => $ofp->sizeof('ofp_queue_get_config_request'), # should generate automatically! + xid => 0x00000000 + }; + + my @pad_2 = (0,0); + my $queue_request_args = { + header => $hdr_args, + port => $i, + pad => \@pad_2 + }; + + my $queue_request = $ofp->pack( 'ofp_queue_get_config_request', $queue_request_args ); + + # Send 'stats_request' message + print $sock $queue_request; + + # Should add timeout here - will crash if no reply + my $recvd_mesg; + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; + + my $msg = $ofp->unpack( 'ofp_queue_get_config_reply', $recvd_mesg ); + + my $msg_size = length($recvd_mesg); + # Verify fields + verify_header( $msg, 'OFPT_QUEUE_GET_CONFIG_REPLY', $msg_size ); + } + } +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_queue_forward/run.pl b/openflow/regress/projects/black_box/regress/test_queue_forward/run.pl new file mode 100755 index 00000000..a3b0d737 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_queue_forward/run.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl -w +# test_queue_forward + +use strict; +use OF::Includes; + +sub forward_unicast_port { + forward_simple(@_, 'enqueue'); +} + +sub my_test { + my ($sock, $options_ref) = @_; + + if ( not defined( $$options_ref{'no_slicing'} ) ) { + for_all_port_pairs($ofp, $sock, $options_ref, \&forward_unicast_port, 0x0); + } +} + +run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_queue_stats/run.pl b/openflow/regress/projects/black_box/regress/test_queue_stats/run.pl new file mode 100755 index 00000000..0f49a329 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_queue_stats/run.pl @@ -0,0 +1,116 @@ +#!/usr/bin/perl -w +# test_queue_stats + +use strict; +use OF::Includes; + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + if ( not defined( $$options_ref{'no_slicing'} ) ) { + + my $port_base = $$options_ref{'port_base'}; + my $num_ports = $$options_ref{'num_ports'}; + + # Prepare stats request + my $hdr_args = { + version => get_of_ver(), + type => $enums{'OFPT_STATS_REQUEST'}, + length => $ofp->sizeof('ofp_stats_request') + $ofp->sizeof('ofp_queue_stats_request'), # should generate automatically! + xid => 0x00000000 + }; + + my @pad_2 = (0,0); + my $body_args = { + port_no => $port_base, + pad => \@pad_2, + queue_id => 0xffffffff # TODO : export get_define to get OFPQ_ALL + }; + + + my $stats_request_args = { + header => $hdr_args, + type => $enums{'OFPST_QUEUE'}, + flags => 0 + }; + + my $request_body = $ofp->pack( 'ofp_queue_stats_request', $body_args ); + my $stats_request = $ofp->pack( 'ofp_stats_request', $stats_request_args ) . $request_body; + + + # Prepare expected stats reply + my $reply_hdr_args = { + version => get_of_ver(), + type => $enums{'OFPT_STATS_REPLY'}, + length => $ofp->sizeof('ofp_stats_reply') + $ofp->sizeof('ofp_queue_stats'), # should generate automatically! + xid => 0x00000000 + }; + + my $stats_reply_args = { + header => $reply_hdr_args, + type => $enums{'OFPST_QUEUE'}, + flags => 0 + }; + + + my $reply_body_args = { + port_no => $port_base, + pad => \@pad_2, + queue_id => 1, + tx_bytes => 0, + tx_packets => 0, + tx_errors => 0 + }; + + my $reply_body = $ofp->pack( 'ofp_queue_stats', $reply_body_args); + my $stats_reply = $ofp->pack( 'ofp_stats_reply', $stats_reply_args ) . $reply_body; + + # Send 'stats_request' message + print $sock $stats_request; + + # Should add timeout here - will crash if no reply + my $recvd_mesg; + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; + + # Inspect message + if ($recvd_mesg ne $stats_reply) { + die "ERROR: stats reply didn't match expected"; + } + + # Send a packet out + forward_simple($ofp, $sock, $options_ref, 1, 0, 0, 'enqueue'); + + # Wait the flow to expire + sleep 3; + + # Expect increased counters + $reply_body_args = { + port_no => $port_base, + pad => \@pad_2, + queue_id => 1, + tx_bytes => 64, + tx_packets => 1, + tx_errors => 0 + }; + + $reply_body = $ofp->pack( 'ofp_queue_stats', $reply_body_args); + $stats_reply = $ofp->pack( 'ofp_stats_reply', $stats_reply_args ) . $reply_body; + + + # Send 'stats_request' message + print $sock $stats_request; + + # Receive stats reply + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; + + # Inspect message + if ($recvd_mesg ne $stats_reply) { + die "ERROR: stats reply didn't match expected"; + } + } + +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_receive_bandwidth_fixed/run.pl b/openflow/regress/projects/black_box/regress/test_receive_bandwidth_fixed/run.pl new file mode 100755 index 00000000..342845e9 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_receive_bandwidth_fixed/run.pl @@ -0,0 +1,89 @@ +#!/usr/bin/perl -w +# test_receive_bandwidth_fixed + +use strict; +use OF::Includes; + +use Time::HiRes qw (sleep gettimeofday tv_interval usleep); + +my $pkts_total = 10000; +my $pkt_size = 64; +#my $pkt_size = 1512 - $ofp->sizeof( 'ofp_packet_in'); + +sub verify_packet_in { + + my ( $recvd_mesg, $pkt ) = @_; + + # Inspect message + my $msg_size = length($recvd_mesg); + my $expected_size = $ofp->offsetof( 'ofp_packet_in', 'data' ) + length( $pkt->packed ); + if ( $msg_size != $expected_size ) { return 1; } + + my $msg = $ofp->unpack( 'ofp_packet_in', $recvd_mesg ); + + # Verify fields + if ( ( $$msg{'header'}{'version'} != 1 ) + || ( $$msg{'header'}{'type'} != $enums{'OFPT_PACKET_IN'} ) + || ( $$msg{'header'}{'length'} != $msg_size ) + || ( $$msg{'total_len'} != length( $pkt->packed ) ) + || ( $$msg{'in_port'} != 0 ) + || ( $$msg{'reason'} != $enums{'OFPR_NO_MATCH'} ) ) + { + return 1; + } + + # verify packet was unchanged! + my $recvd_pkt_data = substr( $recvd_mesg, $ofp->offsetof( 'ofp_packet_in', 'data' ) ); + if ( $recvd_pkt_data ne $pkt->packed ) { return 1; } +} + +sub receive_fixed_bandwidth { + my ( $num_packets, $sock, $pkt, $interface ) = @_; + my $length = length( $pkt->packed ); + print "sending $num_packets packets\n"; + + my @start_time = gettimeofday(); + + my $errors = 0; + + for ( my $count = 0 ; $count < $num_packets ; $count++ ) { + + nftest_send( nftest_get_iface($interface), $pkt->packed ); + + my $recvd_mesg; + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; + + $errors += verify_packet_in( $recvd_mesg, $pkt ); + } + + my $sending_time = tv_interval( \@start_time ); + print "time elapsed: $sending_time\n"; + print "errors: $errors\n"; + + my $bps = ($num_packets - $errors) * $length * 8 / $sending_time; + printf "bandwidth achieved: %.0f bps \n", $bps; + + return $errors; +} + +sub my_test { + + my ($sock) = @_; + + my $pkt_args = { + DA => "00:00:00:00:00:02", + SA => "00:00:00:00:00:01", + src_ip => "192.168.200.40", + dst_ip => "192.168.201.40", + ttl => 64, + len => $pkt_size + }; + my $pkt = new NF2::IP_pkt(%$pkt_args); + + my $errors = &receive_fixed_bandwidth( $pkts_total, $sock, $pkt, 'eth1' ); + + if ($errors > 0) { die "received errors"; } +} + +run_black_box_test( \&my_test ); + diff --git a/openflow/regress/projects/black_box/regress/test_send_bandwidth_fixed/run.pl b/openflow/regress/projects/black_box/regress/test_send_bandwidth_fixed/run.pl new file mode 100755 index 00000000..2941d74a --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_send_bandwidth_fixed/run.pl @@ -0,0 +1,140 @@ +#!/usr/bin/perl -w +# test_send_bandwidth_fixed + +use strict; +use OF::Includes; + +use Time::HiRes qw (sleep gettimeofday tv_interval usleep); + +# Sends packets of the specified length, with specified data rate, over time = duration. +# Length is passed as a parameter and it should be also declared during packet's construction. + +sub send_fixed_bandwidth_unique { + my ( $rate, $duration, $sock, $pkt, $pkt_sent, $interface ) = @_; + my $length = length( $pkt->packed ); + my $num_packets = ( $rate * $duration ) / ( $length * 8 ); + my $inter_time = 1000000.0 * $duration / $num_packets; + + print "Running Test for a single packet size\n"; + print( +"Num Packets : $num_packets, Duration : $duration, Length : $length, InterTime : $inter_time Interface : $interface\n" + ); + + print "sending $num_packets packets\n"; + + my @start_time = gettimeofday(); + + my $count; + for ( $count = 0 ; $count < $num_packets ; $count++ ) { + + # Send 'packet_out' message + print $sock $pkt_sent; + nftest_expect( $interface, $pkt->packed ); + usleep($inter_time); + } + + my $sending_time = tv_interval(\@start_time); + print "time elapsed: $sending_time\n"; + + my $bps = $num_packets * $length * 8 / $sending_time; + print "bandwidth attempted: $rate (bps)\n"; + print "bandwidth achieved: $bps (bps)\n"; +} + +sub send_fixed_bandwidth_mixed { + my ( $rate, $duration, $sock, $pkt_sent_small,$pkt_sent_med,$pkt_sent_lrg,$pkt_small,$pkt_med,$pkt_lrg, $interface ) = @_; + my $len_s = length($pkt_small->packed); + my $len_m = length($pkt_med->packed); + my $len_l = length($pkt_lrg->packed); + my $num_loops = ( $rate * $duration ) / (( $len_s+$len_m+$len_l ) * 8 ); + my $num_packets = $num_loops*3; + my $inter_time = 1000000.0 * $duration / $num_packets; + + print "Running Test for different packet sizes\n"; + + print( +"Num Packets : $num_packets, Duration : $duration, Lengths : $len_s,$len_m,$len_l, InterTime : $inter_time Interface : $interface\n" + ); + + print "sending $num_packets packets\n"; + + my @start_time = gettimeofday(); + + my $count; + for ( $count = 0 ; $count < $num_loops ; $count++ ) { + + # Send 'packet_out' message + print $sock $pkt_sent_small; + nftest_expect( $interface, $pkt_small->packed ); + usleep($inter_time); + print $sock $pkt_sent_med; + nftest_expect( $interface, $pkt_med->packed ); + usleep($inter_time); + print $sock $pkt_sent_lrg; + nftest_expect( $interface, $pkt_lrg->packed ); + usleep($inter_time); + } + + my $sending_time = tv_interval(\@start_time); + print "time elapsed: $sending_time\n"; + + my $bps = $num_loops * ($len_s+$len_m+$len_l) * 8 / $sending_time; + print "bandwidth attempted: $rate(bps)\n"; + print "bandwidth achieved: $bps (bps)\n"; +} + + + +sub my_test { + + my $pkt_args = { + DA => "00:00:00:00:00:02", + SA => "00:00:00:00:00:01", + src_ip => "192.168.200.40", + dst_ip => "192.168.201.40", + ttl => 64, + len => 64 + }; + my $pkt_small = new NF2::IP_pkt(%$pkt_args); + $pkt_args->{ 'len' } = 256; + my $pkt_med = new NF2::IP_pkt(%$pkt_args); + $pkt_args->{ 'len' } = 512; + my $pkt_lrg = new NF2::IP_pkt(%$pkt_args); + + my $hdr_args = { + version => 1, + type => $enums{'OFPT_PACKET_OUT'}, + length => $ofp->sizeof('ofp_packet_out') + length( $pkt_small->packed ), # should generate automatically! + xid => 0x0000abcd + }; + my $packet_out_args = { + header => $hdr_args, + buffer_id => -1, # data included in this packet + in_port => $enums{'OFPP_NONE'}, + out_port => 0 # send out eth1 + }; + my $packet_out = $ofp->pack( 'ofp_packet_out', $packet_out_args ); + + my $pkt_sent_small = $packet_out . $pkt_small->packed; + $hdr_args->{'length'} = $ofp->sizeof('ofp_packet_out') + length( $pkt_med->packed ); + $packet_out_args->{'header'} = $hdr_args; + $packet_out = $ofp->pack( 'ofp_packet_out', $packet_out_args ); + my $pkt_sent_med = $packet_out . $pkt_med->packed; + $hdr_args->{'length'} = $ofp->sizeof('ofp_packet_out') + length( $pkt_lrg->packed ); + $packet_out_args->{'header'} = $hdr_args; + $packet_out = $ofp->pack( 'ofp_packet_out', $packet_out_args ); + my $pkt_sent_lrg = $packet_out . $pkt_lrg->packed; + + my ($sock) = @_; + + &send_fixed_bandwidth_unique( .1 * (10**6) ,5, $sock, $pkt_lrg, $pkt_sent_lrg, 'eth1' ); + + #&send_fixed_bandwidth_mixed( 5 * (10**5) ,5, $sock,$pkt_sent_small,$pkt_sent_med, $pkt_sent_lrg,$pkt_small,$pkt_med,$pkt_lrg,'eth1'); + + # Wait for test to finish + sleep(2); + +} + +run_black_box_test( \&my_test ); + diff --git a/openflow/regress/projects/black_box/regress/test_send_bandwidth_random/run.pl b/openflow/regress/projects/black_box/regress/test_send_bandwidth_random/run.pl new file mode 100755 index 00000000..0fc0b1ce --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_send_bandwidth_random/run.pl @@ -0,0 +1,141 @@ +#!/usr/bin/perl -w +# test_send_bandwidth_fixed + +use strict; +use OF::Includes; + +use Time::HiRes qw (sleep gettimeofday tv_interval usleep); + +# Sends packets of the specified length, with specified data rate, over time = duration. +# A random interarrival time between packets is used, trying to fit the requested data rate. + +sub send_random_bandwidth_unique { + my ( $rate, $duration, $sock, $pkt, $pkt_sent, $interface ) = @_; + my $length = length( $pkt->packed ); + my $num_packets = ( $rate * $duration ) / ( $length * 8 ); + my $inter_time = 1000000.0 * $duration / $num_packets; + + print "Running Test for a single packet size\n"; + print( +"Num Packets : $num_packets, Duration : $duration, Length : $length, InterTime : $inter_time Interface : $interface\n" + ); + + print "sending $num_packets packets\n"; + + my @start_time = gettimeofday(); + my $sending_time = tv_interval(\@start_time); + + my $count = 0; + while($sending_time < $duration){ + # Send 'packet_out' message + print $sock $pkt_sent; + nftest_expect( $interface, $pkt->packed ); + usleep(int(rand(2*$inter_time))); + $count++; + $sending_time = tv_interval(\@start_time); + } + print "time elapsed: $sending_time (loops : $count) \n"; + + my $bps = $count * $length * 8 / $sending_time; + print "bandwidth attempted: $rate (bps)\n"; + print "bandwidth achieved: $bps (bps)\n"; +} + +sub send_random_bandwidth_mixed { + my ( $rate, $duration, $sock, $pkt_sent_small,$pkt_sent_med,$pkt_sent_lrg,$pkt_small,$pkt_med,$pkt_lrg, $interface ) = @_; + my $len_s = length($pkt_small->packed); + my $len_m = length($pkt_med->packed); + my $len_l = length($pkt_lrg->packed); + my $num_loops = ( $rate * $duration ) / (( $len_s+$len_m+$len_l ) * 8 ); + my $num_packets = $num_loops*3; + my $inter_time = 1000000.0 * $duration / $num_packets; + + print "Running Test for different packet sizes\n"; + print( +"Num Packets : $num_packets, Duration : $duration, Lengths : $len_s,$len_m,$len_l, InterTime : $inter_time Interface : $interface\n" + ); + + print "sending $num_packets packets\n"; + + my @start_time = gettimeofday(); + my $sending_time = tv_interval(\@start_time); + + my $count = 0; + while ($sending_time < $duration){ + # Send 'packet_out' message + print $sock $pkt_sent_small; + nftest_expect( $interface, $pkt_small->packed ); + usleep(int(rand(2*$inter_time))); + print $sock $pkt_sent_med; + nftest_expect( $interface, $pkt_med->packed ); + usleep(int(rand(2*$inter_time))); + print $sock $pkt_sent_lrg; + nftest_expect( $interface, $pkt_lrg->packed ); + usleep(int(rand(2*$inter_time))); + $count++; + $sending_time = tv_interval(\@start_time); + } + + print "time elapsed: $sending_time (loops : $count)\n"; + + my $bps = $count * ($len_s+$len_m+$len_l) * 8 / $sending_time; + print "bandwidth attempted: $rate(bps)\n"; + print "bandwidth achieved: $bps (bps)\n"; +} + + + +sub my_test { + + my $pkt_args = { + DA => "00:00:00:00:00:02", + SA => "00:00:00:00:00:01", + src_ip => "192.168.200.40", + dst_ip => "192.168.201.40", + ttl => 64, + len => 64 + }; + my $pkt_small = new NF2::IP_pkt(%$pkt_args); + $pkt_args->{ 'len' } = 256; + my $pkt_med = new NF2::IP_pkt(%$pkt_args); + $pkt_args->{ 'len' } = 512; + my $pkt_lrg = new NF2::IP_pkt(%$pkt_args); + + my $hdr_args = { + version => 1, + type => $enums{'OFPT_PACKET_OUT'}, + length => $ofp->sizeof('ofp_packet_out') + length( $pkt_small->packed ), # should generate automatically! + xid => 0x0000abcd + }; + my $packet_out_args = { + header => $hdr_args, + buffer_id => -1, # data included in this packet + in_port => $enums{'OFPP_NONE'}, + out_port => 0 # send out eth1 + }; + my $packet_out = $ofp->pack( 'ofp_packet_out', $packet_out_args ); + + my $pkt_sent_small = $packet_out . $pkt_small->packed; + $hdr_args->{'length'} = $ofp->sizeof('ofp_packet_out') + length( $pkt_med->packed ); + $packet_out_args->{'header'} = $hdr_args; + $packet_out = $ofp->pack( 'ofp_packet_out', $packet_out_args ); + my $pkt_sent_med = $packet_out . $pkt_med->packed; + $hdr_args->{'length'} = $ofp->sizeof('ofp_packet_out') + length( $pkt_lrg->packed ); + $packet_out_args->{'header'} = $hdr_args; + $packet_out = $ofp->pack( 'ofp_packet_out', $packet_out_args ); + my $pkt_sent_lrg = $packet_out . $pkt_lrg->packed; + + my ($sock) = @_; + + + &send_random_bandwidth_unique( .01 * (10**6) ,15, $sock, $pkt_lrg, $pkt_sent_lrg, 'eth1' ); + + #&send_random_bandwidth_mixed( 5 * (10**5) ,5, $sock,$pkt_sent_small,$pkt_sent_med, $pkt_sent_lrg,$pkt_small,$pkt_med,$pkt_lrg,'eth1'); + + # Wait for test to finish + sleep(2); + +} + +run_black_box_test( \&my_test ); + diff --git a/openflow/regress/projects/black_box/regress/test_set_dl_nw_flip/run.pl b/openflow/regress/projects/black_box/regress/test_set_dl_nw_flip/run.pl new file mode 100755 index 00000000..fbf508b4 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_set_dl_nw_flip/run.pl @@ -0,0 +1,143 @@ +#!/usr/bin/perl -w +# test_set_nw_dst + +use strict; +use OF::Includes; + +sub send_expect_exact { + my ($ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len) = @_; + + my $in_port = $in_port_offset + $$options_ref{'port_base'}; + my $out_port = $out_port_offset + $$options_ref{'port_base'}; + + # in_port refers to the flow mod entry's input + + # Create the payload ourselves to make sure the two packets match + # Jean II + my $pkt_payload = [map {int(rand(256))} (1..($pkt_len - 8 - 4 - 16 - 14))]; + + # This is the packet we are sending... - Jean II + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + tos => 0x0, + ttl => 64, + len => $pkt_len, + src_port => 1, + dst_port => 0, + data => $pkt_payload + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + # This is the packet we are expecting to receive - Jean II + my $expect_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + src_ip => "192.168.201." . ( $out_port ), + dst_ip => "192.168.200." . ( $in_port ), + tos => 0x0, + ttl => 64, + len => $pkt_len, + src_port => 1, + dst_port => 0, + data => $pkt_payload + }; + my $expect_pkt = new NF2::UDP_pkt(%$expect_pkt_args); + + #print HexDump ($test_pkt->packed); + + my $wildcards = 0x0; # exact match + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry + + # Get the various addresses in the expected packet - Jean II + my $chg_val_dl_da = ${$expect_pkt->{Ethernet_hdr}}->DA; + my $chg_val_dl_sa = ${$expect_pkt->{Ethernet_hdr}}->SA; + my $chg_val_nw_dst = ${$expect_pkt->{IP_hdr}}->dst_ip; + my $chg_val_nw_src = ${$expect_pkt->{IP_hdr}}->src_ip; + my @dl_da_addr_chg = NF2::PDU::get_MAC_address($chg_val_dl_da); + my @dl_sa_addr_chg = NF2::PDU::get_MAC_address($chg_val_dl_sa); + my $nw_dst_addr_chg; + my $ok_org; + ($nw_dst_addr_chg, $ok_org) = NF2::IP_hdr::getIP($chg_val_nw_dst); + my $nw_src_addr_chg; + ($nw_src_addr_chg, $ok_org) = NF2::IP_hdr::getIP($chg_val_nw_src); + + # Create the desired rewrite actions + my @pad_6 = (0,0,0,0,0,0); + my $action_mod_dl_da_args = { + type => $enums{'OFPAT_SET_DL_DST'}, + len => $ofp->sizeof('ofp_action_dl_addr'), + dl_addr => \@dl_da_addr_chg, + pad => \@pad_6, + }; + my $action_mod_dl_da = $ofp->pack('ofp_action_dl_addr', $action_mod_dl_da_args); + my $action_mod_dl_sa_args = { + type => $enums{'OFPAT_SET_DL_SRC'}, + len => $ofp->sizeof('ofp_action_dl_addr'), + dl_addr => \@dl_sa_addr_chg, + pad => \@pad_6, + }; + my $action_mod_dl_sa = $ofp->pack('ofp_action_dl_addr', $action_mod_dl_sa_args); + my $action_mod_nw_dst_args = { + type => $enums{'OFPAT_SET_NW_DST'}, + len => $ofp->sizeof('ofp_action_nw_addr'), + nw_addr => $nw_dst_addr_chg, + }; + my $action_mod_nw_dst = $ofp->pack( 'ofp_action_nw_addr', $action_mod_nw_dst_args ); + my $action_mod_nw_src_args = { + type => $enums{'OFPAT_SET_NW_SRC'}, + len => $ofp->sizeof('ofp_action_nw_addr'), + nw_addr => $nw_src_addr_chg, + }; + my $action_mod_nw_src = $ofp->pack( 'ofp_action_nw_addr', $action_mod_nw_src_args ); + + # Output action to get the packet out someplace - Jean II + my $action_output_args = { + type => $enums{'OFPAT_OUTPUT'}, + len => $ofp->sizeof('ofp_action_output'), + port => $out_port, + max_len => 0, # send entire packet + }; + my $action_output = $ofp->pack( 'ofp_action_output', $action_output_args ); + + # Aggregate all actions together + my $action_bytes = $action_mod_dl_da . $action_mod_dl_sa . $action_mod_nw_dst . $action_mod_nw_src . $action_output; + + my $flow_mod_pkt = + create_flow_mod_from_udp_actionbytes( $ofp, $test_pkt, $in_port, $max_idle, $flags, $wildcards, 'OFPFC_ADD', $action_bytes); + + #print HexDump($flow_mod_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent flow_mod message\n"; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + + # Send a packet - ensure packet comes out desired port + nftest_send("eth" . ($in_port_offset + 1), $test_pkt->packed); + nftest_expect("eth" . ($out_port_offset + 1), $expect_pkt->packed); +} + +sub test_set_nw_dst { + my ($ofp, $sock, $options_ref, $i, $j, $wildcards) = @_; + + my $max_idle = $$options_ref{'max_idle'}; + my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_total = $$options_ref{'pkt_total'}; + + send_expect_exact($ofp, $sock, $options_ref, $i, $j, $max_idle, $pkt_len); + wait_for_flow_expired($ofp, $sock, $options_ref, $pkt_len, $pkt_total); +} + +sub my_test { + my ($sock, $options_ref) = @_; + + # send from every port to every other port + for_all_port_pairs($ofp, $sock, $options_ref, \&test_set_nw_dst, 0x0); +} + +run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_set_n_match_nw_tos/run.pl b/openflow/regress/projects/black_box/regress/test_set_n_match_nw_tos/run.pl new file mode 100755 index 00000000..4470c812 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_set_n_match_nw_tos/run.pl @@ -0,0 +1,95 @@ +#!/usr/bin/perl -w +# test_set_nw_tos + +use strict; +use OF::Includes; + +# Please check the following : +# http://en.wikipedia.org/wiki/Type_of_Service + +sub send_expect_exact { + my ($ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len, $vlan_id) = @_; + + my $in_port = $in_port_offset + $$options_ref{'port_base'}; + my $out_port = $out_port_offset + $$options_ref{'port_base'}; + + # in_port refers to the flow mod entry's input + + # Create the payload ourselves to make sure the two packets match + # Jean II + my $pkt_payload = [map {int(rand(256))} (1..($pkt_len - 8 - 4 - 16 - 14))]; + + # This is the packet we are sending... - Jean II + # Set an ECN bit to see if it gets clobbered + my $test_nw_tos = 0xA8; + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + tos => $test_nw_tos | 0x01, # => 0xA9 + ttl => 64, + len => $pkt_len, + src_port => 1, + dst_port => 0, + data => $pkt_payload + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + # This is the packet we are expecting to receive - Jean II + my $expect_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + tos => 0x54 | 0x01, # 0x55 + ttl => 64, + len => $pkt_len, + src_port => 1, + dst_port => 0, + data => $pkt_payload + }; + my $expect_pkt = new NF2::UDP_pkt(%$expect_pkt_args); + + #print HexDump ($test_pkt->packed); + + my $wildcards = 0x0; # exact match + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry + # Don't set ECN bits here, OVS reject it as invalid... + my $nw_tos = 0x54; + + my $flow_mod_pkt = create_flow_mod_from_udp_action($ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards, 'OFPFC_ADD', 'nw_tos', $nw_tos, $vlan_id, $test_nw_tos); + + #print HexDump($flow_mod_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent flow_mod message\n"; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + + # Send a packet - ensure packet comes out desired port + nftest_send("eth" . ($in_port_offset + 1), $test_pkt->packed); + nftest_expect("eth" . ($out_port_offset + 1), $expect_pkt->packed); +} + +sub test_set_nw_tos { + my ($ofp, $sock, $options_ref, $i, $j, $wildcards) = @_; + + my $max_idle = $$options_ref{'max_idle'}; + my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_total = $$options_ref{'pkt_total'}; + + send_expect_exact($ofp, $sock, $options_ref, $i, $j, $max_idle, $pkt_len); + wait_for_flow_expired($ofp, $sock, $options_ref, $pkt_len, $pkt_total); +} + +sub my_test { + my ($sock, $options_ref) = @_; + + # send from every port to every other port + for_all_port_pairs( $ofp, $sock, $options_ref, \&test_set_nw_tos, 0x0); +} + +run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_set_nw_dst/run.pl b/openflow/regress/projects/black_box/regress/test_set_nw_dst/run.pl new file mode 100755 index 00000000..ae101798 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_set_nw_dst/run.pl @@ -0,0 +1,95 @@ +#!/usr/bin/perl -w +# test_set_nw_dst + +use strict; +use OF::Includes; + +sub send_expect_exact { + my ($ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len) = @_; + + my $in_port = $in_port_offset + $$options_ref{'port_base'}; + my $out_port = $out_port_offset + $$options_ref{'port_base'}; + + # in_port refers to the flow mod entry's input + + # Create the payload ourselves to make sure the two packets match + # Jean II + my $pkt_payload = [map {int(rand(256))} (1..($pkt_len - 8 - 4 - 16 - 14))]; + + # This is the packet we are sending... - Jean II + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + tos => 0x0, + ttl => 64, + len => $pkt_len, + src_port => 1, + dst_port => 0, + data => $pkt_payload + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + # This is the packet we are expecting to receive - Jean II + my $expect_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + #dst_ip => "192.168.201." . ( $out_port + 1), + dst_ip => ( $out_port ) . ".201.168.192" , + tos => 0x0, + ttl => 64, + len => $pkt_len, + src_port => 1, + dst_port => 0, + data => $pkt_payload + }; + my $expect_pkt = new NF2::UDP_pkt(%$expect_pkt_args); + + #print HexDump ($test_pkt->packed); + + my $wildcards = 0x0; # exact match + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry + + # Get the IP address in the expected packet in binary form - Jean II + my $chg_val_nw_dst = ${$expect_pkt->{IP_hdr}}->dst_ip; + my $nw_dst_addr_chg; + my $ok_org; + ($nw_dst_addr_chg, $ok_org) = NF2::IP_hdr::getIP($chg_val_nw_dst); + + my $flow_mod_pkt = create_flow_mod_from_udp_action($ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards, 'OFPFC_ADD', 'nw_dst', $nw_dst_addr_chg); + + #print HexDump($flow_mod_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent flow_mod message\n"; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + + # Send a packet - ensure packet comes out desired port + nftest_send("eth" . ($in_port_offset + 1), $test_pkt->packed); + nftest_expect("eth" . ($out_port_offset + 1), $expect_pkt->packed); +} + +sub test_set_nw_dst { + my ($ofp, $sock, $options_ref, $i, $j, $wildcards) = @_; + + my $max_idle = $$options_ref{'max_idle'}; + my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_total = $$options_ref{'pkt_total'}; + + send_expect_exact($ofp, $sock, $options_ref, $i, $j, $max_idle, $pkt_len); + wait_for_flow_expired($ofp, $sock, $options_ref, $pkt_len, $pkt_total); +} + +sub my_test { + my ($sock, $options_ref) = @_; + + # send from every port to every other port + for_all_port_pairs($ofp, $sock, $options_ref, \&test_set_nw_dst, 0x0); +} + +run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_stats_desc/run.pl b/openflow/regress/projects/black_box/regress/test_stats_desc/run.pl new file mode 100755 index 00000000..9409ac9d --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_stats_desc/run.pl @@ -0,0 +1,71 @@ +#!/usr/bin/perl -w +# test_flow_stats + +use strict; +use OF::Includes; + +sub stats_desc_test { + + my ( $sock, $options_ref ) = @_; + + my $port_base = $$options_ref{'port_base'}; + + my $hdr_args = { + version => get_of_ver(), + type => $enums{'OFPT_STATS_REQUEST'}, + length => $ofp->sizeof('ofp_stats_request') , # should generate automatically! + xid => 0x00000001 + }; + + my $stats_request_args = { + header => $hdr_args, + type => $enums{'OFPST_DESC'}, + flags => 0 + }; + + my $stats_request = $ofp->pack( 'ofp_stats_request', $stats_request_args ); + + # Send 'stats_request' message + print $sock $stats_request; + + # Should add timeout here - will crash if no reply + my $recvd_mesg; + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; + + # Inspect message + my $resp_size = length($recvd_mesg); + + my $resp_header = $ofp->unpack( 'ofp_stats_reply', $recvd_mesg ); + + #print HexDump ($recvd_mesg); + print Dumper($resp_header); + + # Verify fields + verify_header( $resp_header, 'OFPT_STATS_REPLY', $resp_size ); + + # Unmarshall embedded description + my $resp_body = $ofp->unpack('ofp_desc_stats', + substr($recvd_mesg, $ofp->offsetof('ofp_stats_reply', 'body'))); + print Dumper($resp_body); + print "keys: " . join(" ",keys %$resp_body) . "\n"; + my $key; + foreach $key (sort keys %$resp_body) + { + my $val = $resp_body->{$key}; + my $len = scalar(@{$val}); + printf("key=%s ref=%s len=%d val='%s'\n", + $key, + ref($val), + $len, + pack("c*", @{$val}) + #@{$val} + ); + } + + #die("forced death"); + die("Missing dp_desc in desc_stats") unless(defined($resp_body->{"dp_desc"})); + +} + +run_black_box_test( \&stats_desc_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_switch_config/run.pl b/openflow/regress/projects/black_box/regress/test_switch_config/run.pl new file mode 100755 index 00000000..cbb4886e --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_switch_config/run.pl @@ -0,0 +1,40 @@ +#!/usr/bin/perl -w +# test_switch_config + +use strict; +use OF::Includes; + +sub my_test { + + my ($sock, $options_ref) = @_; + + my $msg = get_config( $ofp, $sock ); + + # Verify that the miss_send_len is set to the correct default + compare( "miss send len", $$msg{'miss_send_len'}, '==', get_of_miss_send_len_default() ); + + # As of OF v0.8.1, there was no default for flags - we assume 0 + # (don't send flow expiration messages) + compare( "flags", $$msg{'flags'}, '==', 0 ); + + # Now, we change the config and check that it has been committed + + # Set flag OFPC_SEND_FLOW_EXP, which has val 1, and should cause flow exps + my $flags = 1; + + # Change miss_send_len from the default + my $miss_send_len = 0x100; + + set_config($ofp, $sock, $options_ref, $flags, $miss_send_len); + + # Give OF switch time to process the set_config + usleep($$options_ref{'send_delay'}); + + $msg = get_config( $ofp, $sock ); + + compare( "miss send len", $$msg{'miss_send_len'}, '==', $miss_send_len ); + compare( "flags", $$msg{'flags'}, '==', $flags ); +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_tcp_options/run.pl b/openflow/regress/projects/black_box/regress/test_tcp_options/run.pl new file mode 100755 index 00000000..b9025bb0 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_tcp_options/run.pl @@ -0,0 +1,170 @@ +#!/usr/bin/perl -w +# test_tcp_options + +use strict; +use OF::Includes; + +sub create_flow_mod_from_ip { + + my ( $ofp, $udp_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards, $s_port, $d_port ) = @_; + + my $hdr_args = { + version => get_of_ver(), + type => $enums{'OFPT_FLOW_MOD'}, + length => $ofp->sizeof('ofp_flow_mod') + $ofp->sizeof('ofp_action_output'), + xid => 0x0000000 + }; + + # might be cleaner to convert the exported colon-hex MAC addrs + #print ${$udp_pkt->{Ethernet_hdr}}->SA . "\n"; + #print ${$test_pkt->{Ethernet_hdr}}->SA . "\n"; + my $ref_to_eth_hdr = ( $udp_pkt->{'Ethernet_hdr'} ); + my $ref_to_ip_hdr = ( $udp_pkt->{'IP_hdr'} ); + + # pointer to array + my $eth_hdr_bytes = $$ref_to_eth_hdr->{'bytes'}; + my $ip_hdr_bytes = $$ref_to_ip_hdr->{'bytes'}; + my @dst_mac_subarray = @{$eth_hdr_bytes}[ 0 .. 5 ]; + my @src_mac_subarray = @{$eth_hdr_bytes}[ 6 .. 11 ]; + + my @src_ip_subarray = @{$ip_hdr_bytes}[ 12 .. 15 ]; + my @dst_ip_subarray = @{$ip_hdr_bytes}[ 16 .. 19 ]; + + my $src_ip = + ( ( 2**24 ) * $src_ip_subarray[0] + + ( 2**16 ) * $src_ip_subarray[1] + + ( 2**8 ) * $src_ip_subarray[2] + + $src_ip_subarray[3] ); + + my $dst_ip = + ( ( 2**24 ) * $dst_ip_subarray[0] + + ( 2**16 ) * $dst_ip_subarray[1] + + ( 2**8 ) * $dst_ip_subarray[2] + + $dst_ip_subarray[3] ); + + # read IP_header protocol field + my $iph = $udp_pkt->{'IP_hdr'}; + my $proto = $$iph->proto(); + + my $match_args = { + wildcards => $wildcards, + in_port => $in_port, + dl_src => \@src_mac_subarray, + dl_dst => \@dst_mac_subarray, + dl_vlan => 0xffff, + dl_vlan_pcp => 0x00, + dl_type => 0x0800, + nw_src => $src_ip, + nw_dst => $dst_ip, + nw_proto => $proto, #any protocol + tp_src => $s_port, + tp_dst => $d_port + }; + + print "My Out Port: ${out_port}\n"; + my $action_output_args = { + type => $enums{'OFPAT_OUTPUT'}, + len => $ofp->sizeof('ofp_action_output'), + port => $out_port, + max_len => 0 # send entire packet + }; + my $action_output = $ofp->pack('ofp_action_output', $action_output_args); + + my $flow_mod_args = { + header => $hdr_args, + match => $match_args, + command => $enums{'OFPFC_ADD'}, + idle_timeout => $max_idle, + hard_timeout => $max_idle, + flags => $flags, + priority => 0, + buffer_id => -1 + }; + my $flow_mod = $ofp->pack( 'ofp_flow_mod', $flow_mod_args ); + + my $flow_mod_pkt = $flow_mod . $action_output; + + return $flow_mod_pkt; +} + +sub send_tcp_op_expect_exact { + + my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len ) = @_; + + my $in_port = $in_port_offset + $$options_ref{'port_base'}; + my $out_port = $out_port_offset + $$options_ref{'port_base'}; + + my $src_tcp_port = 70; + my $dst_tcp_port = 80; + + # in_port refers to the flow mod entry's input + my @tcp_payload = ( # 30 bytes + 0x00, 0x46, 0x00, 0x50, # $src_tcp_port, $dst_tcp_port (should set automatically) + 0x01, 0x23, 0x45, 0x67, #Seq + 0x01, 0x23, 0x45, 0x00, #Ack + 0x58, 0x23, 0x00, 0x11, #Offset, Flag, Win + 0xaa, 0xbb, 0x00, 0x00, #Chksum, Urgent + 0x03, 0x03, 0x02, 0x00, #TCP Option + 0xaa, 0xbb, 0xcc, 0xdd, #TCP Content + 0xee, 0xff #TCP Content + ); + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + proto => 6, # TCP protocol id + }; + + my $test_pkt = new NF2::IP_pkt(%$test_pkt_args); + my $payload = $test_pkt->{'payload'}; + $$payload->set_bytes(@tcp_payload); + + #print HexDump ( $test_pkt->packed ); + + #my $wildcards = 0; # exact match + my $wildcards = $enums{'OFPFW_TP_SRC'} | + $enums{'OFPFW_TP_DST'};# | + # $enums{'OFPFW_NW_PROTO'}; # wildcard match (don't care udp src/dst ports) + + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; + my $flow_mod_pkt = + create_flow_mod_from_ip( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards, + $src_tcp_port, $dst_tcp_port ); + + #print HexDump($flow_mod_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent flow_mod message\n"; + usleep($$options_ref{'send_delay'}); + + # Send a packet - ensure packet comes out desired port + nftest_send( "eth" . ( $in_port_offset + 1), $test_pkt->packed ); + nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); +} + +sub test_tcp_options { + my ( $ofp, $sock, $options_ref, $i, $j, $wildcards ) = @_; + + my $max_idle = $$options_ref{'max_idle'}; + #my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_len = 64; # len = 14(Ethr_hdr)+ 20(IP_header)+ 30(TCP_header+Option) + # = 64 (IPlen = 50) + my $pkt_total = $$options_ref{'pkt_total'}; + + send_tcp_op_expect_exact( $ofp, $sock, $options_ref, $i, $j, $max_idle, $pkt_len ); + #sleep(5); + wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); +} + +sub my_test { + my ( $sock, $options_ref ) = @_; + + # send from every port to every other port + for_all_port_pairs( $ofp, $sock, $options_ref, \&test_tcp_options, 0x0); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/tests.txt b/openflow/regress/projects/black_box/regress/tests.txt new file mode 100644 index 00000000..f77158ec --- /dev/null +++ b/openflow/regress/projects/black_box/regress/tests.txt @@ -0,0 +1,103 @@ +## two #'s = not tested; 1 # = worked once + +# Basic Tests +test_hello/run.pl +test_barrier/run.pl +test_packet_in/run.pl +test_packet_out/run.pl +test_switch_config/run.pl +test_flow_expired/run.pl +test_flow_expired_idle_timeout/run.pl +test_flow_expired_precision/run.pl +test_flow_expired_send_flow_exp/run.pl +test_miss_send_length/run.pl + +# Read State Tests +test_stats_desc/run.pl +test_port_stats/run.pl +test_flow_stats/run.pl +test_flow_stats_precision/run.pl + +## Forwarding Tests +test_forward_any_port/run.pl +test_forward_exact_port/run.pl +test_forward_broadcast_exact_port/run.pl +test_forward_exact_all/run.pl +test_forward_exact_controller/run.pl +test_forward_wildcard_port/run.pl +test_forward_wildcard_all/run.pl +test_forward_wildcard_controller/run.pl +test_forward_after_expiration/run.pl +test_forward_overlapping_flow_entries/run.pl +test_delete/run.pl +test_delete_strict/run.pl +test_delete_send_flow_exp/run.pl +test_drop_exact/run.pl + +## Modify Action Tests +test_forward_exact_modify_action/run.pl +test_forward_wildcard_modify_action/run.pl +test_flow_mod_check/run.pl +test_set_nw_dst/run.pl +test_set_n_match_nw_tos/run.pl +test_set_dl_nw_flip/run.pl + +## ICMP handling Tests +test_forward_exact_icmp_port/run.pl +test_forward_exact_icmp_all/run.pl +test_forward_exact_icmp_controller/run.pl +test_forward_exact_icmp_fool/run.pl +test_forward_wildcard_icmp_port/run.pl +test_forward_wildcard_icmp_all/run.pl +test_forward_wildcard_icmp_controller/run.pl +test_forward_wildcard_icmp_fool/run.pl + +## ARP handling Tests +test_forward_exact_arp_port/run.pl +test_forward_exact_arp_all/run.pl +test_forward_exact_arp_controller/run.pl +test_forward_exact_arp_fool/run.pl +test_forward_wildcard_arp_port/run.pl +test_forward_wildcard_arp_all/run.pl +test_forward_wildcard_arp_controller/run.pl +test_forward_wildcard_arp_fool/run.pl + +# Flow cookies +test_cookie_flow_expired/run.pl +test_cookie_flow_stats/run.pl + +## Slicing Tests - can be disable via --no_slicing +test_queue_config/run.pl +## These assume that there is a queue with queue_id=1 at port 1. +## Uncomment if your setup supports this. +## Should work OK with the reference implementation +#test_queue_stats/run.pl +test_queue_forward/run.pl + +## Unusual Data +test_ip_options/run.pl +##test_ip_protocol/run.pl +test_ip_offset/run.pl +test_tcp_options/run.pl +##test_llc/run.pl + +# Failover Tests +test_failover_startup/run.pl +test_failover_close/run.pl + +# BELOW NOT INCLUDED IN CURRRENT RELEASE +# WILL BE AVAILABLE SOON +# Stress Tests / Performance Evaluation +#test_send_bandwidth_fixed/run.pl +#test_send_bandwidth_random/run.pl +#test_add_flow_bandwidth/run.pl +#test_add_flow_latency/run.pl +#test_receive_bandwidth_fixed/run.pl +#test_receive_bandwidth_random/run.pl +#test_forward_bandwidth_fixed/run.pl +#test_forward_bandwidth_random/run.pl +#test_forward_latency/run.pl +#test_switch_bandwidth_random/run.pl +#test_switch_bandwidth_random/run.pl +# Additional Failover tests +#test_failover_stop_responding/run.pl diff --git a/openflow/regress/projects/controller_disconnect/regress/common/setup b/openflow/regress/projects/controller_disconnect/regress/common/setup new file mode 100755 index 00000000..f796718c --- /dev/null +++ b/openflow/regress/projects/controller_disconnect/regress/common/setup @@ -0,0 +1,49 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use Test::TestLib; +use OF::OFUtil; + +my $mapFile; +my $platform; +my $args; + +# Process command line options +unless ( + GetOptions ( + "map=s" => \$mapFile, + "common-st-args=s" => \$platform, + ) +) +{ + print "invalid command format\n"; + exit(1); +} + +if (defined($mapFile)) { + $args = "--map=$mapFile"; +} + +if (!defined($platform)) { + print "no platform defined\n"; + exit(1); +} +else { + print "platform = $platform\n"; +} + +$args .= " --emerg"; + +my $filename = "of_${platform}_setup.pl"; + +# exit if of_${platform}_setup.pl not in path +if (-e "$ENV{'OFT_ROOT'}/bin/$filename") { + #system("$filename " . $args . " 2> /dev/null > /dev/null"); + system("$ENV{'OFT_ROOT'}/bin/$filename " . $args ); + #setup_kmod(); + exit (0); +} else { + print "couldn't find setup file $filename\n"; + exit (1); +} diff --git a/openflow/regress/projects/controller_disconnect/regress/common/teardown b/openflow/regress/projects/controller_disconnect/regress/common/teardown new file mode 100755 index 00000000..6f1f8391 --- /dev/null +++ b/openflow/regress/projects/controller_disconnect/regress/common/teardown @@ -0,0 +1,47 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use Test::TestLib; +use OF::OFUtil; + +my $mapFile; +my $platform; +my $args; + +# Process command line options +unless ( + GetOptions ( + "map=s" => \$mapFile, + "common-st-args=s" => \$platform, + ) +) +{ + print "invalid command format\n"; + exit(1); +} + +if (defined($mapFile)) { + $args = "--map=$mapFile"; +} + +if (!defined($platform)) { + print "no platform defined\n"; + exit(1); +} +else { + print "platform = $platform\n"; +} + +my $filename = "of_${platform}_teardown.pl"; + +# exit if of_${platform}_setup.pl not in path +if (-e "$ENV{'OFT_ROOT'}/bin/$filename") { + #system("$filename " . $args . " 2> /dev/null > /dev/null"); + system("$ENV{'OFT_ROOT'}/bin/$filename " . $args ); + #teardown_kmod(); + exit (0); +} else { + print "couldn't find setup file $filename\n"; + exit (1); +} diff --git a/openflow/regress/projects/controller_disconnect/regress/test_emergency_table/run.pl b/openflow/regress/projects/controller_disconnect/regress/test_emergency_table/run.pl new file mode 100755 index 00000000..7e07a6c8 --- /dev/null +++ b/openflow/regress/projects/controller_disconnect/regress/test_emergency_table/run.pl @@ -0,0 +1,107 @@ +#!/usr/bin/perl -w +# test_emergency_table + +use strict; +use OF::Includes; +use OF::OFUtil; + +sub test_emergency_cache_first { + my ( $ofp, $sock, $options_ref, $i, $j, $wildcards ) = @_; + + my $max_idle = $$options_ref{'max_idle'}; + my $pkt_len = $$options_ref{'pkt_len'}; + my $in_port = $i + $$options_ref{'port_base'}; + my $out_port = $j + $$options_ref{'port_base'}; + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + src_port => 70, + dst_port => 80 + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + print "Set both normal and emergency flow table. Normal key must win\n"; + + # 1st flow entry -- exact match, normal flow table + my $max_idle_no_expire = 0; + my $normal_wildcards = 0x0; # exact match + my $normal_flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry + my $flow_mod_normal_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle_no_expire, $normal_flags, $normal_wildcards ); + + # 2nd flow entry -- wildcard match all, emergency flow table + my $emergency_wildcards = $enums{'OFPFW_ALL'}; # wildcard match all to the all ports + my $emergency_flags = $enums{'OFPFF_EMERG'}; + my $flow_mod_emergency_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $enums{'OFPP_ALL'}, $max_idle_no_expire, $emergency_flags, $emergency_wildcards ); + + #print HexDump($flow_mod_normal_pkt); + #print HexDump($flow_mod_emergency_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_normal_pkt; + print "sent flow_mod message (normal table)\n"; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + + # Send 2nd 'flow_mod' message + print $sock $flow_mod_emergency_pkt; + print "sent flow_mod message (emergency table)\n"; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + + # Send a packet - ensure packet comes out desired port + print "Verify packets are forwarded correctly\n"; + nftest_send( "eth" . ( $i + 1 ), $test_pkt->packed ); + nftest_expect( "eth" . ( $j + 1 ), $test_pkt->packed ); + + # Wait for ECHO_REQUEST but don't reply so that ofprotocol notices disconnection. + wait_for_echo_request ( $ofp, $sock, $options_ref, $ofp->sizeof('ofp_header')); + return $test_pkt; +} + +sub test_emergency_cache_second { + my ( $test_pkt, $options_ref, $i, $j ) = @_; + + print "sending from $i to $j, but expect the packet from all ports\n"; + nftest_send( "eth" . ( $i + 1 ), $test_pkt->packed ); + + # expect packets on all other interfaces + print "expect multiple packets\n"; + + for ( my $k = 0 ; $k < $$options_ref{'num_ports'} ; $k++ ) { + if ( $k != $i ) { + nftest_expect( "eth" . ( $k + 1), $test_pkt->packed ); + } + } +} + +sub my_test { + my ($sock, $options_ref) = @_; + + if ( not defined( $$options_ref{'no_emerg'} ) ) { + #This test uses two ports + my $inport = 0; + my $outport = 1; + my $wildcards = 0; #exact match + + # Wait until switch notices disconnection. it depends on implementation + my $wait_timer = 20; + + my $test_pkt = test_emergency_cache_first($ofp, $sock, $options_ref, $inport, $outport, $wildcards); + + # Wait until ofprotocol notices that connection is broken + sleep $wait_timer; + + # chek if the emergency table has become active + test_emergency_cache_second($test_pkt, $options_ref, $inport, $outport); + } +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/controller_disconnect/regress/tests.txt b/openflow/regress/projects/controller_disconnect/regress/tests.txt new file mode 100644 index 00000000..0d34d9b3 --- /dev/null +++ b/openflow/regress/projects/controller_disconnect/regress/tests.txt @@ -0,0 +1,2 @@ +test_emergency_table/run.pl +#test_reconnect/run.pl diff --git a/openflow/regress/projects/learning_switch/regress/common/setup b/openflow/regress/projects/learning_switch/regress/common/setup new file mode 100755 index 00000000..29653173 --- /dev/null +++ b/openflow/regress/projects/learning_switch/regress/common/setup @@ -0,0 +1,46 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use Test::TestLib; +use OF::OFUtil; + +my $mapFile; +my $platform; +my $args; + +# Process command line options +unless ( + GetOptions ( + "map=s" => \$mapFile, + "common-st-args=s" => \$platform, + ) +) +{ + print "invalid command format\n"; + exit(1); +} + +if (defined($mapFile)) { + $args = "--map=$mapFile"; +} + +if (!defined($platform)) { + print "no platform defined\n"; + exit(1); +} +else { + print "platform = $platform\n"; +} + +my $filename = "of_${platform}_setup.pl"; + +# exit if of_${platform}_setup.pl not in path +if (-e "$ENV{'OFT_ROOT'}/bin/$filename") { + system("$ENV{'OFT_ROOT'}/bin/$filename " . $args . " 2> /dev/null > /dev/null"); + #setup_kmod(); + exit (0); +} else { + print "couldn't find setup file $filename\n"; + exit (1); +} diff --git a/openflow/regress/projects/learning_switch/regress/common/teardown b/openflow/regress/projects/learning_switch/regress/common/teardown new file mode 100755 index 00000000..c1813189 --- /dev/null +++ b/openflow/regress/projects/learning_switch/regress/common/teardown @@ -0,0 +1,46 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use Test::TestLib; +use OF::OFUtil; + +my $mapFile; +my $platform; +my $args; + +# Process command line options +unless ( + GetOptions ( + "map=s" => \$mapFile, + "common-st-args=s" => \$platform, + ) +) +{ + print "invalid command format\n"; + exit(1); +} + +if (defined($mapFile)) { + $args = "map=$mapFile"; +} + +if (!defined($platform)) { + print "no platform defined\n"; + exit(1); +} +else { + print "platform = $platform\n"; +} + +my $filename = "of_${platform}_teardown.pl"; + +# exit if of_${platform}_setup.pl not in path +if (-e "$ENV{'OFT_ROOT'}/bin/$filename") { + system("$ENV{'OFT_ROOT'}/bin/$filename " . $args . " 2> /dev/null > /dev/null"); + #teardown_kmod(); + exit (0); +} else { + print "couldn't find setup file $filename\n"; + exit (1); +} diff --git a/openflow/regress/projects/learning_switch/regress/test_broadcast/run.pl b/openflow/regress/projects/learning_switch/regress/test_broadcast/run.pl new file mode 100755 index 00000000..f721f4db --- /dev/null +++ b/openflow/regress/projects/learning_switch/regress/test_broadcast/run.pl @@ -0,0 +1,50 @@ +#!/usr/bin/perl -w +# test_broadcast + +use strict; +use OF::Includes; + +sub gen_broadcast_pkt { + my ($portNum) = shift; + + my $pkt_args = { + DA => "FF:FF:FF:FF:FF:FF", + SA => "00:00:00:00:00:0" . $portNum, + src_ip => "192.168." . $portNum . ".40", + dst_ip => "255.255.255.255", + ttl => 64, + len => 64 + }; + my $pkt = new NF2::IP_pkt(%$pkt_args); + return $pkt; +} + +sub send_expect_broadcast { + my ( $portNum, $pkt, $delta_ref ) = @_; + + send_and_count( 'eth' . $portNum, $pkt->packed, $delta_ref ); + for ( my $i = 1 ; $i <= 4 ; $i++ ) { + if ( $i != $portNum ) { + expect_and_count( 'eth' . $i, $pkt->packed, $delta_ref ); + } + } +} + +sub my_test { + + my %delta; + + for ( my $i = 1 ; $i < 4 ; $i++ ) { + my $pkt = gen_broadcast_pkt($i); + + # send one broadcast packet, then do it again on the same port + send_expect_broadcast( $i, $pkt, \%delta ); + sleep 0.1; + send_expect_broadcast( $i, $pkt, \%delta ); + sleep 0.1; + } + + return %delta; +} + +run_learning_switch_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/learning_switch/regress/test_forward_bandwidth/run.pl b/openflow/regress/projects/learning_switch/regress/test_forward_bandwidth/run.pl new file mode 100755 index 00000000..473afa81 --- /dev/null +++ b/openflow/regress/projects/learning_switch/regress/test_forward_bandwidth/run.pl @@ -0,0 +1,62 @@ +#!/usr/bin/perl -w +#test_unicast_unknown + +use Test::TestLib; +use Test::PacketLib; +use OF::OFUtil; +use Time::HiRes qw(sleep gettimeofday tv_interval usleep); +use strict; + +sub my_test { + my $cnt = 0; + my %delta; + my $pkt_len = 1512; + + my $pkt_args = { + DA => "00:01:00:00:00:02", + SA => "00:00:00:00:00:01", + src_ip => "192.168.0.40", + dst_ip => "192.168.0.41", + ttl => 64, + len => 64 + }; + my $pkt = new NF2::IP_pkt(%$pkt_args); + + # send one packet; controller should learn MAC, add a flow + # entry, and send this packet out the other interfaces + + send_and_count( nftest_get_iface('eth1'), $pkt->packed, \%delta ); + expect_and_count( nftest_get_iface('eth2'), $pkt->packed, \%delta ); + expect_and_count( nftest_get_iface('eth3'), $pkt->packed, \%delta ); + expect_and_count( nftest_get_iface('eth4'), $pkt->packed, \%delta ); + + my @start_time = gettimeofday(); + for ( $cnt = 10 ; $cnt < 20 ; $cnt++ ) { + for ( my $t = 10 ; $t < 100 ; $t++ ) { + my $pkt_args = { + DA => "00:00:00:00:00:01", + SA => "00:00:00:00:$t:$cnt", + src_ip => "192.168.$t.$cnt", + dst_ip => "192.168.1.40", + ttl => 64, + len => $pkt_len + }; + my $pkt = new NF2::IP_pkt(%$pkt_args); + + send_and_count( nftest_get_iface('eth2'), $pkt->packed, \%delta ); + expect_and_count( nftest_get_iface('eth1'), $pkt->packed, \%delta ); + } + } + ( my $second, my $micro ) = tv_interval( \@start_time ); + my $time_elapsed = ( $second + $micro * 1e-6 ); + + my $bw_result = (900 * $pkt_len * 8) / $time_elapsed; + print "PACKET LENGTH: $pkt_len \n"; + print "TIME ELAPSED: $time_elapsed \n"; + print "RESULTING BW: $bw_result bits/sec \n"; + + return %delta; +} + +# how do we pass the cmd-line arguments to the script? +run_learning_switch_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/learning_switch/regress/test_forward_latency/run.pl b/openflow/regress/projects/learning_switch/regress/test_forward_latency/run.pl new file mode 100755 index 00000000..e9690d80 --- /dev/null +++ b/openflow/regress/projects/learning_switch/regress/test_forward_latency/run.pl @@ -0,0 +1,69 @@ +#!/usr/bin/perl -w +#test_fwd_delay +# send 1000 packets to find latency for both new flows and existing ones + +use Test::TestLib; +use Test::PacketLib; +use OF::OFUtil; +use strict; +use Time::HiRes qw(sleep gettimeofday tv_interval usleep); + +sub my_test { + my $cnt = 0; + + my $start_time_ref = [gettimeofday]; + my %delta; + for ( my $t = 10 ; $t < 20 ; $t++ ) { + for ( $cnt = 10 ; $cnt < 100 ; $cnt++ ) { + my $pkt_args = { + DA => "00:01:00:00:$t:$cnt", + SA => "00:00:00:00:00:01", + src_ip => "192.168.0.40", + dst_ip => "192.168.$cnt.$t", + ttl => 64, + len => 64 + }; + my $pkt = new NF2::IP_pkt(%$pkt_args); + + # send one packet; controller should learn MAC, add a flow + # entry, and send this packet out the other interfaces + send_and_count( nftest_get_iface('eth1'), $pkt->packed, \%delta ); + expect_and_count( nftest_get_iface('eth2'), $pkt->packed, \%delta ); + expect_and_count( nftest_get_iface('eth3'), $pkt->packed, \%delta ); + expect_and_count( nftest_get_iface('eth4'), $pkt->packed, \%delta ); + } + } + my $total_time_unknown = tv_interval( $start_time_ref ); + + $start_time_ref = [gettimeofday()]; + for ( $cnt = 10 ; $cnt < 20 ; $cnt++ ) { + for ( my $t = 10 ; $t < 100 ; $t++ ) { + my $pkt_args = { + DA => "00:00:00:00:00:01", + SA => "00:00:00:00:$t:$cnt", + src_ip => "192.168.$t.$cnt", + dst_ip => "192.168.1.40", + ttl => 64, + len => 64 + }; + my $pkt = new NF2::IP_pkt(%$pkt_args); + + # send packet; flow entries are already added for these + send_and_count( nftest_get_iface('eth2'), $pkt->packed, \%delta ); + expect_and_count( nftest_get_iface('eth1'), $pkt->packed, \%delta ); + } + } + my $total_time_known = tv_interval( $start_time_ref ); + + # convert to ms, and consider that we sent 900 packets each + my $time_unknown_ms = $total_time_unknown * 1000 / 900; + my $time_known_ms = $total_time_known * 1000 / 900; + + printf("Delay with unknown MAC: %.3f ms\n", $time_unknown_ms); + printf("Delay with known MAC: %.3f ms\n", $time_known_ms); + + return %delta; +} + +# how do we pass the cmd-line arguments to the script? +run_learning_switch_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/learning_switch/regress/test_hub_connected/run.pl b/openflow/regress/projects/learning_switch/regress/test_hub_connected/run.pl new file mode 100755 index 00000000..f5881672 --- /dev/null +++ b/openflow/regress/projects/learning_switch/regress/test_hub_connected/run.pl @@ -0,0 +1,64 @@ +#!/usr/bin/perl -w +# test_same_port? + +use strict; +use OF::Includes; + +sub my_test { + + my %delta; + + # Host A and B are both on p0. they send unicast with unknown dest. + + my $pkt_args = { + DA => "00:00:00:00:00:09", + SA => "00:00:00:00:00:01", + src_ip => "192.168.0.40", + dst_ip => "192.168.7.40", + ttl => 64, + len => 64 + }; + my $pkt = new NF2::IP_pkt(%$pkt_args); + + # send one packet; controller should learn MAC, add a flow + # entry, and send this packet out the other interfaces + print "Sending now: \n"; + send_and_count( 'eth1', $pkt->packed, \%delta ); + expect_and_count( 'eth2', $pkt->packed, \%delta ); + expect_and_count( 'eth3', $pkt->packed, \%delta ); + expect_and_count( 'eth4', $pkt->packed, \%delta ); + + # sleep as long as needed for the test to finish + sleep 0.1; + + my $pkt_args = { + DA => "00:00:00:00:00:08", + SA => "00:00:00:00:00:02", + src_ip => "192.168.1.40", + dst_ip => "192.168.6.40", + ttl => 64, + len => 64 + }; + my $pkt = new NF2::IP_pkt(%$pkt_args); + send_and_count( 'eth1', $pkt->packed, \%delta ); + expect_and_count( 'eth2', $pkt->packed, \%delta ); + expect_and_count( 'eth3', $pkt->packed, \%delta ); + expect_and_count( 'eth4', $pkt->packed, \%delta ); + sleep 0.1; + + # Now A and B try to talk to each other. see if switch drop the packet or not + + my $pkt_args = { + DA => "00:00:00:00:00:02", + SA => "00:00:00:00:00:01", + src_ip => "192.168.0.40", + dst_ip => "192.168.1.40", + ttl => 64, + len => 64 + }; + my $pkt = new NF2::IP_pkt(%$pkt_args); + send_and_count( 'eth1', $pkt->packed, \%delta ); + return %delta; +} + +run_learning_switch_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/learning_switch/regress/test_unicast_known/run.pl b/openflow/regress/projects/learning_switch/regress/test_unicast_known/run.pl new file mode 100755 index 00000000..34c2c09d --- /dev/null +++ b/openflow/regress/projects/learning_switch/regress/test_unicast_known/run.pl @@ -0,0 +1,71 @@ +#!/usr/bin/perl -w +# test_unicast_known + +use strict; +use OF::Includes; + +sub my_test { + + my $pkt_args = { + DA => "00:00:00:00:00:02", + SA => "00:00:00:00:00:01", + src_ip => "192.168.0.40", + dst_ip => "192.168.1.40", + ttl => 64, + len => 64 + }; + my $pkt = new NF2::IP_pkt(%$pkt_args); + + my %delta; + + # send one packet; controller should learn MAC, add a flow + # entry, and send this packet out the other interfaces + print "Sending now: \n"; + send_and_count( 'eth1', $pkt->packed, \%delta ); + expect_and_count( 'eth2', $pkt->packed, \%delta ); + expect_and_count( 'eth3', $pkt->packed, \%delta ); + expect_and_count( 'eth4', $pkt->packed, \%delta ); + sleep(.1); + + $pkt_args = { + DA => "00:00:00:00:00:01", + SA => "00:00:00:00:00:02", + src_ip => "192.168.1.40", + dst_ip => "192.168.0.40", + ttl => 64, + len => 64 + }; + $pkt = new NF2::IP_pkt(%$pkt_args); + send_and_count( 'eth2', $pkt->packed, \%delta ); + expect_and_count( 'eth1', $pkt->packed, \%delta ); + sleep(.1); + + $pkt_args = { + DA => "00:00:00:00:00:01", + SA => "00:00:00:00:00:03", + src_ip => "192.168.2.40", + dst_ip => "192.168.0.40", + ttl => 64, + len => 64 + }; + $pkt = new NF2::IP_pkt(%$pkt_args); + send_and_count( 'eth3', $pkt->packed, \%delta ); + expect_and_count( 'eth1', $pkt->packed, \%delta ); + sleep(.1); + + $pkt_args = { + DA => "00:00:00:00:00:01", + SA => "00:00:00:00:00:04", + src_ip => "192.168.3.40", + dst_ip => "192.168.0.40", + ttl => 64, + len => 64 + }; + $pkt = new NF2::IP_pkt(%$pkt_args); + send_and_count( 'eth4', $pkt->packed, \%delta ); + expect_and_count( 'eth1', $pkt->packed, \%delta ); + + return %delta; +} + +run_learning_switch_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/learning_switch/regress/test_unicast_move/run.pl b/openflow/regress/projects/learning_switch/regress/test_unicast_move/run.pl new file mode 100755 index 00000000..5bc4670d --- /dev/null +++ b/openflow/regress/projects/learning_switch/regress/test_unicast_move/run.pl @@ -0,0 +1,79 @@ +#!/usr/bin/perl -w +# test_unicast_move + +use strict; +use OF::Includes; + +sub my_test { + + my %delta; + + # host A's MAC address is 00:00:00:00:00:01 + + my $pkt_args = { + DA => "00:00:00:00:00:02", + SA => "00:00:00:00:00:01", + src_ip => "192.168.0.40", + dst_ip => "192.168.1.40", + ttl => 64, + len => 64 + }; + my $pkt = new NF2::IP_pkt(%$pkt_args); + + # send one packet; controller should learn MAC, add a flow + # entry, and send this packet out the other interfaces + print "Sending now: \n"; + send_and_count( 'eth1', $pkt->packed, \%delta ); + expect_and_count( 'eth2', $pkt->packed, \%delta ); + expect_and_count( 'eth3', $pkt->packed, \%delta ); + expect_and_count( 'eth4', $pkt->packed, \%delta ); + + # sleep as long as needed for the test to finish + sleep 0.1; + + $pkt_args = { + DA => "00:00:00:00:00:01", + SA => "00:00:00:00:00:02", + src_ip => "192.168.1.40", + dst_ip => "192.168.0.40", + ttl => 64, + len => 64 + }; + $pkt = new NF2::IP_pkt(%$pkt_args); + send_and_count( 'eth2', $pkt->packed, \%delta ); + expect_and_count( 'eth1', $pkt->packed, \%delta ); + sleep 0.1; + + #Now Host A Has Changed Location and Attached to p2 + #It will send a packet to p1 form its new location + $pkt_args = { + DA => "00:00:00:00:00:02", + SA => "00:00:00:00:00:01", + src_ip => "192.168.2.40", + dst_ip => "192.168.1.40", + ttl => 64, + len => 64 + }; + $pkt = new NF2::IP_pkt(%$pkt_args); + send_and_count( 'eth3', $pkt->packed, \%delta ); + expect_and_count( 'eth2', $pkt->packed, \%delta ); + sleep 0.1; + + # Now p1 sends something to Host A which is now attached to p2 + # we expect the switch to already updated its entry for Host A + $pkt_args = { + DA => "00:00:00:00:00:01", + SA => "00:00:00:00:00:02", + src_ip => "192.168.1.40", + dst_ip => "192.168.2.40", + ttl => 64, + len => 64 + }; + $pkt = new NF2::IP_pkt(%$pkt_args); + send_and_count( 'eth2', $pkt->packed, \%delta ); + expect_and_count( 'eth3', $pkt->packed, \%delta ); + + return %delta; +} + +run_learning_switch_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/learning_switch/regress/test_unicast_multiple_hosts/run.pl b/openflow/regress/projects/learning_switch/regress/test_unicast_multiple_hosts/run.pl new file mode 100755 index 00000000..73c0807b --- /dev/null +++ b/openflow/regress/projects/learning_switch/regress/test_unicast_multiple_hosts/run.pl @@ -0,0 +1,93 @@ +#!/usr/bin/perl -w +# test_unicast_multiple_hosts + +use strict; +use OF::Includes; + +sub my_test { + + my %delta; + + my $pkt_args = { + DA => "00:00:00:00:00:02", + SA => "00:00:00:00:00:01", + src_ip => "192.168.0.40", + dst_ip => "192.168.1.40", + ttl => 64, + len => 64 + }; + my $pkt = new NF2::IP_pkt(%$pkt_args); + + # send one packet; controller should learn MAC, add a flow + # entry, and send this packet out the other interfaces + print "Sending now: \n"; + send_and_count( 'eth1', $pkt->packed, \%delta ); + expect_and_count( 'eth2', $pkt->packed, \%delta ); + expect_and_count( 'eth3', $pkt->packed, \%delta ); + expect_and_count( 'eth4', $pkt->packed, \%delta ); + + # sleep as long as needed for the test to finish + sleep 0.5; + my $count = 10; + my $cnt = 10; + + for ( $cnt = 11 ; $cnt < 21 ; $cnt++ ) { + for ( $count = 10 ; $count < 12 ; $count++ ) { + + $pkt_args = { + DA => "00:00:00:00:00:01", + SA => "00:00:00:$cnt:10:$count", + src_ip => "192.168.$count.$cnt", + dst_ip => "192.168.0.40", + ttl => 64, + len => 64 + }; + $pkt = new NF2::IP_pkt(%$pkt_args); + send_and_count( 'eth2', $pkt->packed, \%delta ); + expect_and_count( 'eth1', $pkt->packed, \%delta ); + sleep 0.1; + + } + } + + for ( $cnt = 21 ; $cnt < 31 ; $cnt++ ) { + for ( $count = 10 ; $count < 12 ; $count++ ) { + + $pkt_args = { + DA => "00:00:00:00:00:01", + SA => "00:00:00:$cnt:11:$count", + src_ip => "192.168.$count.$cnt", + dst_ip => "192.168.0.40", + ttl => 64, + len => 64 + }; + $pkt = new NF2::IP_pkt(%$pkt_args); + send_and_count( 'eth3', $pkt->packed, \%delta ); + expect_and_count( 'eth1', $pkt->packed, \%delta ); + sleep 0.1; + } + } + + for ( $cnt = 31 ; $cnt < 41 ; $cnt++ ) { + for ( $count = 10 ; $count < 12 ; $count++ ) { + + $pkt_args = { + DA => "00:00:00:00:00:01", + SA => "00:00:00:$cnt:12:$count", + src_ip => "192.168.$count.$cnt", + dst_ip => "192.168.0.40", + ttl => 64, + len => 64 + }; + $pkt = new NF2::IP_pkt(%$pkt_args); + send_and_count( 'eth4', $pkt->packed, \%delta ); + expect_and_count( 'eth1', $pkt->packed, \%delta ); + sleep 0.1; + + } + } + + return %delta; +} + +run_learning_switch_test( \&my_test, \@ARGV ); \ No newline at end of file diff --git a/openflow/regress/projects/learning_switch/regress/test_unicast_self/run.pl b/openflow/regress/projects/learning_switch/regress/test_unicast_self/run.pl new file mode 100755 index 00000000..4db2371b --- /dev/null +++ b/openflow/regress/projects/learning_switch/regress/test_unicast_self/run.pl @@ -0,0 +1,61 @@ +#!/usr/bin/perl -w +# test_unicast_self + +use strict; +use OF::Includes; + +sub my_test { + + my %delta; + + # Send packets with same DA and SA; should be ignored + my $pkt_args = { + DA => "00:00:00:00:00:01", + SA => "00:00:00:00:00:01", + src_ip => "192.168.0.40", + dst_ip => "192.168.0.40", + ttl => 64, + len => 64 + }; + my $pkt = new NF2::IP_pkt(%$pkt_args); + + print "Sending now: \n"; + send_and_count( 'eth1', $pkt->packed, \%delta ); + + $pkt_args = { + DA => "00:00:00:00:00:02", + SA => "00:00:00:00:00:02", + src_ip => "192.168.1.40", + dst_ip => "192.168.1.40", + ttl => 64, + len => 64 + }; + $pkt = new NF2::IP_pkt(%$pkt_args); + send_and_count( 'eth2', $pkt->packed, \%delta ); + + $pkt_args = { + DA => "00:00:00:00:00:03", + SA => "00:00:00:00:00:03", + src_ip => "192.168.2.40", + dst_ip => "192.168.2.40", + ttl => 64, + len => 64 + }; + $pkt = new NF2::IP_pkt(%$pkt_args); + send_and_count( 'eth3', $pkt->packed, \%delta ); + + $pkt_args = { + DA => "00:00:00:00:00:04", + SA => "00:00:00:00:00:04", + src_ip => "192.168.3.40", + dst_ip => "192.168.3.40", + ttl => 64, + len => 64 + }; + $pkt = new NF2::IP_pkt(%$pkt_args); + send_and_count( 'eth4', $pkt->packed, \%delta ); + + return %delta; +} + +run_learning_switch_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/learning_switch/regress/test_unicast_unknown/run.pl b/openflow/regress/projects/learning_switch/regress/test_unicast_unknown/run.pl new file mode 100755 index 00000000..4378ae00 --- /dev/null +++ b/openflow/regress/projects/learning_switch/regress/test_unicast_unknown/run.pl @@ -0,0 +1,32 @@ +#!/usr/bin/perl -w +#test_unicast_unknown + +use strict; +use OF::Includes; + +sub my_test { + + my $pkt_args = { + DA => "00:00:00:00:00:02", + SA => "00:00:00:00:00:01", + src_ip => "192.168.0.40", + dst_ip => "192.168.1.40", + ttl => 64, + len => 64 + }; + my $pkt = new NF2::IP_pkt(%$pkt_args); + + my %delta; + + # send one packet; controller should learn MAC, add a flow + # entry, and send this packet out the other interfaces + print "Sending now: \n"; + send_and_count( 'eth1', $pkt->packed, \%delta ); + expect_and_count( 'eth2', $pkt->packed, \%delta ); + expect_and_count( 'eth3', $pkt->packed, \%delta ); + expect_and_count( 'eth4', $pkt->packed, \%delta ); + + return %delta; +} + +run_learning_switch_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/learning_switch/regress/tests.txt b/openflow/regress/projects/learning_switch/regress/tests.txt new file mode 100644 index 00000000..fdeb3c51 --- /dev/null +++ b/openflow/regress/projects/learning_switch/regress/tests.txt @@ -0,0 +1,12 @@ +test_unicast_unknown/run.pl +test_unicast_known/run.pl +test_broadcast/run.pl +##test_unicast_self/run.pl +test_unicast_move/run.pl +##test_hub_connected/run.pl +test_unicast_multiple_hosts/run.pl + +# BELOW NOT INCLUDED IN CURRRENT RELEASE +# WILL BE AVAILABLE SOON +##test_forward_latency/run.pl +##test_forward_bandwidth/run.pl diff --git a/openflow/regress/projects/regress.txt b/openflow/regress/projects/regress.txt new file mode 100644 index 00000000..9339cd32 --- /dev/null +++ b/openflow/regress/projects/regress.txt @@ -0,0 +1,3 @@ +black_box +controller_disconnect +learning_switch diff --git a/openflow/regress/scripts/copy_NF2_code.sh b/openflow/regress/scripts/copy_NF2_code.sh new file mode 100755 index 00000000..56ff83bf --- /dev/null +++ b/openflow/regress/scripts/copy_NF2_code.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +#last use of this script copied in files from NF2 SVN rev 3904 +#note: OFT_ROOT and NF2_ROOT must be set +cp $NF2_ROOT/lib/Perl5/Test/* $OFT_ROOT/lib/Perl5/Test/ diff --git a/openflow/regress/scripts/env_vars b/openflow/regress/scripts/env_vars new file mode 100644 index 00000000..a8f2433d --- /dev/null +++ b/openflow/regress/scripts/env_vars @@ -0,0 +1,12 @@ +export OF_ROOT=/home/yourname/openflow +export OFT_ROOT=${OF_ROOT}/regress +export PATH=${OFT_ROOT}/bin:/sbin:/usr/sbin:${PATH} +export PERL5LIB=${OFT_ROOT}/lib/Perl5:${PERL5LIB} +export OFT_MAP_ETH=${OFT_ROOT}/bin/of_generic_eth.map +export OFT_HP_MAP_ETH=${OFT_ROOT}/bin/of_hp_eth.map +export OFT_HP_SWITCH_IP=10.10.10.2 +export OFT_HP_VLAN=10 +export OFT_HP_CONTROLLER="tcp:10.10.10.3:6633" +export OFT_HP_LISTENER="tcp:10.10.10.2:6633" +export OFT_OVS_ROOT=/home/yourname/openvswitch +export OFT_OVS_MAP_ETH=${OFT_ROOT}/bin/of_ovs_eth.map diff --git a/openflow/regress/scripts/install_deps.pl b/openflow/regress/scripts/install_deps.pl new file mode 100755 index 00000000..4668a58b --- /dev/null +++ b/openflow/regress/scripts/install_deps.pl @@ -0,0 +1,264 @@ +#!/usr/bin/perl -W +# +# Script to automatically install dependencies for regression tests + +use strict; +use File::Basename; +use File::Path; +use Getopt::Std; +use Cwd; + +use constant { + UBUNTU => 'Ubuntu', + DEBIAN => 'Debian', + REDHAT => 'RedHat', + FEDORA => 'Fedora', + + UNKNOWN => 'unknown', + X86_64 => 'x86_64', +}; + +# Executables +my $lsb_release = 'lsb_release'; +my $apt_get = 'apt-get'; +my $yum = 'yum'; +my $uname = '/bin/uname'; + +my $distro; +my $machine; +my $sim; +my %install_funcs = ( + 'Ubuntu' => \&install_ubuntu_debian, + 'Debian' => \&install_ubuntu_debian, + 'Fedora' => \&install_fedora, +); +our($opt_s, $opt_d); + +# Verify that this script is being run as root +if ($> != 0) { + die "This script must be run as root"; +} + +# Parse the command line arguments +parse_args(); + + +# Identify the distribution and machine +if (!defined($distro)) { + identify_distro(); + die "Unable to identify the distribution" if (!defined($distro)); +} +identify_machine(); + +# Call the appropriate install function +if ($install_funcs{$distro}) { + $install_funcs{$distro}->(); +} +else { + die "Unable to find the install function for '$distro'"; +} + +exit 0; + +#========================================================== + +# +# identify_distro: +# Attempt to identify the Linux distro +# +sub identify_distro { + # First, look for lsb release which makes querying easier + $lsb_release = `which $lsb_release`; + chomp($lsb_release); + if ( $? >> 8 == 0) { + $distro = `$lsb_release -s -i`; + chomp($distro); + SWITCH: for ($distro) { + /Ubuntu/ && do { + $distro = UBUNTU; + last SWITCH; + }; + + /Debian/ && do { + $distro = DEBIAN; + last SWITCH; + }; + + (/CentOS/ || /RedHat/) && do { + $distro = REDHAT; + last SWITCH; + }; + + /Fedora/ && do { + $distro = FEDORA; + last SWITCH; + }; + + # DEFAULT + warn "Unknown Linux distro '$distro'"; + $distro = undef; + } + } + + # Otherwise, fall back to looking for release/version files in /etc + else { + if ( -f '/etc/debian_version' || -f '/etc/debian_release' ) { + $distro = DEBIAN; + } + elsif ( -f '/etc/fedora-release') { + $distro = FEDORA; + } + elsif ( -f '/etc/redhat-release' || -f '/etc/redhat_release' ) { + $distro = REDHAT; + } + } +} + +# +# identify_machine: +# Attempt to identify the machine type +# +sub identify_machine { + # First, look for lsb release which makes querying easier + if ( -x $uname) { + $machine = `$uname -m`; + chomp($machine); + } + + # we don't know what sort of machine this is + else { + $machine = UNKNOWN; + } +} + +# +# install_ubuntu_debian: +# Install the necessary dependencies for Ubuntu and Debian +# +sub install_ubuntu_debian { + my @pkgs = ( + 'liberror-perl', + 'libio-interface-perl', + 'liblist-moreutils-perl', + 'libpcap0.8-dev', + 'iproute', + 'psmisc', + 'libnet-pcap-perl', + 'libnet-rawip-perl', + 'wget', + ); + if ($machine eq X86_64) { + push (@pkgs, 'libc6-dev-i386', 'ia32-libs'); + } + + my @modules = ( + 'http://search.cpan.org/CPAN/authors/id/F/FT/FTASSIN/Data-HexDump-0.02.tar.gz', + 'http://www.cpan.org/authors/id/J/JV/JV/Getopt-Long-2.38.tar.gz', + ); + + if ($distro eq UBUNTU) { + push (@pkgs, 'libconvert-binary-c-perl') + } + else { + push (@modules, + 'http://search.cpan.org/CPAN/authors/id/M/MH/MHX/Convert-Binary-C-0.74.tar.gz') + } + + # Run apt-get + my @flags = ('-y'); + push(@flags, '-s') if defined($sim); + system($apt_get, @flags, 'install', @pkgs); + if ($? >> 8 != 0) { + die "Error running $apt_get"; + } + + # Install modules directly from CPAN + install_perl_modules(@modules); +} + +# +# install_fedora: +# Install the necessary dependencies for Fedora Core +# +sub install_fedora { + my @pkgs = ( + 'perl-Convert-Binary-C', + 'perl-Data-HexDump', + 'perl-Net-Pcap', + 'perl-Error.noarch', + 'perl-Module-Build', + 'libpcap-devel', + 'perl-List-MoreUtils', + 'perl-Net-RawIP', + ); + + # Run yum + my @flags = ('-y'); + if (defined($sim)) { + push(@flags, 'info'); + } + else { + push(@flags, 'install'); + } + system($yum, @flags, @pkgs); + if ($? >> 8 != 0) { + die "Error running $yum"; + } +} + +# +# install_perl_modules: +# Fetch and install PERL modules +# +sub install_perl_modules { + my @modules = @_; + + my $dir = "perl_modules"; + + mkdir $dir; + chdir $dir; + + foreach my $path (@modules) { + `wget $path`; + my $module = fileparse($path); + `tar xzf $module`; + $module =~ s/.tar.gz//; + print "compiling $module\n"; + chdir $module; + if (!defined($sim)) { + system 'perl Makefile.PL'; + system 'make'; + system 'make install'; + } + chdir '../'; + } + + chdir '..'; + rmtree $dir; +} + +# +# parse_args +# Parse the command line arguments +# +sub parse_args { + getopts('sd:'); + $sim = 1 if defined($opt_s); + $distro = $opt_d if defined($opt_d); +} + +sub HELP_MESSAGE { + print < 0) { $release_num = $ARGV[0]; } + +check_OF_vars_set(); + +my $rootdir = $ENV{'OFT_ROOT'}; +print "starting at root dir $rootdir\n"; +chdir $rootdir; + +my @ignore_list = ( + './temp', + './scripts/copy_NF2_code.sh', + './scripts/make_release.pl', + './projects/learning_switch/regress/test_forward_bandwidth/run.pl', + './projects/learning_switch/regress/test_forward_bandwidth/run.pl', + './projects/black_box/regress/test_send_bandwidth_fixed/run.pl', + './projects/black_box/regress/test_send_bandwidth_random/run.pl', + './projects/black_box/regress/test_add_flow_bandwidth/run.pl', + './projects/black_box/regress/test_add_flow_latency/run.pl', + './projects/black_box/regress/test_receive_bandwidth_fixed/run.pl', + './projects/black_box/regress/test_receive_bandwidth_random/run.pl', + './projects/black_box/regress/test_forward_bandwidth_fixed/run.pl', + './projects/black_box/regress/test_forward_bandwidth_random/run.pl', + './projects/black_box/regress/test_forward_latency/run.pl', + './projects/black_box/regress/test_switch_bandwidth_random/run.pl', + './projects/black_box/regress/test_switch_bandwidth_random/run.pl' +); + +my @files = parse_dir ('.'); + +print "\n"; + +foreach my $file (@files) { + print $file . "\n"; +} + +# set x permission for non-.pl files +# originally used perl chmod, but it doesn't work +my @write_perm_list = ( + "./temp/$of_ver/projects/learning_switch/regress/common/setup", + "./temp/$of_ver/projects/learning_switch/regress/common/teardown", + "./temp/$of_ver/projects/black_box/regress/common/setup", + "./temp/$of_ver/projects/black_box/regress/common/teardown" +); +foreach my $file (@write_perm_list) { + `chmod 755 $file`; +} + +#print $write_perm_list[0] . "\n"; + +`cd $rootdir/temp; tar czf $of_ver.tar.gz *`; +exit (0); + +# DFS +sub parse_dir { + my ($path) = @_; + #print "parse_dir called with $path\n"; + my @file_list; + # exists? + if (! -e "$path") { + die "checked $path and failed\n"; + } + # file? + elsif (-f "$path") { + if (file_ok($path)) { + print "added $path to list\n"; + push @file_list, "$path"; + + copy($path, "temp/$of_ver/$path") || die "failed to copy $path\n"; + + #for perl files, make them executable + my $match = $path =~ m/.pl/; + print " match = $match\n"; + if ($match) { + # ensure file is executable + print " setting chmod for $path\n"; + chmod 755, "temp/$of_ver/$path" || die "failed to set chmod $path\n"; + }; + } + else { + #print "ignore file $path\n"; + } + } + # directory? + elsif (-d $path) { + #print "parsing directory $path\n"; + opendir(DIR, $path) || print "Can't open... maybe try chmod 777"; + my @files_in_dir=readdir(DIR); + closedir(DIR); + + if (dir_ok('', $path) && $path ne '.') { + #remove ./ at beginning + + my $path_temp = substr($path, 2); + mkdir("temp/$of_ver/$path_temp") || die "failed to make path temp/$of_ver/$path_temp\n"; + } + + #print " dir looks like: \n"; + foreach my $file (@files_in_dir) { + #print " " . $file . "\n"; + } + + foreach my $subdir (@files_in_dir) { + if (dir_ok($subdir, $path) ) { + #print "\nabout to parse $path/$subdir\n"; + push @file_list, parse_dir("$path/$subdir"); + } + } + } + else { + die ("unknown error"); + } + + return @file_list; +} + +sub dir_ok { + my ($subdir, $path) = @_; + my $ignore = 0; + foreach my $file (@ignore_list) { + if ("$path/$subdir" eq $file) { $ignore = 1; last; } + } + + # ignore these three regardless of path - other require path to ignore + if ($subdir ne '.' && $subdir ne '..' && $subdir ne '.svn' && !$ignore ) { + return 1; + } + else { + return 0; + } +} + +sub file_ok { + my ($path) = @_; + my $ok = 1; + foreach my $file (@ignore_list) { + if ("$path" eq $file) { $ok = 0; last; } + } + return $ok; +} diff --git a/openflow/secchan/.dirstamp b/openflow/secchan/.dirstamp new file mode 100644 index 00000000..e69de29b diff --git a/openflow/secchan/.gitignore b/openflow/secchan/.gitignore new file mode 100644 index 00000000..d6d189d3 --- /dev/null +++ b/openflow/secchan/.gitignore @@ -0,0 +1,7 @@ +/Makefile +/Makefile.in +/controller-lite +/ctlpath-lite +/dpctl-lite +/ofprotocol +/ofprotocol.8 diff --git a/openflow/secchan/automake.mk b/openflow/secchan/automake.mk new file mode 100644 index 00000000..6a9f2041 --- /dev/null +++ b/openflow/secchan/automake.mk @@ -0,0 +1,32 @@ +bin_PROGRAMS += secchan/ofprotocol +man_MANS += secchan/ofprotocol.8 + +secchan_ofprotocol_SOURCES = \ + secchan/discovery.c \ + secchan/discovery.h \ + secchan/emerg-flow.c \ + secchan/emerg-flow.h \ + secchan/fail-open.c \ + secchan/fail-open.h \ + secchan/failover.c \ + secchan/failover.h \ + secchan/in-band.c \ + secchan/in-band.h \ + secchan/port-watcher.c \ + secchan/port-watcher.h \ + secchan/protocol-stat.c \ + secchan/protocol-stat.h \ + secchan/ratelimit.c \ + secchan/ratelimit.h \ + secchan/secchan.c \ + secchan/secchan.h \ + secchan/status.c \ + secchan/status.h \ + secchan/stp-secchan.c \ + secchan/stp-secchan.h +secchan_ofprotocol_LDADD = lib/libopenflow.a $(FAULT_LIBS) $(SSL_LIBS) + +EXTRA_DIST += secchan/ofprotocol.8.in +DISTCLEANFILES += secchan/ofprotocol.8 + +include secchan/commands/automake.mk diff --git a/openflow/secchan/commands/automake.mk b/openflow/secchan/commands/automake.mk new file mode 100644 index 00000000..cbe44d8c --- /dev/null +++ b/openflow/secchan/commands/automake.mk @@ -0,0 +1,3 @@ +commandsdir = ${pkgdatadir}/commands +dist_commands_SCRIPTS = \ + secchan/commands/reboot diff --git a/openflow/secchan/commands/reboot b/openflow/secchan/commands/reboot new file mode 100755 index 00000000..4d5145cd --- /dev/null +++ b/openflow/secchan/commands/reboot @@ -0,0 +1,3 @@ +#! /bin/sh +ofp-kill --force --signal=USR1 ofp-switchui.pid +reboot diff --git a/openflow/secchan/discovery.c b/openflow/secchan/discovery.c new file mode 100644 index 00000000..feb9c338 --- /dev/null +++ b/openflow/secchan/discovery.c @@ -0,0 +1,251 @@ +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include "discovery.h" +#include +#include +#include +#include "dhcp-client.h" +#include "dhcp.h" +#include "netdev.h" +#include "openflow/openflow.h" +#include "packets.h" +#include "port-watcher.h" +#include "secchan.h" +#include "status.h" + +#define THIS_MODULE VLM_discovery +#include "vlog.h" + +struct discovery +{ + const struct settings *s; + struct dhclient *dhcp; + int n_changes; +}; + +static void modify_dhcp_request(struct dhcp_msg *, void *aux); +static bool validate_dhcp_offer(const struct dhcp_msg *, void *aux); + +static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60); + +static void +discovery_status_cb(struct status_reply *sr, void *d_) +{ + struct discovery *d = d_; + + status_reply_put(sr, "accept-remote=%s", d->s->accept_controller_re); + status_reply_put(sr, "n-changes=%d", d->n_changes); + if (d->dhcp) { + status_reply_put(sr, "state=%s", dhclient_get_state(d->dhcp)); + status_reply_put(sr, "state-elapsed=%u", + dhclient_get_state_elapsed(d->dhcp)); + if (dhclient_is_bound(d->dhcp)) { + uint32_t ip = dhclient_get_ip(d->dhcp); + uint32_t netmask = dhclient_get_netmask(d->dhcp); + uint32_t router = dhclient_get_router(d->dhcp); + + const struct dhcp_msg *cfg = dhclient_get_config(d->dhcp); + uint32_t dns_server; + char *domain_name; + int i; + + status_reply_put(sr, "ip="IP_FMT, IP_ARGS(&ip)); + status_reply_put(sr, "netmask="IP_FMT, IP_ARGS(&netmask)); + if (router) { + status_reply_put(sr, "router="IP_FMT, IP_ARGS(&router)); + } + + for (i = 0; dhcp_msg_get_ip(cfg, DHCP_CODE_DNS_SERVER, i, + &dns_server); + i++) { + status_reply_put(sr, "dns%d="IP_FMT, i, IP_ARGS(&dns_server)); + } + + domain_name = dhcp_msg_get_string(cfg, DHCP_CODE_DOMAIN_NAME); + if (domain_name) { + status_reply_put(sr, "domain=%s", domain_name); + free(domain_name); + } + + status_reply_put(sr, "lease-remaining=%u", + dhclient_get_lease_remaining(d->dhcp)); + } + } +} + +static void +discovery_local_port_cb(const struct ofp_phy_port *port, void *d_) +{ + struct discovery *d = d_; + if (port) { + char name[OFP_MAX_PORT_NAME_LEN + 1]; + struct netdev *netdev; + int retval; + + /* Check that this was really a change. */ + get_port_name(port, name, sizeof name); + if (d->dhcp && !strcmp(netdev_get_name(dhclient_get_netdev(d->dhcp)), + name)) { + return; + } + + /* Destroy current DHCP client. */ + dhclient_destroy(d->dhcp); + d->dhcp = NULL; + + /* Bring local network device up. */ + retval = netdev_open(name, NETDEV_ETH_TYPE_NONE, &netdev); + if (retval) { + VLOG_ERR("Could not open %s device, discovery disabled: %s", + name, strerror(retval)); + return; + } + retval = netdev_turn_flags_on(netdev, NETDEV_UP, true); + if (retval) { + VLOG_ERR("Could not bring %s device up, discovery disabled: %s", + name, strerror(retval)); + return; + } + netdev_close(netdev); + + /* Initialize DHCP client. */ + retval = dhclient_create(name, modify_dhcp_request, + validate_dhcp_offer, (void *) d->s, &d->dhcp); + if (retval) { + VLOG_ERR("Failed to initialize DHCP client, " + "discovery disabled: %s", strerror(retval)); + return; + } + dhclient_set_max_timeout(d->dhcp, 3); + dhclient_init(d->dhcp, 0); + } else { + dhclient_destroy(d->dhcp); + d->dhcp = NULL; + } +} + + +struct discovery * +discovery_init(const struct settings *s, struct port_watcher *pw, + struct switch_status *ss) +{ + struct discovery *d; + + d = xmalloc(sizeof *d); + d->s = s; + d->dhcp = NULL; + d->n_changes = 0; + + switch_status_register_category(ss, "discovery", discovery_status_cb, d); + port_watcher_register_local_port_callback(pw, discovery_local_port_cb, d); + + return d; +} + +void +discovery_question_connectivity(struct discovery *d) +{ + if (d->dhcp) { + dhclient_force_renew(d->dhcp, 15); + } +} + +bool +discovery_run(struct discovery *d, char **controller_name) +{ + if (!d->dhcp) { + *controller_name = NULL; + return true; + } + + dhclient_run(d->dhcp); + if (!dhclient_changed(d->dhcp)) { + return false; + } + + dhclient_configure_netdev(d->dhcp); + if (d->s->update_resolv_conf) { + dhclient_update_resolv_conf(d->dhcp); + } + + if (dhclient_is_bound(d->dhcp)) { + *controller_name = dhcp_msg_get_string(dhclient_get_config(d->dhcp), + DHCP_CODE_OFP_CONTROLLER_VCONN); + VLOG_INFO("%s: discovered controller", *controller_name); + d->n_changes++; + } else { + *controller_name = NULL; + if (d->n_changes) { + VLOG_INFO("discovered controller no longer available"); + d->n_changes++; + } + } + return true; +} + +void +discovery_wait(struct discovery *d) +{ + if (d->dhcp) { + dhclient_wait(d->dhcp); + } +} + +static void +modify_dhcp_request(struct dhcp_msg *msg, void *aux UNUSED) +{ + dhcp_msg_put_string(msg, DHCP_CODE_VENDOR_CLASS, "OpenFlow"); +} + +static bool +validate_dhcp_offer(const struct dhcp_msg *msg, void *s_) +{ + const struct settings *s = s_; + char *vconn_name; + bool accept; + + vconn_name = dhcp_msg_get_string(msg, DHCP_CODE_OFP_CONTROLLER_VCONN); + if (!vconn_name) { + VLOG_WARN_RL(&rl, "rejecting DHCP offer missing controller vconn"); + return false; + } + accept = !regexec(&s->accept_controller_regex, vconn_name, 0, NULL, 0); + if (!accept) { + VLOG_WARN_RL(&rl, "rejecting controller vconn that fails to match %s", + s->accept_controller_re); + } + free(vconn_name); + return accept; +} diff --git a/openflow/secchan/discovery.h b/openflow/secchan/discovery.h new file mode 100644 index 00000000..b2cb03c9 --- /dev/null +++ b/openflow/secchan/discovery.h @@ -0,0 +1,50 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#ifndef DISCOVERY_H +#define DISCOVERY_H 1 + +#include + +struct settings; +struct port_watcher; +struct switch_status; + +struct discovery *discovery_init(const struct settings *, + struct port_watcher *, + struct switch_status *); +void discovery_question_connectivity(struct discovery *); +bool discovery_run(struct discovery *, char **controller_name); +void discovery_wait(struct discovery *); + +#endif /* discovery.h */ diff --git a/openflow/secchan/emerg-flow.c b/openflow/secchan/emerg-flow.c new file mode 100644 index 00000000..9af58819 --- /dev/null +++ b/openflow/secchan/emerg-flow.c @@ -0,0 +1,144 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "openflow/openflow.h" +#include "openflow/private-ext.h" + +#include "util.h" +#include "vconn.h" +#include "rconn.h" +#include "secchan.h" +#include "status.h" +#include "timeval.h" +#include "sat-math.h" +#include "ofpbuf.h" +#include "emerg-flow.h" +#define THIS_MODULE VLM_emerg_flow +#include "vlog.h" + +struct emerg_flow_context { + const struct settings *settings; + const struct secchan *secchan; + struct rconn *local_rconn; + struct rconn *remote_rconn; + int prev_state; + int state; +}; + +static void emerg_flow_status_cb(struct status_reply *, void *); +static void emerg_flow_periodic_cb(void *); + +static void +emerg_flow_status_cb(struct status_reply *status_reply, void *context_) +{ + struct emerg_flow_context *context = context_; + + status_reply_put(status_reply, "state=%s", + context->state == PRIVATEOPT_EMERG_FLOW_RESTORATION + ? "restoration" + : context->state == PRIVATEOPT_EMERG_FLOW_PROTECTION + ? "protection" : "unknown"); +} + +static void +emerg_flow_periodic_cb(void *context_) +{ + struct emerg_flow_context *context = context_; + struct ofpbuf *buf = NULL; + struct private_vxhdr *vxhdr = NULL; + struct private_vxopt *vxopt = NULL; + int error = 0; + + if (rconn_is_connected(context->remote_rconn)) { + if (context->state == PRIVATEOPT_EMERG_FLOW_PROTECTION) { + context->prev_state = context->state; + context->state = PRIVATEOPT_EMERG_FLOW_RESTORATION; + } else { + return; + } + } else { + if (context->state == PRIVATEOPT_EMERG_FLOW_RESTORATION) { + context->prev_state = context->state; + context->state = PRIVATEOPT_EMERG_FLOW_PROTECTION; + } else { + return; + } + } + + vxhdr = (struct private_vxhdr *)make_openflow + (sizeof(*vxhdr) + sizeof(*vxopt), OFPT_VENDOR, &buf); + vxopt = (struct private_vxopt *)(vxhdr + 1); + vxhdr->ofp_vxid = htonl(PRIVATE_VENDOR_ID); + vxopt->pvo_type = htons(context->state); + vxopt->pvo_len = htons(0); + + error = rconn_send(context->local_rconn, buf, NULL); + if (error && error != EAGAIN) { + VLOG_WARN("send failed (%s)", strerror(error)); + } +} + +void +emerg_flow_start(struct secchan *secchan, const struct settings *settings, + struct switch_status *switch_status, + struct rconn *local_rconn, struct rconn *remote_rconn) +{ + struct emerg_flow_context *context = NULL; + static struct hook_class emerg_flow_hook_class = { + NULL, /* local_packet_cb */ + NULL, /* remote_packet_cb */ + emerg_flow_periodic_cb, /* periodic_cb */ + NULL, /* wait_cb */ + NULL, /* closing_cb */ + }; + + context = xmalloc(sizeof(*context)); + context->settings = settings; + context->secchan = secchan; + context->local_rconn = local_rconn; + context->remote_rconn = remote_rconn; + context->prev_state = PRIVATEOPT_EMERG_FLOW_PROTECTION; + context->state = PRIVATEOPT_EMERG_FLOW_PROTECTION; + + switch_status_register_category(switch_status, "emerg-flow", + emerg_flow_status_cb, context); + add_hook(secchan, &emerg_flow_hook_class, context); +} diff --git a/openflow/secchan/emerg-flow.h b/openflow/secchan/emerg-flow.h new file mode 100644 index 00000000..d61a7fe2 --- /dev/null +++ b/openflow/secchan/emerg-flow.h @@ -0,0 +1,44 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#ifndef EMERG_FLOW_H_ +#define EMERG_FLOW_H_ 1 + +struct rconn; +struct secchan; +struct settings; +struct switch_status; + +void emerg_flow_start(struct secchan *, const struct settings *, + struct switch_status *, struct rconn *, struct rconn *); + +#endif diff --git a/openflow/secchan/fail-open.c b/openflow/secchan/fail-open.c new file mode 100644 index 00000000..eb28bc38 --- /dev/null +++ b/openflow/secchan/fail-open.c @@ -0,0 +1,159 @@ +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include "fail-open.h" +#include +#include +#include +#include "learning-switch.h" +#include "netdev.h" +#include "packets.h" +#include "port-watcher.h" +#include "rconn.h" +#include "secchan.h" +#include "status.h" +#include "stp-secchan.h" +#include "timeval.h" + +#define THIS_MODULE VLM_fail_open +#include "vlog.h" + +struct fail_open_data { + const struct settings *s; + struct rconn *local_rconn; + struct rconn *remote_rconn; + struct lswitch *lswitch; + int last_disconn_secs; + time_t boot_deadline; +}; + +/* Causes 'r' to enter or leave fail-open mode, if appropriate. */ +static void +fail_open_periodic_cb(void *fail_open_) +{ + struct fail_open_data *fail_open = fail_open_; + int disconn_secs; + bool open; + + if (time_now() < fail_open->boot_deadline) { + return; + } + disconn_secs = rconn_failure_duration(fail_open->remote_rconn); + open = disconn_secs >= fail_open->s->probe_interval * 3; + if (open != (fail_open->lswitch != NULL)) { + if (!open) { + VLOG_WARN("No longer in fail-open mode"); + lswitch_destroy(fail_open->lswitch); + fail_open->lswitch = NULL; + } else { + VLOG_WARN("Could not connect to controller for %d seconds, " + "failing open", disconn_secs); + fail_open->lswitch = lswitch_create(fail_open->local_rconn, true, + fail_open->s->max_idle); + fail_open->last_disconn_secs = disconn_secs; + } + } else if (open && disconn_secs > fail_open->last_disconn_secs + 60) { + VLOG_INFO("Still in fail-open mode after %d seconds disconnected " + "from controller", disconn_secs); + fail_open->last_disconn_secs = disconn_secs; + } + if (fail_open->lswitch) { + lswitch_run(fail_open->lswitch, fail_open->local_rconn); + } +} + +static void +fail_open_wait_cb(void *fail_open_) +{ + struct fail_open_data *fail_open = fail_open_; + if (fail_open->lswitch) { + lswitch_wait(fail_open->lswitch); + } +} + +static bool +fail_open_local_packet_cb(struct relay *r, void *fail_open_) +{ + struct fail_open_data *fail_open = fail_open_; + if (rconn_is_connected(fail_open->remote_rconn) || !fail_open->lswitch) { + return false; + } else { + lswitch_process_packet(fail_open->lswitch, fail_open->local_rconn, + r->halves[HALF_LOCAL].rxbuf); + rconn_run(fail_open->local_rconn); + return true; + } +} + +static void +fail_open_status_cb(struct status_reply *sr, void *fail_open_) +{ + struct fail_open_data *fail_open = fail_open_; + const struct settings *s = fail_open->s; + int trigger_duration = s->probe_interval * 3; + int cur_duration = rconn_failure_duration(fail_open->remote_rconn); + + status_reply_put(sr, "trigger-duration=%d", trigger_duration); + status_reply_put(sr, "current-duration=%d", cur_duration); + status_reply_put(sr, "triggered=%s", + cur_duration >= trigger_duration ? "true" : "false"); + status_reply_put(sr, "max-idle=%d", s->max_idle); +} + +static struct hook_class fail_open_hook_class = { + fail_open_local_packet_cb, /* local_packet_cb */ + NULL, /* remote_packet_cb */ + fail_open_periodic_cb, /* periodic_cb */ + fail_open_wait_cb, /* wait_cb */ + NULL, /* closing_cb */ +}; + +void +fail_open_start(struct secchan *secchan, const struct settings *s, + struct switch_status *ss, + struct rconn *local_rconn, struct rconn *remote_rconn) +{ + struct fail_open_data *fail_open = xmalloc(sizeof *fail_open); + fail_open->s = s; + fail_open->local_rconn = local_rconn; + fail_open->remote_rconn = remote_rconn; + fail_open->lswitch = NULL; + fail_open->boot_deadline = time_now() + s->probe_interval * 3; + if (s->enable_stp) { + fail_open->boot_deadline += STP_EXTRA_BOOT_TIME; + } + switch_status_register_category(ss, "fail-open", + fail_open_status_cb, fail_open); + add_hook(secchan, &fail_open_hook_class, fail_open); +} diff --git a/openflow/secchan/fail-open.h b/openflow/secchan/fail-open.h new file mode 100644 index 00000000..69a3b310 --- /dev/null +++ b/openflow/secchan/fail-open.h @@ -0,0 +1,46 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#ifndef FAIL_OPEN_H +#define FAIL_OPEN_H 1 + +struct rconn; +struct secchan; +struct settings; +struct switch_status; + +void fail_open_start(struct secchan *, const struct settings *, + struct switch_status *, + struct rconn *local, struct rconn *remote); + +#endif /* fail-open.h */ diff --git a/openflow/secchan/failover.c b/openflow/secchan/failover.c new file mode 100644 index 00000000..718d7379 --- /dev/null +++ b/openflow/secchan/failover.c @@ -0,0 +1,144 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#include +#include +#include +#include + +#include "util.h" +#include "rconn.h" +#include "secchan.h" +#include "status.h" +#include "timeval.h" +#include "sat-math.h" +#include "failover.h" +#define THIS_MODULE VLM_failover +#include "vlog.h" + +struct failover_peer { + time_t epoch; +}; + +struct failover_context { + const struct settings *settings; + const struct secchan *secchan; + struct rconn *remote_rconn; + int index; + struct failover_peer *peers[MAX_CONTROLLERS]; +}; + +static void failover_status_cb(struct status_reply *, void *); +static bool is_timed_out(const struct failover_peer *, int); +static void failover_periodic_cb(void *); + +static void +failover_status_cb(struct status_reply *status_reply, void *context_) +{ + struct failover_context *context = context_; + int i; + + status_reply_put(status_reply, "num-controllers=%d", + context->settings->num_controllers); + + for (i = 0; i < MAX_CONTROLLERS; ++i) { + if (context->settings->controller_names[i] == NULL) + continue; + status_reply_put(status_reply, "controller#%d=%s", + i, context->settings->controller_names[i]); + } +} + +static bool +is_timed_out(const struct failover_peer *peer, int max_backoff) +{ + unsigned int sat_value = sat_add(peer->epoch, max_backoff); + return time_now() >= sat_value; +} + +static void +failover_periodic_cb(void *context_) +{ + struct failover_context *context = context_; + char *curr_peer = NULL; + char *prev_peer = NULL; + + if (rconn_is_connected(context->remote_rconn)) + return; + + if (!is_timed_out(context->peers[context->index], + context->settings->max_backoff)) { + return; + } + + rconn_disconnect(context->remote_rconn); + prev_peer = (char *)context->settings->controller_names[context->index]; + context->index = (context->index + 1) + % context->settings->num_controllers; + curr_peer = (char *)context->settings->controller_names[context->index]; + rconn_connect(context->remote_rconn, + context->settings->controller_names[context->index]); + context->peers[context->index]->epoch = time_now(); + VLOG_INFO("Switching over to %s, from %s", curr_peer, prev_peer); +} + +void +failover_start(struct secchan *secchan, const struct settings *settings, + struct switch_status *switch_status, struct rconn *remote_rconn) +{ + struct failover_context *context = NULL; + int i; + static struct hook_class failover_hook_class = { + NULL, /* local_packet_cb */ + NULL, /* remote_packet_cb */ + failover_periodic_cb, /* periodic_cb */ + NULL, /* wait_cb */ + NULL, /* closing_cb */ + }; + + context = xmalloc(sizeof(*context)); + context->settings = settings; + context->secchan = secchan; + context->remote_rconn = remote_rconn; + context->index = 0; + for (i = 0; i < MAX_CONTROLLERS; ++i) { + context->peers[i] = NULL; + if (settings->controller_names[i] == NULL) + continue; + context->peers[i] = xmalloc(sizeof(struct failover_peer)); + context->peers[i]->epoch = time_now(); + } + + switch_status_register_category(switch_status, "failover", + failover_status_cb, context); + add_hook(secchan, &failover_hook_class, context); +} diff --git a/openflow/secchan/failover.h b/openflow/secchan/failover.h new file mode 100644 index 00000000..d511b35f --- /dev/null +++ b/openflow/secchan/failover.h @@ -0,0 +1,44 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#ifndef FAILOVER_H_ +#define FAILOVER_H_ 1 + +struct rconn; +struct secchan; +struct settings; +struct switch_status; + +void failover_start(struct secchan *, const struct settings *, + struct switch_status *, struct rconn *); + +#endif diff --git a/openflow/secchan/in-band.c b/openflow/secchan/in-band.c new file mode 100644 index 00000000..46109daf --- /dev/null +++ b/openflow/secchan/in-band.c @@ -0,0 +1,331 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include "in-band.h" +#include +#include +#include +#include +#include "flow.h" +#include "mac-learning.h" +#include "netdev.h" +#include "ofpbuf.h" +#include "openflow/openflow.h" +#include "packets.h" +#include "port-watcher.h" +#include "rconn.h" +#include "secchan.h" +#include "status.h" +#include "timeval.h" +#include "vconn.h" + +#define THIS_MODULE VLM_in_band +#include "vlog.h" + +struct in_band_data { + const struct settings *s; + struct mac_learning *ml; + struct netdev *of_device; + struct rconn *controller; + int n_queued; +}; + +static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60); + +static void +queue_tx(struct rconn *rc, struct in_band_data *in_band, struct ofpbuf *b) +{ + rconn_send_with_limit(rc, b, &in_band->n_queued, 10); +} + +static const uint8_t * +get_controller_mac(struct in_band_data *in_band) +{ + static uint32_t ip, last_nonzero_ip; + static uint8_t mac[ETH_ADDR_LEN], last_nonzero_mac[ETH_ADDR_LEN]; + static time_t next_refresh = 0; + + uint32_t last_ip = ip; + + time_t now = time_now(); + + ip = rconn_get_ip(in_band->controller); + if (last_ip != ip || !next_refresh || now >= next_refresh) { + bool have_mac; + + /* Look up MAC address. */ + memset(mac, 0, sizeof mac); + if (ip && in_band->of_device) { + int retval = netdev_arp_lookup(in_band->of_device, ip, mac); + if (retval) { + VLOG_DBG_RL(&rl, "cannot look up controller hw address " + "("IP_FMT"): %s", IP_ARGS(&ip), strerror(retval)); + } + } + have_mac = !eth_addr_is_zero(mac); + + /* Log changes in IP, MAC addresses. */ + if (ip && ip != last_nonzero_ip) { + VLOG_DBG("controller IP address changed from "IP_FMT + " to "IP_FMT, IP_ARGS(&last_nonzero_ip), IP_ARGS(&ip)); + last_nonzero_ip = ip; + } + if (have_mac && memcmp(last_nonzero_mac, mac, ETH_ADDR_LEN)) { + VLOG_DBG("controller MAC address changed from "ETH_ADDR_FMT" to " + ETH_ADDR_FMT, + ETH_ADDR_ARGS(last_nonzero_mac), ETH_ADDR_ARGS(mac)); + memcpy(last_nonzero_mac, mac, ETH_ADDR_LEN); + } + + /* Schedule next refresh. + * + * If we have an IP address but not a MAC address, then refresh + * quickly, since we probably will get a MAC address soon (via ARP). + * Otherwise, we can afford to wait a little while. */ + next_refresh = now + (!ip || have_mac ? 10 : 1); + } + return !eth_addr_is_zero(mac) ? mac : NULL; +} + +static bool +is_controller_mac(const uint8_t dl_addr[ETH_ADDR_LEN], + struct in_band_data *in_band) +{ + const uint8_t *mac = get_controller_mac(in_band); + return mac && eth_addr_equals(mac, dl_addr); +} + +static void +in_band_learn_mac(struct in_band_data *in_band, + uint16_t in_port, const uint8_t src_mac[ETH_ADDR_LEN]) +{ + if (mac_learning_learn(in_band->ml, src_mac, 0, in_port)) { + VLOG_DBG_RL(&rl, "learned that "ETH_ADDR_FMT" is on port %"PRIu16, + ETH_ADDR_ARGS(src_mac), in_port); + } +} + +static bool +in_band_local_packet_cb(struct relay *r, void *in_band_) +{ + struct in_band_data *in_band = in_band_; + struct rconn *rc = r->halves[HALF_LOCAL].rconn; + struct ofp_packet_in *opi; + struct eth_header *eth; + struct ofpbuf payload; + struct flow flow; + uint16_t in_port; + int out_port; + + if (!get_ofp_packet_eth_header(r, &opi, ð) || !in_band->of_device) { + return false; + } + in_port = ntohs(opi->in_port); + get_ofp_packet_payload(opi, &payload); + flow_extract(&payload, in_port, &flow); + + /* Deal with local stuff. */ + if (in_port == OFPP_LOCAL) { + /* Sent by secure channel. */ + out_port = mac_learning_lookup(in_band->ml, eth->eth_dst, 0); + } else if (eth_addr_equals(eth->eth_dst, + netdev_get_etheraddr(in_band->of_device))) { + /* Sent to secure channel. */ + out_port = OFPP_LOCAL; + in_band_learn_mac(in_band, in_port, eth->eth_src); + } else if (eth->eth_type == htons(ETH_TYPE_ARP) + && eth_addr_is_broadcast(eth->eth_dst) + && is_controller_mac(eth->eth_src, in_band)) { + /* ARP sent by controller. */ + out_port = OFPP_FLOOD; + } else if ((is_controller_mac(eth->eth_dst, in_band) + || is_controller_mac(eth->eth_src, in_band)) + && flow.dl_type == htons(ETH_TYPE_IP) + && flow.nw_proto == IP_TYPE_TCP + && (flow.tp_src == htons(OFP_TCP_PORT) + || flow.tp_src == htons(OFP_SSL_PORT) + || flow.tp_dst == htons(OFP_TCP_PORT) + || flow.tp_dst == htons(OFP_SSL_PORT))) { + /* Traffic to or from controller. Switch it by hand. */ + in_band_learn_mac(in_band, in_port, eth->eth_src); + out_port = mac_learning_lookup(in_band->ml, eth->eth_dst, 0); + } else { + const uint8_t *controller_mac; + controller_mac = get_controller_mac(in_band); + if (eth->eth_type == htons(ETH_TYPE_ARP) + && eth_addr_is_broadcast(eth->eth_dst) + && is_controller_mac(eth->eth_src, in_band)) { + /* ARP sent by controller. */ + out_port = OFPP_FLOOD; + } else if (is_controller_mac(eth->eth_dst, in_band) + && in_port == mac_learning_lookup(in_band->ml, + controller_mac, 0)) { + /* Drop controller traffic that arrives on the controller port. */ + out_port = -1; + } else { + return false; + } + } + + if (in_port == out_port) { + /* The input and output port match. Set up a flow to drop packets. */ + queue_tx(rc, in_band, make_add_flow(&flow, ntohl(opi->buffer_id), + in_band->s->max_idle, 0)); + } else if (out_port != OFPP_FLOOD) { + /* The output port is known, so add a new flow. */ + queue_tx(rc, in_band, + make_add_simple_flow(&flow, ntohl(opi->buffer_id), + out_port, in_band->s->max_idle)); + + /* If the switch didn't buffer the packet, we need to send a copy. */ + if (ntohl(opi->buffer_id) == UINT32_MAX) { + queue_tx(rc, in_band, + make_unbuffered_packet_out(&payload, in_port, out_port)); + } + } else { + /* We don't know that MAC. Send along the packet without setting up a + * flow. */ + struct ofpbuf *b; + if (ntohl(opi->buffer_id) == UINT32_MAX) { + b = make_unbuffered_packet_out(&payload, in_port, out_port); + } else { + b = make_buffered_packet_out(ntohl(opi->buffer_id), + in_port, out_port); + } + queue_tx(rc, in_band, b); + } + return true; +} + +static void +in_band_status_cb(struct status_reply *sr, void *in_band_) +{ + struct in_band_data *in_band = in_band_; + struct in_addr local_ip; + uint32_t controller_ip; + const uint8_t *controller_mac; + + if (in_band->of_device) { + const uint8_t *mac = netdev_get_etheraddr(in_band->of_device); + if (netdev_get_in4(in_band->of_device, &local_ip)) { + status_reply_put(sr, "local-ip="IP_FMT, IP_ARGS(&local_ip.s_addr)); + } + status_reply_put(sr, "local-mac="ETH_ADDR_FMT, ETH_ADDR_ARGS(mac)); + + controller_ip = rconn_get_ip(in_band->controller); + if (controller_ip) { + status_reply_put(sr, "controller-ip="IP_FMT, + IP_ARGS(&controller_ip)); + } + controller_mac = get_controller_mac(in_band); + if (controller_mac) { + status_reply_put(sr, "controller-mac="ETH_ADDR_FMT, + ETH_ADDR_ARGS(controller_mac)); + } + } +} + +void +get_ofp_packet_payload(struct ofp_packet_in *opi, struct ofpbuf *payload) +{ + payload->data = opi->data; + payload->size = ntohs(opi->header.length) - offsetof(struct ofp_packet_in, + data); +} + +static void +in_band_local_port_cb(const struct ofp_phy_port *port, void *in_band_) +{ + struct in_band_data *in_band = in_band_; + if (port) { + char name[sizeof port->name + 1]; + get_port_name(port, name, sizeof name); + + if (!in_band->of_device + || strcmp(netdev_get_name(in_band->of_device), name)) + { + int error; + netdev_close(in_band->of_device); + error = netdev_open(name, NETDEV_ETH_TYPE_NONE, + &in_band->of_device); + if (error) { + VLOG_ERR("failed to open in-band control network device " + "\"%s\": %s", name, strerror(errno)); + } + } + } else { + netdev_close(in_band->of_device); + in_band->of_device = NULL; + } +} + +static void +in_band_periodic_cb(void *in_band_) +{ + struct in_band_data *in_band = in_band_; + mac_learning_run(in_band->ml, NULL); +} + +static void +in_band_wait_cb(void *in_band_) +{ + struct in_band_data *in_band = in_band_; + mac_learning_wait(in_band->ml); +} + +static struct hook_class in_band_hook_class = { + in_band_local_packet_cb, /* local_packet_cb */ + NULL, /* remote_packet_cb */ + in_band_periodic_cb, /* periodic_cb */ + in_band_wait_cb, /* wait_cb */ + NULL, /* closing_cb */ +}; + +void +in_band_start(struct secchan *secchan, + const struct settings *s, struct switch_status *ss, + struct port_watcher *pw, struct rconn *remote) +{ + struct in_band_data *in_band; + + in_band = xcalloc(1, sizeof *in_band); + in_band->s = s; + in_band->ml = mac_learning_create(); + in_band->of_device = NULL; + in_band->controller = remote; + switch_status_register_category(ss, "in-band", in_band_status_cb, in_band); + port_watcher_register_local_port_callback(pw, in_band_local_port_cb, + in_band); + add_hook(secchan, &in_band_hook_class, in_band); +} diff --git a/openflow/secchan/in-band.h b/openflow/secchan/in-band.h new file mode 100644 index 00000000..b4d21ab9 --- /dev/null +++ b/openflow/secchan/in-band.h @@ -0,0 +1,47 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#ifndef IN_BAND_H +#define IN_BAND_H 1 + +struct port_watcher; +struct rconn; +struct secchan; +struct settings; +struct switch_status; + +void in_band_start(struct secchan *, const struct settings *, + struct switch_status *, struct port_watcher *, + struct rconn *remote); + +#endif /* in-band.h */ diff --git a/openflow/secchan/ofprotocol.8.in b/openflow/secchan/ofprotocol.8.in new file mode 100644 index 00000000..4aae44a3 --- /dev/null +++ b/openflow/secchan/ofprotocol.8.in @@ -0,0 +1,462 @@ +.ds PN ofprotocol +.TH ofprotocol 8 "October 2008" "OpenFlow" "OpenFlow Manual" + +.SH NAME +ofprotocol \- secure channel connecting an OpenFlow datapath to a controller + +.SH SYNOPSIS +.B ofprotocol +[\fIoptions\fR] \fIdatapath\fR controller[,\fIcontroller\fR...] + +.SH DESCRIPTION +The \fBofprotocol\fR program sets up a secure channel between a local +OpenFlow datapath and a remote controller. \fBofprotocol\fR connects to +the local datapath over Netlink and to the controller over TCP or SSL, +and then forwards OpenFlow messages from one endpoint to the other. + +The mandatory \fIdatapath\fR argument argument specifies the local datapath +to relay. It takes one of the following forms: + +.TP +\fBnl:\fIdp_idx\fR +Attach to the local kernel-based datapath over the Netlink protocol. +The \fIdp_idx\fR argument is the number of a datapath created with +\fBdpctl\fR(8). + +.TP +\fBunix:\fIfile\fR +Attach to the userspace datapath implemented by \fBofdatapath\fR(8). +The \fIfile\fR argument must the same one specified on the +\fBofdatapath\fR command line. + +.PP +The optional \fIcontroller\fR argument specifies how to connect to +an OpenFlow controller. Up to four controllers may be specified, +using the following forms: + +.TP +\fBssl:\fIhost\fR[\fB:\fIport\fR] +The specified SSL \fIport\fR (default: 6633) on the given remote +\fIhost\fR. The \fB--private-key\fR, \fB--certificate\fR, and +\fB--ca-cert\fR options are mandatory when this form is used. + +.TP +\fBtcp:\fIhost\fR[\fB:\fIport\fR] +The specified TCP \fIport\fR (default: 6633) on the given remote +\fIhost\fR. + +.TP +\fBunix:\fIfile\fR +The Unix domain server socket named \fIfile\fR. + +.PP +If multiple controllers are specified, \fBofprotocol\fR will attempt to +connect to a new controller when a controller connection fails, times +out, or is closed, or when a controller stops responding to echo requests. + +If \fIcontroller\fR is omitted, \fBofprotocol\fR attempts to discover the +location of the controller automatically (see below). + +.SH "CONTACTING THE CONTROLLER" +The OpenFlow switch must be able to contact the OpenFlow controller +over the network. It can do so in one of two ways: + +.IP out-of-band +In this configuration, OpenFlow traffic uses a network separate from +the data traffic that it controls, that is, the switch does not use +any of the network devices added to the datapath with \fBdpctl +addif\fR in its communication with the controller. + +To use \fBofprotocol\fR in a network with out-of-band control, specify +\fB--out-of-band\fR on the \fBofprotocol\fR command line. The control +network must be configured separately, before or after \fBofprotocol\fR +is started. + +.IP in-band +In this configuration, a single network is used for OpenFlow traffic +and other data traffic, that is, the switch contacts the controller +over one of the network devices added to the datapath with \fBdpctl +addif\fR. This configuration is often more convenient than +out-of-band control, because it is not necessary to maintain two +independent networks. + +In-band control is the default for \fBofprotocol\fR, so no special +command-line option is required. + +With in-band control, the location of the controller can be configured +manually or discovered automatically: + +.RS +.IP "controller discovery" +To make \fBofprotocol\fR discover the location of the controller +automatically, do not specify the location of the controller on the +\fBofprotocol\fR command line. + +In this mode, \fBofprotocol\fR will broadcast a DHCP request with vendor +class identifier \fBOpenFlow\fR across the network devices added to +the datapath with \fBdpctl addif\fR. It will accept any valid DHCP +reply that has the same vendor class identifier and includes a +vendor-specific option with code 1 whose contents are a string +specifying the location of the controller in the same format used on +the \fBofprotocol\fR command line (e.g. \fBssl:192.168.0.1\fR). + +The DHCP reply may also, optionally, include a vendor-specific option +with code 2 whose contents are a string specifying the URI to the base +of the OpenFlow PKI (e.g. \fBhttp://192.168.0.1/openflow/pki\fR). +This URI is used only for bootstrapping the OpenFlow PKI at initial +switch setup; \fBofprotocol\fR does not use it at all. + +The following ISC DHCP server configuration file assigns the IP +address range 192.168.0.20 through 192.168.0.30 to OpenFlow switches +that follow the switch protocol and addresses 192.168.0.1 through +192.168.0.10 to all other DHCP clients: + +default-lease-time 600; +.br +max-lease-time 7200; +.br +option space openflow; +.br +option openflow.controller-vconn code 1 = text; +.br +option openflow.pki-uri code 2 = text; +.br +class "OpenFlow" { +.br + match if option vendor-class-identifier = "OpenFlow"; +.br + vendor-option-space openflow; +.br + option openflow.controller-vconn "tcp:192.168.0.10"; +.br + option openflow.pki-uri "http://192.168.0.10/openflow/pki"; +.br + option vendor-class-identifier "OpenFlow"; +.br +} +.br +subnet 192.168.0.0 netmask 255.255.255.0 { +.br + pool { +.br + allow members of "OpenFlow"; +.br + range 192.168.0.20 192.168.0.30; +.br + } +.br + pool { +.br + deny members of "OpenFlow"; +.br + range 192.168.0.1 192.168.0.10; +.br + } +.br +} +.br + +.IP "manual configuration" +To configure in-band control manually, specify the location of the +controller on the \fBofprotocol\fR command line as the \fIcontroller\fR +argument. You must also configure the network device for the OpenFlow +``local port'' to allow \fBofprotocol\fR to connect to that controller. +The OpenFlow local port is a virtual network port that \fBofprotocol\fR +bridges to the physical switch ports. Its network device name depends +on the \fIdatapath\fR specified on the \fBofprotocol\fR command line: + +.RS +.TP +\fBnl:\fIdp_idx\fR +The local port network device for \fBnl:\fIdp_idx\fR is always named +\fBof\fIdp_idx\fR, i.e. the device for \fBnl:0\fR is \fBof0\fR. + +.TP +\fBunix:\fIfile\fR +The local port network device name may be specified on the +\fBofdatapath\fR command line, using the \fB--local-port\fR option. It +is often \fBtap0\fR. +.RE + +.IP +Before \fBofprotocol\fR starts, the local port network device is not +bridged to any physical network, so the next step depends on whether +connectivity is required to configure the device's IP address. If the +switch has a static IP address, you may configure its IP address now +with a command such as: +.RS +.IP +ifconfig of0 192.168.1.1 +.RE +.IP +and then invoke \fBofprotocol\fR. + +On the other hand, if the switch does not have a static IP address, +e.g. it obtains its IP address dynamically via DHCP, the DHCP client +will not be able to contact the DHCP server until the secure channel +has started up. Thus, start \fBofprotocol\fR without configuring +the local port network device, and start the DHCP client afterward. +.RE + +.SH OPTIONS +.SS "Controller Discovery Options" +.TP +\fB--accept-vconn=\fIregex\fR +When \fBofprotocol\fR performs controller discovery (see \fBCONTACTING +THE CONTROLLER\fR, above, for more information about controller +discovery), it validates the controller location obtained via DHCP +with a POSIX extended regular expression. Only controllers whose +names match the regular expression will be accepted. + +The default regular expression is \fBssl:.*\fR (meaning that only SSL +controller connections will be accepted) when any of the SSL +configuration options \fB--private-key\fR, \fB--certificate\fR, or +\fB--ca-cert\fR is specified. The default is \fB.*\fR otherwise +(meaning that any controller will be accepted). + +The \fIregex\fR is implicitly anchored at the beginning of the +controller location string, as if it begins with \fB^\fR. + +When controller discovery is not performed, this option has no effect. + +.TP +\fB--no-resolv-conf\fR +When \fBofprotocol\fR performs controller discovery (see \fBCONTACTING +THE CONTROLLER\fR, above, for more information about controller +discovery), by default it overwrites the system's +\fB/etc/resolv.conf\fR with domain information and DNS servers +obtained via DHCP. If the location of the controller is specified +using a hostname, rather than an IP address, and the network's DNS +servers ever change, this behavior is essential. But because it also +interferes with any administrator or process that manages +\fB/etc/resolv.conf\fR, when this option is specified, \fBofprotocol\fR +will not modify \fB/etc/resolv.conf\fR. + +\fBofprotocol\fR will only modify \fBresolv.conf\fR if the DHCP response +that it receives specifies one or more DNS servers. + +When controller discovery is not performed, this option has no effect. + +.SS "Networking Options" +.TP +\fB-F\fR, \fB--fail=\fR[\fBopen\fR|\fBclosed\fR] +The controller is, ordinarily, responsible for setting up all flows on +the OpenFlow switch. Thus, if the connection to the controller fails, +no new network connections can be set up. If the connection to the +controller stays down long enough, no packets can pass through the +switch at all. + +If this option is set to \fBopen\fR (the default), \fBofprotocol\fR will +take over responsibility for setting up flows in the local datapath +when no message has been received from the controller for three times +the inactivity probe interval (see below), or 45 seconds by default. +In this ``fail open'' mode, \fBofprotocol\fR causes the datapath to act +like an ordinary MAC-learning switch. \fBofprotocol\fR will continue to +retry connection to the controller in the background and, when the +connection succeeds, it discontinues its fail-open behavior. The +secure channel enters the fail-open mode when + +If this option is set to \fBclosed\fR, then \fBofprotocol\fR will not +set up flows on its own when the controller connection fails. + +.TP +\fB--inactivity-probe=\fIsecs\fR +When the secure channel is connected to the controller, the secure +channel waits for a message to be received from the controller for +\fIsecs\fR seconds before it sends a inactivity probe to the +controller. After sending the inactivity probe, if no response is +received for an additional \fIsecs\fR seconds, the secure channel +assumes that the connection has been broken and attempts to reconnect. +The default is 15 seconds, and the minimum value is 1 seconds. + +When fail-open mode is configured, changing the inactivity probe +interval also changes the interval before entering fail-open mode (see +above). + +.TP +\fB--max-idle=\fIsecs\fR|\fBpermanent\fR +Sets \fIsecs\fR as the number of seconds that a flow set up by the +secure channel will remain in the switch's flow table without any +matching packets being seen. If \fBpermanent\fR is specified, which +is not recommended, flows set up by the secure channel will never +expire. The default is 15 seconds. + +Most flows are set up by the OpenFlow controller, not by the secure +channel. This option affects only the following flows, which the +secure channel sets up itself: + +.RS +.IP \(bu +When \fB--fail=open\fR is specified, flows set up when the secure +channel has not been able to contact the controller for the configured +fail-open delay. + +.IP \(bu +When in-band control is in use, flows set up to bootstrap contacting +the controller (see \fBCONTACTING THE CONTROLLER\fR, above, for +more information about in-band control). +.RE + +.IP +As a result, when both \fB--fail=closed\fR and \fB--out-of-band\fR are +specified, this option has no effect. + +.TP +\fB--max-backoff=\fIsecs\fR +Sets the maximum time between attempts to connect to the controller to +\fIsecs\fR, which must be at least 1. The actual interval between +connection attempts starts at 1 second and doubles on each failing +attempt until it reaches the maximum. The default maximum backoff +time is 15 seconds. + +.TP +\fB-l\fR, \fB--listen=\fImethod\fR +Configures the switch to additionally listen for incoming OpenFlow +connections for switch management with \fBdpctl\fR. The \fImethod\fR +must be given as one of the passive OpenFlow connection methods listed +below. This option may be specified multiple times to listen to +multiple connection methods. + +.RS +.TP +\fBpssl:\fR[\fIport\fR] +Listens for SSL connections on \fIport\fR (default: 6633). The +\fB--private-key\fR, \fB--certificate\fR, and \fB--ca-cert\fR options +are mandatory when this form is used. + +.TP +\fBptcp:\fR[\fIport\fR] +Listens for TCP connections on \fIport\fR (default: 6633). + +.TP +\fBpunix:\fIfile\fR +Listens for connections on Unix domain server socket named \fIfile\fR. +.RE + +.TP +\fB-m\fR, \fB--monitor=\fImethod\fR +Configures the switch to additionally listen for incoming OpenFlow +connections for switch monitoring with \fBdpctl\fR's \fBmonitor\fR +command. The \fImethod\fR must be given as one of the passive +OpenFlow connection methods listed above as acceptable for +\fB--listen\fR. + +When \fBdpctl monitor\fR makes a monitoring connection, \fBofprotocol\fR +sends it a copy of every OpenFlow message sent to or received from the +kernel in the normal course of its operations. It does not send a +copy of any messages sent to or from the OpenFlow connection to the +controller. Most of these messages will be seen anyhow, however, +because \fBofprotocol\fR mainly acts as a relay between the controller +and the kernel. \fBofprotocol\fR also does not send a copy of any +messages sent to or from the OpenFlow connection to the controller. +Such messages will typically \fBnot\fR be seen, because \fBofprotocol\fR +maintains a separate connection to the kernel for each management +connection. + +Messages are copied to the monitoring connections on a best-effort +basis. In particular, if the socket buffer of the monitoring +connection fills up, some messages will be lost. + +.TP +\fB--in-band\fR, \fB--out-of-band\fR +Configures \fBofprotocol\fR to operate in in-band or out-of-band control +mode (see \fBCONTACTING THE CONTROLLER\fR above). When neither option +is given, the default is in-band control. + +.TP +\fB--stp\fR, \fB--no-stp\fR +Enable or disable implementation of IEEE 802.1D Spanning Tree Protocol +at the switch. The default is \fB--no-stp\fR in this distribution, +because bugs in the STP implementation are still being worked out. +The default will change to \fB--stp\fR at some point in the future. + +.TP +\fB--emerg-flow\fR +Enable emergecny flow protection and restration at the switch. If emergency +flow enabled, \fBofprotocol\fR will attempt to switch flow table to emergency's +one when a controller connection fails. The default is disabled in this +distribution. + +.SS "Rate-Limiting Options" + +These options configure how the switch applies a ``token bucket'' to +limit the rate at which packets in unknown flows are forwarded to an +OpenFlow controller for flow-setup processing. This feature prevents +a single OpenFlow switch from overwhelming a controller. + +.TP +\fB--rate-limit\fR[\fB=\fIrate\fR] +. +Limits the maximum rate at which packets will be forwarded to the +OpenFlow controller to \fIrate\fR packets per second. If \fIrate\fR +is not specified then the default of 1,000 packets per second is used. + +If \fB--rate-limit\fR is not used, then the switch does not limit the +rate at which packets are forwarded to the controller. + +.TP +\fB--burst-limit=\fIburst\fR +. +Sets the maximum number of unused packet credits that the switch will +allow to accumulate during time in which no packets are being +forwarded to the OpenFlow controller to \fIburst\fR (measured in +packets). The default \fIburst\fR is one-quarter of the \fIrate\fR +specified on \fB--rate-limit\fR. + +This option takes effect only when \fB--rate-limit\fR is also specified. + +.SS "Daemon Options" +.so lib/daemon.man + +.SS "Public Key Infrastructure Options" + +.TP +\fB-p\fR, \fB--private-key=\fIprivkey.pem\fR +Specifies a PEM file containing the private key used as the switch's +identity for SSL connections to the controller. + +.TP +\fB-c\fR, \fB--certificate=\fIcert.pem\fR +Specifies a PEM file containing a certificate, signed by the +controller's certificate authority (CA), that certifies the switch's +private key to identify a trustworthy switch. + +.TP +\fB-C\fR, \fB--ca-cert=\fIcacert.pem\fR +Specifies a PEM file containing the CA certificate used to verify that +the switch is connected to a trustworthy controller. + +.TP +\fB--bootstrap-ca-cert=\fIcacert.pem\fR +When \fIcacert.pem\fR exists, this option has the same effect as +\fB-C\fR or \fB--ca-cert\fR. If it does not exist, then \fBofprotocol\fR +will attempt to obtain the CA certificate from the controller on its +first SSL connection and save it to the named PEM file. If it is +successful, it will immediately drop the connection and reconnect, and +from then on all SSL connections must be authenticated by a +certificate signed by the CA certificate thus obtained. + +\fBThis option exposes the SSL connection to a man-in-the-middle +attack obtaining the initial CA certificate\fR, but it may be useful +for bootstrapping. + +This option is only useful if the controller sends its CA certificate +as part of the SSL certificate chain. The SSL protocol does not +require the controller to send the CA certificate, but +\fBcontroller\fR(8) can be configured to do so with the +\fB--peer-ca-cert\fR option. + +.SS "Logging Options" +.so lib/vlog.man +.SS "Other Options" +.so lib/common.man +.so lib/leak-checker.man + +.SH "SEE ALSO" + +.BR dpctl (8), +.BR ofp-discover (8), +.BR controller (8), +.BR ofp-pki (8), +.BR ofdatapath (8), +.BR vlogconf (8) diff --git a/openflow/secchan/port-watcher.c b/openflow/secchan/port-watcher.c new file mode 100644 index 00000000..0998e161 --- /dev/null +++ b/openflow/secchan/port-watcher.c @@ -0,0 +1,620 @@ +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include "port-watcher.h" +#include +#include +#include +#include +#include "dynamic-string.h" +#include "netdev.h" +#include "ofpbuf.h" +#include "openflow/openflow.h" +#include "poll-loop.h" +#include "port-array.h" +#include "rconn.h" +#include "shash.h" +#include "svec.h" +#include "timeval.h" +#include "vconn.h" +#include "xtoxll.h" + +#define THIS_MODULE VLM_port_watcher +#include "vlog.h" + +struct port_watcher_cb { + port_changed_cb_func *port_changed; + void *aux; +}; + +struct port_watcher_local_cb { + local_port_changed_cb_func *local_port_changed; + void *aux; +}; + +struct port_watcher { + struct rconn *local_rconn; + struct rconn *remote_rconn; + struct port_array ports; + time_t last_feature_request; + bool got_feature_reply; + uint64_t datapath_id; + int n_txq; + struct port_watcher_cb cbs[2]; + int n_cbs; + struct port_watcher_local_cb local_cbs[4]; + int n_local_cbs; + char local_port_name[OFP_MAX_PORT_NAME_LEN + 1]; + struct netdev_monitor *mon; + struct shash port_by_name; +}; + +/* Returns the number of fields that differ from 'a' to 'b'. */ +static int +opp_differs(const struct ofp_phy_port *a, const struct ofp_phy_port *b) +{ + BUILD_ASSERT_DECL(sizeof *a == 48); /* Trips when we add or remove fields. */ + return ((a->port_no != b->port_no) + + (memcmp(a->hw_addr, b->hw_addr, sizeof a->hw_addr) != 0) + + (memcmp(a->name, b->name, sizeof a->name) != 0) + + (a->config != b->config) + + (a->state != b->state) + + (a->curr != b->curr) + + (a->advertised != b->advertised) + + (a->supported != b->supported) + + (a->peer != b->peer)); +} + +static void +sanitize_opp(struct ofp_phy_port *opp) +{ + size_t i; + + for (i = 0; i < sizeof opp->name; i++) { + char c = opp->name[i]; + if (c && (c < 0x20 || c > 0x7e)) { + opp->name[i] = '.'; + } + } + opp->name[sizeof opp->name - 1] = '\0'; +} + +static void +call_port_changed_callbacks(struct port_watcher *pw, int port_no, + const struct ofp_phy_port *old, + const struct ofp_phy_port *new) +{ + int i; + for (i = 0; i < pw->n_cbs; i++) { + port_changed_cb_func *port_changed = pw->cbs[i].port_changed; + (port_changed)(port_no, old, new, pw->cbs[i].aux); + } +} + +void +get_port_name(const struct ofp_phy_port *port, char *name, size_t name_size) +{ + char *p; + + memcpy(name, port->name, MIN(name_size, sizeof port->name)); + name[name_size - 1] = '\0'; + for (p = name; *p != '\0'; p++) { + if (*p < 32 || *p > 126) { + *p = '.'; + } + } +} + +static struct ofp_phy_port * +lookup_port(const struct port_watcher *pw, uint16_t port_no) +{ + return port_array_get(&pw->ports, port_no); +} + +static void +call_local_port_changed_callbacks(struct port_watcher *pw) +{ + char name[OFP_MAX_PORT_NAME_LEN + 1]; + const struct ofp_phy_port *port; + int i; + + /* Pass the local port to the callbacks, if it exists. + Pass a null pointer if there is no local port. */ + port = lookup_port(pw, OFPP_LOCAL); + + /* Log the name of the local port. */ + if (port) { + get_port_name(port, name, sizeof name); + } else { + name[0] = '\0'; + } + if (strcmp(pw->local_port_name, name)) { + if (name[0]) { + VLOG_INFO("Identified data path local port as \"%s\".", name); + } else { + VLOG_WARN("Data path has no local port."); + } + strcpy(pw->local_port_name, name); + } + + /* Invoke callbacks. */ + for (i = 0; i < pw->n_local_cbs; i++) { + local_port_changed_cb_func *cb = pw->local_cbs[i].local_port_changed; + (cb)(port, pw->local_cbs[i].aux); + } +} + +static void +update_phy_port(struct port_watcher *pw, struct ofp_phy_port *opp, + uint8_t reason) +{ + struct ofp_phy_port *old; + uint16_t port_no; + + port_no = ntohs(opp->port_no); + old = lookup_port(pw, port_no); + + if (reason == OFPPR_DELETE && old) { + call_port_changed_callbacks(pw, port_no, old, NULL); + free(old); + port_array_set(&pw->ports, port_no, NULL); + } else if (reason == OFPPR_MODIFY || reason == OFPPR_ADD) { + if (old) { + uint32_t s_mask = htonl(OFPPS_STP_MASK); + opp->state = (opp->state & ~s_mask) | (old->state & s_mask); + } + if (!old || opp_differs(opp, old)) { + struct ofp_phy_port new = *opp; + sanitize_opp(&new); + call_port_changed_callbacks(pw, port_no, old, &new); + if (old) { + *old = new; + } else { + port_array_set(&pw->ports, port_no, xmemdup(&new, sizeof new)); + } + } + } +} + +static void +update_netdev_monitor_devices(struct port_watcher *pw) +{ + struct ofp_phy_port *p; + struct svec netdevs; + unsigned int port_no; + + svec_init(&netdevs); + shash_clear(&pw->port_by_name); + for (p = port_array_first(&pw->ports, &port_no); p; + p = port_array_next(&pw->ports, &port_no)) { + const char *name = (const char *) p->name; + svec_add(&netdevs, name); + shash_add(&pw->port_by_name, name, p); + } + netdev_monitor_set_devices(pw->mon, netdevs.names, netdevs.n); + svec_destroy(&netdevs); +} + +static bool +port_watcher_local_packet_cb(struct relay *r, void *pw_) +{ + struct port_watcher *pw = pw_; + struct ofpbuf *msg = r->halves[HALF_LOCAL].rxbuf; + struct ofp_header *oh = msg->data; + + if (oh->type == OFPT_FEATURES_REPLY + && msg->size >= offsetof(struct ofp_switch_features, ports)) { + struct ofp_switch_features *osf = msg->data; + bool seen[PORT_ARRAY_SIZE]; + struct ofp_phy_port *p; + unsigned int port_no; + size_t n_ports; + size_t i; + + pw->got_feature_reply = true; + if (pw->datapath_id != osf->datapath_id) { + pw->datapath_id = osf->datapath_id; + VLOG_INFO("Datapath id is %012"PRIx64, ntohll(pw->datapath_id)); + } + + /* Update each port included in the message. */ + memset(seen, false, sizeof seen); + n_ports = ((msg->size - offsetof(struct ofp_switch_features, ports)) + / sizeof *osf->ports); + for (i = 0; i < n_ports; i++) { + struct ofp_phy_port *opp = &osf->ports[i]; + update_phy_port(pw, opp, OFPPR_MODIFY); + seen[ntohs(opp->port_no)] = true; + } + + /* Delete all the ports not included in the message. */ + for (p = port_array_first(&pw->ports, &port_no); p; + p = port_array_next(&pw->ports, &port_no)) { + if (!seen[port_no]) { + update_phy_port(pw, p, OFPPR_DELETE); + } + } + + update_netdev_monitor_devices(pw); + + call_local_port_changed_callbacks(pw); + } else if (oh->type == OFPT_PORT_STATUS + && msg->size >= sizeof(struct ofp_port_status)) { + struct ofp_port_status *ops = msg->data; + update_phy_port(pw, &ops->desc, ops->reason); + if (ops->desc.port_no == htons(OFPP_LOCAL)) { + call_local_port_changed_callbacks(pw); + } + if (ops->reason == OFPPR_ADD || OFPPR_DELETE) { + update_netdev_monitor_devices(pw); + } + } + return false; +} + +static void +bring_netdev_up_or_down(const char *name, bool down) +{ + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + struct netdev *netdev; + int retval; + + retval = netdev_open(name, NETDEV_ETH_TYPE_NONE, &netdev); + if (!retval) { + if (down) { + retval = netdev_turn_flags_off(netdev, NETDEV_UP, true); + } else { + retval = netdev_turn_flags_on(netdev, NETDEV_UP, true); + } + if (retval) { + VLOG_WARN_RL(&rl, "failed to bring network device %s %s: %s", + name, down ? "down" : "up", strerror(retval)); + } + netdev_close(netdev); + } else { + VLOG_WARN_RL(&rl, "failed to open network device %s: %s", + name, strerror(retval)); + } +} + +static bool +port_watcher_remote_packet_cb(struct relay *r, void *pw_) +{ + struct port_watcher *pw = pw_; + struct ofpbuf *msg = r->halves[HALF_REMOTE].rxbuf; + struct ofp_header *oh = msg->data; + + if (oh->type == OFPT_PORT_MOD + && msg->size >= sizeof(struct ofp_port_mod)) { + struct ofp_port_mod *opm = msg->data; + uint16_t port_no = ntohs(opm->port_no); + struct ofp_phy_port *pw_opp = lookup_port(pw, port_no); + if (pw_opp->port_no != htons(OFPP_NONE)) { + struct ofp_phy_port old = *pw_opp; + pw_opp->config = ((pw_opp->config & ~opm->mask) + | (opm->config & opm->mask)); + call_port_changed_callbacks(pw, port_no, &old, pw_opp); + if (pw_opp->port_no == htons(OFPP_LOCAL)) { + call_local_port_changed_callbacks(pw); + } + + if (opm->mask & htonl(OFPPC_PORT_DOWN)) { + bring_netdev_up_or_down((const char *) pw_opp->name, + opm->config & htonl(OFPPC_PORT_DOWN)); + } + } + } + return false; +} + +/* Sets 'bit' in '*word' to 0 or 1 according to 'value'. */ +static void +set_bit(uint32_t bit, bool value, uint32_t *word) +{ + if (value) { + *word |= bit; + } else { + *word &= ~bit; + } +} + +static void +port_watcher_periodic_cb(void *pw_) +{ + struct port_watcher *pw = pw_; + const char *name; + + if (!pw->got_feature_reply + && time_now() >= pw->last_feature_request + 5 + && rconn_is_connected(pw->local_rconn)) { + struct ofpbuf *b; + make_openflow(sizeof(struct ofp_header), OFPT_FEATURES_REQUEST, &b); + rconn_send_with_limit(pw->local_rconn, b, &pw->n_txq, 1); + pw->last_feature_request = time_now(); + } + + netdev_monitor_run(pw->mon); + while ((name = netdev_monitor_poll(pw->mon)) != NULL) { + struct ofp_phy_port *opp; + struct ofp_phy_port new_opp; + enum netdev_flags flags; + int retval; + + opp = shash_find_data(&pw->port_by_name, name); + if (!opp) { + continue; + } + + retval = netdev_nodev_get_flags(name, &flags); + if (retval) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_WARN_RL(&rl, "could not get flags for %s", name); + continue; + } + + new_opp = *opp; + set_bit(htonl(OFPPC_PORT_DOWN), ~flags & NETDEV_UP, &new_opp.config); + set_bit(htonl(OFPPS_LINK_DOWN), ~flags & NETDEV_CARRIER, + &new_opp.state); + if (opp->config != new_opp.config || opp->state != new_opp.state) { + struct ofp_port_status *ops; + struct ofpbuf *b; + + /* Notify other secchan modules. */ + update_phy_port(pw, &new_opp, OFPPR_MODIFY); + if (new_opp.port_no == htons(OFPP_LOCAL)) { + call_local_port_changed_callbacks(pw); + } + + /* Notify the controller that the flags changed. */ + ops = make_openflow(sizeof *ops, OFPT_PORT_STATUS, &b); + ops->reason = OFPPR_MODIFY; + ops->desc = new_opp; + rconn_send(pw->remote_rconn, b, NULL); + } + } +} + +static void +port_watcher_wait_cb(void *pw_) +{ + struct port_watcher *pw = pw_; + if (!pw->got_feature_reply && rconn_is_connected(pw->local_rconn)) { + if (pw->last_feature_request != TIME_MIN) { + poll_timer_wait(pw->last_feature_request + 5 - time_now()); + } else { + poll_immediate_wake(); + } + } + netdev_monitor_wait(pw->mon); +} + +static void +put_duplexes(struct ds *ds, const char *name, uint32_t features, + uint32_t hd_bit, uint32_t fd_bit) +{ + if (features & (hd_bit | fd_bit)) { + ds_put_format(ds, " %s", name); + if (features & hd_bit) { + ds_put_cstr(ds, "(HD)"); + } + if (features & fd_bit) { + ds_put_cstr(ds, "(FD)"); + } + } +} + +static void +put_features(struct ds *ds, const char *name, uint32_t features) +{ + if (features & (OFPPF_10MB_HD | OFPPF_10MB_FD + | OFPPF_100MB_HD | OFPPF_100MB_FD + | OFPPF_1GB_HD | OFPPF_1GB_FD | OFPPF_10GB_FD)) { + ds_put_cstr(ds, name); + put_duplexes(ds, "10M", features, OFPPF_10MB_HD, OFPPF_10MB_FD); + put_duplexes(ds, "100M", features, + OFPPF_100MB_HD, OFPPF_100MB_FD); + put_duplexes(ds, "1G", features, OFPPF_1GB_HD, OFPPF_1GB_FD); + if (features & OFPPF_10GB_FD) { + ds_put_cstr(ds, " 10G"); + } + if (features & OFPPF_AUTONEG) { + ds_put_cstr(ds, " AUTO_NEG"); + } + if (features & OFPPF_PAUSE) { + ds_put_cstr(ds, " PAUSE"); + } + if (features & OFPPF_PAUSE_ASYM) { + ds_put_cstr(ds, " PAUSE_ASYM"); + } + } +} + +static void +log_port_status(uint16_t port_no, + const struct ofp_phy_port *old, + const struct ofp_phy_port *new, + void *aux UNUSED) +{ + if (VLOG_IS_DBG_ENABLED()) { + if (old && new && (opp_differs(old, new) + == ((old->config != new->config) + + (old->state != new->state)))) + { + /* Don't care if only state or config changed. */ + } else if (!new) { + if (old) { + VLOG_DBG("Port %d deleted", port_no); + } + } else { + struct ds ds = DS_EMPTY_INITIALIZER; + uint32_t curr = ntohl(new->curr); + uint32_t supported = ntohl(new->supported); + ds_put_format(&ds, "\"%s\", "ETH_ADDR_FMT, new->name, + ETH_ADDR_ARGS(new->hw_addr)); + if (curr) { + put_features(&ds, ", current", curr); + } + if (supported) { + put_features(&ds, ", supports", supported); + } + VLOG_DBG("Port %d %s: %s", + port_no, old ? "changed" : "added", ds_cstr(&ds)); + ds_destroy(&ds); + } + } +} + +void +port_watcher_register_callback(struct port_watcher *pw, + port_changed_cb_func *port_changed, + void *aux) +{ + assert(pw->n_cbs < ARRAY_SIZE(pw->cbs)); + pw->cbs[pw->n_cbs].port_changed = port_changed; + pw->cbs[pw->n_cbs].aux = aux; + pw->n_cbs++; +} + +void +port_watcher_register_local_port_callback(struct port_watcher *pw, + local_port_changed_cb_func *cb, + void *aux) +{ + assert(pw->n_local_cbs < ARRAY_SIZE(pw->local_cbs)); + pw->local_cbs[pw->n_local_cbs].local_port_changed = cb; + pw->local_cbs[pw->n_local_cbs].aux = aux; + pw->n_local_cbs++; +} + +uint32_t +port_watcher_get_config(const struct port_watcher *pw, uint16_t port_no) +{ + struct ofp_phy_port *p = lookup_port(pw, port_no); + return p ? ntohl(p->config) : 0; +} + +const char * +port_watcher_get_name(const struct port_watcher *pw, uint16_t port_no) +{ + struct ofp_phy_port *p = lookup_port(pw, port_no); + return p ? (const char *) p->name : NULL; +} + +const uint8_t * +port_watcher_get_hwaddr(const struct port_watcher *pw, uint16_t port_no) +{ + struct ofp_phy_port *p = lookup_port(pw, port_no); + return p ? p->hw_addr : NULL; +} + +void +port_watcher_set_flags(struct port_watcher *pw, uint16_t port_no, + uint32_t config, uint32_t c_mask, + uint32_t state, uint32_t s_mask) +{ + struct ofp_phy_port old; + struct ofp_phy_port *p; + struct ofp_port_mod *opm; + struct ofp_port_status *ops; + struct ofpbuf *b; + + p = lookup_port(pw, port_no); + if (!p) { + return; + } + + if (!((ntohl(p->state) ^ state) & s_mask) + && (!((ntohl(p->config) ^ config) & c_mask))) { + return; + } + old = *p; + + /* Update our idea of the flags. */ + p->config = htonl((ntohl(p->config) & ~c_mask) | (config & c_mask)); + p->state = htonl((ntohl(p->state) & ~s_mask) | (state & s_mask)); + call_port_changed_callbacks(pw, port_no, &old, p); + + /* Change the flags in the datapath. */ + opm = make_openflow(sizeof *opm, OFPT_PORT_MOD, &b); + opm->port_no = p->port_no; + memcpy(opm->hw_addr, p->hw_addr, OFP_ETH_ALEN); + opm->config = p->config; + opm->mask = htonl(c_mask); + opm->advertise = htonl(0); + rconn_send(pw->local_rconn, b, NULL); + + /* Notify the controller that the flags changed. */ + ops = make_openflow(sizeof *ops, OFPT_PORT_STATUS, &b); + ops->reason = OFPPR_MODIFY; + ops->desc = *p; + rconn_send(pw->remote_rconn, b, NULL); +} + +bool +port_watcher_is_ready(const struct port_watcher *pw) +{ + return pw->got_feature_reply; +} + +static struct hook_class port_watcher_hook_class = { + port_watcher_local_packet_cb, /* local_packet_cb */ + port_watcher_remote_packet_cb, /* remote_packet_cb */ + port_watcher_periodic_cb, /* periodic_cb */ + port_watcher_wait_cb, /* wait_cb */ + NULL, /* closing_cb */ +}; + +void +port_watcher_start(struct secchan *secchan, + struct rconn *local_rconn, struct rconn *remote_rconn, + struct port_watcher **pwp) +{ + struct port_watcher *pw; + int retval; + + pw = *pwp = xcalloc(1, sizeof *pw); + pw->local_rconn = local_rconn; + pw->remote_rconn = remote_rconn; + pw->last_feature_request = TIME_MIN; + port_array_init(&pw->ports); + pw->local_port_name[0] = '\0'; + retval = netdev_monitor_create(&pw->mon); + if (retval) { + ofp_fatal(retval, "failed to start network device monitoring"); + } + shash_init(&pw->port_by_name); + port_watcher_register_callback(pw, log_port_status, NULL); + add_hook(secchan, &port_watcher_hook_class, pw); +} diff --git a/openflow/secchan/port-watcher.h b/openflow/secchan/port-watcher.h new file mode 100644 index 00000000..904e545a --- /dev/null +++ b/openflow/secchan/port-watcher.h @@ -0,0 +1,77 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#ifndef PORT_WATCHER_H +#define PORT_WATCHER_H 1 + +#include +#include "compiler.h" +#include "secchan.h" + +struct ofp_phy_port; +struct port_watcher; +struct secchan; + +void port_watcher_start(struct secchan *, + struct rconn *local, struct rconn *remote, + struct port_watcher **); +bool port_watcher_is_ready(const struct port_watcher *); +uint32_t port_watcher_get_config(const struct port_watcher *, + uint16_t port_no); +const char *port_watcher_get_name(const struct port_watcher *, + uint16_t port_no) UNUSED; +const uint8_t *port_watcher_get_hwaddr(const struct port_watcher *, + uint16_t port_no); +void port_watcher_set_flags(struct port_watcher *, uint16_t port_no, + uint32_t config, uint32_t c_mask, + uint32_t state, uint32_t s_mask); + +typedef void port_changed_cb_func(uint16_t port_no, + const struct ofp_phy_port *old, + const struct ofp_phy_port *new, + void *aux); + +void port_watcher_register_callback(struct port_watcher *, + port_changed_cb_func *port_changed, + void *aux); + +typedef void local_port_changed_cb_func(const struct ofp_phy_port *new, + void *aux); + +void port_watcher_register_local_port_callback(struct port_watcher *pw, + local_port_changed_cb_func *cb, + void *aux); + +void get_port_name(const struct ofp_phy_port *, char *name, size_t name_size); + +#endif /* port-watcher.h */ diff --git a/openflow/secchan/protocol-stat.c b/openflow/secchan/protocol-stat.c new file mode 100644 index 00000000..d54548b3 --- /dev/null +++ b/openflow/secchan/protocol-stat.c @@ -0,0 +1,204 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#include +#include +#include +#include +#include +#include + +#include "openflow/openflow.h" +#include "openflow/private-ext.h" + +#include "ofpbuf.h" +#include "util.h" +#include "xtoxll.h" +#include "rconn.h" +#include "vconn.h" +#include "secchan.h" +#include "status.h" +#include "timeval.h" +#include "sat-math.h" +#include "ofpstat.h" +#include "protocol-stat.h" +#define THIS_MODULE VLM_protocol_stat +#include "vlog.h" + +#define COPY_OFPS(dst_ofps, src_ofps, tag) \ +do { \ + (dst_ofps)->tag = htonll((src_ofps)->tag); \ +} while (0) + +#define COPY_OFP_STAT(dst_ofps, src_ofps) \ +do { \ + COPY_OFPS(dst_ofps, src_ofps, ofps_total); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_unknown); \ + \ + COPY_OFPS(dst_ofps, src_ofps, ofps_hello); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_echo_request); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_echo_reply); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_vendor); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_feats_request); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_feats_reply); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_get_config_request); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_get_config_reply); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_set_config); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_packet_in); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_flow_removed); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_port_status); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_packet_out); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_flow_mod); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_port_mod); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_stats_request); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_stats_reply); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_barrier_request); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_barrier_reply); \ + \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_type.hello_fail); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_type.bad_request); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_type.bad_action); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_type.flow_mod_fail); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_type.unknown); \ + \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.hf_incompat); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.hf_eperm); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.br_bad_version); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.br_bad_type); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.br_bad_stat); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.br_bad_vendor); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.br_eperm); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.ba_bad_type); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.ba_bad_len); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.ba_bad_vendor); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.ba_bad_vendor_type); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.ba_bad_out_port); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.ba_eperm); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.fmf_all_tables_full); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.fmf_overlap); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.fmf_eperm); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.unknown); \ + \ + COPY_OFPS(dst_ofps, src_ofps, ofps_flow_mod_ops.add); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_flow_mod_ops.modify); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_flow_mod_ops.delete); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_flow_mod_ops.delete_strict); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_flow_mod_ops.unknown); \ +} while (0) + +struct protocol_stat_context { + const struct settings *settings; + const struct secchan *secchan; + struct rconn *local_rconn; + struct rconn *remote_rconn; + struct ofpstat ofps_rcvd; + struct ofpstat ofps_sent; +}; + +static bool protocol_stat_remote_packet_cb(struct relay *, void *); + +static bool +protocol_stat_remote_packet_cb(struct relay *relay, void *context_) +{ + struct protocol_stat_context *context = context_; + struct rconn *mgmt_rconn = relay->halves[HALF_REMOTE].rconn; + struct ofpbuf *qbuf = relay->halves[HALF_REMOTE].rxbuf; + struct ofpbuf *pbuf = NULL; + struct private_vxhdr *qvxhdr = NULL; + struct private_vxhdr *pvxhdr = NULL; + struct private_vxopt *qvxopt = NULL; + struct private_vxopt *pvxopt = NULL; + struct ofpstat *ofps = NULL; + struct ofpstat ofps_rcvd; + struct ofpstat ofps_sent; + int error = 0; + + if (qbuf->size < sizeof(*qvxhdr)) + return false; + qvxhdr = qbuf->data; + if (qvxhdr->ofp_hdr.type != OFPT_VENDOR) + return false; + if (ntohl(qvxhdr->ofp_vxid) != PRIVATE_VENDOR_ID) { + return false; + } + qvxopt = (struct private_vxopt *)(qvxhdr + 1); + if (ntohs(qvxopt->pvo_type) != PRIVATEOPT_PROTOCOL_STATS_REQUEST) { + return true; + } + + pvxhdr = make_openflow_xid(sizeof(*pvxhdr) + sizeof(*pvxopt) + + (sizeof(*ofps) * 2), + OFPT_VENDOR, qvxhdr->ofp_hdr.xid, &pbuf); + pvxopt = (struct private_vxopt *)(pvxhdr + 1); + pvxhdr->ofp_vxid = qvxhdr->ofp_vxid; + pvxopt->pvo_type = htons(PRIVATEOPT_PROTOCOL_STATS_REPLY); + pvxopt->pvo_len = htons(sizeof(*ofps) * 2); + + rconn_update_protocol_stat(context->remote_rconn, + &ofps_rcvd, &ofps_sent); + ofps = (struct ofpstat *)((uint8_t *)(pvxhdr + 1) + sizeof(*pvxopt)); + COPY_OFP_STAT(ofps, &ofps_rcvd); + ofps = ofps + 1; + COPY_OFP_STAT(ofps, &ofps_sent); + + error = rconn_send(mgmt_rconn, pbuf, NULL); + if (error && error != EAGAIN) { + VLOG_WARN("send failed (%s)", strerror(error)); + } + + return true; +} + +void +protocol_stat_start(struct secchan *secchan, const struct settings *settings, + struct rconn *local_rconn, struct rconn *remote_rconn) +{ + struct protocol_stat_context *context = NULL; + static struct hook_class protocol_stat_hook_class = { + NULL, /* local_packet_cb */ + protocol_stat_remote_packet_cb, /* remote_packet_cb */ + NULL, /* periodic_cb */ + NULL, /* wait_cb */ + NULL, /* closing_cb */ + }; + + context = xmalloc(sizeof(*context)); + context->settings = settings; + context->secchan = secchan; + context->local_rconn = local_rconn; + context->remote_rconn = remote_rconn; + memset(&context->ofps_rcvd, 0, sizeof(context->ofps_rcvd)); + memset(&context->ofps_sent, 0, sizeof(context->ofps_sent)); + + add_hook(secchan, &protocol_stat_hook_class, context); +} diff --git a/openflow/secchan/protocol-stat.h b/openflow/secchan/protocol-stat.h new file mode 100644 index 00000000..3037b449 --- /dev/null +++ b/openflow/secchan/protocol-stat.h @@ -0,0 +1,44 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#ifndef PROTOCOL_STAT_H_ +#define PROTOCOL_STAT_H_ + +struct rconn; +struct secchan; +struct settings; +struct switch_status; + +void protocol_stat_start(struct secchan *, const struct settings *, + struct rconn *, struct rconn *); + +#endif diff --git a/openflow/secchan/ratelimit.c b/openflow/secchan/ratelimit.c new file mode 100644 index 00000000..7a1e4951 --- /dev/null +++ b/openflow/secchan/ratelimit.c @@ -0,0 +1,263 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include "ratelimit.h" +#include +#include +#include "ofpbuf.h" +#include "openflow/openflow.h" +#include "poll-loop.h" +#include "queue.h" +#include "rconn.h" +#include "secchan.h" +#include "status.h" +#include "timeval.h" +#include "vconn.h" + +struct rate_limiter { + const struct settings *s; + struct rconn *remote_rconn; + + /* One queue per physical port. */ + struct ofp_queue queues[OFPP_MAX]; + int n_queued; /* Sum over queues[*].n. */ + int next_tx_port; /* Next port to check in round-robin. */ + + /* Token bucket. + * + * It costs 1000 tokens to send a single packet_in message. A single token + * per message would be more straightforward, but this choice lets us avoid + * round-off error in refill_bucket()'s calculation of how many tokens to + * add to the bucket, since no division step is needed. */ + long long int last_fill; /* Time at which we last added tokens. */ + int tokens; /* Current number of tokens. */ + + /* Transmission queue. */ + int n_txq; /* No. of packets waiting in rconn for tx. */ + + /* Statistics reporting. */ + unsigned long long n_normal; /* # txed w/o rate limit queuing. */ + unsigned long long n_limited; /* # queued for rate limiting. */ + unsigned long long n_queue_dropped; /* # dropped due to queue overflow. */ + unsigned long long n_tx_dropped; /* # dropped due to tx overflow. */ +}; + +/* Drop a packet from the longest queue in 'rl'. */ +static void +drop_packet(struct rate_limiter *rl) +{ + struct ofp_queue *longest; /* Queue currently selected as longest. */ + int n_longest; /* # of queues of same length as 'longest'. */ + struct ofp_queue *q; + + longest = &rl->queues[0]; + n_longest = 1; + for (q = &rl->queues[0]; q < &rl->queues[OFPP_MAX]; q++) { + if (longest->n < q->n) { + longest = q; + n_longest = 1; + } else if (longest->n == q->n) { + n_longest++; + + /* Randomly select one of the longest queues, with a uniform + * distribution (Knuth algorithm 3.4.2R). */ + if (!random_range(n_longest)) { + longest = q; + } + } + } + + /* FIXME: do we want to pop the tail instead? */ + ofpbuf_delete(queue_pop_head(longest)); + rl->n_queued--; +} + +/* Remove and return the next packet to transmit (in round-robin order). */ +static struct ofpbuf * +dequeue_packet(struct rate_limiter *rl) +{ + unsigned int i; + + for (i = 0; i < OFPP_MAX; i++) { + unsigned int port = (rl->next_tx_port + i) % OFPP_MAX; + struct ofp_queue *q = &rl->queues[port]; + if (q->n) { + rl->next_tx_port = (port + 1) % OFPP_MAX; + rl->n_queued--; + return queue_pop_head(q); + } + } + NOT_REACHED(); +} + +/* Add tokens to the bucket based on elapsed time. */ +static void +refill_bucket(struct rate_limiter *rl) +{ + const struct settings *s = rl->s; + long long int now = time_msec(); + long long int tokens = (now - rl->last_fill) * s->rate_limit + rl->tokens; + if (tokens >= 1000) { + rl->last_fill = now; + rl->tokens = MIN(tokens, s->burst_limit * 1000); + } +} + +/* Attempts to remove enough tokens from 'rl' to transmit a packet. Returns + * true if successful, false otherwise. (In the latter case no tokens are + * removed.) */ +static bool +get_token(struct rate_limiter *rl) +{ + if (rl->tokens >= 1000) { + rl->tokens -= 1000; + return true; + } else { + return false; + } +} + +static bool +rate_limit_local_packet_cb(struct relay *r, void *rl_) +{ + struct rate_limiter *rl = rl_; + const struct settings *s = rl->s; + struct ofp_packet_in *opi; + + opi = get_ofp_packet_in(r); + if (!opi) { + return false; + } + + if (opi->reason == OFPR_ACTION) { + /* Don't rate-limit 'ofp-packet_in's generated by flows that the + * controller set up. XXX we should really just rate-limit them + * *separately* so that no one can flood the controller this way. */ + return false; + } + + if (!rl->n_queued && get_token(rl)) { + /* In the common case where we are not constrained by the rate limit, + * let the packet take the normal path. */ + rl->n_normal++; + return false; + } else { + /* Otherwise queue it up for the periodic callback to drain out. */ + struct ofpbuf *msg = r->halves[HALF_LOCAL].rxbuf; + int port = ntohs(opi->in_port) % OFPP_MAX; + if (rl->n_queued >= s->burst_limit) { + drop_packet(rl); + } + queue_push_tail(&rl->queues[port], ofpbuf_clone(msg)); + rl->n_queued++; + rl->n_limited++; + return true; + } +} + +static void +rate_limit_status_cb(struct status_reply *sr, void *rl_) +{ + struct rate_limiter *rl = rl_; + + status_reply_put(sr, "normal=%llu", rl->n_normal); + status_reply_put(sr, "limited=%llu", rl->n_limited); + status_reply_put(sr, "queue-dropped=%llu", rl->n_queue_dropped); + status_reply_put(sr, "tx-dropped=%llu", rl->n_tx_dropped); +} + +static void +rate_limit_periodic_cb(void *rl_) +{ + struct rate_limiter *rl = rl_; + int i; + + /* Drain some packets out of the bucket if possible, but limit the number + * of iterations to allow other code to get work done too. */ + refill_bucket(rl); + for (i = 0; rl->n_queued && get_token(rl) && i < 50; i++) { + /* Use a small, arbitrary limit for the amount of queuing to do here, + * because the TCP connection is responsible for buffering and there is + * no point in trying to transmit faster than the TCP connection can + * handle. */ + struct ofpbuf *b = dequeue_packet(rl); + if (rconn_send_with_limit(rl->remote_rconn, b, &rl->n_txq, 10)) { + rl->n_tx_dropped++; + } + } +} + +static void +rate_limit_wait_cb(void *rl_) +{ + struct rate_limiter *rl = rl_; + if (rl->n_queued) { + if (rl->tokens >= 1000) { + /* We can transmit more packets as soon as we're called again. */ + poll_immediate_wake(); + } else { + /* We have to wait for the bucket to re-fill. We could calculate + * the exact amount of time here for increased smoothness. */ + poll_timer_wait(TIME_UPDATE_INTERVAL / 2); + } + } +} + +static struct hook_class rate_limit_hook_class = { + rate_limit_local_packet_cb, /* local_packet_cb */ + NULL, /* remote_packet_cb */ + rate_limit_periodic_cb, /* periodic_cb */ + rate_limit_wait_cb, /* wait_cb */ + NULL, /* closing_cb */ +}; + +void +rate_limit_start(struct secchan *secchan, const struct settings *s, + struct switch_status *ss, struct rconn *remote) +{ + struct rate_limiter *rl; + size_t i; + + rl = xcalloc(1, sizeof *rl); + rl->s = s; + rl->remote_rconn = remote; + for (i = 0; i < ARRAY_SIZE(rl->queues); i++) { + queue_init(&rl->queues[i]); + } + rl->last_fill = time_msec(); + rl->tokens = s->rate_limit * 100; + switch_status_register_category(ss, "rate-limit", + rate_limit_status_cb, rl); + add_hook(secchan, &rate_limit_hook_class, rl); +} diff --git a/openflow/secchan/ratelimit.h b/openflow/secchan/ratelimit.h new file mode 100644 index 00000000..25ab9777 --- /dev/null +++ b/openflow/secchan/ratelimit.h @@ -0,0 +1,45 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#ifndef RATELIMIT_H +#define RATELIMIT_H 1 + +struct rconn; +struct secchan; +struct settings; +struct switch_status; + +void rate_limit_start(struct secchan *, const struct settings *, + struct switch_status *, struct rconn *remote); + +#endif /* ratelimit.h */ diff --git a/openflow/secchan/secchan.c b/openflow/secchan/secchan.c new file mode 100644 index 00000000..15c7b696 --- /dev/null +++ b/openflow/secchan/secchan.c @@ -0,0 +1,882 @@ +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include "secchan.h" +#include +#include +#include +#include +#include +#include +#include + +#include "command-line.h" +#include "compiler.h" +#include "daemon.h" +#include "dirs.h" +#include "discovery.h" +#include "emerg-flow.h" +#include "fail-open.h" +#include "failover.h" +#include "fault.h" +#include "in-band.h" +#include "leak-checker.h" +#include "list.h" +#include "ofpbuf.h" +#include "openflow/openflow.h" +#include "packets.h" +#include "protocol-stat.h" +#include "port-watcher.h" +#include "poll-loop.h" +#include "ratelimit.h" +#include "rconn.h" +#include "stp-secchan.h" +#include "status.h" +#include "timeval.h" +#include "util.h" +#include "vconn-ssl.h" +#include "vconn.h" +#include "vlog-socket.h" + +#include "vlog.h" +#define THIS_MODULE VLM_secchan + +struct hook { + const struct hook_class *class; + void *aux; +}; + +struct secchan { + struct hook *hooks; + size_t n_hooks, allocated_hooks; +}; + +static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60); + +static void parse_options(int argc, char *argv[], struct settings *); +static void usage(void) NO_RETURN; + +static char *vconn_name_without_subscription(const char *); +static struct pvconn *open_passive_vconn(const char *name); +static struct vconn *accept_vconn(struct pvconn *pvconn); + +static struct relay *relay_create(struct rconn *async, + struct rconn *local, struct rconn *remote, + bool is_mgmt_conn); +static struct relay *relay_accept(const struct settings *, struct pvconn *); +static void relay_run(struct relay *, struct secchan *); +static void relay_wait(struct relay *); +static void relay_destroy(struct relay *); + +int +main(int argc, char *argv[]) +{ + struct settings s; + + struct list relays = LIST_INITIALIZER(&relays); + + struct secchan secchan; + + struct pvconn *monitor; + + struct pvconn *listeners[MAX_MGMT]; + size_t n_listeners; + + char *local_rconn_name; + struct rconn *async_rconn, *local_rconn, *remote_rconn; + struct relay *controller_relay; + struct discovery *discovery; + struct switch_status *switch_status; + struct port_watcher *pw; + int i; + int retval; + + set_program_name(argv[0]); + register_fault_handlers(); + time_init(); + vlog_init(); + parse_options(argc, argv, &s); + signal(SIGPIPE, SIG_IGN); + + secchan.hooks = NULL; + secchan.n_hooks = 0; + secchan.allocated_hooks = 0; + + /* Start listening for management and monitoring connections. */ + n_listeners = 0; + for (i = 0; i < s.n_listeners; i++) { + listeners[n_listeners++] = open_passive_vconn(s.listener_names[i]); + } + monitor = s.monitor_name ? open_passive_vconn(s.monitor_name) : NULL; + + /* Initialize switch status hook. */ + switch_status_start(&secchan, &s, &switch_status); + + die_if_already_running(); + daemonize(); + + /* Start listening for vlogconf requests. */ + retval = vlog_server_listen(NULL, NULL); + if (retval) { + ofp_fatal(retval, "Could not listen for vlog connections"); + } + + VLOG_INFO("OpenFlow reference implementation version %s", VERSION BUILDNR); + VLOG_INFO("OpenFlow protocol version 0x%02x", OFP_VERSION); + + /* Check datapath name, to try to catch command-line invocation errors. */ + if (strncmp(s.dp_name, "nl:", 3) && strncmp(s.dp_name, "unix:", 5) + && !s.controller_names[0]) { + VLOG_WARN("Controller not specified and datapath is not nl: or " + "unix:. (Did you forget to specify the datapath?)"); + } + + if (!strncmp(s.dp_name, "nl:", 3)) { + /* Connect to datapath with a subscription for asynchronous events. By + * separating the connection for asynchronous events from that for + * request and replies we prevent the socket receive buffer from being + * filled up by received packet data, which in turn would prevent + * getting replies to any Netlink messages we send to the kernel. */ + async_rconn = rconn_create(0, s.max_backoff); + rconn_connect(async_rconn, s.dp_name); + switch_status_register_category(switch_status, "async", + rconn_status_cb, async_rconn); + } else { + /* No need for a separate asynchronous connection: we must be connected + * to the user datapath, which is smart enough to discard packet events + * instead of message replies. In fact, having a second connection + * would work against us since we'd get double copies of asynchronous + * event messages (the user datapath provides no way to turn off + * asynchronous events). */ + async_rconn = NULL; + } + + /* Connect to datapath without a subscription, for requests and replies. */ + local_rconn_name = vconn_name_without_subscription(s.dp_name); + local_rconn = rconn_create(0, s.max_backoff); + rconn_connect(local_rconn, local_rconn_name); + free(local_rconn_name); + switch_status_register_category(switch_status, "local", + rconn_status_cb, local_rconn); + + /* Connect to controller. */ + remote_rconn = rconn_create(s.probe_interval, s.max_backoff); + if (s.controller_names[0]) { + retval = rconn_connect(remote_rconn, s.controller_names[0]); + if (retval == EAFNOSUPPORT) { + ofp_fatal(0, "No support for %s vconn", s.controller_names[0]); + } + } + switch_status_register_category(switch_status, "remote", + rconn_status_cb, remote_rconn); + + /* Start relaying. */ + controller_relay = relay_create(async_rconn, local_rconn, remote_rconn, + false); + list_push_back(&relays, &controller_relay->node); + + /* Set up hooks. */ + port_watcher_start(&secchan, local_rconn, remote_rconn, &pw); + discovery = s.discovery ? discovery_init(&s, pw, switch_status) : NULL; + if (s.enable_stp) { + stp_start(&secchan, pw, local_rconn, remote_rconn); + } + if (s.in_band) { + in_band_start(&secchan, &s, switch_status, pw, remote_rconn); + } + if (s.fail_mode == FAIL_OPEN) { + fail_open_start(&secchan, &s, switch_status, + local_rconn, remote_rconn); + } + if (s.num_controllers > 1) { + failover_start(&secchan, &s, switch_status, remote_rconn); + } + if (s.n_listeners > 0) { + protocol_stat_start(&secchan, &s, local_rconn, remote_rconn); + } + if (s.rate_limit) { + rate_limit_start(&secchan, &s, switch_status, remote_rconn); + } + if (s.emerg_flow) { + emerg_flow_start(&secchan, &s, switch_status, local_rconn, remote_rconn); + } + + while (s.discovery || rconn_is_alive(remote_rconn)) { + struct relay *r, *n; + size_t i; + + /* Do work. */ + LIST_FOR_EACH_SAFE (r, n, struct relay, node, &relays) { + relay_run(r, &secchan); + } + for (i = 0; i < n_listeners; i++) { + for (;;) { + struct relay *r = relay_accept(&s, listeners[i]); + if (!r) { + break; + } + list_push_back(&relays, &r->node); + } + } + if (monitor) { + struct vconn *new = accept_vconn(monitor); + if (new) { + /* XXX should monitor async_rconn too but rconn_add_monitor() + * takes ownership of the vconn passed in. */ + rconn_add_monitor(local_rconn, new); + } + } + for (i = 0; i < secchan.n_hooks; i++) { + if (secchan.hooks[i].class->periodic_cb) { + secchan.hooks[i].class->periodic_cb(secchan.hooks[i].aux); + } + } + if (s.discovery) { + char *controller_name; + if (rconn_is_connectivity_questionable(remote_rconn)) { + discovery_question_connectivity(discovery); + } + if (discovery_run(discovery, &controller_name)) { + if (controller_name) { + rconn_connect(remote_rconn, controller_name); + } else { + rconn_disconnect(remote_rconn); + } + } + } + + /* Wait for something to happen. */ + LIST_FOR_EACH (r, struct relay, node, &relays) { + relay_wait(r); + } + for (i = 0; i < n_listeners; i++) { + pvconn_wait(listeners[i]); + } + if (monitor) { + pvconn_wait(monitor); + } + for (i = 0; i < secchan.n_hooks; i++) { + if (secchan.hooks[i].class->wait_cb) { + secchan.hooks[i].class->wait_cb(secchan.hooks[i].aux); + } + } + if (discovery) { + discovery_wait(discovery); + } + poll_block(); + } + + return 0; +} + +static struct pvconn * +open_passive_vconn(const char *name) +{ + struct pvconn *pvconn; + int retval; + + retval = pvconn_open(name, &pvconn); + if (retval && retval != EAGAIN) { + ofp_fatal(retval, "opening %s", name); + } + return pvconn; +} + +static struct vconn * +accept_vconn(struct pvconn *pvconn) +{ + struct vconn *new; + int retval; + + retval = pvconn_accept(pvconn, OFP_VERSION, &new); + if (retval && retval != EAGAIN) { + VLOG_WARN_RL(&rl, "accept failed (%s)", strerror(retval)); + } + return new; +} + +void +add_hook(struct secchan *secchan, const struct hook_class *class, void *aux) +{ + struct hook *hook; + + if (secchan->n_hooks >= secchan->allocated_hooks) { + secchan->hooks = x2nrealloc(secchan->hooks, &secchan->allocated_hooks, + sizeof *secchan->hooks); + } + hook = &secchan->hooks[secchan->n_hooks++]; + hook->class = class; + hook->aux = aux; +} + +struct ofp_packet_in * +get_ofp_packet_in(struct relay *r) +{ + struct ofpbuf *msg = r->halves[HALF_LOCAL].rxbuf; + struct ofp_header *oh = msg->data; + if (oh->type == OFPT_PACKET_IN) { + if (msg->size >= offsetof (struct ofp_packet_in, data)) { + return msg->data; + } else { + VLOG_WARN("packet too short (%zu bytes) for packet_in", + msg->size); + } + } + return NULL; +} + +bool +get_ofp_packet_eth_header(struct relay *r, struct ofp_packet_in **opip, + struct eth_header **ethp) +{ + const int min_len = offsetof(struct ofp_packet_in, data) + ETH_HEADER_LEN; + struct ofp_packet_in *opi = get_ofp_packet_in(r); + if (opi && ntohs(opi->header.length) >= min_len) { + *opip = opi; + *ethp = (void *) opi->data; + return true; + } + return false; +} + +/* OpenFlow message relaying. */ + +/* Returns a malloc'd string containing a copy of 'vconn_name' modified not to + * subscribe to asynchronous messages such as 'ofp_packet_in' events (if + * possible). */ +static char * +vconn_name_without_subscription(const char *vconn_name) +{ + int nl_index; + if (sscanf(vconn_name, "nl:%d", &nl_index) == 1) { + /* nl:123 or nl:123:1 opens a netlink connection to local datapath 123. + * nl:123:0 opens a netlink connection to local datapath 123 without + * obtaining a subscription for ofp_packet_in or ofp_flow_removed + * messages. */ + return xasprintf("nl:%d:0", nl_index); + } else { + /* We don't have a way to specify not to subscribe to those messages + * for other transports. (That's a defect: really this should be in + * the OpenFlow protocol, not the Netlink transport). */ + VLOG_WARN_RL(&rl, "new management connection will receive " + "asynchronous messages"); + return xstrdup(vconn_name); + } +} + +static struct relay * +relay_accept(const struct settings *s, struct pvconn *pvconn) +{ + struct vconn *new_remote, *new_local; + struct rconn *r1, *r2; + char *vconn_name; + int retval; + + new_remote = accept_vconn(pvconn); + if (!new_remote) { + return NULL; + } + + vconn_name = vconn_name_without_subscription(s->dp_name); + retval = vconn_open(vconn_name, OFP_VERSION, &new_local); + if (retval) { + VLOG_ERR_RL(&rl, "could not connect to %s (%s)", + vconn_name, strerror(retval)); + vconn_close(new_remote); + free(vconn_name); + return NULL; + } + + /* Create and return relay. */ + r1 = rconn_create(0, 0); + rconn_connect_unreliably(r1, vconn_name, new_local); + free(vconn_name); + + r2 = rconn_create(0, 0); + rconn_connect_unreliably(r2, "passive", new_remote); + + return relay_create(NULL, r1, r2, true); +} + +static struct relay * +relay_create(struct rconn *async, struct rconn *local, struct rconn *remote, + bool is_mgmt_conn) +{ + struct relay *r = xcalloc(1, sizeof *r); + r->halves[HALF_LOCAL].rconn = local; + r->halves[HALF_REMOTE].rconn = remote; + r->is_mgmt_conn = is_mgmt_conn; + r->async_rconn = async; + return r; +} + +static bool +call_local_packet_cbs(struct secchan *secchan, struct relay *r) +{ + const struct hook *h; + for (h = secchan->hooks; h < &secchan->hooks[secchan->n_hooks]; h++) { + bool (*cb)(struct relay *, void *aux) = h->class->local_packet_cb; + if (cb && (cb)(r, h->aux)) { + return true; + } + } + return false; +} + +static bool +call_remote_packet_cbs(struct secchan *secchan, struct relay *r) +{ + const struct hook *h; + for (h = secchan->hooks; h < &secchan->hooks[secchan->n_hooks]; h++) { + bool (*cb)(struct relay *, void *aux) = h->class->remote_packet_cb; + if (cb && (cb)(r, h->aux)) { + return true; + } + } + return false; +} + +static void +relay_run(struct relay *r, struct secchan *secchan) +{ + int iteration; + int i; + + if (r->async_rconn) { + rconn_run(r->async_rconn); + } + for (i = 0; i < 2; i++) { + rconn_run(r->halves[i].rconn); + } + + /* Limit the number of iterations to prevent other tasks from starving. */ + for (iteration = 0; iteration < 50; iteration++) { + bool progress = false; + for (i = 0; i < 2; i++) { + struct half *this = &r->halves[i]; + struct half *peer = &r->halves[!i]; + + if (!this->rxbuf) { + this->rxbuf = rconn_recv(this->rconn); + if (!this->rxbuf && i == HALF_LOCAL && r->async_rconn) { + this->rxbuf = rconn_recv(r->async_rconn); + } + if (this->rxbuf && (i == HALF_REMOTE || !r->is_mgmt_conn)) { + if (i == HALF_LOCAL + ? call_local_packet_cbs(secchan, r) + : call_remote_packet_cbs(secchan, r)) + { + ofpbuf_delete(this->rxbuf); + this->rxbuf = NULL; + progress = true; + break; + } + } + } + + if (this->rxbuf && !this->n_txq) { + int retval = rconn_send(peer->rconn, this->rxbuf, + &this->n_txq); + if (retval != EAGAIN) { + if (!retval) { + progress = true; + } else { + ofpbuf_delete(this->rxbuf); + } + this->rxbuf = NULL; + } + } + } + if (!progress) { + break; + } + } + + if (r->is_mgmt_conn) { + for (i = 0; i < 2; i++) { + struct half *this = &r->halves[i]; + if (!rconn_is_alive(this->rconn)) { + relay_destroy(r); + return; + } + } + } +} + +static void +relay_wait(struct relay *r) +{ + int i; + + if (r->async_rconn) { + rconn_run_wait(r->async_rconn); + } + for (i = 0; i < 2; i++) { + struct half *this = &r->halves[i]; + + rconn_run_wait(this->rconn); + if (!this->rxbuf) { + rconn_recv_wait(this->rconn); + if (i == HALF_LOCAL && r->async_rconn) { + rconn_recv_wait(r->async_rconn); + } + } + } +} + +static void +relay_destroy(struct relay *r) +{ + int i; + + list_remove(&r->node); + rconn_destroy(r->async_rconn); + for (i = 0; i < 2; i++) { + struct half *this = &r->halves[i]; + rconn_destroy(this->rconn); + ofpbuf_delete(this->rxbuf); + } + free(r); +} + +/* User interface. */ + +static void +parse_options(int argc, char *argv[], struct settings *s) +{ + enum { + OPT_ACCEPT_VCONN = UCHAR_MAX + 1, + OPT_NO_RESOLV_CONF, + OPT_INACTIVITY_PROBE, + OPT_MAX_IDLE, + OPT_MAX_BACKOFF, + OPT_RATE_LIMIT, + OPT_BURST_LIMIT, + OPT_BOOTSTRAP_CA_CERT, + OPT_STP, + OPT_NO_STP, + OPT_OUT_OF_BAND, + OPT_IN_BAND, + OPT_EMERG_FLOW, + VLOG_OPTION_ENUMS, + LEAK_CHECKER_OPTION_ENUMS + }; + static struct option long_options[] = { + {"accept-vconn", required_argument, 0, OPT_ACCEPT_VCONN}, + {"no-resolv-conf", no_argument, 0, OPT_NO_RESOLV_CONF}, + {"fail", required_argument, 0, 'F'}, + {"inactivity-probe", required_argument, 0, OPT_INACTIVITY_PROBE}, + {"max-idle", required_argument, 0, OPT_MAX_IDLE}, + {"max-backoff", required_argument, 0, OPT_MAX_BACKOFF}, + {"listen", required_argument, 0, 'l'}, + {"monitor", required_argument, 0, 'm'}, + {"rate-limit", optional_argument, 0, OPT_RATE_LIMIT}, + {"burst-limit", required_argument, 0, OPT_BURST_LIMIT}, + {"stp", no_argument, 0, OPT_STP}, + {"no-stp", no_argument, 0, OPT_NO_STP}, + {"out-of-band", no_argument, 0, OPT_OUT_OF_BAND}, + {"in-band", no_argument, 0, OPT_IN_BAND}, + {"emerg-flow", no_argument, 0, OPT_EMERG_FLOW}, + {"verbose", optional_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + DAEMON_LONG_OPTIONS, + VLOG_LONG_OPTIONS, + LEAK_CHECKER_LONG_OPTIONS, +#ifdef HAVE_OPENSSL + VCONN_SSL_LONG_OPTIONS + {"bootstrap-ca-cert", required_argument, 0, OPT_BOOTSTRAP_CA_CERT}, +#endif + {0, 0, 0, 0}, + }; + char *short_options = long_options_to_short_options(long_options); + char *accept_re = NULL; + int retval; + + /* Set defaults that we can figure out before parsing options. */ + s->n_listeners = 0; + s->monitor_name = NULL; + s->fail_mode = FAIL_OPEN; + s->max_idle = 15; + s->probe_interval = 15; + s->max_backoff = 15; + s->update_resolv_conf = true; + s->rate_limit = 0; + s->burst_limit = 0; + s->enable_stp = false; + s->in_band = true; + s->emerg_flow = false; + for (;;) { + int c; + + c = getopt_long(argc, argv, short_options, long_options, NULL); + if (c == -1) { + break; + } + + switch (c) { + case OPT_ACCEPT_VCONN: + accept_re = optarg[0] == '^' ? optarg : xasprintf("^%s", optarg); + break; + + case OPT_NO_RESOLV_CONF: + s->update_resolv_conf = false; + break; + + case 'F': + if (!strcmp(optarg, "open")) { + s->fail_mode = FAIL_OPEN; + } else if (!strcmp(optarg, "closed")) { + s->fail_mode = FAIL_CLOSED; + } else { + ofp_fatal(0, "-f or --fail argument must be \"open\" " + "or \"closed\""); + } + break; + + case OPT_INACTIVITY_PROBE: + s->probe_interval = atoi(optarg); + if (s->probe_interval < 1) { + ofp_fatal(0, "--inactivity-probe argument must be at least 1"); + } + break; + + case OPT_MAX_IDLE: + if (!strcmp(optarg, "permanent")) { + s->max_idle = OFP_FLOW_PERMANENT; + } else { + s->max_idle = atoi(optarg); + if (s->max_idle < 1 || s->max_idle > 65535) { + ofp_fatal(0, "--max-idle argument must be between 1 and " + "65535 or the word 'permanent'"); + } + } + break; + + case OPT_MAX_BACKOFF: + s->max_backoff = atoi(optarg); + if (s->max_backoff < 1) { + ofp_fatal(0, "--max-backoff argument must be at least 1"); + } else if (s->max_backoff > 3600) { + s->max_backoff = 3600; + } + break; + + case OPT_RATE_LIMIT: + if (optarg) { + s->rate_limit = atoi(optarg); + if (s->rate_limit < 1) { + ofp_fatal(0, "--rate-limit argument must be at least 1"); + } + } else { + s->rate_limit = 1000; + } + break; + + case OPT_BURST_LIMIT: + s->burst_limit = atoi(optarg); + if (s->burst_limit < 1) { + ofp_fatal(0, "--burst-limit argument must be at least 1"); + } + break; + + case OPT_STP: + s->enable_stp = true; + break; + + case OPT_NO_STP: + s->enable_stp = false; + break; + + case OPT_OUT_OF_BAND: + s->in_band = false; + break; + + case OPT_IN_BAND: + s->in_band = true; + break; + + case OPT_EMERG_FLOW: + s->emerg_flow = true; + break; + + case 'l': + if (s->n_listeners >= MAX_MGMT) { + ofp_fatal(0, + "-l or --listen may be specified at most %d times", + MAX_MGMT); + } + s->listener_names[s->n_listeners++] = optarg; + break; + + case 'm': + if (s->monitor_name) { + ofp_fatal(0, "-m or --monitor may only be specified once"); + } + s->monitor_name = optarg; + break; + + case 'h': + usage(); + + case 'V': + printf("%s %s compiled "__DATE__" "__TIME__"\n", + program_name, VERSION BUILDNR); + exit(EXIT_SUCCESS); + + DAEMON_OPTION_HANDLERS + + VLOG_OPTION_HANDLERS + + LEAK_CHECKER_OPTION_HANDLERS + +#ifdef HAVE_OPENSSL + VCONN_SSL_OPTION_HANDLERS + + case OPT_BOOTSTRAP_CA_CERT: + vconn_ssl_set_ca_cert_file(optarg, true); + break; +#endif + + case '?': + exit(EXIT_FAILURE); + + default: + abort(); + } + } + free(short_options); + + argc -= optind; + argv += optind; + if (argc < 1 || argc > 2) { + ofp_fatal(0, "need one or two non-option arguments; " + "use --help for usage"); + } + + /* Local and remote vconns. */ + s->dp_name = argv[0]; + { + char *curr; + char *save; + int i; + + s->num_controllers = 0; + for (i = 0; i < MAX_CONTROLLERS; ++i) + s->controller_names[i] = NULL; + if (argc > 1) { + for (curr = strtok_r(argv[1], ",,", &save), i = 0; + curr && i < MAX_CONTROLLERS; + curr = strtok_r(NULL, ",,", &save), ++i) { + s->controller_names[i] = xstrdup(curr); + ++s->num_controllers; + } + } + } + + /* Set accept_controller_regex. */ + if (!accept_re) { + accept_re = vconn_ssl_is_configured() ? "^ssl:.*" : ".*"; + } + retval = regcomp(&s->accept_controller_regex, accept_re, + REG_NOSUB | REG_EXTENDED); + if (retval) { + size_t length = regerror(retval, &s->accept_controller_regex, NULL, 0); + char *buffer = xmalloc(length); + regerror(retval, &s->accept_controller_regex, buffer, length); + ofp_fatal(0, "%s: %s", accept_re, buffer); + } + s->accept_controller_re = accept_re; + + /* Mode of operation. */ + s->discovery = s->controller_names[0] == NULL; + if (s->discovery && !s->in_band) { + ofp_fatal(0, "Cannot perform discovery with out-of-band control"); + } + + /* Rate limiting. */ + if (s->rate_limit) { + if (s->rate_limit < 100) { + VLOG_WARN("Rate limit set to unusually low value %d", + s->rate_limit); + } + if (!s->burst_limit) { + s->burst_limit = s->rate_limit / 4; + } + s->burst_limit = MAX(s->burst_limit, 1); + s->burst_limit = MIN(s->burst_limit, INT_MAX / 1000); + } +} + +static void +usage(void) +{ + printf("%s: secure channel, a relay for OpenFlow messages.\n" + "usage: %s [OPTIONS] DATAPATH [CONTROLLER]\n" + "DATAPATH is an active connection method to a local datapath.\n" + "CONTROLLER is an active OpenFlow connection method; if it is\n" + "omitted, then secchan performs controller discovery.\n", + program_name, program_name); + vconn_usage(true, true, true); + printf("\nController discovery options:\n" + " --accept-vconn=REGEX accept matching discovered controllers\n" + " --no-resolv-conf do not update /etc/resolv.conf\n" + "\nNetworking options:\n" + " -F, --fail=open|closed when controller connection fails:\n" + " closed: drop all packets\n" + " open (default): act as learning switch\n" + " --inactivity-probe=SECS time between inactivity probes\n" + " --max-idle=SECS max idle for flows set up by secchan\n" + " --max-backoff=SECS max time between controller connection\n" + " attempts (default: 15 seconds)\n" + " -l, --listen=METHOD allow management connections on METHOD\n" + " (a passive OpenFlow connection method)\n" + " -m, --monitor=METHOD copy traffic to/from kernel to METHOD\n" + " (a passive OpenFlow connection method)\n" + " --out-of-band controller connection is out-of-band\n" + " --stp enable 802.1D Spanning Tree Protocol\n" + " --no-stp disable 802.1D Spanning Tree Protocol\n" + " --emerg-flow enable emergency flow protection/restoration\n" + "\nRate-limiting of \"packet-in\" messages to the controller:\n" + " --rate-limit[=PACKETS] max rate, in packets/s (default: 1000)\n" + " --burst-limit=BURST limit on packet credit for idle time\n", + ofp_pkgdatadir); + daemon_usage(); + vlog_usage(); + printf("\nOther options:\n" + " -h, --help display this help message\n" + " -V, --version display version information\n"); + leak_checker_usage(); + exit(EXIT_SUCCESS); +} diff --git a/openflow/secchan/secchan.h b/openflow/secchan/secchan.h new file mode 100644 index 00000000..7f89e2ef --- /dev/null +++ b/openflow/secchan/secchan.h @@ -0,0 +1,135 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#ifndef SECCHAN_H +#define SECCHAN_H 1 + +#include +#include +#include +#include "list.h" +#include "packets.h" + +struct secchan; + +/* Behavior when the connection to the controller fails. */ +enum fail_mode { + FAIL_OPEN, /* Act as learning switch. */ + FAIL_CLOSED /* Drop all packets. */ +}; + +/* Maximum number of management connection listeners. */ +#define MAX_MGMT 8 + +#define MAX_CONTROLLERS 3 + +/* Settings that may be configured by the user. */ +struct settings { + /* Overall mode of operation. */ + bool discovery; /* Discover the controller automatically? */ + bool in_band; /* Connect to controller in-band? */ + + /* Related vconns and network devices. */ + const char *dp_name; /* Local datapath. */ + int num_controllers; /* Number of configured controllers. */ + const char *controller_names[MAX_CONTROLLERS]; /* Controllers (if not discovery mode). */ + const char *listener_names[MAX_MGMT]; /* Listen for mgmt connections. */ + size_t n_listeners; /* Number of mgmt connection listeners. */ + const char *monitor_name; /* Listen for traffic monitor connections. */ + + /* Failure behavior. */ + enum fail_mode fail_mode; /* Act as learning switch if no controller? */ + int max_idle; /* Idle time for flows in fail-open mode. */ + int probe_interval; /* # seconds idle before sending echo request. */ + int max_backoff; /* Max # seconds between connection attempts. */ + + /* Packet-in rate-limiting. */ + int rate_limit; /* Tokens added to bucket per second. */ + int burst_limit; /* Maximum number token bucket size. */ + + /* Discovery behavior. */ + regex_t accept_controller_regex; /* Controller vconns to accept. */ + const char *accept_controller_re; /* String version of regex. */ + bool update_resolv_conf; /* Update /etc/resolv.conf? */ + + /* Spanning tree protocol. */ + bool enable_stp; + + /* Emergency flow protection/restoration behavior. */ + bool emerg_flow; +}; + +struct half { + struct rconn *rconn; + struct ofpbuf *rxbuf; + int n_txq; /* No. of packets queued for tx on 'rconn'. */ +}; + +struct relay { + struct list node; + +#define HALF_LOCAL 0 +#define HALF_REMOTE 1 + struct half halves[2]; + + /* The secchan has a primary connection (relay) to an OpenFlow controller. + * This primary connection actually makes two connections to the datapath: + * one for OpenFlow requests and responses, and one that is only used for + * receiving asynchronous events such as 'ofp_packet_in' events. This + * design keeps replies to OpenFlow requests from being dropped by the + * kernel due to a flooded network device. + * + * The secchan may also have any number of secondary "management" + * connections (relays). These connections do not receive asychronous + * events and thus have a null 'async_rconn'. */ + bool is_mgmt_conn; /* Is this a management connection? */ + struct rconn *async_rconn; /* For receiving asynchronous events. */ +}; + +struct hook_class { + bool (*local_packet_cb)(struct relay *, void *aux); + bool (*remote_packet_cb)(struct relay *, void *aux); + void (*periodic_cb)(void *aux); + void (*wait_cb)(void *aux); + void (*closing_cb)(struct relay *, void *aux); +}; + +void add_hook(struct secchan *, const struct hook_class *, void *); + +struct ofp_packet_in *get_ofp_packet_in(struct relay *); +bool get_ofp_packet_eth_header(struct relay *, struct ofp_packet_in **, + struct eth_header **); +void get_ofp_packet_payload(struct ofp_packet_in *, struct ofpbuf *); + + +#endif /* secchan.h */ diff --git a/openflow/secchan/status.c b/openflow/secchan/status.c new file mode 100644 index 00000000..cf228123 --- /dev/null +++ b/openflow/secchan/status.c @@ -0,0 +1,230 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include "status.h" +#include +#include +#include +#include +#include "dynamic-string.h" +#include "openflow/nicira-ext.h" +#include "ofpbuf.h" +#include "openflow/openflow.h" +#include "rconn.h" +#include "timeval.h" +#include "vconn.h" + +#define THIS_MODULE VLM_status +#include "vlog.h" + +struct switch_status_category { + char *name; + void (*cb)(struct status_reply *, void *aux); + void *aux; +}; + +struct switch_status { + const struct settings *s; + time_t booted; + struct switch_status_category *categories; + size_t n_categories, allocated_categories; +}; + +struct status_reply { + struct switch_status_category *category; + struct ds request; + struct ds output; +}; + +static bool +switch_status_remote_packet_cb(struct relay *r, void *ss_) +{ + struct switch_status *ss = ss_; + struct rconn *rc = r->halves[HALF_REMOTE].rconn; + struct ofpbuf *msg = r->halves[HALF_REMOTE].rxbuf; + struct switch_status_category *c; + struct nicira_header *request; + struct nicira_header *reply; + struct status_reply sr; + struct ofpbuf *b; + int retval; + + if (msg->size < sizeof(struct nicira_header)) { + return false; + } + request = msg->data; + if (request->header.type != OFPT_VENDOR + || request->vendor != htonl(NX_VENDOR_ID) + || request->subtype != htonl(NXT_STATUS_REQUEST)) { + return false; + } + + sr.request.string = (void *) (request + 1); + sr.request.length = msg->size - sizeof *request; + ds_init(&sr.output); + for (c = ss->categories; c < &ss->categories[ss->n_categories]; c++) { + if (!memcmp(c->name, sr.request.string, + MIN(strlen(c->name), sr.request.length))) { + sr.category = c; + c->cb(&sr, c->aux); + } + } + reply = make_openflow_xid(sizeof *reply + sr.output.length, + OFPT_VENDOR, request->header.xid, &b); + reply->vendor = htonl(NX_VENDOR_ID); + reply->subtype = htonl(NXT_STATUS_REPLY); + memcpy(reply + 1, sr.output.string, sr.output.length); + retval = rconn_send(rc, b, NULL); + if (retval && retval != EAGAIN) { + VLOG_WARN("send failed (%s)", strerror(retval)); + } + ds_destroy(&sr.output); + return true; +} + +void +rconn_status_cb(struct status_reply *sr, void *rconn_) +{ + struct rconn *rconn = rconn_; + time_t now = time_now(); + + status_reply_put(sr, "name=%s", rconn_get_name(rconn)); + status_reply_put(sr, "state=%s", rconn_get_state(rconn)); + status_reply_put(sr, "backoff=%d", rconn_get_backoff(rconn)); + status_reply_put(sr, "is-connected=%s", + rconn_is_connected(rconn) ? "true" : "false"); + status_reply_put(sr, "sent-msgs=%u", rconn_packets_sent(rconn)); + status_reply_put(sr, "received-msgs=%u", rconn_packets_received(rconn)); + status_reply_put(sr, "attempted-connections=%u", + rconn_get_attempted_connections(rconn)); + status_reply_put(sr, "successful-connections=%u", + rconn_get_successful_connections(rconn)); + status_reply_put(sr, "last-connection=%ld", + (long int) (now - rconn_get_last_connection(rconn))); + status_reply_put(sr, "time-connected=%lu", + rconn_get_total_time_connected(rconn)); + status_reply_put(sr, "state-elapsed=%u", rconn_get_state_elapsed(rconn)); +} + +static void +config_status_cb(struct status_reply *sr, void *s_) +{ + const struct settings *s = s_; + size_t i; + + for (i = 0; i < s->n_listeners; i++) { + status_reply_put(sr, "management%zu=%s", i, s->listener_names[i]); + } + if (s->probe_interval) { + status_reply_put(sr, "probe-interval=%d", s->probe_interval); + } + if (s->max_backoff) { + status_reply_put(sr, "max-backoff=%d", s->max_backoff); + } +} + +static void +switch_status_cb(struct status_reply *sr, void *ss_) +{ + struct switch_status *ss = ss_; + time_t now = time_now(); + + status_reply_put(sr, "now=%ld", (long int) now); + status_reply_put(sr, "uptime=%ld", (long int) (now - ss->booted)); + status_reply_put(sr, "pid=%ld", (long int) getpid()); +} + +static struct hook_class switch_status_hook_class = { + NULL, /* local_packet_cb */ + switch_status_remote_packet_cb, /* remote_packet_cb */ + NULL, /* periodic_cb */ + NULL, /* wait_cb */ + NULL, /* closing_cb */ +}; + +void +switch_status_start(struct secchan *secchan, const struct settings *s, + struct switch_status **ssp) +{ + struct switch_status *ss = xcalloc(1, sizeof *ss); + ss->s = s; + ss->booted = time_now(); + switch_status_register_category(ss, "config", + config_status_cb, (void *) s); + switch_status_register_category(ss, "switch", switch_status_cb, ss); + *ssp = ss; + add_hook(secchan, &switch_status_hook_class, ss); +} + +void +switch_status_register_category(struct switch_status *ss, + const char *category, + void (*cb)(struct status_reply *, void *aux), + void *aux) +{ + struct switch_status_category *c; + if (ss->n_categories >= ss->allocated_categories) { + ss->categories = x2nrealloc(ss->categories, &ss->allocated_categories, + sizeof *ss->categories); + } + c = &ss->categories[ss->n_categories++]; + c->cb = cb; + c->aux = aux; + c->name = xstrdup(category); +} + +void +status_reply_put(struct status_reply *sr, const char *content, ...) +{ + size_t old_length = sr->output.length; + size_t added; + va_list args; + + /* Append the status reply to the output. */ + ds_put_format(&sr->output, "%s.", sr->category->name); + va_start(args, content); + ds_put_format_valist(&sr->output, content, args); + va_end(args); + if (ds_last(&sr->output) != '\n') { + ds_put_char(&sr->output, '\n'); + } + + /* Drop what we just added if it doesn't match the request. */ + added = sr->output.length - old_length; + if (added < sr->request.length + || memcmp(&sr->output.string[old_length], + sr->request.string, sr->request.length)) { + ds_truncate(&sr->output, old_length); + } +} diff --git a/openflow/secchan/status.h b/openflow/secchan/status.h new file mode 100644 index 00000000..68793eff --- /dev/null +++ b/openflow/secchan/status.h @@ -0,0 +1,56 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#ifndef STATUS_H +#define STATUS_H 1 + +#include "secchan.h" + +struct secchan; +struct status_reply; +struct switch_status; + +void switch_status_start(struct secchan *, const struct settings *, + struct switch_status **); +void switch_status_register_category(struct switch_status *, + const char *category, + void (*cb)(struct status_reply *, + void *aux), + void *aux); + +void status_reply_put(struct status_reply *, const char *, ...) + PRINTF_FORMAT(2, 3); + +void rconn_status_cb(struct status_reply *, void *rconn_); + +#endif /* status.h */ diff --git a/openflow/secchan/stp-secchan.c b/openflow/secchan/stp-secchan.c new file mode 100644 index 00000000..152595e9 --- /dev/null +++ b/openflow/secchan/stp-secchan.c @@ -0,0 +1,293 @@ +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include "stp-secchan.h" +#include +#include +#include "flow.h" +#include "secchan.h" +#include "ofpbuf.h" +#include "openflow/openflow.h" +#include "poll-loop.h" +#include "port-watcher.h" +#include "rconn.h" +#include "stp.h" +#include "timeval.h" +#include "vconn.h" + +#define THIS_MODULE VLM_stp_secchan +#include "vlog.h" + +struct stp_data { + struct stp *stp; + struct port_watcher *pw; + struct rconn *local_rconn; + struct rconn *remote_rconn; + long long int last_tick; + int n_txq; +}; + +static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60); + +static bool +stp_local_packet_cb(struct relay *r, void *stp_) +{ + struct ofpbuf *msg = r->halves[HALF_LOCAL].rxbuf; + struct ofp_header *oh; + struct stp_data *stp = stp_; + struct ofp_packet_in *opi; + struct eth_header *eth; + struct llc_header *llc; + struct ofpbuf payload; + uint16_t port_no; + struct flow flow; + + oh = msg->data; + if (oh->type == OFPT_FEATURES_REPLY + && msg->size >= offsetof(struct ofp_switch_features, ports)) { + struct ofp_switch_features *osf = msg->data; + osf->capabilities |= htonl(OFPC_STP); + return false; + } + + if (!get_ofp_packet_eth_header(r, &opi, ð) + || !eth_addr_equals(eth->eth_dst, stp_eth_addr)) { + return false; + } + + port_no = ntohs(opi->in_port); + if (port_no >= STP_MAX_PORTS) { + /* STP only supports 255 ports. */ + return false; + } + if (port_watcher_get_config(stp->pw, port_no) & OFPPC_NO_STP) { + /* We're not doing STP on this port. */ + return false; + } + + if (opi->reason == OFPR_ACTION) { + /* The controller set up a flow for this, so we won't intercept it. */ + return false; + } + + get_ofp_packet_payload(opi, &payload); + flow_extract(&payload, port_no, &flow); + if (flow.dl_type != htons(OFP_DL_TYPE_NOT_ETH_TYPE)) { + VLOG_DBG("non-LLC frame received on STP multicast address"); + return false; + } + llc = ofpbuf_at_assert(&payload, sizeof *eth, sizeof *llc); + if (llc->llc_dsap != STP_LLC_DSAP) { + VLOG_DBG("bad DSAP 0x%02"PRIx8" received on STP multicast address", + llc->llc_dsap); + return false; + } + + /* Trim off padding on payload. */ + if (payload.size > ntohs(eth->eth_type) + ETH_HEADER_LEN) { + payload.size = ntohs(eth->eth_type) + ETH_HEADER_LEN; + } + if (ofpbuf_try_pull(&payload, ETH_HEADER_LEN + LLC_HEADER_LEN)) { + struct stp_port *p = stp_get_port(stp->stp, port_no); + stp_received_bpdu(p, payload.data, payload.size); + } + + return true; +} + +static void +stp_periodic_cb(void *stp_) +{ + struct stp_data *stp = stp_; + long long int now = time_msec(); + long long int elapsed = now - stp->last_tick; + struct stp_port *p; + + if (!port_watcher_is_ready(stp->pw)) { + /* Can't start STP until we know port flags, because port flags can + * disable STP. */ + return; + } + if (elapsed <= 0) { + return; + } + + stp_tick(stp->stp, MIN(INT_MAX, elapsed)); + stp->last_tick = now; + + while (stp_get_changed_port(stp->stp, &p)) { + int port_no = stp_port_no(p); + enum stp_state s_state = stp_port_get_state(p); + + if (s_state != STP_DISABLED) { + VLOG_INFO("STP: Port %d entered %s state", + port_no, stp_state_name(s_state)); + } + if (!(port_watcher_get_config(stp->pw, port_no) & OFPPC_NO_STP)) { + uint32_t p_config = 0; + uint32_t p_state; + switch (s_state) { + case STP_LISTENING: + p_state = OFPPS_STP_LISTEN; + break; + case STP_LEARNING: + p_state = OFPPS_STP_LEARN; + break; + case STP_DISABLED: + case STP_FORWARDING: + p_state = OFPPS_STP_FORWARD; + break; + case STP_BLOCKING: + p_state = OFPPS_STP_BLOCK; + break; + default: + VLOG_DBG_RL(&rl, "STP: Port %d has bad state %x", + port_no, s_state); + p_state = OFPPS_STP_FORWARD; + break; + } + if (!stp_forward_in_state(s_state)) { + p_config = OFPPC_NO_FLOOD; + } + port_watcher_set_flags(stp->pw, port_no, + p_config, OFPPC_NO_FLOOD, + p_state, OFPPS_STP_MASK); + } else { + /* We don't own those flags. */ + } + } +} + +static void +stp_wait_cb(void *stp_ UNUSED) +{ + poll_timer_wait(1000); +} + +static void +send_bpdu(struct ofpbuf *pkt, int port_no, void *stp_) +{ + struct stp_data *stp = stp_; + const uint8_t *port_mac = port_watcher_get_hwaddr(stp->pw, port_no); + if (port_mac) { + struct eth_header *eth = pkt->l2; + struct ofpbuf *opo; + + memcpy(eth->eth_src, port_mac, ETH_ADDR_LEN); + opo = make_unbuffered_packet_out(pkt, OFPP_NONE, port_no); + + rconn_send_with_limit(stp->local_rconn, opo, &stp->n_txq, OFPP_MAX); + } else { + VLOG_WARN_RL(&rl, "cannot send BPDU on missing port %d", port_no); + } + ofpbuf_delete(pkt); +} + +static bool +stp_is_port_supported(uint16_t port_no) +{ + return port_no < STP_MAX_PORTS; +} + +static void +stp_port_changed_cb(uint16_t port_no, + const struct ofp_phy_port *old UNUSED, + const struct ofp_phy_port *new, + void *stp_) +{ + struct stp_data *stp = stp_; + struct stp_port *p; + + if (!stp_is_port_supported(port_no)) { + return; + } + + p = stp_get_port(stp->stp, port_no); + if (!new + || new->config & htonl(OFPPC_NO_STP | OFPPC_PORT_DOWN) + || new->state & htonl(OFPPS_LINK_DOWN)) { + stp_port_disable(p); + } else { + int speed = 0; + stp_port_enable(p); + if (new->curr & (OFPPF_10MB_HD | OFPPF_10MB_FD)) { + speed = 10; + } else if (new->curr & (OFPPF_100MB_HD | OFPPF_100MB_FD)) { + speed = 100; + } else if (new->curr & (OFPPF_1GB_HD | OFPPF_1GB_FD)) { + speed = 1000; + } else if (new->curr & OFPPF_10GB_FD) { + speed = 10000; + } + stp_port_set_speed(p, speed); + } +} + +static void +stp_local_port_changed_cb(const struct ofp_phy_port *port, void *stp_) +{ + struct stp_data *stp = stp_; + if (port) { + stp_set_bridge_id(stp->stp, eth_addr_to_uint64(port->hw_addr)); + } +} + +static struct hook_class stp_hook_class = { + stp_local_packet_cb, /* local_packet_cb */ + NULL, /* remote_packet_cb */ + stp_periodic_cb, /* periodic_cb */ + stp_wait_cb, /* wait_cb */ + NULL, /* closing_cb */ +}; + +void +stp_start(struct secchan *secchan, struct port_watcher *pw, + struct rconn *local, struct rconn *remote) +{ + uint8_t dpid[ETH_ADDR_LEN]; + struct stp_data *stp; + + stp = xcalloc(1, sizeof *stp); + eth_addr_random(dpid); + stp->stp = stp_create("stp", eth_addr_to_uint64(dpid), send_bpdu, stp); + stp->pw = pw; + stp->local_rconn = local; + stp->remote_rconn = remote; + stp->last_tick = time_msec(); + + port_watcher_register_callback(pw, stp_port_changed_cb, stp); + port_watcher_register_local_port_callback(pw, stp_local_port_changed_cb, + stp); + add_hook(secchan, &stp_hook_class, stp); +} diff --git a/openflow/secchan/stp-secchan.h b/openflow/secchan/stp-secchan.h new file mode 100644 index 00000000..2d1105f7 --- /dev/null +++ b/openflow/secchan/stp-secchan.h @@ -0,0 +1,48 @@ +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#ifndef STP_SECCHAN_H +#define STP_SECCHAN_H 1 + +/* Extra time, in seconds, at boot before going into fail-open, to give the + * spanning tree protocol time to figure out the network layout. */ +#define STP_EXTRA_BOOT_TIME 30 + +struct port_watcher; +struct rconn; +struct secchan; + +void stp_start(struct secchan *, struct port_watcher *, + struct rconn *local, struct rconn *remote); + +#endif /* stp-secchan.h */ diff --git a/openflow/soexpand.pl b/openflow/soexpand.pl new file mode 100755 index 00000000..4e130056 --- /dev/null +++ b/openflow/soexpand.pl @@ -0,0 +1,26 @@ +use strict; +use warnings; +use Getopt::Long; + +my ($exit_code) = 0; +my (@include_dirs); +Getopt::Long::Configure ("bundling"); +GetOptions("I|include=s" => \@include_dirs) or exit(1); +@include_dirs = ('.') if !@include_dirs; +OUTER: while () { + if (my ($name) = /^\.so (\S+)$/) { + foreach my $dir (@include_dirs, '.') { + if (open(INNER, "$dir/$name")) { + while () { + print $_; + } + close(INNER); + next OUTER; + } + } + print STDERR "$name not found in: ", join(' ', @include_dirs), "\n"; + $exit_code = 1; + } + print $_; +} +exit $exit_code; diff --git a/openflow/tests/.dirstamp b/openflow/tests/.dirstamp new file mode 100644 index 00000000..e69de29b diff --git a/openflow/tests/.gitignore b/openflow/tests/.gitignore new file mode 100644 index 00000000..3e44d9e7 --- /dev/null +++ b/openflow/tests/.gitignore @@ -0,0 +1,6 @@ +/Makefile +/Makefile.in +/test-list +/test-dhcp-client +/test-stp +/test-type-props diff --git a/openflow/tests/automake.mk b/openflow/tests/automake.mk new file mode 100644 index 00000000..a4e945a9 --- /dev/null +++ b/openflow/tests/automake.mk @@ -0,0 +1,46 @@ +TESTS += tests/test-flows.sh +noinst_PROGRAMS += tests/test-flows +tests_test_flows_SOURCES = tests/test-flows.c +tests_test_flows_LDADD = lib/libopenflow.a +dist_check_SCRIPTS = tests/test-flows.sh tests/flowgen.pl + +TESTS += tests/test-hmap +noinst_PROGRAMS += tests/test-hmap +tests_test_hmap_SOURCES = tests/test-hmap.c +tests_test_hmap_LDADD = lib/libopenflow.a + +TESTS += tests/test-list +noinst_PROGRAMS += tests/test-list +tests_test_list_SOURCES = tests/test-list.c +tests_test_list_LDADD = lib/libopenflow.a + +TESTS += tests/test-type-props +noinst_PROGRAMS += tests/test-type-props +tests_test_type_props_SOURCES = tests/test-type-props.c + +noinst_PROGRAMS += tests/test-dhcp-client +tests_test_dhcp_client_SOURCES = tests/test-dhcp-client.c +tests_test_dhcp_client_LDADD = lib/libopenflow.a $(FAULT_LIBS) + +TESTS += tests/test-stp.sh +EXTRA_DIST += tests/test-stp.sh +noinst_PROGRAMS += tests/test-stp + +tests_test_stp_SOURCES = tests/test-stp.c +tests_test_stp_LDADD = lib/libopenflow.a +stp_files = \ + tests/test-stp-ieee802.1d-1998 \ + tests/test-stp-ieee802.1d-2004-fig17.4 \ + tests/test-stp-ieee802.1d-2004-fig17.6 \ + tests/test-stp-ieee802.1d-2004-fig17.7 \ + tests/test-stp-iol-op-1.1 \ + tests/test-stp-iol-op-1.4 \ + tests/test-stp-iol-op-3.1 \ + tests/test-stp-iol-op-3.3 \ + tests/test-stp-iol-io-1.1 \ + tests/test-stp-iol-io-1.2 \ + tests/test-stp-iol-io-1.4 \ + tests/test-stp-iol-io-1.5 +TESTS_ENVIRONMENT += stp_files='$(stp_files)' + +EXTRA_DIST += $(stp_files) diff --git a/openflow/tests/flowgen.pl b/openflow/tests/flowgen.pl new file mode 100755 index 00000000..eb17b2af --- /dev/null +++ b/openflow/tests/flowgen.pl @@ -0,0 +1,224 @@ +#! /usr/bin/perl + +use strict; +use warnings; + +open(FLOWS, ">&=3");# or die "failed to open fd 3 for writing: $!\n"; +open(PACKETS, ">&=4");# or die "failed to open fd 4 for writing: $!\n"; + +# Print pcap file header. +print PACKETS pack('NnnNNNN', + 0xa1b2c3d4, # magic number + 2, # major version + 4, # minor version + 0, # time zone offset + 0, # time stamp accuracy + 1518, # snaplen + 1); # Ethernet + +output(DL_HEADER => '802.2'); + +for my $dl_header qw(802.2+SNAP Ethernet) { + my %a = (DL_HEADER => $dl_header); + for my $dl_vlan qw(none zero nonzero) { + my %b = (%a, DL_VLAN => $dl_vlan); + + # Non-IP case. + output(%b, DL_TYPE => 'non-ip'); + + for my $ip_options qw(no yes) { + my %c = (%b, DL_TYPE => 'ip', IP_OPTIONS => $ip_options); + for my $ip_fragment qw(no first middle last) { + my %d = (%c, IP_FRAGMENT => $ip_fragment); + for my $tp_proto qw(TCP TCP+options UDP ICMP other) { + output(%d, TP_PROTO => $tp_proto); + } + } + } + } +} + +sub output { + my (%attrs) = @_; + + # Compose flow. + my (%flow); + $flow{DL_SRC} = "00:02:e3:0f:80:a4"; + $flow{DL_DST} = "00:1a:92:40:ac:05"; + $flow{NW_PROTO} = 0; + $flow{NW_SRC} = '0.0.0.0'; + $flow{NW_DST} = '0.0.0.0'; + $flow{TP_SRC} = 0; + $flow{TP_DST} = 0; + if (defined($attrs{DL_VLAN})) { + my (%vlan_map) = ('none' => 0xffff, + 'zero' => 0, + 'nonzero' => 0x0123); + $flow{DL_VLAN} = $vlan_map{$attrs{DL_VLAN}}; + } else { + $flow{DL_VLAN} = 0xffff; # OFP_VLAN_NONE + } + if ($attrs{DL_HEADER} eq '802.2') { + $flow{DL_TYPE} = 0x5ff; # OFP_DL_TYPE_NOT_ETH_TYPE + } elsif ($attrs{DL_TYPE} eq 'ip') { + $flow{DL_TYPE} = 0x0800; # ETH_TYPE_IP + $flow{NW_SRC} = '10.0.2.15'; + $flow{NW_DST} = '192.168.1.20'; + if ($attrs{TP_PROTO} eq 'other') { + $flow{NW_PROTO} = 42; + } elsif ($attrs{TP_PROTO} eq 'TCP' || + $attrs{TP_PROTO} eq 'TCP+options') { + $flow{NW_PROTO} = 6; # IP_TYPE_TCP + $flow{TP_SRC} = 6667; + $flow{TP_DST} = 9998; + } elsif ($attrs{TP_PROTO} eq 'UDP') { + $flow{NW_PROTO} = 17; # IP_TYPE_UDP + $flow{TP_SRC} = 1112; + $flow{TP_DST} = 2223; + } elsif ($attrs{TP_PROTO} eq 'ICMP') { + $flow{NW_PROTO} = 1; # IP_TYPE_ICMP + $flow{TP_SRC} = 8; # echo request + $flow{TP_DST} = 0; # code + } else { + die; + } + if ($attrs{IP_FRAGMENT} ne 'no') { + $flow{TP_SRC} = $flow{TP_DST} = 0; + } + } elsif ($attrs{DL_TYPE} eq 'non-ip') { + $flow{DL_TYPE} = 0x5678; + } else { + die; + } + + # Compose packet. + my $packet = ''; + $packet .= pack_ethaddr($flow{DL_DST}); + $packet .= pack_ethaddr($flow{DL_SRC}); + $packet .= pack('n', 0) if $attrs{DL_HEADER} =~ /^802.2/; + if ($attrs{DL_HEADER} eq '802.2') { + $packet .= pack('CCC', 0x42, 0x42, 0x03); # LLC for 802.1D STP. + } else { + if ($attrs{DL_HEADER} eq '802.2+SNAP') { + $packet .= pack('CCC', 0xaa, 0xaa, 0x03); # LLC for SNAP. + $packet .= pack('CCC', 0, 0, 0); # SNAP OUI. + } + if ($attrs{DL_VLAN} ne 'none') { + $packet .= pack('nn', 0x8100, $flow{DL_VLAN}); + } + $packet .= pack('n', $flow{DL_TYPE}); + if ($attrs{DL_TYPE} eq 'ip') { + my $ip = pack('CCnnnCCnNN', + (4 << 4) | 5, # version, hdrlen + 0, # type of service + 0, # total length (filled in later) + 65432, # id + 0, # frag offset + 64, # ttl + $flow{NW_PROTO}, # protocol + 0, # checksum + 0x0a00020f, # source + 0xc0a80114); # dest + if ($attrs{IP_OPTIONS} eq 'yes') { + substr($ip, 0, 1) = pack('C', (4 << 4) | 8); + $ip .= pack('CCnnnCCCx', + 130, # type + 11, # length + 0x6bc5, # top secret + 0xabcd, + 0x1234, + 1, + 2, + 3); + } + if ($attrs{IP_FRAGMENT} ne 'no') { + my (%frag_map) = ('first' => 0x2000, # more frags, ofs 0 + 'middle' => 0x2111, # more frags, ofs 0x888 + 'last' => 0x0222); # last frag, ofs 0x1110 + substr($ip, 6, 2) + = pack('n', $frag_map{$attrs{IP_FRAGMENT}}); + } + + if ($attrs{TP_PROTO} =~ '^TCP') { + my $tcp = pack('nnNNnnnn', + $flow{TP_SRC}, # source port + $flow{TP_DST}, # dest port + 87123455, # seqno + 712378912, # ackno + (5 << 12) | 0x02 | 0x10, # hdrlen, SYN, ACK + 5823, # window size + 18923, # checksum + 12893); # urgent pointer + if ($attrs{TP_PROTO} eq 'TCP+options') { + substr($tcp, 12, 2) = pack('n', (6 << 12) | 0x02 | 0x10); + $tcp .= pack('CCn', 2, 4, 1975); # MSS option + } + $tcp .= 'payload'; + $ip .= $tcp; + } elsif ($attrs{TP_PROTO} eq 'UDP') { + my $len = 15; + my $udp = pack('nnnn', $flow{TP_SRC}, $flow{TP_DST}, $len, 0); + $udp .= chr($len) while length($udp) < $len; + $ip .= $udp; + } elsif ($attrs{TP_PROTO} eq 'ICMP') { + $ip .= pack('CCnnn', + 8, # echo request + 0, # code + 0, # checksum + 736, # identifier + 931); # sequence number + } elsif ($attrs{TP_PROTO} eq 'other') { + $ip .= 'other header'; + } else { + die; + } + + substr($ip, 2, 2) = pack('n', length($ip)); + $packet .= $ip; + } + } + substr($packet, 12, 2) = pack('n', length($packet)) + if $attrs{DL_HEADER} =~ /^802.2/; + + print join(' ', map("$_=$attrs{$_}", keys(%attrs))), "\n"; + print join(' ', map("$_=$flow{$_}", keys(%flow))), "\n"; + print "\n"; + + print FLOWS pack('Nn', + 0, # wildcards + 0); # in_port + print FLOWS pack_ethaddr($flow{DL_SRC}); + print FLOWS pack_ethaddr($flow{DL_DST}); + print FLOWS pack('nnCxNNnn', + $flow{DL_VLAN}, + $flow{DL_TYPE}, + $flow{NW_PROTO}, + inet_aton($flow{NW_SRC}), + inet_aton($flow{NW_DST}), + $flow{TP_SRC}, + $flow{TP_DST}); + + print PACKETS pack('NNNN', + 0, # timestamp seconds + 0, # timestamp microseconds + length($packet), # bytes saved + length($packet)), # total length + $packet; +} + +sub pack_ethaddr { + local ($_) = @_; + my $xx = '([0-9a-fA-F][0-9a-fA-F])'; + my (@octets) = /$xx:$xx:$xx:$xx:$xx:$xx/; + @octets == 6 or die $_; + my ($out) = ''; + $out .= pack('C', hex($_)) foreach @octets; + return $out; +} + +sub inet_aton { + local ($_) = @_; + my ($a, $b, $c, $d) = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/; + defined $d or die $_; + return ($a << 24) | ($b << 16) | ($c << 8) | $d; +} diff --git a/openflow/tests/test-dhcp-client.c b/openflow/tests/test-dhcp-client.c new file mode 100644 index 00000000..f8a1f427 --- /dev/null +++ b/openflow/tests/test-dhcp-client.c @@ -0,0 +1,206 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include "dhcp-client.h" +#include +#include +#include +#include +#include "command-line.h" +#include "dhcp.h" +#include "fatal-signal.h" +#include "fault.h" +#include "poll-loop.h" +#include "util.h" +#include "vlog.h" + +/* --request-ip: IP address to request from server. If zero, then do not + * request a specific IP address. */ +static struct in_addr request_ip; + +/* --vendor-class: Vendor class string to include in request. If null, no + * vendor class string is included. */ +static const char *vendor_class; + +/* --no-resolv-conf: Update /etc/resolv.conf to match DHCP reply? */ +static bool update_resolv_conf = true; + +static void parse_options(int argc, char *argv[]); +static void usage(void); +static void release(void *cli_); +static void modify_dhcp_request(struct dhcp_msg *, void *aux); + +int +main(int argc, char *argv[]) +{ + struct dhclient *cli; + int error; + + set_program_name(argv[0]); + register_fault_handlers(); + vlog_init(); + parse_options(argc, argv); + + argc -= optind; + argv += optind; + if (argc != 1) { + ofp_fatal(0, "exactly one non-option argument required; " + "use --help for help"); + } + + error = dhclient_create(argv[0], modify_dhcp_request, NULL, NULL, &cli); + if (error) { + ofp_fatal(error, "dhclient_create failed"); + } + dhclient_init(cli, request_ip.s_addr); + fatal_signal_add_hook(release, cli, true); + + for (;;) { + fatal_signal_block(); + dhclient_run(cli); + if (dhclient_changed(cli)) { + dhclient_configure_netdev(cli); + if (update_resolv_conf) { + dhclient_update_resolv_conf(cli); + } + } + dhclient_wait(cli); + fatal_signal_unblock(); + poll_block(); + } +} + +static void +release(void *cli_) +{ + struct dhclient *cli = cli_; + dhclient_release(cli); + if (dhclient_changed(cli)) { + dhclient_configure_netdev(cli); + } +} + +static void +modify_dhcp_request(struct dhcp_msg *msg, void *aux UNUSED) +{ + if (vendor_class) { + dhcp_msg_put_string(msg, DHCP_CODE_VENDOR_CLASS, vendor_class); + } +} + +static void +parse_options(int argc, char *argv[]) +{ + enum { + OPT_REQUEST_IP = UCHAR_MAX + 1, + OPT_VENDOR_CLASS, + OPT_NO_RESOLV_CONF + }; + static struct option long_options[] = { + {"request-ip", required_argument, 0, OPT_REQUEST_IP }, + {"vendor-class", required_argument, 0, OPT_VENDOR_CLASS }, + {"no-resolv-conf", no_argument, 0, OPT_NO_RESOLV_CONF}, + {"verbose", optional_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {0, 0, 0, 0}, + }; + char *short_options = long_options_to_short_options(long_options); + + for (;;) { + int c; + + c = getopt_long(argc, argv, short_options, long_options, NULL); + if (c == -1) { + break; + } + + switch (c) { + case OPT_REQUEST_IP: + if (!inet_aton(optarg, &request_ip)) { + ofp_fatal(0, + "--request-ip argument is not a valid IP address"); + } + break; + + case OPT_VENDOR_CLASS: + vendor_class = optarg; + break; + + case OPT_NO_RESOLV_CONF: + update_resolv_conf = false; + break; + + case 'h': + usage(); + + case 'V': + printf("%s %s compiled "__DATE__" "__TIME__"\n", + program_name, VERSION BUILDNR); + exit(EXIT_SUCCESS); + + case 'v': + vlog_set_verbosity(optarg); + break; + + case '?': + exit(EXIT_FAILURE); + + default: + abort(); + } + } + free(short_options); +} + +static void +usage(void) +{ + printf("%s: standalone program for testing OpenFlow DHCP client.\n" + "usage: %s [OPTIONS] NETDEV\n" + "where NETDEV is a network device (e.g. eth0).\n" + "\nDHCP options:\n" + " --request-ip=IP request specified IP address (default:\n" + " do not request a specific IP)\n" + " --vendor-class=STRING use STRING as vendor class (default:\n" + " none); use OpenFlow to imitate secchan\n" + " --no-resolv-conf do not update /etc/resolv.conf\n", + program_name, program_name); + vlog_usage(); + printf("\nOther options:\n" + " -h, --help display this help message\n" + " -V, --version display version information\n"); + exit(EXIT_SUCCESS); +} + diff --git a/openflow/tests/test-flows b/openflow/tests/test-flows new file mode 100755 index 0000000000000000000000000000000000000000..891f9547888703c22fd04673db3fa828eceb1131 GIT binary patch literal 286976 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 +#include "flow.h" +#include +#include +#include +#include "openflow/openflow.h" +#include "timeval.h" +#include "ofpbuf.h" +#include "ofp-print.h" +#include "pcap.h" +#include "util.h" +#include "vlog.h" + +#undef NDEBUG +#include + +int +main(int argc UNUSED, char *argv[]) +{ + struct ofp_match expected_match; + FILE *flows, *pcap; + int retval; + int n = 0, errors = 0; + + set_program_name(argv[0]); + time_init(); + vlog_init(); + + flows = stdin; + pcap = fdopen(3, "rb"); + if (!pcap) { + ofp_fatal(errno, "failed to open fd 3 for reading"); + } + + retval = pcap_read_header(pcap); + if (retval) { + ofp_fatal(retval > 0 ? retval : 0, "reading pcap header failed"); + } + + while (fread(&expected_match, sizeof expected_match, 1, flows)) { + struct ofpbuf *packet; + struct ofp_match extracted_match; + struct flow flow; + + n++; + + retval = pcap_read(pcap, &packet); + if (retval == EOF) { + ofp_fatal(0, "unexpected end of file reading pcap file"); + } else if (retval) { + ofp_fatal(retval, "error reading pcap file"); + } + + flow_extract(packet, 0, &flow); + flow_fill_match(&extracted_match, &flow, 0); + + if (memcmp(&expected_match, &extracted_match, sizeof expected_match)) { + char *exp_s = ofp_match_to_string(&expected_match, 2); + char *got_s = ofp_match_to_string(&extracted_match, 2); + errors++; + printf("mismatch on packet #%d (1-based).\n", n); + printf("Packet:\n"); + ofp_print_packet(stdout, packet->data, packet->size, packet->size); + printf("Expected flow:\n%s\n", exp_s); + printf("Actually extracted flow:\n%s\n", got_s); + printf("\n"); + free(exp_s); + free(got_s); + } + + ofpbuf_delete(packet); + } + printf("checked %d packets, %d errors\n", n, errors); + return errors != 0; +} + diff --git a/openflow/tests/test-flows.sh b/openflow/tests/test-flows.sh new file mode 100755 index 00000000..0d38ad78 --- /dev/null +++ b/openflow/tests/test-flows.sh @@ -0,0 +1,9 @@ +#! /bin/sh -e +srcdir=`cd $srcdir && pwd` +trap 'rm -f flows$$ pcap$$ out$$' 0 1 2 13 15 +cd tests +"$srcdir"/tests/flowgen.pl >/dev/null 3>flows$$ 4>pcap$$ +./test-flows out$$ || true +diff -u - out$$ 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 HGyVSu&X&XL literal 0 HcmV?d00001 diff --git a/openflow/tests/test-hmap.c b/openflow/tests/test-hmap.c new file mode 100644 index 00000000..962389fa --- /dev/null +++ b/openflow/tests/test-hmap.c @@ -0,0 +1,282 @@ +/* A non-exhaustive test for some of the functions and macros declared in + * hmap.h. */ + +#include +#include "hmap.h" +#include +#include "hash.h" +#include "util.h" + +#undef NDEBUG +#include + +/* Sample hmap element. */ +struct element { + int value; + struct hmap_node node; +}; + +typedef size_t hash_func(int value); + +static int +compare_ints(const void *a_, const void *b_) +{ + const int *a = a_; + const int *b = b_; + return *a < *b ? -1 : *a > *b; +} + +/* Verifies that 'hmap' contains exactly the 'n' values in 'values'. */ +static void +check_hmap(struct hmap *hmap, const int values[], size_t n, + hash_func *hash) +{ + int *sort_values, *hmap_values; + struct element *e; + size_t i; + + /* Check that all the values are there in iteration. */ + sort_values = xmalloc(sizeof *sort_values * n); + hmap_values = xmalloc(sizeof *sort_values * n); + + i = 0; + HMAP_FOR_EACH (e, struct element, node, hmap) { + assert(i < n); + hmap_values[i++] = e->value; + } + assert(i == n); + + memcpy(sort_values, values, sizeof *sort_values * n); + qsort(sort_values, n, sizeof *sort_values, compare_ints); + qsort(hmap_values, n, sizeof *hmap_values, compare_ints); + + for (i = 0; i < n; i++) { + assert(sort_values[i] == hmap_values[i]); + } + + free(hmap_values); + free(sort_values); + + /* Check that all the values are there in lookup. */ + for (i = 0; i < n; i++) { + size_t count = 0; + + HMAP_FOR_EACH_WITH_HASH (e, struct element, node, + hash(values[i]), hmap) { + count += e->value == values[i]; + } + assert(count == 1); + } + + /* Check counters. */ + assert(hmap_is_empty(hmap) == !n); + assert(hmap_count(hmap) == n); +} + +/* Puts the 'n' values in 'values' into 'elements', and then puts those + * elements into 'hmap'. */ +static void +make_hmap(struct hmap *hmap, struct element elements[], + int values[], size_t n, hash_func *hash) +{ + size_t i; + + hmap_init(hmap); + for (i = 0; i < n; i++) { + elements[i].value = i; + hmap_insert(hmap, &elements[i].node, hash(elements[i].value)); + values[i] = i; + } +} + +static void +shuffle(int *p, size_t n) +{ + for (; n > 1; n--, p++) { + int *q = &p[rand() % n]; + int tmp = *p; + *p = *q; + *q = tmp; + } +} + +#if 0 +/* Prints the values in 'hmap', plus 'name' as a title. */ +static void +print_hmap(const char *name, struct hmap *hmap) +{ + struct element *e; + + printf("%s:", name); + HMAP_FOR_EACH (e, struct element, node, hmap) { + printf(" %d(%zu)", e->value, e->node.hash & hmap->mask); + } + printf("\n"); +} + +/* Prints the 'n' values in 'values', plus 'name' as a title. */ +static void +print_ints(const char *name, const int *values, size_t n) +{ + size_t i; + + printf("%s:", name); + for (i = 0; i < n; i++) { + printf(" %d", values[i]); + } + printf("\n"); +} +#endif + +static size_t +identity_hash(int value) +{ + return value; +} + +static size_t +good_hash(int value) +{ + const uint32_t x = value; + return hash_words(&x, 1, 0x1234abcd); +} + +static size_t +constant_hash(int value UNUSED) +{ + return 123; +} + +/* Tests basic hmap insertion and deletion. */ +static void +test_hmap_insert_delete(hash_func *hash) +{ + enum { N_ELEMS = 100 }; + + struct element elements[N_ELEMS]; + int values[N_ELEMS]; + struct hmap hmap; + size_t i; + + hmap_init(&hmap); + for (i = 0; i < N_ELEMS; i++) { + elements[i].value = i; + hmap_insert(&hmap, &elements[i].node, hash(i)); + values[i] = i; + check_hmap(&hmap, values, i + 1, hash); + } + shuffle(values, N_ELEMS); + for (i = 0; i < N_ELEMS; i++) { + hmap_remove(&hmap, &elements[values[i]].node); + check_hmap(&hmap, values + (i + 1), N_ELEMS - (i + 1), hash); + } + hmap_destroy(&hmap); +} + +/* Tests basic hmap_reserve() and hmap_shrink(). */ +static void +test_hmap_reserve_shrink(hash_func *hash) +{ + enum { N_ELEMS = 32 }; + + size_t i; + + for (i = 0; i < N_ELEMS; i++) { + struct element elements[N_ELEMS]; + int values[N_ELEMS]; + struct hmap hmap; + size_t j; + + hmap_init(&hmap); + hmap_reserve(&hmap, i); + for (j = 0; j < N_ELEMS; j++) { + elements[j].value = j; + hmap_insert(&hmap, &elements[j].node, hash(j)); + values[j] = j; + check_hmap(&hmap, values, j + 1, hash); + } + shuffle(values, N_ELEMS); + for (j = 0; j < N_ELEMS; j++) { + hmap_remove(&hmap, &elements[values[j]].node); + hmap_shrink(&hmap); + check_hmap(&hmap, values + (j + 1), N_ELEMS - (j + 1), hash); + } + hmap_destroy(&hmap); + } +} + +/* Tests that HMAP_FOR_EACH_SAFE properly allows for deletion of the current + * element of a hmap. */ +static void +test_hmap_for_each_safe(hash_func *hash) +{ + enum { MAX_ELEMS = 10 }; + size_t n; + unsigned long int pattern; + + for (n = 0; n <= MAX_ELEMS; n++) { + for (pattern = 0; pattern < 1ul << n; pattern++) { + struct element elements[MAX_ELEMS]; + int values[MAX_ELEMS]; + struct hmap hmap; + struct element *e, *next; + size_t n_remaining; + int i; + + make_hmap(&hmap, elements, values, n, hash); + + i = 0; + n_remaining = n; + HMAP_FOR_EACH_SAFE (e, next, struct element, node, &hmap) { + assert(i < n); + if (pattern & (1ul << e->value)) { + size_t j; + hmap_remove(&hmap, &e->node); + for (j = 0; ; j++) { + assert(j < n_remaining); + if (values[j] == e->value) { + values[j] = values[--n_remaining]; + break; + } + } + } + check_hmap(&hmap, values, n_remaining, hash); + i++; + } + assert(i == n); + + for (i = 0; i < n; i++) { + if (pattern & (1ul << i)) { + n_remaining++; + } + } + assert(n == n_remaining); + + hmap_destroy(&hmap); + } + } +} + +static void +run_test(void (*function)(hash_func *)) +{ + hash_func *hash_funcs[] = { identity_hash, good_hash, constant_hash }; + size_t i; + + for (i = 0; i < ARRAY_SIZE(hash_funcs); i++) { + function(hash_funcs[i]); + printf("."); + fflush(stdout); + } +} + +int +main(void) +{ + run_test(test_hmap_insert_delete); + run_test(test_hmap_for_each_safe); + run_test(test_hmap_reserve_shrink); + printf("\n"); + return 0; +} + diff --git a/openflow/tests/test-list.c b/openflow/tests/test-list.c new file mode 100644 index 00000000..62857be9 --- /dev/null +++ b/openflow/tests/test-list.c @@ -0,0 +1,159 @@ +/* A non-exhaustive test for some of the functions and macros declared in + * list.h. */ + +#include +#include "list.h" +#include + +#undef NDEBUG +#include + +/* Sample list element. */ +struct element { + int value; + struct list node; +}; + +/* Puts the 'n' values in 'values' into 'elements', and then puts those + * elements in order into 'list'. */ +static void +make_list(struct list *list, struct element elements[], + int values[], size_t n) +{ + size_t i; + + list_init(list); + for (i = 0; i < n; i++) { + elements[i].value = i; + list_push_back(list, &elements[i].node); + values[i] = i; + } +} + +/* Verifies that 'list' contains exactly the 'n' values in 'values', in the + * specified order. */ +static void +check_list(struct list *list, const int values[], size_t n) +{ + struct element *e; + size_t i; + + i = 0; + LIST_FOR_EACH (e, struct element, node, list) { + assert(i < n); + assert(e->value == values[i]); + i++; + } + assert(&e->node == list); + assert(i == n); + + i = 0; + LIST_FOR_EACH_REVERSE (e, struct element, node, list) { + assert(i < n); + assert(e->value == values[n - i - 1]); + i++; + } + assert(&e->node == list); + assert(i == n); + + assert(list_is_empty(list) == !n); + assert(list_size(list) == n); +} + +#if 0 +/* Prints the values in 'list', plus 'name' as a title. */ +static void +print_list(const char *name, struct list *list) +{ + struct element *e; + + printf("%s:", name); + LIST_FOR_EACH (e, struct element, node, list) { + printf(" %d", e->value); + } + printf("\n"); +} +#endif + +/* Tests basic list construction. */ +static void +test_list_construction(void) +{ + enum { MAX_ELEMS = 100 }; + size_t n; + + for (n = 0; n <= MAX_ELEMS; n++) { + struct element elements[MAX_ELEMS]; + int values[MAX_ELEMS]; + struct list list; + + make_list(&list, elements, values, n); + check_list(&list, values, n); + } +} + +/* Tests that LIST_FOR_EACH_SAFE properly allows for deletion of the current + * element of a list. */ +static void +test_list_for_each_safe(void) +{ + enum { MAX_ELEMS = 10 }; + size_t n; + unsigned long int pattern; + + for (n = 0; n <= MAX_ELEMS; n++) { + for (pattern = 0; pattern < 1ul << n; pattern++) { + struct element elements[MAX_ELEMS]; + int values[MAX_ELEMS]; + struct list list; + struct element *e, *next; + size_t values_idx, n_remaining; + int i; + + make_list(&list, elements, values, n); + + i = 0; + values_idx = 0; + n_remaining = n; + LIST_FOR_EACH_SAFE (e, next, struct element, node, &list) { + assert(i < n); + if (pattern & (1ul << i)) { + list_remove(&e->node); + n_remaining--; + memmove(&values[values_idx], &values[values_idx + 1], + sizeof *values * (n_remaining - values_idx)); + } else { + values_idx++; + } + check_list(&list, values, n_remaining); + i++; + } + assert(i == n); + assert(&e->node == &list); + + for (i = 0; i < n; i++) { + if (pattern & (1ul << i)) { + n_remaining++; + } + } + assert(n == n_remaining); + } + } +} + +static void +run_test(void (*function)(void)) +{ + function(); + printf("."); +} + +int +main(void) +{ + run_test(test_list_construction); + run_test(test_list_for_each_safe); + printf("\n"); + return 0; +} + diff --git a/openflow/tests/test-stp-ieee802.1d-1998 b/openflow/tests/test-stp-ieee802.1d-1998 new file mode 100644 index 00000000..f1982a03 --- /dev/null +++ b/openflow/tests/test-stp-ieee802.1d-1998 @@ -0,0 +1,12 @@ +# This is the STP example from IEEE 802.1D-1998. +bridge 0 0x42 = a b +bridge 1 0x97 = c:5 a d:5 +bridge 2 0x45 = b e +bridge 3 0x57 = b:5 e:5 +bridge 4 0x83 = a:5 e:5 +run 1000 +check 0 = root +check 1 = F F:10 F +check 2 = F:10 B +check 3 = F:5 F +check 4 = F:5 B diff --git a/openflow/tests/test-stp-ieee802.1d-2004-fig17.4 b/openflow/tests/test-stp-ieee802.1d-2004-fig17.4 new file mode 100644 index 00000000..1f708630 --- /dev/null +++ b/openflow/tests/test-stp-ieee802.1d-2004-fig17.4 @@ -0,0 +1,31 @@ +# This is the STP example from IEEE 802.1D-2004 figures 17.4 and 17.5. +bridge 0 0x111 = a b e c +bridge 1 0x222 = a b d f +bridge 2 0x333 = c d l j h g +bridge 3 0x444 = e f n m k i +bridge 4 0x555 = g i 0 0 +bridge 5 0x666 = h k 0 0 +bridge 6 0x777 = j m 0 0 +bridge 7 0x888 = l n 0 0 +run 1000 +check 0 = root +check 1 = F:10 B F F +check 2 = F:10 B F F F F +check 3 = F:10 B F F F F +check 4 = F:20 B F F +check 5 = F:20 B F F +check 6 = F:20 B F F +check 7 = F:20 B F F + +# Now connect two ports of bridge 7 to the same LAN. +bridge 7 = l n o o +# Same results except for bridge 7: +run 1000 +check 0 = root +check 1 = F:10 B F F +check 2 = F:10 B F F F F +check 3 = F:10 B F F F F +check 4 = F:20 B F F +check 5 = F:20 B F F +check 6 = F:20 B F F +check 7 = F:20 B F B diff --git a/openflow/tests/test-stp-ieee802.1d-2004-fig17.6 b/openflow/tests/test-stp-ieee802.1d-2004-fig17.6 new file mode 100644 index 00000000..6ed59177 --- /dev/null +++ b/openflow/tests/test-stp-ieee802.1d-2004-fig17.6 @@ -0,0 +1,14 @@ +# This is the STP example from IEEE 802.1D-2004 figure 17.6. +bridge 0 0x111 = a b l +bridge 1 0x222 = b c d +bridge 2 0x333 = d e f +bridge 3 0x444 = f g h +bridge 4 0x555 = j h i +bridge 5 0x666 = l j k +run 1000 +check 0 = root +check 1 = F:10 F F +check 2 = F:20 F F +check 3 = F:30 F B +check 4 = F:20 F F +check 5 = F:10 F F diff --git a/openflow/tests/test-stp-ieee802.1d-2004-fig17.7 b/openflow/tests/test-stp-ieee802.1d-2004-fig17.7 new file mode 100644 index 00000000..daa0cdf2 --- /dev/null +++ b/openflow/tests/test-stp-ieee802.1d-2004-fig17.7 @@ -0,0 +1,17 @@ +# This is the STP example from IEEE 802.1D-2004 figure 17.7. +bridge 0 0xaa = b +bridge 1 0x111 = a b d f h g e c +bridge 2 0x222 = g h j l n m k i +run 1000 +check 0 = root +check 1 = F F:10 F F F F F F +check 2 = B F:20 F F F F F F + +# This is not the port priority change described in that figure, +# but I don't understand what port priority change would cause +# that change. +bridge 2 = g X j l n m k i +run 1000 +check 0 = root +check 1 = F F:10 F F F F F F +check 2 = F:20 D F F F F F F diff --git a/openflow/tests/test-stp-iol-io-1.1 b/openflow/tests/test-stp-iol-io-1.1 new file mode 100644 index 00000000..186d6c4c --- /dev/null +++ b/openflow/tests/test-stp-iol-io-1.1 @@ -0,0 +1,25 @@ +# This test file approximates the following test from "Bridge +# Functions Consortium Spanning Tree Interoperability Test Suite +# Version 1.5": +# STP.io.1.1: Link Failure +bridge 0 0x111 = a b c +bridge 1 0x222 = a b c +run 1000 +check 0 = root +check 1 = F:10 B B +bridge 1 = 0 _ _ +run 1000 +check 0 = root +check 1 = F F:10 B +bridge 1 = X _ _ +run 1000 +check 0 = root +check 1 = D F:10 B +bridge 1 = _ 0 _ +run 1000 +check 0 = root +check 1 = D F F:10 +bridge 1 = _ X _ +run 1000 +check 0 = root +check 1 = D D F:10 diff --git a/openflow/tests/test-stp-iol-io-1.2 b/openflow/tests/test-stp-iol-io-1.2 new file mode 100644 index 00000000..285bbd88 --- /dev/null +++ b/openflow/tests/test-stp-iol-io-1.2 @@ -0,0 +1,14 @@ +# This test file approximates the following test from "Bridge +# Functions Consortium Spanning Tree Interoperability Test Suite +# Version 1.5": +# STP.io.1.2: Repeated Network +bridge 0 0x111 = a a +bridge 1 0x222 = a a +run 1000 +check 0 = rootid:0x111 F B +check 1 = rootid:0x111 F:10 B +bridge 1 = a^0x90 _ +run 1000 +check 0 = rootid:0x111 F B +check 1 = rootid:0x111 B F:10 + diff --git a/openflow/tests/test-stp-iol-io-1.4 b/openflow/tests/test-stp-iol-io-1.4 new file mode 100644 index 00000000..0065aaf5 --- /dev/null +++ b/openflow/tests/test-stp-iol-io-1.4 @@ -0,0 +1,13 @@ +# This test file approximates the following test from "Bridge +# Functions Consortium Spanning Tree Interoperability Test Suite +# Version 1.5": +# STP.io.1.4: Network Initialization +bridge 0 0x111 = a b c +bridge 1 0x222 = b d e +bridge 2 0x333 = a d f +bridge 3 0x444 = c e f +run 1000 +check 0 = root +check 1 = F:10 F F +check 2 = F:10 B F +check 3 = F:10 B B diff --git a/openflow/tests/test-stp-iol-io-1.5 b/openflow/tests/test-stp-iol-io-1.5 new file mode 100644 index 00000000..285d29de --- /dev/null +++ b/openflow/tests/test-stp-iol-io-1.5 @@ -0,0 +1,40 @@ +# This test file approximates the following test from "Bridge +# Functions Consortium Spanning Tree Interoperability Test Suite +# Version 1.5": +# STP.io.1.5: Topology Change +bridge 0 0x111 = a b d c +bridge 1 0x222 = a b f e +bridge 2 0x333 = c d g h +bridge 3 0x444 = e f g h +run 1000 +check 0 = root +check 1 = F:10 B F F +check 2 = B F:10 F F +check 3 = B F:20 B B +bridge 1^0x7000 +run 1000 +check 0 = F:10 B F F +check 1 = root +check 2 = B F:20 B B +check 3 = B F:10 F F +bridge 2^0x6000 +run 1000 +check 0 = F F B F:10 +check 1 = F:20 B B B +check 2 = root +check 3 = F F F:10 B +bridge 3^0x5000 +run 1000 +check 0 = B B B F:20 +check 1 = F F B F:10 +check 2 = F F F:10 B +check 3 = root +bridge 0^0x4000 +bridge 1^0x4001 +bridge 2^0x4002 +bridge 3^0x4003 +run 1000 +check 0 = root +check 1 = F:10 B F F +check 2 = B F:10 F F +check 3 = B F:20 B B diff --git a/openflow/tests/test-stp-iol-op-1.1 b/openflow/tests/test-stp-iol-op-1.1 new file mode 100644 index 00000000..8432bf36 --- /dev/null +++ b/openflow/tests/test-stp-iol-op-1.1 @@ -0,0 +1,7 @@ +# This test file approximates the following tests from "Bridge +# Functions Consortium Spanning Tree Protocol Operations Test Suite +# Version 2.3": +# Test STP.op.1.1 ­ Root ID Initialized to Bridge ID +# Test STP.op.1.2 ­ Root Path Cost Initialized to Zero +bridge 0 0x123 = +check 0 = root diff --git a/openflow/tests/test-stp-iol-op-1.4 b/openflow/tests/test-stp-iol-op-1.4 new file mode 100644 index 00000000..6a121164 --- /dev/null +++ b/openflow/tests/test-stp-iol-op-1.4 @@ -0,0 +1,8 @@ +# This test file approximates the following test from "Bridge +# Functions Consortium Spanning Tree Protocol Operations Test Suite +# Version 2.3": +# Test STP.op.1.4 ­ All Ports Initialized to Designated Ports +bridge 0 0x123 = a b c d e f +check 0 = Li Li Li Li Li Li +run 1000 +check 0 = F F F F F F diff --git a/openflow/tests/test-stp-iol-op-3.1 b/openflow/tests/test-stp-iol-op-3.1 new file mode 100644 index 00000000..3e1099cb --- /dev/null +++ b/openflow/tests/test-stp-iol-op-3.1 @@ -0,0 +1,11 @@ +# This test file approximates the following test from "Bridge +# Functions Consortium Spanning Tree Protocol Operations Test Suite +# Version 2.3": +# Test STP.op.3.1 ­ Root Bridge Selection: Root ID Values +bridge 0 0x111 = a +bridge 1 0x222 = a +check 0 = rootid:0x111 Li +check 1 = rootid:0x222 Li +run 1000 +check 0 = rootid:0x111 root +check 1 = rootid:0x111 F:10 diff --git a/openflow/tests/test-stp-iol-op-3.3 b/openflow/tests/test-stp-iol-op-3.3 new file mode 100644 index 00000000..2bcd45e1 --- /dev/null +++ b/openflow/tests/test-stp-iol-op-3.3 @@ -0,0 +1,11 @@ +# This test file approximates the following test from "Bridge +# Functions Consortium Spanning Tree Protocol Operations Test Suite +# Version 2.3": +# Test STP.op.3.3 ­ Root Bridge Selection: Bridge ID Values +bridge 0 0x333^0x6000 = a +bridge 1 0x222^0x7000 = b +bridge 2 0x111 = a b +run 1000 +check 0 = rootid:0x333^0x6000 root +check 1 = rootid:0x333^0x6000 F:20 +check 2 = rootid:0x333^0x6000 F:10 F diff --git a/openflow/tests/test-stp-iol-op-3.4 b/openflow/tests/test-stp-iol-op-3.4 new file mode 100644 index 00000000..2bcd45e1 --- /dev/null +++ b/openflow/tests/test-stp-iol-op-3.4 @@ -0,0 +1,11 @@ +# This test file approximates the following test from "Bridge +# Functions Consortium Spanning Tree Protocol Operations Test Suite +# Version 2.3": +# Test STP.op.3.3 ­ Root Bridge Selection: Bridge ID Values +bridge 0 0x333^0x6000 = a +bridge 1 0x222^0x7000 = b +bridge 2 0x111 = a b +run 1000 +check 0 = rootid:0x333^0x6000 root +check 1 = rootid:0x333^0x6000 F:20 +check 2 = rootid:0x333^0x6000 F:10 F diff --git a/openflow/tests/test-stp.c b/openflow/tests/test-stp.c new file mode 100644 index 00000000..ddb7db7e --- /dev/null +++ b/openflow/tests/test-stp.c @@ -0,0 +1,665 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include "stp.h" +#include +#include +#include +#include +#include +#include +#include "ofpbuf.h" +#include "packets.h" + +struct bpdu { + int port_no; + void *data; + size_t size; +}; + +struct bridge { + struct test_case *tc; + int id; + bool reached; + + struct stp *stp; + + struct lan *ports[STP_MAX_PORTS]; + int n_ports; + +#define RXQ_SIZE 16 + struct bpdu rxq[RXQ_SIZE]; + int rxq_head, rxq_tail; +}; + +struct lan_conn { + struct bridge *bridge; + int port_no; +}; + +struct lan { + struct test_case *tc; + const char *name; + bool reached; + struct lan_conn conns[16]; + int n_conns; +}; + +struct test_case { + struct bridge *bridges[16]; + int n_bridges; + struct lan *lans[26]; + int n_lans; +}; + +static const char *file_name; +static int line_number; +static char line[128]; +static char *pos, *token; +static int n_warnings; + +static struct test_case * +new_test_case(void) +{ + struct test_case *tc = xmalloc(sizeof *tc); + tc->n_bridges = 0; + tc->n_lans = 0; + return tc; +} + +static void +send_bpdu(struct ofpbuf *pkt, int port_no, void *b_) +{ + struct bridge *b = b_; + struct lan *lan; + + assert(port_no < b->n_ports); + lan = b->ports[port_no]; + if (lan) { + const void *data = pkt->l3; + size_t size = (char *) ofpbuf_tail(pkt) - (char *) data; + int i; + + for (i = 0; i < lan->n_conns; i++) { + struct lan_conn *conn = &lan->conns[i]; + if (conn->bridge != b || conn->port_no != port_no) { + struct bridge *dst = conn->bridge; + struct bpdu *bpdu = &dst->rxq[dst->rxq_head++ % RXQ_SIZE]; + assert(dst->rxq_head - dst->rxq_tail <= RXQ_SIZE); + bpdu->data = xmemdup(data, size); + bpdu->size = size; + bpdu->port_no = conn->port_no; + } + } + } + ofpbuf_delete(pkt); +} + +static struct bridge * +new_bridge(struct test_case *tc, int id) +{ + struct bridge *b = xmalloc(sizeof *b); + char name[16]; + b->tc = tc; + b->id = id; + snprintf(name, sizeof name, "stp%x", id); + b->stp = stp_create(name, id, send_bpdu, b); + assert(tc->n_bridges < ARRAY_SIZE(tc->bridges)); + b->n_ports = 0; + b->rxq_head = b->rxq_tail = 0; + tc->bridges[tc->n_bridges++] = b; + return b; +} + +static struct lan * +new_lan(struct test_case *tc, const char *name) +{ + struct lan *lan = xmalloc(sizeof *lan); + lan->tc = tc; + lan->name = xstrdup(name); + lan->n_conns = 0; + assert(tc->n_lans < ARRAY_SIZE(tc->lans)); + tc->lans[tc->n_lans++] = lan; + return lan; +} + +static void +reconnect_port(struct bridge *b, int port_no, struct lan *new_lan) +{ + struct lan *old_lan; + int j; + + assert(port_no < b->n_ports); + old_lan = b->ports[port_no]; + if (old_lan == new_lan) { + return; + } + + /* Disconnect from old_lan. */ + if (old_lan) { + for (j = 0; j < old_lan->n_conns; j++) { + struct lan_conn *c = &old_lan->conns[j]; + if (c->bridge == b && c->port_no == port_no) { + memmove(c, c + 1, sizeof *c * (old_lan->n_conns - j - 1)); + old_lan->n_conns--; + break; + } + } + } + + /* Connect to new_lan. */ + b->ports[port_no] = new_lan; + if (new_lan) { + int conn_no = new_lan->n_conns++; + assert(conn_no < ARRAY_SIZE(new_lan->conns)); + new_lan->conns[conn_no].bridge = b; + new_lan->conns[conn_no].port_no = port_no; + } +} + +static void +new_port(struct bridge *b, struct lan *lan, int path_cost) +{ + int port_no = b->n_ports++; + struct stp_port *p = stp_get_port(b->stp, port_no); + assert(port_no < ARRAY_SIZE(b->ports)); + b->ports[port_no] = NULL; + stp_port_set_path_cost(p, path_cost); + stp_port_enable(p); + reconnect_port(b, port_no, lan); +} + +static void +dump(struct test_case *tc) +{ + int i; + + for (i = 0; i < tc->n_bridges; i++) { + struct bridge *b = tc->bridges[i]; + struct stp *stp = b->stp; + int j; + + printf("%s:", stp_get_name(stp)); + if (stp_is_root_bridge(stp)) { + printf(" root"); + } + printf("\n"); + for (j = 0; j < b->n_ports; j++) { + struct stp_port *p = stp_get_port(stp, j); + enum stp_state state = stp_port_get_state(p); + + printf("\tport %d", j); + if (b->ports[j]) { + printf(" (lan %s)", b->ports[j]->name); + } else { + printf(" (disconnected)"); + } + printf(": %s", stp_state_name(state)); + if (p == stp_get_root_port(stp)) { + printf(" (root port, root_path_cost=%u)", stp_get_root_path_cost(stp)); + } + printf("\n"); + } + } +} + +static void dump_lan_tree(struct test_case *, struct lan *, int level); + +static void +dump_bridge_tree(struct test_case *tc, struct bridge *b, int level) +{ + int i; + + if (b->reached) { + return; + } + b->reached = true; + for (i = 0; i < level; i++) { + printf("\t"); + } + printf("%s\n", stp_get_name(b->stp)); + for (i = 0; i < b->n_ports; i++) { + struct lan *lan = b->ports[i]; + struct stp_port *p = stp_get_port(b->stp, i); + if (stp_port_get_state(p) == STP_FORWARDING && lan) { + dump_lan_tree(tc, lan, level + 1); + } + } +} + +static void +dump_lan_tree(struct test_case *tc, struct lan *lan, int level) +{ + int i; + + if (lan->reached) { + return; + } + lan->reached = true; + for (i = 0; i < level; i++) { + printf("\t"); + } + printf("%s\n", lan->name); + for (i = 0; i < lan->n_conns; i++) { + struct bridge *b = lan->conns[i].bridge; + dump_bridge_tree(tc, b, level + 1); + } +} + +static void +tree(struct test_case *tc) +{ + int i; + + for (i = 0; i < tc->n_bridges; i++) { + struct bridge *b = tc->bridges[i]; + b->reached = false; + } + for (i = 0; i < tc->n_lans; i++) { + struct lan *lan = tc->lans[i]; + lan->reached = false; + } + for (i = 0; i < tc->n_bridges; i++) { + struct bridge *b = tc->bridges[i]; + struct stp *stp = b->stp; + if (stp_is_root_bridge(stp)) { + dump_bridge_tree(tc, b, 0); + } + } +} + +static void +simulate(struct test_case *tc, int granularity) +{ + int time; + + for (time = 0; time < 1000 * 180; time += granularity) { + int round_trips; + int i; + + for (i = 0; i < tc->n_bridges; i++) { + stp_tick(tc->bridges[i]->stp, granularity); + } + for (round_trips = 0; round_trips < granularity; round_trips++) { + bool any = false; + for (i = 0; i < tc->n_bridges; i++) { + struct bridge *b = tc->bridges[i]; + for (; b->rxq_tail != b->rxq_head; b->rxq_tail++) { + struct bpdu *bpdu = &b->rxq[b->rxq_tail % RXQ_SIZE]; + stp_received_bpdu(stp_get_port(b->stp, bpdu->port_no), + bpdu->data, bpdu->size); + any = true; + } + } + if (!any) { + break; + } + } + } +} + +static void +err(const char *message, ...) + PRINTF_FORMAT(1, 2) + NO_RETURN; + +static void +err(const char *message, ...) +{ + va_list args; + + fprintf(stderr, "%s:%d:%td: ", file_name, line_number, pos - line); + va_start(args, message); + vfprintf(stderr, message, args); + va_end(args); + putc('\n', stderr); + + exit(EXIT_FAILURE); +} + +static void +warn(const char *message, ...) + PRINTF_FORMAT(1, 2); + +static void +warn(const char *message, ...) +{ + va_list args; + + fprintf(stderr, "%s:%d: ", file_name, line_number); + va_start(args, message); + vfprintf(stderr, message, args); + va_end(args); + putc('\n', stderr); + + n_warnings++; +} + +static bool +get_token(void) +{ + char *start; + + while (isspace((unsigned char) *pos)) { + pos++; + } + if (*pos == '\0') { + token = NULL; + return false; + } + + start = pos; + if (isalpha((unsigned char) *pos)) { + while (isalpha((unsigned char) *++pos)) { + continue; + } + } else if (isdigit((unsigned char) *pos)) { + if (*pos == '0' && (pos[1] == 'x' || pos[1] == 'X')) { + pos += 2; + while (isxdigit((unsigned char) *pos)) { + pos++; + } + } else { + while (isdigit((unsigned char) *++pos)) { + continue; + } + } + } else { + pos++; + } + + free(token); + token = xmemdup0(start, pos - start); + return true; +} + +static bool +get_int(int *intp) +{ + char *save_pos = pos; + if (token && isdigit((unsigned char) *token)) { + *intp = strtol(token, NULL, 0); + get_token(); + return true; + } else { + pos = save_pos; + return false; + } +} + +static bool +match(const char *want) +{ + if (token && !strcmp(want, token)) { + get_token(); + return true; + } else { + return false; + } +} + +static int +must_get_int(void) +{ + int x; + if (!get_int(&x)) { + err("expected integer"); + } + return x; +} + +static void +must_match(const char *want) +{ + if (!match(want)) { + err("expected \"%s\"", want); + } +} + +int +main(int argc, char *argv[]) +{ + struct test_case *tc; + FILE *input_file; + int i; + + if (argc != 2) { + ofp_fatal(0, "usage: test-stp INPUT.STP\n"); + } + file_name = argv[1]; + + input_file = fopen(file_name, "r"); + if (!input_file) { + ofp_fatal(errno, "error opening \"%s\"", file_name); + } + + tc = new_test_case(); + for (i = 0; i < 26; i++) { + char name[2]; + name[0] = 'a' + i; + name[1] = '\0'; + new_lan(tc, name); + } + + for (line_number = 1; fgets(line, sizeof line, input_file); + line_number++) + { + char *newline, *hash; + + newline = strchr(line, '\n'); + if (newline) { + *newline = '\0'; + } + hash = strchr(line, '#'); + if (hash) { + *hash = '\0'; + } + + pos = line; + if (!get_token()) { + continue; + } + if (match("bridge")) { + struct bridge *bridge; + int bridge_no, port_no; + + bridge_no = must_get_int(); + if (bridge_no < tc->n_bridges) { + bridge = tc->bridges[bridge_no]; + } else if (bridge_no == tc->n_bridges) { + bridge = new_bridge(tc, must_get_int()); + } else { + err("bridges must be numbered consecutively from 0"); + } + if (match("^")) { + stp_set_bridge_priority(bridge->stp, must_get_int()); + } + + if (match("=")) { + for (port_no = 0; port_no < STP_MAX_PORTS; port_no++) { + struct stp_port *p = stp_get_port(bridge->stp, port_no); + if (!token || match("X")) { + stp_port_disable(p); + } else if (match("_")) { + /* Nothing to do. */ + } else { + struct lan *lan; + int path_cost; + + if (!strcmp(token, "0")) { + lan = NULL; + } else if (strlen(token) == 1 && islower(*token)) { + lan = tc->lans[*token - 'a']; + } else { + err("%s is not a valid LAN name " + "(0 or a lowercase letter)", token); + } + get_token(); + + path_cost = match(":") ? must_get_int() : 10; + if (port_no < bridge->n_ports) { + stp_port_set_path_cost(p, path_cost); + stp_port_enable(p); + reconnect_port(bridge, port_no, lan); + } else if (port_no == bridge->n_ports) { + new_port(bridge, lan, path_cost); + } else { + err("ports must be numbered consecutively"); + } + if (match("^")) { + stp_port_set_priority(p, must_get_int()); + } + } + } + } + } else if (match("run")) { + simulate(tc, must_get_int()); + } else if (match("dump")) { + dump(tc); + } else if (match("tree")) { + tree(tc); + } else if (match("check")) { + struct bridge *b; + struct stp *stp; + int bridge_no, port_no; + + bridge_no = must_get_int(); + if (bridge_no >= tc->n_bridges) { + err("no bridge numbered %d", bridge_no); + } + b = tc->bridges[bridge_no]; + stp = b->stp; + + must_match("="); + + if (match("rootid")) { + uint64_t rootid; + must_match(":"); + rootid = must_get_int(); + if (match("^")) { + rootid |= (uint64_t) must_get_int() << 48; + } else { + rootid |= UINT64_C(0x8000) << 48; + } + if (stp_get_designated_root(stp) != rootid) { + warn("%s: root %"PRIx64", not %"PRIx64, + stp_get_name(stp), stp_get_designated_root(stp), + rootid); + } + } + + if (match("root")) { + if (stp_get_root_path_cost(stp)) { + warn("%s: root path cost of root is %u but should be 0", + stp_get_name(stp), stp_get_root_path_cost(stp)); + } + if (!stp_is_root_bridge(stp)) { + warn("%s: root is %"PRIx64", not %"PRIx64, + stp_get_name(stp), + stp_get_designated_root(stp), stp_get_bridge_id(stp)); + } + for (port_no = 0; port_no < b->n_ports; port_no++) { + struct stp_port *p = stp_get_port(stp, port_no); + enum stp_state state = stp_port_get_state(p); + if (!(state & (STP_DISABLED | STP_FORWARDING))) { + warn("%s: root port %d in state %s", + stp_get_name(b->stp), port_no, + stp_state_name(state)); + } + } + } else { + for (port_no = 0; port_no < STP_MAX_PORTS; port_no++) { + struct stp_port *p = stp_get_port(stp, port_no); + enum stp_state state; + if (token == NULL || match("D")) { + state = STP_DISABLED; + } else if (match("B")) { + state = STP_BLOCKING; + } else if (match("Li")) { + state = STP_LISTENING; + } else if (match("Le")) { + state = STP_LEARNING; + } else if (match("F")) { + state = STP_FORWARDING; + } else if (match("_")) { + continue; + } else { + err("unknown port state %s", token); + } + if (stp_port_get_state(p) != state) { + warn("%s port %d: state is %s but should be %s", + stp_get_name(stp), port_no, + stp_state_name(stp_port_get_state(p)), + stp_state_name(state)); + } + if (state == STP_FORWARDING) { + struct stp_port *root_port = stp_get_root_port(stp); + if (match(":")) { + int root_path_cost = must_get_int(); + if (p != root_port) { + warn("%s: port %d is not the root port", + stp_get_name(stp), port_no); + if (!root_port) { + warn("%s: (there is no root port)", + stp_get_name(stp)); + } else { + warn("%s: (port %d is the root port)", + stp_get_name(stp), + stp_port_no(root_port)); + } + } else if (root_path_cost + != stp_get_root_path_cost(stp)) { + warn("%s: root path cost is %u, should be %d", + stp_get_name(stp), + stp_get_root_path_cost(stp), + root_path_cost); + } + } else if (p == root_port) { + warn("%s: port %d is the root port but " + "not expected to be", + stp_get_name(stp), port_no); + } + } + } + } + if (n_warnings) { + exit(EXIT_FAILURE); + } + } + if (get_token()) { + err("trailing garbage on line"); + } + } + + return 0; +} diff --git a/openflow/tests/test-stp.sh b/openflow/tests/test-stp.sh new file mode 100755 index 00000000..fd6acf54 --- /dev/null +++ b/openflow/tests/test-stp.sh @@ -0,0 +1,7 @@ +#! /bin/sh +set -e +progress= +for d in ${stp_files}; do + echo "Testing $d..." + $SUPERVISOR ./tests/test-stp ${srcdir}/$d +done diff --git a/openflow/tests/test-type-props.c b/openflow/tests/test-type-props.c new file mode 100644 index 00000000..67dabae8 --- /dev/null +++ b/openflow/tests/test-type-props.c @@ -0,0 +1,41 @@ +#include +#include "type-props.h" +#include +#include + +#define MUST_SUCCEED(EXPRESSION) \ + if (!(EXPRESSION)) { \ + fprintf(stderr, "%s:%d: %s failed\n", \ + __FILE__, __LINE__, #EXPRESSION); \ + exit(EXIT_FAILURE); \ + } + +#define TEST_TYPE(type, minimum, maximum, is_signed) \ + MUST_SUCCEED(TYPE_IS_INTEGER(type)); \ + MUST_SUCCEED(TYPE_IS_SIGNED(type) == is_signed); \ + MUST_SUCCEED(TYPE_MAXIMUM(type) == maximum); \ + MUST_SUCCEED(TYPE_MINIMUM(type) == minimum); + +int +main (void) +{ + TEST_TYPE(char, CHAR_MIN, CHAR_MAX, (CHAR_MIN < 0)); + + TEST_TYPE(signed char, SCHAR_MIN, SCHAR_MAX, 1); + TEST_TYPE(short int, SHRT_MIN, SHRT_MAX, 1); + TEST_TYPE(int, INT_MIN, INT_MAX, 1); + TEST_TYPE(long int, LONG_MIN, LONG_MAX, 1); + TEST_TYPE(long long int, LLONG_MIN, LLONG_MAX, 1); + + TEST_TYPE(unsigned char, 0, UCHAR_MAX, 0); + TEST_TYPE(unsigned short int, 0, USHRT_MAX, 0); + TEST_TYPE(unsigned int, 0, UINT_MAX, 0); + TEST_TYPE(unsigned long int, 0, ULONG_MAX, 0); + TEST_TYPE(unsigned long long int, 0, ULLONG_MAX, 0); + + MUST_SUCCEED(!(TYPE_IS_INTEGER(float))); + MUST_SUCCEED(!(TYPE_IS_INTEGER(double))); + MUST_SUCCEED(!(TYPE_IS_INTEGER(long double))); + + return 0; +} diff --git a/openflow/third-party/.gitignore b/openflow/third-party/.gitignore new file mode 100644 index 00000000..b336cc7c --- /dev/null +++ b/openflow/third-party/.gitignore @@ -0,0 +1,2 @@ +/Makefile +/Makefile.in diff --git a/openflow/third-party/README b/openflow/third-party/README new file mode 100644 index 00000000..15f4d647 --- /dev/null +++ b/openflow/third-party/README @@ -0,0 +1,35 @@ +This directory contains third-party software that may be useful for +debugging. + +tcpdump +------- +The "ofp-tcpdump.patch" patch adds the ability to parse OpenFlow +messages to tcpdump. These instructions assume that tcpdump 3.9.8 +is going to be used, but it should work with other versions that are not +substantially different. To begin, download tcpdump and apply the +patch: + + wget http://www.tcpdump.org/release/tcpdump-3.9.8.tar.gz + tar xzf tcpdump-3.9.8.tar.gz + ln -s tcpdump-3.9.8 tcpdump + patch -p0 < ofp-tcpdump.patch + +Then build the new version of tcpdump: + + cd tcpdump + ./configure + make + +Clearly, tcpdump can only parse unencrypted packets, so you will need to +connect the controller and datapath using plain TCP. To look at the +traffic, tcpdump will be started in a manner similar to the following: + + sudo ./tcpdump -s0 -i eth0 port 6633 + +The "-s0" flag indicates that tcpdump should capture the entire packet. +If the OpenFlow message is not received in its entirety, "[|openflow]" will +be printed instead of the OpenFlow message contents. + +The verbosity of the output may be increased by adding additional "-v" +flags. If "-vvv" is used, the raw OpenFlow data is also printed in +hex and ASCII. diff --git a/openflow/third-party/automake.mk b/openflow/third-party/automake.mk new file mode 100644 index 00000000..02636bb5 --- /dev/null +++ b/openflow/third-party/automake.mk @@ -0,0 +1,3 @@ +EXTRA_DIST += \ + third-party/README \ + third-party/ofp-tcpdump.patch diff --git a/openflow/third-party/ofp-tcpdump.patch b/openflow/third-party/ofp-tcpdump.patch new file mode 100644 index 00000000..3f2cc57b --- /dev/null +++ b/openflow/third-party/ofp-tcpdump.patch @@ -0,0 +1,119 @@ +diff -rNu tcpdump/interface.h tcpdump/interface.h +--- tcpdump/interface.h 2007-06-13 18:03:20.000000000 -0700 ++++ tcpdump/interface.h 2008-02-06 15:06:30.000000000 -0800 +@@ -148,7 +148,8 @@ + + extern const char *dnaddr_string(u_short); + +-extern void error(const char *, ...) ++#define error(fmt, args...) tcpdump_error(fmt, ## args) ++extern void tcpdump_error(const char *, ...) + __attribute__((noreturn, format (printf, 1, 2))); + extern void warning(const char *, ...) __attribute__ ((format (printf, 1, 2))); + +@@ -176,6 +177,7 @@ + extern void hex_print_with_offset(const char *, const u_char *, u_int, u_int); + extern void hex_print(const char *, const u_char *, u_int); + extern void telnet_print(const u_char *, u_int); ++extern void openflow_print(const u_char *, u_int); + extern int ether_encap_print(u_short, const u_char *, u_int, u_int, u_short *); + extern int llc_print(const u_char *, u_int, u_int, const u_char *, + const u_char *, u_short *); +diff -rNu tcpdump/Makefile.in tcpdump/Makefile.in +--- tcpdump/Makefile.in 2007-09-25 18:59:52.000000000 -0700 ++++ tcpdump/Makefile.in 2008-02-07 11:46:03.000000000 -0800 +@@ -49,10 +49,10 @@ + CFLAGS = $(CCOPT) $(DEFS) $(INCLS) + + # Standard LDFLAGS +-LDFLAGS = @LDFLAGS@ ++LDFLAGS = @LDFLAGS@ -L../../lib + + # Standard LIBS +-LIBS = @LIBS@ ++LIBS = @LIBS@ -lopenflow + + INSTALL = @INSTALL@ + INSTALL_PROGRAM = @INSTALL_PROGRAM@ +@@ -87,7 +87,8 @@ + print-slow.c print-snmp.c print-stp.c print-sunatm.c print-sunrpc.c \ + print-symantec.c print-syslog.c print-tcp.c print-telnet.c print-tftp.c \ + print-timed.c print-token.c print-udp.c print-vjc.c print-vrrp.c \ +- print-wb.c print-zephyr.c setsignal.c tcpdump.c util.c ++ print-wb.c print-zephyr.c setsignal.c tcpdump.c util.c \ ++ print-openflow.c + + LOCALSRC = @LOCALSRC@ + GENSRC = version.c +diff -rNu tcpdump/print-openflow.c tcpdump/print-openflow.c +--- tcpdump/print-openflow.c 1969-12-31 16:00:00.000000000 -0800 ++++ tcpdump/print-openflow.c 2008-02-07 11:29:01.000000000 -0800 +@@ -0,0 +1,46 @@ ++/* Copyright (C) 2007, 2008 Board of Trustees, Leland Stanford Jr. University. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include ++ ++#include "interface.h" ++#include "../../include/openflow/openflow.h" ++#include "../../include/ofp-print.h" ++ ++void ++openflow_print(const u_char *sp, u_int length) ++{ ++ const struct ofp_header *ofp = (struct ofp_header *)sp; ++ ++ if (!TTEST2(*sp, ntohs(ofp->length))) ++ goto trunc; ++ ++ ofp_print(stdout, sp, length, vflag); ++ return; ++ ++trunc: ++ printf("[|openflow]"); ++} +diff -rNu tcpdump/print-tcp.c tcpdump/print-tcp.c +--- tcpdump/print-tcp.c 2006-09-19 12:07:57.000000000 -0700 ++++ tcpdump/print-tcp.c 2008-02-07 13:07:58.000000000 -0800 +@@ -52,6 +52,8 @@ + + #include "nameser.h" + ++#include "../../include/openflow.h" ++ + #ifdef HAVE_LIBCRYPTO + #include + +@@ -680,7 +682,8 @@ + } + else if (length > 0 && (sport == LDP_PORT || dport == LDP_PORT)) { + ldp_print(bp, length); +- } ++ } else if (sport == OFP_TCP_PORT || dport == OFP_TCP_PORT) ++ openflow_print(bp, length); + } + return; + bad: diff --git a/openflow/udatapath/.dirstamp b/openflow/udatapath/.dirstamp new file mode 100644 index 00000000..e69de29b diff --git a/openflow/udatapath/.gitignore b/openflow/udatapath/.gitignore new file mode 100644 index 00000000..e4272b0b --- /dev/null +++ b/openflow/udatapath/.gitignore @@ -0,0 +1,4 @@ +/Makefile +/Makefile.in +/ofdatapath +/ofdatapath.8 diff --git a/openflow/udatapath/automake.mk b/openflow/udatapath/automake.mk new file mode 100644 index 00000000..b4b4d8e6 --- /dev/null +++ b/openflow/udatapath/automake.mk @@ -0,0 +1,75 @@ +# +# Build udatapath as binary +# + +bin_PROGRAMS += udatapath/ofdatapath +man_MANS += udatapath/ofdatapath.8 + +udatapath_ofdatapath_SOURCES = \ + udatapath/chain.c \ + udatapath/chain.h \ + udatapath/crc32.c \ + udatapath/crc32.h \ + udatapath/datapath.c \ + udatapath/datapath.h \ + udatapath/dp_act.c \ + udatapath/dp_act.h \ + udatapath/of_ext_msg.c \ + udatapath/of_ext_msg.h \ + udatapath/udatapath.c \ + udatapath/private-msg.c \ + udatapath/private-msg.h \ + udatapath/switch-flow.c \ + udatapath/switch-flow.h \ + udatapath/table.h \ + udatapath/table-hash.c \ + udatapath/table-linear.c + +udatapath_ofdatapath_LDADD = lib/libopenflow.a $(SSL_LIBS) $(FAULT_LIBS) +udatapath_ofdatapath_CPPFLAGS = $(AM_CPPFLAGS) + +EXTRA_DIST += udatapath/ofdatapath.8.in +DISTCLEANFILES += udatapath/ofdatapath.8 + +if BUILD_HW_LIBS + +# Options for each platform +if NF2 +udatapath_ofdatapath_LDADD += hw-lib/libnf2.a +udatapath_ofdatapath_CPPFLAGS += -DOF_HW_PLAT -DUSE_NETDEV -g +noinst_LIBRARIES += hw-lib/libnf2.a +endif + +endif + +if BUILD_HW_LIBS +# +# Build udatapath as a library +# + +noinst_LIBRARIES += udatapath/libudatapath.a + +udatapath_libudatapath_a_SOURCES = \ + udatapath/chain.c \ + udatapath/chain.h \ + udatapath/crc32.c \ + udatapath/crc32.h \ + udatapath/datapath.c \ + udatapath/datapath.h \ + udatapath/dp_act.c \ + udatapath/dp_act.h \ + udatapath/of_ext_msg.c \ + udatapath/of_ext_msg.h \ + udatapath/udatapath.c \ + udatapath/private-msg.c \ + udatapath/private-msg.h \ + udatapath/switch-flow.c \ + udatapath/switch-flow.h \ + udatapath/table.h \ + udatapath/table-hash.c \ + udatapath/table-linear.c + +udatapath_libudatapath_a_CPPFLAGS = $(AM_CPPFLAGS) +udatapath_libudatapath_a_CPPFLAGS += -DOF_HW_PLAT -DUDATAPATH_AS_LIB -g + +endif diff --git a/openflow/udatapath/chain.c b/openflow/udatapath/chain.c new file mode 100644 index 00000000..b9dc39c0 --- /dev/null +++ b/openflow/udatapath/chain.c @@ -0,0 +1,261 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include "chain.h" +#include +#include +#include +#include "switch-flow.h" +#include "table.h" +#include "datapath.h" + +#if defined(OF_HW_PLAT) +#include +#endif + +#define THIS_MODULE VLM_chain +#include "vlog.h" + +/* Attempts to append 'table' to the set of tables in 'chain'. Returns 0 or + * negative error. If 'table' is null it is assumed that table creation failed + * due to out-of-memory. */ +static int add_table(struct sw_chain *chain, struct sw_table *table, int emerg) +{ + if (table == NULL) + return -ENOMEM; + if (chain->n_tables >= CHAIN_MAX_TABLES) { + VLOG_ERR("too many tables in chain\n"); + table->destroy(table); + return -ENOBUFS; + } + if (emerg) + chain->emerg_table = table; + else + chain->tables[chain->n_tables++] = table; + return 0; +} + +/* Creates and returns a new chain. Returns NULL if the chain cannot be + * created. */ +struct sw_chain *chain_create(struct datapath *dp) +{ + struct sw_chain *chain = calloc(1, sizeof *chain); + if (chain == NULL) + return NULL; + + chain->dp = dp; +#if defined(OF_HW_PLAT) + if (dp && dp->hw_drv) { + if (add_table(chain, (struct sw_table *)dp->hw_drv, 0) != 0) { + VLOG_ERR("Could not attach HW table to chain\n"); + } + } +#endif + if (add_table(chain, table_hash2_create(0x1EDC6F41, TABLE_HASH_MAX_FLOWS, + 0x741B8CD7, TABLE_HASH_MAX_FLOWS), + 0) + || add_table(chain, table_linear_create(TABLE_LINEAR_MAX_FLOWS), 0) + || add_table(chain, table_linear_create(TABLE_LINEAR_MAX_FLOWS), 1)) { + chain_destroy(chain); + return NULL; + } + + return chain; +} + +/* Searches 'chain' for a flow matching 'key', which must not have any wildcard + * fields. Returns the flow if successful, otherwise a null pointer. */ +struct sw_flow * +chain_lookup(struct sw_chain *chain, const struct sw_flow_key *key, int emerg) +{ + int i; + + assert(!key->wildcards); + + if (emerg) { + struct sw_table *t = chain->emerg_table; + struct sw_flow *flow = t->lookup(t, key); + t->n_lookup++; + if (flow) { + t->n_matched++; + return flow; + } + } else { + for (i = 0; i < chain->n_tables; i++) { + struct sw_table *t = chain->tables[i]; + struct sw_flow *flow = t->lookup(t, key); + t->n_lookup++; + if (flow) { + t->n_matched++; + return flow; + } + } + } + + return NULL; +} + +/* Inserts 'flow' into 'chain', replacing any duplicate flow. Returns 0 if + * successful or a negative error. + * + * If successful, 'flow' becomes owned by the chain, otherwise it is retained + * by the caller. */ +int +chain_insert(struct sw_chain *chain, struct sw_flow *flow, int emerg) +{ + int i; + + if (emerg) { + struct sw_table *t = chain->emerg_table; + if (t->insert(t, flow)) + return 0; + } else { + for (i = 0; i < chain->n_tables; i++) { + struct sw_table *t = chain->tables[i]; + if (t->insert(t, flow)) + return 0; + } + } + + return -ENOBUFS; +} + +/* Modifies actions in 'chain' that match 'key'. If 'strict' set, wildcards + * and priority must match. Returns the number of flows that were modified. + * + * Expensive in the general case as currently implemented, since it requires + * iterating through the entire contents of each table for keys that contain + * wildcards. Relatively cheap for fully specified keys. */ +int +chain_modify(struct sw_chain *chain, const struct sw_flow_key *key, + uint16_t priority, int strict, + const struct ofp_action_header *actions, size_t actions_len, + int emerg) +{ + int count = 0; + int i; + + if (emerg) { + struct sw_table *t = chain->emerg_table; + count += t->modify(t, key, priority, strict, actions, actions_len); + } else { + for (i = 0; i < chain->n_tables; i++) { + struct sw_table *t = chain->tables[i]; + count += t->modify(t, key, priority, strict, actions, actions_len); + } + } + + return count; +} + +/* Checks whether the chain has an entry with the same priority which conflicts + * with 'key'. If 'strict' set, wildcards should also match. If 'strict' is not + * set, comparison is done 'module wildcards'. + * + * Returns 'true' if such an entry exists, 'false' otherwise. */ +int +chain_has_conflict(struct sw_chain *chain, const struct sw_flow_key *key, + uint16_t priority, int strict) +{ + int i; + + for (i = 0; i < chain->n_tables; i++) { + struct sw_table *t = chain->tables[i]; + if (t->has_conflict(t, key, priority, strict)) { + return true; + } + } + + return false; +} + +/* Deletes from 'chain' any and all flows that match 'key'. If 'out_port' + * is not OFPP_NONE, then matching entries must have that port as an + * argument for an output action. If 'strict" is set, then wildcards and + * priority must match. Returns the number of flows that were deleted. + * + * Expensive in the general case as currently implemented, since it requires + * iterating through the entire contents of each table for keys that contain + * wildcards. Relatively cheap for fully specified keys. */ +int +chain_delete(struct sw_chain *chain, const struct sw_flow_key *key, + uint16_t out_port, uint16_t priority, int strict, int emerg) +{ + int count = 0; + int i; + + if (emerg) { + struct sw_table *t = chain->emerg_table; + count += t->delete(chain->dp, t, key, out_port, priority, strict); + } else { + for (i = 0; i < chain->n_tables; i++) { + struct sw_table *t = chain->tables[i]; + count += t->delete(chain->dp, t, key, out_port, priority, strict); + } + } + + return count; +} + +/* Deletes timed-out flow entries from all the tables in 'chain' and appends + * the deleted flows to 'deleted'. + * + * Expensive as currently implemented, since it iterates through the entire + * contents of each table. */ +void +chain_timeout(struct sw_chain *chain, struct list *deleted) +{ + int i; + + for (i = 0; i < chain->n_tables; i++) { + struct sw_table *t = chain->tables[i]; + t->timeout(t, deleted); + } +} + +/* Destroys 'chain', which must not have any users. */ +void +chain_destroy(struct sw_chain *chain) +{ + int i; + struct sw_table *t; + + for (i = 0; i < chain->n_tables; i++) { + t = chain->tables[i]; + t->destroy(t); + } + t = chain->emerg_table; + t->destroy(t); + free(chain); +} diff --git a/openflow/udatapath/chain.h b/openflow/udatapath/chain.h new file mode 100644 index 00000000..fb4e9c37 --- /dev/null +++ b/openflow/udatapath/chain.h @@ -0,0 +1,74 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#ifndef CHAIN_H +#define CHAIN_H 1 + +#include +#include + +struct sw_flow; +struct sw_flow_key; +struct ofp_action_header; +struct list; +struct datapath; + +#define TABLE_LINEAR_MAX_FLOWS 100 +#define TABLE_HASH_MAX_FLOWS 65536 +#define TABLE_MAC_MAX_FLOWS 1024 +#define TABLE_MAC_NUM_BUCKETS 1024 + +/* Set of tables chained together in sequence from cheap to expensive. */ +#define CHAIN_MAX_TABLES 4 +struct sw_chain { + int n_tables; /* Number of working tables, not includes + * protection (emergency) table. */ + struct sw_table *tables[CHAIN_MAX_TABLES]; + struct sw_table *emerg_table; + + struct datapath *dp; +}; + +struct sw_chain *chain_create(struct datapath *); +struct sw_flow *chain_lookup(struct sw_chain *, const struct sw_flow_key *, int); +int chain_insert(struct sw_chain *, struct sw_flow *, int); +int chain_modify(struct sw_chain *, const struct sw_flow_key *, + uint16_t, int, const struct ofp_action_header *, size_t, int); +int chain_has_conflict(struct sw_chain *, const struct sw_flow_key *, + uint16_t, int); +int chain_delete(struct sw_chain *, const struct sw_flow_key *, uint16_t, + uint16_t, int, int); +void chain_timeout(struct sw_chain *, struct list *deleted); +void chain_destroy(struct sw_chain *); + +#endif /* chain.h */ diff --git a/openflow/udatapath/crc32.c b/openflow/udatapath/crc32.c new file mode 100644 index 00000000..f6c2c0b3 --- /dev/null +++ b/openflow/udatapath/crc32.c @@ -0,0 +1,68 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include "crc32.h" + +void +crc32_init(struct crc32 *crc, unsigned int polynomial) +{ + int i; + + for (i = 0; i < CRC32_TABLE_SIZE; ++i) { + unsigned int reg = i << 24; + int j; + for (j = 0; j < CRC32_TABLE_BITS; j++) { + int topBit = (reg & 0x80000000) != 0; + reg <<= 1; + if (topBit) + reg ^= polynomial; + } + crc->table[i] = reg; + } +} + +unsigned int +crc32_calculate(const struct crc32 *crc, const void *data_, size_t n_bytes) +{ + const uint8_t *data = data_; + unsigned int result = 0; + size_t i; + + for (i = 0; i < n_bytes; i++) { + unsigned int top = result >> 24; + top ^= data[i]; + result = (result << 8) ^ crc->table[top]; + } + return result; +} diff --git a/openflow/udatapath/crc32.h b/openflow/udatapath/crc32.h new file mode 100644 index 00000000..355aefdf --- /dev/null +++ b/openflow/udatapath/crc32.h @@ -0,0 +1,50 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#ifndef CRC32_H +#define CRC32_H 1 + +#include +#include + +#define CRC32_TABLE_BITS 8 +#define CRC32_TABLE_SIZE (1u << CRC32_TABLE_BITS) + +struct crc32 { + unsigned int table[CRC32_TABLE_SIZE]; +}; + +void crc32_init(struct crc32 *, unsigned int polynomial); +unsigned int crc32_calculate(const struct crc32 *, const void *, size_t); + +#endif /* crc32.h */ diff --git a/openflow/udatapath/datapath.c b/openflow/udatapath/datapath.c new file mode 100644 index 00000000..5254b771 --- /dev/null +++ b/openflow/udatapath/datapath.c @@ -0,0 +1,2375 @@ +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include "datapath.h" +#include +#include +#include +#include +#include +#include +#include +#include "chain.h" +#include "csum.h" +#include "flow.h" +#include "ofpbuf.h" +#include "openflow/openflow.h" +#include "openflow/nicira-ext.h" +#include "openflow/private-ext.h" +#include "openflow/openflow-ext.h" +#include "packets.h" +#include "poll-loop.h" +#include "rconn.h" +#include "stp.h" +#include "switch-flow.h" +#include "table.h" +#include "vconn.h" +#include "xtoxll.h" +#include "private-msg.h" +#include "of_ext_msg.h" +#include "dp_act.h" + +#define THIS_MODULE VLM_datapath +#include "vlog.h" + +#if defined(OF_HW_PLAT) +#include +#include +#endif + +#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) +/* Queue to decouple receive packet thread from rconn control thread */ +/* Could make mutex per-DP */ +static pthread_mutex_t pkt_q_mutex = PTHREAD_MUTEX_INITIALIZER; +#define PKT_Q_LOCK pthread_mutex_lock(&pkt_q_mutex) +#define PKT_Q_UNLOCK pthread_mutex_unlock(&pkt_q_mutex) + +static void +enqueue_pkt(struct datapath *dp, struct ofpbuf *buffer, of_port_t port_no, + int reason) +{ + struct hw_pkt_q_entry *q_entry; + + if ((q_entry = xmalloc(sizeof(*q_entry))) == NULL) { + VLOG_WARN("Could not alloc q entry\n"); + /* FIXME: Dealloc buffer */ + return; + } + q_entry->buffer = buffer; + q_entry->next = NULL; + q_entry->port_no = port_no; + q_entry->reason = reason; + pthread_mutex_lock(&pkt_q_mutex); + if (dp->hw_pkt_list_head == NULL) { + dp->hw_pkt_list_head = q_entry; + } else { + dp->hw_pkt_list_tail->next = q_entry; + } + dp->hw_pkt_list_tail = q_entry; + pthread_mutex_unlock(&pkt_q_mutex); +} + +/* If queue non-empty, fill out params and return 1; else return 0 */ +static int +dequeue_pkt(struct datapath *dp, struct ofpbuf **buffer, of_port_t *port_no, + int *reason) +{ + struct hw_pkt_q_entry *q_entry; + int rv = 0; + + pthread_mutex_lock(&pkt_q_mutex); + q_entry = dp->hw_pkt_list_head; + if (dp->hw_pkt_list_head != NULL) { + dp->hw_pkt_list_head = dp->hw_pkt_list_head->next; + if (dp->hw_pkt_list_head == NULL) { + dp->hw_pkt_list_tail = NULL; + } + } + pthread_mutex_unlock(&pkt_q_mutex); + + if (q_entry != NULL) { + rv = 1; + *buffer = q_entry->buffer; + *port_no = q_entry->port_no; + *reason = q_entry->reason; + free(q_entry); + } + + return rv; +} +#endif + +extern char mfr_desc; +extern char hw_desc; +extern char sw_desc; +extern char dp_desc; +extern char serial_num; + +/* Capabilities supported by this implementation. */ +#define OFP_SUPPORTED_CAPABILITIES ( OFPC_FLOW_STATS \ + | OFPC_TABLE_STATS \ + | OFPC_PORT_STATS \ + | OFPC_QUEUE_STATS \ + | OFPC_ARP_MATCH_IP ) + +/* Actions supported by this implementation. */ +#define OFP_SUPPORTED_ACTIONS ( (1 << OFPAT_OUTPUT) \ + | (1 << OFPAT_SET_VLAN_VID) \ + | (1 << OFPAT_SET_VLAN_PCP) \ + | (1 << OFPAT_STRIP_VLAN) \ + | (1 << OFPAT_SET_DL_SRC) \ + | (1 << OFPAT_SET_DL_DST) \ + | (1 << OFPAT_SET_NW_SRC) \ + | (1 << OFPAT_SET_NW_DST) \ + | (1 << OFPAT_SET_TP_SRC) \ + | (1 << OFPAT_SET_TP_DST) \ + | (1 << OFPAT_ENQUEUE)) + +/* The origin of a received OpenFlow message, to enable sending a reply. */ +struct sender { + struct remote *remote; /* The device that sent the message. */ + uint32_t xid; /* The OpenFlow transaction ID. */ +}; + +/* A connection to a secure channel. */ +struct remote { + struct list node; + struct rconn *rconn; +#define TXQ_LIMIT 128 /* Max number of packets to queue for tx. */ + int n_txq; /* Number of packets queued for tx on rconn. */ + + /* Support for reliable, multi-message replies to requests. + * + * If an incoming request needs to have a reliable reply that might + * require multiple messages, it can use remote_start_dump() to set up + * a callback that will be called as buffer space for replies. */ + int (*cb_dump)(struct datapath *, void *aux); + void (*cb_done)(void *aux); + void *cb_aux; +}; + +static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60); + +static struct remote *remote_create(struct datapath *, struct rconn *); +static void remote_run(struct datapath *, struct remote *); +static void remote_wait(struct remote *); +static void remote_destroy(struct remote *); + +static void update_port_flags(struct datapath *, const struct ofp_port_mod *); +static void send_port_status(struct sw_port *p, uint8_t status); + +/* Buffers are identified by a 31-bit opaque ID. We divide the ID + * into a buffer number (low bits) and a cookie (high bits). The buffer number + * is an index into an array of buffers. The cookie distinguishes between + * different packets that have occupied a single buffer. Thus, the more + * buffers we have, the lower-quality the cookie... */ +#define PKT_BUFFER_BITS 8 +#define N_PKT_BUFFERS (1 << PKT_BUFFER_BITS) +#define PKT_BUFFER_MASK (N_PKT_BUFFERS - 1) + +#define PKT_COOKIE_BITS (32 - PKT_BUFFER_BITS) + +int run_flow_through_tables(struct datapath *, struct ofpbuf *, + struct sw_port *); +void fwd_port_input(struct datapath *, struct ofpbuf *, struct sw_port *); +int fwd_control_input(struct datapath *, const struct sender *, + const void *, size_t); + +uint32_t save_buffer(struct ofpbuf *); +static struct ofpbuf *retrieve_buffer(uint32_t id); +static void discard_buffer(uint32_t id); + +struct sw_port * +dp_lookup_port(struct datapath *dp, uint16_t port_no) +{ + return (port_no < DP_MAX_PORTS ? &dp->ports[port_no] + : port_no == OFPP_LOCAL ? dp->local_port + : NULL); +} + +struct sw_queue * +dp_lookup_queue(struct sw_port *p, uint32_t queue_id) +{ + struct sw_queue *q; + + LIST_FOR_EACH(q, struct sw_queue, node, &p->queue_list) { + if ((q != NULL) && (q->queue_id == queue_id)) { + return q; + } + } + return NULL; +} + +/* Generates and returns a random datapath id. */ +static uint64_t +gen_datapath_id(void) +{ + uint8_t ea[ETH_ADDR_LEN]; + eth_addr_random(ea); + ea[0] = 0x00; /* Set Nicira OUI. */ + ea[1] = 0x23; + ea[2] = 0x20; + return eth_addr_to_uint64(ea); +} + +/* FIXME: Should not depend on udatapath_as_lib */ +#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) && defined(UDATAPATH_AS_LIB) +/* + * Receive packet handling for hardware driver controlled ports + * + * FIXME: For now, call the pkt fwding directly; eventually may + * want to enqueue packets at this layer; at that point must + * make sure poll event is registered or timer kicked + */ +static int +hw_packet_in(of_port_t port_no, of_packet_t *packet, int reason, + void *cookie) +{ + struct sw_port *port; + struct ofpbuf *buffer = NULL; + struct datapath *dp = (struct datapath *)cookie; + const int headroom = 128 + 2; + const int hard_header = VLAN_ETH_HEADER_LEN; + const int tail_room = sizeof(uint32_t); /* For crc if needed later */ + + VLOG_INFO("dp rcv packet on port %d, size %d\n", + port_no, packet->length); + if ((port_no < 1) || port_no > DP_MAX_PORTS) { + VLOG_ERR("Bad receive port %d\n", port_no); + /* TODO increment error counter */ + return -1; + } + port = &dp->ports[port_no]; + if (!PORT_IN_USE(port)) { + VLOG_WARN("Receive port not active: %d\n", port_no); + return -1; + } + if (!IS_HW_PORT(port)) { + VLOG_ERR("Receive port not controlled by HW: %d\n", port_no); + return -1; + } + /* Note: We're really not counting these for port stats as they + * should be gotten directly from the HW */ + port->rx_packets++; + port->rx_bytes += packet->length; + /* For now, copy data into OFP buffer; eventually may steal packet + * from RX to avoid copy. As per dp_run, add headroom and offset bytes. + */ + buffer = ofpbuf_new(headroom + hard_header + packet->length + tail_room); + if (buffer == NULL) { + VLOG_WARN("Could not alloc ofpbuf on hw pkt in\n"); + fprintf(stderr, "Could not alloc ofpbuf on hw pkt in\n"); + } else { + buffer->data = (char*)buffer->data + headroom; + buffer->size = packet->length; + memcpy(buffer->data, packet->data, packet->length); + enqueue_pkt(dp, buffer, port_no, reason); + poll_immediate_wake(); + } + + return 0; +} +#endif + +#if defined(OF_HW_PLAT) +static int +dp_hw_drv_init(struct datapath *dp) +{ + dp->hw_pkt_list_head = NULL; + dp->hw_pkt_list_tail = NULL; + + dp->hw_drv = new_of_hw_driver(dp); + if (dp->hw_drv == NULL) { + VLOG_ERR("Could not create HW driver"); + return -1; + } +#if !defined(USE_NETDEV) + if (dp->hw_drv->packet_receive_register(dp->hw_drv, + hw_packet_in, dp) < 0) { + VLOG_ERR("Could not register with HW driver to receive pkts"); + } +#endif + + return 0; +} + +#endif + +int +dp_new(struct datapath **dp_, uint64_t dpid) +{ + struct datapath *dp; + + dp = calloc(1, sizeof *dp); + if (!dp) { + return ENOMEM; + } + + dp->last_timeout = time_now(); + list_init(&dp->remotes); + dp->listeners = NULL; + dp->n_listeners = 0; + dp->id = dpid <= UINT64_C(0xffffffffffff) ? dpid : gen_datapath_id(); +/* FIXME: Should not depend on udatapath_as_lib */ +#if defined(OF_HW_PLAT) && (defined(UDATAPATH_AS_LIB) || defined(USE_NETDEV)) + dp_hw_drv_init(dp); +#endif + dp->chain = chain_create(dp); + if (!dp->chain) { + VLOG_ERR("could not create chain"); + free(dp); + return ENOMEM; + } + + list_init(&dp->port_list); + dp->flags = 0; + dp->miss_send_len = OFP_DEFAULT_MISS_SEND_LEN; + + if(strlen(&dp_desc) > 0) /* use the comment, if specified */ + strncpy(dp->dp_desc, &dp_desc, sizeof dp->dp_desc); + else /* else, just use "$HOSTNAME pid=$$" */ + { + char hostnametmp[DESC_STR_LEN]; + gethostname(hostnametmp,sizeof hostnametmp); + snprintf(dp->dp_desc, sizeof dp->dp_desc,"%s pid=%u",hostnametmp, getpid()); + } + + *dp_ = dp; + return 0; +} + +static int +new_port(struct datapath *dp, struct sw_port *port, uint16_t port_no, + const char *netdev_name, const uint8_t *new_mac, uint16_t num_queues) +{ + struct netdev *netdev; + struct in6_addr in6; + struct in_addr in4; + int error; + + error = netdev_open(netdev_name, NETDEV_ETH_TYPE_ANY, &netdev); + if (error) { + return error; + } + if (new_mac && !eth_addr_equals(netdev_get_etheraddr(netdev), new_mac)) { + /* Generally the device has to be down before we change its hardware + * address. Don't bother to check for an error because it's really + * the netdev_set_etheraddr() call below that we care about. */ + netdev_set_flags(netdev, 0, false); + error = netdev_set_etheraddr(netdev, new_mac); + if (error) { + VLOG_WARN("failed to change %s Ethernet address " + "to "ETH_ADDR_FMT": %s", + netdev_name, ETH_ADDR_ARGS(new_mac), strerror(error)); + } + } + error = netdev_set_flags(netdev, NETDEV_UP | NETDEV_PROMISC, false); + if (error) { + VLOG_ERR("failed to set promiscuous mode on %s device", netdev_name); + netdev_close(netdev); + return error; + } + if (netdev_get_in4(netdev, &in4)) { + VLOG_ERR("%s device has assigned IP address %s", + netdev_name, inet_ntoa(in4)); + } + if (netdev_get_in6(netdev, &in6)) { + char in6_name[INET6_ADDRSTRLEN + 1]; + inet_ntop(AF_INET6, &in6, in6_name, sizeof in6_name); + VLOG_ERR("%s device has assigned IPv6 address %s", + netdev_name, in6_name); + } + + if (num_queues > 0) { + error = netdev_setup_slicing(netdev, num_queues); + if (error) { + VLOG_ERR("failed to configure slicing on %s device: "\ + "check INSTALL for dependencies, or rerun "\ + "using --no-slicing option to disable slicing", + netdev_name); + netdev_close(netdev); + return error; + } + } + + memset(port, '\0', sizeof *port); + + list_init(&port->queue_list); + port->dp = dp; + port->flags |= SWP_USED; + port->netdev = netdev; + port->port_no = port_no; + port->num_queues = num_queues; + list_push_back(&dp->port_list, &port->node); + + /* Notify the ctlpath that this port has been added */ + send_port_status(port, OFPPR_ADD); + + return 0; +} + +#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) +int +dp_add_port(struct datapath *dp, const char *port_name, uint16_t num_queues) +{ + int port_no; + int rc = 0; + struct sw_port *port; + + fprintf(stderr, "Adding port %s. hw_drv is %p\n", port_name, dp->hw_drv); + if (dp->hw_drv && dp->hw_drv->port_add) { + port_no = dp->hw_drv->port_add(dp->hw_drv, -1, port_name); + if (port_no >= 0) { + port = &dp->ports[port_no]; + if (port->flags & SWP_USED) { + VLOG_ERR("HW port %s (%d) already created\n", + port_name, port_no); + rc = -1; + } else { + fprintf(stderr, "Adding HW port %s as OF port number %d\n", + port_name, port_no); + /* FIXME: Determine and record HW addr, etc */ + port->flags |= SWP_USED | SWP_HW_DRV_PORT; + port->dp = dp; + port->port_no = port_no; + list_init(&port->queue_list); + port->num_queues = num_queues; + strncpy(port->hw_name, port_name, sizeof(port->hw_name)); + list_push_back(&dp->port_list, &port->node); + send_port_status(port, OFPPR_ADD); + } + } else { + VLOG_ERR("Port %s not recognized by hardware driver", port_name); + rc = -1; + } + } else { + VLOG_ERR("No hardware driver support; can't add ports"); + rc = -1; + } + + return rc; +} +#else /* Not HW platform support */ +int +dp_add_port(struct datapath *dp, const char *netdev, uint16_t num_queues) +{ + int port_no; + for (port_no = 1; port_no < DP_MAX_PORTS; port_no++) { + struct sw_port *port = &dp->ports[port_no]; + if (!port->netdev) { + return new_port(dp, port, port_no, netdev, NULL, num_queues); + } + } + return EXFULL; +} +#endif /* OF_HW_PLAT */ + +int +dp_add_local_port(struct datapath *dp, const char *netdev, uint16_t num_queues) +{ + if (!dp->local_port) { + uint8_t ea[ETH_ADDR_LEN]; + struct sw_port *port; + int error; + + port = xcalloc(1, sizeof *port); + eth_addr_from_uint64(dp->id, ea); + error = new_port(dp, port, OFPP_LOCAL, netdev, ea, num_queues); + if (!error) { + dp->local_port = port; + } else { + free(port); + } + return error; + } else { + return EXFULL; + } +} + +void +dp_add_pvconn(struct datapath *dp, struct pvconn *pvconn) +{ + dp->listeners = xrealloc(dp->listeners, + sizeof *dp->listeners * (dp->n_listeners + 1)); + dp->listeners[dp->n_listeners++] = pvconn; +} + +void +dp_run(struct datapath *dp) +{ + time_t now = time_now(); + struct sw_port *p, *pn; + struct remote *r, *rn; + struct ofpbuf *buffer = NULL; + size_t i; + + if (now != dp->last_timeout) { + struct list deleted = LIST_INITIALIZER(&deleted); + struct sw_flow *f, *n; + + chain_timeout(dp->chain, &deleted); + LIST_FOR_EACH_SAFE (f, n, struct sw_flow, node, &deleted) { + dp_send_flow_end(dp, f, f->reason); + list_remove(&f->node); + flow_free(f); + } + dp->last_timeout = now; + } + poll_timer_wait(1000); + +#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) + { /* Process packets received from callback thread */ + struct ofpbuf *buffer; + of_port_t port_no; + int reason; + struct sw_port *p; + + while (dequeue_pkt(dp, &buffer, &port_no, &reason)) { + p = dp_lookup_port(dp, port_no); + /* FIXME: We're throwing away the reason that came from HW */ + fwd_port_input(dp, buffer, p); + } + } +#endif + + LIST_FOR_EACH_SAFE (p, pn, struct sw_port, node, &dp->port_list) { + int error; + + if (IS_HW_PORT(p)) { + continue; + } + if (!buffer) { + /* Allocate buffer with some headroom to add headers in forwarding + * to the controller or adding a vlan tag, plus an extra 2 bytes to + * allow IP headers to be aligned on a 4-byte boundary. */ + const int headroom = 128 + 2; + const int hard_header = VLAN_ETH_HEADER_LEN; + const int mtu = netdev_get_mtu(p->netdev); + buffer = ofpbuf_new(headroom + hard_header + mtu); + buffer->data = (char*)buffer->data + headroom; + } + error = netdev_recv(p->netdev, buffer); + if (!error) { + p->rx_packets++; + p->rx_bytes += buffer->size; + fwd_port_input(dp, buffer, p); + buffer = NULL; + } else if (error != EAGAIN) { + VLOG_ERR_RL(&rl, "error receiving data from %s: %s", + netdev_get_name(p->netdev), strerror(error)); + } + } + ofpbuf_delete(buffer); + + /* Talk to remotes. */ + LIST_FOR_EACH_SAFE (r, rn, struct remote, node, &dp->remotes) { + remote_run(dp, r); + } + + for (i = 0; i < dp->n_listeners; ) { + struct pvconn *pvconn = dp->listeners[i]; + struct vconn *new_vconn; + int retval = pvconn_accept(pvconn, OFP_VERSION, &new_vconn); + if (!retval) { + remote_create(dp, rconn_new_from_vconn("passive", new_vconn)); + } else if (retval != EAGAIN) { + VLOG_WARN_RL(&rl, "accept failed (%s)", strerror(retval)); + dp->listeners[i] = dp->listeners[--dp->n_listeners]; + continue; + } + i++; + } +} + +static void +remote_run(struct datapath *dp, struct remote *r) +{ + int i; + + rconn_run(r->rconn); + + /* Do some remote processing, but cap it at a reasonable amount so that + * other processing doesn't starve. */ + for (i = 0; i < 50; i++) { + if (!r->cb_dump) { + struct ofpbuf *buffer; + struct ofp_header *oh; + + buffer = rconn_recv(r->rconn); + if (!buffer) { + break; + } + + if (buffer->size >= sizeof *oh) { + struct sender sender; + + oh = (struct ofp_header *)buffer->data; + sender.remote = r; + sender.xid = oh->xid; + fwd_control_input(dp, &sender, buffer->data, buffer->size); + } else { + VLOG_WARN_RL(&rl, "received too-short OpenFlow message"); + } + ofpbuf_delete(buffer); + } else { + if (r->n_txq < TXQ_LIMIT) { + int error = r->cb_dump(dp, r->cb_aux); + if (error <= 0) { + if (error) { + VLOG_WARN_RL(&rl, "dump callback error: %s", + strerror(-error)); + } + r->cb_done(r->cb_aux); + r->cb_dump = NULL; + } + } else { + break; + } + } + } + + if (!rconn_is_alive(r->rconn)) { + remote_destroy(r); + } +} + +static void +remote_wait(struct remote *r) +{ + rconn_run_wait(r->rconn); + rconn_recv_wait(r->rconn); +} + +static void +remote_destroy(struct remote *r) +{ + if (r) { + if (r->cb_dump && r->cb_done) { + r->cb_done(r->cb_aux); + } + list_remove(&r->node); + rconn_destroy(r->rconn); + free(r); + } +} + +static struct remote * +remote_create(struct datapath *dp, struct rconn *rconn) +{ + struct remote *remote = xmalloc(sizeof *remote); + list_push_back(&dp->remotes, &remote->node); + remote->rconn = rconn; + remote->cb_dump = NULL; + remote->n_txq = 0; + return remote; +} + +/* Starts a callback-based, reliable, possibly multi-message reply to a + * request made by 'remote'. + * + * 'dump' designates a function that will be called when the 'remote' send + * queue has an empty slot. It should compose a message and send it on + * 'remote'. On success, it should return 1 if it should be called again when + * another send queue slot opens up, 0 if its transmissions are complete, or a + * negative errno value on failure. + * + * 'done' designates a function to clean up any resources allocated for the + * dump. It must handle being called before the dump is complete (which will + * happen if 'remote' is closed unexpectedly). + * + * 'aux' is passed to 'dump' and 'done'. */ +static void +remote_start_dump(struct remote *remote, + int (*dump)(struct datapath *, void *), + void (*done)(void *), + void *aux) +{ + assert(!remote->cb_dump); + remote->cb_dump = dump; + remote->cb_done = done; + remote->cb_aux = aux; +} + +void +dp_wait(struct datapath *dp) +{ + struct sw_port *p; + struct remote *r; + size_t i; + + LIST_FOR_EACH (p, struct sw_port, node, &dp->port_list) { + if (IS_HW_PORT(p)) { + continue; + } + netdev_recv_wait(p->netdev); + } + LIST_FOR_EACH (r, struct remote, node, &dp->remotes) { + remote_wait(r); + } + for (i = 0; i < dp->n_listeners; i++) { + pvconn_wait(dp->listeners[i]); + } +} + +/* Send packets out all the ports except the originating one. If the + * "flood" argument is set, don't send out ports with flooding disabled. + */ +static int +output_all(struct datapath *dp, struct ofpbuf *buffer, int in_port, int flood) +{ + struct sw_port *p; + int prev_port; /* Buffer is cloned for multiple transmits */ + + prev_port = -1; + LIST_FOR_EACH (p, struct sw_port, node, &dp->port_list) { + if (p->port_no == in_port) { + continue; + } + if (flood && p->config & OFPPC_NO_FLOOD) { + continue; + } + if (prev_port != -1) { + dp_output_port(dp, ofpbuf_clone(buffer), in_port, prev_port, + 0,false); + } + prev_port = p->port_no; + } + if (prev_port != -1) + dp_output_port(dp, buffer, in_port, prev_port, 0, false); + else + ofpbuf_delete(buffer); + + return 0; +} + +static void +output_packet(struct datapath *dp, struct ofpbuf *buffer, uint16_t out_port, + uint32_t queue_id) +{ + uint16_t class_id; + struct sw_queue * q; + struct sw_port *p; + + q = NULL; + p = dp_lookup_port(dp, out_port); + +/* FIXME: Needs update for queuing */ +#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) + if ((p != NULL) && IS_HW_PORT(p)) { + if (dp && dp->hw_drv) { + if (dp->hw_drv->port_link_get(dp->hw_drv, p->port_no)) { + of_packet_t *pkt; + int rv; + + pkt = calloc(1, sizeof(*pkt)); + OF_PKT_INIT(pkt, buffer); + rv = dp->hw_drv->packet_send(dp->hw_drv, out_port, pkt, 0); + if ((rv < 0) && (rv != OF_HW_PORT_DOWN)) { + VLOG_ERR("Error %d sending pkt on HW port %d\n", + rv, out_port); + ofpbuf_delete(buffer); + free(pkt); + } + } + } + return; + } + + /* Fall through to software controlled ports if not HW port */ +#endif + + if (p && p->netdev != NULL) { + if (!(p->config & OFPPC_PORT_DOWN)) { + /* avoid the queue lookup for best-effort traffic */ + if (queue_id == 0) { + class_id = 0; + } + else { + /* silently drop the packet if queue doesn't exist */ + q = dp_lookup_queue(p, queue_id); + if (q) { + class_id = q->class_id; + } + else { + goto error; + } + } + + if (!netdev_send(p->netdev, buffer, class_id)) { + p->tx_packets++; + p->tx_bytes += buffer->size; + if (q) { + q->tx_packets++; + q->tx_bytes += buffer->size; + } + } else { + p->tx_dropped++; + } + } + ofpbuf_delete(buffer); + return; + } + + error: + ofpbuf_delete(buffer); + VLOG_DBG_RL(&rl, "can't forward to bad port:queue(%d:%d)\n", out_port, + queue_id); +} + +/** Takes ownership of 'buffer' and transmits it to 'out_port' on 'dp'. + */ +void +dp_output_port(struct datapath *dp, struct ofpbuf *buffer, + int in_port, int out_port, uint32_t queue_id, + bool ignore_no_fwd UNUSED) +{ + + assert(buffer); + switch (out_port) { + case OFPP_IN_PORT: + output_packet(dp, buffer, in_port, queue_id); + break; + + case OFPP_TABLE: { + struct sw_port *p = dp_lookup_port(dp, in_port); + if (run_flow_through_tables(dp, buffer, p)) { + ofpbuf_delete(buffer); + } + break; + } + + case OFPP_FLOOD: + output_all(dp, buffer, in_port, 1); + break; + + case OFPP_ALL: + output_all(dp, buffer, in_port, 0); + break; + + case OFPP_CONTROLLER: + dp_output_control(dp, buffer, in_port, UINT16_MAX, OFPR_ACTION); + break; + + case OFPP_LOCAL: + default: + if (in_port == out_port) { + VLOG_DBG_RL(&rl, "can't directly forward to input port"); + return; + } + output_packet(dp, buffer, out_port, queue_id); + break; + } +} + +static void * +make_openflow_reply(size_t openflow_len, uint8_t type, + const struct sender *sender, struct ofpbuf **bufferp) +{ + return make_openflow_xid(openflow_len, type, sender ? sender->xid : 0, + bufferp); +} + +static int +send_openflow_buffer_to_remote(struct ofpbuf *buffer, struct remote *remote) +{ + int retval = rconn_send_with_limit(remote->rconn, buffer, &remote->n_txq, + TXQ_LIMIT); + if (retval) { + VLOG_WARN_RL(&rl, "send to %s failed: %s", + rconn_get_name(remote->rconn), strerror(retval)); + } + return retval; +} + +static int +send_openflow_buffer(struct datapath *dp, struct ofpbuf *buffer, + const struct sender *sender) +{ + update_openflow_length(buffer); + if (sender) { + /* Send back to the sender. */ + return send_openflow_buffer_to_remote(buffer, sender->remote); + } else { + /* Broadcast to all remotes. */ + struct remote *r, *prev = NULL; + LIST_FOR_EACH (r, struct remote, node, &dp->remotes) { + if (prev) { + send_openflow_buffer_to_remote(ofpbuf_clone(buffer), prev); + } + prev = r; + } + if (prev) { + send_openflow_buffer_to_remote(buffer, prev); + } else { + ofpbuf_delete(buffer); + } + return 0; + } +} + +/* Takes ownership of 'buffer' and transmits it to 'dp''s controller. If the + * packet can be saved in a buffer, then only the first max_len bytes of + * 'buffer' are sent; otherwise, all of 'buffer' is sent. 'reason' indicates + * why 'buffer' is being sent. 'max_len' sets the maximum number of bytes that + * the caller wants to be sent. */ +void +dp_output_control(struct datapath *dp, struct ofpbuf *buffer, int in_port, + size_t max_len, int reason) +{ + struct ofp_packet_in *opi; + size_t total_len; + uint32_t buffer_id; + + buffer_id = save_buffer(buffer); + total_len = buffer->size; + if (buffer_id != UINT32_MAX && buffer->size > max_len) { + buffer->size = max_len; + } + + opi = ofpbuf_push_uninit(buffer, offsetof(struct ofp_packet_in, data)); + opi->header.version = OFP_VERSION; + opi->header.type = OFPT_PACKET_IN; + opi->header.length = htons(buffer->size); + opi->header.xid = htonl(0); + opi->buffer_id = htonl(buffer_id); + opi->total_len = htons(total_len); + opi->in_port = htons(in_port); + opi->reason = reason; + opi->pad = 0; + send_openflow_buffer(dp, buffer, NULL); +} + +static void +fill_queue_desc(struct ofpbuf *buffer, struct sw_queue *q, + struct ofp_packet_queue *desc) +{ + struct ofp_queue_prop_min_rate *mr; + int len; + + len = sizeof(struct ofp_packet_queue) + + sizeof(struct ofp_queue_prop_min_rate); + desc->queue_id = htonl(q->queue_id); + desc->len = htons(len); + + /* Property list */ + mr = ofpbuf_put_zeros(buffer, sizeof *mr); + mr->prop_header.property = htons(OFPQT_MIN_RATE); + len = sizeof(struct ofp_queue_prop_min_rate); + mr->prop_header.len = htons(len); + mr->rate = htons(q->min_rate); +} + + +static void +fill_port_desc(struct sw_port *p, struct ofp_phy_port *desc) +{ + desc->port_no = htons(p->port_no); + if (IS_HW_PORT(p)) { +#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) + of_hw_driver_t *hw_drv; + + hw_drv = p->dp->hw_drv; + strncpy((char *) desc->name, p->hw_name, sizeof desc->name); + desc->name[sizeof desc->name - 1] = '\0'; + /* Update local port state */ + if (hw_drv->port_link_get(hw_drv, p->port_no)) { + p->state &= ~OFPPS_LINK_DOWN; + } else { + p->state |= OFPPS_LINK_DOWN; + } + if (hw_drv->port_enable_get(hw_drv, p->port_no)) { + p->config &= ~OFPPC_PORT_DOWN; + } else { + p->config |= OFPPC_PORT_DOWN; + } + /* FIXME: Add current, supported and advertised features */ +#endif + } else if (p->netdev) { + strncpy((char *) desc->name, netdev_get_name(p->netdev), + sizeof desc->name); + desc->name[sizeof desc->name - 1] = '\0'; + memcpy(desc->hw_addr, netdev_get_etheraddr(p->netdev), ETH_ADDR_LEN); + desc->curr= htonl(netdev_get_features(p->netdev, + NETDEV_FEAT_CURRENT)); + desc->supported = htonl(netdev_get_features(p->netdev, + NETDEV_FEAT_SUPPORTED)); + desc->advertised = htonl(netdev_get_features(p->netdev, + NETDEV_FEAT_ADVERTISED)); + desc->peer = htonl(netdev_get_features(p->netdev, NETDEV_FEAT_PEER)); + } + desc->config = htonl(p->config); + desc->state = htonl(p->state); +} + +static void +dp_send_features_reply(struct datapath *dp, const struct sender *sender) +{ + struct ofpbuf *buffer; + struct ofp_switch_features *ofr; + struct sw_port *p; + + ofr = make_openflow_reply(sizeof *ofr, OFPT_FEATURES_REPLY, + sender, &buffer); + ofr->datapath_id = htonll(dp->id); + ofr->n_tables = dp->chain->n_tables; + ofr->n_buffers = htonl(N_PKT_BUFFERS); + ofr->capabilities = htonl(OFP_SUPPORTED_CAPABILITIES); + ofr->actions = htonl(OFP_SUPPORTED_ACTIONS); + LIST_FOR_EACH (p, struct sw_port, node, &dp->port_list) { + struct ofp_phy_port *opp = ofpbuf_put_uninit(buffer, sizeof *opp); + memset(opp, 0, sizeof *opp); + fill_port_desc(p, opp); + } + send_openflow_buffer(dp, buffer, sender); +} + +void +update_port_flags(struct datapath *dp, const struct ofp_port_mod *opm) +{ + struct sw_port *p = dp_lookup_port(dp, ntohs(opm->port_no)); + + /* Make sure the port id hasn't changed since this was sent */ + if (!p || memcmp(opm->hw_addr, netdev_get_etheraddr(p->netdev), + ETH_ADDR_LEN) != 0) { + return; + } + + + if (opm->mask) { + uint32_t config_mask = ntohl(opm->mask); + p->config &= ~config_mask; + p->config |= ntohl(opm->config) & config_mask; + } +} + +static void +send_port_status(struct sw_port *p, uint8_t status) +{ + struct ofpbuf *buffer; + struct ofp_port_status *ops; + ops = make_openflow_xid(sizeof *ops, OFPT_PORT_STATUS, 0, &buffer); + ops->reason = status; + memset(ops->pad, 0, sizeof ops->pad); + fill_port_desc(p, &ops->desc); + + send_openflow_buffer(p->dp, buffer, NULL); +} + +void +dp_send_flow_end(struct datapath *dp, struct sw_flow *flow, + enum ofp_flow_removed_reason reason) +{ + struct ofpbuf *buffer; + struct ofp_flow_removed *ofr; + uint64_t tdiff = time_msec() - flow->created; + uint32_t sec = tdiff / 1000; + + if (!flow->send_flow_rem) { + return; + } + + if (flow->emerg_flow) { + return; + } + + ofr = make_openflow_xid(sizeof *ofr, OFPT_FLOW_REMOVED, 0, &buffer); + if (!ofr) { + return; + } + + flow_fill_match(&ofr->match, &flow->key.flow, flow->key.wildcards); + + ofr->cookie = htonll(flow->cookie); + ofr->priority = htons(flow->priority); + ofr->reason = reason; + + ofr->duration_sec = htonl(sec); + ofr->duration_nsec = htonl((tdiff - (sec * 1000)) * 1000000); + ofr->idle_timeout = htons(flow->idle_timeout); + + ofr->packet_count = htonll(flow->packet_count); + ofr->byte_count = htonll(flow->byte_count); + + send_openflow_buffer(dp, buffer, NULL); +} + +void +dp_send_error_msg(struct datapath *dp, const struct sender *sender, + uint16_t type, uint16_t code, const void *data, size_t len) +{ + struct ofpbuf *buffer; + struct ofp_error_msg *oem; + oem = make_openflow_reply(sizeof(*oem)+len, OFPT_ERROR, sender, &buffer); + oem->type = htons(type); + oem->code = htons(code); + memcpy(oem->data, data, len); + send_openflow_buffer(dp, buffer, sender); +} + +static void +fill_flow_stats(struct ofpbuf *buffer, struct sw_flow *flow, + int table_idx, uint64_t now) +{ + struct ofp_flow_stats *ofs; + int length = sizeof *ofs + flow->sf_acts->actions_len; + uint64_t tdiff = now - flow->created; + uint32_t sec = tdiff / 1000; + ofs = ofpbuf_put_uninit(buffer, length); + ofs->length = htons(length); + ofs->table_id = table_idx; + ofs->pad = 0; + ofs->match.wildcards = htonl(flow->key.wildcards); + ofs->match.in_port = flow->key.flow.in_port; + memcpy(ofs->match.dl_src, flow->key.flow.dl_src, ETH_ADDR_LEN); + memcpy(ofs->match.dl_dst, flow->key.flow.dl_dst, ETH_ADDR_LEN); + ofs->match.dl_vlan = flow->key.flow.dl_vlan; + ofs->match.dl_type = flow->key.flow.dl_type; + ofs->match.nw_tos = flow->key.flow.nw_tos; + ofs->match.nw_src = flow->key.flow.nw_src; + ofs->match.nw_dst = flow->key.flow.nw_dst; + ofs->match.nw_proto = flow->key.flow.nw_proto; + ofs->match.dl_vlan_pcp = flow->key.flow.dl_vlan_pcp; + ofs->match.tp_src = flow->key.flow.tp_src; + ofs->match.tp_dst = flow->key.flow.tp_dst; + ofs->duration_sec = htonl(sec); + ofs->duration_nsec = htonl((tdiff - (sec * 1000)) * 1000000); + ofs->cookie = htonll(flow->cookie); + ofs->priority = htons(flow->priority); + ofs->idle_timeout = htons(flow->idle_timeout); + ofs->hard_timeout = htons(flow->hard_timeout); + memset(&ofs->pad2, 0, sizeof ofs->pad2); + ofs->packet_count = htonll(flow->packet_count); + ofs->byte_count = htonll(flow->byte_count); + memcpy(ofs->actions, flow->sf_acts->actions, flow->sf_acts->actions_len); +} + + +/* 'buffer' was received on 'p', which may be a a physical switch port or a + * null pointer. Process it according to 'dp''s flow table. Returns 0 if + * successful, in which case 'buffer' is destroyed, or -ESRCH if there is no + * matching flow, in which case 'buffer' still belongs to the caller. */ +int run_flow_through_tables(struct datapath *dp, struct ofpbuf *buffer, + struct sw_port *p) +{ + struct sw_flow_key key; + struct sw_flow *flow; + + key.wildcards = 0; + if (flow_extract(buffer, p ? p->port_no : OFPP_NONE, &key.flow) + && (dp->flags & OFPC_FRAG_MASK) == OFPC_FRAG_DROP) { + /* Drop fragment. */ + ofpbuf_delete(buffer); + return 0; + } + + if (p && p->config & (OFPPC_NO_RECV | OFPPC_NO_RECV_STP) + && p->config & (!eth_addr_equals(key.flow.dl_dst, stp_eth_addr) + ? OFPPC_NO_RECV : OFPPC_NO_RECV_STP)) { + ofpbuf_delete(buffer); + return 0; + } + + flow = chain_lookup(dp->chain, &key, 0); + if (flow != NULL) { + flow_used(flow, buffer); + execute_actions(dp, buffer, &key, flow->sf_acts->actions, + flow->sf_acts->actions_len, false); + return 0; + } else { + return -ESRCH; + } +} + +/* 'buffer' was received on 'p', which may be a a physical switch port or a + * null pointer. Process it according to 'dp''s flow table, sending it up to + * the controller if no flow matches. Takes ownership of 'buffer'. */ +void fwd_port_input(struct datapath *dp, struct ofpbuf *buffer, + struct sw_port *p) +{ + if (run_flow_through_tables(dp, buffer, p)) { + dp_output_control(dp, buffer, p->port_no, + dp->miss_send_len, OFPR_NO_MATCH); + } +} + +static struct ofpbuf * +make_barrier_reply(const struct ofp_header *req) +{ + size_t size = ntohs(req->length); + struct ofpbuf *buf = ofpbuf_new(size); + struct ofp_header *reply = ofpbuf_put(buf, req, size); + + reply->type = OFPT_BARRIER_REPLY; + return buf; +} + +static int +recv_barrier_request(struct datapath *dp, const struct sender *sender, + const void *ofph) +{ + return send_openflow_buffer(dp, make_barrier_reply(ofph), sender); +} + +static int +recv_features_request(struct datapath *dp, const struct sender *sender, + const void *msg UNUSED) +{ + dp_send_features_reply(dp, sender); + return 0; +} + +static int +recv_get_config_request(struct datapath *dp, const struct sender *sender, + const void *msg UNUSED) +{ + struct ofpbuf *buffer; + struct ofp_switch_config *osc; + + osc = make_openflow_reply(sizeof *osc, OFPT_GET_CONFIG_REPLY, + sender, &buffer); + + osc->flags = htons(dp->flags); + osc->miss_send_len = htons(dp->miss_send_len); + + return send_openflow_buffer(dp, buffer, sender); +} + +static int +recv_set_config(struct datapath *dp, const struct sender *sender UNUSED, + const void *msg) +{ + const struct ofp_switch_config *osc = msg; + int flags; + + flags = ntohs(osc->flags) & OFPC_FRAG_MASK; + if ((flags & OFPC_FRAG_MASK) != OFPC_FRAG_NORMAL + && (flags & OFPC_FRAG_MASK) != OFPC_FRAG_DROP) { + flags = (flags & ~OFPC_FRAG_MASK) | OFPC_FRAG_DROP; + } + dp->flags = flags; + dp->miss_send_len = ntohs(osc->miss_send_len); + return 0; +} + +static int +recv_packet_out(struct datapath *dp, const struct sender *sender, + const void *msg) +{ + const struct ofp_packet_out *opo = msg; + struct sw_flow_key key; + uint16_t v_code; + struct ofpbuf *buffer; + size_t actions_len = ntohs(opo->actions_len); + + if (actions_len > (ntohs(opo->header.length) - sizeof *opo)) { + VLOG_DBG_RL(&rl, "message too short for number of actions"); + return -EINVAL; + } + + if (ntohl(opo->buffer_id) == (uint32_t) -1) { + /* FIXME: can we avoid copying data here? */ + int data_len = ntohs(opo->header.length) - sizeof *opo - actions_len; + buffer = ofpbuf_new(data_len); + ofpbuf_put(buffer, (uint8_t *)opo->actions + actions_len, data_len); + } else { + buffer = retrieve_buffer(ntohl(opo->buffer_id)); + if (!buffer) { + return -ESRCH; + } + } + + flow_extract(buffer, ntohs(opo->in_port), &key.flow); + + v_code = validate_actions(dp, &key, opo->actions, actions_len); + if (v_code != ACT_VALIDATION_OK) { + dp_send_error_msg(dp, sender, OFPET_BAD_ACTION, v_code, + msg, ntohs(opo->header.length)); + goto error; + } + + execute_actions(dp, buffer, &key, opo->actions, actions_len, true); + + return 0; + +error: + ofpbuf_delete(buffer); + return -EINVAL; +} + +static int +recv_port_mod(struct datapath *dp, const struct sender *sender UNUSED, + const void *msg) +{ + const struct ofp_port_mod *opm = msg; + + update_port_flags(dp, opm); + + return 0; +} + +static int +add_flow(struct datapath *dp, const struct sender *sender, + const struct ofp_flow_mod *ofm) +{ + int error = -ENOMEM; + uint16_t v_code; + struct sw_flow *flow; + size_t actions_len = ntohs(ofm->header.length) - sizeof *ofm; + int overlap; + + /* Allocate memory. */ + flow = flow_alloc(actions_len); + if (flow == NULL) + goto error; + + flow_extract_match(&flow->key, &ofm->match); + + v_code = validate_actions(dp, &flow->key, ofm->actions, actions_len); + if (v_code != ACT_VALIDATION_OK) { + dp_send_error_msg(dp, sender, OFPET_BAD_ACTION, v_code, + ofm, ntohs(ofm->header.length)); + goto error_free_flow; + } + + flow->priority = flow->key.wildcards ? ntohs(ofm->priority) : -1; + + if (ntohs(ofm->flags) & OFPFF_CHECK_OVERLAP) { + /* check whether there is any conflict */ + overlap = chain_has_conflict(dp->chain, &flow->key, flow->priority, + false); + if (overlap){ + dp_send_error_msg(dp, sender, OFPET_FLOW_MOD_FAILED, + OFPFMFC_OVERLAP, ofm, ntohs(ofm->header.length)); + goto error_free_flow; + } + } + + if (ntohs(ofm->flags) & OFPFF_EMERG) { + if (ntohs(ofm->idle_timeout) != OFP_FLOW_PERMANENT + || ntohs(ofm->hard_timeout) != OFP_FLOW_PERMANENT) { + dp_send_error_msg(dp, sender, OFPET_FLOW_MOD_FAILED, + OFPFMFC_BAD_EMERG_TIMEOUT, ofm, + ntohs(ofm->header.length)); + goto error_free_flow; + } + } + + /* Fill out flow. */ + flow->cookie = ntohll(ofm->cookie); + flow->idle_timeout = ntohs(ofm->idle_timeout); + flow->hard_timeout = ntohs(ofm->hard_timeout); + flow->send_flow_rem = (ntohs(ofm->flags) & OFPFF_SEND_FLOW_REM) ? 1 : 0; + flow->emerg_flow = (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0; + flow_setup_actions(flow, ofm->actions, actions_len); + + /* Act. */ + error = chain_insert(dp->chain, flow, + (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0); + if (error == -ENOBUFS) { + dp_send_error_msg(dp, sender, OFPET_FLOW_MOD_FAILED, + OFPFMFC_ALL_TABLES_FULL, ofm, ntohs(ofm->header.length)); + goto error_free_flow; + } else if (error) { + goto error_free_flow; + } + + error = 0; + if (ntohl(ofm->buffer_id) != UINT32_MAX) { + struct ofpbuf *buffer = retrieve_buffer(ntohl(ofm->buffer_id)); + if (buffer) { + struct sw_flow_key key; + uint16_t in_port = ntohs(ofm->match.in_port); + flow_extract(buffer, in_port, &key.flow); + flow_used(flow, buffer); + execute_actions(dp, buffer, &key, + ofm->actions, actions_len, false); + } else { + error = -ESRCH; + } + } + return error; + +error_free_flow: + flow_free(flow); +error: + if (ntohl(ofm->buffer_id) != (uint32_t) -1) + discard_buffer(ntohl(ofm->buffer_id)); + return error; +} + +static int +mod_flow(struct datapath *dp, const struct sender *sender, + const struct ofp_flow_mod *ofm) +{ + int error = -ENOMEM; + uint16_t v_code; + size_t actions_len = ntohs(ofm->header.length) - sizeof *ofm; + struct sw_flow *flow; + int strict; + + /* Allocate memory. */ + flow = flow_alloc(actions_len); + if (flow == NULL) + goto error; + + flow_extract_match(&flow->key, &ofm->match); + + v_code = validate_actions(dp, &flow->key, ofm->actions, actions_len); + if (v_code != ACT_VALIDATION_OK) { + dp_send_error_msg(dp, sender, OFPET_BAD_ACTION, v_code, + ofm, ntohs(ofm->header.length)); + goto error_free_flow; + } + + flow->priority = flow->key.wildcards ? ntohs(ofm->priority) : -1; + strict = (ofm->command == htons(OFPFC_MODIFY_STRICT)) ? 1 : 0; + + /* First try to modify existing flows if any */ + /* if there is no matching flow, add it */ + if (!chain_modify(dp->chain, &flow->key, flow->priority, + strict, ofm->actions, actions_len, + (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0)) { + /* Fill out flow. */ + flow->cookie = ntohll(ofm->cookie); + flow->idle_timeout = ntohs(ofm->idle_timeout); + flow->hard_timeout = ntohs(ofm->hard_timeout); + flow->send_flow_rem = (ntohs(ofm->flags) & OFPFF_SEND_FLOW_REM) ? 1 : 0; + flow->emerg_flow = (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0; + flow_setup_actions(flow, ofm->actions, actions_len); + error = chain_insert(dp->chain, flow, + (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0); + if (error == -ENOBUFS) { + dp_send_error_msg(dp, sender, OFPET_FLOW_MOD_FAILED, + OFPFMFC_ALL_TABLES_FULL, ofm, + ntohs(ofm->header.length)); + goto error_free_flow; + } else if (error) { + goto error_free_flow; + } + } + + error = 0; + if (ntohl(ofm->buffer_id) != UINT32_MAX) { + struct ofpbuf *buffer = retrieve_buffer(ntohl(ofm->buffer_id)); + if (buffer) { + struct sw_flow_key skb_key; + uint16_t in_port = ntohs(ofm->match.in_port); + flow_extract(buffer, in_port, &skb_key.flow); + execute_actions(dp, buffer, &skb_key, + ofm->actions, actions_len, false); + } else { + error = -ESRCH; + } + } + return error; + +error_free_flow: + flow_free(flow); +error: + if (ntohl(ofm->buffer_id) != (uint32_t) -1) + discard_buffer(ntohl(ofm->buffer_id)); + return error; +} + +static int +recv_flow(struct datapath *dp, const struct sender *sender, + const void *msg) +{ + const struct ofp_flow_mod *ofm = msg; + uint16_t command = ntohs(ofm->command); + + if (command == OFPFC_ADD) { + return add_flow(dp, sender, ofm); + } else if ((command == OFPFC_MODIFY) || (command == OFPFC_MODIFY_STRICT)) { + return mod_flow(dp, sender, ofm); + } else if (command == OFPFC_DELETE) { + struct sw_flow_key key; + flow_extract_match(&key, &ofm->match); + return chain_delete(dp->chain, &key, ofm->out_port, 0, 0, + (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0) + ? 0 : -ESRCH; + } else if (command == OFPFC_DELETE_STRICT) { + struct sw_flow_key key; + uint16_t priority; + flow_extract_match(&key, &ofm->match); + priority = key.wildcards ? ntohs(ofm->priority) : -1; + return chain_delete(dp->chain, &key, ofm->out_port, priority, 1, + (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0) + ? 0 : -ESRCH; + } else { + return -ENODEV; + } +} + +static int +desc_stats_dump(struct datapath *dp UNUSED, void *state UNUSED, + struct ofpbuf *buffer) +{ + struct ofp_desc_stats *ods = ofpbuf_put_uninit(buffer, sizeof *ods); + + strncpy(ods->mfr_desc, &mfr_desc, sizeof ods->mfr_desc); + strncpy(ods->hw_desc, &hw_desc, sizeof ods->hw_desc); + strncpy(ods->sw_desc, &sw_desc, sizeof ods->sw_desc); + strncpy(ods->dp_desc, dp->dp_desc, sizeof ods->dp_desc); + strncpy(ods->serial_num, &serial_num, sizeof ods->serial_num); + + return 0; +} + +struct flow_stats_state { + int table_idx; + struct sw_table_position position; + struct ofp_flow_stats_request rq; + uint64_t now; /* Current time in milliseconds */ + + struct ofpbuf *buffer; +}; + +#define MAX_FLOW_STATS_BYTES 4096 +#define EMERG_TABLE_ID_FOR_STATS 0xfe + +static int +flow_stats_init(const void *body, int body_len UNUSED, void **state) +{ + const struct ofp_flow_stats_request *fsr = body; + struct flow_stats_state *s = xmalloc(sizeof *s); + s->table_idx = fsr->table_id == 0xff ? 0 : fsr->table_id; + memset(&s->position, 0, sizeof s->position); + s->rq = *fsr; + *state = s; + return 0; +} + +static int flow_stats_dump_callback(struct sw_flow *flow, void *private) +{ + struct flow_stats_state *s = private; + fill_flow_stats(s->buffer, flow, s->table_idx, s->now); + return s->buffer->size >= MAX_FLOW_STATS_BYTES; +} + +static int flow_stats_dump(struct datapath *dp, void *state, + struct ofpbuf *buffer) +{ + struct flow_stats_state *s = state; + struct sw_flow_key match_key; + + flow_extract_match(&match_key, &s->rq.match); + s->buffer = buffer; + s->now = time_msec(); + + if (s->rq.table_id == EMERG_TABLE_ID_FOR_STATS) { + struct sw_table *table = dp->chain->emerg_table; + + table->iterate(table, &match_key, s->rq.out_port, + &s->position, flow_stats_dump_callback, s); + } else { + while (s->table_idx < dp->chain->n_tables + && (s->rq.table_id == 0xff || s->rq.table_id == s->table_idx)) + { + struct sw_table *table = dp->chain->tables[s->table_idx]; + + if (table->iterate(table, &match_key, s->rq.out_port, + &s->position, flow_stats_dump_callback, s)) + break; + + s->table_idx++; + memset(&s->position, 0, sizeof s->position); + } + } + return s->buffer->size >= MAX_FLOW_STATS_BYTES; +} + +static void flow_stats_done(void *state) +{ + free(state); +} + +struct aggregate_stats_state { + struct ofp_aggregate_stats_request rq; +}; + +static int +aggregate_stats_init(const void *body, int body_len UNUSED, void **state) +{ + const struct ofp_aggregate_stats_request *rq = body; + struct aggregate_stats_state *s = xmalloc(sizeof *s); + s->rq = *rq; + *state = s; + return 0; +} + +static int aggregate_stats_dump_callback(struct sw_flow *flow, void *private) +{ + struct ofp_aggregate_stats_reply *rpy = private; + rpy->packet_count += flow->packet_count; + rpy->byte_count += flow->byte_count; + rpy->flow_count++; + return 0; +} + +static int aggregate_stats_dump(struct datapath *dp, void *state, + struct ofpbuf *buffer) +{ + struct aggregate_stats_state *s = state; + struct ofp_aggregate_stats_request *rq = &s->rq; + struct ofp_aggregate_stats_reply *rpy; + struct sw_table_position position; + struct sw_flow_key match_key; + int table_idx; + int error; + + rpy = ofpbuf_put_uninit(buffer, sizeof *rpy); + memset(rpy, 0, sizeof *rpy); + + flow_extract_match(&match_key, &rq->match); + table_idx = rq->table_id == 0xff ? 0 : rq->table_id; + memset(&position, 0, sizeof position); + + if (rq->table_id == EMERG_TABLE_ID_FOR_STATS) { + struct sw_table *table = dp->chain->emerg_table; + + error = table->iterate(table, &match_key, rq->out_port, &position, + aggregate_stats_dump_callback, rpy); + if (error) + return error; + } else { + while (table_idx < dp->chain->n_tables + && (rq->table_id == 0xff || rq->table_id == table_idx)) + { + struct sw_table *table = dp->chain->tables[table_idx]; + + error = table->iterate(table, &match_key, rq->out_port, &position, + aggregate_stats_dump_callback, rpy); + if (error) + return error; + + table_idx++; + memset(&position, 0, sizeof position); + } + } + + rpy->packet_count = htonll(rpy->packet_count); + rpy->byte_count = htonll(rpy->byte_count); + rpy->flow_count = htonl(rpy->flow_count); + return 0; +} + +static void aggregate_stats_done(void *state) +{ + free(state); +} + +static int +table_stats_dump(struct datapath *dp, void *state UNUSED, + struct ofpbuf *buffer) +{ + int i; + for (i = 0; i < dp->chain->n_tables; i++) { + struct ofp_table_stats *ots = ofpbuf_put_uninit(buffer, sizeof *ots); + struct sw_table_stats stats; + dp->chain->tables[i]->stats(dp->chain->tables[i], &stats); + strncpy(ots->name, stats.name, sizeof ots->name); + ots->table_id = i; + ots->wildcards = htonl(stats.wildcards); + memset(ots->pad, 0, sizeof ots->pad); + ots->max_entries = htonl(stats.max_flows); + ots->active_count = htonl(stats.n_flows); + ots->lookup_count = htonll(stats.n_lookup); + ots->matched_count = htonll(stats.n_matched); + } + return 0; +} + +struct port_stats_state { + int start_port; /* port to start dumping from */ + int port_no; /* from ofp_stats_request */ +}; + +struct queue_stats_state { + uint16_t port; + uint32_t queue_id; +}; + +static int +port_stats_init(const void *body, int body_len UNUSED, void **state) +{ + struct port_stats_state *s = xmalloc(sizeof *s); + const struct ofp_port_stats_request *psr = body; + + s->start_port = 1; + s->port_no = ntohs(psr->port_no); + *state = s; + return 0; +} + +static void +dump_port_stats(struct datapath *dp, struct sw_port *port, + struct ofpbuf *buffer) +{ + struct ofp_port_stats *ops = ofpbuf_put_uninit(buffer, sizeof *ops); + ops->port_no = htons(port->port_no); + memset(ops->pad, 0, sizeof ops->pad); + if (IS_HW_PORT(port)) { +#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) + struct ofp_port_stats stats; + + memset(&stats, 0, sizeof(stats)); + if (dp->hw_drv->port_stats_get) { + if (dp->hw_drv->port_stats_get(dp->hw_drv, port->port_no, + &stats) < 0) { + VLOG_WARN("Error getting stats on port %d\n", port->port_no); + return; + } + } + ops->rx_packets = htonll(stats.rx_packets); + ops->tx_packets = htonll(stats.tx_packets); + ops->rx_bytes = htonll(stats.rx_bytes); + ops->tx_bytes = htonll(stats.tx_bytes); + ops->rx_dropped = htonll(stats.rx_dropped); + ops->tx_dropped = htonll(stats.tx_dropped); + ops->rx_errors = htonll(stats.rx_errors); + ops->tx_errors = htonll(stats.tx_errors); + ops->rx_frame_err = htonll(stats.rx_frame_err); + ops->rx_over_err = htonll(stats.rx_over_err); + ops->rx_crc_err = htonll(stats.rx_crc_err); + ops->collisions = htonll(stats.collisions); +#endif + } else { + ops->rx_packets = htonll(port->rx_packets); + ops->tx_packets = htonll(port->tx_packets); + ops->rx_bytes = htonll(port->rx_bytes); + ops->tx_bytes = htonll(port->tx_bytes); + ops->rx_dropped = htonll(-1); + ops->tx_dropped = htonll(port->tx_dropped); + ops->rx_errors = htonll(-1); + ops->tx_errors = htonll(-1); + ops->rx_frame_err = htonll(-1); + ops->rx_over_err = htonll(-1); + ops->rx_crc_err = htonll(-1); + ops->collisions = htonll(-1); + } +} + +/* Although this makes some of the motions of being called + * multiple times preserving state, it doesn't actually support + * that process; the for loop can never break early. + */ +static int port_stats_dump(struct datapath *dp, void *state, + struct ofpbuf *buffer) +{ + struct port_stats_state *s = state; + struct sw_port *p = NULL; + int i = 0; + + if (s->port_no == OFPP_NONE) { + /* Dump statistics for all ports */ + for (i = s->start_port; i < DP_MAX_PORTS; i++) { + p = dp_lookup_port(dp, i); + if (p && PORT_IN_USE(p)) { + dump_port_stats(dp, p, buffer); + } + } + if (dp->local_port) { + dump_port_stats(dp, dp->local_port, buffer); + } + } else { + /* Dump statistics for a single port */ + p = dp_lookup_port(dp, s->port_no); + if (p && PORT_IN_USE(p)) { + dump_port_stats(dp, p, buffer); + } + } + + return 0; +} + +static void port_stats_done(void *state) +{ + free(state); +} + +static int +queue_stats_init(const void *body, int body_len UNUSED, void **state) +{ + const struct ofp_queue_stats_request *qsr = body; + struct queue_stats_state *s = xmalloc(sizeof *s); + s->port = ntohs(qsr->port_no); + s->queue_id = ntohl(qsr->queue_id); + *state = s; + return 0; +} + +static void +dump_queue_stats(struct sw_queue *q, struct ofpbuf *buffer) +{ + struct ofp_queue_stats *oqs = ofpbuf_put_uninit(buffer, sizeof *oqs); + oqs->port_no = htons(q->port->port_no); + oqs->queue_id = htonl(q->queue_id); + oqs->tx_bytes = htonll(q->tx_bytes); + oqs->tx_packets = htonll(q->tx_packets); + oqs->tx_errors = htonll(q->tx_errors); +} + +static int +queue_stats_dump(struct datapath *dp, void *state, + struct ofpbuf *buffer) +{ + struct queue_stats_state *s = state; + struct sw_queue *q; + struct sw_port *p; + + + if (s->port == OFPP_ALL) { + LIST_FOR_EACH(p, struct sw_port, node, &dp->port_list) { + if (p->port_no < OFPP_MAX) { + if (s->queue_id == OFPQ_ALL) { + LIST_FOR_EACH(q, struct sw_queue, node, &p->queue_list) { + dump_queue_stats(q,buffer); + } + } + else { + q = dp_lookup_queue(p, s->queue_id); + if (q) { + dump_queue_stats(q, buffer); + } + } + } + } + } + else { + p = dp_lookup_port(dp, s->port); + if (p) { + if (s->queue_id == OFPQ_ALL) { + LIST_FOR_EACH(q, struct sw_queue, node, &p->queue_list) { + dump_queue_stats(q,buffer); + } + } + else { + q = dp_lookup_queue(p, s->queue_id); + if (q) { + dump_queue_stats(q, buffer); + } + } + } + } + return 0; +} + +static void +queue_stats_done(void *state) +{ + free(state); +} + +/* + * We don't define any vendor_stats_state, we let the actual + * vendor implementation do that. + * The only requirement is that the first member of that object + * should be the vendor id. + * Jean II + * + * Basically, it would look like : + * struct acme_stats_state { + * uint32_t vendor; // ACME_VENDOR_ID. + * <...> // Other stuff. + * }; + */ +static int +vendor_stats_init(const void *body, int body_len UNUSED, + void **state UNUSED) +{ + /* min_body was checked, this should be safe */ + const uint32_t vendor = ntohl(*((uint32_t *)body)); + int err; + + switch (vendor) { + default: + err = -EINVAL; + } + + return err; +} + +static int +vendor_stats_dump(struct datapath *dp UNUSED, void *state, + struct ofpbuf *buffer UNUSED) +{ + const uint32_t vendor = *((uint32_t *)state); + int err; + + switch (vendor) { + default: + /* Should never happen */ + err = 0; + } + + return err; +} + +static void +vendor_stats_done(void *state) +{ + const uint32_t vendor = *((uint32_t *) state); + + switch (vendor) { + default: + /* Should never happen */ + free(state); + } + + return; +} + +struct stats_type { + /* Value for 'type' member of struct ofp_stats_request. */ + int type; + + /* Minimum and maximum acceptable number of bytes in body member of + * struct ofp_stats_request. */ + size_t min_body, max_body; + + /* Prepares to dump some kind of datapath statistics. 'body' and + * 'body_len' are the 'body' member of the struct ofp_stats_request. + * Returns zero if successful, otherwise a negative error code. + * May initialize '*state' to state information. May be null if no + * initialization is required.*/ + int (*init)(const void *body, int body_len, void **state); + + /* Appends statistics for 'dp' to 'buffer', which initially contains a + * struct ofp_stats_reply. On success, it should return 1 if it should be + * called again later with another buffer, 0 if it is done, or a negative + * errno value on failure. */ + int (*dump)(struct datapath *dp, void *state, struct ofpbuf *buffer); + + /* Cleans any state created by the init or dump functions. May be null + * if no cleanup is required. */ + void (*done)(void *state); +}; + +static const struct stats_type stats[] = { + { + OFPST_DESC, + 0, + 0, + NULL, + desc_stats_dump, + NULL + }, + { + OFPST_FLOW, + sizeof(struct ofp_flow_stats_request), + sizeof(struct ofp_flow_stats_request), + flow_stats_init, + flow_stats_dump, + flow_stats_done + }, + { + OFPST_AGGREGATE, + sizeof(struct ofp_aggregate_stats_request), + sizeof(struct ofp_aggregate_stats_request), + aggregate_stats_init, + aggregate_stats_dump, + aggregate_stats_done + }, + { + OFPST_TABLE, + 0, + 0, + NULL, + table_stats_dump, + NULL + }, + { + OFPST_PORT, + sizeof(struct ofp_port_stats_request), + sizeof(struct ofp_port_stats_request), + port_stats_init, + port_stats_dump, + port_stats_done + }, + { + OFPST_QUEUE, + sizeof(struct ofp_queue_stats_request), + sizeof(struct ofp_queue_stats_request), + queue_stats_init, + queue_stats_dump, + queue_stats_done + }, + { + OFPST_VENDOR, + 8, /* vendor + subtype */ + 32, /* whatever */ + vendor_stats_init, + vendor_stats_dump, + vendor_stats_done + }, +}; + +struct stats_dump_cb { + bool done; + struct ofp_stats_request *rq; + struct sender sender; + const struct stats_type *s; + void *state; +}; + +static int +stats_dump(struct datapath *dp, void *cb_) +{ + struct stats_dump_cb *cb = cb_; + struct ofp_stats_reply *osr; + struct ofpbuf *buffer; + int err; + + if (cb->done) { + return 0; + } + + osr = make_openflow_reply(sizeof *osr, OFPT_STATS_REPLY, &cb->sender, + &buffer); + osr->type = htons(cb->s->type); + osr->flags = 0; + + err = cb->s->dump(dp, cb->state, buffer); + if (err >= 0) { + int err2; + if (!err) { + cb->done = true; + } else { + /* Buffer might have been reallocated, so find our data again. */ + osr = ofpbuf_at_assert(buffer, 0, sizeof *osr); + osr->flags = ntohs(OFPSF_REPLY_MORE); + } + err2 = send_openflow_buffer(dp, buffer, &cb->sender); + if (err2) { + err = err2; + } + } + + return err; +} + +static void +stats_done(void *cb_) +{ + struct stats_dump_cb *cb = cb_; + if (cb) { + if (cb->s->done) { + cb->s->done(cb->state); + } + if (cb->rq) { + free(cb->rq); + } + free(cb); + } +} + +static int +recv_stats_request(struct datapath *dp UNUSED, const struct sender *sender, + const void *oh) +{ + const struct ofp_stats_request *rq = oh; + size_t rq_len = ntohs(rq->header.length); + const struct stats_type *st; + struct stats_dump_cb *cb; + int type, body_len; + int err; + + type = ntohs(rq->type); + for (st = stats; ; st++) { + if (st >= &stats[ARRAY_SIZE(stats)]) { + VLOG_WARN_RL(&rl, "received stats request of unknown type %d", + type); + return -EINVAL; + } else if (type == st->type) { + break; + } + } + + cb = xmalloc(sizeof *cb); + cb->done = false; + cb->rq = xmemdup(rq, rq_len); + cb->sender = *sender; + cb->s = st; + cb->state = NULL; + + body_len = rq_len - offsetof(struct ofp_stats_request, body); + if (body_len < cb->s->min_body || body_len > cb->s->max_body) { + VLOG_WARN_RL(&rl, "stats request type %d with bad body length %d", + type, body_len); + err = -EINVAL; + goto error; + } + + if (cb->s->init) { + err = cb->s->init(rq->body, body_len, &cb->state); + if (err) { + VLOG_WARN_RL(&rl, + "failed initialization of stats request type %d: %s", + type, strerror(-err)); + goto error; + } + } + + remote_start_dump(sender->remote, stats_dump, stats_done, cb); + return 0; + +error: + free(cb->rq); + free(cb); + return err; +} + +static int +recv_echo_request(struct datapath *dp, const struct sender *sender, + const void *oh) +{ + return send_openflow_buffer(dp, make_echo_reply(oh), sender); +} + +static int +recv_echo_reply(struct datapath *dp UNUSED, const struct sender *sender UNUSED, + const void *oh UNUSED) +{ + return 0; +} + +static int +recv_queue_get_config_request(struct datapath *dp, const struct sender *sender, + const void *oh) +{ + struct ofpbuf *buffer; + struct ofp_queue_get_config_reply *ofq_reply; + const struct ofp_queue_get_config_request *ofq_request; + struct sw_port *p; + struct sw_queue *q; + uint16_t port_no; + + ofq_request = (struct ofp_queue_get_config_request *)oh; + port_no = ntohs(ofq_request->port); + + if (port_no < OFPP_MAX) { + /* Find port under query */ + p = dp_lookup_port(dp,port_no); + + /* if the port under query doesn't exist, send an error */ + if (!p || (p->port_no != port_no)) { + dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, OFPQOFC_BAD_PORT, + oh, ntohs(ofq_request->header.length)); + goto error; + } + ofq_reply = make_openflow_reply(sizeof *ofq_reply, OFPT_QUEUE_GET_CONFIG_REPLY, + sender, &buffer); + ofq_reply->port = htons(port_no); + LIST_FOR_EACH(q, struct sw_queue, node, &p->queue_list) { + struct ofp_packet_queue * opq = ofpbuf_put_zeros(buffer, sizeof *opq); + fill_queue_desc(buffer, q, opq); + } + send_openflow_buffer(dp, buffer, sender); + } + else { + dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, OFPQOFC_BAD_PORT, + oh, ntohs(ofq_request->header.length)); + } + error: + return 0; +} + +static int +recv_vendor(struct datapath *dp, const struct sender *sender, + const void *oh) +{ + const struct ofp_vendor_header *ovh = oh; + + switch (ntohl(ovh->vendor)) + { + case PRIVATE_VENDOR_ID: + return private_recv_msg(dp, sender, oh); + + case OPENFLOW_VENDOR_ID: + return of_ext_recv_msg(dp, sender, oh); + + default: + VLOG_WARN_RL(&rl, "unknown vendor: 0x%x\n", ntohl(ovh->vendor)); + dp_send_error_msg(dp, sender, OFPET_BAD_REQUEST, + OFPBRC_BAD_VENDOR, oh, ntohs(ovh->header.length)); + return -EINVAL; + } +} + +/* 'msg', which is 'length' bytes long, was received from the control path. + * Apply it to 'chain'. */ +int +fwd_control_input(struct datapath *dp, const struct sender *sender, + const void *msg, size_t length) +{ + int (*handler)(struct datapath *, const struct sender *, const void *); + struct ofp_header *oh; + size_t min_size; + + /* Check encapsulated length. */ + oh = (struct ofp_header *) msg; + if (ntohs(oh->length) > length) { + return -EINVAL; + } + assert(oh->version == OFP_VERSION); + + /* Figure out how to handle it. */ + switch (oh->type) { + case OFPT_BARRIER_REQUEST: + min_size = sizeof(struct ofp_header); + handler = recv_barrier_request; + break; + case OFPT_FEATURES_REQUEST: + min_size = sizeof(struct ofp_header); + handler = recv_features_request; + break; + case OFPT_GET_CONFIG_REQUEST: + min_size = sizeof(struct ofp_header); + handler = recv_get_config_request; + break; + case OFPT_SET_CONFIG: + min_size = sizeof(struct ofp_switch_config); + handler = recv_set_config; + break; + case OFPT_PACKET_OUT: + min_size = sizeof(struct ofp_packet_out); + handler = recv_packet_out; + break; + case OFPT_FLOW_MOD: + min_size = sizeof(struct ofp_flow_mod); + handler = recv_flow; + break; + case OFPT_PORT_MOD: + min_size = sizeof(struct ofp_port_mod); + handler = recv_port_mod; + break; + case OFPT_STATS_REQUEST: + min_size = sizeof(struct ofp_stats_request); + handler = recv_stats_request; + break; + case OFPT_ECHO_REQUEST: + min_size = sizeof(struct ofp_header); + handler = recv_echo_request; + break; + case OFPT_ECHO_REPLY: + min_size = sizeof(struct ofp_header); + handler = recv_echo_reply; + break; + case OFPT_QUEUE_GET_CONFIG_REQUEST: + min_size = sizeof(struct ofp_header); + handler = recv_queue_get_config_request; + break; + case OFPT_VENDOR: + min_size = sizeof(struct ofp_vendor_header); + handler = recv_vendor; + break; + default: + dp_send_error_msg(dp, sender, OFPET_BAD_REQUEST, OFPBRC_BAD_TYPE, + msg, length); + return -EINVAL; + } + + /* Handle it. */ + if (length < min_size) + return -EFAULT; + return handler(dp, sender, msg); +} + +/* Packet buffering. */ + +#define OVERWRITE_SECS 1 + +struct packet_buffer { + struct ofpbuf *buffer; + uint32_t cookie; + time_t timeout; +}; + +static struct packet_buffer buffers[N_PKT_BUFFERS]; +static unsigned int buffer_idx; + +uint32_t save_buffer(struct ofpbuf *buffer) +{ + struct packet_buffer *p; + uint32_t id; + + buffer_idx = (buffer_idx + 1) & PKT_BUFFER_MASK; + p = &buffers[buffer_idx]; + if (p->buffer) { + /* Don't buffer packet if existing entry is less than + * OVERWRITE_SECS old. */ + if (time_now() < p->timeout) { /* FIXME */ + return (uint32_t)-1; + } else { + ofpbuf_delete(p->buffer); + } + } + /* Don't use maximum cookie value since the all-bits-1 id is + * special. */ + if (++p->cookie >= (1u << PKT_COOKIE_BITS) - 1) + p->cookie = 0; + p->buffer = ofpbuf_clone(buffer); /* FIXME */ + p->timeout = time_now() + OVERWRITE_SECS; /* FIXME */ + id = buffer_idx | (p->cookie << PKT_BUFFER_BITS); + + return id; +} + +static struct ofpbuf *retrieve_buffer(uint32_t id) +{ + struct ofpbuf *buffer = NULL; + struct packet_buffer *p; + + p = &buffers[id & PKT_BUFFER_MASK]; + if (p->cookie == id >> PKT_BUFFER_BITS) { + buffer = p->buffer; + p->buffer = NULL; + } else { + printf("cookie mismatch: %x != %x\n", + id >> PKT_BUFFER_BITS, p->cookie); + } + + return buffer; +} + +static void discard_buffer(uint32_t id) +{ + struct packet_buffer *p; + + p = &buffers[id & PKT_BUFFER_MASK]; + if (p->cookie == id >> PKT_BUFFER_BITS) { + ofpbuf_delete(p->buffer); + p->buffer = NULL; + } +} diff --git a/openflow/udatapath/datapath.h b/openflow/udatapath/datapath.h new file mode 100644 index 00000000..c79c5ead --- /dev/null +++ b/openflow/udatapath/datapath.h @@ -0,0 +1,167 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +/* Interface exported by OpenFlow module. */ + +#ifndef DATAPATH_H +#define DATAPATH_H 1 + +#include +#include +#include "openflow/nicira-ext.h" +#include "ofpbuf.h" +#include "timeval.h" +#include "list.h" +#include "netdev.h" + +/* FIXME: Can declare struct of_hw_driver instead */ +#if defined(OF_HW_PLAT) +#include +#endif + +struct rconn; +struct pvconn; +struct sw_flow; +struct sender; + +struct sw_queue { + struct list node; /* element in port.queues */ + unsigned long long int tx_packets; + unsigned long long int tx_bytes; + unsigned long long int tx_errors; + uint32_t queue_id; + uint16_t class_id; /* internal mapping from OF queue_id to tc class_id */ + struct sw_port *port; /* reference to the parent port */ + /* keep it simple for now, only one property (assuming min_rate) */ + uint16_t property; /* one from OFPQT_ */ + uint16_t min_rate; +}; + +#define MAX_HW_NAME_LEN 32 +enum sw_port_flags { + SWP_USED = 1 << 0, /* Is port being used */ + SWP_HW_DRV_PORT = 1 << 1, /* Port controlled by HW driver */ +}; +#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) +#define IS_HW_PORT(p) ((p)->flags & SWP_HW_DRV_PORT) +#else +#define IS_HW_PORT(p) 0 +#endif + +#define PORT_IN_USE(p) (((p) != NULL) && (p)->flags & SWP_USED) + +struct sw_port { + uint32_t config; /* Some subset of OFPPC_* flags. */ + uint32_t state; /* Some subset of OFPPS_* flags. */ + uint32_t flags; /* SWP_* flags above */ + struct datapath *dp; + struct netdev *netdev; + char hw_name[OFP_MAX_PORT_NAME_LEN]; + struct list node; /* Element in datapath.ports. */ + unsigned long long int rx_packets, tx_packets; + unsigned long long int rx_bytes, tx_bytes; + unsigned long long int tx_dropped; + uint16_t port_no; + /* port queues */ + uint16_t num_queues; + struct sw_queue queues[NETDEV_MAX_QUEUES]; + struct list queue_list; /* list of all queues for this port */ +}; + +#if defined(OF_HW_PLAT) +struct hw_pkt_q_entry { + struct ofpbuf *buffer; + struct hw_pkt_q_entry *next; + of_port_t port_no; + int reason; +}; +#endif + +#define DP_MAX_PORTS 255 +BUILD_ASSERT_DECL(DP_MAX_PORTS <= OFPP_MAX); + +struct datapath { + /* Remote connections. */ + struct list remotes; /* All connections (including controller). */ + + /* Listeners. */ + struct pvconn **listeners; + size_t n_listeners; + + time_t last_timeout; + + /* Unique identifier for this datapath */ + uint64_t id; + char dp_desc[DESC_STR_LEN]; /* human readible comment to ID this DP */ + + struct sw_chain *chain; /* Forwarding rules. */ + + /* Configuration set from controller. */ + uint16_t flags; + uint16_t miss_send_len; + + /* Switch ports. */ + struct sw_port ports[DP_MAX_PORTS]; + struct sw_port *local_port; /* OFPP_LOCAL port, if any. */ + struct list port_list; /* All ports, including local_port. */ + +#if defined(OF_HW_PLAT) + /* Although the chain maintains the pointer to the HW driver + * for flow operations, the datapath needs the port functions + * in the driver structure + */ + of_hw_driver_t *hw_drv; + struct hw_pkt_q_entry *hw_pkt_list_head, *hw_pkt_list_tail; +#endif +}; + +int dp_new(struct datapath **, uint64_t dpid); +int dp_add_port(struct datapath *, const char *netdev, uint16_t); +int dp_add_local_port(struct datapath *, const char *netdev, uint16_t); +void dp_add_pvconn(struct datapath *, struct pvconn *); +void dp_run(struct datapath *); +void dp_wait(struct datapath *); +void dp_send_error_msg(struct datapath *, const struct sender *, + uint16_t, uint16_t, const void *, size_t); +void dp_send_flow_end(struct datapath *, struct sw_flow *, + enum ofp_flow_removed_reason); +void dp_output_port(struct datapath *, struct ofpbuf *, int in_port, + int out_port, uint32_t queue_id, bool ignore_no_fwd); +void dp_output_control(struct datapath *, struct ofpbuf *, int in_port, + size_t max_len, int reason); +struct sw_port * dp_lookup_port(struct datapath *, uint16_t); +struct sw_queue * dp_lookup_queue(struct sw_port *, uint32_t); + +int udatapath_cmd(int argc, char *argv[]); + +#endif /* datapath.h */ diff --git a/openflow/udatapath/dp_act.c b/openflow/udatapath/dp_act.c new file mode 100644 index 00000000..d48beb10 --- /dev/null +++ b/openflow/udatapath/dp_act.c @@ -0,0 +1,531 @@ +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +/* Functions for executing OpenFlow actions. */ + +#include +#include "csum.h" +#include "packets.h" +#include "dp_act.h" +#include "openflow/nicira-ext.h" + +static uint16_t +validate_output(struct datapath *dp UNUSED, const struct sw_flow_key *key, + const struct ofp_action_header *ah) +{ + struct ofp_action_output *oa = (struct ofp_action_output *)ah; + + /* To prevent loops, make sure there's no action to send to the + * OFP_TABLE virtual port. + */ + if (oa->port == htons(OFPP_NONE) || + (!(key->wildcards & OFPFW_IN_PORT) + && oa->port == key->flow.in_port)) { + return OFPBAC_BAD_OUT_PORT; + } + return ACT_VALIDATION_OK; +} + +static uint16_t +validate_queue(struct datapath *dp UNUSED, const struct sw_flow_key *key UNUSED, + const struct ofp_action_header *ah) +{ + struct ofp_action_enqueue *ea = (struct ofp_action_enqueue *)ah; + + /* Only physical ports may have queues. */ + if (ntohs(ea->port) > OFPP_MAX && ntohs(ea->port) != OFPP_IN_PORT) { + return OFPBAC_BAD_OUT_PORT; + } + return ACT_VALIDATION_OK; +} + +static void +do_output(struct datapath *dp, struct ofpbuf *buffer, int in_port, + size_t max_len, int out_port, uint32_t queue_id, + bool ignore_no_fwd) +{ + if (out_port != OFPP_CONTROLLER) { + dp_output_port(dp, buffer, in_port, out_port, queue_id, ignore_no_fwd); + } else { + dp_output_control(dp, buffer, in_port, max_len, OFPR_ACTION); + } +} + +/* Modify vlan tag control information (TCI). Only sets the TCI bits + * indicated by 'mask'. If no vlan tag is present, one is added. + */ +static void +modify_vlan_tci(struct ofpbuf *buffer, struct sw_flow_key *key, + uint16_t tci, uint16_t mask) +{ + struct vlan_eth_header *veh; + + if (key->flow.dl_vlan != htons(OFP_VLAN_NONE)) { + /* Modify vlan id, but maintain other TCI values */ + veh = buffer->l2; + veh->veth_tci &= ~htons(mask); + veh->veth_tci |= htons(tci); + } else { + /* Insert new vlan id. */ + struct eth_header *eh = buffer->l2; + struct vlan_eth_header tmp; + memcpy(tmp.veth_dst, eh->eth_dst, ETH_ADDR_LEN); + memcpy(tmp.veth_src, eh->eth_src, ETH_ADDR_LEN); + tmp.veth_type = htons(ETH_TYPE_VLAN); + tmp.veth_tci = htons(tci); + tmp.veth_next_type = eh->eth_type; + + veh = ofpbuf_push_uninit(buffer, VLAN_HEADER_LEN); + memcpy(veh, &tmp, sizeof tmp); + buffer->l2 = (char*)buffer->l2 - VLAN_HEADER_LEN; + } + + key->flow.dl_vlan = veh->veth_tci & htons(VLAN_VID_MASK); + key->flow.dl_vlan_pcp = (uint8_t)((ntohs(veh->veth_tci) >> VLAN_PCP_SHIFT) + & VLAN_PCP_BITMASK); +} + + +/* Remove an existing vlan header if it exists. */ +static void +vlan_pull_tag(struct ofpbuf *buffer) +{ + struct vlan_eth_header *veh = buffer->l2; + + if (veh->veth_type == htons(ETH_TYPE_VLAN)) { + struct eth_header tmp; + + memcpy(tmp.eth_dst, veh->veth_dst, ETH_ADDR_LEN); + memcpy(tmp.eth_src, veh->veth_src, ETH_ADDR_LEN); + tmp.eth_type = veh->veth_next_type; + + buffer->size -= VLAN_HEADER_LEN; + buffer->data = (char*)buffer->data + VLAN_HEADER_LEN; + buffer->l2 = (char*)buffer->l2 + VLAN_HEADER_LEN; + memcpy(buffer->data, &tmp, sizeof tmp); + } +} + +static void +set_vlan_vid(struct ofpbuf *buffer, struct sw_flow_key *key, + const struct ofp_action_header *ah) +{ + struct ofp_action_vlan_vid *va = (struct ofp_action_vlan_vid *)ah; + uint16_t tci = ntohs(va->vlan_vid); + + modify_vlan_tci(buffer, key, tci, VLAN_VID_MASK); +} + +static void +set_vlan_pcp(struct ofpbuf *buffer, struct sw_flow_key *key, + const struct ofp_action_header *ah) +{ + struct ofp_action_vlan_pcp *va = (struct ofp_action_vlan_pcp *)ah; + uint16_t tci = (uint16_t)va->vlan_pcp << 13; + + modify_vlan_tci(buffer, key, tci, VLAN_PCP_MASK); +} + +static void +strip_vlan(struct ofpbuf *buffer, struct sw_flow_key *key, + const struct ofp_action_header *ah UNUSED) +{ + vlan_pull_tag(buffer); + key->flow.dl_vlan = htons(OFP_VLAN_NONE); +} + +static void +set_dl_addr(struct ofpbuf *buffer, struct sw_flow_key *key UNUSED, + const struct ofp_action_header *ah) +{ + struct ofp_action_dl_addr *da = (struct ofp_action_dl_addr *)ah; + struct eth_header *eh = buffer->l2; + + if (da->type == htons(OFPAT_SET_DL_SRC)) { + memcpy(eh->eth_src, da->dl_addr, sizeof eh->eth_src); + } else { + memcpy(eh->eth_dst, da->dl_addr, sizeof eh->eth_dst); + } +} + +static void +set_nw_addr(struct ofpbuf *buffer, struct sw_flow_key *key, + const struct ofp_action_header *ah) +{ + struct ofp_action_nw_addr *na = (struct ofp_action_nw_addr *)ah; + uint16_t eth_proto = ntohs(key->flow.dl_type); + + if (eth_proto == ETH_TYPE_IP) { + struct ip_header *nh = buffer->l3; + uint8_t nw_proto = key->flow.nw_proto; + uint32_t new, *field; + + new = na->nw_addr; + field = na->type == htons(OFPAT_SET_NW_SRC) ? &nh->ip_src : &nh->ip_dst; + if (nw_proto == IP_TYPE_TCP) { + struct tcp_header *th = buffer->l4; + th->tcp_csum = recalc_csum32(th->tcp_csum, *field, new); + } else if (nw_proto == IP_TYPE_UDP) { + struct udp_header *th = buffer->l4; + if (th->udp_csum) { + th->udp_csum = recalc_csum32(th->udp_csum, *field, new); + if (!th->udp_csum) { + th->udp_csum = 0xffff; + } + } + } + nh->ip_csum = recalc_csum32(nh->ip_csum, *field, new); + *field = new; + } +} + +static void +set_nw_tos(struct ofpbuf *buffer, struct sw_flow_key *key, + const struct ofp_action_header *ah) +{ + struct ofp_action_nw_tos *nt = (struct ofp_action_nw_tos *)ah; + uint16_t eth_proto = ntohs(key->flow.dl_type); + + if (eth_proto == ETH_TYPE_IP) { + struct ip_header *nh = buffer->l3; + uint8_t new, *field; + + /* JeanII : Set only 6 bits, don't clobber ECN */ + new = (nt->nw_tos & 0xFC) | (nh->ip_tos & 0x03); + + /* Get address of field */ + field = &nh->ip_tos; + + /* jklee : ip tos field is not included in TCP pseudo header. + * Need magic as update_csum() don't work with 8 bits. */ + nh->ip_csum = recalc_csum32(nh->ip_csum, htons((uint16_t)*field), + htons((uint16_t)new)); + + /* Change the IP ToS bits */ + *field = new; + } +} + +static void +set_tp_port(struct ofpbuf *buffer, struct sw_flow_key *key, + const struct ofp_action_header *ah) +{ + struct ofp_action_tp_port *ta = (struct ofp_action_tp_port *)ah; + uint16_t eth_proto = ntohs(key->flow.dl_type); + + if (eth_proto == ETH_TYPE_IP) { + uint8_t nw_proto = key->flow.nw_proto; + uint16_t new, *field; + + new = ta->tp_port; + if (nw_proto == IP_TYPE_TCP) { + struct tcp_header *th = buffer->l4; + field = ta->type == htons(OFPAT_SET_TP_SRC) ? &th->tcp_src : &th->tcp_dst; + th->tcp_csum = recalc_csum16(th->tcp_csum, *field, new); + *field = new; + } else if (nw_proto == IP_TYPE_UDP) { + struct udp_header *th = buffer->l4; + field = ta->type == htons(OFPAT_SET_TP_SRC) ? &th->udp_src : &th->udp_dst; + th->udp_csum = recalc_csum16(th->udp_csum, *field, new); + *field = new; + } + } +} + +struct openflow_action { + size_t min_size; + size_t max_size; + uint16_t (*validate)(struct datapath *dp, + const struct sw_flow_key *key, + const struct ofp_action_header *ah); + void (*execute)(struct ofpbuf *buffer, + struct sw_flow_key *key, + const struct ofp_action_header *ah); +}; + +static const struct openflow_action of_actions[] = { + [OFPAT_OUTPUT] = { + sizeof(struct ofp_action_output), + sizeof(struct ofp_action_output), + validate_output, + NULL /* This is optimized into execute_actions */ + }, + [OFPAT_ENQUEUE] = { + sizeof(struct ofp_action_enqueue), + sizeof(struct ofp_action_enqueue), + validate_queue, + NULL /* This is optimized into execute_actions */ + }, + [OFPAT_SET_VLAN_VID] = { + sizeof(struct ofp_action_vlan_vid), + sizeof(struct ofp_action_vlan_vid), + NULL, + set_vlan_vid + }, + [OFPAT_SET_VLAN_PCP] = { + sizeof(struct ofp_action_vlan_pcp), + sizeof(struct ofp_action_vlan_pcp), + NULL, + set_vlan_pcp + }, + [OFPAT_STRIP_VLAN] = { + sizeof(struct ofp_action_header), + sizeof(struct ofp_action_header), + NULL, + strip_vlan + }, + [OFPAT_SET_DL_SRC] = { + sizeof(struct ofp_action_dl_addr), + sizeof(struct ofp_action_dl_addr), + NULL, + set_dl_addr + }, + [OFPAT_SET_DL_DST] = { + sizeof(struct ofp_action_dl_addr), + sizeof(struct ofp_action_dl_addr), + NULL, + set_dl_addr + }, + [OFPAT_SET_NW_SRC] = { + sizeof(struct ofp_action_nw_addr), + sizeof(struct ofp_action_nw_addr), + NULL, + set_nw_addr + }, + [OFPAT_SET_NW_DST] = { + sizeof(struct ofp_action_nw_addr), + sizeof(struct ofp_action_nw_addr), + NULL, + set_nw_addr + }, + [OFPAT_SET_NW_TOS] = { + sizeof(struct ofp_action_nw_tos), + sizeof(struct ofp_action_nw_tos), + NULL, + set_nw_tos + }, + [OFPAT_SET_TP_SRC] = { + sizeof(struct ofp_action_tp_port), + sizeof(struct ofp_action_tp_port), + NULL, + set_tp_port + }, + [OFPAT_SET_TP_DST] = { + sizeof(struct ofp_action_tp_port), + sizeof(struct ofp_action_tp_port), + NULL, + set_tp_port + } + /* OFPAT_VENDOR is not here, since it would blow up the array size. */ +}; + +/* Validate built-in OpenFlow actions. Either returns ACT_VALIDATION_OK + * or an OFPET_BAD_ACTION error code. */ +static uint16_t +validate_ofpat(struct datapath *dp, const struct sw_flow_key *key, + const struct ofp_action_header *ah, uint16_t type, uint16_t len) +{ + uint16_t ret = ACT_VALIDATION_OK; + const struct openflow_action *act = &of_actions[type]; + + if ((len < act->min_size) || (len > act->max_size)) { + return OFPBAC_BAD_LEN; + } + + if (act->validate) { + ret = act->validate(dp, key, ah); + } + + return ret; +} + +/* Validate vendor-defined actions. Either returns ACT_VALIDATION_OK + * or an OFPET_BAD_ACTION error code. */ +static uint16_t +validate_vendor(struct datapath *dp UNUSED, const struct sw_flow_key *key UNUSED, + const struct ofp_action_header *ah, uint16_t len) +{ + struct ofp_action_vendor_header *avh; + int ret = ACT_VALIDATION_OK; + + if (len < sizeof(struct ofp_action_vendor_header)) { + return OFPBAC_BAD_LEN; + } + + avh = (struct ofp_action_vendor_header *)ah; + + switch(ntohl(avh->vendor)) { + default: + return OFPBAC_BAD_VENDOR; + } + + return ret; +} + +/* Validates a list of actions. If a problem is found, a code for the + * OFPET_BAD_ACTION error type is returned. If the action list validates, + * ACT_VALIDATION_OK is returned. */ +uint16_t +validate_actions(struct datapath *dp, const struct sw_flow_key *key, + const struct ofp_action_header *actions, size_t actions_len) +{ + uint8_t *p = (uint8_t *)actions; + int err; + + while (actions_len >= sizeof(struct ofp_action_header)) { + struct ofp_action_header *ah = (struct ofp_action_header *)p; + size_t len = ntohs(ah->len); + uint16_t type; + + /* Make there's enough remaining data for the specified length + * and that the action length is a multiple of 64 bits. */ + if ((actions_len < len) || (len % 8) != 0) { + return OFPBAC_BAD_LEN; + } + + type = ntohs(ah->type); + if (type < ARRAY_SIZE(of_actions)) { + err = validate_ofpat(dp, key, ah, type, len); + if (err != ACT_VALIDATION_OK) { + return err; + } + } else if (type == OFPAT_VENDOR) { + err = validate_vendor(dp, key, ah, len); + if (err != ACT_VALIDATION_OK) { + return err; + } + } else { + return OFPBAC_BAD_TYPE; + } + + p += len; + actions_len -= len; + } + + /* Check if there's any trailing garbage. */ + if (actions_len != 0) { + return OFPBAC_BAD_LEN; + } + + return ACT_VALIDATION_OK; +} + +/* Execute a built-in OpenFlow action against 'buffer'. */ +static void +execute_ofpat(struct ofpbuf *buffer, struct sw_flow_key *key, + const struct ofp_action_header *ah, uint16_t type) +{ + const struct openflow_action *act = &of_actions[type]; + + if (act->execute) { + act->execute(buffer, key, ah); + } +} + +/* Execute a vendor-defined action against 'buffer'. */ +static void +execute_vendor(struct ofpbuf *buffer UNUSED, const struct sw_flow_key *key UNUSED, + const struct ofp_action_header *ah) +{ + struct ofp_action_vendor_header *avh + = (struct ofp_action_vendor_header *)ah; + + switch(ntohl(avh->vendor)) { + default: + /* This should not be possible due to prior validation. */ + printf("attempt to execute action with unknown vendor: %#x\n", + ntohl(avh->vendor)); + break; + } +} + +/* Execute a list of actions against 'buffer'. */ +void execute_actions(struct datapath *dp, struct ofpbuf *buffer, + struct sw_flow_key *key, + const struct ofp_action_header *actions, size_t actions_len, + int ignore_no_fwd) +{ + /* Every output action needs a separate clone of 'buffer', but the common + * case is just a single output action, so that doing a clone and then + * freeing the original buffer is wasteful. So the following code is + * slightly obscure just to avoid that. */ + int prev_port; + uint32_t prev_queue; + size_t max_len = UINT16_MAX; + uint16_t in_port = ntohs(key->flow.in_port); + uint8_t *p = (uint8_t *)actions; + + prev_port = -1; + prev_queue = 0; + + /* The action list was already validated, so we can be a bit looser + * in our sanity-checking. */ + while (actions_len > 0) { + struct ofp_action_header *ah = (struct ofp_action_header *)p; + size_t len = htons(ah->len); + + if (prev_port != -1) { + do_output(dp, ofpbuf_clone(buffer), in_port, max_len, + prev_port, prev_queue, ignore_no_fwd); + prev_port = -1; + } + + if (ah->type == htons(OFPAT_OUTPUT)) { + struct ofp_action_output *oa = (struct ofp_action_output *)p; + prev_port = ntohs(oa->port); + prev_queue = 0; /* using the default best-effort queue */ + max_len = ntohs(oa->max_len); + } else if (ah->type == htons(OFPAT_ENQUEUE)) { + struct ofp_action_enqueue *ea = (struct ofp_action_enqueue *)p; + prev_port = ntohs(ea->port); + prev_queue = ntohl(ea->queue_id); + max_len = 0; /* we will not send to the controller anyways - useless */ + } else { + uint16_t type = ntohs(ah->type); + + if (type < ARRAY_SIZE(of_actions)) { + execute_ofpat(buffer, key, ah, type); + } else if (type == OFPAT_VENDOR) { + execute_vendor(buffer, key, ah); + } + } + + p += len; + actions_len -= len; + } + if (prev_port != -1) { + do_output(dp, buffer, in_port, max_len, prev_port, prev_queue, ignore_no_fwd); + } else { + ofpbuf_delete(buffer); + } +} diff --git a/openflow/udatapath/dp_act.h b/openflow/udatapath/dp_act.h new file mode 100644 index 00000000..e0181fad --- /dev/null +++ b/openflow/udatapath/dp_act.h @@ -0,0 +1,49 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#ifndef DP_ACT_H +#define DP_ACT_H 1 + +#include "openflow/openflow.h" +#include "switch-flow.h" +#include "datapath.h" + +#define ACT_VALIDATION_OK ((uint16_t)-1) + +uint16_t validate_actions(struct datapath *, const struct sw_flow_key *, + const struct ofp_action_header *, size_t); +void execute_actions(struct datapath *, struct ofpbuf *, + struct sw_flow_key *, const struct ofp_action_header *, + size_t action_len, int ignore_no_fwd); + +#endif /* dp_act.h */ diff --git a/openflow/udatapath/of_ext_msg.c b/openflow/udatapath/of_ext_msg.c new file mode 100644 index 00000000..36d587be --- /dev/null +++ b/openflow/udatapath/of_ext_msg.c @@ -0,0 +1,267 @@ +/* Copyright (c) 2009 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include +#include "openflow/openflow-ext.h" +#include "of_ext_msg.h" +#include "netdev.h" +#include "datapath.h" + +#define THIS_MODULE VLM_experimental +#include "vlog.h" + +static int +new_queue(struct sw_port * port, struct sw_queue * queue, + uint32_t queue_id, uint16_t class_id, + struct ofp_queue_prop_min_rate * mr) +{ + memset(queue, '\0', sizeof *queue); + queue->port = port; + queue->queue_id = queue_id; + /* class_id is the internal mapping to class. It is the offset + * in the array of queues for each port. Note that class_id is + * local to port, so we don't have any conflict. + * tc uses 16-bit class_id, so we cannot use the queue_id + * field */ + queue->class_id = class_id; + queue->property = ntohs(mr->prop_header.property); + queue->min_rate = ntohs(mr->rate); + + list_push_back(&port->queue_list, &queue->node); + + return 0; +} + +static int +port_add_queue(struct sw_port *p, uint32_t queue_id, + struct ofp_queue_prop_min_rate * mr) +{ + int queue_no; + for (queue_no = 1; queue_no < p->num_queues; queue_no++) { + struct sw_queue *q = &p->queues[queue_no]; + if (!q->port) { + return new_queue(p,q,queue_id,queue_no,mr); + } + } + return EXFULL; +} + +static int +port_delete_queue(struct sw_port *p UNUSED, struct sw_queue *q) +{ + list_remove(&q->node); + memset(q,'\0', sizeof *q); + return 0; +} + +static void +recv_of_exp_queue_delete(struct datapath *dp, + const struct sender *sender, + const void *oh) +{ + struct sw_port *p; + struct sw_queue *q; + struct openflow_queue_command_header * ofq_delete; + struct ofp_packet_queue *opq; + + uint16_t port_no; + uint32_t queue_id; + + ofq_delete = (struct openflow_queue_command_header *)oh; + opq = (struct ofp_packet_queue *)ofq_delete->body; + port_no = ntohs(ofq_delete->port); + queue_id = ntohl(opq->queue_id); + + p = dp_lookup_port(dp,port_no); + if (p->netdev) { + q = dp_lookup_queue(p,queue_id); + if (q) { + netdev_delete_class(p->netdev,q->class_id); + port_delete_queue(p,q); + } + else { + dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, + OFPQOFC_BAD_PORT, oh, + ntohs(ofq_delete->header.header.length)); + } + } + else { + dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, + OFPQOFC_BAD_PORT, oh, + ntohs(ofq_delete->header.header.length)); + } +} + +/** Modifies/adds a queue. It first searches if a queue with + * id exists for this port. If yes it modifies it, otherwise adds + * a new configuration. + * + * @param dp the related datapath + * @param sender request source + * @param oh the openflow message for queue mod. + */ +static void +recv_of_exp_queue_modify(struct datapath *dp, + const struct sender *sender UNUSED, + const void *oh) +{ + struct sw_port *p; + struct sw_queue *q; + struct openflow_queue_command_header * ofq_modify; + struct ofp_packet_queue *opq; + struct ofp_queue_prop_min_rate *mr; + + int error = 0; + uint16_t port_no; + uint32_t queue_id; + + + ofq_modify = (struct openflow_queue_command_header *)oh; + opq = (struct ofp_packet_queue *)ofq_modify->body; + mr = (struct ofp_queue_prop_min_rate*)opq->properties; + + /* Currently, we only accept queues with a single, min-rate property */ + if ((ntohs(opq->len) != 24) || + ntohs(mr->prop_header.property) != OFPQT_MIN_RATE) { + VLOG_ERR("Unknown queue configuration"); + dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, + OFQ_ERR_DISCIPLINE, oh, + ntohs(ofq_modify->header.header.length)); + return; + } + + + + port_no = ntohs(ofq_modify->port); + queue_id = ntohl(opq->queue_id); + + p = dp_lookup_port(dp, port_no); + if (PORT_IN_USE(p)) { + q = dp_lookup_queue(p, queue_id); + if (q) { + /* queue exists - modify it */ + error = netdev_change_class(p->netdev,q->class_id, ntohs(mr->rate)); + if (error) { + VLOG_ERR("Failed to update queue %d", queue_id); + dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, + OFPQOFC_EPERM, oh, + ntohs(ofq_modify->header.header.length)); + } + else { + q->property = ntohs(mr->prop_header.property); + q->min_rate = ntohs(mr->rate); + } + } + else { + /* create new queue */ + error = port_add_queue(p,queue_id, mr); + if (error == EXFULL) { + dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, + OFPQOFC_EPERM, oh, + ntohs(ofq_modify->header.header.length)); + return; + } + q = dp_lookup_queue(p, queue_id); + error = netdev_setup_class(p->netdev,q->class_id, ntohs(mr->rate)); + if (error) { + VLOG_ERR("Failed to configure queue %d", queue_id); + dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, + OFPQOFC_BAD_QUEUE, oh, + ntohs(ofq_modify->header.header.length)); + } + } + } + else { + dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, OFPQOFC_BAD_PORT, + oh, ntohs(ofq_modify->header.header.length)); + VLOG_ERR("Failed to create/modify queue - port %d doesn't exist", + port_no); + } + if (!error) { + if (IS_HW_PORT(p)) { +#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) + error = dp->hw_drv->port_queue_config(dp->hw_drv, port_no, + queue_id, ntohs(mr->rate)); + if (error < 0) { + VLOG_ERR("Failed to update HW port %d queue %d", + port_no, queue_id); + } +#endif + } + } +} +/** + * Parses a set dp_desc message and uses it to set + * the dp_desc string in dp + */ +static void +recv_of_set_dp_desc(struct datapath *dp, + const struct sender *sender UNUSED, + const struct ofp_extension_header * exth) +{ + struct openflow_ext_set_dp_desc * set_dp_desc = (struct openflow_ext_set_dp_desc * ) + exth; + strncpy(dp->dp_desc, set_dp_desc->dp_desc, DESC_STR_LEN); + dp->dp_desc[DESC_STR_LEN-1] = 0; // force null for safety +} + +/** + * Receives an experimental message and pass it + * to the appropriate handler + */ +int of_ext_recv_msg(struct datapath *dp, const struct sender *sender, + const void *oh) +{ + const struct ofp_extension_header *ofexth = oh; + + switch (ntohl(ofexth->subtype)) { + case OFP_EXT_QUEUE_MODIFY: { + recv_of_exp_queue_modify(dp,sender,oh); + return 0; + } + case OFP_EXT_QUEUE_DELETE: { + recv_of_exp_queue_delete(dp,sender,oh); + return 0; + } + case OFP_EXT_SET_DESC: + recv_of_set_dp_desc(dp,sender,ofexth); + return 0; + default: + VLOG_ERR("Received unknown command of type %d", + ntohl(ofexth->subtype)); + return -EINVAL; + } + + return -EINVAL; +} diff --git a/openflow/udatapath/of_ext_msg.h b/openflow/udatapath/of_ext_msg.h new file mode 100644 index 00000000..510615d7 --- /dev/null +++ b/openflow/udatapath/of_ext_msg.h @@ -0,0 +1,43 @@ +/* Copyright (c) 2009 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#ifndef OF_EXT_MSG_H +#define OF_EXT_MSG_H 1 + +#include "datapath.h" + +struct sender; + +int of_ext_recv_msg(struct datapath *, const struct sender *, const void *); + +#endif /* of_ext_msg.h */ diff --git a/openflow/udatapath/ofdatapath.8.in b/openflow/udatapath/ofdatapath.8.in new file mode 100644 index 00000000..55d6b4ba --- /dev/null +++ b/openflow/udatapath/ofdatapath.8.in @@ -0,0 +1,148 @@ +.ds PN ofdatapath + +.TH ofdatapath 8 "May 2008" "OpenFlow" "OpenFlow Manual" + +.SH NAME +ofdatapath \- userspace implementation of datapath for OpenFlow switch + +.SH SYNOPSIS +.B ofdatapath +[\fIoptions\fR] +\fB-i\fR \fInetdev\fR[\fB,\fInetdev\fR].\|.\|. +\fImethod\fR [\fImethod\fR].\|.\|. + +.SH DESCRIPTION +The \fBofdatapath\fR is a userspace implementation of an OpenFlow +datapath. It monitors one or more network device interfaces, +forwarding packets between them according to the entries in the flow +table that it maintains. When it is used with \fBofprotocol\fR(8), to +connect the datapath to an OpenFlow controller, the combination is an +OpenFlow switch. + +For access to network devices, the ofdatapath program must normally run as +root. + +The mandatory \fImethod\fR argument specifies how \fBofprotocol\fR(8) +communicates with \fBofdatapath\fR, as a passive OpenFlow connection +method. Ordinarily \fImethod\fR takes the following form: + +.TP +\fBpunix:\fIfile\fR +Listens for connections on the Unix domain server socket named +\fIfile\fR. + +.PP +The following connection methods are also supported, but their use +would be unusual because \fBofdatapath\fR and \fBofprotocol\fR should run +on the same machine: + +.TP +\fBpssl:\fR[\fIport\fR] +Listens for SSL connections \fIport\fR (default: 976). The +\fB--private-key\fR, \fB--certificate\fR, and \fB--ca-cert\fR options +are mandatory when this form is used. (\fBofp\-pki\fR(8) does not set +up a suitable PKI for use with this option.) + +.TP +\fBptcp:\fR[\fIport\fR] +Listens for TCP connections from remote OpenFlow switches on +\fIport\fR (default: 975). + +.SH OPTIONS +.TP +\fB-i\fR, \fB--interfaces=\fR\fInetdev\fR[\fB,\fInetdev\fR].\|.\|. +Specifies each \fInetdev\fR (e.g., \fBeth0\fR) as a switch port. The +specified network devices should not have any configured IP addresses. +This option may be given any number of times to specify additional +network devices. + +.TP +\fB-L\fR, \fB--local-port=\fInetdev\fR +Specifies the network device to use as the userspace datapath's +``local port,'' which is a network device that \fBofprotocol\fR(8) +bridges to the physical switch ports for use in in-band control. When +this option is not specified, the default is \fBtap:\fR, which causes +a new TAP virtual network device to be allocated with a default name +assigned by the kernel. To do the same, but assign a specific name +\fBname\fR to the TAP network device, specify the option as +\fB--local-port=tap:\fIname\fR. + +Either way, the existence of TAP devices created by \fBofdatapath\fR is +temporary: they are destroyed when \fBofdatapath\fR exits. If this is +undesirable, you may use \fBtunctl\fR(8) to create a persistent TAP +network device and then pass it to \fBofdatapath\fR, like so: + +.RS +.IP 1. +Create a persistent TAP network device: \fBtunctl -t mytap\fR. (The +\fBtunctl\fR(8) utility is part of User Mode Linux. It is not +included with the OpenFlow reference implementation.) +.IP 2. +Invoke \fBofdatapath\fR(8) using \fBmytap\fR, e.g. \fBofdatapath +--local-port=mytap\fR .\|.\|. (Note the lack of \fBtap:\fR prefix on +the \fB--local-port\fR argument.) +.IP 3. +Invoke \fBofprotocol\fR(8), etc., and use the switch as desired. +.IP 4. +When \fBofprotocol\fR and \fBofdatapath\fR have terminated and the TAP +network device is no longer needed, you may destroy it with: \fBtunctl +-d mytap\fR +.RE + +.IP +It does not ordinarily make sense to specify the name of a physical +network device on \fB-L\fR or \fB--local-port\fR. + +.TP +\fB--no-local-port\fR +Do not provide a local port as part of the datapath. When this option +is used, the switch will not support in-band control. + +.TP +\fB--no-slicing\fR +Disable slicing (no queue configuration to ports). When this option +is used, the switch will have 0 queues, and therefore no +slicing-related functionality is supported. This option is useful when +run-time dependencies for slicing (tc and related kernel +configuration) are not met. + +.TP +\fB-d\fR, \fB--datapath-id=\fIdpid\fR +Specifies the OpenFlow datapath ID (a 48-bit number that uniquely +identifies a controller) as \fIdpid\fR, which consists of exactly 12 +hex digits. Without this option, \fBofdatapath\fR picks an ID randomly. + +.TP +\fB-p\fR, \fB--private-key=\fIprivkey.pem\fR +Specifies a PEM file containing the private key used as the datapath's +identity for SSL connections to \fBofprotocol\fR(8). + +.TP +\fB-c\fR, \fB--certificate=\fIcert.pem\fR +Specifies a PEM file containing a certificate, signed by the +datapath's certificate authority (CA), that certifies the datapath's +private key to identify a trustworthy datapath. + +.TP +\fB-C\fR, \fB--ca-cert=\fIcacert.pem\fR +Specifies a PEM file containing the CA certificate used to verify that +the datapath is connected to a trustworthy secure channel. + +.so lib/daemon.man +.so lib/vlog.man +.so lib/common.man + +.SH BUGS +The userspace datapath's performance lags significantly behind that of +the kernel-based switch. It should only be used when the kernel-based +switch cannot be. + +On Linux, general-purpose support for VLAN tag rewriting is precluded +by the Linux kernel AF_PACKET implementation. + +.SH "SEE ALSO" + +.BR ofprotocol (8), +.BR dpctl (8), +.BR controller (8), +.BR vlogconf (8). diff --git a/openflow/udatapath/private-msg.c b/openflow/udatapath/private-msg.c new file mode 100644 index 00000000..7e868671 --- /dev/null +++ b/openflow/udatapath/private-msg.c @@ -0,0 +1,140 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#include +#include + +#include "openflow/private-ext.h" + +#include "chain.h" +#include "datapath.h" +#include "switch-flow.h" +#include "table.h" +#include "private-msg.h" + +struct emerg_flow_context { + struct datapath *dp; +}; + +static void flush_working(struct datapath *); +static int protection_callback(struct sw_flow *, void *); +static void do_protection(struct datapath *); + +static void +flush_working(struct datapath *dp) +{ + struct sw_flow_key key; + int num_deleted = 0; + + memset(&key, 0, sizeof(key)); + key.wildcards = OFPFW_ALL; + num_deleted = chain_delete(dp->chain, &key, OFPP_NONE, 0, 0, 0); +} + +static int +protection_callback(struct sw_flow *flow, void *private_) +{ + struct emerg_flow_context *private + = (struct emerg_flow_context *)private_; + struct sw_flow_actions *actions = flow->sf_acts; + struct ofp_match match; + struct sw_flow *tgtflow = NULL; + int error = 0; + + tgtflow = flow_alloc(flow->sf_acts->actions_len); + if (tgtflow == NULL) + return -ENOBUFS; + + /* Dup w/o idle and hard timeout. */ + memset(&match, 0, sizeof(match)); + flow_fill_match(&match, &flow->key.flow, flow->key.wildcards); + flow_extract_match(&tgtflow->key, &match); + /* Fill out flow. */ + tgtflow->priority = flow->priority; + tgtflow->idle_timeout = OFP_FLOW_PERMANENT; + tgtflow->hard_timeout = OFP_FLOW_PERMANENT; + tgtflow->send_flow_rem = flow->send_flow_rem; + tgtflow->emerg_flow = 0; + flow_setup_actions(tgtflow, actions->actions, actions->actions_len); + + error = chain_insert(private->dp->chain, tgtflow, 0); + if (error) + flow_free(tgtflow); + + return error; +} + +static void +do_protection(struct datapath *dp) +{ + struct emerg_flow_context private; + struct sw_flow_key key; + struct sw_table_position position; + struct sw_table *table = dp->chain->emerg_table; + int error = 0; + + memset(&private, 0, sizeof(private)); + private.dp = dp; + memset(&key, 0, sizeof(key)); + key.wildcards = OFPFW_ALL; + memset(&position, 0, sizeof(position)); + + error = table->iterate(table, &key, OFPP_NONE, + &position, protection_callback, &private); +} + +int +private_recv_msg(struct datapath *dp, const struct sender *sender UNUSED, + const void *ofph) +{ + struct private_vxhdr *vxhdr = (struct private_vxhdr *)ofph; + struct private_vxopt *vxopt = (struct private_vxopt *)(vxhdr + 1); + int error = 0; + + switch (ntohs(vxopt->pvo_type)) { + case PRIVATEOPT_PROTOCOL_STATS_REQUEST: + case PRIVATEOPT_PROTOCOL_STATS_REPLY: + break; + case PRIVATEOPT_EMERG_FLOW_PROTECTION: + flush_working(dp); + do_protection(dp); + break; + case PRIVATEOPT_EMERG_FLOW_RESTORATION: + /* Nothing to do because we assume that a re-connected + * controller will do flush current working flow table. */ + break; + default: + error = -EINVAL; + } + + return error; +} diff --git a/openflow/udatapath/private-msg.h b/openflow/udatapath/private-msg.h new file mode 100644 index 00000000..082a4531 --- /dev/null +++ b/openflow/udatapath/private-msg.h @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#ifndef PRIVATE_MSG_H_ +#define PRIVATE_MSG_H_ + +#include "datapath.h" + +struct sender; + +int private_recv_msg(struct datapath *, const struct sender *, const void *); + +#endif diff --git a/openflow/udatapath/switch-flow.c b/openflow/udatapath/switch-flow.c new file mode 100644 index 00000000..4ba9b406 --- /dev/null +++ b/openflow/udatapath/switch-flow.c @@ -0,0 +1,341 @@ +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include "switch-flow.h" +#include +#include +#include +#include +#include "ofpbuf.h" +#include "openflow/openflow.h" +#include "openflow/nicira-ext.h" +#include "packets.h" +#include "timeval.h" + +#define THIS_MODULE VLM_chain +#include "vlog.h" + +/* Internal function used to compare fields in flow. */ +static inline int +flow_fields_match(const struct flow *a, const struct flow *b, uint32_t w, + uint32_t src_mask, uint32_t dst_mask) +{ + return ((w & OFPFW_IN_PORT || a->in_port == b->in_port) + && (w & OFPFW_DL_VLAN || a->dl_vlan == b->dl_vlan) + && (w & OFPFW_DL_VLAN_PCP || a->dl_vlan_pcp == b->dl_vlan_pcp) + && (w & OFPFW_DL_SRC || eth_addr_equals(a->dl_src, b->dl_src)) + && (w & OFPFW_DL_DST || eth_addr_equals(a->dl_dst, b->dl_dst)) + && (w & OFPFW_DL_TYPE || a->dl_type == b->dl_type) + && (w & OFPFW_NW_TOS || a->nw_tos == b->nw_tos) + && (w & OFPFW_NW_PROTO || a->nw_proto == b->nw_proto) + && !((a->nw_src ^ b->nw_src) & src_mask) + && !((a->nw_dst ^ b->nw_dst) & dst_mask) + && (w & OFPFW_TP_SRC || a->tp_src == b->tp_src) + && (w & OFPFW_TP_DST || a->tp_dst == b->tp_dst)); +} + +static uint32_t make_nw_mask(int n_wild_bits) +{ + n_wild_bits &= (1u << OFPFW_NW_SRC_BITS) - 1; + return n_wild_bits < 32 ? htonl(~((1u << n_wild_bits) - 1)) : 0; +} + +/* Returns nonzero if 'a' and 'b' match, that is, if their fields are equal + * modulo wildcards in 'b', zero otherwise. */ +inline int +flow_matches_1wild(const struct sw_flow_key *a, const struct sw_flow_key *b) +{ + return flow_fields_match(&a->flow, &b->flow, b->wildcards, + b->nw_src_mask, b->nw_dst_mask); +} + +/* Returns nonzero if 'a' and 'b' match, that is, if their fields are equal + * modulo wildcards in 'a' or 'b', zero otherwise. */ +inline int +flow_matches_2wild(const struct sw_flow_key *a, const struct sw_flow_key *b) +{ + return flow_fields_match(&a->flow, &b->flow, a->wildcards | b->wildcards, + a->nw_src_mask & b->nw_src_mask, + a->nw_dst_mask & b->nw_dst_mask); +} + +/* Returns nonzero if 't' (the table entry's key) and 'd' (the key + * describing the match) match, that is, if their fields are + * equal modulo wildcards, zero otherwise. If 'strict' is nonzero, the + * wildcards must match in both 't_key' and 'd_key'. Note that the + * table's wildcards are ignored unless 'strict' is set. */ +int +flow_matches_desc(const struct sw_flow_key *t, const struct sw_flow_key *d, + int strict) +{ + if (strict && d->wildcards != t->wildcards) { + return 0; + } + return flow_matches_1wild(t, d); +} + +/* Returns nonzero if 't' (the table entry's key) and 'd' (the key + * describing the match) match, that is, if their fields are + * equal modulo 't' or 'd' wildcards, zero otherwise. If 'strict' is nonzero, the + * wildcards must match in both 't_key' and 'd_key'. Note that the + * table's wildcards are ignored unless 'strict' is set. */ +int +flow_matches_2desc(const struct sw_flow_key *t, const struct sw_flow_key *d, + int strict) +{ + if (strict && d->wildcards != t->wildcards) { + return 0; + } + return flow_matches_2wild(t, d); +} + +void +flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from) +{ + to->wildcards = ntohl(from->wildcards) & OFPFW_ALL; + to->flow.dl_vlan_pcp = from->dl_vlan_pcp; + to->flow.in_port = from->in_port; + to->flow.dl_vlan = from->dl_vlan; + memcpy(to->flow.dl_src, from->dl_src, ETH_ADDR_LEN); + memcpy(to->flow.dl_dst, from->dl_dst, ETH_ADDR_LEN); + to->flow.dl_type = from->dl_type; + + to->flow.nw_tos = to->flow.nw_proto = to->flow.nw_src = to->flow.nw_dst = 0; + to->flow.tp_src = to->flow.tp_dst = 0; + memset(to->flow.pad, 0, sizeof(to->flow.pad)); + +#define OFPFW_TP (OFPFW_TP_SRC | OFPFW_TP_DST) +#define OFPFW_NW (OFPFW_NW_TOS | OFPFW_NW_PROTO | OFPFW_NW_SRC_MASK | OFPFW_NW_DST_MASK) + if (to->wildcards & OFPFW_DL_TYPE) { + /* Can't sensibly match on network or transport headers if the + * data link type is unknown. */ + to->wildcards |= OFPFW_NW | OFPFW_TP; + } else if (from->dl_type == htons(ETH_TYPE_IP)) { + to->flow.nw_tos = from->nw_tos & 0xfc; + to->flow.nw_proto = from->nw_proto; + to->flow.nw_src = from->nw_src; + to->flow.nw_dst = from->nw_dst; + + if (to->wildcards & OFPFW_NW_PROTO) { + /* Can't sensibly match on transport headers if the network + * protocol is unknown. */ + to->wildcards |= OFPFW_TP; + } else if (from->nw_proto == IPPROTO_TCP + || from->nw_proto == IPPROTO_UDP + || from->nw_proto == IPPROTO_ICMP) { + to->flow.tp_src = from->tp_src; + to->flow.tp_dst = from->tp_dst; + } else { + /* Transport layer fields are undefined. Mark them as + * exact-match to allow such flows to reside in table-hash, + * instead of falling into table-linear. */ + to->wildcards &= ~OFPFW_TP; + } + } else if (from->dl_type == htons(ETH_TYPE_ARP)) { + to->flow.nw_src = from->nw_src; + to->flow.nw_dst = from->nw_dst; + to->flow.nw_proto = from->nw_proto; + + /* Transport layer fields are undefined. Mark them as + * exact-match to allow such flows to reside in table-hash, + * instead of falling into table-linear. */ + to->wildcards &= ~OFPFW_TP; + } else { + /* Network and transport layer fields are undefined. Mark them + * as exact-match to allow such flows to reside in table-hash, + * instead of falling into table-linear. */ + to->wildcards &= ~(OFPFW_NW | OFPFW_TP); + } + + /* We set these late because code above adjusts to->wildcards. */ + to->nw_src_mask = make_nw_mask(to->wildcards >> OFPFW_NW_SRC_SHIFT); + to->nw_dst_mask = make_nw_mask(to->wildcards >> OFPFW_NW_DST_SHIFT); +} + +/* Allocates and returns a new flow with room for 'actions_len' actions. + * Returns the new flow or a null pointer on failure. */ +struct sw_flow * +flow_alloc(size_t actions_len) +{ + struct sw_flow_actions *sfa; + size_t size = sizeof *sfa + actions_len; + struct sw_flow *flow = calloc(1, sizeof *flow); + if (!flow) + return NULL; + + sfa = calloc(1, size); + if (!sfa) { + free(flow); + return NULL; + } + sfa->actions_len = actions_len; + flow->sf_acts = sfa; + return flow; +} + +/* Setup the action on the flow, just after it was created with flow_alloc(). + * Jean II */ +void +flow_setup_actions(struct sw_flow * flow, + const struct ofp_action_header * actions, + int actions_len) +{ + /* Make sure we don't blow the allocation */ + if (actions_len > flow->sf_acts->actions_len) + ofp_fatal(0, + "flow_setup_actions: actions_len is too big (%d > %lu)", + actions_len, (unsigned long)flow->sf_acts->actions_len); + + flow->used = flow->created = time_msec(); + flow->sf_acts->actions_len = actions_len; + flow->byte_count = 0; + flow->packet_count = 0; + memcpy(flow->sf_acts->actions, actions, actions_len); +} + +/* Frees 'flow' immediately. */ +void +flow_free(struct sw_flow *flow) +{ + if (!flow) { + return; + } + free(flow->sf_acts); + free(flow); +} + +/* Copies 'actions' into a newly allocated structure for use by 'flow' + * and frees the structure that defined the previous actions. */ +void flow_replace_acts(struct sw_flow *flow, + const struct ofp_action_header *actions, size_t actions_len) +{ + struct sw_flow_actions *sfa; + int size = sizeof *sfa + actions_len; + + sfa = malloc(size); + if (unlikely(!sfa)) + return; + + sfa->actions_len = actions_len; + memcpy(sfa->actions, actions, actions_len); + + free(flow->sf_acts); + flow->sf_acts = sfa; + + return; +} + +/* Prints a representation of 'key' to the kernel log. */ +void +print_flow(const struct sw_flow_key *key) +{ + const struct flow *f = &key->flow; + + VLOG_INFO("wild %08x port %04x vlan-vid %04x vlan-pcp %02x " + "src-mac %02x:%02x:%02x:%02x:%02x:%02x " + "dst-mac %02x:%02x:%02x:%02x:%02x:%02x " + "frm-type %04x ip-tos %02x ip-src %u.%u.%u.%u ip-dst %u.%u.%u.%u " + "ip-proto %04x tp-src %d tp-dst %d pad %02x%02x%02x\n", + key->wildcards, ntohs(f->in_port), + ntohs(f->dl_vlan), f->dl_vlan_pcp, + f->dl_src[0], f->dl_src[1], f->dl_src[2], + f->dl_src[3], f->dl_src[4], f->dl_src[5], + f->dl_dst[0], f->dl_dst[1], f->dl_dst[2], + f->dl_dst[3], f->dl_dst[4], f->dl_dst[5], + ntohs(f->dl_type), + f->nw_tos, + ((unsigned char *)&f->nw_src)[0], + ((unsigned char *)&f->nw_src)[1], + ((unsigned char *)&f->nw_src)[2], + ((unsigned char *)&f->nw_src)[3], + ((unsigned char *)&f->nw_dst)[0], + ((unsigned char *)&f->nw_dst)[1], + ((unsigned char *)&f->nw_dst)[2], + ((unsigned char *)&f->nw_dst)[3], + f->nw_proto, + ntohs(f->tp_src), ntohs(f->tp_dst), + f->pad[0], f->pad[1], f->pad[2]); +} + +bool flow_timeout(struct sw_flow *flow) +{ + uint64_t now = time_msec(); + if (flow->idle_timeout != OFP_FLOW_PERMANENT + && now > flow->used + flow->idle_timeout * 1000) { + flow->reason = OFPRR_IDLE_TIMEOUT; + return true; + } else if (flow->hard_timeout != OFP_FLOW_PERMANENT + && now > flow->created + flow->hard_timeout * 1000) { + flow->reason = OFPRR_HARD_TIMEOUT; + return true; + } else { + return false; + } +} + +/* Returns nonzero if 'flow' contains an output action to 'out_port' or + * has the value OFPP_NONE. 'out_port' is in network-byte order. */ +int flow_has_out_port(struct sw_flow *flow, uint16_t out_port) +{ + struct sw_flow_actions *sf_acts = flow->sf_acts; + size_t actions_len = sf_acts->actions_len; + uint8_t *p = (uint8_t *)sf_acts->actions; + + if (out_port == htons(OFPP_NONE)) + return 1; + + while (actions_len > 0) { + struct ofp_action_header *ah = (struct ofp_action_header *)p; + size_t len = ntohs(ah->len); + + if (ah->type == htons(OFPAT_OUTPUT)) { + struct ofp_action_output *oa = (struct ofp_action_output *)p; + if (oa->port == out_port) { + return 1; + } + } + p += len; + actions_len -= len; + } + + return 0; +} + +void flow_used(struct sw_flow *flow, struct ofpbuf *buffer) +{ + flow->used = time_msec(); + + flow->packet_count++; + flow->byte_count += buffer->size; +} diff --git a/openflow/udatapath/switch-flow.h b/openflow/udatapath/switch-flow.h new file mode 100644 index 00000000..374cc737 --- /dev/null +++ b/openflow/udatapath/switch-flow.h @@ -0,0 +1,100 @@ +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#ifndef SWITCH_FLOW_H +#define SWITCH_FLOW_H 1 + +#include +#include "openflow/openflow.h" +#include "flow.h" +#include "list.h" + +struct ofp_match; + +/* Identification data for a flow. */ +struct sw_flow_key { + struct flow flow; /* Flow data (in network byte order). */ + uint32_t wildcards; /* Wildcard fields (in host byte order). */ + uint32_t nw_src_mask; /* 1-bit in each significant nw_src bit. */ + uint32_t nw_dst_mask; /* 1-bit in each significant nw_dst bit. */ +}; + +struct sw_flow_actions { + size_t actions_len; + struct ofp_action_header actions[0]; +}; + +struct sw_flow { + struct sw_flow_key key; + + uint64_t cookie; /* Opaque controller-issued identifier. */ + uint16_t priority; /* Only used on entries with wildcards. */ + uint16_t idle_timeout; /* Idle time before discarding (seconds). */ + uint16_t hard_timeout; /* Hard expiration time (seconds) */ + uint64_t used; /* Last used time. */ + uint64_t created; /* When the flow was created. */ + uint64_t packet_count; /* Number of packets seen. */ + uint64_t byte_count; /* Number of bytes seen. */ + uint8_t reason; /* Reason flow removed (one of OFPRR_*). */ + uint8_t send_flow_rem; /* Send a flow removed to the controller */ + uint8_t emerg_flow; /* Emergency flow indicator */ + + struct sw_flow_actions *sf_acts; + + /* Private to table implementations. */ + struct list node; + struct list iter_node; + unsigned long int serial; + + void *private; /* Cookie for tables */ +}; + +int flow_matches_1wild(const struct sw_flow_key *, const struct sw_flow_key *); +int flow_matches_2wild(const struct sw_flow_key *, const struct sw_flow_key *); +int flow_matches_desc(const struct sw_flow_key *, const struct sw_flow_key *, + int); +int flow_matches_2desc(const struct sw_flow_key *, const struct sw_flow_key *, + int); +int flow_has_out_port(struct sw_flow *flow, uint16_t out_port); +struct sw_flow *flow_alloc(size_t); +void flow_setup_actions(struct sw_flow *, const struct ofp_action_header *, int); +void flow_free(struct sw_flow *); +void flow_replace_acts(struct sw_flow *, const struct ofp_action_header *, + size_t); +void flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from); + +void print_flow(const struct sw_flow_key *); +bool flow_timeout(struct sw_flow *flow); +void flow_used(struct sw_flow *flow, struct ofpbuf *buffer); + +#endif /* switch-flow.h */ diff --git a/openflow/udatapath/table-hash.c b/openflow/udatapath/table-hash.c new file mode 100644 index 00000000..fc7006da --- /dev/null +++ b/openflow/udatapath/table-hash.c @@ -0,0 +1,469 @@ +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include "table.h" +#include +#include +#include +#include "openflow/nicira-ext.h" +#include "crc32.h" +#include "datapath.h" +#include "flow.h" +#include "switch-flow.h" + +struct sw_table_hash { + struct sw_table swt; + struct crc32 crc32; + unsigned int n_flows; + unsigned int bucket_mask; /* Number of buckets minus 1. */ + struct sw_flow **buckets; +}; + +static struct sw_flow **find_bucket(struct sw_table *swt, + const struct sw_flow_key *key) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + unsigned int crc = crc32_calculate(&th->crc32, key, + offsetof(struct sw_flow_key, wildcards)); + return &th->buckets[crc & th->bucket_mask]; +} + +static struct sw_flow *table_hash_lookup(struct sw_table *swt, + const struct sw_flow_key *key) +{ + struct sw_flow *flow = *find_bucket(swt, key); + return flow && !flow_compare(&flow->key.flow, &key->flow) ? flow : NULL; +} + +static int table_hash_insert(struct sw_table *swt, struct sw_flow *flow) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + struct sw_flow **bucket; + int retval; + + if (flow->key.wildcards != 0) + return 0; + + bucket = find_bucket(swt, &flow->key); + if (*bucket == NULL) { + th->n_flows++; + *bucket = flow; + retval = 1; + } else { + struct sw_flow *old_flow = *bucket; + if (!flow_compare(&old_flow->key.flow, &flow->key.flow)) { + *bucket = flow; + flow_free(old_flow); + retval = 1; + } else { + retval = 0; + } + } + return retval; +} + +static int table_hash_modify(struct sw_table *swt, + const struct sw_flow_key *key, uint16_t priority, int strict, + const struct ofp_action_header *actions, size_t actions_len) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + unsigned int count = 0; + + if (key->wildcards == 0) { + struct sw_flow **bucket = find_bucket(swt, key); + struct sw_flow *flow = *bucket; + if (flow && flow_matches_desc(&flow->key, key, strict) + && (!strict || (flow->priority == priority))) { + flow_replace_acts(flow, actions, actions_len); + count = 1; + } + } else { + unsigned int i; + + for (i = 0; i <= th->bucket_mask; i++) { + struct sw_flow **bucket = &th->buckets[i]; + struct sw_flow *flow = *bucket; + if (flow && flow_matches_desc(&flow->key, key, strict) + && (!strict || (flow->priority == priority))) { + flow_replace_acts(flow, actions, actions_len); + count++; + } + } + } + return count; +} + +static int table_hash_has_conflict(struct sw_table *swt, + const struct sw_flow_key *key, + uint16_t priority, int strict) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + + if (key->wildcards == 0) { + struct sw_flow **bucket = find_bucket(swt, key); + struct sw_flow *flow = *bucket; + if (flow && flow_matches_2desc(&flow->key, key,strict) + && (flow->priority == priority)) { + return true; + } + } else { + unsigned int i; + + for (i = 0; i <= th->bucket_mask; i++) { + struct sw_flow **bucket = &th->buckets[i]; + struct sw_flow *flow = *bucket; + if (flow && flow_matches_2desc(&flow->key, key, strict) + && (flow->priority == priority)) { + return true; + } + } + } + return false; +} + +/* Caller must update n_flows. */ +static void +do_delete(struct sw_flow **bucket) +{ + flow_free(*bucket); + *bucket = NULL; +} + +/* Returns number of deleted flows. We ignore the priority + * argument, since all exact-match entries are the same (highest) + * priority. */ +static int table_hash_delete(struct datapath *dp, struct sw_table *swt, + const struct sw_flow_key *key, + uint16_t out_port, + uint16_t priority UNUSED, int strict) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + unsigned int count = 0; + + if (key->wildcards == 0) { + struct sw_flow **bucket = find_bucket(swt, key); + struct sw_flow *flow = *bucket; + if (flow && !flow_compare(&flow->key.flow, &key->flow) + && flow_has_out_port(flow, out_port)) { + dp_send_flow_end(dp, flow, OFPRR_DELETE); + do_delete(bucket); + count = 1; + } + } else { + unsigned int i; + + for (i = 0; i <= th->bucket_mask; i++) { + struct sw_flow **bucket = &th->buckets[i]; + struct sw_flow *flow = *bucket; + if (flow && flow_matches_desc(&flow->key, key, strict) + && flow_has_out_port(flow, out_port)) { + dp_send_flow_end(dp, flow, OFPRR_DELETE); + do_delete(bucket); + count++; + } + } + } + th->n_flows -= count; + return count; +} + +static void table_hash_timeout(struct sw_table *swt, struct list *deleted) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + unsigned int i; + + for (i = 0; i <= th->bucket_mask; i++) { + struct sw_flow **bucket = &th->buckets[i]; + struct sw_flow *flow = *bucket; + if (flow && flow_timeout(flow)) { + list_push_back(deleted, &flow->node); + *bucket = NULL; + th->n_flows--; + } + } +} + +static void table_hash_destroy(struct sw_table *swt) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + unsigned int i; + for (i = 0; i <= th->bucket_mask; i++) { + if (th->buckets[i]) { + flow_free(th->buckets[i]); + } + } + free(th->buckets); + free(th); +} + +static int table_hash_iterate(struct sw_table *swt, + const struct sw_flow_key *key, uint16_t out_port, + struct sw_table_position *position, + int (*callback)(struct sw_flow *, void *private), + void *private) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + + if (position->private[0] > th->bucket_mask) + return 0; + + if (key->wildcards == 0) { + struct sw_flow *flow = table_hash_lookup(swt, key); + position->private[0] = -1; + if (!flow || !flow_has_out_port(flow, out_port)) { + return 0; + } + return callback(flow, private); + } else { + int i; + + for (i = position->private[0]; i <= th->bucket_mask; i++) { + struct sw_flow *flow = th->buckets[i]; + if (flow && flow_matches_1wild(&flow->key, key) + && flow_has_out_port(flow, out_port)) { + int error = callback(flow, private); + if (error) { + position->private[0] = i + 1; + return error; + } + } + } + return 0; + } +} + +static void table_hash_stats(struct sw_table *swt, + struct sw_table_stats *stats) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + stats->name = "hash"; + stats->wildcards = 0; /* No wildcards are supported. */ + stats->n_flows = th->n_flows; + stats->max_flows = th->bucket_mask + 1; + stats->n_lookup = swt->n_lookup; + stats->n_matched = swt->n_matched; +} + +struct sw_table *table_hash_create(unsigned int polynomial, + unsigned int n_buckets) +{ + struct sw_table_hash *th; + struct sw_table *swt; + + th = malloc(sizeof *th); + if (th == NULL) + return NULL; + memset(th, '\0', sizeof *th); + + assert(!(n_buckets & (n_buckets - 1))); + th->buckets = calloc(n_buckets, sizeof *th->buckets); + if (th->buckets == NULL) { + printf("failed to allocate %u buckets\n", n_buckets); + free(th); + return NULL; + } + th->n_flows = 0; + th->bucket_mask = n_buckets - 1; + + swt = &th->swt; + swt->lookup = table_hash_lookup; + swt->insert = table_hash_insert; + swt->modify = table_hash_modify; + swt->has_conflict = table_hash_has_conflict; + swt->delete = table_hash_delete; + swt->timeout = table_hash_timeout; + swt->destroy = table_hash_destroy; + swt->iterate = table_hash_iterate; + swt->stats = table_hash_stats; + + crc32_init(&th->crc32, polynomial); + + return swt; +} + +/* Double-hashing table. */ + +struct sw_table_hash2 { + struct sw_table swt; + struct sw_table *subtable[2]; +}; + +static struct sw_flow *table_hash2_lookup(struct sw_table *swt, + const struct sw_flow_key *key) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + int i; + + for (i = 0; i < 2; i++) { + struct sw_flow *flow = *find_bucket(t2->subtable[i], key); + if (flow && !flow_compare(&flow->key.flow, &key->flow)) + return flow; + } + return NULL; +} + +static int table_hash2_insert(struct sw_table *swt, struct sw_flow *flow) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + + if (table_hash_insert(t2->subtable[0], flow)) + return 1; + return table_hash_insert(t2->subtable[1], flow); +} + +static int table_hash2_modify(struct sw_table *swt, + const struct sw_flow_key *key, uint16_t priority, int strict, + const struct ofp_action_header *actions, size_t actions_len) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + return (table_hash_modify(t2->subtable[0], key, priority, strict, + actions, actions_len) + + table_hash_modify(t2->subtable[1], key, priority, strict, + actions, actions_len)); +} + +static int table_hash2_has_conflict(struct sw_table *swt, + const struct sw_flow_key *key, + uint16_t priority, int strict) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + return (table_hash_has_conflict(t2->subtable[0], key, priority, strict) || + table_hash_has_conflict(t2->subtable[1], key, priority, strict)); +} + +static int table_hash2_delete(struct datapath *dp, struct sw_table *swt, + const struct sw_flow_key *key, + uint16_t out_port, + uint16_t priority, int strict) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + return (table_hash_delete(dp, t2->subtable[0], key, out_port, + priority, strict) + + table_hash_delete(dp, t2->subtable[1], key, out_port, + priority, strict)); +} + +static void table_hash2_timeout(struct sw_table *swt, struct list *deleted) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + table_hash_timeout(t2->subtable[0], deleted); + table_hash_timeout(t2->subtable[1], deleted); +} + +static void table_hash2_destroy(struct sw_table *swt) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + table_hash_destroy(t2->subtable[0]); + table_hash_destroy(t2->subtable[1]); + free(t2); +} + +static int table_hash2_iterate(struct sw_table *swt, + const struct sw_flow_key *key, + uint16_t out_port, + struct sw_table_position *position, + int (*callback)(struct sw_flow *, void *), + void *private) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + int i; + + for (i = position->private[1]; i < 2; i++) { + int error = table_hash_iterate(t2->subtable[i], key, out_port, + position, callback, private); + if (error) { + return error; + } + position->private[0] = 0; + position->private[1]++; + } + return 0; +} + +static void table_hash2_stats(struct sw_table *swt, + struct sw_table_stats *stats) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + struct sw_table_stats substats[2]; + int i; + + for (i = 0; i < 2; i++) + table_hash_stats(t2->subtable[i], &substats[i]); + stats->name = "hash2"; + stats->wildcards = 0; /* No wildcards are supported. */ + stats->n_flows = substats[0].n_flows + substats[1].n_flows; + stats->max_flows = substats[0].max_flows + substats[1].max_flows; + stats->n_lookup = swt->n_lookup; + stats->n_matched = swt->n_matched; +} + +struct sw_table *table_hash2_create(unsigned int poly0, unsigned int buckets0, + unsigned int poly1, unsigned int buckets1) + +{ + struct sw_table_hash2 *t2; + struct sw_table *swt; + + t2 = malloc(sizeof *t2); + if (t2 == NULL) + return NULL; + memset(t2, '\0', sizeof *t2); + + t2->subtable[0] = table_hash_create(poly0, buckets0); + if (t2->subtable[0] == NULL) + goto out_free_t2; + + t2->subtable[1] = table_hash_create(poly1, buckets1); + if (t2->subtable[1] == NULL) + goto out_free_subtable0; + + swt = &t2->swt; + swt->lookup = table_hash2_lookup; + swt->insert = table_hash2_insert; + swt->modify = table_hash2_modify; + swt->has_conflict = table_hash2_has_conflict; + swt->delete = table_hash2_delete; + swt->timeout = table_hash2_timeout; + swt->destroy = table_hash2_destroy; + swt->iterate = table_hash2_iterate; + swt->stats = table_hash2_stats; + + return swt; + +out_free_subtable0: + table_hash_destroy(t2->subtable[0]); +out_free_t2: + free(t2); + return NULL; +} diff --git a/openflow/udatapath/table-linear.c b/openflow/udatapath/table-linear.c new file mode 100644 index 00000000..0aea0e25 --- /dev/null +++ b/openflow/udatapath/table-linear.c @@ -0,0 +1,262 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include "table.h" +#include +#include "flow.h" +#include "list.h" +#include "openflow/openflow.h" +#include "openflow/nicira-ext.h" +#include "switch-flow.h" +#include "datapath.h" + +struct sw_table_linear { + struct sw_table swt; + + unsigned int max_flows; + unsigned int n_flows; + struct list flows; + struct list iter_flows; + unsigned long int next_serial; +}; + +static struct sw_flow *table_linear_lookup(struct sw_table *swt, + const struct sw_flow_key *key) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + struct sw_flow *flow; + LIST_FOR_EACH (flow, struct sw_flow, node, &tl->flows) { + if (flow_matches_1wild(key, &flow->key)) + return flow; + } + return NULL; +} + +static int table_linear_insert(struct sw_table *swt, struct sw_flow *flow) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + struct sw_flow *f; + + /* Loop through the existing list of entries. New entries will + * always be placed behind those with equal priority. Just replace + * any flows that match exactly. + */ + LIST_FOR_EACH (f, struct sw_flow, node, &tl->flows) { + if (f->priority == flow->priority + && f->key.wildcards == flow->key.wildcards + && flow_matches_2wild(&f->key, &flow->key)) { + flow->serial = f->serial; + list_replace(&flow->node, &f->node); + list_replace(&flow->iter_node, &f->iter_node); + flow_free(f); + return 1; + } + + if (f->priority < flow->priority) + break; + } + + /* Make sure there's room in the table. */ + if (tl->n_flows >= tl->max_flows) { + return 0; + } + tl->n_flows++; + + /* Insert the entry immediately in front of where we're pointing. */ + flow->serial = tl->next_serial++; + list_insert(&f->node, &flow->node); + list_push_front(&tl->iter_flows, &flow->iter_node); + + return 1; +} + +static int table_linear_modify(struct sw_table *swt, + const struct sw_flow_key *key, uint16_t priority, int strict, + const struct ofp_action_header *actions, size_t actions_len) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + struct sw_flow *flow; + unsigned int count = 0; + + LIST_FOR_EACH (flow, struct sw_flow, node, &tl->flows) { + if (flow_matches_desc(&flow->key, key, strict) + && (!strict || (flow->priority == priority))) { + flow_replace_acts(flow, actions, actions_len); + count++; + } + } + return count; +} + +static int table_linear_has_conflict(struct sw_table *swt, + const struct sw_flow_key *key, + uint16_t priority, int strict) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + struct sw_flow *flow; + + LIST_FOR_EACH (flow, struct sw_flow, node, &tl->flows) { + if (flow_matches_2desc(&flow->key, key, strict) + && (flow->priority == priority)) { + return true; + } + } + return false; +} + +static void +do_delete(struct sw_flow *flow) +{ + list_remove(&flow->node); + list_remove(&flow->iter_node); + flow_free(flow); +} + +static int table_linear_delete(struct datapath *dp, struct sw_table *swt, + const struct sw_flow_key *key, + uint16_t out_port, + uint16_t priority, int strict) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + struct sw_flow *flow, *n; + unsigned int count = 0; + + LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &tl->flows) { + if (flow_matches_desc(&flow->key, key, strict) + && flow_has_out_port(flow, out_port) + && (!strict || (flow->priority == priority))) { + dp_send_flow_end(dp, flow, OFPRR_DELETE); + do_delete(flow); + count++; + } + } + tl->n_flows -= count; + return count; +} + +static void table_linear_timeout(struct sw_table *swt, struct list *deleted) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + struct sw_flow *flow, *n; + + LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &tl->flows) { + if (flow_timeout(flow)) { + list_remove(&flow->node); + list_remove(&flow->iter_node); + list_push_back(deleted, &flow->node); + tl->n_flows--; + } + } +} + +static void table_linear_destroy(struct sw_table *swt) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + + while (!list_is_empty(&tl->flows)) { + struct sw_flow *flow = CONTAINER_OF(list_front(&tl->flows), + struct sw_flow, node); + list_remove(&flow->node); + flow_free(flow); + } + free(tl); +} + +static int table_linear_iterate(struct sw_table *swt, + const struct sw_flow_key *key, + uint16_t out_port, + struct sw_table_position *position, + int (*callback)(struct sw_flow *, void *), + void *private) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + struct sw_flow *flow; + unsigned long start; + + start = ~position->private[0]; + LIST_FOR_EACH (flow, struct sw_flow, iter_node, &tl->iter_flows) { + if (flow->serial <= start + && flow_matches_2wild(key, &flow->key) + && flow_has_out_port(flow, out_port)) { + int error = callback(flow, private); + if (error) { + position->private[0] = ~(flow->serial - 1); + return error; + } + } + } + return 0; +} + +static void table_linear_stats(struct sw_table *swt, + struct sw_table_stats *stats) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + stats->name = "linear"; + stats->wildcards = OFPFW_ALL; + stats->n_flows = tl->n_flows; + stats->max_flows = tl->max_flows; + stats->n_lookup = swt->n_lookup; + stats->n_matched = swt->n_matched; +} + + +struct sw_table *table_linear_create(unsigned int max_flows) +{ + struct sw_table_linear *tl; + struct sw_table *swt; + + tl = calloc(1, sizeof *tl); + if (tl == NULL) + return NULL; + + swt = &tl->swt; + swt->lookup = table_linear_lookup; + swt->insert = table_linear_insert; + swt->modify = table_linear_modify; + swt->has_conflict = table_linear_has_conflict; + swt->delete = table_linear_delete; + swt->timeout = table_linear_timeout; + swt->destroy = table_linear_destroy; + swt->iterate = table_linear_iterate; + swt->stats = table_linear_stats; + + tl->max_flows = max_flows; + tl->n_flows = 0; + list_init(&tl->flows); + list_init(&tl->iter_flows); + tl->next_serial = 0; + + return swt; +} diff --git a/openflow/udatapath/table.h b/openflow/udatapath/table.h new file mode 100644 index 00000000..1312e3c9 --- /dev/null +++ b/openflow/udatapath/table.h @@ -0,0 +1,150 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +/* Individual switching tables. Generally grouped together in a chain (see + * chain.h). */ + +#ifndef TABLE_H +#define TABLE_H 1 + +#include +#include + +struct datapath; /* Forward declaration for delete operation */ +struct sw_flow; +struct sw_flow_key; +struct ofp_action_header; +struct list; + +/* Table statistics. */ +struct sw_table_stats { + const char *name; /* Human-readable name. */ + uint32_t wildcards; /* Bitmap of OFPFW_* wildcards that are + supported by the table. */ + unsigned int n_flows; /* Number of active flows. */ + unsigned int max_flows; /* Flow capacity. */ + unsigned long int n_lookup; /* Number of packets looked up. */ + unsigned long int n_matched; /* Number of packets that have hit. */ +}; + +/* Position within an iteration of a sw_table. + * + * The contents are private to the table implementation, except that a position + * initialized to all-zero-bits represents the start of a table. */ +struct sw_table_position { + unsigned long private[4]; +}; + +/* A single table of flows. */ +struct sw_table { + /* The number of packets that have been looked up and matched, + * respecitvely. To make these 100% accurate, they should be atomic. + * However, we're primarily concerned about speed. */ + unsigned long long n_lookup; + unsigned long long n_matched; + + /* Searches 'table' for a flow matching 'key', which must not have any + * wildcard fields. Returns the flow if successful, a null pointer + * otherwise. */ + struct sw_flow *(*lookup)(struct sw_table *table, + const struct sw_flow_key *key); + + /* Inserts 'flow' into 'table', replacing any duplicate flow. Returns + * 0 if successful or a negative error. Error can be due to an + * over-capacity table or because the flow is not one of the kind that + * the table accepts. + * + * If successful, 'flow' becomes owned by 'table', otherwise it is + * retained by the caller. */ + int (*insert)(struct sw_table *table, struct sw_flow *flow); + + /* Modifies the actions in 'table' that match 'key'. If 'strict' + * set, wildcards and priority must match. Returns the number of flows + * that were modified. */ + int (*modify)(struct sw_table *table, const struct sw_flow_key *key, + uint16_t priority, int strict, + const struct ofp_action_header *actions, size_t actions_len); + + /* Checks whether 'table' has an equal priotiry entry of thethat conflicts + * with 'key'. If 'strict' is set, wildcards must match. + * Returns the number of flows that were modified. */ + int (*has_conflict)(struct sw_table *table, const struct sw_flow_key *key, + uint16_t priority, int strict); + + /* Deletes from 'table' any and all flows that match 'key' from + * 'table'. If 'out_port' is not OFPP_NONE, then matching entries + * must have that port as an argument for an output action. If + * 'strict' is set, wildcards and priority must match. Returns the + * number of flows that were deleted. */ + int (*delete)(struct datapath *dp, struct sw_table *table, + const struct sw_flow_key *key, + uint16_t out_port, uint16_t priority, int strict); + + /* Performs timeout processing on all the flow entries in 'table'. + * Appends all the flow entries removed from 'table' to 'deleted' for the + * caller to free. */ + void (*timeout)(struct sw_table *table, struct list *deleted); + + /* Destroys 'table', which must not have any users. */ + void (*destroy)(struct sw_table *table); + + /* Iterates through the flow entries in 'table', passing each one + * matches 'key' and output port 'out_port' to 'callback'. The + * callback function should return 0 to continue iteration or a + * nonzero error code to stop. The iterator function returns either + * 0 if the table iteration completed or the value returned by the + * callback function otherwise. + * + * The iteration starts at 'position', which may be initialized to + * all-zero-bits to iterate from the beginning of the table. If the + * iteration terminates due to an error from the callback function, + * 'position' is updated to a value that can be passed back to the + * iterator function to resume iteration later with the following + * flow. */ + int (*iterate)(struct sw_table *table, + const struct sw_flow_key *key, uint16_t out_port, + struct sw_table_position *position, + int (*callback)(struct sw_flow *flow, void *private), + void *private); + + /* Dumps statistics for 'table' into 'stats'. */ + void (*stats)(struct sw_table *table, struct sw_table_stats *stats); +}; + +struct sw_table *table_hash_create(unsigned int polynomial, + unsigned int n_buckets); +struct sw_table *table_hash2_create(unsigned int poly0, unsigned int buckets0, + unsigned int poly1, unsigned int buckets1); +struct sw_table *table_linear_create(unsigned int max_flows); + +#endif /* table.h */ diff --git a/openflow/udatapath/udatapath.c b/openflow/udatapath/udatapath.c new file mode 100644 index 00000000..a4446575 --- /dev/null +++ b/openflow/udatapath/udatapath.c @@ -0,0 +1,345 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "command-line.h" +#include "daemon.h" +#include "datapath.h" +#include "fault.h" +#include "openflow/openflow.h" +#include "poll-loop.h" +#include "queue.h" +#include "util.h" +#include "rconn.h" +#include "timeval.h" +#include "vconn.h" +#include "dirs.h" +#include "vconn-ssl.h" +#include "vlog-socket.h" + +#if defined(OF_HW_PLAT) +#include +#endif + +#define THIS_MODULE VLM_udatapath +#include "vlog.h" + +/* Strings to describe the manufacturer, hardware, and software. This data + * is queriable through the switch description stats message. */ +char mfr_desc[DESC_STR_LEN] = "Stanford University"; +char hw_desc[DESC_STR_LEN] = "Reference Userspace Switch"; +char sw_desc[DESC_STR_LEN] = VERSION BUILDNR; +char dp_desc[DESC_STR_LEN] = ""; +char serial_num[SERIAL_NUM_LEN] = "None"; + +static void parse_options(int argc, char *argv[]); +static void usage(void) NO_RETURN; + +static struct datapath *dp; +static uint64_t dpid = UINT64_MAX; +static char *port_list; +static char *local_port = "tap:"; +static uint16_t num_queues = NETDEV_MAX_QUEUES; + +static void add_ports(struct datapath *dp, char *port_list); + +/* Need to treat this more generically */ +#if defined(UDATAPATH_AS_LIB) +#define OFP_FATAL(_er, _str, args...) do { \ + fprintf(stderr, _str, ## args); \ + return -1; \ + } while (0) +#else +#define OFP_FATAL(_er, _str, args...) ofp_fatal(_er, _str, ## args) +#endif + +#if !defined(UDATAPATH_AS_LIB) +int +main(int argc, char *argv[]) +{ + return udatapath_cmd(argc, argv); +} +#endif + +int +udatapath_cmd(int argc, char *argv[]) +{ + int n_listeners; + int error; + int i; + + set_program_name(argv[0]); + register_fault_handlers(); + time_init(); + vlog_init(); + parse_options(argc, argv); + signal(SIGPIPE, SIG_IGN); + + if (argc - optind < 1) { + OFP_FATAL(0, "at least one listener argument is required; " + "use --help for usage"); + } + + error = dp_new(&dp, dpid); + + n_listeners = 0; + for (i = optind; i < argc; i++) { + const char *pvconn_name = argv[i]; + struct pvconn *pvconn; + int retval; + + retval = pvconn_open(pvconn_name, &pvconn); + if (!retval || retval == EAGAIN) { + dp_add_pvconn(dp, pvconn); + n_listeners++; + } else { + ofp_error(retval, "opening %s", pvconn_name); + } + } + if (!n_listeners) { + OFP_FATAL(0, "could not listen for any connections"); + } + + if (port_list) { + add_ports(dp, port_list); + } + if (local_port) { + error = dp_add_local_port(dp, local_port, 0); + if (error) { + OFP_FATAL(error, "failed to add local port %s", local_port); + } + } + + error = vlog_server_listen(NULL, NULL); + if (error) { + OFP_FATAL(error, "could not listen for vlog connections"); + } + + die_if_already_running(); + daemonize(); + + for (;;) { + dp_run(dp); + dp_wait(dp); + poll_block(); + } + + return 0; +} + +static void +add_ports(struct datapath *dp, char *port_list) +{ + char *port, *save_ptr; + + /* Glibc 2.7 has a bug in strtok_r when compiling with optimization that + * can cause segfaults here: + * http://sources.redhat.com/bugzilla/show_bug.cgi?id=5614. + * Using ",," instead of the obvious "," works around it. */ + for (port = strtok_r(port_list, ",,", &save_ptr); port; + port = strtok_r(NULL, ",,", &save_ptr)) { + int error = dp_add_port(dp, port, num_queues); + if (error) { + ofp_fatal(error, "failed to add port %s", port); + } + } +} + +static void +parse_options(int argc, char *argv[]) +{ + enum { + OPT_MFR_DESC = UCHAR_MAX + 1, + OPT_HW_DESC, + OPT_SW_DESC, + OPT_DP_DESC, + OPT_SERIAL_NUM, + OPT_BOOTSTRAP_CA_CERT, + OPT_NO_LOCAL_PORT, + OPT_NO_SLICING + }; + + static struct option long_options[] = { + {"interfaces", required_argument, 0, 'i'}, + {"local-port", required_argument, 0, 'L'}, + {"no-local-port", no_argument, 0, OPT_NO_LOCAL_PORT}, + {"datapath-id", required_argument, 0, 'd'}, + {"verbose", optional_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {"no-slicing", no_argument, 0, OPT_NO_SLICING}, + {"mfr-desc", required_argument, 0, OPT_MFR_DESC}, + {"hw-desc", required_argument, 0, OPT_HW_DESC}, + {"sw-desc", required_argument, 0, OPT_SW_DESC}, + {"dp_desc", required_argument, 0, OPT_DP_DESC}, + {"serial_num", required_argument, 0, OPT_SERIAL_NUM}, + DAEMON_LONG_OPTIONS, +#ifdef HAVE_OPENSSL + VCONN_SSL_LONG_OPTIONS + {"bootstrap-ca-cert", required_argument, 0, OPT_BOOTSTRAP_CA_CERT}, +#endif + {0, 0, 0, 0}, + }; + char *short_options = long_options_to_short_options(long_options); + + for (;;) { + int indexptr; + int c; + + c = getopt_long(argc, argv, short_options, long_options, &indexptr); + if (c == -1) { + break; + } + + switch (c) { + case 'd': + if (strlen(optarg) != 12 + || strspn(optarg, "0123456789abcdefABCDEF") != 12) { + ofp_fatal(0, "argument to -d or --datapath-id must be " + "exactly 12 hex digits"); + } + dpid = strtoll(optarg, NULL, 16); + if (!dpid) { + ofp_fatal(0, "argument to -d or --datapath-id must " + "be nonzero"); + } + break; + + case 'h': + usage(); + + case 'V': + printf("%s %s compiled "__DATE__" "__TIME__"\n", + program_name, VERSION BUILDNR); + exit(EXIT_SUCCESS); + + case 'v': + vlog_set_verbosity(optarg); + break; + + case 'i': + if (!port_list) { + port_list = optarg; + } else { + port_list = xasprintf("%s,%s", port_list, optarg); + } + break; + + case 'L': + local_port = optarg; + break; + + case OPT_NO_LOCAL_PORT: + local_port = NULL; + break; + + case OPT_MFR_DESC: + strncpy(mfr_desc, optarg, sizeof mfr_desc); + break; + + case OPT_HW_DESC: + strncpy(hw_desc, optarg, sizeof hw_desc); + break; + + case OPT_SW_DESC: + strncpy(sw_desc, optarg, sizeof sw_desc); + break; + + case OPT_DP_DESC: + strncpy(dp_desc, optarg, sizeof dp_desc); + break; + + case OPT_SERIAL_NUM: + strncpy(serial_num, optarg, sizeof serial_num); + break; + + case OPT_NO_SLICING: + num_queues = 0; + break; + + DAEMON_OPTION_HANDLERS + +#ifdef HAVE_OPENSSL + VCONN_SSL_OPTION_HANDLERS + + case OPT_BOOTSTRAP_CA_CERT: + vconn_ssl_set_ca_cert_file(optarg, true); + break; +#endif + + case '?': + exit(EXIT_FAILURE); + + default: + abort(); + } + } + free(short_options); +} + +static void +usage(void) +{ + printf("%s: userspace OpenFlow datapath\n" + "usage: %s [OPTIONS] LISTEN...\n" + "where LISTEN is a passive OpenFlow connection method on which\n" + "to listen for incoming connections from the secure channel.\n", + program_name, program_name); + vconn_usage(false, true, false); + printf("\nConfiguration options:\n" + " -i, --interfaces=NETDEV[,NETDEV]...\n" + " add specified initial switch ports\n" + " -L, --local-port=NETDEV set network device for local port\n" + " --no-local-port disable local port\n" + " -d, --datapath-id=ID Use ID as the OpenFlow switch ID\n" + " (ID must consist of 12 hex digits)\n" + " --no-slicing disable slicing\n" + "\nOther options:\n" + " -D, --detach run in background as daemon\n" + " -P, --pidfile[=FILE] create pidfile (default: %s/ofdatapath.pid)\n" + " -f, --force with -P, start even if already running\n" + " -v, --verbose=MODULE[:FACILITY[:LEVEL]] set logging levels\n" + " -v, --verbose set maximum verbosity level\n" + " -h, --help display this help message\n" + " -V, --version display version information\n", + ofp_rundir); + exit(EXIT_SUCCESS); +} diff --git a/openflow/utilities/.dirstamp b/openflow/utilities/.dirstamp new file mode 100644 index 00000000..e69de29b diff --git a/openflow/utilities/.gitignore b/openflow/utilities/.gitignore new file mode 100644 index 00000000..c93169bf --- /dev/null +++ b/openflow/utilities/.gitignore @@ -0,0 +1,13 @@ +/Makefile +/Makefile.in +/dpctl +/dpctl.8 +/ofp-discover +/ofp-discover.8 +/ofp-kill +/ofp-kill.8 +/ofp-pki +/ofp-pki-cgi +/ofp-pki.8 +/vlogconf +/vlogconf.8 diff --git a/openflow/utilities/automake.mk b/openflow/utilities/automake.mk new file mode 100644 index 00000000..d6f79a8c --- /dev/null +++ b/openflow/utilities/automake.mk @@ -0,0 +1,45 @@ +bin_PROGRAMS += \ + utilities/vlogconf \ + utilities/dpctl \ + utilities/ofp-discover \ + utilities/ofp-kill +bin_SCRIPTS += utilities/ofp-pki +noinst_SCRIPTS += utilities/ofp-pki-cgi utilities/ofp-parse-leaks + +EXTRA_DIST += \ + utilities/dpctl.8.in \ + utilities/ofp-discover.8.in \ + utilities/ofp-kill.8.in \ + utilities/ofp-parse-leaks.in \ + utilities/ofp-pki-cgi.in \ + utilities/ofp-pki.8.in \ + utilities/ofp-pki.in \ + utilities/vlogconf.8.in +DISTCLEANFILES += \ + utilities/dpctl.8 \ + utilities/ofp-discover.8 \ + utilities/ofp-kill.8 \ + utilities/ofp-parse-leaks \ + utilities/ofp-pki \ + utilities/ofp-pki.8 \ + utilities/ofp-pki-cgi \ + utilities/vlogconf.8 + +man_MANS += \ + utilities/dpctl.8 \ + utilities/ofp-discover.8 \ + utilities/ofp-kill.8 \ + utilities/ofp-pki.8 \ + utilities/vlogconf.8 + +utilities_dpctl_SOURCES = utilities/dpctl.c +utilities_dpctl_LDADD = lib/libopenflow.a $(FAULT_LIBS) $(SSL_LIBS) + +utilities_vlogconf_SOURCES = utilities/vlogconf.c +utilities_vlogconf_LDADD = lib/libopenflow.a + +utilities_ofp_discover_SOURCES = utilities/ofp-discover.c +utilities_ofp_discover_LDADD = lib/libopenflow.a + +utilities_ofp_kill_SOURCES = utilities/ofp-kill.c +utilities_ofp_kill_LDADD = lib/libopenflow.a diff --git a/openflow/utilities/dpctl.8.in b/openflow/utilities/dpctl.8.in new file mode 100644 index 00000000..80f06bb0 --- /dev/null +++ b/openflow/utilities/dpctl.8.in @@ -0,0 +1,582 @@ +.ds PN dpctl + +.TH dpctl 8 "May 2008" "OpenFlow" "OpenFlow Manual" + +.SH NAME +dpctl \- administer OpenFlow datapaths + +.SH SYNOPSIS +.B dpctl +[\fIoptions\fR] \fIcommand \fR[\fIswitch\fR] [\fIargs\fR&...] + +.SH DESCRIPTION +The +.B dpctl +program is a command line tool for monitoring and administering OpenFlow +datapaths. It is able to show the current state of a datapath, +including features, configuration, and tables entries. When using the +OpenFlow kernel module, +.B dpctl +is used to add, delete, modify, and monitor datapaths. + +Most \fBdpctl\fR commands take an argument that specifies the +method for connecting to an OpenFlow switch. The following connection +methods are supported: + +.TP +\fBnl:\fIdp_idx\fR +The local Netlink datapath numbered \fIdp_idx\fR. This form requires +that the local host has the OpenFlow kernel module for Linux loaded. + +.TP +\fBssl:\fIhost\fR[\fB:\fIport\fR] +The specified SSL \fIport\fR (default: 6633) on the given remote +\fIhost\fR. The \fB--private-key\fR, \fB--certificate\fR, and +\fB--ca-cert\fR options are mandatory when this form is used. + +.TP +\fBtcp:\fIhost\fR[\fB:\fIport\fR] +The specified TCP \fIport\fR (default: 6633) on the given remote +\fIhost\fR. + +.TP +\fBunix:\fIfile\fR +The Unix domain server socket named \fIfile\fR. + +.SH COMMANDS + +With the \fBdpctl\fR program, datapaths running in the kernel can be +created, deleted, and modified. A single machine may +host up to 32 datapaths (numbered 0 to 31). In most situations, +a machine hosts only one datapath. + +A newly created datapath is not associated with any of the +host's network devices thus does not process any incoming +traffic. To intercept and process traffic on a given network device, the +network device must be explicitly added to a datapath through the +\fBaddif\fR command. + +The following commands manage local datapaths. + +.TP +\fBadddp nl:\fIdp_idx\fR +Creates datapath numbered \fIdp_idx\fR on the local host. This will +fail if \fIdp_idx\fR is not in the range 0 to 31, or if the datapath +with that number already exists on the host. + +.TP +\fBdeldp nl:\fIdp_idx\fR +Deletes datapath \fIdp_idx\fR on the local host. \fIdp_idx\fR must be +an existing datapath. All of a datapath's network devices must be +explicitly removed before the datapath can be deleted (see \fBdelif\fR +command). + +.TP +\fBaddif nl:\fIdp_idx netdev\fR... +Adds each \fInetdev\fR to the list of network devices datapath +\fIdp_idx\fR monitors, where \fIdp_idx\fR is the ID of an existing +datapath, and \fInetdev\fR is the name of one of the host's +network devices, e.g. \fBeth0\fR. Once a network device has been added +to a datapath, the datapath has complete ownership of the network device's +traffic and the network device appears silent to the rest of the system. + +.TP +\fBdelif nl:\fIdp_idx netdev\fR... +Removes each \fInetdev\fR from the list of network devices datapath +\fIdp_idx\fR monitors. + +.TP +\fBget-idx \fIof_dev\fR +Prints the datapath index for OpenFlow device \fIof_dev\fR. + +.PP +The following commands can be apply to OpenFlow switches regardless of +the connection method. + +.TP +\fBshow \fIswitch\fR +Prints to the console information on datapath \fIswitch\fR including +information on its flow tables and ports. + +.TP +\fBstatus \fIswitch\fR [\fIkey\fR] +Prints to the console a series of key-value pairs that report the +status of \fIswitch\fR. If \fIkey\fR is specified, only the key-value +pairs whose key names begin with \fIkey\fR are printed. If \fIkey\fR is +omitted, all key-value pairs are printed. + +(In the OpenFlow reference implementation, the \fBstatus\fR command is +implemented in \fBofprotocol\fR(8), not in the kernel module, so the +\fBnl:\fIdp_idx\fR connection method should not be used with this +command. Instead, specify \fB-l\fR or \fB--listen\fR on the +\fBofprotocol\fR command line and tell \fBdpctl\fR to use the connection +method specified there.) + +.TP +\fBshow-protostat \fIswitch\fR +Prints to the OpenFlow protocol statiscal information of \fIswitch\fR. + +(In the OpenFlow reference implementation, the \fBshow-protostat\fR command +is implemented in \fBofprotocol\fR(8), not in the kernel module, so the +\fBnl:\fIdp_idx\fR connection method should not be used with this +command. Instead, specify \fB-l\fR or \fB--listen\fR on the +\fBofprotocol\fR command line and tell \fBdpctl\fR to use the connection +method specified there.) + +.TP +\fBdump-tables \fIswitch\fR +Prints to the console statistics for each of the flow tables used by +datapath \fIswitch\fR. + +.TP +\fBdump-ports \fIswitch\fR \fR[\fIport number\fR] +Prints to the console statistics for each interface monitored by +\fIswitch\fR. If port number is specified, print statistics only for +the interface corresponding to port number. + +.TP +\fBmod-port \fIswitch\fR \fInetdev\fR \fIaction\fR +Modify characteristics of an interface monitored by \fIswitch\fR. +\fInetdev\fR can be referred to by its OpenFlow assigned port number or +the device name, e.g. \fBeth0\fR. The \fIaction\fR may be any one of the +following: + +.RS +.IP \fBup\fR +Enables the interface. This is equivalent to ``ifconfig up'' on a Unix +system. + +.IP \fBdown\fR +Disables the interface. This is equivalent to ``ifconfig down'' on a Unix +system. + +.IP \fBflood\fR +When a \fIflood\fR action is specified, traffic will be sent out this +interface. This is the default posture for monitored ports. + +.IP \fBnoflood\fR +When a \fIflood\fR action is specified, traffic will not be sent out +this interface. This is primarily useful to prevent loops when a +spanning tree protocol is not in use. + +.RE + +.TP +\fBdump-flows \fIswitch \fR[\fIflows\fR] +Prints to the console all flow entries in datapath \fIswitch\fR's +tables that match \fIflows\fR. If \fIflows\fR is omitted, all flows +except emergency flows in the datapath flows are retrieved. +See \fBFLOW SYNTAX\fR, below, for the syntax of \fIflows\fR. + +.TP +\fBdesc \fIswitch \fIstring +Sets the switch description (as returned in ofp_desc_stats) to +\fIstring (max length is DESC_STR_LEN). + +.TP +\fBdump-aggregate \fIswitch \fR[\fIflows\fR] +Prints to the console aggregate statistics for flows in datapath +\fSWITCH\fR's tables that match \fIflows\fR. If \fIflows\fR is omitted, +the statistics are aggregated across all flows in the datapath's flow +tables. See \fBFLOW SYNTAX\fR, below, for the syntax of \fIflows\fR. + +.TP +\fBadd-flow \fIswitch flow\fR +Add the flow entry as described by \fIflow\fR to the datapath \fIswitch\fR's +tables. The flow entry is in the format described in \fBFLOW SYNTAX\fR, +below. + +.TP +\fBadd-flows \fIswitch file\fR +Add flow entries as described in \fIfile\fR to the datapath \fIswitch\fR's +tables. Each line in \fIfile\fR is a flow entry in the format +described in \fBFLOW SYNTAX\fR, below. + +.TP +\fBmod-flows \fIswitch flow\fR +Modify the actions in entries from the datapath \fIswitch\fR's tables +that match \fIflow\fR. When invoked with the \fB--strict\fR option, +wildcards are not treated as active for matching purposes. See +\fBFLOW SYNTAX\fR, below, for the syntax of \fIflows\fR. + +.TP +\fBdel-flows \fIswitch \fR[\fIflow\fR] +Deletes entries from the datapath \fIswitch\fR's tables that match +\fIflow\fR. When invoked with the \fB--strict\fR option, wildcards are +not treated as active for matching purposes. If \fIflow\fR is +omitted and the \fB--strict\fR option is not used, all flows in the +datapath's tables are removed. See \fBFLOW SYNTAX\fR, below, for the +syntax of \fIflows\fR. + +.TP +\fBmonitor \fIswitch\fR +Connects to \fIswitch\fR and prints to the console all OpenFlow +messages received. Usually, \fIswitch\fR should specify a connection +named on \fBofprotocol\fR(8)'s \fB-m\fR or \fB--monitor\fR command line +option, in which the messages printed will be all those sent or +received by \fBofprotocol\fR to or from the kernel datapath module. A +\fIswitch\fR of the form \fBnl:\fIdp_idx\fR will print all +asynchronously generated OpenFlow messages (such as packet-in +messages), but it will not print any messages sent to the kernel by +\fBofprotocol\fR and other processes, nor will it print replies sent by +the kernel in response to those messages. + +.PP +The following commands monitor and control the egress queue +configuration for an OpenFlow switch if the switch supports such +operations. After a queue is created with the add or modify +operation, the OpenFlow enqueue action may be specified to +direct packets to a particular queue. Queues are associated with +specific ports (so the same queue-id may be used on different +ports and this will refer to different queues). The only +characteristic that may be configured for queues is the minimum +bandwidth guarantee. This parameter is specified in tenths of +a percent (so full link bandwidth is 1000). + +.TP +\fBadd-queue \fIswitch\fR \fIport\fR \fIq-id\fR [\fIbandwidth\fR] +Connect to \fIswitch\fR and add an egress queue identified as \fIq-id\fR +for \fIport\fR. If +specified, \fIbandwidth\fR indicates the minimum bandwidth guarantee +for the queue and is specified in tenths of a +percent. This is the only characteristic of the queue that +may be configured. + +.TP +\fBmod-queue \fIswitch\fR \fIport\fR \fIq-id\fR \fIbandwidth\fR +Connect to \fIswitch\fR and modify the bandwidth setting for an egress +queue identified as \fIq-id\fR +for \fIport\fR. The queue need not have been created with \fBadd-queue\fR +previously. The parameter \fIbandwidth\fR indicates the minimum +bandwidth guarantee for the queue and is specified in tenths of a +percent. This is the only characteristic +of the queue that may be configured. + +.TP +\fBdel-queue \fIswitch\fR \fIport\fR \fIq-id\fR +Delete an egress queue identified as \fIq-id\fR for \fIport\fR which +had been created by \fBadd-queue\fR or \fBmod-queue\fR. + +.TP +\fBdump-queue \fIswitch\fR [\fIport\fR [\fIq-id\fR]] +Dump that current queue configuration. A port may be specified. +If it is, a queue-id may also be specified. + +.PP +The following commands can be used regardless of the connection +method. They apply to OpenFlow switches and controllers. + +.TP +\fBprobe \fIvconn\fR +Connects to \fIvconn\fR and sends a single OpenFlow echo-request +packet and waits for the response. With the \fB-t\fR or +\fB--timeout\fR option, this command can test whether an OpenFlow +switch or controller is up and running. + +.TP +\fBping \fIvconn \fR[\fIn\fR] +Sends a series of 10 echo request packets to \fIvconn\fR and times +each reply. The echo request packets consist of an OpenFlow header +plus \fIn\fR bytes (default: 64) of randomly generated payload. This +measures the latency of individual requests. + +.TP +\fBbenchmark \fIvconn n count\fR +Sends \fIcount\fR echo request packets that each consist of an +OpenFlow header plus \fIn\fR bytes of payload and waits for each +response. Reports the total time required. This is a measure of the +maximum bandwidth to \fIvconn\fR for round-trips of \fIn\fR-byte +messages. + +.SH "FLOW SYNTAX" + +Some \fBdpctl\fR commands accept an argument that describes a flow or +flows. Such flow descriptions comprise a series +\fIfield\fB=\fIvalue\fR assignments, separated by commas or white +space. + +The following field assignments describe how a flow matches a packet. +If any of these assignments is omitted from the flow syntax, the field +is treated as a wildcard; thus, if all of them are omitted, the +resulting flow matches all packets. The string \fB*\fR or \fBANY\fR +may be specified a value to explicitly mark any of these fields as a +wildcard. + +.IP \fBin_port=\fIport_no\fR +Matches physical port \fIport_no\fR. Switch ports are numbered as +displayed by \fBdpctl show\fR. + +.IP \fBdl_vlan=\fIvlan\fR +Matches IEEE 802.1q virtual LAN tag \fIvlan\fR. Specify \fB0xffff\fR +as \fIvlan\fR to match packets that are not tagged with a virtual LAN; +otherwise, specify a number between 0 and 4095, inclusive, as the +12-bit VLAN ID to match. + +.IP \fBdl_src=\fImac\fR +Matches Ethernet source address \fImac\fR, which should be specified +as 6 pairs of hexadecimal digits delimited by colons, +e.g. \fB00:0A:E4:25:6B:B0\fR. + +.IP \fBdl_dst=\fImac\fR +Matches Ethernet destination address \fImac\fR. + +.IP \fBdl_type=\fIethertype\fR +Matches Ethernet protocol type \fIethertype\fR, which should be +specified as a integer between 0 and 65535, inclusive, either in +decimal or as a hexadecimal number prefixed by \fB0x\fR, +e.g. \fB0x0806\fR to match ARP packets. + +.IP \fBnw_src=\fIip\fR[\fB/\fInetmask\fR] +Matches IPv4 source address \fIip\fR, which should be specified as an +IP address or host name, e.g. \fB192.168.1.1\fR or +\fBwww.example.com\fR. The optional \fInetmask\fR allows matching +only on an IPv4 address prefix. It may be specified as a dotted quad +(e.g. \fB192.168.1.0/255.255.255.0\fR) or as a count of bits +(e.g. \fB192.168.1.0/24\fR). + +.IP \fBnw_dst=\fIip\fR[\fB/\fInetmask\fR] +Matches IPv4 destination address \fIip\fR. + +.IP \fBnw_proto=\fIproto\fR +Matches IP protocol type \fIproto\fR, which should be specified as a +decimal number between 0 and 255, inclusive, e.g. 6 to match TCP +packets. + +.IP \fBnw_tos=\fItos/dscp\fR +Matches ToS/DSCP (only 6-bits, not modify reserved 2-bits for future +use) field of IPv4 header \fItos/dscp\fR, which should be specified as +a decimal number between 0 and 255, inclusive. + +.IP \fBtp_src=\fIport\fR +Matches UDP or TCP source port \fIport\fR, which should be specified +as a decimal number between 0 and 65535, inclusive, e.g. 80 to match +packets originating from a HTTP server. + +.IP \fBtp_dst=\fIport\fR +Matches UDP or TCP destination port \fIport\fR. + +.IP \fBicmp_type=\fItype\fR +Matches ICMP message with \fItype\fR, which should be specified as a decimal +number between 0 and 255, inclusive. + +.IP \fBicmp_code=\fIcode\fR +Matches ICMP messages with \fIcode\fR. + +.PP +The following shorthand notations are also available: + +.IP \fBip\fR +Same as \fBdl_type=0x0800\fR. + +.IP \fBicmp\fR +Same as \fBdl_type=0x0800,nw_proto=1\fR. + +.IP \fBtcp\fR +Same as \fBdl_type=0x0800,nw_proto=6\fR. + +.IP \fBudp\fR +Same as \fBdl_type=0x0800,nw_proto=17\fR. + +.IP \fBarp\fR +Same as \fBdl_type=0x0806\fR. + +.PP +The \fBadd-flow\fR and \fBadd-flows\fR commands require an additional field: + +.IP \fIactions\fB=\fItarget\fR[\fB,\fItarget\fR...]\fR +Specifies a comma-separated list of actions to take on a packet when the +flow entry matches. The \fItarget\fR may be a decimal port number +designating the physical port on which to output the packet, or one of +the following keywords: + +.RS +.IP \fBoutput\fR:\fIport\fR +Outputs the packet on the port specified by \fIport\fR. + +.IP \fBenqueue\fR:\fIport\fR:\fIq-id\fR +Enqueue the packet to the queue specified by \fIq-id\fR on the port +specified by \fIport\fR. See \fBadd-queue\fR and related commands +in this manpage above. + +.IP \fBnormal\fR +Subjects the packet to the device's normal L2/L3 processing. (This +action is not implemented by all OpenFlow switches.) + +.IP \fBflood\fR +Outputs the packet on all switch physical ports other than the port on +which it was received and any ports on which flooding is disabled +(typically, these would be ports disabled by the IEEE 802.1D spanning +tree protocol). + +.IP \fBall\fR +Outputs the packet on all switch physical ports other than the port on +which it was received. + +.IP \fBcontroller\fR:\fImax_len\fR +Sends the packet to the OpenFlow controller as a ``packet in'' +message. If \fImax_len\fR is a number, then it specifies the maximum +number of bytes that should be sent. If \fImax_len\fR is \fBALL\fR or +omitted, then the entire packet is sent. + +.IP \fBlocal\fR +Outputs the packet on the ``local port,'' which corresponds to the +\fBof\fIn\fR network device (see \fBCONTACTING THE CONTROLLER\fR in +\fBofprotocol\fR(8) for information on the \fBof\fIn\fR network device). + +.IP \fBmod_vlan_vid\fR:\fIvlan_vid\fR +Modifies the VLAN id on a packet. The VLAN tag is added or modified +as necessary to match the value specified. If the VLAN tag is added, +a priority of zero is used (see the \fBmod_vlan_pcp\fR action to set +this). + +.IP \fBmod_vlan_pcp\fR:\fIvlan_pcp\fR +Modifies the VLAN priority on a packet. The VLAN tag is added or modified +as necessary to match the value specified. Valid values are between 0 +(lowest) and 7 (highest). If the VLAN tag is added, a vid of zero is used +(see the \fBmod_vlan_vid\fR action to set this). + +.IP \fBmod_dl_dst\fR:\fIdst_mac\fR +Modifies the destination mac address on a packet, e.g., actions=mod_dl_dst:12:34:56:78:9a:bc + +.IP \fBmod_dl_src\fR:\fIsrc_mac\fR +Modifies the source mac address on a packet, e.g., actions=mod_dl_src:12:34:56:78:9a:bc + +.IP \fBmod_nw_tos\fR:\fItos/dscp\fR +Modifies the ToS/DSCP (only 6-bits, not modify reserved 2-bits for future use) field of IPv4 header on a packet. + +.IP \fBstrip_vlan\fR +Strips the VLAN tag from a packet if it is present. +.RE + +.IP +(The OpenFlow protocol supports other actions that \fBdpctl\fR does +not yet expose to the user.) + +.PP +The \fBadd-flow\fR, \fBadd-flows\fR, \fBdel-flows\fR, +and \fBdel-emerg-flows\fR commands support an additional optional field: + +.IP \fBpriority=\fIvalue\fR +Sets the priority of the flow to be added or deleted to \fIvalue\fR, +which should be a number between 0 and 65535, inclusive. If this +field is not specified, it defaults to 32768. + +.PP +The \fBadd-flow\fR and \fBadd-flows\fR commands support +additional optional fields: + +.TP +\fBidle_timeout=\fIseconds\fR +Causes the flow to expire after the given number of seconds of +inactivity. A value of 0 prevents a flow from expiring due to +inactivity. The default is 60 seconds. + +.IP \fBhard_timeout=\fIseconds\fR +Causes the flow to expire after the given number of seconds, +regardless of activity. A value of 0 (the default) gives the flow no +hard expiration deadline. + +.PP +The \fBdump-flows\fR, \fBdump-aggregate\fR and \fBdel-flows\fR +commands support the additional optional field: + +.TP +\fBout_port=\fIport\fR +If set, a matching flow must include an output action to \fIport\fR. + +.PP +\fBadd-flow\fR, \fBadd-flows\fR, \fBdel-flows\fR, \fBdump-flows\fR, +and \fBdump-aggregate\fR commands support the additional +optional field: + +.IP \fBtable=\fInumber\fR +If specified, limits the flows about which statistics are gathered to +those in the table with the given \fInumber\fR. Normal (non emergency) +tables are numbered as shown by the \fBdump-tables\fR command. + +If this field is not specified, or if \fInumber\fR is given as +\fB255\fR, statistics are gathered about flows from all normal (non +emergency) tables and flow manipulations are applied to notmal tables. + +If this field is given as \fB254\fR, statistics are gathered about +flows from emergency table and flow manipulations are applied to +emergency table. + +.SH OPTIONS +.TP +\fB--strict\fR +Uses strict matching when running flow modification commands. + +.TP +\fB-t\fR, \fB--timeout=\fIsecs\fR +Limits \fBdpctl\fR runtime to approximately \fIsecs\fR seconds. If +the timeout expires, \fBdpctl\fR will exit with a \fBSIGALRM\fR +signal. + +.TP +\fB-p\fR, \fB--private-key=\fIprivkey.pem\fR +Specifies a PEM file containing the private key used as the +identity for SSL connections to a switch. + +.TP +\fB-c\fR, \fB--certificate=\fIcert.pem\fR +Specifies a PEM file containing a certificate, signed by the +controller's certificate authority (CA), that certifies the +private key to identify a trustworthy controller. + +.TP +\fB-C\fR, \fB--ca-cert=\fIcacert.pem\fR +Specifies a PEM file containing the CA certificate used to verify that +a switch is trustworthy. + +.so lib/vlog.man +.so lib/common.man + +.SH EXAMPLES + +A typical dpctl command sequence for controlling an OpenFlow kernel module: +.nf +.TP +Create datapath numbered 0: + +.B % dpctl adddp nl:0 + +.TP +Add two network devices to the new datapath: + +.B % dpctl addif nl:0 eth0 +.B % dpctl addif nl:0 eth1 + +.TP +Monitor traffic received by the datapath (exit with control-C): + +.B % dpctl monitor nl:0 + + +.TP +View the datapath's table stats after some traffic has passed through: + +.B % dpctl dump-tables nl:0 + +.TP +View the flow entries in the datapath: + +.B % dpctl dump-flows nl:0 + +.TP +Remove network devices from the datapath when finished: + +.B % dpctl delif nl:0 eth0 +.B % dpctl delif nl:0 eth1 + +.TP +Delete the datapath: + +.B % dpctl deldp nl:0 +.fi +.SH "SEE ALSO" + +.BR ofprotocol (8), +.BR controller (8), +.BR ofdatapath (8), +.BR vlogconf (8) diff --git a/openflow/utilities/dpctl.c b/openflow/utilities/dpctl.c new file mode 100644 index 00000000..0406d9b5 --- /dev/null +++ b/openflow/utilities/dpctl.c @@ -0,0 +1,1772 @@ +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_NETLINK +#include "netdev.h" +#include "netlink.h" +#include "openflow/openflow-netlink.h" +#endif + +#include "command-line.h" +#include "compiler.h" +#include "dpif.h" +#include "openflow/nicira-ext.h" +#include "openflow/openflow-ext.h" +#include "ofp-print.h" +#include "ofpbuf.h" +#include "openflow/openflow.h" +#include "packets.h" +#include "random.h" +#include "socket-util.h" +#include "timeval.h" +#include "util.h" +#include "vconn-ssl.h" +#include "vconn.h" + +#include "xtoxll.h" +#include "ofpstat.h" +#include "openflow/private-ext.h" + +#include "vlog.h" +#define THIS_MODULE VLM_dpctl + +#define DEFAULT_IDLE_TIMEOUT 60 + +/* Maximum size of action buffer for adding and modify flows */ +#define MAX_ACT_LEN 60 + +#define MOD_PORT_CMD_UP "up" +#define MOD_PORT_CMD_DOWN "down" +#define MOD_PORT_CMD_FLOOD "flood" +#define MOD_PORT_CMD_NOFLOOD "noflood" + + +/* Settings that may be configured by the user. */ +struct settings { + bool strict; /* Use strict matching for flow mod commands */ +}; + +struct command { + const char *name; + int min_args; + int max_args; + void (*handler)(const struct settings *, int argc, char *argv[]); +}; + +static struct command all_commands[]; + +static void usage(void) NO_RETURN; +static void parse_options(int argc, char *argv[], struct settings *); + +int main(int argc, char *argv[]) +{ + struct settings s; + struct command *p; + + set_program_name(argv[0]); + time_init(); + vlog_init(); + parse_options(argc, argv, &s); + signal(SIGPIPE, SIG_IGN); + + argc -= optind; + argv += optind; + if (argc < 1) + ofp_fatal(0, "missing command name; use --help for help"); + + for (p = all_commands; p->name != NULL; p++) { + if (!strcmp(p->name, argv[0])) { + int n_arg = argc - 1; + if (n_arg < p->min_args) + ofp_fatal(0, "'%s' command requires at least %d arguments", + p->name, p->min_args); + else if (n_arg > p->max_args) + ofp_fatal(0, "'%s' command takes at most %d arguments", + p->name, p->max_args); + else { + p->handler(&s, argc, argv); + if (ferror(stdout)) { + ofp_fatal(0, "write to stdout failed"); + } + if (ferror(stderr)) { + ofp_fatal(0, "write to stderr failed"); + } + exit(0); + } + } + } + ofp_fatal(0, "unknown command '%s'; use --help for help", argv[0]); + + return 0; +} + +static void +parse_options(int argc, char *argv[], struct settings *s) +{ + enum { + OPT_STRICT = UCHAR_MAX + 1 + }; + static struct option long_options[] = { + {"timeout", required_argument, 0, 't'}, + {"verbose", optional_argument, 0, 'v'}, + {"strict", no_argument, 0, OPT_STRICT}, + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + VCONN_SSL_LONG_OPTIONS + {0, 0, 0, 0}, + }; + char *short_options = long_options_to_short_options(long_options); + + /* Set defaults that we can figure out before parsing options. */ + s->strict = false; + + for (;;) { + unsigned long int timeout; + int c; + + c = getopt_long(argc, argv, short_options, long_options, NULL); + if (c == -1) { + break; + } + + switch (c) { + case 't': + timeout = strtoul(optarg, NULL, 10); + if (timeout <= 0) { + ofp_fatal(0, "value %s on -t or --timeout is not at least 1", + optarg); + } else { + time_alarm(timeout); + } + break; + + case 'h': + usage(); + + case 'V': + printf("%s %s compiled "__DATE__" "__TIME__"\n", + program_name, VERSION BUILDNR); + exit(EXIT_SUCCESS); + + case 'v': + vlog_set_verbosity(optarg); + break; + + case OPT_STRICT: + s->strict = true; + break; + + VCONN_SSL_OPTION_HANDLERS + + case '?': + exit(EXIT_FAILURE); + + default: + abort(); + } + } + free(short_options); +} + +static void +usage(void) +{ + printf("%s: OpenFlow switch management utility\n" + "usage: %s [OPTIONS] COMMAND [ARG...]\n" +#ifdef HAVE_NETLINK + "\nFor local datapaths only:\n" + " adddp nl:DP_ID add a new local datapath DP_ID\n" + " deldp nl:DP_ID delete local datapath DP_ID\n" + " addif nl:DP_ID IFACE... add each IFACE as a port on DP_ID\n" + " delif nl:DP_ID IFACE... delete each IFACE from DP_ID\n" + " get-idx OF_DEV get datapath index for OF_DEV\n" +#endif + "\nFor local datapaths and remote switches:\n" + " show SWITCH show basic information\n" + " status SWITCH [KEY] report statistics (about KEY)\n" + " show-protostat SWITCH report protocol statistics\n" + " dump-desc SWITCH print switch description\n" + " dump-tables SWITCH print table stats\n" + " mod-port SWITCH IFACE ACT modify port behavior\n" + " dump-ports SWITCH [PORT] print port statistics\n" + " desc SWITCH STRING set switch description\n" + " dump-flows SWITCH print all flow entries\n" + " dump-flows SWITCH FLOW print matching FLOWs\n" + " dump-aggregate SWITCH print aggregate flow statistics\n" + " dump-aggregate SWITCH FLOW print aggregate stats for FLOWs\n" + " add-flow SWITCH FLOW add flow described by FLOW\n" + " add-flows SWITCH FILE add flows from FILE\n" + " mod-flows SWITCH FLOW modify actions of matching FLOWs\n" + " del-flows SWITCH [FLOW] delete matching FLOWs\n" + " monitor SWITCH print packets received from SWITCH\n" + " execute SWITCH CMD [ARG...] execute CMD with ARGS on SWITCH\n" + "Queue Ops: Q: queue-id; P: port-id; BW: perthousand bandwidth\n" + " add-queue SWITCH P Q [BW] add queue (with min bandwidth)\n" + " mod-queue SWITCH P Q BW modify queue min bandwidth\n" + " del-queue SWITCH P Q delete queue\n" + " dump-queue SWITCH [P [Q]] show queue info\n" + "\nFor local datapaths, remote switches, and controllers:\n" + " probe VCONN probe whether VCONN is up\n" + " ping VCONN [N] latency of N-byte echos\n" + " benchmark VCONN N COUNT bandwidth of COUNT N-byte echos\n" + "where each SWITCH is an active OpenFlow connection method.\n", + program_name, program_name); + vconn_usage(true, false, false); + vlog_usage(); + printf("\nOther options:\n" + " --strict use strict match for flow commands\n" + " -t, --timeout=SECS give up after SECS seconds\n" + " -h, --help display this help message\n" + " -V, --version display version information\n"); + exit(EXIT_SUCCESS); +} + +static void run(int retval, const char *message, ...) + PRINTF_FORMAT(2, 3); + +static void run(int retval, const char *message, ...) +{ + if (retval) { + va_list args; + + fprintf(stderr, "%s: ", program_name); + va_start(args, message); + vfprintf(stderr, message, args); + va_end(args); + if (retval == EOF) { + fputs(": unexpected end of file\n", stderr); + } else { + fprintf(stderr, ": %s\n", strerror(retval)); + } + + exit(EXIT_FAILURE); + } +} + +#ifdef HAVE_NETLINK +/* Netlink-only commands. */ + +static int if_up(const char *netdev_name) +{ + struct netdev *netdev; + int retval; + + retval = netdev_open(netdev_name, NETDEV_ETH_TYPE_NONE, &netdev); + if (!retval) { + retval = netdev_turn_flags_on(netdev, NETDEV_UP, true); + netdev_close(netdev); + } + return retval; +} + +static void +do_get_idx(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) +{ + int dp_idx; + + struct dpif dpif; + run(dpif_open(-1, &dpif), "opening management socket"); + dp_idx = dpif_get_idx(argv[1]); + if (dp_idx == -1) { + dpif_close(&dpif); + ofp_fatal(0, "unknown OpenFlow device: %s", argv[1]); + } + printf("%d\n", dp_idx); + dpif_close(&dpif); +} + +static int +get_dp_idx(const char *name) +{ + if (strncmp(name, "nl:", 3) + || strlen(name) < 4 + || name[strspn(name + 3, "0123456789") + 3]) { + ofp_fatal(0, "%s: argument is not of the form \"nl:DP_ID\"", name); + } + return atoi(name + 3); +} + +static void +do_add_dp(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) +{ + struct dpif dpif; + run(dpif_open(-1, &dpif), "opening management socket"); + run(dpif_add_dp(&dpif, get_dp_idx(argv[1]), NULL), "add_dp"); + dpif_close(&dpif); +} + +static void +do_del_dp(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) +{ + struct dpif dpif; + run(dpif_open(-1, &dpif), "opening management socket"); + run(dpif_del_dp(&dpif, get_dp_idx(argv[1]), NULL), "del_dp"); + dpif_close(&dpif); +} + +static void add_del_ports(int argc UNUSED, char *argv[], + int (*function)(struct dpif *, int dp_idx, + const char *netdev), + const char *operation, const char *preposition) +{ + bool failure = false; + struct dpif dpif; + int dp_idx; + int i; + + run(dpif_open(-1, &dpif), "opening management socket"); + dp_idx = get_dp_idx(argv[1]); + for (i = 2; i < argc; i++) { + int retval = function(&dpif, dp_idx, argv[i]); + if (retval) { + ofp_error(retval, "failed to %s %s %s %s", + operation, argv[i], preposition, argv[1]); + failure = true; + } + } + dpif_close(&dpif); + if (failure) { + exit(EXIT_FAILURE); + } +} + +static int ifup_and_add_port(struct dpif *dpif, int dp_idx, const char *netdev) +{ + int retval = if_up(netdev); + return retval ? retval : dpif_add_port(dpif, dp_idx, netdev); +} + +static void do_add_port(const struct settings *s UNUSED, int argc UNUSED, + char *argv[]) +{ + add_del_ports(argc, argv, ifup_and_add_port, "add", "to"); +} + +static void do_del_port(const struct settings *s UNUSED, int argc UNUSED, + char *argv[]) +{ + add_del_ports(argc, argv, dpif_del_port, "remove", "from"); +} +#endif /* HAVE_NETLINK */ + +/* Generic commands. */ + +static void +open_vconn(const char *name, struct vconn **vconnp) +{ + run(vconn_open_block(name, OFP_VERSION, vconnp), "connecting to %s", name); +} + +static void * +alloc_stats_request(size_t body_len, uint16_t type, struct ofpbuf **bufferp) +{ + struct ofp_stats_request *rq; + rq = make_openflow((offsetof(struct ofp_stats_request, body) + + body_len), OFPT_STATS_REQUEST, bufferp); + rq->type = htons(type); + rq->flags = htons(0); + return rq->body; +} + +static void +send_openflow_buffer(struct vconn *vconn, struct ofpbuf *buffer) +{ + update_openflow_length(buffer); + run(vconn_send_block(vconn, buffer), "failed to send packet to switch"); +} + +static void +dump_transaction(const char *vconn_name, struct ofpbuf *request) +{ + struct vconn *vconn; + struct ofpbuf *reply; + + update_openflow_length(request); + open_vconn(vconn_name, &vconn); + run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name); + ofp_print(stdout, reply->data, reply->size, 1); + vconn_close(vconn); +} + +static void +dump_trivial_transaction(const char *vconn_name, uint8_t request_type) +{ + struct ofpbuf *request; + make_openflow(sizeof(struct ofp_header), request_type, &request); + dump_transaction(vconn_name, request); +} + +static void +dump_stats_transaction(const char *vconn_name, struct ofpbuf *request) +{ + uint32_t send_xid = ((struct ofp_header *) request->data)->xid; + struct vconn *vconn; + bool done = false; + + open_vconn(vconn_name, &vconn); + send_openflow_buffer(vconn, request); + while (!done) { + uint32_t recv_xid; + struct ofpbuf *reply; + + run(vconn_recv_block(vconn, &reply), "OpenFlow packet receive failed"); + + recv_xid = ((struct ofp_header *) reply->data)->xid; + if (send_xid == recv_xid) { + struct ofp_stats_reply *osr; + + ofp_print(stdout, reply->data, reply->size, 1); + + osr = ofpbuf_at(reply, 0, sizeof *osr); + done = !osr || !(ntohs(osr->flags) & OFPSF_REPLY_MORE); + } else { + VLOG_DBG("received reply with xid %08"PRIx32" " + "!= expected %08"PRIx32, recv_xid, send_xid); + } + ofpbuf_delete(reply); + } + vconn_close(vconn); +} + +static void +dump_trivial_stats_transaction(const char *vconn_name, uint8_t stats_type) +{ + struct ofpbuf *request; + alloc_stats_request(0, stats_type, &request); + dump_stats_transaction(vconn_name, request); +} + +/* Get the pointer to struct member based on member offset */ +#define S_PTR(_ptr, _type, _member) \ + ((void *)(((char *)(_ptr)) + offsetof(_type, _member))) + +static void +dump_queue_stats_transaction(const char *vconn_name, uint8_t stats_type, + uint16_t port, uint32_t q_id) +{ + struct ofpbuf *request; + struct ofp_queue_stats_request *q_req; + struct ofp_stats_request *stats_req; + + alloc_stats_request(sizeof(struct ofp_queue_stats_request), + stats_type, &request); + stats_req = request->data; + q_req = S_PTR(stats_req, struct ofp_stats_request, body); + + q_req->port_no = htons(port); + q_req->queue_id = htonl(q_id); + dump_stats_transaction(vconn_name, request); +} + +static void +do_show(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) +{ + dump_trivial_transaction(argv[1], OFPT_FEATURES_REQUEST); + dump_trivial_transaction(argv[1], OFPT_GET_CONFIG_REQUEST); +} + +static void +do_status(const struct settings *s UNUSED, int argc, char *argv[]) +{ + struct nicira_header *request, *reply; + struct vconn *vconn; + struct ofpbuf *b; + + request = make_openflow(sizeof *request, OFPT_VENDOR, &b); + request->vendor = htonl(NX_VENDOR_ID); + request->subtype = htonl(NXT_STATUS_REQUEST); + if (argc > 2) { + ofpbuf_put(b, argv[2], strlen(argv[2])); + } + open_vconn(argv[1], &vconn); + run(vconn_transact(vconn, b, &b), "talking to %s", argv[1]); + vconn_close(vconn); + + if (b->size < sizeof *reply) { + ofp_fatal(0, "short reply (%zu bytes)", b->size); + } + reply = b->data; + if (reply->header.type != OFPT_VENDOR + || reply->vendor != ntohl(NX_VENDOR_ID) + || reply->subtype != ntohl(NXT_STATUS_REPLY)) { + ofp_print(stderr, b->data, b->size, 2); + ofp_fatal(0, "bad reply"); + } + + fwrite(reply + 1, b->size, 1, stdout); +} + +static void +print_protocol_stat(struct ofpstat *ofps_rcvd, struct ofpstat *ofps_sent) +{ + int i; + struct ofpstat *ifps = NULL; +#define PREFIX_STR " " +#define PREFIX_RCVD "Rcvd: " +#define PREFIX_SENT "Sent: " + + fprintf(stdout, + "OpenFlow protocol version 0x%x statisical information\n", + OFP_VERSION); + fprintf(stdout, "\n"); + + fprintf(stdout, "Protocol message:\n"); + for (i = 0; i < 2; ++i) { + ifps = i == 0 ? ofps_rcvd : ofps_sent; + fprintf(stdout, + "%s" + "%"PRIu64" total msgs, %"PRIu64" unknown msgs\n", + i == 0 ? PREFIX_RCVD : PREFIX_SENT, + ntohll(ifps->ofps_total), + ntohll(ifps->ofps_unknown)); + fprintf(stdout, + PREFIX_STR + "%"PRIu64" hello, %"PRIu64" errors, " + "%"PRIu64" echo, %"PRIu64" echo reply, " + "%"PRIu64" vendor\n", + ntohll(ifps->ofps_hello), + ntohll(ifps->ofps_error), + ntohll(ifps->ofps_echo_request), + ntohll(ifps->ofps_echo_reply), + ntohll(ifps->ofps_vendor)); + fprintf(stdout, + PREFIX_STR + "%"PRIu64" feats, %"PRIu64" feats reply\n", + ntohll(ifps->ofps_feats_request), + ntohll(ifps->ofps_feats_reply)); + fprintf(stdout, + PREFIX_STR + "%"PRIu64" get config, %"PRIu64" get config reply, " + "%"PRIu64" set config\n", + ntohll(ifps->ofps_get_config_request), + ntohll(ifps->ofps_get_config_reply), + ntohll(ifps->ofps_set_config)); + fprintf(stdout, + PREFIX_STR + "%"PRIu64" packet in, %"PRIu64" flow removed, " + "%"PRIu64" port status\n", + ntohll(ifps->ofps_packet_in), + ntohll(ifps->ofps_flow_removed), + ntohll(ifps->ofps_port_status)); + fprintf(stdout, + PREFIX_STR + "%"PRIu64" packet out, %"PRIu64" flow mod, %"PRIu64" port mod\n", + ntohll(ifps->ofps_packet_out), + ntohll(ifps->ofps_flow_mod), + ntohll(ifps->ofps_port_mod)); + fprintf(stdout, + PREFIX_STR + "%"PRIu64" stats, %"PRIu64" stats reply, " + "%"PRIu64" barrier, %"PRIu64" barrier reply\n", + ntohll(ifps->ofps_stats_request), + ntohll(ifps->ofps_stats_reply), + ntohll(ifps->ofps_barrier_request), + ntohll(ifps->ofps_barrier_reply)); + } + fprintf(stdout, "\n"); + + fprintf(stdout, "Flow manipulation:\n"); + for (i = 0; i < 2; ++i) { + ifps = i == 0 ? ofps_rcvd : ofps_sent; + fprintf(stdout, + "%s" + "%"PRIu64" add, %"PRIu64" modify, %"PRIu64" modify strict\n", + i == 0 ? PREFIX_RCVD : PREFIX_SENT, + ntohll(ifps->ofps_flow_mod_ops.add), + ntohll(ifps->ofps_flow_mod_ops.modify), + ntohll(ifps->ofps_flow_mod_ops.modify_strict)); + fprintf(stdout, + PREFIX_STR + "%"PRIu64" delete, %"PRIu64" delete strict, %"PRIu64" unknown cmd\n", + ntohll(ifps->ofps_flow_mod_ops.delete), + ntohll(ifps->ofps_flow_mod_ops.delete_strict), + ntohll(ifps->ofps_flow_mod_ops.unknown)); + } + fprintf(stdout, "\n"); + + fprintf(stdout, "Error notification:\n"); + for (i = 0; i < 2; ++i) { + ifps = i == 0 ? ofps_rcvd : ofps_sent; + fprintf(stdout, + "%s" + "%"PRIu64" hello fail: %"PRIu64" incompat, %"PRIu64" eperm\n", + i == 0 ? PREFIX_RCVD : PREFIX_SENT, + ntohll(ifps->ofps_error_type.hello_fail), + ntohll(ifps->ofps_error_code.hf_incompat), + ntohll(ifps->ofps_error_code.hf_eperm)); + fprintf(stdout, + PREFIX_STR + "%"PRIu64" bad request: %"PRIu64" version, %"PRIu64" type, " + "%"PRIu64" stat, %"PRIu64" vendor\n" + PREFIX_STR + " %"PRIu64" eperm\n", + ntohll(ifps->ofps_error_type.bad_request), + ntohll(ifps->ofps_error_code.br_bad_version), + ntohll(ifps->ofps_error_code.br_bad_type), + ntohll(ifps->ofps_error_code.br_bad_stat), + ntohll(ifps->ofps_error_code.br_bad_vendor), + ntohll(ifps->ofps_error_code.br_eperm)); + fprintf(stdout, + PREFIX_STR + "%"PRIu64" bad action: %"PRIu64" type, %"PRIu64" len, " + "%"PRIu64" vendor, %"PRIu64" vendor type\n" + PREFIX_STR + " %"PRIu64" out port, %"PRIu64" argument, %"PRIu64" eperm\n", + ntohll(ifps->ofps_error_type.bad_action), + ntohll(ifps->ofps_error_code.ba_bad_type), + ntohll(ifps->ofps_error_code.ba_bad_len), + ntohll(ifps->ofps_error_code.ba_bad_vendor), + ntohll(ifps->ofps_error_code.ba_bad_vendor_type), + ntohll(ifps->ofps_error_code.ba_bad_out_port), + ntohll(ifps->ofps_error_code.ba_bad_argument), + ntohll(ifps->ofps_error_code.ba_eperm)); + fprintf(stdout, + PREFIX_STR + "%"PRIu64" flow mod fail: %"PRIu64" all tables full, " + "%"PRIu64" overlap, %"PRIu64" eperm, %"PRIu64" emerg\n", + ntohll(ifps->ofps_error_type.flow_mod_fail), + ntohll(ifps->ofps_error_code.fmf_all_tables_full), + ntohll(ifps->ofps_error_code.fmf_overlap), + ntohll(ifps->ofps_error_code.fmf_eperm), + ntohll(ifps->ofps_error_code.fmf_emerg)); + fprintf(stdout, + PREFIX_STR + "%"PRIu64" unknown type, %"PRIu64" unknown code\n", + ntohll(ifps->ofps_error_type.unknown), + ntohll(ifps->ofps_error_code.unknown)); + } + fprintf(stdout, "\n"); +} + +static void +do_protostat(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) +{ + struct ofpbuf *buf; + struct private_vxhdr *vxhdr; + struct private_vxopt *vxopt; + struct vconn *vconn; + struct ofpstat* ofps; + + vxhdr = make_openflow(sizeof(*vxhdr) + sizeof(*vxopt), OFPT_VENDOR, &buf); + vxopt = (struct private_vxopt *)(vxhdr + 1); + vxhdr->ofp_vxid = htonl(PRIVATE_VENDOR_ID); + vxopt->pvo_type = htons(PRIVATEOPT_PROTOCOL_STATS_REQUEST); + vxopt->pvo_len = 0; + + open_vconn(argv[1], &vconn); + run(vconn_transact(vconn, buf, &buf), "talking to %s", argv[1]); + vconn_close(vconn); + if (buf->size < sizeof(*vxhdr)) { + ofp_fatal(0, "short reply (%zu bytes)", buf->size); + } + + vxhdr = buf->data; + if (vxhdr->ofp_hdr.type != OFPT_VENDOR + || ntohl(vxhdr->ofp_vxid) != PRIVATE_VENDOR_ID) { + ofp_print(stderr, buf->data, buf->size, 2); + ofp_fatal(0, "bad reply"); + } + vxopt = (struct private_vxopt *)(vxhdr + 1); + if (ntohs(vxopt->pvo_type) != PRIVATEOPT_PROTOCOL_STATS_REPLY + || ntohs(vxopt->pvo_len) != (sizeof(*ofps) * 2)) { + ofp_print(stderr, buf->data, buf->size, 2); + ofp_fatal(0, "bad reply"); + } + + ofps = (struct ofpstat *)(vxopt + 1); + print_protocol_stat(ofps, ofps + 1); +} + +static void +do_dump_desc(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) +{ + dump_trivial_stats_transaction(argv[1], OFPST_DESC); +} + +static void +do_dump_tables(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) +{ + dump_trivial_stats_transaction(argv[1], OFPST_TABLE); +} + +static uint32_t +str_to_u32(const char *str) +{ + char *tail; + uint32_t value; + + errno = 0; + value = strtoul(str, &tail, 0); + if (errno == EINVAL || errno == ERANGE || *tail) { + ofp_fatal(0, "invalid numeric format %s", str); + } + return value; +} + +static void +str_to_mac(const char *str, uint8_t mac[6]) +{ + if (sscanf(str, "%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8, + &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]) != 6) { + ofp_fatal(0, "invalid mac address %s", str); + } +} + +static uint32_t +str_to_ip(const char *str_, uint32_t *ip) +{ + char *str = xstrdup(str_); + char *save_ptr = NULL; + const char *name, *netmask; + struct in_addr in_addr; + int n_wild, retval; + + name = strtok_r(str, "//", &save_ptr); + retval = name ? lookup_ip(name, &in_addr) : EINVAL; + if (retval) { + ofp_fatal(0, "%s: could not convert to IP address", str); + } + *ip = in_addr.s_addr; + + netmask = strtok_r(NULL, "//", &save_ptr); + if (netmask) { + uint8_t o[4]; + if (sscanf(netmask, "%"SCNu8".%"SCNu8".%"SCNu8".%"SCNu8, + &o[0], &o[1], &o[2], &o[3]) == 4) { + uint32_t nm = (o[0] << 24) | (o[1] << 16) | (o[2] << 8) | o[3]; + int i; + + /* Find first 1-bit. */ + for (i = 0; i < 32; i++) { + if (nm & (1u << i)) { + break; + } + } + n_wild = i; + + /* Verify that the rest of the bits are 1-bits. */ + for (; i < 32; i++) { + if (!(nm & (1u << i))) { + ofp_fatal(0, "%s: %s is not a valid netmask", + str, netmask); + } + } + } else { + int prefix = atoi(netmask); + if (prefix <= 0 || prefix > 32) { + ofp_fatal(0, "%s: network prefix bits not between 1 and 32", + str); + } + n_wild = 32 - prefix; + } + } else { + n_wild = 0; + } + + free(str); + return n_wild; +} + +static void * +put_action(struct ofpbuf *b, size_t size, uint16_t type) +{ + struct ofp_action_header *ah = ofpbuf_put_zeros(b, size); + ah->type = htons(type); + ah->len = htons(size); + return ah; +} + +static struct ofp_action_output * +put_output_action(struct ofpbuf *b, uint16_t port) +{ + struct ofp_action_output *oao = put_action(b, sizeof *oao, OFPAT_OUTPUT); + oao->port = htons(port); + return oao; +} + +static struct ofp_action_enqueue * +put_enqueue_action(struct ofpbuf *b, uint16_t port, uint32_t queue) +{ + struct ofp_action_enqueue *oao; + + oao = put_action(b, sizeof *oao, OFPAT_ENQUEUE); + oao->len = htons(sizeof(*oao)); + oao->port = htons(port); + oao->queue_id = htonl(queue); + return oao; +} + +static void +str_to_action(char *str, struct ofpbuf *b) +{ + char *act, *arg, *arg2; + char *saveptr = NULL; + + for (act = strtok_r(str, ", \t\r\n", &saveptr); act; + act = strtok_r(NULL, ", \t\r\n", &saveptr)) + { + /* Arguments are separated by colons */ + arg = strchr(act, ':'); + if (arg) { + *arg = '\0'; + arg++; + } + + if (!strcasecmp(act, "mod_nw_tos")) { + struct ofp_action_nw_tos *va; + va = put_action(b, sizeof *va, OFPAT_SET_NW_TOS); + va->nw_tos = str_to_u32(arg); + } else if (!strcasecmp(act, "mod_vlan_vid")) { + struct ofp_action_vlan_vid *va; + va = put_action(b, sizeof *va, OFPAT_SET_VLAN_VID); + va->vlan_vid = htons(str_to_u32(arg)); + } else if (!strcasecmp(act, "mod_vlan_pcp")) { + struct ofp_action_vlan_pcp *va; + va = put_action(b, sizeof *va, OFPAT_SET_VLAN_PCP); + va->vlan_pcp = str_to_u32(arg); + } else if (!strcasecmp(act, "mod_dl_dst")) { + struct ofp_action_dl_addr *va; + va = put_action(b, sizeof *va, OFPAT_SET_DL_DST); + str_to_mac(arg, va->dl_addr); + } else if (!strcasecmp(act, "mod_dl_src")) { + struct ofp_action_dl_addr *va; + va = put_action(b, sizeof *va, OFPAT_SET_DL_SRC); + str_to_mac(arg, va->dl_addr); + } else if (!strcasecmp(act, "strip_vlan")) { + struct ofp_action_header *ah; + ah = put_action(b, sizeof *ah, OFPAT_STRIP_VLAN); + ah->type = htons(OFPAT_STRIP_VLAN); + } else if (!strcasecmp(act, "enqueue")) { + arg2 = strchr(arg, ':'); + if (arg2) { + *arg2 = '\0'; + arg2++; + } + put_enqueue_action(b, str_to_u32(arg), str_to_u32(arg2)); + } else if (!strcasecmp(act, "output")) { + put_output_action(b, str_to_u32(arg)); + } else if (!strcasecmp(act, "TABLE")) { + put_output_action(b, OFPP_TABLE); + } else if (!strcasecmp(act, "NORMAL")) { + put_output_action(b, OFPP_NORMAL); + } else if (!strcasecmp(act, "FLOOD")) { + put_output_action(b, OFPP_FLOOD); + } else if (!strcasecmp(act, "ALL")) { + put_output_action(b, OFPP_ALL); + } else if (!strcasecmp(act, "CONTROLLER")) { + struct ofp_action_output *oao; + oao = put_output_action(b, OFPP_CONTROLLER); + + /* Unless a numeric argument is specified, we send the whole + * packet to the controller. */ + if (arg && (strspn(act, "0123456789") == strlen(act))) { + oao->max_len = htons(str_to_u32(arg)); + } + } else if (!strcasecmp(act, "LOCAL")) { + put_output_action(b, OFPP_LOCAL); + } else if (strspn(act, "0123456789") == strlen(act)) { + put_output_action(b, str_to_u32(act)); + } else { + ofp_fatal(0, "Unknown action: %s", act); + } + } +} + +struct protocol { + const char *name; + uint16_t dl_type; + uint8_t nw_proto; +}; + +static bool +parse_protocol(const char *name, const struct protocol **p_out) +{ + static const struct protocol protocols[] = { + { "ip", ETH_TYPE_IP, 0 }, + { "arp", ETH_TYPE_ARP, 0 }, + { "icmp", ETH_TYPE_IP, IP_TYPE_ICMP }, + { "tcp", ETH_TYPE_IP, IP_TYPE_TCP }, + { "udp", ETH_TYPE_IP, IP_TYPE_UDP }, + }; + const struct protocol *p; + + for (p = protocols; p < &protocols[ARRAY_SIZE(protocols)]; p++) { + if (!strcmp(p->name, name)) { + *p_out = p; + return true; + } + } + *p_out = NULL; + return false; +} + +struct field { + const char *name; + uint32_t wildcard; + enum { F_U8, F_U16, F_MAC, F_IP } type; + size_t offset, shift; +}; + +static bool +parse_field(const char *name, const struct field **f_out) +{ +#define F_OFS(MEMBER) offsetof(struct ofp_match, MEMBER) + static const struct field fields[] = { + { "in_port", OFPFW_IN_PORT, F_U16, F_OFS(in_port), 0 }, + { "dl_vlan", OFPFW_DL_VLAN, F_U16, F_OFS(dl_vlan), 0 }, + { "dl_vlan_pcp", OFPFW_DL_VLAN_PCP, F_U8, F_OFS(dl_vlan_pcp), 0 }, + { "dl_src", OFPFW_DL_SRC, F_MAC, F_OFS(dl_src), 0 }, + { "dl_dst", OFPFW_DL_DST, F_MAC, F_OFS(dl_dst), 0 }, + { "dl_type", OFPFW_DL_TYPE, F_U16, F_OFS(dl_type), 0 }, + { "nw_tos", OFPFW_NW_TOS, F_U8, F_OFS(nw_tos), 0 }, + { "nw_proto", OFPFW_NW_PROTO, F_U8, F_OFS(nw_proto), 0 }, + { "nw_src", OFPFW_NW_SRC_MASK, F_IP, + F_OFS(nw_src), OFPFW_NW_SRC_SHIFT }, + { "nw_dst", OFPFW_NW_DST_MASK, F_IP, + F_OFS(nw_dst), OFPFW_NW_DST_SHIFT }, + { "tp_src", OFPFW_TP_SRC, F_U16, F_OFS(tp_src), 0 }, + { "tp_dst", OFPFW_TP_DST, F_U16, F_OFS(tp_dst), 0 }, + { "icmp_type", OFPFW_ICMP_TYPE, F_U16, F_OFS(icmp_type), 0 }, + { "icmp_code", OFPFW_ICMP_CODE, F_U16, F_OFS(icmp_code), 0 } + }; + const struct field *f; + + for (f = fields; f < &fields[ARRAY_SIZE(fields)]; f++) { + if (!strcmp(f->name, name)) { + *f_out = f; + return true; + } + } + *f_out = NULL; + return false; +} + +static void +str_to_flow(char *string, struct ofp_match *match, struct ofpbuf *actions, + uint8_t *table_idx, uint16_t *out_port, uint16_t *priority, + uint16_t *idle_timeout, uint16_t *hard_timeout, + uint64_t *cookie) +{ + char *save_ptr = NULL; + char *name; + uint32_t wildcards; + + if (table_idx) { + *table_idx = 0xff; + } + if (out_port) { + *out_port = OFPP_NONE; + } + if (priority) { + *priority = OFP_DEFAULT_PRIORITY; + } + if (idle_timeout) { + *idle_timeout = DEFAULT_IDLE_TIMEOUT; + } + if (hard_timeout) { + *hard_timeout = OFP_FLOW_PERMANENT; + } + if (cookie) { + *cookie = 0; + } + if (actions) { + char *act_str = strstr(string, "actions"); + if (!act_str) { + ofp_fatal(0, "must specify an action"); + } + *(act_str-1) = '\0'; + + act_str = strchr(act_str, '='); + if (!act_str) { + ofp_fatal(0, "must specify an action"); + } + + act_str++; + + str_to_action(act_str, actions); + } + memset(match, 0, sizeof *match); + wildcards = OFPFW_ALL; + for (name = strtok_r(string, "=, \t\r\n", &save_ptr); name; + name = strtok_r(NULL, "=, \t\r\n", &save_ptr)) { + const struct protocol *p; + + if (parse_protocol(name, &p)) { + wildcards &= ~OFPFW_DL_TYPE; + match->dl_type = htons(p->dl_type); + if (p->nw_proto) { + wildcards &= ~OFPFW_NW_PROTO; + match->nw_proto = p->nw_proto; + } + } else { + const struct field *f; + char *value; + + value = strtok_r(NULL, ", \t\r\n", &save_ptr); + if (!value) { + ofp_fatal(0, "field %s missing value", name); + } + + if (table_idx && !strcmp(name, "table")) { + *table_idx = atoi(value); + } else if (out_port && !strcmp(name, "out_port")) { + *out_port = atoi(value); + } else if (priority && !strcmp(name, "priority")) { + *priority = atoi(value); + } else if (idle_timeout && !strcmp(name, "idle_timeout")) { + *idle_timeout = atoi(value); + } else if (hard_timeout && !strcmp(name, "hard_timeout")) { + *hard_timeout = atoi(value); + } else if (cookie && !strcmp(name, "cookie")) { + *cookie = atoi(value); + } else if (parse_field(name, &f)) { + void *data = (char *) match + f->offset; + if (!strcmp(value, "*") || !strcmp(value, "ANY")) { + wildcards |= f->wildcard; + } else { + wildcards &= ~f->wildcard; + if (f->type == F_U8) { + *(uint8_t *) data = str_to_u32(value); + } else if (f->type == F_U16) { + *(uint16_t *) data = htons(str_to_u32(value)); + } else if (f->type == F_MAC) { + str_to_mac(value, data); + } else if (f->type == F_IP) { + wildcards |= str_to_ip(value, data) << f->shift; + } else { + NOT_REACHED(); + } + } + } else { + ofp_fatal(0, "unknown keyword %s", name); + } + } + } + match->wildcards = htonl(wildcards); +} + +static void +do_desc(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) +{ + struct vconn * vconn; + struct ofpbuf * msg; + struct openflow_ext_set_dp_desc * desc; + + msg = ofpbuf_new(sizeof(*desc)); + ofpbuf_put_uninit(msg, sizeof(*desc)); + desc = ofpbuf_at_assert(msg, 0, sizeof(*desc)); + desc->header.header.version = OFP_VERSION; + desc->header.header.type = OFPT_VENDOR; + desc->header.header.length = htons(sizeof(*desc)); + desc->header.vendor = htonl(OPENFLOW_VENDOR_ID); + desc->header.subtype = htonl(OFP_EXT_SET_DESC); + strncpy(desc->dp_desc, argv[2], DESC_STR_LEN); + + open_vconn(argv[1], &vconn); + send_openflow_buffer(vconn, msg); + vconn_close(vconn); +} + +static void +do_dump_flows(const struct settings *s UNUSED, int argc, char *argv[]) +{ + struct ofp_flow_stats_request *req; + uint16_t out_port; + struct ofpbuf *request; + + req = alloc_stats_request(sizeof *req, OFPST_FLOW, &request); + str_to_flow(argc > 2 ? argv[2] : "", &req->match, NULL, + &req->table_id, &out_port, NULL, NULL, NULL, NULL); + memset(&req->pad, 0, sizeof req->pad); + req->out_port = htons(out_port); + + dump_stats_transaction(argv[1], request); +} + +static void +do_dump_aggregate(const struct settings *s UNUSED, int argc, char *argv[]) +{ + struct ofp_aggregate_stats_request *req; + struct ofpbuf *request; + uint16_t out_port; + + req = alloc_stats_request(sizeof *req, OFPST_AGGREGATE, &request); + str_to_flow(argc > 2 ? argv[2] : "", &req->match, NULL, + &req->table_id, &out_port, NULL, NULL, NULL, NULL); + memset(&req->pad, 0, sizeof req->pad); + req->out_port = htons(out_port); + + dump_stats_transaction(argv[1], request); +} + +#define EMERG_TABLE_ID 0xfe + +static void +do_add_flow(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) +{ + struct vconn *vconn; + struct ofpbuf *buffer; + struct ofp_flow_mod *ofm; + uint16_t priority, idle_timeout, hard_timeout; + uint64_t cookie; + uint8_t table_id; + struct ofp_match match; + + /* Parse and send. str_to_flow() will expand and reallocate the data in + * 'buffer', so we can't keep pointers to across the str_to_flow() call. */ + make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer); + str_to_flow(argv[2], &match, buffer, + &table_id, NULL, &priority, &idle_timeout, &hard_timeout, + &cookie); + ofm = buffer->data; + ofm->match = match; + ofm->command = htons(OFPFC_ADD); + ofm->cookie = htonll(cookie); + ofm->idle_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(idle_timeout); + ofm->hard_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(hard_timeout); + ofm->buffer_id = htonl(UINT32_MAX); + ofm->priority = htons(priority); + ofm->flags = htons(OFPFF_SEND_FLOW_REM); + if (table_id == EMERG_TABLE_ID) + ofm->flags |= htons(OFPFF_EMERG); + + open_vconn(argv[1], &vconn); + send_openflow_buffer(vconn, buffer); + vconn_close(vconn); +} + +static void +do_add_flows(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) +{ + struct vconn *vconn; + FILE *file; + char line[1024]; + + file = fopen(argv[2], "r"); + if (file == NULL) { + ofp_fatal(errno, "%s: open", argv[2]); + } + + open_vconn(argv[1], &vconn); + while (fgets(line, sizeof line, file)) { + struct ofpbuf *buffer; + struct ofp_flow_mod *ofm; + uint16_t priority, idle_timeout, hard_timeout; + uint64_t cookie; + uint8_t table_id; + struct ofp_match match; + + char *comment; + + /* Delete comments. */ + comment = strchr(line, '#'); + if (comment) { + *comment = '\0'; + } + + /* Drop empty lines. */ + if (line[strspn(line, " \t\n")] == '\0') { + continue; + } + + /* Parse and send. str_to_flow() will expand and reallocate the data + * in 'buffer', so we can't keep pointers to across the str_to_flow() + * call. */ + ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer); + str_to_flow(line, &match, buffer, + &table_id, NULL, &priority, &idle_timeout, &hard_timeout, + &cookie); + ofm = buffer->data; + ofm->match = match; + ofm->command = htons(OFPFC_ADD); + ofm->cookie = htonll(cookie); + ofm->idle_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(idle_timeout); + ofm->hard_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(hard_timeout); + ofm->buffer_id = htonl(UINT32_MAX); + ofm->priority = htons(priority); + ofm->flags = htons(OFPFF_SEND_FLOW_REM); + if (table_id == EMERG_TABLE_ID) + ofm->flags |= htons(OFPFF_EMERG); + + send_openflow_buffer(vconn, buffer); + } + vconn_close(vconn); + fclose(file); +} + +static void +do_mod_flows(const struct settings *s, int argc UNUSED, char *argv[]) +{ + uint16_t priority, idle_timeout, hard_timeout; + uint64_t cookie; + uint8_t table_id; + struct vconn *vconn; + struct ofpbuf *buffer; + struct ofp_flow_mod *ofm; + + /* Parse and send. */ + ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer); + str_to_flow(argv[2], &ofm->match, buffer, + &table_id, NULL, &priority, &idle_timeout, &hard_timeout, + &cookie); + if (s->strict) { + ofm->command = htons(OFPFC_MODIFY_STRICT); + } else { + ofm->command = htons(OFPFC_MODIFY); + } + ofm->cookie = htonll(cookie); + ofm->idle_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(idle_timeout); + ofm->hard_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(hard_timeout); + ofm->buffer_id = htonl(UINT32_MAX); + if (table_id == EMERG_TABLE_ID) + ofm->flags = htons(OFPFF_EMERG); + ofm->priority = htons(priority); + + open_vconn(argv[1], &vconn); + send_openflow_buffer(vconn, buffer); + vconn_close(vconn); +} + +static void do_del_flows(const struct settings *s, int argc, char *argv[]) +{ + struct vconn *vconn; + uint16_t priority; + uint16_t out_port; + uint8_t table_id; + struct ofpbuf *buffer; + struct ofp_flow_mod *ofm; + + /* Parse and send. */ + ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer); + str_to_flow(argc > 2 ? argv[2] : "", &ofm->match, NULL, + &table_id, &out_port, &priority, NULL, NULL, NULL); + if (s->strict) { + ofm->command = htons(OFPFC_DELETE_STRICT); + } else { + ofm->command = htons(OFPFC_DELETE); + } + ofm->idle_timeout = htons(0); + ofm->hard_timeout = htons(0); + ofm->buffer_id = htonl(UINT32_MAX); + if (table_id == EMERG_TABLE_ID) + ofm->flags = htons(OFPFF_EMERG); + ofm->out_port = htons(out_port); + ofm->priority = htons(priority); + + open_vconn(argv[1], &vconn); + send_openflow_buffer(vconn, buffer); + vconn_close(vconn); +} + +static void +do_monitor(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) +{ + struct vconn *vconn; + const char *name; + + /* If the user specified, e.g., "nl:0", append ":1" to it to ensure that + * the connection will subscribe to listen for asynchronous messages, such + * as packet-in messages. */ + if (!strncmp(argv[1], "nl:", 3) && strrchr(argv[1], ':') == &argv[1][2]) { + name = xasprintf("%s:1", argv[1]); + } else { + name = argv[1]; + } + open_vconn(argv[1], &vconn); + for (;;) { + struct ofpbuf *b; + run(vconn_recv_block(vconn, &b), "vconn_recv"); + ofp_print(stderr, b->data, b->size, 2); + ofpbuf_delete(b); + } +} + +static void +str_to_port(char *string, uint16_t *start_port) +{ + char *save_ptr = NULL; + char *value = NULL; + + if (start_port) { + *start_port = OFPP_NONE; + } + + value = strtok_r(string, ", \t\r\n", &save_ptr); + if (value && start_port) { + *start_port = atoi(value); + } +} + +static void +do_dump_ports(const struct settings *s UNUSED, int argc, char *argv[]) +{ + struct ofp_port_stats_request *psr; + struct ofpbuf *buf; + + psr = alloc_stats_request(sizeof(*psr), OFPST_PORT, &buf); + str_to_port(argc > 2 ? argv[2] : "", &psr->port_no); + psr->port_no = htons(psr->port_no); + memset(psr->pad, 0, sizeof(psr->pad)); + dump_stats_transaction(argv[1], buf); +} + +static void +do_probe(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) +{ + struct ofpbuf *request; + struct vconn *vconn; + struct ofpbuf *reply; + + make_openflow(sizeof(struct ofp_header), OFPT_ECHO_REQUEST, &request); + open_vconn(argv[1], &vconn); + run(vconn_transact(vconn, request, &reply), "talking to %s", argv[1]); + if (reply->size != sizeof(struct ofp_header)) { + ofp_fatal(0, "reply does not match request"); + } + ofpbuf_delete(reply); + vconn_close(vconn); +} + +static void +do_mod_port(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) +{ + struct ofpbuf *request, *reply; + struct ofp_switch_features *osf; + struct ofp_port_mod *opm; + struct vconn *vconn; + char *endptr; + int n_ports; + int port_idx; + int port_no; + + + /* Check if the argument is a port index. Otherwise, treat it as + * the port name. */ + port_no = strtol(argv[2], &endptr, 10); + if (port_no == 0 && endptr == argv[2]) { + port_no = -1; + } + + /* Send a "Features Request" to get the information we need in order + * to modify the port. */ + make_openflow(sizeof(struct ofp_header), OFPT_FEATURES_REQUEST, &request); + open_vconn(argv[1], &vconn); + run(vconn_transact(vconn, request, &reply), "talking to %s", argv[1]); + + osf = reply->data; + n_ports = (reply->size - sizeof *osf) / sizeof *osf->ports; + + for (port_idx = 0; port_idx < n_ports; port_idx++) { + if (port_no != -1) { + /* Check argument as a port index */ + if (osf->ports[port_idx].port_no == htons(port_no)) { + break; + } + } else { + /* Check argument as an interface name */ + if (!strncmp((char *)osf->ports[port_idx].name, argv[2], + sizeof osf->ports[0].name)) { + break; + } + + } + } + if (port_idx == n_ports) { + ofp_fatal(0, "couldn't find monitored port: %s", argv[2]); + } + + opm = make_openflow(sizeof(struct ofp_port_mod), OFPT_PORT_MOD, &request); + opm->port_no = osf->ports[port_idx].port_no; + memcpy(opm->hw_addr, osf->ports[port_idx].hw_addr, sizeof opm->hw_addr); + opm->config = htonl(0); + opm->mask = htonl(0); + opm->advertise = htonl(0); + + printf("modifying port: %s\n", osf->ports[port_idx].name); + + if (!strncasecmp(argv[3], MOD_PORT_CMD_UP, sizeof MOD_PORT_CMD_UP)) { + opm->mask |= htonl(OFPPC_PORT_DOWN); + } else if (!strncasecmp(argv[3], MOD_PORT_CMD_DOWN, + sizeof MOD_PORT_CMD_DOWN)) { + opm->mask |= htonl(OFPPC_PORT_DOWN); + opm->config |= htonl(OFPPC_PORT_DOWN); + } else if (!strncasecmp(argv[3], MOD_PORT_CMD_FLOOD, + sizeof MOD_PORT_CMD_FLOOD)) { + opm->mask |= htonl(OFPPC_NO_FLOOD); + } else if (!strncasecmp(argv[3], MOD_PORT_CMD_NOFLOOD, + sizeof MOD_PORT_CMD_NOFLOOD)) { + opm->mask |= htonl(OFPPC_NO_FLOOD); + opm->config |= htonl(OFPPC_NO_FLOOD); + } else { + ofp_fatal(0, "unknown mod-port command '%s'", argv[3]); + } + + send_openflow_buffer(vconn, request); + + ofpbuf_delete(reply); + vconn_close(vconn); +} + +static void +do_ping(const struct settings *s UNUSED, int argc, char *argv[]) +{ + size_t max_payload = 65535 - sizeof(struct ofp_header); + unsigned int payload; + struct vconn *vconn; + int i; + + payload = argc > 2 ? atoi(argv[2]) : 64; + if (payload > max_payload) { + ofp_fatal(0, "payload must be between 0 and %zu bytes", max_payload); + } + + open_vconn(argv[1], &vconn); + for (i = 0; i < 10; i++) { + struct timeval start, end; + struct ofpbuf *request, *reply; + struct ofp_header *rq_hdr, *rpy_hdr; + + rq_hdr = make_openflow(sizeof(struct ofp_header) + payload, + OFPT_ECHO_REQUEST, &request); + random_bytes(rq_hdr + 1, payload); + + gettimeofday(&start, NULL); + run(vconn_transact(vconn, ofpbuf_clone(request), &reply), "transact"); + gettimeofday(&end, NULL); + + rpy_hdr = reply->data; + if (reply->size != request->size + || memcmp(rpy_hdr + 1, rq_hdr + 1, payload) + || rpy_hdr->xid != rq_hdr->xid + || rpy_hdr->type != OFPT_ECHO_REPLY) { + printf("Reply does not match request. Request:\n"); + ofp_print(stdout, request, request->size, 2); + printf("Reply:\n"); + ofp_print(stdout, reply, reply->size, 2); + } + printf("%d bytes from %s: xid=%08"PRIx32" time=%.1f ms\n", + reply->size - sizeof *rpy_hdr, argv[1], rpy_hdr->xid, + (1000*(double)(end.tv_sec - start.tv_sec)) + + (.001*(end.tv_usec - start.tv_usec))); + ofpbuf_delete(request); + ofpbuf_delete(reply); + } + vconn_close(vconn); +} + +static void +do_benchmark(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) +{ + size_t max_payload = 65535 - sizeof(struct ofp_header); + struct timeval start, end; + unsigned int payload_size, message_size; + struct vconn *vconn; + double duration; + int count; + int i; + + payload_size = atoi(argv[2]); + if (payload_size > max_payload) { + ofp_fatal(0, "payload must be between 0 and %zu bytes", max_payload); + } + message_size = sizeof(struct ofp_header) + payload_size; + + count = atoi(argv[3]); + + printf("Sending %d packets * %u bytes (with header) = %u bytes total\n", + count, message_size, count * message_size); + + open_vconn(argv[1], &vconn); + gettimeofday(&start, NULL); + for (i = 0; i < count; i++) { + struct ofpbuf *request, *reply; + struct ofp_header *rq_hdr; + + rq_hdr = make_openflow(message_size, OFPT_ECHO_REQUEST, &request); + memset(rq_hdr + 1, 0, payload_size); + run(vconn_transact(vconn, request, &reply), "transact"); + ofpbuf_delete(reply); + } + gettimeofday(&end, NULL); + vconn_close(vconn); + + duration = ((1000*(double)(end.tv_sec - start.tv_sec)) + + (.001*(end.tv_usec - start.tv_usec))); + printf("Finished in %.1f ms (%.0f packets/s) (%.0f bytes/s)\n", + duration, count / (duration / 1000.0), + count * message_size / (duration / 1000.0)); +} + +/**************************************************************** + * + * Queue operations + * + ****************************************************************/ + +static int +parse_queue_params(int argc, char *argv[], uint16_t *port, uint32_t *q_id, + uint16_t *min_rate) +{ + if (!port || !q_id) { + return -1; + } + + *port = OFPP_ALL; + *q_id = OFPQ_ALL; + if (argc > 2) { + *port = str_to_u32(argv[2]); + } + if (argc > 3) { + *q_id = str_to_u32(argv[3]); + } + if (min_rate) { + *min_rate = OFPQ_MIN_RATE_UNCFG; + if (argc > 4) { + *min_rate = str_to_u32(argv[4]); + } + } + + return 0; +} + +/* Length of queue request; works with 16-bit property values like min_rate */ +#define Q_REQ_LEN(prop_count) \ + (sizeof(struct ofp_packet_queue) + Q_PROP_LEN(prop_count)) + +#define Q_PROP_LEN(prop_count) \ + ((prop_count) * sizeof(struct ofp_queue_prop_min_rate)) + +/* + * Execute a queue add/mod/del operation + * + * All commands must specify a port and queue id. + * Add may specify a bandwidth value + * Modify must specify a bandwidth value + * + * To simplify things, always allocate space for all three parameters + * (port, queue, min-bw): + * openflow_queue_header (w/ ofp header, port) + * ofp_queue (with q_id and offset to properties list) + * ofp_queue_prop_min_rate (w/ prop header and rate info) + */ +static struct openflow_queue_command_header * +queue_req_create(int cmd, struct ofpbuf **b, uint16_t port, + uint32_t q_id, uint16_t min_rate) +{ + struct openflow_queue_command_header *request; + struct ofp_packet_queue *queue; + struct ofp_queue_prop_min_rate *min_rate_prop; + int req_bytes; + + req_bytes = sizeof(*request) + sizeof(*queue) + sizeof(*min_rate_prop); + request = make_openflow(req_bytes, OFPT_VENDOR, b); + if (request == NULL) { + return NULL; + } + request->header.vendor = htonl(OPENFLOW_VENDOR_ID); + request->header.subtype = htonl(cmd); + request->port = htons(port); + + /* Will get complicated when queue properties w/ different struct sizes */ + queue = S_PTR(request, struct openflow_queue_command_header, body); + queue->queue_id = htonl(q_id); + queue->len = htons(Q_REQ_LEN(1)); + + min_rate_prop = S_PTR(queue, struct ofp_packet_queue, properties); + min_rate_prop->prop_header.property = htons(OFPQT_MIN_RATE); + min_rate_prop->prop_header.len = htons(Q_PROP_LEN(1)); + min_rate_prop->rate = htons(min_rate); + + return request; +} + +/* Handler for add/modify/delete queue ops */ +static void +do_queue_op(int cmd, int argc, char *argv[]) +{ + struct openflow_queue_command_header *request; + struct vconn *vconn; + struct ofpbuf *b; + uint16_t port; + uint32_t q_id; + uint16_t min_rate; + + if (parse_queue_params(argc, argv, &port, &q_id, &min_rate) < 0) { + ofp_fatal(0, "Error parsing port/queue for cmd %s", argv[0]); + return; + } + + printf("que op %d (%s). port %d. q 0x%x. rate %d\n", cmd, argv[0], + port, q_id, min_rate); + + if ((request = queue_req_create(cmd, &b, port, q_id, min_rate)) == NULL) { + ofp_fatal(0, "Error creating queue req for cmd %s", argv[0]); + return; + } + + printf("made request %p, running transaction\n", request); + + open_vconn(argv[1], &vconn); + /* Unacknowledged call for now */ + send_openflow_buffer(vconn, b); + vconn_close(vconn); +} + +char *openflow_queue_error_strings[] = OPENFLOW_QUEUE_ERROR_STRINGS_DEF; + +static void +do_mod_queue(const struct settings *s UNUSED, int argc, char *argv[]) +{ + do_queue_op(OFP_EXT_QUEUE_MODIFY, argc, argv); +} + +static void +do_del_queue(const struct settings *s UNUSED, int argc, char *argv[]) +{ + do_queue_op(OFP_EXT_QUEUE_DELETE, argc, argv); +} + +static void +do_dump_queue_port(char *vconn_name, uint16_t port, uint32_t q_id) +{ + struct ofp_queue_get_config_request *request; + struct ofpbuf *buf; + + request = make_openflow(sizeof(*request), OFPT_QUEUE_GET_CONFIG_REQUEST, + &buf); + request->port = htons(port); /* FIXME */ + dump_transaction(vconn_name, buf); + + /* Then do a queue stats get */ + dump_queue_stats_transaction(vconn_name, OFPST_QUEUE, port, q_id); +} + +static void +do_dump_queue_all(char *vconn_name, uint32_t q_id) +{ + struct ofpbuf *request, *reply; + struct ofp_switch_features *osf; + int port_idx, n_ports; + uint16_t port_no; + struct vconn *vconn; + + /* Send a "Features Request" to get the list of ports in the system */ + make_openflow(sizeof(struct ofp_header), OFPT_FEATURES_REQUEST, &request); + open_vconn(vconn_name, &vconn); + run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name); + vconn_close(vconn); + + osf = reply->data; + n_ports = (reply->size - sizeof *osf) / sizeof *osf->ports; + for (port_idx = 0; port_idx < n_ports; port_idx++) { + if ((port_no = ntohs(osf->ports[port_idx].port_no)) < OFPP_MAX) { + do_dump_queue_port(vconn_name, port_no, q_id); + } + } + ofpbuf_delete(reply); +} + +static void +do_dump_queue(const struct settings *s UNUSED, int argc, char *argv[]) +{ + uint16_t port; + uint32_t q_id; + + /* Get queue params from the request */ + if (parse_queue_params(argc, argv, &port, &q_id, NULL) < 0) { + ofp_fatal(0, "Error parsing port/queue for cmd %s", argv[0]); + return; + } + + if (port == OFPP_ALL) { + do_dump_queue_all(argv[1], q_id); + } else { + do_dump_queue_port(argv[1], port, q_id); + } +} + +static void +do_help(const struct settings *s UNUSED, int argc UNUSED, char *argv[] UNUSED) +{ + usage(); +} + +static struct command all_commands[] = { +#ifdef HAVE_NETLINK + { "adddp", 1, 1, do_add_dp }, + { "deldp", 1, 1, do_del_dp }, + { "addif", 2, INT_MAX, do_add_port }, + { "delif", 2, INT_MAX, do_del_port }, + { "get-idx", 1, 1, do_get_idx }, +#endif + + { "show", 1, 1, do_show }, + { "status", 1, 2, do_status }, + + { "show-protostat", 1, 1, do_protostat }, + + { "help", 0, INT_MAX, do_help }, + { "monitor", 1, 1, do_monitor }, + { "dump-desc", 1, 1, do_dump_desc }, + { "dump-tables", 1, 1, do_dump_tables }, + { "desc", 2, 2, do_desc }, + { "dump-flows", 1, 2, do_dump_flows }, + { "dump-aggregate", 1, 2, do_dump_aggregate }, + { "add-flow", 2, 2, do_add_flow }, + { "add-flows", 2, 2, do_add_flows }, + { "mod-flows", 2, 2, do_mod_flows }, + { "del-flows", 1, 2, do_del_flows }, + { "dump-ports", 1, 2, do_dump_ports }, + { "mod-port", 3, 3, do_mod_port }, + { "add-queue", 3, 4, do_mod_queue }, + { "mod-queue", 3, 4, do_mod_queue }, + { "del-queue", 3, 3, do_del_queue }, + { "dump-queue", 1, 3, do_dump_queue }, + { "probe", 1, 1, do_probe }, + { "ping", 1, 2, do_ping }, + { "benchmark", 3, 3, do_benchmark }, + { NULL, 0, 0, NULL }, +}; diff --git a/openflow/utilities/ofp-discover.8.in b/openflow/utilities/ofp-discover.8.in new file mode 100644 index 00000000..cf5ac549 --- /dev/null +++ b/openflow/utilities/ofp-discover.8.in @@ -0,0 +1,119 @@ +.ds PN ofp\-discover + +.TH ofp\-discover 8 "May 2008" "OpenFlow" "OpenFlow Manual" + +.SH NAME +ofp\-discover \- controller discovery utility + +.SH SYNOPSIS +.B ofp\-discover +[\fIoptions\fR] \fInetdev\fR [\fInetdev\fR...] + +.SH DESCRIPTION +The \fBofp\-discover\fR program attempts to discover the location of +an OpenFlow controller on one of the network devices listed on the +command line. It repeatedly broadcasts a DHCP request with vendor +class identifier \fBOpenFlow\fR on each network device until it +receives an acceptable DHCP response. It will accept any valid DHCP +reply that has the same vendor class identifier and includes a +vendor-specific option with code 1 whose contents are a string +specifying the location of the controller in the same format used on +the \fBofprotocol\fR command line (e.g. \fBssl:192.168.0.1\fR). + +When \fBofp\-discover\fR receives an acceptable response, it prints +the details of the response on \fBstdout\fR. Then, by default, it +configures the network device on which the response was received with +the received IP address, netmask, and default gateway, and detaches +itself to the background. + +.SH OPTIONS +.TP +\fB--accept-vconn=\fIregex\fR +By default, \fBofp\-discover\fR accepts any controller location +advertised over DHCP. With this option, only controllers whose names +match POSIX extended regular expression \fIregex\fR will be accepted. +Specifying \fBssl:.*\fR for \fIregex\fR, for example, would cause only +SSL controller connections to be accepted. + +The \fIregex\fR is implicitly anchored at the beginning of the +controller location string, as if it begins with \fB^\fR. + +.TP +\fB--exit-without-bind\fR +By default, \fBofp\-discover\fR binds the network device that receives +the first acceptable response to the IP address received over DHCP. +With this option, the configuration of the network device is not +changed at all, except to bring it up if it is initially down, and +\fBofp\-discover\fR will exit immediately after it receives an +acceptable DHCP response. + +This option is mutually exclusive with \fB--exit-after-bind\fR and +\fB--no-detach\fR. + +.TP +\fB--exit-after-bind\fR +By default, after it receives an acceptable DHCP response, +\fBofp\-discover\fR detaches itself from the foreground session and +runs in the background maintaining the DHCP lease as necessary. With +this option, \fBofp\-discover\fR will exit immediately after it +receives an acceptable DHCP response and configures the network device +with the received IP address. The address obtained via DHCP could +therefore be used past the expiration of its lease. + +This option is mutually exclusive with \fB--exit-without-bind\fR and +\fB--no-detach\fR. + +.TP +\fB--no-detach\fR +By default, \fBofp\-discover\fR runs in the foreground until it obtains +an acceptable DHCP response, then it detaches itself from the +foreground session and run as a background process. This option +prevents \fBofp\-discover\fR from detaching, causing it to run in the +foreground even after it obtains a DHCP response. + +This option is mutually exclusive with \fB--exit-without-bind\fR and +\fB--exit-after-bind\fR. + +.TP +\fB-P\fR[\fIpidfile\fR], \fB--pidfile\fR[\fB=\fIpidfile\fR] +Causes a file (by default, \fBofp\-discover.pid\fR) to be created indicating +the PID of the running process. If \fIpidfile\fR is not specified, or +if it does not begin with \fB/\fR, then it is created in +\fB@RUNDIR@\fR. + +The \fIpidfile\fR is created when \fBofp\-discover\fR detaches, so +this this option has no effect when one of \fB--exit-without-bind\fR, +\fB--exit-after-bind\fR, or \fB--no-detach\fR is also given. + +.TP +\fB-f\fR, \fB--force\fR +By default, when \fB-P\fR or \fB--pidfile\fR is specified and the +specified pidfile already exists and is locked by a running process, +\fBcontroller\fR refuses to start. Specify \fB-f\fR or \fB--force\fR +to cause it to instead overwrite the pidfile. + +When \fB-P\fR or \fB--pidfile\fR is not specified, this option has no +effect. + +.so lib/vlog.man +.so lib/common.man + +.SH BUGS + +If the network devices specified on the command line have been added +to an OpenFlow switch with \fBdpctl addif\fR, then controller +discovery will fail because \fBofp\-discover\fR will not be able to +see DHCP responses, even though tools such as \fBtcpdump\fR(8) and +\fBwireshark\fR(1) can see them on the wire. This is because of the +structure of the Linux kernel networking stack, which hands packets +first to programs that listen for all arriving packets, then to +OpenFlow, then to programs that listen for a specific kind of packet. +OpenFlow consumes all the packets handed to it, so tools like +\fBtcpdump\fR that look at all packets will see packets arriving on +OpenFlow interfaces, but \fRofp\-discover\fR, which listens only for +arriving IP packets, will not. + +.SH "SEE ALSO" + +.BR ofprotocol (8), +.BR ofp-pki (8) diff --git a/openflow/utilities/ofp-discover.c b/openflow/utilities/ofp-discover.c new file mode 100644 index 00000000..55f40429 --- /dev/null +++ b/openflow/utilities/ofp-discover.c @@ -0,0 +1,420 @@ +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "command-line.h" +#include "daemon.h" +#include "dhcp-client.h" +#include "dhcp.h" +#include "dirs.h" +#include "dynamic-string.h" +#include "fatal-signal.h" +#include "netdev.h" +#include "poll-loop.h" +#include "timeval.h" +#include "util.h" +#include "vlog-socket.h" + +#include "vlog.h" +#define THIS_MODULE VLM_ofp_discover + +struct iface { + const char *name; + struct dhclient *dhcp; +}; + +/* The interfaces that we serve. */ +static struct iface *ifaces; +static int n_ifaces; + +/* --accept-vconn: Regular expression specifying the class of controller vconns + * that we will accept during autodiscovery. */ +static const char *accept_controller_re = ".*"; +static regex_t accept_controller_regex; + +/* --exit-without-bind: Exit after discovering the controller, without binding + * the network device to an IP address? */ +static bool exit_without_bind; + +/* --exit-after-bind: Exit after discovering the controller, after binding the + * network device to an IP address? */ +static bool exit_after_bind; + +static bool iface_init(struct iface *, const char *netdev_name); +static void release_ifaces(void *aux UNUSED); + +static void parse_options(int argc, char *argv[]); +static void usage(void) NO_RETURN; + +static void modify_dhcp_request(struct dhcp_msg *, void *aux); +static bool validate_dhcp_offer(const struct dhcp_msg *, void *aux); + +int +main(int argc, char *argv[]) +{ + int retval; + int i; + + set_program_name(argv[0]); + time_init(); + vlog_init(); + parse_options(argc, argv); + + argc -= optind; + argv += optind; + if (argc < 1) { + ofp_fatal(0, "need at least one non-option argument; " + "use --help for usage"); + } + + ifaces = xmalloc(argc * sizeof *ifaces); + n_ifaces = 0; + for (i = 0; i < argc; i++) { + if (iface_init(&ifaces[n_ifaces], argv[i])) { + n_ifaces++; + } + } + if (!n_ifaces) { + ofp_fatal(0, "failed to initialize any DHCP clients"); + } + + for (i = 0; i < n_ifaces; i++) { + struct iface *iface = &ifaces[i]; + dhclient_init(iface->dhcp, 0); + } + fatal_signal_add_hook(release_ifaces, NULL, true); + + retval = regcomp(&accept_controller_regex, accept_controller_re, + REG_NOSUB | REG_EXTENDED); + if (retval) { + size_t length = regerror(retval, &accept_controller_regex, NULL, 0); + char *buffer = xmalloc(length); + regerror(retval, &accept_controller_regex, buffer, length); + ofp_fatal(0, "%s: %s", accept_controller_re, buffer); + } + + retval = vlog_server_listen(NULL, NULL); + if (retval) { + ofp_fatal(retval, "Could not listen for vlog connections"); + } + + die_if_already_running(); + + signal(SIGPIPE, SIG_IGN); + for (;;) { + fatal_signal_block(); + for (i = 0; i < n_ifaces; i++) { + struct iface *iface = &ifaces[i]; + dhclient_run(iface->dhcp); + if (dhclient_changed(iface->dhcp)) { + bool is_bound = dhclient_is_bound(iface->dhcp); + int j; + + /* Configure network device. */ + if (!exit_without_bind) { + dhclient_configure_netdev(iface->dhcp); + dhclient_update_resolv_conf(iface->dhcp); + } + + if (is_bound) { + static bool detached = false; + struct ds ds; + + /* Disable timeout, since discovery was successful. */ + time_alarm(0); + + /* Print discovered parameters. */ + ds_init(&ds); + dhcp_msg_to_string(dhclient_get_config(iface->dhcp), + true, &ds); + fputs(ds_cstr(&ds), stdout); + putchar('\n'); + fflush(stdout); + ds_destroy(&ds); + + /* Exit if the user requested it. */ + if (exit_without_bind) { + VLOG_DBG("exiting because of successful binding on %s " + "and --exit-without-bind specified", + iface->name); + exit(0); + } + if (exit_after_bind) { + VLOG_DBG("exiting because of successful binding on %s " + "and --exit-after-bind specified", + iface->name); + exit(0); + } + + /* Detach into background, if we haven't already. */ + if (!detached) { + detached = true; + daemonize(); + } + } + + /* We only want an address on a single one of our interfaces. + * So: if we have an address on this interface, stop looking + * for one on the others; if we don't have an address on this + * interface, start looking everywhere. */ + for (j = 0; j < n_ifaces; j++) { + struct iface *if2 = &ifaces[j]; + if (iface != if2) { + if (is_bound) { + dhclient_release(if2->dhcp); + } else { + dhclient_init(if2->dhcp, 0); + } + } + } + } + } + for (i = 0; i < n_ifaces; i++) { + struct iface *iface = &ifaces[i]; + dhclient_wait(iface->dhcp); + } + fatal_signal_unblock(); + poll_block(); + } + + return 0; +} + +static bool +iface_init(struct iface *iface, const char *netdev_name) +{ + int retval; + + iface->name = netdev_name; + iface->dhcp = NULL; + + if (exit_after_bind) { + /* Bring this interface up permanently, so that the bound address + * persists past program termination. */ + struct netdev *netdev; + + retval = netdev_open(iface->name, NETDEV_ETH_TYPE_NONE, &netdev); + if (retval) { + ofp_error(retval, "Could not open %s device", iface->name); + return false; + } + retval = netdev_turn_flags_on(netdev, NETDEV_UP, true); + if (retval) { + ofp_error(retval, "Could not bring %s device up", iface->name); + return false; + } + netdev_close(netdev); + } + + retval = dhclient_create(iface->name, modify_dhcp_request, + validate_dhcp_offer, NULL, &iface->dhcp); + if (retval) { + ofp_error(retval, "%s: failed to initialize DHCP client", iface->name); + return false; + } + + return true; +} + +static void +release_ifaces(void *aux UNUSED) +{ + int i; + + for (i = 0; i < n_ifaces; i++) { + struct dhclient *dhcp = ifaces[i].dhcp; + dhclient_release(dhcp); + if (dhclient_changed(dhcp)) { + dhclient_configure_netdev(dhcp); + } + } +} + +static void +modify_dhcp_request(struct dhcp_msg *msg, void *aux UNUSED) +{ + dhcp_msg_put_string(msg, DHCP_CODE_VENDOR_CLASS, "OpenFlow"); +} + +static bool +validate_dhcp_offer(const struct dhcp_msg *msg, void *aux UNUSED) +{ + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60); + char *vconn_name; + bool accept; + + vconn_name = dhcp_msg_get_string(msg, DHCP_CODE_OFP_CONTROLLER_VCONN); + if (!vconn_name) { + VLOG_WARN_RL(&rl, "rejecting DHCP offer missing controller vconn"); + return false; + } + accept = !regexec(&accept_controller_regex, vconn_name, 0, NULL, 0); + free(vconn_name); + return accept; +} + +static void +parse_options(int argc, char *argv[]) +{ + enum { + OPT_ACCEPT_VCONN = UCHAR_MAX + 1, + OPT_EXIT_WITHOUT_BIND, + OPT_EXIT_AFTER_BIND, + OPT_NO_DETACH, + }; + static struct option long_options[] = { + {"accept-vconn", required_argument, 0, OPT_ACCEPT_VCONN}, + {"exit-without-bind", no_argument, 0, OPT_EXIT_WITHOUT_BIND}, + {"exit-after-bind", no_argument, 0, OPT_EXIT_AFTER_BIND}, + {"no-detach", no_argument, 0, OPT_NO_DETACH}, + {"timeout", required_argument, 0, 't'}, + {"pidfile", optional_argument, 0, 'P'}, + {"force", no_argument, 0, 'f'}, + {"verbose", optional_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {0, 0, 0, 0}, + }; + char *short_options = long_options_to_short_options(long_options); + bool detach_after_bind = true; + + for (;;) { + unsigned long int timeout; + int c; + + c = getopt_long(argc, argv, short_options, long_options, NULL); + if (c == -1) { + break; + } + + switch (c) { + case OPT_ACCEPT_VCONN: + accept_controller_re = (optarg[0] == '^' + ? optarg + : xasprintf("^%s", optarg)); + break; + + case OPT_EXIT_WITHOUT_BIND: + exit_without_bind = true; + break; + + case OPT_EXIT_AFTER_BIND: + exit_after_bind = true; + break; + + case OPT_NO_DETACH: + detach_after_bind = false; + break; + + case 'P': + set_pidfile(optarg); + break; + + case 'f': + ignore_existing_pidfile(); + break; + + case 't': + timeout = strtoul(optarg, NULL, 10); + if (timeout <= 0) { + ofp_fatal(0, "value %s on -t or --timeout is not at least 1", + optarg); + } else { + time_alarm(timeout); + } + signal(SIGALRM, SIG_DFL); + break; + + case 'h': + usage(); + + case 'V': + printf("%s %s compiled "__DATE__" "__TIME__"\n", + program_name, VERSION BUILDNR); + exit(EXIT_SUCCESS); + + case 'v': + vlog_set_verbosity(optarg); + break; + + case '?': + exit(EXIT_FAILURE); + + default: + abort(); + } + } + free(short_options); + + if ((exit_without_bind + exit_after_bind + !detach_after_bind) > 1) { + ofp_fatal(0, "--exit-without-bind, --exit-after-bind, and --no-detach " + "are mutually exclusive"); + } + if (detach_after_bind) { + set_detach(); + } +} + +static void +usage(void) +{ + printf("%s: a tool for discovering OpenFlow controllers.\n" + "usage: %s [OPTIONS] NETDEV [NETDEV...]\n" + "where each NETDEV is a network device on which to perform\n" + "controller discovery.\n" + "\nOrdinarily, ofp-discover runs in the foreground until it\n" + "obtains an IP address and discovers an OpenFlow controller via\n" + "DHCP, then it prints information about the controller to stdout\n" + "and detaches to the background to maintain the IP address lease.\n" + "\nNetworking options:\n" + " --accept-vconn=REGEX accept matching discovered controllers\n" + " --exit-without-bind exit after discovery, without binding\n" + " --exit-after-bind exit after discovery, after binding\n" + " --no-detach do not detach after discovery\n", + program_name, program_name); + vlog_usage(); + printf("\nOther options:\n" + " -t, --timeout=SECS give up discovery after SECS seconds\n" + " -P, --pidfile[=FILE] create pidfile (default: %s/%s.pid)\n" + " -f, --force with -P, start even if already running\n" + " -h, --help display this help message\n" + " -V, --version display version information\n", + ofp_rundir, program_name); + exit(EXIT_SUCCESS); +} diff --git a/openflow/utilities/ofp-kill.8.in b/openflow/utilities/ofp-kill.8.in new file mode 100644 index 00000000..6c1298ca --- /dev/null +++ b/openflow/utilities/ofp-kill.8.in @@ -0,0 +1,61 @@ +.ds PN ofp\-kill + +.TH ofp\-kill 8 "May 2008" "OpenFlow" "OpenFlow Manual" + +.SH NAME +ofp\-kill \- kills processes given their pidfiles + +.SH SYNOPSIS +.B ofp\-kill +[\fIoptions\fR] \fIpidfile\fR [\fIpidfile\fR...] + +.SH DESCRIPTION +The \fBofp\-kill\fR program reads each \fIpidfile\fR specified on the +command line and sends a signal to the program associated with it, if +any. It reads one line of text from \fIpidfile\fR, which must contain +the PID of the process to kill as a text string. It then uses +\fBfcntl\fR(2) to verify that a process with the PID from the file +owns a lock on \fIpidfile\fR before it sends the signal. + +A \fIpidfile\fR whose name begins with \fB/\fR is used literally. +Otherwise, \fB@RUNDIR@/\fR is prefixed. + +This program exists for use by \fBofp\-switch\-setup\fR, which cannot +easily implement its functionality since Perl has no portable +interface to \fBfcntl\fR-based file locking. + +.SH OPTIONS +.TP +\fB-s \fInumber\fR|\fIname\fR, \fB\-\^\-signal=\fInumber\fR|\fIname\fR +Sets the signal to be sent to each process. Signals may be given by +number (e.g. \fB1\fR) or by name (e.g. \fBHUP\fR or \fBSIGHUP\fR). +By default, \fBSIGTERM\fR is sent. + +.TP +\fB-f\fR, \fB\-\^\-force\fR +Causes \fBofp\-kill\fR to ignore all errors without printing a message +to \fBstderr\fR, and to exit with return code 0. + +.so lib/common.man + +.SH "EXIT CODE" + +Without \fB-f\fR or \fB\-\^\-force\fR, \fBofp\-kill\fR exits with +status 0 if at least one \fIpidfile\fR was given and the process +represented by every \fIpidfile\fR was signaled successfully, +otherwise with status 1. + +With \fB-f\fR or \fB\-\^\-force\fR, \fBofp\-kill\fR always exits with +status 0. + +.SH BUGS + +There is a race between verifying the lock on \fIpidfile\fR and +actually killing the process. + +\fBofp\-kill\fR does not wait for the signaled processes to die before +exiting. + +.SH "SEE ALSO" + +.BR ofp\-switch\-setup (8) diff --git a/openflow/utilities/ofp-kill.c b/openflow/utilities/ofp-kill.c new file mode 100644 index 00000000..0ad04343 --- /dev/null +++ b/openflow/utilities/ofp-kill.c @@ -0,0 +1,228 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "command-line.h" +#include "daemon.h" +#include "timeval.h" +#include "util.h" +#include "vlog.h" + +/* -s, --signal: signal to send. */ +static int sig_nr = SIGTERM; + +/* -f, --force: ignore errors. */ +static bool force; + +static void cond_error(int err_no, const char *, ...) PRINTF_FORMAT(2, 3); + +static void parse_options(int argc, char *argv[]); +static void usage(void); + +int +main(int argc, char *argv[]) +{ + bool ok = true; + int i; + + set_program_name(argv[0]); + time_init(); + vlog_init(); + parse_options(argc, argv); + + argc -= optind; + argv += optind; + if (argc < 1) { + if (!force) { + ofp_fatal(0, "need at least one non-option argument; " + "use --help for usage"); + } + } + + for (i = 0; i < argc; i++) { + char *pidfile; + pid_t pid; + + pidfile = make_pidfile_name(argv[i]); + pid = read_pidfile(pidfile); + if (pid >= 0) { + if (kill(pid, sig_nr) < 0) { + cond_error(errno, "%s: kill(%ld)", pidfile, (long int) pid); + } + } else { + cond_error(-pid, "could not read %s", pidfile); + } + free(pidfile); + } + + return ok || force ? EXIT_SUCCESS : EXIT_FAILURE; +} + +static void +parse_options(int argc, char *argv[]) +{ + static struct option long_options[] = { + {"signal", required_argument, 0, 's'}, + {"force", no_argument, 0, 'f'}, + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {0, 0, 0, 0}, + }; + char *short_options = long_options_to_short_options(long_options); + + for (;;) { + int c; + + c = getopt_long(argc, argv, short_options, long_options, NULL); + if (c == -1) { + break; + } + + switch (c) { + case 's': + if (atoi(optarg) || !strcmp(optarg, "0")) { + sig_nr = atoi(optarg); + } else { + struct signal_name { + const char *name; + int number; + }; + + static const struct signal_name signals[] = { +#define SIGNAL(NAME) { #NAME, NAME } + SIGNAL(SIGABRT), + SIGNAL(SIGALRM), + SIGNAL(SIGBUS), + SIGNAL(SIGCHLD), + SIGNAL(SIGCONT), + SIGNAL(SIGFPE), + SIGNAL(SIGHUP), + SIGNAL(SIGILL), + SIGNAL(SIGINT), + SIGNAL(SIGKILL), + SIGNAL(SIGPIPE), + SIGNAL(SIGQUIT), + SIGNAL(SIGSEGV), + SIGNAL(SIGSTOP), + SIGNAL(SIGTERM), + SIGNAL(SIGTSTP), + SIGNAL(SIGTTIN), + SIGNAL(SIGTTOU), + SIGNAL(SIGUSR1), + SIGNAL(SIGUSR2), +#ifdef SIGPOLL + SIGNAL(SIGPOLL), +#endif + SIGNAL(SIGPROF), + SIGNAL(SIGSYS), + SIGNAL(SIGTRAP), + SIGNAL(SIGURG), + SIGNAL(SIGVTALRM), + SIGNAL(SIGXCPU), + SIGNAL(SIGXFSZ), +#undef SIGNAL + }; + int i; + + for (i = 0; i < ARRAY_SIZE(signals); i++) { + const struct signal_name *s = &signals[i]; + if (!strcmp(optarg, s->name) + || !strcmp(optarg, s->name + 3)) { + sig_nr = s->number; + goto got_name; + } + } + ofp_fatal(0, "unknown signal \"%s\"", optarg); + got_name: ; + } + break; + + case 'f': + force = true; + break; + + case 'h': + usage(); + + case 'V': + printf("%s %s compiled "__DATE__" "__TIME__"\n", + program_name, VERSION BUILDNR); + exit(EXIT_SUCCESS); + + case '?': + exit(EXIT_FAILURE); + + default: + abort(); + } + } + free(short_options); +} + +static void +usage(void) +{ + printf("%s: kills a program using a pidfile\n" + "usage: %s [OPTIONS] PIDFILE [PIDFILE...]\n" + "where each PIDFILE is a pidfile created by an OpenFlow daemon.\n" + "\nOptions:\n" + " -s, --signal=NUMBER|NAME signal to send (default: TERM)\n" + " -f, --force ignore errors\n" + " -h, --help display this help message\n" + " -V, --version display version information\n", + program_name, program_name); + exit(EXIT_SUCCESS); +} + +static void +cond_error(int err_no, const char *format, ...) +{ + if (!force) { + va_list args; + + fprintf(stderr, "%s: ", program_name); + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + if (err_no != 0) + fprintf(stderr, " (%s)", strerror(err_no)); + putc('\n', stderr); + } +} diff --git a/openflow/utilities/ofp-parse-leaks b/openflow/utilities/ofp-parse-leaks new file mode 100644 index 00000000..e51ecb72 --- /dev/null +++ b/openflow/utilities/ofp-parse-leaks @@ -0,0 +1,285 @@ +#! /usr/bin/perl + +use strict; +use warnings; + +if (grep($_ eq '--help', @ARGV)) { + print < 1; +die "$0: $ARGV[0] does not exist" if @ARGV > 0 && ! -e $ARGV[0]; + +our ($binary); +our ($a2l) = search_path("addr2line"); +my ($no_syms) = "symbols will not be translated"; +if (!@ARGV) { + print "no binary specified; $no_syms\n"; +} elsif (! -e $ARGV[0]) { + print "$ARGV[0] does not exist; $no_syms"; +} elsif (!defined($a2l)) { + print "addr2line not found in PATH; $no_syms"; +} else { + $binary = $ARGV[0]; +} + +our ($objdump) = search_path("objdump"); +print "objdump not found; dynamic library symbols will not be translated\n" + if !defined($objdump); + +our %blocks; +our @segments; +while () { + my $ptr = "((?:0x)?[0-9a-fA-F]+|\\(nil\\))"; + my $callers = ":((?: $ptr)+)"; + if (/^malloc\((\d+)\) -> $ptr$callers$/) { + allocated($., $2, $1, $3); + } elsif (/^claim\($ptr\)$callers$/) { + claimed($., $1, $2); + } elsif (/realloc\($ptr, (\d+)\) -> $ptr$callers$/) { + my ($callers) = $4; + freed($., $1, $callers); + allocated($., $3, $2, $callers); + } elsif (/^free\($ptr\)$callers$/) { + freed($., $1, $2); + } elsif (/^segment: $ptr-$ptr $ptr [-r][-w][-x][sp] (.*)/) { + add_segment(hex($1), hex($2), hex($3), $4); + } else { + print "stdin:$.: syntax error\n"; + } +} +if (%blocks) { + my $n_blocks = scalar(keys(%blocks)); + my $n_bytes = 0; + $n_bytes += $_->{SIZE} foreach values(%blocks); + print "$n_bytes bytes in $n_blocks blocks not freed at end of run\n"; + my %blocks_by_callers; + foreach my $block (values(%blocks)) { + my ($trimmed_callers) = trim_callers($block->{CALLERS}); + push (@{$blocks_by_callers{$trimmed_callers}}, $block); + } + foreach my $callers (sort {@{$b} <=> @{$a}} (values(%blocks_by_callers))) { + $n_blocks = scalar(@{$callers}); + $n_bytes = 0; + $n_bytes += $_->{SIZE} foreach @{$callers}; + print "$n_bytes bytes in these $n_blocks blocks were not freed:\n"; + my $i = 0; + my $max = 5; + foreach my $block (sort {$a->{LINE} <=> $b->{LINE}} (@{$callers})) { + printf "\t%d-byte block at 0x%08x allocated on stdin:%d\n", + $block->{SIZE}, $block->{BASE}, $block->{LINE}; + last if $i++ > $max; + } + print "\t...and ", $n_blocks - $max, " others...\n" + if $n_blocks > $max; + print "The blocks listed above were allocated by:\n"; + print_callers("\t", ${$callers}[0]->{CALLERS}); + } +} +sub interp_pointer { + my ($s_ptr) = @_; + return $s_ptr eq '(nil)' ? 0 : hex($s_ptr); +} + +sub allocated { + my ($line, $s_base, $size, $callers) = @_; + my ($base) = interp_pointer($s_base); + return if !$base; + my ($info) = {LINE => $line, + BASE => $base, + SIZE => $size, + CALLERS => $callers}; + if (exists($blocks{$base})) { + print "In-use address returned by allocator:\n"; + print "\tInitial allocation:\n"; + print_block("\t\t", $blocks{$base}); + print "\tNew allocation:\n"; + print_block("\t\t", $info); + } + $blocks{$base} = $info; +} + +sub claimed { + my ($line, $s_base, $callers) = @_; + my ($base) = interp_pointer($s_base); + return if !$base; + if (exists($blocks{$base})) { + $blocks{$base}{LINE} = $line; + $blocks{$base}{CALLERS} = $callers; + } else { + printf "Claim asserted on not-in-use block 0x%08x by:\n", $base; + print_callers('', $callers); + } +} + +sub freed { + my ($line, $s_base, $callers) = @_; + my ($base) = interp_pointer($s_base); + return if !$base; + + if (!delete($blocks{$base})) { + printf "Bad free of not-allocated address 0x%08x on stdin:%d by:\n", $base, $line; + print_callers('', $callers); + } +} + +sub print_block { + my ($prefix, $info) = @_; + printf '%s%d-byte block at 0x%08x allocated on stdin:%d by:' . "\n", + $prefix, $info->{SIZE}, $info->{BASE}, $info->{LINE}; + print_callers($prefix, $info->{CALLERS}); +} + +sub print_callers { + my ($prefix, $callers) = @_; + foreach my $pc (split(' ', $callers)) { + print "$prefix\t", lookup_pc($pc), "\n"; + } +} + +our (%cache); +sub lookup_pc { + my ($s_pc) = @_; + if (defined($binary)) { + my ($pc) = hex($s_pc); + my ($output) = "$s_pc: "; + if (!exists($cache{$pc})) { + open(A2L, "$a2l -fe $binary --demangle $s_pc|"); + chomp(my $function = ); + chomp(my $line = ); + close(A2L); + if ($function eq '??') { + ($function, $line) = lookup_pc_by_segment($pc); + } + $line =~ s/^(\.\.\/)*//; + $line = "..." . substr($line, -25) if length($line) > 28; + $cache{$pc} = "$s_pc: $function ($line)"; + } + return $cache{$pc}; + } else { + return "$s_pc"; + } +} + +sub trim_callers { + my ($in) = @_; + my (@out); + foreach my $pc (split(' ', $in)) { + my $xlated = lookup_pc($pc); + if ($xlated =~ /\?\?/) { + push(@out, "...") if !@out || $out[$#out] ne '...'; + } else { + push(@out, $pc); + } + } + return join(' ', @out); +} + +sub search_path { + my ($target) = @_; + for my $dir (split (':', $ENV{PATH})) { + my ($file) = "$dir/$target"; + return $file if -e $file; + } + return undef; +} + +sub add_segment { + my ($vm_start, $vm_end, $vm_pgoff, $file) = @_; + for (my $i = 0; $i <= $#segments; $i++) { + my ($s) = $segments[$i]; + next if $vm_end <= $s->{START} || $vm_start >= $s->{END}; + if ($vm_start <= $s->{START} && $vm_end >= $s->{END}) { + splice(@segments, $i, 1); + --$i; + } else { + $s->{START} = $vm_end if $vm_end > $s->{START}; + $s->{END} = $vm_start if $vm_start <= $s->{END}; + } + } + push(@segments, {START => $vm_start, + END => $vm_end, + PGOFF => $vm_pgoff, + FILE => $file}); + @segments = sort { $a->{START} <=> $b->{START} } @segments; +} + +sub binary_search { + my ($array, $value) = @_; + my $l = 0; + my $r = $#{$array}; + while ($l <= $r) { + my $m = int(($l + $r) / 2); + my $e = $array->[$m]; + if ($value < $e->{START}) { + $r = $m - 1; + } elsif ($value >= $e->{END}) { + $l = $m + 1; + } else { + return $e; + } + } + return undef; +} + +sub read_sections { + my ($file) = @_; + my (@sections); + open(OBJDUMP, "$objdump -h $file|"); + while () { + my $ptr = "([0-9a-fA-F]+)"; + my ($name, $size, $vma, $lma, $file_off) + = /^\s*\d+\s+(\S+)\s+$ptr\s+$ptr\s+$ptr\s+$ptr/ + or next; + push(@sections, {START => hex($file_off), + END => hex($file_off) + hex($size), + NAME => $name}); + } + close(OBJDUMP); + return [sort { $a->{START} <=> $b->{START} } @sections ]; +} + +our %file_to_sections; +sub segment_to_section { + my ($file, $file_offset) = @_; + if (!defined($file_to_sections{$file})) { + $file_to_sections{$file} = read_sections($file); + } + return binary_search($file_to_sections{$file}, $file_offset); +} + +sub address_to_segment { + my ($pc) = @_; + return binary_search(\@segments, $pc); +} + +sub lookup_pc_by_segment { + return ('??', 0) if !defined($objdump); + + my ($pc) = @_; + my ($segment) = address_to_segment($pc); + return ('??', 0) if !defined($segment) || $segment->{FILE} eq ''; + + my ($file_offset) = $pc - $segment->{START} + $segment->{PGOFF}; + my ($section) = segment_to_section($segment->{FILE}, $file_offset); + return ('??', 0) if !defined($section); + + my ($section_offset) = $file_offset - $section->{START}; + open(A2L, sprintf("%s -fe %s --demangle --section=$section->{NAME} 0x%x|", + $a2l, $segment->{FILE}, $section_offset)); + chomp(my $function = ); + chomp(my $line = ); + close(A2L); + + return ($function, $line); +} + +# Local Variables: +# mode: perl +# End: diff --git a/openflow/utilities/ofp-parse-leaks.in b/openflow/utilities/ofp-parse-leaks.in new file mode 100755 index 00000000..059c8509 --- /dev/null +++ b/openflow/utilities/ofp-parse-leaks.in @@ -0,0 +1,285 @@ +#! @PERL@ + +use strict; +use warnings; + +if (grep($_ eq '--help', @ARGV)) { + print < 1; +die "$0: $ARGV[0] does not exist" if @ARGV > 0 && ! -e $ARGV[0]; + +our ($binary); +our ($a2l) = search_path("addr2line"); +my ($no_syms) = "symbols will not be translated"; +if (!@ARGV) { + print "no binary specified; $no_syms\n"; +} elsif (! -e $ARGV[0]) { + print "$ARGV[0] does not exist; $no_syms"; +} elsif (!defined($a2l)) { + print "addr2line not found in PATH; $no_syms"; +} else { + $binary = $ARGV[0]; +} + +our ($objdump) = search_path("objdump"); +print "objdump not found; dynamic library symbols will not be translated\n" + if !defined($objdump); + +our %blocks; +our @segments; +while () { + my $ptr = "((?:0x)?[0-9a-fA-F]+|\\(nil\\))"; + my $callers = ":((?: $ptr)+)"; + if (/^malloc\((\d+)\) -> $ptr$callers$/) { + allocated($., $2, $1, $3); + } elsif (/^claim\($ptr\)$callers$/) { + claimed($., $1, $2); + } elsif (/realloc\($ptr, (\d+)\) -> $ptr$callers$/) { + my ($callers) = $4; + freed($., $1, $callers); + allocated($., $3, $2, $callers); + } elsif (/^free\($ptr\)$callers$/) { + freed($., $1, $2); + } elsif (/^segment: $ptr-$ptr $ptr [-r][-w][-x][sp] (.*)/) { + add_segment(hex($1), hex($2), hex($3), $4); + } else { + print "stdin:$.: syntax error\n"; + } +} +if (%blocks) { + my $n_blocks = scalar(keys(%blocks)); + my $n_bytes = 0; + $n_bytes += $_->{SIZE} foreach values(%blocks); + print "$n_bytes bytes in $n_blocks blocks not freed at end of run\n"; + my %blocks_by_callers; + foreach my $block (values(%blocks)) { + my ($trimmed_callers) = trim_callers($block->{CALLERS}); + push (@{$blocks_by_callers{$trimmed_callers}}, $block); + } + foreach my $callers (sort {@{$b} <=> @{$a}} (values(%blocks_by_callers))) { + $n_blocks = scalar(@{$callers}); + $n_bytes = 0; + $n_bytes += $_->{SIZE} foreach @{$callers}; + print "$n_bytes bytes in these $n_blocks blocks were not freed:\n"; + my $i = 0; + my $max = 5; + foreach my $block (sort {$a->{LINE} <=> $b->{LINE}} (@{$callers})) { + printf "\t%d-byte block at 0x%08x allocated on stdin:%d\n", + $block->{SIZE}, $block->{BASE}, $block->{LINE}; + last if $i++ > $max; + } + print "\t...and ", $n_blocks - $max, " others...\n" + if $n_blocks > $max; + print "The blocks listed above were allocated by:\n"; + print_callers("\t", ${$callers}[0]->{CALLERS}); + } +} +sub interp_pointer { + my ($s_ptr) = @_; + return $s_ptr eq '(nil)' ? 0 : hex($s_ptr); +} + +sub allocated { + my ($line, $s_base, $size, $callers) = @_; + my ($base) = interp_pointer($s_base); + return if !$base; + my ($info) = {LINE => $line, + BASE => $base, + SIZE => $size, + CALLERS => $callers}; + if (exists($blocks{$base})) { + print "In-use address returned by allocator:\n"; + print "\tInitial allocation:\n"; + print_block("\t\t", $blocks{$base}); + print "\tNew allocation:\n"; + print_block("\t\t", $info); + } + $blocks{$base} = $info; +} + +sub claimed { + my ($line, $s_base, $callers) = @_; + my ($base) = interp_pointer($s_base); + return if !$base; + if (exists($blocks{$base})) { + $blocks{$base}{LINE} = $line; + $blocks{$base}{CALLERS} = $callers; + } else { + printf "Claim asserted on not-in-use block 0x%08x by:\n", $base; + print_callers('', $callers); + } +} + +sub freed { + my ($line, $s_base, $callers) = @_; + my ($base) = interp_pointer($s_base); + return if !$base; + + if (!delete($blocks{$base})) { + printf "Bad free of not-allocated address 0x%08x on stdin:%d by:\n", $base, $line; + print_callers('', $callers); + } +} + +sub print_block { + my ($prefix, $info) = @_; + printf '%s%d-byte block at 0x%08x allocated on stdin:%d by:' . "\n", + $prefix, $info->{SIZE}, $info->{BASE}, $info->{LINE}; + print_callers($prefix, $info->{CALLERS}); +} + +sub print_callers { + my ($prefix, $callers) = @_; + foreach my $pc (split(' ', $callers)) { + print "$prefix\t", lookup_pc($pc), "\n"; + } +} + +our (%cache); +sub lookup_pc { + my ($s_pc) = @_; + if (defined($binary)) { + my ($pc) = hex($s_pc); + my ($output) = "$s_pc: "; + if (!exists($cache{$pc})) { + open(A2L, "$a2l -fe $binary --demangle $s_pc|"); + chomp(my $function = ); + chomp(my $line = ); + close(A2L); + if ($function eq '??') { + ($function, $line) = lookup_pc_by_segment($pc); + } + $line =~ s/^(\.\.\/)*//; + $line = "..." . substr($line, -25) if length($line) > 28; + $cache{$pc} = "$s_pc: $function ($line)"; + } + return $cache{$pc}; + } else { + return "$s_pc"; + } +} + +sub trim_callers { + my ($in) = @_; + my (@out); + foreach my $pc (split(' ', $in)) { + my $xlated = lookup_pc($pc); + if ($xlated =~ /\?\?/) { + push(@out, "...") if !@out || $out[$#out] ne '...'; + } else { + push(@out, $pc); + } + } + return join(' ', @out); +} + +sub search_path { + my ($target) = @_; + for my $dir (split (':', $ENV{PATH})) { + my ($file) = "$dir/$target"; + return $file if -e $file; + } + return undef; +} + +sub add_segment { + my ($vm_start, $vm_end, $vm_pgoff, $file) = @_; + for (my $i = 0; $i <= $#segments; $i++) { + my ($s) = $segments[$i]; + next if $vm_end <= $s->{START} || $vm_start >= $s->{END}; + if ($vm_start <= $s->{START} && $vm_end >= $s->{END}) { + splice(@segments, $i, 1); + --$i; + } else { + $s->{START} = $vm_end if $vm_end > $s->{START}; + $s->{END} = $vm_start if $vm_start <= $s->{END}; + } + } + push(@segments, {START => $vm_start, + END => $vm_end, + PGOFF => $vm_pgoff, + FILE => $file}); + @segments = sort { $a->{START} <=> $b->{START} } @segments; +} + +sub binary_search { + my ($array, $value) = @_; + my $l = 0; + my $r = $#{$array}; + while ($l <= $r) { + my $m = int(($l + $r) / 2); + my $e = $array->[$m]; + if ($value < $e->{START}) { + $r = $m - 1; + } elsif ($value >= $e->{END}) { + $l = $m + 1; + } else { + return $e; + } + } + return undef; +} + +sub read_sections { + my ($file) = @_; + my (@sections); + open(OBJDUMP, "$objdump -h $file|"); + while () { + my $ptr = "([0-9a-fA-F]+)"; + my ($name, $size, $vma, $lma, $file_off) + = /^\s*\d+\s+(\S+)\s+$ptr\s+$ptr\s+$ptr\s+$ptr/ + or next; + push(@sections, {START => hex($file_off), + END => hex($file_off) + hex($size), + NAME => $name}); + } + close(OBJDUMP); + return [sort { $a->{START} <=> $b->{START} } @sections ]; +} + +our %file_to_sections; +sub segment_to_section { + my ($file, $file_offset) = @_; + if (!defined($file_to_sections{$file})) { + $file_to_sections{$file} = read_sections($file); + } + return binary_search($file_to_sections{$file}, $file_offset); +} + +sub address_to_segment { + my ($pc) = @_; + return binary_search(\@segments, $pc); +} + +sub lookup_pc_by_segment { + return ('??', 0) if !defined($objdump); + + my ($pc) = @_; + my ($segment) = address_to_segment($pc); + return ('??', 0) if !defined($segment) || $segment->{FILE} eq ''; + + my ($file_offset) = $pc - $segment->{START} + $segment->{PGOFF}; + my ($section) = segment_to_section($segment->{FILE}, $file_offset); + return ('??', 0) if !defined($section); + + my ($section_offset) = $file_offset - $section->{START}; + open(A2L, sprintf("%s -fe %s --demangle --section=$section->{NAME} 0x%x|", + $a2l, $segment->{FILE}, $section_offset)); + chomp(my $function = ); + chomp(my $line = ); + close(A2L); + + return ($function, $line); +} + +# Local Variables: +# mode: perl +# End: diff --git a/openflow/utilities/ofp-pki-cgi.in b/openflow/utilities/ofp-pki-cgi.in new file mode 100755 index 00000000..837b3f92 --- /dev/null +++ b/openflow/utilities/ofp-pki-cgi.in @@ -0,0 +1,41 @@ +#! @PERL@ + +use CGI; +use Digest::SHA1; +use Fcntl; + +$CGI::POST_MAX = 65536; # Limit POSTs to 64 kB. + +use strict; +use warnings; + +my $pkidir = '@PKIDIR@'; +my $q = new CGI; + +die unless $q->request_method() eq 'POST'; + +my $type = $q->param('type'); +die unless defined $type; +die unless $type eq 'switch' or $type eq 'controller'; + +my $req = $q->param('req'); +die unless defined $req; +die unless $req =~ /^-----BEGIN CERTIFICATE REQUEST-----$/m; +die unless $req =~ /^-----END CERTIFICATE REQUEST-----$/m; + +my $digest = Digest::SHA1::sha1_hex($req); +my $incoming = "$pkidir/${type}ca/incoming"; +my $dst = "$incoming/$digest-req.pem"; + +sysopen(REQUEST, "$dst.tmp", O_RDWR | O_CREAT | O_EXCL, 0600) + or die "sysopen $dst.tmp: $!"; +print REQUEST $req; +close(REQUEST) or die "close $dst.tmp: $!"; + +rename("$dst.tmp", $dst) or die "rename $dst.tmp to $dst: $!"; + +print $q->header('text/html', '204 No response'); + +# Local Variables: +# mode: perl +# End: diff --git a/openflow/utilities/ofp-pki.8.in b/openflow/utilities/ofp-pki.8.in new file mode 100644 index 00000000..82558955 --- /dev/null +++ b/openflow/utilities/ofp-pki.8.in @@ -0,0 +1,325 @@ +.TH ofp\-pki 8 "May 2008" "OpenFlow" "OpenFlow Manual" + +.SH NAME +ofp\-pki \- OpenFlow public key infrastructure management utility + +.SH SYNOPSIS +\fBofp\-pki\fR [\fIOPTIONS\fR] \fICOMMAND\fR [\fIARGS\fR] +.sp +Stand\-alone commands with their arguments: +.br +\fBofp\-pki\fR \fBinit\fR +.br +\fBofp\-pki\fR \fBreq\fR \fINAME\fR +.br +\fBofp\-pki\fR \fBsign\fR \fINAME\fR [\fITYPE\fR] +.br +\fBofp\-pki\fR \fBreq+sign\fR \fINAME\fR [\fITYPE\fR] +.br +\fBofp\-pki\fR \fBverify\fR \fINAME\fR [\fITYPE\fR] +.br +\fBofp\-pki\fR \fBfingerprint\fR \fIFILE\fR +.br +\fBofp\-pki\fR \self-sign\fR \fINAME\fR +.sp +The following additional commands manage an online PKI: +.br +\fBofp\-pki\fR \fBls\fR [\fIPREFIX\fR] [\fITYPE\fR] +.br +\fBofp\-pki\fR \fBflush\fR [\fITYPE\fR] +.br +\fBofp\-pki\fR \fBreject\fR \fIPREFIX\fR [\fITYPE\fR] +.br +\fBofp\-pki\fR \fBapprove\fR \fIPREFIX\fR [\fITYPE\fR] +.br +\fBofp\-pki\fR \fBprompt\fR [\fITYPE\fR] +.br +\fBofp\-pki\fR \fBexpire\fR [\fIAGE\fR] +.sp +Each \fITYPE\fR above is a certificate type, either \fBswitch\fR +(default) or \fBcontroller\fR. +.sp +The available options are: +.br +[\fB\-k\fR \fItype\fR | \fB\-\^\-key=\fItype\fR] +[\fB\-B\fR \fInbits\fR | \fB\-\^\-bits=\fInbits\fR] +[\fB\-D\fR \fIfile\fR | \fB\-\^\-dsaparam=\fIfile\fR] +[\fB\-b\fR | \fB\-\^\-batch\fR] +[\fB\-f\fR | \fB\-\^\-force\fR] +[\fB\-d\fR \fIdir\fR | \fB\-\^\-dir=\fR\fIdir\fR] +[\fB\-l\fR \fIfile\fR | \fB\-\^\-log=\fIfile\fR] +[\fB\-h\fR | \fB\-\^\-help\fR] +.br +Some options do not apply to every command. + +.SH DESCRIPTION +The \fBofp\-pki\fR program sets up and manages a public key +infrastructure for use with OpenFlow. It is intended to be a simple +interface for organizations that do not have an established public key +infrastructure. Other PKI tools can substitute for or supplement the +use of \fBofp\-pki\fR. + +\fBofp\-pki\fR uses \fBopenssl\fR(1) for certificate management and key +generation. + +.SH "OFFLINE COMMANDS" + +The following \fBofp\-pki\fR commands support manual PKI +administration: + +.TP +\fBinit\fR +Initializes a new PKI (by default in directory \fB@PKIDIR@\fR) and populates +it with a pair of certificate authorities for controllers and +switches. + +This command should ideally be run on a high\-security machine separate +from any OpenFlow controller or switch, called the CA machine. The +files \fBpki/controllerca/cacert.pem\fR and +\fBpki/switchca/cacert.pem\fR that it produces will need to be copied +over to the OpenFlow switches and controllers, respectively. Their +contents may safely be made public. + +By default, \fBofp\-pki\fR generates 2048\-bit RSA keys. The \fB\-B\fR +or \fB\-\^\-bits\fR option (see below) may be used to override the key +length. The \fB\-k dsa\fR or \fB\-\^\-key=dsa\fR option may be used to use +DSA in place of RSA. If DSA is selected, the \fBdsaparam.pem\fR file +generated in the new PKI hierarchy must be copied to any machine on +which the \fBreq\fR command (see below) will be executed. Its +contents may safely be made public. + +Other files generated by \fBinit\fR may remain on the CA machine. +The files \fBpki/controllerca/private/cakey.pem\fR and +\fBpki/switchca/private/cakey.pem\fR have particularly sensitive +contents that should not be exposed. + +.TP +\fBreq\fR \fINAME\fR +Generates a new private key named \fINAME\fR\fB\-privkey.pem\fR and +corresponding certificate request named \fINAME\fR\fB\-req.pem\fR. +The private key can be intended for use by a switch or a controller. + +This command should ideally be run on the switch or controller that +will use the private key to identify itself. The file +\fINAME\fR\fB\-req.pem\fR must be copied to the CA machine for signing +with the \fBsign\fR command (below). + +This command will output a fingerprint to stdout as its final step. +Write down the fingerprint and take it to the CA machine before +continuing with the \fBsign\fR step. + +When RSA keys are in use (as is the default), \fBreq\fR, unlike the +rest of \fBofp\-pki\fR's commands, does not need access to a PKI +hierarchy created by \fBofp\-pki init\fR. The \fB\-B\fR or +\fB\-\^\-bits\fR option (see below) may be used to specify the number of +bits in the generated RSA key. + +When DSA keys are used (as specified with \fB\-\^\-key=dsa\fR), \fBreq\fR +needs access to the \fBdsaparam.pem\fR file created as part of the PKI +hierarchy (but not to other files in that tree). By default, +\fBofp\-pki\fR looks for this file in \fB@PKIDIR@/dsaparam.pem\fR, but +the \fB\-D\fR or \fB\-\^\-dsaparam\fR option (see below) may be used to +specify an alternate location. + +\fINAME\fR\fB\-privkey.pem\fR has sensitive contents that should not be +exposed. \fINAME\fR\fB\-req.pem\fR may be safely made public. + +.TP +\fBsign\fR \fINAME\fR [\fITYPE\fR] +Signs the certificate request named \fINAME\fR\fB\-req.pem\fR that was +produced in the previous step, producing a certificate named +\fINAME\fR\fB\-cert.pem\fR. \fITYPE\fR, either \fBswitch\fR (default) or +\fBcontroller\fR, indicates the use for which the key is being +certified. + +This command must be run on the CA machine. + +The command will output a fingerprint to stdout and request that you +verify that it is the same fingerprint output by the \fBreq\fR +command. This ensures that the request being signed is the same one +produced by \fBreq\fR. (The \fB\-b\fR or \fB\-\^\-batch\fR option +suppresses the verification step.) + +The file \fINAME\fR\fB\-cert.pem\fR will need to be copied back to the +switch or controller for which it is intended. Its contents may +safely be made public. + +.TP +\fBreq+sign\fR \fINAME\fR [\fITYPE\fR] +Combines the \fBreq\fR and \fBsign\fR commands into a single step, +outputting all the files produced by each. The +\fINAME\fR\fB\-privkey.pem\fR and \fINAME\fR\fB\-cert.pem\fR files must +be copied securely to the switch or controller. +\fINAME\fR\fB\-privkey.pem\fR has sensitive contents and must not be +exposed in transit. Afterward, it should be deleted from the CA +machine. + +This combined method is, theoretically, less secure than the +individual steps performed separately on two different machines, +because there is additional potential for exposure of the private +key. However, it is also more convenient. + +.TP +\fBverify\fR \fINAME\fR [\fITYPE\fR] +Verifies that \fINAME\fR\fB\-cert.pem\fR is a valid certificate for the +given \fITYPE\fR of use, either \fBswitch\fR (default) or +\fBcontroller\fR. If the certificate is valid for this use, it prints +the message ``\fINAME\fR\fB\-cert.pem\fR: OK''; otherwise, it prints an +error message. + +.TP +\fBfingerprint\fR \fIFILE\fR +Prints the fingerprint for \fIFILE\fR. If \fIFILE\fR is a +certificate, then this is the SHA\-1 digest of the DER encoded version +of the certificate; otherwise, it is the SHA\-1 digest of the entire +file. + +.TP +\fBself-sign\fR \fINAME\fR +Signs the certificate request named \fINAME\fB\-req.pem\fR using the +private key \fINAME\fB-privkey.pem\fR, producing a self-signed +certificate named \fINAMEfB\-cert.pem\fR. The input files should have +been produced with \fBofp\-pki req\fR. + +Some controllers accept such self-signed certificates. + +.SH "ONLINE COMMANDS" + +An OpenFlow PKI can be administered online, in conjunction with +.BR ofp\-pki\-cgi (8) +and a web server such as Apache: + +.IP \(bu +The web server exports the contents of the PKI via HTTP. All files in +a PKI hierarchy files may be made public, except for the files +\fBpki/controllerca/private/cakey.pem\fR and +\fBpki/switchca/private/cakey.pem\fR, which must not be exposed. + +.IP \(bu +\fBofp\-pki\-cgi\fR allows newly generated certificate requests for +controllers and switches to be uploaded into the +\fBpki/controllerca/incoming\fR and \fBpki/switchca/incoming\fR +directories, respectively. Uploaded certificate requests are stored +in those directories under names of the form +\fIFINGERPRINT\fB\-req.pem\fR, which \fIFINGERPRINT\fR is the SHA\-1 +hash of the file. + +.IP \(bu +These \fBofp\-pki\fR commands allow incoming certificate requests to +be approved or rejected, in a form are suitable for use by humans or +other software. + +.PP +The following \fBofp\-pki\fR commands support online administration: + +.TP +\fBofp\-pki\fR \fBls\fR [\fIPREFIX\fR] [\fITYPE\fR] +Lists all of the incoming certificate requests of the given \fITYPE\fR +(either \fBswitch\fR, the default, or \fBcontroller\fR). If +\fIPREFIX\fR, which must be at least 4 characters long, is specified, +it causes the list to be limited to files whose names begin with +\fIPREFIX\fR. This is useful, for example, to avoid typing in an +entire fingerprint when checking that a specific certificate request +has been received. + +.TP +\fBofp\-pki\fR \fBflush\fR [\fITYPE\fR] +Deletes all certificate requests of the given \fITYPE\fR. + +.TP +\fBofp\-pki\fR \fBreject\fR \fIPREFIX\fR [\fITYPE\fR] +Rejects the certificate request whose name begins with \fIPREFIX\fR, +which must be at least 4 characters long, of the given type (either +\fBswitch\fR, the default, or \fBcontroller\fR). \fIPREFIX\fR must +match exactly one certificate request; its purpose is to allow the +user to type fewer characters, not to match multiple certificate +requests. + +.TP +\fBofp\-pki\fR \fBapprove\fR \fIPREFIX\fR [\fITYPE\fR] +Approves the certificate request whose name begins with \fIPREFIX\fR, +which must be at least 4 characters long, of the given \fITYPE\fR +(either \fBswitch\fR, the default, or \fBcontroller\fR). \fIPREFIX\fR +must match exactly one certificate request; its purpose is to allow +the user to type fewer characters, not to match multiple certificate +requests. + +The command will output a fingerprint to stdout and request that you +verify that it is correct. (The \fB\-b\fR or \fB\-\^\-batch\fR option +suppresses the verification step.) + +.TP +\fBofp\-pki\fR \fBprompt\fR [\fITYPE\fR] +Prompts the user for each incoming certificate request of the given +\fITYPE\fR (either \fBswitch\fR, the default, or \fBcontroller\fR). +Based on the certificate request's fingerprint, the user is given the +option of approving, rejecting, or skipping the certificate request. + +.TP +\fBofp\-pki\fR \fBexpire\fR [\fIAGE\fR] + +Rejects all the incoming certificate requests, of either type, that is +older than \fIAGE\fR, which must in one of the forms \fIN\fBs\fR, +\fIN\fBmin\fR, \fIN\fBh\fR, \fIN\fBday\fR. The default is \fB1day\fR. + +.SH OPTIONS +.TP +\fB\-k\fR \fItype\fR | \fB\-\^\-key=\fItype\fR +For the \fBinit\fR command, sets the public key algorithm to use for +the new PKI hierarchy. For the \fBreq\fR and \fBreq+sign\fR commands, +sets the public key algorithm to use for the key to be generated, +which must match the value specified on \fBinit\fR. With other +commands, the value has no effect. + +The \fItype\fR may be \fBrsa\fR (the default) or \fBdsa\fR. + +.TP +\fB\-B\fR \fInbits\fR | \fB\-\^\-bits=\fInbits\fR +Sets the number of bits in the key to be generated. When RSA keys are +in use, this option affects only the \fBinit\fR, \fBreq\fR, and +\fBreq+sign\fR commands, and the same value should be given each time. +With DSA keys are in use, this option affects only the \fBinit\fR +command. + +The value must be at least 1024. The default is 2048. + +.TP +\fB\-D\fR \fIfile\fR | \fB\-\^\-dsaparam=\fIfile\fR +Specifies an alternate location for the \fBdsaparam.pem\fR file +required by the \fBreq\fR and \fBreq+sign\fR commands. This option +affects only these commands, and only when DSA keys are used. + +The default is \fBdsaparam.pem\fR under the PKI hierarchy. + +.TP +\fB\-b\fR | \fB\-\^\-batch\fR +Suppresses the interactive verification of fingerprints that the +\fBsign\fR and \fBapprove\fR commands by default require. + +.TP +\fB\-d\fR \fIdir\fR | \fB\-\^\-dir=\fR\fIdir\fR +Specifies the location of the PKI hierarchy to be used or created by +the command (default: \fB@PKIDIR@\fR). All commands, except \fBreq\fR, +need access to a PKI hierarchy. + +.TP +\fB\-f\fR | \fB\-\^\-force\fR +By default, \fBofp\-pki\fR will not overwrite existing files or +directories. This option overrides this behavior. + +.TP +\fB\-l\fR \fIfile\fR | \fB\-\^\-log=\fIfile\fR +Sets the log file to \fIfile\fR. Default: +\fB@LOGDIR@/ofp\-pki.log\fR. + +.TP +\fB\-h\fR | \fB\-\^\-help\fR +Prints a help usage message and exits. + +.SH "SEE ALSO" + +.BR controller (8), +.BR dpctl (8), +.BR ofp\-pki\-cgi (8), +.BR ofprotocol (8), +.BR ofdatapath (8) diff --git a/openflow/utilities/ofp-pki.in b/openflow/utilities/ofp-pki.in new file mode 100755 index 00000000..3a50cff8 --- /dev/null +++ b/openflow/utilities/ofp-pki.in @@ -0,0 +1,582 @@ +#! /bin/sh + +set -e + +pkidir='@PKIDIR@' +command= +prev= +force=no +batch=no +log='@LOGDIR@/ofp-pki.log' +keytype=rsa +bits=2048 +for option; do + # This option-parsing mechanism borrowed from a Autoconf-generated + # configure script under the following license: + + # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, + # 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + # This configure script is free software; the Free Software Foundation + # gives unlimited permission to copy, distribute and modify it. + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + eval $prev=\$option + prev= + continue + fi + case $option in + *=*) optarg=`expr "X$option" : '[^=]*=\(.*\)'` ;; + *) optarg=yes ;; + esac + + case $dashdash$option in + --) + dashdash=yes ;; + -h|--help) + cat <&2 + exit 1 + ;; + *) + if test -z "$command"; then + command=$option + elif test -z "${arg1+set}"; then + arg1=$option + elif test -z "${arg2+set}"; then + arg2=$option + else + echo "$option: only two arguments may be specified" >&2 + exit 1 + fi + ;; + esac + shift +done +if test -n "$prev"; then + option=--`echo $prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $option" >&2 + { (exit 1); exit 1; }; } +fi +if test -z "$command"; then + echo "$0: missing command name; use --help for help" >&2 + exit 1 +fi +if test "$keytype" != rsa && test "$keytype" != dsa; then + echo "$0: argument to -k or --key must be rsa or dsa" + exit 1 +fi +if test "$bits" -lt 1024; then + echo "$0: argument to -B or --bits must be at least 1024" + exit 1 +fi +if test -z "$dsaparam"; then + dsaparam=$pkidir/dsaparam.pem +fi +case $log in + /*) ;; + *) $log="$PWD/$log" ;; +esac + +if test "$command" = "init"; then + if test -e "$pkidir" && test "$force" != "yes"; then + echo "$0: $pkidir already exists and --force not specified" >&2 + exit 1 + fi + + if test ! -d "$pkidir"; then + mkdir -p "$pkidir" + fi + cd "$pkidir" + exec 3>>$log + + if test $keytype = dsa && test ! -e dsaparam.pem; then + echo "Generating DSA parameters, please wait..." >&2 + openssl dsaparam -out dsaparam.pem $bits 1>&3 2>&3 + fi + + # Create the CAs. + for ca in controllerca switchca; do + echo "Creating $ca..." >&2 + oldpwd=$PWD + mkdir -p $ca + cd $ca + + mkdir -p certs crl newcerts + mkdir -p -m 0700 private + mkdir -p -m 0733 incoming + touch index.txt + test -e crlnumber || echo 01 > crlnumber + test -e serial || echo 01 > serial + + # Put DSA parameters in directory. + if test $keytype = dsa && test ! -e dsaparam.pem; then + cp ../dsaparam.pem . + fi + + # Write CA configuration file. + if test ! -e ca.cnf; then + sed "s/@ca@/$ca/g" > ca.cnf <<'EOF' +[ req ] +prompt = no +distinguished_name = req_distinguished_name + +[ req_distinguished_name ] +C = US +ST = CA +L = Palo Alto +O = OpenFlow +OU = @ca@ +CN = OpenFlow @ca@ CA Certificate + +[ ca ] +default_ca = the_ca + +[ the_ca ] +dir = . # top dir +database = $dir/index.txt # index file. +new_certs_dir = $dir/newcerts # new certs dir +certificate = $dir/cacert.pem # The CA cert +serial = $dir/serial # serial no file +private_key = $dir/private/cakey.pem# CA private key +RANDFILE = $dir/private/.rand # random number file +default_days = 365 # how long to certify for +default_crl_days= 30 # how long before next CRL +default_md = md5 # md to use +policy = policy # default policy +email_in_dn = no # Don't add the email into cert DN +name_opt = ca_default # Subject name display option +cert_opt = ca_default # Certificate display option +copy_extensions = none # Don't copy extensions from request + +# For the CA policy +[ policy ] +countryName = optional +stateOrProvinceName = optional +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional +EOF + fi + + # Create certificate authority. + if test $keytype = dsa; then + newkey=dsa:dsaparam.pem + else + newkey=rsa:$bits + fi + openssl req -config ca.cnf -nodes \ + -newkey $newkey -keyout private/cakey.pem -out careq.pem \ + 1>&3 2>&3 + openssl ca -config ca.cnf -create_serial -out cacert.pem \ + -days 1095 -batch -keyfile private/cakey.pem -selfsign \ + -infiles careq.pem 1>&3 2>&3 + chmod 0700 private/cakey.pem + + cd "$oldpwd" + done + exit 0 +fi + +one_arg() { + if test -z "$arg1" || test -n "$arg2"; then + echo "$0: $command must have exactly one argument; use --help for help" >&2 + exit 1 + fi +} + +zero_or_one_args() { + if test -n "$arg2"; then + echo "$0: $command must have zero or one arguments; use --help for help" >&2 + exit 1 + fi +} + +one_or_two_args() { + if test -z "$arg1"; then + echo "$0: $command must have one or two arguments; use --help for help" >&2 + exit 1 + fi +} + +must_not_exist() { + if test -e "$1" && test "$force" != "yes"; then + echo "$0: $1 already exists and --force not supplied" >&2 + exit 1 + fi +} + +resolve_prefix() { + test -n "$type" || exit 123 # Forgot to call check_type? + + case $1 in + ????*) + ;; + *) + echo "Prefix $arg1 is too short (less than 4 hex digits)" + exit 0 + ;; + esac + + fingerprint=$(cd "$pkidir/${type}ca/incoming" && echo "$1"*-req.pem | sed 's/-req\.pem$//') + case $fingerprint in + "${1}*") + echo "No certificate requests matching $1" + exit 1 + ;; + *" "*) + echo "$1 matches more than one certificate request:" + echo $fingerprint | sed 's/ /\ +/g' + exit 1 + ;; + *) + # Nothing to do. + ;; + esac + req="$pkidir/${type}ca/incoming/$fingerprint-req.pem" + cert="$pkidir/${type}ca/certs/$fingerprint-cert.pem" +} + +make_tmpdir() { + TMP=/tmp/ofp-pki.tmp$$ + rm -rf $TMP + trap "rm -rf $TMP" 0 + mkdir -m 0700 $TMP +} + +fingerprint() { + local file=$1 + local name=${1-$2} + local date=$(date -r $file) + local fingerprint + if grep -q -e '-BEGIN CERTIFICATE-' "$file"; then + fingerprint=$(openssl x509 -noout -in "$file" -fingerprint | + sed 's/SHA1 Fingerprint=//' | tr -d ':') + else + fingerprint=$(sha1sum "$file" | awk '{print $1}') + fi + printf "$name\\t$date\\n" + case $file in + $fingerprint*) + printf "\\t(correct fingerprint in filename)\\n" + ;; + *) + printf "\\tfingerprint $fingerprint\\n" + ;; + esac +} + +verify_fingerprint() { + fingerprint "$@" + if test $batch != yes; then + echo "Does fingerprint match? (yes/no)" + read answer + if test "$answer" != yes; then + echo "Match failure, aborting" >&2 + exit 1 + fi + fi +} + +check_type() { + if test x = x"$1"; then + type=switch + elif test "$1" = switch || test "$1" = controller; then + type=$1 + else + echo "$0: type argument must be 'switch' or 'controller'" >&2 + exit 1 + fi +} + +parse_age() { + number=$(echo $1 | sed 's/^\([0-9]\+\)\([[:alpha:]]\+\)/\1/') + unit=$(echo $1 | sed 's/^\([0-9]\+\)\([[:alpha:]]\+\)/\2/') + case $unit in + s) + factor=1 + ;; + min) + factor=60 + ;; + h) + factor=3600 + ;; + day) + factor=86400 + ;; + *) + echo "$1: age not in the form Ns, Nmin, Nh, Nday (e.g. 1day)" >&2 + exit 1 + ;; + esac + echo $(($number * $factor)) +} + +must_exist() { + if test ! -e "$1"; then + echo "$0: $1 does not exist" >&2 + exit 1 + fi +} + +pkidir_must_exist() { + if test ! -e "$pkidir"; then + echo "$0: $pkidir does not exist (need to run 'init' or use '--dir'?)" >&2 + exit 1 + elif test ! -d "$pkidir"; then + echo "$0: $pkidir is not a directory" >&2 + exit 1 + fi +} + +make_request() { + must_not_exist "$arg1-privkey.pem" + must_not_exist "$arg1-req.pem" + make_tmpdir + cat > "$TMP/req.cnf" <&3 2>&3 +} + +sign_request() { + must_exist "$1" + must_not_exist "$2" + pkidir_must_exist + + (cd "$pkidir/${type}ca" && + openssl ca -config ca.cnf -batch -in /dev/stdin) \ + < "$1" > "$2.tmp$$" 2>&3 + mv "$2.tmp$$" "$2" +} + +glob() { + local files=$(echo $1) + if test "$files" != "$1"; then + echo "$files" + fi +} + +exec 3>>$log || true +if test "$command" = req; then + one_arg + + make_request "$arg1" + fingerprint "$arg1-req.pem" +elif test "$command" = sign; then + one_or_two_args + check_type "$arg2" + verify_fingerprint "$arg1-req.pem" + + sign_request "$arg1-req.pem" "$arg2-cert.pem" +elif test "$command" = req+sign; then + one_or_two_args + check_type "$arg2" + + pkidir_must_exist + make_request "$arg1" + sign_request "$arg1-req.pem" "$arg1-cert.pem" + fingerprint "$arg1-req.pem" +elif test "$command" = verify; then + one_or_two_args + must_exist "$arg1-cert.pem" + check_type "$arg2" + + pkidir_must_exist + openssl verify -CAfile "$pkidir/${type}ca/cacert.pem" "$arg1-cert.pem" +elif test "$command" = fingerprint; then + one_arg + + fingerprint "$arg1" +elif test "$command" = self-sign; then + one_arg + must_exist "$arg1-req.pem" + must_exist "$arg1-privkey.pem" + must_not_exist "$arg1-cert.pem" + + openssl x509 -in "$arg1-req.pem" -out "$arg1-cert.pem" \ + -signkey "$arg1-privkey.pem" -req -text 2>&3 +elif test "$command" = ls; then + check_type "$arg2" + + cd "$pkidir/${type}ca/incoming" + for file in $(glob "$arg1*-req.pem"); do + fingerprint $file + done +elif test "$command" = flush; then + check_type "$arg1" + + rm -f "$pkidir/${type}ca/incoming/"* +elif test "$command" = reject; then + one_or_two_args + check_type "$arg2" + resolve_prefix "$arg1" + + rm -f "$req" +elif test "$command" = approve; then + one_or_two_args + check_type "$arg2" + resolve_prefix "$arg1" + + make_tmpdir + cp "$req" "$TMP/$req" + verify_fingerprint "$TMP/$req" + sign_request "$TMP/$req" + rm -f "$req" "$TMP/$req" +elif test "$command" = prompt; then + zero_or_one_args + check_type "$arg1" + + make_tmpdir + cd "$pkidir/${type}ca/incoming" + for req in $(glob "*-req.pem"); do + cp "$req" "$TMP/$req" + + cert=$(echo "$pkidir/${type}ca/certs/$req" | + sed 's/-req.pem/-cert.pem/') + if test -f $cert; then + echo "Request $req already approved--dropping duplicate request" + rm -f "$req" "$TMP/$req" + continue + fi + + echo + echo + fingerprint "$TMP/$req" "$req" + printf "Disposition for this request (skip/approve/reject)? " + read answer + case $answer in + approve) + echo "Approving $req" + sign_request "$TMP/$req" "$cert" + rm -f "$req" "$TMP/$req" + ;; + r*) + echo "Rejecting $req" + rm -f "$req" "$TMP/$req" + ;; + *) + echo "Skipping $req" + ;; + esac + done +elif test "$command" = expire; then + zero_or_one_args + cutoff=$(($(date +%s) - $(parse_age ${arg1-1day}))) + for type in switch controller; do + cd "$pkidir/${type}ca/incoming" || exit 1 + for file in $(glob "*"); do + time=$(date -r "$file" +%s) + if test "$time" -lt "$cutoff"; then + rm -f "$file" + fi + done + done +else + echo "$0: $command command unknown; use --help for help" >&2 + exit 1 +fi diff --git a/openflow/utilities/vlogconf.8.in b/openflow/utilities/vlogconf.8.in new file mode 100644 index 00000000..eb9c192e --- /dev/null +++ b/openflow/utilities/vlogconf.8.in @@ -0,0 +1,183 @@ +.ds PN vlogconf + +.TH vlogconf 8 "June 2008" "OpenFlow" "OpenFlow Manual" + +.SH NAME +vlogconf \- configuration utility for OpenFlow logging in userspace + +.SH SYNOPSIS +\fBvlogconf\fR [\fB-h\fR | \fB--help\fR] [\fItarget\fR...] [\fIaction\fR...] +.sp 1 +The available \fItarget\fR options are: +.br +[\fB-a\fR | \fB--all\fR] [\fB-t\fR \fIpid\fR | \fB--target=\fIpid\fR] +.sp 1 +The available \fIaction\fR options are: +.br +[\fB-l\fR | \fB--list\fR] [\fB-s\fR +\fImodule\fR[\fB:\fIfacility\fR[\fB:\fIlevel\fR]] | +\fB--set=\fImodule\fR[\fB:\fIfacility\fR[\fB:\fIlevel\fR]]] +[\fB-r\fR | \fB--reopen\fR] + +.SH DESCRIPTION +The \fBvlogconf\fR program configures the logging system used by +OpenFlow userspace programs. The logging configuration may be modified +while OpenFlow programs are running. + +\fBvlogconf\fR applies one or more actions to each of one or more +target processes. Targets may be specified as: + +.TP +\fB-a\fR, \fB--all\fR +All running processes that \fBvlogconf\fR can control. + +.TP +\fB-t \fItarget\fR, \fB--target=\fItarget\fR +The specified \fItarget\fR, which must take one of the following forms: + +.RS +.IP \(bu +A PID (process ID). + +.IP \(bu +An absolute path (beginning with `/') to the Unix domain socket for a +\fBvlogconf\fR-controllable process. + +.IP \(bu +An absolute path (beginning with `/') to a pidfile (created by, e.g., +passing the \fB-P\fR or \fB--pidfile\fR option to one of the OpenFlow +programs). + +.IP \(bu +None of the above, in which case \fItarget\fR prefixed by +\fB@RUNDIR@/\fR must match one of the cases for absolute paths listed +above. (The default name for a program's pidfile is +\fB@RUNDIR@/\fIprogram\fB.pid\fR, so this means that, say, +\fBofprotocol\fR's default pidfile may be referred to simply as +\fBofprotocol.pid\fR.) +.RE + +.PP +The available actions are: + +.TP +\fB-l\fR, \fB--list\fR +Print the list of known modules and their current logging levels to +stdout. + +.TP +\fB-s\fR \fImodule\fR[\fB:\fIfacility\fR[\fB:\fIlevel\fR]], \fB--set=\fImodule\fR[\fB:\fIfacility\fR[\fB:\fIlevel\fR]] + +Sets the logging level for \fImodule\fR in \fIfacility\fR to +\fIlevel\fR. The \fImodule\fR may be any valid module name (as +displayed by the \fB--list\fR option) or the special name \fBANY\fR to +set the logging levels for all modules. The \fIfacility\fR may be +\fBsyslog\fR or \fBconsole\fR to set the levels for logging to the +system log or to the console, respectively, or \fBANY\fR to set the +logging levels for both facilities. If it is omitted, +\fIfacility\fR defaults to \fBANY\fR. The \fIlevel\fR must be one of +\fBemer\fR, \fBerr\fR, \fBwarn\fR, \fBinfo\fR, or \fBdbg\fR, designating the +minimum severity of a message for it to be logged. If it is omitted, +\fIlevel\fR defaults to \fBdbg\fR. + +.TP +\fB-s PATTERN:\fIfacility\fB:\fIpattern\fR, \fB--set=PATTERN:\fIfacility\fB:\fIpattern\fR + +Sets the log pattern for \fIfacility\fR to \fIpattern\fR. Each time a +message is logged to \fIfacility\fR, \fIpattern\fR determines the +message's formatting. Most characters in \fIpattern\fR are copied +literally to the log, but special escapes beginning with \fB%\fR are +expanded as follows: + +.RS +.TP +\fB%A\fR +The name of the application logging the message, e.g. \fBofprotocol\fR. + +.TP +\fB%c\fR +The name of the module (as shown by \fBvlogconf --list\fR) logging +the message. + +.TP +\fB%d\fR +The current date and time in ISO 8601 format (YYYY-MM-DD HH:MM:SS). + +.TP +\fB%d{\fIformat\fB}\fR +The current date and time in the specified \fIformat\fR, which takes +the same format as the \fItemplate\fR argument to \fBstrftime\fR(3). + +.TP +\fB%m\fR +The message being logged. + +.TP +\fB%N\fR +A serial number for this message within this run of the program, as a +decimal number. The first message a program logs has serial number 1, +the second one has serial number 2, and so on. + +.TP +\fB%n\fR +A new-line. + +.TP +\fB%p\fR +The level at which the message is logged, e.g. \fBDBG\fR. + +.TP +\fB%P\fR +The program's process ID (pid), as a decimal number. + +.TP +\fB%r\fR +The number of milliseconds elapsed from the start of the application +to the time the message was logged. + +.TP +\fB%%\fR +A literal \fB%\fR. +.RE + +.IP +A few options may appear between the \fB%\fR and the format specifier +character, in this order: + +.RS +.TP +\fB-\fR +Left justify the escape's expansion within its field width. Right +justification is the default. + +.TP +\fB0\fR +Pad the field to the field width with \fB0\fRs. Padding with spaces +is the default. + +.TP +\fIwidth\fR +A number specifies the minimum field width. If the escape expands to +fewer characters than \fIwidth\fR then it is padded to fill the field +width. (A field wider than \fIwidth\fR is not truncated to fit.) +.RE + +.IP +The default pattern for console output is \fB%d{%b %d +%H:%M:%S}|%05N|%c|%p|%m\fR; for syslog output, \fB%05N|%c|%p|%m\fR. + +.TP +\fB-r\fR, \fB--reopen\fR +Causes the target application to close and reopen its log file. (This +is useful after rotating log files, to cause a new log file to be +used.) + +.SH OPTIONS + +.so lib/common.man + +.SH "SEE ALSO" + +.BR dpctl (8), +.BR ofprotocol (8), +.BR controller (8) diff --git a/openflow/utilities/vlogconf.c b/openflow/utilities/vlogconf.c new file mode 100644 index 00000000..5c48f724 --- /dev/null +++ b/openflow/utilities/vlogconf.c @@ -0,0 +1,235 @@ +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ +#include +#include "vlog.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "command-line.h" +#include "compiler.h" +#include "timeval.h" +#include "util.h" +#include "vlog-socket.h" + +static void +usage(char *prog_name, int exit_code) +{ + printf("Usage: %s [TARGET] [ACTION...]\n" + "Targets:\n" + " -a, --all Apply to all targets (default)\n" + " -t, --target=TARGET Specify target program, as a pid, a\n" + " pidfile, or an absolute path to a Unix\n" + " domain socket\n" + "Actions:\n" + " -l, --list List current settings\n" + " -s, --set=MODULE[:FACILITY[:LEVEL]]\n" + " Set MODULE and FACILITY log level to LEVEL\n" + " MODULE may be any valid module name or 'ANY'\n" + " FACILITY may be 'syslog', 'console', 'file', or 'ANY' (default)\n" + " LEVEL may be 'emer', 'err', 'warn', 'info', or 'dbg' (default)\n" + " -r, --reopen Make the program reopen its log file\n" + " -h, --help Print this helpful information\n", + prog_name); + exit(exit_code); +} + +static char * +transact(struct vlog_client *client, const char *request, bool *ok) +{ + char *reply; + int error = vlog_client_transact(client, request, &reply); + if (error) { + fprintf(stderr, "%s: transaction error: %s\n", + vlog_client_target(client), strerror(error)); + *ok = false; + } + return reply ? reply : xstrdup(""); +} + +static void +transact_ack(struct vlog_client *client, const char* request, bool *ok) +{ + char *reply; + int error = vlog_client_transact(client, request, &reply); + if (error) { + fprintf(stderr, "%s: transaction error: %s\n", + vlog_client_target(client), strerror(error)); + *ok = false; + } else if (strcmp(reply, "ack")) { + fprintf(stderr, "Received unexpected reply from %s: %s\n", + vlog_client_target(client), reply); + *ok = false; + } + free(reply); +} + +static void +add_target(struct vlog_client ***clients, size_t *n_clients, + const char *path, bool *ok) +{ + struct vlog_client *client; + int error = vlog_client_connect(path, &client); + if (error) { + fprintf(stderr, "Error connecting to \"%s\": %s\n", + path, strerror(error)); + *ok = false; + } else { + *clients = xrealloc(*clients, sizeof *clients * (*n_clients + 1)); + (*clients)[*n_clients] = client; + ++*n_clients; + } +} + +static void +add_all_targets(struct vlog_client ***clients, size_t *n_clients, bool *ok) +{ + DIR *directory; + struct dirent* de; + + directory = opendir("/tmp"); + if (!directory) { + fprintf(stderr, "/tmp: opendir: %s\n", strerror(errno)); + } + + while ((de = readdir(directory)) != NULL) { + if (!strncmp(de->d_name, "vlogs.", 5)) { + char *path = xasprintf("/tmp/%s", de->d_name); + add_target(clients, n_clients, path, ok); + free(path); + } + } + + closedir(directory); +} + +int main(int argc, char *argv[]) +{ + static const struct option long_options[] = { + /* Target options must come first. */ + {"all", no_argument, NULL, 'a'}, + {"target", required_argument, NULL, 't'}, + {"help", no_argument, NULL, 'h'}, + + /* Action options come afterward. */ + {"list", no_argument, NULL, 'l'}, + {"set", required_argument, NULL, 's'}, + {"reopen", no_argument, NULL, 'r'}, + {0, 0, 0, 0}, + }; + char *short_options; + + /* Determine targets. */ + bool ok = true; + int n_actions = 0; + struct vlog_client **clients = NULL; + size_t n_clients = 0; + + set_program_name(argv[0]); + time_init(); + + short_options = long_options_to_short_options(long_options); + for (;;) { + int option; + size_t i; + + option = getopt_long(argc, argv, short_options, long_options, NULL); + if (option == -1) { + break; + } + if (!strchr("ath", option) && n_clients == 0) { + ofp_fatal(0, "no targets specified (use --help for help)"); + } else { + ++n_actions; + } + switch (option) { + case 'a': + add_all_targets(&clients, &n_clients, &ok); + break; + + case 't': + add_target(&clients, &n_clients, optarg, &ok); + break; + + case 'l': + for (i = 0; i < n_clients; i++) { + struct vlog_client *client = clients[i]; + char *reply; + + printf("%s:\n", vlog_client_target(client)); + reply = transact(client, "list", &ok); + fputs(reply, stdout); + free(reply); + } + break; + + case 's': + for (i = 0; i < n_clients; i++) { + struct vlog_client *client = clients[i]; + char *request = xasprintf("set %s", optarg); + transact_ack(client, request, &ok); + free(request); + } + break; + + case 'r': + for (i = 0; i < n_clients; i++) { + struct vlog_client *client = clients[i]; + char *request = xstrdup("reopen"); + transact_ack(client, request, &ok); + free(request); + } + break; + + case 'h': + usage(argv[0], EXIT_SUCCESS); + break; + + case '?': + exit(EXIT_FAILURE); + + default: + NOT_REACHED(); + } + } + if (!n_actions) { + fprintf(stderr, + "warning: no actions specified (use --help for help)\n"); + } + exit(ok ? 0 : 1); +} diff --git a/openflow/utilities/wireshark_dissectors/Makefile b/openflow/utilities/wireshark_dissectors/Makefile new file mode 100644 index 00000000..cf82d045 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/Makefile @@ -0,0 +1,32 @@ +# simple Makefile to build and install all of our Wireshark plugins + +# build a list of all sub-directories except the includes path +PLUGIN_DIRS = $(shell ls -l | grep "^d" | cut -d: -f2- | cut -d\ -f2 | fgrep -v 'wireshark-1.0.0-includes') +CLEAN_PLUGIN_DIRS = $(foreach dir,$(PLUGIN_DIRS),clean$(dir)) +INSTALL_PLUGIN_DIRS = $(foreach dir,$(PLUGIN_DIRS),install$(dir)) + +.PHONY: all $(PLUGIN_DIRS) clean $(CLEAN_PLUGIN_DIRS) install $(INSTALL_PLUGIN_DIRS) + +# build all the plugins +all: + @$(MAKE) --no-print-directory $(PLUGIN_DIRS) + +# cleanup all the byproducts (including the plugin itself) +clean: + @$(MAKE) --no-print-directory $(CLEAN_PLUGIN_DIRS) + +# install all plugins +install: + @$(MAKE) --no-print-directory $(INSTALL_PLUGIN_DIRS) + +# build the plugin in the specified directory using its default rule +$(PLUGIN_DIRS): + @$(MAKE) --no-print-directory -C $@ + +# cleans up the plugin in the specified directory using its 'clean' rule +$(CLEAN_PLUGIN_DIRS): + @$(MAKE) --no-print-directory -C `echo $@ | sed -e "s#^clean##"` clean + +# installs up the plugin in the specified directory using its 'install' rule +$(INSTALL_PLUGIN_DIRS): + @$(MAKE) --no-print-directory -C `echo $@ | sed -e "s#^install##"` install diff --git a/openflow/utilities/wireshark_dissectors/README b/openflow/utilities/wireshark_dissectors/README new file mode 100644 index 00000000..0aac13dd --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/README @@ -0,0 +1,37 @@ +README: OpenFlow Wireshark Plugin + + + +---------------------------------------- +I) Installation + +1) Install glib-devel; on Debian this can be done with 'sudo apt-get install libgtk2.0-dev' +2) Install wireshark v1.0.0 or greater +3) cd wireshark_dissectors/openflow +4) make +5) sudo make install +5a) Note that this prints out where the plugin was installed. + + +---------------------------------------- +II) Installation Verification + +1) Run wireshark +2) Open the "Help" --> "About" menu +3) Select the "Plugins" tab +4) Click the "Name" header to the plugins by name +5) Verify that "packet-openflow.so" appears in the list. +6) Verify that its version is listed as . + + +---------------------------------------- +III) Port Changes + +To have the dissector handle OpenFlow packets for any port other than the default, you must change the DISSECT_PORT variable in utilities/wireshark_dissectors/oepnflow/Makefile. + +---------------------------------------- +IV) Feedback and Bug Reporting + +Please post a message on the OpenFlow forums at openflowswitch.org or email +David Underhill at dgu@cs.stanford.edu if you have any feedback or discover any +bugs. diff --git a/openflow/utilities/wireshark_dissectors/openflow/.gitignore b/openflow/utilities/wireshark_dissectors/openflow/.gitignore new file mode 100644 index 00000000..aa1ec1ea --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/openflow/.gitignore @@ -0,0 +1 @@ +*.tgz diff --git a/openflow/utilities/wireshark_dissectors/openflow/Makefile b/openflow/utilities/wireshark_dissectors/openflow/Makefile new file mode 100644 index 00000000..8c533ce9 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/openflow/Makefile @@ -0,0 +1,79 @@ +WIRESHARK_SRC_DIR = ../wireshark-1.0.0-includes + +SRCS = packet-openflow.c plugin.c +CC = gcc +OBJS = $(foreach src, $(SRCS), $(src:.c=.o)) + +PLUGIN_NAME = packet-openflow + +# local installation path +LOCAL_PLUGIN_DIR = /home/$(shell whoami)/.wireshark/plugins + +# determine global installation path (use latest plugin version path) +ifneq ($(wildcard /usr/local/lib/wireshark/plugins),) + GLOBAL_PLUGIN_DIR_PARTIAL=/usr/local/lib/wireshark/plugins +else ifneq ($(wildcard /usr/lib/wireshark/plugins),) + GLOBAL_PLUGIN_DIR_PARTIAL=/usr/lib/wireshark/plugins +endif + +# Work out if there are version-specific subdirectories +GLOBAL_PLUGIN_DIR_FILES := $(wildcard $(GLOBAL_PLUGIN_DIR_PARTIAL)/*) +GLOBAL_PLUGIN_DIR_SUBDIRS := $(foreach file,$(GLOBAL_PLUGIN_DIR_FILES),$(dir $(wildcard $(file)/.))) +GLOBAL_PLUGIN_DIR_SUBDIRS := $(subst $(GLOBAL_PLUGIN_DIR_PARTIAL)/,,$(GLOBAL_PLUGIN_DIR_SUBDIRS)) +GLOBAL_PLUGIN_DIR_SUBDIRS := $(subst /,,$(GLOBAL_PLUGIN_DIR_SUBDIRS)) + +# Assume that the "last" directory is the one we ant to use if it exists +GLOBAL_PLUGIN_VER := $(lastword $(sort $(GLOBAL_PLUGIN_DIR_SUBDIRS))) + +# Create the actual global plugin dir to use +ifneq ($(GLOBAL_PLUGIN_VER),) + GLOBAL_PLUGIN_DIR=$(GLOBAL_PLUGIN_DIR_PARTIAL)/$(GLOBAL_PLUGIN_VER) +else + GLOBAL_PLUGIN_DIR=$(GLOBAL_PLUGIN_DIR_PARTIAL) +endif + +# specify the port on which event capture packets will be destined +DISSECT_PORT = -DOPENFLOW_DST_TCP_PORT=6633 + +OSTYPE = $(shell uname) +ifeq ($(OSTYPE),Linux) +ENDIAN=-D_LITTLE_ENDIAN_ +endif +ifeq ($(OSTYPE),SunOS) +ENDIAN=-D_BIG_ENDIAN_ +endif + +INC_GLIB=$(shell pkg-config --cflags glib-2.0) +INC_OPENFLOW=../../../include + +INC_DIRS = -I. $(INC_GLIB) -I$(INC_OPENFLOW) +CFLAGS = $(INC_DIRS) -DHAVE_CONFIG_H -I$(WIRESHARK_SRC_DIR) -I/usr/local/include -I/usr/local/include -DINET6 -D_U_=__attribute__\(\(unused\)\) -Wall -Wpointer-arith -g -I/usr/local/include -DXTHREADS -D_REENTRANT -DXUSE_MTSAFE_API -pthread -I/usr/include/gtk-2.0 -I/usr/lib/gtk-2.0/include -I/usr/X11R6/include -I/usr/include/atk-1.0 -I/usr/include/pango-1.0 -I/usr/include/freetype2 -I/usr/include/freetype2/config -I/usr/local/include/glib-2.0 -I/usr/lib/glib-2.0/include -fPIC -DPIC $(ENDIAN) $(DISSECT_PORT) + +LDFLAGS = -Wl,--rpath -Wl,/usr/local/lib -Wl,--rpath -Wl,/usr/local/lib -L/usr/local/lib -L$(WIRESHARK_SRC_DIR)/epan -L. -lgmodule-2.0 -ldl -lglib-2.0 -pthread -Wl,--export-dynamic -Wl,-soname -Wl,$(PLUGIN_NAME).so + +.PHONY: clean install + +$(PLUGIN_NAME).so : $(OBJS) $(SRCS) + $(CC) -shared $(OBJS) $(LDFLAGS) -o $@ + +install: $(PLUGIN_NAME).so + @if [ `id -u` -eq 0 ]; then \ + if [ -d "$(GLOBAL_PLUGIN_DIR)" ]; then \ + target="$(GLOBAL_PLUGIN_DIR)/$<"; \ + res="*** Installed plugin for ALL users ($$target)"; \ + else \ + echo "*** Error: global plugin directory $(GLOBAL_PLUGIN_DIR) does not exist"; \ + exit 1; \ + fi; \ + else \ + mkdir -p "$(LOCAL_PLUGIN_DIR)/"; \ + target="$(LOCAL_PLUGIN_DIR)/$<"; \ + res="*** Installed plugin for user "`id | cut -d\( -f2 | cut -d\) -f1`" ($$target)"; \ + fi; \ + install --mode=644 $< "$$target" && echo "" && echo "" && echo "$$res" && echo "" && echo "" + +plugin.c: moduleinfo.h Makefile.am Makefile.common + $(MAKE) -f Makefile.am + +clean: + rm -f $(PLUGIN) $(OBJS) $(PLUGIN_NAME).so diff --git a/openflow/utilities/wireshark_dissectors/openflow/Makefile.am b/openflow/utilities/wireshark_dissectors/openflow/Makefile.am new file mode 100644 index 00000000..be972bd8 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/openflow/Makefile.am @@ -0,0 +1,110 @@ +# Makefile.am +# Automake file for H.223 plugin +# +# $Id: Makefile.am 21961 2007-05-27 18:35:55Z guy $ +# +# Wireshark - Network traffic analyzer +# By Gerald Combs +# Copyright 1998 Gerald Combs + +srcdir = . +top_srcdir = ../wireshark-1.0.0-includes +includedir = ../wireshark-1.0.0-includes +INCLUDES = -I$(top_srcdir) -I$(includedir) + +include Makefile.common + +#if HAVE_WARNINGS_AS_ERRORS +#AM_CFLAGS = -Werror +#endif + +plugindir = ~/.wireshark/plugins + +plugin_LTLIBRARIES = hsapi.la +hsapi_la_SOURCES = \ + plugin.c \ + moduleinfo.h \ + $(DISSECTOR_SRC) \ + $(DISSECTOR_SUPPORT_SRC) \ + $(DISSECTOR_INCLUDES) +openflow_la_LDFLAGS = -module -avoid-version +openflow_la_LIBADD = @PLUGIN_LIBS@ + +# Libs must be cleared, or else libtool won't create a shared module. +# If your module needs to be linked against any particular libraries, +# add them here. +LIBS = + +# +# Build plugin.c, which contains the plugin version[] string, a +# function plugin_register() that calls the register routines for all +# protocols, and a function plugin_reg_handoff() that calls the handoff +# registration routines for all protocols. +# +# We do this by scanning sources. If that turns out to be too slow, +# maybe we could just require every .o file to have an register routine +# of a given name (packet-aarp.o -> proto_register_aarp, etc.). +# +# Formatting conventions: The name of the proto_register_* routines an +# proto_reg_handoff_* routines must start in column zero, or must be +# preceded only by "void " starting in column zero, and must not be +# inside #if. +# +# DISSECTOR_SRC is assumed to have all the files that need to be scanned. +# +# For some unknown reason, having a big "for" loop in the Makefile +# to scan all the files doesn't work with some "make"s; they seem to +# pass only the first few names in the list to the shell, for some +# reason. +# +# Therefore, we have a script to generate the plugin.c file. +# The shell script runs slowly, as multiple greps and seds are run +# for each input file; this is especially slow on Windows. Therefore, +# if Python is present (as indicated by PYTHON being defined), we run +# a faster Python script to do that work instead. +# +# The first argument is the directory in which the source files live. +# The second argument is "plugin", to indicate that we should build +# a plugin.c file for a plugin. +# All subsequent arguments are the files to scan. +# +plugin.c: $(DISSECTOR_SRC) $(top_srcdir)/tools/make-dissector-reg \ + $(top_srcdir)/tools/make-dissector-reg.py + @if test -n $(PYTHON); then \ + echo Making plugin.c with python ; \ + $(PYTHON) $(top_srcdir)/tools/make-dissector-reg.py $(srcdir) \ + plugin $(DISSECTOR_SRC) ; \ + else \ + echo Making plugin.c with shell script ; \ + $(top_srcdir)/tools/make-dissector-reg $(srcdir) \ + $(plugin_src) plugin $(DISSECTOR_SRC) ; \ + fi + +# +# Currently plugin.c can be included in the distribution because +# we always build all protocol dissectors. We used to have to check +# whether or not to build the snmp dissector. If we again need to +# variably build something, making plugin.c non-portable, uncomment +# the dist-hook line below. +# +# Oh, yuk. We don't want to include "plugin.c" in the distribution, as +# its contents depend on the configuration, and therefore we want it +# to be built when the first "make" is done; however, Automake insists +# on putting *all* source into the distribution. +# +# We work around this by having a "dist-hook" rule that deletes +# "plugin.c", so that "dist" won't pick it up. +# +#dist-hook: +# @rm -f $(distdir)/plugin.c + +CLEANFILES = \ + openflow \ + *~ + +MAINTAINERCLEANFILES = \ + Makefile.in \ + plugin.c + +EXTRA_DIST = \ + Makefile.common diff --git a/openflow/utilities/wireshark_dissectors/openflow/Makefile.common b/openflow/utilities/wireshark_dissectors/openflow/Makefile.common new file mode 100644 index 00000000..26c43d26 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/openflow/Makefile.common @@ -0,0 +1,13 @@ +# the name of the plugin +PLUGIN_NAME = openflow + +# the dissector sources (without any helpers) +DISSECTOR_SRC = packet-openflow.c + +# corresponding headers +DISSECTOR_INCLUDES = + +# Dissector helpers. They're included in the source files in this +# directory, but they're not dissectors themselves, i.e. they're not +# used to generate "register.c"). +DISSECTOR_SUPPORT_SRC = diff --git a/openflow/utilities/wireshark_dissectors/openflow/build_distribution_tarball.sh b/openflow/utilities/wireshark_dissectors/openflow/build_distribution_tarball.sh new file mode 100755 index 00000000..d6b1ae05 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/openflow/build_distribution_tarball.sh @@ -0,0 +1,63 @@ +#!/bin/bash +set -o errexit +set -o nounset + +# if user specifies a folder, cd to it +if [ $# -ne 0 ]; then + cd $1 +fi + +# sanity check: make sure script is running from within the plugin build directory +origdir=`pwd` +topdir=wireshark_dissectors +if [ "$topdir" != `dirname $origdir | sed -e "s#.*/##"` ]; then + echo "Error: script must be run from within the plugin's subdirectory with $topdir" + exit 1 +fi + +# sanity check: make sure build works +rm -f *.so +make > /dev/null 2> /dev/null +plugin=`grep 'PLUGIN_NAME =' Makefile | sed -e "s#PLUGIN_NAME =##" -e "s# ##g"`.so +if [ ! -f $plugin ]; then + echo "Error: make failed to build $plugin" + exit 1 +fi + +# make a temporary folder for the build file +tmpdir=/tmp/.$$ +builddir="$tmpdir/$topdir/openflow" +mkdir $tmpdir + +# copy the wireshark plugin directory to the temp folder +cp -r ../ "$tmpdir/$topdir" + +# add the openflow header to the build folder which is in the include search path +cp ../../../include/openflow/openflow.h "$builddir/" + +# cleanup the contents of the build folder +cd "$builddir" +make clean +rm -f *.tgz $0 + +# get the version of the plugin +version=`grep '#define VERSION' moduleinfo.h | cut -d\" -f2` + +# replace tag in README with date information' +date=`date` +cat ../README | sed -e "s##Plugin Version: $version#g" > ../tmp +cat ../tmp | sed -e "s##Distribution Creation Date: $date#g" > ../README + +# make a tarball from the build folder +tarball="openflow-wireshark-dissector-v$version.tar.gz" +cd ../../ +tar -zcf "$tarball" "$topdir" + +# put the tarball back in the original directory +mv "$tarball" "$origdir/" + +# cleanup the temporary folder +rm -rf "$tmpdir" + +# tell the user what we created +echo "tarballed release is now ready: $tarball" diff --git a/openflow/utilities/wireshark_dissectors/openflow/moduleinfo.h b/openflow/utilities/wireshark_dissectors/openflow/moduleinfo.h new file mode 100644 index 00000000..b7bd7f5e --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/openflow/moduleinfo.h @@ -0,0 +1,15 @@ +/* Included *after* config.h, in order to re-define these macros */ + +#ifdef PACKAGE +#undef PACKAGE +#endif + +/* Name of package */ +#define PACKAGE "openflow" + +#ifdef VERSION +#undef VERSION +#endif + +/* Version number of package */ +#define VERSION "1.0.0" /* OpenFlowMajor.OpenFlowMinor.PluginRevForThisMajorMinorRev */ diff --git a/openflow/utilities/wireshark_dissectors/openflow/packet-openflow.c b/openflow/utilities/wireshark_dissectors/openflow/packet-openflow.c new file mode 100644 index 00000000..aea00f88 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/openflow/packet-openflow.c @@ -0,0 +1,3426 @@ +/** + * Filename: packet-openflow.c + * Author: David Underhill + * Changelog: + * dgu 2008-Aug-26 created + * brandonh 2008-Oct-5 updated to 0x95 + * brandonh 2008-Nov-25 updated to 0x96 + bugfixes + * tyabe 2009-May-20 added vlan_pcp_match + * + * Defines a Wireshark 1.0.0+ dissector for the OpenFlow protocol version 0x98. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** the version of openflow this dissector was written for */ +#define DISSECTOR_OPENFLOW_MIN_VERSION OFP_VERSION +#define DISSECTOR_OPENFLOW_MAX_VERSION OFP_VERSION +#define DISSECTOR_OPENFLOW_VERSION_DRAFT_THRESHOLD OFP_VERSION + +/** if 0, padding bytes will not be shown in the dissector */ +#define SHOW_PADDING 0 + +#define PROTO_TAG_OPENFLOW "OFP" + +/* Wireshark ID of the OPENFLOW protocol */ +static int proto_openflow = -1; +static dissector_handle_t openflow_handle; +static void dissect_openflow(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); + +/* traffic will arrive with TCP port OPENFLOW_DST_TCP_PORT */ +#define TCP_PORT_FILTER "tcp.port" +static int global_openflow_proto = OPENFLOW_DST_TCP_PORT; + +/* try to find the ethernet dissector to dissect encapsulated Ethernet data */ +static dissector_handle_t data_ethernet; + +/* AM=Async message, CSM=Control/Switch Message, SM=Symmetric Message */ +/** names to bind to various values in the type field */ +static const value_string names_ofp_type[] = { + /* Immutable messages. */ + { OFPT_HELLO, "Hello (SM)" }, + { OFPT_ERROR, "Error (SM)" }, + { OFPT_ECHO_REQUEST, "Echo Request (SM)" }, + { OFPT_ECHO_REPLY, "Echo Reply (SM)" }, + { OFPT_VENDOR, "Vendor (SM)" }, + + /* Switch configuration messages. */ + { OFPT_FEATURES_REQUEST, "Features Request (CSM)" }, + { OFPT_FEATURES_REPLY, "Features Reply (CSM)" }, + { OFPT_GET_CONFIG_REQUEST, "Get Config Request (CSM)" }, + { OFPT_GET_CONFIG_REPLY, "Get Config Reply (CSM)" }, + { OFPT_SET_CONFIG, "Set Config (CSM)" }, + + /* Asynchronous messages. */ + { OFPT_PACKET_IN, "Packet In (AM)" }, + { OFPT_FLOW_REMOVED, "Flow Removed (AM)" }, + { OFPT_PORT_STATUS, "Port Status (AM)" }, + + /* Controller command messages. */ + { OFPT_PACKET_OUT, "Packet Out (CSM)" }, + { OFPT_FLOW_MOD, "Flow Mod (CSM)" }, + { OFPT_PORT_MOD, "Port Mod (CSM)" }, + + /* Statistics messages. */ + { OFPT_STATS_REQUEST, "Stats Request (CSM)" }, + { OFPT_STATS_REPLY, "Stats Reply (CSM)" }, + + /* Barrier messages. */ + { OFPT_BARRIER_REQUEST, "Barrier Request (CSM)" }, + { OFPT_BARRIER_REPLY, "Barrier Reply (CSM)" }, + + { OFPT_QUEUE_GET_CONFIG_REQUEST, "Get Queue Config Request (CSM)" }, + { OFPT_QUEUE_GET_CONFIG_REPLY, "Get Queue Config Reply (CSM)" }, + + { 0, NULL } +}; +#define OFP_TYPE_MAX_VALUE OFPT_QUEUE_GET_CONFIG_REPLY + +/** names from ofp_action_type */ +static const value_string names_ofp_action_type[] = { + { OFPAT_OUTPUT, "Output to switch port" }, + { OFPAT_SET_VLAN_VID, "Set the 802.1q VLAN id." }, + { OFPAT_SET_VLAN_PCP, "Set the 802.1q priority." }, + { OFPAT_STRIP_VLAN, "Strip the 802.1q header." }, + { OFPAT_SET_DL_SRC, "Ethernet source address" }, + { OFPAT_SET_DL_DST, "Ethernet destination address" }, + { OFPAT_SET_NW_SRC, "IP source address" }, + { OFPAT_SET_NW_DST, "IP destination address" }, + { OFPAT_SET_NW_TOS, "Set IP TOS field" }, + { OFPAT_SET_TP_SRC, "TCP/UDP source port" }, + { OFPAT_SET_TP_DST, "TCP/UDP destination port"}, + { OFPAT_ENQUEUE, "Enqueue to port queue" }, + { OFPAT_VENDOR, "Vendor-defined action"}, + { 0, NULL } +}; +#define NUM_ACTIONS_FLAGS 12 +#define NUM_PORT_CONFIG_FLAGS 7 +#define NUM_PORT_STATE_FLAGS 1 +#define NUM_PORT_FEATURES_FLAGS 12 +#define NUM_WILDCARDS 12 +#define NUM_CAPABILITIES_FLAGS 8 +#define NUM_FLOW_MOD_FLAGS 3 +#define NUM_SF_REPLY_FLAGS 1 + +/** yes/no for bitfields field */ +static const value_string names_choice[] = { + { 0, "No" }, + { 1, "Yes" }, + { 0, NULL } +}; + +/** wildcard or not for bitfields field */ +static const value_string wildcard_choice[] = { + { 0, "Exact" }, + { 1, "Wildcard" }, + { 0, NULL } +}; + +/** wildcard or not for bitfields field */ +static const value_string ts_wildcard_choice[] = { + { 0, "Exact only" }, + { 1, "Wildcard allowed" }, + { 0, NULL } +}; + +/** names from ofp_flow_mod_command */ +static const value_string names_flow_mod_command[] = { + { OFPFC_ADD, "New flow" }, + { OFPFC_MODIFY, "Modify all matching flows" }, + { OFPFC_MODIFY_STRICT, "Modify entry strictly matching wildcards" }, + { OFPFC_DELETE, "Delete all matching flows" }, + { OFPFC_DELETE_STRICT, "Delete entry strictly matching wildcards and priority" }, + { 0, NULL } +}; + +/** names of stats_types */ +static const value_string names_stats_types[] = { + { OFPST_DESC, "Description of this OpenFlow switch" }, + { OFPST_FLOW, "Individual flow statistics" }, + { OFPST_AGGREGATE, "Aggregate flow statistics" }, + { OFPST_TABLE, "Flow table statistics" }, + { OFPST_PORT, "Physical port statistics" }, + { OFPST_QUEUE, "Queue statistics" }, + { OFPST_VENDOR, "Vendor extension" }, + { 0, NULL } +}; + +/** names from ofp_flow_mod_command */ +static const value_string names_ofp_port_reason[] = { + { OFPPR_ADD, "The port was added" }, + { OFPPR_DELETE, "The port was removed" }, + { OFPPR_MODIFY, "Some attribute of the port has changed" }, + { 0, NULL } +}; + +/** names from ofp_packet_in_reason */ +static const value_string names_ofp_packet_in_reason[] = { + { OFPR_NO_MATCH, "No matching flow" }, + { OFPR_ACTION, "Action explicitly output to controller" }, + { 0, NULL } +}; + +/** names from ofp_flow_removed_reason */ +static const value_string names_ofp_flow_removed_reason[] = { + { OFPRR_IDLE_TIMEOUT, "Flow idle time exceeded idle_timeout" }, + { OFPRR_HARD_TIMEOUT, "Time exceeded hard_timeout" }, + { OFPRR_DELETE, "Evicted by a DELETE flow mod." }, + { 0, NULL } +}; + +/** names from ofp_flow_removed_reason */ +static const value_string names_ip_frag[] = { + { OFPC_FRAG_NORMAL, "No special handling for fragments." }, + { OFPC_FRAG_DROP, "Drop fragments." }, + { OFPC_FRAG_REASM, "Reassemble (only if OFPC_IP_REASM set)" }, + { 0, NULL } +}; + +/** names from ofp_error_type */ +static const value_string names_ofp_error_type_reason[] = { + { OFPET_HELLO_FAILED, "Hello protocol failed" }, + { OFPET_BAD_REQUEST, "Request was not understood" }, + { OFPET_BAD_ACTION, "Error in action description" }, + { OFPET_FLOW_MOD_FAILED, "Problem modifying flow entry" }, + { OFPET_PORT_MOD_FAILED, "Port mod request failed" }, + { OFPET_QUEUE_OP_FAILED, "Problem during queue operation" }, + { 0, NULL } +}; + +static const value_string names_ofp_packet_queue_property_type[] = { + { OFPQT_NONE, "No-op Property" }, + { OFPQT_MIN_RATE, "Min Rate Queue" }, + { 0, NULL } +}; + + +/** Address masks */ +static const value_string addr_mask[] = { + { 0, "/32" }, + { 1, "/31" }, + { 2, "/30" }, + { 3, "/29" }, + { 4, "/28" }, + { 5, "/27" }, + { 6, "/26" }, + { 7, "/25" }, + { 8, "/24" }, + { 9, "/23" }, + { 10, "/22" }, + { 11, "/21" }, + { 12, "/20" }, + { 13, "/19" }, + { 14, "/18" }, + { 15, "/17" }, + { 16, "/16" }, + { 17, "/15" }, + { 18, "/14" }, + { 19, "/13" }, + { 20, "/12" }, + { 21, "/11" }, + { 22, "/10" }, + { 23, "/9" }, + { 24, "/8" }, + { 25, "/7" }, + { 26, "/6" }, + { 27, "/5" }, + { 28, "/4" }, + { 29, "/3" }, + { 30, "/2" }, + { 31, "/1" }, + { 32, "/0" }, + { 63, "/0" }, + { 0, NULL } +}; + +/** Address masks */ +static const value_string ts_addr_mask[] = { + { 0, "Exact only" }, + { 63, "Wildcard allowed" }, + { 0, NULL } +}; + +/** Switch config frag values */ +static const value_string sc_frag_choices[] = { + { 0, "No special fragment handling" }, + { 1, "Drop fragments" }, + { 2, "Reassemble (only if OFPC_IP_REASM set)" }, + { 0, NULL } +}; + + +/* Error strings for the various error types */ +static const gchar *hello_failed_err_str[] = {"No compatible version", + "Permissions error"}; + +#define N_HELLOFAILED (sizeof hello_failed_err_str / sizeof hello_failed_err_str[0]) + +static const gchar *bad_request_err_str[] = {"ofp_header.version not supported", + "ofp_header.type not supported", + "ofp_stats_request.type not supported", + "Vendor not supported (in ofp_vendor or ofp_stats_request or ofp_stats_reply)", + "Vendor subtype not supported", + "Permissions error", + "Wrong request length for type", + "Specified buffer has already been used", + "Specified buffer does not exist"}; + +#define N_BADREQUEST (sizeof bad_request_err_str / sizeof bad_request_err_str[0]) + +static const gchar *bad_action_err_str[] = {"Unknown action type", + "Length problem in actions", + "Unknown vendor id specified", + "Unknown action type for vendor id", + "Problem validating output action", + "Bad action argument", + "Permissions error", + "Can't handle this many actions", + "Problem validating output queue"}; + +#define N_BADACTION (sizeof bad_action_err_str / sizeof bad_action_err_str[0]) + +static const gchar *flow_mod_failed_err_str[] = {"Flow not added because of full tables", + "Flow not added because of conflicting entry in tables", + "Permissions error", + "Flow not added because of non-zero idle/hard timeout", + "Unknown command", + "Unsupported action list - cannot process in the order specified"}; + +#define N_FLOWMODFAILED (sizeof flow_mod_failed_err_str / sizeof flow_mod_failed_err_str[0]) + +static const gchar *port_mod_failed_err_str[] = {"Specified port does not exist", + "Specified hardware address is wrong"}; + +#define N_PORTMODFAILED (sizeof port_mod_failed_err_str / sizeof port_mod_failed_err_str[0]) + +static const gchar *queue_op_failed_err_str[] = {"Parent port does not exist", + "queue does not exist", + "Permissions error"}; + +#define N_QUEUEOPFAILED (sizeof queue_op_failed_err_str / sizeof queue_op_failed_err_str[0]) + +/* ICMP definitions from wireshark source: epan/dissectors/packet-ip.c */ +/* ICMP definitions */ + +#define ICMP_ECHOREPLY 0 +#define ICMP_UNREACH 3 +#define ICMP_SOURCEQUENCH 4 +#define ICMP_REDIRECT 5 +#define ICMP_ECHO 8 +#define ICMP_RTRADVERT 9 +#define ICMP_RTRSOLICIT 10 +#define ICMP_TIMXCEED 11 +#define ICMP_PARAMPROB 12 +#define ICMP_TSTAMP 13 +#define ICMP_TSTAMPREPLY 14 +#define ICMP_IREQ 15 +#define ICMP_IREQREPLY 16 +#define ICMP_MASKREQ 17 +#define ICMP_MASKREPLY 18 + +/* ICMP UNREACHABLE */ + +#define ICMP_NET_UNREACH 0 /* Network Unreachable */ +#define ICMP_HOST_UNREACH 1 /* Host Unreachable */ +#define ICMP_PROT_UNREACH 2 /* Protocol Unreachable */ +#define ICMP_PORT_UNREACH 3 /* Port Unreachable */ +#define ICMP_FRAG_NEEDED 4 /* Fragmentation Needed/DF set */ +#define ICMP_SR_FAILED 5 /* Source Route failed */ +#define ICMP_NET_UNKNOWN 6 +#define ICMP_HOST_UNKNOWN 7 +#define ICMP_HOST_ISOLATED 8 +#define ICMP_NET_ANO 9 +#define ICMP_HOST_ANO 10 +#define ICMP_NET_UNR_TOS 11 +#define ICMP_HOST_UNR_TOS 12 +#define ICMP_PKT_FILTERED 13 /* Packet filtered */ +#define ICMP_PREC_VIOLATION 14 /* Precedence violation */ +#define ICMP_PREC_CUTOFF 15 /* Precedence cut off */ + +static const gchar *unreach_str[] = {"Network unreachable", + "Host unreachable", + "Protocol unreachable", + "Port unreachable", + "Fragmentation needed", + "Source route failed", + "Destination network unknown", + "Destination host unknown", + "Source host isolated", + "Network administratively prohibited", + "Host administratively prohibited", + "Network unreachable for TOS", + "Host unreachable for TOS", + "Communication administratively filtered", + "Host precedence violation", + "Precedence cutoff in effect"}; + +#define N_UNREACH (sizeof unreach_str / sizeof unreach_str[0]) + +static const gchar *redir_str[] = {"Redirect for network", + "Redirect for host", + "Redirect for TOS and network", + "Redirect for TOS and host"}; + +#define N_REDIRECT (sizeof redir_str / sizeof redir_str[0]) + +static const gchar *ttl_str[] = {"Time to live exceeded in transit", + "Fragment reassembly time exceeded"}; + +#define N_TIMXCEED (sizeof ttl_str / sizeof ttl_str[0]) + +static const gchar *par_str[] = {"IP header bad", "Required option missing"}; + +#define N_PARAMPROB (sizeof par_str / sizeof par_str[0]) + + +/* ARP definitions from wireshark source: epan/dissectors/packet-arp.c */ +/* ARP / RARP structs and definitions */ +#ifndef ARPOP_REQUEST +#define ARPOP_REQUEST 1 /* ARP request. */ +#endif +#ifndef ARPOP_REPLY +#define ARPOP_REPLY 2 /* ARP reply. */ +#endif +/* Some OSes have different names, or don't define these at all */ +#ifndef ARPOP_RREQUEST +#define ARPOP_RREQUEST 3 /* RARP request. */ +#endif +#ifndef ARPOP_RREPLY +#define ARPOP_RREPLY 4 /* RARP reply. */ +#endif +#ifndef ARPOP_IREQUEST +#define ARPOP_IREQUEST 8 /* Inverse ARP (RFC 1293) request. */ +#endif +#ifndef ARPOP_IREPLY +#define ARPOP_IREPLY 9 /* Inverse ARP reply. */ +#endif +#ifndef ATMARPOP_NAK +#define ATMARPOP_NAK 10 /* ATMARP NAK. */ +#endif + +static const value_string names_arp_opcode[] = { + {ARPOP_REQUEST, "request" }, + {ARPOP_REPLY, "reply" }, + {ARPOP_RREQUEST, "reverse request"}, + {ARPOP_RREPLY, "reverse reply" }, + {ARPOP_IREQUEST, "inverse request"}, + {ARPOP_IREPLY, "inverse reply" }, + {0, NULL } }; + +/* These variables are used to hold the IDs of our fields; they are + * set when we call proto_register_field_array() in proto_register_openflow() + */ +static gint ofp = -1; +static gint ofp_pad = -1; +static gint ofp_port = -1; + +/* OpenFlow Header */ +static gint ofp_header = -1; +static gint ofp_header_version = -1; +static gint ofp_header_type = -1; +static gint ofp_header_length = -1; +static gint ofp_header_xid = -1; +static gint ofp_header_warn_ver = -1; +static gint ofp_header_warn_type = -1; + +/* Common Structures */ +static gint ofp_phy_port = -1; +static gint ofp_phy_port_port_no = -1; +static gint ofp_phy_port_hw_addr = -1; +static gint ofp_phy_port_name = -1; +static gint ofp_phy_port_config_hdr = -1; +static gint ofp_phy_port_config[NUM_PORT_CONFIG_FLAGS]; +static gint ofp_phy_port_state_hdr = -1; +// the following array is EVIL!!!!! do not use, or a curse upon your family. +static gint ofp_phy_port_state[NUM_PORT_STATE_FLAGS]; +// seriously, don't use this bit. +static gint ofp_phy_port_state_not_evil = -1; +static gint ofp_phy_port_state_stp_state = -1; +static gint ofp_phy_port_curr_hdr = -1; +static gint ofp_phy_port_curr[NUM_PORT_FEATURES_FLAGS]; +static gint ofp_phy_port_advertised_hdr = -1; +static gint ofp_phy_port_advertised[NUM_PORT_FEATURES_FLAGS]; +static gint ofp_phy_port_supported_hdr = -1; +static gint ofp_phy_port_supported[NUM_PORT_FEATURES_FLAGS]; +static gint ofp_phy_port_peer_hdr = -1; +static gint ofp_phy_port_peer[NUM_PORT_FEATURES_FLAGS]; + +static gint ofp_match = -1; +static gint ofp_match_wildcards_hdr = -1; +static gint ofp_match_wildcards[NUM_WILDCARDS]; +static gint ofp_match_in_port = -1; +static gint ofp_match_dl_src = -1; +static gint ofp_match_dl_dst = -1; +static gint ofp_match_dl_vlan = -1; +static gint ofp_match_dl_vlan_pcp = -1; +static gint ofp_match_dl_type = -1; +static gint ofp_match_nw_src = -1; +static gint ofp_match_nw_dst = -1; +static gint ofp_match_nw_tos = -1; +static gint ofp_match_nw_proto = -1; +static gint ofp_match_arp_opcode= -1; +static gint ofp_match_tp_src = -1; +static gint ofp_match_tp_dst = -1; +static gint ofp_match_icmp_type = -1; +static gint ofp_match_icmp_code = -1; +static gint ofp_match_nw_src_mask_bits = -1; +static gint ofp_match_nw_dst_mask_bits = -1; + +static gint ofp_action = -1; +static gint ofp_action_type = -1; +static gint ofp_action_len = -1; +static gint ofp_action_vlan_vid = -1; +static gint ofp_action_vlan_pcp = -1; +static gint ofp_action_dl_addr = -1; +static gint ofp_action_nw_addr = -1; +static gint ofp_action_nw_tos = -1; +static gint ofp_action_tp_port = -1; +static gint ofp_action_vendor = -1; +static gint ofp_action_unknown = -1; +static gint ofp_action_warn = -1; +static gint ofp_action_num = -1; + +/* type: ofp_action_output */ +static gint ofp_action_output = -1; +static gint ofp_action_output_port = -1; +static gint ofp_action_output_max_len = -1; + +/* type: ofp_action_enqueue */ +static gint ofp_action_enqueue = -1; +static gint ofp_action_enqueue_port_no = -1; +static gint ofp_action_enqueue_queue_id = -1; + +/* Controller/Switch Messages */ +static gint ofp_switch_features = -1; +static gint ofp_switch_features_datapath_id = -1; +static gint ofp_switch_features_n_buffers = -1; +static gint ofp_switch_features_n_tables = -1; +static gint ofp_switch_features_capabilities_hdr = -1; +static gint ofp_switch_features_capabilities[NUM_CAPABILITIES_FLAGS]; +static gint ofp_switch_features_actions_hdr = -1; +static gint ofp_switch_features_actions[NUM_ACTIONS_FLAGS]; +static gint ofp_switch_features_actions_warn = -1; +// are these two necessary? +static gint ofp_switch_features_ports_hdr = -1; +static gint ofp_switch_features_ports_num = -1; +static gint ofp_switch_features_ports_warn = -1; + +static gint ofp_switch_config = -1; +static gint ofp_switch_config_flags_hdr = -1; +static gint ofp_switch_config_flags_ip_frag = -1; +static gint ofp_switch_config_miss_send_len = -1; + +static gint ofp_queue_get_config_request = -1; +static gint ofp_queue_get_config_request_port_no = -1; + +// there is no limit at the no of queues/port. 1024 is safe for now. +static gint ofp_queue_get_config_reply = -1; +static gint ofp_queue_get_config_reply_port_no = -1; +static gint ofp_queue_get_config_reply_queues_hdr = -1; +static gint ofp_queue_get_config_reply_queues_num = -1; + +static gint ofp_packet_queue = -1; +static gint ofp_packet_queue_queue_id = -1; +static gint ofp_packet_queue_len = -1; +static gint ofp_packet_queue_warn = -1; + +static gint ofp_packet_queue_property = -1; +static gint ofp_packet_queue_property_len = -1; +static gint ofp_packet_queue_property_type = -1; +static gint ofp_packet_queue_property_rate = -1; +static gint ofp_packet_queue_properties_hdr = -1; +static gint ofp_packet_queue_properties_num = -1; +static gint ofp_packet_queue_property_unknown = -1; +static gint ofp_packet_queue_property_warn = -1; + +static gint ofp_flow_mod = -1; +/* field: ofp_match */ +static gint ofp_flow_mod_cookie = -1; +static gint ofp_flow_mod_command = -1; +static gint ofp_flow_mod_idle_timeout = -1; +static gint ofp_flow_mod_hard_timeout = -1; +static gint ofp_flow_mod_priority = -1; +static gint ofp_flow_mod_buffer_id = -1; +static gint ofp_flow_mod_out_port = -1; +static gint ofp_flow_mod_flags[NUM_FLOW_MOD_FLAGS]; + +static gint ofp_port_mod = -1; +static gint ofp_port_mod_port_no = -1; +static gint ofp_port_mod_hw_addr = -1; +static gint ofp_port_mod_config_hdr = -1; +static gint ofp_port_mod_config[NUM_PORT_CONFIG_FLAGS]; +static gint ofp_port_mod_mask_hdr = -1; +static gint ofp_port_mod_mask[NUM_PORT_CONFIG_FLAGS]; +static gint ofp_port_mod_advertise_hdr = -1; +static gint ofp_port_mod_advertise[NUM_PORT_FEATURES_FLAGS]; + +static gint ofp_stats_request = -1; +static gint ofp_stats_request_type = -1; +static gint ofp_stats_request_flags = -1; +static gint ofp_stats_request_body = -1; + +static gint ofp_stats_reply = -1; +static gint ofp_stats_reply_type = -1; +static gint ofp_stats_reply_flags = -1; +static gint ofp_stats_reply_flag[NUM_SF_REPLY_FLAGS]; +static gint ofp_stats_reply_body = -1; + +static gint ofp_desc_stats = -1; +static gint ofp_desc_stats_mfr_desc = -1; +static gint ofp_desc_stats_hw_desc = -1; +static gint ofp_desc_stats_sw_desc = -1; +static gint ofp_desc_stats_dp_desc = -1; +static gint ofp_desc_stats_serial_num = -1; + +static gint ofp_flow_stats_request = -1; +/* field: ofp_match */ +static gint ofp_flow_stats_request_table_id = -1; +static gint ofp_flow_stats_request_out_port = -1; + +static gint ofp_flow_stats_reply = -1; +/* length won't be put in the tree */ +static gint ofp_flow_stats_reply_table_id = -1; +/* field: ofp_match */ +static gint ofp_flow_stats_reply_duration_sec = -1; +static gint ofp_flow_stats_reply_duration_nsec = -1; +static gint ofp_flow_stats_reply_cookie = -1; +static gint ofp_flow_stats_reply_priority = -1; +static gint ofp_flow_stats_reply_idle_timeout = -1; +static gint ofp_flow_stats_reply_hard_timeout = -1; +static gint ofp_flow_stats_reply_packet_count = -1; +static gint ofp_flow_stats_reply_byte_count = -1; +/* field: ofp_actions */ + +static gint ofp_aggr_stats_request = -1; +/* field: ofp_match */ +static gint ofp_aggr_stats_request_table_id = -1; + +static gint ofp_aggr_stats_reply = -1; +static gint ofp_aggr_stats_reply_packet_count = -1; +static gint ofp_aggr_stats_reply_byte_count = -1; +static gint ofp_aggr_stats_reply_flow_count = -1; + +static gint ofp_table_stats = -1; +static gint ofp_table_stats_table_id = -1; +static gint ofp_table_stats_name = -1; +static gint ofp_table_stats_wildcards_hdr = -1; +static gint ofp_table_stats_wildcards[NUM_WILDCARDS]; +static gint ofp_table_stats_max_entries = -1; +static gint ofp_table_stats_active_count = -1; +static gint ofp_table_stats_lookup_count = -1; +static gint ofp_table_stats_matched_count = -1; + +static gint ofp_port_stats_request = -1; +static gint ofp_port_stats_request_port_no = -1; +static gint ofp_port_stats = -1; +static gint ofp_port_stats_port_no = -1; +static gint ofp_port_stats_rx_packets = -1; +static gint ofp_port_stats_tx_packets = -1; +static gint ofp_port_stats_rx_bytes = -1; +static gint ofp_port_stats_tx_bytes = -1; +static gint ofp_port_stats_rx_dropped = -1; +static gint ofp_port_stats_tx_dropped = -1; +static gint ofp_port_stats_rx_errors = -1; +static gint ofp_port_stats_tx_errors = -1; +static gint ofp_port_stats_rx_frame_err = -1; +static gint ofp_port_stats_rx_over_err = -1; +static gint ofp_port_stats_rx_crc_err = -1; +static gint ofp_port_stats_collisions = -1; + +static gint ofp_queue_stats_request = -1; + +static gint ofp_queue_stats = -1; +static gint ofp_queue_stats_port_no = -1; +static gint ofp_queue_stats_queue_id = -1; +static gint ofp_queue_stats_tx_bytes = -1; +static gint ofp_queue_stats_tx_packets = -1; +static gint ofp_queue_stats_tx_errors = -1; + +static gint ofp_vendor_stats = -1; +static gint ofp_vendor_stats_vendor = -1; +static gint ofp_vendor_stats_body = -1; + +static gint ofp_packet_out = -1; +static gint ofp_packet_out_buffer_id = -1; +static gint ofp_packet_out_in_port = -1; +static gint ofp_packet_out_actions_len = -1; +static gint ofp_packet_out_actions_hdr = -1; +static gint ofp_packet_out_data_hdr = -1; + +/* Asynchronous Messages */ +static gint ofp_packet_in = -1; +static gint ofp_packet_in_buffer_id = -1; +static gint ofp_packet_in_total_len = -1; +static gint ofp_packet_in_in_port = -1; +static gint ofp_packet_in_reason = -1; +static gint ofp_packet_in_data_hdr = -1; + +static gint ofp_flow_removed = -1; +/* field: ofp_match */ +static gint ofp_flow_removed_cookie = -1; +static gint ofp_flow_removed_priority = -1; +static gint ofp_flow_removed_reason = -1; +static gint ofp_flow_removed_duration_sec = -1; +static gint ofp_flow_removed_duration_nsec = -1; +static gint ofp_flow_removed_idle_timeout = -1; +static gint ofp_flow_removed_packet_count = -1; +static gint ofp_flow_removed_byte_count = -1; + +static gint ofp_port_status = -1; +static gint ofp_port_status_reason = -1; +/* field: ofp_phy_port desc */ + +static gint ofp_error_msg = -1; +static gint ofp_error_msg_type = -1; +static gint ofp_error_msg_code = -1; +static gint ofp_error_msg_data = -1; +static gint ofp_error_msg_data_str = -1; + +static gint ofp_echo = -1; +static gint ofp_vendor = -1; + +/* These are the ids of the subtrees that we may be creating */ +static gint ett_ofp = -1; + +/* Open Flow Header */ +static gint ett_ofp_header = -1; + +/* Common Structures */ +static gint ett_ofp_phy_port = -1; +static gint ett_ofp_phy_port_config_hdr = -1; +static gint ett_ofp_phy_port_state_hdr = -1; +static gint ett_ofp_phy_port_curr_hdr = -1; +static gint ett_ofp_phy_port_advertised_hdr = -1; +static gint ett_ofp_phy_port_supported_hdr = -1; +static gint ett_ofp_phy_port_peer_hdr = -1; +static gint ett_ofp_match = -1; +static gint ett_ofp_match_wildcards_hdr = -1; +static gint ett_ofp_action = -1; +static gint ett_ofp_action_output = -1; +static gint ett_ofp_action_enqueue = -1; +static gint ett_ofp_packet_queue_root = -1; +static gint ett_ofp_packet_queue = -1; +static gint ett_ofp_packet_queue_property = -1; +static gint ett_ofp_packet_queue_properties_hdr = -1; + +/* Controller/Switch Messages */ +static gint ett_ofp_switch_features = -1; +static gint ett_ofp_switch_features_capabilities_hdr = -1; +static gint ett_ofp_switch_features_actions_hdr = -1; +static gint ett_ofp_switch_features_ports_hdr = -1; +static gint ett_ofp_switch_config = -1; +static gint ett_ofp_switch_config_flags_hdr = -1; +static gint ett_ofp_flow_mod = -1; +static gint ett_ofp_flow_mod_flags_hdr = -1; +static gint ett_ofp_port_mod = -1; +static gint ett_ofp_port_mod_config_hdr = -1; +static gint ett_ofp_port_mod_mask_hdr = -1; +static gint ett_ofp_port_mod_advertise_hdr = -1; + +static gint ett_ofp_queue_get_config_request = -1; +static gint ett_ofp_queue_get_config_reply = -1; +static gint ett_ofp_queue_get_config_reply_queues_hdr = -1; + +static gint ett_ofp_stats_request = -1; +static gint ett_ofp_stats_reply = -1; +static gint ett_ofp_stats_reply_flags = -1; +static gint ett_ofp_desc_stats = -1; +static gint ett_ofp_flow_stats_request = -1; +static gint ett_ofp_flow_stats_reply = -1; +static gint ett_ofp_aggr_stats_request = -1; +static gint ett_ofp_aggr_stats_reply = -1; +static gint ett_ofp_table_stats = -1; +static gint ett_ofp_port_stats_request = -1; +static gint ett_ofp_queue_stats_request = -1; +static gint ett_ofp_port_stats = -1; +static gint ett_ofp_queue_stats = -1; +static gint ett_ofp_vendor_stats = -1; +static gint ett_ofp_packet_out = -1; +static gint ett_ofp_packet_out_actions_hdr = -1; +static gint ett_ofp_packet_out_data_hdr = -1; + +/* Asynchronous Messages */ +static gint ett_ofp_packet_in = -1; +static gint ett_ofp_packet_in_data_hdr = -1; +static gint ett_ofp_flow_removed = -1; +static gint ett_ofp_port_status = -1; +static gint ett_ofp_error_msg = -1; +static gint ett_ofp_error_msg_data = -1; + +void proto_reg_handoff_openflow() +{ + openflow_handle = create_dissector_handle(dissect_openflow, proto_openflow); + dissector_add(TCP_PORT_FILTER, global_openflow_proto, openflow_handle); +} + +#define NO_STRINGS NULL +#define NO_MASK 0x0 + +/** Returns newly allocated string with two spaces in front of str. */ +static inline char* indent( char* str ) { + char* ret = malloc( strlen(str) + 3 ); + ret[0] = ' '; + ret[1] = ' '; + memcpy( &ret[2], str, strlen(str) + 1 ); + return ret; +} + +void proto_register_openflow() +{ + data_ethernet = find_dissector("eth"); + + /* initialize uninitialized header fields */ + int i; + for( i=0; i= 0)) + return names_ofp_type[type].strptr; + else { + snprintf( str_unknown, 17, "Unknown Type %u", type ); + return str_unknown; + } +} + +/** + * Adds "hf" to "tree" starting at "offset" into "tvb" and using "length" + * bytes. offset is incremented by length. + */ +static void add_child( proto_item* tree, gint hf, tvbuff_t *tvb, guint32* offset, guint32 len ) { + proto_tree_add_item( tree, hf, tvb, *offset, len, FALSE ); + *offset += len; +} + +/** + * Adds "hf" to "tree" starting at "offset" into "tvb" and using "length" + * bytes. offset is incremented by length. The specified string is used as the + * field's display value. + */ +static void add_child_str(proto_item* tree, gint hf, tvbuff_t *tvb, guint32* offset, guint32 len, const char* str) { + proto_tree_add_string(tree, hf, tvb, *offset, len, str); + *offset += len; +} + +/** + * Adds "hf" to "tree" starting at "offset" into "tvb" and using "length" + * bytes. The specified string is used as the + * field's display value. + */ +static void add_child_str_const(proto_item* tree, gint hf, tvbuff_t *tvb, guint32 offset, guint32 len, const char* str) { + proto_tree_add_string(tree, hf, tvb, offset, len, str); +} + + +/** + * Adds "hf" to "tree" starting at "offset" into "tvb" and using "length" bytes. + */ +static void add_child_const( proto_item* tree, gint hf, tvbuff_t *tvb, guint32 offset, guint32 len ) { + proto_tree_add_item( tree, hf, tvb, offset, len, FALSE ); +} + +/** returns the length of a PDU which starts at the specified offset in tvb. */ +static guint get_openflow_message_len(packet_info *pinfo, tvbuff_t *tvb, int offset) { + return (guint)tvb_get_ntohs(tvb, offset+2); /* length is at offset 2 in the header */ +} + +static void dissect_pad(proto_tree* tree, guint32 *offset, guint pad_byte_count) { +#if SHOW_PADDING + guint i; + for( i=0; i 0) { + port_item = proto_tree_add_item(tree, ofp_phy_port, tvb, *offset, sizeof(struct ofp_phy_port), FALSE); + port_tree = proto_item_add_subtree(port_item, ett_ofp_phy_port); + + dissect_port( port_tree, ofp_phy_port_port_no, tvb, offset ); + add_child( port_tree, ofp_phy_port_hw_addr, tvb, offset, OFP_ETH_ALEN ); + add_child( port_tree, ofp_phy_port_name, tvb, offset, OFP_MAX_PORT_NAME_LEN ); + + /* config */ + config_item = proto_tree_add_item(port_tree, ofp_phy_port_config_hdr, tvb, *offset, 4, FALSE); + config_tree = proto_item_add_subtree(config_item, ett_ofp_phy_port_config_hdr); + for(i=0; iname, get_tcp_port(port), port); + + *offset += 2; +} + +/* Based on: dissect_icmp from wireshark: epan/dissectors/packet-ip.c */ +static void dissect_icmp_type_code_match(proto_tree* tree, tvbuff_t *tvb, guint32 *offset, gint show_type, gint show_code) +{ + guint16 icmp_type; + guint16 icmp_code; + const gchar *type_str, *code_str; + + type_str=""; + code_str=""; + + /* Get the ICMP type/code */ + icmp_type = tvb_get_ntohs(tvb, *offset); + icmp_code = tvb_get_ntohs(tvb, *offset + 2); + + /* Get string representations of the ICMP types/codes */ + switch (icmp_type) { + case ICMP_ECHOREPLY: + type_str="Echo (ping) reply"; + break; + case ICMP_UNREACH: + type_str="Destination unreachable"; + if (icmp_code < N_UNREACH) { + code_str = unreach_str[icmp_code]; + } else { + code_str = "Unknown - error?"; + } + break; + case ICMP_SOURCEQUENCH: + type_str="Source quench (flow control)"; + break; + case ICMP_REDIRECT: + type_str="Redirect"; + if (icmp_code < N_REDIRECT) { + code_str = redir_str[icmp_code]; + } else { + code_str = "Unknown - error?"; + } + break; + case ICMP_ECHO: + type_str="Echo (ping) request"; + break; + case ICMP_RTRADVERT: + switch (icmp_code) { + case 0: /* Mobile-Ip */ + case 16: /* Mobile-Ip */ + type_str="Mobile IP Advertisement"; + break; + default: + type_str="Router advertisement"; + break; + } /* switch icmp_code */ + break; + case ICMP_RTRSOLICIT: + type_str="Router solicitation"; + break; + case ICMP_TIMXCEED: + type_str="Time-to-live exceeded"; + if (icmp_code < N_TIMXCEED) { + code_str = ttl_str[icmp_code]; + } else { + code_str = "Unknown - error?"; + } + break; + case ICMP_PARAMPROB: + type_str="Parameter problem"; + if (icmp_code < N_PARAMPROB) { + code_str = par_str[icmp_code]; + } else { + code_str = "Unknown - error?"; + } + break; + case ICMP_TSTAMP: + type_str="Timestamp request"; + break; + case ICMP_TSTAMPREPLY: + type_str="Timestamp reply"; + break; + case ICMP_IREQ: + type_str="Information request"; + break; + case ICMP_IREQREPLY: + type_str="Information reply"; + break; + case ICMP_MASKREQ: + type_str="Address mask request"; + break; + case ICMP_MASKREPLY: + type_str="Address mask reply"; + break; + default: + type_str="Unknown ICMP (obsolete or malformed?)"; + break; + } + + if (show_type) + proto_tree_add_uint_format(tree, ofp_match_icmp_type, tvb, *offset, 2, + icmp_type, + "ICMP Type: %u (%s)", + icmp_type, type_str); + if (show_code) + proto_tree_add_uint_format(tree, ofp_match_icmp_code, tvb, *offset, 2, + icmp_code, + "ICMP Code: %u (%s)", + icmp_code, code_str); + + *offset += 4; +} + +static void dissect_match(proto_tree* tree, proto_item* item, tvbuff_t *tvb, packet_info *pinfo, guint32 *offset) +{ + proto_item *match_item = proto_tree_add_item(tree, ofp_match, tvb, *offset, sizeof(struct ofp_match), FALSE); + proto_tree *match_tree = proto_item_add_subtree(match_item, ett_ofp_match); + + /* save wildcards field for later */ + guint32 wildcards = tvb_get_ntohl( tvb, *offset ); + + dissect_wildcards(match_tree, match_item, tvb, pinfo, offset, ofp_match_wildcards); + + /* show only items whose corresponding wildcard bit is not set */ + if( ~wildcards & OFPFW_IN_PORT ) + dissect_port(match_tree, ofp_match_in_port, tvb, offset); + else + *offset += 2; + + if( ~wildcards & OFPFW_DL_SRC ) + add_child(match_tree, ofp_match_dl_src, tvb, offset, 6); + else + *offset += 6; + + if( ~wildcards & OFPFW_DL_DST ) + add_child(match_tree, ofp_match_dl_dst, tvb, offset, 6); + else + *offset += 6; + + if( ~wildcards & OFPFW_DL_VLAN ) + add_child(match_tree, ofp_match_dl_vlan, tvb, offset, 2); + else + *offset += 2; + + if( ~wildcards & OFPFW_DL_VLAN_PCP ) + add_child(match_tree, ofp_match_dl_vlan_pcp, tvb, offset, 1); + else + *offset += 1; + + dissect_pad(match_tree, offset, 1); + + /* Save DL type for later */ + guint16 dl_type = tvb_get_ntohs( tvb, *offset); + + if( ~wildcards & OFPFW_DL_TYPE ) + dissect_dl_type(match_tree, ofp_match_dl_type, tvb, offset); + else + *offset += 2; + + if( ~wildcards & OFPFW_NW_TOS ) + add_child(match_tree, ofp_match_nw_tos, tvb, offset, 1); + else + *offset += 1; + + /* Save NW proto for later */ + guint8 nw_proto = tvb_get_guint8( tvb, *offset); + + /* Custom handling for ARP packets vs non-ARP packets */ + if ( dl_type == ETHERTYPE_ARP ) + add_child(match_tree, ofp_match_arp_opcode, tvb, offset, 1); + else if( ~wildcards & OFPFW_NW_PROTO ) + dissect_nw_proto(match_tree, ofp_match_nw_proto, tvb, offset); + else + *offset += 1; + + dissect_pad(match_tree, offset, 2); + + if( ~wildcards & OFPFW_NW_SRC_MASK ) + add_child(match_tree, ofp_match_nw_src, tvb, offset, 4); + else + *offset += 4; + + if( ~wildcards & OFPFW_NW_DST_MASK ) + add_child(match_tree, ofp_match_nw_dst, tvb, offset, 4); + else + *offset += 4; + + /* Display either ICMP type/code or TCP/UDP ports */ + if( dl_type == ETHERTYPE_IP && nw_proto == IP_PROTO_ICMP) { + dissect_icmp_type_code_match(match_tree, tvb, offset, + ~wildcards & OFPFW_TP_SRC, + ~wildcards & OFPFW_TP_DST ); + } + else { + if( ~wildcards & OFPFW_TP_SRC ) + dissect_tp_port(match_tree, ofp_match_tp_src, tvb, offset); + else + *offset += 2; + + if( ~wildcards & OFPFW_TP_DST ) + dissect_tp_port(match_tree, ofp_match_tp_dst, tvb, offset); + else + *offset += 2; + } +} + +static void dissect_action_output(proto_tree* tree, tvbuff_t *tvb, guint32 *offset) +{ + /* add the output port */ + dissect_port( tree, ofp_action_output_port, tvb, offset ); + + /* determine the maximum number of bytes to send (0 => no limit) */ + guint16 max_len = tvb_get_ntohs( tvb, *offset ); + char str[11]; + snprintf( str, 11, "%u", max_len ); + add_child_str( tree, ofp_action_output_max_len, tvb, offset, 2, str ); +} + +static void dissect_action_enqueue(proto_tree* tree, tvbuff_t *tvb, guint32 *offset) +{ + /* add the output port */ + dissect_port( tree, ofp_action_enqueue_port_no, tvb, offset ); + dissect_pad(tree, offset, 6); + dissect_queue_id(tree, ofp_action_enqueue_queue_id, tvb, offset); +} + + +/** returns the number of bytes dissected (-1 if an unknown action type is + * encountered; and 8/16 for all other actions as of 0x96) */ +static gint dissect_action(proto_tree* tree, proto_item* item, tvbuff_t *tvb, packet_info *pinfo, guint32 *offset) +{ + guint32 offset_start = *offset; + guint16 type = tvb_get_ntohs( tvb, *offset ); + guint16 len = tvb_get_ntohs( tvb, *offset + 2); + + proto_item *action_item = proto_tree_add_item(tree, ofp_action, tvb, *offset, len, FALSE); + proto_tree *action_tree = proto_item_add_subtree(action_item, ett_ofp_action); + + if (!(len == 8 || len == 16)) { + add_child_str(action_tree, ofp_action_unknown, tvb, offset, len, "Invalid Action Length"); + return -1; + } + + add_child( action_tree, ofp_action_type, tvb, offset, 2 ); + add_child( action_tree, ofp_action_len, tvb, offset, 2 ); + + switch( type ) { + case OFPAT_OUTPUT: + dissect_action_output(action_tree, tvb, offset); + break; + + case OFPAT_SET_VLAN_VID: + add_child( action_tree, ofp_action_vlan_vid, tvb, offset, 2 ); + dissect_pad(action_tree, offset, 2); + break; + + case OFPAT_SET_VLAN_PCP: + add_child( action_tree, ofp_action_vlan_pcp, tvb, offset, 1 ); + dissect_pad(action_tree, offset, 3); + break; + + case OFPAT_STRIP_VLAN: + add_child( action_tree, ofp_action_unknown, tvb, offset, 0 ); + dissect_pad(action_tree, offset, 4); + break; + + case OFPAT_SET_DL_SRC: + case OFPAT_SET_DL_DST: + add_child(action_tree, ofp_action_dl_addr, tvb, offset, 6 ); + dissect_pad(action_tree, offset, 6); + break; + + case OFPAT_SET_NW_SRC: + case OFPAT_SET_NW_DST: + add_child( action_tree, ofp_action_nw_addr, tvb, offset, 4 ); + break; + + case OFPAT_SET_NW_TOS: + add_child( action_tree, ofp_action_nw_tos, tvb, offset, 1); + dissect_pad(action_tree, offset, 3); + break; + + case OFPAT_SET_TP_SRC: + case OFPAT_SET_TP_DST: + add_child( action_tree, ofp_action_tp_port, tvb, offset, 2 ); + dissect_pad(action_tree, offset, 2); + break; + + case OFPAT_ENQUEUE: + dissect_action_enqueue(action_tree, tvb, offset); + break; + + default: + add_child( action_tree, ofp_action_unknown, tvb, offset, 0 ); + return -1; + } + + /* return the number of bytes which were consumed */ + return *offset - offset_start; +} + +static void dissect_action_array(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint len, guint offset) +{ + guint total_len = len - offset; + + proto_item* action_item = proto_tree_add_item(tree, ofp_action_output, tvb, offset, total_len, FALSE); + proto_tree* action_tree = proto_item_add_subtree(action_item, ett_ofp_action_output); + + if( total_len == 0 ) + add_child_str(action_tree, ofp_action_warn, tvb, &offset, 0, "No actions were specified"); + else if( offset > len ) { + /* not enough bytes => wireshark will already have reported the error */ + } + else { + guint offset_action_start = offset; + guint num_actions = 0; + while( total_len > 0 ) { + num_actions += 1; + int ret = dissect_action(action_tree, action_item, tvb, pinfo, &offset); + if( ret < 0 ) + break; /* stop if we run into an action we couldn't dissect */ + else + total_len -= ret; + } + proto_tree_add_uint(action_tree, ofp_action_num, tvb, offset_action_start, 0, num_actions); + } +} + +static void dissect_property_min(proto_tree* tree, tvbuff_t *tvb, guint32 *offset) +{ + add_child(tree, ofp_packet_queue_property_rate, tvb, offset, 2); + dissect_pad(tree, offset, 6); +} + +static gint32 dissect_property(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, guint32 *offset) +{ + guint32 offset_start = *offset; + guint16 type = tvb_get_ntohs(tvb, *offset); + guint16 len = tvb_get_ntohs(tvb, *offset + 2); + + proto_item *property_item = proto_tree_add_item(tree, ofp_packet_queue_property, tvb, *offset, len, FALSE); + proto_tree *property_tree = proto_item_add_subtree(property_item, ett_ofp_packet_queue_property); + + add_child(property_tree, ofp_packet_queue_property_type, tvb, offset, 2); + add_child(property_tree, ofp_packet_queue_property_len, tvb, offset, 2); + dissect_pad(tree, offset, 4); + + switch( type ) { + case OFPQT_MIN_RATE: + dissect_property_min(property_tree, tvb, offset); + break; + default: + add_child(property_tree, ofp_packet_queue_property_unknown, tvb, offset, 0); + return -1; + } + + return *offset - offset_start; +} + +/* returns the number of bytes dissected ( -1 if unknown propery is encountered */ +static void dissect_property_array(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint len, guint32 *offset) +{ + guint total_len = len; + + proto_item *property_item = proto_tree_add_item(tree, ofp_packet_queue_properties_hdr, tvb, *offset, total_len, FALSE); + proto_tree *property_tree = proto_item_add_subtree(property_item, ett_ofp_packet_queue_properties_hdr); + + if( total_len == 0 ) { + add_child_str(property_tree, ofp_packet_queue_property_warn, tvb, offset, 0, "No properties were specified"); + } + else { + guint32 offset_property_start = *offset; + guint num_properties = 0; + while( total_len > 0 ) { + num_properties += 1; + int ret = dissect_property(property_tree, tvb, pinfo, offset); + if( ret < 0 ) { + break; /* stop if we run into a property we couldn't dissect */ + } + else + total_len -= ret; + } + proto_tree_add_uint(property_tree, ofp_packet_queue_properties_num, tvb, offset_property_start, 0, num_properties); + } +} + +/** returns the number of bytes dissected (-1 if an unknown property is + * encountered; */ +static gint dissect_queue(proto_tree* tree, tvbuff_t *tvb, packet_info *pinfo, guint32 *offset) +{ + guint32 offset_start = *offset; + guint16 len = tvb_get_ntohs( tvb, *offset + 4); + + proto_item *queue_item = proto_tree_add_item(tree, ofp_packet_queue, tvb, *offset, len, FALSE); + proto_tree *queue_tree = proto_item_add_subtree(queue_item, ett_ofp_packet_queue); + + // add_child( queue_tree, ofp_packet_queue_queue_id, tvb, offset, 4 ); + dissect_queue_id(queue_tree, ofp_packet_queue_queue_id, tvb, offset); + add_child( queue_tree, ofp_packet_queue_len, tvb, offset, 2 ); + dissect_pad( queue_tree, offset, 2); + + dissect_property_array(tvb, pinfo, queue_tree, len - (*offset - offset_start), offset); + return *offset - offset_start; + +} + +static void dissect_queue_array(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint len, guint32 *offset) +{ + guint total_len = len - *offset; + + proto_item *queue_item = proto_tree_add_item(tree, ofp_queue_get_config_reply_queues_hdr, tvb, *offset, total_len, FALSE); + proto_tree *queue_tree = proto_item_add_subtree(queue_item, ett_ofp_queue_get_config_reply_queues_hdr); + + if( total_len == 0 ) { + add_child_str(queue_tree, ofp_packet_queue_warn, tvb, offset, 0, "No queues were specified"); + } + else if( *offset > len ) { + /* not enough bytes => wireshark will already have reported the error */ + } + else { + guint offset_queue_start = *offset; + guint num_queues = 0; + while( total_len > 0 ) { + num_queues += 1; + int ret = dissect_queue(queue_tree, tvb, pinfo, offset); + if( ret < 0 ) + break; /* stop if we run into an action we couldn't dissect */ + else + total_len -= ret; + } + proto_tree_add_uint(queue_tree, ofp_queue_get_config_reply_queues_num, tvb, offset_queue_start, 0, num_queues); + } +} + + +static void dissect_capability_array(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint field_size) { + proto_item *sf_cap_item = proto_tree_add_item(tree, ofp_switch_features_capabilities_hdr, tvb, offset, field_size, FALSE); + proto_tree *sf_cap_tree = proto_item_add_subtree(sf_cap_item, ett_ofp_switch_features_capabilities_hdr); + gint i; + for(i=0; icinfo, COL_PROTOCOL)) + col_append_str( pinfo->cinfo, COL_PROTOCOL, "+" ); + + if(check_col(pinfo->cinfo,COL_INFO)) + col_append_str( pinfo->cinfo, COL_INFO, " => " ); + + /* set up fences so ethernet dissectors only appends to our column info */ + col_set_fence(pinfo->cinfo, COL_PROTOCOL); + col_set_fence(pinfo->cinfo, COL_INFO); + + /* continue the dissection with the ethernet dissector */ + call_dissector(data_ethernet, next_tvb, pinfo, data_tree); +} + +static void dissect_error_code(proto_tree* tree, gint hf, tvbuff_t *tvb, guint32 *offset, guint16 err_type) { + guint16 err_code; + guint8 valid; + const gchar *code_str; + + err_code = tvb_get_ntohs(tvb, *offset); + code_str = ""; + valid = TRUE; + + switch (err_type) { + case OFPET_HELLO_FAILED: + if (err_code < N_HELLOFAILED) { + code_str = hello_failed_err_str[err_code]; + } else { + code_str = "Unknown - error?"; + } + break; + case OFPET_BAD_REQUEST: + if (err_code < N_BADREQUEST) { + code_str = bad_request_err_str[err_code]; + } else { + code_str = "Unknown - error?"; + } + break; + case OFPET_BAD_ACTION: + if (err_code < N_BADACTION) { + code_str = bad_action_err_str[err_code]; + } else { + code_str = "Unknown - error?"; + } + break; + case OFPET_FLOW_MOD_FAILED: + if (err_code < N_FLOWMODFAILED) { + code_str = flow_mod_failed_err_str[err_code]; + } else { + code_str = "Unknown - error?"; + } + break; + case OFPET_PORT_MOD_FAILED: + if (err_code < N_PORTMODFAILED) { + code_str = port_mod_failed_err_str[err_code]; + } else { + code_str = "Unknown - error?"; + } + break; + case OFPET_QUEUE_OP_FAILED: + if (err_code < N_QUEUEOPFAILED) { + code_str = queue_op_failed_err_str[err_code]; + } else { + code_str = "Unknown - error?"; + } + break; + + default: + valid = FALSE; + break; + } + + if (valid) + proto_tree_add_uint_format(tree, hf, tvb, *offset, 2, + err_code, + "Code: %s (%u)", + code_str, err_code); + else + proto_tree_add_item(tree, hf, tvb, *offset, 2, FALSE); + + *offset += 2; +} + +static void dissect_flow_mod_flags(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) { + proto_item *fm_flags_item = proto_tree_add_item(tree, ofp_switch_config_flags_hdr, tvb, *offset, 2, FALSE); + proto_tree *fm_flags_tree = proto_item_add_subtree(fm_flags_item, ett_ofp_flow_mod_flags_hdr); + int i; + + for (i = 0; i < NUM_FLOW_MOD_FLAGS; i++) + add_child_const(fm_flags_tree, ofp_flow_mod_flags[i], tvb, *offset, 2); + + *offset += 2; +} + + +static void dissect_openflow_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ +# define STR_LEN 1024 + char str[STR_LEN]; + + /* display our protocol text if the protocol column is visible */ + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + col_set_str(pinfo->cinfo, COL_PROTOCOL, PROTO_TAG_OPENFLOW); + + /* Clear out stuff in the info column */ + if(check_col(pinfo->cinfo,COL_INFO)) + col_clear(pinfo->cinfo,COL_INFO); + + /* get some of the header fields' values for later use */ + guint8 ver = tvb_get_guint8( tvb, 0 ); + guint8 type = tvb_get_guint8( tvb, 1 ); + guint16 len = tvb_get_ntohs( tvb, 2 ); + + /* add a warning if the version is what the plugin was written to handle */ + guint8 ver_warning = 0; + if( ver < DISSECTOR_OPENFLOW_MIN_VERSION || ver > DISSECTOR_OPENFLOW_MAX_VERSION || ver >= DISSECTOR_OPENFLOW_VERSION_DRAFT_THRESHOLD ) { + if( ver>=DISSECTOR_OPENFLOW_VERSION_DRAFT_THRESHOLD && ver<=DISSECTOR_OPENFLOW_MAX_VERSION ) + snprintf( str, STR_LEN, "DRAFT Dissector written for this OpenFlow version v0x%0X", ver ); + else { + ver_warning = 1; + if( DISSECTOR_OPENFLOW_MIN_VERSION == DISSECTOR_OPENFLOW_MAX_VERSION ) + snprintf( str, STR_LEN, + "Dissector written for OpenFlow v0x%0X (differs from this packet's version v0x%0X)", + DISSECTOR_OPENFLOW_MIN_VERSION, ver ); + else + snprintf( str, STR_LEN, + "Dissector written for OpenFlow v0x%0X-v0x%0X (differs from this packet's version v0x%0X)", + DISSECTOR_OPENFLOW_MIN_VERSION, DISSECTOR_OPENFLOW_MAX_VERSION, ver ); + } + } + + /* clarify protocol name display with version, length, and type information */ + if (check_col(pinfo->cinfo, COL_INFO)) { + /* special handling so we can put buffer IDs in the description */ + char str_extra[32]; + str_extra[0] = '\0'; + if( type==OFPT_PACKET_IN || type==OFPT_PACKET_OUT ) { + guint32 bid = tvb_get_ntohl(tvb, sizeof(struct ofp_header)); + if( bid != 0xFFFFFFFF ) + snprintf(str_extra, 32, "(BufID=%u) ", bid); + } + + if( ver_warning ) + col_add_fstr( pinfo->cinfo, COL_INFO, "%s %s(%uB) Ver Warning!", ofp_type_to_string(type), str_extra, len ); + else + col_add_fstr( pinfo->cinfo, COL_INFO, "%s %s(%uB)", ofp_type_to_string(type), str_extra, len ); + } + + if (tree) { /* we are being asked for details */ + proto_item *item = NULL; + proto_item *sub_item = NULL; + proto_tree *ofp_tree = NULL; + proto_tree *header_tree = NULL; + guint32 offset = 0; + proto_item *type_item = NULL; + proto_tree *type_tree = NULL; + + /* consume the entire tvb for the openflow packet, and add it to the tree */ + item = proto_tree_add_item(tree, proto_openflow, tvb, 0, -1, FALSE); + ofp_tree = proto_item_add_subtree(item, ett_ofp); + + /* put the header in its own node as a child of the openflow node */ + sub_item = proto_tree_add_item( ofp_tree, ofp_header, tvb, offset, 8, FALSE ); + header_tree = proto_item_add_subtree(sub_item, ett_ofp_header); + + if( ver_warning ) + add_child_str( header_tree, ofp_header_warn_ver, tvb, &offset, 0, str ); + + /* add the headers field as children of the header node */ + add_child( header_tree, ofp_header_version, tvb, &offset, 1 ); + add_child( header_tree, ofp_header_type, tvb, &offset, 1 ); + add_child( header_tree, ofp_header_length, tvb, &offset, 2 ); + add_child( header_tree, ofp_header_xid, tvb, &offset, 4 ); + + switch( type ) { + + case OFPT_HELLO: { + /* nothing else in this packet type */ + break; + } + + case OFPT_BARRIER_REQUEST: + case OFPT_BARRIER_REPLY: + /* nothing else in this packet type */ + break; + + case OFPT_ERROR: { + type_item = proto_tree_add_item(ofp_tree, ofp_error_msg, tvb, offset, -1, FALSE); + type_tree = proto_item_add_subtree(type_item, ett_ofp_error_msg); + + /* Extract the type for use later */ + guint16 type = tvb_get_ntohs(tvb, offset); + + add_child(type_tree, ofp_error_msg_type, tvb, &offset, 2); + dissect_error_code(type_tree, ofp_error_msg_code, tvb, &offset, type); + + if (type == OFPET_HELLO_FAILED) + add_child(type_tree, ofp_error_msg_data_str, tvb, &offset, len - offset); + else if (type == OFPET_BAD_REQUEST || + type == OFPET_BAD_ACTION || + type == OFPET_FLOW_MOD_FAILED) { + /* Dissect the data as an OpenFlow packet */ + proto_item *data_item = proto_tree_add_item(type_tree, ofp_error_msg_data, tvb, offset, -1, FALSE); + proto_tree *data_tree = proto_item_add_subtree(data_item, ett_ofp_error_msg_data); + tvbuff_t *next_tvb = tvb_new_subset(tvb, offset, -1, len - offset); + + /* Temporarily disable writing */ + gboolean writeable = col_get_writable(pinfo->cinfo); + col_set_writable( pinfo->cinfo, FALSE); + + /* Finally do the dissection */ + dissect_openflow_message(next_tvb, pinfo, data_tree); + + col_set_writable( pinfo->cinfo, writeable); + + offset += (len - offset); + } + else + add_child(type_tree, ofp_error_msg_data, tvb, &offset, len - offset); + break; + } + + case OFPT_ECHO_REQUEST: + case OFPT_ECHO_REPLY: { + if (len - offset > 0) + add_child(tree, ofp_echo, tvb, &offset, len - offset); + break; + } + + case OFPT_VENDOR: { + if (len - offset > 0) { + add_child(tree, ofp_vendor, tvb, &offset, len - offset); + } + break; + } + + case OFPT_FEATURES_REQUEST: + /* nothing else in this packet type */ + break; + + case OFPT_FEATURES_REPLY: { + + proto_item *sf_port_item = NULL; + proto_tree *sf_port_tree = NULL; + guint num_ports; + gint sz; + + type_item = proto_tree_add_item(ofp_tree, ofp_switch_features, tvb, offset, -1, FALSE); + //break; + type_tree = proto_item_add_subtree(type_item, ett_ofp_switch_features); + + /* fields we'll put directly in the subtree */ + + add_child(type_tree, ofp_switch_features_datapath_id, tvb, &offset, 8); + + add_child(type_tree, ofp_switch_features_n_buffers, tvb, &offset, 4); + add_child(type_tree, ofp_switch_features_n_tables, tvb, &offset, 1); + dissect_pad(type_tree, &offset, 3); + + + /* capabilities */ + dissect_capability_array(tvb, pinfo, type_tree, offset, 4); + offset += 4; + + /* actions */ + dissect_switch_features_actions(tvb, pinfo, type_tree, offset, 4); + offset += 4; + + /* handle ports */ + sf_port_item = proto_tree_add_item(type_tree, ofp_switch_features_ports_hdr, tvb, offset, -1, FALSE); + sf_port_tree = proto_item_add_subtree(sf_port_item, ett_ofp_switch_features_ports_hdr); + sz = len - sizeof(struct ofp_switch_features); + + if( sz > 0 ) { + num_ports = sz / sizeof(struct ofp_phy_port); /* number of ports */ + proto_tree_add_uint(sf_port_tree, ofp_switch_features_ports_num, tvb, offset, num_ports*sizeof(struct ofp_phy_port), num_ports); + + dissect_phy_ports(sf_port_tree, sf_port_item, tvb, pinfo, &offset, num_ports); + if( num_ports * sizeof(struct ofp_phy_port) < sz ) { + snprintf(str, STR_LEN, "%uB were leftover at end of packet", sz - num_ports*sizeof(struct ofp_phy_port)); + add_child_str(sf_port_tree, ofp_switch_features_ports_warn, tvb, &offset, 0, str); + } + } + else if( sz < 0 ) { + /* not enough bytes => wireshark will already have reported the error */ + } + else { + snprintf(str, STR_LEN, "No ports were specified"); + add_child_str(sf_port_tree, ofp_switch_features_ports_warn, tvb, &offset, 0, str); + } + break; + } + + case OFPT_GET_CONFIG_REQUEST: + /* nothing else in this packet type */ + break; + + case OFPT_GET_CONFIG_REPLY: + case OFPT_SET_CONFIG: { + type_item = proto_tree_add_item(ofp_tree, ofp_switch_config, tvb, offset, -1, FALSE); + type_tree = proto_item_add_subtree(type_item, ett_ofp_switch_config); + dissect_switch_config_flags(tvb, pinfo, type_tree, &offset); + add_child(type_tree, ofp_switch_config_miss_send_len, tvb, &offset, 2); + break; + } + + case OFPT_QUEUE_GET_CONFIG_REQUEST: { + type_item = proto_tree_add_item(ofp_tree, ofp_queue_get_config_request, tvb, offset, -1, FALSE); + type_tree = proto_item_add_subtree(type_item, ett_ofp_queue_get_config_request); + dissect_port(type_tree, ofp_queue_get_config_request_port_no, tvb, &offset); + dissect_pad(type_tree, &offset, 2); + break; + } + + case OFPT_QUEUE_GET_CONFIG_REPLY: { + type_item = proto_tree_add_item(ofp_tree, ofp_queue_get_config_reply, tvb, offset, -1, FALSE); + type_tree = proto_item_add_subtree(type_item, ett_ofp_queue_get_config_reply); + + dissect_port(type_tree, ofp_queue_get_config_reply_port_no, tvb, &offset); + dissect_pad(type_tree, &offset, 6); + + /* handle queues */ + dissect_queue_array(tvb, pinfo, type_tree, len, &offset); + break; + } + + case OFPT_PACKET_IN: { + type_item = proto_tree_add_item(ofp_tree, ofp_packet_in, tvb, offset, -1, FALSE); + type_tree = proto_item_add_subtree(type_item, ett_ofp_packet_in); + + add_child(type_tree, ofp_packet_in_buffer_id, tvb, &offset, 4); + + /* explicitly pull out the length so we can use it to determine data's size */ + guint16 total_len = tvb_get_ntohs( tvb, offset ); + proto_tree_add_uint(type_tree, ofp_packet_in_total_len, tvb, offset, 2, total_len); + offset += 2; + + add_child(type_tree, ofp_packet_in_in_port, tvb, &offset, 2); + add_child(type_tree, ofp_packet_in_reason, tvb, &offset, 1); + dissect_pad(type_tree, &offset, 1); + + if (len > sizeof(struct ofp_packet_in)) { + /* continue the dissection with the Ethernet dissector */ + if (data_ethernet) { + proto_item *data_item = proto_tree_add_item(type_tree, ofp_packet_in_data_hdr, tvb, offset, -1, FALSE); + proto_tree *data_tree = proto_item_add_subtree(data_item, ett_ofp_packet_in_data_hdr); + tvbuff_t *next_tvb = tvb_new_subset(tvb, offset, -1, total_len); + dissect_ethernet(next_tvb, pinfo, data_tree); + } else { + /* if we couldn't load the ethernet dissector, just display the bytes */ + add_child(type_tree, ofp_packet_in_data_hdr, tvb, &offset, total_len); + } + } + break; + } + + case OFPT_FLOW_REMOVED: { + type_item = proto_tree_add_item(ofp_tree, ofp_flow_removed, tvb, offset, -1, FALSE); + type_tree = proto_item_add_subtree(type_item, ett_ofp_flow_removed); + + dissect_match(type_tree, type_item, tvb, pinfo, &offset); + add_child(type_tree, ofp_flow_removed_cookie, tvb, &offset, 8); + add_child(type_tree, ofp_flow_removed_priority, tvb, &offset, 2); + add_child(type_tree, ofp_flow_removed_reason, tvb, &offset, 1); + dissect_pad(type_tree, &offset, 1); + add_child(type_tree, ofp_flow_removed_duration_sec, tvb, &offset, 4); + add_child(type_tree, ofp_flow_removed_duration_nsec, tvb, &offset, 4); + add_child(type_tree, ofp_flow_removed_idle_timeout, tvb, &offset, 2); + dissect_pad(type_tree, &offset, 2); + add_child(type_tree, ofp_flow_removed_packet_count, tvb, &offset, 8); + add_child(type_tree, ofp_flow_removed_byte_count, tvb, &offset, 8); + break; + } + + case OFPT_PORT_STATUS: { + type_item = proto_tree_add_item(ofp_tree, ofp_port_status, tvb, offset, -1, FALSE); + type_tree = proto_item_add_subtree(type_item, ett_ofp_port_status); + + add_child(type_tree, ofp_port_status_reason, tvb, &offset, 1); + dissect_pad(type_tree, &offset, 7); + dissect_phy_ports(type_tree, type_item, tvb, pinfo, &offset, 1); + break; + } + + case OFPT_PACKET_OUT: { + type_item = proto_tree_add_item(ofp_tree, ofp_packet_out, tvb, offset, -1, FALSE); + type_tree = proto_item_add_subtree(type_item, ett_ofp_packet_out); + + /* get buffer_id value for later use */ + guint32 buffer_id = tvb_get_ntohl( tvb, offset ); + + if( buffer_id == 0xFFFFFFFF ) + add_child_str(type_tree, ofp_packet_out_buffer_id, tvb, &offset, 4, "None"); + else { + snprintf(str, STR_LEN, "%u", buffer_id); + add_child_str(type_tree, ofp_packet_out_buffer_id, tvb, &offset, 4, str); + } + + /* display in port */ + // FIXME: bug in dissect_port for latest version + dissect_port(type_tree, ofp_packet_out_in_port, tvb, &offset); + + /* pull out actions len */ + guint16 actions_len = tvb_get_ntohs( tvb, offset); + add_child(type_tree, ofp_packet_out_actions_len, tvb, &offset, 2); + + /* dissect action array; will handle no-action case */ + dissect_action_array(tvb, pinfo, type_tree, offset + actions_len, offset); + offset += actions_len; + + /* if buffer id == -1, then display the provided packet */ + if( buffer_id == -1 ) { + /* continue the dissection with the Ethernet dissector */ + guint total_len = len - offset; + if( data_ethernet ) { + proto_item *data_item = proto_tree_add_item(type_tree, ofp_packet_out_data_hdr, tvb, offset, -1, FALSE); + proto_tree *data_tree = proto_item_add_subtree(data_item, ett_ofp_packet_out_data_hdr); + tvbuff_t *next_tvb = tvb_new_subset(tvb, offset, -1, total_len); + dissect_ethernet(next_tvb, pinfo, data_tree); + } + else { + /* if we couldn't load the ethernet dissector, just display the bytes */ + add_child(type_tree, ofp_packet_out_data_hdr, tvb, &offset, total_len); + } + } + + break; + } + + case OFPT_FLOW_MOD: { + type_item = proto_tree_add_item(ofp_tree, ofp_flow_mod, tvb, offset, -1, FALSE); + type_tree = proto_item_add_subtree(type_item, ett_ofp_flow_mod); + + dissect_match(type_tree, type_item, tvb, pinfo, &offset); + add_child(type_tree, ofp_flow_mod_cookie, tvb, &offset, 8); + add_child(type_tree, ofp_flow_mod_command, tvb, &offset, 2); + add_child(type_tree, ofp_flow_mod_idle_timeout, tvb, &offset, 2); + add_child(type_tree, ofp_flow_mod_hard_timeout, tvb, &offset, 2); + add_child(type_tree, ofp_flow_mod_priority, tvb, &offset, 2); + + /* get buffer_id value for later use */ + guint32 buffer_id = tvb_get_ntohl( tvb, offset ); + + if( buffer_id == 0xFFFFFFFF ) + add_child_str(type_tree, ofp_flow_mod_buffer_id, tvb, &offset, 4, "None"); + else { + snprintf(str, STR_LEN, "%u", buffer_id); + add_child_str(type_tree, ofp_flow_mod_buffer_id, tvb, &offset, 4, str); + } + + /* add the output port */ + dissect_port(type_tree, ofp_flow_mod_out_port, tvb, &offset ); + dissect_flow_mod_flags(tvb, pinfo, type_tree, &offset); + dissect_action_array(tvb, pinfo, type_tree, len, offset); + break; + } + + case OFPT_PORT_MOD: { + type_item = proto_tree_add_item(ofp_tree, ofp_port_mod, tvb, offset, -1, FALSE); + type_tree = proto_item_add_subtree(type_item, ett_ofp_port_mod); + + dissect_port_mod(type_tree, type_item, tvb, pinfo, &offset); + break; + } + + case OFPT_STATS_REQUEST: { + type_item = proto_tree_add_item(ofp_tree, ofp_stats_request, tvb, offset, -1, FALSE); + type_tree = proto_item_add_subtree(type_item, ett_ofp_stats_request); + + guint16 type = tvb_get_ntohs( tvb, offset ); + add_child(type_tree, ofp_stats_request_type, tvb, &offset, 2); + add_child(type_tree, ofp_stats_request_flags, tvb, &offset, 2); + + switch( type ) { + case OFPST_FLOW: { + proto_item *flow_item = proto_tree_add_item(type_tree, ofp_flow_stats_request, tvb, offset, -1, FALSE); + proto_tree *flow_tree = proto_item_add_subtree(flow_item, ett_ofp_flow_stats_request); + + dissect_match(flow_tree, flow_item, tvb, pinfo, &offset); + + guint8 id = tvb_get_guint8( tvb, offset ); + if( id == 0xFF ) + add_child_str(flow_tree, ofp_flow_stats_request_table_id, tvb, &offset, 1, "All Tables"); + else { + snprintf(str, STR_LEN, "%u", id); + add_child_str(flow_tree, ofp_flow_stats_request_table_id, tvb, &offset, 1, str); + } + + dissect_pad(flow_tree, &offset, 1); + dissect_port(flow_tree, ofp_flow_stats_request_out_port, tvb, &offset ); + break; + } + + case OFPST_AGGREGATE: { + proto_item *aggr_item = proto_tree_add_item(type_tree, ofp_aggr_stats_request, tvb, offset, -1, FALSE); + proto_tree *aggr_tree = proto_item_add_subtree(aggr_item, ett_ofp_aggr_stats_request); + + dissect_match(aggr_tree, aggr_item, tvb, pinfo, &offset); + + guint8 id = tvb_get_guint8( tvb, offset ); + if( id == 0xFF ) + add_child_str(aggr_tree, ofp_aggr_stats_request_table_id, tvb, &offset, 1, "All Tables"); + else { + snprintf(str, STR_LEN, "%u", id); + add_child_str(aggr_tree, ofp_aggr_stats_request_table_id, tvb, &offset, 1, str); + } + + dissect_pad(aggr_tree, &offset, 3); + break; + } + + case OFPST_TABLE: + /* no body for these types of requests */ + break; + + case OFPST_PORT:{ + if (len - offset > 0) { + proto_item *port_item = proto_tree_add_item(type_tree, ofp_port_stats_request, tvb, offset, -1, FALSE); + proto_tree *port_tree = proto_item_add_subtree(port_item, ett_ofp_port_stats_request); + dissect_port(port_tree, ofp_port_stats_request_port_no, tvb, &offset); + dissect_pad(port_tree, &offset, 6); + } + } + break; + + case OFPST_QUEUE: { + proto_item *queue_item = proto_tree_add_item(type_tree, ofp_queue_stats_request, tvb, offset, -1, FALSE); + proto_tree *queue_tree = proto_item_add_subtree(queue_item, ett_ofp_queue_stats_request); + + dissect_port(queue_tree, ofp_queue_stats_port_no, tvb, &offset); + dissect_pad(queue_tree, &offset, 2); + dissect_queue_id(queue_tree, ofp_queue_stats_queue_id, tvb, &offset); + break; + } + + default: + /* add as bytes if type isn't one we know how to dissect */ + add_child(type_tree, ofp_stats_request_body, tvb, &offset, len - offset); + } + + break; + } + + case OFPT_STATS_REPLY: { + type_item = proto_tree_add_item(ofp_tree, ofp_stats_reply, tvb, offset, -1, FALSE); + type_tree = proto_item_add_subtree(type_item, ett_ofp_stats_reply); + + guint16 type = tvb_get_ntohs( tvb, offset ); + add_child(type_tree, ofp_stats_reply_type, tvb, &offset, 2); + add_child(type_tree, ofp_stats_reply_flags, tvb, &offset, 2); + + switch( type ) { + + case OFPST_DESC: { + // FIXME: add desc stats + proto_item* desc_item = proto_tree_add_item(type_tree, ofp_desc_stats, tvb, offset, -1, FALSE); + proto_tree* desc_tree = proto_item_add_subtree(desc_item, ett_ofp_desc_stats); + + add_child( desc_tree, ofp_desc_stats_mfr_desc, tvb, &offset, DESC_STR_LEN ); + add_child( desc_tree, ofp_desc_stats_hw_desc, tvb, &offset, DESC_STR_LEN ); + add_child( desc_tree, ofp_desc_stats_sw_desc, tvb, &offset, DESC_STR_LEN ); + add_child( desc_tree, ofp_desc_stats_serial_num, tvb, &offset, SERIAL_NUM_LEN ); + add_child( desc_tree, ofp_desc_stats_dp_desc, tvb, &offset, DESC_STR_LEN ); + + break; + } + + case OFPST_FLOW: { + /* process each flow stats struct in the packet */ + while( offset < len ) { + proto_item* flow_item = proto_tree_add_item(type_tree, ofp_flow_stats_reply, tvb, offset, -1, FALSE); + proto_tree* flow_tree = proto_item_add_subtree(flow_item, ett_ofp_flow_stats_reply); + + /* just get the length of this part of the packet; no need + to put it in the tree */ + guint16 total_len = tvb_get_ntohs( tvb, offset ); + guint offset_start = offset; + offset += 2; + + add_child(flow_tree, ofp_flow_stats_reply_table_id, tvb, &offset, 1); + dissect_pad(flow_tree, &offset, 1); + dissect_match(flow_tree, flow_item, tvb, pinfo, &offset); + add_child(flow_tree, ofp_flow_stats_reply_duration_sec, tvb, &offset, 4); + add_child(flow_tree, ofp_flow_stats_reply_duration_nsec, tvb, &offset, 4); + add_child(flow_tree, ofp_flow_stats_reply_priority, tvb, &offset, 2); + add_child(flow_tree, ofp_flow_stats_reply_idle_timeout, tvb, &offset, 2); + add_child(flow_tree, ofp_flow_stats_reply_hard_timeout, tvb, &offset, 2); + dissect_pad(flow_tree, &offset, 6); + add_child(flow_tree, ofp_flow_stats_reply_cookie, tvb, &offset, 8); + add_child(flow_tree, ofp_flow_stats_reply_packet_count, tvb, &offset, 8); + add_child(flow_tree, ofp_flow_stats_reply_byte_count, tvb, &offset, 8); + + /* parse the actions for this flow */ + dissect_action_array(tvb, pinfo, flow_tree, total_len + offset_start, offset); + offset = total_len + offset_start; + } + break; + } + + case OFPST_AGGREGATE: { + proto_item* aggr_item = proto_tree_add_item(type_tree, ofp_aggr_stats_reply, tvb, offset, -1, FALSE); + proto_tree* aggr_tree = proto_item_add_subtree(aggr_item, ett_ofp_aggr_stats_reply); + + add_child(aggr_tree, ofp_aggr_stats_reply_packet_count, tvb, &offset, 8); + add_child(aggr_tree, ofp_aggr_stats_reply_byte_count, tvb, &offset, 8); + add_child(aggr_tree, ofp_aggr_stats_reply_flow_count, tvb, &offset, 4); + + dissect_pad(aggr_tree, &offset, 4); + break; + } + + case OFPST_TABLE: { + /* process each table stats struct in the packet */ + while( offset < len ) { + proto_item *table_item = proto_tree_add_item(type_tree, ofp_table_stats, tvb, offset, -1, FALSE); + proto_tree *table_tree = proto_item_add_subtree(table_item, ett_ofp_table_stats); + + add_child(table_tree, ofp_table_stats_table_id, tvb, &offset, 1); + dissect_pad(table_tree, &offset, 3); + add_child( table_tree, ofp_table_stats_name, tvb, &offset, OFP_MAX_TABLE_NAME_LEN); + dissect_wildcards(table_tree, table_item, tvb, pinfo, &offset, ofp_table_stats_wildcards); + add_child(table_tree, ofp_table_stats_max_entries, tvb, &offset, 4); + add_child(table_tree, ofp_table_stats_active_count, tvb, &offset, 4); + add_child(table_tree, ofp_table_stats_lookup_count, tvb, &offset, 8); + add_child(table_tree, ofp_table_stats_matched_count, tvb, &offset, 8); + } + break; + } + + case OFPST_PORT: { + /* process each port stats struct in the packet */ + while( offset < len ) { + proto_item *port_item = proto_tree_add_item(type_tree, ofp_port_stats, tvb, offset, -1, FALSE); + proto_tree *port_tree = proto_item_add_subtree(port_item, ett_ofp_port_stats); + + dissect_port(port_tree, ofp_port_stats_port_no, tvb, &offset); + dissect_pad(port_tree, &offset, 6); + add_child(port_tree, ofp_port_stats_rx_packets, tvb, &offset, 8); + add_child(port_tree, ofp_port_stats_tx_packets, tvb, &offset, 8); + add_child(port_tree, ofp_port_stats_rx_bytes, tvb, &offset, 8); + add_child(port_tree, ofp_port_stats_tx_bytes, tvb, &offset, 8); + add_child(port_tree, ofp_port_stats_rx_dropped, tvb, &offset, 8); + add_child(port_tree, ofp_port_stats_tx_dropped, tvb, &offset, 8); + add_child(port_tree, ofp_port_stats_rx_errors, tvb, &offset, 8); + add_child(port_tree, ofp_port_stats_tx_errors, tvb, &offset, 8); + add_child(port_tree, ofp_port_stats_rx_frame_err, tvb, &offset, 8); + add_child(port_tree, ofp_port_stats_rx_over_err, tvb, &offset, 8); + add_child(port_tree, ofp_port_stats_rx_crc_err, tvb, &offset, 8); + add_child(port_tree, ofp_port_stats_collisions, tvb, &offset, 8); + } + break; + } + + case OFPST_QUEUE: { + /* process each port stats struct in the packet */ + while( offset < len ) { + proto_item *queue_item = proto_tree_add_item(type_tree, ofp_queue_stats, tvb, offset, -1, FALSE); + proto_tree *queue_tree = proto_item_add_subtree(queue_item, ett_ofp_queue_stats); + + dissect_port(queue_tree, ofp_queue_stats_port_no, tvb, &offset); + dissect_pad(queue_tree, &offset, 2); + dissect_queue_id(queue_tree, ofp_queue_stats_queue_id, tvb, &offset); + add_child(queue_tree, ofp_queue_stats_tx_bytes, tvb, &offset, 8); + add_child(queue_tree, ofp_queue_stats_tx_packets, tvb, &offset, 8); + add_child(queue_tree, ofp_queue_stats_tx_errors, tvb, &offset, 8); + } + break; + } + + case OFPST_VENDOR: { + proto_item* vendor_item = proto_tree_add_item(type_tree, ofp_vendor_stats, tvb, offset, -1, FALSE); + proto_tree* vendor_tree = proto_item_add_subtree(vendor_item, ett_ofp_vendor_stats); + + add_child(vendor_tree, ofp_vendor_stats_vendor, tvb, &offset, 4); + add_child(vendor_tree, ofp_vendor_stats_body, tvb, &offset, len - offset); + + break; + } + + default: + /* add as bytes if type isn't one we know how to dissect */ + add_child(type_tree, ofp_stats_reply_body, tvb, &offset, len - offset); + } + + break; + } + + default: + /* add a warning if we encounter an unrecognized packet type */ + snprintf(str, STR_LEN, "Dissector does not recognize type %u", type); + add_child_str(tree, ofp_header_warn_type, tvb, &offset, len - offset, str); + } + } +} + +static void dissect_openflow(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + /* have wireshark reassemble our PDUs; call dissect_openflow_when full PDU assembled */ + tcp_dissect_pdus(tvb, pinfo, tree, TRUE, 4, get_openflow_message_len, dissect_openflow_message); +} diff --git a/openflow/utilities/wireshark_dissectors/openflow/plugin.c b/openflow/utilities/wireshark_dissectors/openflow/plugin.c new file mode 100644 index 00000000..deb99c25 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/openflow/plugin.c @@ -0,0 +1,28 @@ +/* Do not modify this file. */ +/* It is created automatically by the Makefile. */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "moduleinfo.h" + +#ifndef ENABLE_STATIC +G_MODULE_EXPORT const gchar version[] = VERSION; + +/* Start the functions we need for the plugin stuff */ + +G_MODULE_EXPORT void +plugin_register (void) +{ + {extern void proto_register_openflow (void); proto_register_openflow ();} +} + +G_MODULE_EXPORT void +plugin_reg_handoff(void) +{ + {extern void proto_reg_handoff_openflow (void); proto_reg_handoff_openflow ();} +} +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/airpcap.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/airpcap.h new file mode 100644 index 00000000..639a930a --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/airpcap.h @@ -0,0 +1,907 @@ +/* + * Copyright (c) 2006-2007 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#if !defined(AIRPCAP_H__EAE405F5_0171_9592_B3C2_C19EC426AD34__INCLUDED_) +#define AIRPCAP_H__EAE405F5_0171_9592_B3C2_C19EC426AD34__INCLUDED_ + +#ifdef _MSC_VER +// This disables a VS warning for zero-sized arrays. +#pragma warning( disable : 4200) +// This stops VS2005 ranting against stdio. +#pragma warning( disable : 4996) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + \mainpage AirPcap interface documentation + + \section Introduction + + This document describes the data structures and the functions exported by the CACE Technologies AirPcap library. + The AirPcap library provides low-level access to the AirPcap driver including advanced capabilities such as channel setting, + link type control and WEP configuration.
+ This manual includes the following sections: + + \note throughout this documentation, \e device refers to a physical USB AirPcap device, while \e adapter is an open API + instance. Most of the AirPcap API operations are adapter-specific but some of them, like setting the channel, are + per-device and will be reflected on all the open adapters. These functions will have "Device" in their name, e.g. + AirpcapSetDeviceChannel(). + + \b Sections: + + - \ref airpcapfuncs + - \ref airpcapdefs + - \ref radiotap +*/ + +/** @defgroup airpcapdefs AirPcap definitions and data structures + * @{ + */ + +/*! + \brief This string is the fixed prefix in the airpcap adapter name. + It can be used to parse the name field in an AirpcapDeviceDescription structure. +*/ +#define AIRPCAP_DEVICE_NAME_PREFIX "\\\\.\\airpcap" + +/*! + \brief This string is the scanf modifier to extract the adapter number from an adapter name. + It can be used to parse the name field in an AirpcapDeviceDescription structure with scanf. +*/ +#define AIRPCAP_DEVICE_NUMBER_EXTRACT_STRING "\\\\.\\airpcap%u" + +#define AIRPCAP_DEVICE_ANY_EXTRACT_STRING "\\\\.\\airpcap_any" + +/*! + \brief Entry in the list returned by \ref AirpcapGetDeviceList(); +*/ +typedef struct _AirpcapDeviceDescription +{ + struct _AirpcapDeviceDescription *next; ///< Next element in the list + PCHAR Name; ///< Device name + PCHAR Description; ///< Device description +} AirpcapDeviceDescription, *PAirpcapDeviceDescription; + +#define MAX_ENCRYPTION_KEYS 64 + +#define WEP_KEY_MAX_SIZE 32 ///< Maximum size of a WEP key, in bytes. This is the size of an entry in the + ///< AirpcapWepKeysCollection structure + +#ifndef __MINGW32__ +#pragma pack(push) +#pragma pack(1) +#endif // __MINGW32__ + + +#define AIRPCAP_KEYTYPE_WEP 0 ///< Key type: WEP. The key can have an arbitrary length smaller than 32 bytes. +#define AIRPCAP_KEYTYPE_TKIP 1 ///< Key type: TKIP (WPA). NOT SUPPORTED YET. +#define AIRPCAP_KEYTYPE_CCMP 2 ///< Key type: CCMP (WPA2). NOT SUPPORTED YET. + +/*! + \brief WEP key container +*/ +typedef struct _AirpcapKey +{ + UINT KeyType; ///< Type of key, can be on of: \ref AIRPCAP_KEYTYPE_WEP, \ref AIRPCAP_KEYTYPE_TKIP, \ref AIRPCAP_KEYTYPE_CCMP. Only AIRPCAP_KEYTYPE_WEP is supported by the driver at the moment. + UINT KeyLen; ///< Length of the key, in bytes + BYTE KeyData[WEP_KEY_MAX_SIZE]; ///< Key Data +} +#ifdef __MINGW32__ +__attribute__((__packed__)) +#endif // __MINGW32__ +AirpcapKey, *PAirpcapKey; + +/*! + \brief frequency Band. + 802.11 adapters can support different frequency bands, the most important of which are: 2.4GHz (802.11b/g/n) + and 5GHz (802.11a/n). +*/ +typedef enum _AirpcapChannelBand +{ + AIRPCAP_CB_AUTO = 1, ///< Automatically pick the best frequency band + AIRPCAP_CB_2_4_GHZ = 2, ///< 2.4 GHz frequency band + AIRPCAP_CB_4_GHZ = 4, ///< 4 GHz frequency band + AIRPCAP_CB_5_GHZ = 5 ///< 5 GHz frequency band +}AirpcapChannelBand, *PAirpcapChannelBand; + +/*! + \brief Type of frame validation the adapter performs. + An adapter can be instructed to accept different kind of frames: correct frames only, frames with wrong Frame Check Sequence (FCS) only, all frames. +*/ +typedef enum _AirpcapValidationType +{ + AIRPCAP_VT_ACCEPT_EVERYTHING = 1, ///< Accept all the frames the device captures + AIRPCAP_VT_ACCEPT_CORRECT_FRAMES = 2, ///< Accept correct frames only, i.e. frames with correct Frame Check Sequence (FCS). + AIRPCAP_VT_ACCEPT_CORRUPT_FRAMES = 3, ///< Accept corrupt frames only, i.e. frames with worng Frame Check Sequence (FCS). + AIRPCAP_VT_UNKNOWN = 4 ///< Unknown validation type. You should see it only in case of error. +}AirpcapValidationType, *PAirpcapValidationType; + +/*! + \brief Type of decryption the adapter performs. + An adapter can be instructed to turn decryption (based on the device-configured keys configured + with \ref AirpcapSetDeviceKeys()) on or off. +*/ +typedef enum _AirpcapDecryptionState +{ + AIRPCAP_DECRYPTION_ON = 1, ///< This adapter performs decryption + AIRPCAP_DECRYPTION_OFF = 2 ///< This adapter does not perform decryption +}AirpcapDecryptionState, *PAirpcapDecryptionState; + + +/*! + \brief Storage for a MAC address +*/ +typedef struct _AirpcapMacAddress +{ + BYTE Address[6]; ///< MAC address bytes +} +#ifdef __MINGW32__ +__attribute__((__packed__)) +#endif // __MINGW32__ +AirpcapMacAddress, *PAirpcapMacAddress; + +/*! + \brief This structure is used to store a collection of WEP keys. + Note that the definition of the structure doesn't contain any key, so be careful to allocate a buffer + with the size of the key, like in the following example: + + \code + PAirpcapKeysCollection KeysCollection; + UINT KeysCollectionSize; + + KeysCollectionSize = sizeof(AirpcapKeysCollection) + NumKeys * sizeof(AirpcapKey); + + KeysCollection = (PAirpcapKeysCollection)malloc(KeysCollectionSize); + if(!KeysCollection) + { + // Error + } + \endcode +*/ +typedef struct _AirpcapKeysCollection +{ + UINT nKeys; ///< Number of keys in the collection + AirpcapKey Keys[0]; ///< Array of nKeys keys. +} AirpcapKeysCollection, *PAirpcapKeysCollection; + +/*! + \brief Packet header. + + This structure defines the BPF that preceeds every packet delivered to the application. +*/ +typedef struct _AirpcapBpfHeader +{ + UINT TsSec; ///< Timestamp associated with the captured packet. SECONDS. + UINT TsUsec; ///< Timestamp associated with the captured packet. MICROSECONDS. + UINT Caplen; ///< Length of captured portion. The captured portion can be different from the original packet, because it is possible (with a proper filter) to instruct the driver to capture only a portion of the packets. + UINT Originallen; ///< Original length of packet + USHORT Hdrlen; ///< Length of bpf header (this struct plus alignment padding). In some cases, a padding could be added between the end of this structure and the packet data for performance reasons. This field can be used to retrieve the actual data of the packet. +} +#ifdef __MINGW32__ +__attribute__((__packed__)) +#endif // __MINGW32__ +AirpcapBpfHeader, *PAirpcapBpfHeader; + +/// Helper macros to extract packets coming from the driver. Rounds up to the next even multiple of AIRPCAP_ALIGNMENT. +#define AIRPCAP_ALIGNMENT sizeof(int) +#define AIRPCAP_WORDALIGN(x) (((x)+(AIRPCAP_ALIGNMENT-1))&~(AIRPCAP_ALIGNMENT-1)) + +#ifndef __MINGW32__ +#pragma pack(pop) +#endif // __MINGW32__ + +#define AIRPCAP_ERRBUF_SIZE 512 ///< Size of the error buffer, in bytes + +#ifndef __AIRPCAP_DRIVER__ + +/*! + \brief Link type. + AirPcap supports two kind of 802.11 linktypes: plain 802.11 and radiotap. +*/ +#undef _AirpcapLinkType +typedef enum _AirpcapLinkType +{ + AIRPCAP_LT_802_11 = 1, ///< plain 802.11 linktype. Every packet in the buffer contains the raw 802.11 frame, including MAC FCS. + AIRPCAP_LT_802_11_PLUS_RADIO = 2, ///< 802.11 plus radiotap linktype. Every packet in the buffer contains a radiotap header followed by the 802.11 frame. MAC FCS is included. + AIRPCAP_LT_UNKNOWN = 3, ///< Unknown linktype. You should see it only in case of error. + AIRPCAP_LT_802_11_PLUS_PPI = 4 ///< 802.11 plus PPI header linktype. Every packet in the buffer contains a PPI header followed by the 802.11 frame. MAC FCS is included. +}AirpcapLinkType, *PAirpcapLinkType; + +#if !defined(AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_) +#define AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_ +/*! + \brief Adapter handle. +*/ +typedef struct _AirpcapHandle AirpcapHandle, *PAirpcapHandle; +#endif + +/*! + \brief Capture statistics. + Returned by \ref AirpcapGetStats(); +*/ +typedef struct _AirpcapStats +{ + UINT Recvs; ///< Number of packets that the driver received by the adapter + ///< from the beginning of the current capture. This value includes the packets + ///< dropped because of buffer full. + UINT Drops; ///< number of packets that the driver dropped from the beginning of a capture. + ///< A packet is lost when the the buffer of the driver is full. + UINT IfDrops; ///< Packets dropped by the card before going to the USB bus. + ///< Not supported at the moment. + UINT Capt; ///< number of packets that pass the BPF filter, find place in the kernel buffer and + ///< therefore reach the application. +}AirpcapStats, *PAirpcapStats; + +/*! + \brief Channel information. + Used by \ref AirpcapSetDeviceChannelEx(), \ref AirpcapGetDeviceChannelEx(), \ref AirpcapGetDeviceSupportedChannels() +*/ +typedef struct _AirpcapChannelInfo +{ + UINT Frequency; ///< Channel frequency, in MHz. + /*! + \brief 802.11n specific. Offset of the extension channel in case of 40MHz channels. + + Possible values are -1, 0 +1: + - -1 means that the extension channel should be below the control channel (e.g. Control = 5 and Extension = 1) + - 0 means that no extension channel should be used (20MHz channels or legacy mode) + - +1 means that the extension channel should be above the control channel (e.g. Control = 1 and Extension = 5) + + In case of 802.11a/b/g channels (802.11n legacy mode), this field should be set to 0. + */ + CHAR ExtChannel; + UCHAR Reserved[3]; ///< Reserved. It should be set to {0,0,0}. +} + AirpcapChannelInfo, *PAirpcapChannelInfo; + + +/*@}*/ + +/** @defgroup airpcapfuncs AirPcap functions + * @{ + */ + +/*! + \brief Return a string with the API version + \param VersionMajor Pointer to a variable that will be filled with the major version number. + \param VersionMinor Pointer to a variable that will be filled with the minor version number. + \param VersionRev Pointer to a variable that will be filled with the revision number. + \param VersionBuild Pointer to a variable that will be filled with the build number. +*/ +void AirpcapGetVersion(PUINT VersionMajor, PUINT VersionMinor, PUINT VersionRev, PUINT VersionBuild); + +/*! + \brief Return the last error related to the specified handle + \param AdapterHandle Handle to an open adapter. + \return The string with the last error. +*/ +PCHAR AirpcapGetLastError(PAirpcapHandle AdapterHandle); + +/*! + \brief Return the list of available devices + \param PPAllDevs Address to a caller allocated pointer. On success this pointer will receive the head of a list of available devices. + \param Ebuf String that will contain error information if FALSE is returned. The size of the string must be AIRPCAP_ERRBUF_SIZE bytes. + \return TRUE on success. FALSE is returned on failure, in which case Ebuf is filled in with an appropriate error message. + + Here's a snippet of code that shows how to use AirpcapGetDeviceList(): + + \code + CHAR Ebuf[AIRPCAP_ERRBUF_SIZE]; + AirpcapDeviceDescription *Desc, *tDesc; + + if(AirpcapGetDeviceList(&Desc, Ebuf) == -1) + { + printf("Unable to get the list of devices: %s\n", Ebuf); + return -1; + } + + for(tDesc = Desc; tDesc; tDesc = tDesc->next) + { + printf("%u) %s (%s)\n", + ++i, + tDesc->Name, + tDesc->Description); + } + + AirpcapFreeDeviceList(Desc); + \endcode +*/ +BOOL AirpcapGetDeviceList(PAirpcapDeviceDescription *PPAllDevs, PCHAR Ebuf); + +/*! + \brief Free a list of devices returned by AirpcapGetDeviceList() + \param PAllDevs Head of the list of devices returned by \ref AirpcapGetDeviceList(). +*/ +VOID AirpcapFreeDeviceList(PAirpcapDeviceDescription PAllDevs); + +/*! + \brief Open an adapter + \param DeviceName Name of the device to open. Use \ref AirpcapGetDeviceList() to get the list of devices. + \param Ebuf String that will contain error information in case of failure. The size of the string must be AIRPCAP_ERRBUF_SIZE bytes. + \return A PAirpcapHandle handle on success. NULL is returned on failure, in which case Ebuf is filled in with an appropriate error message. +*/ +PAirpcapHandle AirpcapOpen(PCHAR DeviceName, PCHAR Ebuf); + +/*! + \brief Close an adapter + \param AdapterHandle Handle to the adapter to close. +*/ +VOID AirpcapClose(PAirpcapHandle AdapterHandle); + +/*! + \brief Sets the monitor mode for the specified adapter + \param AdapterHandle Handle to the adapter. + \param MonitorModeEnabled If TRUE, the adapter will be put in monitor mode. If FALSE, the adapter will be configured + for normal operation. + \return TRUE on success. + + When monitor mode is on, the adapter captures all the packets transmitted on the channel. This includes: + + - unicast packets + - multicast packets + - broadcast packets + - control and management packets + + When monitor mode is off, the adapter has a filter on unicast packets to capture only the packets whose MAC + destination address equals to the adapter's address. This means the following frames will be received: + + - unicast packets with the address of the adapter + - multicast packets + - broadcast packets + - beacons and probe requests + + The main reason to turn monitor mode off is that, when not in monitor mode, the adapter will acknowledge the + data frames sent to its address. This is useful when the adapter needs to interact with other devices on the + 802.11 network, bacause handling the ACKs in software is too slow. + + \note When an adapter is plugged into the system, it's always configured with monitor mode ON. The monitor mode + configuration is not stored persistently, so if you want to turn monitor mode off, you will need to do it + every time you open the adapter. +*/ +BOOL AirpcapSetMonitorMode(PAirpcapHandle AdapterHandle, BOOL MonitorModeEnabled); + +/*! + \brief Returns TRUE if the specified adapter is in monitor mode. + \param AdapterHandle Handle to the adapter. + \param PMonitorModeEnabled User-provided variable that will be set to true if the adapter is in monitor mode. + \return TRUE if the operation is successful. FALSE otherwise. + + \note When an adapter is plugged into the system, it's always configured with monitor mode ON. The monitor mode + configuration is not stored persistently, so if you want to turn monitor mode off, you will need to do it + every time you open the adapter. +*/ +BOOL AirpcapGetMonitorMode(PAirpcapHandle AdapterHandle, PBOOL PMonitorModeEnabled); + +/*! + \brief Set the link type of an adapter + \param AdapterHandle Handle to the adapter. + \param NewLinkType the "link type", i.e. the format of the frames that will be received from the adapter. + \return TRUE on success. + + the "link type" determines how the driver will encode the packets captured from the network. + Aircap supports two link types: + - \ref AIRPCAP_LT_802_11, to capture 802.11 frames (including control frames) without any + power information. Look at the Capture_no_radio example application in the developer's pack + for a reference on how to decode 802.11 frames with this link type. + - \ref AIRPCAP_LT_802_11_PLUS_RADIO, to capture 802.11 frames (including control frames) with a radiotap header + that contains power and channel information. More information about the radiotap header can be found in the + \ref radiotap section. Moreover, the "Capture_radio" example application in + the developer's pack can be used as a reference on how to decode 802.11 frames with radiotap headers. + - \ref AIRPCAP_LT_802_11_PLUS_PPI, to capture 802.11 frames (including control frames) with a Per Packet Information (PPI) + header that contains per-packet meta information like channel and power information. More details on the PPI header can + be founf in the PPI online documentation (TODO). +*/ +BOOL AirpcapSetLinkType(PAirpcapHandle AdapterHandle, AirpcapLinkType NewLinkType); + +/*! + \brief Get the link type of the specified adapter + \param AdapterHandle Handle to the adapter. + \param PLinkType Pointer to a caller allocated AirpcapLinkType variable that will contain the link type of the adapter. + \return TRUE on success. + + the "link type" determines how the driver will encode the packets captured from the network. + Aircap supports two link types: + - AIRPCAP_LT_802_11, to capture 802.11 frames (including control frames) without any + power information. Look at the Capture_no_radio example application in the developer's pack + for a reference on how to decode 802.11 frames with this link type. + - AIRPCAP_LT_802_11_PLUS_RADIO, to capture 802.11 frames (including control frames) with a radiotap header + that contains power and channel information. More information about the radiotap header can be found int the + \ref radiotap section. Moreover, the "Capture_radio" example application in + the developer's pack can be used as a reference on how to decode 802.11 frames with radiotap headers. +*/ +BOOL AirpcapGetLinkType(PAirpcapHandle AdapterHandle, PAirpcapLinkType PLinkType); + +/*! + \brief Configures the adapter on whether to include the MAC Frame Check Sequence in the captured packets. + \param AdapterHandle Handle to the adapter. + \param IsFcsPresent TRUE if the packets should include the FCS. FALSE otherwise + \return TRUE on success. + + In the default configuration, the adapter includes the FCS in the captured packets. The MAC Frame Check Sequence + is 4 bytes and is located at the end of the 802.11 packet, with both AIRPCAP_LT_802_11 and AIRPCAP_LT_802_11_PLUS_RADIO + link types. + When the FCS inclusion is turned on, and if the link type is AIRPCAP_LT_802_11_PLUS_RADIO, the radiotap header + that precedes each frame has two additional fields at the end: Padding and FCS. These two fields are not present + when FCS inclusion is off. +*/ +BOOL AirpcapSetFcsPresence(PAirpcapHandle AdapterHandle, BOOL IsFcsPresent); + +/*! + \brief Returns TRUE if the specified adapter includes the MAC Frame Check Sequence in the captured packets + \param AdapterHandle Handle to the adapter. + \param PIsFcsPresent User-provided variable that will be set to true if the adapter is including the FCS. + \return TRUE if the operation is successful. FALSE otherwise. + + In the default configuration, the adatper has FCS inclusion turned on. The MAC Frame Check Sequence is 4 bytes + and is located at the end of the 802.11 packet, with both AIRPCAP_LT_802_11 and AIRPCAP_LT_802_11_PLUS_RADIO + link types. + When the FCS inclusion is turned on, and if the link type is AIRPCAP_LT_802_11_PLUS_RADIO, the radiotap header + that precedes each frame has two additional fields at the end: Padding and FCS. These two fields are not present + when FCS inclusion is off. +*/ +BOOL AirpcapGetFcsPresence(PAirpcapHandle AdapterHandle, PBOOL PIsFcsPresent); + +/*! + \brief Configures the adapter to accept or drop frames with an incorrect Frame Check sequence (FCS). + \param AdapterHandle Handle to the adapter. + \param ValidationType The type of validation the driver will perform. See the documentation of \ref AirpcapValidationType for details. + \return TRUE on success. + + \note By default, the driver is configured in \ref AIRPCAP_VT_ACCEPT_EVERYTHING mode. +*/ +BOOL AirpcapSetFcsValidation(PAirpcapHandle AdapterHandle, AirpcapValidationType ValidationType); + +/*! + \brief Checks if the specified adapter is configured to capture frames with incorrect an incorrect Frame Check Sequence (FCS). + \param AdapterHandle Handle to the adapter. + \param ValidationType Pointer to a user supplied variable that will contain the type of validation the driver will perform. See the documentation of \ref AirpcapValidationType for details. + \return TRUE if the operation is succesful. FALSE otherwise. + + \note By default, the driver is configured in \ref AIRPCAP_VT_ACCEPT_EVERYTHING mode. +*/ +BOOL AirpcapGetFcsValidation(PAirpcapHandle AdapterHandle, PAirpcapValidationType ValidationType); + +/*! + \brief Set the list of decryption keys that the driver is going to use with the specified device. + \param AdapterHandle Handle an open adapter instance. + \param KeysCollection Pointer to a \ref PAirpcapKeysCollection structure that contains the keys to be set in the driver. + \return TRUE if the operation is successful. FALSE otherwise. + + The AirPcap driver is able to use a set of decryption keys to decrypt the traffic transmitted on a specific SSID. If one of the + keys corresponds to the one the frame has been encrypted with, the driver will perform decryption and return the cleartext frames + to the application. + + This function allows to set the adapter-specific set of keys. These keys will be used by the specified adapter only, + and will not be used by other airpcap devices besides the specified one. + + At this time, the only supported decryption method is WEP. + + The keys are applied to the packets in the same order they appear in the KeysCollection structure until the packet is + correctly decrypted, therefore putting frequently used keys at the beginning of the structure improves performance. + + \note: when you change the set of keys from an open capture instance, the change will be + immediately reflected on all the other capture instances. +*/ +BOOL AirpcapSetDeviceKeys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection); + +/*! + \brief Returns the list of decryption keys in the driver that are currently associated with the specified device + \param AdapterHandle Handle to an open adapter instance. + \param KeysCollection User-allocated PAirpcapKeysCollection structure that will be filled with the keys. + \param PKeysCollectionSize \b IN: pointer to a user-allocated variable that contains the length of the KeysCollection structure, in bytes. + \b OUT: amount of data moved by the driver in the buffer pointed by KeysBuffer, in bytes. + \return TRUE if the operation is succesful. If an error occurs, the return value is FALSE and KeysCollectionSize is zero. + If the provided buffer is too small to contain the keys, the return value is FALSE and KeysCollectionSize contains the + needed KeysCollection length, in bytes. If the device doesn't have any decryption key configured, the return value is TRUE, and + KeysCollectionSize will be zero. + + This function returns the adapter-specific set of keys. These keys are used by the specified adapter only, + and not by other airpcap devices besides the specified one. + + The AirPcap driver is able to use a set of decryption keys to decrypt the traffic transmitted on a specific SSID. If one of the + keys corresponds to the one the frame has been encrypted with, the driver will perform decryption and return the cleartext frames + to the application. + The driver supports, for every device, multiple keys at the same time. + + The configured decryption keys are device-specific, therefore AirpcapGetDeviceKeys() will return a different set of keys + when called on different devices. + + At this time, the only supported decryption method is WEP. +*/ +BOOL AirpcapGetDeviceKeys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, PUINT PKeysCollectionSize); + +/*! + \brief Set the global list of decryption keys that the driver is going to use with all the devices. + \param AdapterHandle Handle an open adapter instance. + \param KeysCollection Pointer to a \ref PAirpcapKeysCollection structure that contains the keys to be set in the driver. + \return TRUE if the operation is successful. FALSE otherwise. + + The AirPcap driver is able to use a set of decryption keys to decrypt the traffic transmitted on a specific SSID. If one of the + keys corresponds to the one the frame has been encrypted with, the driver will perform decryption and return the cleartext frames + to the application. + + This function allows to set the global driver set of keys. These keys will be used by all the adapters plugged in + the machine. + + At this time, the only supported decryption method is WEP. + + The keys are applied to the packets in the same order they appear in the KeysCollection structure until the packet is + correctly decrypted, therefore putting frequently used keys at the beginning of the structure improves performance. + + \note: when you change the set of keys from an open capture instance, the change will be + immediately reflected on all the other capture instances. +*/ +BOOL AirpcapSetDriverKeys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection); + +/*! + \brief Returns the global list of decryption keys in the driver that are associated with all the devices. + \param AdapterHandle Handle to an open adapter instance. + \param KeysCollection User-allocated PAirpcapKeysCollection structure that will be filled with the keys. + \param PKeysCollectionSize \b IN: pointer to a user-allocated variable that contains the length of the KeysCollection structure, in bytes. + \b OUT: amount of data moved by the driver in the buffer pointed by KeysBuffer, in bytes. + \return TRUE if the operation is succesful. If an error occurs, the return value is FALSE and KeysCollectionSize is zero. + If the provided buffer is too small to contain the keys, the return value is FALSE and KeysCollectionSize contains the + needed KeysCollection length, in bytes. If the device doesn't have any decryption key configured, the return value is TRUE, and + KeysCollectionSize will be zero. + + This function returns the global driver set of keys. These keys will be used by all the adapters plugged in + the machine. + + The AirPcap driver is able to use a set of decryption keys to decrypt the traffic transmitted on a specific SSID. If one of the + keys corresponds to the one the frame has been encrypted with, the driver will perform decryption and return the cleartext frames + to the application. + + At this time, the only supported decryption method is WEP. +*/ +BOOL AirpcapGetDriverKeys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, PUINT PKeysCollectionSize); + +/*! + \brief Turns on or off the decryption of the incoming frames with the adapter-specific keys. + \param AdapterHandle Handle to the adapter. + \param Enable Either \ref AIRPCAP_DECRYPTION_ON or \ref AIRPCAP_DECRYPTION_OFF + \return TRUE on success. + + The adapter-specific decryption keys can be configured with the \ref AirpcapSetDeviceKeys() function. + \note By default, the driver is configured with \ref AIRPCAP_DECRYPTION_ON. +*/ +BOOL AirpcapSetDecryptionState(PAirpcapHandle AdapterHandle, AirpcapDecryptionState Enable); + +/*! + \brief Tells if this open instance is configured to perform the decryption of the incoming frames with the adapter-specific keys. + \param AdapterHandle Handle to the adapter. + \param PEnable Pointer to a user supplied variable that will contain the decryption configuration. See \ref PAirpcapDecryptionState for details. + \return TRUE if the operation is succesful. FALSE otherwise. + + The adapter-specific decryption keys can be configured with the \ref AirpcapSetDeviceKeys() function. + \note By default, the driver is configured with \ref AIRPCAP_DECRYPTION_ON. +*/ +BOOL AirpcapGetDecryptionState(PAirpcapHandle AdapterHandle, PAirpcapDecryptionState PEnable); + +/*! + \brief Turns on or off the decryption of the incoming frames with the global driver set of keys. + \param AdapterHandle Handle to the adapter. + \param Enable Either \ref AIRPCAP_DECRYPTION_ON or \ref AIRPCAP_DECRYPTION_OFF + \return TRUE on success. + + The global decryption keys can be configured with the \ref AirpcapSetDriverKeys() function. + \note By default, the driver is configured with \ref AIRPCAP_DECRYPTION_ON. +*/ +BOOL AirpcapSetDriverDecryptionState(PAirpcapHandle AdapterHandle, AirpcapDecryptionState Enable); + +/*! + \brief Tells if this open instance is configured to perform the decryption of the incoming frames with the global driver set of keys. + \param AdapterHandle Handle to the adapter. + \param PEnable Pointer to a user supplied variable that will contain the decryption configuration. See \ref PAirpcapDecryptionState for details. + \return TRUE if the operation is succesful. FALSE otherwise. + + The global decryption keys can be configured with the \ref AirpcapSetDriverKeys() function. + \note By default, the driver is configured with \ref AIRPCAP_DECRYPTION_ON. +*/ +BOOL AirpcapGetDriverDecryptionState(PAirpcapHandle AdapterHandle, PAirpcapDecryptionState PEnable); + +/*! + \brief Set the radio channel of a device + \param AdapterHandle Handle to the adapter. + \param Channel the new channel to set. + \return TRUE on success. + + The list of available channels can be retrieved with \ref AirpcapGetDeviceSupportedChannels(). The default channel setting is 6. + + \note this is a device-related function: when you change the channel from an open capture instance, the change will be + immediately reflected on all the other capture instances. +*/ +BOOL AirpcapSetDeviceChannel(PAirpcapHandle AdapterHandle, UINT Channel); + +/*! + \brief Get the radio channel of a device + \param AdapterHandle Handle to the adapter. + \param PChannel Pointer to a user-supplied variable into which the function will copy the currently configured radio channel. + \return TRUE on success. + + The list of available channels can be retrieved with \ref AirpcapGetDeviceSupportedChannels(). The default channel setting is 6. + + \note this is a device-related function: when you change the channel from an open capture instance, the change will be + immediately reflected on all the other capture instances. +*/ +BOOL AirpcapGetDeviceChannel(PAirpcapHandle AdapterHandle, PUINT PChannel); + +/*! + \brief Set the size of the kernel packet buffer for this adapter + \param AdapterHandle Handle to the adapter. + \param BufferSize New size, in bytes. + \return TRUE on success. + + Every AirPcap open instance has an associated kernel buffer, whose default size is 1 Mbyte. + This function can be used to change the size of this buffer, and can be called at any time. + A bigger kernel buffer size decreases the risk of dropping packets during network bursts or when the + application is busy, at the cost of higher kernel memory usage. + + \note don't use this function unless you know what you are doing. Due to caching issues and bigger non-paged + memory consumption, bigger buffer sizes can decrease the capture performace instead of improving it. +*/ +BOOL AirpcapSetKernelBuffer(PAirpcapHandle AdapterHandle, UINT BufferSize); + +/*! + \brief Get the size of the kernel packet buffer for this adapter + \param AdapterHandle Handle to the adapter. + \param PSizeBytes User-allocated variable that will be filled with the size of the kernel buffer. + \return TRUE on success. + + Every AirPcap open instance has an associated kernel buffer, whose default size is 1 Mbyte. + This function can be used to get the size of this buffer. +*/ +BOOL AirpcapGetKernelBufferSize(PAirpcapHandle AdapterHandle, PUINT PSizeBytes); + +/*! + \brief Saves the configuration of the specified adapter in the registry, so that it becomes the default for this adapter. + \param AdapterHandle Handle to the adapter. + \return TRUE on success. FALSE on failure. + + Almost all the AirPcap calls that modify the configuration (\ref AirpcapSetLinkType(), \ref AirpcapSetFcsPresence(), + \ref AirpcapSetFcsValidation(), \ref AirpcapSetKernelBuffer(), \ref AirpcapSetMinToCopy()) + affect only the referenced AirPcap open instance. This means that if you do another \ref AirpcapOpen() on the same + adapter, the configuration changes will not be remembered, and the new adapter handle will have default configuration + settings. + + Exceptions to this rule are the \ref AirpcapSetDeviceChannel() and \ref AirpcapSetDeviceKeys() functions: a channel change is + reflected on all the open instances, and remembered until the next call to \ref AirpcapSetDeviceChannel(), until the adapter + is unplugged, or until the machine is powered off. Same thing for the configuration of the WEP keys. + + AirpcapStoreCurConfigAsAdapterDefault() stores the configuration of the give open instance as the default for the adapter: + all the instances opened in the future will have the same configuration that this adapter currently has. + The configuration is stored in the registry, therefore it is remembered even when the adapter is unplugged or the + machine is turned off. However, an adapter doesn't bring its configuration with it from machine to machine. + + the configuration information saved in the registry includes the following parameters: + - channel + - kernel buffer size + - mintocopy + - link type + - CRC presence + - Encryption keys + - Encryption Enabled/Disabled state + + The configuration is adapter-specific. This means that changing the configuration of an adapter + doesn't modify the one of the other adapters that are currently used or that will be used in the future. + + \note AirpcapStoreCurConfigAsAdapterDefault() must have exclusive access to the adapter -- it + will fail if more than one AirPcap handle is opened at the same time for this adapter. + AirpcapStoreCurConfigAsAdapterDefault() needs administrator privileges. It will fail if the calling user + is not a local machine administrator. +*/ +BOOL AirpcapStoreCurConfigAsAdapterDefault(PAirpcapHandle AdapterHandle); + +/*! + \brief Set the BPF kernel filter for an adapter + \param AdapterHandle Handle to the adapter. + \param Instructions pointer to the first BPF instruction in the array. Corresponds to the bf_insns + in a bpf_program structure (see the WinPcap documentation at http://www.winpcap.org/devel.htm). + \param Len Number of instructions in the array pointed by the previous field. Corresponds to the bf_len in + a a bpf_program structure (see the WinPcap documentation at http://www.winpcap.org/devel.htm). + \return TRUE on success. + + The AirPcap driver is able to perform kernel-level filtering using the standard BPF pseudo-machine format. You can read + the WinPcap documentation at http://www.winpcap.org/devel.htm for more details on the BPF filtering mechaism. + + A filter can be automatically created by using the pcap_compile() function of the WinPcap API. This function + converts a human readable text expression with the tcpdump/libpcap syntax into a BPF program. + If your program doesn't link wpcap, but you need to generate the code for a particular filter, you can run WinDump + with the -d or -dd or -ddd flags to obtain the pseudocode. + +*/ +BOOL AirpcapSetFilter(PAirpcapHandle AdapterHandle, PVOID Instructions, UINT Len); + +/*! + \brief Return the MAC address of an adapter. + \param AdapterHandle Handle to the adapter. + \param PMacAddress Pointer to a user allocated MAC address. + The size of this buffer needs to be at least 6 bytes. + \return TRUE on success. +*/ +BOOL AirpcapGetMacAddress(PAirpcapHandle AdapterHandle, PAirpcapMacAddress PMacAddress); + +/*! + \brief Set the mintocopy parameter for an open adapter + \param AdapterHandle Handle to the adapter. + \param MinToCopy is the mintocopy size in bytes. + \return TRUE on success. + + When the number of bytes in the kernel buffer changes from less than mintocopy bytes to greater than or equal to mintocopy bytes, + the read event is signalled (see \ref AirpcapGetReadEvent()). A high value for mintocopy results in poor responsiveness since the + driver may signal the application "long" after the arrival of the packet. And a high value results in low CPU loading + by minimizing the number of user/kernel context switches. + A low MinToCopy results in good responsiveness since the driver will signal the application close to the arrival time of + the packet. This has higher CPU loading over the first approach. +*/ +BOOL AirpcapSetMinToCopy(PAirpcapHandle AdapterHandle, UINT MinToCopy); + +/*! + \brief Gets an event that is signaled when that is signalled when packets are available in the kernel buffer (see \ref AirpcapSetMinToCopy()). + \param AdapterHandle Handle to the adapter. + \param PReadEvent Pointer to a user-supplied handle that in which the read event will be copied. + \return TRUE on success. + + \note the event is signalled when at least mintocopy bytes are present in the kernel buffer (see \ref AirpcapSetMinToCopy()). + This event can be used by WaitForSingleObject() and WaitForMultipleObjects() to create blocking behavior when reading + packets from one or more adapters (see \ref AirpcapRead()). +*/ +BOOL AirpcapGetReadEvent(PAirpcapHandle AdapterHandle, HANDLE* PReadEvent); + +/*! + \brief Fills a user-provided buffer with zero or more packets that have been captured on the referenced adapter. + \param AdapterHandle Handle to the adapter. + \param Buffer pointer to the buffer that will be filled with captured packets. + \param BufSize size of the input buffer that will contain the packets, in bytes. + \param PReceievedBytes Pointer to a user supplied variable that will receive the number of bytes copied by AirpcapRead. + Can be smaller than BufSize. + \return TRUE on success. + + 802.11 frames are returned by the driver in buffers. Every 802.11 frame in the buffer is preceded by a \ref AirpcapBpfHeader structure. + The suggested way to use an AirPcap adapter is through the pcap API exported by wpcap.dll. If this is not + possible, the Capture_radio and Capture_no_radio examples in the AirPcap developer's pack show how to properly decode the + packets in the read buffer returned by AirpcapRead(). + + \note this function is NOT blocking. Blocking behavior can be obtained using the event returned + by \ref AirpcapGetReadEvent(). See also \ref AirpcapSetMinToCopy(). +*/ +BOOL AirpcapRead(PAirpcapHandle AdapterHandle, PBYTE Buffer, UINT BufSize, PUINT PReceievedBytes); + +/*! + \brief Transmits a packet. + \param AdapterHandle Handle to the adapter. + \param TxPacket Pointer to a buffer that contains the packet to be transmitted. + \param PacketLen Length of the buffer pointed by the TxPacket argument, in bytes. + \return TRUE on success. + + The packet will be transmitted on the channel the device is currently set. To change the device adapter, use the + \ref AirpcapSetDeviceChannel() function. + + If the linktype of the adapter is AIRPCAP_LT_802_11, the buffer pointed by TxPacket should contain just the 802.11 + packet, without additional information. The packet will be transmitted at 1Mbps. + + If the linktype of the adapter is AIRPCAP_LT_802_11_PLUS_RADIO, the buffer pointed by TxPacket should contain a radiotap + header followed by the 802.11 packet. AirpcapWrite will use the rate information in the radiotap header when + transmitting the packet. +*/ +BOOL AirpcapWrite(PAirpcapHandle AdapterHandle, PCHAR TxPacket, ULONG PacketLen); + +/*! + \brief Get per-adapter WinPcap-compatible capture statistics. + \param AdapterHandle Handle to the adapter. + \param PStats pointer to a user-allocated AirpcapStats structure that will be filled with statistical information. + \return TRUE on success. +*/ +BOOL AirpcapGetStats(PAirpcapHandle AdapterHandle, PAirpcapStats PStats); + +/*! + \brief Get the number of LEDs the referenced adapter has available. + \param AdapterHandle Handle to the adapter. + \param NumberOfLeds Number of LEDs available on this adapter. + \return TRUE on success. +*/ +BOOL AirpcapGetLedsNumber(PAirpcapHandle AdapterHandle, PUINT NumberOfLeds); + +/*! + \brief Turn on one of the adapter's LEDs. + \param AdapterHandle Handle to the adapter. + \param LedNumber zero-based identifier of the LED to turn on. + \return TRUE on success. +*/ +BOOL AirpcapTurnLedOn(PAirpcapHandle AdapterHandle, UINT LedNumber); + +/*! + \brief Turn off one of the adapter's LEDs. + \param AdapterHandle Handle to the adapter. + \param LedNumber zero-based identifier of the LED to turn off. + \return TRUE on success. +*/ +BOOL AirpcapTurnLedOff(PAirpcapHandle AdapterHandle, UINT LedNumber); + +/*! + \brief Set the channel of a device through its radio frequency. In case of 802.11n enabled devices, it sets the extension channel, if used. + \param AdapterHandle Handle to the adapter. + \param ChannelInfo The new channel information to set. + \return TRUE on success. + + \note this is a device-related function: when you change the channel from an open capture instance, the change will be + immediately reflected on all the other capture instances. +*/ +BOOL AirpcapSetDeviceChannelEx(PAirpcapHandle AdapterHandle, AirpcapChannelInfo ChannelInfo); + +/*! + \brief Get the channel of a device through its radiofrequency. In case of 802.11n enabled devices, it gets the extension channel, if in use. + \param AdapterHandle Handle to the adapter. + \param PChannelInfo Pointer to a user-supplied variable into which the function will copy the currently configured channel information. + \return TRUE on success. + + \note this is a device-related function: when you change the channel from an open capture instance, the change will be + immediately reflected on all the other capture instances. +*/ +BOOL AirpcapGetDeviceChannelEx(PAirpcapHandle AdapterHandle, PAirpcapChannelInfo PChannelInfo); + +/*! + \brief Get the list of supported channels for a given device. In case of a 802.11n capable device, information related to supported extension channels is also reported. + + Every control channel is listed multiple times, one for each different supported extension channel. For example channel 6 (2437MHz) is usually listed three times: + - Frequency 2437 Extension +1. Control channel is 6, extension channel is 10. + - Frequency 2437 Extension 0. Control channel is 6, no extension channel is used (20MHz channel and legacy mode). + - Frequency 2437 Extension -1. Control channel is 6, extension channel is 2. + \param AdapterHandle Handle to the adapter. + \param ppChannelInfo Pointer to a user-supplied variable that will point to an array of supported channel. Such list must not be freed by the caller + \param pNumChannelInfo Number of channels returned in the array. + \return TRUE on success. + + \note The supported channels are not listed in any specific order. +*/ +BOOL AirpcapGetDeviceSupportedChannels(PAirpcapHandle AdapterHandle, PAirpcapChannelInfo *ppChannelInfo, PUINT pNumChannelInfo); + +/*! + \brief Converts a given frequency to the corresponding channel. + + \param Frequency Frequency of the channel, in MHz. + \param PChannel Pointer to a user-supplied variable that will contain the channel number on success. + \param PBand Pointer to a user-supplied variable that will contain the band (a or b/g) of the given channel. + \return TRUE on success, i.e. the frequency corresponds to a valid a or b/g channel. +*/ +BOOL AirpcapConvertFrequencyToChannel(UINT Frequency, PUINT PChannel, PAirpcapChannelBand PBand); + +/*! + \brief Converts a given channel to the corresponding frequency. + + \param Channel Channel number to be converted. + \param PFrequency Pointer to a user-supplied variable that will contain the channel frequency in MHz on success. + \return TRUE on success, i.e. the given channel number exists. +*/ +BOOL AirpcapConvertChannelToFrequency(UINT Channel, PUINT PFrequency); + + +/*@}*/ + +#endif // __AIRPCAP_DRIVER__ + +#ifdef __cplusplus +} +#endif + +#endif // !defined(AIRPCAP_H__EAE405F5_0171_9592_B3C2_C19EC426AD34__INCLUDED_) diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/airpcap_loader.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/airpcap_loader.h new file mode 100644 index 00000000..df35b0eb --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/airpcap_loader.h @@ -0,0 +1,560 @@ +/* airpcap_loader.h + * Declarations of routines for the "About" dialog + * + * $Id: airpcap_loader.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Giorgio Tino + * Copyright (c) CACE Technologies, LLC 2006 + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __AIRPCAP_LOADER_H__ +#define __AIRPCAP_LOADER_H__ + +#include + +/* Error values from "get_airpcap_interface_list()". */ +#define CANT_GET_AIRPCAP_INTERFACE_LIST 0 /* error getting list */ +#define NO_AIRPCAP_INTERFACES_FOUND 1 /* list is empty */ +#define AIRPCAP_NOT_LOADED 2 /* Airpcap DLL not loaded */ + +#define AIRPCAP_CHANNEL_ANY_NAME "ANY" + +#define AIRPCAP_WEP_KEY_STRING "WEP" +/* + * XXX - WPA_PWD is the passphrase+ssid and WPA-PSK is the hexadecimal key + */ +#define AIRPCAP_WPA_PWD_KEY_STRING "WPA-PWD" +#define AIRPCAP_WPA_BIN_KEY_STRING "WPA-PSK" + +#define AIRPCAP_DLL_OK 0 +#define AIRPCAP_DLL_OLD 1 +#define AIRPCAP_DLL_ERROR 2 +#define AIRPCAP_DLL_NOT_FOUND 3 + +typedef PCHAR (*AirpcapGetLastErrorHandler)(PAirpcapHandle AdapterHandle); +typedef BOOL (*AirpcapGetDeviceListHandler)(PAirpcapDeviceDescription *PPAllDevs, PCHAR Ebuf); +typedef VOID (*AirpcapFreeDeviceListHandler)(PAirpcapDeviceDescription PAllDevs); +typedef PAirpcapHandle (*AirpcapOpenHandler)(PCHAR DeviceName, PCHAR Ebuf); +typedef VOID (*AirpcapCloseHandler)(PAirpcapHandle AdapterHandle); +typedef BOOL (*AirpcapGetLinkTypeHandler)(PAirpcapHandle AdapterHandle, PAirpcapLinkType PLinkType); +typedef BOOL (*AirpcapSetLinkTypeHandler)(PAirpcapHandle AdapterHandle, AirpcapLinkType NewLinkType); +typedef BOOL (*AirpcapSetKernelBufferHandler)(PAirpcapHandle AdapterHandle, UINT BufferSize); +typedef BOOL (*AirpcapSetFilterHandler)(PAirpcapHandle AdapterHandle, PVOID Instructions, UINT Len); +typedef BOOL (*AirpcapGetMacAddressHandler)(PAirpcapHandle AdapterHandle, PAirpcapMacAddress PMacAddress); +typedef BOOL (*AirpcapSetMinToCopyHandler)(PAirpcapHandle AdapterHandle, UINT MinToCopy); +typedef BOOL (*AirpcapGetReadEventHandler)(PAirpcapHandle AdapterHandle, HANDLE* PReadEvent); +typedef BOOL (*AirpcapReadHandler)(PAirpcapHandle AdapterHandle, PBYTE Buffer, UINT BufSize, PUINT PReceievedBytes); +typedef BOOL (*AirpcapGetStatsHandler)(PAirpcapHandle AdapterHandle, PAirpcapStats PStats); +typedef BOOL (*AirpcapTurnLedOnHandler)(PAirpcapHandle AdapterHandle, UINT LedNumber); +typedef BOOL (*AirpcapTurnLedOffHandler)(PAirpcapHandle AdapterHandle, UINT LedNumber); +typedef BOOL (*AirpcapSetDeviceChannelHandler)(PAirpcapHandle AdapterHandle, UINT Channel); +typedef BOOL (*AirpcapGetDeviceChannelHandler)(PAirpcapHandle AdapterHandle, PUINT PChannel); +typedef BOOL (*AirpcapSetFcsPresenceHandler)(PAirpcapHandle AdapterHandle, BOOL IsFcsPresent); +typedef BOOL (*AirpcapGetFcsPresenceHandler)(PAirpcapHandle AdapterHandle, PBOOL PIsFcsPresent); +typedef BOOL (*AirpcapSetFcsValidationHandler)(PAirpcapHandle AdapterHandle, AirpcapValidationType ValidationType); +typedef BOOL (*AirpcapGetFcsValidationHandler)(PAirpcapHandle AdapterHandle, PAirpcapValidationType PValidationType); +typedef BOOL (*AirpcapSetDeviceKeysHandler)(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection); +typedef BOOL (*AirpcapGetDeviceKeysHandler)(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, PUINT PKeysCollectionSize); +typedef BOOL (*AirpcapSetDriverKeysHandler)(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection); +typedef BOOL (*AirpcapGetDriverKeysHandler)(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, PUINT PKeysCollectionSize); +typedef BOOL (*AirpcapSetDecryptionStateHandler)(PAirpcapHandle AdapterHandle, AirpcapDecryptionState Enable); +typedef BOOL (*AirpcapGetDecryptionStateHandler)(PAirpcapHandle AdapterHandle, PAirpcapDecryptionState PEnable); +typedef BOOL (*AirpcapSetDriverDecryptionStateHandler)(PAirpcapHandle AdapterHandle, AirpcapDecryptionState Enable); +typedef BOOL (*AirpcapGetDriverDecryptionStateHandler)(PAirpcapHandle AdapterHandle, PAirpcapDecryptionState PEnable); +typedef BOOL (*AirpcapStoreCurConfigAsAdapterDefaultHandler)(PAirpcapHandle AdapterHandle); +typedef VOID (*AirpcapGetVersionHandler)(PUINT VersionMajor, PUINT VersionMinor, PUINT VersionRev, PUINT VersionBuild); +typedef BOOL (*AirpcapSetDeviceChannelExHandler)(PAirpcapHandle AdapterHandle, AirpcapChannelInfo ChannelInfo); +typedef BOOL (*AirpcapGetDeviceChannelExHandler)(PAirpcapHandle AdapterHandle, PAirpcapChannelInfo PChannelInfo); +typedef BOOL (*AirpcapGetDeviceSupportedChannelsHandler)(PAirpcapHandle AdapterHandle, AirpcapChannelInfo **ppChannelInfo, PULONG pNumChannelInfo); + +#define FLAG_CAN_BE_LOW 0x00000001 +#define FLAG_CAN_BE_HIGH 0x00000002 +#define FLAG_IS_BG_CHANNEL 0x00000004 +#define FLAG_IS_A_CHANNEL 0x00000008 + +typedef struct _Dot11Channel +{ + UINT Channel; + ULONG Frequency; + ULONG Flags; +} Dot11Channel; + +/* + * The list of interfaces returned by "get_airpcap_interface_list()" is + * a list of these structures. + */ +typedef struct { + char *name; /* e.g. "eth0" */ + char *description; /* from OS, e.g. "Local Area Connection" or NULL */ + GSList *ip_addr; /* containing address values of if_addr_t */ + gboolean loopback; /* TRUE if loopback, FALSE otherwise */ + AirpcapLinkType linkType; /* The link layer type */ + AirpcapChannelInfo channelInfo; /* Channel Information */ + BOOL IsFcsPresent; /* Include 802.11 CRC in frames */ + AirpcapValidationType CrcValidationOn; /* Capture Frames with Wrong CRC */ + AirpcapDecryptionState DecryptionOn; /* TRUE if decryption is on, FALSE otherwise */ + PAirpcapKeysCollection keysCollection; /* WEP Key collection for the adapter */ + UINT keysCollectionSize; /* Size of the key collection */ + gboolean blinking; /* TRUE if is blinkng, FALSE otherwise */ + gboolean led; /* TRUE if on, FALSE if off */ + gboolean saved; /* TRUE if current configuration has been saved, FALSE otherwise */ + gint tag; /* int for the gtk blinking callback */ + Dot11Channel *pSupportedChannels; + ULONG numSupportedChannels; +} airpcap_if_info_t; + +/* + * Struct used to store infos to pass to the preferences manager callbacks + */ +typedef struct { + GList *list; + int current_index; + int number_of_keys; +} keys_cb_data_t; + +/* Airpcap interface list */ +extern GList *airpcap_if_list; + +/* Airpcap current selected interface */ +extern airpcap_if_info_t *airpcap_if_selected; + +/* Airpcap current active interface */ +extern airpcap_if_info_t *airpcap_if_active; + +/* WLAN preferences pointer */ +/*extern module_t *wlan_prefs; - TODO: What is this?? */ + +/* + * Function used to read the Decryption Keys from the preferences and store them + * properly into the airpcap adapter. + */ +BOOL +load_wlan_driver_wep_keys(); + +/* + * Function used to save to the prefereces file the Decryption Keys. + */ +BOOL +save_wlan_wep_keys(airpcap_if_info_t* info_if); + +/* + * This function will tell the airpcap driver the key list to use + * This will be stored into the registry... + */ +gboolean +write_wlan_wep_keys_to_registry(airpcap_if_info_t* info_if, GList* key_list); + +/* Returs TRUE if the WEP key is valid, false otherwise */ +gboolean +wep_key_is_valid(char* key); + +/* + * Callback used to free an instance of airpcap_if_info_t + */ +static void +free_airpcap_if_cb(gpointer data, gpointer user_data _U_); + +/* + * USED FOR DEBUG ONLY... PRINTS AN AirPcap ADAPTER STRUCTURE in a fancy way. + */ +void +airpcap_if_info_print(airpcap_if_info_t* if_info); + +/* + * Used to retrieve the two chars string from interface + */ +gchar* +airpcap_get_if_string_number_from_description(gchar* description); + +/* + * Function used to free the airpcap interface list + */ +void +free_airpcap_interface_list(GList *if_list); + +/* + * Used to retrieve the interface given the name + * (the name is used in AirpcapOpen) + */ +airpcap_if_info_t* get_airpcap_if_from_name(GList* if_list, const gchar* name); + +/* + * Airpcap wrapper, used to store the current settings for the selected adapter + */ +BOOL +airpcap_if_store_cur_config_as_adapter_default(PAirpcapHandle ah); + +/* + * Function used to load the WEP keys for a selected interface + */ +BOOL +airpcap_if_load_keys(PAirpcapHandle ad, airpcap_if_info_t *if_info); + +/* + * Function used to load the WEP keys from the global driver list + */ +BOOL +airpcap_if_load_driver_keys(PAirpcapHandle ad, airpcap_if_info_t *if_info); + +/* + * Function used to save the WEP keys for a selected interface + */ +void +airpcap_if_save_keys(PAirpcapHandle ad, airpcap_if_info_t *if_info); + +/* + * Function used to save the WEP keys for a selected interface + */ +void +airpcap_if_save_driver_keys(PAirpcapHandle ad, airpcap_if_info_t *if_info); + +/* + * Airpcap wrapper, used to get the fcs validation of an airpcap adapter + */ +BOOL +airpcap_if_get_fcs_validation(PAirpcapHandle ah, PAirpcapValidationType val); + +/* + * Airpcap wrapper, used to set the fcs validation of an airpcap adapter + */ +BOOL +airpcap_if_set_fcs_validation(PAirpcapHandle ah, AirpcapValidationType val); + +/* + * Airpcap wrapper, used to get the decryption enabling of an airpcap adapter + */ +BOOL +airpcap_if_get_decryption_state(PAirpcapHandle ah, PAirpcapDecryptionState val); + +/* + * Airpcap wrapper, used to set the decryption enabling of an airpcap adapter + */ +BOOL +airpcap_if_set_decryption_state(PAirpcapHandle ah, AirpcapDecryptionState val); + +/* + * Airpcap wrapper, used to get the fcs presence of an airpcap adapter + */ +BOOL +airpcap_if_get_fcs_presence(PAirpcapHandle ah, PBOOL ch); + +/* + * Airpcap wrapper, used to set the fcs presence of an airpcap adapter + */ +BOOL +airpcap_if_set_fcs_presence(PAirpcapHandle ah, BOOL ch); + +/* + * Airpcap wrapper, used to get the link type of an airpcap adapter + */ +BOOL +airpcap_if_get_link_type(PAirpcapHandle ah, PAirpcapLinkType lt); + +/* + * Airpcap wrapper, used to set the link type of an airpcap adapter + */ +BOOL +airpcap_if_set_link_type(PAirpcapHandle ah, AirpcapLinkType lt); + +/* + * Airpcap wrapper, used to get the channel of an airpcap adapter + */ +BOOL +airpcap_if_get_device_channel(PAirpcapHandle ah, PUINT ch); + +/* + * Airpcap wrapper, get the channels supported by the adapter + */ +BOOL +airpcap_if_get_device_supported_channels(PAirpcapHandle ah, AirpcapChannelInfo **cInfo, PULONG nInfo); + +/* + * Airpcap wrapper, get supported channels formatted into an array + */ +Dot11Channel* +airpcap_if_get_device_supported_channels_array(PAirpcapHandle ah, PULONG pNumSupportedChannels); + +/* + * Airpcap wrapper, used to set the channel of an airpcap adapter + */ +BOOL +airpcap_if_set_device_channel(PAirpcapHandle ah, UINT ch); + +/* + * Airpcap wrapper, used to get the frequency of an airpcap adapter + */ +BOOL +airpcap_if_get_device_channel_ex(PAirpcapHandle ah, PAirpcapChannelInfo pChannelInfo); + +/* + * Airpcap wrapper, used to set the frequency of an airpcap adapter + */ +BOOL +airpcap_if_set_device_channel_ex(PAirpcapHandle ah, AirpcapChannelInfo ChannelInfo); + +/* + * Airpcap wrapper, used to open an airpcap adapter + */ +PAirpcapHandle airpcap_if_open(PCHAR name, PCHAR err); + +/* + * Airpcap wrapper, used to close an airpcap adapter + */ +VOID airpcap_if_close(PAirpcapHandle handle); + +/* + * Retrieve the state of the Airpcap DLL + */ +int +airpcap_get_dll_state(); + +/* + * Airpcap wrapper, used to turn on the led of an airpcap adapter + */ +BOOL airpcap_if_turn_led_on(PAirpcapHandle AdapterHandle, UINT LedNumber); + +/* + * Airpcap wrapper, used to turn off the led of an airpcap adapter + */ +BOOL airpcap_if_turn_led_off(PAirpcapHandle AdapterHandle, UINT LedNumber); + +/* + * This function will create a new airpcap_if_info_t using a name and a description + */ +airpcap_if_info_t* airpcap_if_info_new(char *name, char *description); + +/* + * This function will create a new fake drivers' interface, to load global keys... + */ +airpcap_if_info_t* airpcap_driver_fake_if_info_new(); + +/* + * Used to dinamically load the airpcap library in order link it only when + * it's present on the system. + */ +int load_airpcap(void); + +/* + * This function will use the airpcap.dll to find all the airpcap devices. + * Will return null if no device is found. + */ +GList* +get_airpcap_interface_list(int *err, char **err_str); + +/* + * Returns the ASCII string of a key given the key bites + */ +gchar* +airpcap_get_key_string(AirpcapKey key); + +/* + * Load the configuration for the specified interface + */ +void +airpcap_load_selected_if_configuration(airpcap_if_info_t* if_info); + +/* + * Save the configuration for the specified interface + */ +void +airpcap_save_selected_if_configuration(airpcap_if_info_t* if_info); + +/* + * Used to retrieve the two chars string from interface description + */ +gchar* +airpcap_get_if_string_number(airpcap_if_info_t* if_info); + +/* + * Returns the default airpcap interface of a list, NULL if list is empty + */ +airpcap_if_info_t* +airpcap_get_default_if(GList* airpcap_if_list); + +/* + * Airpcap wrapper, used to save the settings for the selected_if + */ +BOOL +airpcap_if_set_device_keys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection); + +/* + * Airpcap wrapper, used to save the settings for the selected_if + */ +BOOL +airpcap_if_get_device_keys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, PUINT PKeysCollectionSize); + +/* + * Airpcap wrapper, used to save the settings for the selected_if + */ +BOOL +airpcap_if_set_driver_keys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection); + +/* + * Airpcap wrapper, used to save the settings for the selected_if + */ +BOOL +airpcap_if_get_driver_keys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, PUINT PKeysCollectionSize); + +/* + * Airpcap wrapper, used to get the decryption enabling of an airpcap driver + */ +BOOL +airpcap_if_get_driver_decryption_state(PAirpcapHandle ah, PAirpcapDecryptionState PEnable); +/* + * Airpcap wrapper, used to set the decryption enabling of an airpcap driver + */ +BOOL +airpcap_if_set_driver_decryption_state(PAirpcapHandle ah, AirpcapDecryptionState Enable); + +/* + * Save the configuration for the specified interface + */ +void +airpcap_save_driver_if_configuration(airpcap_if_info_t* fake_if_info); + +/* + * Free an instance of airpcap_if_info_t + */ +void +airpcap_if_info_free(airpcap_if_info_t *if_info); + +/* + * This function will tell the airpcap driver the key list to use + * This will be stored into the registry... + */ +BOOL +write_wlan_driver_wep_keys_to_registry(GList* key_list); + +/* + * Clear keys and decryption status for the specified interface + */ +void +airpcap_if_clear_decryption_settings(airpcap_if_info_t* info_if); + +/* + * Function used to save to the preference file the Decryption Keys. + */ +int +save_wlan_driver_wep_keys(); + +/* + * Function used to save to the preference file the Decryption Keys. + */ +int +save_wlan_wireshark_wep_keys(GList* key_ls); + +/* + * DECRYPTION KEYS FUNCTIONS + */ +/* + * This function is used for DEBUG PURPOSES ONLY!!! + */ +void +print_key_list(GList* key_list); + +/* + * Retrieves a GList of decryption_key_t structures containing infos about the + * keys for the given adapter... returns NULL if no keys are found. + */ +GList* +get_airpcap_device_keys(airpcap_if_info_t* if_info); + +/* + * Retrieves a GList of decryption_key_t structures containing infos about the + * keys for the global AirPcap driver... returns NULL if no keys are found. + */ +GList* +get_airpcap_driver_keys(); + +/* + * Returns the list of the decryption keys specified for wireshark, NULL if + * no key is found + */ +GList* +get_wireshark_keys(); + +/* + * Tests if two collection of keys are equal or not, to be considered equals, they have to + * contain the same keys in the SAME ORDER! (If both lists are NULL, which means empty will + * return TRUE) + */ +gboolean +key_lists_are_equal(GList* list1, GList* list2); + +/* + * Merges two lists of keys. If a key is found multiple times, it will just appear once! + */ +GList* +merge_key_list(GList* list1, GList* list2); + +/* + * If the given key is contained in the list, returns TRUE. + * Returns FALSE otherwise. + */ +gboolean +key_is_in_list(decryption_key_t *dk,GList *list); + +/* + * Returns TRUE if keys are equals, FALSE otherwise + */ +gboolean +keys_are_equals(decryption_key_t *k1,decryption_key_t *k2); + +/* + * Use this function to free a key list. + */ +void +free_key_list(GList *list); + +/* + * Returns TRUE if the Wireshark decryption is active, FALSE otherwise + */ +gboolean +wireshark_decryption_on(); + +/* + * Returns TRUE if the AirPcap decryption for the current adapter is active, FALSE otherwise + */ +gboolean +airpcap_decryption_on(); + +/* + * Enables decryption for Wireshark if on_off is TRUE, disables it otherwise. + */ +void +set_wireshark_decryption(gboolean on_off); + +/* + * Enables decryption for all the adapters if on_off is TRUE, disables it otherwise. + */ +gboolean +set_airpcap_decryption(gboolean on_off); + +/* + * Adds compiled version string to str + */ +void +get_compiled_airpcap_version(GString *str); + +void +get_runtime_airpcap_version(GString *str); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/alert_box.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/alert_box.h new file mode 100644 index 00000000..62ee1efb --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/alert_box.h @@ -0,0 +1,70 @@ +/* alert_box.h + * Routines to put up various "standard" alert boxes used in multiple + * places + * + * $Id: alert_box.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ALERT_BOX_H__ +#define __ALERT_BOX_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * Alert box for general errors. + */ +extern void failure_alert_box(const char *msg_format, va_list ap); + +/* + * Alert box for a failed attempt to open or create a file. + * "err" is assumed to be a UNIX-style errno; "for_writing" is TRUE if + * the file is being opened for writing and FALSE if it's being opened + * for reading. + */ +extern void open_failure_alert_box(const char *filename, int err, + gboolean for_writing); + +/* + * Alert box for a failed attempt to read a file. + * "err" is assumed to be a UNIX-style errno. + */ +extern void read_failure_alert_box(const char *filename, int err); + +/* + * Alert box for a failed attempt to write to a file. + * "err" is assumed to be a UNIX-style errno. + */ +extern void write_failure_alert_box(const char *filename, int err); + +/* + * Alert box for an invalid display filter expression. + * Assumes "dfilter_error_msg" has been set by "dfilter_compile()" to the + * error message for the filter. + */ +extern void bad_dfilter_alert_box(const char *dftext); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __ALERT_BOX_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-pcap-util-int.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-pcap-util-int.h new file mode 100644 index 00000000..697f2ede --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-pcap-util-int.h @@ -0,0 +1,56 @@ +/* capture-pcap-util-int.h + * Definitions of routines internal to the libpcap/WinPcap utilities + * + * $Id: capture-pcap-util-int.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PCAP_UTIL_INT_H__ +#define __PCAP_UTIL_INT_H__ + +#ifdef HAVE_LIBPCAP +#ifdef HAVE_PCAP_REMOTE +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#endif + +extern if_info_t *if_info_new(char *name, char *description); +extern void if_info_add_address(if_info_t *if_info, struct sockaddr *addr); +#ifdef HAVE_PCAP_FINDALLDEVS +#ifdef HAVE_PCAP_REMOTE +extern GList *get_interface_list_findalldevs_ex(const char *source, + struct pcap_rmtauth *auth, int *err, char **err_str); +#else +extern GList *get_interface_list_findalldevs(int *err, char **err_str); +#endif +#endif + +/* + * Get an error message string for a CANT_GET_INTERFACE_LIST error from + * "get_interface_list()". This is used to let the error message string + * be platform-dependent. + */ +extern gchar *cant_get_if_list_error_message(const char *err_str); + +#endif /* HAVE_LIBPCAP */ + +#endif /* __PCAP_UTIL_INT_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-pcap-util.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-pcap-util.h new file mode 100644 index 00000000..fd480733 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-pcap-util.h @@ -0,0 +1,131 @@ +/* capture-pcap-util.h + * Utility definitions for packet capture + * + * $Id: capture-pcap-util.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PCAP_UTIL_H__ +#define __PCAP_UTIL_H__ + +#ifdef HAVE_LIBPCAP + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include + +#include + +/* + * XXX - this is also the traditional default snapshot size in + * tcpdump - but, if IPv6 is enabled, it defaults to 96, to get an + * IPv6 header + TCP + 22 extra bytes. + * + * Some libpcap versions for particular capture devices might happen + * to impose a minimum, but it's not always 68. + */ +#define MIN_PACKET_SIZE 68 /* minimum amount of packet data we can read */ + +/* + * The list of interfaces returned by "get_interface_list()" is + * a list of these structures. + */ +typedef struct { + char *name; /* e.g. "eth0" */ + char *description; /* from OS, e.g. "Local Area Connection" or NULL */ + GSList *ip_addr; /* containing address values of if_addr_t */ + gboolean loopback; /* TRUE if loopback, FALSE otherwise */ +} if_info_t; + +/* + * An address in the "ip_addr" list. + */ +typedef struct { + address_type type; /* AT_IPv4 or AT_IPv6 */ + union { + guint32 ip4_addr; /* 4 byte IP V4 address, or */ + guint8 ip6_addr[16];/* 16 byte IP V6 address */ + } ip_addr; +} if_addr_t; + +GList *get_interface_list(int *err, char **err_str); +#ifdef HAVE_PCAP_REMOTE +GList *get_remote_interface_list(const char *hostname, const char *port, + int auth_type, const char *username, + const char *passwd, int *err, char **err_str); +#endif + +/* Error values from "get_interface_list()/capture_interface_list()". */ +#define CANT_GET_INTERFACE_LIST 1 /* error getting list */ +#define NO_INTERFACES_FOUND 2 /* list is empty */ +#define CANT_RUN_DUMPCAP 3 /* problem running dumpcap */ + +void free_interface_list(GList *if_list); + +/* + * The list of data link types returned by "get_pcap_linktype_list()" is + * a list of these structures. + */ +typedef struct { + int dlt; /* e.g. DLT_EN10MB (which is 1) */ + char *name; /* e.g. "EN10MB" or "DLT 1" */ + char *description; /* descriptive name from wiretap e.g. "Ethernet", NULL if unknown */ +} data_link_info_t; + +GList *get_pcap_linktype_list(const char *devname, char **err_str); +void free_pcap_linktype_list(GList *linktype_list); + +/* get/set the link type of an interface */ +/* (only used in capture_loop.c / capture-pcap-util.c) */ +int get_pcap_linktype(pcap_t *pch, const char *devname); +const char *set_pcap_linktype(pcap_t *pch, char *devname, int dlt); + + +#ifdef HAVE_PCAP_DATALINK_VAL_TO_NAME +const char *linktype_val_to_name(int dlt); +#endif +#ifdef HAVE_PCAP_DATALINK_NAME_TO_VAL +int linktype_name_to_val(const char *linktype); +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* HAVE_LIBPCAP */ + +/* + * Append to a GString an indication of the version of libpcap/WinPcap + * with which we were compiled, if we were, or an indication that we + * weren't compiled with libpcap/WinPcap, if we weren't. + */ +extern void get_compiled_pcap_version(GString *str); + +/* + * Append to a GString an indication of the version of libpcap/WinPcap + * with which we're running, or an indication that we're not running + * with libpcap/WinPcap, if we were compiled with libpcap/WinPcap, + * or nothing, if we weren't compiled with libpcap/WinPcap. + */ +extern void get_runtime_pcap_version(GString *str); + +#endif /* __PCAP_UTIL_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-wpcap.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-wpcap.h new file mode 100644 index 00000000..94e51244 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-wpcap.h @@ -0,0 +1,34 @@ +/* capture-wpcap.h + * + * $Id: capture-wpcap.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2001 Gerald Combs + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef CAPTURE_WPCAP_H +#define CAPTURE_WPCAP_H + +extern gboolean has_wpcap; + + +void +load_wpcap(void); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture.h new file mode 100644 index 00000000..86a0ef1e --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture.h @@ -0,0 +1,118 @@ +/* capture.h + * Definitions for packet capture windows + * + * $Id: capture.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* This file should only be included if libpcap is present */ + +#ifndef __CAPTURE_H__ +#define __CAPTURE_H__ + +/** @file + * Capture related things. + */ + +#include "capture_opts.h" + +/** + * Start a capture session. + * + * @param capture_opts the numerous capture options + * @return TRUE if the capture starts successfully, FALSE otherwise. + */ +extern gboolean capture_start(capture_options *capture_opts); + +/** Stop a capture session (usually from a menu item). */ +extern void capture_stop(capture_options *capture_opts); + +/** Restart the current captured packets and start again. */ +extern void capture_restart(capture_options *capture_opts); + +/** Terminate the capture child cleanly when exiting. */ +extern void capture_kill_child(capture_options *capture_opts); + +/** + * Capture child told us we have a new (or the first) capture file. + */ +extern gboolean capture_input_new_file(capture_options *capture_opts, gchar *new_file); + +/** + * Capture child told us we have new packets to read. + */ +extern void capture_input_new_packets(capture_options *capture_opts, int to_read); + +/** + * Capture child told us how many dropped packets it counted. + */ +extern void capture_input_drops(capture_options *capture_opts, int dropped); + +/** + * Capture child told us that an error has occurred while starting the capture. + */ +extern void capture_input_error_message(capture_options *capture_opts, char *error_message, char *secondary_error_msg); + +/** + * Capture child told us that an error has occurred while parsing a + * capture filter when starting/running the capture. + */ +extern void capture_input_cfilter_error_message(capture_options *capture_opts, char *error_message); + +/** + * Capture child closed its side of the pipe, do the required cleanup. + */ +extern void capture_input_closed(capture_options *capture_opts); + +#ifdef HAVE_LIBPCAP +/** + * Fetch the interface list from a child process. + */ +extern GList *capture_interface_list(int *err, char **err_str); + +/** + * Fetch the linktype list for the specified interface from a child process. + */ +extern GList *capture_pcap_linktype_list(const char *devname, char **err_str); + + +struct if_stat_cache_s; +typedef struct if_stat_cache_s if_stat_cache_t; + +/** + * Start gathering capture statistics for the interfaces specified. + * @param A GList of if_info_t items + * @return A pointer to the statistics state data. + */ +extern if_stat_cache_t * capture_stat_start(GList *if_list); + +/** + * Fetch capture statistics, similar to pcap_stats(). + */ +struct pcap_stat; /* Stub in case we don't or haven't yet included pcap.h */ +extern gboolean capture_stats(if_stat_cache_t *sc, char *ifname, struct pcap_stat *ps); + +/** + * Stop gathering capture statistics. + */ +void capture_stat_stop(if_stat_cache_t *sc); +#endif /* HAVE_LIBPCAP */ + +#endif /* capture.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_errs.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_errs.h new file mode 100644 index 00000000..be631336 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_errs.h @@ -0,0 +1,34 @@ +/* capture_errs.h + * Declarations of routines to return error and warning messages for + * packet capture + * + * $Id: capture_errs.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_LIBPCAP + +#ifdef _WIN32 +/* error message, if WinPcap couldn't be loaded */ +/* will use g_strdup, don't forget to g_free the returned string! */ +extern char *cant_load_winpcap_err(const char *app_name); +#endif /* _WIN32 */ + +#endif /* HAVE_LIBPCAP */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_info.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_info.h new file mode 100644 index 00000000..8d83d0f7 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_info.h @@ -0,0 +1,76 @@ +/* capture_info.h + * capture info functions + * + * $Id: capture_info.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +/** @file + * + * capture info functions + * + */ + +#ifndef __CAPTURE_INFO_H__ +#define __CAPTURE_INFO_H__ + + +/* open the info - init values (wtap, counts), create dialog */ +extern void capture_info_open(const char *iface); + +/* new file arrived - (eventually close old wtap), open wtap */ +extern gboolean capture_info_new_file(const char *new_filename); + +/* new packets arrived - read from wtap, count */ +extern void capture_info_new_packets(int to_read); + +/* close the info - close wtap, destroy dialog */ +extern void capture_info_close(void); + + + +/** Current Capture info. */ +typedef struct { + /* handle */ + gpointer ui; /**< user interface handle */ + + /* capture info */ + packet_counts *counts; /**< protocol specific counters */ + time_t running_time; /**< running time since last update */ + gint new_packets; /**< packets since last update */ +} capture_info; + + +/** Create the capture info dialog */ +extern void capture_info_ui_create( +capture_info *cinfo, +const gchar *iface); + +/** Update the capture info counters in the dialog */ +extern void capture_info_ui_update( +capture_info *cinfo); + +/** Destroy the capture info dialog again */ +extern void capture_info_ui_destroy( +capture_info *cinfo); + + +#endif /* capture_info.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_opts.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_opts.h new file mode 100644 index 00000000..e813688e --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_opts.h @@ -0,0 +1,194 @@ +/* capture_opts.h + * Capture options (all parameters needed to do the actual capture) + * + * $Id: capture_opts.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +/** @file + * + * Capture options (all parameters needed to do the actual capture) + * + */ + +#ifndef __CAPTURE_OPTS_H__ +#define __CAPTURE_OPTS_H__ + + +/* Current state of capture engine. XXX - differentiate states */ +typedef enum { + CAPTURE_STOPPED, /**< stopped */ + CAPTURE_PREPARING, /**< preparing, but still no response from capture child */ + CAPTURE_RUNNING /**< capture child signalled ok, capture is running now */ +} capture_state; + +#ifdef HAVE_PCAP_REMOTE +/* Type of capture source */ +typedef enum { + CAPTURE_IFLOCAL, /**< Local network interface */ + CAPTURE_IFREMOTE /**< Remote network interface */ +} capture_source; + +/* Type of RPCAPD Authentication */ +typedef enum { + CAPTURE_AUTH_NULL, /**< No authentication */ + CAPTURE_AUTH_PWD /**< User/password authentication */ +} capture_auth; + +#ifdef HAVE_PCAP_SETSAMPLING +/** + * Method of packet sampling (dropping some captured packets), + * may require additional integer parameter, marked here as N + */ +typedef enum { + CAPTURE_SAMP_NONE, /**< No sampling - capture all packets */ + CAPTURE_SAMP_BY_COUNT, /**< Counter-based sampling - + capture 1 packet from every N */ + CAPTURE_SAMP_BY_TIMER /**< Timer-based sampling - + capture no more than 1 packet + in N milliseconds */ +} capture_sampling; +#endif +#endif + +/** Capture options coming from user interface */ +typedef struct capture_options_tag { + /* general */ + void *cf; /**< handle to cfile (note: untyped handle) */ + gboolean has_cfilter; /**< TRUE if capture filter specified on command line */ + gchar *cfilter; /**< Capture filter string */ + gchar *iface; /**< the network interface to capture from */ + gchar *iface_descr; /**< A human readable description of iface. + *< NOTE: capture_opts.c is not able to + *< set this field because doing so + *< requires too many dependencies. + *< Readers of this field should use + *< get_iface_description() from + *< "capture_ui_utils.h" to access it. */ +#ifdef HAVE_PCAP_REMOTE + capture_source src_type; /**< Capturing on remote interface */ + gchar *remote_host; /**< Host name or network address + *< for remote capturing */ + gchar *remote_port; /**< TCP port of remote RPCAP server */ + + capture_auth auth_type; + gchar *auth_username; + gchar *auth_password; /**< Remote authentication parameters */ + + gboolean datatx_udp; /**< Whether to use UDP for data transfer */ + gboolean nocap_rpcap; /**< Whether to capture RPCAP own traffic */ + gboolean nocap_local; /**< TODO: Whether to capture local traffic */ +#ifdef HAVE_PCAP_SETSAMPLING + capture_sampling sampling_method; /**< PCAP packet sampling method */ + int sampling_param; /**< PCAP packet sampling parameter */ +#endif +#endif +#ifdef _WIN32 + int buffer_size; /**< the capture buffer size (MB) */ +#endif + gboolean has_snaplen; /**< TRUE if maximum capture packet length + is specified */ + int snaplen; /**< Maximum captured packet length */ + gboolean promisc_mode; /**< Capture in promiscuous mode */ + int linktype; /**< Data link type to use, or -1 for + "use default" */ + gboolean saving_to_file; /**< TRUE if capture is writing to a file */ + gchar *save_file; /**< the capture file name */ + + /* GUI related */ + gboolean real_time_mode; /**< Update list of packets in real time */ + gboolean show_info; /**< show the info dialog */ + gboolean quit_after_cap; /**< Makes a "capture only mode". Implies -k */ + gboolean restart; /**< restart after closing is done */ + + /* multiple files (and ringbuffer) */ + gboolean multi_files_on; /**< TRUE if ring buffer in use */ + + gboolean has_file_duration; /**< TRUE if ring duration specified */ + gint32 file_duration; /**< Switch file after n seconds */ + gboolean has_ring_num_files; /**< TRUE if ring num_files specified */ + guint32 ring_num_files; /**< Number of multiple buffer files */ + + /* autostop conditions */ + gboolean has_autostop_files; /**< TRUE if maximum number of capture files + are specified */ + gint32 autostop_files; /**< Maximum number of capture files */ + + gboolean has_autostop_packets; /**< TRUE if maximum packet count is + specified */ + int autostop_packets; /**< Maximum packet count */ + gboolean has_autostop_filesize; /**< TRUE if maximum capture file size + is specified */ + gint32 autostop_filesize; /**< Maximum capture file size */ + gboolean has_autostop_duration; /**< TRUE if maximum capture duration + is specified */ + gint32 autostop_duration; /**< Maximum capture duration */ + + /* internally used (don't touch from outside) */ + int fork_child; /**< If not -1, in parent, process ID of child */ +#ifdef _WIN32 + int signal_pipe_write_fd; /**< the pipe to signal the child */ +#endif + capture_state state; /**< current state of the capture engine */ + gboolean output_to_pipe; /**< save_file is a pipe (named or stdout) */ +#ifndef _WIN32 + uid_t owner; /**< owner of the cfile */ + gid_t group; /**< group of the cfile */ +#endif +} capture_options; + +/* initialize the capture_options with some reasonable values */ +extern void +capture_opts_init(capture_options *capture_opts, void *cfile); + +/* set a command line option value */ +extern int +capture_opts_add_opt(capture_options *capture_opts, int opt, const char *optarg, gboolean *start_capture); + +/* log content of capture_opts */ +extern void +capture_opts_log(const char *log_domain, GLogLevelFlags log_level, capture_options *capture_opts); + +/* list link layer types */ +extern int +capture_opts_list_link_layer_types(capture_options *capture_opts, gboolean machine_readable); + +/* list interfaces */ +extern int +capture_opts_list_interfaces(gboolean machine_readable); + +/* print interface statistics */ +extern int +capture_opts_print_statistics(gboolean machine_readable); + +/* trim the snaplen entry */ +extern void +capture_opts_trim_snaplen(capture_options *capture_opts, int snaplen_min); + +/* trim the ring_num_files entry */ +extern void +capture_opts_trim_ring_num_files(capture_options *capture_opts); + +/* trim the interface entry */ +extern gboolean +capture_opts_trim_iface(capture_options *capture_opts, const char *capture_device); + +#endif /* capture_opts.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_stop_conditions.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_stop_conditions.h new file mode 100644 index 00000000..1e6e1f32 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_stop_conditions.h @@ -0,0 +1,29 @@ +/* capture_stop_conditions.h + * Implementation for 'stop condition handler'. + * + * $Id: capture_stop_conditions.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +void init_capture_stop_conditions(void); +void cleanup_capture_stop_conditions(void); + +extern const char* CND_CLASS_TIMEOUT; +extern const char* CND_CLASS_CAPTURESIZE; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_sync.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_sync.h new file mode 100644 index 00000000..6f2f72fb --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_sync.h @@ -0,0 +1,87 @@ +/* capture_sync.h + * Synchronisation between Wireshark capture parent and child instances + * + * $Id: capture_sync.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +/** @file + * + * Sync mode capture (internal interface). + * + * Will start a new Wireshark child instance which will do the actual capture + * work. + */ + +#ifndef __CAPTURE_SYNC_H__ +#define __CAPTURE_SYNC_H__ + + +/** + * Start a new capture session. + * Create a capture child which is doing the real capture work. + * The various capture_input_... functions will be called, if something had + * happened. + * + * Most of the parameters are passed through the global capture_opts. + * + * @param capture_opts the options + * @return TRUE if a capture could be started, FALSE if not + */ +extern gboolean +sync_pipe_start(capture_options *capture_opts); + +/** User wants to stop capturing, gracefully close the capture child */ +extern void +sync_pipe_stop(capture_options *capture_opts); + +/** User wants to stop the program, just kill the child as soon as possible */ +extern void +sync_pipe_kill(int fork_child); + +/** Has the parent signalled the child to stop? */ +#define SIGNAL_PIPE_CTRL_ID_NONE "none" +#ifdef _WIN32 +#define SIGNAL_PIPE_FORMAT "\\\\.\\pipe\\wireshark.%s.signal" +#endif + +/** Get an interface list using dumpcap */ +extern int +sync_interface_list_open(gchar **msg); + +/** Get a linktype list using dumpcap */ +extern int +sync_linktype_list_open(const gchar *ifname, gchar **msg); + +/** Start getting interface statistics using dumpcap. */ +extern int +sync_interface_stats_open(int *read_fd, int *fork_child, gchar **msg); + +/** Stop gathering statistics. */ +extern int +sync_interface_stats_close(int *read_fd, int *fork_child, gchar **msg); + +/** Read a line from a pipe, similar to fgets. Non-blocking. */ +extern int +sync_pipe_gets_nonblock(int pipe, char *bytes, int max); + + +#endif /* capture_sync.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_ui_utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_ui_utils.h new file mode 100644 index 00000000..5da23b2a --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_ui_utils.h @@ -0,0 +1,89 @@ +/* capture_ui_utils.c + * Declarations of utilities for capture user interfaces + * + * $Id: capture_ui_utils.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __CAPTURE_UI_UTILS_H__ +#define __CAPTURE_UI_UTILS_H__ + +#include "capture_opts.h" + +/** @file + * GList of available capture interfaces. + */ + +/** Return as descriptive a name for an interface as we can get. + * If the user has specified a comment, use that. Otherwise, + * if get_interface_list() supplies a description, use that, + * otherwise use the interface name. + * + * @param if_name The name of the interface. + * + * @return The descriptive name (must be g_free'd later) + */ +char *get_interface_descriptive_name(const char *if_name); + +/** Build the GList of available capture interfaces. + * + * @param if_list An interface list from get_interface_list(). + * @param do_hide Hide the "hidden" interfaces. + * + * @return A list of if_info_t structs (use free_capture_combo_list() later). + */ +GList *build_capture_combo_list(GList *if_list, gboolean do_hide); + +/** Free the GList from build_capture_combo_list(). + * + * @param combo_list the interface list from build_capture_combo_list() + */ +void free_capture_combo_list(GList *combo_list); + + +/** Given text that contains an interface name possibly prefixed by an + * interface description, extract the interface name. + * + * @param if_text A string containing the interface description + name. + * This is usually the data from one of the list elements returned by + * build_capture_combo_list(). + * + * @return The raw interface name, without description (must NOT be g_free'd later) + */ +const char *get_if_name(const char *if_text); + +/** Convert plain interface name to the displayed name in the combo box. + * + * @param if_list The list of interfaces returned by build_capture_combo_list() + * @param if_name The name of the interface. + * + * @return The descriptive name (must be g_free'd later) + */ +char *build_capture_combo_name(GList *if_list, gchar *if_name); + +/** Return the interface description (after setting it if not already set) + * + * @param capture_opts The capture_options structure that contains the used interface + * + * @return A pointer to capture_ops->iface_descr + */ +const char *get_iface_description(capture_options *capture_opts); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_wpcap_packet.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_wpcap_packet.h new file mode 100644 index 00000000..38d1cd9d --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_wpcap_packet.h @@ -0,0 +1,47 @@ +/* capture_wpcap_packet.h + * + * $Id: capture_wpcap_packet.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2001 Gerald Combs + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef CAPTURE_WPCAP_PACKET_H +#define CAPTURE_WPCAP_PACKET_H + + +extern void wpcap_packet_load(void); + +/* get the packet.dll version info */ +extern char *wpcap_packet_get_version(void); + +/* open the interface */ +extern void * wpcap_packet_open(char *if_name); + +/* close the interface */ +extern void wpcap_packet_close(void * adapter); + +extern int wpcap_packet_request(void *a, ULONG Oid, int set, char *value, unsigned int *length); + +extern int wpcap_packet_request_uint(void *a, ULONG Oid, UINT *value); + +extern int wpcap_packet_request_ulong(void *a, ULONG Oid, ULONG *value); + + +#endif /* CAPTURE_WPCAP_PACKET_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/cfile.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/cfile.h new file mode 100644 index 00000000..0b388d5d --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/cfile.h @@ -0,0 +1,91 @@ +/* cfile.h + * capture_file definition & GUI-independent manipulation + * + * $Id: cfile.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __CFILE_H__ +#define __CFILE_H__ + +/* Current state of file. */ +typedef enum { + FILE_CLOSED, /* No file open */ + FILE_READ_IN_PROGRESS, /* Reading a file we've opened */ + FILE_READ_ABORTED, /* Read aborted by user */ + FILE_READ_DONE /* Read completed */ +} file_state; + +/* Character set for text search. */ +typedef enum { + SCS_ASCII_AND_UNICODE, + SCS_ASCII, + SCS_UNICODE + /* add EBCDIC when it's implemented */ +} search_charset_t; + +typedef struct _capture_file { + file_state state; /* Current state of capture file */ + gchar *filename; /* Name of capture file */ + gboolean is_tempfile; /* Is capture file a temporary file? */ + gboolean user_saved;/* If capture file is temporary, has it been saved by user yet? */ + gint64 f_datalen; /* Size of capture file data (uncompressed) */ + guint16 cd_t; /* File type of capture file */ + int lnk_t; /* Link-layer type with which to save capture */ + guint32 vers; /* Version. For tcpdump minor is appended to major */ + int count; /* Total number of frames */ + int displayed_count; /* Number of displayed frames */ + int marked_count; /* Number of marked frames */ + gboolean drops_known; /* TRUE if we know how many packets were dropped */ + guint32 drops; /* Dropped packets */ + nstime_t elapsed_time;/* Elapsed time */ + gboolean has_snap; /* TRUE if maximum capture packet length is known */ + int snap; /* Maximum captured packet length */ + wtap *wth; /* Wiretap session */ + dfilter_t *rfcode; /* Compiled read (display) filter program */ + gchar *dfilter; /* Display filter string */ + /* search */ + gchar *sfilter; /* Search filter string */ + gboolean sbackward; /* TRUE if search is backward, FALSE if forward */ + gboolean hex; /* TRUE is raw data search is being performed */ + gboolean string; /* TRUE is text search is being performed */ + guint32 search_pos; /* Position of last character found in search */ + search_charset_t scs_type; /* Character set for text search */ + gboolean case_type; /* TRUE if case-insensitive text search */ + gboolean decode_data; /* TRUE if searching protocol tree text */ + gboolean summary_data; /* TRUE if searching Info column text */ + /* packet data */ + union wtap_pseudo_header pseudo_header; /* Packet pseudo_header */ + guint8 pd[WTAP_MAX_PACKET_SIZE]; /* Packet data */ + GMemChunk *plist_chunk; /* Memory chunk for frame_data structures */ + frame_data *plist; /* Packet list */ + frame_data *plist_end; /* Last packet in list */ + frame_data *first_displayed; /* First frame displayed */ + frame_data *last_displayed; /* Last frame displayed */ + column_info cinfo; /* Column formatting information */ + frame_data *current_frame; /* Frame data for current frame */ + epan_dissect_t *edt; /* Protocol dissection for currently selected packet */ + field_info *finfo_selected; /* Field info for currently selected field */ + struct ph_stats_s* pstats; /* accumulated stats (reset on redisplay in GUI)*/ +} capture_file; + +void init_cap_file(capture_file *); + +#endif /* cfile.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/clopts_common.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/clopts_common.h new file mode 100644 index 00000000..825164bc --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/clopts_common.h @@ -0,0 +1,40 @@ +/* clopts_common.h + * Handle command-line arguments common to Wireshark and TShark + * + * $Id: clopts_common.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PROTO_DUMPOPTS_H__ +#define __PROTO_DUMPOPTS_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +int get_natural_int(const char *string, const char *name); + +int get_positive_int(const char *string, const char *name); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __PROTO_DUMPOPTS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/cmdarg_err.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/cmdarg_err.h new file mode 100644 index 00000000..5bd43cc0 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/cmdarg_err.h @@ -0,0 +1,56 @@ +/* cmdarg_err.h + * Declarations of routines to report command-line errors. + * + * $Id: cmdarg_err.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __CMDARG_ERR_H__ +#define __CMDARG_ERR_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * Report an error in command-line arguments. + */ +#if __GNUC__ >= 2 +extern void cmdarg_err(const char *fmt, ...) + __attribute__((format (printf, 1, 2))); +#else +extern void cmdarg_err(const char *fmt, ...); +#endif + +/* + * Report additional information for an error in command-line arguments. + */ +#if __GNUC__ >= 2 +extern void cmdarg_err_cont(const char *fmt, ...) + __attribute__((format (printf, 1, 2))); +#else +extern void cmdarg_err_cont(const char *fmt, ...); +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __CMDARG_ERR_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/color.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/color.h new file mode 100644 index 00000000..a1c09b2a --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/color.h @@ -0,0 +1,55 @@ +/* color.h + * Definitions for "toolkit-independent" colors + * + * $Id: color.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __COLOR_H__ +#define __COLOR_H__ + +/* + * Data structure holding RGB value for a color. + * + * XXX - yes, I know, there's a "pixel" value in there as well; for + * now, it's intended to look just like a GdkColor but not to require + * that any GTK+ header files be included in order to use it. + * The way we handle colors needs to be cleaned up somewhat, in order + * to keep toolkit-specific stuff separate from toolkit-independent stuff. + */ +typedef struct { + guint32 pixel; + guint16 red; + guint16 green; + guint16 blue; +} color_t; + +/** Initialize a color with R, G, and B values, including any toolkit-dependent + ** work that needs to be done. + * + * @param color the color_t to be filled + * @param red the red value for the color + * @param green the green value for the color + * @param blue the blue value for the color + * @return TRUE if it succeeds, FALSE if it fails + */ +gboolean initialize_color(color_t *color, guint16 red, guint16 green, guint16 blue); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/color_filters.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/color_filters.h new file mode 100644 index 00000000..878ce97f --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/color_filters.h @@ -0,0 +1,196 @@ +/* color_filters.h + * Definitions for color filters + * + * $Id: color_filters.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef __COLOR_FILTERS_H__ +#define __COLOR_FILTERS_H__ + +#define TEMP_COLOR_PREFIX "___tmp_color_filter___" +/** @file + * Color filters. + */ + +/* Data for a color filter. */ +typedef struct _color_filter { + gchar *filter_name; /* name of the filter */ + gchar *filter_text; /* text of the filter expression */ + color_t bg_color; /* background color for packets that match */ + color_t fg_color; /* foreground color for packets that match */ + gboolean disabled; /* set if the filter is disabled */ + gboolean selected; /* set if the filter is selected in the color dialog box */ + + /* only used inside of color_filters.c */ + dfilter_t *c_colorfilter; /* compiled filter expression */ + + /* only used outside of color_filters.c (beside init) */ + void *edit_dialog; /* if filter is being edited, dialog + * box for it */ +} color_filter_t; + + +/** Init the color filters (incl. initial read from file). */ +void color_filters_init(void); + +/** Reload the color filters */ +void color_filters_reload(void); + +/** Cleanup remaining color filter zombies */ +void color_filters_cleanup(void); + +/** Color filters currently used? + * + * @return TRUE, if filters are used + */ +gboolean color_filters_used(void); + +/** Are there any temporary coloring filters used? + * + * @return TRUE, if temporary coloring filters are used + */ +gboolean tmp_color_filters_used(void); + +/** En-/disable color filters + * + * @param enable TRUE to enable (default) + */ +void +color_filters_enable(gboolean enable); + +/** Set the filter string of a temporary color filter + * + * @param filt_nr a number 1-10 pointing to a temporary color + * @param filter the new filter-string + * @param disabled whether the filter-rule should be disabled + */ +void +color_filters_set_tmp(guint8 filt_nr, gchar *filter, gboolean disabled); + +/** Reset the temporary color filters + * + */ +void +color_filters_reset_tmp(void); + +/* Prime the epan_dissect_t with all the compiler + * color filters of the current filter list. + * + * @param the epan dissector details + */ +void color_filters_prime_edt(epan_dissect_t *edt); + +/** Colorize a specific packet. + * + * @param row the row in the packet list + * @param edt the dissected packet + * @return the matching color filter or NULL + */ +color_filter_t * +color_filters_colorize_packet(gint row, epan_dissect_t *edt); + + + +/** Clone the currently active filter list. + * + * @param user_data will be returned by each call to to color_filter_add_cb() + */ +void color_filters_clone(gpointer user_data); + +/** Load filters (import) from some other filter file. + * + * @param path the path to the import file + * @param user_data will be returned by each call to to color_filter_add_cb() + * @return TRUE, if read succeeded + */ +gboolean color_filters_import(gchar *path, gpointer user_data); + +/** Read filters from the global filter file (not the users file). + * + * @param user_data will be returned by each call to to color_filter_add_cb() + * @return TRUE, if read succeeded + */ +gboolean color_filters_read_globals(gpointer user_data); + +/** A color filter was added (while importing). + * (color_filters.c calls this for every filter coming in) + * + * @param colorf the new color filter + * @param user_data from caller + */ +void color_filter_add_cb (color_filter_t *colorf, gpointer user_data); + + + +/** Apply a changed filter list. + * + * @param tmp_cfl the temporary color filter list to apply + * @param edit_cfl the edited permanent color filter list to apply + */ +void color_filters_apply(GSList *tmp_cfl, GSList *edit_cfl); + +/** Save filters in users filter file. + * + * @param cfl the filter list to write + * @return TRUE if write succeeded + */ +gboolean color_filters_write(GSList *cfl); + +/** Save filters (export) to some other filter file. + * + * @param path the path to the filter file + * @param cfl the filter list to write + * @param only_selected TRUE if only the selected filters should be saved + * @return TRUE, if write succeeded + */ +gboolean color_filters_export(gchar *path, GSList *cfl, gboolean only_selected); + + + +/** Create a new color filter (g_malloc'ed). + * + * @param name the name of the filter + * @param filter_string the filter string + * @param bg_color background color + * @param fg_color foreground color + * @return the new color filter + */ +color_filter_t *color_filter_new( + const gchar *name, const gchar *filter_string, + color_t *bg_color, color_t *fg_color, gboolean disabled); + +/** Delete a single color filter (g_free'ed). + * + * @param colorf the color filter to be removed + */ +void color_filter_delete(color_filter_t *colorf); + + + + +/** Delete a filter list including all entries. + * + * @param cfl the filter list to delete + */ +void color_filter_list_delete(GSList **cfl); + + + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/conditions.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/conditions.h new file mode 100644 index 00000000..e07af3b6 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/conditions.h @@ -0,0 +1,134 @@ +/* conditions.h + * Header for condition handler. + * + * $Id: conditions.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef CONDITIONS_H +#define CONDITIONS_H + +#include + +#include + +/* forward declaration for type 'condition' */ +typedef struct condition condition; + +/* condition evaluation handler type */ +typedef gboolean (*_cnd_eval)(condition*, va_list); + +/* condition reset handler type */ +typedef void (*_cnd_reset)(condition*); + +/* condition class constructor type */ +typedef condition* (*_cnd_constr)(condition*, va_list); + +/* condition class destructor type */ +typedef void (*_cnd_destr)(condition*); + +/* + * Conditions must be created with this function. They can be created for + * registered classes only. + * + * parameter: const char* - Identification of a registered condition class. + * ... - Any number of class specific initial values. + * returns: Pointer to a initialized condition of the particular class on + * success or NULL on failure. + */ +condition* cnd_new(const char*, ...); + +/* + * Conditions must be deleted with this function when not used anymore. + * + * parameter: condition* - Pointer to a condition created with 'cnd_new()'. + * returns: - + */ +void cnd_delete(condition*); + +/* + * Call this function to check whether or not a particular condition is true. + * + * parameter: condition* - Pointer to an initialized condition. + * ... - Any number of condition specific arguments. + * returns: TRUE - Condition is true. + * FALSE - Condition is false. + */ +gboolean cnd_eval(condition*, ...); + +/* + * Call this function to reset this condition to its initial state, i.e. the + * state it was in right after creation. + * + * parameter: condition* - Pointer to an initialized condition. + * returns: - + */ +void cnd_reset(condition*); + +/* + * Register a new conditon class. + * New conditions of this class can be created by calling 'cnd_new()' and + * supplying the appropriate class id. + * + * parameter: const char* - The class id. + * _cnd_constr - User supplied constructor function for this + * class. + * _cnd_destr - User supplied destructor function for this + * class. + * _cnd_eval - User supplied evaluation handler function for this + class. + * _cnd_reset - User supplied reset handler for this class. + * returns: TRUE - Success. + * FALSE - Failure. + */ +gboolean cnd_register_class(const char*, + _cnd_constr, + _cnd_destr, + _cnd_eval, + _cnd_reset); + +/* + * Unregister a previously registered conditon class. After unregistration + * of a class it is no longer possible to create conditions of this kind by + * calling 'cnd_new()'. + * + * parameter: const char* - An identification for this condition class. + * returns: - + */ +void cnd_unregister_class(const char*); + +/* + * This function returns the user data of the condition. + * + * parameter: condition* - Pointer to an initialized condition. + * returns: void* - Pointer to user data of this condition. + */ +void* cnd_get_user_data(condition*); + +/* + * This function sets the user data of the condition. + * + * parameter: condition* - Pointer to an initialized condition. + * void* - Pointer to user specified data structure. + * returns: - + */ +void cnd_set_user_data(condition*, void*); + +#endif /* CONDITIONS_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h new file mode 100644 index 00000000..cf2ce4a1 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h @@ -0,0 +1,322 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Directory for data */ +#define DATAFILE_DIR "/usr/local/share/wireshark" + +/* Link plugins statically into Wireshark */ +/* #undef ENABLE_STATIC */ + +/* Format modifier for printing 64-bit numbers */ +/* #undef G_GINT64_MODIFIER */ + +/* Enable AirPDcap (WPA/WPA2 decryption) */ +#define HAVE_AIRPDCAP 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_INET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_NAMESER_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_DIRECT_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_DIRENT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `gethostbyname2' function. */ +#define HAVE_GETHOSTBYNAME2 1 + +/* Define to 1 if you have the `getprotobynumber' function. */ +#define HAVE_GETPROTOBYNUMBER 1 + +/* Define to use GNU ADNS library */ +/* #undef HAVE_GNU_ADNS */ + +/* Define to 1 if you have the header file. */ +#define HAVE_GRP_H 1 + +/* Define to use heimdal kerberos */ +/* #undef HAVE_HEIMDAL_KERBEROS */ + +/* Define if you have the iconv() function. */ +#define HAVE_ICONV 1 + +/* Define if inet_ntop() prototype exists */ +#define HAVE_INET_NTOP_PROTO 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `issetugid' function. */ +/* #undef HAVE_ISSETUGID */ + +/* Define to use kerberos */ +#define HAVE_KERBEROS 1 + +/* Define if krb5.h defines KEYTYPE_ARCFOUR_56 */ +/* #undef HAVE_KEYTYPE_ARCFOUR_56 */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LAUXLIB_H */ + +/* Define to use the libcap library */ +/* #undef HAVE_LIBCAP */ + +/* Define to use libgcrypt */ +#define HAVE_LIBGCRYPT 1 + +/* Define to use gnutls library */ +#define HAVE_LIBGNUTLS 1 + +/* Define to use libpcap library */ +#define HAVE_LIBPCAP 1 + +/* Define to use libpcre library */ +/* #undef HAVE_LIBPCRE */ + +/* Define to use libportaudio library */ +/* #undef HAVE_LIBPORTAUDIO */ + +/* Define to 1 if you have the `smi' library (-lsmi). */ +/* #undef HAVE_LIBSMI */ + +/* Define to use libz library */ +#define HAVE_LIBZ 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LUA5_1_LAUXLIB_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LUA5_1_LUALIB_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LUA5_1_LUA_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LUALIB_H */ + +/* Define to use Lua 5.1 */ +/* #undef HAVE_LUA_5_1 */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LUA_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to use MIT kerberos */ +#define HAVE_MIT_KERBEROS 1 + +/* Define to 1 if you have the `mmap' function. */ +#define HAVE_MMAP 1 + +/* Define to 1 if you have the `mprotect' function. */ +#define HAVE_MPROTECT 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETDB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define to 1 if you have OS X frameworks */ +/* #undef HAVE_OS_X_FRAMEWORKS */ + +/* Define if pcap_breakloop is known */ +#define HAVE_PCAP_BREAKLOOP 1 + +/* Define to 1 if you have the `pcap_createsrcstr' function. */ +/* #undef HAVE_PCAP_CREATESRCSTR */ + +/* Define to 1 if you have the `pcap_datalink_name_to_val' function. */ +#define HAVE_PCAP_DATALINK_NAME_TO_VAL 1 + +/* Define to 1 if you have the `pcap_datalink_val_to_name' function. */ +#define HAVE_PCAP_DATALINK_VAL_TO_NAME 1 + +/* Define to 1 if you have the `pcap_findalldevs' function and a pcap.h that + declares pcap_if_t. */ +#define HAVE_PCAP_FINDALLDEVS 1 + +/* Define to 1 if you have the `pcap_findalldevs_ex' function. */ +/* #undef HAVE_PCAP_FINDALLDEVS_EX */ + +/* Define to 1 if you have the `pcap_freecode' function. */ +#define HAVE_PCAP_FREECODE 1 + +/* Define to 1 if you have the `pcap_get_selectable_fd' function. */ +#define HAVE_PCAP_GET_SELECTABLE_FD 1 + +/* Define to 1 if you have the `pcap_lib_version' function. */ +#define HAVE_PCAP_LIB_VERSION 1 + +/* Define to 1 if you have the `pcap_list_datalinks' function. */ +#define HAVE_PCAP_LIST_DATALINKS 1 + +/* Define to 1 if you have the `pcap_open' function. */ +/* #undef HAVE_PCAP_OPEN */ + +/* Define to 1 if you have the `pcap_open_dead' function. */ +#define HAVE_PCAP_OPEN_DEAD 1 + +/* Define to 1 if you have WinPcap remote capturing support and prefer to use + these new API features. */ +/* #undef HAVE_PCAP_REMOTE */ + +/* Define to 1 if you have the `pcap_setsampling' function. */ +/* #undef HAVE_PCAP_SETSAMPLING */ + +/* Define to 1 if you have the `pcap_set_datalink' function. */ +#define HAVE_PCAP_SET_DATALINK 1 + +/* Define if libpcap version is known */ +#define HAVE_PCAP_VERSION 1 + +/* Define if plugins are enabled */ +#define HAVE_PLUGINS 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_PORTAUDIO_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_PWD_H 1 + +/* Define to 1 to enable remote capturing feature in WinPcap library */ +/* #undef HAVE_REMOTE */ + +/* Define if sa_len field exists in struct sockaddr */ +/* #undef HAVE_SA_LEN */ + +/* Define to 1 if you have the `setresgid' function. */ +#define HAVE_SETRESGID 1 + +/* Define to 1 if you have the `setresuid' function. */ +#define HAVE_SETRESUID 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDARG_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDDEF_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `sysconf' function. */ +#define HAVE_SYSCONF 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_SOCKIO_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_UTSNAME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* HTML viewer, e.g. mozilla */ +#define HTML_VIEWER "mozilla" + +/* Define as const if the declaration of iconv() needs const. */ +#define ICONV_CONST + +/* Define if defines PRI[doxu]64 macros */ +#define INTTYPES_H_DEFINES_FORMATS + +/* Define if getopt.h needs to be included */ +/* #undef NEED_GETOPT_H */ + +/* Define if g_ascii_strcasecmp.h needs to be included */ +/* #undef NEED_G_ASCII_STRCASECMP_H */ + +/* Define if g_ascii_strtoull.h needs to be included */ +/* #undef NEED_G_ASCII_STRTOULL_H */ + +/* Define if inet/aton.h needs to be included */ +/* #undef NEED_INET_ATON_H */ + +/* Define if inet/v6defs.h needs to be included */ +/* #undef NEED_INET_V6DEFS_H */ + +/* Define if strerror.h needs to be included */ +/* #undef NEED_STRERROR_H */ + +/* Define if strptime.h needs to be included */ +/* #undef NEED_STRPTIME_H */ + +/* Name of package */ +#define PACKAGE "wireshark" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "" + +/* Define if we are using version of of the Portaudio library API */ +/* #undef PORTAUDIO_API_1 */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Version number of package */ +#define VERSION "1.0.0" + +/* Define to 1 if your processor stores words with the most significant byte + first (like Motorola and SPARC, unlike Intel and VAX). */ +/* #undef WORDS_BIGENDIAN */ + +/* Define as the string to precede external variable declarations in + dynamically-linked libraries */ +#define WS_VAR_IMPORT extern + +/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a + `char[]'. */ +#define YYTEXT_POINTER 1 diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h.in b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h.in new file mode 100644 index 00000000..b5e1fbdc --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h.in @@ -0,0 +1,321 @@ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Directory for data */ +#undef DATAFILE_DIR + +/* Link plugins statically into Wireshark */ +#undef ENABLE_STATIC + +/* Format modifier for printing 64-bit numbers */ +#undef G_GINT64_MODIFIER + +/* Enable AirPDcap (WPA/WPA2 decryption) */ +#undef HAVE_AIRPDCAP + +/* Define to 1 if you have the header file. */ +#undef HAVE_ARPA_INET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ARPA_NAMESER_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_DIRECT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_DIRENT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the `gethostbyname2' function. */ +#undef HAVE_GETHOSTBYNAME2 + +/* Define to 1 if you have the `getprotobynumber' function. */ +#undef HAVE_GETPROTOBYNUMBER + +/* Define to use GNU ADNS library */ +#undef HAVE_GNU_ADNS + +/* Define to 1 if you have the header file. */ +#undef HAVE_GRP_H + +/* Define to use heimdal kerberos */ +#undef HAVE_HEIMDAL_KERBEROS + +/* Define if you have the iconv() function. */ +#undef HAVE_ICONV + +/* Define if inet_ntop() prototype exists */ +#undef HAVE_INET_NTOP_PROTO + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `issetugid' function. */ +#undef HAVE_ISSETUGID + +/* Define to use kerberos */ +#undef HAVE_KERBEROS + +/* Define if krb5.h defines KEYTYPE_ARCFOUR_56 */ +#undef HAVE_KEYTYPE_ARCFOUR_56 + +/* Define to 1 if you have the header file. */ +#undef HAVE_LAUXLIB_H + +/* Define to use the libcap library */ +#undef HAVE_LIBCAP + +/* Define to use libgcrypt */ +#undef HAVE_LIBGCRYPT + +/* Define to use gnutls library */ +#undef HAVE_LIBGNUTLS + +/* Define to use libpcap library */ +#undef HAVE_LIBPCAP + +/* Define to use libpcre library */ +#undef HAVE_LIBPCRE + +/* Define to use libportaudio library */ +#undef HAVE_LIBPORTAUDIO + +/* Define to 1 if you have the `smi' library (-lsmi). */ +#undef HAVE_LIBSMI + +/* Define to use libz library */ +#undef HAVE_LIBZ + +/* Define to 1 if you have the header file. */ +#undef HAVE_LUA5_1_LAUXLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LUA5_1_LUALIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LUA5_1_LUA_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LUALIB_H + +/* Define to use Lua 5.1 */ +#undef HAVE_LUA_5_1 + +/* Define to 1 if you have the header file. */ +#undef HAVE_LUA_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to use MIT kerberos */ +#undef HAVE_MIT_KERBEROS + +/* Define to 1 if you have the `mmap' function. */ +#undef HAVE_MMAP + +/* Define to 1 if you have the `mprotect' function. */ +#undef HAVE_MPROTECT + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETDB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IN_H + +/* Define to 1 if you have OS X frameworks */ +#undef HAVE_OS_X_FRAMEWORKS + +/* Define if pcap_breakloop is known */ +#undef HAVE_PCAP_BREAKLOOP + +/* Define to 1 if you have the `pcap_createsrcstr' function. */ +#undef HAVE_PCAP_CREATESRCSTR + +/* Define to 1 if you have the `pcap_datalink_name_to_val' function. */ +#undef HAVE_PCAP_DATALINK_NAME_TO_VAL + +/* Define to 1 if you have the `pcap_datalink_val_to_name' function. */ +#undef HAVE_PCAP_DATALINK_VAL_TO_NAME + +/* Define to 1 if you have the `pcap_findalldevs' function and a pcap.h that + declares pcap_if_t. */ +#undef HAVE_PCAP_FINDALLDEVS + +/* Define to 1 if you have the `pcap_findalldevs_ex' function. */ +#undef HAVE_PCAP_FINDALLDEVS_EX + +/* Define to 1 if you have the `pcap_freecode' function. */ +#undef HAVE_PCAP_FREECODE + +/* Define to 1 if you have the `pcap_get_selectable_fd' function. */ +#undef HAVE_PCAP_GET_SELECTABLE_FD + +/* Define to 1 if you have the `pcap_lib_version' function. */ +#undef HAVE_PCAP_LIB_VERSION + +/* Define to 1 if you have the `pcap_list_datalinks' function. */ +#undef HAVE_PCAP_LIST_DATALINKS + +/* Define to 1 if you have the `pcap_open' function. */ +#undef HAVE_PCAP_OPEN + +/* Define to 1 if you have the `pcap_open_dead' function. */ +#undef HAVE_PCAP_OPEN_DEAD + +/* Define to 1 if you have WinPcap remote capturing support and prefer to use + these new API features. */ +#undef HAVE_PCAP_REMOTE + +/* Define to 1 if you have the `pcap_setsampling' function. */ +#undef HAVE_PCAP_SETSAMPLING + +/* Define to 1 if you have the `pcap_set_datalink' function. */ +#undef HAVE_PCAP_SET_DATALINK + +/* Define if libpcap version is known */ +#undef HAVE_PCAP_VERSION + +/* Define if plugins are enabled */ +#undef HAVE_PLUGINS + +/* Define to 1 if you have the header file. */ +#undef HAVE_PORTAUDIO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_PWD_H + +/* Define to 1 to enable remote capturing feature in WinPcap library */ +#undef HAVE_REMOTE + +/* Define if sa_len field exists in struct sockaddr */ +#undef HAVE_SA_LEN + +/* Define to 1 if you have the `setresgid' function. */ +#undef HAVE_SETRESGID + +/* Define to 1 if you have the `setresuid' function. */ +#undef HAVE_SETRESUID + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDARG_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDDEF_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `sysconf' function. */ +#undef HAVE_SYSCONF + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_IOCTL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SOCKET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SOCKIO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_UTSNAME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_WAIT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* HTML viewer, e.g. mozilla */ +#undef HTML_VIEWER + +/* Define as const if the declaration of iconv() needs const. */ +#undef ICONV_CONST + +/* Define if defines PRI[doxu]64 macros */ +#undef INTTYPES_H_DEFINES_FORMATS + +/* Define if getopt.h needs to be included */ +#undef NEED_GETOPT_H + +/* Define if g_ascii_strcasecmp.h needs to be included */ +#undef NEED_G_ASCII_STRCASECMP_H + +/* Define if g_ascii_strtoull.h needs to be included */ +#undef NEED_G_ASCII_STRTOULL_H + +/* Define if inet/aton.h needs to be included */ +#undef NEED_INET_ATON_H + +/* Define if inet/v6defs.h needs to be included */ +#undef NEED_INET_V6DEFS_H + +/* Define if strerror.h needs to be included */ +#undef NEED_STRERROR_H + +/* Define if strptime.h needs to be included */ +#undef NEED_STRPTIME_H + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define if we are using version of of the Portaudio library API */ +#undef PORTAUDIO_API_1 + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef VERSION + +/* Define to 1 if your processor stores words with the most significant byte + first (like Motorola and SPARC, unlike Intel and VAX). */ +#undef WORDS_BIGENDIAN + +/* Define as the string to precede external variable declarations in + dynamically-linked libraries */ +#undef WS_VAR_IMPORT + +/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a + `char[]'. */ +#undef YYTEXT_POINTER diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h.win32 b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h.win32 new file mode 100644 index 00000000..a9569f67 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h.win32 @@ -0,0 +1,274 @@ +/* $Id: config.h.win32 23802 2007-12-07 23:58:46Z guy $ */ +/* config.h.win32 Generated manually. :-) */ +/* config.h. Generated automatically by configure. */ +/* config.h.in. Generated automatically from configure.in by autoheader. */ + +/* Generated Bison and Flex files test whether __STDC__ is defined + in order to check whether to use ANSI C features such as "const". + + GCC defines it as 1 even if extensions that render the implementation + non-conformant are enabled; Sun's C compiler (and, I think, other + AT&T-derived C compilers) define it as 0 if extensions that render + the implementation non-conformant are enabled; Microsoft Visual C++ + 6.0 doesn't define it at all if extensions that render the implementation + non-conformant are enabled. + + We define it as 0 here, so that those generated files will use + those features (and thus not get type warnings when compiled with + MSVC++). */ +#ifndef __STDC__ +#define __STDC__ 0 +#endif + +/* Use Unicode in Windows runtime functions. */ +#define UNICODE 1 +#define _UNICODE 1 + +/* Define if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if your processor stores words with the most significant + byte first (like Motorola and SPARC, unlike Intel and VAX). */ +/* #undef WORDS_BIGENDIAN */ + +/* Define if lex declares yytext as a char * by default, not a char[]. */ +#define YYTEXT_POINTER 1 + +#define HAVE_PLUGINS 1 +#define PLUGINS_NEED_ADDRESS_TABLE 1 + +/* Plugins can also use the import library of libwireshark.dll instead + of the old API. In that case we undefine PLUGINS_NEED_ADDRESS_TABLE + for the plugin. We don't undefine PLUGINS_NEED_ADDRESS_TABLE globally. + Thus Wireshark will be still able to load plugins using the old API. + The macro HAVE_WIN32_LIBWIRESHARK_LIB has to be defined in plugin's + makefile.nmake. A template is available in doc/README.plugins */ +#ifdef HAVE_WIN32_LIBWIRESHARK_LIB +#undef PLUGINS_NEED_ADDRESS_TABLE +#endif + +/* #undef HAVE_SA_LEN */ + +/* #undef NEED_STRERROR_H */ + +#define NEED_MKSTEMP 1 + +@HAVE_LIBPCAP@ +@HAVE_PCAP_BREAKLOOP@ +@HAVE_PCAP_FINDALLDEVS@ +@HAVE_PCAP_DATALINK_NAME_TO_VAL@ +@HAVE_PCAP_DATALINK_VAL_TO_NAME@ +@WPCAP_CONSTIFIED@ +@HAVE_LIBWIRESHARKDLL@ + +@HAVE_REMOTE@ +@HAVE_PCAP_REMOTE@ +@HAVE_PCAP_OPEN@ +@HAVE_PCAP_FINDALLDEVS_EX@ +@HAVE_PCAP_CREATESRCSTR@ +@HAVE_PCAP_SETSAMPLING@ + +@HAVE_AIRPCAP@ +@HAVE_AIRPDCAP@ + +/* availability of pcap_freecode() is handled at runtime */ +#define HAVE_PCAP_FREECODE 1 + +/* define macro for importing variables from an dll + * it depends on HAVE_LIBWIRESHARKDLL and _NEED_VAR_IMPORT_ + */ +#if defined (_NEED_VAR_IMPORT_) && defined (HAVE_LIBWIRESHARKDLL) +# define WS_VAR_IMPORT __declspec(dllimport) extern +#else +# define WS_VAR_IMPORT extern +#endif + +/* Define if you have the gethostbyname2 function. */ +/* #undef HAVE_GETHOSTBYNAME2 */ + +/* Define if you have the getprotobynumber function. */ +/* #undef HAVE_GETPROTOBYNUMBER */ + +/* Define if you have the header file. */ +/* #undef HAVE_ARPA_INET_H */ + +/* Define if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_ICONV */ + +/* Define if you have the header file. */ +/* #undef HAVE_NETDB_H */ + +/* Define if you have the header file. */ +/* #define HAVE_NETINET_IN_H 1 */ + +/* Define if you have the header file. */ +/* #undef HAVE_SNMP_SNMP_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SNMP_VERSION_H */ + +/* Define if you have the header file. */ +#define HAVE_STDARG_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_STDDEF_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_IOCTL_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_SOCKET_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_SOCKIO_H */ + +/* Define if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define if you have the header file. */ +/* #define HAVE_SYS_TIME_H 1 */ + +/* Define if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_WAIT_H */ + +/* Define if you have the header file. */ +/* #define HAVE_UNISTD_H 1 */ + +/* Define if defines PRI[doxu]64 macros */ +/* #define INTTYPES_H_DEFINES_FORMATS */ + +/* Format for printing 64-bit signed decimal numbers */ +#ifndef PRId64 +#ifdef _MSC_EXTENSIONS +#define PRId64 "I64d" +#else /* _MSC_EXTENSIONS */ +#define PRId64 "lld" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRId64 */ + +/* Format for printing 64-bit unsigned octal numbers */ +#ifndef PRIo64 +#ifdef _MSC_EXTENSIONS +#define PRIo64 "I64o" +#else /* _MSC_EXTENSIONS */ +#define PRIo64 "llo" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRIo64 */ + +/* Format for printing 64-bit unsigned decimal numbers */ +#ifndef PRIu64 +#ifdef _MSC_EXTENSIONS +#define PRIu64 "I64u" +#else /* _MSC_EXTENSIONS */ +#define PRIu64 "llu" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRIu64 */ + +/* Formats for printing 64-bit unsigned hexadecimal numbers */ +/* XXX - it seems that GLib has problems with the MSVC like I64x. + As we use GLib's g_sprintf and alike, it should be safe to use + llx everywhere now, making the macros pretty useless. For details see: + http://bugs.wireshark.org/bugzilla/show_bug.cgi?id=1025 */ +#ifndef PRIx64 +#ifdef _MSC_EXTENSIONS +/*#define PRIx64 "I64x"*/ +#define PRIx64 "llx" +#else /* _MSC_EXTENSIONS */ +#define PRIx64 "llx" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRIx64 */ + +#ifndef PRIX64 +#ifdef _MSC_EXTENSIONS +/*#define PRIX64 "I64X"*/ +#define PRIX64 "llX" +#else /* _MSC_EXTENSIONS */ +#define PRIX64 "llX" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRIX64 */ + +/* Define if you have the z library (-lz). */ +@HAVE_LIBZ@ + +/* Define to use GNU ADNS library */ +@HAVE_GNU_ADNS@ +#define ADNS_JGAA_WIN32 1 + +/* Define to use the PCRE library */ +@HAVE_PCRE@ + +/* Define to use the Nettle library */ +@HAVE_NETTLE@ + +/* Define to use the gnutls library */ +@HAVE_LIBGNUTLS@ + +/* Define to use the libgcrypt library */ +@HAVE_LIBGCRYPT@ + +/* Define to use mit kerberos for decryption of kerberos/sasl/dcerpc */ +@HAVE_KFW@ +#ifdef HAVE_MIT_KERBEROS +#define HAVE_KERBEROS +#endif + +/* Define to use Lua */ +@HAVE_LUA@ +@HAVE_LUA_5_1@ + +/* Define to use Portaudio library */ +@HAVE_LIBPORTAUDIO@ +/* Define version of of the Portaudio library API */ +@PORTAUDIO_API_1@ + +/* Define to have SMI */ +@HAVE_SMI@ + + +#ifndef WIN32 +#define WIN32 1 +#endif + +#define HAVE_WINDOWS_H 1 +#define HAVE_WINSOCK2_H 1 +#define HAVE_DIRECT_H 1 +#define NEED_INET_ATON_H 1 +#define NEED_INET_V6DEFS_H 1 +/* Visual C 9 (2008) now needs these prototypes */ +#if _MSC_VER == 1500 +#define NTDDI_VERSION NTDDI_WIN2K +#define _WIN32_WINNT _WIN32_WINNT_WIN2K +#endif +#define NEED_GETOPT_H 1 +#define NEED_STRPTIME_H 1 +#define strcasecmp stricmp +#define strncasecmp strnicmp +#define popen _popen +#define pclose _pclose + +/* Needed for zlib, according to http://www.winimage.com/zLibDll/ */ +/*#define ZLIB_DLL 1 +#define _WINDOWS 1*/ + +/* Name of package */ +#define PACKAGE "wireshark" + +/* Version number of package */ +#define VERSION "@VERSION@" + +/* We shouldn't need this under Windows but we'll define it anyway. */ +#define HTML_VIEWER "mozilla" + +/* Check for the required _MSC_VER */ +#if MSC_VER_REQUIRED != _MSC_VER +#define WS_TO_STRING2(x) #x +#define WS_TO_STRING(x) WS_TO_STRING2(x) +#pragma message( "_MSC_VER is:" WS_TO_STRING(_MSC_VER) " but required is:" WS_TO_STRING(MSC_VER_REQUIRED) ) +#error Your MSVC_VARIANT setting in config.nmake doesn't match the MS compiler version! +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/disabled_protos.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/disabled_protos.h new file mode 100644 index 00000000..87f5b3ab --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/disabled_protos.h @@ -0,0 +1,61 @@ +/* disabled_protos.h + * Declarations of routines for reading and writing the disabled protocols file. + * + * $Id: disabled_protos.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * Item in a list of disabled protocols. + */ +typedef struct { + char *name; /* protocol name */ +} protocol_def; + +/* + * Read in a list of disabled protocols. + * + * On success, "*pref_path_return" is set to NULL. + * On error, "*pref_path_return" is set to point to the pathname of + * the file we tried to read - it should be freed by our caller - + * and "*open_errno_return" is set to the error if we couldn't open the file + * or "*read_errno_return" is set to the error if we got an error reading + * the file. + */ +void read_disabled_protos_list(char **gpath_return, int *gopen_errno_return, + int *gread_errno_return, + char **path_return, int *open_errno_return, + int *read_errno_return); + +/* + * Disable protocols as per the stored configuration + */ +void set_disabled_protos_list(void); + +/* + * Write out a list of disabled protocols. + * + * On success, "*pref_path_return" is set to NULL. + * On error, "*pref_path_return" is set to point to the pathname of + * the file we tried to read - it should be freed by our caller - + * and "*errno_return" is set to the error. + */ +void save_disabled_protos_list(char **pref_path_return, int *errno_return); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/addr_and_mask.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/addr_and_mask.h new file mode 100644 index 00000000..b582aa6e --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/addr_and_mask.h @@ -0,0 +1,53 @@ +/* addr_and_mask.h + * Declarations of routines to fetch IPv4 and IPv6 addresses from a tvbuff + * and then mask out bits other than those covered by a prefix length + * + * $Id: addr_and_mask.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ADDR_AND_MASK_H__ +#define __ADDR_AND_MASK_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * These routines return PREFIX_LEN_OK on success, PREFIX_LEN_TOO_LONG if + * the prefix length is too long, and PREFIX_LEN_ZERO if the prefix length + * is 0. + */ + +#define PREFIX_LEN_OK 0 +#define PREFIX_LEN_TOO_LONG 1 +#define PREFIX_LEN_ZERO 2 + +extern int ipv4_addr_and_mask(tvbuff_t *tvb, int offset, guint8 *addr, + guint32 prefix_len); + +extern int ipv6_addr_and_mask(tvbuff_t *tvb, int offset, + struct e_in6_addr *addr, guint32 prefix_len); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __ADDR_AND_MASK_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/addr_resolv.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/addr_resolv.h new file mode 100644 index 00000000..4733db52 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/addr_resolv.h @@ -0,0 +1,198 @@ +/* addr_resolv.h + * Definitions for network object lookup + * + * $Id: addr_resolv.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Laurent Deniel + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +/* The buffers returned by these functions are all allocated with a + * packet lifetime and does not have have to be freed. + * However, take into account that when the packet dissection + * completes, these buffers will be automatically reclaimed/freed. + * If you need the buffer to remain for a longer scope than packet lifetime + * you must copy the content to an se_alloc() buffer. + */ + +#ifndef __RESOLV_H__ +#define __RESOLV_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifndef MAXNAMELEN +#define MAXNAMELEN 64 /* max name length (hostname and port name) */ +#endif + +/* + * Flag controlling what names to resolve. + */ +WS_VAR_IMPORT guint32 g_resolv_flags; + +/* 32 types are sufficient (as are 640k of RAM) */ +/* FIXME: Maybe MANUF/m, IP/i, IP6/6, IPX/x, UDP+TCP/t etc would be + more useful/consistent */ +#define RESOLV_NONE 0x0 +#define RESOLV_MAC 0x1 +#define RESOLV_NETWORK 0x2 +#define RESOLV_TRANSPORT 0x4 +#define RESOLV_CONCURRENT 0x8 + +#define RESOLV_ALL_ADDRS (RESOLV_MAC|RESOLV_NETWORK|RESOLV_TRANSPORT) +#define RESOLV_ALL 0xFFFFFFFF + +/* global variables */ + +extern gchar *g_ethers_path; +extern gchar *g_ipxnets_path; +extern gchar *g_pethers_path; +extern gchar *g_pipxnets_path; + +/* Functions in resolv.c */ + +/* Set the flags controlling what names to resolve */ +extern void resolv_set_flags(guint32 flags); + +/* + * get_udp_port() returns the port name corresponding to that UDP port, + * or the port number as a string if not found. + */ +extern gchar *get_udp_port(guint port); + +/* + * get_tcp_port() returns the port name corresponding to that TCP port, + * or the port number as a string if not found. + */ +extern gchar *get_tcp_port(guint port); + +/* + * get_dccp_port() returns the port name corresponding to that DCCP port, + * or the port number as a string if not found. + */ +extern gchar *get_dccp_port(guint port); + +/* + * get_sctp_port() returns the port name corresponding to that SCTP port, + * or the port number as a string if not found. + */ +extern gchar *get_sctp_port(guint port); + +/* get_addr_name takes as input an "address", as defined in address.h */ +/* it returns a string that contains: */ +/* - if the address is of a type that can be translated into a name, and the user */ +/* has activated name resolution, the translated name */ +/* - if the address is of type AT_NONE, a pointer to the string "NONE" */ +/* - if the address is of any other type, the result of address_to_str on the argument, */ +/* which should be a string representation for the answer -e.g. "10.10.10.10" for IPv4 */ +/* address 10.10.10.10 */ + +const gchar *get_addr_name(address *addr); + +/* get_addr_name_buf solves an address in the same way as get_addr_name above */ +/* The difference is that get_addr_name_buf takes as input a buffer, into which it puts */ +/* the result which is always NUL ('\0') terminated. The buffer should be large enough to */ +/* contain size characters including the terminator */ + +void get_addr_name_buf(address *addr, gchar *buf, guint size); + + +/* + * Asynchronous host name lookup initialization, processing, and cleanup + */ + +/* host_name_lookup_init fires up an ADNS socket if we're using ADNS */ +extern void host_name_lookup_init(void); + +/* host_name_lookup_process does ADNS processing in GTK+ timeouts in Wireshark, + and before processing each packet in TShark, if we're using ADNS */ +extern gint host_name_lookup_process(gpointer data); + +/* host_name_lookup_cleanup cleans up an ADNS socket if we're using ADNS */ +extern void host_name_lookup_cleanup(void); + +/* get_hostname returns the host name or "%d.%d.%d.%d" if not found */ +extern gchar *get_hostname(guint addr); + +/* get_hostname6 returns the host name, or numeric addr if not found */ +struct e_in6_addr; +const gchar* get_hostname6(struct e_in6_addr *ad); + +/* get_ether_name returns the logical name if found in ethers files else + "_%02x:%02x:%02x" if the vendor code is known else + "%02x:%02x:%02x:%02x:%02x:%02x" */ +extern gchar *get_ether_name(const guint8 *addr); + +/* get_ether_name returns the logical name if found in ethers files else NULL */ +extern gchar *get_ether_name_if_known(const guint8 *addr); + +/* get_manuf_name returns the vendor name or "%02x:%02x:%02x" if not known */ +extern const gchar *get_manuf_name(const guint8 *addr); + +/* get_manuf_name returns the vendor name or NULL if not known */ +extern const gchar *get_manuf_name_if_known(const guint8 *addr); + +/* get_ipxnet_name returns the logical name if found in an ipxnets file, + * or a string formatted with "%X" if not */ +extern const gchar *get_ipxnet_name(const guint32 addr); + +/* returns the ethernet address corresponding to name or NULL if not known */ +extern guint8 *get_ether_addr(const gchar *name); + +/* returns the ipx network corresponding to name. If name is unknown, + * 0 is returned and 'known' is set to FALSE. On success, 'known' + * is set to TRUE. */ +guint32 get_ipxnet_addr(const gchar *name, gboolean *known); + +/* adds a hostname/IPv4 in the hash table */ +extern void add_ipv4_name(guint addr, const gchar *name); + +/* adds a hostname/IPv6 in the hash table */ +extern void add_ipv6_name(struct e_in6_addr *addr, const gchar *name); + +/* add ethernet address / name corresponding to IP address */ +extern void add_ether_byip(guint ip, const guint8 *eth); + +/* Translates a string representing the hostname or dotted-decimal IP address + * into a numeric IP address value, returning TRUE if it succeeds and + * FALSE if it fails. */ +gboolean get_host_ipaddr(const char *host, guint32 *addrp); + +/* + * Translate IPv6 numeric address or FQDN hostname, into binary IPv6 address. + * Return TRUE if we succeed and set "*addrp" to that numeric IP address; + * return FALSE if we fail. + */ +gboolean get_host_ipaddr6(const char *host, struct e_in6_addr *addrp); + +/* + * Find out whether a hostname resolves to an ip or ipv6 address + * Return "ip6" if it is IPv6, "ip" otherwise (including the case + * that we don't know) + */ +const char* host_ip_af(const char *host); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __RESOLV_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/address.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/address.h new file mode 100644 index 00000000..1ce916d4 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/address.h @@ -0,0 +1,172 @@ +/* address.h + * Definitions for structures storing addresses, and for the type of + * variables holding port-type values + * + * $Id: address.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ADDRESS_H__ +#define __ADDRESS_H__ + +#include "emem.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Types of addresses Wireshark knows about. */ +/* If a new address type is added here, a string representation procedure should */ +/* also be included in address_to_str_buf defined in to_str.c, for presentation purposes */ + +typedef enum { + AT_NONE, /* no link-layer address */ + AT_ETHER, /* MAC (Ethernet, 802.x, FDDI) address */ + AT_IPv4, /* IPv4 */ + AT_IPv6, /* IPv6 */ + AT_IPX, /* IPX */ + AT_SNA, /* SNA */ + AT_ATALK, /* Appletalk DDP */ + AT_VINES, /* Banyan Vines */ + AT_OSI, /* OSI NSAP */ + AT_ARCNET, /* ARCNET */ + AT_FC, /* Fibre Channel */ + AT_SS7PC, /* SS7 Point Code */ + AT_STRINGZ, /* null-terminated string */ + AT_EUI64, /* IEEE EUI-64 */ + AT_URI, /* URI/URL/URN */ + AT_TIPC, /* TIPC Address Zone,Subnetwork,Processor */ + AT_USB /* USB Device address + * (0xffffffff represents the host) */ +} address_type; + +typedef struct _address { + address_type type; /* type of address */ + int len; /* length of address, in bytes */ + const void *data; /* pointer to address data */ +} address; + +#define SET_ADDRESS(addr, addr_type, addr_len, addr_data) { \ + (addr)->type = (addr_type); \ + (addr)->len = (addr_len); \ + (addr)->data = (addr_data); \ + } + +/* + * Given two addresses, return + * 0 if the addresses are equal, + * a positive number if addr1>addr2 in some nondefined metric, + * a negative number if addr1type > (addr2)->type)?1: \ + ((addr1)->type < (addr2)->type)?-1: \ + ((addr1)->len > (addr2)->len) ?1: \ + ((addr1)->len < (addr2)->len) ?-1: \ + memcmp((addr1)->data, (addr2)->data, (addr1)->len)\ + ) + +/* + * Given two addresses, return "true" if they're equal, "false" otherwise. + * Addresses are equal only if they have the same type; if the type is + * AT_NONE, they are then equal, otherwise they must have the same + * amount of data and the data must be the same. + */ +#define ADDRESSES_EQUAL(addr1, addr2) \ + ( \ + (addr1)->type == (addr2)->type && \ + ( \ + (addr1)->type == AT_NONE || \ + ( \ + (addr1)->len == (addr2)->len && \ + memcmp((addr1)->data, (addr2)->data, (addr1)->len) == 0 \ + ) \ + ) \ + ) + +/* + * Copy an address, allocating a new buffer for the address data. + */ +#define COPY_ADDRESS(to, from) { \ + guint8 *COPY_ADDRESS_data; \ + (to)->type = (from)->type; \ + (to)->len = (from)->len; \ + COPY_ADDRESS_data = g_malloc((from)->len); \ + memcpy(COPY_ADDRESS_data, (from)->data, (from)->len); \ + (to)->data = COPY_ADDRESS_data; \ + } + +#define SE_COPY_ADDRESS(to, from) { \ + guint8 *SE_COPY_ADDRESS_data; \ + (to)->type = (from)->type; \ + (to)->len = (from)->len; \ + SE_COPY_ADDRESS_data = se_alloc((from)->len); \ + memcpy(SE_COPY_ADDRESS_data, (from)->data, (from)->len); \ + (to)->data = SE_COPY_ADDRESS_data; \ + } + +/* + * Hash an address into a hash value (which must already have been set). + */ +#define ADD_ADDRESS_TO_HASH(hash_val, addr) { \ + const guint8 *ADD_ADDRESS_TO_HASH_data; \ + int ADD_ADDRESS_TO_HASH_index; \ + ADD_ADDRESS_TO_HASH_data = (addr)->data; \ + for (ADD_ADDRESS_TO_HASH_index = 0; \ + ADD_ADDRESS_TO_HASH_index < (addr)->len; \ + ADD_ADDRESS_TO_HASH_index++) \ + hash_val += ADD_ADDRESS_TO_HASH_data[ADD_ADDRESS_TO_HASH_index]; \ + } + +/* Types of port numbers Wireshark knows about. */ +typedef enum { + PT_NONE, /* no port number */ + PT_SCTP, /* SCTP */ + PT_TCP, /* TCP */ + PT_UDP, /* UDP */ + PT_DCCP, /* DCCP */ + PT_IPX, /* IPX sockets */ + PT_NCP, /* NCP connection */ + PT_EXCHG, /* Fibre Channel exchange */ + PT_DDP, /* DDP AppleTalk connection */ + PT_SBCCS, /* FICON */ + PT_IDP, /* XNS IDP sockets */ + PT_TIPC, /* TIPC PORT */ + PT_USB /* USB endpoint 0xffff means the host */ +} port_type; + +/* Types of circuit IDs Wireshark knows about. */ +typedef enum { + CT_NONE, /* no circuit type */ + CT_DLCI, /* Frame Relay DLCI */ + CT_ISDN, /* ISDN channel number */ + CT_X25, /* X.25 logical channel number */ + CT_ISUP, /* ISDN User Part CIC */ + CT_IAX2, /* IAX2 call id */ + CT_H223, /* H.223 logical channel number */ + CT_BICC /* BICC Circuit identifier */ + /* Could also have ATM VPI/VCI pairs */ +} circuit_type; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __ADDRESS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/adler32.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/adler32.h new file mode 100644 index 00000000..277ed53a --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/adler32.h @@ -0,0 +1,42 @@ +/* adler32.h + * Compute the Adler32 checksum (RFC 1950) + * 2003 Tomas Kukosa + * + * $Id: adler32.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef ADLER32_H +#define ADLER32_H + +#ifdef __cplusplus +extern "C"{ +#endif + +unsigned long update_adler32(unsigned long adler, const unsigned char *buf, int len); +unsigned long adler32_bytes(const unsigned char *buf, int len); +unsigned long adler32_str(const char *buf); + +#ifdef __cplusplus +} +#endif + +#endif /* ADLER32_H */ + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/afn.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/afn.h new file mode 100644 index 00000000..16538789 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/afn.h @@ -0,0 +1,71 @@ +/* afn.h + * RFC 1700 address family numbers + * + * $Id: afn.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __AFN_H__ +#define __AFN_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * Address family numbers, from + * + * http://www.iana.org/assignments/address-family-numbers + */ +#define AFNUM_RESERVED 0 /* Reserved */ +#define AFNUM_INET 1 /* IP (IP version 4) */ +#define AFNUM_INET6 2 /* IP6 (IP version 6) */ +#define AFNUM_NSAP 3 /* NSAP */ +#define AFNUM_HDLC 4 /* HDLC (8-bit multidrop) */ +#define AFNUM_BBN1822 5 /* BBN 1822 */ +#define AFNUM_802 6 /* 802 (includes all 802 media plus Ethernet "canonical format") */ +#define AFNUM_E163 7 /* E.163 */ +#define AFNUM_E164 8 /* E.164 (SMDS, Frame Relay, ATM) */ +#define AFNUM_F69 9 /* F.69 (Telex) */ +#define AFNUM_X121 10 /* X.121 (X.25, Frame Relay) */ +#define AFNUM_IPX 11 /* IPX */ +#define AFNUM_ATALK 12 /* Appletalk */ +#define AFNUM_DECNET 13 /* Decnet IV */ +#define AFNUM_BANYAN 14 /* Banyan Vines */ +#define AFNUM_E164NSAP 15 /* E.164 with NSAP format subaddress */ +#define AFNUM_DNS 16 /* DNS (Domain Name System) */ +#define AFNUM_DISTNAME 17 /* Distinguished Name */ +#define AFNUM_AS_NUMBER 18 /* AS Number */ +#define AFNUM_XTP_IP4 19 /* XTP over IP version 4 */ +#define AFNUM_XTP_IP6 20 /* XTP over IP version 6 */ +#define AFNUM_XTP 21 /* XTP native mode XTP */ +#define AFNUM_FC_WWPN 22 /* Fibre Channel World-Wide Port Name */ +#define AFNUM_FC_WWNN 23 /* Fibre Channel World-Wide Node Name */ +#define AFNUM_GWID 24 /* GWID */ +/* draft-kompella-ppvpn-l2vpn */ +#define AFNUM_L2VPN 25 +#define AFNUM_L2VPN_OLD 196 +extern const value_string afn_vals[]; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __AFN_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/aftypes.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/aftypes.h new file mode 100644 index 00000000..a28d7494 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/aftypes.h @@ -0,0 +1,47 @@ +/* aftypes.h + * AF_ values on various flavors of BSD + * + * $Id: aftypes.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * + * This file created and by Mike Hall + * Copyright 1998 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __AFTYPES_H__ +#define __AFTYPES_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* BSD AF_ values. */ +#define BSD_AF_INET 2 +#define BSD_AF_ISO 7 +#define BSD_AF_APPLETALK 16 +#define BSD_AF_IPX 23 +#define BSD_AF_INET6_BSD 24 /* OpenBSD (and probably NetBSD), BSD/OS */ +#define BSD_AF_INET6_FREEBSD 28 +#define BSD_AF_INET6_DARWIN 30 + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* aftypes.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/arcnet_pids.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/arcnet_pids.h new file mode 100644 index 00000000..7f92176a --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/arcnet_pids.h @@ -0,0 +1,70 @@ +/* arcnet_pids.h + * ARCNET protocol ID values + * Copyright 2001-2002, Peter Fales + * + * $Id: arcnet_pids.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ARCNET_PIDS_H__ +#define __ARCNET_PIDS_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* RFC 1051 */ +#define ARCNET_PROTO_IP_1051 240 +#define ARCNET_PROTO_ARP_1051 241 + +/* RFC 1201 */ +#define ARCNET_PROTO_IP_1201 212 +#define ARCNET_PROTO_ARP_1201 213 +#define ARCNET_PROTO_RARP_1201 214 + +#define ARCNET_PROTO_IPX 250 +#define ARCNET_PROTO_NOVELL_EC 236 + +#define ARCNET_PROTO_IPv6 196 /* or so BSD's arcnet.h claims */ + +/* + * Raw Ethernet over ARCNET - Linux's "if_arcnet.h" calls this + * "MS LanMan/WfWg 'NDIS' encapsuation". + */ +#define ARCNET_PROTO_ETHERNET 232 + +#define ARCNET_PROTO_DATAPOINT_BOOT 0 +#define ARCNET_PROTO_DATAPOINT_MOUNT 1 +#define ARCNET_PROTO_POWERLAN_BEACON 8 +#define ARCNET_PROTO_POWERLAN_BEACON2 243 +#define ARCNET_PROTO_LANSOFT 251 + +#define ARCNET_PROTO_APPLETALK 221 +#define ARCNET_PROTO_BANYAN 247 /* Banyan VINES */ + +#define ARCNET_PROTO_DIAGNOSE 128 /* as per ANSI/ATA 878.1 */ + +#define ARCNET_PROTO_BACNET 205 + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* arcnet_pids.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/arptypes.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/arptypes.h new file mode 100644 index 00000000..de936cb6 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/arptypes.h @@ -0,0 +1,75 @@ +/* arptypes.h + * Declarations of ARP address types. + * + * $Id: arptypes.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ARPTYPES_H__ +#define __ARPTYPES_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Definitions taken from Linux "linux/if_arp.h" header file, and from + + http://www.iana.org/assignments/arp-parameters + + */ + +/* ARP protocol HARDWARE identifiers. */ +#define ARPHRD_NETROM 0 /* from KA9Q: NET/ROM pseudo */ +#define ARPHRD_ETHER 1 /* Ethernet 10Mbps */ +#define ARPHRD_EETHER 2 /* Experimental Ethernet */ +#define ARPHRD_AX25 3 /* AX.25 Level 2 */ +#define ARPHRD_PRONET 4 /* PROnet token ring */ +#define ARPHRD_CHAOS 5 /* Chaosnet */ +#define ARPHRD_IEEE802 6 /* IEEE 802.2 Ethernet/TR/TB */ +#define ARPHRD_ARCNET 7 /* ARCnet */ +#define ARPHRD_HYPERCH 8 /* Hyperchannel */ +#define ARPHRD_LANSTAR 9 /* Lanstar */ +#define ARPHRD_AUTONET 10 /* Autonet Short Address */ +#define ARPHRD_LOCALTLK 11 /* Localtalk */ +#define ARPHRD_LOCALNET 12 /* LocalNet (IBM PCNet/Sytek LocalNET) */ +#define ARPHRD_ULTRALNK 13 /* Ultra link */ +#define ARPHRD_SMDS 14 /* SMDS */ +#define ARPHRD_DLCI 15 /* Frame Relay DLCI */ +#define ARPHRD_ATM 16 /* ATM */ +#define ARPHRD_HDLC 17 /* HDLC */ +#define ARPHRD_FIBREC 18 /* Fibre Channel */ +#define ARPHRD_ATM2225 19 /* ATM (RFC 2225) */ +#define ARPHRD_SERIAL 20 /* Serial Line */ +#define ARPHRD_ATM2 21 /* ATM */ +#define ARPHRD_MS188220 22 /* MIL-STD-188-220 */ +#define ARPHRD_METRICOM 23 /* Metricom STRIP */ +#define ARPHRD_IEEE1394 24 /* IEEE 1394.1995 */ +#define ARPHRD_MAPOS 25 /* MAPOS */ +#define ARPHRD_TWINAX 26 /* Twinaxial */ +#define ARPHRD_EUI_64 27 /* EUI-64 */ + +/* Virtual ARP types for non ARP hardware used in Linux cooked mode. */ +#define ARPHRD_IPGRE 778 /* GRE over IP */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* arptypes.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/asm_utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/asm_utils.h new file mode 100644 index 00000000..384b0d68 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/asm_utils.h @@ -0,0 +1,38 @@ +/* asm_utils.h + * Functions optionally implemented in assembler + * + * $Id: asm_utils.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ASM_UTILS_H__ +#define __ASM_UTILS_H__ + +gint wrs_strcmp(gconstpointer a, gconstpointer b); +gint wrs_strcmp_with_data(gconstpointer a, gconstpointer b, gpointer user_data); +gboolean wrs_str_equal(gconstpointer a, gconstpointer b); + +guchar wrs_check_charset(const guchar table[256], const char *str); + +guint wrs_str_hash(gconstpointer v); + +/* int wrs_count_bitshift(guint32 bitmask); */ + +#endif /* __ASM_UTILS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/asn1.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/asn1.h new file mode 100644 index 00000000..b57bbcff --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/asn1.h @@ -0,0 +1,207 @@ +/* asn1.h + * Common data for ASN.1 + * 2007 Anders Broman + * + * $Id: asn1.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ASN1_H__ +#define __ASN1_H__ + +typedef enum { + ASN1_ENC_BER, /* X.690 - BER, CER, DER */ + ASN1_ENC_PER, /* X.691 - PER */ + ASN1_ENC_ECN, /* X.692 - ECN */ + ASN1_ENC_XER /* X.693 - XER */ +} asn1_enc_e; + +typedef enum { + CB_ASN1_ENC, + CB_DISSECTOR, + CB_NEW_DISSECTOR, + CB_DISSECTOR_HANDLE +} asn1_cb_variant; + +typedef enum { + ASN1_PAR_IRR, /* irrelevant parameter */ + /* value */ + ASN1_PAR_BOOLEAN, + ASN1_PAR_INTEGER, + /* type */ + ASN1_PAR_TYPE +} asn1_par_type; + +typedef struct _asn1_par_def_t { + const gchar *name; + asn1_par_type ptype; +} asn1_par_def_t; + +typedef struct _asn1_par_t { + const gchar *name; + asn1_par_type ptype; + union { + gboolean v_boolean; + gint32 v_integer; + void *v_type; + } value; + struct _asn1_par_t *next; +} asn1_par_t; + +typedef struct _asn1_stack_frame_t { + const gchar *name; + struct _asn1_par_t *par; + struct _asn1_stack_frame_t *next; +} asn1_stack_frame_t; + +#define ASN1_CTX_SIGNATURE 0x41435458 /* "ACTX" */ + +typedef struct _asn1_ctx_t { + guint32 signature; + asn1_enc_e encoding; + gboolean aligned; + packet_info *pinfo; + proto_item *created_item; + struct _asn1_stack_frame_t *stack; + void *value_ptr; + void *private_data; + struct { + int hf_index; + gboolean data_value_descr_present; + gboolean direct_ref_present; + gboolean indirect_ref_present; + tvbuff_t *data_value_descriptor; + const char *direct_reference; + gint32 indirect_reference; + gint encoding; + /* + 0 : single-ASN1-type, + 1 : octet-aligned, + 2 : arbitrary + */ + tvbuff_t *single_asn1_type; + tvbuff_t *octet_aligned; + tvbuff_t *arbitrary; + union { + struct { + int (*ber_callback)(gboolean imp_tag, tvbuff_t *tvb, int offset, struct _asn1_ctx_t* ,proto_tree *tree, int hf_index ); + } ber; + struct { + int (*type_cb)(tvbuff_t*, int, struct _asn1_ctx_t*, proto_tree*, int); + } per; + } u; + } external; + struct { + int hf_index; + gboolean data_value_descr_present; + tvbuff_t *data_value_descriptor; + gint identification; + /* + 0 : syntaxes, + 1 : syntax, + 2 : presentation-context-id, + 3 : context-negotiation, + 4 : transfer-syntax, + 5 : fixed + */ + gint32 presentation_context_id; + const char *abstract_syntax; + const char *transfer_syntax; + tvbuff_t *data_value; + union { + struct { + int (*ber_callback)(gboolean imp_tag, tvbuff_t *tvb, int offset, struct _asn1_ctx_t* ,proto_tree *tree, int hf_index ); + } ber; + struct { + int (*type_cb)(tvbuff_t*, int, struct _asn1_ctx_t*, proto_tree*, int); + } per; + } u; + } embedded_pdv; + struct _rose_ctx_t *rose_ctx; +} asn1_ctx_t; + +#define ROSE_CTX_SIGNATURE 0x524F5345 /* "ROSE" */ + +typedef struct _rose_ctx_t { + guint32 signature; + dissector_table_t arg_global_dissector_table; + dissector_table_t arg_local_dissector_table; + dissector_table_t res_global_dissector_table; + dissector_table_t res_local_dissector_table; + dissector_table_t err_global_dissector_table; + dissector_table_t err_local_dissector_table; + /* filling in description into tree, info column, any buffer */ + int apdu_depth; + gboolean fillin_info; + gchar *fillin_ptr; + gsize fillin_buf_size; + struct { /* "dynamic" data */ + gint pdu; + /* + 1 : invoke, + 2 : returnResult, + 3 : returnError, + 4 : reject + */ + gint code; + /* + 0 : local, + 1 : global + */ + gint32 code_local; + const char *code_global; + proto_item *code_item; + } d; + void *private_data; +} rose_ctx_t; + +extern void asn1_ctx_init(asn1_ctx_t *actx, asn1_enc_e encoding, gboolean aligned, packet_info *pinfo); +extern gboolean asn1_ctx_check_signature(asn1_ctx_t *actx); +extern void asn1_ctx_clean_external(asn1_ctx_t *actx); +extern void asn1_ctx_clean_epdv(asn1_ctx_t *actx); + +extern void asn1_stack_frame_push(asn1_ctx_t *actx, const gchar *name); +extern void asn1_stack_frame_pop(asn1_ctx_t *actx, const gchar *name); +extern void asn1_stack_frame_check(asn1_ctx_t *actx, const gchar *name, const asn1_par_def_t *par_def); + +extern void asn1_param_push_boolean(asn1_ctx_t *actx, gboolean value); +extern void asn1_param_push_integer(asn1_ctx_t *actx, gint32 value); +extern gboolean asn1_param_get_boolean(asn1_ctx_t *actx, const gchar *name); +extern gint32 asn1_param_get_integer(asn1_ctx_t *actx, const gchar *name); + +extern void rose_ctx_init(rose_ctx_t *rctx); +extern gboolean rose_ctx_check_signature(rose_ctx_t *rctx); +extern void rose_ctx_clean_data(rose_ctx_t *rctx); + +extern asn1_ctx_t *get_asn1_ctx(void *ptr); +extern rose_ctx_t *get_rose_ctx(void *ptr); + +extern double asn1_get_real(const guint8 *real_ptr, gint real_len); + +/* flags */ +#define ASN1_EXT_ROOT 0x01 +#define ASN1_EXT_EXT 0x02 +#define ASN1_OPT 0x04 +#define ASN1_DFLT 0x08 + +#define ASN1_HAS_EXT(f) ((f)&(ASN1_EXT_ROOT|ASN1_EXT_EXT)) + + +#endif /* __ASN1_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/atalk-utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/atalk-utils.h new file mode 100644 index 00000000..c7cdcdf4 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/atalk-utils.h @@ -0,0 +1,63 @@ +/* atalk-utils.h + * Definitions for Appletalk utilities (DDP, currently). + * + * $Id: atalk-utils.h 3992 2008-06-10 03:13:11Z dgu $ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ATALK_UTILS_H__ +#define __ATALK_UTILS_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * Structure used to represent a DDP address; gives the layout of the + * data pointed to by an AT_ATALK "address" structure. + */ +struct atalk_ddp_addr { + guint16 net; + guint8 node; +}; + +/* + * DDP packet types. + */ +#define DDP_RTMPDATA 0x01 +#define DDP_NBP 0x02 +#define DDP_ATP 0x03 +#define DDP_AEP 0x04 +#define DDP_RTMPREQ 0x05 +#define DDP_ZIP 0x06 +#define DDP_ADSP 0x07 +#define DDP_EIGRP 0x58 + +/* + * Routines to take a DDP address and generate a string. + */ +extern gchar *atalk_addr_to_str(const struct atalk_ddp_addr *addrp); +extern void atalk_addr_to_str_buf(const struct atalk_ddp_addr *addrp, + gchar *buf, int buf_len); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/base64.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/base64.h new file mode 100644 index 00000000..38aacf8a --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/base64.h @@ -0,0 +1,38 @@ +/* base64.h + * Base-64 conversion + * + * $Id: base64.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef __BASE64_H__ +#define __BASE64_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* In-place decoding of a base64 string. */ +size_t epan_base64_decode(char *s); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __BASE64_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/bitswap.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/bitswap.h new file mode 100644 index 00000000..2f0f74db --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/bitswap.h @@ -0,0 +1,40 @@ +/* bitswap.h + * Macro to bitswap a byte by looking it up in a table + * + * $Id: bitswap.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __BITSWAP_H__ +#define __BITSWAP_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +extern guint8 swaptab[256]; + +#define BIT_SWAP(b) (swaptab[b]) + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* bitswap.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/bridged_pids.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/bridged_pids.h new file mode 100644 index 00000000..5eb3a1d0 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/bridged_pids.h @@ -0,0 +1,58 @@ +/* bridged_pids.h + * Definitions of protocol IDs for the 00-80-C2 OUI, used for + * bridging various networks over ATM (RFC 2684) or Frame Relay (RFC 2427). + * + * $Id: bridged_pids.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 - 2000 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __BRIDGED_PID_H__ +#define __BRIDGED_PID_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define BPID_ETH_WITH_FCS 0x0001 /* 802.3/Ethernet with preserved FCS */ +#define BPID_ETH_WITHOUT_FCS 0x0007 /* 802.3/Ethernet without preserved FCS */ + +#define BPID_802_4_WITH_FCS 0x0002 /* 802.4 with preserved FCS */ +#define BPID_802_4_WITHOUT_FCS 0x0008 /* 802.4 without preserved FCS */ + +#define BPID_802_5_WITH_FCS 0x0003 /* 802.5 with preserved FCS */ +#define BPID_802_5_WITHOUT_FCS 0x0009 /* 802.5 without preserved FCS */ + +#define BPID_FDDI_WITH_FCS 0x0004 /* FDDI with preserved FCS */ +#define BPID_FDDI_WITHOUT_FCS 0x000A /* FDDI without preserved FCS */ + +#define BPID_802_6_WITH_FCS 0x0005 /* 802.6 with preserved FCS */ +#define BPID_802_6_WITHOUT_FCS 0x000B /* 802.6 without preserved FCS */ + +#define BPID_FRAGMENTS 0x000D + +#define BPID_BPDU 0x000E /* 802.1(d) or 802.1(g) BPDUs */ + +#define BPID_SR_BPDU 0x000F /* Source Routing BPDUs */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* bridged_pid.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/camel-persistentdata.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/camel-persistentdata.h new file mode 100644 index 00000000..ef8bfd05 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/camel-persistentdata.h @@ -0,0 +1,127 @@ +/* + * camel-persistentdata.h + * Definitions for lists and hash tables used in wireshark's camel dissector + * for calculation of delays in camel-transactions + * Copyright 2006 Florent Drouin + * + * $Id: camel-persistentdata.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __CAMEL_PERSISTENTDATA_H__ +#define __CAMEL_PERSISTENTDATA_H__ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define NB_CAMELSRT_CATEGORY 9+1 /* Number of type of message */ +/* for example TC_BEGIN with InitalDP, and TC_CONT with RequestReportBCSMEvent + is a category, we want to measure the delay between the two messages */ + +#define CAMELSRT_SESSION 1 + +#define CAMELSRT_VOICE_INITIALDP 2 +#define CAMELSRT_VOICE_ACR1 3 +#define CAMELSRT_VOICE_ACR2 4 +#define CAMELSRT_VOICE_ACR3 5 +#define CAMELSRT_VOICE_DISC 6 + +#define CAMELSRT_GPRS_INITIALDP 7 +#define CAMELSRT_GPRS_REPORT 8 + +#define CAMELSRT_SMS_INITIALDP 9 + +WS_VAR_IMPORT const value_string camelSRTtype_naming[]; + +/* If we have a request message and its response, + (eg: ApplyCharging, ApplyChargingReport) + the frames numbers are stored in this structure */ + +struct camelsrt_category_t { + guint32 req_num; /* frame number request seen */ + guint32 rsp_num; /* frame number response seen */ + nstime_t req_time; /* arrival time of request */ + gboolean responded; /* true, if request has been responded */ +}; + +/* List of stored parameters for a Camel dialogue + All this parameters are linked to the hash table key below (use of Tid) + In case of same Tid reused, the Camel parameters are chained. + The right dialogue will be identified with the arrival time of the InitialDP */ + +struct camelsrt_call_t { + guint32 session_id; /* Identify the session, with an internal number */ + struct tcaphash_context_t * tcap_context; + struct camelsrt_category_t category[NB_CAMELSRT_CATEGORY]; +}; + + +/* The Key for the hash table is the TCAP origine transaction identifier + of the TC_BEGIN containing the InitialDP */ + +struct camelsrt_call_info_key_t { + guint32 SessionIdKey; +}; + +/* Info for a couple of messages (or category) + The request must be available, not duplicated, + and once the corresponding response received, + we can deduce the Delta Time between Request/response */ + +struct camelsrt_msginfo_t { + gboolean request_available; + gboolean is_duplicate; + gboolean is_delta_time; + nstime_t req_time; + nstime_t delta_time; +}; + +/* List of infos to store for the analyse */ + +struct camelsrt_info_t { + guint32 tcap_session_id; + void * tcap_context; + guint8 opcode; /* operation code of message received */ + guint8 bool_msginfo[NB_CAMELSRT_CATEGORY]; /* category for the received message */ + struct camelsrt_msginfo_t msginfo[NB_CAMELSRT_CATEGORY]; +}; + +void camelsrt_init_routine(void); + +struct camelsrt_info_t * camelsrt_razinfo(void); + +void camelsrt_call_matching(tvbuff_t *tvb, + packet_info * pinfo _U_, + proto_tree *tree, + struct camelsrt_info_t * p_camel_info); + +WS_VAR_IMPORT gboolean gcamel_StatSRT; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* camel-persistentdata.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/charsets.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/charsets.h new file mode 100644 index 00000000..ed50cfc3 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/charsets.h @@ -0,0 +1,42 @@ +/* charsets.h + * Routines for handling character sets + * + * $Id: charsets.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef __CHARSETS_H__ +#define __CHARSETS_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#if 0 +void ASCII_to_EBCDIC(guint8 *buf, guint bytes); +guint8 ASCII_to_EBCDIC1(guint8 c); +#endif +void EBCDIC_to_ASCII(guint8 *buf, guint bytes); +guint8 EBCDIC_to_ASCII1(guint8 c); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __CHARSETS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/chdlctypes.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/chdlctypes.h new file mode 100644 index 00000000..374c2d75 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/chdlctypes.h @@ -0,0 +1,40 @@ +/* chdlctypes.h + * Defines Cisco HDLC packet types that aren't just Ethernet types + * + * $Id: chdlctypes.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __CHDLCTYPES_H__ +#define __CHDLCTYPES_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define CHDLCTYPE_FRARP 0x0808 /* Frame Relay ARP */ +#define CHDLCTYPE_BPDU 0x4242 /* IEEE spanning tree protocol */ +#define CHDLCTYPE_OSI 0xfefe /* ISO network-layer protocols */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* chdlctypes.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/circuit.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/circuit.h new file mode 100644 index 00000000..c6fa6762 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/circuit.h @@ -0,0 +1,80 @@ +/* circuit.h + * Routines for building lists of packets that are part of a "circuit" + * + * $Id: circuit.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __CIRCUIT_H__ +#define __CIRCUIT_H__ + +#include "packet.h" /* for circuit dissector type */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * Data structure representing a circuit. + */ +typedef struct circuit_key { + circuit_type ctype; + guint32 circuit_id; +} circuit_key; + +typedef struct circuit { + struct circuit *next; /* pointer to next circuit with given circuit ID */ + guint32 first_frame; /* # of first frame for that circuit */ + guint32 last_frame; /* # of last frame for that circuit */ + guint32 index; /* unique ID for circuit */ + GSList *data_list; /* list of data associated with circuit */ + dissector_handle_t dissector_handle; + /* handle for protocol dissector client associated with circuit */ + guint options; /* wildcard flags */ + circuit_key *key_ptr; /* pointer to the key for this circuit */ +} circuit_t; + +extern void circuit_init(void); + +extern circuit_t *circuit_new(circuit_type ctype, guint32 circuit_id, + guint32 first_frame); + +extern circuit_t *find_circuit(circuit_type ctype, guint32 circuit_id, + guint32 frame); + +extern void close_circuit(circuit_t *circuit, guint32 last_frame); + +extern void circuit_add_proto_data(circuit_t *conv, int proto, + void *proto_data); +extern void *circuit_get_proto_data(circuit_t *conv, int proto); +extern void circuit_delete_proto_data(circuit_t *conv, int proto); + +extern void circuit_set_dissector(circuit_t *circuit, + dissector_handle_t handle); +extern dissector_handle_t circuit_get_dissector(circuit_t *circuit); +extern gboolean +try_circuit_dissector(circuit_type ctype, guint32 circuit_id, guint32 frame, + tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* circuit.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/codecs.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/codecs.h new file mode 100644 index 00000000..928ddf34 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/codecs.h @@ -0,0 +1,43 @@ +/* codecs.h + * codecs interface 2007 Tomas Kukosa + * + * $Id: codecs.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _CODECS_H_ +#define _CODECS_H_ + +#include "epan/epan.h" + +struct codec_handle; +typedef struct codec_handle *codec_handle_t; + +typedef void *(*codec_init_fn)(void); +typedef void (*codec_release_fn)(void *context); +typedef int (*codec_decode_fn)(void *context, const void *input, int inputSizeBytes, void *output, int *outputSizeBytes); + +extern void register_codec(const char *name, codec_init_fn init_fn, codec_release_fn release_fn, codec_decode_fn decode_fn); +extern codec_handle_t find_codec(const char *name); +extern void *codec_init(codec_handle_t codec); +extern void codec_release(codec_handle_t codec, void *context); +extern int codec_decode(codec_handle_t codec, void *context, const void *input, int inputSizeBytes, void *output, int *outputSizeBytes); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column-utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column-utils.h new file mode 100644 index 00000000..c85aa5bf --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column-utils.h @@ -0,0 +1,241 @@ +/* column-utils.h + * Definitions for column utility structures and routines + * + * $Id: column-utils.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __COLUMN_UTILS_H__ +#define __COLUMN_UTILS_H__ + +#include + +#include "gnuc_format_check.h" +#include "column_info.h" +#include "packet_info.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** Maximum length of columns (except COL_INFO). + * Internal, don't use this in dissectors! + */ + +#define COL_MAX_LEN 256 +/** Maximum length of info columns (COL_INFO only). + * Internal, don't use this in dissectors! + */ +#define COL_MAX_INFO_LEN 4096 + + +/** Allocate all the data structures for constructing column data, given + * the number of columns. + * + * Internal, don't use this in dissectors! + */ +extern void col_setup(column_info *cinfo, gint num_cols); + +/** Initialize the data structures for constructing column data. + * + * Internal, don't use this in dissectors! + */ +extern void col_init(column_info *cinfo); + +/** Set the format of the "variable time format". + * + * Internal, don't use this in dissectors! + */ +extern void col_set_cls_time(frame_data *, column_info *cinfo, gint col); + +/** Fill in all columns of the given packet. + * + * Internal, don't use this in dissectors! + */ +extern void col_fill_in(packet_info *pinfo); + +/* Utility routines used by packet*.c */ + +/** Are the columns writable? + * + * @param cinfo the current packet row + * @return TRUE if it's writable, FALSE if not + */ +extern gboolean col_get_writable(column_info *cinfo); + +/** Set the columns writable. + * + * @param cinfo the current packet row + * @param writable TRUE if it's writable, FALSE if not + */ +extern void col_set_writable(column_info *cinfo, gboolean writable); + +/** Check if the given column be filled with data. + * + * @param cinfo the current packet row + * @param col the column to use, e.g. COL_INFO + */ +extern gint check_col(column_info *cinfo, gint col); + +/** Sets a fence for the current column content, + * so this content won't be affected by further col_... function calls. + * + * This can be useful if a protocol is more than once in a single packet, + * e.g. multiple HTTP calls in a single TCP packet. + * + * @param cinfo the current packet row + * @param col the column to use, e.g. COL_INFO + */ +extern void col_set_fence(column_info *cinfo, gint col); + +/** Clears the text of a column element. + * + * @param cinfo the current packet row + * @param col the column to use, e.g. COL_INFO + */ +extern void col_clear(column_info *cinfo, gint col); + +/** Set (replace) the text of a column element, the text won't be copied. + * + * Usually used to set const strings! + * + * @param cinfo the current packet row + * @param col the column to use, e.g. COL_INFO + * @param str the string to set + */ +extern void col_set_str(column_info *cinfo, gint col, const gchar * str); + +/** Add (replace) the text of a column element, the text will be copied. + * + * @param cinfo the current packet row + * @param col the column to use, e.g. COL_INFO + * @param str the string to add + */ +extern void col_add_str(column_info *cinfo, gint col, const gchar *str); + +/** Add (replace) the text of a column element, the text will be formatted and copied. + * + * Same function as col_add_str() but using a printf-like format string. + * + * @param cinfo the current packet row + * @param col the column to use, e.g. COL_INFO + * @param format the format string + * @param ... the variable number of parameters + */ +extern void col_add_fstr(column_info *cinfo, gint col, const gchar *format, ...) + GNUC_FORMAT_CHECK(printf, 3, 4); + +/* For internal Wireshark use only. Not to be called from dissectors. */ +void col_custom_set_fstr(header_field_info *hfinfo, const gchar *format, ...) + GNUC_FORMAT_CHECK(printf, 2, 3); + +/* For internal Wireshark use only. Not to be called from dissectors. */ +void col_custom_prime_edt(epan_dissect_t *edt, column_info *cinfo); + +/* For internal Wireshark use only. Not to be called from dissectors. */ +gboolean have_custom_cols(column_info *cinfo); + +/** Append the given text to a column element, the text will be copied. + * + * @param cinfo the current packet row + * @param col the column to use, e.g. COL_INFO + * @param str the string to append + */ +extern void col_append_str(column_info *cinfo, gint col, const gchar *str); + +/** Append the given text to a column element, the text will be formatted and copied. + * + * Same function as col_append_str() but using a printf-like format string. + * + * @param cinfo the current packet row + * @param col the column to use, e.g. COL_INFO + * @param format the format string + * @param ... the variable number of parameters + */ +extern void col_append_fstr(column_info *cinfo, gint col, const gchar *format, ...) + GNUC_FORMAT_CHECK(printf, 3, 4); + +/** Prepend the given text to a column element, the text will be formatted and copied. + * + * @param cinfo the current packet row + * @param col the column to use, e.g. COL_INFO + * @param format the format string + * @param ... the variable number of parameters + */ +extern void col_prepend_fstr(column_info *cinfo, gint col, const gchar *format, ...) + GNUC_FORMAT_CHECK(printf, 3, 4); + +/**Prepend the given text to a column element, the text will be formatted and copied. + * This function is similar to col_prepend_fstr() but this function will + * unconditionally set a fence to the end of the prepended data even if there + * were no fence before. + * The col_prepend_fstr() will only prepend the data before the fence IFF + * there is already a fence created. This function will create a fence in case + * it does not yet exist. + */ +extern void col_prepend_fence_fstr(column_info *cinfo, gint col, const gchar *format, ...) + GNUC_FORMAT_CHECK(printf, 3, 4); + +/** Append the given text (prepended by a separator) to a column element. + * + * Much like col_append_str() but will prepend the given separator if the column isn't empty. + * + * @param cinfo the current packet row + * @param col the column to use, e.g. COL_INFO + * @param sep the separator string or NULL for default: ", " + * @param str the string to append + */ +extern void col_append_sep_str(column_info *cinfo, gint col, const gchar *sep, + const gchar *str); + +/** Append the given text (prepended by a separator) to a column element. + * + * Much like col_append_fstr() but will prepend the given separator if the column isn't empty. + * + * @param cinfo the current packet row + * @param col the column to use, e.g. COL_INFO + * @param sep the separator string or NULL for default: ", " + * @param format the format string + * @param ... the variable number of parameters + */ +extern void col_append_sep_fstr(column_info *cinfo, gint col, const gchar *sep, + const gchar *format, ...) + GNUC_FORMAT_CHECK(printf, 4, 5); + +/** Set the given (relative) time to a column element. + * + * Used by multiple dissectors to set the time in the columns + * COL_REL_CONV_TIME and COL_DELTA_CONV_TIME + * + * @param cinfo the current packet row + * @param col the column to use, e.g. COL_INFO + * @param ts the time to set in the column + * @param fieldname the fieldname to use for creating a filter (when + * applying/preparing/copying as filter) + */ +extern void col_set_time(column_info *cinfo, int col, + nstime_t *ts, char *fieldname); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __COLUMN_UTILS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column.h new file mode 100644 index 00000000..90fa3296 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column.h @@ -0,0 +1,56 @@ +/* column.h + * Definitions for column handling routines + * + * $Id: column.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __COLUMN_H__ +#define __COLUMN_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct _fmt_data { + gchar *title; + gchar *fmt; + gchar *custom_field; +} fmt_data; + +const gchar *col_format_to_string(gint); +const gchar *col_format_desc(gint); +gint get_column_format(gint); +void get_column_format_matches(gboolean *, gint); +gint get_column_format_from_str(gchar *); +gchar *get_column_title(gint); +gchar *get_column_custom_field(gint); +const gchar *get_column_width_string(gint, gint); +const char *get_column_longest_string(gint); +gint get_column_char_width(gint format); + +void +build_column_format_array(capture_file *cfile, gboolean reset_fences); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* column.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column_info.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column_info.h new file mode 100644 index 00000000..5f70573f --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column_info.h @@ -0,0 +1,134 @@ +/* column.h + * Definitions for column structures and routines + * + * $Id: column_info.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __COLUMN_INFO_H__ +#define __COLUMN_INFO_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define COL_MAX_LEN 256 +#define COL_MAX_INFO_LEN 4096 + +typedef struct { + gchar **col_expr; /* Filter expression */ + gchar **col_expr_val; /* Value for filter expression */ +} col_expr_t; + +typedef struct _column_info { + gint num_cols; /* Number of columns */ + gint *col_fmt; /* Format of column */ + gboolean **fmt_matx; /* Specifies which formats apply to a column */ + gint *col_first; /* First column number with a given format */ + gint *col_last; /* Last column number with a given format */ + gchar **col_title; /* Column titles */ + gchar **col_custom_field; /* Custom column field */ + const gchar **col_data; /* Column data */ + gchar **col_buf; /* Buffer into which to copy data for column */ + int *col_fence; /* Stuff in column buffer before this index is immutable */ + col_expr_t col_expr; /* Column expressions and values */ + gboolean writable; /* Are we still writing to the columns? */ + gboolean columns_changed; /* Have the columns been changed in the prefs? */ +} column_info; + +/* + * All of the possible columns in summary listing. + * + * NOTE1: The entries MUST remain in this order, or else you need to reorder + * the slist[] and dlist[] arrays in column.c to match! + * + * NOTE2: Please add the COL_XYZ entry in the appropriate spot, such that the + * dlist[] array remains in alphabetical order! + */ +enum { + COL_8021Q_VLAN_ID, /* 0) 802.1Q vlan ID */ + COL_ABS_DATE_TIME, /* 1) Absolute date and time */ + COL_ABS_TIME, /* 2) Absolute time */ + COL_CIRCUIT_ID, /* 3) Circuit ID */ + COL_DSTIDX, /* 4) Dst port idx - Cisco MDS-specific */ + COL_SRCIDX, /* 5) Src port idx - Cisco MDS-specific */ + COL_VSAN, /* 6) VSAN - Cisco MDS-specific */ + COL_CUMULATIVE_BYTES, /* 7) Cumulative number of bytes */ + COL_CUSTOM, /* 8) Custom column (any filter name's contents) */ + COL_DCE_CALL, /* 9) DCE/RPC connection oriented call id OR datagram sequence number */ + COL_DCE_CTX, /* 10) DCE/RPC connection oriented context id */ + COL_DELTA_TIME, /* 11) Delta time */ + COL_DELTA_CONV_TIME,/* 12) Delta time to last frame in conversation */ + COL_DELTA_TIME_DIS, /* 13) Delta time displayed*/ + COL_RES_DST, /* 14) Resolved dest */ + COL_UNRES_DST, /* 15) Unresolved dest */ + COL_RES_DST_PORT, /* 16) Resolved dest port */ + COL_UNRES_DST_PORT, /* 17) Unresolved dest port */ + COL_DEF_DST, /* 18) Destination address */ + COL_DEF_DST_PORT, /* 19) Destination port */ + COL_EXPERT, /* 20) Expert Info */ + COL_IF_DIR, /* 21) FW-1 monitor interface/direction */ + COL_OXID, /* 22) Fibre Channel OXID */ + COL_RXID, /* 23) Fibre Channel RXID */ + COL_FR_DLCI, /* 24) Frame Relay DLCI */ + COL_FREQ_CHAN, /* 25) IEEE 802.11 (and WiMax?) - Channel */ + COL_BSSGP_TLLI, /* 26) GPRS BSSGP IE TLLI */ + COL_HPUX_DEVID, /* 27) HP-UX Nettl Device ID */ + COL_HPUX_SUBSYS, /* 28) HP-UX Nettl Subsystem */ + COL_DEF_DL_DST, /* 29) Data link layer dest address */ + COL_DEF_DL_SRC, /* 30) Data link layer source address */ + COL_RES_DL_DST, /* 31) Resolved DL dest */ + COL_UNRES_DL_DST, /* 32) Unresolved DL dest */ + COL_RES_DL_SRC, /* 33) Resolved DL source */ + COL_UNRES_DL_SRC, /* 34) Unresolved DL source */ + COL_RSSI, /* 35) IEEE 802.11 - received signal strength */ + COL_TX_RATE, /* 36) IEEE 802.11 - TX rate in Mbps */ + COL_DSCP_VALUE, /* 37) IP DSCP Value */ + COL_INFO, /* 38) Description */ + COL_COS_VALUE, /* 39) L2 COS Value */ + COL_RES_NET_DST, /* 40) Resolved net dest */ + COL_UNRES_NET_DST, /* 41) Unresolved net dest */ + COL_RES_NET_SRC, /* 42) Resolved net source */ + COL_UNRES_NET_SRC, /* 43) Unresolved net source */ + COL_DEF_NET_DST, /* 44) Network layer dest address */ + COL_DEF_NET_SRC, /* 45) Network layer source address */ + COL_NUMBER, /* 46) Packet list item number */ + COL_PACKET_LENGTH, /* 47) Packet length in bytes */ + COL_PROTOCOL, /* 48) Protocol */ + COL_REL_TIME, /* 49) Relative time */ + COL_REL_CONV_TIME, /* 50) Relative time to beginning of conversation */ + COL_DEF_SRC, /* 51) Source address */ + COL_DEF_SRC_PORT, /* 52) Source port */ + COL_RES_SRC, /* 53) Resolved source */ + COL_UNRES_SRC, /* 54) Unresolved source */ + COL_RES_SRC_PORT, /* 55) Resolved source port */ + COL_UNRES_SRC_PORT, /* 56) Unresolved source port */ + COL_TEI, /* 57) Q.921 TEI */ + COL_CLS_TIME, /* 58) Command line-specified time (default relative) */ + NUM_COL_FMTS /* 59) Should always be last */ +}; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __COLUMN_INFO_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/conversation.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/conversation.h new file mode 100644 index 00000000..988ae94b --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/conversation.h @@ -0,0 +1,109 @@ +/* conversation.h + * Routines for building lists of packets that are part of a "conversation" + * + * $Id: conversation.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __CONVERSATION_H__ +#define __CONVERSATION_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * Flags to pass to "conversation_new()" to indicate that the address 2 + * and/or port 2 values for the conversation should be wildcards. + * The CONVERSATION_TEMPLATE option tells that any of the other supplied + * port and / or address wildcards will be used to match an infinite number + * of new connections to the conversation(s) that have the CONVERSATION_- + * TEMPLATE flag set. Any conversation created without the CONVERSATION_- + * TEMPLATE flag will be altered once the first connections (connection + * oriented protocols only) to include the newly found information which + * matched the wildcard options. + */ +#define NO_ADDR2 0x01 +#define NO_PORT2 0x02 +#define NO_PORT2_FORCE 0x04 +#define CONVERSATION_TEMPLATE 0x08 + +/* + * Flags to pass to "find_conversation()" to indicate that the address B + * and/or port B search arguments are wildcards. + */ +#define NO_ADDR_B 0x01 +#define NO_PORT_B 0x02 + +#include "packet.h" /* for conversation dissector type */ + +/* + * Data structure representing a conversation. + */ +typedef struct conversation_key { + struct conversation_key *next; + address addr1; + address addr2; + port_type ptype; + guint32 port1; + guint32 port2; +} conversation_key; + +typedef struct conversation { + struct conversation *next; /* pointer to next conversation on hash chain */ + guint32 index; /* unique ID for conversation */ + guint32 setup_frame; /* frame number that setup this conversation */ + GSList *data_list; /* list of data associated with conversation */ + dissector_handle_t dissector_handle; + /* handle for protocol dissector client associated with conversation */ + guint options; /* wildcard flags */ + conversation_key *key_ptr; /* pointer to the key for this conversation */ +} conversation_t; + +extern void conversation_init(void); + +extern conversation_t *conversation_new(guint32 setup_frame, address *addr1, address *addr2, + port_type ptype, guint32 port1, guint32 port2, guint options); + +extern conversation_t *find_conversation(guint32 frame_num, address *addr_a, address *addr_b, + port_type ptype, guint32 port_a, guint32 port_b, guint options); + +extern void conversation_add_proto_data(conversation_t *conv, int proto, + void *proto_data); +extern void *conversation_get_proto_data(conversation_t *conv, int proto); +extern void conversation_delete_proto_data(conversation_t *conv, int proto); + +extern void conversation_set_dissector(conversation_t *conversation, + dissector_handle_t handle); +extern gboolean +try_conversation_dissector(address *addr_a, address *addr_b, port_type ptype, + guint32 port_a, guint32 port_b, tvbuff_t *tvb, packet_info *pinfo, + proto_tree *tree); + +/* These routines are used to set undefined values for a conversation */ + +extern void conversation_set_port2(conversation_t *conv, guint32 port); +extern void conversation_set_addr2(conversation_t *conv, address *addr); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* conversation.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc10.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc10.h new file mode 100644 index 00000000..90e8cbc6 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc10.h @@ -0,0 +1,27 @@ +/* + * crc10.h + * + * $Id: crc10.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* update the data block's CRC-10 remainder one byte at a time */ +extern guint16 update_crc10_by_bytes(guint16 crc10, const guint8 *data_blk_ptr, int data_blk_size); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc16.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc16.h new file mode 100644 index 00000000..445b9430 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc16.h @@ -0,0 +1,109 @@ +/* crc16.h + * Declaration of CRC-16 routines and table + * + * 2004 Richard van der Hoff + * + * $Id: crc16.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * Copied from README.developer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __CRC16_H_ +#define __CRC16_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Calculate the CCITT/ITU/CRC-16 16-bit CRC + + (parameters for this CRC are: + Polynomial: x^16 + x^12 + x^5 + 1 (0x1021); + Start value 0xFFFF; + XOR result with 0xFFFF; + First bit is LSB) +*/ + +/** Compute CRC16 CCITT checksum of a buffer of data. + @param buf The buffer containing the data. + @param len The number of bytes to include in the computation. + @return The CRC16 CCITT checksum. */ +extern guint16 crc16_ccitt(const guint8 *buf, guint len); + +/** Compute CRC16 X.25 CCITT checksum of a buffer of data. + @param buf The buffer containing the data. + @param len The number of bytes to include in the computation. + @return The CRC16 X.25 CCITT checksum. */ +extern guint16 crc16_x25_ccitt(const guint8 *buf, guint len); + +/** Compute CRC16 CCITT checksum of a buffer of data. If computing the + * checksum over multiple buffers and you want to feed the partial CRC16 + * back in, remember to take the 1's complement of the partial CRC16 first. + @param buf The buffer containing the data. + @param len The number of bytes to include in the computation. + @param seed The seed to use. + @return The CRC16 CCITT checksum (using the given seed). */ +extern guint16 crc16_ccitt_seed(const guint8 *buf, guint len, guint16 seed); + +/** Compute CRC16 CCITT checksum of a tv buffer. + @param tvb The tv buffer containing the data. + @param len The number of bytes to include in the computation. + @return The CRC16 CCITT checksum. */ +extern guint16 crc16_ccitt_tvb(tvbuff_t *tvb, guint len); + +/** Compute CRC16 X.25 CCITT checksum of a tv buffer. + @param tvb The tv buffer containing the data. + @param len The number of bytes to include in the computation. + @return The CRC16 X.25 CCITT checksum. */ +extern guint16 crc16_x25_ccitt_tvb(tvbuff_t *tvb, guint len); + +/** Compute CRC16 CCITT checksum of a tv buffer. + @param tvb The tv buffer containing the data. + @param offset The offset into the tv buffer. + @param len The number of bytes to include in the computation. + @return The CRC16 CCITT checksum. */ +extern guint16 crc16_ccitt_tvb_offset(tvbuff_t *tvb, guint offset, guint len); + +/** Compute CRC16 CCITT checksum of a tv buffer. If computing the + * checksum over multiple tv buffers and you want to feed the partial CRC16 + * back in, remember to take the 1's complement of the partial CRC16 first. + @param tvb The tv buffer containing the data. + @param len The number of bytes to include in the computation. + @param seed The seed to use. + @return The CRC16 CCITT checksum (using the given seed). */ +extern guint16 crc16_ccitt_tvb_seed(tvbuff_t *tvb, guint len, guint16 seed); + +/** Compute CRC16 CCITT checksum of a tv buffer. If computing the + * checksum over multiple tv buffers and you want to feed the partial CRC16 + * back in, remember to take the 1's complement of the partial CRC16 first. + @param tvb The tv buffer containing the data. + @param offset The offset into the tv buffer. + @param len The number of bytes to include in the computation. + @param seed The seed to use. + @return The CRC16 CCITT checksum (using the given seed). */ +extern guint16 crc16_ccitt_tvb_offset_seed(tvbuff_t *tvb, guint offset, + guint len, guint16 seed); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* crc16.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc32.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc32.h new file mode 100644 index 00000000..72f4abbe --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc32.h @@ -0,0 +1,94 @@ +/* crc32.h + * Declaration of CRC-32 routine and table + * + * $Id: crc32.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * Copied from README.developer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __CRC32_H_ +#define __CRC32_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +extern const guint32 crc32_ccitt_table[256]; + +/** Compute CRC32 CCITT checksum of a buffer of data. + @param buf The buffer containing the data. + @param len The number of bytes to include in the computation. + @return The CRC32 CCITT checksum. */ +extern guint32 crc32_ccitt(const guint8 *buf, guint len); + +/** Compute CRC32 CCITT checksum of a buffer of data. If computing the + * checksum over multiple buffers and you want to feed the partial CRC32 + * back in, remember to take the 1's complement of the partial CRC32 first. + @param buf The buffer containing the data. + @param len The number of bytes to include in the computation. + @param seed The seed to use. + @return The CRC32 CCITT checksum (using the given seed). */ +extern guint32 crc32_ccitt_seed(const guint8 *buf, guint len, guint32 seed); + +/** Compute CRC32 CCITT checksum of a tv buffer. + @param tvb The tv buffer containing the data. + @param len The number of bytes to include in the computation. + @return The CRC32 CCITT checksum. */ +extern guint32 crc32_ccitt_tvb(tvbuff_t *tvb, guint len); + +/** Compute CRC32 CCITT checksum of a tv buffer. + @param tvb The tv buffer containing the data. + @param offset The offset into the tv buffer. + @param len The number of bytes to include in the computation. + @return The CRC32 CCITT checksum. */ +extern guint32 crc32_ccitt_tvb_offset(tvbuff_t *tvb, guint offset, guint len); + +/** Compute CRC32 CCITT checksum of a tv buffer. If computing the + * checksum over multiple tv buffers and you want to feed the partial CRC32 + * back in, remember to take the 1's complement of the partial CRC32 first. + @param tvb The tv buffer containing the data. + @param len The number of bytes to include in the computation. + @param seed The seed to use. + @return The CRC32 CCITT checksum (using the given seed). */ +extern guint32 crc32_ccitt_tvb_seed(tvbuff_t *tvb, guint len, guint32 seed); + +/** Compute CRC32 CCITT checksum of a tv buffer. If computing the + * checksum over multiple tv buffers and you want to feed the partial CRC32 + * back in, remember to take the 1's complement of the partial CRC32 first. + @param tvb The tv buffer containing the data. + @param offset The offset into the tv buffer. + @param len The number of bytes to include in the computation. + @param seed The seed to use. + @return The CRC32 CCITT checksum (using the given seed). */ +extern guint32 crc32_ccitt_tvb_offset_seed(tvbuff_t *tvb, guint offset, + guint len, guint32 seed); + +/** Compute IEEE 802.x CRC32 checksum of a tv buffer. + @param tvb The tv buffer containing the data. + @param len The number of bytes to include in the computation. + @return The IEEE 802.x CRC32 checksum. */ +extern guint32 crc32_802_tvb(tvbuff_t *tvb, guint len); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* crc32.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc6.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc6.h new file mode 100644 index 00000000..cb295faa --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc6.h @@ -0,0 +1,26 @@ +/* + * crc6.h + * + * $Id: crc6.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +extern guint16 update_crc6_by_bytes(guint16 crc6, guint8 byte1, guint8 byte2); + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crcdrm.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crcdrm.h new file mode 100644 index 00000000..0987f50f --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crcdrm.h @@ -0,0 +1,7 @@ +#ifndef _CRCDRM_H + +#include + +unsigned long crc_drm(const char *data, size_t bytesize, + unsigned short num_crc_bits, unsigned long crc_gen, int invert); +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_debug.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_debug.h new file mode 100644 index 00000000..849c6662 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_debug.h @@ -0,0 +1,106 @@ +/* airpcap_debug.h + * + * $Id: airpdcap_debug.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Copyright (c) 2006 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _AIRPDCAP_DEBUG_H +#define _AIRPDCAP_DEBUG_H + +#include "airpdcap_interop.h" + +void print_debug_line(CHAR *function, CHAR *msg, INT level); + +#ifdef _DEBUG +#ifdef __FUNCTION__ +#define AIRPDCAP_DEBUG_PRINT_LINE(notdefined, msg, level) print_debug_line(__FUNCTION__, msg, level); +#else +#define AIRPDCAP_DEBUG_PRINT_LINE(function, msg, level) print_debug_line(function, msg, level); +#endif +#else +#ifdef __FUNCTION__ +#define AIRPDCAP_DEBUG_PRINT_LINE(notdefined, msg, level) +#else +#define AIRPDCAP_DEBUG_PRINT_LINE(function, msg, level) +#endif +#endif + +/******************************************************************************/ +/* Debug section: internal function to print debug information */ +/* */ +#ifdef _DEBUG +#include "stdio.h" +#include + +/* Debug level definition */ +#define AIRPDCAP_DEBUG_LEVEL_1 1 +#define AIRPDCAP_DEBUG_LEVEL_2 2 +#define AIRPDCAP_DEBUG_LEVEL_3 3 +#define AIRPDCAP_DEBUG_LEVEL_4 4 +#define AIRPDCAP_DEBUG_LEVEL_5 5 + +#define AIRPDCAP_DEBUG_USED_LEVEL AIRPDCAP_DEBUG_LEVEL_3 + +#ifdef _TRACE +#ifdef __FUNCTION__ +#define AIRPDCAP_DEBUG_TRACE_START(notdefined) print_debug_line(__FUNCTION__, "Start!", AIRPDCAP_DEBUG_USED_LEVEL); +#define AIRPDCAP_DEBUG_TRACE_END(notdefined) print_debug_line(__FUNCTION__, "End!", AIRPDCAP_DEBUG_USED_LEVEL); +#else +#define AIRPDCAP_DEBUG_TRACE_START(function) print_debug_line(function, "Start!", AIRPDCAP_DEBUG_USED_LEVEL); +#define AIRPDCAP_DEBUG_TRACE_END(function) print_debug_line(function, "End!", AIRPDCAP_DEBUG_USED_LEVEL); +#endif +#else +#ifdef __FUNCTION__ +#define AIRPDCAP_DEBUG_TRACE_START(notdefined) +#define AIRPDCAP_DEBUG_TRACE_END(notdefined) +#else +#define AIRPDCAP_DEBUG_TRACE_START(function) +#define AIRPDCAP_DEBUG_TRACE_END(function) +#endif +#endif + +#else /* !defined _DEBUG */ + +#define AIRPDCAP_DEBUG_LEVEL_1 +#define AIRPDCAP_DEBUG_LEVEL_2 +#define AIRPDCAP_DEBUG_LEVEL_3 +#define AIRPDCAP_DEBUG_LEVEL_4 +#define AIRPDCAP_DEBUG_LEVEL_5 + +#define AIRPDCAP_DEBUG_TRACE_START(function) +#define AIRPDCAP_DEBUG_TRACE_END(function) + +#endif /* ?defined _DEBUG */ + + +#endif /* ?defined _AIRPDCAP_DEBUG_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_int.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_int.h new file mode 100644 index 00000000..b3d4a75b --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_int.h @@ -0,0 +1,158 @@ +/* airpcap_int.h + * + * $Id: airpdcap_int.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Copyright (c) 2006 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _AIRPDCAP_INT_H +#define _AIRPDCAP_INT_H + +/****************************************************************************/ +/* File includes */ + +#include "airpdcap_interop.h" + +/****************************************************************************/ + +/****************************************************************************/ +/* Definitions */ + +/* IEEE 802.11 packet type values */ +#define AIRPDCAP_TYPE_MANAGEMENT 0 +#define AIRPDCAP_TYPE_CONTROL 1 +#define AIRPDCAP_TYPE_DATA 2 + +/* Min length of encrypted data (TKIP=25bytes, CCMP=21bytes) */ +#define AIRPDCAP_CRYPTED_DATA_MINLEN 21 + +#define AIRPDCAP_TA_OFFSET 10 + +/* */ +/****************************************************************************/ + +/****************************************************************************/ +/* Macro definitions */ + +/** + * Macros to get various bits of a 802.11 control frame + */ +#define AIRPDCAP_TYPE(FrameControl_0) (UINT8)((FrameControl_0 >> 2) & 0x3) +#define AIRPDCAP_SUBTYPE(FrameControl_0) (UINT8)((FrameControl_0 >> 4) & 0xF) +#define AIRPDCAP_DS_BITS(FrameControl_1) (UINT8)(FrameControl_1 & 0x3) +#define AIRPDCAP_TO_DS(FrameControl_1) (UINT8)(FrameControl_1 & 0x1) +#define AIRPDCAP_FROM_DS(FrameControl_1) (UINT8)((FrameControl_1 >> 1) & 0x1) +#define AIRPDCAP_WEP(FrameControl_1) (UINT8)((FrameControl_1 >> 6) & 0x1) + +/** + * Get the Key ID from the Initialization Vector (last byte) + */ +#define AIRPDCAP_EXTIV(KeyID) ((KeyID >> 5) & 0x1) + +/* Macros to get various bits of an EAPOL frame */ +#define AIRPDCAP_EAP_KEY_DESCR_VER(KeyInfo_1) ((UCHAR)(KeyInfo_1 & 0x3)) +#define AIRPDCAP_EAP_KEY(KeyInfo_1) ((KeyInfo_1 >> 3) & 0x1) +#define AIRPDCAP_EAP_INST(KeyInfo_1) ((KeyInfo_1 >> 6) & 0x1) +#define AIRPDCAP_EAP_ACK(KeyInfo_1) ((KeyInfo_1 >> 7) & 0x1) +#define AIRPDCAP_EAP_MIC(KeyInfo_0) (KeyInfo_0 & 0x1) +#define AIRPDCAP_EAP_SEC(KeyInfo_0) ((KeyInfo_0 >> 1) & 0x1) + +/* Note: copied from net80211/ieee80211_airpdcap_tkip.c */ +#define S_SWAP(a,b) { UINT8 t = S[a]; S[a] = S[b]; S[b] = t; } + +/****************************************************************************/ + +/****************************************************************************/ +/* Structure definitions */ + +/* + * XXX - According to the thread at + * http://www.wireshark.org/lists/wireshark-dev/200612/msg00384.html we + * shouldn't have to worry about packing our structs, since the largest + * elements are 8 bits wide. + */ +#ifdef _MSC_VER /* MS Visual C++ */ +#pragma pack(push) +#pragma pack(1) +#endif + +/* Definition of IEEE 802.11 frame (without the address 4) */ +typedef struct _AIRPDCAP_MAC_FRAME { + UCHAR fc[2]; + UCHAR dur[2]; + UCHAR addr1[AIRPDCAP_MAC_LEN]; + UCHAR addr2[AIRPDCAP_MAC_LEN]; + UCHAR addr3[AIRPDCAP_MAC_LEN]; + UCHAR seq[2]; +} AIRPDCAP_MAC_FRAME, *PAIRPDCAP_MAC_FRAME; + +/* Definition of IEEE 802.11 frame (with the address 4) */ +typedef struct _AIRPDCAP_MAC_FRAME_ADDR4 { + UCHAR fc[2]; + UCHAR dur[2]; + UCHAR addr1[AIRPDCAP_MAC_LEN]; + UCHAR addr2[AIRPDCAP_MAC_LEN]; + UCHAR addr3[AIRPDCAP_MAC_LEN]; + UCHAR seq[2]; + UCHAR addr4[AIRPDCAP_MAC_LEN]; +} AIRPDCAP_MAC_FRAME_ADDR4, *PAIRPDCAP_MAC_FRAME_ADDR4; + +/* Definition of IEEE 802.11 frame (without the address 4, with QOS) */ +typedef struct _AIRPDCAP_MAC_FRAME_QOS { + UCHAR fc[2]; + UCHAR dur[2]; + UCHAR addr1[AIRPDCAP_MAC_LEN]; + UCHAR addr2[AIRPDCAP_MAC_LEN]; + UCHAR addr3[AIRPDCAP_MAC_LEN]; + UCHAR seq[2]; + UCHAR qos[2]; +} AIRPDCAP_MAC_FRAME_QOS, *PAIRPDCAP_MAC_FRAME_QOS; + +/* Definition of IEEE 802.11 frame (with the address 4 and QOS) */ +typedef struct _AIRPDCAP_MAC_FRAME_ADDR4_QOS { + UCHAR fc[2]; + UCHAR dur[2]; + UCHAR addr1[AIRPDCAP_MAC_LEN]; + UCHAR addr2[AIRPDCAP_MAC_LEN]; + UCHAR addr3[AIRPDCAP_MAC_LEN]; + UCHAR seq[2]; + UCHAR addr4[AIRPDCAP_MAC_LEN]; + UCHAR qos[2]; +} AIRPDCAP_MAC_FRAME_ADDR4_QOS, *PAIRPDCAP_MAC_FRAME_ADDR4_QOS; + +#ifdef _MSC_VER /* MS Visual C++ */ +#pragma pack(pop) +#endif + +/******************************************************************************/ + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_interop.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_interop.h new file mode 100644 index 00000000..9d693fb9 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_interop.h @@ -0,0 +1,101 @@ +/* airpdcap_interop.h + * + * $Id: airpdcap_interop.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Copyright (c) 2006 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _AIRPDCAP_INTEROP_H +#define _AIRPDCAP_INTEROP_H + +/** + * Cast data types commonly used (e.g. UINT16) to their + * GLib equivalents. + */ + +#include +#include + +#ifndef INT +typedef gint INT; +#endif + +#ifndef UINT +typedef guint UINT; +#endif + +#ifndef UINT8 +typedef guint8 UINT8; +#endif + +#ifndef UINT16 +typedef guint16 UINT16; +#endif + +#ifndef UINT32 +typedef guint32 UINT32; +#endif + +#ifndef UINT64 +typedef guint64 UINT64; +#endif + +#ifndef USHORT +typedef gushort USHORT; +#endif + +#ifndef ULONG +typedef gulong ULONG; +#endif + +#ifndef ULONGLONG +typedef guint64 ULONGLONG; +#endif + +#ifndef CHAR +typedef gchar CHAR; +#endif + +#ifndef UCHAR +typedef guchar UCHAR; +#endif + +#ifdef _WIN32 +#include /* ntohs() */ +#endif + +#ifndef ntohs +#undef ntohs +#define ntohs(value) g_ntohs(value) +#endif + +#endif /* _AIRPDCAP_INTEROP_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_rijndael.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_rijndael.h new file mode 100644 index 00000000..b031d790 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_rijndael.h @@ -0,0 +1,93 @@ +/** + * airpdcap_rijndael.h + * + * $Id: airpdcap_rijndael.h 3992 2008-06-10 03:13:11Z dgu $ + * + * @version 3.0 (December 2000) + * + * Optimised ANSI C code for the Rijndael cipher (now AES) + * + * @author Vincent Rijmen + * @author Antoon Bosselaers + * @author Paulo Barreto + * + * This code is hereby placed in the public domain. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _AIRPDCAP_RIJNDAEL +#define _AIRPDCAP_RIJNDAEL + +/******************************************************************************/ +/* File includes */ +/* */ +#include "airpdcap_interop.h" +/* */ +/* */ +/******************************************************************************/ + +/******************************************************************************/ +/* Definitions */ +/* */ +/* Note: copied AirPDcap/rijndael/rijndael.h */ +#define RIJNDAEL_MAXKC (256/32) +#define RIJNDAEL_MAXKB (256/8) +#define RIJNDAEL_MAXNR 14 +/* */ +/******************************************************************************/ + +/******************************************************************************/ +/* Type definitions */ +/* */ +/* Note: copied AirPDcap/rijndael/rijndael.h */ +typedef struct s_rijndael_ctx { + INT decrypt; + INT Nr; /* key-length-dependent number of rounds */ + UINT32 ek[4 * (RIJNDAEL_MAXNR + 1)]; /* encrypt key schedule */ + UINT32 dk[4 * (RIJNDAEL_MAXNR + 1)]; /* decrypt key schedule */ +} rijndael_ctx; +/* */ +/******************************************************************************/ + +/******************************************************************************/ +/* External function prototypes declarations */ +/* */ +void rijndael_encrypt( + const rijndael_ctx *ctx, + const UCHAR *src, + UCHAR *dst) + ; + + +void rijndael_set_key( + rijndael_ctx *ctx, + const UCHAR *key, + INT bits) + ; +/* */ +/******************************************************************************/ + +/******************************************************************************/ +/* Block XOR macro definition */ +/* */ +#define XOR_BLOCK(b, a, len) \ + { \ + INT i; \ + for (i = 0; i < (INT)(len); i++) \ + (b)[i] ^= (a)[i]; \ + } +/* */ +/******************************************************************************/ + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_system.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_system.h new file mode 100644 index 00000000..392d5d19 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_system.h @@ -0,0 +1,356 @@ +/* airpdcap_system.h + * + * $Id: airpdcap_system.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Copyright (c) 2006 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _AIRPDCAP_SYSTEM_H +#define _AIRPDCAP_SYSTEM_H + +/************************************************************************/ +/* File includes */ + +#include "airpdcap_interop.h" +#include "airpdcap_user.h" + +/************************************************************************/ +/* Constant definitions */ + +/* General definitions */ +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#define AIRPDCAP_RET_SUCCESS 0 +#define AIRPDCAP_RET_UNSUCCESS 1 + +#define AIRPDCAP_RET_NO_DATA 1 +#define AIRPDCAP_RET_WRONG_DATA_SIZE 2 +#define AIRPDCAP_RET_REQ_DATA 3 +#define AIRPDCAP_RET_NO_VALID_HANDSHAKE 4 +#define AIRPDCAP_RET_NO_DATA_ENCRYPTED 5 + +#define AIRPDCAP_RET_SUCCESS_HANDSHAKE -1 + +#define AIRPDCAP_MAX_KEYS_NR 64 +#define AIRPDCAP_MAX_SEC_ASSOCIATIONS_NR 256 + +/* Decryption algorithms fields size definition (bytes) */ +#define AIRPDCAP_WPA_NONCE_LEN 32 +#define AIRPDCAP_WPA_PTK_LEN 64 /* TKIP uses 48 bytes, CCMP uses 64 bytes */ +#define AIRPDCAP_WPA_MICKEY_LEN 16 + +#define AIRPDCAP_WEP_128_KEY_LEN 16 /* 128 bits */ + +/* General 802.11 constants */ +#define AIRPDCAP_MAC_LEN 6 +#define AIRPDCAP_RADIOTAP_HEADER_LEN 24 + +#define AIRPDCAP_EAPOL_MAX_LEN 1024 + +#define AIRPDCAP_TK_LEN 16 + +/* Max length of capture data */ +#define AIRPDCAP_MAX_CAPLEN 8192 + +#define AIRPDCAP_WEP_IVLEN 3 /* 24bit */ +#define AIRPDCAP_WEP_KIDLEN 1 /* 1 octet */ +#define AIRPDCAP_WEP_ICV 4 +#define AIRPDCAP_WEP_HEADER AIRPDCAP_WEP_IVLEN + AIRPDCAP_WEP_KIDLEN +#define AIRPDCAP_WEP_TRAILER AIRPDCAP_WEP_ICV + +/* + * 802.11i defines an extended IV for use with non-WEP ciphers. + * When the EXTIV bit is set in the key id byte an additional + * 4 bytes immediately follow the IV for TKIP. For CCMP the + * EXTIV bit is likewise set but the 8 bytes represent the + * CCMP header rather than IV+extended-IV. + */ +#define AIRPDCAP_RSNA_EXTIV 0x20 +#define AIRPDCAP_RSNA_EXTIVLEN 4 /* extended IV length */ +#define AIRPDCAP_RSNA_MICLEN 8 /* trailing MIC */ + +#define AIRPDCAP_RSNA_HEADER AIRPDCAP_WEP_HEADER + AIRPDCAP_RSNA_EXTIVLEN + +#define AIRPDCAP_CCMP_HEADER AIRPDCAP_RSNA_HEADER +#define AIRPDCAP_CCMP_TRAILER AIRPDCAP_RSNA_MICLEN + +#define AIRPDCAP_TKIP_HEADER AIRPDCAP_RSNA_HEADER +#define AIRPDCAP_TKIP_TRAILER AIRPDCAP_RSNA_MICLEN + AIRPDCAP_WEP_ICV + +#define AIRPDCAP_CRC_LEN 4 + +/************************************************************************/ +/* Macro definitions */ + +/************************************************************************/ +/* Type definitions */ + +typedef struct _AIRPDCAP_SEC_ASSOCIATION_ID { + UCHAR bssid[AIRPDCAP_MAC_LEN]; + UCHAR sta[AIRPDCAP_MAC_LEN]; +} AIRPDCAP_SEC_ASSOCIATION_ID, *PAIRPDCAP_SEC_ASSOCIATION_ID; + +typedef struct _AIRPDCAP_SEC_ASSOCIATION { + /** + * This flag define whether this item is used or not. Accepted + * values are TRUE and FALSE + */ + UINT8 used; + AIRPDCAP_SEC_ASSOCIATION_ID saId; + AIRPDCAP_KEY_ITEM *key; + UINT8 handshake; + UINT8 validKey; + + struct { + UINT8 key_ver; /* Key descriptor version */ + UINT64 pn; /* only used with CCMP AES -if needed replay check- */ + UCHAR nonce[AIRPDCAP_WPA_NONCE_LEN]; + /* used to derive PTK, ANonce stored, SNonce taken */ + /* the 2nd packet of the 4W handshake */ + + UCHAR ptk[AIRPDCAP_WPA_PTK_LEN]; /* session key used in decryption algorithm */ + } wpa; +} AIRPDCAP_SEC_ASSOCIATION, *PAIRPDCAP_SEC_ASSOCIATION; + +typedef struct _AIRPDCAP_CONTEXT { + AIRPDCAP_SEC_ASSOCIATION sa[AIRPDCAP_MAX_SEC_ASSOCIATIONS_NR]; + INT sa_index; + AIRPDCAP_KEY_ITEM keys[AIRPDCAP_MAX_KEYS_NR]; + size_t keys_nr; + + CHAR pkt_ssid[AIRPDCAP_WPA_SSID_MAX_LEN]; + size_t pkt_ssid_len; + + INT index; + INT first_free_index; +} AIRPDCAP_CONTEXT, *PAIRPDCAP_CONTEXT; + +/************************************************************************/ +/* Function prototype declarations */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Given an 802.11 packet, either extract its key data (in the case of + * WPA handshaking) or try to decrypt it. + * @param ctx [IN] Pointer to the current context + * @param data [IN] Pointer to a buffer with an 802.11 frame, including MAC + * header and payload + * @param data_off [IN] Payload offset (aka the MAC header length) + * @param data_len [IN] Total length of the MAC header and the payload + * @param decrypt_data [OUT] Pointer to a buffer that will contain + * decrypted data + * @param decrypt_len [OUT] Length of decrypted data + * @param key [OUT] Pointer to a preallocated key structure containing + * the key used during the decryption process (if done). If this parameter + * is set to NULL, the key will be not returned. + * @param mngHandshake [IN] If TRUE this function will manage the 4-way + * handshake for WPA/WPA2 + * @param mngDecrypt [IN] If TRUE this function will manage the WEP or + * WPA/WPA2 decryption + * @return + * - AIRPDCAP_RET_SUCCESS: Decryption has been done (decrypt_data and + * decrypt_length will contain the packet data decrypted and the length of + * the new packet) + * - AIRPDCAP_RET_SUCCESS_HANDSHAKE: A step of the 4-way handshake for + * WPA key has been successfully done + * - AIRPDCAP_RET_NO_DATA: The packet is not a data packet + * - AIRPDCAP_RET_WRONG_DATA_SIZE: The size of the packet is below the + * accepted minimum + * - AIRPDCAP_RET_REQ_DATA: Required data is not available and the + * processing must be interrupted + * - AIRPDCAP_RET_NO_VALID_HANDSHAKE: The authentication is not for WPA or RSNA + * - AIRPDCAP_RET_NO_DATA_ENCRYPTED: No encrypted data + * - AIRPDCAP_RET_UNSUCCESS: No decryption has been done (decrypt_data + * and decrypt_length will be not modified). + * Some other errors could be: + * data not correct + * data not encrypted + * key handshake, not encryption + * decryption not successful + * key handshake not correct + * replay check not successful + * @note + * The decrypted buffer should be allocated for a size equal or greater + * than the packet data buffer size. Before decryption process original + * data is copied in the buffer pointed by decrypt_data not to modify the + * original packet. + * @note + * The length of decrypted data will consider the entire 802.11 frame + * (thus the MAC header, the frame body and the recalculated FCS -if + * initially present-) + * @note + * This function is not thread-safe when used in parallel with context + * management functions on the same context. + */ +extern INT AirPDcapPacketProcess( + PAIRPDCAP_CONTEXT ctx, + const guint8 *data, + const guint data_off, + const guint data_len, + UCHAR *decrypt_data, + guint32 *decrypt_len, + PAIRPDCAP_KEY_ITEM key, + gboolean mngHandshake, + gboolean mngDecrypt) + ; + +/** + * It sets a new keys collection to use during packet processing. + * Any key should be well-formed, thus: it should have a defined key + * type and the specified length should be conforming WEP or WPA/WPA2 + * standards. A general WEP keys could be of any length (in the range + * defined in AIRPDCAP_KEY_ITEM), if a specific WEP key is used, the + * length of the key will be the one specified in 802.11i-2004 (40 bits or + * 104 bits). + * For WPA/WPA2 the password (passphrase and SSID), the PSK and the PMK + * are in alternative, as explain in the AIRPDCAP_KEY_ITEM structure + * description. + * @param ctx [IN] pointer to the current context + * @param keys [IN] an array of keys to set. + * @param keys_nr [IN] the size of the keys array + * @return The number of keys correctly inserted in the current database. + * @note Before inserting new keys, the current database will be cleaned. + * @note + * This function is not thread-safe when used in parallel with context + * management functions and the packet process function on the same + * context. + */ +extern INT AirPDcapSetKeys( + PAIRPDCAP_CONTEXT ctx, + AIRPDCAP_KEY_ITEM keys[], + const size_t keys_nr) + ; + +/** + * It gets the keys collection fom the specified context. + * @param ctx [IN] pointer to the current context + * @param key [IN] a preallocated array of keys to be returned + * @param keys_nr [IN] the number of keys to return (the key array must + * be able to contain at least keys_nr keys) + * @return The number of keys returned + * @note + * Any key could be modified, as stated in the AIRPDCAP_KEY_ITEM description. + * @note + * This function is not thread-safe when used in parallel with context + * management functions and the packet process function on the same + * context. + */ +INT AirPDcapGetKeys( + const PAIRPDCAP_CONTEXT ctx, + AIRPDCAP_KEY_ITEM keys[], + const size_t keys_nr) + ; + +/** + * Sets the "last seen" SSID. This allows us to pick up previous + * SSIDs and use them when "wildcard" passphrases are specified + * in the preferences. + * @param ctx [IN|OUT] pointer to a preallocated context structure + * @param pkt_ssid [IN] pointer to the packet's SSID + * @param pkt_ssid_len [IN] length of the packet's SSID + * @return + * AIRPDCAP_RET_SUCCESS: The key has been set. + * AIRPDCAP_RET_UNSUCCESS: The has not been set, e.g. the length was + * too long. + */ +INT AirPDcapSetLastSSID( + PAIRPDCAP_CONTEXT ctx, + CHAR *pkt_ssid, + size_t pkt_ssid_len) + ; + +/** + * Initialize a context used to manage decryption and keys collection. + * @param ctx [IN|OUT] pointer to a preallocated context structure + * @return + * AIRPDCAP_RET_SUCCESS: the context has been successfully initialized + * AIRPDCAP_RET_UNSUCCESS: the context has not been initialized + * @note + * Only a correctly initialized context can be used to manage decryption + * processes and keys. + * @note + * This function is not thread-safe when used in parallel with context + * management functions and the packet process function on the same context. + */ +INT AirPDcapInitContext( + PAIRPDCAP_CONTEXT ctx) + ; + +/** + * Clean up the specified context. After the cleanup the pointer should + * not be used anymore. + * @param ctx [IN|OUT] pointer to the current context structure + * @return + * AIRPDCAP_RET_SUCCESS: the context has been successfully initialized + * AIRPDCAP_RET_UNSUCCESS: the context has not been initialized + * @note + * This function is not thread-safe when used in parallel with context + * management functions and the packet process function on the same + * context. + */ +INT AirPDcapDestroyContext( + PAIRPDCAP_CONTEXT ctx) + ; + + +extern INT AirPDcapWepDecrypt( + const UCHAR *seed, + const size_t seed_len, /* max AIRPDCAP_KEYBUF_SIZE */ + UCHAR *cypher_text, + const size_t data_len) + ; +extern INT AirPDcapCcmpDecrypt( + UINT8 *m, + gint mac_header_len, + INT len, + UCHAR TK1[16]) + ; +extern INT AirPDcapTkipDecrypt( + UCHAR *tkip_mpdu, + size_t mpdu_len, + UCHAR TA[AIRPDCAP_MAC_LEN], + UCHAR TK[AIRPDCAP_TK_LEN]) + ; + +#ifdef __cplusplus +} +#endif + +#endif /* _AIRPDCAP_SYSTEM_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_user.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_user.h new file mode 100644 index 00000000..0cf1a5b8 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_user.h @@ -0,0 +1,231 @@ +/* airpdcap_user.h + * + * $Id: airpdcap_user.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Copyright (c) 2006 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _AIRPDCAP_USER_H +#define _AIRPDCAP_USER_H + +/******************************************************************************/ +/* File includes */ +/* */ +#include "airpdcap_interop.h" +/* */ +/* */ +/******************************************************************************/ + +/******************************************************************************/ +/* Constant definitions */ +/* */ +/* Decryption key types */ +#define AIRPDCAP_KEY_TYPE_WEP 0 +#define AIRPDCAP_KEY_TYPE_WEP_40 1 +#define AIRPDCAP_KEY_TYPE_WEP_104 2 +#define AIRPDCAP_KEY_TYPE_WPA_PWD 3 +#define AIRPDCAP_KEY_TYPE_WPA_PSK 4 +#define AIRPDCAP_KEY_TYPE_WPA_PMK 5 +#define AIRPDCAP_KEY_TYPE_TKIP 6 +#define AIRPDCAP_KEY_TYPE_CCMP 7 + +/* Decryption algorithms fields size definition (bytes) */ +#define AIRPDCAP_WEP_KEY_MINLEN 1 +#define AIRPDCAP_WEP_KEY_MAXLEN 32 +#define AIRPDCAP_WEP_40_KEY_LEN 5 +#define AIRPDCAP_WEP_104_KEY_LEN 13 + +#define AIRPDCAP_WPA_PASSPHRASE_MIN_LEN 8 +#define AIRPDCAP_WPA_PASSPHRASE_MAX_LEN 63 /* null-terminated string, the actual length of the storage is 64 */ +#define AIRPDCAP_WPA_SSID_MIN_LEN 0 +#define AIRPDCAP_WPA_SSID_MAX_LEN 32 +#define AIRPDCAP_WPA_PSK_LEN 64 +#define AIRPDCAP_WPA_PMK_LEN 32 +/* */ +/* */ +/******************************************************************************/ + +/******************************************************************************/ +/* Macro definitions */ +/* */ +/* */ +/******************************************************************************/ + +/******************************************************************************/ +/* Type definitions */ +/* */ +/** + * Struct to store info about a specific decryption key. + */ +typedef struct { + GString *key; + GByteArray *ssid; + guint bits; + guint type; +} decryption_key_t; + +/** + * Key item used during the decryption process. + */ +typedef struct _AIRPDCAP_KEY_ITEM { + /** + * Type of key. The type will remain unchanged during the + * processing, even if some fields could be changed (e.g., WPA + * fields). + * @note + * You can use constants AIRPDCAP_KEY_TYPE_xxx to indicate the + * key type. + */ + UINT8 KeyType; + + /** + * Key data. + * This field can be used for the following decryptographic + * algorithms: WEP-40, with a key of 40 bits (10 hex-digits); + * WEP-104, with a key of 104 bits (or 26 hex-digits); WPA or + * WPA2. + * @note + * For WPA/WPA2, the PMK is calculated from the PSK, and the PSK + * is calculated from the passphrase-SSID pair. You can enter one + * of these 3 values and subsequent fields will be automatically + * calculated. + * @note + * For WPA and WPA2 this implementation will use standards as + * defined in 802.11i (2004) and 802.1X (2004). + */ + union AIRPDCAP_KEY_ITEMDATA { + struct AIRPDCAP_KEY_ITEMDATA_WEP { + /** + * The binary value of the WEP key. + * @note + * It is accepted a key of length between + * AIRPDCAP_WEP_KEY_MINLEN and + * AIRPDCAP_WEP_KEY_MAXLEN. A WEP key + * standard-compliante should be either 40 bits + * (10 hex-digits, 5 bytes) for WEP-40 or 104 bits + * (26 hex-digits, 13 bytes) for WEP-104. + */ + UCHAR WepKey[AIRPDCAP_WEP_KEY_MAXLEN]; + /** + * The length of the WEP key. Acceptable range + * is [AIRPDCAP_WEP_KEY_MINLEN;AIRPDCAP_WEP_KEY_MAXLEN]. + */ + size_t WepKeyLen; + } Wep; + + /** + * WPA/WPA2 key data. Note that the decryption process + * will use the PMK (equal to PSK), that is calculated + * from passphrase-SSID pair. You can define one of these + * three fields and necessary fields will be automatically + * calculated. + */ + union AIRPDCAP_KEY_ITEMDATA_WPA { + + UCHAR Psk[AIRPDCAP_WPA_PSK_LEN]; + + UCHAR Pmk[AIRPDCAP_WPA_PMK_LEN]; + } Wpa; + } KeyData; + + struct AIRPDCAP_KEY_ITEMDATA_PWD { + /** + * The string (null-terminated) value of + * the passphrase. + */ + CHAR Passphrase[AIRPDCAP_WPA_PASSPHRASE_MAX_LEN+1]; + /** + * The value of the SSID (up to + * AIRPDCAP_WPA_SSID_MAX_LEN octets). + * @note + * A zero-length SSID indicates broadcast. + */ + CHAR Ssid[AIRPDCAP_WPA_SSID_MAX_LEN]; + /** + *The length of the SSID + */ + size_t SsidLen; + } UserPwd; +} AIRPDCAP_KEY_ITEM, *PAIRPDCAP_KEY_ITEM; + +/** + * Collection of keys to use to decrypt packets + */ +typedef struct _AIRPDCAP_KEYS_COLLECTION { + /** + * Number of stored keys + */ + size_t nKeys; + + /** + * Array of nKeys keys + */ + AIRPDCAP_KEY_ITEM Keys[256]; +} AIRPDCAP_KEYS_COLLECTION, *PAIRPDCAP_KEYS_COLLECTION; +/* */ +/******************************************************************************/ + +/******************************************************************************/ +/* Function prototype declarations */ + +/** + * Returns the decryption_key_t struct given a string describing the key. + * @param key_string [IN] Key string in one of the following formats: + * - 0102030405 (40/64-bit WEP) + * - 01:02:03:04:05 (40/64-bit WEP) + * - 0102030405060708090a0b0c0d (104/128-bit WEP) + * - 01:02:03:04:05:06:07:08:09:0a:0b:0c:0d (104/128-bit WEP) + * - wep:01020304... (WEP) + * - wep:01:02:03:04... (WEP) + * - wpa-pwd:MyPassword (WPA + plaintext password + "wildcard" SSID) + * - wpa-pwd:MyPassword:MySSID (WPA + plaintext password + specific SSID) + * - wpa-psk:01020304... (WPA + 256-bit raw key) + * @return A pointer to a freshly-g_malloc()ed decryption_key_t struct on + * success, or NULL on failure. + * @see get_key_string() + */ +decryption_key_t* +parse_key_string(gchar* key_string); + +/** + * Returns a newly allocated string representing the given decryption_key_t + * struct. + * @param dk [IN] Pointer to the key to be converted + * @return A g_malloc()ed string representation of the key + * @see parse_key_string() + */ +gchar* +get_key_string(decryption_key_t* dk); + +/******************************************************************************/ + +#endif /* _AIRPDCAP_USER_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_ws.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_ws.h new file mode 100644 index 00000000..22cf6e07 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_ws.h @@ -0,0 +1,43 @@ +/* airpdcap_ws.h + * + * $Id: airpdcap_ws.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Copyright (c) 2006 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _AIRPDCAP_WS_H +#define _AIRPDCAP_WS_H + +#include "airpdcap_system.h" +WS_VAR_IMPORT AIRPDCAP_CONTEXT airpdcap_ctx; + +#endif /* _AIRPDCAP_WS_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-des.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-des.h new file mode 100644 index 00000000..b08ba28b --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-des.h @@ -0,0 +1,26 @@ +/* + Unix SMB/CIFS implementation. + + a partial implementation of DES designed for use in the + SMB authentication protocol + + Copyright (C) Andrew Tridgell 1998 + + $Id: crypt-des.h 3992 2008-06-10 03:13:11Z dgu $ + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +void crypt_des_ecb(unsigned char *out, const unsigned char *in, const unsigned char *key, int forw); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-md4.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-md4.h new file mode 100644 index 00000000..c6179818 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-md4.h @@ -0,0 +1,23 @@ +/* + Unix SMB/CIFS implementation. + a implementation of MD4 designed for use in the SMB authentication protocol + Copyright (C) Andrew Tridgell 1997-1998. + + $Id: crypt-md4.h 3992 2008-06-10 03:13:11Z dgu $ + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +void crypt_md4(unsigned char *out, const unsigned char *in, int n); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-md5.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-md5.h new file mode 100644 index 00000000..d6292004 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-md5.h @@ -0,0 +1,71 @@ +/* $Id: crypt-md5.h 3992 2008-06-10 03:13:11Z dgu $ */ +/* + * Copyright (C) 2003-2005 Benny Prijono + * + * MD5 code from pjlib-util http://www.pjsip.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __MD5_H__ +#define __MD5_H__ + +/** + * @file md5.h + * @brief MD5 Functions + */ + +/** + * @defgroup PJLIB_UTIL_MD5 MD5 Functions + * @ingroup PJLIB_UTIL + * @{ + */ + +#define md5_byte_t guint8 + +/** MD5 context. */ +typedef struct md5_state_s +{ + guint32 buf[4]; + guint32 bits[2]; + guint32 in[16]; +} md5_state_t; + +/** Initialize the algorithm. + * @param pms MD5 context. + */ +void md5_init(md5_state_t *pms); + +/** Append a string to the message. + * @param pms MD5 context. + * @param data Data. + * @param nbytes Length of data. + */ +void md5_append( md5_state_t *pms, + const guint8 *data, guint nbytes); + +/** Finish the message and return the digest. + * @param pms MD5 context. + * @param digest 16 byte digest. + */ +void md5_finish(md5_state_t *pms, guint8 digest[16]); + + +void md5_hmac(const guint8* text, gint text_len, const guint8* key, gint key_len, guint8 digest[16]); + +/** + * @} + */ + +#endif /* _CRYPT_MD5_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-rc4.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-rc4.h new file mode 100644 index 00000000..1068e160 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-rc4.h @@ -0,0 +1,36 @@ +/* + Unix SMB/CIFS implementation. + + a partial implementation of RC4 designed for use in the + SMB authentication protocol + + Copyright (C) Andrew Tridgell 1998 + + $Id: crypt-rc4.h 3992 2008-06-10 03:13:11Z dgu $ + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +typedef struct _rc4_state_struct { + unsigned char s_box[256]; + unsigned char index_i; + unsigned char index_j; +} rc4_state_struct; + +void crypt_rc4_init(rc4_state_struct *rc4_state, + const unsigned char *key, int key_len); + +void crypt_rc4(rc4_state_struct *rc4_state, unsigned char *data, int data_len); + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-sha1.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-sha1.h new file mode 100644 index 00000000..010725b7 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-sha1.h @@ -0,0 +1,45 @@ +/* + * FIPS-180-1 compliant SHA-1 implementation + * + * $Id: crypt-sha1.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Copyright (C) 2001-2003 Christophe Devine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Changed to use guint instead of uint 2004 by Anders Broman + * Original code found at http://www.cr0.net:8040/code/crypto/sha1/ + * References: http://www.ietf.org/rfc/rfc3174.txt?number=3174 + */ + +#ifndef _CRYPT_SHA1_H +#define _CRYPT_SHA1_H + + +typedef struct +{ + guint32 total[2]; + guint32 state[5]; + guint8 buffer[64]; +} +sha1_context; + +void sha1_starts( sha1_context *ctx ); +void sha1_update( sha1_context *ctx, const guint8 *input, guint32 length ); +void sha1_finish( sha1_context *ctx, guint8 digest[20] ); +void sha1_hmac( const guint8 *key, guint32 keylen, const guint8 *buf, guint32 buflen, + guint8 digest[20] ); + +#endif /* crypt-sha1.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/wep-wpadefs.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/wep-wpadefs.h new file mode 100644 index 00000000..f980d401 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/wep-wpadefs.h @@ -0,0 +1,115 @@ +/* wap-wpadefs.h + * + * $Id: wep-wpadefs.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Copyright (c) 2006 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef __WEP_WPADEFS_H__ +#define __WEP_WPADEFS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** @file + * WEP and WPA definitions + * + * Copied from airpcap.h. + */ + +/** + * Maximum number of encryption keys. This determines the size of + * structures in packet-ieee80211.c, as well as the number of keys + * in the IEEE 802.11 preferences. + */ +#define MAX_ENCRYPTION_KEYS 64 + +/** + * Maximum size of a WEP key, in bytes. This is the size of an entry in the + * AirpcapWepKeysCollection structure. + */ +#define WEP_KEY_MAX_SIZE 32 + +/** + * WEP_KEY_MAX_SIZE is in bytes, but each byte is represented as a + * hexadecimal string. + */ +#define WEP_KEY_MAX_CHAR_SIZE (WEP_KEY_MAX_SIZE*2) + +/** + * WEP_KEY_MAX_SIZE is in bytes, this is in bits... + */ +#define WEP_KEY_MAX_BIT_SIZE (WEP_KEY_MAX_SIZE*8) + +#define WEP_KEY_MIN_CHAR_SIZE 2 +#define WEP_KEY_MIN_BIT_SIZE 8 + +/** + * WPA key sizes. + */ +#define WPA_KEY_MAX_SIZE 63 /* 63 chars followed by a '\0' */ + +#define WPA_KEY_MAX_CHAR_SIZE (WPA_KEY_MAX_SIZE*1) +#define WPA_KEY_MAX_BIT_SIZE (WPA_KEY_MAX_SIZE*8) +#define WPA_KEY_MIN_CHAR_SIZE 8 +#define WPA_KEY_MIN_BIT_SIZE (WPA_KEY_MIN_CHAR_SIZE*8) + +/** + * SSID sizes + */ +#define WPA_SSID_MAX_SIZE 32 + +#define WPA_SSID_MAX_CHAR_SIZE (WPA_SSID_MAX_SIZE*1) +#define WPA_SSID_MAX_BIT_SIZE (WPA_SSID_MAX_SIZE*8) +#define WPA_SSID_MIN_CHAR_SIZE 0 +#define WPA_SSID_MIN_BIT_SIZE (WPA_SSID_MIN_CHAR_SIZE*8) + +/** + * Let the user enter a raw PSK along with a passphrase + SSID + */ +#define WPA_PSK_KEY_SIZE 32 /* Fixed size, 32 bytes (256bit) */ +#define WPA_PSK_KEY_CHAR_SIZE (WPA_PSK_KEY_SIZE*2) +#define WPA_PSK_KEY_BIT_SIZE (WPA_PSK_KEY_SIZE*8) + +/** + * Prefix definitions for preferences + */ +#define STRING_KEY_TYPE_WEP "wep" +#define STRING_KEY_TYPE_WPA_PWD "wpa-pwd" +#define STRING_KEY_TYPE_WPA_PSK "wpa-psk" + +#ifdef __cplusplus +} +#endif + +#endif /* __WEP_WPADEFS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter-int.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter-int.h new file mode 100644 index 00000000..aaea0ba4 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter-int.h @@ -0,0 +1,82 @@ +/* + * $Id: dfilter-int.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2001 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef DFILTER_INT_H +#define DFILTER_INT_H + +#include "dfilter.h" +#include "syntax-tree.h" + +#include +#include + +/* Passed back to user */ +struct _dfilter_t { + GPtrArray *insns; + GPtrArray *consts; + int num_registers; + int max_registers; + GList **registers; + gboolean *attempted_load; + int *interesting_fields; + int num_interesting_fields; + GPtrArray *deprecated; +}; + +typedef struct { + /* Syntax Tree stuff */ + stnode_t *st_root; + gboolean syntax_error; + GPtrArray *insns; + GPtrArray *consts; + GHashTable *loaded_fields; + GHashTable *interesting_fields; + int next_insn_id; + int next_const_id; + int next_register; + int first_constant; /* first register used as a constant */ +} dfwork_t; + +/* Constructor/Destructor prototypes for Lemon Parser */ +#if (GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 16)) +void *DfilterAlloc(void* (*)(gsize)); +#else +void *DfilterAlloc(void* (*)(gulong)); +#endif + +void DfilterFree(void*, void (*)(void *)); +void Dfilter(void*, int, stnode_t*, dfwork_t*); + +/* Scanner's lval */ +extern stnode_t *df_lval; + +/* Return value for error in scanner. */ +#define SCAN_FAILED -1 /* not 0, as that means end-of-input */ + +/* Set dfilter_error_msg_buf and dfilter_error_msg */ +void +dfilter_fail(const char *format, ...); + +void +DfilterTrace(FILE *TraceFILE, char *zTracePrompt); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter-macro.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter-macro.h new file mode 100644 index 00000000..c2a78060 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter-macro.h @@ -0,0 +1,59 @@ +/* dfilter-macro.h + * + * $Id: dfilter-macro.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2001 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _DFILTER_MACRO_H +#define _DFILTER_MACRO_H + +#define DFILTER_MACRO_FILENAME "dfilter_macros" + + +typedef struct _dfilter_macro_t { + gchar* name; /* the macro id */ + gchar* text; /* raw data from file */ + gboolean usable; /* macro is usable */ + gchar** parts; /* various segments of text between insertion targets */ + int* args_pos; /* what's to be inserted */ + int argc; /* the expected number of arguments */ + void* priv; /* a copy of text that contains every c-string in parts */ +} dfilter_macro_t; + +/* loop over the macros list */ +typedef void (*dfilter_macro_cb_t)(dfilter_macro_t*, void*); +void dfilter_macro_foreach(dfilter_macro_cb_t, void*); + +/* save dfilter macros to a file */ +void dfilter_macro_save(const gchar*, gchar**); + +/* dumps the macros in the list (debug info, not formated as in the macros file) */ +void dfilter_macro_dump(void); + +/* applies all macros to the given text and returns the resulting string or NULL on failure */ +gchar* dfilter_macro_apply(const gchar* text, guint depth, const gchar** error); + +void dfilter_macro_init(void); + +void dfilter_macro_get_uat(void**); + +void dfilter_macro_build_ftv_cache(void* tree_root); + +#endif /* _DFILTER_MACRO_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter.h new file mode 100644 index 00000000..8ea9f947 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter.h @@ -0,0 +1,94 @@ +/* + * $Id: dfilter.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2001 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef DFILTER_H +#define DFILTER_H + +#include + +/* Passed back to user */ +typedef struct _dfilter_t dfilter_t; + +#include +#include + + +/* Module-level initialization */ +void +dfilter_init(void); + +/* Module-level cleanup */ +void +dfilter_cleanup(void); + +/* Compiles a string to a dfilter_t. + * On success, sets the dfilter* pointed to by dfp + * to either a NULL pointer (if the filter is a null + * filter, as generated by an all-blank string) or to + * a pointer to the newly-allocated dfilter_t + * structure. + * + * On failure, dfilter_error_msg points to an + * appropriate error message. This error message is + * a global string, so another invocation of + * dfilter_compile() will clear it. The dfilter* + * will be set to NULL after a failure. + * + * Returns TRUE on success, FALSE on failure. + */ +gboolean +dfilter_compile(const gchar *text, dfilter_t **dfp); + +/* Frees all memory used by dfilter, and frees + * the dfilter itself. */ +void +dfilter_free(dfilter_t *df); + + +/* dfilter_error_msg is NULL if there was no error during dfilter_compile, + * otherwise it points to a displayable error message. With MSVC and a + * libwireshark.dll, we need a special declaration. + */ + +WS_VAR_IMPORT const gchar *dfilter_error_msg; + + +/* Apply compiled dfilter */ +gboolean +dfilter_apply_edt(dfilter_t *df, epan_dissect_t* edt); + +/* Apply compiled dfilter */ +gboolean +dfilter_apply(dfilter_t *df, proto_tree *tree); + +/* Prime a proto_tree using the fields/protocols used in a dfilter. */ +void +dfilter_prime_proto_tree(const dfilter_t *df, proto_tree *tree); + +GPtrArray * +dfilter_deprecated_tokens(dfilter_t *df); + +/* Print bytecode of dfilter to stdout */ +void +dfilter_dump(dfilter_t *df); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfunctions.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfunctions.h new file mode 100644 index 00000000..f9e1e575 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfunctions.h @@ -0,0 +1,56 @@ +/* + * $Id: dfunctions.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * + * Copyright 2006 Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef DFUNCTIONS_H +#define DFUNCTIONS_H + +#include +#include +#include "syntax-tree.h" + +/* The run-time logic of the dfilter function */ +typedef gboolean (*DFFuncType)(GList *arg1list, GList *arg2list, GList **retval); + +/* The semantic check for the dfilter function */ +typedef void (*DFSemCheckType)(int param_num, stnode_t *st_node); + +/* If a function needs more args than this, increase + * this macro and add more arg members to the dfvm_insn_t + * struct in dfvm.h, and add some logic to dfw_append_function() + * and dfvm_apply() */ +#define DFUNCTION_MAX_NARGS 2 + +/* This is a "function definition" record, holding everything + * we need to know about a function */ +typedef struct { + const char *name; + DFFuncType function; + ftenum_t retval_ftype; + guint min_nargs; + guint max_nargs; + DFSemCheckType semcheck_param_function; +} df_func_def_t; + +/* Return the function definition record for a function of named "name" */ +df_func_def_t* df_func_lookup(char *name); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfvm.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfvm.h new file mode 100644 index 00000000..8e6e2507 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfvm.h @@ -0,0 +1,108 @@ +/* + * $Id: dfvm.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2001 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef DFVM_H +#define DFVM_H + +#include +#include +#include "dfilter-int.h" +#include "syntax-tree.h" +#include "drange.h" +#include "dfunctions.h" + +typedef enum { + EMPTY, + FVALUE, + HFINFO, + INSN_NUMBER, + REGISTER, + INTEGER, + DRANGE, + FUNCTION_DEF +} dfvm_value_type_t; + +typedef struct { + dfvm_value_type_t type; + + union { + fvalue_t *fvalue; + guint32 numeric; + drange *drange; + header_field_info *hfinfo; + df_func_def_t *funcdef; + } value; + +} dfvm_value_t; + + +typedef enum { + + IF_TRUE_GOTO, + IF_FALSE_GOTO, + CHECK_EXISTS, + NOT, + RETURN, + READ_TREE, + PUT_FVALUE, + ANY_EQ, + ANY_NE, + ANY_GT, + ANY_GE, + ANY_LT, + ANY_LE, + ANY_BITWISE_AND, + ANY_CONTAINS, + ANY_MATCHES, + MK_RANGE, + CALL_FUNCTION + +} dfvm_opcode_t; + +typedef struct { + int id; + dfvm_opcode_t op; + dfvm_value_t *arg1; + dfvm_value_t *arg2; + dfvm_value_t *arg3; + dfvm_value_t *arg4; +} dfvm_insn_t; + +dfvm_insn_t* +dfvm_insn_new(dfvm_opcode_t op); + +void +dfvm_insn_free(dfvm_insn_t *insn); + +dfvm_value_t* +dfvm_value_new(dfvm_value_type_t type); + +void +dfvm_dump(FILE *f, GPtrArray *insns); + +gboolean +dfvm_apply(dfilter_t *df, proto_tree *tree); + +void +dfvm_init_const(dfilter_t *df); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/drange.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/drange.h new file mode 100644 index 00000000..37ea4e8c --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/drange.h @@ -0,0 +1,102 @@ +/* drange.h + * Routines for providing general range support to the dfilter library + * + * $Id: drange.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Copyright (c) 2000 by Ed Warnicke + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1999 Gerald Combs + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __DRANGE_H__ +#define __DRANGE_H__ + +#include + +/* Please don't directly manipulate these structs. Please use + * the methods provided. If you REALLY can't do what you need to + * do with the methods provided please write new methods that do + * what you need, put them into the drange object here, and limit + * your direct manipulation of the drange and drange_node structs to + * here. + */ + +typedef enum { + UNINITIALIZED, + LENGTH, + OFFSET, + TO_THE_END +} drange_node_end_t; + +typedef struct _drange_node { + gint start_offset; + gint length; + gint end_offset; + drange_node_end_t ending; +} drange_node; + +typedef struct _drange { + GSList* range_list; + gboolean has_total_length; + gint total_length; + gint min_start_offset; + gint max_start_offset; +} drange; + +/* drange_node constructor */ +drange_node* drange_node_new(void); + +/* drange_node destructor */ +void drange_node_free(drange_node* drnode); + +/* Call drange_node destructor on all list items */ +void drange_node_free_list(GSList* list); + +/* drange_node accessors */ +gint drange_node_get_start_offset(drange_node* drnode); +gint drange_node_get_length(drange_node* drnode); +gint drange_node_get_end_offset(drange_node* drnode); +drange_node_end_t drange_node_get_ending(drange_node* drnode); + +/* drange_node mutators */ +void drange_node_set_start_offset(drange_node* drnode, gint offset); +void drange_node_set_length(drange_node* drnode, gint length); +void drange_node_set_end_offset(drange_node* drnode, gint offset); +void drange_node_set_to_the_end(drange_node* drnode); + +/* drange constructor */ +drange* drange_new(void); +drange* drange_new_from_list(GSList *list); + +/* drange destructor, only use this if you used drange_new() to creat + * the drange + */ +void drange_free(drange* dr); + +/* drange accessors */ +gboolean drange_has_total_length(drange* dr); +gint drange_get_total_length(drange* dr); +gint drange_get_min_start_offset(drange* dr); +gint drange_get_max_start_offset(drange* dr); + +/* drange mutators */ +void drange_append_drange_node(drange* dr, drange_node* drnode); +void drange_prepend_drange_node(drange* dr, drange_node* drnode); +void drange_foreach_drange_node(drange* dr, GFunc func, gpointer funcdata); + +#endif /* ! __DRANGE_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/gencode.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/gencode.h new file mode 100644 index 00000000..2148b2be --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/gencode.h @@ -0,0 +1,10 @@ +#ifndef GENCODE_H +#define GENCODE_H + +void +dfw_gencode(dfwork_t *dfw); + +int* +dfw_interesting_fields(dfwork_t *dfw, int *caller_num_fields); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/glib-util.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/glib-util.h new file mode 100644 index 00000000..f845cbe6 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/glib-util.h @@ -0,0 +1,4 @@ +/* $Id: glib-util.h 3992 2008-06-10 03:13:11Z dgu $ */ + +char* +g_substrdup(const char *s, int start, int len); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/grammar.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/grammar.h new file mode 100644 index 00000000..36c3e11f --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/grammar.h @@ -0,0 +1,24 @@ +#define TOKEN_TEST_AND 1 +#define TOKEN_TEST_OR 2 +#define TOKEN_TEST_EQ 3 +#define TOKEN_TEST_NE 4 +#define TOKEN_TEST_LT 5 +#define TOKEN_TEST_LE 6 +#define TOKEN_TEST_GT 7 +#define TOKEN_TEST_GE 8 +#define TOKEN_TEST_CONTAINS 9 +#define TOKEN_TEST_MATCHES 10 +#define TOKEN_TEST_BITWISE_AND 11 +#define TOKEN_TEST_NOT 12 +#define TOKEN_FIELD 13 +#define TOKEN_STRING 14 +#define TOKEN_UNPARSED 15 +#define TOKEN_LBRACKET 16 +#define TOKEN_RBRACKET 17 +#define TOKEN_COMMA 18 +#define TOKEN_INTEGER 19 +#define TOKEN_COLON 20 +#define TOKEN_HYPHEN 21 +#define TOKEN_FUNCTION 22 +#define TOKEN_LPAREN 23 +#define TOKEN_RPAREN 24 diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/scanner_lex.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/scanner_lex.h new file mode 100644 index 00000000..886d06b1 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/scanner_lex.h @@ -0,0 +1,6 @@ +/* This is generated by runlex.sh. Do not edit it. */ +#define yylex df_lex +#ifndef YY_DECL +#define YY_DECL int yylex(void) +#endif +YY_DECL; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/semcheck.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/semcheck.h new file mode 100644 index 00000000..5eac9804 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/semcheck.h @@ -0,0 +1,31 @@ +/* + * $Id: semcheck.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2001 Gerald Combs + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef SEMCHECK_H +#define SEMCHECK_H + +gboolean +dfw_semcheck(dfwork_t *dfw); + + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-function.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-function.h new file mode 100644 index 00000000..fdcc9c58 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-function.h @@ -0,0 +1,42 @@ +/* + * $Id: sttype-function.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2001 Gerald Combs + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef STTYPE_FUNCTION_H +#define STTYPE_FUNCTION_H + +#include "dfunctions.h" + +/* Set the parameters for a function stnode_t. */ +void +sttype_function_set_params(stnode_t *node, GSList *params); + +/* Get the function-definition record for a function stnode_t. */ +df_func_def_t* sttype_function_funcdef(stnode_t *node); + +/* Get the parameters for a function stnode_t. */ +GSList* sttype_function_params(stnode_t *node); + +/* Free the memory of a param list */ +void st_funcparams_free(GSList *params); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-range.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-range.h new file mode 100644 index 00000000..db92f76d --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-range.h @@ -0,0 +1,45 @@ +/* + * $Id: sttype-range.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2001 Gerald Combs + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef STTYPE_RANGE_H +#define STTYPE_RANGE_H + +#include "syntax-tree.h" +#include "drange.h" + +STTYPE_ACCESSOR_PROTOTYPE(header_field_info*, range, hfinfo) +STTYPE_ACCESSOR_PROTOTYPE(drange*, range, drange) + +/* Set a range */ +void +sttype_range_set(stnode_t *node, stnode_t *field, GSList* drange_list); + +void +sttype_range_set1(stnode_t *node, stnode_t *field, drange_node *rn); + +/* Clear the 'drange' variable to remove responsibility for + * freeing it. */ +void +sttype_range_remove_drange(stnode_t *node); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-test.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-test.h new file mode 100644 index 00000000..1635378b --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-test.h @@ -0,0 +1,56 @@ +/* + * $Id: sttype-test.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2001 Gerald Combs + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef STTYPE_TEST_H +#define STTYPE_TEST_H + +typedef enum { + TEST_OP_UNINITIALIZED, + TEST_OP_EXISTS, + TEST_OP_NOT, + TEST_OP_AND, + TEST_OP_OR, + TEST_OP_EQ, + TEST_OP_NE, + TEST_OP_GT, + TEST_OP_GE, + TEST_OP_LT, + TEST_OP_LE, + TEST_OP_BITWISE_AND, + TEST_OP_CONTAINS, + TEST_OP_MATCHES +} test_op_t; + +void +sttype_test_set1(stnode_t *node, test_op_t op, stnode_t *val1); + +void +sttype_test_set2(stnode_t *node, test_op_t op, stnode_t *val1, stnode_t *val2); + +void +sttype_test_set2_args(stnode_t *node, stnode_t *val1, stnode_t *val2); + +void +sttype_test_get(stnode_t *node, test_op_t *p_op, stnode_t **p_val1, stnode_t **p_val2); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/syntax-tree.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/syntax-tree.h new file mode 100644 index 00000000..0ea35f39 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/syntax-tree.h @@ -0,0 +1,136 @@ +/* + * $Id: syntax-tree.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2001 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef SYNTAX_TREE_H +#define SYNTAX_TREE_H + +#include +#include "cppmagic.h" + +typedef enum { + STTYPE_UNINITIALIZED, + STTYPE_TEST, + STTYPE_UNPARSED, + STTYPE_STRING, + STTYPE_FIELD, + STTYPE_FVALUE, + STTYPE_INTEGER, + STTYPE_RANGE, + STTYPE_FUNCTION, + STTYPE_NUM_TYPES +} sttype_id_t; + +typedef gpointer (*STTypeNewFunc)(gpointer); +typedef void (*STTypeFreeFunc)(gpointer); + + +/* Type information */ +typedef struct { + sttype_id_t id; + const char *name; + STTypeNewFunc func_new; + STTypeFreeFunc func_free; +} sttype_t; + +/* Node (type instance) information */ +typedef struct { + guint32 magic; + sttype_t *type; + + /* This could be made an enum, but I haven't + * set aside to time to do so. */ + gpointer data; + gint32 value; + const char *deprecated_token; +} stnode_t; + +/* These are the sttype_t registration function prototypes. */ +void sttype_register_function(void); +void sttype_register_integer(void); +void sttype_register_pointer(void); +void sttype_register_range(void); +void sttype_register_string(void); +void sttype_register_test(void); + +void +sttype_init(void); + +void +sttype_cleanup(void); + +void +sttype_register(sttype_t *type); + +stnode_t* +stnode_new(sttype_id_t type_id, gpointer data); + +void +stnode_init(stnode_t *node, sttype_id_t type_id, gpointer data); + +void +stnode_init_int(stnode_t *node, sttype_id_t type_id, gint32 value); + +void +stnode_free(stnode_t *node); + +const char* +stnode_type_name(stnode_t *node); + +sttype_id_t +stnode_type_id(stnode_t *node); + +gpointer +stnode_data(stnode_t *node); + +gint32 +stnode_value(stnode_t *node); + +const char * +stnode_deprecated(stnode_t *node); + +#define assert_magic(obj, mnum) \ + g_assert((obj)); \ + if ((obj)->magic != (mnum)) { \ + g_print("\nMagic num is 0x%08x, but should be 0x%08x", \ + (obj)->magic, (mnum)); \ + g_assert((obj)->magic == (mnum)); \ + } + + + + +#define STTYPE_ACCESSOR(ret,type,attr,magicnum) \ + ret \ + CONCAT(CONCAT(CONCAT(sttype_,type),_),attr) (stnode_t *node) \ +{\ + CONCAT(type,_t) *value; \ + value = stnode_data(node);\ + assert_magic(value, magicnum); \ + return value->attr; \ +} + +#define STTYPE_ACCESSOR_PROTOTYPE(ret,type,attr) \ + ret \ + CONCAT(CONCAT(CONCAT(sttype_,type),_),attr) (stnode_t *node); + + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/diam_dict.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/diam_dict.h new file mode 100644 index 00000000..b36ba254 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/diam_dict.h @@ -0,0 +1,89 @@ +/* + ** diam_dict.h + ** Diameter Dictionary Import Routines + ** + ** $Id: diam_dict.h 3992 2008-06-10 03:13:11Z dgu $ + ** + ** (c) 2007, Luis E. Garcia Ontanon + ** + ** This library is free software; you can redistribute it and/or + ** modify it under the terms of the GNU Library General Public + ** License as published by the Free Software Foundation; either + ** version 2 of the License, or (at your option) any later version. + ** + ** This library is distributed in the hope that it will be useful, + ** but WITHOUT ANY WARRANTY; without even the implied warranty of + ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + ** Library General Public License for more details. + ** + ** You should have received a copy of the GNU Library General Public + ** License along with this library; if not, write to the + ** Free Software Foundation, Inc., 59 Temple Place - Suite 330, + ** Boston, MA 02111-1307, USA. + */ + +#ifndef _DIAM_DICT_H_ +#define _DIAM_DICT_H_ + +struct _ddict_namecode_t { + char* name; + unsigned code; + struct _ddict_namecode_t* next; +}; + +typedef struct _ddict_namecode_t ddict_gavp_t; +typedef struct _ddict_namecode_t ddict_enum_t; +typedef struct _ddict_namecode_t ddict_application_t; + +typedef struct _ddict_vendor_t { + char* name; + char* desc; + unsigned code; + struct _ddict_vendor_t* next; +} ddict_vendor_t; + +typedef struct _ddict_avp_t { + char* name; + char* description; + char* vendor; + char* type; + unsigned code; + ddict_gavp_t* gavps; + ddict_enum_t* enums; + struct _ddict_avp_t* next; +} ddict_avp_t; + +typedef struct _ddict_typedefn_t { + char* name; + char* parent; + struct _ddict_typedefn_t* next; +} ddict_typedefn_t; + +typedef struct _ddict_cmd_t { + char* name; + char* vendor; + unsigned code; + struct _ddict_cmd_t* next; +} ddict_cmd_t; + +typedef struct _ddict_xmlpi_t { + char* name; + char* key; + char* value; + struct _ddict_xmlpi_t* next; +} ddict_xmlpi_t; + +typedef struct _ddict_t { + ddict_application_t* applications; + ddict_vendor_t* vendors; + ddict_cmd_t* cmds; + ddict_typedefn_t* typedefns; + ddict_avp_t* avps; + ddict_xmlpi_t* xmlpis; +} ddict_t; + +extern void ddict_print(FILE* fh, ddict_t* d); +extern ddict_t* ddict_scan(const char* directory, const char* filename, int dbg); +extern void ddict_free(ddict_t* d); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/diam_dict_lex.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/diam_dict_lex.h new file mode 100644 index 00000000..1135d99c --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/diam_dict_lex.h @@ -0,0 +1,6 @@ +/* This is generated by runlex.sh. Do not edit it. */ +#define yylex DiamDictlex +#ifndef YY_DECL +#define YY_DECL int yylex(void) +#endif +YY_DECL; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dissector_filters.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dissector_filters.h new file mode 100644 index 00000000..595c3d57 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dissector_filters.h @@ -0,0 +1,60 @@ +/* dissector_filters.h + * Routines for dissector generated display filters + * + * $Id: dissector_filters.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __DISSECTOR_FILTERS_H__ +#define __DISSECTOR_FILTERS_H__ + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* callback function definition: is a filter available for this packet? */ +typedef gboolean (*is_filter_valid_func)(packet_info *pinfo); + +/* callback function definition: return the available filter for this packet or NULL if no filter is available */ +typedef const gchar* (*build_filter_string_func)(packet_info *pinfo); + + +/* register a dissector filter */ +extern void register_dissector_filter(const char *name, is_filter_valid_func is_filter_valid, build_filter_string_func build_filter_string); + + + +/*** THE FOLLOWING SHOULD NOT BE USED BY ANY DISSECTORS!!! ***/ + +typedef struct dissector_filter_s { + const char * name; + is_filter_valid_func is_filter_valid; + build_filter_string_func build_filter_string; +} dissector_filter_t; + +WS_VAR_IMPORT GList *dissector_filter_list; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* dissector_filters.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dissectors/packet-tcp.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dissectors/packet-tcp.h new file mode 100644 index 00000000..ee0b70cb --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dissectors/packet-tcp.h @@ -0,0 +1,232 @@ +/* packet-tcp.h + * + * $Id: packet-tcp.h 23902 2007-12-17 20:43:38Z sfisher $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PACKET_TCP_H__ +#define __PACKET_TCP_H__ + +/* TCP flags */ +#define TH_FIN 0x01 +#define TH_SYN 0x02 +#define TH_RST 0x04 +#define TH_PUSH 0x08 +#define TH_ACK 0x10 +#define TH_URG 0x20 +#define TH_ECN 0x40 +#define TH_CWR 0x80 + +/* Idea for gt: either x > y, or y is much bigger (assume wrap) */ +#define GT_SEQ(x, y) ((gint32)((y) - (x)) < 0) +#define LT_SEQ(x, y) ((gint32)((x) - (y)) < 0) +#define GE_SEQ(x, y) ((gint32)((y) - (x)) <= 0) +#define LE_SEQ(x, y) ((gint32)((x) - (y)) <= 0) +#define EQ_SEQ(x, y) ((x) == (y)) + +/* the tcp header structure, passed to tap listeners */ +struct tcpheader { + guint32 th_seq; + guint32 th_ack; + gboolean th_have_seglen; /* TRUE if th_seglen is valid */ + guint32 th_seglen; + guint32 th_win; /* make it 32 bits so we can handle some scaling */ + guint16 th_sport; + guint16 th_dport; + guint8 th_hlen; + guint8 th_flags; + address ip_src; + address ip_dst; +}; + +/* + * Private data passed from the TCP dissector to subdissectors. Passed to the + * subdissectors in pinfo->private_data + */ +struct tcpinfo { + guint32 seq; /* Sequence number of first byte in the data */ + guint32 nxtseq; /* Sequence number of first byte after data */ + guint32 lastackseq; /* Sequence number of last ack */ + gboolean is_reassembled; /* This is reassembled data. */ + gboolean urgent; /* TRUE if "urgent_pointer" is valid */ + guint16 urgent_pointer; /* Urgent pointer value for the current packet. */ +}; + +/* + * Loop for dissecting PDUs within a TCP stream; assumes that a PDU + * consists of a fixed-length chunk of data that contains enough information + * to determine the length of the PDU, followed by rest of the PDU. + * + * The first three arguments are the arguments passed to the dissector + * that calls this routine. + * + * "proto_desegment" is the dissector's flag controlling whether it should + * desegment PDUs that cross TCP segment boundaries. + * + * "fixed_len" is the length of the fixed-length part of the PDU. + * + * "get_pdu_len()" is a routine called to get the length of the PDU from + * the fixed-length part of the PDU; it's passed "pinfo", "tvb" and "offset". + * + * "dissect_pdu()" is the routine to dissect a PDU. + */ +extern void +tcp_dissect_pdus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + gboolean proto_desegment, guint fixed_len, + guint (*get_pdu_len)(packet_info *, tvbuff_t *, int), + dissector_t dissect_pdu); + +extern struct tcp_multisegment_pdu * +pdu_store_sequencenumber_of_next_pdu(packet_info *pinfo, guint32 seq, guint32 nxtpdu, emem_tree_t *multisegment_pdus); + +typedef struct _tcp_unacked_t { + struct _tcp_unacked_t *next; + guint32 frame; + guint32 seq; + guint32 nextseq; + nstime_t ts; +} tcp_unacked_t; + +struct tcp_acked { + guint32 frame_acked; + nstime_t ts; + + guint32 rto_frame; + nstime_t rto_ts; /* Time since previous packet for + retransmissions. */ + guint16 flags; + guint32 dupack_num; /* dup ack number */ + guint32 dupack_frame; /* dup ack to frame # */ +}; + +/* One instance of this structure is created for each pdu that spans across + * multiple tcp segments. + */ +struct tcp_multisegment_pdu { + guint32 seq; + guint32 nxtpdu; + guint32 first_frame; + guint32 last_frame; + nstime_t last_frame_time; + guint32 flags; +#define MSP_FLAGS_REASSEMBLE_ENTIRE_SEGMENT 0x00000001 +}; + +typedef struct _tcp_flow_t { + guint32 base_seq; /* base seq number (used by relative sequence numbers) + * or 0 if not yet known. + */ + tcp_unacked_t *segments; + guint32 lastack; /* last seen ack */ + nstime_t lastacktime; /* Time of the last ack packet */ + guint32 lastnondupack; /* frame number of last seen non dupack */ + guint32 dupacknum; /* dupack number */ + guint32 nextseq; /* highest seen nextseq */ + guint32 nextseqframe; /* frame number for segment with highest + * sequence number + */ + nstime_t nextseqtime; /* Time of the nextseq packet so we can + * distinguish between retransmission, + * fast retransmissions and outoforder + */ + guint32 window; /* last seen window */ + gint16 win_scale; /* -1 is we dont know */ +/* This tcp flow/session contains only one single PDU and should + * be reassembled until the final FIN segment. + */ +#define TCP_FLOW_REASSEMBLE_UNTIL_FIN 0x0001 + guint16 flags; + guint32 lastsegmentflags; + + /* This tree is indexed by sequence number and keeps track of all + * all pdus spanning multiple segments for this flow. + */ + emem_tree_t *multisegment_pdus; +} tcp_flow_t; + + +struct tcp_analysis { + /* These two structs are managed based on comparing the source + * and destination addresses and, if they're equal, comparing + * the source and destination ports. + * + * If the source is greater than the destination, then stuff + * sent from src is in ual1. + * + * If the source is less than the destination, then stuff + * sent from src is in ual2. + * + * XXX - if the addresses and ports are equal, we don't guarantee + * the behavior. + */ + tcp_flow_t flow1; + tcp_flow_t flow2; + + /* These pointers are set by get_tcp_conversation_data() + * fwd point in the same direction as the current packet + * and rev in the reverse direction + */ + tcp_flow_t *fwd; + tcp_flow_t *rev; + + /* This pointer is NULL or points to a tcp_acked struct if this + * packet has "interesting" properties such as being a KeepAlive or + * similar + */ + struct tcp_acked *ta; + /* This structure contains a tree containing all the various ta's + * keyed by frame number. + */ + emem_tree_t *acked_table; + + /* Remember the timestamp of the first frame seen in this tcp + * conversation to be able to calculate a relative time compared + * to the start of this conversation + */ + nstime_t ts_first; + + /* Remember the timestamp of the frame that was last seen in this + * tcp conversation to be able to calculate a delta time compared + * to previous frame in this conversation + */ + nstime_t ts_prev; +}; + +/* Structure that keeps per packet data. First used to be able + * to calculate the time_delta from the last seen frame in this + * TCP conversation. Can be extended for future use. + */ +struct tcp_per_packet_data_t { + nstime_t ts_del; +}; + + +extern void dissect_tcp_payload(tvbuff_t *tvb, packet_info *pinfo, int offset, + guint32 seq, guint32 nxtseq, guint32 sport, + guint32 dport, proto_tree *tree, + proto_tree *tcp_tree, + struct tcp_analysis *tcpd); + +extern struct tcp_analysis *get_tcp_conversation_data(packet_info *pinfo); + +extern gboolean decode_tcp_ports(tvbuff_t *, int, packet_info *, proto_tree *, int, int, struct tcp_analysis *); + + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd.h new file mode 100644 index 00000000..6063fb31 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd.h @@ -0,0 +1,62 @@ +/* + * dtd.h + * + * XML dissector for Wireshark + * DTD import declarations + * + * Copyright 2005, Luis E. Garcia Ontanon + * + * $Id: dtd.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _DTD_H_ +#define _DTD_H_ + +#include +#include /* exit() */ + +typedef struct _dtd_build_data_t { + gchar* proto_name; + gchar* media_type; + gchar* description; + gchar* proto_root; + gboolean recursion; + + GPtrArray* elements; + GPtrArray* attributes; + + GString* error; +} dtd_build_data_t; + +typedef struct _dtd_token_data_t { + gchar* text; + gchar* location; +} dtd_token_data_t; + +typedef struct _dtd_named_list_t { + gchar* name; + GPtrArray* list; +} dtd_named_list_t; + +extern GString* dtd_preparse(const gchar* dname, const gchar* fname, GString* err); +extern dtd_build_data_t* dtd_parse(GString* s); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_grammar.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_grammar.h new file mode 100644 index 00000000..732b0361 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_grammar.h @@ -0,0 +1,23 @@ +#define TOKEN_TAG_START 1 +#define TOKEN_DOCTYPE_KW 2 +#define TOKEN_NAME 3 +#define TOKEN_OPEN_BRACKET 4 +#define TOKEN_CLOSE_BRACKET 5 +#define TOKEN_TAG_STOP 6 +#define TOKEN_ATTLIST_KW 7 +#define TOKEN_ELEMENT_KW 8 +#define TOKEN_ATT_TYPE 9 +#define TOKEN_ATT_DEF 10 +#define TOKEN_ATT_DEF_WITH_VALUE 11 +#define TOKEN_QUOTED 12 +#define TOKEN_IMPLIED_KW 13 +#define TOKEN_REQUIRED_KW 14 +#define TOKEN_OPEN_PARENS 15 +#define TOKEN_CLOSE_PARENS 16 +#define TOKEN_PIPE 17 +#define TOKEN_STAR 18 +#define TOKEN_PLUS 19 +#define TOKEN_QUESTION 20 +#define TOKEN_ELEM_DATA 21 +#define TOKEN_COMMA 22 +#define TOKEN_EMPTY_KW 23 diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_parse.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_parse.h new file mode 100644 index 00000000..99a9958a --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_parse.h @@ -0,0 +1,37 @@ +/* dtd_parse.h +* an XML dissector for Wireshark +* header file to declare functions defined in lexer and used in parser, +* or vice versa +* +* Copyright 2004, Luis E. Garcia Ontanon +* +* $Id: dtd_parse.h 3992 2008-06-10 03:13:11Z dgu $ +* +* Wireshark - Network traffic analyzer +* By Gerald Combs +* Copyright 1998 Gerald Combs +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +extern void DtdParse(void*,int,dtd_token_data_t*,dtd_build_data_t*); +#if (GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 16)) +extern void *DtdParseAlloc(void *(*)(gsize)); +#else +extern void *DtdParseAlloc(void *(*)(gulong)); +#endif +extern void DtdParseFree( void*, void(*)(void*) ); +extern void DtdParseTrace(FILE *TraceFILE, char *zTracePrompt); +extern int Dtd_Parse_lex(void); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_parse_lex.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_parse_lex.h new file mode 100644 index 00000000..c809f40b --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_parse_lex.h @@ -0,0 +1,6 @@ +/* This is generated by runlex.sh. Do not edit it. */ +#define yylex Dtd_Parse_lex +#ifndef YY_DECL +#define YY_DECL int yylex(void) +#endif +YY_DECL; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_preparse_lex.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_preparse_lex.h new file mode 100644 index 00000000..dc4b7bcf --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_preparse_lex.h @@ -0,0 +1,6 @@ +/* This is generated by runlex.sh. Do not edit it. */ +#define yylex Dtd_PreParse_lex +#ifndef YY_DECL +#define YY_DECL int yylex(void) +#endif +YY_DECL; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/eap.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/eap.h new file mode 100644 index 00000000..24934ceb --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/eap.h @@ -0,0 +1,53 @@ +/* sminmpec.h + * Extenal definitions for EAP Extensible Authentication Protocol dissection + * RFC 2284, RFC 3748 + * + * $Id: eap.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2004 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __EAP_H__ +#define __EAP_H__ + +#define EAP_REQUEST 1 +#define EAP_RESPONSE 2 +#define EAP_SUCCESS 3 +#define EAP_FAILURE 4 + +WS_VAR_IMPORT const value_string eap_code_vals[]; + +#define EAP_TYPE_ID 1 +#define EAP_TYPE_NOTIFY 2 +#define EAP_TYPE_NAK 3 +#define EAP_TYPE_MD5 4 +#define EAP_TYPE_TLS 13 +#define EAP_TYPE_LEAP 17 +#define EAP_TYPE_SIM 18 +#define EAP_TYPE_TTLS 21 +#define EAP_TYPE_AKA 23 +#define EAP_TYPE_PEAP 25 +#define EAP_TYPE_MSCHAPV2 26 +#define EAP_TYPE_FAST 43 +#define EAP_TYPE_EXT 254 + +WS_VAR_IMPORT const value_string eap_type_vals[]; + + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/emem.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/emem.h new file mode 100644 index 00000000..a1e0c898 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/emem.h @@ -0,0 +1,373 @@ +/* emem.h + * Definitions for Wireshark memory management and garbage collection + * Ronnie Sahlberg 2005 + * + * $Id: emem.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __EMEM_H__ +#define __EMEM_H__ + +#include "gnuc_format_check.h" + +/* Functions for handling memory allocation and garbage collection with + * a packet lifetime scope. + * These functions are used to allocate memory that will only remain persistent + * until Wireshark starts dissecting the next packet in the list. + * Everytime Wireshark starts decoding the next packet all memory allocated + * through these functions will be released back to the free pool. + * + * These functions are very fast and offer automatic garbage collection: + * Everytime a new packet is dissected, all memory allocations done in + * the previous packet is freed. + */ +/* Initialize packet-lifetime memory allocation pool. This function is called + * once when [t]Wireshark is initialized to set up the required structures. + */ +void ep_init_chunk(void); + +/* Allocate memory with a packet lifetime scope */ +void *ep_alloc(size_t size); +#define ep_new(type) ((type*)ep_alloc(sizeof(type))) + +/* Allocate memory with a packet lifetime scope and fill it with zeros*/ +void* ep_alloc0(size_t size); +#define ep_new0(type) ((type*)ep_alloc0(sizeof(type))) + +/* Duplicate a string with a packet lifetime scope */ +gchar* ep_strdup(const gchar* src); + +/* Duplicate at most n characters of a string with a packet lifetime scope */ +gchar* ep_strndup(const gchar* src, size_t len); + +/* Duplicate a buffer with a packet lifetime scope */ +void* ep_memdup(const void* src, size_t len); + +/* Create a formatted string with a packet lifetime scope */ +gchar* ep_strdup_vprintf(const gchar* fmt, va_list ap); +gchar* ep_strdup_printf(const gchar* fmt, ...) + GNUC_FORMAT_CHECK(printf, 1, 2); + +/* allocates with a packet lifetime scope an array of type made of num elements */ +#define ep_alloc_array(type,num) (type*)ep_alloc(sizeof(type)*(num)) + +/* allocates with a packet lifetime scope an array of type made of num elements, + * initialised to zero. + */ +#define ep_alloc_array0(type,num) (type*)ep_alloc0(sizeof(type)*(num)) + +/* + * Splits a string into a maximum of max_tokens pieces, using the given + * delimiter. If max_tokens is reached, the remainder of string is appended + * to the last token. Consecutive delimiters are treated as a single delimiter. + * + * the vector and all the strings are allocated with packet lifetime scope + */ +gchar** ep_strsplit(const gchar* string, const gchar* delimiter, int max_tokens); + +/* release all memory allocated in the previous packet dissector */ +void ep_free_all(void); + + +/* a stack implemented using ephemeral allocators */ + +typedef struct _ep_stack_frame_t** ep_stack_t; + +struct _ep_stack_frame_t { + void* payload; + struct _ep_stack_frame_t* below; + struct _ep_stack_frame_t* above; +}; + +/* + * creates an empty stack with a packet lifetime scope + */ +ep_stack_t ep_stack_new(void); + +/* + * pushes item into stack, returns item + */ +void* ep_stack_push(ep_stack_t stack, void* item); + +/* + * pops an item from the stack + */ +void* ep_stack_pop(ep_stack_t stack); + +/* + * returns the item on top of the stack without popping it + */ +#define ep_stack_peek(stack) ((*(stack))->payload) + + +/* Functions for handling memory allocation and garbage collection with + * a capture lifetime scope. + * These functions are used to allocate memory that will only remain persistent + * until Wireshark opens a new capture or capture file. + * Everytime Wireshark starts a new capture or opens a new capture file + * all the data allocated through these functions will be released back + * to the free pool. + * + * These functions are very fast and offer automatic garbage collection. + */ +/* Initialize capture-lifetime memory allocation pool. This function is called + * once when [t]Wireshark is initialized to set up the required structures. + */ +void se_init_chunk(void); + +/* Allocate memory with a capture lifetime scope */ +void *se_alloc(size_t size); + +/* Allocate memory with a capture lifetime scope and fill it with zeros*/ +void* se_alloc0(size_t size); + +/* Duplicate a string with a capture lifetime scope */ +gchar* se_strdup(const gchar* src); + +/* Duplicate at most n characters of a string with a capture lifetime scope */ +gchar* se_strndup(const gchar* src, size_t len); + +/* Duplicate a buffer with a capture lifetime scope */ +void* se_memdup(const void* src, size_t len); + +/* Create a formatted string with a capture lifetime scope */ +gchar* se_strdup_vprintf(const gchar* fmt, va_list ap); +gchar* se_strdup_printf(const gchar* fmt, ...) + GNUC_FORMAT_CHECK(printf, 1, 2); + +/* allocates with a capture lifetime scope an array of type made of num elements */ +#define se_alloc_array(type,num) (type*)se_alloc(sizeof(type)*(num)) + +/* release all memory allocated */ +void se_free_all(void); + + + + +/************************************************************** + * binary trees + **************************************************************/ +typedef struct _emem_tree_node_t { + struct _emem_tree_node_t *parent; + struct _emem_tree_node_t *left; + struct _emem_tree_node_t *right; + struct { +#define EMEM_TREE_RB_COLOR_RED 0 +#define EMEM_TREE_RB_COLOR_BLACK 1 + guint32 rb_color:1; +#define EMEM_TREE_NODE_IS_DATA 0 +#define EMEM_TREE_NODE_IS_SUBTREE 1 + guint32 is_subtree:1; + } u; + guint32 key32; + void *data; +} emem_tree_node_t; + +/* Right now we only do basic red/black trees but in the future we might want + * to try something different, such as a tree where each node keeps track + * of how many times it has been looked up, and letting often looked up + * nodes bubble upwards in the tree using rotate_right/left. + * That would probably be good for things like nfs filehandles + */ +#define EMEM_TREE_TYPE_RED_BLACK 1 +typedef struct _emem_tree_t { + struct _emem_tree_t *next; + int type; + const char *name; /* just a string to make debugging easier */ + emem_tree_node_t *tree; + void *(*malloc)(size_t); +} emem_tree_t; + +/* list of all trees with se allocation scope so that they can all be reset + * automatically when we free all se memory + */ +extern emem_tree_t *se_trees; + + +/* ******************************************************************* + * Tree functions for SE memory allocation scope + * ******************************************************************* */ +/* This function is used to create a se based tree with monitoring. + * When the SE heap is released back to the system the pointer to the + * tree is automatically reset to NULL. + * + * type is : EMEM_TREE_TYPE_RED_BLACK for a standard red/black tree. + */ +emem_tree_t *se_tree_create(int type, const char *name); + +/* This function is similar to the se_tree_create() call but with the + * difference that when the se memory is release everything including the + * pointer to the tree itself will be released. + * This tree will not be just reset to zero it will be completely forgotten + * by the allocator. + * Use this function for when you want to store the pointer to a tree inside + * another structure that is also se allocated so that when the structure is + * released, the tree will be completely released as well. + */ +emem_tree_t *se_tree_create_non_persistent(int type, const char *name); + +/* se_tree_insert32 + * Insert data into the tree and key it by a 32bit integer value + */ +#define se_tree_insert32 emem_tree_insert32 + +/* se_tree_lookup32 + * Retreive the data at the search key. the search key is a 32bit integer value + */ +#define se_tree_lookup32 emem_tree_lookup32 + +/* se_tree_lookup32_le + * Retreive the data for the largest key that is less than or equal + * to the search key. + */ +#define se_tree_lookup32_le emem_tree_lookup32_le + +/* se_tree_insert32_array + * Insert data into the tree and key it by a 32bit integer value + */ +#define se_tree_insert32_array emem_tree_insert32_array + +/* se_tree_lookup32_array + * Lookup data from the tree that is index by an array + */ +#define se_tree_lookup32_array emem_tree_lookup32_array + + + +/* Create a new string based hash table */ +#define se_tree_create_string() se_tree_create(SE_TREE_TYPE_RED_BLACK) + +/* Insert a new value under a string key */ +#define se_tree_insert_string emem_tree_insert_string + +/* Lookup the value under a string key */ +#define se_tree_lookup_string emem_tree_lookup_string + +/* Traverse a tree */ +#define se_tree_foreach emem_tree_foreach + + +/* ******************************************************************* + * Tree functions for PE memory allocation scope + * ******************************************************************* */ +/* These trees have PErmanent allocation scope and will never be released + */ +emem_tree_t *pe_tree_create(int type, char *name); +#define pe_tree_insert32 emem_tree_insert32 +#define pe_tree_lookup32 emem_tree_lookup32 +#define pe_tree_lookup32_le emem_tree_lookup32_le +#define pe_tree_insert32_array emem_tree_insert32_array +#define pe_tree_lookup32_array emem_tree_lookup32_array +#define pe_tree_insert_string emem_tree_insert_string +#define pe_tree_lookup_string emem_tree_lookup_string +#define pe_tree_foreach emem_tree_foreach + + + +/* ****************************************************************** + * Real tree functions + * ****************************************************************** */ + +/* This function is used to insert a node indexed by a guint32 key value. + * The data pointer should be allocated by the appropriate storage scope + * so that it will be released at the same time as the tree itself is + * destroyed. + */ +void emem_tree_insert32(emem_tree_t *se_tree, guint32 key, void *data); + +/* This function will look up a node in the tree indexed by a guint32 integer + * value. + */ +void *emem_tree_lookup32(emem_tree_t *se_tree, guint32 key); + +/* This function will look up a node in the tree indexed by a guint32 integer + * value. + * The function will return the node that has the largest key that is + * equal to or smaller than the search key, or NULL if no such key was + * found. + */ +void *emem_tree_lookup32_le(emem_tree_t *se_tree, guint32 key); + +typedef struct _emem_tree_key_t { + guint32 length; /*length in guint32 words */ + guint32 *key; +} emem_tree_key_t; + +/* This function is used to insert a node indexed by a sequence of guint32 + * key values. + * The data pointer should be allocated by SE allocators so that the + * data will be released at the same time as the tree itself is destroyed. + * + * Note: all the "key" members of the "key" argument MUST be aligned on + * 32-bit boundaries; otherwise, this code will crash on platforms such + * as SPARC that require aligned pointers. + * + * If you use ...32_array() calls you MUST make sure that every single node + * you add to a specific tree always has a key of exactly the same number of + * keylen words or things will most likely crash. Or at least that every single + * item that sits behind the same top level node always have exactly the same + * number of words. + * + * One way to guarantee this is the way that NFS does this for the + * nfs_name_snoop_known tree which holds filehandles for both v2 and v3. + * v2 filehandles are always 32 bytes (8 words) while v3 filehandles can have + * any length (though 32bytes are most common). + * The NFS dissector handles this by providing a guint32 containing the length + * as the very first item in this vector : + * + * emem_tree_key_t fhkey[3]; + * + * fhlen=nns->fh_length; + * fhkey[0].length=1; + * fhkey[0].key=&fhlen; + * fhkey[1].length=fhlen/4; + * fhkey[1].key=nns->fh; + * fhkey[2].length=0; + */ +void emem_tree_insert32_array(emem_tree_t *se_tree, emem_tree_key_t *key, void *data); + +/* This function will look up a node in the tree indexed by a sequence of + * guint32 integer values. + */ +void *emem_tree_lookup32_array(emem_tree_t *se_tree, emem_tree_key_t *key); + +/* case insensitive strings as keys */ +#define EMEM_TREE_STRING_NOCASE 0x00000001 +/* Insert a new value under a string key */ +void emem_tree_insert_string(emem_tree_t* h, const gchar* k, void* v, guint32 flags); + +/* Lookup the value under a string key */ +void* emem_tree_lookup_string(emem_tree_t* h, const gchar* k, guint32 flags); + + +/* traverse a tree. if the callback returns TRUE the traversal will end */ +typedef gboolean (*tree_foreach_func)(void *value, void *userdata); + +gboolean emem_tree_foreach(emem_tree_t* emem_tree, tree_foreach_func callback, void *user_data); + + + + +void emem_print_tree(emem_tree_t* emem_tree); + + + +#endif /* emem.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/epan.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/epan.h new file mode 100644 index 00000000..9da31108 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/epan.h @@ -0,0 +1,93 @@ +/* epan.h + * + * $Id: epan.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark Protocol Analyzer Library + * + * Copyright (c) 2001 by Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPAN_H +#define EPAN_H + +#include +#include "frame_data.h" +#include "column_info.h" +#include "register.h" + +typedef struct _epan_dissect_t epan_dissect_t; + +#include "dfilter/dfilter.h" + +/* init the whole epan module, this is used to be called only once in a program */ +void epan_init(void (*register_all_protocols)(register_cb cb, gpointer client_data), + void (*register_all_handoffs)(register_cb cb, gpointer client_data), + register_cb cb, + void *client_data, + void (*report_failure)(const char *, va_list), + void (*report_open_failure)(const char *, int, gboolean), + void (*report_read_failure)(const char *, int)); +/* cleanup the whole epan module, this is used to be called only once in a program */ +void epan_cleanup(void); +/* Initialize the table of conversations. */ +void epan_conversation_init(void); +/* Initialize the table of circuits. */ +/* XXX - what is a circuit and should this better be combined with epan_conversation_init? */ +void epan_circuit_init(void); + +/* A client will create one epan_t for an entire dissection session. + * A single epan_t will be used to analyze the entire sequence of packets, + * sequentially, in a single session. A session corresponds to a single + * packet trace file. The reaons epan_t exists is that some packets in + * some protocols cannot be decoded without knowledge of previous packets. + * This inter-packet "state" is stored in the epan_t. + */ +/* XXX - NOTE: epan_t, epan_new and epan_free are currently unused! */ +typedef struct epan_session epan_t; + +epan_t* +epan_new(void); + +void +epan_free(epan_t*); + +extern gchar* +epan_get_version(void); + +/* get a new single packet dissection */ +/* should be freed using epan_dissect_free() after packet dissection completed */ +epan_dissect_t* +epan_dissect_new(gboolean create_proto_tree, gboolean proto_tree_visible); + +/* run a single packet dissection */ +void +epan_dissect_run(epan_dissect_t *edt, void* pseudo_header, + const guint8* data, frame_data *fd, column_info *cinfo); + +/* Prime a proto_tree using the fields/protocols used in a dfilter. */ +void +epan_dissect_prime_dfilter(epan_dissect_t *edt, const dfilter_t *dfcode); + +/* fill the dissect run output into the packet list columns */ +void +epan_dissect_fill_in_columns(epan_dissect_t *edt); + +/* free a single packet dissection */ +void +epan_dissect_free(epan_dissect_t* edt); + +#endif /* EPAN_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/epan_dissect.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/epan_dissect.h new file mode 100644 index 00000000..9f40f39a --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/epan_dissect.h @@ -0,0 +1,44 @@ +/* epan_dissect.h + * + * $Id: epan_dissect.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark Protocol Analyzer Library + * + * Copyright (c) 2001 by Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPAN_DISSECT_H +#define EPAN_DISSECT_H + +#include "tvbuff.h" +#include "proto.h" +#include "packet_info.h" + +/* Dissection of a single byte array. Holds tvbuff info as + * well as proto_tree info. As long as the epan_dissect_t for a byte + * array is in existence, you must not free or move that byte array, + * as the structures that the epan_dissect_t contains might have pointers + * to addresses in your byte array. + */ +struct _epan_dissect_t { + tvbuff_t *tvb; + proto_tree *tree; + packet_info pi; +}; + + +#endif /* EPAN_DISSECT_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/etypes.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/etypes.h new file mode 100644 index 00000000..34898676 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/etypes.h @@ -0,0 +1,408 @@ +/* etypes.h + * Defines ethernet packet types, similar to tcpdump's ethertype.h + * + * $Id: etypes.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ETYPES_H__ +#define __ETYPES_H__ + +/* + * Maximum length of an IEEE 802.3 frame; Ethernet type/length values + * greater than it are types, Ethernet type/length values less than or + * equal to it are lengths. + */ +#define IEEE_802_3_MAX_LEN 1500 + +#ifndef ETHERTYPE_UNK +#define ETHERTYPE_UNK 0x0000 +#endif + +/* Sources: + * http://www.iana.org/assignments/ethernet-numbers + * TCP/IP Illustrated, Volume 1 + * RFCs 894, 1042, 826 + * tcpdump's ethertype.h + * http://www.cavebear.com/CaveBear/Ethernet/ + * http://standards.ieee.org/regauth/ethertype/type-pub.html + * http://standards.ieee.org/regauth/ethertype/eth.txt + * (The first of the two IEEE URLs is the one that the "EtherType Field + * Public Assignments" link on the page at + * + * http://standards.ieee.org/regauth/ethertype/index.shtml + * + * goes to, but it is redirected to the second of those - i.e., both + * of the IEEE URLs ultimately go to the same page.) + */ + +/* Order these values by number */ + +#ifndef ETHERTYPE_XNS_IDP +#define ETHERTYPE_XNS_IDP 0x0600 +#endif + +#ifndef ETHERTYPE_IP +#define ETHERTYPE_IP 0x0800 +#endif + +#ifndef ETHERTYPE_X25L3 +#define ETHERTYPE_X25L3 0x0805 +#endif + +#ifndef ETHERTYPE_ARP +#define ETHERTYPE_ARP 0x0806 +#endif + +#ifndef ETHERTYPE_WOL +#define ETHERTYPE_WOL 0x0842 /* Wake on LAN. Not offically registered. */ +#endif + +#ifndef ETHERTYPE_WMX_M2M +#define ETHERTYPE_WMX_M2M 0x08f0 +#endif + +#ifndef ETHERTYPE_VINES_IP +#define ETHERTYPE_VINES_IP 0x0bad +#endif + +#ifndef ETHERTYPE_VINES_ECHO +#define ETHERTYPE_VINES_ECHO 0x0baf +#endif + +#ifndef ETHERTYPE_TRAIN +/* + * Created by Microsoft Network Monitor as a summary packet. + */ +#define ETHERTYPE_TRAIN 0x1984 +#endif + +#ifndef ETHERTYPE_CGMP +#define ETHERTYPE_CGMP 0x2001 +#endif + +#ifndef ETHERTYPE_CENTRINO_PROMISC +#define ETHERTYPE_CENTRINO_PROMISC 0x2452 /* Intel Centrino promiscuous packets */ +#endif + +#ifndef ETHERTYPE_3C_NBP_DGRAM +#define ETHERTYPE_3C_NBP_DGRAM 0x3c07 +#endif + +#ifndef ETHERTYPE_EPL_V1 +#define ETHERTYPE_EPL_V1 0x3E3F +#endif + +#ifndef ETHERTYPE_DEC +#define ETHERTYPE_DEC 0x6000 +#endif + +#ifndef ETHERTYPE_DNA_DL +#define ETHERTYPE_DNA_DL 0x6001 +#endif + +#ifndef ETHERTYPE_DNA_RC +#define ETHERTYPE_DNA_RC 0x6002 +#endif + +#ifndef ETHERTYPE_DNA_RT +#define ETHERTYPE_DNA_RT 0x6003 +#endif + +#ifndef ETHERTYPE_LAT +#define ETHERTYPE_LAT 0x6004 +#endif + +#ifndef ETHERTYPE_DEC_DIAG +#define ETHERTYPE_DEC_DIAG 0x6005 +#endif + +#ifndef ETHERTYPE_DEC_CUST +#define ETHERTYPE_DEC_CUST 0x6006 +#endif + +#ifndef ETHERTYPE_DEC_SCA +#define ETHERTYPE_DEC_SCA 0x6007 +#endif + +#ifndef ETHERTYPE_ETHBRIDGE +#define ETHERTYPE_ETHBRIDGE 0x6558 /* transparent Ethernet bridging [RFC1701]*/ +#endif + +#ifndef ETHERTYPE_RAW_FR +#define ETHERTYPE_RAW_FR 0x6559 /* Raw Frame Relay [RFC1701] */ +#endif + +#ifndef ETHERTYPE_REVARP +#define ETHERTYPE_REVARP 0x8035 +#endif + +#ifndef ETHERTYPE_DEC_LB +#define ETHERTYPE_DEC_LB 0x8038 +#endif + +#ifndef ETHERTYPE_DEC_LAST +#define ETHERTYPE_DEC_LAST 0x8041 /* DEC Local Area Systems Transport */ +#endif + +#ifndef ETHERTYPE_ATALK +#define ETHERTYPE_ATALK 0x809b +#endif + +#ifndef ETHERTYPE_SNA +#define ETHERTYPE_SNA 0x80d5 +#endif + +#ifndef ETHERTYPE_AARP +#define ETHERTYPE_AARP 0x80f3 +#endif + +#ifndef ETHERTYPE_VLAN +#define ETHERTYPE_VLAN 0x8100 /* 802.1Q Virtual LAN */ +#endif + +#ifndef ETHERTYPE_NSRP +#define ETHERTYPE_NSRP 0x8133 +#endif + +#ifndef ETHERTYPE_IPX +#define ETHERTYPE_IPX 0x8137 +#endif + +#ifndef ETHERTYPE_SNMP +#define ETHERTYPE_SNMP 0x814c /* SNMP over Ethernet, RFC 1089 */ +#endif + +#ifndef ETHERTYPE_WCP +#define ETHERTYPE_WCP 0x80ff /* Wellfleet Compression Protocol */ +#endif + +#ifndef ETHERTYPE_STP +#define ETHERTYPE_STP 0x8181 /* STP, HIPPI-ST */ +#endif + +#ifndef ETHERTYPE_ISMP +#define ETHERTYPE_ISMP 0x81fd /* Cabletron Interswitch Message Protocol */ +#endif + +#ifndef ETHERTYPE_ISMP_TBFLOOD +#define ETHERTYPE_ISMP_TBFLOOD 0x81ff /* Cabletron Interswitch Message Protocol */ +#endif + +#ifndef ETHERTYPE_IPv6 +#define ETHERTYPE_IPv6 0x86dd +#endif + +#ifndef ETHERTYPE_WLCCP +#define ETHERTYPE_WLCCP 0x872d /* Cisco Wireless Lan Context Control Protocol */ +#endif + +#ifndef ETHERTYPE_MAC_CONTROL +#define ETHERTYPE_MAC_CONTROL 0x8808 +#endif + +#ifndef ETHERTYPE_SLOW_PROTOCOLS +#define ETHERTYPE_SLOW_PROTOCOLS 0x8809 +#endif + +#ifndef ETHERTYPE_PPP +#define ETHERTYPE_PPP 0x880b /* no, this is not PPPoE */ +#endif + +#ifndef ETHERTYPE_COBRANET +#define ETHERTYPE_COBRANET 0x8819 /* Cirrus cobranet */ +#endif + +#ifndef ETHERTYPE_MPLS +#define ETHERTYPE_MPLS 0x8847 /* MPLS unicast packet */ +#endif + +#ifndef ETHERTYPE_MPLS_MULTI +#define ETHERTYPE_MPLS_MULTI 0x8848 /* MPLS multicast packet */ +#endif + +#ifndef ETHERTYPE_FOUNDRY +#define ETHERTYPE_FOUNDRY 0x885a /* Some Foundry proprietary protocol */ +#endif + +#ifndef ETHERTYPE_PPPOED +#define ETHERTYPE_PPPOED 0x8863 /* PPPoE Discovery Protocol */ +#endif + +#ifndef ETHERTYPE_PPPOES +#define ETHERTYPE_PPPOES 0x8864 /* PPPoE Session Protocol */ +#endif + +#ifndef ETHERTYPE_INTEL_ANS +#define ETHERTYPE_INTEL_ANS 0x886d /* Intel ANS (NIC teaming) http://www.intel.com/support/network/adapter/ans/probes.htm */ +#endif + +#ifndef ETHERTYPE_MS_NLB_HEARTBEAT +#define ETHERTYPE_MS_NLB_HEARTBEAT 0x886f /* MS Network Load Balancing heartbeat http://www.microsoft.com/technet/treeview/default.asp?url=/TechNet/prodtechnol/windows2000serv/deploy/confeat/nlbovw.asp */ +#endif + +#ifndef ETHERTYPE_HOMEPLUG +#define ETHERTYPE_HOMEPLUG 0x887B /* IEEE assigned Ethertype */ +#endif + +#ifndef ETHERTYPE_CDMA2000_A10_UBS +#define ETHERTYPE_CDMA2000_A10_UBS 0x8881 /* the byte stream protocol that is used for IP based micro-mobility bearer interfaces (A10) in CDMA2000(R)-based wireless networks */ +#endif + +#ifndef ETHERTYPE_EAPOL +#define ETHERTYPE_EAPOL 0x888e /* 802.1x Authentication */ +#endif + +#ifndef ETHERTYPE_PROFINET +#define ETHERTYPE_PROFINET 0x8892 /* PROFIBUS PROFINET protocol */ +#endif + +#ifndef ETHERTYPE_HYPERSCSI +#define ETHERTYPE_HYPERSCSI 0x889A /* HyperSCSI */ +#endif + +#ifndef ETHERTYPE_CSM_ENCAPS +#define ETHERTYPE_CSM_ENCAPS 0x889B /* Mindspeed Technologies www.mindspeed.com */ +#endif + +#ifndef ETHERTYPE_TELKONET +#define ETHERTYPE_TELKONET 0x88A1 /* Telkonet powerline ethernet */ +#endif + +#ifndef ETHERTYPE_AOE +#define ETHERTYPE_AOE 0x88A2 +#endif + +#ifndef ETHERTYPE_ECATF +#define ETHERTYPE_ECATF 0x88A4 /* Ethernet type for EtherCAT frames */ +#endif + +#ifndef ETHERTYPE_IEEE_802_1AD +#define ETHERTYPE_IEEE_802_1AD 0x88A8 /* IEEE 802.1ad Provider Bridge, Q-in-Q */ +#endif + +#ifndef ETHERTYPE_EPL_V2 +#define ETHERTYPE_EPL_V2 0x88AB +#endif + +#ifndef ETHERTYPE_BRDWALK +#define ETHERTYPE_BRDWALK 0x88AE +#endif + +#ifndef ETHERTYPE_IEEE802_OUI_EXTENDED +#define ETHERTYPE_IEEE802_OUI_EXTENDED 0x88B7 /* IEEE 802a OUI Extended Ethertype */ +#endif + +#ifndef ETHERTYPE_IEC61850_GOOSE +#define ETHERTYPE_IEC61850_GOOSE 0x88b8 /* IEC 61850 is a global standard for the use in utility communication,*/ +#endif /* in particular for the information exchange between IED's in a power */ + /* transmission or distribution substation. */ + /* There are three types of application services + that use a specific EtherType. GOOSE uses + EtherType field 88b8, GSE management services + uses EtherType field 88b9. These two protocols + are defined in IEC 61850-8-1. SV (Sampled + Value Transmission) uses EtherType field + 88ba; the protocol is defined in IEC 61850-9-1 + and IEC 61850-9-2. */ + +#ifndef ETHERTYPE_IEC61850_GSE +#define ETHERTYPE_IEC61850_GSE 0x88b9 /* IEC 61850 is a global standard for the use in utility communication,*/ +#endif /* in particular for the information exchange between IED's in a power */ + +#ifndef ETHERTYPE_IEC61850_SV +#define ETHERTYPE_IEC61850_SV 0x88ba /* IEC 61850 is a global standard for the use in utility communication,*/ +#endif /* in particular for the information exchange between IED's in a power */ + +#ifndef ETHERTYPE_TIPC +#define ETHERTYPE_TIPC 0x88ca /* TIPC (Transparent Inter Process Communication, */ +#endif /* http://tipc.sourceforge.net/) Ericsson Research Canada Inc */ + +#ifndef ETHERTYPE_RSN_PREAUTH +#define ETHERTYPE_RSN_PREAUTH 0x88c7 /* 802.11i Pre-Authentication */ +#endif + +#ifndef ETHERTYPE_LLDP +#define ETHERTYPE_LLDP 0x88cc /* IEEE 802.1AB Link Layer Discovery Protocol (LLDP) */ +#endif + +#ifndef ETHERTYPE_SERCOS +#define ETHERTYPE_SERCOS 0x88cd /* SERCOS interface real-time protocol for motion control */ +#endif + +#ifndef ETHERTYPE_3GPP2 +#define ETHERTYPE_3GPP2 0x88d2 /* This will be used in a revision of the Interoperabi */ +#endif /* Specification (IOS) for cdma2000 Access Network Interfaces (document numbers A.S0011-B */ + /* through A.S0017-B v1.0). This document already uses the Ether type 8881 */ + +#ifndef ETHERTYPE_LLTD +#define ETHERTYPE_LLTD 0x88d9 /* Link Layer Topology Discovery (LLTD) */ +#endif + +#ifndef ETHERTYPE_MRP +#define ETHERTYPE_MRP 0x88e3 /* IEC 61158-6-10 Media Redundancy Protocol (MRP) */ +#endif + +#ifndef ETHERTYPE_IEEE_802_1AH +#define ETHERTYPE_IEEE_802_1AH 0x88F0 /* IEEE 802.1ah Provider Backbone Bridge Mac-in-Mac */ +#endif + +#ifndef ETHERTYPE_PTP +#define ETHERTYPE_PTP 0x88F7 /* IEEE1588v2 (PTPv2) over Ethernet */ +#endif /* in particular for the information exchange between IED's in a power */ + /* transmission or distribution substation. */ + /* There are three types of application services */ + +#ifndef ETHERTYPE_PRP +#define ETHERTYPE_PRP 0x88FB /* Parallel Redundancy Protocol (IEC62439 Chapter 6) */ +#endif + +#ifndef ETHERTYPE_CFM +#define ETHERTYPE_CFM 0x8902 /* IEEE 802.1ag Connectivity Fault Management */ +#endif /* (CFM) protocol. */ + +#ifndef ETHERTYPE_FCOE +#define ETHERTYPE_FCOE 0x8906 /* Fibre Channel over Ethernet */ +#endif + +#ifndef ETHERTYPE_LOOP +#define ETHERTYPE_LOOP 0x9000 /* used for layer 2 testing (do i see my own frames on the wire) */ +#endif + +#ifndef ETHERTYPE_RTMAC +#define ETHERTYPE_RTMAC 0x9021 /* RTnet: Real-Time Media Access Control */ +#endif + +#ifndef ETHERTYPE_RTCFG +#define ETHERTYPE_RTCFG 0x9022 /* RTnet: Real-Time Configuration Protocol */ +#endif + +#ifndef ETHERTYPE_LLT +#define ETHERTYPE_LLT 0xCAFE /* Veritas Low Latency Transport (not officially registered) */ +#endif + +#ifndef ETHERTYPE_FCFT +/* type used to transport FC frames+MDS hdr internal to Cisco's MDS switch */ +#define ETHERTYPE_FCFT 0xFCFC +#endif + +extern const value_string etype_vals[]; + +#endif /* etypes.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ex-opt.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ex-opt.h new file mode 100644 index 00000000..5839b726 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ex-opt.h @@ -0,0 +1,44 @@ +/* + * ex-opt.h + * + * eXtension command line options + * + * (c) 2006, Luis E. Garcia Ontanon + * + * $Id: ex-opt.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _EX_OPT_H +#define _EX_OPT_H + +/* will be called by main each time a -X option is found */ +extern gboolean ex_opt_add(const gchar* optarg); + +/* yields the number of arguments of a given key obviously returns 0 if there aren't */ +extern gint ex_opt_count(const gchar* key); + +/* fetches the nth argument of a given key returns NULL if there isn't */ +extern const gchar* ex_opt_get_index(const gchar* key, guint index); + +/* extracts the next value of a given key */ +extern const gchar* ex_opt_get_next(const gchar* key); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/except.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/except.h new file mode 100644 index 00000000..42e62ce5 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/except.h @@ -0,0 +1,158 @@ +/* + * Portable Exception Handling for ANSI C. + * Copyright (C) 1999 Kaz Kylheku + * + * Free Software License: + * + * All rights are reserved by the author, with the following exceptions: + * Permission is granted to freely reproduce and distribute this software, + * possibly in exchange for a fee, provided that this copyright notice appears + * intact. Permission is also granted to adapt this software to produce + * derivative works, as long as the modified versions carry this copyright + * notice and additional notices stating that the work has been modified. + * This source code may be translated into executable form and incorporated + * into proprietary software; there is no requirement for such software to + * contain a copyright notice related to this source. + * + * $Id: except.h 3992 2008-06-10 03:13:11Z dgu $ + * $Name: $ + */ + +/* + * Modified to support throwing an exception with a null message pointer, + * and to have the message not be const (as we generate messages with + * "g_strdup_sprintf()", which means they need to be freed; using + * a null message means that we don't have to use a special string + * for exceptions with no message, and don't have to worry about + * not freeing that). + */ + +#ifndef XCEPT_H +#define XCEPT_H + +#include +#include +#include + +#define XCEPT_GROUP_ANY 0 +#define XCEPT_CODE_ANY 0 +#define XCEPT_BAD_ALLOC 1 + +#ifdef __cplusplus +extern "C" { +#endif + +enum { except_no_call, except_call }; + +typedef struct { + unsigned long except_group; + unsigned long except_code; +} except_id_t; + +typedef struct { + except_id_t volatile except_id; + const char *volatile except_message; + void *volatile except_dyndata; +} except_t; + +struct except_cleanup { + void (*except_func)(void *); + void *except_context; +}; + +struct except_catch { + const except_id_t *except_id; + size_t except_size; + except_t except_obj; + jmp_buf except_jmp; +}; + +enum except_stacktype { + XCEPT_CLEANUP, XCEPT_CATCHER +}; + +struct except_stacknode { + struct except_stacknode *except_down; + enum except_stacktype except_type; + union { + struct except_catch *except_catcher; + struct except_cleanup *except_cleanup; + } except_info; +}; + +/* private functions made external so they can be used in macros */ +extern void except_setup_clean(struct except_stacknode *, + struct except_cleanup *, void (*)(void *), void *); +extern void except_setup_try(struct except_stacknode *, + struct except_catch *, const except_id_t [], size_t); +extern struct except_stacknode *except_pop(void); + +/* public interface functions */ +extern int except_init(void); +extern void except_deinit(void); +extern void except_rethrow(except_t *); +extern void except_throw(long, long, const char *); +extern void except_throwd(long, long, const char *, void *); +extern void except_throwf(long, long, const char *, ...); +extern void (*except_unhandled_catcher(void (*)(except_t *)))(except_t *); +extern unsigned long except_code(except_t *); +extern unsigned long except_group(except_t *); +extern const char *except_message(except_t *); +extern void *except_data(except_t *); +extern void *except_take_data(except_t *); +extern void except_set_allocator(void *(*)(size_t), void (*)(void *)); +extern void *except_alloc(size_t); +extern void except_free(void *); + +#define except_code(E) ((E)->except_id.except_code) +#define except_group(E) ((E)->except_id.except_group) +#define except_message(E) ((E)->except_message) +#define except_data(E) ((E)->except_dyndata) + +#ifdef __cplusplus +} +#endif + +/* + * void except_cleanup_push(void (*)(void *), void *); + * void except_cleanup_pop(int); + * void except_checked_cleanup_pop(void (*)(void *), int); + * void except_try_push(const except_id_t [], size_t, except_t **); + * void except_try_pop(void); + */ + +#define except_cleanup_push(F, C) \ + { \ + struct except_stacknode except_sn; \ + struct except_cleanup except_cl; \ + except_setup_clean(&except_sn, &except_cl, F, C) + +#define except_cleanup_pop(E) \ + except_pop(); \ + if (E) \ + except_cl.except_func(except_cl.except_context); \ + } + +#define except_checked_cleanup_pop(F, E) \ + except_pop(); \ + assert (except_cl.except_func == (F)); \ + if (E) \ + except_cl.except_func(except_cl.except_context); \ + } + +#define except_try_push(ID, NUM, PPE) \ + { \ + struct except_stacknode except_sn; \ + struct except_catch except_ch; \ + except_setup_try(&except_sn, &except_ch, ID, NUM); \ + if (setjmp(except_ch.except_jmp)) \ + *(PPE) = &except_ch.except_obj; \ + else \ + *(PPE) = 0 + +#define except_try_pop() \ + except_free(except_ch.except_obj.except_dyndata); \ + except_pop(); \ + } + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/exceptions.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/exceptions.h new file mode 100644 index 00000000..52abdfd7 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/exceptions.h @@ -0,0 +1,319 @@ +#ifndef __EXCEPTIONS_H__ +#define __EXCEPTIONS_H__ + +/* $Id $ */ + +#ifndef XCEPT_H +#include "except.h" +#endif + +/* Wireshark has only one exception group, to make these macros simple */ +#define XCEPT_GROUP_WIRESHARK 1 + +/* Wireshark's exceptions */ + +/** + Index is out of range. + An attempt was made to read past the end of a buffer. + This generally means that the capture was done with a "slice" + length or "snapshot" length less than the maximum packet size, + and a link-layer packet was cut short by that, so not all of the + data in the link-layer packet was available. +**/ +#define BoundsError 1 + +/** + Index is beyond reported length (not cap_len) + An attempt was made to read past the logical end of a buffer. This + differs from a BoundsError in that the parent protocol established a + limit past which this dissector should not process in the buffer and that + limit was execeeded. + This generally means that the packet is invalid, i.e. whatever + code constructed the packet and put it on the wire didn't put enough + data into it. It is therefore currently reported as a "Malformed + packet". + However, it also happens in some cases where the packet was fragmented + and the fragments weren't reassembled. We need to add another length + field to a tvbuff, so that "length of the packet from the link layer" + and "length of the packet were it fully reassembled" are different, + and going past the first of those without going past the second would + throw a different exception, which would be reported as an "Unreassembled + packet" rather than a "Malformed packet". +**/ +#define ReportedBoundsError 2 + +/** + During dfilter parsing +**/ +#define TypeError 3 + +/** + A bug was detected in a dissector. + + DO NOT throw this with THROW(); that means that no details about + the dissector error will be reported. (Instead, the message will + blame you for not providing details.) + + Instead, use the DISSECTOR_ASSERT(), etc. macros in epan/proto.h. +**/ +#define DissectorError 4 + +/** + Index is out of range. + An attempt was made to read past the end of a buffer. + This error is specific to SCSI data transfers where for some CDBs + it is normal that the data PDU might be short. + I.e. ReportLuns initially called with allocation_length=8, just enough + to get the "size" of lun list back after which the initiator will + reissue the command with an allocation_length that is big enough. +**/ +#define ScsiBoundsError 5 + +/** + Running out of memory. + A dissector tried to allocate memory but that failed. +**/ +#define OutOfMemoryError 6 + + +/* Usage: + * + * TRY { + * code; + * } + * + * CATCH(exception) { + * code; + * } + * + * CATCH2(exception1, exception2) { + * code; + * } + * + * CATCH_ALL { + * code; + * } + * + * FINALLY { + * code; + * } + * + * ENDTRY; + * + * ********* Never use 'goto' or 'return' inside the TRY, CATCH, CATCH_ALL, + * ********* or FINALLY blocks. Execution must proceed through ENDTRY before + * ********* branching out. + * + * This is really something like: + * + * { + * caught = FALSE: + * x = setjmp(); + * if (x == 0) { + * + * } + * if (!caught && x == 1) { + * caught = TRUE; + * + * } + * if (!caught && x == 2) { + * caught = TRUE; + * + * } + * if (!caught && (x == 3 || x == 4)) { + * caught = TRUE; + * + * } + * if (!caught && x != 0) { + * caught = TRUE; + * + * } + * + * if(!caught) { + * RETHROW(x) + * } + * } + * + * All CATCH's must precede a CATCH_ALL. + * FINALLY must occur after any CATCH or CATCH_ALL. + * ENDTRY marks the end of the TRY code. + * TRY and ENDTRY are the mandatory parts of a TRY block. + * CATCH, CATCH_ALL, and FINALLY are all optional (although + * you'll probably use at least one, otherwise why "TRY"?) + * + * GET_MESSAGE returns string ptr to exception message + * when exception is thrown via THROW_MESSAGE() + * + * To throw/raise an exception. + * + * THROW(exception) + * RETHROW rethrow the caught exception + * + * A cleanup callback is a function called in case an exception occurs + * and is not caught. It should be used to free any dynamically-allocated data. + * A pop or call_and_pop should occur at the same statement-nesting level + * as the push. + * + * CLEANUP_CB_PUSH(func, data) + * CLEANUP_CB_POP + * CLEANUP_CB_CALL_AND_POP + */ + +/* we do up to three passes through the bit of code after except_try_push(), + * and except_state is used to keep track of where we are. + */ +#define EXCEPT_CAUGHT 1 /* exception has been caught, no need to rethrow at + * END_TRY */ + +#define EXCEPT_RETHROWN 2 /* the exception was rethrown from a CATCH + * block. Don't reenter the CATCH blocks, but do + * execute FINALLY and rethrow at END_TRY */ + +#define EXCEPT_FINALLY 4 /* we've entered the FINALLY block - don't allow + * RETHROW, and don't reenter FINALLY if a + * different exception is thrown */ + +#define TRY \ +{\ + except_t *exc; \ + volatile int except_state = 0; \ + static const except_id_t catch_spec[] = { \ + { XCEPT_GROUP_WIRESHARK, XCEPT_CODE_ANY } }; \ + except_try_push(catch_spec, 1, &exc); \ + \ + if(except_state & EXCEPT_CAUGHT) \ + except_state |= EXCEPT_RETHROWN; \ + except_state &= ~EXCEPT_CAUGHT; \ + \ + if (except_state == 0 && exc == 0) \ + /* user's code goes here */ + +#define ENDTRY \ + /* rethrow the exception if necessary */ \ + if(!(except_state&EXCEPT_CAUGHT) && exc != 0) \ + except_rethrow(exc); \ + except_try_pop();\ +} + +/* the (except_state |= EXCEPT_CAUGHT) in the below is a way of setting + * except_state before the user's code, without disrupting the user's code if + * it's a one-liner. + */ +#define CATCH(x) \ + if (except_state == 0 && exc != 0 && exc->except_id.except_code == (x) && \ + (except_state |= EXCEPT_CAUGHT)) \ + /* user's code goes here */ + +#define CATCH2(x,y) \ + if (except_state == 0 && exc != 0 && \ + (exc->except_id.except_code == (x) || exc->except_id.except_code == (y)) && \ + (except_state|=EXCEPT_CAUGHT)) \ + /* user's code goes here */ + +#define CATCH_ALL \ + if (except_state == 0 && exc != 0 && \ + (except_state|=EXCEPT_CAUGHT)) \ + /* user's code goes here */ + + +#define FINALLY \ + if( !(except_state & EXCEPT_FINALLY) && (except_state|=EXCEPT_FINALLY)) \ + /* user's code goes here */ + +#define THROW(x) \ + except_throw(XCEPT_GROUP_WIRESHARK, (x), NULL) + +#define THROW_MESSAGE(x, y) \ + except_throw(XCEPT_GROUP_WIRESHARK, (x), (y)) + +#define GET_MESSAGE except_message(exc) + +#define RETHROW \ + { \ + /* check we're in a catch block */ \ + g_assert(except_state == EXCEPT_CAUGHT); \ + /* we can't use except_rethrow here, as that pops a catch block \ + * off the stack, and we don't want to do that, because we want to \ + * excecute the FINALLY {} block first. \ + * except_throw doesn't provide an interface to rethrow an existing \ + * exception; however, longjmping back to except_try_push() has the \ + * desired effect. \ + * \ + * Note also that THROW and RETHROW should provide much the same \ + * functionality in terms of which blocks to enter, so any messing \ + * about with except_state in here would indicate that THROW is \ + * doing the wrong thing. \ + */ \ + longjmp(except_ch.except_jmp,1); \ + } + +#define EXCEPT_CODE except_code(exc) + +/* Register cleanup functions in case an exception is thrown and not caught. + * From the Kazlib documentation, with modifications for use with the + * Wireshark-specific macros: + * + * CLEANUP_PUSH(func, arg) + * + * The call to CLEANUP_PUSH shall be matched with a call to + * CLEANUP_CALL_AND_POP or CLEANUP_POP which must occur in the same + * statement block at the same level of nesting. This requirement allows + * an implementation to provide a CLEANUP_PUSH macro which opens up a + * statement block and a CLEANUP_POP which closes the statement block. + * The space for the registered pointers can then be efficiently + * allocated from automatic storage. + * + * The CLEANUP_PUSH macro registers a cleanup handler that will be + * called if an exception subsequently occurs before the matching + * CLEANUP_[CALL_AND_]POP is executed, and is not intercepted and + * handled by a try-catch region that is nested between the two. + * + * The first argument to CLEANUP_PUSH is a pointer to the cleanup + * handler, a function that returns nothing and takes a single + * argument of type void*. The second argument is a void* value that + * is registered along with the handler. This value is what is passed + * to the registered handler, should it be called. + * + * Cleanup handlers are called in the reverse order of their nesting: + * inner handlers are called before outer handlers. + * + * The program shall not leave the cleanup region between + * the call to the macro CLEANUP_PUSH and the matching call to + * CLEANUP_[CALL_AND_]POP by means other than throwing an exception, + * or calling CLEANUP_[CALL_AND_]POP. + * + * Within the call to the cleanup handler, it is possible that new + * exceptions may happen. Such exceptions must be handled before the + * cleanup handler terminates. If the call to the cleanup handler is + * terminated by an exception, the behavior is undefined. The exception + * which triggered the cleanup is not yet caught; thus the program + * would be effectively trying to replace an exception with one that + * isn't in a well-defined state. + * + * + * CLEANUP_POP and CLEANUP_CALL_AND_POP + * + * A call to the CLEANUP_POP or CLEANUP_CALL_AND_POP macro shall match + * each call to CLEANUP_PUSH which shall be in the same statement block + * at the same nesting level. It shall match the most recent such a + * call that is not matched by a previous CLEANUP_[CALL_AND_]POP at + * the same level. + * + * These macros causes the registered cleanup handler to be removed. If + * CLEANUP_CALL_AND_POP is called, the cleanup handler is called. + * In that case, the registered context pointer is passed to the cleanup + * handler. If CLEANUP_POP is called, the cleanup handler is not called. + * + * The program shall not leave the region between the call to the + * macro CLEANUP_PUSH and the matching call to CLEANUP_[CALL_AND_]POP + * other than by throwing an exception, or by executing the + * CLEANUP_CALL_AND_POP. + * + */ + + +#define CLEANUP_PUSH(f,a) except_cleanup_push((f),(a)) +#define CLEANUP_POP except_cleanup_pop(0) +#define CLEANUP_CALL_AND_POP except_cleanup_pop(1) + +#endif /* __EXCEPTIONS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/expert.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/expert.h new file mode 100644 index 00000000..3c32f25e --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/expert.h @@ -0,0 +1,70 @@ +/* expert.h + * Collecting of Expert information. + * + * For further info, see: http://wiki.wireshark.org/Development/ExpertInfo + * + * $Id: expert.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __EXPERT_H__ +#define __EXPERT_H__ + +#include "gnuc_format_check.h" +#include +#include "value_string.h" + + +/** only for internal and display use */ +typedef struct expert_info_s { + guint32 packet_num; + int group; + int severity; + gchar * protocol; + gchar * summary; + proto_item *pitem; +} expert_info_t; + +WS_VAR_IMPORT const value_string expert_severity_vals[]; +WS_VAR_IMPORT const value_string expert_group_vals[]; + +extern void +expert_init(void); + +extern void +expert_cleanup(void); + +extern int +expert_get_highest_severity(void); + +/** Add an expert info. + + @param pinfo packet info of the currently processed packet + @param pi current protocol item (or NULL) + @param group the expert group (like PI_CHECKSUM) + @param severity the expert severity (like PI_WARN) + @param format printf like format string with further infos + */ +extern void +expert_add_info_format(packet_info *pinfo, proto_item *pi, int group, + int severity, const char *format, ...) + GNUC_FORMAT_CHECK(printf, 5, 6); + +#endif /* __EXPERT_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/filesystem.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/filesystem.h new file mode 100644 index 00000000..5b9c9fa2 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/filesystem.h @@ -0,0 +1,248 @@ +/* filesystem.h + * Filesystem utility definitions + * + * $Id: filesystem.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef FILESYSTEM_H +#define FILESYSTEM_H + +/* + * Default profile name. + */ +#define DEFAULT_PROFILE "Default" + + +/* + * Get the pathname of the directory from which the executable came, + * and save it for future use. Returns NULL on success, and a + * g_mallocated string containing an error on failure. + */ +extern char *init_progfile_dir(const char *arg0); + +/* + * Get the directory in which the program resides. + */ +extern const char *get_progfile_dir(void); + +/* + * Get the directory in which plugins are stored; this must not be called + * before init_progfile_dir() is called, as they might be stored in a + * subdirectory of the program file directory. + */ +extern const char *get_plugin_dir(void); + +/* + * Get the flag indicating whether we're running from a build + * directory. + */ +extern gboolean running_in_build_directory(void); + +/* + * Get the directory in which global configuration files are + * stored. + */ +extern const char *get_datafile_dir(void); + +/* + * Construct the path name of a global configuration file, given the + * file name. + * + * The returned file name was g_malloc()'d so it must be g_free()d when the + * caller is done with it. + */ +extern char *get_datafile_path(const char *filename); + +/* + * Get the directory in which files that, at least on UNIX, are + * system files (such as "/etc/ethers") are stored; on Windows, + * there's no "/etc" directory, so we get them from the Wireshark + * global configuration and data file directory. + */ +extern const char *get_systemfile_dir(void); + +/* + * Set the configuration profile name to be used for storing + * personal configuration files. + */ +extern void set_profile_name(const gchar *profilename); + +/* + * Get the current configuration profile name used for storing + * personal configuration files. + */ +extern const char *get_profile_name(void); + +/* + * Get the directory used to store configuration profile directories. + */ +extern const char *get_profiles_dir(void); + +/* + * Check if given configuration profile exists. + */ +extern gboolean profile_exists(const gchar *profilename); + +/* + * Create a directory for the given configuration profile. + * If we attempted to create it, and failed, return -1 and + * set "*pf_dir_path_return" to the pathname of the directory we failed + * to create (it's g_mallocated, so our caller should free it); otherwise, + * return 0. + */ +extern int create_persconffile_profile(const char *profilename, + char **pf_dir_path_return); + +/* + * Delete the directory for the given configuration profile. + * If we attempted to delete it, and failed, return -1 and + * set "*pf_dir_path_return" to the pathname of the directory we failed + * to delete (it's g_mallocated, so our caller should free it); otherwise, + * return 0. + */ +extern int delete_persconffile_profile(const char *profilename, + char **pf_dir_path_return); + +/* + * Rename the directory for the given confinguration profile. + */ +extern int rename_persconffile_profile(const char *fromname, const char *toname, + char **pf_from_dir_path_return, + char **pf_to_dir_path_return); + +/* + * Create the directory that holds personal configuration files, if + * necessary. If we attempted to create it, and failed, return -1 and + * set "*pf_dir_path_return" to the pathname of the directory we failed + * to create (it's g_mallocated, so our caller should free it); otherwise, + * return 0. + */ +extern int create_persconffile_dir(char **pf_dir_path_return); + +/* + * Construct the path name of a personal configuration file, given the + * file name. If using configuration profiles this directory will be + * used if "from_profile" is TRUE. + * + * On Win32, if "for_writing" is FALSE, we check whether the file exists + * and, if not, construct a path name relative to the ".wireshark" + * subdirectory of the user's home directory, and check whether that + * exists; if it does, we return that, so that configuration files + * from earlier versions can be read. + * + * The returned file name was g_malloc()'d so it must be g_free()d when the + * caller is done with it. + */ +extern char *get_persconffile_path(const char *filename, gboolean from_profile, + gboolean for_writing); + +/* + * Get the (default) directory in which personal data is stored. + * + * On Win32, this is the "My Documents" folder in the personal profile. + * On UNIX this is simply the current directory. + */ +extern char *get_persdatafile_dir(void); + +/* + * Construct the path name of a file in $TMP/%TEMP% directory. + * Or "/tmp/" (C:\) if that fails. + * + * Return value is malloced so the caller should free it. + */ +extern char *get_tempfile_path(const char *filename); + +/* + * process command line option belonging to the filesystem settings + */ +extern int filesystem_opt(int opt, const char *optarg); + +/* + * Return an error message for UNIX-style errno indications on open or + * create operations. + */ +extern const char *file_open_error_message(int err, gboolean for_writing); + +/* + * Return an error message for UNIX-style errno indications on write + * operations. + */ +extern const char *file_write_error_message(int err); + +/* + * Given a pathname, return the last component. + */ +extern const char *get_basename(const char *); + +/* + * Given a pathname, return a string containing everything but the + * last component. NOTE: this overwrites the pathname handed into + * it.... + */ +extern char *get_dirname(char *); + +/* + * Given a pathname, return: + * + * the errno, if an attempt to "stat()" the file fails; + * + * EISDIR, if the attempt succeeded and the file turned out + * to be a directory; + * + * 0, if the attempt succeeded and the file turned out not + * to be a directory. + */ +extern int test_for_directory(const char *); + +/* + * Given a pathname, return: + * + * the errno, if an attempt to "stat()" the file fails; + * + * ESPIPE, if the attempt succeeded and the file turned out + * to be a FIFO; + * + * 0, if the attempt succeeded and the file turned out not + * to be a FIFO. + */ +extern int test_for_fifo(const char *); + +/* Delete a file */ +extern gboolean deletefile (const char *path); + +/* + * Check, if file is existing. + */ +extern gboolean file_exists(const char *fname); + +/* + * Check, if two filenames are identical (with absolute and relative paths). + */ +extern gboolean files_identical(const char *fname1, const char *fname2); + +#ifdef WIN32 +/* + * utf8 version of getenv, needed to get win32 filename paths + */ +extern char *getenv_utf8(const char *varname); +#endif + +#endif /* FILESYSTEM_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/follow.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/follow.h new file mode 100644 index 00000000..513e7add --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/follow.h @@ -0,0 +1,58 @@ +/* follow.h + * + * $Id: follow.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Copyright 1998 Mike Hall + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __FOLLOW_H__ +#define __FOLLOW_H__ + +#include + +#define MAX_IPADDR_LEN 16 + +/* With MSVC and a libwireshark.dll, we need a special declaration. */ +WS_VAR_IMPORT gboolean empty_tcp_stream; +WS_VAR_IMPORT gboolean incomplete_tcp_stream; + +typedef struct _tcp_stream_chunk { + guint8 src_addr[MAX_IPADDR_LEN]; + guint16 src_port; + guint32 dlen; +} tcp_stream_chunk; + +char* build_follow_filter( packet_info * ); +void reassemble_tcp( gulong, gulong, gulong, const char*, gulong, int, + address *, address *, guint, guint ); +void reset_tcp_reassembly( void ); + +typedef struct { + guint8 ip_address[2][MAX_IPADDR_LEN]; + guint32 port[2]; + unsigned int bytes_written[2]; + gboolean is_ipv6; +} follow_stats_t; + +void follow_stats(follow_stats_t* stats); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/frame_data.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/frame_data.h new file mode 100644 index 00000000..15d0d021 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/frame_data.h @@ -0,0 +1,79 @@ +/* frame_data.h + * Definitions for frame_data structures and routines + * + * $Id: frame_data.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __FRAME_DATA_H__ +#define __FRAME_DATA_H__ + +#include "column_info.h" +#include "tvbuff.h" +#include + + +/* XXX - some of this stuff is used only while a packet is being dissected; + should we keep that stuff in the "packet_info" structure, instead, to + save memory? */ +/* The frame number is the ordinal number of the frame in the capture, so + it's 1-origin. In various contexts, 0 as a frame number means "frame + number unknown". */ +typedef struct _frame_data { + struct _frame_data *next; /* Next element in list */ + struct _frame_data *prev; /* Previous element in list */ + GSList *pfd; /* Per frame proto data */ + guint32 num; /* Frame number */ + guint32 pkt_len; /* Packet length */ + guint32 cap_len; /* Amount actually captured */ + guint32 cum_bytes; /* Cumulative bytes into the capture */ + nstime_t abs_ts; /* Absolute timestamp */ + nstime_t rel_ts; /* Relative timestamp (yes, it can be negative) */ + nstime_t del_dis_ts; /* Delta timestamp to previous displayed frame (yes, it can be negative) */ + nstime_t del_cap_ts; /* Delta timestamp to previous captured frame (yes, it can be negative) */ + gint64 file_off; /* File offset */ + int lnk_t; /* Per-packet encapsulation/data-link type */ + struct { + unsigned int passed_dfilter : 1; /* 1 = display, 0 = no display */ + unsigned int encoding : 2; /* Character encoding (ASCII, EBCDIC...) */ + unsigned int visited : 1; /* Has this packet been visited yet? 1=Yes,0=No*/ + unsigned int marked : 1; /* 1 = marked by user, 0 = normal */ + unsigned int ref_time : 1; /* 1 = marked as a reference time frame, 0 = normal */ + } flags; + void *color_filter; /* Per-packet matching color_filter_t object */ + col_expr_t col_expr; /* Column expressions & values */ +} frame_data; + +/* + * A data source. + * Has a tvbuff and a name. + */ +typedef struct { + tvbuff_t *tvb; + char *name; +} data_source; + +/* Utility routines used by packet*.c */ + +extern void p_add_proto_data(frame_data *fd, int proto, void *proto_data); +extern void *p_get_proto_data(frame_data *fd, int proto); +extern void p_remove_proto_data(frame_data *fd, int proto); + +#endif /* __FRAME_DATA__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/frequency-utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/frequency-utils.h new file mode 100644 index 00000000..628bff4d --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/frequency-utils.h @@ -0,0 +1,74 @@ +/* frequency-utils.h + * Frequency conversion utility definitions + * + * $Id: frequency-utils.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2007 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __FREQUENCY_UTILS_H__ +#define __FREQUENCY_UTILS_H__ + +/** @file + * Frequency and channel conversion utilities. + */ + +/** + * Given a center frequency in MHz, return a channel number. + * @param freq Frequency in MHz. + * @return The equivalent channel or -1 if no match is found. + */ +gint +ieee80211_mhz_to_chan(guint freq); + +/** + * Given a channel number and a band type, return a center frequency. + * @param chan Channel number + * @param is_bg TRUE if the channel is a b/g channel, FALSE otherwise. + * @return The equivalent frequency or 0 if no match is found. + */ +guint +ieee80211_chan_to_mhz(gint chan, gboolean is_bg); + +/** + * Given a frequency in MHz, return a string representation. + * @param freq Frequench in MHz. + * @return A string showing the frequency, channel number, and type. The string must be freed with g_free() after use. + */ +gchar* +ieee80211_mhz_to_str(guint freq); + +/* Should this be "(freq < 4920)", or something else? */ +#define FREQ_IS_BG(freq) (freq <= 2484) + +/* + * Editor modelines + * + * Local Variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * ex: set shiftwidth=4 tabstop=8 expandtab + * :indentSize=4:tabSize=8:noTabs=true: + */ + +#endif /* __FREQUENCY_UTILS_H__ */ + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ftypes/ftypes-int.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ftypes/ftypes-int.h new file mode 100644 index 00000000..20528f66 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ftypes/ftypes-int.h @@ -0,0 +1,61 @@ +/* + * $Id: ftypes-int.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2001 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef FTYPES_INT_H +#define FTYPES_INT_H + +#include +#include "ftypes.h" + +#ifdef HAVE_LIBPCRE +#include +#endif /* HAVE_LIBPCRE */ + + +#ifdef HAVE_LIBPCRE +struct _pcre_tuple_t { + char *string; + pcre *re; + pcre_extra *ex; + char *error; +}; +#endif /* HAVE_LIBPCRE */ + +void +ftype_register(enum ftenum ftype, ftype_t *ft); + +/* These are the ftype registration functions that need to be called. + * This list and the initialization function could be produced + * via a script, like the dissector registration, but there's so few + * that I don't mind doing it by hand for now. */ +void ftype_register_bytes(void); +void ftype_register_double(void); +void ftype_register_integers(void); +void ftype_register_ipv4(void); +void ftype_register_guid(void); +void ftype_register_none(void); +void ftype_register_string(void); +void ftype_register_time(void); +void ftype_register_tvbuff(void); +void ftype_register_pcre(void); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ftypes/ftypes.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ftypes/ftypes.h new file mode 100644 index 00000000..498c969c --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ftypes/ftypes.h @@ -0,0 +1,367 @@ +/* ftypes.h + * Definitions for field types + * + * $Id: ftypes.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2001 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +#ifndef FTYPES_H +#define FTYPES_H + +#include +#include "../slab.h" + +/* field types */ +enum ftenum { + FT_NONE, /* used for text labels with no value */ + FT_PROTOCOL, + FT_BOOLEAN, /* TRUE and FALSE come from */ + FT_UINT8, + FT_UINT16, + FT_UINT24, /* really a UINT32, but displayed as 3 hex-digits if FD_HEX*/ + FT_UINT32, + FT_UINT64, + FT_INT8, + FT_INT16, + FT_INT24, /* same as for UINT24 */ + FT_INT32, + FT_INT64, + FT_FLOAT, + FT_DOUBLE, + FT_ABSOLUTE_TIME, + FT_RELATIVE_TIME, + FT_STRING, + FT_STRINGZ, /* for use with proto_tree_add_item() */ + FT_EBCDIC, /* for use with proto_tree_add_item() */ + FT_UINT_STRING, /* for use with proto_tree_add_item() */ + /*FT_UCS2_LE, */ /* Unicode, 2 byte, Little Endian */ + FT_ETHER, + FT_BYTES, + FT_UINT_BYTES, + FT_IPv4, + FT_IPv6, + FT_IPXNET, + FT_FRAMENUM, /* a UINT32, but if selected lets you go to frame with that numbe */ + FT_PCRE, /* a compiled Perl-Compatible Regular Expression object */ + FT_GUID, /* GUID, UUID */ + FT_OID, /* OBJECT IDENTIFIER */ + FT_NUM_TYPES /* last item number plus one */ +}; + +#define IS_FT_INT(ft) ((ft)==FT_INT8||(ft)==FT_INT16||(ft)==FT_INT24||(ft)==FT_INT32) +#define IS_FT_UINT(ft) ((ft)==FT_UINT8||(ft)==FT_UINT16||(ft)==FT_UINT24||(ft)==FT_UINT32||(ft)==FT_FRAMENUM) +#define IS_FT_TIME(ft) ((ft)==FT_ABSOLUTE_TIME||(ft)==FT_RELATIVE_TIME) +#define IS_FT_STRING(ft) ((ft)==FT_STRING||(ft)==FT_STRINGZ) + +typedef enum ftenum ftenum_t; +typedef struct _ftype_t ftype_t; + +/* String representation types. */ +enum ftrepr { + FTREPR_DISPLAY, + FTREPR_DFILTER +}; + +typedef enum ftrepr ftrepr_t; + +#ifdef HAVE_LIBPCRE +typedef struct _pcre_tuple_t pcre_tuple_t; +#endif /* HAVE_LIBPCRE */ + +/* Initialize the ftypes subsytem. Called once. */ +void +ftypes_initialize(void); + +/* ---------------- FTYPE ----------------- */ + +/* Return a string representing the name of the type */ +const char* +ftype_name(ftenum_t ftype); + +/* Return a string presenting a "pretty" representation of the + * name of the type. The pretty name means more to the user than + * that "FT_*" name. */ +const char* +ftype_pretty_name(ftenum_t ftype); + +/* Returns length of field in packet, or 0 if not determinable/defined. */ +int +ftype_length(ftenum_t ftype); + +gboolean +ftype_can_slice(enum ftenum ftype); + +gboolean +ftype_can_eq(enum ftenum ftype); + +gboolean +ftype_can_ne(enum ftenum ftype); + +gboolean +ftype_can_gt(enum ftenum ftype); + +gboolean +ftype_can_ge(enum ftenum ftype); + +gboolean +ftype_can_lt(enum ftenum ftype); + +gboolean +ftype_can_le(enum ftenum ftype); + +gboolean +ftype_can_bitwise_and(enum ftenum ftype); + +gboolean +ftype_can_contains(enum ftenum ftype); + +gboolean +ftype_can_matches(enum ftenum ftype); + +/* ---------------- FVALUE ----------------- */ + +#include +#include + +#include +#include +#include + +typedef struct _fvalue_t { + ftype_t *ftype; + union { + /* Put a few basic types in here */ + gpointer pointer; + guint32 uinteger; + gint32 sinteger; + guint64 integer64; + gdouble floating; + gchar *string; + guchar *ustring; + GByteArray *bytes; + GString *gstring; + ipv4_addr ipv4; + e_guid_t guid; + nstime_t time; + tvbuff_t *tvb; +#ifdef HAVE_LIBPCRE + pcre_tuple_t *re; +#endif /* HAVE_LIBPCRE */ + } value; + + /* The following is provided for private use + * by the fvalue. */ + gboolean fvalue_gboolean1; + +} fvalue_t; + +typedef void (*FvalueNewFunc)(fvalue_t*); +typedef void (*FvalueFreeFunc)(fvalue_t*); +typedef void (*LogFunc)(const char*,...); + +typedef gboolean (*FvalueFromUnparsed)(fvalue_t*, char*, gboolean, LogFunc); +typedef gboolean (*FvalueFromString)(fvalue_t*, char*, LogFunc); +typedef void (*FvalueToStringRepr)(fvalue_t*, ftrepr_t, char*); +typedef int (*FvalueStringReprLen)(fvalue_t*, ftrepr_t); + +typedef void (*FvalueSetFunc)(fvalue_t*, gpointer, gboolean); +typedef void (*FvalueSetUnsignedIntegerFunc)(fvalue_t*, guint32); +typedef void (*FvalueSetSignedIntegerFunc)(fvalue_t*, gint32); +typedef void (*FvalueSetInteger64Func)(fvalue_t*, guint64); +typedef void (*FvalueSetFloatingFunc)(fvalue_t*, gdouble); + +typedef gpointer (*FvalueGetFunc)(fvalue_t*); +typedef guint32 (*FvalueGetUnsignedIntegerFunc)(fvalue_t*); +typedef gint32 (*FvalueGetSignedIntegerFunc)(fvalue_t*); +typedef guint64 (*FvalueGetInteger64Func)(fvalue_t*); +typedef double (*FvalueGetFloatingFunc)(fvalue_t*); + +typedef gboolean (*FvalueCmp)(fvalue_t*, fvalue_t*); + +typedef guint (*FvalueLen)(fvalue_t*); +typedef void (*FvalueSlice)(fvalue_t*, GByteArray *, guint offset, guint length); + +struct _ftype_t { + ftenum_t ftype; + const char *name; + const char *pretty_name; + int wire_size; + FvalueNewFunc new_value; + FvalueFreeFunc free_value; + FvalueFromUnparsed val_from_unparsed; + FvalueFromString val_from_string; + FvalueToStringRepr val_to_string_repr; + FvalueStringReprLen len_string_repr; + + /* could be union */ + FvalueSetFunc set_value; + FvalueSetUnsignedIntegerFunc set_value_uinteger; + FvalueSetSignedIntegerFunc set_value_sinteger; + FvalueSetInteger64Func set_value_integer64; + FvalueSetFloatingFunc set_value_floating; + + /* could be union */ + FvalueGetFunc get_value; + FvalueGetUnsignedIntegerFunc get_value_uinteger; + FvalueGetSignedIntegerFunc get_value_sinteger; + FvalueGetInteger64Func get_value_integer64; + FvalueGetFloatingFunc get_value_floating; + + FvalueCmp cmp_eq; + FvalueCmp cmp_ne; + FvalueCmp cmp_gt; + FvalueCmp cmp_ge; + FvalueCmp cmp_lt; + FvalueCmp cmp_le; + FvalueCmp cmp_bitwise_and; + FvalueCmp cmp_contains; + FvalueCmp cmp_matches; + + FvalueLen len; + FvalueSlice slice; +}; + + +fvalue_t* +fvalue_new(ftenum_t ftype); + +void +fvalue_init(fvalue_t *fv, ftenum_t ftype); + + +/* Define type needed for the fvalue_t free list. */ +SLAB_ITEM_TYPE_DEFINE(fvalue_t) + +/* Free all memory used by an fvalue_t. With MSVC and a + * libwireshark.dll, we need a special declaration. + */ +WS_VAR_IMPORT SLAB_FREE_LIST_DECLARE(fvalue_t) + + +#define FVALUE_CLEANUP(fv) \ + { \ + register FvalueFreeFunc free_value; \ + free_value = (fv)->ftype->free_value; \ + if (free_value) { \ + free_value((fv)); \ + } \ + } + +#define FVALUE_FREE(fv) \ + { \ + FVALUE_CLEANUP(fv) \ + SLAB_FREE(fv, fvalue_t); \ + } + + +fvalue_t* +fvalue_from_unparsed(ftenum_t ftype, char *s, gboolean allow_partial_value, LogFunc logfunc); + +fvalue_t* +fvalue_from_string(ftenum_t ftype, char *s, LogFunc logfunc); + +/* Returns the length of the string required to hold the + * string representation of the the field value. + * The length DOES NOT include the terminating NUL. */ +int +fvalue_string_repr_len(fvalue_t *fv, ftrepr_t rtype); + +/* Creates the string representation of the field value. + * If given non-NULL 'buf', the string is written at the memory + * location pointed to by 'buf'. If 'buf' is NULL, new memory + * is malloc'ed and the string representation is written there. + * The pointer to the beginning of the string representation is + * returned. If 'buf' was NULL, this points to the newly-allocated + * memory. if 'buf' was non-NULL, then the return value will be + * 'buf'. */ +extern char * +fvalue_to_string_repr(fvalue_t *fv, ftrepr_t rtype, char *buf); + +ftype_t* +fvalue_ftype(fvalue_t *fv); + +const char* +fvalue_type_name(fvalue_t *fv); + +void +fvalue_set(fvalue_t *fv, gpointer value, gboolean already_copied); + +void +fvalue_set_uinteger(fvalue_t *fv, guint32 value); + +void +fvalue_set_sinteger(fvalue_t *fv, gint32 value); + +void +fvalue_set_integer64(fvalue_t *fv, guint64 value); + +void +fvalue_set_floating(fvalue_t *fv, gdouble value); + +gpointer +fvalue_get(fvalue_t *fv); + +extern guint32 +fvalue_get_uinteger(fvalue_t *fv); + +extern gint32 +fvalue_get_sinteger(fvalue_t *fv); + +guint64 +fvalue_get_integer64(fvalue_t *fv); + +extern double +fvalue_get_floating(fvalue_t *fv); + +gboolean +fvalue_eq(fvalue_t *a, fvalue_t *b); + +gboolean +fvalue_ne(fvalue_t *a, fvalue_t *b); + +gboolean +fvalue_gt(fvalue_t *a, fvalue_t *b); + +gboolean +fvalue_ge(fvalue_t *a, fvalue_t *b); + +gboolean +fvalue_lt(fvalue_t *a, fvalue_t *b); + +gboolean +fvalue_le(fvalue_t *a, fvalue_t *b); + +gboolean +fvalue_bitwise_and(fvalue_t *a, fvalue_t *b); + +gboolean +fvalue_contains(fvalue_t *a, fvalue_t *b); + +gboolean +fvalue_matches(fvalue_t *a, fvalue_t *b); + +guint +fvalue_length(fvalue_t *fv); + +fvalue_t* +fvalue_slice(fvalue_t *fv, drange *dr); + +#endif /* ftypes.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/funnel.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/funnel.h new file mode 100644 index 00000000..a162e100 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/funnel.h @@ -0,0 +1,116 @@ +/* + * funnel.h + * + * EPAN's GUI mini-API + * + * (c) 2006, Luis E. Garcia Ontanon + * + * $Id: funnel.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef _FUNNEL_H +#define _FUNNEL_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "../stat_menu.h" + +typedef struct _funnel_text_window_t funnel_text_window_t ; +typedef struct _funnel_tree_window_t funnel_tree_window_t ; +typedef struct _funnel_node_t funnel_node_t ; + +typedef void (*text_win_close_cb_t)(void*); + +typedef void (*funnel_dlg_cb_t)(gchar** user_input, void* data); + +typedef gboolean (*funnel_bt_cb_t)(funnel_text_window_t* tw, void* data); + +typedef struct _funnel_bt_t { + funnel_text_window_t* tw; + funnel_bt_cb_t func; + void* data; + void (*free)(void*); + void (*free_data)(void*); +} funnel_bt_t; + +typedef struct _funnel_ops_t { + funnel_text_window_t* (*new_text_window)(const gchar* label); + void (*set_text)(funnel_text_window_t* win, const gchar* text); + void (*append_text)(funnel_text_window_t* win, const gchar* text); + void (*prepend_text)(funnel_text_window_t* win, const gchar* text); + void (*clear_text)(funnel_text_window_t* win); + const gchar* (*get_text)(funnel_text_window_t* win); + void (*set_close_cb)(funnel_text_window_t* win, text_win_close_cb_t cb, void* data); + void (*set_editable)(funnel_text_window_t* win, gboolean editable); + void (*destroy_text_window)(funnel_text_window_t* win); + void (*add_button)(funnel_text_window_t* win, funnel_bt_t* cb, const gchar* label); + + + + void (*new_dialog)(const gchar* title, + const gchar** fieldnames, + funnel_dlg_cb_t dlg_cb, + void* data); + + + void (*logger)(const gchar *log_domain, + GLogLevelFlags log_level, + const gchar *message, + gpointer user_data); + + + void (*retap_packets)(void); + void (*copy_to_clipboard)(GString *str); + void (*set_filter)(const char*); + gboolean (*open_file)(const char* fname, const char* filter, const char** error); + void (*reload)(void); + void (*apply_filter)(void); + gboolean (*browser_open_url)(const gchar *url); + void (*browser_open_data_file)(const gchar *filename); +} funnel_ops_t; + + +extern const funnel_ops_t* funnel_get_funnel_ops(void); +extern void funnel_set_funnel_ops(const funnel_ops_t*); + + +extern void funnel_register_menu(const char *name, + register_stat_group_t group, + void (*callback)(gpointer), + gpointer callback_data, + gboolean retap); + + +typedef void (*funnel_registration_cb_t)(const char *name, + register_stat_group_t group, + void (*callback)(gpointer), + gpointer callback_data, + gboolean retap); + +extern void funnel_register_all_menus(funnel_registration_cb_t r_cb); + +extern void initialize_funnel_ops(void); + +extern void funnel_dump_all_text_windows(void); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/g_ascii_strcasecmp.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/g_ascii_strcasecmp.h new file mode 100644 index 00000000..aef486b2 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/g_ascii_strcasecmp.h @@ -0,0 +1,18 @@ +/* + * $Id: g_ascii_strcasecmp.h 3992 2008-06-10 03:13:11Z dgu $ + * + * "g_ascii_strcasecmp()" and "g_ascii_strncasecmp()" extracted from + * GLib 2.4.8, for use with GLibs that don't have it (e.g., GLib 1.2[.x]). + */ + +#ifndef __WIRESHARK_G_ASCII_STRCASECMP_H__ +#define __WIRESHARK_G_ASCII_STRCASECMP_H__ + +extern gint g_ascii_strcasecmp (const gchar *s1, + const gchar *s2); + +extern gint g_ascii_strncasecmp (const gchar *s1, + const gchar *s2, + gsize n); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/g_ascii_strtoull.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/g_ascii_strtoull.h new file mode 100644 index 00000000..d52d6d41 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/g_ascii_strtoull.h @@ -0,0 +1,15 @@ +/* + * $Id: g_ascii_strtoull.h 3992 2008-06-10 03:13:11Z dgu $ + * + * "g_ascii_strtoull()" extracted from GLib 2.4.5, for use with GLibs + * that don't have it (e.g., GLib 1.2[.x]). + */ + +#ifndef __WIRESHARK_G_ASCII_STRTOULL_H__ +#define __WIRESHARK_G_ASCII_STRTOULL_H__ + +extern guint64 g_ascii_strtoull (const gchar *nptr, + gchar **endptr, + guint base); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/garrayfix.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/garrayfix.h new file mode 100644 index 00000000..1d740562 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/garrayfix.h @@ -0,0 +1,38 @@ +/* garrayfix.h + * Macros to work around the "data" field of a GArray having type guint8 *, + * rather than void *, so that, even though the GArray code should be + * ensuring that the data is aligned strictly enough for any data type, + * we still get warnings with -Wcast-align. + * + * $Id: garrayfix.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2007 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __GARRAYFIX_H__ +#define __GARRAYFIX_H__ + +#ifdef g_array_index +#undef g_array_index +#define g_array_index(a,t,i) (((t*) (void*) (a)->data) [(i)]) +#endif + +#define g_array_data(a) ((void*) (a)->data) + +#endif /* __GARRAYFIX_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/gcp.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/gcp.h new file mode 100644 index 00000000..8dd8f728 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/gcp.h @@ -0,0 +1,219 @@ +/* gcp.h + * Gateway Control Protocol -- Context Tracking + * + * $Id: gcp.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef __GCP_H_ +#define __GCP_H_ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +typedef struct _gcp_hf_ett_t { + struct { + int ctx; + int ctx_cmd; + int ctx_term; + int ctx_term_type; + int ctx_term_bir; + int ctx_term_nsap; + } hf; + + struct { + gint ctx; + gint ctx_cmds; + gint ctx_terms; + gint ctx_term; + } ett; +} gcp_hf_ett_t; + +#define NULL_CONTEXT 0 +#define CHOOSE_CONTEXT 0xFFFFFFFE +#define ALL_CONTEXTS 0xFFFFFFFF + + +typedef enum { + GCP_CMD_NONE, + GCP_CMD_ADD_REQ, + GCP_CMD_MOVE_REQ, + GCP_CMD_MOD_REQ, + GCP_CMD_SUB_REQ, + GCP_CMD_AUDITCAP_REQ, + GCP_CMD_AUDITVAL_REQ, + GCP_CMD_NOTIFY_REQ, + GCP_CMD_SVCCHG_REQ, + GCP_CMD_TOPOLOGY_REQ, + GCP_CMD_CTX_ATTR_AUDIT_REQ, + GCP_CMD_OTHER_REQ, + GCP_CMD_ADD_REPLY, + GCP_CMD_MOVE_REPLY, + GCP_CMD_MOD_REPLY, + GCP_CMD_SUB_REPLY, + GCP_CMD_AUDITCAP_REPLY, + GCP_CMD_AUDITVAL_REPLY, + GCP_CMD_NOTIFY_REPLY, + GCP_CMD_SVCCHG_REPLY, + GCP_CMD_TOPOLOGY_REPLY, + GCP_CMD_REPLY +} gcp_cmd_type_t; + +typedef enum { + GCP_TRX_NONE, + GCP_TRX_REQUEST, + GCP_TRX_PENDING, + GCP_TRX_REPLY, + GCP_TRX_ACK +} gcp_trx_type_t; + + +typedef struct _gcp_msg_t { + guint32 lo_addr; + guint32 hi_addr; + guint32 framenum; + struct _gcp_trx_msg_t* trxs; + gboolean commited; +} gcp_msg_t; + +typedef struct _gcp_trx_msg_t { + struct _gcp_trx_t* trx; + struct _gcp_trx_msg_t* next; + struct _gcp_trx_msg_t* last; +} gcp_trx_msg_t; + +typedef struct _gcp_cmd_msg_t { + struct _gcp_cmd_t* cmd; + struct _gcp_cmd_msg_t* next; + struct _gcp_cmd_msg_t* last; +} gcp_cmd_msg_t; + +typedef struct _gcp_trx_t { + gcp_msg_t* initial; + guint32 id; + gcp_trx_type_t type; + guint pendings; + struct _gcp_cmd_msg_t* cmds; + struct _gcp_trx_ctx_t* ctxs; + guint error; +} gcp_trx_t; + +#define GCP_TERM_TYPE_UNKNOWN 0 +#define GCP_TERM_TYPE_AAL1 1 +#define GCP_TERM_TYPE_AAL2 2 +#define GCP_TERM_TYPE_AAL1_STRUCT 3 +#define GCP_TERM_TYPE_IP_RTP 4 +#define GCP_TERM_TYPE_TDM 5 + +typedef enum _gcp_wildcard_t { + GCP_WILDCARD_NONE, + GCP_WILDCARD_CHOOSE, + GCP_WILDCARD_ALL +} gcp_wildcard_t; + +typedef struct _gcp_term_t { + gchar* str; + + guint8* buffer; + guint len; + + guint type; + gchar* bir; + gchar* nsap; + + gcp_msg_t* start; + +} gcp_term_t; + +typedef struct _gcp_terms_t { + gcp_term_t* term; + struct _gcp_terms_t* next; + struct _gcp_terms_t* last; +} gcp_terms_t; + +typedef struct _gcp_cmd_t { + guint offset; + gchar* str; + gcp_cmd_type_t type; + gcp_terms_t terms; + struct _gcp_msg_t* msg; + struct _gcp_trx_t* trx; + struct _gcp_ctx_t* ctx; + guint error; +} gcp_cmd_t; + + +typedef struct _gcp_ctx_t { + gcp_msg_t* initial; + guint32 id; + struct _gcp_cmd_msg_t* cmds; + struct _gcp_ctx_t* prev; + gcp_terms_t terms; +} gcp_ctx_t; + +WS_VAR_IMPORT const value_string gcp_cmd_type[]; +WS_VAR_IMPORT const value_string gcp_term_types[]; + +extern void gcp_init(void); +extern gcp_msg_t* gcp_msg(packet_info* pinfo, int o, gboolean persistent); +extern gcp_trx_t* gcp_trx(gcp_msg_t* m ,guint32 t_id , gcp_trx_type_t type, gboolean persistent); +extern gcp_ctx_t* gcp_ctx(gcp_msg_t* m, gcp_trx_t* t, guint32 c_id, gboolean persistent); +extern gcp_cmd_t* gcp_cmd(gcp_msg_t* m, gcp_trx_t* t, gcp_ctx_t* c, gcp_cmd_type_t type, guint offset, gboolean persistent); +extern gcp_term_t* gcp_cmd_add_term(gcp_msg_t* m, gcp_trx_t* tr, gcp_cmd_t* c, gcp_term_t* t, gcp_wildcard_t wildcard, gboolean persistent); +extern void gcp_analyze_msg(proto_tree* gcp_tree, tvbuff_t* gcp_tvb, gcp_msg_t* m, gcp_hf_ett_t* ids); + +extern gchar* gcp_cmd_to_str(gcp_cmd_t* c, gboolean persistent); +extern gchar* gcp_msg_to_str(gcp_msg_t* m, gboolean persistent); + +#define gcp_cmd_set_error(c,e) (c->error = e) +#define gcp_trx_set_error(t,e) (t->error = e) + +#define GCP_ETT_ARR_ELEMS(gi) &(gi.ett.ctx),&(gi.ett.ctx_cmds),&(gi.ett.ctx_terms),&(gi.ett.ctx_term) + +#define GCP_HF_ARR_ELEMS(n,gi) \ + { &(gi.hf.ctx), { "Context", n ".ctx", FT_UINT32, BASE_HEX, NULL, 0, "", HFILL }}, \ + { &(gi.hf.ctx_term), { "Termination", n ".ctx.term", FT_STRING, BASE_NONE, NULL, 0, "", HFILL }}, \ + { &(gi.hf.ctx_term_type), { "Type", n ".ctx.term.type", FT_UINT32, BASE_HEX, VALS(gcp_term_types), 0, "", HFILL }}, \ + { &(gi.hf.ctx_term_bir), { "BIR", n ".ctx.term.bir", FT_STRING, BASE_HEX, NULL, 0, "", HFILL }}, \ + { &(gi.hf.ctx_term_nsap), { "NSAP", n ".ctx.term.nsap", FT_STRING, BASE_NONE, NULL, 0, "", HFILL }}, \ + { &(gi.hf.ctx_cmd), { "Command in Frame", n ".ctx.cmd", FT_FRAMENUM, BASE_DEC, NULL, 0, "", HFILL }} + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/gnuc_format_check.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/gnuc_format_check.h new file mode 100644 index 00000000..a550dde7 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/gnuc_format_check.h @@ -0,0 +1,39 @@ +/* gnuc_format_check.h + * Definitions of macro to conditionally do GCC format checks + * + * $Id: gnuc_format_check.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __GNUC_FORMAT_CHECK_H__ +#define __GNUC_FORMAT_CHECK_H__ + +/** GNUC has the ability to check format strings that follow the syntax used in printf and others. + Hide the differences between different compilers in this GNUC_FORMAT_CHECK macro. + @param archetype one of: printf, scanf, strftime or strfmon + @param string_index specifies which argument is the format string argument (starting from 1) + @param first_to_check is the number of the first argument to check against the format string */ +#if __GNUC__ >= 2 + #define GNUC_FORMAT_CHECK(archetype, string_index, first_to_check) __attribute__((format (archetype, string_index, first_to_check))) +#else + #define GNUC_FORMAT_CHECK(archetype, string_index, first_to_check) +#endif + +#endif /* gnuc-format-check.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/golay.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/golay.h new file mode 100644 index 00000000..ad3d454a --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/golay.h @@ -0,0 +1,49 @@ +/* $Id: golay.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Provides routines for encoding and decoding the extended Golay + * (24,12,8) code. + * + * This implementation will detect up to 4 errors in a codeword (without + * being able to correct them); it will correct up to 3 errors. + * + * We use guint32s to hold the 24-bit codewords, with the data part in + * the bottom 12 bits and the parity in bits 12-23. + * + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef __GOLAY_H__ +#define __GOLAY_H__ + +/* encodes a 12-bit word to a 24-bit codeword + */ +guint32 golay_encode(guint w); + +/* return a mask showing the bits which are in error in a received + * 24-bit codeword, or -1 if 4 errors were detected. + */ +gint32 golay_errors(guint32 codeword); + +/* decode a received codeword. Up to 3 errors are corrected for; 4 + errors are detected as uncorrectable (return -1); 5 or more errors + cause an incorrect correction. +*/ +gint golay_decode(guint32 w); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/greproto.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/greproto.h new file mode 100644 index 00000000..de295dad --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/greproto.h @@ -0,0 +1,36 @@ +/* greproto.h + * Protocol type values for for the Generic Routing Encapsulation (GRE) + * protocol + * Brad Robel-Forrest + * + * The protocol type in GRE is supposed to be an Ethernet type value; + * this file lists protocol type values for which nobody's found an + * official Ethernet type definition and put that in "etypes.h". + * Move these to "etypes.h" if you find an official Ethernet type + * definition for them; when this file is empty, get rid of all includes + * of it, and get rid of it. + * + * $Id: greproto.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#define GRE_NHRP 0x2001 +#define GRE_WCCP 0x883E +#define GRE_ERSPAN 0x88BE diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/guid-utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/guid-utils.h new file mode 100644 index 00000000..c2fc95d6 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/guid-utils.h @@ -0,0 +1,63 @@ +/* guid-utils.h + * Definitions for GUID handling + * + * $Id: guid-utils.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __GUID_UTILS_H__ +#define __GUID_UTILS_H__ + +#define GUID_LEN 16 + +/* Note: this might be larger than GUID_LEN, so don't overlay data in packets + with this. */ +typedef struct _e_guid_t { + guint32 data1; + guint16 data2; + guint16 data3; + guint8 data4[8]; +} e_guid_t; + + +extern void guids_init(void); + +/* add a GUID */ +extern void guids_add_guid(e_guid_t *guid, const gchar *name); + +/* try to get registered name for this GUID */ +extern const gchar *guids_get_guid_name(e_guid_t *guid); + +/* resolve GUID to name (or if unknown to hex string) */ +/* (if you need hex string only, use guid_to_str instead) */ +extern const gchar* guids_resolve_guid_to_str(e_guid_t *guid); + +/* add a UUID (dcerpc_init_uuid() will call this too) */ +#define guids_add_uuid(uuid, name) guids_add_guid((e_guid_t *) (uuid), (name)) + +/* try to get registered name for this UUID */ +#define guids_get_uuid_name(uuid) guids_get_guid_name((e_guid_t *) (uuid)) + +/* resolve UUID to name (or if unknown to hex string) */ +/* (if you need hex string only, use guid_to_str instead) */ +#define guids_resolve_uuid_to_str(uuid) guids_resolve_guid_to_str((e_guid_t *) (uuid)) + +#endif /* __GUID_UTILS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/h225-persistentdata.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/h225-persistentdata.h new file mode 100644 index 00000000..576330e5 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/h225-persistentdata.h @@ -0,0 +1,62 @@ +/* + * h225-persistentdata.h + * Definitions for lists and hash tables used in wireshark's h225 dissector + * for calculation of delays in h225-calls + * + * Copyright 2003 Lars Roland + * + * $Id: h225-persistentdata.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __h225_HASH__ +#define __h225_HASH__ + +#include +#include +#include + + +/* Item of ras request list*/ +typedef struct _h225ras_call_t { + guint32 requestSeqNum; + e_guid_t guid; + guint32 req_num; /* frame number request seen */ + guint32 rsp_num; /* frame number response seen */ + nstime_t req_time; /* arrival time of request */ + gboolean responded; /* true, if request has been responded */ + struct _h225ras_call_t *next_call; /* pointer to next ras request with same SequenceNumber and conversation handle */ +} h225ras_call_t; + + +/* Item of ras-request key list*/ +typedef struct _h225ras_call_info_key { + guint reqSeqNum; + conversation_t *conversation; +} h225ras_call_info_key; + +/* functions, needed using ras-request and halfcall matching*/ +h225ras_call_t * find_h225ras_call(h225ras_call_info_key *h225ras_call_key ,int category); +h225ras_call_t * new_h225ras_call(h225ras_call_info_key *h225ras_call_key, packet_info *pinfo, e_guid_t *guid, int category); +h225ras_call_t * append_h225ras_call(h225ras_call_t *prev_call, packet_info *pinfo, e_guid_t *guid, int category); + +void h225_init_routine(void); /* init routine, used by wireshark */ + +#endif /* __h225_HASH__*/ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/iax2_codec_type.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/iax2_codec_type.h new file mode 100644 index 00000000..7832eeec --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/iax2_codec_type.h @@ -0,0 +1,77 @@ +/* iax2_codec_type.h + * Defines IAX2 codec types + * + * $Id: iax2_codec_type.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __IAX2_CODEC_TYPE_H__ +#define __IAX2_CODEC_TYPE_H__ + + +/* Ref: frame.h from Asterisk source */ + +/* Data formats for capabilities and frames alike */ +/* suitable for use in iax2.codec dissector table */ +/*! G.723.1 compression */ +#define AST_FORMAT_G723_1 (1 << 0) +/*! GSM compression */ +#define AST_FORMAT_GSM (1 << 1) +/*! Raw mu-law data (G.711) */ +#define AST_FORMAT_ULAW (1 << 2) +/*! Raw A-law data (G.711) */ +#define AST_FORMAT_ALAW (1 << 3) +/*! ADPCM (G.726, 32kbps) */ +#define AST_FORMAT_G726 (1 << 4) +/*! ADPCM (IMA) */ +#define AST_FORMAT_ADPCM (1 << 5) +/*! Raw 16-bit Signed Linear (8000 Hz) PCM */ +#define AST_FORMAT_SLINEAR (1 << 6) +/*! LPC10, 180 samples/frame */ +#define AST_FORMAT_LPC10 (1 << 7) +/*! G.729A audio */ +#define AST_FORMAT_G729A (1 << 8) +/*! SpeeX Free Compression */ +#define AST_FORMAT_SPEEX (1 << 9) +/*! iLBC Free Compression */ +#define AST_FORMAT_ILBC (1 << 10) +/*! Maximum audio format */ +#define AST_FORMAT_MAX_AUDIO (1 << 15) +/*! JPEG Images */ +#define AST_FORMAT_JPEG (1 << 16) +/*! PNG Images */ +#define AST_FORMAT_PNG (1 << 17) +/*! H.261 Video */ +#define AST_FORMAT_H261 (1 << 18) +/*! H.263 Video */ +#define AST_FORMAT_H263 (1 << 19) +/*! Max one */ +#define AST_FORMAT_MAX_VIDEO (1 << 24) + + +/* data format for IAX_IE_DATAFORMAT ie */ +/* suitable for use in iax2.dataformat dissector table */ +typedef enum { + AST_DATAFORMAT_NULL, /* N/A: analogue call etc */ + AST_DATAFORMAT_V110, /* ITU-T V.110 rate adaption */ + AST_DATAFORMAT_H223_H245 /* ITU-T H.223/H.245 */ +} iax_dataformat_t; + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/in_cksum.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/in_cksum.h new file mode 100644 index 00000000..27c8273d --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/in_cksum.h @@ -0,0 +1,14 @@ +/* in_cksum.h + * Declaration of Internet checksum routine. + * + * $Id: in_cksum.h 3992 2008-06-10 03:13:11Z dgu $ + */ + +typedef struct { + const guint8 *ptr; + int len; +} vec_t; + +extern int in_cksum(const vec_t *vec, int veclen); + +extern guint16 in_cksum_shouldbe(guint16 sum, guint16 computed_sum); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/inet_aton.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/inet_aton.h new file mode 100644 index 00000000..b7732a98 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/inet_aton.h @@ -0,0 +1,34 @@ +/* inet_aton.h + * + * $Id: inet_aton.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * Version of "inet_aton()", for the benefit of OSes that don't have it. + */ + +#ifndef __INET_ATON_H__ +#define __INET_ATON_H__ + +struct in_addr; +extern int inet_aton(const char* cp_arg, struct in_addr *addr); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ip_opts.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ip_opts.h new file mode 100644 index 00000000..4915c227 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ip_opts.h @@ -0,0 +1,59 @@ +/* ip_opts.h + * Definitions of structures and routines for dissection of options that + * work like IPv4 or IPv6 options + * + * $Id: ip_opts.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __IP_OPTS_H__ +#define __IP_OPTS_H__ + +typedef enum { + NO_LENGTH, /* option has no data, hence no length */ + FIXED_LENGTH, /* option always has the same length */ + VARIABLE_LENGTH /* option is variable-length - optlen is minimum */ +} opt_len_type; + +/* Member of table of IP or TCP options. */ +typedef struct ip_tcp_opt { + int optcode; /* code for option */ + const char *name; /* name of option */ + int *subtree_index; /* pointer to subtree index for option */ + opt_len_type len_type; /* type of option length field */ + int optlen; /* value length should be (minimum if VARIABLE) */ + void (*dissect)(const struct ip_tcp_opt *, tvbuff_t *, int, guint, + packet_info *, proto_tree *); + /* routine to dissect option */ +} ip_tcp_opt; + +/* Routine to dissect options that work like IPv4 options, where the + length field in the option, if present, includes the type and + length bytes. */ +extern void dissect_ip_tcp_options(tvbuff_t *, int, guint, + const ip_tcp_opt *, int, int, packet_info *, proto_tree *); + +/* Routine to dissect options that work like IPv6 options, where the + length field in the option, if present, includes only the data, not + the type and length bytes. */ +extern void dissect_ipv6_options(tvbuff_t *, int, guint, + const ip_tcp_opt *, int, int, packet_info *, proto_tree *); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipproto.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipproto.h new file mode 100644 index 00000000..a6861cd7 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipproto.h @@ -0,0 +1,193 @@ +/* ipproto.h + * Declarations of IP protocol numbers, and of routines for converting + * IP protocol numbers into strings. + * + * $Id: ipproto.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __IPPROTO_H__ +#define __IPPROTO_H__ + +/* + * IP protocol numbers. + */ +#define IP_PROTO_IP 0 /* dummy for IP */ +#define IP_PROTO_HOPOPTS 0 /* IP6 hop-by-hop options - RFC1883 */ +#define IP_PROTO_ICMP 1 /* control message protocol - RFC792 */ +#define IP_PROTO_IGMP 2 /* group mgmt protocol - RFC1112 */ +#define IP_PROTO_GGP 3 /* gateway^2 (deprecated) - RFC823*/ +#define IP_PROTO_IPIP 4 /* IP inside IP - RFC2003*/ +#define IP_PROTO_IPV4 4 /* IP header */ +#define IP_PROTO_STREAM 5 /* Stream - RFC1190, RFC1819 */ +#define IP_PROTO_TCP 6 /* TCP - RFC792 */ +#define IP_PROTO_CBT 7 /* CBT - */ +#define IP_PROTO_EGP 8 /* exterior gateway protocol - RFC888 */ +#define IP_PROTO_IGP 9 /* any private interior gateway protocol ... */ +#define IP_PROTO_IGRP 9 /* ... and used by Cisco for IGRP */ +#define IP_PROTO_BBN_RCC 10 /* BBN RCC Monitoring */ +#define IP_PROTO_NVPII 11 /* Network Voice Protocol - RFC741 */ +#define IP_PROTO_PUP 12 /* pup */ +#define IP_PROTO_ARGUS 13 /* ARGUS */ +#define IP_PROTO_EMCON 14 /* EMCON */ +#define IP_PROTO_XNET 15 /* Cross net debugger - IEN158 */ +#define IP_PROTO_CHAOS 16 /* CHAOS */ +#define IP_PROTO_UDP 17 /* user datagram protocol - RFC768 */ +#define IP_PROTO_MUX 18 /* multiplexing - IEN90 */ +#define IP_PROTO_DCNMEAS 19 /* DCN Measurement Subsystems */ +#define IP_PROTO_HMP 20 /* Host Monitoring - RFC869 */ +#define IP_PROTO_PRM 21 /* Packet radio measurement */ +#define IP_PROTO_IDP 22 /* xns idp */ +#define IP_PROTO_TRUNK1 23 +#define IP_PROTO_TRUNK2 24 +#define IP_PROTO_LEAF1 25 +#define IP_PROTO_LEAF2 26 +#define IP_PROTO_RDP 27 /* Reliable Data Protocol - RFC908 */ +#define IP_PROTO_IRT 28 /* Internet Reliable Transation - RFC938 */ +#define IP_PROTO_TP 29 /* tp-4 w/ class negotiation - RFC905 */ +#define IP_PROTO_BULK 30 /* Bulk Data Transfer Protocol - RFC969 */ +#define IP_PROTO_MFE_NSP 31 /* MFE Network Services Protocol */ +#define IP_PROTO_MERIT 32 /* MERIT Internodal Protocol */ +/* #define IP_PROTO_SEP 33 Sequential Exchange Protocol */ +#define IP_PROTO_DCCP 33 /* Datagram Congestion Control Protocol */ +#define IP_PROTO_3PC 34 /* Third party connect protocol */ +#define IP_PROTO_IDPR 35 /* Interdomain policy routing protocol */ +#define IP_PROTO_XTP 36 /* XTP */ +#define IP_PROTO_DDP 37 /* Datagram Delivery Protocol */ +#define IP_PROTO_CMTP 38 /* Control Message Transport Protocol */ +#define IP_PROTO_TPPP 39 /* TP++ Transport Protocol */ +#define IP_PROTO_IL 40 /* IL Transport Protocol */ +#define IP_PROTO_IPV6 41 /* IP6 header */ +#define IP_PROTO_SDRP 42 /* Source demand routing protocol */ +#define IP_PROTO_ROUTING 43 /* IP6 routing header */ +#define IP_PROTO_FRAGMENT 44 /* IP6 fragmentation header */ +#define IP_PROTO_IDRP 45 /* Inter-Domain Routing Protocol */ +#define IP_PROTO_RSVP 46 /* Resource ReSerVation protocol */ +#define IP_PROTO_GRE 47 /* General Routing Encapsulation */ +#define IP_PROTO_MHRP 48 /* Mobile Host Routing Protocol */ +#define IP_PROTO_BNA 49 /* BNA */ +#define IP_PROTO_ESP 50 /* Encap Security Payload for IPv6 - RFC2406 */ +#define IP_PROTO_AH 51 /* Authentication Header for IPv6 - RFC2402*/ +#define IP_PROTO_INSLP 52 /* Integrated Net Layer Security */ +#define IP_PROTO_SWIPE 53 /* IP with Encryption */ +#define IP_PROTO_NARP 54 /* NBMA Address resolution protocol - RFC1735 */ +#define IP_PROTO_MOBILE 55 /* IP Mobility */ +#define IP_PROTO_TLSP 56 /* Transport Layer Security Protocol using */ + /* Kryptonet key management */ +#define IP_PROTO_SKIP 57 /* SKIP */ +#define IP_PROTO_ICMPV6 58 /* ICMP6 - RFC1883*/ +#define IP_PROTO_NONE 59 /* IP6 no next header - RFC1883 */ +#define IP_PROTO_DSTOPTS 60 /* IP6 destination options - RFC1883 */ +/* 61 is reserved by IANA for any host internal protocol */ +/* 61 is used by UCL's SHIM6 implementation as Next Header for SHIM6 */ +#define IP_PROTO_SHIM6 61 /* SHIM6 */ + +/* + * The current Protocol Numbers list says that the IP protocol number for + * mobility headers is 135; it cites draft-ietf-mobileip-ipv6-24, but + * that draft doesn't actually give a number. + * + * It appears that 62 used to be used, even though that's assigned to + * a protocol called CFTP; however, the only reference for CFTP is a + * Network Message from BBN back in 1982, so, for now, we support 62, + * as well as 135, as a protocol number for mobility headers. + */ +#define IP_PROTO_MIPV6_OLD 62 /* Mobile IPv6 */ +/* 63 is reserved by IANA for any local network */ +#define IP_PROTO_SATEXPAK 64 +#define IP_PROTO_KRYPTOLAN 65 +#define IP_PROTO_RVD 66 /* MIT Remote virtual disk protocol */ +#define IP_PROTO_IPPC 67 /* Internet Pluribus Packet Core */ +/* 68 is reserved by IANA for any distributed file system */ +#define IP_PROTO_SATMON 69 /* SATNET Monitoring */ +#define IP_PROTO_VISA 70 /* VISA Protocol */ +#define IP_PROTO_IPCV 71 /* Internet Packet Core Utility */ +#define IP_PROTO_CPNX 72 /* Computer Protocol Network Executive */ +#define IP_PROTO_CPHB 73 /* Computer Protocol Heart Beat */ +#define IP_PROTO_WSN 74 /* WANG Span Network */ +#define IP_PROTO_PVP 75 /* Packet Video Protocol */ +#define IP_PROTO_BRSATMON 76 /* Backroon SATNET Monitoring */ +#define IP_PROTO_SUNND 77 /* SUN ND Protocol - Temporary */ +#define IP_PROTO_WBMON 78 /* Wideband Monitoring */ +#define IP_PROTO_WBEXPAK 79 /* Wideband EXPAK */ +#define IP_PROTO_EON 80 /* ISO cnlp */ +#define IP_PROTO_VMTP 81 +#define IP_PROTO_SVMTP 82 /* Secure VMTP */ +#define IP_PROTO_VINES 83 /* Vines over raw IP */ +#define IP_PROTO_TTP 84 +#define IP_PROTO_NSFNETIGP 85 /* NSFNET IGP */ +#define IP_PROTO_DGP 86 /* Dissimilar Gateway Protocol */ +#define IP_PROTO_TCF 87 +#define IP_PROTO_EIGRP 88 +#define IP_PROTO_OSPF 89 /* OSPF Interior Gateway Protocol - RFC1583 */ +#define IP_PROTO_SPRITE 90 /* SPRITE RPC protocol */ +#define IP_PROTO_LARP 91 /* Locus Address Resolution Protocol */ +#define IP_PROTO_MTP 92 /* Multicast Transport Protocol */ +#define IP_PROTO_AX25 93 /* AX.25 frames */ +#define IP_PROTO_IPINIP 94 /* IP within IP Encapsulation protocol */ +#define IP_PROTO_MICP 95 /* Mobile Internetworking Control Protocol */ +#define IP_PROTO_SCCCP 96 /* Semaphore communications security protocol */ +#define IP_PROTO_ETHERIP 97 /* Ethernet-within-IP - RFC 3378 */ +#define IP_PROTO_ENCAP 98 /* encapsulation header - RFC1241*/ +/* 99 is reserved by IANA for any private encryption scheme */ +#define IP_PROTO_GMTP 100 +#define IP_PROTO_IFMP 101 /* Ipsilon flow management protocol */ +#define IP_PROTO_PNNI 102 /* PNNI over IP */ +#define IP_PROTO_PIM 103 /* Protocol Independent Mcast */ +#define IP_PROTO_ARIS 104 +#define IP_PROTO_SCPS 105 +#define IP_PROTO_QNX 106 +#define IP_PROTO_AN 107 /* Active Networks */ +#define IP_PROTO_IPCOMP 108 /* IP payload compression - RFC2393 */ +#define IP_PROTO_SNP 109 /* Sitara Networks Protocol */ +#define IP_PROTO_COMPAQ 110 /* Compaq Peer Protocol */ +#define IP_PROTO_IPX 111 /* IPX over IP */ +#define IP_PROTO_VRRP 112 /* Virtual Router Redundancy Protocol */ +#define IP_PROTO_PGM 113 /* Pragmatic General Multicast */ +/* 114 is reserved by IANA for any zero hop protocol */ +#define IP_PROTO_L2TP 115 /* Layer Two Tunnelling Protocol */ +#define IP_PROTO_DDX 116 /* D-II Data Exchange */ +#define IP_PROTO_IATP 117 /* Interactive Agent Transfer Protocol */ +#define IP_PROTO_STP 118 /* Schedule Transfer Protocol */ +#define IP_PROTO_SRP 119 /* Spectralink Radio Protocol */ +#define IP_PROTO_UTI 120 +#define IP_PROTO_SMP 121 /* Simple Message Protocol */ +#define IP_PROTO_SM 122 +#define IP_PROTO_PTP 123 /* Performance Transparency Protocol */ +#define IP_PROTO_ISIS 124 /* ISIS over IPv4 */ +#define IP_PROTO_FIRE 125 +#define IP_PROTO_CRTP 126 /* Combat Radio Transport Protocol */ +#define IP_PROTO_CRUDP 127 /* Combat Radio User Datagram */ +#define IP_PROTO_SSCOPMCE 128 +#define IP_PROTO_IPLT 129 +#define IP_PROTO_SPS 130 /* Secure Packet Shield */ +#define IP_PROTO_PIPE 131 /* Private IP Encapsulation within IP */ +#define IP_PROTO_SCTP 132 /* Stream Control Transmission Protocol */ +#define IP_PROTO_FC 133 /* Fibre Channel */ +#define IP_PROTO_RSVPE2EI 134 /* RSVP E2E Ignore - RFC3175 */ +#define IP_PROTO_MIPV6 135 /* Mobile IPv6 */ +#define IP_PROTO_UDPLITE 136 /* Lightweight user datagram protocol - RFC3828 */ +#define IP_PROTO_MPLS_IN_IP 137 /* MPLS in IP - RFC4023 */ +#define IP_PROTO_AX4000 173 /* AX/4000 Testblock - non IANA */ +#define IP_PROTO_NCS_HEARTBEAT 224 /* Novell NCS Heartbeat - http://support.novell.com/cgi-bin/search/searchtid.cgi?/10071158.htm */ + +extern const char *ipprotostr(int proto); + +#endif /* ipproto.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipv4.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipv4.h new file mode 100644 index 00000000..c1cbbbde --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipv4.h @@ -0,0 +1,67 @@ +/* ipv4.h + * + * IPv4 address class. They understand how to take netmasks into consideration + * during equivalence testing. + * + * Gilbert Ramirez + * + * $Id: ipv4.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __IPV4_H__ +#define __IPV4_H__ + +#include + +typedef struct { + guint32 addr; /* stored in host order */ + guint32 nmask; /* stored in host order */ +} ipv4_addr; + +/* Allocate a new ipv4_addr struct, initialize it, and return pointer */ +ipv4_addr* ipv4_addr_new(void); + +/* Frees an ipv4 struct */ +void ipv4_addr_free(ipv4_addr *ipv4); + +void ipv4_addr_set_host_order_addr(ipv4_addr *ipv4, guint32 new_addr); +void ipv4_addr_set_net_order_addr(ipv4_addr *ipv4, guint32 new_addr); +void ipv4_addr_set_netmask_bits(ipv4_addr *ipv4, guint new_nmask_bits); + +guint32 ipv4_get_net_order_addr(ipv4_addr *ipv4); +guint32 ipv4_get_host_order_addr(ipv4_addr *ipv4); + +/* Fills in a buffer with a dotted-decimal notation representation of an IPv4 + * address. */ +void ipv4_addr_str_buf(const ipv4_addr *ipv4, gchar *buf); + +/* Compares two ipv4_addrs, taking into account the less restrictive of the + * two netmasks, applying that netmask to both addrs. + */ +gboolean ipv4_addr_eq(ipv4_addr *a, ipv4_addr *b); +gboolean ipv4_addr_gt(ipv4_addr *a, ipv4_addr *b); +gboolean ipv4_addr_ge(ipv4_addr *a, ipv4_addr *b); +gboolean ipv4_addr_lt(ipv4_addr *a, ipv4_addr *b); +gboolean ipv4_addr_le(ipv4_addr *a, ipv4_addr *b); + +#define ipv4_addr_ne(a,b) !ipv4_addr_eq((a),(b)) + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipv6-utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipv6-utils.h new file mode 100644 index 00000000..a743f806 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipv6-utils.h @@ -0,0 +1,49 @@ +/* ipv6-utils.h + * Definitions for IPv6 packet disassembly + * + * $Id: ipv6-utils.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * + * Copyright 1998 Gerald Combs + * + * MobileIPv6 support added by Tomislav Borosa + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __IPV6_UTILS_H__ +#define __IPV6_UTILS_H__ + +struct e_in6_addr { + guint8 bytes[16]; /* 128 bit IP6 address */ +}; + +/* + * Unicast Scope + * Note that we must check topmost 10 bits only, not 16 bits (see RFC2373). + */ +#define E_IN6_IS_ADDR_LINKLOCAL(a) \ + (((a)->bytes[0] == 0xfe) && (((a)->bytes[1] & 0xc0) == 0x80)) +#define E_IN6_IS_ADDR_SITELOCAL(a) \ + (((a)->bytes[0] == 0xfe) && (((a)->bytes[1] & 0xc0) == 0xc0)) + +/* + * Multicast + */ +#define E_IN6_IS_ADDR_MULTICAST(a) ((a)->bytes[0] == 0xff) + +#endif /* __IPV6_UTILS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/lapd_sapi.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/lapd_sapi.h new file mode 100644 index 00000000..5750f796 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/lapd_sapi.h @@ -0,0 +1,38 @@ +/* lapd_sapi.h + * Declarations of LAPD SAPI values. + * + * $Id: lapd_sapi.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2004 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __LAPD_SAPI_H__ +#define __LAPD_SAPI_H__ + +#define LAPD_SAPI_Q931 0 /* Q.931 call control procedure */ +#define LAPD_SAPI_PM_Q931 1 /* Packet mode Q.931 call control procedure */ +#define LAPD_SAPI_X25 16 /* X.25 Level 3 procedures */ +#define LAPD_SAPI_L2 63 /* Layer 2 management procedures */ + +#define LAPD_GSM_SAPI_RA_SIG_PROC 0 +#define LAPD_GSM_SAPI_NOT_USED_1 1 +#define LAPD_GSM_SAPI_NOT_USED_16 16 +#define LAPD_GSM_SAPI_OM_PROC 62 + +#endif /* lapd_sapi.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/llcsaps.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/llcsaps.h new file mode 100644 index 00000000..ddafad20 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/llcsaps.h @@ -0,0 +1,63 @@ +/* llcsaps.h + * Defines LLC SAP values. + * + * $Id: llcsaps.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __LLCSAPS_H__ +#define __LLCSAPS_H__ + +#define SAP_NULL 0x00 +#define SAP_LLC_SLMGMT 0x02 +#define SAP_SNA_PATHCTRL 0x04 +#define SAP_IP 0x06 +#define SAP_SNA1 0x08 +#define SAP_SNA2 0x0C +#define SAP_PROWAY_NM_INIT 0x0E +#define SAP_NETWARE1 0x10 +#define SAP_OSINL1 0x14 +#define SAP_TI 0x18 +#define SAP_OSINL2 0x20 +#define SAP_OSINL3 0x34 +#define SAP_SNA3 0x40 +#define SAP_BPDU 0x42 +#define SAP_RS511 0x4E +#define SAP_OSINL4 0x54 +#define SAP_X25 0x7E +#define SAP_XNS 0x80 +#define SAP_BACNET 0x82 +#define SAP_NESTAR 0x86 +#define SAP_PROWAY_ASLM 0x8E +#define SAP_ARP 0x98 +#define SAP_SNAP 0xAA +#define SAP_HPJD 0xB4 +#define SAP_VINES1 0xBA +#define SAP_VINES2 0xBC +#define SAP_NETWARE2 0xE0 +#define SAP_NETBIOS 0xF0 +#define SAP_IBMNM 0xF4 +#define SAP_HPEXT 0xF8 +#define SAP_UB 0xFA +#define SAP_RPL 0xFC +#define SAP_OSINL5 0xFE +#define SAP_GLOBAL 0xFF + +#endif /* llcsaps.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/next_tvb.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/next_tvb.h new file mode 100644 index 00000000..583c9a41 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/next_tvb.h @@ -0,0 +1,65 @@ +/* next_tvb.h + * Definitions for "next tvb" list + * + * $Id: next_tvb.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +/* The buffers returned by these functions are all allocated with a + * packet lifetime or are static buffers and does not have have to be freed. + * However, take into account that when the packet dissection + * completes, these buffers will be automatically reclaimed/freed. + * If you need the buffer to remain for a longer scope than packet lifetime + * you must copy the content to an se_alloc() buffer. + */ + +#ifndef __NEXT_TVB_H__ +#define __NEXT_TVB_H__ + +typedef enum { + NTVB_HANDLE, + NTVB_PORT, + NTVB_STRING +} next_tvb_call_e; + +typedef struct next_tvb_item { + struct next_tvb_item *next; + struct next_tvb_item *previous; + next_tvb_call_e type; + dissector_handle_t handle; + dissector_table_t table; + guint32 port; + const gchar *string; + tvbuff_t *tvb; + proto_tree *tree; +} next_tvb_item_t; + +typedef struct { + next_tvb_item_t *first; + next_tvb_item_t *last; + int count; +} next_tvb_list_t; + +extern void next_tvb_init(next_tvb_list_t *list); +extern void next_tvb_add_handle(next_tvb_list_t *list, tvbuff_t *tvb, proto_tree *tree, dissector_handle_t handle); +extern void next_tvb_add_port(next_tvb_list_t *list, tvbuff_t *tvb, proto_tree *tree, dissector_table_t table, guint32 port); +extern void next_tvb_add_string(next_tvb_list_t *list, tvbuff_t *tvb, proto_tree *tree, dissector_table_t table, const gchar *string); +extern void next_tvb_call(next_tvb_list_t *list, packet_info *pinfo, proto_tree *tree, dissector_handle_t handle, dissector_handle_t data_handle); + +#endif /* __NEXT_TVB_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/nlpid.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/nlpid.h new file mode 100644 index 00000000..c4c7ce40 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/nlpid.h @@ -0,0 +1,60 @@ +/* nlpid.h + * Definitions of OSI NLPIDs (Network Layer Protocol IDs) + * Laurent Deniel + * + * $Id: nlpid.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __NLPID_H__ +#define __NLPID_H__ + +/* X.263 / ISO/IEC TR 9577 NLPID values. */ + +#define NLPID_NULL 0x00 +#define NLPID_IPI_T_70 0x01 /* T.70, when an IPI */ +#define NLPID_SPI_X_29 0x01 /* X.29, when an SPI */ +#define NLPID_X_633 0x03 /* X.633 */ +#define NLPID_Q_931 0x08 /* Q.931, Q.932, X.36, ISO 11572, ISO 11582 */ +#define NLPID_Q_933 0x08 /* Q.933, on Frame Relay */ +#define NLPID_Q_2931 0x09 /* Q.2931 */ +#define NLPID_Q_2119 0x0c /* Q.2119 */ +#define NLPID_SNAP 0x80 +#define NLPID_ISO8473_CLNP 0x81 /* X.233 */ +#define NLPID_ISO9542_ESIS 0x82 +#define NLPID_ISO10589_ISIS 0x83 +#define NLPID_ISO10747_IDRP 0x85 +#define NLPID_ISO9542X25_ESIS 0x8a +#define NLPID_ISO10030 0x8c +#define NLPID_ISO11577 0x8d /* X.273 */ +#define NLPID_IP6 0x8e +#define NLPID_COMPRESSED 0xb0 /* "Data compression protocol" */ +#define NLPID_SNDCF 0xc1 /* "SubNetwork Dependent Convergence Function */ +#define NLPID_IP 0xcc +#define NLPID_PPP 0xcf + +extern const value_string nlpid_vals[]; + +/* + * 0x09 is, in Frame Relay, LMI, Q.2931. + */ +#define NLPID_LMI 0x09 /* LMI */ + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/nstime.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/nstime.h new file mode 100644 index 00000000..c92375df --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/nstime.h @@ -0,0 +1,92 @@ +/* nstime.h + * Definition of data structure to hold time values with nanosecond resolution + * + * $Id: nstime.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __NSTIME_H__ +#define __NSTIME_H__ + +#include + +#include + +typedef struct { + time_t secs; + int nsecs; +} nstime_t; + +/* functions */ + +/* set the given nstime_t to zero */ +extern void nstime_set_zero(nstime_t *nstime); + +/* is the given nstime_t currently zero? */ +extern gboolean nstime_is_zero(nstime_t *nstime); + +/* set the given nstime_t to (0,maxint) to mark it as "unset" + * That way we can find the first frame even when a timestamp + * is zero (fix for bug 1056) + */ +extern void nstime_set_unset(nstime_t *nstime); + +/* is the given nstime_t currently (0,maxint)? */ +extern gboolean nstime_is_unset(nstime_t *nstime); + +/* calculate the delta between two times (can be negative!) + * + * delta = b-a + * + * Note that it is acceptable for two or more of the arguments to point at the + * same structure. + */ +extern void nstime_delta(nstime_t *delta, const nstime_t *b, const nstime_t *a ); + +/* calculate the sum of two times + * + * sum = a+b + * + * Note that it is acceptable for two or more of the arguments to point at the + * same structure. + */ +extern void nstime_sum(nstime_t *sum, const nstime_t *b, const nstime_t *a ); + +/* sum += a */ +#define nstime_add(sum, a) nstime_sum(sum, sum, a) + +/* compare two times are return a value similar to memcmp() or strcmp(). + * + * a > b : > 0 + * a = b : 0 + * a < b : < 0 + */ +extern int nstime_cmp(nstime_t *a, const nstime_t *b ); + +/* converts nstime to double, time base is milli seconds */ +extern double nstime_to_msec(const nstime_t *time); + +/* converts nstime to double, time base is seconds */ +extern double nstime_to_sec(const nstime_t *time); + +/* converts wtap_nstime to double, time base is seconds */ +extern double wtap_nstime_to_sec(const struct wtap_nstime *time); + +#endif /* __NSTIME_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/oids.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/oids.h new file mode 100644 index 00000000..50a4ea83 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/oids.h @@ -0,0 +1,179 @@ +/* oids.h + * Object IDentifier Support + * + * $Id: oids.h 3992 2008-06-10 03:13:11Z dgu $ + * + * (c) 2007, Luis E. Garcia Ontanon + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __OIDS_H__ +#define __OIDS_H__ + +#define BER_TAG_ANY -1 + +struct _oid_bit_t { + guint offset; + int hfid; +}; + +typedef struct _oid_bits_info_t { + guint num; + gint ett; + struct _oid_bit_t* data; +} oid_bits_info_t; + +typedef enum _oid_key_type_t { + OID_KEY_TYPE_WRONG, + OID_KEY_TYPE_INTEGER, + OID_KEY_TYPE_OID, + OID_KEY_TYPE_STRING, + OID_KEY_TYPE_BYTES, + OID_KEY_TYPE_NSAP, + OID_KEY_TYPE_IPADDR, + OID_KEY_TYPE_IMPLIED_OID, + OID_KEY_TYPE_IMPLIED_STRING, + OID_KEY_TYPE_IMPLIED_BYTES +} oid_key_type_t; + +typedef struct _oid_value_type_t { + enum ftenum ft_type; + int display; + gint8 ber_class; + gint32 ber_tag; + int min_len; + int max_len; + oid_key_type_t keytype; + int keysize; +} oid_value_type_t; + +typedef enum _oid_kind_t { + OID_KIND_UNKNOWN = 0, + OID_KIND_NODE, + OID_KIND_SCALAR, + OID_KIND_TABLE, + OID_KIND_ROW, + OID_KIND_COLUMN, + OID_KIND_NOTIFICATION, + OID_KIND_GROUP, + OID_KIND_COMPLIANCE, + OID_KIND_CAPABILITIES +} oid_kind_t; + +typedef struct _oid_key_t { + char* name; + guint32 num_subids; + oid_key_type_t key_type; + int hfid; + enum ftenum ft_type; + int display; + struct _oid_key_t* next; +} oid_key_t; + +typedef struct _oid_info_t { + guint32 subid; + char* name; + oid_kind_t kind; + void* children; /* an emem_tree_t* */ + const oid_value_type_t* value_type; + int value_hfid; + oid_key_t* key; + oid_bits_info_t* bits; + struct _oid_info_t* parent; +} oid_info_t; + +/* init funcion called from epan.h */ +extern void oids_init(void); + +/* + * The objects returned by all these functions are all allocated with a + * packet lifetime and does not have have to be freed. + * However, take into account that when the packet dissection + * completes, these buffers will be automatically reclaimed/freed. + * If you need the buffer to remain for a longer scope than packet lifetime + * you must copy the content to an se_alloc() buffer. + */ + +/* + * These functions convert through the various formats: + * string: is like "0.1.3.4.5.30" (not resolved) + * encoded: is BER encoded (as per X.690 section 8.19) + * subids: is an array of guint32s + */ + +/* return length of encoded buffer */ +guint oid_subid2encoded(guint len, guint32* subids, guint8** encoded_p); +guint oid_string2encoded(const gchar *oid_str, guint8** encoded_p); + +/* return length of subid array */ +guint oid_encoded2subid(const guint8 *oid, gint len, guint32** subids_p); +guint oid_string2subid(const gchar *oid_str, guint32** subids_p); + +extern const gchar* oid_encoded2string(const guint8* encoded, guint len); +extern const gchar* oid_subid2string(guint32 *subids, guint len); + +/* these return a formated string as human readable as posible */ +extern const gchar *oid_resolved(guint len, guint32 *subids); +extern const gchar *oid_resolved_from_encoded(const guint8 *oid, gint len); +extern const gchar *oid_resolved_from_string(const gchar *oid_str); + +/* these yield two formated strings one resolved and one numeric */ +extern void oid_both(guint oid_len, guint32 *subids, char** resolved_p, char** numeric_p); +extern void oid_both_from_encoded(const guint8 *oid, gint oid_len, char** resolved_p, char** numeric_p); +extern void oid_both_from_string(const gchar *oid_str, char** resolved_p, char** numeric_p); + +/* + * These return the info for the best match. + * *matched_p will be set to the number of nodes used by the returned oid + * *left_p will be set to the number of remaining unresolved subids + */ +extern oid_info_t* oid_get(guint oid_len, guint32 *subids, guint* matched_p, guint* left_p); +extern oid_info_t* oid_get_from_encoded(const guint8 *oid, gint oid_len, guint32 **subids, guint* matched, guint* left); +extern oid_info_t* oid_get_from_string(const gchar *oid_str, guint32 **subids, guint* matched, guint* left); + +/* these are used to add oids to the collection */ +extern void oid_add(const char* name, guint oid_len, guint32 *subids); +extern void oid_add_from_encoded(const char* name, const guint8 *oid, gint oid_len); +extern void oid_add_from_string(const char* name, const gchar *oid_str); + +/** + * Fetch the default MIB/PIB path + * + * @return A string containing the default MIB/PIB path. It must be + * g_free()d by the caller. + */ +extern gchar *oid_get_default_mib_path(void); + +extern void oid_add_from_string(const char* name, const gchar *oid_str); + +/* macros for legacy oid functions */ +#define oid_resolv_cleanup() ((void)0) +#define subid_t guint32 + + + +#ifdef DEBUG_OIDS +extern char* oid_test_a2b(guint32 num_subids, guint32* subids); +extern void add_oid_debug_subtree(oid_info_t* oid_info, proto_tree *tree); +#else +#define add_oid_debug_subtree(a,b) ((void)0) +#endif + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/osi-utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/osi-utils.h new file mode 100644 index 00000000..97b6b27a --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/osi-utils.h @@ -0,0 +1,57 @@ +/* osi-utils.h + * + * $Id: osi-utils.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __OSI_UTILS_H__ +#define __OSI_UTILS_H__ + +/* OSI Global defines, common for all OSI protocols */ + +#define MAX_NSAP_LEN 30 +#define MAX_SYSTEMID_LEN 15 +#define MAX_AREA_LEN 30 + +#define RFC1237_NSAP_LEN 20 +#define RFC1237_FULLAREA_LEN 13 +#define RFC1237_SYSTEMID_LEN 6 +#define RFC1237_SELECTOR_LEN 1 + +#define RFC1237_IDI_LEN 2 +#define RFC1237_AFI_LEN 1 +#define RFC1237_DFI_LEN 1 +#define RFC1237_ORG_LEN 3 +#define RFC1237_AA_LEN 3 +#define RFC1237_RSVD_LEN 2 +#define RFC1237_RD_LEN 2 +#define RFC1237_AREA_LEN 3 + +#define NSAP_IDI_ISODCC 0x39 +#define NSAP_IDI_GOSIP2 0x47 + +gchar* print_nsap_net ( const guint8 *, int ); +void print_nsap_net_buf( const guint8 *, int, gchar *, int); +gchar* print_area ( const guint8 *, int ); +void print_area_buf ( const guint8 *, int, gchar *, int); +gchar* print_system_id( const guint8 *, int ); +void print_system_id_buf( const guint8 *, int, gchar *, int); + +#endif /* __OSI_UTILS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/oui.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/oui.h new file mode 100644 index 00000000..1431d530 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/oui.h @@ -0,0 +1,74 @@ +/* oui.h + * Definitions of OUIs + * + * $Id: oui.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 - 2000 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __OUI_H__ +#define __OUI_H__ + +/* + * See + * + * http://standards.ieee.org/regauth/oui/oui.txt + * + * http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/vlan.htm + * + * for the PIDs for VTP and DRiP that go with an OUI of OUI_CISCO. + */ + +#define OUI_ENCAP_ETHER 0x000000 /* encapsulated Ethernet */ +#define OUI_XEROX 0x000006 /* Xerox */ +#define OUI_CISCO 0x00000C /* Cisco (future use) */ +#define OUI_NORTEL 0x000081 /* Nortel SONMP */ +#define OUI_CISCO_90 0x0000F8 /* Cisco (IOS 9.0 and above?) */ +#define OUI_ERICSSON 0x0001EC /* Ericsson Group */ +#define OUI_CATENA 0x00025A /* Catena Networks */ +#define OUI_SONY_ERICSSON 0x000AD9 /* Sony Ericsson Mobile Communications AB */ +#define OUI_SONY_ERICSSON_2 0x000E07 /* Sony Ericsson Mobile Communications AB */ +#define OUI_PROFINET 0x000ECF /* PROFIBUS Nutzerorganisation e.V. */ +#define OUI_SONY_ERICSSON_3 0x000FDE /* Sony Ericsson Mobile Communications AB */ +#define OUI_IEEE_802_3 0x00120F /* IEEE 802.3 */ +#define OUI_MEDIA_ENDPOINT 0x0012BB /* Media (TIA TR-41 Committee) */ +#define OUI_SONY_ERICSSON_4 0x0012EE /* Sony Ericsson Mobile Communications AB */ +#define OUI_ERICSSON_MOBILE 0x0015E0 /* Ericsson Mobile Platforms */ +#define OUI_SONY_ERICSSON_5 0x001620 /* Sony Ericsson Mobile Communications AB */ +#define OUI_SONY_ERICSSON_6 0x0016B8 /* Sony Ericsson Mobile Communications AB */ +#define OUI_SONY_ERICSSON_7 0x001813 /* Sony Ericsson Mobile Communications AB */ +#define OUI_SONY_ERICSSON_8 0x001963 /* Sony Ericsson Mobile Communications AB */ +#define OUI_CISCOWL 0x004096 /* Cisco Wireless (Aironet) */ +#define OUI_ERICSSON_2 0x008037 /* Ericsson Group */ +#define OUI_BRIDGED 0x0080C2 /* Bridged Frame-Relay, RFC 2427 */ + /* and Bridged ATM, RFC 2684 */ +#define OUI_IEEE_802_1 0x0080C2 /* IEEE 802.1 Committee */ +#define OUI_ATM_FORUM 0x00A03E /* ATM Forum */ +#define OUI_EXTREME 0x00E02B /* Extreme EDP/ESRP */ +#define OUI_CABLE_BPDU 0x00E02F /* DOCSIS spanning tree BPDU */ +#define OUI_SIEMENS 0x080006 /* Siemens AG */ +#define OUI_APPLE_ATALK 0x080007 /* Appletalk */ +#define OUI_HP 0x080009 /* Hewlett-Packard */ + +/* + * Defined in packet-llc.c + */ +extern const value_string oui_vals[]; + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/packet.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/packet.h new file mode 100644 index 00000000..5061c565 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/packet.h @@ -0,0 +1,422 @@ +/* packet.h + * Definitions for packet disassembly structures and routines + * + * $Id: packet.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __PACKET_H__ +#define __PACKET_H__ + +/* + * If defines formats to be used to print 64-bit integers, + * include it. + */ +#ifdef INTTYPES_H_DEFINES_FORMATS +#include +#endif + +#include "wiretap/wtap.h" +#include "proto.h" +#include "tvbuff.h" +#include "pint.h" +#include "to_str.h" +#include "value_string.h" +#include "column_info.h" +#include "frame_data.h" +#include "packet_info.h" +#include "column-utils.h" +#include "epan.h" +#include "tfs.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define hi_nibble(b) (((b) & 0xf0) >> 4) +#define lo_nibble(b) ((b) & 0x0f) + +/* Useful when you have an array whose size you can tell at compile-time */ +#define array_length(x) (sizeof x / sizeof x[0]) + +/* Check whether the "len" bytes of data starting at "offset" is + * entirely inside the captured data for this packet. */ +#define BYTES_ARE_IN_FRAME(offset, captured_len, len) \ + ((guint)(offset) + (guint)(len) > (guint)(offset) && \ + (guint)(offset) + (guint)(len) <= (guint)(captured_len)) + +/* To pass one of two strings, singular or plural */ +#define plurality(d,s,p) ((d) == 1 ? (s) : (p)) + +typedef struct _packet_counts { + gint sctp; + gint tcp; + gint udp; + gint icmp; + gint ospf; + gint gre; + gint netbios; + gint ipx; + gint vines; + gint other; + gint total; + gint arp; +} packet_counts; + +/** Number of packet counts. */ +#define PACKET_COUNTS_SIZE sizeof(packet_counts) / sizeof (gint) + +/* Types of character encodings */ +typedef enum { + CHAR_ASCII = 0, /* ASCII */ + CHAR_EBCDIC = 1 /* EBCDIC */ +} char_enc; + +extern void packet_init(void); +extern void packet_cleanup(void); + +/* Handle for dissectors you call directly or register with "dissector_add()". + This handle is opaque outside of "packet.c". */ +struct dissector_handle; +typedef struct dissector_handle *dissector_handle_t; + +/* Hash table for matching port numbers and dissectors; this is opaque + outside of "packet.c". */ +struct dissector_table; +typedef struct dissector_table *dissector_table_t; + +/* + * Dissector that returns nothing. + */ +typedef void (*dissector_t)(tvbuff_t *, packet_info *, proto_tree *); + +/* + * Dissector that returns: + * + * The amount of data in the protocol's PDU, if it was able to + * dissect all the data; + * + * 0, if the tvbuff doesn't contain a PDU for that protocol; + * + * The negative of the amount of additional data needed, if + * we need more data (e.g., from subsequent TCP segments) to + * dissect the entire PDU. + */ +typedef int (*new_dissector_t)(tvbuff_t *, packet_info *, proto_tree *); + +/** Type of a heuristic dissector, used in heur_dissector_add(). + * + * @param tvb the tv_buff with the (remaining) packet data + * @param pinfo the packet info of this packet (additional info) + * @param tree the protocol tree to be build or NULL + * @return TRUE if the packet was recognized by the sub-dissector (stop dissection here) + */ +typedef gboolean (*heur_dissector_t)(tvbuff_t *tvb, packet_info *pinfo, + proto_tree *tree); + +typedef void (*DATFunc) (const gchar *table_name, ftenum_t selector_type, + gpointer key, gpointer value, gpointer user_data); +typedef void (*DATFunc_handle) (const gchar *table_name, gpointer value, + gpointer user_data); +typedef void (*DATFunc_table) (const gchar *table_name, const gchar *ui_name, + gpointer user_data); + +/* Opaque structure - provides type checking but no access to components */ +typedef struct dtbl_entry dtbl_entry_t; + +extern dissector_handle_t dtbl_entry_get_handle (dtbl_entry_t *dtbl_entry); +extern dissector_handle_t dtbl_entry_get_initial_handle (dtbl_entry_t * entry); +extern void dissector_table_foreach_changed (const char *name, DATFunc func, + gpointer user_data); +extern void dissector_table_foreach (const char *name, DATFunc func, + gpointer user_data); +extern void dissector_all_tables_foreach_changed (DATFunc func, + gpointer user_data); +extern void dissector_table_foreach_handle(const char *name, DATFunc_handle func, + gpointer user_data); +extern void dissector_all_tables_foreach_table (DATFunc_table func, + gpointer user_data); + +/* a protocol uses the function to register a sub-dissector table */ +extern dissector_table_t register_dissector_table(const char *name, + const char *ui_name, ftenum_t type, int base); + +/* Find a dissector table by table name. */ +extern dissector_table_t find_dissector_table(const char *name); + +/* Get the UI name for a sub-dissector table, given its internal name */ +extern const char *get_dissector_table_ui_name(const char *name); + +/* Get the field type for values of the selector for a dissector table, + given the table's internal name */ +extern ftenum_t get_dissector_table_selector_type(const char *name); + +/* Get the base to use when displaying values of the selector for a + sub-dissector table, given the table's internal name */ +extern int get_dissector_table_base(const char *name); + +/* Add an entry to a uint dissector table. */ +extern void dissector_add(const char *abbrev, guint32 pattern, + dissector_handle_t handle); + +/* Delete the entry for a dissector in a uint dissector table + with a particular pattern. */ +extern void dissector_delete(const char *name, guint32 pattern, + dissector_handle_t handle); + +/* Change the entry for a dissector in a uint dissector table + with a particular pattern to use a new dissector handle. */ +extern void dissector_change(const char *abbrev, guint32 pattern, + dissector_handle_t handle); + +/* Reset an entry in a uint dissector table to its initial value. */ +extern void dissector_reset(const char *name, guint32 pattern); + +/* Look for a given value in a given uint dissector table and, if found, + call the dissector with the arguments supplied, and return TRUE, + otherwise return FALSE. */ +extern gboolean dissector_try_port(dissector_table_t sub_dissectors, + guint32 port, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); + +/* Look for a given value in a given uint dissector table and, if found, + return the dissector handle for that value. */ +extern dissector_handle_t dissector_get_port_handle( + dissector_table_t sub_dissectors, guint32 port); + +/* Add an entry to a string dissector table. */ +extern void dissector_add_string(const char *name, const gchar *pattern, + dissector_handle_t handle); + +/* Delete the entry for a dissector in a string dissector table + with a particular pattern. */ +extern void dissector_delete_string(const char *name, const gchar *pattern, + dissector_handle_t handle); + +/* Change the entry for a dissector in a string dissector table + with a particular pattern to use a new dissector handle. */ +extern void dissector_change_string(const char *name, gchar *pattern, + dissector_handle_t handle); + +/* Reset an entry in a string sub-dissector table to its initial value. */ +extern void dissector_reset_string(const char *name, const gchar *pattern); + +/* Look for a given string in a given dissector table and, if found, call + the dissector with the arguments supplied, and return TRUE, otherwise + return FALSE. */ +extern gboolean dissector_try_string(dissector_table_t sub_dissectors, + const gchar *string, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); + +/* Look for a given value in a given string dissector table and, if found, + return the dissector handle for that value. */ +extern dissector_handle_t dissector_get_string_handle( + dissector_table_t sub_dissectors, const gchar *string); + +/* Add a handle to the list of handles that *could* be used with this + table. That list is used by code in the UI. */ +extern void dissector_add_handle(const char *name, dissector_handle_t handle); + +/* List of "heuristic" dissectors (which get handed a packet, look at it, + and either recognize it as being for their protocol, dissect it, and + return TRUE, or don't recognize it and return FALSE) to be called + by another dissector. */ +typedef GSList *heur_dissector_list_t; + +/** A protocol uses this function to register a heuristic sub-dissector list. + * Call this in the parent dissectors proto_register function. + * + * @param name the name of this protocol + * @param list the list of heuristic sub-dissectors to be registered + */ +extern void register_heur_dissector_list(const char *name, + heur_dissector_list_t *list); + +/** Try all the dissectors in a given heuristic dissector list. This is done, + * until we find one that recognizes the protocol. + * Call this while the parent dissector running. + * + * @param sub_dissectors the sub-dissector list + * @param tvb the tv_buff with the (remaining) packet data + * @param pinfo the packet info of this packet (additional info) + * @param tree the protocol tree to be build or NULL + * @return TRUE if the packet was recognized by the sub-dissector (stop dissection here) + */ +extern gboolean dissector_try_heuristic(heur_dissector_list_t sub_dissectors, + tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); + +/** Add a sub-dissector to a heuristic dissector list. + * Call this in the proto_handoff function of the sub-dissector. + * + * @param name the name of the "parent" protocol, e.g. "tcp" + * @param dissector the sub-dissector to be registered + * @param proto the protocol id of the sub-dissector + */ +extern void heur_dissector_add(const char *name, heur_dissector_t dissector, + int proto); + +/** Remove a sub-dissector from a heuristic dissector list. + * Call this in the prefs_reinit function of the sub-dissector. + * + * @param name the name of the "parent" protocol, e.g. "tcp" + * @param dissector the sub-dissector to be unregistered + * @param proto the protocol id of the sub-dissector + */ +extern void heur_dissector_delete(const char *name, heur_dissector_t dissector, int proto); + +/* Register a dissector. */ +extern void register_dissector(const char *name, dissector_t dissector, + int proto); +extern void new_register_dissector(const char *name, new_dissector_t dissector, + int proto); + +/* Get the short name of the protocol for a dissector handle. */ +extern const char *dissector_handle_get_short_name(dissector_handle_t handle); + +/* Get the index of the protocol for a dissector handle. */ +extern int dissector_handle_get_protocol_index(dissector_handle_t handle); + +/* Find a dissector by name. */ +extern dissector_handle_t find_dissector(const char *name); + +/* Create an anonymous handle for a dissector. */ +extern dissector_handle_t create_dissector_handle(dissector_t dissector, + int proto); +extern dissector_handle_t new_create_dissector_handle(new_dissector_t dissector, + int proto); + +/* Call a dissector through a handle and if no dissector was found + * pass if over to the "data" dissector instead. + * + * @param handle The dissector to call. + * @param tvb The buffer to dissect. + * @param pinfo Packet Info. + * @param tree The protocol tree. + * @return If the protocol for that handle isn't enabled call the data + * dissector. Otherwise, if the handle refers to a new-style + * dissector, call the dissector and return its return value, otherwise call + * it and return the length of the tvbuff pointed to by the argument. + */ +extern int call_dissector(dissector_handle_t handle, tvbuff_t *tvb, + packet_info *pinfo, proto_tree *tree); + +/* Call a dissector through a handle but if no dissector was found + * just return 0 and do not call the "data" dissector instead. + * + * @param handle The dissector to call. + * @param tvb The buffer to dissect. + * @param pinfo Packet Info. + * @param tree The protocol tree. + * @return If the protocol for that handle isn't enabled, return 0 without + * calling the dissector. Otherwise, if the handle refers to a new-style + * dissector, call the dissector and return its return value, otherwise call + * it and return the length of the tvbuff pointed to by the argument. + */ +extern int call_dissector_only(dissector_handle_t handle, tvbuff_t *tvb, + packet_info *pinfo, proto_tree *tree); + +/* Do all one-time initialization. */ +extern void dissect_init(void); + +extern void dissect_cleanup(void); + +/* + * Given a tvbuff, and a length from a packet header, adjust the length + * of the tvbuff to reflect the specified length. + */ +extern void set_actual_length(tvbuff_t *tvb, guint specified_len); + +/* Allow protocols to register "init" routines, which are called before + we make a pass through a capture file and dissect all its packets + (e.g., when we read in a new capture file, or run a "filter packets" + or "colorize packets" pass over the current capture file). */ +extern void register_init_routine(void (*func)(void)); + +/* Initialize all data structures used for dissection. */ +extern void init_dissection(void); + +/* Free data structures allocated for dissection. */ +extern void cleanup_dissection(void); + +/* Allow protocols to register a "cleanup" routine to be + * run after the initial sequential run through the packets. + * Note that the file can still be open after this; this is not + * the final cleanup. */ +extern void register_postseq_cleanup_routine(void (*func)(void)); + +/* Call all the registered "postseq_cleanup" routines. */ +extern void postseq_cleanup_all_protocols(void); + +/* Allow dissectors to register a "final_registration" routine + * that is run like the proto_register_XXX() routine, but the end + * end of the epan_init() function; that is, *after* all other + * subsystems, liked dfilters, have finished initializing. This is + * useful for dissector registration routines which need to compile + * display filters. dfilters can't initialize itself until all protocols + * have registereed themselvs. */ +extern void +register_final_registration_routine(void (*func)(void)); + +/* Call all the registered "final_registration" routines. */ +extern void +final_registration_all_protocols(void); + +/* + * Add a new data source to the list of data sources for a frame, given + * the tvbuff for the data source and its name. + */ +extern void add_new_data_source(packet_info *pinfo, tvbuff_t *tvb, + const char *name); + +/* + * Free up a frame's list of data sources. + */ +extern void free_data_sources(packet_info *pinfo); + +/* + * Dissectors should never modify the packet data. + */ +extern void dissect_packet(epan_dissect_t *edt, + union wtap_pseudo_header *pseudo_header, const guchar *pd, + frame_data *fd, column_info *cinfo); + +/* These functions are in packet-ethertype.c */ +extern void capture_ethertype(guint16 etype, const guchar *pd, int offset, + int len, packet_counts *ld); +extern void ethertype(guint16 etype, tvbuff_t *tvb, int offset_after_ethertype, + packet_info *pinfo, proto_tree *tree, proto_tree *fh_tree, + int etype_id, int trailer_id, int fcs_len); + +/* + * Dump layer/selector/dissector records in a fashion similar to the + * proto_registrar_dump_* routines. + */ +extern void dissector_dump_decodes(void); + +/* + * post dissectors are to be called by packet-frame.c after every other + * dissector has been called. + */ +extern void register_postdissector(dissector_handle_t); +extern void call_all_postdissectors(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* packet.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/packet_info.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/packet_info.h new file mode 100644 index 00000000..3902be51 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/packet_info.h @@ -0,0 +1,184 @@ +/* packet_info.h + * Definitions for packet info structures and routines + * + * $Id: packet_info.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PACKET_INFO_H__ +#define __PACKET_INFO_H__ + +#include "frame_data.h" +#include "tvbuff.h" +#include "address.h" + +#define P2P_DIR_UNKNOWN -1 +#define P2P_DIR_SENT 0 +#define P2P_DIR_RECV 1 + +#define PINFO_SOF_FIRST_FRAME 0x1 +#define PINFO_SOF_SOFF 0x2 +#define PINFO_EOF_LAST_FRAME 0x80 +#define PINFO_EOF_INVALID 0x40 +#define MAX_NUMBER_OF_PPIDS 2 + +typedef struct _packet_info { + const char *current_proto; /* name of protocol currently being dissected */ + column_info *cinfo; /* Column formatting information */ + frame_data *fd; + union wtap_pseudo_header *pseudo_header; + GSList *data_src; /* Frame data sources */ + address dl_src; /* link-layer source address */ + address dl_dst; /* link-layer destination address */ + address net_src; /* network-layer source address */ + address net_dst; /* network-layer destination address */ + address src; /* source address (net if present, DL otherwise )*/ + address dst; /* destination address (net if present, DL otherwise )*/ + guint32 ethertype; /* Ethernet Type Code, if this is an Ethernet packet */ + guint32 ipproto; /* IP protocol, if this is an IP packet */ + guint32 ipxptype; /* IPX packet type, if this is an IPX packet */ + circuit_type ctype; /* type of circuit, for protocols with a VC identifier */ + guint32 circuit_id; /* circuit ID, for protocols with a VC identifier */ + const char *noreassembly_reason; /* reason why reassembly wasn't done, if any */ + gboolean fragmented; /* TRUE if the protocol is only a fragment */ + gboolean in_error_pkt; /* TRUE if we're inside an {ICMP,CLNP,...} error packet */ + port_type ptype; /* type of the following two port numbers */ + guint32 srcport; /* source port */ + guint32 destport; /* destination port */ + guint32 match_port; /* matched port for calling subdissector from table */ + const char *match_string; /* matched string for calling subdissector from table */ + guint16 can_desegment; /* >0 if this segment could be desegmented. + A dissector that can offer this API (e.g. + TCP) sets can_desegment=2, then + can_desegment is decremented by 1 each time + we pass to the next subdissector. Thus only + the dissector immediately above the + protocol which sets the flag can use it*/ + guint16 saved_can_desegment; /* Value of can_desegment before current + dissector was called. Supplied so that + dissectors for proxy protocols such as + SOCKS can restore it, allowing the + dissectors that they call to use the + TCP dissector's desegmentation (SOCKS + just retransmits TCP segments once it's + finished setting things up, so the TCP + desegmentor can desegment its payload). */ + int desegment_offset; /* offset to stuff needing desegmentation */ +#define DESEGMENT_ONE_MORE_SEGMENT 0x0fffffff +#define DESEGMENT_UNTIL_FIN 0x0ffffffe + guint32 desegment_len; /* requested desegmentation additional length + or + DESEGMENT_ONE_MORE_SEGMENT: + Desegment one more full segment + (warning! only partially implemented) + DESEGMENT_UNTIL_FIN: + Desgment all data for this tcp session + until the FIN segment. + */ + guint16 want_pdu_tracking; /* >0 if the subdissector has specified + a value in 'bytes_until_next_pdu'. + When a dissector detects that the next PDU + will start beyond the start of the next + segment, it can set this value to 2 + and 'bytes_until_next_pdu' to the number of + bytes beyond the next segment where the + next PDU starts. + + If the protocol dissector below this + one is capable of PDU tracking it can + use this hint to detect PDUs that starts + unaligned to the segment boundaries. + The TCP dissector is using this hint from + (some) protocols to detect when a new PDU + starts in the middle of a tcp segment. + + There is intelligence in the glue between + dissector layers to make sure that this + request is only passed down to the protocol + immediately below the current one and not + any further. + */ + guint32 bytes_until_next_pdu; + + + int iplen; /* total length of IP packet */ + int iphdrlen; /* length of IP header */ + int p2p_dir; /* Packet was captured as an + outbound (P2P_DIR_SENT) + inbound (P2P_DIR_RECV) + unknown (P2P_DIR_UNKNOWN) */ + guint16 oxid; /* next 2 fields reqd to identify fibre */ + guint16 rxid; /* channel conversations */ + guint8 r_ctl; /* R_CTL field in Fibre Channel Protocol */ + guint8 sof_eof; /* FC's SOF/EOF encoding passed to FC decoder + * Bit 7 set if Last frame in sequence + * Bit 6 set if invalid frame content + * Bit 2 set if SOFf + * Bit 1 set if first frame in sequence + */ + guint16 src_idx; /* Source port index (Cisco MDS-specific) */ + guint16 dst_idx; /* Dest port index (Cisco MDS-specific) */ + guint16 vsan; /* Fibre channel/Cisco MDS-specific */ + + /* Extra data for DCERPC handling and tracking of context ids */ + guint16 dcectxid; /* Context ID (DCERPC-specific) */ + int dcetransporttype; /* Transport type + * Value -1 means "not a DCERPC packet" + */ + guint16 dcetransportsalt; /* fid: if transporttype==DCE_CN_TRANSPORT_SMBPIPE */ + + /* Extra data for handling of decryption of GSSAPI wrapped tvbuffs. + Caller sets decrypt_gssapi_tvb if this service is requested. + If gssapi_encrypted_tvb is NULL, then the rest of the tvb data following + the gssapi blob itself is decrypted othervise the gssapi_encrypted_tvb + tvb will be decrypted (DCERPC has the data before the gssapi blob) + If, on return, gssapi_data_encrypted is FALSE, the wrapped tvbuff + was signed (i.e., an encrypted signature was present, to check + whether the data was modified by a man in the middle) but not sealed + (i.e., the data itself wasn't encrypted). + */ +#define DECRYPT_GSSAPI_NORMAL 1 +#define DECRYPT_GSSAPI_DCE 2 + guint16 decrypt_gssapi_tvb; + tvbuff_t *gssapi_wrap_tvb; + tvbuff_t *gssapi_encrypted_tvb; + tvbuff_t *gssapi_decrypted_tvb; + gboolean gssapi_data_encrypted; + + guint32 ppid[MAX_NUMBER_OF_PPIDS]; /* The first NUMBER_OF_PPIDS PPIDS which are present + * in the SCTP packet + */ + void *private_data; /* pointer to data passed from one dissector to another */ + GString *layer_names; /* layers of each protocol */ + guint16 link_number; + guint8 annex_a_used; + guint16 profinet_type; /* the type of PROFINET packet (0: not a PROFINET packet) */ + void *profinet_conv; /* the PROFINET conversation data (NULL: not a PROFINET packet) */ + void *usb_conv_info; + void *tcp_tree; /* proto_tree for the tcp layer */ + + const char *dcerpc_procedure_name; /* Used by PIDL to store the name of the current dcerpc procedure */ + + struct _sccp_msg_info_t* sccp_info; + guint16 clnp_srcref; /* clnp/cotp source reference (can't use srcport, this would confuse tpkt) */ + guint16 clnp_dstref; /* clnp/cotp destination reference (can't use dstport, this would confuse tpkt) */ +} packet_info; + +#endif /* __PACKET_INFO_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/pint.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/pint.h new file mode 100644 index 00000000..f947a04e --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/pint.h @@ -0,0 +1,113 @@ +/* pint.h + * Definitions for extracting and translating integers safely and portably + * via pointers. + * + * $Id: pint.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PINT_H__ +#define __PINT_H__ + +#include + +/* Pointer versions of g_ntohs and g_ntohl. Given a pointer to a member of a + * byte array, returns the value of the two or four bytes at the pointer. + * The pletoh[sl] versions return the little-endian representation. + */ + +#define pntohs(p) ((guint16) \ + ((guint16)*((const guint8 *)(p)+0)<<8| \ + (guint16)*((const guint8 *)(p)+1)<<0)) + +#define pntoh24(p) ((guint32)*((const guint8 *)(p)+0)<<16| \ + (guint32)*((const guint8 *)(p)+1)<<8| \ + (guint32)*((const guint8 *)(p)+2)<<0) + +#define pntohl(p) ((guint32)*((const guint8 *)(p)+0)<<24| \ + (guint32)*((const guint8 *)(p)+1)<<16| \ + (guint32)*((const guint8 *)(p)+2)<<8| \ + (guint32)*((const guint8 *)(p)+3)<<0) +#define pntoh64(p) ((guint64)*((const guint8 *)(p)+0)<<56| \ + (guint64)*((const guint8 *)(p)+1)<<48| \ + (guint64)*((const guint8 *)(p)+2)<<40| \ + (guint64)*((const guint8 *)(p)+3)<<32| \ + (guint64)*((const guint8 *)(p)+4)<<24| \ + (guint64)*((const guint8 *)(p)+5)<<16| \ + (guint64)*((const guint8 *)(p)+6)<<8| \ + (guint64)*((const guint8 *)(p)+7)<<0) + + +#define pletohs(p) ((guint16) \ + ((guint16)*((const guint8 *)(p)+1)<<8| \ + (guint16)*((const guint8 *)(p)+0)<<0)) + +#define pletoh24(p) ((guint32)*((const guint8 *)(p)+2)<<16| \ + (guint32)*((const guint8 *)(p)+1)<<8| \ + (guint32)*((const guint8 *)(p)+0)<<0) + +#define pletohl(p) ((guint32)*((const guint8 *)(p)+3)<<24| \ + (guint32)*((const guint8 *)(p)+2)<<16| \ + (guint32)*((const guint8 *)(p)+1)<<8| \ + (guint32)*((const guint8 *)(p)+0)<<0) +#define pletoh64(p) ((guint64)*((const guint8 *)(p)+7)<<56| \ + (guint64)*((const guint8 *)(p)+6)<<48| \ + (guint64)*((const guint8 *)(p)+5)<<40| \ + (guint64)*((const guint8 *)(p)+4)<<32| \ + (guint64)*((const guint8 *)(p)+3)<<24| \ + (guint64)*((const guint8 *)(p)+2)<<16| \ + (guint64)*((const guint8 *)(p)+1)<<8| \ + (guint64)*((const guint8 *)(p)+0)<<0) + +/* Pointer routines to put items out in a particular byte order. + * These will work regardless of the byte alignment of the pointer. + */ + +#define phtons(p, v) \ + { \ + ((guint8*)(p))[0] = (guint8)((v) >> 8); \ + ((guint8*)(p))[1] = (guint8)((v) >> 0); \ + } + +#define phtonl(p, v) \ + { \ + ((guint8*)(p))[0] = (guint8)((v) >> 24); \ + ((guint8*)(p))[1] = (guint8)((v) >> 16); \ + ((guint8*)(p))[2] = (guint8)((v) >> 8); \ + ((guint8*)(p))[3] = (guint8)((v) >> 0); \ + } + + +/* Macros to byte-swap 32-bit and 16-bit quantities. */ +#define BSWAP32(x) \ + ((((x)&0xFF000000)>>24) | \ + (((x)&0x00FF0000)>>8) | \ + (((x)&0x0000FF00)<<8) | \ + (((x)&0x000000FF)<<24)) +#define BSWAP16(x) \ + ((((x)&0xFF00)>>8) | \ + (((x)&0x00FF)<<8)) + +/* Turn host-byte-order values into little-endian values. */ +#define htoles(s) GUINT16_TO_LE(s) +#define htolel(l) GUINT32_TO_LE(l) + +#endif /* PINT_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/plugins.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/plugins.h new file mode 100644 index 00000000..100e5805 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/plugins.h @@ -0,0 +1,58 @@ +/* plugins.h + * definitions for plugins structures + * + * $Id: plugins.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1999 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PLUGINS_H__ +#define __PLUGINS_H__ + +#include +#include + +#include "packet.h" + +typedef struct _plugin { + GModule *handle; /* handle returned by dlopen */ + gchar *name; /* plugin name */ + gchar *version; /* plugin version */ + void (*register_protoinfo)(void); /* routine to call to register protocol information */ + void (*reg_handoff)(void); /* routine to call to register dissector handoff */ + void (*register_tap_listener)(void); /* routine to call to register tap listener */ + void (*register_wtap_module)(void); /* routine to call to register a wiretap module */ + void (*register_codec_module)(void); /* routine to call to register a codec */ + struct _plugin *next; /* forward link */ +} plugin; + +WS_VAR_IMPORT plugin *plugin_list; + +extern void init_plugins(void); +extern void register_all_plugin_registrations(void); +extern void register_all_plugin_handoffs(void); +extern void register_all_plugin_tap_listeners(void); +extern void register_all_wiretap_modules(void); +extern void register_all_codecs(void); + +/* get the personal plugin dir */ +/* Return value is g_malloced so the caller should g_free() it. */ +extern char *get_plugins_pers_dir(void); + +#endif /* __PLUGINS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ppptypes.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ppptypes.h new file mode 100644 index 00000000..64bbcb34 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ppptypes.h @@ -0,0 +1,158 @@ +/* ppptypes.h + * Defines PPP packet types. + * + * $Id: ppptypes.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PPPTYPES_H__ +#define __PPPTYPES_H__ + +/* Protocol types, from Linux "ppp_defs.h" and + + http://www.iana.org/assignments/ppp-numbers + + */ +#define PPP_PADDING 0x1 /* Padding Protocol */ +#define PPP_ROHC_SCID 0x3 /* ROHC small-CID */ +#define PPP_ROHC_LCID 0x5 /* ROHC large-CID */ +#define PPP_IP 0x21 /* Internet Protocol */ +#define PPP_OSI 0x23 /* OSI Protocol */ +#define PPP_DEC4 0x25 /* DECnet Phase IV */ +#define PPP_AT 0x29 /* AppleTalk Protocol */ +#define PPP_IPX 0x2b /* IPX protocol */ +#define PPP_VJC_COMP 0x2d /* VJ compressed TCP */ +#define PPP_VJC_UNCOMP 0x2f /* VJ uncompressed TCP */ +#define PPP_BPDU 0x31 /* Bridging PDU (spanning tree BPDU?) */ +#define PPP_ST 0x33 /* Stream Protocol (ST-II) */ +#define PPP_VINES 0x35 /* Banyan Vines */ +#define PPP_AT_EDDP 0x39 /* AppleTalk EDDP */ +#define PPP_AT_SB 0x3b /* AppleTalk SmartBuffered */ +#define PPP_MP 0x3d /* Multilink PPP */ +#define PPP_NB 0x3f /* NETBIOS Framing */ +#define PPP_CISCO 0x41 /* Cisco Systems */ +#define PPP_ASCOM 0x43 /* Ascom Timeplex */ +#define PPP_LBLB 0x45 /* Fujitsu Link Backup and Load Balancing */ +#define PPP_RL 0x47 /* DCA Remote Lan */ +#define PPP_SDTP 0x49 /* Serial Data Transport Protocol */ +#define PPP_LLC 0x4b /* SNA over LLC */ +#define PPP_SNA 0x4d /* SNA */ +#define PPP_IPV6HC 0x4f /* IPv6 Header Compression */ +#define PPP_KNX 0x51 /* KNX Bridging Data */ +#define PPP_ENCRYPT 0x53 /* Encryption */ +#define PPP_ILE 0x55 /* Individual Link Encryption */ +#define PPP_IPV6 0x57 /* Internet Protocol Version 6 */ +#define PPP_MUX 0x59 /* PPP Multiplexing */ +#define PPP_RTP_FH 0x61 /* RTP IPHC Full Header */ +#define PPP_RTP_CTCP 0x63 /* RTP IPHC Compressed TCP */ +#define PPP_RTP_CNTCP 0x65 /* RTP IPHC Compressed Non TCP */ +#define PPP_RTP_CUDP8 0x67 /* RTP IPHC Compressed UDP 8 */ +#define PPP_RTP_CRTP8 0x69 /* RTP IPHC Compressed RTP 8 */ +#define PPP_STAMPEDE 0x6f /* Stampede Bridging */ +#define PPP_MPPLUS 0x73 /* MP+ Protocol */ +#define PPP_NTCITS_IPI 0xc1 /* NTCITS IPI */ +#define PPP_ML_SLCOMP 0xfb /* single link compression in multilink */ +#define PPP_COMP 0xfd /* compressed packet */ +#define PPP_STP_HELLO 0x0201 /* 802.1d Hello Packet */ +#define PPP_IBM_SR 0x0203 /* IBM Source Routing BPDU */ +#define PPP_DEC_LB 0x0205 /* DEC LANBridge100 Spanning Tree */ +#define PPP_CDP 0x0207 /* Cisco Discovery Protocol */ +#define PPP_NETCS 0x0209 /* Netcs Twin Routing */ +#define PPP_STP 0x020b /* Scheduled Transfer Protocol */ +#define PPP_EDP 0x020d /* Extreme Discovery Protocol */ +#define PPP_OSCP 0x0211 /* Optical Supervisory Channel Protocol */ +#define PPP_OSCP2 0x0213 /* Optical Supervisory Channel Protocol */ +#define PPP_LUXCOM 0x0231 /* Luxcom */ +#define PPP_SIGMA 0x0233 /* Sigma Network Systems */ +#define PPP_ACSP 0x0235 /* Apple Client Server Protocol */ +#define PPP_MPLS_UNI 0x0281 /* MPLS Unicast */ +#define PPP_MPLS_MULTI 0x0283 /* MPLS Multicast */ +#define PPP_P12844 0x0285 /* IEEE p1284.4 standard - data packets */ +#define PPP_ETSI 0x0287 /* ETSI TETRA Networks Procotol Type 1 */ +#define PPP_MFTP 0x0289 /* Multichannel Flow Treatment Protocol */ +#define PPP_RTP_CTCPND 0x2063 /* RTP IPHC Compressed TCP No Delta */ +#define PPP_RTP_CS 0x2065 /* RTP IPHC Context State */ +#define PPP_RTP_CUDP16 0x2067 /* RTP IPHC Compressed UDP 16 */ +#define PPP_RTP_CRDP16 0x2069 /* RTP IPHC Compressed RTP 16 */ +#define PPP_CCCP 0x4001 /* Cray Communications Control Protocol */ +#define PPP_CDPD_MNRP 0x4003 /* CDPD Mobile Network Registration Protocol */ +#define PPP_EXPANDAP 0x4005 /* Expand accelarator protocol */ +#define PPP_ODSICP 0x4007 /* ODSICP NCP */ +#define PPP_DOCSIS 0x4009 /* DOCSIS DLL */ +#define PPP_LZS 0x4021 /* Stacker LZS */ +#define PPP_REFTEK 0x4023 /* RefTek Protocol */ +#define PPP_FC 0x4025 /* Fibre Channel */ +#define PPP_EMIT 0x4027 /* EMIT Protocols */ +#define PPP_IPCP 0x8021 /* IP Control Protocol */ +#define PPP_OSICP 0x8023 /* OSI Control Protocol */ +#define PPP_XNSIDPCP 0x8025 /* Xerox NS IDP Control Protocol */ +#define PPP_DECNETCP 0x8027 /* DECnet Phase IV Control Protocol */ +#define PPP_ATCP 0x8029 /* AppleTalk Control Protocol */ +#define PPP_IPXCP 0x802b /* IPX Control Protocol */ +#define PPP_BRIDGENCP 0x8031 /* Bridging NCP */ +#define PPP_SPCP 0x8033 /* Stream Protocol Control Protocol */ +#define PPP_BVCP 0x8035 /* Banyan Vines Control Protocol */ +#define PPP_MLCP 0x803d /* Multi-Link Control Protocol */ +#define PPP_NBCP 0x803f /* NETBIOS Framing Control Protocol */ +#define PPP_CISCOCP 0x8041 /* Cisco Systems Control Protocol */ +#define PPP_ASCOMCP 0x8043 /* Ascom Timeplex Control Protocol (?) */ +#define PPP_LBLBCP 0x8045 /* Fujitsu LBLB Control Protocol */ +#define PPP_RLNCP 0x8047 /* DCA Remote Lan Network Control Protocol */ +#define PPP_SDCP 0x8049 /* Serial Data Control Protocol */ +#define PPP_LLCCP 0x804b /* SNA over LLC Control Protocol */ +#define PPP_SNACP 0x804d /* SNA Control Protocol */ +#define PPP_KNXCP 0x8051 /* KNX Bridging Control Protocol */ +#define PPP_ECP 0x8053 /* Encryption Control Protocol */ +#define PPP_ILECP 0x8055 /* Individual Encryption Control Protocol */ +#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */ +#define PPP_MUXCP 0x8059 /* PPPMux Control Protocol */ +#define PPP_STAMPEDECP 0x806f /* Stampede Bridging Control Protocol */ +#define PPP_MPPCP 0x8073 /* MP+ Contorol Protocol */ +#define PPP_IPICP 0x80c1 /* NTCITS IPI Control Protocol */ +#define PPP_SLCC 0x80fb /* single link compression in multilink control */ +#define PPP_CCP 0x80fd /* Compression Control Protocol */ +#define PPP_CDPCP 0x8207 /* Cisco Discovery Protocol Control Protocol */ +#define PPP_NETCSCP 0x8209 /* Netcs Twin Routing */ +#define PPP_STPCP 0x820b /* STP - Control Protocol */ +#define PPP_EDPCP 0x820d /* Extreme Discovery Protocol Control Protocol */ +#define PPP_ACSPC 0x8235 /* Apple Client Server Protocol Control */ +#define PPP_MPLSCP 0x8281 /* MPLS Control Protocol */ +#define PPP_P12844CP 0x8285 /* IEEE p1284.4 standard - Protocol Control */ +#define PPP_ETSICP 0x8287 /* ETSI TETRA TNP1 Control Protocol */ +#define PPP_MFTPCP 0x8287 /* Multichannel Flow Treatment Protocol */ +#define PPP_LCP 0xc021 /* Link Control Protocol */ +#define PPP_PAP 0xc023 /* Password Authentication Protocol */ +#define PPP_LQR 0xc025 /* Link Quality Report protocol */ +#define PPP_SPAP 0xc027 /* Shiva Password Authentication Protocol */ +#define PPP_CBCP 0xc029 /* CallBack Control Protocol */ +#define PPP_BACP 0xc02b /* Bandwidth Allocation Control Protocol */ +#define PPP_BAP 0xc02d /* Bandwidth Allocation Protocol */ +#define PPP_CONTCP 0xc081 /* Container Control Protocol */ +#define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */ +#define PPP_RSAAP 0xc225 /* RSA Authentication Protocol */ +#define PPP_EAP 0xc227 /* Extensible Authentication Protocol */ +#define PPP_SIEP 0xc229 /* Mitsubishi Security Information Exchange Protocol*/ +#define PPP_SBAP 0xc26f /* Stampede Bridging Authorization Protocol */ +#define PPP_PRPAP 0x281 /* Proprietary Authentication Protocol */ +#define PPP_PRPAP2 0x283 /* Proprietary Authentication Protocol */ +#define PPP_PRPNIAP 0x481 /* Proprietary Node ID Authentication Protocol */ + +#endif /* ppptypes.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/prefs-int.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/prefs-int.h new file mode 100644 index 00000000..3f54c931 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/prefs-int.h @@ -0,0 +1,111 @@ +/* prefs-int.h + * Definitions for implementation of preference handling routines; + * used by "friends" of the preferences type. + * + * $Id: prefs-int.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PREFS_INT_H__ +#define __PREFS_INT_H__ + +struct pref_module { + const char *name; /* name of module */ + const char *title; /* title of module (displayed in preferences list) */ + const char *description;/* Description of module (displayed in preferences notebook) */ + void (*apply_cb)(void); /* routine to call when preferences applied */ + GList *prefs; /* list of its preferences */ + emem_tree_t *submodules;/* list of its submodules */ + int numprefs; /* number of non-obsolete preferences */ + gboolean prefs_changed; /* if TRUE, a preference has changed since we last checked */ + gboolean obsolete; /* if TRUE, this is a module that used to + exist but no longer does */ +}; + +/* + * Module used for protocol preferences. + * With MSVC and a libwireshark.dll, we need a special declaration. + */ +WS_VAR_IMPORT module_t *protocols_module; + +/* + * PREF_OBSOLETE is used for preferences that a module used to support + * but no longer supports; we give different error messages for them. + */ +typedef enum { + PREF_UINT, + PREF_BOOL, + PREF_ENUM, + PREF_STRING, + PREF_RANGE, + PREF_STATIC_TEXT, + PREF_UAT, + PREF_OBSOLETE +} pref_type_t; + +struct preference { + const char *name; /* name of preference */ + const char *title; /* title to use in GUI */ + const char *description; /* human-readable description of preference */ + int ordinal; /* ordinal number of this preference */ + pref_type_t type; /* type of that preference */ + union { + guint *uint; + gboolean *boolp; + gint *enump; + const char **string; + range_t **range; + void* uat; + } varp; /* pointer to variable storing the value */ + union { + guint uint; + gboolean boolval; + gint enumval; + char *string; + range_t *range; + } saved_val; /* original value, when editing from the GUI */ + union { + guint base; /* input/output base, for PREF_UINT */ + guint32 max_value; /* maximum value of a range */ + struct { + const enum_val_t *enumvals; /* list of name & values */ + gboolean radio_buttons; /* TRUE if it should be shown as + radio buttons rather than as an + option menu or combo box in + the preferences tab */ + } enum_info; /* for PREF_ENUM */ + } info; /* display/text file information */ + void *control; /* handle for GUI control for this preference */ +}; + +gint find_val_for_string(const char *needle, const enum_val_t *haystack, + gint default_value); + + +/* read_prefs_file: read in a generic config file and do a callback to */ +/* pref_set_pair_fct() for every key/value pair found */ +typedef prefs_set_pref_e (*pref_set_pair_cb) (gchar *key, gchar *value, void *private_data); + +int +read_prefs_file(const char *pf_path, FILE *pf, pref_set_pair_cb pref_set_pair_fct, void *private_data); + + + +#endif /* prefs-int.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/prefs.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/prefs.h new file mode 100644 index 00000000..3f2ab2c9 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/prefs.h @@ -0,0 +1,426 @@ +/* prefs.h + * Definitions for preference handling routines + * + * $Id: prefs.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PREFS_H__ +#define __PREFS_H__ + +#include + +#include "color.h" + +#include + +#define PR_DEST_CMD 0 +#define PR_DEST_FILE 1 + +#define DEF_WIDTH 750 +#define DEF_HEIGHT 550 + +#define MAX_VAL_LEN 1024 + +#define RTP_PLAYER_DEFAULT_VISIBLE 4 + +/* only GTK1 *or* GTK2 font_name should be used */ +/* (we need to keep both in the preferences file but will only use the one suitable for the programs GTK version used) */ +#if GTK_MAJOR_VERSION < 2 +#define PREFS_GUI_FONT_NAME gui_font_name1 +#else +#define PREFS_GUI_FONT_NAME gui_font_name2 +#endif + +/* + * Convert a string listing name resolution types to a bitmask of + * those types. + * + * Set "*name_resolve" to the bitmask, and return '\0', on success; + * return the bad character in the string on error. + */ +char string_to_name_resolve(char *string, guint32 *name_resolve); + +/* + * Modes for the starting directory in File Open dialogs. + */ +#define FO_STYLE_LAST_OPENED 0 /* start in last directory we looked at */ +#define FO_STYLE_SPECIFIED 1 /* start in specified directory */ + +/* + * Toolbar styles. + */ +#define TB_STYLE_ICONS 0 +#define TB_STYLE_TEXT 1 +#define TB_STYLE_BOTH 2 + +/* + * Types of layout of summary/details/hex panes. + */ +typedef enum { + layout_unused, /* entry currently unused */ + layout_type_5, + layout_type_2, + layout_type_1, + layout_type_4, + layout_type_3, + layout_type_6, + layout_type_max +} layout_type_e; + +/* + * Types of pane. + */ +typedef enum { + layout_pane_content_none, + layout_pane_content_plist, + layout_pane_content_pdetails, + layout_pane_content_pbytes +} layout_pane_content_e; + +/* + * open console behaviour (win32 only) + */ +typedef enum { + console_open_never, + console_open_auto, + console_open_always +} console_open_e; + + +typedef struct _e_prefs { + gint pr_format; + gint pr_dest; + gchar *pr_file; + gchar *pr_cmd; + GList *col_list; + gint num_cols; + color_t st_client_fg, st_client_bg, st_server_fg, st_server_bg; + gboolean gui_scrollbar_on_right; + gboolean gui_plist_sel_browse; + gboolean gui_ptree_sel_browse; + gboolean gui_altern_colors; + gboolean filter_toolbar_show_in_statusbar; + gint gui_ptree_line_style; + gint gui_ptree_expander_style; + gboolean gui_hex_dump_highlight_style; + gint gui_toolbar_main_style; + gchar *gui_font_name1; + gchar *gui_font_name2; + color_t gui_marked_fg; + color_t gui_marked_bg; + gchar *gui_colorized_fg; + gchar *gui_colorized_bg; + gboolean gui_geometry_save_position; + gboolean gui_geometry_save_size; + gboolean gui_geometry_save_maximized; + console_open_e gui_console_open; + guint gui_recent_files_count_max; + guint gui_fileopen_style; + gchar *gui_fileopen_dir; + guint gui_fileopen_preview; + gboolean gui_ask_unsaved; + gboolean gui_find_wrap; + gboolean gui_use_pref_save; + gchar *gui_webbrowser; + gchar *gui_window_title; + layout_type_e gui_layout_type; + layout_pane_content_e gui_layout_content_1; + layout_pane_content_e gui_layout_content_2; + layout_pane_content_e gui_layout_content_3; + gint console_log_level; + guint32 name_resolve; + gint name_resolve_concurrency; + gchar *capture_device; + gchar *capture_devices_descr; + gchar *capture_devices_hide; + gboolean capture_prom_mode; + gboolean capture_real_time; + gboolean capture_auto_scroll; + gboolean capture_show_info; + guint rtp_player_max_visible; +} e_prefs; + +WS_VAR_IMPORT e_prefs prefs; + +/* + * Routines to let modules that have preference settings register + * themselves by name, and to let them register preference settings + * by name. + */ +struct pref_module; + +typedef struct pref_module module_t; + +/** Sets up memory used by proto routines. Called at program startup */ +extern void prefs_init(void); + +/** Reset preferences to default values. Called at profile change */ +extern void prefs_reset(void); + +/** Frees memory used by proto routines. Called at program shutdown */ +extern void prefs_cleanup(void); + +/* + * Register a module that will have preferences. + * Specify the module under which to register it or NULL to register it + * at the top level, the name used for the module in the preferences file, + * the title used in the tab for it in a preferences dialog box, and a + * routine to call back when we apply the preferences. + * + * This should not be used for dissector preferences; + * "prefs_register_protocol()" should be used for that, so that the + * preferences go under the "Protocols" subtree, and so that the + * name is the protocol name specified at the "proto_register_protocol()" + * call so that the "Protocol Properties..." menu item works. + */ +extern module_t *prefs_register_module(module_t *parent, const char *name, + const char *title, const char *description, void (*apply_cb)(void)); + +/* + * Register a subtree that will have modules under it. + * Specify the module under which to register it or NULL to register it + * at the top level and the title used in the tab for it in a preferences + * dialog box. + */ +extern module_t *prefs_register_subtree(module_t *parent, const char *title, + const char *description); + +/* + * Register that a protocol has preferences. + */ +extern module_t *prefs_register_protocol(int id, void (*apply_cb)(void)); + +/* + * Register that a protocol has preferences and group it under a single + * subtree + */ +#define PREFERENCE_GROUPING +extern module_t *prefs_register_protocol_subtree(const char *subtree, int id, + void (*apply_cb)(void)); + +/* + * Register that a protocol used to have preferences but no longer does, + * by creating an "obsolete" module for it. + */ +extern module_t *prefs_register_protocol_obsolete(int id); + +/* + * Callback function for module list scanners. + */ +typedef guint (*module_cb)(module_t *module, gpointer user_data); + +/* + * Returns TRUE if module has any submodules + */ +extern gboolean prefs_module_has_submodules(module_t *module); + +/* + * Call a callback function, with a specified argument, for each module + * in the list of all modules. (This list does not include subtrees.) + * + * Ignores "obsolete" modules; their sole purpose is to allow old + * preferences for dissectors that no longer have preferences to be + * silently ignored in preference files. + */ +extern guint prefs_modules_foreach(module_cb callback, gpointer user_data); + +/* + * Call a callback function, with a specified argument, for each submodule + * of specified modules. If the module is NULL, goes through the top-level + * list in the display tree of modules. + * + * Ignores "obsolete" modules; their sole purpose is to allow old + * preferences for dissectors that no longer have preferences to be + * silently ignored in preference files. Does not ignore subtrees, + * as this can be used when walking the display tree of modules. + */ +extern guint prefs_modules_foreach_submodules(module_t *module, module_cb callback, gpointer user_data); + +/* + * Call the "apply" callback function for each module if any of its + * preferences have changed, and then clear the flag saying its + * preferences have changed, as the module has been notified of that + * fact. + */ +extern void prefs_apply_all(void); + +/* + * Call the "apply" callback function for a specific module if any of + * its preferences have changed, and then clear the flag saying its + * preferences have changed, as the module has been notified of that + * fact. + */ +extern void prefs_apply(module_t *module); + + +struct preference; + +typedef struct preference pref_t; + +/* + * Returns TRUE if the given protocol has registered preferences. + */ +extern gboolean prefs_is_registered_protocol(const char *name); + +/* + * Returns the module title of a registered protocol (or NULL if unknown). + */ +extern const char *prefs_get_title_by_name(const char *name); + +/** Given a module name, return a pointer to its pref_module struct, + * or NULL if it's not found. + * + * @param name The preference module name. Usually the same as the protocol + * name, e.g. "tcp". + * @return A pointer to the corresponding preference module, or NULL if it + * wasn't found. + */ +extern module_t *prefs_find_module(const char *name); + +/* + * Register a preference with an unsigned integral value. + */ +extern void prefs_register_uint_preference(module_t *module, const char *name, + const char *title, const char *description, guint base, guint *var); + +/* + * Register a preference with an Boolean value. + * Note that the name must be in lowercase letters only (underscore allowed). + */ +extern void prefs_register_bool_preference(module_t *module, const char *name, + const char *title, const char *description, gboolean *var); + +/* + * Register a preference with an enumerated value. + */ +typedef struct { + const char *name; + const char *description; + gint value; +} enum_val_t; + +extern void prefs_register_enum_preference(module_t *module, const char *name, + const char *title, const char *description, gint *var, + const enum_val_t *enumvals, gboolean radio_buttons); + +/* + * Register a preference with a character-string value. + */ +extern void prefs_register_string_preference(module_t *module, const char *name, + const char *title, const char *description, const char **var); + +/* + * Register a preference with a ranged value. + */ +extern void prefs_register_range_preference(module_t *module, const char *name, + const char *title, const char *description, range_t **var, + guint32 max_value); + +/* + * Register a static text 'preference'. It can be used to add some info/explanation. + */ +extern void prefs_register_static_text_preference(module_t *module, const char *name, + const char *title, const char *description); + +/* + * Register a uat 'preference'. It adds a button that opens the uat's window in the + * preferences tab of the module. + */ +extern void prefs_register_uat_preference(module_t *module, + const char *name, + const char* title, + const char *description, + void* uat); + +/* + * Register a preference that used to be supported but no longer is. + */ +extern void prefs_register_obsolete_preference(module_t *module, + const char *name); + +typedef guint (*pref_cb)(pref_t *pref, gpointer user_data); + +/* + * Call a callback function, with a specified argument, for each preference + * in a given module. + * + * If any of the callbacks return a non-zero value, stop and return that + * value, otherwise return 0. + */ +extern guint prefs_pref_foreach(module_t *module, pref_cb callback, + gpointer user_data); + +/* + * Register all non-dissector modules' preferences. + */ +extern void prefs_register_modules(void); + +/* Read the preferences file, fill in "prefs", and return a pointer to it. + + If we got an error (other than "it doesn't exist") trying to read + the global preferences file, stuff the errno into "*gpf_errno_return" + on an open error and into "*gpf_read_errno_return" on a read error, + stuff a pointer to the path of the file into "*gpf_path_return", and + return NULL. + + If we got an error (other than "it doesn't exist") trying to read + the user's preferences file, stuff the errno into "*pf_errno_return" + on an open error and into "*pf_read_errno_return" on a read error, + stuff a pointer to the path of the file into "*pf_path_return", and + return NULL. */ +extern e_prefs *read_prefs(int *, int *, char **, int *, int *, char **); + +/* Write out "prefs" to the user's preferences file, and return 0. + + If we got an error, stuff a pointer to the path of the preferences file + into "*pf_path_return", and return the errno. */ +extern int write_prefs(char **); + +/* Copy a set of preferences. */ +extern void copy_prefs(e_prefs *dest, e_prefs *src); + +/* Free a set of preferences. */ +extern void free_prefs(e_prefs *pr); + +/* + * Given a string of the form ":", as might appear + * as an argument to a "-o" option, parse it and set the preference in + * question. Return an indication of whether it succeeded or failed + * in some fashion. + * + * XXX - should supply, for syntax errors, a detailed explanation of + * the syntax error. + */ +typedef enum { + PREFS_SET_OK, /* succeeded */ + PREFS_SET_SYNTAX_ERR, /* syntax error in string */ + PREFS_SET_NO_SUCH_PREF, /* no such preference */ + PREFS_SET_OBSOLETE /* preference used to exist but no longer does */ +} prefs_set_pref_e; + +extern prefs_set_pref_e prefs_set_pref(char *prefarg); + +/* + * Returns TRUE if the given device is hidden + */ +extern gboolean prefs_is_capture_device_hidden(const char *name); + +#endif /* prefs.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/privileges.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/privileges.h new file mode 100644 index 00000000..8a0b0ecf --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/privileges.h @@ -0,0 +1,74 @@ +/* privileges.h + * Declarations of routines for handling privileges. + * + * $Id: privileges.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2006 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/** + * Called when the program starts, to save whatever credential information + * we'll need later. + */ +extern void get_credential_info(void); + +/** + * Was this program started with special privileges? get_credential_info() + * MUST be called before calling this. + * @return TRUE if the program was started with special privileges, + * FALSE otherwise. + */ +extern gboolean started_with_special_privs(void); + +/** + * Is this program running with special privileges? get_credential_info() + * MUST be called before calling this. + * @return TRUE if the program is running with special privileges, + * FALSE otherwise. + */ +extern gboolean running_with_special_privs(void); + +/** + * Permanently relinquish special privileges. get_credential_info() + * MUST be called before calling this. + */ +extern void relinquish_special_privs_perm(void); + +/** + * Get the current username. String must be g_free()d after use. + * @return A freshly g_alloc()ed string containing the username, + * or "UNKNOWN" on failure. + */ +extern gchar *get_cur_username(void); + +/** + * Get the current group. String must be g_free()d after use. + * @return A freshly g_alloc()ed string containing the group, + * or "UNKNOWN" on failure. + */ +extern gchar *get_cur_groupname(void); + +#ifdef _WIN32 +/** + * Check to see if npf.sys is running. + * @return TRUE if npf.sys is running, FALSE if it's not or if there was + * an error checking its status. + */ +extern gboolean npf_sys_is_running(); +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/proto.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/proto.h new file mode 100644 index 00000000..f20845fb --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/proto.h @@ -0,0 +1,1655 @@ +/* proto.h + * Definitions for protocol display + * + * $Id: proto.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +/*! @file proto.h + The protocol tree related functions.
+ A protocol tree will hold all necessary data to display the whole dissected packet. + Creating a protocol tree is done in a two stage process: + A static part at program startup, and a dynamic part when the dissection with the real packet data is done.
+ The "static" information is provided by creating a hf_register_info hf[] array, and register it using the + proto_register_field_array() function. This is usually done at dissector registering.
+ The "dynamic" information is added to the protocol tree by calling one of the proto_tree_add_...() functions, + e.g. proto_tree_add_bytes(). +*/ + +#ifndef __PROTO_H__ +#define __PROTO_H__ + +#ifdef HAVE_STDARG_H +# include +#else +# include +#endif + +#include + +#include "gnuc_format_check.h" +#include "ipv4.h" +#include "nstime.h" +#include "tvbuff.h" +#include "ftypes/ftypes.h" +#include "register.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** The header-field index for the special text pseudo-field. Exported by libwireshark.dll */ +WS_VAR_IMPORT int hf_text_only; + +/** the maximum length of a protocol field string representation */ +#define ITEM_LABEL_LENGTH 240 + +struct _value_string; + +/** Make a const value_string[] look like a _value_string pointer, used to set header_field_info.strings */ +#define VALS(x) (const struct _value_string*)(x) + +/** Make a const true_false_string[] look like a _true_false_string pointer, used to set header_field_info.strings */ +#define TFS(x) (const struct true_false_string*)(x) + +/** Make a const range_string[] look like a _range_string pointer, used to set + * header_field_info.strings */ +#define RVALS(x) (const struct _range_string*)(x) + +struct _protocol; + +/** Structure for information about a protocol */ +typedef struct _protocol protocol_t; + +/** check protocol activation + * @todo this macro looks like a hack */ +#define CHECK_DISPLAY_AS_X(x_handle,index, tvb, pinfo, tree) { \ + if (!proto_is_protocol_enabled(find_protocol_by_id(index))) { \ + call_dissector(x_handle,tvb, pinfo, tree); \ + return; \ + } \ + } + +/** Macro used for reporting errors in dissectors; it throws a + * DissectorError exception, with the string passed as an argument + * as the message for the exception, so that it can show up in + * the Info column and the protocol tree. + * + * If that string is dynamically allocated, it should be allocated with + * ep_alloc(); using ep_strdup_printf() would work. + * + * If the WIRESHARK_ABORT_ON_DISSECTOR_BUG environment variable is set, + * it will call abort(), instead, to make it easier to get a stack trace. + * + * @param message string to use as the message + */ +#define REPORT_DISSECTOR_BUG(message) \ + ((getenv("WIRESHARK_ABORT_ON_DISSECTOR_BUG") != NULL) ? \ + abort() : \ + THROW_MESSAGE(DissectorError, message)) + +/** Macro used for assertions in dissectors; it doesn't abort, it just + * throws a DissectorError exception, with the assertion failure + * message as a parameter, so that it can show up in the protocol tree. + * + * @param expression expression to test in the assertion + */ +#define DISSECTOR_ASSERT(expression) \ + ((void) ((expression) ? (void)0 : \ + __DISSECTOR_ASSERT (expression, __FILE__, __LINE__))) + +#if 0 +/* win32: using a debug breakpoint (int 3) can be very handy while debugging, + * as the assert handling of GTK/GLib is currently not very helpful */ +#define DISSECTOR_ASSERT(expression) \ +{ if(!(expression)) _asm { int 3}; } +#endif + +/** Same as DISSECTOR_ASSERT(), but will throw DissectorError exception + * unconditionally, much like GLIB's g_assert_not_reached works. + */ +#define DISSECTOR_ASSERT_NOT_REACHED() \ + (REPORT_DISSECTOR_BUG( \ + ep_strdup_printf("%s:%u: failed assertion \"DISSECTOR_ASSERT_NOT_REACHED\"", \ + __FILE__, __LINE__))) + +#define __DISSECTOR_ASSERT_STRINGIFY(s) # s + +#define __DISSECTOR_ASSERT(expression, file, lineno) \ + (REPORT_DISSECTOR_BUG( \ + ep_strdup_printf("%s:%u: failed assertion \"%s\"", \ + file, lineno, __DISSECTOR_ASSERT_STRINGIFY(expression)))) + +/* BASE_STRUCTURE_RESET constant is used in proto.c to reset the bits + * identifying special structures used in translation of value for display. + * Its value means that we may have at most 16 base_display_e values */ +#define BASE_STRUCTURE_RESET 0x0F +/* Following constants have to be ORed with a base_display_e when dissector + * want to use specials MACROs (for the moment, only RVALS) for a + * header_field_info */ +#define BASE_RANGE_STRING 0x10 +/** radix for decimal values, used in header_field_info.display */ +typedef enum { + BASE_NONE, /**< none */ + BASE_DEC, /**< decimal */ + BASE_HEX, /**< hexadecimal */ + BASE_OCT, /**< octal */ + BASE_DEC_HEX, /**< decimal (hexadecimal) */ + BASE_HEX_DEC /**< hexadecimal (decimal) */ +} base_display_e; + +#define IS_BASE_DUAL(b) ((b)==BASE_DEC_HEX||(b)==BASE_HEX_DEC) + +/** information describing a header field */ +typedef struct _header_field_info header_field_info; + +/** information describing a header field */ +struct _header_field_info { + /* ---------- set by dissector --------- */ + const char *name; /**< full name of this field */ + const char *abbrev; /**< abbreviated name of this field */ + enum ftenum type; /**< field type, one of FT_ (from ftypes.h) */ + int display; /**< one of BASE_, or number of field bits for FT_BOOLEAN */ + const void *strings; /**< value_string, range_string or true_false_string, + typically converted by VALS(), RVALS() or TFS(). + If this is an FT_PROTOCOL then it points to the + associated protocol_t structure */ + guint32 bitmask; /**< bitmask of interesting bits */ + const char *blurb; /**< Brief description of field */ + + /* ------- set by proto routines (prefilled by HFILL macro, see below) ------ */ + int id; /**< Field ID */ + int parent; /**< parent protocol tree */ + int ref_count; /**< is this field referenced by a filter and how often */ + int bitshift; /**< bits to shift */ + header_field_info *same_name_next; /**< Link to next hfinfo with same abbrev */ + header_field_info *same_name_prev; /**< Link to previous hfinfo with same abbrev */ +}; + +/** + * HFILL initializes all the "set by proto routines" fields in a + * _header_field_info. If new fields are added or removed, it should + * be changed as necessary. + */ +#define HFILL 0, 0, 0, 0, NULL, NULL + +/** Used when registering many fields at once, using proto_register_field_array() */ +typedef struct hf_register_info { + int *p_id; /**< written to by register() function */ + header_field_info hfinfo; /**< the field info to be registered */ +} hf_register_info; + + + + +/** string representation, if one of the proto_tree_add_..._format() functions used */ +typedef struct _item_label_t { + char representation[ITEM_LABEL_LENGTH]; +} item_label_t; + + +/** Contains the field information for the proto_item. */ +typedef struct field_info { + header_field_info *hfinfo; /**< pointer to registered field information */ + gint start; /**< current start of data in field_info.ds_tvb */ + gint length; /**< current data length of item in field_info.ds_tvb */ + gint appendix_start; /**< start of appendix data */ + gint appendix_length; /**< length of appendix data */ + gint tree_type; /**< one of ETT_ or -1 */ + item_label_t *rep; /**< string for GUI tree */ + guint32 flags; /**< bitfield like FI_GENERATED, ... */ + tvbuff_t *ds_tvb; /**< data source tvbuff */ + fvalue_t value; +} field_info; + + +/* + * Flag fields. Do not assign values greater than 0x00000080 unless you + * shuffle the expert information upward; see below. + */ + +/** The protocol field should not be shown in the tree (it's used for filtering only), + * used in field_info.flags. */ +/* HIDING PROTOCOL FIELDS IS DEPRECATED, IT'S CONSIDERED TO BE BAD GUI DESIGN! */ +#define FI_HIDDEN 0x00000001 +/** The protocol field should be displayed as "generated by Wireshark", + * used in field_info.flags. */ +#define FI_GENERATED 0x00000002 +/** The protocol field is actually a URL */ +#define FI_URL 0x00000004 + + +/** convenience macro to get field_info.flags */ +#define FI_GET_FLAG(fi, flag) (fi->flags & flag) +/** convenience macro to set field_info.flags */ +#define FI_SET_FLAG(fi, flag) (fi->flags = fi->flags | flag) + +/** One of these exists for the entire protocol tree. Each proto_node + * in the protocol tree points to the same copy. */ +typedef struct { + GHashTable *interesting_hfids; + gboolean visible; + gint count; +} tree_data_t; + +/** Each proto_tree, proto_item is one of these. */ +typedef struct _proto_node { + struct _proto_node *first_child; + struct _proto_node *last_child; + struct _proto_node *next; + struct _proto_node *parent; + field_info *finfo; + tree_data_t *tree_data; +} proto_node; + +/** A protocol tree element. */ +typedef proto_node proto_tree; +/** A protocol item element. */ +typedef proto_node proto_item; + +/* + * Expert information. + * This is in the flags field; we allocate this from the top down, + * so as not to collide with FI_ flags, which are allocated from + * the bottom up. + */ + +/* expert severities */ +#define PI_SEVERITY_MASK 0x00000E00 /* mask usually for internal use only! */ +/** Usual workflow, e.g. TCP connection establishing */ +#define PI_CHAT 0x00000200 +/** Notable messages, e.g. an application returned an "usual" error code like HTTP 404 */ +#define PI_NOTE 0x00000400 +/** Warning, e.g. application returned an "unusual" error code */ +#define PI_WARN 0x00000600 +/** Serious problems, e.g. [Malformed Packet] */ +#define PI_ERROR 0x00000800 + +/* expert "event groups" */ +#define PI_GROUP_MASK 0xFFFFF000 /* mask usually for internal use only! */ +/** The protocol field has a bad checksum, usually PI_WARN */ +#define PI_CHECKSUM 0x00001000 +/** The protocol field indicates a sequence problem (e.g. TCP window is zero) */ +#define PI_SEQUENCE 0x00002000 +/** The protocol field indicates a bad application response code (e.g. HTTP 404), usually PI_NOTE */ +#define PI_RESPONSE_CODE 0x00004000 +/** The protocol field indicates an application request (e.g. File Handle == xxxx), usually PI_CHAT */ +#define PI_REQUEST_CODE 0x00005000 +/** The data is undecoded, the protocol dissection is incomplete here, usually PI_WARN */ +#define PI_UNDECODED 0x00008000 +/** The protocol field indicates a reassemble (e.g. DCE/RPC defragmentation), usually PI_CHAT (or PI_ERROR) */ +#define PI_REASSEMBLE 0x00010000 +/** The packet data is malformed, the dissector has "given up", usually PI_ERROR */ +#define PI_MALFORMED 0x00020000 +/** A generic debugging message (shouldn't remain in production code!), usually PI_ERROR */ +#define PI_DEBUG 0x00040000 +/* The protocol field indicates a security probem (e.g. unsecure implementation) */ +/*#define PI_SECURITY 0x00080000*/ + +/* add more, see http://wiki.wireshark.org/Development/ExpertInfo */ + + +/** is this protocol field hidden from the protocol tree display (used for filtering only)? */ +/* HIDING PROTOCOL FIELDS IS DEPRECATED, IT'S CONSIDERED TO BE BAD GUI DESIGN! */ +#define PROTO_ITEM_IS_HIDDEN(proto_item) \ + ((proto_item) ? FI_GET_FLAG((proto_item)->finfo, FI_HIDDEN) : 0) +/** mark this protocol field to be hidden from the protocol tree display (used for filtering only) */ +/* HIDING PROTOCOL FIELDS IS DEPRECATED, IT'S CONSIDERED TO BE BAD GUI DESIGN! */ +#define PROTO_ITEM_SET_HIDDEN(proto_item) \ + ((proto_item) ? FI_SET_FLAG((proto_item)->finfo, FI_HIDDEN) : 0) +/** is this protocol field generated by Wireshark (and not read from the packet data)? */ +#define PROTO_ITEM_IS_GENERATED(proto_item) \ + ((proto_item) ? FI_GET_FLAG((proto_item)->finfo, FI_GENERATED) : 0) +/** mark this protocol field as generated by Wireshark (and not read from the packet data) */ +#define PROTO_ITEM_SET_GENERATED(proto_item) \ + ((proto_item) ? FI_SET_FLAG((proto_item)->finfo, FI_GENERATED) : 0) +/** is this protocol field actually a URL? */ +#define PROTO_ITEM_IS_URL(proto_item) \ + ((proto_item) ? FI_GET_FLAG((proto_item)->finfo, FI_URL) : 0) +/** mark this protocol field as a URL */ +#define PROTO_ITEM_SET_URL(proto_item) \ + ((proto_item) ? FI_SET_FLAG((proto_item)->finfo, FI_URL) : 0) + +typedef void (*proto_tree_foreach_func)(proto_node *, gpointer); +typedef gboolean (*proto_tree_traverse_func)(proto_node *, gpointer); + +extern gboolean proto_tree_traverse_in_order(proto_tree *tree, + proto_tree_traverse_func func, gpointer data); +extern void proto_tree_children_foreach(proto_tree *tree, + proto_tree_foreach_func func, gpointer data); + +/** Retrieve the field_info from a proto_item */ +#define PITEM_FINFO(proto_item) ((proto_item)->finfo) + +/** Retrieve the tree_data_t from a proto_tree */ +#define PTREE_DATA(proto_tree) ((proto_tree)->tree_data) + +/** Sets up memory used by proto routines. Called at program startup */ +extern void proto_init(void (register_all_protocols)(register_cb cb, gpointer client_data), + void (register_all_handoffs)(register_cb cb, gpointer client_data), + register_cb cb, void *client_data); + + +/** Frees memory used by proto routines. Called at program shutdown */ +extern void proto_cleanup(void); + +/** This function takes a tree and a protocol id as parameter and + will return TRUE/FALSE for whether the protocol or any of the filterable + fields in the protocol is referenced by any fitlers. + If this function returns FALSE then it is safe to skip any + proto_tree_add_...() calls and just treat the call as if the + dissector was called with tree==NULL. + If you reset the tree to NULL by this dissector returning FALSE, + you will still need to call any subdissector with the original value of + tree or filtering will break. + + The purpose of this is to optimize wireshark for speed and make it + faster for when filters are being used. +*/ +extern gboolean proto_field_is_referenced(proto_tree *tree, int proto_id); + + + +/** Create a subtree under an existing item. + @param ti the parent item of the new subtree + @param idx one of the ett_ array elements registered with proto_register_subtree_array() + @return the new subtree */ +extern proto_tree* proto_item_add_subtree(proto_item *ti, gint idx); + +/** Get an existing subtree under an item. + @param ti the parent item of the subtree + @return the subtree or NULL */ +extern proto_tree* proto_item_get_subtree(proto_item *ti); + +/** Get the parent of a subtree item. + @param ti the child item in the subtree + @return parent item or NULL */ +extern proto_item* proto_item_get_parent(proto_item *ti); + +/** Get Nth generation parent item. + @param ti the child item in the subtree + @param gen the generation to get (using 1 here is the same as using proto_item_get_parent()) + @return parent item */ +extern proto_item* proto_item_get_parent_nth(proto_item *ti, int gen); + +/** Replace text of item after it already has been created. + @param ti the item to set the text + @param format printf like format string + @param ... printf like parameters */ +extern void proto_item_set_text(proto_item *ti, const char *format, ...) + GNUC_FORMAT_CHECK(printf, 2,3); + +/** Append to text of item after it has already been created. + @param ti the item to append the text to + @param format printf like format string + @param ... printf like parameters */ +extern void proto_item_append_text(proto_item *ti, const char *format, ...) + GNUC_FORMAT_CHECK(printf, 2,3); + +/** Set proto_item's length inside tvb, after it has already been created. + @param ti the item to set the length + @param length the new length ot the item */ +extern void proto_item_set_len(proto_item *ti, gint length); + +/** + * Sets the length of the item based on its start and on the specified + * offset, which is the offset past the end of the item; as the start + * in the item is relative to the beginning of the data source tvbuff, + * we need to pass in a tvbuff. + @param ti the item to set the length + @param tvb end is relative to this tvbuff + @param end this end offset is relative to the beginning of tvb + @todo make usage clearer, I don't understand it! + */ +extern void proto_item_set_end(proto_item *ti, tvbuff_t *tvb, gint end); + +/** Get length of a proto_item. Useful after using proto_tree_add_item() + * to add a variable-length field (e.g., FT_NSTRING_UINT8). + @param ti the item to get the length from + @return the current length */ +extern int proto_item_get_len(proto_item *ti); + +/** + * Sets an expert info to the proto_item. + @param ti the item to set the expert info + @param group the group of this info (e.g. PI_CHECKSUM) + @param severity of this info (e.g. PI_ERROR) + @return TRUE if value was written + */ +extern gboolean proto_item_set_expert_flags(proto_item *ti, int group, guint severity); + + + + +/** Creates a new proto_tree root. + @return the new tree root */ +extern proto_tree* proto_tree_create_root(void); + +/** Clear memory for entry proto_tree. Clears proto_tree struct also. + @param tree the tree to free */ +extern void proto_tree_free(proto_tree *tree); + +/** Set the tree visible or invisible. + Is the parsing being done for a visible proto_tree or an invisible one? + By setting this correctly, the proto_tree creation is sped up by not + having to call g_vsnprintf and copy strings around. + @param tree the tree to be set + @param visible ... or not */ +extern void +proto_tree_set_visible(proto_tree *tree, gboolean visible); + +/** Mark a field/protocol ID as "interesting". + @param tree the tree to be set + @param hfid the interesting field id + @todo what *does* interesting mean? */ +extern void +proto_tree_prime_hfid(proto_tree *tree, int hfid); + +/** Get a parent item of a subtree. + @param tree the tree to get the parent from + @return parent item */ +extern proto_item* proto_tree_get_parent(proto_tree *tree); + +/** Get the root tree from any subtree. + @param tree the tree to get the root from + @return root tree */ +extern proto_tree* proto_tree_get_root(proto_tree *tree); + +/** Move an existing item behind another existing item. + @param tree the tree to which both items belong + @param fixed_item the item which keeps it's position + @param item_to_move the item which will be moved */ +extern void proto_tree_move_item(proto_tree *tree, proto_item *fixed_item, proto_item *item_to_move); + + +/** Set start and length of an appendix for a proto_tree. + @param tree the tree to set the appendix start and length + @param tvb the tv buffer of the current data + @param start the start offset of the appendix + @param length the length of the appendix */ +extern void proto_tree_set_appendix(proto_tree *tree, tvbuff_t *tvb, gint start, gint length); + + +/** Add an item to a proto_tree, using the text label registered to that item. + The item is extracted from the tvbuff handed to it. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param little_endian big or little endian byte representation + @return the newly created item */ +extern proto_item * +proto_tree_add_item(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, gboolean little_endian); + +/** Add a hidden item to a proto_tree. + @deprecated use proto_tree_add_item() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ +extern proto_item * +proto_tree_add_item_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, gboolean little_endian); + +/** Add a text-only node to a proto_tree. + @param tree the tree to append this item to + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_text(proto_tree *tree, tvbuff_t *tvb, gint start, gint length, const char *format, + ...) GNUC_FORMAT_CHECK(printf,5,6); + +/** Add a text-only node to a proto_tree using a variable argument list. + @param tree the tree to append this item to + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param format printf like format string + @param ap variable argument list + @return the newly created item */ +extern proto_item * +proto_tree_add_text_valist(proto_tree *tree, tvbuff_t *tvb, gint start, + gint length, const char *format, va_list ap); + + +/** Add a FT_NONE field to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_none_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const char *format, ...) GNUC_FORMAT_CHECK(printf,6,7); + +/** Add a FT_PROTOCOL to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_protocol_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const char *format, ...) GNUC_FORMAT_CHECK(printf,6,7); + + + + +/** Add a FT_BYTES to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param start_ptr pointer to the data to display + @return the newly created item */ +extern proto_item * +proto_tree_add_bytes(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const guint8* start_ptr); + +/** Add a hidden FT_BYTES to a proto_tree. + @deprecated use proto_tree_add_bytes() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ +extern proto_item * +proto_tree_add_bytes_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const guint8* start_ptr); + +/** Add a formatted FT_BYTES to a proto_tree, with the format generating + the string for the value and with the field name being included + automatically. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param start_ptr pointer to the data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_bytes_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, const guint8* start_ptr, const char *format, + ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a formatted FT_BYTES to a proto_tree, with the format generating + the entire string for the entry, including any field name. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param start_ptr pointer to the data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_bytes_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const guint8* start_ptr, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a FT_ABSOLUTE_TIME or FT_RELATIVE_TIME to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value_ptr pointer to the data to display + @return the newly created item */ +extern proto_item * +proto_tree_add_time(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, nstime_t* value_ptr); + +/** Add a hidden FT_ABSOLUTE_TIME or FT_RELATIVE_TIME to a proto_tree. + @deprecated use proto_tree_add_time() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ +extern proto_item * +proto_tree_add_time_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, nstime_t* value_ptr); + +/** Add a formatted FT_ABSOLUTE_TIME or FT_RELATIVE_TIME to a proto_tree, with + the format generating the string for the value and with the field name + being included automatically. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value_ptr pointer to the data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_time_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, nstime_t* value_ptr, const char *format, ...) + GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a formatted FT_ABSOLUTE_TIME or FT_RELATIVE_TIME to a proto_tree, with + the format generating the entire string for the entry, including any field + name. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value_ptr pointer to the data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_time_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, nstime_t* value_ptr, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a FT_IPXNET to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @return the newly created item */ +extern proto_item * +proto_tree_add_ipxnet(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, guint32 value); + +/** Add a hidden FT_IPXNET to a proto_tree. + @deprecated use proto_tree_add_ipxnet() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ +extern proto_item * +proto_tree_add_ipxnet_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, guint32 value); + +/** Add a formatted FT_IPXNET to a proto_tree, with the format generating + the string for the value and with the field name being included + automatically. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_ipxnet_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, guint32 value, const char *format, ...) + GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a formatted FT_IPXNET to a proto_tree, with the format generating + the entire string for the entry, including any field name. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_ipxnet_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, guint32 value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a FT_IPv4 to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @return the newly created item */ +extern proto_item * +proto_tree_add_ipv4(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, guint32 value); + +/** Add a hidden FT_IPv4 to a proto_tree. + @deprecated use proto_tree_add_ipv4() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ +extern proto_item * +proto_tree_add_ipv4_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, guint32 value); + +/** Add a formatted FT_IPv4 to a proto_tree, with the format generating + the string for the value and with the field name being included + automatically. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_ipv4_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, guint32 value, const char *format, ...) + GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a formatted FT_IPv4 to a proto_tree, with the format generating + the entire string for the entry, including any field name. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_ipv4_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, guint32 value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a FT_IPv6 to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value_ptr data to display + @return the newly created item */ +extern proto_item * +proto_tree_add_ipv6(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const guint8* value_ptr); + +/** Add a hidden FT_IPv6 to a proto_tree. + @deprecated use proto_tree_add_ipv6() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ +extern proto_item * +proto_tree_add_ipv6_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const guint8* value_ptr); + +/** Add a formatted FT_IPv6 to a proto_tree, with the format generating + the string for the value and with the field name being included + automatically. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value_ptr data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_ipv6_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, const guint8* value_ptr, const char *format, + ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a formatted FT_IPv6 to a proto_tree, with the format generating + the entire string for the entry, including any field name. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value_ptr data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_ipv6_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const guint8* value_ptr, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a FT_ETHER to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @return the newly created item */ +extern proto_item * +proto_tree_add_ether(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const guint8* value); + +/** Add a hidden FT_ETHER to a proto_tree. + @deprecated use proto_tree_add_ether() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ +extern proto_item * +proto_tree_add_ether_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const guint8* value); + +/** Add a formatted FT_ETHER to a proto_tree, with the format generating + the string for the value and with the field name being included + automatically. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_ether_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, const guint8* value, const char *format, ...) + GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a formatted FT_ETHER to a proto_tree, with the format generating + the entire string for the entry, including any field name. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_ether_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const guint8* value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a FT_GUID to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value_ptr data to display + @return the newly created item */ +extern proto_item * +proto_tree_add_guid(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const e_guid_t *value_ptr); + +/** Add a hidden FT_GUID to a proto_tree. + @deprecated use proto_tree_add_guid() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ +extern proto_item * +proto_tree_add_guid_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const e_guid_t *value_ptr); + +/** Add a formatted FT_GUID to a proto_tree, with the format generating + the string for the value and with the field name being included + automatically. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value_ptr data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_guid_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, const e_guid_t *value_ptr, const char *format, + ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a formatted FT_GUID to a proto_tree, with the format generating + the entire string for the entry, including any field name. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value_ptr data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_guid_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const e_guid_t *value_ptr, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a FT_OID to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value_ptr data to display + @return the newly created item */ +extern proto_item * +proto_tree_add_oid(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const guint8* value_ptr); + +/** Add a hidden FT_OID to a proto_tree. + @deprecated use proto_tree_add_oid() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ +extern proto_item * +proto_tree_add_oid_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const guint8* value_ptr); + +/** Add a formatted FT_OID to a proto_tree, with the format generating + the string for the value and with the field name being included + automatically. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value_ptr data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_oid_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, const guint8* value_ptr, const char *format, + ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a formatted FT_OID to a proto_tree, with the format generating + the entire string for the entry, including any field name. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value_ptr data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_oid_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const guint8* value_ptr, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a FT_STRING to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @return the newly created item */ +extern proto_item * +proto_tree_add_string(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const char* value); + +/** Add a hidden FT_STRING to a proto_tree. + @deprecated use proto_tree_add_string() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ +extern proto_item * +proto_tree_add_string_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const char* value); + +/** Add a formatted FT_STRING to a proto_tree, with the format generating + the string for the value and with the field name being included + automatically. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_string_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, const char* value, const char *format, ...) + GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a formatted FT_STRING to a proto_tree, with the format generating + the entire string for the entry, including any field name. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_string_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const char* value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a FT_BOOLEAN to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @return the newly created item */ +extern proto_item * +proto_tree_add_boolean(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, guint32 value); + +/** Add a hidden FT_BOOLEAN to a proto_tree. + @deprecated use proto_tree_add_boolean() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ +extern proto_item * +proto_tree_add_boolean_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, guint32 value); + +/** Add a formatted FT_BOOLEAN to a proto_tree, with the format generating + the string for the value and with the field name being included + automatically. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_boolean_format_value(proto_tree *tree, int hfindex, + tvbuff_t *tvb, gint start, gint length, guint32 value, + const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a formatted FT_BOOLEAN to a proto_tree, with the format generating + the entire string for the entry, including any field name. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_boolean_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, guint32 value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a FT_FLOAT to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @return the newly created item */ +extern proto_item * +proto_tree_add_float(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, float value); + +/** Add a hidden FT_FLOAT to a proto_tree. + @deprecated use proto_tree_add_float() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ +extern proto_item * +proto_tree_add_float_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, float value); + +/** Add a formatted FT_FLOAT to a proto_tree, with the format generating + the string for the value and with the field name being included + automatically. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_float_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, float value, const char *format, ...) + GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a formatted FT_FLOAT to a proto_tree, with the format generating + the entire string for the entry, including any field name. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_float_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, float value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a FT_DOUBLE to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @return the newly created item */ +extern proto_item * +proto_tree_add_double(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, double value); + +/** Add a hidden FT_DOUBLE to a proto_tree. + @deprecated use proto_tree_add_double() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ +extern proto_item * +proto_tree_add_double_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, double value); + +/** Add a formatted FT_DOUBLE to a proto_tree, with the format generating + the string for the value and with the field name being included + automatically. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_double_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, double value, const char *format, ...) + GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a formatted FT_DOUBLE to a proto_tree, with the format generating + the entire string for the entry, including any field name. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_double_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, double value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add one of FT_UINT8, FT_UINT16, FT_UINT24 or FT_UINT32 to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @return the newly created item */ +extern proto_item * +proto_tree_add_uint(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, guint32 value); + +/** Add a hidden FT_UINT8, FT_UINT16, FT_UINT24 or FT_UINT32 to a proto_tree. + @deprecated use proto_tree_add_uint() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ +extern proto_item * +proto_tree_add_uint_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, guint32 value); + +/** Add a formatted FT_UINT8, FT_UINT16, FT_UINT24 or FT_UINT32 to a proto_tree, + with the format generating the string for the value and with the field + name being included automatically. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_uint_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, guint32 value, const char *format, ...) + GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a formatted FT_UINT8, FT_UINT16, FT_UINT24 or FT_UINT32 to a proto_tree, + with the format generating the entire string for the entry, including any + field name. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_uint_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, guint32 value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add an FT_UINT64 to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @return the newly created item */ +extern proto_item * +proto_tree_add_uint64(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, guint64 value); + +/** Add a formatted FT_UINT64 to a proto_tree, with the format generating + the string for the value and with the field name being included + automatically. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_uint64_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, guint64 value, const char *format, ...) + GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a formatted FT_UINT64 to a proto_tree, with the format generating + the entire string for the entry, including any field name. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_uint64_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, guint64 value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add one of FT_INT8, FT_INT16, FT_INT24 or FT_INT32 to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @return the newly created item */ +extern proto_item * +proto_tree_add_int(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, gint32 value); + +/** Add a hidden FT_INT8, FT_INT16, FT_INT24 or FT_INT32 to a proto_tree. + @deprecated use proto_tree_add_int() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ +extern proto_item * +proto_tree_add_int_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, gint32 value); + +/** Add a formatted FT_INT8, FT_INT16, FT_INT24 or FT_INT32 to a proto_tree, + with the format generating the string for the value and with the field + name being included automatically. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_int_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, gint32 value, const char *format, ...) + GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a formatted FT_INT8, FT_INT16, FT_INT24 or FT_INT32 to a proto_tree, + with the format generating the entire string for the entry, including + any field name. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_int_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, gint32 value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add an FT_INT64 to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @return the newly created item */ +extern proto_item * +proto_tree_add_int64(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, gint64 value); + +/** Add a formatted FT_INT64 to a proto_tree, with the format generating + the string for the value and with the field name being included + automatically. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_int64_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, gint64 value, const char *format, ...) + GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a formatted FT_INT64 to a proto_tree, with the format generating + the entire string for the entry, including any field name. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_int64_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, gint64 value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Useful for quick debugging. Also sends string to STDOUT, so don't + leave call to this function in production code. + @param tree the tree to append the text to + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_debug_text(proto_tree *tree, const char *format, + ...) GNUC_FORMAT_CHECK(printf,2,3); + + + +/** Append a string to a protocol item.
+ NOTE: this function will break with the TRY_TO_FAKE_THIS_ITEM() + speed optimization. + Currently only WSP use this function so it is not that bad but try to + avoid using this one if possible. + IF you must use this function you MUST also disable the + TRY_TO_FAKE_THIS_ITEM() optimization for your dissector/function + using proto_item_append_string(). + Do that by faking that the tree is visible by calling + proto_tree_set_visible(tree, TRUE) (see packet-wsp.c) + BEFORE you create the item you are later going to use + proto_item_append_string() on. + @param pi the item to append the string to + @param str the string to append */ +extern void +proto_item_append_string(proto_item *pi, const char *str); + + + +/** Fill given label_str with string representation of field + @param fi the item to get the info from + @param label_str the string to fill + @todo think about changing the parameter profile */ +extern void +proto_item_fill_label(field_info *fi, gchar *label_str); + + +/** Register a new protocol. + @param name the full name of the new protocol + @param short_name abbreviated name of the new protocol + @param filter_name protocol name used for a display filter string + @return the new protocol handle */ +extern int +proto_register_protocol(const char *name, const char *short_name, const char *filter_name); + +/** Register a header_field array. + @param parent the protocol handle from proto_register_protocol() + @param hf the hf_register_info array + @param num_records the number of records in hf */ +extern void +proto_register_field_array(int parent, hf_register_info *hf, int num_records); + +/** Register a protocol subtree (ett) array. + @param indices array of ett indices + @param num_indices the number of records in indices */ +extern void +proto_register_subtree_array(gint *const *indices, int num_indices); + +/** Returns number of items (protocols or header fields) registered. + @return the number of items */ +extern int proto_registrar_n(void); + +/** Get name of registered header_field number n. + @param n item # n (0-indexed) + @return the name of this registered item */ +extern const char* proto_registrar_get_name(int n); + +/** Get abbreviation of registered header_field number n. + @param n item # n (0-indexed) + @return the abbreviation of this registered item */ +extern const char* proto_registrar_get_abbrev(int n); + +/** Get the header_field information based upon a field or protocol id. + @param hfindex item # n (0-indexed) + @return the registered item */ +extern header_field_info* proto_registrar_get_nth(guint hfindex); + +/** Get the header_field information based upon a field name. + @param field_name the field name to search for + @return the registered item */ +extern header_field_info* proto_registrar_get_byname(const char *field_name); + +/** Get enum ftenum FT_ of registered header_field number n. + @param n item # n (0-indexed) + @return the registered item */ +extern int proto_registrar_get_ftype(int n); + +/** Get parent protocol of registered header_field number n. + @param n item # n (0-indexed) + @return -1 if item _is_ a protocol */ +extern int proto_registrar_get_parent(int n); + +/** Is item # n a protocol? + @param n item # n (0-indexed) + @return TRUE if it's a protocol, FALSE if it's not */ +extern gboolean proto_registrar_is_protocol(int n); + +/** Get length of registered field according to field type. + @param n item # n (0-indexed) + @return 0 means undeterminable at registration time, -1 means unknown field */ +extern gint proto_registrar_get_length(int n); + + +/** Routines to use to iterate over the protocols and their fields; + * they return the item number of the protocol in question or the + * appropriate hfinfo pointer, and keep state in "*cookie". */ +extern int proto_get_first_protocol(void **cookie); +extern int proto_get_next_protocol(void **cookie); +extern header_field_info *proto_get_first_protocol_field(int proto_id, void **cookle); +extern header_field_info *proto_get_next_protocol_field(void **cookle); + +/** Given a protocol's filter_name. + @param filter_name the filter name to search for + @return proto_id */ +extern int proto_get_id_by_filter_name(const gchar* filter_name); + +/** Can item # n decoding be disabled? + @param proto_id protocol id (0-indexed) + @return TRUE if it's a protocol, FALSE if it's not */ +extern gboolean proto_can_toggle_protocol(int proto_id); + +/** Get the "protocol_t" structure for the given protocol's item number. + @param proto_id protocol id (0-indexed) */ +extern protocol_t *find_protocol_by_id(int proto_id); + +/** Get the protocol's name for the given protocol's item number. + @param proto_id protocol id (0-indexed) + @return its name */ +extern const char *proto_get_protocol_name(int proto_id); + +/** Get the protocol's item number, for the given protocol's "protocol_t". + @return its proto_id */ +extern int proto_get_id(protocol_t *protocol); + +/** Get the protocol's short name, for the given protocol's "protocol_t". + @return its short name. */ +extern const char *proto_get_protocol_short_name(protocol_t *protocol); + +/** Is protocol's decoding enabled ? + @param protocol + @return TRUE if decoding is enabled, FALSE if not */ +extern gboolean proto_is_protocol_enabled(protocol_t *protocol); + +/** Get a protocol's filter name by it's item number. + @param proto_id protocol id (0-indexed) + @return its filter name. */ +extern const char *proto_get_protocol_filter_name(int proto_id); + +/** Enable / Disable protocol of the given item number. + @param proto_id protocol id (0-indexed) + @param enabled enable / disable the protocol */ +extern void proto_set_decoding(int proto_id, gboolean enabled); + +/** Enable all protocols */ +extern void proto_enable_all(void); + +/** Disable disabling/enabling of protocol of the given item number. + @param proto_id protocol id (0-indexed) */ +extern void proto_set_cant_toggle(int proto_id); + +/** Checks for existence any protocol or field within a tree. + @param tree "Protocols" are assumed to be a child of the [empty] root node. + @param id hfindex of protocol or field + @return TRUE = found, FALSE = not found + @todo add explanation of id parameter */ +extern gboolean proto_check_for_protocol_or_field(proto_tree* tree, int id); + +/** Return GPtrArray* of field_info pointers for all hfindex that appear in + tree. Only works with primed trees, and is fast. + @param tree tree of interest + @param hfindex primed hfindex + @return GPtrArry pointer */ +extern GPtrArray* proto_get_finfo_ptr_array(proto_tree *tree, int hfindex); + +/** Return GPtrArray* of field_info pointers for all hfindex that appear in + tree. Works with any tree, primed or unprimed, and is slower than + proto_get_finfo_ptr_array because it has to search through the tree. + @param tree tree of interest + @param hfidex index of field info of interest + @return GPtrArry pointer */ +extern GPtrArray* proto_find_finfo(proto_tree *tree, int hfindex); + +/** Return GPtrArray* of field_info pointers containg all hfindexes that appear + in tree. + @param tree tree of interest + @return GPtrArry pointer */ +extern GPtrArray* proto_all_finfos(proto_tree *tree); + +/** Dumps a glossary of the protocol registrations to STDOUT */ +extern void proto_registrar_dump_protocols(void); + +/** Dumps a glossary of the field value strings or true/false strings to STDOUT */ +extern void proto_registrar_dump_values(void); + +/** Dumps a glossary of the protocol and field registrations to STDOUT. + * Format 1 is the original format. Format 2 includes the base (for integers) + * and the blurb. */ +extern void proto_registrar_dump_fields(int format); + + + +/** Points to the first element of an array of Booleans, indexed by + a subtree item type. That array element is TRUE if subtrees of + an item of that type are to be expanded. With MSVC and a + libwireshark.dll, we need a special declaration. */ +WS_VAR_IMPORT gboolean *tree_is_expanded; + +/** Number of elements in the tree_is_expanded array. With MSVC and a + * libwireshark.dll, we need a special declaration. */ +WS_VAR_IMPORT int num_tree_types; + +/** glib doesn't have g_ptr_array_len of all things!*/ +#ifndef g_ptr_array_len +#define g_ptr_array_len(a) ((a)->len) +#endif + +/** Get number of bits of a header_field. + @param hfinfo header_field + @return the bitwidth */ +extern int +hfinfo_bitwidth(header_field_info *hfinfo); + + + + +#include "epan.h" + +/** Can we do a "match selected" on this field. + @param finfo field_info + @param edt epan dissecting + @return TRUE if we can do a "match selected" on the field, FALSE otherwise. */ +extern gboolean +proto_can_match_selected(field_info *finfo, epan_dissect_t *edt); + +/** Construct a "match selected" display filter string. + @param finfo field_info + @param edt epan dissecting + @return the display filter string */ +extern char* +proto_construct_match_selected_string(field_info *finfo, epan_dissect_t *edt); + +/** Find field from offset in tvb. + @param tree tree of interest + @param offset offset in the tvb + @param tvb the tv buffer + @return the corresponding field_info */ +extern field_info* +proto_find_field_from_offset(proto_tree *tree, guint offset, tvbuff_t *tvb); + +/** This function will dissect a sequence of bytes that describe a bitmask. + @param tree the tree to append this item to + @param tvb the tv buffer of the current data + @param offset start of data in tvb + @param hf_hdr an 8/16/24/32 bit integer that describes the bitmask to be dissected. + This field will form an expansion under which the individual fields of the + bitmask is dissected and displayed. + This field must be of the type FT_[U]INT{8|16|24|32}. + @param fields an array of pointers to int that lists all the fields of the + bitmask. These fields can be either of the type FT_BOOLEAN for flags + or another integer of the same type/size as hf_hdr with a mask specified. + This array is terminated by a NULL entry. + FT_BOOLEAN bits that are set to 1 will have the name added to the expansion. + FT_integer fields that have a value_string attached will have the + matched string displayed on the expansion line. + @param little_endian big or little endian byte representation + @return the newly created item */ +extern proto_item * +proto_tree_add_bitmask(proto_tree *tree, tvbuff_t *tvb, int offset, int hf_hdr, gint ett, const int **fields, gboolean little_endian); + +/** Add bits to a proto_tree, using the text label registered to that item. + The item is extracted from the tvbuff handed to it. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param bit_offset start of data in tvb expressed in bits + @param no_of_bits length of data in tvb expressed in bits + @param little_endian big or little endian byte representation + @return the newly created item */ +extern proto_item * +proto_tree_add_bits_item(proto_tree *tree, int hf_index, tvbuff_t *tvb, gint bit_offset, gint no_of_bits, gboolean little_endian); + +/** Add bits to a proto_tree, using the text label registered to that item. + The item is extracted from the tvbuff handed to it. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param bit_offset start of data in tvb expressed in bits + @param no_of_bits length of data in tvb expressed in bits + @param return_value if a pointer is passed here the value is returned. + @param little_endian big or little endian byte representation + @return the newly created item */ +extern proto_item * +proto_tree_add_bits_ret_val(proto_tree *tree, int hf_index, tvbuff_t *tvb, gint bit_offset, gint no_of_bits, guint64 *return_value, gboolean little_endian); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* proto.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ptvcursor.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ptvcursor.h new file mode 100644 index 00000000..d94940bf --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ptvcursor.h @@ -0,0 +1,110 @@ +/* ptvcursor.h + * + * Proto Tree TVBuff cursor + * Gilbert Ramirez + * + * $Id: ptvcursor.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2000 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PTVCURSOR_H__ +#define __PTVCURSOR_H__ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#define SUBTREE_UNDEFINED_LENGTH -1 + +typedef struct ptvcursor ptvcursor_t; + +/* Allocates an initializes a ptvcursor_t with 3 variables: + * proto_tree, tvbuff, and offset. */ +ptvcursor_t* +ptvcursor_new(proto_tree*, tvbuff_t*, gint); + +/* Gets data from tvbuff, adds it to proto_tree, increments offset, + * and returns proto_item* */ +proto_item* +ptvcursor_add(ptvcursor_t*, int hf, gint length, gboolean endianness); + + +/* Gets data from tvbuff, adds it to proto_tree, *DOES NOT* increment + * offset, and returns proto_item* */ +proto_item* +ptvcursor_add_no_advance(ptvcursor_t*, int hf, gint length, gboolean endianness); + +/* Advance the ptvcursor's offset within its tvbuff without + * adding anything to the proto_tree. */ +void +ptvcursor_advance(ptvcursor_t* ptvc, gint length); + +/* Frees memory for ptvcursor_t, but nothing deeper than that. */ +void +ptvcursor_free(ptvcursor_t*); + +/* Returns tvbuff. */ +tvbuff_t* +ptvcursor_tvbuff(ptvcursor_t*); + +/* Returns current offset. */ +gint +ptvcursor_current_offset(ptvcursor_t*); + +/* Returns the proto_tree* */ +proto_tree* +ptvcursor_tree(ptvcursor_t* ptvc); + +/* Sets a new proto_tree* for the ptvcursor_t */ +void +ptvcursor_set_tree(ptvcursor_t* ptvc, proto_tree *tree); + +/* push a subtree in the tree stack of the cursor */ +proto_tree* +ptvcursor_push_subtree(ptvcursor_t *ptvc, proto_item *it, gint ett_subtree); + +/* pop a subtree in the tree stack of the cursor */ +void ptvcursor_pop_subtree(ptvcursor_t *ptvc); + +/* Add an item to the tree and create a subtree + * If the length is unknown, length may be defined as SUBTREE_UNDEFINED_LENGTH. + * In this case, when the subtree will be closed, the parent item length will + * be equal to the advancement of the cursor since the creation of the subtree. + */ +proto_tree* ptvcursor_add_with_subtree(ptvcursor_t * ptvc, int hfindex, gint length, +gboolean little_endian, gint ett_subtree); + +/* Add a text node to the tree and create a subtree + * If the length is unknown, length may be defined as SUBTREE_UNDEFINED_LENGTH. + * In this case, when the subtree will be closed, the item length will be equal + * to the advancement of the cursor since the creation of the subtree. + */ +proto_tree * ptvcursor_add_text_with_subtree(ptvcursor_t * ptvc, gint length, + gint ett_subtree, const char *format, ...); + +/* Creates a subtree and adds it to the cursor as the working tree but does not + * save the old working tree */ +proto_tree* +ptvcursor_set_subtree(ptvcursor_t *ptvc, proto_item *it, gint ett_subtree); + +#endif /* __PTVCURSOR_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/radius_dict_lex.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/radius_dict_lex.h new file mode 100644 index 00000000..1ddab2be --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/radius_dict_lex.h @@ -0,0 +1,6 @@ +/* This is generated by runlex.sh. Do not edit it. */ +#define yylex Radiuslex +#ifndef YY_DECL +#define YY_DECL int yylex(void) +#endif +YY_DECL; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/range.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/range.h new file mode 100644 index 00000000..daf339c5 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/range.h @@ -0,0 +1,73 @@ +/* range.h + * Range routines + * + * $Id: range.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Dick Gooris + * Ulf Lamping + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __RANGE_H__ +#define __RANGE_H__ + +#include + +/* XXX where's the best place for these? */ +#define MAX_SCTP_PORT 65535 +#define MAX_TCP_PORT 65535 +#define MAX_UDP_PORT 65535 + +typedef struct range_admin_tag { + guint32 low; + guint32 high; +} range_admin_t; + +typedef struct range { + /* user specified range(s) */ + guint nranges; /* number of entries in ranges */ + range_admin_t ranges[1]; /* variable-length array */ +} range_t; + +/* + * Return value from range_convert_str(). + */ +typedef enum { + CVT_NO_ERROR, + CVT_SYNTAX_ERROR, + CVT_NUMBER_TOO_BIG +} convert_ret_t; + +extern range_t *range_empty(void); + +extern convert_ret_t range_convert_str(range_t **range, const gchar *es, + guint32 max_value); + +extern gboolean value_is_in_range(range_t *range, guint32 val); + +extern gboolean ranges_are_equal(range_t *a, range_t *b); + +extern void range_foreach(range_t *range, void (*callback)(guint32 val)); + +extern char *range_convert_range(range_t *range); + +extern range_t *range_copy(range_t *src); + +#endif /* __RANGE_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/reassemble.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/reassemble.h new file mode 100644 index 00000000..c8581727 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/reassemble.h @@ -0,0 +1,316 @@ +/* reassemble.h + * Declarations of outines for {fragment,segment} reassembly + * + * $Id: reassemble.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* make sure that all flags that are set in a fragment entry is also set for + * the flags field of fd_head !!! + */ + +/* only in fd_head: packet is defragmented */ +#define FD_DEFRAGMENTED 0x0001 + +/* there are overlapping fragments */ +#define FD_OVERLAP 0x0002 + +/* overlapping fragments contain different data */ +#define FD_OVERLAPCONFLICT 0x0004 + +/* more than one fragment which indicates end-of data */ +#define FD_MULTIPLETAILS 0x0008 + +/* fragment contains data past the end of the datagram */ +#define FD_TOOLONGFRAGMENT 0x0010 + +/* fragment data not alloced, fd->data pointing to fd_head->data+fd->offset */ +#define FD_NOT_MALLOCED 0x0020 + +/* this flag is used to request fragment_add to continue the reassembly process */ +#define FD_PARTIAL_REASSEMBLY 0x0040 + +/* fragment offset is indicated by sequence number and not byte offset + into the defragmented packet */ +#define FD_BLOCKSEQUENCE 0x0100 + +/* if REASSEMBLE_FLAGS_CHECK_DATA_PRESENT is set, and the first fragment is + * incomplete, this flag is set in the flags word on the fd_head returned. + * + * It's all a fudge to preserve historical behaviour. + */ +#define FD_DATA_NOT_PRESENT 0x0200 + +/* This flag is set in the to denote that datalen has ben set to a valid value. + * It's implied by FD_DEFRAGMENTED (we must know the total length of the + * datagram if we have defragmented it...) + */ +#define FD_DATALEN_SET 0x0400 + +typedef struct _fragment_data { + struct _fragment_data *next; + guint32 frame; + guint32 offset; + guint32 len; + guint32 datalen; /* Only valid in first item of list and when + * flags&FD_DATALEN_SET is set; + * number of bytes or (if flags&FD_BLOCKSEQUENCE set) + * segments in the datagram */ + guint32 reassembled_in; /* frame where this PDU was reassembled, + only valid in the first item of the list + and when FD_DEFRAGMENTED is set*/ + guint32 flags; + unsigned char *data; +} fragment_data; + + +/* + * Flags for fragment_add_seq_* + */ + +/* we don't have any sequence numbers - fragments are assumed to appear in + * order */ +#define REASSEMBLE_FLAGS_NO_FRAG_NUMBER 0x0001 + +/* a special fudge for the 802.11 dissector */ +#define REASSEMBLE_FLAGS_802_11_HACK 0x0002 + +/* causes fragment_add_seq_key to check that all the fragment data is present + * in the tvb, and if not, do something a bit odd. */ +#define REASSEMBLE_FLAGS_CHECK_DATA_PRESENT 0x0004 + +/* a function for copying hash keys */ +typedef void *(*fragment_key_copier)(const void *key); + + +/* + * Initialize a fragment table. + */ +extern void fragment_table_init(GHashTable **fragment_table); +extern void dcerpc_fragment_table_init(GHashTable **fragment_table); + +/* + * Initialize a reassembled-packet table. + */ +extern void reassembled_table_init(GHashTable **reassembled_table); + +/* + * Free up all space allocated for fragment keys and data. + */ +void reassemble_init(void); + +/* + * This function adds a new fragment to the fragment hash table. + * If this is the first fragment seen for this datagram, a new entry + * is created in the hash table, otherwise this fragment is just added + * to the linked list of fragments for this packet. + * The list of fragments for a specific datagram is kept sorted for + * easier handling. + * + * Returns a pointer to the head of the fragment data list if we have all the + * fragments, NULL otherwise. + */ +extern fragment_data *fragment_add(tvbuff_t *tvb, int offset, packet_info *pinfo, + guint32 id, GHashTable *fragment_table, guint32 frag_offset, + guint32 frag_data_len, gboolean more_frags); +extern fragment_data *fragment_add_multiple_ok(tvbuff_t *tvb, int offset, + packet_info *pinfo, guint32 id, GHashTable *fragment_table, + guint32 frag_offset, guint32 frag_data_len, gboolean more_frags); + +/* + * This routine extends fragment_add to use a "reassembled_table". + * + * If, after processing this fragment, we have all the fragments, they + * remove that from the fragment hash table if necessary and add it + * to the table of reassembled fragments, and return a pointer to the + * head of the fragment list. + */ +extern fragment_data *fragment_add_check(tvbuff_t *tvb, int offset, + packet_info *pinfo, guint32 id, GHashTable *fragment_table, + GHashTable *reassembled_table, guint32 frag_offset, + guint32 frag_data_len, gboolean more_frags); + +/* same as fragment_add() but this one assumes frag_number is a block + sequence number. note that frag_number is 0 for the first fragment. */ + +/* + * These functions add a new fragment to the fragment hash table, + * assuming that frag_number is a block sequence number (starting from zero for + * the first fragment of each datagram). + * + * If this is the first fragment seen for this datagram, a new + * "fragment_data" structure is allocated to refer to the reassembled + * packet, and: + * + * if "more_frags" is false, and either we have no sequence numbers, or + * are using the 802.11 hack, it is assumed that this is the only fragment + * in the datagram. The structure is not added to the hash + * table, and not given any fragments to refer to, but is just returned. + * + * In this latter case reassembly wasn't done (since there was only one + * fragment in the packet); dissectors can check the 'next' pointer on the + * returned list to see if this case was hit or not. + * + * Otherwise, this fragment is just added to the linked list of fragments + * for this packet; the fragment_data is also added to the fragment hash if + * necessary. + * + * If this packet completes assembly, these functions return the head of the + * fragment data; otherwise, they return null. + */ + +/* "key" should be an arbitrary key used for indexing the fragment hash; + * "key_copier" is called to copy the key to a more appropriate store before + * inserting a new entry to the hash. + */ +extern fragment_data * +fragment_add_seq_key(tvbuff_t *tvb, int offset, packet_info *pinfo, + void *key, fragment_key_copier key_copier, + GHashTable *fragment_table, guint32 frag_number, + guint32 frag_data_len, gboolean more_frags, + guint32 flags); + +/* a wrapper for fragment_add_seq_key - uses a key of source, dest and frame number */ +extern fragment_data *fragment_add_seq(tvbuff_t *tvb, int offset, packet_info *pinfo, + guint32 id, GHashTable *fragment_table, guint32 frag_number, + guint32 frag_data_len, gboolean more_frags); + +/* another wrapper for fragment_add_seq_key - uses a key of source, dest, frame + * number and act_id */ +extern fragment_data * +fragment_add_dcerpc_dg(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id, + void *act_id, + GHashTable *fragment_table, guint32 frag_number, + guint32 frag_data_len, gboolean more_frags); + +/* + * These routines extend fragment_add_seq_key to use a "reassembled_table". + * + * If, after processing this fragment, we have all the fragments, they + * remove that from the fragment hash table if necessary and add it + * to the table of reassembled fragments, and return a pointer to the + * head of the fragment list. + */ +extern fragment_data * +fragment_add_seq_check(tvbuff_t *tvb, int offset, packet_info *pinfo, + guint32 id, GHashTable *fragment_table, + GHashTable *reassembled_table, guint32 frag_number, + guint32 frag_data_len, gboolean more_frags); + +extern fragment_data * +fragment_add_seq_802_11(tvbuff_t *tvb, int offset, packet_info *pinfo, + guint32 id, GHashTable *fragment_table, + GHashTable *reassembled_table, guint32 frag_number, + guint32 frag_data_len, gboolean more_frags); + +extern fragment_data * +fragment_add_seq_next(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id, + GHashTable *fragment_table, GHashTable *reassembled_table, + guint32 frag_data_len, gboolean more_frags); + +extern void +fragment_start_seq_check(packet_info *pinfo, guint32 id, GHashTable *fragment_table, + guint32 tot_len); + +extern fragment_data * +fragment_end_seq_next(packet_info *pinfo, guint32 id, GHashTable *fragment_table, + GHashTable *reassembled_table); +/* to specify how much to reassemble, for fragmentation where last fragment can not be + * identified by flags or such. + * note that for FD_BLOCKSEQUENCE tot_len is the index for the tail fragment. + * i.e. since the block numbers start at 0, if we specify tot_len==2, that + * actually means we want to defragment 3 blocks, block 0, 1 and 2. + * + */ +extern void +fragment_set_tot_len(packet_info *pinfo, guint32 id, GHashTable *fragment_table, + guint32 tot_len); + +/* to resad whatever totlen previously set */ +extern guint32 +fragment_get_tot_len(packet_info *pinfo, guint32 id, GHashTable *fragment_table); + +/* + * This function will set the partial reassembly flag(FD_PARTIAL_REASSEMBLY) for a fh. + * When this function is called, the fh MUST already exist, i.e. + * the fh MUST be created by the initial call to fragment_add() before + * this function is called. Also note that this function MUST be called to indicate + * a fh will be extended (increase the already stored data). After calling this function, + * and if FD_DEFRAGMENTED is set, the reassembly process will be continued. + */ +extern void +fragment_set_partial_reassembly(packet_info *pinfo, guint32 id, GHashTable *fragment_table); + +/* This function is used to check if there is partial or completed reassembly state + * matching this packet. I.e. Are there reassembly going on or not for this packet? + */ +extern fragment_data * +fragment_get(packet_info *pinfo, guint32 id, GHashTable *fragment_table); + +/* The same for the reassemble table */ +/* id *must* be the frame number for this to work! */ +extern fragment_data * +fragment_get_reassembled(packet_info *pinfo, guint32 id, GHashTable *reassembled_table); + +extern fragment_data * +fragment_get_reassembled_id(packet_info *pinfo, guint32 id, GHashTable *reassembled_table); + +/* This will free up all resources and delete reassembly state for this PDU. + * Except if the PDU is completely reassembled, then it would NOT deallocate the + * buffer holding the reassembled data but instead return the pointer to that + * buffer. + * + * So, if you call fragment_delete and it returns non-NULL, YOU are responsible to + * g_free() that buffer. + */ +extern unsigned char * +fragment_delete(packet_info *pinfo, guint32 id, GHashTable *fragment_table); + +/* hf_fragment, hf_fragment_error, and hf_reassembled_in should be + FT_FRAMENUM, the others should be FT_BOOLEAN +*/ +typedef struct _fragment_items { + gint *ett_fragment; + gint *ett_fragments; + + int *hf_fragments; + int *hf_fragment; + int *hf_fragment_overlap; + int *hf_fragment_overlap_conflict; + int *hf_fragment_multiple_tails; + int *hf_fragment_too_long_fragment; + int *hf_fragment_error; + int *hf_reassembled_in; + + const char *tag; +} fragment_items; + +extern tvbuff_t * +process_reassembled_data(tvbuff_t *tvb, int offset, packet_info *pinfo, + const char *name, fragment_data *fd_head, const fragment_items *fit, + gboolean *update_col_infop, proto_tree *tree); + +extern gboolean +show_fragment_tree(fragment_data *ipfd_head, const fragment_items *fit, + proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, proto_item **fi); + +extern gboolean +show_fragment_seq_tree(fragment_data *ipfd_head, const fragment_items *fit, + proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, proto_item **fi); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/reedsolomon.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/reedsolomon.h new file mode 100644 index 00000000..433f6e1e --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/reedsolomon.h @@ -0,0 +1,86 @@ +#ifdef __cplusplus +extern "C" { +#endif + +/* Global definitions for Reed-Solomon encoder/decoder + * Phil Karn KA9Q, September 1996 + */ +/* Set one of these to enable encoder/decoder debugging and error checking, + * at the expense of speed */ +/* #undef DEBUG 1*/ +/* #undef DEBUG 2*/ +#undef DEBUG + +/* To select the CCSDS standard (255,223) code, define CCSDS. This + * implies standard values for MM, KK, B0 and PRIM. + */ +/* #undef CCSDS 1*/ +#undef CCSDS +#ifndef CCSDS + +/* Otherwise, leave CCSDS undefined and set the parameters below: + * + * Set MM to be the size of each code symbol in bits. The Reed-Solomon + * block size will then be NN = 2**M - 1 symbols. Supported values are + * defined in rs.c. + */ +#define MM 8 /* Symbol size in bits */ + +/* + * Set KK to be the number of data symbols in each block, which must be + * less than the block size. The code will then be able to correct up + * to NN-KK erasures or (NN-KK)/2 errors, or combinations thereof with + * each error counting as two erasures. + */ +#define KK 207 /* Number of data symbols per block */ + +/* Set B0 to the first root of the generator polynomial, in alpha form, and + * set PRIM to the power of alpha used to generate the roots of the + * generator polynomial. The generator polynomial will then be + * @**PRIM*B0, @**PRIM*(B0+1), @**PRIM*(B0+2)...@**PRIM*(B0+NN-KK) + * where "@" represents a lower case alpha. + */ +#define B0 1 /* First root of generator polynomial, alpha form */ +#define PRIM 1 /* power of alpha used to generate roots of generator poly */ +#define STANDARD_ORDER + +/* If you want to select your own field generator polynomial, you'll have + * to edit that in rs.c. + */ + +#else /* CCSDS */ +/* Don't change these, they're CCSDS standard */ +#define MM 8 +#define KK 223 +#define B0 112 +#define PRIM 11 +#endif + +#define NN ((1 << MM) - 1) + +#if MM <= 8 +typedef unsigned char dtype; +#else +typedef unsigned int dtype; +#endif + +/* Reed-Solomon encoding + * data[] is the input block, parity symbols are placed in bb[] + * bb[] may lie past the end of the data, e.g., for (255,223): + * encode_rs(&data[0],&data[223]); + */ +int encode_rs(dtype data[], dtype bb[]); + +/* Reed-Solomon erasures-and-errors decoding + * The received block goes into data[], and a list of zero-origin + * erasure positions, if any, goes in eras_pos[] with a count in no_eras. + * + * The decoder corrects the symbols in place, if possible and returns + * the number of corrected symbols. If the codeword is illegal or + * uncorrectible, the data array is unchanged and -1 is returned + */ +int eras_dec_rs(dtype data[], int eras_pos[], int no_eras); + +#ifdef __cplusplus +} +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/report_err.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/report_err.h new file mode 100644 index 00000000..c29df457 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/report_err.h @@ -0,0 +1,61 @@ +/* report_err.h + * Declarations of routines for dissectors to use to report errors to + * the user (e.g., problems with preference settings) + * + * $Id: report_err.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __REPORT_ERR_H__ +#define __REPORT_ERR_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * Initialize the report err routines + */ +extern void init_report_err( + void (*report_failure)(const char *, va_list), + void (*report_open_failure)(const char *, int, gboolean), + void (*report_read_failure)(const char *, int)); + +/* + * Report an error when trying to open a file. + */ +extern void report_open_failure(const char *filename, int err, + gboolean for_writing); + +/* + * Report an error when trying to read a file. + */ +extern void report_read_failure(const char *filename, int err); + +/* + * Report a general error. + */ +extern void report_failure(const char *msg_format, ...); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __REPORT_ERR_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/req_resp_hdrs.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/req_resp_hdrs.h new file mode 100644 index 00000000..40e68884 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/req_resp_hdrs.h @@ -0,0 +1,43 @@ +/* req_resp_hdrs.h + * Declarations of routines handling protocols with a request/response line, + * headers, a blank line, and an optional body. + * + * $Id: req_resp_hdrs.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __REQ_RESP_HDRS_H__ +#define __REQ_RESP_HDRS_H__ + +/** + * Optionally do reassembly of the request/response line, headers, and body. + * + * @param tvb The buffer. + * @param offset The offset in the buffer to begin inspection. + * @param pinfo Packet info from the parent protocol. + * @param desegment_headers Do desegmentation on headers. + * @param desegment_body Do desegmenation on body. + * @return TRUE if desegmentation is complete otherwise FALSE + */ +extern gboolean +req_resp_hdrs_do_reassembly(tvbuff_t *tvb, const int offset, packet_info *pinfo, + const gboolean desegment_headers, const gboolean desegment_body); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/rtp_pt.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/rtp_pt.h new file mode 100644 index 00000000..0ddb9b9a --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/rtp_pt.h @@ -0,0 +1,68 @@ +/* rtp_pt.h + * Defines RTP payload types + * + * $Id: rtp_pt.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __RTP_PT_H__ +#define __RTP_PT_H__ + +#include "epan/value_string.h" + +/* + * RTP Payload types + * Table B.2 / H.225.0 + * Also RFC 1890, and + * + * http://www.iana.org/assignments/rtp-parameters + */ +#define PT_PCMU 0 /* RFC 1890 */ +#define PT_1016 1 /* RFC 1890 */ +#define PT_G721 2 /* RFC 1890 */ +#define PT_GSM 3 /* RFC 1890 */ +#define PT_G723 4 /* From Vineet Kumar of Intel; see the Web page */ +#define PT_DVI4_8000 5 /* RFC 1890 */ +#define PT_DVI4_16000 6 /* RFC 1890 */ +#define PT_LPC 7 /* RFC 1890 */ +#define PT_PCMA 8 /* RFC 1890 */ +#define PT_G722 9 /* RFC 1890 */ +#define PT_L16_STEREO 10 /* RFC 1890 */ +#define PT_L16_MONO 11 /* RFC 1890 */ +#define PT_QCELP 12 /* Qualcomm Code Excited Linear Predictive coding? */ +#define PT_CN 13 /* RFC 3389 */ +#define PT_MPA 14 /* RFC 1890, RFC 2250 */ +#define PT_G728 15 /* RFC 1890 */ +#define PT_DVI4_11025 16 /* from Joseph Di Pol of Sun; see the Web page */ +#define PT_DVI4_22050 17 /* from Joseph Di Pol of Sun; see the Web page */ +#define PT_G729 18 +#define PT_CN_OLD 19 /* Payload type reserved (old version Comfort Noise) */ +#define PT_CELB 25 /* RFC 2029 */ +#define PT_JPEG 26 /* RFC 2435 */ +#define PT_NV 28 /* RFC 1890 */ +#define PT_H261 31 /* RFC 2032 */ +#define PT_MPV 32 /* RFC 2250 */ +#define PT_MP2T 33 /* RFC 2250 */ +#define PT_H263 34 /* from Chunrong Zhu of Intel; see the Web page */ + +WS_VAR_IMPORT const value_string rtp_payload_type_vals[]; +WS_VAR_IMPORT const value_string rtp_payload_type_short_vals[]; + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sctpppids.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sctpppids.h new file mode 100644 index 00000000..523a04a8 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sctpppids.h @@ -0,0 +1,50 @@ +/* sctpppids.h + * Declarations of SCTP payload protocol IDs. + * + * $Id: sctpppids.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __SCTPPPIDS_H__ +#define __SCTPPPIDS_H__ + +/* + * SCTP payload protocol IDs. + */ +#define NOT_SPECIFIED_PROTOCOL_ID 0 +#define IUA_PAYLOAD_PROTOCOL_ID 1 +#define M2UA_PAYLOAD_PROTOCOL_ID 2 +#define M3UA_PAYLOAD_PROTOCOL_ID 3 +#define SUA_PAYLOAD_PROTOCOL_ID 4 +#define M2PA_PAYLOAD_PROTOCOL_ID 5 +#define V5UA_PAYLOAD_PROTOCOL_ID 6 +#define H248_PAYLOAD_PROTOCOL_ID 7 +#define BICC_PAYLOAD_PROTOCOL_ID 8 +#define TALI_PAYLOAD_PROTOCOL_ID 9 +#define DUA_PAYLOAD_PROTOCOL_ID 10 +#define ASAP_PAYLOAD_PROTOCOL_ID 11 +#define ENRP_PAYLOAD_PROTOCOL_ID 12 +#define H323_PAYLOAD_PROTOCOL_ID 13 +#define QIPC_PAYLOAD_PROTOCOL_ID 14 +#define SIMCO_PAYLOAD_PROTOCOL_ID 15 +#define DDP_SEG_CHUNK_PROTOCOL_ID 16 +#define DDP_STREAM_SES_CTRL_PROTOCOL_ID 17 +#define M2TP_PAYLOAD_PROTOCOL_ID 99 /* s-link */ +#endif /* sctpppids.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sigcomp-udvm.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sigcomp-udvm.h new file mode 100644 index 00000000..bcbb58fb --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sigcomp-udvm.h @@ -0,0 +1,49 @@ +/* udvm.h + * Routines making up the Univerasl Decompressor Virtual Machine (UDVM) used for + * Signaling Compression (SigComp) dissection. + * Copyright 2004, Anders Broman + * + * $Id: sigcomp-udvm.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * References: + * http://www.ietf.org/rfc/rfc3320.txt?number=3320 + * http://www.ietf.org/rfc/rfc3321.txt?number=3321 + * Useful links : + * http://www.ietf.org/internet-drafts/draft-ietf-rohc-sigcomp-impl-guide-02.txt + * http://www.ietf.org/internet-drafts/draft-ietf-rohc-sigcomp-sip-01.txt + */ + +#ifndef SIGCOMP_UDVM_H +#define SIGCOMP_UDVM_H + +#define UDVM_MEMORY_SIZE 65536 + +extern tvbuff_t* decompress_sigcomp_message(tvbuff_t *bytecode_tvb, tvbuff_t *message_tvb, packet_info *pinfo, + proto_tree *tree, gint destination, + gint print_flags, gint hf_id, gint header_len, + gint byte_code_state_len, gint byte_code_id_len, + gint udvm_start_ip); + + + +/* example: extern const value_string q931_cause_location_vals[]; */ +#endif +/* SIGCOMP_UDVM_H */ + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sigcomp_state_hdlr.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sigcomp_state_hdlr.h new file mode 100644 index 00000000..1a5beaf2 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sigcomp_state_hdlr.h @@ -0,0 +1,49 @@ +/* sigcomp_state_hdlr.c + * Routines making up the State handler of the Univerasl Decompressor Virtual Machine (UDVM) + * used for Signaling Compression (SigComp) dissection. + * Copyright 2004, Anders Broman + * + * $Id: sigcomp_state_hdlr.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * References: + * http://www.ietf.org/rfc/rfc3320.txt?number=3320 + * http://www.ietf.org/rfc/rfc3321.txt?number=3321 + * Useful links : + * http://www.ietf.org/internet-drafts/draft-ietf-rohc-sigcomp-impl-guide-03.txt + * http://www.ietf.org/internet-drafts/draft-ietf-rohc-sigcomp-sip-01.txt + */ + +#ifndef SIGCOMP_STATE_HDLR_H +#define SIGCOMP_STATE_HDLR_H + +extern const value_string result_code_vals[]; +extern int udvm_state_access(tvbuff_t *tvb, proto_tree *tree,guint8 *buff,guint16 p_id_start, guint16 p_id_length, guint16 state_begin, guint16 *state_length, + guint16 *state_address, guint16 *state_instruction, gint hf_id); + +extern void udvm_state_create(guint8 *state_buff,guint8 *state_identifier_buff,guint16 p_id_length); +extern void udvm_state_free(guint8 buff[],guint16 p_id_start,guint16 p_id_length); + +extern void sigcomp_init_udvm(void); + +#define STATE_BUFFER_SIZE 20 +#define STATE_MIN_ACCESS_LEN 6 + +#endif +/* SIGCOMP_STATE_HDLR_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/slab.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/slab.h new file mode 100644 index 00000000..c84e50ca --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/slab.h @@ -0,0 +1,75 @@ +/* slab.h + * Definitions for very simple slab handling + * + * $Id: slab.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __SLAB_H__ +#define __SLAB_H__ + +#define NITEMS_PER_SLAB 100 + +/* + * Generate declaration of a union type containing the specified type of + * slab-allocated item, and a pointer to an object of that type, for use + * in the macros below. + */ +#define SLAB_ITEM_TYPE_DEFINE(type) \ + union type ## slab_item { \ + type slab_item; \ + union type ## slab_item *next_free; \ + }; + +/* + * Generate definition of the free list pointer. + */ +#define SLAB_FREE_LIST_DEFINE(type) \ + union type ## slab_item *type ## _free_list = NULL; + +/* + * Generate an external declaration of the free list pointer. + */ +#define SLAB_FREE_LIST_DECLARE(type) \ + union type ## slab_item *type ## _free_list; + +/* we never free any memory we have allocated, when it is returned to us + we just store it in the free list until (hopefully) it gets used again +*/ +#define SLAB_ALLOC(item, type) \ + if(!type ## _free_list){ \ + int i; \ + union type ## slab_item *tmp; \ + tmp=g_malloc(NITEMS_PER_SLAB*sizeof(*tmp)); \ + for(i=0;islab_item); \ + type ## _free_list = type ## _free_list->next_free; + +#define SLAB_FREE(item, type) \ +{ \ + ((union type ## slab_item *)item)->next_free = type ## _free_list; \ + type ## _free_list = (union type ## slab_item *)item; \ +} + +#endif /* slab.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sminmpec.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sminmpec.h new file mode 100644 index 00000000..b81ea7c2 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sminmpec.h @@ -0,0 +1,83 @@ +/* sminmpec.h + * SMI Network Management Private Enterprise Codes for organizations + * + * $Id: sminmpec.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2004 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __SMINMPEC_H__ +#define __SMINMPEC_H__ + +/* + * These are SMI Network Management Private Enterprise Codes for + * organizations; see + * + * http://www.iana.org/assignments/enterprise-numbers + * + * for a list. + */ +#define VENDOR_IETF 0 /* reserved - used by the IETF in L2TP? */ +#define VENDOR_ACC 5 +#define VENDOR_CISCO 9 +#define VENDOR_HEWLETT_PACKARD 11 +#define VENDOR_SUN_MICROSYSTEMS 42 +#define VENDOR_MERIT 61 +#define VENDOR_MOTOROLA 161 +#define VENDOR_SHIVA 166 +#define VENDOR_ERICSSON 193 +#define VENDOR_CISCO_VPN5000 255 +#define VENDOR_LIVINGSTON 307 +#define VENDOR_MICROSOFT 311 +#define VENDOR_3COM 429 +#define VENDOR_ASCEND 529 +#define VENDOR_BAY 1584 +#define VENDOR_FOUNDRY 1991 +#define VENDOR_VERSANET 2180 +#define VENDOR_REDBACK 2352 +#define VENDOR_JUNIPER 2636 +#define VENDOR_APTIS 2637 +#define VENDOR_DT_AG 2937 +#define VENDOR_CISCO_VPN3000 3076 +#define VENDOR_COSINE 3085 +#define VENDOR_SHASTA 3199 +#define VENDOR_NETSCREEN 3224 +#define VENDOR_NOMADIX 3309 +#define VENDOR_T_MOBILE 3414 /* Former VoiceStream Wireless, Inc. */ +#define VENDOR_SIEMENS 4329 +#define VENDOR_CABLELABS 4491 +#define VENDOR_UNISPHERE 4874 +#define VENDOR_CISCO_BBSM 5263 +#define VENDOR_THE3GPP2 5535 +#define VENDOR_IP_UNPLUGGED 5925 +#define VENDOR_ISSANNI 5948 +#define VENDOR_DE_TE_MOBIL 6490 +#define VENDOR_QUINTUM 6618 +#define VENDOR_INTERLINK 6728 +#define VENDOR_COLUBRIS 8744 +#define VENDOR_COLUMBIA_UNIVERSITY 11862 +#define VENDOR_THE3GPP 10415 +#define VENDOR_GEMTEK_SYSTEMS 10529 +#define VENDOR_WIFI_ALLIANCE 14122 +#define VENDOR_T_SYSTEMS_NOVA 16787 + + +WS_VAR_IMPORT const value_string sminmpec_values[]; + +#endif /* __SMINMPEC_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sna-utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sna-utils.h new file mode 100644 index 00000000..8782af88 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sna-utils.h @@ -0,0 +1,41 @@ +/* sna-utils.h + * Definitions for SNA dissection. + * + * $Id: sna-utils.h 3992 2008-06-10 03:13:11Z dgu $ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __SNA_UTILS__ +#define __SNA_UTILS__ + +#include +#include + +/* + * Structure used to represent an FID Type 4 address; gives the layout of the + * data pointed to by an AT_SNA "address" structure if the size is + * SNA_FID_TYPE_4_ADDR_LEN. + */ +#define SNA_FID_TYPE_4_ADDR_LEN 6 +struct sna_fid_type_4_addr { + guint32 saf; + guint16 ef; +}; + +extern gchar *sna_fid_to_str(const address *addr); +extern void sna_fid_to_str_buf(const address *addr, gchar *buf, int buf_len); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stat_cmd_args.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stat_cmd_args.h new file mode 100644 index 00000000..56233f61 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stat_cmd_args.h @@ -0,0 +1,35 @@ +/* stat_cmd_args.h + * Declarations of routines to register "-z" command-line argument handlers + * for stats + * + * $Id: stat_cmd_args.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _STAT_H_ +#define _STAT_H_ + +extern void register_stat_cmd_arg(const char *cmd, + void (*func)(const char *arg,void* userdata), void* userdata); +extern gboolean process_stat_cmd_arg(char *optarg); +extern void list_stat_cmd_args(void); +extern void start_requested_stats(void); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stats_tree.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stats_tree.h new file mode 100644 index 00000000..ff36fd95 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stats_tree.h @@ -0,0 +1,147 @@ +/* stats_tree.h + * A counter tree API for Wireshark dissectors + * 2005, Luis E. G. Ontanon + * + * $Id: stats_tree.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef __STATS_TREE_H +#define __STATS_TREE_H + +#include +#include +#include +#include +#include +#include "../register.h" + +#define STAT_TREE_ROOT "root" + +/* obscure information regarding the stats_tree */ +typedef struct _stats_tree stats_tree; + +/* tap packet callback for stats_tree */ +typedef int (*stat_tree_packet_cb)(stats_tree*, + packet_info*, + epan_dissect_t*, + const void *); + +/* stats_tree initilaization callback */ +typedef void (*stat_tree_init_cb)(stats_tree*); + +/* stats_tree initilaization callback */ +typedef void (*stat_tree_cleanup_cb)(stats_tree*); + +/* registers a new stats tree + * abbr: protocol abbr + * name: protocol name + * packet: per packet callback + * init: tree initialization callback + */ +extern void stats_tree_register(const guint8* tapname, + const guint8* abbr, + const guint8* name, + stat_tree_packet_cb packet, + stat_tree_init_cb init, + stat_tree_cleanup_cb cleanup); + +extern int stats_tree_parent_id_by_name(stats_tree* st, const gchar* parent_name); + +/* Creates a node in the tree (to be used in the in init_cb) +* st: the stats_tree in which to create it +* name: the name of the new node +* parent_name: the name of the parent_node (NULL for root) +* with_children: TRUE if this node will have "dynamically created" children +*/ +extern int stats_tree_create_node(stats_tree* st, + const gchar* name, + int parent_id, + gboolean with_children); + +/* creates a node using it's parent's tree name */ +extern int stats_tree_create_node_by_pname(stats_tree* st, + const gchar* name, + const gchar* parent_name, + gboolean with_children); + +/* creates a node in the tree, that will contain a ranges list. + example: + stats_tree_create_range_node(st,name,parent, + "-99","100-199","200-299","300-399","400-", NULL); +*/ +extern int stats_tree_create_range_node(stats_tree* st, + const gchar* name, + int parent_id, + ...); + +extern int stats_tree_range_node_with_pname(stats_tree* st, + const gchar* name, + const gchar* parent_name, + ...); + +/* increases by one the ranged node and the sub node to whose range the value belongs */ +extern int stats_tree_tick_range(stats_tree* st, + const gchar* name, + int parent_id, + int value_in_range); + +#define stats_tree_tick_range_by_pname(st,name,parent_name,value_in_range) \ + stats_tree_tick_range((st),(name),stats_tree_parent_id_by_name((st),(parent_name),(value_in_range)) + +/* */ +extern int stats_tree_create_pivot(stats_tree* st, + const gchar* name, + int parent_id); + +extern int stats_tree_create_pivot_by_pname(stats_tree* st, + const gchar* name, + const gchar* parent_name); + +extern int stats_tree_tick_pivot(stats_tree* st, + int pivot_id, + const gchar* pivot_value); + +/* + * manipulates the value of the node whose name is given + * if the node does not exist yet it's created (with counter=1) + * using parent_name as parent node (NULL for root). + * with_children=TRUE to indicate that the created node will be a parent + */ +typedef enum _manip_node_mode { MN_INCREASE, MN_SET } manip_node_mode; +extern int stats_tree_manip_node(manip_node_mode mode, + stats_tree* st, + const guint8* name, + int parent_id, + gboolean with_children, + gint value); + +#define increase_stat_node(st,name,parent_id,with_children,value) \ +(stats_tree_manip_node(MN_INCREASE,(st),(name),(parent_id),(with_children),(value))) + +#define tick_stat_node(st,name,parent_id,with_children) \ +(stats_tree_manip_node(MN_INCREASE,(st),(name),(parent_id),(with_children),1)) + +#define set_stat_node(st,name,parent_id,with_children,value) \ +(stats_tree_manip_node(MN_SET,(st),(name),(parent_id),(with_children),value)) + +#define zero_stat_node(st,name,parent_id,with_children) \ +(stats_tree_manip_node(MN_SET,(st),(name),(parent_id),(with_children),0)) + +#endif /* __STATS_TREE_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stats_tree_priv.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stats_tree_priv.h new file mode 100644 index 00000000..80ca6a11 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stats_tree_priv.h @@ -0,0 +1,202 @@ +/* stats_tree_priv.h + * implementor's API for stats_tree + * 2005, Luis E. G. Ontanon + * + * $Id: stats_tree_priv.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __STATS_TREE_PRIV_H +#define __STATS_TREE_PRIV_H + +#include "stats_tree.h" + +#define INDENT_MAX 32 +#define NUM_BUF_SIZE 32 + +/* implementations should define this to contain its own node related data + * as well as some operations on it */ +typedef struct _st_node_pres st_node_pres; + +/* implementations should define this to contain its own dynamic tree related data +* as well as some operations on it */ +typedef struct _tree_pres tree_pres; + +/* implementations should define this to contain its own static tree related data +* as well as some operations on it */ +typedef struct _tree_cfg_pres tree_cfg_pres; + + +typedef struct _stat_node stat_node; +typedef struct _stats_tree_cfg stats_tree_cfg; + +typedef struct _range_pair { + gint floor; + gint ceil; +} range_pair_t; + +struct _stat_node { + gchar* name; + int id; + + /* the counter it keeps */ + gint counter; + + /* children nodes by name */ + GHashTable* hash; + + /* the owner of this node */ + stats_tree* st; + + /* relatives */ + stat_node* parent; + stat_node* children; + stat_node* next; + + /* used to check if value is within range */ + range_pair_t* rng; + + /* node presentation data */ + st_node_pres* pr; +}; + +struct _stats_tree { + /* the "class" from which it's derived */ + stats_tree_cfg* cfg; + + char* filter; + + /* times */ + double start; + double elapsed; + + /* used to lookup named parents: + * key: parent node name + * value: parent node + */ + GHashTable* names; + + /* used for quicker lookups of parent nodes */ + GPtrArray* parents; + + /* + * tree representation + * to be defined (if needed) by the implementations + */ + tree_pres* pr; + + /* every tree in nature has one */ + stat_node root; +}; + +struct _stats_tree_cfg { + guint8* abbr; + guint8* name; + guint8* tapname; + + gboolean in_use; + + /* dissector defined callbacks */ + stat_tree_packet_cb packet; + stat_tree_init_cb init; + stat_tree_cleanup_cb cleanup; + + /* + * node presentation callbacks + */ + + /* last to be called at node creation */ + void (*setup_node_pr)(stat_node*); + + /* last to be called at node destruction */ + void (*free_node_pr)(stat_node*); + + /* to be called for every node in the tree */ + void (*draw_node)(stat_node*); + void (*reset_node)(stat_node*); + + /* + * tree presentation callbacks + */ + tree_cfg_pres* pr; + + + tree_pres* (*new_tree_pr)(stats_tree*); + void (*free_tree_pr)(stats_tree*); + void (*draw_tree)(stats_tree*); + void (*reset_tree)(stats_tree*); +}; + +/* guess what, this is it! */ +extern void stats_tree_presentation(void (*registry_iterator)(gpointer,gpointer,gpointer), + void (*setup_node_pr)(stat_node*), + void (*free_node_pr)(stat_node*), + void (*draw_node)(stat_node*), + void (*reset_node)(stat_node*), + tree_pres* (*new_tree_pr)(stats_tree*), + void (*free_tree_pr)(stats_tree*), + void (*draw_tree)(stats_tree*), + void (*reset_tree)(stats_tree*), + void* data); + +extern stats_tree* stats_tree_new(stats_tree_cfg* cfg, tree_pres* pr, char* filter); + +/* callback for taps */ +extern int stats_tree_packet(void*, packet_info*, epan_dissect_t*, const void *); + +/* callback for reset */ +extern void stats_tree_reset(void* p_st); + +/* callback for clear */ +extern void stats_tree_reinit(void* p_st); + +/* callback for destoy */ +extern void stats_tree_free(stats_tree* st); + +/* given an optarg splits the abbr part + and returns a newly allocated buffer containing it */ +extern guint8* stats_tree_get_abbr(const guint8* optarg); + +/* obtains a stats tree from the registry given its abbr */ +extern stats_tree_cfg* stats_tree_get_cfg_by_abbr(guint8* abbr); + +/* extracts node data as strings from a stat_node into + the buffers given by value, rate and precent + if NULL they are ignored */ +extern void stats_tree_get_strs_from_node(const stat_node* node, + guint8* value, + guint8* rate, + guint8* percent); + +/* populates the given GString with a tree representation of a branch given by node, + using indent spaces as indentation */ +extern void stats_tree_branch_to_str(const stat_node* node, + GString* s, + guint indent); + +/* used to calcuate the size of the indentation and the longest string */ +extern guint stats_tree_branch_max_namelen(const stat_node* node, guint indent); + +/* a text representation of a node, + if buffer is NULL returns a newly allocated string */ +extern guint8* stats_tree_node_to_str(const stat_node* node, + guint8* buffer, guint len); + +#endif /* __STATS_TREE_PRIV_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stream.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stream.h new file mode 100644 index 00000000..9fd1cc90 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stream.h @@ -0,0 +1,138 @@ +/* stream.h + * + * Definititions for handling circuit-switched protocols + * which are handled as streams, and don't have lengths + * and IDs such as are required for reassemble.h + * + * $Id: stream.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef STREAM_H +#define STREAM_H + +#include + +struct _fragment_items; + +/* A stream represents the concept of an arbitrary stream of data, + divided up into frames for transmission, where the frames have + little or no correspondence to the PDUs of the protocol being + streamed, and those PDUs are just delineated by a magic number. + + For example, we stream H.223 over IAX2. IAX2 has no concept of + H.223 PDUs and just divides the H.223 stream into 160-byte + frames. H.223 PDUs are delineated by two-byte magic numbers (which + may, of course, straddle an IAX2 frame boundary). + + Essentially we act as a wrapper to reassemble.h, by making up + PDU ids and keeping some additional data on fragments to allow the + PDUs to be defragmented again. +*/ + + +/* A stream_t represents a stream. There might be one or two streams + in a circuit, depending on whether that circuit is mono- or bi-directional. +*/ +typedef struct stream stream_t; + +/* Fragments in a PDU are represented using a stream_pdu_fragment_t, + and placed in a linked-list with other fragments in the PDU. + + (They're also placed in a hash so we can find them again later) +*/ +typedef struct stream_pdu_fragment stream_pdu_fragment_t; + + + +struct circuit; +struct conversation; + +/* initialise a new stream. Call this when you first identify a distinct + * stream. The circit pointer is just used as a key to look up the stream. */ +extern stream_t *stream_new_circ ( const struct circuit *circuit, int p2p_dir ); +extern stream_t *stream_new_conv ( const struct conversation *conv, int p2p_dir ); + +/* retrieve a previously-created stream. + * + * Returns null if no matching stream was found. + */ +extern stream_t *find_stream_circ ( const struct circuit *circuit, int p2p_dir ); +extern stream_t *find_stream_conv ( const struct conversation *conv, int p2p_dir ); + + + +/* see if we've seen this fragment before. + + The framenum and offset are just hash keys, so can be any values unique + to this frame, but the idea is that you use the number of the frame being + disassembled, and the byte-offset within that frame. +*/ +extern stream_pdu_fragment_t *stream_find_frag( stream_t *stream, guint32 framenum, guint32 offset ); + +/* add a new fragment to the fragment tables for the stream. The framenum and + * offset are keys allowing future access with stream_find_frag(), tvb is the + * fragment to be added, and pinfo is the information for the frame containing + * this fragment. more_frags should be set if this is the final fragment in the + * PDU. + * + * * the fragment must be later in the stream than any previous fragment + * (ie, framenum.offset must be greater than those passed on the previous + * call) + * + * This essentially means that you can only add fragments on the first pass + * through the stream. + */ +extern stream_pdu_fragment_t *stream_add_frag( stream_t *stream, guint32 framenum, guint32 offset, + tvbuff_t *tvb, packet_info *pinfo, gboolean more_frags ); + +/* Get the length of a fragment previously found by stream_find_frag(). + */ +extern guint32 stream_get_frag_length( const stream_pdu_fragment_t *frag); + +/* Get a handle on the top of the chain of fragment_datas underlying this PDU + * frag can be any fragment within a PDU, and it will always return the head of + * the chain + * + * Returns NULL until the last fragment is added. + */ +extern struct _fragment_data *stream_get_frag_data( const stream_pdu_fragment_t *frag); + +/* + * Process reassembled data; if this is the last fragment, put the fragment + * information into the protocol tree, and construct a tvbuff with the + * reassembled data, otherwise just put a "reassembled in" item into the + * protocol tree. + */ +extern tvbuff_t *stream_process_reassembled( + tvbuff_t *tvb, int offset, packet_info *pinfo, + char *name, const stream_pdu_fragment_t *frag, + const struct _fragment_items *fit, + gboolean *update_col_infop, proto_tree *tree); + +/* Get the PDU number. PDUs are numbered from zero within a stream. + * frag can be any fragment within a PDU. + */ +extern guint32 stream_get_pdu_no( const stream_pdu_fragment_t *frag); + +/* initialise the stream routines */ +void stream_init( void ); + +#endif /* STREAM_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/strutil.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/strutil.h new file mode 100644 index 00000000..4b108175 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/strutil.h @@ -0,0 +1,243 @@ +/* strutil.h + * String utility definitions + * + * $Id: strutil.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __STRUTIL_H__ +#define __STRUTIL_H__ + +/* ... thus, config.h needs to be #included */ + +/** @file + * String handling and conversion utilities. + */ + +/** Given a pointer into a data buffer, and to the end of the buffer, + * find the end of the (putative) line at that position in the data + * buffer. + * + * @param data A pointer to the beginning of the data + * @param dataend A pointer to the end of the data + * @param eol A pointer that will receive the EOL location + * @return A pointer to the EOL character(s) in "*eol". + */ +const guchar *find_line_end(const guchar *data, const guchar *dataend, + const guchar **eol); + +/** Get the length of the next token in a line, and the beginning of the + * next token after that (if any). + * @param linep A pointer to the beginning of the line + * @param lineend A pointer to the end of the line + * @param next_token Receives the location of the next token + * @return 0 if there is no next token. + */ +int get_token_len(const guchar *linep, const guchar *lineend, + const guchar **next_token); + +/** Given a string, generate a string from it that shows non-printable + * characters as C-style escapes, and return a pointer to it. + * + * @param line A pointer to the input string + * @param len The length of the input string + * @return A pointer to the formatted string + * + * @see tvb_format_text() + */ +gchar* format_text(const guchar *line, int len); + +gchar* format_text_wsp(const guchar *line, int len); + +/** Turn an array of bytes into a string showing the bytes in hex. + * + * @param bd A pointer to the byte array + * @param bd_len The length of the byte array + * @return A pointer to the formatted string + * + * @see bytes_to_str_punct() + */ +gchar* bytes_to_str(const guint8 *bd, int bd_len); + +/** Turn an array of bytes into a string showing the bytes in hex, + * separated by a punctuation character. + * + * @param bd A pointer to the byte array + * @param bd_len The length of the byte array + * @param punct The punctuation character + * @return A pointer to the formatted string + * + * @see bytes_to_str() + */ +gchar* bytes_to_str_punct(const guint8 *bd, int bd_len, gchar punct); + +/** Turn a string of hex digits with optional separators (defined by + * is_byte_sep() into a byte array. + * + * @param hex_str The string of hex digits. + * @param bytes The GByteArray that will receive the bytes. This + * must be initialized by the caller. + * @param force_separators If set to TRUE, separators MUST exist between + * bytes. + * @return True if the string was converted successfully + */ +gboolean hex_str_to_bytes(const char *hex_str, GByteArray *bytes, + gboolean force_separators); + +/** Turn an RFC 3986 percent-encoded string into a byte array. + * + * @param uri_str The string of hex digits. + * @param bytes The GByteArray that will receive the bytes. This + * must be initialized by the caller. + * @return True if the string was converted successfully + * @see format_uri() + */ +gboolean uri_str_to_bytes(const char *uri_str, GByteArray *bytes); + +/** Turn a byte array into an RFC 3986 percent-encoded string. + * + * @param bytes The GByteArray that will receive the bytes. This + * must be initialized by the caller. + * @param reserved_chars Normally the "gen-delims" and "sub-delims" + * from RFC 3986 (":/?#[]@" and "!$&'()*+,;=" respectively) + * plus space (hex value 20) are treated as reserved characters. + * If this variable is non-NULL, its contents will be used + * instead. + * @note Any non-printing character determined by isprint(), along + * with the % character itself are always reserved. + * @see uri_str_to_bytes(), format_text(), isprint() + */ +gchar* format_uri(const GByteArray *bytes, const gchar *reserved_chars); + +/** Turn a OID string representation (dot notation) into a byte array. + * + * @param oid_str The OID string (dot notaion). + * @param bytes The GByteArray that will receive the bytes. This + * must be initialized by the caller. + * @return True if the string was converted successfully + */ +gboolean oid_str_to_bytes(const char *oid_str, GByteArray *bytes); + +/** + * Create a copy of a GByteArray + * + * @param ba The byte array to be copied. + * @return If ba exists, a freshly allocated copy. NULL otherwise. + * + * XXX - Should this be in strutil.c? + */ +GByteArray *byte_array_dup(GByteArray *ba); + +/** + * Compare the contents of two GByteArrays + * + * @param ba1 A byte array + * @param ba2 A byte array + * @return If both arrays are non-NULL and their lengths are equal and + * their contents are equal, returns TRUE. Otherwise, returns + * FALSE. + * + * XXX - Should this be in strutil.c? + */ +gboolean byte_array_equal(GByteArray *ba1, GByteArray *ba2); + + +/** Return a XML escaped representation of the unescaped string. + * The returned string must be freed when no longer in use. + * + * @param unescaped The unescaped string + * @return An XML-escaped representation of the input string + */ +gchar* xml_escape(const gchar *unescaped); + +/** + * Return the first occurrence of needle in haystack. + * Algorithm copied from GNU's glibc 2.3.2 memcmp() + * + * @param haystack The data to search + * @param haystack_len The length of the search data + * @param needle The string to look for + * @param needle_len The length of the search string + * @return A pointer to the first occurrence of "needle" in + * "haystack". If "needle" isn't found or is NULL, or if + * "needle_len" is 0, NULL is returned. + */ +const guint8 * epan_memmem(const guint8 *haystack, guint haystack_len, + const guint8 *needle, guint needle_len); + +/* Surround a string or a macro, resolved to a string, with double quotes */ +#define _STRINGIFY(a) # a +#define STRINGIFY(a) _STRINGIFY(a) + +/** Scan a string to make sure it's valid hex. + * + * @param string The string to validate + * @param nbytes The length of the return buffer + * @return A pointer to a buffer containing the converted raw bytes. This + * buffer must be g_free()d by the caller. + */ +guint8 * convert_string_to_hex(const char *string, size_t *nbytes); + +/** Prep a string for case-sensitive vs case-insensitive searching. + * + * @param string The search string + * @param case_insensitive TRUE if case-insensitive, FALSE if not + * @return A direct copy of the string if it's a case-sensitive search and + * an uppercased version if not. In either case the string must be g_free()d + * by the caller. + */ +char * convert_string_case(const char *string, gboolean case_insensitive); + +/** Finds the first occurence of string 'needle' in string 'haystack'. + * The matching is done in a case insensitive manner. + * + * @param haystack The string possibly containing the substring + * @param needle The substring to be searched + * @return A pointer into 'haystack' where 'needle' is first found. + * Otherwise it returns NULL. + */ +char * epan_strcasestr(const char *haystack, const char *needle); + +/* g_strlcat() does not exist in GLib 1.2[.x] */ +#if GLIB_MAJOR_VERSION < 2 +gsize g_strlcat(gchar *dst, const gchar *src, gsize size); +gsize g_strlcpy(gchar *dest, const gchar *src, gsize dest_size); +#endif + +#if GLIB_MAJOR_VERSION < 2 +/* g_ascii_isprint() does not exist in GLib 1.2[.x]. + * assume all codes >=0x20 and <0x80 are ASCII printables. + */ +#define g_ascii_isprint(c) \ + (((c<0x20)||(c>=0x80))?FALSE:TRUE) +/* g_ascii_isxdigit() does not exist in Glib 1.2 */ +#define g_ascii_isxdigit(c) \ + ( ((c>='0')&&(c<='9'))?TRUE: \ + ( ((c>='a')&&(c<='f'))?TRUE: \ + (((c>='A')&&(c<='F'))?TRUE:FALSE) ) ) + +#endif + +#if GLIB_MAJOR_VERSION < 2 +/* g_byte_array_sized_new() doesnt exist in glib-1.2 */ +GByteArray *g_byte_array_sized_new(guint reserved_size); +#endif + +#endif /* __STRUTIL_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/t35.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/t35.h new file mode 100644 index 00000000..692c0b8d --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/t35.h @@ -0,0 +1,35 @@ +/* t35.h + * T.35 and H.221 tables + * 2003 Tomas Kukosa + * + * $Id: t35.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __T35_H__ +#define __T35_H__ + +#include "epan/value_string.h" + +extern const value_string T35CountryCode_vals[]; +extern const value_string T35Extension_vals[]; +extern const value_string H221ManufacturerCode_vals[]; + +#endif /* __T35_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tap-voip.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tap-voip.h new file mode 100644 index 00000000..21888588 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tap-voip.h @@ -0,0 +1,59 @@ +/* tap-voip.h + * VoIP packet tap interface 2007 Tomas Kukosa + * + * $Id: tap-voip.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _TAP_VOIP_H_ +#define _TAP_VOIP_H_ + +/* defines voip call state */ +typedef enum _voip_call_state { + VOIP_NO_STATE, + VOIP_CALL_SETUP, + VOIP_RINGING, + VOIP_IN_CALL, + VOIP_CANCELLED, + VOIP_COMPLETED, + VOIP_REJECTED, + VOIP_UNKNOWN +} voip_call_state; + +typedef enum _voip_call_active_state { + VOIP_ACTIVE, + VOIP_INACTIVE +} voip_call_active_state; + +/* structure for common/proprietary VoIP calls TAP */ +typedef struct _voip_packet_info_t +{ + gchar *protocol_name; + gchar *call_id; + voip_call_state call_state; + voip_call_active_state call_active_state; + gchar *from_identity; + gchar *to_identity; + gchar *call_comment; + gchar *frame_label; + gchar *frame_comment; +} voip_packet_info_t; + +#endif /* _TAP_VOIP_H_ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tap.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tap.h new file mode 100644 index 00000000..11ca6fcb --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tap.h @@ -0,0 +1,61 @@ +/* tap.h + * packet tap interface 2002 Ronnie Sahlberg + * + * $Id: tap.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _TAP_H_ +#define _TAP_H_ + +#include "epan/epan.h" + +#ifdef INTTYPES_H_DEFINES_FORMATS +#include +#endif + +/* With MSVC and a libwireshark.dll, we need a + * special declaration of num_tap_filters. + */ +WS_VAR_IMPORT int num_tap_filters; + +typedef void (*tap_reset_cb)(void *tapdata); +typedef int (*tap_packet_cb)(void *tapdata, packet_info *pinfo, epan_dissect_t *edt, const void *data); +typedef void (*tap_draw_cb)(void *tapdata); + + +extern void tap_init(void); +extern int register_tap(const char *name); +extern int find_tap_id(const char *name); +extern void tap_queue_packet(int tap_id, packet_info *pinfo, const void *tap_specific_data); +extern void tap_queue_init(epan_dissect_t *edt); +extern void tap_push_tapped_queue(epan_dissect_t *edt); +extern void reset_tap_listeners(void); +extern void draw_tap_listeners(gboolean draw_all); +extern GString *register_tap_listener(const char *tapname, void *tapdata, + const char *fstring, tap_reset_cb tap_reset, tap_packet_cb tap_packet, + tap_draw_cb tap_draw); +extern GString *set_tap_dfilter(void *tapdata, const char *fstring); +extern void remove_tap_listener(void *tapdata); +extern gboolean have_tap_listeners(void); +extern gboolean have_tap_listener(int tap_id); +extern const void *fetch_tapped_data(int tap_id, int idx); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tcap-persistentdata.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tcap-persistentdata.h new file mode 100644 index 00000000..4e9c278f --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tcap-persistentdata.h @@ -0,0 +1,148 @@ +/* + * tcap-persistentdata.h + * Definitions for lists and hash tables used in wireshark's tcap dissector + * for calculation of delays in tcap-transactions + * Copyright 2006 Florent Drouin (based on h225-persistentdata from Lars Roland) + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * $Id: tcap-persistentdata.h 3992 2008-06-10 03:13:11Z dgu $ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __tcapsrt_HASH__ +#define __tcapsrt_HASH__ + +#include "epan/packet.h" +#include "epan/conversation.h" +#include "epan/dissectors/packet-tcap.h" + +#define LENGTH_OID 16 +struct tcaphash_context_t { + struct tcaphash_context_key_t * key; + guint32 session_id; + guint32 first_frame; + guint32 last_frame; + nstime_t begin_time; /* time of arrival of TC_BEGIN */ + nstime_t end_time; /* time of closing message */ + gboolean responded; /* true, if request has been responded */ + gboolean closed; + gboolean upper_dissector; + gboolean oid_present; + gchar oid[LENGTH_OID+1]; + gboolean subdissector_present; + dissector_handle_t subdissector_handle; + void (* callback) (tvbuff_t *,packet_info *, proto_tree *, struct tcaphash_context_t *); + struct tcaphash_begincall_t * begincall; + struct tcaphash_contcall_t * contcall; + struct tcaphash_endcall_t * endcall; + struct tcaphash_ansicall_t * ansicall; +}; + +struct tcaphash_begincall_t { + struct tcaphash_begin_info_key_t * beginkey; + struct tcaphash_context_t * context; + gboolean father; + struct tcaphash_begincall_t * next_begincall; + struct tcaphash_begincall_t * previous_begincall; +}; + +struct tcaphash_contcall_t { + struct tcaphash_cont_info_key_t * contkey; + struct tcaphash_context_t * context; + gboolean father; + struct tcaphash_contcall_t * next_contcall; + struct tcaphash_contcall_t * previous_contcall; +}; + +struct tcaphash_endcall_t { + struct tcaphash_end_info_key_t * endkey; + struct tcaphash_context_t * context; + gboolean father; + struct tcaphash_endcall_t * next_endcall; + struct tcaphash_endcall_t * previous_endcall; +}; + +struct tcaphash_ansicall_t { + struct tcaphash_ansi_info_key_t * ansikey; + struct tcaphash_context_t * context; + gboolean father; + struct tcaphash_ansicall_t * next_ansicall; + struct tcaphash_ansicall_t * previous_ansicall; +}; + +/* The Key for the hash table is the TCAP origine transaction identifier + of the TC_BEGIN containing the InitialDP */ + +struct tcaphash_context_key_t { + guint32 session_id; +}; + +struct tcaphash_begin_info_key_t { + guint32 hashKey; + guint32 tid; + guint32 opc_hash; + guint32 dpc_hash; +}; + +struct tcaphash_cont_info_key_t { + guint32 hashKey; + guint32 src_tid; + guint32 dst_tid; + guint32 opc_hash; + guint32 dpc_hash; +}; + +struct tcaphash_end_info_key_t { + guint32 hashKey; + guint32 tid; + guint32 opc_hash; + guint32 dpc_hash; +}; + +struct tcaphash_ansi_info_key_t { + guint32 hashKey; + guint32 tid; + guint32 opc_hash; + guint32 dpc_hash; +}; + + +/* List of infos to store for the analyse */ +struct tcapsrt_info_t { + guint32 tcap_session_id; + guint32 src_tid; + guint32 dst_tid; + guint8 ope; +}; + +void tcapsrt_init_routine(void); + +struct tcapsrt_info_t * tcapsrt_razinfo(void); + +void tcapsrt_close(struct tcaphash_context_t * p_tcaphash_context, + packet_info * pinfo _U_); + +struct tcaphash_context_t * tcapsrt_call_matching(tvbuff_t *tvb, + packet_info * pinfo _U_, + proto_tree *tree, + struct tcapsrt_info_t * p_tcap_info); + +WS_VAR_IMPORT gboolean gtcap_StatSRT; + +#endif /* __tcapsrt_HASH__*/ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tfs.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tfs.h new file mode 100644 index 00000000..e77f0b9c --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tfs.h @@ -0,0 +1,65 @@ +/* tfs.h + * true_false strings + * Copyright 2007, Jaap Keuter + * + * $Id: tfs.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __TFS_H__ +#define __TFS_H__ + +/* Struct for boolean enumerations */ +typedef struct true_false_string { + const char *true_string; + const char *false_string; +} true_false_string; + +/* + * A default set of true/false strings that dissectors can use for + * FT_BOOLEAN header fields. + */ +WS_VAR_IMPORT const true_false_string tfs_true_false; +WS_VAR_IMPORT const true_false_string tfs_yes_no; +WS_VAR_IMPORT const true_false_string tfs_set_notset; +WS_VAR_IMPORT const true_false_string tfs_enabled_disabled; +WS_VAR_IMPORT const true_false_string tfs_ok_error; +WS_VAR_IMPORT const true_false_string tfs_success_fail; +WS_VAR_IMPORT const true_false_string tfs_on_off; +WS_VAR_IMPORT const true_false_string tfs_ack_nack; +WS_VAR_IMPORT const true_false_string tfs_odd_even; +WS_VAR_IMPORT const true_false_string tfs_allow_block; +WS_VAR_IMPORT const true_false_string tfs_restricted_allowed; +WS_VAR_IMPORT const true_false_string tfs_accept_reject; +WS_VAR_IMPORT const true_false_string tfs_more_nomore; +WS_VAR_IMPORT const true_false_string tfs_present_absent; +WS_VAR_IMPORT const true_false_string tfs_active_inactive; +WS_VAR_IMPORT const true_false_string tfs_found_not_found; +WS_VAR_IMPORT const true_false_string tfs_command_response; +WS_VAR_IMPORT const true_false_string tfs_capable_not_capable; +WS_VAR_IMPORT const true_false_string tfs_supported_not_supported; + +/* + * Old true_false_string from packet.c + * Retained for backward compatibility until all dissectors are updated. + */ +WS_VAR_IMPORT const true_false_string flags_set_truth; + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/timestamp.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/timestamp.h new file mode 100644 index 00000000..e357ee21 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/timestamp.h @@ -0,0 +1,68 @@ +/* timestamp.h + * Defines for packet timestamps + * + * $Id: timestamp.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __TIMESTAMP_H__ +#define __TIMESTAMP_H__ + +/* + * Type of time-stamp shown in the summary display. + */ +typedef enum { + TS_RELATIVE, /* Since start of capture */ + TS_ABSOLUTE, + TS_ABSOLUTE_WITH_DATE, + TS_DELTA, /* Since previous captured packet */ + TS_DELTA_DIS, /* Since previous displayed packet */ + TS_EPOCH, /* Seconds (and fractions) since epoch */ + +/* + * Special value used for the command-line setting in Wireshark, to indicate + * that no value has been set from the command line. + */ + TS_NOT_SET +} ts_type; + +typedef enum { + TS_PREC_AUTO, /* recent */ + TS_PREC_FIXED_SEC, /* recent and internal */ + TS_PREC_FIXED_DSEC, /* recent and internal */ + TS_PREC_FIXED_CSEC, /* recent and internal */ + TS_PREC_FIXED_MSEC, /* recent and internal */ + TS_PREC_FIXED_USEC, /* recent and internal */ + TS_PREC_FIXED_NSEC, /* recent and internal */ + TS_PREC_AUTO_SEC, /* internal */ + TS_PREC_AUTO_DSEC, /* internal */ + TS_PREC_AUTO_CSEC, /* internal */ + TS_PREC_AUTO_MSEC, /* internal */ + TS_PREC_AUTO_USEC, /* internal */ + TS_PREC_AUTO_NSEC /* internal */ +} ts_precision; + +extern ts_type timestamp_get_type(void); +extern void timestamp_set_type(ts_type); + +extern int timestamp_get_precision(void); +extern void timestamp_set_precision(int tsp); + +#endif /* timestamp.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/to_str.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/to_str.h new file mode 100644 index 00000000..a1e8028b --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/to_str.h @@ -0,0 +1,94 @@ +/* to_str.h + * Definitions for utilities to convert various other types to strings. + * + * $Id: to_str.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __TO_STR_H__ +#define __TO_STR_H__ + +#include + +#include "nstime.h" +#include "epan/packet_info.h" + +#define GUID_STR_LEN 37 +#define MAX_IP_STR_LEN 16 +#define MAX_ADDR_STR_LEN 256 + +/* + * Resolution of a time stamp. + */ +typedef enum { + SECS, /* seconds */ + DSECS, /* deciseconds */ + CSECS, /* centiseconds */ + MSECS, /* milliseconds */ + USECS, /* microseconds */ + NSECS /* nanoseconds */ +} time_res_t; + +/* + * These are utility functions which convert various types to strings, + * but for which no more specific module applies. + */ + +struct e_in6_addr; + +extern gchar* address_to_str(const address *); +extern void address_to_str_buf(const address *addr, gchar *buf, int buf_len); +extern gchar* bytestring_to_str(const guint8 *, guint32, char); +extern gchar* ether_to_str(const guint8 *); +extern gchar* ip_to_str(const guint8 *); +extern void ip_to_str_buf(const guint8 *ad, gchar *buf, int buf_len); +extern gchar* fc_to_str(const guint8 *); +extern gchar* fcwwn_to_str (const guint8 *); +extern gchar* ip6_to_str(const struct e_in6_addr *); +extern void ip6_to_str_buf(const struct e_in6_addr *, gchar *); +extern gchar* ipx_addr_to_str(guint32, const guint8 *); +extern gchar* ipxnet_to_string(const guint8 *ad); +extern gchar* ipxnet_to_str_punct(const guint32 ad, char punct); +extern gchar* vines_addr_to_str(const guint8 *addrp); +extern void vines_addr_to_str_buf(const guint8 *addrp, gchar *buf, int buf_len); +extern gchar* time_secs_to_str(gint32); +extern gchar* time_msecs_to_str(gint32); +extern gchar* abs_time_to_str(nstime_t*); +extern gchar* abs_time_secs_to_str(time_t); +extern void display_signed_time(gchar *, int, gint32, gint32, time_res_t); +extern void display_epoch_time(gchar *, int, time_t, gint32, time_res_t); + +extern gchar* rel_time_to_str(nstime_t*); +extern gchar* rel_time_to_secs_str(nstime_t*); +extern gchar* guid_to_str(const e_guid_t*); +extern gchar* guid_to_str_buf(const e_guid_t*, gchar*, int); + +void tipc_addr_to_str_buf( const guint8 *data, gchar *buf, int buf_len); + +extern char *other_decode_bitfield_value(char *buf, guint32 val, guint32 mask, + int width); +extern char *decode_bitfield_value(char *buf, guint32 val, guint32 mask, + int width); +extern const char *decode_boolean_bitfield(guint32 val, guint32 mask, int width, + const char *truedesc, const char *falsedesc); +extern const char *decode_numeric_bitfield(guint32 val, guint32 mask, int width, + const char *fmt); + +#endif /* __TO_STR_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tvbparse.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tvbparse.h new file mode 100644 index 00000000..4e04a1b3 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tvbparse.h @@ -0,0 +1,475 @@ + +/* tvbparse.h +* +* an API for text tvb parsers +* +* Copyright 2005, Luis E. Garcia Ontanon +* +* $Id: tvbparse.h 3992 2008-06-10 03:13:11Z dgu $ +* +* Wireshark - Network traffic analyzer +* By Gerald Combs +* Copyright 1998 Gerald Combs +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* + The intention behind this is to ease the writing of dissectors that have to + parse text without the need of writing into buffers. + + It was originally written to avoid using lex and yacc for the xml dissector. + + the parser is able to look for wanted elements these can be: + + simple tokens: + - a char out of a string of needles + - a char not belonging to a string of needles + - a sequence of chars that belong to a set of chars + - a sequence of chars that do not belong to a set of chars + - a string + - a caseless string + - all the characters up to a certain wanted element (included or excluded) + + composed elements: + - one of a given group of wanted elements + - a sequence of wanted elements + - some (at least one) instances of a wanted element + + Once a wanted element is successfully extracted, by either tvbparse_get or + tvbparse_find, the parser will invoke a given callback + before and another one after every of its component's subelement's callbacks + are being called. + + If tvbparse_get or tvbparse_find fail to extract the wanted element the + subelements callbacks are not going to be invoked. + + The wanted elements are instantiated once by the proto_register_xxx function. + + The parser is isntantiated for every packet and it mantains its state. + + The element's data is destroyed before the next packet is dissected. + */ + +#ifndef _TVB_PARSE_H_ +#define _TVB_PARSE_H_ + +#include +#include + +typedef struct _tvbparse_elem_t tvbparse_elem_t; +typedef struct _tvbparse_wanted_t tvbparse_wanted_t; +typedef struct _tvbparse_t tvbparse_t; + + +/* + * a callback function to be called before or after an element has been + * successfuly extracted. + * + * Note that if the token belongs to a composed token the callbacks of the + * components won't be called unless the composed token is successfully + * extracted. + * + * tvbparse_data: the private data of the parser + * wanted_data: the private data of the wanted element + * elem: the extracted element + */ +typedef void (*tvbparse_action_t)(void* tvbparse_data, const void* wanted_data, struct _tvbparse_elem_t* elem); + +typedef int (*tvbparse_condition_t) +(tvbparse_t*, int, + const tvbparse_wanted_t*, + tvbparse_elem_t**); + + +typedef enum { + TP_UNTIL_INCLUDE, /* last elem is included, its span is spent by the parser */ + TP_UNTIL_SPEND, /* last elem is not included, but its span is spent by the parser */ + TP_UNTIL_LEAVE /* last elem is not included, neither its span is spent by the parser */ +} until_mode_t; + + +struct _tvbparse_wanted_t { + int id; + tvbparse_condition_t condition; + + union { + const gchar* str; + struct _tvbparse_wanted_t** handle; + struct { + union { + gint64 i; + guint64 u; + gdouble f; + } value; + gboolean (*comp)(void*,const void*); + void* (*extract)(tvbuff_t*,guint); + } number; + enum ftenum ftenum; + struct { + until_mode_t mode; + const tvbparse_wanted_t* subelem; + } until; + struct { + GHashTable* table; + struct _tvbparse_wanted_t* key; + struct _tvbparse_wanted_t* other; + } hash; + GPtrArray* elems; + const tvbparse_wanted_t* subelem; + void* p; + } control; + + int len; + + guint min; + guint max; + + const void* data; + + tvbparse_action_t before; + tvbparse_action_t after; + +}; + +/* an instance of a per packet parser */ +struct _tvbparse_t { + tvbuff_t* tvb; + int offset; + int end_offset; + void* data; + const tvbparse_wanted_t* ignore; +}; + + +/* a matching token returned by either tvbparser_get or tvb_parser_find */ +struct _tvbparse_elem_t { + int id; + + tvbuff_t* tvb; + int offset; + int len; + + void* data; + + struct _tvbparse_elem_t* sub; + + struct _tvbparse_elem_t* next; + struct _tvbparse_elem_t* last; + + const tvbparse_wanted_t* wanted; +}; + + +/* + * definition of wanted token types + * + * the following functions define the tokens we will be able to look for in a tvb + * common parameters are: + * + * id: an arbitrary id that will be copied to the eventual token (don't use 0) + * private_data: persistent data to be passed to the callback action (wanted_data) + * before_cb: an callback function to be called before those of the subelements + * after_cb: an callback function to be called after those of the subelements + */ + + +/* + * a char element. + * + * When looked for it returns a simple element one character long if the char + * at the current offset matches one of the the needles. + */ +tvbparse_wanted_t* tvbparse_char(int id, + const gchar* needles, + const void* private_data, + tvbparse_action_t before_cb, + tvbparse_action_t after_cb); + +/* + * a not_char element. + * + * When looked for it returns a simple element one character long if the char + * at the current offset does not match one of the the needles. + */ +tvbparse_wanted_t* tvbparse_not_char(int id, + const gchar* needle, + const void* private_data, + tvbparse_action_t before_cb, + tvbparse_action_t after_cb); + +/* + * a chars element + * + * When looked for it returns a simple element one or more characters long if + * one or more char(s) starting from the current offset match one of the needles. + * An element will be returned if at least min_len chars are given (1 if it's 0) + * It will get at most max_len chars or as much as it can if max_len is 0. + */ +tvbparse_wanted_t* tvbparse_chars(int id, + guint min_len, + guint max_len, + const gchar* needles, + const void* private_data, + tvbparse_action_t before_cb, + tvbparse_action_t after_cb); + +/* + * a not_chars element + * + * When looked for it returns a simple element one or more characters long if + * one or more char(s) starting from the current offset do not match one of the + * needles. + * An element will be returned if at least min_len chars are given (1 if it's 0) + * It will get at most max_len chars or as much as it can if max_len is 0. + */ +tvbparse_wanted_t* tvbparse_not_chars(int id, + guint min_len, + guint max_len, + const gchar* needles, + const void* private_data, + tvbparse_action_t before_cb, + tvbparse_action_t after_cb); + +/* + * a string element + * + * When looked for it returns a simple element if we have the given string at + * the current offset + */ +tvbparse_wanted_t* tvbparse_string(int id, + const gchar* string, + const void* private_data, + tvbparse_action_t before_cb, + tvbparse_action_t after_cb); + +/* + * casestring + * + * When looked for it returns a simple element if we have a matching string at + * the current offset + */ +tvbparse_wanted_t* tvbparse_casestring(int id, + const gchar* str, + const void* data, + tvbparse_action_t before_cb, + tvbparse_action_t after_cb); + +/* + * until + * + * When looked for it returns a simple element containing all the characters + * found until the first match of the ending element if the ending element is + * found. + * + * When looking for until elements it calls tvbparse_find so it can be very slow. + * + * It won't have a subelement, the ending's callbacks won't get called. + */ + +/* + * op_mode values determine how the terminating element and the current offset + * of the parser are handled + */ +tvbparse_wanted_t* tvbparse_until(int id, + const void* private_data, + tvbparse_action_t before_cb, + tvbparse_action_t after_cb, + const tvbparse_wanted_t* ending, + until_mode_t until_mode); + +/* + * one_of + * + * When looked for it will try to match to the given candidates and return a + * composed element whose subelement is the first match. + * + * The list of candidates is terminated with a NULL + * + */ +tvbparse_wanted_t* tvbparse_set_oneof(int id, + const void* private_data, + tvbparse_action_t before_cb, + tvbparse_action_t after_cb, + ...); + +/* + * hashed + */ + +tvbparse_wanted_t* tvbparse_hashed(int id, + const void* data, + tvbparse_action_t before_cb, + tvbparse_action_t after_cb, + tvbparse_wanted_t* key, + tvbparse_wanted_t* other, + ...); + +void tvbparse_hashed_add(tvbparse_wanted_t* w, ...); + +/* + * sequence + * + * When looked for it will try to match in order all the given candidates. If + * every candidate is found in the given order it will return a composed + * element whose subelements are the matcheed elemets. + * + * The list of candidates is terminated with a NULL. + * + */ +tvbparse_wanted_t* tvbparse_set_seq(int id, + const void* private_data, + tvbparse_action_t before_cb, + tvbparse_action_t after_cb, + ...); +/* + * some + * + * When looked for it will try to match the given candidate at least min times + * and at most max times. If the given candidate is matched at least min times + * a composed element is returned. + * + */ +tvbparse_wanted_t* tvbparse_some(int id, + guint min, + guint max, + const void* private_data, + tvbparse_action_t before_cb, + tvbparse_action_t after_cb, + const tvbparse_wanted_t* wanted); + +#define tvbparse_one_or_more(id, private_data, before_cb, after_cb, wanted)\ + tvbparse_some(id, 1, G_MAXINT, private_data, before_cb, after_cb, wanted) + + +/* + * handle + * + * this is a pointer to a pointer to a wanted element (that might have not + * been initialized yet) so that recursive structures + */ +tvbparse_wanted_t* tvbparse_handle(tvbparse_wanted_t** handle); + +#if 0 + +enum ft_cmp_op { + TVBPARSE_CMP_GT, + TVBPARSE_CMP_GE, + TVBPARSE_CMP_EQ, + TVBPARSE_CMP_NE, + TVBPARSE_CMP_LE, + TVBPARSE_CMP_LT +}; + +/* not yet tested */ +tvbparse_wanted_t* tvbparse_ft(int id, + const void* data, + tvbparse_action_t before_cb, + tvbparse_action_t after_cb, + enum ftenum ftenum); + +/* not yet tested */ +tvbparse_wanted_t* tvbparse_end_of_buffer(int id, + const void* data, + tvbparse_action_t before_cb, + tvbparse_action_t after_cb); +/* not yet tested */ +tvbparse_wanted_t* tvbparse_ft_numcmp(int id, + const void* data, + tvbparse_action_t before_cb, + tvbparse_action_t after_cb, + enum ftenum ftenum, + int little_endian, + enum ft_cmp_op ft_cmp_op, + ... ); + +#endif + +/* quoted + * this is a composed candidate, that will try to match a quoted string + * (included the quotes) including into it every escaped quote. + * + * C strings are matched with tvbparse_quoted(-1,NULL,NULL,NULL,"\"","\\") + */ +tvbparse_wanted_t* tvbparse_quoted(int id, + const void* data, + tvbparse_action_t before_cb, + tvbparse_action_t after_cb, + char quote, + char escape); + +/* + * a helper callback for quoted strings that will shrink the token to contain + * only the string andnot the quotes + */ +void tvbparse_shrink_token_cb(void* tvbparse_data, + const void* wanted_data, + tvbparse_elem_t* tok); + + + + +/* initialize the parser (at every packet) +* tvb: what are we parsing? +* offset: from where +* len: for how many bytes +* private_data: will be passed to the action callbacks +* ignore: a wanted token type to be ignored (the associated cb WILL be called when it matches) +*/ +tvbparse_t* tvbparse_init(tvbuff_t* tvb, + int offset, + int len, + void* private_data, + const tvbparse_wanted_t* ignore); + +/* reset the parser */ +gboolean tvbparse_reset(tvbparse_t* tt, int offset, int len); + +guint tvbparse_curr_offset(tvbparse_t* tt); +guint tvbparse_len_left(tvbparse_t* tt); + + + +/* + * This will look for the wanted token at the current offset or after any given + * number of ignored tokens returning FALSE if there's no match or TRUE if there + * is a match. + * The parser will be left in its original state and no callbacks will be called. + */ +gboolean tvbparse_peek(tvbparse_t* tt, + const tvbparse_wanted_t* wanted); + +/* + * This will look for the wanted token at the current offset or after any given + * number of ignored tokens returning NULL if there's no match. + * if there is a match it will set the offset of the current parser after + * the end of the token + */ +tvbparse_elem_t* tvbparse_get(tvbparse_t* tt, + const tvbparse_wanted_t* wanted); + +/* + * Like tvbparse_get but this will look for a wanted token even beyond the + * current offset. + * This function is slow. + */ + +tvbparse_elem_t* tvbparse_find(tvbparse_t* tt, + const tvbparse_wanted_t* wanted); + + +void tvbparse_tree_add_elem(proto_tree* tree, tvbparse_elem_t* curr); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tvbuff.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tvbuff.h new file mode 100644 index 00000000..fc1c28f9 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tvbuff.h @@ -0,0 +1,634 @@ +/* tvbuff.h + * + * Testy, Virtual(-izable) Buffer of guint8*'s + * + * "Testy" -- the buffer gets mad when an attempt is made to access data + * beyond the bounds of the buffer. An exception is thrown. + * + * "Virtual" -- the buffer can have its own data, can use a subset of + * the data of a backing tvbuff, or can be a composite of + * other tvbuffs. + * + * $Id: tvbuff.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Copyright (c) 2000 by Gilbert Ramirez + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __TVBUFF_H__ +#define __TVBUFF_H__ + +#include +#include +#include +#include "exceptions.h" + +#ifdef NEED_G_ASCII_STRCASECMP_H +#include "g_ascii_strcasecmp.h" +#endif + +/** @file + * "testy, virtual(-izable) buffer". They are testy in that they get mad when + * an attempt is made to access data beyond the bounds of their array. In that + * case, they throw an exception. + * + * They are virtualizable in that new tvbuff's can be made from other tvbuffs, + * while only the original tvbuff may have data. That is, the new tvbuff has + * virtual data. + */ + + +/** The different types of tvbuff's */ +typedef enum { + TVBUFF_REAL_DATA, + TVBUFF_SUBSET, + TVBUFF_COMPOSITE +} tvbuff_type; + +typedef struct { + /* The backing tvbuff_t */ + struct tvbuff *tvb; + + /* The offset/length of 'tvb' to which I'm privy */ + guint offset; + guint length; + +} tvb_backing_t; + +typedef struct { + GSList *tvbs; + + /* Used for quick testing to see if this + * is the tvbuff that a COMPOSITE is + * interested in. */ + guint *start_offsets; + guint *end_offsets; + +} tvb_comp_t; + +typedef void (*tvbuff_free_cb_t)(void*); + +typedef struct tvbuff { + /* Record-keeping */ + tvbuff_type type; + gboolean initialized; + guint usage_count; + struct tvbuff *ds_tvb; /* data source top-level tvbuff */ + + /* The tvbuffs in which this tvbuff is a member + * (that is, a backing tvbuff for a TVBUFF_SUBSET + * or a member for a TVB_COMPOSITE) */ + GSList *used_in; + + /* TVBUFF_SUBSET and TVBUFF_COMPOSITE keep track + * of the other tvbuff's they use */ + union { + tvb_backing_t subset; + tvb_comp_t composite; + } tvbuffs; + + /* We're either a TVBUFF_REAL_DATA or a + * TVBUFF_SUBSET that has a backing buffer that + * has real_data != NULL, or a TVBUFF_COMPOSITE + * which has flattened its data due to a call + * to tvb_get_ptr(). + */ + const guint8 *real_data; + + /* Length of virtual buffer (and/or real_data). */ + guint length; + + /* Reported length. */ + guint reported_length; + + /* Offset from beginning of first TVBUFF_REAL. */ + gint raw_offset; + + /* Func to call when actually freed */ + tvbuff_free_cb_t free_cb; +} tvbuff_t; + + + +/** TVBUFF_REAL_DATA contains a guint8* that points to real data. + * The data is allocated and contiguous. + * + * TVBUFF_SUBSET has a backing tvbuff. The TVBUFF_SUBSET is a "window" + * through which the program sees only a portion of the backing tvbuff. + * + * TVBUFF_COMPOSITE combines multiple tvbuffs sequentually to produce + * a larger byte array. + * + * tvbuff's of any type can be used as the backing-tvbuff of a + * TVBUFF_SUBSET or as the member of a TVBUFF_COMPOSITE. + * TVBUFF_COMPOSITEs can have member-tvbuffs of different types. + * + * Once a tvbuff is create/initialized/finalized, the tvbuff is read-only. + * That is, it cannot point to any other data. A new tvbuff must be created if + * you want a tvbuff that points to other data. + */ + + +/** "class" initialization. Called once during execution of program + * so that tvbuff.c can initialize its data. */ +extern void tvbuff_init(void); + +/** "class" cleanup. Called once during execution of program + * so that tvbuff.c can clean up its data. */ +extern void tvbuff_cleanup(void); + + +/** Returns a pointer to a newly initialized tvbuff. Note that + * tvbuff's of types TVBUFF_SUBSET and TVBUFF_COMPOSITE + * require further initialization via the appropriate functions */ +extern tvbuff_t* tvb_new(tvbuff_type); + +/** Marks a tvbuff for freeing. The guint8* data of a TVBUFF_REAL_DATA + * is *never* freed by the tvbuff routines. The tvbuff itself is actually freed + * once its usage count drops to 0. + * + * Usage counts increment for any time the tvbuff is + * used as a member of another tvbuff, i.e., as the backing buffer for + * a TVBUFF_SUBSET or as a member of a TVBUFF_COMPOSITE. + * + * Although you may call tvb_free(), the tvbuff may still be in use + * by other tvbuff's (TVBUFF_SUBSET or TVBUFF_COMPOSITE), so it is not + * safe, unless you know otherwise, to free your guint8* data. If you + * cannot be sure that your TVBUFF_REAL_DATA is not in use by another + * tvbuff, register a callback with tvb_set_free_cb(); when your tvbuff + * is _really_ freed, then your callback will be called, and at that time + * you can free your original data. + * + * The caller can artificially increment/decrement the usage count + * with tvbuff_increment_usage_count()/tvbuff_decrement_usage_count(). + */ +extern void tvb_free(tvbuff_t*); + +/** Free the tvbuff_t and all tvbuff's created from it. */ +extern void tvb_free_chain(tvbuff_t*); + +/** Both return the new usage count, after the increment or decrement */ +extern guint tvb_increment_usage_count(tvbuff_t*, guint count); + +/** If a decrement causes the usage count to drop to 0, a the tvbuff + * is immediately freed. Be sure you know exactly what you're doing + * if you decide to use this function, as another tvbuff could + * still have a pointer to the just-freed tvbuff, causing corrupted data + * or a segfault in the future */ +extern guint tvb_decrement_usage_count(tvbuff_t*, guint count); + +/** Set a callback function to call when a tvbuff is actually freed + * (once the usage count drops to 0). One argument is passed to + * that callback --- a void* that points to the real data. + * Obviously, this only applies to a TVBUFF_REAL_DATA tvbuff. */ +extern void tvb_set_free_cb(tvbuff_t*, tvbuff_free_cb_t); + + +/** Attach a TVBUFF_REAL_DATA tvbuff to a parent tvbuff. This connection + * is used during a tvb_free_chain()... the "child" TVBUFF_REAL_DATA acts + * as if is part of the chain-of-creation of the parent tvbuff, although it + * isn't. This is useful if you need to take the data from some tvbuff, + * run some operation on it, like decryption or decompression, and make a new + * tvbuff from it, yet want the new tvbuff to be part of the chain. The reality + * is that the new tvbuff *is* part of the "chain of creation", but in a way + * that these tvbuff routines is ignorant of. Use this function to make + * the tvbuff routines knowledgable of this fact. */ +extern void tvb_set_child_real_data_tvbuff(tvbuff_t* parent, tvbuff_t* child); + +/**Sets parameters for TVBUFF_REAL_DATA. Can throw ReportedBoundsError. */ +extern void tvb_set_real_data(tvbuff_t*, const guint8* data, guint length, + gint reported_length); + +/** Combination of tvb_new() and tvb_set_real_data(). Can throw ReportedBoundsError. */ +extern tvbuff_t* tvb_new_real_data(const guint8* data, guint length, + gint reported_length); + + +/** Define the subset of the backing buffer to use. + * + * 'backing_offset' can be negative, to indicate bytes from + * the end of the backing buffer. + * + * 'backing_length' can be 0, although the usefulness of the buffer would + * be rather limited. + * + * 'backing_length' of -1 means "to the end of the backing buffer" + * + * Will throw BoundsError if 'backing_offset'/'length' + * is beyond the bounds of the backing tvbuff. + * Can throw ReportedBoundsError. */ +extern void tvb_set_subset(tvbuff_t* tvb, tvbuff_t* backing, + gint backing_offset, gint backing_length, gint reported_length); + +/** Combination of tvb_new() and tvb_set_subset() + * Can throw ReportedBoundsError. */ +extern tvbuff_t* tvb_new_subset(tvbuff_t* backing, + gint backing_offset, gint backing_length, gint reported_length); + + +/** Both tvb_composite_append and tvb_composite_prepend can throw + * BoundsError if member_offset/member_length goes beyond bounds of + * the 'member' tvbuff. */ + +/** Append to the list of tvbuffs that make up this composite tvbuff */ +extern void tvb_composite_append(tvbuff_t* tvb, tvbuff_t* member); + +/** Prepend to the list of tvbuffs that make up this composite tvbuff */ +extern void tvb_composite_prepend(tvbuff_t* tvb, tvbuff_t* member); + +/** Helper function that calls tvb_new(TVBUFF_COMPOSITE). + * Provided only to maintain symmetry with other constructors */ +extern tvbuff_t* tvb_new_composite(void); + +/** Mark a composite tvbuff as initialized. No further appends or prepends + * occur, data access can finally happen after this finalization. */ +extern void tvb_composite_finalize(tvbuff_t* tvb); + + +/* Get total length of buffer */ +extern guint tvb_length(tvbuff_t*); + +/** Computes bytes to end of buffer, from offset (which can be negative, + * to indicate bytes from end of buffer). Function returns -1 to + * indicate that offset is out of bounds. No exception is thrown. */ +extern gint tvb_length_remaining(tvbuff_t*, gint offset); + +/** Same as above, but throws an exception if the offset is out of bounds. */ +extern guint tvb_ensure_length_remaining(tvbuff_t*, gint offset); + +/* Checks (w/o throwing exception) that the bytes referred to by + * 'offset'/'length' actually exist in the buffer */ +extern gboolean tvb_bytes_exist(tvbuff_t*, gint offset, gint length); + +/** Checks that the bytes referred to by 'offset'/'length' actually exist + * in the buffer, and throws an exception if they aren't. */ +extern void tvb_ensure_bytes_exist(tvbuff_t *tvb, gint offset, gint length); + +/* Checks (w/o throwing exception) that offset exists in buffer */ +extern gboolean tvb_offset_exists(tvbuff_t*, gint offset); + +/* Get reported length of buffer */ +extern guint tvb_reported_length(tvbuff_t*); + +/** Computes bytes of reported packet data to end of buffer, from offset + * (which can be negative, to indicate bytes from end of buffer). Function + * returns -1 to indicate that offset is out of bounds. No exception is + * thrown. */ +extern gint tvb_reported_length_remaining(tvbuff_t *tvb, gint offset); + +/** Set the reported length of a tvbuff to a given value; used for protocols + whose headers contain an explicit length and where the calling + dissector's payload may include padding as well as the packet for + this protocol. + + Also adjusts the data length. */ +extern void tvb_set_reported_length(tvbuff_t*, guint); + +extern int offset_from_real_beginning(tvbuff_t *tvb, int counter); + +/* Returns the offset from the first byte of real data. */ +#define TVB_RAW_OFFSET(tvb) \ + ((tvb->raw_offset==-1)?(tvb->raw_offset = offset_from_real_beginning(tvb, 0)):tvb->raw_offset) + +/************** START OF ACCESSORS ****************/ +/* All accessors will throw an exception if appropriate */ + +extern guint8 tvb_get_guint8(tvbuff_t*, gint offset); + +extern guint16 tvb_get_ntohs(tvbuff_t*, gint offset); +extern guint32 tvb_get_ntoh24(tvbuff_t*, gint offset); +extern guint32 tvb_get_ntohl(tvbuff_t*, gint offset); +extern guint64 tvb_get_ntoh64(tvbuff_t*, gint offset); +extern gfloat tvb_get_ntohieee_float(tvbuff_t*, gint offset); +extern gdouble tvb_get_ntohieee_double(tvbuff_t*, gint offset); + +extern guint16 tvb_get_letohs(tvbuff_t*, gint offset); +extern guint32 tvb_get_letoh24(tvbuff_t*, gint offset); +extern guint32 tvb_get_letohl(tvbuff_t*, gint offset); +extern guint64 tvb_get_letoh64(tvbuff_t*, gint offset); +extern gfloat tvb_get_letohieee_float(tvbuff_t*, gint offset); +extern gdouble tvb_get_letohieee_double(tvbuff_t*, gint offset); + +/** + * Fetch an IPv4 address, in network byte order. + * We do *not* convert it to host byte order; we leave it in + * network byte order, as that's what its callers expect. */ +extern guint32 tvb_get_ipv4(tvbuff_t*, gint offset); + +/* Fetch an IPv6 address. */ +extern void tvb_get_ipv6(tvbuff_t*, gint offset, struct e_in6_addr *addr); + +/* Fetch a GUID. */ +extern void tvb_get_ntohguid(tvbuff_t *tvb, gint offset, e_guid_t *guid); +extern void tvb_get_letohguid(tvbuff_t *tvb, gint offset, e_guid_t *guid); +extern void tvb_get_guid(tvbuff_t *tvb, gint offset, e_guid_t *guid, gboolean little_endian); + +/* Fetch a specified number of bits from bit offset in a tvb */ +extern guint8 tvb_get_bits8(tvbuff_t *tvb, gint bit_offset, gint no_of_bits); +extern guint16 tvb_get_bits16(tvbuff_t *tvb, gint bit_offset, gint no_of_bits, gboolean little_endian); +extern guint32 tvb_get_bits32(tvbuff_t *tvb, gint bit_offset, gint no_of_bits, gboolean little_endian); +extern guint64 tvb_get_bits64(tvbuff_t *tvb, gint bit_offset, gint no_of_bits, gboolean little_endian); + +/** Returns target for convenience. Does not suffer from possible + * expense of tvb_get_ptr(), since this routine is smart enough + * to copy data in chunks if the request range actually exists in + * different TVBUFF_REAL_DATA tvbuffs. This function assumes that the + * target memory is already allocated; it does not allocate or free the + * target memory. */ +extern void* tvb_memcpy(tvbuff_t*, void* target, gint offset, gint length); + +/** It is the user's responsibility to g_free() the memory allocated by + * tvb_memdup(). Calls tvb_memcpy() */ +extern void* tvb_memdup(tvbuff_t*, gint offset, gint length); + +/* Same as above but the buffer returned from this function does not have to +* be freed. It will be automatically freed after the packet is dissected. +* Buffers allocated by this function are NOT persistent. +*/ +extern void* ep_tvb_memdup(tvbuff_t *tvb, gint offset, gint length); + +/** WARNING! This function is possibly expensive, temporarily allocating + * another copy of the packet data. Furthermore, it's dangerous because once + * this pointer is given to the user, there's no guarantee that the user will + * honor the 'length' and not overstep the boundaries of the buffer. + * + * The returned pointer is data that is internal to the tvbuff, so do not + * attempt to free it. Don't modify the data, either, because another tvbuff + * that might be using this tvbuff may have already copied that portion of + * the data (sometimes tvbuff's need to make copies of data, but that's the + * internal implementation that you need not worry about). Assume that the + * guint8* points to read-only data that the tvbuff manages. + * + * Return a pointer into our buffer if the data asked for via 'offset'/'length' + * is contiguous (which might not be the case for TVBUFF_COMPOSITE). If the + * data is not contiguous, a tvb_memdup() is called for the entire buffer + * and the pointer to the newly-contiguous data is returned. This dynamically- + * allocated memory will be freed when the tvbuff is freed, after the + * tvbuff_free_cb_t() is called, if any. */ +extern const guint8* tvb_get_ptr(tvbuff_t*, gint offset, gint length); + +/** Find first occurence of any of the needles in tvbuff, starting at offset. + * Searches at most maxlength number of bytes; if maxlength is -1, searches + * to end of tvbuff. + * Returns the offset of the found needle, or -1 if not found. + * Will not throw an exception, even if maxlength exceeds boundary of tvbuff; + * in that case, -1 will be returned if the boundary is reached before + * finding needle. */ +extern gint tvb_find_guint8(tvbuff_t*, gint offset, gint maxlength, + guint8 needle); + +/** Find first occurence of any of the needles in tvbuff, starting at offset. + * Searches at most maxlength number of bytes. Returns the offset of the + * found needle, or -1 if not found. Will not throw an exception, even if + * maxlength exceeds boundary of tvbuff; in that case, -1 will be returned if + * the boundary is reached before finding needle. */ +extern gint tvb_pbrk_guint8(tvbuff_t *, gint offset, gint maxlength, + const guint8 *needles); + +/** Find size of stringz (NUL-terminated string) by looking for terminating + * NUL. The size of the string includes the terminating NUL. + * + * If the NUL isn't found, it throws the appropriate exception. + */ +extern guint tvb_strsize(tvbuff_t *tvb, gint offset); + +/** Find length of string by looking for end of zero terminated string, up to + * 'maxlength' characters'; if 'maxlength' is -1, searches to end + * of tvbuff. + * Returns -1 if 'maxlength' reached before finding EOS. */ +extern gint tvb_strnlen(tvbuff_t*, gint offset, guint maxlength); + +/** Convert a string from Unicode to ASCII. At the moment we fake it by + * assuming all characters are ASCII )-: The len parameter is the number + * of guint16's to convert from Unicode. + * + * tvb_fake_unicode() returns a buffer allocated by g_malloc() and must + * be g_free() by the caller. + * tvb_get_ephemeral_faked_unicode() returns a buffer that does not need + * to be explicitely freed. Instead this buffer is + * automatically freed when wireshark starts dissecting + * the next packet. + */ +extern char *tvb_fake_unicode(tvbuff_t *tvb, int offset, int len, + gboolean little_endian); +extern char *tvb_get_ephemeral_faked_unicode(tvbuff_t *tvb, int offset, int len, + gboolean little_endian); + +/** + * Format the data in the tvb from offset for size ... + */ +extern gchar * tvb_format_text(tvbuff_t *tvb, gint offset, gint size); + +/** + * Like "tvb_format_text()", but for 'wsp'; don't show + * the characters as C-style escapes. + */ +extern gchar * tvb_format_text_wsp(tvbuff_t *tvb, gint offset, gint size); + +/** + * Like "tvb_format_text()", but for null-padded strings; don't show + * the null padding characters as "\000". + */ +extern gchar *tvb_format_stringzpad(tvbuff_t *tvb, gint offset, gint size); + + +/** + * Given a tvbuff, an offset, and a length, allocate a buffer big enough + * to hold a non-null-terminated string of that length at that offset, + * plus a trailing zero, copy the string into it, and return a pointer + * to the string. + * + * Throws an exception if the tvbuff ends before the string does. + * + * tvb_get_string() returns a string allocated by g_malloc() and therefore + * MUST be g_free() by the caller in order not to leak + * memory. + * + * tvb_get_ephemeral_string() returns a string that does not need to be freed, + * instead it will automatically be freed once the next + * packet is dissected. + */ +extern guint8 *tvb_get_string(tvbuff_t *tvb, gint offset, gint length); +extern guint8 *tvb_get_ephemeral_string(tvbuff_t *tvb, gint offset, gint length); + + +/** + * Given a tvbuff and an offset, with the offset assumed to refer to + * a null-terminated string, find the length of that string (and throw + * an exception if the tvbuff ends before we find the null), allocate + * a buffer big enough to hold the string, copy the string into it, + * and return a pointer to the string. Also return the length of the + * string (including the terminating null) through a pointer. + * + * tvb_get_stringz() returns a string allocated by g_malloc() and therefore + * MUST be g_free() by the caller in order not to leak + * memory. + * + * tvb_get_ephemeral_stringz() returns a string that does not need to be freed, + * instead it will automatically be freed once the next + * packet is dissected. + */ +extern guint8 *tvb_get_stringz(tvbuff_t *tvb, gint offset, gint *lengthp); +extern guint8 *tvb_get_ephemeral_stringz(tvbuff_t *tvb, gint offset, gint *lengthp); + +/** Looks for a stringz (NUL-terminated string) in tvbuff and copies + * no more than bufsize number of bytes, including terminating NUL, to buffer. + * Returns length of string (not including terminating NUL), or -1 if the string was + * truncated in the buffer due to not having reached the terminating NUL. + * In this way, it acts like g_snprintf(). + * + * When processing a packet where the remaining number of bytes is less + * than bufsize, an exception is not thrown if the end of the packet + * is reached before the NUL is found. If no NUL is found before reaching + * the end of the short packet, -1 is still returned, and the string + * is truncated with a NUL, albeit not at buffer[bufsize - 1], but + * at the correct spot, terminating the string. + */ +extern gint tvb_get_nstringz(tvbuff_t *tvb, gint offset, guint bufsize, + guint8* buffer); + +/** Like tvb_get_nstringz(), but never returns -1. The string is guaranteed to + * have a terminating NUL. If the string was truncated when copied into buffer, + * a NUL is placed at the end of buffer to terminate it. + * + * bufsize MUST be greater than 0. + */ +extern gint tvb_get_nstringz0(tvbuff_t *tvb, gint offset, guint bufsize, + guint8* buffer); + +/** + * Given a tvbuff, an offset into the tvbuff, and a length that starts + * at that offset (which may be -1 for "all the way to the end of the + * tvbuff"), find the end of the (putative) line that starts at the + * specified offset in the tvbuff, going no further than the specified + * length. + * + * Return the length of the line (not counting the line terminator at + * the end), or, if we don't find a line terminator: + * + * if "deseg" is true, return -1; + * + * if "deseg" is false, return the amount of data remaining in + * the buffer. + * + * Set "*next_offset" to the offset of the character past the line + * terminator, or past the end of the buffer if we don't find a line + * terminator. (It's not set if we return -1.) + */ +extern gint tvb_find_line_end(tvbuff_t *tvb, gint offset, int len, + gint *next_offset, gboolean desegment); + +/** + * Given a tvbuff, an offset into the tvbuff, and a length that starts + * at that offset (which may be -1 for "all the way to the end of the + * tvbuff"), find the end of the (putative) line that starts at the + * specified offset in the tvbuff, going no further than the specified + * length. + * + * However, treat quoted strings inside the buffer specially - don't + * treat newlines in quoted strings as line terminators. + * + * Return the length of the line (not counting the line terminator at + * the end), or the amount of data remaining in the buffer if we don't + * find a line terminator. + * + * Set "*next_offset" to the offset of the character past the line + * terminator, or past the end of the buffer if we don't find a line + * terminator. + */ +extern gint tvb_find_line_end_unquoted(tvbuff_t *tvb, gint offset, int len, + gint *next_offset); + +/** + * Copied from the mgcp dissector. (This function should be moved to /epan ) + * tvb_skip_wsp - Returns the position in tvb of the first non-whitespace + * character following offset or offset + maxlength -1 whichever + * is smaller. + * + * Parameters: + * tvb - The tvbuff in which we are skipping whitespace. + * offset - The offset in tvb from which we begin trying to skip whitespace. + * maxlength - The maximum distance from offset that we may try to skip + * whitespace. + * + * Returns: The position in tvb of the first non-whitespace + * character following offset or offset + maxlength -1 whichever + * is smaller. + */ + +extern gint tvb_skip_wsp(tvbuff_t* tvb, gint offset, gint maxlength); + +extern gint tvb_skip_wsp_return(tvbuff_t* tvb, gint offset); + +/** + * Call strncmp after checking if enough chars left, returning 0 if + * it returns 0 (meaning "equal") and -1 otherwise, otherwise return -1. + */ +extern gint tvb_strneql(tvbuff_t *tvb, gint offset, const gchar *str, + gint size); + +/** + * Call g_ascii_strncasecmp after checking if enough chars left, returning + * 0 if it returns 0 (meaning "equal") and -1 otherwise, otherwise return -1. + */ +extern gint tvb_strncaseeql(tvbuff_t *tvb, gint offset, const gchar *str, + gint size); + +/** + * Call memcmp after checking if enough chars left, returning 0 if + * it returns 0 (meaning "equal") and -1 otherwise, otherwise return -1. + */ +extern gint tvb_memeql(tvbuff_t *tvb, gint offset, const guint8 *str, + gint size); + +/** + * Format a bunch of data from a tvbuff as bytes, returning a pointer + * to the string with the formatted data, with "punct" as a byte + * separator. + */ +extern gchar *tvb_bytes_to_str_punct(tvbuff_t *tvb, gint offset, gint len, + gchar punct); + +/* + * Format a bunch of data from a tvbuff as bytes, returning a pointer + * to the string with the formatted data. + */ +extern gchar *tvb_bytes_to_str(tvbuff_t *tvb, gint offset, gint len); + +#define TVB_GET_DS_TVB(tvb) \ + (tvb->ds_tvb) + +/** Locate a sub-tvbuff within another tvbuff, starting at position + * 'haystack_offset'. Returns the index of the beginning of 'needle' within + * 'haystack', or -1 if 'needle' is not found. The index is relative + * to the start of 'haystack', not 'haystack_offset'. */ +extern gint tvb_find_tvb(tvbuff_t *haystack_tvb, tvbuff_t *needle_tvb, + gint haystack_offset); + +/** + * Uncompresses a zlib compressed packet inside a tvbuff at offset with + * length comprlen. Returns an uncompressed tvbuffer if uncompression + * succeeded or NULL if uncompression failed. + */ +extern tvbuff_t* tvb_uncompress(tvbuff_t *tvb, int offset, int comprlen); + +/************** END OF ACCESSORS ****************/ + +#endif /* __TVBUFF_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat-int.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat-int.h new file mode 100644 index 00000000..e875996b --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat-int.h @@ -0,0 +1,92 @@ +/* + * uat-int.h + * + * $Id: uat-int.h 3992 2008-06-10 03:13:11Z dgu $ + * + * User Accessible Tables + * Mantain an array of user accessible data strucures + * Internal interface + * + * (c) 2007, Luis E. Garcia Ontanon + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2001 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ +#ifndef _UAT_INT_H_ +#define _UAT_INT_H_ + +#include "uat.h" + +typedef struct _uat_fld_rep_t uat_fld_rep_t; +typedef struct _uat_rep_t uat_rep_t; + +typedef void (*uat_rep_fld_free_cb_t)(uat_fld_rep_t*); +typedef void (*uat_rep_free_cb_t)(uat_rep_t*); + +typedef struct _fld_data_t { + guint colnum; + uat_fld_rep_t* rep; + uat_rep_fld_free_cb_t free_rep; +} fld_data_t; + +struct _uat_t { + const char* name; + size_t record_size; + const char* filename; + gboolean from_profile; + const char* help; + const char* category; + void** user_ptr; + guint* nrows_p; + uat_copy_cb_t copy_cb; + uat_update_cb_t update_cb; + uat_free_cb_t free_cb; + + uat_field_t* fields; + guint ncols; + GArray* user_data; + gboolean changed; + uat_rep_t* rep; + uat_rep_free_cb_t free_rep; + gboolean loaded; +}; + +gchar* uat_get_actual_filename(uat_t* uat, gboolean for_writing); + +void uat_init(void); + +void uat_reset(void); + +void* uat_add_record(uat_t*, const void* orig_rec_ptr); + +void uat_swap(uat_t*, guint idx_a, guint idx_b); + +void uat_remove_record_idx(uat_t*, guint rec_idx); + +void uat_destroy(uat_t*); + +void uat_clear(uat_t*); + +gboolean uat_save(uat_t* , char** ); + +void uat_load_all(void); + +#define UAT_UPDATE(uat) do { *((uat)->user_ptr) = (void*)((uat)->user_data->data); *((uat)->nrows_p) = (uat)->user_data->len; } while(0) +#define UAT_INDEX_PTR(uat,idx) (uat->user_data->data + (uat->record_size * (idx))) +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat.h new file mode 100644 index 00000000..d6952dae --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat.h @@ -0,0 +1,486 @@ +/* + * uat.h + * + * $Id: uat.h 3992 2008-06-10 03:13:11Z dgu $ + * + * User Accessible Tables + * Mantain an array of user accessible data strucures + * + * (c) 2007, Luis E. Garcia Ontanon + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2001 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _UAT_H_ +#define _UAT_H_ + +/* + * uat mantains a dynamically allocated table accessible to the user + * via a file and/or gui tables. + * + * the file is located either in userdir(when first read or when writen) or + * in datadir for defaults (read only , it will be always written to userdir). + * + * the behaviour of the table is controlled by a series of callbacks + * the caller must provide. + * + * BEWARE that the user can change an uat at (almost) any time, + * That is pointers to records in an uat are valid only during the call + * to the function that obtains them (do not store them). + * + * UATs are meant for short tables of user data (passwords and such) there's + * no quick access, you must iterate through them each time to fetch the record + * you are looking for. Use uat_dup() or uat_se_dup() if necessary. + * + * Only users via gui or editing the file can add/remove records your code cannot. + */ + +/* obscure data type to handle an uat */ +typedef struct _uat_t uat_t; +/******************************************** + * Callbacks: + * these instruct uat on how to deal with user info and data in records + ********************************************/ + +/******** + * Callbacks for the entire table (these deal with entire records) + ********/ + +/* + * Copy CB + * used to copy a record + * optional, memcpy will be used if not given + * copy(dest,orig,len) + */ +typedef void* (*uat_copy_cb_t)(void*, const void*, unsigned); + +/* + * + * Free CB + * + * destroy a record's child data + * (do not free the container, it will be handled by uat) + * it is optional, no child data will be freed if no present + * free(record) + */ +typedef void (*uat_free_cb_t)(void*); + +/* + * Update CB + * + * to be called after all record fields has been updated + * optional, record will be updated always if not given + * update(record,&error) + */ +typedef void (*uat_update_cb_t)(void* , const char** ); + + +/******* + * Callbacks for single fields (these deal with single values) + * the caller should provide one of these for every field! + ********/ + +/* + * given an input string (ptr, len) checks if the value is OK for a field in the record. + * it will return TRUE if OK or else + * it will return FALSE and may set *error to inform the user on what's + * wrong with the given input + * optional, if not given any input is considered OK and the set cb will be called + * chk(record, ptr, len, chk_data, fld_data, &error) + */ +typedef gboolean (*uat_fld_chk_cb_t)(void*, const char*, unsigned, void*, void*, const char**); + +/* + * Set Field CB + * + * given an input string (ptr, len) sets the value of a field in the record, + * it will return TRUE if OK or else + * it will return FALSE and may set *error to inform the user on what's + * wrong with the given input + * it is mandatory + * set(record, ptr, len, set_data, fld_data) + */ +typedef void (*uat_fld_set_cb_t)(void*, const char*, unsigned, void*, void*); + +/* + * given a record returns a string representation of the field + * mandatory + * tostr(record, &out_ptr, &out_len, tostr_data, fld_data) + */ +typedef void (*uat_fld_tostr_cb_t)(void*, const char**, unsigned*, void*, void*); + +/*********** + * Text Mode + * + * used for file and dialog representation of fileds in columns, + * when the file is read it modifies the way the value is passed back to the fld_set_cb + * (see definition bellow for description) + ***********/ + +typedef enum _uat_text_mode_t { + PT_TXTMOD_NONE, + /* not used */ + + PT_TXTMOD_STRING, + /* + file: + reads: + ,"\x20\x00\x30", as " \00",3 + ,"", as "",0 + ,, as NULL,0 + writes: + ,"\x20\x30\x00\x20", for " 0\0 ",4 + ,"", for *, 0 + ,, for NULL, * + dialog: + accepts \x?? and other escapes + gets "",0 on empty string + */ + PT_TXTMOD_HEXBYTES, + /* + file: + reads: + ,A1b2C3d4, as "\001\002\003\004",4 + ,, as NULL,0 + writes: + ,, on NULL, * + ,a1b2c3d4, on "\001\002\003\004",4 + dialog: + "a1b2c3d4" as "\001\002\003\004",4 + "a1 b2:c3d4" as "\001\002\003\004",4 + "" as NULL,0 + "invalid" as NULL,3 + "a1b" as NULL, 1 + */ + PT_TXTMOD_ENUM +} uat_text_mode_t; + +/* + * Fields + * + * + */ +typedef struct _uat_field_t { + const char* name; + uat_text_mode_t mode; + + struct { + uat_fld_chk_cb_t chk; + uat_fld_set_cb_t set; + uat_fld_tostr_cb_t tostr; + } cb; + + struct { + void* chk; + void* set; + void* tostr; + } cbdata; + + void* fld_data; + + const char* desc; + struct _fld_data_t* priv; +} uat_field_t; + +#define FLDFILL NULL +#define UAT_END_FIELDS {0,PT_TXTMOD_NONE,{0,0,0},{0,0,0},0,0,FLDFILL} + + +#define UAT_CAT_GENERAL "General" +#define UAT_CAT_PORTS "Port Assignments" +#define UAT_CAT_CRYPTO "Decryption" +#define UAT_CAT_FFMT "File Formats" + +/** Create a new uat + * + * @param name The name of the table + * @param data_ptr A pointer to a null terminated array of pointers to the data + * @param default_data A pointer to a struct containing default values + * @param size The size of the structure + * @param filename The filename to be used (either in userdir or datadir) + * @param copy_cb A function that copies the data in the struct + * @param update_cb Will be called when a record is updated + * @param free_cb Will be called to destroy a struct in the dataset + * + * @return A freshly-allocated and populated uat_t struct. + */ +uat_t* uat_new(const char* name, + size_t size, + const char* filename, + gboolean from_profile, + void** data_ptr, + guint* num_items, + const char* category, + const char* help, + uat_copy_cb_t copy_cb, + uat_update_cb_t update_cb, + uat_free_cb_t free_cb, + uat_field_t* flds_array); + +/** Populate a uat using its file. + * + * @param uat_in Pointer to a uat. Must not be NULL. + * @param err Upon failure, points to an error string. + * + * @return TRUE on success, FALSE on failure. + */ +gboolean uat_load(uat_t* uat_in, char** err); + +/** Create or update a single uat entry using a string. + * + * @param uat_in Pointer to a uat. Must not be NULL. + * @param entry The string representation of the entry. Format must match + * what's written to the uat's output file. + * @param err Upon failure, points to an error string. + * + * @return TRUE on success, FALSE on failure. + */ +gboolean uat_load_str(uat_t* uat_in, char* entry, char** err); + +/** Given a uat name or filename, find its pointer. + * + * @param name The name or filename of the uat + * + * @return A pointer to the uat on success, NULL on failure. + */ +uat_t *uat_find(gchar *name); + +/* + * uat_dup() + * uat_se_dup() + * make a reliable copy of an uat for internal use, + * so that pointers to records can be kept through calls. + * return NULL on zero len. + */ +void* uat_dup(uat_t*, guint* len_p); /* to be freed */ +void* uat_se_dup(uat_t*, guint* len_p); +uat_t* uat_get_table_by_name(const char* name); + +/* + * Some common uat_fld_chk_cbs + */ +gboolean uat_fld_chk_str(void*, const char*, unsigned, void*,void*, const char** err); +gboolean uat_fld_chk_proto(void*, const char*, unsigned, void*,void*, const char** err); +gboolean uat_fld_chk_num_dec(void*, const char*, unsigned, void*, void*, const char** err); +gboolean uat_fld_chk_num_hex(void*, const char*, unsigned, void*, void*, const char** err); +gboolean uat_fld_chk_enum(void*, const char*, unsigned, void*, void*, const char**); +gboolean uat_fld_chk_range(void*, const char*, unsigned, void*, void*, const char**); + +#define CHK_STR_IS_DECL(what) \ +gboolean uat_fld_chk_str_ ## what (void*, const char*, unsigned, void*, void*, const char**) + +typedef void (*uat_cb_t)(void* uat,void* user_data); +void uat_foreach_table(uat_cb_t cb,void* user_data); +void uat_unload_all(void); + +char* uat_undquote(const char* si, guint in_len, guint* len_p); +char* uat_unbinstring(const char* si, guint in_len, guint* len_p); +char* uat_unesc(const char* si, guint in_len, guint* len_p); +char* uat_esc(const char* buf, guint len); + +/* Some strings entirely made of ... already declared */ +CHK_STR_IS_DECL(isprint); +CHK_STR_IS_DECL(isalpha); +CHK_STR_IS_DECL(isalnum); +CHK_STR_IS_DECL(isdigit); +CHK_STR_IS_DECL(isxdigit); + +#define CHK_STR_IS_DEF(what) \ +gboolean uat_fld_chk_str_ ## what (void* u1 _U_, const char* strptr, unsigned len, void* u2 _U_, void* u3 _U_, const char** err) { \ + guint i; for (i=0;i(field_name)) + */ +#define UAT_CSTRING_CB_DEF(basename,field_name,rec_t) \ +static void basename ## _ ## field_name ## _set_cb(void* rec, const char* buf, unsigned len, void* u1 _U_, void* u2 _U_) {\ + if ((((rec_t*)rec)->field_name)) g_free((((rec_t*)rec)->field_name)); \ + (((rec_t*)rec)->field_name) = g_strndup(buf,len); } \ +static void basename ## _ ## field_name ## _tostr_cb(void* rec, const char** out_ptr, unsigned* out_len, void* u1 _U_, void* u2 _U_) {\ + if (((rec_t*)rec)->field_name ) { \ + *out_ptr = (((rec_t*)rec)->field_name); *out_len = strlen((((rec_t*)rec)->field_name)); \ + } else { \ + *out_ptr = ""; *out_len = 0; } } + +#define UAT_FLD_CSTRING(basename,field_name,desc) \ + {#field_name, PT_TXTMOD_STRING,{uat_fld_chk_str,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{0,0,0},0,desc,FLDFILL} + +#define UAT_FLD_CSTRING_ISPRINT(basename,field_name,desc) \ + {#field_name, PT_TXTMOD_STRING,{uat_fld_chk_str_isprint,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{0,0,0},0,desc,FLDFILL} + +#define UAT_FLD_CSTRING_OTHER(basename,field_name,chk,desc) \ + {#field_name, PT_TXTMOD_STRING,{ chk ,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{0,0,0},0,desc,FLDFILL} + +/* + * LSTRING MACROS + */ +#define UAT_LSTRING_CB_DEF(basename,field_name,rec_t,ptr_element,len_element) \ +static void basename ## _ ## field_name ## _set_cb(void* rec, const char* buf, unsigned len, void* u1 _U_, void* u2 _U_) {\ + if ((((rec_t*)rec)->ptr_element)) g_free((((rec_t*)rec)->ptr_element)); \ + (((rec_t*)rec)->ptr_element) = uat_unesc(buf,len,&(((rec_t*)rec)->len_element)); }\ +static void basename ## _ ## field_name ## _tostr_cb(void* rec, const char** out_ptr, unsigned* out_len, void* u1 _U_, void* u2 _U_) {\ + if (((rec_t*)rec)->ptr_element ) { \ + *out_ptr = uat_esc(((rec_t*)rec)->ptr_element, (((rec_t*)rec)->len_element)); \ + *out_len = strlen(*out_ptr); \ + } else { \ + *out_ptr = ""; *out_len = 0; } } + +#define UAT_FLD_LSTRING(basename,field_name,desc) \ +{#field_name, PT_TXTMOD_STRING,{0,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{0,0,0},0,desc,FLDFILL} + + +/* + * BUFFER macros, + * a buffer_ptr contained in (((rec_t*)rec)->(field_name)) + * and its len in (((rec_t*)rec)->(len_name)) + * XXX: UNTESTED + */ +#define UAT_BUFFER_CB_DEF(basename,field_name,rec_t,ptr_element,len_element) \ +static void basename ## _ ## field_name ## _set_cb(void* rec, const char* buf, unsigned len, void* u1 _U_, void* u2 _U_) {\ + if ((((rec_t*)rec)->ptr_element) ) g_free((((rec_t*)rec)->ptr_element)); \ + (((rec_t*)rec)->ptr_element) = len ? g_memdup(buf,len) : NULL; \ + (((rec_t*)rec)->len_element) = len; } \ +static void basename ## _ ## field_name ## _tostr_cb(void* rec, const char** out_ptr, unsigned* out_len, void* u1 _U_, void* u2 _U_) {\ + *out_ptr = ((rec_t*)rec)->ptr_element ? ep_memdup(((rec_t*)rec)->ptr_element,((rec_t*)rec)->len_element) : ""; \ + *out_len = ((rec_t*)rec)->len_element; } + +#define UAT_FLD_BUFFER(basename,field_name,desc) \ + {#field_name, PT_TXTMOD_HEXBYTES,{0,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{0,0,0},0,desc,FLDFILL} + + +/* + * DEC Macros, + * a decimal number contained in + */ +#define UAT_DEC_CB_DEF(basename,field_name,rec_t) \ +static void basename ## _ ## field_name ## _set_cb(void* rec, const char* buf, unsigned len, void* u1 _U_, void* u2 _U_) {\ + ((rec_t*)rec)->field_name = strtol(ep_strndup(buf,len),NULL,10); } \ +static void basename ## _ ## field_name ## _tostr_cb(void* rec, const char** out_ptr, unsigned* out_len, void* u1 _U_, void* u2 _U_) {\ + *out_ptr = ep_strdup_printf("%d",((rec_t*)rec)->field_name); \ + *out_len = strlen(*out_ptr); } + +#define UAT_FLD_DEC(basename,field_name,desc) \ + {#field_name, PT_TXTMOD_STRING,{uat_fld_chk_num_dec,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{0,0,0},0,desc,FLDFILL} + + +/* + * HEX Macros, + * an hexadecimal number contained in + */ +#define UAT_HEX_CB_DEF(basename,field_name,rec_t) \ +static void basename ## _ ## field_name ## _set_cb(void* rec, const char* buf, unsigned len, void* u1 _U_, void* u2 _U_) {\ + ((rec_t*)rec)->field_name = strtol(ep_strndup(buf,len),NULL,16); } \ +static void basename ## _ ## field_name ## _tostr_cb(void* rec, const char** out_ptr, unsigned* out_len, void* u1 _U_, void* u2 _U_) {\ + *out_ptr = ep_strdup_printf("%x",((rec_t*)rec)->field_name); \ + *out_len = strlen(*out_ptr); } + +#define UAT_FLD_HEX(basename,field_name,desc) \ +{#field_name, PT_TXTMOD_STRING,{uat_fld_chk_num_hex,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{0,0,0},0,desc,FLDFILL} + + +/* + * ENUM macros + * enum_t: name = ((enum_t*)ptr)->strptr + * value = ((enum_t*)ptr)->value + * rec_t: + * value + */ +#define UAT_VS_DEF(basename,field_name,rec_t,default_val,default_str) \ +static void basename ## _ ## field_name ## _set_cb(void* rec, const char* buf, unsigned len, void* vs, void* u2 _U_) {\ + guint i; \ + char* str = ep_strndup(buf,len); \ + const char* cstr; ((rec_t*)rec)->field_name = default_val; \ + for(i=0; ( cstr = ((value_string*)vs)[i].strptr ) ;i++) { \ + if (g_str_equal(cstr,str)) { \ + ((rec_t*)rec)->field_name = ((value_string*)vs)[i].value; return; } } } \ +static void basename ## _ ## field_name ## _tostr_cb(void* rec, const char** out_ptr, unsigned* out_len, void* vs, void* u2 _U_) {\ + guint i; \ + *out_ptr = ep_strdup(default_str); *out_len = strlen(default_str);\ + for(i=0;((value_string*)vs)[i].strptr;i++) { \ + if ( ((value_string*)vs)[i].value == ((rec_t*)rec)->field_name ) { \ + *out_ptr = ep_strdup(((value_string*)vs)[i].strptr); \ + *out_len = strlen(*out_ptr); return; } } } + + +#define UAT_FLD_VS(basename,field_name,enum,desc) \ + {#field_name, PT_TXTMOD_ENUM,{uat_fld_chk_enum,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{&(enum),&(enum),&(enum)},&(enum),desc,FLDFILL} + + +/* + * PROTO macros + */ + +#define UAT_PROTO_DEF(basename, field_name, dissector_field, name_field, rec_t) \ +static void basename ## _ ## field_name ## _set_cb(void* rec, const char* buf, unsigned len, void* u1 _U_, void* u2 _U_) {\ + if (len) { \ + ((rec_t*)rec)->name_field = ep_strndup(buf,len); g_strdown(((rec_t*)rec)->name_field ); g_strchug(((rec_t*)rec)->name_field); \ + ((rec_t*)rec)->dissector_field = find_dissector(((rec_t*)rec)->name_field); \ + } else { \ + ((rec_t*)rec)->dissector_field = find_dissector("data"); \ + ((rec_t*)rec)->name_field = NULL; \ + } } \ +static void basename ## _ ## field_name ## _tostr_cb(void* rec, const char** out_ptr, unsigned* out_len, void* u1 _U_, void* u2 _U_) {\ + if ( ((rec_t*)rec)->name_field ) { \ + *out_ptr = (((rec_t*)rec)->name_field); \ + *out_len = strlen(*out_ptr); \ + } else { \ + *out_ptr = ""; *out_len = 0; } } + + +#define UAT_FLD_PROTO(basename,field_name,desc) \ + {#field_name, PT_TXTMOD_STRING,{uat_fld_chk_proto,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{0,0,0},0,desc,FLDFILL} + +/* + * RANGE macros + */ + +#define UAT_RANGE_CB_DEF(basename,field_name,rec_t) \ +static void basename ## _ ## field_name ## _set_cb(void* rec, const char* buf, unsigned len, void* u1 _U_, void* u2) {\ + char* rng = ep_strndup(buf,len);\ + range_convert_str(&(((rec_t*)rec)->field_name), rng,GPOINTER_TO_UINT(u2)); \ + } \ +static void basename ## _ ## field_name ## _tostr_cb(void* rec, const char** out_ptr, unsigned* out_len, void* u1 _U_, void* u2 _U_) {\ + if ( ((rec_t*)rec)->field_name ) { \ + *out_ptr = range_convert_range(((rec_t*)rec)->field_name); *out_len = strlen(*out_ptr); \ + } else { \ + *out_ptr = ""; *out_len = 0; } } + + +#define UAT_FLD_RANGE(basename,field_name,max,desc) \ + {#field_name, PT_TXTMOD_STRING,{uat_fld_chk_range,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},\ + {GUINT_TO_POINTER(max),GUINT_TO_POINTER(max),GUINT_TO_POINTER(max)},0,desc,FLDFILL} + + + + + +#endif + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat_load_lex.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat_load_lex.h new file mode 100644 index 00000000..a8d694b1 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat_load_lex.h @@ -0,0 +1,6 @@ +/* This is generated by runlex.sh. Do not edit it. */ +#define yylex uat_load_lex +#ifndef YY_DECL +#define YY_DECL int yylex(void) +#endif +YY_DECL; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/unicode-utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/unicode-utils.h new file mode 100644 index 00000000..b3962ae6 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/unicode-utils.h @@ -0,0 +1,54 @@ +/* unicode-utils.h + * Unicode utility definitions + * + * $Id: unicode-utils.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2006 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __UNICODEUTIL_H__ +#define __UNICODEUTIL_H__ + +#ifdef _WIN32 + +/** + * @file Unicode convenience routines. + */ + +/** Given a UTF-8 string, convert it to UTF-16. This is meant to be used + * to convert between GTK+ 2.x (UTF-8) to Windows (UTF-16). + * + * @param utf8str The string to convert. May be NULL. + * @return The string converted to UTF-16. If utf8str is NULL, returns + * NULL. The return value should NOT be freed by the caller. + */ +wchar_t * utf_8to16(const char *utf8str); + +/** Given a UTF-16 string, convert it to UTF-8. This is meant to be used + * to convert between GTK+ 2.x (UTF-8) to Windows (UTF-16). + * + * @param utf16str The string to convert. May be NULL. + * @return The string converted to UTF-8. If utf16str is NULL, returns + * NULL. The return value should NOT be freed by the caller. + */ +gchar * utf_16to8(const wchar_t *utf16str); + +#endif /* _WIN32 */ + +#endif /* __UNICODEUTIL_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/value_string.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/value_string.h new file mode 100644 index 00000000..86a2f1e6 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/value_string.h @@ -0,0 +1,88 @@ +/* value_string.h + * Definitions for value_string structures and routines + * + * $Id: value_string.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __VALUE_STRING_H__ +#define __VALUE_STRING_H__ + +#include + +/* Struct for the val_to_str, match_strval_idx, and match_strval functions */ + +typedef struct _value_string { + guint32 value; + const gchar *strptr; +} value_string; + +/* Struct for the rval_to_str, match_strrval_idx, and match_strrval functions */ +typedef struct _range_string { + guint32 value_min; + guint32 value_max; + const gchar *strptr; +} range_string; + +/* #define VS_DEF(x) { x, #x } */ +/* #define VS_END { 0, NULL } */ + +/* Tries to match val against each element in the value_string array vs. + Returns the associated string ptr, and sets "*idx" to the index in + that table, on a match, and returns NULL, and sets "*idx" to -1, + on failure. */ +extern const gchar* match_strval_idx(guint32 val, const value_string *vs, gint *idx); + +/* Like match_strval_idx(), but doesn't return the index. */ +extern const gchar* match_strval(guint32 val, const value_string *vs); + +/* Tries to match val against each element in the value_string array vs. + Returns the associated string ptr on a match. + Formats val with fmt, and returns the resulting string, on failure. */ +extern const gchar* val_to_str(guint32 val, const value_string *vs, const char *fmt); + +/* Generate a string describing an enumerated bitfield (an N-bit field + with various specific values having particular names). */ +extern const char *decode_enumerated_bitfield(guint32 val, guint32 mask, + int width, const value_string *tab, const char *fmt); + +/* Generate a string describing an enumerated bitfield (an N-bit field + with various specific values having particular names). */ +extern const char *decode_enumerated_bitfield_shifted(guint32 val, guint32 mask, + int width, const value_string *tab, const char *fmt); + + +/* ranges aware versions */ + +/* Tries to match val against each range in the range_string array rs. + Returns the associated string ptr on a match. + Formats val with fmt, and returns the resulting string, on failure. */ +extern const gchar* rval_to_str(guint32 val, const range_string *rs, const char *fmt); + +/* Tries to match val against each range in the range_string array rs. + Returns the associated string ptr, and sets "*idx" to the index in + that table, on a match, and returns NULL, and sets "*idx" to -1, + on failure. */ +extern const gchar *match_strrval_idx(guint32 val, const range_string *rs, gint *idx); + +/* Like match_strrval_idx(), but doesn't return the index. */ +extern const gchar *match_strrval(guint32 val, const range_string *rs); + +#endif /* __VALUE_STRING_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ws_strsplit.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ws_strsplit.h new file mode 100644 index 00000000..b2108c79 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ws_strsplit.h @@ -0,0 +1,41 @@ +/* ws_strsplit.h + * String Split utility function + * Code borrowed from GTK2 to override the GTK1 version of g_strsplit, which is + * known to be buggy. + * + * $Id: ws_strsplit.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __WS_STRSPLIT_H__ +#define __WS_STRSPLIT_H__ + +#if GLIB_MAJOR_VERSION < 2 + +#define g_strsplit(s, d, t) ws_strsplit(s, d, t) + +gchar ** ws_strsplit (const gchar *string, + const gchar *delimiter, + gint max_tokens); + +#endif /* GLIB_MAJOR_VERSION */ + +#endif /* __WS_STRSPLIT_H__ */ + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/wslua/declare_wslua.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/wslua/declare_wslua.h new file mode 100644 index 00000000..d403ce65 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/wslua/declare_wslua.h @@ -0,0 +1,59 @@ +/* This file is automatically genrated by make-reg.pl do not edit */ + +#define WSLUA_DECLARE_CLASSES() \ + WSLUA_CLASS_DECLARE(ByteArray);\ + WSLUA_CLASS_DECLARE(Tvb);\ + WSLUA_CLASS_DECLARE(TvbRange);\ + WSLUA_CLASS_DECLARE(Pref);\ + WSLUA_CLASS_DECLARE(Prefs);\ + WSLUA_CLASS_DECLARE(ProtoField);\ + WSLUA_CLASS_DECLARE(Proto);\ + WSLUA_CLASS_DECLARE(Dissector);\ + WSLUA_CLASS_DECLARE(DissectorTable);\ + WSLUA_CLASS_DECLARE(TreeItem);\ + WSLUA_CLASS_DECLARE(Address);\ + WSLUA_CLASS_DECLARE(Column);\ + WSLUA_CLASS_DECLARE(Columns);\ + WSLUA_CLASS_DECLARE(Pinfo);\ + WSLUA_CLASS_DECLARE(Listener);\ + WSLUA_CLASS_DECLARE(TextWindow);\ + WSLUA_CLASS_DECLARE(Dir);\ + WSLUA_CLASS_DECLARE(FieldInfo);\ + WSLUA_CLASS_DECLARE(Field);\ + WSLUA_CLASS_DECLARE(PseudoHeader);\ + WSLUA_CLASS_DECLARE(Dumper);\ + + +#define WSLUA_DECLARE_FUNCTIONS() \ + WSLUA_FUNCTION wslua_register_postdissector(lua_State* L);\ + WSLUA_FUNCTION wslua_gui_enabled(lua_State* L);\ + WSLUA_FUNCTION wslua_register_menu(lua_State* L);\ + WSLUA_FUNCTION wslua_new_dialog(lua_State* L);\ + WSLUA_FUNCTION wslua_retap_packets(lua_State* L);\ + WSLUA_FUNCTION wslua_copy_to_clipboard(lua_State* L);\ + WSLUA_FUNCTION wslua_open_capture_file(lua_State* L);\ + WSLUA_FUNCTION wslua_set_filter(lua_State* L);\ + WSLUA_FUNCTION wslua_apply_filter(lua_State* L);\ + WSLUA_FUNCTION wslua_reload(lua_State* L);\ + WSLUA_FUNCTION wslua_browser_open_url(lua_State* L);\ + WSLUA_FUNCTION wslua_browser_open_data_file(lua_State* L);\ + WSLUA_FUNCTION wslua_format_date(lua_State* L);\ + WSLUA_FUNCTION wslua_format_time(lua_State* L);\ + WSLUA_FUNCTION wslua_report_failure(lua_State* L);\ + WSLUA_FUNCTION wslua_critical(lua_State* L);\ + WSLUA_FUNCTION wslua_warn(lua_State* L);\ + WSLUA_FUNCTION wslua_message(lua_State* L);\ + WSLUA_FUNCTION wslua_info(lua_State* L);\ + WSLUA_FUNCTION wslua_debug(lua_State* L);\ + WSLUA_FUNCTION wslua_loadfile(lua_State* L);\ + WSLUA_FUNCTION wslua_dofile(lua_State* L);\ + WSLUA_FUNCTION wslua_persconffile_path(lua_State* L);\ + WSLUA_FUNCTION wslua_datafile_path(lua_State* L);\ + WSLUA_FUNCTION wslua_register_stat_cmd_arg(lua_State* L);\ + WSLUA_FUNCTION wslua_all_field_infos(lua_State* L);\ + + +extern void wslua_register_classes(lua_State* L); +extern void wslua_register_functions(lua_State* L); + + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/wslua/wslua.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/wslua/wslua.h new file mode 100644 index 00000000..a58fba23 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/wslua/wslua.h @@ -0,0 +1,372 @@ +/* + * wslua.h + * + * Wireshark's interface to the Lua Programming Language + * + * (c) 2006, Luis E. Garcia Ontanon + * (c) 2007, Tamas Regos + * + * $Id: wslua.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _PACKET_LUA_H +#define _PACKET_LUA_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if GLIB_MAJOR_VERSION < 2 +#include +#endif + +#include "declare_wslua.h" + +#define WSLUA_INIT_ROUTINES "init_routines" +#define LOG_DOMAIN_LUA "wslua" + +struct _wslua_tvbrange { + tvbuff_t* tvb; + int offset; + int len; +}; + +typedef struct _wslua_field_t { + int hfid; + int ett; + char* name; + char* abbr; + char* blob; + enum ftenum type; + base_display_e base; + value_string* vs; + guint32 mask; +} wslua_field_t; + +/* + * PREF_OBSOLETE is used for preferences that a module used to support + * but no longer supports; we give different error messages for them. + */ +typedef enum { + PREF_UINT, + PREF_BOOL, + PREF_ENUM, + PREF_STRING, + PREF_RANGE, + PREF_STATIC_TEXT, + PREF_OBSOLETE +} pref_type_t; + +typedef struct _wslua_pref_t { + gchar* name; + gchar* label; + gchar* desc; + pref_type_t type; + union { + gboolean b; + guint u; + const gchar* s; + gint e; + range_t *r; + void* p; + } value; + union { + guint32 max_value; /* maximum value of a range */ + struct { + const enum_val_t *enumvals; /* list of name & values */ + gboolean radio_buttons; /* TRUE if it should be shown as + radio buttons rather than as an + option menu or combo box in + the preferences tab */ + } enum_info; /* for PREF_ENUM */ + } info; /* display/text file information */ + + struct _wslua_pref_t* next; + struct _wslua_proto_t* proto; +} wslua_pref_t; + +typedef struct _wslua_proto_t { + gchar* name; + gchar* desc; + int hfid; + int ett; + wslua_pref_t prefs; + int fields; + module_t *prefs_module; + dissector_handle_t handle; + gboolean is_postdissector; +} wslua_proto_t; + +struct _wslua_distbl_t { + dissector_table_t table; + gchar* name; +}; + +struct _wslua_col_info { + column_info* cinfo; + gint col; +}; + +struct _wslua_treeitem { + proto_item* item; + proto_tree* tree; +}; + +typedef void (*tap_extractor_t)(lua_State*,const void*); + +struct _wslua_tap { + gchar* name; + gchar* filter; + tap_extractor_t extractor; + lua_State* L; + int packet_ref; + int draw_ref; + int init_ref; +}; + +#if GLIB_MAJOR_VERSION < 2 +# define DIRECTORY_T DIR +# define FILE_T struct dirent +# define OPENDIR_OP(name) opendir(name) +# define DIRGETNEXT_OP(dir) readdir(dir) +# define GETFNAME_OP(file) (gchar *)file->d_name +# define CLOSEDIR_OP(dir) closedir(dir) +#else /* GLIB 2 */ +# define DIRECTORY_T GDir +# define FILE_T gchar +# define OPENDIR_OP(name) g_dir_open(name, 0, dir->dummy) +# define DIRGETNEXT_OP(dir) g_dir_read_name(dir) +# define GETFNAME_OP(file) (file); +# define CLOSEDIR_OP(dir) g_dir_close(dir) +#endif + +struct _wslua_dir { + DIRECTORY_T* dir; + char* ext; +#if GLIB_MAJOR_VERSION >= 2 + GError** dummy; +#endif + +}; + +typedef struct { const char* name; tap_extractor_t extractor; } tappable_t; + +typedef struct {const gchar* str; enum ftenum id; } wslua_ft_types_t; + +typedef wslua_pref_t* Pref; +typedef wslua_pref_t* Prefs; +typedef struct _wslua_field_t* ProtoField; +typedef struct _wslua_proto_t* Proto; +typedef struct _wslua_distbl_t* DissectorTable; +typedef dissector_handle_t Dissector; +typedef GByteArray* ByteArray; +typedef tvbuff_t* Tvb; +typedef struct _wslua_tvbrange* TvbRange; +typedef struct _wslua_col_info* Column; +typedef column_info* Columns; +typedef packet_info* Pinfo; +typedef struct _wslua_treeitem* TreeItem; +typedef address* Address; +typedef header_field_info** Field; +typedef field_info* FieldInfo; +typedef struct _wslua_tap* Listener; +typedef funnel_text_window_t* TextWindow; +typedef wtap_dumper* Dumper; +typedef struct lua_pseudo_header* PseudoHeader; +typedef tvbparse_t* Parser; +typedef tvbparse_wanted_t* Rule; +typedef tvbparse_elem_t* Node; +typedef tvbparse_action_t* Shortcut; +typedef struct _wslua_main* WireShark; +typedef struct _wslua_dir* Dir; + +/* + * toXxx(L,idx) gets a Xxx from an index (Lua Error if fails) + * checkXxx(L,idx) gets a Xxx from an index after calling check_code (No Lua Error if it fails) + * pushXxx(L,xxx) pushes an Xxx into the stack + * isXxx(L,idx) tests whether we have an Xxx at idx + * + * LUA_CLASS_DEFINE must be used without trailing ';' + */ +#define WSLUA_CLASS_DEFINE(C,check_code,push_code) \ +C to##C(lua_State* L, int index) { \ + C* v = (C*)lua_touserdata (L, index); \ + if (!v) luaL_typerror(L,index,#C); \ + return *v; \ +} \ +C check##C(lua_State* L, int index) { \ + C* p; \ + luaL_checktype(L,index,LUA_TUSERDATA); \ + p = (C*)luaL_checkudata(L, index, #C); \ + check_code; \ + return p ? *p : NULL; \ +} \ +C* push##C(lua_State* L, C v) { \ + C* p = lua_newuserdata(L,sizeof(C)); *p = v; \ + luaL_getmetatable(L, #C); lua_setmetatable(L, -2); \ + push_code; \ + return p; \ +}\ +gboolean is##C(lua_State* L,int i) { \ + void *p; \ + if(!lua_isuserdata(L,i)) return FALSE; \ + p = lua_touserdata(L, i); \ + lua_getfield(L, LUA_REGISTRYINDEX, #C); \ + if (p == NULL || !lua_getmetatable(L, i) || !lua_rawequal(L, -1, -2)) p=NULL; \ + lua_pop(L, 2); \ + return p ? TRUE : FALSE; \ +} \ +C shift##C(lua_State* L,int i) { \ + C* p; \ + if(!lua_isuserdata(L,i)) return NULL; \ + p = lua_touserdata(L, i); \ + lua_getfield(L, LUA_REGISTRYINDEX, #C); \ + if (p == NULL || !lua_getmetatable(L, i) || !lua_rawequal(L, -1, -2)) p=NULL; \ + lua_pop(L, 2); \ + if (p) { lua_remove(L,i); return *p; }\ + else return NULL;\ +} \ +int dummy##C + +#ifdef HAVE_LUA_5_1 + +#define WSLUA_REGISTER_CLASS(C) { \ + luaL_register (L, #C, C ## _methods); \ + luaL_newmetatable (L, #C); \ + luaL_register (L, NULL, C ## _meta); \ + lua_pushliteral(L, "__index"); \ + lua_pushvalue(L, -3); \ + lua_rawset(L, -3); \ + lua_pushliteral(L, "__metatable"); \ + lua_pushvalue(L, -3); \ + lua_rawset(L, -3); \ + lua_pop(L, 1); \ +} + +#define WSLUA_REGISTER_META(C) luaL_newmetatable (L, #C); luaL_register (L, NULL, C ## _meta); + +#define WSLUA_INIT(L) \ + luaL_openlibs(L); \ + wslua_register_classes(L); \ + wslua_register_functions(L); + + +#endif + +#define WSLUA_FUNCTION extern int +#define WSLUA_REGISTER_FUNCTION(name) { lua_pushstring(L, #name); lua_pushcfunction(L, wslua_## name); lua_settable(L, LUA_GLOBALSINDEX); } +#define WSLUA_REGISTER extern int + +#define WSLUA_METHOD static int +#define WSLUA_CONSTRUCTOR static int +#define WSLUA_ATTR_SET static int +#define WSLUA_ATTR_GET static int +#define WSLUA_METAMETHOD static int + +#define WSLUA_METHODS static const luaL_reg +#define WSLUA_META static const luaL_reg +#define WSLUA_CLASS_FNREG(class,name) { #name, class##_##name } + +#define WSLUA_ERROR(name,error) { luaL_error(L, ep_strdup_printf("%s%s", #name ": " ,error) ); return 0; } +#define WSLUA_ARG_ERROR(name,attr,error) { luaL_argerror(L,WSLUA_ARG_ ## name ## _ ## attr, #name ": " error); return 0; } +#define WSLUA_OPTARG_ERROR(name,attr,error) { luaL_argerror(L,WSLUA_OPTARG_##name##_ ##attr, #name ": " error); return 0; } + +#define WSLUA_REG_GLOBAL_BOOL(L,n,v) { lua_pushstring(L,n); lua_pushboolean(L,v); lua_settable(L, LUA_GLOBALSINDEX); } +#define WSLUA_REG_GLOBAL_STRING(n,v) { lua_pushstring(L,n); lua_pushstring(L,v); lua_settable(L, LUA_GLOBALSINDEX); } +#define WSLUA_REG_GLOBAL_NUMBER(n,v) { lua_pushstring(L,n); lua_pushnumber(L,v); lua_settable(L, LUA_GLOBALSINDEX); } + +#define WSLUA_RETURN(i) return (i); + +#define WSLUA_API extern + +#define NOP +#define FAIL_ON_NULL(s) if (! *p) luaL_argerror(L,index,s) + + + +#define WSLUA_CLASS_DECLARE(C) \ +extern C to##C(lua_State* L, int index); \ +extern C check##C(lua_State* L, int index); \ +extern C* push##C(lua_State* L, C v); \ +extern int C##_register(lua_State* L); \ +extern gboolean is##C(lua_State* L,int i); \ +extern C shift##C(lua_State* L,int i) + + +extern packet_info* lua_pinfo; +extern TreeItem lua_tree; +extern tvbuff_t* lua_tvb; +extern int lua_malformed; +extern dissector_handle_t lua_data_handle; +extern gboolean lua_initialized; +extern int lua_dissectors_table_ref; + +WSLUA_DECLARE_CLASSES() +WSLUA_DECLARE_FUNCTIONS() + +extern lua_State* wslua_state(void); + +extern gboolean wslua_optbool(lua_State* L, int n, gboolean def); +extern const gchar* lua_shiftstring(lua_State* L,int idx); +extern int dissect_lua(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree); + +extern void proto_register_lua(void); +extern GString* lua_register_all_taps(void); +extern void lua_prime_all_fields(proto_tree* tree); + +extern int Proto_commit(lua_State* L); + +extern void* push_Tvb(lua_State* L, Tvb tvb); +extern void clear_outstanding_tvbs(void); + +extern void* push_Pinfo(lua_State* L, Pinfo p); +extern void clear_outstanding_pinfos(void); + +extern void* push_TreeItem(lua_State* L, TreeItem ti); +extern void clear_outstanding_trees(void); + +extern void wslua_print_stack(char* s, lua_State* L); + +extern int wslua_init(lua_State* L); + +extern tap_extractor_t wslua_get_tap_extractor(const gchar* name); +extern int wslua_set_tap_enums(lua_State* L); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/x264_prt_id.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/x264_prt_id.h new file mode 100644 index 00000000..7be6bc0b --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/x264_prt_id.h @@ -0,0 +1,35 @@ +/* x264_prt_id.h + * Definitions of X.264/ISO 11570 transport protocol IDs + * + * $Id: x264_prt_id.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __X264_PRT_ID_H__ +#define __X264_PRT_ID_H__ + +/* X.264 / ISO 11570 transport protocol ID values. */ + +#define PRT_ID_ISO_8073 0x01 /* X.224/ISO 8073 COTP */ +#define PRT_ID_ISO_8602 0x02 /* X.234/ISO 8602 CLTP */ +#define PRT_ID_ISO_10736_ISO_8073 0x03 /* X.274/ISO 10736 + X.224/ISO 8073 */ +#define PRT_ID_ISO_10736_ISO_8602 0x04 /* X.274/ISO 10736 + X.234/ISO 8602 */ + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/xdlc.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/xdlc.h new file mode 100644 index 00000000..b9265f7e --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/xdlc.h @@ -0,0 +1,140 @@ +/* xdlc.h + * Define *DLC frame types, and routine to dissect the control field of + * a *DLC frame. + * + * $Id: xdlc.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __XDLC_H__ +#define __XDLC_H__ + +/* + * Low-order bits of first (extended) or only (basic) octet of control + * field, specifying the frame type. + */ +#define XDLC_I_MASK 0x01 /* Mask to test for I or not I */ +#define XDLC_I 0x00 /* Information frames */ +#define XDLC_S_U_MASK 0x03 /* Mask to test for S or U */ +#define XDLC_S 0x01 /* Supervisory frames */ +#define XDLC_U 0x03 /* Unnumbered frames */ + +/* + * N(S) and N(R) fields, in basic and extended operation. + */ +#define XDLC_N_R_MASK 0xE0 /* basic */ +#define XDLC_N_R_SHIFT 5 +#define XDLC_N_R_EXT_MASK 0xFE00 /* extended */ +#define XDLC_N_R_EXT_SHIFT 9 +#define XDLC_N_S_MASK 0x0E /* basic */ +#define XDLC_N_S_SHIFT 1 +#define XDLC_N_S_EXT_MASK 0x00FE /* extended */ +#define XDLC_N_S_EXT_SHIFT 1 + +/* + * Poll/Final bit, in basic and extended operation. + */ +#define XDLC_P_F 0x10 /* basic */ +#define XDLC_P_F_EXT 0x0100 /* extended */ + +/* + * S-format frame types. + */ +#define XDLC_S_FTYPE_MASK 0x0C +#define XDLC_RR 0x00 /* Receiver ready */ +#define XDLC_RNR 0x04 /* Receiver not ready */ +#define XDLC_REJ 0x08 /* Reject */ +#define XDLC_SREJ 0x0C /* Selective reject */ + +/* + * U-format modifiers. + */ +#define XDLC_U_MODIFIER_MASK 0xEC +#define XDLC_UI 0x00 /* Unnumbered Information */ +#define XDLC_UP 0x20 /* Unnumbered Poll */ +#define XDLC_DISC 0x40 /* Disconnect (command) */ +#define XDLC_RD 0x40 /* Request Disconnect (response) */ +#define XDLC_UA 0x60 /* Unnumbered Acknowledge */ +#define XDLC_SNRM 0x80 /* Set Normal Response Mode */ +#define XDLC_TEST 0xE0 /* Test */ +#define XDLC_SIM 0x04 /* Set Initialization Mode (command) */ +#define XDLC_RIM 0x04 /* Request Initialization Mode (response) */ +#define XDLC_FRMR 0x84 /* Frame reject */ +#define XDLC_CFGR 0xC4 /* Configure */ +#define XDLC_SARM 0x0C /* Set Asynchronous Response Mode (command) */ +#define XDLC_DM 0x0C /* Disconnected mode (response) */ +#define XDLC_SABM 0x2C /* Set Asynchronous Balanced Mode */ +#define XDLC_SARME 0x4C /* Set Asynchronous Response Mode Extended */ +#define XDLC_SABME 0x6C /* Set Asynchronous Balanced Mode Extended */ +#define XDLC_RESET 0x8C /* Reset */ +#define XDLC_XID 0xAC /* Exchange identification */ +#define XDLC_SNRME 0xCC /* Set Normal Response Mode Extended */ +#define XDLC_BCN 0xEC /* Beacon */ + +/* + * This macro takes the control field of an xDLC frame, as returned by + * "get_xdlc_control()" or "dissect_xdlc_control()", and evaluates to + * TRUE if the frame is an "information" frame and FALSE if it isn't. + * Note that frames other than information frames can have data in them, + * e.g. TEST frames. + */ +#define XDLC_IS_INFORMATION(control) \ + (((control) & XDLC_I_MASK) == XDLC_I || (control) == (XDLC_UI|XDLC_U)) + +/* + * This macro takes the control field of an xDLC frame, and a flag saying + * whether we're doing basic or extended operation, and evaluates to + * the length of that field (if it's an Unnumbered frame, or we're not + * in extended mode, it's 1 byte long, otherwise it's 2 bytes long). + */ +#define XDLC_CONTROL_LEN(control, is_extended) \ + ((((control) & XDLC_S_U_MASK) == XDLC_U || !(is_extended)) ? 1 : 2) + +/* + * Structure containing pointers to hf_ values for various subfields of + * the control field. + */ +typedef struct { + int *hf_xdlc_n_r; + int *hf_xdlc_n_s; + int *hf_xdlc_p; + int *hf_xdlc_f; + int *hf_xdlc_s_ftype; + int *hf_xdlc_u_modifier_cmd; + int *hf_xdlc_u_modifier_resp; + int *hf_xdlc_ftype_i; + int *hf_xdlc_ftype_s_u; +} xdlc_cf_items; + +extern const value_string ftype_vals[]; +extern const value_string stype_vals[]; +extern const value_string modifier_vals_cmd[]; +extern const value_string modifier_vals_resp[]; + +extern int get_xdlc_control(const guchar *pd, int offset, int extended); + +extern int dissect_xdlc_control(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *xdlc_tree, int hf_xdlc_control, gint ett_xdlc_control, + const xdlc_cf_items *cf_items_nonext, const xdlc_cf_items *cf_items_ext, + const value_string *u_modifier_short_vals_cmd, + const value_string *u_modifier_short_vals_resp, int is_response, + int is_extended, int append_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/xmlstub.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/xmlstub.h new file mode 100644 index 00000000..feb7e278 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/xmlstub.h @@ -0,0 +1,1123 @@ +/* + * This is part of tree.h from the libxml2 distribution. It is used + * for structure reference when dynamically linking to libxml. + * + * The GPL agreement for this file and for libxml2 can be found at + * http://www.xmlsoft.org + */ + +#include "config.h" + +/****************** specific to wireshark ********************************/ +/* + * Uncomment the following line to restore XML_DO_VALIDITY_CHECKING + * behavior which is causing issues on WIN32 platforms. See: + * http://www.ethereal.com/lists/ethereal-dev/200410/msg00194.html + */ +/* #define WIRESHARK_XML_DO_VALIDITY_CHECKING */ +/****************** From xml headers ************************************/ + +/* + * use those to be sure nothing nasty will happen if + * your library and includes mismatch + */ +#ifndef LIBXML2_COMPILING_MSCCDEF +extern void xmlCheckVersion(int version); +#endif /* LIBXML2_COMPILING_MSCCDEF */ +#define LIBXML_DOTTED_VERSION "2.3.8" +#define LIBXML_VERSION 20308 +#define LIBXML_VERSION_STRING "20308" +#define LIBXML_TEST_VERSION xmlCheckVersion(20308); + +/* + * Whether the trio support need to be configured in + */ +#if 0 +#define WITH_TRIO +#else +#define WITHOUT_TRIO +#endif + +/* + * Whether the FTP support is configured in + */ +#if 1 +#define LIBXML_FTP_ENABLED +#else +#define LIBXML_FTP_DISABLED +#endif + +/* + * Whether the HTTP support is configured in + */ +#if 1 +#define LIBXML_HTTP_ENABLED +#else +#define LIBXML_HTTP_DISABLED +#endif + +/* + * Whether the HTML support is configured in + */ +#if 1 +#define LIBXML_HTML_ENABLED +#else +#define LIBXML_HTML_DISABLED +#endif + +/* + * Whether the SGML Docbook support is configured in + */ +#if 1 +#define LIBXML_DOCB_ENABLED +#else +#define LIBXML_DOCB_DISABLED +#endif + +/* + * Whether XPath is configured in + */ +#if 1 +#define LIBXML_XPATH_ENABLED +#else +#define LIBXML_XPATH_DISABLED +#endif + +/* + * Whether XPointer is configured in + */ +#if 1 +#define LIBXML_XPTR_ENABLED +#else +#define LIBXML_XPTR_DISABLED +#endif + +/* + * Whether XInclude is configured in + */ +#if 1 +#define LIBXML_XINCLUDE_ENABLED +#else +#define LIBXML_XINCLUDE_DISABLED +#endif + +/* + * Whether iconv support is available + */ +#ifdef HAVE_ICONV +#define LIBXML_ICONV_ENABLED +#include +#else +#define LIBXML_ICONV_DISABLED +#endif + +/* + * Whether Debugging module is configured in + */ +#if 1 +#define LIBXML_DEBUG_ENABLED +#else +#define LIBXML_DEBUG_DISABLED +#endif + +/* + * Whether the memory debugging is configured in + */ +#if 0 +#define DEBUG_MEMORY_LOCATION +#endif + +#ifndef LIBXML_DLL_IMPORT +#if defined(_WIN32) && !defined(STATIC) +#define LIBXML_DLL_IMPORT __declspec(dllimport) +#else +#define LIBXML_DLL_IMPORT +#endif +#endif + +#ifdef __GNUC__ +#ifdef HAVE_ANSIDECL_H +#include +#endif +#ifndef ATTRIBUTE_UNUSED +#define ATTRIBUTE_UNUSED +#endif +#else +#define ATTRIBUTE_UNUSED +#endif + + +#define XML_XML_NAMESPACE \ + (const xmlChar *) "http://www.w3.org/XML/1998/namespace" + +/* + * The different element types carried by an XML tree + * + * NOTE: This is synchronized with DOM Level1 values + * See http://www.w3.org/TR/REC-DOM-Level-1/ + * + * Actually this had diverged a bit, and now XML_DOCUMENT_TYPE_NODE should + * be deprecated to use an XML_DTD_NODE. + */ +typedef enum { + XML_ELEMENT_NODE= 1, + XML_ATTRIBUTE_NODE= 2, + XML_TEXT_NODE= 3, + XML_CDATA_SECTION_NODE= 4, + XML_ENTITY_REF_NODE= 5, + XML_ENTITY_NODE= 6, + XML_PI_NODE= 7, + XML_COMMENT_NODE= 8, + XML_DOCUMENT_NODE= 9, + XML_DOCUMENT_TYPE_NODE= 10, + XML_DOCUMENT_FRAG_NODE= 11, + XML_NOTATION_NODE= 12, + XML_HTML_DOCUMENT_NODE= 13, + XML_DTD_NODE= 14, + XML_ELEMENT_DECL= 15, + XML_ATTRIBUTE_DECL= 16, + XML_ENTITY_DECL= 17, + XML_NAMESPACE_DECL= 18, + XML_XINCLUDE_START= 19, + XML_XINCLUDE_END= 20 +#ifdef LIBXML_DOCB_ENABLED + ,XML_DOCB_DOCUMENT_NODE= 21 +#endif +} xmlElementType; + +/* + * Size of an internal character representation. + * + * We use 8bit chars internal representation for memory efficiency, + * Note that with 8 bits wide xmlChars one can still use UTF-8 to handle + * correctly non ISO-Latin input. + */ + +typedef unsigned char xmlChar; + +#ifndef _WIN32 +#ifndef CHAR +#define CHAR xmlChar +#endif +#endif + +#define BAD_CAST (xmlChar *) + +/* + * a DTD Notation definition + */ + +typedef struct _xmlNotation xmlNotation; +typedef xmlNotation *xmlNotationPtr; +struct _xmlNotation { + const xmlChar *name; /* Notation name */ + const xmlChar *PublicID; /* Public identifier, if any */ + const xmlChar *SystemID; /* System identifier, if any */ +}; + +/* + * a DTD Attribute definition + */ + +typedef enum { + XML_ATTRIBUTE_CDATA = 1, + XML_ATTRIBUTE_ID, + XML_ATTRIBUTE_IDREF , + XML_ATTRIBUTE_IDREFS, + XML_ATTRIBUTE_ENTITY, + XML_ATTRIBUTE_ENTITIES, + XML_ATTRIBUTE_NMTOKEN, + XML_ATTRIBUTE_NMTOKENS, + XML_ATTRIBUTE_ENUMERATION, + XML_ATTRIBUTE_NOTATION +} xmlAttributeType; + +typedef enum { + XML_ATTRIBUTE_NONE = 1, + XML_ATTRIBUTE_REQUIRED, + XML_ATTRIBUTE_IMPLIED, + XML_ATTRIBUTE_FIXED +} xmlAttributeDefault; + +typedef struct _xmlEnumeration xmlEnumeration; +typedef xmlEnumeration *xmlEnumerationPtr; +struct _xmlEnumeration { + struct _xmlEnumeration *next; /* next one */ + const xmlChar *name; /* Enumeration name */ +}; + +typedef struct _xmlAttribute xmlAttribute; +typedef xmlAttribute *xmlAttributePtr; +struct _xmlAttribute { +#ifndef XML_WITHOUT_CORBA + void *_private; /* for Corba, must be first ! */ +#endif + xmlElementType type; /* XML_ATTRIBUTE_DECL, must be second ! */ + const xmlChar *name; /* Attribute name */ + struct _xmlNode *children; /* NULL */ + struct _xmlNode *last; /* NULL */ + struct _xmlDtd *parent; /* -> DTD */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + + struct _xmlAttribute *nexth; /* next in hash table */ + xmlAttributeType atype; /* The attribute type */ + xmlAttributeDefault def; /* the default */ + const xmlChar *defaultValue; /* or the default value */ + xmlEnumerationPtr tree; /* or the enumeration tree if any */ + const xmlChar *prefix; /* the namespace prefix if any */ + const xmlChar *elem; /* Element holding the attribute */ +}; + +/* + * a DTD Element definition. + */ +typedef enum { + XML_ELEMENT_CONTENT_PCDATA = 1, + XML_ELEMENT_CONTENT_ELEMENT, + XML_ELEMENT_CONTENT_SEQ, + XML_ELEMENT_CONTENT_OR +} xmlElementContentType; + +typedef enum { + XML_ELEMENT_CONTENT_ONCE = 1, + XML_ELEMENT_CONTENT_OPT, + XML_ELEMENT_CONTENT_MULT, + XML_ELEMENT_CONTENT_PLUS +} xmlElementContentOccur; + +typedef struct _xmlElementContent xmlElementContent; +typedef xmlElementContent *xmlElementContentPtr; +struct _xmlElementContent { + xmlElementContentType type; /* PCDATA, ELEMENT, SEQ or OR */ + xmlElementContentOccur ocur; /* ONCE, OPT, MULT or PLUS */ + const xmlChar *name; /* Element name */ + struct _xmlElementContent *c1; /* first child */ + struct _xmlElementContent *c2; /* second child */ + struct _xmlElementContent *parent; /* parent */ +}; + +typedef enum { + XML_ELEMENT_TYPE_UNDEFINED = 0, + XML_ELEMENT_TYPE_EMPTY = 1, + XML_ELEMENT_TYPE_ANY, + XML_ELEMENT_TYPE_MIXED, + XML_ELEMENT_TYPE_ELEMENT +} xmlElementTypeVal; + +typedef struct _xmlElement xmlElement; +typedef xmlElement *xmlElementPtr; +struct _xmlElement { +#ifndef XML_WITHOUT_CORBA + void *_private; /* for Corba, must be first ! */ +#endif + xmlElementType type; /* XML_ELEMENT_DECL, must be second ! */ + const xmlChar *name; /* Element name */ + struct _xmlNode *children; /* NULL */ + struct _xmlNode *last; /* NULL */ + struct _xmlDtd *parent; /* -> DTD */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + + xmlElementTypeVal etype; /* The type */ + xmlElementContentPtr content; /* the allowed element content */ + xmlAttributePtr attributes; /* List of the declared attributes */ + const xmlChar *prefix; /* the namespace prefix if any */ +}; + +/* + * An XML namespace. + * Note that prefix == NULL is valid, it defines the default namespace + * within the subtree (until overriden). + * + * XML_GLOBAL_NAMESPACE is now deprecated for good + * xmlNsType is unified with xmlElementType + */ + +#define XML_LOCAL_NAMESPACE XML_NAMESPACE_DECL +typedef xmlElementType xmlNsType; + +typedef struct _xmlNs xmlNs; +typedef xmlNs *xmlNsPtr; +struct _xmlNs { + struct _xmlNs *next; /* next Ns link for this node */ + xmlNsType type; /* global or local */ + const xmlChar *href; /* URL for the namespace */ + const xmlChar *prefix; /* prefix for the namespace */ +}; + +/* + * An XML DtD, as defined by parent link */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + + /* End of common part */ + void *notations; /* Hash table for notations if any */ + void *elements; /* Hash table for elements if any */ + void *attributes; /* Hash table for attributes if any */ + void *entities; /* Hash table for entities if any */ + const xmlChar *ExternalID; /* External identifier for PUBLIC DTD */ + const xmlChar *SystemID; /* URI for a SYSTEM or PUBLIC DTD */ + void *pentities; /* Hash table for param entities if any */ +}; + +/* + * A attribute of an XML node. + */ +typedef struct _xmlAttr xmlAttr; +typedef xmlAttr *xmlAttrPtr; +struct _xmlAttr { +#ifndef XML_WITHOUT_CORBA + void *_private; /* for Corba, must be first ! */ +#endif + xmlElementType type; /* XML_ATTRIBUTE_NODE, must be second ! */ + const xmlChar *name; /* the name of the property */ + struct _xmlNode *children; /* the value of the property */ + struct _xmlNode *last; /* NULL */ + struct _xmlNode *parent; /* child->parent link */ + struct _xmlAttr *next; /* next sibling link */ + struct _xmlAttr *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + xmlNs *ns; /* pointer to the associated namespace */ + xmlAttributeType atype; /* the attribute type if validating */ +}; + +/* + * An XML ID instance. + */ + +typedef struct _xmlID xmlID; +typedef xmlID *xmlIDPtr; +struct _xmlID { + struct _xmlID *next; /* next ID */ + const xmlChar *value; /* The ID name */ + xmlAttrPtr attr; /* The attribut holding it */ +}; + +/* + * An XML IDREF instance. + */ + +typedef struct _xmlRef xmlRef; +typedef xmlRef *xmlRefPtr; +struct _xmlRef { + struct _xmlRef *next; /* next Ref */ + const xmlChar *value; /* The Ref name */ + xmlAttrPtr attr; /* The attribut holding it */ +}; + +/* + * A buffer structure + */ + +typedef enum { + XML_BUFFER_ALLOC_DOUBLEIT, + XML_BUFFER_ALLOC_EXACT +} xmlBufferAllocationScheme; + +typedef struct _xmlBuffer xmlBuffer; +typedef xmlBuffer *xmlBufferPtr; +struct _xmlBuffer { + xmlChar *content; /* The buffer content UTF8 */ + unsigned int use; /* The buffer size used */ + unsigned int size; /* The buffer size */ + xmlBufferAllocationScheme alloc; /* The realloc method */ +}; + +/* + * A node in an XML tree. + */ +typedef struct _xmlNode xmlNode; +typedef xmlNode *xmlNodePtr; +struct _xmlNode { +#ifndef XML_WITHOUT_CORBA + void *_private; /* for Corba, must be first ! */ +#endif + xmlElementType type; /* type number, must be second ! */ + const xmlChar *name; /* the name of the node, or the entity */ + struct _xmlNode *children; /* parent->childs link */ + struct _xmlNode *last; /* last child link */ + struct _xmlNode *parent; /* child->parent link */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + xmlNs *ns; /* pointer to the associated namespace */ +#ifndef XML_USE_BUFFER_CONTENT + xmlChar *content; /* the content */ +#else + xmlBufferPtr content; /* the content in a buffer */ +#endif + + /* End of common part */ + struct _xmlAttr *properties;/* properties list */ + xmlNs *nsDef; /* namespace definitions on this node */ +}; + +/* + * An XML document. + */ +typedef struct _xmlDoc xmlDoc; +typedef xmlDoc *xmlDocPtr; +struct _xmlDoc { +#ifndef XML_WITHOUT_CORBA + void *_private; /* for Corba, must be first ! */ +#endif + xmlElementType type; /* XML_DOCUMENT_NODE, must be second ! */ + char *name; /* name/filename/URI of the document */ + struct _xmlNode *children; /* the document tree */ + struct _xmlNode *last; /* last child link */ + struct _xmlNode *parent; /* child->parent link */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* autoreference to itself */ + + /* End of common part */ + int compression;/* level of zlib compression */ + int standalone; /* standalone document (no external refs) */ + struct _xmlDtd *intSubset; /* the document internal subset */ + struct _xmlDtd *extSubset; /* the document external subset */ + struct _xmlNs *oldNs; /* Global namespace, the old way */ + const xmlChar *version; /* the XML version string */ + const xmlChar *encoding; /* external initial encoding, if any */ + void *ids; /* Hash table for ID attributes if any */ + void *refs; /* Hash table for IDREFs attributes if any */ + const xmlChar *URL; /* The URI for that document */ + int charset; /* encoding of the in-memory content + actually an xmlCharEncoding */ +}; + +/** + * Predefined values for some standard encodings + * Libxml don't do beforehand translation on UTF8, ISOLatinX + * It also support UTF16 (LE and BE) by default. + * + * Anything else would have to be translated to UTF8 before being + * given to the parser itself. The BOM for UTF16 and the encoding + * declaration are looked at and a converter is looked for at that + * point. If not found the parser stops here as asked by the XML REC + * Converter can be registered by the user using xmlRegisterCharEncodingHandler + * but the currentl form doesn't allow stateful transcoding (a serious + * problem agreed !). If iconv has been found it will be used + * automatically and allow stateful transcoding, the simplest is then + * to be sure to enable icon and to provide iconv libs for the encoding + * support needed. + */ +typedef enum { + XML_CHAR_ENCODING_ERROR= -1, /* No char encoding detected */ + XML_CHAR_ENCODING_NONE= 0, /* No char encoding detected */ + XML_CHAR_ENCODING_UTF8= 1, /* UTF-8 */ + XML_CHAR_ENCODING_UTF16LE= 2, /* UTF-16 little endian */ + XML_CHAR_ENCODING_UTF16BE= 3, /* UTF-16 big endian */ + XML_CHAR_ENCODING_UCS4LE= 4, /* UCS-4 little endian */ + XML_CHAR_ENCODING_UCS4BE= 5, /* UCS-4 big endian */ + XML_CHAR_ENCODING_EBCDIC= 6, /* EBCDIC uh! */ + XML_CHAR_ENCODING_UCS4_2143=7, /* UCS-4 unusual ordering */ + XML_CHAR_ENCODING_UCS4_3412=8, /* UCS-4 unusual ordering */ + XML_CHAR_ENCODING_UCS2= 9, /* UCS-2 */ + XML_CHAR_ENCODING_8859_1= 10,/* ISO-8859-1 ISO Latin 1 */ + XML_CHAR_ENCODING_8859_2= 11,/* ISO-8859-2 ISO Latin 2 */ + XML_CHAR_ENCODING_8859_3= 12,/* ISO-8859-3 */ + XML_CHAR_ENCODING_8859_4= 13,/* ISO-8859-4 */ + XML_CHAR_ENCODING_8859_5= 14,/* ISO-8859-5 */ + XML_CHAR_ENCODING_8859_6= 15,/* ISO-8859-6 */ + XML_CHAR_ENCODING_8859_7= 16,/* ISO-8859-7 */ + XML_CHAR_ENCODING_8859_8= 17,/* ISO-8859-8 */ + XML_CHAR_ENCODING_8859_9= 18,/* ISO-8859-9 */ + XML_CHAR_ENCODING_2022_JP= 19,/* ISO-2022-JP */ + XML_CHAR_ENCODING_SHIFT_JIS=20,/* Shift_JIS */ + XML_CHAR_ENCODING_EUC_JP= 21,/* EUC-JP */ + XML_CHAR_ENCODING_ASCII= 22 /* pure ASCII */ +} xmlCharEncoding; + +/** + * xmlCharEncodingInputFunc: + * @param out a pointer ot an array of bytes to store the UTF-8 result + * @param outlen the length of out + * @param in a pointer ot an array of chars in the original encoding + * @param inlen the length of in + * + * Take a block of chars in the original encoding and try to convert + * it to an UTF-8 block of chars out. + * + * Returns the number of byte written, or -1 by lack of space, or -2 + * if the transcoding failed. + * The value of inlen after return is the number of octets consumed + * as the return value is positive, else unpredictiable. + * The value of outlen after return is the number of ocetes consumed. + */ +typedef int (* xmlCharEncodingInputFunc)(unsigned char* out, int *outlen, + const unsigned char* in, int *inlen); + + +/** + * xmlCharEncodingOutputFunc: + * @param out a pointer ot an array of bytes to store the result + * @param outlen the length of out + * @param in a pointer ot an array of UTF-8 chars + * @param inlen the length of in + * + * Take a block of UTF-8 chars in and try to convert it to an other + * encoding. + * Note: a first call designed to produce heading info is called with + * in = NULL. If stateful this should also initialize the encoder state + * + * Returns the number of byte written, or -1 by lack of space, or -2 + * if the transcoding failed. + * The value of inlen after return is the number of octets consumed + * as the return value is positive, else unpredictiable. + * The value of outlen after return is the number of ocetes consumed. + */ +typedef int (* xmlCharEncodingOutputFunc)(unsigned char* out, int *outlen, + const unsigned char* in, int *inlen); + + +/* + * Block defining the handlers for non UTF-8 encodings. + * If iconv is supported, there is two extra fields + */ + +typedef struct _xmlCharEncodingHandler xmlCharEncodingHandler; +typedef xmlCharEncodingHandler *xmlCharEncodingHandlerPtr; +struct _xmlCharEncodingHandler { + char *name; + xmlCharEncodingInputFunc input; + xmlCharEncodingOutputFunc output; +#ifdef LIBXML_ICONV_ENABLED + iconv_t iconv_in; + iconv_t iconv_out; +#endif /* LIBXML_ICONV_ENABLED */ +}; + +typedef int (*xmlInputMatchCallback) (char const *filename); +typedef void * (*xmlInputOpenCallback) (char const *filename); +typedef int (*xmlInputReadCallback) (void * context, char * buffer, int len); +typedef void (*xmlInputCloseCallback) (void * context); + +typedef struct _xmlParserInputBuffer xmlParserInputBuffer; +typedef xmlParserInputBuffer *xmlParserInputBufferPtr; +struct _xmlParserInputBuffer { + void* context; + xmlInputReadCallback readcallback; + xmlInputCloseCallback closecallback; + + xmlCharEncodingHandlerPtr encoder; /* I18N conversions to UTF-8 */ + + xmlBufferPtr buffer; /* Local buffer encoded in UTF-8 */ + xmlBufferPtr raw; /* if encoder != NULL buffer for raw input */ +}; + + +/* + * Those are the functions and datatypes for the library output + * I/O structures. + */ + +typedef int (*xmlOutputMatchCallback) (char const *filename); +typedef void * (*xmlOutputOpenCallback) (char const *filename); +typedef int (*xmlOutputWriteCallback) (void * context, const char * buffer, + int len); +typedef void (*xmlOutputCloseCallback) (void * context); + +typedef struct _xmlOutputBuffer xmlOutputBuffer; +typedef xmlOutputBuffer *xmlOutputBufferPtr; +struct _xmlOutputBuffer { + void* context; + xmlOutputWriteCallback writecallback; + xmlOutputCloseCallback closecallback; + + xmlCharEncodingHandlerPtr encoder; /* I18N conversions to UTF-8 */ + + xmlBufferPtr buffer; /* Local buffer encoded in UTF-8 or ISOLatin */ + xmlBufferPtr conv; /* if encoder != NULL buffer for output */ + int written; /* total number of byte written */ +}; + +#define XML_DEFAULT_VERSION "1.0" + +/** + * an xmlParserInput is an input flow for the XML processor. + * Each entity parsed is associated an xmlParserInput (except the + * few predefined ones). This is the case both for internal entities + * - in which case the flow is already completely in memory - or + * external entities - in which case we use the buf structure for + * progressive reading and I18N conversions to the internal UTF-8 format. + */ + +typedef void (* xmlParserInputDeallocate)(xmlChar *); +typedef struct _xmlParserInput xmlParserInput; +typedef xmlParserInput *xmlParserInputPtr; +struct _xmlParserInput { + /* Input buffer */ + xmlParserInputBufferPtr buf; /* UTF-8 encoded buffer */ + + const char *filename; /* The file analyzed, if any */ + const char *directory; /* the directory/base of teh file */ + const xmlChar *base; /* Base of the array to parse */ + const xmlChar *cur; /* Current char being parsed */ + const xmlChar *end; /* end of the arry to parse */ + int length; /* length if known */ + int line; /* Current line */ + int col; /* Current column */ + int consumed; /* How many xmlChars already consumed */ + xmlParserInputDeallocate free; /* function to deallocate the base */ + const xmlChar *encoding; /* the encoding string for entity */ + const xmlChar *version; /* the version string for entity */ + int standalone; /* Was that entity marked standalone */ +}; + +/** + * the parser can be asked to collect Node informations, i.e. at what + * place in the file they were detected. + * NOTE: This is off by default and not very well tested. + */ +typedef struct _xmlParserNodeInfo xmlParserNodeInfo; +typedef xmlParserNodeInfo *xmlParserNodeInfoPtr; + +struct _xmlParserNodeInfo { + const struct _xmlNode* node; + /* Position & line # that text that created the node begins & ends on */ + unsigned long begin_pos; + unsigned long begin_line; + unsigned long end_pos; + unsigned long end_line; +}; + +typedef struct _xmlParserNodeInfoSeq xmlParserNodeInfoSeq; +typedef xmlParserNodeInfoSeq *xmlParserNodeInfoSeqPtr; +struct _xmlParserNodeInfoSeq { + unsigned long maximum; + unsigned long length; + xmlParserNodeInfo* buffer; +}; + +/* + * Validation state added for non-determinist content model + */ +typedef struct _xmlValidState xmlValidState; +typedef xmlValidState *xmlValidStatePtr; + +/** + * an xmlValidCtxt is used for error reporting when validating + */ + +typedef void (*xmlValidityErrorFunc) (void *ctx, const char *msg, ...); +typedef void (*xmlValidityWarningFunc) (void *ctx, const char *msg, ...); + +typedef struct _xmlValidCtxt xmlValidCtxt; +typedef xmlValidCtxt *xmlValidCtxtPtr; +struct _xmlValidCtxt { + void *userData; /* user specific data block */ + xmlValidityErrorFunc error; /* the callback in case of errors */ + xmlValidityWarningFunc warning; /* the callback in case of warning */ + + /* Node analysis stack used when validating within entities */ + xmlNodePtr node; /* Current parsed Node */ + int nodeNr; /* Depth of the parsing stack */ + int nodeMax; /* Max depth of the parsing stack */ + xmlNodePtr *nodeTab; /* array of nodes */ + + int finishDtd; /* finished validating the Dtd ? */ + xmlDocPtr doc; /* the document */ + int valid; /* temporary validity check result */ + + /* state state used for non-determinist content validation */ + xmlValidState *vstate; /* current state */ + int vstateNr; /* Depth of the validation stack */ + int vstateMax; /* Max depth of the validation stack */ + xmlValidState *vstateTab; /* array of validation states */ +}; + +typedef struct _xmlLink xmlLink; +typedef xmlLink *xmlLinkPtr; + +typedef struct _xmlList xmlList; +typedef xmlList *xmlListPtr; + +typedef void (*xmlListDeallocator) (xmlLinkPtr lk); +typedef int (*xmlListDataCompare) (const void *data0, const void *data1); +typedef int (*xmlListWalker) (const void *data, const void *user); + +/* + * ALl notation declarations are stored in a table + * there is one table per DTD + */ + +typedef struct _xmlHashTable xmlNotationTable; +typedef xmlNotationTable *xmlNotationTablePtr; + +/* + * ALl element declarations are stored in a table + * there is one table per DTD + */ + +typedef struct _xmlHashTable xmlElementTable; +typedef xmlElementTable *xmlElementTablePtr; + +/* + * ALl attribute declarations are stored in a table + * there is one table per DTD + */ + +typedef struct _xmlHashTable xmlAttributeTable; +typedef xmlAttributeTable *xmlAttributeTablePtr; + +/* + * ALl IDs attributes are stored in a table + * there is one table per document + */ + +typedef struct _xmlHashTable xmlIDTable; +typedef xmlIDTable *xmlIDTablePtr; + +/* + * ALl Refs attributes are stored in a table + * there is one table per document + */ + +typedef struct _xmlHashTable xmlRefTable; +typedef xmlRefTable *xmlRefTablePtr; + +/* helper */ +xmlChar * xmlSplitQName2 (const xmlChar *name, + xmlChar **prefix); + +/** + * The parser is now working also as a state based parser + * The recursive one use the stagte info for entities processing + */ +typedef enum { + XML_PARSER_EOF = -1, /* nothing is to be parsed */ + XML_PARSER_START = 0, /* nothing has been parsed */ + XML_PARSER_MISC, /* Misc* before int subset */ + XML_PARSER_PI, /* Whithin a processing instruction */ + XML_PARSER_DTD, /* within some DTD content */ + XML_PARSER_PROLOG, /* Misc* after internal subset */ + XML_PARSER_COMMENT, /* within a comment */ + XML_PARSER_START_TAG, /* within a start tag */ + XML_PARSER_CONTENT, /* within the content */ + XML_PARSER_CDATA_SECTION, /* within a CDATA section */ + XML_PARSER_END_TAG, /* within a closing tag */ + XML_PARSER_ENTITY_DECL, /* within an entity declaration */ + XML_PARSER_ENTITY_VALUE, /* within an entity value in a decl */ + XML_PARSER_ATTRIBUTE_VALUE, /* within an attribute value */ + XML_PARSER_SYSTEM_LITERAL, /* within a SYSTEM value */ + XML_PARSER_EPILOG, /* the Misc* after the last end tag */ + XML_PARSER_IGNORE /* within an IGNORED section */ +} xmlParserInputState; + +/** + * The parser context. + * NOTE This doesn't completely defines the parser state, the (current ?) + * design of the parser uses recursive function calls since this allow + * and easy mapping from the production rules of the specification + * to the actual code. The drawback is that the actual function call + * also reflect the parser state. However most of the parsing routines + * takes as the only argument the parser context pointer, so migrating + * to a state based parser for progressive parsing shouldn't be too hard. + */ +typedef struct _xmlParserCtxt xmlParserCtxt; +typedef xmlParserCtxt *xmlParserCtxtPtr; +struct _xmlParserCtxt { + struct _xmlSAXHandler *sax; /* The SAX handler */ + void *userData; /* For SAX interface only, used by DOM build */ + xmlDocPtr myDoc; /* the document being built */ + int wellFormed; /* is the document well formed */ + int replaceEntities; /* shall we replace entities ? */ + const xmlChar *version; /* the XML version string */ + const xmlChar *encoding; /* the declared encoding, if any */ + int standalone; /* standalone document */ + int html; /* an HTML(1)/Docbook(2) document */ + + /* Input stream stack */ + xmlParserInputPtr input; /* Current input stream */ + int inputNr; /* Number of current input streams */ + int inputMax; /* Max number of input streams */ + xmlParserInputPtr *inputTab; /* stack of inputs */ + + /* Node analysis stack only used for DOM building */ + xmlNodePtr node; /* Current parsed Node */ + int nodeNr; /* Depth of the parsing stack */ + int nodeMax; /* Max depth of the parsing stack */ + xmlNodePtr *nodeTab; /* array of nodes */ + + int record_info; /* Whether node info should be kept */ + xmlParserNodeInfoSeq node_seq; /* info about each node parsed */ + + int errNo; /* error code */ + + int hasExternalSubset; /* reference and external subset */ + int hasPErefs; /* the internal subset has PE refs */ + int external; /* are we parsing an external entity */ + + int valid; /* is the document valid */ + int validate; /* shall we try to validate ? */ + xmlValidCtxt vctxt; /* The validity context */ + + xmlParserInputState instate; /* current type of input */ + int token; /* next char look-ahead */ + + char *directory; /* the data directory */ + + /* Node name stack */ + xmlChar *name; /* Current parsed Node */ + int nameNr; /* Depth of the parsing stack */ + int nameMax; /* Max depth of the parsing stack */ + xmlChar * *nameTab; /* array of nodes */ + + long nbChars; /* number of xmlChar processed */ + long checkIndex; /* used by progressive parsing lookup */ + int keepBlanks; /* ugly but ... */ + int disableSAX; /* SAX callbacks are disabled */ + int inSubset; /* Parsing is in int 1/ext 2 subset */ + xmlChar * intSubName; /* name of subset */ + xmlChar * extSubURI; /* URI of external subset */ + xmlChar * extSubSystem; /* SYSTEM ID of external subset */ + + /* xml:space values */ + int * space; /* Should the parser preserve spaces */ + int spaceNr; /* Depth of the parsing stack */ + int spaceMax; /* Max depth of the parsing stack */ + int * spaceTab; /* array of space infos */ + + int depth; /* to prevent entity substitution loops */ + xmlParserInputPtr entity; /* used to check entities boundaries */ + int charset; /* encoding of the in-memory content + actually an xmlCharEncoding */ + int nodelen; /* Those two fields are there to */ + int nodemem; /* Speed up large node parsing */ + int pedantic; /* signal pedantic warnings */ + void *_private; /* For user data, libxml won't touch it */ + + int loadsubset; /* should the external subset be loaded */ +}; + +/** + * a SAX Locator. + */ +typedef struct _xmlSAXLocator xmlSAXLocator; +typedef xmlSAXLocator *xmlSAXLocatorPtr; +struct _xmlSAXLocator { + const xmlChar *(*getPublicId)(void *ctx); + const xmlChar *(*getSystemId)(void *ctx); + int (*getLineNumber)(void *ctx); + int (*getColumnNumber)(void *ctx); +}; + +/* + * The different valid entity types + */ +typedef enum { + XML_INTERNAL_GENERAL_ENTITY = 1, + XML_EXTERNAL_GENERAL_PARSED_ENTITY = 2, + XML_EXTERNAL_GENERAL_UNPARSED_ENTITY = 3, + XML_INTERNAL_PARAMETER_ENTITY = 4, + XML_EXTERNAL_PARAMETER_ENTITY = 5, + XML_INTERNAL_PREDEFINED_ENTITY = 6 +} xmlEntityType; + +/* + * An unit of storage for an entity, contains the string, the value + * and the linkind data needed for the linking in the hash table. + */ + +typedef struct _xmlEntity xmlEntity; +typedef xmlEntity *xmlEntityPtr; +struct _xmlEntity { +#ifndef XML_WITHOUT_CORBA + void *_private; /* for Corba, must be first ! */ +#endif + xmlElementType type; /* XML_ENTITY_DECL, must be second ! */ + const xmlChar *name; /* Attribute name */ + struct _xmlNode *children; /* NULL */ + struct _xmlNode *last; /* NULL */ + struct _xmlDtd *parent; /* -> DTD */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + + xmlChar *orig; /* content without ref substitution */ + xmlChar *content; /* content or ndata if unparsed */ + int length; /* the content length */ + xmlEntityType etype; /* The entity type */ + const xmlChar *ExternalID; /* External identifier for PUBLIC */ + const xmlChar *SystemID; /* URI for a SYSTEM or PUBLIC Entity */ + + struct _xmlEntity *nexte; /* unused */ + const xmlChar *URI; /* the full URI as computed */ +}; + +/* + * ALl entities are stored in an hash table + * there is 2 separate hash tables for global and parmeter entities + */ + +typedef struct _xmlHashTable xmlEntitiesTable; +typedef xmlEntitiesTable *xmlEntitiesTablePtr; + +/* + * External functions : + */ + +/** + * a SAX handler is bunch of callbacks called by the parser when processing + * of the input generate data or structure informations. + */ + +typedef xmlParserInputPtr (*resolveEntitySAXFunc) (void *ctx, + const xmlChar *publicId, const xmlChar *systemId); +typedef void (*internalSubsetSAXFunc) (void *ctx, const xmlChar *name, + const xmlChar *ExternalID, const xmlChar *SystemID); +typedef void (*externalSubsetSAXFunc) (void *ctx, const xmlChar *name, + const xmlChar *ExternalID, const xmlChar *SystemID); +typedef xmlEntityPtr (*getEntitySAXFunc) (void *ctx, + const xmlChar *name); +typedef xmlEntityPtr (*getParameterEntitySAXFunc) (void *ctx, + const xmlChar *name); +typedef void (*entityDeclSAXFunc) (void *ctx, + const xmlChar *name, int type, const xmlChar *publicId, + const xmlChar *systemId, xmlChar *content); +typedef void (*notationDeclSAXFunc)(void *ctx, const xmlChar *name, + const xmlChar *publicId, const xmlChar *systemId); +typedef void (*attributeDeclSAXFunc)(void *ctx, const xmlChar *elem, + const xmlChar *name, int type, int def, + const xmlChar *defaultValue, xmlEnumerationPtr tree); +typedef void (*elementDeclSAXFunc)(void *ctx, const xmlChar *name, + int type, xmlElementContentPtr content); +typedef void (*unparsedEntityDeclSAXFunc)(void *ctx, + const xmlChar *name, const xmlChar *publicId, + const xmlChar *systemId, const xmlChar *notationName); +typedef void (*setDocumentLocatorSAXFunc) (void *ctx, + xmlSAXLocatorPtr loc); +typedef void (*startDocumentSAXFunc) (void *ctx); +typedef void (*endDocumentSAXFunc) (void *ctx); +typedef void (*startElementSAXFunc) (void *ctx, const xmlChar *name, + const xmlChar **atts); +typedef void (*endElementSAXFunc) (void *ctx, const xmlChar *name); +typedef void (*attributeSAXFunc) (void *ctx, const xmlChar *name, + const xmlChar *value); +typedef void (*referenceSAXFunc) (void *ctx, const xmlChar *name); +typedef void (*charactersSAXFunc) (void *ctx, const xmlChar *ch, + int len); +typedef void (*ignorableWhitespaceSAXFunc) (void *ctx, + const xmlChar *ch, int len); +typedef void (*processingInstructionSAXFunc) (void *ctx, + const xmlChar *target, const xmlChar *data); +typedef void (*commentSAXFunc) (void *ctx, const xmlChar *value); +typedef void (*cdataBlockSAXFunc) (void *ctx, const xmlChar *value, int len); +typedef void (*warningSAXFunc) (void *ctx, const char *msg, ...); +typedef void (*errorSAXFunc) (void *ctx, const char *msg, ...); +typedef void (*fatalErrorSAXFunc) (void *ctx, const char *msg, ...); +typedef int (*isStandaloneSAXFunc) (void *ctx); +typedef int (*hasInternalSubsetSAXFunc) (void *ctx); +typedef int (*hasExternalSubsetSAXFunc) (void *ctx); + +typedef struct _xmlSAXHandler xmlSAXHandler; +typedef xmlSAXHandler *xmlSAXHandlerPtr; +struct _xmlSAXHandler { + internalSubsetSAXFunc internalSubset; + isStandaloneSAXFunc isStandalone; + hasInternalSubsetSAXFunc hasInternalSubset; + hasExternalSubsetSAXFunc hasExternalSubset; + resolveEntitySAXFunc resolveEntity; + getEntitySAXFunc getEntity; + entityDeclSAXFunc entityDecl; + notationDeclSAXFunc notationDecl; + attributeDeclSAXFunc attributeDecl; + elementDeclSAXFunc elementDecl; + unparsedEntityDeclSAXFunc unparsedEntityDecl; + setDocumentLocatorSAXFunc setDocumentLocator; + startDocumentSAXFunc startDocument; + endDocumentSAXFunc endDocument; + startElementSAXFunc startElement; + endElementSAXFunc endElement; + referenceSAXFunc reference; + charactersSAXFunc characters; + ignorableWhitespaceSAXFunc ignorableWhitespace; + processingInstructionSAXFunc processingInstruction; + commentSAXFunc comment; + warningSAXFunc warning; + errorSAXFunc error; + fatalErrorSAXFunc fatalError; + getParameterEntitySAXFunc getParameterEntity; + cdataBlockSAXFunc cdataBlock; + externalSubsetSAXFunc externalSubset; +}; + +/** + * External entity loaders types + */ +typedef xmlParserInputPtr (*xmlExternalEntityLoader)(const char *URL, + const char *ID, + xmlParserCtxtPtr context); + +/* + * Compatibility naming layer with libxml1 + */ +#ifndef xmlChildrenNode +#define xmlChildrenNode children +#define xmlRootNode children +#endif + + +/*********************Xml routines and function pointers */ +#ifdef IN_XMLSTUB +#define XML_EXTERN +#else +#define XML_EXTERN extern +#endif + +typedef struct { + /* Functions */ + xmlDocPtr (*xmlParseFile)(const char *filename); + int (*xmlStrcmp)(const xmlChar *str1, const xmlChar *str2); + xmlParserCtxtPtr (*xmlCreatePushParserCtxt)(xmlSAXHandlerPtr, void *, const char *, + int, const char *); + int (*xmlParseChunk)(xmlParserCtxtPtr, const char *, int, int); + void (*xmlFreeParserCtxt)(xmlParserCtxtPtr); + xmlNodePtr (*xmlDocGetRootElement)(xmlDocPtr); + void (*xmlFreeDoc)(xmlDocPtr); + char *(*xmlNodeListGetString)(xmlDocPtr, xmlNodePtr, int); + char *(*xmlGetProp)(xmlNodePtr, const char *); + int (*xmlKeepBlanksDefault)(int); + int (*xmlSubstituteEntitiesDefault)(int); +#ifdef WIRESHARK_XML_DO_VALIDITY_CHECKING + int *xmlDoValidityCheckingDefaultValue; +#endif +} XML_STUB; + +XML_EXTERN XML_STUB XmlStub; +XML_EXTERN int XmlStubInitialized; + +#ifdef _WIN32 +/* We're in windows, use the windows filename */ +#define XML_LIBRARY "libxml2.dll" +#else +#define XML_LIBRARY "libxml2.so" +#endif + +/* + * This needs to be called before the library is used. It + * returns zero on success. Any non-zero return means that + * either dynamic libraries are not supported, or that libxml + * is not installed on the current system. (Or it's not in + * the LD path) + */ +int loadLibXML(void); + + + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/file.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/file.h new file mode 100644 index 00000000..e7c4de6d --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/file.h @@ -0,0 +1,486 @@ +/* file.h + * Definitions for file structures and routines + * + * $Id: file.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __FILE_H__ +#define __FILE_H__ + +#include "packet-range.h" +#include "wiretap/wtap.h" +#include +#include "print.h" +#include +#include + +#include "cfile.h" + + +/** Return values from functions that only can succeed or fail. */ +typedef enum { + CF_OK, /**< operation succeeded */ + CF_ERROR /**< operation got an error (function may provide err with details) */ +} cf_status_t; + +/** Return values from functions that read capture files. */ +typedef enum { + CF_READ_OK, /**< operation succeeded */ + CF_READ_ERROR, /**< operation got an error (function may provide err with details) */ + CF_READ_ABORTED /**< operation aborted by user */ +} cf_read_status_t; + +/** Return values from functions that print sets of packets. */ +typedef enum { + CF_PRINT_OK, /**< print operation succeeded */ + CF_PRINT_OPEN_ERROR, /**< print operation failed while opening printer */ + CF_PRINT_WRITE_ERROR /**< print operation failed while writing to the printer */ +} cf_print_status_t; + +typedef enum { + cf_cb_file_closing, + cf_cb_file_closed, + cf_cb_file_read_start, + cf_cb_file_read_finished, +#ifdef HAVE_LIBPCAP + cf_cb_live_capture_prepared, + cf_cb_live_capture_update_started, + cf_cb_live_capture_update_continue, + cf_cb_live_capture_update_finished, + cf_cb_live_capture_fixed_started, + cf_cb_live_capture_fixed_continue, + cf_cb_live_capture_fixed_finished, + cf_cb_live_capture_stopping, +#endif + cf_cb_packet_selected, + cf_cb_packet_unselected, + cf_cb_field_unselected, + cf_cb_file_safe_started, + cf_cb_file_safe_finished, + cf_cb_file_safe_reload_finished, + cf_cb_file_safe_failed +} cf_cbs; + +typedef void (*cf_callback_t) (gint event, gpointer data, gpointer user_data); + +extern void +cf_callback_invoke(int event, gpointer data); + +extern void +cf_callback_add(cf_callback_t func, gpointer user_data); + +extern void +cf_callback_remove(cf_callback_t func); + +/** + * Open a capture file. + * + * @param cf the capture file to be opened + * @param fname the filename to be opened + * @param is_tempfile is this a temporary file? + * @return one of cf_status_t + */ +cf_status_t cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err); + +/** + * Close a capture file. + * + * @param cf the capture file to be closed + */ +void cf_close(capture_file *cf); + +/** + * Reload a capture file. + * + * @param cf the capture file to be reloaded + */ +void cf_reload(capture_file *cf); + +/** + * Read all packets of a capture file into the internal structures. + * + * @param cf the capture file to be read + * @return one of cf_read_status_t + */ +cf_read_status_t cf_read(capture_file *cf); + +/** + * Start reading from the end of a capture file. + * This is used in "Update list of packets in Real-Time". + * + * @param cf the capture file to be read from + * @param fname the filename to be read from + * @param is_tempfile is this a temporary file? + * @param err the error code, if an error had occured + * @return one of cf_status_t + */ +cf_status_t cf_start_tail(capture_file *cf, const char *fname, gboolean is_tempfile, int *err); + +/** + * Read packets from the "end" of a capture file. + * + * @param cf the capture file to be read from + * @param to_read the number of packets to read + * @param err the error code, if an error had occured + * @return one of cf_read_status_t + */ +cf_read_status_t cf_continue_tail(capture_file *cf, volatile int to_read, int *err); + +/** + * Finish reading from "end" of a capture file. + * + * @param cf the capture file to be read from + * @param err the error code, if an error had occured + * @return one of cf_read_status_t + */ +cf_read_status_t cf_finish_tail(capture_file *cf, int *err); + +/** + * Determine whether this capture file (or a range of it) can be saved + * (except by copying the raw file data). + * + * @param cf the capture file to check + * @return TRUE if it can be saved, FALSE if it can't + */ +gboolean cf_can_save_as(capture_file *cf); + +/** + * Save a capture file (or a range of it). + * + * @param cf the capture file to save to + * @param fname the filename to save to + * @param range the range of packets to save + * @param save_format the format of the file to save (libpcap, ...) + * @param compressed wether to gzip compress the file + * @return one of cf_status_t + */ +cf_status_t cf_save(capture_file * cf, const char *fname, packet_range_t *range, guint save_format, gboolean compressed); + +/** + * Get a displayable name of the capture file. + * + * @param cf the capture file + * @return the displayable name (don't have to be g_free'd) + */ +const gchar *cf_get_display_name(capture_file *cf); + +/** + * Get the number of packets in the capture file. + * + * @param cf the capture file + * @return the number of packets in the capture file + */ +int cf_get_packet_count(capture_file *cf); + +/** + * Set the number of packets in the capture file. + * + * @param cf the capture file + * @param the number of packets in the capture file + */ +void cf_set_packet_count(capture_file *cf, int packet_count); + +/** + * Is this capture file a temporary file? + * + * @param cf the capture file + * @return TRUE if it's a temporary file, FALSE otherwise + */ +gboolean cf_is_tempfile(capture_file *cf); + +/** + * Set flag, that this file is a tempfile. + */ +void cf_set_tempfile(capture_file *cf, gboolean is_tempfile); + +/** + * Set flag, if the number of packet drops while capturing are known or not. + * + * @param cf the capture file + * @param drops_known TRUE if the number of packet drops are known, FALSE otherwise + */ +void cf_set_drops_known(capture_file *cf, gboolean drops_known); + +/** + * Set the number of packet drops while capturing. + * + * @param cf the capture file + * @param drops the number of packet drops occured while capturing + */ +void cf_set_drops(capture_file *cf, guint32 drops); + +/** + * Get flag state, if the number of packet drops while capturing are known or not. + * + * @param cf the capture file + * @return TRUE if the number of packet drops are known, FALSE otherwise + */ +gboolean cf_get_drops_known(capture_file *cf); + +/** + * Get the number of packet drops while capturing. + * + * @param cf the capture file + * @return the number of packet drops occured while capturing + */ +guint32 cf_get_drops(capture_file *cf); + +/** + * Set the read filter. + * @todo this shouldn't be required, remove it somehow + * + * @param cf the capture file + * @param rfcode the readfilter + */ +void cf_set_rfcode(capture_file *cf, dfilter_t *rfcode); + +/** + * "Display Filter" packets in the capture file. + * + * @param cf the capture file + * @param dfilter the display filter + * @param force TRUE if do in any case, FALSE only if dfilter changed + * @return one of cf_status_t + */ +cf_status_t cf_filter_packets(capture_file *cf, gchar *dfilter, gboolean force); + +/** + * At least one "Refence Time" flag has changed, rescan all packets. + * + * @param cf the capture file + */ +void cf_reftime_packets(capture_file *cf); + +/** + * At least one "Refence Time" flag has changed, rescan all packets. + * + * @param cf the capture file + */ +void cf_colorize_packets(capture_file *cf); + +/** + * "Something" has changed, rescan all packets. + * + * @param cf the capture file + */ +void cf_redissect_packets(capture_file *cf); + +/** + * Rescan all packets and just run taps - don't reconstruct the display. + * + * @param cf the capture file + * @param do_columns TRUE if columns are to be generated, FALSE otherwise + * @return one of cf_read_status_t + */ +cf_read_status_t cf_retap_packets(capture_file *cf, gboolean do_columns); + +/** + * The time format has changed, rescan all packets. + * + * @param cf the capture file + */ +void cf_change_time_formats(capture_file *cf); + +/** + * Print the capture file. + * + * @param cf the capture file + * @param print_args the arguments what and how to print + * @return one of cf_print_status_t + */ +cf_print_status_t cf_print_packets(capture_file *cf, print_args_t *print_args); + +/** + * Print (export) the capture file into PDML format. + * + * @param cf the capture file + * @param print_args the arguments what and how to export + * @return one of cf_print_status_t + */ +cf_print_status_t cf_write_pdml_packets(capture_file *cf, print_args_t *print_args); + +/** + * Print (export) the capture file into PSML format. + * + * @param cf the capture file + * @param print_args the arguments what and how to export + * @return one of cf_print_status_t + */ +cf_print_status_t cf_write_psml_packets(capture_file *cf, print_args_t *print_args); + +/** + * Print (export) the capture file into CSV format. + * + * @param cf the capture file + * @param print_args the arguments what and how to export + * @return one of cf_print_status_t + */ +cf_print_status_t cf_write_csv_packets(capture_file *cf, print_args_t *print_args); + +/** + * Print (export) the capture file into C Arrays format. + * + * @param cf the capture file + * @param print_args the arguments what and how to export + * @return one of cf_print_status_t + */ +cf_print_status_t cf_write_carrays_packets(capture_file *cf, print_args_t *print_args); + +/** + * Find Packet in protocol tree. + * + * @param cf the capture file + * @param string the string to find + * @return TRUE if a packet was found, FALSE otherwise + */ +gboolean cf_find_packet_protocol_tree(capture_file *cf, const char *string); + +/** + * Find Packet in summary line. + * + * @param cf the capture file + * @param string the string to find + * @return TRUE if a packet was found, FALSE otherwise + */ +gboolean cf_find_packet_summary_line(capture_file *cf, const char *string); + +/** + * Find Packet in packet data. + * + * @param cf the capture file + * @param string the string to find + * @param string_size the size of the string to find + * @return TRUE if a packet was found, FALSE otherwise + */ +gboolean cf_find_packet_data(capture_file *cf, const guint8 *string, + size_t string_size); + +/** + * Find Packet by display filter. + * + * @param cf the capture file + * @param sfcode the display filter to find a packet for + * @return TRUE if a packet was found, FALSE otherwise + */ +gboolean cf_find_packet_dfilter(capture_file *cf, dfilter_t *sfcode); + +/** + * GoTo Packet in first row. + * + * @param cf the capture file + * @return TRUE if the first row exists, FALSE otherwise + */ +gboolean cf_goto_top_frame(capture_file *cf); + +/** + * GoTo Packet in last row. + * + * @param cf the capture file + * @return TRUE if last row exists, FALSE otherwise + */ +gboolean cf_goto_bottom_frame(capture_file *cf); + +/** + * GoTo Packet with the given row. + * + * @param cf the capture file + * @param row the row to go to + * @return TRUE if this row exists, FALSE otherwise + */ +gboolean cf_goto_frame(capture_file *cf, guint row); + +/** + * Go to frame specified by currently selected protocol tree field. + * (Go To Corresponding Packet) + * @todo this is ugly and should be improved! + * + * @param cf the capture file + * @return TRUE if this packet exists, FALSE otherwise + */ +gboolean cf_goto_framenum(capture_file *cf); + +/** + * Select the packet in the given row. + * + * @param cf the capture file + * @param row the row to select + */ +void cf_select_packet(capture_file *cf, int row); + +/** + * Unselect all packets, if any. + * + * @param cf the capture file + * @param row the row to select + */ +void cf_unselect_packet(capture_file *cf); + +/** + * Unselect all protocol tree fields, if any. + * + * @param cf the capture file + * @param row the row to select + */ +void cf_unselect_field(capture_file *cf); + +/** + * Mark a particular frame in a particular capture. + * + * @param cf the capture file + * @param frame the frame to be marked + */ +void cf_mark_frame(capture_file *cf, frame_data *frame); + +/** + * Unmark a particular frame in a particular capture. + * + * @param cf the capture file + * @param frame the frame to be unmarked + */ +void cf_unmark_frame(capture_file *cf, frame_data *frame); + +/** + * Convert error number and info to a complete message. + * + * @param err the error number + * @param err_info the additional info about this error (e.g. filename) + * @return statically allocated error message + */ +char *cf_read_error_message(int err, const gchar *err_info); + +/** + * Merge two (or more) capture files into one. + * @todo is this the right place for this function? It doesn't have to do a lot with capture_file. + * + * @param out_filename pointer to output filename; if output filename is + * NULL, a temporary file name is generated and *out_filename is set + * to point to the generated file name + * @param in_file_count the number of input files to merge + * @param in_filnames array of input filenames + * @param file_type the output filetype + * @param do_append FALSE to merge chronologically, TRUE simply append + * @return one of cf_status_t + */ +cf_status_t +cf_merge_files(char **out_filename, int in_file_count, + char *const *in_filenames, int file_type, gboolean do_append); + +#endif /* file.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/fileset.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/fileset.h new file mode 100644 index 00000000..47015f99 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/fileset.h @@ -0,0 +1,75 @@ +/* fileset.h + * Definitions for routines for file sets. + * + * $Id: fileset.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __FILESET_H__ +#define __FILESET_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +typedef struct _fileset_entry { + const char *fullname; /* File name with path (g_strdup'ed) */ + const char *name; /* File name without path (g_strdup'ed) */ + time_t ctime; /* create time */ + time_t mtime; /* last modified time */ + long size; /* size of file in bytes */ + gboolean current; /* is this the currently loaded file? */ +} fileset_entry; + + +/* helper: is this a probable file of a file set (does the naming pattern match)? */ +extern gboolean fileset_filename_match_pattern(const char *fname); + +/* helper: test, if both files could be in the same file set */ +extern gboolean fileset_is_file_in_set(const char *fname1, const char *fname2); + +extern void fileset_add_dir(const char *fname); + +extern void fileset_delete(void); + +/* get the current directory name */ +extern const char *fileset_get_dirname(void); + +extern fileset_entry *fileset_get_next(void); +extern fileset_entry *fileset_get_previous(void); + + + +/* this file is a part of the current file set */ +extern void fileset_dlg_add_file(fileset_entry *entry); + +extern void fileset_file_opened(const char *fname); + +extern void fileset_file_closed(void); + +extern void fileset_update_dlg(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __FILESET_H__ */ + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/filters.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/filters.h new file mode 100644 index 00000000..0ca489b2 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/filters.h @@ -0,0 +1,87 @@ +/* filters.h + * Declarations of routines for reading and writing the filters file. + * + * $Id: filters.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * Filter lists. + */ +typedef enum { + CFILTER_LIST, /* capture filter list - saved */ + DFILTER_LIST, /* display filter list - saved */ + CFILTER_EDITED_LIST, /* capture filter list - currently edited */ + DFILTER_EDITED_LIST /* display filter list - currently edited */ +} filter_list_type_t; + +/* + * Item in a list of filters. + */ +typedef struct { + char *name; /* filter name */ + char *strval; /* filter expression */ +} filter_def; + +/* + * Read in a list of filters. + * + * On success, "*pref_path_return" is set to NULL. + * On error, "*pref_path_return" is set to point to the pathname of + * the file we tried to read - it should be freed by our caller - + * and "*errno_return" is set to the error. + */ +void read_filter_list(filter_list_type_t list_type, char **pref_path_return, + int *errno_return); + +/* + * Get a pointer to the first entry in a filter list. + */ +GList *get_filter_list_first(filter_list_type_t list); + +/* + * Add a new filter to the end of a list. + * Returns a pointer to the newly-added entry. + */ +GList *add_to_filter_list(filter_list_type_t list, const char *name, + const char *expression); + +/* + * Remove a filter from a list. + */ +void remove_from_filter_list(filter_list_type_t list, GList *fl_entry); + +/* + * Write out a list of filters. + * + * On success, "*pref_path_return" is set to NULL. + * On error, "*pref_path_return" is set to point to the pathname of + * the file we tried to read - it should be freed by our caller - + * and "*errno_return" is set to the error. + */ +void save_filter_list(filter_list_type_t list_type, char **pref_path_return, + int *errno_return); + +/* + * Clone the filter list so it can be edited. + */ +void copy_filter_list(filter_list_type_t dest_type, filter_list_type_t src_type); + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/g711.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/g711.h new file mode 100644 index 00000000..b55bd13c --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/g711.h @@ -0,0 +1,30 @@ +/* + * g711.h + * + * Definitions for routines for u-law, A-law and linear PCM conversions + * + * $Id: g711.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +unsigned char linear2alaw( int ); +int alaw2linear( unsigned char ); +unsigned char linear2ulaw( int ); +int ulaw2linear( unsigned char ); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/getopt.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/getopt.h new file mode 100644 index 00000000..45541f5a --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/getopt.h @@ -0,0 +1,129 @@ +/* Declarations for getopt. + Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef _GETOPT_H +#define _GETOPT_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; + +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ +#if __STDC__ + const char *name; +#else + char *name; +#endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +#if __STDC__ +#if defined(__GNU_LIBRARY__) +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int argc, char *const *argv, const char *shortopts); +#else /* not __GNU_LIBRARY__ */ +extern int getopt (); +#endif /* not __GNU_LIBRARY__ */ +extern int getopt_long (int argc, char *const *argv, const char *shortopts, + const struct option *longopts, int *longind); +extern int getopt_long_only (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind, + int long_only); +#else /* not __STDC__ */ +extern int getopt (); +extern int getopt_long (); +extern int getopt_long_only (); + +extern int _getopt_internal (); +#endif /* not __STDC__ */ + +#ifdef __cplusplus +} +#endif + +#endif /* _GETOPT_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/globals.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/globals.h new file mode 100644 index 00000000..ff6ac7f3 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/globals.h @@ -0,0 +1,37 @@ +/* globals.h + * Global defines, etc. + * + * $Id: globals.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __GLOBALS_H__ +#define __GLOBALS_H__ + +#include "file.h" +#include + +extern capture_file cfile; +#ifdef HAVE_LIBPCAP +/** @todo move this to the gtk dir */ +extern gboolean auto_scroll_live; +#endif + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/inet_v6defs.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/inet_v6defs.h new file mode 100644 index 00000000..22f82abc --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/inet_v6defs.h @@ -0,0 +1,54 @@ +/* inet_v6defs.h + * + * $Id: inet_v6defs.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __INET_V6DEFS_H__ +#define __INET_V6DEFS_H__ + +/* + * Versions of "inet_pton()" and "inet_ntop()", for the benefit of OSes that + * don't have it. + */ +extern int inet_pton(int af, const char *src, void *dst); +#ifndef HAVE_INET_NTOP_PROTO +extern const char *inet_ntop(int af, const void *src, char *dst, + size_t size); +#endif + +/* + * Those OSes may also not have AF_INET6, so declare it here if it's not + * already declared, so that we can pass it to "inet_ntop()" and "inet_pton()". + */ +#ifndef AF_INET6 +#define AF_INET6 127 /* pick a value unlikely to duplicate an existing AF_ value */ +#endif + +/* + * And if __P isn't defined, define it here, so we can use it in + * "inet_ntop.c" and "inet_pton.c" (rather than having to change them + * not to use it). + */ +#ifndef __P +#define __P(args) args +#endif + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/isprint.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/isprint.h new file mode 100644 index 00000000..8a2d0a25 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/isprint.h @@ -0,0 +1,46 @@ +/* isprint.h + * Temporary redefinition of "isprint()" to cope with GTK+ 1.3 and + * later using UTF-8 strings + * + * $Id: isprint.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ISPRINT_H__ +#define __ISPRINT_H__ + +#if GLIB_MAJOR_VERSION >= 2 +/* + * XXX - "isprint()" can return "true" for non-ASCII characters, but + * those don't work with GTK+ 1.3 or later, as they take UTF-8 strings + * as input. Until we fix up Wireshark to properly handle non-ASCII + * characters in all output (both GUI displays and text printouts) + * in those versions of GTK+, we work around the problem by escaping + * all characters that aren't printable ASCII. + * + * We don't know what version of GTK+ we're using, as dissectors don't + * use any GTK+ stuff; we use GLib as a proxy for that, with GLib 2.x + * implying GTK+ 1.3 or later (we don't support GLib 1.3[.x]). + */ +#undef isprint +#define isprint(c) (c >= 0x20 && c < 0x7f) +#endif + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/log.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/log.h new file mode 100644 index 00000000..569c4c20 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/log.h @@ -0,0 +1,42 @@ +/* log.h + * log output definitions + * + * $Id: log.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __LOG_H__ +#define __LOG_H__ + +/* capture domain (except for capture child, see below) */ +#define LOG_DOMAIN_CAPTURE "Capture" + +/* capture child domain (the capture child might also contain file domain messages!) */ +#define LOG_DOMAIN_CAPTURE_CHILD "CaptureChild" + +/* main domain */ +#define LOG_DOMAIN_MAIN "Main" + +/* enable very verbose capture log debug output */ +/* (might slightly degrade performance) */ +/*#define LOG_CAPTURE_VERBOSE*/ + + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/main_window.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/main_window.h new file mode 100644 index 00000000..eb196b10 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/main_window.h @@ -0,0 +1,41 @@ +/* main_window.h + * Definitions for main window routines with toolkit-independent APIs but + * toolkit-dependent implementations. + * + * $Id: main_window.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __MAIN_WINDOW_H__ +#define __MAIN_WINDOW_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** Tell the main window that we have a capture file (or not) */ +extern void +main_set_for_capture_file(gboolean have_capture_file_in); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __MAIN_WINDOW_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/menu.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/menu.h new file mode 100644 index 00000000..99cf2a90 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/menu.h @@ -0,0 +1,64 @@ +/* menu.h + * Definitions for menu routines with toolkit-independent APIs but + * toolkit-dependent implementations. + * + * $Id: menu.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __MENU_H__ +#define __MENU_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* Add a new recent capture filename to the "Recent Files" submenu + (duplicates will be ignored) */ +void add_menu_recent_capture_file(gchar *file); + +/* Routines to enable or disable sets of menu items. */ + +/* Enable or disable menu items based on whether you have a capture file + you've finished reading and, if you have one, whether it's been saved + and whether it could be saved except by copying the raw packet data. */ +void set_menus_for_capture_file(capture_file *); + +/* Enable or disable menu items based on whether there's a capture in + progress. */ +void set_menus_for_capture_in_progress(gboolean); + +/* Enable or disable menu items based on whether you have some captured + packets. */ +void set_menus_for_captured_packets(gboolean); + +/* Enable or disable menu items based on whether a packet is selected. */ +void set_menus_for_selected_packet(capture_file *cf); + +/* Enable or disable menu items based on whether a tree row is selected + and and on whether a "Match Selected" can be done. */ +void set_menus_for_selected_tree_row(capture_file *cf); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __MENU_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/merge.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/merge.h new file mode 100644 index 00000000..22620aae --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/merge.h @@ -0,0 +1,125 @@ +/* merge.h + * Definitions for routines for merging files. + * + * $Id: merge.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __MERGE_H__ +#define __MERGE_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef enum { + PACKET_PRESENT, + PACKET_NOT_PRESENT, + AT_EOF, + GOT_ERROR +} in_file_state_e; + +/** + * Structures to manage our input files. + */ +typedef struct merge_in_file_s { + const char *filename; + wtap *wth; + gint64 data_offset; + in_file_state_e state; + gint64 size; /* file size */ +} merge_in_file_t; + +/** Open a number of input files to merge. + * + * @param in_file_count number of entries in in_file_names and in_files + * @param in_file_names filenames of the input files + * @param in_files input file array to be filled (>= sizeof(merge_in_file_t) * in_file_count) + * @param err wiretap error, if failed + * @param err_info wiretap error string, if failed + * @param err_fileno file on which open failed, if failed + * @return TRUE if all files could be opened, FALSE otherwise + */ +extern gboolean +merge_open_in_files(int in_file_count, char *const *in_file_names, + merge_in_file_t **in_files, int *err, gchar **err_info, + int *err_fileno); + +/** Close the input files again. + * + * @param in_file_count number of entries in in_files + * @param in_files input file array to be closed + */ +extern void +merge_close_in_files(int in_file_count, merge_in_file_t in_files[]); + +/** Try to get the frame type from the input files. + * + * @param in_file_count number of entries in in_files + * @param in_files input file array + * @return the frame type + */ +extern int +merge_select_frame_type(int in_file_count, merge_in_file_t in_files[]); + +/** Try to get the snapshot length from the input files. + * + * @param in_file_count number of entries in in_files + * @param in_files input file array + * @return the snapshot length + */ +extern int +merge_max_snapshot_length(int in_file_count, merge_in_file_t in_files[]); + +/** Read the next packet, in chronological order, from the set of files to + * be merged. + * + * @param in_file_count number of entries in in_files + * @param in_files input file array + * @param err wiretap error, if failed + * @param err_info wiretap error string, if failed + * @return pointer to wtap for file from which that packet came, or NULL on + * error or EOF + */ +extern wtap * +merge_read_packet(int in_file_count, merge_in_file_t in_files[], int *err, + gchar **err_info); + + +/** Read the next packet, in file sequence order, from the set of files + * to be merged. + * + * @param in_file_count number of entries in in_files + * @param in_files input file array + * @param err wiretap error, if failed + * @param err_info wiretap error string, if failed + * @return pointer to wtap for file from which that packet came, or NULL on + * error or EOF + */ +extern wtap * +merge_append_read_packet(int in_file_count, merge_in_file_t in_files[], + int *err, gchar **err_info); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __MERGE_H__ */ + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/mkstemp.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/mkstemp.h new file mode 100644 index 00000000..be2cae0f --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/mkstemp.h @@ -0,0 +1,24 @@ +/* Copyright (C) 1991, 1992, 1996, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + + +/* Generate a unique temporary file name from TEMPLATE. + The last six characters of TEMPLATE must be "XXXXXX"; + they are replaced with a string that makes the filename unique. + Returns a file descriptor open on the file for reading and writing. */ +int mkstemp (char *template); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/packet-range.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/packet-range.h new file mode 100644 index 00000000..64702d14 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/packet-range.h @@ -0,0 +1,101 @@ +/* packet-range.h + * Packet range routines (save, print, ...) + * + * $Id: packet-range.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Dick Gooris + * Ulf Lamping + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PACKET_RANGE_H__ +#define __PACKET_RANGE_H__ + +#include + +#include + +#include + +extern guint32 curr_selected_frame; + +typedef enum { + range_process_all, + range_process_selected, + range_process_marked, + range_process_marked_range, + range_process_user_range +} packet_range_e; + +typedef struct packet_range_tag { + /* values coming from the UI */ + packet_range_e process; /* which range to process */ + gboolean process_filtered; /* captured or filtered packets */ + + /* user specified range(s) and, if null, error status */ + range_t *user_range; + convert_ret_t user_range_status; + + /* calculated values */ + guint32 selected_packet; /* the currently selected packet */ + + /* current packet counts (captured) */ + /* cfile.count */ /* packets in capture file */ + /* cfile.marked_count */ /* packets marked */ + guint32 mark_range_cnt; /* packets in marked range */ + guint32 user_range_cnt; /* packets in user specified range */ + + /* current packet counts (displayed) */ + guint32 displayed_cnt; + guint32 displayed_marked_cnt; + guint32 displayed_mark_range_cnt; + guint32 displayed_user_range_cnt; + + /* "enumeration" values */ + gboolean marked_range_active; /* marked range is currently processed */ + guint32 marked_range_left; /* marked range packets left to do */ + gboolean selected_done; /* selected packet already processed */ +} packet_range_t; + +typedef enum { + range_process_this, /* process this packet */ + range_process_next, /* skip this packet, process next */ + range_processing_finished /* stop processing, required packets done */ +} range_process_e; + +/* init the range structure */ +extern void packet_range_init(packet_range_t *range); + +/* check whether the packet range is OK */ +extern convert_ret_t packet_range_check(packet_range_t *range); + +/* init the processing run */ +extern void packet_range_process_init(packet_range_t *range); + +/* do we have to process all packets? */ +extern gboolean packet_range_process_all(packet_range_t *range); + +/* do we have to process this packet? */ +extern range_process_e packet_range_process_packet(packet_range_t *range, frame_data *fdata); + +/* convert user given string to the internal user specified range representation */ +extern void packet_range_convert_str(packet_range_t *range, const gchar *es); + +#endif /* __PACKET_RANGE_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/pcapio.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/pcapio.h new file mode 100644 index 00000000..a675ce30 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/pcapio.h @@ -0,0 +1,44 @@ +/* pcapio.h + * Declarations of our own routins for writing libpcap files. + * + * $Id: pcapio.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * Derived from code in the Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* Returns a FILE * to write to on success, NULL on failure; sets "*err" to + an error code, or 0 for a short write, on failure */ +extern FILE * +libpcap_fdopen(int fd, int linktype, int snaplen, long *bytes_written, + int *err); + +/* Write a record for a packet to a dump file. + Returns TRUE on success, FALSE on failure. */ +extern gboolean +libpcap_write_packet(FILE *fp, const struct pcap_pkthdr *phdr, const u_char *pd, + long *bytes_written, int *err); + +extern gboolean +libpcap_dump_flush(FILE *pd, int *err); + +extern gboolean +libpcap_dump_close(FILE *pd, int *err); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/print.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/print.h new file mode 100644 index 00000000..a337dffc --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/print.h @@ -0,0 +1,148 @@ +/* print.h + * Definitions for printing packet analysis trees. + * + * $Id: print.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Gilbert Ramirez + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PRINT_H__ +#define __PRINT_H__ + +#include + +#include "packet-range.h" + +/* + * Print stream code; this provides a "print stream" class with subclasses + * of various sorts. Additional subclasses might be implemented elsewhere. + */ +struct print_stream; + +typedef struct print_stream_ops { + gboolean (*print_preamble)(struct print_stream *self, gchar *filename); + gboolean (*print_line)(struct print_stream *self, int indent, + const char *line); + gboolean (*print_bookmark)(struct print_stream *self, + const gchar *name, const gchar *title); + gboolean (*new_page)(struct print_stream *self); + gboolean (*print_finale)(struct print_stream *self); + gboolean (*destroy)(struct print_stream *self); +} print_stream_ops_t; + +typedef struct print_stream { + const print_stream_ops_t *ops; + void *data; +} print_stream_t; + +extern print_stream_t *print_stream_text_new(int to_file, const char *dest); +extern print_stream_t *print_stream_text_stdio_new(FILE *fh); +extern print_stream_t *print_stream_ps_new(int to_file, const char *dest); +extern print_stream_t *print_stream_ps_stdio_new(FILE *fh); + +extern gboolean print_preamble(print_stream_t *self, gchar *filename); +extern gboolean print_line(print_stream_t *self, int indent, const char *line); +extern gboolean print_bookmark(print_stream_t *self, const gchar *name, + const gchar *title); +extern gboolean new_page(print_stream_t *self); +extern gboolean print_finale(print_stream_t *self); +extern gboolean destroy_print_stream(print_stream_t *self); + +/* print output format */ +typedef enum { + PR_FMT_TEXT, /* plain text */ + PR_FMT_PS /* postscript */ +} print_format_e; + +/* print_range, enum which frames should be printed */ +typedef enum { + print_range_selected_only, /* selected frame(s) only (currently only one) */ + print_range_marked_only, /* marked frames only */ + print_range_all_displayed, /* all frames currently displayed */ + print_range_all_captured /* all frames in capture */ +} print_range_e; + +/* print_dissections, enum how the dissections should be printed */ +typedef enum { + print_dissections_none, /* no dissections at all */ + print_dissections_collapsed, /* no dissection details */ + print_dissections_as_displayed, /* details as displayed */ + print_dissections_expanded /* all dissection details */ +} print_dissections_e; + +typedef struct { + print_stream_t *stream; /* the stream to which we're printing */ + print_format_e format; /* plain text or PostScript */ + gboolean to_file; /* TRUE if we're printing to a file */ + char *file; /* file output pathname */ + char *cmd; /* print command string (not win32) */ + packet_range_t range; + + gboolean print_summary; /* TRUE if we should just print summary; + FALSE if we should print protocol tree. */ + print_dissections_e print_dissections; + gboolean print_hex; /* TRUE if we should also print hex data; + FALSE if we should print only if not dissected. */ + gboolean print_formfeed; /* TRUE if a formfeed should be printed + before each new packet */ +} print_args_t; + +/* + * Print user selected list of fields + */ +struct _output_fields; +typedef struct _output_fields output_fields_t; + +extern output_fields_t* output_fields_new(void); +extern void output_fields_free(output_fields_t* info); +extern void output_fields_add(output_fields_t* info, const gchar* field); +extern gsize output_fields_num_fields(output_fields_t* info); +extern gboolean output_fields_set_option(output_fields_t* info, gchar* option); +extern void output_fields_list_options(FILE *fh); +/* + * Higher-level packet-printing code. + */ + +extern gboolean proto_tree_print(print_args_t *print_args, epan_dissect_t *edt, + print_stream_t *stream); +extern gboolean print_hex_data(print_stream_t *stream, epan_dissect_t *edt); + +extern void write_pdml_preamble(FILE *fh); +extern void proto_tree_write_pdml(epan_dissect_t *edt, FILE *fh); +extern void write_pdml_finale(FILE *fh); + +extern void write_psml_preamble(FILE *fh); +extern void proto_tree_write_psml(epan_dissect_t *edt, FILE *fh); +extern void write_psml_finale(FILE *fh); + +extern void write_csv_preamble(FILE *fh); +extern void proto_tree_write_csv(epan_dissect_t *edt, FILE *fh); +extern void write_csv_finale(FILE *fh); + +extern void write_carrays_preamble(FILE *fh); +extern void proto_tree_write_carrays(const guint8 *pd, guint32 len, guint32 num, FILE *fh); +extern void write_carrays_finale(FILE *fh); + +extern void write_fields_preamble(output_fields_t* fields, FILE *fh); +extern void proto_tree_write_fields(output_fields_t* fields, epan_dissect_t *edt, FILE *fh); +extern void write_fields_finale(output_fields_t* fields, FILE *fh); + +#endif /* print.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/progress_dlg.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/progress_dlg.h new file mode 100644 index 00000000..0303230e --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/progress_dlg.h @@ -0,0 +1,94 @@ +/* progress_dlg.h + * Definitions for progress dialog box routines + * + * $Id: progress_dlg.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PROGRESS_DLG_H__ +#define __PROGRESS_DLG_H__ + +/** @file + * Progress (modal) dialog box routines. + * @ingroup dialog_group + */ + +/** Progress dialog data. */ +struct progdlg; + +/** Progress dialog data. */ +typedef struct progdlg progdlg_t; + +/** + * Create and pop up the progress dialog. Allocates a "progdlg_t" + * and initialize it to contain all information the implementation + * needs in order to manipulate the dialog, and return a pointer to + * it. + * + * @param task_title the task to do, e.g. "Loading" + * @param item_title the item to do, e.g. "capture.cap" + * @param terminate_is_stop TRUE if the operation can't be cancelled, just + * stopped (i.e., it has a "Stop" button and clicking it doesn't undo + * anything already done), FALSE if it can + * @param stop_flag a pointer to a Boolean variable that will be + * set to TRUE if the user hits that button + * @return the newly created progress dialog + */ +progdlg_t *create_progress_dlg(const gchar *task_title, const gchar *item_title, + gboolean terminate_is_stop, gboolean *stop_flag); + +/** + * Create a progress dialog, but only if it's not likely to disappear + * immediately. This can be disconcerting for the user. + * + * @param task_title the task to do, e.g. "Loading" + * @param item_title the item to do, e.g. "capture.cap" + * @param terminate_is_stop TRUE if the operation can't be cancelled, just + * stopped (i.e., it has a "Stop" button and clicking it doesn't undo + * anything already done), FALSE if it can + * @param stop_flag a pointer to a Boolean variable that will be + * set to TRUE if the user hits that button + * @param start_time a pointer to a GTimeVal structure which holds + * the time at which the caller started to process the data + * @param progress the current progress (0..1) + * @return the newly created progress dialog + */ +progdlg_t * +delayed_create_progress_dlg(const gchar *task_title, const gchar *item_title, + gboolean terminate_is_stop, gboolean *stop_flag, + const GTimeVal *start_time, gfloat progress); + +/** + * Update the progress information of the progress dialog box. + * + * @param dlg the progress dialog from create_progress_dlg() + * @param percentage the current percentage value (0..1) + * @param status the new status string to show, e.g. "3000KB of 6000KB" + */ +void update_progress_dlg(progdlg_t *dlg, gfloat percentage, const gchar *status); + +/** + * Destroy the progress bar. + * + * @param dlg the progress dialog from create_progress_dlg() + */ +void destroy_progress_dlg(progdlg_t *dlg); + +#endif /* __PROGRESS_DLG_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/proto_hier_stats.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/proto_hier_stats.h new file mode 100644 index 00000000..10fb1e39 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/proto_hier_stats.h @@ -0,0 +1,51 @@ +/* proto_hier_stats.h + * + * $Id: proto_hier_stats.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef PROTO_HIER_STATS_H +#define PROTO_HIER_STATS_H + +#include + +typedef struct { + header_field_info *hfinfo; + guint num_pkts_total; + guint num_pkts_last; + guint num_bytes_total; + guint num_bytes_last; +} ph_stats_node_t; + + +typedef struct { + guint tot_packets; + guint tot_bytes; + GNode *stats_tree; + double first_time; /* seconds (msec resolution) of first packet */ + double last_time; /* seconds (msec resolution) of last packet */ +} ph_stats_t; + + +ph_stats_t* ph_stats_new(void); + +void ph_stats_free(ph_stats_t *ps); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ps.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ps.h new file mode 100644 index 00000000..ceafdff6 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ps.h @@ -0,0 +1,35 @@ +/* ps.h + * Definitions for generating PostScript(R) packet output. + * + * $Id: ps.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Gilbert Ramirez + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PS_H__ +#define __PS_H__ + +/* Functions in ps.c; automatically generated by rdps */ + +void print_ps_preamble(FILE *); +void print_ps_finale(FILE *); + +#endif /* ps.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/register.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/register.h new file mode 100644 index 00000000..2b8906ea --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/register.h @@ -0,0 +1,48 @@ +/* register.h + * Definitions for protocol registration + * + * $Id: register.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __REGISTER_H__ +#define __REGISTER_H__ + +#include + +typedef enum { + RA_NONE, /* for initialization */ + RA_DISSECTORS, /* Initializing dissectors */ + RA_LISTENERS, /* Tap listeners */ + RA_REGISTER, /* register */ + RA_PLUGIN_REGISTER, /* plugin register */ + RA_HANDOFF, /* handoff */ + RA_PLUGIN_HANDOFF, /* plugin handoff */ + RA_PREFERENCES, /* module preferences */ + RA_CONFIGURATION /* configuration files */ +} register_action_e; + +typedef void (*register_cb)(register_action_e action, const char *message, gpointer client_data); + +extern void register_all_protocols(register_cb cb, gpointer client_data); +extern void register_all_protocol_handoffs(register_cb cb, gpointer client_data); +extern void register_all_tap_listeners(void); +extern gulong register_count(void); +#endif /* __REGISTER_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ringbuffer.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ringbuffer.h new file mode 100644 index 00000000..85178edc --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ringbuffer.h @@ -0,0 +1,53 @@ +/* ringbuffer.h + * Definitions for capture ringbuffer files + * + * $Id: ringbuffer.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __RINGBUFFER_H__ +#define __RINGBUFFER_H__ + +#ifdef HAVE_LIBPCAP + +#include +#include "file.h" +#include "wiretap/wtap.h" + +#define RINGBUFFER_UNLIMITED_FILES 0 +/* minimum number of ringbuffer files */ +#define RINGBUFFER_MIN_NUM_FILES 0 +/* maximum number of ringbuffer files */ +/* (only to avoid crashes on very large numbers) */ +#define RINGBUFFER_MAX_NUM_FILES 10000 + +int ringbuf_init(const char *capture_name, guint num_files); +const gchar *ringbuf_current_filename(void); +FILE *ringbuf_init_libpcap_fdopen(int linktype, int snaplen, + long *bytes_written, int *err); +gboolean ringbuf_switch_file(FILE **pdh, gchar **save_file, int *save_file_fd, + long *bytes_written, int *err); +gboolean ringbuf_libpcap_dump_close(gchar **save_file, int *err); +void ringbuf_free(void); +void ringbuf_error_cleanup(void); + +#endif /* HAVE_LIBPCAP */ + +#endif /* ringbuffer.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/simple_dialog.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/simple_dialog.h new file mode 100644 index 00000000..fcd35ece --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/simple_dialog.h @@ -0,0 +1,184 @@ +/* simple_dialog.h + * Definitions for alert box routines with toolkit-independent APIs but + * toolkit-dependent implementations. + * + * $Id: simple_dialog.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __DIALOG_H__ +#define __DIALOG_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** @file + * Simple dialog box. + * @ingroup dialog_group + */ + + +/** Dialog types. */ +typedef enum { + ESD_TYPE_INFO, /**< tells the user something they should know, but not requiring + any action; the only button should be "OK" */ + ESD_TYPE_WARN, /**< tells the user about a problem; the only button should be "OK" */ + ESD_TYPE_CONFIRMATION, /**< asks the user for confirmation; there should be more than + one button */ + ESD_TYPE_ERROR, /**< tells the user about a serious problem; the only button should be "OK" */ + ESD_TYPE_STOP /**< tells the user a stop action is in progress, there should be no button */ +} ESD_TYPE_E; + +/** display no buttons at all */ +#define ESD_BTN_NONE 0x00 +/** display an "Ok" button */ +#define ESD_BTN_OK 0x01 +/** display a "Cancel" button */ +#define ESD_BTN_CANCEL 0x02 +/** display a "Yes" button */ +#define ESD_BTN_YES 0x04 +/** display a "No" button */ +#define ESD_BTN_NO 0x08 +/** display a "Clear" button */ +#define ESD_BTN_CLEAR 0x10 +/** display a "Save" button */ +#define ESD_BTN_SAVE 0x20 +/** display a "Continue without Saving" button */ +#define ESD_BTN_DONT_SAVE 0x40 + +/** Standard button combination "Ok" + "Cancel". */ +#define ESD_BTNS_OK_CANCEL (ESD_BTN_OK|ESD_BTN_CANCEL) +/** Standard button combination "Yes" + "No". */ +#define ESD_BTNS_YES_NO (ESD_BTN_YES|ESD_BTN_NO) +/** Standard button combination "Yes" + "No" + "Cancel". */ +#define ESD_BTNS_YES_NO_CANCEL (ESD_BTN_YES|ESD_BTN_NO|ESD_BTN_CANCEL) +/** Standard button combination "No" + "Cancel" + "Save". */ +#define ESD_BTNS_SAVE_DONTSAVE_CANCEL (ESD_BTN_DONT_SAVE|ESD_BTN_CANCEL|ESD_BTN_SAVE) + +#if __GNUC__ >= 2 +/** Create and show a simple dialog. + * + * @param type type of dialog + * @param btn_mask the buttons to display + * @param msg_format printf like message format + * @param ... printf like parameters + * @return the newly created dialog + */ +extern gpointer simple_dialog(ESD_TYPE_E type, gint btn_mask, + const gchar *msg_format, ...) + __attribute__((format (printf, 3, 4))); +/** Create and show a simple dialog using a va_list. + * + * @param type type of dialog + * @param btn_mask the buttons to display + * @param msg_format printf like message format + * @param ap parameters + * @return the newly created dialog + */ +extern gpointer vsimple_dialog(ESD_TYPE_E type, gint btn_mask, + const gchar *msg_format, va_list ap); +#else +/** Create and show a simple dialog. + * + * @param type type of dialog + * @param btn_mask the buttons to display + * @param msg_format printf like message format + * @param ... printf like parameters + * @return the newly created dialog + */ +extern gpointer simple_dialog(ESD_TYPE_E type, gint btn_mask, + const gchar *msg_format, ...); +/** Create and show a simple dialog using a va_list. + * + * @param type type of dialog + * @param btn_mask the buttons to display + * @param msg_format printf like message format + * @param ap parameters + * @return the newly created dialog + */ +extern gpointer vsimple_dialog(ESD_TYPE_E type, gint btn_mask, + const gchar *msg_format, va_list ap); +#endif + +/** Callback function type for simple_dialog_set_cb() */ +typedef void (* simple_dialog_cb_t) (gpointer dialog, gint btn, gpointer data); + +/** Set the callback function for the dialog, called when a button was pressed. + * + * @param dialog the dialog from simple_dialog() + * @param callback_fct the callback function to set + * @param data data to be passed to the callback function + */ +extern void simple_dialog_set_cb(gpointer dialog, simple_dialog_cb_t callback_fct, gpointer data); + +/** Close the dialog, useful for "no button" dialogs. + * + * @param dialog the dialog to close from simple_dialog() + */ +extern void simple_dialog_close(gpointer dialog); + +/** Add a check button to the dialog (e.g. "Don't show this message again") + * + * @param dialog the dialog from simple_dialog() + * @param text the text to display + */ +extern void simple_dialog_check_set(gpointer dialog, gchar *text); + +/** Get the check buttons state. + * + * @param dialog the dialog from simple_dialog() + * @return current button state (TRUE is checked) + */ +extern gboolean simple_dialog_check_get(gpointer dialog); + +/** Surround the primary dialog message text by + * simple_dialog_primary_start() and simple_dialog_primary_end(). + * To highlight the first sentence (will take effect on GTK2 only). + */ +extern char *simple_dialog_primary_start(void); +/** Surround the primary dialog message text by + * simple_dialog_primary_start() and simple_dialog_primary_end(). + * To highlight the first sentence (will take effect on GTK2 only). + */ +extern char *simple_dialog_primary_end(void); + +/** Escape the message text, if it probably contains Pango escape sequences. + * For example html like tags starting with a <. + * + * @param msg the string to escape + * @return the escaped message text, must be freed with g_free() later + */ +extern char *simple_dialog_format_message(const char *msg); + +/** + * Display all queued messages. + * If a routine is called to display a dialog before there are any windows + * open, information to use to display the dialog is queued up. This + * routine should be called once there are windows open, so that the queued + * up dialogs are displayed on top of those windows. + */ +extern void display_queued_messages(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __DIALOG_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/stat_menu.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/stat_menu.h new file mode 100644 index 00000000..1a7bd7f1 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/stat_menu.h @@ -0,0 +1,64 @@ +/* stat_menu.h + * Menu definitions for use by stats + * + * $Id: stat_menu.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __STATMENU_H__ +#define __STATMENU_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** @file + * Add a new menu item for a stat. + */ + +/* + * XXX - defines stuff usable regardless of the GUI toolkit. Right now, + * that's only the menu group, which is used by tap_dfilter_dlg.h. + * + * XXX - stats should be able to register additional menu groups, although + * the question then would be "in what order should they appear in the menu?" + */ + +/** The menu group this stat should be registered in. */ +typedef enum { + REGISTER_STAT_GROUP_NONE, + REGISTER_STAT_GROUP_GENERIC, + REGISTER_STAT_GROUP_CONVERSATION_LIST, + REGISTER_STAT_GROUP_ENDPOINT_LIST, + REGISTER_STAT_GROUP_RESPONSE_TIME, + REGISTER_STAT_GROUP_TELEPHONY, + /* XXX - split into telephony and VoIP? */ + REGISTER_ANALYZE_GROUP_NONE, + REGISTER_ANALYZE_GROUP_CONVERSATION_FILTER +#ifdef HAVE_LUA_5_1 + ,REGISTER_TOOLS_GROUP_NONE +#endif +} register_stat_group_t; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __STATMENU_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/statusbar.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/statusbar.h new file mode 100644 index 00000000..cde19b35 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/statusbar.h @@ -0,0 +1,56 @@ +/* statusbar.h + * Definitions for status bar UI routines + * + * $Id: statusbar.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __STATUSBAR_H__ +#define __STATUSBAR_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * Push a message referring to file access onto the statusbar. + */ +void statusbar_push_file_msg(const gchar *msg); + +/* + * Pop a message referring to file access off the statusbar. + */ +void statusbar_pop_file_msg(void); + +/* + * Push a message referring to the currently-selected field onto the statusbar. + */ +void statusbar_push_field_msg(const gchar *msg); + +/* + * Pop a message referring to the currently-selected field off the statusbar. + */ +void statusbar_pop_field_msg(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __STATUSBAR_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/strerror.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/strerror.h new file mode 100644 index 00000000..2f509795 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/strerror.h @@ -0,0 +1,33 @@ +/* strerror.h + * + * $Id: strerror.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __STRERROR_H__ +#define __STRERROR_H__ + +/* + * Version of "strerror()", for the benefit of OSes that don't have it + * (e.g., SunOS 4.x). + */ +extern char *strerror(int); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/strptime.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/strptime.h new file mode 100644 index 00000000..0bfc58b1 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/strptime.h @@ -0,0 +1,32 @@ +/* strptime.h + * + * $Id: strptime.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __STRPTIME_H__ +#define __STRPTIME_H__ + +/* + * Version of "strptime()", for the benefit of OSes that don't have it. + */ +extern char *strptime(const char *, const char *, struct tm *); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/summary.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/summary.h new file mode 100644 index 00000000..1cc43328 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/summary.h @@ -0,0 +1,76 @@ +/* summary.h + * Definitions for capture file summary data + * + * $Id: summary.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __SUMMARY_H__ +#define __SUMMARY_H__ + +#ifdef HAVE_LIBPCAP +#include "capture.h" +#endif + +typedef struct _summary_tally { + guint64 bytes; /* total bytes */ + double start_time; /* seconds, with msec resolution */ + double stop_time; /* seconds, with msec resolution */ + double elapsed_time; /* seconds, with msec resolution, + includes time before first packet + and after last packet */ + int marked_count; /* number of marked packets */ + guint64 marked_bytes; /* total bytes in the marked packets */ + double marked_start; /* time in seconds, with msec resolution */ + double marked_stop; /* time in seconds, with msec resolution */ + int packet_count; /* total number of packets in trace */ + int filtered_count; /* number of filtered packets */ + guint64 filtered_bytes; /* total bytes in the filtered packets */ + double filtered_start; /* time in seconds, with msec resolution */ + double filtered_stop; /* time in seconds, with msec resolution */ + const char *filename; + gint64 file_length; /* file length in bytes */ + int encap_type; /* wiretap encapsulation type */ + gboolean has_snap; /* TRUE if maximum capture packet length is known */ + int snap; /* Maximum captured packet length */ + gboolean drops_known; /* TRUE if number of packet drops is known */ + guint64 drops; /* number of packet drops */ + const char *dfilter; /* display filter */ + + /* capture related, use summary_fill_in_capture() to get values */ + const char *cfilter; /* capture filter */ + const char *iface; /* interface name */ + const char *iface_descr;/* descriptive interface name */ +} summary_tally; + +extern void +summary_fill_in(capture_file *cf, summary_tally *st); + +#ifdef HAVE_LIBPCAP +extern void +summary_fill_in_capture(capture_options *capture_opts, summary_tally *st); +#endif + +#endif /* summary.h */ + + + + + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/svnversion.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/svnversion.h new file mode 100644 index 00000000..b3f53a6d --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/svnversion.h @@ -0,0 +1 @@ +/* #define SVNVERSION "" */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/sync_pipe.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/sync_pipe.h new file mode 100644 index 00000000..71d91ccd --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/sync_pipe.h @@ -0,0 +1,80 @@ +/* sync_pipe.h + * Low-level synchronization pipe routines for use by Wireshark/TShark + * and dumpcap + * + * $Id: sync_pipe.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +/** @file + * + * Low-level sync pipe interfaces. + */ + +#ifndef __SYNC_PIPE_H__ +#define __SYNC_PIPE_H__ + + +/* + * Maximum length of sync pipe message data. Must be < 2^24, as the + * message length is 3 bytes. + * XXX - this must be large enough to handle a Really Big Filter + * Expression, as the error message for an incorrect filter expression + * is a bit larger than the filter expression. + */ +#define SP_MAX_MSG_LEN 4096 + + +/* Size of buffer to hold decimal representation of + signed/unsigned 64-bit int */ +#define SP_DECISIZE 20 + +/* + * Indications sent out on the sync pipe (from child to parent). + */ +#define SP_FILE 'F' /* the name of the recently opened file */ +#define SP_ERROR_MSG 'E' /* error message */ +#define SP_BAD_FILTER 'B' /* error message for bad capture filter */ +#define SP_PACKET_COUNT 'P' /* count of packets captured since last message */ +#define SP_DROPS 'D' /* count of packets dropped in capture */ +/* + * Win32 only: Indications sent out on the signal pipe (from parent to child) + * (UNIX-like sends signals for this) + */ +#define SP_QUIT 'Q' /* "gracefully" capture quit message (SIGUSR1) */ + +/* write a single message header to the recipient pipe */ +extern int +pipe_write_header(int pipe, char indicator, int length); + +/* write a message to the recipient pipe in the standard format + (3 digit message length (excluding length and indicator field), + 1 byte message indicator and the rest is the message). + If msg is NULL, the message has only a length and indicator. */ +extern void +pipe_write_block(int pipe, char indicator, const char *msg); + +/** the child encountered an error, notify the parent */ +extern void +sync_pipe_errmsg_to_parent(int pipe, const char *error_msg, + const char *secondary_error_msg); + +#endif /* sync_pipe.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tap-rtp-common.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tap-rtp-common.h new file mode 100644 index 00000000..b20db362 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tap-rtp-common.h @@ -0,0 +1,49 @@ +/* tap-rtp-common.h + * RTP streams handler functions used by tshark and wireshark + * + * $Id: tap-rtp-common.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Copyright 2008, Ericsson AB + * By Balint Reczey + * + * most functions are copied from gtk/rtp_stream.c and gtk/rtp_analisys.c + * Copyright 2003, Alcatel Business Systems + * By Lars Ruoff + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef TAP_RTP_COMMON_H_INCLUDED +#define TAP_RTP_COMMON_H_INCLUDED + +#include "gtk/rtp_stream.h" + +gint rtp_stream_info_cmp(gconstpointer, gconstpointer); +void rtpstream_reset_cb(void*); +void rtp_write_header(rtp_stream_info_t*, FILE*); +void rtp_write_sample(rtp_sample_t*, FILE*); +int rtpstream_packet(void*, packet_info*, epan_dissect_t *, const void *); + +/* The one and only global rtpstream_tapinfo_t structure for tshark and wireshark. + */ +static rtpstream_tapinfo_t the_tapinfo_struct = + {0, NULL, 0, TAP_ANALYSE, NULL, NULL, NULL, 0, FALSE}; + + +#endif /*TAP_RTP_COMMON_H_INCLUDED*/ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tap_dfilter_dlg.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tap_dfilter_dlg.h new file mode 100644 index 00000000..ae39ce3d --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tap_dfilter_dlg.h @@ -0,0 +1,73 @@ +/* tap_dfilter_dlg.h + * Header file for display filter dialog used by gui taps + * Copyright 2003 Lars Roland + * + * $Id: tap_dfilter_dlg.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * You can easily add a display filter dialog for your gui tap by using + * the following infrastructure: + * + * Define a global structure of tap_dfilter_dlg within your tap source file. + * Initiate it with: + * 1) a title string for the Dialog Window + * 2) the init string, which is the same as the string after "-z" option without + * the filter string and without the separating comma. + * 3) a pointer to the init function of the tap, which will be called when you click + * on the start button in the display filter dialog. + * 4) the index with "-1" + * + * Within register_tap_menu_yourtap(void), call register_dfilter_stat() + * with a pointer to the tap_dfilter_dlg structure, a string for the + * menu item (don't put "..." at the end, register_dfilter_stat() will + * add it for you), and the REGISTER_STAT_GROUP_ value for the stat + * group to which your stat should belong. + * + * Usage: + * + * tap_dfilter_dlg my_tap_dfilter_dlg = {"My Title", "myproto,mytap", gtk_mytap_init, -1}; + * + * register_tap_menu_mytap(void) { + * register_dfilter_stat(&my_tap_dfilter_dlg, "My Menu Item", + * REGISTER_STAT_GROUP_my_group); + * } + * + * See also: h225_ras_srt.c or h225_counter.c + * + */ + +typedef struct _tap_dfilter_dlg { + const char *win_title; /* title */ + const char *init_string; /* the string to call the tap without a filter via "-z" option */ + void (* tap_init_cb)(const char *,void*); /* callback to init function of the tap */ + gint index; /* initiate this value always with "-1" */ +} tap_dfilter_dlg; + +/* + * Register a stat that has a display filter dialog. + * We register it both as a command-line stat and a menu item stat. + */ +void register_dfilter_stat(tap_dfilter_dlg *info, const char *name, + register_stat_group_t group); + +/* This will update the titles of the dialog windows when we load a new capture file. */ +void tap_dfilter_dlg_update (void); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tempfile.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tempfile.h new file mode 100644 index 00000000..ce13a49d --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tempfile.h @@ -0,0 +1,43 @@ +/* tempfile.h + * Declarations of routines to create temporary files + * + * $Id: tempfile.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __TEMPFILE_H__ +#define __TEMPFILE_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* create a tempfile with the given prefix (e.g. "ether") + * namebuf (and namebuflen) should be 128+1 bytes long (BTW: why?) + * returns the file descriptor of the new tempfile and + * the name of the new file in namebuf + */ +int create_tempfile(char *namebuf, int namebuflen, const char *pfx); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TEMPFILE_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/text2pcap.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/text2pcap.h new file mode 100644 index 00000000..4ca4f1fa --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/text2pcap.h @@ -0,0 +1,49 @@ +/**-*-C-*-********************************************************************** + * + * text2pcap.h + * + * Utility to convert an ASCII hexdump into a libpcap-format capture file + * + * (c) Copyright 2001 Ashok Narayanan + * + * $Id: text2pcap.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + *******************************************************************************/ + + +#ifndef TEXT2PCAP_H +#define TEXT2PCAP_H + +typedef enum { + T_BYTE = 1, + T_OFFSET, + T_DIRECTIVE, + T_TEXT, + T_EOL +} token_t; + +void parse_token(token_t token, char *str); + +int yylex(void); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/timestats.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/timestats.h new file mode 100644 index 00000000..7c418f09 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/timestats.h @@ -0,0 +1,54 @@ +/* timestats.h + * Routines and definitions for time statistics + * Copyrigth 2003 Lars Roland + * + * $Id: timestats.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _time_stat +#define _time_stat + +#include +#include "epan/packet_info.h" +#include "epan/nstime.h" + + /* Summary of time statistics*/ +typedef struct _timestat_t { + guint32 num; /* number of samples */ + guint32 min_num; /* frame number of minimum */ + guint32 max_num; /* frame number of maximum */ + nstime_t min; + nstime_t max; + nstime_t tot; + gdouble variance; +} timestat_t; + +/* functions */ + +/* Initialize a timestat_t struct */ +extern void time_stat_init(timestat_t *stats); + +/* Update a timestat_t struct with a new sample */ +extern void time_stat_update(timestat_t *stats, const nstime_t *delta, packet_info *pinfo); + +extern gdouble get_average(const nstime_t *sum, guint32 num); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tools/make-dissector-reg b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tools/make-dissector-reg new file mode 100755 index 00000000..d2efa7c6 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tools/make-dissector-reg @@ -0,0 +1,186 @@ +#! /bin/sh + +# +# $Id: make-dissector-reg 21716 2007-05-07 17:55:42Z gal $ +# + +# +# The first argument is the directory in which the source files live. +# +srcdir="$1" +shift + +# +# The second argument is either "plugin" or "dissectors"; if it's +# "plugin", we build a plugin.c for a plugin, and if it's +# "dissectors", we build a register.c for libwireshark. +# +registertype="$1" +shift +if [ "$registertype" = plugin ] +then + outfile="plugin.c" +elif [ "$registertype" = dissectors ] +then + outfile="register.c" +else + echo "Unknown output type '$registertype'" 1>&2 + exit 1 +fi + +# +# All subsequent arguments are the files to scan. +# +rm -f ${outfile}-tmp +echo '/* Do not modify this file. */' >${outfile}-tmp +echo '/* It is created automatically by the Makefile. */'>>${outfile}-tmp +if [ "$registertype" = plugin ] +then + cat <<"EOF" >>${outfile}-tmp +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "moduleinfo.h" + +#ifndef ENABLE_STATIC +G_MODULE_EXPORT const gchar version[] = VERSION; + +/* Start the functions we need for the plugin stuff */ + +G_MODULE_EXPORT void +plugin_register (void) +{ +EOF +# +# Build code to call all the protocol registration routines. +# +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^void proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp +else + cat <<"EOF" >>${outfile}-tmp +#include "register.h" +void +register_all_protocols(register_cb cb, gpointer client_data) +{ +EOF +# +# Build code to call all the protocol registration routines. +# +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_REGISTER, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^void proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_REGISTER, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp + +fi +echo '}' >>${outfile}-tmp + + +# +# Build code to call all the protocol handoff registration routines. +# +if [ "$registertype" = plugin ] +then + cat <<"EOF" >>${outfile}-tmp +G_MODULE_EXPORT void +plugin_reg_handoff(void) +{ +EOF +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^void proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp +else + cat <<"EOF" >>${outfile}-tmp +void +register_all_protocol_handoffs(register_cb cb, gpointer client_data) +{ +EOF +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_HANDOFF, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^void proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_HANDOFF, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp +fi +echo '}' >>${outfile}-tmp +if [ "$registertype" = plugin ] +then + echo '#endif' >>${outfile}-tmp +else + cat <<"EOF" >>${outfile}-tmp +gulong register_count(void) +{ +EOF + proto_regs=`grep RA_REGISTER ${outfile}-tmp | wc -l` + handoff_regs=`grep RA_HANDOFF ${outfile}-tmp | wc -l` + echo " return $proto_regs + $handoff_regs;" >>${outfile}-tmp + echo '}' >>${outfile}-tmp +fi +mv ${outfile}-tmp ${outfile} diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tools/make-dissector-reg.py b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tools/make-dissector-reg.py new file mode 100755 index 00000000..c3354279 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tools/make-dissector-reg.py @@ -0,0 +1,238 @@ +#!/usr/bin/env python +# +# Looks for registration routines in the protocol dissectors, +# and assembles C code to call all the routines. +# +# This is a Python version of the make-reg-dotc shell script. +# Running the shell script on Win32 is very very slow because of +# all the process-launching that goes on --- multiple greps and +# seds for each input file. I wrote this python version so that +# less processes would have to be started. +# +# $Id: make-dissector-reg.py 24390 2008-02-19 13:44:02Z wmeier $ + +import os +import sys +import re +import pickle +from stat import * + +# +# The first argument is the directory in which the source files live. +# +srcdir = sys.argv[1] + +# +# The second argument is either "plugin" or "dissectors"; if it's +# "plugin", we build a plugin.c for a plugin, and if it's +# "dissectors", we build a register.c for libwireshark. +# +registertype = sys.argv[2] +if registertype == "plugin": + tmp_filename = "plugin.c-tmp" + final_filename = "plugin.c" + cache_filename = None +elif registertype == "dissectors": + tmp_filename = "register.c-tmp" + final_filename = "register.c" + cache_filename = "register-cache.pkl" +else: + print "Unknown output type '%s'" % registertype + sys.exit(1) + + +# +# All subsequent arguments are the files to scan. +# +files = sys.argv[3:] + +# Create the proper list of filenames +filenames = [] +for file in files: + if os.path.isfile(file): + filenames.append(file) + else: + filenames.append("%s/%s" % (srcdir, file)) + +if len(filenames) < 1: + print "No files found" + sys.exit(1) + + +# Look through all files, applying the regex to each line. +# If the pattern matches, save the "symbol" section to the +# appropriate array. +regs = { + 'proto_reg': [], + 'handoff_reg': [], + } + +# For those that don't know Python, r"" indicates a raw string, +# devoid of Python escapes. +proto_regex0 = r"^(?Pproto_register_[_A-Za-z0-9]+)\s*\([^;]+$" +proto_regex1 = r"void\s+(?Pproto_register_[_A-Za-z0-9]+)\s*\([^;]+$" + +handoff_regex0 = r"^(?Pproto_reg_handoff_[_A-Za-z0-9]+)\s*\([^;]+$" +handoff_regex1 = r"void\s+(?Pproto_reg_handoff_[_A-Za-z0-9]+)\s*\([^;]+$" + +# This table drives the pattern-matching and symbol-harvesting +patterns = [ + ( 'proto_reg', re.compile(proto_regex0) ), + ( 'proto_reg', re.compile(proto_regex1) ), + ( 'handoff_reg', re.compile(handoff_regex0) ), + ( 'handoff_reg', re.compile(handoff_regex1) ), + ] + +# Open our registration symbol cache +cache = None +if cache_filename: + try: + cache_file = open(cache_filename, 'rb') + cache = pickle.load(cache_file) + cache_file.close() + except: + cache = {} + +# Grep +for filename in filenames: + file = open(filename) + cur_mtime = os.fstat(file.fileno())[ST_MTIME] + if cache and cache.has_key(filename): + cdict = cache[filename] + if cur_mtime == cdict['mtime']: +# print "Pulling %s from cache" % (filename) + regs['proto_reg'].extend(cdict['proto_reg']) + regs['handoff_reg'].extend(cdict['handoff_reg']) + file.close() + continue + # We don't have a cache entry + if cache is not None: + cache[filename] = { + 'mtime': cur_mtime, + 'proto_reg': [], + 'handoff_reg': [], + } +# print "Searching %s" % (filename) + for line in file.readlines(): + for action in patterns: + regex = action[1] + match = regex.search(line) + if match: + symbol = match.group("symbol") + sym_type = action[0] + regs[sym_type].append(symbol) + if cache is not None: +# print "Caching %s for %s: %s" % (sym_type, filename, symbol) + cache[filename][sym_type].append(symbol) + file.close() + +if cache is not None and cache_filename is not None: + cache_file = open(cache_filename, 'wb') + pickle.dump(cache, cache_file) + cache_file.close() + +# Make sure we actually processed something +if len(regs['proto_reg']) < 1: + print "No protocol registrations found" + sys.exit(1) + +# Sort the lists to make them pretty +regs['proto_reg'].sort() +regs['handoff_reg'].sort() + +reg_code = open(tmp_filename, "w") + +reg_code.write("/* Do not modify this file. */\n") +reg_code.write("/* It is created automatically by the Makefile. */\n") + +# Make the routine to register all protocols +if registertype == "plugin": + reg_code.write(""" +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "moduleinfo.h" + +#ifndef ENABLE_STATIC +G_MODULE_EXPORT const gchar version[] = VERSION; + +/* Start the functions we need for the plugin stuff */ + +G_MODULE_EXPORT void +plugin_register (void) +{ +"""); +else: + reg_code.write(""" +#include "register.h" +void +register_all_protocols(register_cb cb, gpointer client_data) +{ +"""); + +for symbol in regs['proto_reg']: + if registertype == "plugin": + line = " {extern void %s (void); %s ();}\n" % (symbol, symbol) + else: + line = " {extern void %s (void); if(cb) (*cb)(RA_REGISTER, \"%s\", client_data); %s ();}\n" % (symbol, symbol, symbol) + reg_code.write(line) + +reg_code.write("}\n") + + +# Make the routine to register all protocol handoffs +if registertype == "plugin": + reg_code.write(""" +G_MODULE_EXPORT void +plugin_reg_handoff(void) +{ +"""); +else: + reg_code.write(""" +void +register_all_protocol_handoffs(register_cb cb, gpointer client_data) +{ +"""); + +for symbol in regs['handoff_reg']: + if registertype == "plugin": + line = " {extern void %s (void); %s ();}\n" % (symbol, symbol) + else: + line = " {extern void %s (void); if(cb) (*cb)(RA_HANDOFF, \"%s\", client_data); %s ();}\n" % (symbol, symbol, symbol) + reg_code.write(line) + +reg_code.write("}\n") + +if registertype == "plugin": + reg_code.write("#endif\n"); +else: + reg_code.write(""" +gulong register_count(void) +{ +"""); + + line = " return %d + %d;\n" % (len(regs['proto_reg']), len(regs['handoff_reg'])) + reg_code.write(line) + + reg_code.write(""" +} +"""); + + +# Close the file +reg_code.close() + +# Remove the old final_file if it exists. +try: + os.stat(final_filename) + os.remove(final_filename) +except OSError: + pass + +# Move from tmp file to final file +os.rename(tmp_filename, final_filename) + + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ui_util.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ui_util.h new file mode 100644 index 00000000..fa591a51 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ui_util.h @@ -0,0 +1,79 @@ +/* ui_util.h + * Declarations of UI utility routines; these routines have GUI-independent + * APIs, but GUI-dependent implementations, so that they can be called by + * GUI-independent code to affect the GUI. + * + * $Id: ui_util.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __UI_UTIL_H__ +#define __UI_UTIL_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* gui_utils.c */ + +/* Set the name of the top-level window and its icon. */ +void set_main_window_name(const gchar *); +/* Update the name of the main window if the user-specified decoration + changed. */ +void update_main_window_name(void); +/* update the main window */ +extern void main_window_update(void); +/* exit the main window */ +extern void main_window_exit(void); +/* quit a nested main window */ +extern void main_window_nested_quit(void); +/* quit the main window */ +extern void main_window_quit(void); + +/* read from a pipe (callback) */ +typedef gboolean (*pipe_input_cb_t) (gint source, gpointer user_data); +/* install callback function, called if pipe input is available */ +extern void pipe_input_set_handler(gint source, gpointer user_data, int *child_process, pipe_input_cb_t input_cb); + +/* packet_list.c */ + +/* packet list related functions */ +void packet_list_clear(void); +void packet_list_freeze(void); +void packet_list_thaw(void); +void packet_list_select_row(gint); +void packet_list_moveto_end(void); +gint packet_list_append(const gchar *text[], gpointer data); +void packet_list_set_colors(gint, color_t *, color_t *); +gint packet_list_find_row_from_data(gpointer); +void packet_list_set_text(gint, gint, const gchar *); +void packet_list_set_cls_time_width(gint); +gpointer packet_list_get_row_data(gint); +void packet_list_set_selected_row(gint); +gint packet_list_get_sort_column(void); +void packet_list_set_sort_column(void); +gboolean packet_list_check_end(void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __UI_UTIL_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/util.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/util.h new file mode 100644 index 00000000..2a4198f0 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/util.h @@ -0,0 +1,60 @@ +/* util.h + * Utility definitions + * + * $Id: util.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __UTIL_H__ +#define __UTIL_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Collect command-line arguments as a string consisting of the arguments, + * separated by spaces. + */ +char *get_args_as_string(int argc, char **argv, int optind); + +/* Compute the difference between two seconds/microseconds time stamps. + * Beware: we're using nanosecond resolution now and function is currently unused + */ +void compute_timestamp_diff(gint *diffsec, gint *diffusec, + guint32 sec1, guint32 usec1, guint32 sec2, guint32 usec2); + +/* Try to figure out if we're remotely connected, e.g. via ssh or + Terminal Server, and create a capture filter that matches aspects of the + connection. We match the following environment variables: + + SSH_CONNECTION (ssh): + SSH_CLIENT (ssh): + REMOTEHOST (tcsh, others?): + DISPLAY (x11): [remote name]: + CLIENTNAME (terminal server): + */ +const char *get_conn_cfilter(void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __UTIL_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/version_info.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/version_info.h new file mode 100644 index 00000000..b036fbd2 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/version_info.h @@ -0,0 +1,79 @@ +/* version_info.h + * Declarations of outines to report version information for stuff used + * by Wireshark + * + * $Id: version_info.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __VERSION_INFO_H__ +#define __VERSION_INFO_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * The svn version string or "" + */ +extern const gchar *wireshark_svnversion; + +/* + * Get various library compile-time versions and append them to + * the specified GString. + * + * "additional_info" is called at the end to append any additional + * information; this is required in order to, for example, put the + * Portaudio information at the end of the string, as we currently + * don't use Portaudio in TShark. + */ +void get_compiled_version_info(GString *str, + void (*additional_info)(GString *)); + +/* + * Get compile-time information used only by applications that use + * libwireshark. + */ +void get_epan_compiled_version_info(GString *str); + +/* + * Get various library run-time versions, and the OS version, and append + * them to the specified GString. + */ +void get_runtime_version_info(GString *str, + void (*additional_info)(GString *)); + +/* + * Get copyright information. + */ +const char *get_copyright_info(void); + +#if defined(_WIN32) +/* + * Get the major OS version. + */ +guint32 get_os_major_version(); +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __VERSION_INFO_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/5views.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/5views.h new file mode 100644 index 00000000..2ae18a3a --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/5views.h @@ -0,0 +1,30 @@ +/* 5views.h + * + * $Id: 5views.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __5VIEWS_H__ +#define __5VIEWS_H__ + +int _5views_open(wtap *wth, int *err, gchar **err_info); +gboolean _5views_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); +int _5views_dump_can_write_encap(int encap); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/airopeek9.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/airopeek9.h new file mode 100644 index 00000000..df7a946b --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/airopeek9.h @@ -0,0 +1,29 @@ +/* airopeek9.h + * + * $Id: airopeek9.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __W_AIROPEEK9_H__ +#define __W_AIROPEEK9_H__ + +int airopeek9_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-grammar.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-grammar.h new file mode 100644 index 00000000..c705d457 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-grammar.h @@ -0,0 +1,90 @@ +/* A Bison parser, made by GNU Bison 2.3. */ + +/* Skeleton interface for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + STRING = 258, + KEYWORD = 259, + WDD_DATE = 260, + WDD_CHUNK = 261, + COUNTER = 262, + SLASH_SUFFIX = 263, + WDS_PREFIX = 264, + ISDN_PREFIX = 265, + ETHER_PREFIX = 266, + DECNUM = 267, + HEXNUM = 268, + HEXBYTE = 269 + }; +#endif +/* Tokens. */ +#define STRING 258 +#define KEYWORD 259 +#define WDD_DATE 260 +#define WDD_CHUNK 261 +#define COUNTER 262 +#define SLASH_SUFFIX 263 +#define WDS_PREFIX 264 +#define ISDN_PREFIX 265 +#define ETHER_PREFIX 266 +#define DECNUM 267 +#define HEXNUM 268 +#define HEXBYTE 269 + + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +#line 162 "./ascend-grammar.y" +{ +gchar *s; +guint32 d; +guint8 b; +} +/* Line 1489 of yacc.c. */ +#line 83 "ascend-grammar.h" + YYSTYPE; +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + +extern YYSTYPE ascendlval; + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-int.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-int.h new file mode 100644 index 00000000..6210d8dd --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-int.h @@ -0,0 +1,54 @@ +/* ascend-int.h + * Definitions for routines common to multiple modules in the Lucent/Ascend + * capture file reading code code, but not used outside that code. + * + * $Id: ascend-int.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ASCEND_INT_H__ +#define __ASCEND_INT_H__ + +typedef struct { + time_t start_time; + time_t secs; + int usecs; + guint32 caplen; + guint32 len; +} ascend_pkthdr; + +extern int at_eof; + +extern const gchar *ascend_parse_error; + +/* + * Pointer to the pseudo-header for the current packet. + */ +extern struct ascend_phdr *pseudo_header; + +/* Here we provide interfaces to make our scanner act and look like lex */ +int ascendlex(void); + +void init_parse_ascend(void); +void ascend_init_lexer(FILE_T fh); +int parse_ascend(FILE_T fh, guint8 *pd, struct ascend_phdr *phdr, + ascend_pkthdr *hdr, gint64 *start_of_data); + +#endif /* ! __ASCEND_INT_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-scanner_lex.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-scanner_lex.h new file mode 100644 index 00000000..68794f14 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-scanner_lex.h @@ -0,0 +1,6 @@ +/* This is generated by runlex.sh. Do not edit it. */ +#define yylex ascendlex +#ifndef YY_DECL +#define YY_DECL int yylex(void) +#endif +YY_DECL; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend.h new file mode 100644 index 00000000..1c749aac --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend.h @@ -0,0 +1,33 @@ +/* ascend.h + * + * $Id: ascend.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __ASCEND_H__ +#define __ASCEND_H__ + +#define ASCEND_MAX_DATA_ROWS 8 +#define ASCEND_MAX_DATA_COLS 16 +#define ASCEND_MAX_PKT_LEN (ASCEND_MAX_DATA_ROWS * ASCEND_MAX_DATA_COLS) + +int ascend_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/atm.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/atm.h new file mode 100644 index 00000000..f6aa08c8 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/atm.h @@ -0,0 +1,40 @@ +/* atm.h + * + * $Id: atm.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ATM_H__ +#define __ATM_H__ + +/* + * Routines to use with ATM capture file types that don't include information + * about the *type* of ATM traffic (or, at least, where we haven't found + * that information). + */ + +extern void +atm_guess_traffic_type(const guint8 *pd, guint32 len, + union wtap_pseudo_header *pseudo_header); + +extern void +atm_guess_lane_type(const guint8 *pd, guint32 len, + union wtap_pseudo_header *pseudo_header); + +#endif /* __ATM_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ber.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ber.h new file mode 100644 index 00000000..b3e139de --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ber.h @@ -0,0 +1,28 @@ +/* ber.h + * + * Basic Encoding Rules (BER) file reading + * + * $Id: ber.h 3992 2008-06-10 03:13:11Z dgu $ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __BER_H__ +#define __BER_H__ + +int ber_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/btsnoop.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/btsnoop.h new file mode 100644 index 00000000..d213206e --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/btsnoop.h @@ -0,0 +1,30 @@ +/* btsnoop.h + * + * $Id: btsnoop.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __W_BTSNOOP_H__ +#define __W_BTSNOOP_H__ + +int btsnoop_open(wtap *wth, int *err, gchar **err_info); +gboolean btsnoop_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); +int btsnoop_dump_can_write_encap(int encap); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/buffer.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/buffer.h new file mode 100644 index 00000000..55fb523c --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/buffer.h @@ -0,0 +1,58 @@ +/* buffer.h + * + * $Id: buffer.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __W_BUFFER_H__ +#define __W_BUFFER_H__ + +#define SOME_FUNCTIONS_ARE_DEFINES + +typedef struct Buffer { + guchar *data; + unsigned int allocated; + unsigned int start; + unsigned int first_free; +} Buffer; + +void buffer_init(Buffer* buffer, unsigned int space); +void buffer_free(Buffer* buffer); +void buffer_assure_space(Buffer* buffer, unsigned int space); +void buffer_append(Buffer* buffer, guchar *from, unsigned int bytes); +void buffer_remove_start(Buffer* buffer, unsigned int bytes); + +#ifdef SOME_FUNCTIONS_ARE_DEFINES +# define buffer_clean(buffer) buffer_remove_start((buffer), buffer_length(buffer)) +# define buffer_increase_length(buffer,bytes) (buffer)->first_free += (bytes) +# define buffer_length(buffer) ((buffer)->first_free - (buffer)->start) +# define buffer_start_ptr(buffer) ((buffer)->data + (buffer)->start) +# define buffer_end_ptr(buffer) ((buffer)->data + (buffer)->first_free) +# define buffer_append_buffer(buffer,src_buffer) buffer_append((buffer), buffer_start_ptr(src_buffer), buffer_length(src_buffer)) +#else + void buffer_clean(Buffer* buffer); + void buffer_increase_length(Buffer* buffer, unsigned int bytes); + unsigned int buffer_length(Buffer* buffer); + guchar* buffer_start_ptr(Buffer* buffer); + guchar* buffer_end_ptr(Buffer* buffer); + void buffer_append_buffer(Buffer* buffer, Buffer* src_buffer); +#endif + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/catapult_dct2000.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/catapult_dct2000.h new file mode 100644 index 00000000..89223f5f --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/catapult_dct2000.h @@ -0,0 +1,30 @@ +/* catapult_dct2000.h +* +* $Id: catapult_dct2000.h 3992 2008-06-10 03:13:11Z dgu $ +* +* Wiretap Library +* Copyright (c) 1998 by Gilbert Ramirez +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +int catapult_dct2000_open(wtap *wth, int *err, gchar **err_info); +gboolean catapult_dct2000_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); +int catapult_dct2000_dump_can_write_encap(int encap); + +#define DCT2000_ENCAP_UNHANDLED 0 +#define DCT2000_ENCAP_SSCOP 101 +#define DCT2000_ENCAP_MTP2 102 +#define DCT2000_ENCAP_NBAP 103 diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/commview.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/commview.h new file mode 100644 index 00000000..a07d0d25 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/commview.h @@ -0,0 +1,33 @@ +/* commview.h + * + * $Id: commview.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +#ifndef __COMMVIEW_H__ +#define __COMMVIEW_H__ + +int commview_open(wtap *wth, int *err, gchar **err_info _U_); +int commview_dump_can_write_encap(int encap); +gboolean commview_dump_open(wtap_dumper *wdh, gboolean cant_seek _U_, int *err); + +#endif /* __COMMVIEW_H__ */ + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/cosine.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/cosine.h new file mode 100644 index 00000000..5f5cdadc --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/cosine.h @@ -0,0 +1,32 @@ +/* cosine.h + * + * $Id: cosine.h 3992 2008-06-10 03:13:11Z dgu $ + * + * CoSine IPNOS L2 debug output parsing + * Copyright (c) 2002 by Motonori Shindo + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __W_COSINE_H__ +#define __W_COSINE_H__ + +int cosine_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/csids.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/csids.h new file mode 100644 index 00000000..149d07bd --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/csids.h @@ -0,0 +1,29 @@ + /* csids.h + * + * $Id: csids.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Copyright (c) 2000 by Mike Hall + * Copyright (c) Cisco Systems + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __CSIDS_H__ +#define __CSIDS_H__ + +int csids_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/dbs-etherwatch.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/dbs-etherwatch.h new file mode 100644 index 00000000..971ea7a0 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/dbs-etherwatch.h @@ -0,0 +1,29 @@ +/* dbs-etherwatch.h + * + * $Id: dbs-etherwatch.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __W_DBS_ETHERWATCH_H__ +#define __W_DBS_ETHERWATCH_H__ + +int dbs_etherwatch_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/erf.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/erf.h new file mode 100644 index 00000000..9f6b17cb --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/erf.h @@ -0,0 +1,102 @@ +/* +* +* Copyright (c) 2003 Endace Technology Ltd, Hamilton, New Zealand. +* All rights reserved. +* +* This software and documentation has been developed by Endace Technology Ltd. +* along with the DAG PCI network capture cards. For further information please +* visit http://www.endace.com/. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* 3. The name of Endace Technology Ltd may not be used to endorse or promote +* products derived from this software without specific prior written +* permission. +* +* THIS SOFTWARE IS PROVIDED BY ENDACE TECHNOLOGY LTD ``AS IS'' AND ANY EXPRESS +* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +* EVENT SHALL ENDACE TECHNOLOGY LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +* $Id: erf.h 3992 2008-06-10 03:13:11Z dgu $ +*/ + +#ifndef __W_ERF_H__ +#define __W_ERF_H__ + +/* Record type defines */ +#define ERF_TYPE_LEGACY 0 +#define ERF_TYPE_HDLC_POS 1 +#define ERF_TYPE_ETH 2 +#define ERF_TYPE_ATM 3 +#define ERF_TYPE_AAL5 4 +#define ERF_TYPE_MC_HDLC 5 +#define ERF_TYPE_MC_RAW 6 +#define ERF_TYPE_MC_ATM 7 +#define ERF_TYPE_MC_RAW_CHANNEL 8 +#define ERF_TYPE_MC_AAL5 9 +#define ERF_TYPE_COLOR_HDLC_POS 10 +#define ERF_TYPE_COLOR_ETH 11 +#define ERF_TYPE_MC_AAL2 12 +#define ERF_TYPE_IP_COUNTER 13 +#define ERF_TYPE_TCP_FLOW_COUNTER 14 +#define ERF_TYPE_DSM_COLOR_HDLC_POS 15 +#define ERF_TYPE_DSM_COLOR_ETH 16 +#define ERF_TYPE_COLOR_MC_HDLC_POS 17 +#define ERF_TYPE_AAL2 18 +#define ERF_TYPE_INFINIBAND 21 + +#define ERF_TYPE_PAD 48 + +#define ERF_TYPE_MIN 1 /* sanity checking */ +#define ERF_TYPE_MAX 48 /* sanity checking */ + + /* + * The timestamp is 64bit unsigned fixed point little-endian value with + * 32 bits for second and 32 bits for fraction. + */ +typedef guint64 erf_timestamp_t; + +typedef struct erf_record { + erf_timestamp_t ts; + guint8 type; + guint8 flags; + guint16 rlen; + guint16 lctr; + guint16 wlen; +} erf_header_t; + +typedef struct erf_mc_hdr { + guint32 mc; +} erf_mc_header_t; + +typedef struct erf_eth_hdr { + guint16 eth; +} erf_eth_header_t; + +union erf_subhdr { + struct erf_mc_hdr mc_hdr; + struct erf_eth_hdr eth_hdr; +}; + +#define MIN_RECORDS_FOR_ERF_CHECK 3 +#define RECORDS_FOR_ERF_CHECK 20 +#define FCS_BITS 32 + +int erf_open(wtap *wth, int *err, gchar **err_info); + +#endif /* __W_ERF_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/etherpeek.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/etherpeek.h new file mode 100644 index 00000000..465ad39c --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/etherpeek.h @@ -0,0 +1,29 @@ +/* etherpeek.h + * + * $Id: etherpeek.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __W_ETHERPEEK_H__ +#define __W_ETHERPEEK_H__ + +int etherpeek_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/eyesdn.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/eyesdn.h new file mode 100644 index 00000000..7b28b520 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/eyesdn.h @@ -0,0 +1,29 @@ +/* eyesdn.h + * + * $Id: eyesdn.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __W_EYESDN_H__ +#define __W_EYESDN_H__ + +int eyesdn_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/file_util.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/file_util.h new file mode 100644 index 00000000..e472e3ca --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/file_util.h @@ -0,0 +1,136 @@ +/* file_util.h + * File utility definitions + * + * $Id: file_util.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __FILE_UTIL_H__ +#define __FILE_UTIL_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include + +#ifdef _WIN32 +#include +#endif + +#ifdef HAVE_SYS_STAT_H +#include +#endif + + +/* Win32: Since GLib2.6, we use UTF8 throughout the code, so file functions + * must tweak a given filename from UTF8 to UTF16 as we use NT Unicode (Win9x + * - now unsupported - used locale based encoding here). + */ +#if defined _WIN32 && (GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 6)) +#include + +extern int eth_stdio_open (const gchar *filename, int flags, int mode); +extern int eth_stdio_rename (const gchar *oldfilename, const gchar *newfilename); +extern int eth_stdio_mkdir (const gchar *filename, int mode); +extern int eth_stdio_stat (const gchar *filename, struct stat *buf); +extern int eth_stdio_unlink (const gchar *filename); +extern int eth_stdio_remove (const gchar *filename); +extern FILE * eth_stdio_fopen (const gchar *filename, const gchar *mode); +extern FILE * eth_stdio_freopen (const gchar *filename, const gchar *mode, FILE *stream); + +#define eth_open eth_stdio_open +#define eth_rename eth_stdio_rename +#define eth_mkdir eth_stdio_mkdir +#define eth_stat eth_stdio_stat +#define eth_unlink eth_stdio_unlink +#define eth_remove eth_stdio_remove +#define eth_fopen eth_stdio_fopen +#define eth_freopen eth_stdio_freopen + +#else /* _WIN32 && GLIB_MAJOR_VERSION */ + +/* GLib 2.4 or below, using "old school" functions */ +#ifdef _WIN32 +#define eth_open _open +#define eth_stat _stat +#define eth_unlink _unlink +#define eth_mkdir(dir,mode) _mkdir(dir) +#else +#define eth_open open +#define eth_stat stat +#define eth_unlink unlink +#define eth_mkdir(dir,mode) mkdir(dir,mode) +#endif /* _WIN32 */ + +#define eth_rename rename +#define eth_remove remove +#define eth_fopen fopen +#define eth_freopen freopen + +#endif /* _WIN32 && GLIB_MAJOR_VERSION */ + + +/* some common file function differences between UNIX and WIN32 */ +#ifdef _WIN32 +/* the Win32 API prepends underscores for whatever reasons */ +#define eth_read _read +#define eth_write _write +#define eth_close _close +#define eth_dup _dup +#define eth_lseek _lseek +#else +#define eth_read read +#define eth_write write +#define eth_close close +#define eth_dup dup +#define eth_lseek lseek +#define O_BINARY 0 /* Win32 needs the O_BINARY flag for open() */ +#endif /* _WIN32 */ + +/* directory handling */ +#if GLIB_MAJOR_VERSION >= 2 +#define ETH_DIR GDir +#define ETH_DIRENT const char +#define eth_dir_open g_dir_open +#define eth_dir_read_name g_dir_read_name +#define eth_dir_get_name(dirent) dirent +#define eth_dir_rewind g_dir_rewind +#define eth_dir_close g_dir_close +#else +#define ETH_DIR DIR +#define ETH_DIRENT struct dirent +#define eth_dir_open(name,flags,error) opendir(name) +#define eth_dir_read_name readdir +#define eth_dir_get_name(dirent) (gchar *)(dirent)->d_name +#define eth_dir_rewind rewinddir +#define eth_dir_close closedir +#endif /* GLIB_MAJOR_VERSION */ + +/* XXX - remove include "dirent.h" */ +/* XXX - remove include "direct.h" */ +/* XXX - remove include "sys/stat.h" */ +/* XXX - update docs (e.g. README.developer) */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __FILE_UTIL_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/file_wrappers.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/file_wrappers.h new file mode 100644 index 00000000..193af09f --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/file_wrappers.h @@ -0,0 +1,57 @@ +/* file_wrappers.h + * + * $Id: file_wrappers.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __FILE_H__ +#define __FILE_H__ + +extern gint64 file_seek(void *stream, gint64 offset, int whence, int *err); +extern gint64 file_tell(void *stream); +extern int file_error(void *fh); + +#ifdef HAVE_LIBZ + +extern FILE_T file_open(const char *path, const char *mode); +#define filed_open gzdopen +/* XX: gzread and gzwrite return number of *bytes* (not number of elements) */ +#define file_read(buf, bsize, count, file) gzread((file),(buf),((count)*(bsize))) +#define file_write(buf, bsize, count, file) gzwrite((file),(buf),((count)*(bsize))) +#define file_close gzclose +#define file_getc gzgetc +#define file_gets(buf, len, file) gzgets((file), (buf), (len)) +#define file_eof gzeof + +#else /* No zLib */ + +#define file_open(path, mode) eth_fopen(path, mode) +#define filed_open fdopen +/* XX: file_read and file_write defined to return number of *bytes* to be consistent with gzread & gzwrite */ +#define file_read(buf, bsize, count, file) ((bsize) * fread((buf), (bsize), (count), (file))) +#define file_write(buf, bsize, count, file) ((bsize) * fwrite((buf), (bsize), (count), (file))) +#define file_close fclose +#define file_getc fgetc +#define file_gets fgets +#define file_eof feof + +#endif /* HAVE_LIBZ */ + +#endif /* __FILE_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/hcidump.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/hcidump.h new file mode 100644 index 00000000..08a0a61c --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/hcidump.h @@ -0,0 +1,28 @@ +/* hcidump.h + * + * $Id: hcidump.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Copyright (c) 2003 by Marcel Holtmann + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __HCIDUMP_H__ +#define __HCIDUMP_H__ + +int hcidump_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/i4b_trace.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/i4b_trace.h new file mode 100644 index 00000000..359f09ea --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/i4b_trace.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 1997, 1999 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_trace.h - header file for trace data read device + * ---------------------------------------------------- + * + * $Id: i4b_trace.h 3992 2008-06-10 03:13:11Z dgu $ + * + * last edit-date: [Sun Feb 14 10:39:26 1999] + * + *---------------------------------------------------------------------------*/ + +#ifndef _I4B_TRACE_H_ +#define _I4B_TRACE_H_ + +/*---------------------------------------------------------------------------* + * structure of the header at the beginning of every trace mbuf + *---------------------------------------------------------------------------*/ +typedef struct { + guint32 length; /* length of the following mbuf */ + gint32 unit; /* controller unit number */ + gint32 type; /* type of channel */ +#define TRC_CH_I 0 /* Layer 1 INFO's */ +#define TRC_CH_D 1 /* D channel */ +#define TRC_CH_B1 2 /* B1 channel */ +#define TRC_CH_B2 3 /* B2 channel */ + gint32 dir; /* direction */ +#define FROM_TE 0 /* user -> network */ +#define FROM_NT 1 /* network -> user */ + gint32 trunc; /* # of truncated bytes (frame > MCLBYTES) */ + guint32 count; /* frame count for this unit/type */ + guint32 ts_sec; /* timestamp seconds */ + guint32 ts_usec; /* timestamp microseconds */ +} i4b_trace_hdr_t; + +#define INFO0 0 /* layer 1 */ +#define INFO1_8 1 +#define INFO1_10 2 +#define INFO2 3 +#define INFO3 4 +#define INFO4_8 5 +#define INFO4_10 6 + +/*---------------------------------------------------------------------------* + * ioctl via /dev/i4btrc device(s): + * get/set current trace flag settings + *---------------------------------------------------------------------------*/ + +#define I4B_TRC_GET _IOR('T', 0, int) /* get trace settings */ +#define I4B_TRC_SET _IOW('T', 1, int) /* set trace settings */ + +#define TRACE_OFF 0x00 /* tracing off */ +#define TRACE_I 0x01 /* trace L1 INFO's on */ +#define TRACE_D_TX 0x02 /* trace D channel on */ +#define TRACE_D_RX 0x04 /* trace D channel on */ +#define TRACE_B_TX 0x08 /* trace B channel on */ +#define TRACE_B_RX 0x10 /* trace B channel on */ + +typedef struct { + gint32 rxunit; /* unit # for rx frames */ + gint32 rxflags; /* d and/or b channel */ + gint32 txunit; /* unit # for tx frames */ + gint32 txflags; /* d and/or b channel */ +} i4b_trace_setupa_t; + +#define I4B_TRC_SETA _IOW('T', 2, i4b_trace_setupa_t) /* set analyze mode */ +#define I4B_TRC_RESETA _IOW('T', 3, int) /* reset analyze mode */ + +#endif /* _I4B_TRACE_H_ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/i4btrace.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/i4btrace.h new file mode 100644 index 00000000..716e7c47 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/i4btrace.h @@ -0,0 +1,29 @@ +/* i4btrace.h + * + * $Id: i4btrace.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1999 by Bert Driehuis + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __I4BTRACE_H__ +#define __I4BTRACE_H__ + +int i4btrace_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/iptrace.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/iptrace.h new file mode 100644 index 00000000..57ac0d59 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/iptrace.h @@ -0,0 +1,29 @@ +/* iptrace.h + * + * $Id: iptrace.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __IPTRACE_H__ +#define __IPTRACE_H__ + +int iptrace_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/iseries.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/iseries.h new file mode 100644 index 00000000..ffb43e31 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/iseries.h @@ -0,0 +1,28 @@ +/* iseries.h + * + * $Id: iseries.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 2005 by Martin Warnes + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __W_ISERIES_H__ +#define __W_ISERIES_H__ + +int iseries_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/k12.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/k12.h new file mode 100644 index 00000000..c2647322 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/k12.h @@ -0,0 +1,28 @@ +/* k12.c +* +* $Id: k12.h 3992 2008-06-10 03:13:11Z dgu $ +* +* Wiretap Library +* Copyright (c) 1998 by Gilbert Ramirez +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +int k12_open(wtap *wth, int *err, gchar **err_info); +int k12_dump_can_write_encap(int encap); +gboolean k12_dump_open(wtap_dumper *wdh, gboolean cant_seek _U_, int *err); +int k12text_open(wtap *wth, int *err, gchar **err_info _U_); +int k12text_dump_can_write_encap(int encap); +gboolean k12text_dump_open(wtap_dumper *wdh, gboolean cant_seek _U_, int *err); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/k12text_lex.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/k12text_lex.h new file mode 100644 index 00000000..ccd97c5d --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/k12text_lex.h @@ -0,0 +1,6 @@ +/* This is generated by runlex.sh. Do not edit it. */ +#define yylex K12Text_lex +#ifndef YY_DECL +#define YY_DECL int yylex(void) +#endif +YY_DECL; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/lanalyzer.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/lanalyzer.h new file mode 100644 index 00000000..758a9833 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/lanalyzer.h @@ -0,0 +1,176 @@ +/* lanalyzer.h + * + * $Id: lanalyzer.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __LANALYZER_H__ +#define __LANALYZER_H__ + +/* Record type codes: */ + +#define RT_HeaderRegular 0x1001 +#define RT_HeaderCyclic 0x1007 +#define RT_RxChannelName 0x1006 +#define RT_TxChannelName 0x100b +#define RT_FilterName 0x1032 +#define RT_RxTemplateName 0x1035 +#define RT_TxTemplateName 0x1036 +#define RT_DisplayOptions 0x100a +#define RT_Summary 0x1002 +#define RT_SubfileSummary 0x1003 +#define RT_CyclicInformation 0x1009 +#define RT_Index 0x1004 +#define RT_PacketData 0x1005 + +#define LA_ProFileLimit (1024 * 1024 * 32) + +typedef guint8 Eadr[6]; +typedef guint16 TimeStamp[3]; /* 0.5 microseconds since start of trace */ + +/* + * These records have only 2-byte alignment for 4-byte quantities, + * so the structures aren't necessarily valid; they're kept as comments + * for reference purposes. + */ + +/* + * typedef struct { + * guint8 day; + * guint8 mon; + * gint16 year; + * } Date; + */ + +/* + * typedef struct { + * guint8 second; + * guint8 minute; + * guint8 hour; + * guint8 day; + * gint16 reserved; + * } Time; + */ + +/* + * typedef struct { + * guint16 rx_channels; + * guint16 rx_errors; + * gint16 rx_frm_len; + * gint16 rx_frm_sln; + * TimeStamp rx_time; + * guint32 pktno; + * gint16 prvlen; + * gint16 offset; + * gint16 tx_errs; + * gint16 rx_filters; + * gint8 unused[2]; + * gint16 hwcolls; + * gint16 hwcollschans; + * Packetdata ....; + * } LA_PacketRecord; + */ + +#define LA_PacketRecordSize 32 + +/* + * typedef struct { + * Date datcre; + * Date datclo; + * Time timeopn; + * Time timeclo; + * Eadr statadr; + * gint16 mxseqno; + * gint16 slcoff; + * gint16 mxslc; + * gint32 totpktt; + * gint32 statrg; + * gint32 stptrg; + * gint32 mxpkta[36]; + * gint16 board_type; + * gint16 board_version; + * gint8 reserved[18]; + * } Summary; + */ + +#define SummarySize (18+22+(4*36)+6+6+6+4+4) + + +/* + * typedef struct { + * gint16 rid; + * gint16 rlen; + * Summary s; + * } LA_SummaryRecord; + */ + +#define LA_SummaryRecordSize (SummarySize + 4) + + +/* + * typedef struct { + * gint16 rid; + * gint16 rlen; + * gint16 seqno; + * gint32 totpktf; + * } LA_SubfileSummaryRecord; + */ + +#define LA_SubfileSummaryRecordSize 10 + + +#define LA_IndexSize 500 + +/* + * typedef struct { + * gint16 rid; + * gint16 rlen; + * gint16 idxsp; = LA_IndexSize + * gint16 idxct; + * gint8 idxgranu; + * gint8 idxvd; + * gint32 trcidx[LA_IndexSize + 2]; +2 undocumented but used by La 2.2 + * } LA_IndexRecord; + */ + +#define LA_IndexRecordSize (10 + 4 * (LA_IndexSize + 2)) + +/* + * typedef struct { + * gint16 rid; + * gint16 rlen; + * } LA_RecordHeader; + */ + +#define LA_RecordHeaderSize 4 + +typedef struct { + gboolean init; + struct timeval start; + guint32 pkts; + int encap; + int lastlen; + } LA_TmpInfo; + +int lanalyzer_open(wtap *wth, int *err, gchar **err_info); +gboolean lanalyzer_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); +int lanalyzer_dump_can_write_encap(int encap); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/libpcap.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/libpcap.h new file mode 100644 index 00000000..3d4038f1 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/libpcap.h @@ -0,0 +1,106 @@ +/* libpcap.h + * + * $Id: libpcap.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __W_LIBPCAP_H__ +#define __W_LIBPCAP_H__ + +/* Magic numbers in "libpcap" files. + + "libpcap" file records are written in the byte order of the host that + writes them, and the reader is expected to fix this up. + + PCAP_MAGIC is the magic number, in host byte order; PCAP_SWAPPED_MAGIC + is a byte-swapped version of that. + + PCAP_MODIFIED_MAGIC is for Alexey Kuznetsov's modified "libpcap" + format, as generated on Linux systems that have a "libpcap" with + his patches, at + + http://ftp.sunet.se/pub/os/Linux/ip-routing/lbl-tools/ + + applied; PCAP_SWAPPED_MODIFIED_MAGIC is the byte-swapped version. + + PCAP_NSEC_MAGIC is for Ulf Lamping's modified "libpcap" format, + which uses the same common file format as PCAP_MAGIC, but the + timestamps are saved in nanosecond resolution instead of microseconds. + PCAP_SWAPPED_NSEC_MAGIC is a byte-swapped version of that. */ +#define PCAP_MAGIC 0xa1b2c3d4 +#define PCAP_SWAPPED_MAGIC 0xd4c3b2a1 +#define PCAP_MODIFIED_MAGIC 0xa1b2cd34 +#define PCAP_SWAPPED_MODIFIED_MAGIC 0x34cdb2a1 +#define PCAP_NSEC_MAGIC 0xa1b23c4d +#define PCAP_SWAPPED_NSEC_MAGIC 0x4d3cb2a1 + +/* "libpcap" file header (minus magic number). */ +struct pcap_hdr { + guint16 version_major; /* major version number */ + guint16 version_minor; /* minor version number */ + gint32 thiszone; /* GMT to local correction */ + guint32 sigfigs; /* accuracy of timestamps */ + guint32 snaplen; /* max length of captured packets, in octets */ + guint32 network; /* data link type */ +}; + +/* "libpcap" record header. */ +struct pcaprec_hdr { + guint32 ts_sec; /* timestamp seconds */ + guint32 ts_usec; /* timestamp microseconds (nsecs for PCAP_NSEC_MAGIC) */ + guint32 incl_len; /* number of octets of packet saved in file */ + guint32 orig_len; /* actual length of packet */ +}; + +/* "libpcap" record header for Alexey's patched version. */ +struct pcaprec_modified_hdr { + struct pcaprec_hdr hdr; /* the regular header */ + guint32 ifindex; /* index, in *capturing* machine's list of + interfaces, of the interface on which this + packet came in. */ + guint16 protocol; /* Ethernet packet type */ + guint8 pkt_type; /* broadcast/multicast/etc. indication */ + guint8 pad; /* pad to a 4-byte boundary */ +}; + +/* "libpcap" record header for Alexey's patched version in its ss990915 + incarnation; this version shows up in SuSE Linux 6.3. */ +struct pcaprec_ss990915_hdr { + struct pcaprec_hdr hdr; /* the regular header */ + guint32 ifindex; /* index, in *capturing* machine's list of + interfaces, of the interface on which this + packet came in. */ + guint16 protocol; /* Ethernet packet type */ + guint8 pkt_type; /* broadcast/multicast/etc. indication */ + guint8 cpu1, cpu2; /* SMP debugging gunk? */ + guint8 pad[3]; /* pad to a 4-byte boundary */ +}; + +/* "libpcap" record header for version used on some Nokia boxes (firewalls?) */ +struct pcaprec_nokia_hdr { + struct pcaprec_hdr hdr; /* the regular header */ + guint8 stuff[4]; /* mysterious stuff */ +}; + +int libpcap_open(wtap *wth, int *err, gchar **err_info); +gboolean libpcap_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); +int libpcap_dump_can_write_encap(int encap); +int wtap_pcap_encap_to_wtap_encap(int encap); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/mpeg-audio.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/mpeg-audio.h new file mode 100644 index 00000000..3ead2ff5 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/mpeg-audio.h @@ -0,0 +1,98 @@ +/* mpeg-audio.h + * + * MPEG Audio header dissection + * Written by Shaun Jackman + * Copyright 2007 Shaun Jackman + * + * $Id: mpeg-audio.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef MPA_H +#define MPA_H 1 + +struct mpa { + unsigned emphasis :2; + unsigned original :1; + unsigned copyright :1; + unsigned modeext :2; + unsigned mode :2; + unsigned private :1; + unsigned padding :1; + unsigned frequency :2; + unsigned bitrate :4; + unsigned protection :1; + unsigned layer :2; + unsigned version :2; + unsigned sync :11; +}; + +#define MPA_UNMARSHAL_SYNC(n) ((n) >> 21 & 0x7ff) +#define MPA_UNMARSHAL_VERSION(n) ((n) >> 19 & 0x3) +#define MPA_UNMARSHAL_LAYER(n) ((n) >> 17 & 0x3) +#define MPA_UNMARSHAL_PROTECTION(n) ((n) >> 16 & 0x1) +#define MPA_UNMARSHAL_BITRATE(n) ((n) >> 12 & 0xf) +#define MPA_UNMARSHAL_FREQUENCY(n) ((n) >> 10 & 0x3) +#define MPA_UNMARSHAL_PADDING(n) ((n) >> 9 & 0x1) +#define MPA_UNMARSHAL_PRIVATE(n) ((n) >> 8 & 0x1) +#define MPA_UNMARSHAL_MODE(n) ((n) >> 6 & 0x3) +#define MPA_UNMARSHAL_MODEEXT(n) ((n) >> 4 & 0x3) +#define MPA_UNMARSHAL_COPYRIGHT(n) ((n) >> 3 & 0x1) +#define MPA_UNMARSHAL_ORIGINAL(n) ((n) >> 2 & 0x1) +#define MPA_UNMARSHAL_EMPHASIS(n) ((n) >> 0 & 0x3) + +#define MPA_UNMARSHAL(mpa, n) do { \ + (mpa)->sync = MPA_UNMARSHAL_SYNC(n); \ + (mpa)->version = MPA_UNMARSHAL_VERSION(n); \ + (mpa)->layer = MPA_UNMARSHAL_LAYER(n); \ + (mpa)->protection = MPA_UNMARSHAL_PROTECTION(n); \ + (mpa)->bitrate = MPA_UNMARSHAL_BITRATE(n); \ + (mpa)->frequency = MPA_UNMARSHAL_FREQUENCY(n); \ + (mpa)->padding = MPA_UNMARSHAL_PADDING(n); \ + (mpa)->private = MPA_UNMARSHAL_PRIVATE(n); \ + (mpa)->mode = MPA_UNMARSHAL_MODE(n); \ + (mpa)->modeext = MPA_UNMARSHAL_MODEEXT(n); \ + (mpa)->copyright = MPA_UNMARSHAL_COPYRIGHT(n); \ + (mpa)->original = MPA_UNMARSHAL_ORIGINAL(n); \ + (mpa)->emphasis = MPA_UNMARSHAL_EMPHASIS(n); \ + } while (0) + +int mpa_version(const struct mpa *); +int mpa_layer(const struct mpa *); +unsigned mpa_samples(const struct mpa *); +unsigned mpa_bitrate(const struct mpa *); +unsigned mpa_frequency(const struct mpa *); +unsigned mpa_padding(const struct mpa *); + +#define MPA_DATA_BYTES(mpa) (mpa_bitrate(mpa) * mpa_samples(mpa) \ + / mpa_frequency(mpa) / 8) +#define MPA_BYTES(mpa) (MPA_DATA_BYTES(mpa) + mpa_padding(mpa)) +#define MPA_DURATION_NS(mpa) \ + (1000000000 / mpa_frequency(mpa) * mpa_samples(mpa)) + +enum { MPA_SYNC = 0x7ff }; + +#define MPA_SYNC_VALID(mpa) ((mpa)->sync == MPA_SYNC) +#define MPA_VERSION_VALID(mpa) (mpa_version(mpa) >= 0) +#define MPA_LAYER_VALID(mpa) (mpa_layer(mpa) >= 0) +#define MPA_BITRATE_VALID(mpa) (mpa_bitrate(mpa) > 0) +#define MPA_FREQUENCY_VALID(mpa) (mpa_frequency(mpa) > 0) +#define MPA_VALID(mpa) (MPA_SYNC_VALID(mpa) \ + && MPA_VERSION_VALID(mpa) && MPA_LAYER_VALID(mpa) \ + && MPA_BITRATE_VALID(mpa) && MPA_FREQUENCY_VALID(mpa)) + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/mpeg.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/mpeg.h new file mode 100644 index 00000000..c24fe87d --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/mpeg.h @@ -0,0 +1,32 @@ +/* mpeg.h + * + * MPEG file format decoder for the Wiretap library. + * Written by Shaun Jackman + * Copyright 2007 Shaun Jackman + * + * $Id: mpeg.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __W_MPEG_H__ +#define __W_MPEG_H__ + +#include "wtap-int.h" + +int mpeg_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netmon.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netmon.h new file mode 100644 index 00000000..ab0904cc --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netmon.h @@ -0,0 +1,30 @@ +/* netmon.h + * + * $Id: netmon.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __NETMON_H__ +#define __NETMON_H__ + +int netmon_open(wtap *wth, int *err, gchar **err_info); +gboolean netmon_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); +int netmon_dump_can_write_encap(int encap); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netscreen.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netscreen.h new file mode 100644 index 00000000..dce7c361 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netscreen.h @@ -0,0 +1,53 @@ +/* netscreen.h + * + * $Id: netscreen.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Juniper NetScreen snoop output parser + * Created by re-using a lot of code from cosine.c + * Copyright (c) 2007 by Sake Blok + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __W_NETSCREEN_H__ +#define __W_NETSCREEN_H__ + +/* Magic text to check for NetScreen snoop output */ +#define NETSCREEN_HDR_MAGIC_STR1 "(i) len=" +#define NETSCREEN_HDR_MAGIC_STR2 "(o) len=" + +/* Magic text for start of packet */ +#define NETSCREEN_REC_MAGIC_STR1 NETSCREEN_HDR_MAGIC_STR1 +#define NETSCREEN_REC_MAGIC_STR2 NETSCREEN_HDR_MAGIC_STR2 + +#define NETSCREEN_LINE_LENGTH 128 +#define NETSCREEN_HEADER_LINES_TO_CHECK 32 +#define NETSCREEN_MAX_INFOLINES 8 +#define NETSCREEN_SPACES_ON_INFO_LINE 14 +#define NETSCREEN_MAX_INT_NAME_LENGTH 16 + +#define NETSCREEN_INGRESS FALSE +#define NETSCREEN_EGRESS TRUE + + +#define NETSCREEN_MAX_PACKET_LEN 65536 + +int netscreen_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/nettl.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/nettl.h new file mode 100644 index 00000000..1ac9f756 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/nettl.h @@ -0,0 +1,124 @@ +/* nettl.h + * + * $Id: nettl.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * Enhancements by Mark C. Brown + * Copyright (C) 2003, 2005 Hewlett-Packard Development Company, L.P. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __NETTL_H__ +#define __NETTL_H__ + +/* nettl subsystems are defined in /etc/nettlgen.conf */ + +#define NETTL_SUBSYS_NS_LS_LOGGING 0 +#define NETTL_SUBSYS_NS_LS_NFT 1 +#define NETTL_SUBSYS_NS_LS_LOOPBACK 2 +#define NETTL_SUBSYS_NS_LS_NI 3 +#define NETTL_SUBSYS_NS_LS_IPC 4 +#define NETTL_SUBSYS_NS_LS_SOCKREGD 5 +#define NETTL_SUBSYS_NS_LS_TCP 6 +#define NETTL_SUBSYS_NS_LS_PXP 7 +#define NETTL_SUBSYS_NS_LS_UDP 8 +#define NETTL_SUBSYS_NS_LS_IP 9 +#define NETTL_SUBSYS_NS_LS_PROBE 10 +#define NETTL_SUBSYS_NS_LS_DRIVER 11 +#define NETTL_SUBSYS_NS_LS_RLBD 12 +#define NETTL_SUBSYS_NS_LS_BUFS 13 +#define NETTL_SUBSYS_NS_LS_CASE21 14 +#define NETTL_SUBSYS_NS_LS_ROUTER21 15 +#define NETTL_SUBSYS_NS_LS_NFS 16 +#define NETTL_SUBSYS_NS_LS_NETISR 17 +#define NETTL_SUBSYS_NS_LS_NSE 18 +#define NETTL_SUBSYS_NS_LS_STRLOG 19 +#define NETTL_SUBSYS_NS_LS_TIRDWR 21 +#define NETTL_SUBSYS_NS_LS_TIMOD 22 +#define NETTL_SUBSYS_NS_LS_ICMP 23 +#define NETTL_SUBSYS_FILTER 26 +#define NETTL_SUBSYS_NAME 27 +#define NETTL_SUBSYS_IGMP 29 +#define NETTL_SUBSYS_SX25L2 34 +#define NETTL_SUBSYS_SX25L3 35 +#define NETTL_SUBSYS_FTAM_INIT 64 +#define NETTL_SUBSYS_FTAM_RESP 65 +#define NETTL_SUBSYS_FTAM_VFS 70 +#define NETTL_SUBSYS_FTAM_USER 72 +#define NETTL_SUBSYS_OTS 90 +#define NETTL_SUBSYS_NETWORK 91 +#define NETTL_SUBSYS_TRANSPORT 92 +#define NETTL_SUBSYS_SESSION 93 +#define NETTL_SUBSYS_ACSE_PRES 94 +#define NETTL_SUBSYS_SHM 116 +#define NETTL_SUBSYS_ACSE_US 119 +#define NETTL_SUBSYS_HPS 121 +#define NETTL_SUBSYS_CM 122 +#define NETTL_SUBSYS_ULA_UTILS 123 +#define NETTL_SUBSYS_EM 124 +#define NETTL_SUBSYS_HP_APAPORT 189 +#define NETTL_SUBSYS_HP_APALACP 190 +#define NETTL_SUBSYS_NS_LS_IPV6 244 +#define NETTL_SUBSYS_NS_LS_ICMPV6 245 +#define NETTL_SUBSYS_NS_LS_TELNET 267 +#define NETTL_SUBSYS_NS_LS_SCTP 268 + +/* Ethernet cards */ +#define NETTL_SUBSYS_100VG 37 +#define NETTL_SUBSYS_LAN100 164 +#define NETTL_SUBSYS_EISA100BT 172 +#define NETTL_SUBSYS_BASE100 173 +#define NETTL_SUBSYS_GSC100BT 178 +#define NETTL_SUBSYS_PCI100BT 179 +#define NETTL_SUBSYS_SPP100BT 180 +#define NETTL_SUBSYS_GELAN 185 +#define NETTL_SUBSYS_BTLAN 210 +#define NETTL_SUBSYS_INTL100 233 +#define NETTL_SUBSYS_IGELAN 252 +#define NETTL_SUBSYS_IETHER 253 +#define NETTL_SUBSYS_IXGBE 265 + +/* FDDI cards */ +#define NETTL_SUBSYS_HPPB_FDDI 95 +#define NETTL_SUBSYS_EISA_FDDI 174 +#define NETTL_SUBSYS_PCI_FDDI 176 +#define NETTL_SUBSYS_HSC_FDDI 177 + +/* Token Ring cards */ +#define NETTL_SUBSYS_TOKEN 31 +#define NETTL_SUBSYS_PCI_TR 187 + +/* from /usr/include/sys/subsys_id.h */ + +#define NETTL_HDR_HDRIN 0x80000000 +#define NETTL_HDR_HDROUT 0x40000000 +#define NETTL_HDR_PDUIN 0x20000000 +#define NETTL_HDR_PDUOUT 0x10000000 +#define NETTL_HDR_PROCEDURE_TRACE 0x08000000 +#define NETTL_HDR_STATE_TRACE 0x04000000 +#define NETTL_HDR_ERROR_TRACE 0x02000000 +#define NETTL_HDR_LOG_TRACE 0x01000000 +#define NETTL_HDR_LOOPBACK 0x00800000 +#define NETTL_HDR_PTOP 0x00400000 +#define NETTL_HDR_SUBSYSTEM_BITS_MASK 0x000fffff + +int nettl_open(wtap *wth, int *err, gchar **err_info); +gboolean nettl_dump_open(wtap_dumper *wdh, gboolean cant_seek _U_, int *err); +int nettl_dump_can_write_encap(int encap); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/network_instruments.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/network_instruments.h new file mode 100644 index 00000000..ab9708b7 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/network_instruments.h @@ -0,0 +1,127 @@ +/* + * $Id: network_instruments.h 3992 2008-06-10 03:13:11Z dgu $ + */ + +/*************************************************************************** + NetworkInstruments.h - description + ------------------- + begin : Wed Oct 29 2003 + copyright : (C) 2003 by root + email : scotte[AT}netinst.com + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef __NETWORK_INSTRUMENTS_H__ +#define __NETWORK_INSTRUMENTS_H__ + +int network_instruments_open(wtap *wth, int *err, gchar **err_info); +int network_instruments_dump_can_write_encap(int encap); +gboolean network_instruments_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); + +typedef struct capture_file_header +{ + char observer_version[32]; + guint16 offset_to_first_packet; + char probe_instance; + guint8 number_of_information_elements; /* number of TLVs in the header */ +} capture_file_header; + +typedef struct tlv_header +{ + guint16 type; + guint16 length; /* includes the length of the TLV header */ +} tlv_header; + +/* + * TLV type values. + */ +#define INFORMATION_TYPE_ALIAS_LIST 0x01 +#define INFORMATION_TYPE_COMMENT 0x02 /* ASCII text */ + +typedef struct packet_entry_header +{ + guint32 packet_magic; + guint32 network_speed; + guint16 captured_size; + guint16 network_size; + guint16 offset_to_frame; + guint16 offset_to_next_packet; + guint8 network_type; + guint8 flags; + guint8 number_of_information_elements; /* number of TLVs in the header */ + guint8 packet_type; + guint16 errors; + guint16 reserved; + guint64 packet_number; + guint64 original_packet_number; + guint64 nano_seconds_since_2000; +} packet_entry_header; + +/* + * Network type values. + */ +#define OBSERVER_UNDEFINED 0xFF +#define OBSERVER_ETHERNET 0x00 +#define OBSERVER_TOKENRING 0x01 +#define OBSERVER_FDDI 0x02 + +/* + * Packet type values. + */ +#define PACKET_TYPE_DATA_PACKET 0 +#define PACKET_TYPE_EXPERT_INFORMATION_PACKET 1 + +/* + * The Observer document indicates that the types of expert information + * packets are: + * + * Network Load (markers used by Expert Time Interval and What If + * analysis modes) + * + * Start/Stop Packet Capture marker frames (with time stamps when + * captures start and stop) + * + * Wireless Channel Change (markers showing what channel was being + * currently listened to) + * + * That information appears to be contained in TLVs. + */ + +/* + * TLV type values. + */ +#define INFORMATION_TYPE_NETWORK_LOAD 0x0100 +#define INFORMATION_TYPE_CAPTURE_START_STOP 0x0104 + +/* + * Might some of these be broadcast and multicast packet counts? + */ +typedef struct tlv_network_load +{ + guint32 utilization; /* network utilization, in .1% units */ + guint32 unknown1; + guint32 unknown2; + guint32 packets_per_second; + guint32 unknown3; + guint32 bytes_per_second; + guint32 unknown4; +} tlv_network_load; + +typedef struct tlv_capture_start_stop +{ + guint32 start_stop; +} tlv_capture_start_stop; + +#define START_STOP_TYPE_STOP 0 +#define START_STOP_TYPE_START 1 + +#endif + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netxray.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netxray.h new file mode 100644 index 00000000..0c38bb34 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netxray.h @@ -0,0 +1,32 @@ +/* netxray.h + * + * $Id: netxray.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __NETXRAY_H__ +#define __NETXRAY_H__ + +int netxray_open(wtap *wth, int *err, gchar **err_info); +int netxray_dump_can_write_encap_1_1(int encap); +gboolean netxray_dump_open_1_1(wtap_dumper *wdh, gboolean cant_seek, int *err); +int netxray_dump_can_write_encap_2_0(int encap); +gboolean netxray_dump_open_2_0(wtap_dumper *wdh, gboolean cant_seek, int *err); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ngsniffer.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ngsniffer.h new file mode 100644 index 00000000..a4a25f6e --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ngsniffer.h @@ -0,0 +1,30 @@ +/* ngsniffer.h + * + * $Id: ngsniffer.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __NGSNIFFER_H__ +#define __NGSNIFFER_H__ + +int ngsniffer_open(wtap *wth, int *err, gchar **err_info); +gboolean ngsniffer_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); +int ngsniffer_dump_can_write_encap(int encap); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/pcapng.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/pcapng.h new file mode 100644 index 00000000..65d7de3d --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/pcapng.h @@ -0,0 +1,30 @@ +/* pcapng.h + * + * $Id: pcapng.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __W_PCAPNG_H__ +#define __W_PCAPNG_H__ + +int pcapng_open(wtap *wth, int *err, gchar **err_info); +gboolean pcapng_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); +int pcapng_dump_can_write_encap(int encap); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/pppdump.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/pppdump.h new file mode 100644 index 00000000..c5b8aad0 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/pppdump.h @@ -0,0 +1,28 @@ +/* pppdump.h + * + * $Id: pppdump.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Copyright (c) 2000 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __PPPDUMP_H__ +#define __PPPDUMP_H__ + +int pppdump_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/radcom.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/radcom.h new file mode 100644 index 00000000..0e6724c7 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/radcom.h @@ -0,0 +1,29 @@ +/* radcom.h + * + * $Id: radcom.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __RADCOM_H__ +#define __RADCOM_H__ + +int radcom_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/snoop.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/snoop.h new file mode 100644 index 00000000..a1a68f87 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/snoop.h @@ -0,0 +1,30 @@ +/* snoop.h + * + * $Id: snoop.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __W_SNOOP_H__ +#define __W_SNOOP_H__ + +int snoop_open(wtap *wth, int *err, gchar **err_info); +gboolean snoop_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); +int snoop_dump_can_write_encap(int encap); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/toshiba.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/toshiba.h new file mode 100644 index 00000000..eea69129 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/toshiba.h @@ -0,0 +1,28 @@ +/* toshiba.h + * + * $Id: toshiba.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __W_TOSHIBA_H__ +#define __W_TOSHIBA_H__ + +int toshiba_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/visual.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/visual.h new file mode 100644 index 00000000..0c094a9e --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/visual.h @@ -0,0 +1,35 @@ +/* visual.h + * + * File read write routines for Visual Networks .cap files. + * Copyright 2001, Tom Nisbet tnisbet@visualnetworks.com + * + * Based on the code that handles netmon files. + * + * $Id: visual.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __VISUAL_H__ +#define __VISUAL_H__ + +int visual_open(wtap *wth, int *err, gchar **err_info); +gboolean visual_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); +int visual_dump_can_write_encap(int encap); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/vms.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/vms.h new file mode 100644 index 00000000..34083b07 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/vms.h @@ -0,0 +1,29 @@ +/* vms.h + * + * $Id: vms.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 2001 by Marc Milgram + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __W_VMS_H__ +#define __W_VMS_H__ + +int vms_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/wtap-int.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/wtap-int.h new file mode 100644 index 00000000..3f48d12c --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/wtap-int.h @@ -0,0 +1,482 @@ +/* wtap-int.h + * + * $Id: wtap-int.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __WTAP_INT_H__ +#define __WTAP_INT_H__ + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#include +#include +#include + +#ifdef HAVE_LIBZ +#ifdef HAVE_WINSOCK2_H +#include +#endif +#include +#define FILE_T gzFile +#else /* No zLib */ +#define FILE_T FILE * +#endif /* HAVE_LIBZ */ + +#include "wtap.h" + +/* Information for a compressed Sniffer data stream. */ +typedef struct { + unsigned char *buf; /* buffer into which we uncompress data */ + size_t nbytes; /* number of bytes of data in that buffer */ + int nextout; /* offset in that buffer of stream's current position */ + gint64 comp_offset; /* current offset in compressed data stream */ + gint64 uncomp_offset; /* current offset in uncompressed data stream */ +} ngsniffer_comp_stream_t; + +typedef struct { + char *sdate; /* Packet start date */ + gboolean tcp_formatted; /* TCP/IP data formated Y/N */ + int format; /* Trace format type */ +} iseries_t; + +typedef struct { + guint maj_vers; + guint min_vers; + guint32 timeunit; + time_t start; + guint network; /* network type */ + ngsniffer_comp_stream_t seq; /* sequential access */ + ngsniffer_comp_stream_t rand; /* random access */ + GList *first_blob; /* list element for first blob */ + GList *last_blob; /* list element for last blob */ + GList *current_blob; /* list element for current blob */ +} ngsniffer_t; + +typedef struct { + gboolean byte_swapped; +} i4btrace_t; + +typedef struct { + gboolean is_hpux_11; +} nettl_t; + +typedef struct { + time_t start; +} lanalyzer_t; + +typedef enum { + NOT_SWAPPED, + SWAPPED, + MAYBE_SWAPPED +} swapped_type_t; + +typedef struct { + gboolean byte_swapped; + swapped_type_t lengths_swapped; + guint16 version_major; + guint16 version_minor; +} libpcap_t; + +typedef struct { + gboolean byte_swapped; + guint16 version_major; + guint16 version_minor; + guint8 if_fcslen; +} pcapng_t; + +typedef struct { + time_t start_secs; + guint32 start_usecs; + guint8 version_major; + guint32 *frame_table; + guint32 frame_table_size; + guint current_frame; +} netmon_t; + +typedef struct { + time_t start_time; + double ticks_per_sec; + double start_timestamp; + gboolean wrapped; + guint32 nframes; + gint64 start_offset; + gint64 end_offset; + int version_major; + gboolean fcs_valid; /* if packets have valid FCS at the end */ + guint isdn_type; /* 1 = E1 PRI, 2 = T1 PRI, 3 = BRI */ +} netxray_t; + +typedef struct { + time_t inittime; + int adjusted; + gint64 next_packet_seek_start; +} ascend_t; + +typedef struct { + gboolean byteswapped; +} csids_t; + +typedef struct { + struct timeval reference_time; +} etherpeek_t; + +typedef struct { + gboolean has_fcs; +} airopeek9_t; + +typedef struct _k12_t k12_t; + +typedef struct { + time_t start_secs; + guint32 start_usecs; +} catapult_dct2000_t; + +typedef struct { + struct wtap_nstime now; + time_t t0; +} mpeg_t; + +typedef gboolean (*subtype_read_func)(struct wtap*, int*, char**, gint64*); +typedef gboolean (*subtype_seek_read_func)(struct wtap*, gint64, union wtap_pseudo_header*, + guint8*, int, int *, char **); +struct wtap { + FILE_T fh; + int fd; /* File descriptor for cap file */ + FILE_T random_fh; /* Secondary FILE_T for random access */ + int file_type; + int snapshot_length; + struct Buffer *frame_buffer; + struct wtap_pkthdr phdr; + union wtap_pseudo_header pseudo_header; + + gint64 data_offset; + + union { + libpcap_t *pcap; + lanalyzer_t *lanalyzer; + ngsniffer_t *ngsniffer; + iseries_t *iseries; + i4btrace_t *i4btrace; + nettl_t *nettl; + netmon_t *netmon; + netxray_t *netxray; + ascend_t *ascend; + csids_t *csids; + etherpeek_t *etherpeek; + airopeek9_t *airopeek9; + k12_t *k12; + catapult_dct2000_t *catapult_dct2000; + mpeg_t *mpeg; + void *generic; + pcapng_t *pcapng; + } capture; + + subtype_read_func subtype_read; + subtype_seek_read_func subtype_seek_read; + void (*subtype_sequential_close)(struct wtap*); + void (*subtype_close)(struct wtap*); + int file_encap; /* per-file, for those + file formats that have + per-file encapsulation + types */ + int tsprecision; /* timestamp precision of the lower 32bits + * e.g. WTAP_FILE_TSPREC_USEC */ +}; + +struct wtap_dumper; + +typedef gboolean (*subtype_write_func)(struct wtap_dumper*, + const struct wtap_pkthdr*, const union wtap_pseudo_header*, + const guchar*, int*); +typedef gboolean (*subtype_close_func)(struct wtap_dumper*, int*); + +typedef struct { + gboolean first_frame; + time_t start; +} ngsniffer_dump_t; + +typedef struct { + gboolean first_frame; + struct wtap_nstime start; + guint32 nframes; +} netxray_dump_t; + +typedef struct { + gboolean got_first_record_time; + struct wtap_nstime first_record_time; + guint32 frame_table_offset; + guint32 *frame_table; + guint frame_table_index; + guint frame_table_size; +} netmon_dump_t; + +typedef struct { + guint32 nframes; +} _5views_dump_t; + +typedef struct { + guint64 packet_count; + guint8 network_type; +} niobserver_dump_t; + +typedef struct { + guint32 file_len; + guint32 num_of_records; + guint32 file_offset; +} k12_dump_t; + +typedef struct { + gboolean first_packet_written; + struct wtap_nstime start_time; +} dct2000_dump_t; + +struct wtap_dumper { + FILE* fh; + int file_type; + int snaplen; + int encap; + gboolean compressed; + gint64 bytes_dumped; + + union { + void *opaque; + ngsniffer_dump_t *ngsniffer; + netmon_dump_t *netmon; + netxray_dump_t *netxray; + _5views_dump_t *_5views; + niobserver_dump_t *niobserver; + k12_dump_t *k12; + dct2000_dump_t *dct2000; + } dump; + + subtype_write_func subtype_write; + subtype_close_func subtype_close; + + int tsprecision; /* timestamp precision of the lower 32bits + * e.g. WTAP_FILE_TSPREC_USEC */ +}; + +extern size_t wtap_dump_file_write(wtap_dumper *wdh, const void *buf, unsigned bufsize); +extern int wtap_dump_file_ferror(wtap_dumper *wdh); + +extern gint wtap_num_file_types; + +/* Macros to byte-swap 64-bit, 32-bit and 16-bit quantities. */ +#define BSWAP64(x) \ + ((((x)&G_GINT64_CONSTANT(0xFF00000000000000U))>>56) | \ + (((x)&G_GINT64_CONSTANT(0x00FF000000000000U))>>40) | \ + (((x)&G_GINT64_CONSTANT(0x0000FF0000000000U))>>24) | \ + (((x)&G_GINT64_CONSTANT(0x000000FF00000000U))>>8) | \ + (((x)&G_GINT64_CONSTANT(0x00000000FF000000U))<<8) | \ + (((x)&G_GINT64_CONSTANT(0x0000000000FF0000U))<<24) | \ + (((x)&G_GINT64_CONSTANT(0x000000000000FF00U))<<40) | \ + (((x)&G_GINT64_CONSTANT(0x00000000000000FFU))<<56)) +#define BSWAP32(x) \ + ((((x)&0xFF000000)>>24) | \ + (((x)&0x00FF0000)>>8) | \ + (((x)&0x0000FF00)<<8) | \ + (((x)&0x000000FF)<<24)) +#define BSWAP16(x) \ + ((((x)&0xFF00)>>8) | \ + (((x)&0x00FF)<<8)) + +/* Macros to byte-swap possibly-unaligned 32-bit and 16-bit quantities; + * they take a pointer to the quantity, and byte-swap it in place. + */ +#define PBSWAP32(p) \ + { \ + guint8 tmp; \ + tmp = (p)[3]; \ + (p)[3] = (p)[0]; \ + (p)[0] = tmp; \ + tmp = (p)[2]; \ + (p)[2] = (p)[1]; \ + (p)[1] = tmp; \ + } +#define PBSWAP16(p) \ + { \ + guint8 tmp; \ + tmp = (p)[1]; \ + (p)[1] = (p)[0]; \ + (p)[0] = tmp; \ + } + +/* Turn host-byte-order values into little-endian values. */ +#define htoles(s) GUINT16_TO_LE(s) +#define htolel(l) GUINT32_TO_LE(l) +#define htolell(ll) GUINT64_TO_LE(ll) + +/* Pointer versions of ntohs and ntohl. Given a pointer to a member of a + * byte array, returns the value of the two or four bytes at the pointer. + * The pletoh[sl] versions return the little-endian representation. + * We also provide pntohll and pletohll, which extract 64-bit integral + * quantities. + * + * These will work regardless of the byte alignment of the pointer. + */ + +#ifndef pntohs +#define pntohs(p) ((guint16) \ + ((guint16)*((const guint8 *)(p)+0)<<8| \ + (guint16)*((const guint8 *)(p)+1)<<0)) +#endif + +#ifndef pntoh24 +#define pntoh24(p) ((guint32)*((const guint8 *)(p)+0)<<16| \ + (guint32)*((const guint8 *)(p)+1)<<8| \ + (guint32)*((const guint8 *)(p)+2)<<0) +#endif + +#ifndef pntohl +#define pntohl(p) ((guint32)*((const guint8 *)(p)+0)<<24| \ + (guint32)*((const guint8 *)(p)+1)<<16| \ + (guint32)*((const guint8 *)(p)+2)<<8| \ + (guint32)*((const guint8 *)(p)+3)<<0) +#endif + +#ifndef pntohll +#define pntohll(p) ((guint64)*((const guint8 *)(p)+0)<<56| \ + (guint64)*((const guint8 *)(p)+1)<<48| \ + (guint64)*((const guint8 *)(p)+2)<<40| \ + (guint64)*((const guint8 *)(p)+3)<<32| \ + (guint64)*((const guint8 *)(p)+4)<<24| \ + (guint64)*((const guint8 *)(p)+5)<<16| \ + (guint64)*((const guint8 *)(p)+6)<<8| \ + (guint64)*((const guint8 *)(p)+7)<<0) +#endif + + +#ifndef pletohs +#define pletohs(p) ((guint16) \ + ((guint16)*((const guint8 *)(p)+1)<<8| \ + (guint16)*((const guint8 *)(p)+0)<<0)) +#endif + +#ifndef pletoh24 +#define pletoh24(p) ((guint32)*((const guint8 *)(p)+2)<<16| \ + (guint32)*((const guint8 *)(p)+1)<<8| \ + (guint32)*((const guint8 *)(p)+0)<<0) +#endif + + +#ifndef pletohl +#define pletohl(p) ((guint32)*((const guint8 *)(p)+3)<<24| \ + (guint32)*((const guint8 *)(p)+2)<<16| \ + (guint32)*((const guint8 *)(p)+1)<<8| \ + (guint32)*((const guint8 *)(p)+0)<<0) +#endif + + +#ifndef pletohll +#define pletohll(p) ((guint64)*((const guint8 *)(p)+7)<<56| \ + (guint64)*((const guint8 *)(p)+6)<<48| \ + (guint64)*((const guint8 *)(p)+5)<<40| \ + (guint64)*((const guint8 *)(p)+4)<<32| \ + (guint64)*((const guint8 *)(p)+3)<<24| \ + (guint64)*((const guint8 *)(p)+2)<<16| \ + (guint64)*((const guint8 *)(p)+1)<<8| \ + (guint64)*((const guint8 *)(p)+0)<<0) +#endif + +/* Pointer routines to put items out in a particular byte order. + * These will work regardless of the byte alignment of the pointer. + */ + +#ifndef phtons +#define phtons(p, v) \ + { \ + (p)[0] = (guint8)((v) >> 8); \ + (p)[1] = (guint8)((v) >> 0); \ + } +#endif + +#ifndef phtonl +#define phtonl(p, v) \ + { \ + (p)[0] = (guint8)((v) >> 24); \ + (p)[1] = (guint8)((v) >> 16); \ + (p)[2] = (guint8)((v) >> 8); \ + (p)[3] = (guint8)((v) >> 0); \ + } +#endif + +#ifndef phtonll +#define phtonll(p, v) \ + { \ + (p)[0] = (guint8)((v) >> 56); \ + (p)[1] = (guint8)((v) >> 48); \ + (p)[2] = (guint8)((v) >> 40); \ + (p)[3] = (guint8)((v) >> 32); \ + (p)[4] = (guint8)((v) >> 24); \ + (p)[5] = (guint8)((v) >> 16); \ + (p)[6] = (guint8)((v) >> 8); \ + (p)[7] = (guint8)((v) >> 0); \ + } +#endif + +#ifndef pletonll +#define pletonll(p, v) \ + { \ + (p)[0] = (guint8)((v) >> 0); \ + (p)[1] = (guint8)((v) >> 8); \ + (p)[2] = (guint8)((v) >> 16); \ + (p)[3] = (guint8)((v) >> 24); \ + (p)[4] = (guint8)((v) >> 32); \ + (p)[5] = (guint8)((v) >> 40); \ + (p)[6] = (guint8)((v) >> 48); \ + (p)[7] = (guint8)((v) >> 56); \ + } +#endif + +#define wtap_file_read_unknown_bytes(target, num_bytes, fh, err) \ + G_STMT_START \ + { \ + int _bytes_read; \ + _bytes_read = file_read((target), 1, (num_bytes), (fh)); \ + if (_bytes_read != (int) (num_bytes)) { \ + *(err) = file_error((fh)); \ + return FALSE; \ + } \ + } \ + G_STMT_END + +#define wtap_file_read_expected_bytes(target, num_bytes, fh, err) \ + G_STMT_START \ + { \ + int _bytes_read; \ + _bytes_read = file_read((target), 1, (num_bytes), (fh)); \ + if (_bytes_read != (int) (num_bytes)) { \ + *(err) = file_error((fh)); \ + if (*(err) == 0 && _bytes_read > 0) { \ + *(err) = WTAP_ERR_SHORT_READ; \ + } \ + return FALSE; \ + } \ + } \ + G_STMT_END + +/* glib doesn't have g_ptr_array_len of all things!*/ +#ifndef g_ptr_array_len +#define g_ptr_array_len(a) ((a)->len) +#endif + +#endif /* __WTAP_INT_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/wtap.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/wtap.h new file mode 100644 index 00000000..9f51c19f --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/wtap.h @@ -0,0 +1,944 @@ +/* wtap.h + * + * $Id: wtap.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __WTAP_H__ +#define __WTAP_H__ + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#ifdef HAVE_WINSOCK2_H +# include +#endif + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Encapsulation types. Choose names that truly reflect + * what is contained in the packet trace file. + * + * WTAP_ENCAP_PER_PACKET is a value passed to "wtap_dump_open()" or + * "wtap_dump_fd_open()" to indicate that there is no single encapsulation + * type for all packets in the file; this may cause those routines to + * fail if the capture file format being written can't support that. + * It's also returned by "wtap_file_encap()" for capture files that + * don't have a single encapsulation type for all packets in the file. + * + * WTAP_ENCAP_UNKNOWN is returned by "wtap_pcap_encap_to_wtap_encap()" + * if it's handed an unknown encapsulation. + * + * WTAP_ENCAP_FDDI_BITSWAPPED is for FDDI captures on systems where the + * MAC addresses you get from the hardware are bit-swapped. Ideally, + * the driver would tell us that, but I know of none that do, so, for + * now, we base it on the machine on which we're *reading* the + * capture, rather than on the machine on which the capture was taken + * (they're probably likely to be the same). We assume that they're + * bit-swapped on everything except for systems running Ultrix, Alpha + * systems, and BSD/OS systems (that's what "tcpdump" does; I guess + * Digital decided to bit-swap addresses in the hardware or in the + * driver, and I guess BSDI bit-swapped them in the driver, given that + * BSD/OS generally runs on Boring Old PC's). If we create a wiretap + * save file format, we'd use the WTAP_ENCAP values to flag the + * encapsulation of a packet, so there we'd at least be able to base + * it on the machine on which the capture was taken. + * + * WTAP_ENCAP_LINUX_ATM_CLIP is the encapsulation you get with the + * ATM on Linux code from ; + * that code adds a DLT_ATM_CLIP DLT_ code of 19, and that + * encapsulation isn't the same as the DLT_ATM_RFC1483 encapsulation + * presumably used on some BSD systems, which we turn into + * WTAP_ENCAP_ATM_RFC1483. + * + * WTAP_ENCAP_NULL corresponds to DLT_NULL from "libpcap". This + * corresponds to + * + * 1) PPP-over-HDLC encapsulation, at least with some versions + * of ISDN4BSD (but not the current ones, it appears, unless + * I've missed something); + * + * 2) a 4-byte header containing the AF_ address family, in + * the byte order of the machine that saved the capture, + * for the packet, as used on many BSD systems for the + * loopback device and some other devices, or a 4-byte header + * containing the AF_ address family in network byte order, + * as used on recent OpenBSD systems for the loopback device; + * + * 3) a 4-byte header containing 2 octets of 0 and an Ethernet + * type in the byte order from an Ethernet header, that being + * what older versions of "libpcap" on Linux turn the Ethernet + * header for loopback interfaces into (0.6.0 and later versions + * leave the Ethernet header alone and make it DLT_EN10MB). */ +#define WTAP_ENCAP_PER_PACKET -1 +#define WTAP_ENCAP_UNKNOWN 0 +#define WTAP_ENCAP_ETHERNET 1 +#define WTAP_ENCAP_TOKEN_RING 2 +#define WTAP_ENCAP_SLIP 3 +#define WTAP_ENCAP_PPP 4 +#define WTAP_ENCAP_FDDI 5 +#define WTAP_ENCAP_FDDI_BITSWAPPED 6 +#define WTAP_ENCAP_RAW_IP 7 +#define WTAP_ENCAP_ARCNET 8 +#define WTAP_ENCAP_ARCNET_LINUX 9 +#define WTAP_ENCAP_ATM_RFC1483 10 +#define WTAP_ENCAP_LINUX_ATM_CLIP 11 +#define WTAP_ENCAP_LAPB 12 +#define WTAP_ENCAP_ATM_PDUS 13 +#define WTAP_ENCAP_ATM_PDUS_UNTRUNCATED 14 +#define WTAP_ENCAP_NULL 15 +#define WTAP_ENCAP_ASCEND 16 +#define WTAP_ENCAP_ISDN 17 +#define WTAP_ENCAP_IP_OVER_FC 18 +#define WTAP_ENCAP_PPP_WITH_PHDR 19 +#define WTAP_ENCAP_IEEE_802_11 20 +#define WTAP_ENCAP_PRISM_HEADER 21 +#define WTAP_ENCAP_IEEE_802_11_WITH_RADIO 22 +#define WTAP_ENCAP_IEEE_802_11_WLAN_RADIOTAP 23 +#define WTAP_ENCAP_IEEE_802_11_WLAN_AVS 24 +#define WTAP_ENCAP_SLL 25 +#define WTAP_ENCAP_FRELAY 26 +#define WTAP_ENCAP_FRELAY_WITH_PHDR 27 +#define WTAP_ENCAP_CHDLC 28 +#define WTAP_ENCAP_CISCO_IOS 29 +#define WTAP_ENCAP_LOCALTALK 30 +#define WTAP_ENCAP_OLD_PFLOG 31 +#define WTAP_ENCAP_HHDLC 32 +#define WTAP_ENCAP_DOCSIS 33 +#define WTAP_ENCAP_COSINE 34 +#define WTAP_ENCAP_WFLEET_HDLC 35 +#define WTAP_ENCAP_SDLC 36 +#define WTAP_ENCAP_TZSP 37 +#define WTAP_ENCAP_ENC 38 +#define WTAP_ENCAP_PFLOG 39 +#define WTAP_ENCAP_CHDLC_WITH_PHDR 40 +#define WTAP_ENCAP_BLUETOOTH_H4 41 +#define WTAP_ENCAP_MTP2 42 +#define WTAP_ENCAP_MTP3 43 +#define WTAP_ENCAP_IRDA 44 +#define WTAP_ENCAP_USER0 45 +#define WTAP_ENCAP_USER1 46 +#define WTAP_ENCAP_USER2 47 +#define WTAP_ENCAP_USER3 48 +#define WTAP_ENCAP_USER4 49 +#define WTAP_ENCAP_USER5 50 +#define WTAP_ENCAP_USER6 51 +#define WTAP_ENCAP_USER7 52 +#define WTAP_ENCAP_USER8 53 +#define WTAP_ENCAP_USER9 54 +#define WTAP_ENCAP_USER10 55 +#define WTAP_ENCAP_USER11 56 +#define WTAP_ENCAP_USER12 57 +#define WTAP_ENCAP_USER13 58 +#define WTAP_ENCAP_USER14 59 +#define WTAP_ENCAP_USER15 60 +#define WTAP_ENCAP_SYMANTEC 61 +#define WTAP_ENCAP_APPLE_IP_OVER_IEEE1394 62 +#define WTAP_ENCAP_BACNET_MS_TP 63 +#define WTAP_ENCAP_NETTL_RAW_ICMP 64 +#define WTAP_ENCAP_NETTL_RAW_ICMPV6 65 +#define WTAP_ENCAP_GPRS_LLC 66 +#define WTAP_ENCAP_JUNIPER_ATM1 67 +#define WTAP_ENCAP_JUNIPER_ATM2 68 +#define WTAP_ENCAP_REDBACK 69 +#define WTAP_ENCAP_NETTL_RAW_IP 70 +#define WTAP_ENCAP_NETTL_ETHERNET 71 +#define WTAP_ENCAP_NETTL_TOKEN_RING 72 +#define WTAP_ENCAP_NETTL_FDDI 73 +#define WTAP_ENCAP_NETTL_UNKNOWN 74 +#define WTAP_ENCAP_MTP2_WITH_PHDR 75 +#define WTAP_ENCAP_JUNIPER_PPPOE 76 +#define WTAP_GCOM_TIE1 77 +#define WTAP_GCOM_SERIAL 78 +#define WTAP_ENCAP_NETTL_X25 79 +#define WTAP_ENCAP_K12 80 +#define WTAP_ENCAP_JUNIPER_MLPPP 81 +#define WTAP_ENCAP_JUNIPER_MLFR 82 +#define WTAP_ENCAP_JUNIPER_ETHER 83 +#define WTAP_ENCAP_JUNIPER_PPP 84 +#define WTAP_ENCAP_JUNIPER_FRELAY 85 +#define WTAP_ENCAP_JUNIPER_CHDLC 86 +#define WTAP_ENCAP_JUNIPER_GGSN 87 +#define WTAP_ENCAP_LINUX_LAPD 88 +#define WTAP_ENCAP_CATAPULT_DCT2000 89 +#define WTAP_ENCAP_BER 90 +#define WTAP_ENCAP_JUNIPER_VP 91 +#define WTAP_ENCAP_USB 92 +#define WTAP_ENCAP_IEEE802_16_MAC_CPS 93 +#define WTAP_ENCAP_NETTL_RAW_TELNET 94 +#define WTAP_ENCAP_USB_LINUX 95 +#define WTAP_ENCAP_MPEG 96 +#define WTAP_ENCAP_PPI 97 +#define WTAP_ENCAP_ERF 98 +#define WTAP_ENCAP_BLUETOOTH_H4_WITH_PHDR 99 +#define WTAP_ENCAP_SITA 100 +#define WTAP_ENCAP_SCCP 101 +#define WTAP_ENCAP_BLUETOOTH_HCI 102 /*raw packets without a transport layer header e.g. H4*/ +#define WTAP_ENCAP_IPMB 103 +#define WTAP_ENCAP_IEEE802_15_4 104 +#define WTAP_ENCAP_X2E_XORAYA 105 +#define WTAP_ENCAP_FLEXRAY 106 +#define WTAP_ENCAP_LIN 107 +#define WTAP_ENCAP_MOST 108 +#define WTAP_ENCAP_CAN20B 109 + +#define WTAP_NUM_ENCAP_TYPES wtap_get_num_encap_types() + +/* File types that can be read by wiretap. + We support writing some many of these file types, too, so we + distinguish between different versions of them. */ +#define WTAP_FILE_UNKNOWN 0 +#define WTAP_FILE_WTAP 1 +#define WTAP_FILE_PCAP 2 +#define WTAP_FILE_PCAP_NSEC 3 +#define WTAP_FILE_PCAP_AIX 4 +#define WTAP_FILE_PCAP_SS991029 5 +#define WTAP_FILE_PCAP_NOKIA 6 +#define WTAP_FILE_PCAP_SS990417 7 +#define WTAP_FILE_PCAP_SS990915 8 +#define WTAP_FILE_5VIEWS 9 +#define WTAP_FILE_IPTRACE_1_0 10 +#define WTAP_FILE_IPTRACE_2_0 11 +#define WTAP_FILE_BER 12 +#define WTAP_FILE_HCIDUMP 13 +#define WTAP_FILE_CATAPULT_DCT2000 14 +#define WTAP_FILE_NETXRAY_OLD 15 +#define WTAP_FILE_NETXRAY_1_0 16 +#define WTAP_FILE_COSINE 17 +#define WTAP_FILE_CSIDS 18 +#define WTAP_FILE_DBS_ETHERWATCH 19 +#define WTAP_FILE_ERF 20 +#define WTAP_FILE_EYESDN 21 +#define WTAP_FILE_NETTL 22 +#define WTAP_FILE_ISERIES 23 +#define WTAP_FILE_ISERIES_UNICODE 24 +#define WTAP_FILE_I4BTRACE 25 +#define WTAP_FILE_ASCEND 26 +#define WTAP_FILE_NETMON_1_x 27 +#define WTAP_FILE_NETMON_2_x 28 +#define WTAP_FILE_NGSNIFFER_UNCOMPRESSED 29 +#define WTAP_FILE_NGSNIFFER_COMPRESSED 30 +#define WTAP_FILE_NETXRAY_1_1 31 +#define WTAP_FILE_NETXRAY_2_00x 32 +#define WTAP_FILE_NETWORK_INSTRUMENTS_V9 33 +#define WTAP_FILE_LANALYZER 34 +#define WTAP_FILE_PPPDUMP 35 +#define WTAP_FILE_RADCOM 36 +#define WTAP_FILE_SNOOP 37 +#define WTAP_FILE_SHOMITI 38 +#define WTAP_FILE_VMS 39 +#define WTAP_FILE_K12 40 +#define WTAP_FILE_TOSHIBA 41 +#define WTAP_FILE_VISUAL_NETWORKS 42 +#define WTAP_FILE_ETHERPEEK_V56 43 +#define WTAP_FILE_ETHERPEEK_V7 44 +#define WTAP_FILE_AIROPEEK_V9 45 +#define WTAP_FILE_MPEG 46 +#define WTAP_FILE_K12TEXT 47 +#define WTAP_FILE_NETSCREEN 48 +#define WTAP_FILE_COMMVIEW 49 +#define WTAP_FILE_PCAPNG 50 +#define WTAP_FILE_BTSNOOP 51 +#define WTAP_FILE_X2E_XORAYA 52 + +#define WTAP_NUM_FILE_TYPES wtap_get_num_file_types() + +/* timestamp precision (currently only these values are supported) */ +#define WTAP_FILE_TSPREC_SEC 0 +#define WTAP_FILE_TSPREC_DSEC 1 +#define WTAP_FILE_TSPREC_CSEC 2 +#define WTAP_FILE_TSPREC_MSEC 3 +#define WTAP_FILE_TSPREC_USEC 6 +#define WTAP_FILE_TSPREC_NSEC 9 + +/* + * Maximum packet size we'll support. + * It must be at least 65535. + */ +#define WTAP_MAX_PACKET_SIZE 65535 + +/* + * "Pseudo-headers" are used to supply to the clients of wiretap + * per-packet information that's not part of the packet payload + * proper. + * + * NOTE: do not use pseudo-header structures to hold information + * used by the code to read a particular capture file type; to + * keep that sort of state information, add a new structure for + * that private information to "wtap-int.h", add a pointer to that + * type of structure to the "capture" member of the "struct wtap" + * structure, and allocate one of those structures and set that member + * in the "open" routine for that capture file type if the open + * succeeds. See various other capture file type handlers for examples + * of that. + */ + +/* Packet "pseudo-header" information for Ethernet capture files. */ +struct eth_phdr { + gint fcs_len; /* Number of bytes of FCS - -1 means "unknown" */ +}; + +/* Packet "pseudo-header" information for X.25 capture files. */ +#define FROM_DCE 0x80 +struct x25_phdr { + guint8 flags; /* ENCAP_LAPB, ENCAP_V120 : 1st bit means From DCE */ +}; + +/* Packet "pseudo-header" information for ISDN capture files. */ + +/* Direction */ +struct isdn_phdr { + gboolean uton; + guint8 channel; /* 0 = D-channel; n = B-channel n */ +}; + +/* Packet "pseudo-header" for ATM capture files. + Not all of this information is supplied by all capture types. */ + +/* + * Status bits. + */ +#define ATM_RAW_CELL 0x01 /* TRUE if the packet is a single cell */ + +/* + * AAL types. + */ +#define AAL_UNKNOWN 0 /* AAL unknown */ +#define AAL_1 1 /* AAL1 */ +#define AAL_2 2 /* AAL2 */ +#define AAL_3_4 3 /* AAL3/4 */ +#define AAL_5 4 /* AAL5 */ +#define AAL_USER 5 /* User AAL */ +#define AAL_SIGNALLING 6 /* Signaling AAL */ +#define AAL_OAMCELL 7 /* OAM cell */ + +/* + * Traffic types. + */ +#define TRAF_UNKNOWN 0 /* Unknown */ +#define TRAF_LLCMX 1 /* LLC multiplexed (RFC 1483) */ +#define TRAF_VCMX 2 /* VC multiplexed (RFC 1483) */ +#define TRAF_LANE 3 /* LAN Emulation */ +#define TRAF_ILMI 4 /* ILMI */ +#define TRAF_FR 5 /* Frame Relay */ +#define TRAF_SPANS 6 /* FORE SPANS */ +#define TRAF_IPSILON 7 /* Ipsilon */ +#define TRAF_UMTS_FP 8 /* UMTS Frame Protocol */ + +/* + * Traffic subtypes. + */ +#define TRAF_ST_UNKNOWN 0 /* Unknown */ + +/* + * For TRAF_VCMX: + */ +#define TRAF_ST_VCMX_802_3_FCS 1 /* 802.3 with an FCS */ +#define TRAF_ST_VCMX_802_4_FCS 2 /* 802.4 with an FCS */ +#define TRAF_ST_VCMX_802_5_FCS 3 /* 802.5 with an FCS */ +#define TRAF_ST_VCMX_FDDI_FCS 4 /* FDDI with an FCS */ +#define TRAF_ST_VCMX_802_6_FCS 5 /* 802.6 with an FCS */ +#define TRAF_ST_VCMX_802_3 7 /* 802.3 without an FCS */ +#define TRAF_ST_VCMX_802_4 8 /* 802.4 without an FCS */ +#define TRAF_ST_VCMX_802_5 9 /* 802.5 without an FCS */ +#define TRAF_ST_VCMX_FDDI 10 /* FDDI without an FCS */ +#define TRAF_ST_VCMX_802_6 11 /* 802.6 without an FCS */ +#define TRAF_ST_VCMX_FRAGMENTS 12 /* Fragments */ +#define TRAF_ST_VCMX_BPDU 13 /* BPDU */ + +/* + * For TRAF_LANE: + */ +#define TRAF_ST_LANE_LE_CTRL 1 /* LANE: LE Ctrl */ +#define TRAF_ST_LANE_802_3 2 /* LANE: 802.3 */ +#define TRAF_ST_LANE_802_5 3 /* LANE: 802.5 */ +#define TRAF_ST_LANE_802_3_MC 4 /* LANE: 802.3 multicast */ +#define TRAF_ST_LANE_802_5_MC 5 /* LANE: 802.5 multicast */ + +/* + * For TRAF_IPSILON: + */ +#define TRAF_ST_IPSILON_FT0 1 /* Ipsilon: Flow Type 0 */ +#define TRAF_ST_IPSILON_FT1 2 /* Ipsilon: Flow Type 1 */ +#define TRAF_ST_IPSILON_FT2 3 /* Ipsilon: Flow Type 2 */ + +struct atm_phdr { + guint32 flags; /* status flags */ + guint8 aal; /* AAL of the traffic */ + guint8 type; /* traffic type */ + guint8 subtype; /* traffic subtype */ + guint16 vpi; /* virtual path identifier */ + guint16 vci; /* virtual circuit identifier */ + guint8 aal2_cid; /* channel id */ + guint16 channel; /* link: 0 for DTE->DCE, 1 for DCE->DTE */ + guint16 cells; /* number of cells */ + guint16 aal5t_u2u; /* user-to-user indicator */ + guint16 aal5t_len; /* length of the packet */ + guint32 aal5t_chksum; /* checksum for AAL5 packet */ +}; + +/* Packet "pseudo-header" for the output from "wandsession", "wannext", + "wandisplay", and similar commands on Lucent/Ascend access equipment. */ + +#define ASCEND_MAX_STR_LEN 64 + +#define ASCEND_PFX_WDS_X 1 +#define ASCEND_PFX_WDS_R 2 +#define ASCEND_PFX_WDD 3 +#define ASCEND_PFX_ISDN_X 4 +#define ASCEND_PFX_ISDN_R 5 +#define ASCEND_PFX_ETHER 6 + +struct ascend_phdr { + guint16 type; /* ASCEND_PFX_*, as defined above */ + char user[ASCEND_MAX_STR_LEN]; /* Username, from wandsession header */ + guint32 sess; /* Session number, from wandsession header */ + char call_num[ASCEND_MAX_STR_LEN]; /* Called number, from WDD header */ + guint32 chunk; /* Chunk number, from WDD header */ + guint32 task; /* Task number */ +}; + +/* Packet "pseudo-header" for point-to-point links with direction flags. */ +struct p2p_phdr { + gboolean sent; /* TRUE=sent, FALSE=received */ +}; + +/* + * Packet "pseudo-header" information for 802.11. + * Radio information is only present for WTAP_ENCAP_IEEE_802_11_WITH_RADIO. + * + * Signal strength, etc. information: + * + * Raw signal strength can be measured in milliwatts. + * It can also be represented as dBm, which is 10 times the log base 10 + * of the signal strength in mW. + * + * The Receive Signal Strength Indicator is an integer in the range 0 to 255. + * The actual RSSI value for a given signal strength is dependent on the + * vendor (and perhaps on the adapter). The maximum possible RSSI value + * is also dependent on the vendor and perhaps the adapter. + * + * The signal strength can be represented as a percentage, which is 100 + * times the ratio of the RSSI and the maximum RSSI. + */ +struct ieee_802_11_phdr { + gint fcs_len; /* Number of bytes of FCS - -1 means "unknown" */ + guint8 channel; /* Channel number */ + guint8 data_rate; /* in .5 Mb/s units */ + guint8 signal_level; /* percentage */ +}; + +/* Packet "pseudo-header" for the output from CoSine L2 debug output. */ + +#define COSINE_MAX_IF_NAME_LEN 128 + +#define COSINE_ENCAP_TEST 1 +#define COSINE_ENCAP_PPoATM 2 +#define COSINE_ENCAP_PPoFR 3 +#define COSINE_ENCAP_ATM 4 +#define COSINE_ENCAP_FR 5 +#define COSINE_ENCAP_HDLC 6 +#define COSINE_ENCAP_PPP 7 +#define COSINE_ENCAP_ETH 8 +#define COSINE_ENCAP_UNKNOWN 99 + +#define COSINE_DIR_TX 1 +#define COSINE_DIR_RX 2 + +struct cosine_phdr { + guint8 encap; /* COSINE_ENCAP_* as defined above */ + guint8 direction; /* COSINE_DIR_*, as defined above */ + char if_name[COSINE_MAX_IF_NAME_LEN]; /* Encap & Logical I/F name */ + guint16 pro; /* Protocol */ + guint16 off; /* Offset */ + guint16 pri; /* Priority */ + guint16 rm; /* Rate Marking */ + guint16 err; /* Error Code */ +}; + +/* Packet "pseudo-header" for IrDA capture files. */ + +/* + * Direction of the packet + */ +#define IRDA_INCOMING 0x0000 +#define IRDA_OUTGOING 0x0004 + +/* + * "Inline" log messages produced by IrCOMM2k on Windows + */ +#define IRDA_LOG_MESSAGE 0x0100 /* log message */ +#define IRDA_MISSED_MSG 0x0101 /* missed log entry or frame */ + +/* + * Differentiate between frames and log messages + */ +#define IRDA_CLASS_FRAME 0x0000 +#define IRDA_CLASS_LOG 0x0100 +#define IRDA_CLASS_MASK 0xFF00 + +struct irda_phdr { + guint16 pkttype; /* packet type */ +}; + +/* Packet "pseudo-header" for nettl (HP-UX) capture files. */ + +struct nettl_phdr { + guint16 subsys; + guint32 devid; + guint32 kind; + gint32 pid; + guint16 uid; +}; + +/* Packet "pseudo-header" for MTP2 files. */ + +#define MTP2_ANNEX_A_NOT_USED 0 +#define MTP2_ANNEX_A_USED 1 +#define MTP2_ANNEX_A_USED_UNKNOWN 2 + +struct mtp2_phdr { + guint8 sent; + guint8 annex_a_used; + guint16 link_number; +}; + +/* Packet "pseudo-header" for K12 files. */ + +typedef union { + struct { + guint16 vp; + guint16 vc; + guint16 cid; + } atm; + + guint32 ds0mask; +} k12_input_info_t; + +struct k12_phdr { + guint32 input; + const gchar* input_name; + const gchar* stack_file; + guint32 input_type; + k12_input_info_t input_info; + gchar* extra_info; + guint32 extra_length; + void* stuff; +}; + +#define K12_PORT_DS0S 0x00010008 +#define K12_PORT_DS1 0x00100008 +#define K12_PORT_ATMPVC 0x01020000 + +struct lapd_phdr { + guint16 pkttype; /* packet type */ + guint8 we_network; +}; + +struct wtap; +struct catapult_dct2000_phdr +{ + union + { + struct isdn_phdr isdn; + struct atm_phdr atm; + struct p2p_phdr p2p; + } inner_pseudo_header; + gint64 seek_off; + struct wtap *wth; +}; + +/* + * possible event type + */ +#define URB_SUBMIT 'S' +#define URB_COMPLETE 'C' +#define URB_ERROR 'E' + +/* + * possible transfer mode + */ +#define URB_ISOCHRONOUS 0x0 +#define URB_INTERRUPT 0x1 +#define URB_CONTROL 0x2 +#define URB_BULK 0x3 + +#define URB_TRANSFER_IN 0x80 /* to host */ + +/* + * USB setup header as defined in USB specification + */ +struct usb_request_hdr { + gint8 bmRequestType; + guint8 bRequest; + guint16 wValue; + guint16 wIndex; + guint16 wLength; +}; + +/* + * Header prepended by Linux kernel to each USB event. + * Followed by a struct usb_request_hdr, although that header is valid + * only if setup_flag is 0. + * (Setup flag is '-', 'D', 'Z', or 0. Data flag is '<', '>', 'Z', or 0.) + * + * We present this as a pseudo-header; the values are in host byte order. + */ +struct linux_usb_phdr { + guint64 id; /* urb id, to link submission and completion events*/ + guint8 event_type; /* Submit ('S'), Completed ('C'), Error ('E') */ + guint8 transfer_type; /* ISO (0), Intr, Control, Bulk (3) */ + guint8 endpoint_number; /* Endpoint number (0-15) and transfer direction */ + guint8 device_address; /* 0-127 */ + guint16 bus_id; + gint8 setup_flag; /*if !=0 the urb setup header is not present*/ + gint8 data_flag; /*if !=0 no urb data is present*/ + gint64 ts_sec; + gint32 ts_usec; + gint32 status; + guint32 urb_len; /* whole len of urb this event refers to */ + guint32 data_len; /* amount of urb data really present in this event*/ +}; + +/* + * Header prepended by libpcap to each bluetooth hci h:4 frame. + * Values in network byte order + */ +struct libpcap_bt_phdr { + guint32 direction; /* Bit 0 hold the frame direction. */ +}; + +/* + * Endace Record Format pseudo header + */ +struct erf_phdr { + guint64 ts; /* Time stamp */ + guint8 type; + guint8 flags; + guint16 rlen; + guint16 lctr; + guint16 wlen; +}; + +/* + * ERF pseudo header with optional subheader + * (Multichannel or Ethernet) + */ +struct erf_mc_phdr { + struct erf_phdr phdr; + union + { + guint16 eth_hdr; + guint32 mc_hdr; + } subhdr; +}; + +#define SITA_FRAME_DIR_TXED (0x00) /* values of sita_phdr.flags */ +#define SITA_FRAME_DIR_RXED (0x01) +#define SITA_FRAME_DIR (0x01) /* mask */ +#define SITA_ERROR_NO_BUFFER (0x80) + +#define SITA_SIG_DSR (0x01) /* values of sita_phdr.signals */ +#define SITA_SIG_DTR (0x02) +#define SITA_SIG_CTS (0x04) +#define SITA_SIG_RTS (0x08) +#define SITA_SIG_DCD (0x10) +#define SITA_SIG_UNDEF1 (0x20) +#define SITA_SIG_UNDEF2 (0x40) +#define SITA_SIG_UNDEF3 (0x80) + +#define SITA_ERROR_TX_UNDERRUN (0x01) /* values of sita_phdr.errors2 (if SITA_FRAME_DIR_TXED) */ +#define SITA_ERROR_TX_CTS_LOST (0x02) +#define SITA_ERROR_TX_UART_ERROR (0x04) +#define SITA_ERROR_TX_RETX_LIMIT (0x08) +#define SITA_ERROR_TX_UNDEF1 (0x10) +#define SITA_ERROR_TX_UNDEF2 (0x20) +#define SITA_ERROR_TX_UNDEF3 (0x40) +#define SITA_ERROR_TX_UNDEF4 (0x80) + +#define SITA_ERROR_RX_FRAMING (0x01) /* values of sita_phdr.errors1 (if SITA_FRAME_DIR_RXED) */ +#define SITA_ERROR_RX_PARITY (0x02) +#define SITA_ERROR_RX_COLLISION (0x04) +#define SITA_ERROR_RX_FRAME_LONG (0x08) +#define SITA_ERROR_RX_FRAME_SHORT (0x10) +#define SITA_ERROR_RX_UNDEF1 (0x20) +#define SITA_ERROR_RX_UNDEF2 (0x40) +#define SITA_ERROR_RX_UNDEF3 (0x80) + +#define SITA_ERROR_RX_NONOCTET_ALIGNED (0x01) /* values of sita_phdr.errors2 (if SITA_FRAME_DIR_RXED) */ +#define SITA_ERROR_RX_ABORT (0x02) +#define SITA_ERROR_RX_CD_LOST (0x04) +#define SITA_ERROR_RX_DPLL (0x08) +#define SITA_ERROR_RX_OVERRUN (0x10) +#define SITA_ERROR_RX_FRAME_LEN_VIOL (0x20) +#define SITA_ERROR_RX_CRC (0x40) +#define SITA_ERROR_RX_BREAK (0x80) + +#define SITA_PROTO_UNUSED (0x00) /* values of sita_phdr.proto */ +#define SITA_PROTO_BOP_LAPB (0x01) +#define SITA_PROTO_ETHERNET (0x02) +#define SITA_PROTO_ASYNC_INTIO (0x03) +#define SITA_PROTO_ASYNC_BLKIO (0x04) +#define SITA_PROTO_ALC (0x05) +#define SITA_PROTO_UTS (0x06) +#define SITA_PROTO_PPP_HDLC (0x07) +#define SITA_PROTO_SDLC (0x08) +#define SITA_PROTO_TOKENRING (0x09) +#define SITA_PROTO_I2C (0x10) +#define SITA_PROTO_DPM_LINK (0x11) +#define SITA_PROTO_BOP_FRL (0x12) + +struct sita_phdr { + guint8 flags; + guint8 signals; + guint8 errors1; + guint8 errors2; + guint8 proto; +}; + +/*pseudo header for Bluetooth HCI*/ +struct bthci_phdr { + gboolean sent; + guint8 channel; +}; + +#define BTHCI_CHANNEL_COMMAND 1 +#define BTHCI_CHANNEL_ACL 2 +#define BTHCI_CHANNEL_SCO 3 +#define BTHCI_CHANNEL_EVENT 4 + +union wtap_pseudo_header { + struct eth_phdr eth; + struct x25_phdr x25; + struct isdn_phdr isdn; + struct atm_phdr atm; + struct ascend_phdr ascend; + struct p2p_phdr p2p; + struct ieee_802_11_phdr ieee_802_11; + struct cosine_phdr cosine; + struct irda_phdr irda; + struct nettl_phdr nettl; + struct mtp2_phdr mtp2; + struct k12_phdr k12; + struct lapd_phdr lapd; + struct catapult_dct2000_phdr dct2000; + struct linux_usb_phdr linux_usb; + struct erf_mc_phdr erf; + struct sita_phdr sita; + struct bthci_phdr bthci; +}; + +struct wtap_nstime { + time_t secs; + int nsecs; +}; + +struct wtap_pkthdr { + struct wtap_nstime ts; + guint32 caplen; + guint32 len; + int pkt_encap; +}; + +struct wtap; +struct Buffer; +struct wtap_dumper; + +typedef struct wtap wtap; +typedef struct wtap_dumper wtap_dumper; + +struct file_type_info { + /* the file type name */ + /* should be NULL for all "pseudo" types that are only internally used and not read/writeable */ + const char *name; + + /* the file type short name, used as a shortcut for the command line tools */ + /* should be NULL for all "pseudo" types that are only internally used and not read/writeable */ + const char *short_name; + + /* the common file extensions for this type (seperated by semicolon) */ + /* should be *.* if no common extension is applicable */ + const char *file_extensions; + + /* the default file extension, used to save this type */ + /* should be NULL if no default extension is known */ + const char *file_extension_default; + + /* can this type be compressed with gzip? */ + gboolean can_compress; + + /* can this type write this encapsulation format? */ + /* should be NULL is this file type don't have write support */ + int (*can_write_encap)(int); + + /* the function to open the capture file for writing */ + /* should be NULL is this file type don't have write support */ + int (*dump_open)(wtap_dumper *, gboolean, int *); +}; + + +typedef int (*wtap_open_routine_t)(struct wtap*, int *, char **); + + +/* + * On failure, "wtap_open_offline()" returns NULL, and puts into the + * "int" pointed to by its second argument: + * + * a positive "errno" value if the capture file can't be opened; + * a negative number, indicating the type of error, on other failures. + */ +struct wtap* wtap_open_offline(const char *filename, int *err, + gchar **err_info, gboolean do_random); + +/* Returns TRUE if read was successful. FALSE if failure. data_offset is + * set to the offset in the file where the data for the read packet is + * located. */ +gboolean wtap_read(wtap *wth, int *err, gchar **err_info, + gint64 *data_offset); + +gboolean wtap_seek_read (wtap *wth, gint64 seek_off, + union wtap_pseudo_header *pseudo_header, guint8 *pd, int len, + int *err, gchar **err_info); + +/*** get various information snippets about the current packet ***/ +struct wtap_pkthdr *wtap_phdr(wtap *wth); +union wtap_pseudo_header *wtap_pseudoheader(wtap *wth); +guint8 *wtap_buf_ptr(wtap *wth); + +/*** get various information snippets about the current file ***/ + +/* Return an approximation of the amount of data we've read sequentially + * from the file so far. */ +gint64 wtap_read_so_far(wtap *wth, int *err); +gint64 wtap_file_size(wtap *wth, int *err); +int wtap_snapshot_length(wtap *wth); /* per file */ +int wtap_file_type(wtap *wth); +int wtap_file_encap(wtap *wth); +int wtap_file_tsprecision(wtap *wth); + +/*** close the current file ***/ +void wtap_sequential_close(wtap *wth); +void wtap_close(wtap *wth); + +/*** dump packets into a capture file ***/ +gboolean wtap_dump_can_open(int filetype); +gboolean wtap_dump_can_write_encap(int filetype, int encap); +gboolean wtap_dump_can_compress(int filetype); +wtap_dumper* wtap_dump_open(const char *filename, int filetype, int encap, + int snaplen, gboolean compressed, int *err); +wtap_dumper* wtap_dump_fdopen(int fd, int filetype, int encap, int snaplen, + gboolean compressed, int *err); +gboolean wtap_dump(wtap_dumper *, const struct wtap_pkthdr *, + const union wtap_pseudo_header *pseudo_header, const guchar *, int *err); +void wtap_dump_flush(wtap_dumper *); +gint64 wtap_get_bytes_dumped(wtap_dumper *); +void wtap_set_bytes_dumped(wtap_dumper *wdh, gint64 bytes_dumped); +gboolean wtap_dump_close(wtap_dumper *, int *); + +/*** various string converter functions ***/ +const char *wtap_file_type_string(int filetype); +const char *wtap_file_type_short_string(int filetype); +int wtap_short_string_to_file_type(const char *short_name); + +const char *wtap_file_extensions_string(int filetype); +const char *wtap_file_extension_default_string(int filetype); + +const char *wtap_encap_string(int encap); +const char *wtap_encap_short_string(int encap); +int wtap_short_string_to_encap(const char *short_name); + +const char *wtap_strerror(int err); + +/*** get available number of file types and encapsulations ***/ +int wtap_get_num_encap_types(void); +int wtap_get_num_file_types(void); + +/*** dynamically register new file types and encapsulations ***/ +void wtap_register_open_routine(wtap_open_routine_t, gboolean has_magic); +int wtap_register_file_type(const struct file_type_info* fi); +int wtap_register_encap_type(char* name, char* short_name); + + +/* + * Wiretap error codes. + */ +#define WTAP_ERR_NOT_REGULAR_FILE -1 + /* The file being opened for reading isn't a plain file (or pipe) */ +#define WTAP_ERR_RANDOM_OPEN_PIPE -2 + /* The file is being opened for random access and it's a pipe */ +#define WTAP_ERR_FILE_UNKNOWN_FORMAT -3 + /* The file being opened is not a capture file in a known format */ +#define WTAP_ERR_UNSUPPORTED -4 + /* Supported file type, but there's something in the file we + can't support */ +#define WTAP_ERR_CANT_WRITE_TO_PIPE -5 + /* Wiretap can't save to a pipe in the specified format */ +#define WTAP_ERR_CANT_OPEN -6 + /* The file couldn't be opened, reason unknown */ +#define WTAP_ERR_UNSUPPORTED_FILE_TYPE -7 + /* Wiretap can't save files in the specified format */ +#define WTAP_ERR_UNSUPPORTED_ENCAP -8 + /* Wiretap can't read or save files in the specified format with the + specified encapsulation */ +#define WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED -9 + /* The specified format doesn't support per-packet encapsulations */ +#define WTAP_ERR_CANT_CLOSE -10 + /* The file couldn't be closed, reason unknown */ +#define WTAP_ERR_CANT_READ -11 + /* An attempt to read failed, reason unknown */ +#define WTAP_ERR_SHORT_READ -12 + /* An attempt to read read less data than it should have */ +#define WTAP_ERR_BAD_RECORD -13 + /* We read an invalid record */ +#define WTAP_ERR_SHORT_WRITE -14 + /* An attempt to write wrote less data than it should have */ +#define WTAP_ERR_UNC_TRUNCATED -15 + /* Sniffer compressed data was oddly truncated */ +#define WTAP_ERR_UNC_OVERFLOW -16 + /* Uncompressing Sniffer data would overflow buffer */ +#define WTAP_ERR_UNC_BAD_OFFSET -17 + /* LZ77 compressed data has bad offset to string */ +#define WTAP_ERR_RANDOM_OPEN_STDIN -18 + /* We're trying to open the standard input for random access */ +#define WTAP_ERR_COMPRESSION_NOT_SUPPORTED -19 + /* The filetype doesn't support output compression */ + +/* Errors from zlib; zlib error Z_xxx turns into Wiretap error + WTAP_ERR_ZLIB + Z_xxx. + + WTAP_ERR_ZLIB_MIN and WTAP_ERR_ZLIB_MAX bound the range of zlib + errors; we leave room for 100 positive and 100 negative error + codes. */ + +#define WTAP_ERR_ZLIB -200 +#define WTAP_ERR_ZLIB_MAX -100 +#define WTAP_ERR_ZLIB_MIN -300 + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __WTAP_H__ */ From 3c3cec4b634488699b3a1d4b12d02d59d51d8bb6 Mon Sep 17 00:00:00 2001 From: J980419xq <1908393204@qq.com> Date: Sun, 17 Jul 2022 04:38:29 +0000 Subject: [PATCH 22/44] improve coding --- mininet/mininet/distrinet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mininet/mininet/distrinet.py b/mininet/mininet/distrinet.py index 6f5fa9d8..3622e40b 100755 --- a/mininet/mininet/distrinet.py +++ b/mininet/mininet/distrinet.py @@ -569,7 +569,7 @@ def buildFromTopo( self, topo=None ): for node in nodes: node.waitConnected() - _info ("connected {} ".format( node.name)) + info ("connected {} ".format( node.name)) for node in nodes: info ("startshell {} ".format( node.name) ) From 74e2d00a1eb101f6f0858333382d140a97d0a2a2 Mon Sep 17 00:00:00 2001 From: J980419xq <1908393204@qq.com> Date: Sun, 17 Jul 2022 13:01:30 +0800 Subject: [PATCH 23/44] improve coding --- mininet/mininet/lxc_container.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mininet/mininet/lxc_container.py b/mininet/mininet/lxc_container.py index 95f115fc..15729434 100644 --- a/mininet/mininet/lxc_container.py +++ b/mininet/mininet/lxc_container.py @@ -201,7 +201,7 @@ def configureContainer(self, adminbr="admin-br", wait=True,autoSetDocker=False): # configure the node to be "SSH'able" cmds = [] if autoSetDocker: - cmds.append("docker exec {} bash -c 'echo \"{}\" >> /root/.ssh/authorized_keys'".format(self.name, self.pub_id)) + #cmds.append("docker exec {} bash -c 'echo \"{}\" >> /root/.ssh/authorized_keys'".format(self.name, self.pub_id)) cmds.append("docker exec {} service ssh start".format(self.name)) cmds.append("{}=$(docker inspect -f '{{{{.State.Pid}}}}' {})".format(self.name,self.name)) cmds.append("ip netns exec ${} ip addr add {} dev admin".format(self.name,self.admin_ip)) @@ -350,9 +350,9 @@ def createContainer(self,autoSetDocker=False, **params): # initialise the container if autoSetDocker: if self.image=="ubuntu": - cmd = "docker run -v /root/alcor-control-agent/:/mnt/host/code -itd --privileged --cap-add=NET_ADMIN --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --name {} --net=none {} /bin/bash".format(self.name, self.image) + cmd = "docker create -v /root/alcor-control-agent/:/mnt/host/code -it --privileged --cap-add=NET_ADMIN --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --name {} --net=none {} /bin/bash".format(self.name, self.image) else: - cmd="docker run -itd --privileged --cap-add=NET_ADMIN --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --name {} --net=none {} /bin/bash".format(self.name, self.image) + cmd="docker create -it --privileged --cap-add=NET_ADMIN --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --name {} --net=none {} /bin/bash".format(self.name, self.image) else: cmd = "lxc init {} {} < /dev/null ".format(self.image, self.name) info("{}\n".format(cmd)) @@ -369,6 +369,7 @@ def createContainer(self,autoSetDocker=False, **params): if self.image=="switch": cmds.append("docker exec {} bash -c 'export PATH=$PATH:/usr/share/openvswitch/scripts;ovs-ctl start'".format(self.name)) cmds.append("docker exec {} bash -c 'cd /mnt/host/code;/etc/init.d/openvswitch-switch restart;ovs-vswitchd --pidfile --detach'".format(self.name)) + cmds.append("docker start {}".format(self.name)) else: if self.cpu: cmds.append("lxc config set {} limits.cpu {}".format(self.name, self.cpu)) From fe0020fd3dedc897a1248672976f9d854278d64d Mon Sep 17 00:00:00 2001 From: J980419xq <1908393204@qq.com> Date: Sun, 17 Jul 2022 13:59:38 +0800 Subject: [PATCH 24/44] iprove coding --- mininet/mininet/lxc_container.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mininet/mininet/lxc_container.py b/mininet/mininet/lxc_container.py index 15729434..0685a378 100644 --- a/mininet/mininet/lxc_container.py +++ b/mininet/mininet/lxc_container.py @@ -359,6 +359,7 @@ def createContainer(self,autoSetDocker=False, **params): cmds.append(cmd) # limit resources if autoSetDocker: + cmds.append("docker start {}".format(self.name)) if self.cpu: #cmds.append("lxc config set {} limits.cpu {}".format(self.name, self.cpu)) cmds.append("docker container update --cpuset-cpus={} {}".format(self.cpu, self.name)) @@ -368,8 +369,8 @@ def createContainer(self,autoSetDocker=False, **params): if self.image=="switch": cmds.append("docker exec {} bash -c 'export PATH=$PATH:/usr/share/openvswitch/scripts;ovs-ctl start'".format(self.name)) + else: cmds.append("docker exec {} bash -c 'cd /mnt/host/code;/etc/init.d/openvswitch-switch restart;ovs-vswitchd --pidfile --detach'".format(self.name)) - cmds.append("docker start {}".format(self.name)) else: if self.cpu: cmds.append("lxc config set {} limits.cpu {}".format(self.name, self.cpu)) From 1b8316bfcf50c109757c8f90a1c3adc478acddf1 Mon Sep 17 00:00:00 2001 From: J980419xq <1908393204@qq.com> Date: Mon, 18 Jul 2022 02:53:20 +0000 Subject: [PATCH 25/44] improve coding --- mininet/custom/fat-tree.py | 2 +- mininet/mininet/lxc_container.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mininet/custom/fat-tree.py b/mininet/custom/fat-tree.py index 14f5ef16..1a46483d 100644 --- a/mininet/custom/fat-tree.py +++ b/mininet/custom/fat-tree.py @@ -36,7 +36,7 @@ def __init__(self): super(MyTopo, self).__init__() # K setting - K = 4 + K = 18 # S setting S = K//2 diff --git a/mininet/mininet/lxc_container.py b/mininet/mininet/lxc_container.py index 15729434..2928bf1a 100644 --- a/mininet/mininet/lxc_container.py +++ b/mininet/mininet/lxc_container.py @@ -202,9 +202,8 @@ def configureContainer(self, adminbr="admin-br", wait=True,autoSetDocker=False): cmds = [] if autoSetDocker: #cmds.append("docker exec {} bash -c 'echo \"{}\" >> /root/.ssh/authorized_keys'".format(self.name, self.pub_id)) - cmds.append("docker exec {} service ssh start".format(self.name)) - cmds.append("{}=$(docker inspect -f '{{{{.State.Pid}}}}' {})".format(self.name,self.name)) - cmds.append("ip netns exec ${} ip addr add {} dev admin".format(self.name,self.admin_ip)) + #cmds.append("docker exec {} service ssh start".format(self.name)) + cmds.append("docker exec {} ifconfig admin {}".format(self.name,self.admin_ip)) # configure the container to have else: # an admin IP address @@ -359,6 +358,7 @@ def createContainer(self,autoSetDocker=False, **params): cmds.append(cmd) # limit resources if autoSetDocker: + cmds.append("docker start {};docker exec {} service ssh start".format(self.name,self.name)) if self.cpu: #cmds.append("lxc config set {} limits.cpu {}".format(self.name, self.cpu)) cmds.append("docker container update --cpuset-cpus={} {}".format(self.cpu, self.name)) @@ -368,8 +368,8 @@ def createContainer(self,autoSetDocker=False, **params): if self.image=="switch": cmds.append("docker exec {} bash -c 'export PATH=$PATH:/usr/share/openvswitch/scripts;ovs-ctl start'".format(self.name)) + else: cmds.append("docker exec {} bash -c 'cd /mnt/host/code;/etc/init.d/openvswitch-switch restart;ovs-vswitchd --pidfile --detach'".format(self.name)) - cmds.append("docker start {}".format(self.name)) else: if self.cpu: cmds.append("lxc config set {} limits.cpu {}".format(self.name, self.cpu)) From 3064d5ec7915136e0e7a65bda58e25b44acd7772 Mon Sep 17 00:00:00 2001 From: J980419xq <1908393204@qq.com> Date: Mon, 18 Jul 2022 10:56:49 +0800 Subject: [PATCH 26/44] improve coding --- mininet/mininet/lxc_container.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/mininet/mininet/lxc_container.py b/mininet/mininet/lxc_container.py index 0685a378..2928bf1a 100644 --- a/mininet/mininet/lxc_container.py +++ b/mininet/mininet/lxc_container.py @@ -202,9 +202,8 @@ def configureContainer(self, adminbr="admin-br", wait=True,autoSetDocker=False): cmds = [] if autoSetDocker: #cmds.append("docker exec {} bash -c 'echo \"{}\" >> /root/.ssh/authorized_keys'".format(self.name, self.pub_id)) - cmds.append("docker exec {} service ssh start".format(self.name)) - cmds.append("{}=$(docker inspect -f '{{{{.State.Pid}}}}' {})".format(self.name,self.name)) - cmds.append("ip netns exec ${} ip addr add {} dev admin".format(self.name,self.admin_ip)) + #cmds.append("docker exec {} service ssh start".format(self.name)) + cmds.append("docker exec {} ifconfig admin {}".format(self.name,self.admin_ip)) # configure the container to have else: # an admin IP address @@ -359,7 +358,7 @@ def createContainer(self,autoSetDocker=False, **params): cmds.append(cmd) # limit resources if autoSetDocker: - cmds.append("docker start {}".format(self.name)) + cmds.append("docker start {};docker exec {} service ssh start".format(self.name,self.name)) if self.cpu: #cmds.append("lxc config set {} limits.cpu {}".format(self.name, self.cpu)) cmds.append("docker container update --cpuset-cpus={} {}".format(self.cpu, self.name)) From b8e3706d45a693211a0c4cf2664e13a3d0454034 Mon Sep 17 00:00:00 2001 From: J980419xq <1908393204@qq.com> Date: Mon, 18 Jul 2022 14:35:15 +0800 Subject: [PATCH 27/44] wait lock --- mininet/mininet/distrinet.py | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/mininet/mininet/distrinet.py b/mininet/mininet/distrinet.py index 3622e40b..b3710804 100755 --- a/mininet/mininet/distrinet.py +++ b/mininet/mininet/distrinet.py @@ -533,18 +533,23 @@ def buildFromTopo( self, topo=None ): _info ("createContainer {} ".format( node.name)) node.createContainer(autoSetDocker=self.autoSetDocker) count += 1 - if count > 50: - output("50 nodes created...\n") + if count > 100: + output("100 nodes created...\n") sleep(10) count = 0 - + for node in nodes: node.waitCreated() _info ("createdContainer {} ".format(node.name)) _info ("nodes created\n") + count=0 for node in nodes: _info ("create admin interface {} ".format( node.name)) node.addContainerInterface(intfName="admin", brname="admin-br", wait=False,autoSetDocker=self.autoSetDocker) + count+=1 + if count>100: + sleep(10) + count=0 for node in nodes: node.targetSshWaitOutput() @@ -557,9 +562,15 @@ def buildFromTopo( self, topo=None ): if len (cmds) > 0: cmd = ';'.join(cmds) self.masterSsh.cmd(cmd) - + sleep(10) + count=0 for node in nodes: node.configureContainer(wait=False,autoSetDocker=self.autoSetDocker) + count+=1 + if count>100: + sleep(10) + count=0 + for node in nodes: node.targetSshWaitOutput() @@ -570,17 +581,26 @@ def buildFromTopo( self, topo=None ): for node in nodes: node.waitConnected() info ("connected {} ".format( node.name)) - + count=0 for node in nodes: info ("startshell {} ".format( node.name) ) node.asyncStartShell() + count+=1 + if count>100: + sleep(10) + count=0 for node in nodes: node.waitStarted() info ("startedshell {}".format( node.name)) - + + count=0 for node in nodes: info ("finalize {}".format( node.name)) node.finalizeStartShell() + count+=1 + if count>100: + sleep(10) + count=0 _info ("\n") info( '\n*** Adding links:\n' ) From d06eddff76768fe9ae56cb85119e5e2bf4b7aa81 Mon Sep 17 00:00:00 2001 From: J980419xq <1908393204@qq.com> Date: Mon, 18 Jul 2022 17:25:32 +0800 Subject: [PATCH 28/44] container --- mininet/mininet/lxc_container.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mininet/mininet/lxc_container.py b/mininet/mininet/lxc_container.py index 2928bf1a..b8573fed 100644 --- a/mininet/mininet/lxc_container.py +++ b/mininet/mininet/lxc_container.py @@ -201,7 +201,7 @@ def configureContainer(self, adminbr="admin-br", wait=True,autoSetDocker=False): # configure the node to be "SSH'able" cmds = [] if autoSetDocker: - #cmds.append("docker exec {} bash -c 'echo \"{}\" >> /root/.ssh/authorized_keys'".format(self.name, self.pub_id)) + cmds.append("docker exec {} bash -c 'echo \"{}\" >> /root/.ssh/authorized_keys'".format(self.name, self.pub_id)) #cmds.append("docker exec {} service ssh start".format(self.name)) cmds.append("docker exec {} ifconfig admin {}".format(self.name,self.admin_ip)) # configure the container to have @@ -349,16 +349,16 @@ def createContainer(self,autoSetDocker=False, **params): # initialise the container if autoSetDocker: if self.image=="ubuntu": - cmd = "docker create -v /root/alcor-control-agent/:/mnt/host/code -it --privileged --cap-add=NET_ADMIN --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --name {} --net=none {} /bin/bash".format(self.name, self.image) + cmd = "docker create -v /root/alcor-control-agent/:/mnt/host/code -it --privileged --cap-add=NET_ADMIN --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --name {} --net=none {}".format(self.name, self.image) else: - cmd="docker create -it --privileged --cap-add=NET_ADMIN --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --name {} --net=none {} /bin/bash".format(self.name, self.image) + cmd="docker create -it --privileged --cap-add=NET_ADMIN --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --name {} --net=none {}".format(self.name, self.image) else: cmd = "lxc init {} {} < /dev/null ".format(self.image, self.name) info("{}\n".format(cmd)) cmds.append(cmd) # limit resources if autoSetDocker: - cmds.append("docker start {};docker exec {} service ssh start".format(self.name,self.name)) + cmds.append("docker start {}".format(self.name)) if self.cpu: #cmds.append("lxc config set {} limits.cpu {}".format(self.name, self.cpu)) cmds.append("docker container update --cpuset-cpus={} {}".format(self.cpu, self.name)) From 028c439659d85676326895ee21e8dd9bb8d27d01 Mon Sep 17 00:00:00 2001 From: J980419xq <1908393204@qq.com> Date: Mon, 18 Jul 2022 17:45:30 +0800 Subject: [PATCH 29/44] onos --- deploy_onos.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 deploy_onos.md diff --git a/deploy_onos.md b/deploy_onos.md new file mode 100644 index 00000000..5dde55d3 --- /dev/null +++ b/deploy_onos.md @@ -0,0 +1,28 @@ +### Step1:install dependcies +```bash +apt install wget openjdk-11-jdk +``` + +### Step2:download onos +```bash +sudo mkdir /opt +cd /opt +sudo wget -c https://repo1.maven.org/maven2/org/onosproject/onos-releases/2.7.0/onos-2.7.0.tar.gz +sudo tar xzf onos-2.7.0.tar.gz +sudo mv onos-2.7.0 onos +``` + +### Step3:launch onos +```bash +vim onos/apache-karaf*/bin/setenv # * is your apache-karaf version +#add the follow +export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64/ +``` + +```bash +export ONOS_APPS="drivers,openflow-base,openflow,proxyarp,lldpprovider,fwd,optical-model,hostprovider" #add apps and excute +/opt/onos/bin/onos-service start +``` + + + \ No newline at end of file From 43227cbabb7e5014be9023d22a5307a706aa52a7 Mon Sep 17 00:00:00 2001 From: J980419xq <1908393204@qq.com> Date: Tue, 19 Jul 2022 12:10:16 +0000 Subject: [PATCH 30/44] lab --- mininet/mininet/distrinet.py | 41 +++++++++++++++++++++++--------- mininet/mininet/lxc_container.py | 25 +++++++++---------- 2 files changed, 43 insertions(+), 23 deletions(-) diff --git a/mininet/mininet/distrinet.py b/mininet/mininet/distrinet.py index 3622e40b..5ee365fc 100755 --- a/mininet/mininet/distrinet.py +++ b/mininet/mininet/distrinet.py @@ -486,11 +486,10 @@ def buildFromTopo( self, topo=None ): # == Hosts =========================================================== for hostName in topo.hosts(): - _ip = "{}/{}".format(ipAdd( self.adminNextIP, ipBaseNum=self.adminIpBaseNum, prefixLen=self.adminPrefixLen),self.adminPrefixLen) - self.adminNextIP += 1 + ''' _ip = "{}/{}".format(ipAdd( self.adminNextIP, ipBaseNum=self.adminIpBaseNum, prefixLen=self.adminPrefixLen),self.adminPrefixLen) + self.adminNextIP += 1''' # __ip= newAdminIp(admin_ip) self.addHost( name=hostName, - admin_ip= _ip, loop=self.loop, master=self.masterSsh, username=self.user, @@ -502,10 +501,9 @@ def buildFromTopo( self, topo=None ): info( '\n*** Adding switches:\n' ) for switchName in topo.switches(): - _ip = "{}/{}".format(ipAdd( self.adminNextIP, ipBaseNum=self.adminIpBaseNum, prefixLen=self.adminPrefixLen),self.adminPrefixLen) - self.adminNextIP += 1 + '''_ip = "{}/{}".format(ipAdd( self.adminNextIP, ipBaseNum=self.adminIpBaseNum, prefixLen=self.adminPrefixLen),self.adminPrefixLen) + self.adminNextIP += 1''' self.addSwitch( name=switchName, - admin_ip=_ip, loop=self.loop, master=self.masterSsh, username=self.user, @@ -533,8 +531,8 @@ def buildFromTopo( self, topo=None ): _info ("createContainer {} ".format( node.name)) node.createContainer(autoSetDocker=self.autoSetDocker) count += 1 - if count > 50: - output("50 nodes created...\n") + if count > 100: + output("100 nodes created...\n") sleep(10) count = 0 @@ -542,9 +540,14 @@ def buildFromTopo( self, topo=None ): node.waitCreated() _info ("createdContainer {} ".format(node.name)) _info ("nodes created\n") + count=0 for node in nodes: _info ("create admin interface {} ".format( node.name)) node.addContainerInterface(intfName="admin", brname="admin-br", wait=False,autoSetDocker=self.autoSetDocker) + count+=1 + if count>100: + sleep(10) + count=0 for node in nodes: node.targetSshWaitOutput() @@ -557,9 +560,16 @@ def buildFromTopo( self, topo=None ): if len (cmds) > 0: cmd = ';'.join(cmds) self.masterSsh.cmd(cmd) - + sleep(10) + count=0 for node in nodes: - node.configureContainer(wait=False,autoSetDocker=self.autoSetDocker) + _ip = "{}/{}".format(ipAdd( self.adminNextIP, ipBaseNum=self.adminIpBaseNum, prefixLen=self.adminPrefixLen),self.adminPrefixLen) + self.adminNextIP += 1 + node.configureContainer(admin_ip=_ip,wait=False,autoSetDocker=self.autoSetDocker) + count+=1 + if count>100: + sleep(10) + count=0 for node in nodes: node.targetSshWaitOutput() @@ -571,16 +581,25 @@ def buildFromTopo( self, topo=None ): node.waitConnected() info ("connected {} ".format( node.name)) + count=0 for node in nodes: info ("startshell {} ".format( node.name) ) node.asyncStartShell() + count+=1 + if count>100: + sleep(10) + count=0 for node in nodes: node.waitStarted() info ("startedshell {}".format( node.name)) - + count=0 for node in nodes: info ("finalize {}".format( node.name)) node.finalizeStartShell() + count+=1 + if count>100: + sleep(10) + count=0 _info ("\n") info( '\n*** Adding links:\n' ) diff --git a/mininet/mininet/lxc_container.py b/mininet/mininet/lxc_container.py index 2928bf1a..c1d36f3d 100644 --- a/mininet/mininet/lxc_container.py +++ b/mininet/mininet/lxc_container.py @@ -84,7 +84,6 @@ class LxcNode (Node): connectedToAdminNetwork = {} def __init__(self, name, loop, - admin_ip, master, target=None, port=22, username=None, pub_id=None, bastion=None, bastion_port=22, client_keys=None, @@ -121,7 +120,6 @@ def __init__(self, name, loop, """ # == distrinet self._preInit(loop=loop, - admin_ip=admin_ip, master=master, target=target, port=port, username=username, pub_id=pub_id, bastion=bastion, bastion_port=bastion_port, client_keys=client_keys, @@ -136,7 +134,6 @@ def __init__(self, name, loop, def _preInit(self, loop, - admin_ip, master, target=None, port=22, username=None, pub_id=None, bastion=None, bastion_port=22, client_keys=None, @@ -161,7 +158,6 @@ def _preInit(self, self.bastion_port = bastion_port # IP address to use to administrate the machine - self.admin_ip = admin_ip self.masternode = master self.containerInterfaces = {} @@ -181,12 +177,13 @@ def _preInit(self, if self.target: self.targetSsh = ASsh(loop=self.loop, host=self.target, username=self.username, bastion=self.bastion, client_keys=self.client_keys) # SSH with the node - admin_ip = self.admin_ip + '''admin_ip = seddlf.admin_ip if "/" in admin_ip: - admin_ip, prefix = admin_ip.split("/") - self.ssh = ASsh(loop=self.loop, host=admin_ip, username=self.username, bastion=self.bastion, client_keys=self.client_keys) + admin_ip, prefix = admin_ip.split("/")''' + self.admin_ip=None + self.ssh = None - def configureContainer(self, adminbr="admin-br", wait=True,autoSetDocker=False): + def configureContainer(self,admin_ip, adminbr="admin-br", wait=True,autoSetDocker=False): # # connect the node to the admin network # self.addContainerInterface(intfName="admin", brname=adminbr) @@ -200,8 +197,12 @@ def configureContainer(self, adminbr="admin-br", wait=True,autoSetDocker=False): # configure the node to be "SSH'able" cmds = [] + self.admin_ip=admin_ip + if "/" in admin_ip: + admin_ip, prefix = admin_ip.split("/") + self.ssh = ASsh(loop=self.loop, host=admin_ip, username=self.username, bastion=self.bastion, client_keys=self.client_keys) if autoSetDocker: - #cmds.append("docker exec {} bash -c 'echo \"{}\" >> /root/.ssh/authorized_keys'".format(self.name, self.pub_id)) + cmds.append("docker exec {} bash -c 'echo \"{}\" >> /root/.ssh/authorized_keys'".format(self.name, self.pub_id)) #cmds.append("docker exec {} service ssh start".format(self.name)) cmds.append("docker exec {} ifconfig admin {}".format(self.name,self.admin_ip)) # configure the container to have @@ -349,16 +350,16 @@ def createContainer(self,autoSetDocker=False, **params): # initialise the container if autoSetDocker: if self.image=="ubuntu": - cmd = "docker create -v /root/alcor-control-agent/:/mnt/host/code -it --privileged --cap-add=NET_ADMIN --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --name {} --net=none {} /bin/bash".format(self.name, self.image) + cmd = "docker create -v /root/alcor-control-agent/:/mnt/host/code -it --privileged --cap-add=NET_ADMIN --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --name {} --net=none {} ".format(self.name, self.image) else: - cmd="docker create -it --privileged --cap-add=NET_ADMIN --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --name {} --net=none {} /bin/bash".format(self.name, self.image) + cmd="docker create -it --privileged --cap-add=NET_ADMIN --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --name {} --net=none {} ".format(self.name, self.image) else: cmd = "lxc init {} {} < /dev/null ".format(self.image, self.name) info("{}\n".format(cmd)) cmds.append(cmd) # limit resources if autoSetDocker: - cmds.append("docker start {};docker exec {} service ssh start".format(self.name,self.name)) + cmds.append("docker start {}".format(self.name,self.name)) if self.cpu: #cmds.append("lxc config set {} limits.cpu {}".format(self.name, self.cpu)) cmds.append("docker container update --cpuset-cpus={} {}".format(self.cpu, self.name)) From 2242ab42d0393d6ad6dc6a85da62a0e186dc1245 Mon Sep 17 00:00:00 2001 From: J980419xq <1908393204@qq.com> Date: Tue, 19 Jul 2022 14:14:55 +0000 Subject: [PATCH 31/44] work admin_ip --- mininet/mininet/distrinet.py | 9 +++++-- mininet/mininet/lxc_container.py | 40 +++++++++++++++----------------- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/mininet/mininet/distrinet.py b/mininet/mininet/distrinet.py index 5ee365fc..0a05b440 100755 --- a/mininet/mininet/distrinet.py +++ b/mininet/mininet/distrinet.py @@ -228,7 +228,7 @@ def runforever(loop): _info ("connected to master node\n") - + self.connectedToAdminNetwork=set() self.nameToNode = {} # name to Node (Host/Switch) objects self.terms = [] # list of spawned xterm processes @@ -556,7 +556,12 @@ def buildFromTopo( self, topo=None ): cmds = [] for node in nodes: - cmds = cmds + node.connectToAdminNetwork(master=node.masternode.host, target=node.target, link_id=CloudLink.newLinkId(), admin_br="admin-br", wait=False) + if node.target not in self.connectedToAdminNetwork: + _ip = "{}/{}".format(ipAdd( self.adminNextIP, ipBaseNum=self.adminIpBaseNum, prefixLen=self.adminPrefixLen),self.adminPrefixLen) + self.adminNextIP += 1 + cmds = cmds + node.connectToAdminNetwork(admin_ip=_ip,master=node.masternode.host, target=node.target, link_id=CloudLink.newLinkId(), admin_br="admin-br", wait=False) + self.connectedToAdminNetwork.add(node.target) + info(count) if len (cmds) > 0: cmd = ';'.join(cmds) self.masterSsh.cmd(cmd) diff --git a/mininet/mininet/lxc_container.py b/mininet/mininet/lxc_container.py index c1d36f3d..394cd1f3 100644 --- a/mininet/mininet/lxc_container.py +++ b/mininet/mininet/lxc_container.py @@ -304,33 +304,31 @@ def createContainerLinkCommandList(self, target1, target2, vxlan_id, vxlan_name, self.devices.append(bridge2) return cmds - def connectToAdminNetwork(self, master, target, link_id, admin_br, wait=True, **params): + def connectToAdminNetwork(self, admin_ip,master, target, link_id, admin_br, wait=True, **params): cmds = [] - if not self.target in self.__class__.connectedToAdminNetwork: - self.__class__.connectedToAdminNetwork[self.target] = True - # no need to connect admin on the same machine or if it is already connected - vxlan_name = "vx_{}".format(link_id) + # no need to connect admin on the same machine or if it is already connected + vxlan_name = "vx_{}".format(link_id) - # locally - # DSA - TODO - XXX beurk bridge2 = None - cmds = self.createContainerLinkCommandList(target, master, link_id, vxlan_name, bridge1=admin_br, bridge2=None) - #if target!=master: - # cmds.append("ifconfig admin_br {}".format(self.admin_ip)) - cmd = ';'.join(cmds) + # locally + # DSA - TODO - XXX beurk bridge2 = None + cmds = self.createContainerLinkCommandList(target, master, link_id, vxlan_name, bridge1=admin_br, bridge2=None) + if target!=master: + cmds.append("ifconfig admin-br {}".format(admin_ip)) + cmd = ';'.join(cmds) - if wait: - self.targetSsh.cmd(cmd) - else: - self.targetSsh.sendCmd(cmd) + if wait: + self.targetSsh.cmd(cmd) + else: + self.targetSsh.sendCmd(cmd) - # on master - # DSA - TODO - XXX beurk bridge2 = None - cmds = self.createContainerLinkCommandList(master, target, link_id, vxlan_name, bridge1=admin_br, bridge2=None) - cmd = ';'.join(cmds) - self.devicesMaster.append(vxlan_name) + # on master + # DSA - TODO - XXX beurk bridge2 = None + cmds = self.createContainerLinkCommandList(master, target, link_id, vxlan_name, bridge1=admin_br, bridge2=None) + cmd = ';'.join(cmds) + self.devicesMaster.append(vxlan_name) - self.devices.append(vxlan_name) + self.devices.append(vxlan_name) # print ("master".format(vxlan_name),cmd) # if wait: # self.masternode.cmd(cmd) From c5bae1e59c4a0cbb32d80c6d85a273c3368e732b Mon Sep 17 00:00:00 2001 From: J980419xq <1908393204@qq.com> Date: Tue, 19 Jul 2022 14:39:06 +0000 Subject: [PATCH 32/44] admin-br --- mininet/mininet/distrinet.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mininet/mininet/distrinet.py b/mininet/mininet/distrinet.py index 0a05b440..be0da680 100755 --- a/mininet/mininet/distrinet.py +++ b/mininet/mininet/distrinet.py @@ -728,6 +728,7 @@ def stop( self ): info( '*** cleaning master\n' ) # XXX DSA need to find something nicer + self.masterSsh.cmd("ip link delete admin-br") for node in self.hosts + self.switches + self.controllers: _info ("wait {} ".format( node )) node.targetSshWaitOutput() From 4c875200a4067fb161a81c7e08ff39d0d3249f42 Mon Sep 17 00:00:00 2001 From: J980419xq <1908393204@qq.com> Date: Wed, 20 Jul 2022 07:13:34 +0000 Subject: [PATCH 33/44] improve coding --- mininet/custom/fat-tree.py | 2 +- mininet/mininet/distrinet.py | 25 +++++++++++++------------ mininet/mininet/lxc_container.py | 10 +++++----- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/mininet/custom/fat-tree.py b/mininet/custom/fat-tree.py index 1a46483d..14f5ef16 100644 --- a/mininet/custom/fat-tree.py +++ b/mininet/custom/fat-tree.py @@ -36,7 +36,7 @@ def __init__(self): super(MyTopo, self).__init__() # K setting - K = 18 + K = 4 # S setting S = K//2 diff --git a/mininet/mininet/distrinet.py b/mininet/mininet/distrinet.py index be0da680..29bd5f1c 100755 --- a/mininet/mininet/distrinet.py +++ b/mininet/mininet/distrinet.py @@ -540,6 +540,19 @@ def buildFromTopo( self, topo=None ): node.waitCreated() _info ("createdContainer {} ".format(node.name)) _info ("nodes created\n") + + cmds = [] + for node in nodes: + if node.target not in self.connectedToAdminNetwork: + _ip = "{}/{}".format(ipAdd( self.adminNextIP, ipBaseNum=self.adminIpBaseNum, prefixLen=self.adminPrefixLen),self.adminPrefixLen) + self.adminNextIP += 1 + cmds = cmds + node.connectToAdminNetwork(admin_ip=_ip,master=node.masternode.host, target=node.target, link_id=CloudLink.newLinkId(), admin_br="admin-br", wait=False) + self.connectedToAdminNetwork.add(node.target) + if len (cmds) > 0: + cmd = ';'.join(cmds) + self.masterSsh.cmd(cmd) + sleep(10) + count=0 for node in nodes: _info ("create admin interface {} ".format( node.name)) @@ -554,18 +567,6 @@ def buildFromTopo( self, topo=None ): _info ("admin interface created on {} ".format( node.name)) _info ("\n") - cmds = [] - for node in nodes: - if node.target not in self.connectedToAdminNetwork: - _ip = "{}/{}".format(ipAdd( self.adminNextIP, ipBaseNum=self.adminIpBaseNum, prefixLen=self.adminPrefixLen),self.adminPrefixLen) - self.adminNextIP += 1 - cmds = cmds + node.connectToAdminNetwork(admin_ip=_ip,master=node.masternode.host, target=node.target, link_id=CloudLink.newLinkId(), admin_br="admin-br", wait=False) - self.connectedToAdminNetwork.add(node.target) - info(count) - if len (cmds) > 0: - cmd = ';'.join(cmds) - self.masterSsh.cmd(cmd) - sleep(10) count=0 for node in nodes: _ip = "{}/{}".format(ipAdd( self.adminNextIP, ipBaseNum=self.adminIpBaseNum, prefixLen=self.adminPrefixLen),self.adminPrefixLen) diff --git a/mininet/mininet/lxc_container.py b/mininet/mininet/lxc_container.py index 394cd1f3..ff4af8ac 100644 --- a/mininet/mininet/lxc_container.py +++ b/mininet/mininet/lxc_container.py @@ -306,15 +306,15 @@ def createContainerLinkCommandList(self, target1, target2, vxlan_id, vxlan_name, def connectToAdminNetwork(self, admin_ip,master, target, link_id, admin_br, wait=True, **params): cmds = [] + cmds.append("brctl addbr admin-br") + cmds.append("ifconfig admin-br {}".format(admin_ip)) # no need to connect admin on the same machine or if it is already connected vxlan_name = "vx_{}".format(link_id) # locally # DSA - TODO - XXX beurk bridge2 = None - cmds = self.createContainerLinkCommandList(target, master, link_id, vxlan_name, bridge1=admin_br, bridge2=None) - if target!=master: - cmds.append("ifconfig admin-br {}".format(admin_ip)) + cmds =cmds + self.createContainerLinkCommandList(target, master, link_id, vxlan_name, bridge1=admin_br, bridge2=None) cmd = ';'.join(cmds) if wait: @@ -396,12 +396,12 @@ def addContainerInterface(self, intfName, devicename=None, brname=None, wait=Tru Add the interface with name intfName to the container that is associated to the bridge named name-intfName-br on the host """ + cmds=[] if devicename is None: devicename = genIntfName() if brname is None: brname = genIntfName() - cmds = [] - cmds.append("brctl addbr {}".format(brname)) + cmds.append("brctl addbr {}".format(brname)) if autoSetDocker: cmds.append("ip link add {} type veth peer name {}".format("veth"+devicename,devicename)) cmds.append("brctl addif {} {}".format(brname,devicename)) From f028668ef63e8025988bf22a0d22594048f66330 Mon Sep 17 00:00:00 2001 From: J980419xq <1908393204@qq.com> Date: Wed, 20 Jul 2022 15:38:22 +0800 Subject: [PATCH 34/44] delete openflow --- openflow/.gitignore | 44 - openflow/COPYING | 1054 ----- openflow/ChangeLog | 202 - openflow/INSTALL | 513 --- openflow/Makefile.am | 68 - openflow/README | 110 - openflow/README.hwtables | 39 - openflow/README.kernel | 18 - openflow/acinclude.m4 | 309 -- openflow/boot.sh | 14 - openflow/configure.ac | 94 - openflow/controller/.dirstamp | 0 openflow/controller/.gitignore | 4 - openflow/controller/automake.mk | 8 - openflow/controller/controller.8.in | 150 - openflow/controller/controller.c | 336 -- openflow/datapath/.gitignore | 7 - openflow/datapath/Makefile.am | 27 - openflow/datapath/Modules.mk | 42 - openflow/datapath/chain.c | 270 -- openflow/datapath/chain.h | 43 - openflow/datapath/compat.h | 12 - openflow/datapath/crc32.c | 45 - openflow/datapath/crc32.h | 22 - openflow/datapath/datapath.c | 2137 ---------- openflow/datapath/datapath.h | 114 - openflow/datapath/dp_act.c | 543 --- openflow/datapath/dp_act.h | 15 - openflow/datapath/dp_dev.c | 252 -- openflow/datapath/dp_dev.h | 17 - openflow/datapath/dp_notify.c | 43 - openflow/datapath/flow.c | 504 --- openflow/datapath/flow.h | 199 - openflow/datapath/forward.c | 642 --- openflow/datapath/forward.h | 38 - openflow/datapath/hwtable_dummy/Modules.mk | 7 - .../datapath/hwtable_dummy/hwtable_dummy.c | 320 -- openflow/datapath/hwtable_nf2/Modules.mk | 19 - openflow/datapath/hwtable_nf2/README | 78 - openflow/datapath/hwtable_nf2/nf2.h | 424 -- openflow/datapath/hwtable_nf2/nf2_flowtable.c | 452 --- openflow/datapath/hwtable_nf2/nf2_flowtable.h | 63 - openflow/datapath/hwtable_nf2/nf2_hwapi.h | 43 - openflow/datapath/hwtable_nf2/nf2_lib.c | 918 ----- openflow/datapath/hwtable_nf2/nf2_lib.h | 59 - openflow/datapath/hwtable_nf2/nf2_openflow.c | 847 ---- openflow/datapath/hwtable_nf2/nf2_openflow.h | 169 - openflow/datapath/hwtable_nf2/nf2_procfs.c | 240 -- openflow/datapath/hwtable_nf2/nf2_procfs.h | 39 - openflow/datapath/hwtable_nf2/nf2_reg.h | 767 ---- .../datapath/hwtable_nf2/openflow_switch.bit | Bin 2377746 -> 0 bytes openflow/datapath/linux-2.6/.gitignore | 30 - openflow/datapath/linux-2.6/Kbuild.in | 35 - openflow/datapath/linux-2.6/Makefile.in | 9 - openflow/datapath/linux-2.6/Makefile.main.in | 85 - openflow/datapath/linux-2.6/Modules.mk | 32 - .../datapath/linux-2.6/compat-2.6/compat26.h | 31 - .../linux-2.6/compat-2.6/genetlink-brcompat.c | 20 - .../linux-2.6/compat-2.6/genetlink-openflow.c | 22 - .../compat-2.6/include/asm-generic/bug.h | 20 - .../linux-2.6/compat-2.6/include/linux/dmi.h | 114 - .../linux-2.6/compat-2.6/include/linux/icmp.h | 13 - .../compat-2.6/include/linux/if_arp.h | 16 - .../linux-2.6/compat-2.6/include/linux/ip.h | 18 - .../linux-2.6/compat-2.6/include/linux/ipv6.h | 13 - .../compat-2.6/include/linux/jiffies.h | 26 - .../compat-2.6/include/linux/lockdep.h | 450 --- .../compat-2.6/include/linux/mutex.h | 59 - .../compat-2.6/include/linux/netdevice.h | 10 - .../include/linux/netfilter_bridge.h | 24 - .../compat-2.6/include/linux/netfilter_ipv4.h | 19 - .../compat-2.6/include/linux/netlink.h | 24 - .../compat-2.6/include/linux/random.h | 17 - .../compat-2.6/include/linux/rculist.h | 12 - .../compat-2.6/include/linux/skbuff.h | 137 - .../linux-2.6/compat-2.6/include/linux/tcp.h | 18 - .../compat-2.6/include/linux/timer.h | 96 - .../compat-2.6/include/linux/types.h | 14 - .../linux-2.6/compat-2.6/include/linux/udp.h | 13 - .../compat-2.6/include/linux/workqueue.h | 42 - .../compat-2.6/include/net/checksum.h | 16 - .../compat-2.6/include/net/genetlink.h | 123 - .../compat-2.6/include/net/netlink.h | 22 - .../datapath/linux-2.6/compat-2.6/random32.c | 146 - openflow/datapath/linux-2.6/compat-2.6/veth.c | 537 --- .../config/config-linux-2.6.23-rc9-kvm | 1408 ------- openflow/datapath/openflow-ext.c | 83 - openflow/datapath/openflow-ext.h | 38 - openflow/datapath/private-msg.c | 137 - openflow/datapath/private-msg.h | 38 - openflow/datapath/table-hash.c | 489 --- openflow/datapath/table-linear.c | 233 -- openflow/datapath/table.h | 119 - openflow/debian/.gitignore | 38 - openflow/debian/changelog | 23 - openflow/debian/commands/reconfigure | 128 - openflow/debian/commands/update | 4 - openflow/debian/compat | 1 - openflow/debian/control.in | 93 - openflow/debian/control.modules.in | 19 - openflow/debian/copyright | 38 - openflow/debian/corekeeper.cron.daily | 5 - openflow/debian/corekeeper.init | 63 - openflow/debian/dirs | 2 - openflow/debian/ofp-switch-setup | 615 --- openflow/debian/ofp-switch-setup.8 | 41 - openflow/debian/openflow-common.dirs | 1 - openflow/debian/openflow-common.install | 3 - openflow/debian/openflow-common.manpages | 2 - .../debian/openflow-controller.README.Debian | 10 - openflow/debian/openflow-controller.default | 33 - openflow/debian/openflow-controller.dirs | 1 - openflow/debian/openflow-controller.init | 269 -- openflow/debian/openflow-controller.install | 1 - openflow/debian/openflow-controller.manpages | 1 - openflow/debian/openflow-controller.postinst | 52 - ...atapath-module-_KVERS_.postinst.modules.in | 25 - .../openflow-datapath-source.README.Debian | 31 - .../debian/openflow-datapath-source.copyright | 16 - openflow/debian/openflow-datapath-source.dirs | 1 - .../debian/openflow-datapath-source.install | 6 - openflow/debian/openflow-pki-server.apache2 | 1 - openflow/debian/openflow-pki-server.dirs | 1 - openflow/debian/openflow-pki-server.install | 1 - openflow/debian/openflow-pki-server.postinst | 44 - openflow/debian/openflow-pki.postinst | 41 - openflow/debian/openflow-switch-config.dirs | 1 - .../debian/openflow-switch-config.install | 1 - .../debian/openflow-switch-config.manpages | 1 - .../debian/openflow-switch-config.overrides | 1 - .../debian/openflow-switch-config.templates | 228 -- openflow/debian/openflow-switch.README.Debian | 18 - openflow/debian/openflow-switch.dirs | 2 - openflow/debian/openflow-switch.init | 437 -- openflow/debian/openflow-switch.install | 6 - openflow/debian/openflow-switch.logrotate | 11 - openflow/debian/openflow-switch.manpages | 4 - openflow/debian/openflow-switch.postinst | 51 - openflow/debian/openflow-switch.postrm | 43 - openflow/debian/openflow-switch.template | 169 - openflow/debian/po/POTFILES.in | 1 - openflow/debian/rules | 163 - openflow/doc/of-spec/.gitignore | 8 - openflow/doc/of-spec/Makefile | 40 - openflow/doc/of-spec/README | 3 - openflow/doc/of-spec/appendix.tex | 429 -- openflow/doc/of-spec/credits.tex | 22 - .../doc/of-spec/figure_flow_table_secchan.png | Bin 67886 -> 0 bytes .../of-spec/header_parsing_flowchart.graffle | 3536 ----------------- openflow/doc/of-spec/make_latex_input.pl | 117 - openflow/doc/of-spec/openflow-spec-v1.0.0.tex | 418 -- .../doc/of-spec/packet_flow_flowchart.graffle | 1887 --------- openflow/hw-lib/automake.mk | 28 - openflow/hw-lib/nf2/README | 56 - openflow/hw-lib/nf2/debug.h | 105 - openflow/hw-lib/nf2/hw_flow.c | 514 --- openflow/hw-lib/nf2/hw_flow.h | 56 - openflow/hw-lib/nf2/nf2.h | 452 --- openflow/hw-lib/nf2/nf2_drv.c | 847 ---- openflow/hw-lib/nf2/nf2_drv.h | 150 - openflow/hw-lib/nf2/nf2_lib.c | 1049 ----- openflow/hw-lib/nf2/nf2_lib.h | 59 - openflow/hw-lib/nf2/nf2util.c | 400 -- openflow/hw-lib/nf2/nf2util.h | 46 - .../hw-lib/nf2/reg_defines_openflow_switch.h | 767 ---- openflow/hw-lib/skeleton/debug.h | 106 - openflow/hw-lib/skeleton/hw_drv.c | 309 -- openflow/hw-lib/skeleton/hw_drv.h | 97 - openflow/hw-lib/skeleton/hw_flow.c | 708 ---- openflow/hw-lib/skeleton/hw_flow.h | 111 - openflow/hw-lib/skeleton/of_hw_platform.h | 38 - openflow/hw-lib/skeleton/os.h | 29 - openflow/hw-lib/skeleton/port.c | 497 --- openflow/hw-lib/skeleton/port.h | 45 - openflow/hw-lib/skeleton/sample_plat.c | 82 - openflow/hw-lib/skeleton/sample_plat.h | 61 - openflow/hw-lib/skeleton/txrx.c | 129 - openflow/hw-lib/skeleton/txrx.h | 12 - openflow/include/.gitignore | 2 - openflow/include/automake.mk | 1 - openflow/include/openflow/automake.mk | 5 - openflow/include/openflow/nicira-ext.h | 195 - openflow/include/openflow/of_hw_api.h | 313 -- openflow/include/openflow/openflow-ext.h | 149 - openflow/include/openflow/openflow-netlink.h | 69 - openflow/include/openflow/openflow.h | 970 ----- openflow/include/openflow/private-ext.h | 68 - openflow/m4/libopenflow.m4 | 168 - openflow/m4/nx-build.m4 | 71 - openflow/regress/CREDITS | 22 - openflow/regress/INSTALL | 264 -- openflow/regress/LICENSE | 30 - openflow/regress/README | 329 -- openflow/regress/bin/eth.map | 8 - openflow/regress/bin/nf2.map | 8 - openflow/regress/bin/of_hp_eth.map | 8 - openflow/regress/bin/of_hp_setup.pl | 86 - openflow/regress/bin/of_hp_teardown.pl | 50 - openflow/regress/bin/of_hp_test.pl | 62 - openflow/regress/bin/of_hp_test_6600.pl | 62 - openflow/regress/bin/of_kmod_setup.pl | 22 - openflow/regress/bin/of_kmod_teardown.pl | 20 - openflow/regress/bin/of_kmod_test.pl | 27 - openflow/regress/bin/of_kmod_veth_setup.pl | 26 - openflow/regress/bin/of_kmod_veth_teardown.pl | 24 - openflow/regress/bin/of_kmod_veth_test.pl | 27 - openflow/regress/bin/of_nf2_setup.pl | 26 - openflow/regress/bin/of_nf2_teardown.pl | 20 - openflow/regress/bin/of_nf2_test.pl | 28 - openflow/regress/bin/of_ovs_eth.map | 8 - openflow/regress/bin/of_ovs_setup.pl | 76 - openflow/regress/bin/of_ovs_teardown.pl | 59 - openflow/regress/bin/of_ovs_test.pl | 54 - openflow/regress/bin/of_ovs_user_setup.pl | 60 - openflow/regress/bin/of_ovs_user_teardown.pl | 34 - openflow/regress/bin/of_ovs_user_test.pl | 50 - openflow/regress/bin/of_ovs_user_veth_test.pl | 47 - openflow/regress/bin/of_ovs_veth_test.pl | 47 - openflow/regress/bin/of_user_setup.pl | 22 - openflow/regress/bin/of_user_teardown.pl | 20 - openflow/regress/bin/of_user_test.pl | 27 - openflow/regress/bin/of_user_veth_setup.pl | 26 - openflow/regress/bin/of_user_veth_teardown.pl | 24 - openflow/regress/bin/of_user_veth_test.pl | 27 - openflow/regress/bin/veth.map | 8 - openflow/regress/bin/veth_setup.pl | 10 - openflow/regress/bin/veth_teardown.pl | 4 - .../projects/black_box/regress/common/setup | 47 - .../black_box/regress/common/teardown | 47 - .../regress/test_add_flow_latency/run.pl | 47 - .../black_box/regress/test_barrier/run.pl | 52 - .../regress/test_cookie_flow_expired/run.pl | 39 - .../regress/test_cookie_flow_stats/run.pl | 151 - .../black_box/regress/test_delete/run.pl | 172 - .../regress/test_delete_send_flow_exp/run.pl | 104 - .../regress/test_delete_strict/run.pl | 175 - .../black_box/regress/test_drop_exact/run.pl | 54 - .../regress/test_failover_close/run.pl | 68 - .../regress/test_failover_startup/run.pl | 53 - .../test_failover_stop_responding/run.pl | 65 - .../regress/test_flow_expired/run.pl | 34 - .../test_flow_expired_idle_timeout/run.pl | 34 - .../test_flow_expired_precision/run.pl | 66 - .../test_flow_expired_send_flow_exp/run.pl | 44 - .../regress/test_flow_mod_check/run.pl | 83 - .../test_flow_mod_latency/run-port3.pl | 136 - .../regress/test_flow_mod_latency/run.pl | 129 - .../black_box/regress/test_flow_stats/run.pl | 145 - .../regress/test_flow_stats_precision/run.pl | 191 - .../test_forward_after_expiration/run.pl | 111 - .../regress/test_forward_any_port/run.pl | 20 - .../test_forward_bandwidth_fixed/run.pl | 83 - .../test_forward_bandwidth_random/run.pl | 84 - .../test_forward_broadcast_exact_port/run.pl | 64 - .../regress/test_forward_exact_all/run.pl | 30 - .../regress/test_forward_exact_arp_all/run.pl | 19 - .../test_forward_exact_arp_controller/run.pl | 19 - .../test_forward_exact_arp_fool/run.pl | 19 - .../test_forward_exact_arp_port/run.pl | 19 - .../test_forward_exact_controller/run.pl | 32 - .../test_forward_exact_icmp_all/run.pl | 19 - .../test_forward_exact_icmp_controller/run.pl | 19 - .../test_forward_exact_icmp_fool/run.pl | 19 - .../test_forward_exact_icmp_port/run.pl | 19 - .../test_forward_exact_modify_action/run.pl | 42 - .../regress/test_forward_exact_port/run.pl | 27 - .../run.pl | 86 - .../regress/test_forward_wildcard_all/run.pl | 172 - .../test_forward_wildcard_arp_all/run.pl | 20 - .../run.pl | 19 - .../test_forward_wildcard_arp_fool/run.pl | 20 - .../test_forward_wildcard_arp_port/run.pl | 20 - .../test_forward_wildcard_controller/run.pl | 30 - .../test_forward_wildcard_icmp_all/run.pl | 20 - .../run.pl | 19 - .../test_forward_wildcard_icmp_fool/run.pl | 20 - .../test_forward_wildcard_icmp_port/run.pl | 20 - .../run.pl | 35 - .../regress/test_forward_wildcard_port/run.pl | 97 - .../black_box/regress/test_hello/run.pl | 16 - .../black_box/regress/test_ip_offset/run.pl | 85 - .../black_box/regress/test_ip_options/run.pl | 76 - .../regress/test_ip_protocol/case-c.pl | 150 - .../regress/test_ip_protocol/case-d.pl | 152 - .../regress/test_ip_protocol/case-e.pl | 152 - .../regress/test_ip_protocol/case-tcp.pl | 153 - .../regress/test_ip_protocol/case-udp.pl | 67 - .../black_box/regress/test_llc/run.pl | 128 - .../regress/test_miss_send_length/run.pl | 79 - .../black_box/regress/test_packet_in/run.pl | 45 - .../black_box/regress/test_packet_out/run.pl | 53 - .../black_box/regress/test_port_stats/run.pl | 132 - .../regress/test_queue_config/run.pl | 52 - .../regress/test_queue_forward/run.pl | 19 - .../black_box/regress/test_queue_stats/run.pl | 116 - .../test_receive_bandwidth_fixed/run.pl | 89 - .../regress/test_send_bandwidth_fixed/run.pl | 140 - .../regress/test_send_bandwidth_random/run.pl | 141 - .../regress/test_set_dl_nw_flip/run.pl | 143 - .../regress/test_set_n_match_nw_tos/run.pl | 95 - .../black_box/regress/test_set_nw_dst/run.pl | 95 - .../black_box/regress/test_stats_desc/run.pl | 71 - .../regress/test_switch_config/run.pl | 40 - .../black_box/regress/test_tcp_options/run.pl | 170 - .../projects/black_box/regress/tests.txt | 103 - .../regress/common/setup | 49 - .../regress/common/teardown | 47 - .../regress/test_emergency_table/run.pl | 107 - .../controller_disconnect/regress/tests.txt | 2 - .../learning_switch/regress/common/setup | 46 - .../learning_switch/regress/common/teardown | 46 - .../regress/test_broadcast/run.pl | 50 - .../regress/test_forward_bandwidth/run.pl | 62 - .../regress/test_forward_latency/run.pl | 69 - .../regress/test_hub_connected/run.pl | 64 - .../regress/test_unicast_known/run.pl | 71 - .../regress/test_unicast_move/run.pl | 79 - .../test_unicast_multiple_hosts/run.pl | 93 - .../regress/test_unicast_self/run.pl | 61 - .../regress/test_unicast_unknown/run.pl | 32 - .../learning_switch/regress/tests.txt | 12 - openflow/regress/projects/regress.txt | 3 - openflow/regress/scripts/copy_NF2_code.sh | 5 - openflow/regress/scripts/env_vars | 12 - openflow/regress/scripts/install_deps.pl | 264 -- .../regress/scripts/install_perlmods_apt.pl | 32 - openflow/regress/scripts/make_release.pl | 155 - openflow/secchan/.dirstamp | 0 openflow/secchan/.gitignore | 7 - openflow/secchan/automake.mk | 32 - openflow/secchan/commands/automake.mk | 3 - openflow/secchan/commands/reboot | 3 - openflow/secchan/discovery.c | 251 -- openflow/secchan/discovery.h | 50 - openflow/secchan/emerg-flow.c | 144 - openflow/secchan/emerg-flow.h | 44 - openflow/secchan/fail-open.c | 159 - openflow/secchan/fail-open.h | 46 - openflow/secchan/failover.c | 144 - openflow/secchan/failover.h | 44 - openflow/secchan/in-band.c | 331 -- openflow/secchan/in-band.h | 47 - openflow/secchan/ofprotocol.8.in | 462 --- openflow/secchan/port-watcher.c | 620 --- openflow/secchan/port-watcher.h | 77 - openflow/secchan/protocol-stat.c | 204 - openflow/secchan/protocol-stat.h | 44 - openflow/secchan/ratelimit.c | 263 -- openflow/secchan/ratelimit.h | 45 - openflow/secchan/secchan.c | 882 ---- openflow/secchan/secchan.h | 135 - openflow/secchan/status.c | 230 -- openflow/secchan/status.h | 56 - openflow/secchan/stp-secchan.c | 293 -- openflow/secchan/stp-secchan.h | 48 - openflow/soexpand.pl | 26 - openflow/tests/.dirstamp | 0 openflow/tests/.gitignore | 6 - openflow/tests/automake.mk | 46 - openflow/tests/flowgen.pl | 224 -- openflow/tests/test-dhcp-client.c | 206 - openflow/tests/test-flows | Bin 286976 -> 0 bytes openflow/tests/test-flows.c | 76 - openflow/tests/test-flows.sh | 9 - openflow/tests/test-hmap | Bin 68296 -> 0 bytes openflow/tests/test-hmap.c | 282 -- openflow/tests/test-list.c | 159 - openflow/tests/test-stp-ieee802.1d-1998 | 12 - .../tests/test-stp-ieee802.1d-2004-fig17.4 | 31 - .../tests/test-stp-ieee802.1d-2004-fig17.6 | 14 - .../tests/test-stp-ieee802.1d-2004-fig17.7 | 17 - openflow/tests/test-stp-iol-io-1.1 | 25 - openflow/tests/test-stp-iol-io-1.2 | 14 - openflow/tests/test-stp-iol-io-1.4 | 13 - openflow/tests/test-stp-iol-io-1.5 | 40 - openflow/tests/test-stp-iol-op-1.1 | 7 - openflow/tests/test-stp-iol-op-1.4 | 8 - openflow/tests/test-stp-iol-op-3.1 | 11 - openflow/tests/test-stp-iol-op-3.3 | 11 - openflow/tests/test-stp-iol-op-3.4 | 11 - openflow/tests/test-stp.c | 665 ---- openflow/tests/test-stp.sh | 7 - openflow/tests/test-type-props.c | 41 - openflow/third-party/.gitignore | 2 - openflow/third-party/README | 35 - openflow/third-party/automake.mk | 3 - openflow/third-party/ofp-tcpdump.patch | 119 - openflow/udatapath/.dirstamp | 0 openflow/udatapath/.gitignore | 4 - openflow/udatapath/automake.mk | 75 - openflow/udatapath/chain.c | 261 -- openflow/udatapath/chain.h | 74 - openflow/udatapath/crc32.c | 68 - openflow/udatapath/crc32.h | 50 - openflow/udatapath/datapath.c | 2375 ----------- openflow/udatapath/datapath.h | 167 - openflow/udatapath/dp_act.c | 531 --- openflow/udatapath/dp_act.h | 49 - openflow/udatapath/of_ext_msg.c | 267 -- openflow/udatapath/of_ext_msg.h | 43 - openflow/udatapath/ofdatapath.8.in | 148 - openflow/udatapath/private-msg.c | 140 - openflow/udatapath/private-msg.h | 42 - openflow/udatapath/switch-flow.c | 341 -- openflow/udatapath/switch-flow.h | 100 - openflow/udatapath/table-hash.c | 469 --- openflow/udatapath/table-linear.c | 262 -- openflow/udatapath/table.h | 150 - openflow/udatapath/udatapath.c | 345 -- openflow/utilities/.dirstamp | 0 openflow/utilities/.gitignore | 13 - openflow/utilities/automake.mk | 45 - openflow/utilities/dpctl.8.in | 582 --- openflow/utilities/dpctl.c | 1772 --------- openflow/utilities/ofp-discover.8.in | 119 - openflow/utilities/ofp-discover.c | 420 -- openflow/utilities/ofp-kill.8.in | 61 - openflow/utilities/ofp-kill.c | 228 -- openflow/utilities/ofp-parse-leaks | 285 -- openflow/utilities/ofp-parse-leaks.in | 285 -- openflow/utilities/ofp-pki-cgi.in | 41 - openflow/utilities/ofp-pki.8.in | 325 -- openflow/utilities/ofp-pki.in | 582 --- openflow/utilities/vlogconf.8.in | 183 - openflow/utilities/vlogconf.c | 235 -- .../utilities/wireshark_dissectors/Makefile | 32 - .../utilities/wireshark_dissectors/README | 37 - .../wireshark_dissectors/openflow/.gitignore | 1 - .../wireshark_dissectors/openflow/Makefile | 79 - .../wireshark_dissectors/openflow/Makefile.am | 110 - .../openflow/Makefile.common | 13 - .../openflow/build_distribution_tarball.sh | 63 - .../openflow/moduleinfo.h | 15 - .../openflow/packet-openflow.c | 3426 ---------------- .../wireshark_dissectors/openflow/plugin.c | 28 - .../wireshark-1.0.0-includes/airpcap.h | 907 ----- .../wireshark-1.0.0-includes/airpcap_loader.h | 560 --- .../wireshark-1.0.0-includes/alert_box.h | 70 - .../capture-pcap-util-int.h | 56 - .../capture-pcap-util.h | 131 - .../wireshark-1.0.0-includes/capture-wpcap.h | 34 - .../wireshark-1.0.0-includes/capture.h | 118 - .../wireshark-1.0.0-includes/capture_errs.h | 34 - .../wireshark-1.0.0-includes/capture_info.h | 76 - .../wireshark-1.0.0-includes/capture_opts.h | 194 - .../capture_stop_conditions.h | 29 - .../wireshark-1.0.0-includes/capture_sync.h | 87 - .../capture_ui_utils.h | 89 - .../capture_wpcap_packet.h | 47 - .../wireshark-1.0.0-includes/cfile.h | 91 - .../wireshark-1.0.0-includes/clopts_common.h | 40 - .../wireshark-1.0.0-includes/cmdarg_err.h | 56 - .../wireshark-1.0.0-includes/color.h | 55 - .../wireshark-1.0.0-includes/color_filters.h | 196 - .../wireshark-1.0.0-includes/conditions.h | 134 - .../wireshark-1.0.0-includes/config.h | 322 -- .../wireshark-1.0.0-includes/config.h.in | 321 -- .../wireshark-1.0.0-includes/config.h.win32 | 274 -- .../disabled_protos.h | 61 - .../epan/addr_and_mask.h | 53 - .../epan/addr_resolv.h | 198 - .../wireshark-1.0.0-includes/epan/address.h | 172 - .../wireshark-1.0.0-includes/epan/adler32.h | 42 - .../wireshark-1.0.0-includes/epan/afn.h | 71 - .../wireshark-1.0.0-includes/epan/aftypes.h | 47 - .../epan/arcnet_pids.h | 70 - .../wireshark-1.0.0-includes/epan/arptypes.h | 75 - .../wireshark-1.0.0-includes/epan/asm_utils.h | 38 - .../wireshark-1.0.0-includes/epan/asn1.h | 207 - .../epan/atalk-utils.h | 63 - .../wireshark-1.0.0-includes/epan/base64.h | 38 - .../wireshark-1.0.0-includes/epan/bitswap.h | 40 - .../epan/bridged_pids.h | 58 - .../epan/camel-persistentdata.h | 127 - .../wireshark-1.0.0-includes/epan/charsets.h | 42 - .../epan/chdlctypes.h | 40 - .../wireshark-1.0.0-includes/epan/circuit.h | 80 - .../wireshark-1.0.0-includes/epan/codecs.h | 43 - .../epan/column-utils.h | 241 -- .../wireshark-1.0.0-includes/epan/column.h | 56 - .../epan/column_info.h | 134 - .../epan/conversation.h | 109 - .../wireshark-1.0.0-includes/epan/crc10.h | 27 - .../wireshark-1.0.0-includes/epan/crc16.h | 109 - .../wireshark-1.0.0-includes/epan/crc32.h | 94 - .../wireshark-1.0.0-includes/epan/crc6.h | 26 - .../wireshark-1.0.0-includes/epan/crcdrm.h | 7 - .../epan/crypt/airpdcap_debug.h | 106 - .../epan/crypt/airpdcap_int.h | 158 - .../epan/crypt/airpdcap_interop.h | 101 - .../epan/crypt/airpdcap_rijndael.h | 93 - .../epan/crypt/airpdcap_system.h | 356 -- .../epan/crypt/airpdcap_user.h | 231 -- .../epan/crypt/airpdcap_ws.h | 43 - .../epan/crypt/crypt-des.h | 26 - .../epan/crypt/crypt-md4.h | 23 - .../epan/crypt/crypt-md5.h | 71 - .../epan/crypt/crypt-rc4.h | 36 - .../epan/crypt/crypt-sha1.h | 45 - .../epan/crypt/wep-wpadefs.h | 115 - .../epan/dfilter/dfilter-int.h | 82 - .../epan/dfilter/dfilter-macro.h | 59 - .../epan/dfilter/dfilter.h | 94 - .../epan/dfilter/dfunctions.h | 56 - .../epan/dfilter/dfvm.h | 108 - .../epan/dfilter/drange.h | 102 - .../epan/dfilter/gencode.h | 10 - .../epan/dfilter/glib-util.h | 4 - .../epan/dfilter/grammar.h | 24 - .../epan/dfilter/scanner_lex.h | 6 - .../epan/dfilter/semcheck.h | 31 - .../epan/dfilter/sttype-function.h | 42 - .../epan/dfilter/sttype-range.h | 45 - .../epan/dfilter/sttype-test.h | 56 - .../epan/dfilter/syntax-tree.h | 136 - .../wireshark-1.0.0-includes/epan/diam_dict.h | 89 - .../epan/diam_dict_lex.h | 6 - .../epan/dissector_filters.h | 60 - .../epan/dissectors/packet-tcp.h | 232 -- .../wireshark-1.0.0-includes/epan/dtd.h | 62 - .../epan/dtd_grammar.h | 23 - .../wireshark-1.0.0-includes/epan/dtd_parse.h | 37 - .../epan/dtd_parse_lex.h | 6 - .../epan/dtd_preparse_lex.h | 6 - .../wireshark-1.0.0-includes/epan/eap.h | 53 - .../wireshark-1.0.0-includes/epan/emem.h | 373 -- .../wireshark-1.0.0-includes/epan/epan.h | 93 - .../epan/epan_dissect.h | 44 - .../wireshark-1.0.0-includes/epan/etypes.h | 408 -- .../wireshark-1.0.0-includes/epan/ex-opt.h | 44 - .../wireshark-1.0.0-includes/epan/except.h | 158 - .../epan/exceptions.h | 319 -- .../wireshark-1.0.0-includes/epan/expert.h | 70 - .../epan/filesystem.h | 248 -- .../wireshark-1.0.0-includes/epan/follow.h | 58 - .../epan/frame_data.h | 79 - .../epan/frequency-utils.h | 74 - .../epan/ftypes/ftypes-int.h | 61 - .../epan/ftypes/ftypes.h | 367 -- .../wireshark-1.0.0-includes/epan/funnel.h | 116 - .../epan/g_ascii_strcasecmp.h | 18 - .../epan/g_ascii_strtoull.h | 15 - .../wireshark-1.0.0-includes/epan/garrayfix.h | 38 - .../wireshark-1.0.0-includes/epan/gcp.h | 219 - .../epan/gnuc_format_check.h | 39 - .../wireshark-1.0.0-includes/epan/golay.h | 49 - .../wireshark-1.0.0-includes/epan/greproto.h | 36 - .../epan/guid-utils.h | 63 - .../epan/h225-persistentdata.h | 62 - .../epan/iax2_codec_type.h | 77 - .../wireshark-1.0.0-includes/epan/in_cksum.h | 14 - .../wireshark-1.0.0-includes/epan/inet_aton.h | 34 - .../wireshark-1.0.0-includes/epan/ip_opts.h | 59 - .../wireshark-1.0.0-includes/epan/ipproto.h | 193 - .../wireshark-1.0.0-includes/epan/ipv4.h | 67 - .../epan/ipv6-utils.h | 49 - .../wireshark-1.0.0-includes/epan/lapd_sapi.h | 38 - .../wireshark-1.0.0-includes/epan/llcsaps.h | 63 - .../wireshark-1.0.0-includes/epan/next_tvb.h | 65 - .../wireshark-1.0.0-includes/epan/nlpid.h | 60 - .../wireshark-1.0.0-includes/epan/nstime.h | 92 - .../wireshark-1.0.0-includes/epan/oids.h | 179 - .../wireshark-1.0.0-includes/epan/osi-utils.h | 57 - .../wireshark-1.0.0-includes/epan/oui.h | 74 - .../wireshark-1.0.0-includes/epan/packet.h | 422 -- .../epan/packet_info.h | 184 - .../wireshark-1.0.0-includes/epan/pint.h | 113 - .../wireshark-1.0.0-includes/epan/plugins.h | 58 - .../wireshark-1.0.0-includes/epan/ppptypes.h | 158 - .../wireshark-1.0.0-includes/epan/prefs-int.h | 111 - .../wireshark-1.0.0-includes/epan/prefs.h | 426 -- .../epan/privileges.h | 74 - .../wireshark-1.0.0-includes/epan/proto.h | 1655 -------- .../wireshark-1.0.0-includes/epan/ptvcursor.h | 110 - .../epan/radius_dict_lex.h | 6 - .../wireshark-1.0.0-includes/epan/range.h | 73 - .../epan/reassemble.h | 316 -- .../epan/reedsolomon.h | 86 - .../epan/report_err.h | 61 - .../epan/req_resp_hdrs.h | 43 - .../wireshark-1.0.0-includes/epan/rtp_pt.h | 68 - .../wireshark-1.0.0-includes/epan/sctpppids.h | 50 - .../epan/sigcomp-udvm.h | 49 - .../epan/sigcomp_state_hdlr.h | 49 - .../wireshark-1.0.0-includes/epan/slab.h | 75 - .../wireshark-1.0.0-includes/epan/sminmpec.h | 83 - .../wireshark-1.0.0-includes/epan/sna-utils.h | 41 - .../epan/stat_cmd_args.h | 35 - .../epan/stats_tree.h | 147 - .../epan/stats_tree_priv.h | 202 - .../wireshark-1.0.0-includes/epan/stream.h | 138 - .../wireshark-1.0.0-includes/epan/strutil.h | 243 -- .../wireshark-1.0.0-includes/epan/t35.h | 35 - .../wireshark-1.0.0-includes/epan/tap-voip.h | 59 - .../wireshark-1.0.0-includes/epan/tap.h | 61 - .../epan/tcap-persistentdata.h | 148 - .../wireshark-1.0.0-includes/epan/tfs.h | 65 - .../wireshark-1.0.0-includes/epan/timestamp.h | 68 - .../wireshark-1.0.0-includes/epan/to_str.h | 94 - .../wireshark-1.0.0-includes/epan/tvbparse.h | 475 --- .../wireshark-1.0.0-includes/epan/tvbuff.h | 634 --- .../wireshark-1.0.0-includes/epan/uat-int.h | 92 - .../wireshark-1.0.0-includes/epan/uat.h | 486 --- .../epan/uat_load_lex.h | 6 - .../epan/unicode-utils.h | 54 - .../epan/value_string.h | 88 - .../epan/ws_strsplit.h | 41 - .../epan/wslua/declare_wslua.h | 59 - .../epan/wslua/wslua.h | 372 -- .../epan/x264_prt_id.h | 35 - .../wireshark-1.0.0-includes/epan/xdlc.h | 140 - .../wireshark-1.0.0-includes/epan/xmlstub.h | 1123 ------ .../wireshark-1.0.0-includes/file.h | 486 --- .../wireshark-1.0.0-includes/fileset.h | 75 - .../wireshark-1.0.0-includes/filters.h | 87 - .../wireshark-1.0.0-includes/g711.h | 30 - .../wireshark-1.0.0-includes/getopt.h | 129 - .../wireshark-1.0.0-includes/globals.h | 37 - .../wireshark-1.0.0-includes/inet_v6defs.h | 54 - .../wireshark-1.0.0-includes/isprint.h | 46 - .../wireshark-1.0.0-includes/log.h | 42 - .../wireshark-1.0.0-includes/main_window.h | 41 - .../wireshark-1.0.0-includes/menu.h | 64 - .../wireshark-1.0.0-includes/merge.h | 125 - .../wireshark-1.0.0-includes/mkstemp.h | 24 - .../wireshark-1.0.0-includes/packet-range.h | 101 - .../wireshark-1.0.0-includes/pcapio.h | 44 - .../wireshark-1.0.0-includes/print.h | 148 - .../wireshark-1.0.0-includes/progress_dlg.h | 94 - .../proto_hier_stats.h | 51 - .../wireshark-1.0.0-includes/ps.h | 35 - .../wireshark-1.0.0-includes/register.h | 48 - .../wireshark-1.0.0-includes/ringbuffer.h | 53 - .../wireshark-1.0.0-includes/simple_dialog.h | 184 - .../wireshark-1.0.0-includes/stat_menu.h | 64 - .../wireshark-1.0.0-includes/statusbar.h | 56 - .../wireshark-1.0.0-includes/strerror.h | 33 - .../wireshark-1.0.0-includes/strptime.h | 32 - .../wireshark-1.0.0-includes/summary.h | 76 - .../wireshark-1.0.0-includes/svnversion.h | 1 - .../wireshark-1.0.0-includes/sync_pipe.h | 80 - .../wireshark-1.0.0-includes/tap-rtp-common.h | 49 - .../tap_dfilter_dlg.h | 73 - .../wireshark-1.0.0-includes/tempfile.h | 43 - .../wireshark-1.0.0-includes/text2pcap.h | 49 - .../wireshark-1.0.0-includes/timestats.h | 54 - .../tools/make-dissector-reg | 186 - .../tools/make-dissector-reg.py | 238 -- .../wireshark-1.0.0-includes/ui_util.h | 79 - .../wireshark-1.0.0-includes/util.h | 60 - .../wireshark-1.0.0-includes/version_info.h | 79 - .../wireshark-1.0.0-includes/wiretap/5views.h | 30 - .../wiretap/airopeek9.h | 29 - .../wiretap/ascend-grammar.h | 90 - .../wiretap/ascend-int.h | 54 - .../wiretap/ascend-scanner_lex.h | 6 - .../wireshark-1.0.0-includes/wiretap/ascend.h | 33 - .../wireshark-1.0.0-includes/wiretap/atm.h | 40 - .../wireshark-1.0.0-includes/wiretap/ber.h | 28 - .../wiretap/btsnoop.h | 30 - .../wireshark-1.0.0-includes/wiretap/buffer.h | 58 - .../wiretap/catapult_dct2000.h | 30 - .../wiretap/commview.h | 33 - .../wireshark-1.0.0-includes/wiretap/cosine.h | 32 - .../wireshark-1.0.0-includes/wiretap/csids.h | 29 - .../wiretap/dbs-etherwatch.h | 29 - .../wireshark-1.0.0-includes/wiretap/erf.h | 102 - .../wiretap/etherpeek.h | 29 - .../wireshark-1.0.0-includes/wiretap/eyesdn.h | 29 - .../wiretap/file_util.h | 136 - .../wiretap/file_wrappers.h | 57 - .../wiretap/hcidump.h | 28 - .../wiretap/i4b_trace.h | 92 - .../wiretap/i4btrace.h | 29 - .../wiretap/iptrace.h | 29 - .../wiretap/iseries.h | 28 - .../wireshark-1.0.0-includes/wiretap/k12.h | 28 - .../wiretap/k12text_lex.h | 6 - .../wiretap/lanalyzer.h | 176 - .../wiretap/libpcap.h | 106 - .../wiretap/mpeg-audio.h | 98 - .../wireshark-1.0.0-includes/wiretap/mpeg.h | 32 - .../wireshark-1.0.0-includes/wiretap/netmon.h | 30 - .../wiretap/netscreen.h | 53 - .../wireshark-1.0.0-includes/wiretap/nettl.h | 124 - .../wiretap/network_instruments.h | 127 - .../wiretap/netxray.h | 32 - .../wiretap/ngsniffer.h | 30 - .../wireshark-1.0.0-includes/wiretap/pcapng.h | 30 - .../wiretap/pppdump.h | 28 - .../wireshark-1.0.0-includes/wiretap/radcom.h | 29 - .../wireshark-1.0.0-includes/wiretap/snoop.h | 30 - .../wiretap/toshiba.h | 28 - .../wireshark-1.0.0-includes/wiretap/visual.h | 35 - .../wireshark-1.0.0-includes/wiretap/vms.h | 29 - .../wiretap/wtap-int.h | 482 --- .../wireshark-1.0.0-includes/wiretap/wtap.h | 944 ----- 697 files changed, 95060 deletions(-) delete mode 100644 openflow/.gitignore delete mode 100644 openflow/COPYING delete mode 100644 openflow/ChangeLog delete mode 100644 openflow/INSTALL delete mode 100644 openflow/Makefile.am delete mode 100644 openflow/README delete mode 100644 openflow/README.hwtables delete mode 100644 openflow/README.kernel delete mode 100644 openflow/acinclude.m4 delete mode 100755 openflow/boot.sh delete mode 100644 openflow/configure.ac delete mode 100644 openflow/controller/.dirstamp delete mode 100644 openflow/controller/.gitignore delete mode 100644 openflow/controller/automake.mk delete mode 100644 openflow/controller/controller.8.in delete mode 100644 openflow/controller/controller.c delete mode 100644 openflow/datapath/.gitignore delete mode 100644 openflow/datapath/Makefile.am delete mode 100644 openflow/datapath/Modules.mk delete mode 100644 openflow/datapath/chain.c delete mode 100644 openflow/datapath/chain.h delete mode 100644 openflow/datapath/compat.h delete mode 100644 openflow/datapath/crc32.c delete mode 100644 openflow/datapath/crc32.h delete mode 100644 openflow/datapath/datapath.c delete mode 100644 openflow/datapath/datapath.h delete mode 100644 openflow/datapath/dp_act.c delete mode 100644 openflow/datapath/dp_act.h delete mode 100644 openflow/datapath/dp_dev.c delete mode 100644 openflow/datapath/dp_dev.h delete mode 100644 openflow/datapath/dp_notify.c delete mode 100644 openflow/datapath/flow.c delete mode 100644 openflow/datapath/flow.h delete mode 100644 openflow/datapath/forward.c delete mode 100644 openflow/datapath/forward.h delete mode 100644 openflow/datapath/hwtable_dummy/Modules.mk delete mode 100644 openflow/datapath/hwtable_dummy/hwtable_dummy.c delete mode 100644 openflow/datapath/hwtable_nf2/Modules.mk delete mode 100644 openflow/datapath/hwtable_nf2/README delete mode 100644 openflow/datapath/hwtable_nf2/nf2.h delete mode 100644 openflow/datapath/hwtable_nf2/nf2_flowtable.c delete mode 100644 openflow/datapath/hwtable_nf2/nf2_flowtable.h delete mode 100644 openflow/datapath/hwtable_nf2/nf2_hwapi.h delete mode 100644 openflow/datapath/hwtable_nf2/nf2_lib.c delete mode 100644 openflow/datapath/hwtable_nf2/nf2_lib.h delete mode 100644 openflow/datapath/hwtable_nf2/nf2_openflow.c delete mode 100644 openflow/datapath/hwtable_nf2/nf2_openflow.h delete mode 100644 openflow/datapath/hwtable_nf2/nf2_procfs.c delete mode 100644 openflow/datapath/hwtable_nf2/nf2_procfs.h delete mode 100644 openflow/datapath/hwtable_nf2/nf2_reg.h delete mode 100644 openflow/datapath/hwtable_nf2/openflow_switch.bit delete mode 100644 openflow/datapath/linux-2.6/.gitignore delete mode 100644 openflow/datapath/linux-2.6/Kbuild.in delete mode 100644 openflow/datapath/linux-2.6/Makefile.in delete mode 100644 openflow/datapath/linux-2.6/Makefile.main.in delete mode 100644 openflow/datapath/linux-2.6/Modules.mk delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/compat26.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/genetlink-brcompat.c delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/genetlink-openflow.c delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/asm-generic/bug.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/dmi.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/icmp.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/if_arp.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/ip.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/ipv6.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/jiffies.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/lockdep.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/mutex.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/netdevice.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/netfilter_bridge.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/netfilter_ipv4.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/netlink.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/random.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/rculist.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/skbuff.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/tcp.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/timer.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/types.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/udp.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/workqueue.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/net/checksum.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/net/genetlink.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/net/netlink.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/random32.c delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/veth.c delete mode 100644 openflow/datapath/linux-2.6/config/config-linux-2.6.23-rc9-kvm delete mode 100644 openflow/datapath/openflow-ext.c delete mode 100644 openflow/datapath/openflow-ext.h delete mode 100644 openflow/datapath/private-msg.c delete mode 100644 openflow/datapath/private-msg.h delete mode 100644 openflow/datapath/table-hash.c delete mode 100644 openflow/datapath/table-linear.c delete mode 100644 openflow/datapath/table.h delete mode 100644 openflow/debian/.gitignore delete mode 100644 openflow/debian/changelog delete mode 100755 openflow/debian/commands/reconfigure delete mode 100755 openflow/debian/commands/update delete mode 100644 openflow/debian/compat delete mode 100644 openflow/debian/control.in delete mode 100644 openflow/debian/control.modules.in delete mode 100644 openflow/debian/copyright delete mode 100755 openflow/debian/corekeeper.cron.daily delete mode 100755 openflow/debian/corekeeper.init delete mode 100644 openflow/debian/dirs delete mode 100755 openflow/debian/ofp-switch-setup delete mode 100644 openflow/debian/ofp-switch-setup.8 delete mode 100644 openflow/debian/openflow-common.dirs delete mode 100644 openflow/debian/openflow-common.install delete mode 100644 openflow/debian/openflow-common.manpages delete mode 100644 openflow/debian/openflow-controller.README.Debian delete mode 100644 openflow/debian/openflow-controller.default delete mode 100644 openflow/debian/openflow-controller.dirs delete mode 100755 openflow/debian/openflow-controller.init delete mode 100644 openflow/debian/openflow-controller.install delete mode 100644 openflow/debian/openflow-controller.manpages delete mode 100755 openflow/debian/openflow-controller.postinst delete mode 100755 openflow/debian/openflow-datapath-module-_KVERS_.postinst.modules.in delete mode 100644 openflow/debian/openflow-datapath-source.README.Debian delete mode 100644 openflow/debian/openflow-datapath-source.copyright delete mode 100644 openflow/debian/openflow-datapath-source.dirs delete mode 100644 openflow/debian/openflow-datapath-source.install delete mode 100644 openflow/debian/openflow-pki-server.apache2 delete mode 100644 openflow/debian/openflow-pki-server.dirs delete mode 100644 openflow/debian/openflow-pki-server.install delete mode 100755 openflow/debian/openflow-pki-server.postinst delete mode 100755 openflow/debian/openflow-pki.postinst delete mode 100644 openflow/debian/openflow-switch-config.dirs delete mode 100644 openflow/debian/openflow-switch-config.install delete mode 100644 openflow/debian/openflow-switch-config.manpages delete mode 100644 openflow/debian/openflow-switch-config.overrides delete mode 100644 openflow/debian/openflow-switch-config.templates delete mode 100644 openflow/debian/openflow-switch.README.Debian delete mode 100644 openflow/debian/openflow-switch.dirs delete mode 100755 openflow/debian/openflow-switch.init delete mode 100644 openflow/debian/openflow-switch.install delete mode 100644 openflow/debian/openflow-switch.logrotate delete mode 100644 openflow/debian/openflow-switch.manpages delete mode 100755 openflow/debian/openflow-switch.postinst delete mode 100755 openflow/debian/openflow-switch.postrm delete mode 100644 openflow/debian/openflow-switch.template delete mode 100644 openflow/debian/po/POTFILES.in delete mode 100755 openflow/debian/rules delete mode 100644 openflow/doc/of-spec/.gitignore delete mode 100644 openflow/doc/of-spec/Makefile delete mode 100644 openflow/doc/of-spec/README delete mode 100755 openflow/doc/of-spec/appendix.tex delete mode 100644 openflow/doc/of-spec/credits.tex delete mode 100755 openflow/doc/of-spec/figure_flow_table_secchan.png delete mode 100644 openflow/doc/of-spec/header_parsing_flowchart.graffle delete mode 100755 openflow/doc/of-spec/make_latex_input.pl delete mode 100644 openflow/doc/of-spec/openflow-spec-v1.0.0.tex delete mode 100644 openflow/doc/of-spec/packet_flow_flowchart.graffle delete mode 100644 openflow/hw-lib/automake.mk delete mode 100644 openflow/hw-lib/nf2/README delete mode 100644 openflow/hw-lib/nf2/debug.h delete mode 100644 openflow/hw-lib/nf2/hw_flow.c delete mode 100644 openflow/hw-lib/nf2/hw_flow.h delete mode 100644 openflow/hw-lib/nf2/nf2.h delete mode 100644 openflow/hw-lib/nf2/nf2_drv.c delete mode 100644 openflow/hw-lib/nf2/nf2_drv.h delete mode 100644 openflow/hw-lib/nf2/nf2_lib.c delete mode 100644 openflow/hw-lib/nf2/nf2_lib.h delete mode 100644 openflow/hw-lib/nf2/nf2util.c delete mode 100644 openflow/hw-lib/nf2/nf2util.h delete mode 100644 openflow/hw-lib/nf2/reg_defines_openflow_switch.h delete mode 100644 openflow/hw-lib/skeleton/debug.h delete mode 100644 openflow/hw-lib/skeleton/hw_drv.c delete mode 100644 openflow/hw-lib/skeleton/hw_drv.h delete mode 100644 openflow/hw-lib/skeleton/hw_flow.c delete mode 100644 openflow/hw-lib/skeleton/hw_flow.h delete mode 100644 openflow/hw-lib/skeleton/of_hw_platform.h delete mode 100644 openflow/hw-lib/skeleton/os.h delete mode 100644 openflow/hw-lib/skeleton/port.c delete mode 100644 openflow/hw-lib/skeleton/port.h delete mode 100644 openflow/hw-lib/skeleton/sample_plat.c delete mode 100644 openflow/hw-lib/skeleton/sample_plat.h delete mode 100644 openflow/hw-lib/skeleton/txrx.c delete mode 100644 openflow/hw-lib/skeleton/txrx.h delete mode 100644 openflow/include/.gitignore delete mode 100644 openflow/include/automake.mk delete mode 100644 openflow/include/openflow/automake.mk delete mode 100644 openflow/include/openflow/nicira-ext.h delete mode 100644 openflow/include/openflow/of_hw_api.h delete mode 100644 openflow/include/openflow/openflow-ext.h delete mode 100644 openflow/include/openflow/openflow-netlink.h delete mode 100644 openflow/include/openflow/openflow.h delete mode 100644 openflow/include/openflow/private-ext.h delete mode 100644 openflow/m4/libopenflow.m4 delete mode 100644 openflow/m4/nx-build.m4 delete mode 100644 openflow/regress/CREDITS delete mode 100644 openflow/regress/INSTALL delete mode 100644 openflow/regress/LICENSE delete mode 100644 openflow/regress/README delete mode 100644 openflow/regress/bin/eth.map delete mode 100644 openflow/regress/bin/nf2.map delete mode 100644 openflow/regress/bin/of_hp_eth.map delete mode 100755 openflow/regress/bin/of_hp_setup.pl delete mode 100755 openflow/regress/bin/of_hp_teardown.pl delete mode 100755 openflow/regress/bin/of_hp_test.pl delete mode 100755 openflow/regress/bin/of_hp_test_6600.pl delete mode 100755 openflow/regress/bin/of_kmod_setup.pl delete mode 100755 openflow/regress/bin/of_kmod_teardown.pl delete mode 100755 openflow/regress/bin/of_kmod_test.pl delete mode 100755 openflow/regress/bin/of_kmod_veth_setup.pl delete mode 100755 openflow/regress/bin/of_kmod_veth_teardown.pl delete mode 100755 openflow/regress/bin/of_kmod_veth_test.pl delete mode 100755 openflow/regress/bin/of_nf2_setup.pl delete mode 100755 openflow/regress/bin/of_nf2_teardown.pl delete mode 100755 openflow/regress/bin/of_nf2_test.pl delete mode 100644 openflow/regress/bin/of_ovs_eth.map delete mode 100755 openflow/regress/bin/of_ovs_setup.pl delete mode 100755 openflow/regress/bin/of_ovs_teardown.pl delete mode 100755 openflow/regress/bin/of_ovs_test.pl delete mode 100755 openflow/regress/bin/of_ovs_user_setup.pl delete mode 100755 openflow/regress/bin/of_ovs_user_teardown.pl delete mode 100755 openflow/regress/bin/of_ovs_user_test.pl delete mode 100755 openflow/regress/bin/of_ovs_user_veth_test.pl delete mode 100755 openflow/regress/bin/of_ovs_veth_test.pl delete mode 100755 openflow/regress/bin/of_user_setup.pl delete mode 100755 openflow/regress/bin/of_user_teardown.pl delete mode 100755 openflow/regress/bin/of_user_test.pl delete mode 100755 openflow/regress/bin/of_user_veth_setup.pl delete mode 100755 openflow/regress/bin/of_user_veth_teardown.pl delete mode 100755 openflow/regress/bin/of_user_veth_test.pl delete mode 100644 openflow/regress/bin/veth.map delete mode 100755 openflow/regress/bin/veth_setup.pl delete mode 100755 openflow/regress/bin/veth_teardown.pl delete mode 100755 openflow/regress/projects/black_box/regress/common/setup delete mode 100755 openflow/regress/projects/black_box/regress/common/teardown delete mode 100755 openflow/regress/projects/black_box/regress/test_add_flow_latency/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_barrier/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_cookie_flow_expired/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_cookie_flow_stats/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_delete/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_delete_send_flow_exp/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_delete_strict/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_drop_exact/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_failover_close/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_failover_startup/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_failover_stop_responding/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_flow_expired/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_flow_expired_idle_timeout/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_flow_expired_precision/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_flow_expired_send_flow_exp/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_flow_mod_check/run.pl delete mode 100644 openflow/regress/projects/black_box/regress/test_flow_mod_latency/run-port3.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_flow_mod_latency/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_flow_stats/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_flow_stats_precision/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_after_expiration/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_any_port/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_bandwidth_fixed/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_bandwidth_random/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_broadcast_exact_port/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_all/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_arp_all/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_arp_controller/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_arp_fool/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_arp_port/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_controller/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_icmp_all/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_icmp_controller/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_icmp_fool/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_icmp_port/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_modify_action/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_port/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_overlapping_flow_entries/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_all/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_all/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_controller/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_fool/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_port/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_controller/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_all/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_controller/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_fool/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_port/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_modify_action/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_port/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_hello/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_ip_offset/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_ip_options/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_ip_protocol/case-c.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_ip_protocol/case-d.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_ip_protocol/case-e.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_ip_protocol/case-tcp.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_ip_protocol/case-udp.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_llc/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_miss_send_length/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_packet_in/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_packet_out/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_port_stats/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_queue_config/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_queue_forward/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_queue_stats/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_receive_bandwidth_fixed/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_send_bandwidth_fixed/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_send_bandwidth_random/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_set_dl_nw_flip/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_set_n_match_nw_tos/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_set_nw_dst/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_stats_desc/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_switch_config/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_tcp_options/run.pl delete mode 100644 openflow/regress/projects/black_box/regress/tests.txt delete mode 100755 openflow/regress/projects/controller_disconnect/regress/common/setup delete mode 100755 openflow/regress/projects/controller_disconnect/regress/common/teardown delete mode 100755 openflow/regress/projects/controller_disconnect/regress/test_emergency_table/run.pl delete mode 100644 openflow/regress/projects/controller_disconnect/regress/tests.txt delete mode 100755 openflow/regress/projects/learning_switch/regress/common/setup delete mode 100755 openflow/regress/projects/learning_switch/regress/common/teardown delete mode 100755 openflow/regress/projects/learning_switch/regress/test_broadcast/run.pl delete mode 100755 openflow/regress/projects/learning_switch/regress/test_forward_bandwidth/run.pl delete mode 100755 openflow/regress/projects/learning_switch/regress/test_forward_latency/run.pl delete mode 100755 openflow/regress/projects/learning_switch/regress/test_hub_connected/run.pl delete mode 100755 openflow/regress/projects/learning_switch/regress/test_unicast_known/run.pl delete mode 100755 openflow/regress/projects/learning_switch/regress/test_unicast_move/run.pl delete mode 100755 openflow/regress/projects/learning_switch/regress/test_unicast_multiple_hosts/run.pl delete mode 100755 openflow/regress/projects/learning_switch/regress/test_unicast_self/run.pl delete mode 100755 openflow/regress/projects/learning_switch/regress/test_unicast_unknown/run.pl delete mode 100644 openflow/regress/projects/learning_switch/regress/tests.txt delete mode 100644 openflow/regress/projects/regress.txt delete mode 100755 openflow/regress/scripts/copy_NF2_code.sh delete mode 100644 openflow/regress/scripts/env_vars delete mode 100755 openflow/regress/scripts/install_deps.pl delete mode 100755 openflow/regress/scripts/install_perlmods_apt.pl delete mode 100755 openflow/regress/scripts/make_release.pl delete mode 100644 openflow/secchan/.dirstamp delete mode 100644 openflow/secchan/.gitignore delete mode 100644 openflow/secchan/automake.mk delete mode 100644 openflow/secchan/commands/automake.mk delete mode 100755 openflow/secchan/commands/reboot delete mode 100644 openflow/secchan/discovery.c delete mode 100644 openflow/secchan/discovery.h delete mode 100644 openflow/secchan/emerg-flow.c delete mode 100644 openflow/secchan/emerg-flow.h delete mode 100644 openflow/secchan/fail-open.c delete mode 100644 openflow/secchan/fail-open.h delete mode 100644 openflow/secchan/failover.c delete mode 100644 openflow/secchan/failover.h delete mode 100644 openflow/secchan/in-band.c delete mode 100644 openflow/secchan/in-band.h delete mode 100644 openflow/secchan/ofprotocol.8.in delete mode 100644 openflow/secchan/port-watcher.c delete mode 100644 openflow/secchan/port-watcher.h delete mode 100644 openflow/secchan/protocol-stat.c delete mode 100644 openflow/secchan/protocol-stat.h delete mode 100644 openflow/secchan/ratelimit.c delete mode 100644 openflow/secchan/ratelimit.h delete mode 100644 openflow/secchan/secchan.c delete mode 100644 openflow/secchan/secchan.h delete mode 100644 openflow/secchan/status.c delete mode 100644 openflow/secchan/status.h delete mode 100644 openflow/secchan/stp-secchan.c delete mode 100644 openflow/secchan/stp-secchan.h delete mode 100755 openflow/soexpand.pl delete mode 100644 openflow/tests/.dirstamp delete mode 100644 openflow/tests/.gitignore delete mode 100644 openflow/tests/automake.mk delete mode 100755 openflow/tests/flowgen.pl delete mode 100644 openflow/tests/test-dhcp-client.c delete mode 100755 openflow/tests/test-flows delete mode 100644 openflow/tests/test-flows.c delete mode 100755 openflow/tests/test-flows.sh delete mode 100755 openflow/tests/test-hmap delete mode 100644 openflow/tests/test-hmap.c delete mode 100644 openflow/tests/test-list.c delete mode 100644 openflow/tests/test-stp-ieee802.1d-1998 delete mode 100644 openflow/tests/test-stp-ieee802.1d-2004-fig17.4 delete mode 100644 openflow/tests/test-stp-ieee802.1d-2004-fig17.6 delete mode 100644 openflow/tests/test-stp-ieee802.1d-2004-fig17.7 delete mode 100644 openflow/tests/test-stp-iol-io-1.1 delete mode 100644 openflow/tests/test-stp-iol-io-1.2 delete mode 100644 openflow/tests/test-stp-iol-io-1.4 delete mode 100644 openflow/tests/test-stp-iol-io-1.5 delete mode 100644 openflow/tests/test-stp-iol-op-1.1 delete mode 100644 openflow/tests/test-stp-iol-op-1.4 delete mode 100644 openflow/tests/test-stp-iol-op-3.1 delete mode 100644 openflow/tests/test-stp-iol-op-3.3 delete mode 100644 openflow/tests/test-stp-iol-op-3.4 delete mode 100644 openflow/tests/test-stp.c delete mode 100755 openflow/tests/test-stp.sh delete mode 100644 openflow/tests/test-type-props.c delete mode 100644 openflow/third-party/.gitignore delete mode 100644 openflow/third-party/README delete mode 100644 openflow/third-party/automake.mk delete mode 100644 openflow/third-party/ofp-tcpdump.patch delete mode 100644 openflow/udatapath/.dirstamp delete mode 100644 openflow/udatapath/.gitignore delete mode 100644 openflow/udatapath/automake.mk delete mode 100644 openflow/udatapath/chain.c delete mode 100644 openflow/udatapath/chain.h delete mode 100644 openflow/udatapath/crc32.c delete mode 100644 openflow/udatapath/crc32.h delete mode 100644 openflow/udatapath/datapath.c delete mode 100644 openflow/udatapath/datapath.h delete mode 100644 openflow/udatapath/dp_act.c delete mode 100644 openflow/udatapath/dp_act.h delete mode 100644 openflow/udatapath/of_ext_msg.c delete mode 100644 openflow/udatapath/of_ext_msg.h delete mode 100644 openflow/udatapath/ofdatapath.8.in delete mode 100644 openflow/udatapath/private-msg.c delete mode 100644 openflow/udatapath/private-msg.h delete mode 100644 openflow/udatapath/switch-flow.c delete mode 100644 openflow/udatapath/switch-flow.h delete mode 100644 openflow/udatapath/table-hash.c delete mode 100644 openflow/udatapath/table-linear.c delete mode 100644 openflow/udatapath/table.h delete mode 100644 openflow/udatapath/udatapath.c delete mode 100644 openflow/utilities/.dirstamp delete mode 100644 openflow/utilities/.gitignore delete mode 100644 openflow/utilities/automake.mk delete mode 100644 openflow/utilities/dpctl.8.in delete mode 100644 openflow/utilities/dpctl.c delete mode 100644 openflow/utilities/ofp-discover.8.in delete mode 100644 openflow/utilities/ofp-discover.c delete mode 100644 openflow/utilities/ofp-kill.8.in delete mode 100644 openflow/utilities/ofp-kill.c delete mode 100644 openflow/utilities/ofp-parse-leaks delete mode 100755 openflow/utilities/ofp-parse-leaks.in delete mode 100755 openflow/utilities/ofp-pki-cgi.in delete mode 100644 openflow/utilities/ofp-pki.8.in delete mode 100755 openflow/utilities/ofp-pki.in delete mode 100644 openflow/utilities/vlogconf.8.in delete mode 100644 openflow/utilities/vlogconf.c delete mode 100644 openflow/utilities/wireshark_dissectors/Makefile delete mode 100644 openflow/utilities/wireshark_dissectors/README delete mode 100644 openflow/utilities/wireshark_dissectors/openflow/.gitignore delete mode 100644 openflow/utilities/wireshark_dissectors/openflow/Makefile delete mode 100644 openflow/utilities/wireshark_dissectors/openflow/Makefile.am delete mode 100644 openflow/utilities/wireshark_dissectors/openflow/Makefile.common delete mode 100755 openflow/utilities/wireshark_dissectors/openflow/build_distribution_tarball.sh delete mode 100644 openflow/utilities/wireshark_dissectors/openflow/moduleinfo.h delete mode 100644 openflow/utilities/wireshark_dissectors/openflow/packet-openflow.c delete mode 100644 openflow/utilities/wireshark_dissectors/openflow/plugin.c delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/airpcap.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/airpcap_loader.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/alert_box.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-pcap-util-int.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-pcap-util.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-wpcap.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_errs.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_info.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_opts.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_stop_conditions.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_sync.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_ui_utils.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_wpcap_packet.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/cfile.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/clopts_common.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/cmdarg_err.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/color.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/color_filters.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/conditions.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h.in delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h.win32 delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/disabled_protos.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/addr_and_mask.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/addr_resolv.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/address.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/adler32.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/afn.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/aftypes.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/arcnet_pids.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/arptypes.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/asm_utils.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/asn1.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/atalk-utils.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/base64.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/bitswap.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/bridged_pids.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/camel-persistentdata.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/charsets.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/chdlctypes.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/circuit.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/codecs.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column-utils.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column_info.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/conversation.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc10.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc16.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc32.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc6.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crcdrm.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_debug.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_int.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_interop.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_rijndael.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_system.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_user.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_ws.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-des.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-md4.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-md5.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-rc4.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-sha1.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/wep-wpadefs.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter-int.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter-macro.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfunctions.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfvm.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/drange.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/gencode.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/glib-util.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/grammar.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/scanner_lex.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/semcheck.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-function.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-range.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-test.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/syntax-tree.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/diam_dict.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/diam_dict_lex.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dissector_filters.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dissectors/packet-tcp.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_grammar.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_parse.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_parse_lex.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_preparse_lex.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/eap.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/emem.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/epan.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/epan_dissect.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/etypes.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ex-opt.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/except.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/exceptions.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/expert.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/filesystem.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/follow.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/frame_data.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/frequency-utils.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ftypes/ftypes-int.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ftypes/ftypes.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/funnel.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/g_ascii_strcasecmp.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/g_ascii_strtoull.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/garrayfix.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/gcp.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/gnuc_format_check.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/golay.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/greproto.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/guid-utils.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/h225-persistentdata.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/iax2_codec_type.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/in_cksum.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/inet_aton.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ip_opts.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipproto.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipv4.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipv6-utils.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/lapd_sapi.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/llcsaps.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/next_tvb.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/nlpid.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/nstime.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/oids.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/osi-utils.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/oui.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/packet.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/packet_info.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/pint.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/plugins.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ppptypes.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/prefs-int.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/prefs.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/privileges.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/proto.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ptvcursor.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/radius_dict_lex.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/range.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/reassemble.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/reedsolomon.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/report_err.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/req_resp_hdrs.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/rtp_pt.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sctpppids.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sigcomp-udvm.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sigcomp_state_hdlr.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/slab.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sminmpec.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sna-utils.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stat_cmd_args.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stats_tree.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stats_tree_priv.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stream.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/strutil.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/t35.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tap-voip.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tap.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tcap-persistentdata.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tfs.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/timestamp.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/to_str.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tvbparse.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tvbuff.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat-int.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat_load_lex.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/unicode-utils.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/value_string.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ws_strsplit.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/wslua/declare_wslua.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/wslua/wslua.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/x264_prt_id.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/xdlc.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/xmlstub.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/file.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/fileset.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/filters.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/g711.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/getopt.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/globals.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/inet_v6defs.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/isprint.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/log.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/main_window.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/menu.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/merge.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/mkstemp.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/packet-range.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/pcapio.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/print.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/progress_dlg.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/proto_hier_stats.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ps.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/register.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ringbuffer.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/simple_dialog.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/stat_menu.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/statusbar.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/strerror.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/strptime.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/summary.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/svnversion.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/sync_pipe.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tap-rtp-common.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tap_dfilter_dlg.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tempfile.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/text2pcap.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/timestats.h delete mode 100755 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tools/make-dissector-reg delete mode 100755 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tools/make-dissector-reg.py delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ui_util.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/util.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/version_info.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/5views.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/airopeek9.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-grammar.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-int.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-scanner_lex.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/atm.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ber.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/btsnoop.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/buffer.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/catapult_dct2000.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/commview.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/cosine.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/csids.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/dbs-etherwatch.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/erf.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/etherpeek.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/eyesdn.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/file_util.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/file_wrappers.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/hcidump.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/i4b_trace.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/i4btrace.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/iptrace.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/iseries.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/k12.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/k12text_lex.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/lanalyzer.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/libpcap.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/mpeg-audio.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/mpeg.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netmon.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netscreen.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/nettl.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/network_instruments.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netxray.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ngsniffer.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/pcapng.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/pppdump.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/radcom.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/snoop.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/toshiba.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/visual.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/vms.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/wtap-int.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/wtap.h diff --git a/openflow/.gitignore b/openflow/.gitignore deleted file mode 100644 index be6113cd..00000000 --- a/openflow/.gitignore +++ /dev/null @@ -1,44 +0,0 @@ -#*# -*.a -*.d -*.ko -*.la -*.lo -*.loT -*.mod.c -*.o -*.o -*.pyc -*.so -*~ -.#* -.*.cmd -.deps -.libs -.tmp_versions -/Makefile -/Makefile.in -/aclocal.m4 -/autom4te.cache -/build-arch-stamp -/build-aux -/build-indep-stamp -/compile -/config.guess -/config.h -/config.h.in -/config.log -/config.status -/config.sub -/configure -/configure-stamp -/depcomp -/install-sh -/missing -/stamp-h1 -Module.symvers -TAGS -cscope.* -ext.m4 -ext.mk -tags diff --git a/openflow/COPYING b/openflow/COPYING deleted file mode 100644 index ab5f3705..00000000 --- a/openflow/COPYING +++ /dev/null @@ -1,1054 +0,0 @@ -Source file copyrights are indicated at the top of each file. - -Files not in the datapath/ and vswitchd/ directories or associated -subdirectories are covered under the OpenFlow license included below: - -We are making the OpenFlow specification and associated documentation -(Software) available for public use and benefit with the expectation -that others will use, modify and enhance the Software and contribute -those enhancements back to the community. However, since we would like -to make the Software available for broadest use, with as few -restrictions as possible permission is hereby granted, free of charge, -to any person obtaining a copy of this Software to deal in the Software -under the copyrights without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -The name and trademarks of copyright holder(s) may NOT be used in -advertising or publicity pertaining to the Software or any derivatives -without specific, written prior permission. - -Files in the datapath/ and its sub-directories are covered under the GNU -General Public License Version 2. Included below: - - - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. - -Files in vswitchd/ and its sub-directories are covered under the GNU -General Public License Version 3. Included below: - - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/openflow/ChangeLog b/openflow/ChangeLog deleted file mode 100644 index c2d4b49a..00000000 --- a/openflow/ChangeLog +++ /dev/null @@ -1,202 +0,0 @@ -1.0.0-rev1 - XX XXX 2010 ------------------------- - - Changes to regression suite: - - Added testing support for Open vSwitch - - Updated HP-ProCurve scripts - - Minor fixes applied to libraries - - Fixes applied to the following tests: - test_switch_config, test_forward_broadcast_exact_port, - test_set_n_match_nw_tos, test_set_nw_dst, - test_failover_startup - - Added test to verify flipping of src/dst MAC and IP - - Ability to disable slicing, VLAN, and barrier in tests - - Can easily run a single test - For more information, see regress/README - -1.0.0 - 31 Dec 2009 -------------------- - - Fixed Wireshark plugin warnings - - Clarified purpose of actions field in ofp_switch_features in spec - - Known issues: - - isolation provided by the slicing mechanism has been - observed to degrade when run on systems with low performance CPUs. - Investigations are underway to improve isolation on such systems. - -1.0.0-RC1 - 19 Dec 2009 ------------------------ - - Changed wire protocol version to 0x01 - - Added slicing support - - Improved resolution of flow duration in stats/expiry - - Added flow cookies to flows - - Enable matching on IP fields inside ARP packets - - Enable port stats to be retrieved for individual ports - - Added ability to match on IP ToS bits - - Added datapath description to desc stats - - Added ability to control slicing queues from dpctl - - Set datapath description from dpctl - - Removed kernel datapath from reference switch - (will be release separately) - - Fix bug related to identifying overlapping flows - - Updated Wireshark dissector to support 1.0.0 features - - Added regression tests for ARP handling, flow cookies, slicing, - selective port stats, flow duration precision, matching on ToS bits, and - the datapath description - - Known issues: - - isolation provided by the slicing mechanism has been - observed to degrade when run on systems with low performance CPUs. - Investigations are underway to improve isolation on such systems. - -0.9.0-rev1 - 04 Sep 2009 ------------------------- - - Added NetFPGA hardware table support (wire protocol 0x98) - - Fixed a few userspace datapath bugs - -0.9.0 - 20 Jul 2009 -------------------- - - Changed wire protocol version to 0x98 - - Removed monolithic switch process called switch - - Added userspace data plane process named ofdatapath - - Changed userspace control plane process name to ofprotocol - - Changed kernelspace data plane extension name to ofdatapath.ko - - Changed NetFPGA kernelspace extestion name to ofdatapath_netfpga.ko - - Removed Linux 2.4 kerel support - - Added simple controller failover feature - - Added emergency flow cache feature - - Added barrier command - - Added 802.1Q VLAN priority bits match feature - - Clarified flow expiration, renamed flow expiration to flow removed - - Added protocol statistics collector - - Added IP ToS/DSCP rewrite feature - - Changed port enumeration at 1 instead of 0 - - Clarified emergeency flow cache behavior - - Clarified definition of datapath ID - - Clarified meaning of a zero-size miss_send_len - - Clarified meaning of a zero-size max_len in output action - - Changed protocol structure alignment to ensure 64-bit - -v0.8.9 r2 - 23 Jan 2009 ------------------------ - - Added NetFPGA hardware table support (wire protocol 0x97) - - Added regression tests on port_stats, flow_stats, drop, ICMP handling - - Bug fixes - -v0.8.9~1 - 01 Dec 2008 ----------------------- - - Added support for IP netmasks - - Added new physical port stats - - Added IN_PORT virtual port - - Added echo request/response - - Added detection of link and port status changes - - Added ability to configure port status from controller - - Added support for vendor extensions - - Added support for variable length actions - - Added support for matching ICMP type and code - - Added support for listing and deleting flows based on output port action - - Added support for modifying VLAN priority tag - - Increased max supported ports to 65280 - - More explicit handling for IP fragments - - Added support for 802.1D spanning tree - - Added OFPFC_MODIFY command to Flow Mod message - - Provided more flexible description of tables to controller - - Make port modification more explicit - - Made Packet Out message more consistent - - Added hard timeout value to Flow Mod message - - Added reason field for Flow Expired message - - Reworked initial handshake to support backwards compatibility - - Added OFPST_DESC stat for returning description of hw/sw - - Added support for loadable hardware table support modules** - - In-band control now supported** - - 802.1D spanning tree support** - - Automatic controller discovery (via DHCP) now supported** - - Improved support for older 2.6.x kernels** - - Switch can now "fail open" as a MAC-learning switch if the controller cannot be contacted** - - Debian packages may now be built** - - Fixed bugs in SSL support - - Most programs now take --detach and --pidfile options to run as daemon - - Numerous bug fixes - - ** Only supported in the kernel module for the time-being. - -v0.8.1 - 14 May 2008 --------------------- - - No longer set nwsrc/nwdst fields in flow structs on ARP packets - - Various bug fixes and tweaks - -v0.8.0 - 04 May 2008 --------------------- - - Added support for flow entry priorities - - Added support for all stats messages - - Added support for OFPP_TABLE virtual port - - Removed MAC tables - - Various bug fixes and tweaks - -v0.2.1 - 28 Mar 2008 --------------------- - - Fixed build problem when SSL enabled - -v0.2.0 - 28 Mar 2008 --------------------- - - Added userspace switch reference implementation - -v0.1.9 - 19 Mar 2008 --------------------- - - Added SSL/TLS support - - Various bug fixes and tweaks - -v0.1.8 - 03 Mar 2008 --------------------- - - Added support for cross-compilation - - Various bug fixes and tweaks - -v0.1.7 - 07 Feb 2008 --------------------- - - Allow permanent flow entries to be set - - Added patch for tcpdump that allows parsing of OpenFlow messages - - Various bug fixes and tweaks - -v0.1.6 - 05 Feb 2008 --------------------- - - Added support for Linux 2.6.24 - - Set nwsrc/nwdst fields in flow structs on ARP packets - - Various bug fixes and tweaks - -v0.1.5 - 17 Jan 2008 --------------------- - - Added support for Linux 2.4.20 - - Added support for GCC 2.95 - -v0.1.4 - 15 Jan 2008 --------------------- - - Decode and print port_status messages - - Fixed build problems on big-endian systems - - Fixed compatibility for older 2.6 kernels - - Various bug fixes and tweaks - -v0.1.3 - 08 Jan 2008 --------------------- - - Added support for flow expiration messages - - Decode and print all datapath-generated messages in dpctl's "monitor" - - Added "--noflow" option to controller - - Various bug fixes and tweaks - -v0.1.2 - 07 Jan 2008 --------------------- - - Fixed distribution to include ofp_pcap.h - - Removed autoconf C++ checks - -v0.1.1 - 18 Dec 2007 --------------------- - - Fixed support for Linux 2.4.35 and 2.6.22 - - Added support for Linux 2.6.15 - - Added "vlogconf" utility to modify logging configuration - - Added better support for SNAP headers - - Improved printing of flow information in dpctl - - Made kernel code consistently use tabs instead of spaces - - Removed libpcap requirement for building - - Various bug fixes and tweaks - -v0.1.0 - 30 Nov 2007 --------------------- - - Initial release diff --git a/openflow/INSTALL b/openflow/INSTALL deleted file mode 100644 index f236e16a..00000000 --- a/openflow/INSTALL +++ /dev/null @@ -1,513 +0,0 @@ - Installation Instructions for OpenFlow Reference Release - -This document describes how to build, install, and execute the -reference implementation of OpenFlow. Please send any comments to: - - - -Contents -======== - -The OpenFlow reference implementation includes one OpenFlow switch -implementations: - - - The "userspace datapath-based switch": This divides the switch - into a userspace "datapath" (built as udatapath/ofdatapath) - and a userspace program that implements the secure channel - component (ofprotocol). The userspace datapath-based switch - does not require building a kernel module, but it is not as - fast as a kernel-based switch. - -The reference implementation also contains a simple OpenFlow -controller (built as controller/controller) and a number of related -utilities. - -Build Methods -============= - -There are two principal ways to build and install this distribution: - - - Using "configure" and "make" in the ordinary way. See - Building Conventionally below for detailed instructions. - - - As a set of Debian packages. Refer to Building Debian - Packages, below, for instructions. - -Base Prerequisites ------------------- - -Regardless of how it is built, OpenFlow has a common set of -prerequisites. To compile the userspace programs in the OpenFlow -reference distribution, you will need the following software: - - - A make program, e.g. GNU make - (http://www.gnu.org/software/make/). BSD make should also work. - - - The GNU C compiler (http://gcc.gnu.org/). We generally test - with version 4.1 or 4.2. - - - libssl, from OpenSSL (http://www.openssl.org/), is optional but - recommended. libssl is required to establish confidentiality - and authenticity in the connections among OpenFlow switches and - controllers. To enable, configure with --enable-ssl=yes. - -If you are working from a Git tree or snapshot (instead of from a -distribution tarball), or if you modify the OpenFlow build system, you -will also need the following software: - - - Autoconf version 2.60 or later (http://www.gnu.org/software/autoconf). - - - Automake version 1.10 or later (http://www.gnu.org/software/automake). - - - pkg-config (http://pkg-config.freedesktop.org/wiki/). We test - with version 0.22. - -Debian Prerequisites --------------------- - -To build Debian packages from the OpenFlow distribution, you will need -to install a number of Debian packages in addition to the base -prerequisites listed above. These additional prerequisites may be -found listed as "Build-Depends" in debian/control in the source tree. -To check that they are installed, first install the dpkg-dev package, -then run dpkg-checkbuilddeps from the top level of the OpenFlow source -tree. - -To build Debian packages without being root, also install the -"fakeroot" package. - -Userspace Switch Prerequisites ---------------------------------- - - - To enable slicing support, "tc" frontend should be installed - (from iproute2, part of all major distributions, - http://www.linux-foundation.org/en/Net:Iproute2). - You also need to enable the following kernel configuration - options under the QoS and/or Fair queueing section : - CONFIG_NET_SCHED,CONFIG_NET_SCH_HTB (already configured that - way in most distributions). - (NOTE: You can disable slicing (and these dependencies) at runtime - using the --no-slicing option) - -Building Conventionally -======================= - -This section explains how to build and install the OpenFlow -distribution in the ordinary way using "configure" and "make". - -0. Check that you have installed all the prerequisites listed above in - the Base Prerequisites section. Run `boot.sh` if necessary to create - the configure script. - - % ./boot.sh - -1. In the top source directory, configure the package by running the - configure script. You can usually invoke configure without any - arguments: - - % ./configure - - To use a specific C compiler for compiling OpenFlow user programs, - also specify it on the configure command line, like so: - - % ./configure CC=gcc-4.2 - - If you have hardware that supports accelerated OpenFlow switching - and you have obtained a hardware table library for your hardware - and extracted it into the OpenFlow reference distribution source - tree, then you may also enable building support for the hardware - switch table with --enable-hw-lib. For more information, read - README.hwtables at the root of the OpenFlow distribution tree. - - The configure script accepts a number of other options and honors - additional environment variables. For a full list, invoke - configure with the --help option. - -2. Run make in the top source directory: - - % make - - The following binaries will be built: - - - Userspace datapath: udatapath/ofdatapath. - - - Secure channel executable: secchan/ofprotocol. - - - Controller executable: controller/controller. - - - Datapath administration utility: utilities/dpctl. - - - Runtime logging configuration utility: utilities/vlogconf. - - - Miscellaneous utilities: utilities/ofp-discover, - utilities/ofp-kill. - - - Tests: various binaries in tests/. - - If your distribution includes the OpenFlow extensions, the - following additional binaries will be built: - - - ANSI terminal support for EZIO 16x2 LCD panel: - ext/ezio/ezio-term. - - - Switch monitoring UI for small text displays: - ext/ezio/ofp-switchui. - -3. Run "make install" to install the executables and manpages into the - running system, by default under /usr/local. - -4. Test the userspace programs, as described under Testing Userspace - Programs below. - -Building Debian Packages -======================== - -Follow these instructions to build Debian packages for OpenFlow. - -0. Check that you have installed all the prerequisites listed above in - the Base Prerequisites and Debian Prerequisites sections above. - -1. In the top source directory, run the following command, as root: - - % dpkg-buildpackage - - Alternatively, if you installed the "fakeroot" package, you may run - dpkg-buildpackage as an ordinary user with the following syntax: - - % dpkg-buildpackage -rfakeroot - - The following packages will be built in the directory above the - source tree: - - - openflow-controller: The OpenFlow controller. Depends on - openflow-pki (see below). - - - openflow-switch: Install this package on a machine that acts - as an OpenFlow kernel switch. - - - openflow-datapath-source: Source code for OpenFlow's Linux - kernel module. - - - openflow-pki: Public-key infrastructure for OpenFlow. Install - this package on a machine that acts as an OpenFlow PKI server - (see "Establishing a Public Key Infrastructure" below). - - - openflow-common: Files and utilities required by more than one - of the above packages. - -2. To set up an OpenFlow controller, install the openflow-controller - package and its dependencies. You may configure it by editing - /etc/default/openflow-controller, e.g. to enable non-SSL - connections, which are disabled by default. If you change the - default settings, you will need to restart the controller by - running: - - % /etc/init.d/openflow-controller restart - -3. To set up an OpenFlow switch, install the openflow-switch package - and its dependencies. If it is to be a kernel-based switch, also - install openflow-datapath-source, then follow the instructions in - /usr/share/doc/openflow-datapath-source/README.Debian to build and - install the kernel module. - - You may configure the switch one of the following ways: - - - Completely by hand, as described under the Testing section - below. - - For the userspace datapath-based switch, this is the only - supported form of configuration. - - - By editing /etc/default/openflow-switch. You must at least - configure some network devices, by uncommenting NETDEVS and - adding the appropriate devices to the list, e.g. NETDEVS="eth0 - eth1". - - After you edit this file, you will need to start the switch by - running: - - % /etc/init.d/openflow-switch restart - - This form of configuration is not supported for the userspace - datapath-based switch. - - - By running the ofp-switch-setup program. This interactive - program will walk you through all the steps of configuring an - OpenFlow switch, including configuration of SSL certificates. - Run it without arguments, as root: - - % ofp-switch-setup - - This form of configuration is not supported for the userspace - datapath-based switch. - -Testing -======= - -The following sets of instructions show how to use the OpenFlow -reference implementation as a switch on a single machine. This can be -used to verify that the distribution built properly. For full -installation instructions, refer to the Installation section below. - -Userspace Datapath ------------------- - -These instructions use the OpenFlow userspace datapath ("ofdatapath"). - -1. Start the OpenFlow controller running in the background, by running - the "controller" program with a command like the following: - - # controller punix:/var/run/controller.sock & - - This command causes the controller to bind to the specified Unix - domain socket, awaiting connections from OpenFlow switches. See - controller(8) for details. - - The "controller" program does not require any special privilege, so - you do not need to run it as root. - -2. The commands below must run as root, so log in as root, or use a - program such as "su" to become root temporarily. - -3. Create a datapath instance running in the background. The command - below creates a datapath that listens for connections from ofprotocol - on a Unix domain socket located in /var/run and services physical - ports eth1 and eth2: - - # ofdatapath punix:/var/run/dp0.sock -i eth1,eth2 & - -4. Run ofprotocol to start the secure channel connecting the datapath and - the controller: - - # ofprotocol unix:/var/run/controller.sock unix:/var/run/dp0.sock & - -5. Devices plugged into the network ports specified in step 2 should - now be able to send packets to each other, as if they were plugged - into ports on a conventional Ethernet switch. - -Installation -============ - -This section explains how to install OpenFlow in a network with one -controller and one or more switches, each of which runs on a separate -machine. Before you begin, you must decide on one of two ways for -each switch to reach the controller over the network: - - - Use a "control network" that is completely separate from the - "data network" to be controlled ("out-of-band control"). The - location of the controller must be configured manually in this - case. - - - Use the same network for control and for data ("in-band - control"). When in-band control is used, the location of the - controller may be configured manually or discovered - automatically. We will assume manual configuration here; - please refer to ofprotocol(8) for instructions on setting up - controller discovery. - -Controller Setup ----------------- - -On the machine that is to be the OpenFlow controller, start the -"controller" program listening for connections from switches on TCP -port 6633 (the default), as shown below. - - # controller -v ptcp: - -(See controller(8) for more details) - -Make sure the machine hosting the controller is reachable by the -switch. - -Userspace Datapath-Based Setup ------------------------------- - -On a machine that is to host an OpenFlow userspace datapath-based -switch, follow the procedure below. - -0. The commands below must run as root, so log in as root, or use a - program such as "su" to become root temporarily. - -1. Create a datapath instance running in the background. The command - below creates a datapath that listens for connections from ofprotocol - on a Unix domain socket located in /var/run, services physical - ports eth1 and eth2, and creates a TAP network device named "tap0" - for use in in-band control: - - # ofdatapath punix:/var/run/dp0.sock -i eth1,eth2 --local-port=tap:tap0 & - - (See ofdatapath(8) for details.) - - If the switch will connect to the controller out-of-band, then the - --local-port option may be omitted, or --no-local-port may be - substituted. - -3. Arrange so that the switch can reach the controller over the - network. - - - If you are using out-of-band control, at this point make sure - that the switch machine can reach the controller over the - network. - - - If you are using in-band control with manual configuration, at - this point the TAP network device created in step 1 is not - bridged to any physical network, so the next step depends on - whether connectivity is required to configure the device's IP - address: - - * If the switch has a static IP address, you may configure - its IP address now, e.g.: - - # ifconfig tap0 192.168.1.1 - - * If the switch does not have a static IP address, e.g. its - IP address is obtained dynamically via DHCP, then proceed - to step 4. The DHCP client will not be able to contact - the DHCP server until the secure channel has started up. - - - If you are using in-band control with controller discovery, no - configuration is required at this point. You may proceed to - step 4. - -4. Run ofprotocol to start the secure channel connecting the datapath to - a remote controller. If the controller is running on host - 192.168.1.2 port 6633 (the default port), the ofprotocol invocation - would look like this: - - # ofprotocol unix:/var/run/dp0.sock tcp:192.168.1.2 - - - If you are using in-band control with controller discovery, omit - the second argument to the ofprotocol command. - - - If you are using out-of-band control, add --out-of-band to the - command line. - -5. If you are using in-band control with manual configuration, and the - switch obtains its IP address dynamically, then you may now obtain - the switch's IP address, e.g. by invoking a DHCP client. The - secure channel will only be able to connect to the controller after - an IP address has been obtained. - -6. The secure channel should connect to the controller within a few - seconds. It may take a little longer if controller discovery is in - use, because the switch must then also obtain its own IP address - and the controller's location via DHCP. - -Configuration -============= - -Secure operation over SSL -------------------------- - -The instructions above set up OpenFlow for operation over a plaintext -TCP connection. Production use of OpenFlow should use SSL[*] to -ensure confidentiality and authenticity of traffic among switches and -controllers. The source must be configured with --enable-ssl=yes to -build with SSL support. - -To use SSL with OpenFlow, you must set up a public-key infrastructure -(PKI) including a pair of certificate authorities (CAs), one for -controllers and one for switches. If you have an established PKI, -OpenFlow can use it directly. Otherwise, refer to "Establishing a -Public Key Infrastructure" below. - -To configure the controller to listen for SSL connections on port 6633 -(the default), invoke it as follows: - - # controller -v pssl: --private-key=PRIVKEY --certificate=CERT \ - --ca-cert=CACERT - -where PRIVKEY is a file containing the controller's private key, CERT -is a file containing the controller CA's certificate for the -controller's public key, and CACERT is a file containing the root -certificate for the switch CA. If, for example, your PKI was created -with the instructions below, then the invocation would look like: - - # controller -v pssl: --private-key=ctl-privkey.pem \ - --certificate=ctl-cert.pem --ca-cert=pki/switchca/cacert.pem - -To configure a switch to connect to a controller running on port 6633 -(the default) on host 192.168.1.2 over SSL, invoke ofprotocol as follows: - - # ofprotocol -v DATAPATH ssl:192.168.1.2 --private-key=PRIVKEY \ - --certificate=CERT --ca-cert=CACERT - -where DATAPATH is the datapath to connect to (e.g. nl:0 or -unix:/var/run/dp0.sock), PRIVKEY is a file containing the switch's -private key, CERT is a file containing the switch CA's certificate for -the switch's public key, and CACERT is a file containing the root -certificate for the controller CA. If, for example, your PKI was -created with the instructions below, then the invocation would look -like: - - # ofprotocol -v DATAPATH ssl:192.168.1.2 --private-key=sc-privkey.pem \ - --certificate=sc-cert.pem --ca-cert=pki/controllerca/cacert.pem - -[*] To be specific, OpenFlow uses TLS version 1.0 or later (TLSv1), as - specified by RFC 2246, which is very similar to SSL version 3.0. - TLSv1 was released in January 1999, so all current software and - hardware should implement it. - -Establishing a Public Key Infrastructure ----------------------------------------- - -If you do not have a PKI, the ofp-pki script included with OpenFlow -can help. To create an initial PKI structure, invoke it as: - % ofp-pki init -which will create and populate a new PKI directory. The default -location for the PKI directory depends on how the OpenFlow tree was -configured (to see the configured default, look for the --dir option -description in the output of "ofp-pki --help"). - -The pki directory contains two important subdirectories. The -controllerca subdirectory contains controller certificate authority -related files, including the following: - - - cacert.pem: Root certificate for the controller certificate - authority. This file must be provided to ofprotocol with the - --ca-cert option to enable it to authenticate valid controllers. - - - private/cakey.pem: Private signing key for the controller - certificate authority. This file must be kept secret. There is - no need for switches or controllers to have a copy of it. - -The switchca subdirectory contains switch certificate authority -related files, analogous to those in the controllerca subdirectory: - - - cacert.pem: Root certificate for the switch certificate - authority. This file must be provided to the controller program - with the --ca-cert option to enable it to authenticate valid - switches. - - - private/cakey.pem: Private signing key for the switch - certificate authority. This file must be kept secret. There is - no need for switches or controllers to have a copy of it. - -After you create the initial structure, you can create keys and -certificates for switches and controllers with ofp-pki. To create a -controller private key and certificate in files named ctl-privkey.pem -and ctl-cert.pem, for example, you could run: - % ofp-pki req+sign ctl controller -ctl-privkey.pem and ctl-cert.pem would need to be copied to the -controller for its use at runtime (they could then be deleted from -their original locations). The --private-key and --certificate -options of controller, respectively, would point to these files. - -Analogously, to create a switch private key and certificate in files -named sc-privkey.pem and sc-cert.pem, for example, you could run: - % ofp-pki req+sign sc switch -sc-privkey.pem and sc-cert.pem would need to be copied to the switch -for its use at runtime (they could then be deleted from their original -locations). The --private-key and --certificate options, -respectively, of ofprotocol would point to these files. - -Bug Reporting -------------- - -Please report problems to: - -openflow-discuss@openflowswitch.org - -or post them to our online bug tracking system at: - -http://www.openflowswitch.org/bugs/openflow diff --git a/openflow/Makefile.am b/openflow/Makefile.am deleted file mode 100644 index 97ac1f01..00000000 --- a/openflow/Makefile.am +++ /dev/null @@ -1,68 +0,0 @@ -# The goal of -Wno-syntax here is just to suppress the Automake warning -# about overriding distdir, below. -AUTOMAKE_OPTIONS = foreign -Wno-syntax subdir-objects -ACLOCAL_AMFLAGS = -I m4 -#SUBDIRS = datapath -SUBDIRS = - -if HAVE_DPKG_BUILDPACKAGE -distcheck-hook: - cd $(srcdir) && dpkg-buildpackage -rfakeroot -us -uc - cd $(srcdir) && fakeroot ./debian/rules clean -else -distcheck-hook: -endif - -AM_CPPFLAGS = $(SSL_CFLAGS) -g -AM_CPPFLAGS += -I $(top_srcdir)/include -AM_CPPFLAGS += -I $(top_srcdir)/lib - -AM_CFLAGS = -Wstrict-prototypes - -if NDEBUG -AM_CPPFLAGS += -DNDEBUG -AM_CFLAGS += -fomit-frame-pointer -else -AM_LDFLAGS = -export-dynamic -endif - -CLEANFILES = -DISTCLEANFILES = -EXTRA_DIST = -TESTS = -TESTS_ENVIRONMENT = -bin_PROGRAMS = -bin_SCRIPTS = -dist_commands_DATA = -dist_man_MANS = -dist_pkgdata_SCRIPTS = -dist_sbin_SCRIPTS = -man_MANS = -noinst_HEADERS = -noinst_LIBRARIES = -noinst_PROGRAMS = -noinst_SCRIPTS = - -EXTRA_DIST += README.hwtables soexpand.pl regress - -ro_c = echo '/* -*- mode: c; buffer-read-only: t -*- */' - -SUFFIXES = .in -.in: - $(PERL) $(srcdir)/soexpand.pl -I$(srcdir) < $< | \ - sed -e 's,[@]LOGDIR[@],$(LOGDIR),g' \ - -e 's,[@]PKIDIR[@],$(PKIDIR),g' \ - -e 's,[@]RUNDIR[@],$(RUNDIR),g' \ - -e 's,[@]pkgdatadir[@],$(pkgdatadir),g' \ - -e 's,[@]PERL[@],$(PERL),g' > $@ - -include lib/automake.mk -include secchan/automake.mk -include controller/automake.mk -include utilities/automake.mk -include udatapath/automake.mk -include tests/automake.mk -include include/automake.mk -include third-party/automake.mk -include debian/automake.mk -include hw-lib/automake.mk diff --git a/openflow/README b/openflow/README deleted file mode 100644 index a9cca172..00000000 --- a/openflow/README +++ /dev/null @@ -1,110 +0,0 @@ - OpenFlow Reference Release - -What is OpenFlow? ------------------ - -OpenFlow is a flow-based switch specification designed to enable -researchers to run experiments in live networks. OpenFlow is based on a -simple Ethernet flow switch that exposes a standardized interface for -adding and removing flow entries. - -An OpenFlow switch consists of three parts: (1) A "flow table" in -which each flow entry is associated with an action telling the switch -how to process the flow, (2) a "secure channel" connecting the switch -to a remote process (a controller), allowing commands and packets to -be sent between the controller and the switch, and (3) an OpenFlow -protocol implementation, providing an open and standard way for a -controller to talk to the switch. - -An OpenFlow switch can thus serve as a simple datapath element that -forwards packets between ports according to flow actions defined by -the controller using OpenFlow commands. Example actions are: - - - Forward this flow's packets to the given port(s) - - Drop this flow's packets - - Encapsulate and forward this flow's packets to the controller. - -The OpenFlow switch is defined in detail in the OpenFlow switch -Specification [2]. - -What's here? ------------- - -This distribution includes one reference implementations of an -OpenFlow switch. This implementation has the following components: - - - ofdatapath, which implements the flow table in user space. - - - ofprotocol, a program that implements the secure channel - component of the reference switch. - - - dpctl, a tool for configuring the switch. - -This distribution includes some additional software as well: - - - controller, a simple program that connects to any number of - OpenFlow switches, commanding them to act as regular MAC - learning switches. - - - vlogconf, a utility that can adjust the logging levels of a - running ofprotocol or controller. - - - ofp-pki, a utility for creating and managing the public-key - infrastructure for OpenFlow switches. - - - A patch to tcpdump that enables it to parse OpenFlow - messages. - - - A regression suite that tests OpenFlow functionality, please - see regress/README. - - - A Wireshark dissector that can decode the OpenFlow wire - protocol. Please see utilities/wireshark_dissectors/README. - -For installation instructions, read INSTALL. Each userspace program -is also accompanied by a manpage. - -What's NOT here? ----------------- - -The reference implementation no longer includes the Linux kernel module -or the NetFPGA implementation. The OpenFlow consortium intends to -release these separately from the reference design. - -Platform support ----------------- - -Other than the userspace switch implementation, the software in the -OpenFlow distribution should compile under Unix-like environments such -as Linux, FreeBSD, Mac OS X, and Solaris. Our primary test environment -is Debian GNU/Linux. Please contact us with portability-related bug -reports or patches. - -The userspace datapath implementation should be easy to port to -Unix-like systems. The interface to network devices, in netdev.c, is -the code most likely to need changes. So far, only Linux is -supported. We welcome ports to other platforms. - -GCC is the expected compiler. - -Bugs/Shortcomings ------------------ - -- The flow table does not support the "normal processing" action. - -References ----------- - - [1] OpenFlow: Enabling Innovation in College Networks. Whitepaper. - - - [2] OpenFlow Switch Specification. - - -Contact -------- - -Public discussion list: openflow-discuss@openflowswitch.org -Direct e-mail: info@openflowswitch.org - -Web: http://openflowswitch.org/ diff --git a/openflow/README.hwtables b/openflow/README.hwtables deleted file mode 100644 index 6d982507..00000000 --- a/openflow/README.hwtables +++ /dev/null @@ -1,39 +0,0 @@ -Hardware Table Support -*- text -*- ----------------------- - -The OpenFlow reference implementation in this distribution provides a -mechanism to support hardware that can accelerate OpenFlow switching. -The mechanism consists of the ability to add a "hardware acceleration" -switching table ahead of the software switching tables implemented by -the reference implementation. The hardware switching table is -expected to handle any incoming packets that it can on its own. Any -packets that it cannot handle itself it may pass up to the software -table implementations. - -Hardware table implementation are provided as a library and built -in the userspace datapath executable. - -Creating a hardware table module is straightforward. Create a -directory in the openflow source tree named hw-lib/NAME, -where NAME identifies the hardware that the module supports. Populate -that directory with the C source files that comprise the module, plus -a file named automake.mk that specifies how to build the module in -the hw-lib directory. This distribution includes a "skeleton" hardware -library that demonstrates how this works. - -When you perform 'configure', specify each NAME that identifies a -library to be included on the OpenFlow configure script command as -the argument to --enable-hw-lib, e.g.: - ./configure --enable-hw-lib=NAME - -Each hardware table library's code is encapsulated in a directory, so -it is easy to separate a hardware table implementation from OpenFlow. -Simply package up the contents of the hw-lib/NAME directory and -distribute it for builders to extract into their distribution -directory. - -Included in this distribution is a dummy hardware table to aid in beginning -your own hardware table port, it is located in the hw-lib/skeleton -folder. Also included is a fully functional NetFPGA hardware table that can run -as a 1Gbx4 port line-rate OpenFlow switch. Information and instructions for its -use can be found in the hw-lib/nf2/README file. diff --git a/openflow/README.kernel b/openflow/README.kernel deleted file mode 100644 index 95ce7564..00000000 --- a/openflow/README.kernel +++ /dev/null @@ -1,18 +0,0 @@ -Kernel-mode Support -*- text -*- -------------------- - -The OpenFlow reference implementation no longer includes a kernel module -that implements the datapath. A separate release with kernel-mode support -is expected in 1H2010. - -The release you downloaded *may* include the kernel module source files -depending upon the method used to obtain the release. If you downloaded the -release as a compressed tar file (.tar.gz) then you will *not* have the -source for the kernel module. If you downloaded the release directly from -git then you will have the source. - -Please note that if you obtained the release via git that the kernel module -source is not built by default and does not implement all features. - -Please check the OpenFlow website or subscribe to the openflow-announce -mailing list for updates on the kernel-mode implementation. diff --git a/openflow/acinclude.m4 b/openflow/acinclude.m4 deleted file mode 100644 index 7ccfbaa4..00000000 --- a/openflow/acinclude.m4 +++ /dev/null @@ -1,309 +0,0 @@ -# -*- autoconf -*- - -# Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford -# Junior University -# -# We are making the OpenFlow specification and associated documentation -# (Software) available for public use and benefit with the expectation -# that others will use, modify and enhance the Software and contribute -# those enhancements back to the community. However, since we would -# like to make the Software available for broadest use, with as few -# restrictions as possible permission is hereby granted, free of -# charge, to any person obtaining a copy of this Software to deal in -# the Software under the copyrights without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# -# The name and trademarks of copyright holder(s) may NOT be used in -# advertising or publicity pertaining to the Software or any -# derivatives without specific, written prior permission. - -dnl OFP_CHECK_LINUX(OPTION, VERSION, VARIABLE, CONDITIONAL) -dnl -dnl Configure linux kernel source tree -AC_DEFUN([OFP_CHECK_LINUX], [ - AC_ARG_WITH([$1], - [AC_HELP_STRING([--with-$1=/path/to/linux-$2], - [Specify the linux $2 kernel module build envrionment and sources])], - [path="$withval"], [path=])dnl - if test -n "$path"; then - path=`eval echo "$path"` - - AC_MSG_CHECKING([for $path directory]) - if test -d "$path" && test -d "$path/build" ; then - AC_MSG_RESULT([yes]) - if test -d "$path/source" ; then - $3=$path/build - $4=$path/source - else - $3=$path/build - $4=$path/build - fi - AC_SUBST($3) - AC_SUBST($4) - else - AC_MSG_RESULT([no]) - AC_ERROR([source dir $path doesn't exist]) - fi - - AC_MSG_CHECKING([for $path kernel version]) - patchlevel=`sed -n 's/^PATCHLEVEL = //p' "$KBLD26/Makefile"` - sublevel=`sed -n 's/^SUBLEVEL = //p' "$KBLD26/Makefile"` - AC_MSG_RESULT([2.$patchlevel.$sublevel]) - if test "2.$patchlevel" != '$2'; then - AC_ERROR([Linux kernel source in $path is not version $2]) - fi - if ! test -e $KBLD26/include/linux/version.h || \ - ! test -e $KBLD26/include/linux/autoconf.h; then - AC_MSG_ERROR([Linux kernel source in $path is not configured]) - fi - m4_if($2, [2.6], [OFP_CHECK_LINUX26_COMPAT]) - fi - AM_CONDITIONAL($5, test -n "$path") -]) - -dnl OFP_GREP_IFELSE(FILE, REGEX, IF-MATCH, IF-NO-MATCH) -dnl -dnl Greps FILE for REGEX. If it matches, runs IF-MATCH, otherwise IF-NO-MATCH. -AC_DEFUN([OFP_GREP_IFELSE], [ - AC_MSG_CHECKING([whether $2 matches in $1]) - grep '$2' $1 >/dev/null 2>&1 - status=$? - case $status in - 0) - AC_MSG_RESULT([yes]) - $3 - ;; - 1) - AC_MSG_RESULT([no]) - $4 - ;; - *) - AC_MSG_ERROR([grep exited with status $status]) - ;; - esac -]) - -dnl OFP_DEFINE(NAME) -dnl -dnl Defines NAME to 1 in kcompat.h. -AC_DEFUN([OFP_DEFINE], [ - echo '#define $1 1' >> datapath/linux-2.6/kcompat.h.new -]) - -AC_DEFUN([OFP_CHECK_VETH], [ - AC_MSG_CHECKING([whether to build veth module]) - if test "$sublevel" = 18; then - AC_MSG_RESULT([yes]) - AC_SUBST([BUILD_VETH], 1) - else - AC_MSG_RESULT([no]) - fi -]) - -dnl OFP_CHECK_LINUX26_COMPAT -dnl -dnl Runs various Autoconf checks on the Linux 2.6 kernel source in -dnl the directory in $KSRC26. -AC_DEFUN([OFP_CHECK_LINUX26_COMPAT], [ - rm -f datapath/linux-2.6/kcompat.h.new - mkdir -p datapath/linux-2.6 - : > datapath/linux-2.6/kcompat.h.new - OFP_GREP_IFELSE([$KSRC26/include/linux/skbuff.h], [skb_transport_header], - [OFP_DEFINE([HAVE_SKBUFF_HEADER_HELPERS])]) - OFP_GREP_IFELSE([$KSRC26/include/linux/skbuff.h], [raw], - [OFP_DEFINE([HAVE_MAC_RAW])]) - OFP_GREP_IFELSE([$KSRC26/include/linux/skbuff.h], - [skb_copy_from_linear_data_offset], - [OFP_DEFINE([HAVE_SKB_COPY_FROM_LINEAR_DATA_OFFSET])]) - OFP_GREP_IFELSE([$KSRC26/include/net/netlink.h], [NLA_NUL_STRING], - [OFP_DEFINE([HAVE_NLA_NUL_STRING])]) - OFP_CHECK_VETH - if cmp -s datapath/linux-2.6/kcompat.h.new \ - datapath/linux-2.6/kcompat.h >/dev/null 2>&1; then - rm datapath/linux-2.6/kcompat.h.new - else - mv datapath/linux-2.6/kcompat.h.new datapath/linux-2.6/kcompat.h - fi -]) - -dnl Checks for --enable-hw-tables and substitutes HW_TABLES to any -dnl requested hardware table modules. -AC_DEFUN([OFP_CHECK_HWTABLES], - [AC_ARG_ENABLE( - [hw-tables], - [AC_HELP_STRING([--enable-hw-tables=MODULE...], - [Configure and build the specified externally supplied - hardware table support modules])]) - case "${enable_hw_tables}" in # ( - yes) - AC_MSG_ERROR([--enable-hw-tables has a required argument]) - ;; # ( - ''|no) - hw_tables= - ;; # ( - *) - hw_tables=`echo "$enable_hw_tables" | sed 's/,/ /g'` - ;; - esac - for d in $hw_tables; do - mk=datapath/hwtable_$d/Modules.mk - if test ! -e $srcdir/$mk; then - AC_MSG_ERROR([--enable-hw-tables=$d specified but $mk is missing]) - fi - HW_TABLES="$HW_TABLES \$(top_srcdir)/$mk" - done - AC_SUBST(HW_TABLES)]) - -dnl Checks for --enable-hw-lib and substitutes BUILD_HW_LIBS and plat name -AC_DEFUN([OFP_CHECK_HWLIBS], - [AC_ARG_ENABLE( - [hw-lib], - [AC_HELP_STRING([--enable-hw-lib=PLATFORM], - [Configure and build the specified externally supplied - hardware library: lb4g, t2ref, scorref or nf2])]) - case "${enable_hw_lib}" in # ( - yes) - AC_MSG_ERROR([--enable-hw-lib has a required argument]) - ;; # ( - ''|no) - hw_lib= - NF2=no - LB4G=no - T2REF=no - SCORREF=no - BUILD_HW_LIBS=no - ;; # ( - nf2) - NF2=yes - LB4G=no - T2REF=no - SCORREF=no - hw_lib=$enable_hw_lib - BUILD_HW_LIBS=yes - ;; # ( - lb4g) - NF2=no - LB4G=yes - T2REF=no - SCORREF=no - hw_lib=$enable_hw_lib - BUILD_HW_LIBS=yes - ;; # ( - t2ref) - NF2=no - LB4G=no - T2REF=yes - SCORREF=no - hw_lib=$enable_hw_lib - BUILD_HW_LIBS=yes - ;; # ( - scorref) - NF2=no - LB4G=no - SCORREF=yes - T2REF=no - hw_lib=$enable_hw_lib - BUILD_HW_LIBS=yes - ;; # ( - *) - AC_MSG_ERROR([--enable-hw-lib: Unknown platform: ${enable_hw_lib}]) - BUILD_HW_LIBS=no - ;; - esac - if test $BUILD_HW_LIBS = yes; then - if test -e "$srcdir/hw-lib/automake.mk"; then - : - else - AC_MSG_ERROR([cannot configure HW libraries without "hw-lib" directory]) - fi - AC_DEFINE([BUILD_HW_LIBS], [1], - [Whether the OpenFlow hardware libraries are available]) - fi - if test $NF2 = yes; then - AC_DEFINE([NF2], [1], - [Support NetFPGA platform]) - fi - if test $LB4G = yes; then - AC_DEFINE([LB4G], [1], - [Support Stanford-LB4G platform]) - fi - if test $T2REF = yes; then - AC_DEFINE([T2REF], [1], - [Support Broadcom 56634 reference platform]) - fi - if test $SCORREF = yes; then - AC_DEFINE([SCORREF], [1], - [Support Broadcom 56820 reference platform]) - fi - AM_CONDITIONAL([NF2], [test $NF2 = yes]) - AM_CONDITIONAL([LB4G], [test $LB4G = yes]) - AM_CONDITIONAL([T2REF], [test $T2REF = yes]) - AM_CONDITIONAL([SCORREF], [test $SCORREF = yes]) - AM_CONDITIONAL([BUILD_HW_LIBS], [test $BUILD_HW_LIBS = yes]) - AC_SUBST(HW_LIB)]) - -dnl Checks for net/if_packet.h. -AC_DEFUN([OFP_CHECK_IF_PACKET], - [AC_CHECK_HEADER([net/if_packet.h], - [HAVE_IF_PACKET=yes], - [HAVE_IF_PACKET=no]) - AM_CONDITIONAL([HAVE_IF_PACKET], [test "$HAVE_IF_PACKET" = yes]) - if test "$HAVE_IF_PACKET" = yes; then - AC_DEFINE([HAVE_IF_PACKET], [1], - [Define to 1 if net/if_packet.h is available.]) - fi]) - -dnl Checks for dpkg-buildpackage. If this is available then we check -dnl that the Debian packaging is functional at "make distcheck" time. -AC_DEFUN([OFP_CHECK_DPKG_BUILDPACKAGE], - [AC_CHECK_PROG([HAVE_DPKG_BUILDPACKAGE], [dpkg-buildpackage], [yes], [no]) - AM_CONDITIONAL([HAVE_DPKG_BUILDPACKAGE], - [test $HAVE_DPKG_BUILDPACKAGE = yes])]) - -dnl ---------------------------------------------------------------------- -dnl These macros are from GNU PSPP, with the following original license: -dnl Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc. -dnl This file is free software; the Free Software Foundation -dnl gives unlimited permission to copy and/or distribute it, -dnl with or without modifications, as long as this notice is preserved. - -dnl OFP_CHECK_CC_OPTION([OPTION], [ACTION-IF-ACCEPTED], [ACTION-IF-REJECTED]) -dnl Check whether the given C compiler OPTION is accepted. -dnl If so, execute ACTION-IF-ACCEPTED, otherwise ACTION-IF-REJECTED. -AC_DEFUN([OFP_CHECK_CC_OPTION], -[ - m4_define([ofp_cv_name], [ofp_cv_[]m4_translit([$1], [-], [_])])dnl - AC_CACHE_CHECK([whether $CC accepts $1], [ofp_cv_name], - [ofp_save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $1" - AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,)], [ofp_cv_name[]=yes], [ofp_cv_name[]=no]) - CFLAGS="$ofp_save_CFLAGS"]) - if test $ofp_cv_name = yes; then - m4_if([$2], [], [;], [$2]) - else - m4_if([$3], [], [:], [$3]) - fi -]) - -dnl OFP_ENABLE_OPTION([OPTION]) -dnl Check whether the given C compiler OPTION is accepted. -dnl If so, add it to CFLAGS. -dnl Example: OFP_ENABLE_OPTION([-Wdeclaration-after-statement]) -AC_DEFUN([OFP_ENABLE_OPTION], - [OFP_CHECK_CC_OPTION([$1], [CFLAGS="$CFLAGS $1"])]) -dnl ---------------------------------------------------------------------- diff --git a/openflow/boot.sh b/openflow/boot.sh deleted file mode 100755 index 97921fac..00000000 --- a/openflow/boot.sh +++ /dev/null @@ -1,14 +0,0 @@ -#! /bin/sh - -set -e - -# Generate list of files in debian/ to distribute. -(echo '# Automatically generated by boot.sh (from Git tree).' && - printf 'EXTRA_DIST += \\\n' && - git ls-files debian | grep -v '^debian/\.gitignore$' | - sed -e 's/\(.*\)/ \1 \\/' -e '$s/ \\//') > debian/automake.mk - -cat debian/control.in > debian/control - -# Bootstrap configure system from .ac/.am files -autoreconf --install --force diff --git a/openflow/configure.ac b/openflow/configure.ac deleted file mode 100644 index 13064f68..00000000 --- a/openflow/configure.ac +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford -# Junior University -# -# We are making the OpenFlow specification and associated documentation -# (Software) available for public use and benefit with the expectation -# that others will use, modify and enhance the Software and contribute -# those enhancements back to the community. However, since we would -# like to make the Software available for broadest use, with as few -# restrictions as possible permission is hereby granted, free of -# charge, to any person obtaining a copy of this Software to deal in -# the Software under the copyrights without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# -# The name and trademarks of copyright holder(s) may NOT be used in -# advertising or publicity pertaining to the Software or any -# derivatives without specific, written prior permission. - -AC_PREREQ(2.60) -AC_INIT([openflow], [1.0.0], [openflow-discuss@openflowswitch.org]) -NX_BUILDNR -AC_CONFIG_SRCDIR([README.hwtables]) -AC_CONFIG_MACRO_DIR([m4]) -AC_CONFIG_AUX_DIR([build-aux]) -AC_CONFIG_HEADERS([config.h]) -AM_INIT_AUTOMAKE - -AC_PROG_CC -AM_PROG_CC_C_O -AC_PROG_CPP -AC_PROG_RANLIB -AC_PROG_MKDIR_P - -AC_ARG_VAR([PERL], [path to Perl interpreter]) -AC_PATH_PROG([PERL], perl, no) -if test "$PERL" = no; then - AC_MSG_ERROR([Perl interpreter not found in $PATH or $PERL.]) -fi - -OFP_CHECK_LIBOPENFLOW -OFP_CHECK_IF_PACKET -OFP_CHECK_HWTABLES -OFP_CHECK_HWLIBS -AC_SYS_LARGEFILE - -AC_CHECK_FUNCS([strsignal]) - -AC_ARG_VAR(KARCH, [Kernel Architecture String]) -AC_SUBST(KARCH) -#OFP_CHECK_LINUX(l26, 2.6, KBLD26, KSRC26, L26_ENABLED) - -OFP_CHECK_DPKG_BUILDPACKAGE - -OFP_ENABLE_OPTION([-Wall]) -OFP_ENABLE_OPTION([-Wno-sign-compare]) -OFP_ENABLE_OPTION([-Wpointer-arith]) -OFP_ENABLE_OPTION([-Wdeclaration-after-statement]) -OFP_ENABLE_OPTION([-Wformat-security]) -OFP_ENABLE_OPTION([-Wswitch-enum]) -OFP_ENABLE_OPTION([-Wunused-parameter]) -OFP_ENABLE_OPTION([-Wstrict-aliasing]) -OFP_ENABLE_OPTION([-Wbad-function-cast]) -OFP_ENABLE_OPTION([-Wcast-align]) -OFP_ENABLE_OPTION([-Wstrict-prototypes]) -OFP_ENABLE_OPTION([-Wold-style-definition]) -OFP_ENABLE_OPTION([-Wmissing-prototypes]) -OFP_ENABLE_OPTION([-Wmissing-field-initializers]) -OFP_ENABLE_OPTION([-Wno-override-init]) - -AC_CONFIG_FILES([Makefile -]) - -#AC_CONFIG_FILES([Makefile -#datapath/Makefile -#datapath/linux-2.6/Kbuild -#datapath/linux-2.6/Makefile -#datapath/linux-2.6/Makefile.main -#]) - -AC_OUTPUT diff --git a/openflow/controller/.dirstamp b/openflow/controller/.dirstamp deleted file mode 100644 index e69de29b..00000000 diff --git a/openflow/controller/.gitignore b/openflow/controller/.gitignore deleted file mode 100644 index 8736bbc1..00000000 --- a/openflow/controller/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/Makefile -/Makefile.in -/controller -/controller.8 diff --git a/openflow/controller/automake.mk b/openflow/controller/automake.mk deleted file mode 100644 index ff9f627c..00000000 --- a/openflow/controller/automake.mk +++ /dev/null @@ -1,8 +0,0 @@ -bin_PROGRAMS += controller/controller -man_MANS += controller/controller.8 -DISTCLEANFILES += controller/controller.8 - -controller_controller_SOURCES = controller/controller.c -controller_controller_LDADD = lib/libopenflow.a $(FAULT_LIBS) $(SSL_LIBS) - -EXTRA_DIST += controller/controller.8.in diff --git a/openflow/controller/controller.8.in b/openflow/controller/controller.8.in deleted file mode 100644 index c2b65cfb..00000000 --- a/openflow/controller/controller.8.in +++ /dev/null @@ -1,150 +0,0 @@ -.ds PN controller - -.TH controller 8 "May 2008" "OpenFlow" "OpenFlow Manual" - -.SH NAME -controller \- simple OpenFlow controller reference implementation - -.SH SYNOPSIS -.B controller -[\fIoptions\fR] \fImethod\fR \fB[\fImethod\fR]\&... - -.SH DESCRIPTION -A sample OpenFlow controller which functions as an L2 MAC-learning -switch or hub. \fBcontroller\fR can manage a remote datapath through -a secure channel (see \fBofprotocol(8)\fR). It can also connect directly -to a local datapath via Netlink. - -\fBcontroller\fR controls one or more OpenFlow switches, specified as -one or more of the following OpenFlow connection methods: - -.TP -\fBpssl:\fR[\fIport\fR] -Listens for SSL connections from remote OpenFlow switches on -\fIport\fR (default: 6633). The \fB--private-key\fR, -\fB--certificate\fR, and \fB--ca-cert\fR options are mandatory when -this form is used. - -.TP -\fBptcp:\fR[\fIport\fR] -Listens for TCP connections from remote OpenFlow switches on -\fIport\fR (default: 6633). - -.TP -\fBpunix:\fIfile\fR -Listens for connections from OpenFlow switches on the Unix domain -server socket named \fIfile\fR. - -.TP -\fBnl:\fIdp_idx\fR -The local Netlink datapath numbered \fIdp_idx\fR, as configured with -.BR dpctl (8). -This form requires that the local host has the OpenFlow kernel -module for Linux loaded. - -.TP -\fBssl:\fIhost\fR[\fB:\fIport\fR] -The specified SSL \fIport\fR (default: 6633) on the given remote -\fIhost\fR. The \fB--private-key\fR, \fB--certificate\fR, and -\fB--ca-cert\fR options are mandatory when this form is used. - -.TP -\fBtcp:\fIhost\fR[\fB:\fIport\fR] -The specified TCP \fIport\fR (default: 6633) on the given remote -\fIhost\fR. - -.TP -\fBunix:\fIfile\fR -The Unix domain server socket named \fIfile\fR. - -.SH OPTIONS -.TP -\fB-p\fR, \fB--private-key=\fIprivkey.pem\fR -Specifies a PEM file containing the private key used as the switch's -identity for SSL connections to the controller. - -.TP -\fB-c\fR, \fB--certificate=\fIcert.pem\fR -Specifies a PEM file containing a certificate, signed by the -controller's certificate authority (CA), that certifies the switch's -private key to identify a trustworthy switch. - -.TP -\fB-C\fR, \fB--ca-cert=\fIswitch-cacert.pem\fR -Specifies a PEM file containing the CA certificate used to verify that -the switch is connected to a trustworthy controller. - -.TP -\fB--peer-ca-cert=\fIcontroller-cacert.pem\fR -Specifies a PEM file that contains one or more additional certificates -to send to switches. \fIcontroller-cacert.pem\fR should be the CA -certificate used to sign the controller's own certificate (the -certificate specified on \fB-c\fR or \fB--certificate\fR). - -This option is not useful in normal operation, because the switch must -already have the controller CA certificate for it to have any -confidence in the controller's identity. However, this option allows -a newly installed switch to obtain the controller CA certificate on -first boot using, e.g., the \fB--bootstrap-ca-cert\fR option to -\fBofprotocol\fR(8). - -.TP -.BR \-n ", " \-\^\-noflow -By default, the controller sets up a flow in each OpenFlow switch -whenever it receives a packet whose destination is known due through -MAC learning. This option disables flow setup, so that every packet -in the network passes through the controller. - -This option is most useful for debugging. It reduces switching -performance, so it should not be used in production. - -.TP -\fB--max-idle=\fIsecs\fR|\fBpermanent\fR -Sets \fIsecs\fR as the number of seconds that a flow set up by the -controller will remain in the switch's flow table without any matching -packets being seen. If \fBpermanent\fR is specified, which is not -recommended, flows will never expire. The default is 60 seconds. - -This option affects only flows set up by the OpenFlow controller. In -some configurations, the OpenFlow secure channel can set up some flows -on its own. To set the idle time for those flows, pass -\fB--max-idle\fR to \fBofprotocol\fR(8). - -This option has no effect when \fB-n\fR (or \fB--noflow\fR) is in use -(because the controller does not set up flows in that case). - -.TP -.BR \-H ", " \-\^\-hub -By default, the controller acts as an L2 MAC-learning switch. This -option changes its behavior to that of a hub that floods packets on -all but the incoming port. - -If \fB-H\fR (or \fB--hub\fR) and \fB-n\fR (or \fB--noflow\fR) are used -together, then the cumulative effect is that every packet passes -through the controller and every packet is flooded. - -This option is most useful for debugging. It reduces switching -performance, so it should not be used in production. - -.so lib/daemon.man -.so lib/vlog.man -.so lib/common.man - -.SH EXAMPLES - -.TP -To connect directly to local datapath 0 over netlink (Linux only): - -.B % controller nl:0 - -.TP -To bind locally to port 6633 (the default) and wait for incoming connections from OpenFlow switches: - -.B % controller ptcp: - -.SH "SEE ALSO" - -.BR dpctl (8), -.BR ofprotocol (8), -.BR ofdatapath (8), -.BR vlogconf (8) diff --git a/openflow/controller/controller.c b/openflow/controller/controller.c deleted file mode 100644 index 6eec5906..00000000 --- a/openflow/controller/controller.c +++ /dev/null @@ -1,336 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include - -#include -#include -#include -#include -#include -#include - -#include "command-line.h" -#include "compiler.h" -#include "daemon.h" -#include "fault.h" -#include "learning-switch.h" -#include "ofpbuf.h" -#include "openflow/openflow.h" -#include "poll-loop.h" -#include "rconn.h" -#include "timeval.h" -#include "util.h" -#include "vconn-ssl.h" -#include "vconn.h" -#include "vlog-socket.h" - -#include "vlog.h" -#define THIS_MODULE VLM_controller - -#define MAX_SWITCHES 4096 -#define MAX_LISTENERS 4096 - -struct switch_ { - struct lswitch *lswitch; - struct rconn *rconn; -}; - -/* Learn the ports on which MAC addresses appear? */ -static bool learn_macs = true; - -/* Set up flows? (If not, every packet is processed at the controller.) */ -static bool setup_flows = true; - -/* --max-idle: Maximum idle time, in seconds, before flows expire. */ -static int max_idle = 60; - -static int do_switching(struct switch_ *); -static void new_switch(struct switch_ *, struct vconn *, const char *name); -static void parse_options(int argc, char *argv[]); -static void usage(void) NO_RETURN; - -int -main(int argc, char *argv[]) -{ - struct switch_ switches[MAX_SWITCHES]; - struct pvconn *listeners[MAX_LISTENERS]; - int n_switches, n_listeners; - int retval; - int i; - - set_program_name(argv[0]); - register_fault_handlers(); - time_init(); - vlog_init(); - parse_options(argc, argv); - signal(SIGPIPE, SIG_IGN); - - if (argc - optind < 1) { - ofp_fatal(0, "at least one vconn argument required; " - "use --help for usage"); - } - - n_switches = n_listeners = 0; - for (i = optind; i < argc; i++) { - const char *name = argv[i]; - struct vconn *vconn; - int retval; - - retval = vconn_open(name, OFP_VERSION, &vconn); - if (!retval) { - if (n_switches >= MAX_SWITCHES) { - ofp_fatal(0, "max %d switch connections", n_switches); - } - new_switch(&switches[n_switches++], vconn, name); - continue; - } else if (retval == EAFNOSUPPORT) { - struct pvconn *pvconn; - retval = pvconn_open(name, &pvconn); - if (!retval) { - if (n_listeners >= MAX_LISTENERS) { - ofp_fatal(0, "max %d passive connections", n_listeners); - } - listeners[n_listeners++] = pvconn; - } - } - if (retval) { - VLOG_ERR("%s: connect: %s", name, strerror(retval)); - } - } - if (n_switches == 0 && n_listeners == 0) { - ofp_fatal(0, "no active or passive switch connections"); - } - - die_if_already_running(); - daemonize(); - - retval = vlog_server_listen(NULL, NULL); - if (retval) { - ofp_fatal(retval, "Could not listen for vlog connections"); - } - - while (n_switches > 0 || n_listeners > 0) { - int iteration; - int i; - - /* Accept connections on listening vconns. */ - for (i = 0; i < n_listeners && n_switches < MAX_SWITCHES; ) { - struct vconn *new_vconn; - int retval; - - retval = pvconn_accept(listeners[i], OFP_VERSION, &new_vconn); - if (!retval || retval == EAGAIN) { - if (!retval) { - new_switch(&switches[n_switches++], new_vconn, "tcp"); - } - i++; - } else { - pvconn_close(listeners[i]); - listeners[i] = listeners[--n_listeners]; - } - } - - /* Do some switching work. Limit the number of iterations so that - * callbacks registered with the poll loop don't starve. */ - for (iteration = 0; iteration < 50; iteration++) { - bool progress = false; - for (i = 0; i < n_switches; ) { - struct switch_ *this = &switches[i]; - int retval = do_switching(this); - if (!retval || retval == EAGAIN) { - if (!retval) { - progress = true; - } - i++; - } else { - rconn_destroy(this->rconn); - lswitch_destroy(this->lswitch); - switches[i] = switches[--n_switches]; - } - } - if (!progress) { - break; - } - } - for (i = 0; i < n_switches; i++) { - struct switch_ *this = &switches[i]; - lswitch_run(this->lswitch, this->rconn); - } - - /* Wait for something to happen. */ - if (n_switches < MAX_SWITCHES) { - for (i = 0; i < n_listeners; i++) { - pvconn_wait(listeners[i]); - } - } - for (i = 0; i < n_switches; i++) { - struct switch_ *sw = &switches[i]; - rconn_run_wait(sw->rconn); - rconn_recv_wait(sw->rconn); - lswitch_wait(sw->lswitch); - } - poll_block(); - } - - return 0; -} - -static void -new_switch(struct switch_ *sw, struct vconn *vconn, const char *name) -{ - sw->rconn = rconn_new_from_vconn(name, vconn); - sw->lswitch = lswitch_create(sw->rconn, learn_macs, - setup_flows ? max_idle : -1); -} - -static int -do_switching(struct switch_ *sw) -{ - unsigned int packets_sent; - struct ofpbuf *msg; - - packets_sent = rconn_packets_sent(sw->rconn); - - msg = rconn_recv(sw->rconn); - if (msg) { - lswitch_process_packet(sw->lswitch, sw->rconn, msg); - ofpbuf_delete(msg); - } - rconn_run(sw->rconn); - - return (!rconn_is_alive(sw->rconn) ? EOF - : rconn_packets_sent(sw->rconn) != packets_sent ? 0 - : EAGAIN); -} - -static void -parse_options(int argc, char *argv[]) -{ - enum { - OPT_MAX_IDLE = UCHAR_MAX + 1, - OPT_PEER_CA_CERT, - VLOG_OPTION_ENUMS - }; - static struct option long_options[] = { - {"hub", no_argument, 0, 'H'}, - {"noflow", no_argument, 0, 'n'}, - {"max-idle", required_argument, 0, OPT_MAX_IDLE}, - {"help", no_argument, 0, 'h'}, - {"version", no_argument, 0, 'V'}, - DAEMON_LONG_OPTIONS, - VLOG_LONG_OPTIONS, -#ifdef HAVE_OPENSSL - VCONN_SSL_LONG_OPTIONS - {"peer-ca-cert", required_argument, 0, OPT_PEER_CA_CERT}, -#endif - {0, 0, 0, 0}, - }; - char *short_options = long_options_to_short_options(long_options); - - for (;;) { - int indexptr; - int c; - - c = getopt_long(argc, argv, short_options, long_options, &indexptr); - if (c == -1) { - break; - } - - switch (c) { - case 'H': - learn_macs = false; - break; - - case 'n': - setup_flows = false; - break; - - case OPT_MAX_IDLE: - if (!strcmp(optarg, "permanent")) { - max_idle = OFP_FLOW_PERMANENT; - } else { - max_idle = atoi(optarg); - if (max_idle < 1 || max_idle > 65535) { - ofp_fatal(0, "--max-idle argument must be between 1 and " - "65535 or the word 'permanent'"); - } - } - break; - - case 'h': - usage(); - - case 'V': - printf("%s "VERSION" compiled "__DATE__" "__TIME__"\n", argv[0]); - exit(EXIT_SUCCESS); - - VLOG_OPTION_HANDLERS - DAEMON_OPTION_HANDLERS - -#ifdef HAVE_OPENSSL - VCONN_SSL_OPTION_HANDLERS - - case OPT_PEER_CA_CERT: - vconn_ssl_set_peer_ca_cert_file(optarg); - break; -#endif - - case '?': - exit(EXIT_FAILURE); - - default: - abort(); - } - } - free(short_options); -} - -static void -usage(void) -{ - printf("%s: OpenFlow controller\n" - "usage: %s [OPTIONS] METHOD\n" - "where METHOD is any OpenFlow connection method.\n", - program_name, program_name); - vconn_usage(true, true, false); - daemon_usage(); - vlog_usage(); - printf("\nOther options:\n" - " -H, --hub act as hub instead of learning switch\n" - " -n, --noflow pass traffic, but don't add flows\n" - " --max-idle=SECS max idle time for new flows\n" - " -h, --help display this help message\n" - " -V, --version display version information\n"); - exit(EXIT_SUCCESS); -} diff --git a/openflow/datapath/.gitignore b/openflow/datapath/.gitignore deleted file mode 100644 index 5a59a0d3..00000000 --- a/openflow/datapath/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -/Makefile -/Makefile.in -*.cmd -*.ko -*.mod.c -Module.symvers - diff --git a/openflow/datapath/Makefile.am b/openflow/datapath/Makefile.am deleted file mode 100644 index 7eed78d1..00000000 --- a/openflow/datapath/Makefile.am +++ /dev/null @@ -1,27 +0,0 @@ -SUBDIRS = -if L26_ENABLED -SUBDIRS += linux-2.6 -endif - -EXTRA_DIST = $(dist_headers) $(dist_sources) -EXTRA_DIST += hwtable_dummy/Modules.mk hwtable_dummy/hwtable_dummy.c -EXTRA_DIST += \ - hwtable_nf2/Modules.mk \ - hwtable_nf2/nf2.h \ - hwtable_nf2/nf2_hwapi.h \ - hwtable_nf2/nf2_reg.h \ - hwtable_nf2/nf2_flowtable.c \ - hwtable_nf2/nf2_flowtable.h \ - hwtable_nf2/nf2_lib.c \ - hwtable_nf2/nf2_lib.h \ - hwtable_nf2/nf2_procfs.c \ - hwtable_nf2/nf2_procfs.h \ - hwtable_nf2/nf2_openflow.c \ - hwtable_nf2/nf2_openflow.h \ - hwtable_nf2/openflow_switch.bit - -# Suppress warnings about GNU extensions in Modules.mk files. -AUTOMAKE_OPTIONS = -Wno-portability - -include Modules.mk -include linux-2.6/Modules.mk diff --git a/openflow/datapath/Modules.mk b/openflow/datapath/Modules.mk deleted file mode 100644 index 777dc658..00000000 --- a/openflow/datapath/Modules.mk +++ /dev/null @@ -1,42 +0,0 @@ -# Some modules should be built and distributed, e.g. openflow. -# -# Some modules should be distributed but not built, e.g. we do not build -# veth if the kernel in question already has it. -# -# Some modules should be built but not distributed, e.g. third-party -# hwtable modules. -both_modules = ofdatapath -build_modules = $(both_modules) # Modules to build -dist_modules = $(both_modules) # Modules to distribute - -ofdatapath_sources = \ - chain.c \ - crc32.c \ - datapath.c \ - dp_act.c \ - dp_dev.c \ - dp_notify.c \ - flow.c \ - forward.c \ - private-msg.c \ - table-hash.c \ - table-linear.c - -ofdatapath_headers = \ - chain.h \ - compat.h \ - crc32.h \ - datapath.h \ - dp_dev.h \ - flow.h \ - forward.h \ - dp_act.h \ - private-msg.h \ - table.h - -dist_sources = $(foreach module,$(dist_modules),$($(module)_sources)) -dist_headers = $(foreach module,$(dist_modules),$($(module)_headers)) -build_sources = $(foreach module,$(build_modules),$($(module)_sources)) -build_headers = $(foreach module,$(build_modules),$($(module)_headers)) -build_links = $(notdir $(build_sources)) -build_objects = $(notdir $(patsubst %.c,%.o,$(build_sources))) diff --git a/openflow/datapath/chain.c b/openflow/datapath/chain.c deleted file mode 100644 index e75f77dc..00000000 --- a/openflow/datapath/chain.c +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Distributed under the terms of the GNU GPL version 2. - * Copyright (c) 2007, 2008, 2009 The Board of Trustees of The Leland - * Stanford Junior University - */ - -#include "chain.h" -#include "datapath.h" -#include "flow.h" -#include "table.h" -#include -#include -#include -#include - -static struct sw_table *(*create_hw_table_hook)(void); -static struct module *hw_table_owner; -static DEFINE_SPINLOCK(hook_lock); - -/* Attempts to append 'table' to the set of tables in 'chain'. Returns 0 or - * negative error. If 'table' is null it is assumed that table creation failed - * due to out-of-memory. */ -static int add_table(struct sw_chain *chain, struct sw_table *table, int emerg) -{ - if (table == NULL) - return -ENOMEM; - if (chain->n_tables >= CHAIN_MAX_TABLES) { - printk(KERN_EMERG "%s: too many tables in chain\n", - chain->dp->netdev->name); - table->destroy(table); - return -ENOBUFS; - } - if (emerg) - chain->emerg_table = table; - else - chain->tables[chain->n_tables++] = table; - return 0; -} - -/* Creates and returns a new chain associated with 'dp'. Returns NULL if the - * chain cannot be created. */ -struct sw_chain *chain_create(struct datapath *dp) -{ - struct sw_chain *chain = kzalloc(sizeof *chain, GFP_KERNEL); - if (chain == NULL) - goto error; - chain->dp = dp; - chain->owner = try_module_get(hw_table_owner) ? hw_table_owner : NULL; - if (chain->owner && create_hw_table_hook) { - struct sw_table *hwtable = create_hw_table_hook(); - if (!hwtable || add_table(chain, hwtable, 0)) - goto error; - } - - if (add_table(chain, table_hash2_create(0x1EDC6F41, TABLE_HASH_MAX_FLOWS, - 0x741B8CD7, TABLE_HASH_MAX_FLOWS), - 0) - || add_table(chain, table_linear_create(TABLE_LINEAR_MAX_FLOWS), 0) - || add_table(chain, table_linear_create(TABLE_LINEAR_MAX_FLOWS), 1)) - goto error; - return chain; - -error: - if (chain) - chain_destroy(chain); - return NULL; -} - -/* Searches 'chain' for a flow matching 'key', which must not have any wildcard - * fields. Returns the flow if successful, otherwise a null pointer. - * - * Caller must hold rcu_read_lock or dp_mutex. */ -struct sw_flow *chain_lookup(struct sw_chain *chain, - const struct sw_flow_key *key, int emerg) -{ - int i; - - BUG_ON(key->wildcards); - if (emerg) { - struct sw_table *t = chain->emerg_table; - struct sw_flow *flow = t->lookup(t, key); - t->n_lookup++; - if (flow) { - t->n_matched++; - return flow; - } - } else { - for (i = 0; i < chain->n_tables; i++) { - struct sw_table *t = chain->tables[i]; - struct sw_flow *flow = t->lookup(t, key); - t->n_lookup++; - if (flow) { - t->n_matched++; - return flow; - } - } - } - return NULL; -} - -/* Inserts 'flow' into 'chain', replacing any duplicate flow. Returns 0 if - * successful or a negative error. - * - * If successful, 'flow' becomes owned by the chain, otherwise it is retained - * by the caller. - * - * Caller must hold dp_mutex. */ -int chain_insert(struct sw_chain *chain, struct sw_flow *flow, int emerg) -{ - int i; - - might_sleep(); - if (emerg) { - struct sw_table *t = chain->emerg_table; - if (t->insert(t, flow)) - return 0; - } else { - for (i = 0; i < chain->n_tables; i++) { - struct sw_table *t = chain->tables[i]; - if (t->insert(t, flow)) - return 0; - } - } - return -ENOBUFS; -} - -/* Modifies actions in 'chain' that match 'key'. If 'strict' set, wildcards - * and priority must match. Returns the number of flows that were modified. - * - * Expensive in the general case as currently implemented, since it requires - * iterating through the entire contents of each table for keys that contain - * wildcards. Relatively cheap for fully specified keys. */ -int -chain_modify(struct sw_chain *chain, const struct sw_flow_key *key, - uint16_t priority, int strict, - const struct ofp_action_header *actions, size_t actions_len, - int emerg) -{ - int count = 0; - int i; - - if (emerg) { - struct sw_table *t = chain->emerg_table; - count += t->modify(t, key, priority, strict, - actions, actions_len); - } else { - for (i = 0; i < chain->n_tables; i++) { - struct sw_table *t = chain->tables[i]; - count += t->modify(t, key, priority, strict, - actions, actions_len); - } - } - return count; -} - -/* Checks whether the chain has an entry with the same priority which conflicts - * with 'key'. If 'strict' set, wildcards should also match. If 'strict' is not - * set, comparison is done 'module wildcards'. - * - * Returns 'true' if such an entry exists, 'false' otherwise. */ -int -chain_has_conflict(struct sw_chain *chain, const struct sw_flow_key *key, - uint16_t priority, int strict) -{ - int i; - - for (i = 0; i < chain->n_tables; i++) { - struct sw_table *t = chain->tables[i]; - if (t->has_conflict(t, key, priority, strict)) { - return true; - } - } - - return false; -} - -/* Deletes from 'chain' any and all flows that match 'key'. If 'out_port' - * is not OFPP_NONE, then matching entries must have that port as an - * argument for an output action. If 'strict" is set, then wildcards and - * priority must match. Returns the number of flows that were deleted. - * - * Expensive in the general case as currently implemented, since it requires - * iterating through the entire contents of each table for keys that contain - * wildcards. Relatively cheap for fully specified keys. - * - * Caller must hold dp_mutex. */ -int chain_delete(struct sw_chain *chain, const struct sw_flow_key *key, - uint16_t out_port, uint16_t priority, int strict, int emerg) -{ - int count = 0; - int i; - - might_sleep(); - if (emerg) { - struct sw_table *t = chain->emerg_table; - count += t->delete(chain->dp, t, key, - out_port, priority, strict); - } else { - for (i = 0; i < chain->n_tables; i++) { - struct sw_table *t = chain->tables[i]; - count += t->delete(chain->dp, t, key, - out_port, priority, strict); - } - } - return count; -} - -/* Performs timeout processing on all the tables in 'chain'. Returns the - * number of flow entries deleted through expiration. - * - * Expensive as currently implemented, since it iterates through the entire - * contents of each table. - * - * Caller must not hold dp_mutex, because individual tables take and release it - * as necessary. */ -int chain_timeout(struct sw_chain *chain) -{ - int count = 0; - int i; - - might_sleep(); - for (i = 0; i < chain->n_tables; i++) { - struct sw_table *t = chain->tables[i]; - count += t->timeout(chain->dp, t); - } - return count; -} - -/* Destroys 'chain', which must not have any users. */ -void chain_destroy(struct sw_chain *chain) -{ - int i; - struct sw_table *t = NULL; - - synchronize_rcu(); - for (i = 0; i < chain->n_tables; i++) { - t = chain->tables[i]; - if (t->destroy) - t->destroy(t); - } - t = chain->emerg_table; - if (t->destroy) - t->destroy(t); - module_put(chain->owner); - kfree(chain); -} - -int chain_set_hw_hook(struct sw_table *(*create_hw_table)(void), - struct module *owner) -{ - int retval = -EBUSY; - - spin_lock(&hook_lock); - if (!create_hw_table_hook) { - create_hw_table_hook = create_hw_table; - hw_table_owner = owner; - retval = 0; - } - spin_unlock(&hook_lock); - - return retval; -} -EXPORT_SYMBOL(chain_set_hw_hook); - -void chain_clear_hw_hook(void) -{ - create_hw_table_hook = NULL; - hw_table_owner = NULL; -} -EXPORT_SYMBOL(chain_clear_hw_hook); diff --git a/openflow/datapath/chain.h b/openflow/datapath/chain.h deleted file mode 100644 index 4b00aef6..00000000 --- a/openflow/datapath/chain.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef CHAIN_H -#define CHAIN_H 1 - -#include - -struct sw_flow; -struct sw_flow_key; -struct ofp_action_header; -struct datapath; - - -#define TABLE_LINEAR_MAX_FLOWS 100 -#define TABLE_HASH_MAX_FLOWS 65536 - -/* Set of tables chained together in sequence from cheap to expensive. */ -#define CHAIN_MAX_TABLES 4 -struct sw_chain { - int n_tables; - struct sw_table *tables[CHAIN_MAX_TABLES]; - struct sw_table *emerg_table; - - struct datapath *dp; - struct module *owner; -}; - -struct sw_chain *chain_create(struct datapath *); -struct sw_flow *chain_lookup(struct sw_chain *, const struct sw_flow_key *, - int); -int chain_insert(struct sw_chain *, struct sw_flow *, int); -int chain_modify(struct sw_chain *, const struct sw_flow_key *, - uint16_t, int, const struct ofp_action_header *, size_t, int); -int chain_has_conflict(struct sw_chain *, const struct sw_flow_key *, - uint16_t, int); -int chain_delete(struct sw_chain *, const struct sw_flow_key *, uint16_t, - uint16_t, int, int); -int chain_timeout(struct sw_chain *); -void chain_destroy(struct sw_chain *); - -int chain_set_hw_hook(struct sw_table *(*create_hw_table)(void), - struct module *owner); -void chain_clear_hw_hook(void); - -#endif /* chain.h */ diff --git a/openflow/datapath/compat.h b/openflow/datapath/compat.h deleted file mode 100644 index 1915cd31..00000000 --- a/openflow/datapath/compat.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef COMPAT_H -#define COMPAT_H 1 - -#include - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) - -#include "compat26.h" - -#endif - -#endif /* compat.h */ diff --git a/openflow/datapath/crc32.c b/openflow/datapath/crc32.c deleted file mode 100644 index 3cb26c5a..00000000 --- a/openflow/datapath/crc32.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Distributed under the terms of the GNU GPL version 2. - * Copyright (c) 2007, 2008 The Board of Trustees of The Leland - * Stanford Junior University - */ - -#include -#include "crc32.h" - -void crc32_init(struct crc32 *crc, unsigned int polynomial) -{ - int i; - - for (i = 0; i < CRC32_TABLE_SIZE; ++i) { - unsigned int reg = i << 24; - int j; - for (j = 0; j < CRC32_TABLE_BITS; j++) { - int topBit = (reg & 0x80000000) != 0; - reg <<= 1; - if (topBit) - reg ^= polynomial; - } - crc->table[i] = reg; - } -} - -EXPORT_SYMBOL(crc32_init); - -unsigned int crc32_calculate(const struct crc32 *crc, - const void *data_, size_t n_bytes) -{ - // FIXME: this can be optimized by unrolling, see linux-2.6/lib/crc32.c. - const uint8_t *data = data_; - unsigned int result = 0; - size_t i; - - for (i = 0; i < n_bytes; i++) { - unsigned int top = result >> 24; - top ^= data[i]; - result = (result << 8) ^ crc->table[top]; - } - return result; -} - -EXPORT_SYMBOL(crc32_calculate); diff --git a/openflow/datapath/crc32.h b/openflow/datapath/crc32.h deleted file mode 100644 index 21a350a9..00000000 --- a/openflow/datapath/crc32.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef CRC32_H -#define CRC32_H 1 - -#include -#ifndef __KERNEL__ -#include -#endif -#include - -#define CRC32_TABLE_BITS 8 -#define CRC32_TABLE_SIZE (1u << CRC32_TABLE_BITS) - -struct crc32 { - unsigned int table[CRC32_TABLE_SIZE]; -}; - -void crc32_init(struct crc32 *, unsigned int polynomial); -unsigned int crc32_calculate(const struct crc32 *, - const void *data_, size_t n_bytes); - - -#endif /* crc32.h */ diff --git a/openflow/datapath/datapath.c b/openflow/datapath/datapath.c deleted file mode 100644 index 5678ea68..00000000 --- a/openflow/datapath/datapath.c +++ /dev/null @@ -1,2137 +0,0 @@ -/* - * Distributed under the terms of the GNU GPL version 2. - * Copyright (c) 2007, 2008, 2009 The Board of Trustees of The Leland - * Stanford Junior University - */ - -/* Functions for managing the dp interface/device. */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "openflow/nicira-ext.h" -#include "openflow/openflow-netlink.h" -#include "datapath.h" -#include "table.h" -#include "chain.h" -#include "dp_dev.h" -#include "forward.h" -#include "flow.h" - -#include "compat.h" - - -/* Strings to describe the manufacturer, hardware, and software. This data - * is queriable through the switch description stats message. */ -static char mfr_desc[DESC_STR_LEN] = "Stanford University"; -static char hw_desc[DESC_STR_LEN] = "Reference Kernelspace Switch"; -static char sw_desc[DESC_STR_LEN] = VERSION BUILDNR; -static char serial_num[SERIAL_NUM_LEN] = "None"; - -module_param_string(mfr_desc, mfr_desc, sizeof mfr_desc, 0444); -module_param_string(hw_desc, hw_desc, sizeof hw_desc, 0444); -module_param_string(sw_desc, sw_desc, sizeof sw_desc, 0444); -module_param_string(serial_num, serial_num, sizeof serial_num, 0444); - -int (*dp_ioctl_hook)(struct net_device *dev, struct ifreq *rq, int cmd); -EXPORT_SYMBOL(dp_ioctl_hook); - -int (*dp_add_dp_hook)(struct datapath *dp); -EXPORT_SYMBOL(dp_add_dp_hook); - -int (*dp_del_dp_hook)(struct datapath *dp); -EXPORT_SYMBOL(dp_del_dp_hook); - -int (*dp_add_if_hook)(struct net_bridge_port *p); -EXPORT_SYMBOL(dp_add_if_hook); - -int (*dp_del_if_hook)(struct net_bridge_port *p); -EXPORT_SYMBOL(dp_del_if_hook); - -/* Number of milliseconds between runs of the maintenance thread. */ -#define MAINT_SLEEP_MSECS 1000 - -static struct genl_family dp_genl_family; - -/* - * Datapath multicast groups. - * - * Really we want one multicast group per in-use datapath (or even more than - * one). Locking issues, however, mean that we can't allocate a multicast - * group at the point in the code where we we actually create a datapath[*], so - * we have to pre-allocate them. It's massive overkill to allocate DP_MAX of - * them in advance, since we will hardly ever actually create DP_MAX datapaths, - * so instead we allocate a few multicast groups at startup and choose one for - * each datapath by hashing its datapath index. - * - * [*] dp_genl_add, to add a new datapath, is called under the genl_lock - * mutex, and genl_register_mc_group, called to acquire a new multicast - * group ID, also acquires genl_lock, thus deadlock. - */ -#define N_MC_GROUPS 16 /* Must be power of 2. */ -static struct genl_multicast_group mc_groups[N_MC_GROUPS]; - -/* Datapaths. Protected on the read side by rcu_read_lock, on the write side - * by dp_mutex. dp_mutex is almost completely redundant with genl_mutex - * maintained by the Generic Netlink code, but the timeout path needs mutual - * exclusion too. - * - * dp_mutex nests inside the RTNL lock: if you need both you must take the RTNL - * lock first. - * - * It is safe to access the datapath and net_bridge_port structures with just - * dp_mutex. - */ -static struct datapath *dps[DP_MAX]; -DEFINE_MUTEX(dp_mutex); -EXPORT_SYMBOL(dp_mutex); - -static int dp_maint_func(void *data); -static void init_port_status(struct net_bridge_port *p); -static int dp_genl_openflow_done(struct netlink_callback *); -static struct net_bridge_port *new_nbp(struct datapath *, - struct net_device *, int port_no); - -/* nla_shrink - reduce amount of space reserved by nla_reserve - * @skb: socket buffer from which to recover room - * @nla: netlink attribute to adjust - * @len: new length of attribute payload - * - * Reduces amount of space reserved by a call to nla_reserve. - * - * No other attributes may be added between calling nla_reserve and this - * function, since it will create a hole in the message. - */ -void nla_shrink(struct sk_buff *skb, struct nlattr *nla, int len) -{ - int delta = nla_total_size(len) - nla_total_size(nla_len(nla)); - BUG_ON(delta > 0); - skb->tail += delta; - skb->len += delta; - nla->nla_len = nla_attr_size(len); -} - -/* Puts a set of openflow headers for a message of the given 'type' into 'skb'. - * If 'sender' is nonnull, then it is used as the message's destination. 'dp' - * must specify the datapath to use. - * - * '*max_openflow_len' receives the maximum number of bytes that are available - * for the embedded OpenFlow message. The caller must call - * resize_openflow_skb() to set the actual size of the message to this number - * of bytes or less. - * - * Returns the openflow header if successful, otherwise (if 'skb' is too small) - * an error code. */ -static void * -put_openflow_headers(struct datapath *dp, struct sk_buff *skb, uint8_t type, - const struct sender *sender, int *max_openflow_len) -{ - struct ofp_header *oh; - struct nlattr *attr; - int openflow_len; - - /* Assemble the Generic Netlink wrapper. */ - if (!genlmsg_put(skb, - sender ? sender->pid : 0, - sender ? sender->seq : 0, - &dp_genl_family, 0, DP_GENL_C_OPENFLOW)) - return ERR_PTR(-ENOBUFS); - if (nla_put_u32(skb, DP_GENL_A_DP_IDX, dp->dp_idx) < 0) - return ERR_PTR(-ENOBUFS); - openflow_len = (skb_tailroom(skb) - NLA_HDRLEN) & ~(NLA_ALIGNTO - 1); - if (openflow_len < sizeof *oh) - return ERR_PTR(-ENOBUFS); - *max_openflow_len = openflow_len; - attr = nla_reserve(skb, DP_GENL_A_OPENFLOW, openflow_len); - BUG_ON(!attr); - - /* Fill in the header. The caller is responsible for the length. */ - oh = nla_data(attr); - oh->version = OFP_VERSION; - oh->type = type; - oh->xid = sender ? sender->xid : 0; - - return oh; -} - -/* Resizes OpenFlow header 'oh', which must be at the tail end of 'skb', to new - * length 'new_length' (in bytes), adjusting pointers and size values as - * necessary. */ -static void -resize_openflow_skb(struct sk_buff *skb, - struct ofp_header *oh, size_t new_length) -{ - struct nlattr *attr = ((void *) oh) - NLA_HDRLEN; - nla_shrink(skb, attr, new_length); - oh->length = htons(new_length); - nlmsg_end(skb, (struct nlmsghdr *) skb->data); -} - -/* Allocates a new skb to contain an OpenFlow message 'openflow_len' bytes in - * length. Returns a null pointer if memory is unavailable, otherwise returns - * the OpenFlow header and stores a pointer to the skb in '*pskb'. - * - * 'type' is the OpenFlow message type. If 'sender' is nonnull, then it is - * used as the message's destination. 'dp' must specify the datapath to - * use. */ -static void * -alloc_openflow_skb(struct datapath *dp, size_t openflow_len, uint8_t type, - const struct sender *sender, struct sk_buff **pskb) -{ - struct ofp_header *oh; - size_t genl_len; - struct sk_buff *skb; - int max_openflow_len; - - if ((openflow_len + sizeof(struct ofp_header)) > UINT16_MAX) { - if (net_ratelimit()) - printk(KERN_ERR "%s: alloc_openflow_skb: openflow " - "message too large: %zu\n", - dp->netdev->name, openflow_len); - return NULL; - } - - genl_len = nlmsg_total_size(GENL_HDRLEN + dp_genl_family.hdrsize); - genl_len += nla_total_size(sizeof(uint32_t)); /* DP_GENL_A_DP_IDX */ - genl_len += nla_total_size(openflow_len); /* DP_GENL_A_OPENFLOW */ - skb = *pskb = genlmsg_new(genl_len, GFP_ATOMIC); - if (!skb) { - return NULL; - } - - oh = put_openflow_headers(dp, skb, type, sender, &max_openflow_len); - BUG_ON(!oh || IS_ERR(oh)); - resize_openflow_skb(skb, oh, openflow_len); - - return oh; -} - -/* Returns the ID of the multicast group used by datapath 'dp'. */ -static u32 -dp_mc_group(const struct datapath *dp) -{ - return mc_groups[dp->dp_idx & (N_MC_GROUPS - 1)].id; -} - -/* Sends 'skb' to 'sender' if it is nonnull, otherwise multicasts 'skb' to all - * listeners. */ -static int -send_openflow_skb(const struct datapath *dp, - struct sk_buff *skb, const struct sender *sender) -{ - return (sender - ? genlmsg_unicast(skb, sender->pid) - : genlmsg_multicast(skb, 0, dp_mc_group(dp), GFP_ATOMIC)); -} - -/* Retrieves the datapath id, which is the MAC address of the "of" device. */ -static -uint64_t get_datapath_id(struct net_device *dev) -{ - uint64_t id = 0; - int i; - - for (i=0; idev_addr[i] << (8*(ETH_ALEN-1 - i)); - - return id; -} - -/* Find the first free datapath index. Return the index or -1 if a free - * index could not be found. */ -int gen_dp_idx(void) -{ - int i; - - for (i=0; i= DP_MAX) - goto err_unlock; - - err = -ENODEV; - if (!try_module_get(THIS_MODULE)) - goto err_unlock; - - /* Exit early if a datapath with that number already exists. */ - err = -EEXIST; - if (dps[dp_idx]) - goto err_put; - - err = -ENOMEM; - dp = kzalloc(sizeof *dp, GFP_KERNEL); - if (dp == NULL) - goto err_put; - - dp->dp_idx = dp_idx; - /* copied from sys_gethostname() */ - u = utsname(); - /* shouldn't need to lock b/c no userspace interactions */ - snprintf(dp->dp_desc, sizeof dp->dp_desc, "%s idx=%d", u->nodename, dp_idx); - - /* Setup our datapath device */ - err = dp_dev_setup(dp, dp_name); - if (err) - goto err_free_dp; - - dp->chain = chain_create(dp); - if (dp->chain == NULL) - goto err_destroy_dp_dev; - INIT_LIST_HEAD(&dp->port_list); - - dp->local_port = new_nbp(dp, dp->netdev, OFPP_LOCAL); - if (IS_ERR(dp->local_port)) { - err = PTR_ERR(dp->local_port); - goto err_destroy_local_port; - } - - dp->flags = 0; - dp->miss_send_len = OFP_DEFAULT_MISS_SEND_LEN; - - dp->dp_task = kthread_run(dp_maint_func, dp, "dp%d", dp_idx); - if (IS_ERR(dp->dp_task)) - goto err_destroy_chain; - - dps[dp_idx] = dp; - mutex_unlock(&dp_mutex); - rtnl_unlock(); - - if (dp_add_dp_hook) - dp_add_dp_hook(dp); - - return 0; - -err_destroy_local_port: - dp_del_switch_port(dp->local_port); -err_destroy_chain: - chain_destroy(dp->chain); -err_destroy_dp_dev: - dp_dev_destroy(dp); -err_free_dp: - kfree(dp); -err_put: - module_put(THIS_MODULE); -err_unlock: - mutex_unlock(&dp_mutex); - rtnl_unlock(); - return err; -} - -/* Find and return a free port number under 'dp'. */ -static int find_portno(struct datapath *dp) -{ - int i; - for (i = 1; i < DP_MAX_PORTS; i++) - if (dp->ports[i] == NULL) - return i; - return -EXFULL; -} - -/* Called with RTNL lock and dp_mutex. */ -static struct net_bridge_port *new_nbp(struct datapath *dp, - struct net_device *dev, int port_no) -{ - struct net_bridge_port *p; - - if (dev->br_port != NULL) - return ERR_PTR(-EBUSY); - - p = kzalloc(sizeof(*p), GFP_KERNEL); - if (p == NULL) - return ERR_PTR(-ENOMEM); - - dev_set_promiscuity(dev, 1); - dev_hold(dev); - p->dp = dp; - p->dev = dev; - p->port_no = port_no; - spin_lock_init(&p->lock); - if (port_no != OFPP_LOCAL) - rcu_assign_pointer(dev->br_port, p); - if (port_no < DP_MAX_PORTS) - rcu_assign_pointer(dp->ports[port_no], p); - list_add_rcu(&p->node, &dp->port_list); - - return p; -} - -/* Called with RTNL lock and dp_mutex. */ -int add_switch_port(struct datapath *dp, struct net_device *dev) -{ - struct net_bridge_port *p; - int port_no; - - if (dev->flags & IFF_LOOPBACK || dev->type != ARPHRD_ETHER - || is_dp_dev(dev)) - return -EINVAL; - - port_no = find_portno(dp); - if (port_no < 0) - return port_no; - - p = new_nbp(dp, dev, port_no); - if (IS_ERR(p)) - return PTR_ERR(p); - - init_port_status(p); - - if (dp_add_if_hook) - dp_add_if_hook(p); - - /* Notify the ctlpath that this port has been added */ - dp_send_port_status(p, OFPPR_ADD); - - return 0; -} - -/* Delete 'p' from switch. - * Called with RTNL lock and dp_mutex. */ -int dp_del_switch_port(struct net_bridge_port *p) -{ - -#if CONFIG_SYSFS - if ((p->port_no != OFPP_LOCAL) && dp_del_if_hook) - sysfs_remove_link(&p->dp->ifobj, p->dev->name); -#endif - - /* First drop references to device. */ - dev_set_promiscuity(p->dev, -1); - list_del_rcu(&p->node); - if (p->port_no != OFPP_LOCAL) - rcu_assign_pointer(p->dp->ports[p->port_no], NULL); - rcu_assign_pointer(p->dev->br_port, NULL); - - /* Then wait until no one is still using it, and destroy it. */ - synchronize_rcu(); - - /* Notify the ctlpath that this port no longer exists */ - dp_send_port_status(p, OFPPR_DELETE); - - if ((p->port_no != OFPP_LOCAL) && dp_del_if_hook) { - dp_del_if_hook(p); - } else { - dev_put(p->dev); - kfree(p); - } - - return 0; -} - -static void del_dp(struct datapath *dp) -{ - struct net_bridge_port *p, *n; - - send_sig(SIGKILL, dp->dp_task, 0); - kthread_stop(dp->dp_task); - - /* Drop references to DP. */ - list_for_each_entry_safe (p, n, &dp->port_list, node) - dp_del_switch_port(p); - - if (dp_del_dp_hook) - dp_del_dp_hook(dp); - - rcu_assign_pointer(dps[dp->dp_idx], NULL); - - /* Kill off local_port dev references from buffered packets that have - * associated dst entries. */ - synchronize_rcu(); - fwd_discard_all(); - - /* Destroy dp->netdev. (Must follow deleting switch ports since - * dp->local_port has a reference to it.) */ - dp_dev_destroy(dp); - - /* Wait until no longer in use, then destroy it. */ - synchronize_rcu(); - chain_destroy(dp->chain); - kfree(dp); - module_put(THIS_MODULE); -} - -static int dp_maint_func(void *data) -{ - struct datapath *dp = (struct datapath *) data; - - allow_signal(SIGKILL); - while (!signal_pending(current)) { - /* Timeout old entries */ - chain_timeout(dp->chain); - msleep_interruptible(MAINT_SLEEP_MSECS); - } - while (!kthread_should_stop()) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule(); - } - return 0; -} - -static void -do_port_input(struct net_bridge_port *p, struct sk_buff *skb) -{ - /* Make our own copy of the packet. Otherwise we will mangle the - * packet for anyone who came before us (e.g. tcpdump via AF_PACKET). - * (No one comes after us, since we tell handle_bridge() that we took - * the packet.) */ - skb = skb_share_check(skb, GFP_ATOMIC); - if (!skb) - return; - - /* Push the Ethernet header back on. */ - skb_push(skb, ETH_HLEN); - skb_reset_mac_header(skb); - fwd_port_input(p->dp->chain, skb, p); -} - -/* - * Used as br_handle_frame_hook. (Cannot run bridge at the same time, even on - * different set of devices!) - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) -/* Called with rcu_read_lock. */ -static struct sk_buff *dp_frame_hook(struct net_bridge_port *p, - struct sk_buff *skb) -{ - do_port_input(p, skb); - return NULL; -} -#else -static int dp_frame_hook(struct net_bridge_port *p, struct sk_buff **pskb) -{ - do_port_input(p, *pskb); - return 1; -} -#endif - -/* Forwarding output path. - * Based on net/bridge/br_forward.c. */ - -static inline unsigned packet_length(const struct sk_buff *skb) -{ - unsigned length = skb->len - ETH_HLEN; - if (skb->protocol == htons(ETH_P_8021Q)) - length -= VLAN_HLEN; - return length; -} - -/* Send packets out all the ports except the originating one. If the - * "flood" argument is set, only send along the minimum spanning tree. - */ -static int -output_all(struct datapath *dp, struct sk_buff *skb, int flood) -{ - u32 disable = flood ? OFPPC_NO_FLOOD : 0; - struct net_bridge_port *p; - int prev_port = -1; - - list_for_each_entry_rcu (p, &dp->port_list, node) { - if (skb->dev == p->dev || p->config & disable) - continue; - if (prev_port != -1) { - struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); - if (!clone) { - kfree_skb(skb); - return -ENOMEM; - } - dp_output_port(dp, clone, prev_port, 0); - } - prev_port = p->port_no; - } - if (prev_port != -1) - dp_output_port(dp, skb, prev_port, 0); - else - kfree_skb(skb); - - return 0; -} - -/* Marks 'skb' as having originated from 'in_port' in 'dp'. - FIXME: how are devices reference counted? */ -void dp_set_origin(struct datapath *dp, uint16_t in_port, - struct sk_buff *skb) -{ - struct net_bridge_port *p; - p = (in_port < DP_MAX_PORTS ? dp->ports[in_port] - : in_port == OFPP_LOCAL ? dp->local_port - : NULL); - if (p) - skb->dev = p->dev; - else - skb->dev = NULL; -} - -int -dp_xmit_skb(struct sk_buff *skb) -{ - struct datapath *dp = skb->dev->br_port->dp; - int len = skb->len; - - if (packet_length(skb) > skb->dev->mtu && !skb_is_gso(skb)) { - printk(KERN_WARNING "%s: dropped over-mtu packet: %d > %d\n", - dp->netdev->name, packet_length(skb), skb->dev->mtu); - kfree_skb(skb); - return -E2BIG; - } - - dev_queue_xmit(skb); - - return len; -} - -/* Takes ownership of 'skb' and transmits it to 'out_port' on 'dp'. - */ -int dp_output_port(struct datapath *dp, struct sk_buff *skb, int out_port, - int ignore_no_fwd) -{ - BUG_ON(!skb); - switch (out_port){ - case OFPP_IN_PORT: - /* Send it out the port it came in on, which is already set in - * the skb. */ - if (!skb->dev) { - if (net_ratelimit()) - printk(KERN_NOTICE "%s: skb device not set " - "forwarding to in_port\n", - dp->netdev->name); - kfree_skb(skb); - return -ESRCH; - } - return dp_xmit_skb(skb); - - case OFPP_TABLE: { - int retval = run_flow_through_tables(dp->chain, skb, - skb->dev->br_port); - if (retval) - kfree_skb(skb); - return retval; - } - - case OFPP_FLOOD: - return output_all(dp, skb, 1); - - case OFPP_ALL: - return output_all(dp, skb, 0); - - case OFPP_CONTROLLER: - return dp_output_control(dp, skb, UINT16_MAX, OFPR_ACTION); - - case OFPP_LOCAL: { - struct net_device *dev = dp->netdev; - return dev ? dp_dev_recv(dev, skb) : -ESRCH; - } - - case 0 ... DP_MAX_PORTS - 1: { - struct net_bridge_port *p = dp->ports[out_port]; - if (p == NULL) - goto bad_port; - if (p->dev == skb->dev) { - /* To send to the input port, must use OFPP_IN_PORT */ - kfree_skb(skb); - if (net_ratelimit()) - printk(KERN_NOTICE "%s: can't directly " - "forward to input port\n", - dp->netdev->name); - return -EINVAL; - } - if (p->config & OFPPC_NO_FWD && !ignore_no_fwd) { - kfree_skb(skb); - return 0; - } - skb->dev = p->dev; - return dp_xmit_skb(skb); - } - - default: - goto bad_port; - } - -bad_port: - kfree_skb(skb); - if (net_ratelimit()) - printk(KERN_NOTICE "%s: can't forward to bad port %d\n", - dp->netdev->name, out_port); - return -ENOENT; -} - -/* Takes ownership of 'skb' and transmits it to 'dp''s control path. 'reason' - * indicates why 'skb' is being sent. 'max_len' sets the maximum number of - * bytes that the caller wants to be sent. - */ -int -dp_output_control(struct datapath *dp, struct sk_buff *skb, - size_t max_len, int reason) -{ - /* FIXME? Can we avoid creating a new skbuff in the case where we - * forward the whole packet? */ - struct sk_buff *f_skb; - struct ofp_packet_in *opi; - size_t fwd_len, opi_len; - uint32_t buffer_id; - int err; - - WARN_ON_ONCE(skb_shared(skb)); - - buffer_id = fwd_save_skb(skb); - - fwd_len = skb->len; - if (buffer_id != (uint32_t) -1) - fwd_len = min(fwd_len, max_len); - - opi_len = offsetof(struct ofp_packet_in, data) + fwd_len; - opi = alloc_openflow_skb(dp, opi_len, OFPT_PACKET_IN, NULL, &f_skb); - if (!opi) { - err = -ENOMEM; - goto out; - } - opi->buffer_id = htonl(buffer_id); - opi->total_len = htons(skb->len); - opi->in_port = htons(skb->dev && skb->dev->br_port - ? skb->dev->br_port->port_no - : OFPP_LOCAL); - opi->reason = reason; - opi->pad = 0; - skb_copy_bits(skb, 0, opi->data, fwd_len); - err = send_openflow_skb(dp, f_skb, NULL); - -out: - kfree_skb(skb); - return err; -} - -static void fill_port_desc(struct net_bridge_port *p, struct ofp_phy_port *desc) -{ - unsigned long flags; - desc->port_no = htons(p->port_no); - strncpy(desc->name, p->dev->name, OFP_MAX_PORT_NAME_LEN); - desc->name[OFP_MAX_PORT_NAME_LEN-1] = '\0'; - memcpy(desc->hw_addr, p->dev->dev_addr, ETH_ALEN); - desc->curr = 0; - desc->supported = 0; - desc->advertised = 0; - desc->peer = 0; - - spin_lock_irqsave(&p->lock, flags); - desc->config = htonl(p->config); - desc->state = htonl(p->state); - spin_unlock_irqrestore(&p->lock, flags); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,24) - if (p->dev->ethtool_ops && p->dev->ethtool_ops->get_settings) { - struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; - - if (!p->dev->ethtool_ops->get_settings(p->dev, &ecmd)) { - /* Set the supported features */ - if (ecmd.supported & SUPPORTED_10baseT_Half) - desc->supported |= OFPPF_10MB_HD; - if (ecmd.supported & SUPPORTED_10baseT_Full) - desc->supported |= OFPPF_10MB_FD; - if (ecmd.supported & SUPPORTED_100baseT_Half) - desc->supported |= OFPPF_100MB_HD; - if (ecmd.supported & SUPPORTED_100baseT_Full) - desc->supported |= OFPPF_100MB_FD; - if (ecmd.supported & SUPPORTED_1000baseT_Half) - desc->supported |= OFPPF_1GB_HD; - if (ecmd.supported & SUPPORTED_1000baseT_Full) - desc->supported |= OFPPF_1GB_FD; - if (ecmd.supported & SUPPORTED_10000baseT_Full) - desc->supported |= OFPPF_10GB_FD; - if (ecmd.supported & SUPPORTED_TP) - desc->supported |= OFPPF_COPPER; - if (ecmd.supported & SUPPORTED_FIBRE) - desc->supported |= OFPPF_FIBER; - if (ecmd.supported & SUPPORTED_Autoneg) - desc->supported |= OFPPF_AUTONEG; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14) - if (ecmd.supported & SUPPORTED_Pause) - desc->supported |= OFPPF_PAUSE; - if (ecmd.supported & SUPPORTED_Asym_Pause) - desc->supported |= OFPPF_PAUSE_ASYM; -#endif /* kernel >= 2.6.14 */ - - /* Set the advertised features */ - if (ecmd.advertising & ADVERTISED_10baseT_Half) - desc->advertised |= OFPPF_10MB_HD; - if (ecmd.advertising & ADVERTISED_10baseT_Full) - desc->advertised |= OFPPF_10MB_FD; - if (ecmd.advertising & ADVERTISED_100baseT_Half) - desc->advertised |= OFPPF_100MB_HD; - if (ecmd.advertising & ADVERTISED_100baseT_Full) - desc->advertised |= OFPPF_100MB_FD; - if (ecmd.advertising & ADVERTISED_1000baseT_Half) - desc->advertised |= OFPPF_1GB_HD; - if (ecmd.advertising & ADVERTISED_1000baseT_Full) - desc->advertised |= OFPPF_1GB_FD; - if (ecmd.advertising & ADVERTISED_10000baseT_Full) - desc->advertised |= OFPPF_10GB_FD; - if (ecmd.advertising & ADVERTISED_TP) - desc->advertised |= OFPPF_COPPER; - if (ecmd.advertising & ADVERTISED_FIBRE) - desc->advertised |= OFPPF_FIBER; - if (ecmd.advertising & ADVERTISED_Autoneg) - desc->advertised |= OFPPF_AUTONEG; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14) - if (ecmd.advertising & ADVERTISED_Pause) - desc->advertised |= OFPPF_PAUSE; - if (ecmd.advertising & ADVERTISED_Asym_Pause) - desc->advertised |= OFPPF_PAUSE_ASYM; -#endif /* kernel >= 2.6.14 */ - - /* Set the current features */ - if (ecmd.speed == SPEED_10) - desc->curr = (ecmd.duplex) ? OFPPF_10MB_FD : OFPPF_10MB_HD; - else if (ecmd.speed == SPEED_100) - desc->curr = (ecmd.duplex) ? OFPPF_100MB_FD : OFPPF_100MB_HD; - else if (ecmd.speed == SPEED_1000) - desc->curr = (ecmd.duplex) ? OFPPF_1GB_FD : OFPPF_1GB_HD; - else if (ecmd.speed == SPEED_10000) - desc->curr = OFPPF_10GB_FD; - - if (ecmd.port == PORT_TP) - desc->curr |= OFPPF_COPPER; - else if (ecmd.port == PORT_FIBRE) - desc->curr |= OFPPF_FIBER; - - if (ecmd.autoneg) - desc->curr |= OFPPF_AUTONEG; - } - } -#endif - desc->curr = htonl(desc->curr); - desc->supported = htonl(desc->supported); - desc->advertised = htonl(desc->advertised); - desc->peer = htonl(desc->peer); -} - -static int -fill_features_reply(struct datapath *dp, struct ofp_switch_features *ofr) -{ - struct net_bridge_port *p; - uint64_t dpid = get_datapath_id(dp->netdev); - int port_count = 0; - - ofr->datapath_id = cpu_to_be64(dpid); - - ofr->n_buffers = htonl(N_PKT_BUFFERS); - ofr->n_tables = dp->chain->n_tables; - ofr->capabilities = htonl(OFP_SUPPORTED_CAPABILITIES); - ofr->actions = htonl(OFP_SUPPORTED_ACTIONS); - memset(ofr->pad, 0, sizeof ofr->pad); - - list_for_each_entry_rcu (p, &dp->port_list, node) { - fill_port_desc(p, &ofr->ports[port_count]); - port_count++; - } - - return port_count; -} - -int -dp_send_features_reply(struct datapath *dp, const struct sender *sender) -{ - struct sk_buff *skb; - struct ofp_switch_features *ofr; - size_t ofr_len, port_max_len; - int port_count; - - /* Overallocate. */ - port_max_len = sizeof(struct ofp_phy_port) * DP_MAX_PORTS; - ofr = alloc_openflow_skb(dp, sizeof(*ofr) + port_max_len, - OFPT_FEATURES_REPLY, sender, &skb); - if (!ofr) - return -ENOMEM; - - /* Fill. */ - port_count = fill_features_reply(dp, ofr); - - /* Shrink to fit. */ - ofr_len = sizeof(*ofr) + (sizeof(struct ofp_phy_port) * port_count); - resize_openflow_skb(skb, &ofr->header, ofr_len); - return send_openflow_skb(dp, skb, sender); -} - -int -dp_send_config_reply(struct datapath *dp, const struct sender *sender) -{ - struct sk_buff *skb; - struct ofp_switch_config *osc; - - osc = alloc_openflow_skb(dp, sizeof *osc, OFPT_GET_CONFIG_REPLY, sender, - &skb); - if (!osc) - return -ENOMEM; - - osc->flags = htons(dp->flags); - osc->miss_send_len = htons(dp->miss_send_len); - - return send_openflow_skb(dp, skb, sender); -} - -int -dp_send_hello(struct datapath *dp, const struct sender *sender, - const struct ofp_header *request) -{ - if (request->version < OFP_VERSION) { - char err[64]; - sprintf(err, "Only version 0x%02x supported", OFP_VERSION); - dp_send_error_msg(dp, sender, OFPET_HELLO_FAILED, - OFPHFC_INCOMPATIBLE, err, strlen(err)); - return -EINVAL; - } else { - struct sk_buff *skb; - struct ofp_header *reply; - - reply = alloc_openflow_skb(dp, sizeof *reply, - OFPT_HELLO, sender, &skb); - if (!reply) - return -ENOMEM; - - return send_openflow_skb(dp, skb, sender); - } -} - -int -dp_send_barrier_reply(struct datapath *dp, const struct sender *sender, - const struct ofp_header *request) -{ - struct sk_buff *skb; - struct ofp_header *reply; - - reply = alloc_openflow_skb(dp, sizeof *reply, - OFPT_BARRIER_REPLY, sender, &skb); - if (!reply) - return -ENOMEM; - - return send_openflow_skb(dp, skb, sender); -} - -int -dp_update_port_flags(struct datapath *dp, const struct ofp_port_mod *opm) -{ - unsigned long int flags; - int port_no = ntohs(opm->port_no); - struct net_bridge_port *p; - p = (port_no < DP_MAX_PORTS ? dp->ports[port_no] - : port_no == OFPP_LOCAL ? dp->local_port - : NULL); - - /* Make sure the port id hasn't changed since this was sent */ - if (!p || memcmp(opm->hw_addr, p->dev->dev_addr, ETH_ALEN)) - return -1; - - spin_lock_irqsave(&p->lock, flags); - if (opm->mask) { - uint32_t config_mask = ntohl(opm->mask); - p->config &= ~config_mask; - p->config |= ntohl(opm->config) & config_mask; - } - spin_unlock_irqrestore(&p->lock, flags); - - return 0; -} - -/* Initialize the port status field of the bridge port. */ -static void -init_port_status(struct net_bridge_port *p) -{ - unsigned long int flags; - - spin_lock_irqsave(&p->lock, flags); - - if (p->dev->flags & IFF_UP) - p->config &= ~OFPPC_PORT_DOWN; - else - p->config |= OFPPC_PORT_DOWN; - - if (netif_carrier_ok(p->dev)) - p->state &= ~OFPPS_LINK_DOWN; - else - p->state |= OFPPS_LINK_DOWN; - - spin_unlock_irqrestore(&p->lock, flags); -} - -int -dp_send_port_status(struct net_bridge_port *p, uint8_t status) -{ - struct sk_buff *skb; - struct ofp_port_status *ops; - - ops = alloc_openflow_skb(p->dp, sizeof *ops, OFPT_PORT_STATUS, NULL, - &skb); - if (!ops) - return -ENOMEM; - ops->reason = status; - memset(ops->pad, 0, sizeof ops->pad); - fill_port_desc(p, &ops->desc); - - return send_openflow_skb(p->dp, skb, NULL); -} - -/* Convert jiffies_64 to seconds. */ -static u32 inline jiffies_64_to_secs(u64 j) -{ - /* Call to do_div is necessary as we can't do a 64-bit division in a - * 32-bit kernel (at least not without linking to libgcc) */ - do_div(j, HZ); - return j; -} - -/* Convert jiffies_64 to just the nanosec part between seconds. */ -static u32 inline jiffies_64_to_nsecs(u64 j) -{ - /* Call to do_div is necessary as we can't do a 64-bit division in a - * 32-bit kernel (at least not without linking to libgcc) */ - return (j - jiffies_64_to_secs(j)); -} - -int -dp_send_flow_end(struct datapath *dp, struct sw_flow *flow, - enum ofp_flow_removed_reason reason) -{ - struct sk_buff *skb; - struct ofp_flow_removed *ofr; - - if (!flow->send_flow_rem) - return 0; - - if (flow->emerg_flow) - return 0; - - ofr = alloc_openflow_skb(dp, sizeof *ofr, OFPT_FLOW_REMOVED, 0, &skb); - if (!ofr) - return -ENOMEM; - - flow_fill_match(&ofr->match, &flow->key); - - ofr->priority = htons(flow->priority); - ofr->reason = reason; - - ofr->duration_sec = htonl(jiffies_64_to_secs(get_jiffies_64()-flow->created)); - ofr->duration_nsec = htonl(jiffies_64_to_nsecs(get_jiffies_64()-flow->created)); - ofr->idle_timeout = htons(flow->idle_timeout); - - ofr->packet_count = cpu_to_be64(flow->packet_count); - ofr->byte_count = cpu_to_be64(flow->byte_count); - - return send_openflow_skb(dp, skb, NULL); -} -EXPORT_SYMBOL(dp_send_flow_end); - -int -dp_send_error_msg(struct datapath *dp, const struct sender *sender, - uint16_t type, uint16_t code, const void *data, size_t len) -{ - struct sk_buff *skb; - struct ofp_error_msg *oem; - - - oem = alloc_openflow_skb(dp, sizeof(*oem)+len, OFPT_ERROR, - sender, &skb); - if (!oem) - return -ENOMEM; - - oem->type = htons(type); - oem->code = htons(code); - memcpy(oem->data, data, len); - - return send_openflow_skb(dp, skb, sender); -} - -int -dp_send_echo_reply(struct datapath *dp, const struct sender *sender, - const struct ofp_header *rq) -{ - struct sk_buff *skb; - struct ofp_header *reply; - - reply = alloc_openflow_skb(dp, ntohs(rq->length), OFPT_ECHO_REPLY, - sender, &skb); - if (!reply) - return -ENOMEM; - - memcpy(reply + 1, rq + 1, ntohs(rq->length) - sizeof *rq); - return send_openflow_skb(dp, skb, sender); -} - -/* Generic Netlink interface. - * - * See netlink(7) for an introduction to netlink. See - * http://linux-net.osdl.org/index.php/Netlink for more information and - * pointers on how to work with netlink and Generic Netlink in the kernel and - * in userspace. */ - -static struct genl_family dp_genl_family = { - .id = GENL_ID_GENERATE, - .hdrsize = 0, - .name = DP_GENL_FAMILY_NAME, - .version = 1, - .maxattr = DP_GENL_A_MAX, -}; - -/* Attribute policy: what each attribute may contain. */ -static struct nla_policy dp_genl_policy[DP_GENL_A_MAX + 1] = { - [DP_GENL_A_DP_IDX] = { .type = NLA_U32 }, - [DP_GENL_A_DP_NAME] = { .type = NLA_NUL_STRING }, - [DP_GENL_A_MC_GROUP] = { .type = NLA_U32 }, - [DP_GENL_A_PORTNAME] = { .type = NLA_NUL_STRING } -}; - -static int dp_genl_add(struct sk_buff *skb, struct genl_info *info) -{ - int dp_idx = info->attrs[DP_GENL_A_DP_IDX] ? - nla_get_u32(info->attrs[DP_GENL_A_DP_IDX]) : -1; - const char *dp_name = info->attrs[DP_GENL_A_DP_NAME] ? - nla_data(info->attrs[DP_GENL_A_DP_NAME]) : NULL; - - if (VERIFY_NUL_STRING(info->attrs[DP_GENL_A_DP_NAME])) - return -EINVAL; - - if ((dp_idx == -1) && (!dp_name)) - return -EINVAL; - - return new_dp(dp_idx, dp_name); -} - -static struct genl_ops dp_genl_ops_add_dp = { - .cmd = DP_GENL_C_ADD_DP, - .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ - .policy = dp_genl_policy, - .doit = dp_genl_add, - .dumpit = NULL, -}; - -/* Must be called with rcu_read_lock or dp_mutex. */ -struct datapath *dp_get_by_idx(int dp_idx) -{ - if (dp_idx < 0 || dp_idx >= DP_MAX) - return NULL; - return rcu_dereference(dps[dp_idx]); -} -EXPORT_SYMBOL(dp_get_by_idx); - -/* Must be called with rcu_read_lock or dp_mutex. */ -struct datapath *dp_get_by_name(const char *dp_name) -{ - int i; - for (i=0; inetdev->name, dp_name)) - return dp; - } - return NULL; -} - -/* Must be called with rcu_read_lock or dp_mutex. */ -static struct datapath * -lookup_dp(struct genl_info *info) -{ - int dp_idx = info->attrs[DP_GENL_A_DP_IDX] ? - nla_get_u32(info->attrs[DP_GENL_A_DP_IDX]) : -1; - const char *dp_name = info->attrs[DP_GENL_A_DP_NAME] ? - nla_data(info->attrs[DP_GENL_A_DP_NAME]) : NULL; - - if (VERIFY_NUL_STRING(info->attrs[DP_GENL_A_DP_NAME])) - return ERR_PTR(-EINVAL); - - if (dp_idx != -1) { - struct datapath *dp = dp_get_by_idx(dp_idx); - if (!dp) - return ERR_PTR(-ENOENT); - else if (dp_name && strcmp(dp->netdev->name, dp_name)) - return ERR_PTR(-EINVAL); - else - return dp; - } else if (dp_name) { - struct datapath *dp = dp_get_by_name(dp_name); - return dp ? dp : ERR_PTR(-ENOENT); - } else { - return ERR_PTR(-EINVAL); - } -} - -static int dp_genl_del(struct sk_buff *skb, struct genl_info *info) -{ - struct net_device *dev = NULL; - struct datapath *dp; - int err; - - rtnl_lock(); - mutex_lock(&dp_mutex); - dp = lookup_dp(info); - if (IS_ERR(dp)) - err = PTR_ERR(dp); - else { - dev = dp->netdev; - del_dp(dp); - err = 0; - } - mutex_unlock(&dp_mutex); - rtnl_unlock(); - if (dev) - free_netdev(dev); - return err; -} - -static struct genl_ops dp_genl_ops_del_dp = { - .cmd = DP_GENL_C_DEL_DP, - .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ - .policy = dp_genl_policy, - .doit = dp_genl_del, - .dumpit = NULL, -}; - -/* Queries a datapath for related information. Currently the only relevant - * information is the datapath's multicast group ID, datapath ID, and - * datapath device name. */ -static int dp_genl_query(struct sk_buff *skb, struct genl_info *info) -{ - struct datapath *dp; - struct sk_buff *ans_skb = NULL; - int err; - - rcu_read_lock(); - dp = lookup_dp(info); - if (IS_ERR(dp)) - err = PTR_ERR(dp); - else { - void *data; - ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); - if (!ans_skb) { - err = -ENOMEM; - goto err; - } - err = -ENOMEM; - data = genlmsg_put_reply(ans_skb, info, &dp_genl_family, - 0, DP_GENL_C_QUERY_DP); - if (data == NULL) - goto err; - NLA_PUT_U32(ans_skb, DP_GENL_A_DP_IDX, dp->dp_idx); - NLA_PUT_STRING(ans_skb, DP_GENL_A_DP_NAME, dp->netdev->name); - NLA_PUT_U32(ans_skb, DP_GENL_A_MC_GROUP, dp_mc_group(dp)); - - genlmsg_end(ans_skb, data); - err = genlmsg_reply(ans_skb, info); - ans_skb = NULL; - } -err: -nla_put_failure: - kfree_skb(ans_skb); - rcu_read_unlock(); - return err; -} - -static struct genl_ops dp_genl_ops_query_dp = { - .cmd = DP_GENL_C_QUERY_DP, - .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ - .policy = dp_genl_policy, - .doit = dp_genl_query, - .dumpit = NULL, -}; - -static int dp_genl_add_del_port(struct sk_buff *skb, struct genl_info *info) -{ - struct datapath *dp; - struct net_device *port; - int err; - - if (!info->attrs[DP_GENL_A_PORTNAME] || - VERIFY_NUL_STRING(info->attrs[DP_GENL_A_PORTNAME])) - return -EINVAL; - - rtnl_lock(); - mutex_lock(&dp_mutex); - - /* Get datapath. */ - dp = lookup_dp(info); - if (IS_ERR(dp)) { - err = PTR_ERR(dp); - goto out_unlock; - } - - /* Get interface to add/remove. */ - port = dev_get_by_name(&init_net, - nla_data(info->attrs[DP_GENL_A_PORTNAME])); - if (!port) { - err = -ENOENT; - goto out_unlock; - } - - /* Execute operation. */ - if (info->genlhdr->cmd == DP_GENL_C_ADD_PORT) - err = add_switch_port(dp, port); - else { - if (port->br_port == NULL || port->br_port->dp != dp) { - err = -ENOENT; - goto out_put; - } - err = dp_del_switch_port(port->br_port); - } - -out_put: - dev_put(port); -out_unlock: - mutex_unlock(&dp_mutex); - rtnl_unlock(); - return err; -} - -static struct genl_ops dp_genl_ops_add_port = { - .cmd = DP_GENL_C_ADD_PORT, - .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ - .policy = dp_genl_policy, - .doit = dp_genl_add_del_port, - .dumpit = NULL, -}; - -static struct genl_ops dp_genl_ops_del_port = { - .cmd = DP_GENL_C_DEL_PORT, - .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ - .policy = dp_genl_policy, - .doit = dp_genl_add_del_port, - .dumpit = NULL, -}; - -static int dp_genl_openflow(struct sk_buff *skb, struct genl_info *info) -{ - struct nlattr *va = info->attrs[DP_GENL_A_OPENFLOW]; - struct datapath *dp; - struct ofp_header *oh; - struct sender sender; - int err; - - if (!info->attrs[DP_GENL_A_DP_IDX] || !va) - return -EINVAL; - - dp = dp_get_by_idx(nla_get_u32(info->attrs[DP_GENL_A_DP_IDX])); - if (!dp) - return -ENOENT; - - if (nla_len(va) < sizeof(struct ofp_header)) - return -EINVAL; - oh = nla_data(va); - - sender.xid = oh->xid; - sender.pid = info->snd_pid; - sender.seq = info->snd_seq; - - mutex_lock(&dp_mutex); - err = fwd_control_input(dp->chain, &sender, - nla_data(va), nla_len(va)); - mutex_unlock(&dp_mutex); - return err; -} - -static struct nla_policy dp_genl_openflow_policy[DP_GENL_A_MAX + 1] = { - [DP_GENL_A_DP_IDX] = { .type = NLA_U32 }, -}; - -static int desc_stats_dump(struct datapath *dp, void *state, - void *body, int *body_len) -{ - struct ofp_desc_stats *ods = body; - int n_bytes = sizeof *ods; - - if (n_bytes > *body_len) { - return -ENOBUFS; - } - *body_len = n_bytes; - - strncpy(ods->mfr_desc, mfr_desc, sizeof ods->mfr_desc); - strncpy(ods->hw_desc, hw_desc, sizeof ods->hw_desc); - strncpy(ods->sw_desc, sw_desc, sizeof ods->sw_desc); - strncpy(ods->dp_desc, dp->dp_desc, sizeof ods->dp_desc); - strncpy(ods->serial_num, serial_num, sizeof ods->serial_num); - - return 0; -} - -struct flow_stats_state { - int table_idx; - struct sw_table_position position; - const struct ofp_flow_stats_request *rq; - - void *body; - int bytes_used, bytes_allocated; -}; - -#define EMERG_TABLE_ID_FOR_STATS 0xfe - -static int flow_stats_init(struct datapath *dp, const void *body, int body_len, - void **state) -{ - const struct ofp_flow_stats_request *fsr = body; - struct flow_stats_state *s = kmalloc(sizeof *s, GFP_ATOMIC); - if (!s) - return -ENOMEM; - s->table_idx = fsr->table_id == 0xff ? 0 : fsr->table_id; - memset(&s->position, 0, sizeof s->position); - s->rq = fsr; - *state = s; - return 0; -} - -static int flow_stats_dump_callback(struct sw_flow *flow, void *private) -{ - struct sw_flow_actions *sf_acts = rcu_dereference(flow->sf_acts); - struct flow_stats_state *s = private; - struct ofp_flow_stats *ofs; - int length; - uint64_t duration; - - length = sizeof *ofs + sf_acts->actions_len; - if (length + s->bytes_used > s->bytes_allocated) - return 1; - - ofs = s->body + s->bytes_used; - ofs->length = htons(length); - ofs->table_id = s->table_idx; - ofs->pad = 0; - ofs->match.wildcards = htonl(flow->key.wildcards); - ofs->match.in_port = flow->key.in_port; - memcpy(ofs->match.dl_src, flow->key.dl_src, ETH_ALEN); - memcpy(ofs->match.dl_dst, flow->key.dl_dst, ETH_ALEN); - ofs->match.dl_vlan = flow->key.dl_vlan; - ofs->match.dl_type = flow->key.dl_type; - ofs->match.nw_tos = flow->key.nw_tos; - ofs->match.nw_proto = flow->key.nw_proto; - ofs->match.nw_src = flow->key.nw_src; - ofs->match.nw_dst = flow->key.nw_dst; - ofs->match.dl_vlan_pcp = flow->key.dl_vlan_pcp; - ofs->match.tp_src = flow->key.tp_src; - ofs->match.tp_dst = flow->key.tp_dst; - - /* The kernel doesn't support 64-bit division, so use the 'do_div' - * macro instead. The first argument is replaced with the quotient, - * while the remainder is the return value. */ - duration = get_jiffies_64() - flow->created; - do_div(duration, HZ); - ofs->duration_sec = htonl(jiffies_64_to_secs(duration)); - ofs->duration_nsec = htonl(jiffies_64_to_nsecs(duration)); - - ofs->priority = htons(flow->priority); - ofs->idle_timeout = htons(flow->idle_timeout); - ofs->hard_timeout = htons(flow->hard_timeout); - memset(&ofs->pad2, 0, sizeof ofs->pad2); - ofs->packet_count = cpu_to_be64(flow->packet_count); - ofs->byte_count = cpu_to_be64(flow->byte_count); - memcpy(ofs->actions, sf_acts->actions, sf_acts->actions_len); - - s->bytes_used += length; - return 0; -} - -static int flow_stats_dump(struct datapath *dp, void *state, - void *body, int *body_len) -{ - struct flow_stats_state *s = state; - struct sw_flow_key match_key; - int error = 0; - - s->bytes_used = 0; - s->bytes_allocated = *body_len; - s->body = body; - - flow_extract_match(&match_key, &s->rq->match); - if (s->rq->table_id == EMERG_TABLE_ID_FOR_STATS) { - struct sw_table *table = dp->chain->emerg_table; - - error = table->iterate(table, &match_key, s->rq->out_port, - &s->position, flow_stats_dump_callback, - s); - } else { - while (s->table_idx < dp->chain->n_tables - && (s->rq->table_id == 0xff - || s->rq->table_id == s->table_idx)) { - struct sw_table *table = dp->chain->tables[s->table_idx]; - - error = table->iterate(table, &match_key, - s->rq->out_port, &s->position, - flow_stats_dump_callback, s); - if (error) - break; - - s->table_idx++; - memset(&s->position, 0, sizeof s->position); - } - } - *body_len = s->bytes_used; - - /* If error is 0, we're done. - * Otherwise, if some bytes were used, there are more flows to come. - * Otherwise, we were not able to fit even a single flow in the body, - * which indicates that we have a single flow with too many actions to - * fit. We won't ever make any progress at that rate, so give up. */ - return !error ? 0 : s->bytes_used ? 1 : -ENOMEM; -} - -static void flow_stats_done(void *state) -{ - kfree(state); -} - -static int aggregate_stats_init(struct datapath *dp, - const void *body, int body_len, - void **state) -{ - *state = (void *)body; - return 0; -} - -static int aggregate_stats_dump_callback(struct sw_flow *flow, void *private) -{ - struct ofp_aggregate_stats_reply *rpy = private; - rpy->packet_count += flow->packet_count; - rpy->byte_count += flow->byte_count; - rpy->flow_count++; - return 0; -} - -static int aggregate_stats_dump(struct datapath *dp, void *state, - void *body, int *body_len) -{ - struct ofp_aggregate_stats_request *rq = state; - struct ofp_aggregate_stats_reply *rpy; - struct sw_table_position position; - struct sw_flow_key match_key; - int table_idx; - int error = 0; - - if (*body_len < sizeof *rpy) - return -ENOBUFS; - rpy = body; - *body_len = sizeof *rpy; - - memset(rpy, 0, sizeof *rpy); - - flow_extract_match(&match_key, &rq->match); - table_idx = rq->table_id == 0xff ? 0 : rq->table_id; - memset(&position, 0, sizeof position); - - if (rq->table_id == EMERG_TABLE_ID_FOR_STATS) { - struct sw_table *table = dp->chain->emerg_table; - - error = table->iterate(table, &match_key, rq->out_port, - &position, - aggregate_stats_dump_callback, rpy); - if (error) - return error; - } else { - while (table_idx < dp->chain->n_tables - && (rq->table_id == 0xff || rq->table_id == table_idx)) { - struct sw_table *table = dp->chain->tables[table_idx]; - - error = table->iterate(table, &match_key, rq->out_port, - &position, - aggregate_stats_dump_callback, - rpy); - if (error) - return error; - - table_idx++; - memset(&position, 0, sizeof position); - } - } - - rpy->packet_count = cpu_to_be64(rpy->packet_count); - rpy->byte_count = cpu_to_be64(rpy->byte_count); - rpy->flow_count = htonl(rpy->flow_count); - return 0; -} - -static int table_stats_dump(struct datapath *dp, void *state, - void *body, int *body_len) -{ - struct ofp_table_stats *ots; - int n_bytes = dp->chain->n_tables * sizeof *ots; - int i; - if (n_bytes > *body_len) - return -ENOBUFS; - *body_len = n_bytes; - for (i = 0, ots = body; i < dp->chain->n_tables; i++, ots++) { - struct sw_table_stats stats; - dp->chain->tables[i]->stats(dp->chain->tables[i], &stats); - strncpy(ots->name, stats.name, sizeof ots->name); - ots->table_id = i; - ots->wildcards = htonl(stats.wildcards); - memset(ots->pad, 0, sizeof ots->pad); - ots->max_entries = htonl(stats.max_flows); - ots->active_count = htonl(stats.n_flows); - ots->lookup_count = cpu_to_be64(stats.n_lookup); - ots->matched_count = cpu_to_be64(stats.n_matched); - } - return 0; -} - -struct port_stats_state { - int start_port; /* port to start dumping from */ - int port_no; /* from ofp_port_stats_request */ -}; - -static int port_stats_init(struct datapath *dp, const void *body, int body_len, - void **state) -{ - struct port_stats_state *s = kmalloc(sizeof *s, GFP_ATOMIC); - struct ofp_port_stats_request *psr - = (struct ofp_port_stats_request *)body; - - if (!s) - return -ENOMEM; - s->start_port = 1; - s->port_no = ntohs(psr->port_no); - *state = s; - return 0; -} - -static void -dump_port_stats(struct ofp_port_stats *ops, struct net_bridge_port *p) -{ - struct net_device_stats *stats; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) - stats = p->dev->netdev_ops->ndo_get_stats(p->dev); -#else - stats = p->dev->get_stats(p->dev); -#endif - ops->port_no = htons(p->port_no); - memset(ops->pad, 0, sizeof ops->pad); - ops->rx_packets = cpu_to_be64(stats->rx_packets); - ops->tx_packets = cpu_to_be64(stats->tx_packets); - ops->rx_bytes = cpu_to_be64(stats->rx_bytes); - ops->tx_bytes = cpu_to_be64(stats->tx_bytes); - ops->rx_dropped = cpu_to_be64(stats->rx_dropped); - ops->tx_dropped = cpu_to_be64(stats->tx_dropped); - ops->rx_errors = cpu_to_be64(stats->rx_errors); - ops->tx_errors = cpu_to_be64(stats->tx_errors); - ops->rx_frame_err = cpu_to_be64(stats->rx_frame_errors); - ops->rx_over_err = cpu_to_be64(stats->rx_over_errors); - ops->rx_crc_err = cpu_to_be64(stats->rx_crc_errors); - ops->collisions = cpu_to_be64(stats->collisions); -} - -static struct net_bridge_port * -lookup_port(struct datapath *dp, uint16_t port_no) -{ - return (port_no < DP_MAX_PORTS ? dp->ports[port_no] - : port_no == OFPP_LOCAL ? dp->local_port - : NULL); -} - - -static int port_stats_dump(struct datapath *dp, void *state, - void *body, int *body_len) -{ - struct port_stats_state *s = state; - struct net_bridge_port *p = NULL; - struct ofp_port_stats *ops = NULL; - int n_ports = 0; - int max_ports = 0; - int i = 0; - - max_ports = *body_len / sizeof *ops; - if (!max_ports) - return -ENOMEM; - ops = body; - - if (s->port_no == OFPP_NONE) { - for (i = s->start_port; i < DP_MAX_PORTS && n_ports < max_ports; - i++) { - p = dp->ports[i]; - if (!p) - continue; - dump_port_stats(ops, p); - n_ports++; - ops++; - } - s->start_port = i; - if (dp->local_port) { - dump_port_stats(ops, dp->local_port); - n_ports++; - ops++; - s->start_port = OFPP_LOCAL + 1; /* == OFPP_NONE, > DP_MAX_PORTS */ - } - } else { - p = lookup_port(dp, s->port_no); - if (p) { - dump_port_stats(ops, p); - n_ports++; - ops++; - } - } - - *body_len = n_ports * sizeof *ops; - return n_ports >= max_ports; -} - -static void port_stats_done(void *state) -{ - kfree(state); -} - -/* - * We don't define any vendor_stats_state, we let the actual - * vendor implementation do that. - * The only requirement is that the first member of that object - * should be the vendor id. - * Jean II - * - * Basically, it would look like : - * struct acme_stats_state { - * uint32_t vendor; // ACME_VENDOR_ID. - * <...> // Other stuff. - * }; - */ -static int vendor_stats_init(struct datapath *dp, const void *body, - int body_len, void **state) -{ - /* min_body was checked, this is safe */ - const uint32_t vendor = ntohl(*((uint32_t *)body)); - int err; - - switch (vendor) { - default: - err = -EINVAL; - } - - return err; -} - -static int vendor_stats_dump(struct datapath *dp, void *state, void *body, - int *body_len) -{ - const uint32_t vendor = *((uint32_t *)state); - int newbuf; - - switch (vendor) { - default: - /* Should never happen */ - newbuf = 0; - } - - return newbuf; -} - -static void vendor_stats_done(void *state) -{ - const uint32_t vendor = *((uint32_t *)state); - - switch (vendor) { - default: - /* Should never happen */ - kfree(state); - } - - return; -} - -struct stats_type { - /* Minimum and maximum acceptable number of bytes in body member of - * struct ofp_stats_request. */ - size_t min_body, max_body; - - /* Prepares to dump some kind of statistics on 'dp'. 'body' and - * 'body_len' are the 'body' member of the struct ofp_stats_request. - * Returns zero if successful, otherwise a negative error code. - * May initialize '*state' to state information. May be null if no - * initialization is required.*/ - int (*init)(struct datapath *dp, const void *body, int body_len, - void **state); - - /* Dumps statistics for 'dp' into the '*body_len' bytes at 'body', and - * modifies '*body_len' to reflect the number of bytes actually used. - * ('body' will be transmitted as the 'body' member of struct - * ofp_stats_reply.) */ - int (*dump)(struct datapath *dp, void *state, - void *body, int *body_len); - - /* Cleans any state created by the init or dump functions. May be null - * if no cleanup is required. */ - void (*done)(void *state); -}; - -static const struct stats_type stats[] = { - [OFPST_DESC] = { - 0, - 0, - NULL, - desc_stats_dump, - NULL - }, - [OFPST_FLOW] = { - sizeof(struct ofp_flow_stats_request), - sizeof(struct ofp_flow_stats_request), - flow_stats_init, - flow_stats_dump, - flow_stats_done - }, - [OFPST_AGGREGATE] = { - sizeof(struct ofp_aggregate_stats_request), - sizeof(struct ofp_aggregate_stats_request), - aggregate_stats_init, - aggregate_stats_dump, - NULL - }, - [OFPST_TABLE] = { - 0, - 0, - NULL, - table_stats_dump, - NULL - }, - [OFPST_PORT] = { - sizeof(struct ofp_port_stats_request), - sizeof(struct ofp_port_stats_request), - port_stats_init, - port_stats_dump, - port_stats_done - }, -}; - -/* For OFPST_VENDOR... Jean II */ -static const struct stats_type stats_vendor = { - 8, /* vendor + subtype */ - 32, /* whatever */ - vendor_stats_init, - vendor_stats_dump, - vendor_stats_done -}; - -static int -dp_genl_openflow_dumpit(struct sk_buff *skb, struct netlink_callback *cb) -{ - struct datapath *dp; - struct sender sender; - const struct stats_type *s; - struct ofp_stats_reply *osr; - int dp_idx; - int max_openflow_len, body_len; - void *body; - int err; - - /* Set up the cleanup function for this dump. Linux 2.6.20 and later - * support setting up cleanup functions via the .doneit member of - * struct genl_ops. This kluge supports earlier versions also. */ - cb->done = dp_genl_openflow_done; - - sender.pid = NETLINK_CB(cb->skb).pid; - sender.seq = cb->nlh->nlmsg_seq; - if (!cb->args[0]) { - struct nlattr *attrs[DP_GENL_A_MAX + 1]; - struct ofp_stats_request *rq; - struct nlattr *va; - size_t len, body_len; - int type; - - err = nlmsg_parse(cb->nlh, GENL_HDRLEN, attrs, DP_GENL_A_MAX, - dp_genl_openflow_policy); - if (err < 0) - return err; - - if (!attrs[DP_GENL_A_DP_IDX]) - return -EINVAL; - dp_idx = nla_get_u16(attrs[DP_GENL_A_DP_IDX]); - dp = dp_get_by_idx(dp_idx); - if (!dp) - return -ENOENT; - - va = attrs[DP_GENL_A_OPENFLOW]; - len = nla_len(va); - if (!va || len < sizeof *rq) - return -EINVAL; - - rq = nla_data(va); - sender.xid = rq->header.xid; - type = ntohs(rq->type); - if (rq->header.version != OFP_VERSION) { - dp_send_error_msg(dp, &sender, OFPET_BAD_REQUEST, - OFPBRC_BAD_VERSION, rq, len); - return -EINVAL; - } - if (rq->header.type != OFPT_STATS_REQUEST - || ntohs(rq->header.length) != len) - return -EINVAL; - - if (type == OFPST_VENDOR) { - /* Vendor is not in the array, take care of it */ - s = &stats_vendor; - } else { - if (type >= ARRAY_SIZE(stats) || !stats[type].dump) { - dp_send_error_msg(dp, &sender, - OFPET_BAD_REQUEST, - OFPBRC_BAD_STAT, rq, len); - return -EINVAL; - } - s = &stats[type]; - } - body_len = len - offsetof(struct ofp_stats_request, body); - if (body_len < s->min_body || body_len > s->max_body) - return -EINVAL; - - cb->args[0] = 1; - cb->args[1] = dp_idx; - cb->args[2] = type; - cb->args[3] = rq->header.xid; - if (s->init) { - void *state; - err = s->init(dp, rq->body, body_len, &state); - if (err) - return err; - cb->args[4] = (long) state; - } - } else if (cb->args[0] == 1) { - sender.xid = cb->args[3]; - dp_idx = cb->args[1]; - if (cb->args[2] == OFPST_VENDOR) { - /* Vendor is not in the array, take care of it */ - s = &stats_vendor; - } else { - s = &stats[cb->args[2]]; - } - - dp = dp_get_by_idx(dp_idx); - if (!dp) - return -ENOENT; - } else { - return 0; - } - - osr = put_openflow_headers(dp, skb, OFPT_STATS_REPLY, &sender, - &max_openflow_len); - if (IS_ERR(osr)) - return PTR_ERR(osr); - osr->type = htons(cb->args[2]); - osr->flags = 0; - resize_openflow_skb(skb, &osr->header, max_openflow_len); - body = osr->body; - body_len = max_openflow_len - offsetof(struct ofp_stats_reply, body); - - err = s->dump(dp, (void *) cb->args[4], body, &body_len); - if (err >= 0) { - if (!err) - cb->args[0] = 2; - else - osr->flags = ntohs(OFPSF_REPLY_MORE); - resize_openflow_skb(skb, &osr->header, - (offsetof(struct ofp_stats_reply, body) - + body_len)); - err = skb->len; - } - - return err; -} - -static int -dp_genl_openflow_done(struct netlink_callback *cb) -{ - if (cb->args[0]) { - const struct stats_type *s; - if (cb->args[2] == OFPST_VENDOR) { - /* Vendor is not in the array, take care of it */ - s = &stats_vendor; - } else { - s = &stats[cb->args[2]]; - } - if (s->done) - s->done((void *) cb->args[4]); - } - return 0; -} - -static struct genl_ops dp_genl_ops_openflow = { - .cmd = DP_GENL_C_OPENFLOW, - .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ - .policy = dp_genl_openflow_policy, - .doit = dp_genl_openflow, - .dumpit = dp_genl_openflow_dumpit, -}; - -static struct genl_ops *dp_genl_all_ops[] = { - /* Keep this operation first. Generic Netlink dispatching - * looks up operations with linear search, so we want it at the - * front. */ - &dp_genl_ops_openflow, - - &dp_genl_ops_add_dp, - &dp_genl_ops_del_dp, - &dp_genl_ops_query_dp, - &dp_genl_ops_add_port, - &dp_genl_ops_del_port, -}; - -static int dp_init_netlink(void) -{ - int err; - int i; - - err = genl_register_family(&dp_genl_family); - if (err) - return err; - - for (i = 0; i < ARRAY_SIZE(dp_genl_all_ops); i++) { - err = genl_register_ops(&dp_genl_family, dp_genl_all_ops[i]); - if (err) - goto err_unregister; - } - - for (i = 0; i < N_MC_GROUPS; i++) { - snprintf(mc_groups[i].name, sizeof mc_groups[i].name, - "openflow%d", i); - err = genl_register_mc_group(&dp_genl_family, &mc_groups[i]); - if (err < 0) - goto err_unregister; - } - - return 0; - -err_unregister: - genl_unregister_family(&dp_genl_family); - return err; -} - -static void dp_uninit_netlink(void) -{ - genl_unregister_family(&dp_genl_family); -} - -/* Set the description strings if appropriate values are available from - * the DMI. */ -static void set_desc(void) -{ - const char *uuid = dmi_get_system_info(DMI_PRODUCT_UUID); - const char *vendor = dmi_get_system_info(DMI_SYS_VENDOR); - const char *name = dmi_get_system_info(DMI_PRODUCT_NAME); - const char *version = dmi_get_system_info(DMI_PRODUCT_VERSION); - const char *serial = dmi_get_system_info(DMI_PRODUCT_SERIAL); - const char *uptr; - - if (!uuid || *uuid == '\0' || strlen(uuid) != 36) - return; - - /* We are only interested version 1 UUIDs, since the last six bytes - * are an IEEE 802 MAC address. */ - if (uuid[14] != '1') - return; - - /* Only set if the UUID is from Nicira. */ - uptr = uuid + 24; - if (strncmp(uptr, NICIRA_OUI_STR, strlen(NICIRA_OUI_STR))) - return; - - if (vendor) - strlcpy(mfr_desc, vendor, sizeof(mfr_desc)); - if (name || version) - snprintf(hw_desc, sizeof(hw_desc), "%s %s", - name ? name : "", - version ? version : ""); - if (serial) - strlcpy(serial_num, serial, sizeof(serial_num)); -} - -static int __init dp_init(void) -{ - int err; - - printk("OpenFlow %s, built "__DATE__" "__TIME__", " - "protocol 0x%02x\n", VERSION BUILDNR, OFP_VERSION); - - err = flow_init(); - if (err) - goto error; - - err = register_netdevice_notifier(&dp_device_notifier); - if (err) - goto error_flow_exit; - - err = dp_init_netlink(); - if (err) - goto error_unreg_notifier; - - dp_ioctl_hook = NULL; - dp_add_dp_hook = NULL; - dp_del_dp_hook = NULL; - dp_add_if_hook = NULL; - dp_del_if_hook = NULL; - - /* Check if better descriptions of the switch are available than the - * defaults. */ - set_desc(); - - /* Hook into callback used by the bridge to intercept packets. - * Parasites we are. */ - if (br_handle_frame_hook) - printk("openflow: hijacking bridge hook\n"); - br_handle_frame_hook = dp_frame_hook; - - return 0; - -error_unreg_notifier: - unregister_netdevice_notifier(&dp_device_notifier); -error_flow_exit: - flow_exit(); -error: - printk(KERN_EMERG "openflow: failed to install!"); - return err; -} - -static void dp_cleanup(void) -{ - fwd_exit(); - dp_uninit_netlink(); - unregister_netdevice_notifier(&dp_device_notifier); - flow_exit(); - br_handle_frame_hook = NULL; -} - -module_init(dp_init); -module_exit(dp_cleanup); - -MODULE_DESCRIPTION("OpenFlow Switching Datapath"); -MODULE_AUTHOR("Copyright (c) 2007, 2008 The Board of Trustees of The Leland Stanford Junior University"); -MODULE_LICENSE("GPL"); diff --git a/openflow/datapath/datapath.h b/openflow/datapath/datapath.h deleted file mode 100644 index 79ae0b78..00000000 --- a/openflow/datapath/datapath.h +++ /dev/null @@ -1,114 +0,0 @@ -/* Interface exported by OpenFlow module. */ - -#ifndef DATAPATH_H -#define DATAPATH_H 1 - -#include -#include -#include -#include -#include -#include -#include "openflow/openflow.h" -#include "openflow/nicira-ext.h" -#include "flow.h" - - -#define NL_FLOWS_PER_MESSAGE 100 - -/* Capabilities supported by this implementation. */ -#define OFP_SUPPORTED_CAPABILITIES ( OFPC_FLOW_STATS \ - | OFPC_TABLE_STATS \ - | OFPC_PORT_STATS ) - -/* Actions supported by this implementation. */ -#define OFP_SUPPORTED_ACTIONS ( (1 << OFPAT_OUTPUT) \ - | (1 << OFPAT_SET_VLAN_VID) \ - | (1 << OFPAT_SET_VLAN_PCP) \ - | (1 << OFPAT_STRIP_VLAN) \ - | (1 << OFPAT_SET_DL_SRC) \ - | (1 << OFPAT_SET_DL_DST) \ - | (1 << OFPAT_SET_NW_SRC) \ - | (1 << OFPAT_SET_NW_DST) \ - | (1 << OFPAT_SET_TP_SRC) \ - | (1 << OFPAT_SET_TP_DST) ) - -struct sk_buff; - -#define DP_MAX_PORTS 255 - -struct datapath { - int dp_idx; - - struct timer_list timer; /* Expiration timer. */ - struct sw_chain *chain; /* Forwarding rules. */ - struct task_struct *dp_task; /* Kernel thread for maintenance. */ - - /* Data related to the "of" device of this datapath */ - struct net_device *netdev; - char dp_desc[DESC_STR_LEN]; /* human readible comment to ID this DP */ - - /* Configuration set from controller */ - uint16_t flags; - uint16_t miss_send_len; - - struct kobject ifobj; - - /* Switch ports. */ - struct net_bridge_port *ports[DP_MAX_PORTS]; - struct net_bridge_port *local_port; /* OFPP_LOCAL port. */ - struct list_head port_list; /* All ports, including local_port. */ -}; - -/* Information necessary to reply to the sender of an OpenFlow message. */ -struct sender { - uint32_t xid; /* OpenFlow transaction ID of request. */ - uint32_t pid; /* Netlink process ID of sending socket. */ - uint32_t seq; /* Netlink sequence ID of request. */ -}; - -struct net_bridge_port { - u16 port_no; - u32 config; /* Some subset of OFPPC_* flags. */ - u32 state; /* Some subset of OFPPS_* flags. */ - spinlock_t lock; - struct datapath *dp; - struct net_device *dev; - struct kobject kobj; - struct list_head node; /* Element in datapath.ports. */ -}; - -extern struct mutex dp_mutex; -extern struct notifier_block dp_device_notifier; -extern int (*dp_ioctl_hook)(struct net_device *dev, struct ifreq *rq, int cmd); -extern int (*dp_add_dp_hook)(struct datapath *dp); -extern int (*dp_del_dp_hook)(struct datapath *dp); -extern int (*dp_add_if_hook)(struct net_bridge_port *p); -extern int (*dp_del_if_hook)(struct net_bridge_port *p); - -int dp_del_switch_port(struct net_bridge_port *); -int dp_xmit_skb(struct sk_buff *skb); -int dp_output_port(struct datapath *, struct sk_buff *, int out_port, - int ignore_no_fwd); -int dp_output_control(struct datapath *, struct sk_buff *, size_t, int); -void dp_set_origin(struct datapath *, uint16_t, struct sk_buff *); -int dp_send_features_reply(struct datapath *, const struct sender *); -int dp_send_config_reply(struct datapath *, const struct sender *); -int dp_send_port_status(struct net_bridge_port *p, uint8_t status); -int dp_send_flow_end(struct datapath *, struct sw_flow *, - enum ofp_flow_removed_reason); -int dp_send_error_msg(struct datapath *, const struct sender *, - uint16_t, uint16_t, const void *, size_t); -int dp_update_port_flags(struct datapath *dp, const struct ofp_port_mod *opm); -int dp_send_echo_reply(struct datapath *, const struct sender *, - const struct ofp_header *); -int dp_send_hello(struct datapath *, const struct sender *, - const struct ofp_header *); -int dp_send_barrier_reply(struct datapath *, const struct sender *, - const struct ofp_header *); - -/* Should hold at least RCU read lock when calling */ -struct datapath *dp_get_by_idx(int dp_idx); -struct datapath *dp_get_by_name(const char *dp_name); - -#endif /* datapath.h */ diff --git a/openflow/datapath/dp_act.c b/openflow/datapath/dp_act.c deleted file mode 100644 index 7532c00c..00000000 --- a/openflow/datapath/dp_act.c +++ /dev/null @@ -1,543 +0,0 @@ -/* - * Distributed under the terms of the GNU GPL version 2. - * Copyright (c) 2007, 2008, 2009 The Board of Trustees of The Leland - * Stanford Junior University - */ - -/* Functions for executing OpenFlow actions. */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "forward.h" -#include "dp_act.h" -#include "openflow/nicira-ext.h" -#include "flow.h" - - -static uint16_t -validate_output(struct datapath *dp, const struct sw_flow_key *key, - const struct ofp_action_header *ah) -{ - struct ofp_action_output *oa = (struct ofp_action_output *)ah; - - if (oa->port == htons(OFPP_NONE) || - (!(key->wildcards & OFPFW_IN_PORT) && oa->port == key->in_port)) - return OFPBAC_BAD_OUT_PORT; - - return ACT_VALIDATION_OK; -} - -static int -do_output(struct datapath *dp, struct sk_buff *skb, size_t max_len, - int out_port, int ignore_no_fwd) -{ - if (!skb) - return -ENOMEM; - return (likely(out_port != OFPP_CONTROLLER) - ? dp_output_port(dp, skb, out_port, ignore_no_fwd) - : dp_output_control(dp, skb, max_len, OFPR_ACTION)); -} - - -static struct sk_buff * -vlan_pull_tag(struct sk_buff *skb) -{ - struct vlan_ethhdr *vh = vlan_eth_hdr(skb); - struct ethhdr *eh; - - - /* Verify we were given a vlan packet */ - if (vh->h_vlan_proto != htons(ETH_P_8021Q)) - return skb; - - memmove(skb->data + VLAN_HLEN, skb->data, 2 * VLAN_ETH_ALEN); - - eh = (struct ethhdr *)skb_pull(skb, VLAN_HLEN); - - skb->protocol = eh->h_proto; - skb->mac_header += VLAN_HLEN; - - return skb; -} - - -static struct sk_buff * -modify_vlan_tci(struct sk_buff *skb, struct sw_flow_key *key, - uint16_t tci, uint16_t mask) -{ - struct vlan_ethhdr *vh = vlan_eth_hdr(skb); - - if (key->dl_vlan != htons(OFP_VLAN_NONE)) { - /* Modify vlan id, but maintain other TCI values */ - vh->h_vlan_TCI = (vh->h_vlan_TCI & ~(htons(mask))) | htons(tci); - } else { - /* Add vlan header */ - - /* xxx The vlan_put_tag function, doesn't seem to work - * xxx reliably when it attempts to use the hardware-accelerated - * xxx version. We'll directly use the software version - * xxx until the problem can be diagnosed. - */ - skb = __vlan_put_tag(skb, tci); - vh = vlan_eth_hdr(skb); - } - key->dl_vlan = vh->h_vlan_TCI & htons(VLAN_VID_MASK); - key->dl_vlan_pcp = (uint8_t)((ntohs(vh->h_vlan_TCI) >> VLAN_PCP_SHIFT) - & VLAN_PCP_BITMASK); - - return skb; -} - -static struct sk_buff * -set_vlan_vid(struct sk_buff *skb, struct sw_flow_key *key, - const struct ofp_action_header *ah) -{ - struct ofp_action_vlan_vid *va = (struct ofp_action_vlan_vid *)ah; - uint16_t tci = ntohs(va->vlan_vid); - - return modify_vlan_tci(skb, key, tci, VLAN_VID_MASK); -} - -/* Mask for the priority bits in a vlan header. The kernel doesn't - * define this like it does for VID. */ -#define VLAN_PCP_MASK 0xe000 - -static struct sk_buff * -set_vlan_pcp(struct sk_buff *skb, struct sw_flow_key *key, - const struct ofp_action_header *ah) -{ - struct ofp_action_vlan_pcp *va = (struct ofp_action_vlan_pcp *)ah; - uint16_t tci = (uint16_t)va->vlan_pcp << 13; - - return modify_vlan_tci(skb, key, tci, VLAN_PCP_MASK); -} - -static struct sk_buff * -strip_vlan(struct sk_buff *skb, struct sw_flow_key *key, - const struct ofp_action_header *ah) -{ - vlan_pull_tag(skb); - key->dl_vlan = htons(OFP_VLAN_NONE); - - return skb; -} - -static struct sk_buff * -set_dl_addr(struct sk_buff *skb, struct sw_flow_key *key, - const struct ofp_action_header *ah) -{ - struct ofp_action_dl_addr *da = (struct ofp_action_dl_addr *)ah; - struct ethhdr *eh = eth_hdr(skb); - - if (da->type == htons(OFPAT_SET_DL_SRC)) - memcpy(eh->h_source, da->dl_addr, sizeof eh->h_source); - else - memcpy(eh->h_dest, da->dl_addr, sizeof eh->h_dest); - - return skb; -} - -/* Updates 'sum', which is a field in 'skb''s data, given that a 4-byte field - * covered by the sum has been changed from 'from' to 'to'. If set, - * 'pseudohdr' indicates that the field is in the TCP or UDP pseudo-header. - * Based on nf_proto_csum_replace4. */ -static void update_csum(__sum16 *sum, struct sk_buff *skb, - __be32 from, __be32 to, int pseudohdr) -{ - __be32 diff[] = { ~from, to }; - if (skb->ip_summed != CHECKSUM_PARTIAL) { - *sum = csum_fold(csum_partial((char *)diff, sizeof(diff), - ~csum_unfold(*sum))); - if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr) - skb->csum = ~csum_partial((char *)diff, sizeof(diff), - ~skb->csum); - } else if (pseudohdr) - *sum = ~csum_fold(csum_partial((char *)diff, sizeof(diff), - csum_unfold(*sum))); -} - -static struct sk_buff * -set_nw_addr(struct sk_buff *skb, struct sw_flow_key *key, - const struct ofp_action_header *ah) -{ - struct ofp_action_nw_addr *na = (struct ofp_action_nw_addr *)ah; - uint16_t eth_proto = ntohs(key->dl_type); - - if (eth_proto == ETH_P_IP) { - struct iphdr *nh = ip_hdr(skb); - uint32_t new, *field; - - new = na->nw_addr; - - if (ah->type == htons(OFPAT_SET_NW_SRC)) - field = &nh->saddr; - else - field = &nh->daddr; - - if (key->nw_proto == IPPROTO_TCP) { - struct tcphdr *th = tcp_hdr(skb); - update_csum(&th->check, skb, *field, new, 1); - } else if (key->nw_proto == IPPROTO_UDP) { - struct udphdr *th = udp_hdr(skb); - update_csum(&th->check, skb, *field, new, 1); - } - update_csum(&nh->check, skb, *field, new, 0); - *field = new; - } - - return skb; -} - -static struct sk_buff * -set_nw_tos(struct sk_buff *skb, struct sw_flow_key *key, - const struct ofp_action_header *ah) -{ - struct ofp_action_nw_tos *nt = (struct ofp_action_nw_tos *)ah; - uint16_t eth_proto = ntohs(key->dl_type); - - if (eth_proto == ETH_P_IP) { - struct iphdr *nh = ip_hdr(skb); - uint8_t new, *field; - - /* JeanII : Set only 6 bits, don't clobber ECN */ - new = (nt->nw_tos & 0xFC) | (nh->tos & 0x03); - - /* Get address of field */ - field = &nh->tos; - /* jklee : ip tos field is not included in TCP pseudo header. - * Need magic as update_csum() don't work with 8 bits. */ - update_csum(&nh->check, skb, htons((uint16_t)*field), - htons((uint16_t)new), 0); - - /* Update in packet */ - *field = new; - } - - return skb; -} - -static struct sk_buff * -set_tp_port(struct sk_buff *skb, struct sw_flow_key *key, - const struct ofp_action_header *ah) -{ - struct ofp_action_tp_port *ta = (struct ofp_action_tp_port *)ah; - uint16_t eth_proto = ntohs(key->dl_type); - - if (eth_proto == ETH_P_IP) { - uint16_t new, *field; - - new = ta->tp_port; - - if (key->nw_proto == IPPROTO_TCP) { - struct tcphdr *th = tcp_hdr(skb); - - if (ah->type == htons(OFPAT_SET_TP_SRC)) - field = &th->source; - else - field = &th->dest; - - update_csum(&th->check, skb, *field, new, 1); - *field = new; - } else if (key->nw_proto == IPPROTO_UDP) { - struct udphdr *th = udp_hdr(skb); - - if (ah->type == htons(OFPAT_SET_TP_SRC)) - field = &th->source; - else - field = &th->dest; - - update_csum(&th->check, skb, *field, new, 1); - *field = new; - } - } - - return skb; -} - -struct openflow_action { - size_t min_size; - size_t max_size; - uint16_t (*validate)(struct datapath *dp, - const struct sw_flow_key *key, - const struct ofp_action_header *ah); - struct sk_buff *(*execute)(struct sk_buff *skb, - struct sw_flow_key *key, - const struct ofp_action_header *ah); -}; - -static const struct openflow_action of_actions[] = { - [OFPAT_OUTPUT] = { - sizeof(struct ofp_action_output), - sizeof(struct ofp_action_output), - validate_output, - NULL /* This is optimized into execute_actions */ - }, - [OFPAT_SET_VLAN_VID] = { - sizeof(struct ofp_action_vlan_vid), - sizeof(struct ofp_action_vlan_vid), - NULL, - set_vlan_vid - }, - [OFPAT_SET_VLAN_PCP] = { - sizeof(struct ofp_action_vlan_pcp), - sizeof(struct ofp_action_vlan_pcp), - NULL, - set_vlan_pcp - }, - [OFPAT_STRIP_VLAN] = { - sizeof(struct ofp_action_header), - sizeof(struct ofp_action_header), - NULL, - strip_vlan - }, - [OFPAT_SET_DL_SRC] = { - sizeof(struct ofp_action_dl_addr), - sizeof(struct ofp_action_dl_addr), - NULL, - set_dl_addr - }, - [OFPAT_SET_DL_DST] = { - sizeof(struct ofp_action_dl_addr), - sizeof(struct ofp_action_dl_addr), - NULL, - set_dl_addr - }, - [OFPAT_SET_NW_SRC] = { - sizeof(struct ofp_action_nw_addr), - sizeof(struct ofp_action_nw_addr), - NULL, - set_nw_addr - }, - [OFPAT_SET_NW_DST] = { - sizeof(struct ofp_action_nw_addr), - sizeof(struct ofp_action_nw_addr), - NULL, - set_nw_addr - }, - [OFPAT_SET_NW_TOS] = { - sizeof(struct ofp_action_nw_tos), - sizeof(struct ofp_action_nw_tos), - NULL, - set_nw_tos - }, - [OFPAT_SET_TP_SRC] = { - sizeof(struct ofp_action_tp_port), - sizeof(struct ofp_action_tp_port), - NULL, - set_tp_port - }, - [OFPAT_SET_TP_DST] = { - sizeof(struct ofp_action_tp_port), - sizeof(struct ofp_action_tp_port), - NULL, - set_tp_port - } - /* OFPAT_VENDOR is not here, since it would blow up the array size. */ -}; - -/* Validate built-in OpenFlow actions. Either returns ACT_VALIDATION_OK - * or an OFPET_BAD_ACTION error code. */ -static uint16_t -validate_ofpat(struct datapath *dp, const struct sw_flow_key *key, - const struct ofp_action_header *ah, uint16_t type, uint16_t len) -{ - uint16_t ret = ACT_VALIDATION_OK; - const struct openflow_action *act = &of_actions[type]; - - if ((len < act->min_size) || (len > act->max_size)) - return OFPBAC_BAD_LEN; - - if (act->validate) - ret = act->validate(dp, key, ah); - - return ret; -} - -/* Validate vendor-defined actions. Either returns ACT_VALIDATION_OK - * or an OFPET_BAD_ACTION error code. */ -static uint16_t -validate_vendor(struct datapath *dp, const struct sw_flow_key *key, - const struct ofp_action_header *ah, uint16_t len) -{ - struct ofp_action_vendor_header *avh; - int ret = ACT_VALIDATION_OK; - - if (len < sizeof(struct ofp_action_vendor_header)) - return OFPBAC_BAD_LEN; - - avh = (struct ofp_action_vendor_header *)ah; - - switch(ntohl(avh->vendor)) { - default: - return OFPBAC_BAD_VENDOR; - } - - return ret; -} - -/* Validates a list of actions. If a problem is found, a code for the - * OFPET_BAD_ACTION error type is returned. If the action list validates, - * ACT_VALIDATION_OK is returned. */ -uint16_t -validate_actions(struct datapath *dp, const struct sw_flow_key *key, - const struct ofp_action_header *actions, size_t actions_len) -{ - uint8_t *p = (uint8_t *)actions; - int err; - - while (actions_len >= sizeof(struct ofp_action_header)) { - struct ofp_action_header *ah = (struct ofp_action_header *)p; - size_t len = ntohs(ah->len); - uint16_t type; - - /* Make there's enough remaining data for the specified length - * and that the action length is a multiple of 64 bits. */ - if ((actions_len < len) || (len % 8) != 0) - return OFPBAC_BAD_LEN; - - type = ntohs(ah->type); - if (type < ARRAY_SIZE(of_actions)) { - err = validate_ofpat(dp, key, ah, type, len); - if (err != ACT_VALIDATION_OK) - return err; - } else if (type == OFPAT_VENDOR) { - err = validate_vendor(dp, key, ah, len); - if (err != ACT_VALIDATION_OK) - return err; - } else - return OFPBAC_BAD_TYPE; - - p += len; - actions_len -= len; - } - - /* Check if there's any trailing garbage. */ - if (actions_len != 0) - return OFPBAC_BAD_LEN; - - return ACT_VALIDATION_OK; -} - -/* Execute a built-in OpenFlow action against 'skb'. */ -static struct sk_buff * -execute_ofpat(struct sk_buff *skb, struct sw_flow_key *key, - const struct ofp_action_header *ah, uint16_t type) -{ - const struct openflow_action *act = &of_actions[type]; - if (act->execute && make_writable(&skb)) - skb = act->execute(skb, key, ah); - return skb; -} - -/* Execute a vendor-defined action against 'skb'. */ -static struct sk_buff * -execute_vendor(struct sk_buff *skb, const struct sw_flow_key *key, - const struct ofp_action_header *ah) -{ - struct ofp_action_vendor_header *avh - = (struct ofp_action_vendor_header *)ah; - struct datapath *dp = skb->dev->br_port->dp; - - /* NB: If changes need to be made to the packet, a call should be - * made to make_writable or its equivalent first. */ - - switch(ntohl(avh->vendor)) { - default: - /* This should not be possible due to prior validation. */ - if (net_ratelimit()) - printk(KERN_WARNING "%s: attempt to execute action " - "with unknown vendor: %#x\n", - dp->netdev->name, ntohl(avh->vendor)); - break; - } - - return skb; -} - -/* Execute a list of actions against 'skb'. */ -void execute_actions(struct datapath *dp, struct sk_buff *skb, - struct sw_flow_key *key, - const struct ofp_action_header *actions, size_t actions_len, - int ignore_no_fwd) -{ - /* Every output action needs a separate clone of 'skb', but the common - * case is just a single output action, so that doing a clone and - * then freeing the original skbuff is wasteful. So the following code - * is slightly obscure just to avoid that. */ - int prev_port; - size_t max_len = UINT16_MAX; - uint8_t *p = (uint8_t *)actions; - - prev_port = -1; - - /* The action list was already validated, so we can be a bit looser - * in our sanity-checking. */ - while (actions_len > 0) { - struct ofp_action_header *ah = (struct ofp_action_header *)p; - size_t len = htons(ah->len); - - WARN_ON_ONCE(skb_shared(skb)); - if (prev_port != -1) { - do_output(dp, skb_clone(skb, GFP_ATOMIC), - max_len, prev_port, ignore_no_fwd); - prev_port = -1; - } - - if (likely(ah->type == htons(OFPAT_OUTPUT))) { - struct ofp_action_output *oa = (struct ofp_action_output *)p; - prev_port = ntohs(oa->port); - max_len = ntohs(oa->max_len); - } else { - uint16_t type = ntohs(ah->type); - - if (type < ARRAY_SIZE(of_actions)) - skb = execute_ofpat(skb, key, ah, type); - else if (type == OFPAT_VENDOR) - skb = execute_vendor(skb, key, ah); - - if (!skb) { - if (net_ratelimit()) - printk(KERN_WARNING "%s: " - "execute_actions lost skb\n", - dp->netdev->name); - return; - } - } - - p += len; - actions_len -= len; - } - if (prev_port != -1) - do_output(dp, skb, max_len, prev_port, ignore_no_fwd); - else - kfree_skb(skb); -} - -/* Utility functions. */ - -/* Makes '*pskb' writable, possibly copying it and setting '*pskb' to point to - * the copy. - * Returns 1 if successful, 0 on failure. */ -int -make_writable(struct sk_buff **pskb) -{ - struct sk_buff *skb = *pskb; - if (skb_shared(skb) || skb_cloned(skb)) { - struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC); - if (!nskb) - return 0; - kfree_skb(skb); - *pskb = nskb; - return 1; - } else { - unsigned int hdr_len = (skb_transport_offset(skb) - + sizeof(struct tcphdr)); - return pskb_may_pull(skb, min(hdr_len, skb->len)); - } -} diff --git a/openflow/datapath/dp_act.h b/openflow/datapath/dp_act.h deleted file mode 100644 index d601eca0..00000000 --- a/openflow/datapath/dp_act.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef DP_ACT_H -#define DP_ACT_H 1 - -#include "datapath.h" - -#define ACT_VALIDATION_OK ((uint16_t)-1) - -uint16_t validate_actions(struct datapath *, const struct sw_flow_key *, - const struct ofp_action_header *, size_t); -void execute_actions(struct datapath *, struct sk_buff *, - struct sw_flow_key *, const struct ofp_action_header *, - size_t action_len, int ignore_no_fwd); -int make_writable(struct sk_buff **pskb); - -#endif /* dp_act.h */ diff --git a/openflow/datapath/dp_dev.c b/openflow/datapath/dp_dev.c deleted file mode 100644 index 5db5b19b..00000000 --- a/openflow/datapath/dp_dev.c +++ /dev/null @@ -1,252 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include "datapath.h" -#include "dp_dev.h" -#include "forward.h" - - -static struct dp_dev *dp_dev_priv(struct net_device *netdev) -{ - return netdev_priv(netdev); -} - -struct datapath *dp_dev_get_dp(struct net_device *netdev) -{ - return dp_dev_priv(netdev)->dp; -} -EXPORT_SYMBOL(dp_dev_get_dp); - -static struct net_device_stats *dp_dev_get_stats(struct net_device *netdev) -{ - struct dp_dev *dp_dev = dp_dev_priv(netdev); - return &dp_dev->stats; -} - -int dp_dev_recv(struct net_device *netdev, struct sk_buff *skb) -{ - int len = skb->len; - struct dp_dev *dp_dev = dp_dev_priv(netdev); - skb->dev = netdev; - skb->pkt_type = PACKET_HOST; - skb->protocol = eth_type_trans(skb, netdev); - if (in_interrupt()) - netif_rx(skb); - else - netif_rx_ni(skb); - netdev->last_rx = jiffies; - dp_dev->stats.rx_packets++; - dp_dev->stats.rx_bytes += len; - return len; -} - -static int dp_dev_mac_addr(struct net_device *dev, void *p) -{ - struct sockaddr *addr = p; - - if (netif_running(dev)) - return -EBUSY; - if (!is_valid_ether_addr(addr->sa_data)) - return -EADDRNOTAVAIL; - memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); - return 0; -} - -static int dp_dev_xmit(struct sk_buff *skb, struct net_device *netdev) -{ - struct dp_dev *dp_dev = dp_dev_priv(netdev); - struct datapath *dp = dp_dev->dp; - - /* By orphaning 'skb' we will screw up socket accounting slightly, but - * the effect is limited to the device queue length. If we don't - * do this, then the sk_buff will be destructed eventually, but it is - * harder to predict when. */ - skb_orphan(skb); - - /* We are going to modify 'skb', by sticking it on &dp_dev->xmit_queue, - * so we need to have our own clone. (At any rate, fwd_port_input() - * will need its own clone, so there's no benefit to queuing any other - * way.) */ - skb = skb_share_check(skb, GFP_ATOMIC); - if (!skb) - return 0; - - dp_dev->stats.tx_packets++; - dp_dev->stats.tx_bytes += skb->len; - - if (skb_queue_len(&dp_dev->xmit_queue) >= dp->netdev->tx_queue_len) { - /* Queue overflow. Stop transmitter. */ - netif_stop_queue(dp->netdev); - - /* We won't see all dropped packets individually, so overrun - * error is appropriate. */ - dp_dev->stats.tx_fifo_errors++; - } - skb_queue_tail(&dp_dev->xmit_queue, skb); - dp->netdev->trans_start = jiffies; - - schedule_work(&dp_dev->xmit_work); - - return 0; -} - -static void dp_dev_do_xmit(struct work_struct *work) -{ - struct dp_dev *dp_dev = container_of(work, struct dp_dev, xmit_work); - struct datapath *dp = dp_dev->dp; - struct sk_buff *skb; - - while ((skb = skb_dequeue(&dp_dev->xmit_queue)) != NULL) { - skb_reset_mac_header(skb); - rcu_read_lock(); - fwd_port_input(dp->chain, skb, dp->local_port); - rcu_read_unlock(); - } - netif_wake_queue(dp->netdev); -} - -static int dp_dev_open(struct net_device *netdev) -{ - netif_start_queue(netdev); - return 0; -} - -static int dp_dev_stop(struct net_device *netdev) -{ - netif_stop_queue(netdev); - return 0; -} - -static void dp_getinfo(struct net_device *dev, struct ethtool_drvinfo *info) -{ - strcpy(info->driver, "openflow"); - sprintf(info->version, "0x%d", OFP_VERSION); - strcpy(info->fw_version, "N/A"); - strcpy(info->bus_info, "N/A"); -} - -static struct ethtool_ops dp_ethtool_ops = { - .get_drvinfo = dp_getinfo, - .get_link = ethtool_op_get_link, - .get_sg = ethtool_op_get_sg, - .get_tx_csum = ethtool_op_get_tx_csum, - .get_tso = ethtool_op_get_tso, -}; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) -static const struct net_device_ops dp_netdev_ops = { - .ndo_init = NULL, - .ndo_uninit = NULL, - .ndo_open = dp_dev_open, - .ndo_stop = dp_dev_stop, - .ndo_start_xmit = dp_dev_xmit, - .ndo_select_queue = NULL, - .ndo_change_rx_flags = NULL, - .ndo_set_rx_mode = NULL, - .ndo_set_multicast_list = NULL, - .ndo_set_mac_address = dp_dev_mac_addr, - .ndo_validate_addr = NULL, - .ndo_do_ioctl = NULL, - .ndo_set_config = NULL, - .ndo_change_mtu = NULL, - .ndo_tx_timeout = NULL, - .ndo_get_stats = dp_dev_get_stats, - .ndo_vlan_rx_register = NULL, - .ndo_vlan_rx_add_vid = NULL, - .ndo_vlan_rx_kill_vid = NULL, - .ndo_poll_controller = NULL -}; -#endif - -static void -do_setup(struct net_device *netdev) -{ - ether_setup(netdev); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) - netdev->netdev_ops = &dp_netdev_ops; -#else - netdev->do_ioctl = dp_ioctl_hook; - netdev->get_stats = dp_dev_get_stats; - netdev->hard_start_xmit = dp_dev_xmit; - netdev->open = dp_dev_open; - netdev->stop = dp_dev_stop; - netdev->set_mac_address = dp_dev_mac_addr; -#endif - SET_ETHTOOL_OPS(netdev, &dp_ethtool_ops); - netdev->tx_queue_len = 100; - - netdev->flags = IFF_BROADCAST | IFF_MULTICAST; - - random_ether_addr(netdev->dev_addr); - - /* Set the OUI to the Nicira one. */ - netdev->dev_addr[0] = 0x00; - netdev->dev_addr[1] = 0x23; - netdev->dev_addr[2] = 0x20; - - /* Set the top bits to indicate random Nicira address. */ - netdev->dev_addr[3] |= 0xc0; -} - -/* Create a datapath device associated with 'dp'. If 'dp_name' is null, - * the device name will be of the form 'of'. - * - * Called with RTNL lock and dp_mutex.*/ -int dp_dev_setup(struct datapath *dp, const char *dp_name) -{ - struct dp_dev *dp_dev; - struct net_device *netdev; - char dev_name[IFNAMSIZ]; - int err; - - if (dp_name) { - if (strlen(dp_name) >= IFNAMSIZ) - return -EINVAL; - strncpy(dev_name, dp_name, sizeof(dev_name)); - } else - snprintf(dev_name, sizeof dev_name, "of%d", dp->dp_idx); - - netdev = alloc_netdev(sizeof(struct dp_dev), dev_name, do_setup); - if (!netdev) - return -ENOMEM; - - err = register_netdevice(netdev); - if (err) { - free_netdev(netdev); - return err; - } - - dp_dev = dp_dev_priv(netdev); - dp_dev->dp = dp; - skb_queue_head_init(&dp_dev->xmit_queue); - INIT_WORK(&dp_dev->xmit_work, dp_dev_do_xmit); - dp->netdev = netdev; - return 0; -} - -/* Called with RTNL lock and dp_mutex.*/ -void dp_dev_destroy(struct datapath *dp) -{ - struct dp_dev *dp_dev = dp_dev_priv(dp->netdev); - - netif_tx_disable(dp->netdev); - synchronize_net(); - skb_queue_purge(&dp_dev->xmit_queue); - unregister_netdevice(dp->netdev); -} - -int is_dp_dev(struct net_device *netdev) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) - return netdev->netdev_ops->ndo_open == dp_dev_open; - -#else - return netdev->open == dp_dev_open; -#endif -} diff --git a/openflow/datapath/dp_dev.h b/openflow/datapath/dp_dev.h deleted file mode 100644 index 26f72485..00000000 --- a/openflow/datapath/dp_dev.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef DP_DEV_H -#define DP_DEV_H 1 - -struct dp_dev { - struct net_device_stats stats; - struct datapath *dp; - struct sk_buff_head xmit_queue; - struct work_struct xmit_work; -}; - -int dp_dev_setup(struct datapath *, const char *); -void dp_dev_destroy(struct datapath *); -int dp_dev_recv(struct net_device *, struct sk_buff *); -int is_dp_dev(struct net_device *); -struct datapath *dp_dev_get_dp(struct net_device *); - -#endif /* dp_dev.h */ diff --git a/openflow/datapath/dp_notify.c b/openflow/datapath/dp_notify.c deleted file mode 100644 index 54c88402..00000000 --- a/openflow/datapath/dp_notify.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Distributed under the terms of the GNU GPL version 2. - * Copyright (c) 2007, 2008, 2009 The Board of Trustees of The Leland - * Stanford Junior University - */ - -/* Handle changes to managed devices */ - -#include - -#include "datapath.h" - - -static int dp_device_event(struct notifier_block *unused, unsigned long event, - void *ptr) -{ - struct net_device *dev = ptr; - struct net_bridge_port *p = dev->br_port; - unsigned long int flags; - - - /* Check if monitored port */ - if (!p) - return NOTIFY_DONE; - - spin_lock_irqsave(&p->lock, flags); - switch (event) { - case NETDEV_UNREGISTER: - spin_unlock_irqrestore(&p->lock, flags); - mutex_lock(&dp_mutex); - dp_del_switch_port(p); - mutex_unlock(&dp_mutex); - return NOTIFY_DONE; - break; - } - spin_unlock_irqrestore(&p->lock, flags); - - return NOTIFY_DONE; -} - -struct notifier_block dp_device_notifier = { - .notifier_call = dp_device_event -}; diff --git a/openflow/datapath/flow.c b/openflow/datapath/flow.c deleted file mode 100644 index c927ce65..00000000 --- a/openflow/datapath/flow.c +++ /dev/null @@ -1,504 +0,0 @@ - -/* - * Distributed under the terms of the GNU GPL version 2. - * Copyright (c) 2007, 2008 The Board of Trustees of The Leland - * Stanford Junior University - */ - -#include "flow.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "openflow/openflow.h" -#include "openflow/nicira-ext.h" -#include "compat.h" - -struct kmem_cache *flow_cache; - -/* Internal function used to compare fields in flow. */ -static inline -int flow_fields_match(const struct sw_flow_key *a, const struct sw_flow_key *b, - uint32_t w, uint32_t src_mask, uint32_t dst_mask) -{ - return ((w & OFPFW_IN_PORT || a->in_port == b->in_port) - && (w & OFPFW_DL_VLAN || a->dl_vlan == b->dl_vlan) - && (w & OFPFW_DL_VLAN_PCP || a->dl_vlan_pcp == b->dl_vlan_pcp) - && (w & OFPFW_DL_SRC || !memcmp(a->dl_src, b->dl_src, ETH_ALEN)) - && (w & OFPFW_DL_DST || !memcmp(a->dl_dst, b->dl_dst, ETH_ALEN)) - && (w & OFPFW_DL_TYPE || a->dl_type == b->dl_type) - && (w & OFPFW_NW_TOS || a->nw_tos == b->nw_tos) - && (w & OFPFW_NW_PROTO || a->nw_proto == b->nw_proto) - && !((a->nw_src ^ b->nw_src) & src_mask) - && !((a->nw_dst ^ b->nw_dst) & dst_mask) - && (w & OFPFW_TP_SRC || a->tp_src == b->tp_src) - && (w & OFPFW_TP_DST || a->tp_dst == b->tp_dst)); -} - -/* Returns nonzero if 'a' and 'b' match, that is, if their fields are equal - * modulo wildcards in 'b', zero otherwise. */ -int flow_matches_1wild(const struct sw_flow_key *a, - const struct sw_flow_key *b) -{ - return flow_fields_match(a, b, b->wildcards, - b->nw_src_mask, b->nw_dst_mask); -} -EXPORT_SYMBOL(flow_matches_1wild); - -/* Returns nonzero if 'a' and 'b' match, that is, if their fields are equal - * modulo wildcards in 'a' or 'b', zero otherwise. */ -int flow_matches_2wild(const struct sw_flow_key *a, - const struct sw_flow_key *b) -{ - return flow_fields_match(a, b, - a->wildcards | b->wildcards, - a->nw_src_mask & b->nw_src_mask, - a->nw_dst_mask & b->nw_dst_mask); -} -EXPORT_SYMBOL(flow_matches_2wild); - -/* Returns nonzero if 't' (the table entry's key) and 'd' (the key - * describing the match) match, that is, if their fields are - * equal modulo wildcards, zero otherwise. If 'strict' is nonzero, the - * wildcards must match in both 't_key' and 'd_key'. Note that the - * table's wildcards are ignored unless 'strict' is set. */ -int flow_matches_desc(const struct sw_flow_key *t, const struct sw_flow_key *d, - int strict) -{ - if (strict && d->wildcards != t->wildcards) - return 0; - return flow_matches_1wild(t, d); -} -EXPORT_SYMBOL(flow_matches_desc); - -/* Returns nonzero if 't' (the table entry's key) and 'd' (the key - * describing the match) match, that is, if their fields are - * equal modulo 't' or 'd' wildcards, zero otherwise. If 'strict' is nonzero, the - * wildcards must match in both 't_key' and 'd_key'. Note that the - * table's wildcards are ignored unless 'strict' is set. */ -int -flow_matches_2desc(const struct sw_flow_key *t, const struct sw_flow_key *d, - int strict) -{ - if (strict && d->wildcards != t->wildcards) { - return 0; - } - return flow_matches_2wild(t, d); -} -EXPORT_SYMBOL(flow_matches_2desc); - -static uint32_t make_nw_mask(int n_wild_bits) -{ - n_wild_bits &= (1u << OFPFW_NW_SRC_BITS) - 1; - return n_wild_bits < 32 ? htonl(~((1u << n_wild_bits) - 1)) : 0; -} - -void flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from) -{ - to->wildcards = ntohl(from->wildcards) & OFPFW_ALL; - to->dl_vlan_pcp = from->dl_vlan_pcp; - to->in_port = from->in_port; - to->dl_vlan = from->dl_vlan; - memcpy(to->dl_src, from->dl_src, ETH_ALEN); - memcpy(to->dl_dst, from->dl_dst, ETH_ALEN); - to->dl_type = from->dl_type; - - to->nw_tos = to->nw_proto = to->nw_src = to->nw_dst = 0; - to->tp_src = to->tp_dst = 0; - memset(to->pad, 0, sizeof(to->pad)); - -#define OFPFW_TP (OFPFW_TP_SRC | OFPFW_TP_DST) -#define OFPFW_NW (OFPFW_NW_TOS | OFPFW_NW_PROTO | OFPFW_NW_SRC_MASK | OFPFW_NW_DST_MASK) - if (to->wildcards & OFPFW_DL_TYPE) { - /* Can't sensibly match on network or transport headers if the - * data link type is unknown. */ - to->wildcards |= OFPFW_NW | OFPFW_TP; - } else if (from->dl_type == htons(ETH_P_IP)) { - to->nw_tos = from->nw_tos & 0xfc; - to->nw_proto = from->nw_proto; - to->nw_src = from->nw_src; - to->nw_dst = from->nw_dst; - - if (to->wildcards & OFPFW_NW_PROTO) { - /* Can't sensibly match on transport headers if the - * network protocol is unknown. */ - to->wildcards |= OFPFW_TP; - } else if (from->nw_proto == IPPROTO_TCP - || from->nw_proto == IPPROTO_UDP - || from->nw_proto == IPPROTO_ICMP) { - to->tp_src = from->tp_src; - to->tp_dst = from->tp_dst; - } else { - /* Transport layer fields are undefined. Mark them as - * exact-match to allow such flows to reside in - * table-hash, instead of falling into table-linear. */ - to->wildcards &= ~OFPFW_TP; - } - } else { - /* Network and transport layer fields are undefined. Mark them - * as exact-match to allow such flows to reside in table-hash, - * instead of falling into table-linear. */ - to->wildcards &= ~(OFPFW_NW | OFPFW_TP); - } - - /* We set these late because code above adjusts to->wildcards. */ - to->nw_src_mask = make_nw_mask(to->wildcards >> OFPFW_NW_SRC_SHIFT); - to->nw_dst_mask = make_nw_mask(to->wildcards >> OFPFW_NW_DST_SHIFT); -} - -void flow_fill_match(struct ofp_match* to, const struct sw_flow_key* from) -{ - to->wildcards = htonl(from->wildcards); - to->in_port = from->in_port; - to->dl_vlan = from->dl_vlan; - memcpy(to->dl_src, from->dl_src, ETH_ALEN); - memcpy(to->dl_dst, from->dl_dst, ETH_ALEN); - to->dl_type = from->dl_type; - to->nw_tos = from->nw_tos; - to->nw_proto = from->nw_proto; - to->nw_src = from->nw_src; - to->nw_dst = from->nw_dst; - to->tp_src = from->tp_src; - to->tp_dst = from->tp_dst; - to->dl_vlan_pcp = from->dl_vlan_pcp; -} - -int flow_timeout(struct sw_flow *flow) -{ - if (flow->idle_timeout != OFP_FLOW_PERMANENT - && time_after64(get_jiffies_64(), flow->used + flow->idle_timeout * HZ)) - return OFPRR_IDLE_TIMEOUT; - else if (flow->hard_timeout != OFP_FLOW_PERMANENT - && time_after64(get_jiffies_64(), - flow->created + flow->hard_timeout * HZ)) - return OFPRR_HARD_TIMEOUT; - else - return -1; -} -EXPORT_SYMBOL(flow_timeout); - -/* Returns nonzero if 'flow' contains an output action to 'out_port' or - * has the value OFPP_NONE. 'out_port' is in network-byte order. */ -int flow_has_out_port(struct sw_flow *flow, uint16_t out_port) -{ - struct sw_flow_actions *sf_acts; - size_t actions_len; - uint8_t *p; - - if (out_port == htons(OFPP_NONE)) - return 1; - - sf_acts = rcu_dereference(flow->sf_acts); - - actions_len = sf_acts->actions_len; - p = (uint8_t *)sf_acts->actions; - - while (actions_len > 0) { - struct ofp_action_header *ah = (struct ofp_action_header *)p; - size_t len = ntohs(ah->len); - - if (ah->type == htons(OFPAT_OUTPUT)) { - struct ofp_action_output *oa = (struct ofp_action_output *)p; - if (oa->port == out_port) - return 1; - } - - p += len; - actions_len -= len; - } - - return 0; -} -EXPORT_SYMBOL(flow_has_out_port); - -/* Allocates and returns a new flow with room for 'actions_len' actions, - * using allocation flags 'flags'. Returns the new flow or a null pointer - * on failure. */ -struct sw_flow *flow_alloc(size_t actions_len, gfp_t flags) -{ - struct sw_flow_actions *sfa; - size_t size = sizeof *sfa + actions_len; - struct sw_flow *flow = kmem_cache_alloc(flow_cache, flags); - if (unlikely(!flow)) - return NULL; - - sfa = kmalloc(size, flags); - if (unlikely(!sfa)) { - kmem_cache_free(flow_cache, flow); - return NULL; - } - sfa->actions_len = actions_len; - flow->sf_acts = sfa; - - return flow; -} - -/* Frees 'flow' immediately. */ -void flow_free(struct sw_flow *flow) -{ - if (unlikely(!flow)) - return; - kfree(flow->sf_acts); - kmem_cache_free(flow_cache, flow); -} -EXPORT_SYMBOL(flow_free); - -/* RCU callback used by flow_deferred_free. */ -static void rcu_free_flow_callback(struct rcu_head *rcu) -{ - struct sw_flow *flow = container_of(rcu, struct sw_flow, rcu); - flow_free(flow); -} - -/* Schedules 'flow' to be freed after the next RCU grace period. - * The caller must hold rcu_read_lock for this to be sensible. */ -void flow_deferred_free(struct sw_flow *flow) -{ - call_rcu(&flow->rcu, rcu_free_flow_callback); -} -EXPORT_SYMBOL(flow_deferred_free); - -/* RCU callback used by flow_deferred_free_acts. */ -static void rcu_free_acts_callback(struct rcu_head *rcu) -{ - struct sw_flow_actions *sf_acts = container_of(rcu, - struct sw_flow_actions, rcu); - kfree(sf_acts); -} - -/* Schedules 'sf_acts' to be freed after the next RCU grace period. - * The caller must hold rcu_read_lock for this to be sensible. */ -void flow_deferred_free_acts(struct sw_flow_actions *sf_acts) -{ - call_rcu(&sf_acts->rcu, rcu_free_acts_callback); -} -EXPORT_SYMBOL(flow_deferred_free_acts); - -/* Setup the action on the flow, just after it was created with flow_alloc(). - * Jean II */ -void flow_setup_actions(struct sw_flow * flow, - const struct ofp_action_header * actions, - int actions_len) -{ - /* Basic init of the flow stucture */ - flow->used = flow->created = get_jiffies_64(); - flow->byte_count = 0; - flow->packet_count = 0; - spin_lock_init(&flow->lock); - - /* Make sure we don't blow the allocation done earlier */ - if(actions_len > flow->sf_acts->actions_len) { - printk(KERN_ERR "flow_setup_actions: actions_len is too big (%d > %d)", - actions_len, flow->sf_acts->actions_len); - return; - } - - /* Setup the actions - No need for RCU at this point ;-) */ - memcpy(flow->sf_acts->actions, actions, actions_len); -} - -/* Copies 'actions' into a newly allocated structure for use by 'flow' - * and safely frees the structure that defined the previous actions. */ -void flow_replace_acts(struct sw_flow *flow, - const struct ofp_action_header *actions, size_t actions_len) -{ - struct sw_flow_actions *sfa; - struct sw_flow_actions *orig_sfa = flow->sf_acts; - size_t size = sizeof *sfa + actions_len; - - sfa = kmalloc(size, GFP_ATOMIC); - if (unlikely(!sfa)) - return; - - sfa->actions_len = actions_len; - memcpy(sfa->actions, actions, actions_len); - - rcu_assign_pointer(flow->sf_acts, sfa); - flow_deferred_free_acts(orig_sfa); - - return; -} -EXPORT_SYMBOL(flow_replace_acts); - -/* Prints a representation of 'key' to the kernel log. */ -void print_flow(const struct sw_flow_key *key) -{ - printk("wild %08x port %04x vlan-vid %04x vlan-pcp %02x " - "src-mac %02x:%02x:%02x:%02x:%02x:%02x " - "dst-mac %02x:%02x:%02x:%02x:%02x:%02x " - "frm-type %04x ip-tos %02x ip-proto %02x " - "src-ip %u.%u.%u.%u dst-ip %u.%u.%u.%u tp-src %d tp-dst %d\n", - key->wildcards, ntohs(key->in_port), ntohs(key->dl_vlan), - key->dl_vlan_pcp, - key->dl_src[0], key->dl_src[1], key->dl_src[2], - key->dl_src[3], key->dl_src[4], key->dl_src[5], - key->dl_dst[0], key->dl_dst[1], key->dl_dst[2], - key->dl_dst[3], key->dl_dst[4], key->dl_dst[5], - ntohs(key->dl_type), - key->nw_tos, key->nw_proto, - ((unsigned char *)&key->nw_src)[0], - ((unsigned char *)&key->nw_src)[1], - ((unsigned char *)&key->nw_src)[2], - ((unsigned char *)&key->nw_src)[3], - ((unsigned char *)&key->nw_dst)[0], - ((unsigned char *)&key->nw_dst)[1], - ((unsigned char *)&key->nw_dst)[2], - ((unsigned char *)&key->nw_dst)[3], - ntohs(key->tp_src), ntohs(key->tp_dst)); -} -EXPORT_SYMBOL(print_flow); - -#define SNAP_OUI_LEN 3 - -struct eth_snap_hdr -{ - struct ethhdr eth; - uint8_t dsap; /* Always 0xAA */ - uint8_t ssap; /* Always 0xAA */ - uint8_t ctrl; - uint8_t oui[SNAP_OUI_LEN]; - uint16_t ethertype; -} __attribute__ ((packed)); - -static int is_snap(const struct eth_snap_hdr *esh) -{ - return (esh->dsap == LLC_SAP_SNAP - && esh->ssap == LLC_SAP_SNAP - && !memcmp(esh->oui, "\0\0\0", 3)); -} - -/* Parses the Ethernet frame in 'skb', which was received on 'in_port', - * and initializes 'key' to match. Returns 1 if 'skb' contains an IP - * fragment, 0 otherwise. */ -int flow_extract(struct sk_buff *skb, uint16_t in_port, - struct sw_flow_key *key) -{ - struct ethhdr *eth; - struct eth_snap_hdr *esh; - int retval = 0; - int nh_ofs; - - memset(key, 0, sizeof *key); - key->dl_vlan = htons(OFP_VLAN_NONE); - key->in_port = htons(in_port); - - if (skb->len < sizeof *eth) - return 0; - if (!pskb_may_pull(skb, skb->len >= 64 ? 64 : skb->len)) { - return 0; - } - - skb_reset_mac_header(skb); - eth = eth_hdr(skb); - esh = (struct eth_snap_hdr *) eth; - nh_ofs = sizeof *eth; - if (likely(ntohs(eth->h_proto) >= OFP_DL_TYPE_ETH2_CUTOFF)) - key->dl_type = eth->h_proto; - else if (skb->len >= sizeof *esh && is_snap(esh)) { - key->dl_type = esh->ethertype; - nh_ofs = sizeof *esh; - } else { - key->dl_type = htons(OFP_DL_TYPE_NOT_ETH_TYPE); - if (skb->len >= nh_ofs + sizeof(struct llc_pdu_un)) { - nh_ofs += sizeof(struct llc_pdu_un); - } - } - - /* Check for a VLAN tag */ - if (key->dl_type == htons(ETH_P_8021Q) && - skb->len >= nh_ofs + sizeof(struct vlan_hdr)) { - struct vlan_hdr *vh = (struct vlan_hdr*)(skb->data + nh_ofs); - key->dl_type = vh->h_vlan_encapsulated_proto; - key->dl_vlan = vh->h_vlan_TCI & htons(VLAN_VID_MASK); - key->dl_vlan_pcp = (uint8_t)((ntohs(vh->h_vlan_TCI) >> VLAN_PCP_SHIFT) - & VLAN_PCP_BITMASK); - nh_ofs += sizeof(struct vlan_hdr); - } - memcpy(key->dl_src, eth->h_source, ETH_ALEN); - memcpy(key->dl_dst, eth->h_dest, ETH_ALEN); - skb_set_network_header(skb, nh_ofs); - - /* Network layer. */ - if (key->dl_type == htons(ETH_P_IP) && iphdr_ok(skb)) { - struct iphdr *nh = ip_hdr(skb); - int th_ofs = nh_ofs + nh->ihl * 4; - key->nw_tos = nh->tos & 0xfc; - key->nw_proto = nh->protocol; - key->nw_src = nh->saddr; - key->nw_dst = nh->daddr; - skb_set_transport_header(skb, th_ofs); - - /* Transport layer. */ - if (!(nh->frag_off & htons(IP_MF | IP_OFFSET))) { - if (key->nw_proto == IPPROTO_TCP) { - if (tcphdr_ok(skb)) { - struct tcphdr *tcp = tcp_hdr(skb); - key->tp_src = tcp->source; - key->tp_dst = tcp->dest; - } else { - /* Avoid tricking other code into - * thinking that this packet has an L4 - * header. */ - key->nw_proto = 0; - } - } else if (key->nw_proto == IPPROTO_UDP) { - if (udphdr_ok(skb)) { - struct udphdr *udp = udp_hdr(skb); - key->tp_src = udp->source; - key->tp_dst = udp->dest; - } else { - /* Avoid tricking other code into - * thinking that this packet has an L4 - * header. */ - key->nw_proto = 0; - } - } else if (key->nw_proto == IPPROTO_ICMP) { - if (icmphdr_ok(skb)) { - struct icmphdr *icmp = icmp_hdr(skb); - /* The ICMP type and code fields use the 16-bit - * transport port fields, so we need to store them - * in 16-bit network byte order. */ - key->icmp_type = htons(icmp->type); - key->icmp_code = htons(icmp->code); - } else { - /* Avoid tricking other code into - * thinking that this packet has an L4 - * header. */ - key->nw_proto = 0; - } - } - } else { - retval = 1; - } - } else { - skb_reset_transport_header(skb); - } - return retval; -} - -/* Initializes the flow module. - * Returns zero if successful or a negative error code. */ -int flow_init(void) -{ - flow_cache = kmem_cache_create("sw_flow", sizeof(struct sw_flow), 0, - 0, NULL); - if (flow_cache == NULL) - return -ENOMEM; - - return 0; -} - -/* Uninitializes the flow module. */ -void flow_exit(void) -{ - kmem_cache_destroy(flow_cache); -} - diff --git a/openflow/datapath/flow.h b/openflow/datapath/flow.h deleted file mode 100644 index 5f8597a3..00000000 --- a/openflow/datapath/flow.h +++ /dev/null @@ -1,199 +0,0 @@ -#ifndef FLOW_H -#define FLOW_H 1 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "openflow/openflow.h" - -#define VLAN_PCP_SHIFT 13 -#define VLAN_PCP_BITMASK 0x0007 /* the least 3-bit is valid */ - -struct sk_buff; -struct ofp_flow_mod; - -/* Identification data for a flow. - * Network byte order except for the "wildcards" field. - * Ordered to make bytewise comparisons (e.g. with memcmp()) fail quickly and - * to keep the amount of padding to a minimum. - * If you change the ordering of fields here, change flow_keys_equal() to - * compare the proper fields. - */ -struct sw_flow_key { - uint32_t nw_src; /* IP source address. */ - uint32_t nw_dst; /* IP destination address. */ - uint16_t in_port; /* Input switch port */ - uint16_t dl_vlan; /* Input VLAN id. */ - uint16_t dl_type; /* Ethernet frame type. */ - uint16_t tp_src; /* TCP/UDP source port. */ - uint16_t tp_dst; /* TCP/UDP destination port. */ - uint8_t dl_src[ETH_ALEN]; /* Ethernet source address. */ - uint8_t dl_dst[ETH_ALEN]; /* Ethernet destination address. */ - uint8_t dl_vlan_pcp; /* Input VLAN priority. */ - uint8_t nw_tos; /* IPv4 DSCP */ - uint8_t nw_proto; /* IP protocol. */ - uint8_t pad[3]; - uint32_t wildcards; /* Wildcard fields (host byte order). */ - uint32_t nw_src_mask; /* 1-bit in each significant nw_src bit. */ - uint32_t nw_dst_mask; /* 1-bit in each significant nw_dst bit. */ -}; - -/* The match fields for ICMP type and code use the transport source and - * destination port fields, respectively. */ -#define icmp_type tp_src -#define icmp_code tp_dst - -/* Compare two sw_flow_keys and return true if they are the same flow, false - * otherwise. Wildcards and netmasks are not considered. */ -static inline int flow_keys_equal(const struct sw_flow_key *a, - const struct sw_flow_key *b) -{ - return !memcmp(a, b, offsetof(struct sw_flow_key, wildcards)); -} - -/* We need to manually make sure that the structure is 32-bit aligned, - * since we don't want garbage values in compiler-generated pads from - * messing up hash matches. - */ -static inline void check_key_align(void) -{ - BUILD_BUG_ON(sizeof(struct sw_flow_key) != 48); -} - -/* We keep actions as a separate structure because we need to be able to - * swap them out atomically when the modify command comes from a Flow - * Modify message. */ -struct sw_flow_actions { - size_t actions_len; - struct rcu_head rcu; - - struct ofp_action_header actions[0]; -}; - -/* Locking: - * - * - Readers must take rcu_read_lock and hold it the entire time that the flow - * must continue to exist. - * - * - Writers must hold dp_mutex. - */ -struct sw_flow { - struct sw_flow_key key; - - uint16_t priority; /* Only used on entries with wildcards. */ - uint16_t idle_timeout; /* Idle time before discarding (seconds). */ - uint16_t hard_timeout; /* Hard expiration time (seconds) */ - uint64_t used; /* Last used time (in jiffies). */ - uint8_t send_flow_rem; /* Send a flow removed to the controller */ - uint8_t emerg_flow; /* Emergency flow indicator */ - - struct sw_flow_actions *sf_acts; - - /* For use by table implementation. */ - struct list_head node; - struct list_head iter_node; - unsigned long serial; - void *private; - - spinlock_t lock; /* Lock this entry...mostly for stat updates */ - uint64_t created; /* When the flow was created (in jiffies_64). */ - uint64_t packet_count; /* Number of packets associated with this entry */ - uint64_t byte_count; /* Number of bytes associated with this entry */ - - struct rcu_head rcu; -}; - -int flow_matches_1wild(const struct sw_flow_key *, const struct sw_flow_key *); -int flow_matches_2wild(const struct sw_flow_key *, const struct sw_flow_key *); -int flow_matches_desc(const struct sw_flow_key *, const struct sw_flow_key *, - int); -int flow_matches_2desc(const struct sw_flow_key *, const struct sw_flow_key *, - int); -int flow_has_out_port(struct sw_flow *, uint16_t); -struct sw_flow *flow_alloc(size_t actions_len, gfp_t flags); -void flow_free(struct sw_flow *); -void flow_deferred_free(struct sw_flow *); -void flow_deferred_free_acts(struct sw_flow_actions *); -void flow_setup_actions(struct sw_flow *, const struct ofp_action_header *, - int); -void flow_replace_acts(struct sw_flow *, const struct ofp_action_header *, - size_t); -int flow_extract(struct sk_buff *, uint16_t in_port, struct sw_flow_key *); -void flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from); -void flow_fill_match(struct ofp_match* to, const struct sw_flow_key* from); -int flow_timeout(struct sw_flow *); - -void print_flow(const struct sw_flow_key *); - -static inline int iphdr_ok(struct sk_buff *skb) -{ - int nh_ofs = skb_network_offset(skb); - if (skb->len >= nh_ofs + sizeof(struct iphdr)) { - int ip_len = ip_hdrlen(skb); - return (ip_len >= sizeof(struct iphdr) - && pskb_may_pull(skb, nh_ofs + ip_len)); - } - return 0; -} - -static inline int tcphdr_ok(struct sk_buff *skb) -{ - int th_ofs = skb_transport_offset(skb); - if (pskb_may_pull(skb, th_ofs + sizeof(struct tcphdr))) { - int tcp_len = tcp_hdrlen(skb); - return (tcp_len >= sizeof(struct tcphdr) - && skb->len >= th_ofs + tcp_len); - } - return 0; -} - -static inline int udphdr_ok(struct sk_buff *skb) -{ - int th_ofs = skb_transport_offset(skb); - return pskb_may_pull(skb, th_ofs + sizeof(struct udphdr)); -} - -static inline int icmphdr_ok(struct sk_buff *skb) -{ - int th_ofs = skb_transport_offset(skb); - return pskb_may_pull(skb, th_ofs + sizeof(struct icmphdr)); -} - -#define TCP_FLAGS_OFFSET 13 -#define TCP_FLAG_MASK 0x3f - -static inline struct ofp_tcphdr *ofp_tcp_hdr(const struct sk_buff *skb) -{ - return (struct ofp_tcphdr *)skb_transport_header(skb); -} - -static inline void flow_used(struct sw_flow *flow, struct sk_buff *skb) -{ - unsigned long flags; - - flow->used = get_jiffies_64(); - - spin_lock_irqsave(&flow->lock, flags); - flow->packet_count++; - flow->byte_count += skb->len; - spin_unlock_irqrestore(&flow->lock, flags); -} - -extern struct kmem_cache *flow_cache; - -int flow_init(void); -void flow_exit(void); - -#endif /* flow.h */ diff --git a/openflow/datapath/forward.c b/openflow/datapath/forward.c deleted file mode 100644 index 40d2a332..00000000 --- a/openflow/datapath/forward.c +++ /dev/null @@ -1,642 +0,0 @@ -/* - * Distributed under the terms of the GNU GPL version 2. - * Copyright (c) 2007, 2008, 2009 The Board of Trustees of The Leland - * Stanford Junior University - */ - -#include -#include -#include -#include -#include -#include -#include "forward.h" -#include "datapath.h" -#include "openflow/nicira-ext.h" -#include "openflow/private-ext.h" -#include "dp_act.h" -#include "private-msg.h" -#include "openflow-ext.h" -#include "chain.h" -#include "flow.h" - -/* FIXME: do we need to use GFP_ATOMIC everywhere here? */ - - -static struct sk_buff *retrieve_skb(uint32_t id); -static void discard_skb(uint32_t id); - -/* 'skb' was received on port 'p', which may be a physical switch port, the - * local port, or a null pointer. Process it according to 'chain'. Returns 0 - * if successful, in which case 'skb' is destroyed, or -ESRCH if there is no - * matching flow, in which case 'skb' still belongs to the caller. */ -int run_flow_through_tables(struct sw_chain *chain, struct sk_buff *skb, - struct net_bridge_port *p) -{ - /* Ethernet address used as the destination for STP frames. */ - static const uint8_t stp_eth_addr[ETH_ALEN] - = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x01 }; - struct sw_flow_key key; - struct sw_flow *flow; - - if (flow_extract(skb, p ? p->port_no : OFPP_NONE, &key) - && (chain->dp->flags & OFPC_FRAG_MASK) == OFPC_FRAG_DROP) { - /* Drop fragment. */ - kfree_skb(skb); - return 0; - } - if (p && p->config & (OFPPC_NO_RECV | OFPPC_NO_RECV_STP) && - p->config & (compare_ether_addr(key.dl_dst, stp_eth_addr) - ? OFPPC_NO_RECV : OFPPC_NO_RECV_STP)) { - kfree_skb(skb); - return 0; - } - - flow = chain_lookup(chain, &key, 0); - if (likely(flow != NULL)) { - struct sw_flow_actions *sf_acts = rcu_dereference(flow->sf_acts); - flow_used(flow, skb); - execute_actions(chain->dp, skb, &key, - sf_acts->actions, sf_acts->actions_len, 0); - return 0; - } else { - return -ESRCH; - } -} - -/* 'skb' was received on port 'p', which may be a physical switch port, the - * local port, or a null pointer. Process it according to 'chain', sending it - * up to the controller if no flow matches. Takes ownership of 'skb'. */ -void fwd_port_input(struct sw_chain *chain, struct sk_buff *skb, - struct net_bridge_port *p) -{ - WARN_ON_ONCE(skb_shared(skb)); - WARN_ON_ONCE(skb->destructor); - if (run_flow_through_tables(chain, skb, p)) - dp_output_control(chain->dp, skb, chain->dp->miss_send_len, - OFPR_NO_MATCH); -} - -static int -recv_hello(struct sw_chain *chain, const struct sender *sender, - const void *msg) -{ - return dp_send_hello(chain->dp, sender, msg); -} - -static int -recv_barrier_request(struct sw_chain *chain, const struct sender *sender, - const void *msg) -{ - return dp_send_barrier_reply(chain->dp, sender, msg); -} - -static int -recv_features_request(struct sw_chain *chain, const struct sender *sender, - const void *msg) -{ - return dp_send_features_reply(chain->dp, sender); -} - -static int -recv_get_config_request(struct sw_chain *chain, const struct sender *sender, - const void *msg) -{ - return dp_send_config_reply(chain->dp, sender); -} - -static int -recv_set_config(struct sw_chain *chain, const struct sender *sender, - const void *msg) -{ - const struct ofp_switch_config *osc = msg; - int flags; - - flags = ntohs(osc->flags) & OFPC_FRAG_MASK; - if ((flags & OFPC_FRAG_MASK) != OFPC_FRAG_NORMAL - && (flags & OFPC_FRAG_MASK) != OFPC_FRAG_DROP) { - flags = (flags & ~OFPC_FRAG_MASK) | OFPC_FRAG_DROP; - } - chain->dp->flags = flags; - - chain->dp->miss_send_len = ntohs(osc->miss_send_len); - - return 0; -} - -static int -recv_packet_out(struct sw_chain *chain, const struct sender *sender, - const void *msg) -{ - const struct ofp_packet_out *opo = msg; - struct sk_buff *skb; - uint16_t v_code; - struct sw_flow_key key; - size_t actions_len = ntohs(opo->actions_len); - - if (actions_len > (ntohs(opo->header.length) - sizeof *opo)) { - if (net_ratelimit()) - printk(KERN_NOTICE "%s: message too short for number " - "of actions\n", chain->dp->netdev->name); - return -EINVAL; - } - - if (ntohl(opo->buffer_id) == (uint32_t) -1) { - int data_len = ntohs(opo->header.length) - sizeof *opo - actions_len; - - /* FIXME: there is likely a way to reuse the data in msg. */ - skb = alloc_skb(data_len, GFP_ATOMIC); - if (!skb) - return -ENOMEM; - - /* FIXME? We don't reserve NET_IP_ALIGN or NET_SKB_PAD since - * we're just transmitting this raw without examining anything - * at those layers. */ - skb_put(skb, data_len); - skb_copy_to_linear_data(skb, - (uint8_t *)opo->actions + actions_len, - data_len); - skb_reset_mac_header(skb); - } else { - skb = retrieve_skb(ntohl(opo->buffer_id)); - if (!skb) - return -ESRCH; - } - - dp_set_origin(chain->dp, ntohs(opo->in_port), skb); - - flow_extract(skb, ntohs(opo->in_port), &key); - - v_code = validate_actions(chain->dp, &key, opo->actions, actions_len); - if (v_code != ACT_VALIDATION_OK) { - dp_send_error_msg(chain->dp, sender, OFPET_BAD_ACTION, v_code, - msg, ntohs(opo->header.length)); - goto error; - } - - execute_actions(chain->dp, skb, &key, opo->actions, actions_len, 1); - - return 0; - -error: - kfree_skb(skb); - return -EINVAL; -} - -static int -recv_port_mod(struct sw_chain *chain, const struct sender *sender, - const void *msg) -{ - const struct ofp_port_mod *opm = msg; - - dp_update_port_flags(chain->dp, opm); - - return 0; -} - -static int -recv_echo_request(struct sw_chain *chain, const struct sender *sender, - const void *msg) -{ - return dp_send_echo_reply(chain->dp, sender, msg); -} - -static int -recv_echo_reply(struct sw_chain *chain, const struct sender *sender, - const void *msg) -{ - return 0; -} - -static int -add_flow(struct sw_chain *chain, const struct sender *sender, - const struct ofp_flow_mod *ofm) -{ - int error = -ENOMEM; - uint16_t v_code; - struct sw_flow *flow; - size_t actions_len = ntohs(ofm->header.length) - sizeof *ofm; - int overlap; - - /* Allocate memory. */ - flow = flow_alloc(actions_len, GFP_ATOMIC); - if (flow == NULL) - goto error; - - flow_extract_match(&flow->key, &ofm->match); - - v_code = validate_actions(chain->dp, &flow->key, ofm->actions, actions_len); - if (v_code != ACT_VALIDATION_OK) { - dp_send_error_msg(chain->dp, sender, OFPET_BAD_ACTION, v_code, - ofm, ntohs(ofm->header.length)); - goto error_free_flow; - } - - flow->priority = flow->key.wildcards ? ntohs(ofm->priority) : -1; - - if (ntohs(ofm->flags) & OFPFF_CHECK_OVERLAP) { - /* check whether there is any conflict */ - overlap = chain_has_conflict(chain, &flow->key, flow->priority, - false); - if (overlap){ - dp_send_error_msg(chain->dp, sender, - OFPET_FLOW_MOD_FAILED, - OFPFMFC_OVERLAP, - ofm, ntohs(ofm->header.length)); - goto error_free_flow; - } - } - - if (ntohs(ofm->flags) & OFPFF_EMERG) { - if (ntohs(ofm->idle_timeout) != OFP_FLOW_PERMANENT - || ntohs(ofm->hard_timeout) != OFP_FLOW_PERMANENT) { - dp_send_error_msg(chain->dp, sender, - OFPET_FLOW_MOD_FAILED, - OFPFMFC_BAD_EMERG_TIMEOUT, - ofm, ntohs(ofm->header.length)); - goto error_free_flow; - } - } - - /* Fill out flow. */ - flow->idle_timeout = ntohs(ofm->idle_timeout); - flow->hard_timeout = ntohs(ofm->hard_timeout); - flow->send_flow_rem = (ntohs(ofm->flags) & OFPFF_SEND_FLOW_REM) ? 1 : 0; - flow->emerg_flow = (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0; - flow_setup_actions(flow, ofm->actions, actions_len); - - /* Act. */ - error = chain_insert(chain, flow, - (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0); - if (error == -ENOBUFS) { - dp_send_error_msg(chain->dp, sender, OFPET_FLOW_MOD_FAILED, - OFPFMFC_ALL_TABLES_FULL, ofm, ntohs(ofm->header.length)); - goto error_free_flow; - } else if (error) - goto error_free_flow; - - error = 0; - if (ntohl(ofm->buffer_id) != (uint32_t) -1) { - struct sk_buff *skb = retrieve_skb(ntohl(ofm->buffer_id)); - if (skb) { - struct sw_flow_key key; - flow_used(flow, skb); - dp_set_origin(chain->dp, ntohs(ofm->match.in_port), skb); - flow_extract(skb, ntohs(ofm->match.in_port), &key); - execute_actions(chain->dp, skb, &key, ofm->actions, actions_len, 0); - } - else - error = -ESRCH; - } - return error; - -error_free_flow: - flow_free(flow); -error: - if (ntohl(ofm->buffer_id) != (uint32_t) -1) - discard_skb(ntohl(ofm->buffer_id)); - return error; -} - -static int -mod_flow(struct sw_chain *chain, const struct sender *sender, - const struct ofp_flow_mod *ofm) -{ - int error = -ENOMEM; - uint16_t v_code; - size_t actions_len = ntohs(ofm->header.length) - sizeof *ofm; - struct sw_flow *flow; - int strict; - - /* Allocate memory. */ - flow = flow_alloc(actions_len,GFP_ATOMIC); - if (flow == NULL) - goto error; - - flow_extract_match(&flow->key, &ofm->match); - - v_code = validate_actions(chain->dp, &flow->key, ofm->actions, actions_len); - if (v_code != ACT_VALIDATION_OK) { - dp_send_error_msg(chain->dp, sender, OFPET_BAD_ACTION, v_code, - ofm, ntohs(ofm->header.length)); - goto error_free_flow; - } - - flow->priority = flow->key.wildcards ? ntohs(ofm->priority) : -1; - strict = (ofm->command == htons(OFPFC_MODIFY_STRICT)) ? 1 : 0; - - /* First try to modify existing flows if any */ - /* if there is no matching flow, add it */ - if (!chain_modify(chain, &flow->key, flow->priority, strict, - ofm->actions, actions_len, - (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0)) { - /* Fill out flow. */ - flow->idle_timeout = ntohs(ofm->idle_timeout); - flow->hard_timeout = ntohs(ofm->hard_timeout); - flow->send_flow_rem = (ntohs(ofm->flags) & OFPFF_SEND_FLOW_REM) - ? 1 : 0; - flow->emerg_flow = (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0; - flow_setup_actions(flow, ofm->actions, actions_len); - error = chain_insert(chain, flow, - (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0); - if (error == -ENOBUFS) { - dp_send_error_msg(chain->dp, sender, - OFPET_FLOW_MOD_FAILED, - OFPFMFC_ALL_TABLES_FULL, - ofm, ntohs(ofm->header.length)); - goto error_free_flow; - } else if (error) { - goto error_free_flow; - } - } - - error = 0; - if (ntohl(ofm->buffer_id) != (uint32_t) -1) { - struct sk_buff *skb = retrieve_skb(ntohl(ofm->buffer_id)); - if (skb) { - struct sw_flow_key skb_key; - flow_extract(skb, ntohs(ofm->match.in_port), &skb_key); - execute_actions(chain->dp, skb, &skb_key, - ofm->actions, actions_len, 0); - } - else - error = -ESRCH; - } - return error; - -error_free_flow: - flow_free(flow); -error: - if (ntohl(ofm->buffer_id) != (uint32_t) -1) - discard_skb(ntohl(ofm->buffer_id)); - return error; -} - -static int -recv_flow(struct sw_chain *chain, const struct sender *sender, const void *msg) -{ - const struct ofp_flow_mod *ofm = msg; - uint16_t command = ntohs(ofm->command); - - if (command == OFPFC_ADD) { - return add_flow(chain, sender, ofm); - } else if ((command == OFPFC_MODIFY) || (command == OFPFC_MODIFY_STRICT)) { - return mod_flow(chain, sender, ofm); - } else if (command == OFPFC_DELETE) { - struct sw_flow_key key; - flow_extract_match(&key, &ofm->match); - return chain_delete(chain, &key, ofm->out_port, 0, 0, - (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0) - ? 0 : -ESRCH; - } else if (command == OFPFC_DELETE_STRICT) { - struct sw_flow_key key; - uint16_t priority; - flow_extract_match(&key, &ofm->match); - priority = key.wildcards ? ntohs(ofm->priority) : -1; - return chain_delete(chain, &key, ofm->out_port, priority, 1, - (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0) - ? 0 : -ESRCH; - } else { - return -ENOTSUPP; - } -} - -static int -recv_vendor(struct sw_chain *chain, const struct sender *sender, - const void *msg) -{ - const struct ofp_vendor_header *ovh = msg; - - switch(ntohl(ovh->vendor)) - { - case PRIVATE_VENDOR_ID: - return private_recv_msg(chain, sender, msg); - case OPENFLOW_VENDOR_ID: - return openflow_ext_recv_msg(chain, sender, msg); - default: - if (net_ratelimit()) - printk(KERN_NOTICE "%s: unknown vendor: 0x%x\n", - chain->dp->netdev->name, ntohl(ovh->vendor)); - dp_send_error_msg(chain->dp, sender, OFPET_BAD_REQUEST, - OFPBRC_BAD_VENDOR, msg, ntohs(ovh->header.length)); - return -EINVAL; - } -} - -/* 'msg', which is 'length' bytes long, was received across Netlink from - * 'sender'. Apply it to 'chain'. */ -int -fwd_control_input(struct sw_chain *chain, const struct sender *sender, - const void *msg, size_t length) -{ - - struct openflow_packet { - size_t min_size; - int (*handler)(struct sw_chain *, const struct sender *, - const void *); - }; - - static const struct openflow_packet packets[] = { - [OFPT_HELLO] = { - sizeof (struct ofp_header), - recv_hello, - }, - [OFPT_BARRIER_REQUEST] = { - sizeof (struct ofp_header), - recv_barrier_request, - }, - [OFPT_ECHO_REQUEST] = { - sizeof (struct ofp_header), - recv_echo_request, - }, - [OFPT_ECHO_REPLY] = { - sizeof (struct ofp_header), - recv_echo_reply, - }, - [OFPT_VENDOR] = { - sizeof (struct ofp_vendor_header), - recv_vendor, - }, - [OFPT_FEATURES_REQUEST] = { - sizeof (struct ofp_header), - recv_features_request, - }, - [OFPT_GET_CONFIG_REQUEST] = { - sizeof (struct ofp_header), - recv_get_config_request, - }, - [OFPT_SET_CONFIG] = { - sizeof (struct ofp_switch_config), - recv_set_config, - }, - [OFPT_PACKET_OUT] = { - sizeof (struct ofp_packet_out), - recv_packet_out, - }, - [OFPT_FLOW_MOD] = { - sizeof (struct ofp_flow_mod), - recv_flow, - }, - [OFPT_PORT_MOD] = { - sizeof (struct ofp_port_mod), - recv_port_mod, - } - }; - - struct ofp_header *oh; - - oh = (struct ofp_header *) msg; - if (oh->version != OFP_VERSION - && oh->type != OFPT_HELLO - && oh->type != OFPT_ERROR - && oh->type != OFPT_ECHO_REQUEST - && oh->type != OFPT_ECHO_REPLY - && oh->type != OFPT_VENDOR) - { - dp_send_error_msg(chain->dp, sender, OFPET_BAD_REQUEST, - OFPBRC_BAD_VERSION, msg, length); - return -EINVAL; - } - if (ntohs(oh->length) != length) { - if (net_ratelimit()) - printk(KERN_NOTICE "%s: received message length " - "wrong: %d/%d\n", chain->dp->netdev->name, - ntohs(oh->length), length); - return -EINVAL; - } - - if (oh->type < ARRAY_SIZE(packets)) { - const struct openflow_packet *pkt = &packets[oh->type]; - if (pkt->handler) { - if (length < pkt->min_size) - return -EFAULT; - return pkt->handler(chain, sender, msg); - } - } - dp_send_error_msg(chain->dp, sender, OFPET_BAD_REQUEST, - OFPBRC_BAD_TYPE, msg, length); - return -EINVAL; -} - -/* Packet buffering. */ - -#define OVERWRITE_SECS 1 -#define OVERWRITE_JIFFIES (OVERWRITE_SECS * HZ) - -struct packet_buffer { - struct sk_buff *skb; - uint32_t cookie; - unsigned long exp_jiffies; -}; - -static struct packet_buffer buffers[N_PKT_BUFFERS]; -static unsigned int buffer_idx; -static DEFINE_SPINLOCK(buffer_lock); - -uint32_t fwd_save_skb(struct sk_buff *skb) -{ - struct sk_buff *old_skb = NULL; - struct packet_buffer *p; - unsigned long int flags; - uint32_t id; - - /* FIXME: Probably just need a skb_clone() here. */ - skb = skb_copy(skb, GFP_ATOMIC); - if (!skb) - return -1; - - spin_lock_irqsave(&buffer_lock, flags); - buffer_idx = (buffer_idx + 1) & PKT_BUFFER_MASK; - p = &buffers[buffer_idx]; - if (p->skb) { - /* Don't buffer packet if existing entry is less than - * OVERWRITE_SECS old. */ - if (time_before(jiffies, p->exp_jiffies)) { - spin_unlock_irqrestore(&buffer_lock, flags); - kfree_skb(skb); - return -1; - } else { - /* Defer kfree_skb() until interrupts re-enabled. - * FIXME: we only need to do that if it has a - * destructor, but it never should since we orphan - * sk_buffs on entry. */ - old_skb = p->skb; - } - } - /* Don't use maximum cookie value since the all-bits-1 id is - * special. */ - if (++p->cookie >= (1u << PKT_COOKIE_BITS) - 1) - p->cookie = 0; - p->skb = skb; - p->exp_jiffies = jiffies + OVERWRITE_JIFFIES; - id = buffer_idx | (p->cookie << PKT_BUFFER_BITS); - spin_unlock_irqrestore(&buffer_lock, flags); - - if (old_skb) - kfree_skb(old_skb); - - return id; -} - -static struct sk_buff *retrieve_skb(uint32_t id) -{ - unsigned long int flags; - struct sk_buff *skb = NULL; - struct packet_buffer *p; - - spin_lock_irqsave(&buffer_lock, flags); - p = &buffers[id & PKT_BUFFER_MASK]; - if (p->cookie == id >> PKT_BUFFER_BITS) { - skb = p->skb; - p->skb = NULL; - } else { - if (net_ratelimit()) - printk(KERN_NOTICE "cookie mismatch: %x != %x\n", - id >> PKT_BUFFER_BITS, p->cookie); - } - spin_unlock_irqrestore(&buffer_lock, flags); - - return skb; -} - -void fwd_discard_all(void) -{ - int i; - - for (i = 0; i < N_PKT_BUFFERS; i++) { - struct sk_buff *skb; - unsigned long int flags; - - /* Defer kfree_skb() until interrupts re-enabled. */ - spin_lock_irqsave(&buffer_lock, flags); - skb = buffers[i].skb; - buffers[i].skb = NULL; - spin_unlock_irqrestore(&buffer_lock, flags); - - kfree_skb(skb); - } -} - -static void discard_skb(uint32_t id) -{ - struct sk_buff *old_skb = NULL; - unsigned long int flags; - struct packet_buffer *p; - - spin_lock_irqsave(&buffer_lock, flags); - p = &buffers[id & PKT_BUFFER_MASK]; - if (p->cookie == id >> PKT_BUFFER_BITS) { - /* Defer kfree_skb() until interrupts re-enabled. */ - old_skb = p->skb; - p->skb = NULL; - } - spin_unlock_irqrestore(&buffer_lock, flags); - - if (old_skb) - kfree_skb(old_skb); -} - -void fwd_exit(void) -{ - fwd_discard_all(); -} diff --git a/openflow/datapath/forward.h b/openflow/datapath/forward.h deleted file mode 100644 index 2aa9ee37..00000000 --- a/openflow/datapath/forward.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef FORWARD_H -#define FORWARD_H 1 - -#include -#include "datapath.h" -#include "flow.h" - -struct sk_buff; -struct sw_chain; -struct sender; - -/* Buffers are identified to userspace by a 31-bit opaque ID. We divide the ID - * into a buffer number (low bits) and a cookie (high bits). The buffer number - * is an index into an array of buffers. The cookie distinguishes between - * different packets that have occupied a single buffer. Thus, the more - * buffers we have, the lower-quality the cookie... */ -#define PKT_BUFFER_BITS 8 -#define N_PKT_BUFFERS (1 << PKT_BUFFER_BITS) -#define PKT_BUFFER_MASK (N_PKT_BUFFERS - 1) - -#define PKT_COOKIE_BITS (32 - PKT_BUFFER_BITS) - -#define UINT32_MAX 4294967295U -#define UINT16_MAX 65535 -#define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) - -void fwd_port_input(struct sw_chain *, struct sk_buff *, - struct net_bridge_port *); -int run_flow_through_tables(struct sw_chain *, struct sk_buff *, - struct net_bridge_port *); -int fwd_control_input(struct sw_chain *, const struct sender *, - const void *, size_t); - -uint32_t fwd_save_skb(struct sk_buff *skb); -void fwd_discard_all(void); -void fwd_exit(void); - -#endif /* forward.h */ diff --git a/openflow/datapath/hwtable_dummy/Modules.mk b/openflow/datapath/hwtable_dummy/Modules.mk deleted file mode 100644 index 08e56b1e..00000000 --- a/openflow/datapath/hwtable_dummy/Modules.mk +++ /dev/null @@ -1,7 +0,0 @@ -# Specify the module to build. -build_modules += ofdatapath_dummy -dist_modules += ofdatapath_dummy - -# Specify the source files that comprise the module. -ofdatapath_dummy_sources = \ - hwtable_dummy/hwtable_dummy.c diff --git a/openflow/datapath/hwtable_dummy/hwtable_dummy.c b/openflow/datapath/hwtable_dummy/hwtable_dummy.c deleted file mode 100644 index 82150d0f..00000000 --- a/openflow/datapath/hwtable_dummy/hwtable_dummy.c +++ /dev/null @@ -1,320 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "chain.h" -#include "table.h" -#include "flow.h" -#include "datapath.h" - -/* Max number of flow entries supported by the hardware */ -#define TMPL_MAX_FLOWS 8192 - -/* sw_flow private data for dummy table entries. */ -struct tmpl_flow { - struct list_head nodes; - /* XXX: If per-entry data is needed, define it here. */ -}; - -struct tmpl_flowtable { - struct sw_table flowtab; - unsigned int max_flows; - atomic_t num_flows; - struct list_head flows; - struct list_head iter_flows; - unsigned long int next_serial; -}; - -static struct sw_flow *tmpl_flowtable_lookup(struct sw_table *, - const struct sw_flow_key *); -static int tmpl_install_flow(struct sw_table *, struct sw_flow *); -static int tmpl_modify_flow(struct sw_table *, const struct sw_flow_key *, - uint16_t, int, const struct ofp_action_header *, - size_t); -static int do_uninstall(struct datapath *, struct sw_table *, struct sw_flow *, - enum ofp_flow_removed_reason); -static int tmpl_uninstall_flow(struct datapath *, struct sw_table *, - const struct sw_flow_key *, - uint16_t, uint16_t, int); -static int tmpl_flow_timeout(struct datapath *, struct sw_table *); -static void tmpl_destroy_flowtable(struct sw_table *); -static int tmpl_iterate_flowtable(struct sw_table *, const struct sw_flow_key *, - uint16_t, struct sw_table_position *, - int (*)(struct sw_flow *, void *), void *); -static void tmpl_get_flowstats(struct sw_table *, struct sw_table_stats *); -static struct sw_table *tmpl_create_flowtable(void); -static int __init tmpl_startup(void); -static void tmpl_cleanup(void); - -static struct sw_flow * -tmpl_flowtable_lookup(struct sw_table *flowtab, const struct sw_flow_key *key) -{ - struct tmpl_flowtable *myflowtab = (struct tmpl_flowtable *)flowtab; - struct sw_flow *flow; - - list_for_each_entry(flow, &myflowtab->flows, node) { - if (flow_matches_1wild(key, &flow->key)) { - return flow; - } - } - - return NULL; -} - -static int -tmpl_install_flow(struct sw_table *flowtab, struct sw_flow *flow) -{ - /* XXX: Use a data cache? */ - flow->private = kzalloc(sizeof(struct tmpl_flow), GFP_ATOMIC); - if (flow->private == NULL) - return 0; - - /* XXX: Do whatever needs to be done to insert an entry in hardware. - * If the entry can't be inserted, return 0. This stub code doesn't - * do anything yet, so we're going to return 0... you shouldn't (and - * you should update n_flows in struct tmpl_flowtable, too). - */ - kfree(flow->private); - return 0; -} - -static int -tmpl_modify_flow(struct sw_table *flowtab, const struct sw_flow_key *key, - uint16_t priority, int strict, - const struct ofp_action_header *actions, size_t actions_len) -{ - struct tmpl_flowtable *myflowtab = (struct tmpl_flowtable *)flowtab; - struct sw_flow *flow; - unsigned int count = 0; - - list_for_each_entry(flow, &myflowtab->flows, node) { - if (flow_matches_desc(&flow->key, key, strict) - && (!strict || (flow->priority == priority))) { - flow_replace_acts(flow, actions, actions_len); - /* XXX: Do whatever is necessary to modify the entry - * in hardware - */ - count++; - } - } - - return count; -} - -static int -do_uninstall(struct datapath *dpinst, struct sw_table *flowtab, - struct sw_flow *flow, enum ofp_flow_removed_reason reason) -{ - /* XXX: Remove the entry from hardware. If you need to do any other - * clean-up associated with the entry, do it here. - */ - dp_send_flow_end(dpinst, flow, reason); - list_del_rcu(&flow->node); - list_del_rcu(&flow->iter_node); - flow_deferred_free(flow); - return 1; -} - -static int -tmpl_uninstall_flow(struct datapath *dpinst, struct sw_table *flowtab, - const struct sw_flow_key *key, uint16_t out_port, - uint16_t priority, int strict) -{ - struct tmpl_flowtable *myflowtab = (struct tmpl_flowtable *)flowtab; - struct sw_flow *flow; - unsigned int count = 0; - - list_for_each_entry(flow, &myflowtab->flows, node) { - if (flow_matches_desc(&flow->key, key, strict) - && (!strict || (flow->priority == priority))) - count += do_uninstall(dpinst, flowtab, - flow, OFPRR_DELETE); - } - - if (count != 0) - atomic_sub(count, &myflowtab->num_flows); - return count; -} - -static int -tmpl_flow_timeout(struct datapath *dpinst, struct sw_table *flowtab) -{ - struct tmpl_flowtable *myflowtab = (struct tmpl_flowtable *)flowtab; - struct sw_flow *flow; - int num_uninst_flows = 0; - uint64_t num_forw_packets = 0; - uint64_t num_forw_bytes = 0; - int reason; - - mutex_lock(&dp_mutex); - list_for_each_entry(flow, &myflowtab->flows, node) { - /* XXX: Retrieve the packet and byte counts associated with this - * entry and store them in "packet_count" and "byte_count". - */ -#if 0 - num_forw_pakcets = flow->packet_count + get_hwmib(...); - num_forw_bytes = flow->byte_count + get_hwmib(...); -#endif - if (num_forw_packets > flow->packet_count - && flow->idle_timeout != OFP_FLOW_PERMANENT) { - flow->packet_count = num_forw_packets; - flow->byte_count = num_forw_bytes; - flow->used = get_jiffies_64(); - } - reason = flow_timeout(flow); - if (reason >= 0) { - num_uninst_flows += do_uninstall(dpinst, flowtab, - flow, reason); - } - } - mutex_unlock(&dp_mutex); - - if (num_uninst_flows != 0) - atomic_sub(num_uninst_flows, &myflowtab->num_flows); - return num_uninst_flows; -} - -static void -tmpl_destroy_flowtable(struct sw_table *flowtab) -{ - struct tmpl_flowtable *myflowtab = (struct tmpl_flowtable *)flowtab; - - if (myflowtab == NULL) { - return; - } - - /* XXX: This table is being destroyed, so free any data that you - * don't want to leak. - */ - while (!list_empty(&myflowtab->flows)) { - struct sw_flow *flow = list_entry(myflowtab->flows.next, - struct sw_flow, node); - list_del(&flow->node); - flow_free(flow); - } - - kfree(myflowtab); -} - -static int -tmpl_iterate_flowtable(struct sw_table *flowtab, const struct sw_flow_key *key, - uint16_t out_port, struct sw_table_position *position, - int (*callback) (struct sw_flow *, void *), - void *private) -{ - struct tmpl_flowtable *myflowtab = (struct tmpl_flowtable *)flowtab; - struct sw_flow *flow; - unsigned long start; - int error = 0; - - start = ~position->private[0]; - list_for_each_entry(flow, &myflowtab->iter_flows, iter_node) { - if (flow->serial <= start - && flow_matches_2wild(key, &flow->key)) { - error = callback(flow, private); - if (error) { - position->private[0] = ~flow->serial; - return error; - } - } - } - - return error; -} - -static void -tmpl_get_flowstats(struct sw_table *flowtab, struct sw_table_stats *stats) -{ - struct tmpl_flowtable *myflowtab = (struct tmpl_flowtable *)flowtab; - - stats->name = "template"; - stats->wildcards = OFPFW_ALL; /* XXX: Set this appropriately */ - stats->n_flows = atomic_read(&myflowtab->num_flows); - stats->max_flows = myflowtab->max_flows; - stats->n_matched = flowtab->n_matched; -} - -static struct sw_table * -tmpl_create_flowtable(void) -{ - struct tmpl_flowtable *myflowtab; - struct sw_table *flowtab; - - myflowtab = kzalloc(sizeof(*myflowtab), GFP_KERNEL); - if (myflowtab == NULL) - return NULL; - - flowtab = &myflowtab->flowtab; - flowtab->lookup = tmpl_flowtable_lookup; - flowtab->insert = tmpl_install_flow; - flowtab->modify = tmpl_modify_flow; - flowtab->delete = tmpl_uninstall_flow; - flowtab->timeout = tmpl_flow_timeout; - flowtab->destroy = tmpl_destroy_flowtable; - flowtab->iterate = tmpl_iterate_flowtable; - flowtab->stats = tmpl_get_flowstats; - - myflowtab->max_flows = TMPL_MAX_FLOWS; - atomic_set(&myflowtab->num_flows, 0); - INIT_LIST_HEAD(&myflowtab->flows); - INIT_LIST_HEAD(&myflowtab->iter_flows); - myflowtab->next_serial = 0; - - return flowtab; -} - -static int __init -tmpl_startup(void) -{ - return chain_set_hw_hook(tmpl_create_flowtable, THIS_MODULE); -} - -static void -tmpl_cleanup(void) -{ - chain_clear_hw_hook(); -} - -module_init(tmpl_startup); -module_exit(tmpl_cleanup); - -MODULE_DESCRIPTION("Fastpath Extension Template for OpenFlow Switch"); -MODULE_AUTHOR("Copyright (c) 2008, 2009 " - "The Board of Trustees of The Leland Stanford Junior University"); -MODULE_LICENSE("GPL"); diff --git a/openflow/datapath/hwtable_nf2/Modules.mk b/openflow/datapath/hwtable_nf2/Modules.mk deleted file mode 100644 index 35674911..00000000 --- a/openflow/datapath/hwtable_nf2/Modules.mk +++ /dev/null @@ -1,19 +0,0 @@ -# Specify the module to build. -build_modules += ofdatapath_netfpga -dist_modules += ofdatapath_netfpga - -# Specify the source files that comprise the module. -ofdatapath_netfpga_sources = \ - hwtable_nf2/nf2_flowtable.c \ - hwtable_nf2/nf2_procfs.c \ - hwtable_nf2/nf2_openflow.c \ - hwtable_nf2/nf2_lib.c - -ofdatapath_netfpga_headers = \ - hwtable_nf2/nf2.h \ - hwtable_nf2/nf2_reg.h \ - hwtable_nf2/nf2_hwapi.h \ - hwtable_nf2/nf2_flowtable.h \ - hwtable_nf2/nf2_procfs.h \ - hwtable_nf2/nf2_openflow.h \ - hwtable_nf2/nf2_lib.h diff --git a/openflow/datapath/hwtable_nf2/README b/openflow/datapath/hwtable_nf2/README deleted file mode 100644 index da700f01..00000000 --- a/openflow/datapath/hwtable_nf2/README +++ /dev/null @@ -1,78 +0,0 @@ -NetFPGA Hardware Table - Date - 09/04/09 ----------------------------------------- - -The NetFPGA Hardware Table creates a single software table that contains all -the flows that are currently held in the NetFPGA card. The card itself splits -exact match flows into SRAM and wildcard match flows into TCAMs. Currently -there are 24 usable wildcard flow entries and 32,768 available exact match -entries. - -Installation ----------------------------------------- - -First build OpenFlow ensuring you include the directive to build the -openflow_netfpga2 hardware table in your configure statement: - - % ./configure --with-l26=/lib/modules/`uname -r` --enable-hw-tables=nf2 - -To get debugging output from the NetFPGA hardware table uncomment the following -line from within /datapath/hwtable_nf2/nf2_flowtable.h, then recompile: - - #define NF2_DEBUG 1 - -For further help regarding building OpenFlow please see the INSTALL file in -the OpenFlow root directory. - -Platform support ----------------- - -OpenFlow v0.9 with hwtable_nf2 has been tested on CentOS 5.2(Linux 2.6.18), -which is the officially supported platform of NetFPGA. - -Running ----------------------------------------- - -Use nf2_download to download the openflow_switch.bit file that is located in -the /datapath/hwtable_nf2 folder: - - % nf2_download -r /datapath/hwtable_nf2/openflow_switch.bit - -'-r' option enables PHY interrupt for its link status changing, and OpenFlow -switch can detect it. - -Install the OpenFlow kernel module: - - % insmod /datapath/linux-2.6/openflow_mod.ko - -Install the NetFPGA Hardware Table kernel module: - - % insmod /datapath/linux-2.6/openflow_netfpga2_mod.ko - -Create an OpenFlow datapath: - - % /utilities/dpctl adddp nl:0 - -Add the NetFPGA interfaces to the datapath: - - % /utilities/dpctl addif nl:0 nf2c0 - % /utilities/dpctl addif nl:0 nf2c1 - % /utilities/dpctl addif nl:0 nf2c2 - % /utilities/dpctl addif nl:0 nf2c3 - -At this point your OpenFlow switch should be ready to go. - -While you are running OpenFlow switch, you can check the hardware information -including its bitfile version as follows: - - % cat /proc/net/openflow-netfpga - -Known Bugs ----------------------------------------- -* There is currently no support for priority amongst wildcard-match entries. - -Contact -------- -e-mail: openflow-discuss@lists.stanford.edu -www: http://openflowswitch.org/ - diff --git a/openflow/datapath/hwtable_nf2/nf2.h b/openflow/datapath/hwtable_nf2/nf2.h deleted file mode 100644 index 847d2b10..00000000 --- a/openflow/datapath/hwtable_nf2/nf2.h +++ /dev/null @@ -1,424 +0,0 @@ -/* **************************************************************************** - * $Id: nf2.h 3546 2008-04-03 00:12:27Z grg $ - * - * Module: nf2.h - * Project: NetFPGA 2 Linux Kernel Driver - * Description: Header file for kernel driver - * - * Change history: - * - */ - -#ifndef _NF2_H -#define _NF2_H 1 - -#define NF2_DEV_NAME "nf2" - -#include - -/* Maximum number of interfaces */ -#ifndef MAX_IFACE -#define MAX_IFACE 4 -#endif - -/* - * Register names and locations. - * - * Note that these names are not necessarily identical to - * those in NF2/hw/common/src/defines - */ - -/* CPCI registers */ -#define CPCI_REG_ID 0x000 -#define CPCI_REG_BOARD_ID 0x004 -#define CPCI_REG_CTRL 0x008 -#define CPCI_REG_RESET 0x00c -#define CPCI_REG_ERROR 0x010 -#define CPCI_REG_DUMMY 0x020 -#define CPCI_REG_INTERRUPT_MASK 0x040 -#define CPCI_REG_INTERRUPT_STATUS 0x044 -#define CPCI_REG_PROG_DATA 0x100 -#define CPCI_REG_PROG_STATUS 0x104 -#define CPCI_REG_PROG_CTRL 0x108 -#define CPCI_REG_DMA_I_ADDR 0x140 -#define CPCI_REG_DMA_E_ADDR 0x144 -#define CPCI_REG_DMA_I_SIZE 0x148 -#define CPCI_REG_DMA_E_SIZE 0x14c -#define CPCI_REG_DMA_I_CTRL 0x150 -#define CPCI_REG_DMA_E_CTRL 0x154 -#define CPCI_REG_DMA_MAX_XFER_TIME 0x180 -#define CPCI_REG_DMA_MAX_RETRIES 0x184 -#define CPCI_REG_CNET_MAX_XFER_TIME 0x188 -#define CPCI_REG_DMA_I_PKT_CNT 0x400 -#define CPCI_REG_DMA_E_PKT_CNT 0x404 -#define CPCI_REG_CPCI_REG_RD_CNT 0x408 -#define CPCI_REG_CPCI_REG_WR_CNT 0x40c -#define CPCI_REG_CNET_REG_RD_CNT 0x410 -#define CPCI_REG_CNET_REG_WR_CNT 0x414 - -#define CPCI_REG_N_CLK_COUNT 0x500 -#define CPCI_REG_P_MAX 0x504 -#define CPCI_REG_N_EXP 0x508 -#define CPCI_REG_P_CLK_CTR 0x510 -#define CPCI_REG_RESET_CTR 0x520 - -/* Base address for CNET registers */ -#define CNET_REG_BASE 0x400000 - -/* Added by nweaver for building memory manipulation - utilities */ -/* 2 MB SRAM size on current board, MAX and SIZE will - need to be changed if upgraded to 4 MB SRAMs */ -#define SRAM_SIZE 0x200000 - -#define SRAM_1_BASE 0x800000 -#define SRAM_1_MAX 0x9FFFFF - -#define SRAM_2_BASE 0xC00000 -#define SRAM_2_MAX 0xDFFFFF -/* end nweaver addition */ - -/* Device ID registers */ -#define NF2_DEVICE_ID 0x0400000 -#define NF2_REVISION 0x0400004 -#define NF2_DEVICE_STR 0x0400008 - -/* CNET registers */ -#define CNET_REG_ID (CNET_REG_BASE + 0x000) -#define CNET_REG_CTRL (CNET_REG_BASE + 0x004) -#define CNET_REG_RESET (CNET_REG_BASE + 0x008) -#define CNET_REG_ERROR (CNET_REG_BASE + 0x00C) -#define CNET_REG_ENABLE (CNET_REG_BASE + 0x010) -#define CNET_REG_WR_SRAM1_EOP (CNET_REG_BASE + 0x0F0) -#define CNET_REG_RD_SRAM1_EOP (CNET_REG_BASE + 0x0F4) -#define CNET_REG_WR_SRAM2_EOP (CNET_REG_BASE + 0x0F8) -#define CNET_REG_RD_SRAM2_EOP (CNET_REG_BASE + 0x0FC) -#define CNET_REG_MF_STATUS_0 (CNET_REG_BASE + 0x100) -#define CNET_REG_MF_TX_PKTS_SENT_0 (CNET_REG_BASE + 0x104) -#define CNET_REG_MF_RX_PKTS_RCVD_0 (CNET_REG_BASE + 0x108) -#define CNET_REG_MF_RX_PKTS_LOST_0 (CNET_REG_BASE + 0x10C) -#define CNET_REG_MAC_CONFIG_0 (CNET_REG_BASE + 0x110) -#define CNET_REG_MF_STATUS_1 (CNET_REG_BASE + 0x140) -#define CNET_REG_MF_TX_PKTS_SENT_1 (CNET_REG_BASE + 0x144) -#define CNET_REG_MF_RX_PKTS_RCVD_1 (CNET_REG_BASE + 0x148) -#define CNET_REG_MF_RX_PKTS_LOST_1 (CNET_REG_BASE + 0x14C) -#define CNET_REG_MAC_CONFIG_1 (CNET_REG_BASE + 0x150) -#define CNET_REG_MF_STATUS_2 (CNET_REG_BASE + 0x180) -#define CNET_REG_MF_TX_PKTS_SENT_2 (CNET_REG_BASE + 0x184) -#define CNET_REG_MF_RX_PKTS_RCVD_2 (CNET_REG_BASE + 0x188) -#define CNET_REG_MF_RX_PKTS_LOST_2 (CNET_REG_BASE + 0x18C) -#define CNET_REG_MAC_CONFIG_2 (CNET_REG_BASE + 0x190) -#define CNET_REG_MF_STATUS_3 (CNET_REG_BASE + 0x1C0) -#define CNET_REG_MF_TX_PKTS_SENT_3 (CNET_REG_BASE + 0x1C4) -#define CNET_REG_MF_RX_PKTS_RCVD_3 (CNET_REG_BASE + 0x1C8) -#define CNET_REG_MF_RX_PKTS_LOST_3 (CNET_REG_BASE + 0x1CC) -#define CNET_REG_MAC_CONFIG_3 (CNET_REG_BASE + 0x1D0) -#define CNET_REG_RXQ_NUM_PKTS_0 (CNET_REG_BASE + 0x200) -#define CNET_REG_RXQ_POINTERS_0 (CNET_REG_BASE + 0x204) -#define CNET_REG_RXQ_NUM_PKTS_1 (CNET_REG_BASE + 0x240) -#define CNET_REG_RXQ_POINTERS_1 (CNET_REG_BASE + 0x244) -#define CNET_REG_RXQ_NUM_PKTS_2 (CNET_REG_BASE + 0x280) -#define CNET_REG_RXQ_POINTERS_2 (CNET_REG_BASE + 0x284) -#define CNET_REG_RXQ_NUM_PKTS_3 (CNET_REG_BASE + 0x2C0) -#define CNET_REG_RXQ_POINTERS_3 (CNET_REG_BASE + 0x2C4) - -#define CNET_REG_MF_RX_PKTS_LOST_BAD_FCS_0 (CNET_REG_BASE + 0x114) -#define CNET_REG_MF_RX_PKTS_LOST_FULL_FIFO_0 (CNET_REG_BASE+0x118) -#define CNET_REG_MF_RX_GOOD_PKTS_RCVD_0 (CNET_REG_BASE+0x11C) -#define CNET_REG_MF_RX_GOOD_BYTES_RCVD_0 (CNET_REG_BASE+0x120) -#define CNET_REG_MF_TX_BYTES_SENT_0 (CNET_REG_BASE+0x124) -#define CNET_REG_MF_RX_PKTS_LOST_BAD_FCS_1 (CNET_REG_BASE+0x154) -#define CNET_REG_MF_RX_PKTS_LOST_FULL_FIFO_1 (CNET_REG_BASE+0x158) -#define CNET_REG_MF_RX_GOOD_PKTS_RCVD_1 (CNET_REG_BASE+0x15C) -#define CNET_REG_MF_RX_GOOD_BYTES_RCVD_1 (CNET_REG_BASE+0x160) -#define CNET_REG_MF_TX_BYTES_SENT_1 (CNET_REG_BASE+0x164) -#define CNET_REG_MF_RX_PKTS_LOST_BAD_FCS_2 (CNET_REG_BASE+0x194) -#define CNET_REG_MF_RX_PKTS_LOST_FULL_FIFO_2 (CNET_REG_BASE+0x198) -#define CNET_REG_MF_RX_GOOD_PKTS_RCVD_2 (CNET_REG_BASE+0x19C) -#define CNET_REG_MF_RX_GOOD_BYTES_RCVD_2 (CNET_REG_BASE+0x1A0) -#define CNET_REG_MF_TX_BYTES_SENT_2 (CNET_REG_BASE+0x1A4) -#define CNET_REG_MF_RX_PKTS_LOST_BAD_FCS_3 (CNET_REG_BASE+0x1D4) -#define CNET_REG_MF_RX_PKTS_LOST_FULL_FIFO_3 (CNET_REG_BASE+0x1D8) -#define CNET_REG_MF_RX_GOOD_PKTS_RCVD_3 (CNET_REG_BASE+0x1DC) -#define CNET_REG_MF_RX_GOOD_BYTES_RCVD_3 (CNET_REG_BASE+0x1E0) -#define CNET_REG_MF_TX_BYTES_SENT_3 (CNET_REG_BASE+0x1E4) - -#define CNET_MAC_CLK_CHK_CTRL (CNET_REG_BASE + 0xF00) -#define CNET_MAC_CLK_CHK_CNT_VALUE (CNET_REG_BASE + 0xF04) - -/* Base address for CNET PHY registers */ -#define PHY_REG_BASE 0x600000 - -#define PHY_REG_CMD (PHY_REG_BASE) -#define PHY_REG_STATUS (PHY_REG_BASE) - -/* - * CPCI register masks - */ - -/* ID Masks */ -#define ID_VERSION 0x00FFFFFF -#define ID_REVISION 0xFF000000 - -/* Board ID Masks */ -#define BOARD_ID 0x00000F00 -#define BOARD_ID_CONTROL 0x00000001 - -/* Control masks */ -#define CTRL_CNET_RESET 0x00000100 -#define CTRL_LED 0x00000001 - -/* RESET masks */ -#define RESET_CPCI 0x00000001 - -/* Error masks */ -#define ERR_CNET_READ_TIMEOUT 0x02000000 -#define ERR_CNET_ERROR 0x01000000 -#define ERR_PROG_BUF_OVERFLOW 0x00020000 -#define ERR_PROG_ERROR 0x00010000 -#define ERR_DMA_TIMEOUT 0x00000400 -#define ERR_DMA_RETRY_CNT_EXPIRED 0x00000200 -#define ERR_DMA_BUF_OVERFLOW 0x00000100 -#define ERR_DMA_RD_SIZE_ERROR 0x00000040 -#define ERR_DMA_WR_SIZE_ERROR 0x00000020 -#define ERR_DMA_RD_ADDR_ERROR 0x00000010 -#define ERR_DMA_WR_ADDR_ERROR 0x00000008 -#define ERR_DMA_RD_MAC_ERROR 0x00000004 -#define ERR_DMA_WR_MAC_ERROR 0x00000002 -#define ERR_DMA_FATAL_ERROR 0x00000001 - -#define ERR_DMA_SETUP_ERROR ( ERR_DMA_WR_MAC_ERROR | \ - ERR_DMA_RD_MAC_ERROR | \ - ERR_DMA_WR_ADDR_ERROR | \ - ERR_DMA_RD_ADDR_ERROR | \ - ERR_DMA_WR_SIZE_ERROR | \ - ERR_DMA_RD_SIZE_ERROR ) - -/* Interrupt masks */ -#define INT_DMA_RX_COMPLETE 0x80000000 -#define INT_DMA_TX_COMPLETE 0x40000000 -#define INT_PHY_INTERRUPT 0x20000000 -#define INT_PKT_AVAIL 0x00000100 -#define INT_CNET_ERROR 0x00000020 -#define INT_CNET_READ_TIMEOUT 0x00000010 -#define INT_PROG_ERROR 0x00000008 -#define INT_DMA_TRANSFER_ERROR 0x00000004 -#define INT_DMA_SETUP_ERROR 0x00000002 -#define INT_DMA_FATAL_ERROR 0x00000001 - -#define INT_UNKNOWN ~(INT_DMA_RX_COMPLETE | \ - INT_DMA_TX_COMPLETE | \ - INT_PHY_INTERRUPT | \ - INT_PKT_AVAIL | \ - INT_CNET_ERROR | \ - INT_CNET_READ_TIMEOUT | \ - INT_PROG_ERROR | \ - INT_DMA_TRANSFER_ERROR | \ - INT_DMA_SETUP_ERROR | \ - INT_DMA_FATAL_ERROR) - -/* Programming status */ -#define PROG_INIT 0x00010000 -#define PROG_DONE 0x00000100 -#define PROG_FIFO_EMPTY 0x00000002 -#define PROG_IN_PROGRESS 0x00000001 - -/* Programming control */ -#define PROG_CTRL_RESET 0x00000001 - -/* DMA control */ -#define DMA_CTRL_MAC 0x00000300 -#define DMA_CTRL_OWNER 0x00000001 - -/* - * CNET register masks - */ - -/* Reset masks */ -#define CNET_RESET_MAC 0x0000000F -#define CNET_RESET_MAC_3 0x00000008 -#define CNET_RESET_MAC_2 0x00000004 -#define CNET_RESET_MAC_1 0x00000002 -#define CNET_RESET_MAC_0 0x00000001 - -/* Error masks */ -#define CNET_ERROR_TX_UNDERRUN_MAC 0x000000F0 -#define CNET_ERROR_TX_UNDERRUN_MAC_3 0x00000080 -#define CNET_ERROR_TX_UNDERRUN_MAC_2 0x00000040 -#define CNET_ERROR_TX_UNDERRUN_MAC_1 0x00000020 -#define CNET_ERROR_TX_UNDERRUN_MAC_0 0x00000010 -#define CNET_ERROR_TX_OVERRUN_MAC 0x0000000F -#define CNET_ERROR_TX_OVERRUN_MAC_3 0x00000008 -#define CNET_ERROR_TX_OVERRUN_MAC_2 0x00000004 -#define CNET_ERROR_TX_OVERRUN_MAC_1 0x00000002 -#define CNET_ERROR_TX_OVERRUN_MAC_0 0x00000001 - -/* Enable masks */ -#define CNET_ENABLE_RX_FIFO 0x0000F000 -#define CNET_ENABLE_RX_FIFO_3 0x00008000 -#define CNET_ENABLE_RX_FIFO_2 0x00004000 -#define CNET_ENABLE_RX_FIFO_1 0x00002000 -#define CNET_ENABLE_RX_FIFO_0 0x00001000 -#define CNET_ENABLE_TX_MAC 0x00000F00 -#define CNET_ENABLE_TX_MAC_3 0x00000800 -#define CNET_ENABLE_TX_MAC_2 0x00000400 -#define CNET_ENABLE_TX_MAC_1 0x00000200 -#define CNET_ENABLE_TX_MAC_0 0x00000100 -#define CNET_ENABLE_DEBUG_TRISTATE 0x00000004 -#define CNET_ENABLE_INGRESS_ARBITER 0x00000002 -#define CNET_ENABLE_RX_DMA 0x00000001 - -/* MF Status masks */ -#define CNET_MF_STATUS_RX_FIFO_EMPTY 0x02000000 -#define CNET_MF_STATUS_RX_PKT_AVAIL 0x01000000 -#define CNET_MF_STATUS_RX_NUM_PKTS 0x00FF0000 -#define CNET_MF_STATUS_TX_FIFO_FULL 0x00000200 -#define CNET_MF_STATUS_TX_FIFO_NO_MAX_PKT 0x00000100 -#define CNET_MF_STATUS_TX_NUM_PKTS 0x000000FF - -/* MAC Config masks */ -#define CNET_MAC_CFG_FULL_DUPLEX 0x00000020 -#define CNET_MAC_CFG_TX_FCS_SUPPLIED 0x00000010 -#define CNET_MAC_CFG_RX_WANT_FCS 0x00000008 -#define CNET_MAC_CFG_JUMBO_ENABLE 0x00000004 - -#define CNET_MAC_CFG_SPEED 0x00000002 -#define CNET_MAC_CFG_1000_MBPS 0x00000002 -#define CNET_MAC_CFG_100_MBPS 0x00000001 -#define CNET_MAC_CFG_10_MBPS 0x00000000 - -#define CNET_RXQ_WR_PTR 0x00FF0000 -#define CNET_RXQ_RD_PTR 0x000000FF - -/* Phy register masks */ -#define PHY_RD_WR 0x80000000 -#define PHY_PHY 0x03000000 -#define PHY_ADDR 0x001F0000 -#define PHY_DATA 0x0000FFFF - -#define PHY_DONE 0x80000000 -#define PHY_DONE_CNT 0x001F0000 - -/* Defines to calculate register values */ -/* CPCI Funcs */ -#define NF2_GET_VERSION(x) (x & 0xFFFFFF) -#define NF2_GET_REVISION(x) ((x & 0xFF000000) >> 24) - -#define NF2_GET_BOARD_ID(x) ((x & BOARD_ID) >> 8) -#define NF2_GET_CONTROL(x) (x & BOARD_ID_CONTROL) - -#define NF2_GET_CNET_RESET(x) ((x & CTRL_CNET_RESET) >> 8) -#define NF2_GET_LED(x) (x & CTRL_LED) - -#define NF2_GET_RESET(x) (x & RESET_CPCI) - -#define NF2_GET_CNET_READ_TIMEOUT(x) ((x & ERR_CNET_READ_TIMEOUT) >> 25) -#define NF2_GET_CNET_ERROR(x) ((x & ERR_CNET_ERROR) >> 24) -#define NF2_GET_PROG_BUF_OVERFLOW(x) ((x & ERR_PROG_BUF_OVERFLOW) >> 12) -#define NF2_GET_PROG_ERROR(x) ((x & ERR_PROG_ERROR) >> 11) -#define NF2_GET_DMA_TIMEOUT(x) ((x & ERR_DMA_TIMEOUT) >> 10) -#define NF2_GET_DMA_RETRY_CNT_EXPIRED(x) \ - ((x & ERR_DMA_RETRY_CNT_EXPIRED) >> 9) -#define NF2_GET_DMA_BUF_OVERFLOW(x) ((x & ERR_DMA_BUF_OVERFLOW) >> 8) -#define NF2_GET_DMA_RD_SIZE_ERROR(x) ((x & ERR_DMA_RD_SIZE_ERROR) >> 6) -#define NF2_GET_DMA_WR_SIZE_ERROR(x) ((x & ERR_DMA_WR_SIZE_ERROR) >> 5) -#define NF2_GET_DMA_RD_ADDR_ERROR(x) ((x & ERR_DMA_RD_ADDR_ERROR) >> 4) -#define NF2_GET_DMA_WR_ADDR_ERROR(x) ((x & ERR_DMA_WR_ADDR_ERROR) >> 3) -#define NF2_GET_DMA_RD_MAC_ERROR(x) ((x & ERR_DMA_RD_MAC_ERROR) >> 2) -#define NF2_GET_DMA_WR_MAC_ERROR(x) ((x & ERR_DMA_WR_MAC_ERROR) >> 1) -#define NF2_GET_DMA_FATAL_ERROR(x) (x & ERR_DMA_FATAL_ERROR) - -#define NF2_GET_INT_DMA_TX_COMPLETE(x) ((x & INT_DMA_TX_COMPLETE) >> 31) -#define NF2_GET_INT_DMA_RX_COMPLETE(x) ((x & INT_DMA_RX_COMPLETE) >> 30) -#define NF2_GET_INT_PHY_INTERRUPT(x) ((x & INT_PHY_INTERRUPT) >> 29) -#define NF2_GET_INT_PKT_AVAIL(x) ((x & INT_PKT_AVAIL) >> 8) -#define NF2_GET_INT_CNET_ERROR(x) ((x & INT_CNET_ERROR) >> 5) -#define NF2_GET_INT_CNET_READ_TIMEOUT(x) \ - ((x & INT_CNET_READ_TIMEOUT) >> 4) -#define NF2_GET_INT_PROG_ERROR(x) ((x & INT_PROG_ERROR) >> 3) -#define NF2_GET_INT_DMA_TRANSFER_ERROR(x) \ - ((x & INT_DMA_TRANSFER_ERROR) >> 2) -#define NF2_GET_INT_DMA_SETUP_ERROR(x) ((x & INT_DMA_SETUP_ERROR) >> 1) -#define NF2_GET_INT_DMA_FATAL_ERROR(x) (x & INT_DMA_FATAL_ERROR) - -#define NF2_GET_PROG_INIT(x) ((x & PROG_INIT) >> 16) -#define NF2_GET_PROG_DONE(x) ((x & PROG_DONE) >> 8) -#define NF2_GET_PROG_FIFO_EMPTY(x) ((x & PROG_FIFO_EMPTY) >> 1) -#define NF2_GET_PROG_IN_PROGRESS(x) (x & PROG_IN_PROGRESS) - -#define NF2_GET_DMA_CTRL_MAC(x) ((x & DMA_CTRL_MAC) >> 8) -#define NF2_GET_DMA_CTRL_OWNER(x) (x & DMA_CTRL_OWNER) - -#define NF2_SET_DMA_CTRL_MAC(x) (x << 8) - -/* CNET Funcs */ -#define NF2_GET_CNET_VERSION(x) ((x & 0xFFFF0000) >> 16) -#define NF2_GET_CNET_DEVICE_ID(x) (x & 0xFFFF) - -#define NF2_GET_CNET_RESET_MAC(x) (x & CNET_RESET_MAC) - -#define NF2_GET_CNET_ERROR_TX_UNDERRUN_MAC(x) \ - ((x & CNET_ERROR_TX_UNDERRUN_MAC) >> 4) -#define NF2_GET_CNET_ERROR_TX_OVERRUN_MAC(x) \ - (x & CNET_ERROR_TX_OVERRUN_MAC) - -#define NF2_GET_CNET_ENABLE_RX_FIFO(x) ((x & CNET_ENABLE_RX_FIFO) >> 12) -#define NF2_GET_CNET_ENABLE_TX_MAC(x) ((x & CNET_ENABLE_TX_MAC) >> 8) -#define NF2_GET_CNET_ENABLE_DEBUG_TRISTATE(x) \ - ((x & CNET_ENABLE_DEBUG_TRISTATE) >> 2) -#define NF2_GET_CNET_ENABLE_INGRESS_ARBITER(x) \ - ((x & CNET_ENABLE_INGRESS_ARBITER) >> 1) -#define NF2_GET_CNET_ENABLE_RX_DMA(x) (x & CNET_ENABLE_RX_DMA) - -#define NF2_GET_CNET_MF_STATUS_RX_FIFO_EMPTY(x) \ - ((x & CNET_MF_STATUS_RX_FIFO_EMPTY) >> 25) -#define NF2_GET_CNET_MF_STATUS_RX_PKT_AVAIL(x) \ - ((x & CNET_MF_STATUS_RX_PKT_AVAIL) >> 24) -#define NF2_GET_CNET_MF_STATUS_RX_NUM_PKTS(x) \ - ((x & CNET_MF_STATUS_RX_NUM_PKTS) >> 16) -#define NF2_GET_CNET_MF_STATUS_TX_FIFO_FULL(x) \ - ((x & CNET_MF_STATUS_TX_FIFO_FULL) >> 9) -#define NF2_GET_CNET_MF_STATUS_TX_FIFO_NO_MAX_PKT(x) \ - ((x & CNET_MF_STATUS_TX_FIFO_NO_MAX_PKT) >> 8) -#define NF2_GET_CNET_MF_STATUS_TX_NUM_PKTS(x) \ - (x & CNET_MF_STATUS_TX_NUM_PKTS) - -#define NF2_GET_CNET_MAC_CFG_FULL_DUPLEX(x) \ - ((x & CNET_MAC_CFG_FULL_DUPLEX) >> 5) -#define NF2_GET_CNET_MAC_CFG_TX_FCS_SUPPLIED(x) \ - ((x & CNET_MAC_CFG_TX_FCS_SUPPLIED) >> 4) -#define NF2_GET_CNET_MAC_CFG_RX_WANT_FCS(x) \ - ((x & CNET_MAC_CFG_RX_WANT_FCS) >> 3) -#define NF2_GET_CNET_MAC_CFG_JUMBO_ENABLE(x) \ - ((x & CNET_MAC_CFG_JUMBO_ENABLE) >> 2) -#define NF2_GET_CNET_MAC_CFG_SPEED(x) \ - (x & CNET_MAC_CFG_SPEED) - -#define NF2_GET_CNET_RXQ_WR_PTR(x) ((x & CNET_RXQ_WR_PTR) >> 16) -#define NF2_GET_CNET_RXQ_RD_PTR(x) (x & CNET_RXQ_RD_PTR) - -/* PHY functions */ -#define NF2_SET_PHY_IS_READ(x) (x << 31) -#define NF2_SET_PHY_SELECT(x) (x << 24) -#define NF2_SET_PHY_ADDR(x) (x << 16) -#define NF2_SET_PHY_DATA(x) (x) - -#define NF2_GET_PHY_DATA(x) (x & PHY_DATA) -#define NF2_GET_PHY_DONE(x) ((x & PHY_DONE) >> 31) -#define NF2_GET_PHY_DONE_CNT(x) ((x & PHY_DONE_CNT) >> 16) - -/* - * IOCTLs - */ -#define SIOCREGREAD SIOCDEVPRIVATE -#define SIOCREGWRITE (SIOCDEVPRIVATE + 1) - -/* - * Structure for transferring register data via an IOCTL - */ -struct nf2reg { - unsigned int reg; - unsigned int val; -}; - -#endif diff --git a/openflow/datapath/hwtable_nf2/nf2_flowtable.c b/openflow/datapath/hwtable_nf2/nf2_flowtable.c deleted file mode 100644 index 75eb3223..00000000 --- a/openflow/datapath/hwtable_nf2/nf2_flowtable.c +++ /dev/null @@ -1,452 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "chain.h" -#include "table.h" -#include "flow.h" -#include "datapath.h" - -#include "hwtable_nf2/nf2_reg.h" -#include "hwtable_nf2/nf2_flowtable.h" -#include "hwtable_nf2/nf2_openflow.h" -#include "hwtable_nf2/nf2_lib.h" -#include "hwtable_nf2/nf2_procfs.h" - -struct nf2_flowtable { - struct sw_table flowtab; - spinlock_t lock; - unsigned int max_flows; - atomic_t num_flows; - struct list_head flows; - struct list_head iter_flows; - unsigned long int next_serial; -}; - -static struct sw_flow *nf2_lookup_flowtable(struct sw_table *, - const struct sw_flow_key *); -static int nf2_install_flow(struct sw_table *, struct sw_flow *); -static int nf2_modify_flow(struct sw_table *, const struct sw_flow_key *, - uint16_t, int, const struct ofp_action_header *, - size_t); -static void deferred_uninstall_callback(struct rcu_head *); -static void do_deferred_uninstall(struct sw_flow *); -static int do_uninstall(struct datapath *, struct sw_table *, struct sw_flow *, - enum ofp_flow_removed_reason); -static int nf2_has_conflict(struct sw_table *, const struct sw_flow_key *, - uint16_t, int); -static int nf2_uninstall_flow(struct datapath *, struct sw_table *, - const struct sw_flow_key *, uint16_t, - uint16_t, int); -static int nf2_flow_timeout(struct datapath *, struct sw_table *); -static void nf2_destroy_flowtable(struct sw_table *); -static int nf2_iterate_flowtable(struct sw_table *, - const struct sw_flow_key *, - uint16_t, struct sw_table_position *, - int (*)(struct sw_flow *, void *), void *); -unsigned long int get_lookup_matched_stats(void); -unsigned long int get_lookup_stats(void); -static void nf2_get_flowstats(struct sw_table *, struct sw_table_stats *); -static struct sw_table *nf2_create_flowtable(void); -static int __init nf2_startup(void); -static void nf2_cleanup(void); - -static struct sw_flow * -nf2_lookup_flowtable(struct sw_table *flowtab, const struct sw_flow_key *key) -{ - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - struct sw_flow *flow; - - list_for_each_entry(flow, &nf2flowtab->flows, node) { - if (flow_matches_1wild(key, &flow->key)) { - return flow; - } - } - - return NULL; -} - -static int -nf2_install_flow(struct sw_table *flowtab, struct sw_flow *flow) -{ - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - - /* Delete flows that match exactly. */ - nf2_uninstall_flow(NULL, flowtab, &flow->key, OFPP_NONE, - flow->priority, true); - - if (nf2_are_actions_supported(flow)) { - if (nf2_build_and_write_flow(flow)) { - return 0; - } - } else { - /* Unsupported actions or no netdevice. */ - return 0; - } - - atomic_inc(&nf2flowtab->num_flows); - list_add_rcu(&flow->node, &nf2flowtab->flows); - list_add_rcu(&flow->iter_node, &nf2flowtab->iter_flows); - return 1; -} - -static int -nf2_modify_flow(struct sw_table *flowtab, const struct sw_flow_key *key, - uint16_t priority, int strict, - const struct ofp_action_header *actions, size_t actions_len) -{ - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - struct sw_flow *flow; - unsigned int count = 0; - - list_for_each_entry(flow, &nf2flowtab->flows, node) { - if (flow_matches_desc(&flow->key, key, strict) - && (!strict || flow->priority == priority)) { - flow_replace_acts(flow, actions, actions_len); - if (nf2_are_actions_supported(flow)) { - count += nf2_modify_acts(flowtab, flow); - } - } else { - return 0; - } - } - - return count; -} - -static int -nf2_has_conflict(struct sw_table *flowtab, const struct sw_flow_key *key, - uint16_t priority, int strict) -{ - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - struct sw_flow *flow; - - list_for_each_entry(flow, &nf2flowtab->flows, node) { - if (flow_matches_desc(&flow->key, key, strict) - && (flow->priority == priority)) { - return true; - } - } - return false; -} - -static void -deferred_uninstall_callback(struct rcu_head *rcu) -{ - struct sw_flow *flow = container_of(rcu, struct sw_flow, rcu); - - flow_free(flow); -} - -static void -do_deferred_uninstall(struct sw_flow *flow) -{ - call_rcu(&flow->rcu, deferred_uninstall_callback); -} - -static int -do_uninstall(struct datapath *dpinst, struct sw_table *flowtab, - struct sw_flow *flow, enum ofp_flow_removed_reason reason) -{ - if (flow != NULL && flow->private != NULL) { - if (dpinst != NULL) - dp_send_flow_end(dpinst, flow, reason); - list_del_rcu(&flow->node); - list_del_rcu(&flow->iter_node); - nf2_delete_private(flow->private); - do_deferred_uninstall(flow); - return 1; - } - - return 0; -} - -static int -nf2_uninstall_flow(struct datapath *dpinst, struct sw_table *flowtab, - const struct sw_flow_key *key, uint16_t out_port, - uint16_t priority, int strict) -{ - struct net_device *netdev; - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - struct sw_flow *flow; - struct nf2_flow *nf2flow; - unsigned int count = 0; - - netdev = nf2_get_net_device(); - if (netdev == NULL) - return 0; - - list_for_each_entry(flow, &nf2flowtab->flows, node) { - if (flow_matches_desc(&flow->key, key, strict) - && (!strict || flow->priority == priority) - && flow_has_out_port(flow, out_port)) { - nf2flow = flow->private; - if (nf2flow != NULL) { - flow->packet_count - += nf2_get_packet_count(netdev, - nf2flow); - flow->byte_count += nf2_get_byte_count(netdev, - nf2flow); - } - count += do_uninstall(dpinst, flowtab, - flow, OFPRR_DELETE); - } - } - if (count != 0) - atomic_sub(count, &nf2flowtab->num_flows); - - nf2_free_net_device(netdev); - - return count; -} - -static int -nf2_flow_timeout(struct datapath *dpinst, struct sw_table *flowtab) -{ - struct net_device *netdev; - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - struct sw_flow *flow; - struct nf2_flow *nf2flow; - int num_uninst_flows = 0; - uint64_t num_forw_packets = 0; - int reason; - - netdev = nf2_get_net_device(); - if (netdev == NULL) - return num_uninst_flows; - - mutex_lock(&dp_mutex); - list_for_each_entry(flow, &nf2flowtab->flows, node) { - nf2flow = flow->private; - if (nf2flow != NULL) { - num_forw_packets = flow->packet_count - + nf2_get_packet_count(netdev, nf2flow); - flow->byte_count += nf2_get_byte_count(netdev, nf2flow); - } - if (num_forw_packets > flow->packet_count - && flow->idle_timeout != OFP_FLOW_PERMANENT) { - flow->packet_count = num_forw_packets; - flow->used = get_jiffies_64(); - } - reason = flow_timeout(flow); - if (reason >= 0) { - num_uninst_flows += do_uninstall(dpinst, flowtab, - flow, reason); - } - } - mutex_unlock(&dp_mutex); - - nf2_clear_watchdog(netdev); - - nf2_free_net_device(netdev); - - if (num_uninst_flows != 0) - atomic_sub(num_uninst_flows, &nf2flowtab->num_flows); - return num_uninst_flows; -} - -static void -nf2_destroy_flowtable(struct sw_table *flowtab) -{ - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - struct nf2_flow *nf2flow = NULL; - - if (nf2flowtab == NULL) - return; - - while (!list_empty(&nf2flowtab->flows)) { - struct sw_flow *flow = list_entry(nf2flowtab->flows.next, - struct sw_flow, node); - - list_del(&flow->node); - if (flow->private) { - nf2flow = (struct nf2_flow *)flow->private; - - if (nf2flow->type == NF2_TABLE_EXACT) { - nf2_add_free_exact(nf2flow); - } else if (nf2flow->type == NF2_TABLE_WILDCARD) { - nf2_add_free_wildcard(nf2flow); - } - flow->private = NULL; - } - flow_free(flow); - } - kfree(nf2flowtab); - - nf2_destroy_exact_freelist(); - nf2_destroy_wildcard_freelist(); -} - -static int -nf2_iterate_flowtable(struct sw_table *flowtab, const struct sw_flow_key *key, - uint16_t out_port, struct sw_table_position *position, - int (*callback) (struct sw_flow *, void *), void *private) -{ - unsigned long start; - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - struct sw_flow *flow; - int error = 0; - - start = ~position->private[0]; - list_for_each_entry(flow, &nf2flowtab->iter_flows, iter_node) { - if (flow->serial <= start && flow_matches_2wild(key, &flow->key) - && flow_has_out_port(flow, out_port)) { - error = callback(flow, private); - if (error != 0) { - position->private[0] = ~flow->serial; - return error; - } - } - } - - return error; -} - -unsigned long int -get_lookup_stats(void) -{ - struct net_device *netdev; - unsigned long int num_searched = 0; - - netdev = nf2_get_net_device(); - if (netdev == NULL) - return num_searched; - - num_searched = nf2_get_missed_count(netdev); - nf2_free_net_device(netdev); - num_searched += get_lookup_matched_stats(); - return num_searched; -} - -unsigned long int -get_lookup_matched_stats(void) -{ - struct net_device *netdev; - unsigned long int num_matched = 0; - - netdev = nf2_get_net_device(); - if (netdev == NULL) - return num_matched; - - num_matched = nf2_get_matched_count(netdev); - nf2_free_net_device(netdev); - return num_matched; -} - -static void -nf2_get_flowstats(struct sw_table *flowtab, struct sw_table_stats *stats) -{ - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - - stats->name = "nf2"; - stats->wildcards = OPENFLOW_WILDCARD_TABLE_SIZE - 8; - stats->n_flows = atomic_read(&nf2flowtab->num_flows); - stats->max_flows = nf2flowtab->max_flows; - stats->n_lookup = get_lookup_stats(); - stats->n_matched = get_lookup_matched_stats(); -} - -static struct sw_table * -nf2_create_flowtable(void) -{ - struct net_device *netdev; - struct nf2_flowtable *nf2flowtab; - struct sw_table *flowtab; - - netdev = nf2_get_net_device(); - if (netdev == NULL) - return NULL; - - nf2_reset_card(netdev); - nf2_free_net_device(netdev); - - nf2flowtab = kzalloc(sizeof(*nf2flowtab), GFP_KERNEL); - if (nf2flowtab == NULL) { - nf2_free_net_device(netdev); - return NULL; - } - - flowtab = &nf2flowtab->flowtab; - flowtab->n_lookup = (unsigned long long)get_lookup_stats(); - flowtab->n_matched = (unsigned long long)get_lookup_matched_stats(); - flowtab->lookup = nf2_lookup_flowtable; - flowtab->insert = nf2_install_flow; - flowtab->modify = nf2_modify_flow; - flowtab->has_conflict = nf2_has_conflict; - flowtab->delete = nf2_uninstall_flow; - flowtab->timeout = nf2_flow_timeout; - flowtab->destroy = nf2_destroy_flowtable; - flowtab->iterate = nf2_iterate_flowtable; - flowtab->stats = nf2_get_flowstats; -#define RESERVED_FOR_CPU2NETFPGA 8 - nf2flowtab->max_flows = OPENFLOW_NF2_EXACT_TABLE_SIZE - + OPENFLOW_WILDCARD_TABLE_SIZE - RESERVED_FOR_CPU2NETFPGA; - atomic_set(&nf2flowtab->num_flows, 0); - INIT_LIST_HEAD(&nf2flowtab->flows); - INIT_LIST_HEAD(&nf2flowtab->iter_flows); - nf2flowtab->next_serial = 0; - - nf2_init_wildcard_freelist(); - nf2_write_static_wildcard(); - nf2_init_exact_freelist(); - - return flowtab; -} - -static int __init -nf2_startup(void) -{ - nf2_create_procfs(); - return chain_set_hw_hook(nf2_create_flowtable, THIS_MODULE); -} - -static void -nf2_cleanup(void) -{ - nf2_remove_procfs(); - chain_clear_hw_hook(); -} - -module_init(nf2_startup); -module_exit(nf2_cleanup); - -MODULE_DESCRIPTION("NetFPGA Fastpath Extension for OpenFlow Switch"); -MODULE_AUTHOR("Copyright (c) 2008, 2009 " - "The Board of Trustees of The Leland Stanford Junior University"); -MODULE_LICENSE("GPL"); diff --git a/openflow/datapath/hwtable_nf2/nf2_flowtable.h b/openflow/datapath/hwtable_nf2/nf2_flowtable.h deleted file mode 100644 index 45aca5c7..00000000 --- a/openflow/datapath/hwtable_nf2/nf2_flowtable.h +++ /dev/null @@ -1,63 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#ifndef HWTABLE_NF2_NF2_FLOWTABLE_ -#define HWTABLE_NF2_NF2_FLOWTABLE_ - -struct nf2_flow { - struct list_head node; - uint32_t pos; - uint32_t type; - uint32_t hw_packet_count; - uint32_t hw_byte_count; -}; - -enum nf2_of_table_type { - NF2_TABLE_EXACT, - NF2_TABLE_WILDCARD -}; - -/* #define NF2_DEBUG 1 */ - -#ifdef NF2_DEBUG -#ifdef __KERNEL__ -#define NF2DEBUGMSG(f, s...) printk(f, ## s) -#else -#define NF2DEBUGMSG(f, s...) printf(f, ## s) -#endif /* __KERNEL__ */ -#else -#define NF2DEBUGMSG(f, s...) -#endif - -/* #define NF2_WATCHDOG 1 */ - -#endif diff --git a/openflow/datapath/hwtable_nf2/nf2_hwapi.h b/openflow/datapath/hwtable_nf2/nf2_hwapi.h deleted file mode 100644 index 1a3e7aa1..00000000 --- a/openflow/datapath/hwtable_nf2/nf2_hwapi.h +++ /dev/null @@ -1,43 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#ifndef HWTABLE_NF2_NF2_HWAPI_H_ -#define HWTABLE_NF2_NF2_HWAPI_H_ - -#ifdef __KERNEL__ - -int nf2k_reg_read(struct net_device *, unsigned int, void *); -int nf2k_reg_write(struct net_device *, unsigned int, void *); - -#endif /* __KERNEL__ */ - -#endif diff --git a/openflow/datapath/hwtable_nf2/nf2_lib.c b/openflow/datapath/hwtable_nf2/nf2_lib.c deleted file mode 100644 index 67acd433..00000000 --- a/openflow/datapath/hwtable_nf2/nf2_lib.c +++ /dev/null @@ -1,918 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#include - -#include "crc32.h" -#include "flow.h" -#include "table.h" -#include "compat26.h" - -#include "hwtable_nf2/nf2.h" -#include "hwtable_nf2/nf2_reg.h" -#include "hwtable_nf2/nf2_hwapi.h" -#include "hwtable_nf2/nf2_flowtable.h" -#include "hwtable_nf2/nf2_openflow.h" -#include "hwtable_nf2/nf2_lib.h" - -#define MAX_INT_32 0xFFFFFFFF -#define PORT_BASE 1 - -#define VID_BITMASK 0x0FFF -#define PCP_BITSHIFT 13 -#define PCP_BITMASK 0xE000 - -struct list_head wildcard_free_list; -struct nf2_flow *exact_free_list[OPENFLOW_NF2_EXACT_TABLE_SIZE]; - -static uint32_t make_nw_wildcard(int); -static struct nf2_flow *get_free_exact(nf2_of_entry_wrap *); -static struct nf2_flow *get_free_wildcard(void); -static int is_action_forward_all(struct sw_flow *); -static void populate_action_output(nf2_of_action_wrap *, nf2_of_entry_wrap *, - uint8_t *); -static void populate_action_set_dl_src(nf2_of_action_wrap *, uint8_t *); -static void populate_action_set_dl_dst(nf2_of_action_wrap *, uint8_t *); - -struct net_device * -nf2_get_net_device(void) -{ - return dev_get_by_name(&init_net, "nf2c0"); -} - -void -nf2_free_net_device(struct net_device *dev) -{ - if (dev == NULL) - return; - - dev_put(dev); -} - -/* Checks to see if the actions requested by the flow are capable of being - * done in the NF2 hardware. Returns 1 if yes, 0 for no. - */ -int -nf2_are_actions_supported(struct sw_flow *flow) -{ - struct sw_flow_actions *sfa; - size_t actions_len; - uint8_t *p; - - sfa = flow->sf_acts; - actions_len = sfa->actions_len; - p = (uint8_t *)sfa->actions; - - while (actions_len > 0) { - struct ofp_action_header *ah = (struct ofp_action_header *)p; - struct ofp_action_output *oa = (struct ofp_action_output *)p; - size_t len = ntohs(ah->len); - - NF2DEBUGMSG("Action Support Chk: Len of this action: %i\n", - len); - NF2DEBUGMSG("Action Support Chk: Len of actions : %i\n", - actions_len); - - // Currently, output port(s) action, dl_src/dst rewrite actions - // are suported. - if (!(ntohs(ah->type) == OFPAT_OUTPUT - || ntohs(ah->type) == OFPAT_SET_DL_SRC - || ntohs(ah->type) == OFPAT_SET_DL_DST)) { - NF2DEBUGMSG - ("Flow action type %#0x not supported in hardware\n", - ntohs(ah->type)); - return 0; - } - // Only support ports 1-4(incl. IN_PORT), ALL, FLOOD. - // Let CONTROLLER/LOCAL fall through - if ((ntohs(ah->type) == OFPAT_OUTPUT) - && (!((ntohs(oa->port) >= PORT_BASE) - && (ntohs(oa->port) <= MAX_IFACE)) - && !(ntohs(oa->port) == OFPP_ALL) - && !(ntohs(oa->port) == OFPP_FLOOD) - && !(ntohs(oa->port) == OFPP_IN_PORT))) { - NF2DEBUGMSG - ("Flow action output port %#0x is not supported in hardware\n", - ntohs(oa->port)); - return 0; - } - p += len; - actions_len -= len; - } - - return 1; -} - -/* Write all 0's out to an exact entry position. */ -void -nf2_clear_of_exact(uint32_t pos) -{ - nf2_of_entry_wrap entry; - nf2_of_action_wrap action; - struct net_device *dev = NULL; - - memset(&entry, 0, sizeof(nf2_of_entry_wrap)); - memset(&action, 0, sizeof(nf2_of_action_wrap)); - - dev = nf2_get_net_device(); - if (dev == NULL) - return; - - nf2_write_of_exact(dev, pos, &entry, &action); - nf2_free_net_device(dev); -} - -/* - * Write all 0's out to a wildcard entry position - */ -void -nf2_clear_of_wildcard(uint32_t pos) -{ - nf2_of_entry_wrap entry; - nf2_of_mask_wrap mask; - nf2_of_action_wrap action; - struct net_device *dev = NULL; - - memset(&entry, 0, sizeof(nf2_of_entry_wrap)); - memset(&mask, 0, sizeof(nf2_of_mask_wrap)); - memset(&action, 0, sizeof(nf2_of_action_wrap)); - - dev = nf2_get_net_device(); - if (dev == NULL) - return; - - nf2_write_of_wildcard(dev, pos, &entry, &mask, &action); - nf2_free_net_device(dev); -} - -int -nf2_init_exact_freelist(void) -{ - struct nf2_flow *sfw = NULL; - int i; - - for (i = 0; i < (OPENFLOW_NF2_EXACT_TABLE_SIZE); ++i) { - sfw = kzalloc(sizeof(struct nf2_flow), GFP_ATOMIC); - if (sfw == NULL) { - return 1; - } - sfw->pos = i; - sfw->type = NF2_TABLE_EXACT; - nf2_add_free_exact(sfw); - sfw = NULL; - } - - return 0; -} - -int -nf2_init_wildcard_freelist(void) -{ - struct nf2_flow *sfw = NULL; - int i; - INIT_LIST_HEAD(&wildcard_free_list); - - for (i = 0; i < (OPENFLOW_WILDCARD_TABLE_SIZE - 8); ++i) { - sfw = kzalloc(sizeof(struct nf2_flow), GFP_ATOMIC); - if (sfw == NULL) { - return 1; - } - sfw->pos = i; - sfw->type = NF2_TABLE_WILDCARD; - nf2_add_free_wildcard(sfw); - sfw = NULL; - } - - return 0; -} - -/* Called when the table is being deleted. */ -void -nf2_destroy_exact_freelist(void) -{ - struct nf2_flow *sfw = NULL; - int i; - - for (i = 0; i < (OPENFLOW_NF2_EXACT_TABLE_SIZE); ++i) { - sfw = exact_free_list[i]; - if (sfw) { - kfree(sfw); - } - sfw = NULL; - } -} - -/* Called when the table is being deleted. */ -void -nf2_destroy_wildcard_freelist(void) -{ - struct nf2_flow *sfw = NULL; - struct list_head *next = NULL; - - while (!list_empty(&wildcard_free_list)) { - next = wildcard_free_list.next; - sfw = list_entry(next, struct nf2_flow, node); - list_del(&sfw->node); - kfree(sfw); - } -} - -/* Setup the wildcard table by adding static flows that will handle - * misses by sending them up to the cpu ports, and handle packets coming - * back down from the cpu by sending them out the corresponding port. - */ -int -nf2_write_static_wildcard(void) -{ - nf2_of_entry_wrap entry; - nf2_of_mask_wrap mask; - nf2_of_action_wrap action; - int i; - struct net_device *dev; - - dev = nf2_get_net_device(); - if (dev == NULL) - return 1; - - memset(&entry, 0x00, sizeof(nf2_of_entry_wrap)); - memset(&mask, 0xFF, sizeof(nf2_of_mask_wrap)); - // Only non-wildcard section is the source port - mask.entry.src_port = 0; - memset(&action, 0, sizeof(nf2_of_action_wrap)); - - // write the catch all entries to send to the cpu - for (i = 0; i < 4; ++i) { - entry.entry.src_port = i * 2; - action.action.forward_bitmask = 0x1 << ((i * 2) + 1); - nf2_write_of_wildcard(dev, (OPENFLOW_WILDCARD_TABLE_SIZE - 4) - + i, &entry, &mask, &action); - } - - // write the entries to send out packets coming from the cpu - for (i = 0; i < 4; ++i) { - entry.entry.src_port = (i * 2) + 1; - action.action.forward_bitmask = 0x1 << (i * 2); - nf2_write_of_wildcard(dev, (OPENFLOW_WILDCARD_TABLE_SIZE - 8) - + i, &entry, &mask, &action); - } - - nf2_free_net_device(dev); - return 0; -} - -/* Populate a nf2_of_entry_wrap with entries from a struct sw_flow. */ -void -nf2_populate_of_entry(nf2_of_entry_wrap *key, struct sw_flow *flow) -{ - int vlan_vid; - int vlan_pcp; - int i; - - key->entry.transp_dst = ntohs(flow->key.tp_dst); - key->entry.transp_src = ntohs(flow->key.tp_src); - key->entry.ip_proto = flow->key.nw_proto; - key->entry.ip_dst = ntohl(flow->key.nw_dst); - key->entry.ip_src = ntohl(flow->key.nw_src); - key->entry.eth_type = ntohs(flow->key.dl_type); - // Blame Jad for applying endian'ness to character arrays - for (i = 0; i < 6; ++i) { - key->entry.eth_dst[i] = flow->key.dl_dst[5 - i]; - } - for (i = 0; i < 6; ++i) { - key->entry.eth_src[i] = flow->key.dl_src[5 - i]; - } - - key->entry.src_port = (ntohs(flow->key.in_port) - PORT_BASE) * 2; - - if (ntohs(flow->key.dl_vlan) == 0xffff) { - key->entry.vlan_id = 0xffff; - } else { - vlan_vid = VID_BITMASK & ntohs(flow->key.dl_vlan); - vlan_pcp = PCP_BITMASK - & ((uint16_t)(flow->key.dl_vlan_pcp) << PCP_BITSHIFT); - key->entry.vlan_id = vlan_pcp | vlan_vid; - } -} - -static uint32_t -make_nw_wildcard(int n_wild_bits) -{ - n_wild_bits &= (1u << OFPFW_NW_SRC_BITS) - 1; - return n_wild_bits < 32 ? ((1u << n_wild_bits) - 1) : 0xFFFFFFFF; -} - -/* Populate a nf2_of_mask_wrap with entries from a struct sw_flow's wildcards. */ -void -nf2_populate_of_mask(nf2_of_mask_wrap *mask, struct sw_flow *flow) -{ - int vlan_vid = 0; - int vlan_pcp = 0; - int i; - - if (OFPFW_IN_PORT & flow->key.wildcards) { - mask->entry.src_port = 0xFF; - } - if (OFPFW_DL_VLAN & flow->key.wildcards) { - vlan_vid = 0x0FFF; - } - if (OFPFW_DL_VLAN_PCP & flow->key.wildcards) { - vlan_pcp = 0xE000; - } - mask->entry.vlan_id = vlan_pcp | vlan_vid; - if (OFPFW_DL_SRC & flow->key.wildcards) { - for (i = 0; i < 6; ++i) { - mask->entry.eth_src[i] = 0xFF; - } - } - if (OFPFW_DL_DST & flow->key.wildcards) { - for (i = 0; i < 6; ++i) { - mask->entry.eth_dst[i] = 0xFF; - } - } - if (OFPFW_DL_TYPE & flow->key.wildcards) - mask->entry.eth_type = 0xFFFF; - if ((OFPFW_NW_SRC_ALL & flow->key.wildcards) - || (OFPFW_NW_SRC_MASK & flow->key.wildcards)) - mask->entry.ip_src = make_nw_wildcard - (flow->key.wildcards >> OFPFW_NW_SRC_SHIFT); - if ((OFPFW_NW_DST_ALL & flow->key.wildcards) - || (OFPFW_NW_DST_MASK & flow->key.wildcards)) - mask->entry.ip_dst = make_nw_wildcard - (flow->key.wildcards >> OFPFW_NW_DST_SHIFT); - if (OFPFW_NW_PROTO & flow->key.wildcards) - mask->entry.ip_proto = 0xFF; - if (OFPFW_TP_SRC & flow->key.wildcards) - mask->entry.transp_src = 0xFFFF; - if (OFPFW_TP_DST & flow->key.wildcards) - mask->entry.transp_dst = 0xFFFF; - - mask->entry.pad = 0x0000; -} - -static void -populate_action_output(nf2_of_action_wrap *action, nf2_of_entry_wrap *entry, - uint8_t *flowact) -{ - uint16_t port = 0; - struct ofp_action_output *actout = (struct ofp_action_output *)flowact; - int i; - - port = ntohs(actout->port); - NF2DEBUGMSG("Action Type: %i Output Port: %i\n", - ntohs(actout->type), port); - - if ((port >= PORT_BASE) && (port <= MAX_IFACE)) { - // Bitmask for output port(s), evens are phys odds cpu - action->action.forward_bitmask - |= (1 << ((port - PORT_BASE) * 2)); - NF2DEBUGMSG("Output Port: %i Forward Bitmask: %x\n", - port, action->action.forward_bitmask); - } else if (port == OFPP_IN_PORT) { - // Send out to input port - action->action.forward_bitmask - |= (1 << (entry->entry.src_port)); - NF2DEBUGMSG("Output Port = Input Port Forward Bitmask: %x\n", - action->action.forward_bitmask); - } else if (port == OFPP_ALL || port == OFPP_FLOOD) { - // Send out all ports except the source - for (i = 0; i < 4; ++i) { - if ((i * 2) != entry->entry.src_port) { - // Bitmask for output port(s), evens are - // phys odds cpu - action->action.forward_bitmask - |= (1 << (i * 2)); - NF2DEBUGMSG - ("Output Port: %i Forward Bitmask: %x\n", - port, action->action.forward_bitmask); - } - } - } -} - -static void -populate_action_set_dl_src(nf2_of_action_wrap *action, uint8_t *flowact) -{ - struct ofp_action_dl_addr *actdl = (struct ofp_action_dl_addr *)flowact; - int i; - - for (i = 0; i < 6; ++i) { - action->action.eth_src[5 - i] = actdl->dl_addr[i]; - } - action->action.nf2_action_flag |= (1 << OFPAT_SET_DL_SRC); -} - -static void -populate_action_set_dl_dst(nf2_of_action_wrap *action, uint8_t *flowact) -{ - struct ofp_action_dl_addr *actdl = (struct ofp_action_dl_addr *)flowact; - int i; - - for (i = 0; i < 6; ++i) { - action->action.eth_dst[5 - i] = actdl->dl_addr[i]; - } - action->action.nf2_action_flag |= (1 << OFPAT_SET_DL_DST); -} - -/* Populate an nf2_of_action_wrap. */ -void -nf2_populate_of_action(nf2_of_action_wrap *action, nf2_of_entry_wrap *entry, - nf2_of_mask_wrap *mask, struct sw_flow *flow) -{ - struct sw_flow_actions *sfa; - size_t actions_len; - uint8_t *p; - - sfa = flow->sf_acts; - actions_len = sfa->actions_len; - p = (uint8_t *)sfa->actions; - - // zero it out for now - memset(action, 0, sizeof(nf2_of_action_wrap)); - action->action.nf2_action_flag = 0; - - while (actions_len > 0) { - struct ofp_action_header *acth = (struct ofp_action_header *)p; - size_t len = ntohs(acth->len); - - NF2DEBUGMSG("Action Populate: Len of this action: %i\n", len); - NF2DEBUGMSG("Action Populate: Len of actions : %i\n", - actions_len); - - if (acth->type == htons(OFPAT_OUTPUT)) { - populate_action_output(action, entry, p); - } else if (acth->type == htons(OFPAT_SET_DL_SRC)) { - populate_action_set_dl_src(action, p); - } else if (acth->type == htons(OFPAT_SET_DL_DST)) { - populate_action_set_dl_dst(action, p); - } - p += len; - actions_len -= len; - } -} - -/* Add a free hardware entry back to the exact pool. */ -void -nf2_add_free_exact(struct nf2_flow *sfw) -{ - // clear the node entry - INIT_LIST_HEAD(&sfw->node); - - // Critical section, adding to the actual list - exact_free_list[sfw->pos] = sfw; -} - -/* Add a free hardware entry back to the wildcard pool. */ -void -nf2_add_free_wildcard(struct nf2_flow *sfw) -{ - // clear the hw values - sfw->hw_packet_count = 0; - sfw->hw_byte_count = 0; - - // Critical section, adding to the actual list - list_add_tail(&sfw->node, &wildcard_free_list); -} - -/* Hashes the entry to find where it should exist in the exact table - * returns NULL on failure - */ -static struct nf2_flow * -get_free_exact(nf2_of_entry_wrap *entry) -{ - unsigned int poly1 = 0x04C11DB7; - unsigned int poly2 = 0x1EDC6F41; - struct nf2_flow *sfw = NULL; - unsigned int hash = 0x0; - unsigned int index = 0x0; - struct crc32 crc; - - crc32_init(&crc, poly1); - hash = crc32_calculate(&crc, entry, sizeof(nf2_of_entry_wrap)); - - // the bottom 15 bits of hash == the index into the table - index = 0x7FFF & hash; - - // if this index is free, grab it - sfw = exact_free_list[index]; - exact_free_list[index] = NULL; - - if (sfw != NULL) { - return sfw; - } - // try the second index - crc32_init(&crc, poly2); - hash = crc32_calculate(&crc, entry, sizeof(nf2_of_entry_wrap)); - // the bottom 15 bits of hash == the index into the table - index = 0x7FFF & hash; - - // if this index is free, grab it - sfw = exact_free_list[index]; - exact_free_list[index] = NULL; - - // return whether its good or not - return sfw; -} - -/* Get the first free position in the wildcard hardware table - * to write into. - */ -static struct nf2_flow * -get_free_wildcard(void) -{ - struct nf2_flow *sfw = NULL; - struct list_head *next = NULL; - - // Critical section, pulling the first available from the list - if (list_empty(&wildcard_free_list)) { - // empty :( - sfw = NULL; - } else { - next = wildcard_free_list.next; - sfw = list_entry(next, struct nf2_flow, node); - list_del_init(&sfw->node); - } - - return sfw; -} - -/* Retrieves the type of table this flow should go into. */ -int -nf2_get_table_type(struct sw_flow *flow) -{ - if (flow->key.wildcards != 0) { - NF2DEBUGMSG("--- TABLE TYPE: WILDCARD ---\n"); - return NF2_TABLE_WILDCARD; - } else { - NF2DEBUGMSG("--- TABLE TYPE: EXACT ---\n"); - return NF2_TABLE_EXACT; - } -} - -/* Returns 1 if this flow contains an action outputting to all ports except - * input port, 0 otherwise. We support OFPP_ALL and OFPP_FLOOD actions, however - * since we do not perform the spanning tree protocol (STP) then OFPP_FLOOD is - * equivalent to OFPP_ALL. - */ -static int -is_action_forward_all(struct sw_flow *flow) -{ - struct sw_flow_actions *sfa; - size_t actions_len; - uint8_t *p; - - sfa = flow->sf_acts; - actions_len = sfa->actions_len; - p = (uint8_t *)sfa->actions; - - while (actions_len > 0) { - struct ofp_action_header *ah = (struct ofp_action_header *)p; - struct ofp_action_output *oa = (struct ofp_action_output *)p; - size_t len = ntohs(ah->len); - - NF2DEBUGMSG("Fwd Action Chk: Action type: %x\n", - ntohs(ah->type)); - NF2DEBUGMSG("Fwd Action Chk: Output port: %x\n", - ntohs(oa->port)); - NF2DEBUGMSG("Fwd Action Chk: Len of this action: %i\n", len); - NF2DEBUGMSG("Fwd Action Chk: Len of actions : %i\n", - actions_len); - // Currently only support the output port(s) action - if (ntohs(ah->type) == OFPAT_OUTPUT - && (ntohs(oa->port) == OFPP_ALL - || ntohs(oa->port) == OFPP_FLOOD)) { - return 1; - } - p += len; - actions_len -= len; - } - - return 0; -} - -/* Attempts to build and write the flow to hardware. - * Returns 0 on success, 1 on failure. - */ -int -nf2_build_and_write_flow(struct sw_flow *flow) -{ - struct nf2_flow *sfw = NULL; - struct nf2_flow *sfw_next = NULL; - struct net_device *dev; - int num_entries = 0; - int i, table_type; - nf2_of_entry_wrap key; - nf2_of_mask_wrap mask; - nf2_of_action_wrap action; - - memset(&key, 0, sizeof(nf2_of_entry_wrap)); - memset(&mask, 0, sizeof(nf2_of_mask_wrap)); - memset(&action, 0, sizeof(nf2_of_action_wrap)); - - dev = nf2_get_net_device(); - if (dev == NULL) { - // failure getting net device - NF2DEBUGMSG("Failure getting net device struct\n"); - return 1; - } - - table_type = nf2_get_table_type(flow); - switch (table_type) { - default: - break; - - case NF2_TABLE_EXACT: - NF2DEBUGMSG("---Exact Entry---\n"); - nf2_populate_of_entry(&key, flow); - nf2_populate_of_action(&action, &key, NULL, flow); - sfw = get_free_exact(&key); - if (sfw == NULL) { - NF2DEBUGMSG - ("Collision getting free exact match entry\n"); - // collision - nf2_free_net_device(dev); - return 1; - } - // set the active bit on this entry - key.entry.pad = 0x8000; - nf2_write_of_exact(dev, sfw->pos, &key, &action); - flow->private = (void *)sfw; - break; - - case NF2_TABLE_WILDCARD: - NF2DEBUGMSG("---Wildcard Entry---\n"); - // if action is all out and source port is wildcarded - if ((is_action_forward_all(flow)) && - (flow->key.wildcards & OFPFW_IN_PORT)) { - NF2DEBUGMSG("Grab four wildcard tables\n"); - if (!(sfw = get_free_wildcard())) { - NF2DEBUGMSG("No free wildcard entries found."); - // no free entries - nf2_free_net_device(dev); - return 1; - } - // try to get 3 more positions - for (i = 0; i < 3; ++i) { - if (!(sfw_next = get_free_wildcard())) { - break; - } - list_add_tail(&sfw_next->node, &sfw->node); - ++num_entries; - } - - if (num_entries < 3) { - // failed to get enough entries, return them and exit - nf2_delete_private((void *)sfw); - nf2_free_net_device(dev); - return 1; - } - - nf2_populate_of_entry(&key, flow); - nf2_populate_of_mask(&mask, flow); - - // set first entry's src port to 0, remove wildcard mask on src - key.entry.src_port = 0; - mask.entry.src_port = 0; - nf2_populate_of_action(&action, &key, &mask, flow); - nf2_write_of_wildcard(dev, sfw->pos, &key, &mask, - &action); - - i = 1; - sfw_next = list_entry(sfw->node.next, - struct nf2_flow, node); - // walk through and write the remaining 3 entries - while (sfw_next != sfw) { - key.entry.src_port = i * 2; - nf2_populate_of_action(&action, &key, &mask, - flow); - nf2_write_of_wildcard(dev, sfw_next->pos, &key, - &mask, &action); - sfw_next = list_entry(sfw_next->node.next, - struct nf2_flow, node); - ++i; - } - flow->private = (void *)sfw; - } else { - /* Get a free position here, and write to it */ - if ((sfw = get_free_wildcard())) { - nf2_populate_of_entry(&key, flow); - nf2_populate_of_mask(&mask, flow); - nf2_populate_of_action(&action, &key, &mask, - flow); - if (nf2_write_of_wildcard - (dev, sfw->pos, &key, &mask, &action)) { - // failure writing to hardware - nf2_add_free_wildcard(sfw); - NF2DEBUGMSG - ("Failure writing to hardware\n"); - nf2_free_net_device(dev); - return 1; - } else { - // success writing to hardware, store the position - flow->private = (void *)sfw; - } - } else { - // hardware is full, return 0 - NF2DEBUGMSG("No free wildcard entries found."); - nf2_free_net_device(dev); - return 1; - } - } - break; - } - - nf2_free_net_device(dev); - return 0; -} - -void -nf2_delete_private(void *private) -{ - struct nf2_flow *sfw = (struct nf2_flow *)private; - struct nf2_flow *sfw_next; - struct list_head *next; - - switch (sfw->type) { - default: - break; - - case NF2_TABLE_EXACT: - nf2_clear_of_exact(sfw->pos); - nf2_add_free_exact(sfw); - break; - - case NF2_TABLE_WILDCARD: - while (!list_empty(&sfw->node)) { - next = sfw->node.next; - sfw_next = list_entry(next, struct nf2_flow, node); - list_del_init(&sfw_next->node); - // Immediately zero out the entry in hardware - nf2_clear_of_wildcard(sfw_next->pos); - // add it back to the pool - nf2_add_free_wildcard(sfw_next); - } - // zero the core entry - nf2_clear_of_wildcard(sfw->pos); - // add back the core entry - nf2_add_free_wildcard(sfw); - break; - } -} - -int -nf2_modify_acts(struct sw_table *swt, struct sw_flow *flow) -{ - struct nf2_flow *sfw = (struct nf2_flow *)flow->private; - struct net_device *dev; - nf2_of_entry_wrap key; - nf2_of_mask_wrap mask; - nf2_of_action_wrap action; - - memset(&key, 0, sizeof(nf2_of_entry_wrap)); - memset(&mask, 0, sizeof(nf2_of_mask_wrap)); - memset(&action, 0, sizeof(nf2_of_action_wrap)); - - dev = nf2_get_net_device(); - if (dev == NULL) - return 0; - - switch (sfw->type) { - default: - break; - - case NF2_TABLE_EXACT: - nf2_populate_of_entry(&key, flow); - nf2_populate_of_action(&action, &key, NULL, flow); - key.entry.pad = 0x8000; - nf2_modify_write_of_exact(dev, sfw->pos, &action); - break; - - case NF2_TABLE_WILDCARD: - if (flow->key.wildcards & OFPFW_IN_PORT) { - nf2_free_net_device(dev); - return 0; - } - nf2_populate_of_entry(&key, flow); - nf2_populate_of_mask(&mask, flow); - nf2_populate_of_action(&action, &key, &mask, flow); - nf2_modify_write_of_wildcard(dev, sfw->pos, - &key, &mask, &action); - break; - } - - nf2_free_net_device(dev); - return 1; -} - -uint64_t -nf2_get_packet_count(struct net_device *dev, struct nf2_flow *sfw) -{ - uint32_t count = 0; - uint32_t hw_count = 0; - uint64_t total = 0; - struct nf2_flow *sfw_next = NULL; - - switch (sfw->type) { - default: - break; - - case NF2_TABLE_EXACT: - count = nf2_get_exact_packet_count(dev, sfw->pos); - total = count; - break; - - case NF2_TABLE_WILDCARD: - sfw_next = sfw; - do { - hw_count = nf2_get_wildcard_packet_count(dev, - sfw_next->pos); - if (hw_count >= sfw_next->hw_packet_count) { - count = hw_count - sfw_next->hw_packet_count; - sfw_next->hw_packet_count = hw_count; - } else { - // wrapping occurred - count = (MAX_INT_32 - sfw_next->hw_packet_count) - + hw_count; - sfw_next->hw_packet_count = hw_count; - } - total += count; - sfw_next = list_entry(sfw_next->node.next, - struct nf2_flow, node); - } while (sfw_next != sfw); - break; - } - - NF2DEBUGMSG("Return nf2_get_packet_count value: %llu\n", total); - return total; -} - -uint64_t -nf2_get_byte_count(struct net_device *dev, struct nf2_flow *sfw) -{ - uint32_t count = 0; - uint32_t hw_count = 0; - uint64_t total = 0; - struct nf2_flow *sfw_next = NULL; - - switch (sfw->type) { - default: - break; - - case NF2_TABLE_EXACT: - count = nf2_get_exact_byte_count(dev, sfw->pos); - total = count; - break; - - case NF2_TABLE_WILDCARD: - sfw_next = sfw; - do { - hw_count = nf2_get_wildcard_byte_count(dev, - sfw_next->pos); - if (hw_count >= sfw_next->hw_byte_count) { - count = hw_count - sfw_next->hw_byte_count; - sfw_next->hw_byte_count = hw_count; - } else { - // wrapping occurred - count = (MAX_INT_32 - sfw_next->hw_byte_count) - + hw_count; - sfw_next->hw_byte_count = hw_count; - } - - total += count; - sfw_next = list_entry(sfw_next->node.next, - struct nf2_flow, node); - } while (sfw_next != sfw); - break; - } - - NF2DEBUGMSG("Return nf2_get_byte_count value: %llu\n", total); - return total; -} diff --git a/openflow/datapath/hwtable_nf2/nf2_lib.h b/openflow/datapath/hwtable_nf2/nf2_lib.h deleted file mode 100644 index 9c0fedc8..00000000 --- a/openflow/datapath/hwtable_nf2/nf2_lib.h +++ /dev/null @@ -1,59 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#ifndef HWTABLE_NF2_NF2_LIB_H_ -#define HWTABLE_NF2_NF2_LIB_H_ - -struct net_device *nf2_get_net_device(void); -void nf2_free_net_device(struct net_device *); -int nf2_are_actions_supported(struct sw_flow *); -void nf2_clear_of_exact(uint32_t); -void nf2_clear_of_wildcard(uint32_t); -int nf2_init_exact_freelist(void); -int nf2_init_wildcard_freelist(void); -void nf2_destroy_exact_freelist(void); -void nf2_destroy_wildcard_freelist(void); -int nf2_write_static_wildcard(void); -void nf2_populate_of_entry(nf2_of_entry_wrap *, struct sw_flow *); -void nf2_populate_of_mask(nf2_of_mask_wrap *, struct sw_flow *); -void nf2_populate_of_action(nf2_of_action_wrap *, nf2_of_entry_wrap *, - nf2_of_mask_wrap *, struct sw_flow *); -void nf2_add_free_exact(struct nf2_flow *); -void nf2_add_free_wildcard(struct nf2_flow *); -int nf2_get_table_type(struct sw_flow *); -int nf2_build_and_write_flow(struct sw_flow *); -void nf2_delete_private(void *); -int nf2_modify_acts(struct sw_table *, struct sw_flow *); -uint64_t nf2_get_packet_count(struct net_device *, struct nf2_flow *); -uint64_t nf2_get_byte_count(struct net_device *, struct nf2_flow *); - -#endif diff --git a/openflow/datapath/hwtable_nf2/nf2_openflow.c b/openflow/datapath/hwtable_nf2/nf2_openflow.c deleted file mode 100644 index 7d392f19..00000000 --- a/openflow/datapath/hwtable_nf2/nf2_openflow.c +++ /dev/null @@ -1,847 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#include -#include -#include - -#include "flow.h" -#include "table.h" - -#include "hwtable_nf2/nf2.h" -#include "hwtable_nf2/nf2_reg.h" -#include "hwtable_nf2/nf2_hwapi.h" -#include "hwtable_nf2/nf2_flowtable.h" -#include "hwtable_nf2/nf2_openflow.h" -#include "hwtable_nf2/nf2_lib.h" - -static void log_entry(nf2_of_entry_wrap *); -static void log_entry_raw(nf2_of_entry_wrap *); -static void log_mask(nf2_of_mask_wrap *); -static void log_mask_raw(nf2_of_mask_wrap *); -static void log_action(nf2_of_action_wrap *); -static void log_action_raw(nf2_of_action_wrap *); -static struct nf2_all_ports_info_addr *nf2_get_all_ports_info_addr(void); - -static void -log_entry(nf2_of_entry_wrap *entry) -{ -#ifndef NF2_DEBUG - return; -#else - int i; - - // Log the physical source port - NF2DEBUGMSG("E psrc[%i] ", entry->entry.src_port / 2); - - // Log the link layer source - NF2DEBUGMSG("dlsrc["); - for (i = 5; i > 0; --i) { - NF2DEBUGMSG("%0X:", entry->entry.eth_src[i]); - } - NF2DEBUGMSG("%0X] ", entry->entry.eth_src[0]); - - // Log the link layer dest - NF2DEBUGMSG("dldst["); - for (i = 5; i > 0; --i) { - NF2DEBUGMSG("%0X:", entry->entry.eth_dst[i]); - } - NF2DEBUGMSG("%0X] ", entry->entry.eth_dst[0]); - - // Log the link layer type - NF2DEBUGMSG("dltype[%0X] ", entry->entry.eth_type); - - // Log the link layer vlan - NF2DEBUGMSG("dlvlan[%0X] ", entry->entry.vlan_id); - - // Log the network source - NF2DEBUGMSG("nwsrc["); - NF2DEBUGMSG("%0i.", (entry->entry.ip_src >> 24) & 0xFF); - NF2DEBUGMSG("%0i.", (entry->entry.ip_src >> 16) & 0xFF); - NF2DEBUGMSG("%0i.", (entry->entry.ip_src >> 8) & 0xFF); - NF2DEBUGMSG("%0i", entry->entry.ip_src & 0xFF); - NF2DEBUGMSG("] "); - - // Log the network dest - NF2DEBUGMSG("nwdst["); - NF2DEBUGMSG("%0i.", (entry->entry.ip_dst >> 24) & 0xFF); - NF2DEBUGMSG("%0i.", (entry->entry.ip_dst >> 16) & 0xFF); - NF2DEBUGMSG("%0i.", (entry->entry.ip_dst >> 8) & 0xFF); - NF2DEBUGMSG("%0i", entry->entry.ip_dst & 0xFF); - NF2DEBUGMSG("] "); - - // Log the transport source port - NF2DEBUGMSG("tsrc[%i] ", entry->entry.transp_src); - - // Log the transport dest port - NF2DEBUGMSG("tdst[%i]\n", entry->entry.transp_dst); -#endif -} - -static void -log_entry_raw(nf2_of_entry_wrap *entry) -{ -#ifndef NF2_DEBUG - return; -#else - int i; - unsigned char *c; - - NF2DEBUGMSG("E "); - c = (unsigned char *)entry; - for (i = 0; i < sizeof(nf2_of_entry_wrap); ++i) { - if (!(i % 4)) { - NF2DEBUGMSG(" "); - } - NF2DEBUGMSG("%02x", c[i]); - } - NF2DEBUGMSG("\n"); -#endif -} - -static void -log_mask(nf2_of_mask_wrap *mask) -{ -#ifndef NF2_DEBUG - return; -#else - int i; - - // Log the physical source port - NF2DEBUGMSG("M psrc[%0X] ", mask->entry.src_port / 2); - - // Log the link layer source - NF2DEBUGMSG("dlsrc["); - for (i = 5; i > 0; --i) { - NF2DEBUGMSG("%0X:", mask->entry.eth_src[i]); - } - NF2DEBUGMSG("%0X] ", mask->entry.eth_dst[0]); - - // Log the link layer dest - NF2DEBUGMSG("dldst["); - for (i = 5; i > 0; --i) { - NF2DEBUGMSG("%0X:", mask->entry.eth_dst[i]); - } - NF2DEBUGMSG("%0X] ", mask->entry.eth_dst[0]); - - // Log the link layer type - NF2DEBUGMSG("dltype[%0X] ", mask->entry.eth_type); - - // Log the link layer vlan - NF2DEBUGMSG("dlvlan[%0X] ", mask->entry.vlan_id); - - // Log the network source - NF2DEBUGMSG("nwsrc["); - NF2DEBUGMSG("%0X.", (mask->entry.ip_src >> 24) & 0xFF); - NF2DEBUGMSG("%0X.", (mask->entry.ip_src >> 16) & 0xFF); - NF2DEBUGMSG("%0X.", (mask->entry.ip_src >> 8) & 0xFF); - NF2DEBUGMSG("%0X", mask->entry.ip_src & 0xFF); - NF2DEBUGMSG("] "); - - // Log the network dest - NF2DEBUGMSG("nwdst["); - NF2DEBUGMSG("%0X.", (mask->entry.ip_dst >> 24) & 0xFF); - NF2DEBUGMSG("%0X.", (mask->entry.ip_dst >> 16) & 0xFF); - NF2DEBUGMSG("%0X.", (mask->entry.ip_dst >> 8) & 0xFF); - NF2DEBUGMSG("%0X", mask->entry.ip_dst & 0xFF); - NF2DEBUGMSG("] "); - - // Log the transport source port - NF2DEBUGMSG("tsrc[%0X] ", mask->entry.transp_src); - - // Log the transport dest port - NF2DEBUGMSG("tdst[%0X]\n", mask->entry.transp_dst); -#endif -} - -static void -log_mask_raw(nf2_of_mask_wrap *mask) -{ -#ifndef NF2_DEBUG - return; -#else - int i; - unsigned char *c; - - NF2DEBUGMSG("M "); - c = (unsigned char *)mask; - for (i = 0; i < sizeof(nf2_of_mask_wrap); ++i) { - if (!(i % 4)) { - NF2DEBUGMSG(" "); - } - NF2DEBUGMSG("%02x", c[i]); - } - NF2DEBUGMSG("\n"); -#endif -} - -static void -log_action(nf2_of_action_wrap *action) -{ -#ifndef NF2_DEBUG - return; -#else - int i; - - NF2DEBUGMSG("A Output P["); - for (i = 0; i < 4; ++i) { - if (action->action.forward_bitmask & (1 << (i * 2))) { - NF2DEBUGMSG("%i", i); - } - } - NF2DEBUGMSG("] CPU["); - for (i = 0; i < 4; ++i) { - if (action->action.forward_bitmask & (1 << (1 + (i * 2)))) { - NF2DEBUGMSG("%i", i); - } - } - NF2DEBUGMSG("]\n"); -#endif -} - -static void -log_action_raw(nf2_of_action_wrap *action) -{ -#ifndef NF2_DEBUG - return; -#else - int i; - unsigned char *c; - - NF2DEBUGMSG("A "); - c = (unsigned char *)action; - for (i = 0; i < sizeof(nf2_of_action_wrap); ++i) { - if (!(i % 4)) { - NF2DEBUGMSG(" "); - } - NF2DEBUGMSG("%02x", c[i]); - } - NF2DEBUGMSG("\n"); -#endif -} - -void -nf2_reset_card(struct net_device *dev) -{ - volatile unsigned int val; - - if (dev == NULL) { - return; - } - - /* If we are operating on a NetFPGA enabled box, reset the card */ - printk(KERN_INFO "openflowswitch-netfpga2: Resetting the NetFPGA.\n"); - nf2k_reg_read(dev, WDT_CPCI_REG_CTRL, (void *)&val); - val |= 0x100; - nf2k_reg_write(dev, WDT_CPCI_REG_CTRL, (void *)&val); - printk(KERN_INFO "openflowswitch-netfpga2: Reset the NetFPGA.\n"); - ssleep(2); -} - -void -nf2_clear_watchdog(struct net_device *dev) -{ - volatile unsigned int enable_status; - -#ifndef NF2_WATCHDOG - return; -#endif - if (dev == NULL) { - return; - } - - nf2k_reg_read(dev, WDT_ENABLE_FLG_REG, (void *)&enable_status); - enable_status &= 0x1; - - if (enable_status == WATCHDOG_DISABLE) { - enable_status = WATCHDOG_ENABLE; - nf2k_reg_write(dev, WDT_ENABLE_FLG_REG, (void *)&enable_status); - } - return; -} - -/* Write a wildcard entry to the specified device and row. The row consists of - * the actual entry, its mask that specifies wildcards, as well as the action(s) - * to be taken if the row is matched - */ -int -nf2_write_of_wildcard(struct net_device *dev, int row, - nf2_of_entry_wrap *entry, nf2_of_mask_wrap *mask, - nf2_of_action_wrap *action) -{ - int i; - int val; - struct timeval t; - - NF2DEBUGMSG("** Begin wildcard entry write to row: %i\n", row); - log_entry(entry); - log_mask(mask); - log_action(action); - log_entry_raw(entry); - log_mask_raw(mask); - log_action_raw(action); - - for (i = 0; i < NF2_OF_ENTRY_WORD_LEN; ++i) { - nf2k_reg_write(dev, - OPENFLOW_WILDCARD_LOOKUP_CMP_0_REG - + (4 * i), &(entry->raw[i])); - } - - for (i = 0; i < NF2_OF_MASK_WORD_LEN; ++i) { - nf2k_reg_write(dev, - OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_0_REG - + (4 * i), &(mask->raw[i])); - } - - for (i = 0; i < NF2_OF_ACTION_WORD_LEN; ++i) { - nf2k_reg_write(dev, - OPENFLOW_WILDCARD_LOOKUP_ACTION_0_REG - + (4 * i), &(action->raw[i])); - } - - // Reset the stats for the row - val = 0; - nf2k_reg_write(dev, - OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG + (4 * row), - &val); - nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG + (4 * row), - &val); - nf2k_reg_write(dev, - OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_0_REG + (4 * row), - &val); - nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_WRITE_ADDR_REG, &row); - - do_gettimeofday(&t); - NF2DEBUGMSG("** End wildcard entry write to row: %i time: %i.%i\n", - row, (int)t.tv_sec, (int)t.tv_usec); - - return 0; -} - -int -nf2_write_of_exact(struct net_device *dev, int row, - nf2_of_entry_wrap *entry, nf2_of_action_wrap *action) -{ - int i; - int val; - struct timeval t; - unsigned int index = row << 7; - - NF2DEBUGMSG("** Begin exact match entry write to row: %i\n", row); - log_entry(entry); - log_action(action); - log_entry_raw(entry); - log_action_raw(action); - - for (i = 0; i < NF2_OF_ENTRY_WORD_LEN; ++i) { - nf2k_reg_write(dev, SRAM_BASE_ADDR + index - + (4 * i), &(entry->raw[i])); - } - - // blank out the counters - val = 0; - for (i = 0; i < NF2_OF_EXACT_COUNTERS_WORD_LEN; ++i) { - nf2k_reg_write(dev, SRAM_BASE_ADDR + index - + sizeof(nf2_of_entry_wrap) - + (4 * i), &val); - } - - // write the actions - for (i = 0; i < NF2_OF_ACTION_WORD_LEN; ++i) { - nf2k_reg_write(dev, SRAM_BASE_ADDR + index - + sizeof(nf2_of_entry_wrap) - + sizeof(nf2_of_exact_counters_wrap) - + (4 * i), &(action->raw[i])); - } - - do_gettimeofday(&t); - NF2DEBUGMSG("** End exact match entry write to row: %i time: %i.%i\n", - row, (int)t.tv_sec, (int)t.tv_usec); - - return 0; -} - -/* Write wildcard action(s) to the specified device and row. */ -int -nf2_modify_write_of_wildcard(struct net_device *dev, int row, - nf2_of_entry_wrap *entry, nf2_of_mask_wrap *mask, - nf2_of_action_wrap *action) -{ - int i; - int bytes_reg_val; - int pkts_reg_val; - int last_reg_val; - struct timeval t; - - NF2DEBUGMSG("** Begin wildcard modified action write to row: %i\n", - row); - log_entry(entry); - log_mask(mask); - log_action(action); - log_entry_raw(entry); - log_mask_raw(mask); - log_action_raw(action); - - nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_READ_ADDR_REG, &row); - nf2k_reg_read(dev, - OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG + (4 * row), - &bytes_reg_val); - nf2k_reg_read(dev, - OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG + (4 * row), - &pkts_reg_val); - nf2k_reg_read(dev, - OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_0_REG + (4 * row), - &last_reg_val); - - for (i = 0; i < NF2_OF_ENTRY_WORD_LEN; ++i) { - nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_CMP_0_REG - + (4 * i), &(entry->raw[i])); - } - - for (i = 0; i < NF2_OF_MASK_WORD_LEN; ++i) { - nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_0_REG - + (4 * i), &(mask->raw[i])); - } - - for (i = 0; i < NF2_OF_ACTION_WORD_LEN; ++i) { - nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_ACTION_0_REG - + (4 * i), &(action->raw[i])); - } - - nf2k_reg_write(dev, - OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG + (4 * row), - &bytes_reg_val); - nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG + (4 * row), - &pkts_reg_val); - nf2k_reg_write(dev, - OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_0_REG + (4 * row), - &last_reg_val); - nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_WRITE_ADDR_REG, &row); - - do_gettimeofday(&t); - NF2DEBUGMSG - ("** End wildcard modified action write to row: %i time: %i.%i\n", - row, (int)t.tv_sec, (int)t.tv_usec); - NF2DEBUGMSG(" Bytes hit count: %d\n", bytes_reg_val); - NF2DEBUGMSG(" Pkts hit count: %d\n", pkts_reg_val); - NF2DEBUGMSG(" Last seen : %d\n", last_reg_val); - - return 0; -} - -int -nf2_modify_write_of_exact(struct net_device *dev, int row, - nf2_of_action_wrap *action) -{ - int i; - struct timeval t; - unsigned int index = row << 7; - - NF2DEBUGMSG("** Begin exact match modified action write to row: %i\n", - row); - log_action(action); - log_action_raw(action); - - // write the actions - for (i = 0; i < NF2_OF_ACTION_WORD_LEN; ++i) { - nf2k_reg_write(dev, SRAM_BASE_ADDR + index - + sizeof(nf2_of_entry_wrap) - + sizeof(nf2_of_exact_counters_wrap) - + (4 * i), &(action->raw[i])); - } - - do_gettimeofday(&t); - NF2DEBUGMSG - ("** End exact match modified action write to row: %i time: %i.%i\n", - row, (int)t.tv_sec, (int)t.tv_usec); - - return 0; -} - -unsigned int -nf2_get_exact_packet_count(struct net_device *dev, int row) -{ - unsigned int val = 0; - unsigned int index = 0; - - /* TODO: Need to scrape data from all 4 registers - * in the case of a wildcarded source port and - * forward all action type - */ - nf2_of_exact_counters_wrap counters; - memset(&counters, 0, sizeof(nf2_of_exact_counters_wrap)); - - // build the index to our counters - index = row << 7; - - // Read the first word into our struct, to not disturb the byte count - nf2k_reg_read(dev, - SRAM_BASE_ADDR + index + sizeof(nf2_of_entry_wrap), - &counters); - val = counters.counters.pkt_count; - - NF2DEBUGMSG("** Exact match packet count request row: %i count: %i\n", - row, val); - - return val; -} - -unsigned int -nf2_get_exact_byte_count(struct net_device *dev, int row) -{ - unsigned int val = 0; - unsigned int index = 0; - - /* TODO: Need to scrape data from all 4 registers - * in the case of a wildcarded source port and - * forward all action type - */ - nf2_of_exact_counters_wrap counters; - memset(&counters, 0, sizeof(nf2_of_exact_counters_wrap)); - - // build the index to our counters - index = row << 7; - - // Read the second word into our struct, to not disturb the packet count - nf2k_reg_read(dev, SRAM_BASE_ADDR + index + - sizeof(nf2_of_entry_wrap) + 4, &counters.raw[1]); - val = counters.counters.byte_count; - - NF2DEBUGMSG("** Exact match byte count request row: %i count: %i\n", - row, val); - - return val; -} - -unsigned int -nf2_get_wildcard_packet_count(struct net_device *dev, int row) -{ - unsigned int val = 0; -#ifdef NF2_DEBUG - struct timeval t; -#endif - - nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_READ_ADDR_REG, &row); - nf2k_reg_read(dev, OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG - + (4 * row), &val); - -#ifdef NF2_DEBUG - do_gettimeofday(&t); - NF2DEBUGMSG - ("** Wildcard packet count request row: %i count: %i time: %i.%i\n", - row, val, (int)t.tv_sec, (int)t.tv_usec); -#endif - - return val; -} - -unsigned int -nf2_get_wildcard_byte_count(struct net_device *dev, int row) -{ - unsigned int val = 0; -#ifdef NF2_DEBUG - struct timeval t; -#endif - - nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_READ_ADDR_REG, &row); - nf2k_reg_read(dev, OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG - + (4 * row), &val); - -#ifdef NF2_DEBUG - do_gettimeofday(&t); - NF2DEBUGMSG - ("** Wildcard byte count request row: %i count: %i time: %i.%i\n", - row, val, (int)t.tv_sec, (int)t.tv_usec); -#endif - - return val; -} - -unsigned long int -nf2_get_matched_count(struct net_device *dev) -{ - unsigned int val_wild = 0; - unsigned int val_exact = 0; -#ifdef NF2_DEBUG - struct timeval t; -#endif - - nf2k_reg_read(dev, OPENFLOW_LOOKUP_WILDCARD_HITS_REG, &val_wild); - nf2k_reg_read(dev, OPENFLOW_LOOKUP_EXACT_HITS_REG, &val_exact); - -#ifdef NF2_DEBUG - do_gettimeofday(&t); - NF2DEBUGMSG("** Wildcard Matched count: %i time: %i.%i\n", - val_wild, (int)t.tv_sec, (int)t.tv_usec); - NF2DEBUGMSG("** Exact Matched count: %i time: %i.%i\n", - val_exact, (int)t.tv_sec, (int)t.tv_usec); -#endif - - return ((unsigned long int)(val_wild + val_exact)); -} - -unsigned long int -nf2_get_missed_count(struct net_device *dev) -{ - unsigned int val_wild = 0; - unsigned int val_exact = 0; -#ifdef NF2_DEBUG - struct timeval t; -#endif - - nf2k_reg_read(dev, OPENFLOW_LOOKUP_WILDCARD_MISSES_REG, &val_wild); - nf2k_reg_read(dev, OPENFLOW_LOOKUP_EXACT_MISSES_REG, &val_exact); - -#ifdef NF2_DEBUG - do_gettimeofday(&t); - NF2DEBUGMSG("** Wildcard Missed count: %i time: %i.%i\n", - val_wild, (int)t.tv_sec, (int)t.tv_usec); - NF2DEBUGMSG("** Exact Missed count: %i time: %i.%i\n", - val_exact, (int)t.tv_sec, (int)t.tv_usec); -#endif - - return ((unsigned long int)(val_wild + val_exact)); -} - -struct nf2_device_info * -nf2_get_device_info(struct net_device *dev) -{ - struct nf2_device_info *nf2devinfo; - int i; - - nf2devinfo = kzalloc(sizeof(struct nf2_device_info), GFP_KERNEL); - if (nf2devinfo == NULL) - return NULL; - - // Read the version and revision - nf2k_reg_read(dev, DEV_ID_DEVICE_ID_REG, &(nf2devinfo->nf2_device_id)); - nf2k_reg_read(dev, DEV_ID_REVISION_REG, &(nf2devinfo->nf2_device_rev)); - - // Read the design name string - for (i = 0; i < (DEVICE_STR_LEN / 4) - 2; i++) { - nf2k_reg_read(dev, DEV_ID_DEV_STR_0_REG + i * 4, - (uint32_t *)(nf2devinfo->nf2_device_str + i * 4)); - *(uint32_t *)(nf2devinfo->nf2_device_str + i * 4) - = ntohl(*(uint32_t *) - (nf2devinfo->nf2_device_str + i * 4)); - } - nf2devinfo->nf2_device_str[DEVICE_STR_LEN - 1] = '\0'; - - return nf2devinfo; -} - -struct nf2_match_info * -nf2_get_match_info(struct net_device *dev) -{ - struct nf2_match_info *nf2matchinfo; - - nf2matchinfo = kzalloc(sizeof(struct nf2_match_info), GFP_KERNEL); - if (nf2matchinfo == NULL) - return NULL; - - nf2k_reg_read(dev, OPENFLOW_LOOKUP_WILDCARD_MISSES_REG, - &(nf2matchinfo->wildcard_misses)); - nf2k_reg_read(dev, OPENFLOW_LOOKUP_WILDCARD_HITS_REG, - &(nf2matchinfo->wildcard_hits)); - nf2k_reg_read(dev, OPENFLOW_LOOKUP_EXACT_MISSES_REG, - &(nf2matchinfo->exact_misses)); - nf2k_reg_read(dev, OPENFLOW_LOOKUP_EXACT_HITS_REG, - &(nf2matchinfo->exact_hits)); - - return nf2matchinfo; -} - -unsigned int -nf2_get_watchdog_info(struct net_device *dev) -{ - unsigned int nf2wdtinfo = 0; - - nf2k_reg_read(dev, WDT_COUNTER_REG, &nf2wdtinfo); - return nf2wdtinfo; -} - -static struct nf2_all_ports_info_addr * -nf2_get_all_ports_info_addr(void) -{ - struct nf2_all_ports_info_addr *nf2addr; - - nf2addr = kzalloc(sizeof(struct nf2_all_ports_info_addr), GFP_KERNEL); - if (nf2addr == NULL) - return NULL; - - nf2addr->rx_q_num_pkts_stored_reg[0] - = MAC_GRP_0_RX_QUEUE_NUM_PKTS_STORED_REG; - nf2addr->rx_q_num_pkts_dropped_full_reg[0] - = MAC_GRP_0_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG; - nf2addr->rx_q_num_pkts_dropped_bad_reg[0] - = MAC_GRP_0_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG; - nf2addr->rx_q_num_words_pushed_reg[0] - = MAC_GRP_0_RX_QUEUE_NUM_WORDS_PUSHED_REG; - nf2addr->rx_q_num_bytes_pushed_reg[0] - = MAC_GRP_0_RX_QUEUE_NUM_BYTES_PUSHED_REG; - nf2addr->rx_q_num_pkts_dequeued_reg[0] - = MAC_GRP_0_RX_QUEUE_NUM_PKTS_DEQUEUED_REG; - nf2addr->rx_q_num_pkts_in_queue_reg[0] - = MAC_GRP_0_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG; - nf2addr->tx_q_num_pkts_in_queue_reg[0] - = MAC_GRP_0_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG; - nf2addr->tx_q_num_pkts_sent_reg[0] - = MAC_GRP_0_TX_QUEUE_NUM_PKTS_SENT_REG; - nf2addr->tx_q_num_words_pushed_reg[0] - = MAC_GRP_0_TX_QUEUE_NUM_WORDS_PUSHED_REG; - nf2addr->tx_q_num_bytes_pushed_reg[0] - = MAC_GRP_0_TX_QUEUE_NUM_BYTES_PUSHED_REG; - nf2addr->tx_q_num_pkts_enqueued_reg[0] - = MAC_GRP_0_TX_QUEUE_NUM_PKTS_ENQUEUED_REG; - - nf2addr->rx_q_num_pkts_stored_reg[1] - = MAC_GRP_1_RX_QUEUE_NUM_PKTS_STORED_REG; - nf2addr->rx_q_num_pkts_dropped_full_reg[1] - = MAC_GRP_1_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG; - nf2addr->rx_q_num_pkts_dropped_bad_reg[1] - = MAC_GRP_1_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG; - nf2addr->rx_q_num_words_pushed_reg[1] - = MAC_GRP_1_RX_QUEUE_NUM_WORDS_PUSHED_REG; - nf2addr->rx_q_num_bytes_pushed_reg[1] - = MAC_GRP_1_RX_QUEUE_NUM_BYTES_PUSHED_REG; - nf2addr->rx_q_num_pkts_dequeued_reg[1] - = MAC_GRP_1_RX_QUEUE_NUM_PKTS_DEQUEUED_REG; - nf2addr->rx_q_num_pkts_in_queue_reg[1] - = MAC_GRP_1_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG; - nf2addr->tx_q_num_pkts_in_queue_reg[1] - = MAC_GRP_1_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG; - nf2addr->tx_q_num_pkts_sent_reg[1] - = MAC_GRP_1_TX_QUEUE_NUM_PKTS_SENT_REG; - nf2addr->tx_q_num_words_pushed_reg[1] - = MAC_GRP_1_TX_QUEUE_NUM_WORDS_PUSHED_REG; - nf2addr->tx_q_num_bytes_pushed_reg[1] - = MAC_GRP_1_TX_QUEUE_NUM_BYTES_PUSHED_REG; - nf2addr->tx_q_num_pkts_enqueued_reg[1] - = MAC_GRP_1_TX_QUEUE_NUM_PKTS_ENQUEUED_REG; - - nf2addr->rx_q_num_pkts_stored_reg[2] - = MAC_GRP_2_RX_QUEUE_NUM_PKTS_STORED_REG; - nf2addr->rx_q_num_pkts_dropped_full_reg[2] - = MAC_GRP_2_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG; - nf2addr->rx_q_num_pkts_dropped_bad_reg[2] - = MAC_GRP_2_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG; - nf2addr->rx_q_num_words_pushed_reg[2] - = MAC_GRP_2_RX_QUEUE_NUM_WORDS_PUSHED_REG; - nf2addr->rx_q_num_bytes_pushed_reg[2] - = MAC_GRP_2_RX_QUEUE_NUM_BYTES_PUSHED_REG; - nf2addr->rx_q_num_pkts_dequeued_reg[2] - = MAC_GRP_2_RX_QUEUE_NUM_PKTS_DEQUEUED_REG; - nf2addr->rx_q_num_pkts_in_queue_reg[2] - = MAC_GRP_2_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG; - nf2addr->tx_q_num_pkts_in_queue_reg[2] - = MAC_GRP_2_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG; - nf2addr->tx_q_num_pkts_sent_reg[2] - = MAC_GRP_2_TX_QUEUE_NUM_PKTS_SENT_REG; - nf2addr->tx_q_num_words_pushed_reg[2] - = MAC_GRP_2_TX_QUEUE_NUM_WORDS_PUSHED_REG; - nf2addr->tx_q_num_bytes_pushed_reg[2] - = MAC_GRP_2_TX_QUEUE_NUM_BYTES_PUSHED_REG; - nf2addr->tx_q_num_pkts_enqueued_reg[2] - = MAC_GRP_2_TX_QUEUE_NUM_PKTS_ENQUEUED_REG; - - nf2addr->rx_q_num_pkts_stored_reg[3] - = MAC_GRP_3_RX_QUEUE_NUM_PKTS_STORED_REG; - nf2addr->rx_q_num_pkts_dropped_full_reg[3] - = MAC_GRP_3_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG; - nf2addr->rx_q_num_pkts_dropped_bad_reg[3] - = MAC_GRP_3_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG; - nf2addr->rx_q_num_words_pushed_reg[3] - = MAC_GRP_3_RX_QUEUE_NUM_WORDS_PUSHED_REG; - nf2addr->rx_q_num_bytes_pushed_reg[3] - = MAC_GRP_3_RX_QUEUE_NUM_BYTES_PUSHED_REG; - nf2addr->rx_q_num_pkts_dequeued_reg[3] - = MAC_GRP_3_RX_QUEUE_NUM_PKTS_DEQUEUED_REG; - nf2addr->rx_q_num_pkts_in_queue_reg[3] - = MAC_GRP_3_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG; - nf2addr->tx_q_num_pkts_in_queue_reg[3] - = MAC_GRP_3_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG; - nf2addr->tx_q_num_pkts_sent_reg[3] - = MAC_GRP_3_TX_QUEUE_NUM_PKTS_SENT_REG; - nf2addr->tx_q_num_words_pushed_reg[3] - = MAC_GRP_3_TX_QUEUE_NUM_WORDS_PUSHED_REG; - nf2addr->tx_q_num_bytes_pushed_reg[3] - = MAC_GRP_3_TX_QUEUE_NUM_BYTES_PUSHED_REG; - nf2addr->tx_q_num_pkts_enqueued_reg[3] - = MAC_GRP_3_TX_QUEUE_NUM_PKTS_ENQUEUED_REG; - - return nf2addr; -} - -struct nf2_all_ports_info * -nf2_get_all_ports_info(struct net_device *dev) -{ - struct nf2_all_ports_info *nf2portinfo; - struct nf2_all_ports_info_addr *nf2addr; - int i; - - nf2portinfo = kzalloc(sizeof(struct nf2_all_ports_info), GFP_KERNEL); - if (nf2portinfo == NULL) - return NULL; - nf2addr = nf2_get_all_ports_info_addr(); - if (nf2addr == NULL) - return NULL; - - for (i = 0; i < NF2_PORT_NUM; i++) { - nf2k_reg_read(dev, nf2addr->rx_q_num_pkts_stored_reg[i], - &(nf2portinfo->port[i].rx_q_num_pkts_stored)); - nf2k_reg_read(dev, nf2addr->rx_q_num_pkts_dropped_full_reg[i], - &(nf2portinfo - ->port[i].rx_q_num_pkts_dropped_full)); - nf2k_reg_read(dev, nf2addr->rx_q_num_pkts_dropped_bad_reg[i], - &(nf2portinfo - ->port[i].rx_q_num_pkts_dropped_bad)); - nf2k_reg_read(dev, nf2addr->rx_q_num_words_pushed_reg[i], - &(nf2portinfo->port[i].rx_q_num_words_pushed)); - nf2k_reg_read(dev, nf2addr->rx_q_num_bytes_pushed_reg[i], - &(nf2portinfo->port[i].rx_q_num_bytes_pushed)); - nf2k_reg_read(dev, nf2addr->rx_q_num_pkts_dequeued_reg[i], - &(nf2portinfo->port[i].rx_q_num_pkts_dequeued)); - nf2k_reg_read(dev, nf2addr->rx_q_num_pkts_in_queue_reg[i], - &(nf2portinfo->port[i].rx_q_num_pkts_in_queue)); - nf2k_reg_read(dev, nf2addr->tx_q_num_pkts_in_queue_reg[i], - &(nf2portinfo->port[i].tx_q_num_pkts_in_queue)); - nf2k_reg_read(dev, nf2addr->tx_q_num_pkts_sent_reg[i], - &(nf2portinfo->port[i].tx_q_num_pkts_sent)); - nf2k_reg_read(dev, nf2addr->tx_q_num_words_pushed_reg[i], - &(nf2portinfo->port[i].tx_q_num_words_pushed)); - nf2k_reg_read(dev, nf2addr->tx_q_num_bytes_pushed_reg[i], - &(nf2portinfo->port[i].tx_q_num_bytes_pushed)); - nf2k_reg_read(dev, nf2addr->tx_q_num_pkts_enqueued_reg[i], - &(nf2portinfo->port[i].tx_q_num_pkts_enqueued)); - } - return nf2portinfo; -} diff --git a/openflow/datapath/hwtable_nf2/nf2_openflow.h b/openflow/datapath/hwtable_nf2/nf2_openflow.h deleted file mode 100644 index 2be4b651..00000000 --- a/openflow/datapath/hwtable_nf2/nf2_openflow.h +++ /dev/null @@ -1,169 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#ifndef HATABLE_NF2_NF2_OPENFLOW_H_ -#define HATABLE_NF2_NF2_OPENFLOW_H_ - -#define OPENFLOW_NF2_EXACT_TABLE_SIZE 32768 -#define WATCHDOG_ENABLE 1 -#define WATCHDOG_DISABLE 0 - -#pragma pack(push) /* push current alignment to stack */ -#pragma pack(1) /* set alignment to 1 byte boundary */ - -#define NF2_OF_ENTRY_WORD_LEN 8 -struct nf2_of_entry { - uint16_t transp_dst; - uint16_t transp_src; - uint8_t ip_proto; - uint32_t ip_dst; - uint32_t ip_src; - uint16_t eth_type; - uint8_t eth_dst[6]; - uint8_t eth_src[6]; - uint8_t src_port; - uint16_t vlan_id; - uint16_t pad; -}; - -typedef union nf2_of_entry_wrap { - struct nf2_of_entry entry; - uint32_t raw[NF2_OF_ENTRY_WORD_LEN]; -} nf2_of_entry_wrap; - -typedef nf2_of_entry_wrap nf2_of_mask_wrap; -#define NF2_OF_MASK_WORD_LEN 8 - -struct nf2_of_action { - uint16_t forward_bitmask; - uint16_t nf2_action_flag; - uint16_t vlan_id; - uint8_t vlan_pcp; - uint8_t eth_src[6]; - uint8_t eth_dst[6]; - uint32_t ip_src; - uint32_t ip_dst; - uint16_t transp_src; - uint16_t transp_dst; - uint8_t reserved[19]; -}; - -#define NF2_OF_ACTION_WORD_LEN 10 -typedef union nf2_of_action_wrap { - struct nf2_of_action action; - uint32_t raw[10]; -} nf2_of_action_wrap; - -struct nf2_of_exact_counters { - uint32_t pkt_count:25; - uint8_t last_seen:7; - uint32_t byte_count; -}; - -#define NF2_OF_EXACT_COUNTERS_WORD_LEN 2 -typedef union nf2_of_exact_counters_wrap { - struct nf2_of_exact_counters counters; - uint32_t raw[NF2_OF_EXACT_COUNTERS_WORD_LEN]; -} nf2_of_exact_counters_wrap; - -#define DEVICE_STR_LEN 100 -struct nf2_device_info { - uint32_t nf2_device_id; - uint32_t nf2_device_rev; - char nf2_device_str[DEVICE_STR_LEN]; -}; - -#define NF2_PORT_NUM 4 -struct nf2_all_ports_info_addr { - unsigned int rx_q_num_pkts_stored_reg[NF2_PORT_NUM]; - unsigned int rx_q_num_pkts_dropped_full_reg[NF2_PORT_NUM]; - unsigned int rx_q_num_pkts_dropped_bad_reg[NF2_PORT_NUM]; - unsigned int rx_q_num_words_pushed_reg[NF2_PORT_NUM]; - unsigned int rx_q_num_bytes_pushed_reg[NF2_PORT_NUM]; - unsigned int rx_q_num_pkts_dequeued_reg[NF2_PORT_NUM]; - unsigned int rx_q_num_pkts_in_queue_reg[NF2_PORT_NUM]; - unsigned int tx_q_num_pkts_in_queue_reg[NF2_PORT_NUM]; - unsigned int tx_q_num_pkts_sent_reg[NF2_PORT_NUM]; - unsigned int tx_q_num_words_pushed_reg[NF2_PORT_NUM]; - unsigned int tx_q_num_bytes_pushed_reg[NF2_PORT_NUM]; - unsigned int tx_q_num_pkts_enqueued_reg[NF2_PORT_NUM]; -}; - -struct nf2_port_info { - uint32_t rx_q_num_pkts_stored; - uint32_t rx_q_num_pkts_dropped_full; - uint32_t rx_q_num_pkts_dropped_bad; - uint32_t rx_q_num_words_pushed; - uint32_t rx_q_num_bytes_pushed; - uint32_t rx_q_num_pkts_dequeued; - uint32_t rx_q_num_pkts_in_queue; - uint32_t tx_q_num_pkts_in_queue; - uint32_t tx_q_num_pkts_sent; - uint32_t tx_q_num_words_pushed; - uint32_t tx_q_num_bytes_pushed; - uint32_t tx_q_num_pkts_enqueued; -}; - -struct nf2_all_ports_info { - struct nf2_port_info port[NF2_PORT_NUM]; -}; - -struct nf2_match_info { - uint32_t wildcard_misses; - uint32_t wildcard_hits; - uint32_t exact_misses; - uint32_t exact_hits; -}; - -#pragma pack(pop) /* XXX: Restore original alignment from stack */ - -void nf2_reset_card(struct net_device *); -void nf2_clear_watchdog(struct net_device *); -int nf2_write_of_wildcard(struct net_device *, int, nf2_of_entry_wrap *, - nf2_of_mask_wrap *, nf2_of_action_wrap *); -int nf2_write_of_exact(struct net_device *, int, nf2_of_entry_wrap *, - nf2_of_action_wrap *); -int nf2_modify_write_of_wildcard(struct net_device *, int, nf2_of_entry_wrap *, - nf2_of_mask_wrap *, nf2_of_action_wrap *); -int nf2_modify_write_of_exact(struct net_device *, int, nf2_of_action_wrap *); -unsigned int nf2_get_exact_packet_count(struct net_device *, int); -unsigned int nf2_get_exact_byte_count(struct net_device *, int); -unsigned int nf2_get_wildcard_packet_count(struct net_device *, int); -unsigned int nf2_get_wildcard_byte_count(struct net_device *, int); -unsigned long int nf2_get_matched_count(struct net_device *); -unsigned long int nf2_get_missed_count(struct net_device *); -struct nf2_device_info *nf2_get_device_info(struct net_device *); -struct nf2_match_info *nf2_get_match_info(struct net_device *); -unsigned int nf2_get_watchdog_info(struct net_device *); -struct nf2_all_ports_info *nf2_get_all_ports_info(struct net_device *); - -#endif diff --git a/openflow/datapath/hwtable_nf2/nf2_procfs.c b/openflow/datapath/hwtable_nf2/nf2_procfs.c deleted file mode 100644 index 0324afcb..00000000 --- a/openflow/datapath/hwtable_nf2/nf2_procfs.c +++ /dev/null @@ -1,240 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "chain.h" -#include "table.h" -#include "flow.h" -#include "datapath.h" - -#include "hwtable_nf2/nf2_reg.h" -#include "hwtable_nf2/nf2_flowtable.h" -#include "hwtable_nf2/nf2_openflow.h" -#include "hwtable_nf2/nf2_lib.h" -#include "hwtable_nf2/nf2_procfs.h" - -#define NF2_PROCFS_NAME "net/openflow-netfpga" -#define CLK_CYCLE 8 - -static struct semaphore proc_sem; - -static int disp_dev_info(char *); -static int disp_port_info(char *); -static int disp_match_info(char *); -static int disp_watchdog_info(char *); -static int proc_read(char *, char **, off_t, int, int *, void *); - -static int -disp_dev_info(char *page) -{ - struct net_device *netdev; - struct nf2_device_info *nf2devinfo; - int len = 0; - - netdev = nf2_get_net_device(); - if (netdev == NULL) - return 0; - nf2devinfo = nf2_get_device_info(netdev); - if (nf2devinfo == NULL) { - nf2_free_net_device(netdev); - return 0; - } - nf2_free_net_device(netdev); - - len += sprintf(page + len, - "NetFPGA: " - "design name: %s, device ID: %d, device revision: %d\n", - nf2devinfo->nf2_device_str, - nf2devinfo->nf2_device_id, nf2devinfo->nf2_device_rev); - len += sprintf(page + len, "\n"); - - return len; -} - -static int -disp_port_info(char *page) -{ - struct net_device *netdev; - struct nf2_all_ports_info *nf2portinfo; - int len = 0; - int i; - - netdev = nf2_get_net_device(); - if (netdev == NULL) - return 0; - nf2portinfo = nf2_get_all_ports_info(netdev); - if (nf2portinfo == NULL) { - nf2_free_net_device(netdev); - return 0; - } - nf2_free_net_device(netdev); - - for (i = 0; i < NF2_PORT_NUM; i++) { - len += sprintf(page + len, "Interface nf2c%d\n", i); - len += sprintf(page + len, - " Input queue: %u/%u (current/queued)\n", - nf2portinfo->port[i].rx_q_num_pkts_in_queue, - nf2portinfo->port[i].rx_q_num_pkts_dequeued); - len += sprintf(page + len, - " %u packets input, %u dropped " - "(%u buffer exhausted, %u bad packets)\n" - " %u pushed words, %u pushed bytes\n", - nf2portinfo->port[i].rx_q_num_pkts_stored, - nf2portinfo->port[i].rx_q_num_pkts_dropped_full - + nf2portinfo->port[i].rx_q_num_pkts_dropped_bad, - nf2portinfo->port[i].rx_q_num_pkts_dropped_full, - nf2portinfo->port[i].rx_q_num_pkts_dropped_bad, - nf2portinfo->port[i].rx_q_num_words_pushed, - nf2portinfo->port[i].rx_q_num_bytes_pushed); - len += sprintf(page + len, - " Output queue: %u/%u (current/queued)\n", - nf2portinfo->port[i].tx_q_num_pkts_in_queue, - nf2portinfo->port[i].tx_q_num_pkts_enqueued); - len += sprintf(page + len, - " %u packets output, " - "%u pushed words, %u pushed bytes\n", - nf2portinfo->port[i].tx_q_num_pkts_sent, - nf2portinfo->port[i].tx_q_num_words_pushed, - nf2portinfo->port[i].tx_q_num_bytes_pushed); - } - len += sprintf(page + len, "\n"); - - return len; -} - -static int -disp_match_info(char *page) -{ - struct net_device *netdev; - struct nf2_match_info *nf2matchinfo; - int len = 0; - - netdev = nf2_get_net_device(); - if (netdev == NULL) - return 0; - nf2matchinfo = nf2_get_match_info(netdev); - if (nf2matchinfo == NULL) { - nf2_free_net_device(netdev); - return 0; - } - nf2_free_net_device(netdev); - - len += sprintf(page + len, - "WILDCARD match table lookup: %u/%u (hits/misses)\n", - nf2matchinfo->wildcard_hits, - nf2matchinfo->wildcard_misses); - len += sprintf(page + len, - "EXACT match table lookup: %u/%u (hits/misses)\n", - nf2matchinfo->exact_hits, nf2matchinfo->exact_misses); - len += sprintf(page + len, "\n"); - - return len; -} - -static int -disp_watchdog_info(char *page) -{ - struct net_device *netdev; - unsigned int nf2wdtinfo; - unsigned int elapsed_time; - int len = 0; - -#ifndef NF2_WATCHDOG - return 0; -#endif - - netdev = nf2_get_net_device(); - if (netdev == NULL) - return 0; - nf2wdtinfo = nf2_get_watchdog_info(netdev); - nf2_free_net_device(netdev); - - elapsed_time = nf2wdtinfo * CLK_CYCLE / 1000000; - - len += sprintf(page + len, - "%u (msec) passed since the watchdog counter has been cleared last time\n", - elapsed_time); - len += sprintf(page + len, "\n"); - - return len; -} - -static int -proc_read(char *page, char **start, off_t offset, int count, int *eof, - void *data) -{ - int len = 0; - int buf_pos = 1; - - if (down_interruptible(&proc_sem)) - return -ERESTARTSYS; - - if (buf_pos != 0) { - len += disp_dev_info(page + len); - len += disp_port_info(page + len); - len += disp_match_info(page + len); - len += disp_watchdog_info(page + len); - buf_pos = 0; - } - up(&proc_sem); - - *eof = 1; - return len; -} - -void -nf2_create_procfs(void) -{ - struct proc_dir_entry *entry; - - entry = create_proc_entry(NF2_PROCFS_NAME, - S_IFREG | S_IRUGO | S_IWUGO, NULL); - if (entry == NULL) - return; - - entry->read_proc = proc_read; - sema_init(&proc_sem, 1); -} - -void -nf2_remove_procfs(void) -{ - remove_proc_entry(NF2_PROCFS_NAME, NULL); -} diff --git a/openflow/datapath/hwtable_nf2/nf2_procfs.h b/openflow/datapath/hwtable_nf2/nf2_procfs.h deleted file mode 100644 index 011f680f..00000000 --- a/openflow/datapath/hwtable_nf2/nf2_procfs.h +++ /dev/null @@ -1,39 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#ifndef HWTABLE_NF2_NF2_PROCFS_ -#define HWTABLE_NF2_NF2_PROCFS_ - -void nf2_create_procfs(void); -void nf2_remove_procfs(void); - -#endif diff --git a/openflow/datapath/hwtable_nf2/nf2_reg.h b/openflow/datapath/hwtable_nf2/nf2_reg.h deleted file mode 100644 index 0056f882..00000000 --- a/openflow/datapath/hwtable_nf2/nf2_reg.h +++ /dev/null @@ -1,767 +0,0 @@ -/******************************************************** -* -* C register defines file for openflow_switch -* -********************************************************/ - -#ifndef _REG_DEFINES_ -#define _REG_DEFINES_ - -/* ========= Constants ========= */ - -// ===== File: lib/verilog/core/common/xml/global.xml ===== - -// Maximum number of phy ports -#define MAX_PHY_PORTS 4 - -// PCI address bus width -#define PCI_ADDR_WIDTH 32 - -// PCI data bus width -#define PCI_DATA_WIDTH 32 - -// PCI byte enable bus width -#define PCI_BE_WIDTH 4 - -// CPCI--CNET address bus width. This is byte addresses even though bottom bits are zero. -#define CPCI_CNET_ADDR_WIDTH 27 - -// CPCI--CNET data bus width -#define CPCI_CNET_DATA_WIDTH 32 - -// CPCI--NF2 address bus width. This is byte addresses even though bottom bits are zero. -#define CPCI_NF2_ADDR_WIDTH 27 - -// CPCI--NF2 data bus width -#define CPCI_NF2_DATA_WIDTH 32 - -// DMA data bus width -#define DMA_DATA_WIDTH 32 - -// DMA control bus width -#define DMA_CTRL_WIDTH 4 - -// CPCI debug bus width -#define CPCI_DEBUG_DATA_WIDTH 29 - -// SRAM address width -#define SRAM_ADDR_WIDTH 19 - -// SRAM data width -#define SRAM_DATA_WIDTH 36 - -// DRAM address width -#define DRAM_ADDR_WIDTH 24 - -// ===== File: lib/verilog/core/common/xml/nf_defines.xml ===== - -// Clock period of 125 MHz clock in ns -#define FAST_CLK_PERIOD 8 - -// Clock period of 62.5 MHz clock in ns -#define SLOW_CLK_PERIOD 16 - -// Header value used by the IO queues -#define IO_QUEUE_STAGE_NUM 0xff - -// Data path data width -#define DATA_WIDTH 64 - -// Data path control width -#define CTRL_WIDTH 8 - -// ===== File: projects/openflow_switch/include/output_port_lookup.xml ===== - -#define FAST_CLOCK_PERIOD 8 - -// ===== File: projects/openflow_switch/include/vlan_remover.xml ===== - -#define VLAN_CTRL_WORD 0x42 - -#define VLAN_ETHERTYPE 0x8100 - -// ===== File: lib/verilog/core/output_queues/bram_output_queues/xml/bram_output_queues.xml ===== - -#define NUM_OUTPUT_QUEUES 8 - -// ===== File: projects/openflow_switch/include/opl_processor.xml ===== - -#define NF2_OFPAT_OUTPUT 0x0001 - -#define NF2_OFPAT_SET_VLAN_VID 0x0002 - -#define NF2_OFPAT_SET_VLAN_PCP 0x0004 - -#define NF2_OFPAT_STRIP_VLAN 0x0008 - -#define NF2_OFPAT_SET_DL_SRC 0x0010 - -#define NF2_OFPAT_SET_DL_DST 0x0020 - -#define NF2_OFPAT_SET_NW_SRC 0x0040 - -#define NF2_OFPAT_SET_NW_DST 0x0080 - -#define NF2_OFPAT_SET_TP_SRC 0x0100 - -#define NF2_OFPAT_SET_TP_DST 0x0200 - -// ===== File: projects/openflow_switch/include/wildcard_match.xml ===== - -#define OPENFLOW_WILDCARD_TABLE_SIZE 32 - -#define OPENFLOW_WILDCARD_NUM_DATA_WORDS_USED 10 - -#define OPENFLOW_WILDCARD_NUM_CMP_WORDS_USED 8 - -// ===== File: lib/verilog/core/utils/xml/device_id_reg.xml ===== - -// Total number of registers -#define DEV_ID_NUM_REGS 32 - -// Number of non string registers -#define DEV_ID_NON_DEV_STR_REGS 7 - -// Device description length (in words, not chars) -#define DEV_ID_DEV_STR_WORD_LEN 25 - -// Device description length (in bytes/chars) -#define DEV_ID_DEV_STR_BYTE_LEN 100 - -// Device description length (in bits) -#define DEV_ID_DEV_STR_BIT_LEN 800 - -// Length of MD5 sum (bits) -#define DEV_ID_MD5SUM_LENGTH 128 - -// MD5 sum of the string "device_id.v" -#define DEV_ID_MD5_VALUE 0x4071736d8a603d2b4d55f62989a73c95 -#define DEV_ID_MD5_VALUE_0 0x4071736d -#define DEV_ID_MD5_VALUE_1 0x8a603d2b -#define DEV_ID_MD5_VALUE_2 0x4d55f629 -#define DEV_ID_MD5_VALUE_3 0x89a73c95 - -// ===== File: projects/openflow_switch/include/header_parser.xml ===== - -#define ETH_TYPE_IP 0x0800 - -#define IP_PROTO_TCP 0x06 - -#define IP_PROTO_UDP 0x11 - -#define IP_PROTO_ICMP 0x01 - -// ===== File: projects/openflow_switch/include/watchdog.xml ===== - -#define WDT_CPCI_REG_CTRL 0x00000008 - -// ===== File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml ===== - -// TX queue disable bit -#define MAC_GRP_TX_QUEUE_DISABLE_BIT_NUM 0 - -// RX queue disable bit -#define MAC_GRP_RX_QUEUE_DISABLE_BIT_NUM 1 - -// Reset MAC bit -#define MAC_GRP_RESET_MAC_BIT_NUM 2 - -// MAC TX queue disable bit -#define MAC_GRP_MAC_DISABLE_TX_BIT_NUM 3 - -// MAC RX queue disable bit -#define MAC_GRP_MAC_DISABLE_RX_BIT_NUM 4 - -// MAC disable jumbo TX bit -#define MAC_GRP_MAC_DIS_JUMBO_TX_BIT_NUM 5 - -// MAC disable jumbo RX bit -#define MAC_GRP_MAC_DIS_JUMBO_RX_BIT_NUM 6 - -// MAC disable crc check disable bit -#define MAC_GRP_MAC_DIS_CRC_CHECK_BIT_NUM 7 - -// MAC disable crc generate bit -#define MAC_GRP_MAC_DIS_CRC_GEN_BIT_NUM 8 - -// ===== File: projects/openflow_switch/include/match_arbiter.xml ===== - -#define OPENFLOW_ENTRY_TRANSP_DST_WIDTH 16 - -#define OPENFLOW_ENTRY_TRANSP_DST_POS 0 - -#define OPENFLOW_ENTRY_TRANSP_SRC_WIDTH 16 - -#define OPENFLOW_ENTRY_TRANSP_SRC_POS 16 - -#define OPENFLOW_ENTRY_IP_PROTO_WIDTH 8 - -#define OPENFLOW_ENTRY_IP_PROTO_POS 32 - -#define OPENFLOW_ENTRY_IP_DST_WIDTH 32 - -#define OPENFLOW_ENTRY_IP_DST_POS 40 - -#define OPENFLOW_ENTRY_IP_SRC_WIDTH 32 - -#define OPENFLOW_ENTRY_IP_SRC_POS 72 - -#define OPENFLOW_ENTRY_ETH_TYPE_WIDTH 16 - -#define OPENFLOW_ENTRY_ETH_TYPE_POS 104 - -#define OPENFLOW_ENTRY_ETH_DST_WIDTH 48 - -#define OPENFLOW_ENTRY_ETH_DST_POS 120 - -#define OPENFLOW_ENTRY_ETH_SRC_WIDTH 48 - -#define OPENFLOW_ENTRY_ETH_SRC_POS 168 - -#define OPENFLOW_ENTRY_SRC_PORT_WIDTH 8 - -#define OPENFLOW_ENTRY_SRC_PORT_POS 216 - -#define OPENFLOW_ENTRY_VLAN_ID_WIDTH 16 - -#define OPENFLOW_ENTRY_VLAN_ID_POS 224 - -#define OPENFLOW_ENTRY_WIDTH 240 - -// The actionfield is composed of a bitmask specifying actions to take and arguments. -#define OPENFLOW_ACTION_WIDTH 320 - -// Ports to forward on -#define OPENFLOW_FORWARD_BITMASK_WIDTH 16 - -#define OPENFLOW_FORWARD_BITMASK_POS 0 - -#define OPENFLOW_NF2_ACTION_FLAG_WIDTH 16 - -#define OPENFLOW_NF2_ACTION_FLAG_POS 16 - -// Vlan ID to be replaced -#define OPENFLOW_SET_VLAN_VID_WIDTH 16 - -#define OPENFLOW_SET_VLAN_VID_POS 32 - -// Vlan priority to be replaced -#define OPENFLOW_SET_VLAN_PCP_WIDTH 8 - -#define OPENFLOW_SET_VLAN_PCP_POS 48 - -// Source MAC address to be replaced -#define OPENFLOW_SET_DL_SRC_WIDTH 48 - -#define OPENFLOW_SET_DL_SRC_POS 56 - -// Destination MAC address to be replaced -#define OPENFLOW_SET_DL_DST_WIDTH 48 - -#define OPENFLOW_SET_DL_DST_POS 104 - -// Source network address to be replaced -#define OPENFLOW_SET_NW_SRC_WIDTH 32 - -#define OPENFLOW_SET_NW_SRC_POS 152 - -// Destination network address to be replaced -#define OPENFLOW_SET_NW_DST_WIDTH 32 - -#define OPENFLOW_SET_NW_DST_POS 184 - -// Source transport port to be replaced -#define OPENFLOW_SET_TP_SRC_WIDTH 16 - -#define OPENFLOW_SET_TP_SRC_POS 216 - -// Destination transport port to be replaced -#define OPENFLOW_SET_TP_DST_WIDTH 16 - -#define OPENFLOW_SET_TP_DST_POS 232 - -// ===== File: projects/openflow_switch/include/exact_match.xml ===== - -#define OPENFLOW_EXACT_ENTRY_PKT_COUNTER_WIDTH 25 - -#define OPENFLOW_EXACT_ENTRY_PKT_COUNTER_POS 0 - -#define OPENFLOW_EXACT_ENTRY_LAST_SEEN_WIDTH 7 - -#define OPENFLOW_EXACT_ENTRY_LAST_SEEN_POS 25 - -#define OPENFLOW_EXACT_ENTRY_BYTE_COUNTER_WIDTH 32 - -#define OPENFLOW_EXACT_ENTRY_BYTE_COUNTER_POS 32 - -#define OPENFLOW_EXACT_ENTRY_HDR_BASE_POS 0x00000000 - -#define OPENFLOW_EXACT_ENTRY_COUNTERS_POS 0x00000008 - -#define OPENFLOW_EXACT_ENTRY_ACTION_BASE_POS 0x0000000a - -// ------------------------------------- -// Modules -// ------------------------------------- - -// Module tags -#define CORE_BASE_ADDR 0x0000000 -#define DEV_ID_BASE_ADDR 0x0400000 -#define MDIO_BASE_ADDR 0x0440000 -#define DMA_BASE_ADDR 0x0500000 -#define MAC_GRP_0_BASE_ADDR 0x0600000 -#define MAC_GRP_1_BASE_ADDR 0x0640000 -#define MAC_GRP_2_BASE_ADDR 0x0680000 -#define MAC_GRP_3_BASE_ADDR 0x06c0000 -#define CPU_QUEUE_0_BASE_ADDR 0x0700000 -#define CPU_QUEUE_1_BASE_ADDR 0x0740000 -#define CPU_QUEUE_2_BASE_ADDR 0x0780000 -#define CPU_QUEUE_3_BASE_ADDR 0x07c0000 -#define SRAM_BASE_ADDR 0x1000000 -#define UDP_BASE_ADDR 0x2000000 -#define OPENFLOW_LOOKUP_BASE_ADDR 0x2000000 -#define IN_ARB_BASE_ADDR 0x2000100 -#define VLAN_REMOVER_BASE_ADDR 0x2000200 -#define OPL_PROCESSOR_BASE_ADDR 0x2000240 -#define HEADER_PARSER_BASE_ADDR 0x2000280 -#define MATCH_ARBITER_BASE_ADDR 0x20002c0 -#define BRAM_OQ_BASE_ADDR 0x2000300 -#define WDT_BASE_ADDR 0x2000400 -#define EXACT_MATCH_BASE_ADDR 0x2000500 -#define OPENFLOW_WILDCARD_LOOKUP_BASE_ADDR 0x2001000 -#define DRAM_BASE_ADDR 0x4000000 - -#define CPU_QUEUE_OFFSET 0x0040000 -#define MAC_GRP_OFFSET 0x0040000 - -/* ========== Registers ========== */ - -// Name: device_id (DEV_ID) -// Description: Device identification -// File: lib/verilog/core/utils/xml/device_id_reg.xml -#define DEV_ID_MD5_0_REG 0x0400000 -#define DEV_ID_MD5_1_REG 0x0400004 -#define DEV_ID_MD5_2_REG 0x0400008 -#define DEV_ID_MD5_3_REG 0x040000c -#define DEV_ID_DEVICE_ID_REG 0x0400010 -#define DEV_ID_REVISION_REG 0x0400014 -#define DEV_ID_CPCI_ID_REG 0x0400018 -#define DEV_ID_DEV_STR_0_REG 0x040001c -#define DEV_ID_DEV_STR_1_REG 0x0400020 -#define DEV_ID_DEV_STR_2_REG 0x0400024 -#define DEV_ID_DEV_STR_3_REG 0x0400028 -#define DEV_ID_DEV_STR_4_REG 0x040002c -#define DEV_ID_DEV_STR_5_REG 0x0400030 -#define DEV_ID_DEV_STR_6_REG 0x0400034 -#define DEV_ID_DEV_STR_7_REG 0x0400038 -#define DEV_ID_DEV_STR_8_REG 0x040003c -#define DEV_ID_DEV_STR_9_REG 0x0400040 -#define DEV_ID_DEV_STR_10_REG 0x0400044 -#define DEV_ID_DEV_STR_11_REG 0x0400048 -#define DEV_ID_DEV_STR_12_REG 0x040004c -#define DEV_ID_DEV_STR_13_REG 0x0400050 -#define DEV_ID_DEV_STR_14_REG 0x0400054 -#define DEV_ID_DEV_STR_15_REG 0x0400058 -#define DEV_ID_DEV_STR_16_REG 0x040005c -#define DEV_ID_DEV_STR_17_REG 0x0400060 -#define DEV_ID_DEV_STR_18_REG 0x0400064 -#define DEV_ID_DEV_STR_19_REG 0x0400068 -#define DEV_ID_DEV_STR_20_REG 0x040006c -#define DEV_ID_DEV_STR_21_REG 0x0400070 -#define DEV_ID_DEV_STR_22_REG 0x0400074 -#define DEV_ID_DEV_STR_23_REG 0x0400078 -#define DEV_ID_DEV_STR_24_REG 0x040007c - -// Name: mdio (MDIO) -// Description: MDIO interface -// File: lib/verilog/core/io/mdio/xml/mdio.xml -#define MDIO_PHY_0_CONTROL_REG 0x0440000 -#define MDIO_PHY_0_STATUS_REG 0x0440004 -#define MDIO_PHY_0_PHY_ID_0_REG 0x0440008 -#define MDIO_PHY_0_PHY_ID_1_REG 0x044000c -#define MDIO_PHY_0_AUTONEGOTIATION_ADVERT_REG 0x0440010 -#define MDIO_PHY_0_AUTONEG_LINK_PARTNER_BASE_PAGE_ABILITY_REG 0x0440014 -#define MDIO_PHY_0_AUTONEG_EXPANSION_REG 0x0440018 -#define MDIO_PHY_0_AUTONEG_NEXT_PAGE_TX_REG 0x044001c -#define MDIO_PHY_0_AUTONEG_LINK_PARTNER_RCVD_NEXT_PAGE_REG 0x0440020 -#define MDIO_PHY_0_MASTER_SLAVE_CTRL_REG 0x0440024 -#define MDIO_PHY_0_MASTER_SLAVE_STATUS_REG 0x0440028 -#define MDIO_PHY_0_PSE_CTRL_REG 0x044002c -#define MDIO_PHY_0_PSE_STATUS_REG 0x0440030 -#define MDIO_PHY_0_MMD_ACCESS_CTRL_REG 0x0440034 -#define MDIO_PHY_0_MMD_ACCESS_STATUS_REG 0x0440038 -#define MDIO_PHY_0_EXTENDED_STATUS_REG 0x044003c -#define MDIO_PHY_1_CONTROL_REG 0x0440080 -#define MDIO_PHY_1_STATUS_REG 0x0440084 -#define MDIO_PHY_1_PHY_ID_0_REG 0x0440088 -#define MDIO_PHY_1_PHY_ID_1_REG 0x044008c -#define MDIO_PHY_1_AUTONEGOTIATION_ADVERT_REG 0x0440090 -#define MDIO_PHY_1_AUTONEG_LINK_PARTNER_BASE_PAGE_ABILITY_REG 0x0440094 -#define MDIO_PHY_1_AUTONEG_EXPANSION_REG 0x0440098 -#define MDIO_PHY_1_AUTONEG_NEXT_PAGE_TX_REG 0x044009c -#define MDIO_PHY_1_AUTONEG_LINK_PARTNER_RCVD_NEXT_PAGE_REG 0x04400a0 -#define MDIO_PHY_1_MASTER_SLAVE_CTRL_REG 0x04400a4 -#define MDIO_PHY_1_MASTER_SLAVE_STATUS_REG 0x04400a8 -#define MDIO_PHY_1_PSE_CTRL_REG 0x04400ac -#define MDIO_PHY_1_PSE_STATUS_REG 0x04400b0 -#define MDIO_PHY_1_MMD_ACCESS_CTRL_REG 0x04400b4 -#define MDIO_PHY_1_MMD_ACCESS_STATUS_REG 0x04400b8 -#define MDIO_PHY_1_EXTENDED_STATUS_REG 0x04400bc -#define MDIO_PHY_2_CONTROL_REG 0x0440100 -#define MDIO_PHY_2_STATUS_REG 0x0440104 -#define MDIO_PHY_2_PHY_ID_0_REG 0x0440108 -#define MDIO_PHY_2_PHY_ID_1_REG 0x044010c -#define MDIO_PHY_2_AUTONEGOTIATION_ADVERT_REG 0x0440110 -#define MDIO_PHY_2_AUTONEG_LINK_PARTNER_BASE_PAGE_ABILITY_REG 0x0440114 -#define MDIO_PHY_2_AUTONEG_EXPANSION_REG 0x0440118 -#define MDIO_PHY_2_AUTONEG_NEXT_PAGE_TX_REG 0x044011c -#define MDIO_PHY_2_AUTONEG_LINK_PARTNER_RCVD_NEXT_PAGE_REG 0x0440120 -#define MDIO_PHY_2_MASTER_SLAVE_CTRL_REG 0x0440124 -#define MDIO_PHY_2_MASTER_SLAVE_STATUS_REG 0x0440128 -#define MDIO_PHY_2_PSE_CTRL_REG 0x044012c -#define MDIO_PHY_2_PSE_STATUS_REG 0x0440130 -#define MDIO_PHY_2_MMD_ACCESS_CTRL_REG 0x0440134 -#define MDIO_PHY_2_MMD_ACCESS_STATUS_REG 0x0440138 -#define MDIO_PHY_2_EXTENDED_STATUS_REG 0x044013c -#define MDIO_PHY_3_CONTROL_REG 0x0440180 -#define MDIO_PHY_3_STATUS_REG 0x0440184 -#define MDIO_PHY_3_PHY_ID_0_REG 0x0440188 -#define MDIO_PHY_3_PHY_ID_1_REG 0x044018c -#define MDIO_PHY_3_AUTONEGOTIATION_ADVERT_REG 0x0440190 -#define MDIO_PHY_3_AUTONEG_LINK_PARTNER_BASE_PAGE_ABILITY_REG 0x0440194 -#define MDIO_PHY_3_AUTONEG_EXPANSION_REG 0x0440198 -#define MDIO_PHY_3_AUTONEG_NEXT_PAGE_TX_REG 0x044019c -#define MDIO_PHY_3_AUTONEG_LINK_PARTNER_RCVD_NEXT_PAGE_REG 0x04401a0 -#define MDIO_PHY_3_MASTER_SLAVE_CTRL_REG 0x04401a4 -#define MDIO_PHY_3_MASTER_SLAVE_STATUS_REG 0x04401a8 -#define MDIO_PHY_3_PSE_CTRL_REG 0x04401ac -#define MDIO_PHY_3_PSE_STATUS_REG 0x04401b0 -#define MDIO_PHY_3_MMD_ACCESS_CTRL_REG 0x04401b4 -#define MDIO_PHY_3_MMD_ACCESS_STATUS_REG 0x04401b8 -#define MDIO_PHY_3_EXTENDED_STATUS_REG 0x04401bc - -#define MDIO_PHY_GROUP_BASE_ADDR 0x0440000 -#define MDIO_PHY_GROUP_INST_OFFSET 0x0000080 - -// Name: dma (DMA) -// Description: DMA transfer module -// File: lib/verilog/core/dma/xml/dma.xml - -// Name: nf2_mac_grp (MAC_GRP_0) -// Description: Ethernet MAC group -// File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml -#define MAC_GRP_0_CONTROL_REG 0x0600000 -#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0600004 -#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_STORED_REG 0x0600008 -#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG 0x060000c -#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG 0x0600010 -#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_DEQUEUED_REG 0x0600014 -#define MAC_GRP_0_RX_QUEUE_NUM_WORDS_PUSHED_REG 0x0600018 -#define MAC_GRP_0_RX_QUEUE_NUM_BYTES_PUSHED_REG 0x060001c -#define MAC_GRP_0_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0600020 -#define MAC_GRP_0_TX_QUEUE_NUM_PKTS_ENQUEUED_REG 0x0600024 -#define MAC_GRP_0_TX_QUEUE_NUM_PKTS_SENT_REG 0x0600028 -#define MAC_GRP_0_TX_QUEUE_NUM_WORDS_PUSHED_REG 0x060002c -#define MAC_GRP_0_TX_QUEUE_NUM_BYTES_PUSHED_REG 0x0600030 - -// Name: nf2_mac_grp (MAC_GRP_1) -// Description: Ethernet MAC group -// File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml -#define MAC_GRP_1_CONTROL_REG 0x0640000 -#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0640004 -#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_STORED_REG 0x0640008 -#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG 0x064000c -#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG 0x0640010 -#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_DEQUEUED_REG 0x0640014 -#define MAC_GRP_1_RX_QUEUE_NUM_WORDS_PUSHED_REG 0x0640018 -#define MAC_GRP_1_RX_QUEUE_NUM_BYTES_PUSHED_REG 0x064001c -#define MAC_GRP_1_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0640020 -#define MAC_GRP_1_TX_QUEUE_NUM_PKTS_ENQUEUED_REG 0x0640024 -#define MAC_GRP_1_TX_QUEUE_NUM_PKTS_SENT_REG 0x0640028 -#define MAC_GRP_1_TX_QUEUE_NUM_WORDS_PUSHED_REG 0x064002c -#define MAC_GRP_1_TX_QUEUE_NUM_BYTES_PUSHED_REG 0x0640030 - -// Name: nf2_mac_grp (MAC_GRP_2) -// Description: Ethernet MAC group -// File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml -#define MAC_GRP_2_CONTROL_REG 0x0680000 -#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0680004 -#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_STORED_REG 0x0680008 -#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG 0x068000c -#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG 0x0680010 -#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_DEQUEUED_REG 0x0680014 -#define MAC_GRP_2_RX_QUEUE_NUM_WORDS_PUSHED_REG 0x0680018 -#define MAC_GRP_2_RX_QUEUE_NUM_BYTES_PUSHED_REG 0x068001c -#define MAC_GRP_2_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0680020 -#define MAC_GRP_2_TX_QUEUE_NUM_PKTS_ENQUEUED_REG 0x0680024 -#define MAC_GRP_2_TX_QUEUE_NUM_PKTS_SENT_REG 0x0680028 -#define MAC_GRP_2_TX_QUEUE_NUM_WORDS_PUSHED_REG 0x068002c -#define MAC_GRP_2_TX_QUEUE_NUM_BYTES_PUSHED_REG 0x0680030 - -// Name: nf2_mac_grp (MAC_GRP_3) -// Description: Ethernet MAC group -// File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml -#define MAC_GRP_3_CONTROL_REG 0x06c0000 -#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x06c0004 -#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_STORED_REG 0x06c0008 -#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG 0x06c000c -#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG 0x06c0010 -#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_DEQUEUED_REG 0x06c0014 -#define MAC_GRP_3_RX_QUEUE_NUM_WORDS_PUSHED_REG 0x06c0018 -#define MAC_GRP_3_RX_QUEUE_NUM_BYTES_PUSHED_REG 0x06c001c -#define MAC_GRP_3_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x06c0020 -#define MAC_GRP_3_TX_QUEUE_NUM_PKTS_ENQUEUED_REG 0x06c0024 -#define MAC_GRP_3_TX_QUEUE_NUM_PKTS_SENT_REG 0x06c0028 -#define MAC_GRP_3_TX_QUEUE_NUM_WORDS_PUSHED_REG 0x06c002c -#define MAC_GRP_3_TX_QUEUE_NUM_BYTES_PUSHED_REG 0x06c0030 - -// Name: cpu_dma_queue (CPU_QUEUE_0) -// Description: CPU DMA queue -// File: lib/verilog/core/io_queues/cpu_dma_queue/xml/cpu_dma_queue.xml - -// Name: cpu_dma_queue (CPU_QUEUE_1) -// Description: CPU DMA queue -// File: lib/verilog/core/io_queues/cpu_dma_queue/xml/cpu_dma_queue.xml - -// Name: cpu_dma_queue (CPU_QUEUE_2) -// Description: CPU DMA queue -// File: lib/verilog/core/io_queues/cpu_dma_queue/xml/cpu_dma_queue.xml - -// Name: cpu_dma_queue (CPU_QUEUE_3) -// Description: CPU DMA queue -// File: lib/verilog/core/io_queues/cpu_dma_queue/xml/cpu_dma_queue.xml - -// Name: SRAM (SRAM) -// Description: SRAM - -// Name: openflow_output_port_lookup (OPENFLOW_LOOKUP) -// Description: Output Port Lookup for OpenFlow hardware datapath -// File: projects/openflow_switch/include/output_port_lookup.xml -#define OPENFLOW_LOOKUP_WILDCARD_MISSES_REG 0x2000000 -#define OPENFLOW_LOOKUP_WILDCARD_HITS_REG 0x2000004 -#define OPENFLOW_LOOKUP_EXACT_MISSES_REG 0x2000008 -#define OPENFLOW_LOOKUP_EXACT_HITS_REG 0x200000c -#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_0_REG 0x2000010 -#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_1_REG 0x2000014 -#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_2_REG 0x2000018 -#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_3_REG 0x200001c -#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_4_REG 0x2000020 -#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_5_REG 0x2000024 -#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_6_REG 0x2000028 -#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_7_REG 0x200002c -#define OPENFLOW_LOOKUP_DUMY_SOFTWARE_0_REG 0x2000030 -#define OPENFLOW_LOOKUP_DUMY_SOFTWARE_1_REG 0x2000034 -#define OPENFLOW_LOOKUP_TIMER_REG 0x2000038 - -// Name: in_arb (IN_ARB) -// Description: Round-robin input arbiter -// File: lib/verilog/core/input_arbiter/rr_input_arbiter/xml/rr_input_arbiter.xml -#define IN_ARB_NUM_PKTS_SENT_REG 0x2000100 -#define IN_ARB_LAST_PKT_WORD_0_HI_REG 0x2000104 -#define IN_ARB_LAST_PKT_WORD_0_LO_REG 0x2000108 -#define IN_ARB_LAST_PKT_CTRL_0_REG 0x200010c -#define IN_ARB_LAST_PKT_WORD_1_HI_REG 0x2000110 -#define IN_ARB_LAST_PKT_WORD_1_LO_REG 0x2000114 -#define IN_ARB_LAST_PKT_CTRL_1_REG 0x2000118 -#define IN_ARB_STATE_REG 0x200011c - -// Name: vlan_remover (VLAN_REMOVER) -// Description: Remove vlan tag and ethtype if ethtype is vlan, and store them into module header -// File: projects/openflow_switch/include/vlan_remover.xml - -// Name: opl_processor (OPL_PROCESSOR) -// Description: opl_processor -// File: projects/openflow_switch/include/opl_processor.xml - -// Name: header_parser (HEADER_PARSER) -// Description: Chop ether/IP/UDP-TCP header into 11 tuples -// File: projects/openflow_switch/include/header_parser.xml - -// Name: match_arbiter (MATCH_ARBITER) -// Description: Arbitration between exact and wildcard lookups results -// File: projects/openflow_switch/include/match_arbiter.xml - -// Name: bram_output_queues (BRAM_OQ) -// Description: BRAM-based output queues -// File: lib/verilog/core/output_queues/bram_output_queues/xml/bram_output_queues.xml -#define BRAM_OQ_DISABLE_QUEUES_REG 0x2000300 -#define BRAM_OQ_QUEUE_0_NUM_PKT_BYTES_RECEIVED_REG 0x2000380 -#define BRAM_OQ_QUEUE_0_NUM_PKTS_RECEIVED_REG 0x2000384 -#define BRAM_OQ_QUEUE_0_NUM_PKTS_DROPPED_REG 0x2000388 -#define BRAM_OQ_QUEUE_0_NUM_WORDS_IN_QUEUE_REG 0x200038c -#define BRAM_OQ_QUEUE_1_NUM_PKT_BYTES_RECEIVED_REG 0x2000390 -#define BRAM_OQ_QUEUE_1_NUM_PKTS_RECEIVED_REG 0x2000394 -#define BRAM_OQ_QUEUE_1_NUM_PKTS_DROPPED_REG 0x2000398 -#define BRAM_OQ_QUEUE_1_NUM_WORDS_IN_QUEUE_REG 0x200039c -#define BRAM_OQ_QUEUE_2_NUM_PKT_BYTES_RECEIVED_REG 0x20003a0 -#define BRAM_OQ_QUEUE_2_NUM_PKTS_RECEIVED_REG 0x20003a4 -#define BRAM_OQ_QUEUE_2_NUM_PKTS_DROPPED_REG 0x20003a8 -#define BRAM_OQ_QUEUE_2_NUM_WORDS_IN_QUEUE_REG 0x20003ac -#define BRAM_OQ_QUEUE_3_NUM_PKT_BYTES_RECEIVED_REG 0x20003b0 -#define BRAM_OQ_QUEUE_3_NUM_PKTS_RECEIVED_REG 0x20003b4 -#define BRAM_OQ_QUEUE_3_NUM_PKTS_DROPPED_REG 0x20003b8 -#define BRAM_OQ_QUEUE_3_NUM_WORDS_IN_QUEUE_REG 0x20003bc -#define BRAM_OQ_QUEUE_4_NUM_PKT_BYTES_RECEIVED_REG 0x20003c0 -#define BRAM_OQ_QUEUE_4_NUM_PKTS_RECEIVED_REG 0x20003c4 -#define BRAM_OQ_QUEUE_4_NUM_PKTS_DROPPED_REG 0x20003c8 -#define BRAM_OQ_QUEUE_4_NUM_WORDS_IN_QUEUE_REG 0x20003cc -#define BRAM_OQ_QUEUE_5_NUM_PKT_BYTES_RECEIVED_REG 0x20003d0 -#define BRAM_OQ_QUEUE_5_NUM_PKTS_RECEIVED_REG 0x20003d4 -#define BRAM_OQ_QUEUE_5_NUM_PKTS_DROPPED_REG 0x20003d8 -#define BRAM_OQ_QUEUE_5_NUM_WORDS_IN_QUEUE_REG 0x20003dc -#define BRAM_OQ_QUEUE_6_NUM_PKT_BYTES_RECEIVED_REG 0x20003e0 -#define BRAM_OQ_QUEUE_6_NUM_PKTS_RECEIVED_REG 0x20003e4 -#define BRAM_OQ_QUEUE_6_NUM_PKTS_DROPPED_REG 0x20003e8 -#define BRAM_OQ_QUEUE_6_NUM_WORDS_IN_QUEUE_REG 0x20003ec -#define BRAM_OQ_QUEUE_7_NUM_PKT_BYTES_RECEIVED_REG 0x20003f0 -#define BRAM_OQ_QUEUE_7_NUM_PKTS_RECEIVED_REG 0x20003f4 -#define BRAM_OQ_QUEUE_7_NUM_PKTS_DROPPED_REG 0x20003f8 -#define BRAM_OQ_QUEUE_7_NUM_WORDS_IN_QUEUE_REG 0x20003fc - -#define BRAM_OQ_QUEUE_GROUP_BASE_ADDR 0x2000380 -#define BRAM_OQ_QUEUE_GROUP_INST_OFFSET 0x0000010 - -// Name: watchdog (WDT) -// Description: Watchdog timer -// File: projects/openflow_switch/include/watchdog.xml -#define WDT_ENABLE_FLG_REG 0x2000400 -#define WDT_COUNTER_REG 0x2000404 - -// Name: exact_match (EXACT_MATCH) -// Description: exact match lookup -// File: projects/openflow_switch/include/exact_match.xml - -// Name: wildcard_match (OPENFLOW_WILDCARD_LOOKUP) -// Description: wildcard match lookup -// File: projects/openflow_switch/include/wildcard_match.xml -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_0_REG 0x2001000 -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_1_REG 0x2001004 -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_2_REG 0x2001008 -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_3_REG 0x200100c -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_4_REG 0x2001010 -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_5_REG 0x2001014 -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_6_REG 0x2001018 -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_7_REG 0x200101c -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_8_REG 0x2001020 -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_9_REG 0x2001024 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_0_REG 0x2001028 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_1_REG 0x200102c -#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_2_REG 0x2001030 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_3_REG 0x2001034 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_4_REG 0x2001038 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_5_REG 0x200103c -#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_6_REG 0x2001040 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_7_REG 0x2001044 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_0_REG 0x2001048 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_1_REG 0x200104c -#define OPENFLOW_WILDCARD_LOOKUP_CMP_2_REG 0x2001050 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_3_REG 0x2001054 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_4_REG 0x2001058 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_5_REG 0x200105c -#define OPENFLOW_WILDCARD_LOOKUP_CMP_6_REG 0x2001060 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_7_REG 0x2001064 -#define OPENFLOW_WILDCARD_LOOKUP_READ_ADDR_REG 0x2001068 -#define OPENFLOW_WILDCARD_LOOKUP_WRITE_ADDR_REG 0x200106c -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG 0x2001070 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_1_REG 0x2001074 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_2_REG 0x2001078 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_3_REG 0x200107c -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_4_REG 0x2001080 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_5_REG 0x2001084 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_6_REG 0x2001088 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_7_REG 0x200108c -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_8_REG 0x2001090 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_9_REG 0x2001094 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_10_REG 0x2001098 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_11_REG 0x200109c -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_12_REG 0x20010a0 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_13_REG 0x20010a4 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_14_REG 0x20010a8 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_15_REG 0x20010ac -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_16_REG 0x20010b0 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_17_REG 0x20010b4 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_18_REG 0x20010b8 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_19_REG 0x20010bc -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_20_REG 0x20010c0 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_21_REG 0x20010c4 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_22_REG 0x20010c8 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_23_REG 0x20010cc -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_24_REG 0x20010d0 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_25_REG 0x20010d4 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_26_REG 0x20010d8 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_27_REG 0x20010dc -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_28_REG 0x20010e0 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_29_REG 0x20010e4 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_30_REG 0x20010e8 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_31_REG 0x20010ec -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG 0x20010f0 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_1_REG 0x20010f4 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_2_REG 0x20010f8 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_3_REG 0x20010fc -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_4_REG 0x2001100 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_5_REG 0x2001104 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_6_REG 0x2001108 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_7_REG 0x200110c -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_8_REG 0x2001110 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_9_REG 0x2001114 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_10_REG 0x2001118 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_11_REG 0x200111c -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_12_REG 0x2001120 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_13_REG 0x2001124 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_14_REG 0x2001128 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_15_REG 0x200112c -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_16_REG 0x2001130 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_17_REG 0x2001134 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_18_REG 0x2001138 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_19_REG 0x200113c -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_20_REG 0x2001140 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_21_REG 0x2001144 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_22_REG 0x2001148 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_23_REG 0x200114c -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_24_REG 0x2001150 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_25_REG 0x2001154 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_26_REG 0x2001158 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_27_REG 0x200115c -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_28_REG 0x2001160 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_29_REG 0x2001164 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_30_REG 0x2001168 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_31_REG 0x200116c -#define OPENFLOW_WILDCARD_LOOKUP_DUMMY_1_REG 0x2001170 -#define OPENFLOW_WILDCARD_LOOKUP_DUMMY_2_REG 0x2001174 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_0_REG 0x2001178 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_1_REG 0x200117c -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_2_REG 0x2001180 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_3_REG 0x2001184 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_4_REG 0x2001188 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_5_REG 0x200118c -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_6_REG 0x2001190 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_7_REG 0x2001194 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_8_REG 0x2001198 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_9_REG 0x200119c -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_10_REG 0x20011a0 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_11_REG 0x20011a4 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_12_REG 0x20011a8 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_13_REG 0x20011ac -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_14_REG 0x20011b0 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_15_REG 0x20011b4 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_16_REG 0x20011b8 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_17_REG 0x20011bc -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_18_REG 0x20011c0 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_19_REG 0x20011c4 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_20_REG 0x20011c8 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_21_REG 0x20011cc -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_22_REG 0x20011d0 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_23_REG 0x20011d4 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_24_REG 0x20011d8 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_25_REG 0x20011dc -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_26_REG 0x20011e0 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_27_REG 0x20011e4 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_28_REG 0x20011e8 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_29_REG 0x20011ec -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_30_REG 0x20011f0 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_31_REG 0x20011f4 - -// Name: DRAM (DRAM) -// Description: DRAM - -#endif diff --git a/openflow/datapath/hwtable_nf2/openflow_switch.bit b/openflow/datapath/hwtable_nf2/openflow_switch.bit deleted file mode 100644 index 3d9c2a02601d2f5e12a6193d80a8bb32d474a7c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2377746 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
+I`scXbnae`!KJ-bQ5`)T*Fh^p81rUWyHrL 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 %|t=Z|^S1cZ-aOS3;oaSM-1 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

bJwM?HXj_Ok@!8w|et02u9fd^@>xqoU6cg+|%! z?Kj>aD2%BK_P|dT>eCXK6{AH55B}P2d?+~`!^)t&drsb!zdpCy)Egg4?j>PB!@mD| z;`jKrefrAdkK;QIXJ^0ryEwRecLnEj-+%p$dF}8%e0P24tq*+&FKwNFTl?x|e6wBt zDkl|JsQzTmH*B>mdnWQq>h`~~FFy9c7i%wm{-Z^Zz4-YLzDV%VA|Tmb9}le4qrimx1f$q!p$@s}_E_TlWxA7aVdhTuHT`xq#w z^ZT!#*B;cd#0-})ov3TYPw1pvG(mOp8RqxWxNzE5VEAzR?stEI=;6b^%{asl+xcw< z;~M~+m7h@uayk>}qEU#kGbf~pfgrhgBg^H>bmJFa!Wr8aU&2A?@Bf?U9|I%$fBZWV z{$m5|Uw(nE{qt2O)<69k-F@Zxy}gz1ja&y0+1h4hmmW5GBJ<>Crh9Yl;n;95*Y!MN zGjMPHtOo4E7JClet?M~d6#YrQ^@-)IBt>;)jw#@FKp!V9@~JfGW(tZ2sM<2b2FSU`jR`|>w;r>;&pT9O?Bl>Ih?>F$dc3hiP>_(@$18lG_txiWH%4;dg z6k(QFMU5hy@>)PdliW{0O1F?>GC;ZtQgadob0E8-GYwJ#l@u(^!owRv{%W}!)jcxq z;510`X>fdLG)moOXdtG`Z*Ij1#~H3Z;+S6KL9Ss=jGVM-4JPtw?_QDRA8O@40(e;2 zL@aYdlq^;6?!mCixXlkhSO228({rg_$ zOrm|_e?K<*rwOZGIyNe}Y`kPflSGqCpL(mHHO~HA>9y>$U;R|}q=%n%r;lwdH>tri z;?EWS&?@fqC4af8wcRxN)R9yce{DTHfGMr|y|YYlrsP@WH}o7&Fj;vc2yM2MXGARYs#%c2e!h zrnic1F1*97{ASP3_HSt7OW*Wo^c7*19)DV$L0ZA5#YPrfUnQCfLdS0C{yGb_|H0E0Wq*n>v;#~-@t(3pJ z^-VrbQY>HTm0a4lE=qXpsE{BF3#>!lL}T7vHe2F|o3p)Ar`4KyIC`oy^``=#sc5Ql zj|r3anRBs8TpyS-?`Xj0xasBk+!Z%y>4|?Yc zk8B%fKVAA}`?Ejjot}9|F83$Baf$uGp29c$P2-S~n%&}j0?^vkmXbZ$HKseB3ei4Z z#Uh`ko=(}5l$lV7REsGTe$zN@mPYcb#;O|Ef_9}m+kR@TulclWL9=1m7BuW_TGS!> z4mZ^R?x{&5)hn;^S!hxAwWl^qE@#iyY@*r9N-1AjbtXyDtjD_!sWx>`Q(z;rsH4)f z_)=3aw4+E>D@&LylwY=JK?|xNrR6O>I7_K|^q%VIs7Fg~VF6U~6NPOhei|GkbFtUR zCV7L01kgGglHF5q>B&tJF?;4x5{%b66q6A_<7LGZDspBAON5;O_DPB)y{Wgfgvz&H zm*|wDwHGw_HLTI1+FoAPAtCQEwI@vJ?@ML%_vDMRFKj5Lu#<(m@C6NQBHn9q?>J=@ zGG3ySF^HAkl#5R&LBb#(D>z3q`d*lnwUK*V)a#ylqBBvc&?`{`mKiBU3eo^+cJJCusJG?t{iH7}MB}rVwOhV|6J%HC98Zpey zG|(>`!!O=*8eoi>;{j6k~u>-yK=T z`xbVSNX{*&ha<(=?<863JfSke-crdr!sTUgkwH&t>L-0*O9A~DjC=u;;^`I-;`)M#`UQ|1%lR@7FaELwoX z-b>Sl$Q#gL3X!)}^r>GI?-HR55K^$EzXhb>u3s%8l8b~ul1l3pS6V<+@_XQ_s#AV? zpDneg{fK6GPsPK_ACqCtM>%Kjr$kkz`otcCCrveHxP#$+f34ILL)i)DY7$E7it(b< z76Dk$Zj7x6l6x`aS<-6p2Q(8Ch$@K?J1}OIHI|oS304!0ZE=kZ-x|ijWGZ9y%$wAf zw^03TOJ8Jwp*Odhb(5v(Us;(M=Eb+8pm`r=O7nC~GB6|IcG^O_3@xVq^cCVfsW3H! z&G9pFX&nOxf(E-#3A^}pFbvMeYBm`?t5qs^hRD=(R^1uda<4^Prk(8C29@tZdO44! zL7_CmIGVN0^kKfk-t_ETo*Lz&rcR?K9>@oEgsO^rI0?JSv*bQ6gNsBy%6pjaiV`Ld z%Ngwp7^(z{7#U&cPO<|b5eTXRO(8oI2t9uaCz;kagKE=LKDP5SU23CxXCuslckUlGaH*n6oWM=7l6t&N zhZ3*Ka#z(B+sCGO6&z8~X|C^1*ugsQ$ifHFgH}XSea5ZWD>B&d_Vy6k1B-l?@3yj$ z0NO$HTQ`O$0;SHVd<(c?fn0Mn{}D1QuzJ=bD}94sc?3suT23#lL+G2&Z`pO z%3SZmfi<6-POFt|y1SUDv&e!>ohCbTyKMF@T(-IkKnAAz=JM{cbqr>%1cRYKI_5375n*pd36H{rc^e{{Jo_0x~t=q|MA zPv#0LTsEea)`TiM2730i8C2DKPrMPGYhSf)7Pr=-k52l*D*iW6h#Nf9LP@TP5*?Eh z>K_qEca?34mw~E|eoWhBhAMhxH%rhLBQeBcRZBVO{9lQIqU6?qyd1uHjV!>#;QcDY zCTNDJI*Gjd-wM+XSty52#c~gjxi(L|3)%nZdp+^$?efrtHE=4>5Q4HR`naZq?wLZvb`GVxK`O7Re5R*gnoF#;KJ z{jU&dUgScEr;jMEi}dQS#q~&WC z){?QvJQ`cIxo?i(Rpa9d6R0ON?WK0RX@u8fbYyxw}v9l0yYf&Y)Qw-1u*I1W6sYHEgWTC>LM;gB(;>2P(U0XG@k z*aktbs4(MH-E2TZn&%x*#4Xpc4mKzVf*kttdPCX>osQLwCawu#S4{|FfDZrBgg^y} z^##`-5$8BXNDY9;1GUgftGJE3KTLhl3dhsEcpHceqV(lP*INl|HS}2wAKBY8*LSoIb5oYtz}G6>`W+YU zH=%uTPVVS4Xq~mZH{Cd0HFvzHyO8li@qAV>a?6;*3_7uW&v<2gAYbt}0t?=g~}4)XB_LNz6uY={L7FzN zE{&G%MDuaysVDeMq}R)BXGL1OU4Q?34rl)MGcK#$`y^eu@nLE3(eD_|rWaoD9d<~O z`w{PZa!5jC^{jd<1T1GX4+q9N&t9N^kF1lf9K&f-ZiCe1emNQB-Z*7Xsue|PCN#b* zRKGKEu6Gog0^asy zF8Muc$BxPVn~t5@)mgTEdEpS5|G&UoCbqMgVGfLO779X#W8bynH2Q8RdkgA2h1j74 z^ySDujVe$qbqzEiErmqV95Gcr4YX1~4u$>{GEXwyJuTIWwx>PS&3GXcKELr|bxICW z)x`?3^$ZT6qrrj(UW35Ig(lnJh1k!g%ot29)75Asgx2)(Nk=c(8K>|?{@M)H1Wfz@ z60lW5qlR9CNZ3Mj2zKwqj^1i3bg3hpKGdx18CeXd3E85Ev{gQmnS0{gTAr--1glPu zFX))Jk=+4g3)F2PPE0`Gzt9#GNa`9ED*W|2Z~Z0Na_C|ZamogL4iz;-5F zo-VMBj>5vgKL>BEKGONF;r!)T>Ke7i>3#zx;UlLm8NiS~KEEVgv8^r=w6@AhGN}v{ z8RT^|+yumBqd=8s&`|_?Xr{pArxpQ?#&dyc&2(y~lB^ZtGI1?80Y2grx)p~UHL0dS zf|!NE$SYAUb8iEfj{Xoui|@pUkheA9)vc-SdX$j*OiUId_S1pPw1@II{;seg7MW|x z-Gvn})}TS%9Y!ORYSCr zuFd4{?$&Oy)NiFiNb|**rpQG|)Rq})NgV;Xx>Ox~+*9wYB~882VE*L0oYbEXsD|R^ zLxW9?wV>1^TKKz@%S#?xL|7cA6bV&%;qr9Z%-to83!K;#hDupfU9~oE7$o46SSFN+ zPSgUm@UvTt2=??2EpE!Pt~FU0dv?1^j0f*LYzwVhWY1mM?k+rYo}(tTSe1qSK1h$X zIJ%Sh$yR7Ne{yBqyI-m&X&=m0*s>^@(WFSkHhdE--iC}*GCyV=$QTgpnYwBs_E7g^ zgEcma`cVfzJTSC85Dm;-u{WlRq5Koani8bX5bD+HPVUX}8yR@RA$tv6WYKaMU|~q( zIfl8eJhx`a`Gz=-DtOZ@+&j0wL-*s)duP{L9V5r`hR`fsABF$A6NwR2h=tbS=pCx_ z6RiAkoT44T%MxEVQ&a*=Qw_nq;U13M$5LO>z%zYm`{qmIxYaN!F7DUny_3IyHMFr^ zJ%3_%$I)O!Zg1Ipn&Z(@&2s7{^pc20*q?YZY=K8+p#<2Pe(&s5za|`PPIihk^U?06 z$3D{L!|42`8|fZK9FpdAlPc`$$*GOC+1ZGyPHzueT+@Pq*D4Z%hAJ8GcAz1Di8i~s zs8R{Gfm`x=8Yd3@YD)JSPyvyiBJTurEUOw5@P9kBIAv_9NQEtB(JT=YcO*$$umDqD z5rtU_NVl+?bVh2zFU}}a)i8+)Y5z>~hdZaF!e{mD!WVVtl14h01T*o0nAS1a<}|JS zDb+Ssqb_BEn|26b2`F6ap?NjW3>5b%!YIql2oko{e2#|S2FWB|g|T8378-Z6 zxPotwWsaw7I?Grc11dis!b6UG3jskZ7ZYBDpe#FyQ>l@hC`yo8rtFyRn8tfSIr=Gk z1dF15l6f-Oq^)$#jP6l<=h~_!`W6X=TqtNYJ-aC(N_M+iNjEuZZJZ@RD?}?})IjTW z4J0K<3?&2cm>4|a3*IGM>`{#ZnmzcW5uu)A1Z@nA#pu&Y5e)bP;;gK)h=RHm`Xq(N zZG201tlbfAOCW864V&mYA*rseMRI$S1#zrAE3z|b?oh0Ry@`7k+jixM#=z#ckraIg zt>45&^cst%;@`yMQ(RMG!Zw2-VG}R6qgb~fdA+D#fkKh(azj~WQ8z-%LIhaT;%;77 z0ZdY4U@P|~@F`xThSF|P6-&)k9E3B8!Zu_i+aL*|^--id9i+{z=8jgP4^!>wI}0As z1KxB{r5${00VJc>0qEhuQIYxo&; zCbOtQqT*A4)mPD3A_NsxMolLfojO7e8l+OaBAf80WfywNy`|55vKdB7y--yp=?*pl#CDgXbRPp=`Ym3ozkvd7BKW0f_s)Qd1Iv z&NjN-r|eRpbh?QIqs}RP=uRlnY8v||9@A(}#<*!HA}1i@(Tgi%lyl^Iq=&ZkD6Vw71P&g$h*99ttp2PkYaeRFtmjJiHmRALYhp zO@h(yYwkke zeul~gsuF?^r`R#Cx%GL5&S5L-;vY-Bp^G9k+c2mD;V*i%E2_87;(o`{9WsX2Tw>+tfg51KxzDq0_GDrXN{c?YT2Y1)B9}AWDAagf z6+&d>zS(l|B3(JmAb=%ypFlj>dYHq6pn@4)?aU`Xho8d^MAHo?5)|`ZLoG>L0a7JJHQ+X-CzCQ7lqK@F1)-`_wO7J&e)xzC zqoT%V!7F0(=43K_A~mk}ZnW$J#Z64z$$jGborzl*h~8?QwaqZ^henRB@ycqnZXs4q z+&qppQeN+9Ez+;!Wb$|~O0O&D9$J6yvFd#_?;fo3T!@`iQ&8i%7}ki^!)~ ztetY}!vz`0=wP?)gBvi&Pxw9U2b|;gnMZ1&@i04kqHmfE+T|0{T=X}t*X5Dp_9+|uAU^Ovbl0Cc+jmb= z!LB?c_q9i{D`9=nKGi>O^50wty-v2v-FG1BIm)_wW_95Pw|3~W#C`;VaBiWxSu+^pU_%tEDl(`v20l2t10tkJyjiP2i-@6AqIYTMA8<%Qna z;qbUW(-_)Y=}qS%zt8<8rdpS;uaCvAduA=iq|{hhYtXy8^i`hIX*HebTbW#hM;oc$ zs84Td5-ig=-i_H5G$JjFO$uOO1VLg572)v_;PnL$k(yXSox!_37hp(i-p@T+GRaVME{AQoL;cH;7_D?9@kY}=InfZwHe5< zZYGEV$N^_iRK;(>O#Lm2V%}+S0mSN=k0(MA0E3?DUthyOR7_+f=4^R;5EF;7^~6YN zWkH&wsC2%}_{frbU+ze+EVT=nRpT`I&ouuUcy;%-P{j$>c0Je zt$B__Gb+984ulixcM)~?HSngZ8xfx8Hg0Ev8g#O(sjL35;cPVZPR!zf{^oBJ8_=~O zo>>SZcOuF!-Gd2?(cTOGRk)IJLI7cmwzS65W!#d(D1ec;Mgv-Nr^kfafn!i2fs?6n zU`hTge^c=TkTokE3B);(YIEU81(+vSq9P#?*0TpGPP`}XBv`taCa45(C~-aUdFsJ~ z4-!(w2v=B-yzu2i7Gf?F#QF$V=EIt!mvA#l2M)vZXn8_MOBqe*qka?xI&r#!mDlYT z?fr;XQjI^d2dzjn#(;`-tC%$E62hiSBJ&bV+-NAMdpDlBBi^>Ukcuby16R zd*mg^qF#~|qkL&k%^Pkh5yR)K+p0NdPV7b>vw`(WS{w(*Nt~h$jEGt#FPkbxHDy-u zIxAWA0nHqZUE+v}qc79)@qyg-y-t*S%sdm)q?W(Gj_1DW4Q3LV)!TV3Ubw`vm>(0V zxAHy$ata(td?53epC;D*BHs$EvSVWk#Jl2hb<&!s{dOWIOgwij4~}%K3CqCUE`NGt zeU>dXC&AP9Ze{%dB1euQCv*!MNGIAWkq18R`e5Y&42L0)-J&z-Eqi!?5E-e}A@AnI zW7+E7<$R^;c@bo#wTE4U;IeH`wJQF4+~-EuXXiE?-LhV7<*j^I#t*UHQlnDU`szw{ zACKTxTZ85eeN&yQ@=8f<{pq`^cd31Ez}JRZy**pSlK_6}>}cfgV(ZSl%Q4P+#q`@! zts3;c@9F-@zL__x5B+NHR&!f@;OQ)Hw=vS-hCJu@T&sIfp_;9(?&HRx^)*_S7gK3G zGlwI$R`u9{V{+bPj}3=;|At{s!SzbCxOZ-ulmS>Lr!ypQQTDNy4-IKYY%VRRcn=Qd~`OiFyedFtCcUG(N+iMomgQev>m%HiN7bFjF$+p=2!_t9h}=jw&5_!E<1b=lk#1Y#S_TgkHH}#4>1Ha$wCtn+l0!^bI%`SRMW;^jq##3Ks)JoTq2|fu zF4S*g`WVb+xsepDag@F?N$i@y-gcaDiT7)Droo3L9*Rtn5sSh#c{^lDE$Rlu6owSO zQxNQCN>og19uuaqYaym+5h^-sPsO7K+rSh!vqVB#<&`z1wZ%0nJ3?YI!>^|r*?6L} zBv1ugG_eN_{1M+|h#FVeq?DG?;Z@S&W@_R=T_hDIt=T;%HcE1}d?0!(X(Ml*Wu zcAPF^r1}{r1ht0}ik22zEz%56=dWpuoRvSMv}6n&GEvy+%3P6wP^D=Y3HVcqIrq~+ zDMY9>)LB7bTQE}8$Do%~D@D|deK2Sy)E+gRg~920gd+P)%LjX$CAi7%f267$xOQ~ixnw4^#%p@7BH&%Kq?PgZG%wY#afS) zSh8xHm*7o-_!)s~NO%fkk)u>G?VIU$+T{yX2)&l{uZOyGJnToU(D|%!|=VQcqCoOQ1j?s{wR9w+ho4%>Epb9aYkmA)U zQHjxStEdtZRJ6|msb?z^3QdeRwN&+T&BvpSn!;;O){&s#f`-icK?-uLdY?&M7C8Tyaf#jt`UdG4{l_&8WCw(bbXy(S&$G@ zhux3FPP8Rr;2v#4dC89Tx^zk99+c`?9UWHM!NjPkT~7X9U{^tU4GB>kL<-b<7_GB< z9V^x*>s(L`1ZsdmJa3J6*+bb7J7_gl3T2ZLJ-=BgLl2*iZR2@|XN(-uVq3fRl;bjU zzxXK%#=6?YYBB;eK$YT;l2cTy=c?K&hfmjn*Oa&vZC%8oUIJlEn8w}$zM#Z(DI*CF zDSVrt=pbntAQiSkpTxPPM!DNiE`NX=3|A$tKXT1DX9g4Bu1s7ls9EE2dN zs>DKy7bHzl2>iJjT?q*SVJHG5ja4b-G2BElj}j?iEkqR#giVzL1(wCbteD(*E^%l* z6tsFFm8w{(YGO-CiK7S#^O@~+D-x8uovM}Mg$BqC%=! zlsD8gS4a{F6LeD;bc);#TUjT_>z1|O#^FrmLJ^&@a^BCt6T0l4lFv>`gv*Rek&wvx zm?-I^t5`}_9jYm@4ANdUpKxDHCOZiQTS}Z6gA}jx1q@E*sdRfzuL|VIJYh(&w+XVI z5<~j0m_q7?)~n7z<0(*Nh82X6bWZfm8@UieguU|A|Ww;P1T$g=V`E^U9PPh__;dg#CTcT+$ zd|4Hsv{<@5!yDOl-)Fe(O3^=Qs;@1|i)f%OurLGClK-t)kZ39@5-7`NzzO#lMYaW6 zk1|Tl^ejw+!CaJ(0`iv5)3l&+AS=t%L{>KfEv>A+;%@>qR|yzLYmPh=Cx@!5QH1tY zD`;m_6t&~!e0rYx_##lxV+E#BF&e<9QmMIG*S^bK{it1-|C^8En*l5Z3-f<;tMY7z zBG)#GnvQ79W5U!{+A^Es!BgGFi-A5CghyoIea6arH z(GDq5G0eHm&Z!_Ir-BN}NJ*`rx@@ZPW(;Xs8rf8+3Qt0*k>*tmSXB$Gh-%?r1+!-O z8Gt{XqqN8rIgI$B)owzEY8Qwf4#t7;x%?n=%aw zuVou@UVUg?*=z9}HJ@#K^?l#49eMJ@*`J-nbIz5$IL+B{)%{)eH{ZmE&c? zUa-%7j$op+W#LcR>f$@6^%~KGM1ek%BX!hyQVfXEWE~8L2wAvBQ4v zUreT%{Oa{8ik-*b;TkQudBbU&&WliqzMU0+eARBWNW$CF2F(Lsgqb3r^*A=VZijtC zlHVy@dHv8QXGbX&zizL+rp9>&e_r4F7T&(Ty^JHbFa806x*Ea}5%M-Ro_WTeKlscu zU{4*yW!L9FZ=ZYa3tzA=y_ABdFc@yU)SN zsYf40l%AWY`zDJmHTCZ*AOBnZtc!X)qBea;&r(|n_?Y^&N@e}eHXh}**kAdT><1Hd zW~V;pezH{ka`xj9J>qZbxQ+VZca!OoJE-5q-QLCszP-Fpu2x zmE;5pr%m|T+SqGfei@f;=%d(Qzbtq%+pv#r#0_?@kK*g;xm4+Y@*`^W%fD>@>aR*0 zT+><`Z`h4j>2S~d$#>L28^QC>|JvTlm48RDu~!545Af2qvGHhfAV$g?@BN8+z4Ep5@BQ!Wb)P%*bTFg8QlNE?st*n!_VM%wxF1Uh6GbKlvpe-p-HQ1rLkWgyB7aKB! zilFq|SP?rvSLg6$XQhH~G46jJmOuS0+32-TeOMk=4TAjH?{>SER@2d(f>Oz!W<@d% z+8b}ks~ZfrAAa|%U&S}u^?RAe_8zR9ze+>@snAznyZr7?*^Tqu>%3O^JNo4mZ(slZ zmG^u;`*w{<>Iz;J<$Hf}_uV+$V^EBqJ;1b4m?T+u%R&!7Y~TCdEv@jI_l<8P?NE2` z2Ggnb?%t1n^r=tThaV1sdVF=me))g9s%By)(`wBmCv0Qm14`Q(X>W%m4{yDVjbHku z>~o{}uiH1i{_c6J9@!9I`89h(n4hmqr?|SCPP_k=Eg?ET^Gp)Y0NvOaU8%hCN@`Um zhWn#ojBNY|M&H+y>q2_`%P)V9zV`M1#{B-T!HoG1ZMjjs0d*h65$3_gMVX8@{+s>Y z#%s@KfA?EhrZmo$A+}oUceTi?+9TfcD%f{m-uw5NnIYprk@na)h)}f}9WDU_@9KYH z2!8#Fj=sG~7o59YVdz(W^rNnNOJwQUz`Lb=?n_6GaHX|gdXXZZ{P4S3wkAO*?3Z6A zFE!dYIQ}?=qrt1MmIeG=7v_;jx8%u}t;mNCAN%BENB+mTBf}#fu^)3szIzkDF2z2I zxAysccb+@3){c13A}to>31BJ(DaBoDUKYCAFR;jNyCiYZ8?EAID~HN|m~t(jOFD;3 z>pn4+2P7FKUQo)gUtD9!$(1baT!}E*I5X7F2w`5 zBD3LFr9gSvi@aJf#Wmb49xQ6~tq_%z0!7%jaB6C#zlglPjH4J%>8gn0Xa6)!gEKsW zD)MMe$58pPD9)CiSdHn!;%bZ(UTrILp&>|Vf^_6j7*vzXqeo4C6Ob|Jk!6w)^^PyK z7MC$*B%zR;_Yo7T;lT&qy!}kh-IABKThzl_in1FGF%^W2^c+K-^G8La zA}m_V8AgO%92TH_9%J%J?TODvb6J^yz6NS5h4gqXX~+j5i7xUK+q*>`<*~zjJl?d* z>qR#)t1A@ND5_IX%22=^JX= zKCPu`NamQeP=nUjdZ#~K*Qkp=2Zgi=pV-8H7Bce+_V-V;Cy&<}D0}-L)E+mA-MwJ; zOcQN7XqW!g{`#!(G12mGcPSh`x&0T~{;8RVP{e9O8vjg{I#9>MC~O_H4AnhKFzeW#_!Giu-)=M|9Pp^ zoqzP_MXLFOZ|&Pv)WZ$L$CNi;Xv?A}tGI8r{bCKoTo>PUrz8xgkzQ1?$-klg#jZCwUg`M^xiWC8RIub7zX}mca!Zw+uuE* zrSU!1dSfUnnrhAOr1sDyp^@~nGS6(HHD^yU!#s^w&@Qjd6__2JTknmMehqsl8+n*z zY2nv>;lJ$re`Gd$L|fl|K$FMfzFLub`=I@F!ers>h1yG6+MMfe`AwVoVf$B49@w4Q zZSM597Jo%Qp2TX$XP(>KG49<{%b-0j6ts+7KEV{L+TSi0%%WGUF`jv8dwYLv@}9zy zd3{#y=Uyx^yt$R7;fv}Meq>bBD>i_sE^cAp|C;JCckN>OHA_GiRFTJ_&2pkm8?Ssg@7i1Mc$P-!_cavkvIcw>9>NO7Z#$jAgM-4 zvTD#cRZ7tZi=~e=cS6sObrkgTf#tghFde)jU~N$q9-YDOzAWyz?`T^~>#4TAlZKGspm+GM24Sdm}y+{vQ{?CqsQ8&pB z9Hasu%_L`RvG5#p0Vq~=~z-vY|_u8#_rq-l}OM(715$hvTxbR^_oFtR< z)8n>4geP`}%{3#=XOkKxV+C}*Wd{c`cqt>rH)A)9kxmB$*gKT4z@ zPAJhr`ndo`&zs`Tb=^_%-u0+(bW9qN!yx&tS=Of>F{oe^QIYdPg{h*qesSH)lt>IU z-W$`F@p3Dyu8wKE3q#50`S#2z7t$4n_PhC2=GZjL-$l7EvX=GZ?RFn$_nE%P|JQOw$FXyED53zJuF#&|6&NHQJpPfypH7 z24okXsEK{fwnvAuo(Vp;LK~6rNWQ>RwwsXH&Uc%k$#%CxxZZKE%**TyW=wcUzC>|R z%-|7UN6C8_k-hP5O{1w;7EACmB$`ED|70G;FjU$2)3@E49m*Hz8#mdiYtti+%bDdG zI~aChcBM&1erDb7=Ilcb(M#~mw?7Pe+`GpfG{@kFPZt<3`;9P+<)PlZrQNc_-&^Yq zzXXkzp_zP@S=FNMxMKz(dFzvf_DnIZ*KNb!4$b>E@Cs|kb9%v6h-w$NoT5JBf=rLq zWo|LJ!S%~lcO))I#=F%H`*nG{Hc9MZvw-FOKwo1gmdJhjBCS8YGeAV&A-tX{HS#5G zrPNaCvWY3;Y?M$(LJX>kLbRu*5QXX&;9*lN2T`a8f^zl=E;i{b{8ySvR5XHkX&l?> z2KJ7nRJL1msG4736x+Mx1A>Z0CXp!*l~J7{fsO`m1rI5oYK<}+lksFQ=rrMZ*_yeN zo*$;X@5@)MVIbYPm+tBAzO3Jna8MB3f;m%~g<;Z~M|(m#o~1$%VO26zN%( zP~x4WXBg{1Nqdb}fU5i9OZpm}Mre(hQRI{oqUGc%ZQzN(++9M6`bz`krE{>OiLC7q z6^pHvIeV|Pudmz1%RN~;b>X7hd1imzzjP_QWN+&9m;4|e>%06+?~JS+ueE)v&kX?G zJk#ZFRhQRMCmm6QxfodEX}+6k{i%=KyA@>#y`ER{V;;QF@~5-Qc_(JKEP3V?t(qKT zV&dv}amk0p(E@6PNOOsnf>k;!W_H!(rkmfjX65=)EUh0!{FEpoyKJZcLR$}t79|5%)+>-2GhdI{NunJKwT?{(uy1A;{)3uEV@fbm%>AQ@HX$TS{Yc_Oa zboGtYxaUr>>;n+Jqse1aWvsU-|Rt-csSPY=-=+}rN+}S;8DUA)Ct=V(nz4-q>T$5K*Z|<|FG9M$vY} zwk(Qc3eZ%Y1`F_9mZH(6Aj*`4yFU_fuANWZ3*x)((%!>+rWX(K9g$2wAi=aHk4INd z%izO&MzSc@w+y|AO=7B^Ufv8r22&BQWE5P@z;2oQhwQ1O7M6Nz%s`GFHp~53N5G|*E?sQ*F4?Kvb777hLEXB`SSzODqo0Ds z=@h?D&|s430GeSbrR9TYOC~r(MJ4OxzF&_x1ngYojfiLi9kZFsaXJ$N+W6KfRXmJ) zQ?ChYe)oW{exqBu)Nq+;!ck=lvs*kHiPn63HO~*+P6s^U*>>^ySby>CnUCze)8GF{ zai!gHuSBZYwv75y*M=&{4h9FP#IISpeZ7lf*63I6#{=WAJ$*do|)nr zRji|zw2z3GX_iBYZvqYhbPh5pw-yv7GJ@^&i3^94>1~?sJRD%DY)+}Ynl#19#~3bk z>VN=VC+5HvAEY~PvQ~F?4V1okucp!n2H#{JbS0_J+>E$K2#P5~>+&`bBzQqtz&N9d zVyfs+tEbvYyffPP`HPA+DSN0qj2R;h7`@nFn?8_5Baz*@?vsM}Q$)Inl@x)YkW5KY zIa3rhgJx7Vs0u!X1U1u1hob}VJJxLA!s7bUU?DK~MV4m>a!UClwM2;8qYf#Hk7wSl zpoz)4-M9?-erKhfEr<&P&yaTkZk^kftG)erYexWZT;}FHq9mYI&00N#sy6cWO$c?$ zKqfTMYjc4hnXCryT)>wU=cRHX1hJ%e_=HW_GVU*lM*Z_FyF4%xd;O}5fr$j7=Wh$V za+)cGz@Ln@zGO#C>W)6X%4w9zO_Szy0d|ET zcWAX+)3m)7G`lSA*wVU_(S*bVo2M@U9B24`p*tIoCHQ8xQerYCRa*^URKTqmKBw)H zFUZO;-fu4Qp&|R{vDG~W_u64iym8}3JCny-?88uu+n3Cb!%jb^hKsZa-()r9BpBY? zO^2ZvDXK+>ok0V{VJ#Ypr8ytV90LqmQb&AI%wZ7-*NWZ-lMCLWaER|2YQ=TWXDA+YVfuAWnYp6Cp>of>G!bR@7JF*m9QIujRkY8er$o~Hg zKFujx*%^^qP^60$fNY)h-v+4lG$uN`v{2~a;f(xK+iIY)-U*5vGuOkniqH$!SW zB^F!flE{K#d!x(nXOi+k8<+oF6;cOE$%zi7 zy~1$iI%02-4AS$3S`bxC2?e@YTd18fB{e`OBX7Nwwx?)@Jdgseh-wxEDV3<#i=Vn7 zUplZu*8`_s(f6Hsp)L|)^e~wKs_mFWDB_uU%7)5AoV7zqfo%&?{bqFt46lAD6SaCw z-1^9mj5BIc3^6iJQ)bvo*dFyW;yYfEPX?d2;Rs^nB6SlR6MvOU(mE7zyy)wMi-*ag z;gZ7SCbg_o5C!HefP{2YrgkX7aGeWen8wmbWx~&SAy)x21hd*0w^@`z9ZeS5vZV51 z4@H)@D==k@>_n41Y(C>9p+M~{^G~^!JbuO!XULnb+=nEJTH)=0Z-WZ5PbM|0!Z6wK z%~Qz=DZn6w8k8z*#@~uuQ>bTUfe@69JPx9d4b#G=BT8N+M@Z1yJ-LYWvhCR)^MU>MVX zBdc$k0I;PqJ}JX`hpuEwG4f79H;Zy2o_I+~3atqXse+H`QUqFZUD0leBS6blnAN_B zNx!(Z%INmXW~l{{ZQN!BRXm{6q;Az1MEIFNov759LXf~;>KIXW7Q;+=Kfg@_|>&IBX}T1hzt}5Eg@_nto9BT7gi+Q5%@Bx zKfy5VHL>_vq5Y!t^n}hMare5IE*mDz2ejqpl}In(JK9NC0;g2;6_^Jy@Ie_?S8a#A z?L$!>Qvz}&LyS)1ISv7l*+|fQkqsLZ72JvO1Mc)f=<`#T^SSxb@N9U%t?cgm z`Q92OJSagQWjT-$&jA-7G4VbMS@BPBGq(01UKn~+&KUD*$k%<$!@Agq#2u%sP^t8? zqddLvhXTspw|+EaU01*FIc{e7ylC$#@i z^@zXC?c!@Mlh@6y^UvORu6lePml-$ayCyf}w5YN58XoB$Ycpp(_l4U0n!mB}+vgTL zy+N;fD(l_5g4tZ0=f}mnypMmty0$#|*mB3)xE~$a%-UvW-rD=Rhp;`P&@AugkjE`V zHKUbXfdEFMMy^l_Bb7|u&WaURg;(g^e*A1IGo6fbmVgz#HyI$|bhjsV7m&Q7sS zWt2TQj=v7`!|*;B6~oX$98c(+8>32K(`4d4+vh#S7|kH=>xe}#BSY)w{BVC7my~wf z12Hz%=(i-y4_v5)K($ABP?AY+o|85Zal6dfhD;c|!P$i{Sm1+HHYvxmQQL7IafW9v z?m=!%M-WO-R0eWZ`b;sKPvDZ6W^EXkd z@3tR%`iXiikB6g)=c*i_^xTcU$y=)JtnWO%KJwGZhgTjOPlggF&yD5OX_?oCZ#>eK zwbN@iHz(HjnG>mt?|G5iLM6A+LJb-ZhY~M@ z-n`PVyzM1fanh$3+fI9J^z?*fN)`;y?!tp%jf{bUibrR~ny$E6M@jlw2WAmPyJEHeY^*)UW-wUs4TkH0alpE2cZxo6t@}>!I%W80R_Z}4|C**5 zT%#r(sn<`gxlj+$Po?Fp=TZ+GeyCKASay0F>P&##mj|?gT<^N>?RI(9E-w$gXB^5M zvD4`U_NARbMe0vmAB9K_&bpm?x_^fvZ?mil_N>dNK3KUw_VB1YeH;xhaM@` z#nFJtGyV3VTaJaA`N07d${2BJ0Z@OId&qW6zp2FnF|t3z3TV{lz6#%N%M*CnEpSSy zES#T)Xc+V(G+po0hWRpkn`12UW_=)!#r|q#YATsukNK#&t~uQWb`r;y4XR~JsJx`# zlJKw-jSo;gS)(d(ojGWQ7oDRrKDD(Qvb$8=u#oHkJp(a+?edy^31F zt%vP#j$gH0Mf9k@)^w}YD$5;HpOudg0hy*Rpld2ancXD;td5q|Tt z{ncu==NW5q(|;)MS6BPTM%SO{OMiKNeZ)^{+YLp6rf=OqtA#MRjbze18UyHbJUDLa z^hXbidiTkjQmuYuJFY#qCZ6BXip*b?HaAP07_(+ISn;c^rtf$J%zL{IBSZ#%>S?}4 zTN(*1;ps6mpoDoaPk+fKiIr_B>hXgi>-?OQHQiX5qeUmnUKbkLoc#;n!OCjnbtNdE zwkxoo8d9wpgi=NsN5IbqTgCWUh6uu6;G%!mKpMYLtWt~dR;GvYnl8bM2MMVrONo@4 zLW$%}xeIEEM`CVPov6hp9SDc~(e@e-sa#~g1xPuQh+1#Du9`0}#6bdoN)2U6parDT z;w;8>R{R#pC6wnDaXZbW3b-P%Oz^ozqcY;!Q-Teug44cK6i=wVkGptXCKPI3v$&2< z#^NK}B3>h1k`AhpX+J%jClX2ZH3W&D5;GYO48~C_}lrg20m?y$(MKkaP!ggXjBVjkh11uBiij=oDTuONd zvZjT^@TNeODj;&v>R$tK77H^ZU5nmqOI(b{6s;873T!O#R1LqCuvJLdB$hNU%LOfx zQi$JVNyzr<6(*UPlVqkdYLILnu{?jwvvpiO89d$`867*oPlfWiCr z*i0FZSVzBQad#mirf7x%h#GQEDL_bJ8Q8#Ty^S_YjAc6gJ7Jazv`ShliPOlGm0E@S zZ4wG5ubvH2Y_lc>5{lIAh6;s3?G~F_md8C}N2|C!RheeIV)`uc{Kk<~J$oeno`}rP zNQvTP$Tf93ZlxhK=*H~O(20@D?L*P+QIIqp#2P0Vi26UB@J7Y;_a$f?UfxojbrDFP zU?j6Go9NNSL-V+&a8ZDrv8I;VKmIz*KK*y*>Zh}&Z z>^D_Sl%Ep7`SU=y zhG}~%lh75Wye*C`EM@W-?BQ)1 zp(N>toi?OKAp(RHZVOa;3BJ5)7fmkXWPS4F@EqFc&8pjnje))XkH*a91xD6@%oH9c zk)z7Ef`bA-vZrlQ!xK8y$E{?IiJK&e+~U+#uShO;TU5+PZtbjoI?JsFqu=R&@sr#J z+J}-DhbuaMjbEZ7MO}GUjl2r*MlML#i-n$%4HPh;(uEvYO+!ShK}v}!jYh%yIz|c_ zjhZ{~uM;ao6=OO{DV|W}rOD2C(SHdnSB|cDjzqMe-sYewMB-lMWK91c*MKczK3!rF z*$Vv@x`mZlN`e-64TNiA+agAsm=xDg^Mw@K3W|C0EeWycJzIPUD+?Y^G!_bBPVsBO zybW!u;E+-Sgb)zHU((SPdJ+L~^VEilnq_0wtFmGx{Qh6#~k%q*s{Pe|FWf3Oj~b&dmy}aUKW};hL76Dj2jZ zqdjdqRICn6mZwyJ3TOPdl#i`i-exTD3o*KUF7tP<=*OuJx~HYVSe#7}$_HBf5=ZYoJthG;`jQi9?_s0bM%pSg1v zM`ZQ~`Zf>>nreD2#9oSrl3EtT!+Q<@l1yo-Y|=x)qhZ3zIu#9_D4F*XNiHF9Ri?7c zlD|y+X_w7+Ucx(bsUIoKMes8~`2a4-_mn!c0?U

RotlOHS5K9l`OM`f&SjV%B#4 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

*AwhXvYQ*a? zK?pq=J-L3LkFjEEh-Uvp=Z`!$Ecc$OoM5c`)l+g}Eaxf`2SYr#=p2&wu65>471fux zB$MOgi(PYmxO8`?f<_N@?+(vR&YQ`8X^iAVxO>3TR=Fvok&u8-D4GJ3hKTii>>Z*u z#^6}zT*W;!xVvKp-V9o-15Ys+CNZ2?je&B`M%z6n`=Z=k>b~o+QoZ3xlPz9|ZY{sR z?W=1m?a=(?2UdN%?V|Ie8fSj8*2Z1@nQZ^)@Jc(n!K&eXVzwjIVSV7nx&^Fc>!;+& zTj=*a`jp7P9p=TMXnBony|-M^5-YZj`Po`m#H_0?B^fT!j}XJe!5+*;`Tst%?p?ov)0;0;?h!MLXI^-O7z^=#+ z`V}Z9pU`2XZ>$Q`lkYiL7mO?$;T;`YzbSSryhqRe3g?xl*kE0#`it$}CGR66=2Cmu zyDmm+FIk&*Qf%iLy#`F5=P zLLG-yrAG}CI1SToq$0d--t|O)SmaNIOmt+ll`51F5T}W8C?n&I?KSuo3!vn#@!sN} z_4DGC1PrzHw9G}`x=|EIb&;7DtYRt?av_RGX;U9)5k_WhfGSK9qKn?ym17t0m_+8V zv--qfB|ore+RO*nSGmebC->{HkH~vF=Mg=Vt*eA7jNDT9ZX%U5v)I##Zm7}qV{Ez< zG;X7uW2i*X5K#K*Z~{d&9yExg4?6qD?XKwroCz}%aXLSM(=+sh{H;_sIMtR;vtdjQ zT7@pZ1Ofh7T)$zOi;1SjUZjc&Lozv^(6I9?3_xuip;>z zuy;j}5R@TWeFxvhoK5x&C?XRrlaw%FFjnYvO3USVT8B%VyWB^SVQ01=I&NC(J?-%Mc%UPa_2| z1su3tnpAWk=5&MvH?Um}CgM{+cXTPeGBY0O=CJ5>4y7H;PNl`*36Mu3mt+al{kSGG zyqD-GQgsY-<1*~VHf1t7KRJKB;6N_B^OBrfyK^b!B->f?=Vvd-q@}9R`l^$5OqRHy zWl(Ph&m9ORO3?{YEj8kj%Stsb->6`Sq<*bxS=(YN=QX}UN5qiZ6~Z;2%9^CTZYvk{ zH`a^Xq~f$TrNP1U=JXz$N&gVAcAmu;=%?V6s3HOCjIR#joNWZ@MKfRH_u4y2iMs*U}=gMHp8eD!>s|GTMM86}zH)*M4@r@dMx^9ZFXPyJ0-B;%)GyHrbHGtRDtBIZA{Ot5 zDLS74tq5Dw0<6D9CC6zzQLQRctjN1^C2A2Y?<;dK%ApK*Bu&varkDa{1aPmr$An%{ zohjeD9(~FbOCENRySYn>E~F7V1jIAohzaNnOo6FhPG?w+^FxeJNbs7p z6Wmk)$}4x7u5)YwI)F=d z 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

9%6ch=+Nv9zurr$P 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[Egk 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 z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| 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Ⓢ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 -# e1000-devel Mailing List -# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -# -################################################################################ diff --git a/openflow/datapath/linux-2.6/Modules.mk b/openflow/datapath/linux-2.6/Modules.mk deleted file mode 100644 index 8c854a0e..00000000 --- a/openflow/datapath/linux-2.6/Modules.mk +++ /dev/null @@ -1,32 +0,0 @@ -ofdatapath_sources += \ - linux-2.6/compat-2.6/genetlink-openflow.c \ - linux-2.6/compat-2.6/random32.c -ofdatapath_headers += \ - linux-2.6/compat-2.6/compat26.h \ - linux-2.6/compat-2.6/include/asm-generic/bug.h \ - linux-2.6/compat-2.6/include/linux/dmi.h \ - linux-2.6/compat-2.6/include/linux/icmp.h \ - linux-2.6/compat-2.6/include/linux/if_arp.h \ - linux-2.6/compat-2.6/include/linux/ip.h \ - linux-2.6/compat-2.6/include/linux/ipv6.h \ - linux-2.6/compat-2.6/include/linux/jiffies.h \ - linux-2.6/compat-2.6/include/linux/lockdep.h \ - linux-2.6/compat-2.6/include/linux/mutex.h \ - linux-2.6/compat-2.6/include/linux/netfilter_ipv4.h \ - linux-2.6/compat-2.6/include/linux/netlink.h \ - linux-2.6/compat-2.6/include/linux/random.h \ - linux-2.6/compat-2.6/include/linux/rculist.h \ - linux-2.6/compat-2.6/include/linux/skbuff.h \ - linux-2.6/compat-2.6/include/linux/tcp.h \ - linux-2.6/compat-2.6/include/linux/timer.h \ - linux-2.6/compat-2.6/include/linux/types.h \ - linux-2.6/compat-2.6/include/linux/udp.h \ - linux-2.6/compat-2.6/include/linux/workqueue.h \ - linux-2.6/compat-2.6/include/net/checksum.h \ - linux-2.6/compat-2.6/include/net/genetlink.h \ - linux-2.6/compat-2.6/include/net/netlink.h - -#dist_modules += veth -#build_modules += $(if $(BUILD_VETH),veth) -veth_sources = linux-2.6/compat-2.6/veth.c -veth_headers = diff --git a/openflow/datapath/linux-2.6/compat-2.6/compat26.h b/openflow/datapath/linux-2.6/compat-2.6/compat26.h deleted file mode 100644 index 37f6a4f8..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/compat26.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef __COMPAT26_H -#define __COMPAT26_H 1 - -#include - -#if defined(CONFIG_PREEMPT) && LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21) -#error "CONFIG_PREEMPT is broken with 2.6.x before 2.6.21--see commit 4498121ca3, \"[NET]: Handle disabled preemption in gfp_any()\"" -#endif - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23) -/*---------------------------------------------------------------------------- - * In 2.6.24, a namespace argument became required for dev_get_by_name. */ - -#define dev_get_by_name(net, name) \ - dev_get_by_name((name)) - -#define dev_get_by_index(net, ifindex) \ - dev_get_by_index((ifindex)) - -#endif /* linux kernel <= 2.6.23 */ - - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22) -/*---------------------------------------------------------------------------- - * In 2.6.23, the last argument was dropped from kmem_cache_create. */ -#define kmem_cache_create(n, s, a, f, c) \ - kmem_cache_create((n), (s), (a), (f), (c), NULL) - -#endif /* linux kernel <= 2.6.22 */ - -#endif /* compat26.h */ diff --git a/openflow/datapath/linux-2.6/compat-2.6/genetlink-brcompat.c b/openflow/datapath/linux-2.6/compat-2.6/genetlink-brcompat.c deleted file mode 100644 index f30996ce..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/genetlink-brcompat.c +++ /dev/null @@ -1,20 +0,0 @@ -#include "net/genetlink.h" - -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) - -/* We fix grp->id to 32 so that it doesn't collide with any of the multicast - * groups selected by openflow_mod, which uses groups 16 through 31. Collision - * isn't fatal--multicast listeners should check that the family is the one - * that they want and discard others--but it wastes time and memory to receive - * unwanted messages. */ -int genl_register_mc_group(struct genl_family *family, - struct genl_multicast_group *grp) -{ - grp->id = 32; - grp->family = family; - - return 0; -} - -#endif /* kernel < 2.6.23 */ diff --git a/openflow/datapath/linux-2.6/compat-2.6/genetlink-openflow.c b/openflow/datapath/linux-2.6/compat-2.6/genetlink-openflow.c deleted file mode 100644 index 9e09215f..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/genetlink-openflow.c +++ /dev/null @@ -1,22 +0,0 @@ -#include "net/genetlink.h" - -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) - -/* We use multicast groups 16 through 31 to avoid colliding with the multicast - * group selected by brcompat_mod, which uses groups 32. Collision isn't - * fatal--multicast listeners should check that the family is the one that they - * want and discard others--but it wastes time and memory to receive unwanted - * messages. */ -int genl_register_mc_group(struct genl_family *family, - struct genl_multicast_group *grp) -{ - /* This code is called single-threaded. */ - static unsigned int next_id = 0; - grp->id = next_id++ % 16 + 16; - grp->family = family; - - return 0; -} - -#endif /* kernel < 2.6.23 */ diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/asm-generic/bug.h b/openflow/datapath/linux-2.6/compat-2.6/include/asm-generic/bug.h deleted file mode 100644 index bd0a1714..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/asm-generic/bug.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef __ASM_GENERIC_BUG_WRAPPER_H -#define __ASM_GENERIC_BUG_WRAPPER_H - -#include_next - -#ifndef WARN_ON_ONCE -#define WARN_ON_ONCE(condition) ({ \ - static int __warned; \ - int __ret_warn_once = !!(condition); \ - \ - if (unlikely(__ret_warn_once) && !__warned) { \ - WARN_ON(1); \ - __warned = 1; \ - } \ - unlikely(__ret_warn_once); \ -}) - -#endif - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/dmi.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/dmi.h deleted file mode 100644 index 52916fec..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/dmi.h +++ /dev/null @@ -1,114 +0,0 @@ -#ifndef __LINUX_DMI_WRAPPER_H -#define __LINUX_DMI_WRAPPER_H 1 - -#include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23) - -#include_next - -#else /* linux version >= 2.6.23 */ - -#ifndef __DMI_H__ -#define __DMI_H__ - -#include - -enum dmi_field { - DMI_NONE, - DMI_BIOS_VENDOR, - DMI_BIOS_VERSION, - DMI_BIOS_DATE, - DMI_SYS_VENDOR, - DMI_PRODUCT_NAME, - DMI_PRODUCT_VERSION, - DMI_PRODUCT_SERIAL, - DMI_PRODUCT_UUID, - DMI_BOARD_VENDOR, - DMI_BOARD_NAME, - DMI_BOARD_VERSION, - DMI_BOARD_SERIAL, - DMI_BOARD_ASSET_TAG, - DMI_CHASSIS_VENDOR, - DMI_CHASSIS_TYPE, - DMI_CHASSIS_VERSION, - DMI_CHASSIS_SERIAL, - DMI_CHASSIS_ASSET_TAG, - DMI_STRING_MAX, -}; - -enum dmi_device_type { - DMI_DEV_TYPE_ANY = 0, - DMI_DEV_TYPE_OTHER, - DMI_DEV_TYPE_UNKNOWN, - DMI_DEV_TYPE_VIDEO, - DMI_DEV_TYPE_SCSI, - DMI_DEV_TYPE_ETHERNET, - DMI_DEV_TYPE_TOKENRING, - DMI_DEV_TYPE_SOUND, - DMI_DEV_TYPE_IPMI = -1, - DMI_DEV_TYPE_OEM_STRING = -2 -}; - -struct dmi_header { - u8 type; - u8 length; - u16 handle; -}; - -/* - * DMI callbacks for problem boards - */ -struct dmi_strmatch { - u8 slot; - char *substr; -}; - -struct dmi_system_id { - int (*callback)(struct dmi_system_id *); - const char *ident; - struct dmi_strmatch matches[4]; - void *driver_data; -}; - -#define DMI_MATCH(a, b) { a, b } - -struct dmi_device { - struct list_head list; - int type; - const char *name; - void *device_data; /* Type specific data */ -}; - -/* No CONFIG_DMI before 2.6.16 */ -#if defined(CONFIG_DMI) || defined(CONFIG_X86_32) - -extern int dmi_check_system(struct dmi_system_id *list); -extern char * dmi_get_system_info(int field); -extern struct dmi_device * dmi_find_device(int type, const char *name, - struct dmi_device *from); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) -extern void dmi_scan_machine(void); -#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17) -extern int dmi_get_year(int field); -#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) -extern int dmi_name_in_vendors(char *str); -#endif - -#else - -static inline int dmi_check_system(struct dmi_system_id *list) { return 0; } -static inline char * dmi_get_system_info(int field) { return NULL; } -static inline struct dmi_device * dmi_find_device(int type, const char *name, - struct dmi_device *from) { return NULL; } -static inline int dmi_get_year(int year) { return 0; } -static inline int dmi_name_in_vendors(char *s) { return 0; } - -#endif - -#endif /* __DMI_H__ */ - -#endif /* linux kernel < 2.6.22 */ - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/icmp.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/icmp.h deleted file mode 100644 index 89b354e4..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/icmp.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef __LINUX_ICMP_WRAPPER_H -#define __LINUX_ICMP_WRAPPER_H 1 - -#include_next - -#ifndef HAVE_SKBUFF_HEADER_HELPERS -static inline struct icmphdr *icmp_hdr(const struct sk_buff *skb) -{ - return (struct icmphdr *)skb_transport_header(skb); -} -#endif - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/if_arp.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/if_arp.h deleted file mode 100644 index 3ec9ea7a..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/if_arp.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef __LINUX_IF_ARP_WRAPPER_H -#define __LINUX_IF_ARP_WRAPPER_H 1 - - -#include_next - -#ifndef HAVE_SKBUFF_HEADER_HELPERS -#include - -static inline struct arphdr *arp_hdr(const struct sk_buff *skb) -{ - return (struct arphdr *)skb_network_header(skb); -} -#endif /* !HAVE_SKBUFF_HEADER_HELPERS */ - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/ip.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/ip.h deleted file mode 100644 index 36765396..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/ip.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef __LINUX_IP_WRAPPER_H -#define __LINUX_IP_WRAPPER_H 1 - -#include_next - -#ifndef HAVE_SKBUFF_HEADER_HELPERS -static inline struct iphdr *ip_hdr(const struct sk_buff *skb) -{ - return (struct iphdr *)skb_network_header(skb); -} - -static inline unsigned int ip_hdrlen(const struct sk_buff *skb) -{ - return ip_hdr(skb)->ihl * 4; -} -#endif /* !HAVE_SKBUFF_HEADER_HELPERS */ - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/ipv6.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/ipv6.h deleted file mode 100644 index 25a5431a..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/ipv6.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef __LINUX_IPV6_WRAPPER_H -#define __LINUX_IPV6_WRAPPER_H 1 - -#include_next - -#ifndef HAVE_SKBUFF_HEADER_HELPERS -static inline struct ipv6hdr *ipv6_hdr(const struct sk_buff *skb) -{ - return (struct ipv6hdr *)skb_network_header(skb); -} -#endif - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/jiffies.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/jiffies.h deleted file mode 100644 index 3286e634..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/jiffies.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef __LINUX_JIFFIES_WRAPPER_H -#define __LINUX_JIFFIES_WRAPPER_H 1 - -#include_next - -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) - -/* Same as above, but does so with platform independent 64bit types. - * These must be used when utilizing jiffies_64 (i.e. return value of - * get_jiffies_64() */ -#define time_after64(a,b) \ - (typecheck(__u64, a) && \ - typecheck(__u64, b) && \ - ((__s64)(b) - (__s64)(a) < 0)) -#define time_before64(a,b) time_after64(b,a) - -#define time_after_eq64(a,b) \ - (typecheck(__u64, a) && \ - typecheck(__u64, b) && \ - ((__s64)(a) - (__s64)(b) >= 0)) -#define time_before_eq64(a,b) time_after_eq64(b,a) - -#endif /* linux kernel < 2.6.19 */ - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/lockdep.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/lockdep.h deleted file mode 100644 index 1c839423..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/lockdep.h +++ /dev/null @@ -1,450 +0,0 @@ -/* - * Runtime locking correctness validator - * - * Copyright (C) 2006,2007 Red Hat, Inc., Ingo Molnar - * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra - * - * see Documentation/lockdep-design.txt for more details. - */ -#ifndef __LINUX_LOCKDEP_WRAPPER_H -#define __LINUX_LOCKDEP_WRAPPER_H - -#include_next - -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) - -struct task_struct; -struct lockdep_map; - -#ifdef CONFIG_LOCKDEP - -#include -#include -#include -#include - -/* - * Lock-class usage-state bits: - */ -enum lock_usage_bit -{ - LOCK_USED = 0, - LOCK_USED_IN_HARDIRQ, - LOCK_USED_IN_SOFTIRQ, - LOCK_ENABLED_SOFTIRQS, - LOCK_ENABLED_HARDIRQS, - LOCK_USED_IN_HARDIRQ_READ, - LOCK_USED_IN_SOFTIRQ_READ, - LOCK_ENABLED_SOFTIRQS_READ, - LOCK_ENABLED_HARDIRQS_READ, - LOCK_USAGE_STATES -}; - -/* - * Usage-state bitmasks: - */ -#define LOCKF_USED (1 << LOCK_USED) -#define LOCKF_USED_IN_HARDIRQ (1 << LOCK_USED_IN_HARDIRQ) -#define LOCKF_USED_IN_SOFTIRQ (1 << LOCK_USED_IN_SOFTIRQ) -#define LOCKF_ENABLED_HARDIRQS (1 << LOCK_ENABLED_HARDIRQS) -#define LOCKF_ENABLED_SOFTIRQS (1 << LOCK_ENABLED_SOFTIRQS) - -#define LOCKF_ENABLED_IRQS (LOCKF_ENABLED_HARDIRQS | LOCKF_ENABLED_SOFTIRQS) -#define LOCKF_USED_IN_IRQ (LOCKF_USED_IN_HARDIRQ | LOCKF_USED_IN_SOFTIRQ) - -#define LOCKF_USED_IN_HARDIRQ_READ (1 << LOCK_USED_IN_HARDIRQ_READ) -#define LOCKF_USED_IN_SOFTIRQ_READ (1 << LOCK_USED_IN_SOFTIRQ_READ) -#define LOCKF_ENABLED_HARDIRQS_READ (1 << LOCK_ENABLED_HARDIRQS_READ) -#define LOCKF_ENABLED_SOFTIRQS_READ (1 << LOCK_ENABLED_SOFTIRQS_READ) - -#define LOCKF_ENABLED_IRQS_READ \ - (LOCKF_ENABLED_HARDIRQS_READ | LOCKF_ENABLED_SOFTIRQS_READ) -#define LOCKF_USED_IN_IRQ_READ \ - (LOCKF_USED_IN_HARDIRQ_READ | LOCKF_USED_IN_SOFTIRQ_READ) - -#define MAX_LOCKDEP_SUBCLASSES 8UL - -/* - * Lock-classes are keyed via unique addresses, by embedding the - * lockclass-key into the kernel (or module) .data section. (For - * static locks we use the lock address itself as the key.) - */ -struct lockdep_subclass_key { - char __one_byte; -} __attribute__ ((__packed__)); - -struct lock_class_key { - struct lockdep_subclass_key subkeys[MAX_LOCKDEP_SUBCLASSES]; -}; - -/* - * The lock-class itself: - */ -struct lock_class { - /* - * class-hash: - */ - struct list_head hash_entry; - - /* - * global list of all lock-classes: - */ - struct list_head lock_entry; - - struct lockdep_subclass_key *key; - unsigned int subclass; - - /* - * IRQ/softirq usage tracking bits: - */ - unsigned long usage_mask; - struct stack_trace usage_traces[LOCK_USAGE_STATES]; - - /* - * These fields represent a directed graph of lock dependencies, - * to every node we attach a list of "forward" and a list of - * "backward" graph nodes. - */ - struct list_head locks_after, locks_before; - - /* - * Generation counter, when doing certain classes of graph walking, - * to ensure that we check one node only once: - */ - unsigned int version; - - /* - * Statistics counter: - */ - unsigned long ops; - - const char *name; - int name_version; - -#ifdef CONFIG_LOCK_STAT - unsigned long contention_point[4]; -#endif -}; - -#ifdef CONFIG_LOCK_STAT -struct lock_time { - s64 min; - s64 max; - s64 total; - unsigned long nr; -}; - -enum bounce_type { - bounce_acquired_write, - bounce_acquired_read, - bounce_contended_write, - bounce_contended_read, - nr_bounce_types, - - bounce_acquired = bounce_acquired_write, - bounce_contended = bounce_contended_write, -}; - -struct lock_class_stats { - unsigned long contention_point[4]; - struct lock_time read_waittime; - struct lock_time write_waittime; - struct lock_time read_holdtime; - struct lock_time write_holdtime; - unsigned long bounces[nr_bounce_types]; -}; - -struct lock_class_stats lock_stats(struct lock_class *class); -void clear_lock_stats(struct lock_class *class); -#endif - -/* - * Map the lock object (the lock instance) to the lock-class object. - * This is embedded into specific lock instances: - */ -struct lockdep_map { - struct lock_class_key *key; - struct lock_class *class_cache; - const char *name; -#ifdef CONFIG_LOCK_STAT - int cpu; -#endif -}; - -/* - * Every lock has a list of other locks that were taken after it. - * We only grow the list, never remove from it: - */ -struct lock_list { - struct list_head entry; - struct lock_class *class; - struct stack_trace trace; - int distance; -}; - -/* - * We record lock dependency chains, so that we can cache them: - */ -struct lock_chain { - struct list_head entry; - u64 chain_key; -}; - -struct held_lock { - /* - * One-way hash of the dependency chain up to this point. We - * hash the hashes step by step as the dependency chain grows. - * - * We use it for dependency-caching and we skip detection - * passes and dependency-updates if there is a cache-hit, so - * it is absolutely critical for 100% coverage of the validator - * to have a unique key value for every unique dependency path - * that can occur in the system, to make a unique hash value - * as likely as possible - hence the 64-bit width. - * - * The task struct holds the current hash value (initialized - * with zero), here we store the previous hash value: - */ - u64 prev_chain_key; - struct lock_class *class; - unsigned long acquire_ip; - struct lockdep_map *instance; - -#ifdef CONFIG_LOCK_STAT - u64 waittime_stamp; - u64 holdtime_stamp; -#endif - /* - * The lock-stack is unified in that the lock chains of interrupt - * contexts nest ontop of process context chains, but we 'separate' - * the hashes by starting with 0 if we cross into an interrupt - * context, and we also keep do not add cross-context lock - * dependencies - the lock usage graph walking covers that area - * anyway, and we'd just unnecessarily increase the number of - * dependencies otherwise. [Note: hardirq and softirq contexts - * are separated from each other too.] - * - * The following field is used to detect when we cross into an - * interrupt context: - */ - int irq_context; - int trylock; - int read; - int check; - int hardirqs_off; -}; - -/* - * Initialization, self-test and debugging-output methods: - */ -extern void lockdep_init(void); -extern void lockdep_info(void); -extern void lockdep_reset(void); -extern void lockdep_reset_lock(struct lockdep_map *lock); -extern void lockdep_free_key_range(void *start, unsigned long size); - -extern void lockdep_off(void); -extern void lockdep_on(void); - -/* - * These methods are used by specific locking variants (spinlocks, - * rwlocks, mutexes and rwsems) to pass init/acquire/release events - * to lockdep: - */ - -extern void lockdep_init_map(struct lockdep_map *lock, const char *name, - struct lock_class_key *key, int subclass); - -/* - * Reinitialize a lock key - for cases where there is special locking or - * special initialization of locks so that the validator gets the scope - * of dependencies wrong: they are either too broad (they need a class-split) - * or they are too narrow (they suffer from a false class-split): - */ -#define lockdep_set_class(lock, key) \ - lockdep_init_map(&(lock)->dep_map, #key, key, 0) -#define lockdep_set_class_and_name(lock, key, name) \ - lockdep_init_map(&(lock)->dep_map, name, key, 0) -#define lockdep_set_class_and_subclass(lock, key, sub) \ - lockdep_init_map(&(lock)->dep_map, #key, key, sub) -#define lockdep_set_subclass(lock, sub) \ - lockdep_init_map(&(lock)->dep_map, #lock, \ - (lock)->dep_map.key, sub) - -/* - * Acquire a lock. - * - * Values for "read": - * - * 0: exclusive (write) acquire - * 1: read-acquire (no recursion allowed) - * 2: read-acquire with same-instance recursion allowed - * - * Values for check: - * - * 0: disabled - * 1: simple checks (freeing, held-at-exit-time, etc.) - * 2: full validation - */ -extern void lock_acquire(struct lockdep_map *lock, unsigned int subclass, - int trylock, int read, int check, unsigned long ip); - -extern void lock_release(struct lockdep_map *lock, int nested, - unsigned long ip); - -# define INIT_LOCKDEP .lockdep_recursion = 0, - -#define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0) - -#else /* !LOCKDEP */ - -static inline void lockdep_off(void) -{ -} - -static inline void lockdep_on(void) -{ -} - -# define lock_acquire(l, s, t, r, c, i) do { } while (0) -# define lock_release(l, n, i) do { } while (0) -# define lockdep_init() do { } while (0) -# define lockdep_info() do { } while (0) -# define lockdep_init_map(lock, name, key, sub) do { (void)(key); } while (0) -# define lockdep_set_class(lock, key) do { (void)(key); } while (0) -# define lockdep_set_class_and_name(lock, key, name) \ - do { (void)(key); } while (0) -#define lockdep_set_class_and_subclass(lock, key, sub) \ - do { (void)(key); } while (0) -#define lockdep_set_subclass(lock, sub) do { } while (0) - -# define INIT_LOCKDEP -# define lockdep_reset() do { debug_locks = 1; } while (0) -# define lockdep_free_key_range(start, size) do { } while (0) -/* - * The class key takes no space if lockdep is disabled: - */ -struct lock_class_key { }; - -#define lockdep_depth(tsk) (0) - -#endif /* !LOCKDEP */ - -#ifdef CONFIG_LOCK_STAT - -extern void lock_contended(struct lockdep_map *lock, unsigned long ip); -extern void lock_acquired(struct lockdep_map *lock); - -#define LOCK_CONTENDED(_lock, try, lock) \ -do { \ - if (!try(_lock)) { \ - lock_contended(&(_lock)->dep_map, _RET_IP_); \ - lock(_lock); \ - } \ - lock_acquired(&(_lock)->dep_map); \ -} while (0) - -#else /* CONFIG_LOCK_STAT */ - -#define lock_contended(lockdep_map, ip) do {} while (0) -#define lock_acquired(lockdep_map) do {} while (0) - -#define LOCK_CONTENDED(_lock, try, lock) \ - lock(_lock) - -#endif /* CONFIG_LOCK_STAT */ - -#if defined(CONFIG_TRACE_IRQFLAGS) && defined(CONFIG_GENERIC_HARDIRQS) -extern void early_init_irq_lock_class(void); -#else -static inline void early_init_irq_lock_class(void) -{ -} -#endif - -#ifdef CONFIG_TRACE_IRQFLAGS -extern void early_boot_irqs_off(void); -extern void early_boot_irqs_on(void); -extern void print_irqtrace_events(struct task_struct *curr); -#else -static inline void early_boot_irqs_off(void) -{ -} -static inline void early_boot_irqs_on(void) -{ -} -static inline void print_irqtrace_events(struct task_struct *curr) -{ -} -#endif - -/* - * For trivial one-depth nesting of a lock-class, the following - * global define can be used. (Subsystems with multiple levels - * of nesting should define their own lock-nesting subclasses.) - */ -#define SINGLE_DEPTH_NESTING 1 - -/* - * Map the dependency ops to NOP or to real lockdep ops, depending - * on the per lock-class debug mode: - */ - -#ifdef CONFIG_DEBUG_LOCK_ALLOC -# ifdef CONFIG_PROVE_LOCKING -# define spin_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 2, i) -# else -# define spin_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 1, i) -# endif -# define spin_release(l, n, i) lock_release(l, n, i) -#else -# define spin_acquire(l, s, t, i) do { } while (0) -# define spin_release(l, n, i) do { } while (0) -#endif - -#ifdef CONFIG_DEBUG_LOCK_ALLOC -# ifdef CONFIG_PROVE_LOCKING -# define rwlock_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 2, i) -# define rwlock_acquire_read(l, s, t, i) lock_acquire(l, s, t, 2, 2, i) -# else -# define rwlock_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 1, i) -# define rwlock_acquire_read(l, s, t, i) lock_acquire(l, s, t, 2, 1, i) -# endif -# define rwlock_release(l, n, i) lock_release(l, n, i) -#else -# define rwlock_acquire(l, s, t, i) do { } while (0) -# define rwlock_acquire_read(l, s, t, i) do { } while (0) -# define rwlock_release(l, n, i) do { } while (0) -#endif - -#ifdef CONFIG_DEBUG_LOCK_ALLOC -# ifdef CONFIG_PROVE_LOCKING -# define mutex_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 2, i) -# else -# define mutex_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 1, i) -# endif -# define mutex_release(l, n, i) lock_release(l, n, i) -#else -# define mutex_acquire(l, s, t, i) do { } while (0) -# define mutex_release(l, n, i) do { } while (0) -#endif - -#ifdef CONFIG_DEBUG_LOCK_ALLOC -# ifdef CONFIG_PROVE_LOCKING -# define rwsem_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 2, i) -# define rwsem_acquire_read(l, s, t, i) lock_acquire(l, s, t, 1, 2, i) -# else -# define rwsem_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 1, i) -# define rwsem_acquire_read(l, s, t, i) lock_acquire(l, s, t, 1, 1, i) -# endif -# define rwsem_release(l, n, i) lock_release(l, n, i) -#else -# define rwsem_acquire(l, s, t, i) do { } while (0) -# define rwsem_acquire_read(l, s, t, i) do { } while (0) -# define rwsem_release(l, n, i) do { } while (0) -#endif - -#endif /* linux kernel < 2.6.18 */ - -#endif /* __LINUX_LOCKDEP_WRAPPER_H */ diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/mutex.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/mutex.h deleted file mode 100644 index cb5b2738..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/mutex.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef __LINUX_MUTEX_WRAPPER_H -#define __LINUX_MUTEX_WRAPPER_H - - -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) - -#include - -struct mutex { - struct semaphore sema; -}; - -#define mutex_init(mutex) init_MUTEX(&mutex->sema) -#define mutex_destroy(mutex) do { } while (0) - -#define __MUTEX_INITIALIZER(name) \ - __SEMAPHORE_INITIALIZER(name,1) - -#define DEFINE_MUTEX(mutexname) \ - struct mutex mutexname = { __MUTEX_INITIALIZER(mutexname.sema) } - -/* - * See kernel/mutex.c for detailed documentation of these APIs. - * Also see Documentation/mutex-design.txt. - */ -static inline void mutex_lock(struct mutex *lock) -{ - down(&lock->sema); -} - -static inline int mutex_lock_interruptible(struct mutex *lock) -{ - return down_interruptible(&lock->sema); -} - -#define mutex_lock_nested(lock, subclass) mutex_lock(lock) -#define mutex_lock_interruptible_nested(lock, subclass) mutex_lock_interruptible(lock) - -/* - * NOTE: mutex_trylock() follows the spin_trylock() convention, - * not the down_trylock() convention! - */ -static inline int mutex_trylock(struct mutex *lock) -{ - return !down_trylock(&lock->sema); -} - -static inline void mutex_unlock(struct mutex *lock) -{ - up(&lock->sema); -} -#else - -#include_next - -#endif /* linux version < 2.6.16 */ - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/netdevice.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/netdevice.h deleted file mode 100644 index 7abeb3bf..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/netdevice.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef __LINUX_NETDEVICE_WRAPPER_H -#define __LINUX_NETDEVICE_WRAPPER_H 1 - -#include_next - -#ifndef to_net_dev -#define to_net_dev(class) container_of(class, struct net_device, class_dev) -#endif - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/netfilter_bridge.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/netfilter_bridge.h deleted file mode 100644 index 1c8183c8..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/netfilter_bridge.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef __LINUX_NETFILTER_BRIDGE_WRAPPER_H -#define __LINUX_NETFILTER_BRIDGE_WRAPPER_H - -#include_next - -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) - -#include -#include - -static inline unsigned int nf_bridge_encap_header_len(const struct sk_buff *skb) -{ - switch (skb->protocol) { - case __constant_htons(ETH_P_8021Q): - return VLAN_HLEN; - default: - return 0; - } -} - -#endif /* linux version < 2.6.22 */ - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/netfilter_ipv4.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/netfilter_ipv4.h deleted file mode 100644 index ed8a5d94..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/netfilter_ipv4.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef __LINUX_NETFILTER_IPV4_WRAPPER_H -#define __LINUX_NETFILTER_IPV4_WRAPPER_H 1 - -#include_next - -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) - -#ifdef __KERNEL__ - -#define NF_INET_PRE_ROUTING NF_IP_PRE_ROUTING -#define NF_INET_POST_ROUTING NF_IP_POST_ROUTING -#define NF_INET_FORWARD NF_IP_FORWARD - -#endif /* __KERNEL__ */ - -#endif /* linux kernel < 2.6.25 */ - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/netlink.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/netlink.h deleted file mode 100644 index c5f83bd0..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/netlink.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef __LINUX_NETLINK_WRAPPER_H -#define __LINUX_NETLINK_WRAPPER_H 1 - -#include -#include_next -#include - -#include - -#ifndef NLMSG_DEFAULT_SIZE -#define NLMSG_DEFAULT_SIZE (NLMSG_GOODSIZE - NLMSG_HDRLEN) -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) -#define nlmsg_new(s, f) nlmsg_new_proper((s), (f)) -static inline struct sk_buff *nlmsg_new_proper(int size, gfp_t flags) -{ - return alloc_skb(size, flags); -} - -#endif /* linux kernel < 2.6.19 */ - - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/random.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/random.h deleted file mode 100644 index 4e4932c9..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/random.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef __LINUX_RANDOM_WRAPPER_H -#define __LINUX_RANDOM_WRAPPER_H 1 - -#include_next - -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) - -#ifdef __KERNEL__ -u32 random32(void); -void srandom32(u32 seed); -#endif /* __KERNEL__ */ - -#endif /* linux kernel < 2.6.19 */ - - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/rculist.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/rculist.h deleted file mode 100644 index 4164c0e9..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/rculist.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __LINUX_RCULIST_WRAPPER_H -#define __LINUX_RCULIST_WRAPPER_H - -#include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) -#include_next -#else -/* Prior to 2.6.26, the contents of rculist.h were part of list.h. */ -#include -#endif - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/skbuff.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/skbuff.h deleted file mode 100644 index 55d32eb1..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/skbuff.h +++ /dev/null @@ -1,137 +0,0 @@ -#ifndef __LINUX_SKBUFF_WRAPPER_H -#define __LINUX_SKBUFF_WRAPPER_H 1 - -#include_next - -#include - -#ifndef HAVE_SKB_COPY_FROM_LINEAR_DATA_OFFSET -static inline void skb_copy_from_linear_data_offset(const struct sk_buff *skb, - const int offset, void *to, - const unsigned int len) -{ - memcpy(to, skb->data + offset, len); -} - -static inline void skb_copy_to_linear_data_offset(struct sk_buff *skb, - const int offset, - const void *from, - const unsigned int len) -{ - memcpy(skb->data + offset, from, len); -} - -#endif /* !HAVE_SKB_COPY_FROM_LINEAR_DATA_OFFSET */ - - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) -static inline int __skb_cow(struct sk_buff *skb, unsigned int headroom, - int cloned) -{ - int delta = 0; - - if (headroom < NET_SKB_PAD) - headroom = NET_SKB_PAD; - if (headroom > skb_headroom(skb)) - delta = headroom - skb_headroom(skb); - - if (delta || cloned) - return pskb_expand_head(skb, ALIGN(delta, NET_SKB_PAD), 0, - GFP_ATOMIC); - return 0; -} - -static inline int skb_cow_head(struct sk_buff *skb, unsigned int headroom) -{ - return __skb_cow(skb, headroom, skb_header_cloned(skb)); -} -#endif /* linux < 2.6.23 */ - - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17) -/* Emulate Linux 2.6.17 and later behavior, in which kfree_skb silently ignores - * null pointer arguments. */ -#define kfree_skb(skb) kfree_skb_maybe_null(skb) -static inline void kfree_skb_maybe_null(struct sk_buff *skb) -{ - if (likely(skb != NULL)) - (kfree_skb)(skb); -} -#endif - - -#ifndef CHECKSUM_PARTIAL -/* Note that CHECKSUM_PARTIAL is not implemented, but this allows us to at - * least test against it: see update_csum() in forward.c. */ -#define CHECKSUM_PARTIAL 3 -#endif -#ifndef CHECKSUM_COMPLETE -#define CHECKSUM_COMPLETE CHECKSUM_HW -#endif - -#ifdef HAVE_MAC_RAW -#define mac_header mac.raw -#define network_header nh.raw -#endif - -#ifndef HAVE_SKBUFF_HEADER_HELPERS -static inline unsigned char *skb_transport_header(const struct sk_buff *skb) -{ - return skb->h.raw; -} - -static inline void skb_reset_transport_header(struct sk_buff *skb) -{ - skb->h.raw = skb->data; -} - -static inline void skb_set_transport_header(struct sk_buff *skb, - const int offset) -{ - skb->h.raw = skb->data + offset; -} - -static inline unsigned char *skb_network_header(const struct sk_buff *skb) -{ - return skb->nh.raw; -} - -static inline void skb_set_network_header(struct sk_buff *skb, const int offset) -{ - skb->nh.raw = skb->data + offset; -} - -static inline unsigned char *skb_mac_header(const struct sk_buff *skb) -{ - return skb->mac.raw; -} - -static inline void skb_reset_mac_header(struct sk_buff *skb) -{ - skb->mac_header = skb->data; -} - -static inline void skb_set_mac_header(struct sk_buff *skb, const int offset) -{ - skb->mac.raw = skb->data + offset; -} - -static inline int skb_transport_offset(const struct sk_buff *skb) -{ - return skb_transport_header(skb) - skb->data; -} - -static inline int skb_network_offset(const struct sk_buff *skb) -{ - return skb_network_header(skb) - skb->data; -} - -static inline void skb_copy_to_linear_data(struct sk_buff *skb, - const void *from, - const unsigned int len) -{ - memcpy(skb->data, from, len); -} -#endif /* !HAVE_SKBUFF_HEADER_HELPERS */ - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/tcp.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/tcp.h deleted file mode 100644 index 6fad1933..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/tcp.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef __LINUX_TCP_WRAPPER_H -#define __LINUX_TCP_WRAPPER_H 1 - -#include_next - -#ifndef HAVE_SKBUFF_HEADER_HELPERS -static inline struct tcphdr *tcp_hdr(const struct sk_buff *skb) -{ - return (struct tcphdr *)skb_transport_header(skb); -} - -static inline unsigned int tcp_hdrlen(const struct sk_buff *skb) -{ - return tcp_hdr(skb)->doff * 4; -} -#endif /* !HAVE_SKBUFF_HEADER_HELPERS */ - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/timer.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/timer.h deleted file mode 100644 index 6c3a9b0f..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/timer.h +++ /dev/null @@ -1,96 +0,0 @@ -#ifndef __LINUX_TIMER_WRAPPER_H -#define __LINUX_TIMER_WRAPPER_H 1 - -#include_next - -#include - -#ifndef RHEL_RELEASE_VERSION -#define RHEL_RELEASE_VERSION(X,Y) ( 0 ) -#endif -#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) && \ - (!defined(RHEL_RELEASE_CODE) || \ - (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(5,1)))) - -extern unsigned long volatile jiffies; - -/** - * __round_jiffies - function to round jiffies to a full second - * @j: the time in (absolute) jiffies that should be rounded - * @cpu: the processor number on which the timeout will happen - * - * __round_jiffies() rounds an absolute time in the future (in jiffies) - * up or down to (approximately) full seconds. This is useful for timers - * for which the exact time they fire does not matter too much, as long as - * they fire approximately every X seconds. - * - * By rounding these timers to whole seconds, all such timers will fire - * at the same time, rather than at various times spread out. The goal - * of this is to have the CPU wake up less, which saves power. - * - * The exact rounding is skewed for each processor to avoid all - * processors firing at the exact same time, which could lead - * to lock contention or spurious cache line bouncing. - * - * The return value is the rounded version of the @j parameter. - */ -static inline unsigned long __round_jiffies(unsigned long j, int cpu) -{ - int rem; - unsigned long original = j; - - /* - * We don't want all cpus firing their timers at once hitting the - * same lock or cachelines, so we skew each extra cpu with an extra - * 3 jiffies. This 3 jiffies came originally from the mm/ code which - * already did this. - * The skew is done by adding 3*cpunr, then round, then subtract this - * extra offset again. - */ - j += cpu * 3; - - rem = j % HZ; - - /* - * If the target jiffie is just after a whole second (which can happen - * due to delays of the timer irq, long irq off times etc etc) then - * we should round down to the whole second, not up. Use 1/4th second - * as cutoff for this rounding as an extreme upper bound for this. - */ - if (rem < HZ/4) /* round down */ - j = j - rem; - else /* round up */ - j = j - rem + HZ; - - /* now that we have rounded, subtract the extra skew again */ - j -= cpu * 3; - - if (j <= jiffies) /* rounding ate our timeout entirely; */ - return original; - return j; -} - - -/** - * round_jiffies - function to round jiffies to a full second - * @j: the time in (absolute) jiffies that should be rounded - * - * round_jiffies() rounds an absolute time in the future (in jiffies) - * up or down to (approximately) full seconds. This is useful for timers - * for which the exact time they fire does not matter too much, as long as - * they fire approximately every X seconds. - * - * By rounding these timers to whole seconds, all such timers will fire - * at the same time, rather than at various times spread out. The goal - * of this is to have the CPU wake up less, which saves power. - * - * The return value is the rounded version of the @j parameter. - */ -static inline unsigned long round_jiffies(unsigned long j) -{ - return __round_jiffies(j, 0); // FIXME -} - -#endif /* linux kernel < 2.6.20 */ - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/types.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/types.h deleted file mode 100644 index c1f375eb..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/types.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef __LINUX_TYPES_WRAPPER_H -#define __LINUX_TYPES_WRAPPER_H 1 - -#include_next - -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) - -typedef __u16 __bitwise __sum16; -typedef __u32 __bitwise __wsum; - -#endif /* linux kernel < 2.6.20 */ - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/udp.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/udp.h deleted file mode 100644 index 6fe4721b..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/udp.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef __LINUX_UDP_WRAPPER_H -#define __LINUX_UDP_WRAPPER_H 1 - -#include_next - -#ifndef HAVE_SKBUFF_HEADER_HELPERS -static inline struct udphdr *udp_hdr(const struct sk_buff *skb) -{ - return (struct udphdr *)skb_transport_header(skb); -} -#endif /* HAVE_SKBUFF_HEADER_HELPERS */ - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/workqueue.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/workqueue.h deleted file mode 100644 index 1ac3b6ec..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/workqueue.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef __LINUX_WORKQUEUE_WRAPPER_H -#define __LINUX_WORKQUEUE_WRAPPER_H 1 - -#include_next - -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) - -#ifdef __KERNEL__ -/* - * initialize a work-struct's func and data pointers: - */ -#undef PREPARE_WORK -#define PREPARE_WORK(_work, _func) \ - do { \ - (_work)->func = (void(*)(void*)) _func; \ - (_work)->data = _work; \ - } while (0) - -/* - * initialize all of a work-struct: - */ -#undef INIT_WORK -#define INIT_WORK(_work, _func) \ - do { \ - INIT_LIST_HEAD(&(_work)->entry); \ - (_work)->pending = 0; \ - PREPARE_WORK((_work), (_func)); \ - init_timer(&(_work)->timer); \ - } while (0) - -#endif /* __KERNEL__ */ - -#endif /* linux kernel < 2.6.20 */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) -/* There is no equivalent to cancel_work_sync() so just flush all - * pending work. */ -#define cancel_work_sync(_work) flush_scheduled_work() -#endif - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/net/checksum.h b/openflow/datapath/linux-2.6/compat-2.6/include/net/checksum.h deleted file mode 100644 index c64c6bd0..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/net/checksum.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef __NET_CHECKSUM_WRAPPER_H -#define __NET_CHECKSUM_WRAPPER_H 1 - -#include_next - -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) - -static inline __wsum csum_unfold(__sum16 n) -{ - return (__force __wsum)n; -} - -#endif /* linux kernel < 2.6.20 */ - -#endif /* checksum.h */ diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/net/genetlink.h b/openflow/datapath/linux-2.6/compat-2.6/include/net/genetlink.h deleted file mode 100644 index 57a47316..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/net/genetlink.h +++ /dev/null @@ -1,123 +0,0 @@ -#ifndef __NET_GENERIC_NETLINK_WRAPPER_H -#define __NET_GENERIC_NETLINK_WRAPPER_H 1 - - -#include -#include_next - -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) - -#include - -/*---------------------------------------------------------------------------- - * In 2.6.23, registering of multicast groups was added. Our compatability - * layer just supports registering a single group, since that's all we - * need. - */ - -/** - * struct genl_multicast_group - generic netlink multicast group - * @name: name of the multicast group, names are per-family - * @id: multicast group ID, assigned by the core, to use with - * genlmsg_multicast(). - * @list: list entry for linking - * @family: pointer to family, need not be set before registering - */ -struct genl_multicast_group -{ - struct genl_family *family; /* private */ - struct list_head list; /* private */ - char name[GENL_NAMSIZ]; - u32 id; -}; - -int genl_register_mc_group(struct genl_family *family, - struct genl_multicast_group *grp); -#endif /* linux kernel < 2.6.23 */ - - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) -/** - * genlmsg_msg_size - length of genetlink message not including padding - * @payload: length of message payload - */ -static inline int genlmsg_msg_size(int payload) -{ - return GENL_HDRLEN + payload; -} - -/** - * genlmsg_total_size - length of genetlink message including padding - * @payload: length of message payload - */ -static inline int genlmsg_total_size(int payload) -{ - return NLMSG_ALIGN(genlmsg_msg_size(payload)); -} - -#define genlmsg_multicast(s, p, g, f) \ - genlmsg_multicast_flags((s), (p), (g), (f)) - -static inline int genlmsg_multicast_flags(struct sk_buff *skb, u32 pid, - unsigned int group, gfp_t flags) -{ - int err; - - NETLINK_CB(skb).dst_group = group; - - err = netlink_broadcast(genl_sock, skb, pid, group, flags); - if (err > 0) - err = 0; - - return err; -} -#endif /* linux kernel < 2.6.19 */ - - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) - -#define genlmsg_put(skb, p, seq, fam, flg, c) \ - genlmsg_put((skb), (p), (seq), (fam)->id, (fam)->hdrsize, \ - (flg), (c), (fam)->version) - -/** - * genlmsg_put_reply - Add generic netlink header to a reply message - * @skb: socket buffer holding the message - * @info: receiver info - * @family: generic netlink family - * @flags: netlink message flags - * @cmd: generic netlink command - * - * Returns pointer to user specific header - */ -static inline void *genlmsg_put_reply(struct sk_buff *skb, - struct genl_info *info, struct genl_family *family, - int flags, u8 cmd) -{ - return genlmsg_put(skb, info->snd_pid, info->snd_seq, family, - flags, cmd); -} - -/** - * genlmsg_reply - reply to a request - * @skb: netlink message to be sent back - * @info: receiver information - */ -static inline int genlmsg_reply(struct sk_buff *skb, struct genl_info *info) -{ - return genlmsg_unicast(skb, info->snd_pid); -} - -/** - * genlmsg_new - Allocate a new generic netlink message - * @payload: size of the message payload - * @flags: the type of memory to allocate. - */ -static inline struct sk_buff *genlmsg_new(size_t payload, gfp_t flags) -{ - return nlmsg_new(genlmsg_total_size(payload), flags); -} -#endif /* linux kernel < 2.6.20 */ - -#endif /* genetlink.h */ diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/net/netlink.h b/openflow/datapath/linux-2.6/compat-2.6/include/net/netlink.h deleted file mode 100644 index e0d594d7..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/net/netlink.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef __NET_NETLINK_WRAPPER_H -#define __NET_NETLINK_WRAPPER_H 1 - -#include_next - -#ifndef HAVE_NLA_NUL_STRING -#define NLA_NUL_STRING NLA_STRING - -static inline int VERIFY_NUL_STRING(struct nlattr *attr) -{ - return (!attr || (nla_len(attr) - && memchr(nla_data(attr), '\0', nla_len(attr))) - ? 0 : EINVAL); -} -#else -static inline int VERIFY_NUL_STRING(struct nlattr *attr) -{ - return 0; -} -#endif /* !HAVE_NLA_NUL_STRING */ - -#endif /* net/netlink.h */ diff --git a/openflow/datapath/linux-2.6/compat-2.6/random32.c b/openflow/datapath/linux-2.6/compat-2.6/random32.c deleted file mode 100644 index 981b55c1..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/random32.c +++ /dev/null @@ -1,146 +0,0 @@ -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) - -/* - This is a maximally equidistributed combined Tausworthe generator - based on code from GNU Scientific Library 1.5 (30 Jun 2004) - - x_n = (s1_n ^ s2_n ^ s3_n) - - s1_{n+1} = (((s1_n & 4294967294) <<12) ^ (((s1_n <<13) ^ s1_n) >>19)) - s2_{n+1} = (((s2_n & 4294967288) << 4) ^ (((s2_n << 2) ^ s2_n) >>25)) - s3_{n+1} = (((s3_n & 4294967280) <<17) ^ (((s3_n << 3) ^ s3_n) >>11)) - - The period of this generator is about 2^88. - - From: P. L'Ecuyer, "Maximally Equidistributed Combined Tausworthe - Generators", Mathematics of Computation, 65, 213 (1996), 203--213. - - This is available on the net from L'Ecuyer's home page, - - http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme.ps - ftp://ftp.iro.umontreal.ca/pub/simulation/lecuyer/papers/tausme.ps - - There is an erratum in the paper "Tables of Maximally - Equidistributed Combined LFSR Generators", Mathematics of - Computation, 68, 225 (1999), 261--269: - http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme2.ps - - ... the k_j most significant bits of z_j must be non- - zero, for each j. (Note: this restriction also applies to the - computer code given in [4], but was mistakenly not mentioned in - that paper.) - - This affects the seeding procedure by imposing the requirement - s1 > 1, s2 > 7, s3 > 15. - -*/ - -#include -#include -#include -#include -#include - -#include "compat26.h" - -struct rnd_state { - u32 s1, s2, s3; -}; - -static struct rnd_state net_rand_state[NR_CPUS]; - -static u32 __random32(struct rnd_state *state) -{ -#define TAUSWORTHE(s,a,b,c,d) ((s&c)<>b) - - state->s1 = TAUSWORTHE(state->s1, 13, 19, 4294967294UL, 12); - state->s2 = TAUSWORTHE(state->s2, 2, 25, 4294967288UL, 4); - state->s3 = TAUSWORTHE(state->s3, 3, 11, 4294967280UL, 17); - - return (state->s1 ^ state->s2 ^ state->s3); -} - -static void __set_random32(struct rnd_state *state, unsigned long s) -{ - if (s == 0) - s = 1; /* default seed is 1 */ - -#define LCG(n) (69069 * n) - state->s1 = LCG(s); - state->s2 = LCG(state->s1); - state->s3 = LCG(state->s2); - - /* "warm it up" */ - __random32(state); - __random32(state); - __random32(state); - __random32(state); - __random32(state); - __random32(state); -} - -/** - * random32 - pseudo random number generator - * - * A 32 bit pseudo-random number is generated using a fast - * algorithm suitable for simulation. This algorithm is NOT - * considered safe for cryptographic use. - */ -u32 random32(void) -{ - return __random32(&net_rand_state[smp_processor_id()]); -} -EXPORT_SYMBOL(random32); - -/** - * srandom32 - add entropy to pseudo random number generator - * @seed: seed value - * - * Add some additional seeding to the random32() pool. - * Note: this pool is per cpu so it only affects current CPU. - */ -void srandom32(u32 entropy) -{ - struct rnd_state *state = &net_rand_state[smp_processor_id()]; - __set_random32(state, state->s1 ^ entropy); -} -EXPORT_SYMBOL(srandom32); - -static int __init random32_reseed(void); - -/* - * Generate some initially weak seeding values to allow - * to start the random32() engine. - */ -int __init random32_init(void) -{ - int i; - - for (i = 0; i < NR_CPUS; i++) { - struct rnd_state *state = &net_rand_state[i]; - __set_random32(state, i + jiffies); - } - random32_reseed(); - return 0; -} - -/* - * Generate better values after random number generator - * is fully initalized. - */ -static int __init random32_reseed(void) -{ - int i; - unsigned long seed; - - for (i = 0; i < NR_CPUS; i++) { - struct rnd_state *state = &net_rand_state[i]; - - get_random_bytes(&seed, sizeof(seed)); - __set_random32(state, seed); - } - return 0; -} - -#endif /* kernel < 2.6.19 */ diff --git a/openflow/datapath/linux-2.6/compat-2.6/veth.c b/openflow/datapath/linux-2.6/compat-2.6/veth.c deleted file mode 100644 index 3cda3365..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/veth.c +++ /dev/null @@ -1,537 +0,0 @@ -/* veth driver port to Linux 2.6.18 */ - -/* - * drivers/net/veth.c - * - * Copyright (C) 2007, 2009 OpenVZ http://openvz.org, SWsoft Inc - * - * Author: Pavel Emelianov - * Ethtool interface from: Eric W. Biederman - * - */ - -#include -#include -#include -#include - -#include -#include - -#define DRV_NAME "veth" -#define DRV_VERSION "1.0" - -struct veth_net_stats { - unsigned long rx_packets; - unsigned long tx_packets; - unsigned long rx_bytes; - unsigned long tx_bytes; - unsigned long tx_dropped; -}; - -struct veth_priv { - struct net_device *peer; - struct net_device *dev; - struct list_head list; - struct veth_net_stats *stats; - unsigned ip_summed; - struct net_device_stats dev_stats; -}; - -static LIST_HEAD(veth_list); - -/* - * ethtool interface - */ - -static struct { - const char string[ETH_GSTRING_LEN]; -} ethtool_stats_keys[] = { - { "peer_ifindex" }, -}; - -static int veth_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - cmd->supported = 0; - cmd->advertising = 0; - cmd->speed = SPEED_10000; - cmd->duplex = DUPLEX_FULL; - cmd->port = PORT_TP; - cmd->phy_address = 0; - cmd->transceiver = XCVR_INTERNAL; - cmd->autoneg = AUTONEG_DISABLE; - cmd->maxtxpkt = 0; - cmd->maxrxpkt = 0; - return 0; -} - -static void veth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) -{ - strcpy(info->driver, DRV_NAME); - strcpy(info->version, DRV_VERSION); - strcpy(info->fw_version, "N/A"); -} - -static void veth_get_strings(struct net_device *dev, u32 stringset, u8 *buf) -{ - switch(stringset) { - case ETH_SS_STATS: - memcpy(buf, ðtool_stats_keys, sizeof(ethtool_stats_keys)); - break; - } -} - -static void veth_get_ethtool_stats(struct net_device *dev, - struct ethtool_stats *stats, u64 *data) -{ - struct veth_priv *priv; - - priv = netdev_priv(dev); - data[0] = priv->peer->ifindex; -} - -static u32 veth_get_rx_csum(struct net_device *dev) -{ - struct veth_priv *priv; - - priv = netdev_priv(dev); - return priv->ip_summed == CHECKSUM_UNNECESSARY; -} - -static int veth_set_rx_csum(struct net_device *dev, u32 data) -{ - struct veth_priv *priv; - - priv = netdev_priv(dev); - priv->ip_summed = data ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE; - return 0; -} - -static u32 veth_get_tx_csum(struct net_device *dev) -{ - return (dev->features & NETIF_F_NO_CSUM) != 0; -} - -static int veth_set_tx_csum(struct net_device *dev, u32 data) -{ - if (data) - dev->features |= NETIF_F_NO_CSUM; - else - dev->features &= ~NETIF_F_NO_CSUM; - return 0; -} - -static struct ethtool_ops veth_ethtool_ops = { - .get_settings = veth_get_settings, - .get_drvinfo = veth_get_drvinfo, - .get_link = ethtool_op_get_link, - .get_rx_csum = veth_get_rx_csum, - .set_rx_csum = veth_set_rx_csum, - .get_tx_csum = veth_get_tx_csum, - .set_tx_csum = veth_set_tx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_strings = veth_get_strings, - .get_ethtool_stats = veth_get_ethtool_stats, -}; - -/* - * xmit - */ - -static int veth_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct net_device *rcv = NULL; - struct veth_priv *priv, *rcv_priv; - struct veth_net_stats *stats; - int length, cpu; - - skb_orphan(skb); - - priv = netdev_priv(dev); - rcv = priv->peer; - rcv_priv = netdev_priv(rcv); - - cpu = smp_processor_id(); - stats = per_cpu_ptr(priv->stats, cpu); - - if (!(rcv->flags & IFF_UP)) - goto outf; - - skb->dev = rcv; - skb->pkt_type = PACKET_HOST; - skb->protocol = eth_type_trans(skb, rcv); - if (dev->features & NETIF_F_NO_CSUM) - skb->ip_summed = rcv_priv->ip_summed; - - dst_release(skb->dst); - skb->dst = NULL; - secpath_reset(skb); - nf_reset(skb); - - length = skb->len; - - stats->tx_bytes += length; - stats->tx_packets++; - - stats = per_cpu_ptr(rcv_priv->stats, cpu); - stats->rx_bytes += length; - stats->rx_packets++; - - netif_rx(skb); - return 0; - -outf: - kfree_skb(skb); - stats->tx_dropped++; - return 0; -} - -/* - * general routines - */ - -static struct net_device_stats *veth_get_stats(struct net_device *dev) -{ - struct veth_priv *priv; - struct net_device_stats *dev_stats; - int cpu; - struct veth_net_stats *stats; - - priv = netdev_priv(dev); - dev_stats = &priv->dev_stats; - - dev_stats->rx_packets = 0; - dev_stats->tx_packets = 0; - dev_stats->rx_bytes = 0; - dev_stats->tx_bytes = 0; - dev_stats->tx_dropped = 0; - - for_each_online_cpu(cpu) { - stats = per_cpu_ptr(priv->stats, cpu); - - dev_stats->rx_packets += stats->rx_packets; - dev_stats->tx_packets += stats->tx_packets; - dev_stats->rx_bytes += stats->rx_bytes; - dev_stats->tx_bytes += stats->tx_bytes; - dev_stats->tx_dropped += stats->tx_dropped; - } - - return dev_stats; -} - -static int veth_open(struct net_device *dev) -{ - struct veth_priv *priv; - - priv = netdev_priv(dev); - if (priv->peer == NULL) - return -ENOTCONN; - - if (priv->peer->flags & IFF_UP) { - netif_carrier_on(dev); - netif_carrier_on(priv->peer); - } - return 0; -} - -static int veth_dev_init(struct net_device *dev) -{ - struct veth_net_stats *stats; - struct veth_priv *priv; - - stats = alloc_percpu(struct veth_net_stats); - if (stats == NULL) - return -ENOMEM; - - priv = netdev_priv(dev); - priv->stats = stats; - return 0; -} - -static void veth_dev_free(struct net_device *dev) -{ - struct veth_priv *priv; - - priv = netdev_priv(dev); - free_percpu(priv->stats); - free_netdev(dev); -} - -static void veth_setup(struct net_device *dev) -{ - ether_setup(dev); - - dev->hard_start_xmit = veth_xmit; - dev->get_stats = veth_get_stats; - dev->open = veth_open; - dev->ethtool_ops = &veth_ethtool_ops; - dev->features |= NETIF_F_LLTX; - dev->init = veth_dev_init; - dev->destructor = veth_dev_free; -} - -static void veth_change_state(struct net_device *dev) -{ - struct net_device *peer; - struct veth_priv *priv; - - priv = netdev_priv(dev); - peer = priv->peer; - - if (netif_carrier_ok(peer)) { - if (!netif_carrier_ok(dev)) - netif_carrier_on(dev); - } else { - if (netif_carrier_ok(dev)) - netif_carrier_off(dev); - } -} - -static int veth_device_event(struct notifier_block *unused, - unsigned long event, void *ptr) -{ - struct net_device *dev = ptr; - - if (dev->open != veth_open) - goto out; - - switch (event) { - case NETDEV_CHANGE: - veth_change_state(dev); - break; - } -out: - return NOTIFY_DONE; -} - -static struct notifier_block veth_notifier_block __read_mostly = { - .notifier_call = veth_device_event, -}; - -/* - * netlink interface - */ - -static int veth_newlink(const char *devname, const char *peername) -{ - int err; - const char *names[2]; - struct net_device *devs[2]; - int i; - - names[0] = devname; - names[1] = peername; - devs[0] = devs[1] = NULL; - - for (i = 0; i < 2; i++) { - struct net_device *dev; - - err = -ENOMEM; - devs[i] = alloc_netdev(sizeof(struct veth_priv), - names[i], veth_setup); - if (!devs[i]) { - goto err; - } - - dev = devs[i]; - - if (strchr(dev->name, '%')) { - err = dev_alloc_name(dev, dev->name); - if (err < 0) - goto err; - } - random_ether_addr(dev->dev_addr); - - err = register_netdevice(dev); - if (err < 0) - goto err; - - netif_carrier_off(dev); - } - - /* - * tie the devices together - */ - - for (i = 0; i < 2; i++) { - struct veth_priv *priv = netdev_priv(devs[i]); - priv->dev = devs[i]; - priv->peer = devs[!i]; - if (!i) - list_add(&priv->list, &veth_list); - else - INIT_LIST_HEAD(&priv->list); - } - return 0; - -err: - for (i = 0; i < 2; i++) { - if (devs[i]) { - if (devs[i]->reg_state != NETREG_UNINITIALIZED) - unregister_netdevice(devs[i]); - else - free_netdev(devs[i]); - } - } - return err; -} - -static void veth_dellink(struct net_device *dev) -{ - struct veth_priv *priv; - struct net_device *peer; - - priv = netdev_priv(dev); - peer = priv->peer; - - if (!list_empty(&priv->list)) - list_del(&priv->list); - - priv = netdev_priv(peer); - if (!list_empty(&priv->list)) - list_del(&priv->list); - - unregister_netdevice(dev); - unregister_netdevice(peer); -} - -/* - * sysfs - */ - -/* - * "show" function for the veth_pairs attribute. - * The class parameter is ignored. - */ -static ssize_t veth_show_veth_pairs(struct class *cls, char *buffer) -{ - int res = 0; - struct veth_priv *priv; - - list_for_each_entry(priv, &veth_list, list) { - if (res > (PAGE_SIZE - (IFNAMSIZ * 2 + 1))) { - /* not enough space for another interface name */ - if ((PAGE_SIZE - res) > 10) - res = PAGE_SIZE - 10; - res += sprintf(buffer + res, "++more++"); - break; - } - res += sprintf(buffer + res, "%s,%s ", - priv->dev->name, priv->peer->name); - } - res += sprintf(buffer + res, "\n"); - res++; - return res; -} - -/* - * "store" function for the veth_pairs attribute. This is what - * creates and deletes veth pairs. - * - * The class parameter is ignored. - * - */ -static ssize_t veth_store_veth_pairs(struct class *cls, const char *buffer, - size_t count) -{ - int c = *buffer++; - int retval; - printk("1\n"); - if (c == '+') { - char devname[IFNAMSIZ + 1] = ""; - char peername[IFNAMSIZ + 1] = ""; - char *comma = strchr(buffer, ','); - printk("2\n"); - if (!comma) - goto err_no_cmd; - strncat(devname, buffer, - min_t(int, sizeof devname, comma - buffer)); - strncat(peername, comma + 1, - min_t(int, sizeof peername, strcspn(comma + 1, "\n"))); - printk("3 '%s' '%s'\n", devname, peername); - if (!dev_valid_name(devname) || !dev_valid_name(peername)) - goto err_no_cmd; - printk("4\n"); - rtnl_lock(); - retval = veth_newlink(devname, peername); - rtnl_unlock(); - return retval ? retval : count; - } else if (c == '-') { - struct net_device *dev; - - rtnl_lock(); - dev = dev_get_by_name(buffer); - if (!dev) - retval = -ENODEV; - else if (dev->init != veth_dev_init) - retval = -EINVAL; - else { - veth_dellink(dev); - retval = count; - } - rtnl_unlock(); - - return retval; - } - -err_no_cmd: - printk(KERN_ERR DRV_NAME ": no command found in veth_pairs. Use +ifname,peername or -ifname.\n"); - return -EPERM; -} - -/* class attribute for veth_pairs file. This ends up in /sys/class/net */ -static CLASS_ATTR(veth_pairs, S_IWUSR | S_IRUGO, - veth_show_veth_pairs, veth_store_veth_pairs); - -static struct class *netdev_class; - -/* - * Initialize sysfs. This sets up the veth_pairs file in - * /sys/class/net. - */ -int veth_create_sysfs(void) -{ - struct net_device *dev = dev_get_by_name("lo"); - if (!dev) - return -ESRCH; - netdev_class = dev->class_dev.class; - if (!netdev_class) - return -ENODEV; - - return class_create_file(netdev_class, &class_attr_veth_pairs); -} - -/* - * Remove /sys/class/net/veth_pairs. - */ -void veth_destroy_sysfs(void) -{ - class_remove_file(netdev_class, &class_attr_veth_pairs); -} - - - -/* - * init/fini - */ - -static __init int veth_init(void) -{ - int retval = veth_create_sysfs(); - if (retval) - return retval; - register_netdevice_notifier(&veth_notifier_block); - return 0; -} - -static __exit void veth_exit(void) -{ - unregister_netdevice_notifier(&veth_notifier_block); -} - -module_init(veth_init); -module_exit(veth_exit); - -MODULE_DESCRIPTION("Virtual Ethernet Tunnel"); -MODULE_LICENSE("GPL v2"); diff --git a/openflow/datapath/linux-2.6/config/config-linux-2.6.23-rc9-kvm b/openflow/datapath/linux-2.6/config/config-linux-2.6.23-rc9-kvm deleted file mode 100644 index f287cf72..00000000 --- a/openflow/datapath/linux-2.6/config/config-linux-2.6.23-rc9-kvm +++ /dev/null @@ -1,1408 +0,0 @@ -# -# Automatically generated make config: don't edit -# Linux kernel version: 2.6.23-rc9 -# Fri Oct 19 15:08:37 2007 -# -CONFIG_X86_32=y -CONFIG_GENERIC_TIME=y -CONFIG_GENERIC_CMOS_UPDATE=y -CONFIG_CLOCKSOURCE_WATCHDOG=y -CONFIG_GENERIC_CLOCKEVENTS=y -CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y -CONFIG_LOCKDEP_SUPPORT=y -CONFIG_STACKTRACE_SUPPORT=y -CONFIG_SEMAPHORE_SLEEPERS=y -CONFIG_X86=y -CONFIG_MMU=y -CONFIG_ZONE_DMA=y -CONFIG_QUICKLIST=y -CONFIG_GENERIC_ISA_DMA=y -CONFIG_GENERIC_IOMAP=y -CONFIG_GENERIC_BUG=y -CONFIG_GENERIC_HWEIGHT=y -CONFIG_ARCH_MAY_HAVE_PC_FDC=y -CONFIG_DMI=y -CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" - -# -# General setup -# -CONFIG_EXPERIMENTAL=y -CONFIG_LOCK_KERNEL=y -CONFIG_INIT_ENV_ARG_LIMIT=32 -CONFIG_LOCALVERSION="" -# CONFIG_LOCALVERSION_AUTO is not set -CONFIG_SWAP=y -CONFIG_SYSVIPC=y -CONFIG_SYSVIPC_SYSCTL=y -CONFIG_POSIX_MQUEUE=y -CONFIG_BSD_PROCESS_ACCT=y -# CONFIG_BSD_PROCESS_ACCT_V3 is not set -CONFIG_TASKSTATS=y -CONFIG_TASK_DELAY_ACCT=y -CONFIG_TASK_XACCT=y -CONFIG_TASK_IO_ACCOUNTING=y -# CONFIG_USER_NS is not set -# CONFIG_AUDIT is not set -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -CONFIG_LOG_BUF_SHIFT=14 -# CONFIG_CPUSETS is not set -CONFIG_SYSFS_DEPRECATED=y -CONFIG_RELAY=y -CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="" -CONFIG_CC_OPTIMIZE_FOR_SIZE=y -CONFIG_SYSCTL=y -# CONFIG_EMBEDDED is not set -CONFIG_UID16=y -CONFIG_SYSCTL_SYSCALL=y -CONFIG_KALLSYMS=y -CONFIG_KALLSYMS_ALL=y -CONFIG_KALLSYMS_EXTRA_PASS=y -CONFIG_HOTPLUG=y -CONFIG_PRINTK=y -CONFIG_BUG=y -CONFIG_ELF_CORE=y -CONFIG_BASE_FULL=y -CONFIG_FUTEX=y -CONFIG_ANON_INODES=y -CONFIG_EPOLL=y -CONFIG_SIGNALFD=y -CONFIG_EVENTFD=y -CONFIG_SHMEM=y -CONFIG_VM_EVENT_COUNTERS=y -CONFIG_SLAB=y -# CONFIG_SLUB is not set -# CONFIG_SLOB is not set -CONFIG_RT_MUTEXES=y -# CONFIG_TINY_SHMEM is not set -CONFIG_BASE_SMALL=0 -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_MODULE_FORCE_UNLOAD is not set -# CONFIG_MODVERSIONS is not set -# CONFIG_MODULE_SRCVERSION_ALL is not set -CONFIG_KMOD=y -CONFIG_STOP_MACHINE=y -CONFIG_BLOCK=y -CONFIG_LBD=y -CONFIG_BLK_DEV_IO_TRACE=y -CONFIG_LSF=y -# CONFIG_BLK_DEV_BSG is not set - -# -# IO Schedulers -# -CONFIG_IOSCHED_NOOP=y -CONFIG_IOSCHED_AS=y -CONFIG_IOSCHED_DEADLINE=y -CONFIG_IOSCHED_CFQ=y -CONFIG_DEFAULT_AS=y -# CONFIG_DEFAULT_DEADLINE is not set -# CONFIG_DEFAULT_CFQ is not set -# CONFIG_DEFAULT_NOOP is not set -CONFIG_DEFAULT_IOSCHED="anticipatory" - -# -# Processor type and features -# -# CONFIG_TICK_ONESHOT is not set -# CONFIG_NO_HZ is not set -# CONFIG_HIGH_RES_TIMERS is not set -CONFIG_SMP=y -CONFIG_X86_PC=y -# CONFIG_X86_ELAN is not set -# CONFIG_X86_VOYAGER is not set -# CONFIG_X86_NUMAQ is not set -# CONFIG_X86_SUMMIT is not set -# CONFIG_X86_BIGSMP is not set -# CONFIG_X86_VISWS is not set -# CONFIG_X86_GENERICARCH is not set -# CONFIG_X86_ES7000 is not set -# CONFIG_PARAVIRT is not set -# CONFIG_M386 is not set -CONFIG_M486=y -# CONFIG_M586 is not set -# CONFIG_M586TSC is not set -# CONFIG_M586MMX is not set -# CONFIG_M686 is not set -# CONFIG_MPENTIUMII is not set -# CONFIG_MPENTIUMIII is not set -# CONFIG_MPENTIUMM is not set -# CONFIG_MCORE2 is not set -# CONFIG_MPENTIUM4 is not set -# CONFIG_MK6 is not set -# CONFIG_MK7 is not set -# CONFIG_MK8 is not set -# CONFIG_MCRUSOE is not set -# CONFIG_MEFFICEON is not set -# CONFIG_MWINCHIPC6 is not set -# CONFIG_MWINCHIP2 is not set -# CONFIG_MWINCHIP3D is not set -# CONFIG_MGEODEGX1 is not set -# CONFIG_MGEODE_LX is not set -# CONFIG_MCYRIXIII is not set -# CONFIG_MVIAC3_2 is not set -# CONFIG_MVIAC7 is not set -CONFIG_X86_GENERIC=y -CONFIG_X86_CMPXCHG=y -CONFIG_X86_L1_CACHE_SHIFT=7 -CONFIG_X86_XADD=y -CONFIG_RWSEM_XCHGADD_ALGORITHM=y -# CONFIG_ARCH_HAS_ILOG2_U32 is not set -# CONFIG_ARCH_HAS_ILOG2_U64 is not set -CONFIG_GENERIC_CALIBRATE_DELAY=y -CONFIG_X86_PPRO_FENCE=y -CONFIG_X86_F00F_BUG=y -CONFIG_X86_WP_WORKS_OK=y -CONFIG_X86_INVLPG=y -CONFIG_X86_BSWAP=y -CONFIG_X86_POPAD_OK=y -CONFIG_X86_ALIGNMENT_16=y -CONFIG_X86_INTEL_USERCOPY=y -CONFIG_X86_MINIMUM_CPU_FAMILY=4 -# CONFIG_HPET_TIMER is not set -CONFIG_NR_CPUS=8 -# CONFIG_SCHED_SMT is not set -CONFIG_SCHED_MC=y -CONFIG_PREEMPT_NONE=y -# CONFIG_PREEMPT_VOLUNTARY is not set -# CONFIG_PREEMPT is not set -CONFIG_PREEMPT_BKL=y -CONFIG_X86_LOCAL_APIC=y -CONFIG_X86_IO_APIC=y -# CONFIG_X86_MCE is not set -CONFIG_VM86=y -# CONFIG_TOSHIBA is not set -# CONFIG_I8K is not set -# CONFIG_X86_REBOOTFIXUPS is not set -# CONFIG_MICROCODE is not set -# CONFIG_X86_MSR is not set -# CONFIG_X86_CPUID is not set - -# -# Firmware Drivers -# -# CONFIG_EDD is not set -# CONFIG_DELL_RBU is not set -# CONFIG_DCDBAS is not set -CONFIG_DMIID=y -# CONFIG_NOHIGHMEM is not set -CONFIG_HIGHMEM4G=y -# CONFIG_HIGHMEM64G is not set -CONFIG_PAGE_OFFSET=0xC0000000 -CONFIG_HIGHMEM=y -CONFIG_ARCH_FLATMEM_ENABLE=y -CONFIG_ARCH_SPARSEMEM_ENABLE=y -CONFIG_ARCH_SELECT_MEMORY_MODEL=y -CONFIG_ARCH_POPULATES_NODE_MAP=y -CONFIG_SELECT_MEMORY_MODEL=y -CONFIG_FLATMEM_MANUAL=y -# CONFIG_DISCONTIGMEM_MANUAL is not set -# CONFIG_SPARSEMEM_MANUAL is not set -CONFIG_FLATMEM=y -CONFIG_FLAT_NODE_MEM_MAP=y -CONFIG_SPARSEMEM_STATIC=y -CONFIG_SPLIT_PTLOCK_CPUS=4 -# CONFIG_RESOURCES_64BIT is not set -CONFIG_ZONE_DMA_FLAG=1 -CONFIG_BOUNCE=y -CONFIG_NR_QUICK=1 -CONFIG_VIRT_TO_BUS=y -# CONFIG_HIGHPTE is not set -# CONFIG_MATH_EMULATION is not set -# CONFIG_MTRR is not set -CONFIG_IRQBALANCE=y -CONFIG_SECCOMP=y -# CONFIG_HZ_100 is not set -CONFIG_HZ_250=y -# CONFIG_HZ_300 is not set -# CONFIG_HZ_1000 is not set -CONFIG_HZ=250 -# CONFIG_KEXEC is not set -# CONFIG_CRASH_DUMP is not set -CONFIG_PHYSICAL_START=0x100000 -# CONFIG_RELOCATABLE is not set -CONFIG_PHYSICAL_ALIGN=0x100000 -CONFIG_HOTPLUG_CPU=y -CONFIG_COMPAT_VDSO=y -CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y - -# -# Power management options (ACPI, APM) -# -CONFIG_PM=y -# CONFIG_PM_LEGACY is not set -# CONFIG_PM_DEBUG is not set -CONFIG_PM_SLEEP_SMP=y -CONFIG_PM_SLEEP=y -CONFIG_SUSPEND_SMP_POSSIBLE=y -CONFIG_SUSPEND=y -CONFIG_HIBERNATION_SMP_POSSIBLE=y -# CONFIG_HIBERNATION is not set -# CONFIG_ACPI is not set -CONFIG_APM=y -# CONFIG_APM_IGNORE_USER_SUSPEND is not set -# CONFIG_APM_DO_ENABLE is not set -# CONFIG_APM_CPU_IDLE is not set -# CONFIG_APM_DISPLAY_BLANK is not set -# CONFIG_APM_ALLOW_INTS is not set -# CONFIG_APM_REAL_MODE_POWER_OFF is not set - -# -# CPU Frequency scaling -# -# CONFIG_CPU_FREQ is not set - -# -# Bus options (PCI, PCMCIA, EISA, MCA, ISA) -# -CONFIG_PCI=y -# CONFIG_PCI_GOBIOS is not set -# CONFIG_PCI_GOMMCONFIG is not set -# CONFIG_PCI_GODIRECT is not set -CONFIG_PCI_GOANY=y -CONFIG_PCI_BIOS=y -CONFIG_PCI_DIRECT=y -# CONFIG_PCIEPORTBUS is not set -CONFIG_ARCH_SUPPORTS_MSI=y -# CONFIG_PCI_MSI is not set -# CONFIG_PCI_DEBUG is not set -CONFIG_HT_IRQ=y -CONFIG_ISA_DMA_API=y -CONFIG_ISA=y -# CONFIG_EISA is not set -# CONFIG_MCA is not set -# CONFIG_SCx200 is not set - -# -# PCCARD (PCMCIA/CardBus) support -# -# CONFIG_PCCARD is not set -# CONFIG_HOTPLUG_PCI is not set - -# -# Executable file formats -# -CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_AOUT is not set -CONFIG_BINFMT_MISC=m - -# -# Networking -# -CONFIG_NET=y - -# -# Networking options -# -CONFIG_PACKET=y -CONFIG_PACKET_MMAP=y -CONFIG_UNIX=y -CONFIG_XFRM=y -CONFIG_XFRM_USER=m -CONFIG_XFRM_SUB_POLICY=y -CONFIG_XFRM_MIGRATE=y -CONFIG_NET_KEY=m -CONFIG_NET_KEY_MIGRATE=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_ADVANCED_ROUTER=y -CONFIG_ASK_IP_FIB_HASH=y -# CONFIG_IP_FIB_TRIE is not set -CONFIG_IP_FIB_HASH=y -CONFIG_IP_MULTIPLE_TABLES=y -CONFIG_IP_ROUTE_MULTIPATH=y -# CONFIG_IP_ROUTE_VERBOSE is not set -# CONFIG_IP_PNP is not set -CONFIG_NET_IPIP=m -CONFIG_NET_IPGRE=m -CONFIG_NET_IPGRE_BROADCAST=y -CONFIG_IP_MROUTE=y -CONFIG_IP_PIMSM_V1=y -CONFIG_IP_PIMSM_V2=y -# CONFIG_ARPD is not set -CONFIG_SYN_COOKIES=y -CONFIG_INET_AH=m -CONFIG_INET_ESP=m -CONFIG_INET_IPCOMP=m -CONFIG_INET_XFRM_TUNNEL=m -CONFIG_INET_TUNNEL=m -CONFIG_INET_XFRM_MODE_TRANSPORT=m -CONFIG_INET_XFRM_MODE_TUNNEL=m -CONFIG_INET_XFRM_MODE_BEET=m -CONFIG_INET_DIAG=y -CONFIG_INET_TCP_DIAG=y -CONFIG_TCP_CONG_ADVANCED=y -CONFIG_TCP_CONG_BIC=m -CONFIG_TCP_CONG_CUBIC=y -CONFIG_TCP_CONG_WESTWOOD=m -CONFIG_TCP_CONG_HTCP=m -CONFIG_TCP_CONG_HSTCP=m -CONFIG_TCP_CONG_HYBLA=m -CONFIG_TCP_CONG_VEGAS=m -CONFIG_TCP_CONG_SCALABLE=m -CONFIG_TCP_CONG_LP=m -CONFIG_TCP_CONG_VENO=m -CONFIG_TCP_CONG_YEAH=m -CONFIG_TCP_CONG_ILLINOIS=m -# CONFIG_DEFAULT_BIC is not set -CONFIG_DEFAULT_CUBIC=y -# CONFIG_DEFAULT_HTCP is not set -# CONFIG_DEFAULT_VEGAS is not set -# CONFIG_DEFAULT_WESTWOOD is not set -# CONFIG_DEFAULT_RENO is not set -CONFIG_DEFAULT_TCP_CONG="cubic" -CONFIG_TCP_MD5SIG=y -# CONFIG_IP_VS is not set -CONFIG_IPV6=m -CONFIG_IPV6_PRIVACY=y -CONFIG_IPV6_ROUTER_PREF=y -CONFIG_IPV6_ROUTE_INFO=y -# CONFIG_IPV6_OPTIMISTIC_DAD is not set -CONFIG_INET6_AH=m -CONFIG_INET6_ESP=m -CONFIG_INET6_IPCOMP=m -# CONFIG_IPV6_MIP6 is not set -CONFIG_INET6_XFRM_TUNNEL=m -CONFIG_INET6_TUNNEL=m -CONFIG_INET6_XFRM_MODE_TRANSPORT=m -CONFIG_INET6_XFRM_MODE_TUNNEL=m -CONFIG_INET6_XFRM_MODE_BEET=m -# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set -CONFIG_IPV6_SIT=m -CONFIG_IPV6_TUNNEL=m -CONFIG_IPV6_MULTIPLE_TABLES=y -CONFIG_IPV6_SUBTREES=y -CONFIG_NETWORK_SECMARK=y -CONFIG_NETFILTER=y -# CONFIG_NETFILTER_DEBUG is not set -CONFIG_BRIDGE_NETFILTER=y - -# -# Core Netfilter Configuration -# -CONFIG_NETFILTER_NETLINK=m -CONFIG_NETFILTER_NETLINK_QUEUE=m -CONFIG_NETFILTER_NETLINK_LOG=m -CONFIG_NF_CONNTRACK_ENABLED=m -CONFIG_NF_CONNTRACK=m -CONFIG_NF_CT_ACCT=y -CONFIG_NF_CONNTRACK_MARK=y -CONFIG_NF_CONNTRACK_SECMARK=y -CONFIG_NF_CONNTRACK_EVENTS=y -CONFIG_NF_CT_PROTO_GRE=m -CONFIG_NF_CT_PROTO_SCTP=m -# CONFIG_NF_CT_PROTO_UDPLITE is not set -CONFIG_NF_CONNTRACK_AMANDA=m -CONFIG_NF_CONNTRACK_FTP=m -CONFIG_NF_CONNTRACK_H323=m -CONFIG_NF_CONNTRACK_IRC=m -CONFIG_NF_CONNTRACK_NETBIOS_NS=m -CONFIG_NF_CONNTRACK_PPTP=m -CONFIG_NF_CONNTRACK_SANE=m -CONFIG_NF_CONNTRACK_SIP=m -CONFIG_NF_CONNTRACK_TFTP=m -CONFIG_NF_CT_NETLINK=m -CONFIG_NETFILTER_XTABLES=m -CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m -# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set -# CONFIG_NETFILTER_XT_TARGET_DSCP is not set -CONFIG_NETFILTER_XT_TARGET_MARK=m -CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_NFLOG=m -# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set -# CONFIG_NETFILTER_XT_TARGET_TRACE is not set -CONFIG_NETFILTER_XT_TARGET_SECMARK=m -CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m -CONFIG_NETFILTER_XT_TARGET_TCPMSS=m -CONFIG_NETFILTER_XT_MATCH_COMMENT=m -CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m -# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set -CONFIG_NETFILTER_XT_MATCH_CONNMARK=m -CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m -CONFIG_NETFILTER_XT_MATCH_DCCP=m -CONFIG_NETFILTER_XT_MATCH_DSCP=m -CONFIG_NETFILTER_XT_MATCH_ESP=m -CONFIG_NETFILTER_XT_MATCH_HELPER=m -CONFIG_NETFILTER_XT_MATCH_LENGTH=m -CONFIG_NETFILTER_XT_MATCH_LIMIT=m -CONFIG_NETFILTER_XT_MATCH_MAC=m -CONFIG_NETFILTER_XT_MATCH_MARK=m -CONFIG_NETFILTER_XT_MATCH_POLICY=m -CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m -# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set -CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m -CONFIG_NETFILTER_XT_MATCH_QUOTA=m -CONFIG_NETFILTER_XT_MATCH_REALM=m -CONFIG_NETFILTER_XT_MATCH_SCTP=m -CONFIG_NETFILTER_XT_MATCH_STATE=m -CONFIG_NETFILTER_XT_MATCH_STATISTIC=m -CONFIG_NETFILTER_XT_MATCH_STRING=m -CONFIG_NETFILTER_XT_MATCH_TCPMSS=m -# CONFIG_NETFILTER_XT_MATCH_U32 is not set -CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m - -# -# IP: Netfilter Configuration -# -CONFIG_NF_CONNTRACK_IPV4=m -CONFIG_NF_CONNTRACK_PROC_COMPAT=y -# CONFIG_IP_NF_QUEUE is not set -CONFIG_IP_NF_IPTABLES=m -CONFIG_IP_NF_MATCH_IPRANGE=m -CONFIG_IP_NF_MATCH_TOS=m -CONFIG_IP_NF_MATCH_RECENT=m -CONFIG_IP_NF_MATCH_ECN=m -CONFIG_IP_NF_MATCH_AH=m -CONFIG_IP_NF_MATCH_TTL=m -CONFIG_IP_NF_MATCH_OWNER=m -CONFIG_IP_NF_MATCH_ADDRTYPE=m -CONFIG_IP_NF_FILTER=m -CONFIG_IP_NF_TARGET_REJECT=m -CONFIG_IP_NF_TARGET_LOG=m -CONFIG_IP_NF_TARGET_ULOG=m -CONFIG_NF_NAT=m -CONFIG_NF_NAT_NEEDED=y -CONFIG_IP_NF_TARGET_MASQUERADE=m -CONFIG_IP_NF_TARGET_REDIRECT=m -CONFIG_IP_NF_TARGET_NETMAP=m -CONFIG_IP_NF_TARGET_SAME=m -CONFIG_NF_NAT_SNMP_BASIC=m -CONFIG_NF_NAT_PROTO_GRE=m -CONFIG_NF_NAT_FTP=m -CONFIG_NF_NAT_IRC=m -CONFIG_NF_NAT_TFTP=m -CONFIG_NF_NAT_AMANDA=m -CONFIG_NF_NAT_PPTP=m -CONFIG_NF_NAT_H323=m -CONFIG_NF_NAT_SIP=m -CONFIG_IP_NF_MANGLE=m -CONFIG_IP_NF_TARGET_TOS=m -CONFIG_IP_NF_TARGET_ECN=m -CONFIG_IP_NF_TARGET_TTL=m -CONFIG_IP_NF_TARGET_CLUSTERIP=m -CONFIG_IP_NF_RAW=m -CONFIG_IP_NF_ARPTABLES=m -CONFIG_IP_NF_ARPFILTER=m -CONFIG_IP_NF_ARP_MANGLE=m - -# -# IPv6: Netfilter Configuration (EXPERIMENTAL) -# -CONFIG_NF_CONNTRACK_IPV6=m -# CONFIG_IP6_NF_QUEUE is not set -CONFIG_IP6_NF_IPTABLES=m -CONFIG_IP6_NF_MATCH_RT=m -CONFIG_IP6_NF_MATCH_OPTS=m -CONFIG_IP6_NF_MATCH_FRAG=m -CONFIG_IP6_NF_MATCH_HL=m -CONFIG_IP6_NF_MATCH_OWNER=m -CONFIG_IP6_NF_MATCH_IPV6HEADER=m -CONFIG_IP6_NF_MATCH_AH=m -CONFIG_IP6_NF_MATCH_MH=m -CONFIG_IP6_NF_MATCH_EUI64=m -CONFIG_IP6_NF_FILTER=m -CONFIG_IP6_NF_TARGET_LOG=m -CONFIG_IP6_NF_TARGET_REJECT=m -CONFIG_IP6_NF_MANGLE=m -CONFIG_IP6_NF_TARGET_HL=m -CONFIG_IP6_NF_RAW=m - -# -# DECnet: Netfilter Configuration -# -# CONFIG_DECNET_NF_GRABULATOR is not set - -# -# Bridge: Netfilter Configuration -# -# CONFIG_BRIDGE_NF_EBTABLES is not set -CONFIG_IP_DCCP=m -CONFIG_INET_DCCP_DIAG=m -CONFIG_IP_DCCP_ACKVEC=y - -# -# DCCP CCIDs Configuration (EXPERIMENTAL) -# -CONFIG_IP_DCCP_CCID2=m -# CONFIG_IP_DCCP_CCID2_DEBUG is not set -CONFIG_IP_DCCP_CCID3=m -CONFIG_IP_DCCP_TFRC_LIB=m -# CONFIG_IP_DCCP_CCID3_DEBUG is not set -CONFIG_IP_DCCP_CCID3_RTO=100 - -# -# DCCP Kernel Hacking -# -# CONFIG_IP_DCCP_DEBUG is not set -CONFIG_IP_SCTP=m -# CONFIG_SCTP_DBG_MSG is not set -# CONFIG_SCTP_DBG_OBJCNT is not set -# CONFIG_SCTP_HMAC_NONE is not set -# CONFIG_SCTP_HMAC_SHA1 is not set -CONFIG_SCTP_HMAC_MD5=y -CONFIG_TIPC=m -CONFIG_TIPC_ADVANCED=y -CONFIG_TIPC_ZONES=3 -CONFIG_TIPC_CLUSTERS=1 -CONFIG_TIPC_NODES=255 -CONFIG_TIPC_SLAVE_NODES=0 -CONFIG_TIPC_PORTS=8191 -CONFIG_TIPC_LOG=0 -# CONFIG_TIPC_DEBUG is not set -CONFIG_ATM=m -CONFIG_ATM_CLIP=m -# CONFIG_ATM_CLIP_NO_ICMP is not set -CONFIG_ATM_LANE=m -# CONFIG_ATM_MPOA is not set -CONFIG_ATM_BR2684=m -CONFIG_ATM_BR2684_IPFILTER=y -CONFIG_BRIDGE=m -CONFIG_VLAN_8021Q=m -CONFIG_DECNET=m -# CONFIG_DECNET_ROUTER is not set -CONFIG_LLC=m -CONFIG_LLC2=m -CONFIG_IPX=m -CONFIG_IPX_INTERN=y -CONFIG_ATALK=m -CONFIG_DEV_APPLETALK=m -# CONFIG_LTPC is not set -# CONFIG_COPS is not set -CONFIG_IPDDP=m -CONFIG_IPDDP_ENCAP=y -CONFIG_IPDDP_DECAP=y -CONFIG_X25=m -CONFIG_LAPB=m -CONFIG_ECONET=m -CONFIG_ECONET_AUNUDP=y -CONFIG_ECONET_NATIVE=y -CONFIG_WAN_ROUTER=m - -# -# QoS and/or fair queueing -# -CONFIG_NET_SCHED=y -CONFIG_NET_SCH_FIFO=y - -# -# Queueing/Scheduling -# -CONFIG_NET_SCH_CBQ=m -CONFIG_NET_SCH_HTB=m -CONFIG_NET_SCH_HFSC=m -CONFIG_NET_SCH_ATM=m -CONFIG_NET_SCH_PRIO=m -# CONFIG_NET_SCH_RR is not set -CONFIG_NET_SCH_RED=m -CONFIG_NET_SCH_SFQ=m -CONFIG_NET_SCH_TEQL=m -CONFIG_NET_SCH_TBF=m -CONFIG_NET_SCH_GRED=m -CONFIG_NET_SCH_DSMARK=m -CONFIG_NET_SCH_NETEM=m -CONFIG_NET_SCH_INGRESS=m - -# -# Classification -# -CONFIG_NET_CLS=y -CONFIG_NET_CLS_BASIC=m -CONFIG_NET_CLS_TCINDEX=m -CONFIG_NET_CLS_ROUTE4=m -CONFIG_NET_CLS_ROUTE=y -CONFIG_NET_CLS_FW=m -CONFIG_NET_CLS_U32=m -CONFIG_CLS_U32_PERF=y -CONFIG_CLS_U32_MARK=y -CONFIG_NET_CLS_RSVP=m -CONFIG_NET_CLS_RSVP6=m -CONFIG_NET_EMATCH=y -CONFIG_NET_EMATCH_STACK=32 -CONFIG_NET_EMATCH_CMP=m -CONFIG_NET_EMATCH_NBYTE=m -CONFIG_NET_EMATCH_U32=m -CONFIG_NET_EMATCH_META=m -CONFIG_NET_EMATCH_TEXT=m -CONFIG_NET_CLS_ACT=y -CONFIG_NET_ACT_POLICE=m -CONFIG_NET_ACT_GACT=m -CONFIG_GACT_PROB=y -CONFIG_NET_ACT_MIRRED=m -CONFIG_NET_ACT_IPT=m -CONFIG_NET_ACT_PEDIT=m -CONFIG_NET_ACT_SIMP=m -# CONFIG_NET_CLS_POLICE is not set -CONFIG_NET_CLS_IND=y - -# -# Network testing -# -# CONFIG_NET_PKTGEN is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set -CONFIG_AF_RXRPC=m -# CONFIG_AF_RXRPC_DEBUG is not set -CONFIG_RXKAD=m -CONFIG_FIB_RULES=y - -# -# Wireless -# -# CONFIG_CFG80211 is not set -# CONFIG_WIRELESS_EXT is not set -# CONFIG_MAC80211 is not set -# CONFIG_IEEE80211 is not set -# CONFIG_RFKILL is not set -# CONFIG_NET_9P is not set - -# -# Device Drivers -# - -# -# Generic Driver Options -# -CONFIG_STANDALONE=y -CONFIG_PREVENT_FIRMWARE_BUILD=y -# CONFIG_FW_LOADER is not set -# CONFIG_DEBUG_DRIVER is not set -# CONFIG_DEBUG_DEVRES is not set -# CONFIG_SYS_HYPERVISOR is not set -CONFIG_CONNECTOR=m -# CONFIG_MTD is not set -CONFIG_PARPORT=m -CONFIG_PARPORT_PC=m -# CONFIG_PARPORT_SERIAL is not set -# CONFIG_PARPORT_PC_FIFO is not set -# CONFIG_PARPORT_PC_SUPERIO is not set -# CONFIG_PARPORT_GSC is not set -# CONFIG_PARPORT_AX88796 is not set -# CONFIG_PARPORT_1284 is not set -# CONFIG_PNP is not set -CONFIG_BLK_DEV=y -# CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_XD is not set -# CONFIG_PARIDE is not set -# CONFIG_BLK_CPQ_DA is not set -# CONFIG_BLK_CPQ_CISS_DA is not set -# CONFIG_BLK_DEV_DAC960 is not set -# CONFIG_BLK_DEV_UMEM is not set -# CONFIG_BLK_DEV_COW_COMMON is not set -CONFIG_BLK_DEV_LOOP=m -CONFIG_BLK_DEV_CRYPTOLOOP=m -CONFIG_BLK_DEV_NBD=m -# CONFIG_BLK_DEV_SX8 is not set -CONFIG_BLK_DEV_RAM=m -CONFIG_BLK_DEV_RAM_COUNT=16 -CONFIG_BLK_DEV_RAM_SIZE=4096 -CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 -# CONFIG_CDROM_PKTCDVD is not set -# CONFIG_ATA_OVER_ETH is not set -CONFIG_MISC_DEVICES=y -# CONFIG_IBM_ASM is not set -# CONFIG_PHANTOM is not set -# CONFIG_EEPROM_93CX6 is not set -# CONFIG_SGI_IOC4 is not set -# CONFIG_TIFM_CORE is not set -CONFIG_IDE=y -CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_IDE_SATA is not set -# CONFIG_BLK_DEV_HD_IDE is not set -CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set -CONFIG_BLK_DEV_IDECD=y -# CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_IDE_TASK_IOCTL is not set -CONFIG_IDE_PROC_FS=y - -# -# IDE chipset support/bugfixes -# -CONFIG_IDE_GENERIC=y -# CONFIG_BLK_DEV_CMD640 is not set -CONFIG_BLK_DEV_IDEPCI=y -# CONFIG_IDEPCI_SHARE_IRQ is not set -CONFIG_IDEPCI_PCIBUS_ORDER=y -# CONFIG_BLK_DEV_OFFBOARD is not set -# CONFIG_BLK_DEV_GENERIC is not set -# CONFIG_BLK_DEV_OPTI621 is not set -# CONFIG_BLK_DEV_RZ1000 is not set -# CONFIG_BLK_DEV_IDEDMA_PCI is not set -# CONFIG_IDE_ARM is not set -# CONFIG_IDE_CHIPSETS is not set -# CONFIG_BLK_DEV_IDEDMA is not set -# CONFIG_BLK_DEV_HD is not set - -# -# SCSI device support -# -# CONFIG_RAID_ATTRS is not set -# CONFIG_SCSI is not set -# CONFIG_SCSI_DMA is not set -# CONFIG_SCSI_NETLINK is not set -# CONFIG_ATA is not set -# CONFIG_MD is not set - -# -# Fusion MPT device support -# -# CONFIG_FUSION is not set - -# -# IEEE 1394 (FireWire) support -# -# CONFIG_FIREWIRE is not set -# CONFIG_IEEE1394 is not set -# CONFIG_I2O is not set -# CONFIG_MACINTOSH_DRIVERS is not set -CONFIG_NETDEVICES=y -# CONFIG_NETDEVICES_MULTIQUEUE is not set -# CONFIG_IFB is not set -CONFIG_DUMMY=m -# CONFIG_BONDING is not set -# CONFIG_MACVLAN is not set -# CONFIG_EQUALIZER is not set -CONFIG_TUN=m -# CONFIG_ARCNET is not set -# CONFIG_PHYLIB is not set -CONFIG_NET_ETHERNET=y -CONFIG_MII=y -# CONFIG_HAPPYMEAL is not set -# CONFIG_SUNGEM is not set -# CONFIG_CASSINI is not set -# CONFIG_NET_VENDOR_3COM is not set -# CONFIG_LANCE is not set -# CONFIG_NET_VENDOR_SMC is not set -# CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_NET_TULIP is not set -# CONFIG_AT1700 is not set -# CONFIG_DEPCA is not set -# CONFIG_HP100 is not set -# CONFIG_NET_ISA is not set -CONFIG_NET_PCI=y -CONFIG_PCNET32=y -# CONFIG_PCNET32_NAPI is not set -# CONFIG_AMD8111_ETH is not set -# CONFIG_ADAPTEC_STARFIRE is not set -# CONFIG_AC3200 is not set -# CONFIG_APRICOT is not set -# CONFIG_B44 is not set -# CONFIG_FORCEDETH is not set -# CONFIG_CS89x0 is not set -# CONFIG_DGRS is not set -# CONFIG_EEPRO100 is not set -# CONFIG_E100 is not set -# CONFIG_FEALNX is not set -# CONFIG_NATSEMI is not set -CONFIG_NE2K_PCI=y -CONFIG_8139CP=y -# CONFIG_8139TOO is not set -# CONFIG_SIS900 is not set -# CONFIG_EPIC100 is not set -# CONFIG_SUNDANCE is not set -# CONFIG_TLAN is not set -# CONFIG_VIA_RHINE is not set -# CONFIG_SC92031 is not set -# CONFIG_NET_POCKET is not set -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set -# CONFIG_TR is not set - -# -# Wireless LAN -# -# CONFIG_WLAN_PRE80211 is not set -# CONFIG_WLAN_80211 is not set -# CONFIG_WAN is not set -CONFIG_ATM_DRIVERS=y -# CONFIG_ATM_DUMMY is not set -# CONFIG_ATM_TCP is not set -# CONFIG_ATM_LANAI is not set -# CONFIG_ATM_ENI is not set -# CONFIG_ATM_FIRESTREAM is not set -# CONFIG_ATM_ZATM is not set -# CONFIG_ATM_NICSTAR is not set -# CONFIG_ATM_IDT77252 is not set -# CONFIG_ATM_AMBASSADOR is not set -# CONFIG_ATM_HORIZON is not set -# CONFIG_ATM_IA is not set -# CONFIG_ATM_FORE200E_MAYBE is not set -# CONFIG_ATM_HE is not set -# CONFIG_FDDI is not set -CONFIG_HIPPI=y -# CONFIG_ROADRUNNER is not set -# CONFIG_PLIP is not set -# CONFIG_PPP is not set -# CONFIG_SLIP is not set -# CONFIG_SHAPER is not set -# CONFIG_NETCONSOLE is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set -# CONFIG_ISDN is not set -# CONFIG_PHONE is not set - -# -# Input device support -# -CONFIG_INPUT=y -# CONFIG_INPUT_FF_MEMLESS is not set -# CONFIG_INPUT_POLLDEV is not set - -# -# Userland interfaces -# -CONFIG_INPUT_MOUSEDEV=y -CONFIG_INPUT_MOUSEDEV_PSAUX=y -CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 -CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_TSDEV is not set -# CONFIG_INPUT_EVDEV is not set -# CONFIG_INPUT_EVBUG is not set - -# -# Input Device Drivers -# -CONFIG_INPUT_KEYBOARD=y -CONFIG_KEYBOARD_ATKBD=y -# CONFIG_KEYBOARD_SUNKBD is not set -# CONFIG_KEYBOARD_LKKBD is not set -# CONFIG_KEYBOARD_XTKBD is not set -# CONFIG_KEYBOARD_NEWTON is not set -# CONFIG_KEYBOARD_STOWAWAY is not set -CONFIG_INPUT_MOUSE=y -CONFIG_MOUSE_PS2=y -CONFIG_MOUSE_PS2_ALPS=y -CONFIG_MOUSE_PS2_LOGIPS2PP=y -CONFIG_MOUSE_PS2_SYNAPTICS=y -CONFIG_MOUSE_PS2_LIFEBOOK=y -CONFIG_MOUSE_PS2_TRACKPOINT=y -# CONFIG_MOUSE_PS2_TOUCHKIT is not set -# CONFIG_MOUSE_SERIAL is not set -# CONFIG_MOUSE_APPLETOUCH is not set -# CONFIG_MOUSE_INPORT is not set -# CONFIG_MOUSE_LOGIBM is not set -# CONFIG_MOUSE_PC110PAD is not set -# CONFIG_MOUSE_VSXXXAA is not set -# CONFIG_INPUT_JOYSTICK is not set -# CONFIG_INPUT_TABLET is not set -# CONFIG_INPUT_TOUCHSCREEN is not set -# CONFIG_INPUT_MISC is not set - -# -# Hardware I/O ports -# -CONFIG_SERIO=y -CONFIG_SERIO_I8042=y -CONFIG_SERIO_SERPORT=y -# CONFIG_SERIO_CT82C710 is not set -# CONFIG_SERIO_PARKBD is not set -# CONFIG_SERIO_PCIPS2 is not set -CONFIG_SERIO_LIBPS2=y -# CONFIG_SERIO_RAW is not set -# CONFIG_GAMEPORT is not set - -# -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -CONFIG_HW_CONSOLE=y -# CONFIG_VT_HW_CONSOLE_BINDING is not set -# CONFIG_SERIAL_NONSTANDARD is not set - -# -# Serial drivers -# -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_FIX_EARLYCON_MEM=y -CONFIG_SERIAL_8250_PCI=y -CONFIG_SERIAL_8250_NR_UARTS=4 -CONFIG_SERIAL_8250_RUNTIME_UARTS=4 -# CONFIG_SERIAL_8250_EXTENDED is not set - -# -# Non-8250 serial port support -# -CONFIG_SERIAL_CORE=y -CONFIG_SERIAL_CORE_CONSOLE=y -# CONFIG_SERIAL_JSM is not set -CONFIG_UNIX98_PTYS=y -CONFIG_LEGACY_PTYS=y -CONFIG_LEGACY_PTY_COUNT=256 -# CONFIG_PRINTER is not set -# CONFIG_PPDEV is not set -# CONFIG_TIPAR is not set -# CONFIG_IPMI_HANDLER is not set -CONFIG_WATCHDOG=y -CONFIG_WATCHDOG_NOWAYOUT=y - -# -# Watchdog Device Drivers -# -CONFIG_SOFT_WATCHDOG=y -# CONFIG_ACQUIRE_WDT is not set -# CONFIG_ADVANTECH_WDT is not set -# CONFIG_ALIM1535_WDT is not set -# CONFIG_ALIM7101_WDT is not set -# CONFIG_SC520_WDT is not set -# CONFIG_EUROTECH_WDT is not set -# CONFIG_IB700_WDT is not set -# CONFIG_IBMASR is not set -# CONFIG_WAFER_WDT is not set -# CONFIG_I6300ESB_WDT is not set -# CONFIG_ITCO_WDT is not set -# CONFIG_SC1200_WDT is not set -# CONFIG_PC87413_WDT is not set -# CONFIG_60XX_WDT is not set -# CONFIG_SBC8360_WDT is not set -# CONFIG_CPU5_WDT is not set -# CONFIG_SMSC37B787_WDT is not set -# CONFIG_W83627HF_WDT is not set -# CONFIG_W83697HF_WDT is not set -# CONFIG_W83877F_WDT is not set -# CONFIG_W83977F_WDT is not set -# CONFIG_MACHZ_WDT is not set -# CONFIG_SBC_EPX_C3_WATCHDOG is not set - -# -# ISA-based Watchdog Cards -# -# CONFIG_PCWATCHDOG is not set -# CONFIG_MIXCOMWD is not set -# CONFIG_WDT is not set - -# -# PCI-based Watchdog Cards -# -# CONFIG_PCIPCWATCHDOG is not set -# CONFIG_WDTPCI is not set -# CONFIG_HW_RANDOM is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set -# CONFIG_GEN_RTC is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set -# CONFIG_SONYPI is not set -# CONFIG_AGP is not set -# CONFIG_DRM is not set -# CONFIG_MWAVE is not set -# CONFIG_PC8736x_GPIO is not set -# CONFIG_NSC_GPIO is not set -# CONFIG_CS5535_GPIO is not set -CONFIG_RAW_DRIVER=m -CONFIG_MAX_RAW_DEVS=256 -# CONFIG_HANGCHECK_TIMER is not set -# CONFIG_TCG_TPM is not set -# CONFIG_TELCLOCK is not set -CONFIG_DEVPORT=y -# CONFIG_I2C is not set - -# -# SPI support -# -# CONFIG_SPI is not set -# CONFIG_SPI_MASTER is not set -# CONFIG_W1 is not set -# CONFIG_POWER_SUPPLY is not set -CONFIG_HWMON=y -# CONFIG_HWMON_VID is not set -# CONFIG_SENSORS_ABITUGURU is not set -# CONFIG_SENSORS_ABITUGURU3 is not set -# CONFIG_SENSORS_K8TEMP is not set -# CONFIG_SENSORS_F71805F is not set -# CONFIG_SENSORS_CORETEMP is not set -# CONFIG_SENSORS_IT87 is not set -# CONFIG_SENSORS_PC87360 is not set -# CONFIG_SENSORS_PC87427 is not set -# CONFIG_SENSORS_SIS5595 is not set -# CONFIG_SENSORS_SMSC47M1 is not set -# CONFIG_SENSORS_SMSC47B397 is not set -# CONFIG_SENSORS_VIA686A is not set -# CONFIG_SENSORS_VT1211 is not set -# CONFIG_SENSORS_VT8231 is not set -# CONFIG_SENSORS_W83627HF is not set -# CONFIG_SENSORS_W83627EHF is not set -# CONFIG_SENSORS_HDAPS is not set -# CONFIG_SENSORS_APPLESMC is not set -# CONFIG_HWMON_DEBUG_CHIP is not set - -# -# Multifunction device drivers -# -# CONFIG_MFD_SM501 is not set - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set -# CONFIG_DVB_CORE is not set -# CONFIG_DAB is not set - -# -# Graphics support -# -# CONFIG_BACKLIGHT_LCD_SUPPORT is not set - -# -# Display device support -# -# CONFIG_DISPLAY_SUPPORT is not set -# CONFIG_VGASTATE is not set -CONFIG_VIDEO_OUTPUT_CONTROL=m -# CONFIG_FB is not set - -# -# Console display driver support -# -CONFIG_VGA_CONSOLE=y -# CONFIG_VGACON_SOFT_SCROLLBACK is not set -# CONFIG_VIDEO_SELECT is not set -# CONFIG_MDA_CONSOLE is not set -CONFIG_DUMMY_CONSOLE=y - -# -# Sound -# -# CONFIG_SOUND is not set -CONFIG_HID_SUPPORT=y -# CONFIG_HID is not set -CONFIG_USB_SUPPORT=y -CONFIG_USB_ARCH_HAS_HCD=y -CONFIG_USB_ARCH_HAS_OHCI=y -CONFIG_USB_ARCH_HAS_EHCI=y -# CONFIG_USB is not set - -# -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' -# - -# -# USB Gadget Support -# -# CONFIG_USB_GADGET is not set -# CONFIG_MMC is not set -# CONFIG_NEW_LEDS is not set -# CONFIG_INFINIBAND is not set -# CONFIG_EDAC is not set -# CONFIG_RTC_CLASS is not set - -# -# DMA Engine support -# -# CONFIG_DMA_ENGINE is not set - -# -# DMA Clients -# - -# -# DMA Devices -# -# CONFIG_AUXDISPLAY is not set -CONFIG_VIRTUALIZATION=y -# CONFIG_KVM is not set - -# -# Userspace I/O -# -# CONFIG_UIO is not set - -# -# File systems -# -# CONFIG_EXT2_FS is not set -CONFIG_EXT3_FS=y -CONFIG_EXT3_FS_XATTR=y -CONFIG_EXT3_FS_POSIX_ACL=y -CONFIG_EXT3_FS_SECURITY=y -# CONFIG_EXT4DEV_FS is not set -CONFIG_JBD=y -# CONFIG_JBD_DEBUG is not set -CONFIG_FS_MBCACHE=y -# CONFIG_REISERFS_FS is not set -# CONFIG_JFS_FS is not set -CONFIG_FS_POSIX_ACL=y -# CONFIG_XFS_FS is not set -# CONFIG_GFS2_FS is not set -# CONFIG_OCFS2_FS is not set -# CONFIG_MINIX_FS is not set -CONFIG_ROMFS_FS=m -CONFIG_INOTIFY=y -CONFIG_INOTIFY_USER=y -# CONFIG_QUOTA is not set -CONFIG_DNOTIFY=y -# CONFIG_AUTOFS_FS is not set -# CONFIG_AUTOFS4_FS is not set -# CONFIG_FUSE_FS is not set -CONFIG_GENERIC_ACL=y - -# -# CD-ROM/DVD Filesystems -# -CONFIG_ISO9660_FS=y -CONFIG_JOLIET=y -CONFIG_ZISOFS=y -CONFIG_UDF_FS=y -CONFIG_UDF_NLS=y - -# -# DOS/FAT/NT Filesystems -# -# CONFIG_MSDOS_FS is not set -# CONFIG_VFAT_FS is not set -# CONFIG_NTFS_FS is not set - -# -# Pseudo filesystems -# -CONFIG_PROC_FS=y -CONFIG_PROC_KCORE=y -CONFIG_PROC_SYSCTL=y -CONFIG_SYSFS=y -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y -# CONFIG_HUGETLBFS is not set -# CONFIG_HUGETLB_PAGE is not set -CONFIG_RAMFS=y -CONFIG_CONFIGFS_FS=m - -# -# Miscellaneous filesystems -# -# CONFIG_ADFS_FS is not set -# CONFIG_AFFS_FS is not set -# CONFIG_ECRYPT_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_HFSPLUS_FS is not set -# CONFIG_BEFS_FS is not set -# CONFIG_BFS_FS is not set -# CONFIG_EFS_FS is not set -CONFIG_CRAMFS=m -# CONFIG_VXFS_FS is not set -# CONFIG_HPFS_FS is not set -# CONFIG_QNX4FS_FS is not set -# CONFIG_SYSV_FS is not set -# CONFIG_UFS_FS is not set - -# -# Network File Systems -# -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -# CONFIG_NFS_V3_ACL is not set -# CONFIG_NFS_V4 is not set -# CONFIG_NFS_DIRECTIO is not set -# CONFIG_NFSD is not set -CONFIG_LOCKD=y -CONFIG_LOCKD_V4=y -CONFIG_NFS_COMMON=y -CONFIG_SUNRPC=y -# CONFIG_SUNRPC_BIND34 is not set -# CONFIG_RPCSEC_GSS_KRB5 is not set -# CONFIG_RPCSEC_GSS_SPKM3 is not set -# CONFIG_SMB_FS is not set -# CONFIG_CIFS is not set -# CONFIG_NCP_FS is not set -# CONFIG_CODA_FS is not set -# CONFIG_AFS_FS is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y - -# -# Native Language Support -# -CONFIG_NLS=y -CONFIG_NLS_DEFAULT="iso8859-1" -CONFIG_NLS_CODEPAGE_437=m -CONFIG_NLS_CODEPAGE_737=m -CONFIG_NLS_CODEPAGE_775=m -CONFIG_NLS_CODEPAGE_850=m -CONFIG_NLS_CODEPAGE_852=m -CONFIG_NLS_CODEPAGE_855=m -CONFIG_NLS_CODEPAGE_857=m -CONFIG_NLS_CODEPAGE_860=m -CONFIG_NLS_CODEPAGE_861=m -CONFIG_NLS_CODEPAGE_862=m -CONFIG_NLS_CODEPAGE_863=m -CONFIG_NLS_CODEPAGE_864=m -CONFIG_NLS_CODEPAGE_865=m -CONFIG_NLS_CODEPAGE_866=m -CONFIG_NLS_CODEPAGE_869=m -CONFIG_NLS_CODEPAGE_936=m -CONFIG_NLS_CODEPAGE_950=m -CONFIG_NLS_CODEPAGE_932=m -CONFIG_NLS_CODEPAGE_949=m -CONFIG_NLS_CODEPAGE_874=m -CONFIG_NLS_ISO8859_8=m -CONFIG_NLS_CODEPAGE_1250=m -CONFIG_NLS_CODEPAGE_1251=m -CONFIG_NLS_ASCII=m -CONFIG_NLS_ISO8859_1=m -CONFIG_NLS_ISO8859_2=m -CONFIG_NLS_ISO8859_3=m -CONFIG_NLS_ISO8859_4=m -CONFIG_NLS_ISO8859_5=m -CONFIG_NLS_ISO8859_6=m -CONFIG_NLS_ISO8859_7=m -CONFIG_NLS_ISO8859_9=m -CONFIG_NLS_ISO8859_13=m -CONFIG_NLS_ISO8859_14=m -CONFIG_NLS_ISO8859_15=m -CONFIG_NLS_KOI8_R=m -CONFIG_NLS_KOI8_U=m -CONFIG_NLS_UTF8=m - -# -# Distributed Lock Manager -# -# CONFIG_DLM is not set -CONFIG_INSTRUMENTATION=y -# CONFIG_PROFILING is not set -# CONFIG_KPROBES is not set - -# -# Kernel hacking -# -CONFIG_TRACE_IRQFLAGS_SUPPORT=y -# CONFIG_PRINTK_TIME is not set -# CONFIG_ENABLE_MUST_CHECK is not set -CONFIG_MAGIC_SYSRQ=y -# CONFIG_UNUSED_SYMBOLS is not set -CONFIG_DEBUG_FS=y -# CONFIG_HEADERS_CHECK is not set -CONFIG_DEBUG_KERNEL=y -# CONFIG_DEBUG_SHIRQ is not set -CONFIG_DETECT_SOFTLOCKUP=y -CONFIG_SCHED_DEBUG=y -# CONFIG_SCHEDSTATS is not set -# CONFIG_TIMER_STATS is not set -CONFIG_DEBUG_SLAB=y -CONFIG_DEBUG_SLAB_LEAK=y -CONFIG_DEBUG_RT_MUTEXES=y -CONFIG_DEBUG_PI_LIST=y -# CONFIG_RT_MUTEX_TESTER is not set -CONFIG_DEBUG_SPINLOCK=y -CONFIG_DEBUG_MUTEXES=y -CONFIG_DEBUG_LOCK_ALLOC=y -CONFIG_PROVE_LOCKING=y -CONFIG_LOCKDEP=y -CONFIG_LOCK_STAT=y -# CONFIG_DEBUG_LOCKDEP is not set -CONFIG_TRACE_IRQFLAGS=y -CONFIG_DEBUG_SPINLOCK_SLEEP=y -# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set -CONFIG_STACKTRACE=y -CONFIG_DEBUG_KOBJECT=y -CONFIG_DEBUG_HIGHMEM=y -CONFIG_DEBUG_BUGVERBOSE=y -CONFIG_DEBUG_INFO=y -CONFIG_DEBUG_VM=y -CONFIG_DEBUG_LIST=y -CONFIG_FRAME_POINTER=y -CONFIG_FORCED_INLINING=y -CONFIG_RCU_TORTURE_TEST=m -# CONFIG_FAULT_INJECTION is not set -CONFIG_EARLY_PRINTK=y -CONFIG_DEBUG_STACKOVERFLOW=y -# CONFIG_DEBUG_STACK_USAGE is not set -CONFIG_DEBUG_PAGEALLOC=y -CONFIG_DEBUG_RODATA=y -CONFIG_4KSTACKS=y -CONFIG_X86_FIND_SMP_CONFIG=y -CONFIG_X86_MPPARSE=y -CONFIG_DOUBLEFAULT=y - -# -# Security options -# -CONFIG_KEYS=y -# CONFIG_KEYS_DEBUG_PROC_KEYS is not set -# CONFIG_SECURITY is not set -CONFIG_CRYPTO=y -CONFIG_CRYPTO_ALGAPI=y -CONFIG_CRYPTO_BLKCIPHER=m -CONFIG_CRYPTO_HASH=m -CONFIG_CRYPTO_MANAGER=m -CONFIG_CRYPTO_HMAC=m -# CONFIG_CRYPTO_XCBC is not set -CONFIG_CRYPTO_NULL=m -CONFIG_CRYPTO_MD4=m -CONFIG_CRYPTO_MD5=y -CONFIG_CRYPTO_SHA1=m -CONFIG_CRYPTO_SHA256=m -# CONFIG_CRYPTO_SHA512 is not set -# CONFIG_CRYPTO_WP512 is not set -# CONFIG_CRYPTO_TGR192 is not set -CONFIG_CRYPTO_GF128MUL=m -# CONFIG_CRYPTO_ECB is not set -CONFIG_CRYPTO_CBC=m -CONFIG_CRYPTO_PCBC=m -CONFIG_CRYPTO_LRW=m -# CONFIG_CRYPTO_CRYPTD is not set -CONFIG_CRYPTO_DES=m -CONFIG_CRYPTO_FCRYPT=m -# CONFIG_CRYPTO_BLOWFISH is not set -# CONFIG_CRYPTO_TWOFISH is not set -# CONFIG_CRYPTO_TWOFISH_586 is not set -# CONFIG_CRYPTO_SERPENT is not set -CONFIG_CRYPTO_AES=m -# CONFIG_CRYPTO_AES_586 is not set -# CONFIG_CRYPTO_CAST5 is not set -# CONFIG_CRYPTO_CAST6 is not set -CONFIG_CRYPTO_TEA=m -# CONFIG_CRYPTO_ARC4 is not set -# CONFIG_CRYPTO_KHAZAD is not set -# CONFIG_CRYPTO_ANUBIS is not set -CONFIG_CRYPTO_DEFLATE=m -# CONFIG_CRYPTO_MICHAEL_MIC is not set -# CONFIG_CRYPTO_CRC32C is not set -# CONFIG_CRYPTO_CAMELLIA is not set -# CONFIG_CRYPTO_TEST is not set -CONFIG_CRYPTO_HW=y -# CONFIG_CRYPTO_DEV_PADLOCK is not set -# CONFIG_CRYPTO_DEV_GEODE is not set - -# -# Library routines -# -CONFIG_BITREVERSE=y -CONFIG_CRC_CCITT=m -CONFIG_CRC16=m -CONFIG_CRC_ITU_T=m -CONFIG_CRC32=y -# CONFIG_CRC7 is not set -CONFIG_LIBCRC32C=m -CONFIG_ZLIB_INFLATE=y -CONFIG_ZLIB_DEFLATE=m -CONFIG_TEXTSEARCH=y -CONFIG_TEXTSEARCH_KMP=m -CONFIG_TEXTSEARCH_BM=m -CONFIG_TEXTSEARCH_FSM=m -CONFIG_PLIST=y -CONFIG_HAS_IOMEM=y -CONFIG_HAS_IOPORT=y -CONFIG_HAS_DMA=y -CONFIG_GENERIC_HARDIRQS=y -CONFIG_GENERIC_IRQ_PROBE=y -CONFIG_GENERIC_PENDING_IRQ=y -CONFIG_X86_SMP=y -CONFIG_X86_HT=y -CONFIG_X86_BIOS_REBOOT=y -CONFIG_X86_TRAMPOLINE=y -CONFIG_KTIME_SCALAR=y diff --git a/openflow/datapath/openflow-ext.c b/openflow/datapath/openflow-ext.c deleted file mode 100644 index e9f87a8b..00000000 --- a/openflow/datapath/openflow-ext.c +++ /dev/null @@ -1,83 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#include "openflow/openflow-ext.h" - -#include "chain.h" -#include "datapath.h" -#include "table.h" -#include "private-msg.h" - -/*** - * Copy the new dp_desc out of the passed message - */ - -int -recv_of_set_dp_desc(struct datapath *dp, const struct sender * sender, - const struct openflow_extension_header *ofexth) -{ - struct openflow_ext_set_dp_desc * set_dp_desc = (struct openflow_ext_set_dp_desc * ) - ofexth; - memcpy(dp->dp_desc, set_dp_desc->dp_desc, DESC_STR_LEN); - dp->dp_desc[DESC_STR_LEN-1] = 0; // force null for safety - return 0; -} - - -int -openflow_ext_recv_msg(struct sw_chain *chain, const struct sender *sender, - const void *ofph) -{ - int error = 0; - const struct openflow_queue_command_header *ofexth = ofph; - - switch (ntohl(ofexth->header.subtype)) { - /**** added here as a place holder - * case OFP_EXT_QUEUE_MODIFY: { - * recv_of_exp_queue_modify(dp,sender,oh); - * return 0; - * } - * case OFP_EXT_QUEUE_DELETE: { - * recv_of_exp_queue_delete(dp,sender,oh); - * return 0; - * } - */ - case OFP_EXT_SET_DESC: - return recv_of_set_dp_desc(chain->dp,sender,ofexth); - default: - VLOG_ERR("Received unknown command of type %d", - ntohl(ofexth->header.subtype)); - return -EINVAL; - } - - return error; -} diff --git a/openflow/datapath/openflow-ext.h b/openflow/datapath/openflow-ext.h deleted file mode 100644 index 83edfc01..00000000 --- a/openflow/datapath/openflow-ext.h +++ /dev/null @@ -1,38 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#ifndef OPENFLOW_EXT_H_ -#define OPENFLOW_EXT_H_ - -int openflow_ext_recv_msg(struct sw_chain *, const struct sender *, const void *); - -#endif diff --git a/openflow/datapath/private-msg.c b/openflow/datapath/private-msg.c deleted file mode 100644 index 96110ebf..00000000 --- a/openflow/datapath/private-msg.c +++ /dev/null @@ -1,137 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#include "openflow/private-ext.h" - -#include "chain.h" -#include "datapath.h" -#include "table.h" -#include "private-msg.h" - -struct emerg_flow_context { - struct sw_chain *chain; -}; - -static void flush_working(struct sw_chain *); -static int protection_callback(struct sw_flow *, void *); -static void do_protection(struct sw_chain *); - -static void -flush_working(struct sw_chain *chain) -{ - struct sw_flow_key key; - int num_deleted = 0; - - memset(&key, 0, sizeof(key)); - key.wildcards = OFPFW_ALL; - num_deleted = chain_delete(chain, &key, OFPP_NONE, 0, 0, 0); -} - -static int -protection_callback(struct sw_flow *flow, void *private_) -{ - struct emerg_flow_context *private - = (struct emerg_flow_context *)private_; - struct sw_flow_actions *actions = flow->sf_acts; - struct ofp_match match; - struct sw_flow *tgtflow = NULL; - int error = 0; - - tgtflow = flow_alloc(actions->actions_len, GFP_ATOMIC); - if (tgtflow == NULL) { - return -ENOMEM; - } - - /* Dup w/o idle and hard timeout. */ - memset(&match, 0, sizeof(match)); - flow_fill_match(&match, &flow->key); - flow_extract_match(&tgtflow->key, &match); - /* Fill out flow. */ - tgtflow->priority = flow->priority; - tgtflow->idle_timeout = OFP_FLOW_PERMANENT; - tgtflow->hard_timeout = OFP_FLOW_PERMANENT; - tgtflow->send_flow_rem = flow->send_flow_rem; - tgtflow->emerg_flow = 0; - flow_setup_actions(tgtflow, actions->actions, actions->actions_len); - - error = chain_insert(private->chain, tgtflow, 0); - if (error) - flow_free(tgtflow); - - return error; -} - -static void -do_protection(struct sw_chain *chain) -{ - struct emerg_flow_context private; - struct sw_flow_key key; - struct sw_table_position position; - struct sw_table *table = chain->emerg_table; - int error = 0; - - memset(&private, 0, sizeof(private)); - private.chain = chain; - memset(&key, 0, sizeof(key)); - key.wildcards = OFPFW_ALL; - memset(&position, 0, sizeof(position)); - - error = table->iterate(table, &key, OFPP_NONE, - &position, protection_callback, &private); -} - -int -private_recv_msg(struct sw_chain *chain, const struct sender *sender, - const void *ofph) -{ - int error = 0; - struct private_vxhdr *vxhdr = (struct private_vxhdr *)ofph; - struct private_vxopt *vxopt = (struct private_vxopt *)(vxhdr + 1); - - switch (ntohs(vxopt->pvo_type)) { - case PRIVATEOPT_PROTOCOL_STATS_REQUEST: - case PRIVATEOPT_PROTOCOL_STATS_REPLY: - break; - case PRIVATEOPT_EMERG_FLOW_PROTECTION: - flush_working(chain); - do_protection(chain); - break; - case PRIVATEOPT_EMERG_FLOW_RESTORATION: - /* Nothing to do because we assume that a re-connected - * controller will do flush current working flow table. */ - break; - default: - error = -EINVAL; - } - - return error; -} diff --git a/openflow/datapath/private-msg.h b/openflow/datapath/private-msg.h deleted file mode 100644 index 246aa541..00000000 --- a/openflow/datapath/private-msg.h +++ /dev/null @@ -1,38 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#ifndef PRIVATE_MSG_H_ -#define PRIVATE_MSG_H_ - -int private_recv_msg(struct sw_chain *, const struct sender *, const void *); - -#endif diff --git a/openflow/datapath/table-hash.c b/openflow/datapath/table-hash.c deleted file mode 100644 index 8e5a97b7..00000000 --- a/openflow/datapath/table-hash.c +++ /dev/null @@ -1,489 +0,0 @@ -/* - * Distributed under the terms of the GNU GPL version 2. - * Copyright (c) 2007, 2008, 2009 The Board of Trustees of The Leland - * Stanford Junior University - */ - -#include "table.h" -#include "crc32.h" -#include "flow.h" -#include "datapath.h" - -#include -#include -#include -#include -#include - -static void *kmem_alloc(size_t); -static void *kmem_zalloc(size_t); -static void kmem_free(void *, size_t); - -struct sw_table_hash { - struct sw_table swt; - struct crc32 crc32; - unsigned int n_flows; - unsigned int bucket_mask; /* Number of buckets minus 1. */ - struct sw_flow **buckets; -}; - -static struct sw_flow **find_bucket(struct sw_table *swt, - const struct sw_flow_key *key) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - unsigned int crc = crc32_calculate(&th->crc32, key, - offsetof(struct sw_flow_key, wildcards)); - return &th->buckets[crc & th->bucket_mask]; -} - -static struct sw_flow *table_hash_lookup(struct sw_table *swt, - const struct sw_flow_key *key) -{ - struct sw_flow *flow = *find_bucket(swt, key); - return flow && flow_keys_equal(&flow->key, key) ? flow : NULL; -} - -static int table_hash_insert(struct sw_table *swt, struct sw_flow *flow) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - struct sw_flow **bucket; - int retval; - - if (flow->key.wildcards != 0) - return 0; - - bucket = find_bucket(swt, &flow->key); - if (*bucket == NULL) { - th->n_flows++; - rcu_assign_pointer(*bucket, flow); - retval = 1; - } else { - struct sw_flow *old_flow = *bucket; - if (flow_keys_equal(&old_flow->key, &flow->key)) { - rcu_assign_pointer(*bucket, flow); - flow_deferred_free(old_flow); - retval = 1; - } else { - retval = 0; - } - } - return retval; -} - -static int table_hash_modify(struct sw_table *swt, - const struct sw_flow_key *key, uint16_t priority, int strict, - const struct ofp_action_header *actions, size_t actions_len) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - unsigned int count = 0; - - if (key->wildcards == 0) { - struct sw_flow **bucket = find_bucket(swt, key); - struct sw_flow *flow = *bucket; - if (flow && flow_matches_desc(&flow->key, key, strict) - && (!strict || (flow->priority == priority))) { - flow_replace_acts(flow, actions, actions_len); - count = 1; - } - } else { - unsigned int i; - - for (i = 0; i <= th->bucket_mask; i++) { - struct sw_flow **bucket = &th->buckets[i]; - struct sw_flow *flow = *bucket; - if (flow && flow_matches_desc(&flow->key, key, strict) - && (!strict || (flow->priority == priority))) { - flow_replace_acts(flow, actions, actions_len); - count++; - } - } - } - return count; -} - -static int table_hash_has_conflict(struct sw_table *swt, - const struct sw_flow_key *key, - uint16_t priority, int strict) -{ - struct sw_table_hash *th = (struct sw_table_hash *)swt; - - if (key->wildcards == 0) { - struct sw_flow **bucket = find_bucket(swt, key); - struct sw_flow *flow = *bucket; - if (flow && flow_matches_2desc(&flow->key, key,strict) - && (flow->priority == priority)) { - return true; - } - } else { - unsigned int i; - - for (i = 0; i <= th->bucket_mask; i++) { - struct sw_flow **bucket = &th->buckets[i]; - struct sw_flow *flow = *bucket; - if (flow && flow_matches_2desc(&flow->key, key, strict) - && (flow->priority == priority)) { - return true; - } - } - } - return false; -} - -/* Caller must update n_flows. */ -static int do_delete(struct datapath *dp, struct sw_flow **bucket, - struct sw_flow *flow, enum ofp_flow_removed_reason reason) -{ - dp_send_flow_end(dp, flow, reason); - rcu_assign_pointer(*bucket, NULL); - flow_deferred_free(flow); - return 1; -} - -/* Returns number of deleted flows. We can ignore the priority - * argument, since all exact-match entries are the same (highest) - * priority. */ -static int table_hash_delete(struct datapath *dp, struct sw_table *swt, - const struct sw_flow_key *key, uint16_t out_port, - uint16_t priority, int strict) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - unsigned int count = 0; - - if (key->wildcards == 0) { - struct sw_flow **bucket = find_bucket(swt, key); - struct sw_flow *flow = *bucket; - if (flow && flow_keys_equal(&flow->key, key) - && flow_has_out_port(flow, out_port)) - count = do_delete(dp, bucket, flow, OFPRR_DELETE); - } else { - unsigned int i; - - for (i = 0; i <= th->bucket_mask; i++) { - struct sw_flow **bucket = &th->buckets[i]; - struct sw_flow *flow = *bucket; - if (flow && flow_matches_desc(&flow->key, key, strict) - && flow_has_out_port(flow, out_port)) - count += do_delete(dp, bucket, flow, OFPRR_DELETE); - } - } - th->n_flows -= count; - return count; -} - -static int table_hash_timeout(struct datapath *dp, struct sw_table *swt) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - unsigned int i; - int count = 0; - - if (mutex_lock_interruptible(&dp_mutex)) - return 0; - for (i = 0; i <= th->bucket_mask; i++) { - struct sw_flow **bucket = &th->buckets[i]; - struct sw_flow *flow = *bucket; - if (flow) { - int reason = flow_timeout(flow); - if (reason >= 0) { - count += do_delete(dp, bucket, flow, reason); - } - } - } - th->n_flows -= count; - mutex_unlock(&dp_mutex); - - return count; -} - -static void table_hash_destroy(struct sw_table *swt) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - unsigned int i; - for (i = 0; i <= th->bucket_mask; i++) - if (th->buckets[i]) - flow_free(th->buckets[i]); - kmem_free(th->buckets, (th->bucket_mask + 1) * sizeof *th->buckets); - kfree(th); -} - -static int table_hash_iterate(struct sw_table *swt, - const struct sw_flow_key *key, uint16_t out_port, - struct sw_table_position *position, - int (*callback)(struct sw_flow *, void *private), - void *private) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - - if (position->private[0] > th->bucket_mask) - return 0; - - if (key->wildcards == 0) { - struct sw_flow *flow; - int error; - - flow = table_hash_lookup(swt, key); - if (!flow || !flow_has_out_port(flow, out_port)) - return 0; - - error = callback(flow, private); - if (!error) - position->private[0] = -1; - return error; - } else { - int i; - - for (i = position->private[0]; i <= th->bucket_mask; i++) { - struct sw_flow *flow = th->buckets[i]; - if (flow && flow_matches_1wild(&flow->key, key) - && flow_has_out_port(flow, out_port)) { - int error = callback(flow, private); - if (error) { - position->private[0] = i; - return error; - } - } - } - return 0; - } -} -static void table_hash_stats(struct sw_table *swt, - struct sw_table_stats *stats) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - stats->name = "hash"; - stats->wildcards = 0; /* No wildcards are supported. */ - stats->n_flows = th->n_flows; - stats->max_flows = th->bucket_mask + 1; - stats->n_lookup = swt->n_lookup; - stats->n_matched = swt->n_matched; -} - -struct sw_table *table_hash_create(unsigned int polynomial, - unsigned int n_buckets) -{ - struct sw_table_hash *th; - struct sw_table *swt; - - th = kzalloc(sizeof *th, GFP_KERNEL); - if (th == NULL) - return NULL; - - BUG_ON(n_buckets & (n_buckets - 1)); - th->buckets = kmem_zalloc(n_buckets * sizeof *th->buckets); - if (th->buckets == NULL) { - printk(KERN_EMERG "failed to allocate %u buckets\n", - n_buckets); - kfree(th); - return NULL; - } - th->bucket_mask = n_buckets - 1; - - swt = &th->swt; - swt->lookup = table_hash_lookup; - swt->insert = table_hash_insert; - swt->has_conflict = table_hash_has_conflict; - swt->delete = table_hash_delete; - swt->timeout = table_hash_timeout; - swt->destroy = table_hash_destroy; - swt->iterate = table_hash_iterate; - swt->stats = table_hash_stats; - - crc32_init(&th->crc32, polynomial); - th->n_flows = 0; - - return swt; -} - -/* Double-hashing table. */ - -struct sw_table_hash2 { - struct sw_table swt; - struct sw_table *subtable[2]; -}; - -static struct sw_flow *table_hash2_lookup(struct sw_table *swt, - const struct sw_flow_key *key) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - int i; - - for (i = 0; i < 2; i++) { - struct sw_flow *flow = *find_bucket(t2->subtable[i], key); - if (flow && flow_keys_equal(&flow->key, key)) - return flow; - } - return NULL; -} - -static int table_hash2_insert(struct sw_table *swt, struct sw_flow *flow) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - - if (table_hash_insert(t2->subtable[0], flow)) - return 1; - return table_hash_insert(t2->subtable[1], flow); -} - -static int table_hash2_modify(struct sw_table *swt, - const struct sw_flow_key *key, uint16_t priority, int strict, - const struct ofp_action_header *actions, size_t actions_len) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - return (table_hash_modify(t2->subtable[0], key, priority, strict, - actions, actions_len) - + table_hash_modify(t2->subtable[1], key, priority, strict, - actions, actions_len)); -} - -static int table_hash2_has_conflict(struct sw_table *swt, - const struct sw_flow_key *key, - uint16_t priority, int strict) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - return (table_hash_has_conflict(t2->subtable[0], key, priority, strict) || - table_hash_has_conflict(t2->subtable[1], key, priority, strict)); -} - -static int table_hash2_delete(struct datapath *dp, struct sw_table *swt, - const struct sw_flow_key *key, - uint16_t out_port, - uint16_t priority, int strict) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - return (table_hash_delete(dp, t2->subtable[0], key, out_port, - priority, strict) - + table_hash_delete(dp, t2->subtable[1], key, out_port, - priority, strict)); -} - -static int table_hash2_timeout(struct datapath *dp, struct sw_table *swt) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - return (table_hash_timeout(dp, t2->subtable[0]) - + table_hash_timeout(dp, t2->subtable[1])); -} - -static void table_hash2_destroy(struct sw_table *swt) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - table_hash_destroy(t2->subtable[0]); - table_hash_destroy(t2->subtable[1]); - kfree(t2); -} - -static int table_hash2_iterate(struct sw_table *swt, - const struct sw_flow_key *key, uint16_t out_port, - struct sw_table_position *position, - int (*callback)(struct sw_flow *, void *), - void *private) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - int i; - - for (i = position->private[1]; i < 2; i++) { - int error = table_hash_iterate(t2->subtable[i], key, out_port, - position, callback, private); - if (error) { - return error; - } - position->private[0] = 0; - position->private[1]++; - } - return 0; -} - -static void table_hash2_stats(struct sw_table *swt, - struct sw_table_stats *stats) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - struct sw_table_stats substats[2]; - int i; - - for (i = 0; i < 2; i++) - table_hash_stats(t2->subtable[i], &substats[i]); - stats->name = "hash2"; - stats->wildcards = 0; /* No wildcards are supported. */ - stats->n_flows = substats[0].n_flows + substats[1].n_flows; - stats->max_flows = substats[0].max_flows + substats[1].max_flows; - stats->n_lookup = swt->n_lookup; - stats->n_matched = swt->n_matched; -} - -struct sw_table *table_hash2_create(unsigned int poly0, unsigned int buckets0, - unsigned int poly1, unsigned int buckets1) - -{ - struct sw_table_hash2 *t2; - struct sw_table *swt; - - t2 = kzalloc(sizeof *t2, GFP_KERNEL); - if (t2 == NULL) - return NULL; - - t2->subtable[0] = table_hash_create(poly0, buckets0); - if (t2->subtable[0] == NULL) - goto out_free_t2; - - t2->subtable[1] = table_hash_create(poly1, buckets1); - if (t2->subtable[1] == NULL) - goto out_free_subtable0; - - swt = &t2->swt; - swt->lookup = table_hash2_lookup; - swt->insert = table_hash2_insert; - swt->modify = table_hash2_modify; - swt->has_conflict = table_hash2_has_conflict; - swt->delete = table_hash2_delete; - swt->timeout = table_hash2_timeout; - swt->destroy = table_hash2_destroy; - swt->iterate = table_hash2_iterate; - swt->stats = table_hash2_stats; - - return swt; - -out_free_subtable0: - table_hash_destroy(t2->subtable[0]); -out_free_t2: - kfree(t2); - return NULL; -} - -/* From fs/xfs/linux-2.4/kmem.c. */ - -static void * -kmem_alloc(size_t size) -{ - void *ptr; - -#ifdef KMALLOC_MAX_SIZE - if (size > KMALLOC_MAX_SIZE) - return NULL; -#endif - ptr = kmalloc(size, GFP_KERNEL); - if (!ptr) { - ptr = vmalloc(size); - if (ptr) - printk(KERN_NOTICE "openflow: used vmalloc for %lu " - "bytes\n", (unsigned long)size); - } - return ptr; -} - -static void * -kmem_zalloc(size_t size) -{ - void *ptr = kmem_alloc(size); - if (ptr) - memset(ptr, 0, size); - return ptr; -} - -static void -kmem_free(void *ptr, size_t size) -{ - if (((unsigned long)ptr < VMALLOC_START) || - ((unsigned long)ptr >= VMALLOC_END)) { - kfree(ptr); - } else { - vfree(ptr); - } -} diff --git a/openflow/datapath/table-linear.c b/openflow/datapath/table-linear.c deleted file mode 100644 index 79a95dfb..00000000 --- a/openflow/datapath/table-linear.c +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Distributed under the terms of the GNU GPL version 2. - * Copyright (c) 2007, 2008, 2009 The Board of Trustees of The Leland - * Stanford Junior University - */ - -#include "table.h" -#include "flow.h" -#include "datapath.h" - -#include -#include -#include - -struct sw_table_linear { - struct sw_table swt; - - unsigned int max_flows; - unsigned int n_flows; - struct list_head flows; - struct list_head iter_flows; - unsigned long int next_serial; -}; - -static struct sw_flow *table_linear_lookup(struct sw_table *swt, - const struct sw_flow_key *key) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - struct sw_flow *flow; - list_for_each_entry_rcu (flow, &tl->flows, node) { - if (flow_matches_1wild(key, &flow->key)) - return flow; - } - return NULL; -} - -static int table_linear_insert(struct sw_table *swt, struct sw_flow *flow) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - struct sw_flow *f; - - - /* Loop through the existing list of entries. New entries will - * always be placed behind those with equal priority. Just replace - * any flows that match exactly. - */ - list_for_each_entry (f, &tl->flows, node) { - if (f->priority == flow->priority - && f->key.wildcards == flow->key.wildcards - && flow_matches_2wild(&f->key, &flow->key)) { - flow->serial = f->serial; - list_replace_rcu(&f->node, &flow->node); - list_replace_rcu(&f->iter_node, &flow->iter_node); - flow_deferred_free(f); - return 1; - } - - if (f->priority < flow->priority) - break; - } - - /* Make sure there's room in the table. */ - if (tl->n_flows >= tl->max_flows) { - return 0; - } - tl->n_flows++; - - /* Insert the entry immediately in front of where we're pointing. */ - flow->serial = tl->next_serial++; - list_add_tail_rcu(&flow->node, &f->node); - list_add_rcu(&flow->iter_node, &tl->iter_flows); - return 1; -} - -static int table_linear_modify(struct sw_table *swt, - const struct sw_flow_key *key, uint16_t priority, int strict, - const struct ofp_action_header *actions, size_t actions_len) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - struct sw_flow *flow; - unsigned int count = 0; - - list_for_each_entry (flow, &tl->flows, node) { - if (flow_matches_desc(&flow->key, key, strict) - && (!strict || (flow->priority == priority))) { - flow_replace_acts(flow, actions, actions_len); - count++; - } - } - return count; -} - -static int table_linear_has_conflict(struct sw_table *swt, - const struct sw_flow_key *key, uint16_t priority, int strict) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - struct sw_flow *flow; - - list_for_each_entry (flow, &tl->flows, node) { - if (flow_matches_2desc(&flow->key, key, strict) - && (flow->priority == priority)) { - return true; - } - } - return false; -} - -static int do_delete(struct datapath *dp, struct sw_table *swt, - struct sw_flow *flow, enum ofp_flow_removed_reason reason) -{ - dp_send_flow_end(dp, flow, reason); - list_del_rcu(&flow->node); - list_del_rcu(&flow->iter_node); - flow_deferred_free(flow); - return 1; -} - -static int table_linear_delete(struct datapath *dp, struct sw_table *swt, - const struct sw_flow_key *key, uint16_t out_port, - uint16_t priority, int strict) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - struct sw_flow *flow; - unsigned int count = 0; - - list_for_each_entry (flow, &tl->flows, node) { - if (flow_matches_desc(&flow->key, key, strict) - && flow_has_out_port(flow, out_port) - && (!strict || (flow->priority == priority))) - count += do_delete(dp, swt, flow, OFPRR_DELETE); - } - tl->n_flows -= count; - return count; -} - -static int table_linear_timeout(struct datapath *dp, struct sw_table *swt) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - struct sw_flow *flow; - int count = 0; - - if (mutex_lock_interruptible(&dp_mutex)) - return 0; - list_for_each_entry (flow, &tl->flows, node) { - int reason = flow_timeout(flow); - if (reason >= 0) { - count += do_delete(dp, swt, flow, reason); - } - } - tl->n_flows -= count; - mutex_unlock(&dp_mutex); - return count; -} - -static void table_linear_destroy(struct sw_table *swt) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - - while (!list_empty(&tl->flows)) { - struct sw_flow *flow = list_entry(tl->flows.next, - struct sw_flow, node); - list_del(&flow->node); - flow_free(flow); - } - kfree(tl); -} - -static int table_linear_iterate(struct sw_table *swt, - const struct sw_flow_key *key, uint16_t out_port, - struct sw_table_position *position, - int (*callback)(struct sw_flow *, void *), - void *private) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - struct sw_flow *flow; - unsigned long start; - - start = position->private[0]; - list_for_each_entry (flow, &tl->iter_flows, iter_node) { - if (flow->serial >= start - && flow_matches_2wild(key, &flow->key) - && flow_has_out_port(flow, out_port)) { - int error = callback(flow, private); - if (error) { - position->private[0] = flow->serial; - return error; - } - } - } - return 0; -} - -static void table_linear_stats(struct sw_table *swt, - struct sw_table_stats *stats) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - stats->name = "linear"; - stats->wildcards = OFPFW_ALL; - stats->n_flows = tl->n_flows; - stats->max_flows = tl->max_flows; - stats->n_lookup = swt->n_lookup; - stats->n_matched = swt->n_matched; -} - - -struct sw_table *table_linear_create(unsigned int max_flows) -{ - struct sw_table_linear *tl; - struct sw_table *swt; - - tl = kzalloc(sizeof *tl, GFP_KERNEL); - if (tl == NULL) - return NULL; - - swt = &tl->swt; - swt->lookup = table_linear_lookup; - swt->insert = table_linear_insert; - swt->modify = table_linear_modify; - swt->has_conflict = table_linear_has_conflict; - swt->delete = table_linear_delete; - swt->timeout = table_linear_timeout; - swt->destroy = table_linear_destroy; - swt->iterate = table_linear_iterate; - swt->stats = table_linear_stats; - - tl->max_flows = max_flows; - tl->n_flows = 0; - INIT_LIST_HEAD(&tl->flows); - INIT_LIST_HEAD(&tl->iter_flows); - tl->next_serial = 0; - - return swt; -} diff --git a/openflow/datapath/table.h b/openflow/datapath/table.h deleted file mode 100644 index 1cc90a01..00000000 --- a/openflow/datapath/table.h +++ /dev/null @@ -1,119 +0,0 @@ -/* Individual switching tables. Generally grouped together in a chain (see - * chain.h). */ - -#ifndef TABLE_H -#define TABLE_H 1 - -#include - -struct sw_flow; -struct sw_flow_key; -struct ofp_action_header; -struct datapath; - -/* Table statistics. */ -struct sw_table_stats { - const char *name; /* Human-readable name. */ - uint32_t wildcards; /* Bitmap of OFPFW_* wildcards that are - supported by the table. */ - unsigned int n_flows; /* Number of active flows. */ - unsigned int max_flows; /* Flow capacity. */ - unsigned long int n_lookup; /* Number of packets looked up. */ - unsigned long int n_matched; /* Number of packets that have hit. */ -}; - -/* Position within an iteration of a sw_table. - * - * The contents are private to the table implementation, except that a position - * initialized to all-zero-bits represents the start of a table. */ -struct sw_table_position { - unsigned long private[4]; -}; - -/* A single table of flows. - * - * All functions, except destroy, must be called holding the - * rcu_read_lock. destroy must be fully serialized. - */ -struct sw_table { - /* The number of packets that have been looked up and matched, - * respecitvely. To make these 100% accurate, they should be atomic. - * However, we're primarily concerned about speed. */ - unsigned long long n_lookup; - unsigned long long n_matched; - - /* Searches 'table' for a flow matching 'key', which must not have any - * wildcard fields. Returns the flow if successful, a null pointer - * otherwise. */ - struct sw_flow *(*lookup)(struct sw_table *table, - const struct sw_flow_key *key); - - /* Inserts 'flow' into 'table', replacing any duplicate flow. Returns - * 0 if successful or a negative error. Error can be due to an - * over-capacity table or because the flow is not one of the kind that - * the table accepts. - * - * If successful, 'flow' becomes owned by 'table', otherwise it is - * retained by the caller. */ - int (*insert)(struct sw_table *table, struct sw_flow *flow); - - /* Modifies the actions in 'table' that match 'key'. If 'strict' - * set, wildcards and priority must match. Returns the number of flows - * that were modified. */ - int (*modify)(struct sw_table *table, const struct sw_flow_key *key, - uint16_t priority, int strict, - const struct ofp_action_header *actions, size_t actions_len); - - /* Checks whether 'table' has an equal priotiry entry of thethat conflicts - * with 'key'. If 'strict' is set, wildcards must match. - * Returns the number of flows that were modified. */ - int (*has_conflict)(struct sw_table *table, const struct sw_flow_key *key, - uint16_t priority, int strict); - - /* Deletes from 'table' any and all flows that match 'key' from - * 'table'. If 'out_port' is not OFPP_NONE, then matching entries - * must have that port as an argument for an output action. If - * 'strict' is set, wildcards and priority must match. Returns the - * number of flows that were deleted. */ - int (*delete)(struct datapath *dp, struct sw_table *table, - const struct sw_flow_key *key, - uint16_t out_port, uint16_t priority, int strict); - - /* Performs timeout processing on all the flow entries in 'table'. - * Returns the number of flow entries deleted through expiration. */ - int (*timeout)(struct datapath *dp, struct sw_table *table); - - /* Destroys 'table', which must not have any users. */ - void (*destroy)(struct sw_table *table); - - /* Iterates through the flow entries in 'table', passing each one - * matches 'key' and output port 'out_port' to 'callback'. The - * callback function should return 0 to continue iteration or a - * nonzero error code to stop. The iterator function returns either - * 0 if the table iteration completed or the value returned by the - * callback function otherwise. - * - * The iteration starts at 'position', which may be initialized to - * all-zero-bits to iterate from the beginning of the table. If the - * iteration terminates due to an error from the callback function, - * 'position' is updated to a value that can be passed back to the - * iterator function to continue iteration later from the same position - * that caused the error (assuming that that flow entry has not been - * deleted in the meantime). */ - int (*iterate)(struct sw_table *table, - const struct sw_flow_key *key, uint16_t out_port, - struct sw_table_position *position, - int (*callback)(struct sw_flow *flow, void *private), - void *private); - - /* Dumps statistics for 'table' into 'stats'. */ - void (*stats)(struct sw_table *table, struct sw_table_stats *stats); -}; - -struct sw_table *table_hash_create(unsigned int polynomial, - unsigned int n_buckets); -struct sw_table *table_hash2_create(unsigned int poly0, unsigned int buckets0, - unsigned int poly1, unsigned int buckets1); -struct sw_table *table_linear_create(unsigned int max_flows); - -#endif /* table.h */ diff --git a/openflow/debian/.gitignore b/openflow/debian/.gitignore deleted file mode 100644 index 1df6fba1..00000000 --- a/openflow/debian/.gitignore +++ /dev/null @@ -1,38 +0,0 @@ -*.debhelper -*.debhelper.log -*.substvars -/automake.mk -/control -/corekeeper -/files -/nicira-switch -/openflow -/openflow-common -/openflow-common.copyright -/openflow-controller -/openflow-datapath-source -/openflow-dbg -/openflow-monitor -/openflow-monitor.copyright -/openflow-monitor.default -/openflow-monitor.dirs -/openflow-monitor.init -/openflow-monitor.install -/openflow-pki -/openflow-pki-server -/openflow-switch -/openflow-switch-config -/openflow-switch.copyright -/openflow-switchui -/openflow-switchui.copyright -/openflow-switchui.default -/openflow-switchui.dirs -/openflow-switchui.init -/openflow-switchui.install -/openflow-wdt -/openflow-wdt.copyright -/openflow-wdt.default -/openflow-wdt.dirs -/openflow-wdt.init -/openflow-wdt.install -/rules.ext diff --git a/openflow/debian/changelog b/openflow/debian/changelog deleted file mode 100644 index 235187e5..00000000 --- a/openflow/debian/changelog +++ /dev/null @@ -1,23 +0,0 @@ -openflow (1.0.0) unstable; urgency=low - - * Development version - - -- OpenFlow team Thu, 31 Dec 2009 23:59:59 -0800 - -openflow (0.9.0-rev1) unstable; urgency=low - - * Development version. - - -- OpenFlow team Fri, 04 Sep 2009 12:00:00 -0800 - -openflow (0.8.9-rev4) unstable; urgency=low - - * Develoment version. - - -- OpenFlow team Tue, 15 Sep 2009 12:00:00 -0800 - -openflow (0.8.1) unstable; urgency=low - - * Development version. - - -- OpenFlow team Mon, 19 Nov 2007 14:57:52 -0800 diff --git a/openflow/debian/commands/reconfigure b/openflow/debian/commands/reconfigure deleted file mode 100755 index a9610524..00000000 --- a/openflow/debian/commands/reconfigure +++ /dev/null @@ -1,128 +0,0 @@ -#! /usr/bin/perl - -use POSIX; -use strict; -use warnings; - -my $default = '/etc/default/openflow-switch'; - -my (%config) = load_config($default); -if (@ARGV) { - foreach my $arg (@ARGV) { - my ($key, $value) = $arg =~ /^([^=]+)=(.*)/ - or die "bad argument '$arg'\n"; - if ($value ne '') { - $config{$key} = $value; - } else { - delete $config{$key}; - } - } - save_config($default, %config); -} -print "$_=$config{$_}\n" foreach sort(keys(%config)); - -sub load_config { - my ($file) = @_; - - # Get the list of the variables that the shell sets automatically. - my (%auto_vars) = read_vars("set -a && env"); - - # Get the variables from $default. - my (%config) = read_vars("set -a && . '$default' && env"); - - # Subtract. - delete @config{keys %auto_vars}; - - return %config; -} - -sub read_vars { - my ($cmd) = @_; - local @ENV; - if (!open(VARS, '-|', $cmd)) { - print STDERR "$cmd: failed to execute: $!\n"; - return (); - } - my (%config); - while () { - my ($var, $value) = /^([^=]+)=(.*)$/ or next; - $config{$var} = $value; - } - close(VARS); - return %config; -} - -sub shell_escape { - local $_ = $_[0]; - if ($_ eq '') { - return '""'; - } elsif (m&^[-a-zA-Z0-9:./%^_+,]*$&) { - return $_; - } else { - s/'/'\\''/; - return "'$_'"; - } -} - -sub shell_assign { - my ($var, $value) = @_; - return $var . '=' . shell_escape($value); -} - -sub save_config { - my ($file, %config) = @_; - my (@lines); - if (open(FILE, '<', $file)) { - @lines = ; - chomp @lines; - close(FILE); - } - - # Replace all existing variable assignments. - for (my ($i) = 0; $i <= $#lines; $i++) { - local $_ = $lines[$i]; - my ($var, $value) = /^\s*([^=#]+)=(.*)$/ or next; - if (exists($config{$var})) { - $lines[$i] = shell_assign($var, $config{$var}); - delete $config{$var}; - } else { - $lines[$i] = "#$lines[$i]"; - } - } - - # Find a place to put any remaining variable assignments. - VAR: - for my $var (keys(%config)) { - my $assign = shell_assign($var, $config{$var}); - - # Replace the last commented-out variable assignment to $var, if any. - for (my ($i) = $#lines; $i >= 0; $i--) { - local $_ = $lines[$i]; - if (/^\s*#\s*$var=/) { - $lines[$i] = $assign; - next VAR; - } - } - - # Find a place to add the var: after the final commented line - # just after a line that contains "$var:". - for (my ($i) = 0; $i <= $#lines; $i++) { - if ($lines[$i] =~ /^\s*#\s*$var:/) { - for (my ($j) = $i + 1; $j <= $#lines; $j++) { - if ($lines[$j] !~ /^\s*#/) { - splice(@lines, $j, 0, $assign); - next VAR; - } - } - } - } - - # Just append it. - push(@lines, $assign); - } - - open(NEWFILE, '>', "$file.tmp") or die "$file.tmp: create: $!\n"; - print NEWFILE join('', map("$_\n", @lines)); - close(NEWFILE); - rename("$file.tmp", $file) or die "$file.tmp: rename to $file: $!\n"; -} diff --git a/openflow/debian/commands/update b/openflow/debian/commands/update deleted file mode 100755 index 545e3c23..00000000 --- a/openflow/debian/commands/update +++ /dev/null @@ -1,4 +0,0 @@ -#! /bin/sh -set -e -apt-get update -qy -apt-get upgrade -qy diff --git a/openflow/debian/compat b/openflow/debian/compat deleted file mode 100644 index 7ed6ff82..00000000 --- a/openflow/debian/compat +++ /dev/null @@ -1 +0,0 @@ -5 diff --git a/openflow/debian/control.in b/openflow/debian/control.in deleted file mode 100644 index 2e14410d..00000000 --- a/openflow/debian/control.in +++ /dev/null @@ -1,93 +0,0 @@ -Source: openflow -Section: net -Priority: extra -Maintainer: OpenFlow Team -Build-Depends: debhelper (>= 5), autoconf (>= 2.60), automake1.10 | automake1.11 | automake (>= 1.10), libssl-dev, pkg-config (>= 0.21), po-debconf, bzip2, openssl, libncurses5-dev, libpcre3-dev -Standards-Version: 3.7.3 - -Package: openflow-datapath-source -Architecture: all -Depends: module-assistant, bzip2, debhelper (>= 5.0.37) -Suggests: openflow-switch -Description: Source code for OpenFlow datapath Linux module - This package provides the OpenFlow datapath module source code that - is needed by the kernel-based OpenFlow switch. The kernel module can - be built from it using module-assistant or make-kpkg. README.Debian - in this package provides further instructions. - . - OpenFlow is a protocol for flow-based control over network switching. - -Package: openflow-common -Architecture: any -Depends: ${shlibs:Depends}, openssl -Description: OpenFlow common components - openflow-common provides components required by both openflow-switch - and openflow-controller. - . - OpenFlow is a protocol for flow-based control over network switching. - -Package: openflow-switch -Architecture: any -Suggests: openflow-datapath-module -Depends: ${shlibs:Depends}, ${misc:Depends}, openflow-common, dhcp3-client, module-init-tools, dmidecode, procps, debianutils -Description: OpenFlow switch implementations - openflow-switch provides the userspace components and utilities for - the OpenFlow kernel-based switch. - . - OpenFlow is a protocol for flow-based control over network switching. - -Package: openflow-switch-config -Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, openflow-switch, libwww-perl, libdigest-sha1-perl -Description: OpenFlow switch implementations - openflow-switch-config provides a utility for interactively configuring - the OpenFlow switch provided in the openflow-switch package. - . - OpenFlow is a protocol for flow-based control over network switching. - -Package: openflow-pki -Architecture: all -Depends: ${shlibs:Depends}, ${misc:Depends}, openflow-common -Description: OpenFlow public key infrastructure - openflow-pki provides PKI (public key infrastructure) support for - OpenFlow switches and controllers, reducing the risk of - man-in-the-middle attacks on the OpenFlow network infrastructure. - . - OpenFlow is a protocol for flow-based control over network switching. - -Package: openflow-pki-server -Architecture: all -Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, openflow-pki, apache2 -Description: OpenFlow public key infrastructure (HTTP server support) - openflow-pki-server provides HTTP access to the OpenFlow PKI (public - key infrastructure) maintained on the local machine by the - openflow-pki package. This HTTP access is needed for secure and - convenient OpenFlow switch setup using the ofp-switch-setup program - in the openflow-switch package. - . - OpenFlow is a protocol for flow-based control over network switching. - -Package: openflow-controller -Architecture: any -Depends: ${shlibs:Depends}, openflow-common, openflow-pki -Description: OpenFlow controller implementation - The OpenFlow controller enables OpenFlow switches that connect to it - to act as MAC-learning Ethernet switches. - . - OpenFlow is a protocol for flow-based control over network switching. - -Package: corekeeper -Architecture: all -Depends: tmpreaper -Description: Core file centralizer and reaper - The corekeeper package configures the system to dump all core files to - /var/log/core. It also deletes core files older than 7 days. - -Package: openflow-dbg -Architecture: any -Depends: ${shlibs:Depends} -Description: Debug symbols for OpenFlow packages - This package contains the debug symbols for all the other openflow-* - packages. Install it to debug one of them or to examine a core dump - produced by one of them. - diff --git a/openflow/debian/control.modules.in b/openflow/debian/control.modules.in deleted file mode 100644 index cc149cac..00000000 --- a/openflow/debian/control.modules.in +++ /dev/null @@ -1,19 +0,0 @@ -Source: openflow -Section: net -Priority: extra -Maintainer: OpenFlow Team -Build-Depends: debhelper (>= 5.0.37) -Standards-Version: 3.7.3 - -Package: openflow-datapath-module-_KVERS_ -Architecture: any -Recommends: kernel-image-_KVERS_, openflow-switch -Provides: openflow-datapath-module -Description: OpenFlow Linux datapath kernel module - This package contains the OpenFlow loadable datapath kernel modules for - the kernel-image-_KVERS_ package. - . - If you compiled a custom kernel, you will most likely need to compile - a custom version of this module as well. The openflow-datapath-source - package has been provided for this purpose. Refer to README.Debian - provided in that package for further instructions. diff --git a/openflow/debian/copyright b/openflow/debian/copyright deleted file mode 100644 index b369ec39..00000000 --- a/openflow/debian/copyright +++ /dev/null @@ -1,38 +0,0 @@ -Upstream Authors: - - The Board of Trustees of The Leland Stanford Junior University - -Copyright: - - Copyright (C) 2008 The Board of Trustees of The Leland Stanford - Junior University - -License: - - We are making the OpenFlow specification and associated documentation - (Software) available for public use and benefit with the expectation - that others will use, modify and enhance the Software and contribute - those enhancements back to the community. However, since we would like - to make the Software available for broadest use, with as few - restrictions as possible permission is hereby granted, free of charge, - to any person obtaining a copy of this Software to deal in the Software - under the copyrights without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - The name and trademarks of copyright holder(s) may NOT be used in - advertising or publicity pertaining to the Software or any derivatives - without specific, written prior permission. - diff --git a/openflow/debian/corekeeper.cron.daily b/openflow/debian/corekeeper.cron.daily deleted file mode 100755 index badc192d..00000000 --- a/openflow/debian/corekeeper.cron.daily +++ /dev/null @@ -1,5 +0,0 @@ -#! /bin/sh - -PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin - -tmpreaper 7d --mtime --all /var/log/core diff --git a/openflow/debian/corekeeper.init b/openflow/debian/corekeeper.init deleted file mode 100755 index 27d62a12..00000000 --- a/openflow/debian/corekeeper.init +++ /dev/null @@ -1,63 +0,0 @@ -#!/bin/sh -# -# Example init.d script with LSB support. -# -# Please read this init.d carefully and modify the sections to -# adjust it to the program you want to run. -# -# Copyright (c) 2007 Javier Fernandez-Sanguino -# -# This is free software; you may redistribute it and/or modify -# it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 2, -# or (at your option) any later version. -# -# This is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License with -# the Debian operating system, in /usr/share/common-licenses/GPL; if -# not, write to the Free Software Foundation, Inc., 59 Temple Place, -# Suite 330, Boston, MA 02111-1307 USA -# -### BEGIN INIT INFO -# Provides: corekeeper -# Required-Start: -# Required-Stop: -# Should-Start: $syslog -# Should-Stop: -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: Configure core file dump location -### END INIT INFO - -PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin - -. /lib/lsb/init-functions - -set -e - -case "$1" in - start) - log_daemon_msg "Initializing core dump location..." - if echo "/var/log/core/core.%e.%t" > /proc/sys/kernel/core_pattern - then - log_progress_msg "success" - log_end_msg 0 - exit 0 - else - log_end_msg 1 - exit 1 - fi - ;; - stop|restart|force-reload|status|reload) - exit 0 - ;; - *) - N=/etc/init.d/$NAME - echo "Usage: $N {start|stop|restart|force-reload|status}" >&2 - exit 1 - ;; -esac diff --git a/openflow/debian/dirs b/openflow/debian/dirs deleted file mode 100644 index ca882bbb..00000000 --- a/openflow/debian/dirs +++ /dev/null @@ -1,2 +0,0 @@ -usr/bin -usr/sbin diff --git a/openflow/debian/ofp-switch-setup b/openflow/debian/ofp-switch-setup deleted file mode 100755 index 5a999ab4..00000000 --- a/openflow/debian/ofp-switch-setup +++ /dev/null @@ -1,615 +0,0 @@ -#! /usr/bin/perl - -use POSIX; -use Debconf::Client::ConfModule ':all'; -use HTTP::Request; -use LWP::UserAgent; -use Digest::SHA1 'sha1_hex'; -use strict; -use warnings; - -# XXX should support configuring SWITCH_NETMASK and SWITCH_GATEWAY -# when the mode is in-band. - -my $debconf_owner = 'openflow-switch'; - -my $default = '/etc/default/openflow-switch'; -my $template = '/usr/share/openflow/switch/default.template'; -my $etc = '/etc/openflow-switch'; -my $rundir = '/var/run'; -my $privkey_file = "$etc/of0-privkey.pem"; -my $req_file = "$etc/of0-req.pem"; -my $cert_file = "$etc/of0-cert.pem"; -my $cacert_file = "$etc/cacert.pem"; -my $ofp_discover_pidfile = "$rundir/ofp-discover.pid"; - -my $ua = LWP::UserAgent->new; -$ua->timeout(10); -$ua->env_proxy; - -system("/etc/init.d/openflow-switch stop 1>&2"); -kill_ofp_discover(); - -version('2.0'); -capb('backup'); -title('OpenFlow Switch Setup'); - -my (%netdevs) = find_netdevs(); -db_subst('netdevs', 'choices', - join(', ', map($netdevs{$_}, sort(keys(%netdevs))))); -db_set('netdevs', join(', ', grep(!/IP/, values(%netdevs)))); - -my %oldconfig; -if (-e $default) { - %oldconfig = load_config($default); - - my (%map) = - (NETDEVS => sub { - db_set('netdevs', join(', ', map($netdevs{$_}, - grep(exists $netdevs{$_}, split)))) - }, - MODE => sub { - db_set('mode', - $_ eq 'in-band' || $_ eq 'out-of-band' ? $_ : 'discovery') - }, - SWITCH_IP => sub { db_set('switch-ip', $_) }, - CONTROLLER => sub { db_set('controller-vconn', $_) }, - PRIVKEY => sub { $privkey_file = $_ }, - CERT => sub { $cert_file = $_ }, - CACERT => sub { $cacert_file = $_ }, - ); - - for my $key (keys(%map)) { - local $_ = $oldconfig{$key}; - &{$map{$key}}() if defined && !/^\s*$/; - } -} elsif (-e $template) { - %oldconfig = load_config($template); -} - -my $cacert_preverified = -e $cacert_file; -my ($req, $req_fingerprint); - -my %options; - -my (@states) = - (sub { - # User backed up from first dialog box. - exit(10); - }, - sub { - # Prompt for ports to include in switch. - db_input('netdevs'); - return; - }, - sub { - # Validate the chosen ports. - my (@netdevs) = split(', ', db_get('netdevs')); - if (!@netdevs) { - # No ports chosen. Disable switch. - db_input('no-netdevs'); - return 'prev' if db_go(); - return 'done'; - } elsif (my (@conf_netdevs) = grep(/IP/, @netdevs)) { - # Point out that some ports have configured IP addresses. - db_subst('configured-netdevs', 'configured-netdevs', - join(', ', @conf_netdevs)); - db_input('configured-netdevs'); - return; - } else { - # Otherwise proceed. - return 'skip'; - } - }, - sub { - # Discovery or in-band or out-of-band controller? - db_input('mode'); - return; - }, - sub { - return 'skip' if db_get('mode') ne 'discovery'; - for (;;) { - # Notify user that we are going to do discovery. - db_input('discover'); - return 'prev' if db_go(); - print STDERR "Please wait up to 30 seconds for discovery...\n"; - - # Make sure that there's no running discovery process. - kill_ofp_discover(); - - # Do discovery. - %options = (); - open(DISCOVER, '-|', 'ofp-discover --timeout=30 --pidfile ' - . join(' ', netdev_names())); - while () { - chomp; - if (my ($name, $value) = /^([^=]+)=(.*)$/) { - if ($value =~ /^"(.*)"$/) { - $value = $1; - $value =~ s/\\([0-7][0-7][0-7])/chr($1)/ge; - } else { - $value =~ s/^(0x[[:xdigit:]]+)$/hex($1)/e; - $value = '' if $value eq 'empty'; - next if $value eq 'null'; # Shouldn't happen. - } - $options{$name} = $value; - } - last if /^$/; - } - - # Check results. - my $vconn = $options{'ofp-controller-vconn'}; - my $pki_uri = $options{'ofp-pki-uri'}; - return 'next' - if (defined($vconn) - && is_valid_vconn($vconn) - && (!is_ssl_vconn($vconn) || defined($pki_uri))); - - # Try again? - kill_ofp_discover(); - db_input('discovery-failure'); - db_go(); - } - }, - sub { - return 'skip' if db_get('mode') ne 'discovery'; - - my $vconn = $options{'ofp-controller-vconn'}; - my $pki_uri = $options{'ofp-pki-uri'}; - db_subst('discovery-success', 'controller-vconn', $vconn); - db_subst('discovery-success', - 'pki-uri', is_ssl_vconn($vconn) ? $pki_uri : "no PKI in use"); - db_input('discovery-success'); - return 'prev' if db_go(); - db_set('controller-vconn', $vconn); - db_set('pki-uri', $pki_uri); - return 'next'; - }, - sub { - return 'skip' if db_get('mode') ne 'in-band'; - for (;;) { - db_input('switch-ip'); - return 'prev' if db_go(); - - my $ip = db_get('switch-ip'); - return 'next' if $ip =~ /^dhcp|\d+\.\d+.\d+.\d+$/i; - - db_input('switch-ip-error'); - db_go(); - } - }, - sub { - return 'skip' if db_get('mode') eq 'discovery'; - for (;;) { - my $old_vconn = db_get('controller-vconn'); - db_input('controller-vconn'); - return 'prev' if db_go(); - - my $vconn = db_get('controller-vconn'); - if (is_valid_vconn($vconn)) { - if ($old_vconn ne $vconn || db_get('pki-uri') eq '') { - db_set('pki-uri', pki_host_to_uri($2)); - } - return 'next'; - } - - db_input('controller-vconn-error'); - db_go(); - } - }, - sub { - return 'skip' if !ssl_enabled(); - - if (! -e $privkey_file) { - my $old_umask = umask(077); - run_cmd("ofp-pki req $etc/of0 >&2 2>/dev/null"); - chmod(0644, $req_file) or die "$req_file: chmod: $!\n"; - umask($old_umask); - } - - if (! -e $cert_file) { - open(REQ, '<', $req_file) or die "$req_file: open: $!\n"; - $req = join('', ); - close(REQ); - $req_fingerprint = sha1_hex($req); - } - return 'skip'; - }, - sub { - return 'skip' if !ssl_enabled(); - return 'skip' if -e $cacert_file && -e $cert_file; - - db_input('pki-uri'); - return 'prev' if db_go(); - return; - }, - sub { - return 'skip' if !ssl_enabled(); - return 'skip' if -e $cacert_file; - - my $pki_uri = db_get('pki-uri'); - if ($pki_uri !~ /:/) { - $pki_uri = pki_host_to_uri($pki_uri); - } else { - # Trim trailing slashes. - $pki_uri =~ s%/+$%%; - } - db_set('pki-uri', $pki_uri); - - my $url = "$pki_uri/controllerca/cacert.pem"; - my $response = $ua->get($url, ':content_file' => $cacert_file); - if ($response->is_success) { - return 'next'; - } - - db_subst('fetch-cacert-failed', 'url', $url); - db_subst('fetch-cacert-failed', 'error', $response->status_line); - db_subst('fetch-cacert-failed', 'pki-uri', $pki_uri); - db_input('fetch-cacert-failed'); - db_go(); - return 'prev'; - }, - sub { - return 'skip' if !ssl_enabled(); - return 'skip' if -e $cert_file; - - for (;;) { - db_set('send-cert-req', 'yes'); - db_input('send-cert-req'); - return 'prev' if db_go(); - return 'next' if db_get('send-cert-req') eq 'no'; - - my $pki_uri = db_get('pki-uri'); - my ($pki_base_uri) = $pki_uri =~ m%^([^/]+://[^/]+)/%; - my $url = "$pki_base_uri/cgi-bin/ofp-pki-cgi"; - my $response = $ua->post($url, {'type' => 'switch', - 'req' => $req}); - return 'next' if $response->is_success; - - db_subst('send-cert-req-failed', 'url', $url); - db_subst('send-cert-req-failed', 'error', - $response->status_line); - db_subst('send-cert-req-failed', 'pki-uri', $pki_uri); - db_input('send-cert-req-failed'); - db_go(); - } - }, - sub { - return 'skip' if !ssl_enabled(); - return 'skip' if $cacert_preverified; - - my ($cacert_fingerprint) = x509_fingerprint($cacert_file); - db_subst('verify-controller-ca', 'fingerprint', $cacert_fingerprint); - db_input('verify-controller-ca'); - return 'prev' if db_go(); - return 'next' if db_get('verify-controller-ca') eq 'yes'; - unlink($cacert_file); - return 'prev'; - }, - sub { - return 'skip' if !ssl_enabled(); - return 'skip' if -e $cert_file; - - for (;;) { - db_set('fetch-switch-cert', 'yes'); - db_input('fetch-switch-cert'); - return 'prev' if db_go(); - exit(1) if db_get('fetch-switch-cert') eq 'no'; - - my $pki_uri = db_get('pki-uri'); - my $url = "$pki_uri/switchca/certs/$req_fingerprint-cert.pem"; - my $response = $ua->get($url, ':content_file' => $cert_file); - if ($response->is_success) { - return 'next'; - } - - db_subst('fetch-switch-cert-failed', 'url', $url); - db_subst('fetch-switch-cert-failed', 'error', - $response->status_line); - db_subst('fetch-switch-cert-failed', 'pki-uri', $pki_uri); - db_input('fetch-switch-cert-failed'); - db_go(); - } - }, - sub { - db_input('complete'); - db_go(); - return; - }, - sub { - return 'done'; - }, -); - -my $state = 1; -my $direction = 1; -for (;;) { - my $ret = &{$states[$state]}(); - $ret = db_go() ? 'prev' : 'next' if !defined $ret; - if ($ret eq 'next') { - $direction = 1; - } elsif ($ret eq 'prev') { - $direction = -1; - } elsif ($ret eq 'skip') { - # Nothing to do. - } elsif ($ret eq 'done') { - last; - } else { - die "unknown ret $ret"; - } - $state += $direction; -} - -my %config = %oldconfig; -$config{NETDEVS} = join(' ', netdev_names()); -$config{MODE} = db_get('mode'); -if (db_get('mode') eq 'in-band') { - $config{SWITCH_IP} = db_get('switch-ip'); -} -if (db_get('mode') ne 'discovery') { - $config{CONTROLLER} = db_get('controller-vconn'); -} -$config{PRIVKEY} = $privkey_file; -$config{CERT} = $cert_file; -$config{CACERT} = $cacert_file; -save_config($default, %config); - -dup2(2, 1); # Get stdout back. -kill_ofp_discover(); -system("/etc/init.d/openflow-switch start"); - -sub ssl_enabled { - return is_ssl_vconn(db_get('controller-vconn')); -} - -sub db_subst { - my ($question, $key, $value) = @_; - $question = "$debconf_owner/$question"; - my ($ret, $seen) = subst($question, $key, $value); - if ($ret && $ret != 30) { - die "Error substituting $value for $key in debconf question " - . "$question: $seen"; - } -} - -sub db_set { - my ($question, $value) = @_; - $question = "$debconf_owner/$question"; - my ($ret, $seen) = set($question, $value); - if ($ret && $ret != 30) { - die "Error setting debconf question $question to $value: $seen"; - } -} - -sub db_get { - my ($question) = @_; - $question = "$debconf_owner/$question"; - my ($ret, $seen) = get($question); - if ($ret) { - die "Error getting debconf question $question answer: $seen"; - } - return $seen; -} - -sub db_fset { - my ($question, $flag, $value) = @_; - $question = "$debconf_owner/$question"; - my ($ret, $seen) = fset($question, $flag, $value); - if ($ret && $ret != 30) { - die "Error setting debconf question $question flag $flag to $value: " - . "$seen"; - } -} - -sub db_fget { - my ($question, $flag) = @_; - $question = "$debconf_owner/$question"; - my ($ret, $seen) = fget($question, $flag); - if ($ret) { - die "Error getting debconf question $question flag $flag: $seen"; - } - return $seen; -} - -sub db_input { - my ($question) = @_; - db_fset($question, "seen", "false"); - - $question = "$debconf_owner/$question"; - my ($ret, $seen) = input('high', $question); - if ($ret && $ret != 30) { - die "Error requesting debconf question $question: $seen"; - } - return $ret; -} - -sub db_go { - my ($ret, $seen) = go(); - if (!defined($ret)) { - exit(1); # Cancel button was pushed. - } - if ($ret && $ret != 30) { - die "Error asking debconf questions: $seen"; - } - return $ret; -} - -sub run_cmd { - my ($cmd) = @_; - return if system($cmd) == 0; - - if ($? == -1) { - die "$cmd: failed to execute: $!\n"; - } elsif ($? & 127) { - die sprintf("$cmd: child died with signal %d, %s coredump\n", - ($? & 127), ($? & 128) ? 'with' : 'without'); - } else { - die sprintf("$cmd: child exited with value %d\n", $? >> 8); - } -} - -sub x509_fingerprint { - my ($file) = @_; - my $cmd = "openssl x509 -noout -in $file -fingerprint"; - open(OPENSSL, '-|', $cmd) or die "$cmd: failed to execute: $!\n"; - my $line = ; - close(OPENSSL); - my ($fingerprint) = $line =~ /SHA1 Fingerprint=(.*)/; - return $line if !defined $fingerprint; - $fingerprint =~ s/://g; - return $fingerprint; -} - -sub find_netdevs { - my ($netdev, %netdevs); - open(IFCONFIG, "/sbin/ifconfig -a|") or die "ifconfig failed: $!"; - while () { - if (my ($nd) = /^([^\s]+)/) { - $netdev = $nd; - $netdevs{$netdev} = "$netdev"; - if (my ($hwaddr) = /HWaddr (\S+)/) { - $netdevs{$netdev} .= " (MAC: $hwaddr)"; - } - } elsif (my ($ip4) = /^\s*inet addr:(\S+)/) { - $netdevs{$netdev} .= " (IP: $ip4)"; - } elsif (my ($ip6) = /^\s*inet6 addr:(\S+)/) { - $netdevs{$netdev} .= " (IPv6: $ip6)"; - } - } - foreach my $nd (keys(%netdevs)) { - delete $netdevs{$nd} if $nd eq 'lo' || $nd =~ /^wmaster/; - } - close(IFCONFIG); - return %netdevs; -} - -sub load_config { - my ($file) = @_; - - # Get the list of the variables that the shell sets automatically. - my (%auto_vars) = read_vars("set -a && env"); - - # Get the variables from $default. - my (%config) = read_vars("set -a && . '$default' && env"); - - # Subtract. - delete @config{keys %auto_vars}; - - return %config; -} - -sub read_vars { - my ($cmd) = @_; - local @ENV; - if (!open(VARS, '-|', $cmd)) { - print STDERR "$cmd: failed to execute: $!\n"; - return (); - } - my (%config); - while () { - my ($var, $value) = /^([^=]+)=(.*)$/ or next; - $config{$var} = $value; - } - close(VARS); - return %config; -} - -sub shell_escape { - local $_ = $_[0]; - if ($_ eq '') { - return '""'; - } elsif (m&^[-a-zA-Z0-9:./%^_+,]*$&) { - return $_; - } else { - s/'/'\\''/; - return "'$_'"; - } -} - -sub shell_assign { - my ($var, $value) = @_; - return $var . '=' . shell_escape($value); -} - -sub save_config { - my ($file, %config) = @_; - my (@lines); - if (open(FILE, '<', $file)) { - @lines = ; - chomp @lines; - close(FILE); - } - - # Replace all existing variable assignments. - for (my ($i) = 0; $i <= $#lines; $i++) { - local $_ = $lines[$i]; - my ($var, $value) = /^\s*([^=#]+)=(.*)$/ or next; - if (exists($config{$var})) { - $lines[$i] = shell_assign($var, $config{$var}); - delete $config{$var}; - } else { - $lines[$i] = "#$lines[$i]"; - } - } - - # Find a place to put any remaining variable assignments. - VAR: - for my $var (keys(%config)) { - my $assign = shell_assign($var, $config{$var}); - - # Replace the last commented-out variable assignment to $var, if any. - for (my ($i) = $#lines; $i >= 0; $i--) { - local $_ = $lines[$i]; - if (/^\s*#\s*$var=/) { - $lines[$i] = $assign; - next VAR; - } - } - - # Find a place to add the var: after the final commented line - # just after a line that contains "$var:". - for (my ($i) = 0; $i <= $#lines; $i++) { - if ($lines[$i] =~ /^\s*#\s*$var:/) { - for (my ($j) = $i + 1; $j <= $#lines; $j++) { - if ($lines[$j] !~ /^\s*#/) { - splice(@lines, $j, 0, $assign); - next VAR; - } - } - } - } - - # Just append it. - push(@lines, $assign); - } - - open(NEWFILE, '>', "$file.tmp") or die "$file.tmp: create: $!\n"; - print NEWFILE join('', map("$_\n", @lines)); - close(NEWFILE); - rename("$file.tmp", $file) or die "$file.tmp: rename to $file: $!\n"; -} - -sub pki_host_to_uri { - my ($pki_host) = @_; - return "http://$pki_host/openflow/pki"; -} - -sub kill_ofp_discover { - # Delegate this to a subprocess because there is no portable way - # to invoke fcntl(F_GETLK) from Perl. - system("ofp-kill --force $ofp_discover_pidfile"); -} - -sub netdev_names { - return map(/^(\S+)/, split(', ', db_get('netdevs'))); -} - -sub is_valid_vconn { - my ($vconn) = @_; - return scalar($vconn =~ /^(tcp|ssl):([^:]+)(:.*)?/); -} - -sub is_ssl_vconn { - my ($vconn) = @_; - return scalar($vconn =~ /^ssl:/); -} diff --git a/openflow/debian/ofp-switch-setup.8 b/openflow/debian/ofp-switch-setup.8 deleted file mode 100644 index 50904cfb..00000000 --- a/openflow/debian/ofp-switch-setup.8 +++ /dev/null @@ -1,41 +0,0 @@ -.TH ofp-switch-setup 8 "June 2008" "OpenFlow" "OpenFlow Manual" - -.SH NAME -ofp\-switch\-setup \- interactive setup for OpenFlow switch - -.SH SYNOPSIS -.B ofp\-switch\-setup - -.SH DESCRIPTION -The \fBofp\-switch\-setup\fR program is an interactive program that -assists the system administrator in configuring an OpenFlow switch, -including the underlying public key infrastructure (PKI). - -.SH OPTIONS -ofp\-switch\-setup does not accept any command-line options. - -.SH FILES -.IP /etc/default/openflow-switch -Main configuration file for OpenFlow switch. - -.IP /etc/openflow-switch/cacert.pem -Default location of CA certificate for OpenFlow controllers. - -.IP /etc/openflow-switch/of0-cert.pem -Default location of certificate for the OpenFlow switch's private key. - -.IP /etc/openflow-switch/of0-privkey.pem -Default location of the OpenFlow switch's private key. This file -should be readable only by \fBroot\fR. - -.IP /etc/openflow-switch/of0-req.pem -Default location of certificate request for the OpenFlow switch's -certificate. This file is not used after the signed certificate -(typically \fB/etc/openflow-switch/of0-cert.pem\fR, above) has been -obtained from the OpenFlow PKI server. - -.SH "SEE ALSO" - -.BR ofp-pki (8), -.BR dpctl (8), -.BR secchan (8) diff --git a/openflow/debian/openflow-common.dirs b/openflow/debian/openflow-common.dirs deleted file mode 100644 index 527fe313..00000000 --- a/openflow/debian/openflow-common.dirs +++ /dev/null @@ -1 +0,0 @@ -var/log/openflow diff --git a/openflow/debian/openflow-common.install b/openflow/debian/openflow-common.install deleted file mode 100644 index eed7413e..00000000 --- a/openflow/debian/openflow-common.install +++ /dev/null @@ -1,3 +0,0 @@ -_debian/utilities/ofp-parse-leaks usr/bin -_debian/utilities/ofp-pki usr/sbin -_debian/utilities/vlogconf usr/sbin diff --git a/openflow/debian/openflow-common.manpages b/openflow/debian/openflow-common.manpages deleted file mode 100644 index fbb88201..00000000 --- a/openflow/debian/openflow-common.manpages +++ /dev/null @@ -1,2 +0,0 @@ -_debian/utilities/vlogconf.8 -_debian/utilities/ofp-pki.8 diff --git a/openflow/debian/openflow-controller.README.Debian b/openflow/debian/openflow-controller.README.Debian deleted file mode 100644 index 19d5cb9b..00000000 --- a/openflow/debian/openflow-controller.README.Debian +++ /dev/null @@ -1,10 +0,0 @@ -README.Debian for openflow-controller -------------------------------------- - -* To (re)configure the controller, edit /etc/default/openflow-controller - and run "/etc/init.d/openflow-controller restart". - -* To enable OpenFlow switches to automatically discover the location - of the controller, you must install and configure a DHCP server. - The secchan(8) manpage (found in the openflow-switch package) gives - a working example configuration file for the ISC DHCP server. diff --git a/openflow/debian/openflow-controller.default b/openflow/debian/openflow-controller.default deleted file mode 100644 index 3b84b62a..00000000 --- a/openflow/debian/openflow-controller.default +++ /dev/null @@ -1,33 +0,0 @@ -# This is a POSIX shell fragment -*- sh -*- - -# LISTEN: What OpenFlow connection methods should the controller listen on? -# -# This is a space-delimited list of connection methods: -# -# * "pssl:[PORT]": Listen for SSL connections on the specified PORT -# (default: 6633). The private key, certificate, and CA certificate -# must be specified below. -# -# * "pctp:[PORT]": Listen for TCP connections on the specified PORT -# (default: 6633). Not recommended for security reasons. -# -# * "nl:DP_IDX": Listen on local datapath DP_IDX. Used only if this -# machine is also an OpenFlow switch and not running the secure -# channel, and only if you know what you're doing. -# -LISTEN="pssl:" - -# PRIVKEY: Name of file containing controller's private key. -# Required if SSL enabled. -PRIVKEY=/etc/openflow-controller/privkey.pem - -# CERT: Name of file containing certificate for private key. -# Required if SSL enabled. -CERT=/etc/openflow-controller/cert.pem - -# CACERT: Name of file containing switch CA certificate. -# Required if SSL enabled. -CACERT=/etc/openflow-controller/cacert.pem - -# Additional options to pass to controller, e.g. "--hub" -DAEMON_OPTS="" diff --git a/openflow/debian/openflow-controller.dirs b/openflow/debian/openflow-controller.dirs deleted file mode 100644 index 0a19a9fc..00000000 --- a/openflow/debian/openflow-controller.dirs +++ /dev/null @@ -1 +0,0 @@ -etc/openflow-controller diff --git a/openflow/debian/openflow-controller.init b/openflow/debian/openflow-controller.init deleted file mode 100755 index 121fd76b..00000000 --- a/openflow/debian/openflow-controller.init +++ /dev/null @@ -1,269 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2007 Javier Fernandez-Sanguino -# -# This is free software; you may redistribute it and/or modify -# it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 2, -# or (at your option) any later version. -# -# This is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License with -# the Debian operating system, in /usr/share/common-licenses/GPL; if -# not, write to the Free Software Foundation, Inc., 59 Temple Place, -# Suite 330, Boston, MA 02111-1307 USA -# -### BEGIN INIT INFO -# Provides: openflow-controller -# Required-Start: $network $local_fs -# Required-Stop: -# Should-Start: $named -# Should-Stop: -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: OpenFlow controller -### END INIT INFO - -PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin - -DAEMON=/usr/sbin/controller # Introduce the server's location here -NAME=controller # Introduce the short server's name here -DESC=controller # Introduce a short description here -LOGDIR=/var/log/openflow # Log directory to use - -PIDFILE=/var/run/$NAME.pid - -test -x $DAEMON || exit 0 - -. /lib/lsb/init-functions - -# Default options, these can be overriden by the information -# at /etc/default/$NAME -DAEMON_OPTS="" # Additional options given to the server - -DODTIME=10 # Time to wait for the server to die, in seconds - # If this value is set too low you might not - # let some servers to die gracefully and - # 'restart' will not work - -LOGFILE=$LOGDIR/$NAME.log # Server logfile -#DAEMONUSER= # User to run the daemons as. If this value - # is set start-stop-daemon will chuid the server - -# Include defaults if available -default=/etc/default/openflow-controller -if [ -f $default ] ; then - . $default -fi - -# Check that the user exists (if we set a user) -# Does the user exist? -if [ -n "$DAEMONUSER" ] ; then - if getent passwd | grep -q "^$DAEMONUSER:"; then - # Obtain the uid and gid - DAEMONUID=`getent passwd |grep "^$DAEMONUSER:" | awk -F : '{print $3}'` - DAEMONGID=`getent passwd |grep "^$DAEMONUSER:" | awk -F : '{print $4}'` - else - log_failure_msg "The user $DAEMONUSER, required to run $NAME does not exist." - exit 1 - fi -fi - - -set -e - -running_pid() { -# Check if a given process pid's cmdline matches a given name - pid=$1 - name=$2 - [ -z "$pid" ] && return 1 - [ ! -d /proc/$pid ] && return 1 - cmd=`cat /proc/$pid/cmdline | tr "\000" "\n"|head -n 1 |cut -d : -f 1` - # Is this the expected server - [ "$cmd" != "$name" ] && return 1 - return 0 -} - -running() { -# Check if the process is running looking at /proc -# (works for all users) - - # No pidfile, probably no daemon present - [ ! -f "$PIDFILE" ] && return 1 - pid=`cat $PIDFILE` - running_pid $pid $DAEMON || return 1 - return 0 -} - -start_server() { - if [ -z "$LISTEN" ]; then - echo "$default: No connection methods configured, controller disabled" >&2 - exit 0 - fi - - SSL_OPTS= - case $LISTEN in - *ssl*) - : ${PRIVKEY:=/etc/openflow-controller/privkey.pem} - : ${CERT:=/etc/openflow-controller/cert.pem} - : ${CACERT:=/etc/openflow-controller/cacert.pem} - if test ! -e "$PRIVKEY" || test ! -e "$CERT" || - test ! -e "$CACERT"; then - if test ! -e "$PRIVKEY"; then - echo "$PRIVKEY: private key missing" >&2 - fi - if test ! -e "$CERT"; then - echo "$CERT: certificate for private key missing" >&2 - fi - if test ! -e "$CACERT"; then - echo "$CACERT: CA certificate missing" >&2 - fi - exit 1 - fi - SSL_OPTS="--private-key=$PRIVKEY --certificate=$CERT --ca-cert=$CACERT" - ;; - esac - -# Start the process using the wrapper - if [ -z "$DAEMONUSER" ] ; then - start-stop-daemon --start --pidfile $PIDFILE \ - --exec $DAEMON -- --detach --pidfile=$PIDFILE \ - $LISTEN $DAEMON_OPTS $SSL_OPTS - errcode=$? - else -# if we are using a daemonuser then change the user id - start-stop-daemon --start --quiet --pidfile $PIDFILE \ - --chuid $DAEMONUSER --exec $DAEMON -- \ - --detach --pidfile=$PIDFILE $LISTEN $DAEMON_OPTS \ - $SSL_OPTS - errcode=$? - fi - return $errcode -} - -stop_server() { -# Stop the process using the wrapper - if [ -z "$DAEMONUSER" ] ; then - start-stop-daemon --stop --quiet --pidfile $PIDFILE \ - --exec $DAEMON - errcode=$? - else -# if we are using a daemonuser then look for process that match - start-stop-daemon --stop --quiet --pidfile $PIDFILE \ - --user $DAEMONUSER --exec $DAEMON - errcode=$? - fi - - return $errcode -} - -reload_server() { - [ ! -f "$PIDFILE" ] && return 1 - pid=`cat $PIDFILE` # This is the daemon's pid - # Send a SIGHUP - kill -1 $pid - return $? -} - -force_stop() { -# Force the process to die killing it manually - [ ! -e "$PIDFILE" ] && return - if running ; then - kill -15 $pid - # Is it really dead? - sleep "$DIETIME"s - if running ; then - kill -9 $pid - sleep "$DIETIME"s - if running ; then - echo "Cannot kill $NAME (pid=$pid)!" - exit 1 - fi - fi - fi - rm -f $PIDFILE -} - - -case "$1" in - start) - log_daemon_msg "Starting $DESC " "$NAME" - # Check if it's running first - if running ; then - log_progress_msg "apparently already running" - log_end_msg 0 - exit 0 - fi - if start_server && running ; then - # It's ok, the server started and is running - log_end_msg 0 - else - # Either we could not start it or it is not running - # after we did - # NOTE: Some servers might die some time after they start, - # this code does not try to detect this and might give - # a false positive (use 'status' for that) - log_end_msg 1 - fi - ;; - stop) - log_daemon_msg "Stopping $DESC" "$NAME" - if running ; then - # Only stop the server if we see it running - stop_server - log_end_msg $? - else - # If it's not running don't do anything - log_progress_msg "apparently not running" - log_end_msg 0 - exit 0 - fi - ;; - force-stop) - # First try to stop gracefully the program - $0 stop - if running; then - # If it's still running try to kill it more forcefully - log_daemon_msg "Stopping (force) $DESC" "$NAME" - force_stop - log_end_msg $? - fi - ;; - restart|force-reload) - log_daemon_msg "Restarting $DESC" "$NAME" - stop_server - # Wait some sensible amount, some server need this - [ -n "$DIETIME" ] && sleep $DIETIME - start_server - running - log_end_msg $? - ;; - status) - - log_daemon_msg "Checking status of $DESC" "$NAME" - if running ; then - log_progress_msg "running" - log_end_msg 0 - else - log_progress_msg "apparently not running" - log_end_msg 1 - exit 1 - fi - ;; - # Use this if the daemon cannot reload - reload) - log_warning_msg "Reloading $NAME daemon: not implemented, as the daemon" - log_warning_msg "cannot re-read the config file (use restart)." - ;; - *) - N=/etc/init.d/$NAME - echo "Usage: $N {start|stop|force-stop|restart|force-reload|status}" >&2 - exit 1 - ;; -esac - -exit 0 diff --git a/openflow/debian/openflow-controller.install b/openflow/debian/openflow-controller.install deleted file mode 100644 index 3932ab6a..00000000 --- a/openflow/debian/openflow-controller.install +++ /dev/null @@ -1 +0,0 @@ -_debian/controller/controller usr/sbin diff --git a/openflow/debian/openflow-controller.manpages b/openflow/debian/openflow-controller.manpages deleted file mode 100644 index 3fbaaeaf..00000000 --- a/openflow/debian/openflow-controller.manpages +++ /dev/null @@ -1 +0,0 @@ -_debian/controller/controller.8 diff --git a/openflow/debian/openflow-controller.postinst b/openflow/debian/openflow-controller.postinst deleted file mode 100755 index 93e39116..00000000 --- a/openflow/debian/openflow-controller.postinst +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/sh -# postinst script for openflow-controller -# -# see: dh_installdeb(1) - -set -e - -# summary of how this script can be called: -# * `configure' -# * `abort-upgrade' -# * `abort-remove' `in-favour' -# -# * `abort-remove' -# * `abort-deconfigure' `in-favour' -# `removing' -# -# for details, see http://www.debian.org/doc/debian-policy/ or -# the debian-policy package - - -case "$1" in - configure) - cd /etc/openflow-controller - if ! test -e cacert.pem; then - ln -s /usr/share/openflow/pki/switchca/cacert.pem cacert.pem - fi - if ! test -e privkey.pem || ! test -e cert.pem; then - oldumask=$(umask) - umask 077 - ofp-pki req+sign tmp controller >/dev/null - mv tmp-privkey.pem privkey.pem - mv tmp-cert.pem cert.pem - mv tmp-req.pem req.pem - chmod go+r cert.pem req.pem - umask $oldumask - fi - ;; - - abort-upgrade|abort-remove|abort-deconfigure) - ;; - - *) - echo "postinst called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -#DEBHELPER# - -exit 0 - - diff --git a/openflow/debian/openflow-datapath-module-_KVERS_.postinst.modules.in b/openflow/debian/openflow-datapath-module-_KVERS_.postinst.modules.in deleted file mode 100755 index 6974e13a..00000000 --- a/openflow/debian/openflow-datapath-module-_KVERS_.postinst.modules.in +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh -# postinst script for #PACKAGE# -# -# see: dh_installdeb(1) - -set -e - -depmod -a - -#DEBHELPER# - -# If the switch is running, restart it. This ensures that we are using the -# latest kernel module, because the init script will unload and reload the -# module. -# -# (Ideally we'd only want to do this if this package corresponds to the -# running kernel, but I don't know a reliable way to check.) -INIT=/etc/init.d/openflow-switch -if test -x $INIT && $INIT status; then - $INIT restart || true -fi - -exit 0 - - diff --git a/openflow/debian/openflow-datapath-source.README.Debian b/openflow/debian/openflow-datapath-source.README.Debian deleted file mode 100644 index 59965df9..00000000 --- a/openflow/debian/openflow-datapath-source.README.Debian +++ /dev/null @@ -1,31 +0,0 @@ -OpenFlow for Debian -------------------- - -* How do I build this module the Debian way? - - - Building with module-assistant: - - $ module-assistant auto-install openflow - or - $ m-a a-i openflow - - If kernel source or headers are in a non-standard directory, add - the option -k /path/to/kernel/source with the correct path. - - - Building with make-kpkg - - $ cd /usr/src/ - $ tar jxvf openflow.tar.bz2 - $ cd /usr/src/kernel-source-2.6.9 - $ make-kpkg --added-modules=openflow modules - - - Building without make-kpkg - - $ cd /usr/src/ - $ tar jxvf openflow.tar.bz2 - $ cd modules/openflow - $ fakeroot debian/rules kdist_image - - If you run this as root, fakeroot is not needed. - - -- OpenFlow Team , Thu, 12 Jun 2008 16:42:38 -0700 diff --git a/openflow/debian/openflow-datapath-source.copyright b/openflow/debian/openflow-datapath-source.copyright deleted file mode 100644 index f7bcdda3..00000000 --- a/openflow/debian/openflow-datapath-source.copyright +++ /dev/null @@ -1,16 +0,0 @@ -Upstream Authors: - - The Board of Trustees of The Leland Stanford Junior University - -Copyright: - - Copyright (C) 2008 The Board of Trustees of The Leland Stanford - Junior University - -License: - - Files in the datapath/ and its sub-directories are covered under the GNU - General Public License Version 2. - - On Debian systems, the complete text of the GNU General - Public License can be found in `/usr/share/common-licenses/GPL'. diff --git a/openflow/debian/openflow-datapath-source.dirs b/openflow/debian/openflow-datapath-source.dirs deleted file mode 100644 index 4ddf234a..00000000 --- a/openflow/debian/openflow-datapath-source.dirs +++ /dev/null @@ -1 +0,0 @@ -usr/src/modules/openflow-datapath/debian diff --git a/openflow/debian/openflow-datapath-source.install b/openflow/debian/openflow-datapath-source.install deleted file mode 100644 index a74f13dc..00000000 --- a/openflow/debian/openflow-datapath-source.install +++ /dev/null @@ -1,6 +0,0 @@ -debian/changelog usr/src/modules/openflow-datapath/debian -debian/control usr/src/modules/openflow-datapath/debian -debian/compat usr/src/modules/openflow-datapath/debian -debian/*.modules.in usr/src/modules/openflow-datapath/debian -debian/rules usr/src/modules/openflow-datapath/debian -_debian/openflow.tar.gz usr/src/modules/openflow-datapath diff --git a/openflow/debian/openflow-pki-server.apache2 b/openflow/debian/openflow-pki-server.apache2 deleted file mode 100644 index a341c508..00000000 --- a/openflow/debian/openflow-pki-server.apache2 +++ /dev/null @@ -1 +0,0 @@ -Alias /openflow/pki/ /usr/share/openflow/pki/ diff --git a/openflow/debian/openflow-pki-server.dirs b/openflow/debian/openflow-pki-server.dirs deleted file mode 100644 index 7307777b..00000000 --- a/openflow/debian/openflow-pki-server.dirs +++ /dev/null @@ -1 +0,0 @@ -etc/apache2/sites-available diff --git a/openflow/debian/openflow-pki-server.install b/openflow/debian/openflow-pki-server.install deleted file mode 100644 index cd530ca4..00000000 --- a/openflow/debian/openflow-pki-server.install +++ /dev/null @@ -1 +0,0 @@ -_debian/utilities/ofp-pki-cgi usr/lib/cgi-bin diff --git a/openflow/debian/openflow-pki-server.postinst b/openflow/debian/openflow-pki-server.postinst deleted file mode 100755 index d161a98a..00000000 --- a/openflow/debian/openflow-pki-server.postinst +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/sh -# postinst script for openflow -# -# see: dh_installdeb(1) - -set -e - -# summary of how this script can be called: -# * `configure' -# * `abort-upgrade' -# * `abort-remove' `in-favour' -# -# * `abort-remove' -# * `abort-deconfigure' `in-favour' -# `removing' -# -# for details, see http://www.debian.org/doc/debian-policy/ or -# the debian-policy package - -case "$1" in - configure) - # Enable site under Apache. - a2ensite openflow-pki >/dev/null - if command -v invoke-rc.d >/dev/null 2>&1; then - invoke-rc.d apache2 force-reload || : - else - [ -x /etc/init.d/apache2 ] && /etc/init.d/apache2 force-reload || : - fi - ;; - - abort-upgrade|abort-remove|abort-deconfigure) - ;; - - *) - echo "postinst called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -#DEBHELPER# - -exit 0 - - diff --git a/openflow/debian/openflow-pki.postinst b/openflow/debian/openflow-pki.postinst deleted file mode 100755 index 5cf6515d..00000000 --- a/openflow/debian/openflow-pki.postinst +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/sh -# postinst script for openflow -# -# see: dh_installdeb(1) - -set -e - -# summary of how this script can be called: -# * `configure' -# * `abort-upgrade' -# * `abort-remove' `in-favour' -# -# * `abort-remove' -# * `abort-deconfigure' `in-favour' -# `removing' -# -# for details, see http://www.debian.org/doc/debian-policy/ or -# the debian-policy package - -case "$1" in - configure) - # Create certificate authorities. - if test ! -d /usr/share/openflow/pki; then - ofp-pki init - fi - ;; - - abort-upgrade|abort-remove|abort-deconfigure) - ;; - - *) - echo "postinst called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -#DEBHELPER# - -exit 0 - - diff --git a/openflow/debian/openflow-switch-config.dirs b/openflow/debian/openflow-switch-config.dirs deleted file mode 100644 index 881ded8a..00000000 --- a/openflow/debian/openflow-switch-config.dirs +++ /dev/null @@ -1 +0,0 @@ -/usr/share/lintian/overrides diff --git a/openflow/debian/openflow-switch-config.install b/openflow/debian/openflow-switch-config.install deleted file mode 100644 index 75c50083..00000000 --- a/openflow/debian/openflow-switch-config.install +++ /dev/null @@ -1 +0,0 @@ -debian/ofp-switch-setup usr/sbin diff --git a/openflow/debian/openflow-switch-config.manpages b/openflow/debian/openflow-switch-config.manpages deleted file mode 100644 index e176dad9..00000000 --- a/openflow/debian/openflow-switch-config.manpages +++ /dev/null @@ -1 +0,0 @@ -debian/ofp-switch-setup.8 diff --git a/openflow/debian/openflow-switch-config.overrides b/openflow/debian/openflow-switch-config.overrides deleted file mode 100644 index 4ac77aba..00000000 --- a/openflow/debian/openflow-switch-config.overrides +++ /dev/null @@ -1 +0,0 @@ -debconf-is-not-a-registry diff --git a/openflow/debian/openflow-switch-config.templates b/openflow/debian/openflow-switch-config.templates deleted file mode 100644 index 78761097..00000000 --- a/openflow/debian/openflow-switch-config.templates +++ /dev/null @@ -1,228 +0,0 @@ -Template: openflow-switch/netdevs -Type: multiselect -_Choices: ${choices} -_Description: OpenFlow switch network devices: - Choose the network devices that should become part of the OpenFlow - switch. At least two devices must be selected for this machine to be - a useful switch. Unselecting all network devices will disable the - OpenFlow switch entirely. - . - The network devices that you select should not be configured with IP - or IPv6 addresses, even if the switch contacts the controller over - one of the selected network devices. This is because a running - OpenFlow switch takes over network devices at a low level: they - become part of the switch and cannot be used for other purposes. - -Template: openflow-switch/no-netdevs -Type: error -_Description: No network devices were selected. - No network devices were selected for inclusion in the OpenFlow switch. - The switch will be disabled. - -Template: openflow-switch/configured-netdevs -Type: note -_Description: Some Network Devices Have IP or IPv6 Addresses - The following network devices selected to be part of the OpenFlow switch - have IP or IPv6 addresses configured: - . - ${configured-netdevs} - . - This is usually a mistake, even if the switch contacts the controller over - one of the selected network devices. This is because a running - OpenFlow switch takes over network devices at a low level: they - become part of the switch and cannot be used for other purposes. - . - If this is an unintentional mistake, move back and fix the selection, - or de-configure the IP or IPv6 from these network devices. - -Template: openflow-switch/mode -Type: select -_Choices: discovery, in-band, out-of-band -Default: discovery -_Description: Switch-to-controller access method: - The OpenFlow switch must be able to contact the OpenFlow controller over - the network. It can do so in one of three ways: - . - discovery: A single network is used for OpenFlow traffic and other - data traffic; that is, the switch contacts the controller over one of - the network devices selected as OpenFlow switch network devices in - the previous question. The switch automatically determines the - location of the controller using a DHCP request with an - OpenFlow-specific vendor option. This is the most common case. - . - in-band: As above, but the location of the controller is manually - configured. - . - out-of-band: OpenFlow traffic uses a network separate from the data traffic - that it controls. If this is the case, the control network must already - be configured on a network device other than one of those selected as - an OpenFlow switch netdev in the previous question. - -Template: openflow-switch/discover -Type: note -_Description: Preparing to discover controller. - The setup program will now attempt to discover the OpenFlow controller. - Controller discovery may take up to 30 seconds. Please be patient. - . - See secchan(8) for instructions on how to configure a DHCP server for - controller discovery. - -Template: openflow-switch/discovery-failure -Type: error -_Description: Controller discovery failed. - The controller's location could not be determined automatically. - . - Ensure that the OpenFlow DHCP server is properly configured. See - secchan(8) for instructions on how to configure a DHCP server for - controller discovery. - -Template: openflow-switch/discovery-success -Type: boolean -Default: true -_Description: Use discovered settings? - Controller discovery obtained the following settings: - . - Controller location: ${controller-vconn} - . - PKI URL: ${pki-uri} - . - Please verify that these settings are correct. - -Template: openflow-switch/switch-ip -Type: string -Default: dhcp -_Description: Switch IP address: - For in-band communication with the controller, the OpenFlow switch must - be able to determine its own IP address. Its IP address may be configured - statically or dynamically. - . - For static configuration, specify the switch's IP address as a string. - . - For dynamic configuration with DHCP (the most common case), specify "dhcp". - Configuration with DHCP will only work reliably if the network topology - allows the switch to contact the DHCP server before it connects to the - OpenFlow controller. - -Template: openflow-switch/switch-ip-error -Type: error -_Description: The switch IP address is invalid. - The switch IP address must specified as "dhcp" or a valid IP address in - dotted-octet form (e.g. "1.2.3.4"). - -Template: openflow-switch/controller-vconn -Type: string -_Description: Controller location: - Specify how the OpenFlow switch should connect to the OpenFlow controller. - The value should be in form "ssl:HOST[:PORT]" to connect to the controller - over SSL (recommended for security) or "tcp:HOST[:PORT]" to connect over - cleartext TCP. - -Template: openflow-switch/controller-vconn-error -Type: error -_Description: The controller location is invalid. - The controller location must be specifed as "ssl:HOST[:PORT]" to - connect to the controller over SSL (recommended for security) or - "tcp:HOST[:PORT]" to connect over cleartext TCP. - -Template: openflow-switch/pki-uri -Type: string -_Description: OpenFlow PKI server host name or URL: - Specify a URL to the OpenFlow public key infrastructure (PKI). If a - host name or IP address is specified in place of a URL, then - http:///openflow/pki/ will be used, - where is the specified host name or IP address. - . - The OpenFlow PKI is usually on the same machine as the OpenFlow - controller. - . - The setup process will connect to the OpenFlow PKI server over - HTTP, using the system's configured default HTTP proxy (if any). - -Template: openflow-switch/fetch-cacert-failed -Type: error -_Description: The switch CA certificate could not be retrieved. - Retrieval of ${url} failed, with the following status: "${error}". - . - Ensure that the OpenFlow PKI server is correctly configured and - available at ${pki-uri}. If the system is configured to use an HTTP - proxy, also make sure that the HTTP proxy is available and that the - PKI server can be reached through it. - -Template: openflow-switch/verify-controller-ca -Type: select -_Choices: yes, no -Default: yes -_Description: Is ${fingerprint} the controller CA's fingerprint? - If a man-in-the-middle attack is possible in your network - environment, check that the controller CA's fingerprint is really - ${fingerprint}. Answer "yes" if it matches, "no" if - there is a discrepancy. - . - If a man-in-the-middle attack is not a concern, there is no need to - verify the fingerprint. Simply answer "yes". - -Template: openflow-switch/send-cert-req -Type: select -_Choices: yes, no -Default: yes -_Description: Send certificate request to switch CA? - Before it can connect to the controller over SSL, the OpenFlow - switch's key must be signed by the switch certificate authority (CA) - located on the OpenFlow PKI server, which is usually collocated with - the OpenFlow controller. A signing request can be sent to the PKI - server now. - . - Answer "yes" to send a signing request to the switch CA now. This is - ordinarily the correct choice. There is no harm in sending a given - signing request more than once. - . - Answer "no" to skip sending a signing request to the switch CA. - Unless the request has already been sent to the switch CA, manual - sending of the request and signing will be necessary. - -Template: openflow-switch/send-cert-req-failed -Type: error -_Description: The certificate request could not be sent. - Posting to ${url} failed, with the following status: "${error}". - . - Ensure that the OpenFlow PKI server is correctly configured and - available at ${pki-uri}. - -Template: openflow-switch/fetch-switch-cert -Type: select -_Choices: yes, no -_Description: Fetch signed switch certificate from PKI server? - Before it can connect to the controller over SSL, the OpenFlow - switch's key must be signed by the switch certificate authority (CA) - located on the OpenFlow PKI server, which is usually collocated with - the OpenFlow controller. - . - At this point, a signing request has been sent to the switch CA (or - sending a request has been manually skipped), but the signed - certificate has not yet been retrieved. Manual action may need to be - taken at the PKI server to approve the signing request. - . - Answer "yes" to attempt to retrieve the signed switch certificate - from the switch CA. If the switch certificate request has been - signed at the PKI server, this is the correct choice. - . - Answer "no" to postpone switch configuration. The configuration - process must be restarted later, when the switch certificate request - has been signed. - -Template: openflow-switch/fetch-switch-cert-failed -Type: error -_Description: Signed switch certificate could not be retrieved. - The signed switch certificate could not be retrieved from the switch - CA: retrieval of ${url} failed, with the following status: "${error}". - . - This probably indicates that the switch's certificate request has not - yet been signed. If this is the problem, it may be fixed by signing - the certificate request at ${pki-uri}, then trying to fetch the - signed switch certificate again. - -Template: openflow-switch/complete -Type: note -_Description: OpenFlow Switch Setup Finished - Setup of this OpenFlow switch is finished. Complete the setup procedure - to enable the switch. diff --git a/openflow/debian/openflow-switch.README.Debian b/openflow/debian/openflow-switch.README.Debian deleted file mode 100644 index d9a931c1..00000000 --- a/openflow/debian/openflow-switch.README.Debian +++ /dev/null @@ -1,18 +0,0 @@ -README.Debian for openflow-switch ---------------------------------- - -* The switch must be configured before it can be used. To configure - it interactively, install the openflow-switch-config package and run - the ofp-switch-setup program. Alternatively, edit - /etc/default/openflow-switch by hand, then start the switch manually - with "/etc/init.d/openflow-switch start". - -* To use the Linux kernel-based switch implementation, you will need - to build and install the OpenFlow kernel module. To do so, install - the openflow-datapath-source package, then follow the instructions - given in /usr/share/doc/openflow-datapath-source/README.Debian - -* This package does not yet support the userspace datapath-based - switch implementation. - - -- Ben Pfaff , Tue, 6 Jan 2009 13:52:33 -0800 diff --git a/openflow/debian/openflow-switch.dirs b/openflow/debian/openflow-switch.dirs deleted file mode 100644 index a53002ff..00000000 --- a/openflow/debian/openflow-switch.dirs +++ /dev/null @@ -1,2 +0,0 @@ -/etc/openflow-switch -/usr/share/openflow/switch diff --git a/openflow/debian/openflow-switch.init b/openflow/debian/openflow-switch.init deleted file mode 100755 index cd518a71..00000000 --- a/openflow/debian/openflow-switch.init +++ /dev/null @@ -1,437 +0,0 @@ -#! /bin/sh -# -# /etc/init.d/openflow-switch -# -# Written by Miquel van Smoorenburg . -# Modified for Debian by Ian Murdock . -# Further changes by Javier Fernandez-Sanguino -# Modified for openflow-switch. -# -# Version: @(#)skeleton 1.9 26-Feb-2001 miquels@cistron.nl -# -### BEGIN INIT INFO -# Provides: openflow-switch -# Required-Start: $network $named $remote_fs $syslog -# Required-Stop: -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: OpenFlow switch -### END INIT INFO - -PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin -DAEMON=/usr/sbin/secchan -NAME=secchan -DESC=secchan - -test -x $DAEMON || exit 0 - -NICIRA_OUI="002320" - -LOGDIR=/var/log/openflow -PIDFILE=/var/run/$NAME.pid -DHCLIENT_PIDFILE=/var/run/dhclient.of0.pid -DODTIME=1 # Time to wait for the server to die, in seconds - # If this value is set too low you might not - # let some servers to die gracefully and - # 'restart' will not work - -# Include secchan defaults if available -unset NETDEVS -unset MODE -unset SWITCH_IP -unset CONTROLLER -unset PRIVKEY -unset CERT -unset CACERT -unset CACERT_MODE -unset MGMT_VCONNS -unset COMMANDS -unset DAEMON_OPTS -unset CORE_LIMIT -unset DATAPATH_ID -default=/etc/default/openflow-switch -if [ -f $default ] ; then - . $default -fi - -set -e - -running_pid() -{ - # Check if a given process pid's cmdline matches a given name - pid=$1 - name=$2 - [ -z "$pid" ] && return 1 - [ ! -d /proc/$pid ] && return 1 - cmd=`cat /proc/$pid/cmdline | tr "\000" "\n"|head -n 1 |cut -d : -f 1` - # Is this the expected child? - case $cmd in - $name|*/$name) - return 0 - ;; - *) - return 1 - ;; - esac -} - -running() -{ -# Check if the process is running looking at /proc -# (works for all users) - - # No pidfile, probably no daemon present - [ ! -f "$PIDFILE" ] && return 1 - # Obtain the pid and check it against the binary name - pid=`cat $PIDFILE` - running_pid $pid $NAME || return 1 - return 0 -} - -force_stop() { -# Forcefully kill the process - [ ! -f "$PIDFILE" ] && return - if running ; then - kill -15 $pid - # Is it really dead? - [ -n "$DODTIME" ] && sleep "$DODTIME"s - if running ; then - kill -9 $pid - [ -n "$DODTIME" ] && sleep "$DODTIME"s - if running ; then - echo "Cannot kill $NAME (pid=$pid)!" - exit 1 - fi - fi - fi - rm -f $PIDFILE - return 0 -} - -must_succeed() { - echo -n "$1: " - shift - if "$@"; then - echo "success." - else - echo " ERROR." - exit 1 - fi -} - -check_op() { - echo -n "$1: " - shift - if "$@"; then - echo "success." - else - echo " ERROR." - fi -} - -configure_ssl() { - if (test "$CACERT_MODE" != secure && test "$CACERT_MODE" != bootstrap) \ - || test ! -e "$PRIVKEY" || test ! -e "$CERT" \ - || (test ! -e "$CACERT" && test "$CACERT_MODE" != bootstrap); then - if test "$CACERT_MODE" != secure && test "$CACERT_MODE" != bootstrap - then - echo "CACERT_MODE is not set to 'secure' or 'bootstrap'" - fi - if test ! -e "$PRIVKEY"; then - echo "$PRIVKEY: private key missing" >&2 - fi - if test ! -e "$CERT"; then - echo "$CERT: certificate for private key missing" >&2 - fi - if test ! -e "$CACERT" && test "$CACERT_MODE" != bootstrap; then - echo "$CACERT: CA certificate missing (and CA certificate bootstrapping not enabled)" >&2 - fi - echo "Run ofp-switch-setup (in the openflow-switch-config package) or edit /etc/default/openflow-switch to configure" >&2 - if test "$MODE" = discovery; then - echo "You may also delete or rename $PRIVKEY to disable SSL requirement" >&2 - fi - exit 1 - fi - - SSL_OPTS="--private-key=$PRIVKEY --certificate=$CERT" - if test ! -e "$CACERT" && test "$CACERT_MODE" = bootstrap; then - SSL_OPTS="$SSL_OPTS --bootstrap-ca-cert=$CACERT" - else - SSL_OPTS="$SSL_OPTS --ca-cert=$CACERT" - fi -} - -check_int_var() { - eval value=\$$1 - if test -n "$value"; then - if expr "X$value" : 'X[0-9][0-9]*$'; then - if test $value -lt $2; then - echo "warning: The $1 option may not be set to a value below $2, treating as $2" >&2 - eval $1=$2 - fi - else - echo "warning: The $1 option must be set to a number, ignoring" >&2 - unset $1 - fi - fi -} - -check_new_option() { - case $DAEMON_OPTS in - *$1*) - echo "warning: The $1 option in DAEMON_OPTS may now be set with the $2 variable in $default. The setting in DAEMON_OPTS will override the $2 variable, which will prevent the switch UI from configuring $1." >&2 - ;; - esac -} - -case "$1" in - start) - if test -z "$NETDEVS"; then - echo "$default: No network devices configured, switch disabled" >&2 - echo "Run ofp-switch-setup (in the openflow-switch-config package) or edit /etc/default/openflow-switch to configure" >&2 - exit 0 - fi - if test "$MODE" = discovery; then - unset CONTROLLER - elif test "$MODE" = in-band || test "$MODE" = out-of-band; then - if test -z "$CONTROLLER"; then - echo "$default: No controller configured and not configured for discovery, switch disabled" >&2 - echo "Run ofp-switch-setup (in the openflow-switch-config package) or edit /etc/default/openflow-switch to configure" >&2 - exit 0 - fi - else - echo "$default: MODE must set to 'discovery', 'in-band', or 'out-of-band'" >&2 - echo "Run ofp-switch-setup (in the openflow-switch-config package) or edit /etc/default/openflow-switch to configure" >&2 - exit 1 - fi - : ${PRIVKEY:=/etc/openflow-switch/of0-privkey.pem} - : ${CERT:=/etc/openflow-switch/of0-cert.pem} - : ${CACERT:=/etc/openflow-switch/cacert.pem} - case $CONTROLLER in - '') - # Discovery mode. - if test -e "$PRIVKEY"; then - configure_ssl - fi - ;; - tcp:*) - ;; - ssl:*) - configure_ssl - ;; - *) - echo "$default: CONTROLLER must be in the form 'ssl:HOST[:PORT]' or 'tcp:HOST[:PORT]' when not in discovery mode" >&2 - echo "Run ofp-switch-setup (in the openflow-switch-config package) or edit /etc/default/openflow-switch to configure" >&2 - exit 1 - esac - case $DISCONNECTED_MODE in - ''|switch|drop) ;; - *) echo "$default: warning: DISCONNECTED_MODE is not 'switch' or 'drop'" >&2 ;; - esac - - check_int_var RATE_LIMIT 100 - check_int_var INACTIVITY_PROBE 5 - check_int_var MAX_BACKOFF 1 - - check_new_option --fail DISCONNECTED_MODE - check_new_option --stp STP - check_new_option --rate-limit RATE_LIMIT - check_new_option --inactivity INACTIVITY_PROBE - check_new_option --max-backoff MAX_BACKOFF - case $DAEMON_OPTS in - *--rate-limit*) - echo "$default: --rate-limit may now be set with RATE_LIMIT" >&2 - esac - - echo -n "Loading openflow_mod: " - if grep -q '^openflow_mod$' /proc/modules; then - echo "already loaded, nothing to do." - elif modprobe openflow_mod; then - echo "success." - else - echo "ERROR." - echo "openflow_mod has probably not been built for this kernel." - if ! test -d /usr/share/doc/openflow-datapath-source; then - echo "Install the openflow-datapath-source package, then read" - echo "/usr/share/doc/openflow-datapath-source/README.Debian" - else - echo "For instructions, read" - echo "/usr/share/doc/openflow-datapath-source/README.Debian" - fi - exit 1 - fi - - for netdev in $NETDEVS; do - check_op "Removing IP address from $netdev" ifconfig $netdev 0.0.0.0 - done - - must_succeed "Adding datapath" dpctl adddp nl:0 - for netdev in $NETDEVS; do - must_succeed "Adding $netdev to datapath" dpctl addif nl:0 $netdev - done - - xx='[0-9abcdefABCDEF][0-9abcdefABCDEF]' - case $DATAPATH_ID in - '') - # Check if the DMI System UUID contains a Nicira mac address - # that should be used for this datapath. The UUID is assumed - # to be RFC 4122 compliant. - DMIDECODE=`which dmidecode` - if [ -n $DMIDECODE ]; then - UUID_MAC=`$DMIDECODE -s system-uuid | cut -d'-' -f 5` - case $UUID_MAC in - $NICIRA_OUI*) - ifconfig of0 down - must_succeed "Setting of0 MAC address to $UUID_MAC" ifconfig of0 hw ether $UUID_MAC - ifconfig of0 up - ;; - esac - fi - ;; - $xx:$xx:$xx:$xx:$xx:$xx) - ifconfig of0 down - must_succeed "Setting of0 MAC address to $DATAPATH_ID" ifconfig of0 hw ether $DATAPATH_ID - ifconfig of0 up - ;; - *) - echo "DATAPATH_ID is not a valid MAC address in the form XX:XX:XX:XX:XX:XX, ignoring" >&2 - ;; - esac - - if test "$MODE" = in-band; then - if test "$SWITCH_IP" = dhcp; then - must_succeed "Temporarily disabling of0" ifconfig of0 down - else - COMMAND="ifconfig of0 $SWITCH_IP" - if test -n "$SWITCH_NETMASK"; then - COMMAND="$COMMAND netmask $SWITCH_NETMASK" - fi - must_succeed "Configuring of0: $COMMAND" $COMMAND - if test -n "$SWITCH_GATEWAY"; then - # This can fail because the route already exists, - # so we don't insist that it succeed. - COMMAND="route add default gw $SWITCH_GATEWAY" - check_op "Adding default route: $COMMAND" $COMMAND - fi - fi - else - must_succeed "Disabling of0" ifconfig of0 down - fi - - if test -n "$CORE_LIMIT"; then - check_op "Setting core limit to $CORE_LIMIT" ulimit -c "$CORE_LIMIT" - fi - - # Compose secchan options. - set -- - set -- "$@" --verbose=ANY:console:emer --verbose=ANY:syslog:err - set -- "$@" --log-file - set -- "$@" --detach --pidfile=$PIDFILE - for vconn in $MGMT_VCONNS; do - set -- "$@" --listen="$vconn" - done - if test -n "$MONITOR_VCONN"; then - set -- "$@" --monitor="$MONITOR_VCONN" - fi - if test -n "$COMMANDS"; then - set -- "$@" --command-acl="$COMMANDS" - fi - case $STP in - yes) set -- "$@" --stp ;; - no) set -- "$@" --no-stp ;; - esac - case $DISCONNECTED_MODE in - switch) set -- "$@" --fail=open ;; - drop) set -- "$@" --fail=closed ;; - esac - if test -n "$RATE_LIMIT"; then - set -- "$@" --rate-limit=$RATE_LIMIT - fi - if test -n "$INACTIVITY_PROBE"; then - set -- "$@" --inactivity-probe=$INACTIVITY_PROBE - fi - if test -n "$MAX_BACKOFF"; then - set -- "$@" --max-backoff=$MAX_BACKOFF - fi - set -- "$@" $SSL_OPTS $DAEMON_OPTS - if test "$MODE" = out-of-band; then - set -- "$@" --out-of-band - fi - set -- "$@" nl:0 "$CONTROLLER" - echo -n "Starting $DESC: " - start-stop-daemon --start --quiet --pidfile $PIDFILE \ - --exec $DAEMON -- "$@" - if running; then - echo "$NAME." - else - echo " ERROR." - fi - - if test "$MODE" = in-band && test "$SWITCH_IP" = dhcp; then - echo -n "Starting dhclient on of0: " - start-stop-daemon --start --quiet --pidfile $DHCLIENT_PIDFILE \ - --exec /sbin/dhclient -- -q -pf $DHCLIENT_PIDFILE of0 - if running; then - echo "dhclient." - else - echo " ERROR." - fi - fi - ;; - stop) - if test -e /var/run/dhclient.of0.pid; then - echo -n "Stopping dhclient on of0: " - start-stop-daemon --stop --quiet --oknodo \ - --pidfile $DHCLIENT_PIDFILE --exec /sbin/dhclient - echo "dhclient." - fi - - echo -n "Stopping $DESC: " - start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE \ - --exec $DAEMON - echo "$NAME." - - for netdev in $NETDEVS; do - check_op "Removing $netdev from datapath" dpctl delif nl:0 $netdev - done - check_op "Deleting datapath" dpctl deldp nl:0 - check_op "Unloading kernel module" modprobe -r openflow_mod - ;; - force-stop) - echo -n "Forcefully stopping $DESC: " - force_stop - if ! running; then - echo "$NAME." - else - echo " ERROR." - fi - ;; - reload) - ;; - force-reload) - start-stop-daemon --stop --test --quiet --pidfile \ - $PIDFILE --exec $DAEMON \ - && $0 restart \ - || exit 0 - ;; - restart) - $0 stop || true - $0 start - ;; - status) - echo -n "$NAME is " - if running ; then - echo "running" - else - echo " not running." - exit 1 - fi - ;; - *) - N=/etc/init.d/$NAME - echo "Usage: $N {start|stop|restart|force-reload|status|force-stop}" >&2 - exit 1 - ;; -esac - -exit 0 diff --git a/openflow/debian/openflow-switch.install b/openflow/debian/openflow-switch.install deleted file mode 100644 index b325e3cc..00000000 --- a/openflow/debian/openflow-switch.install +++ /dev/null @@ -1,6 +0,0 @@ -_debian/secchan/ofprotocol usr/sbin -_debian/utilities/dpctl usr/sbin -_debian/utilities/ofp-discover usr/sbin -_debian/utilities/ofp-kill usr/sbin -debian/openflow/usr/share/openflow/commands/* usr/share/openflow/commands -debian/commands/* usr/share/openflow/commands diff --git a/openflow/debian/openflow-switch.logrotate b/openflow/debian/openflow-switch.logrotate deleted file mode 100644 index b2136907..00000000 --- a/openflow/debian/openflow-switch.logrotate +++ /dev/null @@ -1,11 +0,0 @@ -/var/log/openflow/secchan.log { - daily - compress - create 640 root adm - delaycompress - missingok - rotate 30 - postrotate - vlogconf --target /var/run/secchan.pid --reopen - endscript -} diff --git a/openflow/debian/openflow-switch.manpages b/openflow/debian/openflow-switch.manpages deleted file mode 100644 index dd636ac8..00000000 --- a/openflow/debian/openflow-switch.manpages +++ /dev/null @@ -1,4 +0,0 @@ -_debian/secchan/ofprotocol.8 -_debian/utilities/ofp-discover.8 -_debian/utilities/ofp-kill.8 -_debian/utilities/dpctl.8 diff --git a/openflow/debian/openflow-switch.postinst b/openflow/debian/openflow-switch.postinst deleted file mode 100755 index 4f96db3a..00000000 --- a/openflow/debian/openflow-switch.postinst +++ /dev/null @@ -1,51 +0,0 @@ -#!/bin/sh -# postinst script for openflow-switch -# -# see: dh_installdeb(1) - -set -e - -# summary of how this script can be called: -# * `configure' -# * `abort-upgrade' -# * `abort-remove' `in-favour' -# -# * `abort-remove' -# * `abort-deconfigure' `in-favour' -# `removing' -# -# for details, see http://www.debian.org/doc/debian-policy/ or -# the debian-policy package - - -case "$1" in - configure) - DEFAULT=/etc/default/openflow-switch - TEMPLATE=/usr/share/openflow/switch/default.template - if ! test -e $DEFAULT; then - cp $TEMPLATE $DEFAULT - else - for var in $(awk -F'[ :]' '/^# [_A-Z0-9]+:/{print $2}' $TEMPLATE) - do - if ! grep $var $DEFAULT >/dev/null 2>&1; then - echo >> $DEFAULT - sed -n "/$var:/,/$var=/p" $TEMPLATE >> $DEFAULT - fi - done - fi - ;; - - abort-upgrade|abort-remove|abort-deconfigure) - ;; - - *) - echo "postinst called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -#DEBHELPER# - -exit 0 - - diff --git a/openflow/debian/openflow-switch.postrm b/openflow/debian/openflow-switch.postrm deleted file mode 100755 index 20bab0e0..00000000 --- a/openflow/debian/openflow-switch.postrm +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/sh -# postrm script for openflow-switch -# -# see: dh_installdeb(1) - -set -e - -# summary of how this script can be called: -# * `remove' -# * `purge' -# * `upgrade' -# * `failed-upgrade' -# * `abort-install' -# * `abort-install' -# * `abort-upgrade' -# * `disappear' -# -# for details, see http://www.debian.org/doc/debian-policy/ or -# the debian-policy package - - -case "$1" in - purge) - rm -f /etc/default/openflow-switch - ;; - - remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) - ;; - - *) - echo "postrm called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -# dh_installdeb will replace this with shell code automatically -# generated by other debhelper scripts. - -#DEBHELPER# - -exit 0 - - diff --git a/openflow/debian/openflow-switch.template b/openflow/debian/openflow-switch.template deleted file mode 100644 index f3f641e8..00000000 --- a/openflow/debian/openflow-switch.template +++ /dev/null @@ -1,169 +0,0 @@ -# This is a POSIX shell fragment -*- sh -*- - -# To configure the secure channel, fill in the following properly and -# uncomment them. Afterward, the secure channel will come up -# automatically at boot time. It can be started immediately with -# /etc/init.d/openflow-switch start -# Alternatively, use the ofp-switch-setup program (from the -# openflow-switch-config package) to do everything automatically. - -# NETDEVS: Which network devices should the OpenFlow switch include? -# -# List the network devices that should become part of the OpenFlow -# switch, separated by spaces. At least two devices must be selected -# for this machine to be a useful switch. Unselecting all network -# devices will disable the OpenFlow switch entirely. -# -# The network devices that you select should not be configured with IP -# or IPv6 addresses, even if the switch contacts the controller over -# one of the selected network devices. This is because a running -# OpenFlow switch takes over network devices at a low level: they -# become part of the switch and cannot be used for other purposes. -#NETDEVS="" - -# MODE: The OpenFlow switch has three modes that determine how it -# reaches the controller: -# -# * in-band with discovery: A single network is used for OpenFlow -# traffic and other data traffic; that is, the switch contacts the -# controller over one of the network devices selected as OpenFlow -# switch ports. The switch automatically determines the location of -# the controller using a DHCP request with an OpenFlow-specific -# vendor option. This is the most common case. -# -# * in-band: As above, but the location of the controller is manually -# configured. -# -# * out-of-band: OpenFlow traffic uses a network separate from the -# data traffic that it controls. If this is the case, the control -# network must already be configured on a network device other than -# one of those selected as an OpenFlow switch port in the previous -# question. -# -# Set MODE to 'discovery', 'in-band', or 'out-of-band' for these -# respective cases. -MODE=discovery - -# SWITCH_IP: In 'in-band' mode, the switch's IP address may be -# configured statically or dynamically: -# -# * For static configuration, specify the switch's IP address as a -# string. In this case you may also set SWITCH_NETMASK and -# SWITCH_GATEWAY appropriately (see below). -# -# * For dynamic configuration with DHCP (the most common case), -# specify "dhcp". Configuration with DHCP will only work reliably -# if the network topology allows the switch to contact the DHCP -# server before it connects to the OpenFlow controller. -# -# This setting has no effect unless MODE is set to 'in-band'. -SWITCH_IP=dhcp - -# SWITCH_NETMASK: IP netmask to use in 'in-band' mode when the switch -# IP address is not 'dhcp'. -#SWITCH_NETMASK=255.255.255.0 - -# SWITCH_GATEWAY: IP gateway to use in 'in-band' mode when the switch -# IP address is not 'dhcp'. -#SWITCH_GATEWAY=192.168.1.1 - -# CONTROLLER: Location of controller. -# One of the following formats: -# tcp:HOST[:PORT] via TCP to PORT (default: 6633) on HOST -# ssl:HOST[:PORT] via SSL to PORT (default: 6633) on HOST -# The default below assumes that the controller is running locally. -# This setting has no effect when MODE is set to 'discovery'. -#CONTROLLER="tcp:127.0.0.1" - -# PRIVKEY: Name of file containing switch's private key. -# Required if SSL enabled. -#PRIVKEY=/etc/openflow-switch/of0-privkey.pem - -# CERT: Name of file containing certificate for private key. -# Required if SSL enabled. -#CERT=/etc/openflow-switch/of0-cert.pem - -# CACERT: Name of file containing controller CA certificate. -# Required if SSL enabled. -#CACERT=/etc/openflow-switch/cacert.pem - -# CACERT_MODE: Two modes are available: -# -# * secure: The controller CA certificate named in CACERT above must exist. -# (You must copy it manually from the PKI server or another trusted source.) -# -# * bootstrap: If the controller CA certificate named in CACERT above does -# not exist, the switch will obtain it from the controller the first time -# it connects and save a copy to the file named in CACERT. This is insecure, -# in the same way that initial connections with ssh are insecure, but -# it is convenient. -# -# Set CACERT_MODE to 'secure' or 'bootstrap' for these respective cases. -#CACERT_MODE=secure - -# MGMT_VCONNS: List of vconns (space-separated) on which secchan -# should listen for management connections from dpctl, etc. -# openflow-switchui by default connects to -# unix:/var/run/secchan.mgmt, so do not disable this if you want to -# use openflow-switchui. -MGMT_VCONNS="punix:/var/run/secchan.mgmt" - -# MONITOR_VCONN: Name of vconn on which secchan should listen for -# monitoring connections from dpctl. -MONITOR_VCONN="punix:/var/run/secchan.monitor" - -# COMMANDS: Access control list for the commands that can be executed -# remotely over the OpenFlow protocol, as a comma-separated list of -# shell glob patterns. Negative patterns (beginning with !) act as a -# blacklist. To be executable, a command name must match one positive -# pattern and not match any negative patterns. -#COMMANDS="reboot,update" - -# DISCONNECTED_MODE: Switch behavior when attempts to connect to the -# controller repeatedly fail, either 'switch', to act as an L2 switch -# in this case, or 'drop', to drop all packets (except those necessary -# to connect to the controller). If unset, the default is 'drop'. -#DISCONNECTED_MODE=switch - -# STP: Enable or disabled 802.1D-1998 Spanning Tree Protocol. Set to -# 'yes' to enable STP, 'no' to disable it. If unset, secchan's -# current default is 'no' (but this may change in the future). -#STP=no - -# RATE_LIMIT: Maximum number of received frames, that do not match any -# existing switch flow, to forward up to the controller per second. -# The valid range is 100 and up. If unset, this rate will not be -# limited. -#RATE_LIMIT=1000 - -# INACTIVITY_PROBE: The maximum number of seconds of inactivity on the -# controller connection before secchan sends an inactivity probe -# message to the controller. The valid range is 5 and up. If unset, -# secchan defaults to 15 seconds. -#INACTIVITY_PROBE=5 - -# MAX_BACKOFF: The maximum time that secchan will wait between -# attempts to connect to the controller. The valid range is 1 and up. -# If unset, secchan defaults to 15 seconds. -#MAX_BACKOFF=15 - -# DAEMON_OPTS: Additional options to pass to secchan, e.g. "--fail=open" -DAEMON_OPTS="" - -# CORE_LIMIT: Maximum size for core dumps. -# -# Leaving this unset will use the system default. Setting it to 0 -# will disable core dumps. Setting it to "unlimited" will dump all -# core files regardless of size. -#CORE_LIMIT=unlimited - -# DATAPATH_ID: Identifier for this switch. -# -# By default, the switch checks if the DMI System UUID contains a Nicira -# mac address to use as a datapath ID. If not, then the switch generates -# a new, random datapath ID every time it starts up. By setting this -# value, the supplied datapath ID will always be used. -# -# Set DATAPATH_ID to a MAC address in the form XX:XX:XX:XX:XX:XX where each -# X is a hexadecimal digit (0-9 or a-f). -#DATAPATH_ID=XX:XX:XX:XX:XX:XX diff --git a/openflow/debian/po/POTFILES.in b/openflow/debian/po/POTFILES.in deleted file mode 100644 index e3ea07e3..00000000 --- a/openflow/debian/po/POTFILES.in +++ /dev/null @@ -1 +0,0 @@ -[type: gettext/rfc822deb] openflow-switch-config.templates diff --git a/openflow/debian/rules b/openflow/debian/rules deleted file mode 100755 index 539c8f3d..00000000 --- a/openflow/debian/rules +++ /dev/null @@ -1,163 +0,0 @@ -#!/usr/bin/make -f -# -*- makefile -*- -# Sample debian/rules that uses debhelper. -# -# This file was originally written by Joey Hess and Craig Small. -# As a special exception, when this file is copied by dh-make into a -# dh-make output file, you may use that output file without restriction. -# This special exception was added by Craig Small in version 0.37 of dh-make. -# -# Modified to make a template file for a multi-binary package with separated -# build-arch and build-indep targets by Bill Allombert 2001 - -# Uncomment this to turn on verbose mode. -#export DH_VERBOSE=1 - -# This has to be exported to make some magic below work. -export DH_OPTIONS - -# prefix of the target package name -PACKAGE=openflow-datapath-module -# modifieable for experiments or debugging m-a -MA_DIR ?= /usr/share/modass -# load generic variable handling --include $(MA_DIR)/include/generic.make -# load default rules --include $(MA_DIR)/include/common-rules.make - --include debian/rules.ext - -DATAPATH_CONFIGURE_OPTS = --enable-snat - -# Official build number. Leave set to 0 if not an official build. -BUILD_NUMBER = 0 - -configure: configure-stamp -configure-stamp: - dh_testdir - test -e configure || ./boot.sh - test -d _debian || mkdir _debian - cd _debian && ( \ - test -e Makefile || \ - ../configure --prefix=/usr --localstatedir=/var --enable-ssl \ - --with-build-number=$(BUILD_NUMBER) \ - $(DATAPATH_CONFIGURE_OPTS)) - $(ext_configure) - touch configure-stamp - -#Architecture -build: build-arch build-indep - -build-arch: build-arch-stamp -build-arch-stamp: configure-stamp - $(MAKE) -C _debian - $(ext_build_arch) - touch $@ - -build-indep: build-indep-stamp -build-indep-stamp: configure-stamp - $(MAKE) -C _debian dist distdir=openflow - $(ext_build_indep) - touch $@ - -clean: - dh_testdir - dh_testroot - rm -f build-arch-stamp build-indep-stamp configure-stamp - rm -rf _debian - [ ! -f Makefile ] || $(MAKE) distclean - $(ext_clean) - dh_clean - debconf-updatepo - -MAJOR=$(shell echo $(KVERS) | sed -e 's/\(...\).*/\1/') -ifeq ($(MAJOR),2.6) -KO=k -l2x=l26 -dpdir=datapath/linux-2.6 -else -KO= -l2x=l24 -dpdir=datapath/linux-2.4 -endif - -kdist_clean: - dh_clean - rm -rf openflow - -kdist_config: prep-deb-files - -binary-modules: DSTDIR = $(CURDIR)/debian/$(PKGNAME)/lib/modules/$(KVERS) -binary-modules: prep-deb-files - dh_testdir - dh_testroot - dh_clean -k - tar xzf openflow.tar.gz - cd openflow && ./configure --with-$(l2x)=$(KSRC) $(DATAPATH_CONFIGURE_OPTS) --with-build-number=$(BUILD_NUMBER) - cd openflow && $(MAKE) -C $(dpdir) - install -d -m755 $(DSTDIR) - install -m644 openflow/$(dpdir)/*_mod.$(KO)o $(DSTDIR)/ - dh_installdocs - dh_installchangelogs - dh_compress - dh_fixperms - dh_installdeb - dh_gencontrol - dh_md5sums - dh_builddeb --destdir=$(DEB_DESTDIR) - -install: install-indep install-arch -install-indep: build-indep - dh_testdir - dh_testroot - dh_clean -k -i - dh_installdirs -i - dh_install -i - cd debian/openflow-datapath-source/usr/src && tar -c modules | bzip2 -9 > openflow-datapath.tar.bz2 && rm -rf modules - install -m644 debian/openflow-pki-server.apache2 debian/openflow-pki-server/etc/apache2/sites-available/openflow-pki - install -m1777 -d debian/corekeeper/var/log/core - $(ext_install_indep) - -install-arch: build-arch - dh_testdir - dh_testroot - dh_clean -k -s - dh_installdirs -s - $(MAKE) -C _debian DESTDIR=$(CURDIR)/debian/openflow install - cp debian/openflow-switch-config.overrides debian/openflow-switch-config/usr/share/lintian/overrides/openflow-switch-config - cp debian/openflow-switch.template debian/openflow-switch/usr/share/openflow/switch/default.template - dh_install -s - $(ext_install_arch) - -# Must not depend on anything. This is to be called by -# binary-arch/binary-indep -# in another 'make' thread. -binary-common: - dh_testdir - dh_testroot - dh_installchangelogs - dh_installdocs - dh_installexamples - dh_installdebconf - dh_installlogrotate - dh_installinit - dh_installcron - dh_installman - dh_link - dh_strip --dbg-package=openflow-dbg - dh_compress - dh_fixperms -X var/log/core - dh_perl - dh_makeshlibs - dh_installdeb - dh_shlibdeps - dh_gencontrol - dh_md5sums - dh_builddeb -binary-indep: install-indep - $(MAKE) -f debian/rules DH_OPTIONS=-i binary-common -binary-arch: install-arch - $(MAKE) -f debian/rules DH_OPTIONS=-s binary-common - -binary: binary-arch binary-indep -.PHONY: build clean binary-indep binary-arch binary install install-indep install-arch configure diff --git a/openflow/doc/of-spec/.gitignore b/openflow/doc/of-spec/.gitignore deleted file mode 100644 index 7723a762..00000000 --- a/openflow/doc/of-spec/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -/*.aux -/*.log -/*.out -/*.pdf -/*.ps -/define -/enum -/struct diff --git a/openflow/doc/of-spec/Makefile b/openflow/doc/of-spec/Makefile deleted file mode 100644 index 0e4c9462..00000000 --- a/openflow/doc/of-spec/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -TARGET=openflow-spec-v1.0.0 - -BIBTEX := bibtex -TGIF := tgif -XFIG := xfig -GNUPLOT:= gnuplot - -SOURCES=openflow-spec-v1.0.0.tex\ - appendix.tex - -all: $(TARGET).ps -pdf: all - -$(TARGET).pdf: Makefile $(SOURCES) - ./make_latex_input.pl - texi2pdf $(TARGET).tex - -color: $(TARGET).pdf - pdflatex $(TARGET).tex - pdftops $(TARGET).pdf - -$(TARGET).ps: $(TARGET).pdf - pdftops $(TARGET).pdf - -%.pdf : %.fig #Makefile - fig2dev -L pdf -b 1 $< $@ - -%.eps : %.dia #Makefile - dia --nosplash -e $@ $< - -%.eps : %.obj - TMPDIR=/tmp $(TGIF) -print -eps $< - - -%.pdf : %.eps #Makefile - epstopdf $< - -clean: - rm -f *.aux *.log *.out *.bbl *.blg *~ *.bak $(TARGET).ps $(TARGET).pdf - rm -rf define enum struct diff --git a/openflow/doc/of-spec/README b/openflow/doc/of-spec/README deleted file mode 100644 index a010f5dd..00000000 --- a/openflow/doc/of-spec/README +++ /dev/null @@ -1,3 +0,0 @@ -To build the latest OpenFlow specification, you should just be able to -type "make". For this to work, you'll need to have the texinfo and -"listings.sty" packages installed. diff --git a/openflow/doc/of-spec/appendix.tex b/openflow/doc/of-spec/appendix.tex deleted file mode 100755 index ffac6bbb..00000000 --- a/openflow/doc/of-spec/appendix.tex +++ /dev/null @@ -1,429 +0,0 @@ -%\appendix -\section{Appendix A: The OpenFlow Protocol} -The heart of the OpenFlow spec is the set of structures used for OpenFlow Protocol messages. -\\\\ -The structures, defines, and enumerations described below are derived from the file \verb|include/openflow/openflow.h|, which is part of the standard OpenFlow distribution. All structures are packed with padding and 8-byte aligned, as checked by the assertion statements. All OpenFlow messages are sent in big-endian format. - -\subsection{OpenFlow Header} -Each OpenFlow message begins with the OpenFlow header: - -\input{struct/ofp_header} -The version specifies the OpenFlow protocol version being used. During the current draft phase of the OpenFlow Protocol, the most significant bit will be set to indicate an experimental version and the lower bits will indicate a revision number. The current version is \input{define/OFP_VERSION}. The final version for a Type 0 switch will be 0x00. The length field indicates the total length of the message, so no additional framing is used to distinguish one frame from the next. The type can have the following values: - -\input{enum/ofp_type} - -\subsection{Common Structures} -This section describes structures used by multiple messages. - -\subsubsection{Port Structures} -Physical ports are described with the following structure: - -\input{struct/ofp_phy_port} -The \verb|port_no| field is a value the datapath associates with a physical port. The \verb|hw_addr| field typically is the MAC address for the port; \verb|OFP_MAX_ETH_ALEN| is 6. The name field is a null-terminated string containing a human-readable name for the interface. The value of \verb|OFP_MAX_PORT_NAME_LEN| is 16. -\\\\ -The \verb|config| field describes spanning tree and administrative settings with the following structure: - -\input{enum/ofp_port_config} -The port config bits indicate whether a port has been administratively brought down, options for handling 802.1D spanning tree packets, and how to handle incoming and outgoing packets. These bits, configured over multiple switches, enable an OpenFlow network to safely flood packets along either a custom or 802.1D spanning tree. -\\\\ -The controller may set \verb|OFPPFL_NO_STP| to 0 to enable STP on a port or to 1 to disable STP on a port. (The latter corresponds to the Disabled STP port state.) The default is switch implementation-defined; the OpenFlow reference implementation by default sets this bit to 0 (enabling STP). -\\\\ -When \verb|OFPPFL_NO_STP| is 0, STP controls the \verb|OFPPFL_NO_FLOOD| and \verb|OFPPFL_STP_*| bits directly. \verb|OFPPFL_NO_FLOOD| is set to 0 when the STP port state is Forwarding, otherwise to 1. The bits in \verb|OFPPFL_STP_MASK| are set to one of the other \verb|OFPPFL_STP_*| values according to the current STP port state. -\\\\ -When the port flags are changed by STP, the switch sends an \verb|OFPT_PORT_STATUS| message to notify the controller of the change. The \verb|OFPPFL_NO_RECV|, \verb|OFPPFL_NO_RECV_STP|, \verb|OFPPFL_NO_FWD|, and \verb|OFPPFL_NO_PACKET_IN| bits in the OpenFlow port flags may be useful for the controller to implement STP, although they interact poorly with in-band control. -\\\\ -The \verb|state| field describes the spanning tree state and whether a physical link is present, with the following structure: - -\input{enum/ofp_port_state} -All port state bits are read-only, representing spanning tree and physical link state. -\\\\ -The port numbers use the following conventions: - -\input{enum/ofp_port} -The \verb|curr|, \verb|advertised|, \verb|supported|, and \verb|peer| fields indicate link modes (10M to 10G full and half-duplex), link type (copper/fiber) and link features (autonegotiation and pause). Port features are represent by the following structure: - -\input{enum/ofp_port_features} -Multiple of these flags may be set simultaneously. - -\subsubsection{\qosupd{Queue Structures}} -\label{cts:qos} -\qosupd{An OpenFlow switch provides limited Quality-of-Service support - (QoS) through a simple queuing -mechanism. One (or more) queues can attach to a port and be used to map flows -on it. Flows mapped to a specific queue will be treated according to -that queue's configuration (e.g. min rate). -\\\\ -A queue is described by the} \verb|ofp_packet_queue| \qosupd{structure: -\input{struct/ofp_packet_queue} -Each queue is further described by a set of properties, each of a -specific type and configuration. -\input{enum/ofp_queue_properties} -Each queue property description starts with a common header: -\input{struct/ofp_queue_prop_header} -Currently, there is only a minimum-rate type queue, described by the} -\verb|ofp_queue_prop_min_rate| \qosupd{structure: -\input{struct/ofp_queue_prop_min_rate}} - -\subsubsection{Flow Match Structures} -When describing a flow entry, the following structure is used: - -\input{struct/ofp_match} -The \verb|wildcards| field has a number of flags that may be set: - -\input{enum/ofp_flow_wildcards} -If no wildcards are set, then the \verb|ofp_match| exactly describes a flow, over the entire OpenFlow 12-tuple. On the other extreme, if all the wildcard flags are set, then every flow will match. -\\\\ -The source and destination netmasks are each specified with a 6-bit number in the wildcard description. It is interpreted similar to the CIDR suffix, but with the opposite meaning, since this is being used to indicate which bits in the IP address should be treated as ``wild". For example, a CIDR suffix of "24" means to use a netmask of ``255.255.255.0". However, a wildcard mask value of ``24" means that the least-significant 24-bits are wild, so it forms a netmask of ``255.0.0.0". - -\subsubsection{Flow Action Structures} -A number of actions may be associated with flows or packets. The currently defined action types are: - -\input{enum/ofp_action_type} -Output \qosupd{and enqueue} actions are described in Section \ref{ft:actions}, while Field-Modify actions are described in Table \ref{table:field modify actions}. An action definition contains the action type, length, and any associated data: - -\input{struct/ofp_action_header} -An \verb|action_output| has the following fields: - -\input{struct/ofp_action_output} -The \verb|max_len| indicates the maximum amount of data from a packet that should be sent when the port is \verb|OFPP_CONTROLLER|. If \verb|max_len| is zero, the switch must send a zero-size \verb|packet_in| message. The \verb|port| specifies the physical port from which packets should be sent. - \\\\ -\qosupd{The enqueue action maps a flow to an already-configured queue, regardless of the TOS and VLAN PCP bits. - The packet should not change after an enqueue action. If the switch - needs to set the TOS/PCP bits for internal handling, the original values - should be restored before sending the packet out. -\\\\ -A switch may support only queues that are tied to specific PCP/TOS -bits. In that case, we cannot map an arbitrary flow to a specific -queue, therefore the action ENQUEUE is not supported. The user can -still use these queues and map -flows to them by setting the relevant fields (TOS, VLAN PCP). -\\\\ -The enqueue action has the following fields: - -\input{struct/ofp_action_enqueue}} -An \verb|action_vlan_vid| has the following fields: - -\input{struct/ofp_action_vlan_vid} -The \verb|vlan_vid| field is 16 bits long, when an actual VLAN id is only 12 bits. The value \verb|0xffff| is used to indicate that no VLAN id was set. -\\\\ -An \verb|action_vlan_pcp| has the following fields: - -\input{struct/ofp_action_vlan_pcp} -The \verb|vlan_pcp| field is 8 bits long, but only the lower 3 bits have meaning. -\\\\ -An \verb|action_strip_vlan| takes no arguments and consists only of a generic \verb|ofp_action_header|. This action strips the VLAN tag if one is present. -\\\\ -An \verb|action_dl_addr| has the following fields: - -\input{struct/ofp_action_dl_addr} -The \verb|dl_addr| field is the MAC address to set. -\\\\ -An \verb|action_nw_addr| has the following fields: - -\input{struct/ofp_action_nw_addr} -The \verb|nw_addr| field is the IP address to set. -\\\\ -An \verb|action_nw_tos| has the following fields: - -\input{struct/ofp_action_nw_tos} -The \verb|nw_tos| field is the 6 upper bits of the ToS field to set, in the original bit positions (shifted to the left by 2). -\\\\ -An \verb|action_tp_port| has the following fields: - -\input{struct/ofp_action_tp_port} -The \verb|tp_port| field is the TCP/UDP/other port to set. -\\\\ -An \verb|action_vendor| has the following fields: - -\input{struct/ofp_action_vendor_header} -The \verb|vendor| field is the Vendor ID, which takes the same form as in struct \verb|ofp_vendor|. - -\subsection{Controller-to-Switch Messages} - -\subsubsection{Handshake} -\label{cts:handshake} -Upon TLS session establishment, the controller sends an \verb|OFPT_FEATURES_REQUEST| message. This message does not contain a body beyond the OpenFlow header. The switch responds with an \verb|OFPT_FEATURES_REPLY| message: - -\input{struct/ofp_switch_features} -The \verb|datapath_id| field uniquely identifies a datapath. The lower 48 bits are intended for the switch MAC address, while the top 16 bits are up to the implementer. An example use of the top 16 bits would be a VLAN ID to distinguish multiple virtual switch instances on a single physical switch. This field should be treated as an opaque bit string by controllers. -\\\\ -The \verb|n_tables| field describes the number of tables supported by the switch, each of which can have a different set of supported wildcard bits and number of entries. When the controller and switch first communicate, the controller will find out how many tables the switch supports from the Features Reply. If it wishes to understand the size, types, and order in which tables are consulted, the controller sends a \verb|OFPST_TABLE| stats request. A switch must return these tables in the order the packets traverse the tables, with all exact-match tables listed before all tables with wildcards. -\\\\ -The \verb|capabilities| field uses the following flags: - -\input{enum/ofp_capabilities} -The \verb|actions| field is a bitmap of actions supported by the switch. The list of actions is found in Section~\ref{ft:actions}; all actions marked Required must be supported. Vendor actions should \emph{not} be reported via this bitmask. The bitmask uses the values from \verb|ofp_action_type| as the number of bits to shift left for an associated action. For example, \verb|OFPAT_SET_DL_VLAN| would use the flag \verb|0x00000002|. -\\\\ -The \verb|ports| field is an array of \verb|ofp_phy_port| structures that describe all the physical ports in the system that support OpenFlow. The number of port elements is inferred from the length field in the OpenFlow header. - -\subsubsection{Switch Configuration} -The controller is able to set and query configuration parameters in the switch with the \verb|OFPT_SET_CONFIG| and \verb|OFPT_GET_CONFIG_REQUEST| messages, respectively. The switch responds to a configuration request with an \verb|OFPT_GET_CONFIG_REPLY| message; it does not reply to a request to set the configuration. -\\\\ -There is no body for \verb|OFPT_GET_CONFIG_REQUEST| beyond the OpenFlow header. The \verb|OFPT_SET_CONFIG| and \verb|OFPT_GET_CONFIG_REPLY| use the following: - -\input{struct/ofp_switch_config} -The configuration flags include the following: - -\input{enum/ofp_config_flags} -The \verb|OFPC_FRAG_*| flags indicate whether IP fragments should be treated normally, dropped, or reassembled. ``Normal" handling of fragments means that an attempt should be made to pass the fragments through the OpenFlow tables. If any field is not present (e.g., the TCP/UDP ports didn't fit), then the packet should not match any entry that has that field set. -\\\\ -The \verb|miss_send_len| field defines the number of bytes of each packet sent to the controller as a result of both flow table misses and flow table hits with the controller as the destination. If this field equals 0, the switch must send a zero-size \verb|packet_in| message. - -\subsubsection{Modify State Messages} -\paragraph{Modify Flow Entry Message} -Modifications to the flow table from the controller are done with the \verb|OFPT_FLOW_MOD| message: - -\input{struct/ofp_flow_mod} -The \verb|cookie| field is an opaque data value that is set by the -controller. It is not used in any matching functions, and thus does not -need to reside in hardware. The value -1 (0xffffffffffffffff) is -reserved and must not be used. It is required that when \verb|command| is -\verb|OFPC_MODIFY| or \verb|OFPC_MODIFY_STRICT| that matched flows have -their \verb|cookie| field updated appropriately. -\\\\ -The \verb|command| field must be one of the following: - -\input{enum/ofp_flow_mod_command} -The differences between \verb|OFPFC_MODIFY| and \verb|OFPFC_MODIFY_STRICT| are explained in Section \ref{flow_table:sec_chan:flow_mod} and differences between \verb|OFPFC_DELETE| and \verb|OFPFC_DELETE_STRICT| are explained in Section \ref{flow_table:sec_chan:flow_removal}. -\\\\ -The \verb|idle_timeout| and \verb|hard_timeout| fields control how quickly flows expire. -\\\\ -If the \verb|idle_timeout| is set and the \verb|hard_timeout| is zero, the entry must expire after \verb|idle_timeout| seconds with no received traffic. If the \verb|idle_timeout| is zero and the \verb|hard_timeout| is set, the entry must expire in \verb|hard_timeout| seconds regardless of whether or not packets are hitting the entry. -\\\\ -If both \verb|idle_timeout| and \verb|hard_timeout| are set, the flow will timeout after \verb|idle_timeout| seconds with no traffic, or \verb|hard_timeout| seconds, whichever comes first. If both \verb|idle_timeout| and \verb|hard_timeout| are zero, the entry is considered permanent and will never time out. It can still be removed with a \verb|flow_mod| message of type \verb|OFPFC_DELETE|. -\\\\ -The \verb|priority| field is only relevant for flow entries with wildcard fields. The priority field indicates table priority, where higher numbers are higher priorities; the switch must keep the highest-priority wildcard entries in the lowest-numbered (fastest) wildcard table, to ensure correctness. It is the responsibility of each switch implementer to ensure that exact entries always match before wildcards entries, regardless of the table configuration. -\\\\ -The \verb|buffer_id| refers to a buffered packet sent by the \verb|OFPT_PACKET_IN| message. -\\\\ -The \verb|out_port| field optionally filters the scope of DELETE and DELETE\_STRICT messages by output port. If \verb|out_port| contains a value other than \verb|OFPP_NONE|, it introduces a constraint when matching. This constraint is that the rule must contain an output action directed at that port. Other constraints such as \verb|ofp_match| structs and priorities are still used; this is purely an \emph{additional} constraint. Note that to disable output port filtering, \verb|out_port| must be set to \verb|OFPP_NONE|, since 0 is a valid port id. This field is ignored by ADD, MODIFY, and MODIFY\_STRICT messages. -\\\\ -The \verb|flags| field may include the follow flags: - -\input{enum/ofp_flow_mod_flags} -When the \verb|OFPFF_SEND_FLOW_REM| flag is set, the switch must send a flow removed message when the flow expires. The default is for the switch to not send flow removed messages for newly added flows. -\\\\ -When the \verb|OFPFF_CHECK_OVERLAP| flag is set, the switch must check that there are no conflicting entries with the same priority. If there is one, the flow mod fails and an error code is returned. -\\\\ -When the \verb|OFPFF_EMERG_| flag is set, the switch must consider this flow entry as an emergency entry, and only use it for forwarding when disconnected from the controller. - -\paragraph{Port Modification Message} -The controller uses the \verb|OFPT_PORT_MOD| message to modify the behavior of the physical port: - -\input{struct/ofp_port_mod} -The \verb|mask| field is used to select bits in the \verb|config| field to change. The \verb|advertise| field has no mask; all port features change together. - -\subsubsection{\qosupd{Queue Configuration Messages}} -\qosupd{Queue configuration takes place outside the OpenFlow protocol, either - through a command line tool or through an external dedicated configuration -protocol. -\\\\ -The controller can query the switch for configured queues on a port -using the following structure: -\input{struct/ofp_queue_get_config_request} -The switch replies back with an} \verb|ofp_queue_get_config_reply| \qosupd{command, containing -a list of configured queues. - -\input{struct/ofp_queue_get_config_reply} -} - -\subsubsection{Read State Messages} -While the system is running, the datapath may be queried about its current state using the \verb|OFPT_STATS_REQUEST| message: - -\input{struct/ofp_stats_request} -The switch responds with one or more \verb|OFPT_STATS_REPLY| messages: - -\input{struct/ofp_stats_reply} -The only value defined for \verb|flags| in a reply is whether more replies will follow this one - this has the value \verb|0x0001|. To ease implementation, the switch is allowed to send replies with no additional entries. However, it must always send another reply following a message with the �more� flag set. The transaction ids (xid) of replies must always match the request that prompted them. -\\\\ -In both the request and response, the \verb|type| field specifies the kind of information being passed and determines how the \verb|body| field is interpreted: - -\input{enum/ofp_stats_types} - -\paragraph{Description Statistics} -Information about the switch manufacturer, hardware revision, software revision, serial number, and a description field is available from the \verb|OFPST_DESC| stats request type: - -\input{struct/ofp_desc_stats} -Each entry is ASCII formatted and padded on the right with null bytes (\textbackslash0). \verb|DESC_STR_LEN| is \input{define/DESC_STR_LEN}and \verb|SERIAL_NUM_LEN| is \input{define/SERIAL_NUM_LEN}. Note: \footnote{Added to address concerns raised in \url{https://mailman.stanford.edu/pipermail/openflow-spec/2009-September/000504.html}} the \verb|dp_desc| field is a free-form string to describe the datapath for debugging purposes, e.g., ``switch3 in room 3120''. As such, it is not guaranteed to be unique and should not be used as the primary identifier for the datapath---use the \verb|datapath_id| field from the switch features instead (\S~\ref{cts:handshake}). - -\paragraph{Individual Flow Statistics} -Information about individual flows is requested with the \verb|OFPST_FLOW| stats request type: - -\input{struct/ofp_flow_stats_request} -The \verb|match| field contains a description of the flows that should be matched and may contain wildcards. This field's matching behavior is described in Section \ref{flow_table:sec_chan:flow_add}. -\\\\ -The \verb|table_id| field indicates the index of a single table to read, or \verb|0xff| for all tables. -\\\\ -The \verb|out_port| field optionally filters by output port. If \verb|out_port| contains a value other than \verb|OFPP_NONE|, it introduces a constraint when matching. This constraint is that the rule must contain an output action directed at that port. Other constraints such as \verb|ofp_match| structs are still used; this is purely an \emph{additional} constraint. Note that to disable output port filtering, \verb|out_port| must be set to \verb|OFPP_NONE|, since 0 is a valid port id. -\\\\ -The \verb|body| of the reply consists of an array of the following: - -\input{struct/ofp_flow_stats} -The fields consist of those provided in the \verb|flow_mod| that created these, plus the table into which the entry was inserted, the packet count, and the byte count. -\\\\ -\label{flow_duration_info}The \verb|duration_sec| and \verb|duration_nsec| fields indicate the elapsed time the flow has been installed in the switch. The total duration in nanoseconds can be computed as $\verb|duration_sec|*10^{9}$ + \verb|duration_nsec|. Implementations are required to provide millisecond precision; higher precision is encouraged where available. - -\paragraph{Aggregate Flow Statistics} -Aggregate information about multiple flows is requested with the \verb|OFPST_AGGREGATE| stats request type: - -\input{struct/ofp_aggregate_stats_request} -The \verb|match| field contains a description of the flows that should be matched and may contain wildcards. This field's matching behavior is described in Section \ref{flow_table:sec_chan:flow_add}. -\\\\ -The \verb|table_id| field indicates the index of a single table to read, or \verb|0xff| for all tables. -\\\\ -The \verb|out_port| field optionally filters by output port. If \verb|out_port| contains a value other than \verb|OFPP_NONE|, it introduces a constraint when matching. This constraint is that the rule must contain an output action directed at that port. Other constraints such as \verb|ofp_match| structs are still used; this is purely an \emph{additional} constraint. Note that to disable output port filtering, \verb|out_port| must be set to \verb|OFPP_NONE|, since 0 is a valid port id. -\\\\ -The \verb|body| of the reply consists of the following: - -\input{struct/ofp_aggregate_stats_reply} - -\paragraph{Table Statistics} -Information about tables is requested with the \verb|OFPST_TABLE| stats request type. The request does not contain any data in the body. -\\\\ -The body of the reply consists of an array of the following: - -\input{struct/ofp_table_stats} -The \verb|body| contains a \verb|wildcards| field, which indicates the fields for which that particular table supports wildcarding. For example, a direct look-up hash table would have that field set to zero, while a sequentially searched table would have it set to \verb|OFPFW_ALL|. The entries are returned in the order that packets traverse the tables. -\\\\ -\verb|OFP_MAX_TABLE_NAME_LEN| is \input{define/OFP_MAX_TABLE_NAME_LEN}. - -\paragraph{Port Statistics} -Information about physical ports is requested with the \verb|OFPST_PORT| stats request type: - -\input{struct/ofp_port_stats_request} -The \verb|port_no| field optionally filters the stats request to the given port. To request all port statistics, \verb|port_no| must be set to \verb|OFPP_NONE|. -\\\\ -The \verb|body| of the reply consists of an array of the following: - -\input{struct/ofp_port_stats} -The switch should return a value of -1 for unavailable counters. - -\paragraph{\qosupd{Queue Statistics}} -\qosupd{The} \verb|OFPST_QUEUE| \qosupd{stats request message provides - queue statistics for one or more ports. - The request body consists of a} \verb|port_no| \qosupd{field -identifying the port and a} \verb|queue_id|. \verb|OFPP_ALL| -\qosupd{refers to all ports, while} \verb|OFPQ_ALL| \qosupd{refers to all queues configured -at a port. - -\input{struct/ofp_queue_stats_request} -The body of the reply consists of an array of -the following structure: - -\input{struct/ofp_queue_stats}} - -\paragraph{Vendor Statistics} -Vendor-specific stats messages are requested with the \verb|OFPST_VENDOR| stats type. The first four bytes of the message are the vendor identifier. The rest of the body is vendor-defined. -\\\\ -The \verb|vendor| field is a 32-bit value that uniquely identifies the vendor. If the most significant byte is zero, the next three bytes are the vendor's IEEE OUI. If vendor does not have (or wish to use) their OUI, they should contact the OpenFlow consortium to obtain one. - -\subsubsection{Send Packet Message} -When the controller wishes to send a packet out through the datapath, it uses the \verb|OFPT_PACKET_OUT| message: - -\input{struct/ofp_packet_out} -The \verb|buffer_id| is the same given in the \verb|ofp_packet_in| message. If the \verb|buffer_id| is -1, then the packet data is included in the data array. If \verb|OFPP_TABLE| is specified as the output port of an action, the \verb|in_port| in the \verb|packet_out| message is used in the flow table lookup. - -\subsubsection{Barrier Message} -When the controller wants to ensure message dependencies have been met or wants to receive notifications for completed operations, it may use an \verb|OFPT_BARRIER_REQUEST| message. This message has no body. Upon receipt, the switch must finish processing all previously-received messages before executing any messages beyond the Barrier Request. When such processing is complete, the switch must send an \verb|OFPT_BARRIER_REPLY| message with the \verb|xid| of the original request. - -\subsection{Asynchronous Messages} -\subsubsection{Packet-In Message} -When packets are received by the datapath and sent to the controller, they use the \verb|OFPT_PACKET_IN| message: - -\input{struct/ofp_packet_in} -The \verb|buffer_id| is an opaque value used by the datapath to identify a buffered packet. When a packet is buffered, some number of bytes from the message will be included in the data portion of the message. If the packet is sent because of a ``send to controller'' action, then \verb|max_len| bytes from the \verb|action_output| of the flow setup request are sent. If the packet is sent because of a flow table miss, then at least \verb|miss_send_len| bytes from the \verb|OFPT_SET_CONFIG| message are sent. The default \verb|miss_send_len| is \input{define/OFP_DEFAULT_MISS_SEND_LEN}bytes. If the packet is not buffered, the entire packet is included in the data portion, and the \verb|buffer_id| is -1. -\\\\ -Switches that implement buffering are expected to expose, through documentation, both the amount of available buffering, and the length of time before buffers may be reused. A switch must gracefully handle the case where a buffered \verb|packet_in| message yields no response from the controller. A switch should prevent a buffer from being reused until it has been handled by the controller, or some amount of time (indicated in documentation) has passed. -\\\\ -The reason field can be any of these values: - -\input{enum/ofp_packet_in_reason} - -\subsubsection{Flow Removed Message} -If the controller has requested to be notified when flows time out, the datapath does this with the \verb|OFPT_FLOW_REMOVED| message: - -\input{struct/ofp_flow_removed} -The \verb|match|, \verb|cookie|, and \verb|priority| fields are the same as those used in the flow setup request. -\\\\ -The \verb|reason| field is one of the following: - -\input{enum/ofp_flow_removed_reason} -The \verb|duration_sec| and \verb|duration_nsec| fields are described in Section \ref{flow_duration_info}. -\\\\ -The \verb|idle_timeout| field is directly copied from the flow mod that created this entry. -\\\\ -With the above three fields, one can find both the amount of time the flow was active, as well as the amount of time the flow received traffic. -\\\\ -The \verb|packet_count| and \verb|byte_count| indicate the number of packets and bytes that were associated with this flow, respectively. - -\subsubsection{Port Status Message} -As physical ports are added, modified, and removed from the datapath, the controller needs to be informed with the \verb|OFPT_PORT_STATUS| message: - -\input{struct/ofp_port_status} -The \verb|status| can be one of the following values: - -\input{enum/ofp_port_reason} - -\subsubsection{Error Message} -There are times that the switch needs to notify the controller of a problem. This is done with the \verb|OFPT_ERROR_MSG| message: - -\input{struct/ofp_error_msg} -The \verb|type| value indicates the high-level type of error. The \verb|code| value is interpreted based on the type. The \verb|data| is variable length and interpreted based on the \verb|type| and \verb|code|; in most cases this is the message that caused the problem. -\\\\ -Error codes ending in \verb|_EPERM| correspond to a permissions error generated by an entity between a controller and switch, such as an OpenFlow hypervisor. -\\\\ -Currently defined error types are: - -\input{enum/ofp_error_type} -For the \verb|OFPET_HELLO_FAILED| error \verb|type|, the following \verb|code|s are currently defined: - -\input{enum/ofp_hello_failed_code} -The \verb|data| field contains an ASCII text string that adds detail on why the error occurred. -\\\\ -For the \verb|OFPET_BAD_REQUEST| error \verb|type|, the following \verb|code|s are currently defined: - -\input{enum/ofp_bad_request_code} -The \verb|data| field contains at least 64 bytes of the failed request. -\\\\ -For the \verb|OFPET_BAD_ACTION| error \verb|type|, the following \verb|code|s are currently defined: - -\input{enum/ofp_bad_action_code} -The \verb|data| field contains at least 64 bytes of the failed request. -\\\\ -For the \verb|OFPET_FLOW_MOD_FAILED| error \verb|type|, the following \verb|code|s are currently defined: - -\input{enum/ofp_flow_mod_failed_code} -The \verb|data| field contains at least 64 bytes of the failed request. -\\\\ -For the \verb|OFPET_PORT_MOD_FAILED| error \verb|type|, the following \verb|code|s are currently defined: - -\input{enum/ofp_port_mod_failed_code} -The \verb|data| field contains at least 64 bytes of the failed request. -\\\\ -For the \verb|OFPET_QUEUE_OP_FAILED| error \verb|type|, the following \verb|code|s are currently defined: - -\input{enum/ofp_queue_op_failed_code} -The \verb|data| field contains at least 64 bytes of the failed request. -\\\\ -If the error message is in response to a specific message from the controller, e.g., \verb|OFPET_BAD_REQUEST|, \verb|OFPET_BAD_ACTION|, or \verb|OFPET_FLOW_MOD_FAILED|, then the \verb|xid| field of the header should match that of the offending message. - -\subsection{Symmetric Messages} -\subsubsection{Hello} -The \verb|OFPT_HELLO| message has no body; that is, it consists only of an OpenFlow header. Implementations must be prepared to receive a hello message that includes a body, ignoring its contents, to allow for later extensions. - -\subsubsection{Echo Request} -An Echo Request message consists of an OpenFlow header plus an arbitrary-length data field. The data field might be a message timestamp to check latency, various lengths to measure bandwidth, or zero-size to verify liveness between the switch and controller. - -\subsubsection{Echo Reply} -An Echo Reply message consists of an OpenFlow header plus the unmodified data field of an echo request message. -\\\\ -In an OpenFlow protocol implementation divided into multiple layers, the echo request/reply logic should be implemented in the "deepest" practical layer. For example, in the OpenFlow reference implementation that includes a userspace process that relays to a kernel module, echo request/reply is implemented in the kernel module. Receiving a correctly formatted echo reply then shows a greater likelihood of correct end-to-end functionality than if the echo request/reply were implemented in the userspace process, as well as providing more accurate end-to-end latency timing. - -\subsubsection{Vendor} -The Vendor message is defined as follows: - -\input{struct/ofp_vendor_header} -The \verb|vendor| field is a 32-bit value that uniquely identifies the vendor. If the most significant byte is zero, the next three bytes are the vendor's IEEE OUI. If vendor does not have (or wish to use) their OUI, they should contact the OpenFlow consortium to obtain one. The rest of the body is uninterpreted. -\\\\ -If a switch does not understand a vendor extension, it must send an \verb|OFPT_ERROR| message with a \verb|OFPBRC_BAD_VENDOR| error code and \verb|OFPET_BAD_REQUEST| error type. - diff --git a/openflow/doc/of-spec/credits.tex b/openflow/doc/of-spec/credits.tex deleted file mode 100644 index eb917c70..00000000 --- a/openflow/doc/of-spec/credits.tex +++ /dev/null @@ -1,22 +0,0 @@ -\section{Appendix B: Credits} - -Current Maintainer: Brandon Heller (brandonh@stanford.edu). -\\\\ -Spec contributions, in alphabetical order: -\\\\ -Ben Pfaff, -Brandon Heller, -Dan Talayco, -David Erickson, -Glen Gibb, -Guido Appenzeller, -Jean Tourrilhes, -Justin Pettit, -KK Yap, -Martin Casado, -Masayoshi Kobayashi, -Nick McKeown, -Peter Balland, -Reid Price, -Rob Sherwood, -Yiannis Yiakoumis. \ No newline at end of file diff --git a/openflow/doc/of-spec/figure_flow_table_secchan.png b/openflow/doc/of-spec/figure_flow_table_secchan.png deleted file mode 100755 index a21dde001128e353fb0a172fd4b6551931467604..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 67886 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 3~M{>^b~jIm2Vp1dl%!TTqD_` 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 - - - - ActiveLayerIndex - 0 - ApplicationVersion - - com.omnigroup.OmniGrafflePro - 138.12.0.121252 - - AutoAdjust - - BackgroundGraphic - - Bounds - {{0, 0}, {1188, 733}} - Class - SolidGraphic - ID - 2 - Style - - shadow - - Draws - NO - - stroke - - Draws - NO - - - - CanvasOrigin - {0, 0} - ColumnAlign - 1 - ColumnSpacing - 36 - CreationDate - 2009-11-19 17:13:27 -0800 - Creator - brandonh - DisplayScale - 1 0/72 in = 1.0000 in - GraphDocumentVersion - 6 - GraphicsList - - - Class - LineGraphic - Head - - ID - 88 - Position - 0.57036429643630981 - - ID - 102 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {584.932, 656.613} - {584.977, 688.774} - - Style - - stroke - - HeadArrow - 0 - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 42 - Info - 2 - - - - Class - LineGraphic - Head - - ID - 88 - Position - 0.84439820051193237 - - ID - 101 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {458.932, 674.613} - {458.658, 688.774} - - Style - - stroke - - HeadArrow - 0 - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 41 - Info - 1 - - - - Class - LineGraphic - Head - - ID - 67 - Position - 0.93292379379272461 - - ID - 100 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {242.932, 336.714} - {255.646, 688.774} - - Style - - stroke - - HeadArrow - FilledArrow - HopLines - - HopType - 1 - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 93 - Info - 3 - - - - Class - LineGraphic - Head - - ID - 93 - Info - 4 - - ID - 94 - Points - - {125.932, 336.714} - {143.932, 336.714} - - Style - - stroke - - HeadArrow - FilledArrow - TailArrow - 0 - - - Tail - - ID - 92 - - - - Bounds - {{143.932, 300.714}, {99, 72}} - Class - ShapedGraphic - ID - 93 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Rectangle - Style - - stroke - - Pattern - 1 - - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 Set IP source, destination from within ARP packet} - - VFlip - YES - - - Bounds - {{17.9318, 282.714}, {108, 108}} - Class - ShapedGraphic - ID - 92 - Line - - ID - 19 - Position - 0.51827484369277954 - RotationType - 0 - - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Diamond - Style - - stroke - - Pattern - 1 - - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 Eth type = 0x0806?} - VerticalPad - 0 - - - - Class - LineGraphic - Head - - ID - 53 - Info - 3 - - ID - 88 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {629.932, 494.613} - {386.932, 688.774} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 37 - Info - 3 - - - - Bounds - {{447.932, 175.932}, {72, 14}} - Class - ShapedGraphic - FitText - Vertical - Flow - Resize - ID - 83 - Shape - Rectangle - Style - - fill - - Draws - NO - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Pad - 0 - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 no} - VerticalPad - 0 - - - - Bounds - {{509.932, 85.932}, {72, 14}} - Class - ShapedGraphic - FitText - Vertical - Flow - Resize - ID - 82 - Shape - Rectangle - Style - - fill - - Draws - NO - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Pad - 0 - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 yes} - VerticalPad - 0 - - - - Class - LineGraphic - ID - 81 - Points - - {515.932, 108.932} - {566.932, 108.932} - - Style - - stroke - - HeadArrow - FilledArrow - TailArrow - 0 - - - Tail - - ID - 73 - Info - 3 - - - - Class - LineGraphic - ID - 80 - Points - - {461.932, 162.932} - {461.932, 216.932} - - Style - - stroke - - HeadArrow - FilledArrow - TailArrow - 0 - - - Tail - - ID - 73 - - - - Bounds - {{407.932, 54.932}, {108, 108}} - Class - ShapedGraphic - ID - 73 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Diamond - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 decision} - VerticalPad - 0 - - - - Class - LineGraphic - Head - - ID - 19 - Position - 0.11005332320928574 - - ID - 71 - OrthogonalBarAutomatic - - OrthogonalBarPosition - 0.0 - Points - - {197.932, 206.932} - {71.9318, 248.668} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 1 - Info - 2 - - - - Class - LineGraphic - Head - - ID - 53 - - ID - 67 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {71.9318, 548.613} - {278.932, 688.774} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 18 - Info - 1 - - - - Class - LineGraphic - Head - - ID - 53 - - ID - 63 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {332.932, 549.113} - {332.932, 661.774} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 47 - - - - Bounds - {{278.932, 661.774}, {108, 54}} - Class - ShapedGraphic - ID - 53 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Rectangle - Style - - stroke - - Width - 3 - - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\b\fs24 \cf0 Packet Lookup -\b0 Use assigned header fields} - - VFlip - YES - - - Class - LineGraphic - Head - - ID - 39 - - ID - 50 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {386.932, 494.613} - {404.932, 494.613} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 47 - - - - Class - LineGraphic - Head - - ID - 47 - - ID - 49 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {242.932, 494.613} - {278.932, 494.613} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 35 - - - - Class - LineGraphic - Head - - ID - 35 - - ID - 48 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {125.932, 494.613} - {143.932, 494.613} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 18 - - - - Class - LineGraphic - Head - - ID - 41 - - ID - 45 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {458.932, 548.613} - {458.932, 566.613} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 39 - - - - Class - LineGraphic - Head - - ID - 42 - - ID - 44 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {512.932, 620.613} - {539.932, 620.613} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 41 - - - - Class - LineGraphic - Head - - ID - 37 - - ID - 43 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {512.932, 494.613} - {539.932, 494.613} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 39 - - - - Bounds - {{539.932, 584.613}, {90, 72}} - Class - ShapedGraphic - ID - 42 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 Use ICMP type and code for L4 fields} - - VFlip - YES - - - Bounds - {{404.932, 566.613}, {108, 108}} - Class - ShapedGraphic - ID - 41 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Diamond - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 IP Proto = \ -1?} - VerticalPad - 0 - - - - Bounds - {{404.932, 440.613}, {108, 108}} - Class - ShapedGraphic - ID - 39 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Diamond - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 IP Proto = \ -6 or 7?} - VerticalPad - 0 - - - - Bounds - {{539.932, 458.613}, {90, 72}} - Class - ShapedGraphic - ID - 37 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 Use UDP/TCP source and destination for L4 fields} - - VFlip - YES - - - Bounds - {{143.932, 458.613}, {99, 72}} - Class - ShapedGraphic - ID - 35 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 Set IP source, destination, protocol, and ToS fields} - - VFlip - YES - - - Bounds - {{278.932, 440.613}, {108, 108}} - Class - ShapedGraphic - ID - 47 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Diamond - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 Not IP Fragment?} - VerticalPad - 0 - - - - Class - LineGraphic - Head - - ID - 18 - - ID - 19 - Points - - {71.9318, 224.932} - {71.9318, 440.613} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 6 - - - - Bounds - {{17.9318, 440.613}, {108, 108}} - Class - ShapedGraphic - ID - 18 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Diamond - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 Eth type = 0x0800?} - VerticalPad - 0 - - - - Class - LineGraphic - Head - - ID - 1 - - ID - 17 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {125.932, 170.932} - {143.932, 170.932} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 6 - - - - Class - LineGraphic - Head - - ID - 6 - - ID - 16 - Points - - {71.9318, 98.932} - {71.9318, 116.932} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 7 - - - - Bounds - {{8.93179, 8.93201}, {126, 90}} - Class - ShapedGraphic - ID - 7 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Rectangle - Style - - stroke - - Width - 3 - - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\b\fs24 \cf0 Initialize Headers -\b0 \ -Set input port, Ethernet source, destination, and type;\ -set all others to zero} - - - - Bounds - {{17.9318, 116.932}, {108, 108}} - Class - ShapedGraphic - ID - 6 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Diamond - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 Eth type = 0x8100?} - VerticalPad - 0 - - - - Bounds - {{143.932, 134.932}, {108, 72}} - Class - ShapedGraphic - ID - 1 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 Set VLAN ID and PCP. Use encapsulated Eth type for next Eth type check} - - VFlip - YES - - - GridInfo - - ShowsGrid - YES - - GuidesLocked - NO - GuidesVisible - YES - HPages - 1 - ImageCounter - 1 - KeepToScale - - Layers - - - Lock - NO - Name - Layer 1 - Print - YES - View - YES - - - LayoutInfo - - Animate - NO - circoMinDist - 18 - circoSeparation - 0.0 - layoutEngine - dot - neatoSeparation - 0.0 - twopiSeparation - 0.0 - - LinksVisible - YES - MagnetsVisible - NO - MasterSheets - - ModificationDate - 2009-12-16 14:42:02 -0800 - Modifier - brandonh - NotesVisible - NO - Orientation - 2 - OriginVisible - NO - PageBreaks - YES - PrintInfo - - NSBottomMargin - - float - 41 - - NSLeftMargin - - float - 18 - - NSOrientation - - int - 1 - - NSPaperName - - string - eleven_by_seventeen - - NSPaperSize - - size - {1224, 792} - - NSRightMargin - - float - 18 - - NSTopMargin - - float - 18 - - - PrintOnePage - - QuickLookPreview - - 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 - +qSeZg3KM+lp1mCFsp41mJI+c9ZghTrVdC/PGpibp8N9ueoqKWc6QE6f6rBoVuOjNNNT - /vXueHv3cCbpuRl5DNZ3+AhGgfKn35VfBGYCz6muyPvRkuJJHnEBFXnhMfcxFs850/lh - 2YXM3YVqdLFrWHLv0iVjg4DDlI5YMwzsDxWsYZjqkvFqnfUUS7HMj32b5tc04tt4+BPP - 3REWfVtpNV3TtcxXunKsCuxQunIMg3ocurWYtg6ofcXrCsz3qf6mYgolMeExrBIIPvI1 - VumyTiBXmT7aJVyjCx7l8VQKY5e0H4HjsxxckjsaiUKLF30fKcldi7tKsigYCru0k0qt - Xg26sgJFY5KNdJT4KdmEH8Ogt8xPr37hVCrJa/kVF5aTYSjsUtefYKHtHWhL6apgUqYT - v5J/l2ezgB5+pIn0kudmQpDXhQjrMJum+DAMvEc+6RJ9+3/P6L6+CmVuZHN0cmVhbQpl - bmRvYmoKNiAwIG9iagozNzM1CmVuZG9iagozIDAgb2JqCjw8IC9UeXBlIC9QYWdlIC9Q - YXJlbnQgNCAwIFIgL1Jlc291cmNlcyA3IDAgUiAvQ29udGVudHMgNSAwIFIgL01lZGlh - Qm94IFswIDAgMTE4OCA3MzNdCj4+CmVuZG9iago3IDAgb2JqCjw8IC9Qcm9jU2V0IFsg - L1BERiAvVGV4dCAvSW1hZ2VCIC9JbWFnZUMgL0ltYWdlSSBdIC9Db2xvclNwYWNlIDw8 - IC9DczEgOCAwIFIKL0NzMiAzNyAwIFIgPj4gL0ZvbnQgPDwgL0YxLjAgMzggMCBSIC9G - Mi4wIDM5IDAgUiA+PiAvWE9iamVjdCA8PCAvSW0xMiAzMSAwIFIKL0ltNiAxOSAwIFIg - L0ltMyAxMyAwIFIgL0ltMSA5IDAgUiAvSW00IDE1IDAgUiAvSW0xMCAyNyAwIFIgL0lt - OSAyNSAwIFIgL0ltMTEKMjkgMCBSIC9JbTE0IDM1IDAgUiAvSW0yIDExIDAgUiAvSW01 - IDE3IDAgUiAvSW0xMyAzMyAwIFIgL0ltNyAyMSAwIFIgL0ltOAoyMyAwIFIgPj4gPj4K - ZW5kb2JqCjMxIDAgb2JqCjw8IC9MZW5ndGggMzIgMCBSIC9UeXBlIC9YT2JqZWN0IC9T - dWJ0eXBlIC9JbWFnZSAvV2lkdGggMjYwIC9IZWlnaHQgMjYwIC9Db2xvclNwYWNlCjQw - IDAgUiAvU01hc2sgNDEgMCBSIC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxh - dGVEZWNvZGUgPj4Kc3RyZWFtCngB7dAxAQAAAMKg9U/taQmIQGHAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDgAwMYXQABCmVuZHN0cmVhbQplbmRvYmoKMzIgMCBvYmoKOTA4CmVuZG9iagoxOSAw - IG9iago8PCAvTGVuZ3RoIDIwIDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1h - Z2UgL1dpZHRoIDI0MiAvSGVpZ2h0IDE4OCAvQ29sb3JTcGFjZQo0MyAwIFIgL1NNYXNr - IDQ0IDAgUiAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+ - CnN0cmVhbQp4Ae3QAQ0AAADCoPdP7ewBESgMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwY+MBVGAAEKZW5kc3RyZWFtCmVuZG9iagoyMCAwIG9iago2MTgKZW5kb2Jq - CjEzIDAgb2JqCjw8IC9MZW5ndGggMTQgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBl - IC9JbWFnZSAvV2lkdGggMzAwIC9IZWlnaHQgMjI4IC9Db2xvclNwYWNlCjQ2IDAgUiAv - U01hc2sgNDcgMCBSIC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNv - ZGUgPj4Kc3RyZWFtCngB7dAxAQAAAMKg9U9tCj+IQGHAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAwGtgIb0AAQplbmRzdHJlYW0KZW5kb2JqCjE0IDAgb2JqCjkxOAplbmRvYmoK - OSAwIG9iago8PCAvTGVuZ3RoIDEwIDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAv - SW1hZ2UgL1dpZHRoIDI2MCAvSGVpZ2h0IDE4OCAvQ29sb3JTcGFjZQo0OSAwIFIgL1NN - YXNrIDUwIDAgUiAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2Rl - ID4+CnN0cmVhbQp4Ae3QMQEAAADCoPVPbQo/iEBhwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGPgODDzuAAEKZW5kc3RyZWFtCmVuZG9iagoxMCAwIG9iago2NjMKZW5kb2JqCjE1 - IDAgb2JqCjw8IC9MZW5ndGggMTYgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9J - bWFnZSAvV2lkdGggMjYwIC9IZWlnaHQgMjYwIC9Db2xvclNwYWNlCjQwIDAgUiAvU01h - c2sgNTIgMCBSIC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUg - Pj4Kc3RyZWFtCngB7dAxAQAAAMKg9U/taQmIQGHAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDgAwMYXQAB - CmVuZHN0cmVhbQplbmRvYmoKMTYgMCBvYmoKOTA4CmVuZG9iagoyNyAwIG9iago8PCAv - TGVuZ3RoIDI4IDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRo - IDIyNCAvSGVpZ2h0IDE4OCAvQ29sb3JTcGFjZQo1NCAwIFIgL1NNYXNrIDU1IDAgUiAv - Qml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4 - Ae3QAQ0AAADCoPdPbQ43iEBhwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDDwNDDtjwABCmVuZHN0cmVhbQplbmRvYmoKMjggMCBvYmoKNTc0CmVuZG9iagoy - NSAwIG9iago8PCAvTGVuZ3RoIDI2IDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAv - SW1hZ2UgL1dpZHRoIDI2MCAvSGVpZ2h0IDI2MCAvQ29sb3JTcGFjZQo0MCAwIFIgL1NN - YXNrIDU3IDAgUiAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2Rl - ID4+CnN0cmVhbQp4Ae3QMQEAAADCoPVP7WkJiEBhwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg4AMDGF0A - AQplbmRzdHJlYW0KZW5kb2JqCjI2IDAgb2JqCjkwOAplbmRvYmoKMjkgMCBvYmoKPDwg - L0xlbmd0aCAzMCAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUgL0ltYWdlIC9XaWR0 - aCAyNjQgL0hlaWdodCAxNTYgL0NvbG9yU3BhY2UKNTkgMCBSIC9TTWFzayA2MCAwIFIg - L0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0K - eAHt0AENAAAAwqD3T20PBxEoDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMDA/8AA4q8A - AQplbmRzdHJlYW0KZW5kb2JqCjMwIDAgb2JqCjU2MgplbmRvYmoKMzUgMCBvYmoKPDwg - L0xlbmd0aCAzNiAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUgL0ltYWdlIC9XaWR0 - aCAyNDIgL0hlaWdodCAxODggL0NvbG9yU3BhY2UKNjIgMCBSIC9TTWFzayA2MyAwIFIg - L0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0K - eAHt0AENAAAAwqD3T+3sAREoDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - PjAVRgABCmVuZHN0cmVhbQplbmRvYmoKMzYgMCBvYmoKNjE4CmVuZG9iagoxMSAwIG9i - ago8PCAvTGVuZ3RoIDEyIDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2Ug - L1dpZHRoIDI2MCAvSGVpZ2h0IDI2MCAvQ29sb3JTcGFjZQo0MCAwIFIgL1NNYXNrIDY1 - IDAgUiAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0 - cmVhbQp4Ae3QMQEAAADCoPVP7WkJiEBhwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg4AMDGF0AAQplbmRz - dHJlYW0KZW5kb2JqCjEyIDAgb2JqCjkwOAplbmRvYmoKMTcgMCBvYmoKPDwgL0xlbmd0 - aCAxOCAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUgL0ltYWdlIC9XaWR0aCAyNjAg - L0hlaWdodCAyNjAgL0NvbG9yU3BhY2UKNDAgMCBSIC9TTWFzayA2NyAwIFIgL0JpdHNQ - ZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAHt0DEB - AAAAwqD1T+1pCYhAYcCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYOADAxhdAAEKZW5kc3RyZWFtCmVuZG9i - agoxOCAwIG9iago5MDgKZW5kb2JqCjMzIDAgb2JqCjw8IC9MZW5ndGggMzQgMCBSIC9U - eXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMjYwIC9IZWlnaHQgMjYw - IC9Db2xvclNwYWNlCjY5IDAgUiAvU01hc2sgNzAgMCBSIC9CaXRzUGVyQ29tcG9uZW50 - IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7dAxAQAAAMKg9U/taQmI - QGHAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDgAwMYXQABCmVuZHN0cmVhbQplbmRvYmoKMzQgMCBvYmoK - OTA4CmVuZG9iagoyMSAwIG9iago8PCAvTGVuZ3RoIDIyIDAgUiAvVHlwZSAvWE9iamVj - dCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRoIDIyNCAvSGVpZ2h0IDE4OCAvQ29sb3JTcGFj - ZQo1NCAwIFIgL1NNYXNrIDcyIDAgUiAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIg - L0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae3QAQ0AAADCoPdPbQ43iEBhwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDDwNDDtjwABCmVuZHN0cmVhbQplbmRv - YmoKMjIgMCBvYmoKNTc0CmVuZG9iagoyMyAwIG9iago8PCAvTGVuZ3RoIDI0IDAgUiAv - VHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRoIDI2MCAvSGVpZ2h0IDI2 - MCAvQ29sb3JTcGFjZQo0MCAwIFIgL1NNYXNrIDc0IDAgUiAvQml0c1BlckNvbXBvbmVu - dCA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae3QMQEAAADCoPVP7WkJ - iEBhwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBg4AMDGF0AAQplbmRzdHJlYW0KZW5kb2JqCjI0IDAgb2Jq - CjkwOAplbmRvYmoKNDQgMCBvYmoKPDwgL0xlbmd0aCA0NSAwIFIgL1R5cGUgL1hPYmpl - Y3QgL1N1YnR5cGUgL0ltYWdlIC9XaWR0aCAyNDIgL0hlaWdodCAxODggL0NvbG9yU3Bh - Y2UKL0RldmljZUdyYXkgL0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURl - Y29kZSA+PgpzdHJlYW0KeAHtne9vEtkax21LocAAQ0sHyo8LDlAYkLIjKG2pCw0ExVKt - VVxcW1KdapZKRY1EsrUupiqR+KN1bbRGa9dYjbqNNY0as5r7r93nUHP3SnHd+46zPd8X - RpKanM98n/M5U3xxtmwhIU+APAHyBMgTwPcJNGCd/+u5A2njn2nCLH+uvBFA/gb4Oi1Q - ikTNGEckAgQE/y3oCu86rFgiaVmPFKN8XrJEIoa6APsbzJ95m5vFACuVyeRyOUVRCqwC - C4Zly2TSlhZE/dfMCLgJZhlwAZZSKJUqmlZjF5pWKZUK4JYB9DrzV0a7Agz9Il6FUqVW - t7ZpNO3tDKPFKAzT3q7RtLWq1SqlAjFDzzDatZFRw6hgxEsDLaPVdej1BqPRhFGMRoNe - 36HTMkBNV5ihZoRcQ9oVYNjAcgp4ARdYTWaLZStrxSrsVovFbAJugAZmSo62c23kBrSH - JVIoWN3G6PRAy1rtnQ4nx7lcbkzicnGc09Fpt7JArdcxbWqoWSpB/tpYMlQMwC1yhUqt - 0epNFtbWybm2ebxenue3YxNYrNfr2ebiOm2sxaTXatQqBbTcLKox11AxSEtWATaYWbvT - 7fHyvh07Az29kCAWQSvtCezc4eO9HrfTzpoNFWQZ6KtGyQ1QcYuMUqo1OoPZ6nB38f5A - T3BXKNwfiUSimASW2h8O7Qr2BPx8l9thNRt0GrWSkrVAydVjvV6xHIC1BouN8/D+7mCo - PxrbEx9IDO7DJoOJgfieWLQ/FOz28x7OZkEtK+W1SkbEMNM0AJttnNcX6AtHdu8d3D98 - MHk4hVEOJw8O7x/cuzsS7gv4vJwNDTatgJI3jDUMtbhFrmxl9GYr1+XvDUXjiQOHUkdH - 02PHBWEckwjC8bH06NHUoQOJeDTU6+/irGY904pK3jDWDY1wMkHFOhPr8Ph6w7GBoeSR - 0THhZOZUdvJ0DpOcnsyeypwUxkaPJIcGYuFen8fBmnRQMpxQ1RsZDTXsYkZvsbv5QCiW - GE6NHDuRyebOnc9fKGCTC/nz53LZzIljI6nhRCwU4N12i55BOxnG+svXrgqxqk1rYp1d - /r4oAKeFzOTZfGFq+lLxMjYpXpqeKuTPTmaENCBH+/xdTtakbVPVJBZLKVrTYba5+e5w - fCiVHp/I5QvTxZmrpetlbHK9dHWmOF3I5ybG06mheLibd9vMHRqakoo3dCwSSxVoqDs9 - /mBkMDkiTJzJTxWvlMo3b8/ewSazt2+WS1eKU/kzE8JIcjAS9Hs60VgrpKCuqqkWSWTK - Vq2RdXoD3+8+cOTYT7n81OVr5Vtzd+fv31/AJPfvz9+du1W+dnkqn/vp2JEDu78PeJ2s - UduqlElqEMuVsI2tLr6nf++h0RNZAC7dmL1778HDxcdLmOTx4sMH9+7O3igBcvbE6KG9 - /T28ywobWSmvQQyq1nT8y77NB0OdGsucLfxy7cbc/MKjpSdPl59hkuWnT5YeLczP3bj2 - S+FsZiwFY+3bZv9XhwZkvaFjOJxUGrSNd+yK7f9RyOYvzpRn5x8s/rb8/MXLV5jk5Yvn - y78tPpifLc9czGeFH/fHdu1AG1mDZF29j4GYBmKHNxDaMzx6Mlcolm7dXVh88uzlq5XX - q5jk9cqrl8+eLC7cvVUqFnInR4f3hAJeBxDTNYkpul2/FcQVjh9MZ879PFOeu/cIgFdW - 36xhkzerK4D86N5ceebnc5n0wXgY1LVV305TtTqm1O0Glvuup38gOTZx/uLVm78+WFp+ - sbK69vbde0zy7u3a6sqL5aUHv968evH8xFhyoL/nO441tKu/QswYWY7vjSQOH8/mL5Vu - zT988vz312tv33/AJu/frr3+/fmTh/O3Spfy2eOHE5FenmONzNeJ4XAC4h+EyQvF67fv - LT59sfIGgP/4iEn++PD+7ZuVF08X792+XrwwKfyAiF3WbxIPpoTThcvlufuPl1++XnsH - wJ8wycc/Prxbe/1y+fH9ufLlwmkBjqevEcMviy2UmjFWOq5B/G8s8umvib/43qehqRle - q+GVy709GN2XGs9Bx3cWlp69Wl17/+HjJyx4YZGfPn54v7b66tnSwh3oODee2hcNbnfD - Sxe8WDc3EWLSMZlqHPYy2cfEXP/zLQg5nch5jIO2yBsIeecib5nkNwnyuxMWtiZvmeQt - k7xlkm99yPdc9a9r4mriauJq4mriauLq+nsC5HQipxM5ncjpRE6n+nNz9YqIq4mriauJ - q4mrq81Yf5+Jq4mriauJq4mr68/N1SsiriauJq4mriaurjZj/X0mriauJq4mriaurj83 - V6+IuJq4mriauJq4utqM9feZuJq4mriauJq4uv7cXL0i4mriauJq4mri6moz1t9n4mri - auJq4mri6vpzc/WKiKuJq4mriauJq6vNWH+fiauJq4mriauJq+vPzdUrIq4mriauJq4m - rq42Y/19Jq4mriauJq4mrq4/N1eviLiauJq4mrj6n+3qTXej1ZZvEP/zbi37gnhT3Uy3 - 2W4f3HQ3TG66W0Q3302xm+02YNGmu/FZJNl0t3pvvpvbxXDFJIOu9fbDRebJEWHiTH6q - eKVUvnl79g42mb19s1y6UpzKn5kQRpJwjbkfXerNwCWi4g33mDeJpRSt6TDb3Hx3OD6U - So9P5PKF6eLM1dL1Mja5Xro6U5wu5HMT4+nUUDzczbtt5g4NTUnFTdX3mDehq9vbtCbW - 2eXviyaGU2khM3k2X5iavlS8jE2Kl6anCvmzkxkhnRpORPv8XU7WpG1DF7fXJFaisba7 - +UAoBsgjx05ksrlz5/MXCtjkQv78uVw2c+LYCADHQgHebUdDraxBDBcgS6QKWqMzsQ6P - rzccGxhKHhkdE05mTmUnT+cwyenJ7KnMSWFs9EhyaCAW7vV5HKxJp6EVUklz4xeXAW/Z - 0tAoEsOJ3MrozVauy98bisYTBw6ljo6mx44LwjgmEYTjY+nRo6lDBxLxaKjX38VZzXqm - FSoGcW0gho0sg5K1BrON8/oCfeHI7r2D+4cPJg+nMMrh5MHh/YN7d0fCfQGfl7OZDVqo - WIa2cQ1iVLIakC02zsP7u4Oh/mhsT3wgMbgPmwwmBuJ7YtH+ULDbz3s4mwWA0S4WbyRG - Yw0lU4CsM5itDncX7w/0BHeFwv2RSCSKSWCp/eHQrmBPwM93uR1Ws0EHwBRUvGGo0UZu - ahbDXKtQy2bW7nR7vLxvx85ATy8kiEXQSnsCO3f4eK/H7bSzaKTVKpjpWhUDMZQsaZFX - kPUmC2vr5FzbPF4vz/PbsQks1uv1bHNxnTbWYtJXgOUtEqi4ehvDl/VQMiBL5Qqluo3R - 6U1mC2u1dzqcHOdyuTGJy8VxTken3cpazCa9jmlTKxVyOJlEG7yF/ncCSoa5hpYpJd2q - YbR6gxGoLVtZK1Zht1qA1mjQaxlNK62koGE00zUq/owMgy2DmunWNoDWdeiB22jCKEZg - 1XfoALcNeBVyGYz014C3NFRaBn1VmFVqNVBr2tsZRotRGKa9XQO0arWqwgvSqgBXHcaf - /8utgixqhpqBWU4plEoVTauxC02rlEoFJYd+UcGwhxsbagPDXEPLyF9oO7dIZYAtpyhK - gVVgwbBsmUwKuNAv4v06MNLXOjNAAzVgVyLFKJ+XLEG0zaJv8laUjZgbm5qaRAgb2wBs - E6r3L/v9vJtR0RVq9PMQ+JdYZX3VlT8B5L9Qf+cv8PMY5+8Qkp8hT4A8AfIEyBOo1yfw - HxfQr7EKZW5kc3RyZWFtCmVuZG9iago0NSAwIG9iagoyNzk1CmVuZG9iago2NyAwIG9i - ago8PCAvTGVuZ3RoIDY4IDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2Ug - L1dpZHRoIDI2MCAvSGVpZ2h0IDI2MCAvQ29sb3JTcGFjZQovRGV2aWNlR3JheSAvQml0 - c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae3d - /1NSWRQA8L4o8k1ERVSSlaJscSC0MFOyNBq/t1oOI30znDKjRi0dWkfLKdQpsfJL5bjm - aE7soJlp6qhtu7P/2p77sEwXFBXeu/fC+SUNSvh47rnvPeCcPXvCERYIC4QFwgJhgbBA - WCAsgJHAXhT7IJgvMHpgLD2U1WcPAPv3IwYI+CuWfjgWP8bz69+/PyIiIhIC/vBIhJAC - WgAAAM+ex4uC4PEQBMMQIqmAkgAB8KL4fL5AIBQKBPBFFDhEwLIIiVRgCBgBgVAkEkdD - iEUioYBRCA0EIIAk4PH5QpFYIomRxkJIYyQSsUjI5/NQKlCfCR6CKBCIlkhj42SyBAiZ - LC5WKokGhagQQFglEEAOSONkCYlJCiaSEhNkcVLIBQH9CB4CvkCEBORJihRlqgoiVZmi - SJIjBZGAT3kmrBIIRZLYeHnSAaXqkPpIGsQR9SGV8kCSPD5WAuuBaoTvBGJJrCxRoVSp - 0zTpWt2xYzptuiZNrVIqEmWxEjHVCD8IYuISklOQgFafecKQlWU4kanXIoWU5IS4GJoR - fiKQK5QH0zS6TEN2rjEPwpibbcjUadIOKhVymhHWCOLlil/UR7UZhlPGs+fOF0KcP3fW - eMqQoT2q/kUhj6c2E34iSFSkqjW649nGfFNRaXkFRHlpkSnfmH1cp1GnKhJpRVhPcFij - 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 - a7jf3NLSfL/BVme9aq4oMZ0m8qrRVlmAbt+YCfosY0HxhSrL9dpb9ba7d231t2qvW6ou - FBcYs/QEXjjzh+B/CDAnNTe/sKzSbLlWY62ttdZcs5grywrzc2HeKHnXDv0j2ICQehgQ - cs6Yissrq8wWCHNVZXmx6UwOIkgl7fKpvwQbEdQa3fFsY76pqLS8AqK8tMiUb8w+rtOo - KSZYhyCHyclHtRmGU8az584XQpw/d9Z4ypChPQrTh+VkXUT3PwvQPdcKI0zQVh5M0+gy - Ddm5xjwIY262IVOnSTuoZEZxE/Q6wvYI1iEkJKeo1GkarT7zhCEry3AiU6/VpKlVKckJ - ayPZcX1xfbtPe/39f2QCTNFOVCiRQrpWd+yYTpuOBJSKRJhATdKrSeufnn/ffUeAUeLx - 8qQDStUh9ZE0iCPqQyrlgSR5PMxepngheJBWEQQiiTROJk9SpChTVRCpyhRFklwWJ4WJ - 9Hi/y8S/3/Xm9/IgRAlEYqSQkJikYCIpMQEJiEVoDDnGb7TZ/Mn5e+sqAl8oipZIY+Nk - sgQImSwuViqJhnUQCgTfdwceHxTEEkmMNBZCGiOBHBDy+bwQyAKULZAJMCUxkhfFFwhF - InE0hFgkEgr4UbxIGMOO7zvO/E11f+7HIEQwCny+QCAUCgR8PiMApSA0CFAq7INUgLEv - 4MCLguBBBsAqAAFvw3b9cSXwPigVGIYIBBEZEeEBCJkk8PzK9noYGAnkAQF/ReCvc5cP - GZ60R4L5Ypf/WfifhwXCAmGBsEBYICwQFggLBFbgP0gqPFwKZW5kc3RyZWFtCmVuZG9i - ago2OCAwIG9iagozNzExCmVuZG9iago3MCAwIG9iago8PCAvTGVuZ3RoIDcxIDAgUiAv - VHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRoIDI2MCAvSGVpZ2h0IDI2 - MCAvQ29sb3JTcGFjZQovRGV2aWNlR3JheSAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0 - ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae2d+VsUx9bHXdiRYdVhVRBFQRRQzCiK - gEQQQVAgcQEjChoRXFAxEL0oj4orwYvixUB4JRdRiaAoatTXJ//aPVXd1V09U70NPTM9 - A/2DNM0IU585VfU9p06dWrBg/ponME9gnsA8gXkC8wTmCcwTMBOBhfhaxH0x0xtz03uB - hi+SXIiEm/62Of4MD2DxYj/uWrwY85hDFDABaL8/XAHogq9+fhjDXDEFhAADCAgMCgoK - DoZ/ggKBgx+yhrkBgScAAIJDQkNDlyyBf0IARCCiMDcgcAgCgoIAQJjFEg6XxRK2BGEA - CnMCAkLg7x8IBMIs4ZGR0dExMTHRUZERlrDQkKCgAH8/37cEjCAgKBgIRETGxCyzxsbG - xVqtS2OiIoFC8FyAwCMIWWKJiIpZFhufkJS0fHlSUmJ8rDUmKsKyJAQg+Hh3wAgCg0LD - wiNjrHEJSStSUlNXrUpNTUlOSoizxkSGh4XCoODTEHgrCA2LiF4am7A8OXX1mvSMdesy - 0tempSYvT4hdGh1h8XEIgMDPPyAo1AJGEJ+UnJqWnrkhO2fjxpzsrMyMNanJSfFgCgDB - h7sDjSBhRWpaxvrsTZttW/Py8rZ8l5uzPiMtdUUCB8FnuwOFIDYxeVV6Zk6uLS+/sKi4 - eGfhjm1bcnMy01clJ8ZiS/BRCARBWGQMIEjLyNpk21ZQXLJ7T3n5nrKS4sLttk1ZGWkp - SRwEn9QJgGAxKKNQhCApJW1d9ua8guLS8sr91bW1NdVVFbuLC/I2Z2emrfRdCAQBDIcI - QWaObXtRSXlVzYHDdUeO1B8+WLuvoqRouy0nc43PQnBEkF9cVlVzsL6hsenkyRONDUcO - 1laVFefbNvosBIyAmxSxFWzcUrCrfP+B+oamUy1nzp4909p8oqH+x/3lu3ZsAQh4TACx - 5FNjggOCrQUlFTWHjjY1n2m71P7LL5cvtZ1pbvzpYHVFScHWjZnCwOhDs4N9R9i4tbBk - b23dsZ9b29o7r3Zdu9Z1tbO9rfVkw+GavSWFPgmBQhCXtHJNJkJQ+UN9Y/O5S51d3Td7 - bt/uudnd1Xnp7KnjdT9U+iQEQEAEcqyI4Ejj6bZfrnbfunu/97e+3gd3b3VfuXy+ubHe - HoJPyGYZBE0tFzq6bt550Nf/eGDgcX9f750bXR1tpxuP/FBZ6mvdQQ5B64XOa7fu9fU/ - GRyC6+mTR333bl3ruNDSRCBQOsHLXWl5BL9e73nwcGBweOTZ6OjoyPDTgYcPeq53Xmil - IcT5ghdJEHACmRsO98Jw2Hrh1+7bvf1PhkZGx56PvxgfGx0ZetLfe7v714sYAh4YKUvw - 4hgjIMA+AhHIeFIEBC0cgsHhZ2PjLycm/pp49WLs2fCgL0JgIUCTIofg0eAfo2MvJyYn - 37yZmpx4+Xz0Dx+EoIZg5M/xV6+n3k6/ezf9dur1q3GA8EjoDpxY8vbugBHQPsLWwtLK - H47ApIjGgkdPAcHE5Jvp9zMzH2beT7+dnBj/k4dwoQV0Ag9B9B28cHaQQ8ANhwjBi4nJ - t+9mPnxE18w7DGGEswQMwfsVo6QjcAIZW0HrRd4K/osQvJ/5+Onvz5///vTxw3ufgwAI - iEAmPgILwYePQODLF6DAQXjxp2gJIJakvoOXyWYKAe0jNPFWMDgCVjD19j1C8OUrXF8c - IYhiSXClvQqCKgIYCxAC6Adfvv4/XF+/fv78CXeHF/8deYpnB0oxCjFGL4onaEEAY4GI - AFFwgMApRuxAed8USRBggczHC0AgN/EzwiA3I4gIvn3DpsBBmJoAS6B0AjcmeBsEQEAJ - ZNFHIOoQ6wLKCr6hS7QEgEAGRq/1HaQI0oSokQMCmBDQWIARYAgwPfBjgpdDcBIBgoBm - BxYEb5PNGIGjQBbcJGEs+PwZTwi8FfC9wRHChVZBNlNTpKldaRkEZDjkBTIMhw4IuCFB - 6A7jpDtQvoMAwdRTpKQjrMRjAacOiZvECWSCQDQCfIfGRRkIdorRxBAAARHIRB0yBTJv - BQKCf/g7BEHQCVJLsINgWsXIQADrCEckAhlLI64jiAgIA1onTKIpkleMYqBV6A4mhaCK - ADvLwlhAIfhHBgJLNov5CSaMJ+hA8EWUBd/+4S6BCOoPgk4gEFiy2YRjggRBiqAOxY5A - rIBzk0ibeQSiJVCKEboDGwIJuZtsigQElEDm1CEKoquoQwEBE4J3yWYWAjqCLPgIUoFM - IYBbYhuS7kB0gul9B0MQSCA4KkaTQ8AIpAIZTYpUR8CxQySN0HBI3CSpFaDveEtAhiCI - JcGLhKAKI9pskjGBgYBWh2K8wE4gOzJgQpCKJXMmaUg6gg6BzEDAtgQpBDvFaIopEhA4 - J5CZDDRYgvkgMBDQAvkpiSA7+AhsBLQlUGKJzA5UfoJ5ZLMKAjwW4Aiyg4+gwkDOdzBf - yF0LAt5NYghkNgYiE1QVoxBy92geo2YEMgJ5lhDMEG2WIBB9BD7L5JE4KfJLKfwnzG45 - 9ZRhCWaVzYBglj4C1W7JLQMCjieYbt2BhUC3jyBpOvUNoQCS0VExmkY2qyMQBPJXah2B - aqfirQiBHXKXyma8B8rtshkjkPoIWCCLWSYiAspHIDETxfbjH/IQON+BX3eQKkZPZ6ow - rID2EWSD6OptF14hgcCvQEkheFYxShDIZ5k4BNGFBmq5MTcEQGCkjyAHRITAlM2Ouc1u - jDYzENA+As4yYQfR5VrLfs4zMKNsVkVAskykPgK7nYpPCQS2bKYyVQTF6CZXWgsCkmUC - ozpph2Jj5X5I/jMbAivk7hbfgSCwS8Mmy6pOC2Q2BjkItGJ0e7oOIHCRQNYMwdO+AwuB - YQJZmYJZZLMHEAiRJRgT2LL5CMltxjtkXb0vEiOQCmQ8KYqrSUyBzP58tT/lBwWJbKZC - 7kKmirA5NNB1hWUYVmC0QGaDkUBgymZ3hdwlVkALZJUsE3a7dD1Vh+Ae34FCoJiGrTmC - rIcCC4LYHdB+BzsILpHNgMDeR3CJQGaT4RnIyWb3ZKqoIiD5BVKBrD1ewG678JQNgeQn - ULLZdesOmhFA+HS2Allot+SGQNAumw32HQgCaRo2lW5FrEBXEF3SRtVv9EMw1HcABItR - XSM7H4FaXIftWfZp2N8M6wc8HgYEkM1uynLHCKCcC71V08UCmW0VhAJSS0KqP1mLdGm0 - 2TQIaNns3pA76QhSK3Aiy4T92ep7yluCnGx2UaYKAwEtkMV4gXqWib7msl8tgeAm2Szp - CLPNMmE3S99TdQh2inHWUyQgsFeHnBVIt2rOLojuYgizlM0MBLRA1p9loq+5zFdTkwOZ - HagFWdjvQCppGKMYVRA4kWXCbJXOh3IQHPdFGpDgrQWB3iwTne1lvpxAYMtmyncQQu5O - K0YWgr30fgQ3CGQmA5K8Rm8JdE2CtwQBVLojhTwctmoq5SCz2zDrpwxLcIVsBgRuDaLr - 48KAQA2MBslmFgKP+AhybAgFkIwuSvDGCBwiyMz9CM5kmcg1TM9zEQIj5O6Q4K0/U4WB - AEsjw7JM9DRW7rU8BM53UJXNeotXyyGQ1jIRtmfNbl1Vronqz9UhOC+bJQjoILrnBDIb - iG4ImmUzICA+gvuD6OzGyj0VIRgrmykEZLcq7SN4SCCzKfAMSMhdKCwzS9msBQEj0Yb9 - Hl3+lEBQl806fAeCgI4gSzbsUgIZRmTyHlzeWLk/QN4AGwI7U0Vlhywg4CLIEVwpaDMJ - ZDYGOQh0pop9KUJlCAsxgpCwiBhrIvIRthSU6NuqyX6jrnzKgOCYqVIAdZtxPCEC5yco - QcA9IShkSXi0NSEZCoJ7AQLASyjIyWaU21ywJSczLTnRGh0Ox52gI5Bkj4FCZhAYHGqJ - WhafvHpdjm0HqoMMSymdqNIdzAj8UooHPEVFSxIhsGRzS2NdbcWuHbacdauT45dFWUKD - lXI0kBlwTkLc8tT0bFv+rgpAcPpC53UOgUuyTBRbp/GHPARONksLy0CN1tONdTUV3+d/ - l52eujxuKTnoQ8YQODNYAoNB0sq1WZu3F5fX1B1vbutQQmD0iprGVtu9TAJB6jtc72hr - Pna4ek/x9twNa1cmWWPCl2BDkGXg54+W1KAnpGVuyttZVn3oWPP5jms9vf326wjE/MyB - QBgT7BwoVJ60p6vj3KmGg/vKivJgXITegA1BdkRYtMg/IBjMIDYJ9YSCkqoDR38+d7nr - 1gPTI5CBgGq03r/ZdfnsyZ9+rCzZYYPeAEdcRCBDkBkVUVcICrFELkVmkLutuKIWipy1 - X71x79//GR4VhkNqU4rhS8t2Fq7nW2KYYAmi7zA+Ovyfh/duXLnUioaE4m25yBDwiACZ - a8zOgBmEWqJhNEjPshWU7jt4rBmmhDt9A0Ojz/HiOtQ7NCkCwRBIoBX7Dq+ejw4N9N3p - 7mxrht5QWoANAeZHONtBlgHMCtAV4pavWrcxb2d5bf2JM+2oJzwdGXv5GvILUMlHwEyQ - 6/mY3PBa8rY42QyVOd+9ff1yDBXXudXVfuZEfW15cd7GdatXxHGdQc4O/AKCw/iukL+r - 8kDDqTZsBsOjUPNxegZXvTQtAqklQIwRCtVO/fVidPhJ310whFMNBypL8jevx50hLAQN - CKxTXRcu8g+E4WBZQsqarO92lO47dLzl4pWb92FAHHvJuYp0pTs3fLJ6/wRlCSCWPn2E - OrWvxkbQsHj1Ukvj4f27C2xZa1MS8cwgwwCmBWAQZU1Ew0FhWXVdYyt0hd5Hvz+D0WD6 - vdQM9L4/97yep4DHRTCE6amJ589+fwzzY/uZprrqssItaGawglYMkmMA0wLoZCuaGbcU - ltXUnzh7uet2L4yI4xNT71BXEAdE9zRJ/1/hIHBzA+oME+MwKv52G6bHE/U1e4q25lAM - WBMDmhoFBkVez4CzA8IABsWasqItNAPWeEAYQF/Ixn2hCU0LvY9RX+CHRHFW0P8RueN/ - iH0BDYrvpydRX8ATAygE6AswOa5MVOwLwpi4FuTB7v2HG1suXeXGxFcwJn78hKt/koHH - HU3S+zdEBGhMRMWKYXJEY+KViy3HD+0r3fFd1pqUBBgTlecFbm5cn5tfAnNjM8yNd/ue - wNz41xs8INDywCyugghKgkDsCkgknT919EDlru25/NwIYllBHwgaqbi89gjWSFAj//+4 - yVEyKsIfFP+6Ke6IhXIbXohGGux/wGmkmvKdoJFWLUcaSVknSrQyNgRKK7skL98ofiIC - tArLa+VnolauAq2clQ7eczSaGmW1Mp4YpD7TpSve5TNJAszIZ/r3vRtX26HGVi3xmdBw - gOQBa2pcIIRQRN/5p5MgEZDv/IcYR0MiwXQ+AzECCYIXcKoF6gm/nPv56IGqEs5lEnxn - 1tS4YAEJpeEYysa8orL9BxtOnSMxFMF7RgMjgWCUIc/y98gggDmht+dax/nmY4f2l+3M - 2yTEUOS6wgIwBD8IqaKoMsTSNuRCLK368DExliZCEPWiOcZFNgIupf16Bw4olhdv35wF - sTTBDJhdATHACyyQmczHVL+vqKFjqmaFQBAg+xQrkfI1aXFMFQLL+Sh4QGKq8nVD8PKC - JLaOA8vi9kUegs5aP7O0c9X/LocALzV1XuBOuCmQxNZlRkQ0RIAhQFQVr7HA0buMNRY+ - uu7C7SqqLXZ8Ac8AGYFQREdaNYSssSSQNZZF7FmBY4B7A15rQyfPorU2M6+4Yh5aEHBH - ASZaYyLCQvAx4jKjAQWB27LCnx9hD0FfDTjHj83gJzoRcCepL1RgAL1BSEJhZ2DIlEw3 - uGHaf50EgXSJqftXqmy/sBlaQz4OQBAmB/7YTU9n6ysB4REgaWRgmiKGQHZw0RlZrt/W - rNRY9s8oBIbu8qIsgTuMmT9ozWSZeQCFEKAEsmPqARoO9SewMyCg2YHazmiOBWgGApy+ - TqegOF0sRdId+JR1UyUr444hh4BLSmOlIuna2uQNEAgCqUA2cBc4gcDt7hU3L5hHNrMR - GHpuBUAgyaowMOo/S4A9jBv4lGegIJDtkpU16AKkEulLAkFGMeIFOM+sw+pGoGssICC0 - QPCYbFZHYEyVGFUI/CGMHgi0ShA4CGTGcbBKmWjkQ2d+ZUAwh2zmEYA0YuTi4UmRrzNq - QNUok0IQEbijAgBAIA6UaWQzIeACgczsDciVZkLw3MYmBgLjBLJmCOA7eG6DmxwCeYHs - 9D5fEQi2BOJKe9x3UEZAb3Umezac0gVi87k7FgRP5fMTBFIfQRDIrjucASBg2WxfGcgD - G595BgiBEEGmy6YZW/qAtgYCAVeFUZHNsAJFPiwDnQP+V4kI5ILodj6CIR1B6A6iA6UE - gTuAyVUQPIkArb1QXiQLgjuizRIEClXouRogqnt2aEvXdE9BIPs+6cUXdxRGIdYlJ5Bd - fxoBQCDlEAgE9/oOIgIjg+iaDEB4EQVBi2wmb9mgtXnh16GYiXDGpVtKpQkE4AZDkJZE - cFs9ADYCN5XMU4EgJ5sNzu2WQ+BSgUw3XbxndAe3QNCMQDi1yumQidhYuTsWBNfLZoJA - u0A2UBo5ogAIkLFECmqKIXdRNrsgU4VnYI+AW03ywCl2GIJdVVH7/AQSbTZINosI3C+Q - Ha0APSEQVH0Ho2Sz+RBog2BgyF0dgTFBdPYnLvdU1RKM9B1YCERnudWx5L4BUSO5htPP - AYIYY+QcqNIqsZYc9h24LWDU3h9ojBO+NI/A4CwTujHO3mMIJLzGQ8ADo9GZKhQCDwpk - NiaJJXAxRs6BIhBI0ZRZ1ZklBKgguvF14dgN1PKUAQG50oZmqrARkPwCaYpFXAxX1UA+ - BVdLq3S+hg2BGXJ30nfQgyAWI3CpOmTxkYwJLgi5EwT26pBzk6ggujGVY1lNVH9GINhH - mx0yVZwqnqKCwD1nTmiC4BBoBQeqqZWrLCcWznAmwZtnILECaRq2XQTZiSwT9SaqvwIs - wQEC03fQL5tFBGbxEeRw6IBAbXzRIJbUEXhCILMxaIHghO/AQiAvkPVXCWU3xtmnFATj - os08Ao1ZJp5GwPQiZxtyFxEw1hQ5aWRfA86t0sjRXsASRAfKANlMCFAC2ag0bMc3b9QT - OQiiTmAmeMt4kWwE7CC6RwQyGxuGQLxIpmIUIKjKZgYCnGjjgSA6u7FyT9UhaN0XqYyA - JZDd7iPogeBMyJ0gkKhDmBRN5SMoQKBC7lSCNxdPEGWzsu/AM0AI5LJM8IzgSTdJDgFz - iqSX5kUISgneIgKzC2Q2CBgTVH0HhmKkQ4zejkCbJTAgiFOkBIFClomwT9E0w6FoFZQl - OCObeQTaBbILl1XFRum9k0yRdLRZS6V6EYHnskz0Npj1egyBkaQh7IuULr5QOXyEACWQ - zRRBZjVW7pkqBJmQOxsBWyBz4VM3rSbJNVTpOQOCXZIGUzYTBqALxKUU5SC6UqFspXfo - hp9JxgSm78CUzRwEJgJKIFMbdk2MAE+RJIWPZK9pKdgOEJA6FK1ASSCbcFKUmhdYAhZL - 9iF3MVOF3R3sEZAsE4NPoJO+WVd9J4HAp/Wqn3CGjEDwERSD6Ka3AgSWQNCTqeJjCHRB - QCF30AkcAlWBDOFTr7ACDZZgn6SBOEBHcNiqCXXe4OAEXMIBb8zBmegeDp9qH0EY3UE2 - 2oxNgYHAlBFk7Qjspkjad3BM0vjyFS5S73BCWErxegQ8BHnfQQiqQGXOz19gQuBKPrrt - 5HI9n6fzr4XuYL/uwMxU+fgJKPz9iT9dSlkge81YQLBhCIohdySboVDtx08fP36YefdW - JYjuNTMCAYC+aoMw/X7mw8zM++k32FmWjyB7JQL7MUGINguJW3+MPn/1eurt9Lt302+n - Xr+i1GGT6/Yp0p+SO+4ZUyRyoPhMFajROjr2cmJy6s3U5OTEyzE4N+RR722ocYZKONhl - mXipFfDdQSHa3D84/GzsxasJuF6Ojz0bhtqnvocAdwclCE+GRkbHnr8Yfz42OjL0RERg - niwTI7oLqztwab2d13vuPxx4OjwyOjr6bGRocODhgx44T4pRy8TEgTNtiBgQ+LTejms3 - 7/X1PxkcGhr6fXCgv+/erWuAQPQRcC0Tz2eZaGum8qswBKITRNnc2NLW0XXjzoO+/scD - A4/7+x7cudHVAVYAM4LJskyUm6ftpwDBPrwGllDf2Hz+8pXuW3fv9/72W+/9O7e6r14+ - f1qYEajYodepQxYWDEHqO4Bsrjt+6uyljq7umz23b/fc7P5X56VzzT6LgK0Y99YcbjjZ - 2tbeeaXrWlfXlY72ttafj9XV8vECcSwwdQSZ9YnLPXPsDgUlFdUHf2psPtN2sf3y5faL - 5880Nx09VFPB5Rf4IAJ72YzqNu/4fs++H+samk61nDl7trXlVFND/YH95buEM0fJKYvy - taDlgJv2OZ4dhH2RUMHbll9cVllzsL7heNOJE43Hj9YfrKkqK863wYmjpKKNh9KwXceQ - QOCizQjC9qKS8qqaA4fq6uvrDv1YU1VeUrSdRuDFPoIcRgmElLR12bl5O4pLyyv3V9fU - VO+r3FNaXJC3OXtdWkqih3alyL1xI5/bQcjI2mTbVlBcsrtsz56y0l07C7bZNmVlrIaj - d2MiIYLsg1aAYNIQEpNXrc3MzrXl5RcW7dxZWJCfZ8vNzly7CiPwDYHMth+AQBSjNWHF - yrT09dmbNtu25m3dYtu8MXt9elrqigSwAl9GIBFL1vik5NS09MwNWTlwZW3IBALJSfHW - aO4gbp8QyAqWgKbIiKilsYjC6jXp6RkZ6WvTVgOBhNilUT6PQBRLYeGRMcuAworklalw - rUxekRQftywmMty7FtTYn7TaUzwmBMBxJ5aIqJhl1viExCS4EuPjrMtioiIscBi7z0kj - RyQ8hODQMEtEZDRgsMbGWgFAdGSEJSw0eC4gIN0hMCgEKIRHRkZFwxUVGRFuWRIaArIA - DhHzIR/B0Qa4J8gSUKQVKAAGS3h4uMUStiQUbACMAM4gnwMIOEvw8/cPCAwKBgz4CgEA - gQH+cITYIsXjYuS4et9zsARkChhDEL4CMQBsBEon5nhfU+Xf8UJMAWPwDwiAzx8sAAGY - G/2A57IQU1i0ePFiP3TBVwxgjvQDwTh4DKjt+ILvhZ/NpRtoN7nmUrPn2zpPYJ7APIF5 - AvME5gnME/AKAv8Df6F/1QplbmRzdHJlYW0KZW5kb2JqCjcxIDAgb2JqCjY4MjQKZW5k - b2JqCjc0IDAgb2JqCjw8IC9MZW5ndGggNzUgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0 - eXBlIC9JbWFnZSAvV2lkdGggMjYwIC9IZWlnaHQgMjYwIC9Db2xvclNwYWNlCi9EZXZp - Y2VHcmF5IC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4K - 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 - EKnKFEWSXBYnhYn0eL/LxL/f9eb38iBECURipJCQmKRgIikxAQmIRWgMOcZvtNn8yfl7 - 6yoCXyiKlkhj42SyBAiZLC5WKomGdRAKBN93Bx4fFMQSSYw0FkIaI4EcEPL5vBDIApQt - kAkwJTGSF8UXCEUicTSEWCQSCvhRvEgYw47vO878TXV/7scgRDAKfL5AIBQKBHw+IwCl - IDQIUCrsg1SAsS/gwIuC4EEGwCoAAW/Ddv1xJfA+KBUYhggEERkR4QEImSTw/Mr2ehgY - CeQBAX9F4K9zlw8ZnrRHgvlil/9Z+J+HBcICYYGwQFggLBAWCAsEVuA/SCo8XAplbmRz - dHJlYW0KZW5kb2JqCjc1IDAgb2JqCjM3MTEKZW5kb2JqCjYwIDAgb2JqCjw8IC9MZW5n - dGggNjEgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMjY0 - IC9IZWlnaHQgMTU2IC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5IC9CaXRzUGVyQ29tcG9u - ZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7Z3bT1NZFIeFll7o - nZ6209PT0gv0RhEKhHKJRayiYBWJaBslpKaMqabKjAOBMAwMGsTUYUAJQQjDxSAGCAFD - kBAx/muzdlvHIwW8zLwcZv0eCC9Nuj6+tfY5POx14gQGCSABJIAEkMC/IpB17PKNOKD+ - 7E/hHYN8qiYbivsaHGkGPB6fz885ZoGSeDyC5IssUiLwCAGBQCgUpSLmeNJlCIUCARTG - T6M4wgrSDgSCgBAQ50ogUqlUxvlAEaSWXDGUJQQWSRSHtgeRIU0BGEhlcrlCoVQdkygV - CrlcJiUsPpI4bFCkMIALAEEuV6ry1BRFabRaHeej1WqgFHWeSimXAwpCgihxsBFpDCIx - UFCq1JRGp9PTtMHAMEaOh2EMBprW63QaSg0opBKx6HAQKQxEBrlCBRD0NGM0mc0Wq9XG - +VitFrPZZGSAhYZSKeREicOMyCKzATCADGqNjmZMZqut0O5wulxut7uIw4Gv73I5HfZC - m9VsYmidRg1KpEEc0BkwI3MEBIOK0tJMvqXA7nR7ik+WlHq9ZRyP11tacrLY43baCyz5 - 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 - uVyhUKqOSZQKhVwuAwhiQiFlw2crxNLHxcfWIEoQEiLCAiKVSmWcDxRBagEGon8oHNIU - KRxEiWR3AAuBkNAgEXM8qSpEQqEATEiqAKPhUBk+kkih4PH5IMbxCpTEg+lIIHyBwmcs - yCcgvGOQVCXJn1/JIEUi+RM+cczCKg5/RQJIAAkgASTwPQT+Bp5VVMAKZW5kc3RyZWFt - CmVuZG9iago2MSAwIG9iagoyMjk5CmVuZG9iago1MCAwIG9iago8PCAvTGVuZ3RoIDUx - IDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRoIDI2MCAvSGVp - Z2h0IDE4OCAvQ29sb3JTcGFjZQovRGV2aWNlR3JheSAvQml0c1BlckNvbXBvbmVudCA4 - IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae2d+1NS+RvHvaDI7QCKgFyC - DqBcRPYEhooGDAzmLS9pi6WOhjZhGNnExKxZOJZMjJm2Ol6mzJys0dbJxqmm2Zr9177P - wdidFLfm+9tpn/cPjT/QzHlevp/X54O/nJwcDBJAAkgACSCBHyGQ+5PlR2b++zMwe94/ - yWd8/pklD0b7e8zjfziYH+ZmsQp+qrBYMBSN43sY0gQOxi9ks4sOwmF0vg7BZhfCrxRA - fIfCVwIFBYUwPofL5fF4fD5fwPDACDAIl8spKqI5/DsFGkE+bAAAgPH5AoIQikTinyAi - kZAgBECCCxgOKByzEGkE0AGagIAQisXFJRJJaalUKmN0pNLSUomkpFgsFhICmgJ0ARYi - OwS6BXQJaAIimF8qk5cpFEqVSs3oqFRKhaJMLpMCB1GaAlSBhpDlXEgjABHw+EAAAMD0 - ao1We5LUMTzkSa1WowYSgAEo8Hm0FrJDyKVdwOZACcQlUrkC5id1hvIKo8lkNlsYG7PZ - ZDJWlBt0JHBQyKUlYqgCh02b8WgRoAaAoIgnEIolMoVaS+rLTeZKq81GUdQpBgce32az - VppN5XpSq1bIJGKhAJpQwMqyDVAD0CE3jUCpIQ1Gi9VG2atPO2vrIC6Ghn72Wufpajtl - s1qMBlKjTEPgghizFCEXalDE5RNiiVyp0VVYqiiHs9bV4PZ4fT6fn7GBh/d63A2uWqeD - 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 - dGggMjYwIC9IZWlnaHQgMjYwIC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5IC9CaXRzUGVy - Q29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7d3/U1JZ - FADwvijyTURFVJKVomxxILQwU7I0Gr+3Wg4jfTOcMqNGLR1aR8sp1Cmx8kvluOZoTuyg - mWnqqG27s//anvuwTBcUFd6798L5JQ1K+Hjuue894Jw9e8IRFggLhAXCAmGBsEBYICyA - kcBeFPsgmC8wemAsPZTVZw8A+/cjBgj4K5Z+OBY/xvPr378/IiIiEgL+8EiEkAJaAAAA - z57Hi4Lg8RAEwxAiqYCSAAHwovh8vkAgFAoE8EUUOETAsgiJVGAIGAGBUCQSR0OIRSKh - gFEIDQQggCTg8flCkVgiiZHGQkhjJBKxSMjn81AqUJ8JHoIoEIiWSGPjZLIECJksLlYq - iQaFqBBAWCUQQA5I42QJiUkKJpISE2RxUsgFAf0IHgK+QIQE5EmKFGWqCiJVmaJIkiMF - kYBPeSasEghFkth4edIBpeqQ+kgaxBH1IZXyQJI8PlYC64FqhO8EYkmsLFGhVKnTNOla - 3bFjOm26Jk2tUioSZbESMdUIPwhi4hKSU5CAVp95wpCVZTiRqdcihZTkhLgYmhF+IpAr - lAfTNLpMQ3auMQ/CmJttyNRp0g4qFXKaEdYI4uWKX9RHtRmGU8az584XQpw/d9Z4ypCh - Par+RSGPpzYTfiJIVKSqNbrj2cZ8U1FpeQVEeWmRKd+YfVynUacqEmlFWE9wWKM35Jwx - FZdXVpktEOaqyvJi05kcg15zmFqEdQQqRJCbX1hWabZcq7HW1lprrlnMlWWF+bkIQUVn - JmwgSNdnGQuKL1RZrtfeqrfdvWurv1V73VJ1objAmKVPpxNhI0HGydOmkgrzVWudreF+ - c0tL8/0GW531qrmixHT6ZAaVCP8nyDOVVFbX3LQ1Nttb29rb21rtzY22mzXVlSWmPCoR - vBGUXrTcqLv3wN7W8dTR1eV42tFmf3Cv7oblYimVCN4Iyi5dtt5uaGntcHQ/d/b2Op93 - OzpaWxpuWy9fKqMQwRdBfaO9/Um382XfwODgQN9LZ/eTdntjPZUIvgjuNNkfOZ696H89 - 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 - fXF9u097/f1/ZAJM0U5UKJFCulZ37JhOm44ElIpEmEBN0qtJ65+ef999R4BR4vHypANK - 1SH1kTSII+pDKuWBJHk8zF6meCF4kFYRBCKJNE4mT1KkKFNVEKnKFEWSXBYnhYn0eL/L - xL/f9eb38iBECURipJCQmKRgIikxAQmIRWgMOcZvtNn8yfl76yoCXyiKlkhj42SyBAiZ - LC5WKomGdRAKBN93Bx4fFMQSSYw0FkIaI4EcEPL5vBDIApQtkAkwJTGSF8UXCEUicTSE - WCQSCvhRvEgYw47vO878TXV/7scgRDAKfL5AIBQKBHw+IwClIDQIUCrsg1SAsS/gwIuC - 4EEGwCoAAW/Ddv1xJfA+KBUYhggEERkR4QEImSTw/Mr2ehgYCeQBAX9F4K9zlw8ZnrRH - gvlil/9Z+J+HBcICYYGwQFggLBAWCAsEVuA/SCo8XAplbmRzdHJlYW0KZW5kb2JqCjUz - IDAgb2JqCjM3MTEKZW5kb2JqCjU3IDAgb2JqCjw8IC9MZW5ndGggNTggMCBSIC9UeXBl - IC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMjYwIC9IZWlnaHQgMjYwIC9D - b2xvclNwYWNlCi9EZXZpY2VHcmF5IC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAv - RmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7d3/U1JZFADwvijyTURFVJKVomxxILQwU7I0 - Gr+3Wg4jfTOcMqNGLR1aR8sp1Cmx8kvluOZoTuygmWnqqG27s//anvuwTBcUFd6798L5 - JQ1K+Hjuue894Jw9e8IRFggLhAXCAmGBsEBYICyAkcBeFPsgmC8wemAsPZTVZw8A+/cj - Bgj4K5Z+OBY/xvPr378/IiIiEgL+8EiEkAJaAAAAz57Hi4Lg8RAEwxAiqYCSAAHwovh8 - vkAgFAoE8EUUOETAsgiJVGAIGAGBUCQSR0OIRSKhgFEIDQQggCTg8flCkVgiiZHGQkhj - JBKxSMjn81AqUJ8JHoIoEIiWSGPjZLIECJksLlYqiQaFqBBAWCUQQA5I42QJiUkKJpIS - E2RxUsgFAf0IHgK+QIQE5EmKFGWqCiJVmaJIkiMFkYBPeSasEghFkth4edIBpeqQ+kga - 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 - 4BPAJ4BP4J88gf8Cx7sMUAplbmRzdHJlYW0KZW5kb2JqCjczIDAgb2JqCjI1MTQKZW5k - b2JqCjY1IDAgb2JqCjw8IC9MZW5ndGggNjYgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0 - eXBlIC9JbWFnZSAvV2lkdGggMjYwIC9IZWlnaHQgMjYwIC9Db2xvclNwYWNlCi9EZXZp - Y2VHcmF5IC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4K - c3RyZWFtCngB7d3/U1JZFADwvijyTURFVJKVomxxILQwU7I0Gr+3Wg4jfTOcMqNGLR1a - R8sp1Cmx8kvluOZoTuygmWnqqG27s//anvuwTBcUFd6798L5JQ1K+Hjuue894Jw9e8IR - FggLhAXCAmGBsEBYICyAkcBeFPsgmC8wemAsPZTVZw8A+/cjBgj4K5Z+OBY/xvPr378/ - IiIiEgL+8EiEkAJaAAAAz57Hi4Lg8RAEwxAiqYCSAAHwovh8vkAgFAoE8EUUOETAsgiJ - VGAIGAGBUCQSR0OIRSKhgFEIDQQggCTg8flCkVgiiZHGQkhjJBKxSMjn81AqUJ8JHoIo - EIiWSGPjZLIECJksLlYqiQaFqBBAWCUQQA5I42QJiUkKJpISE2RxUsgFAf0IHgK+QIQE - 5EmKFGWqCiJVmaJIkiMFkYBPeSasEghFkth4edIBpeqQ+kgaxBH1IZXyQJI8PlYC64Fq - hO8EYkmsLFGhVKnTNOla3bFjOm26Jk2tUioSZbESMdUIPwhi4hKSU5CAVp95wpCVZTiR - qdcihZTkhLgYmhF+IpArlAfTNLpMQ3auMQ/CmJttyNRp0g4qFXKaEdYI4uWKX9RHtRmG - U8az584XQpw/d9Z4ypChPar+RSGPpzYTfiJIVKSqNbrj2cZ8U1FpeQVEeWmRKd+YfVyn - UacqEmlFWE9wWKM35JwxFZdXVpktEOaqyvJi05kcg15zmFqEdQQqRJCbX1hWabZcq7HW - 1lprrlnMlWWF+bkIQUVnJmwgSNdnGQuKL1RZrtfeqrfdvWurv1V73VJ1objAmKVPpxNh - I0HGydOmkgrzVWudreF+c0tL8/0GW531qrmixHT6ZAaVCP8nyDOVVFbX3LQ1Nttb29rb - 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 - ory0yJRvzD6u06gpJliHIIfJyUe1GYZTxrPnzhdCnD931njKkKE9CtOH5WRdRPc/C9A9 - 1wojTNBWHkzT6DIN2bnGPAhjbrYhU6dJO6hkRnET9DrC9gjWISQkp6jUaRqtPvOEISvL - cCJTr9WkqVUpyQlrI9lxfXF9u097/f1/ZAJM0U5UKJFCulZ37JhOm44ElIpEmEBN0qtJ - 65+ef999R4BR4vHypANK1SH1kTSII+pDKuWBJHk8zF6meCF4kFYRBCKJNE4mT1KkKFNV - EKnKFEWSXBYnhYn0eL/LxL/f9eb38iBECURipJCQmKRgIikxAQmIRWgMOcZvtNn8yfl7 - 6yoCXyiKlkhj42SyBAiZLC5WKomGdRAKBN93Bx4fFMQSSYw0FkIaI4EcEPL5vBDIApQt - kAkwJTGSF8UXCEUicTSEWCQSCvhRvEgYw47vO878TXV/7scgRDAKfL5AIBQKBHw+IwCl - IDQIUCrsg1SAsS/gwIuC4EEGwCoAAW/Ddv1xJfA+KBUYhggEERkR4QEImSTw/Mr2ehgY - CeQBAX9F4K9zlw8ZnrRHgvlil/9Z+J+HBcICYYGwQFggLBAWCAsEVuA/SCo8XAplbmRz - dHJlYW0KZW5kb2JqCjY2IDAgb2JqCjM3MTEKZW5kb2JqCjU1IDAgb2JqCjw8IC9MZW5n - dGggNTYgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMjI0 - IC9IZWlnaHQgMTg4IC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5IC9CaXRzUGVyQ29tcG9u - ZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7Z3tTxPpGodBCqXt - 9A3aaenLtkxb2mkp3bHFUgrbNm14RxSErbtC0KpZWJDV2EgWdTGsEokiuBBeosgS0YBL - wBAlRs351849hbNGGNRNTmbH5v59IGaCmeea3309U/rlycnB4BPAJ4BPAJ/A//cJ5H5F - +UfkwHXkQ/IEnQ/rPALL/gLMXTZgEonyv5qIRLBgFvVziBm6XbQCsbhwNxLBZm+BYnEB - VAGQnyHco8vPLwA0iVQqk8kIgpALOLA8WKRUKiksZBk/Tcji5cFUAhygEXKFQqlSqQUe - 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 - tNhpnz9YE43XN7W2tXd0diUFm67Ojva21qb6eLQm6PfRdotRB8fbS9nj3z863jAnJxcO - gC9gT7gHQKud9jKBqnAklqhraGxuaT0u0LS2NDc21CVikXBVgPHSdivgsafbFxzkA0AR - FEgAoN5osTk9FUwgGArXRqKxeDyeEGRgYbFopDYcCgaYCo/TZjHqAY+A+kT76/tfgVK5 - km3QQjlcHq+P8VceC4aqIWEBhl1XKHis0s/4vB6Xg2KHU62E6eSqD/qDAsWFsgygwWyl - 7GW0u9zr8zEMc1SggaX5fN5yN11mp6xmQwZPViiG+g72xxoIgBKZXKEuJvUGs8VK2Rxl - ThdNu90eQcbtpmmXs8xho6wWs0FPFqsVcpkE8A7sLuz3hFAgbDHQIKFQFWlIncFoAkZr - KWUTcKhSK7CZjAYdqSlSKQhoj51Ojvr2AGFEpVChqqgYEPUlBqA0mQUbE5AZSvQAVwx0 - cpkUhvMwvJzcTIPwlsgQKtVqYNRotSSpE2xIUqvVAJtarczQwdaSwdv38tv7GjsDKMqH - CoFQRsgVCqVKpRZ4VCqlQiEnZNAdWx64dySXGw8mFBpkdxlWw0KJFCBlBEHIBRxYHixS - KpUAHHTH0h2Ox24yu4SACIwAmYlEsNlboJhlyxd9li6zjbKER/Ly8kQs5FcSQMtjq/tk - d3sWsiVmGNnfh8D/FHB215j5Ccv+G+FL/gG//9XkS3jwd/AJ4BPAJ4BP4J88gf8Cx7sM - UAplbmRzdHJlYW0KZW5kb2JqCjU2IDAgb2JqCjI1MTQKZW5kb2JqCjQxIDAgb2JqCjw8 - IC9MZW5ndGggNDIgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lk - dGggMjYwIC9IZWlnaHQgMjYwIC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5IC9CaXRzUGVy - Q29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7d3/U1JZ - FADwvijyTURFVJKVomxxILQwU7I0Gr+3Wg4jfTOcMqNGLR1aR8sp1Cmx8kvluOZoTuyg - mWnqqG27s//anvuwTBcUFd6798L5JQ1K+Hjuue894Jw9e8IRFggLhAXCAmGBsEBYICyA - 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 - WCQSCvhRvEgYw47vO878TXV/7scgRDAKfL5AIBQKBHw+IwClIDQIUCrsg1SAsS/gwIuC - 4EEGwCoAAW/Ddv1xJfA+KBUYhggEERkR4QEImSTw/Mr2ehgYCeQBAX9F4K9zlw8ZnrRH - gvlil/9Z+J+HBcICYYGwQFggLBAWCAsEVuA/SCo8XAplbmRzdHJlYW0KZW5kb2JqCjQy - IDAgb2JqCjM3MTEKZW5kb2JqCjQ3IDAgb2JqCjw8IC9MZW5ndGggNDggMCBSIC9UeXBl - IC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMzAwIC9IZWlnaHQgMjI4IC9D - b2xvclNwYWNlCi9EZXZpY2VHcmF5IC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAv - RmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7dn9T5P31wdwpKUPUPpAn0YppQ9YSi1CgVAe - YhE7UbAOiWgbJaSmzlRTZXMQCGMwNIipY+AIQQgDMYgBQtAQJETI/rX7XKBzB8rZ/b3v - 70/tOT9sO3tHk88r53yuq21GBhcLsAALsAALsEASgVNpWUkgqP8FRplfS5Qm9fXEmQBA - +XzJPjuJRGKxOCsNC44tEgls/+p1OFAiQUkikUplhyVPg/p8VKlUIoHDiz9zfZmgJP8W - Vk+AkghK8uwcKIVCkZsWBQcVzpsth6NLweuA68RVFIbqsxQ4KXKVSpVKrUmjUqtUSmWu - QvD6onXSxXVIBTMFUEqlWpOn1el0eoPBmBZlMOjhuNo8jVqpBC5BSxit5JP1mUomBym1 - RqvTG435JlNBgdlcmAZlNhcUmEz5RqNepwUuRY5cdjLWIZUwVEqVBqDyTeZCi9Vqs9sd - aVF2u81qtRSawUuv06iUwmidNFmnhLsKqGCotHqjyWyx2h2nnSWu0lK3230mxQuOWFrq - KnGedtitFrPJqNfCaH3GSrKFcK9nSQQqjc5gMhfZip0ut6fsbHmF11uZBuX1VpSfLfO4 - Xc5iW5HZZNBpBCxJFlxZx14YYKy+UBlNhbbiEren3FtVXeOrrasXqiGF6+CAdbW+muoq - b7nHXVJsKzQZv2IdG6xTmbCB8hyYKqPJ4nC6y7xVNbX15/znmy4EAt+mfAUCF5rO+8/V - 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 - FeIgG7YieVDIVoiDbNiK5EEhWyEOsmErkgeFbIU4yIatSB4UshXiIBu2InlQyFaIg2zY - iuRBIVshDrJhK5IHhf+ZlUyhMZgdbm994Go4+qh/JPHy1eLbtc2tj7t7e/vo703BZn9v - b/fj1uba28VXLxMj/Y+i4auBeq/bYTZoFLIs0amMf1Zm1slWn9LB6hNhlflPqYyMf7Ha - T+nJ2t/f3/tvWsHfl8r1f7UKhqIP+4afT8wsLK9ufNje2f20l/L1aXdn+8PG6vLCzMTz - 4b6H0VDwH/dV0h0ssJd66y4Eb96J9w6N/T49/+bd+uYWYKVB7Wxvba6/ezM//fvYUG/8 - zs3ghTpvqb3g4G5PYqXWg1VFbVPrjciDnwZHf5uaW4TBer+1/XEn5evj9tZ7GKvFuanf - Rgd/ehC50dpUWwFWejU8B49b5aj1Jpur3He+5XpX7PHAk8TkzJ9LK2sbmx+20qA+bG6s - rSz9OTOZeDLwONZ1veW8r9xlM+nVOUmtVDqTteRsjf9Se+e97r7hsfGp2YU3K6vrG5vv - U742N9ZXV94szE6Njw33dd/rbL/krzlbYjXpVCdZ5Rc5PdXnmttuReM9g08TE9NzC0vL - 71bX1lO+1lbfLS8tzE1PJJ4O9sSjt9qaz1V7nEX5Sa3Eshyl9hvL6TNV9YFgKBL7oX9o - 9MXk9Oz866XltyspX2+Xl17Pz05Pvhgd6v8hFhEeg1VnTlu+0SpzZOKj95VYmq3MMxY6 - Sr21cGF13o33DIw8ezExNTM3v7D4OuVrcWF+bmZq4sWzkYGe+N1OuK5qvaWOQmOeMlua - zCoXPhDaXeU1/uZr4Uisu/fnkWeJ8cmp6ZlXsylfr2ampybHE89Gfu7tjkXC15r9NeUu - O3wczE1iJZLIczV6k9XpEZaw43b0PmANPx1LjE9Mvvwj5evl5MR4YuzpMFDdj97uEFbQ - 47Sa9JpcuUR0dAdFElmOWpdvgW8afI2X20JdgNXTPzj8ZHTseSIN6vnY6JPhwf4eoOoK - tV1u9MG3DJZ8HbwyJLHKgss9z2i2lZRVNwRa28Nd0Vj8x97+gV+Gfh1Jg/p16JeB/t4f - 47FoV7i9NdBQXVZiM8N1Ba8MR+fqVGYWXO6whEXF7gqf/+KV9tDtyPf3492Pe3r7+tOg - +np7HnfH738fuR1qv3LR76twFxfBCsLVnpWJv77KACuJXKHSwWA5PZV1jRdb2zrCnZHo - vdiD+MNH3Slfjx7GH8TuRSOd4Y621ouNdZUeJ4yVTqWQS5JYiYUl1OjzCx2usqo6f+By - 8FpH6FZnV+RONHo35SsavRPp6rwV6rgWvBzw11WVuRyF+TBWsILi43MlypLCYGkNJgtg - VfoaGgPNLcG29us3bobCaVChmzeut7cFW5oDjQ2+SqCymAxaGCspXFdHdjAjM1MMT8Jc - tc5oKnK4PBXVvgZ/U6D5UsuVYPDqdylfV4PBKy2XmgNN/gZfdYXH5SgyGXXqXHgKijOP - vDJkwIUlhsGCLQQsi8PpLvNW1dTWn/Ofb7oQCHyb8hUIXGg67z9XX1tT5S1zO2GqjDrY - QBirYysoWImyJLJsxQFWoa24xO0p91ZV1/hq6+qFakjhOjhgXa2vprrKW+5xlxTbCg+o - FNkySZIVhF8nvmIZTOYiW7HT5faUnS2v8Hor06C83orys2Uet8tZbCsymwwwVZ+pjq3g - wWDBFgqTpdbqjSazxWp3nHaWuEpL3W73mRQvOGJpqavEedpht1rMJqNeqxaoYAOP3+zw - A9gpGKwDrBylSqPTG/NN5kKL1Wqz2x1pUXa7zWq1FJpN+Ua9TqNS5nymOvYUFH4sPMSS - yOQ5MFoaLXCBl6mgwGwuTIMymwsKTOAEUFoNDFWOHO4qmKqkVH9jwR6CFnDlaXU6nd5g - MKZFGQx6OK42D6BACoaKoso4dThZWRKpTA5cuUqlSqXWpFGpVSqlMheg5ILU4VQdfQ/9 - ++d6wBIuLUFLJnhBKRSK3LQoOKhwXnCS/S11wgIeegmjdciVJZFIBTGh5GlQhyeVSaUS - mKiDkYKr6sSh+qJ1yCUSi2HA0q/g2CK40QWof5FCXsKfgBKlSR2e9uCf/0unv+8ueC6m - Zf0DgP+TBViABViABVjgq8D/AOqBT24KZW5kc3RyZWFtCmVuZG9iago0OCAwIG9iagoz - ODc3CmVuZG9iago3NiAwIG9iago8PCAvTGVuZ3RoIDc3IDAgUiAvTiAzIC9BbHRlcm5h - dGUgL0RldmljZVJHQiAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAGtk89r - 02Acxp+0Q4fOCXPzIAg5OPBQpbQFfyDYtetGN+lK263VW5ukTbVJQ5JWWzz0HxC8CepB - 8bLD9Kx4UQTx4kEmongV8eJlhzEYIz5JTOvB4cVvefN++uR5v++b7/u+QHinahitEABN - t83CYkqsXL0mHvyCCRziL4GZqmQZc/n8FVr2ie1PENxXm2fcXPeNXZy7u5nYftT7funp - xcP7DArkSZMTAkKEwnTD56TLNZ9LLt+0DZse1WVJrcrk2+SIWSqkyevkyYbPz12u+fzO - 5a7UcMd+Jkd1uakDoXHyeVmxJHKSrMqWpJGZRwhpWpv5wxvUT0uGybHhj+RTbl3YM3pH - gcv36H890ipvgY1nwPGfI22W3mNfgRfdkba149VKOPnNqsdjXjrhyGPgQN9xtmaAcc69 - t+Y4uynH2ePcY0zy8o7UMbuelwsU3gP/+u9/s58d+MA8DG+P/s5+XTxXFHgyANZeAUsU - HrLN8lunHgArSaA4QCgeD5pfQ1pY56KkGLapiJVYorzoSf/vobU63Csvpvic0Gu5FfYn - 2H4Ydr4UsNUtZgKuNxeyAcvV+eWA+2o6F3DdXCgEfL26lA9Y0VeLARst7+z/nis19CtW - Zujpq6Vy4Dc7hdWAb7SXh35ZmR+uTW/l3Pvk5Wza2eH6UYQEBQZsmOxFVBDjHSyDBfXP - JUchN83jOEbIvFnXBq7yZ9jKLW+/022jZzYbqi3O8VYqETGrS2cjYiwavYBfakqyNwpl - bmRzdHJlYW0KZW5kb2JqCjc3IDAgb2JqCjU2NQplbmRvYmoKNDMgMCBvYmoKWyAvSUND - QmFzZWQgNzYgMCBSIF0KZW5kb2JqCjc4IDAgb2JqCjw8IC9MZW5ndGggNzkgMCBSIC9O - IDMgL0FsdGVybmF0ZSAvRGV2aWNlUkdCIC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0 - cmVhbQp4Aa2Tz2vTYBzGn7RDh84Jc/MgCDk48FCltAV/INi160Y36UrbrdVbm6RNtUlD - klZbPPQfELwJ6kHxssP0rHhRBPHiQSaieBXx4mWHMRgjPklM68HhxW9583765Hm/75vv - +75AeKdqGK0QAE23zcJiSqxcvSYe/IIJHOIvgZmqZBlz+fwVWvaJ7U8Q3FebZ9xc941d - nLu7mdh+1Pt+6enFw/sMCuRJkxMCQoTCdMPnpMs1n0su37QNmx7VZUmtyuTb5IhZKqTJ - 6+TJhs/PXa75/M7lrtRwx34mR3W5qQOhcfJ5WbEkcpKsypakkZlHCGlam/nDG9RPS4bJ - seGP5FNuXdgzekeBy/fofz3SKm+BjWfA8Z8jbZbeY1+BF92RtrXj1Uo4+c2qx2NeOuHI - Y+BA33G2ZoBxzr235ji7KcfZ49xjTPLyjtQxu56XCxTeA//673+znx34wDwMb4/+zn5d - PFcUeDIA1l4BSxQess3yW6ceACtJoDhAKB4Pml9DWljnoqQYtqmIlViivOhJ/++htTrc - Ky+m+JzQa7kV9ifYfhh2vhSw1S1mAq43F7IBy9X55YD7ajoXcN1cKAR8vbqUD1jRV4sB - Gy3v7P+eKzX0K1Zm6OmrpXLgNzuF1YBvtJeHflmZH65Nb+Xc++TlbNrZ4fpRhAQFBmyY - 7EVUEOMdLIMF9c8lRyE3zeM4Rsi8WdcGrvJn2Motb7/TbaNnNhuqLc7xVioRMatLZyNi - LBq9gF9qSrI3CmVuZHN0cmVhbQplbmRvYmoKNzkgMCBvYmoKNTY1CmVuZG9iago1OSAw - IG9iagpbIC9JQ0NCYXNlZCA3OCAwIFIgXQplbmRvYmoKODAgMCBvYmoKPDwgL0xlbmd0 - aCA4MSAwIFIgL04gMyAvQWx0ZXJuYXRlIC9EZXZpY2VSR0IgL0ZpbHRlciAvRmxhdGVE - ZWNvZGUgPj4Kc3RyZWFtCngBrZPPa9NgHMaftEOHzglz8yAIOTjwUKW0BX8g2LXrRjfp - Stut1VubpE21SUOSVls89B8QvAnqQfGyw/SseFEE8eJBJqJ4FfHiZYcxGCM+SUzrweHF - b3nzfvrkeb/vm+/7vkB4p2oYrRAATbfNwmJKrFy9Jh78ggkc4i+BmapkGXP5/BVa9ont - TxDcV5tn3Fz3jV2cu7uZ2H7U+37p6cXD+wwK5EmTEwJChMJ0w+ekyzWfSy7ftA2bHtVl - Sa3K5NvkiFkqpMnr5MmGz89drvn8zuWu1HDHfiZHdbmpA6Fx8nlZsSRykqzKlqSRmUcI - aVqb+cMb1E9Lhsmx4Y/kU25d2DN6R4HL9+h/PdIqb4GNZ8DxnyNtlt5jX4EX3ZG2tePV - Sjj5zarHY1464chj4EDfcbZmgHHOvbfmOLspx9nj3GNM8vKO1DG7npcLFN4D//rvf7Of - HfjAPAxvj/7Ofl08VxR4MgDWXgFLFB6yzfJbpx4AK0mgOEAoHg+aX0NaWOeipBi2qYiV - WKK86En/76G1OtwrL6b4nNBruRX2J9h+GHa+FLDVLWYCrjcXsgHL1fnlgPtqOhdw3Vwo - BHy9upQPWNFXiwEbLe/s/54rNfQrVmbo6aulcuA3O4XVgG+0l4d+WZkfrk1v5dz75OVs - 2tnh+lGEBAUGbJjsRVQQ4x0sgwX1zyVHITfN4zhGyLxZ1wau8mfYyi1vv9Nto2c2G6ot - zvFWKhExq0tnI2IsGr2AX2pKsjcKZW5kc3RyZWFtCmVuZG9iago4MSAwIG9iago1NjUK - ZW5kb2JqCjU0IDAgb2JqClsgL0lDQ0Jhc2VkIDgwIDAgUiBdCmVuZG9iago4MiAwIG9i - ago8PCAvTGVuZ3RoIDgzIDAgUiAvTiAzIC9BbHRlcm5hdGUgL0RldmljZVJHQiAvRmls - dGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAGtk89r02Acxp+0Q4fOCXPzIAg5OPBQ - pbQFfyDYtetGN+lK263VW5ukTbVJQ5JWWzz0HxC8CepB8bLD9Kx4UQTx4kEmongV8eJl - hzEYIz5JTOvB4cVvefN++uR5v++b7/u+QHinahitEABNt83CYkqsXL0mHvyCCRziL4GZ - qmQZc/n8FVr2ie1PENxXm2fcXPeNXZy7u5nYftT7funpxcP7DArkSZMTAkKEwnTD56TL - NZ9LLt+0DZse1WVJrcrk2+SIWSqkyevkyYbPz12u+fzO5a7UcMd+Jkd1uakDoXHyeVmx - JHKSrMqWpJGZRwhpWpv5wxvUT0uGybHhj+RTbl3YM3pHgcv36H890ipvgY1nwPGfI22W - 3mNfgRfdkba149VKOPnNqsdjXjrhyGPgQN9xtmaAcc69t+Y4uynH2ePcY0zy8o7UMbue - lwsU3gP/+u9/s58d+MA8DG+P/s5+XTxXFHgyANZeAUsUHrLN8lunHgArSaA4QCgeD5pf - Q1pY56KkGLapiJVYorzoSf/vobU63Csvpvic0Gu5FfYn2H4Ydr4UsNUtZgKuNxeyAcvV - +eWA+2o6F3DdXCgEfL26lA9Y0VeLARst7+z/nis19CtWZujpq6Vy4Dc7hdWAb7SXh35Z - mR+uTW/l3Pvk5Wza2eH6UYQEBQZsmOxFVBDjHSyDBfXPJUchN83jOEbIvFnXBq7yZ9jK - LW+/022jZzYbqi3O8VYqETGrS2cjYiwavYBfakqyNwplbmRzdHJlYW0KZW5kb2JqCjgz - IDAgb2JqCjU2NQplbmRvYmoKNjIgMCBvYmoKWyAvSUNDQmFzZWQgODIgMCBSIF0KZW5k - b2JqCjg0IDAgb2JqCjw8IC9MZW5ndGggODUgMCBSIC9OIDMgL0FsdGVybmF0ZSAvRGV2 - aWNlUkdCIC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Aa2Tz2vTYBzGn7RD - h84Jc/MgCDk48FCltAV/INi160Y36UrbrdVbm6RNtUlDklZbPPQfELwJ6kHxssP0rHhR - BPHiQSaieBXx4mWHMRgjPklM68HhxW9583765Hm/75vv+75AeKdqGK0QAE23zcJiSqxc - vSYe/IIJHOIvgZmqZBlz+fwVWvaJ7U8Q3FebZ9xc941dnLu7mdh+1Pt+6enFw/sMCuRJ - kxMCQoTCdMPnpMs1n0su37QNmx7VZUmtyuTb5IhZKqTJ6+TJhs/PXa75/M7lrtRwx34m - R3W5qQOhcfJ5WbEkcpKsypakkZlHCGlam/nDG9RPS4bJseGP5FNuXdgzekeBy/fofz3S - Km+BjWfA8Z8jbZbeY1+BF92RtrXj1Uo4+c2qx2NeOuHIY+BA33G2ZoBxzr235ji7KcfZ - 49xjTPLyjtQxu56XCxTeA//673+znx34wDwMb4/+zn5dPFcUeDIA1l4BSxQess3yW6ce - ACtJoDhAKB4Pml9DWljnoqQYtqmIlViivOhJ/++htTrcKy+m+JzQa7kV9ifYfhh2vhSw - 1S1mAq43F7IBy9X55YD7ajoXcN1cKAR8vbqUD1jRV4sBGy3v7P+eKzX0K1Zm6OmrpXLg - NzuF1YBvtJeHflmZH65Nb+Xc++TlbNrZ4fpRhAQFBmyY7EVUEOMdLIMF9c8lRyE3zeM4 - Rsi8WdcGrvJn2Motb7/TbaNnNhuqLc7xVioRMatLZyNiLBq9gF9qSrI3CmVuZHN0cmVh - bQplbmRvYmoKODUgMCBvYmoKNTY1CmVuZG9iago0NiAwIG9iagpbIC9JQ0NCYXNlZCA4 - NCAwIFIgXQplbmRvYmoKODYgMCBvYmoKPDwgL0xlbmd0aCA4NyAwIFIgL04gMyAvQWx0 - ZXJuYXRlIC9EZXZpY2VSR0IgL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB - rZPPa9NgHMaftEOHzglz8yAIOTjwUKW0BX8g2LXrRjfpStut1VubpE21SUOSVls89B8Q - vAnqQfGyw/SseFEE8eJBJqJ4FfHiZYcxGCM+SUzrweHFb3nzfvrkeb/vm+/7vkB4p2oY - rRAATbfNwmJKrFy9Jh78ggkc4i+BmapkGXP5/BVa9ontTxDcV5tn3Fz3jV2cu7uZ2H7U - +37p6cXD+wwK5EmTEwJChMJ0w+ekyzWfSy7ftA2bHtVlSa3K5NvkiFkqpMnr5MmGz89d - rvn8zuWu1HDHfiZHdbmpA6Fx8nlZsSRykqzKlqSRmUcIaVqb+cMb1E9Lhsmx4Y/kU25d - 2DN6R4HL9+h/PdIqb4GNZ8DxnyNtlt5jX4EX3ZG2tePVSjj5zarHY1464chj4EDfcbZm - gHHOvbfmOLspx9nj3GNM8vKO1DG7npcLFN4D//rvf7OfHfjAPAxvj/7Ofl08VxR4MgDW - XgFLFB6yzfJbpx4AK0mgOEAoHg+aX0NaWOeipBi2qYiVWKK86En/76G1OtwrL6b4nNBr - uRX2J9h+GHa+FLDVLWYCrjcXsgHL1fnlgPtqOhdw3VwoBHy9upQPWNFXiwEbLe/s/54r - NfQrVmbo6aulcuA3O4XVgG+0l4d+WZkfrk1v5dz75OVs2tnh+lGEBAUGbJjsRVQQ4x0s - gwX1zyVHITfN4zhGyLxZ1wau8mfYyi1vv9Nto2c2G6otzvFWKhExq0tnI2IsGr2AX2pK - sjcKZW5kc3RyZWFtCmVuZG9iago4NyAwIG9iago1NjUKZW5kb2JqCjQ5IDAgb2JqClsg - L0lDQ0Jhc2VkIDg2IDAgUiBdCmVuZG9iago4OCAwIG9iago8PCAvTGVuZ3RoIDg5IDAg - UiAvTiAzIC9BbHRlcm5hdGUgL0RldmljZVJHQiAvRmlsdGVyIC9GbGF0ZURlY29kZSA+ - PgpzdHJlYW0KeAGFlE1IFGEYx/+zjQSxBtGXCMXQwSRUJgtSAtP1K1O2ZdVMCWKdfXed - HGenmd0tRSKE6Jh1jC5WRIeITuGhQ6c6RASZdYmgo0UQBV4itv87k7tjVL4wM795nv/7 - fL3DAFWPUo5jRTRgys67yd6Ydnp0TNv8GlWoRhRcKcNzOhKJAZ+plc/1a/UtFGlZapSx - 1vs2fKt2mRBQNCp3ZAM+LHk84OOSL+SdPDVnJBsTqTTZITe4Q8lO8i3y1myIx0OcFp4B - VLVTkzMcl3EiO8gtRSMrYz4g63batMnvpT3tGVPUsN/INzkL2rjy/UDbHmDTi4ptzAMe - 3AN211Vs9TXAzhFg8VDF9j3pz0fZ9crLHGr2wynRGGv6UCp9rwM23wB+Xi+VftwulX7e - YQ7W8dQyCm7R17Iw5SUQ1BvsZvzkGv2Lg558VQuwwDmObAH6rwA3PwL7HwLbHwOJamCo - FZHLbDe48uIi5wJ05pxp18xO5LVmXT+idfBohdZnG00NWsqyNN/laa7whFsU6SZMWQXO - 2V/beI8Ke3iQT/YXuSS87t+szKVTXZwlmtjWp7To6iY3kO9nzJ4+cj2v9xm3Zzhg5YCZ - 7xsKOHLKtuI8F6mJ1Njj8ZNkxldUJx+T85A85xUHZUzffi51IkGupT05meuXml3c2z4z - McQzkqxYMxOd8d/8xi0kZd591Nx1LP+bZ22RZxiFBQETNu82NCTRixga4cBFDhl6TCpM - WqVf0GrCw+RflRYS5V0WFb1Y4Z4Vf895FLhbxj+FWBxzDeUImv5O/6Iv6wv6Xf3zfG2h - vuKZc8+axqtrXxlXZpbVyLhBjTK+rCmIb7DaDnotZGmd4hX05JX1jeHqMvZ8bdmjyRzi - anw11KUIZWrEOOPJrmX3RbLFN+HnW8v2r+lR+3z2SU0l17K6eGYp+nw2XA1r/7OrYNKy - q/DkjZAuPGuh7lUPqn1qi9oKTT2mtqttahffjqoD5R3DnJWJC6zbZfUp9mBjmt7KSVdm - i+Dfwi+G/6VeYQvXNDT5D024uYxpCd8R3DZwh5T/w1+zAw3eCmVuZHN0cmVhbQplbmRv - YmoKODkgMCBvYmoKNzkyCmVuZG9iago4IDAgb2JqClsgL0lDQ0Jhc2VkIDg4IDAgUiBd - CmVuZG9iago5MCAwIG9iago8PCAvTGVuZ3RoIDkxIDAgUiAvTiAzIC9BbHRlcm5hdGUg - L0RldmljZVJHQiAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAGtk89r02Ac - xp+0Q4fOCXPzIAg5OPBQpbQFfyDYtetGN+lK263VW5ukTbVJQ5JWWzz0HxC8CepB8bLD - 9Kx4UQTx4kEmongV8eJlhzEYIz5JTOvB4cVvefN++uR5v++b7/u+QHinahitEABNt83C - YkqsXL0mHvyCCRziL4GZqmQZc/n8FVr2ie1PENxXm2fcXPeNXZy7u5nYftT7funpxcP7 - DArkSZMTAkKEwnTD56TLNZ9LLt+0DZse1WVJrcrk2+SIWSqkyevkyYbPz12u+fzO5a7U - cMd+Jkd1uakDoXHyeVmxJHKSrMqWpJGZRwhpWpv5wxvUT0uGybHhj+RTbl3YM3pHgcv3 - 6H890ipvgY1nwPGfI22W3mNfgRfdkba149VKOPnNqsdjXjrhyGPgQN9xtmaAcc69t+Y4 - uynH2ePcY0zy8o7UMbuelwsU3gP/+u9/s58d+MA8DG+P/s5+XTxXFHgyANZeAUsUHrLN - 8lunHgArSaA4QCgeD5pfQ1pY56KkGLapiJVYorzoSf/vobU63Csvpvic0Gu5FfYn2H4Y - dr4UsNUtZgKuNxeyAcvV+eWA+2o6F3DdXCgEfL26lA9Y0VeLARst7+z/nis19CtWZujp - q6Vy4Dc7hdWAb7SXh35ZmR+uTW/l3Pvk5Wza2eH6UYQEBQZsmOxFVBDjHSyDBfXPJUch - N83jOEbIvFnXBq7yZ9jKLW+/022jZzYbqi3O8VYqETGrS2cjYiwavYBfakqyNwplbmRz - dHJlYW0KZW5kb2JqCjkxIDAgb2JqCjU2NQplbmRvYmoKNjkgMCBvYmoKWyAvSUNDQmFz - ZWQgOTAgMCBSIF0KZW5kb2JqCjkyIDAgb2JqCjw8IC9MZW5ndGggOTMgMCBSIC9OIDMg - L0FsdGVybmF0ZSAvRGV2aWNlUkdCIC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVh - bQp4Aa2Tz2vTYBzGn7RDh84Jc/MgCDk48FCltAV/INi160Y36UrbrdVbm6RNtUlDklZb - PPQfELwJ6kHxssP0rHhRBPHiQSaieBXx4mWHMRgjPklM68HhxW9583765Hm/75vv+75A - eKdqGK0QAE23zcJiSqxcvSYe/IIJHOIvgZmqZBlz+fwVWvaJ7U8Q3FebZ9xc941dnLu7 - mdh+1Pt+6enFw/sMCuRJkxMCQoTCdMPnpMs1n0su37QNmx7VZUmtyuTb5IhZKqTJ6+TJ - hs/PXa75/M7lrtRwx34mR3W5qQOhcfJ5WbEkcpKsypakkZlHCGlam/nDG9RPS4bJseGP - 5FNuXdgzekeBy/fofz3SKm+BjWfA8Z8jbZbeY1+BF92RtrXj1Uo4+c2qx2NeOuHIY+BA - 33G2ZoBxzr235ji7KcfZ49xjTPLyjtQxu56XCxTeA//673+znx34wDwMb4/+zn5dPFcU - eDIA1l4BSxQess3yW6ceACtJoDhAKB4Pml9DWljnoqQYtqmIlViivOhJ/++htTrcKy+m - +JzQa7kV9ifYfhh2vhSw1S1mAq43F7IBy9X55YD7ajoXcN1cKAR8vbqUD1jRV4sBGy3v - 7P+eKzX0K1Zm6OmrpXLgNzuF1YBvtJeHflmZH65Nb+Xc++TlbNrZ4fpRhAQFBmyY7EVU - EOMdLIMF9c8lRyE3zeM4Rsi8WdcGrvJn2Motb7/TbaNnNhuqLc7xVioRMatLZyNiLBq9 - gF9qSrI3CmVuZHN0cmVhbQplbmRvYmoKOTMgMCBvYmoKNTY1CmVuZG9iago0MCAwIG9i - agpbIC9JQ0NCYXNlZCA5MiAwIFIgXQplbmRvYmoKOTQgMCBvYmoKPDwgL0xlbmd0aCA5 - NSAwIFIgL04gMSAvQWx0ZXJuYXRlIC9EZXZpY2VHcmF5IC9GaWx0ZXIgL0ZsYXRlRGVj - b2RlID4+CnN0cmVhbQp4AYVST0gUURz+zTYShIhBhXiIdwoJlSmsrKDadnVZlW1bldKi - GGffuqOzM9Ob2TXFkwRdojx1D6JjdOzQoZuXosCsS9cgqSAIPHXo+83s6iiEb3k73/v9 - /X7fe0RtnabvOylBVHNDlSulp25OTYuDHylFHdROWKYV+OlicYyx67mSv7vX1mfS2LLe - x7V2+/Y9tZVlYCHqLba3EPohkWYAH5mfKGWAs8Adlq/YPgE8WA6sGvAjogMPmrkw09Gc - dKWyLZFT5qIoKq9iO0mu+/m5xr6LtYmD/lyPZtaOvbPqqtFM1LT3RKG8D65EGc9fVPZs - NRSnDeOcSEMaKfKu1d8rTMcRkSsQSgZSNWS5n2pOnXXgdRi7XbqT4/j2EKU+yWCoibXp - spkdhX0AdirL7BDwBejxsmIP54F7Yf9bUcOTwCdhP2SHedatH/YXrlPge4Q9NeDOFK7F - 8dqKH14tAUP3VCNojHNNxNPXOXOkiO8x1BmY90Y5pgsxd5aqEzeAO2EfWapmCrFd+67q - Je57AnfT4zvRmzkLXKAcSXKxFdkU0DwJWBR9i7BJDjw+zh5V4HeomMAcuYnczSj3HtUR - G2ejUoFWeo1Xxk/jufHF+GVsGM+Afqx213t8/+njFXXXtj48+Y163DmuvZ0bVWFWcWUL - 3f/HMoSP2Sc5psHToVlYa9h25A+azEywDCjEfwU+l/qSE1Xc1e7tuEUSzFA+LGwluktU - binU6j2DSqwcK9gAdnCSxCxaHLhTa7o5eHfYInpt+U1XsuuG/vr2evva8h5tyqgpKBPN - s0RmlLFbo+TdeNv9ZpERnzg6vue9ilrJ/klFED+FOVoq8hRV9FZQ1sRvZw5+G7Z+XD+l - 5/VB/TwJPa2f0a/ooxG+DHRJz8JzUR+jSfCwaSHiEqCKgzPUTlRjjQPiKfHytFtkkf0P - QBn9ZgplbmRzdHJlYW0KZW5kb2JqCjk1IDAgb2JqCjcwNAplbmRvYmoKMzcgMCBvYmoK - WyAvSUNDQmFzZWQgOTQgMCBSIF0KZW5kb2JqCjQgMCBvYmoKPDwgL1R5cGUgL1BhZ2Vz - IC9NZWRpYUJveCBbMCAwIDYxMiA3OTJdIC9Db3VudCAxIC9LaWRzIFsgMyAwIFIgXSA+ - PgplbmRvYmoKOTYgMCBvYmoKPDwgL1R5cGUgL0NhdGFsb2cgL091dGxpbmVzIDIgMCBS - IC9QYWdlcyA0IDAgUiAvVmVyc2lvbiAvMS40ID4+CmVuZG9iagoyIDAgb2JqCjw8IC9M - YXN0IDk3IDAgUiAvRmlyc3QgOTggMCBSID4+CmVuZG9iago5OCAwIG9iago8PCAvQ291 - bnQgMCAvRGVzdCBbIDMgMCBSIC9YWVogMCA3MzMgMCBdIC9UaXRsZSAoQ2FudmFzIDEp - ID4+CmVuZG9iago5NyAwIG9iago8PCAvQ291bnQgMCAvRGVzdCBbIDMgMCBSIC9YWVog - MCA3MzMgMCBdIC9UaXRsZSAoQ2FudmFzIDEpID4+CmVuZG9iago5OSAwIG9iago8PCAv - TGVuZ3RoIDEwMCAwIFIgL0xlbmd0aDEgMTU3MDQgL0ZpbHRlciAvRmxhdGVEZWNvZGUg - Pj4Kc3RyZWFtCngBvXt5YFXFufjMnPWeu+/7lpu7Zd8XEsglJIRdFoUEiYZ9UWQRA1jg - RWWNiAqyCIjgwhLUhBAlSLHUgoi1CiqoqLVWoHRJbfvQ10Luzfvm3IDQ9vXnH/31njtz - 5szMmeX7vvm2mYMwQkiFmhCDYpNnT5zbv+Tu+yDnXYSwYXLjAt9jv+23A9K/Qoi5d9rc - 6bP1v/rZOwhxwxCSVNPvXTxtd48V6mprEQq/PWPqxCn/fem+nQgV+6CNohmQIaUIULcY - ylHqjNkLFn3xoWkePC+B59P3zpk88cpff/cGQiVQB82aPXHRXHGL9Dd47oRn330TZ0+t - b1y8GJ4/geeUuXPuX8C1chfguRuem+fOnzr3x4/cl4tQ6WoY3/uQh+GiPxUkeTn1L6Nk - 5WQVghiWg3cEJCokhJTQhhppkFanNyBkRMhktiArstkdTtf3bbqRx+vzpwRSUTAUjkTT - UHpGZhbKzsnN+77O/7dU/g9omTuGdNxRFOGakIPNRl6Eej6FcJ7eE3f0XOJOIl1ids+f - mTJo7DANJFFRjo6hx9A21Ip4tBfSEXQX2oJO4VnoMJ6AOtA57EFZQDMs6kTD0Lu4p+cM - moZegPoL0JtoIzoAsIug2cgMpetwsOdBeI5BehJa3vMcSkUlaCU6ikqh1XWoq2dfz0Eo - HY3uQC1oP7z/cxwgB1hjzys9F5CIRkGby6HkTM+wnlZkQBmoEo2E3OXoDRxkzvfMQDZU - BqPbjp5Fu9BP0R/ww7ijZ0ZPY8/pnq8QgVIXGgPXUtyBv2Ja2ZU923t+15MASERQGvTa - gDag56H9VriOAflU43vwArwBbyQx8jDpYFdw1kQc4BBFNXANQnPQaoDAYXQc/QX9DX9D - bIyOWcCc6Cns+W+gmaEwSzqTqagRrlVwrYM5HcE8zsED8Ei8FD+FN+IPSRq5g9SShWQR - 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 - dEJCb3ggWzAgLTIyMSA3NjggNzM3XSAvRm9udE5hbWUgL1pCWE9FUCtIZWx2ZXRpY2Eg - L0l0YWxpY0FuZ2xlIDAgL1N0ZW1WCjAgL01heFdpZHRoIDE1MDAgL1hIZWlnaHQgNTEz - IC9Gb250RmlsZTIgOTkgMCBSID4+CmVuZG9iagoxMDIgMCBvYmoKWyAyNzggMCAwIDAg - MCAwIDAgMCAwIDAgMCAwIDI3OCAwIDI3OCAyNzggNTU2IDU1NiAwIDAgNTU2IDAgNTU2 - IDU1NiA1NTYgMAowIDI3OCAwIDU4NCAwIDU1NiAwIDY2NyAwIDcyMiA3MjIgNjY3IDYx - MSAwIDAgMjc4IDAgMCA1NTYgODMzIDcyMiAwIDY2NyAwCjcyMiA2NjcgNjExIDcyMiA2 - NjcgMCAwIDAgMCAwIDAgMCAwIDAgMCA1NTYgMCA1MDAgNTU2IDU1NiAyNzggNTU2IDU1 - NiAyMjIKMCA1MDAgMjIyIDgzMyA1NTYgNTU2IDU1NiAwIDMzMyA1MDAgMjc4IDU1NiAw - IDcyMiA1MDAgNTAwIDUwMCAwIDAgMCAwIDAgMAowIDAgMCAwIDAgMCAwIDAgMCAwIDAg - MCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAw - CjAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAg - MCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAKMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAw - IDAgMCAwIDAgMCA1MDAgXQplbmRvYmoKMzggMCBvYmoKPDwgL1R5cGUgL0ZvbnQgL1N1 - YnR5cGUgL1RydWVUeXBlIC9CYXNlRm9udCAvWkJYT0VQK0hlbHZldGljYSAvRm9udERl - c2NyaXB0b3IKMTAxIDAgUiAvV2lkdGhzIDEwMiAwIFIgL0ZpcnN0Q2hhciAzMiAvTGFz - dENoYXIgMjIyIC9FbmNvZGluZyAvTWFjUm9tYW5FbmNvZGluZwo+PgplbmRvYmoKMTAz - IDAgb2JqCjw8IC9MZW5ndGggMTA0IDAgUiAvTGVuZ3RoMSA4Njg0IC9GaWx0ZXIgL0Zs - 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 - pVjbU66bbL8ty7Q9UlZhG8ugvDHb6EwSB2x7ym6yPbBZyflFliLudwVwZMx2nywO2HZT - /3dtUgrujDTcGBGDm5WBrtuviOX7A8yDB2wDrnTbQmqIktbW7Vpm63K5bW0zA5g2ZvPK - zQ7YGjOO2RrkocdsUmSg0kjvJS4FcVFk2BzXIduUyAipcm0p3mZ3Ndqs1H/OfXfZclzX - 2GZmBXDvo/VTslz1GXeVBvCcMoYsCKgslkdEb8bj+EvSZyYuoGv73fvrMwkz7hizbSIx - sr9+SllagD0txdn2Z9RnbKZQSiGNwvwAtkk54k5xkThfnCpmi5liuugQU8QkMUEVp9Kp - YlRRKo1KpaLlrmJUoEoIhP8qZcs2mSDoZCGQwdMbECWuIxtExRDJXOlFAgNzICDAzYmr - qkxVcTP07tqab/jrUTJ7arK/+pHjnvyZ0Oq/i16G+/dZO/1FciRs7Zws/f9F+qqpfUPL - mv0ta860K99TnJ6+Hvqs4t+2ij57bVhot4+eWSMXyG/2exb29svS1+df4+yr8Z9x1thH - W5R2Xytul4tbnDWj0O5p6xhtl/pqxlqkFvl7Sef+Zk89bUc0yMWxtk6OVe/5hrE8cmf1 - 8ljNSruvjdUkFzfLYzXJYzXJYzVLzcpY2dmeJa3V8L9upOJhCmVuZHN0cmVhbQplbmRv - YmoKMTA0IDAgb2JqCjU2NzcKZW5kb2JqCjEwNSAwIG9iago8PCAvVHlwZSAvRm9udERl - c2NyaXB0b3IgL0FzY2VudCA3NzAgL0NhcEhlaWdodCA2ODQgL0Rlc2NlbnQgLTIzMCAv - RmxhZ3MgMzIKL0ZvbnRCQm94IFsxMCAtMjA5IDY1NSA3MzRdIC9Gb250TmFtZSAvQk5G - UEVKK0hlbHZldGljYS1Cb2xkIC9JdGFsaWNBbmdsZQowIC9TdGVtViAwIC9NYXhXaWR0 - aCAxNTAwIC9YSGVpZ2h0IDUxMyAvRm9udEZpbGUyIDEwMyAwIFIgPj4KZW5kb2JqCjEw - NiAwIG9iagpbIDI3OCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAw - IDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwCjAgMCAwIDAgMCA3MjIgMjc4IDAg - MCA2MTEgMCAwIDAgNjY3IDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgNTU2 - IDAKNTU2IDYxMSA1NTYgMCAwIDAgMjc4IDAgNTU2IDI3OCAwIDYxMSA2MTEgNjExIDAg - Mzg5IDU1NiAzMzMgNjExIDAgMCAwIDAgNTAwCl0KZW5kb2JqCjM5IDAgb2JqCjw8IC9U - eXBlIC9Gb250IC9TdWJ0eXBlIC9UcnVlVHlwZSAvQmFzZUZvbnQgL0JORlBFSitIZWx2 - ZXRpY2EtQm9sZCAvRm9udERlc2NyaXB0b3IKMTA1IDAgUiAvV2lkdGhzIDEwNiAwIFIg - L0ZpcnN0Q2hhciAzMiAvTGFzdENoYXIgMTIyIC9FbmNvZGluZyAvTWFjUm9tYW5FbmNv - ZGluZwo+PgplbmRvYmoKMSAwIG9iago8PCAvVGl0bGUgKFVudGl0bGVkKSAvQXV0aG9y - IChicmFuZG9uaCkgL0NyZWF0b3IgKE9tbmlHcmFmZmxlIFByb2Zlc3Npb25hbCkKL1By - b2R1Y2VyIChNYWMgT1MgWCAxMC41LjggUXVhcnR6IFBERkNvbnRleHQpIC9DcmVhdGlv - bkRhdGUgKEQ6MjAwOTEyMTYyMjQyMDlaMDAnMDAnKQovTW9kRGF0ZSAoRDoyMDA5MTIx - NjIyNDIwOVowMCcwMCcpID4+CmVuZG9iagp4cmVmCjAgMTA3CjAwMDAwMDAwMDAgNjU1 - MzUgZiAKMDAwMDA5NjU1OCAwMDAwMCBuIAowMDAwMDc3OTE1IDAwMDAwIG4gCjAwMDAw - MDM4NTEgMDAwMDAgbiAKMDAwMDA3Nzc1MiAwMDAwMCBuIAowMDAwMDAwMDIyIDAwMDAw - IG4gCjAwMDAwMDM4MzEgMDAwMDAgbiAKMDAwMDAwMzk1NiAwMDAwMCBuIAowMDAwMDc1 - NDAxIDAwMDAwIG4gCjAwMDAwMDczNDQgMDAwMDAgbiAKMDAwMDAwODE4OSAwMDAwMCBu - IAowMDAwMDEyNzk0IDAwMDAwIG4gCjAwMDAwMTM4ODUgMDAwMDAgbiAKMDAwMDAwNjIy - MyAwMDAwMCBuIAowMDAwMDA3MzI0IDAwMDAwIG4gCjAwMDAwMDgyMDkgMDAwMDAgbiAK - MDAwMDAwOTMwMCAwMDAwMCBuIAowMDAwMDEzOTA1IDAwMDAwIG4gCjAwMDAwMTQ5OTYg - MDAwMDAgbiAKMDAwMDAwNTQwMiAwMDAwMCBuIAowMDAwMDA2MjAzIDAwMDAwIG4gCjAw - MDAwMTYxMjcgMDAwMDAgbiAKMDAwMDAxNjg4NCAwMDAwMCBuIAowMDAwMDE2OTA0IDAw - MDAwIG4gCjAwMDAwMTc5OTUgMDAwMDAgbiAKMDAwMDAxMDA5NyAwMDAwMCBuIAowMDAw - MDExMTg4IDAwMDAwIG4gCjAwMDAwMDkzMjAgMDAwMDAgbiAKMDAwMDAxMDA3NyAwMDAw - MCBuIAowMDAwMDExMjA4IDAwMDAwIG4gCjAwMDAwMTE5NTMgMDAwMDAgbiAKMDAwMDAw - NDI5MSAwMDAwMCBuIAowMDAwMDA1MzgyIDAwMDAwIG4gCjAwMDAwMTUwMTYgMDAwMDAg - biAKMDAwMDAxNjEwNyAwMDAwMCBuIAowMDAwMDExOTczIDAwMDAwIG4gCjAwMDAwMTI3 - NzQgMDAwMDAgbiAKMDAwMDA3NzcxNSAwMDAwMCBuIAowMDAwMDg5OTM3IDAwMDAwIG4g - CjAwMDAwOTYzNzYgMDAwMDAgbiAKMDAwMDA3Njg1MCAwMDAwMCBuIAowMDAwMDYyMTU4 - IDAwMDAwIG4gCjAwMDAwNjYwNDMgMDAwMDAgbiAKMDAwMDA3MDgyNCAwMDAwMCBuIAow - MDAwMDE4MDE1IDAwMDAwIG4gCjAwMDAwMjA5ODQgMDAwMDAgbiAKMDAwMDA3MzcyNCAw - MDAwMCBuIAowMDAwMDY2MDY0IDAwMDAwIG4gCjAwMDAwNzAxMTUgMDAwMDAgbiAKMDAw - MDA3NDQ0OSAwMDAwMCBuIAowMDAwMDM4MzMwIDAwMDAwIG4gCjAwMDAwNDE1NDEgMDAw - MDAgbiAKMDAwMDA0NTAyMiAwMDAwMCBuIAowMDAwMDQ4OTA3IDAwMDAwIG4gCjAwMDAw - NzIyNzQgMDAwMDAgbiAKMDAwMDA1OTQ0OSAwMDAwMCBuIAowMDAwMDYyMTM3IDAwMDAw - IG4gCjAwMDAwNDg5MjggMDAwMDAgbiAKMDAwMDA1MjgxMyAwMDAwMCBuIAowMDAwMDcx - NTQ5IDAwMDAwIG4gCjAwMDAwMzU4MzYgMDAwMDAgbiAKMDAwMDAzODMwOSAwMDAwMCBu - IAowMDAwMDcyOTk5IDAwMDAwIG4gCjAwMDAwNDE1NjIgMDAwMDAgbiAKMDAwMDA0NTAw - MSAwMDAwMCBuIAowMDAwMDU1NTQzIDAwMDAwIG4gCjAwMDAwNTk0MjggMDAwMDAgbiAK - MDAwMDAyMTAwNSAwMDAwMCBuIAowMDAwMDI0ODkwIDAwMDAwIG4gCjAwMDAwNzYxMjUg - MDAwMDAgbiAKMDAwMDAyNDkxMSAwMDAwMCBuIAowMDAwMDMxOTA5IDAwMDAwIG4gCjAw - MDAwNTI4MzQgMDAwMDAgbiAKMDAwMDA1NTUyMiAwMDAwMCBuIAowMDAwMDMxOTMwIDAw - MDAwIG4gCjAwMDAwMzU4MTUgMDAwMDAgbiAKMDAwMDA3MDEzNiAwMDAwMCBuIAowMDAw - MDcwODA0IDAwMDAwIG4gCjAwMDAwNzA4NjEgMDAwMDAgbiAKMDAwMDA3MTUyOSAwMDAw - MCBuIAowMDAwMDcxNTg2IDAwMDAwIG4gCjAwMDAwNzIyNTQgMDAwMDAgbiAKMDAwMDA3 - MjMxMSAwMDAwMCBuIAowMDAwMDcyOTc5IDAwMDAwIG4gCjAwMDAwNzMwMzYgMDAwMDAg - biAKMDAwMDA3MzcwNCAwMDAwMCBuIAowMDAwMDczNzYxIDAwMDAwIG4gCjAwMDAwNzQ0 - MjkgMDAwMDAgbiAKMDAwMDA3NDQ4NiAwMDAwMCBuIAowMDAwMDc1MzgxIDAwMDAwIG4g - CjAwMDAwNzU0MzcgMDAwMDAgbiAKMDAwMDA3NjEwNSAwMDAwMCBuIAowMDAwMDc2MTYy - IDAwMDAwIG4gCjAwMDAwNzY4MzAgMDAwMDAgbiAKMDAwMDA3Njg4NyAwMDAwMCBuIAow - MDAwMDc3Njk1IDAwMDAwIG4gCjAwMDAwNzc4MzUgMDAwMDAgbiAKMDAwMDA3ODA0MSAw - MDAwMCBuIAowMDAwMDc3OTYzIDAwMDAwIG4gCjAwMDAwNzgxMTkgMDAwMDAgbiAKMDAw - MDA4OTE4OCAwMDAwMCBuIAowMDAwMDg5MjExIDAwMDAwIG4gCjAwMDAwODk0MzIgMDAw - MDAgbiAKMDAwMDA5MDExNCAwMDAwMCBuIAowMDAwMDk1ODgzIDAwMDAwIG4gCjAwMDAw - OTU5MDUgMDAwMDAgbiAKMDAwMDA5NjEzMyAwMDAwMCBuIAp0cmFpbGVyCjw8IC9TaXpl - IDEwNyAvUm9vdCA5NiAwIFIgL0luZm8gMSAwIFIgL0lEIFsgPDE3ZDJjNDJhMzE3NDJh - NTgyMWQxNTc1OWQwMGFhYWE5Pgo8MTdkMmM0MmEzMTc0MmE1ODIxZDE1NzU5ZDAwYWFh - YTk+IF0gPj4Kc3RhcnR4cmVmCjk2NzczCiUlRU9GCjEgMCBvYmoKPDwvQXV0aG9yIChi - cmFuZG9uaCkvQ3JlYXRpb25EYXRlIChEOjIwMDkxMTIwMDExMzAwWikvQ3JlYXRvciAo - T21uaUdyYWZmbGUgUHJvZmVzc2lvbmFsIDUuMi4xKS9Nb2REYXRlIChEOjIwMDkxMjE2 - MjI0MjAwWikvUHJvZHVjZXIgKE1hYyBPUyBYIDEwLjUuOCBRdWFydHogUERGQ29udGV4 - dCkvVGl0bGUgKGhlYWRlcl9wYXJzaW5nX2Zsb3djaGFydC5ncmFmZmxlKT4+CmVuZG9i - agp4cmVmCjEgMQowMDAwMDk5MDczIDAwMDAwIG4gCnRyYWlsZXIKPDwvSUQgWzwxN2Qy - YzQyYTMxNzQyYTU4MjFkMTU3NTlkMDBhYWFhOT4gPDE3ZDJjNDJhMzE3NDJhNTgyMWQx - NTc1OWQwMGFhYWE5Pl0gL0luZm8gMSAwIFIgL1ByZXYgOTY3NzMgL1Jvb3QgOTYgMCBS - IC9TaXplIDEwNz4+CnN0YXJ0eHJlZgo5OTI5OQolJUVPRgo= - - QuickLookThumbnail - - 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 - AAASmwAAT0AAAFOAAAIzMwACMzMAAjMzZGVzYwAAAAAAAAAOU2NlcHRyZSBYMjRXRwAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABtbHVjAAAAAAAAABIAAAAMbmJOTwAAABoA - AADocHRQVAAAABoAAADoc3ZTRQAAABoAAADoZmlGSQAAABoAAADoZGFESwAAABoAAADo - emhDTgAAABoAAADoZnJGUgAAABoAAADoamFKUAAAABoAAADoZW5VUwAAABoAAADocGxQ - TAAAABoAAADocHRCUgAAABoAAADoZXNFUwAAABoAAADoemhUVwAAABoAAADocnVSVQAA - ABoAAADoa29LUgAAABoAAADoZGVERQAAABoAAADobmxOTAAAABoAAADoaXRJVAAAABoA - AADoAFMAYwBlAHAAdAByAGUAIABYADIANABXAEcAAG1tb2QAAAAAAABOFAAAJAQAAABF - w6htgAAAAAAAAAAAAAAAAAAAAAB0ZXh0AAAAAENvcHlyaWdodCBBcHBsZSwgSW5jLiwg - MjAwOQA= - - ReadOnly - NO - RowAlign - 1 - RowSpacing - 36 - SheetTitle - Canvas 1 - SmartAlignmentGuidesActive - YES - SmartDistanceGuidesActive - YES - UniqueID - 1 - UseEntirePage - - VPages - 1 - WindowInfo - - CurrentSheet - 0 - ExpandedCanvases - - - name - Canvas 1 - - - FitInWindow - - Frame - {{94, 4}, {1714, 1174}} - ListView - - OutlineWidth - 142 - RightSidebar - - ShowRuler - - Sidebar - - SidebarWidth - 120 - VisibleRegion - {{0, -16}, {1187.25, 766.937}} - Zoom - 1.3299663066864014 - ZoomValues - - - Canvas 1 - 0.0 - 1 - - - - saveQuickLookFiles - YES - - diff --git a/openflow/doc/of-spec/make_latex_input.pl b/openflow/doc/of-spec/make_latex_input.pl deleted file mode 100755 index 7a1c48b7..00000000 --- a/openflow/doc/of-spec/make_latex_input.pl +++ /dev/null @@ -1,117 +0,0 @@ -#!/usr/bin/perl -w - -use strict; - -sub handle_comment { - my ($comment) = @_; - - my $next_line; - do { - $next_line = ; - chomp $next_line; - $comment .= $next_line . "\n"; - } until ( $next_line =~ m/\*\// ); - - return $comment; -} - -sub handle_define { - my ( $var, $val ) = @_; - open( OUTFILE, ">define/$var" ); - print OUTFILE $val; - close(OUTFILE); -} - -sub handle_multiline { - my ( $dir, $filename, $line_orig, $last_comment ) = @_; - - open( OUTFILE, ">$dir/$filename" ); - - #print OUTFILE "\\scriptsize\n"; - print OUTFILE "\\begin{footnotesize}\n"; - print OUTFILE "\\begin{verbatim}\n"; - - #print OUTFILE "\\begin{lstlisting}[frame=htb]{$filename}\n"; - print OUTFILE $last_comment; - print OUTFILE $line_orig; - my $next_line; - do { - - $next_line = ; - chomp $next_line; - - print OUTFILE $next_line . "\n"; - - } until ( $next_line eq '};' ); - - # add assertion line for structs - if ( $dir eq 'struct' ) { - $next_line = ; - print OUTFILE $next_line; - } - print OUTFILE "\\end{verbatim}\n"; - - #print OUTFILE "\\end{lstlisting}\n"; - print OUTFILE "\\end{footnotesize}\n"; - close(OUTFILE); -} - -#---------------------------------------- -use File::Path; - -foreach my $type ( 'enum', 'struct', 'define' ) { - if ( -d $type ) { - rmtree($type); - } - mkdir $type; -} - -open( INFILE, "<../../include/openflow/openflow.h" ); - -my $last_comment; -while () { - - # Good practice to store $_ value because - # subsequent operations may change it. - my ($line) = $_; - my $line_orig = $line; - my @line_split = split ' ', $line; - - if ( not defined( $line_split[0] ) ) { - $last_comment = ''; - } - - # Handle single-line comment - elsif ( $line =~ m/^\/\*.*\*\// ) { - $last_comment = $line; - - #print $last_comment; - } - - # Handle multi-line comment - elsif ( $line =~ m/^\/\*/ ) { - $last_comment = handle_comment($line_orig); - - #print $last_comment; - } - - # Handle define - elsif ( $line_split[0] eq '#define' ) { - handle_define( $line_split[1], $line_split[2] ); - $last_comment = ''; - } - - # Handle enum - elsif ( $line_split[0] eq 'enum' ) { - handle_multiline( 'enum', $line_split[1], $line_orig, $last_comment ); - $last_comment = ''; - } - - # Handle struct - elsif ( $line_split[0] eq 'struct' ) { - handle_multiline( 'struct', $line_split[1], $line_orig, $last_comment ); - $last_comment = ''; - } - -} -print "completed\n"; diff --git a/openflow/doc/of-spec/openflow-spec-v1.0.0.tex b/openflow/doc/of-spec/openflow-spec-v1.0.0.tex deleted file mode 100644 index 56dca85c..00000000 --- a/openflow/doc/of-spec/openflow-spec-v1.0.0.tex +++ /dev/null @@ -1,418 +0,0 @@ -\documentclass[10pt]{article} -\usepackage{amsmath} -\usepackage{listings} -\usepackage{hyperref} -\usepackage{fancyhdr} -\usepackage{graphicx} -\usepackage{tabularx} -\usepackage{color} - -\hbadness=10000 % No "underfull hbox" messages - -\begin{document} - -%\lstset{language=C} - -% Define the OpenFlow version here -\newcommand{\ofversion}{1.0.0} - -\pagestyle{fancy} -\fancyhead{} -\lhead{OpenFlow Switch Specification} -%\chead{DO NOT BUILD A SWITCH FROM THIS SPECIFICATION!} -\rhead{Version \ofversion} -\renewcommand{\headrulewidth}{0.4pt} -\renewcommand{\footrulewidth}{0.4pt} - -\fontfamily{cmr} % what about cmss? -\selectfont - -\newcommand{\qosupd}[1]{{#1}} -%\newcommand{\qosupd}[1]{{\color{blue} #1}} - -\title{OpenFlow Switch Specification} -\author{Version \ofversion{} ( Wire Protocol \input{define/OFP_VERSION})} -\date{\today} -\maketitle - -\section{Introduction} -This document describes the requirements of an OpenFlow Switch. We recommend that you read the latest version of the OpenFlow whitepaper before reading this specification. The whitepaper is available on the OpenFlow Consortium website (\url{http://OpenFlowSwitch.org}). This specification covers the components and the basic functions of the switch, and the OpenFlow protocol to manage an OpenFlow switch from a remote controller. -\\\\ -Version 1.0 of this document will be the first for which official vendor support is expected. Versions before 1.0 will be marked ``Draft", and will include the header: ``Do not build a switch from this specification!" We hope to generate feedback prior to Version 1.0 from switch designers and network researchers, so that the set of features defined in Version 1.0 enables production deployments on a variety of vendor hardware. - -\begin{figure}[htbp] -\centering -\includegraphics[height=2.5in]{figure_flow_table_secchan.png} -\caption{An OpenFlow switch communicates with a controller over a secure connection using the OpenFlow protocol.} -\label{fig:flow table and controller} -\end{figure} - -\section{Switch Components} -An OpenFlow Switch consists of a \emph{flow table}, which performs packet lookup and forwarding, and a \emph{secure channel} to an external controller (Figure \ref{fig:flow table and controller}). The controller manages the switch over the secure channel using the OpenFlow protocol. -\\\\ -The flow table contains a set of flow entries (header values to match packets against), activity counters, and a set of zero or more actions to apply to matching packets. All packets processed by the switch are compared against the flow table. If a matching entry is found, any actions for that entry are performed on the packet (e.g., the action might be to forward a packet out a specified port). If no match is found, the packet is forwarded to the controller over the secure channel. The controller is responsible for determining how to handle packets without valid flow entries, and it manages the switch flow table by adding and removing flow entries. -\\\\ -Flow entries may forward packets to one or more OpenFlow ports. In general, these are physical ports, but the protocol does not preclude abstractions like port aggregations or VLAN traffic on a port appearing as an OpenFlow port. OpenFlow ports have limited state such as ``up'', ``down'' and whether spanning tree flood packets should be forwarded out the port. Additional configuration of ports may handled by the OpenFlow configuration protocol. There are several OpenFlow virtual ports used to indicate, for example, flooding or the ingress port (see \ref{ft:actions}). - -\section{Flow Table} -This section describes the components of flow table entries and the process by which incoming packets are matched against flow table entries. - -\begin{table}[hbp] -\centering -\begin{tabular}{|c|c|c|} -\hline -Header Fields & Counters & Actions\\ -\hline -\end{tabular} -\caption{A flow entry consists of header fields, counters, and actions.} -\label{table:flow entry} -\end{table} - -Each flow table entry (see Table \ref{table:flow entry}) contains: -\begin{itemize} -\item \textbf{header fields} to match against packets -\item \textbf{counters} to update for matching packet -\item \textbf{actions} to apply to matching packets -\end{itemize} - -\subsection{Header Fields} -\begin{table}[hbp] -\centering -\footnotesize -\begin{tabularx}{\textwidth}{ |X|X|X|X|X|X|X|X|X|X|X|X| } -\hline -Ingress Port & -Ether source & -Ether dst & -Ether type & -VLAN id & -VLAN priority & -IP src & -IP dst & -IP proto & -IP ToS bits & -TCP/ UDP src port & -TCP/ UDP dst port -\\ -\hline -\end{tabularx} -\caption{Fields from packets used to match against flow entries.} -\label{table:header fields} -\end{table} - -Table \ref{table:header fields} shows the header fields an incoming packet is compared against. Each entry contains a specific value, or ANY, which matches any value. If the switch supports subnet masks on the IP source and/or destination fields, these can more precisely specify matches. The fields in the OpenFlow 12-tuple are listed in Table \ref{table:header fields} and details on the properties of each field are described in Table \ref{table:header field details}. -\\\\ -\begin{table}[hbp] -\centering -\footnotesize -\begin{tabularx}{\textwidth}{ |X|X|X|X| } -\hline Field & Bits & When applicable & Notes \\ -\hline Ingress Port & (Implementation dependent) & All packets & Numerical representation of incoming port, starting at 1. \\ -\hline Ethernet source address & 48 & All packets on enabled ports & \\ -\hline Ethernet destination address & 48 & All packets on enabled ports & \\ -\hline Ethernet type & 16 & All packets on enabled ports & An OpenFlow switch is required to match the type in both standard Ethernet and 802.2 with a SNAP header and OUI of 0x000000. The special value of 0x05FF is used to match all 802.3 packets without SNAP headers. \\ -\hline VLAN id & 12 & All packets of Ethernet type 0x8100 & \\ -\hline VLAN priority & 3 & All packets of Ethernet type 0x8100 & VLAN PCP field \\ -\hline IP source address & 32 & All IP and ARP packets & Can be subnet masked \\ -\hline IP destination address & 32 & All IP and ARP packets & Can be subnet masked \\ -\hline IP protocol & 8 & All IP and IP over Ethernet, ARP packets & Only the lower 8 bits of the ARP opcode are used \\ -\hline IP ToS bits & 6 & All IP packets & Specify as 8-bit value and place ToS in upper 6 bits. \\ -\hline Transport source port / ICMP Type & 16 & All TCP, UDP, and ICMP packets & Only lower 8 bits used for ICMP Type \\ -\hline Transport destination port / ICMP Code & 16 & All TCP, UDP, and ICMP packets & Only lower 8 bits used for ICMP Code \\ -\hline -\end{tabularx} -\caption{Field lengths and the way they must be applied to flow entries.} -\label{table:header field details} -\end{table}Switch designers are free to implement the internals in any way convenient provided that correct functionality is preserved. For example, while a flow may have multiple forward actions, each specifying a different port, a switch designer may choose to implement this as a single bitmask within the hardware forwarding table. - -\subsection{Counters} - -Counters are maintained per-table, per-flow, \qosupd{per-port and - per queue}. OpenFlow-compliant counters may be implemented in software and maintained by polling hardware counters with more limited ranges. -\\\\ -Table \ref{table:counters} contains the required set of counters. Duration refers to the time the flow has been installed in the switch. The Receive Errors field includes all explicitly specified errors, including frame, overrun, and CRC errors, plus any others. Counters wrap around with no overflow indicator. In this document, the phrase byte refers to 8-bit octets. -\begin{table}[!hbp] -\centering -\footnotesize -%\begin{tabularx}{\textwidth}{ |X|X| } -\begin{tabular}{ |l|c| } -\hline Counter & Bits \\ -\hline \multicolumn{2}{|c|}{Per Table} \\ -\hline Active Entries & 32 \\ -\hline Packet Lookups & 64 \\ -\hline Packet Matches & 64 \\ -\hline \multicolumn{2}{|c|}{Per Flow} \\ -\hline Received Packets & 64 \\ -\hline Received Bytes & 64 \\ -\hline Duration (seconds) & 32 \\ -\hline Duration (nanoseconds) & 32 \\ -\hline \multicolumn{2}{|c|}{Per Port} \\ -\hline Received Packets & 64 \\ -\hline Transmitted Packets & 64 \\ -\hline Received Bytes & 64 \\ -\hline Transmitted Bytes & 64 \\ -\hline Receive Drops & 64 \\ -\hline Transmit Drops & 64 \\ -\hline Receive Errors & 64 \\ -\hline Transmit Errors & 64 \\ -\hline Receive Frame Alignment Errors & 64 \\ -\hline Receive Overrun Errors & 64 \\ -\hline Receive CRC Errors & 64 \\ -\hline Collisions & 64 \\ -\hline \multicolumn{2}{|c|}{\qosupd{Per Queue}} \\ -\hline \qosupd{Transmit Packets} & \qosupd{64} \\ -\hline \qosupd{Transmit Bytes} & \qosupd{64} \\ -\hline \qosupd{Transmit Overrun Errors} & \qosupd{64}\\ -\hline -\end{tabular} -\caption{Required list of counters for use in statistics messages.} -\label{table:counters} -\end{table} - -\subsection{Actions} -\label{ft:actions} -Each flow entry is associated with zero or more actions that dictate how the switch handles matching packets. If no forward actions are present, the packet is dropped. Action lists for \emph{inserted} flow entries MUST be processed in the order specified. However, there is no packet output ordering guaranteed within a port. For example, an action list may result in two packets sent to two different VLANs on a single port. These two packets may be arbitrarily re-ordered, but the packet bodies must match those generated from a sequential execution of the actions. -\\\\ -A switch may reject a flow entry if it cannot process the action list in the order specified, in which case it should immediately return an unsupported flow error (see \ref{unsupported_flow}). Ordering within a port may vary between vendor switch implementations. -\\\\ -A switch is not required to support all action types --- just those marked ``Required Actions'' below. When connecting to the controller, a switch indicates which of the ``Optional Actions'' it supports. OpenFlow-compliant switches come in two types: \emph{OpenFlow-only}, and \emph{OpenFlow-enabled}. -\\\\ -OpenFlow-only switches support only the required actions below, while OpenFlow-enabled switches, routers, and access points may also support the \textbf{NORMAL} action. Either type of switch can also support the \textbf{FLOOD} action. -\\\\ -\textbf{Required Action:} \textit{Forward}. -OpenFlow switches must support forwarding the packet to physical ports and the following virtual ones: -\begin{itemize} -\item \textbf{ALL:} Send the packet out all interfaces, not including the incoming interface. -\item \textbf{CONTROLLER:} Encapsulate and send the packet to the controller. -\item \textbf{LOCAL:} Send the packet to the switchÕs local networking stack. -\item \textbf{TABLE:} Perform actions in flow table. Only for packet-out messages. -\item \textbf{IN\_PORT:} Send the packet out the input port. -\end{itemize} -\textbf{Optional Action:} \textit{Forward}. -The switch may optionally support the following virtual ports: -\begin{itemize} -\item \textbf{NORMAL:} Process the packet using the traditional forwarding path supported by the switch (i.e., traditional L2, VLAN, and L3 processing.) The switch may check the VLAN field to determine whether or not to forward the packet along the normal processing route. If the switch cannot forward entries for the OpenFlow-specific VLAN back to the normal processing route, it must indicate that it does not support this action. -\item \textbf{FLOOD:} Flood the packet along the minimum spanning tree, not including the incoming interface. -\end{itemize} -The controller will only ask the switch to send to multiple physical ports simultaneously if the switch indicates it supports this behavior in the initial handshake (see section \ref{cts:handshake}). -\\\\ -\textbf{\qosupd{Optional Action:}} \emph{\qosupd{Enqueue}}. \qosupd{The enqueue action forwards -a packet through a queue attached to a port. Forwarding behavior is -dictated by the configuration of the queue and is used to provide -basic Quality-of-Service (QoS) support (see section \ref{cts:qos}).} -\\\\ -\textbf{Required Action:} \emph{Drop}. A flow-entry with no specified action indicates that all matching packets should be dropped. -\\\\ -\textbf{Optional Action:} \emph{Modify-Field}. While not strictly required, the actions shown in Table \ref{table:field modify actions} greatly increase the usefulness of an OpenFlow implementation. To aid integration with existing networks, we suggest that VLAN modification actions be supported. - -\begin{table}[hbp] -\centering -\footnotesize -\begin{tabularx}{\linewidth}{ |X|X|X| } -\hline -Action & Associated Data & Description \\ -\hline -Set VLAN ID & -12 bits & -If no VLAN is present, a new header is added with the specified VLAN ID and priority of zero. - -If a VLAN header already exists, the VLAN ID is replaced with the specified value. \\ -\hline -Set VLAN priority & -3 bits & -If no VLAN is present, a new header is added with the specified priority and a VLAN ID of zero. - -If a VLAN header already exists, the priority field is replaced with the specified value. \\ -\hline -Strip VLAN header & -- & -Strip VLAN header if present. \\ -\hline -Modify Ethernet source MAC address & -48 bits: Value with which to replace existing source MAC address & -Replace the existing Ethernet source MAC address with the new value \\ -\hline -Modify Ethernet destination MAC address & -48 bits: Value with which to replace existing destination MAC address & -Replace the existing Ethernet destination MAC address with the new value. \\ -\hline -Modify IPv4 source address & -32 bits: Value with which to replace existing IPv4 source address & -Replace the existing IP source address with new value and update the IP checksum (and TCP/UDP -checksum if applicable). - -This action is only applicable to IPv4 packets. \\ -\hline -Modify IPv4 destination address & -32 bits: Value with which to replace existing IPv4 destination address & -Replace the existing IP destination address with new value and update the IP checksum (and TCP/UDP checksum if applicable). - -This action is only applied to IPv4 packets. \\ -\hline -Modify IPv4 ToS bits & -6 bits: Value with which to replace existing IPv4 ToS field & -Replace the existing IP ToS field. -This action is only applied to IPv4 packets. \\ -\hline -Modify transport source port & -16 bits: Value with which to replace existing TCP or UDP source port & -Replace the existing TCP/UDP source port with new value and update the TCP/UDP checksum. - -This action is only applicable to TCP and UDP packets.\\ -\hline -Modify transport destination port & -16 bits: Value with which to replace existing TCP or UDP destination port & -Replace the existing TCP/UDP destination port with new value and update the TCP/UDP checksum - -This action is only applied to TCP and UDP packets.\\ -\hline -\end{tabularx} -\caption{Field-modify actions.} -\label{table:field modify actions} -\end{table} - -\subsection{Matching} -\begin{figure}[!htb] -\centering -\includegraphics[height=1.85in]{packet_flow_flowchart} -\caption{Packet flow in an OpenFlow switch. As discussed in Section \ref{flow_table:stp_support}, support for 802.1D is optional.} -\label{fig:packet_flow} -\end{figure} - -\begin{figure}[!htb] -\centering -\includegraphics[height=2.9in]{header_parsing_flowchart} -\caption{Flowchart showing how header fields are parsed for matching.} -\label{fig:header_parsing} -\end{figure} - -On receipt of a packet, an OpenFlow Switch performs the functions shown in Figure \ref{fig:packet_flow}. Header fields used for the table lookup depend on the packet type as described below (and shown in Figure \ref{fig:header_parsing}). - -\begin{itemize} -\item Rules specifying an ingress port are matched against the physical port that received the packet. -\item The Ethernet headers as specified in Table \ref{table:header fields} are used for all packets. -\item If the packet is a VLAN (Ethernet type 0x8100), the VLAN ID and PCP fields are used in the lookup. -\item (Optional) For ARP packets (Ethernet type equal to 0x0806), the lookup fields may also include the contained IP source and destination fields. -\item For IP packets (Ethernet type equal to 0x0800), the lookup fields also include those in the IP header. -\item For IP packets that are TCP or UDP (IP protocol is equal to 6 or 17), the lookup includes the transport ports. -\item For IP packets that are ICMP (IP prototcol is equal to 1), the lookup includes the Type and Code fields. -\item For IP packets with nonzero fragment offset or More Fragments bit set, the transport ports are set to zero for the lookup. -\end{itemize} -A packet matches a flow table entry if the values in the header fields used for the lookup (as defined above) match those defined in the flow table. If a flow table field has a value of ANY, it matches all possible values in the header. -\\\\ -To handle the various Ethernet framing types, matching the Ethernet type is handled in a slightly different manner. If the packet is an Ethernet II frame, the Ethernet type is handled in the expected way. If the packet is an 802.3 frame with a SNAP header and Organizationally Unique Identifier (OUI) of 0x000000, the SNAP protocol id is matched against the flowÕs Ethernet type. A flow entry that specifies an Ethernet type of 0x05FF, matches all Ethernet 802.2 frames without a SNAP header and those with SNAP headers that do not have an OUI of 0x000000. -\\\\ -Packets are matched against flow entries based on prioritization. An entry that specifies an exact match (i.e., it has no wildcards) is always the highest priority. All wildcard entries have a priority associated with them. Higher priority entries must match before lower priority ones. If multiple entries have the same priority, the switch is free to choose any ordering. Higher numbers have higher priorities. -\\\\ -For each packet that matches a flow entry, the associated counters for that entry are updated. If no matching entry can be found for a packet, the packet is sent to the controller over the secure channel. - -\section{Secure Channel} -The secure channel is the interface that connects each OpenFlow switch to a controller. Through this interface, the controller configures and manages the switch, receives events from the switch, and send packets out the switch. -\\\\ -Between the datapath and the secure channel, the interface is implementation-specific, however all secure channel messages must be formatted according to the OpenFlow protocol. -\\\\ -Support for multiple simultaneous controllers is currently undefined. - -\subsection{OpenFlow Protocol Overview} -The OpenFlow protocol supports three message types, \emph{controller-to-switch}, \emph{asynchronous}, and \emph{symmetric}, each with multiple sub-types. Controller-to-switch messages are initiated by the controller and used to directly manage or inspect the state of the switch. Asynchronous messages are initiated by the switch and used to update the controller of network events and changes to the switch state. Symmetric messages are initiated by either the switch or the controller and sent without solicitation. The message types used by OpenFlow are described below. - -\subsubsection{Controller-to-Switch} -Controller/switch messages are initiated by the controller and may or may not require a response from the switch. -\\\\ -\textbf{Features:} Upon Transport Layer Security (TLS) session establishment, the controller sends a features request message to the switch. The switch must reply with a features reply that specifies the capabilities supported by the switch. -\\\\ -\textbf{Configuration:} The controller is able to set and query configuration parameters in the switch. The switch only responds to a query from the controller. -\\\\ -\textbf{Modify-State:} Modify-State messages are sent by the controller to manage state on the switches. Their primary purpose is to add/delete and modify flows in the flow tables and to set switch port properties. -\\\\ -\textbf{Read-State:} Read-State messages are used by the controller to collect statistics from the switchÕs flow-tables, ports and the individual flow entries. -\\\\\ -\textbf{Send-Packet}: These are used by the controller to send packets out of a specified port on the switch. -\\\\ -\textbf{Barrier}: Barrier request/reply messages are used by the controller to ensure message dependencies have been met or to receive notifications for completed operations. - -\subsubsection{Asynchronous} -Asynchronous messages are sent without the controller soliciting them from a switch. Switches send asynchronous messages to the controller to denote a packet arrival, switch state change, or error. The four main asynchronous message types are described below. -\\\\ -\textbf{Packet-in:} For all packets that do not have a matching flow entry, a packet-in event is sent to the controller (or if a packet matches an entry with a ``send to controller" action). If the switch has sufficient memory to buffer packets that are sent to the controller, the packet-in events contain some fraction of the packet header (by default \input{define/OFP_DEFAULT_MISS_SEND_LEN} bytes) and a buffer ID to be used by the controller when it is ready for the switch to forward the packet. Switches that do not support internal buffering (or have run out of internal buffering) must send the full packet to the controller as part of the event. -\\\\ -\textbf{Flow-Removed:} When a flow entry is added to the switch by a flow modify message, an idle timeout value indicates when the entry should be removed due to a lack of activity, as well as a hard timeout value that indicates when the entry should be removed, regardless of activity. The flow modify message also specifies whether the switch should send a flow removed message to the controller when the flow expires. Flow modify messages which delete flows may also cause flow removed messages. -\\\\ -\textbf{Port-status:} The switch is expected to send port-status messages to the controller as port configuration state changes. These events include change in port status (for example, if it was brought down directly by a user) or a change in port status as specified by 802.1D (see Section \ref{flow_table:stp_support} for a description of 802.1D support requirements). -\\\\ -\textbf{Error:} The switch is able to notify the controller of problems using error messages. - -\subsubsection{Symmetric} -Symmetric messages are sent without solicitation, in either direction. -\\\\ -\textbf{Hello:} Hello messages are exchanged between the switch and controller upon connection startup. -\\\\ -\textbf{Echo:} Echo request/reply messages can be sent from either the switch or the controller, and must return an echo reply. They can be used to indicate the latency, bandwidth, and/or liveness of a controller-switch connection. -\\\\ -\textbf{Vendor:} Vendor messages provide a standard way for OpenFlow switches to offer additional functionality within the OpenFlow message type space. This is a staging area for features meant for future OpenFlow revisions. - -\subsection{Connection Setup} -The switch must be able to establish the communication at a user-configurable (but otherwise fixed) IP address, using a user-specified port. Traffic to and from the secure channel is not checked against the flow table. Therefore, the switch must identify incoming traffic as local before checking it against the flow table. Future versions of the protocol specification will describe a dynamic controller discovery protocol in which the IP address and port for communicating with the controller is determined at runtime. -\\\\ -When an OpenFlow connection is first established, each side of the connection must immediately send an \verb|OFPT_HELLO| message with the \verb|version| field set to the highest OpenFlow protocol version supported by the sender. Upon receipt of this message, the recipient may calculate the OpenFlow protocol version to be used as the smaller of the version number that it sent and the one that it received. -\\\\ -If the negotiated version is supported by the recipient, then the connection proceeds. Otherwise, the recipient must reply with an \verb|OFPT_ERROR| message with a \verb|type| field of \verb|OFPET_HELLO_FAILED|, a \verb|code| field of \verb| OFPHFC_COMPATIBLE|, and optionally an ASCII string explaining the situation in \verb|data|, and then terminate the connection. - -\subsection{Connection Interruption} -In the case that a switch loses contact with the controller, as a result of a echo request timeout, TLS session timeout, or other disconnection, it should attempt to contact one or more backup controllers. The ordering of the controller IP addresses is not specified by the protocol. -\\\\ -If some number of attempts to contact a controller (zero or more) fail, the switch must enter ``emergency mode'' and immediately reset the current TCP connection. In emergency mode, the matching process is dictated by the emergency flow table entries (those marked with the emergency bit when added to the switch). All normal entries are deleted when entering emergency mode. -\\\\ -Upon connecting to a controller again, the emergency flow entries remain. The controller then has the option of deleting all flow entries, if desired. -\\\\ -The first time a switch starts up, it is considered to be in emergency mode. Configuration of the default set of flow entries is outside the scope of the OpenFlow protocol. - -\subsection{Encryption} -The switch and controller communicate through a TLS connection. The TLS connection is initiated by the switch on startup to the controller's server, which is located by default on TCP port \input{define/OFP_TCP_PORT}. The switch and controller mutually authenticate by exchanging certificates signed by a site-specific private key. Each switch must be user-configurable with one certificate for authenticating the controller (controller certificate) and the other for authenticating to the controller (switch certificate). - -\subsection{Spanning Tree} -\label{flow_table:stp_support} -OpenFlow switches may optionally support 802.1D Spanning Tree Protocol. Those switches that do support it are expected to process all 802.1D packets locally before performing flow lookup. A switch that implements STP must set the \verb|OFPC_STP| bit in the 'capabilities' field of its \verb|OFPT_FEATURES_REPLY| message. A switch that implements STP must make it available on all of its physical ports, but it need not implement it on virtual ports (e.g. \verb|OFPP_LOCAL|). -\\\\ -Port status, as specified by the spanning tree protocol, is then used to limit packets forwarded to the \verb|OFP_FLOOD| port to only those ports along the spanning tree. Port changes as a result of the spanning tree are sent to the controller via port-update messages. Note that forward actions that specify the outgoing port or \verb|OFP_ALL| ignore the port status set by the spanning tree protocol. Packets received on ports that are disabled by spanning tree must follow the normal flow table processing path. -\\\\ -Switches that do not support 802.1D spanning tree must allow the controller to specify the port status for packet flooding through the port-mod messages. - -\subsection{Flow Table Modification Messages} -\label{flow_table:sec_chan:flow_add} -\label{flow_table:sec_chan:flow_mod} -\label{flow_table:sec_chan:flow_removal} -Flow table modification messages can have the following types: -\input{enum/ofp_flow_mod_command} -For ADD requests with the \verb|OFPFF_CHECK_OVERLAP| flag set, the switch must first check for any overlapping flow entries. Two flow entries overlap if a single packet may match both, and both entries have the same priority. If an overlap conflict exists between an existing flow entry and the ADD request, the switch must refuse the addition and respond with an \verb|ofp_error_msg| with \verb|OFPET_FLOW_MOD_FAILED| type and \verb|OFPFMFC_OVERLAP| code. -\\\\ -For valid (non-overlapping) ADD requests, or those with no overlap checking, the switch must insert the flow entry at the lowest numbered table for which the switch supports all wildcards set in the \verb|flow_match| struct, and for which the priority would be observed during the matching process. If a flow entry with identical header fields and priority already resides in any table, then that entry, including its counters, must be removed, and the new flow entry added. -\\\\ -If a switch cannot find any table in which to add the incoming flow entry, the switch should send an \verb|ofp_error_msg| with \verb|OFPET_FLOW_MOD_FAILED| type and \verb|OFPFMFC_ALL_TABLES_FULL| code. -\\\\ -If the action list in a flow mod message references a port that will never be valid on a switch, the switch must return an \verb|ofp_error_msg| with \verb|OFPET_BAD_ACTION| type and \verb|OFPBAC_BAD_OUT_PORT| code. If the referenced port may be valid in the future, e.g. when a linecard is added to a chassis switch, or a port is dynamically added to a software switch, the switch may either silently drop packets sent to the referenced port, or immediately return an \verb|OFPBAC_BAD_OUT_PORT| error and refuse the flow mod. -\\\\ -For MODIFY requests, if a flow entry with identical header fields does not current reside in any table, the MODIFY acts like an ADD, and the new flow entry must be inserted with zeroed counters. Otherwise, the actions field is changed on the existing entry and its counters and idle time fields are left unchanged. -\\\\ -For DELETE requests, if no flow entry matches, no error is recorded, and no flow table modification occurs. If flow entries match, and must be deleted, then each normal entry with the \verb|OFPFF_SEND_FLOW_REM| flag set should generate a flow removed message. Deleted emergency flow entries generate no flow removed messages. -\\\\ -MODIFY and DELETE flow mod commands have corresponding \_STRICT versions. Without \_STRICT appended, the wildcards are active and all flows that match the description are modified or removed. If \_STRICT is appended, all fields, including the wildcards and priority, are strictly matched against the entry, and only an identical flow is modified or removed. For example, if a message to remove entries is sent that has all the wildcard flags set, the DELETE command would delete all flows from all tables, while the DELETE\_STRICT command would only delete a rule that applies to all packets at the specified priority. -\\\\ -For non-strict MODIFY and DELETE commands that contain wildcards, a match will occur when a flow entry exactly matches or is more specific than the description in the flow\_mod command. For example, if a DELETE command says to delete all flows with a destination port of 80, then a flow entry that is all wildcards will not be deleted. However, a DELETE command that is all wildcards will delete an entry that matches all port 80 traffic. This same interpretation of mixed wildcard and exact header fields also applies to individual and aggregate flows stats. -\\\\ -DELETE and DELETE\_STRICT commands can be optionally filtered by output port. If the \verb|out_port| field contains a value other than \verb|OFPP_NONE|, it introduces a constraint when matching. This constraint is that the rule must contain an output action directed at that port. This field is ignored by ADD, MODIFY, and MODIFY\_STRICT messages. -\\\\ -Emergency flow mod messages must have timeout values set to zero. Otherwise, the switch must refuse the addition and respond with an \verb|ofp_error_msg| with \verb|OFPET_FLOW_MOD_FAILED| type and \verb|OFPFMFC_BAD_EMERG_TIMEOUT| code. -\\\\ -\label{unsupported_flow}If a switch cannot process the action list for any flow mod message in the order specified, it MUST immediately return an \verb|OFPET_FLOW_MOD_FAILED| : -\verb|OFPFMFC_UNSUPPORTED| error and reject the flow. - -\subsection{Flow Removal} - -Each flow entry has an \verb|idle_timeout| and a \verb|hard_timeout| associated with it. If no packet has matched the rule in the last \verb|idle_timeout| seconds, or it has been \verb|hard_timeout| seconds since the flow was inserted, the switch removes the entry and sends a flow removed message. In addition, the controller is able to actively remove entries by sending a flow message with the \verb|DELETE| or \verb|DELETE_STRICT| command. Like the message used to add the entry, a removal message contains a description, which may include wild cards. - -\input{appendix} - -\input{credits} - -\end{document} diff --git a/openflow/doc/of-spec/packet_flow_flowchart.graffle b/openflow/doc/of-spec/packet_flow_flowchart.graffle deleted file mode 100644 index 57a76098..00000000 --- a/openflow/doc/of-spec/packet_flow_flowchart.graffle +++ /dev/null @@ -1,1887 +0,0 @@ - - - - - ActiveLayerIndex - 0 - ApplicationVersion - - com.omnigroup.OmniGraffle - 138.12.0.121252 - - AutoAdjust - - BackgroundGraphic - - Bounds - {{0, 0}, {756, 553}} - Class - SolidGraphic - ID - 2 - Style - - shadow - - Draws - NO - - stroke - - Draws - NO - - - - CanvasOrigin - {0, 0} - ColumnAlign - 1 - ColumnSpacing - 36 - CreationDate - 2009-11-20 14:54:05 -0800 - Creator - brandonh - DisplayScale - 1 0/72 in = 1 0/72 in - GraphDocumentVersion - 6 - GraphicsList - - - Class - LineGraphic - Head - - ID - 50 - - ID - 67 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {104.25, 130.5} - {141.75, 130.5} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 66 - - - - Bounds - {{5.25, 99}, {99, 63}} - Class - ShapedGraphic - ID - 66 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 Packet in from network} - - VFlip - YES - - - Bounds - {{470.5, 317.375}, {30.1875, 14}} - Class - ShapedGraphic - FitText - Vertical - Flow - Resize - ID - 64 - Shape - Rectangle - Style - - fill - - Draws - NO - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Pad - 0 - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 no} - VerticalPad - 0 - - - - Bounds - {{470.5, 192.5}, {30.1875, 14}} - Class - ShapedGraphic - FitText - Vertical - Flow - Resize - ID - 63 - Shape - Rectangle - Style - - fill - - Draws - NO - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Pad - 0 - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 no} - VerticalPad - 0 - - - - Bounds - {{521.062, 277}, {30.1875, 14}} - Class - ShapedGraphic - FitText - Vertical - Flow - Resize - ID - 62 - Shape - Rectangle - Style - - fill - - Draws - NO - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Pad - 0 - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 yes} - VerticalPad - 0 - - - - Class - LineGraphic - Head - - ID - 55 - Position - 0.46666735410690308 - - ID - 61 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {514.5, 268.5} - {535.5, 130.5} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 52 - Info - 3 - - - - Bounds - {{514.5, 105.438}, {30.1875, 14}} - Class - ShapedGraphic - FitText - Vertical - Flow - Resize - ID - 60 - Shape - Rectangle - Style - - fill - - Draws - NO - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Pad - 0 - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 yes} - VerticalPad - 0 - - - - Class - LineGraphic - Head - - ID - 53 - - ID - 57 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {460.5, 322.5} - {460.5, 345} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 52 - Info - 1 - - - - Class - LineGraphic - Head - - ID - 52 - - ID - 56 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {460.5, 184.5} - {460.5, 214.5} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - Pattern - 2 - TailArrow - 0 - - - Tail - - ID - 47 - - - - Class - LineGraphic - Head - - ID - 54 - - ID - 55 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {514.5, 130.5} - {559.5, 130.5} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 47 - Info - 3 - - - - Bounds - {{559.5, 99}, {99, 63}} - Class - ShapedGraphic - ID - 54 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 Apply actions} - - VFlip - YES - - - Bounds - {{411, 345}, {99, 63}} - Class - ShapedGraphic - ID - 53 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 Send to controller via Secure Channel} - - VFlip - YES - - - Bounds - {{406.5, 214.5}, {108, 108}} - Class - ShapedGraphic - ID - 52 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Diamond - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 Match table N?} - VerticalPad - 0 - - - - Class - LineGraphic - Head - - ID - 35 - Info - 4 - - ID - 51 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {240.75, 130.5} - {271.5, 130.5} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 50 - Info - 3 - - - - Bounds - {{141.75, 99}, {99, 63}} - Class - ShapedGraphic - ID - 50 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Rectangle - Style - - stroke - - Pattern - 1 - - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 Optional\ -802.1d STP processing} - - VFlip - YES - - - Class - LineGraphic - Head - - ID - 47 - - ID - 49 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {370.5, 130.5} - {406.5, 130.5} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 35 - - - - Bounds - {{271.5, 99}, {99, 63}} - Class - ShapedGraphic - ID - 35 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 Parse header fields\ -(see below)} - - VFlip - YES - - - Bounds - {{406.5, 76.5}, {108, 108}} - Class - ShapedGraphic - ID - 47 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Diamond - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 Match table 0?} - VerticalPad - 0 - - - - GridInfo - - GuidesLocked - NO - GuidesVisible - YES - HPages - 1 - ImageCounter - 1 - KeepToScale - - Layers - - - Lock - NO - Name - Layer 1 - Print - YES - View - YES - - - LayoutInfo - - Animate - NO - circoMinDist - 18 - circoSeparation - 0.0 - layoutEngine - dot - neatoSeparation - 0.0 - twopiSeparation - 0.0 - - LinksVisible - NO - MagnetsVisible - NO - MasterSheets - - ModificationDate - 2009-11-20 15:11:07 -0800 - Modifier - brandonh - NotesVisible - NO - Orientation - 2 - OriginVisible - NO - PageBreaks - YES - PrintInfo - - NSBottomMargin - - float - 41 - - NSLeftMargin - - float - 18 - - NSOrientation - - int - 1 - - NSPaperSize - - size - {792, 612} - - NSRightMargin - - float - 18 - - NSTopMargin - - float - 18 - - - PrintOnePage - - QuickLookPreview - - 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 - ago8PCAvUHJvY1NldCBbIC9QREYgL1RleHQgL0ltYWdlQiAvSW1hZ2VDIC9JbWFnZUkg - XSAvQ29sb3JTcGFjZSA8PCAvQ3MyIDIzIDAgUgovQ3MxIDggMCBSID4+IC9Gb250IDw8 - IC9GMS4wIDI0IDAgUiA+PiAvWE9iamVjdCA8PCAvSW0xIDkgMCBSIC9JbTYgMTkgMCBS - Ci9JbTQgMTUgMCBSIC9JbTUgMTcgMCBSIC9JbTMgMTMgMCBSIC9JbTIgMTEgMCBSIC9J - bTcgMjEgMCBSID4+ID4+CmVuZG9iago5IDAgb2JqCjw8IC9MZW5ndGggMTAgMCBSIC9U - eXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMjYwIC9IZWlnaHQgMjYw - IC9Db2xvclNwYWNlCjI1IDAgUiAvU01hc2sgMjYgMCBSIC9CaXRzUGVyQ29tcG9uZW50 - IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7dAxAQAAAMKg9U/taQmI - QGHAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDgAwMYXQABCmVuZHN0cmVhbQplbmRvYmoKMTAgMCBvYmoK - OTA4CmVuZG9iagoxOSAwIG9iago8PCAvTGVuZ3RoIDIwIDAgUiAvVHlwZSAvWE9iamVj - dCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRoIDI0MiAvSGVpZ2h0IDE3MCAvQ29sb3JTcGFj - ZQoyOCAwIFIgL1NNYXNrIDI5IDAgUiAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIg - L0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae3QMQEAAADCoPVPbQo/iEBhwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwa+AwPiKwABCmVuZHN0cmVhbQplbmRvYmoKMjAgMCBvYmoK - NTYyCmVuZG9iagoxNSAwIG9iago8PCAvTGVuZ3RoIDE2IDAgUiAvVHlwZSAvWE9iamVj - dCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRoIDI2MCAvSGVpZ2h0IDI2MCAvQ29sb3JTcGFj - ZQoyNSAwIFIgL1NNYXNrIDMxIDAgUiAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIg - L0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae3QMQEAAADCoPVP7WkJiEBhwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBg4AMDGF0AAQplbmRzdHJlYW0KZW5kb2JqCjE2IDAgb2JqCjkwOAplbmRvYmoK - MTcgMCBvYmoKPDwgL0xlbmd0aCAxOCAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUg - L0ltYWdlIC9XaWR0aCAyNDIgL0hlaWdodCAxNzAgL0NvbG9yU3BhY2UKMjggMCBSIC9T - TWFzayAzMyAwIFIgL0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29k - ZSA+PgpzdHJlYW0KeAHt0DEBAAAAwqD1T20KP4hAYcCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGvgMD4isAAQplbmRzdHJlYW0KZW5kb2JqCjE4IDAgb2JqCjU2MgplbmRvYmoK - MTMgMCBvYmoKPDwgL0xlbmd0aCAxNCAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUg - L0ltYWdlIC9XaWR0aCAyNDIgL0hlaWdodCAxNzAgL0NvbG9yU3BhY2UKMzUgMCBSIC9T - TWFzayAzNiAwIFIgL0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29k - ZSA+PgpzdHJlYW0KeAHt0DEBAAAAwqD1T20KP4hAYcCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGvgMD4isAAQplbmRzdHJlYW0KZW5kb2JqCjE0IDAgb2JqCjU2MgplbmRvYmoK - MTEgMCBvYmoKPDwgL0xlbmd0aCAxMiAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUg - L0ltYWdlIC9XaWR0aCAyNDIgL0hlaWdodCAxNzAgL0NvbG9yU3BhY2UKMjggMCBSIC9T - TWFzayAzOCAwIFIgL0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29k - ZSA+PgpzdHJlYW0KeAHt0DEBAAAAwqD1T20KP4hAYcCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGvgMD4isAAQplbmRzdHJlYW0KZW5kb2JqCjEyIDAgb2JqCjU2MgplbmRvYmoK - MjEgMCBvYmoKPDwgL0xlbmd0aCAyMiAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUg - L0ltYWdlIC9XaWR0aCAyNDIgL0hlaWdodCAxNzAgL0NvbG9yU3BhY2UKMjggMCBSIC9T - TWFzayA0MCAwIFIgL0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29k - ZSA+PgpzdHJlYW0KeAHt0DEBAAAAwqD1T20KP4hAYcCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGvgMD4isAAQplbmRzdHJlYW0KZW5kb2JqCjIyIDAgb2JqCjU2MgplbmRvYmoK - NDAgMCBvYmoKPDwgL0xlbmd0aCA0MSAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUg - L0ltYWdlIC9XaWR0aCAyNDIgL0hlaWdodCAxNzAgL0NvbG9yU3BhY2UKL0RldmljZUdy - YXkgL0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJl - YW0KeAHtnf9PU9cbx/lS6Lfb215ob8ttu5ZbCr0tpbsCVkAHBIIi4BcUVzchaNUMBnYa - G5uhDsOU2CiCg/AlioyIBhwBQ5AQNZ9/7fOcYrZRim6/9azP+wfiTTB5Xuf9nPc5vSR9 - srJQuAK4ArgCuAL0rkA21fpX6w6kOX8plzL9VXkOgPwD8B1aoFQo8iiWQgEIBP5L0Ane - Hdh8pVK1IzVF+lSyUpkPdgH2F5g/8ebl5QOsWqPRarUMw+ioEhQMZWs0apWKUH+emQDn - Qi8DLsAyOpbVGwwcdTIY9CyrA24NQO8w79PaCWDwl/DqWD3HFRQajSYTz5spEs+bTEZj - YQHH6VkdYQafobVTIxOHicGE1wC0vNlSJAhWm81OkWw2qyAUWcw8UBsSzGAzQU4R2glg - 2MBaBngBF1jtDqezWHRRJbHY6XTYgRuggZnRku2cGjmb7GGlGgzmCnmLALSiy11a5pEk - r9dHibxeSfKUlbpdIlALFr6QA5vVSpJfe00GiwFYpdXpOaNZsDvFklLJW+4PBGRZPkCN - oNhAwF/ulUpLRKddMBs5vQ5czlOk6GuwGEJLkwC2OkS3x+cPyJXVB4M1taA6KkQqrQke - rK6UA36fxy06rAlkDcRXCpOzwWKVhmE5o8XqcJX5KuSqYE3dkfqGxqampmZKBKU2NtQf - qasJVskVvjKXw2oxciyjUYHJyW29Y7EWgM1WZ4nkl6sO1dU3Nrcca21r7zhBjTra21qP - tTQ31tcdqpL9UomTuMxqU5lMiKGnDQDsKJEClcHDDU1Hj3ec7DzTdS5Ekc51nek82XH8 - aFPD4WBlQCohjW3Qgcl72hqaOl+lZQt4weGSKqpq65tb20+fDX3f3dN7KRy+TInC4Uu9 - Pd3fh86ebm9trq+tqpBcDoEvICbvaevsHDiZwGKLXSzzV9Y2tLSd6jrf3Ru+2vfjwOC1 - CCW6NjjwY9/VcG/3+a5TbS0NtZX+MtFuAZPhhEreyKSpYRfzgtPtk4P1Le2doQsXr/QN - RG7cjN6KUaNb0Zs3IgN9Vy5eCHW2t9QHZZ/bKfBkJ0Nb7752JYj1hWa76KmoOtwMwD3h - vsHr0djQnbvD96jR8N07Q7Ho9cG+cA8gNx+uqvCIdnOhPiVxvpoxGIscJT75UEPrqVDP - 5f5INHZneOT+6MM4NXo4en9k+E4sGum/3BM61dpwSPaVOIqMBkadv8djRb5aR5q61F9V - 19TRdSHc/1N0aPjX0fjjJ+NPqdH4k8fx0V+Hh6I/9YcvdHU01VX5S0lb69QQXUldrVBq - 2AKzTfQEgt8cPX3+4g+R6NC9B/GxicmpmZlZSjQzMzU5MRZ/cG8oGvnh4vnTR78JBjyi - zVzAapQpiLUsbGOXV65pPH62+8oAAI8+Gp+cnns2/2KBEr2YfzY3PTn+aBSQB650nz3e - WCN7XbCRWW0KYohqY9FX7vJKaOpQb9/12C8PHk1MzT5fWHy59IoSLb1cXHg+OzXx6MEv - set9vSFo68py91dFRgjrPR7D4aQ3km1cfaTl5Hfhgejtkfj41Nz870uvl1feUKKV5ddL - v8/PTY3HR25HB8LfnWw5Uk02spGEdfI+BmIDEJcFgvXHOruvRmLDo2OTs/OLr1berK6t - U6K11TcrrxbnZyfHRodjkavdncfqg4EyIDakJGYMJqEYgquh9UxP342fR+IT088BeHX9 - 7QY1eru+CsjPpyfiIz/f6Os509oA0VUsmAxMKo8ZzmQVpa9rGtu6evtv3r7/+Le5haXl - 1fWNzXdblOjd5sb66vLSwtxvj+/fvtnf29XWWPO1JFpN3D7EvE2U5Nqm9nOXBqJ3R8em - ni2+/mNtY3NrmxptbW6s/fF68dnU2Ojd6MClc+1NtbIk2vj9ieFwAuJvw4O3hh8+mZ5/ - ubz6FoDff6BE77e3Nt+uLr+cn37ycPjWYPhbQux1fZG4IxS+FrsXn5h5sbSytvEOgD9S - og/vt99trK0svZiZiN+LXQvD8bQfMXxYVDEcb0t4nIL4f1To4+eJd733yc7Ng2s1XLl8 - B+qaT4QuR8Djp7MLr96sb2xtf/hIBS8U+fHD9tbG+ptXC7NPwePI5dCJ5roDPrh0wcU6 - LxeJ0WPsahr2Mu5jTK6/vQXB0wnPYxpiC28geOfCWyZ+ksDPTlSkNd4y8ZaJt0x864Pv - udI/rjGrMasxqzGrMasxq9NvBfB0wtMJTyc8nfB0Sr9sTq4IsxqzGrMasxqzOjkZ0+8Z - sxqzGrMasxqzOv2yObkizGrMasxqzGrM6uRkTL9nzGrMasxqzGrM6vTL5uSKMKsxqzGr - Masxq5OTMf2eMasxqzGrMasxq9Mvm5MrwqzGrMasxqzGrE5OxvR7xqzGrMasxqzGrE6/ - bE6uCLMasxqzGrMaszo5GdPvGbMasxqzGrP6v53VGfdtzllfIP7vfWP3LuKM+lb2TPvm - /YybrpBxEzQyb0pKpk3CUWTctCOFMuMmWmXe1LKMm0yXm3HTB8lMzQybMJlpU0Qzb1Js - Jk4DzryJz2RweyZN9c7KuMntQExM1uj0ZHa7Q3R7fP6AXFl9MFhDZt7XUSFSaU3wYHWl - HPD7PG6RDDHn9DDFPH/vGPMsIM5R5ClV2gSyYHeKJaWSt9wfCMiyfIAaQbGBgL/cK5WW - iE67kADWqpR5ipzkod7wsh5MBmS1VsdyhbxFsDucostdWuaRJK/XR4m8XknylJW6XaLT - YRcsfCHH6rQww1yxZ1I9+esEmAx9DS4zrKHAyJsFqw2oncWiiyqJxU6gtVkFM28sMLAM - OEx6OoXFn5ChsTVgs6GgEKAtRQJw2+wUyQasQpEFcAuBV6fVQEvvB5yVnXAZ4ivBrOc4 - oDaaTDxvpkg8bzIZgZbj9AleCK0E8K7Jg3/+wS2BrMgDm4FZy+hYVm8wcNTJYNCzrI7R - gr/EYNjDOdmpgaGvwWWSX2Q7q9QawNYyDKOjSlAwlK3RqAEX/CW8+wOT+NphBmigBuyE - 1BTpU8lKQpun+CJvIrIJc05ubq6CYFMrgM0l9n7W37/t5wQ1+X0Q/E+qtFN14mf2vvv3 - T9Zd/4Dfp1i7UPABVwBXAFcAV4CyFfg/bog27wplbmRzdHJlYW0KZW5kb2JqCjQxIDAg - b2JqCjIzMjAKZW5kb2JqCjMxIDAgb2JqCjw8IC9MZW5ndGggMzIgMCBSIC9UeXBlIC9Y - T2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMjYwIC9IZWlnaHQgMjYwIC9Db2xv - clNwYWNlCi9EZXZpY2VHcmF5IC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxh - dGVEZWNvZGUgPj4Kc3RyZWFtCngB7d3/U1JZFADwvijyTURFVJKVomxxILQwU7I0Gr+3 - Wg4jfTOcMqNGLR1aR8sp1Cmx8kvluOZoTuygmWnqqG27s//anvuwTBcUFd6798L5JQ1K - +Hjuue894Jw9e8IRFggLhAXCAmGBsEBYICyAkcBeFPsgmC8wemAsPZTVZw8A+/cjBgj4 - K5Z+OBY/xvPr378/IiIiEgL+8EiEkAJaAAAAz57Hi4Lg8RAEwxAiqYCSAAHwovh8vkAg - FAoE8EUUOETAsgiJVGAIGAGBUCQSR0OIRSKhgFEIDQQggCTg8flCkVgiiZHGQkhjJBKx - SMjn81AqUJ8JHoIoEIiWSGPjZLIECJksLlYqiQaFqBBAWCUQQA5I42QJiUkKJpISE2Rx - UsgFAf0IHgK+QIQE5EmKFGWqCiJVmaJIkiMFkYBPeSasEghFkth4edIBpeqQ+kgaxBH1 - IZXyQJI8PlYC64FqhO8EYkmsLFGhVKnTNOla3bFjOm26Jk2tUioSZbESMdUIPwhi4hKS - U5CAVp95wpCVZTiRqdcihZTkhLgYmhF+IpArlAfTNLpMQ3auMQ/CmJttyNRp0g4qFXKa - EdYI4uWKX9RHtRmGU8az584XQpw/d9Z4ypChPar+RSGPpzYTfiJIVKSqNbrj2cZ8U1Fp - eQVEeWmRKd+YfVynUacqEmlFWE9wWKM35JwxFZdXVpktEOaqyvJi05kcg15zmFqEdQQq - RJCbX1hWabZcq7HW1lprrlnMlWWF+bkIQUVnJmwgSNdnGQuKL1RZrtfeqrfdvWurv1V7 - 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 - 1lyzmCvLCvNzYd4oedcO/SPYgJB6GBByzpiKyyurzBYIc1VlebHpTA4iSCXt8qm/BBsR - 1Brd8WxjvqmotLwCory0yJRvzD6u06gpJliHIIfJyUe1GYZTxrPnzhdCnD931njKkKE9 - CtOH5WRdRPc/C9A91wojTNBWHkzT6DIN2bnGPAhjbrYhU6dJO6hkRnET9DrC9gjWISQk - p6jUaRqtPvOEISvLcCJTr9WkqVUpyQlrI9lxfXF9u097/f1/ZAJM0U5UKJFCulZ37JhO - m44ElIpEmEBN0qtJ65+ef999R4BR4vHypANK1SH1kTSII+pDKuWBJHk8zF6meCF4kFYR - BCKJNE4mT1KkKFNVEKnKFEWSXBYnhYn0eL/LxL/f9eb38iBECURipJCQmKRgIikxAQmI - RWgMOcZvtNn8yfl76yoCXyiKlkhj42SyBAiZLC5WKomGdRAKBN93Bx4fFMQSSYw0FkIa - I4EcEPL5vBDIApQtkAkwJTGSF8UXCEUicTSEWCQSCvhRvEgYw47vO878TXV/7scgRDAK - fL5AIBQKBHw+IwClIDQIUCrsg1SAsS/gwIuC4EEGwCoAAW/Ddv1xJfA+KBUYhggEERkR - 4QEImSTw/Mr2ehgYCeQBAX9F4K9zlw8ZnrRHgvlil/9Z+J+HBcICYYGwQFggLBAWCAsE - VuA/SCo8XAplbmRzdHJlYW0KZW5kb2JqCjMyIDAgb2JqCjM3MTEKZW5kb2JqCjI5IDAg - b2JqCjw8IC9MZW5ndGggMzAgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFn - ZSAvV2lkdGggMjQyIC9IZWlnaHQgMTcwIC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5IC9C - aXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB - 7Z3/T1PXG8f5Uui329teaG/LbbuWWwq9LaW7AlZABwSCIuAXFFc3IWjVDAZ2GhuboQ7D - lNgogoPwJYqMiAYcAUOQEDWff+3znGK2UYpuv/Wsz/sH4k0weV7n/Zz3Ob0kfbKyULgC - uAK4ArgC9K5ANtX6V+sOpDl/KZcy/VV5DoD8A/AdWqBUKPIolkIBCAT+S9AJ3h3YfKVS - tSM1RfpUslKZD3YB9heYP/Hm5eUDrFqj0Wq1DMPoqBIUDGVrNGqVilB/npkA50IvAy7A - MjqW1RsMHHUyGPQsqwNuDUDvMO/T2glg8Jfw6lg9xxUUGo0mE8+bKRLPm0xGY2EBx+lZ - HWEGn6G1UyMTh4nBhNcAtLzZUiQIVpvNTpFsNqsgFFnMPFAbEsxgM0FOEdoJYNjAWgZ4 - ARdY7Q6ns1h0USWx2Ol02IEboIGZ0ZLtnBo5m+xhpRoM5gp5iwC0ostdWuaRJK/XR4m8 - XknylJW6XSJQCxa+kAOb1UqSX3tNBosBWKXV6TmjWbA7xZJSyVvuDwRkWT5AjaDYQMBf - 7pVKS0SnXTAbOb0OXM5TpOhrsBhCS5MAtjpEt8fnD8iV1QeDNbWgOipEKq0JHqyulAN+ - n8ctOqwJZA3EVwqTs8FilYZhOaPF6nCV+SrkqmBN3ZH6hsampqZmSgSlNjbUH6mrCVbJ - Fb4yl8NqMXIso1GBycltvWOxFoDNVmeJ5JerDtXVNza3HGtta+84QY062ttaj7U0N9bX - HaqS/VKJk7jMalOZTIihpw0A7CiRApXBww1NR493nOw803UuRJHOdZ3pPNlx/GhTw+Fg - ZUAqIY1t0IHJe9oamjpfpWULeMHhkiqqauubW9tPnw19393TeykcvkyJwuFLvT3d34fO - nm5vba6vraqQXA6BLyAm72nr7Bw4mcBii10s81fWNrS0neo6390bvtr348DgtQglujY4 - 8GPf1XBv9/muU20tDbWV/jLRbgGT4YRK3sikqWEX84LT7ZOD9S3tnaELF6/0DURu3Ize - ilGjW9GbNyIDfVcuXgh1trfUB2Wf2ynwZCdDW+++diWI9YVmu+ipqDrcDMA94b7B69HY - 0J27w/eo0fDdO0Ox6PXBvnAPIDcfrqrwiHZzoT4lcb6aMRiLHCU++VBD66lQz+X+SDR2 - Z3jk/ujDODV6OHp/ZPhOLBrpv9wTOtXacEj2lTiKjAZGnb/HY0W+WkeautRfVdfU0XUh - 3P9TdGj419H44yfjT6nR+JPH8dFfh4eiP/WHL3R1NNVV+UtJW+vUEF1JXa1QatgCs030 - BILfHD19/uIPkejQvQfxsYnJqZmZWUo0MzM1OTEWf3BvKBr54eL500e/CQY8os1cwGqU - KYi1LGxjl1euaTx+tvvKAACPPhqfnJ57Nv9igRK9mH82Nz05/mgUkAeudJ893lgje12w - kVltCmKIamPRV+7ySmjqUG/f9dgvDx5NTM0+X1h8ufSKEi29XFx4Pjs18ejBL7Hrfb0h - aOvKcvdXRUYI6z0ew+GkN5JtXH2k5eR34YHo7ZH4+NTc/O9Lr5dX3lCileXXS7/Pz02N - x0duRwfC351sOVJNNrKRhHXyPgZiAxCXBYL1xzq7r0Ziw6Njk7Pzi69W3qyurVOitdU3 - K68W52cnx0aHY5Gr3Z3H6oOBMiA2pCRmDCahGIKrofVMT9+Nn0fiE9PPAXh1/e0GNXq7 - vgrIz6cn4iM/3+jrOdPaANFVLJgMTCqPGc5kFaWvaxrbunr7b96+//i3uYWl5dX1jc13 - W5To3ebG+ury0sLcb4/v377Z39vV1ljztSRaTdw+xLxNlOTapvZzlwaid0fHpp4tvv5j - bWNza5sabW1urP3xevHZ1Njo3ejApXPtTbWyJNr4/YnhcALib8ODt4YfPpmef7m8+haA - 33+gRO+3tzbfri6/nJ9+8nD41mD4W0LsdX2RuCMUvha7F5+YebG0srbxDoA/UqIP77ff - baytLL2YmYjfi10Lw/G0HzF8WFQxHG9LeJyC+H9U6OPniXe998nOzYNrNVy5fAfqmk+E - LkfA46ezC6/erG9sbX/4SAUvFPnxw/bWxvqbVwuzT8HjyOXQiea6Az64dMHFOi8XidFj - 7Goa9jLuY0yuv70FwdMJz2MaYgtvIHjnwlsmfpLAz05UpDXeMvGWibdMfOuD77nSP64x - qzGrMasxqzGrMavTbwXwdMLTCU8nPJ3wdEq/bE6uCLMasxqzGrMaszo5GdPvGbMasxqz - GrMaszr9sjm5IsxqzGrMasxqzOrkZEy/Z8xqzGrMasxqzOr0y+bkijCrMasxqzGrMauT - kzH9njGrMasxqzGrMavTL5uTK8KsxqzGrMasxqxOTsb0e8asxqzGrMasxqxOv2xOrgiz - GrMasxqzGrM6ORnT7xmzGrMasxqz+r+d1Rn3bc5ZXyD+731j9y7ijPpW9kz75v2Mm66Q - cRM0Mm9KSqZNwlFk3LQjhTLjJlpl3tSyjJtMl5tx0wfJTM0MmzCZaVNEM29SbCZOA868 - ic9kcHsmTfXOyrjJ7UBMTNbo9GR2u0N0e3z+gFxZfTBYQ2be11EhUmlN8GB1pRzw+zxu - kQwx5/QwxTx/7xjzLCDOUeQpVdoEsmB3iiWlkrfcHwjIsnyAGkGxgYC/3CuVlohOu5AA - 1qqUeYqc5KHe8LIeTAZktVbHcoW8RbA7nKLLXVrmkSSv10eJvF5J8pSVul2i02EXLHwh - x+q0MMNcsWdSPfnrBJgMfQ0uM6yhwMibBasNqJ3FoosqicVOoLVZBTNvLDCwDDhMejqF - xZ+QobE1YLOhoBCgLUUCcNvsFMkGrEKRBXALgVen1UBL7weclZ1wGeIrwaznOKA2mkw8 - b6ZIPG8yGYGW4/QJXgitBPCuyYN//sEtgazIA5uBWcvoWFZvMHDUyWDQs6yO0YK/xGDY - wznZqYGhr8Flkl9kO6vUGsDWMgyjo0pQMJSt0agBF/wlvPsDk/jaYQZooAbshNQU6VPJ - SkKbp/gibyKyCXNObm6ugmBTK4DNJfZ+1t+/7ecENfl9EPxPqrRTdeJn9r7790/WXf+A - 36dYu1DwAVcAVwBXAFeAshX4P26INu8KZW5kc3RyZWFtCmVuZG9iagozMCAwIG9iagoy - MzIwCmVuZG9iagozOCAwIG9iago8PCAvTGVuZ3RoIDM5IDAgUiAvVHlwZSAvWE9iamVj - dCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRoIDI0MiAvSGVpZ2h0IDE3MCAvQ29sb3JTcGFj - ZQovRGV2aWNlR3JheSAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIgL0ZsYXRlRGVj - b2RlID4+CnN0cmVhbQp4Ae2d/09T1xvH+VLot9vbXmhvy227llsKvS2luwJWQAcEgiLg - FxRXNyFo1QwGdhobm6EOw5TYKIKD8CWKjIgGHAFDkBA1n3/t85xitlGKbr/1rM/7B+JN - MHle5/2c9zm9JH2yslC4ArgCuAK4AvSuQDbV+lfrDqQ5fymXMv1VeQ6A/APwHVqgVCjy - KJZCAQgE/kvQCd4d2HylUrUjNUX6VLJSmQ92AfYXmD/x5uXlA6xao9FqtQzD6KgSFAxl - azRqlYpQf56ZAOdCLwMuwDI6ltUbDBx1Mhj0LKsDbg1A7zDv09oJYPCX8OpYPccVFBqN - JhPPmykSz5tMRmNhAcfpWR1hBp+htVMjE4eJwYTXALS82VIkCFabzU6RbDarIBRZzDxQ - GxLMYDNBThHaCWDYwFoGeAEXWO0Op7NYdFElsdjpdNiBG6CBmdGS7ZwaOZvsYaUaDOYK - eYsAtKLLXVrmkSSv10eJvF5J8pSVul0iUAsWvpADm9VKkl97TQaLAVil1ek5o1mwO8WS - Uslb7g8EZFk+QI2g2EDAX+6VSktEp10wGzm9DlzOU6Toa7AYQkuTALY6RLfH5w/IldUH - gzW1oDoqRCqtCR6srpQDfp/HLTqsCWQNxFcKk7PBYpWGYTmjxepwlfkq5KpgTd2R+obG - pqamZkoEpTY21B+pqwlWyRW+MpfDajFyLKNRgcnJbb1jsRaAzVZnieSXqw7V1Tc2txxr - bWvvOEGNOtrbWo+1NDfW1x2qkv1SiZO4zGpTmUyIoacNAOwokQKVwcMNTUePd5zsPNN1 - LkSRznWd6TzZcfxoU8PhYGVAKiGNbdCByXvaGpo6X6VlC3jB4ZIqqmrrm1vbT58Nfd/d - 03spHL5MicLhS7093d+Hzp5ub22ur62qkFwOgS8gJu9p6+wcOJnAYotdLPNX1ja0tJ3q - Ot/dG77a9+PA4LUIJbo2OPBj39Vwb/f5rlNtLQ21lf4y0W4Bk+GESt7IpKlhF/OC0+2T - g/Ut7Z2hCxev9A1EbtyM3opRo1vRmzciA31XLl4Idba31Adln9sp8GQnQ1vvvnYliPWF - Zrvoqag63AzAPeG+wevR2NCdu8P3qNHw3TtDsej1wb5wDyA3H66q8Ih2c6E+JXG+mjEY - ixwlPvlQQ+upUM/l/kg0dmd45P7owzg1ejh6f2T4Tiwa6b/cEzrV2nBI9pU4iowGRp2/ - x2NFvlpHmrrUX1XX1NF1Idz/U3Ro+NfR+OMn40+p0fiTx/HRX4eHoj/1hy90dTTVVflL - SVvr1BBdSV2tUGrYArNN9ASC3xw9ff7iD5Ho0L0H8bGJyamZmVlKNDMzNTkxFn9wbyga - +eHi+dNHvwkGPKLNXMBqlCmItSxsY5dXrmk8frb7ygAAjz4an5yeezb/YoESvZh/Njc9 - Of5oFJAHrnSfPd5YI3tdsJFZbQpiiGpj0Vfu8kpo6lBv3/XYLw8eTUzNPl9YfLn0ihIt - vVxceD47NfHowS+x6329IWjrynL3V0VGCOs9HsPhpDeSbVx9pOXkd+GB6O2R+PjU3Pzv - S6+XV95QopXl10u/z89NjcdHbkcHwt+dbDlSTTaykYR18j4GYgMQlwWC9cc6u69GYsOj - Y5Oz84uvVt6srq1TorXVNyuvFudnJ8dGh2ORq92dx+qDgTIgNqQkZgwmoRiCq6H1TE/f - jZ9H4hPTzwF4df3tBjV6u74KyM+nJ+IjP9/o6znT2gDRVSyYDEwqjxnOZBWlr2sa27p6 - +2/evv/4t7mFpeXV9Y3Nd1uU6N3mxvrq8tLC3G+P79++2d/b1dZY87UkWk3cPsS8TZTk - 2qb2c5cGondHx6aeLb7+Y21jc2ubGm1tbqz98Xrx2dTY6N3owKVz7U21siTa+P2J4XAC - 4m/Dg7eGHz6Znn+5vPoWgN9/oETvt7c2364uv5yffvJw+NZg+FtC7HV9kbgjFL4Wuxef - mHmxtLK28Q6AP1KiD++3322srSy9mJmI34tdC8PxtB8xfFhUMRxvS3icgvh/VOjj54l3 - vffJzs2DazVcuXwH6ppPhC5HwOOnswuv3qxvbG1/+EgFLxT58cP21sb6m1cLs0/B48jl - 0InmugM+uHTBxTovF4nRY+xqGvYy7mNMrr+9BcHTCc9jGmILbyB458JbJn6SwM9OVKQ1 - 3jLxlom3THzrg++50j+uMasxqzGrMasxqzGr028F8HTC0wlPJzyd8HRKv2xOrgizGrMa - sxqzGrM6ORnT7xmzGrMasxqzGrM6/bI5uSLMasxqzGrMaszq5GRMv2fMasxqzGrMaszq - 9Mvm5IowqzGrMasxqzGrk5Mx/Z4xqzGrMasxqzGr0y+bkyvCrMasxqzGrMasTk7G9HvG - rMasxqzGrMasTr9sTq4IsxqzGrMasxqzOjkZ0+8ZsxqzGrMas/q/ndUZ923OWV8g/u99 - Y/cu4oz6VvZM++b9jJuukHETNDJvSkqmTcJRZNy0I4Uy4yZaZd7UsoybTJebcdMHyUzN - DJswmWlTRDNvUmwmTgPOvInPZHB7Jk31zsq4ye1ATEzW6PRkdrtDdHt8/oBcWX0wWENm - 3tdRIVJpTfBgdaUc8Ps8bpEMMef0MMU8f+8Y8ywgzlHkKVXaBLJgd4olpZK33B8IyLJ8 - gBpBsYGAv9wrlZaITruQANaqlHmKnOSh3vCyHkwGZLVWx3KFvEWwO5yiy11a5pEkr9dH - ibxeSfKUlbpdotNhFyx8IcfqtDDDXLFnUj356wSYDH0NLjOsocDImwWrDaidxaKLKonF - TqC1WQUzbywwsAw4THo6hcWfkKGxNWCzoaAQoC1FAnDb7BTJBqxCkQVwC4FXp9VAS+8H - nJWdcBniK8Gs5zigNppMPG+mSDxvMhmBluP0CV4IrQTwrsmDf/7BLYGsyAObgVnL6FhW - bzBw1Mlg0LOsjtGCv8Rg2MM52amBoa/BZZJfZDur1BrA1jIMo6NKUDCUrdGoARf8Jbz7 - A5P42mEGaKAG7ITUFOlTyUpCm6f4Im8isglzTm5uroJgUyuAzSX2ftbfv+3nBDX5fRD8 - T6q0U3XiZ/a++/dP1l3/gN+nWLtQ8AFXAFcAVwBXgLIV+D9uiDbvCmVuZHN0cmVhbQpl - bmRvYmoKMzkgMCBvYmoKMjMyMAplbmRvYmoKMzMgMCBvYmoKPDwgL0xlbmd0aCAzNCAw - IFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUgL0ltYWdlIC9XaWR0aCAyNDIgL0hlaWdo - dCAxNzAgL0NvbG9yU3BhY2UKL0RldmljZUdyYXkgL0JpdHNQZXJDb21wb25lbnQgOCAv - RmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAHtnf9PU9cbx/lS6Lfb215ob8tt - u5ZbCr0tpbsCVkAHBIIi4BcUVzchaNUMBnYaG5uhDsOU2CiCg/AlioyIBhwBQ5AQNZ9/ - 7fOcYrZRim6/9azP+wfiTTB5Xuf9nPc5vSR9srJQuAK4ArgCuAL0rkA21fpX6w6kOX8p - lzL9VXkOgPwD8B1aoFQo8iiWQgEIBP5L0AneHdh8pVK1IzVF+lSyUpkPdgH2F5g/8ebl - 5QOsWqPRarUMw+ioEhQMZWs0apWKUH+emQDnQi8DLsAyOpbVGwwcdTIY9CyrA24NQO8w - 79PaCWDwl/DqWD3HFRQajSYTz5spEs+bTEZjYQHH6VkdYQafobVTIxOHicGE1wC0vNlS - JAhWm81OkWw2qyAUWcw8UBsSzGAzQU4R2glg2MBaBngBF1jtDqezWHRRJbHY6XTYgRug - gZnRku2cGjmb7GGlGgzmCnmLALSiy11a5pEkr9dHibxeSfKUlbpdIlALFr6QA5vVSpJf - e00GiwFYpdXpOaNZsDvFklLJW+4PBGRZPkCNoNhAwF/ulUpLRKddMBs5vQ5czlOk6Guw - GEJLkwC2OkS3x+cPyJXVB4M1taA6KkQqrQkerK6UA36fxy06rAlkDcRXCpOzwWKVhmE5 - o8XqcJX5KuSqYE3dkfqGxqampmZKBKU2NtQfqasJVskVvjKXw2oxciyjUYHJyW29Y7EW - gM1WZ4nkl6sO1dU3Nrcca21r7zhBjTra21qPtTQ31tcdqpL9UomTuMxqU5lMiKGnDQDs - KJEClcHDDU1Hj3ec7DzTdS5Ekc51nek82XH8aFPD4WBlQCohjW3Qgcl72hqaOl+lZQt4 - weGSKqpq65tb20+fDX3f3dN7KRy+TInC4Uu9Pd3fh86ebm9trq+tqpBcDoEvICbvaevs - HDiZwGKLXSzzV9Y2tLSd6jrf3Ru+2vfjwOC1CCW6NjjwY9/VcG/3+a5TbS0NtZX+MtFu - AZPhhEreyKSpYRfzgtPtk4P1Le2doQsXr/QNRG7cjN6KUaNb0Zs3IgN9Vy5eCHW2t9QH - ZZ/bKfBkJ0Nb7752JYj1hWa76KmoOtwMwD3hvsHr0djQnbvD96jR8N07Q7Ho9cG+cA8g - Nx+uqvCIdnOhPiVxvpoxGIscJT75UEPrqVDP5f5INHZneOT+6MM4NXo4en9k+E4sGum/ - 3BM61dpwSPaVOIqMBkadv8djRb5aR5q61F9V19TRdSHc/1N0aPjX0fjjJ+NPqdH4k8fx - 0V+Hh6I/9YcvdHU01VX5S0lb69QQXUldrVBq2AKzTfQEgt8cPX3+4g+R6NC9B/Gxicmp - mZlZSjQzMzU5MRZ/cG8oGvnh4vnTR78JBjyizVzAapQpiLUsbGOXV65pPH62+8oAAI8+ - Gp+cnns2/2KBEr2YfzY3PTn+aBSQB650nz3eWCN7XbCRWW0KYohqY9FX7vJKaOpQb9/1 - 2C8PHk1MzT5fWHy59IoSLb1cXHg+OzXx6MEvset9vSFo68py91dFRgjrPR7D4aQ3km1c - faTl5Hfhgejtkfj41Nz870uvl1feUKKV5ddLv8/PTY3HR25HB8LfnWw5Uk02spGEdfI+ - BmIDEJcFgvXHOruvRmLDo2OTs/OLr1berK6tU6K11TcrrxbnZyfHRodjkavdncfqg4Ey - IDakJGYMJqEYgquh9UxP342fR+IT088BeHX97QY1eru+CsjPpyfiIz/f6Os509oA0VUs - mAxMKo8ZzmQVpa9rGtu6evtv3r7/+Le5haXl1fWNzXdblOjd5sb66vLSwtxvj+/fvtnf - 29XWWPO1JFpN3D7EvE2U5Nqm9nOXBqJ3R8emni2+/mNtY3NrmxptbW6s/fF68dnU2Ojd - 6MClc+1NtbIk2vj9ieFwAuJvw4O3hh8+mZ5/ubz6FoDff6BE77e3Nt+uLr+cn37ycPjW - YPhbQux1fZG4IxS+FrsXn5h5sbSytvEOgD9Sog/vt99trK0svZiZiN+LXQvD8bQfMXxY - VDEcb0t4nIL4f1To4+eJd733yc7Ng2s1XLl8B+qaT4QuR8Djp7MLr96sb2xtf/hIBS8U - +fHD9tbG+ptXC7NPwePI5dCJ5roDPrh0wcU6LxeJ0WPsahr2Mu5jTK6/vQXB0wnPYxpi - C28geOfCWyZ+ksDPTlSkNd4y8ZaJt0x864PvudI/rjGrMasxqzGrMasxq9NvBfB0wtMJ - Tyc8nfB0Sr9sTq4IsxqzGrMasxqzOjkZ0+8ZsxqzGrMasxqzOv2yObkizGrMasxqzGrM - 6uRkTL9nzGrMasxqzGrM6vTL5uSKMKsxqzGrMasxq5OTMf2eMasxqzGrMasxq9Mvm5Mr - wqzGrMasxqzGrE5OxvR7xqzGrMasxqzGrE6/bE6uCLMasxqzGrMaszo5GdPvGbMasxqz - GrP6v53VGfdtzllfIP7vfWP3LuKM+lb2TPvm/YybrpBxEzQyb0pKpk3CUWTctCOFMuMm - WmXe1LKMm0yXm3HTB8lMzQybMJlpU0Qzb1JsJk4DzryJz2RweyZN9c7KuMntQExM1uj0 - ZHa7Q3R7fP6AXFl9MFhDZt7XUSFSaU3wYHWlHPD7PG6RDDHn9DDFPH/vGPMsIM5R5ClV - 2gSyYHeKJaWSt9wfCMiyfIAaQbGBgL/cK5WWiE67kADWqpR5ipzkod7wsh5MBmS1Vsdy - hbxFsDucostdWuaRJK/XR4m8XknylJW6XaLTYRcsfCHH6rQww1yxZ1I9+esEmAx9DS4z - rKHAyJsFqw2oncWiiyqJxU6gtVkFM28sMLAMOEx6OoXFn5ChsTVgs6GgEKAtRQJw2+wU - yQasQpEFcAuBV6fVQEvvB5yVnXAZ4ivBrOc4oDaaTDxvpkg8bzIZgZbj9AleCK0E8K7J - g3/+wS2BrMgDm4FZy+hYVm8wcNTJYNCzrI7Rgr/EYNjDOdmpgaGvwWWSX2Q7q9QawNYy - DKOjSlAwlK3RqAEX/CW8+wOT+NphBmigBuyE1BTpU8lKQpun+CJvIrIJc05ubq6CYFMr - gM0l9n7W37/t5wQ1+X0Q/E+qtFN14mf2vvv3T9Zd/4Dfp1i7UPABVwBXAFcAV4CyFfg/ - bog27wplbmRzdHJlYW0KZW5kb2JqCjM0IDAgb2JqCjIzMjAKZW5kb2JqCjI2IDAgb2Jq - Cjw8IC9MZW5ndGggMjcgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAv - V2lkdGggMjYwIC9IZWlnaHQgMjYwIC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5IC9CaXRz - UGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7d3/ - U1JZFADwvijyTURFVJKVomxxILQwU7I0Gr+3Wg4jfTOcMqNGLR1aR8sp1Cmx8kvluOZo - TuygmWnqqG27s//anvuwTBcUFd6798L5JQ1K+Hjuue894Jw9e8IRFggLhAXCAmGBsEBY - ICyAkcBeFPsgmC8wemAsPZTVZw8A+/cjBgj4K5Z+OBY/xvPr378/IiIiEgL+8EiEkAJa - AAAAz57Hi4Lg8RAEwxAiqYCSAAHwovh8vkAgFAoE8EUUOETAsgiJVGAIGAGBUCQSR0OI - RSKhgFEIDQQggCTg8flCkVgiiZHGQkhjJBKxSMjn81AqUJ8JHoIoEIiWSGPjZLIECJks - LlYqiQaFqBBAWCUQQA5I42QJiUkKJpISE2RxUsgFAf0IHgK+QIQE5EmKFGWqCiJVmaJI - kiMFkYBPeSasEghFkth4edIBpeqQ+kgaxBH1IZXyQJI8PlYC64FqhO8EYkmsLFGhVKnT - NOla3bFjOm26Jk2tUioSZbESMdUIPwhi4hKSU5CAVp95wpCVZTiRqdcihZTkhLgYmhF+ - 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 - N8LthpbWDkf3c2dvr/N5t6OjtaXhNqUE3hFKL1pu1N17YG/reOro6nI87WizP7hXd8Ny - sZTQ6wW+F4LnFm+HzSWV1TU3bY3N9ta29va2Vntzo+1mTXVlCaUE3jLhtKmkwnzVWmdr - uN/c0tJ8v8FWZ71qrigxnSbyqtFWWYBu35gJ+ixjQfGFKsv12lv1trt3bfW3aq9bqi4U - Fxiz9AReOPOH4H8IMCc1N7+wrNJsuVZjra211lyzmCvLCvNzYd4oedcO/SPYgJB6GBBy - zpiKyyurzBYIc1VlebHpTA4iSCXt8qm/BBsR1Brd8WxjvqmotLwCory0yJRvzD6u06gp - JliHIIfJyUe1GYZTxrPnzhdCnD931njKkKE9CtOH5WRdRPc/C9A91wojTNBWHkzT6DIN - 2bnGPAhjbrYhU6dJO6hkRnET9DrC9gjWISQkp6jUaRqtPvOEISvLcCJTr9WkqVUpyQlr - I9lxfXF9u097/f1/ZAJM0U5UKJFCulZ37JhOm44ElIpEmEBN0qtJ65+ef999R4BR4vHy - pANK1SH1kTSII+pDKuWBJHk8zF6meCF4kFYRBCKJNE4mT1KkKFNVEKnKFEWSXBYnhYn0 - eL/LxL/f9eb38iBECURipJCQmKRgIikxAQmIRWgMOcZvtNn8yfl76yoCXyiKlkhj42Sy - BAiZLC5WKomGdRAKBN93Bx4fFMQSSYw0FkIaI4EcEPL5vBDIApQtkAkwJTGSF8UXCEUi - cTSEWCQSCvhRvEgYw47vO878TXV/7scgRDAKfL5AIBQKBHw+IwClIDQIUCrsg1SAsS/g - wIuC4EEGwCoAAW/Ddv1xJfA+KBUYhggEERkR4QEImSTw/Mr2ehgYCeQBAX9F4K9zlw8Z - nrRHgvlil/9Z+J+HBcICYYGwQFggLBAWCAsEVuA/SCo8XAplbmRzdHJlYW0KZW5kb2Jq - CjI3IDAgb2JqCjM3MTEKZW5kb2JqCjM2IDAgb2JqCjw8IC9MZW5ndGggMzcgMCBSIC9U - eXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMjQyIC9IZWlnaHQgMTcw - IC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5IC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRl - 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 - d8WApwNg7RWwTOERxyzfdfIhsJoEigOEEgkxgh7Swj4XFdV0LFWuxucqS770/x56u8uz - 8mOSzwljPbfK+TzHd9PJlwTbvWJGcKO1mBVcry2sCO5r6ZzghrVYELxRW84LVo1yUbDZ - 9u/+71qpoV+1M0NPXytVhN/qFsqCb3dWhv66ujDcm9HOed+Tn7PlZIf7RxEKVJhwYHGW - UUUcc6iADQ3uJVchN83rOEbIvNnWB57yZzjqpn/e6Y65ZbWamiPP86tUo3LWUC5H5Xgs - dg2/AEmasesKZW5kc3RyZWFtCmVuZG9iago0MyAwIG9iago1NjMKZW5kb2JqCjM1IDAg - b2JqClsgL0lDQ0Jhc2VkIDQyIDAgUiBdCmVuZG9iago0NCAwIG9iago8PCAvTGVuZ3Ro - IDQ1IDAgUiAvTiAzIC9BbHRlcm5hdGUgL0RldmljZVJHQiAvRmlsdGVyIC9GbGF0ZURl - Y29kZSA+PgpzdHJlYW0KeAGtkz9oE1Ecx7+XFC1YI7TVQSjcYMEhakg66GSaNC1pJQ35 - 00S39HLJpeYux90ltsEhg6uzgzqIS4eiq8VFEcTFoSiiuDq4dOkgBSnn9+58iYPFxR+8 - e598832/37vfeweED2um2Q4B0A3HKiyl5OrNW/LJLziFKY4ZTNQU25zP52/Qckz8+ATJ - ++vDJS/XpmonIntXHu9v7KbvPS+/OGaRkCMWCwJSlMJ0M+Ckx+sBlzy+45gOPZrHilar - k++So1apkCZvkyPNgL16kfWA33ncU5re2s/kmFFvGUBonHy1rtoKOUnW6raik5lHCul6 - h/nDO9QvKqbFteGP5AteXzgzts4A1x/Q/3qkVd8CO8+Ac/sjbZbeqa/Abm+kHRz6vZJm - vtmNRNxPJ51+Apzou+7BWWCctY/WXPdnynWPWHuMSV7eV7pWz/dyg9J74F+/g3cOsgN7 - zMPwz+jvHPTFd8WApwNg7RWwTOERxyzfdfIhsJoEigOEEgkxgh7Swj4XFdV0LFWuxucq - S770/x56u8uz8mOSzwljPbfK+TzHd9PJlwTbvWJGcKO1mBVcry2sCO5r6ZzghrVYELxR - W84LVo1yUbDZ9u/+71qpoV+1M0NPXytVhN/qFsqCb3dWhv66ujDcm9HOed+Tn7PlZIf7 - RxEKVJhwYHGWUUUcc6iADQ3uJVchN83rOEbIvNnWB57yZzjqpn/e6Y65ZbWamiPP86tU - o3LWUC5H5Xgsdg2/AEmasesKZW5kc3RyZWFtCmVuZG9iago0NSAwIG9iago1NjMKZW5k - b2JqCjI1IDAgb2JqClsgL0lDQ0Jhc2VkIDQ0IDAgUiBdCmVuZG9iago0NiAwIG9iago8 - PCAvTGVuZ3RoIDQ3IDAgUiAvTiAzIC9BbHRlcm5hdGUgL0RldmljZVJHQiAvRmlsdGVy - IC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAGFlE1IFGEYx/+zjQSxBtGXCMXQwSRUJgtS - AtP1K1O2ZdVMCWKdfXedHGenmd0tRSKE6Jh1jC5WRIeITuGhQ6c6RASZdYmgo0UQBV4i - tv87k7tjVL4wM795nv/7fL3DAFWPUo5jRTRgys67yd6Ydnp0TNv8GlWoRhRcKcNzOhKJ - AZ+plc/1a/UtFGlZapSx1vs2fKt2mRBQNCp3ZAM+LHk84OOSL+SdPDVnJBsTqTTZITe4 - Q8lO8i3y1myIx0OcFp4BVLVTkzMcl3EiO8gtRSMrYz4g63batMnvpT3tGVPUsN/INzkL - 2rjy/UDbHmDTi4ptzAMe3AN211Vs9TXAzhFg8VDF9j3pz0fZ9crLHGr2wynRGGv6UCp9 - rwM23wB+Xi+VftwulX7eYQ7W8dQyCm7R17Iw5SUQ1BvsZvzkGv2Lg558VQuwwDmObAH6 - rwA3PwL7HwLbHwOJamCoFZHLbDe48uIi5wJ05pxp18xO5LVmXT+idfBohdZnG00NWsqy - NN/laa7whFsU6SZMWQXO2V/beI8Ke3iQT/YXuSS87t+szKVTXZwlmtjWp7To6iY3kO9n - zJ4+cj2v9xm3Zzhg5YCZ7xsKOHLKtuI8F6mJ1Njj8ZNkxldUJx+T85A85xUHZUzffi51 - IkGupT05meuXml3c2z4zMcQzkqxYMxOd8d/8xi0kZd591Nx1LP+bZ22RZxiFBQETNu82 - NCTRixga4cBFDhl6TCpMWqVf0GrCw+RflRYS5V0WFb1Y4Z4Vf895FLhbxj+FWBxzDeUI - mv5O/6Iv6wv6Xf3zfG2hvuKZc8+axqtrXxlXZpbVyLhBjTK+rCmIb7DaDnotZGmd4hX0 - 5JX1jeHqMvZ8bdmjyRzianw11KUIZWrEOOPJrmX3RbLFN+HnW8v2r+lR+3z2SU0l17K6 - eGYp+nw2XA1r/7OrYNKyq/DkjZAuPGuh7lUPqn1qi9oKTT2mtqttahffjqoD5R3DnJWJ - C6zbZfUp9mBjmt7KSVdmi+Dfwi+G/6VeYQvXNDT5D024uYxpCd8R3DZwh5T/w1+zAw3e - CmVuZHN0cmVhbQplbmRvYmoKNDcgMCBvYmoKNzkyCmVuZG9iago4IDAgb2JqClsgL0lD - Q0Jhc2VkIDQ2IDAgUiBdCmVuZG9iago0OCAwIG9iago8PCAvTGVuZ3RoIDQ5IDAgUiAv - TiAzIC9BbHRlcm5hdGUgL0RldmljZVJHQiAvRmlsdGVyIC9GbGF0ZURlY29kZSA+Pgpz - dHJlYW0KeAGtkz9oE1Ecx7+XFC1YI7TVQSjcYMEhakg66GSaNC1pJQ3500S39HLJpeYu - x90ltsEhg6uzgzqIS4eiq8VFEcTFoSiiuDq4dOkgBSnn9+58iYPFxR+8e598832/37vf - eweED2um2Q4B0A3HKiyl5OrNW/LJLziFKY4ZTNQU25zP52/Qckz8+ATJ++vDJS/Xpmon - IntXHu9v7KbvPS+/OGaRkCMWCwJSlMJ0M+Ckx+sBlzy+45gOPZrHilark++So1apkCZv - kyPNgL16kfWA33ncU5re2s/kmFFvGUBonHy1rtoKOUnW6raik5lHCul6h/nDO9QvKqbF - teGP5AteXzgzts4A1x/Q/3qkVd8CO8+Ac/sjbZbeqa/Abm+kHRz6vZJmvtmNRNxPJ51+ - Apzou+7BWWCctY/WXPdnynWPWHuMSV7eV7pWz/dyg9J74F+/g3cOsgN7zMPwz+jvHPTF - d8WApwNg7RWwTOERxyzfdfIhsJoEigOEEgkxgh7Swj4XFdV0LFWuxucqS770/x56u8uz - 8mOSzwljPbfK+TzHd9PJlwTbvWJGcKO1mBVcry2sCO5r6ZzghrVYELxRW84LVo1yUbDZ - 9u/+71qpoV+1M0NPXytVhN/qFsqCb3dWhv66ujDcm9HOed+Tn7PlZIf7RxEKVJhwYHGW - UUUcc6iADQ3uJVchN83rOEbIvNnWB57yZzjqpn/e6Y65ZbWamiPP86tUo3LWUC5H5Xgs - dg2/AEmasesKZW5kc3RyZWFtCmVuZG9iago0OSAwIG9iago1NjMKZW5kb2JqCjI4IDAg - b2JqClsgL0lDQ0Jhc2VkIDQ4IDAgUiBdCmVuZG9iago1MCAwIG9iago8PCAvTGVuZ3Ro - IDUxIDAgUiAvTiAxIC9BbHRlcm5hdGUgL0RldmljZUdyYXkgL0ZpbHRlciAvRmxhdGVE - ZWNvZGUgPj4Kc3RyZWFtCngBhVJPSBRRHP7NNhKEiEGFeIh3CgmVKaysoNp2dVmVbVuV - 0qIYZ9+6o7Mz05vZNcWTBF2iPHUPomN07NChm5eiwKxL1yCpIAg8dej7zezqKIRveTvf - +/39ft97RG2dpu87KUFUc0OVK6Wnbk5Ni4MfKUUd1E5YphX46WJxjLHruZK/u9fWZ9LY - st7HtXb79j21lWVgIeottrcQ+iGRZgAfmZ8oZYCzwB2Wr9g+ATxYDqwa8COiAw+auTDT - 0Zx0pbItkVPmoigqr2I7Sa77+bnGvou1iYP+XI9m1o69s+qq0UzUtPdEobwPrkQZz19U - 9mw1FKcN45xIQxop8q7V3ytMxxGRKxBKBlI1ZLmfak6ddeB1GLtdupPj+PYQpT7JYKiJ - temymR2FfQB2KsvsEPAF6PGyYg/ngXth/1tRw5PAJ2E/ZId51q0f9heuU+B7hD014M4U - rsXx2oofXi0BQ/dUI2iMc03E09c5c6SI7zHUGZj3RjmmCzF3lqoTN4A7YR9ZqmYKsV37 - ruol7nsCd9PjO9GbOQtcoBxJcrEV2RTQPAlYFH2LsEkOPD7OHlXgd6iYwBy5idzNKPce - 1REbZ6NSgVZ6jVfGT+O58cX4ZWwYz4B+rHbXe3z/6eMVdde2Pjz5jXrcOa69nRtVYVZx - ZQvd/8cyhI/ZJzmmwdOhWVhr2HbkD5rMTLAMKMR/BT6X+pITVdzV7u24RRLMUD4sbCW6 - S1RuKdTqPYNKrBwr2AB2cJLELFocuFNrujl4d9giem35TVey64b++vZ6+9ryHm3KqCko - E82zRGaUsVuj5N142/1mkRGfODq+572KWsn+SUUQP4U5WiryFFX0VlDWxG9nDn4btn5c - P6Xn9UH9PAk9rZ/Rr+ijEb4MdEnPwnNRH6NJ8LBpIeISoIqDM9ROVGONA+Ip8fK0W2SR - /Q9AGf1mCmVuZHN0cmVhbQplbmRvYmoKNTEgMCBvYmoKNzA0CmVuZG9iagoyMyAwIG9i - agpbIC9JQ0NCYXNlZCA1MCAwIFIgXQplbmRvYmoKNCAwIG9iago8PCAvVHlwZSAvUGFn - ZXMgL01lZGlhQm94IFswIDAgNjEyIDc5Ml0gL0NvdW50IDEgL0tpZHMgWyAzIDAgUiBd - ID4+CmVuZG9iago1MiAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvT3V0bGluZXMgMiAw - IFIgL1BhZ2VzIDQgMCBSIC9WZXJzaW9uIC8xLjQgPj4KZW5kb2JqCjIgMCBvYmoKPDwg - L0xhc3QgNTMgMCBSIC9GaXJzdCA1NCAwIFIgPj4KZW5kb2JqCjU0IDAgb2JqCjw8IC9D - b3VudCAwIC9EZXN0IFsgMyAwIFIgL1hZWiAwIDU1MyAwIF0gL1RpdGxlIChDYW52YXMg - MSkgPj4KZW5kb2JqCjUzIDAgb2JqCjw8IC9Db3VudCAwIC9EZXN0IFsgMyAwIFIgL1hZ - WiAwIDU1MyAwIF0gL1RpdGxlIChDYW52YXMgMSkgPj4KZW5kb2JqCjU1IDAgb2JqCjw8 - IC9MZW5ndGggNTYgMCBSIC9MZW5ndGgxIDE0NTA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2Rl - ID4+CnN0cmVhbQp4Ab17eWBVxfX/zN3fvu97Xt6WfSchgTxCFrZEFpUECSZAICAoIEZB - oFGBQEQUkUXAXVnFhBDlAYVSDCLWKlpxwb2Ctbapbb+oLZD7vmfuCxGs3/78o7++++7M - 3Lnz5p45c+aczzl3HsIIISVqRTSKTpvbOO+Nz49+BDWvI4T101oWeh/449DHofwZQvSc - GfNmztV99vJrCLFjEJIrZ85ZNGNeZ+VvENLUIuS/q7mpcfr/PP+XcoRyTkMfBc1QIU/i - hyGUK8B1cvPchXe9wKlnwHUaXD8757ZpjTuf7XoSrkn76+c23jVPeED+T4TykuHae2vj - 3KYJi5rb4Rr6REnzbrt9IeNgH4TrZrheOG9B07xf3ndrNlwDzfSbUIfhIB8lFDmp9G+T - RGOEKJo0YxDL8VJ7Qi58ZEiOFIkipEqVWoOQVjdQAQW9wWgyW6w2O3I4XW6PF/mS/MmB - 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 - u+quNIW44P/js/AOaNBUlkos6/6WebNnSFv7/RVNDbDDv/P+FvirRetUr3ff7HnkBtlT - 3jB1WjPJG5s65/mbyjtn+8u9+1qk3/3o9gxyu8Vfvg/NqLi+dt+MaFN5V0u0pYL8xWH/ - 1LIF9dc8a/XAsxaU/cSzykhnC8izpkq/+9Gz6sntqeRZ9eRZ9eRZU6NTpWcRFlTMmlB2 - +0KQTtj+D9vvwxM6R46bVAv/cqkrj+Ht5D8Bd6D/BVDOTaIKZW5kc3RyZWFtCmVuZG9i - ago1NiAwIG9iagoxMDA3MQplbmRvYmoKNTcgMCBvYmoKPDwgL1R5cGUgL0ZvbnREZXNj - cmlwdG9yIC9Bc2NlbnQgNzcwIC9DYXBIZWlnaHQgNjg0IC9EZXNjZW50IC0yMzAgL0Zs - YWdzIDMyCi9Gb250QkJveCBbNSAtMjIxIDc2OCA3MzddIC9Gb250TmFtZSAvQk5OUkxV - K0hlbHZldGljYSAvSXRhbGljQW5nbGUgMCAvU3RlbVYKMCAvTWF4V2lkdGggMTUwMCAv - WEhlaWdodCA1MTMgL0ZvbnRGaWxlMiA1NSAwIFIgPj4KZW5kb2JqCjU4IDAgb2JqClsg - Mjc4IDAgMCAwIDAgMCAwIDAgMzMzIDMzMyAwIDAgMCAwIDI3OCAwIDU1NiA1NTYgNTU2 - IDAgMCAwIDAgMCA1NTYgMCAwIDAKMCAwIDAgNTU2IDAgNjY3IDAgNzIyIDAgMCAwIDAg - MCAwIDAgMCAwIDgzMyA3MjIgNzc4IDY2NyAwIDAgNjY3IDYxMSAwIDAgMAowIDAgMCAw - IDAgMCAwIDAgMCA1NTYgNTU2IDUwMCA1NTYgNTU2IDI3OCA1NTYgNTU2IDIyMiAwIDUw - MCAyMjIgODMzIDU1NiA1NTYKNTU2IDAgMzMzIDUwMCAyNzggNTU2IDUwMCA3MjIgMCA1 - MDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMAowIDAgMCAwIDAg - MCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAw - IDAgMCAwIDAgMCAwCjAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAg - MCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAKMCAwIDAgMCAwIDAgMCA1 - MDAgXQplbmRvYmoKMjQgMCBvYmoKPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1RydWVU - eXBlIC9CYXNlRm9udCAvQk5OUkxVK0hlbHZldGljYSAvRm9udERlc2NyaXB0b3IKNTcg - MCBSIC9XaWR0aHMgNTggMCBSIC9GaXJzdENoYXIgMzIgL0xhc3RDaGFyIDIyMiAvRW5j - b2RpbmcgL01hY1JvbWFuRW5jb2RpbmcKPj4KZW5kb2JqCjEgMCBvYmoKPDwgL1RpdGxl - IChVbnRpdGxlZCkgL0F1dGhvciAoYnJhbmRvbmgpIC9DcmVhdG9yIChPbW5pR3JhZmZs - ZSkgL1Byb2R1Y2VyIChNYWMgT1MgWCAxMC41LjggUXVhcnR6IFBERkNvbnRleHQpCi9D - cmVhdGlvbkRhdGUgKEQ6MjAwOTExMjAyMzExMTVaMDAnMDAnKSAvTW9kRGF0ZSAoRDoy - MDA5MTEyMDIzMTExNVowMCcwMCcpCj4+CmVuZG9iagp4cmVmCjAgNTkKMDAwMDAwMDAw - MCA2NTUzNSBmIAowMDAwMDQ0NDU1IDAwMDAwIG4gCjAwMDAwMzMxOTAgMDAwMDAgbiAK - MDAwMDAwMTYyNCAwMDAwMCBuIAowMDAwMDMzMDI3IDAwMDAwIG4gCjAwMDAwMDAwMjIg - MDAwMDAgbiAKMDAwMDAwMTYwNCAwMDAwMCBuIAowMDAwMDAxNzI4IDAwMDAwIG4gCjAw - MDAwMzE0MDMgMDAwMDAgbiAKMDAwMDAwMTk2MSAwMDAwMCBuIAowMDAwMDAzMDUxIDAw - MDAwIG4gCjAwMDAwMDY0NzcgMDAwMDAgbiAKMDAwMDAwNzIyMiAwMDAwMCBuIAowMDAw - MDA1NzEyIDAwMDAwIG4gCjAwMDAwMDY0NTcgMDAwMDAgbiAKMDAwMDAwMzgzNiAwMDAw - MCBuIAowMDAwMDA0OTI3IDAwMDAwIG4gCjAwMDAwMDQ5NDcgMDAwMDAgbiAKMDAwMDAw - NTY5MiAwMDAwMCBuIAowMDAwMDAzMDcxIDAwMDAwIG4gCjAwMDAwMDM4MTYgMDAwMDAg - biAKMDAwMDAwNzI0MiAwMDAwMCBuIAowMDAwMDA3OTg3IDAwMDAwIG4gCjAwMDAwMzI5 - OTAgMDAwMDAgbiAKMDAwMDA0NDI4MCAwMDAwMCBuIAowMDAwMDMwNDUxIDAwMDAwIG4g - CjAwMDAwMjE5NzMgMDAwMDAgbiAKMDAwMDAyNTg1OCAwMDAwMCBuIAowMDAwMDMyMTI1 - IDAwMDAwIG4gCjAwMDAwMTQ0MjggMDAwMDAgbiAKMDAwMDAxNjkyMiAwMDAwMCBuIAow - MDAwMDEwNTIyIDAwMDAwIG4gCjAwMDAwMTQ0MDcgMDAwMDAgbiAKMDAwMDAxOTQ1OCAw - MDAwMCBuIAowMDAwMDIxOTUyIDAwMDAwIG4gCjAwMDAwMjk3MjggMDAwMDAgbiAKMDAw - MDAyNTg3OSAwMDAwMCBuIAowMDAwMDI5MDIxIDAwMDAwIG4gCjAwMDAwMTY5NDMgMDAw - MDAgbiAKMDAwMDAxOTQzNyAwMDAwMCBuIAowMDAwMDA4MDA3IDAwMDAwIG4gCjAwMDAw - MTA1MDEgMDAwMDAgbiAKMDAwMDAyOTA0MiAwMDAwMCBuIAowMDAwMDI5NzA4IDAwMDAw - IG4gCjAwMDAwMjk3NjUgMDAwMDAgbiAKMDAwMDAzMDQzMSAwMDAwMCBuIAowMDAwMDMw - NDg4IDAwMDAwIG4gCjAwMDAwMzEzODMgMDAwMDAgbiAKMDAwMDAzMTQzOSAwMDAwMCBu - IAowMDAwMDMyMTA1IDAwMDAwIG4gCjAwMDAwMzIxNjIgMDAwMDAgbiAKMDAwMDAzMjk3 - MCAwMDAwMCBuIAowMDAwMDMzMTEwIDAwMDAwIG4gCjAwMDAwMzMzMTYgMDAwMDAgbiAK - MDAwMDAzMzIzOCAwMDAwMCBuIAowMDAwMDMzMzk0IDAwMDAwIG4gCjAwMDAwNDM1NTYg - MDAwMDAgbiAKMDAwMDA0MzU3OCAwMDAwMCBuIAowMDAwMDQzNzk4IDAwMDAwIG4gCnRy - YWlsZXIKPDwgL1NpemUgNTkgL1Jvb3QgNTIgMCBSIC9JbmZvIDEgMCBSIC9JRCBbIDw0 - MjZkMDljZjFjMDY3M2I0NTU4MGUzOGJlY2FkZWY4OD4KPDQyNmQwOWNmMWMwNjczYjQ1 - NTgwZTM4YmVjYWRlZjg4PiBdID4+CnN0YXJ0eHJlZgo0NDY1NwolJUVPRgoxIDAgb2Jq - Cjw8L0F1dGhvciAoYnJhbmRvbmgpL0NyZWF0aW9uRGF0ZSAoRDoyMDA5MTEyMDIyNTQw - MFopL0NyZWF0b3IgKE9tbmlHcmFmZmxlIDUuMi4xKS9Nb2REYXRlIChEOjIwMDkxMTIw - MjMxMTAwWikvUHJvZHVjZXIgKE1hYyBPUyBYIDEwLjUuOCBRdWFydHogUERGQ29udGV4 - dCkvVGl0bGUgKHBhY2tldF9mbG93X2Zsb3djaGFydCk+PgplbmRvYmoKeHJlZgoxIDEK - MDAwMDA0NTk5NSAwMDAwMCBuIAp0cmFpbGVyCjw8L0lEIFs8NDI2ZDA5Y2YxYzA2NzNi - NDU1ODBlMzhiZWNhZGVmODg+IDw0MjZkMDljZjFjMDY3M2I0NTU4MGUzOGJlY2FkZWY4 - OD5dIC9JbmZvIDEgMCBSIC9QcmV2IDQ0NjU3IC9Sb290IDUyIDAgUiAvU2l6ZSA1OT4+ - CnN0YXJ0eHJlZgo0NjE5NwolJUVPRgo= - - QuickLookThumbnail - - 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 - Yy4sIDIwMDkA - - ReadOnly - NO - RowAlign - 1 - RowSpacing - 36 - SheetTitle - Canvas 1 - SmartAlignmentGuidesActive - YES - SmartDistanceGuidesActive - YES - UniqueID - 1 - UseEntirePage - - VPages - 1 - WindowInfo - - CurrentSheet - 0 - ExpandedCanvases - - - name - Canvas 1 - - - FitInWindow - - Frame - {{759, 198}, {710, 887}} - ListView - - OutlineWidth - 142 - RightSidebar - - ShowRuler - - Sidebar - - SidebarWidth - 120 - VisibleRegion - {{0, -204}, {754.688, 962.062}} - Zoom - 0.76190477609634399 - ZoomValues - - - Canvas 1 - 0.0 - 1 - - - - saveQuickLookFiles - YES - - diff --git a/openflow/hw-lib/automake.mk b/openflow/hw-lib/automake.mk deleted file mode 100644 index 204e1217..00000000 --- a/openflow/hw-lib/automake.mk +++ /dev/null @@ -1,28 +0,0 @@ -# -# Hardware library dependency file definitions. -# - -if NF2 -# -# NetFPGA hardware library -# -noinst_LIBRARIES += hw-lib/libnf2.a - -hw_lib_libnf2_a_SOURCES = \ - hw-lib/nf2/hw_flow.c \ - hw-lib/nf2/hw_flow.h \ - hw-lib/nf2/nf2_lib.c \ - hw-lib/nf2/nf2_lib.h \ - hw-lib/nf2/nf2_drv.c \ - hw-lib/nf2/nf2_drv.h \ - hw-lib/nf2/nf2.h \ - hw-lib/nf2/debug.h \ - hw-lib/nf2/reg_defines_openflow_switch.h \ - hw-lib/nf2/nf2util.c \ - hw-lib/nf2/nf2util.h - -hw_lib_nf2_a_CPPFLAGS = $(AM_CPPFLAGS) $(OF_CPP_FLAGS) -DHWTABLE_NO_DEBUG -hw_lib_nf2_a_CPPFLAGS += -I hw-lib/nf2 -hw_lib_nf2_a_CPPFLAGS += -I $(HW_SYSTEM)/include - -endif diff --git a/openflow/hw-lib/nf2/README b/openflow/hw-lib/nf2/README deleted file mode 100644 index 7e111b30..00000000 --- a/openflow/hw-lib/nf2/README +++ /dev/null @@ -1,56 +0,0 @@ -NetFPGA Hardware Table - Date - 03/09/10 ----------------------------------------- - -This library creates and maintains a single software table that contains all -the flows that are currently held in the NetFPGA card. The card itself splits -exact match flows into SRAM and wildcard match flows into TCAMs. Currently -there are 24 usable wildcard flow entries and 32,768 available exact match -entries. The exact match table is hashed so actual available entries will be -varied. - -Installation ----------------------------------------- - -First build OpenFlow ensuring you include the directive to build the -openflow_netfpga hardware table in your configure statement: - - % ./configure --enable-hw-lib=nf2 - -For further help regarding building OpenFlow please see the INSTALL file in -the OpenFlow root directory. - -Platform support ----------------- - -OpenFlow v1.0 with NetFPGA hardware table has been tested on CentOS5.4 -(Linux 2.6.18), which is the officially supported platform of NetFPGA. - -Running ----------------------------------------- - -Use nf2_download to download the openflow_switch.bit file that is located in -the /datapath/hwtable_nf2 folder: - - % nf2_download -r /hw-lib/nf2/openflow_switch.bit - -'-r' option enables PHY interrupt for its link status changing, and OpenFlow -switch can detect it. - -Run ofdatapth with indicating *all* the NetFPGA interfaces: - - % /udatapath/ofdatapath punix:/var/run/test \ - -i nf2c0,nf2c1,nf2c2,nf2c3 - -At this point your OpenFlow switch should be ready to go. -The way you start up ofprotocol is as same as you do for software reference -switch. - -Known Issues ----------------------------------------- -* There is currently no support for priority amongst wildcard-match entries. - -Contact -------- -e-mail: openflow-discuss@lists.stanford.edu -www: http://openflowswitch.org/ diff --git a/openflow/hw-lib/nf2/debug.h b/openflow/hw-lib/nf2/debug.h deleted file mode 100644 index 9cb2b10d..00000000 --- a/openflow/hw-lib/nf2/debug.h +++ /dev/null @@ -1,105 +0,0 @@ - -#ifndef OF_HW_DEBUG_H -#define OF_HW_DEBUG_H 1 - -#include -#include - -#if !defined(HWTABLE_NO_DEBUG) -extern int of_hw_debug; -#define dbg_send(mod, lvl, fmt, args...) \ - if (of_hw_debug >= (lvl)) fprintf(stderr, fmt, ##args) - -#define DBG_LVL_NONE -1 /* All output off */ -#define DBG_LVL_ERROR 0 /* Default value */ -#define DBG_LVL_ALWAYS 0 /* For requested dump output */ -#define DBG_LVL_WARN 1 -#define DBG_LVL_VERBOSE 2 -#define DBG_LVL_VVERB 3 /* Include success indications */ - -/* Sorry for the lazy syntax here. */ -#define DBG_CHECK(lvl) (((lvl) >= 0) && (of_hw_debug >= (lvl))) -#define DBG_ERROR(fmt, args...) dbg_send(0, DBG_LVL_ERROR, fmt, ##args) -#define DBG_ALWAYS(fmt, args...) dbg_send(0, DBG_LVL_ALWAYS, fmt, ##args) -#define DBG_WARN(fmt, args...) dbg_send(0, DBG_LVL_WARN, fmt, ##args) -#define DBG_VERBOSE(fmt, args...) dbg_send(0, DBG_LVL_VERBOSE, fmt, ##args) -#define DBG_VVERB(fmt, args...) dbg_send(0, DBG_LVL_VVERB, fmt, ##args) -#define DBG_NONE(fmt, args...) -/* Same as DEBUG_ALWAYS */ -#define DEBUGK(fmt, args...) dbg_send(0, DBG_LVL_ALWAYS, fmt, ##args) - -#define REPORT_ERROR(str) \ - DBG_ERROR("ERROR: %s:%d. %s\n", __FUNCTION__, __LINE__, str) - -/* Default debugging location string */ -#define ANNOUNCE_LOCATION DBG_VVERB("%s: %d\n", __FUNCTION__, __LINE__) -#define DBG_INCR(cnt) (++(cnt)) - -/* Should assert return? Not presently */ -#define ASSERT(cond) \ - if (!(cond)) DBG_ERROR("ASSERTION %s IN %s FAILED LINE %d\n", \ - #cond, __FUNCTION__, __LINE__) - -/* DEBUG for HW flow lists */ -#define HW_FLOW_MAGIC 0xba5eba11 -#define HW_FLOW_MAKE_VALID(hf) (hf)->magic = HW_FLOW_MAGIC -#define HW_FLOW_IS_VALID(hf) \ - (((hf) != NULL) && ((hf)->magic == HW_FLOW_MAGIC)) - -/* - * Carry out an operation and check for error, optionally returning - * from the calling routine. To avoid compiler - * warnings in routines with void return, we give two macros. - * - * WARNING: This check uses rv != 0 (not just rv < 0). - */ - -#define TRY(op, str) do { \ - int rv; \ - if (((rv = (op)) < 0)) { \ - DBG_ERROR("ERROR %d: %s\n", rv, str); \ - return rv; \ - } else { \ - DBG_NONE("%s: success\n", str); \ - } \ - } while (0) - -#define TRY_NR(op, str) do { \ - int rv; \ - if (((rv = (op)) != 0)) { \ - DBG_ERROR("ERROR %d: %s\n", rv, str); \ - } else { \ - DBG_NONE("%s: success\n", str); \ - } \ - } while (0) - -#else /* No debugging */ - -#define DBG_CHECK(lvl) 0 -#define ANNOUNCE_LOCATION -#define ACT_STRING(action) "" -#define DBG_INCR(cnt) -#define DBG_ERROR(fmt, args...) -#define DBG_ALWAYS(fmt, args...) -#define DBG_WARN(fmt, args...) -#define DBG_VERBOSE(fmt, args...) -#define DBG_VVERB(fmt, args...) -#define DBG_NONE(fmt, args...) -#define DEBUGK(fmt, args...) -#define REPORT_ERROR(str) - -#define ASSERT(cond) - -#define HW_FLOW_MAKE_VALID(hf) -#define HW_FLOW_IS_VALID(hf) 1 - -#define TRY(op, str) do { \ - int rv; \ - if (((rv = (op)) != 0)) return rv; \ - } while (0) - -#define TRY_NR(op, str) (void)op - -#endif /* !defined(HWTABLE_NO_DEBUG) */ - -#endif /* OF_HW_DEBUG_H */ diff --git a/openflow/hw-lib/nf2/hw_flow.c b/openflow/hw-lib/nf2/hw_flow.c deleted file mode 100644 index d59a7713..00000000 --- a/openflow/hw-lib/nf2/hw_flow.c +++ /dev/null @@ -1,514 +0,0 @@ -/*- - * Copyright (c) 2008, 2009, 2010 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#include - -#include -#include "list.h" -#include "udatapath/switch-flow.h" -#include "udatapath/datapath.h" -#include "reg_defines_openflow_switch.h" -#include "nf2util.h" -#include "hw_flow.h" -#include "nf2_drv.h" -#include "nf2_lib.h" -#include "debug.h" - -struct nf2_flowtable { - struct of_hw_driver hw_driver; - unsigned int max_flows; - unsigned int num_flows; - struct list flows; - struct list iter_flows; - unsigned long int next_serial; -}; - -static struct sw_flow *nf2_lookup_flowtable(struct sw_table *, - const struct sw_flow_key *); -static int nf2_install_flow(struct sw_table *, struct sw_flow *); -static int nf2_modify_flow(struct sw_table *, const struct sw_flow_key *, - uint16_t, int, const struct ofp_action_header *, - size_t); -static int do_uninstall(struct sw_flow *, struct list *); -static int nf2_has_conflict(struct sw_table *, const struct sw_flow_key *, - uint16_t, int); -static int nf2_uninstall_flow_wrap(struct datapath *, struct sw_table *, - const struct sw_flow_key *, uint16_t, - uint16_t, int); -static int nf2_uninstall_flow(struct datapath *, struct sw_table *, - const struct sw_flow_key *, uint16_t, - uint16_t, int, int); -static void nf2_flow_timeout(struct sw_table *, struct list *); - -static void nf2_destroy_flowtable(struct sw_table *); -static int nf2_iterate_flowtable(struct sw_table *, - const struct sw_flow_key *, - uint16_t, struct sw_table_position *, - int (*)(struct sw_flow *, void *), void *); -static void nf2_get_flowstats(struct sw_table *, struct sw_table_stats *); -static int nf2_get_portstats(of_hw_driver_t *, int, struct ofp_port_stats *); - -#if !defined(HWTABLE_NO_DEBUG) -int of_hw_debug = DBG_LVL_WARN; -#endif - -#define DELETE_FLOW 0 -#define KEEP_FLOW 1 - -static struct sw_flow * -nf2_lookup_flowtable(struct sw_table *flowtab, const struct sw_flow_key *key) -{ - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - struct sw_flow *flow; - - LIST_FOR_EACH(flow, struct sw_flow, node, &nf2flowtab->flows) { - if (flow_matches_1wild(key, &flow->key)) { - return flow; - } - } - - return NULL; -} - -static int -nf2_install_flow(struct sw_table *flowtab, struct sw_flow *flow) -{ - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - - /* Delete flows that match exactly. */ - nf2_uninstall_flow(NULL, flowtab, &flow->key, OFPP_NONE, - flow->priority, true, KEEP_FLOW); - - if (nf2_are_actions_supported(flow)) { - if (nf2_build_and_write_flow(flow)) { - /* Not successful */ - return 0; - } - } else { - /* Unsupported actions or no device. */ - return 0; - } - - nf2flowtab->num_flows++; - list_push_front(&nf2flowtab->flows, &flow->node); - list_push_front(&nf2flowtab->iter_flows, &flow->iter_node); - - return 1; -} - -static int -nf2_modify_flow(struct sw_table *flowtab, const struct sw_flow_key *key, - uint16_t priority, int strict, - const struct ofp_action_header *actions, size_t actions_len) -{ - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - struct sw_flow *flow; - unsigned int count = 0; - - LIST_FOR_EACH(flow, struct sw_flow, node, &nf2flowtab->flows) { - if (flow_matches_desc(&flow->key, key, strict) - && (!strict || flow->priority == priority)) { - flow_replace_acts(flow, actions, actions_len); - if (nf2_are_actions_supported(flow)) { - count += nf2_modify_acts(flow); - } - } else { - return 0; - } - } - - return count; -} - -static int -nf2_has_conflict(struct sw_table *flowtab, const struct sw_flow_key *key, - uint16_t priority, int strict) -{ - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - struct sw_flow *flow; - - LIST_FOR_EACH(flow, struct sw_flow, node, &nf2flowtab->flows) { - - if (flow_matches_2desc(&flow->key, key, strict) - && (flow->priority == priority)) { - return true; - } - } - - return false; -} - -static int -do_uninstall(struct sw_flow *flow, struct list *deleted) -{ - if (flow != NULL && flow->private != NULL) { - list_remove(&flow->node); - list_remove(&flow->iter_node); - list_push_back(deleted, &flow->node); - return 1; - } - - return 0; -} - -static int -nf2_uninstall_flow_wrap(struct datapath *dpinst, struct sw_table *flowtab, - const struct sw_flow_key *key, uint16_t out_port, - uint16_t priority, int strict) -{ - return nf2_uninstall_flow(dpinst, flowtab, key, out_port, - priority, strict, DELETE_FLOW); -} - -static int -nf2_uninstall_flow(struct datapath *dpinst, struct sw_table *flowtab, - const struct sw_flow_key *key, uint16_t out_port, - uint16_t priority, int strict, int keep_flow) -{ - struct nf2device *dev; - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - struct sw_flow *flow, *n; - struct nf2_flow *nf2flow; - unsigned int count = 0; - struct list deleted; - list_init(&deleted); - - dev = nf2_get_net_device(); - if (dev == NULL) - return 0; - - LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &nf2flowtab->flows) { - if (flow_matches_desc(&flow->key, key, strict) - && (!strict || flow->priority == priority) - && flow_has_out_port(flow, out_port)) { - nf2flow = flow->private; - - if (nf2flow != NULL) { - flow->packet_count - += nf2_get_packet_count(dev, - nf2flow); - flow->byte_count += nf2_get_byte_count(dev, - nf2flow); - } - count += do_uninstall(flow, &deleted); - if (keep_flow == KEEP_FLOW) { - /* Delete private in sw_flow here */ - nf2_delete_private(flow->private); - } - } - } - nf2flowtab->num_flows -= count; - - nf2_free_net_device(dev); - - if (keep_flow == DELETE_FLOW) { - /* Notify DP of deleted flows and delete the flow */ - LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &deleted) { - dp_send_flow_end(dpinst, flow, flow->reason); - list_remove(&flow->node); - nf2_delete_private(flow->private); - flow_free(flow); - } - } - - return count; -} - -static void -nf2_flow_timeout(struct sw_table *flowtab, struct list *deleted) -{ - struct nf2device *dev; - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - struct sw_flow *flow, *n; - struct nf2_flow *nf2flow; - int num_uninst_flows = 0; - uint64_t num_forw_packets = 0; - uint64_t now = time_msec(); - - dev = nf2_get_net_device(); - if (dev == NULL) { - DBG_ERROR("Could not open NetFPGA device\n"); - return; - } - - /* LOCK; */ - /* FIXME */ - LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &nf2flowtab->flows) { - nf2flow = flow->private; - if (nf2flow != NULL) { - num_forw_packets = flow->packet_count - + nf2_get_packet_count(dev, nf2flow); - flow->byte_count += nf2_get_byte_count(dev, nf2flow); - } - if (num_forw_packets > flow->packet_count) { - flow->packet_count = num_forw_packets; - flow->used = now; - } - - if (flow_timeout(flow)) { - num_uninst_flows += do_uninstall(flow, deleted); - nf2_delete_private(flow->private); - } - } - - /* UNLOCK; */ - - nf2_clear_watchdog(dev); - nf2_free_net_device(dev); - - nf2flowtab->num_flows -= num_uninst_flows; -} - -static void -nf2_destroy_flowtable(struct sw_table *flowtab) -{ - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - struct nf2_flow *nf2flow = NULL; - - if (nf2flowtab == NULL) - return; - - while (!list_is_empty(&nf2flowtab->flows)) { - struct sw_flow *flow - = CONTAINER_OF(list_front(&nf2flowtab->flows), - struct sw_flow, node); - list_remove(&flow->node); - if (flow->private) { - nf2flow = (struct nf2_flow *)flow->private; - - if (nf2flow->type == NF2_TABLE_EXACT) { - nf2_add_free_exact(nf2flow); - } else if (nf2flow->type == NF2_TABLE_WILDCARD) { - nf2_add_free_wildcard(nf2flow); - } - flow->private = NULL; - } - flow_free(flow); - } - free(nf2flowtab); - - nf2_destroy_exact_freelist(); - nf2_destroy_wildcard_freelist(); -} - -static int -nf2_iterate_flowtable(struct sw_table *flowtab, const struct sw_flow_key *key, - uint16_t out_port, struct sw_table_position *position, - int (*callback) (struct sw_flow *, void *), - void *private) -{ - unsigned long start; - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - struct sw_flow *flow; - int error = 0; - - start = ~position->private[0]; - LIST_FOR_EACH(flow, struct sw_flow, iter_node, &nf2flowtab->iter_flows) { - if (flow->serial <= start - && flow_matches_2wild(key, &flow->key) - && flow_has_out_port(flow, out_port)) { - error = callback(flow, private); - if (error != 0) { - position->private[0] = ~flow->serial; - return error; - } - } - } - - return error; -} - -static void -nf2_get_flowstats(struct sw_table *flowtab, struct sw_table_stats *stats) -{ - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - struct nf2device *dev; - unsigned long int num_matched = 0; - unsigned long int num_missed = 0; - - dev = nf2_get_net_device(); - if (dev == NULL) { - DBG_VERBOSE("Could not open NetFPGA device\n"); - } else { - num_matched = nf2_get_matched_count(dev); - num_missed = nf2_get_missed_count(dev); - nf2_free_net_device(dev); - } - - stats->name = "nf2"; - stats->wildcards = OPENFLOW_WILDCARD_TABLE_SIZE - - RESERVED_FOR_CPU2NETFPGA; - stats->n_flows = nf2flowtab->num_flows; - stats->max_flows = nf2flowtab->max_flows; - stats->n_lookup = num_matched + num_missed; - stats->n_matched = num_matched; -} - -static int -nf2_get_portstats(of_hw_driver_t *hw_drv, int of_port, - struct ofp_port_stats *stats) -{ - int nf2_port; - struct nf2_port_info *nf2portinfo; - struct nf2device *dev; - - if ((of_port > NF2_PORT_NUM) || (of_port <= 0)) { - return 1; - } - nf2_port = of_port - 1; - - nf2portinfo = calloc(1, sizeof(struct nf2_port_info)); - if (nf2portinfo == NULL) { - return 1; - } - - dev = nf2_get_net_device(); - if (dev == NULL) { - free(nf2portinfo); - return 1; - } - - if (nf2_get_port_info(dev, nf2_port, nf2portinfo)) { - nf2_free_net_device(dev); - free(nf2portinfo); - return 1; - } - - stats->rx_packets = (uint64_t)(nf2portinfo->rx_q_num_pkts_stored); - stats->rx_dropped = (uint64_t)(nf2portinfo->rx_q_num_pkts_dropped_full - + nf2portinfo->rx_q_num_pkts_dropped_bad); - stats->rx_bytes = (uint64_t)(nf2portinfo->rx_q_num_bytes_pushed); - stats->tx_packets = (uint64_t)(nf2portinfo->tx_q_num_pkts_sent); - stats->tx_bytes = (uint64_t)(nf2portinfo->tx_q_num_bytes_pushed); - - /* Not supported */ - stats->tx_dropped = -1; - stats->rx_errors = -1; - stats->tx_errors = -1; - stats->rx_frame_err = -1; - stats->rx_over_err = -1; - stats->rx_crc_err = -1; - stats->collisions = -1; - - nf2_free_net_device(dev); - free(nf2portinfo); - return 0; -} - -/* - * Create and initialize a new hardware datapath object - */ - -of_hw_driver_t * -new_of_hw_driver(struct datapath *dp) -{ - struct sw_table *sw_tab; - of_hw_driver_t *hw_drv; - struct nf2device *dev; - struct nf2_flowtable *nf2flowtab; - - dev = nf2_get_net_device(); - if (dev == NULL) { - return NULL; - } - nf2_reset_card(dev); - nf2_free_net_device(dev); - - nf2flowtab = calloc(1, sizeof(*nf2flowtab)); - if (nf2flowtab == NULL) { - return NULL; - } - - /* These all point to the same place */ - hw_drv = &nf2flowtab->hw_driver; - sw_tab = &hw_drv->sw_table; - - sw_tab->n_lookup = 0; - sw_tab->n_matched = 0; - - /* Fill out the function pointers */ - sw_tab->lookup = nf2_lookup_flowtable; - sw_tab->insert = nf2_install_flow; - sw_tab->modify = nf2_modify_flow; - sw_tab->has_conflict = nf2_has_conflict; - - sw_tab->delete = nf2_uninstall_flow_wrap; - sw_tab->timeout = nf2_flow_timeout; - - sw_tab->destroy = nf2_destroy_flowtable; - sw_tab->iterate = nf2_iterate_flowtable; - sw_tab->stats = nf2_get_flowstats; - - nf2flowtab->max_flows = OPENFLOW_NF2_EXACT_TABLE_SIZE - + OPENFLOW_WILDCARD_TABLE_SIZE - RESERVED_FOR_CPU2NETFPGA; - nf2flowtab->num_flows = 0; - list_init(&nf2flowtab->flows); - list_init(&nf2flowtab->iter_flows); - nf2flowtab->next_serial = 0; - - if (nf2_init_wildcard_freelist()) { - DBG_ERROR("Could not create wildcard freelist\n"); - free(nf2flowtab); - return NULL; - } - if (nf2_write_static_wildcard()) { - DBG_ERROR("Could not create wildcard freelist\n"); - free(nf2flowtab); - return NULL; - } - if (nf2_init_exact_freelist()) { - DBG_ERROR("Could not create exact freelist\n"); - free(nf2flowtab); - return NULL; - } - - hw_drv->table_stats_get = NULL; - hw_drv->port_stats_get = nf2_get_portstats; - hw_drv->flow_stats_get = NULL; - hw_drv->aggregate_stats_get = NULL; - - hw_drv->port_add = NULL; - hw_drv->port_remove = NULL; - hw_drv->port_link_get = NULL; - hw_drv->port_enable_set = NULL; - hw_drv->port_enable_get = NULL; - hw_drv->port_queue_config = NULL; - hw_drv->port_queue_remove = NULL; - hw_drv->port_change_register = NULL; - - hw_drv->packet_send = NULL; - hw_drv->packet_receive_register = NULL; - - hw_drv->ioctl = NULL; - - return hw_drv; -} diff --git a/openflow/hw-lib/nf2/hw_flow.h b/openflow/hw-lib/nf2/hw_flow.h deleted file mode 100644 index 96e0320f..00000000 --- a/openflow/hw-lib/nf2/hw_flow.h +++ /dev/null @@ -1,56 +0,0 @@ -/*- - * Copyright (c) 2008, 2009, 2010 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#ifndef HWTABLE_NF2_NF2_FLOWTABLE_ -#define HWTABLE_NF2_NF2_FLOWTABLE_ - -#define RESERVED_FOR_CPU2NETFPGA 8 - -struct nf2_flow { - struct list node; - uint32_t pos; - uint32_t type; - uint32_t hw_packet_count; - uint32_t hw_byte_count; -}; - -enum nf2_of_table_type { - NF2_TABLE_EXACT, - NF2_TABLE_WILDCARD -}; - -/* Remove the commentout of the following 'define' line - * if you want to enable NetFPGA watchdog timer capability. - */ -/* #define NF2_WATCHDOG 1 */ - -#endif diff --git a/openflow/hw-lib/nf2/nf2.h b/openflow/hw-lib/nf2/nf2.h deleted file mode 100644 index 519f52da..00000000 --- a/openflow/hw-lib/nf2/nf2.h +++ /dev/null @@ -1,452 +0,0 @@ -/* **************************************************************************** - * $Id: nf2.h 5575 2009-05-13 18:44:26Z grg $ - * - * Module: nf2.h - * Project: NetFPGA 2 Linux Kernel Driver - * Description: Header file for kernel driver - * - * Change history: - * - */ - -#ifndef _NF2_H -#define _NF2_H 1 - -#define NF2_DEV_NAME "nf2" - -/* Include for socket IOCTLs */ -#include - -/* Maximum number of interfaces */ -#ifndef MAX_IFACE -#define MAX_IFACE 4 -#endif - -/* - * Register names and locations. - * - * Note that these names are not necessarily identical to - * those in NF2/hw/common/src/defines - */ - -/* CPCI registers */ -#define CPCI_REG_ID 0x000 -#define CPCI_REG_BOARD_ID 0x004 -#define CPCI_REG_CTRL 0x008 -#define CPCI_REG_RESET 0x00c -#define CPCI_REG_ERROR 0x010 -#define CPCI_REG_DUMMY 0x020 -#define CPCI_REG_INTERRUPT_MASK 0x040 -#define CPCI_REG_INTERRUPT_STATUS 0x044 -#define CPCI_REG_PROG_DATA 0x100 -#define CPCI_REG_PROG_STATUS 0x104 -#define CPCI_REG_PROG_CTRL 0x108 -#define CPCI_REG_DMA_I_ADDR 0x140 -#define CPCI_REG_DMA_E_ADDR 0x144 -#define CPCI_REG_DMA_I_SIZE 0x148 -#define CPCI_REG_DMA_E_SIZE 0x14c -#define CPCI_REG_DMA_I_CTRL 0x150 -#define CPCI_REG_DMA_E_CTRL 0x154 -#define CPCI_REG_DMA_MAX_XFER_TIME 0x180 -#define CPCI_REG_DMA_MAX_RETRIES 0x184 -#define CPCI_REG_CNET_MAX_XFER_TIME 0x188 -#define CPCI_REG_DMA_I_PKT_CNT 0x400 -#define CPCI_REG_DMA_E_PKT_CNT 0x404 -#define CPCI_REG_CPCI_REG_RD_CNT 0x408 -#define CPCI_REG_CPCI_REG_WR_CNT 0x40c -#define CPCI_REG_CNET_REG_RD_CNT 0x410 -#define CPCI_REG_CNET_REG_WR_CNT 0x414 - -#define CPCI_REG_N_CLK_COUNT 0x500 -#define CPCI_REG_P_MAX 0x504 -#define CPCI_REG_N_EXP 0x508 -#define CPCI_REG_P_CLK_CTR 0x510 -#define CPCI_REG_RESET_CTR 0x520 - - - -/* Base address for CNET registers */ -#define CNET_REG_BASE 0x400000 - - -/* Added by nweaver for building memory manipulation - utilities */ -/* 2 MB SRAM size on current board, MAX and SIZE will - need to be changed if upgraded to 4 MB SRAMs */ -#define SRAM_SIZE 0x200000 - -#define SRAM_1_BASE 0x800000 -#define SRAM_1_MAX 0x9FFFFF - -#define SRAM_2_BASE 0xC00000 -#define SRAM_2_MAX 0xDFFFFF -/* end nweaver addition */ - - -/* Device ID registers */ -#define NF2_DEVICE_ID 0x0400000 -#define NF2_REVISION 0x0400004 -#define NF2_DEVICE_STR 0x0400008 - - -/* CNET registers */ -#define CNET_REG_ID (CNET_REG_BASE + 0x000) -#define CNET_REG_CTRL (CNET_REG_BASE + 0x004) -#define CNET_REG_RESET (CNET_REG_BASE + 0x008) -#define CNET_REG_ERROR (CNET_REG_BASE + 0x00C) -#define CNET_REG_ENABLE (CNET_REG_BASE + 0x010) -#define CNET_REG_WR_SRAM1_EOP (CNET_REG_BASE + 0x0F0) -#define CNET_REG_RD_SRAM1_EOP (CNET_REG_BASE + 0x0F4) -#define CNET_REG_WR_SRAM2_EOP (CNET_REG_BASE + 0x0F8) -#define CNET_REG_RD_SRAM2_EOP (CNET_REG_BASE + 0x0FC) -#define CNET_REG_MF_STATUS_0 (CNET_REG_BASE + 0x100) -#define CNET_REG_MF_TX_PKTS_SENT_0 (CNET_REG_BASE + 0x104) -#define CNET_REG_MF_RX_PKTS_RCVD_0 (CNET_REG_BASE + 0x108) -#define CNET_REG_MF_RX_PKTS_LOST_0 (CNET_REG_BASE + 0x10C) -#define CNET_REG_MAC_CONFIG_0 (CNET_REG_BASE + 0x110) -#define CNET_REG_MF_STATUS_1 (CNET_REG_BASE + 0x140) -#define CNET_REG_MF_TX_PKTS_SENT_1 (CNET_REG_BASE + 0x144) -#define CNET_REG_MF_RX_PKTS_RCVD_1 (CNET_REG_BASE + 0x148) -#define CNET_REG_MF_RX_PKTS_LOST_1 (CNET_REG_BASE + 0x14C) -#define CNET_REG_MAC_CONFIG_1 (CNET_REG_BASE + 0x150) -#define CNET_REG_MF_STATUS_2 (CNET_REG_BASE + 0x180) -#define CNET_REG_MF_TX_PKTS_SENT_2 (CNET_REG_BASE + 0x184) -#define CNET_REG_MF_RX_PKTS_RCVD_2 (CNET_REG_BASE + 0x188) -#define CNET_REG_MF_RX_PKTS_LOST_2 (CNET_REG_BASE + 0x18C) -#define CNET_REG_MAC_CONFIG_2 (CNET_REG_BASE + 0x190) -#define CNET_REG_MF_STATUS_3 (CNET_REG_BASE + 0x1C0) -#define CNET_REG_MF_TX_PKTS_SENT_3 (CNET_REG_BASE + 0x1C4) -#define CNET_REG_MF_RX_PKTS_RCVD_3 (CNET_REG_BASE + 0x1C8) -#define CNET_REG_MF_RX_PKTS_LOST_3 (CNET_REG_BASE + 0x1CC) -#define CNET_REG_MAC_CONFIG_3 (CNET_REG_BASE + 0x1D0) -#define CNET_REG_RXQ_NUM_PKTS_0 (CNET_REG_BASE + 0x200) -#define CNET_REG_RXQ_POINTERS_0 (CNET_REG_BASE + 0x204) -#define CNET_REG_RXQ_NUM_PKTS_1 (CNET_REG_BASE + 0x240) -#define CNET_REG_RXQ_POINTERS_1 (CNET_REG_BASE + 0x244) -#define CNET_REG_RXQ_NUM_PKTS_2 (CNET_REG_BASE + 0x280) -#define CNET_REG_RXQ_POINTERS_2 (CNET_REG_BASE + 0x284) -#define CNET_REG_RXQ_NUM_PKTS_3 (CNET_REG_BASE + 0x2C0) -#define CNET_REG_RXQ_POINTERS_3 (CNET_REG_BASE + 0x2C4) - -#define CNET_REG_MF_RX_PKTS_LOST_BAD_FCS_0 (CNET_REG_BASE + 0x114) -#define CNET_REG_MF_RX_PKTS_LOST_FULL_FIFO_0 (CNET_REG_BASE+0x118) -#define CNET_REG_MF_RX_GOOD_PKTS_RCVD_0 (CNET_REG_BASE+0x11C) -#define CNET_REG_MF_RX_GOOD_BYTES_RCVD_0 (CNET_REG_BASE+0x120) -#define CNET_REG_MF_TX_BYTES_SENT_0 (CNET_REG_BASE+0x124) -#define CNET_REG_MF_RX_PKTS_LOST_BAD_FCS_1 (CNET_REG_BASE+0x154) -#define CNET_REG_MF_RX_PKTS_LOST_FULL_FIFO_1 (CNET_REG_BASE+0x158) -#define CNET_REG_MF_RX_GOOD_PKTS_RCVD_1 (CNET_REG_BASE+0x15C) -#define CNET_REG_MF_RX_GOOD_BYTES_RCVD_1 (CNET_REG_BASE+0x160) -#define CNET_REG_MF_TX_BYTES_SENT_1 (CNET_REG_BASE+0x164) -#define CNET_REG_MF_RX_PKTS_LOST_BAD_FCS_2 (CNET_REG_BASE+0x194) -#define CNET_REG_MF_RX_PKTS_LOST_FULL_FIFO_2 (CNET_REG_BASE+0x198) -#define CNET_REG_MF_RX_GOOD_PKTS_RCVD_2 (CNET_REG_BASE+0x19C) -#define CNET_REG_MF_RX_GOOD_BYTES_RCVD_2 (CNET_REG_BASE+0x1A0) -#define CNET_REG_MF_TX_BYTES_SENT_2 (CNET_REG_BASE+0x1A4) -#define CNET_REG_MF_RX_PKTS_LOST_BAD_FCS_3 (CNET_REG_BASE+0x1D4) -#define CNET_REG_MF_RX_PKTS_LOST_FULL_FIFO_3 (CNET_REG_BASE+0x1D8) -#define CNET_REG_MF_RX_GOOD_PKTS_RCVD_3 (CNET_REG_BASE+0x1DC) -#define CNET_REG_MF_RX_GOOD_BYTES_RCVD_3 (CNET_REG_BASE+0x1E0) -#define CNET_REG_MF_TX_BYTES_SENT_3 (CNET_REG_BASE+0x1E4) - -#define CNET_MAC_CLK_CHK_CTRL (CNET_REG_BASE + 0xF00) -#define CNET_MAC_CLK_CHK_CNT_VALUE (CNET_REG_BASE + 0xF04) - - -/* Base address for CNET PHY registers */ -#define PHY_REG_BASE 0x600000 - -#define PHY_REG_CMD (PHY_REG_BASE) -#define PHY_REG_STATUS (PHY_REG_BASE) - -/* - * CPCI register masks - */ - -/* ID Masks */ -#define ID_VERSION 0x00FFFFFF -#define ID_REVISION 0xFF000000 - -/* Board ID Masks */ -#define BOARD_ID 0x00000F00 -#define BOARD_ID_CONTROL 0x00000001 - -/* Control masks */ -#define CTRL_CNET_RESET 0x00000100 -#define CTRL_LED 0x00000001 - -/* RESET masks */ -#define RESET_CPCI 0x00000001 - -/* Error masks */ -#define ERR_CNET_READ_TIMEOUT 0x02000000 -#define ERR_CNET_ERROR 0x01000000 -#define ERR_PROG_BUF_OVERFLOW 0x00020000 -#define ERR_PROG_ERROR 0x00010000 -#define ERR_DMA_TIMEOUT 0x00000400 -#define ERR_DMA_RETRY_CNT_EXPIRED 0x00000200 -#define ERR_DMA_BUF_OVERFLOW 0x00000100 -#define ERR_DMA_RD_SIZE_ERROR 0x00000040 -#define ERR_DMA_WR_SIZE_ERROR 0x00000020 -#define ERR_DMA_RD_ADDR_ERROR 0x00000010 -#define ERR_DMA_WR_ADDR_ERROR 0x00000008 -#define ERR_DMA_RD_MAC_ERROR 0x00000004 -#define ERR_DMA_WR_MAC_ERROR 0x00000002 -#define ERR_DMA_FATAL_ERROR 0x00000001 - -#define ERR_DMA_SETUP_ERROR ( ERR_DMA_WR_MAC_ERROR | \ - ERR_DMA_RD_MAC_ERROR | \ - ERR_DMA_WR_ADDR_ERROR | \ - ERR_DMA_RD_ADDR_ERROR | \ - ERR_DMA_WR_SIZE_ERROR | \ - ERR_DMA_RD_SIZE_ERROR ) - - -/* Interrupt masks */ -#define INT_DMA_RX_COMPLETE 0x80000000 -#define INT_DMA_TX_COMPLETE 0x40000000 -#define INT_PHY_INTERRUPT 0x20000000 -#define INT_PKT_AVAIL 0x00000100 -#define INT_CNET_ERROR 0x00000020 -#define INT_CNET_READ_TIMEOUT 0x00000010 -#define INT_PROG_ERROR 0x00000008 -#define INT_DMA_TRANSFER_ERROR 0x00000004 -#define INT_DMA_SETUP_ERROR 0x00000002 -#define INT_DMA_FATAL_ERROR 0x00000001 - -#define INT_UNKNOWN ~(INT_DMA_RX_COMPLETE | \ - INT_DMA_TX_COMPLETE | \ - INT_PHY_INTERRUPT | \ - INT_PKT_AVAIL | \ - INT_CNET_ERROR | \ - INT_CNET_READ_TIMEOUT | \ - INT_PROG_ERROR | \ - INT_DMA_TRANSFER_ERROR | \ - INT_DMA_SETUP_ERROR | \ - INT_DMA_FATAL_ERROR) - -/* Programming status */ -#define PROG_INIT 0x00010000 -#define PROG_DONE 0x00000100 -#define PROG_FIFO_EMPTY 0x00000002 -#define PROG_IN_PROGRESS 0x00000001 - -/* Programming control */ -#define PROG_CTRL_RESET 0x00000001 - -/* DMA control */ -#define DMA_CTRL_MAC 0x00000300 -#define DMA_CTRL_OWNER 0x00000001 - -/* - * CNET register masks - */ - -/* Reset masks */ -#define CNET_RESET_MAC 0x0000000F -#define CNET_RESET_MAC_3 0x00000008 -#define CNET_RESET_MAC_2 0x00000004 -#define CNET_RESET_MAC_1 0x00000002 -#define CNET_RESET_MAC_0 0x00000001 - -/* Error masks */ -#define CNET_ERROR_TX_UNDERRUN_MAC 0x000000F0 -#define CNET_ERROR_TX_UNDERRUN_MAC_3 0x00000080 -#define CNET_ERROR_TX_UNDERRUN_MAC_2 0x00000040 -#define CNET_ERROR_TX_UNDERRUN_MAC_1 0x00000020 -#define CNET_ERROR_TX_UNDERRUN_MAC_0 0x00000010 -#define CNET_ERROR_TX_OVERRUN_MAC 0x0000000F -#define CNET_ERROR_TX_OVERRUN_MAC_3 0x00000008 -#define CNET_ERROR_TX_OVERRUN_MAC_2 0x00000004 -#define CNET_ERROR_TX_OVERRUN_MAC_1 0x00000002 -#define CNET_ERROR_TX_OVERRUN_MAC_0 0x00000001 - -/* Enable masks */ -#define CNET_ENABLE_RX_FIFO 0x0000F000 -#define CNET_ENABLE_RX_FIFO_3 0x00008000 -#define CNET_ENABLE_RX_FIFO_2 0x00004000 -#define CNET_ENABLE_RX_FIFO_1 0x00002000 -#define CNET_ENABLE_RX_FIFO_0 0x00001000 -#define CNET_ENABLE_TX_MAC 0x00000F00 -#define CNET_ENABLE_TX_MAC_3 0x00000800 -#define CNET_ENABLE_TX_MAC_2 0x00000400 -#define CNET_ENABLE_TX_MAC_1 0x00000200 -#define CNET_ENABLE_TX_MAC_0 0x00000100 -#define CNET_ENABLE_DEBUG_TRISTATE 0x00000004 -#define CNET_ENABLE_INGRESS_ARBITER 0x00000002 -#define CNET_ENABLE_RX_DMA 0x00000001 - -/* MF Status masks */ -#define CNET_MF_STATUS_RX_FIFO_EMPTY 0x02000000 -#define CNET_MF_STATUS_RX_PKT_AVAIL 0x01000000 -#define CNET_MF_STATUS_RX_NUM_PKTS 0x00FF0000 -#define CNET_MF_STATUS_TX_FIFO_FULL 0x00000200 -#define CNET_MF_STATUS_TX_FIFO_NO_MAX_PKT 0x00000100 -#define CNET_MF_STATUS_TX_NUM_PKTS 0x000000FF - -/* MAC Config masks */ -#define CNET_MAC_CFG_FULL_DUPLEX 0x00000020 -#define CNET_MAC_CFG_TX_FCS_SUPPLIED 0x00000010 -#define CNET_MAC_CFG_RX_WANT_FCS 0x00000008 -#define CNET_MAC_CFG_JUMBO_ENABLE 0x00000004 - -#define CNET_MAC_CFG_SPEED 0x00000002 -#define CNET_MAC_CFG_1000_MBPS 0x00000002 -#define CNET_MAC_CFG_100_MBPS 0x00000001 -#define CNET_MAC_CFG_10_MBPS 0x00000000 - -#define CNET_RXQ_WR_PTR 0x00FF0000 -#define CNET_RXQ_RD_PTR 0x000000FF - - -/* Phy register masks */ -#define PHY_RD_WR 0x80000000 -#define PHY_PHY 0x03000000 -#define PHY_ADDR 0x001F0000 -#define PHY_DATA 0x0000FFFF - -#define PHY_DONE 0x80000000 -#define PHY_DONE_CNT 0x001F0000 - -/* Defines to calculate register values */ -/* CPCI Funcs */ -#define NF2_GET_VERSION(x) (x & 0xFFFFFF) -#define NF2_GET_REVISION(x) ((x & 0xFF000000) >> 24) - -#define NF2_GET_BOARD_ID(x) ((x & BOARD_ID) >> 8) -#define NF2_GET_CONTROL(x) (x & BOARD_ID_CONTROL) - -#define NF2_GET_CNET_RESET(x) ((x & CTRL_CNET_RESET) >> 8) -#define NF2_GET_LED(x) (x & CTRL_LED) - -#define NF2_GET_RESET(x) (x & RESET_CPCI) - -#define NF2_GET_CNET_READ_TIMEOUT(x) ((x & ERR_CNET_READ_TIMEOUT) >> 25) -#define NF2_GET_CNET_ERROR(x) ((x & ERR_CNET_ERROR) >> 24) -#define NF2_GET_PROG_BUF_OVERFLOW(x) ((x & ERR_PROG_BUF_OVERFLOW) >> 12) -#define NF2_GET_PROG_ERROR(x) ((x & ERR_PROG_ERROR) >> 11) -#define NF2_GET_DMA_TIMEOUT(x) ((x & ERR_DMA_TIMEOUT) >> 10) -#define NF2_GET_DMA_RETRY_CNT_EXPIRED(x) \ - ((x & ERR_DMA_RETRY_CNT_EXPIRED) >> 9) -#define NF2_GET_DMA_BUF_OVERFLOW(x) ((x & ERR_DMA_BUF_OVERFLOW) >> 8) -#define NF2_GET_DMA_RD_SIZE_ERROR(x) ((x & ERR_DMA_RD_SIZE_ERROR) >> 6) -#define NF2_GET_DMA_WR_SIZE_ERROR(x) ((x & ERR_DMA_WR_SIZE_ERROR) >> 5) -#define NF2_GET_DMA_RD_ADDR_ERROR(x) ((x & ERR_DMA_RD_ADDR_ERROR) >> 4) -#define NF2_GET_DMA_WR_ADDR_ERROR(x) ((x & ERR_DMA_WR_ADDR_ERROR) >> 3) -#define NF2_GET_DMA_RD_MAC_ERROR(x) ((x & ERR_DMA_RD_MAC_ERROR) >> 2) -#define NF2_GET_DMA_WR_MAC_ERROR(x) ((x & ERR_DMA_WR_MAC_ERROR) >> 1) -#define NF2_GET_DMA_FATAL_ERROR(x) (x & ERR_DMA_FATAL_ERROR) - -#define NF2_GET_INT_DMA_TX_COMPLETE(x) ((x & INT_DMA_TX_COMPLETE) >> 31) -#define NF2_GET_INT_DMA_RX_COMPLETE(x) ((x & INT_DMA_RX_COMPLETE) >> 30) -#define NF2_GET_INT_PHY_INTERRUPT(x) ((x & INT_PHY_INTERRUPT) >> 29) -#define NF2_GET_INT_PKT_AVAIL(x) ((x & INT_PKT_AVAIL) >> 8) -#define NF2_GET_INT_CNET_ERROR(x) ((x & INT_CNET_ERROR) >> 5) -#define NF2_GET_INT_CNET_READ_TIMEOUT(x) \ - ((x & INT_CNET_READ_TIMEOUT) >> 4) -#define NF2_GET_INT_PROG_ERROR(x) ((x & INT_PROG_ERROR) >> 3) -#define NF2_GET_INT_DMA_TRANSFER_ERROR(x) \ - ((x & INT_DMA_TRANSFER_ERROR) >> 2) -#define NF2_GET_INT_DMA_SETUP_ERROR(x) ((x & INT_DMA_SETUP_ERROR) >> 1) -#define NF2_GET_INT_DMA_FATAL_ERROR(x) (x & INT_DMA_FATAL_ERROR) - -#define NF2_GET_PROG_INIT(x) ((x & PROG_INIT) >> 16) -#define NF2_GET_PROG_DONE(x) ((x & PROG_DONE) >> 8) -#define NF2_GET_PROG_FIFO_EMPTY(x) ((x & PROG_FIFO_EMPTY) >> 1) -#define NF2_GET_PROG_IN_PROGRESS(x) (x & PROG_IN_PROGRESS) - -#define NF2_GET_DMA_CTRL_MAC(x) ((x & DMA_CTRL_MAC) >> 8) -#define NF2_GET_DMA_CTRL_OWNER(x) (x & DMA_CTRL_OWNER) - -#define NF2_SET_DMA_CTRL_MAC(x) (x << 8) - - -/* CNET Funcs */ -#define NF2_GET_CNET_VERSION(x) ((x & 0xFFFF0000) >> 16) -#define NF2_GET_CNET_DEVICE_ID(x) (x & 0xFFFF) - -#define NF2_GET_CNET_RESET_MAC(x) (x & CNET_RESET_MAC) - -#define NF2_GET_CNET_ERROR_TX_UNDERRUN_MAC(x) \ - ((x & CNET_ERROR_TX_UNDERRUN_MAC) >> 4) -#define NF2_GET_CNET_ERROR_TX_OVERRUN_MAC(x) \ - (x & CNET_ERROR_TX_OVERRUN_MAC) - -#define NF2_GET_CNET_ENABLE_RX_FIFO(x) ((x & CNET_ENABLE_RX_FIFO) >> 12) -#define NF2_GET_CNET_ENABLE_TX_MAC(x) ((x & CNET_ENABLE_TX_MAC) >> 8) -#define NF2_GET_CNET_ENABLE_DEBUG_TRISTATE(x) \ - ((x & CNET_ENABLE_DEBUG_TRISTATE) >> 2) -#define NF2_GET_CNET_ENABLE_INGRESS_ARBITER(x) \ - ((x & CNET_ENABLE_INGRESS_ARBITER) >> 1) -#define NF2_GET_CNET_ENABLE_RX_DMA(x) (x & CNET_ENABLE_RX_DMA) - -#define NF2_GET_CNET_MF_STATUS_RX_FIFO_EMPTY(x) \ - ((x & CNET_MF_STATUS_RX_FIFO_EMPTY) >> 25) -#define NF2_GET_CNET_MF_STATUS_RX_PKT_AVAIL(x) \ - ((x & CNET_MF_STATUS_RX_PKT_AVAIL) >> 24) -#define NF2_GET_CNET_MF_STATUS_RX_NUM_PKTS(x) \ - ((x & CNET_MF_STATUS_RX_NUM_PKTS) >> 16) -#define NF2_GET_CNET_MF_STATUS_TX_FIFO_FULL(x) \ - ((x & CNET_MF_STATUS_TX_FIFO_FULL) >> 9) -#define NF2_GET_CNET_MF_STATUS_TX_FIFO_NO_MAX_PKT(x) \ - ((x & CNET_MF_STATUS_TX_FIFO_NO_MAX_PKT) >> 8) -#define NF2_GET_CNET_MF_STATUS_TX_NUM_PKTS(x) \ - (x & CNET_MF_STATUS_TX_NUM_PKTS) - -#define NF2_GET_CNET_MAC_CFG_FULL_DUPLEX(x) \ - ((x & CNET_MAC_CFG_FULL_DUPLEX) >> 5) -#define NF2_GET_CNET_MAC_CFG_TX_FCS_SUPPLIED(x) \ - ((x & CNET_MAC_CFG_TX_FCS_SUPPLIED) >> 4) -#define NF2_GET_CNET_MAC_CFG_RX_WANT_FCS(x) \ - ((x & CNET_MAC_CFG_RX_WANT_FCS) >> 3) -#define NF2_GET_CNET_MAC_CFG_JUMBO_ENABLE(x) \ - ((x & CNET_MAC_CFG_JUMBO_ENABLE) >> 2) -#define NF2_GET_CNET_MAC_CFG_SPEED(x) \ - (x & CNET_MAC_CFG_SPEED) - -#define NF2_GET_CNET_RXQ_WR_PTR(x) ((x & CNET_RXQ_WR_PTR) >> 16) -#define NF2_GET_CNET_RXQ_RD_PTR(x) (x & CNET_RXQ_RD_PTR) - - -/* PHY functions */ -#define NF2_SET_PHY_IS_READ(x) (x << 31) -#define NF2_SET_PHY_SELECT(x) (x << 24) -#define NF2_SET_PHY_ADDR(x) (x << 16) -#define NF2_SET_PHY_DATA(x) (x) - -#define NF2_GET_PHY_DATA(x) (x & PHY_DATA) -#define NF2_GET_PHY_DONE(x) ((x & PHY_DONE) >> 31) -#define NF2_GET_PHY_DONE_CNT(x) ((x & PHY_DONE_CNT) >> 16) - - -/* - * IOCTLs - */ -#define SIOCREGREAD SIOCDEVPRIVATE -#define SIOCREGWRITE (SIOCDEVPRIVATE + 1) - - -/* MDIO registers */ -#define MDIO_0_AUX_STATUS 0x04c0064 -#define MDIO_0_INTR_STATUS 0x04c0068 -#define MDIO_0_INTR_MASK 0x04c006c - - -/* MDIO address delta between each phy base address */ -#define ADDRESS_DELTA 0x80 - - -/* MDIO bit positions */ -#define INTR_LINK_STATUS_POS 0x2 -#define AUX_LINK_STATUS_POS 0x4 - - -/* - * Structure for transferring register data via an IOCTL - */ -struct nf2reg { - unsigned int reg; - unsigned int val; -}; - -#endif diff --git a/openflow/hw-lib/nf2/nf2_drv.c b/openflow/hw-lib/nf2/nf2_drv.c deleted file mode 100644 index 36f3de1a..00000000 --- a/openflow/hw-lib/nf2/nf2_drv.c +++ /dev/null @@ -1,847 +0,0 @@ -/*- - * Copyright (c) 2008, 2009, 2010 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#include -#include -#include - -#include "udatapath/switch-flow.h" -#include "udatapath/table.h" -#include "timeval.h" -#include "reg_defines_openflow_switch.h" -#include "nf2.h" -#include "nf2util.h" -#include "hw_flow.h" -#include "nf2_drv.h" -#include "nf2_lib.h" -#include "debug.h" - -static void log_entry(nf2_of_entry_wrap *); -static void log_entry_raw(nf2_of_entry_wrap *); -static void log_mask(nf2_of_mask_wrap *); -static void log_mask_raw(nf2_of_mask_wrap *); -static void log_action(nf2_of_action_wrap *); -static void log_action_raw(nf2_of_action_wrap *); -static void log_watchdog_info(struct nf2device *); -static void nf2_get_all_ports_info_addr(struct nf2_all_ports_info_addr *); - -static void -log_entry(nf2_of_entry_wrap *entry) -{ - int i; - - DBG_VERBOSE("log entry\n"); -#ifdef HWTABLE_NO_DEBUG - return; -#else - - // Log the physical source port - DBG_VERBOSE("E psrc[%i] ", entry->entry.src_port / 2); - - // Log the link layer source - DBG_VERBOSE("dlsrc["); - for (i = 5; i > 0; --i) { - DBG_VERBOSE("%0X:", entry->entry.eth_src[i]); - } - DBG_VERBOSE("%0X] ", entry->entry.eth_src[0]); - - // Log the link layer dest - DBG_VERBOSE("dldst["); - for (i = 5; i > 0; --i) { - DBG_VERBOSE("%0X:", entry->entry.eth_dst[i]); - } - DBG_VERBOSE("%0X] ", entry->entry.eth_dst[0]); - - // Log the link layer type - DBG_VERBOSE("dltype[%0X] ", entry->entry.eth_type); - - // Log the link layer vlan - DBG_VERBOSE("dlvlan[%0X] ", entry->entry.vlan_id); - - // Log the network source - DBG_VERBOSE("nwsrc["); - DBG_VERBOSE("%0i.", (entry->entry.ip_src >> 24) & 0xFF); - DBG_VERBOSE("%0i.", (entry->entry.ip_src >> 16) & 0xFF); - DBG_VERBOSE("%0i.", (entry->entry.ip_src >> 8) & 0xFF); - DBG_VERBOSE("%0i", entry->entry.ip_src & 0xFF); - DBG_VERBOSE("] "); - - // Log the network dest - DBG_VERBOSE("nwdst["); - DBG_VERBOSE("%0i.", (entry->entry.ip_dst >> 24) & 0xFF); - DBG_VERBOSE("%0i.", (entry->entry.ip_dst >> 16) & 0xFF); - DBG_VERBOSE("%0i.", (entry->entry.ip_dst >> 8) & 0xFF); - DBG_VERBOSE("%0i", entry->entry.ip_dst & 0xFF); - DBG_VERBOSE("] "); - - // Log the network TOS - DBG_VERBOSE("nwtos[0x%0X] ", entry->entry.ip_tos); - - // Log the transport source port - DBG_VERBOSE("tsrc[%i] ", entry->entry.transp_src); - - // Log the transport dest port - DBG_VERBOSE("tdst[%i]\n", entry->entry.transp_dst); -#endif -} - -static void -log_entry_raw(nf2_of_entry_wrap *entry) -{ -#ifdef HWTABLE_NO_DEBUG - return; -#else - int i; - unsigned char *c; - - DBG_VERBOSE("E "); - c = (unsigned char *)entry; - for (i = 0; i < sizeof(nf2_of_entry_wrap); ++i) { - if (!(i % 4)) { - DBG_VERBOSE(" "); - } - DBG_VERBOSE("%02x", c[i]); - } - DBG_VERBOSE("\n"); -#endif -} - -static void -log_mask(nf2_of_mask_wrap *mask) -{ -#ifdef HWTABLE_NO_DEBUG - return; -#else - int i; - - // Log the physical source port - DBG_VERBOSE("M psrc[%0X] ", mask->entry.src_port / 2); - - // Log the link layer source - DBG_VERBOSE("dlsrc["); - for (i = 5; i > 0; --i) { - DBG_VERBOSE("%0X:", mask->entry.eth_src[i]); - } - DBG_VERBOSE("%0X] ", mask->entry.eth_src[0]); - - // Log the link layer dest - DBG_VERBOSE("dldst["); - for (i = 5; i > 0; --i) { - DBG_VERBOSE("%0X:", mask->entry.eth_dst[i]); - } - DBG_VERBOSE("%0X] ", mask->entry.eth_dst[0]); - - // Log the link layer type - DBG_VERBOSE("dltype[%0X] ", mask->entry.eth_type); - - // Log the link layer vlan - DBG_VERBOSE("dlvlan[%0X] ", mask->entry.vlan_id); - - // Log the network source - DBG_VERBOSE("nwsrc["); - DBG_VERBOSE("%0X.", (mask->entry.ip_src >> 24) & 0xFF); - DBG_VERBOSE("%0X.", (mask->entry.ip_src >> 16) & 0xFF); - DBG_VERBOSE("%0X.", (mask->entry.ip_src >> 8) & 0xFF); - DBG_VERBOSE("%0X", mask->entry.ip_src & 0xFF); - DBG_VERBOSE("] "); - - // Log the network dest - DBG_VERBOSE("nwdst["); - DBG_VERBOSE("%0X.", (mask->entry.ip_dst >> 24) & 0xFF); - DBG_VERBOSE("%0X.", (mask->entry.ip_dst >> 16) & 0xFF); - DBG_VERBOSE("%0X.", (mask->entry.ip_dst >> 8) & 0xFF); - DBG_VERBOSE("%0X", mask->entry.ip_dst & 0xFF); - DBG_VERBOSE("] "); - - // Log the network TOS - DBG_VERBOSE("nwtos[0x%0X] ", mask->entry.ip_tos); - - // Log the transport source port - DBG_VERBOSE("tsrc[%0X] ", mask->entry.transp_src); - - // Log the transport dest port - DBG_VERBOSE("tdst[%0X]\n", mask->entry.transp_dst); -#endif -} - -static void -log_mask_raw(nf2_of_mask_wrap *mask) -{ -#ifdef HWTABLE_NO_DEBUG - return; -#else - int i; - unsigned char *c; - - DBG_VERBOSE("M "); - c = (unsigned char *)mask; - for (i = 0; i < sizeof(nf2_of_mask_wrap); ++i) { - if (!(i % 4)) { - DBG_VERBOSE(" "); - } - DBG_VERBOSE("%02x", c[i]); - } - DBG_VERBOSE("\n"); -#endif -} - -static void -log_action(nf2_of_action_wrap *action) -{ -#ifdef HWTABLE_NO_DEBUG - return; -#else - int i; - - DBG_VERBOSE("A Output P["); - for (i = 0; i < 4; ++i) { - if (action->action.forward_bitmask & (1 << (i * 2))) { - DBG_VERBOSE("%i", i); - } - } - DBG_VERBOSE("] CPU["); - for (i = 0; i < 4; ++i) { - if (action->action.forward_bitmask & (1 << (1 + (i * 2)))) { - DBG_VERBOSE("%i", i); - } - } - DBG_VERBOSE("]\n"); - - // Log the link layer source - if (action->action.nf2_action_flag & (1 << OFPAT_SET_DL_SRC)) { - DBG_VERBOSE("A Modify: dlsrc: new value ["); - for (i = 5; i > 0; --i) { - DBG_VERBOSE("%0X:", action->action.eth_src[i]); - } - DBG_VERBOSE("%0X]\n", action->action.eth_src[0]); - } - - // Log the link layer dest - if (action->action.nf2_action_flag & (1 << OFPAT_SET_DL_DST)) { - DBG_VERBOSE("A Modify: dldst: new value ["); - for (i = 5; i > 0; --i) { - DBG_VERBOSE("%0X:", action->action.eth_dst[i]); - } - DBG_VERBOSE("%0X]\n", action->action.eth_dst[0]); - } - - // Log the link layer vlan id - if (action->action.nf2_action_flag & (1 << OFPAT_SET_VLAN_VID)) { - DBG_VERBOSE("A Modify: dlvlanid: new value [%0X]\n", - action->action.vlan_id); - } - - // Log the link layer vlan pcp - if (action->action.nf2_action_flag & (1 << OFPAT_SET_VLAN_PCP)) { - DBG_VERBOSE("A Modify: dlvlanpcp: new value [%0X]\n", - action->action.vlan_pcp); - } - - // Log the link layer vlan strip - if (action->action.nf2_action_flag & (1 << OFPAT_STRIP_VLAN)) { - DBG_VERBOSE("A Modify: dlvlan strip\n"); - } - - // Log the network source - if (action->action.nf2_action_flag & (1 << OFPAT_SET_NW_SRC)) { - DBG_VERBOSE("A Modify: nwsrc: new value ["); - DBG_VERBOSE("%0i.", (action->action.ip_src >> 24) & 0xFF); - DBG_VERBOSE("%0i.", (action->action.ip_src >> 16) & 0xFF); - DBG_VERBOSE("%0i.", (action->action.ip_src >> 8) & 0xFF); - DBG_VERBOSE("%0i", action->action.ip_src & 0xFF); - DBG_VERBOSE("]\n"); - } - - // Log the network dest - if (action->action.nf2_action_flag & (1 << OFPAT_SET_NW_DST)) { - DBG_VERBOSE("A Modify: nwdst: new value ["); - DBG_VERBOSE("%0i.", (action->action.ip_dst >> 24) & 0xFF); - DBG_VERBOSE("%0i.", (action->action.ip_dst >> 16) & 0xFF); - DBG_VERBOSE("%0i.", (action->action.ip_dst >> 8) & 0xFF); - DBG_VERBOSE("%0i", action->action.ip_dst & 0xFF); - DBG_VERBOSE("]\n"); - } - - // Log the network TOS - if (action->action.nf2_action_flag & (1 << OFPAT_SET_NW_TOS)) { - DBG_VERBOSE("A Modify: nwtos: new value [%0X]\n", - action->action.ip_tos & 0xFF); - } - - // Log the transport source port - if (action->action.nf2_action_flag & (1 << OFPAT_SET_TP_SRC)) { - DBG_VERBOSE("A Modify: tsrc: new value [%0X]\n", - action->action.transp_src); - } - - // Log the transport dest port - if (action->action.nf2_action_flag & (1 << OFPAT_SET_TP_DST)) { - DBG_VERBOSE("A Modify: tdst: new value [%0X]\n", - action->action.transp_dst); - } -#endif -} - -static void -log_action_raw(nf2_of_action_wrap *action) -{ -#ifdef HWTABLE_NO_DEBUG - return; -#else - int i; - unsigned char *c; - - DBG_VERBOSE("A "); - c = (unsigned char *)action; - for (i = 0; i < sizeof(nf2_of_action_wrap); ++i) { - if (!(i % 4)) { - DBG_VERBOSE(" "); - } - DBG_VERBOSE("%02x", c[i]); - } - DBG_VERBOSE("\n"); -#endif -} - -void -nf2_reset_card(struct nf2device *dev) -{ - volatile unsigned int val; - - /* If we are operating on a NetFPGA enabled box, reset the card */ - readReg(dev, CPCI_REG_CTRL, (void *)&val); - val |= 0x100; - writeReg(dev, CPCI_REG_CTRL, val); - DBG_VERBOSE("Reset the NetFPGA.\n"); - sleep(2); -} - -void -nf2_clear_watchdog(struct nf2device *dev) -{ - volatile unsigned int enable_status; - -#ifndef NF2_WATCHDOG - return; -#endif - log_watchdog_info(dev); - - readReg(dev, WDT_ENABLE_FLG_REG, (void *)&enable_status); - enable_status &= 0x1; - - if (enable_status == WATCHDOG_DISABLE) { - enable_status = WATCHDOG_ENABLE; - writeReg(dev, WDT_ENABLE_FLG_REG, enable_status); - } -} - -/* Write a wildcard entry to the specified device and row. The row consists of - * the actual entry, its mask that specifies wildcards, as well as the action(s) - * to be taken if the row is matched - */ -int -nf2_write_of_wildcard(struct nf2device *dev, int row, - nf2_of_entry_wrap *entry, nf2_of_mask_wrap *mask, - nf2_of_action_wrap *action) -{ - int i; - unsigned int val; - - DBG_VERBOSE("** Begin wildcard entry write to row: %i\n", row); - log_entry(entry); - log_mask(mask); - log_action(action); - log_entry_raw(entry); - log_mask_raw(mask); - log_action_raw(action); - - for (i = 0; i < NF2_OF_ENTRY_WORD_LEN; ++i) { - writeReg(dev, - OPENFLOW_WILDCARD_LOOKUP_CMP_0_REG - + (4 * i), entry->raw[i]); - } - - for (i = 0; i < NF2_OF_MASK_WORD_LEN; ++i) { - writeReg(dev, - OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_0_REG - + (4 * i), mask->raw[i]); - } - - for (i = 0; i < NF2_OF_ACTION_WORD_LEN; ++i) { - writeReg(dev, - OPENFLOW_WILDCARD_LOOKUP_ACTION_0_REG - + (4 * i), action->raw[i]); - } - - // Reset the stats for the row - val = 0; - writeReg(dev, - OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG + (4 * row), - val); - writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG + (4 * row), - val); - writeReg(dev, - OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_0_REG + (4 * row), - val); - writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_WRITE_ADDR_REG, row); - - DBG_VERBOSE("** End wildcard entry write to row: %i time(msec): %llu\n", - row, time_msec()); - - return 0; -} - -int -nf2_write_of_exact(struct nf2device *dev, int row, - nf2_of_entry_wrap *entry, nf2_of_action_wrap *action) -{ - int i; - unsigned int val; - unsigned int index = row << 7; - - DBG_VERBOSE("** Begin exact match entry write to row: %i\n", row); - log_entry(entry); - log_action(action); - log_entry_raw(entry); - log_action_raw(action); - - for (i = 0; i < NF2_OF_ENTRY_WORD_LEN; ++i) { - writeReg(dev, SRAM_BASE_ADDR + index - + (4 * i), entry->raw[i]); - } - - // blank out the counters - val = 0; - for (i = 0; i < NF2_OF_EXACT_COUNTERS_WORD_LEN; ++i) { - writeReg(dev, SRAM_BASE_ADDR + index - + sizeof(nf2_of_entry_wrap) - + (4 * i), val); - } - - // write the actions - for (i = 0; i < NF2_OF_ACTION_WORD_LEN; ++i) { - writeReg(dev, SRAM_BASE_ADDR + index - + sizeof(nf2_of_entry_wrap) - + sizeof(nf2_of_exact_counters_wrap) - + (4 * i), action->raw[i]); - } - - DBG_VERBOSE - ("** End exact match entry write to row: %i time(msec): %llu\n", - row, time_msec()); - - return 0; -} - -/* Write wildcard action(s) to the specified device and row. */ -int -nf2_modify_write_of_wildcard(struct nf2device *dev, int row, - nf2_of_entry_wrap *entry, nf2_of_mask_wrap *mask, - nf2_of_action_wrap *action) -{ - int i; - unsigned int bytes_reg_val; - unsigned int pkts_reg_val; - unsigned int last_reg_val; - - DBG_VERBOSE("** Begin wildcard modified action write to row: %i\n", - row); - log_entry(entry); - log_mask(mask); - log_action(action); - log_entry_raw(entry); - log_mask_raw(mask); - log_action_raw(action); - - writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_READ_ADDR_REG, row); - readReg(dev, - OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG + (4 * row), - &bytes_reg_val); - readReg(dev, - OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG + (4 * row), - &pkts_reg_val); - readReg(dev, - OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_0_REG + (4 * row), - &last_reg_val); - - for (i = 0; i < NF2_OF_ENTRY_WORD_LEN; ++i) { - writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_CMP_0_REG - + (4 * i), entry->raw[i]); - } - - for (i = 0; i < NF2_OF_MASK_WORD_LEN; ++i) { - writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_0_REG - + (4 * i), mask->raw[i]); - } - - for (i = 0; i < NF2_OF_ACTION_WORD_LEN; ++i) { - writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_ACTION_0_REG - + (4 * i), action->raw[i]); - } - - writeReg(dev, - OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG + (4 * row), - bytes_reg_val); - writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG + (4 * row), - pkts_reg_val); - writeReg(dev, - OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_0_REG + (4 * row), - last_reg_val); - writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_WRITE_ADDR_REG, row); - - DBG_VERBOSE - ("** End wildcard modified action write to row: %i time(msec): %llu\n", - row, time_msec()); - DBG_VERBOSE(" Bytes hit count: %d\n", bytes_reg_val); - DBG_VERBOSE(" Pkts hit count: %d\n", pkts_reg_val); - DBG_VERBOSE(" Last seen : %d\n", last_reg_val); - - return 0; -} - -int -nf2_modify_write_of_exact(struct nf2device *dev, int row, - nf2_of_action_wrap *action) -{ - int i; - unsigned int index = row << 7; - - DBG_VERBOSE("** Begin exact match modified action write to row: %i\n", - row); - log_action(action); - log_action_raw(action); - - // write the actions - for (i = 0; i < NF2_OF_ACTION_WORD_LEN; ++i) { - writeReg(dev, SRAM_BASE_ADDR + index - + sizeof(nf2_of_entry_wrap) - + sizeof(nf2_of_exact_counters_wrap) - + (4 * i), action->raw[i]); - } - - DBG_VERBOSE - ("** End exact match modified action write to row: %i time(msec): %llu\n", - row, time_msec()); - - return 0; -} - -unsigned int -nf2_get_exact_packet_count(struct nf2device *dev, int row) -{ - unsigned int val = 0; - unsigned int index = 0; - - /* TODO: Need to scrape data from all 4 registers - * in the case of a wildcarded source port and - * forward all action type - */ - nf2_of_exact_counters_wrap counters; - memset(&counters, 0, sizeof(nf2_of_exact_counters_wrap)); - - // build the index to our counters - index = row << 7; - - // Read the first word into our struct, to not disturb the byte count - readReg(dev, - SRAM_BASE_ADDR + index + sizeof(nf2_of_entry_wrap), - &counters.raw[0]); - val = counters.counters.pkt_count; - - DBG_VERBOSE - ("** Exact match packet count(delta) row: %i count: %i time(msec): %llu\n", - row, val, time_msec()); - - return val; -} - -unsigned int -nf2_get_exact_byte_count(struct nf2device *dev, int row) -{ - unsigned int val = 0; - unsigned int index = 0; - - /* TODO: Need to scrape data from all 4 registers - * in the case of a wildcarded source port and - * forward all action type - */ - nf2_of_exact_counters_wrap counters; - memset(&counters, 0, sizeof(nf2_of_exact_counters_wrap)); - - // build the index to our counters - index = row << 7; - - // Read the second word into our struct, to not disturb the packet count - readReg(dev, SRAM_BASE_ADDR + index + - sizeof(nf2_of_entry_wrap) + 4, &counters.raw[1]); - val = counters.counters.byte_count; - - DBG_VERBOSE - ("** Exact match byte count(delta) row: %i count: %i time(msec): %llu\n", - row, val, time_msec()); - - return val; -} - -unsigned int -nf2_get_wildcard_packet_count(struct nf2device *dev, int row) -{ - unsigned int val = 0; - - writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_READ_ADDR_REG, row); - readReg(dev, OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG - + (4 * row), &val); - - DBG_VERBOSE - ("** Wildcard packet count(sum) row: %i count: %i time(msec): %llu\n", - row, val, time_msec()); - - return val; -} - -unsigned int -nf2_get_wildcard_byte_count(struct nf2device *dev, int row) -{ - unsigned int val = 0; - - writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_READ_ADDR_REG, row); - readReg(dev, OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG - + (4 * row), &val); - - DBG_VERBOSE - ("** Wildcard byte count(sum) row: %i count: %i time(msec): %llu\n", - row, val, time_msec()); - - return val; -} - -unsigned long int -nf2_get_matched_count(struct nf2device *dev) -{ - unsigned int val_wild = 0; - unsigned int val_exact = 0; - - readReg(dev, OPENFLOW_LOOKUP_WILDCARD_HITS_REG, &val_wild); - readReg(dev, OPENFLOW_LOOKUP_EXACT_HITS_REG, &val_exact); - - DBG_VERBOSE("** Wildcard Matched count: %i time(msec): %llu\n", - val_wild, time_msec()); - DBG_VERBOSE("** Exact Matched count: %i time(msec): %llu\n", - val_exact, time_msec()); - - return ((unsigned long int)(val_wild + val_exact)); -} - -unsigned long int -nf2_get_missed_count(struct nf2device *dev) -{ - unsigned int val_wild = 0; - unsigned int val_exact = 0; - - readReg(dev, OPENFLOW_LOOKUP_WILDCARD_MISSES_REG, &val_wild); - readReg(dev, OPENFLOW_LOOKUP_EXACT_MISSES_REG, &val_exact); - - DBG_VERBOSE("** Wildcard Missed count: %i time(msec): %llu\n", - val_wild, time_msec()); - DBG_VERBOSE("** Exact Missed count: %i time(msec): %llu\n", - val_exact, time_msec()); - - return ((unsigned long int)(val_wild + val_exact)); -} - -static void -log_watchdog_info(struct nf2device *dev) -{ -#ifdef HWTABLE_NO_DEBUG - return; -#else -#define CLK_CYCLE 8 - unsigned int nf2wdtinfo; - unsigned int elapsed_time; - readReg(dev, WDT_COUNTER_REG, &nf2wdtinfo); - elapsed_time = nf2wdtinfo * CLK_CYCLE / 1000000; - DBG_VVERB - ("%u (msec) passed since the watchdog counter has been cleared last time\n", - elapsed_time); - DBG_VVERB("NetFPGA WDT now clearing\n"); -#endif -} - -static void -nf2_get_all_ports_info_addr(struct nf2_all_ports_info_addr *nf2addr) -{ - nf2addr->rx_q_num_pkts_stored_reg[0] - = MAC_GRP_0_RX_QUEUE_NUM_PKTS_STORED_REG; - nf2addr->rx_q_num_pkts_dropped_full_reg[0] - = MAC_GRP_0_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG; - nf2addr->rx_q_num_pkts_dropped_bad_reg[0] - = MAC_GRP_0_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG; - nf2addr->rx_q_num_words_pushed_reg[0] - = MAC_GRP_0_RX_QUEUE_NUM_WORDS_PUSHED_REG; - nf2addr->rx_q_num_bytes_pushed_reg[0] - = MAC_GRP_0_RX_QUEUE_NUM_BYTES_PUSHED_REG; - nf2addr->rx_q_num_pkts_dequeued_reg[0] - = MAC_GRP_0_RX_QUEUE_NUM_PKTS_DEQUEUED_REG; - nf2addr->rx_q_num_pkts_in_queue_reg[0] - = MAC_GRP_0_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG; - nf2addr->tx_q_num_pkts_in_queue_reg[0] - = MAC_GRP_0_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG; - nf2addr->tx_q_num_pkts_sent_reg[0] - = MAC_GRP_0_TX_QUEUE_NUM_PKTS_SENT_REG; - nf2addr->tx_q_num_words_pushed_reg[0] - = MAC_GRP_0_TX_QUEUE_NUM_WORDS_PUSHED_REG; - nf2addr->tx_q_num_bytes_pushed_reg[0] - = MAC_GRP_0_TX_QUEUE_NUM_BYTES_PUSHED_REG; - nf2addr->tx_q_num_pkts_enqueued_reg[0] - = MAC_GRP_0_TX_QUEUE_NUM_PKTS_ENQUEUED_REG; - - nf2addr->rx_q_num_pkts_stored_reg[1] - = MAC_GRP_1_RX_QUEUE_NUM_PKTS_STORED_REG; - nf2addr->rx_q_num_pkts_dropped_full_reg[1] - = MAC_GRP_1_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG; - nf2addr->rx_q_num_pkts_dropped_bad_reg[1] - = MAC_GRP_1_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG; - nf2addr->rx_q_num_words_pushed_reg[1] - = MAC_GRP_1_RX_QUEUE_NUM_WORDS_PUSHED_REG; - nf2addr->rx_q_num_bytes_pushed_reg[1] - = MAC_GRP_1_RX_QUEUE_NUM_BYTES_PUSHED_REG; - nf2addr->rx_q_num_pkts_dequeued_reg[1] - = MAC_GRP_1_RX_QUEUE_NUM_PKTS_DEQUEUED_REG; - nf2addr->rx_q_num_pkts_in_queue_reg[1] - = MAC_GRP_1_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG; - nf2addr->tx_q_num_pkts_in_queue_reg[1] - = MAC_GRP_1_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG; - nf2addr->tx_q_num_pkts_sent_reg[1] - = MAC_GRP_1_TX_QUEUE_NUM_PKTS_SENT_REG; - nf2addr->tx_q_num_words_pushed_reg[1] - = MAC_GRP_1_TX_QUEUE_NUM_WORDS_PUSHED_REG; - nf2addr->tx_q_num_bytes_pushed_reg[1] - = MAC_GRP_1_TX_QUEUE_NUM_BYTES_PUSHED_REG; - nf2addr->tx_q_num_pkts_enqueued_reg[1] - = MAC_GRP_1_TX_QUEUE_NUM_PKTS_ENQUEUED_REG; - - nf2addr->rx_q_num_pkts_stored_reg[2] - = MAC_GRP_2_RX_QUEUE_NUM_PKTS_STORED_REG; - nf2addr->rx_q_num_pkts_dropped_full_reg[2] - = MAC_GRP_2_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG; - nf2addr->rx_q_num_pkts_dropped_bad_reg[2] - = MAC_GRP_2_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG; - nf2addr->rx_q_num_words_pushed_reg[2] - = MAC_GRP_2_RX_QUEUE_NUM_WORDS_PUSHED_REG; - nf2addr->rx_q_num_bytes_pushed_reg[2] - = MAC_GRP_2_RX_QUEUE_NUM_BYTES_PUSHED_REG; - nf2addr->rx_q_num_pkts_dequeued_reg[2] - = MAC_GRP_2_RX_QUEUE_NUM_PKTS_DEQUEUED_REG; - nf2addr->rx_q_num_pkts_in_queue_reg[2] - = MAC_GRP_2_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG; - nf2addr->tx_q_num_pkts_in_queue_reg[2] - = MAC_GRP_2_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG; - nf2addr->tx_q_num_pkts_sent_reg[2] - = MAC_GRP_2_TX_QUEUE_NUM_PKTS_SENT_REG; - nf2addr->tx_q_num_words_pushed_reg[2] - = MAC_GRP_2_TX_QUEUE_NUM_WORDS_PUSHED_REG; - nf2addr->tx_q_num_bytes_pushed_reg[2] - = MAC_GRP_2_TX_QUEUE_NUM_BYTES_PUSHED_REG; - nf2addr->tx_q_num_pkts_enqueued_reg[2] - = MAC_GRP_2_TX_QUEUE_NUM_PKTS_ENQUEUED_REG; - - nf2addr->rx_q_num_pkts_stored_reg[3] - = MAC_GRP_3_RX_QUEUE_NUM_PKTS_STORED_REG; - nf2addr->rx_q_num_pkts_dropped_full_reg[3] - = MAC_GRP_3_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG; - nf2addr->rx_q_num_pkts_dropped_bad_reg[3] - = MAC_GRP_3_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG; - nf2addr->rx_q_num_words_pushed_reg[3] - = MAC_GRP_3_RX_QUEUE_NUM_WORDS_PUSHED_REG; - nf2addr->rx_q_num_bytes_pushed_reg[3] - = MAC_GRP_3_RX_QUEUE_NUM_BYTES_PUSHED_REG; - nf2addr->rx_q_num_pkts_dequeued_reg[3] - = MAC_GRP_3_RX_QUEUE_NUM_PKTS_DEQUEUED_REG; - nf2addr->rx_q_num_pkts_in_queue_reg[3] - = MAC_GRP_3_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG; - nf2addr->tx_q_num_pkts_in_queue_reg[3] - = MAC_GRP_3_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG; - nf2addr->tx_q_num_pkts_sent_reg[3] - = MAC_GRP_3_TX_QUEUE_NUM_PKTS_SENT_REG; - nf2addr->tx_q_num_words_pushed_reg[3] - = MAC_GRP_3_TX_QUEUE_NUM_WORDS_PUSHED_REG; - nf2addr->tx_q_num_bytes_pushed_reg[3] - = MAC_GRP_3_TX_QUEUE_NUM_BYTES_PUSHED_REG; - nf2addr->tx_q_num_pkts_enqueued_reg[3] - = MAC_GRP_3_TX_QUEUE_NUM_PKTS_ENQUEUED_REG; -} - -int -nf2_get_port_info(struct nf2device *dev, int nf_port, - struct nf2_port_info *nf2portinfo) -{ - struct nf2_all_ports_info_addr *nf2addr; - - if ((nf_port >= NF2_PORT_NUM) || (nf_port < 0)) { - DBG_ERROR("Illegal port number\n"); - return 1; - } - - nf2addr = calloc(1, sizeof(struct nf2_all_ports_info_addr)); - if (nf2addr == NULL) { - DBG_ERROR("Could not allocate memory for port information gathering\n"); - return 1; - } - nf2_get_all_ports_info_addr(nf2addr); - - readReg(dev, nf2addr->rx_q_num_pkts_stored_reg[nf_port], - &(nf2portinfo->rx_q_num_pkts_stored)); - readReg(dev, nf2addr->rx_q_num_pkts_dropped_full_reg[nf_port], - &(nf2portinfo->rx_q_num_pkts_dropped_full)); - readReg(dev, nf2addr->rx_q_num_pkts_dropped_bad_reg[nf_port], - &(nf2portinfo->rx_q_num_pkts_dropped_bad)); - readReg(dev, nf2addr->rx_q_num_words_pushed_reg[nf_port], - &(nf2portinfo->rx_q_num_words_pushed)); - readReg(dev, nf2addr->rx_q_num_bytes_pushed_reg[nf_port], - &(nf2portinfo->rx_q_num_bytes_pushed)); - readReg(dev, nf2addr->rx_q_num_pkts_dequeued_reg[nf_port], - &(nf2portinfo->rx_q_num_pkts_dequeued)); - readReg(dev, nf2addr->rx_q_num_pkts_in_queue_reg[nf_port], - &(nf2portinfo->rx_q_num_pkts_in_queue)); - readReg(dev, nf2addr->tx_q_num_pkts_in_queue_reg[nf_port], - &(nf2portinfo->tx_q_num_pkts_in_queue)); - readReg(dev, nf2addr->tx_q_num_pkts_sent_reg[nf_port], - &(nf2portinfo->tx_q_num_pkts_sent)); - readReg(dev, nf2addr->tx_q_num_words_pushed_reg[nf_port], - &(nf2portinfo->tx_q_num_words_pushed)); - readReg(dev, nf2addr->tx_q_num_bytes_pushed_reg[nf_port], - &(nf2portinfo->tx_q_num_bytes_pushed)); - readReg(dev, nf2addr->tx_q_num_pkts_enqueued_reg[nf_port], - &(nf2portinfo->tx_q_num_pkts_enqueued)); - free(nf2addr); - return 0; -} diff --git a/openflow/hw-lib/nf2/nf2_drv.h b/openflow/hw-lib/nf2/nf2_drv.h deleted file mode 100644 index 6f961267..00000000 --- a/openflow/hw-lib/nf2/nf2_drv.h +++ /dev/null @@ -1,150 +0,0 @@ -/*- - * Copyright (c) 2008, 2009, 2010 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#ifndef HATABLE_NF2_NF2_OPENFLOW_H_ -#define HATABLE_NF2_NF2_OPENFLOW_H_ - -#define OPENFLOW_NF2_EXACT_TABLE_SIZE 32768 -#define WATCHDOG_ENABLE 1 -#define WATCHDOG_DISABLE 0 - -#pragma pack(push) /* push current alignment to stack */ -#pragma pack(1) /* set alignment to 1 byte boundary */ - -#define NF2_OF_ENTRY_WORD_LEN 8 -struct nf2_of_entry { - uint16_t transp_dst; - uint16_t transp_src; - uint8_t ip_proto; - uint32_t ip_dst; - uint32_t ip_src; - uint16_t eth_type; - uint8_t eth_dst[6]; - uint8_t eth_src[6]; - uint8_t src_port; - uint8_t ip_tos; - uint16_t vlan_id; - uint8_t pad; -}; - -typedef union nf2_of_entry_wrap { - struct nf2_of_entry entry; - uint32_t raw[NF2_OF_ENTRY_WORD_LEN]; -} nf2_of_entry_wrap; - -typedef nf2_of_entry_wrap nf2_of_mask_wrap; -#define NF2_OF_MASK_WORD_LEN 8 - -struct nf2_of_action { - uint16_t forward_bitmask; - uint16_t nf2_action_flag; - uint16_t vlan_id; - uint8_t vlan_pcp; - uint8_t eth_src[6]; - uint8_t eth_dst[6]; - uint32_t ip_src; - uint32_t ip_dst; - uint8_t ip_tos; - uint16_t transp_src; - uint16_t transp_dst; - uint8_t reserved[18]; -}; - -#define NF2_OF_ACTION_WORD_LEN 10 -typedef union nf2_of_action_wrap { - struct nf2_of_action action; - uint32_t raw[10]; -} nf2_of_action_wrap; - -struct nf2_of_exact_counters { - uint32_t pkt_count:25; - uint8_t last_seen:7; - uint32_t byte_count; -}; - -#define NF2_OF_EXACT_COUNTERS_WORD_LEN 2 -typedef union nf2_of_exact_counters_wrap { - struct nf2_of_exact_counters counters; - uint32_t raw[NF2_OF_EXACT_COUNTERS_WORD_LEN]; -} nf2_of_exact_counters_wrap; - -#define NF2_PORT_NUM 4 -struct nf2_all_ports_info_addr { - unsigned int rx_q_num_pkts_stored_reg[NF2_PORT_NUM]; - unsigned int rx_q_num_pkts_dropped_full_reg[NF2_PORT_NUM]; - unsigned int rx_q_num_pkts_dropped_bad_reg[NF2_PORT_NUM]; - unsigned int rx_q_num_words_pushed_reg[NF2_PORT_NUM]; - unsigned int rx_q_num_bytes_pushed_reg[NF2_PORT_NUM]; - unsigned int rx_q_num_pkts_dequeued_reg[NF2_PORT_NUM]; - unsigned int rx_q_num_pkts_in_queue_reg[NF2_PORT_NUM]; - unsigned int tx_q_num_pkts_in_queue_reg[NF2_PORT_NUM]; - unsigned int tx_q_num_pkts_sent_reg[NF2_PORT_NUM]; - unsigned int tx_q_num_words_pushed_reg[NF2_PORT_NUM]; - unsigned int tx_q_num_bytes_pushed_reg[NF2_PORT_NUM]; - unsigned int tx_q_num_pkts_enqueued_reg[NF2_PORT_NUM]; -}; - -struct nf2_port_info { - uint32_t rx_q_num_pkts_stored; - uint32_t rx_q_num_pkts_dropped_full; - uint32_t rx_q_num_pkts_dropped_bad; - uint32_t rx_q_num_words_pushed; - uint32_t rx_q_num_bytes_pushed; - uint32_t rx_q_num_pkts_dequeued; - uint32_t rx_q_num_pkts_in_queue; - uint32_t tx_q_num_pkts_in_queue; - uint32_t tx_q_num_pkts_sent; - uint32_t tx_q_num_words_pushed; - uint32_t tx_q_num_bytes_pushed; - uint32_t tx_q_num_pkts_enqueued; -}; - -#pragma pack(pop) /* XXX: Restore original alignment from stack */ - -void nf2_reset_card(struct nf2device *); -void nf2_clear_watchdog(struct nf2device *); -int nf2_write_of_wildcard(struct nf2device *, int, nf2_of_entry_wrap *, - nf2_of_mask_wrap *, nf2_of_action_wrap *); -int nf2_write_of_exact(struct nf2device *, int, nf2_of_entry_wrap *, - nf2_of_action_wrap *); -int nf2_modify_write_of_wildcard(struct nf2device *, int, nf2_of_entry_wrap *, - nf2_of_mask_wrap *, nf2_of_action_wrap *); -int nf2_modify_write_of_exact(struct nf2device *, int, nf2_of_action_wrap *); -unsigned int nf2_get_exact_packet_count(struct nf2device *, int); -unsigned int nf2_get_exact_byte_count(struct nf2device *, int); -unsigned int nf2_get_wildcard_packet_count(struct nf2device *, int); -unsigned int nf2_get_wildcard_byte_count(struct nf2device *, int); -unsigned long int nf2_get_matched_count(struct nf2device *); -unsigned long int nf2_get_missed_count(struct nf2device *); -int nf2_get_port_info(struct nf2device *, int, struct nf2_port_info *); - -#endif diff --git a/openflow/hw-lib/nf2/nf2_lib.c b/openflow/hw-lib/nf2/nf2_lib.c deleted file mode 100644 index 972d91bd..00000000 --- a/openflow/hw-lib/nf2/nf2_lib.c +++ /dev/null @@ -1,1049 +0,0 @@ -/*- - * Copyright (c) 2008, 2009, 2010 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#include -#include - -#include "list.h" -#include "udatapath/crc32.h" -#include "udatapath/switch-flow.h" -#include "udatapath/table.h" -#include "reg_defines_openflow_switch.h" -#include "nf2.h" -#include "nf2util.h" -#include "hw_flow.h" -#include "nf2_drv.h" -#include "nf2_lib.h" -#include "debug.h" - -#define DEFAULT_IFACE "nf2c0" - -#define MAX_INT_32 0xFFFFFFFF -#define PORT_BASE 1 - -#define VID_BITMASK 0x0FFF -#define PCP_BITSHIFT 13 -#define PCP_BITMASK 0xE000 -#define TOS_BITMASK 0xFC - -struct list wildcard_free_list; -struct nf2_flow *exact_free_list[OPENFLOW_NF2_EXACT_TABLE_SIZE]; - -static uint32_t make_nw_wildcard(int); -static struct nf2_flow *get_free_exact(nf2_of_entry_wrap *); -static struct nf2_flow *get_free_wildcard(void); -static int is_action_forward_all(struct sw_flow *); -static void populate_action_output(nf2_of_action_wrap *, nf2_of_entry_wrap *, - uint8_t *); -static void populate_action_set_dl_src(nf2_of_action_wrap *, uint8_t *); -static void populate_action_set_dl_dst(nf2_of_action_wrap *, uint8_t *); -static void populate_action_set_nw_src(nf2_of_action_wrap *, uint8_t *); -static void populate_action_set_nw_dst(nf2_of_action_wrap *, uint8_t *); -static void populate_action_set_tp_src(nf2_of_action_wrap *, uint8_t *); -static void populate_action_set_tp_dst(nf2_of_action_wrap *, uint8_t *); -static void populate_action_set_nw_tos(nf2_of_action_wrap *, uint8_t *); -static void populate_action_set_vlan_vid(nf2_of_action_wrap *, uint8_t *); -static void populate_action_set_vlan_pcp(nf2_of_action_wrap *, uint8_t *); -static void populate_action_strip_vlan(nf2_of_action_wrap *); - -int iface_chk_done = 0; -int net_iface = 0; - -struct nf2device * -nf2_get_net_device(void) -{ - struct nf2device *dev; - dev = calloc(1, sizeof(struct nf2device)); - dev->device_name = DEFAULT_IFACE; - - if (iface_chk_done) { - dev->net_iface = net_iface; - } else { - if (check_iface(dev)) { - iface_chk_done = 0; - return NULL; - } else { - iface_chk_done = 1; - net_iface = dev->net_iface; - } - } - - if (openDescriptor(dev)) { - return NULL; - } - return dev; -} - -void -nf2_free_net_device(struct nf2device *dev) -{ - if (dev == NULL){ - return; - } - - closeDescriptor(dev); - free(dev); -} - -/* Checks to see if the actions requested by the flow are capable of being - * done in the NF2 hardware. Returns 1 if yes, 0 for no. - */ -int -nf2_are_actions_supported(struct sw_flow *flow) -{ - struct sw_flow_actions *sfa; - size_t actions_len; - uint8_t *p; - - sfa = flow->sf_acts; - actions_len = sfa->actions_len; - p = (uint8_t *)sfa->actions; - - while (actions_len > 0) { - struct ofp_action_header *ah = (struct ofp_action_header *)p; - struct ofp_action_output *oa = (struct ofp_action_output *)p; - size_t len = ntohs(ah->len); - - DBG_VERBOSE("Action Support Chk: Len of this action: %i\n", - len); - DBG_VERBOSE("Action Support Chk: Len of actions : %i\n", - actions_len); - - // All the modify actions are supported. - // Each of them can be specified once otherwise overwritten. - // Output action happens last. - if (!(ntohs(ah->type) == OFPAT_OUTPUT - || ntohs(ah->type) == OFPAT_SET_DL_SRC - || ntohs(ah->type) == OFPAT_SET_DL_DST - - || ntohs(ah->type) == OFPAT_SET_NW_SRC - || ntohs(ah->type) == OFPAT_SET_NW_DST - - || ntohs(ah->type) == OFPAT_SET_NW_TOS - - || ntohs(ah->type) == OFPAT_SET_TP_SRC - || ntohs(ah->type) == OFPAT_SET_TP_DST - - || ntohs(ah->type) == OFPAT_SET_VLAN_VID - || ntohs(ah->type) == OFPAT_SET_VLAN_PCP - || ntohs(ah->type) == OFPAT_STRIP_VLAN)) { - DBG_VERBOSE - ("Flow action type %#0x not supported in hardware\n", - ntohs(ah->type)); - return 0; - } - // Only support ports 1-4(incl. IN_PORT), ALL, FLOOD. - // Let CONTROLLER/LOCAL fall through - if ((ntohs(ah->type) == OFPAT_OUTPUT) - && (!((ntohs(oa->port) >= PORT_BASE) - && (ntohs(oa->port) <= MAX_IFACE)) - && !(ntohs(oa->port) == OFPP_ALL) - && !(ntohs(oa->port) == OFPP_FLOOD) - && !(ntohs(oa->port) == OFPP_IN_PORT))) { - DBG_VERBOSE - ("Flow action output port %#0x is not supported in hardware\n", - ntohs(oa->port)); - return 0; - } - p += len; - actions_len -= len; - } - - return 1; -} - -/* Write all 0's out to an exact entry position. */ -void -nf2_clear_of_exact(uint32_t pos) -{ - nf2_of_entry_wrap entry; - nf2_of_action_wrap action; - struct nf2device *dev = NULL; - - memset(&entry, 0, sizeof(nf2_of_entry_wrap)); - memset(&action, 0, sizeof(nf2_of_action_wrap)); - - dev = nf2_get_net_device(); - if (dev == NULL) { - DBG_ERROR("Could not open NetFPGA device\n"); - return; - } - nf2_write_of_exact(dev, pos, &entry, &action); - nf2_free_net_device(dev); -} - -/* - * Write all 0's out to a wildcard entry position - */ -void -nf2_clear_of_wildcard(uint32_t pos) -{ - nf2_of_entry_wrap entry; - nf2_of_mask_wrap mask; - nf2_of_action_wrap action; - struct nf2device *dev = NULL; - - memset(&entry, 0, sizeof(nf2_of_entry_wrap)); - memset(&mask, 0, sizeof(nf2_of_mask_wrap)); - memset(&action, 0, sizeof(nf2_of_action_wrap)); - - dev = nf2_get_net_device(); - if (dev == NULL) { - DBG_ERROR("Could not open NetFPGA device\n"); - return; - } - nf2_write_of_wildcard(dev, pos, &entry, &mask, &action); - nf2_free_net_device(dev); -} - -int -nf2_init_exact_freelist(void) -{ - struct nf2_flow *sfw = NULL; - int i; - - for (i = 0; i < (OPENFLOW_NF2_EXACT_TABLE_SIZE); ++i) { - sfw = calloc(1, sizeof(struct nf2_flow)); - if (sfw == NULL) { - return 1; - } - sfw->pos = i; - sfw->type = NF2_TABLE_EXACT; - nf2_add_free_exact(sfw); - sfw = NULL; - } - - return 0; -} - -int -nf2_init_wildcard_freelist(void) -{ - struct nf2_flow *sfw = NULL; - int i; - list_init(&wildcard_free_list); - - for (i = 0; i < (OPENFLOW_WILDCARD_TABLE_SIZE - RESERVED_FOR_CPU2NETFPGA); ++i) { - sfw = calloc(1, sizeof(struct nf2_flow)); - if (sfw == NULL) { - return 1; - } - sfw->pos = i; - sfw->type = NF2_TABLE_WILDCARD; - nf2_add_free_wildcard(sfw); - sfw = NULL; - } - - return 0; -} - -/* Called when the table is being deleted. */ -void -nf2_destroy_exact_freelist(void) -{ - struct nf2_flow *sfw = NULL; - int i; - - for (i = 0; i < (OPENFLOW_NF2_EXACT_TABLE_SIZE); ++i) { - sfw = exact_free_list[i]; - if (sfw) { - free(sfw); - } - sfw = NULL; - } -} - -/* Called when the table is being deleted. */ -void -nf2_destroy_wildcard_freelist(void) -{ - struct nf2_flow *sfw = NULL; - - while (!list_is_empty(&wildcard_free_list)) { - sfw = CONTAINER_OF(list_front(&wildcard_free_list), struct nf2_flow, node); - list_remove(&sfw->node); - free(sfw); - } -} - -/* Setup the wildcard table by adding static flows that will handle - * misses by sending them up to the cpu ports, and handle packets coming - * back down from the cpu by sending them out the corresponding port. - */ -int -nf2_write_static_wildcard(void) -{ - nf2_of_entry_wrap entry; - nf2_of_mask_wrap mask; - nf2_of_action_wrap action; - int i; - struct nf2device *dev; - - dev = nf2_get_net_device(); - if (dev == NULL) - return 1; - - memset(&entry, 0x00, sizeof(nf2_of_entry_wrap)); - memset(&mask, 0xFF, sizeof(nf2_of_mask_wrap)); - // Only non-wildcard section is the source port - mask.entry.src_port = 0; - memset(&action, 0, sizeof(nf2_of_action_wrap)); - - // write the catch all entries to send to the cpu - for (i = 0; i < 4; ++i) { - entry.entry.src_port = i * 2; - action.action.forward_bitmask = 0x1 << ((i * 2) + 1); - nf2_write_of_wildcard(dev, (OPENFLOW_WILDCARD_TABLE_SIZE - 4) - + i, &entry, &mask, &action); - } - - // write the entries to send out packets coming from the cpu - for (i = 0; i < 4; ++i) { - entry.entry.src_port = (i * 2) + 1; - action.action.forward_bitmask = 0x1 << (i * 2); - nf2_write_of_wildcard(dev, (OPENFLOW_WILDCARD_TABLE_SIZE - 8) - + i, &entry, &mask, &action); - } - - nf2_free_net_device(dev); - return 0; -} - -/* Populate a nf2_of_entry_wrap with entries from a struct sw_flow. */ -void -nf2_populate_of_entry(nf2_of_entry_wrap *key, struct sw_flow *flow) -{ - int vlan_vid; - int vlan_pcp; - int i; - - key->entry.transp_dst = ntohs(flow->key.flow.tp_dst); - key->entry.transp_src = ntohs(flow->key.flow.tp_src); - key->entry.ip_proto = flow->key.flow.nw_proto; - key->entry.ip_dst = ntohl(flow->key.flow.nw_dst); - key->entry.ip_src = ntohl(flow->key.flow.nw_src); - key->entry.eth_type = ntohs(flow->key.flow.dl_type); - // Blame Jad for applying endian'ness to character arrays - for (i = 0; i < 6; ++i) { - key->entry.eth_dst[i] = flow->key.flow.dl_dst[5 - i]; - } - for (i = 0; i < 6; ++i) { - key->entry.eth_src[i] = flow->key.flow.dl_src[5 - i]; - } - key->entry.src_port = (ntohs(flow->key.flow.in_port) - PORT_BASE) * 2; - key->entry.ip_tos = TOS_BITMASK & flow->key.flow.nw_tos; - if (ntohs(flow->key.flow.dl_vlan) == 0xffff) { - key->entry.vlan_id = 0xffff; - } else { - vlan_vid = VID_BITMASK & ntohs(flow->key.flow.dl_vlan); - vlan_pcp = PCP_BITMASK - & ((uint16_t)(flow->key.flow.dl_vlan_pcp) << PCP_BITSHIFT); - key->entry.vlan_id = vlan_pcp | vlan_vid; - } -} - -static uint32_t -make_nw_wildcard(int n_wild_bits) -{ - n_wild_bits &= (1u << OFPFW_NW_SRC_BITS) - 1; - return n_wild_bits < 32 ? ((1u << n_wild_bits) - 1) : 0xFFFFFFFF; -} - -/* Populate a nf2_of_mask_wrap with entries from a struct sw_flow's wildcards. */ -void -nf2_populate_of_mask(nf2_of_mask_wrap *mask, struct sw_flow *flow) -{ - int vlan_vid = 0; - int vlan_pcp = 0; - int i; - - if (OFPFW_IN_PORT & flow->key.wildcards) { - mask->entry.src_port = 0xFF; - } - if (OFPFW_DL_VLAN & flow->key.wildcards) { - vlan_vid = VID_BITMASK; - } - if (OFPFW_DL_VLAN_PCP & flow->key.wildcards) { - vlan_pcp = 0xF000; - } - mask->entry.vlan_id = vlan_pcp | vlan_vid; - if (OFPFW_DL_SRC & flow->key.wildcards) { - for (i = 0; i < 6; ++i) { - mask->entry.eth_src[i] = 0xFF; - } - } - if (OFPFW_DL_DST & flow->key.wildcards) { - for (i = 0; i < 6; ++i) { - mask->entry.eth_dst[i] = 0xFF; - } - } - if (OFPFW_DL_TYPE & flow->key.wildcards) - mask->entry.eth_type = 0xFFFF; - if ((OFPFW_NW_SRC_ALL & flow->key.wildcards) - || (OFPFW_NW_SRC_MASK & flow->key.wildcards)) - mask->entry.ip_src = make_nw_wildcard - (flow->key.wildcards >> OFPFW_NW_SRC_SHIFT); - if ((OFPFW_NW_DST_ALL & flow->key.wildcards) - || (OFPFW_NW_DST_MASK & flow->key.wildcards)) - mask->entry.ip_dst = make_nw_wildcard - (flow->key.wildcards >> OFPFW_NW_DST_SHIFT); - if (OFPFW_NW_PROTO & flow->key.wildcards) - mask->entry.ip_proto = 0xFF; - if (OFPFW_TP_SRC & flow->key.wildcards) - mask->entry.transp_src = 0xFFFF; - if (OFPFW_TP_DST & flow->key.wildcards) - mask->entry.transp_dst = 0xFFFF; - if (OFPFW_NW_TOS & flow->key.wildcards) - mask->entry.ip_tos = TOS_BITMASK; - - mask->entry.pad = 0x00; -} - -static void -populate_action_output(nf2_of_action_wrap *action, nf2_of_entry_wrap *entry, - uint8_t *flowact) -{ - uint16_t port = 0; - struct ofp_action_output *actout = (struct ofp_action_output *)flowact; - int i; - - port = ntohs(actout->port); - DBG_VERBOSE("Action Type: %i Output Port: %i\n", - ntohs(actout->type), port); - - if ((port >= PORT_BASE) && (port <= MAX_IFACE)) { - // Bitmask for output port(s), evens are phys odds cpu - action->action.forward_bitmask - |= (1 << ((port - PORT_BASE) * 2)); - DBG_VERBOSE("Output Port: %i Forward Bitmask: %x\n", - port, action->action.forward_bitmask); - } else if (port == OFPP_IN_PORT) { - // Send out to input port - action->action.forward_bitmask - |= (1 << (entry->entry.src_port)); - DBG_VERBOSE("Output Port = Input Port Forward Bitmask: %x\n", - action->action.forward_bitmask); - } else if (port == OFPP_ALL || port == OFPP_FLOOD) { - // Send out all ports except the source - for (i = 0; i < 4; ++i) { - if ((i * 2) != entry->entry.src_port) { - // Bitmask for output port(s), evens are - // phys odds cpu - action->action.forward_bitmask - |= (1 << (i * 2)); - DBG_VERBOSE - ("Output Port: %i Forward Bitmask: %x\n", - port, action->action.forward_bitmask); - } - } - } -} - -static void -populate_action_set_dl_src(nf2_of_action_wrap *action, uint8_t *flowact) -{ - struct ofp_action_dl_addr *actdl = (struct ofp_action_dl_addr *)flowact; - int i; - - for (i = 0; i < 6; ++i) { - action->action.eth_src[5 - i] = actdl->dl_addr[i]; - } - action->action.nf2_action_flag |= (1 << OFPAT_SET_DL_SRC); -} - -static void -populate_action_set_dl_dst(nf2_of_action_wrap *action, uint8_t *flowact) -{ - struct ofp_action_dl_addr *actdl = (struct ofp_action_dl_addr *)flowact; - int i; - - for (i = 0; i < 6; ++i) { - action->action.eth_dst[5 - i] = actdl->dl_addr[i]; - } - action->action.nf2_action_flag |= (1 << OFPAT_SET_DL_DST); -} - -static void -populate_action_set_nw_src(nf2_of_action_wrap *action, uint8_t *flowact) -{ - struct ofp_action_nw_addr *actnw = (struct ofp_action_nw_addr *)flowact; - action->action.ip_src = ntohl(actnw->nw_addr); - action->action.nf2_action_flag |= (1 << OFPAT_SET_NW_SRC); -} - -static void -populate_action_set_nw_dst(nf2_of_action_wrap *action, uint8_t *flowact) -{ - struct ofp_action_nw_addr *actnw = (struct ofp_action_nw_addr *)flowact; - action->action.ip_dst = ntohl(actnw->nw_addr); - action->action.nf2_action_flag |= (1 << OFPAT_SET_NW_DST); -} - -static void -populate_action_set_nw_tos(nf2_of_action_wrap *action, uint8_t *flowact) -{ - struct ofp_action_nw_tos *actnwtos = (struct ofp_action_nw_tos *)flowact; - action->action.ip_tos = actnwtos->nw_tos; - action->action.nf2_action_flag |= (1 << OFPAT_SET_NW_TOS); -} - -static void -populate_action_set_tp_src(nf2_of_action_wrap *action, uint8_t *flowact) -{ - struct ofp_action_tp_port *acttp = (struct ofp_action_tp_port *)flowact; - action->action.transp_src = ntohs(acttp->tp_port); - action->action.nf2_action_flag |= (1 << OFPAT_SET_TP_SRC); -} - -static void -populate_action_set_tp_dst(nf2_of_action_wrap *action, uint8_t *flowact) -{ - struct ofp_action_tp_port *acttp = (struct ofp_action_tp_port *)flowact; - action->action.transp_dst = ntohs(acttp->tp_port); - action->action.nf2_action_flag |= (1 << OFPAT_SET_TP_DST); -} - -static void -populate_action_set_vlan_vid(nf2_of_action_wrap *action, uint8_t *flowact) -{ - struct ofp_action_vlan_vid *actvlan = (struct ofp_action_vlan_vid *)flowact; - action->action.vlan_id = ntohs(actvlan->vlan_vid) & VID_BITMASK; - action->action.nf2_action_flag |= (1 << OFPAT_SET_VLAN_VID); -} - -static void -populate_action_set_vlan_pcp(nf2_of_action_wrap *action, uint8_t *flowact) -{ - struct ofp_action_vlan_pcp *actvlan = (struct ofp_action_vlan_pcp *)flowact; - action->action.vlan_pcp = actvlan->vlan_pcp; - action->action.nf2_action_flag |= (1 << OFPAT_SET_VLAN_PCP); -} - -static void -populate_action_strip_vlan(nf2_of_action_wrap *action) -{ - action->action.nf2_action_flag |= (1 << OFPAT_STRIP_VLAN); -} - -/* Populate an nf2_of_action_wrap. */ -void -nf2_populate_of_action(nf2_of_action_wrap *action, nf2_of_entry_wrap *entry, - struct sw_flow *flow) -{ - struct sw_flow_actions *sfa; - size_t actions_len; - uint8_t *p; - - sfa = flow->sf_acts; - actions_len = sfa->actions_len; - p = (uint8_t *)sfa->actions; - - // zero it out for now - memset(action, 0, sizeof(nf2_of_action_wrap)); - action->action.nf2_action_flag = 0; - - while (actions_len > 0) { - struct ofp_action_header *acth = (struct ofp_action_header *)p; - size_t len = ntohs(acth->len); - - DBG_VERBOSE("Action Populate: Len of this action: %i\n", len); - DBG_VERBOSE("Action Populate: Len of actions : %i\n", - actions_len); - - if (acth->type == htons(OFPAT_OUTPUT)) { - populate_action_output(action, entry, p); - } else if (acth->type == htons(OFPAT_SET_DL_SRC)) { - populate_action_set_dl_src(action, p); - } else if (acth->type == htons(OFPAT_SET_DL_DST)) { - populate_action_set_dl_dst(action, p); - } else if (acth->type == htons(OFPAT_SET_NW_SRC)) { - populate_action_set_nw_src(action, p); - } else if (acth->type == htons(OFPAT_SET_NW_DST)) { - populate_action_set_nw_dst(action, p); - } else if (acth->type == htons(OFPAT_SET_NW_TOS)) { - populate_action_set_nw_tos(action, p); - } else if (acth->type == htons(OFPAT_SET_TP_SRC)) { - populate_action_set_tp_src(action, p); - } else if (acth->type == htons(OFPAT_SET_TP_DST)) { - populate_action_set_tp_dst(action, p); - } else if (acth->type == htons(OFPAT_SET_VLAN_VID)) { - populate_action_set_vlan_vid(action, p); - } else if (acth->type == htons(OFPAT_SET_VLAN_PCP)) { - populate_action_set_vlan_pcp(action, p); - } else if (acth->type == htons(OFPAT_STRIP_VLAN)) { - populate_action_strip_vlan(action); - } - - p += len; - actions_len -= len; - } -} - -/* Add a free hardware entry back to the exact pool. */ -void -nf2_add_free_exact(struct nf2_flow *sfw) -{ - // clear the node entry - list_init(&sfw->node); - - // Critical section, adding to the actual list - exact_free_list[sfw->pos] = sfw; -} - -/* Add a free hardware entry back to the wildcard pool. */ -void -nf2_add_free_wildcard(struct nf2_flow *sfw) -{ - // clear the hw values - sfw->hw_packet_count = 0; - sfw->hw_byte_count = 0; - - // Critical section, adding to the actual list - list_insert(&wildcard_free_list, &sfw->node); -} - -/* Hashes the entry to find where it should exist in the exact table - * returns NULL on failure - */ -static struct nf2_flow * -get_free_exact(nf2_of_entry_wrap *entry) -{ - unsigned int poly1 = 0x04C11DB7; - unsigned int poly2 = 0x1EDC6F41; - struct nf2_flow *sfw = NULL; - unsigned int hash = 0x0; - unsigned int index = 0x0; - struct crc32 crc; - - crc32_init(&crc, poly1); - hash = crc32_calculate(&crc, entry, sizeof(nf2_of_entry_wrap)); - - // the bottom 15 bits of hash == the index into the table - index = 0x7FFF & hash; - - // if this index is free, grab it - sfw = exact_free_list[index]; - exact_free_list[index] = NULL; - - if (sfw != NULL) { - return sfw; - } - // try the second index - crc32_init(&crc, poly2); - hash = crc32_calculate(&crc, entry, sizeof(nf2_of_entry_wrap)); - // the bottom 15 bits of hash == the index into the table - index = 0x7FFF & hash; - - // if this index is free, grab it - sfw = exact_free_list[index]; - exact_free_list[index] = NULL; - - // return whether its good or not - return sfw; -} - -/* Get the first free position in the wildcard hardware table - * to write into. - */ -static struct nf2_flow * -get_free_wildcard(void) -{ - struct nf2_flow *sfw = NULL; - - // Critical section, pulling the first available from the list - if (list_is_empty(&wildcard_free_list)) { - // empty :( - sfw = NULL; - } else { - sfw = CONTAINER_OF(list_front(&wildcard_free_list), struct nf2_flow, node); - list_remove(&sfw->node); - list_init(&sfw->node); - } - - return sfw; -} - -/* Retrieves the type of table this flow should go into. */ -int -nf2_get_table_type(struct sw_flow *flow) -{ - if (flow->key.wildcards != 0) { - DBG_VERBOSE("--- TABLE TYPE: WILDCARD ---\n"); - return NF2_TABLE_WILDCARD; - } else { - DBG_VERBOSE("--- TABLE TYPE: EXACT ---\n"); - return NF2_TABLE_EXACT; - } -} - -/* Returns 1 if this flow contains an action outputting to all ports except - * input port, 0 otherwise. We support OFPP_ALL and OFPP_FLOOD actions, however - * since we do not perform the spanning tree protocol (STP) then OFPP_FLOOD is - * equivalent to OFPP_ALL. - */ -static int -is_action_forward_all(struct sw_flow *flow) -{ - struct sw_flow_actions *sfa; - size_t actions_len; - uint8_t *p; - - sfa = flow->sf_acts; - actions_len = sfa->actions_len; - p = (uint8_t *)sfa->actions; - - while (actions_len > 0) { - struct ofp_action_header *ah = (struct ofp_action_header *)p; - struct ofp_action_output *oa = (struct ofp_action_output *)p; - size_t len = ntohs(ah->len); - - DBG_VERBOSE("Fwd Action Chk: Action type: %x\n", - ntohs(ah->type)); - DBG_VERBOSE("Fwd Action Chk: Output port: %x\n", - ntohs(oa->port)); - DBG_VERBOSE("Fwd Action Chk: Len of this action: %i\n", len); - DBG_VERBOSE("Fwd Action Chk: Len of actions : %i\n", - actions_len); - // Currently only support the output port(s) action - if (ntohs(ah->type) == OFPAT_OUTPUT - && (ntohs(oa->port) == OFPP_ALL - || ntohs(oa->port) == OFPP_FLOOD)) { - return 1; - } - p += len; - actions_len -= len; - } - - return 0; -} - -/* Attempts to build and write the flow to hardware. - * Returns 0 on success, 1 on failure. - */ -int -nf2_build_and_write_flow(struct sw_flow *flow) -{ - struct nf2_flow *sfw = NULL; - struct nf2_flow *sfw_next = NULL; - struct nf2device *dev; - int num_entries = 0; - int i, table_type; - nf2_of_entry_wrap key; - nf2_of_mask_wrap mask; - nf2_of_action_wrap action; - - memset(&key, 0, sizeof(nf2_of_entry_wrap)); - memset(&mask, 0, sizeof(nf2_of_mask_wrap)); - memset(&action, 0, sizeof(nf2_of_action_wrap)); - - dev = nf2_get_net_device(); - if (dev == NULL) { - return 1; - } - - table_type = nf2_get_table_type(flow); - switch (table_type) { - default: - break; - - case NF2_TABLE_EXACT: - DBG_VERBOSE("---Exact Entry---\n"); - nf2_populate_of_entry(&key, flow); - nf2_populate_of_action(&action, &key, flow); - sfw = get_free_exact(&key); - if (sfw == NULL) { - DBG_VERBOSE - ("Collision getting free exact match entry\n"); - // collision - nf2_free_net_device(dev); - return 1; - } - // set the active bit on this entry - key.entry.pad = 0x80; - nf2_write_of_exact(dev, sfw->pos, &key, &action); - flow->private = (void *)sfw; - break; - - case NF2_TABLE_WILDCARD: - DBG_VERBOSE("---Wildcard Entry---\n"); - // if action is all out and source port is wildcarded - if ((is_action_forward_all(flow)) && - (flow->key.wildcards & OFPFW_IN_PORT)) { - DBG_VERBOSE("Grab four wildcard tables\n"); - if (!(sfw = get_free_wildcard())) { - DBG_VERBOSE("No free wildcard entries found."); - // no free entries - nf2_free_net_device(dev); - return 1; - } - // try to get 3 more positions - for (i = 0; i < 3; ++i) { - if (!(sfw_next = get_free_wildcard())) { - break; - } - list_insert(&sfw->node, &sfw_next->node); - ++num_entries; - } - - if (num_entries < 3) { - // failed to get enough entries, return them and exit - nf2_delete_private((void *)sfw); - nf2_free_net_device(dev); - return 1; - } - - nf2_populate_of_entry(&key, flow); - nf2_populate_of_mask(&mask, flow); - - // set first entry's src port to 0, remove wildcard mask on src - key.entry.src_port = 0; - mask.entry.src_port = 0; - nf2_populate_of_action(&action, &key, flow); - nf2_write_of_wildcard(dev, sfw->pos, &key, &mask, - &action); - - i = 1; - sfw_next = CONTAINER_OF(list_front(&sfw->node), - struct nf2_flow, node); - // walk through and write the remaining 3 entries - while (sfw_next != sfw) { - key.entry.src_port = i * 2; - nf2_populate_of_action(&action, &key, flow); - nf2_write_of_wildcard(dev, sfw_next->pos, &key, - &mask, &action); - sfw_next = CONTAINER_OF(list_front(&sfw_next->node), - struct nf2_flow, node); - ++i; - } - flow->private = (void *)sfw; - } else { - /* Get a free position here, and write to it */ - if ((sfw = get_free_wildcard())) { - nf2_populate_of_entry(&key, flow); - nf2_populate_of_mask(&mask, flow); - nf2_populate_of_action(&action, &key, flow); - if (nf2_write_of_wildcard - (dev, sfw->pos, &key, &mask, &action)) { - // failure writing to hardware - nf2_add_free_wildcard(sfw); - DBG_VERBOSE - ("Failure writing to hardware\n"); - nf2_free_net_device(dev); - return 1; - } else { - // success writing to hardware, store the position - flow->private = (void *)sfw; - } - } else { - // hardware is full, return 0 - DBG_VERBOSE("No free wildcard entries found."); - nf2_free_net_device(dev); - return 1; - } - } - break; - } - - nf2_free_net_device(dev); - return 0; -} - -void -nf2_delete_private(void *private) -{ - struct nf2_flow *sfw = (struct nf2_flow *)private; - struct nf2_flow *sfw_next; - struct list *next; - - switch (sfw->type) { - default: - break; - - case NF2_TABLE_EXACT: - nf2_clear_of_exact(sfw->pos); - nf2_add_free_exact(sfw); - break; - - case NF2_TABLE_WILDCARD: - while (!list_is_empty(&sfw->node)) { - next = sfw->node.next; - sfw_next = CONTAINER_OF(list_front(&sfw->node), struct nf2_flow, node); - list_remove(&sfw_next->node); - list_init(&sfw_next->node); - // Immediately zero out the entry in hardware - nf2_clear_of_wildcard(sfw_next->pos); - // add it back to the pool - nf2_add_free_wildcard(sfw_next); - } - // zero the core entry - nf2_clear_of_wildcard(sfw->pos); - // add back the core entry - nf2_add_free_wildcard(sfw); - break; - } -} - -int -nf2_modify_acts(struct sw_flow *flow) -{ - struct nf2_flow *sfw = (struct nf2_flow *)flow->private; - struct nf2device *dev; - nf2_of_entry_wrap key; - nf2_of_mask_wrap mask; - nf2_of_action_wrap action; - - memset(&key, 0, sizeof(nf2_of_entry_wrap)); - memset(&mask, 0, sizeof(nf2_of_mask_wrap)); - memset(&action, 0, sizeof(nf2_of_action_wrap)); - - dev = nf2_get_net_device(); - if (dev == NULL) - return 0; - - switch (sfw->type) { - default: - break; - - case NF2_TABLE_EXACT: - nf2_populate_of_entry(&key, flow); - nf2_populate_of_action(&action, &key, flow); - key.entry.pad = 0x80; - nf2_modify_write_of_exact(dev, sfw->pos, &action); - break; - - case NF2_TABLE_WILDCARD: - if (flow->key.wildcards & OFPFW_IN_PORT) { - nf2_free_net_device(dev); - return 0; - } - nf2_populate_of_entry(&key, flow); - nf2_populate_of_mask(&mask, flow); - nf2_populate_of_action(&action, &key, flow); - nf2_modify_write_of_wildcard(dev, sfw->pos, - &key, &mask, &action); - break; - } - - nf2_free_net_device(dev); - return 1; -} - -uint64_t -nf2_get_packet_count(struct nf2device *dev, struct nf2_flow *sfw) -{ - uint32_t count = 0; - uint32_t hw_count = 0; - uint64_t total = 0; - struct nf2_flow *sfw_next = NULL; - - switch (sfw->type) { - default: - break; - - case NF2_TABLE_EXACT: - // Get delta value - total = nf2_get_exact_packet_count(dev, sfw->pos); - break; - - case NF2_TABLE_WILDCARD: - sfw_next = sfw; - do { - // Get sum value - hw_count = nf2_get_wildcard_packet_count(dev, - sfw_next->pos); - if (hw_count >= sfw_next->hw_packet_count) { - count = hw_count - sfw_next->hw_packet_count; - sfw_next->hw_packet_count = hw_count; - } else { - // wrapping occurred - count = (MAX_INT_32 - sfw_next->hw_packet_count) - + hw_count; - sfw_next->hw_packet_count = hw_count; - } - total += count; - - if(!list_is_empty(&sfw_next->node)){ - sfw_next = CONTAINER_OF(list_front(&sfw_next->node), - struct nf2_flow, node); - } - } while (sfw_next != sfw); - break; - } - - return total; -} - -uint64_t -nf2_get_byte_count(struct nf2device *dev, struct nf2_flow *sfw) -{ - uint32_t count = 0; - uint32_t hw_count = 0; - uint64_t total = 0; - struct nf2_flow *sfw_next = NULL; - - switch (sfw->type) { - default: - break; - - case NF2_TABLE_EXACT: - // Get delta value - total = nf2_get_exact_byte_count(dev, sfw->pos); - break; - - case NF2_TABLE_WILDCARD: - sfw_next = sfw; - do { - // Get sum value - hw_count = nf2_get_wildcard_byte_count(dev, - sfw_next->pos); - if (hw_count >= sfw_next->hw_byte_count) { - count = hw_count - sfw_next->hw_byte_count; - sfw_next->hw_byte_count = hw_count; - } else { - // wrapping occurred - count = (MAX_INT_32 - sfw_next->hw_byte_count) - + hw_count; - sfw_next->hw_byte_count = hw_count; - } - - total += count; - - if(!list_is_empty(&sfw_next->node)) { - sfw_next = CONTAINER_OF(list_front(&sfw_next->node), - struct nf2_flow, node); - } - } while (sfw_next != sfw); - break; - } - - return total; -} diff --git a/openflow/hw-lib/nf2/nf2_lib.h b/openflow/hw-lib/nf2/nf2_lib.h deleted file mode 100644 index cc75b2c6..00000000 --- a/openflow/hw-lib/nf2/nf2_lib.h +++ /dev/null @@ -1,59 +0,0 @@ -/*- - * Copyright (c) 2008, 2009, 2010 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#ifndef HWTABLE_NF2_NF2_LIB_H_ -#define HWTABLE_NF2_NF2_LIB_H_ - -struct nf2device *nf2_get_net_device(void); -void nf2_free_net_device(struct nf2device *); -int nf2_are_actions_supported(struct sw_flow *); -void nf2_clear_of_exact(uint32_t); -void nf2_clear_of_wildcard(uint32_t); -int nf2_init_exact_freelist(void); -int nf2_init_wildcard_freelist(void); -void nf2_destroy_exact_freelist(void); -void nf2_destroy_wildcard_freelist(void); -int nf2_write_static_wildcard(void); -void nf2_populate_of_entry(nf2_of_entry_wrap *, struct sw_flow *); -void nf2_populate_of_mask(nf2_of_mask_wrap *, struct sw_flow *); -void nf2_populate_of_action(nf2_of_action_wrap *, nf2_of_entry_wrap *, - struct sw_flow *); -void nf2_add_free_exact(struct nf2_flow *); -void nf2_add_free_wildcard(struct nf2_flow *); -int nf2_get_table_type(struct sw_flow *); -int nf2_build_and_write_flow(struct sw_flow *); -void nf2_delete_private(void *); -int nf2_modify_acts(struct sw_flow *); -uint64_t nf2_get_packet_count(struct nf2device *, struct nf2_flow *); -uint64_t nf2_get_byte_count(struct nf2device *, struct nf2_flow *); - -#endif diff --git a/openflow/hw-lib/nf2/nf2util.c b/openflow/hw-lib/nf2/nf2util.c deleted file mode 100644 index fd3b500e..00000000 --- a/openflow/hw-lib/nf2/nf2util.c +++ /dev/null @@ -1,400 +0,0 @@ -/* **************************************************************************** - * $Id: nf2util.c 3764 2008-05-22 06:48:34Z grg $ - * - * Module: nf2util.c - * Project: NetFPGA 2 Linux Kernel Driver - * Description: Utility functions for user mode programs - * - * Change history: - * - */ - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include - -#include "nf2.h" -#include "nf2util.h" - -#include "reg_defines_openflow_switch.h" - -#define MD5_LEN 4 - -/* Function declarations */ -static int readRegNet(struct nf2device *nf2, unsigned reg, unsigned *val); -static int readRegFile(struct nf2device *nf2, unsigned reg, unsigned *val); -static int writeRegNet(struct nf2device *nf2, unsigned reg, unsigned val); -static int writeRegFile(struct nf2device *nf2, unsigned reg, unsigned val); - -/* Local variables */ -unsigned cpci_version = -1; -unsigned cpci_revision = -1; -unsigned nf2_device_id = -1; -unsigned nf2_revision = -1; -unsigned nf2_cpci_version = -1; -unsigned nf2_cpci_revision = -1; -char nf2_device_str[DEVICE_STR_LEN] = ""; - -/* - * readReg - read a register - */ -int readReg(struct nf2device *nf2, unsigned reg, unsigned *val) -{ - if (nf2->net_iface) - { - return readRegNet(nf2, reg, val); - } - else - { - return readRegFile(nf2, reg, val); - } -} - -/* - * readRegNet - read a register, using a network socket - */ -static int readRegNet(struct nf2device *nf2, unsigned reg, unsigned *val) -{ - struct ifreq ifreq; - struct nf2reg nf2reg; - int ret; - - nf2reg.reg = reg; - - /* Set up the ifreq structure */ - ifreq.ifr_data = (char *)&nf2reg; - strncpy(ifreq.ifr_ifrn.ifrn_name, nf2->device_name, IFNAMSIZ); - /*if (setsockopt(nf2->fd, SOL_SOCKET, SO_BINDTODEVICE, - (char *)&ifreq, sizeof(ifreq)) < 0) { - perror("sendpacket: setting SO_BINDTODEVICE"); - return -1; - } */ - - /* Call the ioctl */ - if ((ret = ioctl(nf2->fd, SIOCREGREAD, &ifreq)) == 0) - { - *val = nf2reg.val; - return 0; - } - else - { - perror("sendpacket: ioctl failed"); - return -1; - } -} - -/* - * readRegFile - read a register, using a file descriptor - */ -static int readRegFile(struct nf2device *nf2, unsigned reg, unsigned *val) -{ - struct nf2reg nf2reg; - int ret; - - nf2reg.reg = reg; - - /* Call the ioctl */ - if ((ret = ioctl(nf2->fd, SIOCREGREAD, &nf2reg)) == 0) - { - *val = nf2reg.val; - return 0; - } - else - { - perror("sendpacket: ioctl failed"); - return -1; - } -} - - -/* - * writeReg - write a register - */ -int writeReg(struct nf2device *nf2, unsigned reg, unsigned val) -{ - if (nf2->net_iface) - { - return writeRegNet(nf2, reg, val); - } - else - { - return writeRegFile(nf2, reg, val); - } -} - - -/* - * writeRegNet - write a register, using a network socket - */ -static int writeRegNet(struct nf2device *nf2, unsigned reg, unsigned val) -{ - struct ifreq ifreq; - struct nf2reg nf2reg; - int ret; - - nf2reg.reg = reg; - nf2reg.val = val; - - /* Set up the ifreq structure */ - ifreq.ifr_data = (char *)&nf2reg; - strncpy(ifreq.ifr_ifrn.ifrn_name, nf2->device_name, IFNAMSIZ); - /*if (setsockopt(nf2->fd, SOL_SOCKET, SO_BINDTODEVICE, - (char *)&ifreq, sizeof(ifreq)) < 0) { - perror("sendpacket: setting SO_BINDTODEVICE"); - return -1; - } */ - - /* Call the ioctl */ - if ((ret = ioctl(nf2->fd, SIOCREGWRITE, &ifreq)) == 0) - { - return 0; - } - else - { - perror("sendpacket: ioctl failed"); - return -1; - } -} - - -/* - * writeRegFile - write a register, using a file descriptor - */ -static int writeRegFile(struct nf2device *nf2, unsigned reg, unsigned val) -{ - struct nf2reg nf2reg; - int ret; - - nf2reg.reg = reg; - nf2reg.val = val; - - /* Call the ioctl */ - if ((ret = ioctl(nf2->fd, SIOCREGWRITE, &nf2reg)) == 0) - { - return 0; - } - else - { - perror("sendpacket: ioctl failed"); - return -1; - } -} - -/* - * Check the iface name to make sure we can find the interface - */ -int check_iface(struct nf2device *nf2) -{ - struct stat buf; - char filename[PATHLEN]; - - /* See if we can find the interface name as a network device */ - - /* Test the length first of all */ - if (strlen(nf2->device_name) > IFNAMSIZ) - { - fprintf(stderr, "Interface name is too long: %s\n", nf2->device_name); - return -1; - } - - /* Check for /sys/class/net/iface_name */ - strcpy(filename, "/sys/class/net/"); - strcat(filename, nf2->device_name); - if (stat(filename, &buf) == 0) - { - nf2->net_iface = 1; - return 0; - } - - /* Check for /dev/iface_name */ - strcpy(filename, "/dev/"); - strcat(filename, nf2->device_name); - if (stat(filename, &buf) == 0) - { - nf2->net_iface = 0; - return 0; - } - - fprintf(stderr, "Can't find device: %s\n", nf2->device_name); - return -1; -} - -/* - * Open the descriptor associated with the device name - */ -int openDescriptor(struct nf2device *nf2) -{ - struct ifreq ifreq; - char filename[PATHLEN]; - struct sockaddr_in address; - int i; - struct sockaddr_in *sin = (struct sockaddr_in *) &ifreq.ifr_addr; - int found = 0; - - if (nf2->net_iface) - { - /* Open a network socket */ - nf2->fd = socket(AF_INET, SOCK_DGRAM, 0); - if (nf2->fd == -1) - { - perror("socket: creating socket"); - return -1; - } - else - { - /* Root can bind to a network interface. - Non-root has to bind to a network address. */ - if (geteuid() == 0) - { - strncpy(ifreq.ifr_ifrn.ifrn_name, nf2->device_name, IFNAMSIZ); - if (setsockopt(nf2->fd, SOL_SOCKET, SO_BINDTODEVICE, - (char *)&ifreq, sizeof(ifreq)) < 0) { - perror("setsockopt: setting SO_BINDTODEVICE"); - return -1; - } - - } - else - { - /* Attempt to find the IP address for the interface */ - for (i = 1; ; i++) - { - /* Find interface number i*/ - ifreq.ifr_ifindex = i; - if (ioctl (nf2->fd, SIOCGIFNAME, &ifreq) < 0) - break; - - /* Check if we've found the correct interface */ - if (strcmp(ifreq.ifr_name, nf2->device_name) != 0) - continue; - - /* If we get to here we've found the IP */ - found = 1; - break; - } - - /* Verify that we found the interface */ - if (!found) - { - fprintf(stderr, "Can't find device: %s\n", nf2->device_name); - return -1; - } - - /* Attempt to get the IP address associated with the interface */ - if (ioctl (nf2->fd, SIOCGIFADDR, &ifreq) < 0) - { - perror("ioctl: calling SIOCGIFADDR"); - - fprintf(stderr, "Unable to find IP address for device: %s\n", nf2->device_name); - fprintf(stderr, "Either run this program as root or ask an administrator\n"); - fprintf(stderr, "to assign an IP address to the device\n"); - return -1; - } - - /* Set the addres and attempt to bind to the socket */ - address.sin_family = AF_INET; - address.sin_addr.s_addr = sin->sin_addr.s_addr; - address.sin_port = htons(0); - if (bind(nf2->fd,(struct sockaddr *)&address,sizeof(address)) == -1) { - perror("bind: binding"); - return -1; - } - } - } - } - else - { - strcpy(filename, "/dev/"); - strcat(filename, nf2->device_name); - nf2->fd = fileno(fopen(filename, "w+")); - if (nf2->fd == -1) - { - perror("fileno: creating descriptor"); - return -1; - } - } - - return 0; -} - -/* - * Close the descriptor associated with the device name - */ -int closeDescriptor(struct nf2device *nf2) -{ - if (nf2->net_iface) - { - close(nf2->fd); - } - else - { - close(nf2->fd); - } - - return 0; -} - -/* - * Read the version info from the Virtex and CPCI - */ -void nf2_read_info(struct nf2device *nf2) -{ - int i; - int md5_good = 1; - unsigned md5[MD5_LEN]; - unsigned cpci_id; - unsigned nf2_cpci_id; - - // Read the CPCI version/revision - readReg(nf2, CPCI_REG_ID, &cpci_id); - cpci_version = cpci_id & 0xffffff; - cpci_revision = cpci_id >> 24; - - // Verify the MD5 checksum of the device ID block - for (i = 0; i < MD5_LEN; i++) { - readReg(nf2, DEV_ID_MD5_0_REG + i * 4, &md5[i]); - } - md5_good &= md5[0] == DEV_ID_MD5_VALUE_0; - md5_good &= md5[1] == DEV_ID_MD5_VALUE_1; - md5_good &= md5[2] == DEV_ID_MD5_VALUE_2; - md5_good &= md5[3] == DEV_ID_MD5_VALUE_3; - - // Process only if the MD5 sum is good - if (md5_good) { - // Read the version and revision - readReg(nf2, DEV_ID_DEVICE_ID_REG, &nf2_device_id); - readReg(nf2, DEV_ID_REVISION_REG, &nf2_revision); - readReg(nf2, DEV_ID_CPCI_ID_REG, &nf2_cpci_id); - nf2_cpci_version = nf2_cpci_id & 0xffffff; - nf2_cpci_revision = nf2_cpci_id >> 24; - - // Read the version string - for (i = 0; i < (DEVICE_STR_LEN / 4) - 2; i++) - { - readReg(nf2, DEV_ID_DEV_STR_0_REG + i * 4, (unsigned *)(nf2_device_str + i * 4)); - - // Perform byte swapping if necessary - *(unsigned *)(nf2_device_str + i * 4) = ntohl(*(unsigned *)(nf2_device_str + i * 4)); - } - nf2_device_str[DEVICE_STR_LEN - 1] = '\0'; - } -} - -/* - * Print out a test string - */ -void printHello (struct nf2device *nf2, int *val) -{ - printf ("Hello world. Name=%s val=%d\n", nf2->device_name, *val); - *val = 10; -} diff --git a/openflow/hw-lib/nf2/nf2util.h b/openflow/hw-lib/nf2/nf2util.h deleted file mode 100644 index 88d3c159..00000000 --- a/openflow/hw-lib/nf2/nf2util.h +++ /dev/null @@ -1,46 +0,0 @@ -/* **************************************************************************** - * $Id: nf2util.h 3764 2008-05-22 06:48:34Z grg $ - * - * Module: nf2util.h - * Project: NetFPGA 2 Linux Kernel Driver - * Description: Header file for kernel driver - * - * Change history: - * - */ - -#ifndef _NF2UTIL_H -#define _NF2UTIL_H 1 - -#define PATHLEN 80 -#define DEVICE_STR_LEN 100 - - -/* - * Structure to represent an nf2 device to a user mode programs - */ -struct nf2device { - char *device_name; - int fd; - int net_iface; -}; - -/* Function declarations */ - -int readReg(struct nf2device *nf2, unsigned reg, unsigned *val); -int writeReg(struct nf2device *nf2, unsigned reg, unsigned val); -int check_iface(struct nf2device *nf2); -int openDescriptor(struct nf2device *nf2); -int closeDescriptor(struct nf2device *nf2); -void nf2_read_info(struct nf2device *nf2); -void printHello (struct nf2device *nf2, int *val); - -extern unsigned cpci_version; -extern unsigned cpci_revision; -extern unsigned nf2_device_id; -extern unsigned nf2_revision; -extern unsigned nf2_cpci_version; -extern unsigned nf2_cpci_revision; -extern char nf2_device_str[DEVICE_STR_LEN]; - -#endif diff --git a/openflow/hw-lib/nf2/reg_defines_openflow_switch.h b/openflow/hw-lib/nf2/reg_defines_openflow_switch.h deleted file mode 100644 index 0056f882..00000000 --- a/openflow/hw-lib/nf2/reg_defines_openflow_switch.h +++ /dev/null @@ -1,767 +0,0 @@ -/******************************************************** -* -* C register defines file for openflow_switch -* -********************************************************/ - -#ifndef _REG_DEFINES_ -#define _REG_DEFINES_ - -/* ========= Constants ========= */ - -// ===== File: lib/verilog/core/common/xml/global.xml ===== - -// Maximum number of phy ports -#define MAX_PHY_PORTS 4 - -// PCI address bus width -#define PCI_ADDR_WIDTH 32 - -// PCI data bus width -#define PCI_DATA_WIDTH 32 - -// PCI byte enable bus width -#define PCI_BE_WIDTH 4 - -// CPCI--CNET address bus width. This is byte addresses even though bottom bits are zero. -#define CPCI_CNET_ADDR_WIDTH 27 - -// CPCI--CNET data bus width -#define CPCI_CNET_DATA_WIDTH 32 - -// CPCI--NF2 address bus width. This is byte addresses even though bottom bits are zero. -#define CPCI_NF2_ADDR_WIDTH 27 - -// CPCI--NF2 data bus width -#define CPCI_NF2_DATA_WIDTH 32 - -// DMA data bus width -#define DMA_DATA_WIDTH 32 - -// DMA control bus width -#define DMA_CTRL_WIDTH 4 - -// CPCI debug bus width -#define CPCI_DEBUG_DATA_WIDTH 29 - -// SRAM address width -#define SRAM_ADDR_WIDTH 19 - -// SRAM data width -#define SRAM_DATA_WIDTH 36 - -// DRAM address width -#define DRAM_ADDR_WIDTH 24 - -// ===== File: lib/verilog/core/common/xml/nf_defines.xml ===== - -// Clock period of 125 MHz clock in ns -#define FAST_CLK_PERIOD 8 - -// Clock period of 62.5 MHz clock in ns -#define SLOW_CLK_PERIOD 16 - -// Header value used by the IO queues -#define IO_QUEUE_STAGE_NUM 0xff - -// Data path data width -#define DATA_WIDTH 64 - -// Data path control width -#define CTRL_WIDTH 8 - -// ===== File: projects/openflow_switch/include/output_port_lookup.xml ===== - -#define FAST_CLOCK_PERIOD 8 - -// ===== File: projects/openflow_switch/include/vlan_remover.xml ===== - -#define VLAN_CTRL_WORD 0x42 - -#define VLAN_ETHERTYPE 0x8100 - -// ===== File: lib/verilog/core/output_queues/bram_output_queues/xml/bram_output_queues.xml ===== - -#define NUM_OUTPUT_QUEUES 8 - -// ===== File: projects/openflow_switch/include/opl_processor.xml ===== - -#define NF2_OFPAT_OUTPUT 0x0001 - -#define NF2_OFPAT_SET_VLAN_VID 0x0002 - -#define NF2_OFPAT_SET_VLAN_PCP 0x0004 - -#define NF2_OFPAT_STRIP_VLAN 0x0008 - -#define NF2_OFPAT_SET_DL_SRC 0x0010 - -#define NF2_OFPAT_SET_DL_DST 0x0020 - -#define NF2_OFPAT_SET_NW_SRC 0x0040 - -#define NF2_OFPAT_SET_NW_DST 0x0080 - -#define NF2_OFPAT_SET_TP_SRC 0x0100 - -#define NF2_OFPAT_SET_TP_DST 0x0200 - -// ===== File: projects/openflow_switch/include/wildcard_match.xml ===== - -#define OPENFLOW_WILDCARD_TABLE_SIZE 32 - -#define OPENFLOW_WILDCARD_NUM_DATA_WORDS_USED 10 - -#define OPENFLOW_WILDCARD_NUM_CMP_WORDS_USED 8 - -// ===== File: lib/verilog/core/utils/xml/device_id_reg.xml ===== - -// Total number of registers -#define DEV_ID_NUM_REGS 32 - -// Number of non string registers -#define DEV_ID_NON_DEV_STR_REGS 7 - -// Device description length (in words, not chars) -#define DEV_ID_DEV_STR_WORD_LEN 25 - -// Device description length (in bytes/chars) -#define DEV_ID_DEV_STR_BYTE_LEN 100 - -// Device description length (in bits) -#define DEV_ID_DEV_STR_BIT_LEN 800 - -// Length of MD5 sum (bits) -#define DEV_ID_MD5SUM_LENGTH 128 - -// MD5 sum of the string "device_id.v" -#define DEV_ID_MD5_VALUE 0x4071736d8a603d2b4d55f62989a73c95 -#define DEV_ID_MD5_VALUE_0 0x4071736d -#define DEV_ID_MD5_VALUE_1 0x8a603d2b -#define DEV_ID_MD5_VALUE_2 0x4d55f629 -#define DEV_ID_MD5_VALUE_3 0x89a73c95 - -// ===== File: projects/openflow_switch/include/header_parser.xml ===== - -#define ETH_TYPE_IP 0x0800 - -#define IP_PROTO_TCP 0x06 - -#define IP_PROTO_UDP 0x11 - -#define IP_PROTO_ICMP 0x01 - -// ===== File: projects/openflow_switch/include/watchdog.xml ===== - -#define WDT_CPCI_REG_CTRL 0x00000008 - -// ===== File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml ===== - -// TX queue disable bit -#define MAC_GRP_TX_QUEUE_DISABLE_BIT_NUM 0 - -// RX queue disable bit -#define MAC_GRP_RX_QUEUE_DISABLE_BIT_NUM 1 - -// Reset MAC bit -#define MAC_GRP_RESET_MAC_BIT_NUM 2 - -// MAC TX queue disable bit -#define MAC_GRP_MAC_DISABLE_TX_BIT_NUM 3 - -// MAC RX queue disable bit -#define MAC_GRP_MAC_DISABLE_RX_BIT_NUM 4 - -// MAC disable jumbo TX bit -#define MAC_GRP_MAC_DIS_JUMBO_TX_BIT_NUM 5 - -// MAC disable jumbo RX bit -#define MAC_GRP_MAC_DIS_JUMBO_RX_BIT_NUM 6 - -// MAC disable crc check disable bit -#define MAC_GRP_MAC_DIS_CRC_CHECK_BIT_NUM 7 - -// MAC disable crc generate bit -#define MAC_GRP_MAC_DIS_CRC_GEN_BIT_NUM 8 - -// ===== File: projects/openflow_switch/include/match_arbiter.xml ===== - -#define OPENFLOW_ENTRY_TRANSP_DST_WIDTH 16 - -#define OPENFLOW_ENTRY_TRANSP_DST_POS 0 - -#define OPENFLOW_ENTRY_TRANSP_SRC_WIDTH 16 - -#define OPENFLOW_ENTRY_TRANSP_SRC_POS 16 - -#define OPENFLOW_ENTRY_IP_PROTO_WIDTH 8 - -#define OPENFLOW_ENTRY_IP_PROTO_POS 32 - -#define OPENFLOW_ENTRY_IP_DST_WIDTH 32 - -#define OPENFLOW_ENTRY_IP_DST_POS 40 - -#define OPENFLOW_ENTRY_IP_SRC_WIDTH 32 - -#define OPENFLOW_ENTRY_IP_SRC_POS 72 - -#define OPENFLOW_ENTRY_ETH_TYPE_WIDTH 16 - -#define OPENFLOW_ENTRY_ETH_TYPE_POS 104 - -#define OPENFLOW_ENTRY_ETH_DST_WIDTH 48 - -#define OPENFLOW_ENTRY_ETH_DST_POS 120 - -#define OPENFLOW_ENTRY_ETH_SRC_WIDTH 48 - -#define OPENFLOW_ENTRY_ETH_SRC_POS 168 - -#define OPENFLOW_ENTRY_SRC_PORT_WIDTH 8 - -#define OPENFLOW_ENTRY_SRC_PORT_POS 216 - -#define OPENFLOW_ENTRY_VLAN_ID_WIDTH 16 - -#define OPENFLOW_ENTRY_VLAN_ID_POS 224 - -#define OPENFLOW_ENTRY_WIDTH 240 - -// The actionfield is composed of a bitmask specifying actions to take and arguments. -#define OPENFLOW_ACTION_WIDTH 320 - -// Ports to forward on -#define OPENFLOW_FORWARD_BITMASK_WIDTH 16 - -#define OPENFLOW_FORWARD_BITMASK_POS 0 - -#define OPENFLOW_NF2_ACTION_FLAG_WIDTH 16 - -#define OPENFLOW_NF2_ACTION_FLAG_POS 16 - -// Vlan ID to be replaced -#define OPENFLOW_SET_VLAN_VID_WIDTH 16 - -#define OPENFLOW_SET_VLAN_VID_POS 32 - -// Vlan priority to be replaced -#define OPENFLOW_SET_VLAN_PCP_WIDTH 8 - -#define OPENFLOW_SET_VLAN_PCP_POS 48 - -// Source MAC address to be replaced -#define OPENFLOW_SET_DL_SRC_WIDTH 48 - -#define OPENFLOW_SET_DL_SRC_POS 56 - -// Destination MAC address to be replaced -#define OPENFLOW_SET_DL_DST_WIDTH 48 - -#define OPENFLOW_SET_DL_DST_POS 104 - -// Source network address to be replaced -#define OPENFLOW_SET_NW_SRC_WIDTH 32 - -#define OPENFLOW_SET_NW_SRC_POS 152 - -// Destination network address to be replaced -#define OPENFLOW_SET_NW_DST_WIDTH 32 - -#define OPENFLOW_SET_NW_DST_POS 184 - -// Source transport port to be replaced -#define OPENFLOW_SET_TP_SRC_WIDTH 16 - -#define OPENFLOW_SET_TP_SRC_POS 216 - -// Destination transport port to be replaced -#define OPENFLOW_SET_TP_DST_WIDTH 16 - -#define OPENFLOW_SET_TP_DST_POS 232 - -// ===== File: projects/openflow_switch/include/exact_match.xml ===== - -#define OPENFLOW_EXACT_ENTRY_PKT_COUNTER_WIDTH 25 - -#define OPENFLOW_EXACT_ENTRY_PKT_COUNTER_POS 0 - -#define OPENFLOW_EXACT_ENTRY_LAST_SEEN_WIDTH 7 - -#define OPENFLOW_EXACT_ENTRY_LAST_SEEN_POS 25 - -#define OPENFLOW_EXACT_ENTRY_BYTE_COUNTER_WIDTH 32 - -#define OPENFLOW_EXACT_ENTRY_BYTE_COUNTER_POS 32 - -#define OPENFLOW_EXACT_ENTRY_HDR_BASE_POS 0x00000000 - -#define OPENFLOW_EXACT_ENTRY_COUNTERS_POS 0x00000008 - -#define OPENFLOW_EXACT_ENTRY_ACTION_BASE_POS 0x0000000a - -// ------------------------------------- -// Modules -// ------------------------------------- - -// Module tags -#define CORE_BASE_ADDR 0x0000000 -#define DEV_ID_BASE_ADDR 0x0400000 -#define MDIO_BASE_ADDR 0x0440000 -#define DMA_BASE_ADDR 0x0500000 -#define MAC_GRP_0_BASE_ADDR 0x0600000 -#define MAC_GRP_1_BASE_ADDR 0x0640000 -#define MAC_GRP_2_BASE_ADDR 0x0680000 -#define MAC_GRP_3_BASE_ADDR 0x06c0000 -#define CPU_QUEUE_0_BASE_ADDR 0x0700000 -#define CPU_QUEUE_1_BASE_ADDR 0x0740000 -#define CPU_QUEUE_2_BASE_ADDR 0x0780000 -#define CPU_QUEUE_3_BASE_ADDR 0x07c0000 -#define SRAM_BASE_ADDR 0x1000000 -#define UDP_BASE_ADDR 0x2000000 -#define OPENFLOW_LOOKUP_BASE_ADDR 0x2000000 -#define IN_ARB_BASE_ADDR 0x2000100 -#define VLAN_REMOVER_BASE_ADDR 0x2000200 -#define OPL_PROCESSOR_BASE_ADDR 0x2000240 -#define HEADER_PARSER_BASE_ADDR 0x2000280 -#define MATCH_ARBITER_BASE_ADDR 0x20002c0 -#define BRAM_OQ_BASE_ADDR 0x2000300 -#define WDT_BASE_ADDR 0x2000400 -#define EXACT_MATCH_BASE_ADDR 0x2000500 -#define OPENFLOW_WILDCARD_LOOKUP_BASE_ADDR 0x2001000 -#define DRAM_BASE_ADDR 0x4000000 - -#define CPU_QUEUE_OFFSET 0x0040000 -#define MAC_GRP_OFFSET 0x0040000 - -/* ========== Registers ========== */ - -// Name: device_id (DEV_ID) -// Description: Device identification -// File: lib/verilog/core/utils/xml/device_id_reg.xml -#define DEV_ID_MD5_0_REG 0x0400000 -#define DEV_ID_MD5_1_REG 0x0400004 -#define DEV_ID_MD5_2_REG 0x0400008 -#define DEV_ID_MD5_3_REG 0x040000c -#define DEV_ID_DEVICE_ID_REG 0x0400010 -#define DEV_ID_REVISION_REG 0x0400014 -#define DEV_ID_CPCI_ID_REG 0x0400018 -#define DEV_ID_DEV_STR_0_REG 0x040001c -#define DEV_ID_DEV_STR_1_REG 0x0400020 -#define DEV_ID_DEV_STR_2_REG 0x0400024 -#define DEV_ID_DEV_STR_3_REG 0x0400028 -#define DEV_ID_DEV_STR_4_REG 0x040002c -#define DEV_ID_DEV_STR_5_REG 0x0400030 -#define DEV_ID_DEV_STR_6_REG 0x0400034 -#define DEV_ID_DEV_STR_7_REG 0x0400038 -#define DEV_ID_DEV_STR_8_REG 0x040003c -#define DEV_ID_DEV_STR_9_REG 0x0400040 -#define DEV_ID_DEV_STR_10_REG 0x0400044 -#define DEV_ID_DEV_STR_11_REG 0x0400048 -#define DEV_ID_DEV_STR_12_REG 0x040004c -#define DEV_ID_DEV_STR_13_REG 0x0400050 -#define DEV_ID_DEV_STR_14_REG 0x0400054 -#define DEV_ID_DEV_STR_15_REG 0x0400058 -#define DEV_ID_DEV_STR_16_REG 0x040005c -#define DEV_ID_DEV_STR_17_REG 0x0400060 -#define DEV_ID_DEV_STR_18_REG 0x0400064 -#define DEV_ID_DEV_STR_19_REG 0x0400068 -#define DEV_ID_DEV_STR_20_REG 0x040006c -#define DEV_ID_DEV_STR_21_REG 0x0400070 -#define DEV_ID_DEV_STR_22_REG 0x0400074 -#define DEV_ID_DEV_STR_23_REG 0x0400078 -#define DEV_ID_DEV_STR_24_REG 0x040007c - -// Name: mdio (MDIO) -// Description: MDIO interface -// File: lib/verilog/core/io/mdio/xml/mdio.xml -#define MDIO_PHY_0_CONTROL_REG 0x0440000 -#define MDIO_PHY_0_STATUS_REG 0x0440004 -#define MDIO_PHY_0_PHY_ID_0_REG 0x0440008 -#define MDIO_PHY_0_PHY_ID_1_REG 0x044000c -#define MDIO_PHY_0_AUTONEGOTIATION_ADVERT_REG 0x0440010 -#define MDIO_PHY_0_AUTONEG_LINK_PARTNER_BASE_PAGE_ABILITY_REG 0x0440014 -#define MDIO_PHY_0_AUTONEG_EXPANSION_REG 0x0440018 -#define MDIO_PHY_0_AUTONEG_NEXT_PAGE_TX_REG 0x044001c -#define MDIO_PHY_0_AUTONEG_LINK_PARTNER_RCVD_NEXT_PAGE_REG 0x0440020 -#define MDIO_PHY_0_MASTER_SLAVE_CTRL_REG 0x0440024 -#define MDIO_PHY_0_MASTER_SLAVE_STATUS_REG 0x0440028 -#define MDIO_PHY_0_PSE_CTRL_REG 0x044002c -#define MDIO_PHY_0_PSE_STATUS_REG 0x0440030 -#define MDIO_PHY_0_MMD_ACCESS_CTRL_REG 0x0440034 -#define MDIO_PHY_0_MMD_ACCESS_STATUS_REG 0x0440038 -#define MDIO_PHY_0_EXTENDED_STATUS_REG 0x044003c -#define MDIO_PHY_1_CONTROL_REG 0x0440080 -#define MDIO_PHY_1_STATUS_REG 0x0440084 -#define MDIO_PHY_1_PHY_ID_0_REG 0x0440088 -#define MDIO_PHY_1_PHY_ID_1_REG 0x044008c -#define MDIO_PHY_1_AUTONEGOTIATION_ADVERT_REG 0x0440090 -#define MDIO_PHY_1_AUTONEG_LINK_PARTNER_BASE_PAGE_ABILITY_REG 0x0440094 -#define MDIO_PHY_1_AUTONEG_EXPANSION_REG 0x0440098 -#define MDIO_PHY_1_AUTONEG_NEXT_PAGE_TX_REG 0x044009c -#define MDIO_PHY_1_AUTONEG_LINK_PARTNER_RCVD_NEXT_PAGE_REG 0x04400a0 -#define MDIO_PHY_1_MASTER_SLAVE_CTRL_REG 0x04400a4 -#define MDIO_PHY_1_MASTER_SLAVE_STATUS_REG 0x04400a8 -#define MDIO_PHY_1_PSE_CTRL_REG 0x04400ac -#define MDIO_PHY_1_PSE_STATUS_REG 0x04400b0 -#define MDIO_PHY_1_MMD_ACCESS_CTRL_REG 0x04400b4 -#define MDIO_PHY_1_MMD_ACCESS_STATUS_REG 0x04400b8 -#define MDIO_PHY_1_EXTENDED_STATUS_REG 0x04400bc -#define MDIO_PHY_2_CONTROL_REG 0x0440100 -#define MDIO_PHY_2_STATUS_REG 0x0440104 -#define MDIO_PHY_2_PHY_ID_0_REG 0x0440108 -#define MDIO_PHY_2_PHY_ID_1_REG 0x044010c -#define MDIO_PHY_2_AUTONEGOTIATION_ADVERT_REG 0x0440110 -#define MDIO_PHY_2_AUTONEG_LINK_PARTNER_BASE_PAGE_ABILITY_REG 0x0440114 -#define MDIO_PHY_2_AUTONEG_EXPANSION_REG 0x0440118 -#define MDIO_PHY_2_AUTONEG_NEXT_PAGE_TX_REG 0x044011c -#define MDIO_PHY_2_AUTONEG_LINK_PARTNER_RCVD_NEXT_PAGE_REG 0x0440120 -#define MDIO_PHY_2_MASTER_SLAVE_CTRL_REG 0x0440124 -#define MDIO_PHY_2_MASTER_SLAVE_STATUS_REG 0x0440128 -#define MDIO_PHY_2_PSE_CTRL_REG 0x044012c -#define MDIO_PHY_2_PSE_STATUS_REG 0x0440130 -#define MDIO_PHY_2_MMD_ACCESS_CTRL_REG 0x0440134 -#define MDIO_PHY_2_MMD_ACCESS_STATUS_REG 0x0440138 -#define MDIO_PHY_2_EXTENDED_STATUS_REG 0x044013c -#define MDIO_PHY_3_CONTROL_REG 0x0440180 -#define MDIO_PHY_3_STATUS_REG 0x0440184 -#define MDIO_PHY_3_PHY_ID_0_REG 0x0440188 -#define MDIO_PHY_3_PHY_ID_1_REG 0x044018c -#define MDIO_PHY_3_AUTONEGOTIATION_ADVERT_REG 0x0440190 -#define MDIO_PHY_3_AUTONEG_LINK_PARTNER_BASE_PAGE_ABILITY_REG 0x0440194 -#define MDIO_PHY_3_AUTONEG_EXPANSION_REG 0x0440198 -#define MDIO_PHY_3_AUTONEG_NEXT_PAGE_TX_REG 0x044019c -#define MDIO_PHY_3_AUTONEG_LINK_PARTNER_RCVD_NEXT_PAGE_REG 0x04401a0 -#define MDIO_PHY_3_MASTER_SLAVE_CTRL_REG 0x04401a4 -#define MDIO_PHY_3_MASTER_SLAVE_STATUS_REG 0x04401a8 -#define MDIO_PHY_3_PSE_CTRL_REG 0x04401ac -#define MDIO_PHY_3_PSE_STATUS_REG 0x04401b0 -#define MDIO_PHY_3_MMD_ACCESS_CTRL_REG 0x04401b4 -#define MDIO_PHY_3_MMD_ACCESS_STATUS_REG 0x04401b8 -#define MDIO_PHY_3_EXTENDED_STATUS_REG 0x04401bc - -#define MDIO_PHY_GROUP_BASE_ADDR 0x0440000 -#define MDIO_PHY_GROUP_INST_OFFSET 0x0000080 - -// Name: dma (DMA) -// Description: DMA transfer module -// File: lib/verilog/core/dma/xml/dma.xml - -// Name: nf2_mac_grp (MAC_GRP_0) -// Description: Ethernet MAC group -// File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml -#define MAC_GRP_0_CONTROL_REG 0x0600000 -#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0600004 -#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_STORED_REG 0x0600008 -#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG 0x060000c -#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG 0x0600010 -#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_DEQUEUED_REG 0x0600014 -#define MAC_GRP_0_RX_QUEUE_NUM_WORDS_PUSHED_REG 0x0600018 -#define MAC_GRP_0_RX_QUEUE_NUM_BYTES_PUSHED_REG 0x060001c -#define MAC_GRP_0_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0600020 -#define MAC_GRP_0_TX_QUEUE_NUM_PKTS_ENQUEUED_REG 0x0600024 -#define MAC_GRP_0_TX_QUEUE_NUM_PKTS_SENT_REG 0x0600028 -#define MAC_GRP_0_TX_QUEUE_NUM_WORDS_PUSHED_REG 0x060002c -#define MAC_GRP_0_TX_QUEUE_NUM_BYTES_PUSHED_REG 0x0600030 - -// Name: nf2_mac_grp (MAC_GRP_1) -// Description: Ethernet MAC group -// File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml -#define MAC_GRP_1_CONTROL_REG 0x0640000 -#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0640004 -#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_STORED_REG 0x0640008 -#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG 0x064000c -#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG 0x0640010 -#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_DEQUEUED_REG 0x0640014 -#define MAC_GRP_1_RX_QUEUE_NUM_WORDS_PUSHED_REG 0x0640018 -#define MAC_GRP_1_RX_QUEUE_NUM_BYTES_PUSHED_REG 0x064001c -#define MAC_GRP_1_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0640020 -#define MAC_GRP_1_TX_QUEUE_NUM_PKTS_ENQUEUED_REG 0x0640024 -#define MAC_GRP_1_TX_QUEUE_NUM_PKTS_SENT_REG 0x0640028 -#define MAC_GRP_1_TX_QUEUE_NUM_WORDS_PUSHED_REG 0x064002c -#define MAC_GRP_1_TX_QUEUE_NUM_BYTES_PUSHED_REG 0x0640030 - -// Name: nf2_mac_grp (MAC_GRP_2) -// Description: Ethernet MAC group -// File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml -#define MAC_GRP_2_CONTROL_REG 0x0680000 -#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0680004 -#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_STORED_REG 0x0680008 -#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG 0x068000c -#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG 0x0680010 -#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_DEQUEUED_REG 0x0680014 -#define MAC_GRP_2_RX_QUEUE_NUM_WORDS_PUSHED_REG 0x0680018 -#define MAC_GRP_2_RX_QUEUE_NUM_BYTES_PUSHED_REG 0x068001c -#define MAC_GRP_2_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0680020 -#define MAC_GRP_2_TX_QUEUE_NUM_PKTS_ENQUEUED_REG 0x0680024 -#define MAC_GRP_2_TX_QUEUE_NUM_PKTS_SENT_REG 0x0680028 -#define MAC_GRP_2_TX_QUEUE_NUM_WORDS_PUSHED_REG 0x068002c -#define MAC_GRP_2_TX_QUEUE_NUM_BYTES_PUSHED_REG 0x0680030 - -// Name: nf2_mac_grp (MAC_GRP_3) -// Description: Ethernet MAC group -// File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml -#define MAC_GRP_3_CONTROL_REG 0x06c0000 -#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x06c0004 -#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_STORED_REG 0x06c0008 -#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG 0x06c000c -#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG 0x06c0010 -#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_DEQUEUED_REG 0x06c0014 -#define MAC_GRP_3_RX_QUEUE_NUM_WORDS_PUSHED_REG 0x06c0018 -#define MAC_GRP_3_RX_QUEUE_NUM_BYTES_PUSHED_REG 0x06c001c -#define MAC_GRP_3_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x06c0020 -#define MAC_GRP_3_TX_QUEUE_NUM_PKTS_ENQUEUED_REG 0x06c0024 -#define MAC_GRP_3_TX_QUEUE_NUM_PKTS_SENT_REG 0x06c0028 -#define MAC_GRP_3_TX_QUEUE_NUM_WORDS_PUSHED_REG 0x06c002c -#define MAC_GRP_3_TX_QUEUE_NUM_BYTES_PUSHED_REG 0x06c0030 - -// Name: cpu_dma_queue (CPU_QUEUE_0) -// Description: CPU DMA queue -// File: lib/verilog/core/io_queues/cpu_dma_queue/xml/cpu_dma_queue.xml - -// Name: cpu_dma_queue (CPU_QUEUE_1) -// Description: CPU DMA queue -// File: lib/verilog/core/io_queues/cpu_dma_queue/xml/cpu_dma_queue.xml - -// Name: cpu_dma_queue (CPU_QUEUE_2) -// Description: CPU DMA queue -// File: lib/verilog/core/io_queues/cpu_dma_queue/xml/cpu_dma_queue.xml - -// Name: cpu_dma_queue (CPU_QUEUE_3) -// Description: CPU DMA queue -// File: lib/verilog/core/io_queues/cpu_dma_queue/xml/cpu_dma_queue.xml - -// Name: SRAM (SRAM) -// Description: SRAM - -// Name: openflow_output_port_lookup (OPENFLOW_LOOKUP) -// Description: Output Port Lookup for OpenFlow hardware datapath -// File: projects/openflow_switch/include/output_port_lookup.xml -#define OPENFLOW_LOOKUP_WILDCARD_MISSES_REG 0x2000000 -#define OPENFLOW_LOOKUP_WILDCARD_HITS_REG 0x2000004 -#define OPENFLOW_LOOKUP_EXACT_MISSES_REG 0x2000008 -#define OPENFLOW_LOOKUP_EXACT_HITS_REG 0x200000c -#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_0_REG 0x2000010 -#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_1_REG 0x2000014 -#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_2_REG 0x2000018 -#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_3_REG 0x200001c -#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_4_REG 0x2000020 -#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_5_REG 0x2000024 -#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_6_REG 0x2000028 -#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_7_REG 0x200002c -#define OPENFLOW_LOOKUP_DUMY_SOFTWARE_0_REG 0x2000030 -#define OPENFLOW_LOOKUP_DUMY_SOFTWARE_1_REG 0x2000034 -#define OPENFLOW_LOOKUP_TIMER_REG 0x2000038 - -// Name: in_arb (IN_ARB) -// Description: Round-robin input arbiter -// File: lib/verilog/core/input_arbiter/rr_input_arbiter/xml/rr_input_arbiter.xml -#define IN_ARB_NUM_PKTS_SENT_REG 0x2000100 -#define IN_ARB_LAST_PKT_WORD_0_HI_REG 0x2000104 -#define IN_ARB_LAST_PKT_WORD_0_LO_REG 0x2000108 -#define IN_ARB_LAST_PKT_CTRL_0_REG 0x200010c -#define IN_ARB_LAST_PKT_WORD_1_HI_REG 0x2000110 -#define IN_ARB_LAST_PKT_WORD_1_LO_REG 0x2000114 -#define IN_ARB_LAST_PKT_CTRL_1_REG 0x2000118 -#define IN_ARB_STATE_REG 0x200011c - -// Name: vlan_remover (VLAN_REMOVER) -// Description: Remove vlan tag and ethtype if ethtype is vlan, and store them into module header -// File: projects/openflow_switch/include/vlan_remover.xml - -// Name: opl_processor (OPL_PROCESSOR) -// Description: opl_processor -// File: projects/openflow_switch/include/opl_processor.xml - -// Name: header_parser (HEADER_PARSER) -// Description: Chop ether/IP/UDP-TCP header into 11 tuples -// File: projects/openflow_switch/include/header_parser.xml - -// Name: match_arbiter (MATCH_ARBITER) -// Description: Arbitration between exact and wildcard lookups results -// File: projects/openflow_switch/include/match_arbiter.xml - -// Name: bram_output_queues (BRAM_OQ) -// Description: BRAM-based output queues -// File: lib/verilog/core/output_queues/bram_output_queues/xml/bram_output_queues.xml -#define BRAM_OQ_DISABLE_QUEUES_REG 0x2000300 -#define BRAM_OQ_QUEUE_0_NUM_PKT_BYTES_RECEIVED_REG 0x2000380 -#define BRAM_OQ_QUEUE_0_NUM_PKTS_RECEIVED_REG 0x2000384 -#define BRAM_OQ_QUEUE_0_NUM_PKTS_DROPPED_REG 0x2000388 -#define BRAM_OQ_QUEUE_0_NUM_WORDS_IN_QUEUE_REG 0x200038c -#define BRAM_OQ_QUEUE_1_NUM_PKT_BYTES_RECEIVED_REG 0x2000390 -#define BRAM_OQ_QUEUE_1_NUM_PKTS_RECEIVED_REG 0x2000394 -#define BRAM_OQ_QUEUE_1_NUM_PKTS_DROPPED_REG 0x2000398 -#define BRAM_OQ_QUEUE_1_NUM_WORDS_IN_QUEUE_REG 0x200039c -#define BRAM_OQ_QUEUE_2_NUM_PKT_BYTES_RECEIVED_REG 0x20003a0 -#define BRAM_OQ_QUEUE_2_NUM_PKTS_RECEIVED_REG 0x20003a4 -#define BRAM_OQ_QUEUE_2_NUM_PKTS_DROPPED_REG 0x20003a8 -#define BRAM_OQ_QUEUE_2_NUM_WORDS_IN_QUEUE_REG 0x20003ac -#define BRAM_OQ_QUEUE_3_NUM_PKT_BYTES_RECEIVED_REG 0x20003b0 -#define BRAM_OQ_QUEUE_3_NUM_PKTS_RECEIVED_REG 0x20003b4 -#define BRAM_OQ_QUEUE_3_NUM_PKTS_DROPPED_REG 0x20003b8 -#define BRAM_OQ_QUEUE_3_NUM_WORDS_IN_QUEUE_REG 0x20003bc -#define BRAM_OQ_QUEUE_4_NUM_PKT_BYTES_RECEIVED_REG 0x20003c0 -#define BRAM_OQ_QUEUE_4_NUM_PKTS_RECEIVED_REG 0x20003c4 -#define BRAM_OQ_QUEUE_4_NUM_PKTS_DROPPED_REG 0x20003c8 -#define BRAM_OQ_QUEUE_4_NUM_WORDS_IN_QUEUE_REG 0x20003cc -#define BRAM_OQ_QUEUE_5_NUM_PKT_BYTES_RECEIVED_REG 0x20003d0 -#define BRAM_OQ_QUEUE_5_NUM_PKTS_RECEIVED_REG 0x20003d4 -#define BRAM_OQ_QUEUE_5_NUM_PKTS_DROPPED_REG 0x20003d8 -#define BRAM_OQ_QUEUE_5_NUM_WORDS_IN_QUEUE_REG 0x20003dc -#define BRAM_OQ_QUEUE_6_NUM_PKT_BYTES_RECEIVED_REG 0x20003e0 -#define BRAM_OQ_QUEUE_6_NUM_PKTS_RECEIVED_REG 0x20003e4 -#define BRAM_OQ_QUEUE_6_NUM_PKTS_DROPPED_REG 0x20003e8 -#define BRAM_OQ_QUEUE_6_NUM_WORDS_IN_QUEUE_REG 0x20003ec -#define BRAM_OQ_QUEUE_7_NUM_PKT_BYTES_RECEIVED_REG 0x20003f0 -#define BRAM_OQ_QUEUE_7_NUM_PKTS_RECEIVED_REG 0x20003f4 -#define BRAM_OQ_QUEUE_7_NUM_PKTS_DROPPED_REG 0x20003f8 -#define BRAM_OQ_QUEUE_7_NUM_WORDS_IN_QUEUE_REG 0x20003fc - -#define BRAM_OQ_QUEUE_GROUP_BASE_ADDR 0x2000380 -#define BRAM_OQ_QUEUE_GROUP_INST_OFFSET 0x0000010 - -// Name: watchdog (WDT) -// Description: Watchdog timer -// File: projects/openflow_switch/include/watchdog.xml -#define WDT_ENABLE_FLG_REG 0x2000400 -#define WDT_COUNTER_REG 0x2000404 - -// Name: exact_match (EXACT_MATCH) -// Description: exact match lookup -// File: projects/openflow_switch/include/exact_match.xml - -// Name: wildcard_match (OPENFLOW_WILDCARD_LOOKUP) -// Description: wildcard match lookup -// File: projects/openflow_switch/include/wildcard_match.xml -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_0_REG 0x2001000 -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_1_REG 0x2001004 -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_2_REG 0x2001008 -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_3_REG 0x200100c -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_4_REG 0x2001010 -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_5_REG 0x2001014 -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_6_REG 0x2001018 -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_7_REG 0x200101c -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_8_REG 0x2001020 -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_9_REG 0x2001024 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_0_REG 0x2001028 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_1_REG 0x200102c -#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_2_REG 0x2001030 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_3_REG 0x2001034 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_4_REG 0x2001038 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_5_REG 0x200103c -#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_6_REG 0x2001040 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_7_REG 0x2001044 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_0_REG 0x2001048 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_1_REG 0x200104c -#define OPENFLOW_WILDCARD_LOOKUP_CMP_2_REG 0x2001050 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_3_REG 0x2001054 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_4_REG 0x2001058 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_5_REG 0x200105c -#define OPENFLOW_WILDCARD_LOOKUP_CMP_6_REG 0x2001060 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_7_REG 0x2001064 -#define OPENFLOW_WILDCARD_LOOKUP_READ_ADDR_REG 0x2001068 -#define OPENFLOW_WILDCARD_LOOKUP_WRITE_ADDR_REG 0x200106c -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG 0x2001070 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_1_REG 0x2001074 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_2_REG 0x2001078 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_3_REG 0x200107c -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_4_REG 0x2001080 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_5_REG 0x2001084 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_6_REG 0x2001088 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_7_REG 0x200108c -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_8_REG 0x2001090 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_9_REG 0x2001094 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_10_REG 0x2001098 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_11_REG 0x200109c -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_12_REG 0x20010a0 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_13_REG 0x20010a4 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_14_REG 0x20010a8 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_15_REG 0x20010ac -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_16_REG 0x20010b0 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_17_REG 0x20010b4 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_18_REG 0x20010b8 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_19_REG 0x20010bc -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_20_REG 0x20010c0 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_21_REG 0x20010c4 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_22_REG 0x20010c8 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_23_REG 0x20010cc -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_24_REG 0x20010d0 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_25_REG 0x20010d4 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_26_REG 0x20010d8 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_27_REG 0x20010dc -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_28_REG 0x20010e0 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_29_REG 0x20010e4 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_30_REG 0x20010e8 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_31_REG 0x20010ec -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG 0x20010f0 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_1_REG 0x20010f4 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_2_REG 0x20010f8 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_3_REG 0x20010fc -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_4_REG 0x2001100 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_5_REG 0x2001104 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_6_REG 0x2001108 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_7_REG 0x200110c -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_8_REG 0x2001110 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_9_REG 0x2001114 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_10_REG 0x2001118 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_11_REG 0x200111c -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_12_REG 0x2001120 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_13_REG 0x2001124 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_14_REG 0x2001128 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_15_REG 0x200112c -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_16_REG 0x2001130 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_17_REG 0x2001134 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_18_REG 0x2001138 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_19_REG 0x200113c -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_20_REG 0x2001140 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_21_REG 0x2001144 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_22_REG 0x2001148 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_23_REG 0x200114c -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_24_REG 0x2001150 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_25_REG 0x2001154 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_26_REG 0x2001158 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_27_REG 0x200115c -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_28_REG 0x2001160 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_29_REG 0x2001164 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_30_REG 0x2001168 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_31_REG 0x200116c -#define OPENFLOW_WILDCARD_LOOKUP_DUMMY_1_REG 0x2001170 -#define OPENFLOW_WILDCARD_LOOKUP_DUMMY_2_REG 0x2001174 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_0_REG 0x2001178 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_1_REG 0x200117c -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_2_REG 0x2001180 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_3_REG 0x2001184 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_4_REG 0x2001188 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_5_REG 0x200118c -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_6_REG 0x2001190 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_7_REG 0x2001194 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_8_REG 0x2001198 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_9_REG 0x200119c -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_10_REG 0x20011a0 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_11_REG 0x20011a4 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_12_REG 0x20011a8 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_13_REG 0x20011ac -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_14_REG 0x20011b0 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_15_REG 0x20011b4 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_16_REG 0x20011b8 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_17_REG 0x20011bc -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_18_REG 0x20011c0 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_19_REG 0x20011c4 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_20_REG 0x20011c8 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_21_REG 0x20011cc -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_22_REG 0x20011d0 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_23_REG 0x20011d4 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_24_REG 0x20011d8 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_25_REG 0x20011dc -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_26_REG 0x20011e0 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_27_REG 0x20011e4 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_28_REG 0x20011e8 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_29_REG 0x20011ec -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_30_REG 0x20011f0 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_31_REG 0x20011f4 - -// Name: DRAM (DRAM) -// Description: DRAM - -#endif diff --git a/openflow/hw-lib/skeleton/debug.h b/openflow/hw-lib/skeleton/debug.h deleted file mode 100644 index d6a8f8af..00000000 --- a/openflow/hw-lib/skeleton/debug.h +++ /dev/null @@ -1,106 +0,0 @@ - -#ifndef OF_HW_DEBUG_H -#define OF_HW_DEBUG_H 1 - -#include -#include - -#if !defined(HWTABLE_NO_DEBUG) -extern int of_hw_debug; -#define dbg_send(mod, lvl, fmt, args...) \ - if (of_hw_debug >= (lvl)) fprintf(stderr, fmt, ##args) -#endif - -#define DBG_LVL_NONE -1 /* All output off */ -#define DBG_LVL_ERROR 0 /* Default value */ -#define DBG_LVL_ALWAYS 0 /* For requested dump output */ -#define DBG_LVL_WARN 1 -#define DBG_LVL_VERBOSE 2 -#define DBG_LVL_VVERB 3 /* Include success indications */ - -/* Sorry for the lazy syntax here. */ -#define DBG_CHECK(lvl) (((lvl) >= 0) && (of_hw_debug >= (lvl))) -#define DBG_ERROR(fmt, args...) dbg_send(0, DBG_LVL_ERROR, fmt, ##args) -#define DBG_ALWAYS(fmt, args...) dbg_send(0, DBG_LVL_ALWAYS, fmt, ##args) -#define DBG_WARN(fmt, args...) dbg_send(0, DBG_LVL_WARN, fmt, ##args) -#define DBG_VERBOSE(fmt, args...) dbg_send(0, DBG_LVL_VERBOSE, fmt, ##args) -#define DBG_VVERB(fmt, args...) dbg_send(0, DBG_LVL_VVERB, fmt, ##args) -#define DBG_NONE(fmt, args...) -/* Same as DEBUG_ALWAYS */ -#define DEBUGK(fmt, args...) dbg_send(0, DBG_LVL_ALWAYS, fmt, ##args) - -#define REPORT_ERROR(str) \ - DBG_ERROR("ERROR: %s:%d. %s\n", __FUNCTION__, __LINE__, str) - -/* Default debugging location string */ -#define ANNOUNCE_LOCATION DBG_VVERB("%s: %d\n", __FUNCTION__, __LINE__) -#define DBG_INCR(cnt) (++(cnt)) - -/* Should assert return? Not presently */ -#define ASSERT(cond) \ - if (!(cond)) DBG_ERROR("ASSERTION %s IN %s FAILED LINE %d\n", \ - #cond, __FUNCTION__, __LINE__) - -/* DEBUG for HW flow lists */ -#define HW_FLOW_MAGIC 0xba5eba11 -#define HW_FLOW_MAKE_VALID(hf) (hf)->magic = HW_FLOW_MAGIC -#define HW_FLOW_IS_VALID(hf) \ - (((hf) != NULL) && ((hf)->magic == HW_FLOW_MAGIC)) - -/* - * Carry out an operation and check for error, optionally returning - * from the calling routine. To avoid compiler - * warnings in routines with void return, we give two macros. - * - * WARNING: This check uses rv != 0 (not just rv < 0). - */ - -#define TRY(op, str) do { \ - int rv; \ - if (((rv = (op)) < 0)) { \ - DBG_ERROR("ERROR %d: %s\n", rv, str); \ - return rv; \ - } else { \ - DBG_NONE("%s: success\n", str); \ - } \ - } while (0) - -#define TRY_NR(op, str) do { \ - int rv; \ - if (((rv = (op)) != 0)) { \ - DBG_ERROR("ERROR %d: %s\n", rv, str); \ - } else { \ - DBG_NONE("%s: success\n", str); \ - } \ - } while (0) - -#else /* No debugging */ - -#define DBG_CHECK(lvl) 0 -#define ANNOUNCE_LOCATION -#define ACT_STRING(action) "" -#define DBG_INCR(cnt) -#define DBG_ERROR(fmt, args...) -#define DBG_ALWAYS(fmt, args...) -#define DBG_WARN(fmt, args...) -#define DBG_VERBOSE(fmt, args...) -#define DBG_VVERB(fmt, args...) -#define DBG_NONE(fmt, args...) -#define DEBUGK(fmt, args...) -#define REPORT_ERROR(str) - -#define ASSERT(cond) - -#define HW_FLOW_MAKE_VALID(hf) -#define HW_FLOW_IS_VALID(hf) 1 - -#define TRY(op, str) do { \ - int rv; \ - if (((rv = (op)) != 0)) return rv; \ - } while (0) - -#define TRY_NR(op, str) (void)op - -#endif /* !defined(HWTABLE_NO_DEBUG) */ - -#endif /* OF_HW_DEBUG_H */ diff --git a/openflow/hw-lib/skeleton/hw_drv.c b/openflow/hw-lib/skeleton/hw_drv.c deleted file mode 100644 index 0ecd5909..00000000 --- a/openflow/hw-lib/skeleton/hw_drv.c +++ /dev/null @@ -1,309 +0,0 @@ -/* - * Skeleton hardware datapath, internal implemenation - * - */ -#include - -#include -#include - -#include "list.h" - -#include "os.h" -#include "debug.h" -#include "of_hw_platform.h" -#include "hw_drv.h" -#include "hw_flow.h" -#include "port.h" -#include "txrx.h" -#include "udatapath/switch-flow.h" - -/**************************************************************** - * - * Hardware resource management section - * - ****************************************************************/ - -static int global_init_done = 0; -int of_hw_drv_instances = 0; - -#if !defined(HWTABLE_NO_DEBUG) -int of_hw_debug = DBG_LVL_WARN; -#endif - -/* Internal initialization of HW datapath structures */ -static int -hw_drv_global_init(int init_hw) -{ - HW_DRV_MUTEX_INIT; - of_hw_ports_init(); - - if (init_hw) { /* Do hardware initialization */ - TRY(PLATFORM_INIT(), "PLATFORM INIT"); - TRY_NR(of_hw_fp_setup(), "global FP setup"); - } - - global_init_done = 1; - return 0; -} - -/* Skeleton capabilities structure */ -static of_hw_driver_caps_t of_hw_caps = { - .flags = , - .max_flows = , - .wc_supported = OFPFW_ALL, - .actions_supported = OFPAT_XXX, - .ofpc_flags = OFPC_XXX -}; - -/* Initialize the internal HW datapath structure */ -static int -hw_drv_int_init(of_hw_driver_int_t *hw_int, struct datapath *dp) -{ - static int dp_idx = 0; - - /* Fill in caps object */ - memcpy(&hw_int->hw_driver.caps, &of_hw_caps, sizeof(of_hw_caps)); - hw_int->dp = dp; - hw_int->dp_idx = dp_idx++; - - hw_int->n_flows = 0; - list_init(&hw_int->flows); - list_init(&hw_int->iter_flows); - hw_int->next_serial = 0; - - return 0; -} - -/**************************************************************** - * - * Driver functions - * - ****************************************************************/ - -/* - * of_hw_ioctl - * - * HW IOCTL function - */ - -static int -of_hw_ioctl(of_hw_driver_t *hw_drv, uint32_t op, void **io_param, - int *io_len UNUSED) -{ - int val; - of_hw_driver_int_t *hw_int; - int rv = 0; - - hw_int = (of_hw_driver_int_t *)hw_drv; - - switch (op) { - case OF_HW_IOCTL_TABLE_DEBUG_SET: - val = *(int *)(*io_param); - DBG_WARN("Changing table debug value to %d\n", val); - /* FIXME: Use HW driver for debug level? */ - hw_int->table_debug_level = val; - of_hw_debug = val; - break; - case OF_HW_IOCTL_PORT_DEBUG_SET: - val = *(int *)(*io_param); - DBG_WARN("Changing port debug value to %d\n", val); - hw_int->port_debug_level = val; - break; - case OF_HW_IOCTL_BYTE_PKT_CNTR_SET: - val = *(int *)(*io_param); - if ((val != OF_HW_CNTR_PACKETS) && - (val != OF_HW_CNTR_BYTES)) { - DBG_ERROR("Bad byte/pkt counters select value %d\n", val); - } else { - hw_int->stat_sel = val; - } - break; - default: - rv = -1; /* Change to UNSUPPORTED */ - break; - } - - return 0; -} - -static void -of_hw_table_destroy(struct sw_table *table) -{ - of_hw_driver_int_t *hw_int; - - hw_int = (of_hw_driver_int_t *)table; - if (hw_int != NULL && hw_int->dp != NULL) { - DBG_WARN("Table destroy called for dp idx %d\n", - hw_int->dp_idx); - } else { - DBG_ERROR("Table destroy called on NULL dp\n"); - } - - delete_of_hw_driver(&hw_int->hw_driver); -} - -static int -of_hw_table_iterate(struct sw_table *table, - const struct sw_flow_key *key, uint16_t out_port, - struct sw_table_position *position, - int (*callback)(struct sw_flow *flow, void *private), - void *private) -{ - - of_hw_driver_int_t *hw_int; - struct sw_flow *flow; - unsigned long start; - - hw_int = (of_hw_driver_int_t *)table; - if (hw_int != NULL) { - start = ~position->private[0]; - LIST_FOR_EACH (flow, struct sw_flow, iter_node, &hw_int->iter_flows) { - if (flow->serial <= start - && flow_matches_2wild(key, &flow->key) - && flow_has_out_port(flow, out_port)) { - int error; - - /* Update stats as that's what's generally used */ - TRY_NR(of_hw_sw_flow_stat_update(flow, NULL, false), - "sw flow stat update"); - error = callback(flow, private); - if (error) { - position->private[0] = ~(flow->serial - 1); - return error; - } - } - } - } else { - DBG_ERROR("Table iterate called on NULL driver or SW flow table\n"); - return -1; - } - - return 0; -} - -static const char *hw_drv_name = "HW FlowDriver"; - -static void -of_hw_sw_table_stats(struct sw_table *table, struct sw_table_stats *stats) -{ - of_hw_driver_int_t *hw_int; - unsigned long matched = 0; - unsigned long missed = 0; - - hw_int = (of_hw_driver_int_t *)table; - stats->name = hw_drv_name; - stats->wildcards = OFPFW_ALL; - stats->n_flows = hw_int->n_flows; - stats->max_flows = of_hw_caps.max_flows; - /* FIXME: Collect stats */ - TRY_NR(of_hw_table_stats_update(hw_int, &matched, &missed), - "of_hw_table_stats_update"); - stats->n_lookup = missed + matched; - stats->n_matched = matched; -} - -static int -of_hw_table_stats_get(of_hw_driver_t *hw_drv, struct ofp_table_stats *stats) -{ - DBG_WARN("TABLE STATS FIXME\n"); - return 0; -} - -/* - * Create and initialize a new hardware datapath object - */ - -of_hw_driver_t * -new_of_hw_driver(struct datapath *dp) -{ - struct sw_table *sw_tab; - of_hw_driver_t *hw_drv; - of_hw_driver_int_t *hw_int; - - if (!global_init_done) { - if (hw_drv_global_init(1) < 0) { - REPORT_ERROR("HW driver global init failed\n"); - return NULL; - } - } - hw_int = ALLOC(sizeof(*hw_int)); - if (hw_int == NULL) { - REPORT_ERROR("Could not allocate HW driver\n"); - return NULL; - } - memset(hw_int, 0, sizeof(*hw_int)); - - if (hw_drv_int_init(hw_int, dp) < 0) { - FREE(hw_int); - return NULL; - } - - - /* These all point to the same place */ - hw_drv = &hw_int->hw_driver; - sw_tab = &hw_drv->sw_table; - - sw_tab->n_lookup = 0; - sw_tab->n_matched = 0; - - /* Fill out the function pointers */ - sw_tab->lookup = of_hw_flow_lookup; - sw_tab->insert = of_hw_flow_install; - sw_tab->modify = of_hw_flow_modify; - sw_tab->delete = of_hw_flow_delete; - sw_tab->timeout = of_hw_flow_timeout; - - sw_tab->destroy = of_hw_table_destroy; - sw_tab->iterate = of_hw_table_iterate; - sw_tab->stats = of_hw_sw_table_stats; - - hw_drv->table_stats_get =of_hw_table_stats_get; - hw_drv->port_stats_get = of_hw_port_stats_get; - hw_drv->flow_stats_get = NULL; - hw_drv->aggregate_stats_get = NULL; - - hw_drv->port_add = of_hw_port_add; - hw_drv->port_remove = of_hw_port_remove; - hw_drv->port_link_get = of_hw_port_link_get; - hw_drv->port_enable_set = of_hw_port_enable_set; - hw_drv->port_enable_get = of_hw_port_enable_get; - hw_drv->port_queue_config = of_hw_port_queue_config; - hw_drv->port_queue_remove = of_hw_port_queue_remove; - hw_drv->port_change_register = of_hw_port_change_register; - - hw_drv->packet_send = of_hw_packet_send; - hw_drv->packet_receive_register = of_hw_packet_receive_register; - - hw_drv->ioctl = of_hw_ioctl; - - ++of_hw_drv_instances; - - return hw_drv; -} - -/* - * Deallocate a hardware datapath object - * If clear_hw is set, the HW structures related to the - * datapath are also cleared. - * - * In general, clear_hw should be set for now. - */ -void -delete_of_hw_driver(of_hw_driver_t *hw_drv) -{ - int idx; - of_hw_driver_int_t *hw_int; - - hw_int = (of_hw_driver_int_t *)hw_drv; - - /* Clear the port table of ownership for this dp */ - FOREACH_DP_PORT(idx, hw_drv) { - of_hw_ports[idx].owner = NULL; - } - - of_hw_flow_remove_all(hw_int); - - FREE(hw_drv); - --of_hw_drv_instances; -} diff --git a/openflow/hw-lib/skeleton/hw_drv.h b/openflow/hw-lib/skeleton/hw_drv.h deleted file mode 100644 index 7e6ecb0e..00000000 --- a/openflow/hw-lib/skeleton/hw_drv.h +++ /dev/null @@ -1,97 +0,0 @@ -#ifndef OF_HW_DRV_H -#define OF_HW_DRV_H 1 - -#include -#include "of_hw_platform.h" -#include "list.h" - -/**************************************************************** - * - * High Level Design Notes - * - * Hardware tables are managed field_control_t and entry_control_t - * structures in hw_flow.h; these roughly mirror the HW structure - * and are preallocated. - * - * The glue between these and SW flows are provided by the HW flow - * objects (also in hw_flow.h) which are dynamically allocated and - * logically extend the SW flow object. - * - * A linear table of HW flow objects is maintained, mostly drawn - * from the existing table-linear.c implementation in udatapath. - * - */ - -/**************************************************************** - * Hardware independent port mapping macros - ****************************************************************/ - -/* Map ports using software data structures and DP check; independent of HW */ -#define OF_PORT_IN_DP(_hwdrv, _i) (((_i) < OF_HW_MAX_PORT) && \ - (of_hw_ports[_i].owner == (of_hw_driver_t *)(_hwdrv))) - -#define OF_PORT_TO_HW_PORT(_hwdrv, _i) \ - (OF_PORT_IN_DP(_hwdrv, _i) ? of_hw_ports[_i].port : -1) - -/* TBD: Define flow tracking objects */ - -/**************************************************************** - * - * Hardware datapath internal control structure - * Extends generic hardware datapath structure - * (which currently extends software table structure) - * - ****************************************************************/ - -/* Counts the number of instances */ -extern int of_hw_drv_instances; - -typedef struct of_hw_driver_int { - of_hw_driver_t hw_driver; - struct datapath *dp; /* Owning datapath */ - - /* Maintain a linked list of flows for tracking */ - struct list flows; /* The main list */ - struct list iter_flows; /* For iteration operation */ - unsigned long int next_serial; - - /* Callback function for received packets. */ - of_packet_in_f rx_handler; - void *rx_cookie; - - /* Callback function for port change notification */ - of_port_change_f port_change; - void *port_change_cookie; - - /* Lock object? */ - - // struct list sw_flows; - // struct list iter_sw_flows; - // struct sw_flow *iter_state; /* Place tracker for interrupted iterations */ - - /* Stats */ - uint32_t n_flows; /* Current number of flows in table */ - uint32_t n_inserts; /* Total inserts */ - uint32_t rx_pkt_alloc_failures; - uint32_t insert_errors; - - /* Configuration */ - /* Port bitmap of ports in DP by device */ - FIXME port_bitmap; - FIXME flood_bitmap; - int stat_sel; /* Packets or bytes */ - int dp_idx; /* In HW dp, but not SW dp */ - - int table_debug_level; - int port_debug_level; -} of_hw_driver_int_t; - -/* HW_DRV_MUTEX object ? */ - -#define HW_DRV_MUTEX_INIT /* TBD */ -#define HW_DRV_LOCK /* TBD */ -#define HW_DRV_UNLOCK /* TBD */ - -#define HW_INT(hw_drv) ((of_hw_driver_int_t *)hw_drv) - -#endif /* OF_HW_DRV_H */ diff --git a/openflow/hw-lib/skeleton/hw_flow.c b/openflow/hw-lib/skeleton/hw_flow.c deleted file mode 100644 index 2f9d6eca..00000000 --- a/openflow/hw-lib/skeleton/hw_flow.c +++ /dev/null @@ -1,708 +0,0 @@ -/* - * Functions related to hardware flow processing; this is the glue - * and administration between upper level flow operations and lower - * level field processor operations. - */ - -#include -#include -#include - -#include "os.h" -#include "debug.h" -#include "hw_drv.h" -#include "port.h" -#include "hw_flow.h" -#include "udatapath/switch-flow.h" -#include "udatapath/datapath.h" -#include "lib/packets.h" - -static field_control_t field_control; - -/**************************************************************** - * - * SW/HW flow correlation book keeping routines - * - ****************************************************************/ - -/* Allocate and initialize a HW flow control structure. */ -static hw_flow_t * -hw_flow_create(struct sw_flow *flow) -{ - hw_flow_t *hw_flow; - - if ((hw_flow = ALLOC(sizeof(*hw_flow))) != NULL) { - memset(hw_flow, 0, sizeof(*hw_flow)); - HW_FLOW_MAKE_VALID(hw_flow); - hw_flow->flow = flow; - flow->private = (void *)hw_flow; - } - - return hw_flow; -} - -/* Remove an FP entry from a device */ -static int -HW_entry_remove(entry_control_t *entry) -{ - FIXME; - - return 0; -} - -/**************************************************************** - * - * Flow stats operations - * - ****************************************************************/ - -/* - * Read and convert the stats for an FP entry; maintains state - * of last counter value read and accumulates differences. - * - * Assumes mutex held. - */ -static int -entry_stat_update(entry_control_t *ent, int *used) -{ - unsigned long int cur_counter; - - FIXME_get_current_stats(cur_counter); - - ent->total_counter += cur_counter - ent->last_counter; - ent->last_counter = cur_counter; - - if (used != NULL) { - *used |= (ent->used_check != cur_counter); - ent->used_check = cur_counter; - } - - return 0; -} - -/* - * Get the stats for an OF (SW) flow object from HW tables - * NOTE: This will clear any existing value from the flow - * counters; if SW table counters need to be added in, that - * should be done after this calculation. - * - * If used is non-NULL, it will be filled with a boolean - * indication of whether the flow's counters have changed - * from their current state. - * - * Assumes mutex held. - * - * If force_sync is true, will sync SW counters with HW first - */ -int -of_hw_sw_flow_stat_update(struct sw_flow *flow, int *used, int force_sync) -{ - entry_control_t *ent; - hw_flow_t *hw_flow; - int idx; - - if (used != NULL) { - *used = false; - } - hw_flow = (hw_flow_t *)(flow->private); - if (!HW_FLOW_IS_VALID(hw_flow)) { - DBG_ERROR("BAD HW FLOW OBJECT %p for flow %p\n", hw_flow, flow); - return -1; - } - ASSERT(hw_flow->entry_count <= HW_FLOWS_PER_FLOW_MAX); - - if (force_sync) { - FIXME_sync_hw_stats(); - } - - /* FIXME: Will this accumulate and clear HW counters? */ - hw_flow->hw_byte_count = hw_flow->hw_packet_count = 0; - for (idx = 0; idx < hw_flow->entry_count; idx++) { - ent = hw_flow->entry_list[idx]; - - if (entry_stat_update(ent, used) < 0) { - DBG_WARN("Warning: could not get stats for flow\n"); - continue; - } - FIXME_update proper hw_flow counters; - } - flow->packet_count = hw_flow->hw_packet_count; - flow->byte_count = hw_flow->hw_byte_count; - - return 0; -} - -/* Read all the stats from the chip and update counters in flow tab */ -/* Index 0 holds default rule that indicates a missed count */ -/* ASSUMES LOCK HELD */ -int -of_hw_table_stats_update(of_hw_driver_int_t *hw_drv, unsigned long *matched, - unsigned long *missed) -{ - struct sw_flow *flow, *n; - of_hw_driver_int_t *hw_int; - - hw_int = (of_hw_driver_int_t *)hw_drv; - *matched = 0; - *missed = 0; - - if (STATS_BYTES(hw_int->stat_sel)) { /* Lookup count not supported */ - return -1; - } - - LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &hw_int->flows) { - if (flow->private != NULL) { - TRY_NR(of_hw_sw_flow_stat_update(flow, NULL, false), - "update flow stat"); - *matched += flow->packet_count; - } - } - - /* - * FIXME: To get missed stats, query entry 0 of HW table. - * This isn't really correct if there are entries in the SW datapath - * - * FIXME: If there are multiple data paths, should have one - * default entry qualifying on ports in that datapath with - * another entry dropping any packets on other ports. - */ - { - field_control_t *fc; - entry_control_t *ent; - - fc = &field_control; - ent = &fc->entry_list[0]; - ASSERT(ent->in_use); - TRY_NR(entry_stat_update(ent, NULL), "tab: entry_stat_update"); - *missed += ent->total_counter; - } - - return 0; -} - -/* - * Remove the FP entry or entries associated to a SW flow from the HW; - * - */ -static int -hw_flow_remove(struct sw_flow *flow) -{ - field_control_t *fc; - entry_control_t *ent; - hw_flow_t *hw_flow; - int idx; - -#if 0 /* Do not remove entries (debugging) */ - return 0; -#endif - - if (flow == NULL) { - return 0; - } - - hw_flow = (hw_flow_t *)(flow->private); - DBG_VERBOSE("Removing hw flow %p, flow %p\n", hw_flow, flow); - if (!HW_FLOW_IS_VALID(hw_flow)) { - return 0; - } - ASSERT(hw_flow->entry_count <= HW_FLOWS_PER_FLOW_MAX); - - TRY_NR(of_hw_sw_flow_stat_update(flow, NULL, true), - "rmv flow stat update"); - for (idx = 0; idx < hw_flow->entry_count; idx++) { - ent = hw_flow->entry_list[idx]; - ASSERT(ent != NULL); - - TRY_NR(HW_entry_remove(ent), "HW_entry_remove"); - hw_flow->entry_list[idx] = NULL; - } - FREE(hw_flow); - flow->private = NULL; - - return 0; -} - - -/**************************************************************** - * - * Important support routines related to FP setup, actions, flows - * - ****************************************************************/ - -/* ASSERT: of_port belongs to datapath */ -static void -add_dport_to_extra(of_hw_driver_int_t *hw_int, int of_port, - hw_flow_extra_t *extra) -{ - ASSERT(OF_PORT_IN_DP(hw_int, of_port)); - - extra->dest_port = MAP_OF_PORT_TO_HW_PORT(hw_int, of_port); - FIXME_update extra->dest_count if appropriate; -} - -/* Set up flood/all bitmaps - * NOTE: Assumes source port is not wildcarded. - */ -static void -mcast_bitmaps_set(of_hw_driver_int_t *hw_int, hw_flow_extra_t *extra, - int dest_port) -{ - FIXME; -} - -/* - * Validate actions for a flow relative to HW capabilities; - * - * Bool: true means supported, false not supported - * - * Accumulate additional info about the flow in extra. Specifically, - * this determines the output ports on each physical device related - * to the flow. - * - * FIXME: No-flood ports are currently not specified - */ - -static int -actions_supported_check(of_hw_driver_int_t *hw_int, - const struct sw_flow_key *key, - const struct ofp_action_header *actions, - size_t actions_len, - hw_flow_extra_t *extra) -{ - uint8_t *p; - int src_port; /* Port in host order */ - int dest_port; /* Port in host order */ - int action; - int src_is_wc = false; /* Is source wildcarded? */ - - ANNOUNCE_LOCATION; - ASSERT(extra != NULL); - - FIXME("probably needs work for your platform"); - - p = (uint8_t *)actions; - src_port = ntohs(key->flow.in_port); - - src_is_wc = key->wildcards & OFPFW_IN_PORT; - if (!src_is_wc) { - if (OF_PORT_IN_DP(hw_int, src_port)) { - extra->source_port = MAP_TO_HW_PORT(hw_int, src_port); - } else { - DBG_WARN("Source port %d not in DP %d\n", src_port, - hw_int->dp_idx); - return false; - } - } else { - extra->source_port = -1; - if (of_hw_drv_instances > 1) { - DBG_WARN("Source port WC not supported w/ multi-DP\n"); - return false; /* Not currently supported w/ multiple datapaths */ - } - /* NOTE/FIXME: Source wildcard with multiple output ports requires - * using a per-port hardware flow rule to allow filtering of - * the source port. (Currently not supported and checked below.) - */ - } - - while (actions_len > 0) { - struct ofp_action_header *ah = (struct ofp_action_header *)p; - struct ofp_action_output *oa = (struct ofp_action_output *)p; - size_t len = ntohs(ah->len); - - action = ntohs(ah->type); - DBG_VVERB("action chk %d\n", action); - /* Currently supported: output port(s) action */ - if ((action < 0) || (action > ACTION_LAST)) { - DBG_WARN("Unknown action id %d\n", action); - return false; - } - - if (action_map[action] == ACTION_NOT_SUPPORTED) { - DBG_WARN("Action %d not supported\n", action); - return false; - } - - /* Support front panel ports plus IN_PORT, ALL, FLOOD. */ - if ((action == OFPAT_OUTPUT) || (action == OFPAT_ENQUEUE)) { - /* FIXME: For now, using the fact that enqueue and output - * actions are the same at the start of the structure - */ - dest_port = ntohs(oa->port); - if (dest_port == OFPP_TABLE) { /* Unsupported */ - DBG_WARN("Warning: TABLE output action seen\n"); - return false; - } else if (OF_PORT_IN_DP(hw_int, dest_port)) { - add_dport_to_extra(hw_int, dest_port, extra); - } else if ((dest_port == OFPP_FLOOD) || (dest_port == OFPP_ALL)) { - mcast_bitmaps_set(hw_int, extra, dest_port); - } else if (dest_port == OFPP_IN_PORT) { - if (src_is_wc) { - DBG_WARN("Warning: IN_PORT action on source wildcard\n"); - return false; - } - add_dport_to_extra(hw_int, src_port, extra); - } else if (dest_port == OFPP_CONTROLLER) { - /* Controller/local are implemented with a "copy to CPU" - * action and a special reason code; Don't count as output port - */ - extra->local_reason |= CPU_REASON_TO_CONTROLLER; - } else if (dest_port == OFPP_LOCAL) { - extra->local_reason |= CPU_REASON_TO_LOCAL; - } else { /* NORMAL */ - // DBG_WARN("Output action to port 0x%x not supported\n", - // dest_port); - // return false; /* FIXME: Ignore bad ports for now */ - } - if (action == OFPAT_ENQUEUE) { - uint32 qid; - struct ofp_action_enqueue *ea; - ea = (struct ofp_action_enqueue *)p; - qid = ntohl(ea->queue_id); - if ((extra->cosq = of_hw_qid_find(dest_port, qid)) < 0) { - DBG_WARN("Warning: qid %d, port %d, map to cos failed\n", - qid, dest_port); - } - } - } - p += len; - actions_len -= len; - } - - if (src_is_wc && (extra->dest_count > 1)) { - DBG_WARN("Warning: multi dest w/ src wildcard\n"); - return false; - } - - DBG_VERBOSE("Actions supported\n"); - return true; -} - -/**************************************************************** - * - * FP Table management and manipulation routines - * - ****************************************************************/ - -/* - * Functions related to hardware flow table manipulation and maintenance - */ - -/* Set up field control structure; should be idempotent */ -static void -field_control_init(void) -{ - field_control_t *fc; - int idx; - - fc = &field_control; - fc->entry_count = 0; - for (idx = 0; idx < FIELD_ENTRY_MAX; idx++) { - fc->entry_list[idx].in_use = 0; - fc->entry_list[idx].hw_flow = NULL; - fc->entry_list[idx].index = idx; - fc->entry_list[idx].last_counter = 0; - fc->entry_list[idx].counter_last_check = 0; - fc->entry_list[idx].total_counter = 0; - } -} - -/* Alloc HW entry control structure, add qualification, actions and install */ -static int -hw_entry_install(of_hw_driver_int_t *hw_int, - struct sw_flow *flow, hw_flow_t *hw_flow, - hw_flow_extra_t *extra) -{ - - /* Install HW entry */ - FIXME; -} - -/* - * hw_flow_install - * - * Install HW table entries corresponding to the given SW flow - */ -static int -hw_flow_install(of_hw_driver_int_t *hw_int, struct sw_flow *flow, - hw_flow_extra_t *extra) -{ - hw_flow_t *hw_flow; - - /* Allocate the HW flow object */ - if ((hw_flow = hw_flow_create(flow)) == NULL) { - DBG_ERROR("failed to create hw flow struct\n"); - return -1; - } - - DBG_VERBOSE("hw flow install: sw %p. hw %p\n", flow, hw_flow); - TRY(hw_entry_install(hw_int, 0, flow, hw_flow, extra), - "local entry"); - - return 0; -} - -/**************************************************************** - * - * The driver APIs - * - ****************************************************************/ - -/* - * Install a flow. - * - * First, check that the flow is supported; simultaneously, build - * up the "extra" information needed by the hardware for its installation. - * This includes bitmaps of the ports to which the packet will be - * forwarded (on local and remote devices if appropriate). - * - * Then look to see if the flow should overwrite an existing entry. - * If so, just remove that entry. - * - * Then call hw_flow_install which does all the actual HW changes - * based on the flow and on extra. - */ - -/* NOTE: Returns 1 if flow installed, not normal error code */ -int -of_hw_flow_install(struct sw_table *sw_tab, struct sw_flow *flow) -{ - hw_flow_extra_t extra; - of_hw_driver_int_t *hw_int; - int hw_rc = 0; - int sw_insert_done = 0; - struct sw_flow *f; - - hw_int = (of_hw_driver_int_t *)sw_tab; - - DBG_VERBOSE("flow install %p\n", flow); - memset(&extra, 0, sizeof(extra)); - extra.cosq = -1; - - if (!actions_supported_check(hw_int, &flow->key, flow->sf_acts->actions, - flow->sf_acts->actions_len, &extra)) { - /* Unsupported actions */ - DBG_VERBOSE("HW install failed: Unsupported actions\n"); - return 0; - } - - /* LOCK; */ - /* Go through list looking for matching flows */ - LIST_FOR_EACH (f, struct sw_flow, node, &hw_int->flows) { - if (f->priority == flow->priority - && f->key.wildcards == flow->key.wildcards - && flow_matches_2wild(&f->key, &flow->key)) { - /* Just remove the HW flow; install other below */ - TRY_NR(hw_flow_remove(f), "hw_flow_remove for replace"); - flow->serial = f->serial; - list_replace(&flow->node, &f->node); - list_replace(&flow->iter_node, &f->iter_node); - sw_insert_done = 1; - flow_free(f); - break; - } - if (f->priority < flow->priority) { - break; - } - } - - /* ASSERT: sw_insert_done OR f points to insertion point for flow */ - - hw_rc = hw_flow_install(hw_int, flow, &extra); - - if (hw_rc < 0) { - hw_int->insert_errors++; - if (sw_insert_done) { /* Remove from SW list */ - list_remove(&flow->node); - list_remove(&flow->iter_node); - flow_free(flow); - hw_int->n_flows--; - } - } else { - hw_int->n_flows++; - hw_int->n_inserts++; - if (!sw_insert_done) { - flow->serial = hw_int->next_serial++; - list_insert(&f->node, &flow->node); - list_push_front(&hw_int->iter_flows, &flow->iter_node); - } - } - /* UNLOCK */ - - if (hw_rc < 0) { - DBG_WARN("Could not install flow in HW\n"); - if (sw_insert_done) { /* Remove from SW list */ - DBG_WARN("Removed matching flow but could not replace in HW\n"); - } - return 0; - } - - return 1; -} - -/* FIXME: Change API to return list of deleted flows? */ -/* Would make this easier */ -/* Remove a flow or flows from the HW and SW tracking tables */ -int -of_hw_flow_delete(struct datapath *dp, struct sw_table *sw_tab, - const struct sw_flow_key *key, uint16_t out_port, - uint16_t priority, int strict) -{ - of_hw_driver_int_t *hw_int = (of_hw_driver_int_t *)sw_tab; - struct sw_flow *flow, *n; - int count = 0; - struct list deleted; - - DBG_VERBOSE("delete: dp %p, idx %d, key %p, out 0x%x, prio %d, strict %d\n", - dp, hw_int->dp_idx, key, out_port, priority, strict); - - list_init(&deleted); - - /* LOCK; */ - LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &hw_int->flows) { - if (flow_matches_desc(&flow->key, key, strict) - && flow_has_out_port(flow, out_port) - && (!strict || (flow->priority == priority))) { - TRY_NR(hw_flow_remove(flow), "hw flow remove"); - list_remove(&flow->node); - list_remove(&flow->iter_node); - list_push_back(&deleted, &flow->node); - count++; - } - } - /* UNLOCK; */ - - /* Notify DP of deleted flows */ - LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &deleted) { - dp_send_flow_end(dp, flow, flow->reason); - list_remove(&flow->node); - flow_free(flow); - } - - return count; -} - - -/* - * Modify an existing flow - * - * We chicken out and just de-install/re-install in HW - */ -int -of_hw_flow_modify(struct sw_table *sw_tab, const struct sw_flow_key *key, - uint16_t priority, int strict, - const struct ofp_action_header *actions, size_t actions_len) -{ - of_hw_driver_int_t *hw_int = (of_hw_driver_int_t *)sw_tab; - struct sw_flow *flow; - int count = 0; - hw_flow_extra_t extra; - - memset(&extra, 0, sizeof(extra)); - extra.cosq = -1; -#if defined(PLATFORM_HAS_REMOTES) - extra.new_vid = -1; - extra.new_pcp = -1; -#endif - - if (!actions_supported_check(hw_int, &flow->key, actions, - actions_len, &extra)) { - /* Unsupported actions */ - DBG_VERBOSE("Mod actions-supported failed: Unsupported actions\n"); - return 0; - } - - /* LOCK; */ - LIST_FOR_EACH (flow, struct sw_flow, node, &hw_int->flows) { - if (flow_matches_desc(&flow->key, key, strict) - && (!strict || (flow->priority == priority))) { - /* Change the flow, de-install from HW and re-install */ - TRY_NR(hw_flow_remove(flow), "hw_flow_remove modify"); - flow_replace_acts(flow, actions, actions_len); - TRY_NR(hw_flow_install(hw_int, flow, &extra), - "hw_flow_install modify"); - /* FIXME: Clear stats on flow if updated? */ - count++; - } - } - /* UNLOCK; */ - - return count; -} - -/* - * Update stats - * Call sw tracking table timeout - * Iterate the deleted object list and call HW flow remove - */ -void -of_hw_flow_timeout(struct sw_table *sw_tab, struct list *deleted) -{ - of_hw_driver_int_t *hw_int = (of_hw_driver_int_t *)sw_tab; - struct sw_flow *flow, *n; - int used; - uint64_t now = time_msec(); - - /* LOCK; */ - /* FIXME */ - LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &hw_int->flows) { - if (of_hw_sw_flow_stat_update(flow, &used, false) == 0) { - if (used) { - flow->used = now; - } else { - if (flow_timeout(flow)) { - DBG_VERBOSE("Flow %p expired\n", flow); - list_remove(&flow->node); - list_remove(&flow->iter_node); - list_push_back(deleted, &flow->node); - ASSERT(flow->private != NULL); - TRY_NR(hw_flow_remove(flow), "hw flow remove, timeout"); - hw_int->n_flows--; - } - } - } - } - - /* UNLOCK; */ -} - -struct sw_flow * -of_hw_flow_lookup(struct sw_table *sw_tab, const struct sw_flow_key *key) -{ - of_hw_driver_int_t *hw_int = (of_hw_driver_int_t *)sw_tab; - struct sw_flow *flow; - - LIST_FOR_EACH (flow, struct sw_flow, node, &hw_int->flows) { - if (flow_matches_1wild(key, &flow->key)) - return flow; - } - return NULL; -} - -int -of_hw_flow_stats_get(of_hw_driver_t *hw_drv, struct ofp_match match, - struct ofp_flow_stats **stats, int *count) -{ - DBG_WARN("FIXME FLOW STATS GET\n"); - return 0; -} - -int -of_hw_aggregate_stats_get(struct ofp_match match, - struct ofp_aggregate_stats_reply *stats) -{ - DBG_WARN("FIXME AGGREGATE STATS GET\n"); - return 0; -} - -void -of_hw_flow_remove_all(of_hw_driver_int_t *hw_int) -{ - struct sw_flow *flow, *n; - - /* FIXME: Other de-init? Keep count of DPs? */ - LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &hw_int->flows) { - TRY_NR(hw_flow_remove(flow), "hw_flow_remove all"); - list_remove(&flow->node); - list_remove(&flow->iter_node); - } -} diff --git a/openflow/hw-lib/skeleton/hw_flow.h b/openflow/hw-lib/skeleton/hw_flow.h deleted file mode 100644 index 7c801c60..00000000 --- a/openflow/hw-lib/skeleton/hw_flow.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef SAMPLE_PLATFORM_HW_FLOW_H -#define SAMPLE_PLATFORM_HW_FLOW_H 1 - -/* - * Hardware Flow operations: The glue between software flows and - * actual hardware table entries. - */ - -#include -#include - -#include "of_hw_platform.h" - -/* DEBUG for HW flow lists */ -#define HW_FLOW_MAGIC 0xba5eba11 -#define HW_FLOW_MAKE_VALID(hf) (hf)->magic = HW_FLOW_MAGIC -#define HW_FLOW_IS_VALID(hf) \ - (((hf) != NULL) && ((hf)->magic == HW_FLOW_MAGIC)) - -/* Some flows require multiple HW entries */ -#define HW_FLOWS_PER_FLOW_MAX (2) - -/* The glue between SW flows and HW entries */ -typedef struct hw_flow { - struct sw_flow *flow; /* Corresponding SW flow */ - of_hw_driver_t *hw_drv; /* DP for this flow; MAY BE NULL for internal */ - int entry_count; /* SW flow may require multiple HW table entries */ - entry_control_t *entry_list[HW_FLOWS_PER_FLOW_MAX]; - uint32 hw_packet_count; - uint32 hw_byte_count; - uint32 magic; /* DEBUG */ -} hw_flow_t; - -/* Extra info needed by hardware about flow entry; - * determined during supported check; all in host order - * - * For smac, dmac, vid and priority, if these are changed at ingress - * and a remote rule is necessary, the remote rule must have the - * rewrite values to match. This is indicated if value is not -1. - */ -typedef struct hw_flow_extra_s { - int source_port; /* If single source port, what is it */ - int dest_port; /* If one dest port, what is it */ - /* If multi dest ports, one pbmp per device */ - FIXME dports; - int dest_count; /* Drop (0), unicast (1), multicast (>1) */ - uint32 local_reason; /* Why forwarded to CPU */ - int cosq; /* For enqueue action */ -} hw_flow_extra_t; - -/* Driver functions */ -extern int of_hw_flow_install(struct sw_table *flowtab, struct sw_flow *flow); -extern int of_hw_flow_modify(struct sw_table *flowtab, - const struct sw_flow_key *key, uint16_t priority, int strict, - const struct ofp_action_header *actions, size_t actions_len); -extern int of_hw_flow_delete(struct datapath *dp, struct sw_table *flowtab, - const struct sw_flow_key *key, uint16_t out_port, - uint16_t priority, int strict); -extern void of_hw_flow_timeout(struct sw_table *flowtab, - struct list *deleted); -extern struct sw_flow *of_hw_flow_lookup(struct sw_table *flowtab, - const struct sw_flow_key *key); - - -extern int of_hw_sw_flow_stat_update(struct sw_flow *flow, int *used, - int force_sync); -extern int of_hw_flow_stats_get(of_hw_driver_t *hw_drv, struct ofp_match, - struct ofp_flow_stats **stats, int *count); -extern int of_hw_aggregate_stats_get(struct ofp_match, - struct ofp_aggregate_stats_reply *stats); - -/* Controls a single FP (HW table flow) entry */ -struct entry_control_s { - /* These must be persistent; update fp_entry_remove if you change this */ - int index; /* This entry-s index in field_control list */ - - int in_use; - hw_flow_t *hw_flow; - - /* - * HW specific info - */ - FIXME; - - unsigned long int used_check; /* Last counter; for checking if used */ - unsigned long int last_counter; /* pkts or bytes, see stat_sel above */ - unsigned long int counter_last_check; /* Track entry usage by cntr */ - unsigned long int total_counter; /* FIXME: u64? */ -}; - -/* Driver associated with a HW entry */ -#define HW_ENTRY_DRIVER(ent) ((ent)->hw_flow->hw_drv) - -/* FP control structure */ -struct field_control_s { - /* HW Specific info */ - FIXME; - int entry_count; /* How many entries in use */ - entry_control_t entry_list[FIELD_ENTRY_MAX]; /* Instantiation of entries */ -}; - -/* FIXME: Do we need reference counts on stat objects? */ - -extern int of_hw_fp_setup(void); -extern int of_hw_table_stats_update(of_hw_driver_int_t *hw_drv, - unsigned long *matched, unsigned long *missed); - -extern void of_hw_flow_remove_all(of_hw_driver_int_t *hw_int); - - -#endif /* SAMPLE_PLATFORM_HW_FLOW_H */ diff --git a/openflow/hw-lib/skeleton/of_hw_platform.h b/openflow/hw-lib/skeleton/of_hw_platform.h deleted file mode 100644 index 11a3364c..00000000 --- a/openflow/hw-lib/skeleton/of_hw_platform.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef HW_LIB_SKELETON_PLATFORM_H -#define HW_LIB_SKELETON_PLATFORM_H 1 - -#if defined(OF_HW_DP_MAIN) -#define P printf -#else -#define P printf -#endif - -/* - * General Hardware Switch platform defines - * - * Also includes platform specific definitions based on make defines - */ - -#define OF_HW_MAX_PORT 64 - -/* Reasons that a packet is being forwarded to the controller; */ -#define CPU_REASON_DEFAULT (1 << 0) -#define CPU_REASON_TO_CONTROLLER (1 << 1) -#define CPU_REASON_TO_LOCAL (1 << 2) - -#define EXACT_MATCH_PRIORITY TBD - -/**************************************************************** - * - * Platform specific defines and linkage - * - * Implicitly we have a "driver" for the board which includes - * hardware specific information including HW to OF port mapping - * - ****************************************************************/ - -#if defined(OF_SAMPLE_PLAT) -#include "sample_plat.h" -#endif - -#endif /* HW_LIB_SKELETON_PLATFORM_H */ diff --git a/openflow/hw-lib/skeleton/os.h b/openflow/hw-lib/skeleton/os.h deleted file mode 100644 index 268daa97..00000000 --- a/openflow/hw-lib/skeleton/os.h +++ /dev/null @@ -1,29 +0,0 @@ - -/* - * OS abstractions - */ - -#ifndef OF_HW_OS_H -#define OF_HW_OS_H 1 - -#include - -#define ALLOC(bytes) malloc(bytes) -#define FREE(ptr) free(ptr) - -#define PKT_ALLOC(bytes) TBD -#define PKT_FREE(ptr) TBD - -#define MUTEX_DECLARE(name) TBD -#define MUTEX_INIT(name) TBD -#define MUTEX_LOCK(name) TBD -#define MUTEX_UNLOCK(name) TBD - -#define TIME_NOW(time) TBD -#define TIME_DIFF(diff, early, late) TBD - -/* FIXME */ -#include -#define os_pkt_free(pkt) ofpbuf_delete(pkt) - -#endif /* OF_HW_OS_H */ diff --git a/openflow/hw-lib/skeleton/port.c b/openflow/hw-lib/skeleton/port.c deleted file mode 100644 index 7d8c5e3b..00000000 --- a/openflow/hw-lib/skeleton/port.c +++ /dev/null @@ -1,497 +0,0 @@ -/* - * Port related HW datapath functions - */ - -#include -#include - -#include "xtoxll.h" -#include "hw_drv.h" -#include "of_hw_platform.h" -#include "port.h" -#include "debug.h" - -/* Single set of HW port objects managed here; indexed by OF port num */ -of_hw_port_t of_hw_ports[OF_HW_MAX_PORT]; - -/* Check if hw DP and port are valid and if port belongs to the DP */ -#define CHECK_PORT(_drv, _p) do { \ - if ((_drv) == NULL) return -1; \ - if (((_p) < 1) || ((_p) > OF_HW_MAX_PORT)) { \ - REPORT_ERROR("bad port number"); \ - return -1; \ - } \ - if (!(OF_PORT_IN_DP(((of_hw_driver_int_t *)(_drv)), (_p)))) { \ - REPORT_ERROR("DP does not own port"); \ - return -1; \ - } \ -} while (0) - - -/* - * Queue configuration section - * - * Port queue: Per port structure for queue related information - * Queue map: Indicated queue is mapped and what OF qid its mapped to as - * well as queue properties (min-bw). Indexed by OF port number; - * per port instance of array - * - */ - -typedef struct queue_map_s { - int in_use; - uint32_t qid; /* OF queue name */ - int min_bw; /* OF value, tenths of a percent */ -} queue_map_t; - -typedef struct port_queue_s { - int speed; /* In Mbps */ - queue_map_t queue_map[NUM_COS_QUEUES]; -} port_queue_t; - -static port_queue_t port_queue[OF_HW_MAX_PORT]; - -/* Return the cos for the queue matching qid if found; else -1. - * Assumes lock held - */ -static int -qid_find(int of_port, uint32_t qid) -{ - struct queue_map_s *qm; - int cosq; - - qm = port_queue[of_port].queue_map; - for (cosq = 0; cosq < NUM_COS_QUEUES; cosq++) { - if (qm[cosq].in_use && (qid == qm[cosq].qid)) { - return cosq; - } - } - - return -1; -} - -/* Return the cos for the queue matching qid if found; else -1. - * Assumes lock held - */ -int -of_hw_qid_find(int of_port, uint32_t qid) -{ - int cosq; - - /* LOCK */ - cosq = qid_find(of_port, qid); - /* UNLOCK */ - - return cosq; -} - -/* - * Map an OF qid to a COS queue index; if not present, add it if possible - * Assumes lock held - */ -static int -qid_find_add(int of_port, uint32_t qid) -{ - struct queue_map_s *qm; - int cosq; - - cosq = qid_find(of_port, qid); - if (cosq >= 0) { - return cosq; - } - - /* Not found; add queue */ - for (cosq = 0; cosq < NUM_COS_QUEUES; cosq++) { - qm = port_queue[of_port].queue_map; - if (!qm[cosq].in_use) { - qm[cosq].in_use = true; - qm[cosq].qid = qid; - return cosq; - } - } - - return -1; -} - -/* - * Port speed has changed; requires queue b/w to change - */ -static void -port_speed_change_reconfig(of_hw_driver_int_t *hw_int, int of_port) -{ - int cosq; - struct queue_map_s *qm; - int rv; - - /* LOCK */ - for (cosq = 0; cosq < NUM_COS_QUEUES; cosq++) { - qm = port_queue[of_port].queue_map; - if (qm[cosq].in_use) { - /* FIXME: Calc and program values for HW for min-bw */ - if (rv < 0) { - DBG_ERROR("ERROR: Set min BW for queue on port %d " - "link change\n", of_port); - } - } - } - /* UNLOCK */ -} - - -/* Internal handler for port link status changes */ - -/* FIXME */ -static void -of_hw_linkscan_handler(...) -{ - int of_port; - of_hw_driver_int_t *hw_int; - - /* Assumes speed, linkstatus from HW */ - /* Map port to internal port object */ - of_port = HW_MAP_TO_PORT(); - if ((of_port < 0) || (of_port > OF_HW_MAX_PORT)) { - return; - } - - /* LOCK */ - hw_int = (of_hw_driver_int_t *)(of_hw_ports[of_port].owner); - if (hw_int != NULL) { - if (port_queue[of_port].speed != speed) { - port_queue[of_port].speed = speed; - port_speed_change_reconfig(hw_int, of_port); - } - } - /* Record in local struct */ - of_hw_ports[of_port].link = linkstatus != 0; - if ((hw_int != NULL) && (hw_int->port_change != NULL)) { - hw_int->port_change(of_port, linkstatus != 0, - hw_int->port_change_cookie); - } - /* UNLOCK */ -} - -static int linkscan_registered; - -/* - * of_hw_ports_init - * Set up hardware port map - */ -void -of_hw_ports_init(void) -{ - int i; - - for (i = 0; i < OF_HW_MAX_PORT; i++) { - of_hw_ports[i].owner = NULL; - of_hw_ports[i].port = MAP_OF_PORT_TO_HW_PORT(i); - } - - /* FIXME: REGISTER FOR LINK CHANGE CALLBACK */ - /* Always register linkscan handler */ - linkscan_registered = 1; - - /* Get current link status for each port; ignore errors for bad ports */ - for (i = 0; i < OF_HW_MAX_PORT; i++) { - /* FIXME */ - HW_LINK_STATUS_GET(of_hw_ports[i].port, &of_hw_ports[i].link); - } -} - - -#define HTON64 htonll - -/* Get port stats into a standard openflow port stats structure */ -int -of_hw_port_stats_get(of_hw_driver_t *hw_drv, int of_port, - struct ofp_port_stats *stats) -{ - uint64 v1, v2; - - CHECK_PORT(hw_drv, of_port); - - -#if 0 /* FIXME; Get stats from HW */ - HW_STAT(of_port, snmpIfInNUcastPkts, &v1); - HW_STAT(of_port, snmpIfInUcastPkts, &v2); - v1 += v2; - stats->rx_packets = HTON64(v1); - HW_STAT(of_port, snmpIfOutNUcastPkts, &v1); - HW_STAT(of_port, snmpIfOutUcastPkts, &v2); - v1 += v2; - stats->tx_packets = HTON64(v1); - HW_STAT(of_port, snmpIfInOctets, &v1); - stats->rx_bytes = HTON64(v1); - HW_STAT(of_port, snmpIfOutOctets, &v1); - stats->tx_bytes = HTON64(v1); - HW_STAT(of_port, snmpIfInDiscards, &v1); - stats->rx_dropped = HTON64(v1); - HW_STAT(of_port, snmpIfOutDiscards, &v1); - stats->tx_dropped = HTON64(v1); - HW_STAT(of_port, snmpIfInErrors, &v1); - stats->rx_errors = HTON64(v1); - HW_STAT(of_port, snmpIfOutErrors, &v1); - stats->tx_errors = HTON64(v1); -#endif - - v1 = UINT64_C(0xffffffffffffffff); - stats->rx_frame_err = HTON64(v1); - stats->rx_over_err = HTON64(v1); - stats->rx_crc_err = HTON64(v1); - stats->collisions = HTON64(v1); - - return 0; -} - -/* - * port_add/remove(table, port) - * - * The indicated port has been added to/removed from the datapath - * Add also maps the of_port number to the hw_port indicated - * - * SPEC CHANGE: If of_port passed is less than 0, use the passed - * port name to determine the port number and attach to that value; - * - * Returns the of_port number or -1 on error - */ -int -of_hw_port_add(of_hw_driver_t *hw_drv, int of_port, const char *hw_name) -{ - int hw_idx; - of_hw_port_t *port_ctl; - of_hw_driver_int_t *hw_int; - - if (hw_drv == NULL) { - return -1; - } - - hw_idx = hw_port_name_to_index(hw_name); - if (of_port < 0) { - of_port = hw_idx + 1; - } else if (hw_idx + 1 != of_port) { - DBG_WARN("Add Port: OF port %d does not match name %s\n", - of_port, hw_name); - } - - if (of_port >= OF_HW_MAX_PORT) { - DBG_ERROR("Add Port: Bad port number %d\n", of_port); - return -1; - } - - hw_int = (of_hw_driver_int_t *)hw_drv; - port_ctl = &of_hw_ports[of_port]; - - HW_DRV_LOCK; - if (port_ctl->owner == NULL) { - port_ctl->owner = hw_drv; - /* FIXME: port bitmaps in HW structure */ - } else if (port_ctl->owner != hw_drv) { - DBG_ERROR("Add Port: OF port %d owned by other DP\n", of_port); - } else { - DBG_WARN("Add Port: OF port %d already added\n", of_port); - } - HW_DRV_UNLOCK; - - return of_port; -} - -int -of_hw_port_remove(of_hw_driver_t *hw_drv, of_port_t of_port) -{ - of_hw_port_t *port_ctl; - of_hw_driver_int_t *hw_int; - int rc = 0; - - if (hw_drv == NULL) { - return -1; - } - - if ((of_port < 1) || (of_port >= OF_HW_MAX_PORT)) { - DBG_ERROR("Remove Port: Bad port number %d\n", of_port); - return -1; - } - - hw_int = (of_hw_driver_int_t *)hw_drv; - port_ctl = &of_hw_ports[of_port]; - - HW_DRV_LOCK; - if (port_ctl->owner == NULL) { - DBG_WARN("Remove Port: OF port %d already free\n", of_port); - } else if (port_ctl->owner != hw_drv) { - DBG_ERROR("Remove Port: OF port %d owned by other DP\n", of_port); - rc = -1; - } else { - port_ctl->owner = NULL; - } - /* FIXME UPDATE HW port bitmaps in hw_int */ - HW_DRV_UNLOCK; - - return rc; -} - - -/* - * port_link_get(table, port) - * port_enable_set(table, port, enable) - * port_enable_get(table, port) - * - * Get/set the indicated properties of a port. Only real ports - * set with port_add are supported. - */ -int -of_hw_port_link_get(of_hw_driver_t *hw_drv, int of_port) -{ - int rc; - int link; - - CHECK_PORT(hw_drv, of_port); - - if (linkscan_registered) { - return of_hw_ports[of_port].link; - } - - if ((rc = HW_LINK_GET(of_hw_ports[of_port].port, &link)) < 0) { - DBG_ERROR("link_get: error %d port %d\n", rc, of_port); - /* Return link down on error */ - return 0; - } - - return link ? 1 : 0; -} - -int -of_hw_port_enable_set(of_hw_driver_t *hw_drv, int of_port, int enable) -{ - int rc; - - CHECK_PORT(hw_drv, of_port); - - if ((rc = HW_PORT_ENABLE_SET(of_hw_ports[of_port].port, enable)) < 0) { - DBG_ERROR("of_hw_port_enable_set: error %d port %d\n", - rc, of_port); - return rc; - } - - return 0; -} - -int -of_hw_port_enable_get(of_hw_driver_t *hw_drv, int of_port) -{ - int rc; - int enable; - - CHECK_PORT(hw_drv, of_port); - - if ((rc = HW_PORT_ENABLE_GET(of_hw_ports[of_port].port, &enable)) < 0) { - DBG_ERROR("of_hw_port_enable_get: error %d port %d\n", - rc, of_port); - return rc; - } - - return enable ? 1 : 0; -} - - -/* - * port_change_register - * - * Register a callback function to receive port change notifications - * from ports in this datapath; only one callback per datapath is - * supported. - */ -int -of_hw_port_change_register(of_hw_driver_t *hw_drv, of_port_change_f callback, - void *cookie) -{ - of_hw_driver_int_t *dp_int; - - dp_int = (of_hw_driver_int_t *)hw_drv; - dp_int->port_change = callback; - dp_int->port_change_cookie = cookie; - - return 0; -} - -/* - * Init COS queue setup. The queues number is fixed at 8. Deficit - * round robin is the discipline, initially with all equal weights. - * As queues are configured with min bandwidth reservations, the - * weights are adjusted to ensure the requested targets. - * - * For now, these are device generic; may need to specialize in the - * future. - */ - -int -of_hw_cos_setup(int num_cos) -{ - /* FIXME: Set up COS queues */ - - return 0; -} - -/* - * Add and/or configure an output queue on a port. - * - * If qid exists, update. If not, look for an unreferenced queue and - * set the qid to that value. - * - * Note that when a port state changes, may need to re-configure - * the bandwidth values for the port's queues. - */ - -int -of_hw_port_queue_config(of_hw_driver_t *hw_drv, int of_port, uint32_t qid, - int min_bw) /* In tenths of a percent */ -{ - int min_kbps; - of_hw_driver_int_t *hw_int; - int cosq; - struct queue_map_s *qm; - int rv; - - hw_int = (of_hw_driver_int_t *)hw_drv; - - CHECK_PORT(hw_int, of_port); - - /* LOCK */ - /* Get the current bandwidth of the port (cached?) */ - if ((cosq = qid_find_add(of_port, qid)) < 0) { - DBG_ERROR("Could not add queue: of port %d, qid %d\n", of_port, qid); - /* UNLOCK */ - return -1; - } - qm = &port_queue[of_port].queue_map[qid]; - qm->min_bw = min_bw; - - HW_SET_MIN_BW(...); - /* UNLOCK */ - - return (rv != 0) ? -1 : 0; -} - -/* Remove a queue from a port; this potentially affects the queue - * configuration otherwise we would not worry about it here. - * Return -1 if not found; 0 on success - */ - -int -of_hw_port_queue_remove(of_hw_driver_t *hw_drv, int of_port, uint32_t qid) -{ - int cosq; - - (void)hw_drv; - /* LOCK */ - if ((cosq = qid_find(of_port, qid)) == -1) { - /* UNLOCK */ - return -1; - } - - /* Do we need to update stats or DRR weights or anything? */ - - port_queue[of_port].queue_map[cosq].in_use = false; - - /* UNLOCK */ - return 0; -} diff --git a/openflow/hw-lib/skeleton/port.h b/openflow/hw-lib/skeleton/port.h deleted file mode 100644 index dd2c0828..00000000 --- a/openflow/hw-lib/skeleton/port.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef OF_HW_PORT_H -#define OF_HW_PORT_H 1 - -#include -#include -#include "of_hw_platform.h" - -#define NUM_COS_QUEUES 8 - -/* Define port mapping object indexed by OF number */ -typedef struct of_hw_port_s { - of_hw_driver_t *owner; /* Owner of this port */ - int port; /* Physical port number on device */ - int link; /* Link state */ - /* TBD: Keep track of link state and don't transmit if down? */ - /* Add other physical info here as needed */ -} of_hw_port_t; - -extern of_hw_port_t of_hw_ports[OF_HW_MAX_PORT]; - -#define FOREACH_DP_PORT(_idx, _drv) \ - for (_idx = 0; _idx < OF_HW_MAX_PORT; _idx++) \ - if (of_hw_ports[_idx].owner == (of_hw_driver_t *)(_drv)) - -extern int of_hw_cos_setup(int num_cos); -extern int of_hw_qid_find(int of_port, uint32_t qid); - -extern void of_hw_ports_init(void); -extern int of_hw_port_stats_get(of_hw_driver_t *hw_drv, int of_port, - struct ofp_port_stats *stats); -extern int of_hw_port_add(of_hw_driver_t *hw_drv, int of_port, - const char *hw_name); -extern int of_hw_port_remove(of_hw_driver_t *hw_drv, of_port_t of_port); -extern int of_hw_port_link_get(of_hw_driver_t *hw_drv, int of_port); -extern int of_hw_port_enable_set(of_hw_driver_t *hw_drv, int of_port, - int enable); -extern int of_hw_port_enable_get(of_hw_driver_t *hw_drv, int of_port); -extern int of_hw_port_queue_config(of_hw_driver_t *hw_drv, int of_port, - uint32_t qid, int min_bw); /* In tenths of a percent */ -extern int of_hw_port_queue_remove(of_hw_driver_t *hw_drv, int of_port, - uint32_t qid); -extern int of_hw_port_change_register(of_hw_driver_t *hw_drv, - of_port_change_f callback, void *cookie); - -#endif /* OF_HW_PORT_H */ diff --git a/openflow/hw-lib/skeleton/sample_plat.c b/openflow/hw-lib/skeleton/sample_plat.c deleted file mode 100644 index 17f3747b..00000000 --- a/openflow/hw-lib/skeleton/sample_plat.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * sample_plat.c - * - * FIXME: Standard confidential header - * - * $Id: $ - */ - -/* - * Sample hardware initialization functions - */ - -#include "debug.h" -#include "of_hw_platform.h" - -#if defined(SAMPLE_PLAT) - -#include "port.h" - -/* sample_plat_port_setup - * - * Set up linkscan and necessary spanning tree for ports - * Disable VLAN dropping - */ -static int -sample_plat_port_setup(...) -{ - - return 0; -} - -#if defined(OF_HW_DP_MAIN) && defined(SAMPLE_HW_PLAT) - -/* If defined, need to do init here */ - -/* - * sample_plat_pre_init - * - * Turn off everything that might cause problems during init - */ - -static int -sample_plat_pre_init(void) -{ - /* bring system down to known state */ - return 0; -} - -/* - */ -int -sample_plat_init(void) -{ - /* Init system */ - - /* First, clear out everything */ - sample_plat_pre_init(); - - /* ... */ - - sample_plat_port_setup(...); - - return 0; -} - -/* FIXME: Deal with initial FP setup */ - -#else /* Not stand alone init; Other code does init */ - -int -sample_plat_init(void) -{ - DBG_WARN("sample_plat_init\n"); - - TRY(sample_plat_port_setup(...), "sample plat init port setup"); - - return 0; -} - -#endif - -#endif /* SAMPLE_PLAT */ diff --git a/openflow/hw-lib/skeleton/sample_plat.h b/openflow/hw-lib/skeleton/sample_plat.h deleted file mode 100644 index 3d88eb01..00000000 --- a/openflow/hw-lib/skeleton/sample_plat.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef SAMPLE_PLAT_H -#define SAMPLE_PLAT_H 1 - - -#include -#include -#include - -#include - -#define OF_HW_MAX_PORTS 4 - -static inline int -of_port_to_hw_port(int of_port) -{ - return of_port - 1; -} - - -/* Map port to OF port number */ -static inline int -of_hw_port_to_of_port(int port) -{ - if ((port < 0) || (port > 3)) { - return -1; - } - - return port + 1; -} - -#define _IS_DIGIT(c) ((c) >= '0' && (c) <= '9') - -/* Map name to hw port number: N => N-1 - ge0 => 0 where "ge" can be any string and 0 can be any number -*/ - -static inline int -hw_port_name_to_index(const char *name) -{ - - if (_IS_DIGIT(name[0])) { - /* Treat as 1-based, OF number */ - i = strtoul(&name[0], NULL, 10); - return i - 1; - } - - len = strlen(name); - for (idx = 0; idx < len && !_IS_DIGIT(name[idx]); idx++) ; - - if ((idx < len) && _IS_DIGIT(name[idx])) { - i = strtoul(&name[idx], NULL, 10); - return i; - } - - return -1; -} -#undef _IS_DIGIT - - - -#endif /* SAMPLE_PLAT_H */ diff --git a/openflow/hw-lib/skeleton/txrx.c b/openflow/hw-lib/skeleton/txrx.c deleted file mode 100644 index 950d839f..00000000 --- a/openflow/hw-lib/skeleton/txrx.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Transmit and receive related functions for hardware platforms - */ - -#include -#include "os.h" -#include "hw_drv.h" -#include "txrx.h" -#include "port.h" -#include "debug.h" -#include "of_hw_platform.h" - -static int pkt_count, failures, prev_success, free_count, error_free; -static void -tx_pkt_callback(...) -{ - of_packet_t *of_pkt = cookie; - - /* os_pkt_free(of_pkt->os_pkt); */ - FREE(of_pkt); - /* ... */ - ++free_count; -} - -/* - * tx_packet_send(table, of_port, pkt, flags) - * - * Send packet to an openflow port. - * - * Proposed flags: - * APPLY_FLOW_TABLE: If set, and if the hardware supports - * it, send the packet through the flow table with the source - * port being the local CPU port. (Would be nice to have - * a flexible source port indicated; could hide in flags...) - * - * Assumes buffer in pkt struct can be used for sending data - * - * - */ -int -of_hw_packet_send(of_hw_driver_t *hw_drv, int of_port, of_packet_t *pkt, - uint32_t flags) -{ - /* FIXME: Code to prepare and send pkt */ - return 0; -} - -/* Callback function registered with HW */ -static int -of_hw_rx(...) -{ - /* Sample RX handler */ - int of_port; - of_hw_driver_int_t *hw_drv; - of_packet_t *of_pkt; - int pkt_len; - - /* map receive port to of_port */ - /* map received packet to of_pkt */ - /* Call callback */ - - of_port = of_hw_port_to_of_port(receive_port); - if (of_port < 0) { - return hw_not_handled; - } - - /* LOCK */ - hw_drv = (of_hw_driver_int_t *)(of_hw_ports[of_port].owner); - if ((hw_drv == NULL) || (hw_drv->rx_handler == NULL)) { - /* UNLOCK */ - return hw_not_handled; - } - - of_pkt = ALLOC(sizeof(of_packet_t)); - if (of_pkt == NULL) { - ++hw_drv->rx_pkt_alloc_failures; - /* UNLOCK */ - return hw_not_handled; - } - pkt_len = pkt->tot_len; - - /* FIXME: FOR NOW, COPY DATA INTO NEW BUFFER; */ - of_pkt->data = ALLOC(pkt_len); - if (of_pkt->data == NULL) { - FREE(of_pkt); - /* UNLOCK */ - return hw_not_handled; - } - - /* Handle VLAN tagging if needed */ - /* Coy pkt data appropriately */ - - /* FIXME: Determine reason (dflt rule or directed) */ - /* FIXME: Return code interpretation? */ - /* OFPR_NO_MATCH, No matching flow. */ - /* OFPR_ACTION Action explicitly output to controller. */ - hw_drv->rx_handler(of_port, of_pkt, 0, hw_drv->rx_cookie); - /* UNLOCK */ - - return hw_handled; -} - -static int rx_registered = 0; - -/* - * packet_receive_register - * - * Register a callback function to receive packets from ports in - * this datapath - */ -int -of_hw_packet_receive_register(of_hw_driver_t *hw_drv, - of_packet_in_f callback, void *cookie) -{ - of_hw_driver_int_t *dp_int; - int rv; - - /* Register for link status changes */ - if (!rx_registered) { - /* Set up low level pkt receive for callback */ - rx_registered = 1; - } - - dp_int = (of_hw_driver_int_t *)hw_drv; - dp_int->rx_handler = callback; - dp_int->rx_cookie = cookie; - - return 0; -} diff --git a/openflow/hw-lib/skeleton/txrx.h b/openflow/hw-lib/skeleton/txrx.h deleted file mode 100644 index 1aef9026..00000000 --- a/openflow/hw-lib/skeleton/txrx.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef OF_HW_TXRX_H -#define OF_HW_TXRX_H 1 - -#include -#include - -extern int of_hw_packet_send(of_hw_driver_t *hw_drv, int of_port, - of_packet_t *pkt, uint32_t flags); -extern int of_hw_packet_receive_register(of_hw_driver_t *hw_drv, - of_packet_in_f callback, void *cookie); - -#endif /* OF_HW_TXRX_H */ diff --git a/openflow/include/.gitignore b/openflow/include/.gitignore deleted file mode 100644 index b336cc7c..00000000 --- a/openflow/include/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/Makefile -/Makefile.in diff --git a/openflow/include/automake.mk b/openflow/include/automake.mk deleted file mode 100644 index 581c1085..00000000 --- a/openflow/include/automake.mk +++ /dev/null @@ -1 +0,0 @@ -include include/openflow/automake.mk diff --git a/openflow/include/openflow/automake.mk b/openflow/include/openflow/automake.mk deleted file mode 100644 index 3c45b082..00000000 --- a/openflow/include/openflow/automake.mk +++ /dev/null @@ -1,5 +0,0 @@ -noinst_HEADERS += \ - include/openflow/nicira-ext.h \ - include/openflow/private-ext.h \ - include/openflow/openflow.h \ - include/openflow/openflow-netlink.h diff --git a/openflow/include/openflow/nicira-ext.h b/openflow/include/openflow/nicira-ext.h deleted file mode 100644 index 727864a6..00000000 --- a/openflow/include/openflow/nicira-ext.h +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Distributed under the terms of the GNU GPL version 2. - * Copyright (c) 2008 Nicira Networks - */ - -#ifndef OPENFLOW_NICIRA_EXT_H -#define OPENFLOW_NICIRA_EXT_H 1 - -#include "openflow/openflow.h" - -#define NICIRA_OUI_STR "002320" - -/* The following vendor extensions, proposed by Nicira Networks, are not yet - * ready for standardization (and may never be), so they are not included in - * openflow.h. */ - -#define NX_VENDOR_ID 0x00002320 - -enum nicira_type { - /* Switch status request. The request body is an ASCII string that - * specifies a prefix of the key names to include in the output; if it is - * the null string, then all key-value pairs are included. */ - NXT_STATUS_REQUEST, - - /* Switch status reply. The reply body is an ASCII string of key-value - * pairs in the form "key=value\n". */ - NXT_STATUS_REPLY, - - /* Configure an action. Most actions do not require configuration - * beyond that supplied in the actual action call. */ - NXT_ACT_SET_CONFIG, - - /* Get configuration of action. */ - NXT_ACT_GET_CONFIG, - - /* Remote command execution. The request body is a sequence of strings - * delimited by null bytes. The first string is a command name. - * Subsequent strings are command arguments. */ - NXT_COMMAND_REQUEST, - - /* Remote command execution reply, sent when the command's execution - * completes. The reply body is struct nx_command_reply. */ - NXT_COMMAND_REPLY, - - /* Configure whether Flow End messages should be sent. */ - NXT_FLOW_END_CONFIG, - - /* Sent by switch when a flow ends. These messages are turned into - * ofp_flow_removed and NetFlow messages in user-space. */ - NXT_FLOW_END -}; - -struct nicira_header { - struct ofp_header header; - uint32_t vendor; /* NX_VENDOR_ID. */ - uint32_t subtype; /* One of NXT_* above. */ -}; -OFP_ASSERT(sizeof(struct nicira_header) == sizeof(struct ofp_vendor_header) + 4); - - -enum nx_snat_command { - NXSC_ADD, - NXSC_DELETE -}; - -/* Configuration for source-NATing */ -struct nx_snat_config { - uint8_t command; /* One of NXSC_*. */ - uint8_t pad[3]; - uint16_t port; /* Physical switch port. */ - uint16_t mac_timeout; /* Time to cache MAC addresses of SNAT'd hosts - in seconds. 0 uses the default value. */ - - /* Range of IP addresses to impersonate. Set both values to the - * same to support a single address. */ - uint32_t ip_addr_start; - uint32_t ip_addr_end; - - /* Range of transport ports that should be used as new source port. A - * value of zero, let's the switch choose.*/ - uint16_t tcp_start; - uint16_t tcp_end; - uint16_t udp_start; - uint16_t udp_end; - - /* MAC address to use for ARP requests for a SNAT IP address that - * comes in on a different interface than 'port'. A value of all - * zeros silently drops those ARP requests. Requests that arrive - * on 'port' get a response with the mac address of the datapath - * device. */ - uint8_t mac_addr[OFP_ETH_ALEN]; - uint8_t pad2[2]; -}; -OFP_ASSERT(sizeof(struct nx_snat_config) == 32); - -/* Action configuration. Not all actions require separate configuration. */ -struct nx_act_config { - struct nicira_header header; - uint16_t type; /* One of OFPAT_* */ - uint8_t pad[2]; - union { - struct nx_snat_config snat[0]; - }; /* Array of action configurations. The number - is inferred from the length field in the - header. */ -}; -OFP_ASSERT(sizeof(struct nx_act_config) == 20); - - -enum nx_action_subtype { - NXAST_SNAT /* Source-NAT */ -}; - -/* Action structure for NXAST_SNAT. */ -struct nx_action_snat { - uint16_t type; /* OFPAT_VENDOR. */ - uint16_t len; /* Length is 8. */ - uint32_t vendor; /* NX_VENDOR_ID. */ - uint16_t subtype; /* NXAST_SNAT. */ - uint16_t port; /* Output port--it must be previously - configured. */ - uint8_t pad[4]; -}; -OFP_ASSERT(sizeof(struct nx_action_snat) == 16); - -/* Header for Nicira-defined actions. */ -struct nx_action_header { - uint16_t type; /* OFPAT_VENDOR. */ - uint16_t len; /* Length is 8. */ - uint32_t vendor; /* NX_VENDOR_ID. */ - uint16_t subtype; /* NXAST_*. */ - uint8_t pad[6]; -}; -OFP_ASSERT(sizeof(struct nx_action_header) == 16); - -/* Status bits for NXT_COMMAND_REPLY. */ -enum { - NXT_STATUS_EXITED = 1 << 31, /* Exited normally. */ - NXT_STATUS_SIGNALED = 1 << 30, /* Exited due to signal. */ - NXT_STATUS_UNKNOWN = 1 << 29, /* Exited for unknown reason. */ - NXT_STATUS_COREDUMP = 1 << 28, /* Exited with core dump. */ - NXT_STATUS_ERROR = 1 << 27, /* Command could not be executed. */ - NXT_STATUS_STARTED = 1 << 26, /* Command was started. */ - NXT_STATUS_EXITSTATUS = 0xff, /* Exit code mask if NXT_STATUS_EXITED. */ - NXT_STATUS_TERMSIG = 0xff, /* Signal number if NXT_STATUS_SIGNALED. */ -}; - -/* NXT_COMMAND_REPLY. */ -struct nx_command_reply { - struct nicira_header nxh; - uint32_t status; /* Status bits defined above. */ - /* Followed by any number of bytes of process output. */ -}; -OFP_ASSERT(sizeof(struct nx_command_reply) == 20); - -enum nx_flow_end_reason { - NXFER_IDLE_TIMEOUT, /* Flow idle time exceeded idle_timeout. */ - NXFER_HARD_TIMEOUT, /* Time exceeded hard_timeout. */ - NXFER_DELETE, /* Flow was removed by delete command. */ - NXFER_EJECT /* Flow was ejected. */ -}; - -struct nx_flow_end_config { - struct nicira_header header; - uint8_t enable; /* Set to 1 to enable Flow End message - generation. 0 to disable. */ - uint8_t pad[3]; -}; -OFP_ASSERT(sizeof(struct nx_flow_end_config) == 20); - -struct nx_flow_end { - struct nicira_header header; - struct ofp_match match; /* Description of fields. */ - uint64_t cookie; /* Opaque controller-issued identifier. */ - - uint16_t priority; /* Priority level of flow entry. */ - uint8_t reason; /* One of NXFER_*. */ - - uint8_t tcp_flags; /* Union of seen TCP flags. */ - uint8_t ip_tos; /* IP TOS value. */ - - uint8_t send_flow_exp; /* Send flow expiry to controller. */ - - uint16_t idle_timeout; /* Idle time before discarding (seconds). */ - - uint64_t init_time; /* Time flow started in milliseconds. */ - uint64_t used_time; /* Time entry was last used in milliseconds. */ - uint64_t end_time; /* Time flow ended in milliseconds. */ - - uint64_t packet_count; - uint64_t byte_count; -}; -OFP_ASSERT(sizeof(struct nx_flow_end) == 112); - -#endif /* openflow/nicira-ext.h */ diff --git a/openflow/include/openflow/of_hw_api.h b/openflow/include/openflow/of_hw_api.h deleted file mode 100644 index 2dca1900..00000000 --- a/openflow/include/openflow/of_hw_api.h +++ /dev/null @@ -1,313 +0,0 @@ -/* Copyright (c) 2008, 2009, 2010 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#if !defined(OF_HW_API_H) -#define OF_HW_API_H - -/* - * OpenFlow hardware API definition - * - * This header file provides an abstraction of the flow table and - * port operations that can be used to build a driver for hardware - * that implements the OpenFlow protocol. - * - * Currently this driver depends (extends) the sw_table defined - * in the udatapath/table.h file. Hopefully that file will be - * moved up to library status to support kernel and userspace - * implementations. - * - */ - -#include -#include /* For sw_table */ - -/* REQUIRES: - * struct sw_table defined - * TBD: We could remove this restriction; it's mainly so that - * current chain.c operations can work. It also allows - * pointer coersion between the two types. - * - * Eventually, sw_table may be extended to include everything in - * this driver. - * - * pointer to struct datapath - */ - -/**************** basic types ****************/ - -typedef uint32_t of_port_t; -typedef struct of_hw_driver of_hw_driver_t; - -/**************** packet ****************/ - -/* The OpenFlow hardware packet abstraction */ -typedef void *os_pkt_t; /* OS representation of packet */ - -/* Requires monolithic packet data */ -typedef struct of_packet_s { - unsigned char *data; /* Pointer to packet data */ - int length; /* Length in bytes */ - os_pkt_t os_pkt; /* OS specific representation */ -} of_packet_t; - -/* Init an of_packet struct from an ofp_buffer struct */ -#define OF_PKT_INIT(pkt, ofp_buf) do { \ - (pkt)->data = (ofp_buf)->data; \ - (pkt)->length = (ofp_buf)->size; \ - (pkt)->os_pkt = (ofp_buf); \ - } while (0) - -/**************** callback protos ****************/ - -/* packet in callback function prototype */ -typedef int (*of_packet_in_f)(of_port_t port, - of_packet_t *packet, - int reason, - void *cookie); - -typedef void (*of_port_change_f)(of_port_t port, - int state, - void *cookie); - -/**************************************************************** - * - * Hardware Driver - * - ****************************************************************/ - -/* Hardware capabilities structure */ -typedef struct of_hw_driver_caps { - /* Proposed Flags: - * COUNT_PKTS_OR_BYTES Can count either pkts or bytes, not both - * INTERNAL_PRI Support internal priority mapping, and thus - * normal enqueuing action - * LOCAL_CPU_THRU_TABLE Can send packets from the CPU through - * the flow table - */ - uint32_t flags; - - /* Number of fully qualified flows supported (approx) */ - int max_flows; - uint32_t wc_supported; /* Bitmap of OFPFW_* supported wildcards */ - uint32_t actions_supported; /* Bitmap of OFPAT_* supported actions */ - uint32_t ofpc_flags; /* Bitmap of ofp_capabilities flags */ -} of_hw_driver_caps_t; - -enum of_hw_driver_flags { - OF_HW_DRV_COUNT_PKTS_OR_BYTES = 1 << 0, - OF_HW_DRV_INTERNAL_PRI = 1 << 1, - OF_HW_DRV_CPU_PKTS_THRU_TABLE = 1 << 2 -}; - -/**************** Constructor/Destructor ****************/ - -extern of_hw_driver_t *new_of_hw_driver(struct datapath *dp); -extern void delete_of_hw_driver(of_hw_driver_t *hw_drv); - -/* TBD: Add a HW/DP init function? */ - -/**************** HW DataPath Driver Structure ****************/ -/* Extends sw_table */ -struct of_hw_driver { - - /* - * Notes on sw_table inheritance: - * - * See above as well - * - * n_lookup and n_matched are not dynamically updated, but the - * call to table_stats_update should set them - */ - struct sw_table sw_table; - - /* HW datapath capabilities structure */ - of_hw_driver_caps_t caps; - - /* OPTIONAL - * init(table, flags) - * - * Initialize necessary hardware and software to run - * the switching table. Must be called prior to any other calls - * into the table (except maybe some ioctls?). - * - * Proposed flags include: - * BYTES/PACKETS: If COUNT_PKTS_OR_BYTES, which to count by default - * REATTACH: Inidicates HW was running, don't re-initialize HW - * - */ - int (*init)(of_hw_driver_t *hw_drv, uint32_t flags); - - /* - * table_stats_get(table, stats) - * port_stats_get(port, stats) - * flow_stats_get(flow_desc, stats) - * aggregate_stats_get(flow_desc, stats) - * - * Fill out the stats object(s) for this table/port/flow(s)/set of flows - * - * Returns 0 on success. - * - * For all but flow_stats, the routine fills out a pre-allocated - * stats structure. For flow stats, an array of stats is allocated - * by the called routine with *count elements. It must be freed by - * the caller. - * - * (Optional? If count is NULL for flow_stats_get, find a single - * match with exactly the given ofp_match.) - */ - int (*table_stats_get)(of_hw_driver_t *hw_drv, struct - ofp_table_stats *stats); - int (*port_stats_get)(of_hw_driver_t *hw_drv, int of_port, - struct ofp_port_stats *stats); - int (*flow_stats_get)(of_hw_driver_t *hw_drv, struct ofp_match, - struct ofp_flow_stats **stats, int *count); - int (*aggregate_stats_get)(struct ofp_match, - struct ofp_aggregate_stats_reply *stats); - - /* - * port_add/remove(table, port) - * - * The indicated port has been added to/removed from the datapath - * Add also maps the of_port number to the hw_port indicated - */ - int (*port_add)(of_hw_driver_t *hw_drv, int of_port, const char *hw_name); - int (*port_remove)(of_hw_driver_t *hw_drv, of_port_t port); - - /* - * port_link_get(table, port) - * port_enable_set(table, port, enable) - * port_enable_get(table, port) - * - * Get/set the indicated properties of a port. Only real ports - * set with port_add are supported. - */ - int (*port_link_get)(of_hw_driver_t *hw_drv, int of_port); - int (*port_enable_set)(of_hw_driver_t *hw_drv, int of_port, int enable); - int (*port_enable_get)(of_hw_driver_t *hw_drv, int of_port); - - /* - * port_queue_config(drv, port, qid, min-bw) - * port_queue_remove(drv, port, qid) - * - * Port queue control. Config will add the queue if not present - */ - int (*port_queue_config)(of_hw_driver_t *hw_drv, int of_port, - uint32_t qid, int min_bw); - int (*port_queue_remove)(of_hw_driver_t *hw_drv, int of_port, - uint32_t qid); - - /* - * port_change_register - * - * Register a callback function to receive port change notifications - * from ports in this datapath - */ - int (*port_change_register)(of_hw_driver_t *hw_drv, - of_port_change_f callback, void *cookie); - - /* - * packet_send(table, of_port, pkt, flags) - * - * Send packet to an openflow port. - * - * Proposed flags: - * APPLY_FLOW_TABLE: If set, and if the hardware supports - * it, send the packet through the flow table with the source - * port being the local CPU port. (Would be nice to have - * a flexible source port indicated; could hide in flags...) - * - * TBD: Owner of pkt and pkt->data after call; sync/async. - */ - int (*packet_send)(of_hw_driver_t *hw_drv, int of_port, of_packet_t *pkt, - uint32_t flags); - - /* - * packet_receive_register - * - * Register a callback function to receive packets from ports in - * this datapath - * - * TBD: Semantics for owning packets and return codes so indicating. - */ - int (*packet_receive_register)(of_hw_driver_t *hw_drv, - of_packet_in_f callback, void *cookie); - - /* OPTIONAL - * ioctl(table, request, io_param) - * - * Execute an ioctl on the table. A few ioctls are predefined, - * but most will be implementation specific. - * Returns 0 on success or an implementation specific other code. - * - * io_param is an input/output parameter whose value may be - * returned to the caller. - * io_len is the length of io_param in bytes. - * On input, the *io_param pointer may clobbered, so the caller must - * maintain it for deallocation if necessary. - * On output, when used -- which depends on the operation -- - * the *io_param is a pointer to a buffer allocated by the ioctl - * routine, but owned by the calling routine. - * - * Question: Should a full I/O buffer be supported? - * ioctl(table, op, in_buf, in_len, out_buf, out_len); or - * ioctl(table, op, io_buf, io_len); where buf/len set on output. - * - * Proposed operations: - * Set debug level - * Clear port/flow/table stats - * Select packet or byte counter collection - */ - int (*ioctl)(of_hw_driver_t *hw_drv, uint32_t op, void **io_param, - int *io_len); - -}; - -/**************** IOCTL values ****************/ - -enum of_hw_ioctl_e { - OF_HW_IOCTL_TABLE_DEBUG_SET = 1, - OF_HW_IOCTL_PORT_DEBUG_SET = 2, - OF_HW_IOCTL_BYTE_PKT_CNTR_SET = 3 -}; - -/* Values for OF_HW_IOCTL_BYTE_PKT_CNTR_SET */ -#define OF_HW_CNTR_PACKETS 0 -#define OF_HW_CNTR_BYTES 1 - -enum of_hw_error_e { - OF_HW_OKAY = 0, - OF_HW_ERROR = -1, - OF_HW_PORT_DOWN = -2 -}; - -#endif /* OF_HW_API_H */ diff --git a/openflow/include/openflow/openflow-ext.h b/openflow/include/openflow/openflow-ext.h deleted file mode 100644 index 581d49a5..00000000 --- a/openflow/include/openflow/openflow-ext.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2009 The Board of Trustees of The Leland - * Stanford Junior University - */ - -#ifndef OPENFLOW_OPENFLOW_EXT_H -#define OPENFLOW_OPENFLOW_EXT_H 1 - -#include "openflow/openflow.h" - -/* - * The following are vendor extensions from OpenFlow. This is a - * means of allowing the introduction of non-standardized - * proposed code. - * - * Structures in this file are 64-bit aligned in size. - */ - -#define OPENFLOW_VENDOR_ID 0x000026e1 - -enum ofp_extension_commands { /* Queue configuration commands */ - /* Queue Commands */ - OFP_EXT_QUEUE_MODIFY, /* Add and/or modify */ - OFP_EXT_QUEUE_DELETE, /* Remove a queue */ - OFP_EXT_SET_DESC, /* Set ofp_desc_stat->dp_desc */ - - OFP_EXT_COUNT -}; - -struct ofp_extension_header { - struct ofp_header header; - uint32_t vendor; /* OPENFLOW_VENDOR_ID. */ - uint32_t subtype; /* One of ofp_extension_commands */ -}; -OFP_ASSERT(sizeof(struct ofp_extension_header) == 16); - -/**************************************************************** - * - * OpenFlow Queue Configuration Operations - * - ****************************************************************/ - -struct openflow_queue_command_header { - struct ofp_extension_header header; - uint16_t port; /* Port for operations */ - uint8_t pad[6]; /* Align to 64-bits */ - uint8_t body[0]; /* Body of ofp_queue objects for op. */ -}; -OFP_ASSERT(sizeof(struct openflow_queue_command_header) == 24); - -/* NOTE - * Bug number: TBD. - * The definitions for openflow_queue_error_code conflict with - * those for ofp_queue_op_failed_code defined in openflow.h. - * This will be addressed after the release of OpenFlow 1.0. - * The error codes below for openflow_queue_error_code may be - * removed at that time. - */ -/* - * Entries for 'code' in ofp_error_msg with error 'type' - * OFPET_QUEUE_OP_FAILED - */ -enum openflow_queue_error_code { - OFQ_ERR_NONE, /* Success */ - OFQ_ERR_FAIL, /* Unspecified failure */ - OFQ_ERR_NOT_FOUND, /* Queue not found */ - OFQ_ERR_DISCIPLINE, /* Discipline not supported */ - OFQ_ERR_BW_UNAVAIL, /* Bandwidth unavailable */ - OFQ_ERR_QUEUE_UNAVAIL, /* Queue unavailable */ - OFQ_ERR_COUNT /* Last please */ -}; - -#define OPENFLOW_QUEUE_ERROR_STRINGS_DEF { \ - "Success", /* OFQ_ERR_NONE */ \ - "Unspecified failure", /* OFQ_ERR_FAIL */ \ - "Queue not found", /* OFQ_ERR_NOT_FOUND */ \ - "Discipline not supported", /* OFQ_ERR_DISCIPLINE */ \ - "Bandwidth unavailable", /* OFQ_ERR_BW_UNAVAIL */ \ - "Queue unavailable" /* OFQ_ERR_QUEUE_UNAVAIL */ \ -} - -extern char *openflow_queue_error_strings[]; - -struct openflow_ext_set_dp_desc { - struct ofp_extension_header header; - char dp_desc[DESC_STR_LEN]; -}; -OFP_ASSERT(sizeof(struct openflow_ext_set_dp_desc) == 272); - -#define ofq_error_string(rv) (((rv) < OFQ_ERR_COUNT) && ((rv) >= 0) ? \ - openflow_queue_error_strings[rv] : "Unknown error code") - -/**************************************************************** - * - * Unsupported, but potential extended queue properties - * - ****************************************************************/ - -#if 0 - -enum ofp_queue_prop_ext { - OFPQT_EXT_MAX_RATE = OFPQT_MIN + 1, /* maximum rate limit */ - OFPQT_EXT_BUF_ALLOC, /* buffer alloc config */ - OFPQT_EXT_SCHED_WEIGHT /* schedule weight config */ - OFPQT_EXT_COUNT /* Last please */ -}; - -#define OPENFLOW_QUEUE_PROP_STRINGS_DEF { \ - "No property specified" /* OFPQT_NONE */ \ - "Minimum Rate", /* OFPQT_MIN */ \ - "Maximum Rate", /* OFQ_PROP_MAX_RATE */ \ - "Buffer alloc weight", /* OFQ_PROP_BUF_ALLOC */ \ - "Scheduling weight" /* OFQ_PROP_SCHED_WEIGHT */ \ -} -extern char *openflow_queue_prop_strings[]; - -#define ofq_prop_string(val) (((val) < OFPQT_EXT_COUNT) && ((val) >= 0) ? \ - openflow_queue_prop_strings[val] : "Unknown property value") - -/* These are all the same a min-rate queue property description */ -/* Max-Rate queue property description */ -struct ofp_queue_prop_max_rate { - struct ofp_queue_prop_header prop_header; /* prop: OFPQT_MIN, len: 16 */ - uint16_t rate; /* in 1/10 of a percent of port BW */ - uint8_t pad[6]; /* 64-bit alignment */ -}; -OFP_ASSERT(sizeof(struct ofp_queue_prop_max_rate) == 16); - -/* Buffer alloc weight queue property description */ -struct ofp_queue_prop_buf_alloc { - struct ofp_queue_prop_header prop_header; /* prop: OFPQT_MIN, len: 16 */ - uint16_t alloc_val; /* 0 disabled; 1 min; 0xffff max */ - uint8_t pad[6]; /* 64-bit alignment */ -}; -OFP_ASSERT(sizeof(struct ofp_queue_prop_buf_alloc) == 16); - -/* Max-Rate queue property description */ -struct ofp_queue_prop_sched_weight { - struct ofp_queue_prop_header prop_header; /* prop: OFPQT_MIN, len: 16 */ - uint16_t weight; /* discipline specific; 0 disabled; 1 min; 0xffff max */ - uint8_t pad[6]; /* 64-bit alignment */ -}; -OFP_ASSERT(sizeof(struct ofp_queue_prop_sched_weight) == 16); - -#endif - - - -#endif /* OPENFLOW_OPENFLOW_EXT_H */ diff --git a/openflow/include/openflow/openflow-netlink.h b/openflow/include/openflow/openflow-netlink.h deleted file mode 100644 index 931e6972..00000000 --- a/openflow/include/openflow/openflow-netlink.h +++ /dev/null @@ -1,69 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#ifndef OPENFLOW_OPENFLOW_NETLINK_H -#define OPENFLOW_OPENFLOW_NETLINK_H 1 - -#define DP_GENL_FAMILY_NAME "OpenFlow" - -/* Attributes that can be attached to the datapath's netlink messages. */ -enum { - DP_GENL_A_UNSPEC, - DP_GENL_A_DP_IDX, /* Datapath device index. */ - DP_GENL_A_PORTNAME, /* Device name for datapath port. */ - DP_GENL_A_MC_GROUP, /* Generic netlink multicast group. */ - DP_GENL_A_OPENFLOW, /* OpenFlow packet. */ - DP_GENL_A_DP_NAME, /* Datapath device name. */ - - __DP_GENL_A_MAX, - DP_GENL_A_MAX = __DP_GENL_A_MAX - 1 -}; - -/* Commands that can be executed on the datapath's netlink interface. */ -enum dp_genl_command { - DP_GENL_C_UNSPEC, - DP_GENL_C_ADD_DP, /* Create datapath. */ - DP_GENL_C_DEL_DP, /* Destroy datapath. */ - DP_GENL_C_QUERY_DP, /* Get multicast group for datapath. */ - DP_GENL_C_ADD_PORT, /* Add port to datapath. */ - DP_GENL_C_DEL_PORT, /* Remove port from datapath. */ - DP_GENL_C_OPENFLOW, /* Encapsulated OpenFlow protocol. */ - - __DP_GENL_C_MAX, - DP_GENL_C_MAX = __DP_GENL_C_MAX - 1 -}; - -/* Maximum number of datapaths. */ -#define DP_MAX 256 - -#endif /* openflow/openflow-netlink.h */ diff --git a/openflow/include/openflow/openflow.h b/openflow/include/openflow/openflow.h deleted file mode 100644 index c0b5090d..00000000 --- a/openflow/include/openflow/openflow.h +++ /dev/null @@ -1,970 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -/* OpenFlow: protocol between controller and datapath. */ - -#ifndef OPENFLOW_OPENFLOW_H -#define OPENFLOW_OPENFLOW_H 1 - -#ifdef __KERNEL__ -#include -#else -#include -#endif - -#ifdef SWIG -#define OFP_ASSERT(EXPR) /* SWIG can't handle OFP_ASSERT. */ -#elif !defined(__cplusplus) -/* Build-time assertion for use in a declaration context. */ -#define OFP_ASSERT(EXPR) \ - extern int (*build_assert(void))[ sizeof(struct { \ - unsigned int build_assert_failed : (EXPR) ? 1 : -1; })] -#else /* __cplusplus */ -#define OFP_ASSERT(_EXPR) typedef int build_assert_failed[(_EXPR) ? 1 : -1] -#endif /* __cplusplus */ - -#ifndef SWIG -#define OFP_PACKED __attribute__((packed)) -#else -#define OFP_PACKED /* SWIG doesn't understand __attribute. */ -#endif - -/* Version number: - * Non-experimental versions released: 0x01 - * Experimental versions released: 0x81 -- 0x99 - */ -/* The most significant bit being set in the version field indicates an - * experimental OpenFlow version. - */ -#define OFP_VERSION 0x01 - -#define OFP_MAX_TABLE_NAME_LEN 32 -#define OFP_MAX_PORT_NAME_LEN 16 - -#define OFP_TCP_PORT 6633 -#define OFP_SSL_PORT 6633 - -#define OFP_ETH_ALEN 6 /* Bytes in an Ethernet address. */ - -/* Port numbering. Physical ports are numbered starting from 1. */ -enum ofp_port { - /* Maximum number of physical switch ports. */ - OFPP_MAX = 0xff00, - - /* Fake output "ports". */ - OFPP_IN_PORT = 0xfff8, /* Send the packet out the input port. This - virtual port must be explicitly used - in order to send back out of the input - port. */ - OFPP_TABLE = 0xfff9, /* Perform actions in flow table. - NB: This can only be the destination - port for packet-out messages. */ - OFPP_NORMAL = 0xfffa, /* Process with normal L2/L3 switching. */ - OFPP_FLOOD = 0xfffb, /* All physical ports except input port and - those disabled by STP. */ - OFPP_ALL = 0xfffc, /* All physical ports except input port. */ - OFPP_CONTROLLER = 0xfffd, /* Send to controller. */ - OFPP_LOCAL = 0xfffe, /* Local openflow "port". */ - OFPP_NONE = 0xffff /* Not associated with a physical port. */ -}; - -enum ofp_type { - /* Immutable messages. */ - OFPT_HELLO, /* Symmetric message */ - OFPT_ERROR, /* Symmetric message */ - OFPT_ECHO_REQUEST, /* Symmetric message */ - OFPT_ECHO_REPLY, /* Symmetric message */ - OFPT_VENDOR, /* Symmetric message */ - - /* Switch configuration messages. */ - OFPT_FEATURES_REQUEST, /* Controller/switch message */ - OFPT_FEATURES_REPLY, /* Controller/switch message */ - OFPT_GET_CONFIG_REQUEST, /* Controller/switch message */ - OFPT_GET_CONFIG_REPLY, /* Controller/switch message */ - OFPT_SET_CONFIG, /* Controller/switch message */ - - /* Asynchronous messages. */ - OFPT_PACKET_IN, /* Async message */ - OFPT_FLOW_REMOVED, /* Async message */ - OFPT_PORT_STATUS, /* Async message */ - - /* Controller command messages. */ - OFPT_PACKET_OUT, /* Controller/switch message */ - OFPT_FLOW_MOD, /* Controller/switch message */ - OFPT_PORT_MOD, /* Controller/switch message */ - - /* Statistics messages. */ - OFPT_STATS_REQUEST, /* Controller/switch message */ - OFPT_STATS_REPLY, /* Controller/switch message */ - - /* Barrier messages. */ - OFPT_BARRIER_REQUEST, /* Controller/switch message */ - OFPT_BARRIER_REPLY, /* Controller/switch message */ - - /* Queue Configuration messages. */ - OFPT_QUEUE_GET_CONFIG_REQUEST, /* Controller/switch message */ - OFPT_QUEUE_GET_CONFIG_REPLY /* Controller/switch message */ - -}; - -/* Header on all OpenFlow packets. */ -struct ofp_header { - uint8_t version; /* OFP_VERSION. */ - uint8_t type; /* One of the OFPT_ constants. */ - uint16_t length; /* Length including this ofp_header. */ - uint32_t xid; /* Transaction id associated with this packet. - Replies use the same id as was in the request - to facilitate pairing. */ -}; -OFP_ASSERT(sizeof(struct ofp_header) == 8); - -/* OFPT_HELLO. This message has an empty body, but implementations must - * ignore any data included in the body, to allow for future extensions. */ -struct ofp_hello { - struct ofp_header header; -}; - -#define OFP_DEFAULT_MISS_SEND_LEN 128 - -enum ofp_config_flags { - /* Handling of IP fragments. */ - OFPC_FRAG_NORMAL = 0, /* No special handling for fragments. */ - OFPC_FRAG_DROP = 1, /* Drop fragments. */ - OFPC_FRAG_REASM = 2, /* Reassemble (only if OFPC_IP_REASM set). */ - OFPC_FRAG_MASK = 3 -}; - -/* Switch configuration. */ -struct ofp_switch_config { - struct ofp_header header; - uint16_t flags; /* OFPC_* flags. */ - uint16_t miss_send_len; /* Max bytes of new flow that datapath should - send to the controller. */ -}; -OFP_ASSERT(sizeof(struct ofp_switch_config) == 12); - -/* Capabilities supported by the datapath. */ -enum ofp_capabilities { - OFPC_FLOW_STATS = 1 << 0, /* Flow statistics. */ - OFPC_TABLE_STATS = 1 << 1, /* Table statistics. */ - OFPC_PORT_STATS = 1 << 2, /* Port statistics. */ - OFPC_STP = 1 << 3, /* 802.1d spanning tree. */ - OFPC_RESERVED = 1 << 4, /* Reserved, must be zero. */ - OFPC_IP_REASM = 1 << 5, /* Can reassemble IP fragments. */ - OFPC_QUEUE_STATS = 1 << 6, /* Queue statistics. */ - OFPC_ARP_MATCH_IP = 1 << 7 /* Match IP addresses in ARP pkts. */ -}; - -/* Flags to indicate behavior of the physical port. These flags are - * used in ofp_phy_port to describe the current configuration. They are - * used in the ofp_port_mod message to configure the port's behavior. - */ -enum ofp_port_config { - OFPPC_PORT_DOWN = 1 << 0, /* Port is administratively down. */ - - OFPPC_NO_STP = 1 << 1, /* Disable 802.1D spanning tree on port. */ - OFPPC_NO_RECV = 1 << 2, /* Drop all packets except 802.1D spanning - tree packets. */ - OFPPC_NO_RECV_STP = 1 << 3, /* Drop received 802.1D STP packets. */ - OFPPC_NO_FLOOD = 1 << 4, /* Do not include this port when flooding. */ - OFPPC_NO_FWD = 1 << 5, /* Drop packets forwarded to port. */ - OFPPC_NO_PACKET_IN = 1 << 6 /* Do not send packet-in msgs for port. */ -}; - -/* Current state of the physical port. These are not configurable from - * the controller. - */ -enum ofp_port_state { - OFPPS_LINK_DOWN = 1 << 0, /* No physical link present. */ - - /* The OFPPS_STP_* bits have no effect on switch operation. The - * controller must adjust OFPPC_NO_RECV, OFPPC_NO_FWD, and - * OFPPC_NO_PACKET_IN appropriately to fully implement an 802.1D spanning - * tree. */ - OFPPS_STP_LISTEN = 0 << 8, /* Not learning or relaying frames. */ - OFPPS_STP_LEARN = 1 << 8, /* Learning but not relaying frames. */ - OFPPS_STP_FORWARD = 2 << 8, /* Learning and relaying frames. */ - OFPPS_STP_BLOCK = 3 << 8, /* Not part of spanning tree. */ - OFPPS_STP_MASK = 3 << 8 /* Bit mask for OFPPS_STP_* values. */ -}; - -/* Features of physical ports available in a datapath. */ -enum ofp_port_features { - OFPPF_10MB_HD = 1 << 0, /* 10 Mb half-duplex rate support. */ - OFPPF_10MB_FD = 1 << 1, /* 10 Mb full-duplex rate support. */ - OFPPF_100MB_HD = 1 << 2, /* 100 Mb half-duplex rate support. */ - OFPPF_100MB_FD = 1 << 3, /* 100 Mb full-duplex rate support. */ - OFPPF_1GB_HD = 1 << 4, /* 1 Gb half-duplex rate support. */ - OFPPF_1GB_FD = 1 << 5, /* 1 Gb full-duplex rate support. */ - OFPPF_10GB_FD = 1 << 6, /* 10 Gb full-duplex rate support. */ - OFPPF_COPPER = 1 << 7, /* Copper medium. */ - OFPPF_FIBER = 1 << 8, /* Fiber medium. */ - OFPPF_AUTONEG = 1 << 9, /* Auto-negotiation. */ - OFPPF_PAUSE = 1 << 10, /* Pause. */ - OFPPF_PAUSE_ASYM = 1 << 11 /* Asymmetric pause. */ -}; - -/* Description of a physical port */ -struct ofp_phy_port { - uint16_t port_no; - uint8_t hw_addr[OFP_ETH_ALEN]; - char name[OFP_MAX_PORT_NAME_LEN]; /* Null-terminated */ - - uint32_t config; /* Bitmap of OFPPC_* flags. */ - uint32_t state; /* Bitmap of OFPPS_* flags. */ - - /* Bitmaps of OFPPF_* that describe features. All bits zeroed if - * unsupported or unavailable. */ - uint32_t curr; /* Current features. */ - uint32_t advertised; /* Features being advertised by the port. */ - uint32_t supported; /* Features supported by the port. */ - uint32_t peer; /* Features advertised by peer. */ -}; -OFP_ASSERT(sizeof(struct ofp_phy_port) == 48); - -/* Switch features. */ -struct ofp_switch_features { - struct ofp_header header; - uint64_t datapath_id; /* Datapath unique ID. The lower 48-bits are for - a MAC address, while the upper 16-bits are - implementer-defined. */ - - uint32_t n_buffers; /* Max packets buffered at once. */ - - uint8_t n_tables; /* Number of tables supported by datapath. */ - uint8_t pad[3]; /* Align to 64-bits. */ - - /* Features. */ - uint32_t capabilities; /* Bitmap of support "ofp_capabilities". */ - uint32_t actions; /* Bitmap of supported "ofp_action_type"s. */ - - /* Port info.*/ - struct ofp_phy_port ports[0]; /* Port definitions. The number of ports - is inferred from the length field in - the header. */ -}; -OFP_ASSERT(sizeof(struct ofp_switch_features) == 32); - -/* What changed about the physical port */ -enum ofp_port_reason { - OFPPR_ADD, /* The port was added. */ - OFPPR_DELETE, /* The port was removed. */ - OFPPR_MODIFY /* Some attribute of the port has changed. */ -}; - -/* A physical port has changed in the datapath */ -struct ofp_port_status { - struct ofp_header header; - uint8_t reason; /* One of OFPPR_*. */ - uint8_t pad[7]; /* Align to 64-bits. */ - struct ofp_phy_port desc; -}; -OFP_ASSERT(sizeof(struct ofp_port_status) == 64); - -/* Modify behavior of the physical port */ -struct ofp_port_mod { - struct ofp_header header; - uint16_t port_no; - uint8_t hw_addr[OFP_ETH_ALEN]; /* The hardware address is not - configurable. This is used to - sanity-check the request, so it must - be the same as returned in an - ofp_phy_port struct. */ - - uint32_t config; /* Bitmap of OFPPC_* flags. */ - uint32_t mask; /* Bitmap of OFPPC_* flags to be changed. */ - - uint32_t advertise; /* Bitmap of "ofp_port_features"s. Zero all - bits to prevent any action taking place. */ - uint8_t pad[4]; /* Pad to 64-bits. */ -}; -OFP_ASSERT(sizeof(struct ofp_port_mod) == 32); - -/* Why is this packet being sent to the controller? */ -enum ofp_packet_in_reason { - OFPR_NO_MATCH, /* No matching flow. */ - OFPR_ACTION /* Action explicitly output to controller. */ -}; - -/* Packet received on port (datapath -> controller). */ -struct ofp_packet_in { - struct ofp_header header; - uint32_t buffer_id; /* ID assigned by datapath. */ - uint16_t total_len; /* Full length of frame. */ - uint16_t in_port; /* Port on which frame was received. */ - uint8_t reason; /* Reason packet is being sent (one of OFPR_*) */ - uint8_t pad; - uint8_t data[0]; /* Ethernet frame, halfway through 32-bit word, - so the IP header is 32-bit aligned. The - amount of data is inferred from the length - field in the header. Because of padding, - offsetof(struct ofp_packet_in, data) == - sizeof(struct ofp_packet_in) - 2. */ -}; -OFP_ASSERT(sizeof(struct ofp_packet_in) == 20); - -enum ofp_action_type { - OFPAT_OUTPUT, /* Output to switch port. */ - OFPAT_SET_VLAN_VID, /* Set the 802.1q VLAN id. */ - OFPAT_SET_VLAN_PCP, /* Set the 802.1q priority. */ - OFPAT_STRIP_VLAN, /* Strip the 802.1q header. */ - OFPAT_SET_DL_SRC, /* Ethernet source address. */ - OFPAT_SET_DL_DST, /* Ethernet destination address. */ - OFPAT_SET_NW_SRC, /* IP source address. */ - OFPAT_SET_NW_DST, /* IP destination address. */ - OFPAT_SET_NW_TOS, /* IP ToS (DSCP field, 6 bits). */ - OFPAT_SET_TP_SRC, /* TCP/UDP source port. */ - OFPAT_SET_TP_DST, /* TCP/UDP destination port. */ - OFPAT_ENQUEUE, /* Output to queue. */ - OFPAT_VENDOR = 0xffff -}; - -/* Action structure for OFPAT_OUTPUT, which sends packets out 'port'. - * When the 'port' is the OFPP_CONTROLLER, 'max_len' indicates the max - * number of bytes to send. A 'max_len' of zero means no bytes of the - * packet should be sent.*/ -struct ofp_action_output { - uint16_t type; /* OFPAT_OUTPUT. */ - uint16_t len; /* Length is 8. */ - uint16_t port; /* Output port. */ - uint16_t max_len; /* Max length to send to controller. */ -}; -OFP_ASSERT(sizeof(struct ofp_action_output) == 8); - -/* The VLAN id is 12 bits, so we can use the entire 16 bits to indicate - * special conditions. All ones is used to match that no VLAN id was - * set. */ -#define OFP_VLAN_NONE 0xffff - -/* Action structure for OFPAT_SET_VLAN_VID. */ -struct ofp_action_vlan_vid { - uint16_t type; /* OFPAT_SET_VLAN_VID. */ - uint16_t len; /* Length is 8. */ - uint16_t vlan_vid; /* VLAN id. */ - uint8_t pad[2]; -}; -OFP_ASSERT(sizeof(struct ofp_action_vlan_vid) == 8); - -/* Action structure for OFPAT_SET_VLAN_PCP. */ -struct ofp_action_vlan_pcp { - uint16_t type; /* OFPAT_SET_VLAN_PCP. */ - uint16_t len; /* Length is 8. */ - uint8_t vlan_pcp; /* VLAN priority. */ - uint8_t pad[3]; -}; -OFP_ASSERT(sizeof(struct ofp_action_vlan_pcp) == 8); - -/* Action structure for OFPAT_SET_DL_SRC/DST. */ -struct ofp_action_dl_addr { - uint16_t type; /* OFPAT_SET_DL_SRC/DST. */ - uint16_t len; /* Length is 16. */ - uint8_t dl_addr[OFP_ETH_ALEN]; /* Ethernet address. */ - uint8_t pad[6]; -}; -OFP_ASSERT(sizeof(struct ofp_action_dl_addr) == 16); - -/* Action structure for OFPAT_SET_NW_SRC/DST. */ -struct ofp_action_nw_addr { - uint16_t type; /* OFPAT_SET_TW_SRC/DST. */ - uint16_t len; /* Length is 8. */ - uint32_t nw_addr; /* IP address. */ -}; -OFP_ASSERT(sizeof(struct ofp_action_nw_addr) == 8); - -/* Action structure for OFPAT_SET_TP_SRC/DST. */ -struct ofp_action_tp_port { - uint16_t type; /* OFPAT_SET_TP_SRC/DST. */ - uint16_t len; /* Length is 8. */ - uint16_t tp_port; /* TCP/UDP port. */ - uint8_t pad[2]; -}; -OFP_ASSERT(sizeof(struct ofp_action_tp_port) == 8); - -/* Action structure for OFPAT_SET_NW_TOS. */ -struct ofp_action_nw_tos { - uint16_t type; /* OFPAT_SET_TW_SRC/DST. */ - uint16_t len; /* Length is 8. */ - uint8_t nw_tos; /* IP ToS (DSCP field, 6 bits). */ - uint8_t pad[3]; -}; -OFP_ASSERT(sizeof(struct ofp_action_nw_tos) == 8); - -/* Action header for OFPAT_VENDOR. The rest of the body is vendor-defined. */ -struct ofp_action_vendor_header { - uint16_t type; /* OFPAT_VENDOR. */ - uint16_t len; /* Length is a multiple of 8. */ - uint32_t vendor; /* Vendor ID, which takes the same form - as in "struct ofp_vendor_header". */ -}; -OFP_ASSERT(sizeof(struct ofp_action_vendor_header) == 8); - -/* Action header that is common to all actions. The length includes the - * header and any padding used to make the action 64-bit aligned. - * NB: The length of an action *must* always be a multiple of eight. */ -struct ofp_action_header { - uint16_t type; /* One of OFPAT_*. */ - uint16_t len; /* Length of action, including this - header. This is the length of action, - including any padding to make it - 64-bit aligned. */ - uint8_t pad[4]; -}; -OFP_ASSERT(sizeof(struct ofp_action_header) == 8); - -/* Send packet (controller -> datapath). */ -struct ofp_packet_out { - struct ofp_header header; - uint32_t buffer_id; /* ID assigned by datapath (-1 if none). */ - uint16_t in_port; /* Packet's input port (OFPP_NONE if none). */ - uint16_t actions_len; /* Size of action array in bytes. */ - struct ofp_action_header actions[0]; /* Actions. */ - /* uint8_t data[0]; */ /* Packet data. The length is inferred - from the length field in the header. - (Only meaningful if buffer_id == -1.) */ -}; -OFP_ASSERT(sizeof(struct ofp_packet_out) == 16); - -enum ofp_flow_mod_command { - OFPFC_ADD, /* New flow. */ - OFPFC_MODIFY, /* Modify all matching flows. */ - OFPFC_MODIFY_STRICT, /* Modify entry strictly matching wildcards */ - OFPFC_DELETE, /* Delete all matching flows. */ - OFPFC_DELETE_STRICT /* Strictly match wildcards and priority. */ -}; - -/* Flow wildcards. */ -enum ofp_flow_wildcards { - OFPFW_IN_PORT = 1 << 0, /* Switch input port. */ - OFPFW_DL_VLAN = 1 << 1, /* VLAN id. */ - OFPFW_DL_SRC = 1 << 2, /* Ethernet source address. */ - OFPFW_DL_DST = 1 << 3, /* Ethernet destination address. */ - OFPFW_DL_TYPE = 1 << 4, /* Ethernet frame type. */ - OFPFW_NW_PROTO = 1 << 5, /* IP protocol. */ - OFPFW_TP_SRC = 1 << 6, /* TCP/UDP source port. */ - OFPFW_TP_DST = 1 << 7, /* TCP/UDP destination port. */ - - /* IP source address wildcard bit count. 0 is exact match, 1 ignores the - * LSB, 2 ignores the 2 least-significant bits, ..., 32 and higher wildcard - * the entire field. This is the *opposite* of the usual convention where - * e.g. /24 indicates that 8 bits (not 24 bits) are wildcarded. */ - OFPFW_NW_SRC_SHIFT = 8, - OFPFW_NW_SRC_BITS = 6, - OFPFW_NW_SRC_MASK = ((1 << OFPFW_NW_SRC_BITS) - 1) << OFPFW_NW_SRC_SHIFT, - OFPFW_NW_SRC_ALL = 32 << OFPFW_NW_SRC_SHIFT, - - /* IP destination address wildcard bit count. Same format as source. */ - OFPFW_NW_DST_SHIFT = 14, - OFPFW_NW_DST_BITS = 6, - OFPFW_NW_DST_MASK = ((1 << OFPFW_NW_DST_BITS) - 1) << OFPFW_NW_DST_SHIFT, - OFPFW_NW_DST_ALL = 32 << OFPFW_NW_DST_SHIFT, - - OFPFW_DL_VLAN_PCP = 1 << 20, /* VLAN priority. */ - OFPFW_NW_TOS = 1 << 21, /* IP ToS (DSCP field, 6 bits). */ - - /* Wildcard all fields. */ - OFPFW_ALL = ((1 << 22) - 1) -}; - -/* The wildcards for ICMP type and code fields use the transport source - * and destination port fields, respectively. */ -#define OFPFW_ICMP_TYPE OFPFW_TP_SRC -#define OFPFW_ICMP_CODE OFPFW_TP_DST - -/* Values below this cutoff are 802.3 packets and the two bytes - * following MAC addresses are used as a frame length. Otherwise, the - * two bytes are used as the Ethernet type. - */ -#define OFP_DL_TYPE_ETH2_CUTOFF 0x0600 - -/* Value of dl_type to indicate that the frame does not include an - * Ethernet type. - */ -#define OFP_DL_TYPE_NOT_ETH_TYPE 0x05ff - -/* The VLAN id is 12-bits, so we can use the entire 16 bits to indicate - * special conditions. All ones indicates that no VLAN id was set. - */ -#define OFP_VLAN_NONE 0xffff - -/* Fields to match against flows */ -struct ofp_match { - uint32_t wildcards; /* Wildcard fields. */ - uint16_t in_port; /* Input switch port. */ - uint8_t dl_src[OFP_ETH_ALEN]; /* Ethernet source address. */ - uint8_t dl_dst[OFP_ETH_ALEN]; /* Ethernet destination address. */ - uint16_t dl_vlan; /* Input VLAN id. */ - uint8_t dl_vlan_pcp; /* Input VLAN priority. */ - uint8_t pad1[1]; /* Align to 64-bits */ - uint16_t dl_type; /* Ethernet frame type. */ - uint8_t nw_tos; /* IP ToS (actually DSCP field, 6 bits). */ - uint8_t nw_proto; /* IP protocol or lower 8 bits of - * ARP opcode. */ - uint8_t pad2[2]; /* Align to 64-bits */ - uint32_t nw_src; /* IP source address. */ - uint32_t nw_dst; /* IP destination address. */ - uint16_t tp_src; /* TCP/UDP source port. */ - uint16_t tp_dst; /* TCP/UDP destination port. */ -}; -OFP_ASSERT(sizeof(struct ofp_match) == 40); - -/* The match fields for ICMP type and code use the transport source and - * destination port fields, respectively. */ -#define icmp_type tp_src -#define icmp_code tp_dst - -/* Value used in "idle_timeout" and "hard_timeout" to indicate that the entry - * is permanent. */ -#define OFP_FLOW_PERMANENT 0 - -/* By default, choose a priority in the middle. */ -#define OFP_DEFAULT_PRIORITY 0x8000 - -enum ofp_flow_mod_flags { - OFPFF_SEND_FLOW_REM = 1 << 0, /* Send flow removed message when flow - * expires or is deleted. */ - OFPFF_CHECK_OVERLAP = 1 << 1, /* Check for overlapping entries first. */ - OFPFF_EMERG = 1 << 2 /* Remark this is for emergency. */ -}; - -/* Flow setup and teardown (controller -> datapath). */ -struct ofp_flow_mod { - struct ofp_header header; - struct ofp_match match; /* Fields to match */ - uint64_t cookie; /* Opaque controller-issued identifier. */ - - /* Flow actions. */ - uint16_t command; /* One of OFPFC_*. */ - uint16_t idle_timeout; /* Idle time before discarding (seconds). */ - uint16_t hard_timeout; /* Max time before discarding (seconds). */ - uint16_t priority; /* Priority level of flow entry. */ - uint32_t buffer_id; /* Buffered packet to apply to (or -1). - Not meaningful for OFPFC_DELETE*. */ - uint16_t out_port; /* For OFPFC_DELETE* commands, require - matching entries to include this as an - output port. A value of OFPP_NONE - indicates no restriction. */ - uint16_t flags; /* One of OFPFF_*. */ - struct ofp_action_header actions[0]; /* The action length is inferred - from the length field in the - header. */ -}; -OFP_ASSERT(sizeof(struct ofp_flow_mod) == 72); - -/* Why was this flow removed? */ -enum ofp_flow_removed_reason { - OFPRR_IDLE_TIMEOUT, /* Flow idle time exceeded idle_timeout. */ - OFPRR_HARD_TIMEOUT, /* Time exceeded hard_timeout. */ - OFPRR_DELETE /* Evicted by a DELETE flow mod. */ -}; - -/* Flow removed (datapath -> controller). */ -struct ofp_flow_removed { - struct ofp_header header; - struct ofp_match match; /* Description of fields. */ - uint64_t cookie; /* Opaque controller-issued identifier. */ - - uint16_t priority; /* Priority level of flow entry. */ - uint8_t reason; /* One of OFPRR_*. */ - uint8_t pad[1]; /* Align to 32-bits. */ - - uint32_t duration_sec; /* Time flow was alive in seconds. */ - uint32_t duration_nsec; /* Time flow was alive in nanoseconds beyond - duration_sec. */ - uint16_t idle_timeout; /* Idle timeout from original flow mod. */ - uint8_t pad2[2]; /* Align to 64-bits. */ - uint64_t packet_count; - uint64_t byte_count; -}; -OFP_ASSERT(sizeof(struct ofp_flow_removed) == 88); - -/* Values for 'type' in ofp_error_message. These values are immutable: they - * will not change in future versions of the protocol (although new values may - * be added). */ -enum ofp_error_type { - OFPET_HELLO_FAILED, /* Hello protocol failed. */ - OFPET_BAD_REQUEST, /* Request was not understood. */ - OFPET_BAD_ACTION, /* Error in action description. */ - OFPET_FLOW_MOD_FAILED, /* Problem modifying flow entry. */ - OFPET_PORT_MOD_FAILED, /* Port mod request failed. */ - OFPET_QUEUE_OP_FAILED /* Queue operation failed. */ -}; - -/* ofp_error_msg 'code' values for OFPET_HELLO_FAILED. 'data' contains an - * ASCII text string that may give failure details. */ -enum ofp_hello_failed_code { - OFPHFC_INCOMPATIBLE, /* No compatible version. */ - OFPHFC_EPERM /* Permissions error. */ -}; - -/* ofp_error_msg 'code' values for OFPET_BAD_REQUEST. 'data' contains at least - * the first 64 bytes of the failed request. */ -enum ofp_bad_request_code { - OFPBRC_BAD_VERSION, /* ofp_header.version not supported. */ - OFPBRC_BAD_TYPE, /* ofp_header.type not supported. */ - OFPBRC_BAD_STAT, /* ofp_stats_request.type not supported. */ - OFPBRC_BAD_VENDOR, /* Vendor not supported (in ofp_vendor_header - * or ofp_stats_request or ofp_stats_reply). */ - OFPBRC_BAD_SUBTYPE, /* Vendor subtype not supported. */ - OFPBRC_EPERM, /* Permissions error. */ - OFPBRC_BAD_LEN, /* Wrong request length for type. */ - OFPBRC_BUFFER_EMPTY, /* Specified buffer has already been used. */ - OFPBRC_BUFFER_UNKNOWN /* Specified buffer does not exist. */ -}; - -/* ofp_error_msg 'code' values for OFPET_BAD_ACTION. 'data' contains at least - * the first 64 bytes of the failed request. */ -enum ofp_bad_action_code { - OFPBAC_BAD_TYPE, /* Unknown action type. */ - OFPBAC_BAD_LEN, /* Length problem in actions. */ - OFPBAC_BAD_VENDOR, /* Unknown vendor id specified. */ - OFPBAC_BAD_VENDOR_TYPE, /* Unknown action type for vendor id. */ - OFPBAC_BAD_OUT_PORT, /* Problem validating output action. */ - OFPBAC_BAD_ARGUMENT, /* Bad action argument. */ - OFPBAC_EPERM, /* Permissions error. */ - OFPBAC_TOO_MANY, /* Can't handle this many actions. */ - OFPBAC_BAD_QUEUE /* Problem validating output queue. */ -}; - -/* ofp_error_msg 'code' values for OFPET_FLOW_MOD_FAILED. 'data' contains - * at least the first 64 bytes of the failed request. */ -enum ofp_flow_mod_failed_code { - OFPFMFC_ALL_TABLES_FULL, /* Flow not added because of full tables. */ - OFPFMFC_OVERLAP, /* Attempted to add overlapping flow with - * CHECK_OVERLAP flag set. */ - OFPFMFC_EPERM, /* Permissions error. */ - OFPFMFC_BAD_EMERG_TIMEOUT, /* Flow not added because of non-zero idle/hard - * timeout. */ - OFPFMFC_BAD_COMMAND, /* Unknown command. */ - OFPFMFC_UNSUPPORTED /* Unsupported action list - cannot process in - * the order specified. */ -}; - -/* ofp_error_msg 'code' values for OFPET_PORT_MOD_FAILED. 'data' contains - * at least the first 64 bytes of the failed request. */ -enum ofp_port_mod_failed_code { - OFPPMFC_BAD_PORT, /* Specified port does not exist. */ - OFPPMFC_BAD_HW_ADDR, /* Specified hardware address is wrong. */ -}; - -/* ofp_error msg 'code' values for OFPET_QUEUE_OP_FAILED. 'data' contains - * at least the first 64 bytes of the failed request */ -enum ofp_queue_op_failed_code { - OFPQOFC_BAD_PORT, /* Invalid port (or port does not exist). */ - OFPQOFC_BAD_QUEUE, /* Queue does not exist. */ - OFPQOFC_EPERM /* Permissions error. */ -}; - -/* OFPT_ERROR: Error message (datapath -> controller). */ -struct ofp_error_msg { - struct ofp_header header; - - uint16_t type; - uint16_t code; - uint8_t data[0]; /* Variable-length data. Interpreted based - on the type and code. */ -}; -OFP_ASSERT(sizeof(struct ofp_error_msg) == 12); - -enum ofp_stats_types { - /* Description of this OpenFlow switch. - * The request body is empty. - * The reply body is struct ofp_desc_stats. */ - OFPST_DESC, - - /* Individual flow statistics. - * The request body is struct ofp_flow_stats_request. - * The reply body is an array of struct ofp_flow_stats. */ - OFPST_FLOW, - - /* Aggregate flow statistics. - * The request body is struct ofp_aggregate_stats_request. - * The reply body is struct ofp_aggregate_stats_reply. */ - OFPST_AGGREGATE, - - /* Flow table statistics. - * The request body is empty. - * The reply body is an array of struct ofp_table_stats. */ - OFPST_TABLE, - - /* Physical port statistics. - * The request body is struct ofp_port_stats_request. - * The reply body is an array of struct ofp_port_stats. */ - OFPST_PORT, - - /* Queue statistics for a port - * The request body defines the port - * The reply body is an array of struct ofp_queue_stats */ - OFPST_QUEUE, - - /* Vendor extension. - * The request and reply bodies begin with a 32-bit vendor ID, which takes - * the same form as in "struct ofp_vendor_header". The request and reply - * bodies are otherwise vendor-defined. */ - OFPST_VENDOR = 0xffff -}; - -struct ofp_stats_request { - struct ofp_header header; - uint16_t type; /* One of the OFPST_* constants. */ - uint16_t flags; /* OFPSF_REQ_* flags (none yet defined). */ - uint8_t body[0]; /* Body of the request. */ -}; -OFP_ASSERT(sizeof(struct ofp_stats_request) == 12); - -enum ofp_stats_reply_flags { - OFPSF_REPLY_MORE = 1 << 0 /* More replies to follow. */ -}; - -struct ofp_stats_reply { - struct ofp_header header; - uint16_t type; /* One of the OFPST_* constants. */ - uint16_t flags; /* OFPSF_REPLY_* flags. */ - uint8_t body[0]; /* Body of the reply. */ -}; -OFP_ASSERT(sizeof(struct ofp_stats_reply) == 12); - -#define DESC_STR_LEN 256 -#define SERIAL_NUM_LEN 32 -/* Body of reply to OFPST_DESC request. Each entry is a NULL-terminated - * ASCII string. */ -struct ofp_desc_stats { - char mfr_desc[DESC_STR_LEN]; /* Manufacturer description. */ - char hw_desc[DESC_STR_LEN]; /* Hardware description. */ - char sw_desc[DESC_STR_LEN]; /* Software description. */ - char serial_num[SERIAL_NUM_LEN]; /* Serial number. */ - char dp_desc[DESC_STR_LEN]; /* Human readable description of datapath. */ -}; -OFP_ASSERT(sizeof(struct ofp_desc_stats) == 1056); - -/* Body for ofp_stats_request of type OFPST_FLOW. */ -struct ofp_flow_stats_request { - struct ofp_match match; /* Fields to match. */ - uint8_t table_id; /* ID of table to read (from ofp_table_stats), - 0xff for all tables or 0xfe for emergency. */ - uint8_t pad; /* Align to 32 bits. */ - uint16_t out_port; /* Require matching entries to include this - as an output port. A value of OFPP_NONE - indicates no restriction. */ -}; -OFP_ASSERT(sizeof(struct ofp_flow_stats_request) == 44); - -/* Body of reply to OFPST_FLOW request. */ -struct ofp_flow_stats { - uint16_t length; /* Length of this entry. */ - uint8_t table_id; /* ID of table flow came from. */ - uint8_t pad; - struct ofp_match match; /* Description of fields. */ - uint32_t duration_sec; /* Time flow has been alive in seconds. */ - uint32_t duration_nsec; /* Time flow has been alive in nanoseconds beyond - duration_sec. */ - uint16_t priority; /* Priority of the entry. Only meaningful - when this is not an exact-match entry. */ - uint16_t idle_timeout; /* Number of seconds idle before expiration. */ - uint16_t hard_timeout; /* Number of seconds before expiration. */ - uint8_t pad2[6]; /* Align to 64-bits. */ - uint64_t cookie; /* Opaque controller-issued identifier. */ - uint64_t packet_count; /* Number of packets in flow. */ - uint64_t byte_count; /* Number of bytes in flow. */ - struct ofp_action_header actions[0]; /* Actions. */ -}; -OFP_ASSERT(sizeof(struct ofp_flow_stats) == 88); - -/* Body for ofp_stats_request of type OFPST_AGGREGATE. */ -struct ofp_aggregate_stats_request { - struct ofp_match match; /* Fields to match. */ - uint8_t table_id; /* ID of table to read (from ofp_table_stats) - 0xff for all tables or 0xfe for emergency. */ - uint8_t pad; /* Align to 32 bits. */ - uint16_t out_port; /* Require matching entries to include this - as an output port. A value of OFPP_NONE - indicates no restriction. */ -}; -OFP_ASSERT(sizeof(struct ofp_aggregate_stats_request) == 44); - -/* Body of reply to OFPST_AGGREGATE request. */ -struct ofp_aggregate_stats_reply { - uint64_t packet_count; /* Number of packets in flows. */ - uint64_t byte_count; /* Number of bytes in flows. */ - uint32_t flow_count; /* Number of flows. */ - uint8_t pad[4]; /* Align to 64 bits. */ -}; -OFP_ASSERT(sizeof(struct ofp_aggregate_stats_reply) == 24); - -/* Body of reply to OFPST_TABLE request. */ -struct ofp_table_stats { - uint8_t table_id; /* Identifier of table. Lower numbered tables - are consulted first. */ - uint8_t pad[3]; /* Align to 32-bits. */ - char name[OFP_MAX_TABLE_NAME_LEN]; - uint32_t wildcards; /* Bitmap of OFPFW_* wildcards that are - supported by the table. */ - uint32_t max_entries; /* Max number of entries supported. */ - uint32_t active_count; /* Number of active entries. */ - uint64_t lookup_count; /* Number of packets looked up in table. */ - uint64_t matched_count; /* Number of packets that hit table. */ -}; -OFP_ASSERT(sizeof(struct ofp_table_stats) == 64); - -/* Body for ofp_stats_request of type OFPST_PORT. */ -struct ofp_port_stats_request { - uint16_t port_no; /* OFPST_PORT message must request statistics - * either for a single port (specified in - * port_no) or for all ports (if port_no == - * OFPP_NONE). */ - uint8_t pad[6]; -}; -OFP_ASSERT(sizeof(struct ofp_port_stats_request) == 8); - -/* Body of reply to OFPST_PORT request. If a counter is unsupported, set - * the field to all ones. */ -struct ofp_port_stats { - uint16_t port_no; - uint8_t pad[6]; /* Align to 64-bits. */ - uint64_t rx_packets; /* Number of received packets. */ - uint64_t tx_packets; /* Number of transmitted packets. */ - uint64_t rx_bytes; /* Number of received bytes. */ - uint64_t tx_bytes; /* Number of transmitted bytes. */ - uint64_t rx_dropped; /* Number of packets dropped by RX. */ - uint64_t tx_dropped; /* Number of packets dropped by TX. */ - uint64_t rx_errors; /* Number of receive errors. This is a super-set - of more specific receive errors and should be - greater than or equal to the sum of all - rx_*_err values. */ - uint64_t tx_errors; /* Number of transmit errors. This is a super-set - of more specific transmit errors and should be - greater than or equal to the sum of all - tx_*_err values (none currently defined.) */ - uint64_t rx_frame_err; /* Number of frame alignment errors. */ - uint64_t rx_over_err; /* Number of packets with RX overrun. */ - uint64_t rx_crc_err; /* Number of CRC errors. */ - uint64_t collisions; /* Number of collisions. */ -}; -OFP_ASSERT(sizeof(struct ofp_port_stats) == 104); - -/* Vendor extension. */ -struct ofp_vendor_header { - struct ofp_header header; /* Type OFPT_VENDOR. */ - uint32_t vendor; /* Vendor ID: - * - MSB 0: low-order bytes are IEEE OUI. - * - MSB != 0: defined by OpenFlow - * consortium. */ - /* Vendor-defined arbitrary additional data. */ -}; -OFP_ASSERT(sizeof(struct ofp_vendor_header) == 12); - -/* All ones is used to indicate all queues in a port (for stats retrieval). */ -#define OFPQ_ALL 0xffffffff - -/* Min rate > 1000 means not configured. */ -#define OFPQ_MIN_RATE_UNCFG 0xffff - -enum ofp_queue_properties { - OFPQT_NONE = 0, /* No property defined for queue (default). */ - OFPQT_MIN_RATE, /* Minimum datarate guaranteed. */ - /* Other types should be added here - * (i.e. max rate, precedence, etc). */ -}; - -/* Common description for a queue. */ -struct ofp_queue_prop_header { - uint16_t property; /* One of OFPQT_. */ - uint16_t len; /* Length of property, including this header. */ - uint8_t pad[4]; /* 64-bit alignemnt. */ -}; -OFP_ASSERT(sizeof(struct ofp_queue_prop_header) == 8); - -/* Min-Rate queue property description. */ -struct ofp_queue_prop_min_rate { - struct ofp_queue_prop_header prop_header; /* prop: OFPQT_MIN, len: 16. */ - uint16_t rate; /* In 1/10 of a percent; >1000 -> disabled. */ - uint8_t pad[6]; /* 64-bit alignment */ -}; -OFP_ASSERT(sizeof(struct ofp_queue_prop_min_rate) == 16); - -/* Full description for a queue. */ -struct ofp_packet_queue { - uint32_t queue_id; /* id for the specific queue. */ - uint16_t len; /* Length in bytes of this queue desc. */ - uint8_t pad[2]; /* 64-bit alignment. */ - struct ofp_queue_prop_header properties[0]; /* List of properties. */ -}; -OFP_ASSERT(sizeof(struct ofp_packet_queue) == 8); - -/* Query for port queue configuration. */ -struct ofp_queue_get_config_request { - struct ofp_header header; - uint16_t port; /* Port to be queried. Should refer - to a valid physical port (i.e. < OFPP_MAX) */ - uint8_t pad[2]; /* 32-bit alignment. */ -}; -OFP_ASSERT(sizeof(struct ofp_queue_get_config_request) == 12); - -/* Queue configuration for a given port. */ -struct ofp_queue_get_config_reply { - struct ofp_header header; - uint16_t port; - uint8_t pad[6]; - struct ofp_packet_queue queues[0]; /* List of configured queues. */ -}; -OFP_ASSERT(sizeof(struct ofp_queue_get_config_reply) == 16); - -/* OFPAT_ENQUEUE action struct: send packets to given queue on port. */ -struct ofp_action_enqueue { - uint16_t type; /* OFPAT_ENQUEUE. */ - uint16_t len; /* Len is 16. */ - uint16_t port; /* Port that queue belongs. Should - refer to a valid physical port - (i.e. < OFPP_MAX) or OFPP_IN_PORT. */ - uint8_t pad[6]; /* Pad for 64-bit alignment. */ - uint32_t queue_id; /* Where to enqueue the packets. */ -}; -OFP_ASSERT(sizeof(struct ofp_action_enqueue) == 16); - -struct ofp_queue_stats_request { - uint16_t port_no; /* All ports if OFPT_ALL. */ - uint8_t pad[2]; /* Align to 32-bits. */ - uint32_t queue_id; /* All queues if OFPQ_ALL. */ -}; -OFP_ASSERT(sizeof(struct ofp_queue_stats_request) == 8); - -struct ofp_queue_stats { - uint16_t port_no; - uint8_t pad[2]; /* Align to 32-bits. */ - uint32_t queue_id; /* Queue i.d */ - uint64_t tx_bytes; /* Number of transmitted bytes. */ - uint64_t tx_packets; /* Number of transmitted packets. */ - uint64_t tx_errors; /* Number of packets dropped due to overrun. */ -}; -OFP_ASSERT(sizeof(struct ofp_queue_stats) == 32); - -#endif /* openflow/openflow.h */ diff --git a/openflow/include/openflow/private-ext.h b/openflow/include/openflow/private-ext.h deleted file mode 100644 index 61fc8fb0..00000000 --- a/openflow/include/openflow/private-ext.h +++ /dev/null @@ -1,68 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#ifndef OPENFLOW_PRIVATE_EXT_H_ -#define OPENFLOW_PRIVATE_EXT_H_ - -#ifdef __KERNEL__ -#include -#endif - -#include "openflow/openflow.h" - -/* - * The following PRIVATE vendor extensions are just sample and may never be - * ready for standardization, so they are not included in openflow.h. - * - * As a sample, we use private OUI (AC-DE-48) for PRIVATE vendor ID. - */ - -#define PRIVATE_VENDOR_ID 0x00acde48 -#define PRIVATEOPT_PROTOCOL_STATS_REQUEST 0x0001 -#define PRIVATEOPT_PROTOCOL_STATS_REPLY 0x0002 -#define PRIVATEOPT_EMERG_FLOW_PROTECTION 0x0003 -#define PRIVATEOPT_EMERG_FLOW_RESTORATION 0x0004 - -struct private_vxhdr { - struct ofp_header ofp_hdr; /* protocol header */ - uint32_t ofp_vxid; /* vendor extenion ID */ -} __attribute__ ((__packed__)); - -/* TLV encoding */ -struct private_vxopt { - uint16_t pvo_type; /* type of vendor extension option */ - uint16_t pvo_len; /* length of value (octet) */ - /* followed by value */ - /* uint8_t pvo_value[0]; */ -} __attribute__ ((__packed__)); - -#endif diff --git a/openflow/m4/libopenflow.m4 b/openflow/m4/libopenflow.m4 deleted file mode 100644 index 58014ed5..00000000 --- a/openflow/m4/libopenflow.m4 +++ /dev/null @@ -1,168 +0,0 @@ -# -*- autoconf -*- - -# Copyright (c) 2008 The Board of Trustees of The Leland Stanford -# Junior University -# -# We are making the OpenFlow specification and associated documentation -# (Software) available for public use and benefit with the expectation -# that others will use, modify and enhance the Software and contribute -# those enhancements back to the community. However, since we would -# like to make the Software available for broadest use, with as few -# restrictions as possible permission is hereby granted, free of -# charge, to any person obtaining a copy of this Software to deal in -# the Software under the copyrights without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# -# The name and trademarks of copyright holder(s) may NOT be used in -# advertising or publicity pertaining to the Software or any -# derivatives without specific, written prior permission. - -dnl Checks for --enable-ndebug and defines NDEBUG if it is specified. -AC_DEFUN([OFP_CHECK_NDEBUG], - [AC_ARG_ENABLE( - [ndebug], - [AC_HELP_STRING([--enable-ndebug], - [Disable debugging features for max performance])], - [case "${enableval}" in - (yes) ndebug=true ;; - (no) ndebug=false ;; - (*) AC_MSG_ERROR([bad value ${enableval} for --enable-ndebug]) ;; - esac], - [ndebug=false]) - AM_CONDITIONAL([NDEBUG], [test x$ndebug = xtrue])]) - -dnl Checks for Netlink support. -AC_DEFUN([OFP_CHECK_NETLINK], - [AC_CHECK_HEADER([linux/netlink.h], - [HAVE_NETLINK=yes], - [HAVE_NETLINK=no], - [#include - #include - ]) - AM_CONDITIONAL([HAVE_NETLINK], [test "$HAVE_NETLINK" = yes]) - if test "$HAVE_NETLINK" = yes; then - AC_DEFINE([HAVE_NETLINK], [1], - [Define to 1 if Netlink protocol is available.]) - fi]) - -dnl Checks for OpenSSL, if --enable-ssl is passed in. -AC_DEFUN([OFP_CHECK_OPENSSL], - [AC_ARG_ENABLE( - [ssl], - [AC_HELP_STRING([--enable-ssl], - [Enable ssl support (requires libssl)])], - [case "${enableval}" in - (yes) ssl=true ;; - (no) ssl=false ;; - (*) AC_MSG_ERROR([bad value ${enableval} for --enable-ssl]) ;; - esac], - [ssl=false]) - - if test "$ssl" = true; then - dnl Make sure that pkg-config is installed. - m4_pattern_forbid([PKG_CHECK_MODULES]) - PKG_CHECK_MODULES([SSL], [libssl], - [HAVE_OPENSSL=yes], - [HAVE_OPENSSL=no - AC_MSG_WARN([Cannot find libssl: - - $SSL_PKG_ERRORS - - OpenFlow will not support SSL connections.])]) - - fi - AM_CONDITIONAL([HAVE_OPENSSL], [test "$HAVE_OPENSSL" = yes]) - if test "$HAVE_OPENSSL" = yes; then - AC_DEFINE([HAVE_OPENSSL], [1], [Define to 1 if OpenSSL is installed.]) - fi]) - -dnl Checks for libraries needed by lib/fault.c. -AC_DEFUN([OFP_CHECK_FAULT_LIBS], - [AC_CHECK_LIB([dl], [dladdr], [FAULT_LIBS=-ldl]) - AC_SUBST([FAULT_LIBS])]) - -dnl Checks for libraries needed by lib/socket-util.c. -AC_DEFUN([OFP_CHECK_SOCKET_LIBS], - [AC_CHECK_LIB([socket], [connect]) - AC_SEARCH_LIBS([gethostbyname], [resolv], [RESOLVER_LIBS=-lresolv])]) - -dnl Checks for the directory in which to store the PKI. -AC_DEFUN([OFP_CHECK_PKIDIR], - [AC_ARG_WITH( - [pkidir], - AC_HELP_STRING([--with-pkidir=DIR], - [PKI hierarchy directory [[DATADIR/openflow/pki]]]), - [PKIDIR=$withval], - [PKIDIR='${pkgdatadir}/pki']) - AC_SUBST([PKIDIR])]) - -dnl Checks for the directory in which to store pidfiles. -AC_DEFUN([OFP_CHECK_RUNDIR], - [AC_ARG_WITH( - [rundir], - AC_HELP_STRING([--with-rundir=DIR], - [directory used for pidfiles [[LOCALSTATEDIR/run]]]), - [RUNDIR=$withval], - [RUNDIR='${localstatedir}/run']) - AC_SUBST([RUNDIR])]) - -dnl Checks for the directory in which to store logs. -AC_DEFUN([OFP_CHECK_LOGDIR], - [AC_ARG_WITH( - [logdir], - AC_HELP_STRING([--with-logdir=DIR], - [directory used for logs [[LOCALSTATEDIR/log/PACKAGE]]]), - [LOGDIR=$withval], - [LOGDIR='${localstatedir}/log/${PACKAGE}']) - AC_SUBST([LOGDIR])]) - -dnl Checks for __malloc_hook, etc., supported by glibc. -AC_DEFUN([OFP_CHECK_MALLOC_HOOKS], - [AC_CACHE_CHECK( - [whether libc supports hooks for malloc and related functions], - [ofp_cv_malloc_hooks], - [AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM( - [#include - ], - [(void) __malloc_hook; - (void) __realloc_hook; - (void) __free_hook;])], - [ofp_cv_malloc_hooks=yes], - [ofp_cv_malloc_hooks=no])]) - if test $ofp_cv_malloc_hooks = yes; then - AC_DEFINE([HAVE_MALLOC_HOOKS], [1], - [Define to 1 if you have __malloc_hook, __realloc_hook, and - __free_hook in .]) - fi]) - -dnl Runs the checks required to include the headers in include/ and -dnl link against lib/libopenflow.a. -AC_DEFUN([OFP_CHECK_LIBOPENFLOW], - [AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS]) - AC_REQUIRE([OFP_CHECK_NDEBUG]) - AC_REQUIRE([OFP_CHECK_NETLINK]) - AC_REQUIRE([OFP_CHECK_OPENSSL]) - AC_REQUIRE([OFP_CHECK_FAULT_LIBS]) - AC_REQUIRE([OFP_CHECK_SOCKET_LIBS]) - AC_REQUIRE([OFP_CHECK_PKIDIR]) - AC_REQUIRE([OFP_CHECK_RUNDIR]) - AC_REQUIRE([OFP_CHECK_LOGDIR]) - AC_REQUIRE([OFP_CHECK_MALLOC_HOOKS]) - AC_CHECK_FUNCS([strlcpy])]) - diff --git a/openflow/m4/nx-build.m4 b/openflow/m4/nx-build.m4 deleted file mode 100644 index d681cecc..00000000 --- a/openflow/m4/nx-build.m4 +++ /dev/null @@ -1,71 +0,0 @@ -# -*- autoconf -*- - -# Copyright (c) 2008 The Board of Trustees of The Leland Stanford -# Junior University -# -# We are making the OpenFlow specification and associated documentation -# (Software) available for public use and benefit with the expectation -# that others will use, modify and enhance the Software and contribute -# those enhancements back to the community. However, since we would -# like to make the Software available for broadest use, with as few -# restrictions as possible permission is hereby granted, free of -# charge, to any person obtaining a copy of this Software to deal in -# the Software under the copyrights without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# -# The name and trademarks of copyright holder(s) may NOT be used in -# advertising or publicity pertaining to the Software or any -# derivatives without specific, written prior permission. - -dnl NX_BUILDNR -dnl -dnl If --with-build-number=NUMBER is used, substitutes a Makefile -dnl variable BUILDNR with NUMBER, and sets a C preprocessor variable -dnl BUILDNR to "+buildNUMBER". -dnl -dnl Otherwise, if --with-build-number is not used, substitutes BUILDNR -dnl with 0 and sets C preprocessor variable BUILDNR to "". -AC_DEFUN([NX_BUILDNR], - [AC_ARG_WITH( - [build-number], - [AS_HELP_STRING([--with-build-number=NUMBER], - [Official build number (default is none)])]) - AC_MSG_CHECKING([build number]) - case $with_build_number in # ( - [[0-9]] | \ - [[0-9]][[0-9]] | \ - [[0-9]][[0-9]][[0-9]] | \ - [[0-9]][[0-9]][[0-9]][[0-9]] | \ - [[0-9]][[0-9]][[0-9]][[0-9]][[0-9]]) - BUILDNR=$with_build_number - buildnr='"+build'$BUILDNR'"' - AC_MSG_RESULT([$with_build_number]) - ;; # ( - ''|no) - BUILDNR=0 - buildnr='""' - AC_MSG_RESULT([none]) - ;; # ( - *) - AC_MSG_ERROR([invalid build number $with_build_number]) - ;; - esac - AC_SUBST([BUILDNR]) - AC_DEFINE_UNQUOTED([BUILDNR], [$buildnr], - [Official build number as a VERSION suffix string, e.g. "+build123", - or "" if this is not an official build.])]) diff --git a/openflow/regress/CREDITS b/openflow/regress/CREDITS deleted file mode 100644 index 987380af..00000000 --- a/openflow/regress/CREDITS +++ /dev/null @@ -1,22 +0,0 @@ -Credit goes to those who contributed code to the regression suite. Unless -otherwise noted, the contributors are at Stanford University. - - -Test writers/editors: - Clay Collier - David Erickson - Mikio Hara (NEC) - Brandon Heller - Peyman Kazemian - Masayoshi Kobayashi (NEC) - Bob Lantz - Brandon Nefcy - Rob Sherwood (Deutsche Telekom R&D Labs) - Jean Tourrilhes (HP Labs) - Tatsuya Yabe (NEC) - Yiannis Yiakoumis - -Supporting libraries: - Adam Covington - Glen Gibb - Jad Naous diff --git a/openflow/regress/INSTALL b/openflow/regress/INSTALL deleted file mode 100644 index 4ddad72f..00000000 --- a/openflow/regress/INSTALL +++ /dev/null @@ -1,264 +0,0 @@ - Installation Instructions for OpenFlow Reference Tests - -This document describes how to install and execute the OpenFlow reference test -suite, which provides an automated way to verify that an OpenFlow switch -adheres to the OpenFlow Protocol. Out of the box, tests work with the OpenFlow -Reference Linux Switch, but can support other platforms by defining custom -setup and teardown scripts. Additional tests verify the reference learning -Ethernet switch controller included with the OpenFlow Reference Linux Switch. - -Please send any comments to: - - - -=== Prerequisites === - -The tests require no other packets to be sent on the testing interfaces. -Built-in programs like avahi-daemon and/or network-manager may send packets, -causing the tests to report failure. The simplest way to remove these packets -is to disable the ipv6 module and reboot, as well as remove avahi-daemon. - -All test configurations require the following Perl modules: - perl-Convert-Binary-C - perl-Data-HexDump - perl-Net-Pcap (perl-Net-Pcap-0.16-1) - perl-Net-RawIP.i386 (perl-Net-RawIP-0.23-1) - perl-Error.noarch (perl-Error-0.17012-1) - -These packages can be installed from source via www.cpan.org, or you can use -pre-built packages (much faster!). - -The code has been tested on CentOS 5.1/5.2, Ubuntu Hardy Heron, and Debian -Unstable under the following configurations. - -** Config 1 - Four virtual Ethernet loopback pairs - -To set these up, you must have a kernel version >= 2.6.24 and the veth kernel -module compiled. - -To set up link pairs, you must also have iproute installed. - -Scripts to simplify this are included in bin/: --bin/veth_setup.pl --bin/veth_teardown.pl - -Before running any veth tests, make sure to run bin/veth_setup.pl, which will -create interfaces veth{0..7}. The usual ports of eth{1..8} are remapped to these -ports via the file veth.map in /bin/. To remove these interfaces, run -bin/veth_teardown.pl - -** Config 2 - Two quad-port Ethernet NICs connected by physical loopback cables - -Assign ports as eth{1..8} and connect cables as: - eth1 to eth5 - eth2 to eth6 - eth3 to eth7 - eth4 to eth8 - -** Config 3 - Four local ethernet ports connected to external switch - -A third configuration is to use four ports of Ethernet on the test machine, -connected to an external switch. To do this, you must provide custom setup -and teardown scripts that enable/disable OpenFlow on the external switch via -SSH, telnet, or SNMP. See the scripts in bin/ for examples of how to create -these. - -** Config 4 - One quad-port Ethernet NIC connected to a NetFPGA - -This testing configuration is used to verify the NetFPGA's OpenFlow -functionality. It requires 4 ports of Ethernet connected to corresponding ports -on the NetFPGA in the following arrangement: - eth1 to nf2c0 - eth2 to nf2c1 - eth3 to nf2c2 - eth4 to nf2c3 - -This test also assumes that you have correctly installed the NetFPGA ahead of -time. For further information about the NetFPGA please see -http://www.netfpga.org/ - -Of particular note, by default installing the NetFPGA also puts the -NF2/lib/Perl5 directory into your PERL5LIB environment variable, this must be -removed else the tests will fail. Ensure that your PERL5LIB only contains the -path set by the env_vars file that will be discussed later in this document. - - -=== Ubuntu Quickstart === - -Follow these instructions to quickly create a VM or physical machine with -OpenFlow that runs the tests. - -Ubuntu is recommended because it is based on Debian sources and has a recent -kernel version - which removes the need for some steps. - -If installing as a VM, you'll need to install VMWare Server (Windows/Linux, -free) or VMWare Fusion (Mac, $$$). - -Download the Ubuntu 8.04 Desktop or Server ISO, and install Ubuntu. - -If you prefer, install VMWare Tools to enable better mouse and display support. -Alternately, install SSH and use it for the rest of the instructions: - sudo apt-get install ssh -Install GCC, which is required for OpenFlow: - sudo apt-get install gcc -Download and untar OpenFlow v0.8.1 - wget http://openflowswitch.org/downloads/openflow-v0.8.1.tar.gz - tar xzf openflow-v0.8.1.tar.gz -Build OpenFlow user-space and kernel-space switches: - cd openflow-v0.8.1 - ./configure --with-l26=/lib/modules/`uname -r` - make - sudo make install -Now, download and untar the OpenFlow Test Suite: - wget http://openflowswitch.org/downloads/openflow-test-v0.8.1-r2.tar.gz -Install required packages for the test suite: - sudo apt-get install liberror-perl libio-interface-perl liblist-moreutils-perl libpcap0.8-dev -Download the following: - wget http://search.cpan.org/CPAN/authors/id/S/SA/SAPER/Net-Pcap-0.14.tar.gz - wget http://search.cpan.org/CPAN/authors/id/S/SZ/SZABGAB/Net-RawIP-0.21.tar.gz - wget http://search.cpan.org/CPAN/authors/id/M/MH/MHX/Convert-Binary-C-0.71.tar.gz - wget http://search.cpan.org/CPAN/authors/id/F/FT/FTASSIN/Data-HexDump-0.02.tar.gz -For each package: - tar xzf - cd - perl Makefile.PL - make - make install -Remove avahi-daemon, which often causes tests to fail by sending out messages: - sudo apt-get remove avahi-daemon -Create a root password, to be used later: - sudo passwd root - -From here, skip to the Running The Tests section below. - - -=== CentOS 5.2 === - -First, download and verify you can build the current version of OpenFlow. - -Install the RPMForge repository: - wget http://dag.wieers.com/rpm/packages/rpmforge-release/rpmforge-release-0.3.6-1.el5.rf.i386.rpm - rpm -Uhv rpmforge-release-0.3.6-1.el5.rf.i386.rpm - -Install Perl packages: - yum -y install perl-Convert-Binary-C perl-Data-HexDump perl-Net-Pcap perl-Net-RawIP.i386 perl-Error.noarch - -To run tests with Veth pairs, you'll need to upgrade to a newer version of the kernel. - -Install iproute: - yum -y install iproute - -From here, skip to the Running The Tests section below. - -=== Debian Install === - -These instructions derive from http://netfpga.org/netfpgawiki/index.php/Ubuntu_Compatibility - -Some instructions may no longer be necessary. - -*The version of libnet-pcap-perl that Debian and Ubuntu 6.06/7.04/7.10 provides is ANCIENT (version 0.04). The latest stable version is 0.14. No newer version is available as a package, so we must build it ourselves. -*The version of libpcap that Debian and Ubuntu 7.04 provides by default is old (version 0.72). The latest stable version is 0.9.8. Fortunately, the package manager has a newer version called "libpcap0.8" that is really version 0.9.5 -*Remove old packages / install new ones - -May not be necessary: - apt-get remove libpcap0.7 libpcap0.7-dev libpcap-dev libnet-pcap-perl - -Will be necessary: - apt-get install liberror-perl libio-interface-perl liblist-moreutils-perl libpcap0.8 libpcap0.8-dev psmisc -Listed individually: - apt-get install liberror-perl - apt-get install libio-interface-perl (Used to manually build a newer version of Net::PCap) - apt-get install liblist-moreutils-perl (Used to manually build a newer version of Net::RawIP) - apt-get install libpcap0.8 - apt-get install libpcap0.8-dev - apt-get install psmisc (Used to get killall) - -Required packages have Debian versions at packages.debian.org, however these packages may not be the newest, or not exist at all. libnet-rawip-perl and libnet-pacp-perl may work, but have not been tested. We'll manually install these two packages: -http://search.cpan.org/~saper/Net-Pcap-0.14/Pcap.pm -http://search.cpan.org/~szabgab/Net-RawIP-0.21/lib/Net/RawIP.pm -http://search.cpan.org/dist/Convert-Binary-C/lib/Convert/Binary/C.pm -http://search.cpan.org/dist/Data-HexDump/lib/Data/HexDump.pm - -Download the following: - wget http://search.cpan.org/CPAN/authors/id/S/SA/SAPER/Net-Pcap-0.14.tar.gz - wget http://search.cpan.org/CPAN/authors/id/S/SZ/SZABGAB/Net-RawIP-0.21.tar.gz - wget http://search.cpan.org/CPAN/authors/id/M/MH/MHX/Convert-Binary-C-0.71.tar.gz - wget http://search.cpan.org/CPAN/authors/id/F/FT/FTASSIN/Data-HexDump-0.02.tar.gz -For each package: - tar xzf - cd - perl Makefile.PL - make - make install - -Install if you want to use veth pairs: - apt-get install iproute - -=== Running the Tests === - -In the sections below, {platform} refers to: -user -user_veth -kmod -kmod_veth -nf2 - -First copy the env_vars file to your home directory: - cd ~/ - cp /regress/scripts/env_vars . - -Update the OF_ROOT (openflow) environment variable to point to your OpenFlow -directory in your setup. These exports can also be added to your ~/.bashrc -file to load automatically: - vim env_vars - -Enter a root shell session, or set up sudo. The perl-Net-RawIP library requires -root access to bind to ports. - su - -Source the environment variables: - source env_vars - -For a setup with virtual ethernet pairs, set them up: - veth_setup.pl - -Verify your setup by running regression tests on your platform of choice: - of_{platform}_test.pl -For the user-space switch, the tests should show pass for all scripts except -the _X_controller ones. For the kernel-space switch, all tests should pass. - -To see more options for the regression script, type: - of_{platform}_test.pl --help - -== Writing Your Own Tests == - -Look at an example controller test: - vim /regress/projects/learning_switch/regress/test_unicast_unknown/run.pl - -Look at an example black box switch test: - vim /regress/projects/black_box/regress/test_hello/run.pl - -To run an individual test (learning switch example): - cd /regres/projects/learning_switch/regress/test_unicast_unknown - of_{platform}_setup.pl; ./run.pl; of_{platform}_teardown.pl - -To see traffic when running a black box test, use tcpdump. Secchan and the -Perl code use the loopback interface to communicate, and you can snoop on this: - tcpdump -X -i lo -s 256 - -It can be convenient to run your test in isolation, without setup and teardown -automatically called. To set up the OF kmod and interfaces, run: - of_{platform}_setup.pl - -To remove the OF kmod cleanly, run: - of_{platform}_teardown.pl -Note that the kmod refuses removal until the interfaces and datapaths have been removed. - -== Reporting Bugs == - -Please report problems to: -openflow-discuss@openflowswitch.org - -or post them directly to our bug tracking system: - -http://www.openflowswitch.org/bugs/openflow diff --git a/openflow/regress/LICENSE b/openflow/regress/LICENSE deleted file mode 100644 index b9e21768..00000000 --- a/openflow/regress/LICENSE +++ /dev/null @@ -1,30 +0,0 @@ -Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior -University - - -We are making the OpenFlow tests and associated documentation (Software) -available for public use and benefit with the expectation that others will -use, modify and enhance the Software and contribute those enhancements back -to the community. However, since we would like to make the Software -available for broadest use, with as few restrictions as possible permission -is hereby granted, free of charge, to any person obtaining a copy of this -Software) to deal in the Software under the copyrights without restriction, -including without limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to the -following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. - -The name and trademarks of copyright holder(s) may NOT be used in -advertising or publicity pertaining to the Software or any derivatives -without specific, written prior permission. diff --git a/openflow/regress/README b/openflow/regress/README deleted file mode 100644 index a27967fb..00000000 --- a/openflow/regress/README +++ /dev/null @@ -1,329 +0,0 @@ - OpenFlow Reference Tests - -What's here? ------------- - -This distribution includes: - - - 55+ "black box" tests to verify that an OF switch conforms to the - OF protocol 0x01 - - - 7 tests to verify that the reference controller acts as a learning - Ethernet switch - -The tests are intended to simplify the process of creating an OF switch -that conforms to spec. - -Please see INSTALL for instruction on installing and running the tests. - -Changelog ---------------- -1.0.0-r1 - - Added Open vSwitch scripts : kernel + user + interface maps - - Added VETH scripts for Open vSwitch : kernel + user - - Updated HP-ProCurve scipts : 5400/3500 and 6600 - - Assorted fixes to libraries : - accept port > 10 - accept vlan interfaces - more explicit error messages - - Assorted fixes to tests : - test_switch_config/ -> add delay - test_forward_broadcast_exact_port/ -> run for allports - test_set_n_match_nw_tos/ -> fixup nw_tos usage - test_set_nw_dst/ -> cleanup - test_failover_startup/ -> argv parsing was broken - - Add new test : test_set_dl_nw_flip -> flip dl & nw addresses - - Add new command line options : no_vlan, no_slicing and no_barrier, - no_emerg - - Add ability to run a single test with --testPath - - New debugging function : dpctl_show_flows - -1.0.0 - - all tests updated to OpenFlow wire protocol 0x01 - - added tests for new features in the OpenFlow 1.0.0 spec - -0.9.0 - - all tests updated to OpenFlow wire protocol 0x98 - -v0.8.2 - - Added support for the NetFPGA - - Integrated the tests into the OpenFlow directory structure - -v0.8.1-r2 - - refactored code to make new test ports easier - - fixed documentation bug in test_LLC - - changed all interfaces IPs to 192.168.20X.X to not conflict with the - IP addrs typically assigned via DHCP by home routers - - added easy support for testing user-space switch with physical ports - - added easy support for user-space switch with virtual ports - -v0.8.1-r1 - - added instructions for Debian install - - fixed timing bug in packet_out - -v0.8.1-r0 - - all tests updated to OF spec v0.8.1 - - added black box test switch_config - - fixed timing dependence in learning switch tests - -v0.2.1 - - initial release for OF spec v0.5.1, code tested for ref OF code v0.2.1 - -Platform support ----------------- - -The code is written in Perl5, and should in theory work on any system. -It has been tested with CentOS 5.4, Ubuntu 9.10, Fedora Core 12, and Debian Unstable. - -Learning Switch Tests ----------------- - -Two tests currently fail with OF Reference v0.8.1: - --Unicast, send to self: the switch is forwarding packets with source and destination on the same port to that port instead of dropping it. - --Unicast, hub connected:the switch is forwarding traffic to the same port it has came out of, although the source and destination are on the same port and switch already knows about that. - -Both failing tests can be re-activated by changing -projects/learning_switch/regress/tests.txt - -=== Unicast, unknown dest === -:; Name: test_unicast_unknown -:; Owner: Peyman -:; Description -::send packet out p0 to unknown MAC addr -::verify unmodified packet received at p1..p3 -::verify counters incremented - -=== Unicast, known dest === -:; Name: test_unicast_known -:; Owner: Peyman -:; Description: Send to known unicast address, verify switch sent to only one port -::send out p0 to p1 -::verify received at p1..p3 -::send out p1 to p0 -::verify received at p0, NOT p2, p3 -::send out p2 to p0 -::verify received at p0, NOT p1, p3 -::send out p3 to p0 -::verify received at p0, NOT p1, p2 -::verify counters - -=== Broadcast === -:; Name: test_broadcast -:; Owner: Peyman -:; Description: Send to broadcast address, verify received on all ports -::send out p0 to all -::verify received at p1..p3 -::send out p0 to all, again -::verify received at p1..p3, again -::repeat for each port -::verify counters - -=== Unicast, send to self === -:; Name: test_unicast_self -:; Owner: Peyman -:; Description: Send to self, verify dropped - -=== Unicast, change attachment point === -:; Name: test_unicast_move -:; Owner: Peyman -:; Description: Send normal unicast, but then change attachment point (one MAC sent from multiple ports), verify that new location is used -::send form host A at p0 to p1 -::verify received at p1..p3 -::send from p1 to host A -::verify received at p0, NOT p1, p2, p3 -::(original p0 has now moves to p2) -::send from host A (currently at p2) to p1 -::verify received at p1, NOT p0, p2, p3 -::send from p1 to Host A (currently at p2) -::verify received p2, NOT p0, p1, p3 - -=== Unicast, hub connected === -:; Name: test_hub_connected -:; Owner: Peyman -:; Description: if a port connects to a hub, we may receive traffic for which the sender and receiver are connected to the same port. This traffic should be dropped. - -=== Unicast, multiple hosts per port === -:; Name: test_unicast_multiple_hosts -:; Owner: Peyman -:; Description: assume each port is connected to a switch, so that each port receives traffic from multiple MAC addresses - say, 20 per port. Other than multiple MAC addrs per port, this is just like test_unicast_known. Each port sends to a host at a different port. - - -Black Box Tests ----------------- - -One test currently fails with the OF Reference v0.8.1 kmod: - --LLC: Pkt is forwarded to the controller, when it should be dropped. - -Two tests are currently failing with the OF Reference v0.8.1 user-space switch: - --test_forward_exact_controller --test_forward_wildcard_controller - -All failing tests can be re-activated by changing -projects/black_box/regress/tests.txt - -== Basic Functionality == - -=== Hello === -:; Name: test_hello -:; Owner: Brandon Heller -:; Description: send hello packet to switch, verify reply with correct params - -=== Send from Switch to Controller === -:; Name: test_packet_in -:; Owner: Brandon Heller -:; Description: send packet from switch to SC, verify it is received at the controller - -=== Send from Controller to Switch === -:; Name: test_packet_out -:; Owner: Brandon Heller -:; Description: send packet to switch on secure chan for each output port, ensure packet received at proper ports. - -=== Switch Config === -:; Name: test_switch_config -:; Owner: Brandon Heller -:; Description: verify default switch config, set config, verify that config has changed -:; Status: done - -=== Flow Expired === -:; Name: test_flow_expired -:; Owner: Brandon Heller -:; Description: send add flow message for short timeout, verify no error message received, plus flow timeout message received within time bounds -::send a second add flow message and keep it active with packets; verify that flow expires only if idle - -=== Miss Send Length === -:; Name: test_miss_send_length -:; Owner: Brandon Heller -:; Description: get the miss send length from the hello message, then send a packet to switch, verify correct length for forwarded chunk of packet - -== Modify State Tests == - -=== Forward Any Port === -:; Name: test_forward_any_port -:; Owner: Brandon Heller -:; Description: add a flow mod with all wildcards set, and ensure that all packets get diverted to the specified port. - -=== Forward Exact Port === -:; Name: test_forward_exact_port -:; Owner: Brandon Heller -:; Description: add an exact flow entry, verify a packet is forwarded to the correct port, for all port combinations - -=== Forward Exact ALL === -:; Name: test_forward_exact_all -:; Owner: Brandon Nefcy -:; Description: add an exact flow entry, verify a packet is sent out all ports, for all port combinations -:; Implementation: One packet is sent in to eth0, eth1, eth2, and eth3. An exact match flow entry is set up for each, with the expected action to be flooding the packet out on all ports except the input port. - -=== Forward Exact Controller === -:; Name: test_forward_exact_controller -:; Owner: Brandon Nefcy -:; Description: add an exact flow entry, verify a packet is forwarded to the secure channel -:; Implementation: One packet is sent in on each of eth0, eth1, eth2, and eth3. Test behavior expects to see each packet arrive via the secchan. - -=== Forward Wildcard Port === -:; Name: test_forward_wildcard_port -:; Owner: Brandon Nefcy -:; Description: Test each individual wildcard field. verify a matching packet is forwarded to the correct port, for all port combinations, and a mismatching packet is sent to secchan -:; Implementation: For each possible single-input-port to single-output-port combination flows are set up, one at a time, where each flow is wildcarded on a single field, with enough flows rotated in to test every wildcard field. For each, a matching packet is sent in and expected on the appropriate output port, and a mismatching packet is sent in and expected on the secchan output - -=== Forward Wildcard ALL === -:; Name: test_forward_wildcard_all -:; Owner: Brandon Nefcy -:; Description: same as test_forward_wildcard_port, but instead of sending from one input to one output, sends from one input to all outputs. -:; Implementation: Combination of test_foward_wildcard_port and test_forward_exact_all - -=== Forward Wildcard Controller === -:; Name: test_forward_wildcard_controller -:; Owner: Brandon Nefcy -:; Description: Combination of test_forward_wildcard_port and test_forward_exact_controller. Tests various single wildcard flows where matching packets and mismatching packets are both sent to secchan. -:; Status: Checked in, working, but with limitations as mentioned in test_forward_wildcard_port - -=== Forward After Expiration === -:; Name: test_forward_after_expiration -:; Owner: Brandon Nefcy -:; Description: insert short-lived flow, use it to forward packet, wait until expiration, send packet again, verify nothing received and counters zeroed -:; Implementation: An exact match flow entry is inserted for a specific input port -> output port combination (ie eth0->eth1), a packet is sent to match this entry with the test expecting the appropriate output behavior. The test waits for the flow entry to expire and verifies the expiration via a secchan flow expiration message, then proceeds to re-send the same packet from before, expecting a secchan OFPR_NO_MATCH message. The above is repeated for all combinations of input port -> output port. - -=== Overlapping Flow Entries === -:; Name: test_forward_overlapping_flow_entries -:; Owner: Brandon Nefcy -:; Description: insert both wildcard and exact match flow entries that overlap, verify that the exact match takes precedence -:; Implementation: One packet is sent in on eth0, eth1, eth2, and eth3. Before each packet is sent, two flow entries are set up, one where the entire flow is wildcarded and the action is to send to secchan, and another where the flow is set up to be an exact-match for the packet about to be sent and the action is to flood the packet. The test verifies that the sent packets are flooded out, and no secchan messages are received other than the flows expiring. - -=== Delete === -:; Name: test_delete -:; Owner: Masa -:; Description: insert two flow entries (one wildcard entry and one exact entry where the exact one is covered by the wildcard one). Send packets to verify they are forwarded correctly. Then delete the wildcard entry with DELETE (not strict) -- both the wildcard and the exeact entries should be deleted. To check this, send a packet matching to the exact entry to verify it gets sent to contoller. Re-insert the entry and verify that counters are zeroed. -::; Note -- Counter reading has not been implemented yet so the last part is not verified (5/2/2008) -:; Status: Done (rewritten with clean format) - -=== Delete Strict === -:; Name: test_delete_strict -:; Owner: Masa -:; Description: insert two flow entries (one wildcard entry and one exact entry where the exact one is covered by the wildcard one. The output ports of these two entries are different). Send packets to verify they are forwarded correctly. Then delete the wildcard entry with DELETE_STRICT (not strict) -- only the wildcard entry should be deleted (the exeact entry should not be deleted). To check this, send a packet matching to the exact entry to verify it gets forwarded. -:; Status: Done (rewritten with clean format) - -== Unusual Data == - -=== IP Options === -:; Name: test_ip_options -:; Owner: Masa -:; Description: suggested by Nicira. -::;(1) Create a flow entry that matches to a UDP flow coming from port eth7 (action = forward to port eth8). -::;(2) Send UDP packets with IP time stamp option (ip_hdr_len=7) to port eth7. -::;(3) To see whether the packet comes out from port eth8. -::; As of May 2, 2008, test succeeded. - -=== IP Protocol === -:; Name: test_ip_protocol -:; Owner: Masa -:; Description: -:: Added by Masa -:: see if src/dst port fields are used for matching only for TCP/UDP packets -:: As of May 2, 2008, the result is the following. Even if protocol is not TCP nor UDP, port number fields seems used for matching. Only when protocol number is specified to zero, port number fields are not used for matching.. It seems a strange behavior. -:; Status: Done (rewritten w/ clean format) -:; Note : TCP checksum (in TCP header) is not calculated due to lack of NF2::TCP library (but OF switch won't check it anyway). - -=== IP Offset > Pkt Len === -:; Name: test_ip_offset -:; Owner: Masa -:; Description: -:: possible security risk, shouldn't be an issue -:: suggested by Nicira -:: Create a flow entry. Send several packets matching the entry but whose IP Offset > Pkt Len. Verify all the packets are forwarded to the specified port (specified by the flow entry). - -=== TCP Options === -:; Name: test_tcp_options -:; Owner: Masa -:; Description: -:: See if TCP options affect operation -:: Install a TCP flow entry. Sent a TCP pkt that matches to the installed entry but has TCP option. Verify the packet is forwarded to the specified port. -:; Note : TCP checksum (in TCP header) is not calculated due to lack of NF2::TCP library (but OF switch won't check it anyway). - -=== LLC === -:; Name: test_llc -:; Owner: Masa -:; Description: see LLC packet format; adds 5B to Eth packet -::; Install a flow entry (exact match to an IP flow). Send an IP packet that matches to the installed entry and has the following Ethernet LLC/SNAP header. Verify it is forwarded to the specified port. -:::; Dst MAC (6 byte) -:::; Src MAC (6 byte) -:::; Length (2 byte) = data length from LLC header to the end of IP packet -:::; LLC header (3 byte) = 0xAA 0xAA 0x03 (always this value for IP packets) -:::; SNAP header(5 byte) = OUI(3B)+Type(2B)=0x000000 + 0x0800(IP) (always this value for IP packets) -:::; IP Packet -:; NOTE: It fails (pkt is forwarded to the controller) as of June 11, 2008. - - -Bugs/Shortcomings ------------------ - -- test_llc and test_ip_protocol are not actually run when enabled in a tests.txt file - -Contact -------- - -e-mail: openflow-discuss@openflowswitch.org -www: http://openflowswitch.org/ diff --git a/openflow/regress/bin/eth.map b/openflow/regress/bin/eth.map deleted file mode 100644 index 689ad0f0..00000000 --- a/openflow/regress/bin/eth.map +++ /dev/null @@ -1,8 +0,0 @@ -eth1:eth1 -eth2:eth2 -eth3:eth3 -eth4:eth4 -eth5:eth5 -eth6:eth6 -eth7:eth7 -eth8:eth8 diff --git a/openflow/regress/bin/nf2.map b/openflow/regress/bin/nf2.map deleted file mode 100644 index 797b3896..00000000 --- a/openflow/regress/bin/nf2.map +++ /dev/null @@ -1,8 +0,0 @@ -eth1:eth1 -eth2:eth2 -eth3:eth3 -eth4:eth4 -eth5:nf2c0 -eth6:nf2c1 -eth7:nf2c2 -eth8:nf2c3 diff --git a/openflow/regress/bin/of_hp_eth.map b/openflow/regress/bin/of_hp_eth.map deleted file mode 100644 index 4f652145..00000000 --- a/openflow/regress/bin/of_hp_eth.map +++ /dev/null @@ -1,8 +0,0 @@ -eth1:eth10 -eth2:eth11 -eth3:eth12 -eth4:eth13 -eth5:eth10 -eth6:eth11 -eth7:eth12 -eth8:eth13 diff --git a/openflow/regress/bin/of_hp_setup.pl b/openflow/regress/bin/of_hp_setup.pl deleted file mode 100755 index 213376c6..00000000 --- a/openflow/regress/bin/of_hp_setup.pl +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use OF::OFUtil; -use Test::TestLib; -use Time::HiRes qw(usleep); - -my $mapFile; -my $of_hp_switch_ip; -my $of_hp_vlan; -my $of_hp_controller; -my $of_hp_listener; -my $of_hp_community; - -# Process command line options -# Don't fail on unrecognised options, those failures are tricky -# to diagnose. For example projects/controller_disconnect sets --emerg -# Jean II -Getopt::Long::Configure( 'pass_through' ); -GetOptions( "map=s" => \$mapFile, ); -Getopt::Long::Configure( 'default' ); - -# If not specified on command line, use environment variable. -# Try specific first, then try generic - Jean II -if ( (! defined($mapFile) ) && (defined($ENV{'OFT_HP_MAP_ETH'})) ) { - $mapFile = "$ENV{OFT_HP_MAP_ETH}"; -} -if ( (! defined($mapFile) ) && (defined($ENV{'OFT_MAP_ETH'})) ) { - $mapFile = "$ENV{OFT_MAP_ETH}"; -} - -if ( defined($mapFile) ) { - nftest_process_iface_map($mapFile); -} - -setup_pcap_interfaces(); - -# Get HP switch address and configuration - Jean II -if (defined($ENV{'OFT_HP_SWITCH_IP'})) { - $of_hp_switch_ip = $ENV{'OFT_HP_SWITCH_IP'}; -} else { - $of_hp_switch_ip = "10.10.10.1"; -} -if (defined($ENV{'OFT_HP_VLAN'})) { - $of_hp_vlan = $ENV{'OFT_HP_VLAN'}; -} else { - $of_hp_vlan = 18; -} -if (defined($ENV{'OFT_HP_CONTROLLER'})) { - $of_hp_controller = $ENV{'OFT_HP_CONTROLLER'}; -} else { - my $of_port = get_of_port(); - $of_hp_controller = "tcp:10.10.10.2:$of_port"; -} -if (defined($ENV{'OFT_HP_LISTENER'})) { - # Transform into a passive string - ($proto, $host, $port) = split(/:/,$ENV{'OFT_HP_LISTENER'}); - $of_hp_listener = "p$proto:$port"; -} -if (defined($ENV{'OFT_HP_COMMUNITY'})) { - $of_hp_community = $ENV{'OFT_HP_COMMUNITY'}; -} else { - $of_hp_community = 'public'; -} - - -# disable OpenFlow module to make sure it restarts -`snmpset -v2c -c ${of_hp_community} ${of_hp_switch_ip} iso.org.dod.internet.private.enterprises.11.2.14.11.5.1.7.1.35.1.1.2.${of_hp_vlan} i 2`; - -# Make sure the snmp commands don't coalesce -usleep(200000); - -# set OpenFlow Controller string -`snmpset -v2c -c ${of_hp_community} ${of_hp_switch_ip} iso.org.dod.internet.private.enterprises.11.2.14.11.5.1.7.1.35.1.1.3.${of_hp_vlan} s ${of_hp_controller}`; - -# set OpenFlow Listener string -if (defined($of_hp_listener)) { - `snmpset -v2c -c ${of_hp_community} ${of_hp_switch_ip} iso.org.dod.internet.private.enterprises.11.2.14.11.5.1.7.1.35.1.1.4.${of_hp_vlan} s ${of_hp_listener}`; -} - -# enable OpenFlow module -`snmpset -v2c -c ${of_hp_community} ${of_hp_switch_ip} iso.org.dod.internet.private.enterprises.11.2.14.11.5.1.7.1.35.1.1.2.${of_hp_vlan} i 1`; - -# Starting OpenFlow takes time, give switch a bit of time... -usleep(900000); diff --git a/openflow/regress/bin/of_hp_teardown.pl b/openflow/regress/bin/of_hp_teardown.pl deleted file mode 100755 index 0365ce67..00000000 --- a/openflow/regress/bin/of_hp_teardown.pl +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use OF::OFUtil; -use Test::TestLib; - -my $mapFile; -my $of_hp_switch_ip; -my $of_hp_community; - -# Process command line options -unless ( GetOptions( "map=s" => \$mapFile, ) ) { - print "unrecognized option\n"; - exit 1; -} - -# If not specified on command line, use environment variable. -# Try specific first, then try generic - Jean II -if ( (! defined($mapFile) ) && (defined($ENV{'OFT_HP_MAP_ETH'})) ) { - $mapFile = "$ENV{OFT_HP_MAP_ETH}"; -} -if ( (! defined($mapFile) ) && (defined($ENV{'OFT_MAP_ETH'})) ) { - $mapFile = "$ENV{OFT_MAP_ETH}"; -} - -if ( defined($mapFile) ) { - nftest_process_iface_map($mapFile); -} - -# Get HP switch address - Jean II -if (defined($ENV{'OFT_HP_SWITCH_IP'})) { - $of_hp_switch_ip = $ENV{'OFT_HP_SWITCH_IP'}; -} else { - $of_hp_switch_ip = "10.10.10.1"; -} -if (defined($ENV{'OFT_HP_VLAN'})) { - $of_hp_vlan = $ENV{'OFT_HP_VLAN'}; -} else { - $of_hp_vlan = 18; -} -if (defined($ENV{'OFT_HP_COMMUNITY'})) { - $of_hp_community = $ENV{'OFT_HP_COMMUNITY'}; -} else { - $of_hp_community = 'public'; -} - -# disable OpenFlow module -`snmpset -v2c -c ${of_hp_community} ${of_hp_switch_ip} iso.org.dod.internet.private.enterprises.11.2.14.11.5.1.7.1.35.1.1.2.${of_hp_vlan} i 2`; - diff --git a/openflow/regress/bin/of_hp_test.pl b/openflow/regress/bin/of_hp_test.pl deleted file mode 100755 index d6c3233f..00000000 --- a/openflow/regress/bin/of_hp_test.pl +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/perl -w - -############################################################################## -# -# Wrapper for running OpenFlow regression tests against ProCurve 3500/5400 -# Jean Tourrilhes - HP-Labs - copyright 2009-2010 -# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ -# -############################################################################## - -use OF::Base; -use Test::RegressTest; -use strict; -use OF::OFUtil; - -# check vars are set. -check_OF_vars_set(); - -sub INT_Handler { - my $signame = shift; - print "\nNo interrupt handler implemented yet...\n"; - print "\nExited with SIG$signame\n"; - exit(1); -} - -# For the 5406zl and 3500yl... - -# HP switch starts at port 1 == 'A1' or 1 == '1' -# Test need extra delay due to slow controller socket -# Add more idle time due to stat resolution -# byte count is not available - Jean II -push @ARGV, "--root=$ENV{'OFT_ROOT'}", "--common-st-args=hp", "--controller=".$ENV{'OFT_HP_CONTROLLER'}, "--port_base=1", "--send_delay=300000", "--base_idle=2", "--ignore_byte_count"; - -# Use a single random port instead of all four -push @ARGV, "--less_ports"; - -# For QinQ, you will need the premium license... -push @ARGV, "--no_vlan"; - -# The hardware can not support slicing -push @ARGV, "--no_slicing"; - -# The hardware can not support barrier -push @ARGV, "--no_barrier"; - -# The hardware can not support emergency flow table -push @ARGV, "--no_emerg"; - -# Check for listener -if ( defined($ENV{'OFT_HP_LISTENER'}) ) { - push @ARGV, "--listener=$ENV{OFT_HP_LISTENER}"; -} - -# Check for specific MAP file... -if ( defined($ENV{'OFT_HP_MAP_ETH'}) ) { - push @ARGV, "--map=$ENV{OFT_HP_MAP_ETH}"; -} - -# Other configuration is through Environment Variables, See of_hp_setup.pl -# Jean II - -run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_hp_test_6600.pl b/openflow/regress/bin/of_hp_test_6600.pl deleted file mode 100755 index e141def5..00000000 --- a/openflow/regress/bin/of_hp_test_6600.pl +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/perl -w - -############################################################################## -# -# Wrapper for running OpenFlow regression tests against ProCurve 6600 -# Jean Tourrilhes - HP-Labs - copyright 2009-2010 -# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ -# -############################################################################## - -use OF::Base; -use Test::RegressTest; -use strict; -use OF::OFUtil; - -# check vars are set. -check_OF_vars_set(); - -sub INT_Handler { - my $signame = shift; - print "\nNo interrupt handler implemented yet...\n"; - print "\nExited with SIG$signame\n"; - exit(1); -} - -# For the 6600... - -# HP switch starts at port 25 == '1' -# Test need extra delay due to slow controller socket -# Add more idle time due to stat resolution -# byte count is not available - Jean II -push @ARGV, "--root=$ENV{'OFT_ROOT'}", "--common-st-args=hp", "--controller=".$ENV{'OFT_HP_CONTROLLER'}, "--port_base=25", "--send_delay=650000", "--base_idle=3", "--ignore_byte_count"; - -# Use a single random port instead of all four -push @ARGV, "--less_ports"; - -# For QinQ, you will need the premium license... -push @ARGV, "--no_vlan"; - -# The hardware can not support slicing -push @ARGV, "--no_slicing"; - -# The hardware can not support barrier -push @ARGV, "--no_barrier"; - -# The hardware can not support emergency flow table -push @ARGV, "--no_emerg"; - -# Check for listener -if ( defined($ENV{'OFT_HP_LISTENER'}) ) { - push @ARGV, "--listener=$ENV{OFT_HP_LISTENER}"; -} - -# Check for specific MAP file... -if ( defined($ENV{'OFT_HP_MAP_ETH'}) ) { - push @ARGV, "--map=$ENV{OFT_HP_MAP_ETH}"; -} - -# Other configuration is through Environment Variables, See of_hp_setup.pl -# Jean II - -run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_kmod_setup.pl b/openflow/regress/bin/of_kmod_setup.pl deleted file mode 100755 index fc3ef4ba..00000000 --- a/openflow/regress/bin/of_kmod_setup.pl +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use OF::OFUtil; -use Test::TestLib; - -my $mapFile, $controller; - -# Process command line options -unless ( GetOptions( "map=s" => \$mapFile, - "emerg" => \$emerg, - "controller=s", \$controller) ) { - print "unrecognized option\n"; - exit 1; -} - -if ( defined($mapFile) ) { - nftest_process_iface_map($mapFile); -} - -setup_kmod($controller, $emerg); diff --git a/openflow/regress/bin/of_kmod_teardown.pl b/openflow/regress/bin/of_kmod_teardown.pl deleted file mode 100755 index 4fa7dbfa..00000000 --- a/openflow/regress/bin/of_kmod_teardown.pl +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use OF::OFUtil; -use Test::TestLib; - -my $mapFile; - -# Process command line options -unless ( GetOptions( "map=s" => \$mapFile, ) ) { - print "unrecognized option\n"; - exit 1; -} - -if ( defined($mapFile) ) { - nftest_process_iface_map($mapFile); -} - -teardown_kmod(); diff --git a/openflow/regress/bin/of_kmod_test.pl b/openflow/regress/bin/of_kmod_test.pl deleted file mode 100755 index 6ce99411..00000000 --- a/openflow/regress/bin/of_kmod_test.pl +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/perl -w - -############################################################################## -# -# Wrapper for OpenFlow regression tests -# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ -# -############################################################################## - -use OF::Base; -use Test::RegressTest; -use strict; -use OF::OFUtil; - -# check vars are set. -check_OF_vars_set(); - -sub INT_Handler { - my $signame = shift; - print "\nNo interrupt handler implemented yet...\n"; - print "\nExited with SIG$signame\n"; - exit(1); -} - -push (@ARGV, "--root=$ENV{'OFT_ROOT'}", "--map=$ENV{'OFT_ROOT'}/bin/eth.map", "--port_base=1", "--common-st-args=kmod"); - -run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_kmod_veth_setup.pl b/openflow/regress/bin/of_kmod_veth_setup.pl deleted file mode 100755 index 79a37733..00000000 --- a/openflow/regress/bin/of_kmod_veth_setup.pl +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use OF::OFUtil; -use Test::TestLib; - -my ($mapFile, $controller); - -# Process command line options -unless ( GetOptions( "map=s" => \$mapFile, - "emerg" => \$emerg, - "controller=s", \$controller) ) { - print "unrecognized option\n"; - exit 1; -} - -if ( defined($mapFile) ) { - nftest_process_iface_map($mapFile); -} -#else, use pre-defined veth map -else { - nftest_process_iface_map("$ENV{'OFT_ROOT'}/bin/veth.map"); -} - -setup_kmod($controller, $emerg); diff --git a/openflow/regress/bin/of_kmod_veth_teardown.pl b/openflow/regress/bin/of_kmod_veth_teardown.pl deleted file mode 100755 index 52b57927..00000000 --- a/openflow/regress/bin/of_kmod_veth_teardown.pl +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use OF::OFUtil; -use Test::TestLib; - -my $mapFile; - -# Process command line options -unless ( GetOptions( "map=s" => \$mapFile, ) ) { - print "unrecognized option\n"; - exit 1; -} - -if ( defined($mapFile) ) { - nftest_process_iface_map($mapFile); -} -#else, use pre-defined veth map -else { - nftest_process_iface_map("$ENV{'OFT_ROOT'}/bin/veth.map"); -} - -teardown_kmod(); diff --git a/openflow/regress/bin/of_kmod_veth_test.pl b/openflow/regress/bin/of_kmod_veth_test.pl deleted file mode 100755 index 0f08edbb..00000000 --- a/openflow/regress/bin/of_kmod_veth_test.pl +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/perl -w - -############################################################################## -# -# Wrapper for OpenFlow regression tests -# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ -# -############################################################################## - -use OF::Base; -use Test::RegressTest; -use strict; -use OF::OFUtil; - -# check vars are set. -check_OF_vars_set(); - -sub INT_Handler { - my $signame = shift; - print "\nNo interrupt handler implemented yet...\n"; - print "\nExited with SIG$signame\n"; - exit(1); -} - -push (@ARGV, "--map=$ENV{'OFT_ROOT'}/bin/veth.map", "--root=$ENV{'OFT_ROOT'}", "--port_base=1", "--common-st-args=kmod_veth"); - -run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_nf2_setup.pl b/openflow/regress/bin/of_nf2_setup.pl deleted file mode 100755 index 34fe3351..00000000 --- a/openflow/regress/bin/of_nf2_setup.pl +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; -use Data::Dumper; - -use OF::OFUtil; -use Test::TestLib; - -my ($mapFile, $controller); - -print "Calling of_nf2_setup.pl\n"; -print Dumper(@ARGV) . "\n"; - -# Process command line options -unless ( GetOptions( "map=s" => \$mapFile, - "emerg" => \$emerg, - "controller=s", \$controller) ) { - print "unrecognized option\n"; - exit 1; -} - -if ( defined($mapFile) ) { - nftest_process_iface_map($mapFile); -} - -setup_NF2($controller, $emerg); diff --git a/openflow/regress/bin/of_nf2_teardown.pl b/openflow/regress/bin/of_nf2_teardown.pl deleted file mode 100755 index 286a87cf..00000000 --- a/openflow/regress/bin/of_nf2_teardown.pl +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use OF::OFUtil; -use Test::TestLib; - -my $mapFile; - -# Process command line options -unless ( GetOptions( "map=s" => \$mapFile, ) ) { - print "unrecognized option\n"; - exit 1; -} - -if ( defined($mapFile) ) { - nftest_process_iface_map($mapFile); -} - -teardown_NF2(); diff --git a/openflow/regress/bin/of_nf2_test.pl b/openflow/regress/bin/of_nf2_test.pl deleted file mode 100755 index 0704e99a..00000000 --- a/openflow/regress/bin/of_nf2_test.pl +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/perl -w - -############################################################################## -# -# Wrapper for OpenFlow regression tests -# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ -# -############################################################################## - -use OF::Base; -use Test::RegressTest; -use strict; -use OF::OFUtil; - -# check vars are set. -check_OF_vars_set(); - -sub INT_Handler { - my $signame = shift; - print "\nNo interrupt handler implemented yet...\n"; - print "\nExited with SIG$signame\n"; - exit(1); -} - -push (@ARGV, "--root=$ENV{'OFT_ROOT'}", "--map=$ENV{'OFT_ROOT'}/bin/nf2.map", "--port_base=1", "--common-st-args=nf2"); -push @ARGV, "--no_slicing"; - -run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_ovs_eth.map b/openflow/regress/bin/of_ovs_eth.map deleted file mode 100644 index 120ee51d..00000000 --- a/openflow/regress/bin/of_ovs_eth.map +++ /dev/null @@ -1,8 +0,0 @@ -eth1:eth10.91 -eth2:eth10.92 -eth3:eth10.93 -eth4:eth10.94 -eth5:eth11.91 -eth6:eth11.92 -eth7:eth11.93 -eth8:eth11.94 diff --git a/openflow/regress/bin/of_ovs_setup.pl b/openflow/regress/bin/of_ovs_setup.pl deleted file mode 100755 index ca2cc93f..00000000 --- a/openflow/regress/bin/of_ovs_setup.pl +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/perl -w -# Jean Tourrilhes - HP-Labs - -use Getopt::Long; - -use OF::OFUtil; -use Test::TestLib; - -my $mapFile; - -# The map file is necessary. It assing the real interface to the -# fictious names used by the test suite. -# eth1->eth4 are capture interfaces used to send/receive probe packets -# eth5->eth8 are configured to run the OpenFlow switch -# Jean II - -# Process command line options -# Don't fail on unrecognised options, those failures are tricky -# to diagnose. For example projects/controller_disconnect sets --emerg -# Jean II -Getopt::Long::Configure( 'pass_through' ); -GetOptions( "map=s" => \$mapFile, ); -Getopt::Long::Configure( 'default' ); - -# If not specified on command line, use enviroment variable. -# Try specific first, then try generic - Jean II -if ( (! defined($mapFile) ) && (defined($ENV{'OFT_OVS_MAP_ETH'})) ) { - $mapFile = "$ENV{OFT_OVS_MAP_ETH}"; -} -if ( (! defined($mapFile) ) && (defined($ENV{'OFT_MAP_ETH'})) ) { - $mapFile = "$ENV{OFT_MAP_ETH}"; -} - -# Set up the mappings -if ( defined($mapFile) ) { - nftest_process_iface_map($mapFile); -} - -# Debug... -#for ( my $i = 1 ; $i <= 8 ; $i++ ) { -# my $iface = nftest_get_iface("eth$i"); -# print "iface($i) = $iface\n"; -#} - -# Start capturing on eth1->eth4 -setup_pcap_interfaces(); - -# Get the directly where Open vSwitch resides -my $ovs_dir = $ENV{'OFT_OVS_ROOT'}; -my $of_port = get_of_port(); - -# Setup the kernel module -`insmod ${ovs_dir}/datapath/linux-2.6/openvswitch_mod.ko`; -`${ovs_dir}/utilities/ovs-dpctl add-dp dp0`; - -# Not needed after 0.99.2 -#for ( my $i = 5 ; $i <= 8 ; $i++ ) { -# my $iface = nftest_get_iface("eth$i"); -# `${ovs_dir}/utilities/ovs-dpctl add-if dp0 $iface`; -#} - -# create command line arguments containing all four ports -my $if_string = ''; -for ( my $i = 5 ; $i <= 7 ; $i++ ) { - $if_string .= nftest_get_iface("eth$i") . ','; -} -$if_string .= nftest_get_iface("eth8"); - -# create Open vSwitch openflow switch on four ports eth5->eth9 -system("${ovs_dir}/utilities/ovs-openflowd dp0 --ports=${if_string} tcp:127.0.0.1:${of_port} --listen=ptcp:6634 --fail=closed --inactivity-probe=999999 &"); - -# For 0.99.0, you'll need to manually add ports as above -#system("${ovs_dir}/utilities/ovs-openflowd dp0 tcp:127.0.0.1:${of_port} --listen=ptcp:6634 --fail=closed --inactivity-probe=999999 &"); - -# Up to 0.90.6, you would use secchan, after that you need to use ovs-openflowd -#system("${ovs_dir}/secchan/secchan dp0 tcp:127.0.0.1:${of_port} --listen=ptcp:6634 --fail=closed --inactivity-probe=999999 &"); diff --git a/openflow/regress/bin/of_ovs_teardown.pl b/openflow/regress/bin/of_ovs_teardown.pl deleted file mode 100755 index 303eb4ad..00000000 --- a/openflow/regress/bin/of_ovs_teardown.pl +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/perl -w -# Jean Tourrilhes - HP-Labs - -use Getopt::Long; - -use OF::OFUtil; -use Test::TestLib; - -my $mapFile; - -# Process command line options -unless ( GetOptions( "map=s" => \$mapFile, ) ) { - print "unrecognized option\n"; - exit 1; -} - -# If not specified on command line, use enviroment variable. -# Try specific first, then try generic - Jean II -if ( (! defined($mapFile) ) && (defined($ENV{'OFT_OVS_MAP_ETH'})) ) { - $mapFile = "$ENV{OFT_OVS_MAP_ETH}"; -} -if ( (! defined($mapFile) ) && (defined($ENV{'OFT_MAP_ETH'})) ) { - $mapFile = "$ENV{OFT_MAP_ETH}"; -} - -if ( defined($mapFile) ) { - nftest_process_iface_map($mapFile); -} - -# Get the directly where Open vSwitch resides -my $ovs_dir = $ENV{'OFT_OVS_ROOT'}; - -# Start by killing secchan or ovs-openflowd -`killall secchan`; -`killall ovs-openflowd`; - -# check if openflow kernel module loaded -my $of_kmod_loaded = `lsmod | grep openvswitch_mod`; -if ( $of_kmod_loaded eq "" ) { exit 0; } - -print "tearing down interfaces and datapaths\n"; - -# remove interfaces from openflow -for ( my $i = 5 ; $i <= 8 ; $i++ ) { - my $iface = nftest_get_iface("eth$i"); - `${ovs_dir}/utilities/ovs-dpctl del-if dp0 $iface`; -} - -`${ovs_dir}/utilities/ovs-dpctl del-dp dp0`; - -my $of_kmod_removed = `rmmod openvswitch_mod`; -if ( $of_kmod_removed ne "" ) { - die "failed to remove kernel module... please fix!\n"; -} - -$of_kmod_loaded = `lsmod | grep openvswitch_mod`; -if ( $of_kmod_loaded ne "" ) { - die "failed to remove kernel module... please fix!\n"; -} diff --git a/openflow/regress/bin/of_ovs_test.pl b/openflow/regress/bin/of_ovs_test.pl deleted file mode 100755 index a842aa64..00000000 --- a/openflow/regress/bin/of_ovs_test.pl +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/perl -w - -############################################################################## -# -# Wrapper for running OpenFlow regression tests against Open vSwitch -# Jean Tourrilhes - HP-Labs - copyright 2009-2010 -# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ -# -############################################################################## - -use OF::Base; -use Test::RegressTest; -use strict; -use OF::OFUtil; - -# check vars are set. -check_OF_vars_set(); - -sub INT_Handler { - my $signame = shift; - print "\nNo interrupt handler implemented yet...\n"; - print "\nExited with SIG$signame\n"; - exit(1); -} - -# For Open vSwitch - -# Open vSwitch starts at port 1 -# Get a bit of speedup by tweaking send_delay and base_idle -# Jean II -my $of_port = get_of_port(); -push @ARGV, "--root=$ENV{'OFT_ROOT'}", "--common-st-args=ovs", "--controller=tcp:localhost:$of_port,tcp:localhost:$of_port", "--listener=tcp:127.0.0.1:6634", "--port_base=1", "--send_delay=2000", "--base_idle=2"; - -# Use a single random port instead of all four -push @ARGV, "--less_ports"; - -# Don't bother with VLAN if we go outside the box, too many issues... -#push @ARGV, "--no_vlan"; - -# Don't bother with QoS currently, it's broken... -push @ARGV, "--no_slicing"; - -# The bother with emergency flow table tests, it's not supported... -push @ARGV, "--no_emerg"; - -# Don't forget to configure the OVS_ROOT environment variable -# Jean II - -# Check for specific MAP file... -if ( defined($ENV{'OFT_OVS_MAP_ETH'}) ) { - push @ARGV, "--map=$ENV{OFT_OVS_MAP_ETH}"; -} - -run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_ovs_user_setup.pl b/openflow/regress/bin/of_ovs_user_setup.pl deleted file mode 100755 index aa31cff6..00000000 --- a/openflow/regress/bin/of_ovs_user_setup.pl +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/perl -w -# Jean Tourrilhes - HP-Labs - -use Getopt::Long; - -use OF::OFUtil; -use Test::TestLib; - -my $mapFile; - -# The map file is necessary. It assing the real interface to the -# fictious names used by the test suite. -# eth1->eth4 are capture interfaces used to send/receive probe packets -# eth5->eth8 are configured to run the OpenFlow switch -# Jean II - -# Process command line options -# Don't fail on unrecognised options, those failures are tricky -# to diagnose. For example projects/controller_disconnect sets --emerg -# Jean II -Getopt::Long::Configure( 'pass_through' ); -GetOptions( "map=s" => \$mapFile, ); -Getopt::Long::Configure( 'default' ); - -# If not specified on command line, use enviroment variable. -# Try specific first, then try generic - Jean II -if ( (! defined($mapFile) ) && (defined($ENV{'OFT_OVS_MAP_ETH'})) ) { - $mapFile = "$ENV{OFT_OVS_MAP_ETH}"; -} -if ( (! defined($mapFile) ) && (defined($ENV{'OFT_MAP_ETH'})) ) { - $mapFile = "$ENV{OFT_MAP_ETH}"; -} - -# Set up the mappings -if ( defined($mapFile) ) { - nftest_process_iface_map($mapFile); -} - -# Debug... -#for ( my $i = 1 ; $i <= 8 ; $i++ ) { -# my $iface = nftest_get_iface("eth$i"); -# print "iface($i) = $iface\n"; -#} - -# Start capturing on eth1->eth4 -setup_pcap_interfaces(); - -# Get the directly where Open vSwitch resides -my $ovs_dir = $ENV{'OFT_OVS_ROOT'}; -my $of_port = get_of_port(); - -# create command line arguments containing all four ports -my $if_string = ''; -for ( my $i = 5 ; $i <= 7 ; $i++ ) { - $if_string .= nftest_get_iface("eth$i") . ','; -} -$if_string .= nftest_get_iface("eth8"); - -# create userspace Open vSwitch openflow switch on four ports -system("${ovs_dir}/utilities/ovs-openflowd netdev\@br0 --ports=${if_string} tcp:127.0.0.1:${of_port} --listen=ptcp:6634 --fail=closed --inactivity-probe=999999 &"); diff --git a/openflow/regress/bin/of_ovs_user_teardown.pl b/openflow/regress/bin/of_ovs_user_teardown.pl deleted file mode 100755 index 81124624..00000000 --- a/openflow/regress/bin/of_ovs_user_teardown.pl +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/perl -w -# Jean Tourrilhes - HP-Labs - -use Getopt::Long; - -use OF::OFUtil; -use Test::TestLib; - -my $mapFile; - -# Process command line options -unless ( GetOptions( "map=s" => \$mapFile, ) ) { - print "unrecognized option\n"; - exit 1; -} - -# If not specified on command line, use enviroment variable. -# Try specific first, then try generic - Jean II -if ( (! defined($mapFile) ) && (defined($ENV{'OFT_OVS_MAP_ETH'})) ) { - $mapFile = "$ENV{OFT_OVS_MAP_ETH}"; -} -if ( (! defined($mapFile) ) && (defined($ENV{'OFT_MAP_ETH'})) ) { - $mapFile = "$ENV{OFT_MAP_ETH}"; -} - -if ( defined($mapFile) ) { - nftest_process_iface_map($mapFile); -} - -# Get the directly where Open vSwitch resides -my $ovs_dir = $ENV{'OFT_OVS_ROOT'}; - -# Just kill ovs-openflowd -`killall ovs-openflowd`; diff --git a/openflow/regress/bin/of_ovs_user_test.pl b/openflow/regress/bin/of_ovs_user_test.pl deleted file mode 100755 index e726e556..00000000 --- a/openflow/regress/bin/of_ovs_user_test.pl +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/perl -w - -############################################################################## -# -# Wrapper for OpenFlow regression tests -# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ -# -############################################################################## - -use OF::Base; -use Test::RegressTest; -use strict; -use OF::OFUtil; - -# check vars are set. -check_OF_vars_set(); - -sub INT_Handler { - my $signame = shift; - print "\nNo interrupt handler implemented yet...\n"; - print "\nExited with SIG$signame\n"; - exit(1); -} - -# For Open vSwitch - -# Open vSwitch starts at port 1 -# Get a bit of speedup by tweaking send_delay and base_idle -# Jean II -my $of_port = get_of_port(); -push @ARGV, "--root=$ENV{'OFT_ROOT'}", "--common-st-args=ovs_user", "--controller=tcp:localhost:$of_port,tcp:localhost:$of_port", "--listener=tcp:127.0.0.1:6634", "--port_base=1", "--send_delay=2000", "--base_idle=2"; - -# Use a single random port instead of all four -push @ARGV, "--less_ports"; - -# Don't bother with QoS currently, it's broken... -push @ARGV, "--no_slicing"; - -# The bother with emergency flow table tests, it's not supported... -push @ARGV, "--no_emerg"; - -# Don't forget to configure the OVS_ROOT environment variable -# Jean II - -# Check for specific MAP file... -if ( defined($ENV{'OFT_OVS_MAP_ETH'}) ) { - push @ARGV, "--map=$ENV{OFT_OVS_MAP_ETH}"; -} - -run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_ovs_user_veth_test.pl b/openflow/regress/bin/of_ovs_user_veth_test.pl deleted file mode 100755 index 93a7a5df..00000000 --- a/openflow/regress/bin/of_ovs_user_veth_test.pl +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/perl -w - -############################################################################## -# -# Wrapper for running OpenFlow regression tests against Open vSwitch -# using veth -# Jean Tourrilhes - HP-Labs - copyright 2009-2010 -# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ -# -############################################################################## - -use OF::Base; -use Test::RegressTest; -use strict; -use OF::OFUtil; - -# check vars are set. -check_OF_vars_set(); - -sub INT_Handler { - my $signame = shift; - print "\nNo interrupt handler implemented yet...\n"; - print "\nExited with SIG$signame\n"; - exit(1); -} - -# For Open vSwitch - -# Open vSwitch starts at port 1 -# Get a bit of speedup by tweaking send_delay and base_idle -# Jean II -my $of_port = get_of_port(); -push @ARGV, "--root=$ENV{'OFT_ROOT'}", "--common-st-args=ovs_user", "--controller=tcp:localhost:$of_port,tcp:localhost:$of_port", "--listener=tcp:127.0.0.1:6634", "--port_base=1", "--send_delay=2000", "--base_idle=2", "--map=$ENV{'OFT_ROOT'}/bin/veth.map"; - -# Use a single random port instead of all four -push @ARGV, "--less_ports"; - -# Don't bother with QoS currently, it's broken... -push @ARGV, "--no_slicing"; - -# The bother with emergency flow table tests, it's not supported... -push @ARGV, "--no_emerg"; - -# Don't forget to configure the OVS_ROOT environment variable -# Jean II - -run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_ovs_veth_test.pl b/openflow/regress/bin/of_ovs_veth_test.pl deleted file mode 100755 index 4f09714a..00000000 --- a/openflow/regress/bin/of_ovs_veth_test.pl +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/perl -w - -############################################################################## -# -# Wrapper for running OpenFlow regression tests against Open vSwitch -# using veth -# Jean Tourrilhes - HP-Labs - copyright 2009-2010 -# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ -# -############################################################################## - -use OF::Base; -use Test::RegressTest; -use strict; -use OF::OFUtil; - -# check vars are set. -check_OF_vars_set(); - -sub INT_Handler { - my $signame = shift; - print "\nNo interrupt handler implemented yet...\n"; - print "\nExited with SIG$signame\n"; - exit(1); -} - -# For Open vSwitch - -# Open vSwitch starts at port 1 -# Get a bit of speedup by tweaking send_delay and base_idle -# Jean II -my $of_port = get_of_port(); -push @ARGV, "--root=$ENV{'OFT_ROOT'}", "--common-st-args=ovs", "--controller=tcp:localhost:$of_port,tcp:localhost:$of_port", "--listener=tcp:127.0.0.1:6634", "--port_base=1", "--send_delay=2000", "--base_idle=2", "--map=$ENV{'OFT_ROOT'}/bin/veth.map"; - -# Use a single random port instead of all four -push @ARGV, "--less_ports"; - -# Don't bother with QoS currently, it's broken... -push @ARGV, "--no_slicing"; - -# The bother with emergency flow table tests, it's not supported... -push @ARGV, "--no_emerg"; - -# Don't forget to configure the OVS_ROOT environment variable -# Jean II - -run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_user_setup.pl b/openflow/regress/bin/of_user_setup.pl deleted file mode 100755 index 5ff86039..00000000 --- a/openflow/regress/bin/of_user_setup.pl +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use OF::OFUtil; -use Test::TestLib; - -my ($mapFile, $controller); - -# Process command line options -unless ( GetOptions( "map=s" => \$mapFile, - "emerg" => \$emerg, - "controller=s", \$controller) ) { - print "unrecognized option\n"; - exit 1; -} - -if ( defined($mapFile) ) { - nftest_process_iface_map($mapFile); -} - -setup_user($controller, $emerg); diff --git a/openflow/regress/bin/of_user_teardown.pl b/openflow/regress/bin/of_user_teardown.pl deleted file mode 100755 index 760d7e25..00000000 --- a/openflow/regress/bin/of_user_teardown.pl +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use OF::OFUtil; -use Test::TestLib; - -my $mapFile; - -# Process command line options -unless ( GetOptions( "map=s" => \$mapFile, ) ) { - print "unrecognized option\n"; - exit 1; -} - -if ( defined($mapFile) ) { - nftest_process_iface_map($mapFile); -} - -teardown_user(); diff --git a/openflow/regress/bin/of_user_test.pl b/openflow/regress/bin/of_user_test.pl deleted file mode 100755 index 1fb19ea0..00000000 --- a/openflow/regress/bin/of_user_test.pl +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/perl -w - -############################################################################## -# -# Wrapper for OpenFlow regression tests -# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ -# -############################################################################## - -use OF::Base; -use Test::RegressTest; -use strict; -use OF::OFUtil; - -# check vars are set. -check_OF_vars_set(); - -sub INT_Handler { - my $signame = shift; - print "\nNo interrupt handler implemented yet...\n"; - print "\nExited with SIG$signame\n"; - exit(1); -} - -push (@ARGV, "--root=$ENV{'OFT_ROOT'}", "--map=$ENV{'OFT_ROOT'}/bin/eth.map", "--port_base=1", "--common-st-args=user"); - -run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_user_veth_setup.pl b/openflow/regress/bin/of_user_veth_setup.pl deleted file mode 100755 index d5ae5edc..00000000 --- a/openflow/regress/bin/of_user_veth_setup.pl +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use OF::OFUtil; -use Test::TestLib; - -my ($mapFile, $controller); - -# Process command line options -unless ( GetOptions( "map=s" => \$mapFile, - "emerg" => \$emerg, - "controller=s", \$controller) ) { - print "unrecognized option\n"; - exit 1; -} - -if ( defined($mapFile) ) { - nftest_process_iface_map($mapFile); -} -#else, use pre-defined veth map -else { - nftest_process_iface_map("$ENV{'OFT_ROOT'}/bin/veth.map"); -} - -setup_user($controller, $emerg); diff --git a/openflow/regress/bin/of_user_veth_teardown.pl b/openflow/regress/bin/of_user_veth_teardown.pl deleted file mode 100755 index 7d14c89c..00000000 --- a/openflow/regress/bin/of_user_veth_teardown.pl +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use OF::OFUtil; -use Test::TestLib; - -my $mapFile; - -# Process command line options -unless ( GetOptions( "map=s" => \$mapFile, ) ) { - print "unrecognized option\n"; - exit 1; -} - -if ( defined($mapFile) ) { - nftest_process_iface_map($mapFile); -} -#else, use pre-defined veth map -else { - nftest_process_iface_map("$ENV{'OFT_ROOT'}/bin/veth.map"); -} - -teardown_user(); diff --git a/openflow/regress/bin/of_user_veth_test.pl b/openflow/regress/bin/of_user_veth_test.pl deleted file mode 100755 index 63551f98..00000000 --- a/openflow/regress/bin/of_user_veth_test.pl +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/perl -w - -############################################################################## -# -# Wrapper for OpenFlow regression tests -# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ -# -############################################################################## - -use OF::Base; -use Test::RegressTest; -use strict; -use OF::OFUtil; - -# check vars are set. -check_OF_vars_set(); - -sub INT_Handler { - my $signame = shift; - print "\nNo interrupt handler implemented yet...\n"; - print "\nExited with SIG$signame\n"; - exit(1); -} - -push( @ARGV, "--map=$ENV{'OFT_ROOT'}/bin/veth.map", "--root=$ENV{'OFT_ROOT'}", "--port_base=1", "--common-st-args=user_veth"); - -run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/veth.map b/openflow/regress/bin/veth.map deleted file mode 100644 index bb1c1b09..00000000 --- a/openflow/regress/bin/veth.map +++ /dev/null @@ -1,8 +0,0 @@ -eth1:veth0 -eth2:veth2 -eth3:veth4 -eth4:veth6 -eth5:veth1 -eth6:veth3 -eth7:veth5 -eth8:veth7 diff --git a/openflow/regress/bin/veth_setup.pl b/openflow/regress/bin/veth_setup.pl deleted file mode 100755 index 11e746e8..00000000 --- a/openflow/regress/bin/veth_setup.pl +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/perl -w - -`/sbin/modprobe veth`; -for (my $i = 0; $i < 4; $i++) { - `/sbin/ip link add type veth`; -} - -for (my $i = 0; $i < 8; $i++) { - `sudo /sbin/ifconfig veth$i 192.168.1$i.1 netmask 255.255.255.0`; -} diff --git a/openflow/regress/bin/veth_teardown.pl b/openflow/regress/bin/veth_teardown.pl deleted file mode 100755 index ad103756..00000000 --- a/openflow/regress/bin/veth_teardown.pl +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/perl -w - -`/sbin/rmmod veth`; - diff --git a/openflow/regress/projects/black_box/regress/common/setup b/openflow/regress/projects/black_box/regress/common/setup deleted file mode 100755 index 8836cf7b..00000000 --- a/openflow/regress/projects/black_box/regress/common/setup +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use Test::TestLib; -use OF::OFUtil; - -my $mapFile; -my $platform; -my $args; - -# Process command line options -unless ( - GetOptions ( - "map=s" => \$mapFile, - "common-st-args=s" => \$platform, - ) -) -{ - print "invalid command format\n"; - exit(1); -} - -if (defined($mapFile)) { - $args = "--map=$mapFile"; -} - -if (!defined($platform)) { - print "no platform defined\n"; - exit(1); -} -else { - print "platform = $platform\n"; -} - -my $filename = "of_${platform}_setup.pl"; - -# exit if of_${platform}_setup.pl not in path -if (-e "$ENV{'OFT_ROOT'}/bin/$filename") { - #system("$filename " . $args . " 2> /dev/null > /dev/null"); - system("$ENV{'OFT_ROOT'}/bin/$filename " . $args ); - #setup_kmod(); - exit (0); -} else { - print "couldn't find setup file $filename\n"; - exit (1); -} diff --git a/openflow/regress/projects/black_box/regress/common/teardown b/openflow/regress/projects/black_box/regress/common/teardown deleted file mode 100755 index 6f1f8391..00000000 --- a/openflow/regress/projects/black_box/regress/common/teardown +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use Test::TestLib; -use OF::OFUtil; - -my $mapFile; -my $platform; -my $args; - -# Process command line options -unless ( - GetOptions ( - "map=s" => \$mapFile, - "common-st-args=s" => \$platform, - ) -) -{ - print "invalid command format\n"; - exit(1); -} - -if (defined($mapFile)) { - $args = "--map=$mapFile"; -} - -if (!defined($platform)) { - print "no platform defined\n"; - exit(1); -} -else { - print "platform = $platform\n"; -} - -my $filename = "of_${platform}_teardown.pl"; - -# exit if of_${platform}_setup.pl not in path -if (-e "$ENV{'OFT_ROOT'}/bin/$filename") { - #system("$filename " . $args . " 2> /dev/null > /dev/null"); - system("$ENV{'OFT_ROOT'}/bin/$filename " . $args ); - #teardown_kmod(); - exit (0); -} else { - print "couldn't find setup file $filename\n"; - exit (1); -} diff --git a/openflow/regress/projects/black_box/regress/test_add_flow_latency/run.pl b/openflow/regress/projects/black_box/regress/test_add_flow_latency/run.pl deleted file mode 100755 index 91ec09af..00000000 --- a/openflow/regress/projects/black_box/regress/test_add_flow_latency/run.pl +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/perl -w -# test_add_flow_latency - -use strict; -use OF::Includes; - -sub my_test { - - my ($sock) = @_; - - my $pkt_args = { - DA => "00:00:00:00:00:01", - SA => "00:00:00:00:00:02", - src_ip => "192.168.200.40", - dst_ip => "192.168.201.40", - ttl => 64, - len => 60 - }; - - my $test_pkt = new NF2::UDP_pkt(%$pkt_args); - - my $wildcards = 0x0; - my $in_port = 1; - my $out_port = 2; - my $max_idle = 0; - my $flags = 0x0; # don't send flow expiry - - my $flow_mod_pkt = create_flow_mod_from_udp($ofp,$test_pkt,$in_port,$out_port,$max_idle,$flags,$wildcards); - - print $sock $flow_mod_pkt; - usleep(1000000); - - - my $cnt = 0; - my $start_time = [gettimeofday()]; - for( $cnt = 0;$cnt < 1000; $cnt++){ - nftest_send( nftest_get_iface( "eth" . ($in_port+1)),$test_pkt->packed ); - nftest_expect( nftest_get_iface( "eth" . ($out_port+1)),$test_pkt->packed ); - } - my $time_elapse = tv_interval($start_time); - my $latency = $time_elapse*1000/1000; - print "Latency is $latency ms"; - - } - - -run_black_box_test( \&my_test); diff --git a/openflow/regress/projects/black_box/regress/test_barrier/run.pl b/openflow/regress/projects/black_box/regress/test_barrier/run.pl deleted file mode 100755 index 87b91153..00000000 --- a/openflow/regress/projects/black_box/regress/test_barrier/run.pl +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/perl -w -# test_barrier - -use strict; -use OF::Includes; - -sub my_test { - my ($sock, $options_ref) = @_; - - if ( not defined( $$options_ref{'no_barrier'} ) ) { - my $in_port = $$options_ref{'port_base'}; - my $out_port = $in_port + 1; - - # RUOK? - send_get_config_request($ofp, $sock, 0xdeadbeef); - wait_for_get_config_reply($ofp, $sock, 0xdeadbeef); - - my $base_packet = get_default_black_box_pkt($in_port, $out_port); - - my $wildcards = 0x0000; - my $flags = $enums{'OFPFF_CHECK_OVERLAP'}; - my $max_idle = 0x0; - my $packet = create_flow_mod_from_udp($ofp, $base_packet, $in_port, $out_port, $max_idle, $flags, $wildcards); - - # FOO - print $sock $packet; - - my $wildcards = 0x03fe; - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; - my $packet = create_flow_mod_from_udp($ofp, $base_packet, $in_port, $out_port, $max_idle, $flags, $wildcards); - - # BAR - print $sock $packet; - - my $wildcards = 0x03fd; - my $flags = 0x0000; - my $packet = create_flow_mod_from_udp($ofp, $base_packet, $in_port, $out_port, $max_idle, $flags, $wildcards); - - # BAZ - print $sock $packet; - - # SYNC - enter_barrier($ofp, $sock, 0x12345678); - wait_for_barrier_exit($ofp, $sock, 0x12345678); - - # RUOK? - send_get_config_request($ofp, $sock, 0xcafe2009); - wait_for_get_config_reply($ofp, $sock, 0xcafe2009); - } -} - -run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_cookie_flow_expired/run.pl b/openflow/regress/projects/black_box/regress/test_cookie_flow_expired/run.pl deleted file mode 100755 index 5a300ad9..00000000 --- a/openflow/regress/projects/black_box/regress/test_cookie_flow_expired/run.pl +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/perl -w -# test_flow_expired - -use strict; -use OF::Includes; - -sub my_test { - - my ($sock, $options_ref) = @_; - - my $in_port = $$options_ref{'port_base'}; - my $out_port = $in_port + 1; - - my $test_pkt = get_default_black_box_pkt( $in_port, $out_port); - - my $max_idle = 0x1; # second before flow expiration - my $wildcards = 0x0; # exact match - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry - my $cookie = 0x123456; - # Create a flow mod with a flow cookie - my $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, - $max_idle, $flags, $wildcards, undef, undef, undef, - undef, $cookie ); - - #print HexDump($pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - - my $pkt_len = 0; - my $pkt_total = 0; - wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, - $pkt_total, undef, $cookie ); - -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_cookie_flow_stats/run.pl b/openflow/regress/projects/black_box/regress/test_cookie_flow_stats/run.pl deleted file mode 100755 index 705146b1..00000000 --- a/openflow/regress/projects/black_box/regress/test_cookie_flow_stats/run.pl +++ /dev/null @@ -1,151 +0,0 @@ -#!/usr/bin/perl -w -# test_flow_stats - -use strict; -use OF::Includes; - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - my $port_base = $$options_ref{'port_base'}; - - my $cookie = 0x123456; - - my $hdr_args = { - version => get_of_ver(), - type => $enums{'OFPT_STATS_REQUEST'}, - length => $ofp->sizeof('ofp_stats_request') + - $ofp->sizeof('ofp_flow_stats_request'), - # should generate automatically! - xid => 0x00000000 - }; - - my $match_args = { - wildcards => 0x2003ef, - in_port => 0, - dl_src => [], - dl_dst => [], - dl_vlan => 0, - dl_type => 0x800, - nw_tos => 0, - nw_src => (NF2::IP_hdr::getIP('192.168.200.1'))[0], - nw_dst => (NF2::IP_hdr::getIP('192.168.201.2'))[0], - nw_proto => 0, - tp_src => 0, - tp_dst => 0 - }; - - my $stats_request_args = { - header => $hdr_args, - type => $enums{'OFPST_FLOW'}, - flags => 0 - }; - - my $body_args = { - match => $match_args, - table_id => 0xff, #match all tables - out_port => $enums{'OFPP_NONE'}, - }; - - my $body = $ofp->pack('ofp_flow_stats_request', $body_args ); - - my $stats_request = $ofp->pack( 'ofp_stats_request', $stats_request_args ); - - my $mesg = $stats_request . $body; - - # Send 'stats_request' message - print $sock $mesg; - - # Should add timeout here - will crash if no reply - my $recvd_mesg; - sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; - - # Inspect message - my $msg_size = length($recvd_mesg); - - my $msg = $ofp->unpack( 'ofp_stats_reply', $recvd_mesg ); - - #print HexDump ($recvd_mesg); - print Dumper($msg); - - # Verify fields - verify_header( $msg, 'OFPT_STATS_REPLY', $msg_size ); - - #---------------------- - - # add flow mod, send pkt - { - - my $in_port_offset = 0; - my $out_port_offset = 1; - my $wildcards = 0x2003ef, - my $wait = 5; - - #$$options_ref{'send_delay'} = 5; - - forward_simple ( $ofp, $sock, $options_ref, $in_port_offset, - $out_port_offset, $wildcards, 'any', 1, undef, undef, $cookie); - -# my $in_port = $in_port_offset + $$options_ref{'port_base'}; -# my $out_port = $out_port_offset + $$options_ref{'port_base'}; -# -# my $test_pkt = get_default_black_box_pkt_len( $in_port, $out_port, $$options_ref{'pkt_len'} ); -# my $flow_mod_pkt = -# create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $wait, $wildcards ); -# -# print $sock $flow_mod_pkt; -# -# # Give OF switch time to process the flow mod -# usleep($$options_ref{'send_delay'}); -# -# nftest_send( "eth" . ($in_port_offset + 1), $test_pkt->packed ); - } - - sleep .1; - - - # Send 'stats_request' message - print $sock $mesg; - - # Should add timeout here - will crash if no reply - my $recvd_mesg; - sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; - - # Inspect message - my $msg_size = length($recvd_mesg); - - my $msg = $ofp->unpack( 'ofp_stats_reply', $recvd_mesg ); - - # Strip off the header from the received message - $recvd_mesg = substr($recvd_mesg, $ofp->sizeof('ofp_stats_reply')); - - # Unpack each of the ofp_flow_stats messages - my $flow_stats_len = $ofp->sizeof('ofp_flow_stats'); - while (length($recvd_mesg) > 0) { - if (length($recvd_mesg) < $flow_stats_len) {\ - die "Error: Partial flow stats message received"; - } - my $flow_stats = $ofp->unpack('ofp_flow_stats', $recvd_mesg); - - push @{$msg->{'body'}}, $flow_stats; - $recvd_mesg = substr($recvd_mesg, $flow_stats->{'length'}); - } - - #print HexDump ($recvd_mesg); - print Dumper($msg); - - # Verify fields - verify_header( $msg, 'OFPT_STATS_REPLY', $msg_size ); - - # Verify the cookie - compare( "stats_reply cookie", $msg->{'body'}->[0]->{'cookie'}, '==', $cookie ); - - - #wait_for_flow_expired_all( $ofp, $sock, $options_ref ); - - -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_delete/run.pl b/openflow/regress/projects/black_box/regress/test_delete/run.pl deleted file mode 100755 index 7b594682..00000000 --- a/openflow/regress/projects/black_box/regress/test_delete/run.pl +++ /dev/null @@ -1,172 +0,0 @@ -#!/usr/bin/perl -w -# test_delete - -use strict; -use OF::Includes; - -sub send_expect_exact_with_wildcard { - - my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $out_port2_offset, $max_idle, $pkt_len ) = @_; - - my $in_port = $in_port_offset + $$options_ref{'port_base'}; - my $out_port = $out_port_offset + $$options_ref{'port_base'}; - my $out_port2 = $out_port2_offset + $$options_ref{'port_base'}; - - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - src_port => 70, - dst_port => 80 - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - my $test_pkt_args2 = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - src_port => 170, - dst_port => 180 - }; - my $test_pkt2 = new NF2::UDP_pkt(%$test_pkt_args2); - - # Flow entry -- exact match, $out_port - my $wildcards = 0x0; # exact match - my $flags = 0x0; # don't send flow expiry - my $flow_mod_exact_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); - - # 2nd flow entry -- wildcard match, $out_port2 - $wildcards = $enums{'OFPFW_TP_SRC'} | $enums{'OFPFW_TP_DST'}; # wildcard match (don't care udp src/dst ports) - print "wildcards = $wildcards\n"; - my $flow_mod_wildcard_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port2, $max_idle, $flags, $wildcards ); - - #print HexDump($flow_mod_exact_pkt); - #print HexDump($flow_mod_wildcard_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_exact_pkt; - print "sent flow_mod message (create exact match entry)\n"; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - - print $sock $flow_mod_wildcard_pkt; - print "sent flow_mod message (create wildcard entry)\n"; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - - # Check what's on the switch - #dpctl_show_flows($options_ref); - - # Send a packet - ensure packet comes out desired port - print "Verify packets are forwarded correctly\n"; - nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt->packed ); - nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); - - nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt2->packed ); - nftest_expect( "eth" . ( $out_port2_offset + 1 ), $test_pkt2->packed ); - - print "sent two packets\n"; -} - -sub delete_send_expect { - - my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $out_port2_offset, $max_idle, $pkt_len ) = @_; - - my $in_port = $in_port_offset + $$options_ref{'port_base'}; - my $out_port = $out_port_offset + $$options_ref{'port_base'}; - my $out_port2 = $out_port2_offset + $$options_ref{'port_base'}; - - # in_port refers to the flow mod entry's input - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - src_port => 70, - dst_port => 80 - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - my $test_pkt_args2 = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - src_port => 170, - dst_port => 180 - }; - my $test_pkt2 = new NF2::UDP_pkt(%$test_pkt_args2); - - my $wildcards = $enums{'OFPFW_TP_SRC'} | $enums{'OFPFW_TP_DST'}; # wildcard match (don't care udp src/dst ports) - my $flags = 0x0; # don't send flow expiry - my $flow_mod_wildcard_pkt = - create_flow_mod_from_udp_action( $ofp, $test_pkt2, $in_port, $out_port2, $max_idle, - $flags, $wildcards, "OFPFC_DELETE" ); - - #print HexDump($flow_mod_exact_pkt); - #print HexDump($flow_mod_wildcard_pkt); - - # Send 'flow_mod' message (delete wildcard entry without STRICT) - print $sock $flow_mod_wildcard_pkt; - print "sent flow_mod message (delete wildcard entry)\n"; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - # Give extra time, wildcard delete takes more time - Jean II - usleep($$options_ref{'send_delay'}); - - # Check what's on the switch - #dpctl_show_flows($options_ref); - - # Send a packet - print "Verify packets are forwarded correctly i.e., fwded to contoller\n"; - nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt->packed ); - nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt2->packed ); - - # both pkts should go to the controller - wait_for_one_packet_in( $ofp, $sock, $pkt_len, $test_pkt->packed ); - wait_for_one_packet_in( $ofp, $sock, $pkt_len, $test_pkt2->packed ); - -} - -sub test_delete { - - my ( $ofp, $sock, $options_ref, $i, $j, $o_port2, $wildcards ) = @_; - - my $max_idle = $$options_ref{'max_idle'}; - my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_total = $$options_ref{'pkt_total'}; - - print "sending from $i to $j & $i to $o_port2 -- both should match\n"; - send_expect_exact_with_wildcard( $ofp, $sock, $options_ref, $i, $j, $o_port2, $max_idle, $pkt_len ); - - # wait for switch to process last packets - usleep($$options_ref{'send_delay'}); - - print "delete wildcard entry (without STRICT) and send packets again\n"; - delete_send_expect( $ofp, $sock, $options_ref, $i, $j, $o_port2, $max_idle, $pkt_len ); -} - -sub my_test { - - my ($sock, $options_ref) = @_; - - # send from every port to every other port - for_all_port_triplets( $ofp, $sock, $options_ref, \&test_delete, 0x0); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_delete_send_flow_exp/run.pl b/openflow/regress/projects/black_box/regress/test_delete_send_flow_exp/run.pl deleted file mode 100755 index 6e093fcc..00000000 --- a/openflow/regress/projects/black_box/regress/test_delete_send_flow_exp/run.pl +++ /dev/null @@ -1,104 +0,0 @@ -#!/usr/bin/perl -w -# test_delete - -use strict; -use OF::Includes; - -sub my_test { - - my ($sock, $options_ref) = @_; - - my $in_port = $$options_ref{'port_base'}; - my $out_port = $in_port + 1; - - my $test_pkt = get_default_black_box_pkt( $in_port, $out_port, $$options_ref{'pkt_len'} ); - - my $max_idle = 0x0; # second before flow expiration -- never time out - my $wildcards = 0x0; # exact match - # Create a flow mod without expiry - my $flags = 0x0; # don't send flow expiry - my $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); - print "send flow mode without expiry\n"; - print $sock $flow_mod_pkt; - - # Delete the flow and verify that we don't see an expiry - $flow_mod_pkt = - create_flow_mod_from_udp_action( $ofp, $test_pkt, $in_port, $out_port, $max_idle, - $flags, $wildcards, "OFPFC_DELETE" ); - print $sock $flow_mod_pkt; - - my $sel = IO::Select->new($sock); - if ($sel->can_read(2)) { - print "Error: was not expecting a message from the switch\n"; - exit 1; - } - - # Create a flow mod with expiry - $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry - $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); - print "send flow mode with expiry\n"; - print $sock $flow_mod_pkt; - - # Delete the flow and verify that we do see an expiry - $flags = 0x0; # Reset the flags to zero. Should not matter as it - # should only depend on the flags when the flow was installed. - $flow_mod_pkt = - create_flow_mod_from_udp_action( $ofp, $test_pkt, $in_port, $out_port, $max_idle, - $flags, $wildcards, "OFPFC_DELETE" ); - print $sock $flow_mod_pkt; - - my $pkt_len = 0; - my $pkt_total = 0; - wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); - - # Redo the same test with a few packets to make sure stats are correct - # Jean II - - # Create a flow mod with expiry - $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry - $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); - print "send flow mode with expiry and with 3 packets\n"; - print $sock $flow_mod_pkt; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - usleep($$options_ref{'send_delay'}); - - # Send 3 packets, because first packet can be "special" - Jean II - # We should be using $options{'pkt_total'}, but that is stuck at 1 - nftest_send("eth" . ($in_port), $test_pkt->packed); - nftest_send("eth" . ($in_port), $test_pkt->packed); - nftest_send("eth" . ($in_port), $test_pkt->packed); - - # expect 3 packets - print "expect 3 packets\n"; - nftest_expect("eth" . ($out_port), $test_pkt->packed); - nftest_expect("eth" . ($out_port), $test_pkt->packed); - nftest_expect("eth" . ($out_port), $test_pkt->packed); - - # Wait for stats to refresh - sleep($$options_ref{'max_idle'}); - #dpctl_show_flows($options_ref); - - # Delete the flow and verify that we do see an expiry - $flags = 0x0; # Reset the flags to zero. Should not matter as it - # should only depend on the flags when the flow was installed. - $flow_mod_pkt = - create_flow_mod_from_udp_action( $ofp, $test_pkt, $in_port, $out_port, $max_idle, - $flags, $wildcards, "OFPFC_DELETE" ); - print $sock $flow_mod_pkt; - - # And now check the stats in the flow removed message... - my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_total = 3; - wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); - - - -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_delete_strict/run.pl b/openflow/regress/projects/black_box/regress/test_delete_strict/run.pl deleted file mode 100755 index 8290dae9..00000000 --- a/openflow/regress/projects/black_box/regress/test_delete_strict/run.pl +++ /dev/null @@ -1,175 +0,0 @@ -#!/usr/bin/perl -w -# test_delete_strict - -use strict; -use OF::Includes; - -sub send_expect_exact_with_wildcard { - - my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $out_port2_offset, $max_idle, $pkt_len ) = @_; - - my $in_port = $in_port_offset + $$options_ref{'port_base'}; - my $out_port = $out_port_offset + $$options_ref{'port_base'}; - my $out_port2 = $out_port2_offset + $$options_ref{'port_base'}; - - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - src_port => 70, - dst_port => 80 - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - my $test_pkt_args2 = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - src_port => 170, - dst_port => 180 - }; - my $test_pkt2 = new NF2::UDP_pkt(%$test_pkt_args2); - - # Flow entry -- exact match, $out_port - my $wildcards = 0x0; # exact match - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; - my $flow_mod_exact_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); - - # 2nd flow entry -- wildcard match, $out_port2 - $wildcards = $enums{'OFPFW_TP_SRC'} | $enums{'OFPFW_TP_DST'}; # wildcard match (don't care udp src/dst ports) - my $flow_mod_wildcard_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port2, $max_idle, $flags, $wildcards ); - - #print HexDump($flow_mod_exact_pkt); - #print HexDump($flow_mod_wildcard_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_exact_pkt; - print "sent flow_mod message (create exact match entry)\n"; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - - print $sock $flow_mod_wildcard_pkt; - print "sent flow_mod message (create wildcard entry)\n"; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - - # Check what's on the switch - #dpctl_show_flows($options_ref); - - # Send a packet - ensure packet comes out desired port - print "Verify packets are forwarded correctly\n"; - nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt->packed ); - nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); - - nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt2->packed ); - nftest_expect( "eth" . ( $out_port2_offset + 1 ), $test_pkt2->packed ); -} - -sub delete_strict_send_expect { - - my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $out_port2_offset, $max_idle, $pkt_len ) = @_; - - my $in_port = $in_port_offset + $$options_ref{'port_base'}; - my $out_port = $out_port_offset + $$options_ref{'port_base'}; - my $out_port2 = $out_port2_offset + $$options_ref{'port_base'}; - - # in_port refers to the flow mod entry's input - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - src_port => 70, - dst_port => 80 - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - my $test_pkt_args2 = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - src_port => 170, - dst_port => 180 - }; - my $test_pkt2 = new NF2::UDP_pkt(%$test_pkt_args2); - - my $wildcards = $enums{'OFPFW_TP_SRC'} | $enums{'OFPFW_TP_DST'}; # wildcard match (don't care udp src/dst ports) - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; - my $flow_mod_wildcard_pkt = - - # delete_strict_from_udp( $ofp, $test_pkt, $in_port, $out_port2, $wildcards ); - create_flow_mod_from_udp_action( $ofp, $test_pkt, $in_port, $out_port2, $max_idle, $flags, $wildcards, - 'OFPFC_DELETE_STRICT' ); - - #print HexDump($flow_mod_exact_pkt); - #print HexDump($flow_mod_wildcard_pkt); - - # Send 'flow_mod' message (delete wildcard entry with STRICT) - print $sock $flow_mod_wildcard_pkt; - print "sent flow_mod message (delete (strict) wildcard entry)\n"; - - # Expect a flow expire due to the delete - wait_for_flow_expired_readone( $ofp, $sock, $options_ref, $pkt_len, 1 ); - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - # Give extra time, delete takes more time - Jean II - usleep($$options_ref{'send_delay'}); - - # Check what's on the switch - #dpctl_show_flows($options_ref); - - # Send a packet - print - "Verify packets are forwarded correctly i.e., one fwded to contoller and one (exact match) fwd to the specified port\n"; - nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt->packed ); - nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); - - nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt2->packed ); - wait_for_one_packet_in( $ofp, $sock, $pkt_len, $test_pkt2->packed ); -} - -sub test_delete_strict { - - my ( $ofp, $sock, $options_ref, $i, $j, $o_port2, $wildcards ) = @_; - - my $max_idle = $$options_ref{'max_idle'}; - my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_total = $$options_ref{'pkt_total'}; - - print "sending from $i to $j & $i to $o_port2 -- both should match\n"; - send_expect_exact_with_wildcard( $ofp, $sock, $options_ref, $i, $j, $o_port2, $max_idle, $pkt_len ); - - # wait for switch to process last packets - usleep($$options_ref{'send_delay'}); - - print "delete wildcard entry (with STRICT) \n"; - print "sending from $i to $j & $i to $o_port2 "; - delete_strict_send_expect( $ofp, $sock, $options_ref, $i, $j, $o_port2, $max_idle, $pkt_len ); - wait_for_flow_expired_readone( $ofp, $sock, $options_ref, $pkt_len, 2 ); -} - -sub my_test { - - my ($sock, $options_ref) = @_; - - # send from every port to every other port - for_all_port_triplets( $ofp, $sock, $options_ref, \&test_delete_strict, 0x0); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_drop_exact/run.pl b/openflow/regress/projects/black_box/regress/test_drop_exact/run.pl deleted file mode 100755 index 98180d18..00000000 --- a/openflow/regress/projects/black_box/regress/test_drop_exact/run.pl +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/perl -w -# test_drop_exact - -use strict; -use OF::Includes; - -#sub drop_simple { -# -# my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $wildcards, $nowait ) = @_; -# -# my $in_port = $in_port_offset + $$options_ref{'port_base'}; -# my $out_port = $out_port_offset + $$options_ref{'port_base'}; -# # print "drop_simple : ports = ".($in_port).",".($out_port); -# -# my $test_pkt = get_default_black_box_pkt_len( $in_port, $out_port, $$options_ref{'pkt_len'} ); -# -# #print HexDump ( $test_pkt->packed ); -# -# my $flow_mod_pkt = -# create_flow_drop_from_udp_action( $ofp, $test_pkt, $in_port, $out_port, $$options_ref{'max_idle'}, $wildcards, 'drop' ); -# -# #print HexDump($flow_mod_pkt); -# #print Dumper($flow_mod_pkt); -# -# # Send 'flow_mod' message -# syswrite( $sock, $flow_mod_pkt ); -# print "sent flow_mod message\n"; -# -# # Give OF switch time to process the flow mod -# usleep($$options_ref{'send_delay'}); -# -# nftest_send( "eth" . ($in_port_offset + 1), $test_pkt->packed); -# -# # We should expect no message at all on any port ! - Jean II -# -# if (not defined($nowait)) { -# print "wait \n"; -# wait_for_flow_expired_all( $ofp, $sock, $options_ref ); -# } -#} - -sub drop_port { - - forward_simple(@_, 'drop'); -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_port_pairs( $ofp, $sock, $options_ref, \&drop_port, 0x0); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_failover_close/run.pl b/openflow/regress/projects/black_box/regress/test_failover_close/run.pl deleted file mode 100755 index 06fd9a71..00000000 --- a/openflow/regress/projects/black_box/regress/test_failover_close/run.pl +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/perl -w - -# Simple two-controller failover test -# -# For this test to work, the switch must be set up to use our -# two "controllers", e.g. -# -# ofprotocol --controller=tcp:127.0.0.1:6633,tcp:127.0.0.1:6634 -# -# If you use different ports than the defaults, then you must -# pass the --controller option into this script as well. -# -# Failover test 2: Controller is fine, but closes connection -# -# For this test, we accept the Hello sequence and then close -# the socket. Then we listen for a failover connection on the -# second socket. -# - -use strict; -use OF::Includes; - -# Save ARGV for future reference -my @ARGS = @ARGV; - -my $test = "Failover test 2 (connection closed)"; - -print "$test phase 1: calling run_black_box_test with @ARGV\n"; - -# Start up, say Hello, and close connection -sub close_failover_test_phase_1 { - my ($sock) = @_; - print "$test: Got socket $sock\n"; - print "$test: Finished Hello sequence on first controller\n"; - print "$test: Closing socket\n"; - $sock->close(); -} - -run_black_box_test( \&close_failover_test_phase_1, \@ARGV, 1); # 1 -> don't exit - -# Now, attempt to open up the second controller connection, and -# hope that we fail over - -# Restore ARGV -@ARGV = @ARGS; - -# If no controllers specified, use default -if (not "@ARGV" =~ "--controller") { - push( @ARGV, "--controller=" . nftest_default_controllers() ); -} - -# Replace --controller=foo,bar with --controller=bar so that -# run_black_box_test() will use bar's port rather than foo's -for (my $i = 0; $i < @ARGV; $i++) { - if ($ARGV[$i] =~ /controller=[^,]*,([^\s]+)/ ) { - print "failover_startup: got controller $1\n"; - $ARGV[$i] = "--controller=$1"; - } -} - - -sub close_failover_test_phase_2 { - print "$test: Failover to second controller succeeded\n"; -} - -print "$test: Calling run_black_box_test with @ARGV\n"; -run_black_box_test( \&close_failover_test_phase_2, \@ARGV ); # do exit this time - diff --git a/openflow/regress/projects/black_box/regress/test_failover_startup/run.pl b/openflow/regress/projects/black_box/regress/test_failover_startup/run.pl deleted file mode 100755 index 7bfee7aa..00000000 --- a/openflow/regress/projects/black_box/regress/test_failover_startup/run.pl +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/perl - -# Simple two-controller failover test -# -# For this test to work, the switch must be set up to use our -# two "controllers", e.g. -# -# ofprotocol --controller=tcp:127.0.0.1:6633,tcp:127.0.0.1:6634 -# -# If you use different ports than the defaults, then you must -# pass the --controller option into this script as well. -# -# Failover Test 1: Startup Failover -# -# For this test, we listen on the second controller port rather -# than the first. -# - -use strict; -use OF::Includes; -use Getopt::Long; - -my $test="Failover test 1 (startup failover)"; - -my $controllers; - -# Remove '--controller' from the option list... - Jean II -Getopt::Long::Configure( 'pass_through' ); -GetOptions( - "controller=s" => \$controllers -); -if (!defined($controllers)) -{ - # If no controllers specified, use default - $controllers = nftest_default_controllers(); -} -Getopt::Long::Configure( 'default' ); - -# Get controller -my @controller_array = split(/,/, $controllers); -my $failover_controller = @controller_array[1]; - -# Push back a controller string -push( @ARGV, "--controller=$failover_controller" ); - -print "$test: Calling run_black_box_test with @ARGV\n"; - -sub startup_failover_test { - print "$test: Failed over successfully\n"; -} - -run_black_box_test( \&startup_failover_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_failover_stop_responding/run.pl b/openflow/regress/projects/black_box/regress/test_failover_stop_responding/run.pl deleted file mode 100755 index 50a4a475..00000000 --- a/openflow/regress/projects/black_box/regress/test_failover_stop_responding/run.pl +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/perl -w - -# Simple two-controller failover test -# -# For this test to work, the switch must be set up to use our -# two "controllers", e.g. -# -# ofprotocol --controller=tcp:127.0.0.1:6633,tcp:127.0.0.1:6634 -# -# If you use different ports than the defaults, then you must -# pass the --controller option into this script as well. -# -# Failover test 3: Controller is fine, but stops responding -# -# For this test, we accept the Hello sequence on the first port -# but then listen for a failover connection on the second port. -# - -use strict; -use OF::Includes; - -# Save ARGV for future reference -my @ARGS = @ARGV; - -my $test="Failover test 3 (controller stops responding)"; - -print "$test phase 1: calling run_black_box_test with @ARGV\n"; - -# Start up, say Hello, and close connection -sub stop_responding_test_phase_1 { - my ($sock) = @_; - print "$test: Got socket $sock\n"; - print "$test: Finished Hello sequence on first controller\n"; - print "$test: Not closing socket\n"; - print "$test: Invoking phase 2\n"; - stop_responding_phase_2(); -} - -run_black_box_test( \&stop_responding_test_phase_1, \@ARGV, 1); # 1 -> don't exit - -sub stop_responding_phase_2 { - - # Now, attempt to open up the second controller connection, and - # hope that we fail over - - # Restore ARGV - @ARGV = @ARGS; - - # If no controllers specified, use default - if (not "@ARGV" =~ "--controller") { - push( @ARGV, "--controller=" . nftest_default_controllers() ); - } - - # Replace --controller=foo,bar with --controller=bar so that - # run_black_box_test() will use bar's port rather than foo's - for (my $i = 0; $i < @ARGV; $i++) { - if ($ARGV[$i] =~ /controller=[^,]*,([^\s]+)/ ) { - print "$test: got controller $1\n"; - $ARGV[$i] = "--controller=$1"; - } - } - - print "$test: Calling run_black_box_test with @ARGV\n"; - run_black_box_test( \&close_failover_test_phase_2, \@ARGV ); # do exit this time -} diff --git a/openflow/regress/projects/black_box/regress/test_flow_expired/run.pl b/openflow/regress/projects/black_box/regress/test_flow_expired/run.pl deleted file mode 100755 index 97ea35cc..00000000 --- a/openflow/regress/projects/black_box/regress/test_flow_expired/run.pl +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/perl -w -# test_flow_expired - -use strict; -use OF::Includes; - -sub my_test { - - my ($sock, $options_ref) = @_; - - my $in_port = $$options_ref{'port_base'}; - my $out_port = $in_port + 1; - - my $test_pkt = get_default_black_box_pkt( $in_port, $out_port); - - my $max_idle = 0x1; # second before flow expiration - my $wildcards = 0x0; # exact match - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry - my $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); - - #print HexDump($pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - - my $pkt_len = 0; - my $pkt_total = 0; - wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); - -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_flow_expired_idle_timeout/run.pl b/openflow/regress/projects/black_box/regress/test_flow_expired_idle_timeout/run.pl deleted file mode 100755 index 5fa74924..00000000 --- a/openflow/regress/projects/black_box/regress/test_flow_expired_idle_timeout/run.pl +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/perl -w -# test_flow_expired - -use strict; -use OF::Includes; - -sub my_test { - - my ($sock, $options_ref) = @_; - - my $in_port = $$options_ref{'port_base'}; - my $out_port = $in_port + 1; - - my $test_pkt = get_default_black_box_pkt( $in_port, $out_port); - - my $max_idle = 0x1; # second before flow expiration - my $wildcards = 0x0; # exact match - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; - my $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); - - #print HexDump($pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - - my $pkt_len = 0; - my $pkt_total = 0; - wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total, $max_idle ); - -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_flow_expired_precision/run.pl b/openflow/regress/projects/black_box/regress/test_flow_expired_precision/run.pl deleted file mode 100755 index 798f6b89..00000000 --- a/openflow/regress/projects/black_box/regress/test_flow_expired_precision/run.pl +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/perl -w -# test_flow_expired -# This test checks if the flow duration time is in a reasonable range. -# This test assumes a reference switch as a target. -# The switch polls flow expiration every 1 sec with jitter, -# so we should expect 1sec difference for flow_duration. - -use strict; -use OF::Includes; - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - my $in_port = $$options_ref{'port_base'}; - my $out_port = $in_port + 1; - - my $test_pkt = get_default_black_box_pkt( $in_port, $out_port ); - - my $max_idle = 0x1; # second before flow expiration - my $wildcards = 0x0; # exact match - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry - my $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, - $flags, $wildcards ); - - #print HexDump($pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - - my $pkt_len = 0; - my $pkt_total = 0; - - my $read_size = 1512; - - my $recvd_mesg; - sysread( $sock, $recvd_mesg, $read_size ) - || die "Failed to receive ofp_flow_removed message: $!"; - - # Inspect message - my $msg_size = length($recvd_mesg); - my $expected_size = $ofp->sizeof('ofp_flow_removed'); - compare( "ofp_flow_removed msg size", - length($recvd_mesg), '==', $expected_size ); - - my $msg = $ofp->unpack( 'ofp_flow_removed', $recvd_mesg ); - - print Dumper($msg); - - my $sample_period = 1; - - compare( "ofp_flow_removed packet_count", - $$msg{'packet_count'}, '==', $pkt_total ); - print "Duretion_sec : $$msg{'duration_sec'} sec\n"; - print "Duration_nsec: $$msg{'duration_nsec'} nano sec\n"; - - if (($$msg{'duration_sec'} < $max_idle) - || ($$msg{'duration_sec'} > ($max_idle + $sample_period))) { - die "Error, duration_sec out of acceptable range"; - } - -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_flow_expired_send_flow_exp/run.pl b/openflow/regress/projects/black_box/regress/test_flow_expired_send_flow_exp/run.pl deleted file mode 100755 index 4a47caef..00000000 --- a/openflow/regress/projects/black_box/regress/test_flow_expired_send_flow_exp/run.pl +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/perl -w -# test_flow_expired - -use strict; -use OF::Includes; -use IO::Select; - -sub my_test { - - my ($sock, $options_ref) = @_; - - my $in_port = $$options_ref{'port_base'}; - my $out_port = $in_port + 1; - - my $test_pkt = get_default_black_box_pkt( $in_port, $out_port); - - my $max_idle = 0x1; # second before flow expiration - my $wildcards = 0x0; # exact match - # Create a flow mod without expiry - my $flags = 0x0; # don't send flow expiry - my $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); - print $sock $flow_mod_pkt; - - my $sel = IO::Select->new($sock); - if ($sel->can_read(2 * $max_idle)) { - print "Error: was not expecting a message from the switch\n"; - exit 1; - } - - # Create a flow mod with expiry - $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry - $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); - print $sock $flow_mod_pkt; - - my $pkt_len = 0; - my $pkt_total = 0; - wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); - -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_flow_mod_check/run.pl b/openflow/regress/projects/black_box/regress/test_flow_mod_check/run.pl deleted file mode 100755 index 1c0b7f76..00000000 --- a/openflow/regress/projects/black_box/regress/test_flow_mod_check/run.pl +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/perl -w -# test_flow_mod_check - -use strict; -use OF::Includes; - -sub wait_for_flow_overlap_error { - my ($ofp, $sock, $flow_mod_pkt) = @_; - my $rcvd_msg; - - sysread($sock, $rcvd_msg, 1512); - - my $msg_size = length($rcvd_msg); - my $expected_size = $ofp->sizeof('ofp_error_msg') + length($flow_mod_pkt); - compare("msg size", $msg_size, '==', $expected_size); - - my $msg = $ofp->unpack('ofp_error_msg', $rcvd_msg); - verify_header($msg, 'OFPT_ERROR', $msg_size); - - compare("error type", $$msg{'type'}, '==', $enums{'OFPET_FLOW_MOD_FAILED'}); - compare("error code", $$msg{'code'}, '==', $enums{'OFPFMFC_OVERLAP'}); -} - -sub my_test { - my ($sock, $options_ref) = @_; - - my $in_port = $$options_ref{'port_base'}; - my $out_port_1 = $in_port + 1; - my $out_port_2 = $in_port + 2; - my $out_port_3 = $in_port + 3; - - my $test_pkt = get_default_black_box_pkt($in_port, $out_port_1); - - - my $wildcards = 0x0c0; - my $flags = $enums{'OFPFF_CHECK_OVERLAP'}; - my $max_idle = 0x0; # never expire - my $flow_mod_pkt = create_flow_mod_from_udp($ofp, $test_pkt, $in_port, $out_port_1, $max_idle, $flags, $wildcards); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - - # change the wildcard and send again. this should fail - $wildcards = 0x0c1; - my $flags = $enums{'OFPFF_CHECK_OVERLAP'}; - $flow_mod_pkt = create_flow_mod_from_udp($ofp, $test_pkt, $in_port+1, $out_port_2, $max_idle, $flags, $wildcards); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - - wait_for_flow_overlap_error($ofp, $sock, $flow_mod_pkt); - - # Start with coarse granularity flow - # edge-case bug reported by Justin - # https://mailman.stanford.edu/pipermail/openflow-dev/2009-November/000529.html - $wildcards = 0x0c1; - $flags = 0x0; - $flow_mod_pkt = create_flow_mod_from_udp($ofp, $test_pkt, $in_port, $out_port_1, $max_idle, $flags, $wildcards); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - - # change the wildcard and send again. this should fail - $wildcards = 0x0c0; - $flags = $enums{'OFPFF_CHECK_OVERLAP'}; - $flow_mod_pkt = create_flow_mod_from_udp($ofp, $test_pkt, $in_port+1, $out_port_2, $max_idle, $flags, $wildcards); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - - wait_for_flow_overlap_error($ofp, $sock, $flow_mod_pkt); - - - -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_flow_mod_latency/run-port3.pl b/openflow/regress/projects/black_box/regress/test_flow_mod_latency/run-port3.pl deleted file mode 100644 index 204873b7..00000000 --- a/openflow/regress/projects/black_box/regress/test_flow_mod_latency/run-port3.pl +++ /dev/null @@ -1,136 +0,0 @@ -#!/usr/bin/perl -w -# test_flow_mod_latency -# -# Don't include this test as part of the official test suite, -# as it is not supposed to pass... -# -# Run it like this : -# ./bin/of_hp_test.pl --testPath=black_box/regress/test_flow_mod_latency/run.pl -# -# Check the number of packets received : -# tcpdump -p -i eth11 -w stanford.test.log -# tcpdump -r stanford.test.log | wc -# -# On the HP, it requires increasing the SW rate limiter : -# openflow 9 sw-rate 5000 -# -# Jean II - -use strict; -use OF::Includes; - -sub forward_flow_mod_latency { - - my ($sock, $options_ref) = @_; - my $in_port = $$options_ref{'port_base'}; - my $out_port = $in_port + 1; - my $fallback_port = $out_port + 1; - - my $len = $$options_ref{'pkt_len'}; - my $wildcards = 0x0; # exact match - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; - my $pkt_args; - my $test_pkt; - my $flow_mod_pkt; - my $i; - - if (1) { - # Create a flow mod to track all packets sent to the controller - # We create a wildcard on both transport port, that sends - # packets to the controller - Jean II - $pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $len, - src_port => 0, - dst_port => 0 - }; - $test_pkt = new NF2::UDP_pkt(%$pkt_args); - $wildcards = $enums{'OFPFW_TP_SRC'} | $enums{'OFPFW_TP_DST'}; - print"wildcards = $wildcards\n"; - # Full experiment is around 15s - $flow_mod_pkt = create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $fallback_port, 25, $flags, $wildcards ); - syswrite( $sock, $flow_mod_pkt ); - print "sent flow_mod message with wildcard\n"; - - # Make sure the flow mod is properly inserted and the - # OpenFlow instance properly started. The OpenFlow instance - # takes time to get started, we want to make sure this is - # not a factor. Jean II - sleep(1); - - # No more wildcards - $wildcards = 0x0; # exact match - } - - # Let's create 100 sequencial connections - Jean II - for ( my $c = 0 ; $c < 100 ; $c++ ) { - - # Packets for creating the flow mod - $pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $len, - src_port => 2000 + $c, - dst_port => 4000 + $c - }; - $test_pkt = new NF2::UDP_pkt(%$pkt_args); - - # Let's create a long lived flow mod - $flow_mod_pkt = create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, 20, $flags, $wildcards ); - - # Send 'flow_mod' message - syswrite( $sock, $flow_mod_pkt ); - print "sent flow_mod message for connection $c\n"; - - # Test packet to be sent - should match flow mod - $pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $len, - src_port => 2000 + $c, - dst_port => 4000 + $c - }; - $test_pkt = new NF2::UDP_pkt(%$pkt_args); - - # For this test, the TCAM is much slower. Wait a bit more - # to get more interesting results. I also increased pkt count. - # Jean II - usleep(20000); - - # Max in SW is around 5000 pkts/sec - # Note : default rate limiter value is 100 pkts/sec, which is - # one packet every 10s, so you can't run at default value - # Send 15 packets as a short burst over 60ms - for ($i = 0 ; $i < 15 ; $i++ ) { - - # Wait 4 ms between packets - usleep(4000); - - # Send test packet - nftest_send( "eth" . ($in_port), $test_pkt->packed ); - - # This does not block, so we are good... - nftest_expect( "eth" . ($out_port), $test_pkt->packed ); - } - - # We don't wait for flow expiry, that's too long waiting - Jean II - } - - # Wait for stats to refresh - # For most flow mod, we should be about half life, which means - # they have not expired yet, and have already got stats a few time. - sleep(6); - dpctl_show_flows($options_ref); -} - -run_black_box_test( \&forward_flow_mod_latency, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_flow_mod_latency/run.pl b/openflow/regress/projects/black_box/regress/test_flow_mod_latency/run.pl deleted file mode 100755 index 49789383..00000000 --- a/openflow/regress/projects/black_box/regress/test_flow_mod_latency/run.pl +++ /dev/null @@ -1,129 +0,0 @@ -#!/usr/bin/perl -w -# test_flow_mod_latency -# -# Don't include this test as part of the official test suite, -# as it is not supposed to pass... -# -# Run it like this : -# ./bin/of_hp_test.pl --testPath=black_box/regress/test_flow_mod_latency/run.pl -# -# Check the number of packets received : -# tcpdump -p -i eth11 -w stanford.test.log -# tcpdump -r stanford.test.log | wc -# -# On the HP, it requires increasing the SW rate limiter : -# openflow 9 sw-rate 5000 -# -# Jean II - -use strict; -use OF::Includes; - -sub forward_flow_mod_latency { - - my ($sock, $options_ref) = @_; - my $in_port = $$options_ref{'port_base'}; - my $out_port = $in_port + 1; - - my $len = $$options_ref{'pkt_len'}; - my $wildcards = 0x0; # exact match - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; - my $pkt_args; - my $test_pkt; - my $flow_mod_pkt; - my $i; - - if (1) { - # Create a flow mod to track all packets sent to the controller - # We create a wildcard on both transport port, that sends - # packets to the controller - Jean II - $pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $len, - src_port => 0, - dst_port => 0 - }; - $test_pkt = new NF2::UDP_pkt(%$pkt_args); - $wildcards = $enums{'OFPFW_TP_SRC'} | $enums{'OFPFW_TP_DST'}; - print"wildcards = $wildcards\n"; - $flow_mod_pkt = create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $enums{'OFPP_CONTROLLER'}, 20, $flags, $wildcards ); - syswrite( $sock, $flow_mod_pkt ); - print "sent flow_mod message with wildcard\n"; - - # Make sure the flow mod is properly inserted and the - # OpenFlow instance properly started. The OpenFlow instance - # takes time to get started, we want to make sure this is - # not a factor. Jean II - sleep(1); - - # No more wildcards - $wildcards = 0x0; # exact match - } - - # Let's create 100 sequencial connections - Jean II - for ( my $c = 0 ; $c < 100 ; $c++ ) { - - # Packets for creating the flow mod - $pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $len, - src_port => 2000 + $c, - dst_port => 4000 + $c - }; - $test_pkt = new NF2::UDP_pkt(%$pkt_args); - - # Let's create a long lived flow mod - $flow_mod_pkt = create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, 15, $flags, $wildcards ); - - # Send 'flow_mod' message - syswrite( $sock, $flow_mod_pkt ); - print "sent flow_mod message for connection $c\n"; - - # Test packet to be sent - should match flow mod - $pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $len, - src_port => 2000 + $c, - dst_port => 4000 + $c - }; - $test_pkt = new NF2::UDP_pkt(%$pkt_args); - - # Max in SW is around 5000 pkts/sec - # Note : default rate limiter value is 100 pkts/sec, which is - # one packet every 10s, so you can't run at default value - # Send 5 packets as a short burst over 20ms - for ($i = 0 ; $i < 5 ; $i++ ) { - - # Wait 4 ms between packets - usleep(4000); - - # Send test packet - nftest_send( "eth" . ($in_port), $test_pkt->packed ); - - # This does not block, so we are good... - nftest_expect( "eth" . ($out_port), $test_pkt->packed ); - } - - # We don't wait for flow expiry, that's too long waiting - Jean II - } - - # Wait for stats to refresh - # For most flow mod, we should be about half life, which means - # they have not expired yet, and have already got stats a few time. - sleep(6); - dpctl_show_flows($options_ref); -} - -run_black_box_test( \&forward_flow_mod_latency, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_flow_stats/run.pl b/openflow/regress/projects/black_box/regress/test_flow_stats/run.pl deleted file mode 100755 index eeea50a6..00000000 --- a/openflow/regress/projects/black_box/regress/test_flow_stats/run.pl +++ /dev/null @@ -1,145 +0,0 @@ -#!/usr/bin/perl -w -# test_flow_stats - -use strict; -use OF::Includes; - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - my $port_base = $$options_ref{'port_base'}; - - my $hdr_args = { - version => get_of_ver(), - type => $enums{'OFPT_STATS_REQUEST'}, - length => $ofp->sizeof('ofp_stats_request') + $ofp->sizeof('ofp_flow_stats_request'), # should generate automatically! - xid => 0x00000000 - }; - - my $match_args = { - wildcards => 0x3ef, - in_port => 0, - dl_src => [], - dl_dst => [], - dl_vlan => 0, - dl_type => 0x800, - nw_src => (NF2::IP_hdr::getIP('192.168.200.1'))[0], - nw_dst => (NF2::IP_hdr::getIP('192.168.201.2'))[0], - nw_proto => 0, - tp_src => 0, - tp_dst => 0 - }; - - my $stats_request_args = { - header => $hdr_args, - type => $enums{'OFPST_FLOW'}, - flags => 0 - }; - - my $body_args = { - match => $match_args, - table_id => 0xff, #match all tables - out_port => $enums{'OFPP_NONE'}, - }; - - my $body = $ofp->pack('ofp_flow_stats_request', $body_args ); - - my $stats_request = $ofp->pack( 'ofp_stats_request', $stats_request_args ); - - my $mesg = $stats_request . $body; - - # Send 'stats_request' message - print $sock $mesg; - - # Should add timeout here - will crash if no reply - my $recvd_mesg; - sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; - - # Inspect message - my $msg_size = length($recvd_mesg); - - my $msg = $ofp->unpack( 'ofp_stats_reply', $recvd_mesg ); - - #print HexDump ($recvd_mesg); - print Dumper($msg); - - # Verify fields - verify_header( $msg, 'OFPT_STATS_REPLY', $msg_size ); - - #---------------------- - - # add flow mod, send pkt - { - - my $in_port_offset = 0; - my $out_port_offset = 1; - my $wildcards = 0x3ef; - my $wait = 5; - - #$$options_ref{'send_delay'} = 5; - - forward_simple ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $wildcards, 'any', 1); - -# my $in_port = $in_port_offset + $$options_ref{'port_base'}; -# my $out_port = $out_port_offset + $$options_ref{'port_base'}; -# -# my $test_pkt = get_default_black_box_pkt_len( $in_port, $out_port, $$options_ref{'pkt_len'} ); -# my $flow_mod_pkt = -# create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $wait, $wildcards ); -# -# print $sock $flow_mod_pkt; -# -# # Give OF switch time to process the flow mod -# usleep($$options_ref{'send_delay'}); -# -# nftest_send( "eth" . ($in_port_offset + 1), $test_pkt->packed ); - } - - sleep .1; - - - # Send 'stats_request' message - print $sock $mesg; - - # Should add timeout here - will crash if no reply - my $recvd_mesg; - sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; - - # Inspect message - my $msg_size = length($recvd_mesg); - - my $msg = $ofp->unpack( 'ofp_stats_reply', $recvd_mesg ); - - # Strip off the header from the received message - $recvd_mesg = substr($recvd_mesg, $ofp->sizeof('ofp_stats_reply')); - - # Unpack each of the ofp_flow_stats messages - my $flow_stats_len = $ofp->sizeof('ofp_flow_stats'); - while (length($recvd_mesg) > 0) { - if (length($recvd_mesg) < $flow_stats_len) {\ - die "Error: Partial flow stats message received"; - } - my $flow_stats = $ofp->unpack('ofp_flow_stats', $recvd_mesg); - - push @{$msg->{'body'}}, $flow_stats; - $recvd_mesg = substr($recvd_mesg, $flow_stats->{'length'}); - } - - #print HexDump ($recvd_mesg); - print Dumper($msg); - - # Verify fields - verify_header( $msg, 'OFPT_STATS_REPLY', $msg_size ); - - # Ensure that we got back one ofp_flow_stats body - compare( "stats_reply flow_stats count", scalar(@{$msg->{'body'}}), '==', 1 ); - - - #wait_for_flow_expired_all( $ofp, $sock, $options_ref ); - - -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_flow_stats_precision/run.pl b/openflow/regress/projects/black_box/regress/test_flow_stats_precision/run.pl deleted file mode 100755 index 06dc1ae5..00000000 --- a/openflow/regress/projects/black_box/regress/test_flow_stats_precision/run.pl +++ /dev/null @@ -1,191 +0,0 @@ -#!/usr/bin/perl -w -# test_flow_stats -# This test assumes a lightly loaded switch that can measure and reply to -# flow stats requests within 500ms of receiving the request. - -use strict; -use OF::Includes; - -sub my_test { - - my ( $sock, $options_ref ) = @_; - my $time_threshold = 500000000; - my $port_base = $$options_ref{'port_base'}; - - my $hdr_args = { - version => get_of_ver(), - type => $enums{'OFPT_STATS_REQUEST'}, - length => $ofp->sizeof('ofp_stats_request') + - $ofp->sizeof('ofp_flow_stats_request') - , # should generate automatically! - xid => 0x00000000 - }; - - my $match_args = { - wildcards => 0x3ef, - in_port => 0, - dl_src => [], - dl_dst => [], - dl_vlan => 0, - dl_type => 0x800, - nw_src => ( NF2::IP_hdr::getIP("192.168.200.1") )[0], - nw_dst => ( NF2::IP_hdr::getIP("192.168.201.2") )[0], - nw_proto => 0, - tp_src => 0, - tp_dst => 0 - }; - - my $stats_request_args = { - header => $hdr_args, - type => $enums{'OFPST_FLOW'}, - flags => 0 - }; - - my $body_args = { - match => $match_args, - table_id => 0xff, #match all tables - out_port => $enums{'OFPP_NONE'}, - }; - - my $body = $ofp->pack( 'ofp_flow_stats_request', $body_args ); - - my $stats_request = $ofp->pack( 'ofp_stats_request', $stats_request_args ); - - my $mesg = $stats_request . $body; - - # Send 'stats_request' message - print $sock $mesg; - - # Should add timeout here - will crash if no reply - my $recvd_mesg; - sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; - - # Inspect message - my $msg_size = length($recvd_mesg); - - my $msg = $ofp->unpack( 'ofp_stats_reply', $recvd_mesg ); - - #print HexDump ($recvd_mesg); - print Dumper($msg); - - # Verify fields - verify_header( $msg, 'OFPT_STATS_REPLY', $msg_size ); - - #---------------------- - - # add flow mod, send pkt - { - my $in_port_offset = 0; - my $out_port_offset = 1; - my $wildcards = 0x3ef; - my $wait = 5; - - forward_simple( $ofp, $sock, $options_ref, $in_port_offset, - $out_port_offset, $wildcards, 'any', 1 ); - } - - sleep .1; - - # Send 'stats_request' message - print $sock $mesg; - - # Should add timeout here - will crash if no reply - my $recvd_mesg; - sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; - - # Inspect message - my $msg_size = length($recvd_mesg); - - my $msg = $ofp->unpack( 'ofp_stats_reply', $recvd_mesg ); - - # Strip off the header from the received message - $recvd_mesg = substr( $recvd_mesg, $ofp->sizeof('ofp_stats_reply') ); - - # Unpack each of the ofp_flow_stats messages - my $flow_stats_len = $ofp->sizeof('ofp_flow_stats'); - while ( length($recvd_mesg) > 0 ) { - if ( length($recvd_mesg) < $flow_stats_len ) { - die "Error: Partial flow stats message received"; - } - my $flow_stats = $ofp->unpack( 'ofp_flow_stats', $recvd_mesg ); - - push @{ $msg->{'body'} }, $flow_stats; - $recvd_mesg = substr( $recvd_mesg, $flow_stats->{'length'} ); - } - - #print HexDump ($recvd_mesg); - print Dumper($msg); - - # Verify fields - verify_header( $msg, 'OFPT_STATS_REPLY', $msg_size ); - - # Ensure that we got back one ofp_flow_stats body - compare( - "stats_reply flow_stats count", - scalar( @{ $msg->{'body'} } ), - '==', 1 - ); - if ( $msg->{'body'}[0]->{'duration_sec'} != 0 ) { - die "Error, duration_sec out of acceptable range"; - } - if ( $msg->{'body'}[0]->{'duration_nsec'} < 100000000 - || $msg->{'body'}[0]->{'duration_nsec'} > (100000000+$time_threshold) ) - { - die "Error, duration_nsec out of acceptable range"; - } - - # Sleep 1 more second to test duration_sec - sleep 1.0; - - # Send 'stats_request' message - print $sock $mesg; - - # Should add timeout here - will crash if no reply - my $recvd_mesg; - sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; - - # Inspect message - my $msg_size = length($recvd_mesg); - - my $msg = $ofp->unpack( 'ofp_stats_reply', $recvd_mesg ); - - # Strip off the header from the received message - $recvd_mesg = substr( $recvd_mesg, $ofp->sizeof('ofp_stats_reply') ); - - # Unpack each of the ofp_flow_stats messages - my $flow_stats_len = $ofp->sizeof('ofp_flow_stats'); - while ( length($recvd_mesg) > 0 ) { - if ( length($recvd_mesg) < $flow_stats_len ) { - die "Error: Partial flow stats message received"; - } - my $flow_stats = $ofp->unpack( 'ofp_flow_stats', $recvd_mesg ); - - push @{ $msg->{'body'} }, $flow_stats; - $recvd_mesg = substr( $recvd_mesg, $flow_stats->{'length'} ); - } - - #print HexDump ($recvd_mesg); - print Dumper($msg); - - # Verify fields - verify_header( $msg, 'OFPT_STATS_REPLY', $msg_size ); - - # Ensure that we got back one ofp_flow_stats body - compare( - "stats_reply flow_stats count", - scalar( @{ $msg->{'body'} } ), - '==', 1 - ); - if ( $msg->{'body'}[0]->{'duration_sec'} != 1 ) { - die "Error, duration_sec out of acceptable range"; - } - if ( $msg->{'body'}[0]->{'duration_nsec'} < 100000000 - || $msg->{'body'}[0]->{'duration_nsec'} > (100000000+$time_threshold) ) - { - die "Error, duration_nsec out of acceptable range"; - } - -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_forward_after_expiration/run.pl b/openflow/regress/projects/black_box/regress/test_forward_after_expiration/run.pl deleted file mode 100755 index 347051ca..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_after_expiration/run.pl +++ /dev/null @@ -1,111 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_after_expiration - -use strict; -use OF::Includes; - -sub send_expect_exact { - - my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset ) = @_; - - my $in_port = $in_port_offset + $$options_ref{'port_base'}; - my $out_port = $out_port_offset + $$options_ref{'port_base'}; - - my $test_pkt = get_default_black_box_pkt_len( $in_port, $out_port, $$options_ref{'pkt_len'} ); - - #print HexDump ( $test_pkt->packed ); - - my $wildcards = 0x0; # exact match - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; - - my $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, - $$options_ref{'max_idle'}, $flags, $wildcards ); - - #print HexDump($flow_mod_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent flow_mod message\n"; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - - # Send a packet - ensure packet comes out desired port - nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt->packed ); - nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); -} - -sub send_expect_secchan_nomatch { - - my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len ) = @_; - - my $in_port = $in_port_offset + $$options_ref{'port_base'}; - my $out_port = $out_port_offset + $$options_ref{'port_base'}; - - my $test_pkt2 = get_default_black_box_pkt_len( $in_port, $out_port, $$options_ref{'pkt_len'} ); - - print "sending out eth" - . ( $in_port_offset + 1 ) - . ", expecting response on secchan due to no flow matching\n"; - - # Send a packet - ensure packet comes out desired port - nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt2->packed ); - - my $recvd_mesg; - sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; - - # Inspect message - my $msg_size = length($recvd_mesg); - my $expected_size = $ofp->offsetof( 'ofp_packet_in', 'data' ) + length( $test_pkt2->packed ); - compare( "msg size", $msg_size, '==', $expected_size ); - - my $msg = $ofp->unpack( 'ofp_packet_in', $recvd_mesg ); - - #print HexDump ($recvd_mesg); - #print Dumper($msg); - - # Verify fields - - print "Verifying secchan message for packet sent in to eth" . ( $in_port_offset + 1 ) . "\n"; - - verify_header( $msg, 'OFPT_PACKET_IN', $msg_size ); - - compare( "total len", $$msg{'total_len'}, '==', length( $test_pkt2->packed ) ); - compare( "in_port", $$msg{'in_port'}, '==', $in_port ); - compare( "reason", $$msg{'reason'}, '==', $enums{'OFPR_NO_MATCH'} ); - - # verify packet was unchanged! - my $recvd_pkt_data = substr( $recvd_mesg, $ofp->offsetof( 'ofp_packet_in', 'data' ) ); - if ( $recvd_pkt_data ne $test_pkt2->packed ) { - die "ERROR: sending from eth" - . $in_port + 1 - . " received packet data didn't match packet sent\n"; - } - -} - -sub test_forward_after_expiration { - - my ( $ofp, $sock, $options_ref, $i, $j, $wildcards ) = @_; - - my $max_idle = $$options_ref{'max_idle'}; - my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_total = $$options_ref{'pkt_total'}; - - send_expect_exact( $ofp, $sock, $options_ref, $i, $j); - print "waiting for flow to expire\n"; - wait_for_flow_expired_all( $ofp, $sock, $options_ref ); - usleep($$options_ref{'send_delay'}); - send_expect_secchan_nomatch( $ofp, $sock, $options_ref, $i, $j); -} - -sub my_test { - - my ($sock, $options_ref) = @_; - - # send from every port to every other port - for_all_port_pairs( $ofp, $sock, $options_ref, \&test_forward_after_expiration, 0x0); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_any_port/run.pl b/openflow/regress/projects/black_box/regress/test_forward_any_port/run.pl deleted file mode 100755 index 83c07e1d..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_any_port/run.pl +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_any_port - -use strict; -use OF::Includes; - -sub forward_any { - - forward_simple(@_, 'any'); -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_any, 0xfffff); -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_forward_bandwidth_fixed/run.pl b/openflow/regress/projects/black_box/regress/test_forward_bandwidth_fixed/run.pl deleted file mode 100755 index 44ac6ec9..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_bandwidth_fixed/run.pl +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_bandwidth_fixed - -use strict; -use OF::Includes; - -my $pkt_len = 1512; -my $pkt_total = 1000; -my $max_idle = 2; - -sub send_expect_exact { - - my ( $ofp, $sock, $in_port, $out_port, $max_idle, $pkt_len ) = @_; - my %delta; - - # in_port refers to the flow mod entry's input - - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - src_port => 1, - dst_port => 0 - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - #print HexDump ( $test_pkt->packed ); - - my $wildcards = 0x0; # exact match - #my $wildcards = 0x2; # only wildcard the vlan - #my $wildcards = 0x2FF; # exact match - #my $wildcards = 0x3FE; # exact match on switch in port - #my $wildcards = 0x3DF; # exact match on src ip - #my $wildcards = 0x1; # exact match on eth src/dest/eth frame/ipsrcdest/128ipproto/256port source - #my $wildcards = 0x3BF; # exact match on dest ip - #my $wildcards = 0x3FD; # exact match on vlan - #my $wildcards = 0x3FB; # exact match on ether source - #my $wildcards = 0x3F7; # exact match on ether dest - my $flags = 0x0; # don't send flow expiry - - my $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, - $max_idle, $flags, $wildcards ); - - #print HexDump($flow_mod_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent flow_mod message\n"; - - usleep(200000); - my @start_time = gettimeofday(); - for (my $k = 0; $k < $pkt_total; $k++) { - send_and_count( nftest_get_iface( "eth" . ( $in_port + 1 ) ), - $test_pkt->packed, \%delta ); - expect_and_count( nftest_get_iface( "eth" . ( $out_port + 1 ) ), - $test_pkt->packed, \%delta ); - } - (my $second, my $micro) = tv_interval(\@start_time); - my $time_elapsed = ($second + $micro * 1e-6); - my $bw_result = ($pkt_total * $pkt_len * 8) / $time_elapsed; - print "PACKET LENGTH: $pkt_len \n"; - print "PACKETS SENT: $pkt_total\n"; - print "TIME ELAPSED: $time_elapsed \n"; - print "RESULTING BW: $bw_result bits/sec \n"; - -} - -sub my_test { - - my ($sock, $options_ref) = @_; - - my $inport = 0; - my $outport = 1; - print "Checking forwarding bandwidth from $inport to $outport\n"; - send_expect_exact( $ofp, $sock, $inport, $outport, $max_idle, $pkt_len ); - wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); -} - -run_black_box_test( \&my_test ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_bandwidth_random/run.pl b/openflow/regress/projects/black_box/regress/test_forward_bandwidth_random/run.pl deleted file mode 100755 index 4fa05282..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_bandwidth_random/run.pl +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_bandwidth_fixed - -use strict; -use OF::Includes; - -my $pkt_total = 1000; -my $max_idle = 2; - -# Maximum and minimum packet sizes -my $min_length = 64; -my $max_length = 1512; - -sub send_expect_exact { - - my ( $ofp, $sock, $in_port, $out_port, $max_idle) = @_; - my %delta; - - # in_port refers to the flow mod entry's input - - my @packets; - my $bytes = 0; - for (my $i = 0; $i < $pkt_total; $i++) { - my $pkt_len = int(rand($max_length - $min_length)) + $min_length; - $bytes += $pkt_len; - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port + 1 ), - dst_ip => "192.168.201." . ( $out_port + 1 ), - ttl => 64, - len => $pkt_len, - src_port => 1, - dst_port => 0 - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - push @packets, $test_pkt; - } - - - my $wildcards = 0x1; # wild card on input port - my $flags = 0x0; # don't send flow expiry - - my $test_pkt = pop @packets; - my $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, - $max_idle, $flags, $wildcards ); - push @packets, $test_pkt; - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent flow_mod message\n"; - - usleep(200000); - my @start_time = gettimeofday(); - for (my $k = 0; $k < $pkt_total; $k++) { - my $packet = pop @packets; - my $randport = int(rand(2)); - send_and_count( nftest_get_iface( "eth" . ( $randport + 1 ) ), - $packet->packed, \%delta ); - expect_and_count( nftest_get_iface( "eth" . ( $out_port + 1 ) ), - $packet->packed, \%delta ); - } - (my $second, my $micro) = tv_interval(\@start_time); - my $time_elapsed = ($second + $micro * 1e-6); - my $bw_result = ($bytes * 8) / $time_elapsed; - print "PACKETS SENT: $pkt_total\n"; - print "BYTES SENT: $bytes\n"; - print "TIME ELAPSED: $time_elapsed \n"; - print "RESULTING BW: $bw_result bits/sec \n"; - return $bytes; -} - -sub my_test { - - my ($sock, $options_ref) = @_; - - my $inport = 0; - my $outport = 3; - my $bytes_sent = send_expect_exact( $ofp, $sock, $inport, $outport, $max_idle ); - wait_for_flow_expired_total_bytes( $ofp, $sock, $options_ref, $bytes_sent, $pkt_total ); -} - -run_black_box_test( \&my_test ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_broadcast_exact_port/run.pl b/openflow/regress/projects/black_box/regress/test_forward_broadcast_exact_port/run.pl deleted file mode 100755 index 03bf655b..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_broadcast_exact_port/run.pl +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_exact_port - -use strict; -use OF::Includes; - -sub forward_broadcast { - - my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $wildcards, $type, $nowait ) = @_; - - my $in_port = $in_port_offset + $$options_ref{'port_base'}; - my $out_port; - - $out_port = $out_port_offset + $$options_ref{'port_base'}; - - my $len = $$options_ref{'pkt_len'}; - my $pkt_args = { - DA => "FF:FF:FF:FF:FF:FF", - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168." . ( $in_port ) . "." . ( $out_port ), - dst_ip => "255.255.255.255", - ttl => 64, - len => $len, - src_port => 1, - dst_port => 0 - }; - my $test_pkt = new NF2::UDP_pkt(%$pkt_args); - - my $flow_mod_pkt; - - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; - $flow_mod_pkt = create_flow_mod_from_udp($ofp, $test_pkt, $in_port, $out_port, $$options_ref{'max_idle'}, $flags, $wildcards); - - # Send 'flow_mod' message - syswrite( $sock, $flow_mod_pkt ); - print "sent flow_mod message\n"; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - - nftest_send( "eth" . ($in_port_offset + 1), $test_pkt->packed ); - - # expect single packet - print "expect single packet\n"; - nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); - - print "wait \n"; - wait_for_flow_expired_all( $ofp, $sock, $options_ref ); -} - - -sub forward_port { - - forward_broadcast(@_, 'port'); -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_port, 0x0); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_all/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_all/run.pl deleted file mode 100755 index 052ebbeb..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_exact_all/run.pl +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_exact_all - -use strict; -use OF::Includes; - -sub forward_all { - - forward_simple(@_, 'all'); -} - -sub forward_all_vlan { - my $vlan_id = 0xa5f3; - #[15:13] priority, [11:0] vlan id - #The value was chosen at random - forward_simple(@_, 'all', undef, undef, $vlan_id); -} - - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_ports( $ofp, $sock, $options_ref, \&forward_all, 0x0); - if ( not defined( $$options_ref{'no_vlan'} ) ) { - for_all_ports( $ofp, $sock, $options_ref, \&forward_all_vlan, 0x0); - } -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_arp_all/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_arp_all/run.pl deleted file mode 100755 index 0f44f91f..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_exact_arp_all/run.pl +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_exact_arp_all - -use strict; -use OF::Includes; - -sub forward_all { - - forward_simple_arp(@_, 'all', 0); # 0: fool_flg = off -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_ports( $ofp, $sock, $options_ref, \&forward_all, 0x0); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_arp_controller/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_arp_controller/run.pl deleted file mode 100755 index e7de7bad..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_exact_arp_controller/run.pl +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_exact_arp_controller - -use strict; -use OF::Includes; - -sub forward_controller { - - forward_simple_arp(@_, 'controller', 0); # 0: fool_flg = off -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_ports( $ofp, $sock, $options_ref, \&forward_controller, 0x0); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_arp_fool/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_arp_fool/run.pl deleted file mode 100755 index 076dfc42..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_exact_arp_fool/run.pl +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_exact_arp_fool - -use strict; -use OF::Includes; - -sub forward_port { - - forward_simple_arp(@_, 'port', 1); # 1: fool_flg=on -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_port, 0x0); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_arp_port/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_arp_port/run.pl deleted file mode 100755 index b0af883e..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_exact_arp_port/run.pl +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_exact_arp_port - -use strict; -use OF::Includes; - -sub forward_port { - - forward_simple_arp(@_, 'port', 0); # 0: fool_flg = off -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_port, 0x0); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_controller/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_controller/run.pl deleted file mode 100755 index e0888d16..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_exact_controller/run.pl +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_exact_controller - -use strict; -use OF::Includes; - -use strict; -use OF::Includes; - -sub forward_controller { - - forward_simple(@_, 'controller'); -} - -sub forward_controller_vlan { - my $vlan_id = 0xc123; - #[15:13] priority, [11:0] vlan id - #The value was chosen at random - forward_simple(@_, 'controller', undef, undef, $vlan_id); -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_ports( $ofp, $sock, $options_ref, \&forward_controller, 0x0); - if ( not defined( $$options_ref{'no_vlan'} ) ) { - for_all_ports( $ofp, $sock, $options_ref, \&forward_controller_vlan, 0x0); - } -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_all/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_all/run.pl deleted file mode 100755 index 3b1f6bfd..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_all/run.pl +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_exact_icmp_all - -use strict; -use OF::Includes; - -sub forward_all { - - forward_simple_icmp(@_, 'all', 0); # 0: fool_flg = off -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_ports( $ofp, $sock, $options_ref, \&forward_all, 0x0); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_controller/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_controller/run.pl deleted file mode 100755 index c07debe8..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_controller/run.pl +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_exact_icmp_controller - -use strict; -use OF::Includes; - -sub forward_controller { - - forward_simple_icmp(@_, 'controller', 0); # 0: fool_flg = off -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_ports( $ofp, $sock, $options_ref, \&forward_controller, 0x0); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_fool/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_fool/run.pl deleted file mode 100755 index dee5a6c2..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_fool/run.pl +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_exact_icmp_fool - -use strict; -use OF::Includes; - -sub forward_port { - - forward_simple_icmp(@_, 'port', 1); # 1: fool_flg=on -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_port, 0x0); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_port/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_port/run.pl deleted file mode 100755 index 100bc3ad..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_port/run.pl +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_exact_icmp_port - -use strict; -use OF::Includes; - -sub forward_port { - - forward_simple_icmp(@_, 'port', 0); # 0: fool_flg = off -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_port, 0x0); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_modify_action/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_modify_action/run.pl deleted file mode 100755 index 805c9ad9..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_exact_modify_action/run.pl +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_exact_modify_action - -use strict; -use OF::Includes; - -sub forward_port { - - my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, - $wildcards ) = @_; - - my @chg_field; - if ( not defined( $$options_ref{'no_vlan'} ) ) { - @chg_field = ('vlan_vid', 'vlan_pcp', 'dl_src', 'dl_dst', 'nw_src', 'nw_dst', 'tp_src', 'tp_dst'); - } else { - @chg_field = ('dl_src', 'dl_dst', 'nw_src', 'nw_dst', 'tp_src', 'tp_dst'); - } - foreach (@chg_field) { - forward_simple(@_, 'port', undef, $_ ); - } -} - -sub forward_port_vlan { - my @chg_field = ('strip_vlan', 'vlan_vid', 'vlan_pcp', 'dl_src', 'dl_dst', 'nw_src', 'nw_dst', 'tp_src', 'tp_dst'); - my $vlan = 0x65a1; - #[15:13]:vlan_pcp, [11:0]:vlan_vid - #The value was chosen at random - foreach (@chg_field) { - forward_simple(@_, 'port', undef, $_, $vlan ); - } -} -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_port, 0x0); - if ( not defined( $$options_ref{'no_vlan'} ) ) { - for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_port_vlan, 0x0); - } -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_port/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_port/run.pl deleted file mode 100755 index c3fc215f..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_exact_port/run.pl +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_exact_port - -use strict; -use OF::Includes; - -sub forward_unicast_port { - forward_simple(@_, 'port'); -} - -sub forward_unicast_vlan_port { - my $vlan_id = 0xea5a; - #[15:13] priority, [11:0] vlan id - #The value was chosen at random - forward_simple(@_, 'port', undef, undef, $vlan_id); -} - -sub my_test { - my ($sock, $options_ref) = @_; - - for_all_port_pairs($ofp, $sock, $options_ref, \&forward_unicast_port, 0x0); - if ( not defined( $$options_ref{'no_vlan'} ) ) { - for_all_port_pairs($ofp, $sock, $options_ref, \&forward_unicast_vlan_port, 0x0); - } -} - -run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_forward_overlapping_flow_entries/run.pl b/openflow/regress/projects/black_box/regress/test_forward_overlapping_flow_entries/run.pl deleted file mode 100755 index 6ed870e6..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_overlapping_flow_entries/run.pl +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_overlapping_flow_entries - -use strict; -use OF::Includes; - -sub send_expect_multi_flow { - - my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len ) = @_; - - my $in_port = $in_port_offset + $$options_ref{'port_base'}; - my $out_port = $out_port_offset + $$options_ref{'port_base'}; - - my $test_pkt = get_default_black_box_pkt_len( $in_port, $out_port, $pkt_len ); - - #print HexDump ( $test_pkt->packed ); - - my $wildcards = 0x0; # exact match - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; - - my $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, - $enums{'OFPP_ALL'}, $max_idle, $flags, $wildcards ); - - #print HexDump($flow_mod_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent exact match flow_mod message\n"; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - - $wildcards = 0x1fffff; # wildcard everything - - # (send to controller) - $flow_mod_pkt = create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, - $enums{'OFPP_CONTROLLER'}, 2, $flags, $wildcards ); - - #print HexDump($flow_mod_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent wildcard match flow_mod message\n"; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - - # Send a packet - ensure packet comes out desired port - nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt->packed ); - - for ( my $k = 0 ; $k < $$options_ref{'num_ports'}; $k++ ) { - if ( $k != $in_port_offset ) { - nftest_expect( "eth" . ( $k + 1 ), $test_pkt->packed ); - } - } -} - -sub my_test { - - my ($sock, $options_ref) = @_; - - #my $max_idle = $$options_ref{'max_idle'}; - my $max_idle = 5; - my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_total = $$options_ref{'pkt_total'}; - - my $num_ports = $$options_ref{'num_ports'}; - - my $j = 0; - - # send from every port, receive on every port except the send port - #for ( my $i = 0 ; $i < $num_ports ; $i++ ) { - my $i = 0; - my $j = ($i + 1) % $num_ports; - print "sending from $i to (all ports but $i)\n"; - send_expect_multi_flow( $ofp, $sock, $options_ref, $i, $j, $max_idle, $pkt_len ); - print "waiting for first flow to expire\n"; - wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, 0 ); - print "waiting for second flow to expire\n"; - wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); - #} -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_all/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_all/run.pl deleted file mode 100755 index 51a504b8..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_wildcard_all/run.pl +++ /dev/null @@ -1,172 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_wildcard_all - -use strict; -use OF::Includes; - -sub forward_wc_all { - - forward_simple(@_, 'all'); -} - -sub forward_wc_all_vlan { - my $vlan_id = 0x25ae; - #[15:13] priority, [11:0] vlan id - #The value was chosen at random - forward_simple(@_, 'all', undef, undef, $vlan_id); -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_all); - if ( not defined( $$options_ref{'no_vlan'} ) ) { - for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_all_vlan); - } -} - -run_black_box_test( \&my_test, \@ARGV ); - -#sub send_expect_exact { -# -# my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $wildcards ) = @_; -# -# my $in_port = $in_port_offset + $$options_ref{'port_base'}; -# my $out_port = $enums{'OFPP_ALL'}; # all physical ports except the input -# -# printf( "Wildcards are: %04x\n", $wildcards ); -# -# # in_port refers to the flow mod entry's input -# -# # This packet will always match -# my $test_pkt = get_default_black_box_pkt_len( $in_port, $out_port, $$options_ref{'pkt_len'} ); -# -# # This packet will always miss -# my $test_pkt2 = get_default_black_box_pkt_len( $in_port + 5, $out_port + 5, $$options_ref{'pkt_len'} ); -# -# print HexDump ( $test_pkt->packed ); -# print HexDump ( $test_pkt2->packed ); -# -# my $flow_mod_pkt = -# create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $$options_ref{'max_idle'}, $wildcards ); -# -# #print HexDump($flow_mod_pkt); -# -# # Send 'flow_mod' message -# print $sock $flow_mod_pkt; -# print "sent flow_mod message\n"; -# -# # Give OF switch time to process the flow mod -# usleep($$options_ref{'send_delay'}); -# -# # Send a packet - ensure packet comes out desired port -# nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt->packed ); -# -# for ( my $k = 0 ; $k < $$options_ref{'num_ports'} ; $k++ ) { -# if ( $k != $in_port_offset ) { -# nftest_expect( "eth" . ( $k + 1 ), $test_pkt->packed ); -# } -# } -# -# print "Matching packet sent\n"; -# -# #nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt2->packed ); -# -## #print "Non-matching packet sent\n"; -## my $recvd_mesg; -## sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; -## -## # Inspect message -## my $msg_size = length($recvd_mesg); -## my $expected_size = $ofp->offsetof( 'ofp_packet_in', 'data' ) + length( $test_pkt2->packed ); -## -## print HexDump ($recvd_mesg); -## -## #print "Comparing sizes $msg_size and $expected_size\n"; -## compare( "msg size", $msg_size, '==', $expected_size ); -## -## my $msg = $ofp->unpack( 'ofp_packet_in', $recvd_mesg ); -## -## #print HexDump ($recvd_mesg); -## #print Dumper($msg); -## -## # Verify fields -## verify_header( $msg, 'OFPT_PACKET_IN', $msg_size ); -## -## compare( "total len", $$msg{'total_len'}, '==', length( $test_pkt2->packed ) ); -## compare( "in_port", $$msg{'in_port'}, '==', $in_port ); -## compare( "reason", $$msg{'reason'}, '==', $enums{'OFPR_NO_MATCH'} ); -## -## # verify packet was unchanged! -## my $recvd_pkt_data = substr( $recvd_mesg, $ofp->offsetof( 'ofp_packet_in', 'data' ) ); -## if ( $recvd_pkt_data ne $test_pkt2->packed ) { -## die "ERROR: received packet data didn't match packet sent\n"; -## } -# -#} -# -#sub my_test { -# -# my ( $sock, $options_ref ) = @_; -# my $j = $enums{'OFPP_FLOOD'}; -# -# my $max_idle = $$options_ref{'max_idle'}; -# my $pkt_len = $$options_ref{'pkt_len'}; -# my $pkt_total = $$options_ref{'pkt_total'}; -# -# # send from every port to every other port -# for ( my $i = 0 ; $i < 4 ; $i++ ) { -# -# print "sending from $i to $j\n"; -# -# #Very hackish, but basically iterate through the possibilities for -# #wildcarding one at a time. -# print "wildcards 0x0001 : IN_PORT\n"; -# send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0001 ); -# wait_for_flow_expired_all( $ofp, $sock, $options_ref ); -# -# #DL_VLAN fixed at 0xffff currently. -# #print "wildcards 0x0002 : DL_VLAN\n"; -# #send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0002); -# #wait_for_flow_expired_all( $ofp, $sock, $options_ref ); -# -# print "wildcards 0x0004 : DL_SRC\n"; -# send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0004 ); -# wait_for_flow_expired_all( $ofp, $sock, $options_ref ); -# -# print "wildcards 0x0008 : DL_DST\n"; -# send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0008 ); -# wait_for_flow_expired_all( $ofp, $sock, $options_ref ); -# -# #DL_TYPE fixed at 0x0800 currently. -# #print "wildcards 0x0010 : DL_TYPE\n"; -# #send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0010); -# #wait_for_flow_expired_all( $ofp, $sock, $options_ref ); -# -# print "wildcards 0x0020 : NW_SRC\n"; -# send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0020 ); -# wait_for_flow_expired_all( $ofp, $sock, $options_ref ); -# -# print "wildcards 0x0040 : NW_DST\n"; -# send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0040 ); -# wait_for_flow_expired_all( $ofp, $sock, $options_ref ); -# -# #NW_PROTO fixed at 17 currently. -# #print "wildcards 0x0080 : NW_PROTO\n"; -# #send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0080); -# #wait_for_flow_expired_all( $ofp, $sock, $options_ref ); -# -# print "wildcards 0x0100 : TP_SRC\n"; -# send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0100 ); -# wait_for_flow_expired_all( $ofp, $sock, $options_ref ); -# -# print "wildcards 0x0200 : TP_SRC\n"; -# send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0200 ); -# wait_for_flow_expired_all( $ofp, $sock, $options_ref ); -# -# } -#} -# -#run_black_box_test( \&my_test, \@ARGV ); -# diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_all/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_all/run.pl deleted file mode 100755 index ccebe303..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_all/run.pl +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_wildcard_arp_all - -use strict; -use OF::Includes; - -sub forward_wc_all { - - forward_simple_arp(@_, 'all', 0); # 0: fool_flg = off -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_all); -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_controller/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_controller/run.pl deleted file mode 100755 index 90e8b5ad..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_controller/run.pl +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_wildcard_arp_controller - -use strict; -use OF::Includes; - -sub forward_wc_controller { - - forward_simple_arp(@_, 'controller', 0); # 0: fool_flg = off -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_controller); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_fool/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_fool/run.pl deleted file mode 100755 index 0b4d5249..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_fool/run.pl +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_wildcard_arp_port - -use strict; -use OF::Includes; - -sub forward_wc_port { - forward_simple_arp(@_, 'port', 1); # 1: fool_flg = on -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_port); -} - -run_black_box_test( \&my_test, \@ARGV ); - - diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_port/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_port/run.pl deleted file mode 100755 index ef8cb8ab..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_port/run.pl +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_wildcard_arp_port - -use strict; -use OF::Includes; - -sub forward_wc_port { - forward_simple_arp(@_, 'port', 0); # 0: fool_flg = off -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_port); -} - -run_black_box_test( \&my_test, \@ARGV ); - - diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_controller/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_controller/run.pl deleted file mode 100755 index 125c5071..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_wildcard_controller/run.pl +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_wildcard_controller - -use strict; -use OF::Includes; - -sub forward_wc_controller { - - forward_simple(@_, 'controller'); -} - -sub forward_wc_controller_vlan { - my $vlan_id = 0x4abc; - #[15:13] priority, [11:0] vlan id - #The value was chosen at random - forward_simple(@_, 'controller', undef, undef, $vlan_id); -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_controller); - if ( not defined( $$options_ref{'no_vlan'} ) ) { - for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_controller_vlan); - } -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_all/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_all/run.pl deleted file mode 100755 index 7ccdea0b..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_all/run.pl +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_wildcard_icmp_all - -use strict; -use OF::Includes; - -sub forward_wc_all { - - forward_simple_icmp(@_, 'all', 0); # 0: fool_flg = off -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_all); -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_controller/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_controller/run.pl deleted file mode 100755 index 21a0c608..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_controller/run.pl +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_wildcard_icmp_controller - -use strict; -use OF::Includes; - -sub forward_wc_controller { - - forward_simple_icmp(@_, 'controller', 0); # 0: fool_flg = off -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_controller); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_fool/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_fool/run.pl deleted file mode 100755 index eacfb9d5..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_fool/run.pl +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_wildcard_icmp_port - -use strict; -use OF::Includes; - -sub forward_wc_port { - forward_simple_icmp(@_, 'port', 1); # 1: fool_flg = on -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_port); -} - -run_black_box_test( \&my_test, \@ARGV ); - - diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_port/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_port/run.pl deleted file mode 100755 index c428a9e5..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_port/run.pl +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_wildcard_icmp_port - -use strict; -use OF::Includes; - -sub forward_wc_port { - forward_simple_icmp(@_, 'port', 0); # 0: fool_flg = off -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_port); -} - -run_black_box_test( \&my_test, \@ARGV ); - - diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_modify_action/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_modify_action/run.pl deleted file mode 100755 index ca32aaaf..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_wildcard_modify_action/run.pl +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_wildcard_modify_action - -use strict; -use OF::Includes; - -sub forward_wc_port { - my @chg_field = ('vlan_vid', 'vlan_pcp','dl_src', 'dl_dst', 'nw_src', 'nw_dst', 'tp_src', 'tp_dst'); - foreach (@chg_field) { - forward_simple(@_, 'port', undef, $_ ); - } -} - - -sub forward_wc_port_vlan { - my @chg_field = ('strip_vlan', 'vlan_vid','vlan_pcp','dl_src', 'dl_dst', 'nw_src', 'nw_dst', 'tp_src', 'tp_dst'); - my $vlan_id = 0xa344; - #The value was chosen at random - foreach (@chg_field) { - forward_simple(@_, 'port', undef, $_, $vlan_id); - } -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_port); - if ( not defined( $$options_ref{'no_vlan'} ) ) { - for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_port_vlan); - } -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_port/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_port/run.pl deleted file mode 100755 index 934da7cc..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_wildcard_port/run.pl +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_wildcard_port - -use strict; -use OF::Includes; - -sub forward_wc_port { - - forward_simple(@_, 'port'); -} - -sub forward_wc_port_vlan { - my $vlan_id = 0x8ea5; - #[15:13] priority, [11:0] vlan id - #The value was chosen at random - forward_simple(@_, 'port', undef, undef, $vlan_id); -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_port); - if ( not defined( $$options_ref{'no_vlan'} ) ) { - for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_port_vlan); - } -} - -run_black_box_test( \&my_test, \@ARGV ); - -#sub send_expect_exact { -# -# my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len, $wildcards ) = @_; -# -# my $in_port = $in_port_offset + $$options_ref{'port_base'}; -# my $out_port = $out_port_offset + $$options_ref{'port_base'}; -# -# printf( "Wildcards are: %04x\n", $wildcards ); -# -# # This packet will always match -# my $test_pkt = get_default_black_box_pkt_len( $in_port, $out_port, $pkt_len ); -# -# # This packet will always miss -# my $test_pkt2 = get_default_black_box_pkt_len( $in_port + 5, $out_port + 5, $pkt_len ); -# -# #print HexDump ( $test_pkt->packed ); -# -# my $flow_mod_pkt = -# create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $wildcards ); -# -# #print HexDump($flow_mod_pkt); -# -# # Send 'flow_mod' message -# print $sock $flow_mod_pkt; -# print "sent flow_mod message\n"; -# -# # Give OF switch time to process the flow mod -# usleep($$options_ref{'send_delay'}); -# -# # Send a packet - ensure packet comes out desired port -# nftest_send( "eth" . ($in_port_offset + 1), $test_pkt->packed ); -# nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); -# print "Matching packet sent\n"; -# -# nftest_send( "eth" . ($in_port_offset + 1), $test_pkt2->packed ); -# -# print "Non-matching packet sent\n"; -# my $recvd_mesg; -# sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; -# -# # Inspect message -# my $msg_size = length($recvd_mesg); -# my $expected_size = $ofp->offsetof( 'ofp_packet_in', 'data' ) + length( $test_pkt2->packed ); -# -# #print "Comparing sizes $msg_size and $expected_size\n"; -# compare( "msg size", $msg_size, '==', $expected_size ); -# -# my $msg = $ofp->unpack( 'ofp_packet_in', $recvd_mesg ); -# -# #print HexDump ($recvd_mesg); -# #print Dumper($msg); -# -# # Verify fields -# verify_header( $msg, 'OFPT_PACKET_IN', $msg_size ); -# -# compare( "total len", $$msg{'total_len'}, '==', length( $test_pkt2->packed ) ); -# compare( "in_port", $$msg{'in_port'}, '==', $in_port ); -# compare( "reason", $$msg{'reason'}, '==', $enums{'OFPR_NO_MATCH'} ); -# -# # verify packet was unchanged! -# my $recvd_pkt_data = substr( $recvd_mesg, $ofp->offsetof( 'ofp_packet_in', 'data' ) ); -# if ( $recvd_pkt_data ne $test_pkt2->packed ) { -# die "ERROR: received packet data didn't match packet sent\n"; -# } -# -#} - diff --git a/openflow/regress/projects/black_box/regress/test_hello/run.pl b/openflow/regress/projects/black_box/regress/test_hello/run.pl deleted file mode 100755 index e1bbdb23..00000000 --- a/openflow/regress/projects/black_box/regress/test_hello/run.pl +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/perl -w -# test_hello - -use strict; -require OF::Includes; - -sub my_test { - - my ($sock, $options_ref) = @_; - - - - # hello sequence automatically done by test harness! -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_ip_offset/run.pl b/openflow/regress/projects/black_box/regress/test_ip_offset/run.pl deleted file mode 100755 index 0aa567b3..00000000 --- a/openflow/regress/projects/black_box/regress/test_ip_offset/run.pl +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/perl -w -# test_ip_offset - -use strict; -use OF::Includes; - -sub send_expect_exact { - - my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len ) = @_; - - my $in_port = $in_port_offset + $$options_ref{'port_base'}; - my $out_port = $out_port_offset + $$options_ref{'port_base'}; - - # in_port refers to the flow mod entry's input - - my $test_pkt_frag_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - frag => 0x2fff, # IP_frag > IP_len - src_port => 1, - dst_port => 0 - }; - my $test_pkt_frag = new NF2::UDP_pkt(%$test_pkt_frag_args); - - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - frag => 0, - src_port => 0, - dst_port => 0 - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - #print HexDump ( $test_pkt->packed ); - - my $wildcards = 0x0; # exact match - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; - - my $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); - - #print HexDump($flow_mod_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent flow_mod message\n"; - usleep($$options_ref{'send_delay'}); - - # Send a packet - ensure packet comes out desired port - nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt_frag->packed ); - nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt_frag->packed ); -} - -sub test_ip_offset { - - my ( $ofp, $sock, $options_ref, $i, $j, $wildcards ) = @_; - - my $max_idle = $$options_ref{'max_idle'}; - my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_total = $$options_ref{'pkt_total'}; - - my $port_base = $$options_ref{'port_base'}; - my $num_ports = $$options_ref{'num_ports'}; - - send_expect_exact( $ofp, $sock, $options_ref, $i, $j, $max_idle, $pkt_len ); - wait_for_flow_expired_all( $ofp, $sock, $options_ref ); -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - # send from every port to every other port - for_all_port_pairs( $ofp, $sock, $options_ref, \&test_ip_offset, 0x0); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_ip_options/run.pl b/openflow/regress/projects/black_box/regress/test_ip_options/run.pl deleted file mode 100755 index ce8f9266..00000000 --- a/openflow/regress/projects/black_box/regress/test_ip_options/run.pl +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/perl -w -# test_ip_options - -use strict; -use OF::Includes; - -sub send_expect_exact { - - my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len ) = @_; - - my $in_port = $in_port_offset + $$options_ref{'port_base'}; - my $out_port = $out_port_offset + $$options_ref{'port_base'}; - - # in_port refers to the flow mod entry's input - my @ipopt = ( 0x44, 0x08, 0x08, 0x00, 0x11, 0x22, 0x33, 0x44 ); #IP timestamp option - my $num_ipopt = @ipopt; - - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - ip_hdr_len => 5 + ( $#ipopt + 1 ) / 4, - ip_options => \@ipopt, - src_port => 1, - dst_port => 0 - - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - #print ("pkt_len = $pkt_len\n"); - #print HexDump ( $test_pkt->packed ); - - my $wildcards = 0x0; # exact match - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; - - my $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); - #print HexDump($flow_mod_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent flow_mod message\n"; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - - # Send a packet - ensure packet comes out desired port - nftest_send("eth" . ( $in_port_offset + 1 ), $test_pkt->packed ); - nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); -} - -sub test_ip_options { - - my ( $ofp, $sock, $options_ref, $i, $j, $wildcards ) = @_; - - my $max_idle = $$options_ref{'max_idle'}; - #my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_len = 68; - my $pkt_total = $$options_ref{'pkt_total'}; - - send_expect_exact( $ofp, $sock, $options_ref, $i, $j, $max_idle, $pkt_len ); - wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); -} - -sub my_test { - - my ($sock, $options_ref) = @_; - - # send from every port to every other port - for_all_port_pairs( $ofp, $sock, $options_ref, \&test_ip_options, 0x0); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_ip_protocol/case-c.pl b/openflow/regress/projects/black_box/regress/test_ip_protocol/case-c.pl deleted file mode 100755 index 4637c860..00000000 --- a/openflow/regress/projects/black_box/regress/test_ip_protocol/case-c.pl +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/perl -w -# test_ip_protocol (case c, not TCP nor UDP) - -use strict; -use OF::Includes; - -sub send_expect_exact { - - my ( $ofp, $sock, $in_port, $out_port, $max_idle, $pkt_len ) = @_; - - # in_port refers to the flow mod entry's input - - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - src_port => 70, - dst_port => 80 - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - ## Change protocol field - my $iphdr=$test_pkt->{'IP_hdr'}; - $$iphdr->proto(0x13); # overwrite protocol filed in IP header - - #print HexDump ( $test_pkt->packed ); - - my $wildcards = 0x0; # exact match - - my $flow_mod_pkt = - create_flow_mod_from_pseudo_tcp( $ofp, $test_pkt, $in_port, $out_port, - $max_idle, $wildcards ); - - #print HexDump($flow_mod_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent flow_mod message\n"; - usleep(100000); - - # Send a packet - ensure packet comes out desired port - nftest_send( "eth" . ( $in_port + 1 ), - $test_pkt->packed ); - nftest_expect( "eth" . ( $out_port + 1 ), - $test_pkt->packed ); -} - -sub test_ip_protocol { - - my ( $ofp, $sock, $options_ref, $i, $j, $wildcards ) = @_; - - my $max_idle = $$options_ref{'max_idle'}; - my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_total = $$options_ref{'pkt_total'}; - - send_expect_exact( $ofp, $sock, $i, $j, $max_idle, $pkt_len ); - wait_for_flow_expired_all( $ofp, $sock, $options_ref ); -} - -sub my_test { - - my ($sock, $options_ref) = @_; - - # send from every port to every other port - for_all_port_pairs( $ofp, $sock, $options_ref, \&test_ip_protocol, 0x0); -} - -sub create_flow_mod_from_pseudo_tcp { - - my ( $ofp, $udp_pkt, $in_port, $out_port, $max_idle, $wildcards ) = @_; - - my $hdr_args = { - version => get_of_ver(), - type => $enums{'OFPT_FLOW_MOD'}, - length => $ofp->sizeof('ofp_flow_mod') + $ofp->sizeof('ofp_action'), - xid => 0x0000000 - }; - - # might be cleaner to convert the exported colon-hex MAC addrs - #print ${$udp_pkt->{Ethernet_hdr}}->SA . "\n"; - #print ${$test_pkt->{Ethernet_hdr}}->SA . "\n"; - my $ref_to_eth_hdr = ( $udp_pkt->{'Ethernet_hdr'} ); - my $ref_to_ip_hdr = ( $udp_pkt->{'IP_hdr'} ); - - # pointer to array - my $eth_hdr_bytes = $$ref_to_eth_hdr->{'bytes'}; - my $ip_hdr_bytes = $$ref_to_ip_hdr->{'bytes'}; - my @dst_mac_subarray = @{$eth_hdr_bytes}[ 0 .. 5 ]; - my @src_mac_subarray = @{$eth_hdr_bytes}[ 6 .. 11 ]; - - my @src_ip_subarray = @{$ip_hdr_bytes}[ 12 .. 15 ]; - my @dst_ip_subarray = @{$ip_hdr_bytes}[ 16 .. 19 ]; - - my $src_ip = - ( ( 2**24 ) * $src_ip_subarray[0] + ( 2**16 ) * $src_ip_subarray[1] + - ( 2**8 ) * $src_ip_subarray[2] + $src_ip_subarray[3] ); - - my $dst_ip = - ( ( 2**24 ) * $dst_ip_subarray[0] + ( 2**16 ) * $dst_ip_subarray[1] + - ( 2**8 ) * $dst_ip_subarray[2] + $dst_ip_subarray[3] ); - - # read IP_header protocol field - my $iph = $udp_pkt->{'IP_hdr'}; - my $proto = $$iph->proto(); - - my $match_args = { - wildcards => $wildcards, - in_port => $in_port, - dl_src => \@src_mac_subarray, - dl_dst => \@dst_mac_subarray, - dl_vlan => 0xffff, - dl_type => 0x0800, - nw_src => $src_ip, - nw_dst => $dst_ip, - nw_proto => $proto, #any protocol - tp_src => ${ $udp_pkt->{UDP_pdu} }->SrcPort, - tp_dst => ${ $udp_pkt->{UDP_pdu} }->DstPort - }; - - my $action_output_args = { - max_len => 0, # send entire packet - port => $out_port - }; - print "My Out Port: ${out_port}\n"; - - my $action_args = { - type => $enums{'OFPAT_OUTPUT'}, - arg => { output => $action_output_args } - }; - my $action = $ofp->pack( 'ofp_action', $action_args ); - - my $flow_mod_args = { - header => $hdr_args, - match => $match_args, - command => $enums{'OFPFC_ADD'}, - max_idle => $max_idle, - buffer_id => 0x0000, - group_id => 0 - }; - my $flow_mod = $ofp->pack( 'ofp_flow_mod', $flow_mod_args ); - - my $flow_mod_pkt = $flow_mod . $action; - - return $flow_mod_pkt; -} - -run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_ip_protocol/case-d.pl b/openflow/regress/projects/black_box/regress/test_ip_protocol/case-d.pl deleted file mode 100755 index 4f71280e..00000000 --- a/openflow/regress/projects/black_box/regress/test_ip_protocol/case-d.pl +++ /dev/null @@ -1,152 +0,0 @@ -#!/usr/bin/perl -w -# test_ip_protocol (case d, not TCP nor UDP, but specify src port=0, dst port=0); - -use strict; -use OF::Includes; - -sub send_expect_exact { - - my ( $ofp, $sock, $in_port, $out_port, $max_idle, $pkt_len ) = @_; - - # in_port refers to the flow mod entry's input - - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - src_port => 70, - dst_port => 80 - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - ## Change protoco field - my $iphdr=$test_pkt->{'IP_hdr'}; - $$iphdr->proto(0x13); # overwrite protocol filed in IP header - - #print HexDump ( $test_pkt->packed ); - - my $wildcards = 0x0; # exact match - - my $flow_mod_pkt = - create_flow_mod_from_ip( $ofp, $test_pkt, $in_port, $out_port, - $max_idle, $wildcards, 0, 0); - - #print HexDump($flow_mod_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent flow_mod message\n"; - usleep(100000); - - - # Send a packet - ensure packet comes out desired port - nftest_send( "eth" . ( $in_port + 1 ), - $test_pkt->packed ); - nftest_expect( "eth" . ( $out_port + 1 ), - $test_pkt->packed ); -} - - -sub my_test { - - my ($sock, $options_ref) = @_; - - my $max_idle = $$options_ref{'max_idle'}; - my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_total = $$options_ref{'pkt_total'}; - - # send from every port to every other port - for ( my $i = 0 ; $i < 4 ; $i++ ) { - for ( my $j = 0 ; $j < 4 ; $j++ ) { - if ( $i != $j ) { - print "sending from $i to $j\n"; - send_expect_exact( $ofp, $sock, $i, $j, $max_idle, $pkt_len ); - wait_for_flow_expired_all( $ofp, $sock, $options_ref ); - } - } - } -} - -sub create_flow_mod_from_ip { - - my ( $ofp, $udp_pkt, $in_port, $out_port, $max_idle, $wildcards, $s_port, $d_port ) = @_; - - my $hdr_args = { - version => get_of_ver(), - type => $enums{'OFPT_FLOW_MOD'}, - length => $ofp->sizeof('ofp_flow_mod') + $ofp->sizeof('ofp_action'), - xid => 0x0000000 - }; - - # might be cleaner to convert the exported colon-hex MAC addrs - #print ${$udp_pkt->{Ethernet_hdr}}->SA . "\n"; - #print ${$test_pkt->{Ethernet_hdr}}->SA . "\n"; - my $ref_to_eth_hdr = ( $udp_pkt->{'Ethernet_hdr'} ); - my $ref_to_ip_hdr = ( $udp_pkt->{'IP_hdr'} ); - - # pointer to array - my $eth_hdr_bytes = $$ref_to_eth_hdr->{'bytes'}; - my $ip_hdr_bytes = $$ref_to_ip_hdr->{'bytes'}; - my @dst_mac_subarray = @{$eth_hdr_bytes}[ 0 .. 5 ]; - my @src_mac_subarray = @{$eth_hdr_bytes}[ 6 .. 11 ]; - - my @src_ip_subarray = @{$ip_hdr_bytes}[ 12 .. 15 ]; - my @dst_ip_subarray = @{$ip_hdr_bytes}[ 16 .. 19 ]; - - my $src_ip = - ( ( 2**24 ) * $src_ip_subarray[0] + ( 2**16 ) * $src_ip_subarray[1] + - ( 2**8 ) * $src_ip_subarray[2] + $src_ip_subarray[3] ); - - my $dst_ip = - ( ( 2**24 ) * $dst_ip_subarray[0] + ( 2**16 ) * $dst_ip_subarray[1] + - ( 2**8 ) * $dst_ip_subarray[2] + $dst_ip_subarray[3] ); - - # read IP_header protocol field - my $iph = $udp_pkt->{'IP_hdr'}; - my $proto = $$iph->proto(); - - my $match_args = { - wildcards => $wildcards, - in_port => $in_port, - dl_src => \@src_mac_subarray, - dl_dst => \@dst_mac_subarray, - dl_vlan => 0xffff, - dl_type => 0x0800, - nw_src => $src_ip, - nw_dst => $dst_ip, - nw_proto => $proto, #any protocol - tp_src => $s_port, - tp_dst => $d_port - }; - - my $action_output_args = { - max_len => 0, # send entire packet - port => $out_port - }; - print "My Out Port: ${out_port}\n"; - - my $action_args = { - type => $enums{'OFPAT_OUTPUT'}, - arg => { output => $action_output_args } - }; - my $action = $ofp->pack( 'ofp_action', $action_args ); - - my $flow_mod_args = { - header => $hdr_args, - match => $match_args, - command => $enums{'OFPFC_ADD'}, - max_idle => $max_idle, - buffer_id => 0x0000, - group_id => 0 - }; - my $flow_mod = $ofp->pack( 'ofp_flow_mod', $flow_mod_args ); - - my $flow_mod_pkt = $flow_mod . $action; - - return $flow_mod_pkt; -} - -run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_ip_protocol/case-e.pl b/openflow/regress/projects/black_box/regress/test_ip_protocol/case-e.pl deleted file mode 100755 index 47d1227c..00000000 --- a/openflow/regress/projects/black_box/regress/test_ip_protocol/case-e.pl +++ /dev/null @@ -1,152 +0,0 @@ -#!/usr/bin/perl -w -# test_ip_protocol (case e, not TCP nor UDP, but specify src port!=0, dst port!=0); - -use strict; -use OF::Includes; - -sub send_expect_exact { - - my ( $ofp, $sock, $in_port, $out_port, $max_idle, $pkt_len ) = @_; - - # in_port refers to the flow mod entry's input - - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - src_port => 70, - dst_port => 80 - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - ## Change protoco field - my $iphdr=$test_pkt->{'IP_hdr'}; - $$iphdr->proto(0x13); # overwrite protocol filed in IP header - - #print HexDump ( $test_pkt->packed ); - - my $wildcards = 0x0; # exact match - - my $flow_mod_pkt = - create_flow_mod_from_ip( $ofp, $test_pkt, $in_port, $out_port, - $max_idle, $wildcards, 3, 4); - - #print HexDump($flow_mod_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent flow_mod message\n"; - usleep(100000); - - - # Send a packet - ensure packet comes out desired port - nftest_send( "eth" . ( $in_port + 1 ), - $test_pkt->packed ); - nftest_expect( "eth" . ( $out_port + 1 ), - $test_pkt->packed ); -} - - -sub my_test { - - my ($sock, $options_ref) = @_; - - my $max_idle = $$options_ref{'max_idle'}; - my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_total = $$options_ref{'pkt_total'}; - - # send from every port to every other port - for ( my $i = 0 ; $i < 4 ; $i++ ) { - for ( my $j = 0 ; $j < 4 ; $j++ ) { - if ( $i != $j ) { - print "sending from $i to $j\n"; - send_expect_exact( $ofp, $sock, $i, $j, $max_idle, $pkt_len ); - wait_for_flow_expired_all( $ofp, $sock, $options_ref ); - } - } - } -} - -sub create_flow_mod_from_ip { - - my ( $ofp, $udp_pkt, $in_port, $out_port, $max_idle, $wildcards, $s_port, $d_port ) = @_; - - my $hdr_args = { - version => get_of_ver(), - type => $enums{'OFPT_FLOW_MOD'}, - length => $ofp->sizeof('ofp_flow_mod') + $ofp->sizeof('ofp_action'), - xid => 0x0000000 - }; - - # might be cleaner to convert the exported colon-hex MAC addrs - #print ${$udp_pkt->{Ethernet_hdr}}->SA . "\n"; - #print ${$test_pkt->{Ethernet_hdr}}->SA . "\n"; - my $ref_to_eth_hdr = ( $udp_pkt->{'Ethernet_hdr'} ); - my $ref_to_ip_hdr = ( $udp_pkt->{'IP_hdr'} ); - - # pointer to array - my $eth_hdr_bytes = $$ref_to_eth_hdr->{'bytes'}; - my $ip_hdr_bytes = $$ref_to_ip_hdr->{'bytes'}; - my @dst_mac_subarray = @{$eth_hdr_bytes}[ 0 .. 5 ]; - my @src_mac_subarray = @{$eth_hdr_bytes}[ 6 .. 11 ]; - - my @src_ip_subarray = @{$ip_hdr_bytes}[ 12 .. 15 ]; - my @dst_ip_subarray = @{$ip_hdr_bytes}[ 16 .. 19 ]; - - my $src_ip = - ( ( 2**24 ) * $src_ip_subarray[0] + ( 2**16 ) * $src_ip_subarray[1] + - ( 2**8 ) * $src_ip_subarray[2] + $src_ip_subarray[3] ); - - my $dst_ip = - ( ( 2**24 ) * $dst_ip_subarray[0] + ( 2**16 ) * $dst_ip_subarray[1] + - ( 2**8 ) * $dst_ip_subarray[2] + $dst_ip_subarray[3] ); - - # read IP_header protocol field - my $iph = $udp_pkt->{'IP_hdr'}; - my $proto = $$iph->proto(); - - my $match_args = { - wildcards => $wildcards, - in_port => $in_port, - dl_src => \@src_mac_subarray, - dl_dst => \@dst_mac_subarray, - dl_vlan => 0xffff, - dl_type => 0x0800, - nw_src => $src_ip, - nw_dst => $dst_ip, - nw_proto => $proto, #any protocol - tp_src => $s_port, - tp_dst => $d_port - }; - - my $action_output_args = { - max_len => 0, # send entire packet - port => $out_port - }; - print "My Out Port: ${out_port}\n"; - - my $action_args = { - type => $enums{'OFPAT_OUTPUT'}, - arg => { output => $action_output_args } - }; - my $action = $ofp->pack( 'ofp_action', $action_args ); - - my $flow_mod_args = { - header => $hdr_args, - match => $match_args, - command => $enums{'OFPFC_ADD'}, - max_idle => $max_idle, - buffer_id => 0x0000, - group_id => 0 - }; - my $flow_mod = $ofp->pack( 'ofp_flow_mod', $flow_mod_args ); - - my $flow_mod_pkt = $flow_mod . $action; - - return $flow_mod_pkt; -} - -run_black_box_test(\&my_test); diff --git a/openflow/regress/projects/black_box/regress/test_ip_protocol/case-tcp.pl b/openflow/regress/projects/black_box/regress/test_ip_protocol/case-tcp.pl deleted file mode 100755 index 98117252..00000000 --- a/openflow/regress/projects/black_box/regress/test_ip_protocol/case-tcp.pl +++ /dev/null @@ -1,153 +0,0 @@ -#!/usr/bin/perl -w -# test_ip_protocol (tcp) - -use strict; -use OF::Includes; - -sub send_expect_exact { - - my ( $ofp, $sock, $in_port, $out_port, $max_idle, $pkt_len ) = @_; - - # in_port refers to the flow mod entry's input - - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - src_port => 70, - dst_port => 80 - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - ## Make packet TCP (assuming only tcp src port, tcp dst port fields are used) - my $iphdr = $test_pkt->{'IP_hdr'}; - $$iphdr->proto(6); # overwrite protocol filed in IP header - - #print HexDump ( $test_pkt->packed ); - - my $wildcards = 0x0; # exact match - - my $flow_mod_pkt = - create_flow_mod_from_pseudo_tcp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, - $wildcards ); - - #print HexDump($flow_mod_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent flow_mod message\n"; - usleep(100000); - - # Send a packet - ensure packet comes out desired port - nftest_send( "eth" . ( $in_port + 1 ), $test_pkt->packed ); - nftest_expect( "eth" . ( $out_port + 1 ), $test_pkt->packed ); -} - -sub my_test { - - my ($sock, $options_ref) = @_; - - my $max_idle = $$options_ref{'max_idle'}; - my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_total = $$options_ref{'pkt_total'}; - - # send from every port to every other port - for ( my $i = 0 ; $i < 4 ; $i++ ) { - for ( my $j = 0 ; $j < 4 ; $j++ ) { - if ( $i != $j ) { - print "sending from $i to $j\n"; - send_expect_exact( $ofp, $sock, $i, $j, $max_idle, $pkt_len ); - wait_for_flow_expired_all( $ofp, $sock, $options_ref ); - } - } - } -} - -sub create_flow_mod_from_pseudo_tcp { - - my ( $ofp, $udp_pkt, $in_port, $out_port, $max_idle, $wildcards ) = @_; - - my $hdr_args = { - version => get_of_ver(), - type => $enums{'OFPT_FLOW_MOD'}, - length => $ofp->sizeof('ofp_flow_mod') + $ofp->sizeof('ofp_action'), - xid => 0x0000000 - }; - - # might be cleaner to convert the exported colon-hex MAC addrs - #print ${$udp_pkt->{Ethernet_hdr}}->SA . "\n"; - #print ${$test_pkt->{Ethernet_hdr}}->SA . "\n"; - my $ref_to_eth_hdr = ( $udp_pkt->{'Ethernet_hdr'} ); - my $ref_to_ip_hdr = ( $udp_pkt->{'IP_hdr'} ); - - # pointer to array - my $eth_hdr_bytes = $$ref_to_eth_hdr->{'bytes'}; - my $ip_hdr_bytes = $$ref_to_ip_hdr->{'bytes'}; - my @dst_mac_subarray = @{$eth_hdr_bytes}[ 0 .. 5 ]; - my @src_mac_subarray = @{$eth_hdr_bytes}[ 6 .. 11 ]; - - my @src_ip_subarray = @{$ip_hdr_bytes}[ 12 .. 15 ]; - my @dst_ip_subarray = @{$ip_hdr_bytes}[ 16 .. 19 ]; - - my $src_ip = - ( ( 2**24 ) * $src_ip_subarray[0] + - ( 2**16 ) * $src_ip_subarray[1] + - ( 2**8 ) * $src_ip_subarray[2] + - $src_ip_subarray[3] ); - - my $dst_ip = - ( ( 2**24 ) * $dst_ip_subarray[0] + - ( 2**16 ) * $dst_ip_subarray[1] + - ( 2**8 ) * $dst_ip_subarray[2] + - $dst_ip_subarray[3] ); - - # read IP_header protocol field - my $iph = $udp_pkt->{'IP_hdr'}; - my $proto = $$iph->proto(); - - my $match_args = { - wildcards => $wildcards, - in_port => $in_port, - dl_src => \@src_mac_subarray, - dl_dst => \@dst_mac_subarray, - dl_vlan => 0xffff, - dl_type => 0x0800, - nw_src => $src_ip, - nw_dst => $dst_ip, - nw_proto => $proto, #any protocol - tp_src => ${ $udp_pkt->{UDP_pdu} }->SrcPort, - tp_dst => ${ $udp_pkt->{UDP_pdu} }->DstPort - }; - - my $action_output_args = { - max_len => 0, # send entire packet - port => $out_port - }; - print "My Out Port: ${out_port}\n"; - - my $action_args = { - type => $enums{'OFPAT_OUTPUT'}, - arg => { output => $action_output_args } - }; - my $action = $ofp->pack( 'ofp_action', $action_args ); - - my $flow_mod_args = { - header => $hdr_args, - match => $match_args, - command => $enums{'OFPFC_ADD'}, - max_idle => $max_idle, - buffer_id => 0x0000, - group_id => 0 - }; - my $flow_mod = $ofp->pack( 'ofp_flow_mod', $flow_mod_args ); - - my $flow_mod_pkt = $flow_mod . $action; - - return $flow_mod_pkt; -} - -run_black_box_test( \&my_test, \@ARGV); - diff --git a/openflow/regress/projects/black_box/regress/test_ip_protocol/case-udp.pl b/openflow/regress/projects/black_box/regress/test_ip_protocol/case-udp.pl deleted file mode 100755 index 5f59ad32..00000000 --- a/openflow/regress/projects/black_box/regress/test_ip_protocol/case-udp.pl +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/perl -w -# test_ip_protocol (udp) - -use strict; -use OF::Includes; - -sub send_expect_exact { - - my ( $ofp, $sock, $in_port, $out_port, $max_idle, $pkt_len ) = @_; - - # in_port refers to the flow mod entry's input - - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - src_port => 70, - dst_port => 80 - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - #print HexDump ( $test_pkt->packed ); - - my $wildcards = 0x0; # exact match - my $flags = 0x0; # don't send flow expiry - - my $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, - $max_idle, $flags, $wildcards ); - - #print HexDump($flow_mod_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent flow_mod message\n"; - usleep(100000); - - # Send a packet - ensure packet comes out desired port - nftest_send( "eth" . ( $in_port + 1 ), $test_pkt->packed ); - nftest_expect( "eth" . ( $out_port + 1 ), $test_pkt->packed ); -} - -sub my_test { - - my ($sock, $options_ref) = @_; - - my $max_idle = $$options_ref{'max_idle'}; - my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_total = $$options_ref{'pkt_total'}; - - # send from every port to every other port - for ( my $i = 0 ; $i < 4 ; $i++ ) { - for ( my $j = 0 ; $j < 4 ; $j++ ) { - if ( $i != $j ) { - print "sending from $i to $j\n"; - send_expect_exact( $ofp, $sock, $i, $j, $max_idle, $pkt_len ); - wait_for_flow_expired_all( $ofp, $sock, $options_ref ); - } - } - } -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_llc/run.pl b/openflow/regress/projects/black_box/regress/test_llc/run.pl deleted file mode 100755 index 761f878d..00000000 --- a/openflow/regress/projects/black_box/regress/test_llc/run.pl +++ /dev/null @@ -1,128 +0,0 @@ -#!/usr/bin/perl -w -# test_llc (use $EthFMT = "LLC") -# if you want to test DIX format, use use $EthFMT = "DIX" - -use strict; -use OF::Includes; - -## choose one from "DIX" or "LLC"; -#my $EthFMT = "DIX"; -my $EthFMT = "LLC"; - -my $pkt_len_llc = 68; -my $pkt_len_dix = 60; - -my $pkt_len; -if ( $EthFMT eq "LLC" ) { - $pkt_len = $pkt_len_llc; - print "test for LLC\n"; -} -else { - $pkt_len = $pkt_len_dix; - print "test for DIX\n"; -} - -sub send_expect_exact_oneshot { - - my ( $ofp, $sock, $in_port, $out_port, $max_idle, $pkt_len ) = @_; - - my $test_pkt_llc_ip = new NF2::PDU($pkt_len_llc); - @{ $test_pkt_llc_ip->{'bytes'} }[ 0 .. ( $pkt_len_llc - 1 ) ] = ( - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, # dst mac 6byte (02:02:02:02:02:02) - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, # src mac 6byte (04:04:04:04:04:04) - 0x00, 0x36, # 2byte (Length=54byte=0x0036) - 0xAA, 0xAA, 0x03, #LLC # 3byte (always this value) - 0x00, 0x00, 0x00, #SNAP(OUI) # 3byte (always this value) - 0x08, 0x00, #SNAP(PID) # 2byte (0x0800 = IP) - 0x45, 0x00, 0x00, 0x2E, # 46 byte - 0x00, 0x00, 0x40, 0x00, # - 0x40, 0x11, 0xB8, 0x1E, # TTL=64, proto=UDP(0x11) - 0xC0, 0xA8, 0xC9, 0x28, # SrcIP= 192.168.201.40 - 0xC0, 0xA8, 0xC8, 0x28, # DstIP= 192.168.200.40 - 0x00, 0x46, 0x00, 0x50, # SrcPort=70, DstPort=80 - 0x00, 0x1A, 0xCD, 0x3F, # .. - 0xAE, 0xA5, 0x7F, 0x87, - 0xEE, 0x67, 0x72, 0xA7, - 0x17, 0x91, 0xFE, 0x10, - 0xBD, 0xFA, 0xC0, 0xC2, - 0x8B, 0xA7 - ); - - my $test_pkt_dix_ip = new NF2::PDU($pkt_len_dix); - @{ $test_pkt_dix_ip->{'bytes'} }[ 0 .. ( $pkt_len_dix - 1 ) ] = ( - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, # dst mac 6byte (02:02:02:02:02:02) - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, # src mac 6byte (04:04:04:04:04:04) - 0x08, 0x00, - 0x45, 0x00, 0x00, 0x2E, # 46 byte - 0x00, 0x00, 0x40, 0x00, # - 0x40, 0x11, 0xB8, 0x1E, # TTL=64, proto=UDP(0x11) - 0xC0, 0xA8, 0xC9, 0x28, # SrcIP= 192.168.201.40 - 0xC0, 0xA8, 0xC8, 0x28, # DstIP= 192.168.200.40 - 0x00, 0x46, 0x00, 0x50, # SrcPort=70, DstPort=80 - 0x00, 0x1A, 0xCD, 0x3F, # .. - 0xAE, 0xA5, 0x7F, 0x87, - 0xEE, 0x67, 0x72, 0xA7, - 0x17, 0x91, 0xFE, 0x10, - 0xBD, 0xFA, 0xC0, 0xC2, - 0x8B, 0xA7 - ); - - # Create Test Packet (only to call "create_flow_mod_from_udp") - # which should match test_pkt_llc_ip or test_pkt_dix packet - my $test_pkt_args = { - DA => "02:02:02:02:02:02", - SA => "04:04:04:04:04:04", - src_ip => "192.168.201.40", - dst_ip => "192.168.200.40", - ttl => 64, - len => $pkt_len, - src_port => 70, - dst_port => 80 - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - my $wildcards = 0x0; # exact match - my $flags = 0x0; # don't send flow expiry - my $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); - - #print HexDump($flow_mod_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent flow_mod message\n"; - usleep(100000); - - # Send a packet - ensure packet comes out desired port - if ( $EthFMT eq "LLC" ) { - nftest_send( "eth" . ( $in_port + 1 ), $test_pkt_llc_ip->packed ); - nftest_expect( "eth" . ( $out_port + 1 ), $test_pkt_llc_ip->packed ); - } - else { - nftest_send( "eth" . ( $in_port + 1 ), $test_pkt_dix_ip->packed ); - nftest_expect( "eth" . ( $out_port + 1 ), $test_pkt_dix_ip->packed ); - } -} - -sub my_test { - - my ($sock, $options_ref) = @_; - - my $max_idle = $$options_ref{'max_idle'}; - #my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_total = $$options_ref{'pkt_total'}; - - # send from every port to every other port - for ( my $i = 0 ; $i < 4 ; $i++ ) { - for ( my $j = 0 ; $j < 4 ; $j++ ) { - if ( $i != $j ) { - print "sending from $i to $j\n"; - send_expect_exact_oneshot( $ofp, $sock, $i, $j, $max_idle, $pkt_len ); - wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); - } - } - } -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_miss_send_length/run.pl b/openflow/regress/projects/black_box/regress/test_miss_send_length/run.pl deleted file mode 100755 index d787a624..00000000 --- a/openflow/regress/projects/black_box/regress/test_miss_send_length/run.pl +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/perl -w -# test_packet_in -# Send a packet of size 256B, and ensure that it gets reduced to 128B - -use strict; -use OF::Includes; - -sub verify_packet_in { - my ($sock, $options_ref, $miss_send_len, $pktsiz, $expected_pktsiz) = @_; - - my $in_port = $$options_ref{'port_base'}; - my $out_port = $in_port + 1; - - # Give OF switch time to process the set_config - usleep($$options_ref{'send_delay'}); - - my $pkt = get_default_black_box_pkt_len($in_port, $out_port, $pktsiz); - nftest_send('eth1', $pkt->packed); - print "Sent test packet for len ".$miss_send_len."...\n"; - - my $rcvd_msg; - sysread($sock, $rcvd_msg, 1512) || die "Failed to receive message: $!"; - - # Inspect message - my $msg_size = length($rcvd_msg); - compare("msg size", $msg_size, '==', $expected_pktsiz); - - my $msg = $ofp->unpack('ofp_packet_in', $rcvd_msg); - #print HexDump ($rcvd_msg); - #print Dumper($msg); - - # Verify fields - verify_header($msg, 'OFPT_PACKET_IN', $msg_size); - - # total len should be full length of original sent frame - compare("total len", $$msg{'total_len'}, '==', length($pkt->packed)); - compare("in_port", $$msg{'in_port'}, '==', $in_port); - compare("reason", $$msg{'reason'}, '==', $enums{'OFPR_NO_MATCH'}); - - # verify packet was unchanged! - my $rcvd_pkt_data = substr($rcvd_msg, $ofp->offsetof('ofp_packet_in', 'data')); - - # trim to MISS_SEND_LEN - my $pkt_trimmed = substr($pkt->packed, 0, $miss_send_len); - if ($rcvd_pkt_data ne $pkt_trimmed) { - die "ERROR: received packet data didn't match packet sent\n"; - } -} - -sub my_test { - my ($sock, $options_ref) = @_; - - my $miss_send_len = get_of_miss_send_len_default(); - my $pktsiz = 63; - my $expected_pktsiz = 8 + 10 + $pktsiz; - verify_packet_in($sock, $options_ref, $miss_send_len, $pktsiz, $expected_pktsiz); - - $miss_send_len = 0; - $pktsiz = 67; - $expected_pktsiz = 8 + 10; - set_config($ofp, $sock, $options_ref, 1, $miss_send_len); - verify_packet_in($sock, $options_ref, $miss_send_len, $pktsiz, $expected_pktsiz); - - $miss_send_len = 127; - $pktsiz = 259; - $expected_pktsiz = 8 + 10 + $miss_send_len; - set_config($ofp, $sock, $options_ref, 1, $miss_send_len); - verify_packet_in($sock, $options_ref, $miss_send_len, $pktsiz, $expected_pktsiz); - - $miss_send_len = 65535; - $pktsiz = 1500 - 8 - 10; - $expected_pktsiz = 1500; - set_config($ofp, $sock, $options_ref, 1, $miss_send_len); - verify_packet_in($sock, $options_ref, $miss_send_len, $pktsiz, $expected_pktsiz); - - set_config($ofp, $sock, $options_ref, 1, get_of_miss_send_len_default()); -} - -run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_packet_in/run.pl b/openflow/regress/projects/black_box/regress/test_packet_in/run.pl deleted file mode 100755 index 7ddfb830..00000000 --- a/openflow/regress/projects/black_box/regress/test_packet_in/run.pl +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/perl -w -# test_packet_in - -use strict; -use OF::Includes; - -sub my_test { - - my ($sock, $options_ref) = @_; - - my $in_port = $$options_ref{'port_base'}; - my $out_port = $in_port + 1; - - my $pkt = get_default_black_box_pkt( $in_port, $out_port); - nftest_send('eth1', $pkt->packed ); - print "Sent test packet...\n"; - - my $recvd_mesg; - sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; - - # Inspect message - my $msg_size = length($recvd_mesg); - my $expected_size = $ofp->offsetof( 'ofp_packet_in', 'data' ) + length( $pkt->packed ); - compare( "msg size", $msg_size, '==', $expected_size ); - - my $msg = $ofp->unpack( 'ofp_packet_in', $recvd_mesg ); - - #print HexDump ($recvd_mesg); - #print Dumper($msg); - - # Verify fields - verify_header( $msg, 'OFPT_PACKET_IN', $msg_size ); - - compare( "total len", $$msg{'total_len'}, '==', length( $pkt->packed ) ); - compare( "in_port", $$msg{'in_port'}, '==', $in_port ); - compare( "reason", $$msg{'reason'}, '==', $enums{'OFPR_NO_MATCH'} ); - - # verify packet was unchanged! - my $recvd_pkt_data = substr( $recvd_mesg, $ofp->offsetof( 'ofp_packet_in', 'data' ) ); - if ( $recvd_pkt_data ne $pkt->packed ) { - die "ERROR: received packet data didn't match packet sent\n"; - } -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_packet_out/run.pl b/openflow/regress/projects/black_box/regress/test_packet_out/run.pl deleted file mode 100755 index 4d872ac8..00000000 --- a/openflow/regress/projects/black_box/regress/test_packet_out/run.pl +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/perl -w -# test_packet_out - -use strict; -use OF::Includes; - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - my $port_base = $$options_ref{'port_base'}; - my $in_port = $port_base; - my $out_port = $in_port + 1; - - my $pkt = get_default_black_box_pkt( $in_port, $out_port ); - - my $hdr_args = { - version => get_of_ver(), - type => $enums{'OFPT_PACKET_OUT'}, - length => $ofp->sizeof('ofp_packet_out') + - $ofp->sizeof('ofp_action_output') + - length( $pkt->packed ), # should generate automatically! - xid => 0x0000abcd - }; - my $packet_out_args = { - header => $hdr_args, - buffer_id => -1, # data included in this packet - in_port => $enums{'OFPP_NONE'}, - actions_len => $ofp->sizeof('ofp_action_output') - }; - my $packet_out = $ofp->pack( 'ofp_packet_out', $packet_out_args ); - my $action_output_args = { - type => $enums{'OFPAT_OUTPUT'}, - len => $ofp->sizeof('ofp_action_output'), - port => $port_base, # send out eth1 - max_len => get_of_miss_send_len_default() - }; - my $action_output = $ofp->pack( 'ofp_action_output', $action_output_args ); - - my $pkt_sent = $packet_out . $action_output . $pkt->packed; - - # Send 'packet_out' message - print $sock $pkt_sent; - - nftest_expect( 'eth1', $pkt->packed ); - - # Wait for packet to be forwarded out - sleep(.1); - -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_port_stats/run.pl b/openflow/regress/projects/black_box/regress/test_port_stats/run.pl deleted file mode 100755 index 5c321c8d..00000000 --- a/openflow/regress/projects/black_box/regress/test_port_stats/run.pl +++ /dev/null @@ -1,132 +0,0 @@ -#!/usr/bin/perl -w -# test_port_stats - -use strict; -use OF::Includes; - -sub forward_any { - forward_simple(@_, 'any'); -} - -sub my_test { - my ($sock, $options_ref) = @_; - - my $port_base = $$options_ref{'port_base'}; - my $num_ports = $$options_ref{'num_ports'}; - - my $hdr_args = { - version => get_of_ver(), - type => $enums{'OFPT_STATS_REQUEST'}, - length => $ofp->sizeof('ofp_stats_request') + $ofp->sizeof('ofp_port_stats_request'), # should generate automatically! - xid => 0x00000000 - }; - - my $stats_reqhdr_args = { - header => $hdr_args, - type => $enums{'OFPST_PORT'}, - flags => 0 - }; - - my $stats_all_ports_reqbody_args = { - port_no => $enums{'OFPP_NONE'}, - }; - my $stats_single_port_reqbody_args = { - port_no => 1, - }; - my $stats_invalid_port_reqbody_args = { - port_no => 32768, - }; - - my $stats_reqhead = $ofp->pack('ofp_stats_request', $stats_reqhdr_args); - my $stats_all_ports_reqbody = $ofp->pack('ofp_port_stats_request', $stats_all_ports_reqbody_args); - my $stats_single_port_reqbody = $ofp->pack('ofp_port_stats_request', $stats_single_port_reqbody_args); - my $stats_invalid_port_reqbody = $ofp->pack('ofp_port_stats_request', $stats_invalid_port_reqbody_args); - my $stats_all_ports_reqmsg = $stats_reqhead . $stats_all_ports_reqbody; - my $stats_single_port_reqmsg = $stats_reqhead . $stats_single_port_reqbody; - my $stats_invalid_port_reqmsg = $stats_reqhead . $stats_invalid_port_reqbody; - - my $stats_rephdr_args = { - version => get_of_ver(), - type => $enums{'OFPT_STATS_REPLY'}, - length => $ofp->sizeof('ofp_stats_reply'), # should generate automatically! - xid => 0x00000000 - }; - - my $stats_repbody_args = { - header => $stats_rephdr_args, - type => $enums{'OFPST_PORT'}, - flags => 0 - }; - - my $stats_repbody; - for (my $i = $port_base; $i < $port_base + $num_ports; $i++ ) { - my $body_args = { - port_no => $port_base, - rx_count => 0, - tx_count => 0, - drop_count => 0 - }; - $stats_repbody .= $ofp->pack('ofp_port_stats', $body_args); - } - - my $stats_repmsg = $ofp->pack('ofp_stats_reply', $stats_repbody_args) . $stats_repbody; - my $rcvd_msg; - - # Send 'stats_request' for single port - print $sock $stats_single_port_reqmsg; - # Should add timeout here - will crash if no reply - sysread($sock, $rcvd_msg, 1512) || die "Failed to receive message: $!"; - - # Send 'stats_request' for invalid port - print $sock $stats_invalid_port_reqmsg; - # Should add timeout here - will crash if no reply - sysread($sock, $rcvd_msg, 1512) || die "Failed to receive message: $!"; - - # Send 'stats_request' for all ports - print $sock $stats_all_ports_reqmsg; - # Should add timeout here - will crash if no reply - sysread($sock, $rcvd_msg, 1512) || die "Failed to receive message: $!"; - - # Inspect message - my $msg_size = length($rcvd_msg); - my $expected_size = $ofp->sizeof('ofp_stats_reply') + 4 * $ofp->sizeof('ofp_port_stats'); - - # Removed this compare because varying numbers of ports may be activated - # compare("msg size", $msg_size, '==', $expected_size); - my $msg = $ofp->unpack('ofp_stats_reply', $rcvd_msg); - #print HexDump($rcvd_msg); - #print Dumper($msg); - - # Verify fields - verify_header($msg, 'OFPT_STATS_REPLY', $msg_size); - compare("type", $$msg{'type'}, '==', $enums{'OFPST_PORT'}); - compare("flags", $$msg{'flags'}, '==', 0); - -# if ($rcvd_msg ne $stats_reply) { -# die "stats reply is not what was expected" -# } - - # TODO: Look at each received port_stats field, to ensure they equal zero... - - # Send data plane packets - for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_any, 0x1fffff); - - # TODO: Look at each received port_stats field, to ensure correct counters - - # Send 'stats_request' for all ports - print $sock $stats_all_ports_reqmsg; - # Should add timeout here - will crash if no reply - sysread($sock, $rcvd_msg, 1512) || die "Failed to receive message: $!"; - - # Send 'stats_request' for invalid port - print $sock $stats_invalid_port_reqmsg; - # Should add timeout here - will crash if no reply - sysread($sock, $rcvd_msg, 1512) || die "Failed to receive message: $!"; - - # Send 'stats_request' for single port - print $sock $stats_single_port_reqmsg; - # Should add timeout here - will crash if no reply - sysread($sock, $rcvd_msg, 1512) || die "Failed to receive message: $!"; -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_queue_config/run.pl b/openflow/regress/projects/black_box/regress/test_queue_config/run.pl deleted file mode 100755 index e3f512ee..00000000 --- a/openflow/regress/projects/black_box/regress/test_queue_config/run.pl +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/perl -w -# test_queue_config - -use strict; -use OF::Includes; - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - if ( not defined( $$options_ref{'no_slicing'} ) ) { - my $port_base = $$options_ref{'port_base'}; - my $num_ports = $$options_ref{'num_ports'}; - - # for each port, - - for (my $i = 1; $i <= $num_ports; $i++){ - - my $hdr_args = { - version => get_of_ver(), - type => $enums{'OFPT_QUEUE_GET_CONFIG_REQUEST'}, - length => $ofp->sizeof('ofp_queue_get_config_request'), # should generate automatically! - xid => 0x00000000 - }; - - my @pad_2 = (0,0); - my $queue_request_args = { - header => $hdr_args, - port => $i, - pad => \@pad_2 - }; - - my $queue_request = $ofp->pack( 'ofp_queue_get_config_request', $queue_request_args ); - - # Send 'stats_request' message - print $sock $queue_request; - - # Should add timeout here - will crash if no reply - my $recvd_mesg; - sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; - - my $msg = $ofp->unpack( 'ofp_queue_get_config_reply', $recvd_mesg ); - - my $msg_size = length($recvd_mesg); - # Verify fields - verify_header( $msg, 'OFPT_QUEUE_GET_CONFIG_REPLY', $msg_size ); - } - } -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_queue_forward/run.pl b/openflow/regress/projects/black_box/regress/test_queue_forward/run.pl deleted file mode 100755 index a3b0d737..00000000 --- a/openflow/regress/projects/black_box/regress/test_queue_forward/run.pl +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/perl -w -# test_queue_forward - -use strict; -use OF::Includes; - -sub forward_unicast_port { - forward_simple(@_, 'enqueue'); -} - -sub my_test { - my ($sock, $options_ref) = @_; - - if ( not defined( $$options_ref{'no_slicing'} ) ) { - for_all_port_pairs($ofp, $sock, $options_ref, \&forward_unicast_port, 0x0); - } -} - -run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_queue_stats/run.pl b/openflow/regress/projects/black_box/regress/test_queue_stats/run.pl deleted file mode 100755 index 0f49a329..00000000 --- a/openflow/regress/projects/black_box/regress/test_queue_stats/run.pl +++ /dev/null @@ -1,116 +0,0 @@ -#!/usr/bin/perl -w -# test_queue_stats - -use strict; -use OF::Includes; - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - if ( not defined( $$options_ref{'no_slicing'} ) ) { - - my $port_base = $$options_ref{'port_base'}; - my $num_ports = $$options_ref{'num_ports'}; - - # Prepare stats request - my $hdr_args = { - version => get_of_ver(), - type => $enums{'OFPT_STATS_REQUEST'}, - length => $ofp->sizeof('ofp_stats_request') + $ofp->sizeof('ofp_queue_stats_request'), # should generate automatically! - xid => 0x00000000 - }; - - my @pad_2 = (0,0); - my $body_args = { - port_no => $port_base, - pad => \@pad_2, - queue_id => 0xffffffff # TODO : export get_define to get OFPQ_ALL - }; - - - my $stats_request_args = { - header => $hdr_args, - type => $enums{'OFPST_QUEUE'}, - flags => 0 - }; - - my $request_body = $ofp->pack( 'ofp_queue_stats_request', $body_args ); - my $stats_request = $ofp->pack( 'ofp_stats_request', $stats_request_args ) . $request_body; - - - # Prepare expected stats reply - my $reply_hdr_args = { - version => get_of_ver(), - type => $enums{'OFPT_STATS_REPLY'}, - length => $ofp->sizeof('ofp_stats_reply') + $ofp->sizeof('ofp_queue_stats'), # should generate automatically! - xid => 0x00000000 - }; - - my $stats_reply_args = { - header => $reply_hdr_args, - type => $enums{'OFPST_QUEUE'}, - flags => 0 - }; - - - my $reply_body_args = { - port_no => $port_base, - pad => \@pad_2, - queue_id => 1, - tx_bytes => 0, - tx_packets => 0, - tx_errors => 0 - }; - - my $reply_body = $ofp->pack( 'ofp_queue_stats', $reply_body_args); - my $stats_reply = $ofp->pack( 'ofp_stats_reply', $stats_reply_args ) . $reply_body; - - # Send 'stats_request' message - print $sock $stats_request; - - # Should add timeout here - will crash if no reply - my $recvd_mesg; - sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; - - # Inspect message - if ($recvd_mesg ne $stats_reply) { - die "ERROR: stats reply didn't match expected"; - } - - # Send a packet out - forward_simple($ofp, $sock, $options_ref, 1, 0, 0, 'enqueue'); - - # Wait the flow to expire - sleep 3; - - # Expect increased counters - $reply_body_args = { - port_no => $port_base, - pad => \@pad_2, - queue_id => 1, - tx_bytes => 64, - tx_packets => 1, - tx_errors => 0 - }; - - $reply_body = $ofp->pack( 'ofp_queue_stats', $reply_body_args); - $stats_reply = $ofp->pack( 'ofp_stats_reply', $stats_reply_args ) . $reply_body; - - - # Send 'stats_request' message - print $sock $stats_request; - - # Receive stats reply - sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; - - # Inspect message - if ($recvd_mesg ne $stats_reply) { - die "ERROR: stats reply didn't match expected"; - } - } - -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_receive_bandwidth_fixed/run.pl b/openflow/regress/projects/black_box/regress/test_receive_bandwidth_fixed/run.pl deleted file mode 100755 index 342845e9..00000000 --- a/openflow/regress/projects/black_box/regress/test_receive_bandwidth_fixed/run.pl +++ /dev/null @@ -1,89 +0,0 @@ -#!/usr/bin/perl -w -# test_receive_bandwidth_fixed - -use strict; -use OF::Includes; - -use Time::HiRes qw (sleep gettimeofday tv_interval usleep); - -my $pkts_total = 10000; -my $pkt_size = 64; -#my $pkt_size = 1512 - $ofp->sizeof( 'ofp_packet_in'); - -sub verify_packet_in { - - my ( $recvd_mesg, $pkt ) = @_; - - # Inspect message - my $msg_size = length($recvd_mesg); - my $expected_size = $ofp->offsetof( 'ofp_packet_in', 'data' ) + length( $pkt->packed ); - if ( $msg_size != $expected_size ) { return 1; } - - my $msg = $ofp->unpack( 'ofp_packet_in', $recvd_mesg ); - - # Verify fields - if ( ( $$msg{'header'}{'version'} != 1 ) - || ( $$msg{'header'}{'type'} != $enums{'OFPT_PACKET_IN'} ) - || ( $$msg{'header'}{'length'} != $msg_size ) - || ( $$msg{'total_len'} != length( $pkt->packed ) ) - || ( $$msg{'in_port'} != 0 ) - || ( $$msg{'reason'} != $enums{'OFPR_NO_MATCH'} ) ) - { - return 1; - } - - # verify packet was unchanged! - my $recvd_pkt_data = substr( $recvd_mesg, $ofp->offsetof( 'ofp_packet_in', 'data' ) ); - if ( $recvd_pkt_data ne $pkt->packed ) { return 1; } -} - -sub receive_fixed_bandwidth { - my ( $num_packets, $sock, $pkt, $interface ) = @_; - my $length = length( $pkt->packed ); - print "sending $num_packets packets\n"; - - my @start_time = gettimeofday(); - - my $errors = 0; - - for ( my $count = 0 ; $count < $num_packets ; $count++ ) { - - nftest_send( nftest_get_iface($interface), $pkt->packed ); - - my $recvd_mesg; - sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; - - $errors += verify_packet_in( $recvd_mesg, $pkt ); - } - - my $sending_time = tv_interval( \@start_time ); - print "time elapsed: $sending_time\n"; - print "errors: $errors\n"; - - my $bps = ($num_packets - $errors) * $length * 8 / $sending_time; - printf "bandwidth achieved: %.0f bps \n", $bps; - - return $errors; -} - -sub my_test { - - my ($sock) = @_; - - my $pkt_args = { - DA => "00:00:00:00:00:02", - SA => "00:00:00:00:00:01", - src_ip => "192.168.200.40", - dst_ip => "192.168.201.40", - ttl => 64, - len => $pkt_size - }; - my $pkt = new NF2::IP_pkt(%$pkt_args); - - my $errors = &receive_fixed_bandwidth( $pkts_total, $sock, $pkt, 'eth1' ); - - if ($errors > 0) { die "received errors"; } -} - -run_black_box_test( \&my_test ); - diff --git a/openflow/regress/projects/black_box/regress/test_send_bandwidth_fixed/run.pl b/openflow/regress/projects/black_box/regress/test_send_bandwidth_fixed/run.pl deleted file mode 100755 index 2941d74a..00000000 --- a/openflow/regress/projects/black_box/regress/test_send_bandwidth_fixed/run.pl +++ /dev/null @@ -1,140 +0,0 @@ -#!/usr/bin/perl -w -# test_send_bandwidth_fixed - -use strict; -use OF::Includes; - -use Time::HiRes qw (sleep gettimeofday tv_interval usleep); - -# Sends packets of the specified length, with specified data rate, over time = duration. -# Length is passed as a parameter and it should be also declared during packet's construction. - -sub send_fixed_bandwidth_unique { - my ( $rate, $duration, $sock, $pkt, $pkt_sent, $interface ) = @_; - my $length = length( $pkt->packed ); - my $num_packets = ( $rate * $duration ) / ( $length * 8 ); - my $inter_time = 1000000.0 * $duration / $num_packets; - - print "Running Test for a single packet size\n"; - print( -"Num Packets : $num_packets, Duration : $duration, Length : $length, InterTime : $inter_time Interface : $interface\n" - ); - - print "sending $num_packets packets\n"; - - my @start_time = gettimeofday(); - - my $count; - for ( $count = 0 ; $count < $num_packets ; $count++ ) { - - # Send 'packet_out' message - print $sock $pkt_sent; - nftest_expect( $interface, $pkt->packed ); - usleep($inter_time); - } - - my $sending_time = tv_interval(\@start_time); - print "time elapsed: $sending_time\n"; - - my $bps = $num_packets * $length * 8 / $sending_time; - print "bandwidth attempted: $rate (bps)\n"; - print "bandwidth achieved: $bps (bps)\n"; -} - -sub send_fixed_bandwidth_mixed { - my ( $rate, $duration, $sock, $pkt_sent_small,$pkt_sent_med,$pkt_sent_lrg,$pkt_small,$pkt_med,$pkt_lrg, $interface ) = @_; - my $len_s = length($pkt_small->packed); - my $len_m = length($pkt_med->packed); - my $len_l = length($pkt_lrg->packed); - my $num_loops = ( $rate * $duration ) / (( $len_s+$len_m+$len_l ) * 8 ); - my $num_packets = $num_loops*3; - my $inter_time = 1000000.0 * $duration / $num_packets; - - print "Running Test for different packet sizes\n"; - - print( -"Num Packets : $num_packets, Duration : $duration, Lengths : $len_s,$len_m,$len_l, InterTime : $inter_time Interface : $interface\n" - ); - - print "sending $num_packets packets\n"; - - my @start_time = gettimeofday(); - - my $count; - for ( $count = 0 ; $count < $num_loops ; $count++ ) { - - # Send 'packet_out' message - print $sock $pkt_sent_small; - nftest_expect( $interface, $pkt_small->packed ); - usleep($inter_time); - print $sock $pkt_sent_med; - nftest_expect( $interface, $pkt_med->packed ); - usleep($inter_time); - print $sock $pkt_sent_lrg; - nftest_expect( $interface, $pkt_lrg->packed ); - usleep($inter_time); - } - - my $sending_time = tv_interval(\@start_time); - print "time elapsed: $sending_time\n"; - - my $bps = $num_loops * ($len_s+$len_m+$len_l) * 8 / $sending_time; - print "bandwidth attempted: $rate(bps)\n"; - print "bandwidth achieved: $bps (bps)\n"; -} - - - -sub my_test { - - my $pkt_args = { - DA => "00:00:00:00:00:02", - SA => "00:00:00:00:00:01", - src_ip => "192.168.200.40", - dst_ip => "192.168.201.40", - ttl => 64, - len => 64 - }; - my $pkt_small = new NF2::IP_pkt(%$pkt_args); - $pkt_args->{ 'len' } = 256; - my $pkt_med = new NF2::IP_pkt(%$pkt_args); - $pkt_args->{ 'len' } = 512; - my $pkt_lrg = new NF2::IP_pkt(%$pkt_args); - - my $hdr_args = { - version => 1, - type => $enums{'OFPT_PACKET_OUT'}, - length => $ofp->sizeof('ofp_packet_out') + length( $pkt_small->packed ), # should generate automatically! - xid => 0x0000abcd - }; - my $packet_out_args = { - header => $hdr_args, - buffer_id => -1, # data included in this packet - in_port => $enums{'OFPP_NONE'}, - out_port => 0 # send out eth1 - }; - my $packet_out = $ofp->pack( 'ofp_packet_out', $packet_out_args ); - - my $pkt_sent_small = $packet_out . $pkt_small->packed; - $hdr_args->{'length'} = $ofp->sizeof('ofp_packet_out') + length( $pkt_med->packed ); - $packet_out_args->{'header'} = $hdr_args; - $packet_out = $ofp->pack( 'ofp_packet_out', $packet_out_args ); - my $pkt_sent_med = $packet_out . $pkt_med->packed; - $hdr_args->{'length'} = $ofp->sizeof('ofp_packet_out') + length( $pkt_lrg->packed ); - $packet_out_args->{'header'} = $hdr_args; - $packet_out = $ofp->pack( 'ofp_packet_out', $packet_out_args ); - my $pkt_sent_lrg = $packet_out . $pkt_lrg->packed; - - my ($sock) = @_; - - &send_fixed_bandwidth_unique( .1 * (10**6) ,5, $sock, $pkt_lrg, $pkt_sent_lrg, 'eth1' ); - - #&send_fixed_bandwidth_mixed( 5 * (10**5) ,5, $sock,$pkt_sent_small,$pkt_sent_med, $pkt_sent_lrg,$pkt_small,$pkt_med,$pkt_lrg,'eth1'); - - # Wait for test to finish - sleep(2); - -} - -run_black_box_test( \&my_test ); - diff --git a/openflow/regress/projects/black_box/regress/test_send_bandwidth_random/run.pl b/openflow/regress/projects/black_box/regress/test_send_bandwidth_random/run.pl deleted file mode 100755 index 0fc0b1ce..00000000 --- a/openflow/regress/projects/black_box/regress/test_send_bandwidth_random/run.pl +++ /dev/null @@ -1,141 +0,0 @@ -#!/usr/bin/perl -w -# test_send_bandwidth_fixed - -use strict; -use OF::Includes; - -use Time::HiRes qw (sleep gettimeofday tv_interval usleep); - -# Sends packets of the specified length, with specified data rate, over time = duration. -# A random interarrival time between packets is used, trying to fit the requested data rate. - -sub send_random_bandwidth_unique { - my ( $rate, $duration, $sock, $pkt, $pkt_sent, $interface ) = @_; - my $length = length( $pkt->packed ); - my $num_packets = ( $rate * $duration ) / ( $length * 8 ); - my $inter_time = 1000000.0 * $duration / $num_packets; - - print "Running Test for a single packet size\n"; - print( -"Num Packets : $num_packets, Duration : $duration, Length : $length, InterTime : $inter_time Interface : $interface\n" - ); - - print "sending $num_packets packets\n"; - - my @start_time = gettimeofday(); - my $sending_time = tv_interval(\@start_time); - - my $count = 0; - while($sending_time < $duration){ - # Send 'packet_out' message - print $sock $pkt_sent; - nftest_expect( $interface, $pkt->packed ); - usleep(int(rand(2*$inter_time))); - $count++; - $sending_time = tv_interval(\@start_time); - } - print "time elapsed: $sending_time (loops : $count) \n"; - - my $bps = $count * $length * 8 / $sending_time; - print "bandwidth attempted: $rate (bps)\n"; - print "bandwidth achieved: $bps (bps)\n"; -} - -sub send_random_bandwidth_mixed { - my ( $rate, $duration, $sock, $pkt_sent_small,$pkt_sent_med,$pkt_sent_lrg,$pkt_small,$pkt_med,$pkt_lrg, $interface ) = @_; - my $len_s = length($pkt_small->packed); - my $len_m = length($pkt_med->packed); - my $len_l = length($pkt_lrg->packed); - my $num_loops = ( $rate * $duration ) / (( $len_s+$len_m+$len_l ) * 8 ); - my $num_packets = $num_loops*3; - my $inter_time = 1000000.0 * $duration / $num_packets; - - print "Running Test for different packet sizes\n"; - print( -"Num Packets : $num_packets, Duration : $duration, Lengths : $len_s,$len_m,$len_l, InterTime : $inter_time Interface : $interface\n" - ); - - print "sending $num_packets packets\n"; - - my @start_time = gettimeofday(); - my $sending_time = tv_interval(\@start_time); - - my $count = 0; - while ($sending_time < $duration){ - # Send 'packet_out' message - print $sock $pkt_sent_small; - nftest_expect( $interface, $pkt_small->packed ); - usleep(int(rand(2*$inter_time))); - print $sock $pkt_sent_med; - nftest_expect( $interface, $pkt_med->packed ); - usleep(int(rand(2*$inter_time))); - print $sock $pkt_sent_lrg; - nftest_expect( $interface, $pkt_lrg->packed ); - usleep(int(rand(2*$inter_time))); - $count++; - $sending_time = tv_interval(\@start_time); - } - - print "time elapsed: $sending_time (loops : $count)\n"; - - my $bps = $count * ($len_s+$len_m+$len_l) * 8 / $sending_time; - print "bandwidth attempted: $rate(bps)\n"; - print "bandwidth achieved: $bps (bps)\n"; -} - - - -sub my_test { - - my $pkt_args = { - DA => "00:00:00:00:00:02", - SA => "00:00:00:00:00:01", - src_ip => "192.168.200.40", - dst_ip => "192.168.201.40", - ttl => 64, - len => 64 - }; - my $pkt_small = new NF2::IP_pkt(%$pkt_args); - $pkt_args->{ 'len' } = 256; - my $pkt_med = new NF2::IP_pkt(%$pkt_args); - $pkt_args->{ 'len' } = 512; - my $pkt_lrg = new NF2::IP_pkt(%$pkt_args); - - my $hdr_args = { - version => 1, - type => $enums{'OFPT_PACKET_OUT'}, - length => $ofp->sizeof('ofp_packet_out') + length( $pkt_small->packed ), # should generate automatically! - xid => 0x0000abcd - }; - my $packet_out_args = { - header => $hdr_args, - buffer_id => -1, # data included in this packet - in_port => $enums{'OFPP_NONE'}, - out_port => 0 # send out eth1 - }; - my $packet_out = $ofp->pack( 'ofp_packet_out', $packet_out_args ); - - my $pkt_sent_small = $packet_out . $pkt_small->packed; - $hdr_args->{'length'} = $ofp->sizeof('ofp_packet_out') + length( $pkt_med->packed ); - $packet_out_args->{'header'} = $hdr_args; - $packet_out = $ofp->pack( 'ofp_packet_out', $packet_out_args ); - my $pkt_sent_med = $packet_out . $pkt_med->packed; - $hdr_args->{'length'} = $ofp->sizeof('ofp_packet_out') + length( $pkt_lrg->packed ); - $packet_out_args->{'header'} = $hdr_args; - $packet_out = $ofp->pack( 'ofp_packet_out', $packet_out_args ); - my $pkt_sent_lrg = $packet_out . $pkt_lrg->packed; - - my ($sock) = @_; - - - &send_random_bandwidth_unique( .01 * (10**6) ,15, $sock, $pkt_lrg, $pkt_sent_lrg, 'eth1' ); - - #&send_random_bandwidth_mixed( 5 * (10**5) ,5, $sock,$pkt_sent_small,$pkt_sent_med, $pkt_sent_lrg,$pkt_small,$pkt_med,$pkt_lrg,'eth1'); - - # Wait for test to finish - sleep(2); - -} - -run_black_box_test( \&my_test ); - diff --git a/openflow/regress/projects/black_box/regress/test_set_dl_nw_flip/run.pl b/openflow/regress/projects/black_box/regress/test_set_dl_nw_flip/run.pl deleted file mode 100755 index fbf508b4..00000000 --- a/openflow/regress/projects/black_box/regress/test_set_dl_nw_flip/run.pl +++ /dev/null @@ -1,143 +0,0 @@ -#!/usr/bin/perl -w -# test_set_nw_dst - -use strict; -use OF::Includes; - -sub send_expect_exact { - my ($ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len) = @_; - - my $in_port = $in_port_offset + $$options_ref{'port_base'}; - my $out_port = $out_port_offset + $$options_ref{'port_base'}; - - # in_port refers to the flow mod entry's input - - # Create the payload ourselves to make sure the two packets match - # Jean II - my $pkt_payload = [map {int(rand(256))} (1..($pkt_len - 8 - 4 - 16 - 14))]; - - # This is the packet we are sending... - Jean II - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - tos => 0x0, - ttl => 64, - len => $pkt_len, - src_port => 1, - dst_port => 0, - data => $pkt_payload - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - # This is the packet we are expecting to receive - Jean II - my $expect_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - src_ip => "192.168.201." . ( $out_port ), - dst_ip => "192.168.200." . ( $in_port ), - tos => 0x0, - ttl => 64, - len => $pkt_len, - src_port => 1, - dst_port => 0, - data => $pkt_payload - }; - my $expect_pkt = new NF2::UDP_pkt(%$expect_pkt_args); - - #print HexDump ($test_pkt->packed); - - my $wildcards = 0x0; # exact match - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry - - # Get the various addresses in the expected packet - Jean II - my $chg_val_dl_da = ${$expect_pkt->{Ethernet_hdr}}->DA; - my $chg_val_dl_sa = ${$expect_pkt->{Ethernet_hdr}}->SA; - my $chg_val_nw_dst = ${$expect_pkt->{IP_hdr}}->dst_ip; - my $chg_val_nw_src = ${$expect_pkt->{IP_hdr}}->src_ip; - my @dl_da_addr_chg = NF2::PDU::get_MAC_address($chg_val_dl_da); - my @dl_sa_addr_chg = NF2::PDU::get_MAC_address($chg_val_dl_sa); - my $nw_dst_addr_chg; - my $ok_org; - ($nw_dst_addr_chg, $ok_org) = NF2::IP_hdr::getIP($chg_val_nw_dst); - my $nw_src_addr_chg; - ($nw_src_addr_chg, $ok_org) = NF2::IP_hdr::getIP($chg_val_nw_src); - - # Create the desired rewrite actions - my @pad_6 = (0,0,0,0,0,0); - my $action_mod_dl_da_args = { - type => $enums{'OFPAT_SET_DL_DST'}, - len => $ofp->sizeof('ofp_action_dl_addr'), - dl_addr => \@dl_da_addr_chg, - pad => \@pad_6, - }; - my $action_mod_dl_da = $ofp->pack('ofp_action_dl_addr', $action_mod_dl_da_args); - my $action_mod_dl_sa_args = { - type => $enums{'OFPAT_SET_DL_SRC'}, - len => $ofp->sizeof('ofp_action_dl_addr'), - dl_addr => \@dl_sa_addr_chg, - pad => \@pad_6, - }; - my $action_mod_dl_sa = $ofp->pack('ofp_action_dl_addr', $action_mod_dl_sa_args); - my $action_mod_nw_dst_args = { - type => $enums{'OFPAT_SET_NW_DST'}, - len => $ofp->sizeof('ofp_action_nw_addr'), - nw_addr => $nw_dst_addr_chg, - }; - my $action_mod_nw_dst = $ofp->pack( 'ofp_action_nw_addr', $action_mod_nw_dst_args ); - my $action_mod_nw_src_args = { - type => $enums{'OFPAT_SET_NW_SRC'}, - len => $ofp->sizeof('ofp_action_nw_addr'), - nw_addr => $nw_src_addr_chg, - }; - my $action_mod_nw_src = $ofp->pack( 'ofp_action_nw_addr', $action_mod_nw_src_args ); - - # Output action to get the packet out someplace - Jean II - my $action_output_args = { - type => $enums{'OFPAT_OUTPUT'}, - len => $ofp->sizeof('ofp_action_output'), - port => $out_port, - max_len => 0, # send entire packet - }; - my $action_output = $ofp->pack( 'ofp_action_output', $action_output_args ); - - # Aggregate all actions together - my $action_bytes = $action_mod_dl_da . $action_mod_dl_sa . $action_mod_nw_dst . $action_mod_nw_src . $action_output; - - my $flow_mod_pkt = - create_flow_mod_from_udp_actionbytes( $ofp, $test_pkt, $in_port, $max_idle, $flags, $wildcards, 'OFPFC_ADD', $action_bytes); - - #print HexDump($flow_mod_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent flow_mod message\n"; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - - # Send a packet - ensure packet comes out desired port - nftest_send("eth" . ($in_port_offset + 1), $test_pkt->packed); - nftest_expect("eth" . ($out_port_offset + 1), $expect_pkt->packed); -} - -sub test_set_nw_dst { - my ($ofp, $sock, $options_ref, $i, $j, $wildcards) = @_; - - my $max_idle = $$options_ref{'max_idle'}; - my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_total = $$options_ref{'pkt_total'}; - - send_expect_exact($ofp, $sock, $options_ref, $i, $j, $max_idle, $pkt_len); - wait_for_flow_expired($ofp, $sock, $options_ref, $pkt_len, $pkt_total); -} - -sub my_test { - my ($sock, $options_ref) = @_; - - # send from every port to every other port - for_all_port_pairs($ofp, $sock, $options_ref, \&test_set_nw_dst, 0x0); -} - -run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_set_n_match_nw_tos/run.pl b/openflow/regress/projects/black_box/regress/test_set_n_match_nw_tos/run.pl deleted file mode 100755 index 4470c812..00000000 --- a/openflow/regress/projects/black_box/regress/test_set_n_match_nw_tos/run.pl +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/perl -w -# test_set_nw_tos - -use strict; -use OF::Includes; - -# Please check the following : -# http://en.wikipedia.org/wiki/Type_of_Service - -sub send_expect_exact { - my ($ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len, $vlan_id) = @_; - - my $in_port = $in_port_offset + $$options_ref{'port_base'}; - my $out_port = $out_port_offset + $$options_ref{'port_base'}; - - # in_port refers to the flow mod entry's input - - # Create the payload ourselves to make sure the two packets match - # Jean II - my $pkt_payload = [map {int(rand(256))} (1..($pkt_len - 8 - 4 - 16 - 14))]; - - # This is the packet we are sending... - Jean II - # Set an ECN bit to see if it gets clobbered - my $test_nw_tos = 0xA8; - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - tos => $test_nw_tos | 0x01, # => 0xA9 - ttl => 64, - len => $pkt_len, - src_port => 1, - dst_port => 0, - data => $pkt_payload - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - # This is the packet we are expecting to receive - Jean II - my $expect_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - tos => 0x54 | 0x01, # 0x55 - ttl => 64, - len => $pkt_len, - src_port => 1, - dst_port => 0, - data => $pkt_payload - }; - my $expect_pkt = new NF2::UDP_pkt(%$expect_pkt_args); - - #print HexDump ($test_pkt->packed); - - my $wildcards = 0x0; # exact match - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry - # Don't set ECN bits here, OVS reject it as invalid... - my $nw_tos = 0x54; - - my $flow_mod_pkt = create_flow_mod_from_udp_action($ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards, 'OFPFC_ADD', 'nw_tos', $nw_tos, $vlan_id, $test_nw_tos); - - #print HexDump($flow_mod_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent flow_mod message\n"; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - - # Send a packet - ensure packet comes out desired port - nftest_send("eth" . ($in_port_offset + 1), $test_pkt->packed); - nftest_expect("eth" . ($out_port_offset + 1), $expect_pkt->packed); -} - -sub test_set_nw_tos { - my ($ofp, $sock, $options_ref, $i, $j, $wildcards) = @_; - - my $max_idle = $$options_ref{'max_idle'}; - my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_total = $$options_ref{'pkt_total'}; - - send_expect_exact($ofp, $sock, $options_ref, $i, $j, $max_idle, $pkt_len); - wait_for_flow_expired($ofp, $sock, $options_ref, $pkt_len, $pkt_total); -} - -sub my_test { - my ($sock, $options_ref) = @_; - - # send from every port to every other port - for_all_port_pairs( $ofp, $sock, $options_ref, \&test_set_nw_tos, 0x0); -} - -run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_set_nw_dst/run.pl b/openflow/regress/projects/black_box/regress/test_set_nw_dst/run.pl deleted file mode 100755 index ae101798..00000000 --- a/openflow/regress/projects/black_box/regress/test_set_nw_dst/run.pl +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/perl -w -# test_set_nw_dst - -use strict; -use OF::Includes; - -sub send_expect_exact { - my ($ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len) = @_; - - my $in_port = $in_port_offset + $$options_ref{'port_base'}; - my $out_port = $out_port_offset + $$options_ref{'port_base'}; - - # in_port refers to the flow mod entry's input - - # Create the payload ourselves to make sure the two packets match - # Jean II - my $pkt_payload = [map {int(rand(256))} (1..($pkt_len - 8 - 4 - 16 - 14))]; - - # This is the packet we are sending... - Jean II - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - tos => 0x0, - ttl => 64, - len => $pkt_len, - src_port => 1, - dst_port => 0, - data => $pkt_payload - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - # This is the packet we are expecting to receive - Jean II - my $expect_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - #dst_ip => "192.168.201." . ( $out_port + 1), - dst_ip => ( $out_port ) . ".201.168.192" , - tos => 0x0, - ttl => 64, - len => $pkt_len, - src_port => 1, - dst_port => 0, - data => $pkt_payload - }; - my $expect_pkt = new NF2::UDP_pkt(%$expect_pkt_args); - - #print HexDump ($test_pkt->packed); - - my $wildcards = 0x0; # exact match - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry - - # Get the IP address in the expected packet in binary form - Jean II - my $chg_val_nw_dst = ${$expect_pkt->{IP_hdr}}->dst_ip; - my $nw_dst_addr_chg; - my $ok_org; - ($nw_dst_addr_chg, $ok_org) = NF2::IP_hdr::getIP($chg_val_nw_dst); - - my $flow_mod_pkt = create_flow_mod_from_udp_action($ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards, 'OFPFC_ADD', 'nw_dst', $nw_dst_addr_chg); - - #print HexDump($flow_mod_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent flow_mod message\n"; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - - # Send a packet - ensure packet comes out desired port - nftest_send("eth" . ($in_port_offset + 1), $test_pkt->packed); - nftest_expect("eth" . ($out_port_offset + 1), $expect_pkt->packed); -} - -sub test_set_nw_dst { - my ($ofp, $sock, $options_ref, $i, $j, $wildcards) = @_; - - my $max_idle = $$options_ref{'max_idle'}; - my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_total = $$options_ref{'pkt_total'}; - - send_expect_exact($ofp, $sock, $options_ref, $i, $j, $max_idle, $pkt_len); - wait_for_flow_expired($ofp, $sock, $options_ref, $pkt_len, $pkt_total); -} - -sub my_test { - my ($sock, $options_ref) = @_; - - # send from every port to every other port - for_all_port_pairs($ofp, $sock, $options_ref, \&test_set_nw_dst, 0x0); -} - -run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_stats_desc/run.pl b/openflow/regress/projects/black_box/regress/test_stats_desc/run.pl deleted file mode 100755 index 9409ac9d..00000000 --- a/openflow/regress/projects/black_box/regress/test_stats_desc/run.pl +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/perl -w -# test_flow_stats - -use strict; -use OF::Includes; - -sub stats_desc_test { - - my ( $sock, $options_ref ) = @_; - - my $port_base = $$options_ref{'port_base'}; - - my $hdr_args = { - version => get_of_ver(), - type => $enums{'OFPT_STATS_REQUEST'}, - length => $ofp->sizeof('ofp_stats_request') , # should generate automatically! - xid => 0x00000001 - }; - - my $stats_request_args = { - header => $hdr_args, - type => $enums{'OFPST_DESC'}, - flags => 0 - }; - - my $stats_request = $ofp->pack( 'ofp_stats_request', $stats_request_args ); - - # Send 'stats_request' message - print $sock $stats_request; - - # Should add timeout here - will crash if no reply - my $recvd_mesg; - sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; - - # Inspect message - my $resp_size = length($recvd_mesg); - - my $resp_header = $ofp->unpack( 'ofp_stats_reply', $recvd_mesg ); - - #print HexDump ($recvd_mesg); - print Dumper($resp_header); - - # Verify fields - verify_header( $resp_header, 'OFPT_STATS_REPLY', $resp_size ); - - # Unmarshall embedded description - my $resp_body = $ofp->unpack('ofp_desc_stats', - substr($recvd_mesg, $ofp->offsetof('ofp_stats_reply', 'body'))); - print Dumper($resp_body); - print "keys: " . join(" ",keys %$resp_body) . "\n"; - my $key; - foreach $key (sort keys %$resp_body) - { - my $val = $resp_body->{$key}; - my $len = scalar(@{$val}); - printf("key=%s ref=%s len=%d val='%s'\n", - $key, - ref($val), - $len, - pack("c*", @{$val}) - #@{$val} - ); - } - - #die("forced death"); - die("Missing dp_desc in desc_stats") unless(defined($resp_body->{"dp_desc"})); - -} - -run_black_box_test( \&stats_desc_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_switch_config/run.pl b/openflow/regress/projects/black_box/regress/test_switch_config/run.pl deleted file mode 100755 index cbb4886e..00000000 --- a/openflow/regress/projects/black_box/regress/test_switch_config/run.pl +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/perl -w -# test_switch_config - -use strict; -use OF::Includes; - -sub my_test { - - my ($sock, $options_ref) = @_; - - my $msg = get_config( $ofp, $sock ); - - # Verify that the miss_send_len is set to the correct default - compare( "miss send len", $$msg{'miss_send_len'}, '==', get_of_miss_send_len_default() ); - - # As of OF v0.8.1, there was no default for flags - we assume 0 - # (don't send flow expiration messages) - compare( "flags", $$msg{'flags'}, '==', 0 ); - - # Now, we change the config and check that it has been committed - - # Set flag OFPC_SEND_FLOW_EXP, which has val 1, and should cause flow exps - my $flags = 1; - - # Change miss_send_len from the default - my $miss_send_len = 0x100; - - set_config($ofp, $sock, $options_ref, $flags, $miss_send_len); - - # Give OF switch time to process the set_config - usleep($$options_ref{'send_delay'}); - - $msg = get_config( $ofp, $sock ); - - compare( "miss send len", $$msg{'miss_send_len'}, '==', $miss_send_len ); - compare( "flags", $$msg{'flags'}, '==', $flags ); -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_tcp_options/run.pl b/openflow/regress/projects/black_box/regress/test_tcp_options/run.pl deleted file mode 100755 index b9025bb0..00000000 --- a/openflow/regress/projects/black_box/regress/test_tcp_options/run.pl +++ /dev/null @@ -1,170 +0,0 @@ -#!/usr/bin/perl -w -# test_tcp_options - -use strict; -use OF::Includes; - -sub create_flow_mod_from_ip { - - my ( $ofp, $udp_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards, $s_port, $d_port ) = @_; - - my $hdr_args = { - version => get_of_ver(), - type => $enums{'OFPT_FLOW_MOD'}, - length => $ofp->sizeof('ofp_flow_mod') + $ofp->sizeof('ofp_action_output'), - xid => 0x0000000 - }; - - # might be cleaner to convert the exported colon-hex MAC addrs - #print ${$udp_pkt->{Ethernet_hdr}}->SA . "\n"; - #print ${$test_pkt->{Ethernet_hdr}}->SA . "\n"; - my $ref_to_eth_hdr = ( $udp_pkt->{'Ethernet_hdr'} ); - my $ref_to_ip_hdr = ( $udp_pkt->{'IP_hdr'} ); - - # pointer to array - my $eth_hdr_bytes = $$ref_to_eth_hdr->{'bytes'}; - my $ip_hdr_bytes = $$ref_to_ip_hdr->{'bytes'}; - my @dst_mac_subarray = @{$eth_hdr_bytes}[ 0 .. 5 ]; - my @src_mac_subarray = @{$eth_hdr_bytes}[ 6 .. 11 ]; - - my @src_ip_subarray = @{$ip_hdr_bytes}[ 12 .. 15 ]; - my @dst_ip_subarray = @{$ip_hdr_bytes}[ 16 .. 19 ]; - - my $src_ip = - ( ( 2**24 ) * $src_ip_subarray[0] + - ( 2**16 ) * $src_ip_subarray[1] + - ( 2**8 ) * $src_ip_subarray[2] + - $src_ip_subarray[3] ); - - my $dst_ip = - ( ( 2**24 ) * $dst_ip_subarray[0] + - ( 2**16 ) * $dst_ip_subarray[1] + - ( 2**8 ) * $dst_ip_subarray[2] + - $dst_ip_subarray[3] ); - - # read IP_header protocol field - my $iph = $udp_pkt->{'IP_hdr'}; - my $proto = $$iph->proto(); - - my $match_args = { - wildcards => $wildcards, - in_port => $in_port, - dl_src => \@src_mac_subarray, - dl_dst => \@dst_mac_subarray, - dl_vlan => 0xffff, - dl_vlan_pcp => 0x00, - dl_type => 0x0800, - nw_src => $src_ip, - nw_dst => $dst_ip, - nw_proto => $proto, #any protocol - tp_src => $s_port, - tp_dst => $d_port - }; - - print "My Out Port: ${out_port}\n"; - my $action_output_args = { - type => $enums{'OFPAT_OUTPUT'}, - len => $ofp->sizeof('ofp_action_output'), - port => $out_port, - max_len => 0 # send entire packet - }; - my $action_output = $ofp->pack('ofp_action_output', $action_output_args); - - my $flow_mod_args = { - header => $hdr_args, - match => $match_args, - command => $enums{'OFPFC_ADD'}, - idle_timeout => $max_idle, - hard_timeout => $max_idle, - flags => $flags, - priority => 0, - buffer_id => -1 - }; - my $flow_mod = $ofp->pack( 'ofp_flow_mod', $flow_mod_args ); - - my $flow_mod_pkt = $flow_mod . $action_output; - - return $flow_mod_pkt; -} - -sub send_tcp_op_expect_exact { - - my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len ) = @_; - - my $in_port = $in_port_offset + $$options_ref{'port_base'}; - my $out_port = $out_port_offset + $$options_ref{'port_base'}; - - my $src_tcp_port = 70; - my $dst_tcp_port = 80; - - # in_port refers to the flow mod entry's input - my @tcp_payload = ( # 30 bytes - 0x00, 0x46, 0x00, 0x50, # $src_tcp_port, $dst_tcp_port (should set automatically) - 0x01, 0x23, 0x45, 0x67, #Seq - 0x01, 0x23, 0x45, 0x00, #Ack - 0x58, 0x23, 0x00, 0x11, #Offset, Flag, Win - 0xaa, 0xbb, 0x00, 0x00, #Chksum, Urgent - 0x03, 0x03, 0x02, 0x00, #TCP Option - 0xaa, 0xbb, 0xcc, 0xdd, #TCP Content - 0xee, 0xff #TCP Content - ); - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - proto => 6, # TCP protocol id - }; - - my $test_pkt = new NF2::IP_pkt(%$test_pkt_args); - my $payload = $test_pkt->{'payload'}; - $$payload->set_bytes(@tcp_payload); - - #print HexDump ( $test_pkt->packed ); - - #my $wildcards = 0; # exact match - my $wildcards = $enums{'OFPFW_TP_SRC'} | - $enums{'OFPFW_TP_DST'};# | - # $enums{'OFPFW_NW_PROTO'}; # wildcard match (don't care udp src/dst ports) - - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; - my $flow_mod_pkt = - create_flow_mod_from_ip( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards, - $src_tcp_port, $dst_tcp_port ); - - #print HexDump($flow_mod_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent flow_mod message\n"; - usleep($$options_ref{'send_delay'}); - - # Send a packet - ensure packet comes out desired port - nftest_send( "eth" . ( $in_port_offset + 1), $test_pkt->packed ); - nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); -} - -sub test_tcp_options { - my ( $ofp, $sock, $options_ref, $i, $j, $wildcards ) = @_; - - my $max_idle = $$options_ref{'max_idle'}; - #my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_len = 64; # len = 14(Ethr_hdr)+ 20(IP_header)+ 30(TCP_header+Option) - # = 64 (IPlen = 50) - my $pkt_total = $$options_ref{'pkt_total'}; - - send_tcp_op_expect_exact( $ofp, $sock, $options_ref, $i, $j, $max_idle, $pkt_len ); - #sleep(5); - wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); -} - -sub my_test { - my ( $sock, $options_ref ) = @_; - - # send from every port to every other port - for_all_port_pairs( $ofp, $sock, $options_ref, \&test_tcp_options, 0x0); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/tests.txt b/openflow/regress/projects/black_box/regress/tests.txt deleted file mode 100644 index f77158ec..00000000 --- a/openflow/regress/projects/black_box/regress/tests.txt +++ /dev/null @@ -1,103 +0,0 @@ -## two #'s = not tested; 1 # = worked once - -# Basic Tests -test_hello/run.pl -test_barrier/run.pl -test_packet_in/run.pl -test_packet_out/run.pl -test_switch_config/run.pl -test_flow_expired/run.pl -test_flow_expired_idle_timeout/run.pl -test_flow_expired_precision/run.pl -test_flow_expired_send_flow_exp/run.pl -test_miss_send_length/run.pl - -# Read State Tests -test_stats_desc/run.pl -test_port_stats/run.pl -test_flow_stats/run.pl -test_flow_stats_precision/run.pl - -## Forwarding Tests -test_forward_any_port/run.pl -test_forward_exact_port/run.pl -test_forward_broadcast_exact_port/run.pl -test_forward_exact_all/run.pl -test_forward_exact_controller/run.pl -test_forward_wildcard_port/run.pl -test_forward_wildcard_all/run.pl -test_forward_wildcard_controller/run.pl -test_forward_after_expiration/run.pl -test_forward_overlapping_flow_entries/run.pl -test_delete/run.pl -test_delete_strict/run.pl -test_delete_send_flow_exp/run.pl -test_drop_exact/run.pl - -## Modify Action Tests -test_forward_exact_modify_action/run.pl -test_forward_wildcard_modify_action/run.pl -test_flow_mod_check/run.pl -test_set_nw_dst/run.pl -test_set_n_match_nw_tos/run.pl -test_set_dl_nw_flip/run.pl - -## ICMP handling Tests -test_forward_exact_icmp_port/run.pl -test_forward_exact_icmp_all/run.pl -test_forward_exact_icmp_controller/run.pl -test_forward_exact_icmp_fool/run.pl -test_forward_wildcard_icmp_port/run.pl -test_forward_wildcard_icmp_all/run.pl -test_forward_wildcard_icmp_controller/run.pl -test_forward_wildcard_icmp_fool/run.pl - -## ARP handling Tests -test_forward_exact_arp_port/run.pl -test_forward_exact_arp_all/run.pl -test_forward_exact_arp_controller/run.pl -test_forward_exact_arp_fool/run.pl -test_forward_wildcard_arp_port/run.pl -test_forward_wildcard_arp_all/run.pl -test_forward_wildcard_arp_controller/run.pl -test_forward_wildcard_arp_fool/run.pl - -# Flow cookies -test_cookie_flow_expired/run.pl -test_cookie_flow_stats/run.pl - -## Slicing Tests - can be disable via --no_slicing -test_queue_config/run.pl -## These assume that there is a queue with queue_id=1 at port 1. -## Uncomment if your setup supports this. -## Should work OK with the reference implementation -#test_queue_stats/run.pl -test_queue_forward/run.pl - -## Unusual Data -test_ip_options/run.pl -##test_ip_protocol/run.pl -test_ip_offset/run.pl -test_tcp_options/run.pl -##test_llc/run.pl - -# Failover Tests -test_failover_startup/run.pl -test_failover_close/run.pl - -# BELOW NOT INCLUDED IN CURRRENT RELEASE -# WILL BE AVAILABLE SOON -# Stress Tests / Performance Evaluation -#test_send_bandwidth_fixed/run.pl -#test_send_bandwidth_random/run.pl -#test_add_flow_bandwidth/run.pl -#test_add_flow_latency/run.pl -#test_receive_bandwidth_fixed/run.pl -#test_receive_bandwidth_random/run.pl -#test_forward_bandwidth_fixed/run.pl -#test_forward_bandwidth_random/run.pl -#test_forward_latency/run.pl -#test_switch_bandwidth_random/run.pl -#test_switch_bandwidth_random/run.pl -# Additional Failover tests -#test_failover_stop_responding/run.pl diff --git a/openflow/regress/projects/controller_disconnect/regress/common/setup b/openflow/regress/projects/controller_disconnect/regress/common/setup deleted file mode 100755 index f796718c..00000000 --- a/openflow/regress/projects/controller_disconnect/regress/common/setup +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use Test::TestLib; -use OF::OFUtil; - -my $mapFile; -my $platform; -my $args; - -# Process command line options -unless ( - GetOptions ( - "map=s" => \$mapFile, - "common-st-args=s" => \$platform, - ) -) -{ - print "invalid command format\n"; - exit(1); -} - -if (defined($mapFile)) { - $args = "--map=$mapFile"; -} - -if (!defined($platform)) { - print "no platform defined\n"; - exit(1); -} -else { - print "platform = $platform\n"; -} - -$args .= " --emerg"; - -my $filename = "of_${platform}_setup.pl"; - -# exit if of_${platform}_setup.pl not in path -if (-e "$ENV{'OFT_ROOT'}/bin/$filename") { - #system("$filename " . $args . " 2> /dev/null > /dev/null"); - system("$ENV{'OFT_ROOT'}/bin/$filename " . $args ); - #setup_kmod(); - exit (0); -} else { - print "couldn't find setup file $filename\n"; - exit (1); -} diff --git a/openflow/regress/projects/controller_disconnect/regress/common/teardown b/openflow/regress/projects/controller_disconnect/regress/common/teardown deleted file mode 100755 index 6f1f8391..00000000 --- a/openflow/regress/projects/controller_disconnect/regress/common/teardown +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use Test::TestLib; -use OF::OFUtil; - -my $mapFile; -my $platform; -my $args; - -# Process command line options -unless ( - GetOptions ( - "map=s" => \$mapFile, - "common-st-args=s" => \$platform, - ) -) -{ - print "invalid command format\n"; - exit(1); -} - -if (defined($mapFile)) { - $args = "--map=$mapFile"; -} - -if (!defined($platform)) { - print "no platform defined\n"; - exit(1); -} -else { - print "platform = $platform\n"; -} - -my $filename = "of_${platform}_teardown.pl"; - -# exit if of_${platform}_setup.pl not in path -if (-e "$ENV{'OFT_ROOT'}/bin/$filename") { - #system("$filename " . $args . " 2> /dev/null > /dev/null"); - system("$ENV{'OFT_ROOT'}/bin/$filename " . $args ); - #teardown_kmod(); - exit (0); -} else { - print "couldn't find setup file $filename\n"; - exit (1); -} diff --git a/openflow/regress/projects/controller_disconnect/regress/test_emergency_table/run.pl b/openflow/regress/projects/controller_disconnect/regress/test_emergency_table/run.pl deleted file mode 100755 index 7e07a6c8..00000000 --- a/openflow/regress/projects/controller_disconnect/regress/test_emergency_table/run.pl +++ /dev/null @@ -1,107 +0,0 @@ -#!/usr/bin/perl -w -# test_emergency_table - -use strict; -use OF::Includes; -use OF::OFUtil; - -sub test_emergency_cache_first { - my ( $ofp, $sock, $options_ref, $i, $j, $wildcards ) = @_; - - my $max_idle = $$options_ref{'max_idle'}; - my $pkt_len = $$options_ref{'pkt_len'}; - my $in_port = $i + $$options_ref{'port_base'}; - my $out_port = $j + $$options_ref{'port_base'}; - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - src_port => 70, - dst_port => 80 - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - print "Set both normal and emergency flow table. Normal key must win\n"; - - # 1st flow entry -- exact match, normal flow table - my $max_idle_no_expire = 0; - my $normal_wildcards = 0x0; # exact match - my $normal_flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry - my $flow_mod_normal_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle_no_expire, $normal_flags, $normal_wildcards ); - - # 2nd flow entry -- wildcard match all, emergency flow table - my $emergency_wildcards = $enums{'OFPFW_ALL'}; # wildcard match all to the all ports - my $emergency_flags = $enums{'OFPFF_EMERG'}; - my $flow_mod_emergency_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $enums{'OFPP_ALL'}, $max_idle_no_expire, $emergency_flags, $emergency_wildcards ); - - #print HexDump($flow_mod_normal_pkt); - #print HexDump($flow_mod_emergency_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_normal_pkt; - print "sent flow_mod message (normal table)\n"; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - - # Send 2nd 'flow_mod' message - print $sock $flow_mod_emergency_pkt; - print "sent flow_mod message (emergency table)\n"; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - - # Send a packet - ensure packet comes out desired port - print "Verify packets are forwarded correctly\n"; - nftest_send( "eth" . ( $i + 1 ), $test_pkt->packed ); - nftest_expect( "eth" . ( $j + 1 ), $test_pkt->packed ); - - # Wait for ECHO_REQUEST but don't reply so that ofprotocol notices disconnection. - wait_for_echo_request ( $ofp, $sock, $options_ref, $ofp->sizeof('ofp_header')); - return $test_pkt; -} - -sub test_emergency_cache_second { - my ( $test_pkt, $options_ref, $i, $j ) = @_; - - print "sending from $i to $j, but expect the packet from all ports\n"; - nftest_send( "eth" . ( $i + 1 ), $test_pkt->packed ); - - # expect packets on all other interfaces - print "expect multiple packets\n"; - - for ( my $k = 0 ; $k < $$options_ref{'num_ports'} ; $k++ ) { - if ( $k != $i ) { - nftest_expect( "eth" . ( $k + 1), $test_pkt->packed ); - } - } -} - -sub my_test { - my ($sock, $options_ref) = @_; - - if ( not defined( $$options_ref{'no_emerg'} ) ) { - #This test uses two ports - my $inport = 0; - my $outport = 1; - my $wildcards = 0; #exact match - - # Wait until switch notices disconnection. it depends on implementation - my $wait_timer = 20; - - my $test_pkt = test_emergency_cache_first($ofp, $sock, $options_ref, $inport, $outport, $wildcards); - - # Wait until ofprotocol notices that connection is broken - sleep $wait_timer; - - # chek if the emergency table has become active - test_emergency_cache_second($test_pkt, $options_ref, $inport, $outport); - } -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/controller_disconnect/regress/tests.txt b/openflow/regress/projects/controller_disconnect/regress/tests.txt deleted file mode 100644 index 0d34d9b3..00000000 --- a/openflow/regress/projects/controller_disconnect/regress/tests.txt +++ /dev/null @@ -1,2 +0,0 @@ -test_emergency_table/run.pl -#test_reconnect/run.pl diff --git a/openflow/regress/projects/learning_switch/regress/common/setup b/openflow/regress/projects/learning_switch/regress/common/setup deleted file mode 100755 index 29653173..00000000 --- a/openflow/regress/projects/learning_switch/regress/common/setup +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use Test::TestLib; -use OF::OFUtil; - -my $mapFile; -my $platform; -my $args; - -# Process command line options -unless ( - GetOptions ( - "map=s" => \$mapFile, - "common-st-args=s" => \$platform, - ) -) -{ - print "invalid command format\n"; - exit(1); -} - -if (defined($mapFile)) { - $args = "--map=$mapFile"; -} - -if (!defined($platform)) { - print "no platform defined\n"; - exit(1); -} -else { - print "platform = $platform\n"; -} - -my $filename = "of_${platform}_setup.pl"; - -# exit if of_${platform}_setup.pl not in path -if (-e "$ENV{'OFT_ROOT'}/bin/$filename") { - system("$ENV{'OFT_ROOT'}/bin/$filename " . $args . " 2> /dev/null > /dev/null"); - #setup_kmod(); - exit (0); -} else { - print "couldn't find setup file $filename\n"; - exit (1); -} diff --git a/openflow/regress/projects/learning_switch/regress/common/teardown b/openflow/regress/projects/learning_switch/regress/common/teardown deleted file mode 100755 index c1813189..00000000 --- a/openflow/regress/projects/learning_switch/regress/common/teardown +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use Test::TestLib; -use OF::OFUtil; - -my $mapFile; -my $platform; -my $args; - -# Process command line options -unless ( - GetOptions ( - "map=s" => \$mapFile, - "common-st-args=s" => \$platform, - ) -) -{ - print "invalid command format\n"; - exit(1); -} - -if (defined($mapFile)) { - $args = "map=$mapFile"; -} - -if (!defined($platform)) { - print "no platform defined\n"; - exit(1); -} -else { - print "platform = $platform\n"; -} - -my $filename = "of_${platform}_teardown.pl"; - -# exit if of_${platform}_setup.pl not in path -if (-e "$ENV{'OFT_ROOT'}/bin/$filename") { - system("$ENV{'OFT_ROOT'}/bin/$filename " . $args . " 2> /dev/null > /dev/null"); - #teardown_kmod(); - exit (0); -} else { - print "couldn't find setup file $filename\n"; - exit (1); -} diff --git a/openflow/regress/projects/learning_switch/regress/test_broadcast/run.pl b/openflow/regress/projects/learning_switch/regress/test_broadcast/run.pl deleted file mode 100755 index f721f4db..00000000 --- a/openflow/regress/projects/learning_switch/regress/test_broadcast/run.pl +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/perl -w -# test_broadcast - -use strict; -use OF::Includes; - -sub gen_broadcast_pkt { - my ($portNum) = shift; - - my $pkt_args = { - DA => "FF:FF:FF:FF:FF:FF", - SA => "00:00:00:00:00:0" . $portNum, - src_ip => "192.168." . $portNum . ".40", - dst_ip => "255.255.255.255", - ttl => 64, - len => 64 - }; - my $pkt = new NF2::IP_pkt(%$pkt_args); - return $pkt; -} - -sub send_expect_broadcast { - my ( $portNum, $pkt, $delta_ref ) = @_; - - send_and_count( 'eth' . $portNum, $pkt->packed, $delta_ref ); - for ( my $i = 1 ; $i <= 4 ; $i++ ) { - if ( $i != $portNum ) { - expect_and_count( 'eth' . $i, $pkt->packed, $delta_ref ); - } - } -} - -sub my_test { - - my %delta; - - for ( my $i = 1 ; $i < 4 ; $i++ ) { - my $pkt = gen_broadcast_pkt($i); - - # send one broadcast packet, then do it again on the same port - send_expect_broadcast( $i, $pkt, \%delta ); - sleep 0.1; - send_expect_broadcast( $i, $pkt, \%delta ); - sleep 0.1; - } - - return %delta; -} - -run_learning_switch_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/learning_switch/regress/test_forward_bandwidth/run.pl b/openflow/regress/projects/learning_switch/regress/test_forward_bandwidth/run.pl deleted file mode 100755 index 473afa81..00000000 --- a/openflow/regress/projects/learning_switch/regress/test_forward_bandwidth/run.pl +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/perl -w -#test_unicast_unknown - -use Test::TestLib; -use Test::PacketLib; -use OF::OFUtil; -use Time::HiRes qw(sleep gettimeofday tv_interval usleep); -use strict; - -sub my_test { - my $cnt = 0; - my %delta; - my $pkt_len = 1512; - - my $pkt_args = { - DA => "00:01:00:00:00:02", - SA => "00:00:00:00:00:01", - src_ip => "192.168.0.40", - dst_ip => "192.168.0.41", - ttl => 64, - len => 64 - }; - my $pkt = new NF2::IP_pkt(%$pkt_args); - - # send one packet; controller should learn MAC, add a flow - # entry, and send this packet out the other interfaces - - send_and_count( nftest_get_iface('eth1'), $pkt->packed, \%delta ); - expect_and_count( nftest_get_iface('eth2'), $pkt->packed, \%delta ); - expect_and_count( nftest_get_iface('eth3'), $pkt->packed, \%delta ); - expect_and_count( nftest_get_iface('eth4'), $pkt->packed, \%delta ); - - my @start_time = gettimeofday(); - for ( $cnt = 10 ; $cnt < 20 ; $cnt++ ) { - for ( my $t = 10 ; $t < 100 ; $t++ ) { - my $pkt_args = { - DA => "00:00:00:00:00:01", - SA => "00:00:00:00:$t:$cnt", - src_ip => "192.168.$t.$cnt", - dst_ip => "192.168.1.40", - ttl => 64, - len => $pkt_len - }; - my $pkt = new NF2::IP_pkt(%$pkt_args); - - send_and_count( nftest_get_iface('eth2'), $pkt->packed, \%delta ); - expect_and_count( nftest_get_iface('eth1'), $pkt->packed, \%delta ); - } - } - ( my $second, my $micro ) = tv_interval( \@start_time ); - my $time_elapsed = ( $second + $micro * 1e-6 ); - - my $bw_result = (900 * $pkt_len * 8) / $time_elapsed; - print "PACKET LENGTH: $pkt_len \n"; - print "TIME ELAPSED: $time_elapsed \n"; - print "RESULTING BW: $bw_result bits/sec \n"; - - return %delta; -} - -# how do we pass the cmd-line arguments to the script? -run_learning_switch_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/learning_switch/regress/test_forward_latency/run.pl b/openflow/regress/projects/learning_switch/regress/test_forward_latency/run.pl deleted file mode 100755 index e9690d80..00000000 --- a/openflow/regress/projects/learning_switch/regress/test_forward_latency/run.pl +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/perl -w -#test_fwd_delay -# send 1000 packets to find latency for both new flows and existing ones - -use Test::TestLib; -use Test::PacketLib; -use OF::OFUtil; -use strict; -use Time::HiRes qw(sleep gettimeofday tv_interval usleep); - -sub my_test { - my $cnt = 0; - - my $start_time_ref = [gettimeofday]; - my %delta; - for ( my $t = 10 ; $t < 20 ; $t++ ) { - for ( $cnt = 10 ; $cnt < 100 ; $cnt++ ) { - my $pkt_args = { - DA => "00:01:00:00:$t:$cnt", - SA => "00:00:00:00:00:01", - src_ip => "192.168.0.40", - dst_ip => "192.168.$cnt.$t", - ttl => 64, - len => 64 - }; - my $pkt = new NF2::IP_pkt(%$pkt_args); - - # send one packet; controller should learn MAC, add a flow - # entry, and send this packet out the other interfaces - send_and_count( nftest_get_iface('eth1'), $pkt->packed, \%delta ); - expect_and_count( nftest_get_iface('eth2'), $pkt->packed, \%delta ); - expect_and_count( nftest_get_iface('eth3'), $pkt->packed, \%delta ); - expect_and_count( nftest_get_iface('eth4'), $pkt->packed, \%delta ); - } - } - my $total_time_unknown = tv_interval( $start_time_ref ); - - $start_time_ref = [gettimeofday()]; - for ( $cnt = 10 ; $cnt < 20 ; $cnt++ ) { - for ( my $t = 10 ; $t < 100 ; $t++ ) { - my $pkt_args = { - DA => "00:00:00:00:00:01", - SA => "00:00:00:00:$t:$cnt", - src_ip => "192.168.$t.$cnt", - dst_ip => "192.168.1.40", - ttl => 64, - len => 64 - }; - my $pkt = new NF2::IP_pkt(%$pkt_args); - - # send packet; flow entries are already added for these - send_and_count( nftest_get_iface('eth2'), $pkt->packed, \%delta ); - expect_and_count( nftest_get_iface('eth1'), $pkt->packed, \%delta ); - } - } - my $total_time_known = tv_interval( $start_time_ref ); - - # convert to ms, and consider that we sent 900 packets each - my $time_unknown_ms = $total_time_unknown * 1000 / 900; - my $time_known_ms = $total_time_known * 1000 / 900; - - printf("Delay with unknown MAC: %.3f ms\n", $time_unknown_ms); - printf("Delay with known MAC: %.3f ms\n", $time_known_ms); - - return %delta; -} - -# how do we pass the cmd-line arguments to the script? -run_learning_switch_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/learning_switch/regress/test_hub_connected/run.pl b/openflow/regress/projects/learning_switch/regress/test_hub_connected/run.pl deleted file mode 100755 index f5881672..00000000 --- a/openflow/regress/projects/learning_switch/regress/test_hub_connected/run.pl +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/perl -w -# test_same_port? - -use strict; -use OF::Includes; - -sub my_test { - - my %delta; - - # Host A and B are both on p0. they send unicast with unknown dest. - - my $pkt_args = { - DA => "00:00:00:00:00:09", - SA => "00:00:00:00:00:01", - src_ip => "192.168.0.40", - dst_ip => "192.168.7.40", - ttl => 64, - len => 64 - }; - my $pkt = new NF2::IP_pkt(%$pkt_args); - - # send one packet; controller should learn MAC, add a flow - # entry, and send this packet out the other interfaces - print "Sending now: \n"; - send_and_count( 'eth1', $pkt->packed, \%delta ); - expect_and_count( 'eth2', $pkt->packed, \%delta ); - expect_and_count( 'eth3', $pkt->packed, \%delta ); - expect_and_count( 'eth4', $pkt->packed, \%delta ); - - # sleep as long as needed for the test to finish - sleep 0.1; - - my $pkt_args = { - DA => "00:00:00:00:00:08", - SA => "00:00:00:00:00:02", - src_ip => "192.168.1.40", - dst_ip => "192.168.6.40", - ttl => 64, - len => 64 - }; - my $pkt = new NF2::IP_pkt(%$pkt_args); - send_and_count( 'eth1', $pkt->packed, \%delta ); - expect_and_count( 'eth2', $pkt->packed, \%delta ); - expect_and_count( 'eth3', $pkt->packed, \%delta ); - expect_and_count( 'eth4', $pkt->packed, \%delta ); - sleep 0.1; - - # Now A and B try to talk to each other. see if switch drop the packet or not - - my $pkt_args = { - DA => "00:00:00:00:00:02", - SA => "00:00:00:00:00:01", - src_ip => "192.168.0.40", - dst_ip => "192.168.1.40", - ttl => 64, - len => 64 - }; - my $pkt = new NF2::IP_pkt(%$pkt_args); - send_and_count( 'eth1', $pkt->packed, \%delta ); - return %delta; -} - -run_learning_switch_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/learning_switch/regress/test_unicast_known/run.pl b/openflow/regress/projects/learning_switch/regress/test_unicast_known/run.pl deleted file mode 100755 index 34c2c09d..00000000 --- a/openflow/regress/projects/learning_switch/regress/test_unicast_known/run.pl +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/perl -w -# test_unicast_known - -use strict; -use OF::Includes; - -sub my_test { - - my $pkt_args = { - DA => "00:00:00:00:00:02", - SA => "00:00:00:00:00:01", - src_ip => "192.168.0.40", - dst_ip => "192.168.1.40", - ttl => 64, - len => 64 - }; - my $pkt = new NF2::IP_pkt(%$pkt_args); - - my %delta; - - # send one packet; controller should learn MAC, add a flow - # entry, and send this packet out the other interfaces - print "Sending now: \n"; - send_and_count( 'eth1', $pkt->packed, \%delta ); - expect_and_count( 'eth2', $pkt->packed, \%delta ); - expect_and_count( 'eth3', $pkt->packed, \%delta ); - expect_and_count( 'eth4', $pkt->packed, \%delta ); - sleep(.1); - - $pkt_args = { - DA => "00:00:00:00:00:01", - SA => "00:00:00:00:00:02", - src_ip => "192.168.1.40", - dst_ip => "192.168.0.40", - ttl => 64, - len => 64 - }; - $pkt = new NF2::IP_pkt(%$pkt_args); - send_and_count( 'eth2', $pkt->packed, \%delta ); - expect_and_count( 'eth1', $pkt->packed, \%delta ); - sleep(.1); - - $pkt_args = { - DA => "00:00:00:00:00:01", - SA => "00:00:00:00:00:03", - src_ip => "192.168.2.40", - dst_ip => "192.168.0.40", - ttl => 64, - len => 64 - }; - $pkt = new NF2::IP_pkt(%$pkt_args); - send_and_count( 'eth3', $pkt->packed, \%delta ); - expect_and_count( 'eth1', $pkt->packed, \%delta ); - sleep(.1); - - $pkt_args = { - DA => "00:00:00:00:00:01", - SA => "00:00:00:00:00:04", - src_ip => "192.168.3.40", - dst_ip => "192.168.0.40", - ttl => 64, - len => 64 - }; - $pkt = new NF2::IP_pkt(%$pkt_args); - send_and_count( 'eth4', $pkt->packed, \%delta ); - expect_and_count( 'eth1', $pkt->packed, \%delta ); - - return %delta; -} - -run_learning_switch_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/learning_switch/regress/test_unicast_move/run.pl b/openflow/regress/projects/learning_switch/regress/test_unicast_move/run.pl deleted file mode 100755 index 5bc4670d..00000000 --- a/openflow/regress/projects/learning_switch/regress/test_unicast_move/run.pl +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/perl -w -# test_unicast_move - -use strict; -use OF::Includes; - -sub my_test { - - my %delta; - - # host A's MAC address is 00:00:00:00:00:01 - - my $pkt_args = { - DA => "00:00:00:00:00:02", - SA => "00:00:00:00:00:01", - src_ip => "192.168.0.40", - dst_ip => "192.168.1.40", - ttl => 64, - len => 64 - }; - my $pkt = new NF2::IP_pkt(%$pkt_args); - - # send one packet; controller should learn MAC, add a flow - # entry, and send this packet out the other interfaces - print "Sending now: \n"; - send_and_count( 'eth1', $pkt->packed, \%delta ); - expect_and_count( 'eth2', $pkt->packed, \%delta ); - expect_and_count( 'eth3', $pkt->packed, \%delta ); - expect_and_count( 'eth4', $pkt->packed, \%delta ); - - # sleep as long as needed for the test to finish - sleep 0.1; - - $pkt_args = { - DA => "00:00:00:00:00:01", - SA => "00:00:00:00:00:02", - src_ip => "192.168.1.40", - dst_ip => "192.168.0.40", - ttl => 64, - len => 64 - }; - $pkt = new NF2::IP_pkt(%$pkt_args); - send_and_count( 'eth2', $pkt->packed, \%delta ); - expect_and_count( 'eth1', $pkt->packed, \%delta ); - sleep 0.1; - - #Now Host A Has Changed Location and Attached to p2 - #It will send a packet to p1 form its new location - $pkt_args = { - DA => "00:00:00:00:00:02", - SA => "00:00:00:00:00:01", - src_ip => "192.168.2.40", - dst_ip => "192.168.1.40", - ttl => 64, - len => 64 - }; - $pkt = new NF2::IP_pkt(%$pkt_args); - send_and_count( 'eth3', $pkt->packed, \%delta ); - expect_and_count( 'eth2', $pkt->packed, \%delta ); - sleep 0.1; - - # Now p1 sends something to Host A which is now attached to p2 - # we expect the switch to already updated its entry for Host A - $pkt_args = { - DA => "00:00:00:00:00:01", - SA => "00:00:00:00:00:02", - src_ip => "192.168.1.40", - dst_ip => "192.168.2.40", - ttl => 64, - len => 64 - }; - $pkt = new NF2::IP_pkt(%$pkt_args); - send_and_count( 'eth2', $pkt->packed, \%delta ); - expect_and_count( 'eth3', $pkt->packed, \%delta ); - - return %delta; -} - -run_learning_switch_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/learning_switch/regress/test_unicast_multiple_hosts/run.pl b/openflow/regress/projects/learning_switch/regress/test_unicast_multiple_hosts/run.pl deleted file mode 100755 index 73c0807b..00000000 --- a/openflow/regress/projects/learning_switch/regress/test_unicast_multiple_hosts/run.pl +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/perl -w -# test_unicast_multiple_hosts - -use strict; -use OF::Includes; - -sub my_test { - - my %delta; - - my $pkt_args = { - DA => "00:00:00:00:00:02", - SA => "00:00:00:00:00:01", - src_ip => "192.168.0.40", - dst_ip => "192.168.1.40", - ttl => 64, - len => 64 - }; - my $pkt = new NF2::IP_pkt(%$pkt_args); - - # send one packet; controller should learn MAC, add a flow - # entry, and send this packet out the other interfaces - print "Sending now: \n"; - send_and_count( 'eth1', $pkt->packed, \%delta ); - expect_and_count( 'eth2', $pkt->packed, \%delta ); - expect_and_count( 'eth3', $pkt->packed, \%delta ); - expect_and_count( 'eth4', $pkt->packed, \%delta ); - - # sleep as long as needed for the test to finish - sleep 0.5; - my $count = 10; - my $cnt = 10; - - for ( $cnt = 11 ; $cnt < 21 ; $cnt++ ) { - for ( $count = 10 ; $count < 12 ; $count++ ) { - - $pkt_args = { - DA => "00:00:00:00:00:01", - SA => "00:00:00:$cnt:10:$count", - src_ip => "192.168.$count.$cnt", - dst_ip => "192.168.0.40", - ttl => 64, - len => 64 - }; - $pkt = new NF2::IP_pkt(%$pkt_args); - send_and_count( 'eth2', $pkt->packed, \%delta ); - expect_and_count( 'eth1', $pkt->packed, \%delta ); - sleep 0.1; - - } - } - - for ( $cnt = 21 ; $cnt < 31 ; $cnt++ ) { - for ( $count = 10 ; $count < 12 ; $count++ ) { - - $pkt_args = { - DA => "00:00:00:00:00:01", - SA => "00:00:00:$cnt:11:$count", - src_ip => "192.168.$count.$cnt", - dst_ip => "192.168.0.40", - ttl => 64, - len => 64 - }; - $pkt = new NF2::IP_pkt(%$pkt_args); - send_and_count( 'eth3', $pkt->packed, \%delta ); - expect_and_count( 'eth1', $pkt->packed, \%delta ); - sleep 0.1; - } - } - - for ( $cnt = 31 ; $cnt < 41 ; $cnt++ ) { - for ( $count = 10 ; $count < 12 ; $count++ ) { - - $pkt_args = { - DA => "00:00:00:00:00:01", - SA => "00:00:00:$cnt:12:$count", - src_ip => "192.168.$count.$cnt", - dst_ip => "192.168.0.40", - ttl => 64, - len => 64 - }; - $pkt = new NF2::IP_pkt(%$pkt_args); - send_and_count( 'eth4', $pkt->packed, \%delta ); - expect_and_count( 'eth1', $pkt->packed, \%delta ); - sleep 0.1; - - } - } - - return %delta; -} - -run_learning_switch_test( \&my_test, \@ARGV ); \ No newline at end of file diff --git a/openflow/regress/projects/learning_switch/regress/test_unicast_self/run.pl b/openflow/regress/projects/learning_switch/regress/test_unicast_self/run.pl deleted file mode 100755 index 4db2371b..00000000 --- a/openflow/regress/projects/learning_switch/regress/test_unicast_self/run.pl +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/perl -w -# test_unicast_self - -use strict; -use OF::Includes; - -sub my_test { - - my %delta; - - # Send packets with same DA and SA; should be ignored - my $pkt_args = { - DA => "00:00:00:00:00:01", - SA => "00:00:00:00:00:01", - src_ip => "192.168.0.40", - dst_ip => "192.168.0.40", - ttl => 64, - len => 64 - }; - my $pkt = new NF2::IP_pkt(%$pkt_args); - - print "Sending now: \n"; - send_and_count( 'eth1', $pkt->packed, \%delta ); - - $pkt_args = { - DA => "00:00:00:00:00:02", - SA => "00:00:00:00:00:02", - src_ip => "192.168.1.40", - dst_ip => "192.168.1.40", - ttl => 64, - len => 64 - }; - $pkt = new NF2::IP_pkt(%$pkt_args); - send_and_count( 'eth2', $pkt->packed, \%delta ); - - $pkt_args = { - DA => "00:00:00:00:00:03", - SA => "00:00:00:00:00:03", - src_ip => "192.168.2.40", - dst_ip => "192.168.2.40", - ttl => 64, - len => 64 - }; - $pkt = new NF2::IP_pkt(%$pkt_args); - send_and_count( 'eth3', $pkt->packed, \%delta ); - - $pkt_args = { - DA => "00:00:00:00:00:04", - SA => "00:00:00:00:00:04", - src_ip => "192.168.3.40", - dst_ip => "192.168.3.40", - ttl => 64, - len => 64 - }; - $pkt = new NF2::IP_pkt(%$pkt_args); - send_and_count( 'eth4', $pkt->packed, \%delta ); - - return %delta; -} - -run_learning_switch_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/learning_switch/regress/test_unicast_unknown/run.pl b/openflow/regress/projects/learning_switch/regress/test_unicast_unknown/run.pl deleted file mode 100755 index 4378ae00..00000000 --- a/openflow/regress/projects/learning_switch/regress/test_unicast_unknown/run.pl +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/perl -w -#test_unicast_unknown - -use strict; -use OF::Includes; - -sub my_test { - - my $pkt_args = { - DA => "00:00:00:00:00:02", - SA => "00:00:00:00:00:01", - src_ip => "192.168.0.40", - dst_ip => "192.168.1.40", - ttl => 64, - len => 64 - }; - my $pkt = new NF2::IP_pkt(%$pkt_args); - - my %delta; - - # send one packet; controller should learn MAC, add a flow - # entry, and send this packet out the other interfaces - print "Sending now: \n"; - send_and_count( 'eth1', $pkt->packed, \%delta ); - expect_and_count( 'eth2', $pkt->packed, \%delta ); - expect_and_count( 'eth3', $pkt->packed, \%delta ); - expect_and_count( 'eth4', $pkt->packed, \%delta ); - - return %delta; -} - -run_learning_switch_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/learning_switch/regress/tests.txt b/openflow/regress/projects/learning_switch/regress/tests.txt deleted file mode 100644 index fdeb3c51..00000000 --- a/openflow/regress/projects/learning_switch/regress/tests.txt +++ /dev/null @@ -1,12 +0,0 @@ -test_unicast_unknown/run.pl -test_unicast_known/run.pl -test_broadcast/run.pl -##test_unicast_self/run.pl -test_unicast_move/run.pl -##test_hub_connected/run.pl -test_unicast_multiple_hosts/run.pl - -# BELOW NOT INCLUDED IN CURRRENT RELEASE -# WILL BE AVAILABLE SOON -##test_forward_latency/run.pl -##test_forward_bandwidth/run.pl diff --git a/openflow/regress/projects/regress.txt b/openflow/regress/projects/regress.txt deleted file mode 100644 index 9339cd32..00000000 --- a/openflow/regress/projects/regress.txt +++ /dev/null @@ -1,3 +0,0 @@ -black_box -controller_disconnect -learning_switch diff --git a/openflow/regress/scripts/copy_NF2_code.sh b/openflow/regress/scripts/copy_NF2_code.sh deleted file mode 100755 index 56ff83bf..00000000 --- a/openflow/regress/scripts/copy_NF2_code.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -#last use of this script copied in files from NF2 SVN rev 3904 -#note: OFT_ROOT and NF2_ROOT must be set -cp $NF2_ROOT/lib/Perl5/Test/* $OFT_ROOT/lib/Perl5/Test/ diff --git a/openflow/regress/scripts/env_vars b/openflow/regress/scripts/env_vars deleted file mode 100644 index a8f2433d..00000000 --- a/openflow/regress/scripts/env_vars +++ /dev/null @@ -1,12 +0,0 @@ -export OF_ROOT=/home/yourname/openflow -export OFT_ROOT=${OF_ROOT}/regress -export PATH=${OFT_ROOT}/bin:/sbin:/usr/sbin:${PATH} -export PERL5LIB=${OFT_ROOT}/lib/Perl5:${PERL5LIB} -export OFT_MAP_ETH=${OFT_ROOT}/bin/of_generic_eth.map -export OFT_HP_MAP_ETH=${OFT_ROOT}/bin/of_hp_eth.map -export OFT_HP_SWITCH_IP=10.10.10.2 -export OFT_HP_VLAN=10 -export OFT_HP_CONTROLLER="tcp:10.10.10.3:6633" -export OFT_HP_LISTENER="tcp:10.10.10.2:6633" -export OFT_OVS_ROOT=/home/yourname/openvswitch -export OFT_OVS_MAP_ETH=${OFT_ROOT}/bin/of_ovs_eth.map diff --git a/openflow/regress/scripts/install_deps.pl b/openflow/regress/scripts/install_deps.pl deleted file mode 100755 index 4668a58b..00000000 --- a/openflow/regress/scripts/install_deps.pl +++ /dev/null @@ -1,264 +0,0 @@ -#!/usr/bin/perl -W -# -# Script to automatically install dependencies for regression tests - -use strict; -use File::Basename; -use File::Path; -use Getopt::Std; -use Cwd; - -use constant { - UBUNTU => 'Ubuntu', - DEBIAN => 'Debian', - REDHAT => 'RedHat', - FEDORA => 'Fedora', - - UNKNOWN => 'unknown', - X86_64 => 'x86_64', -}; - -# Executables -my $lsb_release = 'lsb_release'; -my $apt_get = 'apt-get'; -my $yum = 'yum'; -my $uname = '/bin/uname'; - -my $distro; -my $machine; -my $sim; -my %install_funcs = ( - 'Ubuntu' => \&install_ubuntu_debian, - 'Debian' => \&install_ubuntu_debian, - 'Fedora' => \&install_fedora, -); -our($opt_s, $opt_d); - -# Verify that this script is being run as root -if ($> != 0) { - die "This script must be run as root"; -} - -# Parse the command line arguments -parse_args(); - - -# Identify the distribution and machine -if (!defined($distro)) { - identify_distro(); - die "Unable to identify the distribution" if (!defined($distro)); -} -identify_machine(); - -# Call the appropriate install function -if ($install_funcs{$distro}) { - $install_funcs{$distro}->(); -} -else { - die "Unable to find the install function for '$distro'"; -} - -exit 0; - -#========================================================== - -# -# identify_distro: -# Attempt to identify the Linux distro -# -sub identify_distro { - # First, look for lsb release which makes querying easier - $lsb_release = `which $lsb_release`; - chomp($lsb_release); - if ( $? >> 8 == 0) { - $distro = `$lsb_release -s -i`; - chomp($distro); - SWITCH: for ($distro) { - /Ubuntu/ && do { - $distro = UBUNTU; - last SWITCH; - }; - - /Debian/ && do { - $distro = DEBIAN; - last SWITCH; - }; - - (/CentOS/ || /RedHat/) && do { - $distro = REDHAT; - last SWITCH; - }; - - /Fedora/ && do { - $distro = FEDORA; - last SWITCH; - }; - - # DEFAULT - warn "Unknown Linux distro '$distro'"; - $distro = undef; - } - } - - # Otherwise, fall back to looking for release/version files in /etc - else { - if ( -f '/etc/debian_version' || -f '/etc/debian_release' ) { - $distro = DEBIAN; - } - elsif ( -f '/etc/fedora-release') { - $distro = FEDORA; - } - elsif ( -f '/etc/redhat-release' || -f '/etc/redhat_release' ) { - $distro = REDHAT; - } - } -} - -# -# identify_machine: -# Attempt to identify the machine type -# -sub identify_machine { - # First, look for lsb release which makes querying easier - if ( -x $uname) { - $machine = `$uname -m`; - chomp($machine); - } - - # we don't know what sort of machine this is - else { - $machine = UNKNOWN; - } -} - -# -# install_ubuntu_debian: -# Install the necessary dependencies for Ubuntu and Debian -# -sub install_ubuntu_debian { - my @pkgs = ( - 'liberror-perl', - 'libio-interface-perl', - 'liblist-moreutils-perl', - 'libpcap0.8-dev', - 'iproute', - 'psmisc', - 'libnet-pcap-perl', - 'libnet-rawip-perl', - 'wget', - ); - if ($machine eq X86_64) { - push (@pkgs, 'libc6-dev-i386', 'ia32-libs'); - } - - my @modules = ( - 'http://search.cpan.org/CPAN/authors/id/F/FT/FTASSIN/Data-HexDump-0.02.tar.gz', - 'http://www.cpan.org/authors/id/J/JV/JV/Getopt-Long-2.38.tar.gz', - ); - - if ($distro eq UBUNTU) { - push (@pkgs, 'libconvert-binary-c-perl') - } - else { - push (@modules, - 'http://search.cpan.org/CPAN/authors/id/M/MH/MHX/Convert-Binary-C-0.74.tar.gz') - } - - # Run apt-get - my @flags = ('-y'); - push(@flags, '-s') if defined($sim); - system($apt_get, @flags, 'install', @pkgs); - if ($? >> 8 != 0) { - die "Error running $apt_get"; - } - - # Install modules directly from CPAN - install_perl_modules(@modules); -} - -# -# install_fedora: -# Install the necessary dependencies for Fedora Core -# -sub install_fedora { - my @pkgs = ( - 'perl-Convert-Binary-C', - 'perl-Data-HexDump', - 'perl-Net-Pcap', - 'perl-Error.noarch', - 'perl-Module-Build', - 'libpcap-devel', - 'perl-List-MoreUtils', - 'perl-Net-RawIP', - ); - - # Run yum - my @flags = ('-y'); - if (defined($sim)) { - push(@flags, 'info'); - } - else { - push(@flags, 'install'); - } - system($yum, @flags, @pkgs); - if ($? >> 8 != 0) { - die "Error running $yum"; - } -} - -# -# install_perl_modules: -# Fetch and install PERL modules -# -sub install_perl_modules { - my @modules = @_; - - my $dir = "perl_modules"; - - mkdir $dir; - chdir $dir; - - foreach my $path (@modules) { - `wget $path`; - my $module = fileparse($path); - `tar xzf $module`; - $module =~ s/.tar.gz//; - print "compiling $module\n"; - chdir $module; - if (!defined($sim)) { - system 'perl Makefile.PL'; - system 'make'; - system 'make install'; - } - chdir '../'; - } - - chdir '..'; - rmtree $dir; -} - -# -# parse_args -# Parse the command line arguments -# -sub parse_args { - getopts('sd:'); - $sim = 1 if defined($opt_s); - $distro = $opt_d if defined($opt_d); -} - -sub HELP_MESSAGE { - print < 0) { $release_num = $ARGV[0]; } - -check_OF_vars_set(); - -my $rootdir = $ENV{'OFT_ROOT'}; -print "starting at root dir $rootdir\n"; -chdir $rootdir; - -my @ignore_list = ( - './temp', - './scripts/copy_NF2_code.sh', - './scripts/make_release.pl', - './projects/learning_switch/regress/test_forward_bandwidth/run.pl', - './projects/learning_switch/regress/test_forward_bandwidth/run.pl', - './projects/black_box/regress/test_send_bandwidth_fixed/run.pl', - './projects/black_box/regress/test_send_bandwidth_random/run.pl', - './projects/black_box/regress/test_add_flow_bandwidth/run.pl', - './projects/black_box/regress/test_add_flow_latency/run.pl', - './projects/black_box/regress/test_receive_bandwidth_fixed/run.pl', - './projects/black_box/regress/test_receive_bandwidth_random/run.pl', - './projects/black_box/regress/test_forward_bandwidth_fixed/run.pl', - './projects/black_box/regress/test_forward_bandwidth_random/run.pl', - './projects/black_box/regress/test_forward_latency/run.pl', - './projects/black_box/regress/test_switch_bandwidth_random/run.pl', - './projects/black_box/regress/test_switch_bandwidth_random/run.pl' -); - -my @files = parse_dir ('.'); - -print "\n"; - -foreach my $file (@files) { - print $file . "\n"; -} - -# set x permission for non-.pl files -# originally used perl chmod, but it doesn't work -my @write_perm_list = ( - "./temp/$of_ver/projects/learning_switch/regress/common/setup", - "./temp/$of_ver/projects/learning_switch/regress/common/teardown", - "./temp/$of_ver/projects/black_box/regress/common/setup", - "./temp/$of_ver/projects/black_box/regress/common/teardown" -); -foreach my $file (@write_perm_list) { - `chmod 755 $file`; -} - -#print $write_perm_list[0] . "\n"; - -`cd $rootdir/temp; tar czf $of_ver.tar.gz *`; -exit (0); - -# DFS -sub parse_dir { - my ($path) = @_; - #print "parse_dir called with $path\n"; - my @file_list; - # exists? - if (! -e "$path") { - die "checked $path and failed\n"; - } - # file? - elsif (-f "$path") { - if (file_ok($path)) { - print "added $path to list\n"; - push @file_list, "$path"; - - copy($path, "temp/$of_ver/$path") || die "failed to copy $path\n"; - - #for perl files, make them executable - my $match = $path =~ m/.pl/; - print " match = $match\n"; - if ($match) { - # ensure file is executable - print " setting chmod for $path\n"; - chmod 755, "temp/$of_ver/$path" || die "failed to set chmod $path\n"; - }; - } - else { - #print "ignore file $path\n"; - } - } - # directory? - elsif (-d $path) { - #print "parsing directory $path\n"; - opendir(DIR, $path) || print "Can't open... maybe try chmod 777"; - my @files_in_dir=readdir(DIR); - closedir(DIR); - - if (dir_ok('', $path) && $path ne '.') { - #remove ./ at beginning - - my $path_temp = substr($path, 2); - mkdir("temp/$of_ver/$path_temp") || die "failed to make path temp/$of_ver/$path_temp\n"; - } - - #print " dir looks like: \n"; - foreach my $file (@files_in_dir) { - #print " " . $file . "\n"; - } - - foreach my $subdir (@files_in_dir) { - if (dir_ok($subdir, $path) ) { - #print "\nabout to parse $path/$subdir\n"; - push @file_list, parse_dir("$path/$subdir"); - } - } - } - else { - die ("unknown error"); - } - - return @file_list; -} - -sub dir_ok { - my ($subdir, $path) = @_; - my $ignore = 0; - foreach my $file (@ignore_list) { - if ("$path/$subdir" eq $file) { $ignore = 1; last; } - } - - # ignore these three regardless of path - other require path to ignore - if ($subdir ne '.' && $subdir ne '..' && $subdir ne '.svn' && !$ignore ) { - return 1; - } - else { - return 0; - } -} - -sub file_ok { - my ($path) = @_; - my $ok = 1; - foreach my $file (@ignore_list) { - if ("$path" eq $file) { $ok = 0; last; } - } - return $ok; -} diff --git a/openflow/secchan/.dirstamp b/openflow/secchan/.dirstamp deleted file mode 100644 index e69de29b..00000000 diff --git a/openflow/secchan/.gitignore b/openflow/secchan/.gitignore deleted file mode 100644 index d6d189d3..00000000 --- a/openflow/secchan/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -/Makefile -/Makefile.in -/controller-lite -/ctlpath-lite -/dpctl-lite -/ofprotocol -/ofprotocol.8 diff --git a/openflow/secchan/automake.mk b/openflow/secchan/automake.mk deleted file mode 100644 index 6a9f2041..00000000 --- a/openflow/secchan/automake.mk +++ /dev/null @@ -1,32 +0,0 @@ -bin_PROGRAMS += secchan/ofprotocol -man_MANS += secchan/ofprotocol.8 - -secchan_ofprotocol_SOURCES = \ - secchan/discovery.c \ - secchan/discovery.h \ - secchan/emerg-flow.c \ - secchan/emerg-flow.h \ - secchan/fail-open.c \ - secchan/fail-open.h \ - secchan/failover.c \ - secchan/failover.h \ - secchan/in-band.c \ - secchan/in-band.h \ - secchan/port-watcher.c \ - secchan/port-watcher.h \ - secchan/protocol-stat.c \ - secchan/protocol-stat.h \ - secchan/ratelimit.c \ - secchan/ratelimit.h \ - secchan/secchan.c \ - secchan/secchan.h \ - secchan/status.c \ - secchan/status.h \ - secchan/stp-secchan.c \ - secchan/stp-secchan.h -secchan_ofprotocol_LDADD = lib/libopenflow.a $(FAULT_LIBS) $(SSL_LIBS) - -EXTRA_DIST += secchan/ofprotocol.8.in -DISTCLEANFILES += secchan/ofprotocol.8 - -include secchan/commands/automake.mk diff --git a/openflow/secchan/commands/automake.mk b/openflow/secchan/commands/automake.mk deleted file mode 100644 index cbe44d8c..00000000 --- a/openflow/secchan/commands/automake.mk +++ /dev/null @@ -1,3 +0,0 @@ -commandsdir = ${pkgdatadir}/commands -dist_commands_SCRIPTS = \ - secchan/commands/reboot diff --git a/openflow/secchan/commands/reboot b/openflow/secchan/commands/reboot deleted file mode 100755 index 4d5145cd..00000000 --- a/openflow/secchan/commands/reboot +++ /dev/null @@ -1,3 +0,0 @@ -#! /bin/sh -ofp-kill --force --signal=USR1 ofp-switchui.pid -reboot diff --git a/openflow/secchan/discovery.c b/openflow/secchan/discovery.c deleted file mode 100644 index feb9c338..00000000 --- a/openflow/secchan/discovery.c +++ /dev/null @@ -1,251 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include "discovery.h" -#include -#include -#include -#include "dhcp-client.h" -#include "dhcp.h" -#include "netdev.h" -#include "openflow/openflow.h" -#include "packets.h" -#include "port-watcher.h" -#include "secchan.h" -#include "status.h" - -#define THIS_MODULE VLM_discovery -#include "vlog.h" - -struct discovery -{ - const struct settings *s; - struct dhclient *dhcp; - int n_changes; -}; - -static void modify_dhcp_request(struct dhcp_msg *, void *aux); -static bool validate_dhcp_offer(const struct dhcp_msg *, void *aux); - -static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60); - -static void -discovery_status_cb(struct status_reply *sr, void *d_) -{ - struct discovery *d = d_; - - status_reply_put(sr, "accept-remote=%s", d->s->accept_controller_re); - status_reply_put(sr, "n-changes=%d", d->n_changes); - if (d->dhcp) { - status_reply_put(sr, "state=%s", dhclient_get_state(d->dhcp)); - status_reply_put(sr, "state-elapsed=%u", - dhclient_get_state_elapsed(d->dhcp)); - if (dhclient_is_bound(d->dhcp)) { - uint32_t ip = dhclient_get_ip(d->dhcp); - uint32_t netmask = dhclient_get_netmask(d->dhcp); - uint32_t router = dhclient_get_router(d->dhcp); - - const struct dhcp_msg *cfg = dhclient_get_config(d->dhcp); - uint32_t dns_server; - char *domain_name; - int i; - - status_reply_put(sr, "ip="IP_FMT, IP_ARGS(&ip)); - status_reply_put(sr, "netmask="IP_FMT, IP_ARGS(&netmask)); - if (router) { - status_reply_put(sr, "router="IP_FMT, IP_ARGS(&router)); - } - - for (i = 0; dhcp_msg_get_ip(cfg, DHCP_CODE_DNS_SERVER, i, - &dns_server); - i++) { - status_reply_put(sr, "dns%d="IP_FMT, i, IP_ARGS(&dns_server)); - } - - domain_name = dhcp_msg_get_string(cfg, DHCP_CODE_DOMAIN_NAME); - if (domain_name) { - status_reply_put(sr, "domain=%s", domain_name); - free(domain_name); - } - - status_reply_put(sr, "lease-remaining=%u", - dhclient_get_lease_remaining(d->dhcp)); - } - } -} - -static void -discovery_local_port_cb(const struct ofp_phy_port *port, void *d_) -{ - struct discovery *d = d_; - if (port) { - char name[OFP_MAX_PORT_NAME_LEN + 1]; - struct netdev *netdev; - int retval; - - /* Check that this was really a change. */ - get_port_name(port, name, sizeof name); - if (d->dhcp && !strcmp(netdev_get_name(dhclient_get_netdev(d->dhcp)), - name)) { - return; - } - - /* Destroy current DHCP client. */ - dhclient_destroy(d->dhcp); - d->dhcp = NULL; - - /* Bring local network device up. */ - retval = netdev_open(name, NETDEV_ETH_TYPE_NONE, &netdev); - if (retval) { - VLOG_ERR("Could not open %s device, discovery disabled: %s", - name, strerror(retval)); - return; - } - retval = netdev_turn_flags_on(netdev, NETDEV_UP, true); - if (retval) { - VLOG_ERR("Could not bring %s device up, discovery disabled: %s", - name, strerror(retval)); - return; - } - netdev_close(netdev); - - /* Initialize DHCP client. */ - retval = dhclient_create(name, modify_dhcp_request, - validate_dhcp_offer, (void *) d->s, &d->dhcp); - if (retval) { - VLOG_ERR("Failed to initialize DHCP client, " - "discovery disabled: %s", strerror(retval)); - return; - } - dhclient_set_max_timeout(d->dhcp, 3); - dhclient_init(d->dhcp, 0); - } else { - dhclient_destroy(d->dhcp); - d->dhcp = NULL; - } -} - - -struct discovery * -discovery_init(const struct settings *s, struct port_watcher *pw, - struct switch_status *ss) -{ - struct discovery *d; - - d = xmalloc(sizeof *d); - d->s = s; - d->dhcp = NULL; - d->n_changes = 0; - - switch_status_register_category(ss, "discovery", discovery_status_cb, d); - port_watcher_register_local_port_callback(pw, discovery_local_port_cb, d); - - return d; -} - -void -discovery_question_connectivity(struct discovery *d) -{ - if (d->dhcp) { - dhclient_force_renew(d->dhcp, 15); - } -} - -bool -discovery_run(struct discovery *d, char **controller_name) -{ - if (!d->dhcp) { - *controller_name = NULL; - return true; - } - - dhclient_run(d->dhcp); - if (!dhclient_changed(d->dhcp)) { - return false; - } - - dhclient_configure_netdev(d->dhcp); - if (d->s->update_resolv_conf) { - dhclient_update_resolv_conf(d->dhcp); - } - - if (dhclient_is_bound(d->dhcp)) { - *controller_name = dhcp_msg_get_string(dhclient_get_config(d->dhcp), - DHCP_CODE_OFP_CONTROLLER_VCONN); - VLOG_INFO("%s: discovered controller", *controller_name); - d->n_changes++; - } else { - *controller_name = NULL; - if (d->n_changes) { - VLOG_INFO("discovered controller no longer available"); - d->n_changes++; - } - } - return true; -} - -void -discovery_wait(struct discovery *d) -{ - if (d->dhcp) { - dhclient_wait(d->dhcp); - } -} - -static void -modify_dhcp_request(struct dhcp_msg *msg, void *aux UNUSED) -{ - dhcp_msg_put_string(msg, DHCP_CODE_VENDOR_CLASS, "OpenFlow"); -} - -static bool -validate_dhcp_offer(const struct dhcp_msg *msg, void *s_) -{ - const struct settings *s = s_; - char *vconn_name; - bool accept; - - vconn_name = dhcp_msg_get_string(msg, DHCP_CODE_OFP_CONTROLLER_VCONN); - if (!vconn_name) { - VLOG_WARN_RL(&rl, "rejecting DHCP offer missing controller vconn"); - return false; - } - accept = !regexec(&s->accept_controller_regex, vconn_name, 0, NULL, 0); - if (!accept) { - VLOG_WARN_RL(&rl, "rejecting controller vconn that fails to match %s", - s->accept_controller_re); - } - free(vconn_name); - return accept; -} diff --git a/openflow/secchan/discovery.h b/openflow/secchan/discovery.h deleted file mode 100644 index b2cb03c9..00000000 --- a/openflow/secchan/discovery.h +++ /dev/null @@ -1,50 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#ifndef DISCOVERY_H -#define DISCOVERY_H 1 - -#include - -struct settings; -struct port_watcher; -struct switch_status; - -struct discovery *discovery_init(const struct settings *, - struct port_watcher *, - struct switch_status *); -void discovery_question_connectivity(struct discovery *); -bool discovery_run(struct discovery *, char **controller_name); -void discovery_wait(struct discovery *); - -#endif /* discovery.h */ diff --git a/openflow/secchan/emerg-flow.c b/openflow/secchan/emerg-flow.c deleted file mode 100644 index 9af58819..00000000 --- a/openflow/secchan/emerg-flow.c +++ /dev/null @@ -1,144 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#include - -#include -#include -#include -#include -#include -#include - -#include "openflow/openflow.h" -#include "openflow/private-ext.h" - -#include "util.h" -#include "vconn.h" -#include "rconn.h" -#include "secchan.h" -#include "status.h" -#include "timeval.h" -#include "sat-math.h" -#include "ofpbuf.h" -#include "emerg-flow.h" -#define THIS_MODULE VLM_emerg_flow -#include "vlog.h" - -struct emerg_flow_context { - const struct settings *settings; - const struct secchan *secchan; - struct rconn *local_rconn; - struct rconn *remote_rconn; - int prev_state; - int state; -}; - -static void emerg_flow_status_cb(struct status_reply *, void *); -static void emerg_flow_periodic_cb(void *); - -static void -emerg_flow_status_cb(struct status_reply *status_reply, void *context_) -{ - struct emerg_flow_context *context = context_; - - status_reply_put(status_reply, "state=%s", - context->state == PRIVATEOPT_EMERG_FLOW_RESTORATION - ? "restoration" - : context->state == PRIVATEOPT_EMERG_FLOW_PROTECTION - ? "protection" : "unknown"); -} - -static void -emerg_flow_periodic_cb(void *context_) -{ - struct emerg_flow_context *context = context_; - struct ofpbuf *buf = NULL; - struct private_vxhdr *vxhdr = NULL; - struct private_vxopt *vxopt = NULL; - int error = 0; - - if (rconn_is_connected(context->remote_rconn)) { - if (context->state == PRIVATEOPT_EMERG_FLOW_PROTECTION) { - context->prev_state = context->state; - context->state = PRIVATEOPT_EMERG_FLOW_RESTORATION; - } else { - return; - } - } else { - if (context->state == PRIVATEOPT_EMERG_FLOW_RESTORATION) { - context->prev_state = context->state; - context->state = PRIVATEOPT_EMERG_FLOW_PROTECTION; - } else { - return; - } - } - - vxhdr = (struct private_vxhdr *)make_openflow - (sizeof(*vxhdr) + sizeof(*vxopt), OFPT_VENDOR, &buf); - vxopt = (struct private_vxopt *)(vxhdr + 1); - vxhdr->ofp_vxid = htonl(PRIVATE_VENDOR_ID); - vxopt->pvo_type = htons(context->state); - vxopt->pvo_len = htons(0); - - error = rconn_send(context->local_rconn, buf, NULL); - if (error && error != EAGAIN) { - VLOG_WARN("send failed (%s)", strerror(error)); - } -} - -void -emerg_flow_start(struct secchan *secchan, const struct settings *settings, - struct switch_status *switch_status, - struct rconn *local_rconn, struct rconn *remote_rconn) -{ - struct emerg_flow_context *context = NULL; - static struct hook_class emerg_flow_hook_class = { - NULL, /* local_packet_cb */ - NULL, /* remote_packet_cb */ - emerg_flow_periodic_cb, /* periodic_cb */ - NULL, /* wait_cb */ - NULL, /* closing_cb */ - }; - - context = xmalloc(sizeof(*context)); - context->settings = settings; - context->secchan = secchan; - context->local_rconn = local_rconn; - context->remote_rconn = remote_rconn; - context->prev_state = PRIVATEOPT_EMERG_FLOW_PROTECTION; - context->state = PRIVATEOPT_EMERG_FLOW_PROTECTION; - - switch_status_register_category(switch_status, "emerg-flow", - emerg_flow_status_cb, context); - add_hook(secchan, &emerg_flow_hook_class, context); -} diff --git a/openflow/secchan/emerg-flow.h b/openflow/secchan/emerg-flow.h deleted file mode 100644 index d61a7fe2..00000000 --- a/openflow/secchan/emerg-flow.h +++ /dev/null @@ -1,44 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#ifndef EMERG_FLOW_H_ -#define EMERG_FLOW_H_ 1 - -struct rconn; -struct secchan; -struct settings; -struct switch_status; - -void emerg_flow_start(struct secchan *, const struct settings *, - struct switch_status *, struct rconn *, struct rconn *); - -#endif diff --git a/openflow/secchan/fail-open.c b/openflow/secchan/fail-open.c deleted file mode 100644 index eb28bc38..00000000 --- a/openflow/secchan/fail-open.c +++ /dev/null @@ -1,159 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include "fail-open.h" -#include -#include -#include -#include "learning-switch.h" -#include "netdev.h" -#include "packets.h" -#include "port-watcher.h" -#include "rconn.h" -#include "secchan.h" -#include "status.h" -#include "stp-secchan.h" -#include "timeval.h" - -#define THIS_MODULE VLM_fail_open -#include "vlog.h" - -struct fail_open_data { - const struct settings *s; - struct rconn *local_rconn; - struct rconn *remote_rconn; - struct lswitch *lswitch; - int last_disconn_secs; - time_t boot_deadline; -}; - -/* Causes 'r' to enter or leave fail-open mode, if appropriate. */ -static void -fail_open_periodic_cb(void *fail_open_) -{ - struct fail_open_data *fail_open = fail_open_; - int disconn_secs; - bool open; - - if (time_now() < fail_open->boot_deadline) { - return; - } - disconn_secs = rconn_failure_duration(fail_open->remote_rconn); - open = disconn_secs >= fail_open->s->probe_interval * 3; - if (open != (fail_open->lswitch != NULL)) { - if (!open) { - VLOG_WARN("No longer in fail-open mode"); - lswitch_destroy(fail_open->lswitch); - fail_open->lswitch = NULL; - } else { - VLOG_WARN("Could not connect to controller for %d seconds, " - "failing open", disconn_secs); - fail_open->lswitch = lswitch_create(fail_open->local_rconn, true, - fail_open->s->max_idle); - fail_open->last_disconn_secs = disconn_secs; - } - } else if (open && disconn_secs > fail_open->last_disconn_secs + 60) { - VLOG_INFO("Still in fail-open mode after %d seconds disconnected " - "from controller", disconn_secs); - fail_open->last_disconn_secs = disconn_secs; - } - if (fail_open->lswitch) { - lswitch_run(fail_open->lswitch, fail_open->local_rconn); - } -} - -static void -fail_open_wait_cb(void *fail_open_) -{ - struct fail_open_data *fail_open = fail_open_; - if (fail_open->lswitch) { - lswitch_wait(fail_open->lswitch); - } -} - -static bool -fail_open_local_packet_cb(struct relay *r, void *fail_open_) -{ - struct fail_open_data *fail_open = fail_open_; - if (rconn_is_connected(fail_open->remote_rconn) || !fail_open->lswitch) { - return false; - } else { - lswitch_process_packet(fail_open->lswitch, fail_open->local_rconn, - r->halves[HALF_LOCAL].rxbuf); - rconn_run(fail_open->local_rconn); - return true; - } -} - -static void -fail_open_status_cb(struct status_reply *sr, void *fail_open_) -{ - struct fail_open_data *fail_open = fail_open_; - const struct settings *s = fail_open->s; - int trigger_duration = s->probe_interval * 3; - int cur_duration = rconn_failure_duration(fail_open->remote_rconn); - - status_reply_put(sr, "trigger-duration=%d", trigger_duration); - status_reply_put(sr, "current-duration=%d", cur_duration); - status_reply_put(sr, "triggered=%s", - cur_duration >= trigger_duration ? "true" : "false"); - status_reply_put(sr, "max-idle=%d", s->max_idle); -} - -static struct hook_class fail_open_hook_class = { - fail_open_local_packet_cb, /* local_packet_cb */ - NULL, /* remote_packet_cb */ - fail_open_periodic_cb, /* periodic_cb */ - fail_open_wait_cb, /* wait_cb */ - NULL, /* closing_cb */ -}; - -void -fail_open_start(struct secchan *secchan, const struct settings *s, - struct switch_status *ss, - struct rconn *local_rconn, struct rconn *remote_rconn) -{ - struct fail_open_data *fail_open = xmalloc(sizeof *fail_open); - fail_open->s = s; - fail_open->local_rconn = local_rconn; - fail_open->remote_rconn = remote_rconn; - fail_open->lswitch = NULL; - fail_open->boot_deadline = time_now() + s->probe_interval * 3; - if (s->enable_stp) { - fail_open->boot_deadline += STP_EXTRA_BOOT_TIME; - } - switch_status_register_category(ss, "fail-open", - fail_open_status_cb, fail_open); - add_hook(secchan, &fail_open_hook_class, fail_open); -} diff --git a/openflow/secchan/fail-open.h b/openflow/secchan/fail-open.h deleted file mode 100644 index 69a3b310..00000000 --- a/openflow/secchan/fail-open.h +++ /dev/null @@ -1,46 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#ifndef FAIL_OPEN_H -#define FAIL_OPEN_H 1 - -struct rconn; -struct secchan; -struct settings; -struct switch_status; - -void fail_open_start(struct secchan *, const struct settings *, - struct switch_status *, - struct rconn *local, struct rconn *remote); - -#endif /* fail-open.h */ diff --git a/openflow/secchan/failover.c b/openflow/secchan/failover.c deleted file mode 100644 index 718d7379..00000000 --- a/openflow/secchan/failover.c +++ /dev/null @@ -1,144 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#include -#include -#include -#include - -#include "util.h" -#include "rconn.h" -#include "secchan.h" -#include "status.h" -#include "timeval.h" -#include "sat-math.h" -#include "failover.h" -#define THIS_MODULE VLM_failover -#include "vlog.h" - -struct failover_peer { - time_t epoch; -}; - -struct failover_context { - const struct settings *settings; - const struct secchan *secchan; - struct rconn *remote_rconn; - int index; - struct failover_peer *peers[MAX_CONTROLLERS]; -}; - -static void failover_status_cb(struct status_reply *, void *); -static bool is_timed_out(const struct failover_peer *, int); -static void failover_periodic_cb(void *); - -static void -failover_status_cb(struct status_reply *status_reply, void *context_) -{ - struct failover_context *context = context_; - int i; - - status_reply_put(status_reply, "num-controllers=%d", - context->settings->num_controllers); - - for (i = 0; i < MAX_CONTROLLERS; ++i) { - if (context->settings->controller_names[i] == NULL) - continue; - status_reply_put(status_reply, "controller#%d=%s", - i, context->settings->controller_names[i]); - } -} - -static bool -is_timed_out(const struct failover_peer *peer, int max_backoff) -{ - unsigned int sat_value = sat_add(peer->epoch, max_backoff); - return time_now() >= sat_value; -} - -static void -failover_periodic_cb(void *context_) -{ - struct failover_context *context = context_; - char *curr_peer = NULL; - char *prev_peer = NULL; - - if (rconn_is_connected(context->remote_rconn)) - return; - - if (!is_timed_out(context->peers[context->index], - context->settings->max_backoff)) { - return; - } - - rconn_disconnect(context->remote_rconn); - prev_peer = (char *)context->settings->controller_names[context->index]; - context->index = (context->index + 1) - % context->settings->num_controllers; - curr_peer = (char *)context->settings->controller_names[context->index]; - rconn_connect(context->remote_rconn, - context->settings->controller_names[context->index]); - context->peers[context->index]->epoch = time_now(); - VLOG_INFO("Switching over to %s, from %s", curr_peer, prev_peer); -} - -void -failover_start(struct secchan *secchan, const struct settings *settings, - struct switch_status *switch_status, struct rconn *remote_rconn) -{ - struct failover_context *context = NULL; - int i; - static struct hook_class failover_hook_class = { - NULL, /* local_packet_cb */ - NULL, /* remote_packet_cb */ - failover_periodic_cb, /* periodic_cb */ - NULL, /* wait_cb */ - NULL, /* closing_cb */ - }; - - context = xmalloc(sizeof(*context)); - context->settings = settings; - context->secchan = secchan; - context->remote_rconn = remote_rconn; - context->index = 0; - for (i = 0; i < MAX_CONTROLLERS; ++i) { - context->peers[i] = NULL; - if (settings->controller_names[i] == NULL) - continue; - context->peers[i] = xmalloc(sizeof(struct failover_peer)); - context->peers[i]->epoch = time_now(); - } - - switch_status_register_category(switch_status, "failover", - failover_status_cb, context); - add_hook(secchan, &failover_hook_class, context); -} diff --git a/openflow/secchan/failover.h b/openflow/secchan/failover.h deleted file mode 100644 index d511b35f..00000000 --- a/openflow/secchan/failover.h +++ /dev/null @@ -1,44 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#ifndef FAILOVER_H_ -#define FAILOVER_H_ 1 - -struct rconn; -struct secchan; -struct settings; -struct switch_status; - -void failover_start(struct secchan *, const struct settings *, - struct switch_status *, struct rconn *); - -#endif diff --git a/openflow/secchan/in-band.c b/openflow/secchan/in-band.c deleted file mode 100644 index 46109daf..00000000 --- a/openflow/secchan/in-band.c +++ /dev/null @@ -1,331 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include "in-band.h" -#include -#include -#include -#include -#include "flow.h" -#include "mac-learning.h" -#include "netdev.h" -#include "ofpbuf.h" -#include "openflow/openflow.h" -#include "packets.h" -#include "port-watcher.h" -#include "rconn.h" -#include "secchan.h" -#include "status.h" -#include "timeval.h" -#include "vconn.h" - -#define THIS_MODULE VLM_in_band -#include "vlog.h" - -struct in_band_data { - const struct settings *s; - struct mac_learning *ml; - struct netdev *of_device; - struct rconn *controller; - int n_queued; -}; - -static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60); - -static void -queue_tx(struct rconn *rc, struct in_band_data *in_band, struct ofpbuf *b) -{ - rconn_send_with_limit(rc, b, &in_band->n_queued, 10); -} - -static const uint8_t * -get_controller_mac(struct in_band_data *in_band) -{ - static uint32_t ip, last_nonzero_ip; - static uint8_t mac[ETH_ADDR_LEN], last_nonzero_mac[ETH_ADDR_LEN]; - static time_t next_refresh = 0; - - uint32_t last_ip = ip; - - time_t now = time_now(); - - ip = rconn_get_ip(in_band->controller); - if (last_ip != ip || !next_refresh || now >= next_refresh) { - bool have_mac; - - /* Look up MAC address. */ - memset(mac, 0, sizeof mac); - if (ip && in_band->of_device) { - int retval = netdev_arp_lookup(in_band->of_device, ip, mac); - if (retval) { - VLOG_DBG_RL(&rl, "cannot look up controller hw address " - "("IP_FMT"): %s", IP_ARGS(&ip), strerror(retval)); - } - } - have_mac = !eth_addr_is_zero(mac); - - /* Log changes in IP, MAC addresses. */ - if (ip && ip != last_nonzero_ip) { - VLOG_DBG("controller IP address changed from "IP_FMT - " to "IP_FMT, IP_ARGS(&last_nonzero_ip), IP_ARGS(&ip)); - last_nonzero_ip = ip; - } - if (have_mac && memcmp(last_nonzero_mac, mac, ETH_ADDR_LEN)) { - VLOG_DBG("controller MAC address changed from "ETH_ADDR_FMT" to " - ETH_ADDR_FMT, - ETH_ADDR_ARGS(last_nonzero_mac), ETH_ADDR_ARGS(mac)); - memcpy(last_nonzero_mac, mac, ETH_ADDR_LEN); - } - - /* Schedule next refresh. - * - * If we have an IP address but not a MAC address, then refresh - * quickly, since we probably will get a MAC address soon (via ARP). - * Otherwise, we can afford to wait a little while. */ - next_refresh = now + (!ip || have_mac ? 10 : 1); - } - return !eth_addr_is_zero(mac) ? mac : NULL; -} - -static bool -is_controller_mac(const uint8_t dl_addr[ETH_ADDR_LEN], - struct in_band_data *in_band) -{ - const uint8_t *mac = get_controller_mac(in_band); - return mac && eth_addr_equals(mac, dl_addr); -} - -static void -in_band_learn_mac(struct in_band_data *in_band, - uint16_t in_port, const uint8_t src_mac[ETH_ADDR_LEN]) -{ - if (mac_learning_learn(in_band->ml, src_mac, 0, in_port)) { - VLOG_DBG_RL(&rl, "learned that "ETH_ADDR_FMT" is on port %"PRIu16, - ETH_ADDR_ARGS(src_mac), in_port); - } -} - -static bool -in_band_local_packet_cb(struct relay *r, void *in_band_) -{ - struct in_band_data *in_band = in_band_; - struct rconn *rc = r->halves[HALF_LOCAL].rconn; - struct ofp_packet_in *opi; - struct eth_header *eth; - struct ofpbuf payload; - struct flow flow; - uint16_t in_port; - int out_port; - - if (!get_ofp_packet_eth_header(r, &opi, ð) || !in_band->of_device) { - return false; - } - in_port = ntohs(opi->in_port); - get_ofp_packet_payload(opi, &payload); - flow_extract(&payload, in_port, &flow); - - /* Deal with local stuff. */ - if (in_port == OFPP_LOCAL) { - /* Sent by secure channel. */ - out_port = mac_learning_lookup(in_band->ml, eth->eth_dst, 0); - } else if (eth_addr_equals(eth->eth_dst, - netdev_get_etheraddr(in_band->of_device))) { - /* Sent to secure channel. */ - out_port = OFPP_LOCAL; - in_band_learn_mac(in_band, in_port, eth->eth_src); - } else if (eth->eth_type == htons(ETH_TYPE_ARP) - && eth_addr_is_broadcast(eth->eth_dst) - && is_controller_mac(eth->eth_src, in_band)) { - /* ARP sent by controller. */ - out_port = OFPP_FLOOD; - } else if ((is_controller_mac(eth->eth_dst, in_band) - || is_controller_mac(eth->eth_src, in_band)) - && flow.dl_type == htons(ETH_TYPE_IP) - && flow.nw_proto == IP_TYPE_TCP - && (flow.tp_src == htons(OFP_TCP_PORT) - || flow.tp_src == htons(OFP_SSL_PORT) - || flow.tp_dst == htons(OFP_TCP_PORT) - || flow.tp_dst == htons(OFP_SSL_PORT))) { - /* Traffic to or from controller. Switch it by hand. */ - in_band_learn_mac(in_band, in_port, eth->eth_src); - out_port = mac_learning_lookup(in_band->ml, eth->eth_dst, 0); - } else { - const uint8_t *controller_mac; - controller_mac = get_controller_mac(in_band); - if (eth->eth_type == htons(ETH_TYPE_ARP) - && eth_addr_is_broadcast(eth->eth_dst) - && is_controller_mac(eth->eth_src, in_band)) { - /* ARP sent by controller. */ - out_port = OFPP_FLOOD; - } else if (is_controller_mac(eth->eth_dst, in_band) - && in_port == mac_learning_lookup(in_band->ml, - controller_mac, 0)) { - /* Drop controller traffic that arrives on the controller port. */ - out_port = -1; - } else { - return false; - } - } - - if (in_port == out_port) { - /* The input and output port match. Set up a flow to drop packets. */ - queue_tx(rc, in_band, make_add_flow(&flow, ntohl(opi->buffer_id), - in_band->s->max_idle, 0)); - } else if (out_port != OFPP_FLOOD) { - /* The output port is known, so add a new flow. */ - queue_tx(rc, in_band, - make_add_simple_flow(&flow, ntohl(opi->buffer_id), - out_port, in_band->s->max_idle)); - - /* If the switch didn't buffer the packet, we need to send a copy. */ - if (ntohl(opi->buffer_id) == UINT32_MAX) { - queue_tx(rc, in_band, - make_unbuffered_packet_out(&payload, in_port, out_port)); - } - } else { - /* We don't know that MAC. Send along the packet without setting up a - * flow. */ - struct ofpbuf *b; - if (ntohl(opi->buffer_id) == UINT32_MAX) { - b = make_unbuffered_packet_out(&payload, in_port, out_port); - } else { - b = make_buffered_packet_out(ntohl(opi->buffer_id), - in_port, out_port); - } - queue_tx(rc, in_band, b); - } - return true; -} - -static void -in_band_status_cb(struct status_reply *sr, void *in_band_) -{ - struct in_band_data *in_band = in_band_; - struct in_addr local_ip; - uint32_t controller_ip; - const uint8_t *controller_mac; - - if (in_band->of_device) { - const uint8_t *mac = netdev_get_etheraddr(in_band->of_device); - if (netdev_get_in4(in_band->of_device, &local_ip)) { - status_reply_put(sr, "local-ip="IP_FMT, IP_ARGS(&local_ip.s_addr)); - } - status_reply_put(sr, "local-mac="ETH_ADDR_FMT, ETH_ADDR_ARGS(mac)); - - controller_ip = rconn_get_ip(in_band->controller); - if (controller_ip) { - status_reply_put(sr, "controller-ip="IP_FMT, - IP_ARGS(&controller_ip)); - } - controller_mac = get_controller_mac(in_band); - if (controller_mac) { - status_reply_put(sr, "controller-mac="ETH_ADDR_FMT, - ETH_ADDR_ARGS(controller_mac)); - } - } -} - -void -get_ofp_packet_payload(struct ofp_packet_in *opi, struct ofpbuf *payload) -{ - payload->data = opi->data; - payload->size = ntohs(opi->header.length) - offsetof(struct ofp_packet_in, - data); -} - -static void -in_band_local_port_cb(const struct ofp_phy_port *port, void *in_band_) -{ - struct in_band_data *in_band = in_band_; - if (port) { - char name[sizeof port->name + 1]; - get_port_name(port, name, sizeof name); - - if (!in_band->of_device - || strcmp(netdev_get_name(in_band->of_device), name)) - { - int error; - netdev_close(in_band->of_device); - error = netdev_open(name, NETDEV_ETH_TYPE_NONE, - &in_band->of_device); - if (error) { - VLOG_ERR("failed to open in-band control network device " - "\"%s\": %s", name, strerror(errno)); - } - } - } else { - netdev_close(in_band->of_device); - in_band->of_device = NULL; - } -} - -static void -in_band_periodic_cb(void *in_band_) -{ - struct in_band_data *in_band = in_band_; - mac_learning_run(in_band->ml, NULL); -} - -static void -in_band_wait_cb(void *in_band_) -{ - struct in_band_data *in_band = in_band_; - mac_learning_wait(in_band->ml); -} - -static struct hook_class in_band_hook_class = { - in_band_local_packet_cb, /* local_packet_cb */ - NULL, /* remote_packet_cb */ - in_band_periodic_cb, /* periodic_cb */ - in_band_wait_cb, /* wait_cb */ - NULL, /* closing_cb */ -}; - -void -in_band_start(struct secchan *secchan, - const struct settings *s, struct switch_status *ss, - struct port_watcher *pw, struct rconn *remote) -{ - struct in_band_data *in_band; - - in_band = xcalloc(1, sizeof *in_band); - in_band->s = s; - in_band->ml = mac_learning_create(); - in_band->of_device = NULL; - in_band->controller = remote; - switch_status_register_category(ss, "in-band", in_band_status_cb, in_band); - port_watcher_register_local_port_callback(pw, in_band_local_port_cb, - in_band); - add_hook(secchan, &in_band_hook_class, in_band); -} diff --git a/openflow/secchan/in-band.h b/openflow/secchan/in-band.h deleted file mode 100644 index b4d21ab9..00000000 --- a/openflow/secchan/in-band.h +++ /dev/null @@ -1,47 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#ifndef IN_BAND_H -#define IN_BAND_H 1 - -struct port_watcher; -struct rconn; -struct secchan; -struct settings; -struct switch_status; - -void in_band_start(struct secchan *, const struct settings *, - struct switch_status *, struct port_watcher *, - struct rconn *remote); - -#endif /* in-band.h */ diff --git a/openflow/secchan/ofprotocol.8.in b/openflow/secchan/ofprotocol.8.in deleted file mode 100644 index 4aae44a3..00000000 --- a/openflow/secchan/ofprotocol.8.in +++ /dev/null @@ -1,462 +0,0 @@ -.ds PN ofprotocol -.TH ofprotocol 8 "October 2008" "OpenFlow" "OpenFlow Manual" - -.SH NAME -ofprotocol \- secure channel connecting an OpenFlow datapath to a controller - -.SH SYNOPSIS -.B ofprotocol -[\fIoptions\fR] \fIdatapath\fR controller[,\fIcontroller\fR...] - -.SH DESCRIPTION -The \fBofprotocol\fR program sets up a secure channel between a local -OpenFlow datapath and a remote controller. \fBofprotocol\fR connects to -the local datapath over Netlink and to the controller over TCP or SSL, -and then forwards OpenFlow messages from one endpoint to the other. - -The mandatory \fIdatapath\fR argument argument specifies the local datapath -to relay. It takes one of the following forms: - -.TP -\fBnl:\fIdp_idx\fR -Attach to the local kernel-based datapath over the Netlink protocol. -The \fIdp_idx\fR argument is the number of a datapath created with -\fBdpctl\fR(8). - -.TP -\fBunix:\fIfile\fR -Attach to the userspace datapath implemented by \fBofdatapath\fR(8). -The \fIfile\fR argument must the same one specified on the -\fBofdatapath\fR command line. - -.PP -The optional \fIcontroller\fR argument specifies how to connect to -an OpenFlow controller. Up to four controllers may be specified, -using the following forms: - -.TP -\fBssl:\fIhost\fR[\fB:\fIport\fR] -The specified SSL \fIport\fR (default: 6633) on the given remote -\fIhost\fR. The \fB--private-key\fR, \fB--certificate\fR, and -\fB--ca-cert\fR options are mandatory when this form is used. - -.TP -\fBtcp:\fIhost\fR[\fB:\fIport\fR] -The specified TCP \fIport\fR (default: 6633) on the given remote -\fIhost\fR. - -.TP -\fBunix:\fIfile\fR -The Unix domain server socket named \fIfile\fR. - -.PP -If multiple controllers are specified, \fBofprotocol\fR will attempt to -connect to a new controller when a controller connection fails, times -out, or is closed, or when a controller stops responding to echo requests. - -If \fIcontroller\fR is omitted, \fBofprotocol\fR attempts to discover the -location of the controller automatically (see below). - -.SH "CONTACTING THE CONTROLLER" -The OpenFlow switch must be able to contact the OpenFlow controller -over the network. It can do so in one of two ways: - -.IP out-of-band -In this configuration, OpenFlow traffic uses a network separate from -the data traffic that it controls, that is, the switch does not use -any of the network devices added to the datapath with \fBdpctl -addif\fR in its communication with the controller. - -To use \fBofprotocol\fR in a network with out-of-band control, specify -\fB--out-of-band\fR on the \fBofprotocol\fR command line. The control -network must be configured separately, before or after \fBofprotocol\fR -is started. - -.IP in-band -In this configuration, a single network is used for OpenFlow traffic -and other data traffic, that is, the switch contacts the controller -over one of the network devices added to the datapath with \fBdpctl -addif\fR. This configuration is often more convenient than -out-of-band control, because it is not necessary to maintain two -independent networks. - -In-band control is the default for \fBofprotocol\fR, so no special -command-line option is required. - -With in-band control, the location of the controller can be configured -manually or discovered automatically: - -.RS -.IP "controller discovery" -To make \fBofprotocol\fR discover the location of the controller -automatically, do not specify the location of the controller on the -\fBofprotocol\fR command line. - -In this mode, \fBofprotocol\fR will broadcast a DHCP request with vendor -class identifier \fBOpenFlow\fR across the network devices added to -the datapath with \fBdpctl addif\fR. It will accept any valid DHCP -reply that has the same vendor class identifier and includes a -vendor-specific option with code 1 whose contents are a string -specifying the location of the controller in the same format used on -the \fBofprotocol\fR command line (e.g. \fBssl:192.168.0.1\fR). - -The DHCP reply may also, optionally, include a vendor-specific option -with code 2 whose contents are a string specifying the URI to the base -of the OpenFlow PKI (e.g. \fBhttp://192.168.0.1/openflow/pki\fR). -This URI is used only for bootstrapping the OpenFlow PKI at initial -switch setup; \fBofprotocol\fR does not use it at all. - -The following ISC DHCP server configuration file assigns the IP -address range 192.168.0.20 through 192.168.0.30 to OpenFlow switches -that follow the switch protocol and addresses 192.168.0.1 through -192.168.0.10 to all other DHCP clients: - -default-lease-time 600; -.br -max-lease-time 7200; -.br -option space openflow; -.br -option openflow.controller-vconn code 1 = text; -.br -option openflow.pki-uri code 2 = text; -.br -class "OpenFlow" { -.br - match if option vendor-class-identifier = "OpenFlow"; -.br - vendor-option-space openflow; -.br - option openflow.controller-vconn "tcp:192.168.0.10"; -.br - option openflow.pki-uri "http://192.168.0.10/openflow/pki"; -.br - option vendor-class-identifier "OpenFlow"; -.br -} -.br -subnet 192.168.0.0 netmask 255.255.255.0 { -.br - pool { -.br - allow members of "OpenFlow"; -.br - range 192.168.0.20 192.168.0.30; -.br - } -.br - pool { -.br - deny members of "OpenFlow"; -.br - range 192.168.0.1 192.168.0.10; -.br - } -.br -} -.br - -.IP "manual configuration" -To configure in-band control manually, specify the location of the -controller on the \fBofprotocol\fR command line as the \fIcontroller\fR -argument. You must also configure the network device for the OpenFlow -``local port'' to allow \fBofprotocol\fR to connect to that controller. -The OpenFlow local port is a virtual network port that \fBofprotocol\fR -bridges to the physical switch ports. Its network device name depends -on the \fIdatapath\fR specified on the \fBofprotocol\fR command line: - -.RS -.TP -\fBnl:\fIdp_idx\fR -The local port network device for \fBnl:\fIdp_idx\fR is always named -\fBof\fIdp_idx\fR, i.e. the device for \fBnl:0\fR is \fBof0\fR. - -.TP -\fBunix:\fIfile\fR -The local port network device name may be specified on the -\fBofdatapath\fR command line, using the \fB--local-port\fR option. It -is often \fBtap0\fR. -.RE - -.IP -Before \fBofprotocol\fR starts, the local port network device is not -bridged to any physical network, so the next step depends on whether -connectivity is required to configure the device's IP address. If the -switch has a static IP address, you may configure its IP address now -with a command such as: -.RS -.IP -ifconfig of0 192.168.1.1 -.RE -.IP -and then invoke \fBofprotocol\fR. - -On the other hand, if the switch does not have a static IP address, -e.g. it obtains its IP address dynamically via DHCP, the DHCP client -will not be able to contact the DHCP server until the secure channel -has started up. Thus, start \fBofprotocol\fR without configuring -the local port network device, and start the DHCP client afterward. -.RE - -.SH OPTIONS -.SS "Controller Discovery Options" -.TP -\fB--accept-vconn=\fIregex\fR -When \fBofprotocol\fR performs controller discovery (see \fBCONTACTING -THE CONTROLLER\fR, above, for more information about controller -discovery), it validates the controller location obtained via DHCP -with a POSIX extended regular expression. Only controllers whose -names match the regular expression will be accepted. - -The default regular expression is \fBssl:.*\fR (meaning that only SSL -controller connections will be accepted) when any of the SSL -configuration options \fB--private-key\fR, \fB--certificate\fR, or -\fB--ca-cert\fR is specified. The default is \fB.*\fR otherwise -(meaning that any controller will be accepted). - -The \fIregex\fR is implicitly anchored at the beginning of the -controller location string, as if it begins with \fB^\fR. - -When controller discovery is not performed, this option has no effect. - -.TP -\fB--no-resolv-conf\fR -When \fBofprotocol\fR performs controller discovery (see \fBCONTACTING -THE CONTROLLER\fR, above, for more information about controller -discovery), by default it overwrites the system's -\fB/etc/resolv.conf\fR with domain information and DNS servers -obtained via DHCP. If the location of the controller is specified -using a hostname, rather than an IP address, and the network's DNS -servers ever change, this behavior is essential. But because it also -interferes with any administrator or process that manages -\fB/etc/resolv.conf\fR, when this option is specified, \fBofprotocol\fR -will not modify \fB/etc/resolv.conf\fR. - -\fBofprotocol\fR will only modify \fBresolv.conf\fR if the DHCP response -that it receives specifies one or more DNS servers. - -When controller discovery is not performed, this option has no effect. - -.SS "Networking Options" -.TP -\fB-F\fR, \fB--fail=\fR[\fBopen\fR|\fBclosed\fR] -The controller is, ordinarily, responsible for setting up all flows on -the OpenFlow switch. Thus, if the connection to the controller fails, -no new network connections can be set up. If the connection to the -controller stays down long enough, no packets can pass through the -switch at all. - -If this option is set to \fBopen\fR (the default), \fBofprotocol\fR will -take over responsibility for setting up flows in the local datapath -when no message has been received from the controller for three times -the inactivity probe interval (see below), or 45 seconds by default. -In this ``fail open'' mode, \fBofprotocol\fR causes the datapath to act -like an ordinary MAC-learning switch. \fBofprotocol\fR will continue to -retry connection to the controller in the background and, when the -connection succeeds, it discontinues its fail-open behavior. The -secure channel enters the fail-open mode when - -If this option is set to \fBclosed\fR, then \fBofprotocol\fR will not -set up flows on its own when the controller connection fails. - -.TP -\fB--inactivity-probe=\fIsecs\fR -When the secure channel is connected to the controller, the secure -channel waits for a message to be received from the controller for -\fIsecs\fR seconds before it sends a inactivity probe to the -controller. After sending the inactivity probe, if no response is -received for an additional \fIsecs\fR seconds, the secure channel -assumes that the connection has been broken and attempts to reconnect. -The default is 15 seconds, and the minimum value is 1 seconds. - -When fail-open mode is configured, changing the inactivity probe -interval also changes the interval before entering fail-open mode (see -above). - -.TP -\fB--max-idle=\fIsecs\fR|\fBpermanent\fR -Sets \fIsecs\fR as the number of seconds that a flow set up by the -secure channel will remain in the switch's flow table without any -matching packets being seen. If \fBpermanent\fR is specified, which -is not recommended, flows set up by the secure channel will never -expire. The default is 15 seconds. - -Most flows are set up by the OpenFlow controller, not by the secure -channel. This option affects only the following flows, which the -secure channel sets up itself: - -.RS -.IP \(bu -When \fB--fail=open\fR is specified, flows set up when the secure -channel has not been able to contact the controller for the configured -fail-open delay. - -.IP \(bu -When in-band control is in use, flows set up to bootstrap contacting -the controller (see \fBCONTACTING THE CONTROLLER\fR, above, for -more information about in-band control). -.RE - -.IP -As a result, when both \fB--fail=closed\fR and \fB--out-of-band\fR are -specified, this option has no effect. - -.TP -\fB--max-backoff=\fIsecs\fR -Sets the maximum time between attempts to connect to the controller to -\fIsecs\fR, which must be at least 1. The actual interval between -connection attempts starts at 1 second and doubles on each failing -attempt until it reaches the maximum. The default maximum backoff -time is 15 seconds. - -.TP -\fB-l\fR, \fB--listen=\fImethod\fR -Configures the switch to additionally listen for incoming OpenFlow -connections for switch management with \fBdpctl\fR. The \fImethod\fR -must be given as one of the passive OpenFlow connection methods listed -below. This option may be specified multiple times to listen to -multiple connection methods. - -.RS -.TP -\fBpssl:\fR[\fIport\fR] -Listens for SSL connections on \fIport\fR (default: 6633). The -\fB--private-key\fR, \fB--certificate\fR, and \fB--ca-cert\fR options -are mandatory when this form is used. - -.TP -\fBptcp:\fR[\fIport\fR] -Listens for TCP connections on \fIport\fR (default: 6633). - -.TP -\fBpunix:\fIfile\fR -Listens for connections on Unix domain server socket named \fIfile\fR. -.RE - -.TP -\fB-m\fR, \fB--monitor=\fImethod\fR -Configures the switch to additionally listen for incoming OpenFlow -connections for switch monitoring with \fBdpctl\fR's \fBmonitor\fR -command. The \fImethod\fR must be given as one of the passive -OpenFlow connection methods listed above as acceptable for -\fB--listen\fR. - -When \fBdpctl monitor\fR makes a monitoring connection, \fBofprotocol\fR -sends it a copy of every OpenFlow message sent to or received from the -kernel in the normal course of its operations. It does not send a -copy of any messages sent to or from the OpenFlow connection to the -controller. Most of these messages will be seen anyhow, however, -because \fBofprotocol\fR mainly acts as a relay between the controller -and the kernel. \fBofprotocol\fR also does not send a copy of any -messages sent to or from the OpenFlow connection to the controller. -Such messages will typically \fBnot\fR be seen, because \fBofprotocol\fR -maintains a separate connection to the kernel for each management -connection. - -Messages are copied to the monitoring connections on a best-effort -basis. In particular, if the socket buffer of the monitoring -connection fills up, some messages will be lost. - -.TP -\fB--in-band\fR, \fB--out-of-band\fR -Configures \fBofprotocol\fR to operate in in-band or out-of-band control -mode (see \fBCONTACTING THE CONTROLLER\fR above). When neither option -is given, the default is in-band control. - -.TP -\fB--stp\fR, \fB--no-stp\fR -Enable or disable implementation of IEEE 802.1D Spanning Tree Protocol -at the switch. The default is \fB--no-stp\fR in this distribution, -because bugs in the STP implementation are still being worked out. -The default will change to \fB--stp\fR at some point in the future. - -.TP -\fB--emerg-flow\fR -Enable emergecny flow protection and restration at the switch. If emergency -flow enabled, \fBofprotocol\fR will attempt to switch flow table to emergency's -one when a controller connection fails. The default is disabled in this -distribution. - -.SS "Rate-Limiting Options" - -These options configure how the switch applies a ``token bucket'' to -limit the rate at which packets in unknown flows are forwarded to an -OpenFlow controller for flow-setup processing. This feature prevents -a single OpenFlow switch from overwhelming a controller. - -.TP -\fB--rate-limit\fR[\fB=\fIrate\fR] -. -Limits the maximum rate at which packets will be forwarded to the -OpenFlow controller to \fIrate\fR packets per second. If \fIrate\fR -is not specified then the default of 1,000 packets per second is used. - -If \fB--rate-limit\fR is not used, then the switch does not limit the -rate at which packets are forwarded to the controller. - -.TP -\fB--burst-limit=\fIburst\fR -. -Sets the maximum number of unused packet credits that the switch will -allow to accumulate during time in which no packets are being -forwarded to the OpenFlow controller to \fIburst\fR (measured in -packets). The default \fIburst\fR is one-quarter of the \fIrate\fR -specified on \fB--rate-limit\fR. - -This option takes effect only when \fB--rate-limit\fR is also specified. - -.SS "Daemon Options" -.so lib/daemon.man - -.SS "Public Key Infrastructure Options" - -.TP -\fB-p\fR, \fB--private-key=\fIprivkey.pem\fR -Specifies a PEM file containing the private key used as the switch's -identity for SSL connections to the controller. - -.TP -\fB-c\fR, \fB--certificate=\fIcert.pem\fR -Specifies a PEM file containing a certificate, signed by the -controller's certificate authority (CA), that certifies the switch's -private key to identify a trustworthy switch. - -.TP -\fB-C\fR, \fB--ca-cert=\fIcacert.pem\fR -Specifies a PEM file containing the CA certificate used to verify that -the switch is connected to a trustworthy controller. - -.TP -\fB--bootstrap-ca-cert=\fIcacert.pem\fR -When \fIcacert.pem\fR exists, this option has the same effect as -\fB-C\fR or \fB--ca-cert\fR. If it does not exist, then \fBofprotocol\fR -will attempt to obtain the CA certificate from the controller on its -first SSL connection and save it to the named PEM file. If it is -successful, it will immediately drop the connection and reconnect, and -from then on all SSL connections must be authenticated by a -certificate signed by the CA certificate thus obtained. - -\fBThis option exposes the SSL connection to a man-in-the-middle -attack obtaining the initial CA certificate\fR, but it may be useful -for bootstrapping. - -This option is only useful if the controller sends its CA certificate -as part of the SSL certificate chain. The SSL protocol does not -require the controller to send the CA certificate, but -\fBcontroller\fR(8) can be configured to do so with the -\fB--peer-ca-cert\fR option. - -.SS "Logging Options" -.so lib/vlog.man -.SS "Other Options" -.so lib/common.man -.so lib/leak-checker.man - -.SH "SEE ALSO" - -.BR dpctl (8), -.BR ofp-discover (8), -.BR controller (8), -.BR ofp-pki (8), -.BR ofdatapath (8), -.BR vlogconf (8) diff --git a/openflow/secchan/port-watcher.c b/openflow/secchan/port-watcher.c deleted file mode 100644 index 0998e161..00000000 --- a/openflow/secchan/port-watcher.c +++ /dev/null @@ -1,620 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include "port-watcher.h" -#include -#include -#include -#include -#include "dynamic-string.h" -#include "netdev.h" -#include "ofpbuf.h" -#include "openflow/openflow.h" -#include "poll-loop.h" -#include "port-array.h" -#include "rconn.h" -#include "shash.h" -#include "svec.h" -#include "timeval.h" -#include "vconn.h" -#include "xtoxll.h" - -#define THIS_MODULE VLM_port_watcher -#include "vlog.h" - -struct port_watcher_cb { - port_changed_cb_func *port_changed; - void *aux; -}; - -struct port_watcher_local_cb { - local_port_changed_cb_func *local_port_changed; - void *aux; -}; - -struct port_watcher { - struct rconn *local_rconn; - struct rconn *remote_rconn; - struct port_array ports; - time_t last_feature_request; - bool got_feature_reply; - uint64_t datapath_id; - int n_txq; - struct port_watcher_cb cbs[2]; - int n_cbs; - struct port_watcher_local_cb local_cbs[4]; - int n_local_cbs; - char local_port_name[OFP_MAX_PORT_NAME_LEN + 1]; - struct netdev_monitor *mon; - struct shash port_by_name; -}; - -/* Returns the number of fields that differ from 'a' to 'b'. */ -static int -opp_differs(const struct ofp_phy_port *a, const struct ofp_phy_port *b) -{ - BUILD_ASSERT_DECL(sizeof *a == 48); /* Trips when we add or remove fields. */ - return ((a->port_no != b->port_no) - + (memcmp(a->hw_addr, b->hw_addr, sizeof a->hw_addr) != 0) - + (memcmp(a->name, b->name, sizeof a->name) != 0) - + (a->config != b->config) - + (a->state != b->state) - + (a->curr != b->curr) - + (a->advertised != b->advertised) - + (a->supported != b->supported) - + (a->peer != b->peer)); -} - -static void -sanitize_opp(struct ofp_phy_port *opp) -{ - size_t i; - - for (i = 0; i < sizeof opp->name; i++) { - char c = opp->name[i]; - if (c && (c < 0x20 || c > 0x7e)) { - opp->name[i] = '.'; - } - } - opp->name[sizeof opp->name - 1] = '\0'; -} - -static void -call_port_changed_callbacks(struct port_watcher *pw, int port_no, - const struct ofp_phy_port *old, - const struct ofp_phy_port *new) -{ - int i; - for (i = 0; i < pw->n_cbs; i++) { - port_changed_cb_func *port_changed = pw->cbs[i].port_changed; - (port_changed)(port_no, old, new, pw->cbs[i].aux); - } -} - -void -get_port_name(const struct ofp_phy_port *port, char *name, size_t name_size) -{ - char *p; - - memcpy(name, port->name, MIN(name_size, sizeof port->name)); - name[name_size - 1] = '\0'; - for (p = name; *p != '\0'; p++) { - if (*p < 32 || *p > 126) { - *p = '.'; - } - } -} - -static struct ofp_phy_port * -lookup_port(const struct port_watcher *pw, uint16_t port_no) -{ - return port_array_get(&pw->ports, port_no); -} - -static void -call_local_port_changed_callbacks(struct port_watcher *pw) -{ - char name[OFP_MAX_PORT_NAME_LEN + 1]; - const struct ofp_phy_port *port; - int i; - - /* Pass the local port to the callbacks, if it exists. - Pass a null pointer if there is no local port. */ - port = lookup_port(pw, OFPP_LOCAL); - - /* Log the name of the local port. */ - if (port) { - get_port_name(port, name, sizeof name); - } else { - name[0] = '\0'; - } - if (strcmp(pw->local_port_name, name)) { - if (name[0]) { - VLOG_INFO("Identified data path local port as \"%s\".", name); - } else { - VLOG_WARN("Data path has no local port."); - } - strcpy(pw->local_port_name, name); - } - - /* Invoke callbacks. */ - for (i = 0; i < pw->n_local_cbs; i++) { - local_port_changed_cb_func *cb = pw->local_cbs[i].local_port_changed; - (cb)(port, pw->local_cbs[i].aux); - } -} - -static void -update_phy_port(struct port_watcher *pw, struct ofp_phy_port *opp, - uint8_t reason) -{ - struct ofp_phy_port *old; - uint16_t port_no; - - port_no = ntohs(opp->port_no); - old = lookup_port(pw, port_no); - - if (reason == OFPPR_DELETE && old) { - call_port_changed_callbacks(pw, port_no, old, NULL); - free(old); - port_array_set(&pw->ports, port_no, NULL); - } else if (reason == OFPPR_MODIFY || reason == OFPPR_ADD) { - if (old) { - uint32_t s_mask = htonl(OFPPS_STP_MASK); - opp->state = (opp->state & ~s_mask) | (old->state & s_mask); - } - if (!old || opp_differs(opp, old)) { - struct ofp_phy_port new = *opp; - sanitize_opp(&new); - call_port_changed_callbacks(pw, port_no, old, &new); - if (old) { - *old = new; - } else { - port_array_set(&pw->ports, port_no, xmemdup(&new, sizeof new)); - } - } - } -} - -static void -update_netdev_monitor_devices(struct port_watcher *pw) -{ - struct ofp_phy_port *p; - struct svec netdevs; - unsigned int port_no; - - svec_init(&netdevs); - shash_clear(&pw->port_by_name); - for (p = port_array_first(&pw->ports, &port_no); p; - p = port_array_next(&pw->ports, &port_no)) { - const char *name = (const char *) p->name; - svec_add(&netdevs, name); - shash_add(&pw->port_by_name, name, p); - } - netdev_monitor_set_devices(pw->mon, netdevs.names, netdevs.n); - svec_destroy(&netdevs); -} - -static bool -port_watcher_local_packet_cb(struct relay *r, void *pw_) -{ - struct port_watcher *pw = pw_; - struct ofpbuf *msg = r->halves[HALF_LOCAL].rxbuf; - struct ofp_header *oh = msg->data; - - if (oh->type == OFPT_FEATURES_REPLY - && msg->size >= offsetof(struct ofp_switch_features, ports)) { - struct ofp_switch_features *osf = msg->data; - bool seen[PORT_ARRAY_SIZE]; - struct ofp_phy_port *p; - unsigned int port_no; - size_t n_ports; - size_t i; - - pw->got_feature_reply = true; - if (pw->datapath_id != osf->datapath_id) { - pw->datapath_id = osf->datapath_id; - VLOG_INFO("Datapath id is %012"PRIx64, ntohll(pw->datapath_id)); - } - - /* Update each port included in the message. */ - memset(seen, false, sizeof seen); - n_ports = ((msg->size - offsetof(struct ofp_switch_features, ports)) - / sizeof *osf->ports); - for (i = 0; i < n_ports; i++) { - struct ofp_phy_port *opp = &osf->ports[i]; - update_phy_port(pw, opp, OFPPR_MODIFY); - seen[ntohs(opp->port_no)] = true; - } - - /* Delete all the ports not included in the message. */ - for (p = port_array_first(&pw->ports, &port_no); p; - p = port_array_next(&pw->ports, &port_no)) { - if (!seen[port_no]) { - update_phy_port(pw, p, OFPPR_DELETE); - } - } - - update_netdev_monitor_devices(pw); - - call_local_port_changed_callbacks(pw); - } else if (oh->type == OFPT_PORT_STATUS - && msg->size >= sizeof(struct ofp_port_status)) { - struct ofp_port_status *ops = msg->data; - update_phy_port(pw, &ops->desc, ops->reason); - if (ops->desc.port_no == htons(OFPP_LOCAL)) { - call_local_port_changed_callbacks(pw); - } - if (ops->reason == OFPPR_ADD || OFPPR_DELETE) { - update_netdev_monitor_devices(pw); - } - } - return false; -} - -static void -bring_netdev_up_or_down(const char *name, bool down) -{ - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); - struct netdev *netdev; - int retval; - - retval = netdev_open(name, NETDEV_ETH_TYPE_NONE, &netdev); - if (!retval) { - if (down) { - retval = netdev_turn_flags_off(netdev, NETDEV_UP, true); - } else { - retval = netdev_turn_flags_on(netdev, NETDEV_UP, true); - } - if (retval) { - VLOG_WARN_RL(&rl, "failed to bring network device %s %s: %s", - name, down ? "down" : "up", strerror(retval)); - } - netdev_close(netdev); - } else { - VLOG_WARN_RL(&rl, "failed to open network device %s: %s", - name, strerror(retval)); - } -} - -static bool -port_watcher_remote_packet_cb(struct relay *r, void *pw_) -{ - struct port_watcher *pw = pw_; - struct ofpbuf *msg = r->halves[HALF_REMOTE].rxbuf; - struct ofp_header *oh = msg->data; - - if (oh->type == OFPT_PORT_MOD - && msg->size >= sizeof(struct ofp_port_mod)) { - struct ofp_port_mod *opm = msg->data; - uint16_t port_no = ntohs(opm->port_no); - struct ofp_phy_port *pw_opp = lookup_port(pw, port_no); - if (pw_opp->port_no != htons(OFPP_NONE)) { - struct ofp_phy_port old = *pw_opp; - pw_opp->config = ((pw_opp->config & ~opm->mask) - | (opm->config & opm->mask)); - call_port_changed_callbacks(pw, port_no, &old, pw_opp); - if (pw_opp->port_no == htons(OFPP_LOCAL)) { - call_local_port_changed_callbacks(pw); - } - - if (opm->mask & htonl(OFPPC_PORT_DOWN)) { - bring_netdev_up_or_down((const char *) pw_opp->name, - opm->config & htonl(OFPPC_PORT_DOWN)); - } - } - } - return false; -} - -/* Sets 'bit' in '*word' to 0 or 1 according to 'value'. */ -static void -set_bit(uint32_t bit, bool value, uint32_t *word) -{ - if (value) { - *word |= bit; - } else { - *word &= ~bit; - } -} - -static void -port_watcher_periodic_cb(void *pw_) -{ - struct port_watcher *pw = pw_; - const char *name; - - if (!pw->got_feature_reply - && time_now() >= pw->last_feature_request + 5 - && rconn_is_connected(pw->local_rconn)) { - struct ofpbuf *b; - make_openflow(sizeof(struct ofp_header), OFPT_FEATURES_REQUEST, &b); - rconn_send_with_limit(pw->local_rconn, b, &pw->n_txq, 1); - pw->last_feature_request = time_now(); - } - - netdev_monitor_run(pw->mon); - while ((name = netdev_monitor_poll(pw->mon)) != NULL) { - struct ofp_phy_port *opp; - struct ofp_phy_port new_opp; - enum netdev_flags flags; - int retval; - - opp = shash_find_data(&pw->port_by_name, name); - if (!opp) { - continue; - } - - retval = netdev_nodev_get_flags(name, &flags); - if (retval) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); - VLOG_WARN_RL(&rl, "could not get flags for %s", name); - continue; - } - - new_opp = *opp; - set_bit(htonl(OFPPC_PORT_DOWN), ~flags & NETDEV_UP, &new_opp.config); - set_bit(htonl(OFPPS_LINK_DOWN), ~flags & NETDEV_CARRIER, - &new_opp.state); - if (opp->config != new_opp.config || opp->state != new_opp.state) { - struct ofp_port_status *ops; - struct ofpbuf *b; - - /* Notify other secchan modules. */ - update_phy_port(pw, &new_opp, OFPPR_MODIFY); - if (new_opp.port_no == htons(OFPP_LOCAL)) { - call_local_port_changed_callbacks(pw); - } - - /* Notify the controller that the flags changed. */ - ops = make_openflow(sizeof *ops, OFPT_PORT_STATUS, &b); - ops->reason = OFPPR_MODIFY; - ops->desc = new_opp; - rconn_send(pw->remote_rconn, b, NULL); - } - } -} - -static void -port_watcher_wait_cb(void *pw_) -{ - struct port_watcher *pw = pw_; - if (!pw->got_feature_reply && rconn_is_connected(pw->local_rconn)) { - if (pw->last_feature_request != TIME_MIN) { - poll_timer_wait(pw->last_feature_request + 5 - time_now()); - } else { - poll_immediate_wake(); - } - } - netdev_monitor_wait(pw->mon); -} - -static void -put_duplexes(struct ds *ds, const char *name, uint32_t features, - uint32_t hd_bit, uint32_t fd_bit) -{ - if (features & (hd_bit | fd_bit)) { - ds_put_format(ds, " %s", name); - if (features & hd_bit) { - ds_put_cstr(ds, "(HD)"); - } - if (features & fd_bit) { - ds_put_cstr(ds, "(FD)"); - } - } -} - -static void -put_features(struct ds *ds, const char *name, uint32_t features) -{ - if (features & (OFPPF_10MB_HD | OFPPF_10MB_FD - | OFPPF_100MB_HD | OFPPF_100MB_FD - | OFPPF_1GB_HD | OFPPF_1GB_FD | OFPPF_10GB_FD)) { - ds_put_cstr(ds, name); - put_duplexes(ds, "10M", features, OFPPF_10MB_HD, OFPPF_10MB_FD); - put_duplexes(ds, "100M", features, - OFPPF_100MB_HD, OFPPF_100MB_FD); - put_duplexes(ds, "1G", features, OFPPF_1GB_HD, OFPPF_1GB_FD); - if (features & OFPPF_10GB_FD) { - ds_put_cstr(ds, " 10G"); - } - if (features & OFPPF_AUTONEG) { - ds_put_cstr(ds, " AUTO_NEG"); - } - if (features & OFPPF_PAUSE) { - ds_put_cstr(ds, " PAUSE"); - } - if (features & OFPPF_PAUSE_ASYM) { - ds_put_cstr(ds, " PAUSE_ASYM"); - } - } -} - -static void -log_port_status(uint16_t port_no, - const struct ofp_phy_port *old, - const struct ofp_phy_port *new, - void *aux UNUSED) -{ - if (VLOG_IS_DBG_ENABLED()) { - if (old && new && (opp_differs(old, new) - == ((old->config != new->config) - + (old->state != new->state)))) - { - /* Don't care if only state or config changed. */ - } else if (!new) { - if (old) { - VLOG_DBG("Port %d deleted", port_no); - } - } else { - struct ds ds = DS_EMPTY_INITIALIZER; - uint32_t curr = ntohl(new->curr); - uint32_t supported = ntohl(new->supported); - ds_put_format(&ds, "\"%s\", "ETH_ADDR_FMT, new->name, - ETH_ADDR_ARGS(new->hw_addr)); - if (curr) { - put_features(&ds, ", current", curr); - } - if (supported) { - put_features(&ds, ", supports", supported); - } - VLOG_DBG("Port %d %s: %s", - port_no, old ? "changed" : "added", ds_cstr(&ds)); - ds_destroy(&ds); - } - } -} - -void -port_watcher_register_callback(struct port_watcher *pw, - port_changed_cb_func *port_changed, - void *aux) -{ - assert(pw->n_cbs < ARRAY_SIZE(pw->cbs)); - pw->cbs[pw->n_cbs].port_changed = port_changed; - pw->cbs[pw->n_cbs].aux = aux; - pw->n_cbs++; -} - -void -port_watcher_register_local_port_callback(struct port_watcher *pw, - local_port_changed_cb_func *cb, - void *aux) -{ - assert(pw->n_local_cbs < ARRAY_SIZE(pw->local_cbs)); - pw->local_cbs[pw->n_local_cbs].local_port_changed = cb; - pw->local_cbs[pw->n_local_cbs].aux = aux; - pw->n_local_cbs++; -} - -uint32_t -port_watcher_get_config(const struct port_watcher *pw, uint16_t port_no) -{ - struct ofp_phy_port *p = lookup_port(pw, port_no); - return p ? ntohl(p->config) : 0; -} - -const char * -port_watcher_get_name(const struct port_watcher *pw, uint16_t port_no) -{ - struct ofp_phy_port *p = lookup_port(pw, port_no); - return p ? (const char *) p->name : NULL; -} - -const uint8_t * -port_watcher_get_hwaddr(const struct port_watcher *pw, uint16_t port_no) -{ - struct ofp_phy_port *p = lookup_port(pw, port_no); - return p ? p->hw_addr : NULL; -} - -void -port_watcher_set_flags(struct port_watcher *pw, uint16_t port_no, - uint32_t config, uint32_t c_mask, - uint32_t state, uint32_t s_mask) -{ - struct ofp_phy_port old; - struct ofp_phy_port *p; - struct ofp_port_mod *opm; - struct ofp_port_status *ops; - struct ofpbuf *b; - - p = lookup_port(pw, port_no); - if (!p) { - return; - } - - if (!((ntohl(p->state) ^ state) & s_mask) - && (!((ntohl(p->config) ^ config) & c_mask))) { - return; - } - old = *p; - - /* Update our idea of the flags. */ - p->config = htonl((ntohl(p->config) & ~c_mask) | (config & c_mask)); - p->state = htonl((ntohl(p->state) & ~s_mask) | (state & s_mask)); - call_port_changed_callbacks(pw, port_no, &old, p); - - /* Change the flags in the datapath. */ - opm = make_openflow(sizeof *opm, OFPT_PORT_MOD, &b); - opm->port_no = p->port_no; - memcpy(opm->hw_addr, p->hw_addr, OFP_ETH_ALEN); - opm->config = p->config; - opm->mask = htonl(c_mask); - opm->advertise = htonl(0); - rconn_send(pw->local_rconn, b, NULL); - - /* Notify the controller that the flags changed. */ - ops = make_openflow(sizeof *ops, OFPT_PORT_STATUS, &b); - ops->reason = OFPPR_MODIFY; - ops->desc = *p; - rconn_send(pw->remote_rconn, b, NULL); -} - -bool -port_watcher_is_ready(const struct port_watcher *pw) -{ - return pw->got_feature_reply; -} - -static struct hook_class port_watcher_hook_class = { - port_watcher_local_packet_cb, /* local_packet_cb */ - port_watcher_remote_packet_cb, /* remote_packet_cb */ - port_watcher_periodic_cb, /* periodic_cb */ - port_watcher_wait_cb, /* wait_cb */ - NULL, /* closing_cb */ -}; - -void -port_watcher_start(struct secchan *secchan, - struct rconn *local_rconn, struct rconn *remote_rconn, - struct port_watcher **pwp) -{ - struct port_watcher *pw; - int retval; - - pw = *pwp = xcalloc(1, sizeof *pw); - pw->local_rconn = local_rconn; - pw->remote_rconn = remote_rconn; - pw->last_feature_request = TIME_MIN; - port_array_init(&pw->ports); - pw->local_port_name[0] = '\0'; - retval = netdev_monitor_create(&pw->mon); - if (retval) { - ofp_fatal(retval, "failed to start network device monitoring"); - } - shash_init(&pw->port_by_name); - port_watcher_register_callback(pw, log_port_status, NULL); - add_hook(secchan, &port_watcher_hook_class, pw); -} diff --git a/openflow/secchan/port-watcher.h b/openflow/secchan/port-watcher.h deleted file mode 100644 index 904e545a..00000000 --- a/openflow/secchan/port-watcher.h +++ /dev/null @@ -1,77 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#ifndef PORT_WATCHER_H -#define PORT_WATCHER_H 1 - -#include -#include "compiler.h" -#include "secchan.h" - -struct ofp_phy_port; -struct port_watcher; -struct secchan; - -void port_watcher_start(struct secchan *, - struct rconn *local, struct rconn *remote, - struct port_watcher **); -bool port_watcher_is_ready(const struct port_watcher *); -uint32_t port_watcher_get_config(const struct port_watcher *, - uint16_t port_no); -const char *port_watcher_get_name(const struct port_watcher *, - uint16_t port_no) UNUSED; -const uint8_t *port_watcher_get_hwaddr(const struct port_watcher *, - uint16_t port_no); -void port_watcher_set_flags(struct port_watcher *, uint16_t port_no, - uint32_t config, uint32_t c_mask, - uint32_t state, uint32_t s_mask); - -typedef void port_changed_cb_func(uint16_t port_no, - const struct ofp_phy_port *old, - const struct ofp_phy_port *new, - void *aux); - -void port_watcher_register_callback(struct port_watcher *, - port_changed_cb_func *port_changed, - void *aux); - -typedef void local_port_changed_cb_func(const struct ofp_phy_port *new, - void *aux); - -void port_watcher_register_local_port_callback(struct port_watcher *pw, - local_port_changed_cb_func *cb, - void *aux); - -void get_port_name(const struct ofp_phy_port *, char *name, size_t name_size); - -#endif /* port-watcher.h */ diff --git a/openflow/secchan/protocol-stat.c b/openflow/secchan/protocol-stat.c deleted file mode 100644 index d54548b3..00000000 --- a/openflow/secchan/protocol-stat.c +++ /dev/null @@ -1,204 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#include -#include -#include -#include -#include -#include - -#include "openflow/openflow.h" -#include "openflow/private-ext.h" - -#include "ofpbuf.h" -#include "util.h" -#include "xtoxll.h" -#include "rconn.h" -#include "vconn.h" -#include "secchan.h" -#include "status.h" -#include "timeval.h" -#include "sat-math.h" -#include "ofpstat.h" -#include "protocol-stat.h" -#define THIS_MODULE VLM_protocol_stat -#include "vlog.h" - -#define COPY_OFPS(dst_ofps, src_ofps, tag) \ -do { \ - (dst_ofps)->tag = htonll((src_ofps)->tag); \ -} while (0) - -#define COPY_OFP_STAT(dst_ofps, src_ofps) \ -do { \ - COPY_OFPS(dst_ofps, src_ofps, ofps_total); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_unknown); \ - \ - COPY_OFPS(dst_ofps, src_ofps, ofps_hello); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_echo_request); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_echo_reply); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_vendor); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_feats_request); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_feats_reply); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_get_config_request); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_get_config_reply); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_set_config); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_packet_in); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_flow_removed); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_port_status); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_packet_out); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_flow_mod); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_port_mod); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_stats_request); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_stats_reply); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_barrier_request); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_barrier_reply); \ - \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_type.hello_fail); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_type.bad_request); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_type.bad_action); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_type.flow_mod_fail); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_type.unknown); \ - \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.hf_incompat); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.hf_eperm); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.br_bad_version); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.br_bad_type); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.br_bad_stat); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.br_bad_vendor); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.br_eperm); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.ba_bad_type); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.ba_bad_len); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.ba_bad_vendor); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.ba_bad_vendor_type); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.ba_bad_out_port); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.ba_eperm); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.fmf_all_tables_full); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.fmf_overlap); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.fmf_eperm); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.unknown); \ - \ - COPY_OFPS(dst_ofps, src_ofps, ofps_flow_mod_ops.add); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_flow_mod_ops.modify); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_flow_mod_ops.delete); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_flow_mod_ops.delete_strict); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_flow_mod_ops.unknown); \ -} while (0) - -struct protocol_stat_context { - const struct settings *settings; - const struct secchan *secchan; - struct rconn *local_rconn; - struct rconn *remote_rconn; - struct ofpstat ofps_rcvd; - struct ofpstat ofps_sent; -}; - -static bool protocol_stat_remote_packet_cb(struct relay *, void *); - -static bool -protocol_stat_remote_packet_cb(struct relay *relay, void *context_) -{ - struct protocol_stat_context *context = context_; - struct rconn *mgmt_rconn = relay->halves[HALF_REMOTE].rconn; - struct ofpbuf *qbuf = relay->halves[HALF_REMOTE].rxbuf; - struct ofpbuf *pbuf = NULL; - struct private_vxhdr *qvxhdr = NULL; - struct private_vxhdr *pvxhdr = NULL; - struct private_vxopt *qvxopt = NULL; - struct private_vxopt *pvxopt = NULL; - struct ofpstat *ofps = NULL; - struct ofpstat ofps_rcvd; - struct ofpstat ofps_sent; - int error = 0; - - if (qbuf->size < sizeof(*qvxhdr)) - return false; - qvxhdr = qbuf->data; - if (qvxhdr->ofp_hdr.type != OFPT_VENDOR) - return false; - if (ntohl(qvxhdr->ofp_vxid) != PRIVATE_VENDOR_ID) { - return false; - } - qvxopt = (struct private_vxopt *)(qvxhdr + 1); - if (ntohs(qvxopt->pvo_type) != PRIVATEOPT_PROTOCOL_STATS_REQUEST) { - return true; - } - - pvxhdr = make_openflow_xid(sizeof(*pvxhdr) + sizeof(*pvxopt) - + (sizeof(*ofps) * 2), - OFPT_VENDOR, qvxhdr->ofp_hdr.xid, &pbuf); - pvxopt = (struct private_vxopt *)(pvxhdr + 1); - pvxhdr->ofp_vxid = qvxhdr->ofp_vxid; - pvxopt->pvo_type = htons(PRIVATEOPT_PROTOCOL_STATS_REPLY); - pvxopt->pvo_len = htons(sizeof(*ofps) * 2); - - rconn_update_protocol_stat(context->remote_rconn, - &ofps_rcvd, &ofps_sent); - ofps = (struct ofpstat *)((uint8_t *)(pvxhdr + 1) + sizeof(*pvxopt)); - COPY_OFP_STAT(ofps, &ofps_rcvd); - ofps = ofps + 1; - COPY_OFP_STAT(ofps, &ofps_sent); - - error = rconn_send(mgmt_rconn, pbuf, NULL); - if (error && error != EAGAIN) { - VLOG_WARN("send failed (%s)", strerror(error)); - } - - return true; -} - -void -protocol_stat_start(struct secchan *secchan, const struct settings *settings, - struct rconn *local_rconn, struct rconn *remote_rconn) -{ - struct protocol_stat_context *context = NULL; - static struct hook_class protocol_stat_hook_class = { - NULL, /* local_packet_cb */ - protocol_stat_remote_packet_cb, /* remote_packet_cb */ - NULL, /* periodic_cb */ - NULL, /* wait_cb */ - NULL, /* closing_cb */ - }; - - context = xmalloc(sizeof(*context)); - context->settings = settings; - context->secchan = secchan; - context->local_rconn = local_rconn; - context->remote_rconn = remote_rconn; - memset(&context->ofps_rcvd, 0, sizeof(context->ofps_rcvd)); - memset(&context->ofps_sent, 0, sizeof(context->ofps_sent)); - - add_hook(secchan, &protocol_stat_hook_class, context); -} diff --git a/openflow/secchan/protocol-stat.h b/openflow/secchan/protocol-stat.h deleted file mode 100644 index 3037b449..00000000 --- a/openflow/secchan/protocol-stat.h +++ /dev/null @@ -1,44 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#ifndef PROTOCOL_STAT_H_ -#define PROTOCOL_STAT_H_ - -struct rconn; -struct secchan; -struct settings; -struct switch_status; - -void protocol_stat_start(struct secchan *, const struct settings *, - struct rconn *, struct rconn *); - -#endif diff --git a/openflow/secchan/ratelimit.c b/openflow/secchan/ratelimit.c deleted file mode 100644 index 7a1e4951..00000000 --- a/openflow/secchan/ratelimit.c +++ /dev/null @@ -1,263 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include "ratelimit.h" -#include -#include -#include "ofpbuf.h" -#include "openflow/openflow.h" -#include "poll-loop.h" -#include "queue.h" -#include "rconn.h" -#include "secchan.h" -#include "status.h" -#include "timeval.h" -#include "vconn.h" - -struct rate_limiter { - const struct settings *s; - struct rconn *remote_rconn; - - /* One queue per physical port. */ - struct ofp_queue queues[OFPP_MAX]; - int n_queued; /* Sum over queues[*].n. */ - int next_tx_port; /* Next port to check in round-robin. */ - - /* Token bucket. - * - * It costs 1000 tokens to send a single packet_in message. A single token - * per message would be more straightforward, but this choice lets us avoid - * round-off error in refill_bucket()'s calculation of how many tokens to - * add to the bucket, since no division step is needed. */ - long long int last_fill; /* Time at which we last added tokens. */ - int tokens; /* Current number of tokens. */ - - /* Transmission queue. */ - int n_txq; /* No. of packets waiting in rconn for tx. */ - - /* Statistics reporting. */ - unsigned long long n_normal; /* # txed w/o rate limit queuing. */ - unsigned long long n_limited; /* # queued for rate limiting. */ - unsigned long long n_queue_dropped; /* # dropped due to queue overflow. */ - unsigned long long n_tx_dropped; /* # dropped due to tx overflow. */ -}; - -/* Drop a packet from the longest queue in 'rl'. */ -static void -drop_packet(struct rate_limiter *rl) -{ - struct ofp_queue *longest; /* Queue currently selected as longest. */ - int n_longest; /* # of queues of same length as 'longest'. */ - struct ofp_queue *q; - - longest = &rl->queues[0]; - n_longest = 1; - for (q = &rl->queues[0]; q < &rl->queues[OFPP_MAX]; q++) { - if (longest->n < q->n) { - longest = q; - n_longest = 1; - } else if (longest->n == q->n) { - n_longest++; - - /* Randomly select one of the longest queues, with a uniform - * distribution (Knuth algorithm 3.4.2R). */ - if (!random_range(n_longest)) { - longest = q; - } - } - } - - /* FIXME: do we want to pop the tail instead? */ - ofpbuf_delete(queue_pop_head(longest)); - rl->n_queued--; -} - -/* Remove and return the next packet to transmit (in round-robin order). */ -static struct ofpbuf * -dequeue_packet(struct rate_limiter *rl) -{ - unsigned int i; - - for (i = 0; i < OFPP_MAX; i++) { - unsigned int port = (rl->next_tx_port + i) % OFPP_MAX; - struct ofp_queue *q = &rl->queues[port]; - if (q->n) { - rl->next_tx_port = (port + 1) % OFPP_MAX; - rl->n_queued--; - return queue_pop_head(q); - } - } - NOT_REACHED(); -} - -/* Add tokens to the bucket based on elapsed time. */ -static void -refill_bucket(struct rate_limiter *rl) -{ - const struct settings *s = rl->s; - long long int now = time_msec(); - long long int tokens = (now - rl->last_fill) * s->rate_limit + rl->tokens; - if (tokens >= 1000) { - rl->last_fill = now; - rl->tokens = MIN(tokens, s->burst_limit * 1000); - } -} - -/* Attempts to remove enough tokens from 'rl' to transmit a packet. Returns - * true if successful, false otherwise. (In the latter case no tokens are - * removed.) */ -static bool -get_token(struct rate_limiter *rl) -{ - if (rl->tokens >= 1000) { - rl->tokens -= 1000; - return true; - } else { - return false; - } -} - -static bool -rate_limit_local_packet_cb(struct relay *r, void *rl_) -{ - struct rate_limiter *rl = rl_; - const struct settings *s = rl->s; - struct ofp_packet_in *opi; - - opi = get_ofp_packet_in(r); - if (!opi) { - return false; - } - - if (opi->reason == OFPR_ACTION) { - /* Don't rate-limit 'ofp-packet_in's generated by flows that the - * controller set up. XXX we should really just rate-limit them - * *separately* so that no one can flood the controller this way. */ - return false; - } - - if (!rl->n_queued && get_token(rl)) { - /* In the common case where we are not constrained by the rate limit, - * let the packet take the normal path. */ - rl->n_normal++; - return false; - } else { - /* Otherwise queue it up for the periodic callback to drain out. */ - struct ofpbuf *msg = r->halves[HALF_LOCAL].rxbuf; - int port = ntohs(opi->in_port) % OFPP_MAX; - if (rl->n_queued >= s->burst_limit) { - drop_packet(rl); - } - queue_push_tail(&rl->queues[port], ofpbuf_clone(msg)); - rl->n_queued++; - rl->n_limited++; - return true; - } -} - -static void -rate_limit_status_cb(struct status_reply *sr, void *rl_) -{ - struct rate_limiter *rl = rl_; - - status_reply_put(sr, "normal=%llu", rl->n_normal); - status_reply_put(sr, "limited=%llu", rl->n_limited); - status_reply_put(sr, "queue-dropped=%llu", rl->n_queue_dropped); - status_reply_put(sr, "tx-dropped=%llu", rl->n_tx_dropped); -} - -static void -rate_limit_periodic_cb(void *rl_) -{ - struct rate_limiter *rl = rl_; - int i; - - /* Drain some packets out of the bucket if possible, but limit the number - * of iterations to allow other code to get work done too. */ - refill_bucket(rl); - for (i = 0; rl->n_queued && get_token(rl) && i < 50; i++) { - /* Use a small, arbitrary limit for the amount of queuing to do here, - * because the TCP connection is responsible for buffering and there is - * no point in trying to transmit faster than the TCP connection can - * handle. */ - struct ofpbuf *b = dequeue_packet(rl); - if (rconn_send_with_limit(rl->remote_rconn, b, &rl->n_txq, 10)) { - rl->n_tx_dropped++; - } - } -} - -static void -rate_limit_wait_cb(void *rl_) -{ - struct rate_limiter *rl = rl_; - if (rl->n_queued) { - if (rl->tokens >= 1000) { - /* We can transmit more packets as soon as we're called again. */ - poll_immediate_wake(); - } else { - /* We have to wait for the bucket to re-fill. We could calculate - * the exact amount of time here for increased smoothness. */ - poll_timer_wait(TIME_UPDATE_INTERVAL / 2); - } - } -} - -static struct hook_class rate_limit_hook_class = { - rate_limit_local_packet_cb, /* local_packet_cb */ - NULL, /* remote_packet_cb */ - rate_limit_periodic_cb, /* periodic_cb */ - rate_limit_wait_cb, /* wait_cb */ - NULL, /* closing_cb */ -}; - -void -rate_limit_start(struct secchan *secchan, const struct settings *s, - struct switch_status *ss, struct rconn *remote) -{ - struct rate_limiter *rl; - size_t i; - - rl = xcalloc(1, sizeof *rl); - rl->s = s; - rl->remote_rconn = remote; - for (i = 0; i < ARRAY_SIZE(rl->queues); i++) { - queue_init(&rl->queues[i]); - } - rl->last_fill = time_msec(); - rl->tokens = s->rate_limit * 100; - switch_status_register_category(ss, "rate-limit", - rate_limit_status_cb, rl); - add_hook(secchan, &rate_limit_hook_class, rl); -} diff --git a/openflow/secchan/ratelimit.h b/openflow/secchan/ratelimit.h deleted file mode 100644 index 25ab9777..00000000 --- a/openflow/secchan/ratelimit.h +++ /dev/null @@ -1,45 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#ifndef RATELIMIT_H -#define RATELIMIT_H 1 - -struct rconn; -struct secchan; -struct settings; -struct switch_status; - -void rate_limit_start(struct secchan *, const struct settings *, - struct switch_status *, struct rconn *remote); - -#endif /* ratelimit.h */ diff --git a/openflow/secchan/secchan.c b/openflow/secchan/secchan.c deleted file mode 100644 index 15c7b696..00000000 --- a/openflow/secchan/secchan.c +++ /dev/null @@ -1,882 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include "secchan.h" -#include -#include -#include -#include -#include -#include -#include - -#include "command-line.h" -#include "compiler.h" -#include "daemon.h" -#include "dirs.h" -#include "discovery.h" -#include "emerg-flow.h" -#include "fail-open.h" -#include "failover.h" -#include "fault.h" -#include "in-band.h" -#include "leak-checker.h" -#include "list.h" -#include "ofpbuf.h" -#include "openflow/openflow.h" -#include "packets.h" -#include "protocol-stat.h" -#include "port-watcher.h" -#include "poll-loop.h" -#include "ratelimit.h" -#include "rconn.h" -#include "stp-secchan.h" -#include "status.h" -#include "timeval.h" -#include "util.h" -#include "vconn-ssl.h" -#include "vconn.h" -#include "vlog-socket.h" - -#include "vlog.h" -#define THIS_MODULE VLM_secchan - -struct hook { - const struct hook_class *class; - void *aux; -}; - -struct secchan { - struct hook *hooks; - size_t n_hooks, allocated_hooks; -}; - -static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60); - -static void parse_options(int argc, char *argv[], struct settings *); -static void usage(void) NO_RETURN; - -static char *vconn_name_without_subscription(const char *); -static struct pvconn *open_passive_vconn(const char *name); -static struct vconn *accept_vconn(struct pvconn *pvconn); - -static struct relay *relay_create(struct rconn *async, - struct rconn *local, struct rconn *remote, - bool is_mgmt_conn); -static struct relay *relay_accept(const struct settings *, struct pvconn *); -static void relay_run(struct relay *, struct secchan *); -static void relay_wait(struct relay *); -static void relay_destroy(struct relay *); - -int -main(int argc, char *argv[]) -{ - struct settings s; - - struct list relays = LIST_INITIALIZER(&relays); - - struct secchan secchan; - - struct pvconn *monitor; - - struct pvconn *listeners[MAX_MGMT]; - size_t n_listeners; - - char *local_rconn_name; - struct rconn *async_rconn, *local_rconn, *remote_rconn; - struct relay *controller_relay; - struct discovery *discovery; - struct switch_status *switch_status; - struct port_watcher *pw; - int i; - int retval; - - set_program_name(argv[0]); - register_fault_handlers(); - time_init(); - vlog_init(); - parse_options(argc, argv, &s); - signal(SIGPIPE, SIG_IGN); - - secchan.hooks = NULL; - secchan.n_hooks = 0; - secchan.allocated_hooks = 0; - - /* Start listening for management and monitoring connections. */ - n_listeners = 0; - for (i = 0; i < s.n_listeners; i++) { - listeners[n_listeners++] = open_passive_vconn(s.listener_names[i]); - } - monitor = s.monitor_name ? open_passive_vconn(s.monitor_name) : NULL; - - /* Initialize switch status hook. */ - switch_status_start(&secchan, &s, &switch_status); - - die_if_already_running(); - daemonize(); - - /* Start listening for vlogconf requests. */ - retval = vlog_server_listen(NULL, NULL); - if (retval) { - ofp_fatal(retval, "Could not listen for vlog connections"); - } - - VLOG_INFO("OpenFlow reference implementation version %s", VERSION BUILDNR); - VLOG_INFO("OpenFlow protocol version 0x%02x", OFP_VERSION); - - /* Check datapath name, to try to catch command-line invocation errors. */ - if (strncmp(s.dp_name, "nl:", 3) && strncmp(s.dp_name, "unix:", 5) - && !s.controller_names[0]) { - VLOG_WARN("Controller not specified and datapath is not nl: or " - "unix:. (Did you forget to specify the datapath?)"); - } - - if (!strncmp(s.dp_name, "nl:", 3)) { - /* Connect to datapath with a subscription for asynchronous events. By - * separating the connection for asynchronous events from that for - * request and replies we prevent the socket receive buffer from being - * filled up by received packet data, which in turn would prevent - * getting replies to any Netlink messages we send to the kernel. */ - async_rconn = rconn_create(0, s.max_backoff); - rconn_connect(async_rconn, s.dp_name); - switch_status_register_category(switch_status, "async", - rconn_status_cb, async_rconn); - } else { - /* No need for a separate asynchronous connection: we must be connected - * to the user datapath, which is smart enough to discard packet events - * instead of message replies. In fact, having a second connection - * would work against us since we'd get double copies of asynchronous - * event messages (the user datapath provides no way to turn off - * asynchronous events). */ - async_rconn = NULL; - } - - /* Connect to datapath without a subscription, for requests and replies. */ - local_rconn_name = vconn_name_without_subscription(s.dp_name); - local_rconn = rconn_create(0, s.max_backoff); - rconn_connect(local_rconn, local_rconn_name); - free(local_rconn_name); - switch_status_register_category(switch_status, "local", - rconn_status_cb, local_rconn); - - /* Connect to controller. */ - remote_rconn = rconn_create(s.probe_interval, s.max_backoff); - if (s.controller_names[0]) { - retval = rconn_connect(remote_rconn, s.controller_names[0]); - if (retval == EAFNOSUPPORT) { - ofp_fatal(0, "No support for %s vconn", s.controller_names[0]); - } - } - switch_status_register_category(switch_status, "remote", - rconn_status_cb, remote_rconn); - - /* Start relaying. */ - controller_relay = relay_create(async_rconn, local_rconn, remote_rconn, - false); - list_push_back(&relays, &controller_relay->node); - - /* Set up hooks. */ - port_watcher_start(&secchan, local_rconn, remote_rconn, &pw); - discovery = s.discovery ? discovery_init(&s, pw, switch_status) : NULL; - if (s.enable_stp) { - stp_start(&secchan, pw, local_rconn, remote_rconn); - } - if (s.in_band) { - in_band_start(&secchan, &s, switch_status, pw, remote_rconn); - } - if (s.fail_mode == FAIL_OPEN) { - fail_open_start(&secchan, &s, switch_status, - local_rconn, remote_rconn); - } - if (s.num_controllers > 1) { - failover_start(&secchan, &s, switch_status, remote_rconn); - } - if (s.n_listeners > 0) { - protocol_stat_start(&secchan, &s, local_rconn, remote_rconn); - } - if (s.rate_limit) { - rate_limit_start(&secchan, &s, switch_status, remote_rconn); - } - if (s.emerg_flow) { - emerg_flow_start(&secchan, &s, switch_status, local_rconn, remote_rconn); - } - - while (s.discovery || rconn_is_alive(remote_rconn)) { - struct relay *r, *n; - size_t i; - - /* Do work. */ - LIST_FOR_EACH_SAFE (r, n, struct relay, node, &relays) { - relay_run(r, &secchan); - } - for (i = 0; i < n_listeners; i++) { - for (;;) { - struct relay *r = relay_accept(&s, listeners[i]); - if (!r) { - break; - } - list_push_back(&relays, &r->node); - } - } - if (monitor) { - struct vconn *new = accept_vconn(monitor); - if (new) { - /* XXX should monitor async_rconn too but rconn_add_monitor() - * takes ownership of the vconn passed in. */ - rconn_add_monitor(local_rconn, new); - } - } - for (i = 0; i < secchan.n_hooks; i++) { - if (secchan.hooks[i].class->periodic_cb) { - secchan.hooks[i].class->periodic_cb(secchan.hooks[i].aux); - } - } - if (s.discovery) { - char *controller_name; - if (rconn_is_connectivity_questionable(remote_rconn)) { - discovery_question_connectivity(discovery); - } - if (discovery_run(discovery, &controller_name)) { - if (controller_name) { - rconn_connect(remote_rconn, controller_name); - } else { - rconn_disconnect(remote_rconn); - } - } - } - - /* Wait for something to happen. */ - LIST_FOR_EACH (r, struct relay, node, &relays) { - relay_wait(r); - } - for (i = 0; i < n_listeners; i++) { - pvconn_wait(listeners[i]); - } - if (monitor) { - pvconn_wait(monitor); - } - for (i = 0; i < secchan.n_hooks; i++) { - if (secchan.hooks[i].class->wait_cb) { - secchan.hooks[i].class->wait_cb(secchan.hooks[i].aux); - } - } - if (discovery) { - discovery_wait(discovery); - } - poll_block(); - } - - return 0; -} - -static struct pvconn * -open_passive_vconn(const char *name) -{ - struct pvconn *pvconn; - int retval; - - retval = pvconn_open(name, &pvconn); - if (retval && retval != EAGAIN) { - ofp_fatal(retval, "opening %s", name); - } - return pvconn; -} - -static struct vconn * -accept_vconn(struct pvconn *pvconn) -{ - struct vconn *new; - int retval; - - retval = pvconn_accept(pvconn, OFP_VERSION, &new); - if (retval && retval != EAGAIN) { - VLOG_WARN_RL(&rl, "accept failed (%s)", strerror(retval)); - } - return new; -} - -void -add_hook(struct secchan *secchan, const struct hook_class *class, void *aux) -{ - struct hook *hook; - - if (secchan->n_hooks >= secchan->allocated_hooks) { - secchan->hooks = x2nrealloc(secchan->hooks, &secchan->allocated_hooks, - sizeof *secchan->hooks); - } - hook = &secchan->hooks[secchan->n_hooks++]; - hook->class = class; - hook->aux = aux; -} - -struct ofp_packet_in * -get_ofp_packet_in(struct relay *r) -{ - struct ofpbuf *msg = r->halves[HALF_LOCAL].rxbuf; - struct ofp_header *oh = msg->data; - if (oh->type == OFPT_PACKET_IN) { - if (msg->size >= offsetof (struct ofp_packet_in, data)) { - return msg->data; - } else { - VLOG_WARN("packet too short (%zu bytes) for packet_in", - msg->size); - } - } - return NULL; -} - -bool -get_ofp_packet_eth_header(struct relay *r, struct ofp_packet_in **opip, - struct eth_header **ethp) -{ - const int min_len = offsetof(struct ofp_packet_in, data) + ETH_HEADER_LEN; - struct ofp_packet_in *opi = get_ofp_packet_in(r); - if (opi && ntohs(opi->header.length) >= min_len) { - *opip = opi; - *ethp = (void *) opi->data; - return true; - } - return false; -} - -/* OpenFlow message relaying. */ - -/* Returns a malloc'd string containing a copy of 'vconn_name' modified not to - * subscribe to asynchronous messages such as 'ofp_packet_in' events (if - * possible). */ -static char * -vconn_name_without_subscription(const char *vconn_name) -{ - int nl_index; - if (sscanf(vconn_name, "nl:%d", &nl_index) == 1) { - /* nl:123 or nl:123:1 opens a netlink connection to local datapath 123. - * nl:123:0 opens a netlink connection to local datapath 123 without - * obtaining a subscription for ofp_packet_in or ofp_flow_removed - * messages. */ - return xasprintf("nl:%d:0", nl_index); - } else { - /* We don't have a way to specify not to subscribe to those messages - * for other transports. (That's a defect: really this should be in - * the OpenFlow protocol, not the Netlink transport). */ - VLOG_WARN_RL(&rl, "new management connection will receive " - "asynchronous messages"); - return xstrdup(vconn_name); - } -} - -static struct relay * -relay_accept(const struct settings *s, struct pvconn *pvconn) -{ - struct vconn *new_remote, *new_local; - struct rconn *r1, *r2; - char *vconn_name; - int retval; - - new_remote = accept_vconn(pvconn); - if (!new_remote) { - return NULL; - } - - vconn_name = vconn_name_without_subscription(s->dp_name); - retval = vconn_open(vconn_name, OFP_VERSION, &new_local); - if (retval) { - VLOG_ERR_RL(&rl, "could not connect to %s (%s)", - vconn_name, strerror(retval)); - vconn_close(new_remote); - free(vconn_name); - return NULL; - } - - /* Create and return relay. */ - r1 = rconn_create(0, 0); - rconn_connect_unreliably(r1, vconn_name, new_local); - free(vconn_name); - - r2 = rconn_create(0, 0); - rconn_connect_unreliably(r2, "passive", new_remote); - - return relay_create(NULL, r1, r2, true); -} - -static struct relay * -relay_create(struct rconn *async, struct rconn *local, struct rconn *remote, - bool is_mgmt_conn) -{ - struct relay *r = xcalloc(1, sizeof *r); - r->halves[HALF_LOCAL].rconn = local; - r->halves[HALF_REMOTE].rconn = remote; - r->is_mgmt_conn = is_mgmt_conn; - r->async_rconn = async; - return r; -} - -static bool -call_local_packet_cbs(struct secchan *secchan, struct relay *r) -{ - const struct hook *h; - for (h = secchan->hooks; h < &secchan->hooks[secchan->n_hooks]; h++) { - bool (*cb)(struct relay *, void *aux) = h->class->local_packet_cb; - if (cb && (cb)(r, h->aux)) { - return true; - } - } - return false; -} - -static bool -call_remote_packet_cbs(struct secchan *secchan, struct relay *r) -{ - const struct hook *h; - for (h = secchan->hooks; h < &secchan->hooks[secchan->n_hooks]; h++) { - bool (*cb)(struct relay *, void *aux) = h->class->remote_packet_cb; - if (cb && (cb)(r, h->aux)) { - return true; - } - } - return false; -} - -static void -relay_run(struct relay *r, struct secchan *secchan) -{ - int iteration; - int i; - - if (r->async_rconn) { - rconn_run(r->async_rconn); - } - for (i = 0; i < 2; i++) { - rconn_run(r->halves[i].rconn); - } - - /* Limit the number of iterations to prevent other tasks from starving. */ - for (iteration = 0; iteration < 50; iteration++) { - bool progress = false; - for (i = 0; i < 2; i++) { - struct half *this = &r->halves[i]; - struct half *peer = &r->halves[!i]; - - if (!this->rxbuf) { - this->rxbuf = rconn_recv(this->rconn); - if (!this->rxbuf && i == HALF_LOCAL && r->async_rconn) { - this->rxbuf = rconn_recv(r->async_rconn); - } - if (this->rxbuf && (i == HALF_REMOTE || !r->is_mgmt_conn)) { - if (i == HALF_LOCAL - ? call_local_packet_cbs(secchan, r) - : call_remote_packet_cbs(secchan, r)) - { - ofpbuf_delete(this->rxbuf); - this->rxbuf = NULL; - progress = true; - break; - } - } - } - - if (this->rxbuf && !this->n_txq) { - int retval = rconn_send(peer->rconn, this->rxbuf, - &this->n_txq); - if (retval != EAGAIN) { - if (!retval) { - progress = true; - } else { - ofpbuf_delete(this->rxbuf); - } - this->rxbuf = NULL; - } - } - } - if (!progress) { - break; - } - } - - if (r->is_mgmt_conn) { - for (i = 0; i < 2; i++) { - struct half *this = &r->halves[i]; - if (!rconn_is_alive(this->rconn)) { - relay_destroy(r); - return; - } - } - } -} - -static void -relay_wait(struct relay *r) -{ - int i; - - if (r->async_rconn) { - rconn_run_wait(r->async_rconn); - } - for (i = 0; i < 2; i++) { - struct half *this = &r->halves[i]; - - rconn_run_wait(this->rconn); - if (!this->rxbuf) { - rconn_recv_wait(this->rconn); - if (i == HALF_LOCAL && r->async_rconn) { - rconn_recv_wait(r->async_rconn); - } - } - } -} - -static void -relay_destroy(struct relay *r) -{ - int i; - - list_remove(&r->node); - rconn_destroy(r->async_rconn); - for (i = 0; i < 2; i++) { - struct half *this = &r->halves[i]; - rconn_destroy(this->rconn); - ofpbuf_delete(this->rxbuf); - } - free(r); -} - -/* User interface. */ - -static void -parse_options(int argc, char *argv[], struct settings *s) -{ - enum { - OPT_ACCEPT_VCONN = UCHAR_MAX + 1, - OPT_NO_RESOLV_CONF, - OPT_INACTIVITY_PROBE, - OPT_MAX_IDLE, - OPT_MAX_BACKOFF, - OPT_RATE_LIMIT, - OPT_BURST_LIMIT, - OPT_BOOTSTRAP_CA_CERT, - OPT_STP, - OPT_NO_STP, - OPT_OUT_OF_BAND, - OPT_IN_BAND, - OPT_EMERG_FLOW, - VLOG_OPTION_ENUMS, - LEAK_CHECKER_OPTION_ENUMS - }; - static struct option long_options[] = { - {"accept-vconn", required_argument, 0, OPT_ACCEPT_VCONN}, - {"no-resolv-conf", no_argument, 0, OPT_NO_RESOLV_CONF}, - {"fail", required_argument, 0, 'F'}, - {"inactivity-probe", required_argument, 0, OPT_INACTIVITY_PROBE}, - {"max-idle", required_argument, 0, OPT_MAX_IDLE}, - {"max-backoff", required_argument, 0, OPT_MAX_BACKOFF}, - {"listen", required_argument, 0, 'l'}, - {"monitor", required_argument, 0, 'm'}, - {"rate-limit", optional_argument, 0, OPT_RATE_LIMIT}, - {"burst-limit", required_argument, 0, OPT_BURST_LIMIT}, - {"stp", no_argument, 0, OPT_STP}, - {"no-stp", no_argument, 0, OPT_NO_STP}, - {"out-of-band", no_argument, 0, OPT_OUT_OF_BAND}, - {"in-band", no_argument, 0, OPT_IN_BAND}, - {"emerg-flow", no_argument, 0, OPT_EMERG_FLOW}, - {"verbose", optional_argument, 0, 'v'}, - {"help", no_argument, 0, 'h'}, - {"version", no_argument, 0, 'V'}, - DAEMON_LONG_OPTIONS, - VLOG_LONG_OPTIONS, - LEAK_CHECKER_LONG_OPTIONS, -#ifdef HAVE_OPENSSL - VCONN_SSL_LONG_OPTIONS - {"bootstrap-ca-cert", required_argument, 0, OPT_BOOTSTRAP_CA_CERT}, -#endif - {0, 0, 0, 0}, - }; - char *short_options = long_options_to_short_options(long_options); - char *accept_re = NULL; - int retval; - - /* Set defaults that we can figure out before parsing options. */ - s->n_listeners = 0; - s->monitor_name = NULL; - s->fail_mode = FAIL_OPEN; - s->max_idle = 15; - s->probe_interval = 15; - s->max_backoff = 15; - s->update_resolv_conf = true; - s->rate_limit = 0; - s->burst_limit = 0; - s->enable_stp = false; - s->in_band = true; - s->emerg_flow = false; - for (;;) { - int c; - - c = getopt_long(argc, argv, short_options, long_options, NULL); - if (c == -1) { - break; - } - - switch (c) { - case OPT_ACCEPT_VCONN: - accept_re = optarg[0] == '^' ? optarg : xasprintf("^%s", optarg); - break; - - case OPT_NO_RESOLV_CONF: - s->update_resolv_conf = false; - break; - - case 'F': - if (!strcmp(optarg, "open")) { - s->fail_mode = FAIL_OPEN; - } else if (!strcmp(optarg, "closed")) { - s->fail_mode = FAIL_CLOSED; - } else { - ofp_fatal(0, "-f or --fail argument must be \"open\" " - "or \"closed\""); - } - break; - - case OPT_INACTIVITY_PROBE: - s->probe_interval = atoi(optarg); - if (s->probe_interval < 1) { - ofp_fatal(0, "--inactivity-probe argument must be at least 1"); - } - break; - - case OPT_MAX_IDLE: - if (!strcmp(optarg, "permanent")) { - s->max_idle = OFP_FLOW_PERMANENT; - } else { - s->max_idle = atoi(optarg); - if (s->max_idle < 1 || s->max_idle > 65535) { - ofp_fatal(0, "--max-idle argument must be between 1 and " - "65535 or the word 'permanent'"); - } - } - break; - - case OPT_MAX_BACKOFF: - s->max_backoff = atoi(optarg); - if (s->max_backoff < 1) { - ofp_fatal(0, "--max-backoff argument must be at least 1"); - } else if (s->max_backoff > 3600) { - s->max_backoff = 3600; - } - break; - - case OPT_RATE_LIMIT: - if (optarg) { - s->rate_limit = atoi(optarg); - if (s->rate_limit < 1) { - ofp_fatal(0, "--rate-limit argument must be at least 1"); - } - } else { - s->rate_limit = 1000; - } - break; - - case OPT_BURST_LIMIT: - s->burst_limit = atoi(optarg); - if (s->burst_limit < 1) { - ofp_fatal(0, "--burst-limit argument must be at least 1"); - } - break; - - case OPT_STP: - s->enable_stp = true; - break; - - case OPT_NO_STP: - s->enable_stp = false; - break; - - case OPT_OUT_OF_BAND: - s->in_band = false; - break; - - case OPT_IN_BAND: - s->in_band = true; - break; - - case OPT_EMERG_FLOW: - s->emerg_flow = true; - break; - - case 'l': - if (s->n_listeners >= MAX_MGMT) { - ofp_fatal(0, - "-l or --listen may be specified at most %d times", - MAX_MGMT); - } - s->listener_names[s->n_listeners++] = optarg; - break; - - case 'm': - if (s->monitor_name) { - ofp_fatal(0, "-m or --monitor may only be specified once"); - } - s->monitor_name = optarg; - break; - - case 'h': - usage(); - - case 'V': - printf("%s %s compiled "__DATE__" "__TIME__"\n", - program_name, VERSION BUILDNR); - exit(EXIT_SUCCESS); - - DAEMON_OPTION_HANDLERS - - VLOG_OPTION_HANDLERS - - LEAK_CHECKER_OPTION_HANDLERS - -#ifdef HAVE_OPENSSL - VCONN_SSL_OPTION_HANDLERS - - case OPT_BOOTSTRAP_CA_CERT: - vconn_ssl_set_ca_cert_file(optarg, true); - break; -#endif - - case '?': - exit(EXIT_FAILURE); - - default: - abort(); - } - } - free(short_options); - - argc -= optind; - argv += optind; - if (argc < 1 || argc > 2) { - ofp_fatal(0, "need one or two non-option arguments; " - "use --help for usage"); - } - - /* Local and remote vconns. */ - s->dp_name = argv[0]; - { - char *curr; - char *save; - int i; - - s->num_controllers = 0; - for (i = 0; i < MAX_CONTROLLERS; ++i) - s->controller_names[i] = NULL; - if (argc > 1) { - for (curr = strtok_r(argv[1], ",,", &save), i = 0; - curr && i < MAX_CONTROLLERS; - curr = strtok_r(NULL, ",,", &save), ++i) { - s->controller_names[i] = xstrdup(curr); - ++s->num_controllers; - } - } - } - - /* Set accept_controller_regex. */ - if (!accept_re) { - accept_re = vconn_ssl_is_configured() ? "^ssl:.*" : ".*"; - } - retval = regcomp(&s->accept_controller_regex, accept_re, - REG_NOSUB | REG_EXTENDED); - if (retval) { - size_t length = regerror(retval, &s->accept_controller_regex, NULL, 0); - char *buffer = xmalloc(length); - regerror(retval, &s->accept_controller_regex, buffer, length); - ofp_fatal(0, "%s: %s", accept_re, buffer); - } - s->accept_controller_re = accept_re; - - /* Mode of operation. */ - s->discovery = s->controller_names[0] == NULL; - if (s->discovery && !s->in_band) { - ofp_fatal(0, "Cannot perform discovery with out-of-band control"); - } - - /* Rate limiting. */ - if (s->rate_limit) { - if (s->rate_limit < 100) { - VLOG_WARN("Rate limit set to unusually low value %d", - s->rate_limit); - } - if (!s->burst_limit) { - s->burst_limit = s->rate_limit / 4; - } - s->burst_limit = MAX(s->burst_limit, 1); - s->burst_limit = MIN(s->burst_limit, INT_MAX / 1000); - } -} - -static void -usage(void) -{ - printf("%s: secure channel, a relay for OpenFlow messages.\n" - "usage: %s [OPTIONS] DATAPATH [CONTROLLER]\n" - "DATAPATH is an active connection method to a local datapath.\n" - "CONTROLLER is an active OpenFlow connection method; if it is\n" - "omitted, then secchan performs controller discovery.\n", - program_name, program_name); - vconn_usage(true, true, true); - printf("\nController discovery options:\n" - " --accept-vconn=REGEX accept matching discovered controllers\n" - " --no-resolv-conf do not update /etc/resolv.conf\n" - "\nNetworking options:\n" - " -F, --fail=open|closed when controller connection fails:\n" - " closed: drop all packets\n" - " open (default): act as learning switch\n" - " --inactivity-probe=SECS time between inactivity probes\n" - " --max-idle=SECS max idle for flows set up by secchan\n" - " --max-backoff=SECS max time between controller connection\n" - " attempts (default: 15 seconds)\n" - " -l, --listen=METHOD allow management connections on METHOD\n" - " (a passive OpenFlow connection method)\n" - " -m, --monitor=METHOD copy traffic to/from kernel to METHOD\n" - " (a passive OpenFlow connection method)\n" - " --out-of-band controller connection is out-of-band\n" - " --stp enable 802.1D Spanning Tree Protocol\n" - " --no-stp disable 802.1D Spanning Tree Protocol\n" - " --emerg-flow enable emergency flow protection/restoration\n" - "\nRate-limiting of \"packet-in\" messages to the controller:\n" - " --rate-limit[=PACKETS] max rate, in packets/s (default: 1000)\n" - " --burst-limit=BURST limit on packet credit for idle time\n", - ofp_pkgdatadir); - daemon_usage(); - vlog_usage(); - printf("\nOther options:\n" - " -h, --help display this help message\n" - " -V, --version display version information\n"); - leak_checker_usage(); - exit(EXIT_SUCCESS); -} diff --git a/openflow/secchan/secchan.h b/openflow/secchan/secchan.h deleted file mode 100644 index 7f89e2ef..00000000 --- a/openflow/secchan/secchan.h +++ /dev/null @@ -1,135 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#ifndef SECCHAN_H -#define SECCHAN_H 1 - -#include -#include -#include -#include "list.h" -#include "packets.h" - -struct secchan; - -/* Behavior when the connection to the controller fails. */ -enum fail_mode { - FAIL_OPEN, /* Act as learning switch. */ - FAIL_CLOSED /* Drop all packets. */ -}; - -/* Maximum number of management connection listeners. */ -#define MAX_MGMT 8 - -#define MAX_CONTROLLERS 3 - -/* Settings that may be configured by the user. */ -struct settings { - /* Overall mode of operation. */ - bool discovery; /* Discover the controller automatically? */ - bool in_band; /* Connect to controller in-band? */ - - /* Related vconns and network devices. */ - const char *dp_name; /* Local datapath. */ - int num_controllers; /* Number of configured controllers. */ - const char *controller_names[MAX_CONTROLLERS]; /* Controllers (if not discovery mode). */ - const char *listener_names[MAX_MGMT]; /* Listen for mgmt connections. */ - size_t n_listeners; /* Number of mgmt connection listeners. */ - const char *monitor_name; /* Listen for traffic monitor connections. */ - - /* Failure behavior. */ - enum fail_mode fail_mode; /* Act as learning switch if no controller? */ - int max_idle; /* Idle time for flows in fail-open mode. */ - int probe_interval; /* # seconds idle before sending echo request. */ - int max_backoff; /* Max # seconds between connection attempts. */ - - /* Packet-in rate-limiting. */ - int rate_limit; /* Tokens added to bucket per second. */ - int burst_limit; /* Maximum number token bucket size. */ - - /* Discovery behavior. */ - regex_t accept_controller_regex; /* Controller vconns to accept. */ - const char *accept_controller_re; /* String version of regex. */ - bool update_resolv_conf; /* Update /etc/resolv.conf? */ - - /* Spanning tree protocol. */ - bool enable_stp; - - /* Emergency flow protection/restoration behavior. */ - bool emerg_flow; -}; - -struct half { - struct rconn *rconn; - struct ofpbuf *rxbuf; - int n_txq; /* No. of packets queued for tx on 'rconn'. */ -}; - -struct relay { - struct list node; - -#define HALF_LOCAL 0 -#define HALF_REMOTE 1 - struct half halves[2]; - - /* The secchan has a primary connection (relay) to an OpenFlow controller. - * This primary connection actually makes two connections to the datapath: - * one for OpenFlow requests and responses, and one that is only used for - * receiving asynchronous events such as 'ofp_packet_in' events. This - * design keeps replies to OpenFlow requests from being dropped by the - * kernel due to a flooded network device. - * - * The secchan may also have any number of secondary "management" - * connections (relays). These connections do not receive asychronous - * events and thus have a null 'async_rconn'. */ - bool is_mgmt_conn; /* Is this a management connection? */ - struct rconn *async_rconn; /* For receiving asynchronous events. */ -}; - -struct hook_class { - bool (*local_packet_cb)(struct relay *, void *aux); - bool (*remote_packet_cb)(struct relay *, void *aux); - void (*periodic_cb)(void *aux); - void (*wait_cb)(void *aux); - void (*closing_cb)(struct relay *, void *aux); -}; - -void add_hook(struct secchan *, const struct hook_class *, void *); - -struct ofp_packet_in *get_ofp_packet_in(struct relay *); -bool get_ofp_packet_eth_header(struct relay *, struct ofp_packet_in **, - struct eth_header **); -void get_ofp_packet_payload(struct ofp_packet_in *, struct ofpbuf *); - - -#endif /* secchan.h */ diff --git a/openflow/secchan/status.c b/openflow/secchan/status.c deleted file mode 100644 index cf228123..00000000 --- a/openflow/secchan/status.c +++ /dev/null @@ -1,230 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include "status.h" -#include -#include -#include -#include -#include "dynamic-string.h" -#include "openflow/nicira-ext.h" -#include "ofpbuf.h" -#include "openflow/openflow.h" -#include "rconn.h" -#include "timeval.h" -#include "vconn.h" - -#define THIS_MODULE VLM_status -#include "vlog.h" - -struct switch_status_category { - char *name; - void (*cb)(struct status_reply *, void *aux); - void *aux; -}; - -struct switch_status { - const struct settings *s; - time_t booted; - struct switch_status_category *categories; - size_t n_categories, allocated_categories; -}; - -struct status_reply { - struct switch_status_category *category; - struct ds request; - struct ds output; -}; - -static bool -switch_status_remote_packet_cb(struct relay *r, void *ss_) -{ - struct switch_status *ss = ss_; - struct rconn *rc = r->halves[HALF_REMOTE].rconn; - struct ofpbuf *msg = r->halves[HALF_REMOTE].rxbuf; - struct switch_status_category *c; - struct nicira_header *request; - struct nicira_header *reply; - struct status_reply sr; - struct ofpbuf *b; - int retval; - - if (msg->size < sizeof(struct nicira_header)) { - return false; - } - request = msg->data; - if (request->header.type != OFPT_VENDOR - || request->vendor != htonl(NX_VENDOR_ID) - || request->subtype != htonl(NXT_STATUS_REQUEST)) { - return false; - } - - sr.request.string = (void *) (request + 1); - sr.request.length = msg->size - sizeof *request; - ds_init(&sr.output); - for (c = ss->categories; c < &ss->categories[ss->n_categories]; c++) { - if (!memcmp(c->name, sr.request.string, - MIN(strlen(c->name), sr.request.length))) { - sr.category = c; - c->cb(&sr, c->aux); - } - } - reply = make_openflow_xid(sizeof *reply + sr.output.length, - OFPT_VENDOR, request->header.xid, &b); - reply->vendor = htonl(NX_VENDOR_ID); - reply->subtype = htonl(NXT_STATUS_REPLY); - memcpy(reply + 1, sr.output.string, sr.output.length); - retval = rconn_send(rc, b, NULL); - if (retval && retval != EAGAIN) { - VLOG_WARN("send failed (%s)", strerror(retval)); - } - ds_destroy(&sr.output); - return true; -} - -void -rconn_status_cb(struct status_reply *sr, void *rconn_) -{ - struct rconn *rconn = rconn_; - time_t now = time_now(); - - status_reply_put(sr, "name=%s", rconn_get_name(rconn)); - status_reply_put(sr, "state=%s", rconn_get_state(rconn)); - status_reply_put(sr, "backoff=%d", rconn_get_backoff(rconn)); - status_reply_put(sr, "is-connected=%s", - rconn_is_connected(rconn) ? "true" : "false"); - status_reply_put(sr, "sent-msgs=%u", rconn_packets_sent(rconn)); - status_reply_put(sr, "received-msgs=%u", rconn_packets_received(rconn)); - status_reply_put(sr, "attempted-connections=%u", - rconn_get_attempted_connections(rconn)); - status_reply_put(sr, "successful-connections=%u", - rconn_get_successful_connections(rconn)); - status_reply_put(sr, "last-connection=%ld", - (long int) (now - rconn_get_last_connection(rconn))); - status_reply_put(sr, "time-connected=%lu", - rconn_get_total_time_connected(rconn)); - status_reply_put(sr, "state-elapsed=%u", rconn_get_state_elapsed(rconn)); -} - -static void -config_status_cb(struct status_reply *sr, void *s_) -{ - const struct settings *s = s_; - size_t i; - - for (i = 0; i < s->n_listeners; i++) { - status_reply_put(sr, "management%zu=%s", i, s->listener_names[i]); - } - if (s->probe_interval) { - status_reply_put(sr, "probe-interval=%d", s->probe_interval); - } - if (s->max_backoff) { - status_reply_put(sr, "max-backoff=%d", s->max_backoff); - } -} - -static void -switch_status_cb(struct status_reply *sr, void *ss_) -{ - struct switch_status *ss = ss_; - time_t now = time_now(); - - status_reply_put(sr, "now=%ld", (long int) now); - status_reply_put(sr, "uptime=%ld", (long int) (now - ss->booted)); - status_reply_put(sr, "pid=%ld", (long int) getpid()); -} - -static struct hook_class switch_status_hook_class = { - NULL, /* local_packet_cb */ - switch_status_remote_packet_cb, /* remote_packet_cb */ - NULL, /* periodic_cb */ - NULL, /* wait_cb */ - NULL, /* closing_cb */ -}; - -void -switch_status_start(struct secchan *secchan, const struct settings *s, - struct switch_status **ssp) -{ - struct switch_status *ss = xcalloc(1, sizeof *ss); - ss->s = s; - ss->booted = time_now(); - switch_status_register_category(ss, "config", - config_status_cb, (void *) s); - switch_status_register_category(ss, "switch", switch_status_cb, ss); - *ssp = ss; - add_hook(secchan, &switch_status_hook_class, ss); -} - -void -switch_status_register_category(struct switch_status *ss, - const char *category, - void (*cb)(struct status_reply *, void *aux), - void *aux) -{ - struct switch_status_category *c; - if (ss->n_categories >= ss->allocated_categories) { - ss->categories = x2nrealloc(ss->categories, &ss->allocated_categories, - sizeof *ss->categories); - } - c = &ss->categories[ss->n_categories++]; - c->cb = cb; - c->aux = aux; - c->name = xstrdup(category); -} - -void -status_reply_put(struct status_reply *sr, const char *content, ...) -{ - size_t old_length = sr->output.length; - size_t added; - va_list args; - - /* Append the status reply to the output. */ - ds_put_format(&sr->output, "%s.", sr->category->name); - va_start(args, content); - ds_put_format_valist(&sr->output, content, args); - va_end(args); - if (ds_last(&sr->output) != '\n') { - ds_put_char(&sr->output, '\n'); - } - - /* Drop what we just added if it doesn't match the request. */ - added = sr->output.length - old_length; - if (added < sr->request.length - || memcmp(&sr->output.string[old_length], - sr->request.string, sr->request.length)) { - ds_truncate(&sr->output, old_length); - } -} diff --git a/openflow/secchan/status.h b/openflow/secchan/status.h deleted file mode 100644 index 68793eff..00000000 --- a/openflow/secchan/status.h +++ /dev/null @@ -1,56 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#ifndef STATUS_H -#define STATUS_H 1 - -#include "secchan.h" - -struct secchan; -struct status_reply; -struct switch_status; - -void switch_status_start(struct secchan *, const struct settings *, - struct switch_status **); -void switch_status_register_category(struct switch_status *, - const char *category, - void (*cb)(struct status_reply *, - void *aux), - void *aux); - -void status_reply_put(struct status_reply *, const char *, ...) - PRINTF_FORMAT(2, 3); - -void rconn_status_cb(struct status_reply *, void *rconn_); - -#endif /* status.h */ diff --git a/openflow/secchan/stp-secchan.c b/openflow/secchan/stp-secchan.c deleted file mode 100644 index 152595e9..00000000 --- a/openflow/secchan/stp-secchan.c +++ /dev/null @@ -1,293 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include "stp-secchan.h" -#include -#include -#include "flow.h" -#include "secchan.h" -#include "ofpbuf.h" -#include "openflow/openflow.h" -#include "poll-loop.h" -#include "port-watcher.h" -#include "rconn.h" -#include "stp.h" -#include "timeval.h" -#include "vconn.h" - -#define THIS_MODULE VLM_stp_secchan -#include "vlog.h" - -struct stp_data { - struct stp *stp; - struct port_watcher *pw; - struct rconn *local_rconn; - struct rconn *remote_rconn; - long long int last_tick; - int n_txq; -}; - -static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60); - -static bool -stp_local_packet_cb(struct relay *r, void *stp_) -{ - struct ofpbuf *msg = r->halves[HALF_LOCAL].rxbuf; - struct ofp_header *oh; - struct stp_data *stp = stp_; - struct ofp_packet_in *opi; - struct eth_header *eth; - struct llc_header *llc; - struct ofpbuf payload; - uint16_t port_no; - struct flow flow; - - oh = msg->data; - if (oh->type == OFPT_FEATURES_REPLY - && msg->size >= offsetof(struct ofp_switch_features, ports)) { - struct ofp_switch_features *osf = msg->data; - osf->capabilities |= htonl(OFPC_STP); - return false; - } - - if (!get_ofp_packet_eth_header(r, &opi, ð) - || !eth_addr_equals(eth->eth_dst, stp_eth_addr)) { - return false; - } - - port_no = ntohs(opi->in_port); - if (port_no >= STP_MAX_PORTS) { - /* STP only supports 255 ports. */ - return false; - } - if (port_watcher_get_config(stp->pw, port_no) & OFPPC_NO_STP) { - /* We're not doing STP on this port. */ - return false; - } - - if (opi->reason == OFPR_ACTION) { - /* The controller set up a flow for this, so we won't intercept it. */ - return false; - } - - get_ofp_packet_payload(opi, &payload); - flow_extract(&payload, port_no, &flow); - if (flow.dl_type != htons(OFP_DL_TYPE_NOT_ETH_TYPE)) { - VLOG_DBG("non-LLC frame received on STP multicast address"); - return false; - } - llc = ofpbuf_at_assert(&payload, sizeof *eth, sizeof *llc); - if (llc->llc_dsap != STP_LLC_DSAP) { - VLOG_DBG("bad DSAP 0x%02"PRIx8" received on STP multicast address", - llc->llc_dsap); - return false; - } - - /* Trim off padding on payload. */ - if (payload.size > ntohs(eth->eth_type) + ETH_HEADER_LEN) { - payload.size = ntohs(eth->eth_type) + ETH_HEADER_LEN; - } - if (ofpbuf_try_pull(&payload, ETH_HEADER_LEN + LLC_HEADER_LEN)) { - struct stp_port *p = stp_get_port(stp->stp, port_no); - stp_received_bpdu(p, payload.data, payload.size); - } - - return true; -} - -static void -stp_periodic_cb(void *stp_) -{ - struct stp_data *stp = stp_; - long long int now = time_msec(); - long long int elapsed = now - stp->last_tick; - struct stp_port *p; - - if (!port_watcher_is_ready(stp->pw)) { - /* Can't start STP until we know port flags, because port flags can - * disable STP. */ - return; - } - if (elapsed <= 0) { - return; - } - - stp_tick(stp->stp, MIN(INT_MAX, elapsed)); - stp->last_tick = now; - - while (stp_get_changed_port(stp->stp, &p)) { - int port_no = stp_port_no(p); - enum stp_state s_state = stp_port_get_state(p); - - if (s_state != STP_DISABLED) { - VLOG_INFO("STP: Port %d entered %s state", - port_no, stp_state_name(s_state)); - } - if (!(port_watcher_get_config(stp->pw, port_no) & OFPPC_NO_STP)) { - uint32_t p_config = 0; - uint32_t p_state; - switch (s_state) { - case STP_LISTENING: - p_state = OFPPS_STP_LISTEN; - break; - case STP_LEARNING: - p_state = OFPPS_STP_LEARN; - break; - case STP_DISABLED: - case STP_FORWARDING: - p_state = OFPPS_STP_FORWARD; - break; - case STP_BLOCKING: - p_state = OFPPS_STP_BLOCK; - break; - default: - VLOG_DBG_RL(&rl, "STP: Port %d has bad state %x", - port_no, s_state); - p_state = OFPPS_STP_FORWARD; - break; - } - if (!stp_forward_in_state(s_state)) { - p_config = OFPPC_NO_FLOOD; - } - port_watcher_set_flags(stp->pw, port_no, - p_config, OFPPC_NO_FLOOD, - p_state, OFPPS_STP_MASK); - } else { - /* We don't own those flags. */ - } - } -} - -static void -stp_wait_cb(void *stp_ UNUSED) -{ - poll_timer_wait(1000); -} - -static void -send_bpdu(struct ofpbuf *pkt, int port_no, void *stp_) -{ - struct stp_data *stp = stp_; - const uint8_t *port_mac = port_watcher_get_hwaddr(stp->pw, port_no); - if (port_mac) { - struct eth_header *eth = pkt->l2; - struct ofpbuf *opo; - - memcpy(eth->eth_src, port_mac, ETH_ADDR_LEN); - opo = make_unbuffered_packet_out(pkt, OFPP_NONE, port_no); - - rconn_send_with_limit(stp->local_rconn, opo, &stp->n_txq, OFPP_MAX); - } else { - VLOG_WARN_RL(&rl, "cannot send BPDU on missing port %d", port_no); - } - ofpbuf_delete(pkt); -} - -static bool -stp_is_port_supported(uint16_t port_no) -{ - return port_no < STP_MAX_PORTS; -} - -static void -stp_port_changed_cb(uint16_t port_no, - const struct ofp_phy_port *old UNUSED, - const struct ofp_phy_port *new, - void *stp_) -{ - struct stp_data *stp = stp_; - struct stp_port *p; - - if (!stp_is_port_supported(port_no)) { - return; - } - - p = stp_get_port(stp->stp, port_no); - if (!new - || new->config & htonl(OFPPC_NO_STP | OFPPC_PORT_DOWN) - || new->state & htonl(OFPPS_LINK_DOWN)) { - stp_port_disable(p); - } else { - int speed = 0; - stp_port_enable(p); - if (new->curr & (OFPPF_10MB_HD | OFPPF_10MB_FD)) { - speed = 10; - } else if (new->curr & (OFPPF_100MB_HD | OFPPF_100MB_FD)) { - speed = 100; - } else if (new->curr & (OFPPF_1GB_HD | OFPPF_1GB_FD)) { - speed = 1000; - } else if (new->curr & OFPPF_10GB_FD) { - speed = 10000; - } - stp_port_set_speed(p, speed); - } -} - -static void -stp_local_port_changed_cb(const struct ofp_phy_port *port, void *stp_) -{ - struct stp_data *stp = stp_; - if (port) { - stp_set_bridge_id(stp->stp, eth_addr_to_uint64(port->hw_addr)); - } -} - -static struct hook_class stp_hook_class = { - stp_local_packet_cb, /* local_packet_cb */ - NULL, /* remote_packet_cb */ - stp_periodic_cb, /* periodic_cb */ - stp_wait_cb, /* wait_cb */ - NULL, /* closing_cb */ -}; - -void -stp_start(struct secchan *secchan, struct port_watcher *pw, - struct rconn *local, struct rconn *remote) -{ - uint8_t dpid[ETH_ADDR_LEN]; - struct stp_data *stp; - - stp = xcalloc(1, sizeof *stp); - eth_addr_random(dpid); - stp->stp = stp_create("stp", eth_addr_to_uint64(dpid), send_bpdu, stp); - stp->pw = pw; - stp->local_rconn = local; - stp->remote_rconn = remote; - stp->last_tick = time_msec(); - - port_watcher_register_callback(pw, stp_port_changed_cb, stp); - port_watcher_register_local_port_callback(pw, stp_local_port_changed_cb, - stp); - add_hook(secchan, &stp_hook_class, stp); -} diff --git a/openflow/secchan/stp-secchan.h b/openflow/secchan/stp-secchan.h deleted file mode 100644 index 2d1105f7..00000000 --- a/openflow/secchan/stp-secchan.h +++ /dev/null @@ -1,48 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#ifndef STP_SECCHAN_H -#define STP_SECCHAN_H 1 - -/* Extra time, in seconds, at boot before going into fail-open, to give the - * spanning tree protocol time to figure out the network layout. */ -#define STP_EXTRA_BOOT_TIME 30 - -struct port_watcher; -struct rconn; -struct secchan; - -void stp_start(struct secchan *, struct port_watcher *, - struct rconn *local, struct rconn *remote); - -#endif /* stp-secchan.h */ diff --git a/openflow/soexpand.pl b/openflow/soexpand.pl deleted file mode 100755 index 4e130056..00000000 --- a/openflow/soexpand.pl +++ /dev/null @@ -1,26 +0,0 @@ -use strict; -use warnings; -use Getopt::Long; - -my ($exit_code) = 0; -my (@include_dirs); -Getopt::Long::Configure ("bundling"); -GetOptions("I|include=s" => \@include_dirs) or exit(1); -@include_dirs = ('.') if !@include_dirs; -OUTER: while () { - if (my ($name) = /^\.so (\S+)$/) { - foreach my $dir (@include_dirs, '.') { - if (open(INNER, "$dir/$name")) { - while () { - print $_; - } - close(INNER); - next OUTER; - } - } - print STDERR "$name not found in: ", join(' ', @include_dirs), "\n"; - $exit_code = 1; - } - print $_; -} -exit $exit_code; diff --git a/openflow/tests/.dirstamp b/openflow/tests/.dirstamp deleted file mode 100644 index e69de29b..00000000 diff --git a/openflow/tests/.gitignore b/openflow/tests/.gitignore deleted file mode 100644 index 3e44d9e7..00000000 --- a/openflow/tests/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -/Makefile -/Makefile.in -/test-list -/test-dhcp-client -/test-stp -/test-type-props diff --git a/openflow/tests/automake.mk b/openflow/tests/automake.mk deleted file mode 100644 index a4e945a9..00000000 --- a/openflow/tests/automake.mk +++ /dev/null @@ -1,46 +0,0 @@ -TESTS += tests/test-flows.sh -noinst_PROGRAMS += tests/test-flows -tests_test_flows_SOURCES = tests/test-flows.c -tests_test_flows_LDADD = lib/libopenflow.a -dist_check_SCRIPTS = tests/test-flows.sh tests/flowgen.pl - -TESTS += tests/test-hmap -noinst_PROGRAMS += tests/test-hmap -tests_test_hmap_SOURCES = tests/test-hmap.c -tests_test_hmap_LDADD = lib/libopenflow.a - -TESTS += tests/test-list -noinst_PROGRAMS += tests/test-list -tests_test_list_SOURCES = tests/test-list.c -tests_test_list_LDADD = lib/libopenflow.a - -TESTS += tests/test-type-props -noinst_PROGRAMS += tests/test-type-props -tests_test_type_props_SOURCES = tests/test-type-props.c - -noinst_PROGRAMS += tests/test-dhcp-client -tests_test_dhcp_client_SOURCES = tests/test-dhcp-client.c -tests_test_dhcp_client_LDADD = lib/libopenflow.a $(FAULT_LIBS) - -TESTS += tests/test-stp.sh -EXTRA_DIST += tests/test-stp.sh -noinst_PROGRAMS += tests/test-stp - -tests_test_stp_SOURCES = tests/test-stp.c -tests_test_stp_LDADD = lib/libopenflow.a -stp_files = \ - tests/test-stp-ieee802.1d-1998 \ - tests/test-stp-ieee802.1d-2004-fig17.4 \ - tests/test-stp-ieee802.1d-2004-fig17.6 \ - tests/test-stp-ieee802.1d-2004-fig17.7 \ - tests/test-stp-iol-op-1.1 \ - tests/test-stp-iol-op-1.4 \ - tests/test-stp-iol-op-3.1 \ - tests/test-stp-iol-op-3.3 \ - tests/test-stp-iol-io-1.1 \ - tests/test-stp-iol-io-1.2 \ - tests/test-stp-iol-io-1.4 \ - tests/test-stp-iol-io-1.5 -TESTS_ENVIRONMENT += stp_files='$(stp_files)' - -EXTRA_DIST += $(stp_files) diff --git a/openflow/tests/flowgen.pl b/openflow/tests/flowgen.pl deleted file mode 100755 index eb17b2af..00000000 --- a/openflow/tests/flowgen.pl +++ /dev/null @@ -1,224 +0,0 @@ -#! /usr/bin/perl - -use strict; -use warnings; - -open(FLOWS, ">&=3");# or die "failed to open fd 3 for writing: $!\n"; -open(PACKETS, ">&=4");# or die "failed to open fd 4 for writing: $!\n"; - -# Print pcap file header. -print PACKETS pack('NnnNNNN', - 0xa1b2c3d4, # magic number - 2, # major version - 4, # minor version - 0, # time zone offset - 0, # time stamp accuracy - 1518, # snaplen - 1); # Ethernet - -output(DL_HEADER => '802.2'); - -for my $dl_header qw(802.2+SNAP Ethernet) { - my %a = (DL_HEADER => $dl_header); - for my $dl_vlan qw(none zero nonzero) { - my %b = (%a, DL_VLAN => $dl_vlan); - - # Non-IP case. - output(%b, DL_TYPE => 'non-ip'); - - for my $ip_options qw(no yes) { - my %c = (%b, DL_TYPE => 'ip', IP_OPTIONS => $ip_options); - for my $ip_fragment qw(no first middle last) { - my %d = (%c, IP_FRAGMENT => $ip_fragment); - for my $tp_proto qw(TCP TCP+options UDP ICMP other) { - output(%d, TP_PROTO => $tp_proto); - } - } - } - } -} - -sub output { - my (%attrs) = @_; - - # Compose flow. - my (%flow); - $flow{DL_SRC} = "00:02:e3:0f:80:a4"; - $flow{DL_DST} = "00:1a:92:40:ac:05"; - $flow{NW_PROTO} = 0; - $flow{NW_SRC} = '0.0.0.0'; - $flow{NW_DST} = '0.0.0.0'; - $flow{TP_SRC} = 0; - $flow{TP_DST} = 0; - if (defined($attrs{DL_VLAN})) { - my (%vlan_map) = ('none' => 0xffff, - 'zero' => 0, - 'nonzero' => 0x0123); - $flow{DL_VLAN} = $vlan_map{$attrs{DL_VLAN}}; - } else { - $flow{DL_VLAN} = 0xffff; # OFP_VLAN_NONE - } - if ($attrs{DL_HEADER} eq '802.2') { - $flow{DL_TYPE} = 0x5ff; # OFP_DL_TYPE_NOT_ETH_TYPE - } elsif ($attrs{DL_TYPE} eq 'ip') { - $flow{DL_TYPE} = 0x0800; # ETH_TYPE_IP - $flow{NW_SRC} = '10.0.2.15'; - $flow{NW_DST} = '192.168.1.20'; - if ($attrs{TP_PROTO} eq 'other') { - $flow{NW_PROTO} = 42; - } elsif ($attrs{TP_PROTO} eq 'TCP' || - $attrs{TP_PROTO} eq 'TCP+options') { - $flow{NW_PROTO} = 6; # IP_TYPE_TCP - $flow{TP_SRC} = 6667; - $flow{TP_DST} = 9998; - } elsif ($attrs{TP_PROTO} eq 'UDP') { - $flow{NW_PROTO} = 17; # IP_TYPE_UDP - $flow{TP_SRC} = 1112; - $flow{TP_DST} = 2223; - } elsif ($attrs{TP_PROTO} eq 'ICMP') { - $flow{NW_PROTO} = 1; # IP_TYPE_ICMP - $flow{TP_SRC} = 8; # echo request - $flow{TP_DST} = 0; # code - } else { - die; - } - if ($attrs{IP_FRAGMENT} ne 'no') { - $flow{TP_SRC} = $flow{TP_DST} = 0; - } - } elsif ($attrs{DL_TYPE} eq 'non-ip') { - $flow{DL_TYPE} = 0x5678; - } else { - die; - } - - # Compose packet. - my $packet = ''; - $packet .= pack_ethaddr($flow{DL_DST}); - $packet .= pack_ethaddr($flow{DL_SRC}); - $packet .= pack('n', 0) if $attrs{DL_HEADER} =~ /^802.2/; - if ($attrs{DL_HEADER} eq '802.2') { - $packet .= pack('CCC', 0x42, 0x42, 0x03); # LLC for 802.1D STP. - } else { - if ($attrs{DL_HEADER} eq '802.2+SNAP') { - $packet .= pack('CCC', 0xaa, 0xaa, 0x03); # LLC for SNAP. - $packet .= pack('CCC', 0, 0, 0); # SNAP OUI. - } - if ($attrs{DL_VLAN} ne 'none') { - $packet .= pack('nn', 0x8100, $flow{DL_VLAN}); - } - $packet .= pack('n', $flow{DL_TYPE}); - if ($attrs{DL_TYPE} eq 'ip') { - my $ip = pack('CCnnnCCnNN', - (4 << 4) | 5, # version, hdrlen - 0, # type of service - 0, # total length (filled in later) - 65432, # id - 0, # frag offset - 64, # ttl - $flow{NW_PROTO}, # protocol - 0, # checksum - 0x0a00020f, # source - 0xc0a80114); # dest - if ($attrs{IP_OPTIONS} eq 'yes') { - substr($ip, 0, 1) = pack('C', (4 << 4) | 8); - $ip .= pack('CCnnnCCCx', - 130, # type - 11, # length - 0x6bc5, # top secret - 0xabcd, - 0x1234, - 1, - 2, - 3); - } - if ($attrs{IP_FRAGMENT} ne 'no') { - my (%frag_map) = ('first' => 0x2000, # more frags, ofs 0 - 'middle' => 0x2111, # more frags, ofs 0x888 - 'last' => 0x0222); # last frag, ofs 0x1110 - substr($ip, 6, 2) - = pack('n', $frag_map{$attrs{IP_FRAGMENT}}); - } - - if ($attrs{TP_PROTO} =~ '^TCP') { - my $tcp = pack('nnNNnnnn', - $flow{TP_SRC}, # source port - $flow{TP_DST}, # dest port - 87123455, # seqno - 712378912, # ackno - (5 << 12) | 0x02 | 0x10, # hdrlen, SYN, ACK - 5823, # window size - 18923, # checksum - 12893); # urgent pointer - if ($attrs{TP_PROTO} eq 'TCP+options') { - substr($tcp, 12, 2) = pack('n', (6 << 12) | 0x02 | 0x10); - $tcp .= pack('CCn', 2, 4, 1975); # MSS option - } - $tcp .= 'payload'; - $ip .= $tcp; - } elsif ($attrs{TP_PROTO} eq 'UDP') { - my $len = 15; - my $udp = pack('nnnn', $flow{TP_SRC}, $flow{TP_DST}, $len, 0); - $udp .= chr($len) while length($udp) < $len; - $ip .= $udp; - } elsif ($attrs{TP_PROTO} eq 'ICMP') { - $ip .= pack('CCnnn', - 8, # echo request - 0, # code - 0, # checksum - 736, # identifier - 931); # sequence number - } elsif ($attrs{TP_PROTO} eq 'other') { - $ip .= 'other header'; - } else { - die; - } - - substr($ip, 2, 2) = pack('n', length($ip)); - $packet .= $ip; - } - } - substr($packet, 12, 2) = pack('n', length($packet)) - if $attrs{DL_HEADER} =~ /^802.2/; - - print join(' ', map("$_=$attrs{$_}", keys(%attrs))), "\n"; - print join(' ', map("$_=$flow{$_}", keys(%flow))), "\n"; - print "\n"; - - print FLOWS pack('Nn', - 0, # wildcards - 0); # in_port - print FLOWS pack_ethaddr($flow{DL_SRC}); - print FLOWS pack_ethaddr($flow{DL_DST}); - print FLOWS pack('nnCxNNnn', - $flow{DL_VLAN}, - $flow{DL_TYPE}, - $flow{NW_PROTO}, - inet_aton($flow{NW_SRC}), - inet_aton($flow{NW_DST}), - $flow{TP_SRC}, - $flow{TP_DST}); - - print PACKETS pack('NNNN', - 0, # timestamp seconds - 0, # timestamp microseconds - length($packet), # bytes saved - length($packet)), # total length - $packet; -} - -sub pack_ethaddr { - local ($_) = @_; - my $xx = '([0-9a-fA-F][0-9a-fA-F])'; - my (@octets) = /$xx:$xx:$xx:$xx:$xx:$xx/; - @octets == 6 or die $_; - my ($out) = ''; - $out .= pack('C', hex($_)) foreach @octets; - return $out; -} - -sub inet_aton { - local ($_) = @_; - my ($a, $b, $c, $d) = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/; - defined $d or die $_; - return ($a << 24) | ($b << 16) | ($c << 8) | $d; -} diff --git a/openflow/tests/test-dhcp-client.c b/openflow/tests/test-dhcp-client.c deleted file mode 100644 index f8a1f427..00000000 --- a/openflow/tests/test-dhcp-client.c +++ /dev/null @@ -1,206 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include "dhcp-client.h" -#include -#include -#include -#include -#include "command-line.h" -#include "dhcp.h" -#include "fatal-signal.h" -#include "fault.h" -#include "poll-loop.h" -#include "util.h" -#include "vlog.h" - -/* --request-ip: IP address to request from server. If zero, then do not - * request a specific IP address. */ -static struct in_addr request_ip; - -/* --vendor-class: Vendor class string to include in request. If null, no - * vendor class string is included. */ -static const char *vendor_class; - -/* --no-resolv-conf: Update /etc/resolv.conf to match DHCP reply? */ -static bool update_resolv_conf = true; - -static void parse_options(int argc, char *argv[]); -static void usage(void); -static void release(void *cli_); -static void modify_dhcp_request(struct dhcp_msg *, void *aux); - -int -main(int argc, char *argv[]) -{ - struct dhclient *cli; - int error; - - set_program_name(argv[0]); - register_fault_handlers(); - vlog_init(); - parse_options(argc, argv); - - argc -= optind; - argv += optind; - if (argc != 1) { - ofp_fatal(0, "exactly one non-option argument required; " - "use --help for help"); - } - - error = dhclient_create(argv[0], modify_dhcp_request, NULL, NULL, &cli); - if (error) { - ofp_fatal(error, "dhclient_create failed"); - } - dhclient_init(cli, request_ip.s_addr); - fatal_signal_add_hook(release, cli, true); - - for (;;) { - fatal_signal_block(); - dhclient_run(cli); - if (dhclient_changed(cli)) { - dhclient_configure_netdev(cli); - if (update_resolv_conf) { - dhclient_update_resolv_conf(cli); - } - } - dhclient_wait(cli); - fatal_signal_unblock(); - poll_block(); - } -} - -static void -release(void *cli_) -{ - struct dhclient *cli = cli_; - dhclient_release(cli); - if (dhclient_changed(cli)) { - dhclient_configure_netdev(cli); - } -} - -static void -modify_dhcp_request(struct dhcp_msg *msg, void *aux UNUSED) -{ - if (vendor_class) { - dhcp_msg_put_string(msg, DHCP_CODE_VENDOR_CLASS, vendor_class); - } -} - -static void -parse_options(int argc, char *argv[]) -{ - enum { - OPT_REQUEST_IP = UCHAR_MAX + 1, - OPT_VENDOR_CLASS, - OPT_NO_RESOLV_CONF - }; - static struct option long_options[] = { - {"request-ip", required_argument, 0, OPT_REQUEST_IP }, - {"vendor-class", required_argument, 0, OPT_VENDOR_CLASS }, - {"no-resolv-conf", no_argument, 0, OPT_NO_RESOLV_CONF}, - {"verbose", optional_argument, 0, 'v'}, - {"help", no_argument, 0, 'h'}, - {"version", no_argument, 0, 'V'}, - {0, 0, 0, 0}, - }; - char *short_options = long_options_to_short_options(long_options); - - for (;;) { - int c; - - c = getopt_long(argc, argv, short_options, long_options, NULL); - if (c == -1) { - break; - } - - switch (c) { - case OPT_REQUEST_IP: - if (!inet_aton(optarg, &request_ip)) { - ofp_fatal(0, - "--request-ip argument is not a valid IP address"); - } - break; - - case OPT_VENDOR_CLASS: - vendor_class = optarg; - break; - - case OPT_NO_RESOLV_CONF: - update_resolv_conf = false; - break; - - case 'h': - usage(); - - case 'V': - printf("%s %s compiled "__DATE__" "__TIME__"\n", - program_name, VERSION BUILDNR); - exit(EXIT_SUCCESS); - - case 'v': - vlog_set_verbosity(optarg); - break; - - case '?': - exit(EXIT_FAILURE); - - default: - abort(); - } - } - free(short_options); -} - -static void -usage(void) -{ - printf("%s: standalone program for testing OpenFlow DHCP client.\n" - "usage: %s [OPTIONS] NETDEV\n" - "where NETDEV is a network device (e.g. eth0).\n" - "\nDHCP options:\n" - " --request-ip=IP request specified IP address (default:\n" - " do not request a specific IP)\n" - " --vendor-class=STRING use STRING as vendor class (default:\n" - " none); use OpenFlow to imitate secchan\n" - " --no-resolv-conf do not update /etc/resolv.conf\n", - program_name, program_name); - vlog_usage(); - printf("\nOther options:\n" - " -h, --help display this help message\n" - " -V, --version display version information\n"); - exit(EXIT_SUCCESS); -} - diff --git a/openflow/tests/test-flows b/openflow/tests/test-flows deleted file mode 100755 index 891f9547888703c22fd04673db3fa828eceb1131..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 286976 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 -#include "flow.h" -#include -#include -#include -#include "openflow/openflow.h" -#include "timeval.h" -#include "ofpbuf.h" -#include "ofp-print.h" -#include "pcap.h" -#include "util.h" -#include "vlog.h" - -#undef NDEBUG -#include - -int -main(int argc UNUSED, char *argv[]) -{ - struct ofp_match expected_match; - FILE *flows, *pcap; - int retval; - int n = 0, errors = 0; - - set_program_name(argv[0]); - time_init(); - vlog_init(); - - flows = stdin; - pcap = fdopen(3, "rb"); - if (!pcap) { - ofp_fatal(errno, "failed to open fd 3 for reading"); - } - - retval = pcap_read_header(pcap); - if (retval) { - ofp_fatal(retval > 0 ? retval : 0, "reading pcap header failed"); - } - - while (fread(&expected_match, sizeof expected_match, 1, flows)) { - struct ofpbuf *packet; - struct ofp_match extracted_match; - struct flow flow; - - n++; - - retval = pcap_read(pcap, &packet); - if (retval == EOF) { - ofp_fatal(0, "unexpected end of file reading pcap file"); - } else if (retval) { - ofp_fatal(retval, "error reading pcap file"); - } - - flow_extract(packet, 0, &flow); - flow_fill_match(&extracted_match, &flow, 0); - - if (memcmp(&expected_match, &extracted_match, sizeof expected_match)) { - char *exp_s = ofp_match_to_string(&expected_match, 2); - char *got_s = ofp_match_to_string(&extracted_match, 2); - errors++; - printf("mismatch on packet #%d (1-based).\n", n); - printf("Packet:\n"); - ofp_print_packet(stdout, packet->data, packet->size, packet->size); - printf("Expected flow:\n%s\n", exp_s); - printf("Actually extracted flow:\n%s\n", got_s); - printf("\n"); - free(exp_s); - free(got_s); - } - - ofpbuf_delete(packet); - } - printf("checked %d packets, %d errors\n", n, errors); - return errors != 0; -} - diff --git a/openflow/tests/test-flows.sh b/openflow/tests/test-flows.sh deleted file mode 100755 index 0d38ad78..00000000 --- a/openflow/tests/test-flows.sh +++ /dev/null @@ -1,9 +0,0 @@ -#! /bin/sh -e -srcdir=`cd $srcdir && pwd` -trap 'rm -f flows$$ pcap$$ out$$' 0 1 2 13 15 -cd tests -"$srcdir"/tests/flowgen.pl >/dev/null 3>flows$$ 4>pcap$$ -./test-flows out$$ || true -diff -u - out$$ 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 HGyVSu&X&XL diff --git a/openflow/tests/test-hmap.c b/openflow/tests/test-hmap.c deleted file mode 100644 index 962389fa..00000000 --- a/openflow/tests/test-hmap.c +++ /dev/null @@ -1,282 +0,0 @@ -/* A non-exhaustive test for some of the functions and macros declared in - * hmap.h. */ - -#include -#include "hmap.h" -#include -#include "hash.h" -#include "util.h" - -#undef NDEBUG -#include - -/* Sample hmap element. */ -struct element { - int value; - struct hmap_node node; -}; - -typedef size_t hash_func(int value); - -static int -compare_ints(const void *a_, const void *b_) -{ - const int *a = a_; - const int *b = b_; - return *a < *b ? -1 : *a > *b; -} - -/* Verifies that 'hmap' contains exactly the 'n' values in 'values'. */ -static void -check_hmap(struct hmap *hmap, const int values[], size_t n, - hash_func *hash) -{ - int *sort_values, *hmap_values; - struct element *e; - size_t i; - - /* Check that all the values are there in iteration. */ - sort_values = xmalloc(sizeof *sort_values * n); - hmap_values = xmalloc(sizeof *sort_values * n); - - i = 0; - HMAP_FOR_EACH (e, struct element, node, hmap) { - assert(i < n); - hmap_values[i++] = e->value; - } - assert(i == n); - - memcpy(sort_values, values, sizeof *sort_values * n); - qsort(sort_values, n, sizeof *sort_values, compare_ints); - qsort(hmap_values, n, sizeof *hmap_values, compare_ints); - - for (i = 0; i < n; i++) { - assert(sort_values[i] == hmap_values[i]); - } - - free(hmap_values); - free(sort_values); - - /* Check that all the values are there in lookup. */ - for (i = 0; i < n; i++) { - size_t count = 0; - - HMAP_FOR_EACH_WITH_HASH (e, struct element, node, - hash(values[i]), hmap) { - count += e->value == values[i]; - } - assert(count == 1); - } - - /* Check counters. */ - assert(hmap_is_empty(hmap) == !n); - assert(hmap_count(hmap) == n); -} - -/* Puts the 'n' values in 'values' into 'elements', and then puts those - * elements into 'hmap'. */ -static void -make_hmap(struct hmap *hmap, struct element elements[], - int values[], size_t n, hash_func *hash) -{ - size_t i; - - hmap_init(hmap); - for (i = 0; i < n; i++) { - elements[i].value = i; - hmap_insert(hmap, &elements[i].node, hash(elements[i].value)); - values[i] = i; - } -} - -static void -shuffle(int *p, size_t n) -{ - for (; n > 1; n--, p++) { - int *q = &p[rand() % n]; - int tmp = *p; - *p = *q; - *q = tmp; - } -} - -#if 0 -/* Prints the values in 'hmap', plus 'name' as a title. */ -static void -print_hmap(const char *name, struct hmap *hmap) -{ - struct element *e; - - printf("%s:", name); - HMAP_FOR_EACH (e, struct element, node, hmap) { - printf(" %d(%zu)", e->value, e->node.hash & hmap->mask); - } - printf("\n"); -} - -/* Prints the 'n' values in 'values', plus 'name' as a title. */ -static void -print_ints(const char *name, const int *values, size_t n) -{ - size_t i; - - printf("%s:", name); - for (i = 0; i < n; i++) { - printf(" %d", values[i]); - } - printf("\n"); -} -#endif - -static size_t -identity_hash(int value) -{ - return value; -} - -static size_t -good_hash(int value) -{ - const uint32_t x = value; - return hash_words(&x, 1, 0x1234abcd); -} - -static size_t -constant_hash(int value UNUSED) -{ - return 123; -} - -/* Tests basic hmap insertion and deletion. */ -static void -test_hmap_insert_delete(hash_func *hash) -{ - enum { N_ELEMS = 100 }; - - struct element elements[N_ELEMS]; - int values[N_ELEMS]; - struct hmap hmap; - size_t i; - - hmap_init(&hmap); - for (i = 0; i < N_ELEMS; i++) { - elements[i].value = i; - hmap_insert(&hmap, &elements[i].node, hash(i)); - values[i] = i; - check_hmap(&hmap, values, i + 1, hash); - } - shuffle(values, N_ELEMS); - for (i = 0; i < N_ELEMS; i++) { - hmap_remove(&hmap, &elements[values[i]].node); - check_hmap(&hmap, values + (i + 1), N_ELEMS - (i + 1), hash); - } - hmap_destroy(&hmap); -} - -/* Tests basic hmap_reserve() and hmap_shrink(). */ -static void -test_hmap_reserve_shrink(hash_func *hash) -{ - enum { N_ELEMS = 32 }; - - size_t i; - - for (i = 0; i < N_ELEMS; i++) { - struct element elements[N_ELEMS]; - int values[N_ELEMS]; - struct hmap hmap; - size_t j; - - hmap_init(&hmap); - hmap_reserve(&hmap, i); - for (j = 0; j < N_ELEMS; j++) { - elements[j].value = j; - hmap_insert(&hmap, &elements[j].node, hash(j)); - values[j] = j; - check_hmap(&hmap, values, j + 1, hash); - } - shuffle(values, N_ELEMS); - for (j = 0; j < N_ELEMS; j++) { - hmap_remove(&hmap, &elements[values[j]].node); - hmap_shrink(&hmap); - check_hmap(&hmap, values + (j + 1), N_ELEMS - (j + 1), hash); - } - hmap_destroy(&hmap); - } -} - -/* Tests that HMAP_FOR_EACH_SAFE properly allows for deletion of the current - * element of a hmap. */ -static void -test_hmap_for_each_safe(hash_func *hash) -{ - enum { MAX_ELEMS = 10 }; - size_t n; - unsigned long int pattern; - - for (n = 0; n <= MAX_ELEMS; n++) { - for (pattern = 0; pattern < 1ul << n; pattern++) { - struct element elements[MAX_ELEMS]; - int values[MAX_ELEMS]; - struct hmap hmap; - struct element *e, *next; - size_t n_remaining; - int i; - - make_hmap(&hmap, elements, values, n, hash); - - i = 0; - n_remaining = n; - HMAP_FOR_EACH_SAFE (e, next, struct element, node, &hmap) { - assert(i < n); - if (pattern & (1ul << e->value)) { - size_t j; - hmap_remove(&hmap, &e->node); - for (j = 0; ; j++) { - assert(j < n_remaining); - if (values[j] == e->value) { - values[j] = values[--n_remaining]; - break; - } - } - } - check_hmap(&hmap, values, n_remaining, hash); - i++; - } - assert(i == n); - - for (i = 0; i < n; i++) { - if (pattern & (1ul << i)) { - n_remaining++; - } - } - assert(n == n_remaining); - - hmap_destroy(&hmap); - } - } -} - -static void -run_test(void (*function)(hash_func *)) -{ - hash_func *hash_funcs[] = { identity_hash, good_hash, constant_hash }; - size_t i; - - for (i = 0; i < ARRAY_SIZE(hash_funcs); i++) { - function(hash_funcs[i]); - printf("."); - fflush(stdout); - } -} - -int -main(void) -{ - run_test(test_hmap_insert_delete); - run_test(test_hmap_for_each_safe); - run_test(test_hmap_reserve_shrink); - printf("\n"); - return 0; -} - diff --git a/openflow/tests/test-list.c b/openflow/tests/test-list.c deleted file mode 100644 index 62857be9..00000000 --- a/openflow/tests/test-list.c +++ /dev/null @@ -1,159 +0,0 @@ -/* A non-exhaustive test for some of the functions and macros declared in - * list.h. */ - -#include -#include "list.h" -#include - -#undef NDEBUG -#include - -/* Sample list element. */ -struct element { - int value; - struct list node; -}; - -/* Puts the 'n' values in 'values' into 'elements', and then puts those - * elements in order into 'list'. */ -static void -make_list(struct list *list, struct element elements[], - int values[], size_t n) -{ - size_t i; - - list_init(list); - for (i = 0; i < n; i++) { - elements[i].value = i; - list_push_back(list, &elements[i].node); - values[i] = i; - } -} - -/* Verifies that 'list' contains exactly the 'n' values in 'values', in the - * specified order. */ -static void -check_list(struct list *list, const int values[], size_t n) -{ - struct element *e; - size_t i; - - i = 0; - LIST_FOR_EACH (e, struct element, node, list) { - assert(i < n); - assert(e->value == values[i]); - i++; - } - assert(&e->node == list); - assert(i == n); - - i = 0; - LIST_FOR_EACH_REVERSE (e, struct element, node, list) { - assert(i < n); - assert(e->value == values[n - i - 1]); - i++; - } - assert(&e->node == list); - assert(i == n); - - assert(list_is_empty(list) == !n); - assert(list_size(list) == n); -} - -#if 0 -/* Prints the values in 'list', plus 'name' as a title. */ -static void -print_list(const char *name, struct list *list) -{ - struct element *e; - - printf("%s:", name); - LIST_FOR_EACH (e, struct element, node, list) { - printf(" %d", e->value); - } - printf("\n"); -} -#endif - -/* Tests basic list construction. */ -static void -test_list_construction(void) -{ - enum { MAX_ELEMS = 100 }; - size_t n; - - for (n = 0; n <= MAX_ELEMS; n++) { - struct element elements[MAX_ELEMS]; - int values[MAX_ELEMS]; - struct list list; - - make_list(&list, elements, values, n); - check_list(&list, values, n); - } -} - -/* Tests that LIST_FOR_EACH_SAFE properly allows for deletion of the current - * element of a list. */ -static void -test_list_for_each_safe(void) -{ - enum { MAX_ELEMS = 10 }; - size_t n; - unsigned long int pattern; - - for (n = 0; n <= MAX_ELEMS; n++) { - for (pattern = 0; pattern < 1ul << n; pattern++) { - struct element elements[MAX_ELEMS]; - int values[MAX_ELEMS]; - struct list list; - struct element *e, *next; - size_t values_idx, n_remaining; - int i; - - make_list(&list, elements, values, n); - - i = 0; - values_idx = 0; - n_remaining = n; - LIST_FOR_EACH_SAFE (e, next, struct element, node, &list) { - assert(i < n); - if (pattern & (1ul << i)) { - list_remove(&e->node); - n_remaining--; - memmove(&values[values_idx], &values[values_idx + 1], - sizeof *values * (n_remaining - values_idx)); - } else { - values_idx++; - } - check_list(&list, values, n_remaining); - i++; - } - assert(i == n); - assert(&e->node == &list); - - for (i = 0; i < n; i++) { - if (pattern & (1ul << i)) { - n_remaining++; - } - } - assert(n == n_remaining); - } - } -} - -static void -run_test(void (*function)(void)) -{ - function(); - printf("."); -} - -int -main(void) -{ - run_test(test_list_construction); - run_test(test_list_for_each_safe); - printf("\n"); - return 0; -} - diff --git a/openflow/tests/test-stp-ieee802.1d-1998 b/openflow/tests/test-stp-ieee802.1d-1998 deleted file mode 100644 index f1982a03..00000000 --- a/openflow/tests/test-stp-ieee802.1d-1998 +++ /dev/null @@ -1,12 +0,0 @@ -# This is the STP example from IEEE 802.1D-1998. -bridge 0 0x42 = a b -bridge 1 0x97 = c:5 a d:5 -bridge 2 0x45 = b e -bridge 3 0x57 = b:5 e:5 -bridge 4 0x83 = a:5 e:5 -run 1000 -check 0 = root -check 1 = F F:10 F -check 2 = F:10 B -check 3 = F:5 F -check 4 = F:5 B diff --git a/openflow/tests/test-stp-ieee802.1d-2004-fig17.4 b/openflow/tests/test-stp-ieee802.1d-2004-fig17.4 deleted file mode 100644 index 1f708630..00000000 --- a/openflow/tests/test-stp-ieee802.1d-2004-fig17.4 +++ /dev/null @@ -1,31 +0,0 @@ -# This is the STP example from IEEE 802.1D-2004 figures 17.4 and 17.5. -bridge 0 0x111 = a b e c -bridge 1 0x222 = a b d f -bridge 2 0x333 = c d l j h g -bridge 3 0x444 = e f n m k i -bridge 4 0x555 = g i 0 0 -bridge 5 0x666 = h k 0 0 -bridge 6 0x777 = j m 0 0 -bridge 7 0x888 = l n 0 0 -run 1000 -check 0 = root -check 1 = F:10 B F F -check 2 = F:10 B F F F F -check 3 = F:10 B F F F F -check 4 = F:20 B F F -check 5 = F:20 B F F -check 6 = F:20 B F F -check 7 = F:20 B F F - -# Now connect two ports of bridge 7 to the same LAN. -bridge 7 = l n o o -# Same results except for bridge 7: -run 1000 -check 0 = root -check 1 = F:10 B F F -check 2 = F:10 B F F F F -check 3 = F:10 B F F F F -check 4 = F:20 B F F -check 5 = F:20 B F F -check 6 = F:20 B F F -check 7 = F:20 B F B diff --git a/openflow/tests/test-stp-ieee802.1d-2004-fig17.6 b/openflow/tests/test-stp-ieee802.1d-2004-fig17.6 deleted file mode 100644 index 6ed59177..00000000 --- a/openflow/tests/test-stp-ieee802.1d-2004-fig17.6 +++ /dev/null @@ -1,14 +0,0 @@ -# This is the STP example from IEEE 802.1D-2004 figure 17.6. -bridge 0 0x111 = a b l -bridge 1 0x222 = b c d -bridge 2 0x333 = d e f -bridge 3 0x444 = f g h -bridge 4 0x555 = j h i -bridge 5 0x666 = l j k -run 1000 -check 0 = root -check 1 = F:10 F F -check 2 = F:20 F F -check 3 = F:30 F B -check 4 = F:20 F F -check 5 = F:10 F F diff --git a/openflow/tests/test-stp-ieee802.1d-2004-fig17.7 b/openflow/tests/test-stp-ieee802.1d-2004-fig17.7 deleted file mode 100644 index daa0cdf2..00000000 --- a/openflow/tests/test-stp-ieee802.1d-2004-fig17.7 +++ /dev/null @@ -1,17 +0,0 @@ -# This is the STP example from IEEE 802.1D-2004 figure 17.7. -bridge 0 0xaa = b -bridge 1 0x111 = a b d f h g e c -bridge 2 0x222 = g h j l n m k i -run 1000 -check 0 = root -check 1 = F F:10 F F F F F F -check 2 = B F:20 F F F F F F - -# This is not the port priority change described in that figure, -# but I don't understand what port priority change would cause -# that change. -bridge 2 = g X j l n m k i -run 1000 -check 0 = root -check 1 = F F:10 F F F F F F -check 2 = F:20 D F F F F F F diff --git a/openflow/tests/test-stp-iol-io-1.1 b/openflow/tests/test-stp-iol-io-1.1 deleted file mode 100644 index 186d6c4c..00000000 --- a/openflow/tests/test-stp-iol-io-1.1 +++ /dev/null @@ -1,25 +0,0 @@ -# This test file approximates the following test from "Bridge -# Functions Consortium Spanning Tree Interoperability Test Suite -# Version 1.5": -# STP.io.1.1: Link Failure -bridge 0 0x111 = a b c -bridge 1 0x222 = a b c -run 1000 -check 0 = root -check 1 = F:10 B B -bridge 1 = 0 _ _ -run 1000 -check 0 = root -check 1 = F F:10 B -bridge 1 = X _ _ -run 1000 -check 0 = root -check 1 = D F:10 B -bridge 1 = _ 0 _ -run 1000 -check 0 = root -check 1 = D F F:10 -bridge 1 = _ X _ -run 1000 -check 0 = root -check 1 = D D F:10 diff --git a/openflow/tests/test-stp-iol-io-1.2 b/openflow/tests/test-stp-iol-io-1.2 deleted file mode 100644 index 285bbd88..00000000 --- a/openflow/tests/test-stp-iol-io-1.2 +++ /dev/null @@ -1,14 +0,0 @@ -# This test file approximates the following test from "Bridge -# Functions Consortium Spanning Tree Interoperability Test Suite -# Version 1.5": -# STP.io.1.2: Repeated Network -bridge 0 0x111 = a a -bridge 1 0x222 = a a -run 1000 -check 0 = rootid:0x111 F B -check 1 = rootid:0x111 F:10 B -bridge 1 = a^0x90 _ -run 1000 -check 0 = rootid:0x111 F B -check 1 = rootid:0x111 B F:10 - diff --git a/openflow/tests/test-stp-iol-io-1.4 b/openflow/tests/test-stp-iol-io-1.4 deleted file mode 100644 index 0065aaf5..00000000 --- a/openflow/tests/test-stp-iol-io-1.4 +++ /dev/null @@ -1,13 +0,0 @@ -# This test file approximates the following test from "Bridge -# Functions Consortium Spanning Tree Interoperability Test Suite -# Version 1.5": -# STP.io.1.4: Network Initialization -bridge 0 0x111 = a b c -bridge 1 0x222 = b d e -bridge 2 0x333 = a d f -bridge 3 0x444 = c e f -run 1000 -check 0 = root -check 1 = F:10 F F -check 2 = F:10 B F -check 3 = F:10 B B diff --git a/openflow/tests/test-stp-iol-io-1.5 b/openflow/tests/test-stp-iol-io-1.5 deleted file mode 100644 index 285d29de..00000000 --- a/openflow/tests/test-stp-iol-io-1.5 +++ /dev/null @@ -1,40 +0,0 @@ -# This test file approximates the following test from "Bridge -# Functions Consortium Spanning Tree Interoperability Test Suite -# Version 1.5": -# STP.io.1.5: Topology Change -bridge 0 0x111 = a b d c -bridge 1 0x222 = a b f e -bridge 2 0x333 = c d g h -bridge 3 0x444 = e f g h -run 1000 -check 0 = root -check 1 = F:10 B F F -check 2 = B F:10 F F -check 3 = B F:20 B B -bridge 1^0x7000 -run 1000 -check 0 = F:10 B F F -check 1 = root -check 2 = B F:20 B B -check 3 = B F:10 F F -bridge 2^0x6000 -run 1000 -check 0 = F F B F:10 -check 1 = F:20 B B B -check 2 = root -check 3 = F F F:10 B -bridge 3^0x5000 -run 1000 -check 0 = B B B F:20 -check 1 = F F B F:10 -check 2 = F F F:10 B -check 3 = root -bridge 0^0x4000 -bridge 1^0x4001 -bridge 2^0x4002 -bridge 3^0x4003 -run 1000 -check 0 = root -check 1 = F:10 B F F -check 2 = B F:10 F F -check 3 = B F:20 B B diff --git a/openflow/tests/test-stp-iol-op-1.1 b/openflow/tests/test-stp-iol-op-1.1 deleted file mode 100644 index 8432bf36..00000000 --- a/openflow/tests/test-stp-iol-op-1.1 +++ /dev/null @@ -1,7 +0,0 @@ -# This test file approximates the following tests from "Bridge -# Functions Consortium Spanning Tree Protocol Operations Test Suite -# Version 2.3": -# Test STP.op.1.1 ­ Root ID Initialized to Bridge ID -# Test STP.op.1.2 ­ Root Path Cost Initialized to Zero -bridge 0 0x123 = -check 0 = root diff --git a/openflow/tests/test-stp-iol-op-1.4 b/openflow/tests/test-stp-iol-op-1.4 deleted file mode 100644 index 6a121164..00000000 --- a/openflow/tests/test-stp-iol-op-1.4 +++ /dev/null @@ -1,8 +0,0 @@ -# This test file approximates the following test from "Bridge -# Functions Consortium Spanning Tree Protocol Operations Test Suite -# Version 2.3": -# Test STP.op.1.4 ­ All Ports Initialized to Designated Ports -bridge 0 0x123 = a b c d e f -check 0 = Li Li Li Li Li Li -run 1000 -check 0 = F F F F F F diff --git a/openflow/tests/test-stp-iol-op-3.1 b/openflow/tests/test-stp-iol-op-3.1 deleted file mode 100644 index 3e1099cb..00000000 --- a/openflow/tests/test-stp-iol-op-3.1 +++ /dev/null @@ -1,11 +0,0 @@ -# This test file approximates the following test from "Bridge -# Functions Consortium Spanning Tree Protocol Operations Test Suite -# Version 2.3": -# Test STP.op.3.1 ­ Root Bridge Selection: Root ID Values -bridge 0 0x111 = a -bridge 1 0x222 = a -check 0 = rootid:0x111 Li -check 1 = rootid:0x222 Li -run 1000 -check 0 = rootid:0x111 root -check 1 = rootid:0x111 F:10 diff --git a/openflow/tests/test-stp-iol-op-3.3 b/openflow/tests/test-stp-iol-op-3.3 deleted file mode 100644 index 2bcd45e1..00000000 --- a/openflow/tests/test-stp-iol-op-3.3 +++ /dev/null @@ -1,11 +0,0 @@ -# This test file approximates the following test from "Bridge -# Functions Consortium Spanning Tree Protocol Operations Test Suite -# Version 2.3": -# Test STP.op.3.3 ­ Root Bridge Selection: Bridge ID Values -bridge 0 0x333^0x6000 = a -bridge 1 0x222^0x7000 = b -bridge 2 0x111 = a b -run 1000 -check 0 = rootid:0x333^0x6000 root -check 1 = rootid:0x333^0x6000 F:20 -check 2 = rootid:0x333^0x6000 F:10 F diff --git a/openflow/tests/test-stp-iol-op-3.4 b/openflow/tests/test-stp-iol-op-3.4 deleted file mode 100644 index 2bcd45e1..00000000 --- a/openflow/tests/test-stp-iol-op-3.4 +++ /dev/null @@ -1,11 +0,0 @@ -# This test file approximates the following test from "Bridge -# Functions Consortium Spanning Tree Protocol Operations Test Suite -# Version 2.3": -# Test STP.op.3.3 ­ Root Bridge Selection: Bridge ID Values -bridge 0 0x333^0x6000 = a -bridge 1 0x222^0x7000 = b -bridge 2 0x111 = a b -run 1000 -check 0 = rootid:0x333^0x6000 root -check 1 = rootid:0x333^0x6000 F:20 -check 2 = rootid:0x333^0x6000 F:10 F diff --git a/openflow/tests/test-stp.c b/openflow/tests/test-stp.c deleted file mode 100644 index ddb7db7e..00000000 --- a/openflow/tests/test-stp.c +++ /dev/null @@ -1,665 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include "stp.h" -#include -#include -#include -#include -#include -#include -#include "ofpbuf.h" -#include "packets.h" - -struct bpdu { - int port_no; - void *data; - size_t size; -}; - -struct bridge { - struct test_case *tc; - int id; - bool reached; - - struct stp *stp; - - struct lan *ports[STP_MAX_PORTS]; - int n_ports; - -#define RXQ_SIZE 16 - struct bpdu rxq[RXQ_SIZE]; - int rxq_head, rxq_tail; -}; - -struct lan_conn { - struct bridge *bridge; - int port_no; -}; - -struct lan { - struct test_case *tc; - const char *name; - bool reached; - struct lan_conn conns[16]; - int n_conns; -}; - -struct test_case { - struct bridge *bridges[16]; - int n_bridges; - struct lan *lans[26]; - int n_lans; -}; - -static const char *file_name; -static int line_number; -static char line[128]; -static char *pos, *token; -static int n_warnings; - -static struct test_case * -new_test_case(void) -{ - struct test_case *tc = xmalloc(sizeof *tc); - tc->n_bridges = 0; - tc->n_lans = 0; - return tc; -} - -static void -send_bpdu(struct ofpbuf *pkt, int port_no, void *b_) -{ - struct bridge *b = b_; - struct lan *lan; - - assert(port_no < b->n_ports); - lan = b->ports[port_no]; - if (lan) { - const void *data = pkt->l3; - size_t size = (char *) ofpbuf_tail(pkt) - (char *) data; - int i; - - for (i = 0; i < lan->n_conns; i++) { - struct lan_conn *conn = &lan->conns[i]; - if (conn->bridge != b || conn->port_no != port_no) { - struct bridge *dst = conn->bridge; - struct bpdu *bpdu = &dst->rxq[dst->rxq_head++ % RXQ_SIZE]; - assert(dst->rxq_head - dst->rxq_tail <= RXQ_SIZE); - bpdu->data = xmemdup(data, size); - bpdu->size = size; - bpdu->port_no = conn->port_no; - } - } - } - ofpbuf_delete(pkt); -} - -static struct bridge * -new_bridge(struct test_case *tc, int id) -{ - struct bridge *b = xmalloc(sizeof *b); - char name[16]; - b->tc = tc; - b->id = id; - snprintf(name, sizeof name, "stp%x", id); - b->stp = stp_create(name, id, send_bpdu, b); - assert(tc->n_bridges < ARRAY_SIZE(tc->bridges)); - b->n_ports = 0; - b->rxq_head = b->rxq_tail = 0; - tc->bridges[tc->n_bridges++] = b; - return b; -} - -static struct lan * -new_lan(struct test_case *tc, const char *name) -{ - struct lan *lan = xmalloc(sizeof *lan); - lan->tc = tc; - lan->name = xstrdup(name); - lan->n_conns = 0; - assert(tc->n_lans < ARRAY_SIZE(tc->lans)); - tc->lans[tc->n_lans++] = lan; - return lan; -} - -static void -reconnect_port(struct bridge *b, int port_no, struct lan *new_lan) -{ - struct lan *old_lan; - int j; - - assert(port_no < b->n_ports); - old_lan = b->ports[port_no]; - if (old_lan == new_lan) { - return; - } - - /* Disconnect from old_lan. */ - if (old_lan) { - for (j = 0; j < old_lan->n_conns; j++) { - struct lan_conn *c = &old_lan->conns[j]; - if (c->bridge == b && c->port_no == port_no) { - memmove(c, c + 1, sizeof *c * (old_lan->n_conns - j - 1)); - old_lan->n_conns--; - break; - } - } - } - - /* Connect to new_lan. */ - b->ports[port_no] = new_lan; - if (new_lan) { - int conn_no = new_lan->n_conns++; - assert(conn_no < ARRAY_SIZE(new_lan->conns)); - new_lan->conns[conn_no].bridge = b; - new_lan->conns[conn_no].port_no = port_no; - } -} - -static void -new_port(struct bridge *b, struct lan *lan, int path_cost) -{ - int port_no = b->n_ports++; - struct stp_port *p = stp_get_port(b->stp, port_no); - assert(port_no < ARRAY_SIZE(b->ports)); - b->ports[port_no] = NULL; - stp_port_set_path_cost(p, path_cost); - stp_port_enable(p); - reconnect_port(b, port_no, lan); -} - -static void -dump(struct test_case *tc) -{ - int i; - - for (i = 0; i < tc->n_bridges; i++) { - struct bridge *b = tc->bridges[i]; - struct stp *stp = b->stp; - int j; - - printf("%s:", stp_get_name(stp)); - if (stp_is_root_bridge(stp)) { - printf(" root"); - } - printf("\n"); - for (j = 0; j < b->n_ports; j++) { - struct stp_port *p = stp_get_port(stp, j); - enum stp_state state = stp_port_get_state(p); - - printf("\tport %d", j); - if (b->ports[j]) { - printf(" (lan %s)", b->ports[j]->name); - } else { - printf(" (disconnected)"); - } - printf(": %s", stp_state_name(state)); - if (p == stp_get_root_port(stp)) { - printf(" (root port, root_path_cost=%u)", stp_get_root_path_cost(stp)); - } - printf("\n"); - } - } -} - -static void dump_lan_tree(struct test_case *, struct lan *, int level); - -static void -dump_bridge_tree(struct test_case *tc, struct bridge *b, int level) -{ - int i; - - if (b->reached) { - return; - } - b->reached = true; - for (i = 0; i < level; i++) { - printf("\t"); - } - printf("%s\n", stp_get_name(b->stp)); - for (i = 0; i < b->n_ports; i++) { - struct lan *lan = b->ports[i]; - struct stp_port *p = stp_get_port(b->stp, i); - if (stp_port_get_state(p) == STP_FORWARDING && lan) { - dump_lan_tree(tc, lan, level + 1); - } - } -} - -static void -dump_lan_tree(struct test_case *tc, struct lan *lan, int level) -{ - int i; - - if (lan->reached) { - return; - } - lan->reached = true; - for (i = 0; i < level; i++) { - printf("\t"); - } - printf("%s\n", lan->name); - for (i = 0; i < lan->n_conns; i++) { - struct bridge *b = lan->conns[i].bridge; - dump_bridge_tree(tc, b, level + 1); - } -} - -static void -tree(struct test_case *tc) -{ - int i; - - for (i = 0; i < tc->n_bridges; i++) { - struct bridge *b = tc->bridges[i]; - b->reached = false; - } - for (i = 0; i < tc->n_lans; i++) { - struct lan *lan = tc->lans[i]; - lan->reached = false; - } - for (i = 0; i < tc->n_bridges; i++) { - struct bridge *b = tc->bridges[i]; - struct stp *stp = b->stp; - if (stp_is_root_bridge(stp)) { - dump_bridge_tree(tc, b, 0); - } - } -} - -static void -simulate(struct test_case *tc, int granularity) -{ - int time; - - for (time = 0; time < 1000 * 180; time += granularity) { - int round_trips; - int i; - - for (i = 0; i < tc->n_bridges; i++) { - stp_tick(tc->bridges[i]->stp, granularity); - } - for (round_trips = 0; round_trips < granularity; round_trips++) { - bool any = false; - for (i = 0; i < tc->n_bridges; i++) { - struct bridge *b = tc->bridges[i]; - for (; b->rxq_tail != b->rxq_head; b->rxq_tail++) { - struct bpdu *bpdu = &b->rxq[b->rxq_tail % RXQ_SIZE]; - stp_received_bpdu(stp_get_port(b->stp, bpdu->port_no), - bpdu->data, bpdu->size); - any = true; - } - } - if (!any) { - break; - } - } - } -} - -static void -err(const char *message, ...) - PRINTF_FORMAT(1, 2) - NO_RETURN; - -static void -err(const char *message, ...) -{ - va_list args; - - fprintf(stderr, "%s:%d:%td: ", file_name, line_number, pos - line); - va_start(args, message); - vfprintf(stderr, message, args); - va_end(args); - putc('\n', stderr); - - exit(EXIT_FAILURE); -} - -static void -warn(const char *message, ...) - PRINTF_FORMAT(1, 2); - -static void -warn(const char *message, ...) -{ - va_list args; - - fprintf(stderr, "%s:%d: ", file_name, line_number); - va_start(args, message); - vfprintf(stderr, message, args); - va_end(args); - putc('\n', stderr); - - n_warnings++; -} - -static bool -get_token(void) -{ - char *start; - - while (isspace((unsigned char) *pos)) { - pos++; - } - if (*pos == '\0') { - token = NULL; - return false; - } - - start = pos; - if (isalpha((unsigned char) *pos)) { - while (isalpha((unsigned char) *++pos)) { - continue; - } - } else if (isdigit((unsigned char) *pos)) { - if (*pos == '0' && (pos[1] == 'x' || pos[1] == 'X')) { - pos += 2; - while (isxdigit((unsigned char) *pos)) { - pos++; - } - } else { - while (isdigit((unsigned char) *++pos)) { - continue; - } - } - } else { - pos++; - } - - free(token); - token = xmemdup0(start, pos - start); - return true; -} - -static bool -get_int(int *intp) -{ - char *save_pos = pos; - if (token && isdigit((unsigned char) *token)) { - *intp = strtol(token, NULL, 0); - get_token(); - return true; - } else { - pos = save_pos; - return false; - } -} - -static bool -match(const char *want) -{ - if (token && !strcmp(want, token)) { - get_token(); - return true; - } else { - return false; - } -} - -static int -must_get_int(void) -{ - int x; - if (!get_int(&x)) { - err("expected integer"); - } - return x; -} - -static void -must_match(const char *want) -{ - if (!match(want)) { - err("expected \"%s\"", want); - } -} - -int -main(int argc, char *argv[]) -{ - struct test_case *tc; - FILE *input_file; - int i; - - if (argc != 2) { - ofp_fatal(0, "usage: test-stp INPUT.STP\n"); - } - file_name = argv[1]; - - input_file = fopen(file_name, "r"); - if (!input_file) { - ofp_fatal(errno, "error opening \"%s\"", file_name); - } - - tc = new_test_case(); - for (i = 0; i < 26; i++) { - char name[2]; - name[0] = 'a' + i; - name[1] = '\0'; - new_lan(tc, name); - } - - for (line_number = 1; fgets(line, sizeof line, input_file); - line_number++) - { - char *newline, *hash; - - newline = strchr(line, '\n'); - if (newline) { - *newline = '\0'; - } - hash = strchr(line, '#'); - if (hash) { - *hash = '\0'; - } - - pos = line; - if (!get_token()) { - continue; - } - if (match("bridge")) { - struct bridge *bridge; - int bridge_no, port_no; - - bridge_no = must_get_int(); - if (bridge_no < tc->n_bridges) { - bridge = tc->bridges[bridge_no]; - } else if (bridge_no == tc->n_bridges) { - bridge = new_bridge(tc, must_get_int()); - } else { - err("bridges must be numbered consecutively from 0"); - } - if (match("^")) { - stp_set_bridge_priority(bridge->stp, must_get_int()); - } - - if (match("=")) { - for (port_no = 0; port_no < STP_MAX_PORTS; port_no++) { - struct stp_port *p = stp_get_port(bridge->stp, port_no); - if (!token || match("X")) { - stp_port_disable(p); - } else if (match("_")) { - /* Nothing to do. */ - } else { - struct lan *lan; - int path_cost; - - if (!strcmp(token, "0")) { - lan = NULL; - } else if (strlen(token) == 1 && islower(*token)) { - lan = tc->lans[*token - 'a']; - } else { - err("%s is not a valid LAN name " - "(0 or a lowercase letter)", token); - } - get_token(); - - path_cost = match(":") ? must_get_int() : 10; - if (port_no < bridge->n_ports) { - stp_port_set_path_cost(p, path_cost); - stp_port_enable(p); - reconnect_port(bridge, port_no, lan); - } else if (port_no == bridge->n_ports) { - new_port(bridge, lan, path_cost); - } else { - err("ports must be numbered consecutively"); - } - if (match("^")) { - stp_port_set_priority(p, must_get_int()); - } - } - } - } - } else if (match("run")) { - simulate(tc, must_get_int()); - } else if (match("dump")) { - dump(tc); - } else if (match("tree")) { - tree(tc); - } else if (match("check")) { - struct bridge *b; - struct stp *stp; - int bridge_no, port_no; - - bridge_no = must_get_int(); - if (bridge_no >= tc->n_bridges) { - err("no bridge numbered %d", bridge_no); - } - b = tc->bridges[bridge_no]; - stp = b->stp; - - must_match("="); - - if (match("rootid")) { - uint64_t rootid; - must_match(":"); - rootid = must_get_int(); - if (match("^")) { - rootid |= (uint64_t) must_get_int() << 48; - } else { - rootid |= UINT64_C(0x8000) << 48; - } - if (stp_get_designated_root(stp) != rootid) { - warn("%s: root %"PRIx64", not %"PRIx64, - stp_get_name(stp), stp_get_designated_root(stp), - rootid); - } - } - - if (match("root")) { - if (stp_get_root_path_cost(stp)) { - warn("%s: root path cost of root is %u but should be 0", - stp_get_name(stp), stp_get_root_path_cost(stp)); - } - if (!stp_is_root_bridge(stp)) { - warn("%s: root is %"PRIx64", not %"PRIx64, - stp_get_name(stp), - stp_get_designated_root(stp), stp_get_bridge_id(stp)); - } - for (port_no = 0; port_no < b->n_ports; port_no++) { - struct stp_port *p = stp_get_port(stp, port_no); - enum stp_state state = stp_port_get_state(p); - if (!(state & (STP_DISABLED | STP_FORWARDING))) { - warn("%s: root port %d in state %s", - stp_get_name(b->stp), port_no, - stp_state_name(state)); - } - } - } else { - for (port_no = 0; port_no < STP_MAX_PORTS; port_no++) { - struct stp_port *p = stp_get_port(stp, port_no); - enum stp_state state; - if (token == NULL || match("D")) { - state = STP_DISABLED; - } else if (match("B")) { - state = STP_BLOCKING; - } else if (match("Li")) { - state = STP_LISTENING; - } else if (match("Le")) { - state = STP_LEARNING; - } else if (match("F")) { - state = STP_FORWARDING; - } else if (match("_")) { - continue; - } else { - err("unknown port state %s", token); - } - if (stp_port_get_state(p) != state) { - warn("%s port %d: state is %s but should be %s", - stp_get_name(stp), port_no, - stp_state_name(stp_port_get_state(p)), - stp_state_name(state)); - } - if (state == STP_FORWARDING) { - struct stp_port *root_port = stp_get_root_port(stp); - if (match(":")) { - int root_path_cost = must_get_int(); - if (p != root_port) { - warn("%s: port %d is not the root port", - stp_get_name(stp), port_no); - if (!root_port) { - warn("%s: (there is no root port)", - stp_get_name(stp)); - } else { - warn("%s: (port %d is the root port)", - stp_get_name(stp), - stp_port_no(root_port)); - } - } else if (root_path_cost - != stp_get_root_path_cost(stp)) { - warn("%s: root path cost is %u, should be %d", - stp_get_name(stp), - stp_get_root_path_cost(stp), - root_path_cost); - } - } else if (p == root_port) { - warn("%s: port %d is the root port but " - "not expected to be", - stp_get_name(stp), port_no); - } - } - } - } - if (n_warnings) { - exit(EXIT_FAILURE); - } - } - if (get_token()) { - err("trailing garbage on line"); - } - } - - return 0; -} diff --git a/openflow/tests/test-stp.sh b/openflow/tests/test-stp.sh deleted file mode 100755 index fd6acf54..00000000 --- a/openflow/tests/test-stp.sh +++ /dev/null @@ -1,7 +0,0 @@ -#! /bin/sh -set -e -progress= -for d in ${stp_files}; do - echo "Testing $d..." - $SUPERVISOR ./tests/test-stp ${srcdir}/$d -done diff --git a/openflow/tests/test-type-props.c b/openflow/tests/test-type-props.c deleted file mode 100644 index 67dabae8..00000000 --- a/openflow/tests/test-type-props.c +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include "type-props.h" -#include -#include - -#define MUST_SUCCEED(EXPRESSION) \ - if (!(EXPRESSION)) { \ - fprintf(stderr, "%s:%d: %s failed\n", \ - __FILE__, __LINE__, #EXPRESSION); \ - exit(EXIT_FAILURE); \ - } - -#define TEST_TYPE(type, minimum, maximum, is_signed) \ - MUST_SUCCEED(TYPE_IS_INTEGER(type)); \ - MUST_SUCCEED(TYPE_IS_SIGNED(type) == is_signed); \ - MUST_SUCCEED(TYPE_MAXIMUM(type) == maximum); \ - MUST_SUCCEED(TYPE_MINIMUM(type) == minimum); - -int -main (void) -{ - TEST_TYPE(char, CHAR_MIN, CHAR_MAX, (CHAR_MIN < 0)); - - TEST_TYPE(signed char, SCHAR_MIN, SCHAR_MAX, 1); - TEST_TYPE(short int, SHRT_MIN, SHRT_MAX, 1); - TEST_TYPE(int, INT_MIN, INT_MAX, 1); - TEST_TYPE(long int, LONG_MIN, LONG_MAX, 1); - TEST_TYPE(long long int, LLONG_MIN, LLONG_MAX, 1); - - TEST_TYPE(unsigned char, 0, UCHAR_MAX, 0); - TEST_TYPE(unsigned short int, 0, USHRT_MAX, 0); - TEST_TYPE(unsigned int, 0, UINT_MAX, 0); - TEST_TYPE(unsigned long int, 0, ULONG_MAX, 0); - TEST_TYPE(unsigned long long int, 0, ULLONG_MAX, 0); - - MUST_SUCCEED(!(TYPE_IS_INTEGER(float))); - MUST_SUCCEED(!(TYPE_IS_INTEGER(double))); - MUST_SUCCEED(!(TYPE_IS_INTEGER(long double))); - - return 0; -} diff --git a/openflow/third-party/.gitignore b/openflow/third-party/.gitignore deleted file mode 100644 index b336cc7c..00000000 --- a/openflow/third-party/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/Makefile -/Makefile.in diff --git a/openflow/third-party/README b/openflow/third-party/README deleted file mode 100644 index 15f4d647..00000000 --- a/openflow/third-party/README +++ /dev/null @@ -1,35 +0,0 @@ -This directory contains third-party software that may be useful for -debugging. - -tcpdump -------- -The "ofp-tcpdump.patch" patch adds the ability to parse OpenFlow -messages to tcpdump. These instructions assume that tcpdump 3.9.8 -is going to be used, but it should work with other versions that are not -substantially different. To begin, download tcpdump and apply the -patch: - - wget http://www.tcpdump.org/release/tcpdump-3.9.8.tar.gz - tar xzf tcpdump-3.9.8.tar.gz - ln -s tcpdump-3.9.8 tcpdump - patch -p0 < ofp-tcpdump.patch - -Then build the new version of tcpdump: - - cd tcpdump - ./configure - make - -Clearly, tcpdump can only parse unencrypted packets, so you will need to -connect the controller and datapath using plain TCP. To look at the -traffic, tcpdump will be started in a manner similar to the following: - - sudo ./tcpdump -s0 -i eth0 port 6633 - -The "-s0" flag indicates that tcpdump should capture the entire packet. -If the OpenFlow message is not received in its entirety, "[|openflow]" will -be printed instead of the OpenFlow message contents. - -The verbosity of the output may be increased by adding additional "-v" -flags. If "-vvv" is used, the raw OpenFlow data is also printed in -hex and ASCII. diff --git a/openflow/third-party/automake.mk b/openflow/third-party/automake.mk deleted file mode 100644 index 02636bb5..00000000 --- a/openflow/third-party/automake.mk +++ /dev/null @@ -1,3 +0,0 @@ -EXTRA_DIST += \ - third-party/README \ - third-party/ofp-tcpdump.patch diff --git a/openflow/third-party/ofp-tcpdump.patch b/openflow/third-party/ofp-tcpdump.patch deleted file mode 100644 index 3f2cc57b..00000000 --- a/openflow/third-party/ofp-tcpdump.patch +++ /dev/null @@ -1,119 +0,0 @@ -diff -rNu tcpdump/interface.h tcpdump/interface.h ---- tcpdump/interface.h 2007-06-13 18:03:20.000000000 -0700 -+++ tcpdump/interface.h 2008-02-06 15:06:30.000000000 -0800 -@@ -148,7 +148,8 @@ - - extern const char *dnaddr_string(u_short); - --extern void error(const char *, ...) -+#define error(fmt, args...) tcpdump_error(fmt, ## args) -+extern void tcpdump_error(const char *, ...) - __attribute__((noreturn, format (printf, 1, 2))); - extern void warning(const char *, ...) __attribute__ ((format (printf, 1, 2))); - -@@ -176,6 +177,7 @@ - extern void hex_print_with_offset(const char *, const u_char *, u_int, u_int); - extern void hex_print(const char *, const u_char *, u_int); - extern void telnet_print(const u_char *, u_int); -+extern void openflow_print(const u_char *, u_int); - extern int ether_encap_print(u_short, const u_char *, u_int, u_int, u_short *); - extern int llc_print(const u_char *, u_int, u_int, const u_char *, - const u_char *, u_short *); -diff -rNu tcpdump/Makefile.in tcpdump/Makefile.in ---- tcpdump/Makefile.in 2007-09-25 18:59:52.000000000 -0700 -+++ tcpdump/Makefile.in 2008-02-07 11:46:03.000000000 -0800 -@@ -49,10 +49,10 @@ - CFLAGS = $(CCOPT) $(DEFS) $(INCLS) - - # Standard LDFLAGS --LDFLAGS = @LDFLAGS@ -+LDFLAGS = @LDFLAGS@ -L../../lib - - # Standard LIBS --LIBS = @LIBS@ -+LIBS = @LIBS@ -lopenflow - - INSTALL = @INSTALL@ - INSTALL_PROGRAM = @INSTALL_PROGRAM@ -@@ -87,7 +87,8 @@ - print-slow.c print-snmp.c print-stp.c print-sunatm.c print-sunrpc.c \ - print-symantec.c print-syslog.c print-tcp.c print-telnet.c print-tftp.c \ - print-timed.c print-token.c print-udp.c print-vjc.c print-vrrp.c \ -- print-wb.c print-zephyr.c setsignal.c tcpdump.c util.c -+ print-wb.c print-zephyr.c setsignal.c tcpdump.c util.c \ -+ print-openflow.c - - LOCALSRC = @LOCALSRC@ - GENSRC = version.c -diff -rNu tcpdump/print-openflow.c tcpdump/print-openflow.c ---- tcpdump/print-openflow.c 1969-12-31 16:00:00.000000000 -0800 -+++ tcpdump/print-openflow.c 2008-02-07 11:29:01.000000000 -0800 -@@ -0,0 +1,46 @@ -+/* Copyright (C) 2007, 2008 Board of Trustees, Leland Stanford Jr. University. -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to -+ * deal in the Software without restriction, including without limitation the -+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -+ * sell copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -+ * IN THE SOFTWARE. -+ */ -+ -+ -+#ifdef HAVE_CONFIG_H -+#include "config.h" -+#endif -+ -+#include -+ -+#include "interface.h" -+#include "../../include/openflow/openflow.h" -+#include "../../include/ofp-print.h" -+ -+void -+openflow_print(const u_char *sp, u_int length) -+{ -+ const struct ofp_header *ofp = (struct ofp_header *)sp; -+ -+ if (!TTEST2(*sp, ntohs(ofp->length))) -+ goto trunc; -+ -+ ofp_print(stdout, sp, length, vflag); -+ return; -+ -+trunc: -+ printf("[|openflow]"); -+} -diff -rNu tcpdump/print-tcp.c tcpdump/print-tcp.c ---- tcpdump/print-tcp.c 2006-09-19 12:07:57.000000000 -0700 -+++ tcpdump/print-tcp.c 2008-02-07 13:07:58.000000000 -0800 -@@ -52,6 +52,8 @@ - - #include "nameser.h" - -+#include "../../include/openflow.h" -+ - #ifdef HAVE_LIBCRYPTO - #include - -@@ -680,7 +682,8 @@ - } - else if (length > 0 && (sport == LDP_PORT || dport == LDP_PORT)) { - ldp_print(bp, length); -- } -+ } else if (sport == OFP_TCP_PORT || dport == OFP_TCP_PORT) -+ openflow_print(bp, length); - } - return; - bad: diff --git a/openflow/udatapath/.dirstamp b/openflow/udatapath/.dirstamp deleted file mode 100644 index e69de29b..00000000 diff --git a/openflow/udatapath/.gitignore b/openflow/udatapath/.gitignore deleted file mode 100644 index e4272b0b..00000000 --- a/openflow/udatapath/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/Makefile -/Makefile.in -/ofdatapath -/ofdatapath.8 diff --git a/openflow/udatapath/automake.mk b/openflow/udatapath/automake.mk deleted file mode 100644 index b4b4d8e6..00000000 --- a/openflow/udatapath/automake.mk +++ /dev/null @@ -1,75 +0,0 @@ -# -# Build udatapath as binary -# - -bin_PROGRAMS += udatapath/ofdatapath -man_MANS += udatapath/ofdatapath.8 - -udatapath_ofdatapath_SOURCES = \ - udatapath/chain.c \ - udatapath/chain.h \ - udatapath/crc32.c \ - udatapath/crc32.h \ - udatapath/datapath.c \ - udatapath/datapath.h \ - udatapath/dp_act.c \ - udatapath/dp_act.h \ - udatapath/of_ext_msg.c \ - udatapath/of_ext_msg.h \ - udatapath/udatapath.c \ - udatapath/private-msg.c \ - udatapath/private-msg.h \ - udatapath/switch-flow.c \ - udatapath/switch-flow.h \ - udatapath/table.h \ - udatapath/table-hash.c \ - udatapath/table-linear.c - -udatapath_ofdatapath_LDADD = lib/libopenflow.a $(SSL_LIBS) $(FAULT_LIBS) -udatapath_ofdatapath_CPPFLAGS = $(AM_CPPFLAGS) - -EXTRA_DIST += udatapath/ofdatapath.8.in -DISTCLEANFILES += udatapath/ofdatapath.8 - -if BUILD_HW_LIBS - -# Options for each platform -if NF2 -udatapath_ofdatapath_LDADD += hw-lib/libnf2.a -udatapath_ofdatapath_CPPFLAGS += -DOF_HW_PLAT -DUSE_NETDEV -g -noinst_LIBRARIES += hw-lib/libnf2.a -endif - -endif - -if BUILD_HW_LIBS -# -# Build udatapath as a library -# - -noinst_LIBRARIES += udatapath/libudatapath.a - -udatapath_libudatapath_a_SOURCES = \ - udatapath/chain.c \ - udatapath/chain.h \ - udatapath/crc32.c \ - udatapath/crc32.h \ - udatapath/datapath.c \ - udatapath/datapath.h \ - udatapath/dp_act.c \ - udatapath/dp_act.h \ - udatapath/of_ext_msg.c \ - udatapath/of_ext_msg.h \ - udatapath/udatapath.c \ - udatapath/private-msg.c \ - udatapath/private-msg.h \ - udatapath/switch-flow.c \ - udatapath/switch-flow.h \ - udatapath/table.h \ - udatapath/table-hash.c \ - udatapath/table-linear.c - -udatapath_libudatapath_a_CPPFLAGS = $(AM_CPPFLAGS) -udatapath_libudatapath_a_CPPFLAGS += -DOF_HW_PLAT -DUDATAPATH_AS_LIB -g - -endif diff --git a/openflow/udatapath/chain.c b/openflow/udatapath/chain.c deleted file mode 100644 index b9dc39c0..00000000 --- a/openflow/udatapath/chain.c +++ /dev/null @@ -1,261 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include "chain.h" -#include -#include -#include -#include "switch-flow.h" -#include "table.h" -#include "datapath.h" - -#if defined(OF_HW_PLAT) -#include -#endif - -#define THIS_MODULE VLM_chain -#include "vlog.h" - -/* Attempts to append 'table' to the set of tables in 'chain'. Returns 0 or - * negative error. If 'table' is null it is assumed that table creation failed - * due to out-of-memory. */ -static int add_table(struct sw_chain *chain, struct sw_table *table, int emerg) -{ - if (table == NULL) - return -ENOMEM; - if (chain->n_tables >= CHAIN_MAX_TABLES) { - VLOG_ERR("too many tables in chain\n"); - table->destroy(table); - return -ENOBUFS; - } - if (emerg) - chain->emerg_table = table; - else - chain->tables[chain->n_tables++] = table; - return 0; -} - -/* Creates and returns a new chain. Returns NULL if the chain cannot be - * created. */ -struct sw_chain *chain_create(struct datapath *dp) -{ - struct sw_chain *chain = calloc(1, sizeof *chain); - if (chain == NULL) - return NULL; - - chain->dp = dp; -#if defined(OF_HW_PLAT) - if (dp && dp->hw_drv) { - if (add_table(chain, (struct sw_table *)dp->hw_drv, 0) != 0) { - VLOG_ERR("Could not attach HW table to chain\n"); - } - } -#endif - if (add_table(chain, table_hash2_create(0x1EDC6F41, TABLE_HASH_MAX_FLOWS, - 0x741B8CD7, TABLE_HASH_MAX_FLOWS), - 0) - || add_table(chain, table_linear_create(TABLE_LINEAR_MAX_FLOWS), 0) - || add_table(chain, table_linear_create(TABLE_LINEAR_MAX_FLOWS), 1)) { - chain_destroy(chain); - return NULL; - } - - return chain; -} - -/* Searches 'chain' for a flow matching 'key', which must not have any wildcard - * fields. Returns the flow if successful, otherwise a null pointer. */ -struct sw_flow * -chain_lookup(struct sw_chain *chain, const struct sw_flow_key *key, int emerg) -{ - int i; - - assert(!key->wildcards); - - if (emerg) { - struct sw_table *t = chain->emerg_table; - struct sw_flow *flow = t->lookup(t, key); - t->n_lookup++; - if (flow) { - t->n_matched++; - return flow; - } - } else { - for (i = 0; i < chain->n_tables; i++) { - struct sw_table *t = chain->tables[i]; - struct sw_flow *flow = t->lookup(t, key); - t->n_lookup++; - if (flow) { - t->n_matched++; - return flow; - } - } - } - - return NULL; -} - -/* Inserts 'flow' into 'chain', replacing any duplicate flow. Returns 0 if - * successful or a negative error. - * - * If successful, 'flow' becomes owned by the chain, otherwise it is retained - * by the caller. */ -int -chain_insert(struct sw_chain *chain, struct sw_flow *flow, int emerg) -{ - int i; - - if (emerg) { - struct sw_table *t = chain->emerg_table; - if (t->insert(t, flow)) - return 0; - } else { - for (i = 0; i < chain->n_tables; i++) { - struct sw_table *t = chain->tables[i]; - if (t->insert(t, flow)) - return 0; - } - } - - return -ENOBUFS; -} - -/* Modifies actions in 'chain' that match 'key'. If 'strict' set, wildcards - * and priority must match. Returns the number of flows that were modified. - * - * Expensive in the general case as currently implemented, since it requires - * iterating through the entire contents of each table for keys that contain - * wildcards. Relatively cheap for fully specified keys. */ -int -chain_modify(struct sw_chain *chain, const struct sw_flow_key *key, - uint16_t priority, int strict, - const struct ofp_action_header *actions, size_t actions_len, - int emerg) -{ - int count = 0; - int i; - - if (emerg) { - struct sw_table *t = chain->emerg_table; - count += t->modify(t, key, priority, strict, actions, actions_len); - } else { - for (i = 0; i < chain->n_tables; i++) { - struct sw_table *t = chain->tables[i]; - count += t->modify(t, key, priority, strict, actions, actions_len); - } - } - - return count; -} - -/* Checks whether the chain has an entry with the same priority which conflicts - * with 'key'. If 'strict' set, wildcards should also match. If 'strict' is not - * set, comparison is done 'module wildcards'. - * - * Returns 'true' if such an entry exists, 'false' otherwise. */ -int -chain_has_conflict(struct sw_chain *chain, const struct sw_flow_key *key, - uint16_t priority, int strict) -{ - int i; - - for (i = 0; i < chain->n_tables; i++) { - struct sw_table *t = chain->tables[i]; - if (t->has_conflict(t, key, priority, strict)) { - return true; - } - } - - return false; -} - -/* Deletes from 'chain' any and all flows that match 'key'. If 'out_port' - * is not OFPP_NONE, then matching entries must have that port as an - * argument for an output action. If 'strict" is set, then wildcards and - * priority must match. Returns the number of flows that were deleted. - * - * Expensive in the general case as currently implemented, since it requires - * iterating through the entire contents of each table for keys that contain - * wildcards. Relatively cheap for fully specified keys. */ -int -chain_delete(struct sw_chain *chain, const struct sw_flow_key *key, - uint16_t out_port, uint16_t priority, int strict, int emerg) -{ - int count = 0; - int i; - - if (emerg) { - struct sw_table *t = chain->emerg_table; - count += t->delete(chain->dp, t, key, out_port, priority, strict); - } else { - for (i = 0; i < chain->n_tables; i++) { - struct sw_table *t = chain->tables[i]; - count += t->delete(chain->dp, t, key, out_port, priority, strict); - } - } - - return count; -} - -/* Deletes timed-out flow entries from all the tables in 'chain' and appends - * the deleted flows to 'deleted'. - * - * Expensive as currently implemented, since it iterates through the entire - * contents of each table. */ -void -chain_timeout(struct sw_chain *chain, struct list *deleted) -{ - int i; - - for (i = 0; i < chain->n_tables; i++) { - struct sw_table *t = chain->tables[i]; - t->timeout(t, deleted); - } -} - -/* Destroys 'chain', which must not have any users. */ -void -chain_destroy(struct sw_chain *chain) -{ - int i; - struct sw_table *t; - - for (i = 0; i < chain->n_tables; i++) { - t = chain->tables[i]; - t->destroy(t); - } - t = chain->emerg_table; - t->destroy(t); - free(chain); -} diff --git a/openflow/udatapath/chain.h b/openflow/udatapath/chain.h deleted file mode 100644 index fb4e9c37..00000000 --- a/openflow/udatapath/chain.h +++ /dev/null @@ -1,74 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#ifndef CHAIN_H -#define CHAIN_H 1 - -#include -#include - -struct sw_flow; -struct sw_flow_key; -struct ofp_action_header; -struct list; -struct datapath; - -#define TABLE_LINEAR_MAX_FLOWS 100 -#define TABLE_HASH_MAX_FLOWS 65536 -#define TABLE_MAC_MAX_FLOWS 1024 -#define TABLE_MAC_NUM_BUCKETS 1024 - -/* Set of tables chained together in sequence from cheap to expensive. */ -#define CHAIN_MAX_TABLES 4 -struct sw_chain { - int n_tables; /* Number of working tables, not includes - * protection (emergency) table. */ - struct sw_table *tables[CHAIN_MAX_TABLES]; - struct sw_table *emerg_table; - - struct datapath *dp; -}; - -struct sw_chain *chain_create(struct datapath *); -struct sw_flow *chain_lookup(struct sw_chain *, const struct sw_flow_key *, int); -int chain_insert(struct sw_chain *, struct sw_flow *, int); -int chain_modify(struct sw_chain *, const struct sw_flow_key *, - uint16_t, int, const struct ofp_action_header *, size_t, int); -int chain_has_conflict(struct sw_chain *, const struct sw_flow_key *, - uint16_t, int); -int chain_delete(struct sw_chain *, const struct sw_flow_key *, uint16_t, - uint16_t, int, int); -void chain_timeout(struct sw_chain *, struct list *deleted); -void chain_destroy(struct sw_chain *); - -#endif /* chain.h */ diff --git a/openflow/udatapath/crc32.c b/openflow/udatapath/crc32.c deleted file mode 100644 index f6c2c0b3..00000000 --- a/openflow/udatapath/crc32.c +++ /dev/null @@ -1,68 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include "crc32.h" - -void -crc32_init(struct crc32 *crc, unsigned int polynomial) -{ - int i; - - for (i = 0; i < CRC32_TABLE_SIZE; ++i) { - unsigned int reg = i << 24; - int j; - for (j = 0; j < CRC32_TABLE_BITS; j++) { - int topBit = (reg & 0x80000000) != 0; - reg <<= 1; - if (topBit) - reg ^= polynomial; - } - crc->table[i] = reg; - } -} - -unsigned int -crc32_calculate(const struct crc32 *crc, const void *data_, size_t n_bytes) -{ - const uint8_t *data = data_; - unsigned int result = 0; - size_t i; - - for (i = 0; i < n_bytes; i++) { - unsigned int top = result >> 24; - top ^= data[i]; - result = (result << 8) ^ crc->table[top]; - } - return result; -} diff --git a/openflow/udatapath/crc32.h b/openflow/udatapath/crc32.h deleted file mode 100644 index 355aefdf..00000000 --- a/openflow/udatapath/crc32.h +++ /dev/null @@ -1,50 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#ifndef CRC32_H -#define CRC32_H 1 - -#include -#include - -#define CRC32_TABLE_BITS 8 -#define CRC32_TABLE_SIZE (1u << CRC32_TABLE_BITS) - -struct crc32 { - unsigned int table[CRC32_TABLE_SIZE]; -}; - -void crc32_init(struct crc32 *, unsigned int polynomial); -unsigned int crc32_calculate(const struct crc32 *, const void *, size_t); - -#endif /* crc32.h */ diff --git a/openflow/udatapath/datapath.c b/openflow/udatapath/datapath.c deleted file mode 100644 index 5254b771..00000000 --- a/openflow/udatapath/datapath.c +++ /dev/null @@ -1,2375 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include "datapath.h" -#include -#include -#include -#include -#include -#include -#include -#include "chain.h" -#include "csum.h" -#include "flow.h" -#include "ofpbuf.h" -#include "openflow/openflow.h" -#include "openflow/nicira-ext.h" -#include "openflow/private-ext.h" -#include "openflow/openflow-ext.h" -#include "packets.h" -#include "poll-loop.h" -#include "rconn.h" -#include "stp.h" -#include "switch-flow.h" -#include "table.h" -#include "vconn.h" -#include "xtoxll.h" -#include "private-msg.h" -#include "of_ext_msg.h" -#include "dp_act.h" - -#define THIS_MODULE VLM_datapath -#include "vlog.h" - -#if defined(OF_HW_PLAT) -#include -#include -#endif - -#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) -/* Queue to decouple receive packet thread from rconn control thread */ -/* Could make mutex per-DP */ -static pthread_mutex_t pkt_q_mutex = PTHREAD_MUTEX_INITIALIZER; -#define PKT_Q_LOCK pthread_mutex_lock(&pkt_q_mutex) -#define PKT_Q_UNLOCK pthread_mutex_unlock(&pkt_q_mutex) - -static void -enqueue_pkt(struct datapath *dp, struct ofpbuf *buffer, of_port_t port_no, - int reason) -{ - struct hw_pkt_q_entry *q_entry; - - if ((q_entry = xmalloc(sizeof(*q_entry))) == NULL) { - VLOG_WARN("Could not alloc q entry\n"); - /* FIXME: Dealloc buffer */ - return; - } - q_entry->buffer = buffer; - q_entry->next = NULL; - q_entry->port_no = port_no; - q_entry->reason = reason; - pthread_mutex_lock(&pkt_q_mutex); - if (dp->hw_pkt_list_head == NULL) { - dp->hw_pkt_list_head = q_entry; - } else { - dp->hw_pkt_list_tail->next = q_entry; - } - dp->hw_pkt_list_tail = q_entry; - pthread_mutex_unlock(&pkt_q_mutex); -} - -/* If queue non-empty, fill out params and return 1; else return 0 */ -static int -dequeue_pkt(struct datapath *dp, struct ofpbuf **buffer, of_port_t *port_no, - int *reason) -{ - struct hw_pkt_q_entry *q_entry; - int rv = 0; - - pthread_mutex_lock(&pkt_q_mutex); - q_entry = dp->hw_pkt_list_head; - if (dp->hw_pkt_list_head != NULL) { - dp->hw_pkt_list_head = dp->hw_pkt_list_head->next; - if (dp->hw_pkt_list_head == NULL) { - dp->hw_pkt_list_tail = NULL; - } - } - pthread_mutex_unlock(&pkt_q_mutex); - - if (q_entry != NULL) { - rv = 1; - *buffer = q_entry->buffer; - *port_no = q_entry->port_no; - *reason = q_entry->reason; - free(q_entry); - } - - return rv; -} -#endif - -extern char mfr_desc; -extern char hw_desc; -extern char sw_desc; -extern char dp_desc; -extern char serial_num; - -/* Capabilities supported by this implementation. */ -#define OFP_SUPPORTED_CAPABILITIES ( OFPC_FLOW_STATS \ - | OFPC_TABLE_STATS \ - | OFPC_PORT_STATS \ - | OFPC_QUEUE_STATS \ - | OFPC_ARP_MATCH_IP ) - -/* Actions supported by this implementation. */ -#define OFP_SUPPORTED_ACTIONS ( (1 << OFPAT_OUTPUT) \ - | (1 << OFPAT_SET_VLAN_VID) \ - | (1 << OFPAT_SET_VLAN_PCP) \ - | (1 << OFPAT_STRIP_VLAN) \ - | (1 << OFPAT_SET_DL_SRC) \ - | (1 << OFPAT_SET_DL_DST) \ - | (1 << OFPAT_SET_NW_SRC) \ - | (1 << OFPAT_SET_NW_DST) \ - | (1 << OFPAT_SET_TP_SRC) \ - | (1 << OFPAT_SET_TP_DST) \ - | (1 << OFPAT_ENQUEUE)) - -/* The origin of a received OpenFlow message, to enable sending a reply. */ -struct sender { - struct remote *remote; /* The device that sent the message. */ - uint32_t xid; /* The OpenFlow transaction ID. */ -}; - -/* A connection to a secure channel. */ -struct remote { - struct list node; - struct rconn *rconn; -#define TXQ_LIMIT 128 /* Max number of packets to queue for tx. */ - int n_txq; /* Number of packets queued for tx on rconn. */ - - /* Support for reliable, multi-message replies to requests. - * - * If an incoming request needs to have a reliable reply that might - * require multiple messages, it can use remote_start_dump() to set up - * a callback that will be called as buffer space for replies. */ - int (*cb_dump)(struct datapath *, void *aux); - void (*cb_done)(void *aux); - void *cb_aux; -}; - -static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60); - -static struct remote *remote_create(struct datapath *, struct rconn *); -static void remote_run(struct datapath *, struct remote *); -static void remote_wait(struct remote *); -static void remote_destroy(struct remote *); - -static void update_port_flags(struct datapath *, const struct ofp_port_mod *); -static void send_port_status(struct sw_port *p, uint8_t status); - -/* Buffers are identified by a 31-bit opaque ID. We divide the ID - * into a buffer number (low bits) and a cookie (high bits). The buffer number - * is an index into an array of buffers. The cookie distinguishes between - * different packets that have occupied a single buffer. Thus, the more - * buffers we have, the lower-quality the cookie... */ -#define PKT_BUFFER_BITS 8 -#define N_PKT_BUFFERS (1 << PKT_BUFFER_BITS) -#define PKT_BUFFER_MASK (N_PKT_BUFFERS - 1) - -#define PKT_COOKIE_BITS (32 - PKT_BUFFER_BITS) - -int run_flow_through_tables(struct datapath *, struct ofpbuf *, - struct sw_port *); -void fwd_port_input(struct datapath *, struct ofpbuf *, struct sw_port *); -int fwd_control_input(struct datapath *, const struct sender *, - const void *, size_t); - -uint32_t save_buffer(struct ofpbuf *); -static struct ofpbuf *retrieve_buffer(uint32_t id); -static void discard_buffer(uint32_t id); - -struct sw_port * -dp_lookup_port(struct datapath *dp, uint16_t port_no) -{ - return (port_no < DP_MAX_PORTS ? &dp->ports[port_no] - : port_no == OFPP_LOCAL ? dp->local_port - : NULL); -} - -struct sw_queue * -dp_lookup_queue(struct sw_port *p, uint32_t queue_id) -{ - struct sw_queue *q; - - LIST_FOR_EACH(q, struct sw_queue, node, &p->queue_list) { - if ((q != NULL) && (q->queue_id == queue_id)) { - return q; - } - } - return NULL; -} - -/* Generates and returns a random datapath id. */ -static uint64_t -gen_datapath_id(void) -{ - uint8_t ea[ETH_ADDR_LEN]; - eth_addr_random(ea); - ea[0] = 0x00; /* Set Nicira OUI. */ - ea[1] = 0x23; - ea[2] = 0x20; - return eth_addr_to_uint64(ea); -} - -/* FIXME: Should not depend on udatapath_as_lib */ -#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) && defined(UDATAPATH_AS_LIB) -/* - * Receive packet handling for hardware driver controlled ports - * - * FIXME: For now, call the pkt fwding directly; eventually may - * want to enqueue packets at this layer; at that point must - * make sure poll event is registered or timer kicked - */ -static int -hw_packet_in(of_port_t port_no, of_packet_t *packet, int reason, - void *cookie) -{ - struct sw_port *port; - struct ofpbuf *buffer = NULL; - struct datapath *dp = (struct datapath *)cookie; - const int headroom = 128 + 2; - const int hard_header = VLAN_ETH_HEADER_LEN; - const int tail_room = sizeof(uint32_t); /* For crc if needed later */ - - VLOG_INFO("dp rcv packet on port %d, size %d\n", - port_no, packet->length); - if ((port_no < 1) || port_no > DP_MAX_PORTS) { - VLOG_ERR("Bad receive port %d\n", port_no); - /* TODO increment error counter */ - return -1; - } - port = &dp->ports[port_no]; - if (!PORT_IN_USE(port)) { - VLOG_WARN("Receive port not active: %d\n", port_no); - return -1; - } - if (!IS_HW_PORT(port)) { - VLOG_ERR("Receive port not controlled by HW: %d\n", port_no); - return -1; - } - /* Note: We're really not counting these for port stats as they - * should be gotten directly from the HW */ - port->rx_packets++; - port->rx_bytes += packet->length; - /* For now, copy data into OFP buffer; eventually may steal packet - * from RX to avoid copy. As per dp_run, add headroom and offset bytes. - */ - buffer = ofpbuf_new(headroom + hard_header + packet->length + tail_room); - if (buffer == NULL) { - VLOG_WARN("Could not alloc ofpbuf on hw pkt in\n"); - fprintf(stderr, "Could not alloc ofpbuf on hw pkt in\n"); - } else { - buffer->data = (char*)buffer->data + headroom; - buffer->size = packet->length; - memcpy(buffer->data, packet->data, packet->length); - enqueue_pkt(dp, buffer, port_no, reason); - poll_immediate_wake(); - } - - return 0; -} -#endif - -#if defined(OF_HW_PLAT) -static int -dp_hw_drv_init(struct datapath *dp) -{ - dp->hw_pkt_list_head = NULL; - dp->hw_pkt_list_tail = NULL; - - dp->hw_drv = new_of_hw_driver(dp); - if (dp->hw_drv == NULL) { - VLOG_ERR("Could not create HW driver"); - return -1; - } -#if !defined(USE_NETDEV) - if (dp->hw_drv->packet_receive_register(dp->hw_drv, - hw_packet_in, dp) < 0) { - VLOG_ERR("Could not register with HW driver to receive pkts"); - } -#endif - - return 0; -} - -#endif - -int -dp_new(struct datapath **dp_, uint64_t dpid) -{ - struct datapath *dp; - - dp = calloc(1, sizeof *dp); - if (!dp) { - return ENOMEM; - } - - dp->last_timeout = time_now(); - list_init(&dp->remotes); - dp->listeners = NULL; - dp->n_listeners = 0; - dp->id = dpid <= UINT64_C(0xffffffffffff) ? dpid : gen_datapath_id(); -/* FIXME: Should not depend on udatapath_as_lib */ -#if defined(OF_HW_PLAT) && (defined(UDATAPATH_AS_LIB) || defined(USE_NETDEV)) - dp_hw_drv_init(dp); -#endif - dp->chain = chain_create(dp); - if (!dp->chain) { - VLOG_ERR("could not create chain"); - free(dp); - return ENOMEM; - } - - list_init(&dp->port_list); - dp->flags = 0; - dp->miss_send_len = OFP_DEFAULT_MISS_SEND_LEN; - - if(strlen(&dp_desc) > 0) /* use the comment, if specified */ - strncpy(dp->dp_desc, &dp_desc, sizeof dp->dp_desc); - else /* else, just use "$HOSTNAME pid=$$" */ - { - char hostnametmp[DESC_STR_LEN]; - gethostname(hostnametmp,sizeof hostnametmp); - snprintf(dp->dp_desc, sizeof dp->dp_desc,"%s pid=%u",hostnametmp, getpid()); - } - - *dp_ = dp; - return 0; -} - -static int -new_port(struct datapath *dp, struct sw_port *port, uint16_t port_no, - const char *netdev_name, const uint8_t *new_mac, uint16_t num_queues) -{ - struct netdev *netdev; - struct in6_addr in6; - struct in_addr in4; - int error; - - error = netdev_open(netdev_name, NETDEV_ETH_TYPE_ANY, &netdev); - if (error) { - return error; - } - if (new_mac && !eth_addr_equals(netdev_get_etheraddr(netdev), new_mac)) { - /* Generally the device has to be down before we change its hardware - * address. Don't bother to check for an error because it's really - * the netdev_set_etheraddr() call below that we care about. */ - netdev_set_flags(netdev, 0, false); - error = netdev_set_etheraddr(netdev, new_mac); - if (error) { - VLOG_WARN("failed to change %s Ethernet address " - "to "ETH_ADDR_FMT": %s", - netdev_name, ETH_ADDR_ARGS(new_mac), strerror(error)); - } - } - error = netdev_set_flags(netdev, NETDEV_UP | NETDEV_PROMISC, false); - if (error) { - VLOG_ERR("failed to set promiscuous mode on %s device", netdev_name); - netdev_close(netdev); - return error; - } - if (netdev_get_in4(netdev, &in4)) { - VLOG_ERR("%s device has assigned IP address %s", - netdev_name, inet_ntoa(in4)); - } - if (netdev_get_in6(netdev, &in6)) { - char in6_name[INET6_ADDRSTRLEN + 1]; - inet_ntop(AF_INET6, &in6, in6_name, sizeof in6_name); - VLOG_ERR("%s device has assigned IPv6 address %s", - netdev_name, in6_name); - } - - if (num_queues > 0) { - error = netdev_setup_slicing(netdev, num_queues); - if (error) { - VLOG_ERR("failed to configure slicing on %s device: "\ - "check INSTALL for dependencies, or rerun "\ - "using --no-slicing option to disable slicing", - netdev_name); - netdev_close(netdev); - return error; - } - } - - memset(port, '\0', sizeof *port); - - list_init(&port->queue_list); - port->dp = dp; - port->flags |= SWP_USED; - port->netdev = netdev; - port->port_no = port_no; - port->num_queues = num_queues; - list_push_back(&dp->port_list, &port->node); - - /* Notify the ctlpath that this port has been added */ - send_port_status(port, OFPPR_ADD); - - return 0; -} - -#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) -int -dp_add_port(struct datapath *dp, const char *port_name, uint16_t num_queues) -{ - int port_no; - int rc = 0; - struct sw_port *port; - - fprintf(stderr, "Adding port %s. hw_drv is %p\n", port_name, dp->hw_drv); - if (dp->hw_drv && dp->hw_drv->port_add) { - port_no = dp->hw_drv->port_add(dp->hw_drv, -1, port_name); - if (port_no >= 0) { - port = &dp->ports[port_no]; - if (port->flags & SWP_USED) { - VLOG_ERR("HW port %s (%d) already created\n", - port_name, port_no); - rc = -1; - } else { - fprintf(stderr, "Adding HW port %s as OF port number %d\n", - port_name, port_no); - /* FIXME: Determine and record HW addr, etc */ - port->flags |= SWP_USED | SWP_HW_DRV_PORT; - port->dp = dp; - port->port_no = port_no; - list_init(&port->queue_list); - port->num_queues = num_queues; - strncpy(port->hw_name, port_name, sizeof(port->hw_name)); - list_push_back(&dp->port_list, &port->node); - send_port_status(port, OFPPR_ADD); - } - } else { - VLOG_ERR("Port %s not recognized by hardware driver", port_name); - rc = -1; - } - } else { - VLOG_ERR("No hardware driver support; can't add ports"); - rc = -1; - } - - return rc; -} -#else /* Not HW platform support */ -int -dp_add_port(struct datapath *dp, const char *netdev, uint16_t num_queues) -{ - int port_no; - for (port_no = 1; port_no < DP_MAX_PORTS; port_no++) { - struct sw_port *port = &dp->ports[port_no]; - if (!port->netdev) { - return new_port(dp, port, port_no, netdev, NULL, num_queues); - } - } - return EXFULL; -} -#endif /* OF_HW_PLAT */ - -int -dp_add_local_port(struct datapath *dp, const char *netdev, uint16_t num_queues) -{ - if (!dp->local_port) { - uint8_t ea[ETH_ADDR_LEN]; - struct sw_port *port; - int error; - - port = xcalloc(1, sizeof *port); - eth_addr_from_uint64(dp->id, ea); - error = new_port(dp, port, OFPP_LOCAL, netdev, ea, num_queues); - if (!error) { - dp->local_port = port; - } else { - free(port); - } - return error; - } else { - return EXFULL; - } -} - -void -dp_add_pvconn(struct datapath *dp, struct pvconn *pvconn) -{ - dp->listeners = xrealloc(dp->listeners, - sizeof *dp->listeners * (dp->n_listeners + 1)); - dp->listeners[dp->n_listeners++] = pvconn; -} - -void -dp_run(struct datapath *dp) -{ - time_t now = time_now(); - struct sw_port *p, *pn; - struct remote *r, *rn; - struct ofpbuf *buffer = NULL; - size_t i; - - if (now != dp->last_timeout) { - struct list deleted = LIST_INITIALIZER(&deleted); - struct sw_flow *f, *n; - - chain_timeout(dp->chain, &deleted); - LIST_FOR_EACH_SAFE (f, n, struct sw_flow, node, &deleted) { - dp_send_flow_end(dp, f, f->reason); - list_remove(&f->node); - flow_free(f); - } - dp->last_timeout = now; - } - poll_timer_wait(1000); - -#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) - { /* Process packets received from callback thread */ - struct ofpbuf *buffer; - of_port_t port_no; - int reason; - struct sw_port *p; - - while (dequeue_pkt(dp, &buffer, &port_no, &reason)) { - p = dp_lookup_port(dp, port_no); - /* FIXME: We're throwing away the reason that came from HW */ - fwd_port_input(dp, buffer, p); - } - } -#endif - - LIST_FOR_EACH_SAFE (p, pn, struct sw_port, node, &dp->port_list) { - int error; - - if (IS_HW_PORT(p)) { - continue; - } - if (!buffer) { - /* Allocate buffer with some headroom to add headers in forwarding - * to the controller or adding a vlan tag, plus an extra 2 bytes to - * allow IP headers to be aligned on a 4-byte boundary. */ - const int headroom = 128 + 2; - const int hard_header = VLAN_ETH_HEADER_LEN; - const int mtu = netdev_get_mtu(p->netdev); - buffer = ofpbuf_new(headroom + hard_header + mtu); - buffer->data = (char*)buffer->data + headroom; - } - error = netdev_recv(p->netdev, buffer); - if (!error) { - p->rx_packets++; - p->rx_bytes += buffer->size; - fwd_port_input(dp, buffer, p); - buffer = NULL; - } else if (error != EAGAIN) { - VLOG_ERR_RL(&rl, "error receiving data from %s: %s", - netdev_get_name(p->netdev), strerror(error)); - } - } - ofpbuf_delete(buffer); - - /* Talk to remotes. */ - LIST_FOR_EACH_SAFE (r, rn, struct remote, node, &dp->remotes) { - remote_run(dp, r); - } - - for (i = 0; i < dp->n_listeners; ) { - struct pvconn *pvconn = dp->listeners[i]; - struct vconn *new_vconn; - int retval = pvconn_accept(pvconn, OFP_VERSION, &new_vconn); - if (!retval) { - remote_create(dp, rconn_new_from_vconn("passive", new_vconn)); - } else if (retval != EAGAIN) { - VLOG_WARN_RL(&rl, "accept failed (%s)", strerror(retval)); - dp->listeners[i] = dp->listeners[--dp->n_listeners]; - continue; - } - i++; - } -} - -static void -remote_run(struct datapath *dp, struct remote *r) -{ - int i; - - rconn_run(r->rconn); - - /* Do some remote processing, but cap it at a reasonable amount so that - * other processing doesn't starve. */ - for (i = 0; i < 50; i++) { - if (!r->cb_dump) { - struct ofpbuf *buffer; - struct ofp_header *oh; - - buffer = rconn_recv(r->rconn); - if (!buffer) { - break; - } - - if (buffer->size >= sizeof *oh) { - struct sender sender; - - oh = (struct ofp_header *)buffer->data; - sender.remote = r; - sender.xid = oh->xid; - fwd_control_input(dp, &sender, buffer->data, buffer->size); - } else { - VLOG_WARN_RL(&rl, "received too-short OpenFlow message"); - } - ofpbuf_delete(buffer); - } else { - if (r->n_txq < TXQ_LIMIT) { - int error = r->cb_dump(dp, r->cb_aux); - if (error <= 0) { - if (error) { - VLOG_WARN_RL(&rl, "dump callback error: %s", - strerror(-error)); - } - r->cb_done(r->cb_aux); - r->cb_dump = NULL; - } - } else { - break; - } - } - } - - if (!rconn_is_alive(r->rconn)) { - remote_destroy(r); - } -} - -static void -remote_wait(struct remote *r) -{ - rconn_run_wait(r->rconn); - rconn_recv_wait(r->rconn); -} - -static void -remote_destroy(struct remote *r) -{ - if (r) { - if (r->cb_dump && r->cb_done) { - r->cb_done(r->cb_aux); - } - list_remove(&r->node); - rconn_destroy(r->rconn); - free(r); - } -} - -static struct remote * -remote_create(struct datapath *dp, struct rconn *rconn) -{ - struct remote *remote = xmalloc(sizeof *remote); - list_push_back(&dp->remotes, &remote->node); - remote->rconn = rconn; - remote->cb_dump = NULL; - remote->n_txq = 0; - return remote; -} - -/* Starts a callback-based, reliable, possibly multi-message reply to a - * request made by 'remote'. - * - * 'dump' designates a function that will be called when the 'remote' send - * queue has an empty slot. It should compose a message and send it on - * 'remote'. On success, it should return 1 if it should be called again when - * another send queue slot opens up, 0 if its transmissions are complete, or a - * negative errno value on failure. - * - * 'done' designates a function to clean up any resources allocated for the - * dump. It must handle being called before the dump is complete (which will - * happen if 'remote' is closed unexpectedly). - * - * 'aux' is passed to 'dump' and 'done'. */ -static void -remote_start_dump(struct remote *remote, - int (*dump)(struct datapath *, void *), - void (*done)(void *), - void *aux) -{ - assert(!remote->cb_dump); - remote->cb_dump = dump; - remote->cb_done = done; - remote->cb_aux = aux; -} - -void -dp_wait(struct datapath *dp) -{ - struct sw_port *p; - struct remote *r; - size_t i; - - LIST_FOR_EACH (p, struct sw_port, node, &dp->port_list) { - if (IS_HW_PORT(p)) { - continue; - } - netdev_recv_wait(p->netdev); - } - LIST_FOR_EACH (r, struct remote, node, &dp->remotes) { - remote_wait(r); - } - for (i = 0; i < dp->n_listeners; i++) { - pvconn_wait(dp->listeners[i]); - } -} - -/* Send packets out all the ports except the originating one. If the - * "flood" argument is set, don't send out ports with flooding disabled. - */ -static int -output_all(struct datapath *dp, struct ofpbuf *buffer, int in_port, int flood) -{ - struct sw_port *p; - int prev_port; /* Buffer is cloned for multiple transmits */ - - prev_port = -1; - LIST_FOR_EACH (p, struct sw_port, node, &dp->port_list) { - if (p->port_no == in_port) { - continue; - } - if (flood && p->config & OFPPC_NO_FLOOD) { - continue; - } - if (prev_port != -1) { - dp_output_port(dp, ofpbuf_clone(buffer), in_port, prev_port, - 0,false); - } - prev_port = p->port_no; - } - if (prev_port != -1) - dp_output_port(dp, buffer, in_port, prev_port, 0, false); - else - ofpbuf_delete(buffer); - - return 0; -} - -static void -output_packet(struct datapath *dp, struct ofpbuf *buffer, uint16_t out_port, - uint32_t queue_id) -{ - uint16_t class_id; - struct sw_queue * q; - struct sw_port *p; - - q = NULL; - p = dp_lookup_port(dp, out_port); - -/* FIXME: Needs update for queuing */ -#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) - if ((p != NULL) && IS_HW_PORT(p)) { - if (dp && dp->hw_drv) { - if (dp->hw_drv->port_link_get(dp->hw_drv, p->port_no)) { - of_packet_t *pkt; - int rv; - - pkt = calloc(1, sizeof(*pkt)); - OF_PKT_INIT(pkt, buffer); - rv = dp->hw_drv->packet_send(dp->hw_drv, out_port, pkt, 0); - if ((rv < 0) && (rv != OF_HW_PORT_DOWN)) { - VLOG_ERR("Error %d sending pkt on HW port %d\n", - rv, out_port); - ofpbuf_delete(buffer); - free(pkt); - } - } - } - return; - } - - /* Fall through to software controlled ports if not HW port */ -#endif - - if (p && p->netdev != NULL) { - if (!(p->config & OFPPC_PORT_DOWN)) { - /* avoid the queue lookup for best-effort traffic */ - if (queue_id == 0) { - class_id = 0; - } - else { - /* silently drop the packet if queue doesn't exist */ - q = dp_lookup_queue(p, queue_id); - if (q) { - class_id = q->class_id; - } - else { - goto error; - } - } - - if (!netdev_send(p->netdev, buffer, class_id)) { - p->tx_packets++; - p->tx_bytes += buffer->size; - if (q) { - q->tx_packets++; - q->tx_bytes += buffer->size; - } - } else { - p->tx_dropped++; - } - } - ofpbuf_delete(buffer); - return; - } - - error: - ofpbuf_delete(buffer); - VLOG_DBG_RL(&rl, "can't forward to bad port:queue(%d:%d)\n", out_port, - queue_id); -} - -/** Takes ownership of 'buffer' and transmits it to 'out_port' on 'dp'. - */ -void -dp_output_port(struct datapath *dp, struct ofpbuf *buffer, - int in_port, int out_port, uint32_t queue_id, - bool ignore_no_fwd UNUSED) -{ - - assert(buffer); - switch (out_port) { - case OFPP_IN_PORT: - output_packet(dp, buffer, in_port, queue_id); - break; - - case OFPP_TABLE: { - struct sw_port *p = dp_lookup_port(dp, in_port); - if (run_flow_through_tables(dp, buffer, p)) { - ofpbuf_delete(buffer); - } - break; - } - - case OFPP_FLOOD: - output_all(dp, buffer, in_port, 1); - break; - - case OFPP_ALL: - output_all(dp, buffer, in_port, 0); - break; - - case OFPP_CONTROLLER: - dp_output_control(dp, buffer, in_port, UINT16_MAX, OFPR_ACTION); - break; - - case OFPP_LOCAL: - default: - if (in_port == out_port) { - VLOG_DBG_RL(&rl, "can't directly forward to input port"); - return; - } - output_packet(dp, buffer, out_port, queue_id); - break; - } -} - -static void * -make_openflow_reply(size_t openflow_len, uint8_t type, - const struct sender *sender, struct ofpbuf **bufferp) -{ - return make_openflow_xid(openflow_len, type, sender ? sender->xid : 0, - bufferp); -} - -static int -send_openflow_buffer_to_remote(struct ofpbuf *buffer, struct remote *remote) -{ - int retval = rconn_send_with_limit(remote->rconn, buffer, &remote->n_txq, - TXQ_LIMIT); - if (retval) { - VLOG_WARN_RL(&rl, "send to %s failed: %s", - rconn_get_name(remote->rconn), strerror(retval)); - } - return retval; -} - -static int -send_openflow_buffer(struct datapath *dp, struct ofpbuf *buffer, - const struct sender *sender) -{ - update_openflow_length(buffer); - if (sender) { - /* Send back to the sender. */ - return send_openflow_buffer_to_remote(buffer, sender->remote); - } else { - /* Broadcast to all remotes. */ - struct remote *r, *prev = NULL; - LIST_FOR_EACH (r, struct remote, node, &dp->remotes) { - if (prev) { - send_openflow_buffer_to_remote(ofpbuf_clone(buffer), prev); - } - prev = r; - } - if (prev) { - send_openflow_buffer_to_remote(buffer, prev); - } else { - ofpbuf_delete(buffer); - } - return 0; - } -} - -/* Takes ownership of 'buffer' and transmits it to 'dp''s controller. If the - * packet can be saved in a buffer, then only the first max_len bytes of - * 'buffer' are sent; otherwise, all of 'buffer' is sent. 'reason' indicates - * why 'buffer' is being sent. 'max_len' sets the maximum number of bytes that - * the caller wants to be sent. */ -void -dp_output_control(struct datapath *dp, struct ofpbuf *buffer, int in_port, - size_t max_len, int reason) -{ - struct ofp_packet_in *opi; - size_t total_len; - uint32_t buffer_id; - - buffer_id = save_buffer(buffer); - total_len = buffer->size; - if (buffer_id != UINT32_MAX && buffer->size > max_len) { - buffer->size = max_len; - } - - opi = ofpbuf_push_uninit(buffer, offsetof(struct ofp_packet_in, data)); - opi->header.version = OFP_VERSION; - opi->header.type = OFPT_PACKET_IN; - opi->header.length = htons(buffer->size); - opi->header.xid = htonl(0); - opi->buffer_id = htonl(buffer_id); - opi->total_len = htons(total_len); - opi->in_port = htons(in_port); - opi->reason = reason; - opi->pad = 0; - send_openflow_buffer(dp, buffer, NULL); -} - -static void -fill_queue_desc(struct ofpbuf *buffer, struct sw_queue *q, - struct ofp_packet_queue *desc) -{ - struct ofp_queue_prop_min_rate *mr; - int len; - - len = sizeof(struct ofp_packet_queue) + - sizeof(struct ofp_queue_prop_min_rate); - desc->queue_id = htonl(q->queue_id); - desc->len = htons(len); - - /* Property list */ - mr = ofpbuf_put_zeros(buffer, sizeof *mr); - mr->prop_header.property = htons(OFPQT_MIN_RATE); - len = sizeof(struct ofp_queue_prop_min_rate); - mr->prop_header.len = htons(len); - mr->rate = htons(q->min_rate); -} - - -static void -fill_port_desc(struct sw_port *p, struct ofp_phy_port *desc) -{ - desc->port_no = htons(p->port_no); - if (IS_HW_PORT(p)) { -#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) - of_hw_driver_t *hw_drv; - - hw_drv = p->dp->hw_drv; - strncpy((char *) desc->name, p->hw_name, sizeof desc->name); - desc->name[sizeof desc->name - 1] = '\0'; - /* Update local port state */ - if (hw_drv->port_link_get(hw_drv, p->port_no)) { - p->state &= ~OFPPS_LINK_DOWN; - } else { - p->state |= OFPPS_LINK_DOWN; - } - if (hw_drv->port_enable_get(hw_drv, p->port_no)) { - p->config &= ~OFPPC_PORT_DOWN; - } else { - p->config |= OFPPC_PORT_DOWN; - } - /* FIXME: Add current, supported and advertised features */ -#endif - } else if (p->netdev) { - strncpy((char *) desc->name, netdev_get_name(p->netdev), - sizeof desc->name); - desc->name[sizeof desc->name - 1] = '\0'; - memcpy(desc->hw_addr, netdev_get_etheraddr(p->netdev), ETH_ADDR_LEN); - desc->curr= htonl(netdev_get_features(p->netdev, - NETDEV_FEAT_CURRENT)); - desc->supported = htonl(netdev_get_features(p->netdev, - NETDEV_FEAT_SUPPORTED)); - desc->advertised = htonl(netdev_get_features(p->netdev, - NETDEV_FEAT_ADVERTISED)); - desc->peer = htonl(netdev_get_features(p->netdev, NETDEV_FEAT_PEER)); - } - desc->config = htonl(p->config); - desc->state = htonl(p->state); -} - -static void -dp_send_features_reply(struct datapath *dp, const struct sender *sender) -{ - struct ofpbuf *buffer; - struct ofp_switch_features *ofr; - struct sw_port *p; - - ofr = make_openflow_reply(sizeof *ofr, OFPT_FEATURES_REPLY, - sender, &buffer); - ofr->datapath_id = htonll(dp->id); - ofr->n_tables = dp->chain->n_tables; - ofr->n_buffers = htonl(N_PKT_BUFFERS); - ofr->capabilities = htonl(OFP_SUPPORTED_CAPABILITIES); - ofr->actions = htonl(OFP_SUPPORTED_ACTIONS); - LIST_FOR_EACH (p, struct sw_port, node, &dp->port_list) { - struct ofp_phy_port *opp = ofpbuf_put_uninit(buffer, sizeof *opp); - memset(opp, 0, sizeof *opp); - fill_port_desc(p, opp); - } - send_openflow_buffer(dp, buffer, sender); -} - -void -update_port_flags(struct datapath *dp, const struct ofp_port_mod *opm) -{ - struct sw_port *p = dp_lookup_port(dp, ntohs(opm->port_no)); - - /* Make sure the port id hasn't changed since this was sent */ - if (!p || memcmp(opm->hw_addr, netdev_get_etheraddr(p->netdev), - ETH_ADDR_LEN) != 0) { - return; - } - - - if (opm->mask) { - uint32_t config_mask = ntohl(opm->mask); - p->config &= ~config_mask; - p->config |= ntohl(opm->config) & config_mask; - } -} - -static void -send_port_status(struct sw_port *p, uint8_t status) -{ - struct ofpbuf *buffer; - struct ofp_port_status *ops; - ops = make_openflow_xid(sizeof *ops, OFPT_PORT_STATUS, 0, &buffer); - ops->reason = status; - memset(ops->pad, 0, sizeof ops->pad); - fill_port_desc(p, &ops->desc); - - send_openflow_buffer(p->dp, buffer, NULL); -} - -void -dp_send_flow_end(struct datapath *dp, struct sw_flow *flow, - enum ofp_flow_removed_reason reason) -{ - struct ofpbuf *buffer; - struct ofp_flow_removed *ofr; - uint64_t tdiff = time_msec() - flow->created; - uint32_t sec = tdiff / 1000; - - if (!flow->send_flow_rem) { - return; - } - - if (flow->emerg_flow) { - return; - } - - ofr = make_openflow_xid(sizeof *ofr, OFPT_FLOW_REMOVED, 0, &buffer); - if (!ofr) { - return; - } - - flow_fill_match(&ofr->match, &flow->key.flow, flow->key.wildcards); - - ofr->cookie = htonll(flow->cookie); - ofr->priority = htons(flow->priority); - ofr->reason = reason; - - ofr->duration_sec = htonl(sec); - ofr->duration_nsec = htonl((tdiff - (sec * 1000)) * 1000000); - ofr->idle_timeout = htons(flow->idle_timeout); - - ofr->packet_count = htonll(flow->packet_count); - ofr->byte_count = htonll(flow->byte_count); - - send_openflow_buffer(dp, buffer, NULL); -} - -void -dp_send_error_msg(struct datapath *dp, const struct sender *sender, - uint16_t type, uint16_t code, const void *data, size_t len) -{ - struct ofpbuf *buffer; - struct ofp_error_msg *oem; - oem = make_openflow_reply(sizeof(*oem)+len, OFPT_ERROR, sender, &buffer); - oem->type = htons(type); - oem->code = htons(code); - memcpy(oem->data, data, len); - send_openflow_buffer(dp, buffer, sender); -} - -static void -fill_flow_stats(struct ofpbuf *buffer, struct sw_flow *flow, - int table_idx, uint64_t now) -{ - struct ofp_flow_stats *ofs; - int length = sizeof *ofs + flow->sf_acts->actions_len; - uint64_t tdiff = now - flow->created; - uint32_t sec = tdiff / 1000; - ofs = ofpbuf_put_uninit(buffer, length); - ofs->length = htons(length); - ofs->table_id = table_idx; - ofs->pad = 0; - ofs->match.wildcards = htonl(flow->key.wildcards); - ofs->match.in_port = flow->key.flow.in_port; - memcpy(ofs->match.dl_src, flow->key.flow.dl_src, ETH_ADDR_LEN); - memcpy(ofs->match.dl_dst, flow->key.flow.dl_dst, ETH_ADDR_LEN); - ofs->match.dl_vlan = flow->key.flow.dl_vlan; - ofs->match.dl_type = flow->key.flow.dl_type; - ofs->match.nw_tos = flow->key.flow.nw_tos; - ofs->match.nw_src = flow->key.flow.nw_src; - ofs->match.nw_dst = flow->key.flow.nw_dst; - ofs->match.nw_proto = flow->key.flow.nw_proto; - ofs->match.dl_vlan_pcp = flow->key.flow.dl_vlan_pcp; - ofs->match.tp_src = flow->key.flow.tp_src; - ofs->match.tp_dst = flow->key.flow.tp_dst; - ofs->duration_sec = htonl(sec); - ofs->duration_nsec = htonl((tdiff - (sec * 1000)) * 1000000); - ofs->cookie = htonll(flow->cookie); - ofs->priority = htons(flow->priority); - ofs->idle_timeout = htons(flow->idle_timeout); - ofs->hard_timeout = htons(flow->hard_timeout); - memset(&ofs->pad2, 0, sizeof ofs->pad2); - ofs->packet_count = htonll(flow->packet_count); - ofs->byte_count = htonll(flow->byte_count); - memcpy(ofs->actions, flow->sf_acts->actions, flow->sf_acts->actions_len); -} - - -/* 'buffer' was received on 'p', which may be a a physical switch port or a - * null pointer. Process it according to 'dp''s flow table. Returns 0 if - * successful, in which case 'buffer' is destroyed, or -ESRCH if there is no - * matching flow, in which case 'buffer' still belongs to the caller. */ -int run_flow_through_tables(struct datapath *dp, struct ofpbuf *buffer, - struct sw_port *p) -{ - struct sw_flow_key key; - struct sw_flow *flow; - - key.wildcards = 0; - if (flow_extract(buffer, p ? p->port_no : OFPP_NONE, &key.flow) - && (dp->flags & OFPC_FRAG_MASK) == OFPC_FRAG_DROP) { - /* Drop fragment. */ - ofpbuf_delete(buffer); - return 0; - } - - if (p && p->config & (OFPPC_NO_RECV | OFPPC_NO_RECV_STP) - && p->config & (!eth_addr_equals(key.flow.dl_dst, stp_eth_addr) - ? OFPPC_NO_RECV : OFPPC_NO_RECV_STP)) { - ofpbuf_delete(buffer); - return 0; - } - - flow = chain_lookup(dp->chain, &key, 0); - if (flow != NULL) { - flow_used(flow, buffer); - execute_actions(dp, buffer, &key, flow->sf_acts->actions, - flow->sf_acts->actions_len, false); - return 0; - } else { - return -ESRCH; - } -} - -/* 'buffer' was received on 'p', which may be a a physical switch port or a - * null pointer. Process it according to 'dp''s flow table, sending it up to - * the controller if no flow matches. Takes ownership of 'buffer'. */ -void fwd_port_input(struct datapath *dp, struct ofpbuf *buffer, - struct sw_port *p) -{ - if (run_flow_through_tables(dp, buffer, p)) { - dp_output_control(dp, buffer, p->port_no, - dp->miss_send_len, OFPR_NO_MATCH); - } -} - -static struct ofpbuf * -make_barrier_reply(const struct ofp_header *req) -{ - size_t size = ntohs(req->length); - struct ofpbuf *buf = ofpbuf_new(size); - struct ofp_header *reply = ofpbuf_put(buf, req, size); - - reply->type = OFPT_BARRIER_REPLY; - return buf; -} - -static int -recv_barrier_request(struct datapath *dp, const struct sender *sender, - const void *ofph) -{ - return send_openflow_buffer(dp, make_barrier_reply(ofph), sender); -} - -static int -recv_features_request(struct datapath *dp, const struct sender *sender, - const void *msg UNUSED) -{ - dp_send_features_reply(dp, sender); - return 0; -} - -static int -recv_get_config_request(struct datapath *dp, const struct sender *sender, - const void *msg UNUSED) -{ - struct ofpbuf *buffer; - struct ofp_switch_config *osc; - - osc = make_openflow_reply(sizeof *osc, OFPT_GET_CONFIG_REPLY, - sender, &buffer); - - osc->flags = htons(dp->flags); - osc->miss_send_len = htons(dp->miss_send_len); - - return send_openflow_buffer(dp, buffer, sender); -} - -static int -recv_set_config(struct datapath *dp, const struct sender *sender UNUSED, - const void *msg) -{ - const struct ofp_switch_config *osc = msg; - int flags; - - flags = ntohs(osc->flags) & OFPC_FRAG_MASK; - if ((flags & OFPC_FRAG_MASK) != OFPC_FRAG_NORMAL - && (flags & OFPC_FRAG_MASK) != OFPC_FRAG_DROP) { - flags = (flags & ~OFPC_FRAG_MASK) | OFPC_FRAG_DROP; - } - dp->flags = flags; - dp->miss_send_len = ntohs(osc->miss_send_len); - return 0; -} - -static int -recv_packet_out(struct datapath *dp, const struct sender *sender, - const void *msg) -{ - const struct ofp_packet_out *opo = msg; - struct sw_flow_key key; - uint16_t v_code; - struct ofpbuf *buffer; - size_t actions_len = ntohs(opo->actions_len); - - if (actions_len > (ntohs(opo->header.length) - sizeof *opo)) { - VLOG_DBG_RL(&rl, "message too short for number of actions"); - return -EINVAL; - } - - if (ntohl(opo->buffer_id) == (uint32_t) -1) { - /* FIXME: can we avoid copying data here? */ - int data_len = ntohs(opo->header.length) - sizeof *opo - actions_len; - buffer = ofpbuf_new(data_len); - ofpbuf_put(buffer, (uint8_t *)opo->actions + actions_len, data_len); - } else { - buffer = retrieve_buffer(ntohl(opo->buffer_id)); - if (!buffer) { - return -ESRCH; - } - } - - flow_extract(buffer, ntohs(opo->in_port), &key.flow); - - v_code = validate_actions(dp, &key, opo->actions, actions_len); - if (v_code != ACT_VALIDATION_OK) { - dp_send_error_msg(dp, sender, OFPET_BAD_ACTION, v_code, - msg, ntohs(opo->header.length)); - goto error; - } - - execute_actions(dp, buffer, &key, opo->actions, actions_len, true); - - return 0; - -error: - ofpbuf_delete(buffer); - return -EINVAL; -} - -static int -recv_port_mod(struct datapath *dp, const struct sender *sender UNUSED, - const void *msg) -{ - const struct ofp_port_mod *opm = msg; - - update_port_flags(dp, opm); - - return 0; -} - -static int -add_flow(struct datapath *dp, const struct sender *sender, - const struct ofp_flow_mod *ofm) -{ - int error = -ENOMEM; - uint16_t v_code; - struct sw_flow *flow; - size_t actions_len = ntohs(ofm->header.length) - sizeof *ofm; - int overlap; - - /* Allocate memory. */ - flow = flow_alloc(actions_len); - if (flow == NULL) - goto error; - - flow_extract_match(&flow->key, &ofm->match); - - v_code = validate_actions(dp, &flow->key, ofm->actions, actions_len); - if (v_code != ACT_VALIDATION_OK) { - dp_send_error_msg(dp, sender, OFPET_BAD_ACTION, v_code, - ofm, ntohs(ofm->header.length)); - goto error_free_flow; - } - - flow->priority = flow->key.wildcards ? ntohs(ofm->priority) : -1; - - if (ntohs(ofm->flags) & OFPFF_CHECK_OVERLAP) { - /* check whether there is any conflict */ - overlap = chain_has_conflict(dp->chain, &flow->key, flow->priority, - false); - if (overlap){ - dp_send_error_msg(dp, sender, OFPET_FLOW_MOD_FAILED, - OFPFMFC_OVERLAP, ofm, ntohs(ofm->header.length)); - goto error_free_flow; - } - } - - if (ntohs(ofm->flags) & OFPFF_EMERG) { - if (ntohs(ofm->idle_timeout) != OFP_FLOW_PERMANENT - || ntohs(ofm->hard_timeout) != OFP_FLOW_PERMANENT) { - dp_send_error_msg(dp, sender, OFPET_FLOW_MOD_FAILED, - OFPFMFC_BAD_EMERG_TIMEOUT, ofm, - ntohs(ofm->header.length)); - goto error_free_flow; - } - } - - /* Fill out flow. */ - flow->cookie = ntohll(ofm->cookie); - flow->idle_timeout = ntohs(ofm->idle_timeout); - flow->hard_timeout = ntohs(ofm->hard_timeout); - flow->send_flow_rem = (ntohs(ofm->flags) & OFPFF_SEND_FLOW_REM) ? 1 : 0; - flow->emerg_flow = (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0; - flow_setup_actions(flow, ofm->actions, actions_len); - - /* Act. */ - error = chain_insert(dp->chain, flow, - (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0); - if (error == -ENOBUFS) { - dp_send_error_msg(dp, sender, OFPET_FLOW_MOD_FAILED, - OFPFMFC_ALL_TABLES_FULL, ofm, ntohs(ofm->header.length)); - goto error_free_flow; - } else if (error) { - goto error_free_flow; - } - - error = 0; - if (ntohl(ofm->buffer_id) != UINT32_MAX) { - struct ofpbuf *buffer = retrieve_buffer(ntohl(ofm->buffer_id)); - if (buffer) { - struct sw_flow_key key; - uint16_t in_port = ntohs(ofm->match.in_port); - flow_extract(buffer, in_port, &key.flow); - flow_used(flow, buffer); - execute_actions(dp, buffer, &key, - ofm->actions, actions_len, false); - } else { - error = -ESRCH; - } - } - return error; - -error_free_flow: - flow_free(flow); -error: - if (ntohl(ofm->buffer_id) != (uint32_t) -1) - discard_buffer(ntohl(ofm->buffer_id)); - return error; -} - -static int -mod_flow(struct datapath *dp, const struct sender *sender, - const struct ofp_flow_mod *ofm) -{ - int error = -ENOMEM; - uint16_t v_code; - size_t actions_len = ntohs(ofm->header.length) - sizeof *ofm; - struct sw_flow *flow; - int strict; - - /* Allocate memory. */ - flow = flow_alloc(actions_len); - if (flow == NULL) - goto error; - - flow_extract_match(&flow->key, &ofm->match); - - v_code = validate_actions(dp, &flow->key, ofm->actions, actions_len); - if (v_code != ACT_VALIDATION_OK) { - dp_send_error_msg(dp, sender, OFPET_BAD_ACTION, v_code, - ofm, ntohs(ofm->header.length)); - goto error_free_flow; - } - - flow->priority = flow->key.wildcards ? ntohs(ofm->priority) : -1; - strict = (ofm->command == htons(OFPFC_MODIFY_STRICT)) ? 1 : 0; - - /* First try to modify existing flows if any */ - /* if there is no matching flow, add it */ - if (!chain_modify(dp->chain, &flow->key, flow->priority, - strict, ofm->actions, actions_len, - (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0)) { - /* Fill out flow. */ - flow->cookie = ntohll(ofm->cookie); - flow->idle_timeout = ntohs(ofm->idle_timeout); - flow->hard_timeout = ntohs(ofm->hard_timeout); - flow->send_flow_rem = (ntohs(ofm->flags) & OFPFF_SEND_FLOW_REM) ? 1 : 0; - flow->emerg_flow = (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0; - flow_setup_actions(flow, ofm->actions, actions_len); - error = chain_insert(dp->chain, flow, - (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0); - if (error == -ENOBUFS) { - dp_send_error_msg(dp, sender, OFPET_FLOW_MOD_FAILED, - OFPFMFC_ALL_TABLES_FULL, ofm, - ntohs(ofm->header.length)); - goto error_free_flow; - } else if (error) { - goto error_free_flow; - } - } - - error = 0; - if (ntohl(ofm->buffer_id) != UINT32_MAX) { - struct ofpbuf *buffer = retrieve_buffer(ntohl(ofm->buffer_id)); - if (buffer) { - struct sw_flow_key skb_key; - uint16_t in_port = ntohs(ofm->match.in_port); - flow_extract(buffer, in_port, &skb_key.flow); - execute_actions(dp, buffer, &skb_key, - ofm->actions, actions_len, false); - } else { - error = -ESRCH; - } - } - return error; - -error_free_flow: - flow_free(flow); -error: - if (ntohl(ofm->buffer_id) != (uint32_t) -1) - discard_buffer(ntohl(ofm->buffer_id)); - return error; -} - -static int -recv_flow(struct datapath *dp, const struct sender *sender, - const void *msg) -{ - const struct ofp_flow_mod *ofm = msg; - uint16_t command = ntohs(ofm->command); - - if (command == OFPFC_ADD) { - return add_flow(dp, sender, ofm); - } else if ((command == OFPFC_MODIFY) || (command == OFPFC_MODIFY_STRICT)) { - return mod_flow(dp, sender, ofm); - } else if (command == OFPFC_DELETE) { - struct sw_flow_key key; - flow_extract_match(&key, &ofm->match); - return chain_delete(dp->chain, &key, ofm->out_port, 0, 0, - (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0) - ? 0 : -ESRCH; - } else if (command == OFPFC_DELETE_STRICT) { - struct sw_flow_key key; - uint16_t priority; - flow_extract_match(&key, &ofm->match); - priority = key.wildcards ? ntohs(ofm->priority) : -1; - return chain_delete(dp->chain, &key, ofm->out_port, priority, 1, - (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0) - ? 0 : -ESRCH; - } else { - return -ENODEV; - } -} - -static int -desc_stats_dump(struct datapath *dp UNUSED, void *state UNUSED, - struct ofpbuf *buffer) -{ - struct ofp_desc_stats *ods = ofpbuf_put_uninit(buffer, sizeof *ods); - - strncpy(ods->mfr_desc, &mfr_desc, sizeof ods->mfr_desc); - strncpy(ods->hw_desc, &hw_desc, sizeof ods->hw_desc); - strncpy(ods->sw_desc, &sw_desc, sizeof ods->sw_desc); - strncpy(ods->dp_desc, dp->dp_desc, sizeof ods->dp_desc); - strncpy(ods->serial_num, &serial_num, sizeof ods->serial_num); - - return 0; -} - -struct flow_stats_state { - int table_idx; - struct sw_table_position position; - struct ofp_flow_stats_request rq; - uint64_t now; /* Current time in milliseconds */ - - struct ofpbuf *buffer; -}; - -#define MAX_FLOW_STATS_BYTES 4096 -#define EMERG_TABLE_ID_FOR_STATS 0xfe - -static int -flow_stats_init(const void *body, int body_len UNUSED, void **state) -{ - const struct ofp_flow_stats_request *fsr = body; - struct flow_stats_state *s = xmalloc(sizeof *s); - s->table_idx = fsr->table_id == 0xff ? 0 : fsr->table_id; - memset(&s->position, 0, sizeof s->position); - s->rq = *fsr; - *state = s; - return 0; -} - -static int flow_stats_dump_callback(struct sw_flow *flow, void *private) -{ - struct flow_stats_state *s = private; - fill_flow_stats(s->buffer, flow, s->table_idx, s->now); - return s->buffer->size >= MAX_FLOW_STATS_BYTES; -} - -static int flow_stats_dump(struct datapath *dp, void *state, - struct ofpbuf *buffer) -{ - struct flow_stats_state *s = state; - struct sw_flow_key match_key; - - flow_extract_match(&match_key, &s->rq.match); - s->buffer = buffer; - s->now = time_msec(); - - if (s->rq.table_id == EMERG_TABLE_ID_FOR_STATS) { - struct sw_table *table = dp->chain->emerg_table; - - table->iterate(table, &match_key, s->rq.out_port, - &s->position, flow_stats_dump_callback, s); - } else { - while (s->table_idx < dp->chain->n_tables - && (s->rq.table_id == 0xff || s->rq.table_id == s->table_idx)) - { - struct sw_table *table = dp->chain->tables[s->table_idx]; - - if (table->iterate(table, &match_key, s->rq.out_port, - &s->position, flow_stats_dump_callback, s)) - break; - - s->table_idx++; - memset(&s->position, 0, sizeof s->position); - } - } - return s->buffer->size >= MAX_FLOW_STATS_BYTES; -} - -static void flow_stats_done(void *state) -{ - free(state); -} - -struct aggregate_stats_state { - struct ofp_aggregate_stats_request rq; -}; - -static int -aggregate_stats_init(const void *body, int body_len UNUSED, void **state) -{ - const struct ofp_aggregate_stats_request *rq = body; - struct aggregate_stats_state *s = xmalloc(sizeof *s); - s->rq = *rq; - *state = s; - return 0; -} - -static int aggregate_stats_dump_callback(struct sw_flow *flow, void *private) -{ - struct ofp_aggregate_stats_reply *rpy = private; - rpy->packet_count += flow->packet_count; - rpy->byte_count += flow->byte_count; - rpy->flow_count++; - return 0; -} - -static int aggregate_stats_dump(struct datapath *dp, void *state, - struct ofpbuf *buffer) -{ - struct aggregate_stats_state *s = state; - struct ofp_aggregate_stats_request *rq = &s->rq; - struct ofp_aggregate_stats_reply *rpy; - struct sw_table_position position; - struct sw_flow_key match_key; - int table_idx; - int error; - - rpy = ofpbuf_put_uninit(buffer, sizeof *rpy); - memset(rpy, 0, sizeof *rpy); - - flow_extract_match(&match_key, &rq->match); - table_idx = rq->table_id == 0xff ? 0 : rq->table_id; - memset(&position, 0, sizeof position); - - if (rq->table_id == EMERG_TABLE_ID_FOR_STATS) { - struct sw_table *table = dp->chain->emerg_table; - - error = table->iterate(table, &match_key, rq->out_port, &position, - aggregate_stats_dump_callback, rpy); - if (error) - return error; - } else { - while (table_idx < dp->chain->n_tables - && (rq->table_id == 0xff || rq->table_id == table_idx)) - { - struct sw_table *table = dp->chain->tables[table_idx]; - - error = table->iterate(table, &match_key, rq->out_port, &position, - aggregate_stats_dump_callback, rpy); - if (error) - return error; - - table_idx++; - memset(&position, 0, sizeof position); - } - } - - rpy->packet_count = htonll(rpy->packet_count); - rpy->byte_count = htonll(rpy->byte_count); - rpy->flow_count = htonl(rpy->flow_count); - return 0; -} - -static void aggregate_stats_done(void *state) -{ - free(state); -} - -static int -table_stats_dump(struct datapath *dp, void *state UNUSED, - struct ofpbuf *buffer) -{ - int i; - for (i = 0; i < dp->chain->n_tables; i++) { - struct ofp_table_stats *ots = ofpbuf_put_uninit(buffer, sizeof *ots); - struct sw_table_stats stats; - dp->chain->tables[i]->stats(dp->chain->tables[i], &stats); - strncpy(ots->name, stats.name, sizeof ots->name); - ots->table_id = i; - ots->wildcards = htonl(stats.wildcards); - memset(ots->pad, 0, sizeof ots->pad); - ots->max_entries = htonl(stats.max_flows); - ots->active_count = htonl(stats.n_flows); - ots->lookup_count = htonll(stats.n_lookup); - ots->matched_count = htonll(stats.n_matched); - } - return 0; -} - -struct port_stats_state { - int start_port; /* port to start dumping from */ - int port_no; /* from ofp_stats_request */ -}; - -struct queue_stats_state { - uint16_t port; - uint32_t queue_id; -}; - -static int -port_stats_init(const void *body, int body_len UNUSED, void **state) -{ - struct port_stats_state *s = xmalloc(sizeof *s); - const struct ofp_port_stats_request *psr = body; - - s->start_port = 1; - s->port_no = ntohs(psr->port_no); - *state = s; - return 0; -} - -static void -dump_port_stats(struct datapath *dp, struct sw_port *port, - struct ofpbuf *buffer) -{ - struct ofp_port_stats *ops = ofpbuf_put_uninit(buffer, sizeof *ops); - ops->port_no = htons(port->port_no); - memset(ops->pad, 0, sizeof ops->pad); - if (IS_HW_PORT(port)) { -#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) - struct ofp_port_stats stats; - - memset(&stats, 0, sizeof(stats)); - if (dp->hw_drv->port_stats_get) { - if (dp->hw_drv->port_stats_get(dp->hw_drv, port->port_no, - &stats) < 0) { - VLOG_WARN("Error getting stats on port %d\n", port->port_no); - return; - } - } - ops->rx_packets = htonll(stats.rx_packets); - ops->tx_packets = htonll(stats.tx_packets); - ops->rx_bytes = htonll(stats.rx_bytes); - ops->tx_bytes = htonll(stats.tx_bytes); - ops->rx_dropped = htonll(stats.rx_dropped); - ops->tx_dropped = htonll(stats.tx_dropped); - ops->rx_errors = htonll(stats.rx_errors); - ops->tx_errors = htonll(stats.tx_errors); - ops->rx_frame_err = htonll(stats.rx_frame_err); - ops->rx_over_err = htonll(stats.rx_over_err); - ops->rx_crc_err = htonll(stats.rx_crc_err); - ops->collisions = htonll(stats.collisions); -#endif - } else { - ops->rx_packets = htonll(port->rx_packets); - ops->tx_packets = htonll(port->tx_packets); - ops->rx_bytes = htonll(port->rx_bytes); - ops->tx_bytes = htonll(port->tx_bytes); - ops->rx_dropped = htonll(-1); - ops->tx_dropped = htonll(port->tx_dropped); - ops->rx_errors = htonll(-1); - ops->tx_errors = htonll(-1); - ops->rx_frame_err = htonll(-1); - ops->rx_over_err = htonll(-1); - ops->rx_crc_err = htonll(-1); - ops->collisions = htonll(-1); - } -} - -/* Although this makes some of the motions of being called - * multiple times preserving state, it doesn't actually support - * that process; the for loop can never break early. - */ -static int port_stats_dump(struct datapath *dp, void *state, - struct ofpbuf *buffer) -{ - struct port_stats_state *s = state; - struct sw_port *p = NULL; - int i = 0; - - if (s->port_no == OFPP_NONE) { - /* Dump statistics for all ports */ - for (i = s->start_port; i < DP_MAX_PORTS; i++) { - p = dp_lookup_port(dp, i); - if (p && PORT_IN_USE(p)) { - dump_port_stats(dp, p, buffer); - } - } - if (dp->local_port) { - dump_port_stats(dp, dp->local_port, buffer); - } - } else { - /* Dump statistics for a single port */ - p = dp_lookup_port(dp, s->port_no); - if (p && PORT_IN_USE(p)) { - dump_port_stats(dp, p, buffer); - } - } - - return 0; -} - -static void port_stats_done(void *state) -{ - free(state); -} - -static int -queue_stats_init(const void *body, int body_len UNUSED, void **state) -{ - const struct ofp_queue_stats_request *qsr = body; - struct queue_stats_state *s = xmalloc(sizeof *s); - s->port = ntohs(qsr->port_no); - s->queue_id = ntohl(qsr->queue_id); - *state = s; - return 0; -} - -static void -dump_queue_stats(struct sw_queue *q, struct ofpbuf *buffer) -{ - struct ofp_queue_stats *oqs = ofpbuf_put_uninit(buffer, sizeof *oqs); - oqs->port_no = htons(q->port->port_no); - oqs->queue_id = htonl(q->queue_id); - oqs->tx_bytes = htonll(q->tx_bytes); - oqs->tx_packets = htonll(q->tx_packets); - oqs->tx_errors = htonll(q->tx_errors); -} - -static int -queue_stats_dump(struct datapath *dp, void *state, - struct ofpbuf *buffer) -{ - struct queue_stats_state *s = state; - struct sw_queue *q; - struct sw_port *p; - - - if (s->port == OFPP_ALL) { - LIST_FOR_EACH(p, struct sw_port, node, &dp->port_list) { - if (p->port_no < OFPP_MAX) { - if (s->queue_id == OFPQ_ALL) { - LIST_FOR_EACH(q, struct sw_queue, node, &p->queue_list) { - dump_queue_stats(q,buffer); - } - } - else { - q = dp_lookup_queue(p, s->queue_id); - if (q) { - dump_queue_stats(q, buffer); - } - } - } - } - } - else { - p = dp_lookup_port(dp, s->port); - if (p) { - if (s->queue_id == OFPQ_ALL) { - LIST_FOR_EACH(q, struct sw_queue, node, &p->queue_list) { - dump_queue_stats(q,buffer); - } - } - else { - q = dp_lookup_queue(p, s->queue_id); - if (q) { - dump_queue_stats(q, buffer); - } - } - } - } - return 0; -} - -static void -queue_stats_done(void *state) -{ - free(state); -} - -/* - * We don't define any vendor_stats_state, we let the actual - * vendor implementation do that. - * The only requirement is that the first member of that object - * should be the vendor id. - * Jean II - * - * Basically, it would look like : - * struct acme_stats_state { - * uint32_t vendor; // ACME_VENDOR_ID. - * <...> // Other stuff. - * }; - */ -static int -vendor_stats_init(const void *body, int body_len UNUSED, - void **state UNUSED) -{ - /* min_body was checked, this should be safe */ - const uint32_t vendor = ntohl(*((uint32_t *)body)); - int err; - - switch (vendor) { - default: - err = -EINVAL; - } - - return err; -} - -static int -vendor_stats_dump(struct datapath *dp UNUSED, void *state, - struct ofpbuf *buffer UNUSED) -{ - const uint32_t vendor = *((uint32_t *)state); - int err; - - switch (vendor) { - default: - /* Should never happen */ - err = 0; - } - - return err; -} - -static void -vendor_stats_done(void *state) -{ - const uint32_t vendor = *((uint32_t *) state); - - switch (vendor) { - default: - /* Should never happen */ - free(state); - } - - return; -} - -struct stats_type { - /* Value for 'type' member of struct ofp_stats_request. */ - int type; - - /* Minimum and maximum acceptable number of bytes in body member of - * struct ofp_stats_request. */ - size_t min_body, max_body; - - /* Prepares to dump some kind of datapath statistics. 'body' and - * 'body_len' are the 'body' member of the struct ofp_stats_request. - * Returns zero if successful, otherwise a negative error code. - * May initialize '*state' to state information. May be null if no - * initialization is required.*/ - int (*init)(const void *body, int body_len, void **state); - - /* Appends statistics for 'dp' to 'buffer', which initially contains a - * struct ofp_stats_reply. On success, it should return 1 if it should be - * called again later with another buffer, 0 if it is done, or a negative - * errno value on failure. */ - int (*dump)(struct datapath *dp, void *state, struct ofpbuf *buffer); - - /* Cleans any state created by the init or dump functions. May be null - * if no cleanup is required. */ - void (*done)(void *state); -}; - -static const struct stats_type stats[] = { - { - OFPST_DESC, - 0, - 0, - NULL, - desc_stats_dump, - NULL - }, - { - OFPST_FLOW, - sizeof(struct ofp_flow_stats_request), - sizeof(struct ofp_flow_stats_request), - flow_stats_init, - flow_stats_dump, - flow_stats_done - }, - { - OFPST_AGGREGATE, - sizeof(struct ofp_aggregate_stats_request), - sizeof(struct ofp_aggregate_stats_request), - aggregate_stats_init, - aggregate_stats_dump, - aggregate_stats_done - }, - { - OFPST_TABLE, - 0, - 0, - NULL, - table_stats_dump, - NULL - }, - { - OFPST_PORT, - sizeof(struct ofp_port_stats_request), - sizeof(struct ofp_port_stats_request), - port_stats_init, - port_stats_dump, - port_stats_done - }, - { - OFPST_QUEUE, - sizeof(struct ofp_queue_stats_request), - sizeof(struct ofp_queue_stats_request), - queue_stats_init, - queue_stats_dump, - queue_stats_done - }, - { - OFPST_VENDOR, - 8, /* vendor + subtype */ - 32, /* whatever */ - vendor_stats_init, - vendor_stats_dump, - vendor_stats_done - }, -}; - -struct stats_dump_cb { - bool done; - struct ofp_stats_request *rq; - struct sender sender; - const struct stats_type *s; - void *state; -}; - -static int -stats_dump(struct datapath *dp, void *cb_) -{ - struct stats_dump_cb *cb = cb_; - struct ofp_stats_reply *osr; - struct ofpbuf *buffer; - int err; - - if (cb->done) { - return 0; - } - - osr = make_openflow_reply(sizeof *osr, OFPT_STATS_REPLY, &cb->sender, - &buffer); - osr->type = htons(cb->s->type); - osr->flags = 0; - - err = cb->s->dump(dp, cb->state, buffer); - if (err >= 0) { - int err2; - if (!err) { - cb->done = true; - } else { - /* Buffer might have been reallocated, so find our data again. */ - osr = ofpbuf_at_assert(buffer, 0, sizeof *osr); - osr->flags = ntohs(OFPSF_REPLY_MORE); - } - err2 = send_openflow_buffer(dp, buffer, &cb->sender); - if (err2) { - err = err2; - } - } - - return err; -} - -static void -stats_done(void *cb_) -{ - struct stats_dump_cb *cb = cb_; - if (cb) { - if (cb->s->done) { - cb->s->done(cb->state); - } - if (cb->rq) { - free(cb->rq); - } - free(cb); - } -} - -static int -recv_stats_request(struct datapath *dp UNUSED, const struct sender *sender, - const void *oh) -{ - const struct ofp_stats_request *rq = oh; - size_t rq_len = ntohs(rq->header.length); - const struct stats_type *st; - struct stats_dump_cb *cb; - int type, body_len; - int err; - - type = ntohs(rq->type); - for (st = stats; ; st++) { - if (st >= &stats[ARRAY_SIZE(stats)]) { - VLOG_WARN_RL(&rl, "received stats request of unknown type %d", - type); - return -EINVAL; - } else if (type == st->type) { - break; - } - } - - cb = xmalloc(sizeof *cb); - cb->done = false; - cb->rq = xmemdup(rq, rq_len); - cb->sender = *sender; - cb->s = st; - cb->state = NULL; - - body_len = rq_len - offsetof(struct ofp_stats_request, body); - if (body_len < cb->s->min_body || body_len > cb->s->max_body) { - VLOG_WARN_RL(&rl, "stats request type %d with bad body length %d", - type, body_len); - err = -EINVAL; - goto error; - } - - if (cb->s->init) { - err = cb->s->init(rq->body, body_len, &cb->state); - if (err) { - VLOG_WARN_RL(&rl, - "failed initialization of stats request type %d: %s", - type, strerror(-err)); - goto error; - } - } - - remote_start_dump(sender->remote, stats_dump, stats_done, cb); - return 0; - -error: - free(cb->rq); - free(cb); - return err; -} - -static int -recv_echo_request(struct datapath *dp, const struct sender *sender, - const void *oh) -{ - return send_openflow_buffer(dp, make_echo_reply(oh), sender); -} - -static int -recv_echo_reply(struct datapath *dp UNUSED, const struct sender *sender UNUSED, - const void *oh UNUSED) -{ - return 0; -} - -static int -recv_queue_get_config_request(struct datapath *dp, const struct sender *sender, - const void *oh) -{ - struct ofpbuf *buffer; - struct ofp_queue_get_config_reply *ofq_reply; - const struct ofp_queue_get_config_request *ofq_request; - struct sw_port *p; - struct sw_queue *q; - uint16_t port_no; - - ofq_request = (struct ofp_queue_get_config_request *)oh; - port_no = ntohs(ofq_request->port); - - if (port_no < OFPP_MAX) { - /* Find port under query */ - p = dp_lookup_port(dp,port_no); - - /* if the port under query doesn't exist, send an error */ - if (!p || (p->port_no != port_no)) { - dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, OFPQOFC_BAD_PORT, - oh, ntohs(ofq_request->header.length)); - goto error; - } - ofq_reply = make_openflow_reply(sizeof *ofq_reply, OFPT_QUEUE_GET_CONFIG_REPLY, - sender, &buffer); - ofq_reply->port = htons(port_no); - LIST_FOR_EACH(q, struct sw_queue, node, &p->queue_list) { - struct ofp_packet_queue * opq = ofpbuf_put_zeros(buffer, sizeof *opq); - fill_queue_desc(buffer, q, opq); - } - send_openflow_buffer(dp, buffer, sender); - } - else { - dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, OFPQOFC_BAD_PORT, - oh, ntohs(ofq_request->header.length)); - } - error: - return 0; -} - -static int -recv_vendor(struct datapath *dp, const struct sender *sender, - const void *oh) -{ - const struct ofp_vendor_header *ovh = oh; - - switch (ntohl(ovh->vendor)) - { - case PRIVATE_VENDOR_ID: - return private_recv_msg(dp, sender, oh); - - case OPENFLOW_VENDOR_ID: - return of_ext_recv_msg(dp, sender, oh); - - default: - VLOG_WARN_RL(&rl, "unknown vendor: 0x%x\n", ntohl(ovh->vendor)); - dp_send_error_msg(dp, sender, OFPET_BAD_REQUEST, - OFPBRC_BAD_VENDOR, oh, ntohs(ovh->header.length)); - return -EINVAL; - } -} - -/* 'msg', which is 'length' bytes long, was received from the control path. - * Apply it to 'chain'. */ -int -fwd_control_input(struct datapath *dp, const struct sender *sender, - const void *msg, size_t length) -{ - int (*handler)(struct datapath *, const struct sender *, const void *); - struct ofp_header *oh; - size_t min_size; - - /* Check encapsulated length. */ - oh = (struct ofp_header *) msg; - if (ntohs(oh->length) > length) { - return -EINVAL; - } - assert(oh->version == OFP_VERSION); - - /* Figure out how to handle it. */ - switch (oh->type) { - case OFPT_BARRIER_REQUEST: - min_size = sizeof(struct ofp_header); - handler = recv_barrier_request; - break; - case OFPT_FEATURES_REQUEST: - min_size = sizeof(struct ofp_header); - handler = recv_features_request; - break; - case OFPT_GET_CONFIG_REQUEST: - min_size = sizeof(struct ofp_header); - handler = recv_get_config_request; - break; - case OFPT_SET_CONFIG: - min_size = sizeof(struct ofp_switch_config); - handler = recv_set_config; - break; - case OFPT_PACKET_OUT: - min_size = sizeof(struct ofp_packet_out); - handler = recv_packet_out; - break; - case OFPT_FLOW_MOD: - min_size = sizeof(struct ofp_flow_mod); - handler = recv_flow; - break; - case OFPT_PORT_MOD: - min_size = sizeof(struct ofp_port_mod); - handler = recv_port_mod; - break; - case OFPT_STATS_REQUEST: - min_size = sizeof(struct ofp_stats_request); - handler = recv_stats_request; - break; - case OFPT_ECHO_REQUEST: - min_size = sizeof(struct ofp_header); - handler = recv_echo_request; - break; - case OFPT_ECHO_REPLY: - min_size = sizeof(struct ofp_header); - handler = recv_echo_reply; - break; - case OFPT_QUEUE_GET_CONFIG_REQUEST: - min_size = sizeof(struct ofp_header); - handler = recv_queue_get_config_request; - break; - case OFPT_VENDOR: - min_size = sizeof(struct ofp_vendor_header); - handler = recv_vendor; - break; - default: - dp_send_error_msg(dp, sender, OFPET_BAD_REQUEST, OFPBRC_BAD_TYPE, - msg, length); - return -EINVAL; - } - - /* Handle it. */ - if (length < min_size) - return -EFAULT; - return handler(dp, sender, msg); -} - -/* Packet buffering. */ - -#define OVERWRITE_SECS 1 - -struct packet_buffer { - struct ofpbuf *buffer; - uint32_t cookie; - time_t timeout; -}; - -static struct packet_buffer buffers[N_PKT_BUFFERS]; -static unsigned int buffer_idx; - -uint32_t save_buffer(struct ofpbuf *buffer) -{ - struct packet_buffer *p; - uint32_t id; - - buffer_idx = (buffer_idx + 1) & PKT_BUFFER_MASK; - p = &buffers[buffer_idx]; - if (p->buffer) { - /* Don't buffer packet if existing entry is less than - * OVERWRITE_SECS old. */ - if (time_now() < p->timeout) { /* FIXME */ - return (uint32_t)-1; - } else { - ofpbuf_delete(p->buffer); - } - } - /* Don't use maximum cookie value since the all-bits-1 id is - * special. */ - if (++p->cookie >= (1u << PKT_COOKIE_BITS) - 1) - p->cookie = 0; - p->buffer = ofpbuf_clone(buffer); /* FIXME */ - p->timeout = time_now() + OVERWRITE_SECS; /* FIXME */ - id = buffer_idx | (p->cookie << PKT_BUFFER_BITS); - - return id; -} - -static struct ofpbuf *retrieve_buffer(uint32_t id) -{ - struct ofpbuf *buffer = NULL; - struct packet_buffer *p; - - p = &buffers[id & PKT_BUFFER_MASK]; - if (p->cookie == id >> PKT_BUFFER_BITS) { - buffer = p->buffer; - p->buffer = NULL; - } else { - printf("cookie mismatch: %x != %x\n", - id >> PKT_BUFFER_BITS, p->cookie); - } - - return buffer; -} - -static void discard_buffer(uint32_t id) -{ - struct packet_buffer *p; - - p = &buffers[id & PKT_BUFFER_MASK]; - if (p->cookie == id >> PKT_BUFFER_BITS) { - ofpbuf_delete(p->buffer); - p->buffer = NULL; - } -} diff --git a/openflow/udatapath/datapath.h b/openflow/udatapath/datapath.h deleted file mode 100644 index c79c5ead..00000000 --- a/openflow/udatapath/datapath.h +++ /dev/null @@ -1,167 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -/* Interface exported by OpenFlow module. */ - -#ifndef DATAPATH_H -#define DATAPATH_H 1 - -#include -#include -#include "openflow/nicira-ext.h" -#include "ofpbuf.h" -#include "timeval.h" -#include "list.h" -#include "netdev.h" - -/* FIXME: Can declare struct of_hw_driver instead */ -#if defined(OF_HW_PLAT) -#include -#endif - -struct rconn; -struct pvconn; -struct sw_flow; -struct sender; - -struct sw_queue { - struct list node; /* element in port.queues */ - unsigned long long int tx_packets; - unsigned long long int tx_bytes; - unsigned long long int tx_errors; - uint32_t queue_id; - uint16_t class_id; /* internal mapping from OF queue_id to tc class_id */ - struct sw_port *port; /* reference to the parent port */ - /* keep it simple for now, only one property (assuming min_rate) */ - uint16_t property; /* one from OFPQT_ */ - uint16_t min_rate; -}; - -#define MAX_HW_NAME_LEN 32 -enum sw_port_flags { - SWP_USED = 1 << 0, /* Is port being used */ - SWP_HW_DRV_PORT = 1 << 1, /* Port controlled by HW driver */ -}; -#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) -#define IS_HW_PORT(p) ((p)->flags & SWP_HW_DRV_PORT) -#else -#define IS_HW_PORT(p) 0 -#endif - -#define PORT_IN_USE(p) (((p) != NULL) && (p)->flags & SWP_USED) - -struct sw_port { - uint32_t config; /* Some subset of OFPPC_* flags. */ - uint32_t state; /* Some subset of OFPPS_* flags. */ - uint32_t flags; /* SWP_* flags above */ - struct datapath *dp; - struct netdev *netdev; - char hw_name[OFP_MAX_PORT_NAME_LEN]; - struct list node; /* Element in datapath.ports. */ - unsigned long long int rx_packets, tx_packets; - unsigned long long int rx_bytes, tx_bytes; - unsigned long long int tx_dropped; - uint16_t port_no; - /* port queues */ - uint16_t num_queues; - struct sw_queue queues[NETDEV_MAX_QUEUES]; - struct list queue_list; /* list of all queues for this port */ -}; - -#if defined(OF_HW_PLAT) -struct hw_pkt_q_entry { - struct ofpbuf *buffer; - struct hw_pkt_q_entry *next; - of_port_t port_no; - int reason; -}; -#endif - -#define DP_MAX_PORTS 255 -BUILD_ASSERT_DECL(DP_MAX_PORTS <= OFPP_MAX); - -struct datapath { - /* Remote connections. */ - struct list remotes; /* All connections (including controller). */ - - /* Listeners. */ - struct pvconn **listeners; - size_t n_listeners; - - time_t last_timeout; - - /* Unique identifier for this datapath */ - uint64_t id; - char dp_desc[DESC_STR_LEN]; /* human readible comment to ID this DP */ - - struct sw_chain *chain; /* Forwarding rules. */ - - /* Configuration set from controller. */ - uint16_t flags; - uint16_t miss_send_len; - - /* Switch ports. */ - struct sw_port ports[DP_MAX_PORTS]; - struct sw_port *local_port; /* OFPP_LOCAL port, if any. */ - struct list port_list; /* All ports, including local_port. */ - -#if defined(OF_HW_PLAT) - /* Although the chain maintains the pointer to the HW driver - * for flow operations, the datapath needs the port functions - * in the driver structure - */ - of_hw_driver_t *hw_drv; - struct hw_pkt_q_entry *hw_pkt_list_head, *hw_pkt_list_tail; -#endif -}; - -int dp_new(struct datapath **, uint64_t dpid); -int dp_add_port(struct datapath *, const char *netdev, uint16_t); -int dp_add_local_port(struct datapath *, const char *netdev, uint16_t); -void dp_add_pvconn(struct datapath *, struct pvconn *); -void dp_run(struct datapath *); -void dp_wait(struct datapath *); -void dp_send_error_msg(struct datapath *, const struct sender *, - uint16_t, uint16_t, const void *, size_t); -void dp_send_flow_end(struct datapath *, struct sw_flow *, - enum ofp_flow_removed_reason); -void dp_output_port(struct datapath *, struct ofpbuf *, int in_port, - int out_port, uint32_t queue_id, bool ignore_no_fwd); -void dp_output_control(struct datapath *, struct ofpbuf *, int in_port, - size_t max_len, int reason); -struct sw_port * dp_lookup_port(struct datapath *, uint16_t); -struct sw_queue * dp_lookup_queue(struct sw_port *, uint32_t); - -int udatapath_cmd(int argc, char *argv[]); - -#endif /* datapath.h */ diff --git a/openflow/udatapath/dp_act.c b/openflow/udatapath/dp_act.c deleted file mode 100644 index d48beb10..00000000 --- a/openflow/udatapath/dp_act.c +++ /dev/null @@ -1,531 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -/* Functions for executing OpenFlow actions. */ - -#include -#include "csum.h" -#include "packets.h" -#include "dp_act.h" -#include "openflow/nicira-ext.h" - -static uint16_t -validate_output(struct datapath *dp UNUSED, const struct sw_flow_key *key, - const struct ofp_action_header *ah) -{ - struct ofp_action_output *oa = (struct ofp_action_output *)ah; - - /* To prevent loops, make sure there's no action to send to the - * OFP_TABLE virtual port. - */ - if (oa->port == htons(OFPP_NONE) || - (!(key->wildcards & OFPFW_IN_PORT) - && oa->port == key->flow.in_port)) { - return OFPBAC_BAD_OUT_PORT; - } - return ACT_VALIDATION_OK; -} - -static uint16_t -validate_queue(struct datapath *dp UNUSED, const struct sw_flow_key *key UNUSED, - const struct ofp_action_header *ah) -{ - struct ofp_action_enqueue *ea = (struct ofp_action_enqueue *)ah; - - /* Only physical ports may have queues. */ - if (ntohs(ea->port) > OFPP_MAX && ntohs(ea->port) != OFPP_IN_PORT) { - return OFPBAC_BAD_OUT_PORT; - } - return ACT_VALIDATION_OK; -} - -static void -do_output(struct datapath *dp, struct ofpbuf *buffer, int in_port, - size_t max_len, int out_port, uint32_t queue_id, - bool ignore_no_fwd) -{ - if (out_port != OFPP_CONTROLLER) { - dp_output_port(dp, buffer, in_port, out_port, queue_id, ignore_no_fwd); - } else { - dp_output_control(dp, buffer, in_port, max_len, OFPR_ACTION); - } -} - -/* Modify vlan tag control information (TCI). Only sets the TCI bits - * indicated by 'mask'. If no vlan tag is present, one is added. - */ -static void -modify_vlan_tci(struct ofpbuf *buffer, struct sw_flow_key *key, - uint16_t tci, uint16_t mask) -{ - struct vlan_eth_header *veh; - - if (key->flow.dl_vlan != htons(OFP_VLAN_NONE)) { - /* Modify vlan id, but maintain other TCI values */ - veh = buffer->l2; - veh->veth_tci &= ~htons(mask); - veh->veth_tci |= htons(tci); - } else { - /* Insert new vlan id. */ - struct eth_header *eh = buffer->l2; - struct vlan_eth_header tmp; - memcpy(tmp.veth_dst, eh->eth_dst, ETH_ADDR_LEN); - memcpy(tmp.veth_src, eh->eth_src, ETH_ADDR_LEN); - tmp.veth_type = htons(ETH_TYPE_VLAN); - tmp.veth_tci = htons(tci); - tmp.veth_next_type = eh->eth_type; - - veh = ofpbuf_push_uninit(buffer, VLAN_HEADER_LEN); - memcpy(veh, &tmp, sizeof tmp); - buffer->l2 = (char*)buffer->l2 - VLAN_HEADER_LEN; - } - - key->flow.dl_vlan = veh->veth_tci & htons(VLAN_VID_MASK); - key->flow.dl_vlan_pcp = (uint8_t)((ntohs(veh->veth_tci) >> VLAN_PCP_SHIFT) - & VLAN_PCP_BITMASK); -} - - -/* Remove an existing vlan header if it exists. */ -static void -vlan_pull_tag(struct ofpbuf *buffer) -{ - struct vlan_eth_header *veh = buffer->l2; - - if (veh->veth_type == htons(ETH_TYPE_VLAN)) { - struct eth_header tmp; - - memcpy(tmp.eth_dst, veh->veth_dst, ETH_ADDR_LEN); - memcpy(tmp.eth_src, veh->veth_src, ETH_ADDR_LEN); - tmp.eth_type = veh->veth_next_type; - - buffer->size -= VLAN_HEADER_LEN; - buffer->data = (char*)buffer->data + VLAN_HEADER_LEN; - buffer->l2 = (char*)buffer->l2 + VLAN_HEADER_LEN; - memcpy(buffer->data, &tmp, sizeof tmp); - } -} - -static void -set_vlan_vid(struct ofpbuf *buffer, struct sw_flow_key *key, - const struct ofp_action_header *ah) -{ - struct ofp_action_vlan_vid *va = (struct ofp_action_vlan_vid *)ah; - uint16_t tci = ntohs(va->vlan_vid); - - modify_vlan_tci(buffer, key, tci, VLAN_VID_MASK); -} - -static void -set_vlan_pcp(struct ofpbuf *buffer, struct sw_flow_key *key, - const struct ofp_action_header *ah) -{ - struct ofp_action_vlan_pcp *va = (struct ofp_action_vlan_pcp *)ah; - uint16_t tci = (uint16_t)va->vlan_pcp << 13; - - modify_vlan_tci(buffer, key, tci, VLAN_PCP_MASK); -} - -static void -strip_vlan(struct ofpbuf *buffer, struct sw_flow_key *key, - const struct ofp_action_header *ah UNUSED) -{ - vlan_pull_tag(buffer); - key->flow.dl_vlan = htons(OFP_VLAN_NONE); -} - -static void -set_dl_addr(struct ofpbuf *buffer, struct sw_flow_key *key UNUSED, - const struct ofp_action_header *ah) -{ - struct ofp_action_dl_addr *da = (struct ofp_action_dl_addr *)ah; - struct eth_header *eh = buffer->l2; - - if (da->type == htons(OFPAT_SET_DL_SRC)) { - memcpy(eh->eth_src, da->dl_addr, sizeof eh->eth_src); - } else { - memcpy(eh->eth_dst, da->dl_addr, sizeof eh->eth_dst); - } -} - -static void -set_nw_addr(struct ofpbuf *buffer, struct sw_flow_key *key, - const struct ofp_action_header *ah) -{ - struct ofp_action_nw_addr *na = (struct ofp_action_nw_addr *)ah; - uint16_t eth_proto = ntohs(key->flow.dl_type); - - if (eth_proto == ETH_TYPE_IP) { - struct ip_header *nh = buffer->l3; - uint8_t nw_proto = key->flow.nw_proto; - uint32_t new, *field; - - new = na->nw_addr; - field = na->type == htons(OFPAT_SET_NW_SRC) ? &nh->ip_src : &nh->ip_dst; - if (nw_proto == IP_TYPE_TCP) { - struct tcp_header *th = buffer->l4; - th->tcp_csum = recalc_csum32(th->tcp_csum, *field, new); - } else if (nw_proto == IP_TYPE_UDP) { - struct udp_header *th = buffer->l4; - if (th->udp_csum) { - th->udp_csum = recalc_csum32(th->udp_csum, *field, new); - if (!th->udp_csum) { - th->udp_csum = 0xffff; - } - } - } - nh->ip_csum = recalc_csum32(nh->ip_csum, *field, new); - *field = new; - } -} - -static void -set_nw_tos(struct ofpbuf *buffer, struct sw_flow_key *key, - const struct ofp_action_header *ah) -{ - struct ofp_action_nw_tos *nt = (struct ofp_action_nw_tos *)ah; - uint16_t eth_proto = ntohs(key->flow.dl_type); - - if (eth_proto == ETH_TYPE_IP) { - struct ip_header *nh = buffer->l3; - uint8_t new, *field; - - /* JeanII : Set only 6 bits, don't clobber ECN */ - new = (nt->nw_tos & 0xFC) | (nh->ip_tos & 0x03); - - /* Get address of field */ - field = &nh->ip_tos; - - /* jklee : ip tos field is not included in TCP pseudo header. - * Need magic as update_csum() don't work with 8 bits. */ - nh->ip_csum = recalc_csum32(nh->ip_csum, htons((uint16_t)*field), - htons((uint16_t)new)); - - /* Change the IP ToS bits */ - *field = new; - } -} - -static void -set_tp_port(struct ofpbuf *buffer, struct sw_flow_key *key, - const struct ofp_action_header *ah) -{ - struct ofp_action_tp_port *ta = (struct ofp_action_tp_port *)ah; - uint16_t eth_proto = ntohs(key->flow.dl_type); - - if (eth_proto == ETH_TYPE_IP) { - uint8_t nw_proto = key->flow.nw_proto; - uint16_t new, *field; - - new = ta->tp_port; - if (nw_proto == IP_TYPE_TCP) { - struct tcp_header *th = buffer->l4; - field = ta->type == htons(OFPAT_SET_TP_SRC) ? &th->tcp_src : &th->tcp_dst; - th->tcp_csum = recalc_csum16(th->tcp_csum, *field, new); - *field = new; - } else if (nw_proto == IP_TYPE_UDP) { - struct udp_header *th = buffer->l4; - field = ta->type == htons(OFPAT_SET_TP_SRC) ? &th->udp_src : &th->udp_dst; - th->udp_csum = recalc_csum16(th->udp_csum, *field, new); - *field = new; - } - } -} - -struct openflow_action { - size_t min_size; - size_t max_size; - uint16_t (*validate)(struct datapath *dp, - const struct sw_flow_key *key, - const struct ofp_action_header *ah); - void (*execute)(struct ofpbuf *buffer, - struct sw_flow_key *key, - const struct ofp_action_header *ah); -}; - -static const struct openflow_action of_actions[] = { - [OFPAT_OUTPUT] = { - sizeof(struct ofp_action_output), - sizeof(struct ofp_action_output), - validate_output, - NULL /* This is optimized into execute_actions */ - }, - [OFPAT_ENQUEUE] = { - sizeof(struct ofp_action_enqueue), - sizeof(struct ofp_action_enqueue), - validate_queue, - NULL /* This is optimized into execute_actions */ - }, - [OFPAT_SET_VLAN_VID] = { - sizeof(struct ofp_action_vlan_vid), - sizeof(struct ofp_action_vlan_vid), - NULL, - set_vlan_vid - }, - [OFPAT_SET_VLAN_PCP] = { - sizeof(struct ofp_action_vlan_pcp), - sizeof(struct ofp_action_vlan_pcp), - NULL, - set_vlan_pcp - }, - [OFPAT_STRIP_VLAN] = { - sizeof(struct ofp_action_header), - sizeof(struct ofp_action_header), - NULL, - strip_vlan - }, - [OFPAT_SET_DL_SRC] = { - sizeof(struct ofp_action_dl_addr), - sizeof(struct ofp_action_dl_addr), - NULL, - set_dl_addr - }, - [OFPAT_SET_DL_DST] = { - sizeof(struct ofp_action_dl_addr), - sizeof(struct ofp_action_dl_addr), - NULL, - set_dl_addr - }, - [OFPAT_SET_NW_SRC] = { - sizeof(struct ofp_action_nw_addr), - sizeof(struct ofp_action_nw_addr), - NULL, - set_nw_addr - }, - [OFPAT_SET_NW_DST] = { - sizeof(struct ofp_action_nw_addr), - sizeof(struct ofp_action_nw_addr), - NULL, - set_nw_addr - }, - [OFPAT_SET_NW_TOS] = { - sizeof(struct ofp_action_nw_tos), - sizeof(struct ofp_action_nw_tos), - NULL, - set_nw_tos - }, - [OFPAT_SET_TP_SRC] = { - sizeof(struct ofp_action_tp_port), - sizeof(struct ofp_action_tp_port), - NULL, - set_tp_port - }, - [OFPAT_SET_TP_DST] = { - sizeof(struct ofp_action_tp_port), - sizeof(struct ofp_action_tp_port), - NULL, - set_tp_port - } - /* OFPAT_VENDOR is not here, since it would blow up the array size. */ -}; - -/* Validate built-in OpenFlow actions. Either returns ACT_VALIDATION_OK - * or an OFPET_BAD_ACTION error code. */ -static uint16_t -validate_ofpat(struct datapath *dp, const struct sw_flow_key *key, - const struct ofp_action_header *ah, uint16_t type, uint16_t len) -{ - uint16_t ret = ACT_VALIDATION_OK; - const struct openflow_action *act = &of_actions[type]; - - if ((len < act->min_size) || (len > act->max_size)) { - return OFPBAC_BAD_LEN; - } - - if (act->validate) { - ret = act->validate(dp, key, ah); - } - - return ret; -} - -/* Validate vendor-defined actions. Either returns ACT_VALIDATION_OK - * or an OFPET_BAD_ACTION error code. */ -static uint16_t -validate_vendor(struct datapath *dp UNUSED, const struct sw_flow_key *key UNUSED, - const struct ofp_action_header *ah, uint16_t len) -{ - struct ofp_action_vendor_header *avh; - int ret = ACT_VALIDATION_OK; - - if (len < sizeof(struct ofp_action_vendor_header)) { - return OFPBAC_BAD_LEN; - } - - avh = (struct ofp_action_vendor_header *)ah; - - switch(ntohl(avh->vendor)) { - default: - return OFPBAC_BAD_VENDOR; - } - - return ret; -} - -/* Validates a list of actions. If a problem is found, a code for the - * OFPET_BAD_ACTION error type is returned. If the action list validates, - * ACT_VALIDATION_OK is returned. */ -uint16_t -validate_actions(struct datapath *dp, const struct sw_flow_key *key, - const struct ofp_action_header *actions, size_t actions_len) -{ - uint8_t *p = (uint8_t *)actions; - int err; - - while (actions_len >= sizeof(struct ofp_action_header)) { - struct ofp_action_header *ah = (struct ofp_action_header *)p; - size_t len = ntohs(ah->len); - uint16_t type; - - /* Make there's enough remaining data for the specified length - * and that the action length is a multiple of 64 bits. */ - if ((actions_len < len) || (len % 8) != 0) { - return OFPBAC_BAD_LEN; - } - - type = ntohs(ah->type); - if (type < ARRAY_SIZE(of_actions)) { - err = validate_ofpat(dp, key, ah, type, len); - if (err != ACT_VALIDATION_OK) { - return err; - } - } else if (type == OFPAT_VENDOR) { - err = validate_vendor(dp, key, ah, len); - if (err != ACT_VALIDATION_OK) { - return err; - } - } else { - return OFPBAC_BAD_TYPE; - } - - p += len; - actions_len -= len; - } - - /* Check if there's any trailing garbage. */ - if (actions_len != 0) { - return OFPBAC_BAD_LEN; - } - - return ACT_VALIDATION_OK; -} - -/* Execute a built-in OpenFlow action against 'buffer'. */ -static void -execute_ofpat(struct ofpbuf *buffer, struct sw_flow_key *key, - const struct ofp_action_header *ah, uint16_t type) -{ - const struct openflow_action *act = &of_actions[type]; - - if (act->execute) { - act->execute(buffer, key, ah); - } -} - -/* Execute a vendor-defined action against 'buffer'. */ -static void -execute_vendor(struct ofpbuf *buffer UNUSED, const struct sw_flow_key *key UNUSED, - const struct ofp_action_header *ah) -{ - struct ofp_action_vendor_header *avh - = (struct ofp_action_vendor_header *)ah; - - switch(ntohl(avh->vendor)) { - default: - /* This should not be possible due to prior validation. */ - printf("attempt to execute action with unknown vendor: %#x\n", - ntohl(avh->vendor)); - break; - } -} - -/* Execute a list of actions against 'buffer'. */ -void execute_actions(struct datapath *dp, struct ofpbuf *buffer, - struct sw_flow_key *key, - const struct ofp_action_header *actions, size_t actions_len, - int ignore_no_fwd) -{ - /* Every output action needs a separate clone of 'buffer', but the common - * case is just a single output action, so that doing a clone and then - * freeing the original buffer is wasteful. So the following code is - * slightly obscure just to avoid that. */ - int prev_port; - uint32_t prev_queue; - size_t max_len = UINT16_MAX; - uint16_t in_port = ntohs(key->flow.in_port); - uint8_t *p = (uint8_t *)actions; - - prev_port = -1; - prev_queue = 0; - - /* The action list was already validated, so we can be a bit looser - * in our sanity-checking. */ - while (actions_len > 0) { - struct ofp_action_header *ah = (struct ofp_action_header *)p; - size_t len = htons(ah->len); - - if (prev_port != -1) { - do_output(dp, ofpbuf_clone(buffer), in_port, max_len, - prev_port, prev_queue, ignore_no_fwd); - prev_port = -1; - } - - if (ah->type == htons(OFPAT_OUTPUT)) { - struct ofp_action_output *oa = (struct ofp_action_output *)p; - prev_port = ntohs(oa->port); - prev_queue = 0; /* using the default best-effort queue */ - max_len = ntohs(oa->max_len); - } else if (ah->type == htons(OFPAT_ENQUEUE)) { - struct ofp_action_enqueue *ea = (struct ofp_action_enqueue *)p; - prev_port = ntohs(ea->port); - prev_queue = ntohl(ea->queue_id); - max_len = 0; /* we will not send to the controller anyways - useless */ - } else { - uint16_t type = ntohs(ah->type); - - if (type < ARRAY_SIZE(of_actions)) { - execute_ofpat(buffer, key, ah, type); - } else if (type == OFPAT_VENDOR) { - execute_vendor(buffer, key, ah); - } - } - - p += len; - actions_len -= len; - } - if (prev_port != -1) { - do_output(dp, buffer, in_port, max_len, prev_port, prev_queue, ignore_no_fwd); - } else { - ofpbuf_delete(buffer); - } -} diff --git a/openflow/udatapath/dp_act.h b/openflow/udatapath/dp_act.h deleted file mode 100644 index e0181fad..00000000 --- a/openflow/udatapath/dp_act.h +++ /dev/null @@ -1,49 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#ifndef DP_ACT_H -#define DP_ACT_H 1 - -#include "openflow/openflow.h" -#include "switch-flow.h" -#include "datapath.h" - -#define ACT_VALIDATION_OK ((uint16_t)-1) - -uint16_t validate_actions(struct datapath *, const struct sw_flow_key *, - const struct ofp_action_header *, size_t); -void execute_actions(struct datapath *, struct ofpbuf *, - struct sw_flow_key *, const struct ofp_action_header *, - size_t action_len, int ignore_no_fwd); - -#endif /* dp_act.h */ diff --git a/openflow/udatapath/of_ext_msg.c b/openflow/udatapath/of_ext_msg.c deleted file mode 100644 index 36d587be..00000000 --- a/openflow/udatapath/of_ext_msg.c +++ /dev/null @@ -1,267 +0,0 @@ -/* Copyright (c) 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include -#include "openflow/openflow-ext.h" -#include "of_ext_msg.h" -#include "netdev.h" -#include "datapath.h" - -#define THIS_MODULE VLM_experimental -#include "vlog.h" - -static int -new_queue(struct sw_port * port, struct sw_queue * queue, - uint32_t queue_id, uint16_t class_id, - struct ofp_queue_prop_min_rate * mr) -{ - memset(queue, '\0', sizeof *queue); - queue->port = port; - queue->queue_id = queue_id; - /* class_id is the internal mapping to class. It is the offset - * in the array of queues for each port. Note that class_id is - * local to port, so we don't have any conflict. - * tc uses 16-bit class_id, so we cannot use the queue_id - * field */ - queue->class_id = class_id; - queue->property = ntohs(mr->prop_header.property); - queue->min_rate = ntohs(mr->rate); - - list_push_back(&port->queue_list, &queue->node); - - return 0; -} - -static int -port_add_queue(struct sw_port *p, uint32_t queue_id, - struct ofp_queue_prop_min_rate * mr) -{ - int queue_no; - for (queue_no = 1; queue_no < p->num_queues; queue_no++) { - struct sw_queue *q = &p->queues[queue_no]; - if (!q->port) { - return new_queue(p,q,queue_id,queue_no,mr); - } - } - return EXFULL; -} - -static int -port_delete_queue(struct sw_port *p UNUSED, struct sw_queue *q) -{ - list_remove(&q->node); - memset(q,'\0', sizeof *q); - return 0; -} - -static void -recv_of_exp_queue_delete(struct datapath *dp, - const struct sender *sender, - const void *oh) -{ - struct sw_port *p; - struct sw_queue *q; - struct openflow_queue_command_header * ofq_delete; - struct ofp_packet_queue *opq; - - uint16_t port_no; - uint32_t queue_id; - - ofq_delete = (struct openflow_queue_command_header *)oh; - opq = (struct ofp_packet_queue *)ofq_delete->body; - port_no = ntohs(ofq_delete->port); - queue_id = ntohl(opq->queue_id); - - p = dp_lookup_port(dp,port_no); - if (p->netdev) { - q = dp_lookup_queue(p,queue_id); - if (q) { - netdev_delete_class(p->netdev,q->class_id); - port_delete_queue(p,q); - } - else { - dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, - OFPQOFC_BAD_PORT, oh, - ntohs(ofq_delete->header.header.length)); - } - } - else { - dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, - OFPQOFC_BAD_PORT, oh, - ntohs(ofq_delete->header.header.length)); - } -} - -/** Modifies/adds a queue. It first searches if a queue with - * id exists for this port. If yes it modifies it, otherwise adds - * a new configuration. - * - * @param dp the related datapath - * @param sender request source - * @param oh the openflow message for queue mod. - */ -static void -recv_of_exp_queue_modify(struct datapath *dp, - const struct sender *sender UNUSED, - const void *oh) -{ - struct sw_port *p; - struct sw_queue *q; - struct openflow_queue_command_header * ofq_modify; - struct ofp_packet_queue *opq; - struct ofp_queue_prop_min_rate *mr; - - int error = 0; - uint16_t port_no; - uint32_t queue_id; - - - ofq_modify = (struct openflow_queue_command_header *)oh; - opq = (struct ofp_packet_queue *)ofq_modify->body; - mr = (struct ofp_queue_prop_min_rate*)opq->properties; - - /* Currently, we only accept queues with a single, min-rate property */ - if ((ntohs(opq->len) != 24) || - ntohs(mr->prop_header.property) != OFPQT_MIN_RATE) { - VLOG_ERR("Unknown queue configuration"); - dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, - OFQ_ERR_DISCIPLINE, oh, - ntohs(ofq_modify->header.header.length)); - return; - } - - - - port_no = ntohs(ofq_modify->port); - queue_id = ntohl(opq->queue_id); - - p = dp_lookup_port(dp, port_no); - if (PORT_IN_USE(p)) { - q = dp_lookup_queue(p, queue_id); - if (q) { - /* queue exists - modify it */ - error = netdev_change_class(p->netdev,q->class_id, ntohs(mr->rate)); - if (error) { - VLOG_ERR("Failed to update queue %d", queue_id); - dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, - OFPQOFC_EPERM, oh, - ntohs(ofq_modify->header.header.length)); - } - else { - q->property = ntohs(mr->prop_header.property); - q->min_rate = ntohs(mr->rate); - } - } - else { - /* create new queue */ - error = port_add_queue(p,queue_id, mr); - if (error == EXFULL) { - dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, - OFPQOFC_EPERM, oh, - ntohs(ofq_modify->header.header.length)); - return; - } - q = dp_lookup_queue(p, queue_id); - error = netdev_setup_class(p->netdev,q->class_id, ntohs(mr->rate)); - if (error) { - VLOG_ERR("Failed to configure queue %d", queue_id); - dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, - OFPQOFC_BAD_QUEUE, oh, - ntohs(ofq_modify->header.header.length)); - } - } - } - else { - dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, OFPQOFC_BAD_PORT, - oh, ntohs(ofq_modify->header.header.length)); - VLOG_ERR("Failed to create/modify queue - port %d doesn't exist", - port_no); - } - if (!error) { - if (IS_HW_PORT(p)) { -#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) - error = dp->hw_drv->port_queue_config(dp->hw_drv, port_no, - queue_id, ntohs(mr->rate)); - if (error < 0) { - VLOG_ERR("Failed to update HW port %d queue %d", - port_no, queue_id); - } -#endif - } - } -} -/** - * Parses a set dp_desc message and uses it to set - * the dp_desc string in dp - */ -static void -recv_of_set_dp_desc(struct datapath *dp, - const struct sender *sender UNUSED, - const struct ofp_extension_header * exth) -{ - struct openflow_ext_set_dp_desc * set_dp_desc = (struct openflow_ext_set_dp_desc * ) - exth; - strncpy(dp->dp_desc, set_dp_desc->dp_desc, DESC_STR_LEN); - dp->dp_desc[DESC_STR_LEN-1] = 0; // force null for safety -} - -/** - * Receives an experimental message and pass it - * to the appropriate handler - */ -int of_ext_recv_msg(struct datapath *dp, const struct sender *sender, - const void *oh) -{ - const struct ofp_extension_header *ofexth = oh; - - switch (ntohl(ofexth->subtype)) { - case OFP_EXT_QUEUE_MODIFY: { - recv_of_exp_queue_modify(dp,sender,oh); - return 0; - } - case OFP_EXT_QUEUE_DELETE: { - recv_of_exp_queue_delete(dp,sender,oh); - return 0; - } - case OFP_EXT_SET_DESC: - recv_of_set_dp_desc(dp,sender,ofexth); - return 0; - default: - VLOG_ERR("Received unknown command of type %d", - ntohl(ofexth->subtype)); - return -EINVAL; - } - - return -EINVAL; -} diff --git a/openflow/udatapath/of_ext_msg.h b/openflow/udatapath/of_ext_msg.h deleted file mode 100644 index 510615d7..00000000 --- a/openflow/udatapath/of_ext_msg.h +++ /dev/null @@ -1,43 +0,0 @@ -/* Copyright (c) 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#ifndef OF_EXT_MSG_H -#define OF_EXT_MSG_H 1 - -#include "datapath.h" - -struct sender; - -int of_ext_recv_msg(struct datapath *, const struct sender *, const void *); - -#endif /* of_ext_msg.h */ diff --git a/openflow/udatapath/ofdatapath.8.in b/openflow/udatapath/ofdatapath.8.in deleted file mode 100644 index 55d6b4ba..00000000 --- a/openflow/udatapath/ofdatapath.8.in +++ /dev/null @@ -1,148 +0,0 @@ -.ds PN ofdatapath - -.TH ofdatapath 8 "May 2008" "OpenFlow" "OpenFlow Manual" - -.SH NAME -ofdatapath \- userspace implementation of datapath for OpenFlow switch - -.SH SYNOPSIS -.B ofdatapath -[\fIoptions\fR] -\fB-i\fR \fInetdev\fR[\fB,\fInetdev\fR].\|.\|. -\fImethod\fR [\fImethod\fR].\|.\|. - -.SH DESCRIPTION -The \fBofdatapath\fR is a userspace implementation of an OpenFlow -datapath. It monitors one or more network device interfaces, -forwarding packets between them according to the entries in the flow -table that it maintains. When it is used with \fBofprotocol\fR(8), to -connect the datapath to an OpenFlow controller, the combination is an -OpenFlow switch. - -For access to network devices, the ofdatapath program must normally run as -root. - -The mandatory \fImethod\fR argument specifies how \fBofprotocol\fR(8) -communicates with \fBofdatapath\fR, as a passive OpenFlow connection -method. Ordinarily \fImethod\fR takes the following form: - -.TP -\fBpunix:\fIfile\fR -Listens for connections on the Unix domain server socket named -\fIfile\fR. - -.PP -The following connection methods are also supported, but their use -would be unusual because \fBofdatapath\fR and \fBofprotocol\fR should run -on the same machine: - -.TP -\fBpssl:\fR[\fIport\fR] -Listens for SSL connections \fIport\fR (default: 976). The -\fB--private-key\fR, \fB--certificate\fR, and \fB--ca-cert\fR options -are mandatory when this form is used. (\fBofp\-pki\fR(8) does not set -up a suitable PKI for use with this option.) - -.TP -\fBptcp:\fR[\fIport\fR] -Listens for TCP connections from remote OpenFlow switches on -\fIport\fR (default: 975). - -.SH OPTIONS -.TP -\fB-i\fR, \fB--interfaces=\fR\fInetdev\fR[\fB,\fInetdev\fR].\|.\|. -Specifies each \fInetdev\fR (e.g., \fBeth0\fR) as a switch port. The -specified network devices should not have any configured IP addresses. -This option may be given any number of times to specify additional -network devices. - -.TP -\fB-L\fR, \fB--local-port=\fInetdev\fR -Specifies the network device to use as the userspace datapath's -``local port,'' which is a network device that \fBofprotocol\fR(8) -bridges to the physical switch ports for use in in-band control. When -this option is not specified, the default is \fBtap:\fR, which causes -a new TAP virtual network device to be allocated with a default name -assigned by the kernel. To do the same, but assign a specific name -\fBname\fR to the TAP network device, specify the option as -\fB--local-port=tap:\fIname\fR. - -Either way, the existence of TAP devices created by \fBofdatapath\fR is -temporary: they are destroyed when \fBofdatapath\fR exits. If this is -undesirable, you may use \fBtunctl\fR(8) to create a persistent TAP -network device and then pass it to \fBofdatapath\fR, like so: - -.RS -.IP 1. -Create a persistent TAP network device: \fBtunctl -t mytap\fR. (The -\fBtunctl\fR(8) utility is part of User Mode Linux. It is not -included with the OpenFlow reference implementation.) -.IP 2. -Invoke \fBofdatapath\fR(8) using \fBmytap\fR, e.g. \fBofdatapath ---local-port=mytap\fR .\|.\|. (Note the lack of \fBtap:\fR prefix on -the \fB--local-port\fR argument.) -.IP 3. -Invoke \fBofprotocol\fR(8), etc., and use the switch as desired. -.IP 4. -When \fBofprotocol\fR and \fBofdatapath\fR have terminated and the TAP -network device is no longer needed, you may destroy it with: \fBtunctl --d mytap\fR -.RE - -.IP -It does not ordinarily make sense to specify the name of a physical -network device on \fB-L\fR or \fB--local-port\fR. - -.TP -\fB--no-local-port\fR -Do not provide a local port as part of the datapath. When this option -is used, the switch will not support in-band control. - -.TP -\fB--no-slicing\fR -Disable slicing (no queue configuration to ports). When this option -is used, the switch will have 0 queues, and therefore no -slicing-related functionality is supported. This option is useful when -run-time dependencies for slicing (tc and related kernel -configuration) are not met. - -.TP -\fB-d\fR, \fB--datapath-id=\fIdpid\fR -Specifies the OpenFlow datapath ID (a 48-bit number that uniquely -identifies a controller) as \fIdpid\fR, which consists of exactly 12 -hex digits. Without this option, \fBofdatapath\fR picks an ID randomly. - -.TP -\fB-p\fR, \fB--private-key=\fIprivkey.pem\fR -Specifies a PEM file containing the private key used as the datapath's -identity for SSL connections to \fBofprotocol\fR(8). - -.TP -\fB-c\fR, \fB--certificate=\fIcert.pem\fR -Specifies a PEM file containing a certificate, signed by the -datapath's certificate authority (CA), that certifies the datapath's -private key to identify a trustworthy datapath. - -.TP -\fB-C\fR, \fB--ca-cert=\fIcacert.pem\fR -Specifies a PEM file containing the CA certificate used to verify that -the datapath is connected to a trustworthy secure channel. - -.so lib/daemon.man -.so lib/vlog.man -.so lib/common.man - -.SH BUGS -The userspace datapath's performance lags significantly behind that of -the kernel-based switch. It should only be used when the kernel-based -switch cannot be. - -On Linux, general-purpose support for VLAN tag rewriting is precluded -by the Linux kernel AF_PACKET implementation. - -.SH "SEE ALSO" - -.BR ofprotocol (8), -.BR dpctl (8), -.BR controller (8), -.BR vlogconf (8). diff --git a/openflow/udatapath/private-msg.c b/openflow/udatapath/private-msg.c deleted file mode 100644 index 7e868671..00000000 --- a/openflow/udatapath/private-msg.c +++ /dev/null @@ -1,140 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#include -#include - -#include "openflow/private-ext.h" - -#include "chain.h" -#include "datapath.h" -#include "switch-flow.h" -#include "table.h" -#include "private-msg.h" - -struct emerg_flow_context { - struct datapath *dp; -}; - -static void flush_working(struct datapath *); -static int protection_callback(struct sw_flow *, void *); -static void do_protection(struct datapath *); - -static void -flush_working(struct datapath *dp) -{ - struct sw_flow_key key; - int num_deleted = 0; - - memset(&key, 0, sizeof(key)); - key.wildcards = OFPFW_ALL; - num_deleted = chain_delete(dp->chain, &key, OFPP_NONE, 0, 0, 0); -} - -static int -protection_callback(struct sw_flow *flow, void *private_) -{ - struct emerg_flow_context *private - = (struct emerg_flow_context *)private_; - struct sw_flow_actions *actions = flow->sf_acts; - struct ofp_match match; - struct sw_flow *tgtflow = NULL; - int error = 0; - - tgtflow = flow_alloc(flow->sf_acts->actions_len); - if (tgtflow == NULL) - return -ENOBUFS; - - /* Dup w/o idle and hard timeout. */ - memset(&match, 0, sizeof(match)); - flow_fill_match(&match, &flow->key.flow, flow->key.wildcards); - flow_extract_match(&tgtflow->key, &match); - /* Fill out flow. */ - tgtflow->priority = flow->priority; - tgtflow->idle_timeout = OFP_FLOW_PERMANENT; - tgtflow->hard_timeout = OFP_FLOW_PERMANENT; - tgtflow->send_flow_rem = flow->send_flow_rem; - tgtflow->emerg_flow = 0; - flow_setup_actions(tgtflow, actions->actions, actions->actions_len); - - error = chain_insert(private->dp->chain, tgtflow, 0); - if (error) - flow_free(tgtflow); - - return error; -} - -static void -do_protection(struct datapath *dp) -{ - struct emerg_flow_context private; - struct sw_flow_key key; - struct sw_table_position position; - struct sw_table *table = dp->chain->emerg_table; - int error = 0; - - memset(&private, 0, sizeof(private)); - private.dp = dp; - memset(&key, 0, sizeof(key)); - key.wildcards = OFPFW_ALL; - memset(&position, 0, sizeof(position)); - - error = table->iterate(table, &key, OFPP_NONE, - &position, protection_callback, &private); -} - -int -private_recv_msg(struct datapath *dp, const struct sender *sender UNUSED, - const void *ofph) -{ - struct private_vxhdr *vxhdr = (struct private_vxhdr *)ofph; - struct private_vxopt *vxopt = (struct private_vxopt *)(vxhdr + 1); - int error = 0; - - switch (ntohs(vxopt->pvo_type)) { - case PRIVATEOPT_PROTOCOL_STATS_REQUEST: - case PRIVATEOPT_PROTOCOL_STATS_REPLY: - break; - case PRIVATEOPT_EMERG_FLOW_PROTECTION: - flush_working(dp); - do_protection(dp); - break; - case PRIVATEOPT_EMERG_FLOW_RESTORATION: - /* Nothing to do because we assume that a re-connected - * controller will do flush current working flow table. */ - break; - default: - error = -EINVAL; - } - - return error; -} diff --git a/openflow/udatapath/private-msg.h b/openflow/udatapath/private-msg.h deleted file mode 100644 index 082a4531..00000000 --- a/openflow/udatapath/private-msg.h +++ /dev/null @@ -1,42 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#ifndef PRIVATE_MSG_H_ -#define PRIVATE_MSG_H_ - -#include "datapath.h" - -struct sender; - -int private_recv_msg(struct datapath *, const struct sender *, const void *); - -#endif diff --git a/openflow/udatapath/switch-flow.c b/openflow/udatapath/switch-flow.c deleted file mode 100644 index 4ba9b406..00000000 --- a/openflow/udatapath/switch-flow.c +++ /dev/null @@ -1,341 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include "switch-flow.h" -#include -#include -#include -#include -#include "ofpbuf.h" -#include "openflow/openflow.h" -#include "openflow/nicira-ext.h" -#include "packets.h" -#include "timeval.h" - -#define THIS_MODULE VLM_chain -#include "vlog.h" - -/* Internal function used to compare fields in flow. */ -static inline int -flow_fields_match(const struct flow *a, const struct flow *b, uint32_t w, - uint32_t src_mask, uint32_t dst_mask) -{ - return ((w & OFPFW_IN_PORT || a->in_port == b->in_port) - && (w & OFPFW_DL_VLAN || a->dl_vlan == b->dl_vlan) - && (w & OFPFW_DL_VLAN_PCP || a->dl_vlan_pcp == b->dl_vlan_pcp) - && (w & OFPFW_DL_SRC || eth_addr_equals(a->dl_src, b->dl_src)) - && (w & OFPFW_DL_DST || eth_addr_equals(a->dl_dst, b->dl_dst)) - && (w & OFPFW_DL_TYPE || a->dl_type == b->dl_type) - && (w & OFPFW_NW_TOS || a->nw_tos == b->nw_tos) - && (w & OFPFW_NW_PROTO || a->nw_proto == b->nw_proto) - && !((a->nw_src ^ b->nw_src) & src_mask) - && !((a->nw_dst ^ b->nw_dst) & dst_mask) - && (w & OFPFW_TP_SRC || a->tp_src == b->tp_src) - && (w & OFPFW_TP_DST || a->tp_dst == b->tp_dst)); -} - -static uint32_t make_nw_mask(int n_wild_bits) -{ - n_wild_bits &= (1u << OFPFW_NW_SRC_BITS) - 1; - return n_wild_bits < 32 ? htonl(~((1u << n_wild_bits) - 1)) : 0; -} - -/* Returns nonzero if 'a' and 'b' match, that is, if their fields are equal - * modulo wildcards in 'b', zero otherwise. */ -inline int -flow_matches_1wild(const struct sw_flow_key *a, const struct sw_flow_key *b) -{ - return flow_fields_match(&a->flow, &b->flow, b->wildcards, - b->nw_src_mask, b->nw_dst_mask); -} - -/* Returns nonzero if 'a' and 'b' match, that is, if their fields are equal - * modulo wildcards in 'a' or 'b', zero otherwise. */ -inline int -flow_matches_2wild(const struct sw_flow_key *a, const struct sw_flow_key *b) -{ - return flow_fields_match(&a->flow, &b->flow, a->wildcards | b->wildcards, - a->nw_src_mask & b->nw_src_mask, - a->nw_dst_mask & b->nw_dst_mask); -} - -/* Returns nonzero if 't' (the table entry's key) and 'd' (the key - * describing the match) match, that is, if their fields are - * equal modulo wildcards, zero otherwise. If 'strict' is nonzero, the - * wildcards must match in both 't_key' and 'd_key'. Note that the - * table's wildcards are ignored unless 'strict' is set. */ -int -flow_matches_desc(const struct sw_flow_key *t, const struct sw_flow_key *d, - int strict) -{ - if (strict && d->wildcards != t->wildcards) { - return 0; - } - return flow_matches_1wild(t, d); -} - -/* Returns nonzero if 't' (the table entry's key) and 'd' (the key - * describing the match) match, that is, if their fields are - * equal modulo 't' or 'd' wildcards, zero otherwise. If 'strict' is nonzero, the - * wildcards must match in both 't_key' and 'd_key'. Note that the - * table's wildcards are ignored unless 'strict' is set. */ -int -flow_matches_2desc(const struct sw_flow_key *t, const struct sw_flow_key *d, - int strict) -{ - if (strict && d->wildcards != t->wildcards) { - return 0; - } - return flow_matches_2wild(t, d); -} - -void -flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from) -{ - to->wildcards = ntohl(from->wildcards) & OFPFW_ALL; - to->flow.dl_vlan_pcp = from->dl_vlan_pcp; - to->flow.in_port = from->in_port; - to->flow.dl_vlan = from->dl_vlan; - memcpy(to->flow.dl_src, from->dl_src, ETH_ADDR_LEN); - memcpy(to->flow.dl_dst, from->dl_dst, ETH_ADDR_LEN); - to->flow.dl_type = from->dl_type; - - to->flow.nw_tos = to->flow.nw_proto = to->flow.nw_src = to->flow.nw_dst = 0; - to->flow.tp_src = to->flow.tp_dst = 0; - memset(to->flow.pad, 0, sizeof(to->flow.pad)); - -#define OFPFW_TP (OFPFW_TP_SRC | OFPFW_TP_DST) -#define OFPFW_NW (OFPFW_NW_TOS | OFPFW_NW_PROTO | OFPFW_NW_SRC_MASK | OFPFW_NW_DST_MASK) - if (to->wildcards & OFPFW_DL_TYPE) { - /* Can't sensibly match on network or transport headers if the - * data link type is unknown. */ - to->wildcards |= OFPFW_NW | OFPFW_TP; - } else if (from->dl_type == htons(ETH_TYPE_IP)) { - to->flow.nw_tos = from->nw_tos & 0xfc; - to->flow.nw_proto = from->nw_proto; - to->flow.nw_src = from->nw_src; - to->flow.nw_dst = from->nw_dst; - - if (to->wildcards & OFPFW_NW_PROTO) { - /* Can't sensibly match on transport headers if the network - * protocol is unknown. */ - to->wildcards |= OFPFW_TP; - } else if (from->nw_proto == IPPROTO_TCP - || from->nw_proto == IPPROTO_UDP - || from->nw_proto == IPPROTO_ICMP) { - to->flow.tp_src = from->tp_src; - to->flow.tp_dst = from->tp_dst; - } else { - /* Transport layer fields are undefined. Mark them as - * exact-match to allow such flows to reside in table-hash, - * instead of falling into table-linear. */ - to->wildcards &= ~OFPFW_TP; - } - } else if (from->dl_type == htons(ETH_TYPE_ARP)) { - to->flow.nw_src = from->nw_src; - to->flow.nw_dst = from->nw_dst; - to->flow.nw_proto = from->nw_proto; - - /* Transport layer fields are undefined. Mark them as - * exact-match to allow such flows to reside in table-hash, - * instead of falling into table-linear. */ - to->wildcards &= ~OFPFW_TP; - } else { - /* Network and transport layer fields are undefined. Mark them - * as exact-match to allow such flows to reside in table-hash, - * instead of falling into table-linear. */ - to->wildcards &= ~(OFPFW_NW | OFPFW_TP); - } - - /* We set these late because code above adjusts to->wildcards. */ - to->nw_src_mask = make_nw_mask(to->wildcards >> OFPFW_NW_SRC_SHIFT); - to->nw_dst_mask = make_nw_mask(to->wildcards >> OFPFW_NW_DST_SHIFT); -} - -/* Allocates and returns a new flow with room for 'actions_len' actions. - * Returns the new flow or a null pointer on failure. */ -struct sw_flow * -flow_alloc(size_t actions_len) -{ - struct sw_flow_actions *sfa; - size_t size = sizeof *sfa + actions_len; - struct sw_flow *flow = calloc(1, sizeof *flow); - if (!flow) - return NULL; - - sfa = calloc(1, size); - if (!sfa) { - free(flow); - return NULL; - } - sfa->actions_len = actions_len; - flow->sf_acts = sfa; - return flow; -} - -/* Setup the action on the flow, just after it was created with flow_alloc(). - * Jean II */ -void -flow_setup_actions(struct sw_flow * flow, - const struct ofp_action_header * actions, - int actions_len) -{ - /* Make sure we don't blow the allocation */ - if (actions_len > flow->sf_acts->actions_len) - ofp_fatal(0, - "flow_setup_actions: actions_len is too big (%d > %lu)", - actions_len, (unsigned long)flow->sf_acts->actions_len); - - flow->used = flow->created = time_msec(); - flow->sf_acts->actions_len = actions_len; - flow->byte_count = 0; - flow->packet_count = 0; - memcpy(flow->sf_acts->actions, actions, actions_len); -} - -/* Frees 'flow' immediately. */ -void -flow_free(struct sw_flow *flow) -{ - if (!flow) { - return; - } - free(flow->sf_acts); - free(flow); -} - -/* Copies 'actions' into a newly allocated structure for use by 'flow' - * and frees the structure that defined the previous actions. */ -void flow_replace_acts(struct sw_flow *flow, - const struct ofp_action_header *actions, size_t actions_len) -{ - struct sw_flow_actions *sfa; - int size = sizeof *sfa + actions_len; - - sfa = malloc(size); - if (unlikely(!sfa)) - return; - - sfa->actions_len = actions_len; - memcpy(sfa->actions, actions, actions_len); - - free(flow->sf_acts); - flow->sf_acts = sfa; - - return; -} - -/* Prints a representation of 'key' to the kernel log. */ -void -print_flow(const struct sw_flow_key *key) -{ - const struct flow *f = &key->flow; - - VLOG_INFO("wild %08x port %04x vlan-vid %04x vlan-pcp %02x " - "src-mac %02x:%02x:%02x:%02x:%02x:%02x " - "dst-mac %02x:%02x:%02x:%02x:%02x:%02x " - "frm-type %04x ip-tos %02x ip-src %u.%u.%u.%u ip-dst %u.%u.%u.%u " - "ip-proto %04x tp-src %d tp-dst %d pad %02x%02x%02x\n", - key->wildcards, ntohs(f->in_port), - ntohs(f->dl_vlan), f->dl_vlan_pcp, - f->dl_src[0], f->dl_src[1], f->dl_src[2], - f->dl_src[3], f->dl_src[4], f->dl_src[5], - f->dl_dst[0], f->dl_dst[1], f->dl_dst[2], - f->dl_dst[3], f->dl_dst[4], f->dl_dst[5], - ntohs(f->dl_type), - f->nw_tos, - ((unsigned char *)&f->nw_src)[0], - ((unsigned char *)&f->nw_src)[1], - ((unsigned char *)&f->nw_src)[2], - ((unsigned char *)&f->nw_src)[3], - ((unsigned char *)&f->nw_dst)[0], - ((unsigned char *)&f->nw_dst)[1], - ((unsigned char *)&f->nw_dst)[2], - ((unsigned char *)&f->nw_dst)[3], - f->nw_proto, - ntohs(f->tp_src), ntohs(f->tp_dst), - f->pad[0], f->pad[1], f->pad[2]); -} - -bool flow_timeout(struct sw_flow *flow) -{ - uint64_t now = time_msec(); - if (flow->idle_timeout != OFP_FLOW_PERMANENT - && now > flow->used + flow->idle_timeout * 1000) { - flow->reason = OFPRR_IDLE_TIMEOUT; - return true; - } else if (flow->hard_timeout != OFP_FLOW_PERMANENT - && now > flow->created + flow->hard_timeout * 1000) { - flow->reason = OFPRR_HARD_TIMEOUT; - return true; - } else { - return false; - } -} - -/* Returns nonzero if 'flow' contains an output action to 'out_port' or - * has the value OFPP_NONE. 'out_port' is in network-byte order. */ -int flow_has_out_port(struct sw_flow *flow, uint16_t out_port) -{ - struct sw_flow_actions *sf_acts = flow->sf_acts; - size_t actions_len = sf_acts->actions_len; - uint8_t *p = (uint8_t *)sf_acts->actions; - - if (out_port == htons(OFPP_NONE)) - return 1; - - while (actions_len > 0) { - struct ofp_action_header *ah = (struct ofp_action_header *)p; - size_t len = ntohs(ah->len); - - if (ah->type == htons(OFPAT_OUTPUT)) { - struct ofp_action_output *oa = (struct ofp_action_output *)p; - if (oa->port == out_port) { - return 1; - } - } - p += len; - actions_len -= len; - } - - return 0; -} - -void flow_used(struct sw_flow *flow, struct ofpbuf *buffer) -{ - flow->used = time_msec(); - - flow->packet_count++; - flow->byte_count += buffer->size; -} diff --git a/openflow/udatapath/switch-flow.h b/openflow/udatapath/switch-flow.h deleted file mode 100644 index 374cc737..00000000 --- a/openflow/udatapath/switch-flow.h +++ /dev/null @@ -1,100 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#ifndef SWITCH_FLOW_H -#define SWITCH_FLOW_H 1 - -#include -#include "openflow/openflow.h" -#include "flow.h" -#include "list.h" - -struct ofp_match; - -/* Identification data for a flow. */ -struct sw_flow_key { - struct flow flow; /* Flow data (in network byte order). */ - uint32_t wildcards; /* Wildcard fields (in host byte order). */ - uint32_t nw_src_mask; /* 1-bit in each significant nw_src bit. */ - uint32_t nw_dst_mask; /* 1-bit in each significant nw_dst bit. */ -}; - -struct sw_flow_actions { - size_t actions_len; - struct ofp_action_header actions[0]; -}; - -struct sw_flow { - struct sw_flow_key key; - - uint64_t cookie; /* Opaque controller-issued identifier. */ - uint16_t priority; /* Only used on entries with wildcards. */ - uint16_t idle_timeout; /* Idle time before discarding (seconds). */ - uint16_t hard_timeout; /* Hard expiration time (seconds) */ - uint64_t used; /* Last used time. */ - uint64_t created; /* When the flow was created. */ - uint64_t packet_count; /* Number of packets seen. */ - uint64_t byte_count; /* Number of bytes seen. */ - uint8_t reason; /* Reason flow removed (one of OFPRR_*). */ - uint8_t send_flow_rem; /* Send a flow removed to the controller */ - uint8_t emerg_flow; /* Emergency flow indicator */ - - struct sw_flow_actions *sf_acts; - - /* Private to table implementations. */ - struct list node; - struct list iter_node; - unsigned long int serial; - - void *private; /* Cookie for tables */ -}; - -int flow_matches_1wild(const struct sw_flow_key *, const struct sw_flow_key *); -int flow_matches_2wild(const struct sw_flow_key *, const struct sw_flow_key *); -int flow_matches_desc(const struct sw_flow_key *, const struct sw_flow_key *, - int); -int flow_matches_2desc(const struct sw_flow_key *, const struct sw_flow_key *, - int); -int flow_has_out_port(struct sw_flow *flow, uint16_t out_port); -struct sw_flow *flow_alloc(size_t); -void flow_setup_actions(struct sw_flow *, const struct ofp_action_header *, int); -void flow_free(struct sw_flow *); -void flow_replace_acts(struct sw_flow *, const struct ofp_action_header *, - size_t); -void flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from); - -void print_flow(const struct sw_flow_key *); -bool flow_timeout(struct sw_flow *flow); -void flow_used(struct sw_flow *flow, struct ofpbuf *buffer); - -#endif /* switch-flow.h */ diff --git a/openflow/udatapath/table-hash.c b/openflow/udatapath/table-hash.c deleted file mode 100644 index fc7006da..00000000 --- a/openflow/udatapath/table-hash.c +++ /dev/null @@ -1,469 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include "table.h" -#include -#include -#include -#include "openflow/nicira-ext.h" -#include "crc32.h" -#include "datapath.h" -#include "flow.h" -#include "switch-flow.h" - -struct sw_table_hash { - struct sw_table swt; - struct crc32 crc32; - unsigned int n_flows; - unsigned int bucket_mask; /* Number of buckets minus 1. */ - struct sw_flow **buckets; -}; - -static struct sw_flow **find_bucket(struct sw_table *swt, - const struct sw_flow_key *key) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - unsigned int crc = crc32_calculate(&th->crc32, key, - offsetof(struct sw_flow_key, wildcards)); - return &th->buckets[crc & th->bucket_mask]; -} - -static struct sw_flow *table_hash_lookup(struct sw_table *swt, - const struct sw_flow_key *key) -{ - struct sw_flow *flow = *find_bucket(swt, key); - return flow && !flow_compare(&flow->key.flow, &key->flow) ? flow : NULL; -} - -static int table_hash_insert(struct sw_table *swt, struct sw_flow *flow) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - struct sw_flow **bucket; - int retval; - - if (flow->key.wildcards != 0) - return 0; - - bucket = find_bucket(swt, &flow->key); - if (*bucket == NULL) { - th->n_flows++; - *bucket = flow; - retval = 1; - } else { - struct sw_flow *old_flow = *bucket; - if (!flow_compare(&old_flow->key.flow, &flow->key.flow)) { - *bucket = flow; - flow_free(old_flow); - retval = 1; - } else { - retval = 0; - } - } - return retval; -} - -static int table_hash_modify(struct sw_table *swt, - const struct sw_flow_key *key, uint16_t priority, int strict, - const struct ofp_action_header *actions, size_t actions_len) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - unsigned int count = 0; - - if (key->wildcards == 0) { - struct sw_flow **bucket = find_bucket(swt, key); - struct sw_flow *flow = *bucket; - if (flow && flow_matches_desc(&flow->key, key, strict) - && (!strict || (flow->priority == priority))) { - flow_replace_acts(flow, actions, actions_len); - count = 1; - } - } else { - unsigned int i; - - for (i = 0; i <= th->bucket_mask; i++) { - struct sw_flow **bucket = &th->buckets[i]; - struct sw_flow *flow = *bucket; - if (flow && flow_matches_desc(&flow->key, key, strict) - && (!strict || (flow->priority == priority))) { - flow_replace_acts(flow, actions, actions_len); - count++; - } - } - } - return count; -} - -static int table_hash_has_conflict(struct sw_table *swt, - const struct sw_flow_key *key, - uint16_t priority, int strict) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - - if (key->wildcards == 0) { - struct sw_flow **bucket = find_bucket(swt, key); - struct sw_flow *flow = *bucket; - if (flow && flow_matches_2desc(&flow->key, key,strict) - && (flow->priority == priority)) { - return true; - } - } else { - unsigned int i; - - for (i = 0; i <= th->bucket_mask; i++) { - struct sw_flow **bucket = &th->buckets[i]; - struct sw_flow *flow = *bucket; - if (flow && flow_matches_2desc(&flow->key, key, strict) - && (flow->priority == priority)) { - return true; - } - } - } - return false; -} - -/* Caller must update n_flows. */ -static void -do_delete(struct sw_flow **bucket) -{ - flow_free(*bucket); - *bucket = NULL; -} - -/* Returns number of deleted flows. We ignore the priority - * argument, since all exact-match entries are the same (highest) - * priority. */ -static int table_hash_delete(struct datapath *dp, struct sw_table *swt, - const struct sw_flow_key *key, - uint16_t out_port, - uint16_t priority UNUSED, int strict) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - unsigned int count = 0; - - if (key->wildcards == 0) { - struct sw_flow **bucket = find_bucket(swt, key); - struct sw_flow *flow = *bucket; - if (flow && !flow_compare(&flow->key.flow, &key->flow) - && flow_has_out_port(flow, out_port)) { - dp_send_flow_end(dp, flow, OFPRR_DELETE); - do_delete(bucket); - count = 1; - } - } else { - unsigned int i; - - for (i = 0; i <= th->bucket_mask; i++) { - struct sw_flow **bucket = &th->buckets[i]; - struct sw_flow *flow = *bucket; - if (flow && flow_matches_desc(&flow->key, key, strict) - && flow_has_out_port(flow, out_port)) { - dp_send_flow_end(dp, flow, OFPRR_DELETE); - do_delete(bucket); - count++; - } - } - } - th->n_flows -= count; - return count; -} - -static void table_hash_timeout(struct sw_table *swt, struct list *deleted) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - unsigned int i; - - for (i = 0; i <= th->bucket_mask; i++) { - struct sw_flow **bucket = &th->buckets[i]; - struct sw_flow *flow = *bucket; - if (flow && flow_timeout(flow)) { - list_push_back(deleted, &flow->node); - *bucket = NULL; - th->n_flows--; - } - } -} - -static void table_hash_destroy(struct sw_table *swt) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - unsigned int i; - for (i = 0; i <= th->bucket_mask; i++) { - if (th->buckets[i]) { - flow_free(th->buckets[i]); - } - } - free(th->buckets); - free(th); -} - -static int table_hash_iterate(struct sw_table *swt, - const struct sw_flow_key *key, uint16_t out_port, - struct sw_table_position *position, - int (*callback)(struct sw_flow *, void *private), - void *private) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - - if (position->private[0] > th->bucket_mask) - return 0; - - if (key->wildcards == 0) { - struct sw_flow *flow = table_hash_lookup(swt, key); - position->private[0] = -1; - if (!flow || !flow_has_out_port(flow, out_port)) { - return 0; - } - return callback(flow, private); - } else { - int i; - - for (i = position->private[0]; i <= th->bucket_mask; i++) { - struct sw_flow *flow = th->buckets[i]; - if (flow && flow_matches_1wild(&flow->key, key) - && flow_has_out_port(flow, out_port)) { - int error = callback(flow, private); - if (error) { - position->private[0] = i + 1; - return error; - } - } - } - return 0; - } -} - -static void table_hash_stats(struct sw_table *swt, - struct sw_table_stats *stats) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - stats->name = "hash"; - stats->wildcards = 0; /* No wildcards are supported. */ - stats->n_flows = th->n_flows; - stats->max_flows = th->bucket_mask + 1; - stats->n_lookup = swt->n_lookup; - stats->n_matched = swt->n_matched; -} - -struct sw_table *table_hash_create(unsigned int polynomial, - unsigned int n_buckets) -{ - struct sw_table_hash *th; - struct sw_table *swt; - - th = malloc(sizeof *th); - if (th == NULL) - return NULL; - memset(th, '\0', sizeof *th); - - assert(!(n_buckets & (n_buckets - 1))); - th->buckets = calloc(n_buckets, sizeof *th->buckets); - if (th->buckets == NULL) { - printf("failed to allocate %u buckets\n", n_buckets); - free(th); - return NULL; - } - th->n_flows = 0; - th->bucket_mask = n_buckets - 1; - - swt = &th->swt; - swt->lookup = table_hash_lookup; - swt->insert = table_hash_insert; - swt->modify = table_hash_modify; - swt->has_conflict = table_hash_has_conflict; - swt->delete = table_hash_delete; - swt->timeout = table_hash_timeout; - swt->destroy = table_hash_destroy; - swt->iterate = table_hash_iterate; - swt->stats = table_hash_stats; - - crc32_init(&th->crc32, polynomial); - - return swt; -} - -/* Double-hashing table. */ - -struct sw_table_hash2 { - struct sw_table swt; - struct sw_table *subtable[2]; -}; - -static struct sw_flow *table_hash2_lookup(struct sw_table *swt, - const struct sw_flow_key *key) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - int i; - - for (i = 0; i < 2; i++) { - struct sw_flow *flow = *find_bucket(t2->subtable[i], key); - if (flow && !flow_compare(&flow->key.flow, &key->flow)) - return flow; - } - return NULL; -} - -static int table_hash2_insert(struct sw_table *swt, struct sw_flow *flow) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - - if (table_hash_insert(t2->subtable[0], flow)) - return 1; - return table_hash_insert(t2->subtable[1], flow); -} - -static int table_hash2_modify(struct sw_table *swt, - const struct sw_flow_key *key, uint16_t priority, int strict, - const struct ofp_action_header *actions, size_t actions_len) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - return (table_hash_modify(t2->subtable[0], key, priority, strict, - actions, actions_len) - + table_hash_modify(t2->subtable[1], key, priority, strict, - actions, actions_len)); -} - -static int table_hash2_has_conflict(struct sw_table *swt, - const struct sw_flow_key *key, - uint16_t priority, int strict) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - return (table_hash_has_conflict(t2->subtable[0], key, priority, strict) || - table_hash_has_conflict(t2->subtable[1], key, priority, strict)); -} - -static int table_hash2_delete(struct datapath *dp, struct sw_table *swt, - const struct sw_flow_key *key, - uint16_t out_port, - uint16_t priority, int strict) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - return (table_hash_delete(dp, t2->subtable[0], key, out_port, - priority, strict) - + table_hash_delete(dp, t2->subtable[1], key, out_port, - priority, strict)); -} - -static void table_hash2_timeout(struct sw_table *swt, struct list *deleted) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - table_hash_timeout(t2->subtable[0], deleted); - table_hash_timeout(t2->subtable[1], deleted); -} - -static void table_hash2_destroy(struct sw_table *swt) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - table_hash_destroy(t2->subtable[0]); - table_hash_destroy(t2->subtable[1]); - free(t2); -} - -static int table_hash2_iterate(struct sw_table *swt, - const struct sw_flow_key *key, - uint16_t out_port, - struct sw_table_position *position, - int (*callback)(struct sw_flow *, void *), - void *private) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - int i; - - for (i = position->private[1]; i < 2; i++) { - int error = table_hash_iterate(t2->subtable[i], key, out_port, - position, callback, private); - if (error) { - return error; - } - position->private[0] = 0; - position->private[1]++; - } - return 0; -} - -static void table_hash2_stats(struct sw_table *swt, - struct sw_table_stats *stats) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - struct sw_table_stats substats[2]; - int i; - - for (i = 0; i < 2; i++) - table_hash_stats(t2->subtable[i], &substats[i]); - stats->name = "hash2"; - stats->wildcards = 0; /* No wildcards are supported. */ - stats->n_flows = substats[0].n_flows + substats[1].n_flows; - stats->max_flows = substats[0].max_flows + substats[1].max_flows; - stats->n_lookup = swt->n_lookup; - stats->n_matched = swt->n_matched; -} - -struct sw_table *table_hash2_create(unsigned int poly0, unsigned int buckets0, - unsigned int poly1, unsigned int buckets1) - -{ - struct sw_table_hash2 *t2; - struct sw_table *swt; - - t2 = malloc(sizeof *t2); - if (t2 == NULL) - return NULL; - memset(t2, '\0', sizeof *t2); - - t2->subtable[0] = table_hash_create(poly0, buckets0); - if (t2->subtable[0] == NULL) - goto out_free_t2; - - t2->subtable[1] = table_hash_create(poly1, buckets1); - if (t2->subtable[1] == NULL) - goto out_free_subtable0; - - swt = &t2->swt; - swt->lookup = table_hash2_lookup; - swt->insert = table_hash2_insert; - swt->modify = table_hash2_modify; - swt->has_conflict = table_hash2_has_conflict; - swt->delete = table_hash2_delete; - swt->timeout = table_hash2_timeout; - swt->destroy = table_hash2_destroy; - swt->iterate = table_hash2_iterate; - swt->stats = table_hash2_stats; - - return swt; - -out_free_subtable0: - table_hash_destroy(t2->subtable[0]); -out_free_t2: - free(t2); - return NULL; -} diff --git a/openflow/udatapath/table-linear.c b/openflow/udatapath/table-linear.c deleted file mode 100644 index 0aea0e25..00000000 --- a/openflow/udatapath/table-linear.c +++ /dev/null @@ -1,262 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include "table.h" -#include -#include "flow.h" -#include "list.h" -#include "openflow/openflow.h" -#include "openflow/nicira-ext.h" -#include "switch-flow.h" -#include "datapath.h" - -struct sw_table_linear { - struct sw_table swt; - - unsigned int max_flows; - unsigned int n_flows; - struct list flows; - struct list iter_flows; - unsigned long int next_serial; -}; - -static struct sw_flow *table_linear_lookup(struct sw_table *swt, - const struct sw_flow_key *key) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - struct sw_flow *flow; - LIST_FOR_EACH (flow, struct sw_flow, node, &tl->flows) { - if (flow_matches_1wild(key, &flow->key)) - return flow; - } - return NULL; -} - -static int table_linear_insert(struct sw_table *swt, struct sw_flow *flow) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - struct sw_flow *f; - - /* Loop through the existing list of entries. New entries will - * always be placed behind those with equal priority. Just replace - * any flows that match exactly. - */ - LIST_FOR_EACH (f, struct sw_flow, node, &tl->flows) { - if (f->priority == flow->priority - && f->key.wildcards == flow->key.wildcards - && flow_matches_2wild(&f->key, &flow->key)) { - flow->serial = f->serial; - list_replace(&flow->node, &f->node); - list_replace(&flow->iter_node, &f->iter_node); - flow_free(f); - return 1; - } - - if (f->priority < flow->priority) - break; - } - - /* Make sure there's room in the table. */ - if (tl->n_flows >= tl->max_flows) { - return 0; - } - tl->n_flows++; - - /* Insert the entry immediately in front of where we're pointing. */ - flow->serial = tl->next_serial++; - list_insert(&f->node, &flow->node); - list_push_front(&tl->iter_flows, &flow->iter_node); - - return 1; -} - -static int table_linear_modify(struct sw_table *swt, - const struct sw_flow_key *key, uint16_t priority, int strict, - const struct ofp_action_header *actions, size_t actions_len) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - struct sw_flow *flow; - unsigned int count = 0; - - LIST_FOR_EACH (flow, struct sw_flow, node, &tl->flows) { - if (flow_matches_desc(&flow->key, key, strict) - && (!strict || (flow->priority == priority))) { - flow_replace_acts(flow, actions, actions_len); - count++; - } - } - return count; -} - -static int table_linear_has_conflict(struct sw_table *swt, - const struct sw_flow_key *key, - uint16_t priority, int strict) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - struct sw_flow *flow; - - LIST_FOR_EACH (flow, struct sw_flow, node, &tl->flows) { - if (flow_matches_2desc(&flow->key, key, strict) - && (flow->priority == priority)) { - return true; - } - } - return false; -} - -static void -do_delete(struct sw_flow *flow) -{ - list_remove(&flow->node); - list_remove(&flow->iter_node); - flow_free(flow); -} - -static int table_linear_delete(struct datapath *dp, struct sw_table *swt, - const struct sw_flow_key *key, - uint16_t out_port, - uint16_t priority, int strict) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - struct sw_flow *flow, *n; - unsigned int count = 0; - - LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &tl->flows) { - if (flow_matches_desc(&flow->key, key, strict) - && flow_has_out_port(flow, out_port) - && (!strict || (flow->priority == priority))) { - dp_send_flow_end(dp, flow, OFPRR_DELETE); - do_delete(flow); - count++; - } - } - tl->n_flows -= count; - return count; -} - -static void table_linear_timeout(struct sw_table *swt, struct list *deleted) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - struct sw_flow *flow, *n; - - LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &tl->flows) { - if (flow_timeout(flow)) { - list_remove(&flow->node); - list_remove(&flow->iter_node); - list_push_back(deleted, &flow->node); - tl->n_flows--; - } - } -} - -static void table_linear_destroy(struct sw_table *swt) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - - while (!list_is_empty(&tl->flows)) { - struct sw_flow *flow = CONTAINER_OF(list_front(&tl->flows), - struct sw_flow, node); - list_remove(&flow->node); - flow_free(flow); - } - free(tl); -} - -static int table_linear_iterate(struct sw_table *swt, - const struct sw_flow_key *key, - uint16_t out_port, - struct sw_table_position *position, - int (*callback)(struct sw_flow *, void *), - void *private) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - struct sw_flow *flow; - unsigned long start; - - start = ~position->private[0]; - LIST_FOR_EACH (flow, struct sw_flow, iter_node, &tl->iter_flows) { - if (flow->serial <= start - && flow_matches_2wild(key, &flow->key) - && flow_has_out_port(flow, out_port)) { - int error = callback(flow, private); - if (error) { - position->private[0] = ~(flow->serial - 1); - return error; - } - } - } - return 0; -} - -static void table_linear_stats(struct sw_table *swt, - struct sw_table_stats *stats) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - stats->name = "linear"; - stats->wildcards = OFPFW_ALL; - stats->n_flows = tl->n_flows; - stats->max_flows = tl->max_flows; - stats->n_lookup = swt->n_lookup; - stats->n_matched = swt->n_matched; -} - - -struct sw_table *table_linear_create(unsigned int max_flows) -{ - struct sw_table_linear *tl; - struct sw_table *swt; - - tl = calloc(1, sizeof *tl); - if (tl == NULL) - return NULL; - - swt = &tl->swt; - swt->lookup = table_linear_lookup; - swt->insert = table_linear_insert; - swt->modify = table_linear_modify; - swt->has_conflict = table_linear_has_conflict; - swt->delete = table_linear_delete; - swt->timeout = table_linear_timeout; - swt->destroy = table_linear_destroy; - swt->iterate = table_linear_iterate; - swt->stats = table_linear_stats; - - tl->max_flows = max_flows; - tl->n_flows = 0; - list_init(&tl->flows); - list_init(&tl->iter_flows); - tl->next_serial = 0; - - return swt; -} diff --git a/openflow/udatapath/table.h b/openflow/udatapath/table.h deleted file mode 100644 index 1312e3c9..00000000 --- a/openflow/udatapath/table.h +++ /dev/null @@ -1,150 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -/* Individual switching tables. Generally grouped together in a chain (see - * chain.h). */ - -#ifndef TABLE_H -#define TABLE_H 1 - -#include -#include - -struct datapath; /* Forward declaration for delete operation */ -struct sw_flow; -struct sw_flow_key; -struct ofp_action_header; -struct list; - -/* Table statistics. */ -struct sw_table_stats { - const char *name; /* Human-readable name. */ - uint32_t wildcards; /* Bitmap of OFPFW_* wildcards that are - supported by the table. */ - unsigned int n_flows; /* Number of active flows. */ - unsigned int max_flows; /* Flow capacity. */ - unsigned long int n_lookup; /* Number of packets looked up. */ - unsigned long int n_matched; /* Number of packets that have hit. */ -}; - -/* Position within an iteration of a sw_table. - * - * The contents are private to the table implementation, except that a position - * initialized to all-zero-bits represents the start of a table. */ -struct sw_table_position { - unsigned long private[4]; -}; - -/* A single table of flows. */ -struct sw_table { - /* The number of packets that have been looked up and matched, - * respecitvely. To make these 100% accurate, they should be atomic. - * However, we're primarily concerned about speed. */ - unsigned long long n_lookup; - unsigned long long n_matched; - - /* Searches 'table' for a flow matching 'key', which must not have any - * wildcard fields. Returns the flow if successful, a null pointer - * otherwise. */ - struct sw_flow *(*lookup)(struct sw_table *table, - const struct sw_flow_key *key); - - /* Inserts 'flow' into 'table', replacing any duplicate flow. Returns - * 0 if successful or a negative error. Error can be due to an - * over-capacity table or because the flow is not one of the kind that - * the table accepts. - * - * If successful, 'flow' becomes owned by 'table', otherwise it is - * retained by the caller. */ - int (*insert)(struct sw_table *table, struct sw_flow *flow); - - /* Modifies the actions in 'table' that match 'key'. If 'strict' - * set, wildcards and priority must match. Returns the number of flows - * that were modified. */ - int (*modify)(struct sw_table *table, const struct sw_flow_key *key, - uint16_t priority, int strict, - const struct ofp_action_header *actions, size_t actions_len); - - /* Checks whether 'table' has an equal priotiry entry of thethat conflicts - * with 'key'. If 'strict' is set, wildcards must match. - * Returns the number of flows that were modified. */ - int (*has_conflict)(struct sw_table *table, const struct sw_flow_key *key, - uint16_t priority, int strict); - - /* Deletes from 'table' any and all flows that match 'key' from - * 'table'. If 'out_port' is not OFPP_NONE, then matching entries - * must have that port as an argument for an output action. If - * 'strict' is set, wildcards and priority must match. Returns the - * number of flows that were deleted. */ - int (*delete)(struct datapath *dp, struct sw_table *table, - const struct sw_flow_key *key, - uint16_t out_port, uint16_t priority, int strict); - - /* Performs timeout processing on all the flow entries in 'table'. - * Appends all the flow entries removed from 'table' to 'deleted' for the - * caller to free. */ - void (*timeout)(struct sw_table *table, struct list *deleted); - - /* Destroys 'table', which must not have any users. */ - void (*destroy)(struct sw_table *table); - - /* Iterates through the flow entries in 'table', passing each one - * matches 'key' and output port 'out_port' to 'callback'. The - * callback function should return 0 to continue iteration or a - * nonzero error code to stop. The iterator function returns either - * 0 if the table iteration completed or the value returned by the - * callback function otherwise. - * - * The iteration starts at 'position', which may be initialized to - * all-zero-bits to iterate from the beginning of the table. If the - * iteration terminates due to an error from the callback function, - * 'position' is updated to a value that can be passed back to the - * iterator function to resume iteration later with the following - * flow. */ - int (*iterate)(struct sw_table *table, - const struct sw_flow_key *key, uint16_t out_port, - struct sw_table_position *position, - int (*callback)(struct sw_flow *flow, void *private), - void *private); - - /* Dumps statistics for 'table' into 'stats'. */ - void (*stats)(struct sw_table *table, struct sw_table_stats *stats); -}; - -struct sw_table *table_hash_create(unsigned int polynomial, - unsigned int n_buckets); -struct sw_table *table_hash2_create(unsigned int poly0, unsigned int buckets0, - unsigned int poly1, unsigned int buckets1); -struct sw_table *table_linear_create(unsigned int max_flows); - -#endif /* table.h */ diff --git a/openflow/udatapath/udatapath.c b/openflow/udatapath/udatapath.c deleted file mode 100644 index a4446575..00000000 --- a/openflow/udatapath/udatapath.c +++ /dev/null @@ -1,345 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "command-line.h" -#include "daemon.h" -#include "datapath.h" -#include "fault.h" -#include "openflow/openflow.h" -#include "poll-loop.h" -#include "queue.h" -#include "util.h" -#include "rconn.h" -#include "timeval.h" -#include "vconn.h" -#include "dirs.h" -#include "vconn-ssl.h" -#include "vlog-socket.h" - -#if defined(OF_HW_PLAT) -#include -#endif - -#define THIS_MODULE VLM_udatapath -#include "vlog.h" - -/* Strings to describe the manufacturer, hardware, and software. This data - * is queriable through the switch description stats message. */ -char mfr_desc[DESC_STR_LEN] = "Stanford University"; -char hw_desc[DESC_STR_LEN] = "Reference Userspace Switch"; -char sw_desc[DESC_STR_LEN] = VERSION BUILDNR; -char dp_desc[DESC_STR_LEN] = ""; -char serial_num[SERIAL_NUM_LEN] = "None"; - -static void parse_options(int argc, char *argv[]); -static void usage(void) NO_RETURN; - -static struct datapath *dp; -static uint64_t dpid = UINT64_MAX; -static char *port_list; -static char *local_port = "tap:"; -static uint16_t num_queues = NETDEV_MAX_QUEUES; - -static void add_ports(struct datapath *dp, char *port_list); - -/* Need to treat this more generically */ -#if defined(UDATAPATH_AS_LIB) -#define OFP_FATAL(_er, _str, args...) do { \ - fprintf(stderr, _str, ## args); \ - return -1; \ - } while (0) -#else -#define OFP_FATAL(_er, _str, args...) ofp_fatal(_er, _str, ## args) -#endif - -#if !defined(UDATAPATH_AS_LIB) -int -main(int argc, char *argv[]) -{ - return udatapath_cmd(argc, argv); -} -#endif - -int -udatapath_cmd(int argc, char *argv[]) -{ - int n_listeners; - int error; - int i; - - set_program_name(argv[0]); - register_fault_handlers(); - time_init(); - vlog_init(); - parse_options(argc, argv); - signal(SIGPIPE, SIG_IGN); - - if (argc - optind < 1) { - OFP_FATAL(0, "at least one listener argument is required; " - "use --help for usage"); - } - - error = dp_new(&dp, dpid); - - n_listeners = 0; - for (i = optind; i < argc; i++) { - const char *pvconn_name = argv[i]; - struct pvconn *pvconn; - int retval; - - retval = pvconn_open(pvconn_name, &pvconn); - if (!retval || retval == EAGAIN) { - dp_add_pvconn(dp, pvconn); - n_listeners++; - } else { - ofp_error(retval, "opening %s", pvconn_name); - } - } - if (!n_listeners) { - OFP_FATAL(0, "could not listen for any connections"); - } - - if (port_list) { - add_ports(dp, port_list); - } - if (local_port) { - error = dp_add_local_port(dp, local_port, 0); - if (error) { - OFP_FATAL(error, "failed to add local port %s", local_port); - } - } - - error = vlog_server_listen(NULL, NULL); - if (error) { - OFP_FATAL(error, "could not listen for vlog connections"); - } - - die_if_already_running(); - daemonize(); - - for (;;) { - dp_run(dp); - dp_wait(dp); - poll_block(); - } - - return 0; -} - -static void -add_ports(struct datapath *dp, char *port_list) -{ - char *port, *save_ptr; - - /* Glibc 2.7 has a bug in strtok_r when compiling with optimization that - * can cause segfaults here: - * http://sources.redhat.com/bugzilla/show_bug.cgi?id=5614. - * Using ",," instead of the obvious "," works around it. */ - for (port = strtok_r(port_list, ",,", &save_ptr); port; - port = strtok_r(NULL, ",,", &save_ptr)) { - int error = dp_add_port(dp, port, num_queues); - if (error) { - ofp_fatal(error, "failed to add port %s", port); - } - } -} - -static void -parse_options(int argc, char *argv[]) -{ - enum { - OPT_MFR_DESC = UCHAR_MAX + 1, - OPT_HW_DESC, - OPT_SW_DESC, - OPT_DP_DESC, - OPT_SERIAL_NUM, - OPT_BOOTSTRAP_CA_CERT, - OPT_NO_LOCAL_PORT, - OPT_NO_SLICING - }; - - static struct option long_options[] = { - {"interfaces", required_argument, 0, 'i'}, - {"local-port", required_argument, 0, 'L'}, - {"no-local-port", no_argument, 0, OPT_NO_LOCAL_PORT}, - {"datapath-id", required_argument, 0, 'd'}, - {"verbose", optional_argument, 0, 'v'}, - {"help", no_argument, 0, 'h'}, - {"version", no_argument, 0, 'V'}, - {"no-slicing", no_argument, 0, OPT_NO_SLICING}, - {"mfr-desc", required_argument, 0, OPT_MFR_DESC}, - {"hw-desc", required_argument, 0, OPT_HW_DESC}, - {"sw-desc", required_argument, 0, OPT_SW_DESC}, - {"dp_desc", required_argument, 0, OPT_DP_DESC}, - {"serial_num", required_argument, 0, OPT_SERIAL_NUM}, - DAEMON_LONG_OPTIONS, -#ifdef HAVE_OPENSSL - VCONN_SSL_LONG_OPTIONS - {"bootstrap-ca-cert", required_argument, 0, OPT_BOOTSTRAP_CA_CERT}, -#endif - {0, 0, 0, 0}, - }; - char *short_options = long_options_to_short_options(long_options); - - for (;;) { - int indexptr; - int c; - - c = getopt_long(argc, argv, short_options, long_options, &indexptr); - if (c == -1) { - break; - } - - switch (c) { - case 'd': - if (strlen(optarg) != 12 - || strspn(optarg, "0123456789abcdefABCDEF") != 12) { - ofp_fatal(0, "argument to -d or --datapath-id must be " - "exactly 12 hex digits"); - } - dpid = strtoll(optarg, NULL, 16); - if (!dpid) { - ofp_fatal(0, "argument to -d or --datapath-id must " - "be nonzero"); - } - break; - - case 'h': - usage(); - - case 'V': - printf("%s %s compiled "__DATE__" "__TIME__"\n", - program_name, VERSION BUILDNR); - exit(EXIT_SUCCESS); - - case 'v': - vlog_set_verbosity(optarg); - break; - - case 'i': - if (!port_list) { - port_list = optarg; - } else { - port_list = xasprintf("%s,%s", port_list, optarg); - } - break; - - case 'L': - local_port = optarg; - break; - - case OPT_NO_LOCAL_PORT: - local_port = NULL; - break; - - case OPT_MFR_DESC: - strncpy(mfr_desc, optarg, sizeof mfr_desc); - break; - - case OPT_HW_DESC: - strncpy(hw_desc, optarg, sizeof hw_desc); - break; - - case OPT_SW_DESC: - strncpy(sw_desc, optarg, sizeof sw_desc); - break; - - case OPT_DP_DESC: - strncpy(dp_desc, optarg, sizeof dp_desc); - break; - - case OPT_SERIAL_NUM: - strncpy(serial_num, optarg, sizeof serial_num); - break; - - case OPT_NO_SLICING: - num_queues = 0; - break; - - DAEMON_OPTION_HANDLERS - -#ifdef HAVE_OPENSSL - VCONN_SSL_OPTION_HANDLERS - - case OPT_BOOTSTRAP_CA_CERT: - vconn_ssl_set_ca_cert_file(optarg, true); - break; -#endif - - case '?': - exit(EXIT_FAILURE); - - default: - abort(); - } - } - free(short_options); -} - -static void -usage(void) -{ - printf("%s: userspace OpenFlow datapath\n" - "usage: %s [OPTIONS] LISTEN...\n" - "where LISTEN is a passive OpenFlow connection method on which\n" - "to listen for incoming connections from the secure channel.\n", - program_name, program_name); - vconn_usage(false, true, false); - printf("\nConfiguration options:\n" - " -i, --interfaces=NETDEV[,NETDEV]...\n" - " add specified initial switch ports\n" - " -L, --local-port=NETDEV set network device for local port\n" - " --no-local-port disable local port\n" - " -d, --datapath-id=ID Use ID as the OpenFlow switch ID\n" - " (ID must consist of 12 hex digits)\n" - " --no-slicing disable slicing\n" - "\nOther options:\n" - " -D, --detach run in background as daemon\n" - " -P, --pidfile[=FILE] create pidfile (default: %s/ofdatapath.pid)\n" - " -f, --force with -P, start even if already running\n" - " -v, --verbose=MODULE[:FACILITY[:LEVEL]] set logging levels\n" - " -v, --verbose set maximum verbosity level\n" - " -h, --help display this help message\n" - " -V, --version display version information\n", - ofp_rundir); - exit(EXIT_SUCCESS); -} diff --git a/openflow/utilities/.dirstamp b/openflow/utilities/.dirstamp deleted file mode 100644 index e69de29b..00000000 diff --git a/openflow/utilities/.gitignore b/openflow/utilities/.gitignore deleted file mode 100644 index c93169bf..00000000 --- a/openflow/utilities/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -/Makefile -/Makefile.in -/dpctl -/dpctl.8 -/ofp-discover -/ofp-discover.8 -/ofp-kill -/ofp-kill.8 -/ofp-pki -/ofp-pki-cgi -/ofp-pki.8 -/vlogconf -/vlogconf.8 diff --git a/openflow/utilities/automake.mk b/openflow/utilities/automake.mk deleted file mode 100644 index d6f79a8c..00000000 --- a/openflow/utilities/automake.mk +++ /dev/null @@ -1,45 +0,0 @@ -bin_PROGRAMS += \ - utilities/vlogconf \ - utilities/dpctl \ - utilities/ofp-discover \ - utilities/ofp-kill -bin_SCRIPTS += utilities/ofp-pki -noinst_SCRIPTS += utilities/ofp-pki-cgi utilities/ofp-parse-leaks - -EXTRA_DIST += \ - utilities/dpctl.8.in \ - utilities/ofp-discover.8.in \ - utilities/ofp-kill.8.in \ - utilities/ofp-parse-leaks.in \ - utilities/ofp-pki-cgi.in \ - utilities/ofp-pki.8.in \ - utilities/ofp-pki.in \ - utilities/vlogconf.8.in -DISTCLEANFILES += \ - utilities/dpctl.8 \ - utilities/ofp-discover.8 \ - utilities/ofp-kill.8 \ - utilities/ofp-parse-leaks \ - utilities/ofp-pki \ - utilities/ofp-pki.8 \ - utilities/ofp-pki-cgi \ - utilities/vlogconf.8 - -man_MANS += \ - utilities/dpctl.8 \ - utilities/ofp-discover.8 \ - utilities/ofp-kill.8 \ - utilities/ofp-pki.8 \ - utilities/vlogconf.8 - -utilities_dpctl_SOURCES = utilities/dpctl.c -utilities_dpctl_LDADD = lib/libopenflow.a $(FAULT_LIBS) $(SSL_LIBS) - -utilities_vlogconf_SOURCES = utilities/vlogconf.c -utilities_vlogconf_LDADD = lib/libopenflow.a - -utilities_ofp_discover_SOURCES = utilities/ofp-discover.c -utilities_ofp_discover_LDADD = lib/libopenflow.a - -utilities_ofp_kill_SOURCES = utilities/ofp-kill.c -utilities_ofp_kill_LDADD = lib/libopenflow.a diff --git a/openflow/utilities/dpctl.8.in b/openflow/utilities/dpctl.8.in deleted file mode 100644 index 80f06bb0..00000000 --- a/openflow/utilities/dpctl.8.in +++ /dev/null @@ -1,582 +0,0 @@ -.ds PN dpctl - -.TH dpctl 8 "May 2008" "OpenFlow" "OpenFlow Manual" - -.SH NAME -dpctl \- administer OpenFlow datapaths - -.SH SYNOPSIS -.B dpctl -[\fIoptions\fR] \fIcommand \fR[\fIswitch\fR] [\fIargs\fR&...] - -.SH DESCRIPTION -The -.B dpctl -program is a command line tool for monitoring and administering OpenFlow -datapaths. It is able to show the current state of a datapath, -including features, configuration, and tables entries. When using the -OpenFlow kernel module, -.B dpctl -is used to add, delete, modify, and monitor datapaths. - -Most \fBdpctl\fR commands take an argument that specifies the -method for connecting to an OpenFlow switch. The following connection -methods are supported: - -.TP -\fBnl:\fIdp_idx\fR -The local Netlink datapath numbered \fIdp_idx\fR. This form requires -that the local host has the OpenFlow kernel module for Linux loaded. - -.TP -\fBssl:\fIhost\fR[\fB:\fIport\fR] -The specified SSL \fIport\fR (default: 6633) on the given remote -\fIhost\fR. The \fB--private-key\fR, \fB--certificate\fR, and -\fB--ca-cert\fR options are mandatory when this form is used. - -.TP -\fBtcp:\fIhost\fR[\fB:\fIport\fR] -The specified TCP \fIport\fR (default: 6633) on the given remote -\fIhost\fR. - -.TP -\fBunix:\fIfile\fR -The Unix domain server socket named \fIfile\fR. - -.SH COMMANDS - -With the \fBdpctl\fR program, datapaths running in the kernel can be -created, deleted, and modified. A single machine may -host up to 32 datapaths (numbered 0 to 31). In most situations, -a machine hosts only one datapath. - -A newly created datapath is not associated with any of the -host's network devices thus does not process any incoming -traffic. To intercept and process traffic on a given network device, the -network device must be explicitly added to a datapath through the -\fBaddif\fR command. - -The following commands manage local datapaths. - -.TP -\fBadddp nl:\fIdp_idx\fR -Creates datapath numbered \fIdp_idx\fR on the local host. This will -fail if \fIdp_idx\fR is not in the range 0 to 31, or if the datapath -with that number already exists on the host. - -.TP -\fBdeldp nl:\fIdp_idx\fR -Deletes datapath \fIdp_idx\fR on the local host. \fIdp_idx\fR must be -an existing datapath. All of a datapath's network devices must be -explicitly removed before the datapath can be deleted (see \fBdelif\fR -command). - -.TP -\fBaddif nl:\fIdp_idx netdev\fR... -Adds each \fInetdev\fR to the list of network devices datapath -\fIdp_idx\fR monitors, where \fIdp_idx\fR is the ID of an existing -datapath, and \fInetdev\fR is the name of one of the host's -network devices, e.g. \fBeth0\fR. Once a network device has been added -to a datapath, the datapath has complete ownership of the network device's -traffic and the network device appears silent to the rest of the system. - -.TP -\fBdelif nl:\fIdp_idx netdev\fR... -Removes each \fInetdev\fR from the list of network devices datapath -\fIdp_idx\fR monitors. - -.TP -\fBget-idx \fIof_dev\fR -Prints the datapath index for OpenFlow device \fIof_dev\fR. - -.PP -The following commands can be apply to OpenFlow switches regardless of -the connection method. - -.TP -\fBshow \fIswitch\fR -Prints to the console information on datapath \fIswitch\fR including -information on its flow tables and ports. - -.TP -\fBstatus \fIswitch\fR [\fIkey\fR] -Prints to the console a series of key-value pairs that report the -status of \fIswitch\fR. If \fIkey\fR is specified, only the key-value -pairs whose key names begin with \fIkey\fR are printed. If \fIkey\fR is -omitted, all key-value pairs are printed. - -(In the OpenFlow reference implementation, the \fBstatus\fR command is -implemented in \fBofprotocol\fR(8), not in the kernel module, so the -\fBnl:\fIdp_idx\fR connection method should not be used with this -command. Instead, specify \fB-l\fR or \fB--listen\fR on the -\fBofprotocol\fR command line and tell \fBdpctl\fR to use the connection -method specified there.) - -.TP -\fBshow-protostat \fIswitch\fR -Prints to the OpenFlow protocol statiscal information of \fIswitch\fR. - -(In the OpenFlow reference implementation, the \fBshow-protostat\fR command -is implemented in \fBofprotocol\fR(8), not in the kernel module, so the -\fBnl:\fIdp_idx\fR connection method should not be used with this -command. Instead, specify \fB-l\fR or \fB--listen\fR on the -\fBofprotocol\fR command line and tell \fBdpctl\fR to use the connection -method specified there.) - -.TP -\fBdump-tables \fIswitch\fR -Prints to the console statistics for each of the flow tables used by -datapath \fIswitch\fR. - -.TP -\fBdump-ports \fIswitch\fR \fR[\fIport number\fR] -Prints to the console statistics for each interface monitored by -\fIswitch\fR. If port number is specified, print statistics only for -the interface corresponding to port number. - -.TP -\fBmod-port \fIswitch\fR \fInetdev\fR \fIaction\fR -Modify characteristics of an interface monitored by \fIswitch\fR. -\fInetdev\fR can be referred to by its OpenFlow assigned port number or -the device name, e.g. \fBeth0\fR. The \fIaction\fR may be any one of the -following: - -.RS -.IP \fBup\fR -Enables the interface. This is equivalent to ``ifconfig up'' on a Unix -system. - -.IP \fBdown\fR -Disables the interface. This is equivalent to ``ifconfig down'' on a Unix -system. - -.IP \fBflood\fR -When a \fIflood\fR action is specified, traffic will be sent out this -interface. This is the default posture for monitored ports. - -.IP \fBnoflood\fR -When a \fIflood\fR action is specified, traffic will not be sent out -this interface. This is primarily useful to prevent loops when a -spanning tree protocol is not in use. - -.RE - -.TP -\fBdump-flows \fIswitch \fR[\fIflows\fR] -Prints to the console all flow entries in datapath \fIswitch\fR's -tables that match \fIflows\fR. If \fIflows\fR is omitted, all flows -except emergency flows in the datapath flows are retrieved. -See \fBFLOW SYNTAX\fR, below, for the syntax of \fIflows\fR. - -.TP -\fBdesc \fIswitch \fIstring -Sets the switch description (as returned in ofp_desc_stats) to -\fIstring (max length is DESC_STR_LEN). - -.TP -\fBdump-aggregate \fIswitch \fR[\fIflows\fR] -Prints to the console aggregate statistics for flows in datapath -\fSWITCH\fR's tables that match \fIflows\fR. If \fIflows\fR is omitted, -the statistics are aggregated across all flows in the datapath's flow -tables. See \fBFLOW SYNTAX\fR, below, for the syntax of \fIflows\fR. - -.TP -\fBadd-flow \fIswitch flow\fR -Add the flow entry as described by \fIflow\fR to the datapath \fIswitch\fR's -tables. The flow entry is in the format described in \fBFLOW SYNTAX\fR, -below. - -.TP -\fBadd-flows \fIswitch file\fR -Add flow entries as described in \fIfile\fR to the datapath \fIswitch\fR's -tables. Each line in \fIfile\fR is a flow entry in the format -described in \fBFLOW SYNTAX\fR, below. - -.TP -\fBmod-flows \fIswitch flow\fR -Modify the actions in entries from the datapath \fIswitch\fR's tables -that match \fIflow\fR. When invoked with the \fB--strict\fR option, -wildcards are not treated as active for matching purposes. See -\fBFLOW SYNTAX\fR, below, for the syntax of \fIflows\fR. - -.TP -\fBdel-flows \fIswitch \fR[\fIflow\fR] -Deletes entries from the datapath \fIswitch\fR's tables that match -\fIflow\fR. When invoked with the \fB--strict\fR option, wildcards are -not treated as active for matching purposes. If \fIflow\fR is -omitted and the \fB--strict\fR option is not used, all flows in the -datapath's tables are removed. See \fBFLOW SYNTAX\fR, below, for the -syntax of \fIflows\fR. - -.TP -\fBmonitor \fIswitch\fR -Connects to \fIswitch\fR and prints to the console all OpenFlow -messages received. Usually, \fIswitch\fR should specify a connection -named on \fBofprotocol\fR(8)'s \fB-m\fR or \fB--monitor\fR command line -option, in which the messages printed will be all those sent or -received by \fBofprotocol\fR to or from the kernel datapath module. A -\fIswitch\fR of the form \fBnl:\fIdp_idx\fR will print all -asynchronously generated OpenFlow messages (such as packet-in -messages), but it will not print any messages sent to the kernel by -\fBofprotocol\fR and other processes, nor will it print replies sent by -the kernel in response to those messages. - -.PP -The following commands monitor and control the egress queue -configuration for an OpenFlow switch if the switch supports such -operations. After a queue is created with the add or modify -operation, the OpenFlow enqueue action may be specified to -direct packets to a particular queue. Queues are associated with -specific ports (so the same queue-id may be used on different -ports and this will refer to different queues). The only -characteristic that may be configured for queues is the minimum -bandwidth guarantee. This parameter is specified in tenths of -a percent (so full link bandwidth is 1000). - -.TP -\fBadd-queue \fIswitch\fR \fIport\fR \fIq-id\fR [\fIbandwidth\fR] -Connect to \fIswitch\fR and add an egress queue identified as \fIq-id\fR -for \fIport\fR. If -specified, \fIbandwidth\fR indicates the minimum bandwidth guarantee -for the queue and is specified in tenths of a -percent. This is the only characteristic of the queue that -may be configured. - -.TP -\fBmod-queue \fIswitch\fR \fIport\fR \fIq-id\fR \fIbandwidth\fR -Connect to \fIswitch\fR and modify the bandwidth setting for an egress -queue identified as \fIq-id\fR -for \fIport\fR. The queue need not have been created with \fBadd-queue\fR -previously. The parameter \fIbandwidth\fR indicates the minimum -bandwidth guarantee for the queue and is specified in tenths of a -percent. This is the only characteristic -of the queue that may be configured. - -.TP -\fBdel-queue \fIswitch\fR \fIport\fR \fIq-id\fR -Delete an egress queue identified as \fIq-id\fR for \fIport\fR which -had been created by \fBadd-queue\fR or \fBmod-queue\fR. - -.TP -\fBdump-queue \fIswitch\fR [\fIport\fR [\fIq-id\fR]] -Dump that current queue configuration. A port may be specified. -If it is, a queue-id may also be specified. - -.PP -The following commands can be used regardless of the connection -method. They apply to OpenFlow switches and controllers. - -.TP -\fBprobe \fIvconn\fR -Connects to \fIvconn\fR and sends a single OpenFlow echo-request -packet and waits for the response. With the \fB-t\fR or -\fB--timeout\fR option, this command can test whether an OpenFlow -switch or controller is up and running. - -.TP -\fBping \fIvconn \fR[\fIn\fR] -Sends a series of 10 echo request packets to \fIvconn\fR and times -each reply. The echo request packets consist of an OpenFlow header -plus \fIn\fR bytes (default: 64) of randomly generated payload. This -measures the latency of individual requests. - -.TP -\fBbenchmark \fIvconn n count\fR -Sends \fIcount\fR echo request packets that each consist of an -OpenFlow header plus \fIn\fR bytes of payload and waits for each -response. Reports the total time required. This is a measure of the -maximum bandwidth to \fIvconn\fR for round-trips of \fIn\fR-byte -messages. - -.SH "FLOW SYNTAX" - -Some \fBdpctl\fR commands accept an argument that describes a flow or -flows. Such flow descriptions comprise a series -\fIfield\fB=\fIvalue\fR assignments, separated by commas or white -space. - -The following field assignments describe how a flow matches a packet. -If any of these assignments is omitted from the flow syntax, the field -is treated as a wildcard; thus, if all of them are omitted, the -resulting flow matches all packets. The string \fB*\fR or \fBANY\fR -may be specified a value to explicitly mark any of these fields as a -wildcard. - -.IP \fBin_port=\fIport_no\fR -Matches physical port \fIport_no\fR. Switch ports are numbered as -displayed by \fBdpctl show\fR. - -.IP \fBdl_vlan=\fIvlan\fR -Matches IEEE 802.1q virtual LAN tag \fIvlan\fR. Specify \fB0xffff\fR -as \fIvlan\fR to match packets that are not tagged with a virtual LAN; -otherwise, specify a number between 0 and 4095, inclusive, as the -12-bit VLAN ID to match. - -.IP \fBdl_src=\fImac\fR -Matches Ethernet source address \fImac\fR, which should be specified -as 6 pairs of hexadecimal digits delimited by colons, -e.g. \fB00:0A:E4:25:6B:B0\fR. - -.IP \fBdl_dst=\fImac\fR -Matches Ethernet destination address \fImac\fR. - -.IP \fBdl_type=\fIethertype\fR -Matches Ethernet protocol type \fIethertype\fR, which should be -specified as a integer between 0 and 65535, inclusive, either in -decimal or as a hexadecimal number prefixed by \fB0x\fR, -e.g. \fB0x0806\fR to match ARP packets. - -.IP \fBnw_src=\fIip\fR[\fB/\fInetmask\fR] -Matches IPv4 source address \fIip\fR, which should be specified as an -IP address or host name, e.g. \fB192.168.1.1\fR or -\fBwww.example.com\fR. The optional \fInetmask\fR allows matching -only on an IPv4 address prefix. It may be specified as a dotted quad -(e.g. \fB192.168.1.0/255.255.255.0\fR) or as a count of bits -(e.g. \fB192.168.1.0/24\fR). - -.IP \fBnw_dst=\fIip\fR[\fB/\fInetmask\fR] -Matches IPv4 destination address \fIip\fR. - -.IP \fBnw_proto=\fIproto\fR -Matches IP protocol type \fIproto\fR, which should be specified as a -decimal number between 0 and 255, inclusive, e.g. 6 to match TCP -packets. - -.IP \fBnw_tos=\fItos/dscp\fR -Matches ToS/DSCP (only 6-bits, not modify reserved 2-bits for future -use) field of IPv4 header \fItos/dscp\fR, which should be specified as -a decimal number between 0 and 255, inclusive. - -.IP \fBtp_src=\fIport\fR -Matches UDP or TCP source port \fIport\fR, which should be specified -as a decimal number between 0 and 65535, inclusive, e.g. 80 to match -packets originating from a HTTP server. - -.IP \fBtp_dst=\fIport\fR -Matches UDP or TCP destination port \fIport\fR. - -.IP \fBicmp_type=\fItype\fR -Matches ICMP message with \fItype\fR, which should be specified as a decimal -number between 0 and 255, inclusive. - -.IP \fBicmp_code=\fIcode\fR -Matches ICMP messages with \fIcode\fR. - -.PP -The following shorthand notations are also available: - -.IP \fBip\fR -Same as \fBdl_type=0x0800\fR. - -.IP \fBicmp\fR -Same as \fBdl_type=0x0800,nw_proto=1\fR. - -.IP \fBtcp\fR -Same as \fBdl_type=0x0800,nw_proto=6\fR. - -.IP \fBudp\fR -Same as \fBdl_type=0x0800,nw_proto=17\fR. - -.IP \fBarp\fR -Same as \fBdl_type=0x0806\fR. - -.PP -The \fBadd-flow\fR and \fBadd-flows\fR commands require an additional field: - -.IP \fIactions\fB=\fItarget\fR[\fB,\fItarget\fR...]\fR -Specifies a comma-separated list of actions to take on a packet when the -flow entry matches. The \fItarget\fR may be a decimal port number -designating the physical port on which to output the packet, or one of -the following keywords: - -.RS -.IP \fBoutput\fR:\fIport\fR -Outputs the packet on the port specified by \fIport\fR. - -.IP \fBenqueue\fR:\fIport\fR:\fIq-id\fR -Enqueue the packet to the queue specified by \fIq-id\fR on the port -specified by \fIport\fR. See \fBadd-queue\fR and related commands -in this manpage above. - -.IP \fBnormal\fR -Subjects the packet to the device's normal L2/L3 processing. (This -action is not implemented by all OpenFlow switches.) - -.IP \fBflood\fR -Outputs the packet on all switch physical ports other than the port on -which it was received and any ports on which flooding is disabled -(typically, these would be ports disabled by the IEEE 802.1D spanning -tree protocol). - -.IP \fBall\fR -Outputs the packet on all switch physical ports other than the port on -which it was received. - -.IP \fBcontroller\fR:\fImax_len\fR -Sends the packet to the OpenFlow controller as a ``packet in'' -message. If \fImax_len\fR is a number, then it specifies the maximum -number of bytes that should be sent. If \fImax_len\fR is \fBALL\fR or -omitted, then the entire packet is sent. - -.IP \fBlocal\fR -Outputs the packet on the ``local port,'' which corresponds to the -\fBof\fIn\fR network device (see \fBCONTACTING THE CONTROLLER\fR in -\fBofprotocol\fR(8) for information on the \fBof\fIn\fR network device). - -.IP \fBmod_vlan_vid\fR:\fIvlan_vid\fR -Modifies the VLAN id on a packet. The VLAN tag is added or modified -as necessary to match the value specified. If the VLAN tag is added, -a priority of zero is used (see the \fBmod_vlan_pcp\fR action to set -this). - -.IP \fBmod_vlan_pcp\fR:\fIvlan_pcp\fR -Modifies the VLAN priority on a packet. The VLAN tag is added or modified -as necessary to match the value specified. Valid values are between 0 -(lowest) and 7 (highest). If the VLAN tag is added, a vid of zero is used -(see the \fBmod_vlan_vid\fR action to set this). - -.IP \fBmod_dl_dst\fR:\fIdst_mac\fR -Modifies the destination mac address on a packet, e.g., actions=mod_dl_dst:12:34:56:78:9a:bc - -.IP \fBmod_dl_src\fR:\fIsrc_mac\fR -Modifies the source mac address on a packet, e.g., actions=mod_dl_src:12:34:56:78:9a:bc - -.IP \fBmod_nw_tos\fR:\fItos/dscp\fR -Modifies the ToS/DSCP (only 6-bits, not modify reserved 2-bits for future use) field of IPv4 header on a packet. - -.IP \fBstrip_vlan\fR -Strips the VLAN tag from a packet if it is present. -.RE - -.IP -(The OpenFlow protocol supports other actions that \fBdpctl\fR does -not yet expose to the user.) - -.PP -The \fBadd-flow\fR, \fBadd-flows\fR, \fBdel-flows\fR, -and \fBdel-emerg-flows\fR commands support an additional optional field: - -.IP \fBpriority=\fIvalue\fR -Sets the priority of the flow to be added or deleted to \fIvalue\fR, -which should be a number between 0 and 65535, inclusive. If this -field is not specified, it defaults to 32768. - -.PP -The \fBadd-flow\fR and \fBadd-flows\fR commands support -additional optional fields: - -.TP -\fBidle_timeout=\fIseconds\fR -Causes the flow to expire after the given number of seconds of -inactivity. A value of 0 prevents a flow from expiring due to -inactivity. The default is 60 seconds. - -.IP \fBhard_timeout=\fIseconds\fR -Causes the flow to expire after the given number of seconds, -regardless of activity. A value of 0 (the default) gives the flow no -hard expiration deadline. - -.PP -The \fBdump-flows\fR, \fBdump-aggregate\fR and \fBdel-flows\fR -commands support the additional optional field: - -.TP -\fBout_port=\fIport\fR -If set, a matching flow must include an output action to \fIport\fR. - -.PP -\fBadd-flow\fR, \fBadd-flows\fR, \fBdel-flows\fR, \fBdump-flows\fR, -and \fBdump-aggregate\fR commands support the additional -optional field: - -.IP \fBtable=\fInumber\fR -If specified, limits the flows about which statistics are gathered to -those in the table with the given \fInumber\fR. Normal (non emergency) -tables are numbered as shown by the \fBdump-tables\fR command. - -If this field is not specified, or if \fInumber\fR is given as -\fB255\fR, statistics are gathered about flows from all normal (non -emergency) tables and flow manipulations are applied to notmal tables. - -If this field is given as \fB254\fR, statistics are gathered about -flows from emergency table and flow manipulations are applied to -emergency table. - -.SH OPTIONS -.TP -\fB--strict\fR -Uses strict matching when running flow modification commands. - -.TP -\fB-t\fR, \fB--timeout=\fIsecs\fR -Limits \fBdpctl\fR runtime to approximately \fIsecs\fR seconds. If -the timeout expires, \fBdpctl\fR will exit with a \fBSIGALRM\fR -signal. - -.TP -\fB-p\fR, \fB--private-key=\fIprivkey.pem\fR -Specifies a PEM file containing the private key used as the -identity for SSL connections to a switch. - -.TP -\fB-c\fR, \fB--certificate=\fIcert.pem\fR -Specifies a PEM file containing a certificate, signed by the -controller's certificate authority (CA), that certifies the -private key to identify a trustworthy controller. - -.TP -\fB-C\fR, \fB--ca-cert=\fIcacert.pem\fR -Specifies a PEM file containing the CA certificate used to verify that -a switch is trustworthy. - -.so lib/vlog.man -.so lib/common.man - -.SH EXAMPLES - -A typical dpctl command sequence for controlling an OpenFlow kernel module: -.nf -.TP -Create datapath numbered 0: - -.B % dpctl adddp nl:0 - -.TP -Add two network devices to the new datapath: - -.B % dpctl addif nl:0 eth0 -.B % dpctl addif nl:0 eth1 - -.TP -Monitor traffic received by the datapath (exit with control-C): - -.B % dpctl monitor nl:0 - - -.TP -View the datapath's table stats after some traffic has passed through: - -.B % dpctl dump-tables nl:0 - -.TP -View the flow entries in the datapath: - -.B % dpctl dump-flows nl:0 - -.TP -Remove network devices from the datapath when finished: - -.B % dpctl delif nl:0 eth0 -.B % dpctl delif nl:0 eth1 - -.TP -Delete the datapath: - -.B % dpctl deldp nl:0 -.fi -.SH "SEE ALSO" - -.BR ofprotocol (8), -.BR controller (8), -.BR ofdatapath (8), -.BR vlogconf (8) diff --git a/openflow/utilities/dpctl.c b/openflow/utilities/dpctl.c deleted file mode 100644 index 0406d9b5..00000000 --- a/openflow/utilities/dpctl.c +++ /dev/null @@ -1,1772 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_NETLINK -#include "netdev.h" -#include "netlink.h" -#include "openflow/openflow-netlink.h" -#endif - -#include "command-line.h" -#include "compiler.h" -#include "dpif.h" -#include "openflow/nicira-ext.h" -#include "openflow/openflow-ext.h" -#include "ofp-print.h" -#include "ofpbuf.h" -#include "openflow/openflow.h" -#include "packets.h" -#include "random.h" -#include "socket-util.h" -#include "timeval.h" -#include "util.h" -#include "vconn-ssl.h" -#include "vconn.h" - -#include "xtoxll.h" -#include "ofpstat.h" -#include "openflow/private-ext.h" - -#include "vlog.h" -#define THIS_MODULE VLM_dpctl - -#define DEFAULT_IDLE_TIMEOUT 60 - -/* Maximum size of action buffer for adding and modify flows */ -#define MAX_ACT_LEN 60 - -#define MOD_PORT_CMD_UP "up" -#define MOD_PORT_CMD_DOWN "down" -#define MOD_PORT_CMD_FLOOD "flood" -#define MOD_PORT_CMD_NOFLOOD "noflood" - - -/* Settings that may be configured by the user. */ -struct settings { - bool strict; /* Use strict matching for flow mod commands */ -}; - -struct command { - const char *name; - int min_args; - int max_args; - void (*handler)(const struct settings *, int argc, char *argv[]); -}; - -static struct command all_commands[]; - -static void usage(void) NO_RETURN; -static void parse_options(int argc, char *argv[], struct settings *); - -int main(int argc, char *argv[]) -{ - struct settings s; - struct command *p; - - set_program_name(argv[0]); - time_init(); - vlog_init(); - parse_options(argc, argv, &s); - signal(SIGPIPE, SIG_IGN); - - argc -= optind; - argv += optind; - if (argc < 1) - ofp_fatal(0, "missing command name; use --help for help"); - - for (p = all_commands; p->name != NULL; p++) { - if (!strcmp(p->name, argv[0])) { - int n_arg = argc - 1; - if (n_arg < p->min_args) - ofp_fatal(0, "'%s' command requires at least %d arguments", - p->name, p->min_args); - else if (n_arg > p->max_args) - ofp_fatal(0, "'%s' command takes at most %d arguments", - p->name, p->max_args); - else { - p->handler(&s, argc, argv); - if (ferror(stdout)) { - ofp_fatal(0, "write to stdout failed"); - } - if (ferror(stderr)) { - ofp_fatal(0, "write to stderr failed"); - } - exit(0); - } - } - } - ofp_fatal(0, "unknown command '%s'; use --help for help", argv[0]); - - return 0; -} - -static void -parse_options(int argc, char *argv[], struct settings *s) -{ - enum { - OPT_STRICT = UCHAR_MAX + 1 - }; - static struct option long_options[] = { - {"timeout", required_argument, 0, 't'}, - {"verbose", optional_argument, 0, 'v'}, - {"strict", no_argument, 0, OPT_STRICT}, - {"help", no_argument, 0, 'h'}, - {"version", no_argument, 0, 'V'}, - VCONN_SSL_LONG_OPTIONS - {0, 0, 0, 0}, - }; - char *short_options = long_options_to_short_options(long_options); - - /* Set defaults that we can figure out before parsing options. */ - s->strict = false; - - for (;;) { - unsigned long int timeout; - int c; - - c = getopt_long(argc, argv, short_options, long_options, NULL); - if (c == -1) { - break; - } - - switch (c) { - case 't': - timeout = strtoul(optarg, NULL, 10); - if (timeout <= 0) { - ofp_fatal(0, "value %s on -t or --timeout is not at least 1", - optarg); - } else { - time_alarm(timeout); - } - break; - - case 'h': - usage(); - - case 'V': - printf("%s %s compiled "__DATE__" "__TIME__"\n", - program_name, VERSION BUILDNR); - exit(EXIT_SUCCESS); - - case 'v': - vlog_set_verbosity(optarg); - break; - - case OPT_STRICT: - s->strict = true; - break; - - VCONN_SSL_OPTION_HANDLERS - - case '?': - exit(EXIT_FAILURE); - - default: - abort(); - } - } - free(short_options); -} - -static void -usage(void) -{ - printf("%s: OpenFlow switch management utility\n" - "usage: %s [OPTIONS] COMMAND [ARG...]\n" -#ifdef HAVE_NETLINK - "\nFor local datapaths only:\n" - " adddp nl:DP_ID add a new local datapath DP_ID\n" - " deldp nl:DP_ID delete local datapath DP_ID\n" - " addif nl:DP_ID IFACE... add each IFACE as a port on DP_ID\n" - " delif nl:DP_ID IFACE... delete each IFACE from DP_ID\n" - " get-idx OF_DEV get datapath index for OF_DEV\n" -#endif - "\nFor local datapaths and remote switches:\n" - " show SWITCH show basic information\n" - " status SWITCH [KEY] report statistics (about KEY)\n" - " show-protostat SWITCH report protocol statistics\n" - " dump-desc SWITCH print switch description\n" - " dump-tables SWITCH print table stats\n" - " mod-port SWITCH IFACE ACT modify port behavior\n" - " dump-ports SWITCH [PORT] print port statistics\n" - " desc SWITCH STRING set switch description\n" - " dump-flows SWITCH print all flow entries\n" - " dump-flows SWITCH FLOW print matching FLOWs\n" - " dump-aggregate SWITCH print aggregate flow statistics\n" - " dump-aggregate SWITCH FLOW print aggregate stats for FLOWs\n" - " add-flow SWITCH FLOW add flow described by FLOW\n" - " add-flows SWITCH FILE add flows from FILE\n" - " mod-flows SWITCH FLOW modify actions of matching FLOWs\n" - " del-flows SWITCH [FLOW] delete matching FLOWs\n" - " monitor SWITCH print packets received from SWITCH\n" - " execute SWITCH CMD [ARG...] execute CMD with ARGS on SWITCH\n" - "Queue Ops: Q: queue-id; P: port-id; BW: perthousand bandwidth\n" - " add-queue SWITCH P Q [BW] add queue (with min bandwidth)\n" - " mod-queue SWITCH P Q BW modify queue min bandwidth\n" - " del-queue SWITCH P Q delete queue\n" - " dump-queue SWITCH [P [Q]] show queue info\n" - "\nFor local datapaths, remote switches, and controllers:\n" - " probe VCONN probe whether VCONN is up\n" - " ping VCONN [N] latency of N-byte echos\n" - " benchmark VCONN N COUNT bandwidth of COUNT N-byte echos\n" - "where each SWITCH is an active OpenFlow connection method.\n", - program_name, program_name); - vconn_usage(true, false, false); - vlog_usage(); - printf("\nOther options:\n" - " --strict use strict match for flow commands\n" - " -t, --timeout=SECS give up after SECS seconds\n" - " -h, --help display this help message\n" - " -V, --version display version information\n"); - exit(EXIT_SUCCESS); -} - -static void run(int retval, const char *message, ...) - PRINTF_FORMAT(2, 3); - -static void run(int retval, const char *message, ...) -{ - if (retval) { - va_list args; - - fprintf(stderr, "%s: ", program_name); - va_start(args, message); - vfprintf(stderr, message, args); - va_end(args); - if (retval == EOF) { - fputs(": unexpected end of file\n", stderr); - } else { - fprintf(stderr, ": %s\n", strerror(retval)); - } - - exit(EXIT_FAILURE); - } -} - -#ifdef HAVE_NETLINK -/* Netlink-only commands. */ - -static int if_up(const char *netdev_name) -{ - struct netdev *netdev; - int retval; - - retval = netdev_open(netdev_name, NETDEV_ETH_TYPE_NONE, &netdev); - if (!retval) { - retval = netdev_turn_flags_on(netdev, NETDEV_UP, true); - netdev_close(netdev); - } - return retval; -} - -static void -do_get_idx(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) -{ - int dp_idx; - - struct dpif dpif; - run(dpif_open(-1, &dpif), "opening management socket"); - dp_idx = dpif_get_idx(argv[1]); - if (dp_idx == -1) { - dpif_close(&dpif); - ofp_fatal(0, "unknown OpenFlow device: %s", argv[1]); - } - printf("%d\n", dp_idx); - dpif_close(&dpif); -} - -static int -get_dp_idx(const char *name) -{ - if (strncmp(name, "nl:", 3) - || strlen(name) < 4 - || name[strspn(name + 3, "0123456789") + 3]) { - ofp_fatal(0, "%s: argument is not of the form \"nl:DP_ID\"", name); - } - return atoi(name + 3); -} - -static void -do_add_dp(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) -{ - struct dpif dpif; - run(dpif_open(-1, &dpif), "opening management socket"); - run(dpif_add_dp(&dpif, get_dp_idx(argv[1]), NULL), "add_dp"); - dpif_close(&dpif); -} - -static void -do_del_dp(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) -{ - struct dpif dpif; - run(dpif_open(-1, &dpif), "opening management socket"); - run(dpif_del_dp(&dpif, get_dp_idx(argv[1]), NULL), "del_dp"); - dpif_close(&dpif); -} - -static void add_del_ports(int argc UNUSED, char *argv[], - int (*function)(struct dpif *, int dp_idx, - const char *netdev), - const char *operation, const char *preposition) -{ - bool failure = false; - struct dpif dpif; - int dp_idx; - int i; - - run(dpif_open(-1, &dpif), "opening management socket"); - dp_idx = get_dp_idx(argv[1]); - for (i = 2; i < argc; i++) { - int retval = function(&dpif, dp_idx, argv[i]); - if (retval) { - ofp_error(retval, "failed to %s %s %s %s", - operation, argv[i], preposition, argv[1]); - failure = true; - } - } - dpif_close(&dpif); - if (failure) { - exit(EXIT_FAILURE); - } -} - -static int ifup_and_add_port(struct dpif *dpif, int dp_idx, const char *netdev) -{ - int retval = if_up(netdev); - return retval ? retval : dpif_add_port(dpif, dp_idx, netdev); -} - -static void do_add_port(const struct settings *s UNUSED, int argc UNUSED, - char *argv[]) -{ - add_del_ports(argc, argv, ifup_and_add_port, "add", "to"); -} - -static void do_del_port(const struct settings *s UNUSED, int argc UNUSED, - char *argv[]) -{ - add_del_ports(argc, argv, dpif_del_port, "remove", "from"); -} -#endif /* HAVE_NETLINK */ - -/* Generic commands. */ - -static void -open_vconn(const char *name, struct vconn **vconnp) -{ - run(vconn_open_block(name, OFP_VERSION, vconnp), "connecting to %s", name); -} - -static void * -alloc_stats_request(size_t body_len, uint16_t type, struct ofpbuf **bufferp) -{ - struct ofp_stats_request *rq; - rq = make_openflow((offsetof(struct ofp_stats_request, body) - + body_len), OFPT_STATS_REQUEST, bufferp); - rq->type = htons(type); - rq->flags = htons(0); - return rq->body; -} - -static void -send_openflow_buffer(struct vconn *vconn, struct ofpbuf *buffer) -{ - update_openflow_length(buffer); - run(vconn_send_block(vconn, buffer), "failed to send packet to switch"); -} - -static void -dump_transaction(const char *vconn_name, struct ofpbuf *request) -{ - struct vconn *vconn; - struct ofpbuf *reply; - - update_openflow_length(request); - open_vconn(vconn_name, &vconn); - run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name); - ofp_print(stdout, reply->data, reply->size, 1); - vconn_close(vconn); -} - -static void -dump_trivial_transaction(const char *vconn_name, uint8_t request_type) -{ - struct ofpbuf *request; - make_openflow(sizeof(struct ofp_header), request_type, &request); - dump_transaction(vconn_name, request); -} - -static void -dump_stats_transaction(const char *vconn_name, struct ofpbuf *request) -{ - uint32_t send_xid = ((struct ofp_header *) request->data)->xid; - struct vconn *vconn; - bool done = false; - - open_vconn(vconn_name, &vconn); - send_openflow_buffer(vconn, request); - while (!done) { - uint32_t recv_xid; - struct ofpbuf *reply; - - run(vconn_recv_block(vconn, &reply), "OpenFlow packet receive failed"); - - recv_xid = ((struct ofp_header *) reply->data)->xid; - if (send_xid == recv_xid) { - struct ofp_stats_reply *osr; - - ofp_print(stdout, reply->data, reply->size, 1); - - osr = ofpbuf_at(reply, 0, sizeof *osr); - done = !osr || !(ntohs(osr->flags) & OFPSF_REPLY_MORE); - } else { - VLOG_DBG("received reply with xid %08"PRIx32" " - "!= expected %08"PRIx32, recv_xid, send_xid); - } - ofpbuf_delete(reply); - } - vconn_close(vconn); -} - -static void -dump_trivial_stats_transaction(const char *vconn_name, uint8_t stats_type) -{ - struct ofpbuf *request; - alloc_stats_request(0, stats_type, &request); - dump_stats_transaction(vconn_name, request); -} - -/* Get the pointer to struct member based on member offset */ -#define S_PTR(_ptr, _type, _member) \ - ((void *)(((char *)(_ptr)) + offsetof(_type, _member))) - -static void -dump_queue_stats_transaction(const char *vconn_name, uint8_t stats_type, - uint16_t port, uint32_t q_id) -{ - struct ofpbuf *request; - struct ofp_queue_stats_request *q_req; - struct ofp_stats_request *stats_req; - - alloc_stats_request(sizeof(struct ofp_queue_stats_request), - stats_type, &request); - stats_req = request->data; - q_req = S_PTR(stats_req, struct ofp_stats_request, body); - - q_req->port_no = htons(port); - q_req->queue_id = htonl(q_id); - dump_stats_transaction(vconn_name, request); -} - -static void -do_show(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) -{ - dump_trivial_transaction(argv[1], OFPT_FEATURES_REQUEST); - dump_trivial_transaction(argv[1], OFPT_GET_CONFIG_REQUEST); -} - -static void -do_status(const struct settings *s UNUSED, int argc, char *argv[]) -{ - struct nicira_header *request, *reply; - struct vconn *vconn; - struct ofpbuf *b; - - request = make_openflow(sizeof *request, OFPT_VENDOR, &b); - request->vendor = htonl(NX_VENDOR_ID); - request->subtype = htonl(NXT_STATUS_REQUEST); - if (argc > 2) { - ofpbuf_put(b, argv[2], strlen(argv[2])); - } - open_vconn(argv[1], &vconn); - run(vconn_transact(vconn, b, &b), "talking to %s", argv[1]); - vconn_close(vconn); - - if (b->size < sizeof *reply) { - ofp_fatal(0, "short reply (%zu bytes)", b->size); - } - reply = b->data; - if (reply->header.type != OFPT_VENDOR - || reply->vendor != ntohl(NX_VENDOR_ID) - || reply->subtype != ntohl(NXT_STATUS_REPLY)) { - ofp_print(stderr, b->data, b->size, 2); - ofp_fatal(0, "bad reply"); - } - - fwrite(reply + 1, b->size, 1, stdout); -} - -static void -print_protocol_stat(struct ofpstat *ofps_rcvd, struct ofpstat *ofps_sent) -{ - int i; - struct ofpstat *ifps = NULL; -#define PREFIX_STR " " -#define PREFIX_RCVD "Rcvd: " -#define PREFIX_SENT "Sent: " - - fprintf(stdout, - "OpenFlow protocol version 0x%x statisical information\n", - OFP_VERSION); - fprintf(stdout, "\n"); - - fprintf(stdout, "Protocol message:\n"); - for (i = 0; i < 2; ++i) { - ifps = i == 0 ? ofps_rcvd : ofps_sent; - fprintf(stdout, - "%s" - "%"PRIu64" total msgs, %"PRIu64" unknown msgs\n", - i == 0 ? PREFIX_RCVD : PREFIX_SENT, - ntohll(ifps->ofps_total), - ntohll(ifps->ofps_unknown)); - fprintf(stdout, - PREFIX_STR - "%"PRIu64" hello, %"PRIu64" errors, " - "%"PRIu64" echo, %"PRIu64" echo reply, " - "%"PRIu64" vendor\n", - ntohll(ifps->ofps_hello), - ntohll(ifps->ofps_error), - ntohll(ifps->ofps_echo_request), - ntohll(ifps->ofps_echo_reply), - ntohll(ifps->ofps_vendor)); - fprintf(stdout, - PREFIX_STR - "%"PRIu64" feats, %"PRIu64" feats reply\n", - ntohll(ifps->ofps_feats_request), - ntohll(ifps->ofps_feats_reply)); - fprintf(stdout, - PREFIX_STR - "%"PRIu64" get config, %"PRIu64" get config reply, " - "%"PRIu64" set config\n", - ntohll(ifps->ofps_get_config_request), - ntohll(ifps->ofps_get_config_reply), - ntohll(ifps->ofps_set_config)); - fprintf(stdout, - PREFIX_STR - "%"PRIu64" packet in, %"PRIu64" flow removed, " - "%"PRIu64" port status\n", - ntohll(ifps->ofps_packet_in), - ntohll(ifps->ofps_flow_removed), - ntohll(ifps->ofps_port_status)); - fprintf(stdout, - PREFIX_STR - "%"PRIu64" packet out, %"PRIu64" flow mod, %"PRIu64" port mod\n", - ntohll(ifps->ofps_packet_out), - ntohll(ifps->ofps_flow_mod), - ntohll(ifps->ofps_port_mod)); - fprintf(stdout, - PREFIX_STR - "%"PRIu64" stats, %"PRIu64" stats reply, " - "%"PRIu64" barrier, %"PRIu64" barrier reply\n", - ntohll(ifps->ofps_stats_request), - ntohll(ifps->ofps_stats_reply), - ntohll(ifps->ofps_barrier_request), - ntohll(ifps->ofps_barrier_reply)); - } - fprintf(stdout, "\n"); - - fprintf(stdout, "Flow manipulation:\n"); - for (i = 0; i < 2; ++i) { - ifps = i == 0 ? ofps_rcvd : ofps_sent; - fprintf(stdout, - "%s" - "%"PRIu64" add, %"PRIu64" modify, %"PRIu64" modify strict\n", - i == 0 ? PREFIX_RCVD : PREFIX_SENT, - ntohll(ifps->ofps_flow_mod_ops.add), - ntohll(ifps->ofps_flow_mod_ops.modify), - ntohll(ifps->ofps_flow_mod_ops.modify_strict)); - fprintf(stdout, - PREFIX_STR - "%"PRIu64" delete, %"PRIu64" delete strict, %"PRIu64" unknown cmd\n", - ntohll(ifps->ofps_flow_mod_ops.delete), - ntohll(ifps->ofps_flow_mod_ops.delete_strict), - ntohll(ifps->ofps_flow_mod_ops.unknown)); - } - fprintf(stdout, "\n"); - - fprintf(stdout, "Error notification:\n"); - for (i = 0; i < 2; ++i) { - ifps = i == 0 ? ofps_rcvd : ofps_sent; - fprintf(stdout, - "%s" - "%"PRIu64" hello fail: %"PRIu64" incompat, %"PRIu64" eperm\n", - i == 0 ? PREFIX_RCVD : PREFIX_SENT, - ntohll(ifps->ofps_error_type.hello_fail), - ntohll(ifps->ofps_error_code.hf_incompat), - ntohll(ifps->ofps_error_code.hf_eperm)); - fprintf(stdout, - PREFIX_STR - "%"PRIu64" bad request: %"PRIu64" version, %"PRIu64" type, " - "%"PRIu64" stat, %"PRIu64" vendor\n" - PREFIX_STR - " %"PRIu64" eperm\n", - ntohll(ifps->ofps_error_type.bad_request), - ntohll(ifps->ofps_error_code.br_bad_version), - ntohll(ifps->ofps_error_code.br_bad_type), - ntohll(ifps->ofps_error_code.br_bad_stat), - ntohll(ifps->ofps_error_code.br_bad_vendor), - ntohll(ifps->ofps_error_code.br_eperm)); - fprintf(stdout, - PREFIX_STR - "%"PRIu64" bad action: %"PRIu64" type, %"PRIu64" len, " - "%"PRIu64" vendor, %"PRIu64" vendor type\n" - PREFIX_STR - " %"PRIu64" out port, %"PRIu64" argument, %"PRIu64" eperm\n", - ntohll(ifps->ofps_error_type.bad_action), - ntohll(ifps->ofps_error_code.ba_bad_type), - ntohll(ifps->ofps_error_code.ba_bad_len), - ntohll(ifps->ofps_error_code.ba_bad_vendor), - ntohll(ifps->ofps_error_code.ba_bad_vendor_type), - ntohll(ifps->ofps_error_code.ba_bad_out_port), - ntohll(ifps->ofps_error_code.ba_bad_argument), - ntohll(ifps->ofps_error_code.ba_eperm)); - fprintf(stdout, - PREFIX_STR - "%"PRIu64" flow mod fail: %"PRIu64" all tables full, " - "%"PRIu64" overlap, %"PRIu64" eperm, %"PRIu64" emerg\n", - ntohll(ifps->ofps_error_type.flow_mod_fail), - ntohll(ifps->ofps_error_code.fmf_all_tables_full), - ntohll(ifps->ofps_error_code.fmf_overlap), - ntohll(ifps->ofps_error_code.fmf_eperm), - ntohll(ifps->ofps_error_code.fmf_emerg)); - fprintf(stdout, - PREFIX_STR - "%"PRIu64" unknown type, %"PRIu64" unknown code\n", - ntohll(ifps->ofps_error_type.unknown), - ntohll(ifps->ofps_error_code.unknown)); - } - fprintf(stdout, "\n"); -} - -static void -do_protostat(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) -{ - struct ofpbuf *buf; - struct private_vxhdr *vxhdr; - struct private_vxopt *vxopt; - struct vconn *vconn; - struct ofpstat* ofps; - - vxhdr = make_openflow(sizeof(*vxhdr) + sizeof(*vxopt), OFPT_VENDOR, &buf); - vxopt = (struct private_vxopt *)(vxhdr + 1); - vxhdr->ofp_vxid = htonl(PRIVATE_VENDOR_ID); - vxopt->pvo_type = htons(PRIVATEOPT_PROTOCOL_STATS_REQUEST); - vxopt->pvo_len = 0; - - open_vconn(argv[1], &vconn); - run(vconn_transact(vconn, buf, &buf), "talking to %s", argv[1]); - vconn_close(vconn); - if (buf->size < sizeof(*vxhdr)) { - ofp_fatal(0, "short reply (%zu bytes)", buf->size); - } - - vxhdr = buf->data; - if (vxhdr->ofp_hdr.type != OFPT_VENDOR - || ntohl(vxhdr->ofp_vxid) != PRIVATE_VENDOR_ID) { - ofp_print(stderr, buf->data, buf->size, 2); - ofp_fatal(0, "bad reply"); - } - vxopt = (struct private_vxopt *)(vxhdr + 1); - if (ntohs(vxopt->pvo_type) != PRIVATEOPT_PROTOCOL_STATS_REPLY - || ntohs(vxopt->pvo_len) != (sizeof(*ofps) * 2)) { - ofp_print(stderr, buf->data, buf->size, 2); - ofp_fatal(0, "bad reply"); - } - - ofps = (struct ofpstat *)(vxopt + 1); - print_protocol_stat(ofps, ofps + 1); -} - -static void -do_dump_desc(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) -{ - dump_trivial_stats_transaction(argv[1], OFPST_DESC); -} - -static void -do_dump_tables(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) -{ - dump_trivial_stats_transaction(argv[1], OFPST_TABLE); -} - -static uint32_t -str_to_u32(const char *str) -{ - char *tail; - uint32_t value; - - errno = 0; - value = strtoul(str, &tail, 0); - if (errno == EINVAL || errno == ERANGE || *tail) { - ofp_fatal(0, "invalid numeric format %s", str); - } - return value; -} - -static void -str_to_mac(const char *str, uint8_t mac[6]) -{ - if (sscanf(str, "%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8, - &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]) != 6) { - ofp_fatal(0, "invalid mac address %s", str); - } -} - -static uint32_t -str_to_ip(const char *str_, uint32_t *ip) -{ - char *str = xstrdup(str_); - char *save_ptr = NULL; - const char *name, *netmask; - struct in_addr in_addr; - int n_wild, retval; - - name = strtok_r(str, "//", &save_ptr); - retval = name ? lookup_ip(name, &in_addr) : EINVAL; - if (retval) { - ofp_fatal(0, "%s: could not convert to IP address", str); - } - *ip = in_addr.s_addr; - - netmask = strtok_r(NULL, "//", &save_ptr); - if (netmask) { - uint8_t o[4]; - if (sscanf(netmask, "%"SCNu8".%"SCNu8".%"SCNu8".%"SCNu8, - &o[0], &o[1], &o[2], &o[3]) == 4) { - uint32_t nm = (o[0] << 24) | (o[1] << 16) | (o[2] << 8) | o[3]; - int i; - - /* Find first 1-bit. */ - for (i = 0; i < 32; i++) { - if (nm & (1u << i)) { - break; - } - } - n_wild = i; - - /* Verify that the rest of the bits are 1-bits. */ - for (; i < 32; i++) { - if (!(nm & (1u << i))) { - ofp_fatal(0, "%s: %s is not a valid netmask", - str, netmask); - } - } - } else { - int prefix = atoi(netmask); - if (prefix <= 0 || prefix > 32) { - ofp_fatal(0, "%s: network prefix bits not between 1 and 32", - str); - } - n_wild = 32 - prefix; - } - } else { - n_wild = 0; - } - - free(str); - return n_wild; -} - -static void * -put_action(struct ofpbuf *b, size_t size, uint16_t type) -{ - struct ofp_action_header *ah = ofpbuf_put_zeros(b, size); - ah->type = htons(type); - ah->len = htons(size); - return ah; -} - -static struct ofp_action_output * -put_output_action(struct ofpbuf *b, uint16_t port) -{ - struct ofp_action_output *oao = put_action(b, sizeof *oao, OFPAT_OUTPUT); - oao->port = htons(port); - return oao; -} - -static struct ofp_action_enqueue * -put_enqueue_action(struct ofpbuf *b, uint16_t port, uint32_t queue) -{ - struct ofp_action_enqueue *oao; - - oao = put_action(b, sizeof *oao, OFPAT_ENQUEUE); - oao->len = htons(sizeof(*oao)); - oao->port = htons(port); - oao->queue_id = htonl(queue); - return oao; -} - -static void -str_to_action(char *str, struct ofpbuf *b) -{ - char *act, *arg, *arg2; - char *saveptr = NULL; - - for (act = strtok_r(str, ", \t\r\n", &saveptr); act; - act = strtok_r(NULL, ", \t\r\n", &saveptr)) - { - /* Arguments are separated by colons */ - arg = strchr(act, ':'); - if (arg) { - *arg = '\0'; - arg++; - } - - if (!strcasecmp(act, "mod_nw_tos")) { - struct ofp_action_nw_tos *va; - va = put_action(b, sizeof *va, OFPAT_SET_NW_TOS); - va->nw_tos = str_to_u32(arg); - } else if (!strcasecmp(act, "mod_vlan_vid")) { - struct ofp_action_vlan_vid *va; - va = put_action(b, sizeof *va, OFPAT_SET_VLAN_VID); - va->vlan_vid = htons(str_to_u32(arg)); - } else if (!strcasecmp(act, "mod_vlan_pcp")) { - struct ofp_action_vlan_pcp *va; - va = put_action(b, sizeof *va, OFPAT_SET_VLAN_PCP); - va->vlan_pcp = str_to_u32(arg); - } else if (!strcasecmp(act, "mod_dl_dst")) { - struct ofp_action_dl_addr *va; - va = put_action(b, sizeof *va, OFPAT_SET_DL_DST); - str_to_mac(arg, va->dl_addr); - } else if (!strcasecmp(act, "mod_dl_src")) { - struct ofp_action_dl_addr *va; - va = put_action(b, sizeof *va, OFPAT_SET_DL_SRC); - str_to_mac(arg, va->dl_addr); - } else if (!strcasecmp(act, "strip_vlan")) { - struct ofp_action_header *ah; - ah = put_action(b, sizeof *ah, OFPAT_STRIP_VLAN); - ah->type = htons(OFPAT_STRIP_VLAN); - } else if (!strcasecmp(act, "enqueue")) { - arg2 = strchr(arg, ':'); - if (arg2) { - *arg2 = '\0'; - arg2++; - } - put_enqueue_action(b, str_to_u32(arg), str_to_u32(arg2)); - } else if (!strcasecmp(act, "output")) { - put_output_action(b, str_to_u32(arg)); - } else if (!strcasecmp(act, "TABLE")) { - put_output_action(b, OFPP_TABLE); - } else if (!strcasecmp(act, "NORMAL")) { - put_output_action(b, OFPP_NORMAL); - } else if (!strcasecmp(act, "FLOOD")) { - put_output_action(b, OFPP_FLOOD); - } else if (!strcasecmp(act, "ALL")) { - put_output_action(b, OFPP_ALL); - } else if (!strcasecmp(act, "CONTROLLER")) { - struct ofp_action_output *oao; - oao = put_output_action(b, OFPP_CONTROLLER); - - /* Unless a numeric argument is specified, we send the whole - * packet to the controller. */ - if (arg && (strspn(act, "0123456789") == strlen(act))) { - oao->max_len = htons(str_to_u32(arg)); - } - } else if (!strcasecmp(act, "LOCAL")) { - put_output_action(b, OFPP_LOCAL); - } else if (strspn(act, "0123456789") == strlen(act)) { - put_output_action(b, str_to_u32(act)); - } else { - ofp_fatal(0, "Unknown action: %s", act); - } - } -} - -struct protocol { - const char *name; - uint16_t dl_type; - uint8_t nw_proto; -}; - -static bool -parse_protocol(const char *name, const struct protocol **p_out) -{ - static const struct protocol protocols[] = { - { "ip", ETH_TYPE_IP, 0 }, - { "arp", ETH_TYPE_ARP, 0 }, - { "icmp", ETH_TYPE_IP, IP_TYPE_ICMP }, - { "tcp", ETH_TYPE_IP, IP_TYPE_TCP }, - { "udp", ETH_TYPE_IP, IP_TYPE_UDP }, - }; - const struct protocol *p; - - for (p = protocols; p < &protocols[ARRAY_SIZE(protocols)]; p++) { - if (!strcmp(p->name, name)) { - *p_out = p; - return true; - } - } - *p_out = NULL; - return false; -} - -struct field { - const char *name; - uint32_t wildcard; - enum { F_U8, F_U16, F_MAC, F_IP } type; - size_t offset, shift; -}; - -static bool -parse_field(const char *name, const struct field **f_out) -{ -#define F_OFS(MEMBER) offsetof(struct ofp_match, MEMBER) - static const struct field fields[] = { - { "in_port", OFPFW_IN_PORT, F_U16, F_OFS(in_port), 0 }, - { "dl_vlan", OFPFW_DL_VLAN, F_U16, F_OFS(dl_vlan), 0 }, - { "dl_vlan_pcp", OFPFW_DL_VLAN_PCP, F_U8, F_OFS(dl_vlan_pcp), 0 }, - { "dl_src", OFPFW_DL_SRC, F_MAC, F_OFS(dl_src), 0 }, - { "dl_dst", OFPFW_DL_DST, F_MAC, F_OFS(dl_dst), 0 }, - { "dl_type", OFPFW_DL_TYPE, F_U16, F_OFS(dl_type), 0 }, - { "nw_tos", OFPFW_NW_TOS, F_U8, F_OFS(nw_tos), 0 }, - { "nw_proto", OFPFW_NW_PROTO, F_U8, F_OFS(nw_proto), 0 }, - { "nw_src", OFPFW_NW_SRC_MASK, F_IP, - F_OFS(nw_src), OFPFW_NW_SRC_SHIFT }, - { "nw_dst", OFPFW_NW_DST_MASK, F_IP, - F_OFS(nw_dst), OFPFW_NW_DST_SHIFT }, - { "tp_src", OFPFW_TP_SRC, F_U16, F_OFS(tp_src), 0 }, - { "tp_dst", OFPFW_TP_DST, F_U16, F_OFS(tp_dst), 0 }, - { "icmp_type", OFPFW_ICMP_TYPE, F_U16, F_OFS(icmp_type), 0 }, - { "icmp_code", OFPFW_ICMP_CODE, F_U16, F_OFS(icmp_code), 0 } - }; - const struct field *f; - - for (f = fields; f < &fields[ARRAY_SIZE(fields)]; f++) { - if (!strcmp(f->name, name)) { - *f_out = f; - return true; - } - } - *f_out = NULL; - return false; -} - -static void -str_to_flow(char *string, struct ofp_match *match, struct ofpbuf *actions, - uint8_t *table_idx, uint16_t *out_port, uint16_t *priority, - uint16_t *idle_timeout, uint16_t *hard_timeout, - uint64_t *cookie) -{ - char *save_ptr = NULL; - char *name; - uint32_t wildcards; - - if (table_idx) { - *table_idx = 0xff; - } - if (out_port) { - *out_port = OFPP_NONE; - } - if (priority) { - *priority = OFP_DEFAULT_PRIORITY; - } - if (idle_timeout) { - *idle_timeout = DEFAULT_IDLE_TIMEOUT; - } - if (hard_timeout) { - *hard_timeout = OFP_FLOW_PERMANENT; - } - if (cookie) { - *cookie = 0; - } - if (actions) { - char *act_str = strstr(string, "actions"); - if (!act_str) { - ofp_fatal(0, "must specify an action"); - } - *(act_str-1) = '\0'; - - act_str = strchr(act_str, '='); - if (!act_str) { - ofp_fatal(0, "must specify an action"); - } - - act_str++; - - str_to_action(act_str, actions); - } - memset(match, 0, sizeof *match); - wildcards = OFPFW_ALL; - for (name = strtok_r(string, "=, \t\r\n", &save_ptr); name; - name = strtok_r(NULL, "=, \t\r\n", &save_ptr)) { - const struct protocol *p; - - if (parse_protocol(name, &p)) { - wildcards &= ~OFPFW_DL_TYPE; - match->dl_type = htons(p->dl_type); - if (p->nw_proto) { - wildcards &= ~OFPFW_NW_PROTO; - match->nw_proto = p->nw_proto; - } - } else { - const struct field *f; - char *value; - - value = strtok_r(NULL, ", \t\r\n", &save_ptr); - if (!value) { - ofp_fatal(0, "field %s missing value", name); - } - - if (table_idx && !strcmp(name, "table")) { - *table_idx = atoi(value); - } else if (out_port && !strcmp(name, "out_port")) { - *out_port = atoi(value); - } else if (priority && !strcmp(name, "priority")) { - *priority = atoi(value); - } else if (idle_timeout && !strcmp(name, "idle_timeout")) { - *idle_timeout = atoi(value); - } else if (hard_timeout && !strcmp(name, "hard_timeout")) { - *hard_timeout = atoi(value); - } else if (cookie && !strcmp(name, "cookie")) { - *cookie = atoi(value); - } else if (parse_field(name, &f)) { - void *data = (char *) match + f->offset; - if (!strcmp(value, "*") || !strcmp(value, "ANY")) { - wildcards |= f->wildcard; - } else { - wildcards &= ~f->wildcard; - if (f->type == F_U8) { - *(uint8_t *) data = str_to_u32(value); - } else if (f->type == F_U16) { - *(uint16_t *) data = htons(str_to_u32(value)); - } else if (f->type == F_MAC) { - str_to_mac(value, data); - } else if (f->type == F_IP) { - wildcards |= str_to_ip(value, data) << f->shift; - } else { - NOT_REACHED(); - } - } - } else { - ofp_fatal(0, "unknown keyword %s", name); - } - } - } - match->wildcards = htonl(wildcards); -} - -static void -do_desc(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) -{ - struct vconn * vconn; - struct ofpbuf * msg; - struct openflow_ext_set_dp_desc * desc; - - msg = ofpbuf_new(sizeof(*desc)); - ofpbuf_put_uninit(msg, sizeof(*desc)); - desc = ofpbuf_at_assert(msg, 0, sizeof(*desc)); - desc->header.header.version = OFP_VERSION; - desc->header.header.type = OFPT_VENDOR; - desc->header.header.length = htons(sizeof(*desc)); - desc->header.vendor = htonl(OPENFLOW_VENDOR_ID); - desc->header.subtype = htonl(OFP_EXT_SET_DESC); - strncpy(desc->dp_desc, argv[2], DESC_STR_LEN); - - open_vconn(argv[1], &vconn); - send_openflow_buffer(vconn, msg); - vconn_close(vconn); -} - -static void -do_dump_flows(const struct settings *s UNUSED, int argc, char *argv[]) -{ - struct ofp_flow_stats_request *req; - uint16_t out_port; - struct ofpbuf *request; - - req = alloc_stats_request(sizeof *req, OFPST_FLOW, &request); - str_to_flow(argc > 2 ? argv[2] : "", &req->match, NULL, - &req->table_id, &out_port, NULL, NULL, NULL, NULL); - memset(&req->pad, 0, sizeof req->pad); - req->out_port = htons(out_port); - - dump_stats_transaction(argv[1], request); -} - -static void -do_dump_aggregate(const struct settings *s UNUSED, int argc, char *argv[]) -{ - struct ofp_aggregate_stats_request *req; - struct ofpbuf *request; - uint16_t out_port; - - req = alloc_stats_request(sizeof *req, OFPST_AGGREGATE, &request); - str_to_flow(argc > 2 ? argv[2] : "", &req->match, NULL, - &req->table_id, &out_port, NULL, NULL, NULL, NULL); - memset(&req->pad, 0, sizeof req->pad); - req->out_port = htons(out_port); - - dump_stats_transaction(argv[1], request); -} - -#define EMERG_TABLE_ID 0xfe - -static void -do_add_flow(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) -{ - struct vconn *vconn; - struct ofpbuf *buffer; - struct ofp_flow_mod *ofm; - uint16_t priority, idle_timeout, hard_timeout; - uint64_t cookie; - uint8_t table_id; - struct ofp_match match; - - /* Parse and send. str_to_flow() will expand and reallocate the data in - * 'buffer', so we can't keep pointers to across the str_to_flow() call. */ - make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer); - str_to_flow(argv[2], &match, buffer, - &table_id, NULL, &priority, &idle_timeout, &hard_timeout, - &cookie); - ofm = buffer->data; - ofm->match = match; - ofm->command = htons(OFPFC_ADD); - ofm->cookie = htonll(cookie); - ofm->idle_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(idle_timeout); - ofm->hard_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(hard_timeout); - ofm->buffer_id = htonl(UINT32_MAX); - ofm->priority = htons(priority); - ofm->flags = htons(OFPFF_SEND_FLOW_REM); - if (table_id == EMERG_TABLE_ID) - ofm->flags |= htons(OFPFF_EMERG); - - open_vconn(argv[1], &vconn); - send_openflow_buffer(vconn, buffer); - vconn_close(vconn); -} - -static void -do_add_flows(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) -{ - struct vconn *vconn; - FILE *file; - char line[1024]; - - file = fopen(argv[2], "r"); - if (file == NULL) { - ofp_fatal(errno, "%s: open", argv[2]); - } - - open_vconn(argv[1], &vconn); - while (fgets(line, sizeof line, file)) { - struct ofpbuf *buffer; - struct ofp_flow_mod *ofm; - uint16_t priority, idle_timeout, hard_timeout; - uint64_t cookie; - uint8_t table_id; - struct ofp_match match; - - char *comment; - - /* Delete comments. */ - comment = strchr(line, '#'); - if (comment) { - *comment = '\0'; - } - - /* Drop empty lines. */ - if (line[strspn(line, " \t\n")] == '\0') { - continue; - } - - /* Parse and send. str_to_flow() will expand and reallocate the data - * in 'buffer', so we can't keep pointers to across the str_to_flow() - * call. */ - ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer); - str_to_flow(line, &match, buffer, - &table_id, NULL, &priority, &idle_timeout, &hard_timeout, - &cookie); - ofm = buffer->data; - ofm->match = match; - ofm->command = htons(OFPFC_ADD); - ofm->cookie = htonll(cookie); - ofm->idle_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(idle_timeout); - ofm->hard_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(hard_timeout); - ofm->buffer_id = htonl(UINT32_MAX); - ofm->priority = htons(priority); - ofm->flags = htons(OFPFF_SEND_FLOW_REM); - if (table_id == EMERG_TABLE_ID) - ofm->flags |= htons(OFPFF_EMERG); - - send_openflow_buffer(vconn, buffer); - } - vconn_close(vconn); - fclose(file); -} - -static void -do_mod_flows(const struct settings *s, int argc UNUSED, char *argv[]) -{ - uint16_t priority, idle_timeout, hard_timeout; - uint64_t cookie; - uint8_t table_id; - struct vconn *vconn; - struct ofpbuf *buffer; - struct ofp_flow_mod *ofm; - - /* Parse and send. */ - ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer); - str_to_flow(argv[2], &ofm->match, buffer, - &table_id, NULL, &priority, &idle_timeout, &hard_timeout, - &cookie); - if (s->strict) { - ofm->command = htons(OFPFC_MODIFY_STRICT); - } else { - ofm->command = htons(OFPFC_MODIFY); - } - ofm->cookie = htonll(cookie); - ofm->idle_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(idle_timeout); - ofm->hard_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(hard_timeout); - ofm->buffer_id = htonl(UINT32_MAX); - if (table_id == EMERG_TABLE_ID) - ofm->flags = htons(OFPFF_EMERG); - ofm->priority = htons(priority); - - open_vconn(argv[1], &vconn); - send_openflow_buffer(vconn, buffer); - vconn_close(vconn); -} - -static void do_del_flows(const struct settings *s, int argc, char *argv[]) -{ - struct vconn *vconn; - uint16_t priority; - uint16_t out_port; - uint8_t table_id; - struct ofpbuf *buffer; - struct ofp_flow_mod *ofm; - - /* Parse and send. */ - ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer); - str_to_flow(argc > 2 ? argv[2] : "", &ofm->match, NULL, - &table_id, &out_port, &priority, NULL, NULL, NULL); - if (s->strict) { - ofm->command = htons(OFPFC_DELETE_STRICT); - } else { - ofm->command = htons(OFPFC_DELETE); - } - ofm->idle_timeout = htons(0); - ofm->hard_timeout = htons(0); - ofm->buffer_id = htonl(UINT32_MAX); - if (table_id == EMERG_TABLE_ID) - ofm->flags = htons(OFPFF_EMERG); - ofm->out_port = htons(out_port); - ofm->priority = htons(priority); - - open_vconn(argv[1], &vconn); - send_openflow_buffer(vconn, buffer); - vconn_close(vconn); -} - -static void -do_monitor(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) -{ - struct vconn *vconn; - const char *name; - - /* If the user specified, e.g., "nl:0", append ":1" to it to ensure that - * the connection will subscribe to listen for asynchronous messages, such - * as packet-in messages. */ - if (!strncmp(argv[1], "nl:", 3) && strrchr(argv[1], ':') == &argv[1][2]) { - name = xasprintf("%s:1", argv[1]); - } else { - name = argv[1]; - } - open_vconn(argv[1], &vconn); - for (;;) { - struct ofpbuf *b; - run(vconn_recv_block(vconn, &b), "vconn_recv"); - ofp_print(stderr, b->data, b->size, 2); - ofpbuf_delete(b); - } -} - -static void -str_to_port(char *string, uint16_t *start_port) -{ - char *save_ptr = NULL; - char *value = NULL; - - if (start_port) { - *start_port = OFPP_NONE; - } - - value = strtok_r(string, ", \t\r\n", &save_ptr); - if (value && start_port) { - *start_port = atoi(value); - } -} - -static void -do_dump_ports(const struct settings *s UNUSED, int argc, char *argv[]) -{ - struct ofp_port_stats_request *psr; - struct ofpbuf *buf; - - psr = alloc_stats_request(sizeof(*psr), OFPST_PORT, &buf); - str_to_port(argc > 2 ? argv[2] : "", &psr->port_no); - psr->port_no = htons(psr->port_no); - memset(psr->pad, 0, sizeof(psr->pad)); - dump_stats_transaction(argv[1], buf); -} - -static void -do_probe(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) -{ - struct ofpbuf *request; - struct vconn *vconn; - struct ofpbuf *reply; - - make_openflow(sizeof(struct ofp_header), OFPT_ECHO_REQUEST, &request); - open_vconn(argv[1], &vconn); - run(vconn_transact(vconn, request, &reply), "talking to %s", argv[1]); - if (reply->size != sizeof(struct ofp_header)) { - ofp_fatal(0, "reply does not match request"); - } - ofpbuf_delete(reply); - vconn_close(vconn); -} - -static void -do_mod_port(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) -{ - struct ofpbuf *request, *reply; - struct ofp_switch_features *osf; - struct ofp_port_mod *opm; - struct vconn *vconn; - char *endptr; - int n_ports; - int port_idx; - int port_no; - - - /* Check if the argument is a port index. Otherwise, treat it as - * the port name. */ - port_no = strtol(argv[2], &endptr, 10); - if (port_no == 0 && endptr == argv[2]) { - port_no = -1; - } - - /* Send a "Features Request" to get the information we need in order - * to modify the port. */ - make_openflow(sizeof(struct ofp_header), OFPT_FEATURES_REQUEST, &request); - open_vconn(argv[1], &vconn); - run(vconn_transact(vconn, request, &reply), "talking to %s", argv[1]); - - osf = reply->data; - n_ports = (reply->size - sizeof *osf) / sizeof *osf->ports; - - for (port_idx = 0; port_idx < n_ports; port_idx++) { - if (port_no != -1) { - /* Check argument as a port index */ - if (osf->ports[port_idx].port_no == htons(port_no)) { - break; - } - } else { - /* Check argument as an interface name */ - if (!strncmp((char *)osf->ports[port_idx].name, argv[2], - sizeof osf->ports[0].name)) { - break; - } - - } - } - if (port_idx == n_ports) { - ofp_fatal(0, "couldn't find monitored port: %s", argv[2]); - } - - opm = make_openflow(sizeof(struct ofp_port_mod), OFPT_PORT_MOD, &request); - opm->port_no = osf->ports[port_idx].port_no; - memcpy(opm->hw_addr, osf->ports[port_idx].hw_addr, sizeof opm->hw_addr); - opm->config = htonl(0); - opm->mask = htonl(0); - opm->advertise = htonl(0); - - printf("modifying port: %s\n", osf->ports[port_idx].name); - - if (!strncasecmp(argv[3], MOD_PORT_CMD_UP, sizeof MOD_PORT_CMD_UP)) { - opm->mask |= htonl(OFPPC_PORT_DOWN); - } else if (!strncasecmp(argv[3], MOD_PORT_CMD_DOWN, - sizeof MOD_PORT_CMD_DOWN)) { - opm->mask |= htonl(OFPPC_PORT_DOWN); - opm->config |= htonl(OFPPC_PORT_DOWN); - } else if (!strncasecmp(argv[3], MOD_PORT_CMD_FLOOD, - sizeof MOD_PORT_CMD_FLOOD)) { - opm->mask |= htonl(OFPPC_NO_FLOOD); - } else if (!strncasecmp(argv[3], MOD_PORT_CMD_NOFLOOD, - sizeof MOD_PORT_CMD_NOFLOOD)) { - opm->mask |= htonl(OFPPC_NO_FLOOD); - opm->config |= htonl(OFPPC_NO_FLOOD); - } else { - ofp_fatal(0, "unknown mod-port command '%s'", argv[3]); - } - - send_openflow_buffer(vconn, request); - - ofpbuf_delete(reply); - vconn_close(vconn); -} - -static void -do_ping(const struct settings *s UNUSED, int argc, char *argv[]) -{ - size_t max_payload = 65535 - sizeof(struct ofp_header); - unsigned int payload; - struct vconn *vconn; - int i; - - payload = argc > 2 ? atoi(argv[2]) : 64; - if (payload > max_payload) { - ofp_fatal(0, "payload must be between 0 and %zu bytes", max_payload); - } - - open_vconn(argv[1], &vconn); - for (i = 0; i < 10; i++) { - struct timeval start, end; - struct ofpbuf *request, *reply; - struct ofp_header *rq_hdr, *rpy_hdr; - - rq_hdr = make_openflow(sizeof(struct ofp_header) + payload, - OFPT_ECHO_REQUEST, &request); - random_bytes(rq_hdr + 1, payload); - - gettimeofday(&start, NULL); - run(vconn_transact(vconn, ofpbuf_clone(request), &reply), "transact"); - gettimeofday(&end, NULL); - - rpy_hdr = reply->data; - if (reply->size != request->size - || memcmp(rpy_hdr + 1, rq_hdr + 1, payload) - || rpy_hdr->xid != rq_hdr->xid - || rpy_hdr->type != OFPT_ECHO_REPLY) { - printf("Reply does not match request. Request:\n"); - ofp_print(stdout, request, request->size, 2); - printf("Reply:\n"); - ofp_print(stdout, reply, reply->size, 2); - } - printf("%d bytes from %s: xid=%08"PRIx32" time=%.1f ms\n", - reply->size - sizeof *rpy_hdr, argv[1], rpy_hdr->xid, - (1000*(double)(end.tv_sec - start.tv_sec)) - + (.001*(end.tv_usec - start.tv_usec))); - ofpbuf_delete(request); - ofpbuf_delete(reply); - } - vconn_close(vconn); -} - -static void -do_benchmark(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) -{ - size_t max_payload = 65535 - sizeof(struct ofp_header); - struct timeval start, end; - unsigned int payload_size, message_size; - struct vconn *vconn; - double duration; - int count; - int i; - - payload_size = atoi(argv[2]); - if (payload_size > max_payload) { - ofp_fatal(0, "payload must be between 0 and %zu bytes", max_payload); - } - message_size = sizeof(struct ofp_header) + payload_size; - - count = atoi(argv[3]); - - printf("Sending %d packets * %u bytes (with header) = %u bytes total\n", - count, message_size, count * message_size); - - open_vconn(argv[1], &vconn); - gettimeofday(&start, NULL); - for (i = 0; i < count; i++) { - struct ofpbuf *request, *reply; - struct ofp_header *rq_hdr; - - rq_hdr = make_openflow(message_size, OFPT_ECHO_REQUEST, &request); - memset(rq_hdr + 1, 0, payload_size); - run(vconn_transact(vconn, request, &reply), "transact"); - ofpbuf_delete(reply); - } - gettimeofday(&end, NULL); - vconn_close(vconn); - - duration = ((1000*(double)(end.tv_sec - start.tv_sec)) - + (.001*(end.tv_usec - start.tv_usec))); - printf("Finished in %.1f ms (%.0f packets/s) (%.0f bytes/s)\n", - duration, count / (duration / 1000.0), - count * message_size / (duration / 1000.0)); -} - -/**************************************************************** - * - * Queue operations - * - ****************************************************************/ - -static int -parse_queue_params(int argc, char *argv[], uint16_t *port, uint32_t *q_id, - uint16_t *min_rate) -{ - if (!port || !q_id) { - return -1; - } - - *port = OFPP_ALL; - *q_id = OFPQ_ALL; - if (argc > 2) { - *port = str_to_u32(argv[2]); - } - if (argc > 3) { - *q_id = str_to_u32(argv[3]); - } - if (min_rate) { - *min_rate = OFPQ_MIN_RATE_UNCFG; - if (argc > 4) { - *min_rate = str_to_u32(argv[4]); - } - } - - return 0; -} - -/* Length of queue request; works with 16-bit property values like min_rate */ -#define Q_REQ_LEN(prop_count) \ - (sizeof(struct ofp_packet_queue) + Q_PROP_LEN(prop_count)) - -#define Q_PROP_LEN(prop_count) \ - ((prop_count) * sizeof(struct ofp_queue_prop_min_rate)) - -/* - * Execute a queue add/mod/del operation - * - * All commands must specify a port and queue id. - * Add may specify a bandwidth value - * Modify must specify a bandwidth value - * - * To simplify things, always allocate space for all three parameters - * (port, queue, min-bw): - * openflow_queue_header (w/ ofp header, port) - * ofp_queue (with q_id and offset to properties list) - * ofp_queue_prop_min_rate (w/ prop header and rate info) - */ -static struct openflow_queue_command_header * -queue_req_create(int cmd, struct ofpbuf **b, uint16_t port, - uint32_t q_id, uint16_t min_rate) -{ - struct openflow_queue_command_header *request; - struct ofp_packet_queue *queue; - struct ofp_queue_prop_min_rate *min_rate_prop; - int req_bytes; - - req_bytes = sizeof(*request) + sizeof(*queue) + sizeof(*min_rate_prop); - request = make_openflow(req_bytes, OFPT_VENDOR, b); - if (request == NULL) { - return NULL; - } - request->header.vendor = htonl(OPENFLOW_VENDOR_ID); - request->header.subtype = htonl(cmd); - request->port = htons(port); - - /* Will get complicated when queue properties w/ different struct sizes */ - queue = S_PTR(request, struct openflow_queue_command_header, body); - queue->queue_id = htonl(q_id); - queue->len = htons(Q_REQ_LEN(1)); - - min_rate_prop = S_PTR(queue, struct ofp_packet_queue, properties); - min_rate_prop->prop_header.property = htons(OFPQT_MIN_RATE); - min_rate_prop->prop_header.len = htons(Q_PROP_LEN(1)); - min_rate_prop->rate = htons(min_rate); - - return request; -} - -/* Handler for add/modify/delete queue ops */ -static void -do_queue_op(int cmd, int argc, char *argv[]) -{ - struct openflow_queue_command_header *request; - struct vconn *vconn; - struct ofpbuf *b; - uint16_t port; - uint32_t q_id; - uint16_t min_rate; - - if (parse_queue_params(argc, argv, &port, &q_id, &min_rate) < 0) { - ofp_fatal(0, "Error parsing port/queue for cmd %s", argv[0]); - return; - } - - printf("que op %d (%s). port %d. q 0x%x. rate %d\n", cmd, argv[0], - port, q_id, min_rate); - - if ((request = queue_req_create(cmd, &b, port, q_id, min_rate)) == NULL) { - ofp_fatal(0, "Error creating queue req for cmd %s", argv[0]); - return; - } - - printf("made request %p, running transaction\n", request); - - open_vconn(argv[1], &vconn); - /* Unacknowledged call for now */ - send_openflow_buffer(vconn, b); - vconn_close(vconn); -} - -char *openflow_queue_error_strings[] = OPENFLOW_QUEUE_ERROR_STRINGS_DEF; - -static void -do_mod_queue(const struct settings *s UNUSED, int argc, char *argv[]) -{ - do_queue_op(OFP_EXT_QUEUE_MODIFY, argc, argv); -} - -static void -do_del_queue(const struct settings *s UNUSED, int argc, char *argv[]) -{ - do_queue_op(OFP_EXT_QUEUE_DELETE, argc, argv); -} - -static void -do_dump_queue_port(char *vconn_name, uint16_t port, uint32_t q_id) -{ - struct ofp_queue_get_config_request *request; - struct ofpbuf *buf; - - request = make_openflow(sizeof(*request), OFPT_QUEUE_GET_CONFIG_REQUEST, - &buf); - request->port = htons(port); /* FIXME */ - dump_transaction(vconn_name, buf); - - /* Then do a queue stats get */ - dump_queue_stats_transaction(vconn_name, OFPST_QUEUE, port, q_id); -} - -static void -do_dump_queue_all(char *vconn_name, uint32_t q_id) -{ - struct ofpbuf *request, *reply; - struct ofp_switch_features *osf; - int port_idx, n_ports; - uint16_t port_no; - struct vconn *vconn; - - /* Send a "Features Request" to get the list of ports in the system */ - make_openflow(sizeof(struct ofp_header), OFPT_FEATURES_REQUEST, &request); - open_vconn(vconn_name, &vconn); - run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name); - vconn_close(vconn); - - osf = reply->data; - n_ports = (reply->size - sizeof *osf) / sizeof *osf->ports; - for (port_idx = 0; port_idx < n_ports; port_idx++) { - if ((port_no = ntohs(osf->ports[port_idx].port_no)) < OFPP_MAX) { - do_dump_queue_port(vconn_name, port_no, q_id); - } - } - ofpbuf_delete(reply); -} - -static void -do_dump_queue(const struct settings *s UNUSED, int argc, char *argv[]) -{ - uint16_t port; - uint32_t q_id; - - /* Get queue params from the request */ - if (parse_queue_params(argc, argv, &port, &q_id, NULL) < 0) { - ofp_fatal(0, "Error parsing port/queue for cmd %s", argv[0]); - return; - } - - if (port == OFPP_ALL) { - do_dump_queue_all(argv[1], q_id); - } else { - do_dump_queue_port(argv[1], port, q_id); - } -} - -static void -do_help(const struct settings *s UNUSED, int argc UNUSED, char *argv[] UNUSED) -{ - usage(); -} - -static struct command all_commands[] = { -#ifdef HAVE_NETLINK - { "adddp", 1, 1, do_add_dp }, - { "deldp", 1, 1, do_del_dp }, - { "addif", 2, INT_MAX, do_add_port }, - { "delif", 2, INT_MAX, do_del_port }, - { "get-idx", 1, 1, do_get_idx }, -#endif - - { "show", 1, 1, do_show }, - { "status", 1, 2, do_status }, - - { "show-protostat", 1, 1, do_protostat }, - - { "help", 0, INT_MAX, do_help }, - { "monitor", 1, 1, do_monitor }, - { "dump-desc", 1, 1, do_dump_desc }, - { "dump-tables", 1, 1, do_dump_tables }, - { "desc", 2, 2, do_desc }, - { "dump-flows", 1, 2, do_dump_flows }, - { "dump-aggregate", 1, 2, do_dump_aggregate }, - { "add-flow", 2, 2, do_add_flow }, - { "add-flows", 2, 2, do_add_flows }, - { "mod-flows", 2, 2, do_mod_flows }, - { "del-flows", 1, 2, do_del_flows }, - { "dump-ports", 1, 2, do_dump_ports }, - { "mod-port", 3, 3, do_mod_port }, - { "add-queue", 3, 4, do_mod_queue }, - { "mod-queue", 3, 4, do_mod_queue }, - { "del-queue", 3, 3, do_del_queue }, - { "dump-queue", 1, 3, do_dump_queue }, - { "probe", 1, 1, do_probe }, - { "ping", 1, 2, do_ping }, - { "benchmark", 3, 3, do_benchmark }, - { NULL, 0, 0, NULL }, -}; diff --git a/openflow/utilities/ofp-discover.8.in b/openflow/utilities/ofp-discover.8.in deleted file mode 100644 index cf5ac549..00000000 --- a/openflow/utilities/ofp-discover.8.in +++ /dev/null @@ -1,119 +0,0 @@ -.ds PN ofp\-discover - -.TH ofp\-discover 8 "May 2008" "OpenFlow" "OpenFlow Manual" - -.SH NAME -ofp\-discover \- controller discovery utility - -.SH SYNOPSIS -.B ofp\-discover -[\fIoptions\fR] \fInetdev\fR [\fInetdev\fR...] - -.SH DESCRIPTION -The \fBofp\-discover\fR program attempts to discover the location of -an OpenFlow controller on one of the network devices listed on the -command line. It repeatedly broadcasts a DHCP request with vendor -class identifier \fBOpenFlow\fR on each network device until it -receives an acceptable DHCP response. It will accept any valid DHCP -reply that has the same vendor class identifier and includes a -vendor-specific option with code 1 whose contents are a string -specifying the location of the controller in the same format used on -the \fBofprotocol\fR command line (e.g. \fBssl:192.168.0.1\fR). - -When \fBofp\-discover\fR receives an acceptable response, it prints -the details of the response on \fBstdout\fR. Then, by default, it -configures the network device on which the response was received with -the received IP address, netmask, and default gateway, and detaches -itself to the background. - -.SH OPTIONS -.TP -\fB--accept-vconn=\fIregex\fR -By default, \fBofp\-discover\fR accepts any controller location -advertised over DHCP. With this option, only controllers whose names -match POSIX extended regular expression \fIregex\fR will be accepted. -Specifying \fBssl:.*\fR for \fIregex\fR, for example, would cause only -SSL controller connections to be accepted. - -The \fIregex\fR is implicitly anchored at the beginning of the -controller location string, as if it begins with \fB^\fR. - -.TP -\fB--exit-without-bind\fR -By default, \fBofp\-discover\fR binds the network device that receives -the first acceptable response to the IP address received over DHCP. -With this option, the configuration of the network device is not -changed at all, except to bring it up if it is initially down, and -\fBofp\-discover\fR will exit immediately after it receives an -acceptable DHCP response. - -This option is mutually exclusive with \fB--exit-after-bind\fR and -\fB--no-detach\fR. - -.TP -\fB--exit-after-bind\fR -By default, after it receives an acceptable DHCP response, -\fBofp\-discover\fR detaches itself from the foreground session and -runs in the background maintaining the DHCP lease as necessary. With -this option, \fBofp\-discover\fR will exit immediately after it -receives an acceptable DHCP response and configures the network device -with the received IP address. The address obtained via DHCP could -therefore be used past the expiration of its lease. - -This option is mutually exclusive with \fB--exit-without-bind\fR and -\fB--no-detach\fR. - -.TP -\fB--no-detach\fR -By default, \fBofp\-discover\fR runs in the foreground until it obtains -an acceptable DHCP response, then it detaches itself from the -foreground session and run as a background process. This option -prevents \fBofp\-discover\fR from detaching, causing it to run in the -foreground even after it obtains a DHCP response. - -This option is mutually exclusive with \fB--exit-without-bind\fR and -\fB--exit-after-bind\fR. - -.TP -\fB-P\fR[\fIpidfile\fR], \fB--pidfile\fR[\fB=\fIpidfile\fR] -Causes a file (by default, \fBofp\-discover.pid\fR) to be created indicating -the PID of the running process. If \fIpidfile\fR is not specified, or -if it does not begin with \fB/\fR, then it is created in -\fB@RUNDIR@\fR. - -The \fIpidfile\fR is created when \fBofp\-discover\fR detaches, so -this this option has no effect when one of \fB--exit-without-bind\fR, -\fB--exit-after-bind\fR, or \fB--no-detach\fR is also given. - -.TP -\fB-f\fR, \fB--force\fR -By default, when \fB-P\fR or \fB--pidfile\fR is specified and the -specified pidfile already exists and is locked by a running process, -\fBcontroller\fR refuses to start. Specify \fB-f\fR or \fB--force\fR -to cause it to instead overwrite the pidfile. - -When \fB-P\fR or \fB--pidfile\fR is not specified, this option has no -effect. - -.so lib/vlog.man -.so lib/common.man - -.SH BUGS - -If the network devices specified on the command line have been added -to an OpenFlow switch with \fBdpctl addif\fR, then controller -discovery will fail because \fBofp\-discover\fR will not be able to -see DHCP responses, even though tools such as \fBtcpdump\fR(8) and -\fBwireshark\fR(1) can see them on the wire. This is because of the -structure of the Linux kernel networking stack, which hands packets -first to programs that listen for all arriving packets, then to -OpenFlow, then to programs that listen for a specific kind of packet. -OpenFlow consumes all the packets handed to it, so tools like -\fBtcpdump\fR that look at all packets will see packets arriving on -OpenFlow interfaces, but \fRofp\-discover\fR, which listens only for -arriving IP packets, will not. - -.SH "SEE ALSO" - -.BR ofprotocol (8), -.BR ofp-pki (8) diff --git a/openflow/utilities/ofp-discover.c b/openflow/utilities/ofp-discover.c deleted file mode 100644 index 55f40429..00000000 --- a/openflow/utilities/ofp-discover.c +++ /dev/null @@ -1,420 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include -#include -#include -#include -#include -#include -#include "command-line.h" -#include "daemon.h" -#include "dhcp-client.h" -#include "dhcp.h" -#include "dirs.h" -#include "dynamic-string.h" -#include "fatal-signal.h" -#include "netdev.h" -#include "poll-loop.h" -#include "timeval.h" -#include "util.h" -#include "vlog-socket.h" - -#include "vlog.h" -#define THIS_MODULE VLM_ofp_discover - -struct iface { - const char *name; - struct dhclient *dhcp; -}; - -/* The interfaces that we serve. */ -static struct iface *ifaces; -static int n_ifaces; - -/* --accept-vconn: Regular expression specifying the class of controller vconns - * that we will accept during autodiscovery. */ -static const char *accept_controller_re = ".*"; -static regex_t accept_controller_regex; - -/* --exit-without-bind: Exit after discovering the controller, without binding - * the network device to an IP address? */ -static bool exit_without_bind; - -/* --exit-after-bind: Exit after discovering the controller, after binding the - * network device to an IP address? */ -static bool exit_after_bind; - -static bool iface_init(struct iface *, const char *netdev_name); -static void release_ifaces(void *aux UNUSED); - -static void parse_options(int argc, char *argv[]); -static void usage(void) NO_RETURN; - -static void modify_dhcp_request(struct dhcp_msg *, void *aux); -static bool validate_dhcp_offer(const struct dhcp_msg *, void *aux); - -int -main(int argc, char *argv[]) -{ - int retval; - int i; - - set_program_name(argv[0]); - time_init(); - vlog_init(); - parse_options(argc, argv); - - argc -= optind; - argv += optind; - if (argc < 1) { - ofp_fatal(0, "need at least one non-option argument; " - "use --help for usage"); - } - - ifaces = xmalloc(argc * sizeof *ifaces); - n_ifaces = 0; - for (i = 0; i < argc; i++) { - if (iface_init(&ifaces[n_ifaces], argv[i])) { - n_ifaces++; - } - } - if (!n_ifaces) { - ofp_fatal(0, "failed to initialize any DHCP clients"); - } - - for (i = 0; i < n_ifaces; i++) { - struct iface *iface = &ifaces[i]; - dhclient_init(iface->dhcp, 0); - } - fatal_signal_add_hook(release_ifaces, NULL, true); - - retval = regcomp(&accept_controller_regex, accept_controller_re, - REG_NOSUB | REG_EXTENDED); - if (retval) { - size_t length = regerror(retval, &accept_controller_regex, NULL, 0); - char *buffer = xmalloc(length); - regerror(retval, &accept_controller_regex, buffer, length); - ofp_fatal(0, "%s: %s", accept_controller_re, buffer); - } - - retval = vlog_server_listen(NULL, NULL); - if (retval) { - ofp_fatal(retval, "Could not listen for vlog connections"); - } - - die_if_already_running(); - - signal(SIGPIPE, SIG_IGN); - for (;;) { - fatal_signal_block(); - for (i = 0; i < n_ifaces; i++) { - struct iface *iface = &ifaces[i]; - dhclient_run(iface->dhcp); - if (dhclient_changed(iface->dhcp)) { - bool is_bound = dhclient_is_bound(iface->dhcp); - int j; - - /* Configure network device. */ - if (!exit_without_bind) { - dhclient_configure_netdev(iface->dhcp); - dhclient_update_resolv_conf(iface->dhcp); - } - - if (is_bound) { - static bool detached = false; - struct ds ds; - - /* Disable timeout, since discovery was successful. */ - time_alarm(0); - - /* Print discovered parameters. */ - ds_init(&ds); - dhcp_msg_to_string(dhclient_get_config(iface->dhcp), - true, &ds); - fputs(ds_cstr(&ds), stdout); - putchar('\n'); - fflush(stdout); - ds_destroy(&ds); - - /* Exit if the user requested it. */ - if (exit_without_bind) { - VLOG_DBG("exiting because of successful binding on %s " - "and --exit-without-bind specified", - iface->name); - exit(0); - } - if (exit_after_bind) { - VLOG_DBG("exiting because of successful binding on %s " - "and --exit-after-bind specified", - iface->name); - exit(0); - } - - /* Detach into background, if we haven't already. */ - if (!detached) { - detached = true; - daemonize(); - } - } - - /* We only want an address on a single one of our interfaces. - * So: if we have an address on this interface, stop looking - * for one on the others; if we don't have an address on this - * interface, start looking everywhere. */ - for (j = 0; j < n_ifaces; j++) { - struct iface *if2 = &ifaces[j]; - if (iface != if2) { - if (is_bound) { - dhclient_release(if2->dhcp); - } else { - dhclient_init(if2->dhcp, 0); - } - } - } - } - } - for (i = 0; i < n_ifaces; i++) { - struct iface *iface = &ifaces[i]; - dhclient_wait(iface->dhcp); - } - fatal_signal_unblock(); - poll_block(); - } - - return 0; -} - -static bool -iface_init(struct iface *iface, const char *netdev_name) -{ - int retval; - - iface->name = netdev_name; - iface->dhcp = NULL; - - if (exit_after_bind) { - /* Bring this interface up permanently, so that the bound address - * persists past program termination. */ - struct netdev *netdev; - - retval = netdev_open(iface->name, NETDEV_ETH_TYPE_NONE, &netdev); - if (retval) { - ofp_error(retval, "Could not open %s device", iface->name); - return false; - } - retval = netdev_turn_flags_on(netdev, NETDEV_UP, true); - if (retval) { - ofp_error(retval, "Could not bring %s device up", iface->name); - return false; - } - netdev_close(netdev); - } - - retval = dhclient_create(iface->name, modify_dhcp_request, - validate_dhcp_offer, NULL, &iface->dhcp); - if (retval) { - ofp_error(retval, "%s: failed to initialize DHCP client", iface->name); - return false; - } - - return true; -} - -static void -release_ifaces(void *aux UNUSED) -{ - int i; - - for (i = 0; i < n_ifaces; i++) { - struct dhclient *dhcp = ifaces[i].dhcp; - dhclient_release(dhcp); - if (dhclient_changed(dhcp)) { - dhclient_configure_netdev(dhcp); - } - } -} - -static void -modify_dhcp_request(struct dhcp_msg *msg, void *aux UNUSED) -{ - dhcp_msg_put_string(msg, DHCP_CODE_VENDOR_CLASS, "OpenFlow"); -} - -static bool -validate_dhcp_offer(const struct dhcp_msg *msg, void *aux UNUSED) -{ - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60); - char *vconn_name; - bool accept; - - vconn_name = dhcp_msg_get_string(msg, DHCP_CODE_OFP_CONTROLLER_VCONN); - if (!vconn_name) { - VLOG_WARN_RL(&rl, "rejecting DHCP offer missing controller vconn"); - return false; - } - accept = !regexec(&accept_controller_regex, vconn_name, 0, NULL, 0); - free(vconn_name); - return accept; -} - -static void -parse_options(int argc, char *argv[]) -{ - enum { - OPT_ACCEPT_VCONN = UCHAR_MAX + 1, - OPT_EXIT_WITHOUT_BIND, - OPT_EXIT_AFTER_BIND, - OPT_NO_DETACH, - }; - static struct option long_options[] = { - {"accept-vconn", required_argument, 0, OPT_ACCEPT_VCONN}, - {"exit-without-bind", no_argument, 0, OPT_EXIT_WITHOUT_BIND}, - {"exit-after-bind", no_argument, 0, OPT_EXIT_AFTER_BIND}, - {"no-detach", no_argument, 0, OPT_NO_DETACH}, - {"timeout", required_argument, 0, 't'}, - {"pidfile", optional_argument, 0, 'P'}, - {"force", no_argument, 0, 'f'}, - {"verbose", optional_argument, 0, 'v'}, - {"help", no_argument, 0, 'h'}, - {"version", no_argument, 0, 'V'}, - {0, 0, 0, 0}, - }; - char *short_options = long_options_to_short_options(long_options); - bool detach_after_bind = true; - - for (;;) { - unsigned long int timeout; - int c; - - c = getopt_long(argc, argv, short_options, long_options, NULL); - if (c == -1) { - break; - } - - switch (c) { - case OPT_ACCEPT_VCONN: - accept_controller_re = (optarg[0] == '^' - ? optarg - : xasprintf("^%s", optarg)); - break; - - case OPT_EXIT_WITHOUT_BIND: - exit_without_bind = true; - break; - - case OPT_EXIT_AFTER_BIND: - exit_after_bind = true; - break; - - case OPT_NO_DETACH: - detach_after_bind = false; - break; - - case 'P': - set_pidfile(optarg); - break; - - case 'f': - ignore_existing_pidfile(); - break; - - case 't': - timeout = strtoul(optarg, NULL, 10); - if (timeout <= 0) { - ofp_fatal(0, "value %s on -t or --timeout is not at least 1", - optarg); - } else { - time_alarm(timeout); - } - signal(SIGALRM, SIG_DFL); - break; - - case 'h': - usage(); - - case 'V': - printf("%s %s compiled "__DATE__" "__TIME__"\n", - program_name, VERSION BUILDNR); - exit(EXIT_SUCCESS); - - case 'v': - vlog_set_verbosity(optarg); - break; - - case '?': - exit(EXIT_FAILURE); - - default: - abort(); - } - } - free(short_options); - - if ((exit_without_bind + exit_after_bind + !detach_after_bind) > 1) { - ofp_fatal(0, "--exit-without-bind, --exit-after-bind, and --no-detach " - "are mutually exclusive"); - } - if (detach_after_bind) { - set_detach(); - } -} - -static void -usage(void) -{ - printf("%s: a tool for discovering OpenFlow controllers.\n" - "usage: %s [OPTIONS] NETDEV [NETDEV...]\n" - "where each NETDEV is a network device on which to perform\n" - "controller discovery.\n" - "\nOrdinarily, ofp-discover runs in the foreground until it\n" - "obtains an IP address and discovers an OpenFlow controller via\n" - "DHCP, then it prints information about the controller to stdout\n" - "and detaches to the background to maintain the IP address lease.\n" - "\nNetworking options:\n" - " --accept-vconn=REGEX accept matching discovered controllers\n" - " --exit-without-bind exit after discovery, without binding\n" - " --exit-after-bind exit after discovery, after binding\n" - " --no-detach do not detach after discovery\n", - program_name, program_name); - vlog_usage(); - printf("\nOther options:\n" - " -t, --timeout=SECS give up discovery after SECS seconds\n" - " -P, --pidfile[=FILE] create pidfile (default: %s/%s.pid)\n" - " -f, --force with -P, start even if already running\n" - " -h, --help display this help message\n" - " -V, --version display version information\n", - ofp_rundir, program_name); - exit(EXIT_SUCCESS); -} diff --git a/openflow/utilities/ofp-kill.8.in b/openflow/utilities/ofp-kill.8.in deleted file mode 100644 index 6c1298ca..00000000 --- a/openflow/utilities/ofp-kill.8.in +++ /dev/null @@ -1,61 +0,0 @@ -.ds PN ofp\-kill - -.TH ofp\-kill 8 "May 2008" "OpenFlow" "OpenFlow Manual" - -.SH NAME -ofp\-kill \- kills processes given their pidfiles - -.SH SYNOPSIS -.B ofp\-kill -[\fIoptions\fR] \fIpidfile\fR [\fIpidfile\fR...] - -.SH DESCRIPTION -The \fBofp\-kill\fR program reads each \fIpidfile\fR specified on the -command line and sends a signal to the program associated with it, if -any. It reads one line of text from \fIpidfile\fR, which must contain -the PID of the process to kill as a text string. It then uses -\fBfcntl\fR(2) to verify that a process with the PID from the file -owns a lock on \fIpidfile\fR before it sends the signal. - -A \fIpidfile\fR whose name begins with \fB/\fR is used literally. -Otherwise, \fB@RUNDIR@/\fR is prefixed. - -This program exists for use by \fBofp\-switch\-setup\fR, which cannot -easily implement its functionality since Perl has no portable -interface to \fBfcntl\fR-based file locking. - -.SH OPTIONS -.TP -\fB-s \fInumber\fR|\fIname\fR, \fB\-\^\-signal=\fInumber\fR|\fIname\fR -Sets the signal to be sent to each process. Signals may be given by -number (e.g. \fB1\fR) or by name (e.g. \fBHUP\fR or \fBSIGHUP\fR). -By default, \fBSIGTERM\fR is sent. - -.TP -\fB-f\fR, \fB\-\^\-force\fR -Causes \fBofp\-kill\fR to ignore all errors without printing a message -to \fBstderr\fR, and to exit with return code 0. - -.so lib/common.man - -.SH "EXIT CODE" - -Without \fB-f\fR or \fB\-\^\-force\fR, \fBofp\-kill\fR exits with -status 0 if at least one \fIpidfile\fR was given and the process -represented by every \fIpidfile\fR was signaled successfully, -otherwise with status 1. - -With \fB-f\fR or \fB\-\^\-force\fR, \fBofp\-kill\fR always exits with -status 0. - -.SH BUGS - -There is a race between verifying the lock on \fIpidfile\fR and -actually killing the process. - -\fBofp\-kill\fR does not wait for the signaled processes to die before -exiting. - -.SH "SEE ALSO" - -.BR ofp\-switch\-setup (8) diff --git a/openflow/utilities/ofp-kill.c b/openflow/utilities/ofp-kill.c deleted file mode 100644 index 0ad04343..00000000 --- a/openflow/utilities/ofp-kill.c +++ /dev/null @@ -1,228 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "command-line.h" -#include "daemon.h" -#include "timeval.h" -#include "util.h" -#include "vlog.h" - -/* -s, --signal: signal to send. */ -static int sig_nr = SIGTERM; - -/* -f, --force: ignore errors. */ -static bool force; - -static void cond_error(int err_no, const char *, ...) PRINTF_FORMAT(2, 3); - -static void parse_options(int argc, char *argv[]); -static void usage(void); - -int -main(int argc, char *argv[]) -{ - bool ok = true; - int i; - - set_program_name(argv[0]); - time_init(); - vlog_init(); - parse_options(argc, argv); - - argc -= optind; - argv += optind; - if (argc < 1) { - if (!force) { - ofp_fatal(0, "need at least one non-option argument; " - "use --help for usage"); - } - } - - for (i = 0; i < argc; i++) { - char *pidfile; - pid_t pid; - - pidfile = make_pidfile_name(argv[i]); - pid = read_pidfile(pidfile); - if (pid >= 0) { - if (kill(pid, sig_nr) < 0) { - cond_error(errno, "%s: kill(%ld)", pidfile, (long int) pid); - } - } else { - cond_error(-pid, "could not read %s", pidfile); - } - free(pidfile); - } - - return ok || force ? EXIT_SUCCESS : EXIT_FAILURE; -} - -static void -parse_options(int argc, char *argv[]) -{ - static struct option long_options[] = { - {"signal", required_argument, 0, 's'}, - {"force", no_argument, 0, 'f'}, - {"help", no_argument, 0, 'h'}, - {"version", no_argument, 0, 'V'}, - {0, 0, 0, 0}, - }; - char *short_options = long_options_to_short_options(long_options); - - for (;;) { - int c; - - c = getopt_long(argc, argv, short_options, long_options, NULL); - if (c == -1) { - break; - } - - switch (c) { - case 's': - if (atoi(optarg) || !strcmp(optarg, "0")) { - sig_nr = atoi(optarg); - } else { - struct signal_name { - const char *name; - int number; - }; - - static const struct signal_name signals[] = { -#define SIGNAL(NAME) { #NAME, NAME } - SIGNAL(SIGABRT), - SIGNAL(SIGALRM), - SIGNAL(SIGBUS), - SIGNAL(SIGCHLD), - SIGNAL(SIGCONT), - SIGNAL(SIGFPE), - SIGNAL(SIGHUP), - SIGNAL(SIGILL), - SIGNAL(SIGINT), - SIGNAL(SIGKILL), - SIGNAL(SIGPIPE), - SIGNAL(SIGQUIT), - SIGNAL(SIGSEGV), - SIGNAL(SIGSTOP), - SIGNAL(SIGTERM), - SIGNAL(SIGTSTP), - SIGNAL(SIGTTIN), - SIGNAL(SIGTTOU), - SIGNAL(SIGUSR1), - SIGNAL(SIGUSR2), -#ifdef SIGPOLL - SIGNAL(SIGPOLL), -#endif - SIGNAL(SIGPROF), - SIGNAL(SIGSYS), - SIGNAL(SIGTRAP), - SIGNAL(SIGURG), - SIGNAL(SIGVTALRM), - SIGNAL(SIGXCPU), - SIGNAL(SIGXFSZ), -#undef SIGNAL - }; - int i; - - for (i = 0; i < ARRAY_SIZE(signals); i++) { - const struct signal_name *s = &signals[i]; - if (!strcmp(optarg, s->name) - || !strcmp(optarg, s->name + 3)) { - sig_nr = s->number; - goto got_name; - } - } - ofp_fatal(0, "unknown signal \"%s\"", optarg); - got_name: ; - } - break; - - case 'f': - force = true; - break; - - case 'h': - usage(); - - case 'V': - printf("%s %s compiled "__DATE__" "__TIME__"\n", - program_name, VERSION BUILDNR); - exit(EXIT_SUCCESS); - - case '?': - exit(EXIT_FAILURE); - - default: - abort(); - } - } - free(short_options); -} - -static void -usage(void) -{ - printf("%s: kills a program using a pidfile\n" - "usage: %s [OPTIONS] PIDFILE [PIDFILE...]\n" - "where each PIDFILE is a pidfile created by an OpenFlow daemon.\n" - "\nOptions:\n" - " -s, --signal=NUMBER|NAME signal to send (default: TERM)\n" - " -f, --force ignore errors\n" - " -h, --help display this help message\n" - " -V, --version display version information\n", - program_name, program_name); - exit(EXIT_SUCCESS); -} - -static void -cond_error(int err_no, const char *format, ...) -{ - if (!force) { - va_list args; - - fprintf(stderr, "%s: ", program_name); - va_start(args, format); - vfprintf(stderr, format, args); - va_end(args); - if (err_no != 0) - fprintf(stderr, " (%s)", strerror(err_no)); - putc('\n', stderr); - } -} diff --git a/openflow/utilities/ofp-parse-leaks b/openflow/utilities/ofp-parse-leaks deleted file mode 100644 index e51ecb72..00000000 --- a/openflow/utilities/ofp-parse-leaks +++ /dev/null @@ -1,285 +0,0 @@ -#! /usr/bin/perl - -use strict; -use warnings; - -if (grep($_ eq '--help', @ARGV)) { - print < 1; -die "$0: $ARGV[0] does not exist" if @ARGV > 0 && ! -e $ARGV[0]; - -our ($binary); -our ($a2l) = search_path("addr2line"); -my ($no_syms) = "symbols will not be translated"; -if (!@ARGV) { - print "no binary specified; $no_syms\n"; -} elsif (! -e $ARGV[0]) { - print "$ARGV[0] does not exist; $no_syms"; -} elsif (!defined($a2l)) { - print "addr2line not found in PATH; $no_syms"; -} else { - $binary = $ARGV[0]; -} - -our ($objdump) = search_path("objdump"); -print "objdump not found; dynamic library symbols will not be translated\n" - if !defined($objdump); - -our %blocks; -our @segments; -while () { - my $ptr = "((?:0x)?[0-9a-fA-F]+|\\(nil\\))"; - my $callers = ":((?: $ptr)+)"; - if (/^malloc\((\d+)\) -> $ptr$callers$/) { - allocated($., $2, $1, $3); - } elsif (/^claim\($ptr\)$callers$/) { - claimed($., $1, $2); - } elsif (/realloc\($ptr, (\d+)\) -> $ptr$callers$/) { - my ($callers) = $4; - freed($., $1, $callers); - allocated($., $3, $2, $callers); - } elsif (/^free\($ptr\)$callers$/) { - freed($., $1, $2); - } elsif (/^segment: $ptr-$ptr $ptr [-r][-w][-x][sp] (.*)/) { - add_segment(hex($1), hex($2), hex($3), $4); - } else { - print "stdin:$.: syntax error\n"; - } -} -if (%blocks) { - my $n_blocks = scalar(keys(%blocks)); - my $n_bytes = 0; - $n_bytes += $_->{SIZE} foreach values(%blocks); - print "$n_bytes bytes in $n_blocks blocks not freed at end of run\n"; - my %blocks_by_callers; - foreach my $block (values(%blocks)) { - my ($trimmed_callers) = trim_callers($block->{CALLERS}); - push (@{$blocks_by_callers{$trimmed_callers}}, $block); - } - foreach my $callers (sort {@{$b} <=> @{$a}} (values(%blocks_by_callers))) { - $n_blocks = scalar(@{$callers}); - $n_bytes = 0; - $n_bytes += $_->{SIZE} foreach @{$callers}; - print "$n_bytes bytes in these $n_blocks blocks were not freed:\n"; - my $i = 0; - my $max = 5; - foreach my $block (sort {$a->{LINE} <=> $b->{LINE}} (@{$callers})) { - printf "\t%d-byte block at 0x%08x allocated on stdin:%d\n", - $block->{SIZE}, $block->{BASE}, $block->{LINE}; - last if $i++ > $max; - } - print "\t...and ", $n_blocks - $max, " others...\n" - if $n_blocks > $max; - print "The blocks listed above were allocated by:\n"; - print_callers("\t", ${$callers}[0]->{CALLERS}); - } -} -sub interp_pointer { - my ($s_ptr) = @_; - return $s_ptr eq '(nil)' ? 0 : hex($s_ptr); -} - -sub allocated { - my ($line, $s_base, $size, $callers) = @_; - my ($base) = interp_pointer($s_base); - return if !$base; - my ($info) = {LINE => $line, - BASE => $base, - SIZE => $size, - CALLERS => $callers}; - if (exists($blocks{$base})) { - print "In-use address returned by allocator:\n"; - print "\tInitial allocation:\n"; - print_block("\t\t", $blocks{$base}); - print "\tNew allocation:\n"; - print_block("\t\t", $info); - } - $blocks{$base} = $info; -} - -sub claimed { - my ($line, $s_base, $callers) = @_; - my ($base) = interp_pointer($s_base); - return if !$base; - if (exists($blocks{$base})) { - $blocks{$base}{LINE} = $line; - $blocks{$base}{CALLERS} = $callers; - } else { - printf "Claim asserted on not-in-use block 0x%08x by:\n", $base; - print_callers('', $callers); - } -} - -sub freed { - my ($line, $s_base, $callers) = @_; - my ($base) = interp_pointer($s_base); - return if !$base; - - if (!delete($blocks{$base})) { - printf "Bad free of not-allocated address 0x%08x on stdin:%d by:\n", $base, $line; - print_callers('', $callers); - } -} - -sub print_block { - my ($prefix, $info) = @_; - printf '%s%d-byte block at 0x%08x allocated on stdin:%d by:' . "\n", - $prefix, $info->{SIZE}, $info->{BASE}, $info->{LINE}; - print_callers($prefix, $info->{CALLERS}); -} - -sub print_callers { - my ($prefix, $callers) = @_; - foreach my $pc (split(' ', $callers)) { - print "$prefix\t", lookup_pc($pc), "\n"; - } -} - -our (%cache); -sub lookup_pc { - my ($s_pc) = @_; - if (defined($binary)) { - my ($pc) = hex($s_pc); - my ($output) = "$s_pc: "; - if (!exists($cache{$pc})) { - open(A2L, "$a2l -fe $binary --demangle $s_pc|"); - chomp(my $function = ); - chomp(my $line = ); - close(A2L); - if ($function eq '??') { - ($function, $line) = lookup_pc_by_segment($pc); - } - $line =~ s/^(\.\.\/)*//; - $line = "..." . substr($line, -25) if length($line) > 28; - $cache{$pc} = "$s_pc: $function ($line)"; - } - return $cache{$pc}; - } else { - return "$s_pc"; - } -} - -sub trim_callers { - my ($in) = @_; - my (@out); - foreach my $pc (split(' ', $in)) { - my $xlated = lookup_pc($pc); - if ($xlated =~ /\?\?/) { - push(@out, "...") if !@out || $out[$#out] ne '...'; - } else { - push(@out, $pc); - } - } - return join(' ', @out); -} - -sub search_path { - my ($target) = @_; - for my $dir (split (':', $ENV{PATH})) { - my ($file) = "$dir/$target"; - return $file if -e $file; - } - return undef; -} - -sub add_segment { - my ($vm_start, $vm_end, $vm_pgoff, $file) = @_; - for (my $i = 0; $i <= $#segments; $i++) { - my ($s) = $segments[$i]; - next if $vm_end <= $s->{START} || $vm_start >= $s->{END}; - if ($vm_start <= $s->{START} && $vm_end >= $s->{END}) { - splice(@segments, $i, 1); - --$i; - } else { - $s->{START} = $vm_end if $vm_end > $s->{START}; - $s->{END} = $vm_start if $vm_start <= $s->{END}; - } - } - push(@segments, {START => $vm_start, - END => $vm_end, - PGOFF => $vm_pgoff, - FILE => $file}); - @segments = sort { $a->{START} <=> $b->{START} } @segments; -} - -sub binary_search { - my ($array, $value) = @_; - my $l = 0; - my $r = $#{$array}; - while ($l <= $r) { - my $m = int(($l + $r) / 2); - my $e = $array->[$m]; - if ($value < $e->{START}) { - $r = $m - 1; - } elsif ($value >= $e->{END}) { - $l = $m + 1; - } else { - return $e; - } - } - return undef; -} - -sub read_sections { - my ($file) = @_; - my (@sections); - open(OBJDUMP, "$objdump -h $file|"); - while () { - my $ptr = "([0-9a-fA-F]+)"; - my ($name, $size, $vma, $lma, $file_off) - = /^\s*\d+\s+(\S+)\s+$ptr\s+$ptr\s+$ptr\s+$ptr/ - or next; - push(@sections, {START => hex($file_off), - END => hex($file_off) + hex($size), - NAME => $name}); - } - close(OBJDUMP); - return [sort { $a->{START} <=> $b->{START} } @sections ]; -} - -our %file_to_sections; -sub segment_to_section { - my ($file, $file_offset) = @_; - if (!defined($file_to_sections{$file})) { - $file_to_sections{$file} = read_sections($file); - } - return binary_search($file_to_sections{$file}, $file_offset); -} - -sub address_to_segment { - my ($pc) = @_; - return binary_search(\@segments, $pc); -} - -sub lookup_pc_by_segment { - return ('??', 0) if !defined($objdump); - - my ($pc) = @_; - my ($segment) = address_to_segment($pc); - return ('??', 0) if !defined($segment) || $segment->{FILE} eq ''; - - my ($file_offset) = $pc - $segment->{START} + $segment->{PGOFF}; - my ($section) = segment_to_section($segment->{FILE}, $file_offset); - return ('??', 0) if !defined($section); - - my ($section_offset) = $file_offset - $section->{START}; - open(A2L, sprintf("%s -fe %s --demangle --section=$section->{NAME} 0x%x|", - $a2l, $segment->{FILE}, $section_offset)); - chomp(my $function = ); - chomp(my $line = ); - close(A2L); - - return ($function, $line); -} - -# Local Variables: -# mode: perl -# End: diff --git a/openflow/utilities/ofp-parse-leaks.in b/openflow/utilities/ofp-parse-leaks.in deleted file mode 100755 index 059c8509..00000000 --- a/openflow/utilities/ofp-parse-leaks.in +++ /dev/null @@ -1,285 +0,0 @@ -#! @PERL@ - -use strict; -use warnings; - -if (grep($_ eq '--help', @ARGV)) { - print < 1; -die "$0: $ARGV[0] does not exist" if @ARGV > 0 && ! -e $ARGV[0]; - -our ($binary); -our ($a2l) = search_path("addr2line"); -my ($no_syms) = "symbols will not be translated"; -if (!@ARGV) { - print "no binary specified; $no_syms\n"; -} elsif (! -e $ARGV[0]) { - print "$ARGV[0] does not exist; $no_syms"; -} elsif (!defined($a2l)) { - print "addr2line not found in PATH; $no_syms"; -} else { - $binary = $ARGV[0]; -} - -our ($objdump) = search_path("objdump"); -print "objdump not found; dynamic library symbols will not be translated\n" - if !defined($objdump); - -our %blocks; -our @segments; -while () { - my $ptr = "((?:0x)?[0-9a-fA-F]+|\\(nil\\))"; - my $callers = ":((?: $ptr)+)"; - if (/^malloc\((\d+)\) -> $ptr$callers$/) { - allocated($., $2, $1, $3); - } elsif (/^claim\($ptr\)$callers$/) { - claimed($., $1, $2); - } elsif (/realloc\($ptr, (\d+)\) -> $ptr$callers$/) { - my ($callers) = $4; - freed($., $1, $callers); - allocated($., $3, $2, $callers); - } elsif (/^free\($ptr\)$callers$/) { - freed($., $1, $2); - } elsif (/^segment: $ptr-$ptr $ptr [-r][-w][-x][sp] (.*)/) { - add_segment(hex($1), hex($2), hex($3), $4); - } else { - print "stdin:$.: syntax error\n"; - } -} -if (%blocks) { - my $n_blocks = scalar(keys(%blocks)); - my $n_bytes = 0; - $n_bytes += $_->{SIZE} foreach values(%blocks); - print "$n_bytes bytes in $n_blocks blocks not freed at end of run\n"; - my %blocks_by_callers; - foreach my $block (values(%blocks)) { - my ($trimmed_callers) = trim_callers($block->{CALLERS}); - push (@{$blocks_by_callers{$trimmed_callers}}, $block); - } - foreach my $callers (sort {@{$b} <=> @{$a}} (values(%blocks_by_callers))) { - $n_blocks = scalar(@{$callers}); - $n_bytes = 0; - $n_bytes += $_->{SIZE} foreach @{$callers}; - print "$n_bytes bytes in these $n_blocks blocks were not freed:\n"; - my $i = 0; - my $max = 5; - foreach my $block (sort {$a->{LINE} <=> $b->{LINE}} (@{$callers})) { - printf "\t%d-byte block at 0x%08x allocated on stdin:%d\n", - $block->{SIZE}, $block->{BASE}, $block->{LINE}; - last if $i++ > $max; - } - print "\t...and ", $n_blocks - $max, " others...\n" - if $n_blocks > $max; - print "The blocks listed above were allocated by:\n"; - print_callers("\t", ${$callers}[0]->{CALLERS}); - } -} -sub interp_pointer { - my ($s_ptr) = @_; - return $s_ptr eq '(nil)' ? 0 : hex($s_ptr); -} - -sub allocated { - my ($line, $s_base, $size, $callers) = @_; - my ($base) = interp_pointer($s_base); - return if !$base; - my ($info) = {LINE => $line, - BASE => $base, - SIZE => $size, - CALLERS => $callers}; - if (exists($blocks{$base})) { - print "In-use address returned by allocator:\n"; - print "\tInitial allocation:\n"; - print_block("\t\t", $blocks{$base}); - print "\tNew allocation:\n"; - print_block("\t\t", $info); - } - $blocks{$base} = $info; -} - -sub claimed { - my ($line, $s_base, $callers) = @_; - my ($base) = interp_pointer($s_base); - return if !$base; - if (exists($blocks{$base})) { - $blocks{$base}{LINE} = $line; - $blocks{$base}{CALLERS} = $callers; - } else { - printf "Claim asserted on not-in-use block 0x%08x by:\n", $base; - print_callers('', $callers); - } -} - -sub freed { - my ($line, $s_base, $callers) = @_; - my ($base) = interp_pointer($s_base); - return if !$base; - - if (!delete($blocks{$base})) { - printf "Bad free of not-allocated address 0x%08x on stdin:%d by:\n", $base, $line; - print_callers('', $callers); - } -} - -sub print_block { - my ($prefix, $info) = @_; - printf '%s%d-byte block at 0x%08x allocated on stdin:%d by:' . "\n", - $prefix, $info->{SIZE}, $info->{BASE}, $info->{LINE}; - print_callers($prefix, $info->{CALLERS}); -} - -sub print_callers { - my ($prefix, $callers) = @_; - foreach my $pc (split(' ', $callers)) { - print "$prefix\t", lookup_pc($pc), "\n"; - } -} - -our (%cache); -sub lookup_pc { - my ($s_pc) = @_; - if (defined($binary)) { - my ($pc) = hex($s_pc); - my ($output) = "$s_pc: "; - if (!exists($cache{$pc})) { - open(A2L, "$a2l -fe $binary --demangle $s_pc|"); - chomp(my $function = ); - chomp(my $line = ); - close(A2L); - if ($function eq '??') { - ($function, $line) = lookup_pc_by_segment($pc); - } - $line =~ s/^(\.\.\/)*//; - $line = "..." . substr($line, -25) if length($line) > 28; - $cache{$pc} = "$s_pc: $function ($line)"; - } - return $cache{$pc}; - } else { - return "$s_pc"; - } -} - -sub trim_callers { - my ($in) = @_; - my (@out); - foreach my $pc (split(' ', $in)) { - my $xlated = lookup_pc($pc); - if ($xlated =~ /\?\?/) { - push(@out, "...") if !@out || $out[$#out] ne '...'; - } else { - push(@out, $pc); - } - } - return join(' ', @out); -} - -sub search_path { - my ($target) = @_; - for my $dir (split (':', $ENV{PATH})) { - my ($file) = "$dir/$target"; - return $file if -e $file; - } - return undef; -} - -sub add_segment { - my ($vm_start, $vm_end, $vm_pgoff, $file) = @_; - for (my $i = 0; $i <= $#segments; $i++) { - my ($s) = $segments[$i]; - next if $vm_end <= $s->{START} || $vm_start >= $s->{END}; - if ($vm_start <= $s->{START} && $vm_end >= $s->{END}) { - splice(@segments, $i, 1); - --$i; - } else { - $s->{START} = $vm_end if $vm_end > $s->{START}; - $s->{END} = $vm_start if $vm_start <= $s->{END}; - } - } - push(@segments, {START => $vm_start, - END => $vm_end, - PGOFF => $vm_pgoff, - FILE => $file}); - @segments = sort { $a->{START} <=> $b->{START} } @segments; -} - -sub binary_search { - my ($array, $value) = @_; - my $l = 0; - my $r = $#{$array}; - while ($l <= $r) { - my $m = int(($l + $r) / 2); - my $e = $array->[$m]; - if ($value < $e->{START}) { - $r = $m - 1; - } elsif ($value >= $e->{END}) { - $l = $m + 1; - } else { - return $e; - } - } - return undef; -} - -sub read_sections { - my ($file) = @_; - my (@sections); - open(OBJDUMP, "$objdump -h $file|"); - while () { - my $ptr = "([0-9a-fA-F]+)"; - my ($name, $size, $vma, $lma, $file_off) - = /^\s*\d+\s+(\S+)\s+$ptr\s+$ptr\s+$ptr\s+$ptr/ - or next; - push(@sections, {START => hex($file_off), - END => hex($file_off) + hex($size), - NAME => $name}); - } - close(OBJDUMP); - return [sort { $a->{START} <=> $b->{START} } @sections ]; -} - -our %file_to_sections; -sub segment_to_section { - my ($file, $file_offset) = @_; - if (!defined($file_to_sections{$file})) { - $file_to_sections{$file} = read_sections($file); - } - return binary_search($file_to_sections{$file}, $file_offset); -} - -sub address_to_segment { - my ($pc) = @_; - return binary_search(\@segments, $pc); -} - -sub lookup_pc_by_segment { - return ('??', 0) if !defined($objdump); - - my ($pc) = @_; - my ($segment) = address_to_segment($pc); - return ('??', 0) if !defined($segment) || $segment->{FILE} eq ''; - - my ($file_offset) = $pc - $segment->{START} + $segment->{PGOFF}; - my ($section) = segment_to_section($segment->{FILE}, $file_offset); - return ('??', 0) if !defined($section); - - my ($section_offset) = $file_offset - $section->{START}; - open(A2L, sprintf("%s -fe %s --demangle --section=$section->{NAME} 0x%x|", - $a2l, $segment->{FILE}, $section_offset)); - chomp(my $function = ); - chomp(my $line = ); - close(A2L); - - return ($function, $line); -} - -# Local Variables: -# mode: perl -# End: diff --git a/openflow/utilities/ofp-pki-cgi.in b/openflow/utilities/ofp-pki-cgi.in deleted file mode 100755 index 837b3f92..00000000 --- a/openflow/utilities/ofp-pki-cgi.in +++ /dev/null @@ -1,41 +0,0 @@ -#! @PERL@ - -use CGI; -use Digest::SHA1; -use Fcntl; - -$CGI::POST_MAX = 65536; # Limit POSTs to 64 kB. - -use strict; -use warnings; - -my $pkidir = '@PKIDIR@'; -my $q = new CGI; - -die unless $q->request_method() eq 'POST'; - -my $type = $q->param('type'); -die unless defined $type; -die unless $type eq 'switch' or $type eq 'controller'; - -my $req = $q->param('req'); -die unless defined $req; -die unless $req =~ /^-----BEGIN CERTIFICATE REQUEST-----$/m; -die unless $req =~ /^-----END CERTIFICATE REQUEST-----$/m; - -my $digest = Digest::SHA1::sha1_hex($req); -my $incoming = "$pkidir/${type}ca/incoming"; -my $dst = "$incoming/$digest-req.pem"; - -sysopen(REQUEST, "$dst.tmp", O_RDWR | O_CREAT | O_EXCL, 0600) - or die "sysopen $dst.tmp: $!"; -print REQUEST $req; -close(REQUEST) or die "close $dst.tmp: $!"; - -rename("$dst.tmp", $dst) or die "rename $dst.tmp to $dst: $!"; - -print $q->header('text/html', '204 No response'); - -# Local Variables: -# mode: perl -# End: diff --git a/openflow/utilities/ofp-pki.8.in b/openflow/utilities/ofp-pki.8.in deleted file mode 100644 index 82558955..00000000 --- a/openflow/utilities/ofp-pki.8.in +++ /dev/null @@ -1,325 +0,0 @@ -.TH ofp\-pki 8 "May 2008" "OpenFlow" "OpenFlow Manual" - -.SH NAME -ofp\-pki \- OpenFlow public key infrastructure management utility - -.SH SYNOPSIS -\fBofp\-pki\fR [\fIOPTIONS\fR] \fICOMMAND\fR [\fIARGS\fR] -.sp -Stand\-alone commands with their arguments: -.br -\fBofp\-pki\fR \fBinit\fR -.br -\fBofp\-pki\fR \fBreq\fR \fINAME\fR -.br -\fBofp\-pki\fR \fBsign\fR \fINAME\fR [\fITYPE\fR] -.br -\fBofp\-pki\fR \fBreq+sign\fR \fINAME\fR [\fITYPE\fR] -.br -\fBofp\-pki\fR \fBverify\fR \fINAME\fR [\fITYPE\fR] -.br -\fBofp\-pki\fR \fBfingerprint\fR \fIFILE\fR -.br -\fBofp\-pki\fR \self-sign\fR \fINAME\fR -.sp -The following additional commands manage an online PKI: -.br -\fBofp\-pki\fR \fBls\fR [\fIPREFIX\fR] [\fITYPE\fR] -.br -\fBofp\-pki\fR \fBflush\fR [\fITYPE\fR] -.br -\fBofp\-pki\fR \fBreject\fR \fIPREFIX\fR [\fITYPE\fR] -.br -\fBofp\-pki\fR \fBapprove\fR \fIPREFIX\fR [\fITYPE\fR] -.br -\fBofp\-pki\fR \fBprompt\fR [\fITYPE\fR] -.br -\fBofp\-pki\fR \fBexpire\fR [\fIAGE\fR] -.sp -Each \fITYPE\fR above is a certificate type, either \fBswitch\fR -(default) or \fBcontroller\fR. -.sp -The available options are: -.br -[\fB\-k\fR \fItype\fR | \fB\-\^\-key=\fItype\fR] -[\fB\-B\fR \fInbits\fR | \fB\-\^\-bits=\fInbits\fR] -[\fB\-D\fR \fIfile\fR | \fB\-\^\-dsaparam=\fIfile\fR] -[\fB\-b\fR | \fB\-\^\-batch\fR] -[\fB\-f\fR | \fB\-\^\-force\fR] -[\fB\-d\fR \fIdir\fR | \fB\-\^\-dir=\fR\fIdir\fR] -[\fB\-l\fR \fIfile\fR | \fB\-\^\-log=\fIfile\fR] -[\fB\-h\fR | \fB\-\^\-help\fR] -.br -Some options do not apply to every command. - -.SH DESCRIPTION -The \fBofp\-pki\fR program sets up and manages a public key -infrastructure for use with OpenFlow. It is intended to be a simple -interface for organizations that do not have an established public key -infrastructure. Other PKI tools can substitute for or supplement the -use of \fBofp\-pki\fR. - -\fBofp\-pki\fR uses \fBopenssl\fR(1) for certificate management and key -generation. - -.SH "OFFLINE COMMANDS" - -The following \fBofp\-pki\fR commands support manual PKI -administration: - -.TP -\fBinit\fR -Initializes a new PKI (by default in directory \fB@PKIDIR@\fR) and populates -it with a pair of certificate authorities for controllers and -switches. - -This command should ideally be run on a high\-security machine separate -from any OpenFlow controller or switch, called the CA machine. The -files \fBpki/controllerca/cacert.pem\fR and -\fBpki/switchca/cacert.pem\fR that it produces will need to be copied -over to the OpenFlow switches and controllers, respectively. Their -contents may safely be made public. - -By default, \fBofp\-pki\fR generates 2048\-bit RSA keys. The \fB\-B\fR -or \fB\-\^\-bits\fR option (see below) may be used to override the key -length. The \fB\-k dsa\fR or \fB\-\^\-key=dsa\fR option may be used to use -DSA in place of RSA. If DSA is selected, the \fBdsaparam.pem\fR file -generated in the new PKI hierarchy must be copied to any machine on -which the \fBreq\fR command (see below) will be executed. Its -contents may safely be made public. - -Other files generated by \fBinit\fR may remain on the CA machine. -The files \fBpki/controllerca/private/cakey.pem\fR and -\fBpki/switchca/private/cakey.pem\fR have particularly sensitive -contents that should not be exposed. - -.TP -\fBreq\fR \fINAME\fR -Generates a new private key named \fINAME\fR\fB\-privkey.pem\fR and -corresponding certificate request named \fINAME\fR\fB\-req.pem\fR. -The private key can be intended for use by a switch or a controller. - -This command should ideally be run on the switch or controller that -will use the private key to identify itself. The file -\fINAME\fR\fB\-req.pem\fR must be copied to the CA machine for signing -with the \fBsign\fR command (below). - -This command will output a fingerprint to stdout as its final step. -Write down the fingerprint and take it to the CA machine before -continuing with the \fBsign\fR step. - -When RSA keys are in use (as is the default), \fBreq\fR, unlike the -rest of \fBofp\-pki\fR's commands, does not need access to a PKI -hierarchy created by \fBofp\-pki init\fR. The \fB\-B\fR or -\fB\-\^\-bits\fR option (see below) may be used to specify the number of -bits in the generated RSA key. - -When DSA keys are used (as specified with \fB\-\^\-key=dsa\fR), \fBreq\fR -needs access to the \fBdsaparam.pem\fR file created as part of the PKI -hierarchy (but not to other files in that tree). By default, -\fBofp\-pki\fR looks for this file in \fB@PKIDIR@/dsaparam.pem\fR, but -the \fB\-D\fR or \fB\-\^\-dsaparam\fR option (see below) may be used to -specify an alternate location. - -\fINAME\fR\fB\-privkey.pem\fR has sensitive contents that should not be -exposed. \fINAME\fR\fB\-req.pem\fR may be safely made public. - -.TP -\fBsign\fR \fINAME\fR [\fITYPE\fR] -Signs the certificate request named \fINAME\fR\fB\-req.pem\fR that was -produced in the previous step, producing a certificate named -\fINAME\fR\fB\-cert.pem\fR. \fITYPE\fR, either \fBswitch\fR (default) or -\fBcontroller\fR, indicates the use for which the key is being -certified. - -This command must be run on the CA machine. - -The command will output a fingerprint to stdout and request that you -verify that it is the same fingerprint output by the \fBreq\fR -command. This ensures that the request being signed is the same one -produced by \fBreq\fR. (The \fB\-b\fR or \fB\-\^\-batch\fR option -suppresses the verification step.) - -The file \fINAME\fR\fB\-cert.pem\fR will need to be copied back to the -switch or controller for which it is intended. Its contents may -safely be made public. - -.TP -\fBreq+sign\fR \fINAME\fR [\fITYPE\fR] -Combines the \fBreq\fR and \fBsign\fR commands into a single step, -outputting all the files produced by each. The -\fINAME\fR\fB\-privkey.pem\fR and \fINAME\fR\fB\-cert.pem\fR files must -be copied securely to the switch or controller. -\fINAME\fR\fB\-privkey.pem\fR has sensitive contents and must not be -exposed in transit. Afterward, it should be deleted from the CA -machine. - -This combined method is, theoretically, less secure than the -individual steps performed separately on two different machines, -because there is additional potential for exposure of the private -key. However, it is also more convenient. - -.TP -\fBverify\fR \fINAME\fR [\fITYPE\fR] -Verifies that \fINAME\fR\fB\-cert.pem\fR is a valid certificate for the -given \fITYPE\fR of use, either \fBswitch\fR (default) or -\fBcontroller\fR. If the certificate is valid for this use, it prints -the message ``\fINAME\fR\fB\-cert.pem\fR: OK''; otherwise, it prints an -error message. - -.TP -\fBfingerprint\fR \fIFILE\fR -Prints the fingerprint for \fIFILE\fR. If \fIFILE\fR is a -certificate, then this is the SHA\-1 digest of the DER encoded version -of the certificate; otherwise, it is the SHA\-1 digest of the entire -file. - -.TP -\fBself-sign\fR \fINAME\fR -Signs the certificate request named \fINAME\fB\-req.pem\fR using the -private key \fINAME\fB-privkey.pem\fR, producing a self-signed -certificate named \fINAMEfB\-cert.pem\fR. The input files should have -been produced with \fBofp\-pki req\fR. - -Some controllers accept such self-signed certificates. - -.SH "ONLINE COMMANDS" - -An OpenFlow PKI can be administered online, in conjunction with -.BR ofp\-pki\-cgi (8) -and a web server such as Apache: - -.IP \(bu -The web server exports the contents of the PKI via HTTP. All files in -a PKI hierarchy files may be made public, except for the files -\fBpki/controllerca/private/cakey.pem\fR and -\fBpki/switchca/private/cakey.pem\fR, which must not be exposed. - -.IP \(bu -\fBofp\-pki\-cgi\fR allows newly generated certificate requests for -controllers and switches to be uploaded into the -\fBpki/controllerca/incoming\fR and \fBpki/switchca/incoming\fR -directories, respectively. Uploaded certificate requests are stored -in those directories under names of the form -\fIFINGERPRINT\fB\-req.pem\fR, which \fIFINGERPRINT\fR is the SHA\-1 -hash of the file. - -.IP \(bu -These \fBofp\-pki\fR commands allow incoming certificate requests to -be approved or rejected, in a form are suitable for use by humans or -other software. - -.PP -The following \fBofp\-pki\fR commands support online administration: - -.TP -\fBofp\-pki\fR \fBls\fR [\fIPREFIX\fR] [\fITYPE\fR] -Lists all of the incoming certificate requests of the given \fITYPE\fR -(either \fBswitch\fR, the default, or \fBcontroller\fR). If -\fIPREFIX\fR, which must be at least 4 characters long, is specified, -it causes the list to be limited to files whose names begin with -\fIPREFIX\fR. This is useful, for example, to avoid typing in an -entire fingerprint when checking that a specific certificate request -has been received. - -.TP -\fBofp\-pki\fR \fBflush\fR [\fITYPE\fR] -Deletes all certificate requests of the given \fITYPE\fR. - -.TP -\fBofp\-pki\fR \fBreject\fR \fIPREFIX\fR [\fITYPE\fR] -Rejects the certificate request whose name begins with \fIPREFIX\fR, -which must be at least 4 characters long, of the given type (either -\fBswitch\fR, the default, or \fBcontroller\fR). \fIPREFIX\fR must -match exactly one certificate request; its purpose is to allow the -user to type fewer characters, not to match multiple certificate -requests. - -.TP -\fBofp\-pki\fR \fBapprove\fR \fIPREFIX\fR [\fITYPE\fR] -Approves the certificate request whose name begins with \fIPREFIX\fR, -which must be at least 4 characters long, of the given \fITYPE\fR -(either \fBswitch\fR, the default, or \fBcontroller\fR). \fIPREFIX\fR -must match exactly one certificate request; its purpose is to allow -the user to type fewer characters, not to match multiple certificate -requests. - -The command will output a fingerprint to stdout and request that you -verify that it is correct. (The \fB\-b\fR or \fB\-\^\-batch\fR option -suppresses the verification step.) - -.TP -\fBofp\-pki\fR \fBprompt\fR [\fITYPE\fR] -Prompts the user for each incoming certificate request of the given -\fITYPE\fR (either \fBswitch\fR, the default, or \fBcontroller\fR). -Based on the certificate request's fingerprint, the user is given the -option of approving, rejecting, or skipping the certificate request. - -.TP -\fBofp\-pki\fR \fBexpire\fR [\fIAGE\fR] - -Rejects all the incoming certificate requests, of either type, that is -older than \fIAGE\fR, which must in one of the forms \fIN\fBs\fR, -\fIN\fBmin\fR, \fIN\fBh\fR, \fIN\fBday\fR. The default is \fB1day\fR. - -.SH OPTIONS -.TP -\fB\-k\fR \fItype\fR | \fB\-\^\-key=\fItype\fR -For the \fBinit\fR command, sets the public key algorithm to use for -the new PKI hierarchy. For the \fBreq\fR and \fBreq+sign\fR commands, -sets the public key algorithm to use for the key to be generated, -which must match the value specified on \fBinit\fR. With other -commands, the value has no effect. - -The \fItype\fR may be \fBrsa\fR (the default) or \fBdsa\fR. - -.TP -\fB\-B\fR \fInbits\fR | \fB\-\^\-bits=\fInbits\fR -Sets the number of bits in the key to be generated. When RSA keys are -in use, this option affects only the \fBinit\fR, \fBreq\fR, and -\fBreq+sign\fR commands, and the same value should be given each time. -With DSA keys are in use, this option affects only the \fBinit\fR -command. - -The value must be at least 1024. The default is 2048. - -.TP -\fB\-D\fR \fIfile\fR | \fB\-\^\-dsaparam=\fIfile\fR -Specifies an alternate location for the \fBdsaparam.pem\fR file -required by the \fBreq\fR and \fBreq+sign\fR commands. This option -affects only these commands, and only when DSA keys are used. - -The default is \fBdsaparam.pem\fR under the PKI hierarchy. - -.TP -\fB\-b\fR | \fB\-\^\-batch\fR -Suppresses the interactive verification of fingerprints that the -\fBsign\fR and \fBapprove\fR commands by default require. - -.TP -\fB\-d\fR \fIdir\fR | \fB\-\^\-dir=\fR\fIdir\fR -Specifies the location of the PKI hierarchy to be used or created by -the command (default: \fB@PKIDIR@\fR). All commands, except \fBreq\fR, -need access to a PKI hierarchy. - -.TP -\fB\-f\fR | \fB\-\^\-force\fR -By default, \fBofp\-pki\fR will not overwrite existing files or -directories. This option overrides this behavior. - -.TP -\fB\-l\fR \fIfile\fR | \fB\-\^\-log=\fIfile\fR -Sets the log file to \fIfile\fR. Default: -\fB@LOGDIR@/ofp\-pki.log\fR. - -.TP -\fB\-h\fR | \fB\-\^\-help\fR -Prints a help usage message and exits. - -.SH "SEE ALSO" - -.BR controller (8), -.BR dpctl (8), -.BR ofp\-pki\-cgi (8), -.BR ofprotocol (8), -.BR ofdatapath (8) diff --git a/openflow/utilities/ofp-pki.in b/openflow/utilities/ofp-pki.in deleted file mode 100755 index 3a50cff8..00000000 --- a/openflow/utilities/ofp-pki.in +++ /dev/null @@ -1,582 +0,0 @@ -#! /bin/sh - -set -e - -pkidir='@PKIDIR@' -command= -prev= -force=no -batch=no -log='@LOGDIR@/ofp-pki.log' -keytype=rsa -bits=2048 -for option; do - # This option-parsing mechanism borrowed from a Autoconf-generated - # configure script under the following license: - - # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, - # 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. - # This configure script is free software; the Free Software Foundation - # gives unlimited permission to copy, distribute and modify it. - - # If the previous option needs an argument, assign it. - if test -n "$prev"; then - eval $prev=\$option - prev= - continue - fi - case $option in - *=*) optarg=`expr "X$option" : '[^=]*=\(.*\)'` ;; - *) optarg=yes ;; - esac - - case $dashdash$option in - --) - dashdash=yes ;; - -h|--help) - cat <&2 - exit 1 - ;; - *) - if test -z "$command"; then - command=$option - elif test -z "${arg1+set}"; then - arg1=$option - elif test -z "${arg2+set}"; then - arg2=$option - else - echo "$option: only two arguments may be specified" >&2 - exit 1 - fi - ;; - esac - shift -done -if test -n "$prev"; then - option=--`echo $prev | sed 's/_/-/g'` - { echo "$as_me: error: missing argument to $option" >&2 - { (exit 1); exit 1; }; } -fi -if test -z "$command"; then - echo "$0: missing command name; use --help for help" >&2 - exit 1 -fi -if test "$keytype" != rsa && test "$keytype" != dsa; then - echo "$0: argument to -k or --key must be rsa or dsa" - exit 1 -fi -if test "$bits" -lt 1024; then - echo "$0: argument to -B or --bits must be at least 1024" - exit 1 -fi -if test -z "$dsaparam"; then - dsaparam=$pkidir/dsaparam.pem -fi -case $log in - /*) ;; - *) $log="$PWD/$log" ;; -esac - -if test "$command" = "init"; then - if test -e "$pkidir" && test "$force" != "yes"; then - echo "$0: $pkidir already exists and --force not specified" >&2 - exit 1 - fi - - if test ! -d "$pkidir"; then - mkdir -p "$pkidir" - fi - cd "$pkidir" - exec 3>>$log - - if test $keytype = dsa && test ! -e dsaparam.pem; then - echo "Generating DSA parameters, please wait..." >&2 - openssl dsaparam -out dsaparam.pem $bits 1>&3 2>&3 - fi - - # Create the CAs. - for ca in controllerca switchca; do - echo "Creating $ca..." >&2 - oldpwd=$PWD - mkdir -p $ca - cd $ca - - mkdir -p certs crl newcerts - mkdir -p -m 0700 private - mkdir -p -m 0733 incoming - touch index.txt - test -e crlnumber || echo 01 > crlnumber - test -e serial || echo 01 > serial - - # Put DSA parameters in directory. - if test $keytype = dsa && test ! -e dsaparam.pem; then - cp ../dsaparam.pem . - fi - - # Write CA configuration file. - if test ! -e ca.cnf; then - sed "s/@ca@/$ca/g" > ca.cnf <<'EOF' -[ req ] -prompt = no -distinguished_name = req_distinguished_name - -[ req_distinguished_name ] -C = US -ST = CA -L = Palo Alto -O = OpenFlow -OU = @ca@ -CN = OpenFlow @ca@ CA Certificate - -[ ca ] -default_ca = the_ca - -[ the_ca ] -dir = . # top dir -database = $dir/index.txt # index file. -new_certs_dir = $dir/newcerts # new certs dir -certificate = $dir/cacert.pem # The CA cert -serial = $dir/serial # serial no file -private_key = $dir/private/cakey.pem# CA private key -RANDFILE = $dir/private/.rand # random number file -default_days = 365 # how long to certify for -default_crl_days= 30 # how long before next CRL -default_md = md5 # md to use -policy = policy # default policy -email_in_dn = no # Don't add the email into cert DN -name_opt = ca_default # Subject name display option -cert_opt = ca_default # Certificate display option -copy_extensions = none # Don't copy extensions from request - -# For the CA policy -[ policy ] -countryName = optional -stateOrProvinceName = optional -organizationName = match -organizationalUnitName = optional -commonName = supplied -emailAddress = optional -EOF - fi - - # Create certificate authority. - if test $keytype = dsa; then - newkey=dsa:dsaparam.pem - else - newkey=rsa:$bits - fi - openssl req -config ca.cnf -nodes \ - -newkey $newkey -keyout private/cakey.pem -out careq.pem \ - 1>&3 2>&3 - openssl ca -config ca.cnf -create_serial -out cacert.pem \ - -days 1095 -batch -keyfile private/cakey.pem -selfsign \ - -infiles careq.pem 1>&3 2>&3 - chmod 0700 private/cakey.pem - - cd "$oldpwd" - done - exit 0 -fi - -one_arg() { - if test -z "$arg1" || test -n "$arg2"; then - echo "$0: $command must have exactly one argument; use --help for help" >&2 - exit 1 - fi -} - -zero_or_one_args() { - if test -n "$arg2"; then - echo "$0: $command must have zero or one arguments; use --help for help" >&2 - exit 1 - fi -} - -one_or_two_args() { - if test -z "$arg1"; then - echo "$0: $command must have one or two arguments; use --help for help" >&2 - exit 1 - fi -} - -must_not_exist() { - if test -e "$1" && test "$force" != "yes"; then - echo "$0: $1 already exists and --force not supplied" >&2 - exit 1 - fi -} - -resolve_prefix() { - test -n "$type" || exit 123 # Forgot to call check_type? - - case $1 in - ????*) - ;; - *) - echo "Prefix $arg1 is too short (less than 4 hex digits)" - exit 0 - ;; - esac - - fingerprint=$(cd "$pkidir/${type}ca/incoming" && echo "$1"*-req.pem | sed 's/-req\.pem$//') - case $fingerprint in - "${1}*") - echo "No certificate requests matching $1" - exit 1 - ;; - *" "*) - echo "$1 matches more than one certificate request:" - echo $fingerprint | sed 's/ /\ -/g' - exit 1 - ;; - *) - # Nothing to do. - ;; - esac - req="$pkidir/${type}ca/incoming/$fingerprint-req.pem" - cert="$pkidir/${type}ca/certs/$fingerprint-cert.pem" -} - -make_tmpdir() { - TMP=/tmp/ofp-pki.tmp$$ - rm -rf $TMP - trap "rm -rf $TMP" 0 - mkdir -m 0700 $TMP -} - -fingerprint() { - local file=$1 - local name=${1-$2} - local date=$(date -r $file) - local fingerprint - if grep -q -e '-BEGIN CERTIFICATE-' "$file"; then - fingerprint=$(openssl x509 -noout -in "$file" -fingerprint | - sed 's/SHA1 Fingerprint=//' | tr -d ':') - else - fingerprint=$(sha1sum "$file" | awk '{print $1}') - fi - printf "$name\\t$date\\n" - case $file in - $fingerprint*) - printf "\\t(correct fingerprint in filename)\\n" - ;; - *) - printf "\\tfingerprint $fingerprint\\n" - ;; - esac -} - -verify_fingerprint() { - fingerprint "$@" - if test $batch != yes; then - echo "Does fingerprint match? (yes/no)" - read answer - if test "$answer" != yes; then - echo "Match failure, aborting" >&2 - exit 1 - fi - fi -} - -check_type() { - if test x = x"$1"; then - type=switch - elif test "$1" = switch || test "$1" = controller; then - type=$1 - else - echo "$0: type argument must be 'switch' or 'controller'" >&2 - exit 1 - fi -} - -parse_age() { - number=$(echo $1 | sed 's/^\([0-9]\+\)\([[:alpha:]]\+\)/\1/') - unit=$(echo $1 | sed 's/^\([0-9]\+\)\([[:alpha:]]\+\)/\2/') - case $unit in - s) - factor=1 - ;; - min) - factor=60 - ;; - h) - factor=3600 - ;; - day) - factor=86400 - ;; - *) - echo "$1: age not in the form Ns, Nmin, Nh, Nday (e.g. 1day)" >&2 - exit 1 - ;; - esac - echo $(($number * $factor)) -} - -must_exist() { - if test ! -e "$1"; then - echo "$0: $1 does not exist" >&2 - exit 1 - fi -} - -pkidir_must_exist() { - if test ! -e "$pkidir"; then - echo "$0: $pkidir does not exist (need to run 'init' or use '--dir'?)" >&2 - exit 1 - elif test ! -d "$pkidir"; then - echo "$0: $pkidir is not a directory" >&2 - exit 1 - fi -} - -make_request() { - must_not_exist "$arg1-privkey.pem" - must_not_exist "$arg1-req.pem" - make_tmpdir - cat > "$TMP/req.cnf" <&3 2>&3 -} - -sign_request() { - must_exist "$1" - must_not_exist "$2" - pkidir_must_exist - - (cd "$pkidir/${type}ca" && - openssl ca -config ca.cnf -batch -in /dev/stdin) \ - < "$1" > "$2.tmp$$" 2>&3 - mv "$2.tmp$$" "$2" -} - -glob() { - local files=$(echo $1) - if test "$files" != "$1"; then - echo "$files" - fi -} - -exec 3>>$log || true -if test "$command" = req; then - one_arg - - make_request "$arg1" - fingerprint "$arg1-req.pem" -elif test "$command" = sign; then - one_or_two_args - check_type "$arg2" - verify_fingerprint "$arg1-req.pem" - - sign_request "$arg1-req.pem" "$arg2-cert.pem" -elif test "$command" = req+sign; then - one_or_two_args - check_type "$arg2" - - pkidir_must_exist - make_request "$arg1" - sign_request "$arg1-req.pem" "$arg1-cert.pem" - fingerprint "$arg1-req.pem" -elif test "$command" = verify; then - one_or_two_args - must_exist "$arg1-cert.pem" - check_type "$arg2" - - pkidir_must_exist - openssl verify -CAfile "$pkidir/${type}ca/cacert.pem" "$arg1-cert.pem" -elif test "$command" = fingerprint; then - one_arg - - fingerprint "$arg1" -elif test "$command" = self-sign; then - one_arg - must_exist "$arg1-req.pem" - must_exist "$arg1-privkey.pem" - must_not_exist "$arg1-cert.pem" - - openssl x509 -in "$arg1-req.pem" -out "$arg1-cert.pem" \ - -signkey "$arg1-privkey.pem" -req -text 2>&3 -elif test "$command" = ls; then - check_type "$arg2" - - cd "$pkidir/${type}ca/incoming" - for file in $(glob "$arg1*-req.pem"); do - fingerprint $file - done -elif test "$command" = flush; then - check_type "$arg1" - - rm -f "$pkidir/${type}ca/incoming/"* -elif test "$command" = reject; then - one_or_two_args - check_type "$arg2" - resolve_prefix "$arg1" - - rm -f "$req" -elif test "$command" = approve; then - one_or_two_args - check_type "$arg2" - resolve_prefix "$arg1" - - make_tmpdir - cp "$req" "$TMP/$req" - verify_fingerprint "$TMP/$req" - sign_request "$TMP/$req" - rm -f "$req" "$TMP/$req" -elif test "$command" = prompt; then - zero_or_one_args - check_type "$arg1" - - make_tmpdir - cd "$pkidir/${type}ca/incoming" - for req in $(glob "*-req.pem"); do - cp "$req" "$TMP/$req" - - cert=$(echo "$pkidir/${type}ca/certs/$req" | - sed 's/-req.pem/-cert.pem/') - if test -f $cert; then - echo "Request $req already approved--dropping duplicate request" - rm -f "$req" "$TMP/$req" - continue - fi - - echo - echo - fingerprint "$TMP/$req" "$req" - printf "Disposition for this request (skip/approve/reject)? " - read answer - case $answer in - approve) - echo "Approving $req" - sign_request "$TMP/$req" "$cert" - rm -f "$req" "$TMP/$req" - ;; - r*) - echo "Rejecting $req" - rm -f "$req" "$TMP/$req" - ;; - *) - echo "Skipping $req" - ;; - esac - done -elif test "$command" = expire; then - zero_or_one_args - cutoff=$(($(date +%s) - $(parse_age ${arg1-1day}))) - for type in switch controller; do - cd "$pkidir/${type}ca/incoming" || exit 1 - for file in $(glob "*"); do - time=$(date -r "$file" +%s) - if test "$time" -lt "$cutoff"; then - rm -f "$file" - fi - done - done -else - echo "$0: $command command unknown; use --help for help" >&2 - exit 1 -fi diff --git a/openflow/utilities/vlogconf.8.in b/openflow/utilities/vlogconf.8.in deleted file mode 100644 index eb9c192e..00000000 --- a/openflow/utilities/vlogconf.8.in +++ /dev/null @@ -1,183 +0,0 @@ -.ds PN vlogconf - -.TH vlogconf 8 "June 2008" "OpenFlow" "OpenFlow Manual" - -.SH NAME -vlogconf \- configuration utility for OpenFlow logging in userspace - -.SH SYNOPSIS -\fBvlogconf\fR [\fB-h\fR | \fB--help\fR] [\fItarget\fR...] [\fIaction\fR...] -.sp 1 -The available \fItarget\fR options are: -.br -[\fB-a\fR | \fB--all\fR] [\fB-t\fR \fIpid\fR | \fB--target=\fIpid\fR] -.sp 1 -The available \fIaction\fR options are: -.br -[\fB-l\fR | \fB--list\fR] [\fB-s\fR -\fImodule\fR[\fB:\fIfacility\fR[\fB:\fIlevel\fR]] | -\fB--set=\fImodule\fR[\fB:\fIfacility\fR[\fB:\fIlevel\fR]]] -[\fB-r\fR | \fB--reopen\fR] - -.SH DESCRIPTION -The \fBvlogconf\fR program configures the logging system used by -OpenFlow userspace programs. The logging configuration may be modified -while OpenFlow programs are running. - -\fBvlogconf\fR applies one or more actions to each of one or more -target processes. Targets may be specified as: - -.TP -\fB-a\fR, \fB--all\fR -All running processes that \fBvlogconf\fR can control. - -.TP -\fB-t \fItarget\fR, \fB--target=\fItarget\fR -The specified \fItarget\fR, which must take one of the following forms: - -.RS -.IP \(bu -A PID (process ID). - -.IP \(bu -An absolute path (beginning with `/') to the Unix domain socket for a -\fBvlogconf\fR-controllable process. - -.IP \(bu -An absolute path (beginning with `/') to a pidfile (created by, e.g., -passing the \fB-P\fR or \fB--pidfile\fR option to one of the OpenFlow -programs). - -.IP \(bu -None of the above, in which case \fItarget\fR prefixed by -\fB@RUNDIR@/\fR must match one of the cases for absolute paths listed -above. (The default name for a program's pidfile is -\fB@RUNDIR@/\fIprogram\fB.pid\fR, so this means that, say, -\fBofprotocol\fR's default pidfile may be referred to simply as -\fBofprotocol.pid\fR.) -.RE - -.PP -The available actions are: - -.TP -\fB-l\fR, \fB--list\fR -Print the list of known modules and their current logging levels to -stdout. - -.TP -\fB-s\fR \fImodule\fR[\fB:\fIfacility\fR[\fB:\fIlevel\fR]], \fB--set=\fImodule\fR[\fB:\fIfacility\fR[\fB:\fIlevel\fR]] - -Sets the logging level for \fImodule\fR in \fIfacility\fR to -\fIlevel\fR. The \fImodule\fR may be any valid module name (as -displayed by the \fB--list\fR option) or the special name \fBANY\fR to -set the logging levels for all modules. The \fIfacility\fR may be -\fBsyslog\fR or \fBconsole\fR to set the levels for logging to the -system log or to the console, respectively, or \fBANY\fR to set the -logging levels for both facilities. If it is omitted, -\fIfacility\fR defaults to \fBANY\fR. The \fIlevel\fR must be one of -\fBemer\fR, \fBerr\fR, \fBwarn\fR, \fBinfo\fR, or \fBdbg\fR, designating the -minimum severity of a message for it to be logged. If it is omitted, -\fIlevel\fR defaults to \fBdbg\fR. - -.TP -\fB-s PATTERN:\fIfacility\fB:\fIpattern\fR, \fB--set=PATTERN:\fIfacility\fB:\fIpattern\fR - -Sets the log pattern for \fIfacility\fR to \fIpattern\fR. Each time a -message is logged to \fIfacility\fR, \fIpattern\fR determines the -message's formatting. Most characters in \fIpattern\fR are copied -literally to the log, but special escapes beginning with \fB%\fR are -expanded as follows: - -.RS -.TP -\fB%A\fR -The name of the application logging the message, e.g. \fBofprotocol\fR. - -.TP -\fB%c\fR -The name of the module (as shown by \fBvlogconf --list\fR) logging -the message. - -.TP -\fB%d\fR -The current date and time in ISO 8601 format (YYYY-MM-DD HH:MM:SS). - -.TP -\fB%d{\fIformat\fB}\fR -The current date and time in the specified \fIformat\fR, which takes -the same format as the \fItemplate\fR argument to \fBstrftime\fR(3). - -.TP -\fB%m\fR -The message being logged. - -.TP -\fB%N\fR -A serial number for this message within this run of the program, as a -decimal number. The first message a program logs has serial number 1, -the second one has serial number 2, and so on. - -.TP -\fB%n\fR -A new-line. - -.TP -\fB%p\fR -The level at which the message is logged, e.g. \fBDBG\fR. - -.TP -\fB%P\fR -The program's process ID (pid), as a decimal number. - -.TP -\fB%r\fR -The number of milliseconds elapsed from the start of the application -to the time the message was logged. - -.TP -\fB%%\fR -A literal \fB%\fR. -.RE - -.IP -A few options may appear between the \fB%\fR and the format specifier -character, in this order: - -.RS -.TP -\fB-\fR -Left justify the escape's expansion within its field width. Right -justification is the default. - -.TP -\fB0\fR -Pad the field to the field width with \fB0\fRs. Padding with spaces -is the default. - -.TP -\fIwidth\fR -A number specifies the minimum field width. If the escape expands to -fewer characters than \fIwidth\fR then it is padded to fill the field -width. (A field wider than \fIwidth\fR is not truncated to fit.) -.RE - -.IP -The default pattern for console output is \fB%d{%b %d -%H:%M:%S}|%05N|%c|%p|%m\fR; for syslog output, \fB%05N|%c|%p|%m\fR. - -.TP -\fB-r\fR, \fB--reopen\fR -Causes the target application to close and reopen its log file. (This -is useful after rotating log files, to cause a new log file to be -used.) - -.SH OPTIONS - -.so lib/common.man - -.SH "SEE ALSO" - -.BR dpctl (8), -.BR ofprotocol (8), -.BR controller (8) diff --git a/openflow/utilities/vlogconf.c b/openflow/utilities/vlogconf.c deleted file mode 100644 index 5c48f724..00000000 --- a/openflow/utilities/vlogconf.c +++ /dev/null @@ -1,235 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ -#include -#include "vlog.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "command-line.h" -#include "compiler.h" -#include "timeval.h" -#include "util.h" -#include "vlog-socket.h" - -static void -usage(char *prog_name, int exit_code) -{ - printf("Usage: %s [TARGET] [ACTION...]\n" - "Targets:\n" - " -a, --all Apply to all targets (default)\n" - " -t, --target=TARGET Specify target program, as a pid, a\n" - " pidfile, or an absolute path to a Unix\n" - " domain socket\n" - "Actions:\n" - " -l, --list List current settings\n" - " -s, --set=MODULE[:FACILITY[:LEVEL]]\n" - " Set MODULE and FACILITY log level to LEVEL\n" - " MODULE may be any valid module name or 'ANY'\n" - " FACILITY may be 'syslog', 'console', 'file', or 'ANY' (default)\n" - " LEVEL may be 'emer', 'err', 'warn', 'info', or 'dbg' (default)\n" - " -r, --reopen Make the program reopen its log file\n" - " -h, --help Print this helpful information\n", - prog_name); - exit(exit_code); -} - -static char * -transact(struct vlog_client *client, const char *request, bool *ok) -{ - char *reply; - int error = vlog_client_transact(client, request, &reply); - if (error) { - fprintf(stderr, "%s: transaction error: %s\n", - vlog_client_target(client), strerror(error)); - *ok = false; - } - return reply ? reply : xstrdup(""); -} - -static void -transact_ack(struct vlog_client *client, const char* request, bool *ok) -{ - char *reply; - int error = vlog_client_transact(client, request, &reply); - if (error) { - fprintf(stderr, "%s: transaction error: %s\n", - vlog_client_target(client), strerror(error)); - *ok = false; - } else if (strcmp(reply, "ack")) { - fprintf(stderr, "Received unexpected reply from %s: %s\n", - vlog_client_target(client), reply); - *ok = false; - } - free(reply); -} - -static void -add_target(struct vlog_client ***clients, size_t *n_clients, - const char *path, bool *ok) -{ - struct vlog_client *client; - int error = vlog_client_connect(path, &client); - if (error) { - fprintf(stderr, "Error connecting to \"%s\": %s\n", - path, strerror(error)); - *ok = false; - } else { - *clients = xrealloc(*clients, sizeof *clients * (*n_clients + 1)); - (*clients)[*n_clients] = client; - ++*n_clients; - } -} - -static void -add_all_targets(struct vlog_client ***clients, size_t *n_clients, bool *ok) -{ - DIR *directory; - struct dirent* de; - - directory = opendir("/tmp"); - if (!directory) { - fprintf(stderr, "/tmp: opendir: %s\n", strerror(errno)); - } - - while ((de = readdir(directory)) != NULL) { - if (!strncmp(de->d_name, "vlogs.", 5)) { - char *path = xasprintf("/tmp/%s", de->d_name); - add_target(clients, n_clients, path, ok); - free(path); - } - } - - closedir(directory); -} - -int main(int argc, char *argv[]) -{ - static const struct option long_options[] = { - /* Target options must come first. */ - {"all", no_argument, NULL, 'a'}, - {"target", required_argument, NULL, 't'}, - {"help", no_argument, NULL, 'h'}, - - /* Action options come afterward. */ - {"list", no_argument, NULL, 'l'}, - {"set", required_argument, NULL, 's'}, - {"reopen", no_argument, NULL, 'r'}, - {0, 0, 0, 0}, - }; - char *short_options; - - /* Determine targets. */ - bool ok = true; - int n_actions = 0; - struct vlog_client **clients = NULL; - size_t n_clients = 0; - - set_program_name(argv[0]); - time_init(); - - short_options = long_options_to_short_options(long_options); - for (;;) { - int option; - size_t i; - - option = getopt_long(argc, argv, short_options, long_options, NULL); - if (option == -1) { - break; - } - if (!strchr("ath", option) && n_clients == 0) { - ofp_fatal(0, "no targets specified (use --help for help)"); - } else { - ++n_actions; - } - switch (option) { - case 'a': - add_all_targets(&clients, &n_clients, &ok); - break; - - case 't': - add_target(&clients, &n_clients, optarg, &ok); - break; - - case 'l': - for (i = 0; i < n_clients; i++) { - struct vlog_client *client = clients[i]; - char *reply; - - printf("%s:\n", vlog_client_target(client)); - reply = transact(client, "list", &ok); - fputs(reply, stdout); - free(reply); - } - break; - - case 's': - for (i = 0; i < n_clients; i++) { - struct vlog_client *client = clients[i]; - char *request = xasprintf("set %s", optarg); - transact_ack(client, request, &ok); - free(request); - } - break; - - case 'r': - for (i = 0; i < n_clients; i++) { - struct vlog_client *client = clients[i]; - char *request = xstrdup("reopen"); - transact_ack(client, request, &ok); - free(request); - } - break; - - case 'h': - usage(argv[0], EXIT_SUCCESS); - break; - - case '?': - exit(EXIT_FAILURE); - - default: - NOT_REACHED(); - } - } - if (!n_actions) { - fprintf(stderr, - "warning: no actions specified (use --help for help)\n"); - } - exit(ok ? 0 : 1); -} diff --git a/openflow/utilities/wireshark_dissectors/Makefile b/openflow/utilities/wireshark_dissectors/Makefile deleted file mode 100644 index cf82d045..00000000 --- a/openflow/utilities/wireshark_dissectors/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# simple Makefile to build and install all of our Wireshark plugins - -# build a list of all sub-directories except the includes path -PLUGIN_DIRS = $(shell ls -l | grep "^d" | cut -d: -f2- | cut -d\ -f2 | fgrep -v 'wireshark-1.0.0-includes') -CLEAN_PLUGIN_DIRS = $(foreach dir,$(PLUGIN_DIRS),clean$(dir)) -INSTALL_PLUGIN_DIRS = $(foreach dir,$(PLUGIN_DIRS),install$(dir)) - -.PHONY: all $(PLUGIN_DIRS) clean $(CLEAN_PLUGIN_DIRS) install $(INSTALL_PLUGIN_DIRS) - -# build all the plugins -all: - @$(MAKE) --no-print-directory $(PLUGIN_DIRS) - -# cleanup all the byproducts (including the plugin itself) -clean: - @$(MAKE) --no-print-directory $(CLEAN_PLUGIN_DIRS) - -# install all plugins -install: - @$(MAKE) --no-print-directory $(INSTALL_PLUGIN_DIRS) - -# build the plugin in the specified directory using its default rule -$(PLUGIN_DIRS): - @$(MAKE) --no-print-directory -C $@ - -# cleans up the plugin in the specified directory using its 'clean' rule -$(CLEAN_PLUGIN_DIRS): - @$(MAKE) --no-print-directory -C `echo $@ | sed -e "s#^clean##"` clean - -# installs up the plugin in the specified directory using its 'install' rule -$(INSTALL_PLUGIN_DIRS): - @$(MAKE) --no-print-directory -C `echo $@ | sed -e "s#^install##"` install diff --git a/openflow/utilities/wireshark_dissectors/README b/openflow/utilities/wireshark_dissectors/README deleted file mode 100644 index 0aac13dd..00000000 --- a/openflow/utilities/wireshark_dissectors/README +++ /dev/null @@ -1,37 +0,0 @@ -README: OpenFlow Wireshark Plugin - - - ----------------------------------------- -I) Installation - -1) Install glib-devel; on Debian this can be done with 'sudo apt-get install libgtk2.0-dev' -2) Install wireshark v1.0.0 or greater -3) cd wireshark_dissectors/openflow -4) make -5) sudo make install -5a) Note that this prints out where the plugin was installed. - - ----------------------------------------- -II) Installation Verification - -1) Run wireshark -2) Open the "Help" --> "About" menu -3) Select the "Plugins" tab -4) Click the "Name" header to the plugins by name -5) Verify that "packet-openflow.so" appears in the list. -6) Verify that its version is listed as . - - ----------------------------------------- -III) Port Changes - -To have the dissector handle OpenFlow packets for any port other than the default, you must change the DISSECT_PORT variable in utilities/wireshark_dissectors/oepnflow/Makefile. - ----------------------------------------- -IV) Feedback and Bug Reporting - -Please post a message on the OpenFlow forums at openflowswitch.org or email -David Underhill at dgu@cs.stanford.edu if you have any feedback or discover any -bugs. diff --git a/openflow/utilities/wireshark_dissectors/openflow/.gitignore b/openflow/utilities/wireshark_dissectors/openflow/.gitignore deleted file mode 100644 index aa1ec1ea..00000000 --- a/openflow/utilities/wireshark_dissectors/openflow/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.tgz diff --git a/openflow/utilities/wireshark_dissectors/openflow/Makefile b/openflow/utilities/wireshark_dissectors/openflow/Makefile deleted file mode 100644 index 8c533ce9..00000000 --- a/openflow/utilities/wireshark_dissectors/openflow/Makefile +++ /dev/null @@ -1,79 +0,0 @@ -WIRESHARK_SRC_DIR = ../wireshark-1.0.0-includes - -SRCS = packet-openflow.c plugin.c -CC = gcc -OBJS = $(foreach src, $(SRCS), $(src:.c=.o)) - -PLUGIN_NAME = packet-openflow - -# local installation path -LOCAL_PLUGIN_DIR = /home/$(shell whoami)/.wireshark/plugins - -# determine global installation path (use latest plugin version path) -ifneq ($(wildcard /usr/local/lib/wireshark/plugins),) - GLOBAL_PLUGIN_DIR_PARTIAL=/usr/local/lib/wireshark/plugins -else ifneq ($(wildcard /usr/lib/wireshark/plugins),) - GLOBAL_PLUGIN_DIR_PARTIAL=/usr/lib/wireshark/plugins -endif - -# Work out if there are version-specific subdirectories -GLOBAL_PLUGIN_DIR_FILES := $(wildcard $(GLOBAL_PLUGIN_DIR_PARTIAL)/*) -GLOBAL_PLUGIN_DIR_SUBDIRS := $(foreach file,$(GLOBAL_PLUGIN_DIR_FILES),$(dir $(wildcard $(file)/.))) -GLOBAL_PLUGIN_DIR_SUBDIRS := $(subst $(GLOBAL_PLUGIN_DIR_PARTIAL)/,,$(GLOBAL_PLUGIN_DIR_SUBDIRS)) -GLOBAL_PLUGIN_DIR_SUBDIRS := $(subst /,,$(GLOBAL_PLUGIN_DIR_SUBDIRS)) - -# Assume that the "last" directory is the one we ant to use if it exists -GLOBAL_PLUGIN_VER := $(lastword $(sort $(GLOBAL_PLUGIN_DIR_SUBDIRS))) - -# Create the actual global plugin dir to use -ifneq ($(GLOBAL_PLUGIN_VER),) - GLOBAL_PLUGIN_DIR=$(GLOBAL_PLUGIN_DIR_PARTIAL)/$(GLOBAL_PLUGIN_VER) -else - GLOBAL_PLUGIN_DIR=$(GLOBAL_PLUGIN_DIR_PARTIAL) -endif - -# specify the port on which event capture packets will be destined -DISSECT_PORT = -DOPENFLOW_DST_TCP_PORT=6633 - -OSTYPE = $(shell uname) -ifeq ($(OSTYPE),Linux) -ENDIAN=-D_LITTLE_ENDIAN_ -endif -ifeq ($(OSTYPE),SunOS) -ENDIAN=-D_BIG_ENDIAN_ -endif - -INC_GLIB=$(shell pkg-config --cflags glib-2.0) -INC_OPENFLOW=../../../include - -INC_DIRS = -I. $(INC_GLIB) -I$(INC_OPENFLOW) -CFLAGS = $(INC_DIRS) -DHAVE_CONFIG_H -I$(WIRESHARK_SRC_DIR) -I/usr/local/include -I/usr/local/include -DINET6 -D_U_=__attribute__\(\(unused\)\) -Wall -Wpointer-arith -g -I/usr/local/include -DXTHREADS -D_REENTRANT -DXUSE_MTSAFE_API -pthread -I/usr/include/gtk-2.0 -I/usr/lib/gtk-2.0/include -I/usr/X11R6/include -I/usr/include/atk-1.0 -I/usr/include/pango-1.0 -I/usr/include/freetype2 -I/usr/include/freetype2/config -I/usr/local/include/glib-2.0 -I/usr/lib/glib-2.0/include -fPIC -DPIC $(ENDIAN) $(DISSECT_PORT) - -LDFLAGS = -Wl,--rpath -Wl,/usr/local/lib -Wl,--rpath -Wl,/usr/local/lib -L/usr/local/lib -L$(WIRESHARK_SRC_DIR)/epan -L. -lgmodule-2.0 -ldl -lglib-2.0 -pthread -Wl,--export-dynamic -Wl,-soname -Wl,$(PLUGIN_NAME).so - -.PHONY: clean install - -$(PLUGIN_NAME).so : $(OBJS) $(SRCS) - $(CC) -shared $(OBJS) $(LDFLAGS) -o $@ - -install: $(PLUGIN_NAME).so - @if [ `id -u` -eq 0 ]; then \ - if [ -d "$(GLOBAL_PLUGIN_DIR)" ]; then \ - target="$(GLOBAL_PLUGIN_DIR)/$<"; \ - res="*** Installed plugin for ALL users ($$target)"; \ - else \ - echo "*** Error: global plugin directory $(GLOBAL_PLUGIN_DIR) does not exist"; \ - exit 1; \ - fi; \ - else \ - mkdir -p "$(LOCAL_PLUGIN_DIR)/"; \ - target="$(LOCAL_PLUGIN_DIR)/$<"; \ - res="*** Installed plugin for user "`id | cut -d\( -f2 | cut -d\) -f1`" ($$target)"; \ - fi; \ - install --mode=644 $< "$$target" && echo "" && echo "" && echo "$$res" && echo "" && echo "" - -plugin.c: moduleinfo.h Makefile.am Makefile.common - $(MAKE) -f Makefile.am - -clean: - rm -f $(PLUGIN) $(OBJS) $(PLUGIN_NAME).so diff --git a/openflow/utilities/wireshark_dissectors/openflow/Makefile.am b/openflow/utilities/wireshark_dissectors/openflow/Makefile.am deleted file mode 100644 index be972bd8..00000000 --- a/openflow/utilities/wireshark_dissectors/openflow/Makefile.am +++ /dev/null @@ -1,110 +0,0 @@ -# Makefile.am -# Automake file for H.223 plugin -# -# $Id: Makefile.am 21961 2007-05-27 18:35:55Z guy $ -# -# Wireshark - Network traffic analyzer -# By Gerald Combs -# Copyright 1998 Gerald Combs - -srcdir = . -top_srcdir = ../wireshark-1.0.0-includes -includedir = ../wireshark-1.0.0-includes -INCLUDES = -I$(top_srcdir) -I$(includedir) - -include Makefile.common - -#if HAVE_WARNINGS_AS_ERRORS -#AM_CFLAGS = -Werror -#endif - -plugindir = ~/.wireshark/plugins - -plugin_LTLIBRARIES = hsapi.la -hsapi_la_SOURCES = \ - plugin.c \ - moduleinfo.h \ - $(DISSECTOR_SRC) \ - $(DISSECTOR_SUPPORT_SRC) \ - $(DISSECTOR_INCLUDES) -openflow_la_LDFLAGS = -module -avoid-version -openflow_la_LIBADD = @PLUGIN_LIBS@ - -# Libs must be cleared, or else libtool won't create a shared module. -# If your module needs to be linked against any particular libraries, -# add them here. -LIBS = - -# -# Build plugin.c, which contains the plugin version[] string, a -# function plugin_register() that calls the register routines for all -# protocols, and a function plugin_reg_handoff() that calls the handoff -# registration routines for all protocols. -# -# We do this by scanning sources. If that turns out to be too slow, -# maybe we could just require every .o file to have an register routine -# of a given name (packet-aarp.o -> proto_register_aarp, etc.). -# -# Formatting conventions: The name of the proto_register_* routines an -# proto_reg_handoff_* routines must start in column zero, or must be -# preceded only by "void " starting in column zero, and must not be -# inside #if. -# -# DISSECTOR_SRC is assumed to have all the files that need to be scanned. -# -# For some unknown reason, having a big "for" loop in the Makefile -# to scan all the files doesn't work with some "make"s; they seem to -# pass only the first few names in the list to the shell, for some -# reason. -# -# Therefore, we have a script to generate the plugin.c file. -# The shell script runs slowly, as multiple greps and seds are run -# for each input file; this is especially slow on Windows. Therefore, -# if Python is present (as indicated by PYTHON being defined), we run -# a faster Python script to do that work instead. -# -# The first argument is the directory in which the source files live. -# The second argument is "plugin", to indicate that we should build -# a plugin.c file for a plugin. -# All subsequent arguments are the files to scan. -# -plugin.c: $(DISSECTOR_SRC) $(top_srcdir)/tools/make-dissector-reg \ - $(top_srcdir)/tools/make-dissector-reg.py - @if test -n $(PYTHON); then \ - echo Making plugin.c with python ; \ - $(PYTHON) $(top_srcdir)/tools/make-dissector-reg.py $(srcdir) \ - plugin $(DISSECTOR_SRC) ; \ - else \ - echo Making plugin.c with shell script ; \ - $(top_srcdir)/tools/make-dissector-reg $(srcdir) \ - $(plugin_src) plugin $(DISSECTOR_SRC) ; \ - fi - -# -# Currently plugin.c can be included in the distribution because -# we always build all protocol dissectors. We used to have to check -# whether or not to build the snmp dissector. If we again need to -# variably build something, making plugin.c non-portable, uncomment -# the dist-hook line below. -# -# Oh, yuk. We don't want to include "plugin.c" in the distribution, as -# its contents depend on the configuration, and therefore we want it -# to be built when the first "make" is done; however, Automake insists -# on putting *all* source into the distribution. -# -# We work around this by having a "dist-hook" rule that deletes -# "plugin.c", so that "dist" won't pick it up. -# -#dist-hook: -# @rm -f $(distdir)/plugin.c - -CLEANFILES = \ - openflow \ - *~ - -MAINTAINERCLEANFILES = \ - Makefile.in \ - plugin.c - -EXTRA_DIST = \ - Makefile.common diff --git a/openflow/utilities/wireshark_dissectors/openflow/Makefile.common b/openflow/utilities/wireshark_dissectors/openflow/Makefile.common deleted file mode 100644 index 26c43d26..00000000 --- a/openflow/utilities/wireshark_dissectors/openflow/Makefile.common +++ /dev/null @@ -1,13 +0,0 @@ -# the name of the plugin -PLUGIN_NAME = openflow - -# the dissector sources (without any helpers) -DISSECTOR_SRC = packet-openflow.c - -# corresponding headers -DISSECTOR_INCLUDES = - -# Dissector helpers. They're included in the source files in this -# directory, but they're not dissectors themselves, i.e. they're not -# used to generate "register.c"). -DISSECTOR_SUPPORT_SRC = diff --git a/openflow/utilities/wireshark_dissectors/openflow/build_distribution_tarball.sh b/openflow/utilities/wireshark_dissectors/openflow/build_distribution_tarball.sh deleted file mode 100755 index d6b1ae05..00000000 --- a/openflow/utilities/wireshark_dissectors/openflow/build_distribution_tarball.sh +++ /dev/null @@ -1,63 +0,0 @@ -#!/bin/bash -set -o errexit -set -o nounset - -# if user specifies a folder, cd to it -if [ $# -ne 0 ]; then - cd $1 -fi - -# sanity check: make sure script is running from within the plugin build directory -origdir=`pwd` -topdir=wireshark_dissectors -if [ "$topdir" != `dirname $origdir | sed -e "s#.*/##"` ]; then - echo "Error: script must be run from within the plugin's subdirectory with $topdir" - exit 1 -fi - -# sanity check: make sure build works -rm -f *.so -make > /dev/null 2> /dev/null -plugin=`grep 'PLUGIN_NAME =' Makefile | sed -e "s#PLUGIN_NAME =##" -e "s# ##g"`.so -if [ ! -f $plugin ]; then - echo "Error: make failed to build $plugin" - exit 1 -fi - -# make a temporary folder for the build file -tmpdir=/tmp/.$$ -builddir="$tmpdir/$topdir/openflow" -mkdir $tmpdir - -# copy the wireshark plugin directory to the temp folder -cp -r ../ "$tmpdir/$topdir" - -# add the openflow header to the build folder which is in the include search path -cp ../../../include/openflow/openflow.h "$builddir/" - -# cleanup the contents of the build folder -cd "$builddir" -make clean -rm -f *.tgz $0 - -# get the version of the plugin -version=`grep '#define VERSION' moduleinfo.h | cut -d\" -f2` - -# replace tag in README with date information' -date=`date` -cat ../README | sed -e "s##Plugin Version: $version#g" > ../tmp -cat ../tmp | sed -e "s##Distribution Creation Date: $date#g" > ../README - -# make a tarball from the build folder -tarball="openflow-wireshark-dissector-v$version.tar.gz" -cd ../../ -tar -zcf "$tarball" "$topdir" - -# put the tarball back in the original directory -mv "$tarball" "$origdir/" - -# cleanup the temporary folder -rm -rf "$tmpdir" - -# tell the user what we created -echo "tarballed release is now ready: $tarball" diff --git a/openflow/utilities/wireshark_dissectors/openflow/moduleinfo.h b/openflow/utilities/wireshark_dissectors/openflow/moduleinfo.h deleted file mode 100644 index b7bd7f5e..00000000 --- a/openflow/utilities/wireshark_dissectors/openflow/moduleinfo.h +++ /dev/null @@ -1,15 +0,0 @@ -/* Included *after* config.h, in order to re-define these macros */ - -#ifdef PACKAGE -#undef PACKAGE -#endif - -/* Name of package */ -#define PACKAGE "openflow" - -#ifdef VERSION -#undef VERSION -#endif - -/* Version number of package */ -#define VERSION "1.0.0" /* OpenFlowMajor.OpenFlowMinor.PluginRevForThisMajorMinorRev */ diff --git a/openflow/utilities/wireshark_dissectors/openflow/packet-openflow.c b/openflow/utilities/wireshark_dissectors/openflow/packet-openflow.c deleted file mode 100644 index aea00f88..00000000 --- a/openflow/utilities/wireshark_dissectors/openflow/packet-openflow.c +++ /dev/null @@ -1,3426 +0,0 @@ -/** - * Filename: packet-openflow.c - * Author: David Underhill - * Changelog: - * dgu 2008-Aug-26 created - * brandonh 2008-Oct-5 updated to 0x95 - * brandonh 2008-Nov-25 updated to 0x96 + bugfixes - * tyabe 2009-May-20 added vlan_pcp_match - * - * Defines a Wireshark 1.0.0+ dissector for the OpenFlow protocol version 0x98. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** the version of openflow this dissector was written for */ -#define DISSECTOR_OPENFLOW_MIN_VERSION OFP_VERSION -#define DISSECTOR_OPENFLOW_MAX_VERSION OFP_VERSION -#define DISSECTOR_OPENFLOW_VERSION_DRAFT_THRESHOLD OFP_VERSION - -/** if 0, padding bytes will not be shown in the dissector */ -#define SHOW_PADDING 0 - -#define PROTO_TAG_OPENFLOW "OFP" - -/* Wireshark ID of the OPENFLOW protocol */ -static int proto_openflow = -1; -static dissector_handle_t openflow_handle; -static void dissect_openflow(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); - -/* traffic will arrive with TCP port OPENFLOW_DST_TCP_PORT */ -#define TCP_PORT_FILTER "tcp.port" -static int global_openflow_proto = OPENFLOW_DST_TCP_PORT; - -/* try to find the ethernet dissector to dissect encapsulated Ethernet data */ -static dissector_handle_t data_ethernet; - -/* AM=Async message, CSM=Control/Switch Message, SM=Symmetric Message */ -/** names to bind to various values in the type field */ -static const value_string names_ofp_type[] = { - /* Immutable messages. */ - { OFPT_HELLO, "Hello (SM)" }, - { OFPT_ERROR, "Error (SM)" }, - { OFPT_ECHO_REQUEST, "Echo Request (SM)" }, - { OFPT_ECHO_REPLY, "Echo Reply (SM)" }, - { OFPT_VENDOR, "Vendor (SM)" }, - - /* Switch configuration messages. */ - { OFPT_FEATURES_REQUEST, "Features Request (CSM)" }, - { OFPT_FEATURES_REPLY, "Features Reply (CSM)" }, - { OFPT_GET_CONFIG_REQUEST, "Get Config Request (CSM)" }, - { OFPT_GET_CONFIG_REPLY, "Get Config Reply (CSM)" }, - { OFPT_SET_CONFIG, "Set Config (CSM)" }, - - /* Asynchronous messages. */ - { OFPT_PACKET_IN, "Packet In (AM)" }, - { OFPT_FLOW_REMOVED, "Flow Removed (AM)" }, - { OFPT_PORT_STATUS, "Port Status (AM)" }, - - /* Controller command messages. */ - { OFPT_PACKET_OUT, "Packet Out (CSM)" }, - { OFPT_FLOW_MOD, "Flow Mod (CSM)" }, - { OFPT_PORT_MOD, "Port Mod (CSM)" }, - - /* Statistics messages. */ - { OFPT_STATS_REQUEST, "Stats Request (CSM)" }, - { OFPT_STATS_REPLY, "Stats Reply (CSM)" }, - - /* Barrier messages. */ - { OFPT_BARRIER_REQUEST, "Barrier Request (CSM)" }, - { OFPT_BARRIER_REPLY, "Barrier Reply (CSM)" }, - - { OFPT_QUEUE_GET_CONFIG_REQUEST, "Get Queue Config Request (CSM)" }, - { OFPT_QUEUE_GET_CONFIG_REPLY, "Get Queue Config Reply (CSM)" }, - - { 0, NULL } -}; -#define OFP_TYPE_MAX_VALUE OFPT_QUEUE_GET_CONFIG_REPLY - -/** names from ofp_action_type */ -static const value_string names_ofp_action_type[] = { - { OFPAT_OUTPUT, "Output to switch port" }, - { OFPAT_SET_VLAN_VID, "Set the 802.1q VLAN id." }, - { OFPAT_SET_VLAN_PCP, "Set the 802.1q priority." }, - { OFPAT_STRIP_VLAN, "Strip the 802.1q header." }, - { OFPAT_SET_DL_SRC, "Ethernet source address" }, - { OFPAT_SET_DL_DST, "Ethernet destination address" }, - { OFPAT_SET_NW_SRC, "IP source address" }, - { OFPAT_SET_NW_DST, "IP destination address" }, - { OFPAT_SET_NW_TOS, "Set IP TOS field" }, - { OFPAT_SET_TP_SRC, "TCP/UDP source port" }, - { OFPAT_SET_TP_DST, "TCP/UDP destination port"}, - { OFPAT_ENQUEUE, "Enqueue to port queue" }, - { OFPAT_VENDOR, "Vendor-defined action"}, - { 0, NULL } -}; -#define NUM_ACTIONS_FLAGS 12 -#define NUM_PORT_CONFIG_FLAGS 7 -#define NUM_PORT_STATE_FLAGS 1 -#define NUM_PORT_FEATURES_FLAGS 12 -#define NUM_WILDCARDS 12 -#define NUM_CAPABILITIES_FLAGS 8 -#define NUM_FLOW_MOD_FLAGS 3 -#define NUM_SF_REPLY_FLAGS 1 - -/** yes/no for bitfields field */ -static const value_string names_choice[] = { - { 0, "No" }, - { 1, "Yes" }, - { 0, NULL } -}; - -/** wildcard or not for bitfields field */ -static const value_string wildcard_choice[] = { - { 0, "Exact" }, - { 1, "Wildcard" }, - { 0, NULL } -}; - -/** wildcard or not for bitfields field */ -static const value_string ts_wildcard_choice[] = { - { 0, "Exact only" }, - { 1, "Wildcard allowed" }, - { 0, NULL } -}; - -/** names from ofp_flow_mod_command */ -static const value_string names_flow_mod_command[] = { - { OFPFC_ADD, "New flow" }, - { OFPFC_MODIFY, "Modify all matching flows" }, - { OFPFC_MODIFY_STRICT, "Modify entry strictly matching wildcards" }, - { OFPFC_DELETE, "Delete all matching flows" }, - { OFPFC_DELETE_STRICT, "Delete entry strictly matching wildcards and priority" }, - { 0, NULL } -}; - -/** names of stats_types */ -static const value_string names_stats_types[] = { - { OFPST_DESC, "Description of this OpenFlow switch" }, - { OFPST_FLOW, "Individual flow statistics" }, - { OFPST_AGGREGATE, "Aggregate flow statistics" }, - { OFPST_TABLE, "Flow table statistics" }, - { OFPST_PORT, "Physical port statistics" }, - { OFPST_QUEUE, "Queue statistics" }, - { OFPST_VENDOR, "Vendor extension" }, - { 0, NULL } -}; - -/** names from ofp_flow_mod_command */ -static const value_string names_ofp_port_reason[] = { - { OFPPR_ADD, "The port was added" }, - { OFPPR_DELETE, "The port was removed" }, - { OFPPR_MODIFY, "Some attribute of the port has changed" }, - { 0, NULL } -}; - -/** names from ofp_packet_in_reason */ -static const value_string names_ofp_packet_in_reason[] = { - { OFPR_NO_MATCH, "No matching flow" }, - { OFPR_ACTION, "Action explicitly output to controller" }, - { 0, NULL } -}; - -/** names from ofp_flow_removed_reason */ -static const value_string names_ofp_flow_removed_reason[] = { - { OFPRR_IDLE_TIMEOUT, "Flow idle time exceeded idle_timeout" }, - { OFPRR_HARD_TIMEOUT, "Time exceeded hard_timeout" }, - { OFPRR_DELETE, "Evicted by a DELETE flow mod." }, - { 0, NULL } -}; - -/** names from ofp_flow_removed_reason */ -static const value_string names_ip_frag[] = { - { OFPC_FRAG_NORMAL, "No special handling for fragments." }, - { OFPC_FRAG_DROP, "Drop fragments." }, - { OFPC_FRAG_REASM, "Reassemble (only if OFPC_IP_REASM set)" }, - { 0, NULL } -}; - -/** names from ofp_error_type */ -static const value_string names_ofp_error_type_reason[] = { - { OFPET_HELLO_FAILED, "Hello protocol failed" }, - { OFPET_BAD_REQUEST, "Request was not understood" }, - { OFPET_BAD_ACTION, "Error in action description" }, - { OFPET_FLOW_MOD_FAILED, "Problem modifying flow entry" }, - { OFPET_PORT_MOD_FAILED, "Port mod request failed" }, - { OFPET_QUEUE_OP_FAILED, "Problem during queue operation" }, - { 0, NULL } -}; - -static const value_string names_ofp_packet_queue_property_type[] = { - { OFPQT_NONE, "No-op Property" }, - { OFPQT_MIN_RATE, "Min Rate Queue" }, - { 0, NULL } -}; - - -/** Address masks */ -static const value_string addr_mask[] = { - { 0, "/32" }, - { 1, "/31" }, - { 2, "/30" }, - { 3, "/29" }, - { 4, "/28" }, - { 5, "/27" }, - { 6, "/26" }, - { 7, "/25" }, - { 8, "/24" }, - { 9, "/23" }, - { 10, "/22" }, - { 11, "/21" }, - { 12, "/20" }, - { 13, "/19" }, - { 14, "/18" }, - { 15, "/17" }, - { 16, "/16" }, - { 17, "/15" }, - { 18, "/14" }, - { 19, "/13" }, - { 20, "/12" }, - { 21, "/11" }, - { 22, "/10" }, - { 23, "/9" }, - { 24, "/8" }, - { 25, "/7" }, - { 26, "/6" }, - { 27, "/5" }, - { 28, "/4" }, - { 29, "/3" }, - { 30, "/2" }, - { 31, "/1" }, - { 32, "/0" }, - { 63, "/0" }, - { 0, NULL } -}; - -/** Address masks */ -static const value_string ts_addr_mask[] = { - { 0, "Exact only" }, - { 63, "Wildcard allowed" }, - { 0, NULL } -}; - -/** Switch config frag values */ -static const value_string sc_frag_choices[] = { - { 0, "No special fragment handling" }, - { 1, "Drop fragments" }, - { 2, "Reassemble (only if OFPC_IP_REASM set)" }, - { 0, NULL } -}; - - -/* Error strings for the various error types */ -static const gchar *hello_failed_err_str[] = {"No compatible version", - "Permissions error"}; - -#define N_HELLOFAILED (sizeof hello_failed_err_str / sizeof hello_failed_err_str[0]) - -static const gchar *bad_request_err_str[] = {"ofp_header.version not supported", - "ofp_header.type not supported", - "ofp_stats_request.type not supported", - "Vendor not supported (in ofp_vendor or ofp_stats_request or ofp_stats_reply)", - "Vendor subtype not supported", - "Permissions error", - "Wrong request length for type", - "Specified buffer has already been used", - "Specified buffer does not exist"}; - -#define N_BADREQUEST (sizeof bad_request_err_str / sizeof bad_request_err_str[0]) - -static const gchar *bad_action_err_str[] = {"Unknown action type", - "Length problem in actions", - "Unknown vendor id specified", - "Unknown action type for vendor id", - "Problem validating output action", - "Bad action argument", - "Permissions error", - "Can't handle this many actions", - "Problem validating output queue"}; - -#define N_BADACTION (sizeof bad_action_err_str / sizeof bad_action_err_str[0]) - -static const gchar *flow_mod_failed_err_str[] = {"Flow not added because of full tables", - "Flow not added because of conflicting entry in tables", - "Permissions error", - "Flow not added because of non-zero idle/hard timeout", - "Unknown command", - "Unsupported action list - cannot process in the order specified"}; - -#define N_FLOWMODFAILED (sizeof flow_mod_failed_err_str / sizeof flow_mod_failed_err_str[0]) - -static const gchar *port_mod_failed_err_str[] = {"Specified port does not exist", - "Specified hardware address is wrong"}; - -#define N_PORTMODFAILED (sizeof port_mod_failed_err_str / sizeof port_mod_failed_err_str[0]) - -static const gchar *queue_op_failed_err_str[] = {"Parent port does not exist", - "queue does not exist", - "Permissions error"}; - -#define N_QUEUEOPFAILED (sizeof queue_op_failed_err_str / sizeof queue_op_failed_err_str[0]) - -/* ICMP definitions from wireshark source: epan/dissectors/packet-ip.c */ -/* ICMP definitions */ - -#define ICMP_ECHOREPLY 0 -#define ICMP_UNREACH 3 -#define ICMP_SOURCEQUENCH 4 -#define ICMP_REDIRECT 5 -#define ICMP_ECHO 8 -#define ICMP_RTRADVERT 9 -#define ICMP_RTRSOLICIT 10 -#define ICMP_TIMXCEED 11 -#define ICMP_PARAMPROB 12 -#define ICMP_TSTAMP 13 -#define ICMP_TSTAMPREPLY 14 -#define ICMP_IREQ 15 -#define ICMP_IREQREPLY 16 -#define ICMP_MASKREQ 17 -#define ICMP_MASKREPLY 18 - -/* ICMP UNREACHABLE */ - -#define ICMP_NET_UNREACH 0 /* Network Unreachable */ -#define ICMP_HOST_UNREACH 1 /* Host Unreachable */ -#define ICMP_PROT_UNREACH 2 /* Protocol Unreachable */ -#define ICMP_PORT_UNREACH 3 /* Port Unreachable */ -#define ICMP_FRAG_NEEDED 4 /* Fragmentation Needed/DF set */ -#define ICMP_SR_FAILED 5 /* Source Route failed */ -#define ICMP_NET_UNKNOWN 6 -#define ICMP_HOST_UNKNOWN 7 -#define ICMP_HOST_ISOLATED 8 -#define ICMP_NET_ANO 9 -#define ICMP_HOST_ANO 10 -#define ICMP_NET_UNR_TOS 11 -#define ICMP_HOST_UNR_TOS 12 -#define ICMP_PKT_FILTERED 13 /* Packet filtered */ -#define ICMP_PREC_VIOLATION 14 /* Precedence violation */ -#define ICMP_PREC_CUTOFF 15 /* Precedence cut off */ - -static const gchar *unreach_str[] = {"Network unreachable", - "Host unreachable", - "Protocol unreachable", - "Port unreachable", - "Fragmentation needed", - "Source route failed", - "Destination network unknown", - "Destination host unknown", - "Source host isolated", - "Network administratively prohibited", - "Host administratively prohibited", - "Network unreachable for TOS", - "Host unreachable for TOS", - "Communication administratively filtered", - "Host precedence violation", - "Precedence cutoff in effect"}; - -#define N_UNREACH (sizeof unreach_str / sizeof unreach_str[0]) - -static const gchar *redir_str[] = {"Redirect for network", - "Redirect for host", - "Redirect for TOS and network", - "Redirect for TOS and host"}; - -#define N_REDIRECT (sizeof redir_str / sizeof redir_str[0]) - -static const gchar *ttl_str[] = {"Time to live exceeded in transit", - "Fragment reassembly time exceeded"}; - -#define N_TIMXCEED (sizeof ttl_str / sizeof ttl_str[0]) - -static const gchar *par_str[] = {"IP header bad", "Required option missing"}; - -#define N_PARAMPROB (sizeof par_str / sizeof par_str[0]) - - -/* ARP definitions from wireshark source: epan/dissectors/packet-arp.c */ -/* ARP / RARP structs and definitions */ -#ifndef ARPOP_REQUEST -#define ARPOP_REQUEST 1 /* ARP request. */ -#endif -#ifndef ARPOP_REPLY -#define ARPOP_REPLY 2 /* ARP reply. */ -#endif -/* Some OSes have different names, or don't define these at all */ -#ifndef ARPOP_RREQUEST -#define ARPOP_RREQUEST 3 /* RARP request. */ -#endif -#ifndef ARPOP_RREPLY -#define ARPOP_RREPLY 4 /* RARP reply. */ -#endif -#ifndef ARPOP_IREQUEST -#define ARPOP_IREQUEST 8 /* Inverse ARP (RFC 1293) request. */ -#endif -#ifndef ARPOP_IREPLY -#define ARPOP_IREPLY 9 /* Inverse ARP reply. */ -#endif -#ifndef ATMARPOP_NAK -#define ATMARPOP_NAK 10 /* ATMARP NAK. */ -#endif - -static const value_string names_arp_opcode[] = { - {ARPOP_REQUEST, "request" }, - {ARPOP_REPLY, "reply" }, - {ARPOP_RREQUEST, "reverse request"}, - {ARPOP_RREPLY, "reverse reply" }, - {ARPOP_IREQUEST, "inverse request"}, - {ARPOP_IREPLY, "inverse reply" }, - {0, NULL } }; - -/* These variables are used to hold the IDs of our fields; they are - * set when we call proto_register_field_array() in proto_register_openflow() - */ -static gint ofp = -1; -static gint ofp_pad = -1; -static gint ofp_port = -1; - -/* OpenFlow Header */ -static gint ofp_header = -1; -static gint ofp_header_version = -1; -static gint ofp_header_type = -1; -static gint ofp_header_length = -1; -static gint ofp_header_xid = -1; -static gint ofp_header_warn_ver = -1; -static gint ofp_header_warn_type = -1; - -/* Common Structures */ -static gint ofp_phy_port = -1; -static gint ofp_phy_port_port_no = -1; -static gint ofp_phy_port_hw_addr = -1; -static gint ofp_phy_port_name = -1; -static gint ofp_phy_port_config_hdr = -1; -static gint ofp_phy_port_config[NUM_PORT_CONFIG_FLAGS]; -static gint ofp_phy_port_state_hdr = -1; -// the following array is EVIL!!!!! do not use, or a curse upon your family. -static gint ofp_phy_port_state[NUM_PORT_STATE_FLAGS]; -// seriously, don't use this bit. -static gint ofp_phy_port_state_not_evil = -1; -static gint ofp_phy_port_state_stp_state = -1; -static gint ofp_phy_port_curr_hdr = -1; -static gint ofp_phy_port_curr[NUM_PORT_FEATURES_FLAGS]; -static gint ofp_phy_port_advertised_hdr = -1; -static gint ofp_phy_port_advertised[NUM_PORT_FEATURES_FLAGS]; -static gint ofp_phy_port_supported_hdr = -1; -static gint ofp_phy_port_supported[NUM_PORT_FEATURES_FLAGS]; -static gint ofp_phy_port_peer_hdr = -1; -static gint ofp_phy_port_peer[NUM_PORT_FEATURES_FLAGS]; - -static gint ofp_match = -1; -static gint ofp_match_wildcards_hdr = -1; -static gint ofp_match_wildcards[NUM_WILDCARDS]; -static gint ofp_match_in_port = -1; -static gint ofp_match_dl_src = -1; -static gint ofp_match_dl_dst = -1; -static gint ofp_match_dl_vlan = -1; -static gint ofp_match_dl_vlan_pcp = -1; -static gint ofp_match_dl_type = -1; -static gint ofp_match_nw_src = -1; -static gint ofp_match_nw_dst = -1; -static gint ofp_match_nw_tos = -1; -static gint ofp_match_nw_proto = -1; -static gint ofp_match_arp_opcode= -1; -static gint ofp_match_tp_src = -1; -static gint ofp_match_tp_dst = -1; -static gint ofp_match_icmp_type = -1; -static gint ofp_match_icmp_code = -1; -static gint ofp_match_nw_src_mask_bits = -1; -static gint ofp_match_nw_dst_mask_bits = -1; - -static gint ofp_action = -1; -static gint ofp_action_type = -1; -static gint ofp_action_len = -1; -static gint ofp_action_vlan_vid = -1; -static gint ofp_action_vlan_pcp = -1; -static gint ofp_action_dl_addr = -1; -static gint ofp_action_nw_addr = -1; -static gint ofp_action_nw_tos = -1; -static gint ofp_action_tp_port = -1; -static gint ofp_action_vendor = -1; -static gint ofp_action_unknown = -1; -static gint ofp_action_warn = -1; -static gint ofp_action_num = -1; - -/* type: ofp_action_output */ -static gint ofp_action_output = -1; -static gint ofp_action_output_port = -1; -static gint ofp_action_output_max_len = -1; - -/* type: ofp_action_enqueue */ -static gint ofp_action_enqueue = -1; -static gint ofp_action_enqueue_port_no = -1; -static gint ofp_action_enqueue_queue_id = -1; - -/* Controller/Switch Messages */ -static gint ofp_switch_features = -1; -static gint ofp_switch_features_datapath_id = -1; -static gint ofp_switch_features_n_buffers = -1; -static gint ofp_switch_features_n_tables = -1; -static gint ofp_switch_features_capabilities_hdr = -1; -static gint ofp_switch_features_capabilities[NUM_CAPABILITIES_FLAGS]; -static gint ofp_switch_features_actions_hdr = -1; -static gint ofp_switch_features_actions[NUM_ACTIONS_FLAGS]; -static gint ofp_switch_features_actions_warn = -1; -// are these two necessary? -static gint ofp_switch_features_ports_hdr = -1; -static gint ofp_switch_features_ports_num = -1; -static gint ofp_switch_features_ports_warn = -1; - -static gint ofp_switch_config = -1; -static gint ofp_switch_config_flags_hdr = -1; -static gint ofp_switch_config_flags_ip_frag = -1; -static gint ofp_switch_config_miss_send_len = -1; - -static gint ofp_queue_get_config_request = -1; -static gint ofp_queue_get_config_request_port_no = -1; - -// there is no limit at the no of queues/port. 1024 is safe for now. -static gint ofp_queue_get_config_reply = -1; -static gint ofp_queue_get_config_reply_port_no = -1; -static gint ofp_queue_get_config_reply_queues_hdr = -1; -static gint ofp_queue_get_config_reply_queues_num = -1; - -static gint ofp_packet_queue = -1; -static gint ofp_packet_queue_queue_id = -1; -static gint ofp_packet_queue_len = -1; -static gint ofp_packet_queue_warn = -1; - -static gint ofp_packet_queue_property = -1; -static gint ofp_packet_queue_property_len = -1; -static gint ofp_packet_queue_property_type = -1; -static gint ofp_packet_queue_property_rate = -1; -static gint ofp_packet_queue_properties_hdr = -1; -static gint ofp_packet_queue_properties_num = -1; -static gint ofp_packet_queue_property_unknown = -1; -static gint ofp_packet_queue_property_warn = -1; - -static gint ofp_flow_mod = -1; -/* field: ofp_match */ -static gint ofp_flow_mod_cookie = -1; -static gint ofp_flow_mod_command = -1; -static gint ofp_flow_mod_idle_timeout = -1; -static gint ofp_flow_mod_hard_timeout = -1; -static gint ofp_flow_mod_priority = -1; -static gint ofp_flow_mod_buffer_id = -1; -static gint ofp_flow_mod_out_port = -1; -static gint ofp_flow_mod_flags[NUM_FLOW_MOD_FLAGS]; - -static gint ofp_port_mod = -1; -static gint ofp_port_mod_port_no = -1; -static gint ofp_port_mod_hw_addr = -1; -static gint ofp_port_mod_config_hdr = -1; -static gint ofp_port_mod_config[NUM_PORT_CONFIG_FLAGS]; -static gint ofp_port_mod_mask_hdr = -1; -static gint ofp_port_mod_mask[NUM_PORT_CONFIG_FLAGS]; -static gint ofp_port_mod_advertise_hdr = -1; -static gint ofp_port_mod_advertise[NUM_PORT_FEATURES_FLAGS]; - -static gint ofp_stats_request = -1; -static gint ofp_stats_request_type = -1; -static gint ofp_stats_request_flags = -1; -static gint ofp_stats_request_body = -1; - -static gint ofp_stats_reply = -1; -static gint ofp_stats_reply_type = -1; -static gint ofp_stats_reply_flags = -1; -static gint ofp_stats_reply_flag[NUM_SF_REPLY_FLAGS]; -static gint ofp_stats_reply_body = -1; - -static gint ofp_desc_stats = -1; -static gint ofp_desc_stats_mfr_desc = -1; -static gint ofp_desc_stats_hw_desc = -1; -static gint ofp_desc_stats_sw_desc = -1; -static gint ofp_desc_stats_dp_desc = -1; -static gint ofp_desc_stats_serial_num = -1; - -static gint ofp_flow_stats_request = -1; -/* field: ofp_match */ -static gint ofp_flow_stats_request_table_id = -1; -static gint ofp_flow_stats_request_out_port = -1; - -static gint ofp_flow_stats_reply = -1; -/* length won't be put in the tree */ -static gint ofp_flow_stats_reply_table_id = -1; -/* field: ofp_match */ -static gint ofp_flow_stats_reply_duration_sec = -1; -static gint ofp_flow_stats_reply_duration_nsec = -1; -static gint ofp_flow_stats_reply_cookie = -1; -static gint ofp_flow_stats_reply_priority = -1; -static gint ofp_flow_stats_reply_idle_timeout = -1; -static gint ofp_flow_stats_reply_hard_timeout = -1; -static gint ofp_flow_stats_reply_packet_count = -1; -static gint ofp_flow_stats_reply_byte_count = -1; -/* field: ofp_actions */ - -static gint ofp_aggr_stats_request = -1; -/* field: ofp_match */ -static gint ofp_aggr_stats_request_table_id = -1; - -static gint ofp_aggr_stats_reply = -1; -static gint ofp_aggr_stats_reply_packet_count = -1; -static gint ofp_aggr_stats_reply_byte_count = -1; -static gint ofp_aggr_stats_reply_flow_count = -1; - -static gint ofp_table_stats = -1; -static gint ofp_table_stats_table_id = -1; -static gint ofp_table_stats_name = -1; -static gint ofp_table_stats_wildcards_hdr = -1; -static gint ofp_table_stats_wildcards[NUM_WILDCARDS]; -static gint ofp_table_stats_max_entries = -1; -static gint ofp_table_stats_active_count = -1; -static gint ofp_table_stats_lookup_count = -1; -static gint ofp_table_stats_matched_count = -1; - -static gint ofp_port_stats_request = -1; -static gint ofp_port_stats_request_port_no = -1; -static gint ofp_port_stats = -1; -static gint ofp_port_stats_port_no = -1; -static gint ofp_port_stats_rx_packets = -1; -static gint ofp_port_stats_tx_packets = -1; -static gint ofp_port_stats_rx_bytes = -1; -static gint ofp_port_stats_tx_bytes = -1; -static gint ofp_port_stats_rx_dropped = -1; -static gint ofp_port_stats_tx_dropped = -1; -static gint ofp_port_stats_rx_errors = -1; -static gint ofp_port_stats_tx_errors = -1; -static gint ofp_port_stats_rx_frame_err = -1; -static gint ofp_port_stats_rx_over_err = -1; -static gint ofp_port_stats_rx_crc_err = -1; -static gint ofp_port_stats_collisions = -1; - -static gint ofp_queue_stats_request = -1; - -static gint ofp_queue_stats = -1; -static gint ofp_queue_stats_port_no = -1; -static gint ofp_queue_stats_queue_id = -1; -static gint ofp_queue_stats_tx_bytes = -1; -static gint ofp_queue_stats_tx_packets = -1; -static gint ofp_queue_stats_tx_errors = -1; - -static gint ofp_vendor_stats = -1; -static gint ofp_vendor_stats_vendor = -1; -static gint ofp_vendor_stats_body = -1; - -static gint ofp_packet_out = -1; -static gint ofp_packet_out_buffer_id = -1; -static gint ofp_packet_out_in_port = -1; -static gint ofp_packet_out_actions_len = -1; -static gint ofp_packet_out_actions_hdr = -1; -static gint ofp_packet_out_data_hdr = -1; - -/* Asynchronous Messages */ -static gint ofp_packet_in = -1; -static gint ofp_packet_in_buffer_id = -1; -static gint ofp_packet_in_total_len = -1; -static gint ofp_packet_in_in_port = -1; -static gint ofp_packet_in_reason = -1; -static gint ofp_packet_in_data_hdr = -1; - -static gint ofp_flow_removed = -1; -/* field: ofp_match */ -static gint ofp_flow_removed_cookie = -1; -static gint ofp_flow_removed_priority = -1; -static gint ofp_flow_removed_reason = -1; -static gint ofp_flow_removed_duration_sec = -1; -static gint ofp_flow_removed_duration_nsec = -1; -static gint ofp_flow_removed_idle_timeout = -1; -static gint ofp_flow_removed_packet_count = -1; -static gint ofp_flow_removed_byte_count = -1; - -static gint ofp_port_status = -1; -static gint ofp_port_status_reason = -1; -/* field: ofp_phy_port desc */ - -static gint ofp_error_msg = -1; -static gint ofp_error_msg_type = -1; -static gint ofp_error_msg_code = -1; -static gint ofp_error_msg_data = -1; -static gint ofp_error_msg_data_str = -1; - -static gint ofp_echo = -1; -static gint ofp_vendor = -1; - -/* These are the ids of the subtrees that we may be creating */ -static gint ett_ofp = -1; - -/* Open Flow Header */ -static gint ett_ofp_header = -1; - -/* Common Structures */ -static gint ett_ofp_phy_port = -1; -static gint ett_ofp_phy_port_config_hdr = -1; -static gint ett_ofp_phy_port_state_hdr = -1; -static gint ett_ofp_phy_port_curr_hdr = -1; -static gint ett_ofp_phy_port_advertised_hdr = -1; -static gint ett_ofp_phy_port_supported_hdr = -1; -static gint ett_ofp_phy_port_peer_hdr = -1; -static gint ett_ofp_match = -1; -static gint ett_ofp_match_wildcards_hdr = -1; -static gint ett_ofp_action = -1; -static gint ett_ofp_action_output = -1; -static gint ett_ofp_action_enqueue = -1; -static gint ett_ofp_packet_queue_root = -1; -static gint ett_ofp_packet_queue = -1; -static gint ett_ofp_packet_queue_property = -1; -static gint ett_ofp_packet_queue_properties_hdr = -1; - -/* Controller/Switch Messages */ -static gint ett_ofp_switch_features = -1; -static gint ett_ofp_switch_features_capabilities_hdr = -1; -static gint ett_ofp_switch_features_actions_hdr = -1; -static gint ett_ofp_switch_features_ports_hdr = -1; -static gint ett_ofp_switch_config = -1; -static gint ett_ofp_switch_config_flags_hdr = -1; -static gint ett_ofp_flow_mod = -1; -static gint ett_ofp_flow_mod_flags_hdr = -1; -static gint ett_ofp_port_mod = -1; -static gint ett_ofp_port_mod_config_hdr = -1; -static gint ett_ofp_port_mod_mask_hdr = -1; -static gint ett_ofp_port_mod_advertise_hdr = -1; - -static gint ett_ofp_queue_get_config_request = -1; -static gint ett_ofp_queue_get_config_reply = -1; -static gint ett_ofp_queue_get_config_reply_queues_hdr = -1; - -static gint ett_ofp_stats_request = -1; -static gint ett_ofp_stats_reply = -1; -static gint ett_ofp_stats_reply_flags = -1; -static gint ett_ofp_desc_stats = -1; -static gint ett_ofp_flow_stats_request = -1; -static gint ett_ofp_flow_stats_reply = -1; -static gint ett_ofp_aggr_stats_request = -1; -static gint ett_ofp_aggr_stats_reply = -1; -static gint ett_ofp_table_stats = -1; -static gint ett_ofp_port_stats_request = -1; -static gint ett_ofp_queue_stats_request = -1; -static gint ett_ofp_port_stats = -1; -static gint ett_ofp_queue_stats = -1; -static gint ett_ofp_vendor_stats = -1; -static gint ett_ofp_packet_out = -1; -static gint ett_ofp_packet_out_actions_hdr = -1; -static gint ett_ofp_packet_out_data_hdr = -1; - -/* Asynchronous Messages */ -static gint ett_ofp_packet_in = -1; -static gint ett_ofp_packet_in_data_hdr = -1; -static gint ett_ofp_flow_removed = -1; -static gint ett_ofp_port_status = -1; -static gint ett_ofp_error_msg = -1; -static gint ett_ofp_error_msg_data = -1; - -void proto_reg_handoff_openflow() -{ - openflow_handle = create_dissector_handle(dissect_openflow, proto_openflow); - dissector_add(TCP_PORT_FILTER, global_openflow_proto, openflow_handle); -} - -#define NO_STRINGS NULL -#define NO_MASK 0x0 - -/** Returns newly allocated string with two spaces in front of str. */ -static inline char* indent( char* str ) { - char* ret = malloc( strlen(str) + 3 ); - ret[0] = ' '; - ret[1] = ' '; - memcpy( &ret[2], str, strlen(str) + 1 ); - return ret; -} - -void proto_register_openflow() -{ - data_ethernet = find_dissector("eth"); - - /* initialize uninitialized header fields */ - int i; - for( i=0; i= 0)) - return names_ofp_type[type].strptr; - else { - snprintf( str_unknown, 17, "Unknown Type %u", type ); - return str_unknown; - } -} - -/** - * Adds "hf" to "tree" starting at "offset" into "tvb" and using "length" - * bytes. offset is incremented by length. - */ -static void add_child( proto_item* tree, gint hf, tvbuff_t *tvb, guint32* offset, guint32 len ) { - proto_tree_add_item( tree, hf, tvb, *offset, len, FALSE ); - *offset += len; -} - -/** - * Adds "hf" to "tree" starting at "offset" into "tvb" and using "length" - * bytes. offset is incremented by length. The specified string is used as the - * field's display value. - */ -static void add_child_str(proto_item* tree, gint hf, tvbuff_t *tvb, guint32* offset, guint32 len, const char* str) { - proto_tree_add_string(tree, hf, tvb, *offset, len, str); - *offset += len; -} - -/** - * Adds "hf" to "tree" starting at "offset" into "tvb" and using "length" - * bytes. The specified string is used as the - * field's display value. - */ -static void add_child_str_const(proto_item* tree, gint hf, tvbuff_t *tvb, guint32 offset, guint32 len, const char* str) { - proto_tree_add_string(tree, hf, tvb, offset, len, str); -} - - -/** - * Adds "hf" to "tree" starting at "offset" into "tvb" and using "length" bytes. - */ -static void add_child_const( proto_item* tree, gint hf, tvbuff_t *tvb, guint32 offset, guint32 len ) { - proto_tree_add_item( tree, hf, tvb, offset, len, FALSE ); -} - -/** returns the length of a PDU which starts at the specified offset in tvb. */ -static guint get_openflow_message_len(packet_info *pinfo, tvbuff_t *tvb, int offset) { - return (guint)tvb_get_ntohs(tvb, offset+2); /* length is at offset 2 in the header */ -} - -static void dissect_pad(proto_tree* tree, guint32 *offset, guint pad_byte_count) { -#if SHOW_PADDING - guint i; - for( i=0; i 0) { - port_item = proto_tree_add_item(tree, ofp_phy_port, tvb, *offset, sizeof(struct ofp_phy_port), FALSE); - port_tree = proto_item_add_subtree(port_item, ett_ofp_phy_port); - - dissect_port( port_tree, ofp_phy_port_port_no, tvb, offset ); - add_child( port_tree, ofp_phy_port_hw_addr, tvb, offset, OFP_ETH_ALEN ); - add_child( port_tree, ofp_phy_port_name, tvb, offset, OFP_MAX_PORT_NAME_LEN ); - - /* config */ - config_item = proto_tree_add_item(port_tree, ofp_phy_port_config_hdr, tvb, *offset, 4, FALSE); - config_tree = proto_item_add_subtree(config_item, ett_ofp_phy_port_config_hdr); - for(i=0; iname, get_tcp_port(port), port); - - *offset += 2; -} - -/* Based on: dissect_icmp from wireshark: epan/dissectors/packet-ip.c */ -static void dissect_icmp_type_code_match(proto_tree* tree, tvbuff_t *tvb, guint32 *offset, gint show_type, gint show_code) -{ - guint16 icmp_type; - guint16 icmp_code; - const gchar *type_str, *code_str; - - type_str=""; - code_str=""; - - /* Get the ICMP type/code */ - icmp_type = tvb_get_ntohs(tvb, *offset); - icmp_code = tvb_get_ntohs(tvb, *offset + 2); - - /* Get string representations of the ICMP types/codes */ - switch (icmp_type) { - case ICMP_ECHOREPLY: - type_str="Echo (ping) reply"; - break; - case ICMP_UNREACH: - type_str="Destination unreachable"; - if (icmp_code < N_UNREACH) { - code_str = unreach_str[icmp_code]; - } else { - code_str = "Unknown - error?"; - } - break; - case ICMP_SOURCEQUENCH: - type_str="Source quench (flow control)"; - break; - case ICMP_REDIRECT: - type_str="Redirect"; - if (icmp_code < N_REDIRECT) { - code_str = redir_str[icmp_code]; - } else { - code_str = "Unknown - error?"; - } - break; - case ICMP_ECHO: - type_str="Echo (ping) request"; - break; - case ICMP_RTRADVERT: - switch (icmp_code) { - case 0: /* Mobile-Ip */ - case 16: /* Mobile-Ip */ - type_str="Mobile IP Advertisement"; - break; - default: - type_str="Router advertisement"; - break; - } /* switch icmp_code */ - break; - case ICMP_RTRSOLICIT: - type_str="Router solicitation"; - break; - case ICMP_TIMXCEED: - type_str="Time-to-live exceeded"; - if (icmp_code < N_TIMXCEED) { - code_str = ttl_str[icmp_code]; - } else { - code_str = "Unknown - error?"; - } - break; - case ICMP_PARAMPROB: - type_str="Parameter problem"; - if (icmp_code < N_PARAMPROB) { - code_str = par_str[icmp_code]; - } else { - code_str = "Unknown - error?"; - } - break; - case ICMP_TSTAMP: - type_str="Timestamp request"; - break; - case ICMP_TSTAMPREPLY: - type_str="Timestamp reply"; - break; - case ICMP_IREQ: - type_str="Information request"; - break; - case ICMP_IREQREPLY: - type_str="Information reply"; - break; - case ICMP_MASKREQ: - type_str="Address mask request"; - break; - case ICMP_MASKREPLY: - type_str="Address mask reply"; - break; - default: - type_str="Unknown ICMP (obsolete or malformed?)"; - break; - } - - if (show_type) - proto_tree_add_uint_format(tree, ofp_match_icmp_type, tvb, *offset, 2, - icmp_type, - "ICMP Type: %u (%s)", - icmp_type, type_str); - if (show_code) - proto_tree_add_uint_format(tree, ofp_match_icmp_code, tvb, *offset, 2, - icmp_code, - "ICMP Code: %u (%s)", - icmp_code, code_str); - - *offset += 4; -} - -static void dissect_match(proto_tree* tree, proto_item* item, tvbuff_t *tvb, packet_info *pinfo, guint32 *offset) -{ - proto_item *match_item = proto_tree_add_item(tree, ofp_match, tvb, *offset, sizeof(struct ofp_match), FALSE); - proto_tree *match_tree = proto_item_add_subtree(match_item, ett_ofp_match); - - /* save wildcards field for later */ - guint32 wildcards = tvb_get_ntohl( tvb, *offset ); - - dissect_wildcards(match_tree, match_item, tvb, pinfo, offset, ofp_match_wildcards); - - /* show only items whose corresponding wildcard bit is not set */ - if( ~wildcards & OFPFW_IN_PORT ) - dissect_port(match_tree, ofp_match_in_port, tvb, offset); - else - *offset += 2; - - if( ~wildcards & OFPFW_DL_SRC ) - add_child(match_tree, ofp_match_dl_src, tvb, offset, 6); - else - *offset += 6; - - if( ~wildcards & OFPFW_DL_DST ) - add_child(match_tree, ofp_match_dl_dst, tvb, offset, 6); - else - *offset += 6; - - if( ~wildcards & OFPFW_DL_VLAN ) - add_child(match_tree, ofp_match_dl_vlan, tvb, offset, 2); - else - *offset += 2; - - if( ~wildcards & OFPFW_DL_VLAN_PCP ) - add_child(match_tree, ofp_match_dl_vlan_pcp, tvb, offset, 1); - else - *offset += 1; - - dissect_pad(match_tree, offset, 1); - - /* Save DL type for later */ - guint16 dl_type = tvb_get_ntohs( tvb, *offset); - - if( ~wildcards & OFPFW_DL_TYPE ) - dissect_dl_type(match_tree, ofp_match_dl_type, tvb, offset); - else - *offset += 2; - - if( ~wildcards & OFPFW_NW_TOS ) - add_child(match_tree, ofp_match_nw_tos, tvb, offset, 1); - else - *offset += 1; - - /* Save NW proto for later */ - guint8 nw_proto = tvb_get_guint8( tvb, *offset); - - /* Custom handling for ARP packets vs non-ARP packets */ - if ( dl_type == ETHERTYPE_ARP ) - add_child(match_tree, ofp_match_arp_opcode, tvb, offset, 1); - else if( ~wildcards & OFPFW_NW_PROTO ) - dissect_nw_proto(match_tree, ofp_match_nw_proto, tvb, offset); - else - *offset += 1; - - dissect_pad(match_tree, offset, 2); - - if( ~wildcards & OFPFW_NW_SRC_MASK ) - add_child(match_tree, ofp_match_nw_src, tvb, offset, 4); - else - *offset += 4; - - if( ~wildcards & OFPFW_NW_DST_MASK ) - add_child(match_tree, ofp_match_nw_dst, tvb, offset, 4); - else - *offset += 4; - - /* Display either ICMP type/code or TCP/UDP ports */ - if( dl_type == ETHERTYPE_IP && nw_proto == IP_PROTO_ICMP) { - dissect_icmp_type_code_match(match_tree, tvb, offset, - ~wildcards & OFPFW_TP_SRC, - ~wildcards & OFPFW_TP_DST ); - } - else { - if( ~wildcards & OFPFW_TP_SRC ) - dissect_tp_port(match_tree, ofp_match_tp_src, tvb, offset); - else - *offset += 2; - - if( ~wildcards & OFPFW_TP_DST ) - dissect_tp_port(match_tree, ofp_match_tp_dst, tvb, offset); - else - *offset += 2; - } -} - -static void dissect_action_output(proto_tree* tree, tvbuff_t *tvb, guint32 *offset) -{ - /* add the output port */ - dissect_port( tree, ofp_action_output_port, tvb, offset ); - - /* determine the maximum number of bytes to send (0 => no limit) */ - guint16 max_len = tvb_get_ntohs( tvb, *offset ); - char str[11]; - snprintf( str, 11, "%u", max_len ); - add_child_str( tree, ofp_action_output_max_len, tvb, offset, 2, str ); -} - -static void dissect_action_enqueue(proto_tree* tree, tvbuff_t *tvb, guint32 *offset) -{ - /* add the output port */ - dissect_port( tree, ofp_action_enqueue_port_no, tvb, offset ); - dissect_pad(tree, offset, 6); - dissect_queue_id(tree, ofp_action_enqueue_queue_id, tvb, offset); -} - - -/** returns the number of bytes dissected (-1 if an unknown action type is - * encountered; and 8/16 for all other actions as of 0x96) */ -static gint dissect_action(proto_tree* tree, proto_item* item, tvbuff_t *tvb, packet_info *pinfo, guint32 *offset) -{ - guint32 offset_start = *offset; - guint16 type = tvb_get_ntohs( tvb, *offset ); - guint16 len = tvb_get_ntohs( tvb, *offset + 2); - - proto_item *action_item = proto_tree_add_item(tree, ofp_action, tvb, *offset, len, FALSE); - proto_tree *action_tree = proto_item_add_subtree(action_item, ett_ofp_action); - - if (!(len == 8 || len == 16)) { - add_child_str(action_tree, ofp_action_unknown, tvb, offset, len, "Invalid Action Length"); - return -1; - } - - add_child( action_tree, ofp_action_type, tvb, offset, 2 ); - add_child( action_tree, ofp_action_len, tvb, offset, 2 ); - - switch( type ) { - case OFPAT_OUTPUT: - dissect_action_output(action_tree, tvb, offset); - break; - - case OFPAT_SET_VLAN_VID: - add_child( action_tree, ofp_action_vlan_vid, tvb, offset, 2 ); - dissect_pad(action_tree, offset, 2); - break; - - case OFPAT_SET_VLAN_PCP: - add_child( action_tree, ofp_action_vlan_pcp, tvb, offset, 1 ); - dissect_pad(action_tree, offset, 3); - break; - - case OFPAT_STRIP_VLAN: - add_child( action_tree, ofp_action_unknown, tvb, offset, 0 ); - dissect_pad(action_tree, offset, 4); - break; - - case OFPAT_SET_DL_SRC: - case OFPAT_SET_DL_DST: - add_child(action_tree, ofp_action_dl_addr, tvb, offset, 6 ); - dissect_pad(action_tree, offset, 6); - break; - - case OFPAT_SET_NW_SRC: - case OFPAT_SET_NW_DST: - add_child( action_tree, ofp_action_nw_addr, tvb, offset, 4 ); - break; - - case OFPAT_SET_NW_TOS: - add_child( action_tree, ofp_action_nw_tos, tvb, offset, 1); - dissect_pad(action_tree, offset, 3); - break; - - case OFPAT_SET_TP_SRC: - case OFPAT_SET_TP_DST: - add_child( action_tree, ofp_action_tp_port, tvb, offset, 2 ); - dissect_pad(action_tree, offset, 2); - break; - - case OFPAT_ENQUEUE: - dissect_action_enqueue(action_tree, tvb, offset); - break; - - default: - add_child( action_tree, ofp_action_unknown, tvb, offset, 0 ); - return -1; - } - - /* return the number of bytes which were consumed */ - return *offset - offset_start; -} - -static void dissect_action_array(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint len, guint offset) -{ - guint total_len = len - offset; - - proto_item* action_item = proto_tree_add_item(tree, ofp_action_output, tvb, offset, total_len, FALSE); - proto_tree* action_tree = proto_item_add_subtree(action_item, ett_ofp_action_output); - - if( total_len == 0 ) - add_child_str(action_tree, ofp_action_warn, tvb, &offset, 0, "No actions were specified"); - else if( offset > len ) { - /* not enough bytes => wireshark will already have reported the error */ - } - else { - guint offset_action_start = offset; - guint num_actions = 0; - while( total_len > 0 ) { - num_actions += 1; - int ret = dissect_action(action_tree, action_item, tvb, pinfo, &offset); - if( ret < 0 ) - break; /* stop if we run into an action we couldn't dissect */ - else - total_len -= ret; - } - proto_tree_add_uint(action_tree, ofp_action_num, tvb, offset_action_start, 0, num_actions); - } -} - -static void dissect_property_min(proto_tree* tree, tvbuff_t *tvb, guint32 *offset) -{ - add_child(tree, ofp_packet_queue_property_rate, tvb, offset, 2); - dissect_pad(tree, offset, 6); -} - -static gint32 dissect_property(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, guint32 *offset) -{ - guint32 offset_start = *offset; - guint16 type = tvb_get_ntohs(tvb, *offset); - guint16 len = tvb_get_ntohs(tvb, *offset + 2); - - proto_item *property_item = proto_tree_add_item(tree, ofp_packet_queue_property, tvb, *offset, len, FALSE); - proto_tree *property_tree = proto_item_add_subtree(property_item, ett_ofp_packet_queue_property); - - add_child(property_tree, ofp_packet_queue_property_type, tvb, offset, 2); - add_child(property_tree, ofp_packet_queue_property_len, tvb, offset, 2); - dissect_pad(tree, offset, 4); - - switch( type ) { - case OFPQT_MIN_RATE: - dissect_property_min(property_tree, tvb, offset); - break; - default: - add_child(property_tree, ofp_packet_queue_property_unknown, tvb, offset, 0); - return -1; - } - - return *offset - offset_start; -} - -/* returns the number of bytes dissected ( -1 if unknown propery is encountered */ -static void dissect_property_array(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint len, guint32 *offset) -{ - guint total_len = len; - - proto_item *property_item = proto_tree_add_item(tree, ofp_packet_queue_properties_hdr, tvb, *offset, total_len, FALSE); - proto_tree *property_tree = proto_item_add_subtree(property_item, ett_ofp_packet_queue_properties_hdr); - - if( total_len == 0 ) { - add_child_str(property_tree, ofp_packet_queue_property_warn, tvb, offset, 0, "No properties were specified"); - } - else { - guint32 offset_property_start = *offset; - guint num_properties = 0; - while( total_len > 0 ) { - num_properties += 1; - int ret = dissect_property(property_tree, tvb, pinfo, offset); - if( ret < 0 ) { - break; /* stop if we run into a property we couldn't dissect */ - } - else - total_len -= ret; - } - proto_tree_add_uint(property_tree, ofp_packet_queue_properties_num, tvb, offset_property_start, 0, num_properties); - } -} - -/** returns the number of bytes dissected (-1 if an unknown property is - * encountered; */ -static gint dissect_queue(proto_tree* tree, tvbuff_t *tvb, packet_info *pinfo, guint32 *offset) -{ - guint32 offset_start = *offset; - guint16 len = tvb_get_ntohs( tvb, *offset + 4); - - proto_item *queue_item = proto_tree_add_item(tree, ofp_packet_queue, tvb, *offset, len, FALSE); - proto_tree *queue_tree = proto_item_add_subtree(queue_item, ett_ofp_packet_queue); - - // add_child( queue_tree, ofp_packet_queue_queue_id, tvb, offset, 4 ); - dissect_queue_id(queue_tree, ofp_packet_queue_queue_id, tvb, offset); - add_child( queue_tree, ofp_packet_queue_len, tvb, offset, 2 ); - dissect_pad( queue_tree, offset, 2); - - dissect_property_array(tvb, pinfo, queue_tree, len - (*offset - offset_start), offset); - return *offset - offset_start; - -} - -static void dissect_queue_array(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint len, guint32 *offset) -{ - guint total_len = len - *offset; - - proto_item *queue_item = proto_tree_add_item(tree, ofp_queue_get_config_reply_queues_hdr, tvb, *offset, total_len, FALSE); - proto_tree *queue_tree = proto_item_add_subtree(queue_item, ett_ofp_queue_get_config_reply_queues_hdr); - - if( total_len == 0 ) { - add_child_str(queue_tree, ofp_packet_queue_warn, tvb, offset, 0, "No queues were specified"); - } - else if( *offset > len ) { - /* not enough bytes => wireshark will already have reported the error */ - } - else { - guint offset_queue_start = *offset; - guint num_queues = 0; - while( total_len > 0 ) { - num_queues += 1; - int ret = dissect_queue(queue_tree, tvb, pinfo, offset); - if( ret < 0 ) - break; /* stop if we run into an action we couldn't dissect */ - else - total_len -= ret; - } - proto_tree_add_uint(queue_tree, ofp_queue_get_config_reply_queues_num, tvb, offset_queue_start, 0, num_queues); - } -} - - -static void dissect_capability_array(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint field_size) { - proto_item *sf_cap_item = proto_tree_add_item(tree, ofp_switch_features_capabilities_hdr, tvb, offset, field_size, FALSE); - proto_tree *sf_cap_tree = proto_item_add_subtree(sf_cap_item, ett_ofp_switch_features_capabilities_hdr); - gint i; - for(i=0; icinfo, COL_PROTOCOL)) - col_append_str( pinfo->cinfo, COL_PROTOCOL, "+" ); - - if(check_col(pinfo->cinfo,COL_INFO)) - col_append_str( pinfo->cinfo, COL_INFO, " => " ); - - /* set up fences so ethernet dissectors only appends to our column info */ - col_set_fence(pinfo->cinfo, COL_PROTOCOL); - col_set_fence(pinfo->cinfo, COL_INFO); - - /* continue the dissection with the ethernet dissector */ - call_dissector(data_ethernet, next_tvb, pinfo, data_tree); -} - -static void dissect_error_code(proto_tree* tree, gint hf, tvbuff_t *tvb, guint32 *offset, guint16 err_type) { - guint16 err_code; - guint8 valid; - const gchar *code_str; - - err_code = tvb_get_ntohs(tvb, *offset); - code_str = ""; - valid = TRUE; - - switch (err_type) { - case OFPET_HELLO_FAILED: - if (err_code < N_HELLOFAILED) { - code_str = hello_failed_err_str[err_code]; - } else { - code_str = "Unknown - error?"; - } - break; - case OFPET_BAD_REQUEST: - if (err_code < N_BADREQUEST) { - code_str = bad_request_err_str[err_code]; - } else { - code_str = "Unknown - error?"; - } - break; - case OFPET_BAD_ACTION: - if (err_code < N_BADACTION) { - code_str = bad_action_err_str[err_code]; - } else { - code_str = "Unknown - error?"; - } - break; - case OFPET_FLOW_MOD_FAILED: - if (err_code < N_FLOWMODFAILED) { - code_str = flow_mod_failed_err_str[err_code]; - } else { - code_str = "Unknown - error?"; - } - break; - case OFPET_PORT_MOD_FAILED: - if (err_code < N_PORTMODFAILED) { - code_str = port_mod_failed_err_str[err_code]; - } else { - code_str = "Unknown - error?"; - } - break; - case OFPET_QUEUE_OP_FAILED: - if (err_code < N_QUEUEOPFAILED) { - code_str = queue_op_failed_err_str[err_code]; - } else { - code_str = "Unknown - error?"; - } - break; - - default: - valid = FALSE; - break; - } - - if (valid) - proto_tree_add_uint_format(tree, hf, tvb, *offset, 2, - err_code, - "Code: %s (%u)", - code_str, err_code); - else - proto_tree_add_item(tree, hf, tvb, *offset, 2, FALSE); - - *offset += 2; -} - -static void dissect_flow_mod_flags(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) { - proto_item *fm_flags_item = proto_tree_add_item(tree, ofp_switch_config_flags_hdr, tvb, *offset, 2, FALSE); - proto_tree *fm_flags_tree = proto_item_add_subtree(fm_flags_item, ett_ofp_flow_mod_flags_hdr); - int i; - - for (i = 0; i < NUM_FLOW_MOD_FLAGS; i++) - add_child_const(fm_flags_tree, ofp_flow_mod_flags[i], tvb, *offset, 2); - - *offset += 2; -} - - -static void dissect_openflow_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) -{ -# define STR_LEN 1024 - char str[STR_LEN]; - - /* display our protocol text if the protocol column is visible */ - if (check_col(pinfo->cinfo, COL_PROTOCOL)) - col_set_str(pinfo->cinfo, COL_PROTOCOL, PROTO_TAG_OPENFLOW); - - /* Clear out stuff in the info column */ - if(check_col(pinfo->cinfo,COL_INFO)) - col_clear(pinfo->cinfo,COL_INFO); - - /* get some of the header fields' values for later use */ - guint8 ver = tvb_get_guint8( tvb, 0 ); - guint8 type = tvb_get_guint8( tvb, 1 ); - guint16 len = tvb_get_ntohs( tvb, 2 ); - - /* add a warning if the version is what the plugin was written to handle */ - guint8 ver_warning = 0; - if( ver < DISSECTOR_OPENFLOW_MIN_VERSION || ver > DISSECTOR_OPENFLOW_MAX_VERSION || ver >= DISSECTOR_OPENFLOW_VERSION_DRAFT_THRESHOLD ) { - if( ver>=DISSECTOR_OPENFLOW_VERSION_DRAFT_THRESHOLD && ver<=DISSECTOR_OPENFLOW_MAX_VERSION ) - snprintf( str, STR_LEN, "DRAFT Dissector written for this OpenFlow version v0x%0X", ver ); - else { - ver_warning = 1; - if( DISSECTOR_OPENFLOW_MIN_VERSION == DISSECTOR_OPENFLOW_MAX_VERSION ) - snprintf( str, STR_LEN, - "Dissector written for OpenFlow v0x%0X (differs from this packet's version v0x%0X)", - DISSECTOR_OPENFLOW_MIN_VERSION, ver ); - else - snprintf( str, STR_LEN, - "Dissector written for OpenFlow v0x%0X-v0x%0X (differs from this packet's version v0x%0X)", - DISSECTOR_OPENFLOW_MIN_VERSION, DISSECTOR_OPENFLOW_MAX_VERSION, ver ); - } - } - - /* clarify protocol name display with version, length, and type information */ - if (check_col(pinfo->cinfo, COL_INFO)) { - /* special handling so we can put buffer IDs in the description */ - char str_extra[32]; - str_extra[0] = '\0'; - if( type==OFPT_PACKET_IN || type==OFPT_PACKET_OUT ) { - guint32 bid = tvb_get_ntohl(tvb, sizeof(struct ofp_header)); - if( bid != 0xFFFFFFFF ) - snprintf(str_extra, 32, "(BufID=%u) ", bid); - } - - if( ver_warning ) - col_add_fstr( pinfo->cinfo, COL_INFO, "%s %s(%uB) Ver Warning!", ofp_type_to_string(type), str_extra, len ); - else - col_add_fstr( pinfo->cinfo, COL_INFO, "%s %s(%uB)", ofp_type_to_string(type), str_extra, len ); - } - - if (tree) { /* we are being asked for details */ - proto_item *item = NULL; - proto_item *sub_item = NULL; - proto_tree *ofp_tree = NULL; - proto_tree *header_tree = NULL; - guint32 offset = 0; - proto_item *type_item = NULL; - proto_tree *type_tree = NULL; - - /* consume the entire tvb for the openflow packet, and add it to the tree */ - item = proto_tree_add_item(tree, proto_openflow, tvb, 0, -1, FALSE); - ofp_tree = proto_item_add_subtree(item, ett_ofp); - - /* put the header in its own node as a child of the openflow node */ - sub_item = proto_tree_add_item( ofp_tree, ofp_header, tvb, offset, 8, FALSE ); - header_tree = proto_item_add_subtree(sub_item, ett_ofp_header); - - if( ver_warning ) - add_child_str( header_tree, ofp_header_warn_ver, tvb, &offset, 0, str ); - - /* add the headers field as children of the header node */ - add_child( header_tree, ofp_header_version, tvb, &offset, 1 ); - add_child( header_tree, ofp_header_type, tvb, &offset, 1 ); - add_child( header_tree, ofp_header_length, tvb, &offset, 2 ); - add_child( header_tree, ofp_header_xid, tvb, &offset, 4 ); - - switch( type ) { - - case OFPT_HELLO: { - /* nothing else in this packet type */ - break; - } - - case OFPT_BARRIER_REQUEST: - case OFPT_BARRIER_REPLY: - /* nothing else in this packet type */ - break; - - case OFPT_ERROR: { - type_item = proto_tree_add_item(ofp_tree, ofp_error_msg, tvb, offset, -1, FALSE); - type_tree = proto_item_add_subtree(type_item, ett_ofp_error_msg); - - /* Extract the type for use later */ - guint16 type = tvb_get_ntohs(tvb, offset); - - add_child(type_tree, ofp_error_msg_type, tvb, &offset, 2); - dissect_error_code(type_tree, ofp_error_msg_code, tvb, &offset, type); - - if (type == OFPET_HELLO_FAILED) - add_child(type_tree, ofp_error_msg_data_str, tvb, &offset, len - offset); - else if (type == OFPET_BAD_REQUEST || - type == OFPET_BAD_ACTION || - type == OFPET_FLOW_MOD_FAILED) { - /* Dissect the data as an OpenFlow packet */ - proto_item *data_item = proto_tree_add_item(type_tree, ofp_error_msg_data, tvb, offset, -1, FALSE); - proto_tree *data_tree = proto_item_add_subtree(data_item, ett_ofp_error_msg_data); - tvbuff_t *next_tvb = tvb_new_subset(tvb, offset, -1, len - offset); - - /* Temporarily disable writing */ - gboolean writeable = col_get_writable(pinfo->cinfo); - col_set_writable( pinfo->cinfo, FALSE); - - /* Finally do the dissection */ - dissect_openflow_message(next_tvb, pinfo, data_tree); - - col_set_writable( pinfo->cinfo, writeable); - - offset += (len - offset); - } - else - add_child(type_tree, ofp_error_msg_data, tvb, &offset, len - offset); - break; - } - - case OFPT_ECHO_REQUEST: - case OFPT_ECHO_REPLY: { - if (len - offset > 0) - add_child(tree, ofp_echo, tvb, &offset, len - offset); - break; - } - - case OFPT_VENDOR: { - if (len - offset > 0) { - add_child(tree, ofp_vendor, tvb, &offset, len - offset); - } - break; - } - - case OFPT_FEATURES_REQUEST: - /* nothing else in this packet type */ - break; - - case OFPT_FEATURES_REPLY: { - - proto_item *sf_port_item = NULL; - proto_tree *sf_port_tree = NULL; - guint num_ports; - gint sz; - - type_item = proto_tree_add_item(ofp_tree, ofp_switch_features, tvb, offset, -1, FALSE); - //break; - type_tree = proto_item_add_subtree(type_item, ett_ofp_switch_features); - - /* fields we'll put directly in the subtree */ - - add_child(type_tree, ofp_switch_features_datapath_id, tvb, &offset, 8); - - add_child(type_tree, ofp_switch_features_n_buffers, tvb, &offset, 4); - add_child(type_tree, ofp_switch_features_n_tables, tvb, &offset, 1); - dissect_pad(type_tree, &offset, 3); - - - /* capabilities */ - dissect_capability_array(tvb, pinfo, type_tree, offset, 4); - offset += 4; - - /* actions */ - dissect_switch_features_actions(tvb, pinfo, type_tree, offset, 4); - offset += 4; - - /* handle ports */ - sf_port_item = proto_tree_add_item(type_tree, ofp_switch_features_ports_hdr, tvb, offset, -1, FALSE); - sf_port_tree = proto_item_add_subtree(sf_port_item, ett_ofp_switch_features_ports_hdr); - sz = len - sizeof(struct ofp_switch_features); - - if( sz > 0 ) { - num_ports = sz / sizeof(struct ofp_phy_port); /* number of ports */ - proto_tree_add_uint(sf_port_tree, ofp_switch_features_ports_num, tvb, offset, num_ports*sizeof(struct ofp_phy_port), num_ports); - - dissect_phy_ports(sf_port_tree, sf_port_item, tvb, pinfo, &offset, num_ports); - if( num_ports * sizeof(struct ofp_phy_port) < sz ) { - snprintf(str, STR_LEN, "%uB were leftover at end of packet", sz - num_ports*sizeof(struct ofp_phy_port)); - add_child_str(sf_port_tree, ofp_switch_features_ports_warn, tvb, &offset, 0, str); - } - } - else if( sz < 0 ) { - /* not enough bytes => wireshark will already have reported the error */ - } - else { - snprintf(str, STR_LEN, "No ports were specified"); - add_child_str(sf_port_tree, ofp_switch_features_ports_warn, tvb, &offset, 0, str); - } - break; - } - - case OFPT_GET_CONFIG_REQUEST: - /* nothing else in this packet type */ - break; - - case OFPT_GET_CONFIG_REPLY: - case OFPT_SET_CONFIG: { - type_item = proto_tree_add_item(ofp_tree, ofp_switch_config, tvb, offset, -1, FALSE); - type_tree = proto_item_add_subtree(type_item, ett_ofp_switch_config); - dissect_switch_config_flags(tvb, pinfo, type_tree, &offset); - add_child(type_tree, ofp_switch_config_miss_send_len, tvb, &offset, 2); - break; - } - - case OFPT_QUEUE_GET_CONFIG_REQUEST: { - type_item = proto_tree_add_item(ofp_tree, ofp_queue_get_config_request, tvb, offset, -1, FALSE); - type_tree = proto_item_add_subtree(type_item, ett_ofp_queue_get_config_request); - dissect_port(type_tree, ofp_queue_get_config_request_port_no, tvb, &offset); - dissect_pad(type_tree, &offset, 2); - break; - } - - case OFPT_QUEUE_GET_CONFIG_REPLY: { - type_item = proto_tree_add_item(ofp_tree, ofp_queue_get_config_reply, tvb, offset, -1, FALSE); - type_tree = proto_item_add_subtree(type_item, ett_ofp_queue_get_config_reply); - - dissect_port(type_tree, ofp_queue_get_config_reply_port_no, tvb, &offset); - dissect_pad(type_tree, &offset, 6); - - /* handle queues */ - dissect_queue_array(tvb, pinfo, type_tree, len, &offset); - break; - } - - case OFPT_PACKET_IN: { - type_item = proto_tree_add_item(ofp_tree, ofp_packet_in, tvb, offset, -1, FALSE); - type_tree = proto_item_add_subtree(type_item, ett_ofp_packet_in); - - add_child(type_tree, ofp_packet_in_buffer_id, tvb, &offset, 4); - - /* explicitly pull out the length so we can use it to determine data's size */ - guint16 total_len = tvb_get_ntohs( tvb, offset ); - proto_tree_add_uint(type_tree, ofp_packet_in_total_len, tvb, offset, 2, total_len); - offset += 2; - - add_child(type_tree, ofp_packet_in_in_port, tvb, &offset, 2); - add_child(type_tree, ofp_packet_in_reason, tvb, &offset, 1); - dissect_pad(type_tree, &offset, 1); - - if (len > sizeof(struct ofp_packet_in)) { - /* continue the dissection with the Ethernet dissector */ - if (data_ethernet) { - proto_item *data_item = proto_tree_add_item(type_tree, ofp_packet_in_data_hdr, tvb, offset, -1, FALSE); - proto_tree *data_tree = proto_item_add_subtree(data_item, ett_ofp_packet_in_data_hdr); - tvbuff_t *next_tvb = tvb_new_subset(tvb, offset, -1, total_len); - dissect_ethernet(next_tvb, pinfo, data_tree); - } else { - /* if we couldn't load the ethernet dissector, just display the bytes */ - add_child(type_tree, ofp_packet_in_data_hdr, tvb, &offset, total_len); - } - } - break; - } - - case OFPT_FLOW_REMOVED: { - type_item = proto_tree_add_item(ofp_tree, ofp_flow_removed, tvb, offset, -1, FALSE); - type_tree = proto_item_add_subtree(type_item, ett_ofp_flow_removed); - - dissect_match(type_tree, type_item, tvb, pinfo, &offset); - add_child(type_tree, ofp_flow_removed_cookie, tvb, &offset, 8); - add_child(type_tree, ofp_flow_removed_priority, tvb, &offset, 2); - add_child(type_tree, ofp_flow_removed_reason, tvb, &offset, 1); - dissect_pad(type_tree, &offset, 1); - add_child(type_tree, ofp_flow_removed_duration_sec, tvb, &offset, 4); - add_child(type_tree, ofp_flow_removed_duration_nsec, tvb, &offset, 4); - add_child(type_tree, ofp_flow_removed_idle_timeout, tvb, &offset, 2); - dissect_pad(type_tree, &offset, 2); - add_child(type_tree, ofp_flow_removed_packet_count, tvb, &offset, 8); - add_child(type_tree, ofp_flow_removed_byte_count, tvb, &offset, 8); - break; - } - - case OFPT_PORT_STATUS: { - type_item = proto_tree_add_item(ofp_tree, ofp_port_status, tvb, offset, -1, FALSE); - type_tree = proto_item_add_subtree(type_item, ett_ofp_port_status); - - add_child(type_tree, ofp_port_status_reason, tvb, &offset, 1); - dissect_pad(type_tree, &offset, 7); - dissect_phy_ports(type_tree, type_item, tvb, pinfo, &offset, 1); - break; - } - - case OFPT_PACKET_OUT: { - type_item = proto_tree_add_item(ofp_tree, ofp_packet_out, tvb, offset, -1, FALSE); - type_tree = proto_item_add_subtree(type_item, ett_ofp_packet_out); - - /* get buffer_id value for later use */ - guint32 buffer_id = tvb_get_ntohl( tvb, offset ); - - if( buffer_id == 0xFFFFFFFF ) - add_child_str(type_tree, ofp_packet_out_buffer_id, tvb, &offset, 4, "None"); - else { - snprintf(str, STR_LEN, "%u", buffer_id); - add_child_str(type_tree, ofp_packet_out_buffer_id, tvb, &offset, 4, str); - } - - /* display in port */ - // FIXME: bug in dissect_port for latest version - dissect_port(type_tree, ofp_packet_out_in_port, tvb, &offset); - - /* pull out actions len */ - guint16 actions_len = tvb_get_ntohs( tvb, offset); - add_child(type_tree, ofp_packet_out_actions_len, tvb, &offset, 2); - - /* dissect action array; will handle no-action case */ - dissect_action_array(tvb, pinfo, type_tree, offset + actions_len, offset); - offset += actions_len; - - /* if buffer id == -1, then display the provided packet */ - if( buffer_id == -1 ) { - /* continue the dissection with the Ethernet dissector */ - guint total_len = len - offset; - if( data_ethernet ) { - proto_item *data_item = proto_tree_add_item(type_tree, ofp_packet_out_data_hdr, tvb, offset, -1, FALSE); - proto_tree *data_tree = proto_item_add_subtree(data_item, ett_ofp_packet_out_data_hdr); - tvbuff_t *next_tvb = tvb_new_subset(tvb, offset, -1, total_len); - dissect_ethernet(next_tvb, pinfo, data_tree); - } - else { - /* if we couldn't load the ethernet dissector, just display the bytes */ - add_child(type_tree, ofp_packet_out_data_hdr, tvb, &offset, total_len); - } - } - - break; - } - - case OFPT_FLOW_MOD: { - type_item = proto_tree_add_item(ofp_tree, ofp_flow_mod, tvb, offset, -1, FALSE); - type_tree = proto_item_add_subtree(type_item, ett_ofp_flow_mod); - - dissect_match(type_tree, type_item, tvb, pinfo, &offset); - add_child(type_tree, ofp_flow_mod_cookie, tvb, &offset, 8); - add_child(type_tree, ofp_flow_mod_command, tvb, &offset, 2); - add_child(type_tree, ofp_flow_mod_idle_timeout, tvb, &offset, 2); - add_child(type_tree, ofp_flow_mod_hard_timeout, tvb, &offset, 2); - add_child(type_tree, ofp_flow_mod_priority, tvb, &offset, 2); - - /* get buffer_id value for later use */ - guint32 buffer_id = tvb_get_ntohl( tvb, offset ); - - if( buffer_id == 0xFFFFFFFF ) - add_child_str(type_tree, ofp_flow_mod_buffer_id, tvb, &offset, 4, "None"); - else { - snprintf(str, STR_LEN, "%u", buffer_id); - add_child_str(type_tree, ofp_flow_mod_buffer_id, tvb, &offset, 4, str); - } - - /* add the output port */ - dissect_port(type_tree, ofp_flow_mod_out_port, tvb, &offset ); - dissect_flow_mod_flags(tvb, pinfo, type_tree, &offset); - dissect_action_array(tvb, pinfo, type_tree, len, offset); - break; - } - - case OFPT_PORT_MOD: { - type_item = proto_tree_add_item(ofp_tree, ofp_port_mod, tvb, offset, -1, FALSE); - type_tree = proto_item_add_subtree(type_item, ett_ofp_port_mod); - - dissect_port_mod(type_tree, type_item, tvb, pinfo, &offset); - break; - } - - case OFPT_STATS_REQUEST: { - type_item = proto_tree_add_item(ofp_tree, ofp_stats_request, tvb, offset, -1, FALSE); - type_tree = proto_item_add_subtree(type_item, ett_ofp_stats_request); - - guint16 type = tvb_get_ntohs( tvb, offset ); - add_child(type_tree, ofp_stats_request_type, tvb, &offset, 2); - add_child(type_tree, ofp_stats_request_flags, tvb, &offset, 2); - - switch( type ) { - case OFPST_FLOW: { - proto_item *flow_item = proto_tree_add_item(type_tree, ofp_flow_stats_request, tvb, offset, -1, FALSE); - proto_tree *flow_tree = proto_item_add_subtree(flow_item, ett_ofp_flow_stats_request); - - dissect_match(flow_tree, flow_item, tvb, pinfo, &offset); - - guint8 id = tvb_get_guint8( tvb, offset ); - if( id == 0xFF ) - add_child_str(flow_tree, ofp_flow_stats_request_table_id, tvb, &offset, 1, "All Tables"); - else { - snprintf(str, STR_LEN, "%u", id); - add_child_str(flow_tree, ofp_flow_stats_request_table_id, tvb, &offset, 1, str); - } - - dissect_pad(flow_tree, &offset, 1); - dissect_port(flow_tree, ofp_flow_stats_request_out_port, tvb, &offset ); - break; - } - - case OFPST_AGGREGATE: { - proto_item *aggr_item = proto_tree_add_item(type_tree, ofp_aggr_stats_request, tvb, offset, -1, FALSE); - proto_tree *aggr_tree = proto_item_add_subtree(aggr_item, ett_ofp_aggr_stats_request); - - dissect_match(aggr_tree, aggr_item, tvb, pinfo, &offset); - - guint8 id = tvb_get_guint8( tvb, offset ); - if( id == 0xFF ) - add_child_str(aggr_tree, ofp_aggr_stats_request_table_id, tvb, &offset, 1, "All Tables"); - else { - snprintf(str, STR_LEN, "%u", id); - add_child_str(aggr_tree, ofp_aggr_stats_request_table_id, tvb, &offset, 1, str); - } - - dissect_pad(aggr_tree, &offset, 3); - break; - } - - case OFPST_TABLE: - /* no body for these types of requests */ - break; - - case OFPST_PORT:{ - if (len - offset > 0) { - proto_item *port_item = proto_tree_add_item(type_tree, ofp_port_stats_request, tvb, offset, -1, FALSE); - proto_tree *port_tree = proto_item_add_subtree(port_item, ett_ofp_port_stats_request); - dissect_port(port_tree, ofp_port_stats_request_port_no, tvb, &offset); - dissect_pad(port_tree, &offset, 6); - } - } - break; - - case OFPST_QUEUE: { - proto_item *queue_item = proto_tree_add_item(type_tree, ofp_queue_stats_request, tvb, offset, -1, FALSE); - proto_tree *queue_tree = proto_item_add_subtree(queue_item, ett_ofp_queue_stats_request); - - dissect_port(queue_tree, ofp_queue_stats_port_no, tvb, &offset); - dissect_pad(queue_tree, &offset, 2); - dissect_queue_id(queue_tree, ofp_queue_stats_queue_id, tvb, &offset); - break; - } - - default: - /* add as bytes if type isn't one we know how to dissect */ - add_child(type_tree, ofp_stats_request_body, tvb, &offset, len - offset); - } - - break; - } - - case OFPT_STATS_REPLY: { - type_item = proto_tree_add_item(ofp_tree, ofp_stats_reply, tvb, offset, -1, FALSE); - type_tree = proto_item_add_subtree(type_item, ett_ofp_stats_reply); - - guint16 type = tvb_get_ntohs( tvb, offset ); - add_child(type_tree, ofp_stats_reply_type, tvb, &offset, 2); - add_child(type_tree, ofp_stats_reply_flags, tvb, &offset, 2); - - switch( type ) { - - case OFPST_DESC: { - // FIXME: add desc stats - proto_item* desc_item = proto_tree_add_item(type_tree, ofp_desc_stats, tvb, offset, -1, FALSE); - proto_tree* desc_tree = proto_item_add_subtree(desc_item, ett_ofp_desc_stats); - - add_child( desc_tree, ofp_desc_stats_mfr_desc, tvb, &offset, DESC_STR_LEN ); - add_child( desc_tree, ofp_desc_stats_hw_desc, tvb, &offset, DESC_STR_LEN ); - add_child( desc_tree, ofp_desc_stats_sw_desc, tvb, &offset, DESC_STR_LEN ); - add_child( desc_tree, ofp_desc_stats_serial_num, tvb, &offset, SERIAL_NUM_LEN ); - add_child( desc_tree, ofp_desc_stats_dp_desc, tvb, &offset, DESC_STR_LEN ); - - break; - } - - case OFPST_FLOW: { - /* process each flow stats struct in the packet */ - while( offset < len ) { - proto_item* flow_item = proto_tree_add_item(type_tree, ofp_flow_stats_reply, tvb, offset, -1, FALSE); - proto_tree* flow_tree = proto_item_add_subtree(flow_item, ett_ofp_flow_stats_reply); - - /* just get the length of this part of the packet; no need - to put it in the tree */ - guint16 total_len = tvb_get_ntohs( tvb, offset ); - guint offset_start = offset; - offset += 2; - - add_child(flow_tree, ofp_flow_stats_reply_table_id, tvb, &offset, 1); - dissect_pad(flow_tree, &offset, 1); - dissect_match(flow_tree, flow_item, tvb, pinfo, &offset); - add_child(flow_tree, ofp_flow_stats_reply_duration_sec, tvb, &offset, 4); - add_child(flow_tree, ofp_flow_stats_reply_duration_nsec, tvb, &offset, 4); - add_child(flow_tree, ofp_flow_stats_reply_priority, tvb, &offset, 2); - add_child(flow_tree, ofp_flow_stats_reply_idle_timeout, tvb, &offset, 2); - add_child(flow_tree, ofp_flow_stats_reply_hard_timeout, tvb, &offset, 2); - dissect_pad(flow_tree, &offset, 6); - add_child(flow_tree, ofp_flow_stats_reply_cookie, tvb, &offset, 8); - add_child(flow_tree, ofp_flow_stats_reply_packet_count, tvb, &offset, 8); - add_child(flow_tree, ofp_flow_stats_reply_byte_count, tvb, &offset, 8); - - /* parse the actions for this flow */ - dissect_action_array(tvb, pinfo, flow_tree, total_len + offset_start, offset); - offset = total_len + offset_start; - } - break; - } - - case OFPST_AGGREGATE: { - proto_item* aggr_item = proto_tree_add_item(type_tree, ofp_aggr_stats_reply, tvb, offset, -1, FALSE); - proto_tree* aggr_tree = proto_item_add_subtree(aggr_item, ett_ofp_aggr_stats_reply); - - add_child(aggr_tree, ofp_aggr_stats_reply_packet_count, tvb, &offset, 8); - add_child(aggr_tree, ofp_aggr_stats_reply_byte_count, tvb, &offset, 8); - add_child(aggr_tree, ofp_aggr_stats_reply_flow_count, tvb, &offset, 4); - - dissect_pad(aggr_tree, &offset, 4); - break; - } - - case OFPST_TABLE: { - /* process each table stats struct in the packet */ - while( offset < len ) { - proto_item *table_item = proto_tree_add_item(type_tree, ofp_table_stats, tvb, offset, -1, FALSE); - proto_tree *table_tree = proto_item_add_subtree(table_item, ett_ofp_table_stats); - - add_child(table_tree, ofp_table_stats_table_id, tvb, &offset, 1); - dissect_pad(table_tree, &offset, 3); - add_child( table_tree, ofp_table_stats_name, tvb, &offset, OFP_MAX_TABLE_NAME_LEN); - dissect_wildcards(table_tree, table_item, tvb, pinfo, &offset, ofp_table_stats_wildcards); - add_child(table_tree, ofp_table_stats_max_entries, tvb, &offset, 4); - add_child(table_tree, ofp_table_stats_active_count, tvb, &offset, 4); - add_child(table_tree, ofp_table_stats_lookup_count, tvb, &offset, 8); - add_child(table_tree, ofp_table_stats_matched_count, tvb, &offset, 8); - } - break; - } - - case OFPST_PORT: { - /* process each port stats struct in the packet */ - while( offset < len ) { - proto_item *port_item = proto_tree_add_item(type_tree, ofp_port_stats, tvb, offset, -1, FALSE); - proto_tree *port_tree = proto_item_add_subtree(port_item, ett_ofp_port_stats); - - dissect_port(port_tree, ofp_port_stats_port_no, tvb, &offset); - dissect_pad(port_tree, &offset, 6); - add_child(port_tree, ofp_port_stats_rx_packets, tvb, &offset, 8); - add_child(port_tree, ofp_port_stats_tx_packets, tvb, &offset, 8); - add_child(port_tree, ofp_port_stats_rx_bytes, tvb, &offset, 8); - add_child(port_tree, ofp_port_stats_tx_bytes, tvb, &offset, 8); - add_child(port_tree, ofp_port_stats_rx_dropped, tvb, &offset, 8); - add_child(port_tree, ofp_port_stats_tx_dropped, tvb, &offset, 8); - add_child(port_tree, ofp_port_stats_rx_errors, tvb, &offset, 8); - add_child(port_tree, ofp_port_stats_tx_errors, tvb, &offset, 8); - add_child(port_tree, ofp_port_stats_rx_frame_err, tvb, &offset, 8); - add_child(port_tree, ofp_port_stats_rx_over_err, tvb, &offset, 8); - add_child(port_tree, ofp_port_stats_rx_crc_err, tvb, &offset, 8); - add_child(port_tree, ofp_port_stats_collisions, tvb, &offset, 8); - } - break; - } - - case OFPST_QUEUE: { - /* process each port stats struct in the packet */ - while( offset < len ) { - proto_item *queue_item = proto_tree_add_item(type_tree, ofp_queue_stats, tvb, offset, -1, FALSE); - proto_tree *queue_tree = proto_item_add_subtree(queue_item, ett_ofp_queue_stats); - - dissect_port(queue_tree, ofp_queue_stats_port_no, tvb, &offset); - dissect_pad(queue_tree, &offset, 2); - dissect_queue_id(queue_tree, ofp_queue_stats_queue_id, tvb, &offset); - add_child(queue_tree, ofp_queue_stats_tx_bytes, tvb, &offset, 8); - add_child(queue_tree, ofp_queue_stats_tx_packets, tvb, &offset, 8); - add_child(queue_tree, ofp_queue_stats_tx_errors, tvb, &offset, 8); - } - break; - } - - case OFPST_VENDOR: { - proto_item* vendor_item = proto_tree_add_item(type_tree, ofp_vendor_stats, tvb, offset, -1, FALSE); - proto_tree* vendor_tree = proto_item_add_subtree(vendor_item, ett_ofp_vendor_stats); - - add_child(vendor_tree, ofp_vendor_stats_vendor, tvb, &offset, 4); - add_child(vendor_tree, ofp_vendor_stats_body, tvb, &offset, len - offset); - - break; - } - - default: - /* add as bytes if type isn't one we know how to dissect */ - add_child(type_tree, ofp_stats_reply_body, tvb, &offset, len - offset); - } - - break; - } - - default: - /* add a warning if we encounter an unrecognized packet type */ - snprintf(str, STR_LEN, "Dissector does not recognize type %u", type); - add_child_str(tree, ofp_header_warn_type, tvb, &offset, len - offset, str); - } - } -} - -static void dissect_openflow(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) -{ - /* have wireshark reassemble our PDUs; call dissect_openflow_when full PDU assembled */ - tcp_dissect_pdus(tvb, pinfo, tree, TRUE, 4, get_openflow_message_len, dissect_openflow_message); -} diff --git a/openflow/utilities/wireshark_dissectors/openflow/plugin.c b/openflow/utilities/wireshark_dissectors/openflow/plugin.c deleted file mode 100644 index deb99c25..00000000 --- a/openflow/utilities/wireshark_dissectors/openflow/plugin.c +++ /dev/null @@ -1,28 +0,0 @@ -/* Do not modify this file. */ -/* It is created automatically by the Makefile. */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include - -#include "moduleinfo.h" - -#ifndef ENABLE_STATIC -G_MODULE_EXPORT const gchar version[] = VERSION; - -/* Start the functions we need for the plugin stuff */ - -G_MODULE_EXPORT void -plugin_register (void) -{ - {extern void proto_register_openflow (void); proto_register_openflow ();} -} - -G_MODULE_EXPORT void -plugin_reg_handoff(void) -{ - {extern void proto_reg_handoff_openflow (void); proto_reg_handoff_openflow ();} -} -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/airpcap.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/airpcap.h deleted file mode 100644 index 639a930a..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/airpcap.h +++ /dev/null @@ -1,907 +0,0 @@ -/* - * Copyright (c) 2006-2007 CACE Technologies, Davis (California) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#if !defined(AIRPCAP_H__EAE405F5_0171_9592_B3C2_C19EC426AD34__INCLUDED_) -#define AIRPCAP_H__EAE405F5_0171_9592_B3C2_C19EC426AD34__INCLUDED_ - -#ifdef _MSC_VER -// This disables a VS warning for zero-sized arrays. -#pragma warning( disable : 4200) -// This stops VS2005 ranting against stdio. -#pragma warning( disable : 4996) -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/*! - \mainpage AirPcap interface documentation - - \section Introduction - - This document describes the data structures and the functions exported by the CACE Technologies AirPcap library. - The AirPcap library provides low-level access to the AirPcap driver including advanced capabilities such as channel setting, - link type control and WEP configuration.
- This manual includes the following sections: - - \note throughout this documentation, \e device refers to a physical USB AirPcap device, while \e adapter is an open API - instance. Most of the AirPcap API operations are adapter-specific but some of them, like setting the channel, are - per-device and will be reflected on all the open adapters. These functions will have "Device" in their name, e.g. - AirpcapSetDeviceChannel(). - - \b Sections: - - - \ref airpcapfuncs - - \ref airpcapdefs - - \ref radiotap -*/ - -/** @defgroup airpcapdefs AirPcap definitions and data structures - * @{ - */ - -/*! - \brief This string is the fixed prefix in the airpcap adapter name. - It can be used to parse the name field in an AirpcapDeviceDescription structure. -*/ -#define AIRPCAP_DEVICE_NAME_PREFIX "\\\\.\\airpcap" - -/*! - \brief This string is the scanf modifier to extract the adapter number from an adapter name. - It can be used to parse the name field in an AirpcapDeviceDescription structure with scanf. -*/ -#define AIRPCAP_DEVICE_NUMBER_EXTRACT_STRING "\\\\.\\airpcap%u" - -#define AIRPCAP_DEVICE_ANY_EXTRACT_STRING "\\\\.\\airpcap_any" - -/*! - \brief Entry in the list returned by \ref AirpcapGetDeviceList(); -*/ -typedef struct _AirpcapDeviceDescription -{ - struct _AirpcapDeviceDescription *next; ///< Next element in the list - PCHAR Name; ///< Device name - PCHAR Description; ///< Device description -} AirpcapDeviceDescription, *PAirpcapDeviceDescription; - -#define MAX_ENCRYPTION_KEYS 64 - -#define WEP_KEY_MAX_SIZE 32 ///< Maximum size of a WEP key, in bytes. This is the size of an entry in the - ///< AirpcapWepKeysCollection structure - -#ifndef __MINGW32__ -#pragma pack(push) -#pragma pack(1) -#endif // __MINGW32__ - - -#define AIRPCAP_KEYTYPE_WEP 0 ///< Key type: WEP. The key can have an arbitrary length smaller than 32 bytes. -#define AIRPCAP_KEYTYPE_TKIP 1 ///< Key type: TKIP (WPA). NOT SUPPORTED YET. -#define AIRPCAP_KEYTYPE_CCMP 2 ///< Key type: CCMP (WPA2). NOT SUPPORTED YET. - -/*! - \brief WEP key container -*/ -typedef struct _AirpcapKey -{ - UINT KeyType; ///< Type of key, can be on of: \ref AIRPCAP_KEYTYPE_WEP, \ref AIRPCAP_KEYTYPE_TKIP, \ref AIRPCAP_KEYTYPE_CCMP. Only AIRPCAP_KEYTYPE_WEP is supported by the driver at the moment. - UINT KeyLen; ///< Length of the key, in bytes - BYTE KeyData[WEP_KEY_MAX_SIZE]; ///< Key Data -} -#ifdef __MINGW32__ -__attribute__((__packed__)) -#endif // __MINGW32__ -AirpcapKey, *PAirpcapKey; - -/*! - \brief frequency Band. - 802.11 adapters can support different frequency bands, the most important of which are: 2.4GHz (802.11b/g/n) - and 5GHz (802.11a/n). -*/ -typedef enum _AirpcapChannelBand -{ - AIRPCAP_CB_AUTO = 1, ///< Automatically pick the best frequency band - AIRPCAP_CB_2_4_GHZ = 2, ///< 2.4 GHz frequency band - AIRPCAP_CB_4_GHZ = 4, ///< 4 GHz frequency band - AIRPCAP_CB_5_GHZ = 5 ///< 5 GHz frequency band -}AirpcapChannelBand, *PAirpcapChannelBand; - -/*! - \brief Type of frame validation the adapter performs. - An adapter can be instructed to accept different kind of frames: correct frames only, frames with wrong Frame Check Sequence (FCS) only, all frames. -*/ -typedef enum _AirpcapValidationType -{ - AIRPCAP_VT_ACCEPT_EVERYTHING = 1, ///< Accept all the frames the device captures - AIRPCAP_VT_ACCEPT_CORRECT_FRAMES = 2, ///< Accept correct frames only, i.e. frames with correct Frame Check Sequence (FCS). - AIRPCAP_VT_ACCEPT_CORRUPT_FRAMES = 3, ///< Accept corrupt frames only, i.e. frames with worng Frame Check Sequence (FCS). - AIRPCAP_VT_UNKNOWN = 4 ///< Unknown validation type. You should see it only in case of error. -}AirpcapValidationType, *PAirpcapValidationType; - -/*! - \brief Type of decryption the adapter performs. - An adapter can be instructed to turn decryption (based on the device-configured keys configured - with \ref AirpcapSetDeviceKeys()) on or off. -*/ -typedef enum _AirpcapDecryptionState -{ - AIRPCAP_DECRYPTION_ON = 1, ///< This adapter performs decryption - AIRPCAP_DECRYPTION_OFF = 2 ///< This adapter does not perform decryption -}AirpcapDecryptionState, *PAirpcapDecryptionState; - - -/*! - \brief Storage for a MAC address -*/ -typedef struct _AirpcapMacAddress -{ - BYTE Address[6]; ///< MAC address bytes -} -#ifdef __MINGW32__ -__attribute__((__packed__)) -#endif // __MINGW32__ -AirpcapMacAddress, *PAirpcapMacAddress; - -/*! - \brief This structure is used to store a collection of WEP keys. - Note that the definition of the structure doesn't contain any key, so be careful to allocate a buffer - with the size of the key, like in the following example: - - \code - PAirpcapKeysCollection KeysCollection; - UINT KeysCollectionSize; - - KeysCollectionSize = sizeof(AirpcapKeysCollection) + NumKeys * sizeof(AirpcapKey); - - KeysCollection = (PAirpcapKeysCollection)malloc(KeysCollectionSize); - if(!KeysCollection) - { - // Error - } - \endcode -*/ -typedef struct _AirpcapKeysCollection -{ - UINT nKeys; ///< Number of keys in the collection - AirpcapKey Keys[0]; ///< Array of nKeys keys. -} AirpcapKeysCollection, *PAirpcapKeysCollection; - -/*! - \brief Packet header. - - This structure defines the BPF that preceeds every packet delivered to the application. -*/ -typedef struct _AirpcapBpfHeader -{ - UINT TsSec; ///< Timestamp associated with the captured packet. SECONDS. - UINT TsUsec; ///< Timestamp associated with the captured packet. MICROSECONDS. - UINT Caplen; ///< Length of captured portion. The captured portion can be different from the original packet, because it is possible (with a proper filter) to instruct the driver to capture only a portion of the packets. - UINT Originallen; ///< Original length of packet - USHORT Hdrlen; ///< Length of bpf header (this struct plus alignment padding). In some cases, a padding could be added between the end of this structure and the packet data for performance reasons. This field can be used to retrieve the actual data of the packet. -} -#ifdef __MINGW32__ -__attribute__((__packed__)) -#endif // __MINGW32__ -AirpcapBpfHeader, *PAirpcapBpfHeader; - -/// Helper macros to extract packets coming from the driver. Rounds up to the next even multiple of AIRPCAP_ALIGNMENT. -#define AIRPCAP_ALIGNMENT sizeof(int) -#define AIRPCAP_WORDALIGN(x) (((x)+(AIRPCAP_ALIGNMENT-1))&~(AIRPCAP_ALIGNMENT-1)) - -#ifndef __MINGW32__ -#pragma pack(pop) -#endif // __MINGW32__ - -#define AIRPCAP_ERRBUF_SIZE 512 ///< Size of the error buffer, in bytes - -#ifndef __AIRPCAP_DRIVER__ - -/*! - \brief Link type. - AirPcap supports two kind of 802.11 linktypes: plain 802.11 and radiotap. -*/ -#undef _AirpcapLinkType -typedef enum _AirpcapLinkType -{ - AIRPCAP_LT_802_11 = 1, ///< plain 802.11 linktype. Every packet in the buffer contains the raw 802.11 frame, including MAC FCS. - AIRPCAP_LT_802_11_PLUS_RADIO = 2, ///< 802.11 plus radiotap linktype. Every packet in the buffer contains a radiotap header followed by the 802.11 frame. MAC FCS is included. - AIRPCAP_LT_UNKNOWN = 3, ///< Unknown linktype. You should see it only in case of error. - AIRPCAP_LT_802_11_PLUS_PPI = 4 ///< 802.11 plus PPI header linktype. Every packet in the buffer contains a PPI header followed by the 802.11 frame. MAC FCS is included. -}AirpcapLinkType, *PAirpcapLinkType; - -#if !defined(AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_) -#define AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_ -/*! - \brief Adapter handle. -*/ -typedef struct _AirpcapHandle AirpcapHandle, *PAirpcapHandle; -#endif - -/*! - \brief Capture statistics. - Returned by \ref AirpcapGetStats(); -*/ -typedef struct _AirpcapStats -{ - UINT Recvs; ///< Number of packets that the driver received by the adapter - ///< from the beginning of the current capture. This value includes the packets - ///< dropped because of buffer full. - UINT Drops; ///< number of packets that the driver dropped from the beginning of a capture. - ///< A packet is lost when the the buffer of the driver is full. - UINT IfDrops; ///< Packets dropped by the card before going to the USB bus. - ///< Not supported at the moment. - UINT Capt; ///< number of packets that pass the BPF filter, find place in the kernel buffer and - ///< therefore reach the application. -}AirpcapStats, *PAirpcapStats; - -/*! - \brief Channel information. - Used by \ref AirpcapSetDeviceChannelEx(), \ref AirpcapGetDeviceChannelEx(), \ref AirpcapGetDeviceSupportedChannels() -*/ -typedef struct _AirpcapChannelInfo -{ - UINT Frequency; ///< Channel frequency, in MHz. - /*! - \brief 802.11n specific. Offset of the extension channel in case of 40MHz channels. - - Possible values are -1, 0 +1: - - -1 means that the extension channel should be below the control channel (e.g. Control = 5 and Extension = 1) - - 0 means that no extension channel should be used (20MHz channels or legacy mode) - - +1 means that the extension channel should be above the control channel (e.g. Control = 1 and Extension = 5) - - In case of 802.11a/b/g channels (802.11n legacy mode), this field should be set to 0. - */ - CHAR ExtChannel; - UCHAR Reserved[3]; ///< Reserved. It should be set to {0,0,0}. -} - AirpcapChannelInfo, *PAirpcapChannelInfo; - - -/*@}*/ - -/** @defgroup airpcapfuncs AirPcap functions - * @{ - */ - -/*! - \brief Return a string with the API version - \param VersionMajor Pointer to a variable that will be filled with the major version number. - \param VersionMinor Pointer to a variable that will be filled with the minor version number. - \param VersionRev Pointer to a variable that will be filled with the revision number. - \param VersionBuild Pointer to a variable that will be filled with the build number. -*/ -void AirpcapGetVersion(PUINT VersionMajor, PUINT VersionMinor, PUINT VersionRev, PUINT VersionBuild); - -/*! - \brief Return the last error related to the specified handle - \param AdapterHandle Handle to an open adapter. - \return The string with the last error. -*/ -PCHAR AirpcapGetLastError(PAirpcapHandle AdapterHandle); - -/*! - \brief Return the list of available devices - \param PPAllDevs Address to a caller allocated pointer. On success this pointer will receive the head of a list of available devices. - \param Ebuf String that will contain error information if FALSE is returned. The size of the string must be AIRPCAP_ERRBUF_SIZE bytes. - \return TRUE on success. FALSE is returned on failure, in which case Ebuf is filled in with an appropriate error message. - - Here's a snippet of code that shows how to use AirpcapGetDeviceList(): - - \code - CHAR Ebuf[AIRPCAP_ERRBUF_SIZE]; - AirpcapDeviceDescription *Desc, *tDesc; - - if(AirpcapGetDeviceList(&Desc, Ebuf) == -1) - { - printf("Unable to get the list of devices: %s\n", Ebuf); - return -1; - } - - for(tDesc = Desc; tDesc; tDesc = tDesc->next) - { - printf("%u) %s (%s)\n", - ++i, - tDesc->Name, - tDesc->Description); - } - - AirpcapFreeDeviceList(Desc); - \endcode -*/ -BOOL AirpcapGetDeviceList(PAirpcapDeviceDescription *PPAllDevs, PCHAR Ebuf); - -/*! - \brief Free a list of devices returned by AirpcapGetDeviceList() - \param PAllDevs Head of the list of devices returned by \ref AirpcapGetDeviceList(). -*/ -VOID AirpcapFreeDeviceList(PAirpcapDeviceDescription PAllDevs); - -/*! - \brief Open an adapter - \param DeviceName Name of the device to open. Use \ref AirpcapGetDeviceList() to get the list of devices. - \param Ebuf String that will contain error information in case of failure. The size of the string must be AIRPCAP_ERRBUF_SIZE bytes. - \return A PAirpcapHandle handle on success. NULL is returned on failure, in which case Ebuf is filled in with an appropriate error message. -*/ -PAirpcapHandle AirpcapOpen(PCHAR DeviceName, PCHAR Ebuf); - -/*! - \brief Close an adapter - \param AdapterHandle Handle to the adapter to close. -*/ -VOID AirpcapClose(PAirpcapHandle AdapterHandle); - -/*! - \brief Sets the monitor mode for the specified adapter - \param AdapterHandle Handle to the adapter. - \param MonitorModeEnabled If TRUE, the adapter will be put in monitor mode. If FALSE, the adapter will be configured - for normal operation. - \return TRUE on success. - - When monitor mode is on, the adapter captures all the packets transmitted on the channel. This includes: - - - unicast packets - - multicast packets - - broadcast packets - - control and management packets - - When monitor mode is off, the adapter has a filter on unicast packets to capture only the packets whose MAC - destination address equals to the adapter's address. This means the following frames will be received: - - - unicast packets with the address of the adapter - - multicast packets - - broadcast packets - - beacons and probe requests - - The main reason to turn monitor mode off is that, when not in monitor mode, the adapter will acknowledge the - data frames sent to its address. This is useful when the adapter needs to interact with other devices on the - 802.11 network, bacause handling the ACKs in software is too slow. - - \note When an adapter is plugged into the system, it's always configured with monitor mode ON. The monitor mode - configuration is not stored persistently, so if you want to turn monitor mode off, you will need to do it - every time you open the adapter. -*/ -BOOL AirpcapSetMonitorMode(PAirpcapHandle AdapterHandle, BOOL MonitorModeEnabled); - -/*! - \brief Returns TRUE if the specified adapter is in monitor mode. - \param AdapterHandle Handle to the adapter. - \param PMonitorModeEnabled User-provided variable that will be set to true if the adapter is in monitor mode. - \return TRUE if the operation is successful. FALSE otherwise. - - \note When an adapter is plugged into the system, it's always configured with monitor mode ON. The monitor mode - configuration is not stored persistently, so if you want to turn monitor mode off, you will need to do it - every time you open the adapter. -*/ -BOOL AirpcapGetMonitorMode(PAirpcapHandle AdapterHandle, PBOOL PMonitorModeEnabled); - -/*! - \brief Set the link type of an adapter - \param AdapterHandle Handle to the adapter. - \param NewLinkType the "link type", i.e. the format of the frames that will be received from the adapter. - \return TRUE on success. - - the "link type" determines how the driver will encode the packets captured from the network. - Aircap supports two link types: - - \ref AIRPCAP_LT_802_11, to capture 802.11 frames (including control frames) without any - power information. Look at the Capture_no_radio example application in the developer's pack - for a reference on how to decode 802.11 frames with this link type. - - \ref AIRPCAP_LT_802_11_PLUS_RADIO, to capture 802.11 frames (including control frames) with a radiotap header - that contains power and channel information. More information about the radiotap header can be found in the - \ref radiotap section. Moreover, the "Capture_radio" example application in - the developer's pack can be used as a reference on how to decode 802.11 frames with radiotap headers. - - \ref AIRPCAP_LT_802_11_PLUS_PPI, to capture 802.11 frames (including control frames) with a Per Packet Information (PPI) - header that contains per-packet meta information like channel and power information. More details on the PPI header can - be founf in the PPI online documentation (TODO). -*/ -BOOL AirpcapSetLinkType(PAirpcapHandle AdapterHandle, AirpcapLinkType NewLinkType); - -/*! - \brief Get the link type of the specified adapter - \param AdapterHandle Handle to the adapter. - \param PLinkType Pointer to a caller allocated AirpcapLinkType variable that will contain the link type of the adapter. - \return TRUE on success. - - the "link type" determines how the driver will encode the packets captured from the network. - Aircap supports two link types: - - AIRPCAP_LT_802_11, to capture 802.11 frames (including control frames) without any - power information. Look at the Capture_no_radio example application in the developer's pack - for a reference on how to decode 802.11 frames with this link type. - - AIRPCAP_LT_802_11_PLUS_RADIO, to capture 802.11 frames (including control frames) with a radiotap header - that contains power and channel information. More information about the radiotap header can be found int the - \ref radiotap section. Moreover, the "Capture_radio" example application in - the developer's pack can be used as a reference on how to decode 802.11 frames with radiotap headers. -*/ -BOOL AirpcapGetLinkType(PAirpcapHandle AdapterHandle, PAirpcapLinkType PLinkType); - -/*! - \brief Configures the adapter on whether to include the MAC Frame Check Sequence in the captured packets. - \param AdapterHandle Handle to the adapter. - \param IsFcsPresent TRUE if the packets should include the FCS. FALSE otherwise - \return TRUE on success. - - In the default configuration, the adapter includes the FCS in the captured packets. The MAC Frame Check Sequence - is 4 bytes and is located at the end of the 802.11 packet, with both AIRPCAP_LT_802_11 and AIRPCAP_LT_802_11_PLUS_RADIO - link types. - When the FCS inclusion is turned on, and if the link type is AIRPCAP_LT_802_11_PLUS_RADIO, the radiotap header - that precedes each frame has two additional fields at the end: Padding and FCS. These two fields are not present - when FCS inclusion is off. -*/ -BOOL AirpcapSetFcsPresence(PAirpcapHandle AdapterHandle, BOOL IsFcsPresent); - -/*! - \brief Returns TRUE if the specified adapter includes the MAC Frame Check Sequence in the captured packets - \param AdapterHandle Handle to the adapter. - \param PIsFcsPresent User-provided variable that will be set to true if the adapter is including the FCS. - \return TRUE if the operation is successful. FALSE otherwise. - - In the default configuration, the adatper has FCS inclusion turned on. The MAC Frame Check Sequence is 4 bytes - and is located at the end of the 802.11 packet, with both AIRPCAP_LT_802_11 and AIRPCAP_LT_802_11_PLUS_RADIO - link types. - When the FCS inclusion is turned on, and if the link type is AIRPCAP_LT_802_11_PLUS_RADIO, the radiotap header - that precedes each frame has two additional fields at the end: Padding and FCS. These two fields are not present - when FCS inclusion is off. -*/ -BOOL AirpcapGetFcsPresence(PAirpcapHandle AdapterHandle, PBOOL PIsFcsPresent); - -/*! - \brief Configures the adapter to accept or drop frames with an incorrect Frame Check sequence (FCS). - \param AdapterHandle Handle to the adapter. - \param ValidationType The type of validation the driver will perform. See the documentation of \ref AirpcapValidationType for details. - \return TRUE on success. - - \note By default, the driver is configured in \ref AIRPCAP_VT_ACCEPT_EVERYTHING mode. -*/ -BOOL AirpcapSetFcsValidation(PAirpcapHandle AdapterHandle, AirpcapValidationType ValidationType); - -/*! - \brief Checks if the specified adapter is configured to capture frames with incorrect an incorrect Frame Check Sequence (FCS). - \param AdapterHandle Handle to the adapter. - \param ValidationType Pointer to a user supplied variable that will contain the type of validation the driver will perform. See the documentation of \ref AirpcapValidationType for details. - \return TRUE if the operation is succesful. FALSE otherwise. - - \note By default, the driver is configured in \ref AIRPCAP_VT_ACCEPT_EVERYTHING mode. -*/ -BOOL AirpcapGetFcsValidation(PAirpcapHandle AdapterHandle, PAirpcapValidationType ValidationType); - -/*! - \brief Set the list of decryption keys that the driver is going to use with the specified device. - \param AdapterHandle Handle an open adapter instance. - \param KeysCollection Pointer to a \ref PAirpcapKeysCollection structure that contains the keys to be set in the driver. - \return TRUE if the operation is successful. FALSE otherwise. - - The AirPcap driver is able to use a set of decryption keys to decrypt the traffic transmitted on a specific SSID. If one of the - keys corresponds to the one the frame has been encrypted with, the driver will perform decryption and return the cleartext frames - to the application. - - This function allows to set the adapter-specific set of keys. These keys will be used by the specified adapter only, - and will not be used by other airpcap devices besides the specified one. - - At this time, the only supported decryption method is WEP. - - The keys are applied to the packets in the same order they appear in the KeysCollection structure until the packet is - correctly decrypted, therefore putting frequently used keys at the beginning of the structure improves performance. - - \note: when you change the set of keys from an open capture instance, the change will be - immediately reflected on all the other capture instances. -*/ -BOOL AirpcapSetDeviceKeys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection); - -/*! - \brief Returns the list of decryption keys in the driver that are currently associated with the specified device - \param AdapterHandle Handle to an open adapter instance. - \param KeysCollection User-allocated PAirpcapKeysCollection structure that will be filled with the keys. - \param PKeysCollectionSize \b IN: pointer to a user-allocated variable that contains the length of the KeysCollection structure, in bytes. - \b OUT: amount of data moved by the driver in the buffer pointed by KeysBuffer, in bytes. - \return TRUE if the operation is succesful. If an error occurs, the return value is FALSE and KeysCollectionSize is zero. - If the provided buffer is too small to contain the keys, the return value is FALSE and KeysCollectionSize contains the - needed KeysCollection length, in bytes. If the device doesn't have any decryption key configured, the return value is TRUE, and - KeysCollectionSize will be zero. - - This function returns the adapter-specific set of keys. These keys are used by the specified adapter only, - and not by other airpcap devices besides the specified one. - - The AirPcap driver is able to use a set of decryption keys to decrypt the traffic transmitted on a specific SSID. If one of the - keys corresponds to the one the frame has been encrypted with, the driver will perform decryption and return the cleartext frames - to the application. - The driver supports, for every device, multiple keys at the same time. - - The configured decryption keys are device-specific, therefore AirpcapGetDeviceKeys() will return a different set of keys - when called on different devices. - - At this time, the only supported decryption method is WEP. -*/ -BOOL AirpcapGetDeviceKeys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, PUINT PKeysCollectionSize); - -/*! - \brief Set the global list of decryption keys that the driver is going to use with all the devices. - \param AdapterHandle Handle an open adapter instance. - \param KeysCollection Pointer to a \ref PAirpcapKeysCollection structure that contains the keys to be set in the driver. - \return TRUE if the operation is successful. FALSE otherwise. - - The AirPcap driver is able to use a set of decryption keys to decrypt the traffic transmitted on a specific SSID. If one of the - keys corresponds to the one the frame has been encrypted with, the driver will perform decryption and return the cleartext frames - to the application. - - This function allows to set the global driver set of keys. These keys will be used by all the adapters plugged in - the machine. - - At this time, the only supported decryption method is WEP. - - The keys are applied to the packets in the same order they appear in the KeysCollection structure until the packet is - correctly decrypted, therefore putting frequently used keys at the beginning of the structure improves performance. - - \note: when you change the set of keys from an open capture instance, the change will be - immediately reflected on all the other capture instances. -*/ -BOOL AirpcapSetDriverKeys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection); - -/*! - \brief Returns the global list of decryption keys in the driver that are associated with all the devices. - \param AdapterHandle Handle to an open adapter instance. - \param KeysCollection User-allocated PAirpcapKeysCollection structure that will be filled with the keys. - \param PKeysCollectionSize \b IN: pointer to a user-allocated variable that contains the length of the KeysCollection structure, in bytes. - \b OUT: amount of data moved by the driver in the buffer pointed by KeysBuffer, in bytes. - \return TRUE if the operation is succesful. If an error occurs, the return value is FALSE and KeysCollectionSize is zero. - If the provided buffer is too small to contain the keys, the return value is FALSE and KeysCollectionSize contains the - needed KeysCollection length, in bytes. If the device doesn't have any decryption key configured, the return value is TRUE, and - KeysCollectionSize will be zero. - - This function returns the global driver set of keys. These keys will be used by all the adapters plugged in - the machine. - - The AirPcap driver is able to use a set of decryption keys to decrypt the traffic transmitted on a specific SSID. If one of the - keys corresponds to the one the frame has been encrypted with, the driver will perform decryption and return the cleartext frames - to the application. - - At this time, the only supported decryption method is WEP. -*/ -BOOL AirpcapGetDriverKeys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, PUINT PKeysCollectionSize); - -/*! - \brief Turns on or off the decryption of the incoming frames with the adapter-specific keys. - \param AdapterHandle Handle to the adapter. - \param Enable Either \ref AIRPCAP_DECRYPTION_ON or \ref AIRPCAP_DECRYPTION_OFF - \return TRUE on success. - - The adapter-specific decryption keys can be configured with the \ref AirpcapSetDeviceKeys() function. - \note By default, the driver is configured with \ref AIRPCAP_DECRYPTION_ON. -*/ -BOOL AirpcapSetDecryptionState(PAirpcapHandle AdapterHandle, AirpcapDecryptionState Enable); - -/*! - \brief Tells if this open instance is configured to perform the decryption of the incoming frames with the adapter-specific keys. - \param AdapterHandle Handle to the adapter. - \param PEnable Pointer to a user supplied variable that will contain the decryption configuration. See \ref PAirpcapDecryptionState for details. - \return TRUE if the operation is succesful. FALSE otherwise. - - The adapter-specific decryption keys can be configured with the \ref AirpcapSetDeviceKeys() function. - \note By default, the driver is configured with \ref AIRPCAP_DECRYPTION_ON. -*/ -BOOL AirpcapGetDecryptionState(PAirpcapHandle AdapterHandle, PAirpcapDecryptionState PEnable); - -/*! - \brief Turns on or off the decryption of the incoming frames with the global driver set of keys. - \param AdapterHandle Handle to the adapter. - \param Enable Either \ref AIRPCAP_DECRYPTION_ON or \ref AIRPCAP_DECRYPTION_OFF - \return TRUE on success. - - The global decryption keys can be configured with the \ref AirpcapSetDriverKeys() function. - \note By default, the driver is configured with \ref AIRPCAP_DECRYPTION_ON. -*/ -BOOL AirpcapSetDriverDecryptionState(PAirpcapHandle AdapterHandle, AirpcapDecryptionState Enable); - -/*! - \brief Tells if this open instance is configured to perform the decryption of the incoming frames with the global driver set of keys. - \param AdapterHandle Handle to the adapter. - \param PEnable Pointer to a user supplied variable that will contain the decryption configuration. See \ref PAirpcapDecryptionState for details. - \return TRUE if the operation is succesful. FALSE otherwise. - - The global decryption keys can be configured with the \ref AirpcapSetDriverKeys() function. - \note By default, the driver is configured with \ref AIRPCAP_DECRYPTION_ON. -*/ -BOOL AirpcapGetDriverDecryptionState(PAirpcapHandle AdapterHandle, PAirpcapDecryptionState PEnable); - -/*! - \brief Set the radio channel of a device - \param AdapterHandle Handle to the adapter. - \param Channel the new channel to set. - \return TRUE on success. - - The list of available channels can be retrieved with \ref AirpcapGetDeviceSupportedChannels(). The default channel setting is 6. - - \note this is a device-related function: when you change the channel from an open capture instance, the change will be - immediately reflected on all the other capture instances. -*/ -BOOL AirpcapSetDeviceChannel(PAirpcapHandle AdapterHandle, UINT Channel); - -/*! - \brief Get the radio channel of a device - \param AdapterHandle Handle to the adapter. - \param PChannel Pointer to a user-supplied variable into which the function will copy the currently configured radio channel. - \return TRUE on success. - - The list of available channels can be retrieved with \ref AirpcapGetDeviceSupportedChannels(). The default channel setting is 6. - - \note this is a device-related function: when you change the channel from an open capture instance, the change will be - immediately reflected on all the other capture instances. -*/ -BOOL AirpcapGetDeviceChannel(PAirpcapHandle AdapterHandle, PUINT PChannel); - -/*! - \brief Set the size of the kernel packet buffer for this adapter - \param AdapterHandle Handle to the adapter. - \param BufferSize New size, in bytes. - \return TRUE on success. - - Every AirPcap open instance has an associated kernel buffer, whose default size is 1 Mbyte. - This function can be used to change the size of this buffer, and can be called at any time. - A bigger kernel buffer size decreases the risk of dropping packets during network bursts or when the - application is busy, at the cost of higher kernel memory usage. - - \note don't use this function unless you know what you are doing. Due to caching issues and bigger non-paged - memory consumption, bigger buffer sizes can decrease the capture performace instead of improving it. -*/ -BOOL AirpcapSetKernelBuffer(PAirpcapHandle AdapterHandle, UINT BufferSize); - -/*! - \brief Get the size of the kernel packet buffer for this adapter - \param AdapterHandle Handle to the adapter. - \param PSizeBytes User-allocated variable that will be filled with the size of the kernel buffer. - \return TRUE on success. - - Every AirPcap open instance has an associated kernel buffer, whose default size is 1 Mbyte. - This function can be used to get the size of this buffer. -*/ -BOOL AirpcapGetKernelBufferSize(PAirpcapHandle AdapterHandle, PUINT PSizeBytes); - -/*! - \brief Saves the configuration of the specified adapter in the registry, so that it becomes the default for this adapter. - \param AdapterHandle Handle to the adapter. - \return TRUE on success. FALSE on failure. - - Almost all the AirPcap calls that modify the configuration (\ref AirpcapSetLinkType(), \ref AirpcapSetFcsPresence(), - \ref AirpcapSetFcsValidation(), \ref AirpcapSetKernelBuffer(), \ref AirpcapSetMinToCopy()) - affect only the referenced AirPcap open instance. This means that if you do another \ref AirpcapOpen() on the same - adapter, the configuration changes will not be remembered, and the new adapter handle will have default configuration - settings. - - Exceptions to this rule are the \ref AirpcapSetDeviceChannel() and \ref AirpcapSetDeviceKeys() functions: a channel change is - reflected on all the open instances, and remembered until the next call to \ref AirpcapSetDeviceChannel(), until the adapter - is unplugged, or until the machine is powered off. Same thing for the configuration of the WEP keys. - - AirpcapStoreCurConfigAsAdapterDefault() stores the configuration of the give open instance as the default for the adapter: - all the instances opened in the future will have the same configuration that this adapter currently has. - The configuration is stored in the registry, therefore it is remembered even when the adapter is unplugged or the - machine is turned off. However, an adapter doesn't bring its configuration with it from machine to machine. - - the configuration information saved in the registry includes the following parameters: - - channel - - kernel buffer size - - mintocopy - - link type - - CRC presence - - Encryption keys - - Encryption Enabled/Disabled state - - The configuration is adapter-specific. This means that changing the configuration of an adapter - doesn't modify the one of the other adapters that are currently used or that will be used in the future. - - \note AirpcapStoreCurConfigAsAdapterDefault() must have exclusive access to the adapter -- it - will fail if more than one AirPcap handle is opened at the same time for this adapter. - AirpcapStoreCurConfigAsAdapterDefault() needs administrator privileges. It will fail if the calling user - is not a local machine administrator. -*/ -BOOL AirpcapStoreCurConfigAsAdapterDefault(PAirpcapHandle AdapterHandle); - -/*! - \brief Set the BPF kernel filter for an adapter - \param AdapterHandle Handle to the adapter. - \param Instructions pointer to the first BPF instruction in the array. Corresponds to the bf_insns - in a bpf_program structure (see the WinPcap documentation at http://www.winpcap.org/devel.htm). - \param Len Number of instructions in the array pointed by the previous field. Corresponds to the bf_len in - a a bpf_program structure (see the WinPcap documentation at http://www.winpcap.org/devel.htm). - \return TRUE on success. - - The AirPcap driver is able to perform kernel-level filtering using the standard BPF pseudo-machine format. You can read - the WinPcap documentation at http://www.winpcap.org/devel.htm for more details on the BPF filtering mechaism. - - A filter can be automatically created by using the pcap_compile() function of the WinPcap API. This function - converts a human readable text expression with the tcpdump/libpcap syntax into a BPF program. - If your program doesn't link wpcap, but you need to generate the code for a particular filter, you can run WinDump - with the -d or -dd or -ddd flags to obtain the pseudocode. - -*/ -BOOL AirpcapSetFilter(PAirpcapHandle AdapterHandle, PVOID Instructions, UINT Len); - -/*! - \brief Return the MAC address of an adapter. - \param AdapterHandle Handle to the adapter. - \param PMacAddress Pointer to a user allocated MAC address. - The size of this buffer needs to be at least 6 bytes. - \return TRUE on success. -*/ -BOOL AirpcapGetMacAddress(PAirpcapHandle AdapterHandle, PAirpcapMacAddress PMacAddress); - -/*! - \brief Set the mintocopy parameter for an open adapter - \param AdapterHandle Handle to the adapter. - \param MinToCopy is the mintocopy size in bytes. - \return TRUE on success. - - When the number of bytes in the kernel buffer changes from less than mintocopy bytes to greater than or equal to mintocopy bytes, - the read event is signalled (see \ref AirpcapGetReadEvent()). A high value for mintocopy results in poor responsiveness since the - driver may signal the application "long" after the arrival of the packet. And a high value results in low CPU loading - by minimizing the number of user/kernel context switches. - A low MinToCopy results in good responsiveness since the driver will signal the application close to the arrival time of - the packet. This has higher CPU loading over the first approach. -*/ -BOOL AirpcapSetMinToCopy(PAirpcapHandle AdapterHandle, UINT MinToCopy); - -/*! - \brief Gets an event that is signaled when that is signalled when packets are available in the kernel buffer (see \ref AirpcapSetMinToCopy()). - \param AdapterHandle Handle to the adapter. - \param PReadEvent Pointer to a user-supplied handle that in which the read event will be copied. - \return TRUE on success. - - \note the event is signalled when at least mintocopy bytes are present in the kernel buffer (see \ref AirpcapSetMinToCopy()). - This event can be used by WaitForSingleObject() and WaitForMultipleObjects() to create blocking behavior when reading - packets from one or more adapters (see \ref AirpcapRead()). -*/ -BOOL AirpcapGetReadEvent(PAirpcapHandle AdapterHandle, HANDLE* PReadEvent); - -/*! - \brief Fills a user-provided buffer with zero or more packets that have been captured on the referenced adapter. - \param AdapterHandle Handle to the adapter. - \param Buffer pointer to the buffer that will be filled with captured packets. - \param BufSize size of the input buffer that will contain the packets, in bytes. - \param PReceievedBytes Pointer to a user supplied variable that will receive the number of bytes copied by AirpcapRead. - Can be smaller than BufSize. - \return TRUE on success. - - 802.11 frames are returned by the driver in buffers. Every 802.11 frame in the buffer is preceded by a \ref AirpcapBpfHeader structure. - The suggested way to use an AirPcap adapter is through the pcap API exported by wpcap.dll. If this is not - possible, the Capture_radio and Capture_no_radio examples in the AirPcap developer's pack show how to properly decode the - packets in the read buffer returned by AirpcapRead(). - - \note this function is NOT blocking. Blocking behavior can be obtained using the event returned - by \ref AirpcapGetReadEvent(). See also \ref AirpcapSetMinToCopy(). -*/ -BOOL AirpcapRead(PAirpcapHandle AdapterHandle, PBYTE Buffer, UINT BufSize, PUINT PReceievedBytes); - -/*! - \brief Transmits a packet. - \param AdapterHandle Handle to the adapter. - \param TxPacket Pointer to a buffer that contains the packet to be transmitted. - \param PacketLen Length of the buffer pointed by the TxPacket argument, in bytes. - \return TRUE on success. - - The packet will be transmitted on the channel the device is currently set. To change the device adapter, use the - \ref AirpcapSetDeviceChannel() function. - - If the linktype of the adapter is AIRPCAP_LT_802_11, the buffer pointed by TxPacket should contain just the 802.11 - packet, without additional information. The packet will be transmitted at 1Mbps. - - If the linktype of the adapter is AIRPCAP_LT_802_11_PLUS_RADIO, the buffer pointed by TxPacket should contain a radiotap - header followed by the 802.11 packet. AirpcapWrite will use the rate information in the radiotap header when - transmitting the packet. -*/ -BOOL AirpcapWrite(PAirpcapHandle AdapterHandle, PCHAR TxPacket, ULONG PacketLen); - -/*! - \brief Get per-adapter WinPcap-compatible capture statistics. - \param AdapterHandle Handle to the adapter. - \param PStats pointer to a user-allocated AirpcapStats structure that will be filled with statistical information. - \return TRUE on success. -*/ -BOOL AirpcapGetStats(PAirpcapHandle AdapterHandle, PAirpcapStats PStats); - -/*! - \brief Get the number of LEDs the referenced adapter has available. - \param AdapterHandle Handle to the adapter. - \param NumberOfLeds Number of LEDs available on this adapter. - \return TRUE on success. -*/ -BOOL AirpcapGetLedsNumber(PAirpcapHandle AdapterHandle, PUINT NumberOfLeds); - -/*! - \brief Turn on one of the adapter's LEDs. - \param AdapterHandle Handle to the adapter. - \param LedNumber zero-based identifier of the LED to turn on. - \return TRUE on success. -*/ -BOOL AirpcapTurnLedOn(PAirpcapHandle AdapterHandle, UINT LedNumber); - -/*! - \brief Turn off one of the adapter's LEDs. - \param AdapterHandle Handle to the adapter. - \param LedNumber zero-based identifier of the LED to turn off. - \return TRUE on success. -*/ -BOOL AirpcapTurnLedOff(PAirpcapHandle AdapterHandle, UINT LedNumber); - -/*! - \brief Set the channel of a device through its radio frequency. In case of 802.11n enabled devices, it sets the extension channel, if used. - \param AdapterHandle Handle to the adapter. - \param ChannelInfo The new channel information to set. - \return TRUE on success. - - \note this is a device-related function: when you change the channel from an open capture instance, the change will be - immediately reflected on all the other capture instances. -*/ -BOOL AirpcapSetDeviceChannelEx(PAirpcapHandle AdapterHandle, AirpcapChannelInfo ChannelInfo); - -/*! - \brief Get the channel of a device through its radiofrequency. In case of 802.11n enabled devices, it gets the extension channel, if in use. - \param AdapterHandle Handle to the adapter. - \param PChannelInfo Pointer to a user-supplied variable into which the function will copy the currently configured channel information. - \return TRUE on success. - - \note this is a device-related function: when you change the channel from an open capture instance, the change will be - immediately reflected on all the other capture instances. -*/ -BOOL AirpcapGetDeviceChannelEx(PAirpcapHandle AdapterHandle, PAirpcapChannelInfo PChannelInfo); - -/*! - \brief Get the list of supported channels for a given device. In case of a 802.11n capable device, information related to supported extension channels is also reported. - - Every control channel is listed multiple times, one for each different supported extension channel. For example channel 6 (2437MHz) is usually listed three times: - - Frequency 2437 Extension +1. Control channel is 6, extension channel is 10. - - Frequency 2437 Extension 0. Control channel is 6, no extension channel is used (20MHz channel and legacy mode). - - Frequency 2437 Extension -1. Control channel is 6, extension channel is 2. - \param AdapterHandle Handle to the adapter. - \param ppChannelInfo Pointer to a user-supplied variable that will point to an array of supported channel. Such list must not be freed by the caller - \param pNumChannelInfo Number of channels returned in the array. - \return TRUE on success. - - \note The supported channels are not listed in any specific order. -*/ -BOOL AirpcapGetDeviceSupportedChannels(PAirpcapHandle AdapterHandle, PAirpcapChannelInfo *ppChannelInfo, PUINT pNumChannelInfo); - -/*! - \brief Converts a given frequency to the corresponding channel. - - \param Frequency Frequency of the channel, in MHz. - \param PChannel Pointer to a user-supplied variable that will contain the channel number on success. - \param PBand Pointer to a user-supplied variable that will contain the band (a or b/g) of the given channel. - \return TRUE on success, i.e. the frequency corresponds to a valid a or b/g channel. -*/ -BOOL AirpcapConvertFrequencyToChannel(UINT Frequency, PUINT PChannel, PAirpcapChannelBand PBand); - -/*! - \brief Converts a given channel to the corresponding frequency. - - \param Channel Channel number to be converted. - \param PFrequency Pointer to a user-supplied variable that will contain the channel frequency in MHz on success. - \return TRUE on success, i.e. the given channel number exists. -*/ -BOOL AirpcapConvertChannelToFrequency(UINT Channel, PUINT PFrequency); - - -/*@}*/ - -#endif // __AIRPCAP_DRIVER__ - -#ifdef __cplusplus -} -#endif - -#endif // !defined(AIRPCAP_H__EAE405F5_0171_9592_B3C2_C19EC426AD34__INCLUDED_) diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/airpcap_loader.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/airpcap_loader.h deleted file mode 100644 index df35b0eb..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/airpcap_loader.h +++ /dev/null @@ -1,560 +0,0 @@ -/* airpcap_loader.h - * Declarations of routines for the "About" dialog - * - * $Id: airpcap_loader.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Giorgio Tino - * Copyright (c) CACE Technologies, LLC 2006 - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __AIRPCAP_LOADER_H__ -#define __AIRPCAP_LOADER_H__ - -#include - -/* Error values from "get_airpcap_interface_list()". */ -#define CANT_GET_AIRPCAP_INTERFACE_LIST 0 /* error getting list */ -#define NO_AIRPCAP_INTERFACES_FOUND 1 /* list is empty */ -#define AIRPCAP_NOT_LOADED 2 /* Airpcap DLL not loaded */ - -#define AIRPCAP_CHANNEL_ANY_NAME "ANY" - -#define AIRPCAP_WEP_KEY_STRING "WEP" -/* - * XXX - WPA_PWD is the passphrase+ssid and WPA-PSK is the hexadecimal key - */ -#define AIRPCAP_WPA_PWD_KEY_STRING "WPA-PWD" -#define AIRPCAP_WPA_BIN_KEY_STRING "WPA-PSK" - -#define AIRPCAP_DLL_OK 0 -#define AIRPCAP_DLL_OLD 1 -#define AIRPCAP_DLL_ERROR 2 -#define AIRPCAP_DLL_NOT_FOUND 3 - -typedef PCHAR (*AirpcapGetLastErrorHandler)(PAirpcapHandle AdapterHandle); -typedef BOOL (*AirpcapGetDeviceListHandler)(PAirpcapDeviceDescription *PPAllDevs, PCHAR Ebuf); -typedef VOID (*AirpcapFreeDeviceListHandler)(PAirpcapDeviceDescription PAllDevs); -typedef PAirpcapHandle (*AirpcapOpenHandler)(PCHAR DeviceName, PCHAR Ebuf); -typedef VOID (*AirpcapCloseHandler)(PAirpcapHandle AdapterHandle); -typedef BOOL (*AirpcapGetLinkTypeHandler)(PAirpcapHandle AdapterHandle, PAirpcapLinkType PLinkType); -typedef BOOL (*AirpcapSetLinkTypeHandler)(PAirpcapHandle AdapterHandle, AirpcapLinkType NewLinkType); -typedef BOOL (*AirpcapSetKernelBufferHandler)(PAirpcapHandle AdapterHandle, UINT BufferSize); -typedef BOOL (*AirpcapSetFilterHandler)(PAirpcapHandle AdapterHandle, PVOID Instructions, UINT Len); -typedef BOOL (*AirpcapGetMacAddressHandler)(PAirpcapHandle AdapterHandle, PAirpcapMacAddress PMacAddress); -typedef BOOL (*AirpcapSetMinToCopyHandler)(PAirpcapHandle AdapterHandle, UINT MinToCopy); -typedef BOOL (*AirpcapGetReadEventHandler)(PAirpcapHandle AdapterHandle, HANDLE* PReadEvent); -typedef BOOL (*AirpcapReadHandler)(PAirpcapHandle AdapterHandle, PBYTE Buffer, UINT BufSize, PUINT PReceievedBytes); -typedef BOOL (*AirpcapGetStatsHandler)(PAirpcapHandle AdapterHandle, PAirpcapStats PStats); -typedef BOOL (*AirpcapTurnLedOnHandler)(PAirpcapHandle AdapterHandle, UINT LedNumber); -typedef BOOL (*AirpcapTurnLedOffHandler)(PAirpcapHandle AdapterHandle, UINT LedNumber); -typedef BOOL (*AirpcapSetDeviceChannelHandler)(PAirpcapHandle AdapterHandle, UINT Channel); -typedef BOOL (*AirpcapGetDeviceChannelHandler)(PAirpcapHandle AdapterHandle, PUINT PChannel); -typedef BOOL (*AirpcapSetFcsPresenceHandler)(PAirpcapHandle AdapterHandle, BOOL IsFcsPresent); -typedef BOOL (*AirpcapGetFcsPresenceHandler)(PAirpcapHandle AdapterHandle, PBOOL PIsFcsPresent); -typedef BOOL (*AirpcapSetFcsValidationHandler)(PAirpcapHandle AdapterHandle, AirpcapValidationType ValidationType); -typedef BOOL (*AirpcapGetFcsValidationHandler)(PAirpcapHandle AdapterHandle, PAirpcapValidationType PValidationType); -typedef BOOL (*AirpcapSetDeviceKeysHandler)(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection); -typedef BOOL (*AirpcapGetDeviceKeysHandler)(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, PUINT PKeysCollectionSize); -typedef BOOL (*AirpcapSetDriverKeysHandler)(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection); -typedef BOOL (*AirpcapGetDriverKeysHandler)(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, PUINT PKeysCollectionSize); -typedef BOOL (*AirpcapSetDecryptionStateHandler)(PAirpcapHandle AdapterHandle, AirpcapDecryptionState Enable); -typedef BOOL (*AirpcapGetDecryptionStateHandler)(PAirpcapHandle AdapterHandle, PAirpcapDecryptionState PEnable); -typedef BOOL (*AirpcapSetDriverDecryptionStateHandler)(PAirpcapHandle AdapterHandle, AirpcapDecryptionState Enable); -typedef BOOL (*AirpcapGetDriverDecryptionStateHandler)(PAirpcapHandle AdapterHandle, PAirpcapDecryptionState PEnable); -typedef BOOL (*AirpcapStoreCurConfigAsAdapterDefaultHandler)(PAirpcapHandle AdapterHandle); -typedef VOID (*AirpcapGetVersionHandler)(PUINT VersionMajor, PUINT VersionMinor, PUINT VersionRev, PUINT VersionBuild); -typedef BOOL (*AirpcapSetDeviceChannelExHandler)(PAirpcapHandle AdapterHandle, AirpcapChannelInfo ChannelInfo); -typedef BOOL (*AirpcapGetDeviceChannelExHandler)(PAirpcapHandle AdapterHandle, PAirpcapChannelInfo PChannelInfo); -typedef BOOL (*AirpcapGetDeviceSupportedChannelsHandler)(PAirpcapHandle AdapterHandle, AirpcapChannelInfo **ppChannelInfo, PULONG pNumChannelInfo); - -#define FLAG_CAN_BE_LOW 0x00000001 -#define FLAG_CAN_BE_HIGH 0x00000002 -#define FLAG_IS_BG_CHANNEL 0x00000004 -#define FLAG_IS_A_CHANNEL 0x00000008 - -typedef struct _Dot11Channel -{ - UINT Channel; - ULONG Frequency; - ULONG Flags; -} Dot11Channel; - -/* - * The list of interfaces returned by "get_airpcap_interface_list()" is - * a list of these structures. - */ -typedef struct { - char *name; /* e.g. "eth0" */ - char *description; /* from OS, e.g. "Local Area Connection" or NULL */ - GSList *ip_addr; /* containing address values of if_addr_t */ - gboolean loopback; /* TRUE if loopback, FALSE otherwise */ - AirpcapLinkType linkType; /* The link layer type */ - AirpcapChannelInfo channelInfo; /* Channel Information */ - BOOL IsFcsPresent; /* Include 802.11 CRC in frames */ - AirpcapValidationType CrcValidationOn; /* Capture Frames with Wrong CRC */ - AirpcapDecryptionState DecryptionOn; /* TRUE if decryption is on, FALSE otherwise */ - PAirpcapKeysCollection keysCollection; /* WEP Key collection for the adapter */ - UINT keysCollectionSize; /* Size of the key collection */ - gboolean blinking; /* TRUE if is blinkng, FALSE otherwise */ - gboolean led; /* TRUE if on, FALSE if off */ - gboolean saved; /* TRUE if current configuration has been saved, FALSE otherwise */ - gint tag; /* int for the gtk blinking callback */ - Dot11Channel *pSupportedChannels; - ULONG numSupportedChannels; -} airpcap_if_info_t; - -/* - * Struct used to store infos to pass to the preferences manager callbacks - */ -typedef struct { - GList *list; - int current_index; - int number_of_keys; -} keys_cb_data_t; - -/* Airpcap interface list */ -extern GList *airpcap_if_list; - -/* Airpcap current selected interface */ -extern airpcap_if_info_t *airpcap_if_selected; - -/* Airpcap current active interface */ -extern airpcap_if_info_t *airpcap_if_active; - -/* WLAN preferences pointer */ -/*extern module_t *wlan_prefs; - TODO: What is this?? */ - -/* - * Function used to read the Decryption Keys from the preferences and store them - * properly into the airpcap adapter. - */ -BOOL -load_wlan_driver_wep_keys(); - -/* - * Function used to save to the prefereces file the Decryption Keys. - */ -BOOL -save_wlan_wep_keys(airpcap_if_info_t* info_if); - -/* - * This function will tell the airpcap driver the key list to use - * This will be stored into the registry... - */ -gboolean -write_wlan_wep_keys_to_registry(airpcap_if_info_t* info_if, GList* key_list); - -/* Returs TRUE if the WEP key is valid, false otherwise */ -gboolean -wep_key_is_valid(char* key); - -/* - * Callback used to free an instance of airpcap_if_info_t - */ -static void -free_airpcap_if_cb(gpointer data, gpointer user_data _U_); - -/* - * USED FOR DEBUG ONLY... PRINTS AN AirPcap ADAPTER STRUCTURE in a fancy way. - */ -void -airpcap_if_info_print(airpcap_if_info_t* if_info); - -/* - * Used to retrieve the two chars string from interface - */ -gchar* -airpcap_get_if_string_number_from_description(gchar* description); - -/* - * Function used to free the airpcap interface list - */ -void -free_airpcap_interface_list(GList *if_list); - -/* - * Used to retrieve the interface given the name - * (the name is used in AirpcapOpen) - */ -airpcap_if_info_t* get_airpcap_if_from_name(GList* if_list, const gchar* name); - -/* - * Airpcap wrapper, used to store the current settings for the selected adapter - */ -BOOL -airpcap_if_store_cur_config_as_adapter_default(PAirpcapHandle ah); - -/* - * Function used to load the WEP keys for a selected interface - */ -BOOL -airpcap_if_load_keys(PAirpcapHandle ad, airpcap_if_info_t *if_info); - -/* - * Function used to load the WEP keys from the global driver list - */ -BOOL -airpcap_if_load_driver_keys(PAirpcapHandle ad, airpcap_if_info_t *if_info); - -/* - * Function used to save the WEP keys for a selected interface - */ -void -airpcap_if_save_keys(PAirpcapHandle ad, airpcap_if_info_t *if_info); - -/* - * Function used to save the WEP keys for a selected interface - */ -void -airpcap_if_save_driver_keys(PAirpcapHandle ad, airpcap_if_info_t *if_info); - -/* - * Airpcap wrapper, used to get the fcs validation of an airpcap adapter - */ -BOOL -airpcap_if_get_fcs_validation(PAirpcapHandle ah, PAirpcapValidationType val); - -/* - * Airpcap wrapper, used to set the fcs validation of an airpcap adapter - */ -BOOL -airpcap_if_set_fcs_validation(PAirpcapHandle ah, AirpcapValidationType val); - -/* - * Airpcap wrapper, used to get the decryption enabling of an airpcap adapter - */ -BOOL -airpcap_if_get_decryption_state(PAirpcapHandle ah, PAirpcapDecryptionState val); - -/* - * Airpcap wrapper, used to set the decryption enabling of an airpcap adapter - */ -BOOL -airpcap_if_set_decryption_state(PAirpcapHandle ah, AirpcapDecryptionState val); - -/* - * Airpcap wrapper, used to get the fcs presence of an airpcap adapter - */ -BOOL -airpcap_if_get_fcs_presence(PAirpcapHandle ah, PBOOL ch); - -/* - * Airpcap wrapper, used to set the fcs presence of an airpcap adapter - */ -BOOL -airpcap_if_set_fcs_presence(PAirpcapHandle ah, BOOL ch); - -/* - * Airpcap wrapper, used to get the link type of an airpcap adapter - */ -BOOL -airpcap_if_get_link_type(PAirpcapHandle ah, PAirpcapLinkType lt); - -/* - * Airpcap wrapper, used to set the link type of an airpcap adapter - */ -BOOL -airpcap_if_set_link_type(PAirpcapHandle ah, AirpcapLinkType lt); - -/* - * Airpcap wrapper, used to get the channel of an airpcap adapter - */ -BOOL -airpcap_if_get_device_channel(PAirpcapHandle ah, PUINT ch); - -/* - * Airpcap wrapper, get the channels supported by the adapter - */ -BOOL -airpcap_if_get_device_supported_channels(PAirpcapHandle ah, AirpcapChannelInfo **cInfo, PULONG nInfo); - -/* - * Airpcap wrapper, get supported channels formatted into an array - */ -Dot11Channel* -airpcap_if_get_device_supported_channels_array(PAirpcapHandle ah, PULONG pNumSupportedChannels); - -/* - * Airpcap wrapper, used to set the channel of an airpcap adapter - */ -BOOL -airpcap_if_set_device_channel(PAirpcapHandle ah, UINT ch); - -/* - * Airpcap wrapper, used to get the frequency of an airpcap adapter - */ -BOOL -airpcap_if_get_device_channel_ex(PAirpcapHandle ah, PAirpcapChannelInfo pChannelInfo); - -/* - * Airpcap wrapper, used to set the frequency of an airpcap adapter - */ -BOOL -airpcap_if_set_device_channel_ex(PAirpcapHandle ah, AirpcapChannelInfo ChannelInfo); - -/* - * Airpcap wrapper, used to open an airpcap adapter - */ -PAirpcapHandle airpcap_if_open(PCHAR name, PCHAR err); - -/* - * Airpcap wrapper, used to close an airpcap adapter - */ -VOID airpcap_if_close(PAirpcapHandle handle); - -/* - * Retrieve the state of the Airpcap DLL - */ -int -airpcap_get_dll_state(); - -/* - * Airpcap wrapper, used to turn on the led of an airpcap adapter - */ -BOOL airpcap_if_turn_led_on(PAirpcapHandle AdapterHandle, UINT LedNumber); - -/* - * Airpcap wrapper, used to turn off the led of an airpcap adapter - */ -BOOL airpcap_if_turn_led_off(PAirpcapHandle AdapterHandle, UINT LedNumber); - -/* - * This function will create a new airpcap_if_info_t using a name and a description - */ -airpcap_if_info_t* airpcap_if_info_new(char *name, char *description); - -/* - * This function will create a new fake drivers' interface, to load global keys... - */ -airpcap_if_info_t* airpcap_driver_fake_if_info_new(); - -/* - * Used to dinamically load the airpcap library in order link it only when - * it's present on the system. - */ -int load_airpcap(void); - -/* - * This function will use the airpcap.dll to find all the airpcap devices. - * Will return null if no device is found. - */ -GList* -get_airpcap_interface_list(int *err, char **err_str); - -/* - * Returns the ASCII string of a key given the key bites - */ -gchar* -airpcap_get_key_string(AirpcapKey key); - -/* - * Load the configuration for the specified interface - */ -void -airpcap_load_selected_if_configuration(airpcap_if_info_t* if_info); - -/* - * Save the configuration for the specified interface - */ -void -airpcap_save_selected_if_configuration(airpcap_if_info_t* if_info); - -/* - * Used to retrieve the two chars string from interface description - */ -gchar* -airpcap_get_if_string_number(airpcap_if_info_t* if_info); - -/* - * Returns the default airpcap interface of a list, NULL if list is empty - */ -airpcap_if_info_t* -airpcap_get_default_if(GList* airpcap_if_list); - -/* - * Airpcap wrapper, used to save the settings for the selected_if - */ -BOOL -airpcap_if_set_device_keys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection); - -/* - * Airpcap wrapper, used to save the settings for the selected_if - */ -BOOL -airpcap_if_get_device_keys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, PUINT PKeysCollectionSize); - -/* - * Airpcap wrapper, used to save the settings for the selected_if - */ -BOOL -airpcap_if_set_driver_keys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection); - -/* - * Airpcap wrapper, used to save the settings for the selected_if - */ -BOOL -airpcap_if_get_driver_keys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, PUINT PKeysCollectionSize); - -/* - * Airpcap wrapper, used to get the decryption enabling of an airpcap driver - */ -BOOL -airpcap_if_get_driver_decryption_state(PAirpcapHandle ah, PAirpcapDecryptionState PEnable); -/* - * Airpcap wrapper, used to set the decryption enabling of an airpcap driver - */ -BOOL -airpcap_if_set_driver_decryption_state(PAirpcapHandle ah, AirpcapDecryptionState Enable); - -/* - * Save the configuration for the specified interface - */ -void -airpcap_save_driver_if_configuration(airpcap_if_info_t* fake_if_info); - -/* - * Free an instance of airpcap_if_info_t - */ -void -airpcap_if_info_free(airpcap_if_info_t *if_info); - -/* - * This function will tell the airpcap driver the key list to use - * This will be stored into the registry... - */ -BOOL -write_wlan_driver_wep_keys_to_registry(GList* key_list); - -/* - * Clear keys and decryption status for the specified interface - */ -void -airpcap_if_clear_decryption_settings(airpcap_if_info_t* info_if); - -/* - * Function used to save to the preference file the Decryption Keys. - */ -int -save_wlan_driver_wep_keys(); - -/* - * Function used to save to the preference file the Decryption Keys. - */ -int -save_wlan_wireshark_wep_keys(GList* key_ls); - -/* - * DECRYPTION KEYS FUNCTIONS - */ -/* - * This function is used for DEBUG PURPOSES ONLY!!! - */ -void -print_key_list(GList* key_list); - -/* - * Retrieves a GList of decryption_key_t structures containing infos about the - * keys for the given adapter... returns NULL if no keys are found. - */ -GList* -get_airpcap_device_keys(airpcap_if_info_t* if_info); - -/* - * Retrieves a GList of decryption_key_t structures containing infos about the - * keys for the global AirPcap driver... returns NULL if no keys are found. - */ -GList* -get_airpcap_driver_keys(); - -/* - * Returns the list of the decryption keys specified for wireshark, NULL if - * no key is found - */ -GList* -get_wireshark_keys(); - -/* - * Tests if two collection of keys are equal or not, to be considered equals, they have to - * contain the same keys in the SAME ORDER! (If both lists are NULL, which means empty will - * return TRUE) - */ -gboolean -key_lists_are_equal(GList* list1, GList* list2); - -/* - * Merges two lists of keys. If a key is found multiple times, it will just appear once! - */ -GList* -merge_key_list(GList* list1, GList* list2); - -/* - * If the given key is contained in the list, returns TRUE. - * Returns FALSE otherwise. - */ -gboolean -key_is_in_list(decryption_key_t *dk,GList *list); - -/* - * Returns TRUE if keys are equals, FALSE otherwise - */ -gboolean -keys_are_equals(decryption_key_t *k1,decryption_key_t *k2); - -/* - * Use this function to free a key list. - */ -void -free_key_list(GList *list); - -/* - * Returns TRUE if the Wireshark decryption is active, FALSE otherwise - */ -gboolean -wireshark_decryption_on(); - -/* - * Returns TRUE if the AirPcap decryption for the current adapter is active, FALSE otherwise - */ -gboolean -airpcap_decryption_on(); - -/* - * Enables decryption for Wireshark if on_off is TRUE, disables it otherwise. - */ -void -set_wireshark_decryption(gboolean on_off); - -/* - * Enables decryption for all the adapters if on_off is TRUE, disables it otherwise. - */ -gboolean -set_airpcap_decryption(gboolean on_off); - -/* - * Adds compiled version string to str - */ -void -get_compiled_airpcap_version(GString *str); - -void -get_runtime_airpcap_version(GString *str); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/alert_box.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/alert_box.h deleted file mode 100644 index 62ee1efb..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/alert_box.h +++ /dev/null @@ -1,70 +0,0 @@ -/* alert_box.h - * Routines to put up various "standard" alert boxes used in multiple - * places - * - * $Id: alert_box.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __ALERT_BOX_H__ -#define __ALERT_BOX_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* - * Alert box for general errors. - */ -extern void failure_alert_box(const char *msg_format, va_list ap); - -/* - * Alert box for a failed attempt to open or create a file. - * "err" is assumed to be a UNIX-style errno; "for_writing" is TRUE if - * the file is being opened for writing and FALSE if it's being opened - * for reading. - */ -extern void open_failure_alert_box(const char *filename, int err, - gboolean for_writing); - -/* - * Alert box for a failed attempt to read a file. - * "err" is assumed to be a UNIX-style errno. - */ -extern void read_failure_alert_box(const char *filename, int err); - -/* - * Alert box for a failed attempt to write to a file. - * "err" is assumed to be a UNIX-style errno. - */ -extern void write_failure_alert_box(const char *filename, int err); - -/* - * Alert box for an invalid display filter expression. - * Assumes "dfilter_error_msg" has been set by "dfilter_compile()" to the - * error message for the filter. - */ -extern void bad_dfilter_alert_box(const char *dftext); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __ALERT_BOX_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-pcap-util-int.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-pcap-util-int.h deleted file mode 100644 index 697f2ede..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-pcap-util-int.h +++ /dev/null @@ -1,56 +0,0 @@ -/* capture-pcap-util-int.h - * Definitions of routines internal to the libpcap/WinPcap utilities - * - * $Id: capture-pcap-util-int.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __PCAP_UTIL_INT_H__ -#define __PCAP_UTIL_INT_H__ - -#ifdef HAVE_LIBPCAP -#ifdef HAVE_PCAP_REMOTE -#ifdef HAVE_CONFIG_H -#include -#endif -#include -#endif - -extern if_info_t *if_info_new(char *name, char *description); -extern void if_info_add_address(if_info_t *if_info, struct sockaddr *addr); -#ifdef HAVE_PCAP_FINDALLDEVS -#ifdef HAVE_PCAP_REMOTE -extern GList *get_interface_list_findalldevs_ex(const char *source, - struct pcap_rmtauth *auth, int *err, char **err_str); -#else -extern GList *get_interface_list_findalldevs(int *err, char **err_str); -#endif -#endif - -/* - * Get an error message string for a CANT_GET_INTERFACE_LIST error from - * "get_interface_list()". This is used to let the error message string - * be platform-dependent. - */ -extern gchar *cant_get_if_list_error_message(const char *err_str); - -#endif /* HAVE_LIBPCAP */ - -#endif /* __PCAP_UTIL_INT_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-pcap-util.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-pcap-util.h deleted file mode 100644 index fd480733..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-pcap-util.h +++ /dev/null @@ -1,131 +0,0 @@ -/* capture-pcap-util.h - * Utility definitions for packet capture - * - * $Id: capture-pcap-util.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __PCAP_UTIL_H__ -#define __PCAP_UTIL_H__ - -#ifdef HAVE_LIBPCAP - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#include - -#include - -/* - * XXX - this is also the traditional default snapshot size in - * tcpdump - but, if IPv6 is enabled, it defaults to 96, to get an - * IPv6 header + TCP + 22 extra bytes. - * - * Some libpcap versions for particular capture devices might happen - * to impose a minimum, but it's not always 68. - */ -#define MIN_PACKET_SIZE 68 /* minimum amount of packet data we can read */ - -/* - * The list of interfaces returned by "get_interface_list()" is - * a list of these structures. - */ -typedef struct { - char *name; /* e.g. "eth0" */ - char *description; /* from OS, e.g. "Local Area Connection" or NULL */ - GSList *ip_addr; /* containing address values of if_addr_t */ - gboolean loopback; /* TRUE if loopback, FALSE otherwise */ -} if_info_t; - -/* - * An address in the "ip_addr" list. - */ -typedef struct { - address_type type; /* AT_IPv4 or AT_IPv6 */ - union { - guint32 ip4_addr; /* 4 byte IP V4 address, or */ - guint8 ip6_addr[16];/* 16 byte IP V6 address */ - } ip_addr; -} if_addr_t; - -GList *get_interface_list(int *err, char **err_str); -#ifdef HAVE_PCAP_REMOTE -GList *get_remote_interface_list(const char *hostname, const char *port, - int auth_type, const char *username, - const char *passwd, int *err, char **err_str); -#endif - -/* Error values from "get_interface_list()/capture_interface_list()". */ -#define CANT_GET_INTERFACE_LIST 1 /* error getting list */ -#define NO_INTERFACES_FOUND 2 /* list is empty */ -#define CANT_RUN_DUMPCAP 3 /* problem running dumpcap */ - -void free_interface_list(GList *if_list); - -/* - * The list of data link types returned by "get_pcap_linktype_list()" is - * a list of these structures. - */ -typedef struct { - int dlt; /* e.g. DLT_EN10MB (which is 1) */ - char *name; /* e.g. "EN10MB" or "DLT 1" */ - char *description; /* descriptive name from wiretap e.g. "Ethernet", NULL if unknown */ -} data_link_info_t; - -GList *get_pcap_linktype_list(const char *devname, char **err_str); -void free_pcap_linktype_list(GList *linktype_list); - -/* get/set the link type of an interface */ -/* (only used in capture_loop.c / capture-pcap-util.c) */ -int get_pcap_linktype(pcap_t *pch, const char *devname); -const char *set_pcap_linktype(pcap_t *pch, char *devname, int dlt); - - -#ifdef HAVE_PCAP_DATALINK_VAL_TO_NAME -const char *linktype_val_to_name(int dlt); -#endif -#ifdef HAVE_PCAP_DATALINK_NAME_TO_VAL -int linktype_name_to_val(const char *linktype); -#endif - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* HAVE_LIBPCAP */ - -/* - * Append to a GString an indication of the version of libpcap/WinPcap - * with which we were compiled, if we were, or an indication that we - * weren't compiled with libpcap/WinPcap, if we weren't. - */ -extern void get_compiled_pcap_version(GString *str); - -/* - * Append to a GString an indication of the version of libpcap/WinPcap - * with which we're running, or an indication that we're not running - * with libpcap/WinPcap, if we were compiled with libpcap/WinPcap, - * or nothing, if we weren't compiled with libpcap/WinPcap. - */ -extern void get_runtime_pcap_version(GString *str); - -#endif /* __PCAP_UTIL_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-wpcap.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-wpcap.h deleted file mode 100644 index 94e51244..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-wpcap.h +++ /dev/null @@ -1,34 +0,0 @@ -/* capture-wpcap.h - * - * $Id: capture-wpcap.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2001 Gerald Combs - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef CAPTURE_WPCAP_H -#define CAPTURE_WPCAP_H - -extern gboolean has_wpcap; - - -void -load_wpcap(void); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture.h deleted file mode 100644 index 86a0ef1e..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture.h +++ /dev/null @@ -1,118 +0,0 @@ -/* capture.h - * Definitions for packet capture windows - * - * $Id: capture.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* This file should only be included if libpcap is present */ - -#ifndef __CAPTURE_H__ -#define __CAPTURE_H__ - -/** @file - * Capture related things. - */ - -#include "capture_opts.h" - -/** - * Start a capture session. - * - * @param capture_opts the numerous capture options - * @return TRUE if the capture starts successfully, FALSE otherwise. - */ -extern gboolean capture_start(capture_options *capture_opts); - -/** Stop a capture session (usually from a menu item). */ -extern void capture_stop(capture_options *capture_opts); - -/** Restart the current captured packets and start again. */ -extern void capture_restart(capture_options *capture_opts); - -/** Terminate the capture child cleanly when exiting. */ -extern void capture_kill_child(capture_options *capture_opts); - -/** - * Capture child told us we have a new (or the first) capture file. - */ -extern gboolean capture_input_new_file(capture_options *capture_opts, gchar *new_file); - -/** - * Capture child told us we have new packets to read. - */ -extern void capture_input_new_packets(capture_options *capture_opts, int to_read); - -/** - * Capture child told us how many dropped packets it counted. - */ -extern void capture_input_drops(capture_options *capture_opts, int dropped); - -/** - * Capture child told us that an error has occurred while starting the capture. - */ -extern void capture_input_error_message(capture_options *capture_opts, char *error_message, char *secondary_error_msg); - -/** - * Capture child told us that an error has occurred while parsing a - * capture filter when starting/running the capture. - */ -extern void capture_input_cfilter_error_message(capture_options *capture_opts, char *error_message); - -/** - * Capture child closed its side of the pipe, do the required cleanup. - */ -extern void capture_input_closed(capture_options *capture_opts); - -#ifdef HAVE_LIBPCAP -/** - * Fetch the interface list from a child process. - */ -extern GList *capture_interface_list(int *err, char **err_str); - -/** - * Fetch the linktype list for the specified interface from a child process. - */ -extern GList *capture_pcap_linktype_list(const char *devname, char **err_str); - - -struct if_stat_cache_s; -typedef struct if_stat_cache_s if_stat_cache_t; - -/** - * Start gathering capture statistics for the interfaces specified. - * @param A GList of if_info_t items - * @return A pointer to the statistics state data. - */ -extern if_stat_cache_t * capture_stat_start(GList *if_list); - -/** - * Fetch capture statistics, similar to pcap_stats(). - */ -struct pcap_stat; /* Stub in case we don't or haven't yet included pcap.h */ -extern gboolean capture_stats(if_stat_cache_t *sc, char *ifname, struct pcap_stat *ps); - -/** - * Stop gathering capture statistics. - */ -void capture_stat_stop(if_stat_cache_t *sc); -#endif /* HAVE_LIBPCAP */ - -#endif /* capture.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_errs.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_errs.h deleted file mode 100644 index be631336..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_errs.h +++ /dev/null @@ -1,34 +0,0 @@ -/* capture_errs.h - * Declarations of routines to return error and warning messages for - * packet capture - * - * $Id: capture_errs.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_LIBPCAP - -#ifdef _WIN32 -/* error message, if WinPcap couldn't be loaded */ -/* will use g_strdup, don't forget to g_free the returned string! */ -extern char *cant_load_winpcap_err(const char *app_name); -#endif /* _WIN32 */ - -#endif /* HAVE_LIBPCAP */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_info.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_info.h deleted file mode 100644 index 8d83d0f7..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_info.h +++ /dev/null @@ -1,76 +0,0 @@ -/* capture_info.h - * capture info functions - * - * $Id: capture_info.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - - -/** @file - * - * capture info functions - * - */ - -#ifndef __CAPTURE_INFO_H__ -#define __CAPTURE_INFO_H__ - - -/* open the info - init values (wtap, counts), create dialog */ -extern void capture_info_open(const char *iface); - -/* new file arrived - (eventually close old wtap), open wtap */ -extern gboolean capture_info_new_file(const char *new_filename); - -/* new packets arrived - read from wtap, count */ -extern void capture_info_new_packets(int to_read); - -/* close the info - close wtap, destroy dialog */ -extern void capture_info_close(void); - - - -/** Current Capture info. */ -typedef struct { - /* handle */ - gpointer ui; /**< user interface handle */ - - /* capture info */ - packet_counts *counts; /**< protocol specific counters */ - time_t running_time; /**< running time since last update */ - gint new_packets; /**< packets since last update */ -} capture_info; - - -/** Create the capture info dialog */ -extern void capture_info_ui_create( -capture_info *cinfo, -const gchar *iface); - -/** Update the capture info counters in the dialog */ -extern void capture_info_ui_update( -capture_info *cinfo); - -/** Destroy the capture info dialog again */ -extern void capture_info_ui_destroy( -capture_info *cinfo); - - -#endif /* capture_info.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_opts.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_opts.h deleted file mode 100644 index e813688e..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_opts.h +++ /dev/null @@ -1,194 +0,0 @@ -/* capture_opts.h - * Capture options (all parameters needed to do the actual capture) - * - * $Id: capture_opts.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - - -/** @file - * - * Capture options (all parameters needed to do the actual capture) - * - */ - -#ifndef __CAPTURE_OPTS_H__ -#define __CAPTURE_OPTS_H__ - - -/* Current state of capture engine. XXX - differentiate states */ -typedef enum { - CAPTURE_STOPPED, /**< stopped */ - CAPTURE_PREPARING, /**< preparing, but still no response from capture child */ - CAPTURE_RUNNING /**< capture child signalled ok, capture is running now */ -} capture_state; - -#ifdef HAVE_PCAP_REMOTE -/* Type of capture source */ -typedef enum { - CAPTURE_IFLOCAL, /**< Local network interface */ - CAPTURE_IFREMOTE /**< Remote network interface */ -} capture_source; - -/* Type of RPCAPD Authentication */ -typedef enum { - CAPTURE_AUTH_NULL, /**< No authentication */ - CAPTURE_AUTH_PWD /**< User/password authentication */ -} capture_auth; - -#ifdef HAVE_PCAP_SETSAMPLING -/** - * Method of packet sampling (dropping some captured packets), - * may require additional integer parameter, marked here as N - */ -typedef enum { - CAPTURE_SAMP_NONE, /**< No sampling - capture all packets */ - CAPTURE_SAMP_BY_COUNT, /**< Counter-based sampling - - capture 1 packet from every N */ - CAPTURE_SAMP_BY_TIMER /**< Timer-based sampling - - capture no more than 1 packet - in N milliseconds */ -} capture_sampling; -#endif -#endif - -/** Capture options coming from user interface */ -typedef struct capture_options_tag { - /* general */ - void *cf; /**< handle to cfile (note: untyped handle) */ - gboolean has_cfilter; /**< TRUE if capture filter specified on command line */ - gchar *cfilter; /**< Capture filter string */ - gchar *iface; /**< the network interface to capture from */ - gchar *iface_descr; /**< A human readable description of iface. - *< NOTE: capture_opts.c is not able to - *< set this field because doing so - *< requires too many dependencies. - *< Readers of this field should use - *< get_iface_description() from - *< "capture_ui_utils.h" to access it. */ -#ifdef HAVE_PCAP_REMOTE - capture_source src_type; /**< Capturing on remote interface */ - gchar *remote_host; /**< Host name or network address - *< for remote capturing */ - gchar *remote_port; /**< TCP port of remote RPCAP server */ - - capture_auth auth_type; - gchar *auth_username; - gchar *auth_password; /**< Remote authentication parameters */ - - gboolean datatx_udp; /**< Whether to use UDP for data transfer */ - gboolean nocap_rpcap; /**< Whether to capture RPCAP own traffic */ - gboolean nocap_local; /**< TODO: Whether to capture local traffic */ -#ifdef HAVE_PCAP_SETSAMPLING - capture_sampling sampling_method; /**< PCAP packet sampling method */ - int sampling_param; /**< PCAP packet sampling parameter */ -#endif -#endif -#ifdef _WIN32 - int buffer_size; /**< the capture buffer size (MB) */ -#endif - gboolean has_snaplen; /**< TRUE if maximum capture packet length - is specified */ - int snaplen; /**< Maximum captured packet length */ - gboolean promisc_mode; /**< Capture in promiscuous mode */ - int linktype; /**< Data link type to use, or -1 for - "use default" */ - gboolean saving_to_file; /**< TRUE if capture is writing to a file */ - gchar *save_file; /**< the capture file name */ - - /* GUI related */ - gboolean real_time_mode; /**< Update list of packets in real time */ - gboolean show_info; /**< show the info dialog */ - gboolean quit_after_cap; /**< Makes a "capture only mode". Implies -k */ - gboolean restart; /**< restart after closing is done */ - - /* multiple files (and ringbuffer) */ - gboolean multi_files_on; /**< TRUE if ring buffer in use */ - - gboolean has_file_duration; /**< TRUE if ring duration specified */ - gint32 file_duration; /**< Switch file after n seconds */ - gboolean has_ring_num_files; /**< TRUE if ring num_files specified */ - guint32 ring_num_files; /**< Number of multiple buffer files */ - - /* autostop conditions */ - gboolean has_autostop_files; /**< TRUE if maximum number of capture files - are specified */ - gint32 autostop_files; /**< Maximum number of capture files */ - - gboolean has_autostop_packets; /**< TRUE if maximum packet count is - specified */ - int autostop_packets; /**< Maximum packet count */ - gboolean has_autostop_filesize; /**< TRUE if maximum capture file size - is specified */ - gint32 autostop_filesize; /**< Maximum capture file size */ - gboolean has_autostop_duration; /**< TRUE if maximum capture duration - is specified */ - gint32 autostop_duration; /**< Maximum capture duration */ - - /* internally used (don't touch from outside) */ - int fork_child; /**< If not -1, in parent, process ID of child */ -#ifdef _WIN32 - int signal_pipe_write_fd; /**< the pipe to signal the child */ -#endif - capture_state state; /**< current state of the capture engine */ - gboolean output_to_pipe; /**< save_file is a pipe (named or stdout) */ -#ifndef _WIN32 - uid_t owner; /**< owner of the cfile */ - gid_t group; /**< group of the cfile */ -#endif -} capture_options; - -/* initialize the capture_options with some reasonable values */ -extern void -capture_opts_init(capture_options *capture_opts, void *cfile); - -/* set a command line option value */ -extern int -capture_opts_add_opt(capture_options *capture_opts, int opt, const char *optarg, gboolean *start_capture); - -/* log content of capture_opts */ -extern void -capture_opts_log(const char *log_domain, GLogLevelFlags log_level, capture_options *capture_opts); - -/* list link layer types */ -extern int -capture_opts_list_link_layer_types(capture_options *capture_opts, gboolean machine_readable); - -/* list interfaces */ -extern int -capture_opts_list_interfaces(gboolean machine_readable); - -/* print interface statistics */ -extern int -capture_opts_print_statistics(gboolean machine_readable); - -/* trim the snaplen entry */ -extern void -capture_opts_trim_snaplen(capture_options *capture_opts, int snaplen_min); - -/* trim the ring_num_files entry */ -extern void -capture_opts_trim_ring_num_files(capture_options *capture_opts); - -/* trim the interface entry */ -extern gboolean -capture_opts_trim_iface(capture_options *capture_opts, const char *capture_device); - -#endif /* capture_opts.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_stop_conditions.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_stop_conditions.h deleted file mode 100644 index 1e6e1f32..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_stop_conditions.h +++ /dev/null @@ -1,29 +0,0 @@ -/* capture_stop_conditions.h - * Implementation for 'stop condition handler'. - * - * $Id: capture_stop_conditions.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -void init_capture_stop_conditions(void); -void cleanup_capture_stop_conditions(void); - -extern const char* CND_CLASS_TIMEOUT; -extern const char* CND_CLASS_CAPTURESIZE; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_sync.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_sync.h deleted file mode 100644 index 6f2f72fb..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_sync.h +++ /dev/null @@ -1,87 +0,0 @@ -/* capture_sync.h - * Synchronisation between Wireshark capture parent and child instances - * - * $Id: capture_sync.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - - -/** @file - * - * Sync mode capture (internal interface). - * - * Will start a new Wireshark child instance which will do the actual capture - * work. - */ - -#ifndef __CAPTURE_SYNC_H__ -#define __CAPTURE_SYNC_H__ - - -/** - * Start a new capture session. - * Create a capture child which is doing the real capture work. - * The various capture_input_... functions will be called, if something had - * happened. - * - * Most of the parameters are passed through the global capture_opts. - * - * @param capture_opts the options - * @return TRUE if a capture could be started, FALSE if not - */ -extern gboolean -sync_pipe_start(capture_options *capture_opts); - -/** User wants to stop capturing, gracefully close the capture child */ -extern void -sync_pipe_stop(capture_options *capture_opts); - -/** User wants to stop the program, just kill the child as soon as possible */ -extern void -sync_pipe_kill(int fork_child); - -/** Has the parent signalled the child to stop? */ -#define SIGNAL_PIPE_CTRL_ID_NONE "none" -#ifdef _WIN32 -#define SIGNAL_PIPE_FORMAT "\\\\.\\pipe\\wireshark.%s.signal" -#endif - -/** Get an interface list using dumpcap */ -extern int -sync_interface_list_open(gchar **msg); - -/** Get a linktype list using dumpcap */ -extern int -sync_linktype_list_open(const gchar *ifname, gchar **msg); - -/** Start getting interface statistics using dumpcap. */ -extern int -sync_interface_stats_open(int *read_fd, int *fork_child, gchar **msg); - -/** Stop gathering statistics. */ -extern int -sync_interface_stats_close(int *read_fd, int *fork_child, gchar **msg); - -/** Read a line from a pipe, similar to fgets. Non-blocking. */ -extern int -sync_pipe_gets_nonblock(int pipe, char *bytes, int max); - - -#endif /* capture_sync.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_ui_utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_ui_utils.h deleted file mode 100644 index 5da23b2a..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_ui_utils.h +++ /dev/null @@ -1,89 +0,0 @@ -/* capture_ui_utils.c - * Declarations of utilities for capture user interfaces - * - * $Id: capture_ui_utils.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __CAPTURE_UI_UTILS_H__ -#define __CAPTURE_UI_UTILS_H__ - -#include "capture_opts.h" - -/** @file - * GList of available capture interfaces. - */ - -/** Return as descriptive a name for an interface as we can get. - * If the user has specified a comment, use that. Otherwise, - * if get_interface_list() supplies a description, use that, - * otherwise use the interface name. - * - * @param if_name The name of the interface. - * - * @return The descriptive name (must be g_free'd later) - */ -char *get_interface_descriptive_name(const char *if_name); - -/** Build the GList of available capture interfaces. - * - * @param if_list An interface list from get_interface_list(). - * @param do_hide Hide the "hidden" interfaces. - * - * @return A list of if_info_t structs (use free_capture_combo_list() later). - */ -GList *build_capture_combo_list(GList *if_list, gboolean do_hide); - -/** Free the GList from build_capture_combo_list(). - * - * @param combo_list the interface list from build_capture_combo_list() - */ -void free_capture_combo_list(GList *combo_list); - - -/** Given text that contains an interface name possibly prefixed by an - * interface description, extract the interface name. - * - * @param if_text A string containing the interface description + name. - * This is usually the data from one of the list elements returned by - * build_capture_combo_list(). - * - * @return The raw interface name, without description (must NOT be g_free'd later) - */ -const char *get_if_name(const char *if_text); - -/** Convert plain interface name to the displayed name in the combo box. - * - * @param if_list The list of interfaces returned by build_capture_combo_list() - * @param if_name The name of the interface. - * - * @return The descriptive name (must be g_free'd later) - */ -char *build_capture_combo_name(GList *if_list, gchar *if_name); - -/** Return the interface description (after setting it if not already set) - * - * @param capture_opts The capture_options structure that contains the used interface - * - * @return A pointer to capture_ops->iface_descr - */ -const char *get_iface_description(capture_options *capture_opts); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_wpcap_packet.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_wpcap_packet.h deleted file mode 100644 index 38d1cd9d..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_wpcap_packet.h +++ /dev/null @@ -1,47 +0,0 @@ -/* capture_wpcap_packet.h - * - * $Id: capture_wpcap_packet.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2001 Gerald Combs - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef CAPTURE_WPCAP_PACKET_H -#define CAPTURE_WPCAP_PACKET_H - - -extern void wpcap_packet_load(void); - -/* get the packet.dll version info */ -extern char *wpcap_packet_get_version(void); - -/* open the interface */ -extern void * wpcap_packet_open(char *if_name); - -/* close the interface */ -extern void wpcap_packet_close(void * adapter); - -extern int wpcap_packet_request(void *a, ULONG Oid, int set, char *value, unsigned int *length); - -extern int wpcap_packet_request_uint(void *a, ULONG Oid, UINT *value); - -extern int wpcap_packet_request_ulong(void *a, ULONG Oid, ULONG *value); - - -#endif /* CAPTURE_WPCAP_PACKET_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/cfile.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/cfile.h deleted file mode 100644 index 0b388d5d..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/cfile.h +++ /dev/null @@ -1,91 +0,0 @@ -/* cfile.h - * capture_file definition & GUI-independent manipulation - * - * $Id: cfile.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __CFILE_H__ -#define __CFILE_H__ - -/* Current state of file. */ -typedef enum { - FILE_CLOSED, /* No file open */ - FILE_READ_IN_PROGRESS, /* Reading a file we've opened */ - FILE_READ_ABORTED, /* Read aborted by user */ - FILE_READ_DONE /* Read completed */ -} file_state; - -/* Character set for text search. */ -typedef enum { - SCS_ASCII_AND_UNICODE, - SCS_ASCII, - SCS_UNICODE - /* add EBCDIC when it's implemented */ -} search_charset_t; - -typedef struct _capture_file { - file_state state; /* Current state of capture file */ - gchar *filename; /* Name of capture file */ - gboolean is_tempfile; /* Is capture file a temporary file? */ - gboolean user_saved;/* If capture file is temporary, has it been saved by user yet? */ - gint64 f_datalen; /* Size of capture file data (uncompressed) */ - guint16 cd_t; /* File type of capture file */ - int lnk_t; /* Link-layer type with which to save capture */ - guint32 vers; /* Version. For tcpdump minor is appended to major */ - int count; /* Total number of frames */ - int displayed_count; /* Number of displayed frames */ - int marked_count; /* Number of marked frames */ - gboolean drops_known; /* TRUE if we know how many packets were dropped */ - guint32 drops; /* Dropped packets */ - nstime_t elapsed_time;/* Elapsed time */ - gboolean has_snap; /* TRUE if maximum capture packet length is known */ - int snap; /* Maximum captured packet length */ - wtap *wth; /* Wiretap session */ - dfilter_t *rfcode; /* Compiled read (display) filter program */ - gchar *dfilter; /* Display filter string */ - /* search */ - gchar *sfilter; /* Search filter string */ - gboolean sbackward; /* TRUE if search is backward, FALSE if forward */ - gboolean hex; /* TRUE is raw data search is being performed */ - gboolean string; /* TRUE is text search is being performed */ - guint32 search_pos; /* Position of last character found in search */ - search_charset_t scs_type; /* Character set for text search */ - gboolean case_type; /* TRUE if case-insensitive text search */ - gboolean decode_data; /* TRUE if searching protocol tree text */ - gboolean summary_data; /* TRUE if searching Info column text */ - /* packet data */ - union wtap_pseudo_header pseudo_header; /* Packet pseudo_header */ - guint8 pd[WTAP_MAX_PACKET_SIZE]; /* Packet data */ - GMemChunk *plist_chunk; /* Memory chunk for frame_data structures */ - frame_data *plist; /* Packet list */ - frame_data *plist_end; /* Last packet in list */ - frame_data *first_displayed; /* First frame displayed */ - frame_data *last_displayed; /* Last frame displayed */ - column_info cinfo; /* Column formatting information */ - frame_data *current_frame; /* Frame data for current frame */ - epan_dissect_t *edt; /* Protocol dissection for currently selected packet */ - field_info *finfo_selected; /* Field info for currently selected field */ - struct ph_stats_s* pstats; /* accumulated stats (reset on redisplay in GUI)*/ -} capture_file; - -void init_cap_file(capture_file *); - -#endif /* cfile.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/clopts_common.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/clopts_common.h deleted file mode 100644 index 825164bc..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/clopts_common.h +++ /dev/null @@ -1,40 +0,0 @@ -/* clopts_common.h - * Handle command-line arguments common to Wireshark and TShark - * - * $Id: clopts_common.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __PROTO_DUMPOPTS_H__ -#define __PROTO_DUMPOPTS_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -int get_natural_int(const char *string, const char *name); - -int get_positive_int(const char *string, const char *name); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __PROTO_DUMPOPTS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/cmdarg_err.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/cmdarg_err.h deleted file mode 100644 index 5bd43cc0..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/cmdarg_err.h +++ /dev/null @@ -1,56 +0,0 @@ -/* cmdarg_err.h - * Declarations of routines to report command-line errors. - * - * $Id: cmdarg_err.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __CMDARG_ERR_H__ -#define __CMDARG_ERR_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* - * Report an error in command-line arguments. - */ -#if __GNUC__ >= 2 -extern void cmdarg_err(const char *fmt, ...) - __attribute__((format (printf, 1, 2))); -#else -extern void cmdarg_err(const char *fmt, ...); -#endif - -/* - * Report additional information for an error in command-line arguments. - */ -#if __GNUC__ >= 2 -extern void cmdarg_err_cont(const char *fmt, ...) - __attribute__((format (printf, 1, 2))); -#else -extern void cmdarg_err_cont(const char *fmt, ...); -#endif - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __CMDARG_ERR_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/color.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/color.h deleted file mode 100644 index a1c09b2a..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/color.h +++ /dev/null @@ -1,55 +0,0 @@ -/* color.h - * Definitions for "toolkit-independent" colors - * - * $Id: color.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __COLOR_H__ -#define __COLOR_H__ - -/* - * Data structure holding RGB value for a color. - * - * XXX - yes, I know, there's a "pixel" value in there as well; for - * now, it's intended to look just like a GdkColor but not to require - * that any GTK+ header files be included in order to use it. - * The way we handle colors needs to be cleaned up somewhat, in order - * to keep toolkit-specific stuff separate from toolkit-independent stuff. - */ -typedef struct { - guint32 pixel; - guint16 red; - guint16 green; - guint16 blue; -} color_t; - -/** Initialize a color with R, G, and B values, including any toolkit-dependent - ** work that needs to be done. - * - * @param color the color_t to be filled - * @param red the red value for the color - * @param green the green value for the color - * @param blue the blue value for the color - * @return TRUE if it succeeds, FALSE if it fails - */ -gboolean initialize_color(color_t *color, guint16 red, guint16 green, guint16 blue); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/color_filters.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/color_filters.h deleted file mode 100644 index 878ce97f..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/color_filters.h +++ /dev/null @@ -1,196 +0,0 @@ -/* color_filters.h - * Definitions for color filters - * - * $Id: color_filters.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#ifndef __COLOR_FILTERS_H__ -#define __COLOR_FILTERS_H__ - -#define TEMP_COLOR_PREFIX "___tmp_color_filter___" -/** @file - * Color filters. - */ - -/* Data for a color filter. */ -typedef struct _color_filter { - gchar *filter_name; /* name of the filter */ - gchar *filter_text; /* text of the filter expression */ - color_t bg_color; /* background color for packets that match */ - color_t fg_color; /* foreground color for packets that match */ - gboolean disabled; /* set if the filter is disabled */ - gboolean selected; /* set if the filter is selected in the color dialog box */ - - /* only used inside of color_filters.c */ - dfilter_t *c_colorfilter; /* compiled filter expression */ - - /* only used outside of color_filters.c (beside init) */ - void *edit_dialog; /* if filter is being edited, dialog - * box for it */ -} color_filter_t; - - -/** Init the color filters (incl. initial read from file). */ -void color_filters_init(void); - -/** Reload the color filters */ -void color_filters_reload(void); - -/** Cleanup remaining color filter zombies */ -void color_filters_cleanup(void); - -/** Color filters currently used? - * - * @return TRUE, if filters are used - */ -gboolean color_filters_used(void); - -/** Are there any temporary coloring filters used? - * - * @return TRUE, if temporary coloring filters are used - */ -gboolean tmp_color_filters_used(void); - -/** En-/disable color filters - * - * @param enable TRUE to enable (default) - */ -void -color_filters_enable(gboolean enable); - -/** Set the filter string of a temporary color filter - * - * @param filt_nr a number 1-10 pointing to a temporary color - * @param filter the new filter-string - * @param disabled whether the filter-rule should be disabled - */ -void -color_filters_set_tmp(guint8 filt_nr, gchar *filter, gboolean disabled); - -/** Reset the temporary color filters - * - */ -void -color_filters_reset_tmp(void); - -/* Prime the epan_dissect_t with all the compiler - * color filters of the current filter list. - * - * @param the epan dissector details - */ -void color_filters_prime_edt(epan_dissect_t *edt); - -/** Colorize a specific packet. - * - * @param row the row in the packet list - * @param edt the dissected packet - * @return the matching color filter or NULL - */ -color_filter_t * -color_filters_colorize_packet(gint row, epan_dissect_t *edt); - - - -/** Clone the currently active filter list. - * - * @param user_data will be returned by each call to to color_filter_add_cb() - */ -void color_filters_clone(gpointer user_data); - -/** Load filters (import) from some other filter file. - * - * @param path the path to the import file - * @param user_data will be returned by each call to to color_filter_add_cb() - * @return TRUE, if read succeeded - */ -gboolean color_filters_import(gchar *path, gpointer user_data); - -/** Read filters from the global filter file (not the users file). - * - * @param user_data will be returned by each call to to color_filter_add_cb() - * @return TRUE, if read succeeded - */ -gboolean color_filters_read_globals(gpointer user_data); - -/** A color filter was added (while importing). - * (color_filters.c calls this for every filter coming in) - * - * @param colorf the new color filter - * @param user_data from caller - */ -void color_filter_add_cb (color_filter_t *colorf, gpointer user_data); - - - -/** Apply a changed filter list. - * - * @param tmp_cfl the temporary color filter list to apply - * @param edit_cfl the edited permanent color filter list to apply - */ -void color_filters_apply(GSList *tmp_cfl, GSList *edit_cfl); - -/** Save filters in users filter file. - * - * @param cfl the filter list to write - * @return TRUE if write succeeded - */ -gboolean color_filters_write(GSList *cfl); - -/** Save filters (export) to some other filter file. - * - * @param path the path to the filter file - * @param cfl the filter list to write - * @param only_selected TRUE if only the selected filters should be saved - * @return TRUE, if write succeeded - */ -gboolean color_filters_export(gchar *path, GSList *cfl, gboolean only_selected); - - - -/** Create a new color filter (g_malloc'ed). - * - * @param name the name of the filter - * @param filter_string the filter string - * @param bg_color background color - * @param fg_color foreground color - * @return the new color filter - */ -color_filter_t *color_filter_new( - const gchar *name, const gchar *filter_string, - color_t *bg_color, color_t *fg_color, gboolean disabled); - -/** Delete a single color filter (g_free'ed). - * - * @param colorf the color filter to be removed - */ -void color_filter_delete(color_filter_t *colorf); - - - - -/** Delete a filter list including all entries. - * - * @param cfl the filter list to delete - */ -void color_filter_list_delete(GSList **cfl); - - - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/conditions.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/conditions.h deleted file mode 100644 index e07af3b6..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/conditions.h +++ /dev/null @@ -1,134 +0,0 @@ -/* conditions.h - * Header for condition handler. - * - * $Id: conditions.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef CONDITIONS_H -#define CONDITIONS_H - -#include - -#include - -/* forward declaration for type 'condition' */ -typedef struct condition condition; - -/* condition evaluation handler type */ -typedef gboolean (*_cnd_eval)(condition*, va_list); - -/* condition reset handler type */ -typedef void (*_cnd_reset)(condition*); - -/* condition class constructor type */ -typedef condition* (*_cnd_constr)(condition*, va_list); - -/* condition class destructor type */ -typedef void (*_cnd_destr)(condition*); - -/* - * Conditions must be created with this function. They can be created for - * registered classes only. - * - * parameter: const char* - Identification of a registered condition class. - * ... - Any number of class specific initial values. - * returns: Pointer to a initialized condition of the particular class on - * success or NULL on failure. - */ -condition* cnd_new(const char*, ...); - -/* - * Conditions must be deleted with this function when not used anymore. - * - * parameter: condition* - Pointer to a condition created with 'cnd_new()'. - * returns: - - */ -void cnd_delete(condition*); - -/* - * Call this function to check whether or not a particular condition is true. - * - * parameter: condition* - Pointer to an initialized condition. - * ... - Any number of condition specific arguments. - * returns: TRUE - Condition is true. - * FALSE - Condition is false. - */ -gboolean cnd_eval(condition*, ...); - -/* - * Call this function to reset this condition to its initial state, i.e. the - * state it was in right after creation. - * - * parameter: condition* - Pointer to an initialized condition. - * returns: - - */ -void cnd_reset(condition*); - -/* - * Register a new conditon class. - * New conditions of this class can be created by calling 'cnd_new()' and - * supplying the appropriate class id. - * - * parameter: const char* - The class id. - * _cnd_constr - User supplied constructor function for this - * class. - * _cnd_destr - User supplied destructor function for this - * class. - * _cnd_eval - User supplied evaluation handler function for this - class. - * _cnd_reset - User supplied reset handler for this class. - * returns: TRUE - Success. - * FALSE - Failure. - */ -gboolean cnd_register_class(const char*, - _cnd_constr, - _cnd_destr, - _cnd_eval, - _cnd_reset); - -/* - * Unregister a previously registered conditon class. After unregistration - * of a class it is no longer possible to create conditions of this kind by - * calling 'cnd_new()'. - * - * parameter: const char* - An identification for this condition class. - * returns: - - */ -void cnd_unregister_class(const char*); - -/* - * This function returns the user data of the condition. - * - * parameter: condition* - Pointer to an initialized condition. - * returns: void* - Pointer to user data of this condition. - */ -void* cnd_get_user_data(condition*); - -/* - * This function sets the user data of the condition. - * - * parameter: condition* - Pointer to an initialized condition. - * void* - Pointer to user specified data structure. - * returns: - - */ -void cnd_set_user_data(condition*, void*); - -#endif /* CONDITIONS_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h deleted file mode 100644 index cf2ce4a1..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h +++ /dev/null @@ -1,322 +0,0 @@ -/* config.h. Generated from config.h.in by configure. */ -/* config.h.in. Generated from configure.in by autoheader. */ - -/* Directory for data */ -#define DATAFILE_DIR "/usr/local/share/wireshark" - -/* Link plugins statically into Wireshark */ -/* #undef ENABLE_STATIC */ - -/* Format modifier for printing 64-bit numbers */ -/* #undef G_GINT64_MODIFIER */ - -/* Enable AirPDcap (WPA/WPA2 decryption) */ -#define HAVE_AIRPDCAP 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_ARPA_INET_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_ARPA_NAMESER_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_DIRECT_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_DIRENT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_DLFCN_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_FCNTL_H 1 - -/* Define to 1 if you have the `gethostbyname2' function. */ -#define HAVE_GETHOSTBYNAME2 1 - -/* Define to 1 if you have the `getprotobynumber' function. */ -#define HAVE_GETPROTOBYNUMBER 1 - -/* Define to use GNU ADNS library */ -/* #undef HAVE_GNU_ADNS */ - -/* Define to 1 if you have the header file. */ -#define HAVE_GRP_H 1 - -/* Define to use heimdal kerberos */ -/* #undef HAVE_HEIMDAL_KERBEROS */ - -/* Define if you have the iconv() function. */ -#define HAVE_ICONV 1 - -/* Define if inet_ntop() prototype exists */ -#define HAVE_INET_NTOP_PROTO 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the `issetugid' function. */ -/* #undef HAVE_ISSETUGID */ - -/* Define to use kerberos */ -#define HAVE_KERBEROS 1 - -/* Define if krb5.h defines KEYTYPE_ARCFOUR_56 */ -/* #undef HAVE_KEYTYPE_ARCFOUR_56 */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LAUXLIB_H */ - -/* Define to use the libcap library */ -/* #undef HAVE_LIBCAP */ - -/* Define to use libgcrypt */ -#define HAVE_LIBGCRYPT 1 - -/* Define to use gnutls library */ -#define HAVE_LIBGNUTLS 1 - -/* Define to use libpcap library */ -#define HAVE_LIBPCAP 1 - -/* Define to use libpcre library */ -/* #undef HAVE_LIBPCRE */ - -/* Define to use libportaudio library */ -/* #undef HAVE_LIBPORTAUDIO */ - -/* Define to 1 if you have the `smi' library (-lsmi). */ -/* #undef HAVE_LIBSMI */ - -/* Define to use libz library */ -#define HAVE_LIBZ 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LUA5_1_LAUXLIB_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LUA5_1_LUALIB_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LUA5_1_LUA_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LUALIB_H */ - -/* Define to use Lua 5.1 */ -/* #undef HAVE_LUA_5_1 */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LUA_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to use MIT kerberos */ -#define HAVE_MIT_KERBEROS 1 - -/* Define to 1 if you have the `mmap' function. */ -#define HAVE_MMAP 1 - -/* Define to 1 if you have the `mprotect' function. */ -#define HAVE_MPROTECT 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_NETDB_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_NETINET_IN_H 1 - -/* Define to 1 if you have OS X frameworks */ -/* #undef HAVE_OS_X_FRAMEWORKS */ - -/* Define if pcap_breakloop is known */ -#define HAVE_PCAP_BREAKLOOP 1 - -/* Define to 1 if you have the `pcap_createsrcstr' function. */ -/* #undef HAVE_PCAP_CREATESRCSTR */ - -/* Define to 1 if you have the `pcap_datalink_name_to_val' function. */ -#define HAVE_PCAP_DATALINK_NAME_TO_VAL 1 - -/* Define to 1 if you have the `pcap_datalink_val_to_name' function. */ -#define HAVE_PCAP_DATALINK_VAL_TO_NAME 1 - -/* Define to 1 if you have the `pcap_findalldevs' function and a pcap.h that - declares pcap_if_t. */ -#define HAVE_PCAP_FINDALLDEVS 1 - -/* Define to 1 if you have the `pcap_findalldevs_ex' function. */ -/* #undef HAVE_PCAP_FINDALLDEVS_EX */ - -/* Define to 1 if you have the `pcap_freecode' function. */ -#define HAVE_PCAP_FREECODE 1 - -/* Define to 1 if you have the `pcap_get_selectable_fd' function. */ -#define HAVE_PCAP_GET_SELECTABLE_FD 1 - -/* Define to 1 if you have the `pcap_lib_version' function. */ -#define HAVE_PCAP_LIB_VERSION 1 - -/* Define to 1 if you have the `pcap_list_datalinks' function. */ -#define HAVE_PCAP_LIST_DATALINKS 1 - -/* Define to 1 if you have the `pcap_open' function. */ -/* #undef HAVE_PCAP_OPEN */ - -/* Define to 1 if you have the `pcap_open_dead' function. */ -#define HAVE_PCAP_OPEN_DEAD 1 - -/* Define to 1 if you have WinPcap remote capturing support and prefer to use - these new API features. */ -/* #undef HAVE_PCAP_REMOTE */ - -/* Define to 1 if you have the `pcap_setsampling' function. */ -/* #undef HAVE_PCAP_SETSAMPLING */ - -/* Define to 1 if you have the `pcap_set_datalink' function. */ -#define HAVE_PCAP_SET_DATALINK 1 - -/* Define if libpcap version is known */ -#define HAVE_PCAP_VERSION 1 - -/* Define if plugins are enabled */ -#define HAVE_PLUGINS 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_PORTAUDIO_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_PWD_H 1 - -/* Define to 1 to enable remote capturing feature in WinPcap library */ -/* #undef HAVE_REMOTE */ - -/* Define if sa_len field exists in struct sockaddr */ -/* #undef HAVE_SA_LEN */ - -/* Define to 1 if you have the `setresgid' function. */ -#define HAVE_SETRESGID 1 - -/* Define to 1 if you have the `setresuid' function. */ -#define HAVE_SETRESUID 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDARG_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDDEF_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the `sysconf' function. */ -#define HAVE_SYSCONF 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_IOCTL_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_PARAM_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_SOCKET_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_SOCKIO_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TIME_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_UTSNAME_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_WAIT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_UNISTD_H 1 - -/* HTML viewer, e.g. mozilla */ -#define HTML_VIEWER "mozilla" - -/* Define as const if the declaration of iconv() needs const. */ -#define ICONV_CONST - -/* Define if defines PRI[doxu]64 macros */ -#define INTTYPES_H_DEFINES_FORMATS - -/* Define if getopt.h needs to be included */ -/* #undef NEED_GETOPT_H */ - -/* Define if g_ascii_strcasecmp.h needs to be included */ -/* #undef NEED_G_ASCII_STRCASECMP_H */ - -/* Define if g_ascii_strtoull.h needs to be included */ -/* #undef NEED_G_ASCII_STRTOULL_H */ - -/* Define if inet/aton.h needs to be included */ -/* #undef NEED_INET_ATON_H */ - -/* Define if inet/v6defs.h needs to be included */ -/* #undef NEED_INET_V6DEFS_H */ - -/* Define if strerror.h needs to be included */ -/* #undef NEED_STRERROR_H */ - -/* Define if strptime.h needs to be included */ -/* #undef NEED_STRPTIME_H */ - -/* Name of package */ -#define PACKAGE "wireshark" - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "" - -/* Define if we are using version of of the Portaudio library API */ -/* #undef PORTAUDIO_API_1 */ - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Version number of package */ -#define VERSION "1.0.0" - -/* Define to 1 if your processor stores words with the most significant byte - first (like Motorola and SPARC, unlike Intel and VAX). */ -/* #undef WORDS_BIGENDIAN */ - -/* Define as the string to precede external variable declarations in - dynamically-linked libraries */ -#define WS_VAR_IMPORT extern - -/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a - `char[]'. */ -#define YYTEXT_POINTER 1 diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h.in b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h.in deleted file mode 100644 index b5e1fbdc..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h.in +++ /dev/null @@ -1,321 +0,0 @@ -/* config.h.in. Generated from configure.in by autoheader. */ - -/* Directory for data */ -#undef DATAFILE_DIR - -/* Link plugins statically into Wireshark */ -#undef ENABLE_STATIC - -/* Format modifier for printing 64-bit numbers */ -#undef G_GINT64_MODIFIER - -/* Enable AirPDcap (WPA/WPA2 decryption) */ -#undef HAVE_AIRPDCAP - -/* Define to 1 if you have the header file. */ -#undef HAVE_ARPA_INET_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_ARPA_NAMESER_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_DIRECT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_DIRENT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_DLFCN_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_FCNTL_H - -/* Define to 1 if you have the `gethostbyname2' function. */ -#undef HAVE_GETHOSTBYNAME2 - -/* Define to 1 if you have the `getprotobynumber' function. */ -#undef HAVE_GETPROTOBYNUMBER - -/* Define to use GNU ADNS library */ -#undef HAVE_GNU_ADNS - -/* Define to 1 if you have the header file. */ -#undef HAVE_GRP_H - -/* Define to use heimdal kerberos */ -#undef HAVE_HEIMDAL_KERBEROS - -/* Define if you have the iconv() function. */ -#undef HAVE_ICONV - -/* Define if inet_ntop() prototype exists */ -#undef HAVE_INET_NTOP_PROTO - -/* Define to 1 if you have the header file. */ -#undef HAVE_INTTYPES_H - -/* Define to 1 if you have the `issetugid' function. */ -#undef HAVE_ISSETUGID - -/* Define to use kerberos */ -#undef HAVE_KERBEROS - -/* Define if krb5.h defines KEYTYPE_ARCFOUR_56 */ -#undef HAVE_KEYTYPE_ARCFOUR_56 - -/* Define to 1 if you have the header file. */ -#undef HAVE_LAUXLIB_H - -/* Define to use the libcap library */ -#undef HAVE_LIBCAP - -/* Define to use libgcrypt */ -#undef HAVE_LIBGCRYPT - -/* Define to use gnutls library */ -#undef HAVE_LIBGNUTLS - -/* Define to use libpcap library */ -#undef HAVE_LIBPCAP - -/* Define to use libpcre library */ -#undef HAVE_LIBPCRE - -/* Define to use libportaudio library */ -#undef HAVE_LIBPORTAUDIO - -/* Define to 1 if you have the `smi' library (-lsmi). */ -#undef HAVE_LIBSMI - -/* Define to use libz library */ -#undef HAVE_LIBZ - -/* Define to 1 if you have the header file. */ -#undef HAVE_LUA5_1_LAUXLIB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LUA5_1_LUALIB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LUA5_1_LUA_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LUALIB_H - -/* Define to use Lua 5.1 */ -#undef HAVE_LUA_5_1 - -/* Define to 1 if you have the header file. */ -#undef HAVE_LUA_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_MEMORY_H - -/* Define to use MIT kerberos */ -#undef HAVE_MIT_KERBEROS - -/* Define to 1 if you have the `mmap' function. */ -#undef HAVE_MMAP - -/* Define to 1 if you have the `mprotect' function. */ -#undef HAVE_MPROTECT - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETDB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETINET_IN_H - -/* Define to 1 if you have OS X frameworks */ -#undef HAVE_OS_X_FRAMEWORKS - -/* Define if pcap_breakloop is known */ -#undef HAVE_PCAP_BREAKLOOP - -/* Define to 1 if you have the `pcap_createsrcstr' function. */ -#undef HAVE_PCAP_CREATESRCSTR - -/* Define to 1 if you have the `pcap_datalink_name_to_val' function. */ -#undef HAVE_PCAP_DATALINK_NAME_TO_VAL - -/* Define to 1 if you have the `pcap_datalink_val_to_name' function. */ -#undef HAVE_PCAP_DATALINK_VAL_TO_NAME - -/* Define to 1 if you have the `pcap_findalldevs' function and a pcap.h that - declares pcap_if_t. */ -#undef HAVE_PCAP_FINDALLDEVS - -/* Define to 1 if you have the `pcap_findalldevs_ex' function. */ -#undef HAVE_PCAP_FINDALLDEVS_EX - -/* Define to 1 if you have the `pcap_freecode' function. */ -#undef HAVE_PCAP_FREECODE - -/* Define to 1 if you have the `pcap_get_selectable_fd' function. */ -#undef HAVE_PCAP_GET_SELECTABLE_FD - -/* Define to 1 if you have the `pcap_lib_version' function. */ -#undef HAVE_PCAP_LIB_VERSION - -/* Define to 1 if you have the `pcap_list_datalinks' function. */ -#undef HAVE_PCAP_LIST_DATALINKS - -/* Define to 1 if you have the `pcap_open' function. */ -#undef HAVE_PCAP_OPEN - -/* Define to 1 if you have the `pcap_open_dead' function. */ -#undef HAVE_PCAP_OPEN_DEAD - -/* Define to 1 if you have WinPcap remote capturing support and prefer to use - these new API features. */ -#undef HAVE_PCAP_REMOTE - -/* Define to 1 if you have the `pcap_setsampling' function. */ -#undef HAVE_PCAP_SETSAMPLING - -/* Define to 1 if you have the `pcap_set_datalink' function. */ -#undef HAVE_PCAP_SET_DATALINK - -/* Define if libpcap version is known */ -#undef HAVE_PCAP_VERSION - -/* Define if plugins are enabled */ -#undef HAVE_PLUGINS - -/* Define to 1 if you have the header file. */ -#undef HAVE_PORTAUDIO_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_PWD_H - -/* Define to 1 to enable remote capturing feature in WinPcap library */ -#undef HAVE_REMOTE - -/* Define if sa_len field exists in struct sockaddr */ -#undef HAVE_SA_LEN - -/* Define to 1 if you have the `setresgid' function. */ -#undef HAVE_SETRESGID - -/* Define to 1 if you have the `setresuid' function. */ -#undef HAVE_SETRESUID - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDARG_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDDEF_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDINT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDLIB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRINGS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRING_H - -/* Define to 1 if you have the `sysconf' function. */ -#undef HAVE_SYSCONF - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_IOCTL_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_PARAM_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_SOCKET_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_SOCKIO_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_STAT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TIME_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_UTSNAME_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_WAIT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_UNISTD_H - -/* HTML viewer, e.g. mozilla */ -#undef HTML_VIEWER - -/* Define as const if the declaration of iconv() needs const. */ -#undef ICONV_CONST - -/* Define if defines PRI[doxu]64 macros */ -#undef INTTYPES_H_DEFINES_FORMATS - -/* Define if getopt.h needs to be included */ -#undef NEED_GETOPT_H - -/* Define if g_ascii_strcasecmp.h needs to be included */ -#undef NEED_G_ASCII_STRCASECMP_H - -/* Define if g_ascii_strtoull.h needs to be included */ -#undef NEED_G_ASCII_STRTOULL_H - -/* Define if inet/aton.h needs to be included */ -#undef NEED_INET_ATON_H - -/* Define if inet/v6defs.h needs to be included */ -#undef NEED_INET_V6DEFS_H - -/* Define if strerror.h needs to be included */ -#undef NEED_STRERROR_H - -/* Define if strptime.h needs to be included */ -#undef NEED_STRPTIME_H - -/* Name of package */ -#undef PACKAGE - -/* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT - -/* Define to the full name of this package. */ -#undef PACKAGE_NAME - -/* Define to the full name and version of this package. */ -#undef PACKAGE_STRING - -/* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME - -/* Define to the version of this package. */ -#undef PACKAGE_VERSION - -/* Define if we are using version of of the Portaudio library API */ -#undef PORTAUDIO_API_1 - -/* Define to 1 if you have the ANSI C header files. */ -#undef STDC_HEADERS - -/* Version number of package */ -#undef VERSION - -/* Define to 1 if your processor stores words with the most significant byte - first (like Motorola and SPARC, unlike Intel and VAX). */ -#undef WORDS_BIGENDIAN - -/* Define as the string to precede external variable declarations in - dynamically-linked libraries */ -#undef WS_VAR_IMPORT - -/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a - `char[]'. */ -#undef YYTEXT_POINTER diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h.win32 b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h.win32 deleted file mode 100644 index a9569f67..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h.win32 +++ /dev/null @@ -1,274 +0,0 @@ -/* $Id: config.h.win32 23802 2007-12-07 23:58:46Z guy $ */ -/* config.h.win32 Generated manually. :-) */ -/* config.h. Generated automatically by configure. */ -/* config.h.in. Generated automatically from configure.in by autoheader. */ - -/* Generated Bison and Flex files test whether __STDC__ is defined - in order to check whether to use ANSI C features such as "const". - - GCC defines it as 1 even if extensions that render the implementation - non-conformant are enabled; Sun's C compiler (and, I think, other - AT&T-derived C compilers) define it as 0 if extensions that render - the implementation non-conformant are enabled; Microsoft Visual C++ - 6.0 doesn't define it at all if extensions that render the implementation - non-conformant are enabled. - - We define it as 0 here, so that those generated files will use - those features (and thus not get type warnings when compiled with - MSVC++). */ -#ifndef __STDC__ -#define __STDC__ 0 -#endif - -/* Use Unicode in Windows runtime functions. */ -#define UNICODE 1 -#define _UNICODE 1 - -/* Define if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Define if your processor stores words with the most significant - byte first (like Motorola and SPARC, unlike Intel and VAX). */ -/* #undef WORDS_BIGENDIAN */ - -/* Define if lex declares yytext as a char * by default, not a char[]. */ -#define YYTEXT_POINTER 1 - -#define HAVE_PLUGINS 1 -#define PLUGINS_NEED_ADDRESS_TABLE 1 - -/* Plugins can also use the import library of libwireshark.dll instead - of the old API. In that case we undefine PLUGINS_NEED_ADDRESS_TABLE - for the plugin. We don't undefine PLUGINS_NEED_ADDRESS_TABLE globally. - Thus Wireshark will be still able to load plugins using the old API. - The macro HAVE_WIN32_LIBWIRESHARK_LIB has to be defined in plugin's - makefile.nmake. A template is available in doc/README.plugins */ -#ifdef HAVE_WIN32_LIBWIRESHARK_LIB -#undef PLUGINS_NEED_ADDRESS_TABLE -#endif - -/* #undef HAVE_SA_LEN */ - -/* #undef NEED_STRERROR_H */ - -#define NEED_MKSTEMP 1 - -@HAVE_LIBPCAP@ -@HAVE_PCAP_BREAKLOOP@ -@HAVE_PCAP_FINDALLDEVS@ -@HAVE_PCAP_DATALINK_NAME_TO_VAL@ -@HAVE_PCAP_DATALINK_VAL_TO_NAME@ -@WPCAP_CONSTIFIED@ -@HAVE_LIBWIRESHARKDLL@ - -@HAVE_REMOTE@ -@HAVE_PCAP_REMOTE@ -@HAVE_PCAP_OPEN@ -@HAVE_PCAP_FINDALLDEVS_EX@ -@HAVE_PCAP_CREATESRCSTR@ -@HAVE_PCAP_SETSAMPLING@ - -@HAVE_AIRPCAP@ -@HAVE_AIRPDCAP@ - -/* availability of pcap_freecode() is handled at runtime */ -#define HAVE_PCAP_FREECODE 1 - -/* define macro for importing variables from an dll - * it depends on HAVE_LIBWIRESHARKDLL and _NEED_VAR_IMPORT_ - */ -#if defined (_NEED_VAR_IMPORT_) && defined (HAVE_LIBWIRESHARKDLL) -# define WS_VAR_IMPORT __declspec(dllimport) extern -#else -# define WS_VAR_IMPORT extern -#endif - -/* Define if you have the gethostbyname2 function. */ -/* #undef HAVE_GETHOSTBYNAME2 */ - -/* Define if you have the getprotobynumber function. */ -/* #undef HAVE_GETPROTOBYNUMBER */ - -/* Define if you have the header file. */ -/* #undef HAVE_ARPA_INET_H */ - -/* Define if you have the header file. */ -#define HAVE_FCNTL_H 1 - -/* Define if you have the header file. */ -/* #undef HAVE_ICONV */ - -/* Define if you have the header file. */ -/* #undef HAVE_NETDB_H */ - -/* Define if you have the header file. */ -/* #define HAVE_NETINET_IN_H 1 */ - -/* Define if you have the header file. */ -/* #undef HAVE_SNMP_SNMP_H */ - -/* Define if you have the header file. */ -/* #undef HAVE_SNMP_VERSION_H */ - -/* Define if you have the header file. */ -#define HAVE_STDARG_H 1 - -/* Define if you have the header file. */ -/* #undef HAVE_STDDEF_H */ - -/* Define if you have the header file. */ -/* #undef HAVE_SYS_IOCTL_H */ - -/* Define if you have the header file. */ -/* #undef HAVE_SYS_SOCKET_H */ - -/* Define if you have the header file. */ -/* #undef HAVE_SYS_SOCKIO_H */ - -/* Define if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define if you have the header file. */ -/* #define HAVE_SYS_TIME_H 1 */ - -/* Define if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define if you have the header file. */ -/* #undef HAVE_SYS_WAIT_H */ - -/* Define if you have the header file. */ -/* #define HAVE_UNISTD_H 1 */ - -/* Define if defines PRI[doxu]64 macros */ -/* #define INTTYPES_H_DEFINES_FORMATS */ - -/* Format for printing 64-bit signed decimal numbers */ -#ifndef PRId64 -#ifdef _MSC_EXTENSIONS -#define PRId64 "I64d" -#else /* _MSC_EXTENSIONS */ -#define PRId64 "lld" -#endif /* _MSC_EXTENSIONS */ -#endif /* PRId64 */ - -/* Format for printing 64-bit unsigned octal numbers */ -#ifndef PRIo64 -#ifdef _MSC_EXTENSIONS -#define PRIo64 "I64o" -#else /* _MSC_EXTENSIONS */ -#define PRIo64 "llo" -#endif /* _MSC_EXTENSIONS */ -#endif /* PRIo64 */ - -/* Format for printing 64-bit unsigned decimal numbers */ -#ifndef PRIu64 -#ifdef _MSC_EXTENSIONS -#define PRIu64 "I64u" -#else /* _MSC_EXTENSIONS */ -#define PRIu64 "llu" -#endif /* _MSC_EXTENSIONS */ -#endif /* PRIu64 */ - -/* Formats for printing 64-bit unsigned hexadecimal numbers */ -/* XXX - it seems that GLib has problems with the MSVC like I64x. - As we use GLib's g_sprintf and alike, it should be safe to use - llx everywhere now, making the macros pretty useless. For details see: - http://bugs.wireshark.org/bugzilla/show_bug.cgi?id=1025 */ -#ifndef PRIx64 -#ifdef _MSC_EXTENSIONS -/*#define PRIx64 "I64x"*/ -#define PRIx64 "llx" -#else /* _MSC_EXTENSIONS */ -#define PRIx64 "llx" -#endif /* _MSC_EXTENSIONS */ -#endif /* PRIx64 */ - -#ifndef PRIX64 -#ifdef _MSC_EXTENSIONS -/*#define PRIX64 "I64X"*/ -#define PRIX64 "llX" -#else /* _MSC_EXTENSIONS */ -#define PRIX64 "llX" -#endif /* _MSC_EXTENSIONS */ -#endif /* PRIX64 */ - -/* Define if you have the z library (-lz). */ -@HAVE_LIBZ@ - -/* Define to use GNU ADNS library */ -@HAVE_GNU_ADNS@ -#define ADNS_JGAA_WIN32 1 - -/* Define to use the PCRE library */ -@HAVE_PCRE@ - -/* Define to use the Nettle library */ -@HAVE_NETTLE@ - -/* Define to use the gnutls library */ -@HAVE_LIBGNUTLS@ - -/* Define to use the libgcrypt library */ -@HAVE_LIBGCRYPT@ - -/* Define to use mit kerberos for decryption of kerberos/sasl/dcerpc */ -@HAVE_KFW@ -#ifdef HAVE_MIT_KERBEROS -#define HAVE_KERBEROS -#endif - -/* Define to use Lua */ -@HAVE_LUA@ -@HAVE_LUA_5_1@ - -/* Define to use Portaudio library */ -@HAVE_LIBPORTAUDIO@ -/* Define version of of the Portaudio library API */ -@PORTAUDIO_API_1@ - -/* Define to have SMI */ -@HAVE_SMI@ - - -#ifndef WIN32 -#define WIN32 1 -#endif - -#define HAVE_WINDOWS_H 1 -#define HAVE_WINSOCK2_H 1 -#define HAVE_DIRECT_H 1 -#define NEED_INET_ATON_H 1 -#define NEED_INET_V6DEFS_H 1 -/* Visual C 9 (2008) now needs these prototypes */ -#if _MSC_VER == 1500 -#define NTDDI_VERSION NTDDI_WIN2K -#define _WIN32_WINNT _WIN32_WINNT_WIN2K -#endif -#define NEED_GETOPT_H 1 -#define NEED_STRPTIME_H 1 -#define strcasecmp stricmp -#define strncasecmp strnicmp -#define popen _popen -#define pclose _pclose - -/* Needed for zlib, according to http://www.winimage.com/zLibDll/ */ -/*#define ZLIB_DLL 1 -#define _WINDOWS 1*/ - -/* Name of package */ -#define PACKAGE "wireshark" - -/* Version number of package */ -#define VERSION "@VERSION@" - -/* We shouldn't need this under Windows but we'll define it anyway. */ -#define HTML_VIEWER "mozilla" - -/* Check for the required _MSC_VER */ -#if MSC_VER_REQUIRED != _MSC_VER -#define WS_TO_STRING2(x) #x -#define WS_TO_STRING(x) WS_TO_STRING2(x) -#pragma message( "_MSC_VER is:" WS_TO_STRING(_MSC_VER) " but required is:" WS_TO_STRING(MSC_VER_REQUIRED) ) -#error Your MSVC_VARIANT setting in config.nmake doesn't match the MS compiler version! -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/disabled_protos.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/disabled_protos.h deleted file mode 100644 index 87f5b3ab..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/disabled_protos.h +++ /dev/null @@ -1,61 +0,0 @@ -/* disabled_protos.h - * Declarations of routines for reading and writing the disabled protocols file. - * - * $Id: disabled_protos.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* - * Item in a list of disabled protocols. - */ -typedef struct { - char *name; /* protocol name */ -} protocol_def; - -/* - * Read in a list of disabled protocols. - * - * On success, "*pref_path_return" is set to NULL. - * On error, "*pref_path_return" is set to point to the pathname of - * the file we tried to read - it should be freed by our caller - - * and "*open_errno_return" is set to the error if we couldn't open the file - * or "*read_errno_return" is set to the error if we got an error reading - * the file. - */ -void read_disabled_protos_list(char **gpath_return, int *gopen_errno_return, - int *gread_errno_return, - char **path_return, int *open_errno_return, - int *read_errno_return); - -/* - * Disable protocols as per the stored configuration - */ -void set_disabled_protos_list(void); - -/* - * Write out a list of disabled protocols. - * - * On success, "*pref_path_return" is set to NULL. - * On error, "*pref_path_return" is set to point to the pathname of - * the file we tried to read - it should be freed by our caller - - * and "*errno_return" is set to the error. - */ -void save_disabled_protos_list(char **pref_path_return, int *errno_return); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/addr_and_mask.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/addr_and_mask.h deleted file mode 100644 index b582aa6e..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/addr_and_mask.h +++ /dev/null @@ -1,53 +0,0 @@ -/* addr_and_mask.h - * Declarations of routines to fetch IPv4 and IPv6 addresses from a tvbuff - * and then mask out bits other than those covered by a prefix length - * - * $Id: addr_and_mask.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __ADDR_AND_MASK_H__ -#define __ADDR_AND_MASK_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* - * These routines return PREFIX_LEN_OK on success, PREFIX_LEN_TOO_LONG if - * the prefix length is too long, and PREFIX_LEN_ZERO if the prefix length - * is 0. - */ - -#define PREFIX_LEN_OK 0 -#define PREFIX_LEN_TOO_LONG 1 -#define PREFIX_LEN_ZERO 2 - -extern int ipv4_addr_and_mask(tvbuff_t *tvb, int offset, guint8 *addr, - guint32 prefix_len); - -extern int ipv6_addr_and_mask(tvbuff_t *tvb, int offset, - struct e_in6_addr *addr, guint32 prefix_len); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __ADDR_AND_MASK_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/addr_resolv.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/addr_resolv.h deleted file mode 100644 index 4733db52..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/addr_resolv.h +++ /dev/null @@ -1,198 +0,0 @@ -/* addr_resolv.h - * Definitions for network object lookup - * - * $Id: addr_resolv.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Laurent Deniel - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -/* The buffers returned by these functions are all allocated with a - * packet lifetime and does not have have to be freed. - * However, take into account that when the packet dissection - * completes, these buffers will be automatically reclaimed/freed. - * If you need the buffer to remain for a longer scope than packet lifetime - * you must copy the content to an se_alloc() buffer. - */ - -#ifndef __RESOLV_H__ -#define __RESOLV_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#ifndef MAXNAMELEN -#define MAXNAMELEN 64 /* max name length (hostname and port name) */ -#endif - -/* - * Flag controlling what names to resolve. - */ -WS_VAR_IMPORT guint32 g_resolv_flags; - -/* 32 types are sufficient (as are 640k of RAM) */ -/* FIXME: Maybe MANUF/m, IP/i, IP6/6, IPX/x, UDP+TCP/t etc would be - more useful/consistent */ -#define RESOLV_NONE 0x0 -#define RESOLV_MAC 0x1 -#define RESOLV_NETWORK 0x2 -#define RESOLV_TRANSPORT 0x4 -#define RESOLV_CONCURRENT 0x8 - -#define RESOLV_ALL_ADDRS (RESOLV_MAC|RESOLV_NETWORK|RESOLV_TRANSPORT) -#define RESOLV_ALL 0xFFFFFFFF - -/* global variables */ - -extern gchar *g_ethers_path; -extern gchar *g_ipxnets_path; -extern gchar *g_pethers_path; -extern gchar *g_pipxnets_path; - -/* Functions in resolv.c */ - -/* Set the flags controlling what names to resolve */ -extern void resolv_set_flags(guint32 flags); - -/* - * get_udp_port() returns the port name corresponding to that UDP port, - * or the port number as a string if not found. - */ -extern gchar *get_udp_port(guint port); - -/* - * get_tcp_port() returns the port name corresponding to that TCP port, - * or the port number as a string if not found. - */ -extern gchar *get_tcp_port(guint port); - -/* - * get_dccp_port() returns the port name corresponding to that DCCP port, - * or the port number as a string if not found. - */ -extern gchar *get_dccp_port(guint port); - -/* - * get_sctp_port() returns the port name corresponding to that SCTP port, - * or the port number as a string if not found. - */ -extern gchar *get_sctp_port(guint port); - -/* get_addr_name takes as input an "address", as defined in address.h */ -/* it returns a string that contains: */ -/* - if the address is of a type that can be translated into a name, and the user */ -/* has activated name resolution, the translated name */ -/* - if the address is of type AT_NONE, a pointer to the string "NONE" */ -/* - if the address is of any other type, the result of address_to_str on the argument, */ -/* which should be a string representation for the answer -e.g. "10.10.10.10" for IPv4 */ -/* address 10.10.10.10 */ - -const gchar *get_addr_name(address *addr); - -/* get_addr_name_buf solves an address in the same way as get_addr_name above */ -/* The difference is that get_addr_name_buf takes as input a buffer, into which it puts */ -/* the result which is always NUL ('\0') terminated. The buffer should be large enough to */ -/* contain size characters including the terminator */ - -void get_addr_name_buf(address *addr, gchar *buf, guint size); - - -/* - * Asynchronous host name lookup initialization, processing, and cleanup - */ - -/* host_name_lookup_init fires up an ADNS socket if we're using ADNS */ -extern void host_name_lookup_init(void); - -/* host_name_lookup_process does ADNS processing in GTK+ timeouts in Wireshark, - and before processing each packet in TShark, if we're using ADNS */ -extern gint host_name_lookup_process(gpointer data); - -/* host_name_lookup_cleanup cleans up an ADNS socket if we're using ADNS */ -extern void host_name_lookup_cleanup(void); - -/* get_hostname returns the host name or "%d.%d.%d.%d" if not found */ -extern gchar *get_hostname(guint addr); - -/* get_hostname6 returns the host name, or numeric addr if not found */ -struct e_in6_addr; -const gchar* get_hostname6(struct e_in6_addr *ad); - -/* get_ether_name returns the logical name if found in ethers files else - "_%02x:%02x:%02x" if the vendor code is known else - "%02x:%02x:%02x:%02x:%02x:%02x" */ -extern gchar *get_ether_name(const guint8 *addr); - -/* get_ether_name returns the logical name if found in ethers files else NULL */ -extern gchar *get_ether_name_if_known(const guint8 *addr); - -/* get_manuf_name returns the vendor name or "%02x:%02x:%02x" if not known */ -extern const gchar *get_manuf_name(const guint8 *addr); - -/* get_manuf_name returns the vendor name or NULL if not known */ -extern const gchar *get_manuf_name_if_known(const guint8 *addr); - -/* get_ipxnet_name returns the logical name if found in an ipxnets file, - * or a string formatted with "%X" if not */ -extern const gchar *get_ipxnet_name(const guint32 addr); - -/* returns the ethernet address corresponding to name or NULL if not known */ -extern guint8 *get_ether_addr(const gchar *name); - -/* returns the ipx network corresponding to name. If name is unknown, - * 0 is returned and 'known' is set to FALSE. On success, 'known' - * is set to TRUE. */ -guint32 get_ipxnet_addr(const gchar *name, gboolean *known); - -/* adds a hostname/IPv4 in the hash table */ -extern void add_ipv4_name(guint addr, const gchar *name); - -/* adds a hostname/IPv6 in the hash table */ -extern void add_ipv6_name(struct e_in6_addr *addr, const gchar *name); - -/* add ethernet address / name corresponding to IP address */ -extern void add_ether_byip(guint ip, const guint8 *eth); - -/* Translates a string representing the hostname or dotted-decimal IP address - * into a numeric IP address value, returning TRUE if it succeeds and - * FALSE if it fails. */ -gboolean get_host_ipaddr(const char *host, guint32 *addrp); - -/* - * Translate IPv6 numeric address or FQDN hostname, into binary IPv6 address. - * Return TRUE if we succeed and set "*addrp" to that numeric IP address; - * return FALSE if we fail. - */ -gboolean get_host_ipaddr6(const char *host, struct e_in6_addr *addrp); - -/* - * Find out whether a hostname resolves to an ip or ipv6 address - * Return "ip6" if it is IPv6, "ip" otherwise (including the case - * that we don't know) - */ -const char* host_ip_af(const char *host); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __RESOLV_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/address.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/address.h deleted file mode 100644 index 1ce916d4..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/address.h +++ /dev/null @@ -1,172 +0,0 @@ -/* address.h - * Definitions for structures storing addresses, and for the type of - * variables holding port-type values - * - * $Id: address.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __ADDRESS_H__ -#define __ADDRESS_H__ - -#include "emem.h" - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* Types of addresses Wireshark knows about. */ -/* If a new address type is added here, a string representation procedure should */ -/* also be included in address_to_str_buf defined in to_str.c, for presentation purposes */ - -typedef enum { - AT_NONE, /* no link-layer address */ - AT_ETHER, /* MAC (Ethernet, 802.x, FDDI) address */ - AT_IPv4, /* IPv4 */ - AT_IPv6, /* IPv6 */ - AT_IPX, /* IPX */ - AT_SNA, /* SNA */ - AT_ATALK, /* Appletalk DDP */ - AT_VINES, /* Banyan Vines */ - AT_OSI, /* OSI NSAP */ - AT_ARCNET, /* ARCNET */ - AT_FC, /* Fibre Channel */ - AT_SS7PC, /* SS7 Point Code */ - AT_STRINGZ, /* null-terminated string */ - AT_EUI64, /* IEEE EUI-64 */ - AT_URI, /* URI/URL/URN */ - AT_TIPC, /* TIPC Address Zone,Subnetwork,Processor */ - AT_USB /* USB Device address - * (0xffffffff represents the host) */ -} address_type; - -typedef struct _address { - address_type type; /* type of address */ - int len; /* length of address, in bytes */ - const void *data; /* pointer to address data */ -} address; - -#define SET_ADDRESS(addr, addr_type, addr_len, addr_data) { \ - (addr)->type = (addr_type); \ - (addr)->len = (addr_len); \ - (addr)->data = (addr_data); \ - } - -/* - * Given two addresses, return - * 0 if the addresses are equal, - * a positive number if addr1>addr2 in some nondefined metric, - * a negative number if addr1type > (addr2)->type)?1: \ - ((addr1)->type < (addr2)->type)?-1: \ - ((addr1)->len > (addr2)->len) ?1: \ - ((addr1)->len < (addr2)->len) ?-1: \ - memcmp((addr1)->data, (addr2)->data, (addr1)->len)\ - ) - -/* - * Given two addresses, return "true" if they're equal, "false" otherwise. - * Addresses are equal only if they have the same type; if the type is - * AT_NONE, they are then equal, otherwise they must have the same - * amount of data and the data must be the same. - */ -#define ADDRESSES_EQUAL(addr1, addr2) \ - ( \ - (addr1)->type == (addr2)->type && \ - ( \ - (addr1)->type == AT_NONE || \ - ( \ - (addr1)->len == (addr2)->len && \ - memcmp((addr1)->data, (addr2)->data, (addr1)->len) == 0 \ - ) \ - ) \ - ) - -/* - * Copy an address, allocating a new buffer for the address data. - */ -#define COPY_ADDRESS(to, from) { \ - guint8 *COPY_ADDRESS_data; \ - (to)->type = (from)->type; \ - (to)->len = (from)->len; \ - COPY_ADDRESS_data = g_malloc((from)->len); \ - memcpy(COPY_ADDRESS_data, (from)->data, (from)->len); \ - (to)->data = COPY_ADDRESS_data; \ - } - -#define SE_COPY_ADDRESS(to, from) { \ - guint8 *SE_COPY_ADDRESS_data; \ - (to)->type = (from)->type; \ - (to)->len = (from)->len; \ - SE_COPY_ADDRESS_data = se_alloc((from)->len); \ - memcpy(SE_COPY_ADDRESS_data, (from)->data, (from)->len); \ - (to)->data = SE_COPY_ADDRESS_data; \ - } - -/* - * Hash an address into a hash value (which must already have been set). - */ -#define ADD_ADDRESS_TO_HASH(hash_val, addr) { \ - const guint8 *ADD_ADDRESS_TO_HASH_data; \ - int ADD_ADDRESS_TO_HASH_index; \ - ADD_ADDRESS_TO_HASH_data = (addr)->data; \ - for (ADD_ADDRESS_TO_HASH_index = 0; \ - ADD_ADDRESS_TO_HASH_index < (addr)->len; \ - ADD_ADDRESS_TO_HASH_index++) \ - hash_val += ADD_ADDRESS_TO_HASH_data[ADD_ADDRESS_TO_HASH_index]; \ - } - -/* Types of port numbers Wireshark knows about. */ -typedef enum { - PT_NONE, /* no port number */ - PT_SCTP, /* SCTP */ - PT_TCP, /* TCP */ - PT_UDP, /* UDP */ - PT_DCCP, /* DCCP */ - PT_IPX, /* IPX sockets */ - PT_NCP, /* NCP connection */ - PT_EXCHG, /* Fibre Channel exchange */ - PT_DDP, /* DDP AppleTalk connection */ - PT_SBCCS, /* FICON */ - PT_IDP, /* XNS IDP sockets */ - PT_TIPC, /* TIPC PORT */ - PT_USB /* USB endpoint 0xffff means the host */ -} port_type; - -/* Types of circuit IDs Wireshark knows about. */ -typedef enum { - CT_NONE, /* no circuit type */ - CT_DLCI, /* Frame Relay DLCI */ - CT_ISDN, /* ISDN channel number */ - CT_X25, /* X.25 logical channel number */ - CT_ISUP, /* ISDN User Part CIC */ - CT_IAX2, /* IAX2 call id */ - CT_H223, /* H.223 logical channel number */ - CT_BICC /* BICC Circuit identifier */ - /* Could also have ATM VPI/VCI pairs */ -} circuit_type; - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __ADDRESS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/adler32.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/adler32.h deleted file mode 100644 index 277ed53a..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/adler32.h +++ /dev/null @@ -1,42 +0,0 @@ -/* adler32.h - * Compute the Adler32 checksum (RFC 1950) - * 2003 Tomas Kukosa - * - * $Id: adler32.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef ADLER32_H -#define ADLER32_H - -#ifdef __cplusplus -extern "C"{ -#endif - -unsigned long update_adler32(unsigned long adler, const unsigned char *buf, int len); -unsigned long adler32_bytes(const unsigned char *buf, int len); -unsigned long adler32_str(const char *buf); - -#ifdef __cplusplus -} -#endif - -#endif /* ADLER32_H */ - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/afn.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/afn.h deleted file mode 100644 index 16538789..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/afn.h +++ /dev/null @@ -1,71 +0,0 @@ -/* afn.h - * RFC 1700 address family numbers - * - * $Id: afn.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __AFN_H__ -#define __AFN_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* - * Address family numbers, from - * - * http://www.iana.org/assignments/address-family-numbers - */ -#define AFNUM_RESERVED 0 /* Reserved */ -#define AFNUM_INET 1 /* IP (IP version 4) */ -#define AFNUM_INET6 2 /* IP6 (IP version 6) */ -#define AFNUM_NSAP 3 /* NSAP */ -#define AFNUM_HDLC 4 /* HDLC (8-bit multidrop) */ -#define AFNUM_BBN1822 5 /* BBN 1822 */ -#define AFNUM_802 6 /* 802 (includes all 802 media plus Ethernet "canonical format") */ -#define AFNUM_E163 7 /* E.163 */ -#define AFNUM_E164 8 /* E.164 (SMDS, Frame Relay, ATM) */ -#define AFNUM_F69 9 /* F.69 (Telex) */ -#define AFNUM_X121 10 /* X.121 (X.25, Frame Relay) */ -#define AFNUM_IPX 11 /* IPX */ -#define AFNUM_ATALK 12 /* Appletalk */ -#define AFNUM_DECNET 13 /* Decnet IV */ -#define AFNUM_BANYAN 14 /* Banyan Vines */ -#define AFNUM_E164NSAP 15 /* E.164 with NSAP format subaddress */ -#define AFNUM_DNS 16 /* DNS (Domain Name System) */ -#define AFNUM_DISTNAME 17 /* Distinguished Name */ -#define AFNUM_AS_NUMBER 18 /* AS Number */ -#define AFNUM_XTP_IP4 19 /* XTP over IP version 4 */ -#define AFNUM_XTP_IP6 20 /* XTP over IP version 6 */ -#define AFNUM_XTP 21 /* XTP native mode XTP */ -#define AFNUM_FC_WWPN 22 /* Fibre Channel World-Wide Port Name */ -#define AFNUM_FC_WWNN 23 /* Fibre Channel World-Wide Node Name */ -#define AFNUM_GWID 24 /* GWID */ -/* draft-kompella-ppvpn-l2vpn */ -#define AFNUM_L2VPN 25 -#define AFNUM_L2VPN_OLD 196 -extern const value_string afn_vals[]; - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __AFN_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/aftypes.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/aftypes.h deleted file mode 100644 index a28d7494..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/aftypes.h +++ /dev/null @@ -1,47 +0,0 @@ -/* aftypes.h - * AF_ values on various flavors of BSD - * - * $Id: aftypes.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * - * This file created and by Mike Hall - * Copyright 1998 - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __AFTYPES_H__ -#define __AFTYPES_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* BSD AF_ values. */ -#define BSD_AF_INET 2 -#define BSD_AF_ISO 7 -#define BSD_AF_APPLETALK 16 -#define BSD_AF_IPX 23 -#define BSD_AF_INET6_BSD 24 /* OpenBSD (and probably NetBSD), BSD/OS */ -#define BSD_AF_INET6_FREEBSD 28 -#define BSD_AF_INET6_DARWIN 30 - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* aftypes.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/arcnet_pids.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/arcnet_pids.h deleted file mode 100644 index 7f92176a..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/arcnet_pids.h +++ /dev/null @@ -1,70 +0,0 @@ -/* arcnet_pids.h - * ARCNET protocol ID values - * Copyright 2001-2002, Peter Fales - * - * $Id: arcnet_pids.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __ARCNET_PIDS_H__ -#define __ARCNET_PIDS_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* RFC 1051 */ -#define ARCNET_PROTO_IP_1051 240 -#define ARCNET_PROTO_ARP_1051 241 - -/* RFC 1201 */ -#define ARCNET_PROTO_IP_1201 212 -#define ARCNET_PROTO_ARP_1201 213 -#define ARCNET_PROTO_RARP_1201 214 - -#define ARCNET_PROTO_IPX 250 -#define ARCNET_PROTO_NOVELL_EC 236 - -#define ARCNET_PROTO_IPv6 196 /* or so BSD's arcnet.h claims */ - -/* - * Raw Ethernet over ARCNET - Linux's "if_arcnet.h" calls this - * "MS LanMan/WfWg 'NDIS' encapsuation". - */ -#define ARCNET_PROTO_ETHERNET 232 - -#define ARCNET_PROTO_DATAPOINT_BOOT 0 -#define ARCNET_PROTO_DATAPOINT_MOUNT 1 -#define ARCNET_PROTO_POWERLAN_BEACON 8 -#define ARCNET_PROTO_POWERLAN_BEACON2 243 -#define ARCNET_PROTO_LANSOFT 251 - -#define ARCNET_PROTO_APPLETALK 221 -#define ARCNET_PROTO_BANYAN 247 /* Banyan VINES */ - -#define ARCNET_PROTO_DIAGNOSE 128 /* as per ANSI/ATA 878.1 */ - -#define ARCNET_PROTO_BACNET 205 - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* arcnet_pids.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/arptypes.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/arptypes.h deleted file mode 100644 index de936cb6..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/arptypes.h +++ /dev/null @@ -1,75 +0,0 @@ -/* arptypes.h - * Declarations of ARP address types. - * - * $Id: arptypes.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __ARPTYPES_H__ -#define __ARPTYPES_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* Definitions taken from Linux "linux/if_arp.h" header file, and from - - http://www.iana.org/assignments/arp-parameters - - */ - -/* ARP protocol HARDWARE identifiers. */ -#define ARPHRD_NETROM 0 /* from KA9Q: NET/ROM pseudo */ -#define ARPHRD_ETHER 1 /* Ethernet 10Mbps */ -#define ARPHRD_EETHER 2 /* Experimental Ethernet */ -#define ARPHRD_AX25 3 /* AX.25 Level 2 */ -#define ARPHRD_PRONET 4 /* PROnet token ring */ -#define ARPHRD_CHAOS 5 /* Chaosnet */ -#define ARPHRD_IEEE802 6 /* IEEE 802.2 Ethernet/TR/TB */ -#define ARPHRD_ARCNET 7 /* ARCnet */ -#define ARPHRD_HYPERCH 8 /* Hyperchannel */ -#define ARPHRD_LANSTAR 9 /* Lanstar */ -#define ARPHRD_AUTONET 10 /* Autonet Short Address */ -#define ARPHRD_LOCALTLK 11 /* Localtalk */ -#define ARPHRD_LOCALNET 12 /* LocalNet (IBM PCNet/Sytek LocalNET) */ -#define ARPHRD_ULTRALNK 13 /* Ultra link */ -#define ARPHRD_SMDS 14 /* SMDS */ -#define ARPHRD_DLCI 15 /* Frame Relay DLCI */ -#define ARPHRD_ATM 16 /* ATM */ -#define ARPHRD_HDLC 17 /* HDLC */ -#define ARPHRD_FIBREC 18 /* Fibre Channel */ -#define ARPHRD_ATM2225 19 /* ATM (RFC 2225) */ -#define ARPHRD_SERIAL 20 /* Serial Line */ -#define ARPHRD_ATM2 21 /* ATM */ -#define ARPHRD_MS188220 22 /* MIL-STD-188-220 */ -#define ARPHRD_METRICOM 23 /* Metricom STRIP */ -#define ARPHRD_IEEE1394 24 /* IEEE 1394.1995 */ -#define ARPHRD_MAPOS 25 /* MAPOS */ -#define ARPHRD_TWINAX 26 /* Twinaxial */ -#define ARPHRD_EUI_64 27 /* EUI-64 */ - -/* Virtual ARP types for non ARP hardware used in Linux cooked mode. */ -#define ARPHRD_IPGRE 778 /* GRE over IP */ - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* arptypes.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/asm_utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/asm_utils.h deleted file mode 100644 index 384b0d68..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/asm_utils.h +++ /dev/null @@ -1,38 +0,0 @@ -/* asm_utils.h - * Functions optionally implemented in assembler - * - * $Id: asm_utils.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __ASM_UTILS_H__ -#define __ASM_UTILS_H__ - -gint wrs_strcmp(gconstpointer a, gconstpointer b); -gint wrs_strcmp_with_data(gconstpointer a, gconstpointer b, gpointer user_data); -gboolean wrs_str_equal(gconstpointer a, gconstpointer b); - -guchar wrs_check_charset(const guchar table[256], const char *str); - -guint wrs_str_hash(gconstpointer v); - -/* int wrs_count_bitshift(guint32 bitmask); */ - -#endif /* __ASM_UTILS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/asn1.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/asn1.h deleted file mode 100644 index b57bbcff..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/asn1.h +++ /dev/null @@ -1,207 +0,0 @@ -/* asn1.h - * Common data for ASN.1 - * 2007 Anders Broman - * - * $Id: asn1.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __ASN1_H__ -#define __ASN1_H__ - -typedef enum { - ASN1_ENC_BER, /* X.690 - BER, CER, DER */ - ASN1_ENC_PER, /* X.691 - PER */ - ASN1_ENC_ECN, /* X.692 - ECN */ - ASN1_ENC_XER /* X.693 - XER */ -} asn1_enc_e; - -typedef enum { - CB_ASN1_ENC, - CB_DISSECTOR, - CB_NEW_DISSECTOR, - CB_DISSECTOR_HANDLE -} asn1_cb_variant; - -typedef enum { - ASN1_PAR_IRR, /* irrelevant parameter */ - /* value */ - ASN1_PAR_BOOLEAN, - ASN1_PAR_INTEGER, - /* type */ - ASN1_PAR_TYPE -} asn1_par_type; - -typedef struct _asn1_par_def_t { - const gchar *name; - asn1_par_type ptype; -} asn1_par_def_t; - -typedef struct _asn1_par_t { - const gchar *name; - asn1_par_type ptype; - union { - gboolean v_boolean; - gint32 v_integer; - void *v_type; - } value; - struct _asn1_par_t *next; -} asn1_par_t; - -typedef struct _asn1_stack_frame_t { - const gchar *name; - struct _asn1_par_t *par; - struct _asn1_stack_frame_t *next; -} asn1_stack_frame_t; - -#define ASN1_CTX_SIGNATURE 0x41435458 /* "ACTX" */ - -typedef struct _asn1_ctx_t { - guint32 signature; - asn1_enc_e encoding; - gboolean aligned; - packet_info *pinfo; - proto_item *created_item; - struct _asn1_stack_frame_t *stack; - void *value_ptr; - void *private_data; - struct { - int hf_index; - gboolean data_value_descr_present; - gboolean direct_ref_present; - gboolean indirect_ref_present; - tvbuff_t *data_value_descriptor; - const char *direct_reference; - gint32 indirect_reference; - gint encoding; - /* - 0 : single-ASN1-type, - 1 : octet-aligned, - 2 : arbitrary - */ - tvbuff_t *single_asn1_type; - tvbuff_t *octet_aligned; - tvbuff_t *arbitrary; - union { - struct { - int (*ber_callback)(gboolean imp_tag, tvbuff_t *tvb, int offset, struct _asn1_ctx_t* ,proto_tree *tree, int hf_index ); - } ber; - struct { - int (*type_cb)(tvbuff_t*, int, struct _asn1_ctx_t*, proto_tree*, int); - } per; - } u; - } external; - struct { - int hf_index; - gboolean data_value_descr_present; - tvbuff_t *data_value_descriptor; - gint identification; - /* - 0 : syntaxes, - 1 : syntax, - 2 : presentation-context-id, - 3 : context-negotiation, - 4 : transfer-syntax, - 5 : fixed - */ - gint32 presentation_context_id; - const char *abstract_syntax; - const char *transfer_syntax; - tvbuff_t *data_value; - union { - struct { - int (*ber_callback)(gboolean imp_tag, tvbuff_t *tvb, int offset, struct _asn1_ctx_t* ,proto_tree *tree, int hf_index ); - } ber; - struct { - int (*type_cb)(tvbuff_t*, int, struct _asn1_ctx_t*, proto_tree*, int); - } per; - } u; - } embedded_pdv; - struct _rose_ctx_t *rose_ctx; -} asn1_ctx_t; - -#define ROSE_CTX_SIGNATURE 0x524F5345 /* "ROSE" */ - -typedef struct _rose_ctx_t { - guint32 signature; - dissector_table_t arg_global_dissector_table; - dissector_table_t arg_local_dissector_table; - dissector_table_t res_global_dissector_table; - dissector_table_t res_local_dissector_table; - dissector_table_t err_global_dissector_table; - dissector_table_t err_local_dissector_table; - /* filling in description into tree, info column, any buffer */ - int apdu_depth; - gboolean fillin_info; - gchar *fillin_ptr; - gsize fillin_buf_size; - struct { /* "dynamic" data */ - gint pdu; - /* - 1 : invoke, - 2 : returnResult, - 3 : returnError, - 4 : reject - */ - gint code; - /* - 0 : local, - 1 : global - */ - gint32 code_local; - const char *code_global; - proto_item *code_item; - } d; - void *private_data; -} rose_ctx_t; - -extern void asn1_ctx_init(asn1_ctx_t *actx, asn1_enc_e encoding, gboolean aligned, packet_info *pinfo); -extern gboolean asn1_ctx_check_signature(asn1_ctx_t *actx); -extern void asn1_ctx_clean_external(asn1_ctx_t *actx); -extern void asn1_ctx_clean_epdv(asn1_ctx_t *actx); - -extern void asn1_stack_frame_push(asn1_ctx_t *actx, const gchar *name); -extern void asn1_stack_frame_pop(asn1_ctx_t *actx, const gchar *name); -extern void asn1_stack_frame_check(asn1_ctx_t *actx, const gchar *name, const asn1_par_def_t *par_def); - -extern void asn1_param_push_boolean(asn1_ctx_t *actx, gboolean value); -extern void asn1_param_push_integer(asn1_ctx_t *actx, gint32 value); -extern gboolean asn1_param_get_boolean(asn1_ctx_t *actx, const gchar *name); -extern gint32 asn1_param_get_integer(asn1_ctx_t *actx, const gchar *name); - -extern void rose_ctx_init(rose_ctx_t *rctx); -extern gboolean rose_ctx_check_signature(rose_ctx_t *rctx); -extern void rose_ctx_clean_data(rose_ctx_t *rctx); - -extern asn1_ctx_t *get_asn1_ctx(void *ptr); -extern rose_ctx_t *get_rose_ctx(void *ptr); - -extern double asn1_get_real(const guint8 *real_ptr, gint real_len); - -/* flags */ -#define ASN1_EXT_ROOT 0x01 -#define ASN1_EXT_EXT 0x02 -#define ASN1_OPT 0x04 -#define ASN1_DFLT 0x08 - -#define ASN1_HAS_EXT(f) ((f)&(ASN1_EXT_ROOT|ASN1_EXT_EXT)) - - -#endif /* __ASN1_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/atalk-utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/atalk-utils.h deleted file mode 100644 index c7cdcdf4..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/atalk-utils.h +++ /dev/null @@ -1,63 +0,0 @@ -/* atalk-utils.h - * Definitions for Appletalk utilities (DDP, currently). - * - * $Id: atalk-utils.h 3992 2008-06-10 03:13:11Z dgu $ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __ATALK_UTILS_H__ -#define __ATALK_UTILS_H__ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* - * Structure used to represent a DDP address; gives the layout of the - * data pointed to by an AT_ATALK "address" structure. - */ -struct atalk_ddp_addr { - guint16 net; - guint8 node; -}; - -/* - * DDP packet types. - */ -#define DDP_RTMPDATA 0x01 -#define DDP_NBP 0x02 -#define DDP_ATP 0x03 -#define DDP_AEP 0x04 -#define DDP_RTMPREQ 0x05 -#define DDP_ZIP 0x06 -#define DDP_ADSP 0x07 -#define DDP_EIGRP 0x58 - -/* - * Routines to take a DDP address and generate a string. - */ -extern gchar *atalk_addr_to_str(const struct atalk_ddp_addr *addrp); -extern void atalk_addr_to_str_buf(const struct atalk_ddp_addr *addrp, - gchar *buf, int buf_len); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/base64.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/base64.h deleted file mode 100644 index 38aacf8a..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/base64.h +++ /dev/null @@ -1,38 +0,0 @@ -/* base64.h - * Base-64 conversion - * - * $Id: base64.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#ifndef __BASE64_H__ -#define __BASE64_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* In-place decoding of a base64 string. */ -size_t epan_base64_decode(char *s); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __BASE64_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/bitswap.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/bitswap.h deleted file mode 100644 index 2f0f74db..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/bitswap.h +++ /dev/null @@ -1,40 +0,0 @@ -/* bitswap.h - * Macro to bitswap a byte by looking it up in a table - * - * $Id: bitswap.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __BITSWAP_H__ -#define __BITSWAP_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -extern guint8 swaptab[256]; - -#define BIT_SWAP(b) (swaptab[b]) - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* bitswap.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/bridged_pids.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/bridged_pids.h deleted file mode 100644 index 5eb3a1d0..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/bridged_pids.h +++ /dev/null @@ -1,58 +0,0 @@ -/* bridged_pids.h - * Definitions of protocol IDs for the 00-80-C2 OUI, used for - * bridging various networks over ATM (RFC 2684) or Frame Relay (RFC 2427). - * - * $Id: bridged_pids.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 - 2000 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __BRIDGED_PID_H__ -#define __BRIDGED_PID_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#define BPID_ETH_WITH_FCS 0x0001 /* 802.3/Ethernet with preserved FCS */ -#define BPID_ETH_WITHOUT_FCS 0x0007 /* 802.3/Ethernet without preserved FCS */ - -#define BPID_802_4_WITH_FCS 0x0002 /* 802.4 with preserved FCS */ -#define BPID_802_4_WITHOUT_FCS 0x0008 /* 802.4 without preserved FCS */ - -#define BPID_802_5_WITH_FCS 0x0003 /* 802.5 with preserved FCS */ -#define BPID_802_5_WITHOUT_FCS 0x0009 /* 802.5 without preserved FCS */ - -#define BPID_FDDI_WITH_FCS 0x0004 /* FDDI with preserved FCS */ -#define BPID_FDDI_WITHOUT_FCS 0x000A /* FDDI without preserved FCS */ - -#define BPID_802_6_WITH_FCS 0x0005 /* 802.6 with preserved FCS */ -#define BPID_802_6_WITHOUT_FCS 0x000B /* 802.6 without preserved FCS */ - -#define BPID_FRAGMENTS 0x000D - -#define BPID_BPDU 0x000E /* 802.1(d) or 802.1(g) BPDUs */ - -#define BPID_SR_BPDU 0x000F /* Source Routing BPDUs */ - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* bridged_pid.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/camel-persistentdata.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/camel-persistentdata.h deleted file mode 100644 index ef8bfd05..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/camel-persistentdata.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * camel-persistentdata.h - * Definitions for lists and hash tables used in wireshark's camel dissector - * for calculation of delays in camel-transactions - * Copyright 2006 Florent Drouin - * - * $Id: camel-persistentdata.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __CAMEL_PERSISTENTDATA_H__ -#define __CAMEL_PERSISTENTDATA_H__ - -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#define NB_CAMELSRT_CATEGORY 9+1 /* Number of type of message */ -/* for example TC_BEGIN with InitalDP, and TC_CONT with RequestReportBCSMEvent - is a category, we want to measure the delay between the two messages */ - -#define CAMELSRT_SESSION 1 - -#define CAMELSRT_VOICE_INITIALDP 2 -#define CAMELSRT_VOICE_ACR1 3 -#define CAMELSRT_VOICE_ACR2 4 -#define CAMELSRT_VOICE_ACR3 5 -#define CAMELSRT_VOICE_DISC 6 - -#define CAMELSRT_GPRS_INITIALDP 7 -#define CAMELSRT_GPRS_REPORT 8 - -#define CAMELSRT_SMS_INITIALDP 9 - -WS_VAR_IMPORT const value_string camelSRTtype_naming[]; - -/* If we have a request message and its response, - (eg: ApplyCharging, ApplyChargingReport) - the frames numbers are stored in this structure */ - -struct camelsrt_category_t { - guint32 req_num; /* frame number request seen */ - guint32 rsp_num; /* frame number response seen */ - nstime_t req_time; /* arrival time of request */ - gboolean responded; /* true, if request has been responded */ -}; - -/* List of stored parameters for a Camel dialogue - All this parameters are linked to the hash table key below (use of Tid) - In case of same Tid reused, the Camel parameters are chained. - The right dialogue will be identified with the arrival time of the InitialDP */ - -struct camelsrt_call_t { - guint32 session_id; /* Identify the session, with an internal number */ - struct tcaphash_context_t * tcap_context; - struct camelsrt_category_t category[NB_CAMELSRT_CATEGORY]; -}; - - -/* The Key for the hash table is the TCAP origine transaction identifier - of the TC_BEGIN containing the InitialDP */ - -struct camelsrt_call_info_key_t { - guint32 SessionIdKey; -}; - -/* Info for a couple of messages (or category) - The request must be available, not duplicated, - and once the corresponding response received, - we can deduce the Delta Time between Request/response */ - -struct camelsrt_msginfo_t { - gboolean request_available; - gboolean is_duplicate; - gboolean is_delta_time; - nstime_t req_time; - nstime_t delta_time; -}; - -/* List of infos to store for the analyse */ - -struct camelsrt_info_t { - guint32 tcap_session_id; - void * tcap_context; - guint8 opcode; /* operation code of message received */ - guint8 bool_msginfo[NB_CAMELSRT_CATEGORY]; /* category for the received message */ - struct camelsrt_msginfo_t msginfo[NB_CAMELSRT_CATEGORY]; -}; - -void camelsrt_init_routine(void); - -struct camelsrt_info_t * camelsrt_razinfo(void); - -void camelsrt_call_matching(tvbuff_t *tvb, - packet_info * pinfo _U_, - proto_tree *tree, - struct camelsrt_info_t * p_camel_info); - -WS_VAR_IMPORT gboolean gcamel_StatSRT; - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* camel-persistentdata.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/charsets.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/charsets.h deleted file mode 100644 index ed50cfc3..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/charsets.h +++ /dev/null @@ -1,42 +0,0 @@ -/* charsets.h - * Routines for handling character sets - * - * $Id: charsets.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#ifndef __CHARSETS_H__ -#define __CHARSETS_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#if 0 -void ASCII_to_EBCDIC(guint8 *buf, guint bytes); -guint8 ASCII_to_EBCDIC1(guint8 c); -#endif -void EBCDIC_to_ASCII(guint8 *buf, guint bytes); -guint8 EBCDIC_to_ASCII1(guint8 c); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __CHARSETS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/chdlctypes.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/chdlctypes.h deleted file mode 100644 index 374c2d75..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/chdlctypes.h +++ /dev/null @@ -1,40 +0,0 @@ -/* chdlctypes.h - * Defines Cisco HDLC packet types that aren't just Ethernet types - * - * $Id: chdlctypes.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __CHDLCTYPES_H__ -#define __CHDLCTYPES_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#define CHDLCTYPE_FRARP 0x0808 /* Frame Relay ARP */ -#define CHDLCTYPE_BPDU 0x4242 /* IEEE spanning tree protocol */ -#define CHDLCTYPE_OSI 0xfefe /* ISO network-layer protocols */ - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* chdlctypes.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/circuit.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/circuit.h deleted file mode 100644 index c6fa6762..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/circuit.h +++ /dev/null @@ -1,80 +0,0 @@ -/* circuit.h - * Routines for building lists of packets that are part of a "circuit" - * - * $Id: circuit.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __CIRCUIT_H__ -#define __CIRCUIT_H__ - -#include "packet.h" /* for circuit dissector type */ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* - * Data structure representing a circuit. - */ -typedef struct circuit_key { - circuit_type ctype; - guint32 circuit_id; -} circuit_key; - -typedef struct circuit { - struct circuit *next; /* pointer to next circuit with given circuit ID */ - guint32 first_frame; /* # of first frame for that circuit */ - guint32 last_frame; /* # of last frame for that circuit */ - guint32 index; /* unique ID for circuit */ - GSList *data_list; /* list of data associated with circuit */ - dissector_handle_t dissector_handle; - /* handle for protocol dissector client associated with circuit */ - guint options; /* wildcard flags */ - circuit_key *key_ptr; /* pointer to the key for this circuit */ -} circuit_t; - -extern void circuit_init(void); - -extern circuit_t *circuit_new(circuit_type ctype, guint32 circuit_id, - guint32 first_frame); - -extern circuit_t *find_circuit(circuit_type ctype, guint32 circuit_id, - guint32 frame); - -extern void close_circuit(circuit_t *circuit, guint32 last_frame); - -extern void circuit_add_proto_data(circuit_t *conv, int proto, - void *proto_data); -extern void *circuit_get_proto_data(circuit_t *conv, int proto); -extern void circuit_delete_proto_data(circuit_t *conv, int proto); - -extern void circuit_set_dissector(circuit_t *circuit, - dissector_handle_t handle); -extern dissector_handle_t circuit_get_dissector(circuit_t *circuit); -extern gboolean -try_circuit_dissector(circuit_type ctype, guint32 circuit_id, guint32 frame, - tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* circuit.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/codecs.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/codecs.h deleted file mode 100644 index 928ddf34..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/codecs.h +++ /dev/null @@ -1,43 +0,0 @@ -/* codecs.h - * codecs interface 2007 Tomas Kukosa - * - * $Id: codecs.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef _CODECS_H_ -#define _CODECS_H_ - -#include "epan/epan.h" - -struct codec_handle; -typedef struct codec_handle *codec_handle_t; - -typedef void *(*codec_init_fn)(void); -typedef void (*codec_release_fn)(void *context); -typedef int (*codec_decode_fn)(void *context, const void *input, int inputSizeBytes, void *output, int *outputSizeBytes); - -extern void register_codec(const char *name, codec_init_fn init_fn, codec_release_fn release_fn, codec_decode_fn decode_fn); -extern codec_handle_t find_codec(const char *name); -extern void *codec_init(codec_handle_t codec); -extern void codec_release(codec_handle_t codec, void *context); -extern int codec_decode(codec_handle_t codec, void *context, const void *input, int inputSizeBytes, void *output, int *outputSizeBytes); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column-utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column-utils.h deleted file mode 100644 index c85aa5bf..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column-utils.h +++ /dev/null @@ -1,241 +0,0 @@ -/* column-utils.h - * Definitions for column utility structures and routines - * - * $Id: column-utils.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __COLUMN_UTILS_H__ -#define __COLUMN_UTILS_H__ - -#include - -#include "gnuc_format_check.h" -#include "column_info.h" -#include "packet_info.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/** Maximum length of columns (except COL_INFO). - * Internal, don't use this in dissectors! - */ - -#define COL_MAX_LEN 256 -/** Maximum length of info columns (COL_INFO only). - * Internal, don't use this in dissectors! - */ -#define COL_MAX_INFO_LEN 4096 - - -/** Allocate all the data structures for constructing column data, given - * the number of columns. - * - * Internal, don't use this in dissectors! - */ -extern void col_setup(column_info *cinfo, gint num_cols); - -/** Initialize the data structures for constructing column data. - * - * Internal, don't use this in dissectors! - */ -extern void col_init(column_info *cinfo); - -/** Set the format of the "variable time format". - * - * Internal, don't use this in dissectors! - */ -extern void col_set_cls_time(frame_data *, column_info *cinfo, gint col); - -/** Fill in all columns of the given packet. - * - * Internal, don't use this in dissectors! - */ -extern void col_fill_in(packet_info *pinfo); - -/* Utility routines used by packet*.c */ - -/** Are the columns writable? - * - * @param cinfo the current packet row - * @return TRUE if it's writable, FALSE if not - */ -extern gboolean col_get_writable(column_info *cinfo); - -/** Set the columns writable. - * - * @param cinfo the current packet row - * @param writable TRUE if it's writable, FALSE if not - */ -extern void col_set_writable(column_info *cinfo, gboolean writable); - -/** Check if the given column be filled with data. - * - * @param cinfo the current packet row - * @param col the column to use, e.g. COL_INFO - */ -extern gint check_col(column_info *cinfo, gint col); - -/** Sets a fence for the current column content, - * so this content won't be affected by further col_... function calls. - * - * This can be useful if a protocol is more than once in a single packet, - * e.g. multiple HTTP calls in a single TCP packet. - * - * @param cinfo the current packet row - * @param col the column to use, e.g. COL_INFO - */ -extern void col_set_fence(column_info *cinfo, gint col); - -/** Clears the text of a column element. - * - * @param cinfo the current packet row - * @param col the column to use, e.g. COL_INFO - */ -extern void col_clear(column_info *cinfo, gint col); - -/** Set (replace) the text of a column element, the text won't be copied. - * - * Usually used to set const strings! - * - * @param cinfo the current packet row - * @param col the column to use, e.g. COL_INFO - * @param str the string to set - */ -extern void col_set_str(column_info *cinfo, gint col, const gchar * str); - -/** Add (replace) the text of a column element, the text will be copied. - * - * @param cinfo the current packet row - * @param col the column to use, e.g. COL_INFO - * @param str the string to add - */ -extern void col_add_str(column_info *cinfo, gint col, const gchar *str); - -/** Add (replace) the text of a column element, the text will be formatted and copied. - * - * Same function as col_add_str() but using a printf-like format string. - * - * @param cinfo the current packet row - * @param col the column to use, e.g. COL_INFO - * @param format the format string - * @param ... the variable number of parameters - */ -extern void col_add_fstr(column_info *cinfo, gint col, const gchar *format, ...) - GNUC_FORMAT_CHECK(printf, 3, 4); - -/* For internal Wireshark use only. Not to be called from dissectors. */ -void col_custom_set_fstr(header_field_info *hfinfo, const gchar *format, ...) - GNUC_FORMAT_CHECK(printf, 2, 3); - -/* For internal Wireshark use only. Not to be called from dissectors. */ -void col_custom_prime_edt(epan_dissect_t *edt, column_info *cinfo); - -/* For internal Wireshark use only. Not to be called from dissectors. */ -gboolean have_custom_cols(column_info *cinfo); - -/** Append the given text to a column element, the text will be copied. - * - * @param cinfo the current packet row - * @param col the column to use, e.g. COL_INFO - * @param str the string to append - */ -extern void col_append_str(column_info *cinfo, gint col, const gchar *str); - -/** Append the given text to a column element, the text will be formatted and copied. - * - * Same function as col_append_str() but using a printf-like format string. - * - * @param cinfo the current packet row - * @param col the column to use, e.g. COL_INFO - * @param format the format string - * @param ... the variable number of parameters - */ -extern void col_append_fstr(column_info *cinfo, gint col, const gchar *format, ...) - GNUC_FORMAT_CHECK(printf, 3, 4); - -/** Prepend the given text to a column element, the text will be formatted and copied. - * - * @param cinfo the current packet row - * @param col the column to use, e.g. COL_INFO - * @param format the format string - * @param ... the variable number of parameters - */ -extern void col_prepend_fstr(column_info *cinfo, gint col, const gchar *format, ...) - GNUC_FORMAT_CHECK(printf, 3, 4); - -/**Prepend the given text to a column element, the text will be formatted and copied. - * This function is similar to col_prepend_fstr() but this function will - * unconditionally set a fence to the end of the prepended data even if there - * were no fence before. - * The col_prepend_fstr() will only prepend the data before the fence IFF - * there is already a fence created. This function will create a fence in case - * it does not yet exist. - */ -extern void col_prepend_fence_fstr(column_info *cinfo, gint col, const gchar *format, ...) - GNUC_FORMAT_CHECK(printf, 3, 4); - -/** Append the given text (prepended by a separator) to a column element. - * - * Much like col_append_str() but will prepend the given separator if the column isn't empty. - * - * @param cinfo the current packet row - * @param col the column to use, e.g. COL_INFO - * @param sep the separator string or NULL for default: ", " - * @param str the string to append - */ -extern void col_append_sep_str(column_info *cinfo, gint col, const gchar *sep, - const gchar *str); - -/** Append the given text (prepended by a separator) to a column element. - * - * Much like col_append_fstr() but will prepend the given separator if the column isn't empty. - * - * @param cinfo the current packet row - * @param col the column to use, e.g. COL_INFO - * @param sep the separator string or NULL for default: ", " - * @param format the format string - * @param ... the variable number of parameters - */ -extern void col_append_sep_fstr(column_info *cinfo, gint col, const gchar *sep, - const gchar *format, ...) - GNUC_FORMAT_CHECK(printf, 4, 5); - -/** Set the given (relative) time to a column element. - * - * Used by multiple dissectors to set the time in the columns - * COL_REL_CONV_TIME and COL_DELTA_CONV_TIME - * - * @param cinfo the current packet row - * @param col the column to use, e.g. COL_INFO - * @param ts the time to set in the column - * @param fieldname the fieldname to use for creating a filter (when - * applying/preparing/copying as filter) - */ -extern void col_set_time(column_info *cinfo, int col, - nstime_t *ts, char *fieldname); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __COLUMN_UTILS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column.h deleted file mode 100644 index 90fa3296..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column.h +++ /dev/null @@ -1,56 +0,0 @@ -/* column.h - * Definitions for column handling routines - * - * $Id: column.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __COLUMN_H__ -#define __COLUMN_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -typedef struct _fmt_data { - gchar *title; - gchar *fmt; - gchar *custom_field; -} fmt_data; - -const gchar *col_format_to_string(gint); -const gchar *col_format_desc(gint); -gint get_column_format(gint); -void get_column_format_matches(gboolean *, gint); -gint get_column_format_from_str(gchar *); -gchar *get_column_title(gint); -gchar *get_column_custom_field(gint); -const gchar *get_column_width_string(gint, gint); -const char *get_column_longest_string(gint); -gint get_column_char_width(gint format); - -void -build_column_format_array(capture_file *cfile, gboolean reset_fences); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* column.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column_info.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column_info.h deleted file mode 100644 index 5f70573f..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column_info.h +++ /dev/null @@ -1,134 +0,0 @@ -/* column.h - * Definitions for column structures and routines - * - * $Id: column_info.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __COLUMN_INFO_H__ -#define __COLUMN_INFO_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#define COL_MAX_LEN 256 -#define COL_MAX_INFO_LEN 4096 - -typedef struct { - gchar **col_expr; /* Filter expression */ - gchar **col_expr_val; /* Value for filter expression */ -} col_expr_t; - -typedef struct _column_info { - gint num_cols; /* Number of columns */ - gint *col_fmt; /* Format of column */ - gboolean **fmt_matx; /* Specifies which formats apply to a column */ - gint *col_first; /* First column number with a given format */ - gint *col_last; /* Last column number with a given format */ - gchar **col_title; /* Column titles */ - gchar **col_custom_field; /* Custom column field */ - const gchar **col_data; /* Column data */ - gchar **col_buf; /* Buffer into which to copy data for column */ - int *col_fence; /* Stuff in column buffer before this index is immutable */ - col_expr_t col_expr; /* Column expressions and values */ - gboolean writable; /* Are we still writing to the columns? */ - gboolean columns_changed; /* Have the columns been changed in the prefs? */ -} column_info; - -/* - * All of the possible columns in summary listing. - * - * NOTE1: The entries MUST remain in this order, or else you need to reorder - * the slist[] and dlist[] arrays in column.c to match! - * - * NOTE2: Please add the COL_XYZ entry in the appropriate spot, such that the - * dlist[] array remains in alphabetical order! - */ -enum { - COL_8021Q_VLAN_ID, /* 0) 802.1Q vlan ID */ - COL_ABS_DATE_TIME, /* 1) Absolute date and time */ - COL_ABS_TIME, /* 2) Absolute time */ - COL_CIRCUIT_ID, /* 3) Circuit ID */ - COL_DSTIDX, /* 4) Dst port idx - Cisco MDS-specific */ - COL_SRCIDX, /* 5) Src port idx - Cisco MDS-specific */ - COL_VSAN, /* 6) VSAN - Cisco MDS-specific */ - COL_CUMULATIVE_BYTES, /* 7) Cumulative number of bytes */ - COL_CUSTOM, /* 8) Custom column (any filter name's contents) */ - COL_DCE_CALL, /* 9) DCE/RPC connection oriented call id OR datagram sequence number */ - COL_DCE_CTX, /* 10) DCE/RPC connection oriented context id */ - COL_DELTA_TIME, /* 11) Delta time */ - COL_DELTA_CONV_TIME,/* 12) Delta time to last frame in conversation */ - COL_DELTA_TIME_DIS, /* 13) Delta time displayed*/ - COL_RES_DST, /* 14) Resolved dest */ - COL_UNRES_DST, /* 15) Unresolved dest */ - COL_RES_DST_PORT, /* 16) Resolved dest port */ - COL_UNRES_DST_PORT, /* 17) Unresolved dest port */ - COL_DEF_DST, /* 18) Destination address */ - COL_DEF_DST_PORT, /* 19) Destination port */ - COL_EXPERT, /* 20) Expert Info */ - COL_IF_DIR, /* 21) FW-1 monitor interface/direction */ - COL_OXID, /* 22) Fibre Channel OXID */ - COL_RXID, /* 23) Fibre Channel RXID */ - COL_FR_DLCI, /* 24) Frame Relay DLCI */ - COL_FREQ_CHAN, /* 25) IEEE 802.11 (and WiMax?) - Channel */ - COL_BSSGP_TLLI, /* 26) GPRS BSSGP IE TLLI */ - COL_HPUX_DEVID, /* 27) HP-UX Nettl Device ID */ - COL_HPUX_SUBSYS, /* 28) HP-UX Nettl Subsystem */ - COL_DEF_DL_DST, /* 29) Data link layer dest address */ - COL_DEF_DL_SRC, /* 30) Data link layer source address */ - COL_RES_DL_DST, /* 31) Resolved DL dest */ - COL_UNRES_DL_DST, /* 32) Unresolved DL dest */ - COL_RES_DL_SRC, /* 33) Resolved DL source */ - COL_UNRES_DL_SRC, /* 34) Unresolved DL source */ - COL_RSSI, /* 35) IEEE 802.11 - received signal strength */ - COL_TX_RATE, /* 36) IEEE 802.11 - TX rate in Mbps */ - COL_DSCP_VALUE, /* 37) IP DSCP Value */ - COL_INFO, /* 38) Description */ - COL_COS_VALUE, /* 39) L2 COS Value */ - COL_RES_NET_DST, /* 40) Resolved net dest */ - COL_UNRES_NET_DST, /* 41) Unresolved net dest */ - COL_RES_NET_SRC, /* 42) Resolved net source */ - COL_UNRES_NET_SRC, /* 43) Unresolved net source */ - COL_DEF_NET_DST, /* 44) Network layer dest address */ - COL_DEF_NET_SRC, /* 45) Network layer source address */ - COL_NUMBER, /* 46) Packet list item number */ - COL_PACKET_LENGTH, /* 47) Packet length in bytes */ - COL_PROTOCOL, /* 48) Protocol */ - COL_REL_TIME, /* 49) Relative time */ - COL_REL_CONV_TIME, /* 50) Relative time to beginning of conversation */ - COL_DEF_SRC, /* 51) Source address */ - COL_DEF_SRC_PORT, /* 52) Source port */ - COL_RES_SRC, /* 53) Resolved source */ - COL_UNRES_SRC, /* 54) Unresolved source */ - COL_RES_SRC_PORT, /* 55) Resolved source port */ - COL_UNRES_SRC_PORT, /* 56) Unresolved source port */ - COL_TEI, /* 57) Q.921 TEI */ - COL_CLS_TIME, /* 58) Command line-specified time (default relative) */ - NUM_COL_FMTS /* 59) Should always be last */ -}; - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __COLUMN_INFO_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/conversation.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/conversation.h deleted file mode 100644 index 988ae94b..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/conversation.h +++ /dev/null @@ -1,109 +0,0 @@ -/* conversation.h - * Routines for building lists of packets that are part of a "conversation" - * - * $Id: conversation.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __CONVERSATION_H__ -#define __CONVERSATION_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* - * Flags to pass to "conversation_new()" to indicate that the address 2 - * and/or port 2 values for the conversation should be wildcards. - * The CONVERSATION_TEMPLATE option tells that any of the other supplied - * port and / or address wildcards will be used to match an infinite number - * of new connections to the conversation(s) that have the CONVERSATION_- - * TEMPLATE flag set. Any conversation created without the CONVERSATION_- - * TEMPLATE flag will be altered once the first connections (connection - * oriented protocols only) to include the newly found information which - * matched the wildcard options. - */ -#define NO_ADDR2 0x01 -#define NO_PORT2 0x02 -#define NO_PORT2_FORCE 0x04 -#define CONVERSATION_TEMPLATE 0x08 - -/* - * Flags to pass to "find_conversation()" to indicate that the address B - * and/or port B search arguments are wildcards. - */ -#define NO_ADDR_B 0x01 -#define NO_PORT_B 0x02 - -#include "packet.h" /* for conversation dissector type */ - -/* - * Data structure representing a conversation. - */ -typedef struct conversation_key { - struct conversation_key *next; - address addr1; - address addr2; - port_type ptype; - guint32 port1; - guint32 port2; -} conversation_key; - -typedef struct conversation { - struct conversation *next; /* pointer to next conversation on hash chain */ - guint32 index; /* unique ID for conversation */ - guint32 setup_frame; /* frame number that setup this conversation */ - GSList *data_list; /* list of data associated with conversation */ - dissector_handle_t dissector_handle; - /* handle for protocol dissector client associated with conversation */ - guint options; /* wildcard flags */ - conversation_key *key_ptr; /* pointer to the key for this conversation */ -} conversation_t; - -extern void conversation_init(void); - -extern conversation_t *conversation_new(guint32 setup_frame, address *addr1, address *addr2, - port_type ptype, guint32 port1, guint32 port2, guint options); - -extern conversation_t *find_conversation(guint32 frame_num, address *addr_a, address *addr_b, - port_type ptype, guint32 port_a, guint32 port_b, guint options); - -extern void conversation_add_proto_data(conversation_t *conv, int proto, - void *proto_data); -extern void *conversation_get_proto_data(conversation_t *conv, int proto); -extern void conversation_delete_proto_data(conversation_t *conv, int proto); - -extern void conversation_set_dissector(conversation_t *conversation, - dissector_handle_t handle); -extern gboolean -try_conversation_dissector(address *addr_a, address *addr_b, port_type ptype, - guint32 port_a, guint32 port_b, tvbuff_t *tvb, packet_info *pinfo, - proto_tree *tree); - -/* These routines are used to set undefined values for a conversation */ - -extern void conversation_set_port2(conversation_t *conv, guint32 port); -extern void conversation_set_addr2(conversation_t *conv, address *addr); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* conversation.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc10.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc10.h deleted file mode 100644 index 90e8cbc6..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc10.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * crc10.h - * - * $Id: crc10.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -/* update the data block's CRC-10 remainder one byte at a time */ -extern guint16 update_crc10_by_bytes(guint16 crc10, const guint8 *data_blk_ptr, int data_blk_size); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc16.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc16.h deleted file mode 100644 index 445b9430..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc16.h +++ /dev/null @@ -1,109 +0,0 @@ -/* crc16.h - * Declaration of CRC-16 routines and table - * - * 2004 Richard van der Hoff - * - * $Id: crc16.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * Copied from README.developer - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#ifndef __CRC16_H_ -#define __CRC16_H_ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* Calculate the CCITT/ITU/CRC-16 16-bit CRC - - (parameters for this CRC are: - Polynomial: x^16 + x^12 + x^5 + 1 (0x1021); - Start value 0xFFFF; - XOR result with 0xFFFF; - First bit is LSB) -*/ - -/** Compute CRC16 CCITT checksum of a buffer of data. - @param buf The buffer containing the data. - @param len The number of bytes to include in the computation. - @return The CRC16 CCITT checksum. */ -extern guint16 crc16_ccitt(const guint8 *buf, guint len); - -/** Compute CRC16 X.25 CCITT checksum of a buffer of data. - @param buf The buffer containing the data. - @param len The number of bytes to include in the computation. - @return The CRC16 X.25 CCITT checksum. */ -extern guint16 crc16_x25_ccitt(const guint8 *buf, guint len); - -/** Compute CRC16 CCITT checksum of a buffer of data. If computing the - * checksum over multiple buffers and you want to feed the partial CRC16 - * back in, remember to take the 1's complement of the partial CRC16 first. - @param buf The buffer containing the data. - @param len The number of bytes to include in the computation. - @param seed The seed to use. - @return The CRC16 CCITT checksum (using the given seed). */ -extern guint16 crc16_ccitt_seed(const guint8 *buf, guint len, guint16 seed); - -/** Compute CRC16 CCITT checksum of a tv buffer. - @param tvb The tv buffer containing the data. - @param len The number of bytes to include in the computation. - @return The CRC16 CCITT checksum. */ -extern guint16 crc16_ccitt_tvb(tvbuff_t *tvb, guint len); - -/** Compute CRC16 X.25 CCITT checksum of a tv buffer. - @param tvb The tv buffer containing the data. - @param len The number of bytes to include in the computation. - @return The CRC16 X.25 CCITT checksum. */ -extern guint16 crc16_x25_ccitt_tvb(tvbuff_t *tvb, guint len); - -/** Compute CRC16 CCITT checksum of a tv buffer. - @param tvb The tv buffer containing the data. - @param offset The offset into the tv buffer. - @param len The number of bytes to include in the computation. - @return The CRC16 CCITT checksum. */ -extern guint16 crc16_ccitt_tvb_offset(tvbuff_t *tvb, guint offset, guint len); - -/** Compute CRC16 CCITT checksum of a tv buffer. If computing the - * checksum over multiple tv buffers and you want to feed the partial CRC16 - * back in, remember to take the 1's complement of the partial CRC16 first. - @param tvb The tv buffer containing the data. - @param len The number of bytes to include in the computation. - @param seed The seed to use. - @return The CRC16 CCITT checksum (using the given seed). */ -extern guint16 crc16_ccitt_tvb_seed(tvbuff_t *tvb, guint len, guint16 seed); - -/** Compute CRC16 CCITT checksum of a tv buffer. If computing the - * checksum over multiple tv buffers and you want to feed the partial CRC16 - * back in, remember to take the 1's complement of the partial CRC16 first. - @param tvb The tv buffer containing the data. - @param offset The offset into the tv buffer. - @param len The number of bytes to include in the computation. - @param seed The seed to use. - @return The CRC16 CCITT checksum (using the given seed). */ -extern guint16 crc16_ccitt_tvb_offset_seed(tvbuff_t *tvb, guint offset, - guint len, guint16 seed); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* crc16.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc32.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc32.h deleted file mode 100644 index 72f4abbe..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc32.h +++ /dev/null @@ -1,94 +0,0 @@ -/* crc32.h - * Declaration of CRC-32 routine and table - * - * $Id: crc32.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * Copied from README.developer - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __CRC32_H_ -#define __CRC32_H_ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -extern const guint32 crc32_ccitt_table[256]; - -/** Compute CRC32 CCITT checksum of a buffer of data. - @param buf The buffer containing the data. - @param len The number of bytes to include in the computation. - @return The CRC32 CCITT checksum. */ -extern guint32 crc32_ccitt(const guint8 *buf, guint len); - -/** Compute CRC32 CCITT checksum of a buffer of data. If computing the - * checksum over multiple buffers and you want to feed the partial CRC32 - * back in, remember to take the 1's complement of the partial CRC32 first. - @param buf The buffer containing the data. - @param len The number of bytes to include in the computation. - @param seed The seed to use. - @return The CRC32 CCITT checksum (using the given seed). */ -extern guint32 crc32_ccitt_seed(const guint8 *buf, guint len, guint32 seed); - -/** Compute CRC32 CCITT checksum of a tv buffer. - @param tvb The tv buffer containing the data. - @param len The number of bytes to include in the computation. - @return The CRC32 CCITT checksum. */ -extern guint32 crc32_ccitt_tvb(tvbuff_t *tvb, guint len); - -/** Compute CRC32 CCITT checksum of a tv buffer. - @param tvb The tv buffer containing the data. - @param offset The offset into the tv buffer. - @param len The number of bytes to include in the computation. - @return The CRC32 CCITT checksum. */ -extern guint32 crc32_ccitt_tvb_offset(tvbuff_t *tvb, guint offset, guint len); - -/** Compute CRC32 CCITT checksum of a tv buffer. If computing the - * checksum over multiple tv buffers and you want to feed the partial CRC32 - * back in, remember to take the 1's complement of the partial CRC32 first. - @param tvb The tv buffer containing the data. - @param len The number of bytes to include in the computation. - @param seed The seed to use. - @return The CRC32 CCITT checksum (using the given seed). */ -extern guint32 crc32_ccitt_tvb_seed(tvbuff_t *tvb, guint len, guint32 seed); - -/** Compute CRC32 CCITT checksum of a tv buffer. If computing the - * checksum over multiple tv buffers and you want to feed the partial CRC32 - * back in, remember to take the 1's complement of the partial CRC32 first. - @param tvb The tv buffer containing the data. - @param offset The offset into the tv buffer. - @param len The number of bytes to include in the computation. - @param seed The seed to use. - @return The CRC32 CCITT checksum (using the given seed). */ -extern guint32 crc32_ccitt_tvb_offset_seed(tvbuff_t *tvb, guint offset, - guint len, guint32 seed); - -/** Compute IEEE 802.x CRC32 checksum of a tv buffer. - @param tvb The tv buffer containing the data. - @param len The number of bytes to include in the computation. - @return The IEEE 802.x CRC32 checksum. */ -extern guint32 crc32_802_tvb(tvbuff_t *tvb, guint len); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* crc32.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc6.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc6.h deleted file mode 100644 index cb295faa..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc6.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * crc6.h - * - * $Id: crc6.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -extern guint16 update_crc6_by_bytes(guint16 crc6, guint8 byte1, guint8 byte2); - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crcdrm.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crcdrm.h deleted file mode 100644 index 0987f50f..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crcdrm.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _CRCDRM_H - -#include - -unsigned long crc_drm(const char *data, size_t bytesize, - unsigned short num_crc_bits, unsigned long crc_gen, int invert); -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_debug.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_debug.h deleted file mode 100644 index 849c6662..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_debug.h +++ /dev/null @@ -1,106 +0,0 @@ -/* airpcap_debug.h - * - * $Id: airpdcap_debug.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Copyright (c) 2006 CACE Technologies, Davis (California) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _AIRPDCAP_DEBUG_H -#define _AIRPDCAP_DEBUG_H - -#include "airpdcap_interop.h" - -void print_debug_line(CHAR *function, CHAR *msg, INT level); - -#ifdef _DEBUG -#ifdef __FUNCTION__ -#define AIRPDCAP_DEBUG_PRINT_LINE(notdefined, msg, level) print_debug_line(__FUNCTION__, msg, level); -#else -#define AIRPDCAP_DEBUG_PRINT_LINE(function, msg, level) print_debug_line(function, msg, level); -#endif -#else -#ifdef __FUNCTION__ -#define AIRPDCAP_DEBUG_PRINT_LINE(notdefined, msg, level) -#else -#define AIRPDCAP_DEBUG_PRINT_LINE(function, msg, level) -#endif -#endif - -/******************************************************************************/ -/* Debug section: internal function to print debug information */ -/* */ -#ifdef _DEBUG -#include "stdio.h" -#include - -/* Debug level definition */ -#define AIRPDCAP_DEBUG_LEVEL_1 1 -#define AIRPDCAP_DEBUG_LEVEL_2 2 -#define AIRPDCAP_DEBUG_LEVEL_3 3 -#define AIRPDCAP_DEBUG_LEVEL_4 4 -#define AIRPDCAP_DEBUG_LEVEL_5 5 - -#define AIRPDCAP_DEBUG_USED_LEVEL AIRPDCAP_DEBUG_LEVEL_3 - -#ifdef _TRACE -#ifdef __FUNCTION__ -#define AIRPDCAP_DEBUG_TRACE_START(notdefined) print_debug_line(__FUNCTION__, "Start!", AIRPDCAP_DEBUG_USED_LEVEL); -#define AIRPDCAP_DEBUG_TRACE_END(notdefined) print_debug_line(__FUNCTION__, "End!", AIRPDCAP_DEBUG_USED_LEVEL); -#else -#define AIRPDCAP_DEBUG_TRACE_START(function) print_debug_line(function, "Start!", AIRPDCAP_DEBUG_USED_LEVEL); -#define AIRPDCAP_DEBUG_TRACE_END(function) print_debug_line(function, "End!", AIRPDCAP_DEBUG_USED_LEVEL); -#endif -#else -#ifdef __FUNCTION__ -#define AIRPDCAP_DEBUG_TRACE_START(notdefined) -#define AIRPDCAP_DEBUG_TRACE_END(notdefined) -#else -#define AIRPDCAP_DEBUG_TRACE_START(function) -#define AIRPDCAP_DEBUG_TRACE_END(function) -#endif -#endif - -#else /* !defined _DEBUG */ - -#define AIRPDCAP_DEBUG_LEVEL_1 -#define AIRPDCAP_DEBUG_LEVEL_2 -#define AIRPDCAP_DEBUG_LEVEL_3 -#define AIRPDCAP_DEBUG_LEVEL_4 -#define AIRPDCAP_DEBUG_LEVEL_5 - -#define AIRPDCAP_DEBUG_TRACE_START(function) -#define AIRPDCAP_DEBUG_TRACE_END(function) - -#endif /* ?defined _DEBUG */ - - -#endif /* ?defined _AIRPDCAP_DEBUG_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_int.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_int.h deleted file mode 100644 index b3d4a75b..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_int.h +++ /dev/null @@ -1,158 +0,0 @@ -/* airpcap_int.h - * - * $Id: airpdcap_int.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Copyright (c) 2006 CACE Technologies, Davis (California) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _AIRPDCAP_INT_H -#define _AIRPDCAP_INT_H - -/****************************************************************************/ -/* File includes */ - -#include "airpdcap_interop.h" - -/****************************************************************************/ - -/****************************************************************************/ -/* Definitions */ - -/* IEEE 802.11 packet type values */ -#define AIRPDCAP_TYPE_MANAGEMENT 0 -#define AIRPDCAP_TYPE_CONTROL 1 -#define AIRPDCAP_TYPE_DATA 2 - -/* Min length of encrypted data (TKIP=25bytes, CCMP=21bytes) */ -#define AIRPDCAP_CRYPTED_DATA_MINLEN 21 - -#define AIRPDCAP_TA_OFFSET 10 - -/* */ -/****************************************************************************/ - -/****************************************************************************/ -/* Macro definitions */ - -/** - * Macros to get various bits of a 802.11 control frame - */ -#define AIRPDCAP_TYPE(FrameControl_0) (UINT8)((FrameControl_0 >> 2) & 0x3) -#define AIRPDCAP_SUBTYPE(FrameControl_0) (UINT8)((FrameControl_0 >> 4) & 0xF) -#define AIRPDCAP_DS_BITS(FrameControl_1) (UINT8)(FrameControl_1 & 0x3) -#define AIRPDCAP_TO_DS(FrameControl_1) (UINT8)(FrameControl_1 & 0x1) -#define AIRPDCAP_FROM_DS(FrameControl_1) (UINT8)((FrameControl_1 >> 1) & 0x1) -#define AIRPDCAP_WEP(FrameControl_1) (UINT8)((FrameControl_1 >> 6) & 0x1) - -/** - * Get the Key ID from the Initialization Vector (last byte) - */ -#define AIRPDCAP_EXTIV(KeyID) ((KeyID >> 5) & 0x1) - -/* Macros to get various bits of an EAPOL frame */ -#define AIRPDCAP_EAP_KEY_DESCR_VER(KeyInfo_1) ((UCHAR)(KeyInfo_1 & 0x3)) -#define AIRPDCAP_EAP_KEY(KeyInfo_1) ((KeyInfo_1 >> 3) & 0x1) -#define AIRPDCAP_EAP_INST(KeyInfo_1) ((KeyInfo_1 >> 6) & 0x1) -#define AIRPDCAP_EAP_ACK(KeyInfo_1) ((KeyInfo_1 >> 7) & 0x1) -#define AIRPDCAP_EAP_MIC(KeyInfo_0) (KeyInfo_0 & 0x1) -#define AIRPDCAP_EAP_SEC(KeyInfo_0) ((KeyInfo_0 >> 1) & 0x1) - -/* Note: copied from net80211/ieee80211_airpdcap_tkip.c */ -#define S_SWAP(a,b) { UINT8 t = S[a]; S[a] = S[b]; S[b] = t; } - -/****************************************************************************/ - -/****************************************************************************/ -/* Structure definitions */ - -/* - * XXX - According to the thread at - * http://www.wireshark.org/lists/wireshark-dev/200612/msg00384.html we - * shouldn't have to worry about packing our structs, since the largest - * elements are 8 bits wide. - */ -#ifdef _MSC_VER /* MS Visual C++ */ -#pragma pack(push) -#pragma pack(1) -#endif - -/* Definition of IEEE 802.11 frame (without the address 4) */ -typedef struct _AIRPDCAP_MAC_FRAME { - UCHAR fc[2]; - UCHAR dur[2]; - UCHAR addr1[AIRPDCAP_MAC_LEN]; - UCHAR addr2[AIRPDCAP_MAC_LEN]; - UCHAR addr3[AIRPDCAP_MAC_LEN]; - UCHAR seq[2]; -} AIRPDCAP_MAC_FRAME, *PAIRPDCAP_MAC_FRAME; - -/* Definition of IEEE 802.11 frame (with the address 4) */ -typedef struct _AIRPDCAP_MAC_FRAME_ADDR4 { - UCHAR fc[2]; - UCHAR dur[2]; - UCHAR addr1[AIRPDCAP_MAC_LEN]; - UCHAR addr2[AIRPDCAP_MAC_LEN]; - UCHAR addr3[AIRPDCAP_MAC_LEN]; - UCHAR seq[2]; - UCHAR addr4[AIRPDCAP_MAC_LEN]; -} AIRPDCAP_MAC_FRAME_ADDR4, *PAIRPDCAP_MAC_FRAME_ADDR4; - -/* Definition of IEEE 802.11 frame (without the address 4, with QOS) */ -typedef struct _AIRPDCAP_MAC_FRAME_QOS { - UCHAR fc[2]; - UCHAR dur[2]; - UCHAR addr1[AIRPDCAP_MAC_LEN]; - UCHAR addr2[AIRPDCAP_MAC_LEN]; - UCHAR addr3[AIRPDCAP_MAC_LEN]; - UCHAR seq[2]; - UCHAR qos[2]; -} AIRPDCAP_MAC_FRAME_QOS, *PAIRPDCAP_MAC_FRAME_QOS; - -/* Definition of IEEE 802.11 frame (with the address 4 and QOS) */ -typedef struct _AIRPDCAP_MAC_FRAME_ADDR4_QOS { - UCHAR fc[2]; - UCHAR dur[2]; - UCHAR addr1[AIRPDCAP_MAC_LEN]; - UCHAR addr2[AIRPDCAP_MAC_LEN]; - UCHAR addr3[AIRPDCAP_MAC_LEN]; - UCHAR seq[2]; - UCHAR addr4[AIRPDCAP_MAC_LEN]; - UCHAR qos[2]; -} AIRPDCAP_MAC_FRAME_ADDR4_QOS, *PAIRPDCAP_MAC_FRAME_ADDR4_QOS; - -#ifdef _MSC_VER /* MS Visual C++ */ -#pragma pack(pop) -#endif - -/******************************************************************************/ - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_interop.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_interop.h deleted file mode 100644 index 9d693fb9..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_interop.h +++ /dev/null @@ -1,101 +0,0 @@ -/* airpdcap_interop.h - * - * $Id: airpdcap_interop.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Copyright (c) 2006 CACE Technologies, Davis (California) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _AIRPDCAP_INTEROP_H -#define _AIRPDCAP_INTEROP_H - -/** - * Cast data types commonly used (e.g. UINT16) to their - * GLib equivalents. - */ - -#include -#include - -#ifndef INT -typedef gint INT; -#endif - -#ifndef UINT -typedef guint UINT; -#endif - -#ifndef UINT8 -typedef guint8 UINT8; -#endif - -#ifndef UINT16 -typedef guint16 UINT16; -#endif - -#ifndef UINT32 -typedef guint32 UINT32; -#endif - -#ifndef UINT64 -typedef guint64 UINT64; -#endif - -#ifndef USHORT -typedef gushort USHORT; -#endif - -#ifndef ULONG -typedef gulong ULONG; -#endif - -#ifndef ULONGLONG -typedef guint64 ULONGLONG; -#endif - -#ifndef CHAR -typedef gchar CHAR; -#endif - -#ifndef UCHAR -typedef guchar UCHAR; -#endif - -#ifdef _WIN32 -#include /* ntohs() */ -#endif - -#ifndef ntohs -#undef ntohs -#define ntohs(value) g_ntohs(value) -#endif - -#endif /* _AIRPDCAP_INTEROP_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_rijndael.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_rijndael.h deleted file mode 100644 index b031d790..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_rijndael.h +++ /dev/null @@ -1,93 +0,0 @@ -/** - * airpdcap_rijndael.h - * - * $Id: airpdcap_rijndael.h 3992 2008-06-10 03:13:11Z dgu $ - * - * @version 3.0 (December 2000) - * - * Optimised ANSI C code for the Rijndael cipher (now AES) - * - * @author Vincent Rijmen - * @author Antoon Bosselaers - * @author Paulo Barreto - * - * This code is hereby placed in the public domain. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _AIRPDCAP_RIJNDAEL -#define _AIRPDCAP_RIJNDAEL - -/******************************************************************************/ -/* File includes */ -/* */ -#include "airpdcap_interop.h" -/* */ -/* */ -/******************************************************************************/ - -/******************************************************************************/ -/* Definitions */ -/* */ -/* Note: copied AirPDcap/rijndael/rijndael.h */ -#define RIJNDAEL_MAXKC (256/32) -#define RIJNDAEL_MAXKB (256/8) -#define RIJNDAEL_MAXNR 14 -/* */ -/******************************************************************************/ - -/******************************************************************************/ -/* Type definitions */ -/* */ -/* Note: copied AirPDcap/rijndael/rijndael.h */ -typedef struct s_rijndael_ctx { - INT decrypt; - INT Nr; /* key-length-dependent number of rounds */ - UINT32 ek[4 * (RIJNDAEL_MAXNR + 1)]; /* encrypt key schedule */ - UINT32 dk[4 * (RIJNDAEL_MAXNR + 1)]; /* decrypt key schedule */ -} rijndael_ctx; -/* */ -/******************************************************************************/ - -/******************************************************************************/ -/* External function prototypes declarations */ -/* */ -void rijndael_encrypt( - const rijndael_ctx *ctx, - const UCHAR *src, - UCHAR *dst) - ; - - -void rijndael_set_key( - rijndael_ctx *ctx, - const UCHAR *key, - INT bits) - ; -/* */ -/******************************************************************************/ - -/******************************************************************************/ -/* Block XOR macro definition */ -/* */ -#define XOR_BLOCK(b, a, len) \ - { \ - INT i; \ - for (i = 0; i < (INT)(len); i++) \ - (b)[i] ^= (a)[i]; \ - } -/* */ -/******************************************************************************/ - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_system.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_system.h deleted file mode 100644 index 392d5d19..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_system.h +++ /dev/null @@ -1,356 +0,0 @@ -/* airpdcap_system.h - * - * $Id: airpdcap_system.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Copyright (c) 2006 CACE Technologies, Davis (California) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _AIRPDCAP_SYSTEM_H -#define _AIRPDCAP_SYSTEM_H - -/************************************************************************/ -/* File includes */ - -#include "airpdcap_interop.h" -#include "airpdcap_user.h" - -/************************************************************************/ -/* Constant definitions */ - -/* General definitions */ -#ifndef TRUE -#define TRUE 1 -#endif -#ifndef FALSE -#define FALSE 0 -#endif - -#define AIRPDCAP_RET_SUCCESS 0 -#define AIRPDCAP_RET_UNSUCCESS 1 - -#define AIRPDCAP_RET_NO_DATA 1 -#define AIRPDCAP_RET_WRONG_DATA_SIZE 2 -#define AIRPDCAP_RET_REQ_DATA 3 -#define AIRPDCAP_RET_NO_VALID_HANDSHAKE 4 -#define AIRPDCAP_RET_NO_DATA_ENCRYPTED 5 - -#define AIRPDCAP_RET_SUCCESS_HANDSHAKE -1 - -#define AIRPDCAP_MAX_KEYS_NR 64 -#define AIRPDCAP_MAX_SEC_ASSOCIATIONS_NR 256 - -/* Decryption algorithms fields size definition (bytes) */ -#define AIRPDCAP_WPA_NONCE_LEN 32 -#define AIRPDCAP_WPA_PTK_LEN 64 /* TKIP uses 48 bytes, CCMP uses 64 bytes */ -#define AIRPDCAP_WPA_MICKEY_LEN 16 - -#define AIRPDCAP_WEP_128_KEY_LEN 16 /* 128 bits */ - -/* General 802.11 constants */ -#define AIRPDCAP_MAC_LEN 6 -#define AIRPDCAP_RADIOTAP_HEADER_LEN 24 - -#define AIRPDCAP_EAPOL_MAX_LEN 1024 - -#define AIRPDCAP_TK_LEN 16 - -/* Max length of capture data */ -#define AIRPDCAP_MAX_CAPLEN 8192 - -#define AIRPDCAP_WEP_IVLEN 3 /* 24bit */ -#define AIRPDCAP_WEP_KIDLEN 1 /* 1 octet */ -#define AIRPDCAP_WEP_ICV 4 -#define AIRPDCAP_WEP_HEADER AIRPDCAP_WEP_IVLEN + AIRPDCAP_WEP_KIDLEN -#define AIRPDCAP_WEP_TRAILER AIRPDCAP_WEP_ICV - -/* - * 802.11i defines an extended IV for use with non-WEP ciphers. - * When the EXTIV bit is set in the key id byte an additional - * 4 bytes immediately follow the IV for TKIP. For CCMP the - * EXTIV bit is likewise set but the 8 bytes represent the - * CCMP header rather than IV+extended-IV. - */ -#define AIRPDCAP_RSNA_EXTIV 0x20 -#define AIRPDCAP_RSNA_EXTIVLEN 4 /* extended IV length */ -#define AIRPDCAP_RSNA_MICLEN 8 /* trailing MIC */ - -#define AIRPDCAP_RSNA_HEADER AIRPDCAP_WEP_HEADER + AIRPDCAP_RSNA_EXTIVLEN - -#define AIRPDCAP_CCMP_HEADER AIRPDCAP_RSNA_HEADER -#define AIRPDCAP_CCMP_TRAILER AIRPDCAP_RSNA_MICLEN - -#define AIRPDCAP_TKIP_HEADER AIRPDCAP_RSNA_HEADER -#define AIRPDCAP_TKIP_TRAILER AIRPDCAP_RSNA_MICLEN + AIRPDCAP_WEP_ICV - -#define AIRPDCAP_CRC_LEN 4 - -/************************************************************************/ -/* Macro definitions */ - -/************************************************************************/ -/* Type definitions */ - -typedef struct _AIRPDCAP_SEC_ASSOCIATION_ID { - UCHAR bssid[AIRPDCAP_MAC_LEN]; - UCHAR sta[AIRPDCAP_MAC_LEN]; -} AIRPDCAP_SEC_ASSOCIATION_ID, *PAIRPDCAP_SEC_ASSOCIATION_ID; - -typedef struct _AIRPDCAP_SEC_ASSOCIATION { - /** - * This flag define whether this item is used or not. Accepted - * values are TRUE and FALSE - */ - UINT8 used; - AIRPDCAP_SEC_ASSOCIATION_ID saId; - AIRPDCAP_KEY_ITEM *key; - UINT8 handshake; - UINT8 validKey; - - struct { - UINT8 key_ver; /* Key descriptor version */ - UINT64 pn; /* only used with CCMP AES -if needed replay check- */ - UCHAR nonce[AIRPDCAP_WPA_NONCE_LEN]; - /* used to derive PTK, ANonce stored, SNonce taken */ - /* the 2nd packet of the 4W handshake */ - - UCHAR ptk[AIRPDCAP_WPA_PTK_LEN]; /* session key used in decryption algorithm */ - } wpa; -} AIRPDCAP_SEC_ASSOCIATION, *PAIRPDCAP_SEC_ASSOCIATION; - -typedef struct _AIRPDCAP_CONTEXT { - AIRPDCAP_SEC_ASSOCIATION sa[AIRPDCAP_MAX_SEC_ASSOCIATIONS_NR]; - INT sa_index; - AIRPDCAP_KEY_ITEM keys[AIRPDCAP_MAX_KEYS_NR]; - size_t keys_nr; - - CHAR pkt_ssid[AIRPDCAP_WPA_SSID_MAX_LEN]; - size_t pkt_ssid_len; - - INT index; - INT first_free_index; -} AIRPDCAP_CONTEXT, *PAIRPDCAP_CONTEXT; - -/************************************************************************/ -/* Function prototype declarations */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Given an 802.11 packet, either extract its key data (in the case of - * WPA handshaking) or try to decrypt it. - * @param ctx [IN] Pointer to the current context - * @param data [IN] Pointer to a buffer with an 802.11 frame, including MAC - * header and payload - * @param data_off [IN] Payload offset (aka the MAC header length) - * @param data_len [IN] Total length of the MAC header and the payload - * @param decrypt_data [OUT] Pointer to a buffer that will contain - * decrypted data - * @param decrypt_len [OUT] Length of decrypted data - * @param key [OUT] Pointer to a preallocated key structure containing - * the key used during the decryption process (if done). If this parameter - * is set to NULL, the key will be not returned. - * @param mngHandshake [IN] If TRUE this function will manage the 4-way - * handshake for WPA/WPA2 - * @param mngDecrypt [IN] If TRUE this function will manage the WEP or - * WPA/WPA2 decryption - * @return - * - AIRPDCAP_RET_SUCCESS: Decryption has been done (decrypt_data and - * decrypt_length will contain the packet data decrypted and the length of - * the new packet) - * - AIRPDCAP_RET_SUCCESS_HANDSHAKE: A step of the 4-way handshake for - * WPA key has been successfully done - * - AIRPDCAP_RET_NO_DATA: The packet is not a data packet - * - AIRPDCAP_RET_WRONG_DATA_SIZE: The size of the packet is below the - * accepted minimum - * - AIRPDCAP_RET_REQ_DATA: Required data is not available and the - * processing must be interrupted - * - AIRPDCAP_RET_NO_VALID_HANDSHAKE: The authentication is not for WPA or RSNA - * - AIRPDCAP_RET_NO_DATA_ENCRYPTED: No encrypted data - * - AIRPDCAP_RET_UNSUCCESS: No decryption has been done (decrypt_data - * and decrypt_length will be not modified). - * Some other errors could be: - * data not correct - * data not encrypted - * key handshake, not encryption - * decryption not successful - * key handshake not correct - * replay check not successful - * @note - * The decrypted buffer should be allocated for a size equal or greater - * than the packet data buffer size. Before decryption process original - * data is copied in the buffer pointed by decrypt_data not to modify the - * original packet. - * @note - * The length of decrypted data will consider the entire 802.11 frame - * (thus the MAC header, the frame body and the recalculated FCS -if - * initially present-) - * @note - * This function is not thread-safe when used in parallel with context - * management functions on the same context. - */ -extern INT AirPDcapPacketProcess( - PAIRPDCAP_CONTEXT ctx, - const guint8 *data, - const guint data_off, - const guint data_len, - UCHAR *decrypt_data, - guint32 *decrypt_len, - PAIRPDCAP_KEY_ITEM key, - gboolean mngHandshake, - gboolean mngDecrypt) - ; - -/** - * It sets a new keys collection to use during packet processing. - * Any key should be well-formed, thus: it should have a defined key - * type and the specified length should be conforming WEP or WPA/WPA2 - * standards. A general WEP keys could be of any length (in the range - * defined in AIRPDCAP_KEY_ITEM), if a specific WEP key is used, the - * length of the key will be the one specified in 802.11i-2004 (40 bits or - * 104 bits). - * For WPA/WPA2 the password (passphrase and SSID), the PSK and the PMK - * are in alternative, as explain in the AIRPDCAP_KEY_ITEM structure - * description. - * @param ctx [IN] pointer to the current context - * @param keys [IN] an array of keys to set. - * @param keys_nr [IN] the size of the keys array - * @return The number of keys correctly inserted in the current database. - * @note Before inserting new keys, the current database will be cleaned. - * @note - * This function is not thread-safe when used in parallel with context - * management functions and the packet process function on the same - * context. - */ -extern INT AirPDcapSetKeys( - PAIRPDCAP_CONTEXT ctx, - AIRPDCAP_KEY_ITEM keys[], - const size_t keys_nr) - ; - -/** - * It gets the keys collection fom the specified context. - * @param ctx [IN] pointer to the current context - * @param key [IN] a preallocated array of keys to be returned - * @param keys_nr [IN] the number of keys to return (the key array must - * be able to contain at least keys_nr keys) - * @return The number of keys returned - * @note - * Any key could be modified, as stated in the AIRPDCAP_KEY_ITEM description. - * @note - * This function is not thread-safe when used in parallel with context - * management functions and the packet process function on the same - * context. - */ -INT AirPDcapGetKeys( - const PAIRPDCAP_CONTEXT ctx, - AIRPDCAP_KEY_ITEM keys[], - const size_t keys_nr) - ; - -/** - * Sets the "last seen" SSID. This allows us to pick up previous - * SSIDs and use them when "wildcard" passphrases are specified - * in the preferences. - * @param ctx [IN|OUT] pointer to a preallocated context structure - * @param pkt_ssid [IN] pointer to the packet's SSID - * @param pkt_ssid_len [IN] length of the packet's SSID - * @return - * AIRPDCAP_RET_SUCCESS: The key has been set. - * AIRPDCAP_RET_UNSUCCESS: The has not been set, e.g. the length was - * too long. - */ -INT AirPDcapSetLastSSID( - PAIRPDCAP_CONTEXT ctx, - CHAR *pkt_ssid, - size_t pkt_ssid_len) - ; - -/** - * Initialize a context used to manage decryption and keys collection. - * @param ctx [IN|OUT] pointer to a preallocated context structure - * @return - * AIRPDCAP_RET_SUCCESS: the context has been successfully initialized - * AIRPDCAP_RET_UNSUCCESS: the context has not been initialized - * @note - * Only a correctly initialized context can be used to manage decryption - * processes and keys. - * @note - * This function is not thread-safe when used in parallel with context - * management functions and the packet process function on the same context. - */ -INT AirPDcapInitContext( - PAIRPDCAP_CONTEXT ctx) - ; - -/** - * Clean up the specified context. After the cleanup the pointer should - * not be used anymore. - * @param ctx [IN|OUT] pointer to the current context structure - * @return - * AIRPDCAP_RET_SUCCESS: the context has been successfully initialized - * AIRPDCAP_RET_UNSUCCESS: the context has not been initialized - * @note - * This function is not thread-safe when used in parallel with context - * management functions and the packet process function on the same - * context. - */ -INT AirPDcapDestroyContext( - PAIRPDCAP_CONTEXT ctx) - ; - - -extern INT AirPDcapWepDecrypt( - const UCHAR *seed, - const size_t seed_len, /* max AIRPDCAP_KEYBUF_SIZE */ - UCHAR *cypher_text, - const size_t data_len) - ; -extern INT AirPDcapCcmpDecrypt( - UINT8 *m, - gint mac_header_len, - INT len, - UCHAR TK1[16]) - ; -extern INT AirPDcapTkipDecrypt( - UCHAR *tkip_mpdu, - size_t mpdu_len, - UCHAR TA[AIRPDCAP_MAC_LEN], - UCHAR TK[AIRPDCAP_TK_LEN]) - ; - -#ifdef __cplusplus -} -#endif - -#endif /* _AIRPDCAP_SYSTEM_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_user.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_user.h deleted file mode 100644 index 0cf1a5b8..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_user.h +++ /dev/null @@ -1,231 +0,0 @@ -/* airpdcap_user.h - * - * $Id: airpdcap_user.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Copyright (c) 2006 CACE Technologies, Davis (California) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _AIRPDCAP_USER_H -#define _AIRPDCAP_USER_H - -/******************************************************************************/ -/* File includes */ -/* */ -#include "airpdcap_interop.h" -/* */ -/* */ -/******************************************************************************/ - -/******************************************************************************/ -/* Constant definitions */ -/* */ -/* Decryption key types */ -#define AIRPDCAP_KEY_TYPE_WEP 0 -#define AIRPDCAP_KEY_TYPE_WEP_40 1 -#define AIRPDCAP_KEY_TYPE_WEP_104 2 -#define AIRPDCAP_KEY_TYPE_WPA_PWD 3 -#define AIRPDCAP_KEY_TYPE_WPA_PSK 4 -#define AIRPDCAP_KEY_TYPE_WPA_PMK 5 -#define AIRPDCAP_KEY_TYPE_TKIP 6 -#define AIRPDCAP_KEY_TYPE_CCMP 7 - -/* Decryption algorithms fields size definition (bytes) */ -#define AIRPDCAP_WEP_KEY_MINLEN 1 -#define AIRPDCAP_WEP_KEY_MAXLEN 32 -#define AIRPDCAP_WEP_40_KEY_LEN 5 -#define AIRPDCAP_WEP_104_KEY_LEN 13 - -#define AIRPDCAP_WPA_PASSPHRASE_MIN_LEN 8 -#define AIRPDCAP_WPA_PASSPHRASE_MAX_LEN 63 /* null-terminated string, the actual length of the storage is 64 */ -#define AIRPDCAP_WPA_SSID_MIN_LEN 0 -#define AIRPDCAP_WPA_SSID_MAX_LEN 32 -#define AIRPDCAP_WPA_PSK_LEN 64 -#define AIRPDCAP_WPA_PMK_LEN 32 -/* */ -/* */ -/******************************************************************************/ - -/******************************************************************************/ -/* Macro definitions */ -/* */ -/* */ -/******************************************************************************/ - -/******************************************************************************/ -/* Type definitions */ -/* */ -/** - * Struct to store info about a specific decryption key. - */ -typedef struct { - GString *key; - GByteArray *ssid; - guint bits; - guint type; -} decryption_key_t; - -/** - * Key item used during the decryption process. - */ -typedef struct _AIRPDCAP_KEY_ITEM { - /** - * Type of key. The type will remain unchanged during the - * processing, even if some fields could be changed (e.g., WPA - * fields). - * @note - * You can use constants AIRPDCAP_KEY_TYPE_xxx to indicate the - * key type. - */ - UINT8 KeyType; - - /** - * Key data. - * This field can be used for the following decryptographic - * algorithms: WEP-40, with a key of 40 bits (10 hex-digits); - * WEP-104, with a key of 104 bits (or 26 hex-digits); WPA or - * WPA2. - * @note - * For WPA/WPA2, the PMK is calculated from the PSK, and the PSK - * is calculated from the passphrase-SSID pair. You can enter one - * of these 3 values and subsequent fields will be automatically - * calculated. - * @note - * For WPA and WPA2 this implementation will use standards as - * defined in 802.11i (2004) and 802.1X (2004). - */ - union AIRPDCAP_KEY_ITEMDATA { - struct AIRPDCAP_KEY_ITEMDATA_WEP { - /** - * The binary value of the WEP key. - * @note - * It is accepted a key of length between - * AIRPDCAP_WEP_KEY_MINLEN and - * AIRPDCAP_WEP_KEY_MAXLEN. A WEP key - * standard-compliante should be either 40 bits - * (10 hex-digits, 5 bytes) for WEP-40 or 104 bits - * (26 hex-digits, 13 bytes) for WEP-104. - */ - UCHAR WepKey[AIRPDCAP_WEP_KEY_MAXLEN]; - /** - * The length of the WEP key. Acceptable range - * is [AIRPDCAP_WEP_KEY_MINLEN;AIRPDCAP_WEP_KEY_MAXLEN]. - */ - size_t WepKeyLen; - } Wep; - - /** - * WPA/WPA2 key data. Note that the decryption process - * will use the PMK (equal to PSK), that is calculated - * from passphrase-SSID pair. You can define one of these - * three fields and necessary fields will be automatically - * calculated. - */ - union AIRPDCAP_KEY_ITEMDATA_WPA { - - UCHAR Psk[AIRPDCAP_WPA_PSK_LEN]; - - UCHAR Pmk[AIRPDCAP_WPA_PMK_LEN]; - } Wpa; - } KeyData; - - struct AIRPDCAP_KEY_ITEMDATA_PWD { - /** - * The string (null-terminated) value of - * the passphrase. - */ - CHAR Passphrase[AIRPDCAP_WPA_PASSPHRASE_MAX_LEN+1]; - /** - * The value of the SSID (up to - * AIRPDCAP_WPA_SSID_MAX_LEN octets). - * @note - * A zero-length SSID indicates broadcast. - */ - CHAR Ssid[AIRPDCAP_WPA_SSID_MAX_LEN]; - /** - *The length of the SSID - */ - size_t SsidLen; - } UserPwd; -} AIRPDCAP_KEY_ITEM, *PAIRPDCAP_KEY_ITEM; - -/** - * Collection of keys to use to decrypt packets - */ -typedef struct _AIRPDCAP_KEYS_COLLECTION { - /** - * Number of stored keys - */ - size_t nKeys; - - /** - * Array of nKeys keys - */ - AIRPDCAP_KEY_ITEM Keys[256]; -} AIRPDCAP_KEYS_COLLECTION, *PAIRPDCAP_KEYS_COLLECTION; -/* */ -/******************************************************************************/ - -/******************************************************************************/ -/* Function prototype declarations */ - -/** - * Returns the decryption_key_t struct given a string describing the key. - * @param key_string [IN] Key string in one of the following formats: - * - 0102030405 (40/64-bit WEP) - * - 01:02:03:04:05 (40/64-bit WEP) - * - 0102030405060708090a0b0c0d (104/128-bit WEP) - * - 01:02:03:04:05:06:07:08:09:0a:0b:0c:0d (104/128-bit WEP) - * - wep:01020304... (WEP) - * - wep:01:02:03:04... (WEP) - * - wpa-pwd:MyPassword (WPA + plaintext password + "wildcard" SSID) - * - wpa-pwd:MyPassword:MySSID (WPA + plaintext password + specific SSID) - * - wpa-psk:01020304... (WPA + 256-bit raw key) - * @return A pointer to a freshly-g_malloc()ed decryption_key_t struct on - * success, or NULL on failure. - * @see get_key_string() - */ -decryption_key_t* -parse_key_string(gchar* key_string); - -/** - * Returns a newly allocated string representing the given decryption_key_t - * struct. - * @param dk [IN] Pointer to the key to be converted - * @return A g_malloc()ed string representation of the key - * @see parse_key_string() - */ -gchar* -get_key_string(decryption_key_t* dk); - -/******************************************************************************/ - -#endif /* _AIRPDCAP_USER_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_ws.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_ws.h deleted file mode 100644 index 22cf6e07..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_ws.h +++ /dev/null @@ -1,43 +0,0 @@ -/* airpdcap_ws.h - * - * $Id: airpdcap_ws.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Copyright (c) 2006 CACE Technologies, Davis (California) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _AIRPDCAP_WS_H -#define _AIRPDCAP_WS_H - -#include "airpdcap_system.h" -WS_VAR_IMPORT AIRPDCAP_CONTEXT airpdcap_ctx; - -#endif /* _AIRPDCAP_WS_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-des.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-des.h deleted file mode 100644 index b08ba28b..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-des.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - a partial implementation of DES designed for use in the - SMB authentication protocol - - Copyright (C) Andrew Tridgell 1998 - - $Id: crypt-des.h 3992 2008-06-10 03:13:11Z dgu $ - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -void crypt_des_ecb(unsigned char *out, const unsigned char *in, const unsigned char *key, int forw); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-md4.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-md4.h deleted file mode 100644 index c6179818..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-md4.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - Unix SMB/CIFS implementation. - a implementation of MD4 designed for use in the SMB authentication protocol - Copyright (C) Andrew Tridgell 1997-1998. - - $Id: crypt-md4.h 3992 2008-06-10 03:13:11Z dgu $ - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -void crypt_md4(unsigned char *out, const unsigned char *in, int n); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-md5.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-md5.h deleted file mode 100644 index d6292004..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-md5.h +++ /dev/null @@ -1,71 +0,0 @@ -/* $Id: crypt-md5.h 3992 2008-06-10 03:13:11Z dgu $ */ -/* - * Copyright (C) 2003-2005 Benny Prijono - * - * MD5 code from pjlib-util http://www.pjsip.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef __MD5_H__ -#define __MD5_H__ - -/** - * @file md5.h - * @brief MD5 Functions - */ - -/** - * @defgroup PJLIB_UTIL_MD5 MD5 Functions - * @ingroup PJLIB_UTIL - * @{ - */ - -#define md5_byte_t guint8 - -/** MD5 context. */ -typedef struct md5_state_s -{ - guint32 buf[4]; - guint32 bits[2]; - guint32 in[16]; -} md5_state_t; - -/** Initialize the algorithm. - * @param pms MD5 context. - */ -void md5_init(md5_state_t *pms); - -/** Append a string to the message. - * @param pms MD5 context. - * @param data Data. - * @param nbytes Length of data. - */ -void md5_append( md5_state_t *pms, - const guint8 *data, guint nbytes); - -/** Finish the message and return the digest. - * @param pms MD5 context. - * @param digest 16 byte digest. - */ -void md5_finish(md5_state_t *pms, guint8 digest[16]); - - -void md5_hmac(const guint8* text, gint text_len, const guint8* key, gint key_len, guint8 digest[16]); - -/** - * @} - */ - -#endif /* _CRYPT_MD5_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-rc4.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-rc4.h deleted file mode 100644 index 1068e160..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-rc4.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - a partial implementation of RC4 designed for use in the - SMB authentication protocol - - Copyright (C) Andrew Tridgell 1998 - - $Id: crypt-rc4.h 3992 2008-06-10 03:13:11Z dgu $ - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -typedef struct _rc4_state_struct { - unsigned char s_box[256]; - unsigned char index_i; - unsigned char index_j; -} rc4_state_struct; - -void crypt_rc4_init(rc4_state_struct *rc4_state, - const unsigned char *key, int key_len); - -void crypt_rc4(rc4_state_struct *rc4_state, unsigned char *data, int data_len); - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-sha1.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-sha1.h deleted file mode 100644 index 010725b7..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-sha1.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * FIPS-180-1 compliant SHA-1 implementation - * - * $Id: crypt-sha1.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Copyright (C) 2001-2003 Christophe Devine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Changed to use guint instead of uint 2004 by Anders Broman - * Original code found at http://www.cr0.net:8040/code/crypto/sha1/ - * References: http://www.ietf.org/rfc/rfc3174.txt?number=3174 - */ - -#ifndef _CRYPT_SHA1_H -#define _CRYPT_SHA1_H - - -typedef struct -{ - guint32 total[2]; - guint32 state[5]; - guint8 buffer[64]; -} -sha1_context; - -void sha1_starts( sha1_context *ctx ); -void sha1_update( sha1_context *ctx, const guint8 *input, guint32 length ); -void sha1_finish( sha1_context *ctx, guint8 digest[20] ); -void sha1_hmac( const guint8 *key, guint32 keylen, const guint8 *buf, guint32 buflen, - guint8 digest[20] ); - -#endif /* crypt-sha1.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/wep-wpadefs.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/wep-wpadefs.h deleted file mode 100644 index f980d401..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/wep-wpadefs.h +++ /dev/null @@ -1,115 +0,0 @@ -/* wap-wpadefs.h - * - * $Id: wep-wpadefs.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Copyright (c) 2006 CACE Technologies, Davis (California) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef __WEP_WPADEFS_H__ -#define __WEP_WPADEFS_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -/** @file - * WEP and WPA definitions - * - * Copied from airpcap.h. - */ - -/** - * Maximum number of encryption keys. This determines the size of - * structures in packet-ieee80211.c, as well as the number of keys - * in the IEEE 802.11 preferences. - */ -#define MAX_ENCRYPTION_KEYS 64 - -/** - * Maximum size of a WEP key, in bytes. This is the size of an entry in the - * AirpcapWepKeysCollection structure. - */ -#define WEP_KEY_MAX_SIZE 32 - -/** - * WEP_KEY_MAX_SIZE is in bytes, but each byte is represented as a - * hexadecimal string. - */ -#define WEP_KEY_MAX_CHAR_SIZE (WEP_KEY_MAX_SIZE*2) - -/** - * WEP_KEY_MAX_SIZE is in bytes, this is in bits... - */ -#define WEP_KEY_MAX_BIT_SIZE (WEP_KEY_MAX_SIZE*8) - -#define WEP_KEY_MIN_CHAR_SIZE 2 -#define WEP_KEY_MIN_BIT_SIZE 8 - -/** - * WPA key sizes. - */ -#define WPA_KEY_MAX_SIZE 63 /* 63 chars followed by a '\0' */ - -#define WPA_KEY_MAX_CHAR_SIZE (WPA_KEY_MAX_SIZE*1) -#define WPA_KEY_MAX_BIT_SIZE (WPA_KEY_MAX_SIZE*8) -#define WPA_KEY_MIN_CHAR_SIZE 8 -#define WPA_KEY_MIN_BIT_SIZE (WPA_KEY_MIN_CHAR_SIZE*8) - -/** - * SSID sizes - */ -#define WPA_SSID_MAX_SIZE 32 - -#define WPA_SSID_MAX_CHAR_SIZE (WPA_SSID_MAX_SIZE*1) -#define WPA_SSID_MAX_BIT_SIZE (WPA_SSID_MAX_SIZE*8) -#define WPA_SSID_MIN_CHAR_SIZE 0 -#define WPA_SSID_MIN_BIT_SIZE (WPA_SSID_MIN_CHAR_SIZE*8) - -/** - * Let the user enter a raw PSK along with a passphrase + SSID - */ -#define WPA_PSK_KEY_SIZE 32 /* Fixed size, 32 bytes (256bit) */ -#define WPA_PSK_KEY_CHAR_SIZE (WPA_PSK_KEY_SIZE*2) -#define WPA_PSK_KEY_BIT_SIZE (WPA_PSK_KEY_SIZE*8) - -/** - * Prefix definitions for preferences - */ -#define STRING_KEY_TYPE_WEP "wep" -#define STRING_KEY_TYPE_WPA_PWD "wpa-pwd" -#define STRING_KEY_TYPE_WPA_PSK "wpa-psk" - -#ifdef __cplusplus -} -#endif - -#endif /* __WEP_WPADEFS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter-int.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter-int.h deleted file mode 100644 index aaea0ba4..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter-int.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * $Id: dfilter-int.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2001 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef DFILTER_INT_H -#define DFILTER_INT_H - -#include "dfilter.h" -#include "syntax-tree.h" - -#include -#include - -/* Passed back to user */ -struct _dfilter_t { - GPtrArray *insns; - GPtrArray *consts; - int num_registers; - int max_registers; - GList **registers; - gboolean *attempted_load; - int *interesting_fields; - int num_interesting_fields; - GPtrArray *deprecated; -}; - -typedef struct { - /* Syntax Tree stuff */ - stnode_t *st_root; - gboolean syntax_error; - GPtrArray *insns; - GPtrArray *consts; - GHashTable *loaded_fields; - GHashTable *interesting_fields; - int next_insn_id; - int next_const_id; - int next_register; - int first_constant; /* first register used as a constant */ -} dfwork_t; - -/* Constructor/Destructor prototypes for Lemon Parser */ -#if (GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 16)) -void *DfilterAlloc(void* (*)(gsize)); -#else -void *DfilterAlloc(void* (*)(gulong)); -#endif - -void DfilterFree(void*, void (*)(void *)); -void Dfilter(void*, int, stnode_t*, dfwork_t*); - -/* Scanner's lval */ -extern stnode_t *df_lval; - -/* Return value for error in scanner. */ -#define SCAN_FAILED -1 /* not 0, as that means end-of-input */ - -/* Set dfilter_error_msg_buf and dfilter_error_msg */ -void -dfilter_fail(const char *format, ...); - -void -DfilterTrace(FILE *TraceFILE, char *zTracePrompt); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter-macro.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter-macro.h deleted file mode 100644 index c2a78060..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter-macro.h +++ /dev/null @@ -1,59 +0,0 @@ -/* dfilter-macro.h - * - * $Id: dfilter-macro.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2001 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef _DFILTER_MACRO_H -#define _DFILTER_MACRO_H - -#define DFILTER_MACRO_FILENAME "dfilter_macros" - - -typedef struct _dfilter_macro_t { - gchar* name; /* the macro id */ - gchar* text; /* raw data from file */ - gboolean usable; /* macro is usable */ - gchar** parts; /* various segments of text between insertion targets */ - int* args_pos; /* what's to be inserted */ - int argc; /* the expected number of arguments */ - void* priv; /* a copy of text that contains every c-string in parts */ -} dfilter_macro_t; - -/* loop over the macros list */ -typedef void (*dfilter_macro_cb_t)(dfilter_macro_t*, void*); -void dfilter_macro_foreach(dfilter_macro_cb_t, void*); - -/* save dfilter macros to a file */ -void dfilter_macro_save(const gchar*, gchar**); - -/* dumps the macros in the list (debug info, not formated as in the macros file) */ -void dfilter_macro_dump(void); - -/* applies all macros to the given text and returns the resulting string or NULL on failure */ -gchar* dfilter_macro_apply(const gchar* text, guint depth, const gchar** error); - -void dfilter_macro_init(void); - -void dfilter_macro_get_uat(void**); - -void dfilter_macro_build_ftv_cache(void* tree_root); - -#endif /* _DFILTER_MACRO_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter.h deleted file mode 100644 index 8ea9f947..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * $Id: dfilter.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2001 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef DFILTER_H -#define DFILTER_H - -#include - -/* Passed back to user */ -typedef struct _dfilter_t dfilter_t; - -#include -#include - - -/* Module-level initialization */ -void -dfilter_init(void); - -/* Module-level cleanup */ -void -dfilter_cleanup(void); - -/* Compiles a string to a dfilter_t. - * On success, sets the dfilter* pointed to by dfp - * to either a NULL pointer (if the filter is a null - * filter, as generated by an all-blank string) or to - * a pointer to the newly-allocated dfilter_t - * structure. - * - * On failure, dfilter_error_msg points to an - * appropriate error message. This error message is - * a global string, so another invocation of - * dfilter_compile() will clear it. The dfilter* - * will be set to NULL after a failure. - * - * Returns TRUE on success, FALSE on failure. - */ -gboolean -dfilter_compile(const gchar *text, dfilter_t **dfp); - -/* Frees all memory used by dfilter, and frees - * the dfilter itself. */ -void -dfilter_free(dfilter_t *df); - - -/* dfilter_error_msg is NULL if there was no error during dfilter_compile, - * otherwise it points to a displayable error message. With MSVC and a - * libwireshark.dll, we need a special declaration. - */ - -WS_VAR_IMPORT const gchar *dfilter_error_msg; - - -/* Apply compiled dfilter */ -gboolean -dfilter_apply_edt(dfilter_t *df, epan_dissect_t* edt); - -/* Apply compiled dfilter */ -gboolean -dfilter_apply(dfilter_t *df, proto_tree *tree); - -/* Prime a proto_tree using the fields/protocols used in a dfilter. */ -void -dfilter_prime_proto_tree(const dfilter_t *df, proto_tree *tree); - -GPtrArray * -dfilter_deprecated_tokens(dfilter_t *df); - -/* Print bytecode of dfilter to stdout */ -void -dfilter_dump(dfilter_t *df); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfunctions.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfunctions.h deleted file mode 100644 index f9e1e575..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfunctions.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * $Id: dfunctions.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * - * Copyright 2006 Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef DFUNCTIONS_H -#define DFUNCTIONS_H - -#include -#include -#include "syntax-tree.h" - -/* The run-time logic of the dfilter function */ -typedef gboolean (*DFFuncType)(GList *arg1list, GList *arg2list, GList **retval); - -/* The semantic check for the dfilter function */ -typedef void (*DFSemCheckType)(int param_num, stnode_t *st_node); - -/* If a function needs more args than this, increase - * this macro and add more arg members to the dfvm_insn_t - * struct in dfvm.h, and add some logic to dfw_append_function() - * and dfvm_apply() */ -#define DFUNCTION_MAX_NARGS 2 - -/* This is a "function definition" record, holding everything - * we need to know about a function */ -typedef struct { - const char *name; - DFFuncType function; - ftenum_t retval_ftype; - guint min_nargs; - guint max_nargs; - DFSemCheckType semcheck_param_function; -} df_func_def_t; - -/* Return the function definition record for a function of named "name" */ -df_func_def_t* df_func_lookup(char *name); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfvm.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfvm.h deleted file mode 100644 index 8e6e2507..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfvm.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * $Id: dfvm.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2001 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef DFVM_H -#define DFVM_H - -#include -#include -#include "dfilter-int.h" -#include "syntax-tree.h" -#include "drange.h" -#include "dfunctions.h" - -typedef enum { - EMPTY, - FVALUE, - HFINFO, - INSN_NUMBER, - REGISTER, - INTEGER, - DRANGE, - FUNCTION_DEF -} dfvm_value_type_t; - -typedef struct { - dfvm_value_type_t type; - - union { - fvalue_t *fvalue; - guint32 numeric; - drange *drange; - header_field_info *hfinfo; - df_func_def_t *funcdef; - } value; - -} dfvm_value_t; - - -typedef enum { - - IF_TRUE_GOTO, - IF_FALSE_GOTO, - CHECK_EXISTS, - NOT, - RETURN, - READ_TREE, - PUT_FVALUE, - ANY_EQ, - ANY_NE, - ANY_GT, - ANY_GE, - ANY_LT, - ANY_LE, - ANY_BITWISE_AND, - ANY_CONTAINS, - ANY_MATCHES, - MK_RANGE, - CALL_FUNCTION - -} dfvm_opcode_t; - -typedef struct { - int id; - dfvm_opcode_t op; - dfvm_value_t *arg1; - dfvm_value_t *arg2; - dfvm_value_t *arg3; - dfvm_value_t *arg4; -} dfvm_insn_t; - -dfvm_insn_t* -dfvm_insn_new(dfvm_opcode_t op); - -void -dfvm_insn_free(dfvm_insn_t *insn); - -dfvm_value_t* -dfvm_value_new(dfvm_value_type_t type); - -void -dfvm_dump(FILE *f, GPtrArray *insns); - -gboolean -dfvm_apply(dfilter_t *df, proto_tree *tree); - -void -dfvm_init_const(dfilter_t *df); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/drange.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/drange.h deleted file mode 100644 index 37ea4e8c..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/drange.h +++ /dev/null @@ -1,102 +0,0 @@ -/* drange.h - * Routines for providing general range support to the dfilter library - * - * $Id: drange.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Copyright (c) 2000 by Ed Warnicke - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1999 Gerald Combs - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __DRANGE_H__ -#define __DRANGE_H__ - -#include - -/* Please don't directly manipulate these structs. Please use - * the methods provided. If you REALLY can't do what you need to - * do with the methods provided please write new methods that do - * what you need, put them into the drange object here, and limit - * your direct manipulation of the drange and drange_node structs to - * here. - */ - -typedef enum { - UNINITIALIZED, - LENGTH, - OFFSET, - TO_THE_END -} drange_node_end_t; - -typedef struct _drange_node { - gint start_offset; - gint length; - gint end_offset; - drange_node_end_t ending; -} drange_node; - -typedef struct _drange { - GSList* range_list; - gboolean has_total_length; - gint total_length; - gint min_start_offset; - gint max_start_offset; -} drange; - -/* drange_node constructor */ -drange_node* drange_node_new(void); - -/* drange_node destructor */ -void drange_node_free(drange_node* drnode); - -/* Call drange_node destructor on all list items */ -void drange_node_free_list(GSList* list); - -/* drange_node accessors */ -gint drange_node_get_start_offset(drange_node* drnode); -gint drange_node_get_length(drange_node* drnode); -gint drange_node_get_end_offset(drange_node* drnode); -drange_node_end_t drange_node_get_ending(drange_node* drnode); - -/* drange_node mutators */ -void drange_node_set_start_offset(drange_node* drnode, gint offset); -void drange_node_set_length(drange_node* drnode, gint length); -void drange_node_set_end_offset(drange_node* drnode, gint offset); -void drange_node_set_to_the_end(drange_node* drnode); - -/* drange constructor */ -drange* drange_new(void); -drange* drange_new_from_list(GSList *list); - -/* drange destructor, only use this if you used drange_new() to creat - * the drange - */ -void drange_free(drange* dr); - -/* drange accessors */ -gboolean drange_has_total_length(drange* dr); -gint drange_get_total_length(drange* dr); -gint drange_get_min_start_offset(drange* dr); -gint drange_get_max_start_offset(drange* dr); - -/* drange mutators */ -void drange_append_drange_node(drange* dr, drange_node* drnode); -void drange_prepend_drange_node(drange* dr, drange_node* drnode); -void drange_foreach_drange_node(drange* dr, GFunc func, gpointer funcdata); - -#endif /* ! __DRANGE_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/gencode.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/gencode.h deleted file mode 100644 index 2148b2be..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/gencode.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef GENCODE_H -#define GENCODE_H - -void -dfw_gencode(dfwork_t *dfw); - -int* -dfw_interesting_fields(dfwork_t *dfw, int *caller_num_fields); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/glib-util.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/glib-util.h deleted file mode 100644 index f845cbe6..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/glib-util.h +++ /dev/null @@ -1,4 +0,0 @@ -/* $Id: glib-util.h 3992 2008-06-10 03:13:11Z dgu $ */ - -char* -g_substrdup(const char *s, int start, int len); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/grammar.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/grammar.h deleted file mode 100644 index 36c3e11f..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/grammar.h +++ /dev/null @@ -1,24 +0,0 @@ -#define TOKEN_TEST_AND 1 -#define TOKEN_TEST_OR 2 -#define TOKEN_TEST_EQ 3 -#define TOKEN_TEST_NE 4 -#define TOKEN_TEST_LT 5 -#define TOKEN_TEST_LE 6 -#define TOKEN_TEST_GT 7 -#define TOKEN_TEST_GE 8 -#define TOKEN_TEST_CONTAINS 9 -#define TOKEN_TEST_MATCHES 10 -#define TOKEN_TEST_BITWISE_AND 11 -#define TOKEN_TEST_NOT 12 -#define TOKEN_FIELD 13 -#define TOKEN_STRING 14 -#define TOKEN_UNPARSED 15 -#define TOKEN_LBRACKET 16 -#define TOKEN_RBRACKET 17 -#define TOKEN_COMMA 18 -#define TOKEN_INTEGER 19 -#define TOKEN_COLON 20 -#define TOKEN_HYPHEN 21 -#define TOKEN_FUNCTION 22 -#define TOKEN_LPAREN 23 -#define TOKEN_RPAREN 24 diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/scanner_lex.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/scanner_lex.h deleted file mode 100644 index 886d06b1..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/scanner_lex.h +++ /dev/null @@ -1,6 +0,0 @@ -/* This is generated by runlex.sh. Do not edit it. */ -#define yylex df_lex -#ifndef YY_DECL -#define YY_DECL int yylex(void) -#endif -YY_DECL; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/semcheck.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/semcheck.h deleted file mode 100644 index 5eac9804..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/semcheck.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * $Id: semcheck.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2001 Gerald Combs - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef SEMCHECK_H -#define SEMCHECK_H - -gboolean -dfw_semcheck(dfwork_t *dfw); - - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-function.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-function.h deleted file mode 100644 index fdcc9c58..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-function.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * $Id: sttype-function.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2001 Gerald Combs - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef STTYPE_FUNCTION_H -#define STTYPE_FUNCTION_H - -#include "dfunctions.h" - -/* Set the parameters for a function stnode_t. */ -void -sttype_function_set_params(stnode_t *node, GSList *params); - -/* Get the function-definition record for a function stnode_t. */ -df_func_def_t* sttype_function_funcdef(stnode_t *node); - -/* Get the parameters for a function stnode_t. */ -GSList* sttype_function_params(stnode_t *node); - -/* Free the memory of a param list */ -void st_funcparams_free(GSList *params); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-range.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-range.h deleted file mode 100644 index db92f76d..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-range.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * $Id: sttype-range.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2001 Gerald Combs - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef STTYPE_RANGE_H -#define STTYPE_RANGE_H - -#include "syntax-tree.h" -#include "drange.h" - -STTYPE_ACCESSOR_PROTOTYPE(header_field_info*, range, hfinfo) -STTYPE_ACCESSOR_PROTOTYPE(drange*, range, drange) - -/* Set a range */ -void -sttype_range_set(stnode_t *node, stnode_t *field, GSList* drange_list); - -void -sttype_range_set1(stnode_t *node, stnode_t *field, drange_node *rn); - -/* Clear the 'drange' variable to remove responsibility for - * freeing it. */ -void -sttype_range_remove_drange(stnode_t *node); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-test.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-test.h deleted file mode 100644 index 1635378b..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-test.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * $Id: sttype-test.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2001 Gerald Combs - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef STTYPE_TEST_H -#define STTYPE_TEST_H - -typedef enum { - TEST_OP_UNINITIALIZED, - TEST_OP_EXISTS, - TEST_OP_NOT, - TEST_OP_AND, - TEST_OP_OR, - TEST_OP_EQ, - TEST_OP_NE, - TEST_OP_GT, - TEST_OP_GE, - TEST_OP_LT, - TEST_OP_LE, - TEST_OP_BITWISE_AND, - TEST_OP_CONTAINS, - TEST_OP_MATCHES -} test_op_t; - -void -sttype_test_set1(stnode_t *node, test_op_t op, stnode_t *val1); - -void -sttype_test_set2(stnode_t *node, test_op_t op, stnode_t *val1, stnode_t *val2); - -void -sttype_test_set2_args(stnode_t *node, stnode_t *val1, stnode_t *val2); - -void -sttype_test_get(stnode_t *node, test_op_t *p_op, stnode_t **p_val1, stnode_t **p_val2); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/syntax-tree.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/syntax-tree.h deleted file mode 100644 index 0ea35f39..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/syntax-tree.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * $Id: syntax-tree.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2001 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef SYNTAX_TREE_H -#define SYNTAX_TREE_H - -#include -#include "cppmagic.h" - -typedef enum { - STTYPE_UNINITIALIZED, - STTYPE_TEST, - STTYPE_UNPARSED, - STTYPE_STRING, - STTYPE_FIELD, - STTYPE_FVALUE, - STTYPE_INTEGER, - STTYPE_RANGE, - STTYPE_FUNCTION, - STTYPE_NUM_TYPES -} sttype_id_t; - -typedef gpointer (*STTypeNewFunc)(gpointer); -typedef void (*STTypeFreeFunc)(gpointer); - - -/* Type information */ -typedef struct { - sttype_id_t id; - const char *name; - STTypeNewFunc func_new; - STTypeFreeFunc func_free; -} sttype_t; - -/* Node (type instance) information */ -typedef struct { - guint32 magic; - sttype_t *type; - - /* This could be made an enum, but I haven't - * set aside to time to do so. */ - gpointer data; - gint32 value; - const char *deprecated_token; -} stnode_t; - -/* These are the sttype_t registration function prototypes. */ -void sttype_register_function(void); -void sttype_register_integer(void); -void sttype_register_pointer(void); -void sttype_register_range(void); -void sttype_register_string(void); -void sttype_register_test(void); - -void -sttype_init(void); - -void -sttype_cleanup(void); - -void -sttype_register(sttype_t *type); - -stnode_t* -stnode_new(sttype_id_t type_id, gpointer data); - -void -stnode_init(stnode_t *node, sttype_id_t type_id, gpointer data); - -void -stnode_init_int(stnode_t *node, sttype_id_t type_id, gint32 value); - -void -stnode_free(stnode_t *node); - -const char* -stnode_type_name(stnode_t *node); - -sttype_id_t -stnode_type_id(stnode_t *node); - -gpointer -stnode_data(stnode_t *node); - -gint32 -stnode_value(stnode_t *node); - -const char * -stnode_deprecated(stnode_t *node); - -#define assert_magic(obj, mnum) \ - g_assert((obj)); \ - if ((obj)->magic != (mnum)) { \ - g_print("\nMagic num is 0x%08x, but should be 0x%08x", \ - (obj)->magic, (mnum)); \ - g_assert((obj)->magic == (mnum)); \ - } - - - - -#define STTYPE_ACCESSOR(ret,type,attr,magicnum) \ - ret \ - CONCAT(CONCAT(CONCAT(sttype_,type),_),attr) (stnode_t *node) \ -{\ - CONCAT(type,_t) *value; \ - value = stnode_data(node);\ - assert_magic(value, magicnum); \ - return value->attr; \ -} - -#define STTYPE_ACCESSOR_PROTOTYPE(ret,type,attr) \ - ret \ - CONCAT(CONCAT(CONCAT(sttype_,type),_),attr) (stnode_t *node); - - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/diam_dict.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/diam_dict.h deleted file mode 100644 index b36ba254..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/diam_dict.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - ** diam_dict.h - ** Diameter Dictionary Import Routines - ** - ** $Id: diam_dict.h 3992 2008-06-10 03:13:11Z dgu $ - ** - ** (c) 2007, Luis E. Garcia Ontanon - ** - ** This library is free software; you can redistribute it and/or - ** modify it under the terms of the GNU Library General Public - ** License as published by the Free Software Foundation; either - ** version 2 of the License, or (at your option) any later version. - ** - ** This library is distributed in the hope that it will be useful, - ** but WITHOUT ANY WARRANTY; without even the implied warranty of - ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - ** Library General Public License for more details. - ** - ** You should have received a copy of the GNU Library General Public - ** License along with this library; if not, write to the - ** Free Software Foundation, Inc., 59 Temple Place - Suite 330, - ** Boston, MA 02111-1307, USA. - */ - -#ifndef _DIAM_DICT_H_ -#define _DIAM_DICT_H_ - -struct _ddict_namecode_t { - char* name; - unsigned code; - struct _ddict_namecode_t* next; -}; - -typedef struct _ddict_namecode_t ddict_gavp_t; -typedef struct _ddict_namecode_t ddict_enum_t; -typedef struct _ddict_namecode_t ddict_application_t; - -typedef struct _ddict_vendor_t { - char* name; - char* desc; - unsigned code; - struct _ddict_vendor_t* next; -} ddict_vendor_t; - -typedef struct _ddict_avp_t { - char* name; - char* description; - char* vendor; - char* type; - unsigned code; - ddict_gavp_t* gavps; - ddict_enum_t* enums; - struct _ddict_avp_t* next; -} ddict_avp_t; - -typedef struct _ddict_typedefn_t { - char* name; - char* parent; - struct _ddict_typedefn_t* next; -} ddict_typedefn_t; - -typedef struct _ddict_cmd_t { - char* name; - char* vendor; - unsigned code; - struct _ddict_cmd_t* next; -} ddict_cmd_t; - -typedef struct _ddict_xmlpi_t { - char* name; - char* key; - char* value; - struct _ddict_xmlpi_t* next; -} ddict_xmlpi_t; - -typedef struct _ddict_t { - ddict_application_t* applications; - ddict_vendor_t* vendors; - ddict_cmd_t* cmds; - ddict_typedefn_t* typedefns; - ddict_avp_t* avps; - ddict_xmlpi_t* xmlpis; -} ddict_t; - -extern void ddict_print(FILE* fh, ddict_t* d); -extern ddict_t* ddict_scan(const char* directory, const char* filename, int dbg); -extern void ddict_free(ddict_t* d); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/diam_dict_lex.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/diam_dict_lex.h deleted file mode 100644 index 1135d99c..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/diam_dict_lex.h +++ /dev/null @@ -1,6 +0,0 @@ -/* This is generated by runlex.sh. Do not edit it. */ -#define yylex DiamDictlex -#ifndef YY_DECL -#define YY_DECL int yylex(void) -#endif -YY_DECL; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dissector_filters.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dissector_filters.h deleted file mode 100644 index 595c3d57..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dissector_filters.h +++ /dev/null @@ -1,60 +0,0 @@ -/* dissector_filters.h - * Routines for dissector generated display filters - * - * $Id: dissector_filters.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __DISSECTOR_FILTERS_H__ -#define __DISSECTOR_FILTERS_H__ - - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - - -/* callback function definition: is a filter available for this packet? */ -typedef gboolean (*is_filter_valid_func)(packet_info *pinfo); - -/* callback function definition: return the available filter for this packet or NULL if no filter is available */ -typedef const gchar* (*build_filter_string_func)(packet_info *pinfo); - - -/* register a dissector filter */ -extern void register_dissector_filter(const char *name, is_filter_valid_func is_filter_valid, build_filter_string_func build_filter_string); - - - -/*** THE FOLLOWING SHOULD NOT BE USED BY ANY DISSECTORS!!! ***/ - -typedef struct dissector_filter_s { - const char * name; - is_filter_valid_func is_filter_valid; - build_filter_string_func build_filter_string; -} dissector_filter_t; - -WS_VAR_IMPORT GList *dissector_filter_list; - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* dissector_filters.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dissectors/packet-tcp.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dissectors/packet-tcp.h deleted file mode 100644 index ee0b70cb..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dissectors/packet-tcp.h +++ /dev/null @@ -1,232 +0,0 @@ -/* packet-tcp.h - * - * $Id: packet-tcp.h 23902 2007-12-17 20:43:38Z sfisher $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __PACKET_TCP_H__ -#define __PACKET_TCP_H__ - -/* TCP flags */ -#define TH_FIN 0x01 -#define TH_SYN 0x02 -#define TH_RST 0x04 -#define TH_PUSH 0x08 -#define TH_ACK 0x10 -#define TH_URG 0x20 -#define TH_ECN 0x40 -#define TH_CWR 0x80 - -/* Idea for gt: either x > y, or y is much bigger (assume wrap) */ -#define GT_SEQ(x, y) ((gint32)((y) - (x)) < 0) -#define LT_SEQ(x, y) ((gint32)((x) - (y)) < 0) -#define GE_SEQ(x, y) ((gint32)((y) - (x)) <= 0) -#define LE_SEQ(x, y) ((gint32)((x) - (y)) <= 0) -#define EQ_SEQ(x, y) ((x) == (y)) - -/* the tcp header structure, passed to tap listeners */ -struct tcpheader { - guint32 th_seq; - guint32 th_ack; - gboolean th_have_seglen; /* TRUE if th_seglen is valid */ - guint32 th_seglen; - guint32 th_win; /* make it 32 bits so we can handle some scaling */ - guint16 th_sport; - guint16 th_dport; - guint8 th_hlen; - guint8 th_flags; - address ip_src; - address ip_dst; -}; - -/* - * Private data passed from the TCP dissector to subdissectors. Passed to the - * subdissectors in pinfo->private_data - */ -struct tcpinfo { - guint32 seq; /* Sequence number of first byte in the data */ - guint32 nxtseq; /* Sequence number of first byte after data */ - guint32 lastackseq; /* Sequence number of last ack */ - gboolean is_reassembled; /* This is reassembled data. */ - gboolean urgent; /* TRUE if "urgent_pointer" is valid */ - guint16 urgent_pointer; /* Urgent pointer value for the current packet. */ -}; - -/* - * Loop for dissecting PDUs within a TCP stream; assumes that a PDU - * consists of a fixed-length chunk of data that contains enough information - * to determine the length of the PDU, followed by rest of the PDU. - * - * The first three arguments are the arguments passed to the dissector - * that calls this routine. - * - * "proto_desegment" is the dissector's flag controlling whether it should - * desegment PDUs that cross TCP segment boundaries. - * - * "fixed_len" is the length of the fixed-length part of the PDU. - * - * "get_pdu_len()" is a routine called to get the length of the PDU from - * the fixed-length part of the PDU; it's passed "pinfo", "tvb" and "offset". - * - * "dissect_pdu()" is the routine to dissect a PDU. - */ -extern void -tcp_dissect_pdus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, - gboolean proto_desegment, guint fixed_len, - guint (*get_pdu_len)(packet_info *, tvbuff_t *, int), - dissector_t dissect_pdu); - -extern struct tcp_multisegment_pdu * -pdu_store_sequencenumber_of_next_pdu(packet_info *pinfo, guint32 seq, guint32 nxtpdu, emem_tree_t *multisegment_pdus); - -typedef struct _tcp_unacked_t { - struct _tcp_unacked_t *next; - guint32 frame; - guint32 seq; - guint32 nextseq; - nstime_t ts; -} tcp_unacked_t; - -struct tcp_acked { - guint32 frame_acked; - nstime_t ts; - - guint32 rto_frame; - nstime_t rto_ts; /* Time since previous packet for - retransmissions. */ - guint16 flags; - guint32 dupack_num; /* dup ack number */ - guint32 dupack_frame; /* dup ack to frame # */ -}; - -/* One instance of this structure is created for each pdu that spans across - * multiple tcp segments. - */ -struct tcp_multisegment_pdu { - guint32 seq; - guint32 nxtpdu; - guint32 first_frame; - guint32 last_frame; - nstime_t last_frame_time; - guint32 flags; -#define MSP_FLAGS_REASSEMBLE_ENTIRE_SEGMENT 0x00000001 -}; - -typedef struct _tcp_flow_t { - guint32 base_seq; /* base seq number (used by relative sequence numbers) - * or 0 if not yet known. - */ - tcp_unacked_t *segments; - guint32 lastack; /* last seen ack */ - nstime_t lastacktime; /* Time of the last ack packet */ - guint32 lastnondupack; /* frame number of last seen non dupack */ - guint32 dupacknum; /* dupack number */ - guint32 nextseq; /* highest seen nextseq */ - guint32 nextseqframe; /* frame number for segment with highest - * sequence number - */ - nstime_t nextseqtime; /* Time of the nextseq packet so we can - * distinguish between retransmission, - * fast retransmissions and outoforder - */ - guint32 window; /* last seen window */ - gint16 win_scale; /* -1 is we dont know */ -/* This tcp flow/session contains only one single PDU and should - * be reassembled until the final FIN segment. - */ -#define TCP_FLOW_REASSEMBLE_UNTIL_FIN 0x0001 - guint16 flags; - guint32 lastsegmentflags; - - /* This tree is indexed by sequence number and keeps track of all - * all pdus spanning multiple segments for this flow. - */ - emem_tree_t *multisegment_pdus; -} tcp_flow_t; - - -struct tcp_analysis { - /* These two structs are managed based on comparing the source - * and destination addresses and, if they're equal, comparing - * the source and destination ports. - * - * If the source is greater than the destination, then stuff - * sent from src is in ual1. - * - * If the source is less than the destination, then stuff - * sent from src is in ual2. - * - * XXX - if the addresses and ports are equal, we don't guarantee - * the behavior. - */ - tcp_flow_t flow1; - tcp_flow_t flow2; - - /* These pointers are set by get_tcp_conversation_data() - * fwd point in the same direction as the current packet - * and rev in the reverse direction - */ - tcp_flow_t *fwd; - tcp_flow_t *rev; - - /* This pointer is NULL or points to a tcp_acked struct if this - * packet has "interesting" properties such as being a KeepAlive or - * similar - */ - struct tcp_acked *ta; - /* This structure contains a tree containing all the various ta's - * keyed by frame number. - */ - emem_tree_t *acked_table; - - /* Remember the timestamp of the first frame seen in this tcp - * conversation to be able to calculate a relative time compared - * to the start of this conversation - */ - nstime_t ts_first; - - /* Remember the timestamp of the frame that was last seen in this - * tcp conversation to be able to calculate a delta time compared - * to previous frame in this conversation - */ - nstime_t ts_prev; -}; - -/* Structure that keeps per packet data. First used to be able - * to calculate the time_delta from the last seen frame in this - * TCP conversation. Can be extended for future use. - */ -struct tcp_per_packet_data_t { - nstime_t ts_del; -}; - - -extern void dissect_tcp_payload(tvbuff_t *tvb, packet_info *pinfo, int offset, - guint32 seq, guint32 nxtseq, guint32 sport, - guint32 dport, proto_tree *tree, - proto_tree *tcp_tree, - struct tcp_analysis *tcpd); - -extern struct tcp_analysis *get_tcp_conversation_data(packet_info *pinfo); - -extern gboolean decode_tcp_ports(tvbuff_t *, int, packet_info *, proto_tree *, int, int, struct tcp_analysis *); - - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd.h deleted file mode 100644 index 6063fb31..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * dtd.h - * - * XML dissector for Wireshark - * DTD import declarations - * - * Copyright 2005, Luis E. Garcia Ontanon - * - * $Id: dtd.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef _DTD_H_ -#define _DTD_H_ - -#include -#include /* exit() */ - -typedef struct _dtd_build_data_t { - gchar* proto_name; - gchar* media_type; - gchar* description; - gchar* proto_root; - gboolean recursion; - - GPtrArray* elements; - GPtrArray* attributes; - - GString* error; -} dtd_build_data_t; - -typedef struct _dtd_token_data_t { - gchar* text; - gchar* location; -} dtd_token_data_t; - -typedef struct _dtd_named_list_t { - gchar* name; - GPtrArray* list; -} dtd_named_list_t; - -extern GString* dtd_preparse(const gchar* dname, const gchar* fname, GString* err); -extern dtd_build_data_t* dtd_parse(GString* s); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_grammar.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_grammar.h deleted file mode 100644 index 732b0361..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_grammar.h +++ /dev/null @@ -1,23 +0,0 @@ -#define TOKEN_TAG_START 1 -#define TOKEN_DOCTYPE_KW 2 -#define TOKEN_NAME 3 -#define TOKEN_OPEN_BRACKET 4 -#define TOKEN_CLOSE_BRACKET 5 -#define TOKEN_TAG_STOP 6 -#define TOKEN_ATTLIST_KW 7 -#define TOKEN_ELEMENT_KW 8 -#define TOKEN_ATT_TYPE 9 -#define TOKEN_ATT_DEF 10 -#define TOKEN_ATT_DEF_WITH_VALUE 11 -#define TOKEN_QUOTED 12 -#define TOKEN_IMPLIED_KW 13 -#define TOKEN_REQUIRED_KW 14 -#define TOKEN_OPEN_PARENS 15 -#define TOKEN_CLOSE_PARENS 16 -#define TOKEN_PIPE 17 -#define TOKEN_STAR 18 -#define TOKEN_PLUS 19 -#define TOKEN_QUESTION 20 -#define TOKEN_ELEM_DATA 21 -#define TOKEN_COMMA 22 -#define TOKEN_EMPTY_KW 23 diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_parse.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_parse.h deleted file mode 100644 index 99a9958a..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_parse.h +++ /dev/null @@ -1,37 +0,0 @@ -/* dtd_parse.h -* an XML dissector for Wireshark -* header file to declare functions defined in lexer and used in parser, -* or vice versa -* -* Copyright 2004, Luis E. Garcia Ontanon -* -* $Id: dtd_parse.h 3992 2008-06-10 03:13:11Z dgu $ -* -* Wireshark - Network traffic analyzer -* By Gerald Combs -* Copyright 1998 Gerald Combs -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version 2 -* of the License, or (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -extern void DtdParse(void*,int,dtd_token_data_t*,dtd_build_data_t*); -#if (GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 16)) -extern void *DtdParseAlloc(void *(*)(gsize)); -#else -extern void *DtdParseAlloc(void *(*)(gulong)); -#endif -extern void DtdParseFree( void*, void(*)(void*) ); -extern void DtdParseTrace(FILE *TraceFILE, char *zTracePrompt); -extern int Dtd_Parse_lex(void); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_parse_lex.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_parse_lex.h deleted file mode 100644 index c809f40b..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_parse_lex.h +++ /dev/null @@ -1,6 +0,0 @@ -/* This is generated by runlex.sh. Do not edit it. */ -#define yylex Dtd_Parse_lex -#ifndef YY_DECL -#define YY_DECL int yylex(void) -#endif -YY_DECL; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_preparse_lex.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_preparse_lex.h deleted file mode 100644 index dc4b7bcf..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_preparse_lex.h +++ /dev/null @@ -1,6 +0,0 @@ -/* This is generated by runlex.sh. Do not edit it. */ -#define yylex Dtd_PreParse_lex -#ifndef YY_DECL -#define YY_DECL int yylex(void) -#endif -YY_DECL; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/eap.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/eap.h deleted file mode 100644 index 24934ceb..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/eap.h +++ /dev/null @@ -1,53 +0,0 @@ -/* sminmpec.h - * Extenal definitions for EAP Extensible Authentication Protocol dissection - * RFC 2284, RFC 3748 - * - * $Id: eap.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2004 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __EAP_H__ -#define __EAP_H__ - -#define EAP_REQUEST 1 -#define EAP_RESPONSE 2 -#define EAP_SUCCESS 3 -#define EAP_FAILURE 4 - -WS_VAR_IMPORT const value_string eap_code_vals[]; - -#define EAP_TYPE_ID 1 -#define EAP_TYPE_NOTIFY 2 -#define EAP_TYPE_NAK 3 -#define EAP_TYPE_MD5 4 -#define EAP_TYPE_TLS 13 -#define EAP_TYPE_LEAP 17 -#define EAP_TYPE_SIM 18 -#define EAP_TYPE_TTLS 21 -#define EAP_TYPE_AKA 23 -#define EAP_TYPE_PEAP 25 -#define EAP_TYPE_MSCHAPV2 26 -#define EAP_TYPE_FAST 43 -#define EAP_TYPE_EXT 254 - -WS_VAR_IMPORT const value_string eap_type_vals[]; - - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/emem.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/emem.h deleted file mode 100644 index a1e0c898..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/emem.h +++ /dev/null @@ -1,373 +0,0 @@ -/* emem.h - * Definitions for Wireshark memory management and garbage collection - * Ronnie Sahlberg 2005 - * - * $Id: emem.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __EMEM_H__ -#define __EMEM_H__ - -#include "gnuc_format_check.h" - -/* Functions for handling memory allocation and garbage collection with - * a packet lifetime scope. - * These functions are used to allocate memory that will only remain persistent - * until Wireshark starts dissecting the next packet in the list. - * Everytime Wireshark starts decoding the next packet all memory allocated - * through these functions will be released back to the free pool. - * - * These functions are very fast and offer automatic garbage collection: - * Everytime a new packet is dissected, all memory allocations done in - * the previous packet is freed. - */ -/* Initialize packet-lifetime memory allocation pool. This function is called - * once when [t]Wireshark is initialized to set up the required structures. - */ -void ep_init_chunk(void); - -/* Allocate memory with a packet lifetime scope */ -void *ep_alloc(size_t size); -#define ep_new(type) ((type*)ep_alloc(sizeof(type))) - -/* Allocate memory with a packet lifetime scope and fill it with zeros*/ -void* ep_alloc0(size_t size); -#define ep_new0(type) ((type*)ep_alloc0(sizeof(type))) - -/* Duplicate a string with a packet lifetime scope */ -gchar* ep_strdup(const gchar* src); - -/* Duplicate at most n characters of a string with a packet lifetime scope */ -gchar* ep_strndup(const gchar* src, size_t len); - -/* Duplicate a buffer with a packet lifetime scope */ -void* ep_memdup(const void* src, size_t len); - -/* Create a formatted string with a packet lifetime scope */ -gchar* ep_strdup_vprintf(const gchar* fmt, va_list ap); -gchar* ep_strdup_printf(const gchar* fmt, ...) - GNUC_FORMAT_CHECK(printf, 1, 2); - -/* allocates with a packet lifetime scope an array of type made of num elements */ -#define ep_alloc_array(type,num) (type*)ep_alloc(sizeof(type)*(num)) - -/* allocates with a packet lifetime scope an array of type made of num elements, - * initialised to zero. - */ -#define ep_alloc_array0(type,num) (type*)ep_alloc0(sizeof(type)*(num)) - -/* - * Splits a string into a maximum of max_tokens pieces, using the given - * delimiter. If max_tokens is reached, the remainder of string is appended - * to the last token. Consecutive delimiters are treated as a single delimiter. - * - * the vector and all the strings are allocated with packet lifetime scope - */ -gchar** ep_strsplit(const gchar* string, const gchar* delimiter, int max_tokens); - -/* release all memory allocated in the previous packet dissector */ -void ep_free_all(void); - - -/* a stack implemented using ephemeral allocators */ - -typedef struct _ep_stack_frame_t** ep_stack_t; - -struct _ep_stack_frame_t { - void* payload; - struct _ep_stack_frame_t* below; - struct _ep_stack_frame_t* above; -}; - -/* - * creates an empty stack with a packet lifetime scope - */ -ep_stack_t ep_stack_new(void); - -/* - * pushes item into stack, returns item - */ -void* ep_stack_push(ep_stack_t stack, void* item); - -/* - * pops an item from the stack - */ -void* ep_stack_pop(ep_stack_t stack); - -/* - * returns the item on top of the stack without popping it - */ -#define ep_stack_peek(stack) ((*(stack))->payload) - - -/* Functions for handling memory allocation and garbage collection with - * a capture lifetime scope. - * These functions are used to allocate memory that will only remain persistent - * until Wireshark opens a new capture or capture file. - * Everytime Wireshark starts a new capture or opens a new capture file - * all the data allocated through these functions will be released back - * to the free pool. - * - * These functions are very fast and offer automatic garbage collection. - */ -/* Initialize capture-lifetime memory allocation pool. This function is called - * once when [t]Wireshark is initialized to set up the required structures. - */ -void se_init_chunk(void); - -/* Allocate memory with a capture lifetime scope */ -void *se_alloc(size_t size); - -/* Allocate memory with a capture lifetime scope and fill it with zeros*/ -void* se_alloc0(size_t size); - -/* Duplicate a string with a capture lifetime scope */ -gchar* se_strdup(const gchar* src); - -/* Duplicate at most n characters of a string with a capture lifetime scope */ -gchar* se_strndup(const gchar* src, size_t len); - -/* Duplicate a buffer with a capture lifetime scope */ -void* se_memdup(const void* src, size_t len); - -/* Create a formatted string with a capture lifetime scope */ -gchar* se_strdup_vprintf(const gchar* fmt, va_list ap); -gchar* se_strdup_printf(const gchar* fmt, ...) - GNUC_FORMAT_CHECK(printf, 1, 2); - -/* allocates with a capture lifetime scope an array of type made of num elements */ -#define se_alloc_array(type,num) (type*)se_alloc(sizeof(type)*(num)) - -/* release all memory allocated */ -void se_free_all(void); - - - - -/************************************************************** - * binary trees - **************************************************************/ -typedef struct _emem_tree_node_t { - struct _emem_tree_node_t *parent; - struct _emem_tree_node_t *left; - struct _emem_tree_node_t *right; - struct { -#define EMEM_TREE_RB_COLOR_RED 0 -#define EMEM_TREE_RB_COLOR_BLACK 1 - guint32 rb_color:1; -#define EMEM_TREE_NODE_IS_DATA 0 -#define EMEM_TREE_NODE_IS_SUBTREE 1 - guint32 is_subtree:1; - } u; - guint32 key32; - void *data; -} emem_tree_node_t; - -/* Right now we only do basic red/black trees but in the future we might want - * to try something different, such as a tree where each node keeps track - * of how many times it has been looked up, and letting often looked up - * nodes bubble upwards in the tree using rotate_right/left. - * That would probably be good for things like nfs filehandles - */ -#define EMEM_TREE_TYPE_RED_BLACK 1 -typedef struct _emem_tree_t { - struct _emem_tree_t *next; - int type; - const char *name; /* just a string to make debugging easier */ - emem_tree_node_t *tree; - void *(*malloc)(size_t); -} emem_tree_t; - -/* list of all trees with se allocation scope so that they can all be reset - * automatically when we free all se memory - */ -extern emem_tree_t *se_trees; - - -/* ******************************************************************* - * Tree functions for SE memory allocation scope - * ******************************************************************* */ -/* This function is used to create a se based tree with monitoring. - * When the SE heap is released back to the system the pointer to the - * tree is automatically reset to NULL. - * - * type is : EMEM_TREE_TYPE_RED_BLACK for a standard red/black tree. - */ -emem_tree_t *se_tree_create(int type, const char *name); - -/* This function is similar to the se_tree_create() call but with the - * difference that when the se memory is release everything including the - * pointer to the tree itself will be released. - * This tree will not be just reset to zero it will be completely forgotten - * by the allocator. - * Use this function for when you want to store the pointer to a tree inside - * another structure that is also se allocated so that when the structure is - * released, the tree will be completely released as well. - */ -emem_tree_t *se_tree_create_non_persistent(int type, const char *name); - -/* se_tree_insert32 - * Insert data into the tree and key it by a 32bit integer value - */ -#define se_tree_insert32 emem_tree_insert32 - -/* se_tree_lookup32 - * Retreive the data at the search key. the search key is a 32bit integer value - */ -#define se_tree_lookup32 emem_tree_lookup32 - -/* se_tree_lookup32_le - * Retreive the data for the largest key that is less than or equal - * to the search key. - */ -#define se_tree_lookup32_le emem_tree_lookup32_le - -/* se_tree_insert32_array - * Insert data into the tree and key it by a 32bit integer value - */ -#define se_tree_insert32_array emem_tree_insert32_array - -/* se_tree_lookup32_array - * Lookup data from the tree that is index by an array - */ -#define se_tree_lookup32_array emem_tree_lookup32_array - - - -/* Create a new string based hash table */ -#define se_tree_create_string() se_tree_create(SE_TREE_TYPE_RED_BLACK) - -/* Insert a new value under a string key */ -#define se_tree_insert_string emem_tree_insert_string - -/* Lookup the value under a string key */ -#define se_tree_lookup_string emem_tree_lookup_string - -/* Traverse a tree */ -#define se_tree_foreach emem_tree_foreach - - -/* ******************************************************************* - * Tree functions for PE memory allocation scope - * ******************************************************************* */ -/* These trees have PErmanent allocation scope and will never be released - */ -emem_tree_t *pe_tree_create(int type, char *name); -#define pe_tree_insert32 emem_tree_insert32 -#define pe_tree_lookup32 emem_tree_lookup32 -#define pe_tree_lookup32_le emem_tree_lookup32_le -#define pe_tree_insert32_array emem_tree_insert32_array -#define pe_tree_lookup32_array emem_tree_lookup32_array -#define pe_tree_insert_string emem_tree_insert_string -#define pe_tree_lookup_string emem_tree_lookup_string -#define pe_tree_foreach emem_tree_foreach - - - -/* ****************************************************************** - * Real tree functions - * ****************************************************************** */ - -/* This function is used to insert a node indexed by a guint32 key value. - * The data pointer should be allocated by the appropriate storage scope - * so that it will be released at the same time as the tree itself is - * destroyed. - */ -void emem_tree_insert32(emem_tree_t *se_tree, guint32 key, void *data); - -/* This function will look up a node in the tree indexed by a guint32 integer - * value. - */ -void *emem_tree_lookup32(emem_tree_t *se_tree, guint32 key); - -/* This function will look up a node in the tree indexed by a guint32 integer - * value. - * The function will return the node that has the largest key that is - * equal to or smaller than the search key, or NULL if no such key was - * found. - */ -void *emem_tree_lookup32_le(emem_tree_t *se_tree, guint32 key); - -typedef struct _emem_tree_key_t { - guint32 length; /*length in guint32 words */ - guint32 *key; -} emem_tree_key_t; - -/* This function is used to insert a node indexed by a sequence of guint32 - * key values. - * The data pointer should be allocated by SE allocators so that the - * data will be released at the same time as the tree itself is destroyed. - * - * Note: all the "key" members of the "key" argument MUST be aligned on - * 32-bit boundaries; otherwise, this code will crash on platforms such - * as SPARC that require aligned pointers. - * - * If you use ...32_array() calls you MUST make sure that every single node - * you add to a specific tree always has a key of exactly the same number of - * keylen words or things will most likely crash. Or at least that every single - * item that sits behind the same top level node always have exactly the same - * number of words. - * - * One way to guarantee this is the way that NFS does this for the - * nfs_name_snoop_known tree which holds filehandles for both v2 and v3. - * v2 filehandles are always 32 bytes (8 words) while v3 filehandles can have - * any length (though 32bytes are most common). - * The NFS dissector handles this by providing a guint32 containing the length - * as the very first item in this vector : - * - * emem_tree_key_t fhkey[3]; - * - * fhlen=nns->fh_length; - * fhkey[0].length=1; - * fhkey[0].key=&fhlen; - * fhkey[1].length=fhlen/4; - * fhkey[1].key=nns->fh; - * fhkey[2].length=0; - */ -void emem_tree_insert32_array(emem_tree_t *se_tree, emem_tree_key_t *key, void *data); - -/* This function will look up a node in the tree indexed by a sequence of - * guint32 integer values. - */ -void *emem_tree_lookup32_array(emem_tree_t *se_tree, emem_tree_key_t *key); - -/* case insensitive strings as keys */ -#define EMEM_TREE_STRING_NOCASE 0x00000001 -/* Insert a new value under a string key */ -void emem_tree_insert_string(emem_tree_t* h, const gchar* k, void* v, guint32 flags); - -/* Lookup the value under a string key */ -void* emem_tree_lookup_string(emem_tree_t* h, const gchar* k, guint32 flags); - - -/* traverse a tree. if the callback returns TRUE the traversal will end */ -typedef gboolean (*tree_foreach_func)(void *value, void *userdata); - -gboolean emem_tree_foreach(emem_tree_t* emem_tree, tree_foreach_func callback, void *user_data); - - - - -void emem_print_tree(emem_tree_t* emem_tree); - - - -#endif /* emem.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/epan.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/epan.h deleted file mode 100644 index 9da31108..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/epan.h +++ /dev/null @@ -1,93 +0,0 @@ -/* epan.h - * - * $Id: epan.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark Protocol Analyzer Library - * - * Copyright (c) 2001 by Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef EPAN_H -#define EPAN_H - -#include -#include "frame_data.h" -#include "column_info.h" -#include "register.h" - -typedef struct _epan_dissect_t epan_dissect_t; - -#include "dfilter/dfilter.h" - -/* init the whole epan module, this is used to be called only once in a program */ -void epan_init(void (*register_all_protocols)(register_cb cb, gpointer client_data), - void (*register_all_handoffs)(register_cb cb, gpointer client_data), - register_cb cb, - void *client_data, - void (*report_failure)(const char *, va_list), - void (*report_open_failure)(const char *, int, gboolean), - void (*report_read_failure)(const char *, int)); -/* cleanup the whole epan module, this is used to be called only once in a program */ -void epan_cleanup(void); -/* Initialize the table of conversations. */ -void epan_conversation_init(void); -/* Initialize the table of circuits. */ -/* XXX - what is a circuit and should this better be combined with epan_conversation_init? */ -void epan_circuit_init(void); - -/* A client will create one epan_t for an entire dissection session. - * A single epan_t will be used to analyze the entire sequence of packets, - * sequentially, in a single session. A session corresponds to a single - * packet trace file. The reaons epan_t exists is that some packets in - * some protocols cannot be decoded without knowledge of previous packets. - * This inter-packet "state" is stored in the epan_t. - */ -/* XXX - NOTE: epan_t, epan_new and epan_free are currently unused! */ -typedef struct epan_session epan_t; - -epan_t* -epan_new(void); - -void -epan_free(epan_t*); - -extern gchar* -epan_get_version(void); - -/* get a new single packet dissection */ -/* should be freed using epan_dissect_free() after packet dissection completed */ -epan_dissect_t* -epan_dissect_new(gboolean create_proto_tree, gboolean proto_tree_visible); - -/* run a single packet dissection */ -void -epan_dissect_run(epan_dissect_t *edt, void* pseudo_header, - const guint8* data, frame_data *fd, column_info *cinfo); - -/* Prime a proto_tree using the fields/protocols used in a dfilter. */ -void -epan_dissect_prime_dfilter(epan_dissect_t *edt, const dfilter_t *dfcode); - -/* fill the dissect run output into the packet list columns */ -void -epan_dissect_fill_in_columns(epan_dissect_t *edt); - -/* free a single packet dissection */ -void -epan_dissect_free(epan_dissect_t* edt); - -#endif /* EPAN_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/epan_dissect.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/epan_dissect.h deleted file mode 100644 index 9f40f39a..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/epan_dissect.h +++ /dev/null @@ -1,44 +0,0 @@ -/* epan_dissect.h - * - * $Id: epan_dissect.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark Protocol Analyzer Library - * - * Copyright (c) 2001 by Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef EPAN_DISSECT_H -#define EPAN_DISSECT_H - -#include "tvbuff.h" -#include "proto.h" -#include "packet_info.h" - -/* Dissection of a single byte array. Holds tvbuff info as - * well as proto_tree info. As long as the epan_dissect_t for a byte - * array is in existence, you must not free or move that byte array, - * as the structures that the epan_dissect_t contains might have pointers - * to addresses in your byte array. - */ -struct _epan_dissect_t { - tvbuff_t *tvb; - proto_tree *tree; - packet_info pi; -}; - - -#endif /* EPAN_DISSECT_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/etypes.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/etypes.h deleted file mode 100644 index 34898676..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/etypes.h +++ /dev/null @@ -1,408 +0,0 @@ -/* etypes.h - * Defines ethernet packet types, similar to tcpdump's ethertype.h - * - * $Id: etypes.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __ETYPES_H__ -#define __ETYPES_H__ - -/* - * Maximum length of an IEEE 802.3 frame; Ethernet type/length values - * greater than it are types, Ethernet type/length values less than or - * equal to it are lengths. - */ -#define IEEE_802_3_MAX_LEN 1500 - -#ifndef ETHERTYPE_UNK -#define ETHERTYPE_UNK 0x0000 -#endif - -/* Sources: - * http://www.iana.org/assignments/ethernet-numbers - * TCP/IP Illustrated, Volume 1 - * RFCs 894, 1042, 826 - * tcpdump's ethertype.h - * http://www.cavebear.com/CaveBear/Ethernet/ - * http://standards.ieee.org/regauth/ethertype/type-pub.html - * http://standards.ieee.org/regauth/ethertype/eth.txt - * (The first of the two IEEE URLs is the one that the "EtherType Field - * Public Assignments" link on the page at - * - * http://standards.ieee.org/regauth/ethertype/index.shtml - * - * goes to, but it is redirected to the second of those - i.e., both - * of the IEEE URLs ultimately go to the same page.) - */ - -/* Order these values by number */ - -#ifndef ETHERTYPE_XNS_IDP -#define ETHERTYPE_XNS_IDP 0x0600 -#endif - -#ifndef ETHERTYPE_IP -#define ETHERTYPE_IP 0x0800 -#endif - -#ifndef ETHERTYPE_X25L3 -#define ETHERTYPE_X25L3 0x0805 -#endif - -#ifndef ETHERTYPE_ARP -#define ETHERTYPE_ARP 0x0806 -#endif - -#ifndef ETHERTYPE_WOL -#define ETHERTYPE_WOL 0x0842 /* Wake on LAN. Not offically registered. */ -#endif - -#ifndef ETHERTYPE_WMX_M2M -#define ETHERTYPE_WMX_M2M 0x08f0 -#endif - -#ifndef ETHERTYPE_VINES_IP -#define ETHERTYPE_VINES_IP 0x0bad -#endif - -#ifndef ETHERTYPE_VINES_ECHO -#define ETHERTYPE_VINES_ECHO 0x0baf -#endif - -#ifndef ETHERTYPE_TRAIN -/* - * Created by Microsoft Network Monitor as a summary packet. - */ -#define ETHERTYPE_TRAIN 0x1984 -#endif - -#ifndef ETHERTYPE_CGMP -#define ETHERTYPE_CGMP 0x2001 -#endif - -#ifndef ETHERTYPE_CENTRINO_PROMISC -#define ETHERTYPE_CENTRINO_PROMISC 0x2452 /* Intel Centrino promiscuous packets */ -#endif - -#ifndef ETHERTYPE_3C_NBP_DGRAM -#define ETHERTYPE_3C_NBP_DGRAM 0x3c07 -#endif - -#ifndef ETHERTYPE_EPL_V1 -#define ETHERTYPE_EPL_V1 0x3E3F -#endif - -#ifndef ETHERTYPE_DEC -#define ETHERTYPE_DEC 0x6000 -#endif - -#ifndef ETHERTYPE_DNA_DL -#define ETHERTYPE_DNA_DL 0x6001 -#endif - -#ifndef ETHERTYPE_DNA_RC -#define ETHERTYPE_DNA_RC 0x6002 -#endif - -#ifndef ETHERTYPE_DNA_RT -#define ETHERTYPE_DNA_RT 0x6003 -#endif - -#ifndef ETHERTYPE_LAT -#define ETHERTYPE_LAT 0x6004 -#endif - -#ifndef ETHERTYPE_DEC_DIAG -#define ETHERTYPE_DEC_DIAG 0x6005 -#endif - -#ifndef ETHERTYPE_DEC_CUST -#define ETHERTYPE_DEC_CUST 0x6006 -#endif - -#ifndef ETHERTYPE_DEC_SCA -#define ETHERTYPE_DEC_SCA 0x6007 -#endif - -#ifndef ETHERTYPE_ETHBRIDGE -#define ETHERTYPE_ETHBRIDGE 0x6558 /* transparent Ethernet bridging [RFC1701]*/ -#endif - -#ifndef ETHERTYPE_RAW_FR -#define ETHERTYPE_RAW_FR 0x6559 /* Raw Frame Relay [RFC1701] */ -#endif - -#ifndef ETHERTYPE_REVARP -#define ETHERTYPE_REVARP 0x8035 -#endif - -#ifndef ETHERTYPE_DEC_LB -#define ETHERTYPE_DEC_LB 0x8038 -#endif - -#ifndef ETHERTYPE_DEC_LAST -#define ETHERTYPE_DEC_LAST 0x8041 /* DEC Local Area Systems Transport */ -#endif - -#ifndef ETHERTYPE_ATALK -#define ETHERTYPE_ATALK 0x809b -#endif - -#ifndef ETHERTYPE_SNA -#define ETHERTYPE_SNA 0x80d5 -#endif - -#ifndef ETHERTYPE_AARP -#define ETHERTYPE_AARP 0x80f3 -#endif - -#ifndef ETHERTYPE_VLAN -#define ETHERTYPE_VLAN 0x8100 /* 802.1Q Virtual LAN */ -#endif - -#ifndef ETHERTYPE_NSRP -#define ETHERTYPE_NSRP 0x8133 -#endif - -#ifndef ETHERTYPE_IPX -#define ETHERTYPE_IPX 0x8137 -#endif - -#ifndef ETHERTYPE_SNMP -#define ETHERTYPE_SNMP 0x814c /* SNMP over Ethernet, RFC 1089 */ -#endif - -#ifndef ETHERTYPE_WCP -#define ETHERTYPE_WCP 0x80ff /* Wellfleet Compression Protocol */ -#endif - -#ifndef ETHERTYPE_STP -#define ETHERTYPE_STP 0x8181 /* STP, HIPPI-ST */ -#endif - -#ifndef ETHERTYPE_ISMP -#define ETHERTYPE_ISMP 0x81fd /* Cabletron Interswitch Message Protocol */ -#endif - -#ifndef ETHERTYPE_ISMP_TBFLOOD -#define ETHERTYPE_ISMP_TBFLOOD 0x81ff /* Cabletron Interswitch Message Protocol */ -#endif - -#ifndef ETHERTYPE_IPv6 -#define ETHERTYPE_IPv6 0x86dd -#endif - -#ifndef ETHERTYPE_WLCCP -#define ETHERTYPE_WLCCP 0x872d /* Cisco Wireless Lan Context Control Protocol */ -#endif - -#ifndef ETHERTYPE_MAC_CONTROL -#define ETHERTYPE_MAC_CONTROL 0x8808 -#endif - -#ifndef ETHERTYPE_SLOW_PROTOCOLS -#define ETHERTYPE_SLOW_PROTOCOLS 0x8809 -#endif - -#ifndef ETHERTYPE_PPP -#define ETHERTYPE_PPP 0x880b /* no, this is not PPPoE */ -#endif - -#ifndef ETHERTYPE_COBRANET -#define ETHERTYPE_COBRANET 0x8819 /* Cirrus cobranet */ -#endif - -#ifndef ETHERTYPE_MPLS -#define ETHERTYPE_MPLS 0x8847 /* MPLS unicast packet */ -#endif - -#ifndef ETHERTYPE_MPLS_MULTI -#define ETHERTYPE_MPLS_MULTI 0x8848 /* MPLS multicast packet */ -#endif - -#ifndef ETHERTYPE_FOUNDRY -#define ETHERTYPE_FOUNDRY 0x885a /* Some Foundry proprietary protocol */ -#endif - -#ifndef ETHERTYPE_PPPOED -#define ETHERTYPE_PPPOED 0x8863 /* PPPoE Discovery Protocol */ -#endif - -#ifndef ETHERTYPE_PPPOES -#define ETHERTYPE_PPPOES 0x8864 /* PPPoE Session Protocol */ -#endif - -#ifndef ETHERTYPE_INTEL_ANS -#define ETHERTYPE_INTEL_ANS 0x886d /* Intel ANS (NIC teaming) http://www.intel.com/support/network/adapter/ans/probes.htm */ -#endif - -#ifndef ETHERTYPE_MS_NLB_HEARTBEAT -#define ETHERTYPE_MS_NLB_HEARTBEAT 0x886f /* MS Network Load Balancing heartbeat http://www.microsoft.com/technet/treeview/default.asp?url=/TechNet/prodtechnol/windows2000serv/deploy/confeat/nlbovw.asp */ -#endif - -#ifndef ETHERTYPE_HOMEPLUG -#define ETHERTYPE_HOMEPLUG 0x887B /* IEEE assigned Ethertype */ -#endif - -#ifndef ETHERTYPE_CDMA2000_A10_UBS -#define ETHERTYPE_CDMA2000_A10_UBS 0x8881 /* the byte stream protocol that is used for IP based micro-mobility bearer interfaces (A10) in CDMA2000(R)-based wireless networks */ -#endif - -#ifndef ETHERTYPE_EAPOL -#define ETHERTYPE_EAPOL 0x888e /* 802.1x Authentication */ -#endif - -#ifndef ETHERTYPE_PROFINET -#define ETHERTYPE_PROFINET 0x8892 /* PROFIBUS PROFINET protocol */ -#endif - -#ifndef ETHERTYPE_HYPERSCSI -#define ETHERTYPE_HYPERSCSI 0x889A /* HyperSCSI */ -#endif - -#ifndef ETHERTYPE_CSM_ENCAPS -#define ETHERTYPE_CSM_ENCAPS 0x889B /* Mindspeed Technologies www.mindspeed.com */ -#endif - -#ifndef ETHERTYPE_TELKONET -#define ETHERTYPE_TELKONET 0x88A1 /* Telkonet powerline ethernet */ -#endif - -#ifndef ETHERTYPE_AOE -#define ETHERTYPE_AOE 0x88A2 -#endif - -#ifndef ETHERTYPE_ECATF -#define ETHERTYPE_ECATF 0x88A4 /* Ethernet type for EtherCAT frames */ -#endif - -#ifndef ETHERTYPE_IEEE_802_1AD -#define ETHERTYPE_IEEE_802_1AD 0x88A8 /* IEEE 802.1ad Provider Bridge, Q-in-Q */ -#endif - -#ifndef ETHERTYPE_EPL_V2 -#define ETHERTYPE_EPL_V2 0x88AB -#endif - -#ifndef ETHERTYPE_BRDWALK -#define ETHERTYPE_BRDWALK 0x88AE -#endif - -#ifndef ETHERTYPE_IEEE802_OUI_EXTENDED -#define ETHERTYPE_IEEE802_OUI_EXTENDED 0x88B7 /* IEEE 802a OUI Extended Ethertype */ -#endif - -#ifndef ETHERTYPE_IEC61850_GOOSE -#define ETHERTYPE_IEC61850_GOOSE 0x88b8 /* IEC 61850 is a global standard for the use in utility communication,*/ -#endif /* in particular for the information exchange between IED's in a power */ - /* transmission or distribution substation. */ - /* There are three types of application services - that use a specific EtherType. GOOSE uses - EtherType field 88b8, GSE management services - uses EtherType field 88b9. These two protocols - are defined in IEC 61850-8-1. SV (Sampled - Value Transmission) uses EtherType field - 88ba; the protocol is defined in IEC 61850-9-1 - and IEC 61850-9-2. */ - -#ifndef ETHERTYPE_IEC61850_GSE -#define ETHERTYPE_IEC61850_GSE 0x88b9 /* IEC 61850 is a global standard for the use in utility communication,*/ -#endif /* in particular for the information exchange between IED's in a power */ - -#ifndef ETHERTYPE_IEC61850_SV -#define ETHERTYPE_IEC61850_SV 0x88ba /* IEC 61850 is a global standard for the use in utility communication,*/ -#endif /* in particular for the information exchange between IED's in a power */ - -#ifndef ETHERTYPE_TIPC -#define ETHERTYPE_TIPC 0x88ca /* TIPC (Transparent Inter Process Communication, */ -#endif /* http://tipc.sourceforge.net/) Ericsson Research Canada Inc */ - -#ifndef ETHERTYPE_RSN_PREAUTH -#define ETHERTYPE_RSN_PREAUTH 0x88c7 /* 802.11i Pre-Authentication */ -#endif - -#ifndef ETHERTYPE_LLDP -#define ETHERTYPE_LLDP 0x88cc /* IEEE 802.1AB Link Layer Discovery Protocol (LLDP) */ -#endif - -#ifndef ETHERTYPE_SERCOS -#define ETHERTYPE_SERCOS 0x88cd /* SERCOS interface real-time protocol for motion control */ -#endif - -#ifndef ETHERTYPE_3GPP2 -#define ETHERTYPE_3GPP2 0x88d2 /* This will be used in a revision of the Interoperabi */ -#endif /* Specification (IOS) for cdma2000 Access Network Interfaces (document numbers A.S0011-B */ - /* through A.S0017-B v1.0). This document already uses the Ether type 8881 */ - -#ifndef ETHERTYPE_LLTD -#define ETHERTYPE_LLTD 0x88d9 /* Link Layer Topology Discovery (LLTD) */ -#endif - -#ifndef ETHERTYPE_MRP -#define ETHERTYPE_MRP 0x88e3 /* IEC 61158-6-10 Media Redundancy Protocol (MRP) */ -#endif - -#ifndef ETHERTYPE_IEEE_802_1AH -#define ETHERTYPE_IEEE_802_1AH 0x88F0 /* IEEE 802.1ah Provider Backbone Bridge Mac-in-Mac */ -#endif - -#ifndef ETHERTYPE_PTP -#define ETHERTYPE_PTP 0x88F7 /* IEEE1588v2 (PTPv2) over Ethernet */ -#endif /* in particular for the information exchange between IED's in a power */ - /* transmission or distribution substation. */ - /* There are three types of application services */ - -#ifndef ETHERTYPE_PRP -#define ETHERTYPE_PRP 0x88FB /* Parallel Redundancy Protocol (IEC62439 Chapter 6) */ -#endif - -#ifndef ETHERTYPE_CFM -#define ETHERTYPE_CFM 0x8902 /* IEEE 802.1ag Connectivity Fault Management */ -#endif /* (CFM) protocol. */ - -#ifndef ETHERTYPE_FCOE -#define ETHERTYPE_FCOE 0x8906 /* Fibre Channel over Ethernet */ -#endif - -#ifndef ETHERTYPE_LOOP -#define ETHERTYPE_LOOP 0x9000 /* used for layer 2 testing (do i see my own frames on the wire) */ -#endif - -#ifndef ETHERTYPE_RTMAC -#define ETHERTYPE_RTMAC 0x9021 /* RTnet: Real-Time Media Access Control */ -#endif - -#ifndef ETHERTYPE_RTCFG -#define ETHERTYPE_RTCFG 0x9022 /* RTnet: Real-Time Configuration Protocol */ -#endif - -#ifndef ETHERTYPE_LLT -#define ETHERTYPE_LLT 0xCAFE /* Veritas Low Latency Transport (not officially registered) */ -#endif - -#ifndef ETHERTYPE_FCFT -/* type used to transport FC frames+MDS hdr internal to Cisco's MDS switch */ -#define ETHERTYPE_FCFT 0xFCFC -#endif - -extern const value_string etype_vals[]; - -#endif /* etypes.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ex-opt.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ex-opt.h deleted file mode 100644 index 5839b726..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ex-opt.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * ex-opt.h - * - * eXtension command line options - * - * (c) 2006, Luis E. Garcia Ontanon - * - * $Id: ex-opt.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef _EX_OPT_H -#define _EX_OPT_H - -/* will be called by main each time a -X option is found */ -extern gboolean ex_opt_add(const gchar* optarg); - -/* yields the number of arguments of a given key obviously returns 0 if there aren't */ -extern gint ex_opt_count(const gchar* key); - -/* fetches the nth argument of a given key returns NULL if there isn't */ -extern const gchar* ex_opt_get_index(const gchar* key, guint index); - -/* extracts the next value of a given key */ -extern const gchar* ex_opt_get_next(const gchar* key); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/except.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/except.h deleted file mode 100644 index 42e62ce5..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/except.h +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Portable Exception Handling for ANSI C. - * Copyright (C) 1999 Kaz Kylheku - * - * Free Software License: - * - * All rights are reserved by the author, with the following exceptions: - * Permission is granted to freely reproduce and distribute this software, - * possibly in exchange for a fee, provided that this copyright notice appears - * intact. Permission is also granted to adapt this software to produce - * derivative works, as long as the modified versions carry this copyright - * notice and additional notices stating that the work has been modified. - * This source code may be translated into executable form and incorporated - * into proprietary software; there is no requirement for such software to - * contain a copyright notice related to this source. - * - * $Id: except.h 3992 2008-06-10 03:13:11Z dgu $ - * $Name: $ - */ - -/* - * Modified to support throwing an exception with a null message pointer, - * and to have the message not be const (as we generate messages with - * "g_strdup_sprintf()", which means they need to be freed; using - * a null message means that we don't have to use a special string - * for exceptions with no message, and don't have to worry about - * not freeing that). - */ - -#ifndef XCEPT_H -#define XCEPT_H - -#include -#include -#include - -#define XCEPT_GROUP_ANY 0 -#define XCEPT_CODE_ANY 0 -#define XCEPT_BAD_ALLOC 1 - -#ifdef __cplusplus -extern "C" { -#endif - -enum { except_no_call, except_call }; - -typedef struct { - unsigned long except_group; - unsigned long except_code; -} except_id_t; - -typedef struct { - except_id_t volatile except_id; - const char *volatile except_message; - void *volatile except_dyndata; -} except_t; - -struct except_cleanup { - void (*except_func)(void *); - void *except_context; -}; - -struct except_catch { - const except_id_t *except_id; - size_t except_size; - except_t except_obj; - jmp_buf except_jmp; -}; - -enum except_stacktype { - XCEPT_CLEANUP, XCEPT_CATCHER -}; - -struct except_stacknode { - struct except_stacknode *except_down; - enum except_stacktype except_type; - union { - struct except_catch *except_catcher; - struct except_cleanup *except_cleanup; - } except_info; -}; - -/* private functions made external so they can be used in macros */ -extern void except_setup_clean(struct except_stacknode *, - struct except_cleanup *, void (*)(void *), void *); -extern void except_setup_try(struct except_stacknode *, - struct except_catch *, const except_id_t [], size_t); -extern struct except_stacknode *except_pop(void); - -/* public interface functions */ -extern int except_init(void); -extern void except_deinit(void); -extern void except_rethrow(except_t *); -extern void except_throw(long, long, const char *); -extern void except_throwd(long, long, const char *, void *); -extern void except_throwf(long, long, const char *, ...); -extern void (*except_unhandled_catcher(void (*)(except_t *)))(except_t *); -extern unsigned long except_code(except_t *); -extern unsigned long except_group(except_t *); -extern const char *except_message(except_t *); -extern void *except_data(except_t *); -extern void *except_take_data(except_t *); -extern void except_set_allocator(void *(*)(size_t), void (*)(void *)); -extern void *except_alloc(size_t); -extern void except_free(void *); - -#define except_code(E) ((E)->except_id.except_code) -#define except_group(E) ((E)->except_id.except_group) -#define except_message(E) ((E)->except_message) -#define except_data(E) ((E)->except_dyndata) - -#ifdef __cplusplus -} -#endif - -/* - * void except_cleanup_push(void (*)(void *), void *); - * void except_cleanup_pop(int); - * void except_checked_cleanup_pop(void (*)(void *), int); - * void except_try_push(const except_id_t [], size_t, except_t **); - * void except_try_pop(void); - */ - -#define except_cleanup_push(F, C) \ - { \ - struct except_stacknode except_sn; \ - struct except_cleanup except_cl; \ - except_setup_clean(&except_sn, &except_cl, F, C) - -#define except_cleanup_pop(E) \ - except_pop(); \ - if (E) \ - except_cl.except_func(except_cl.except_context); \ - } - -#define except_checked_cleanup_pop(F, E) \ - except_pop(); \ - assert (except_cl.except_func == (F)); \ - if (E) \ - except_cl.except_func(except_cl.except_context); \ - } - -#define except_try_push(ID, NUM, PPE) \ - { \ - struct except_stacknode except_sn; \ - struct except_catch except_ch; \ - except_setup_try(&except_sn, &except_ch, ID, NUM); \ - if (setjmp(except_ch.except_jmp)) \ - *(PPE) = &except_ch.except_obj; \ - else \ - *(PPE) = 0 - -#define except_try_pop() \ - except_free(except_ch.except_obj.except_dyndata); \ - except_pop(); \ - } - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/exceptions.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/exceptions.h deleted file mode 100644 index 52abdfd7..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/exceptions.h +++ /dev/null @@ -1,319 +0,0 @@ -#ifndef __EXCEPTIONS_H__ -#define __EXCEPTIONS_H__ - -/* $Id $ */ - -#ifndef XCEPT_H -#include "except.h" -#endif - -/* Wireshark has only one exception group, to make these macros simple */ -#define XCEPT_GROUP_WIRESHARK 1 - -/* Wireshark's exceptions */ - -/** - Index is out of range. - An attempt was made to read past the end of a buffer. - This generally means that the capture was done with a "slice" - length or "snapshot" length less than the maximum packet size, - and a link-layer packet was cut short by that, so not all of the - data in the link-layer packet was available. -**/ -#define BoundsError 1 - -/** - Index is beyond reported length (not cap_len) - An attempt was made to read past the logical end of a buffer. This - differs from a BoundsError in that the parent protocol established a - limit past which this dissector should not process in the buffer and that - limit was execeeded. - This generally means that the packet is invalid, i.e. whatever - code constructed the packet and put it on the wire didn't put enough - data into it. It is therefore currently reported as a "Malformed - packet". - However, it also happens in some cases where the packet was fragmented - and the fragments weren't reassembled. We need to add another length - field to a tvbuff, so that "length of the packet from the link layer" - and "length of the packet were it fully reassembled" are different, - and going past the first of those without going past the second would - throw a different exception, which would be reported as an "Unreassembled - packet" rather than a "Malformed packet". -**/ -#define ReportedBoundsError 2 - -/** - During dfilter parsing -**/ -#define TypeError 3 - -/** - A bug was detected in a dissector. - - DO NOT throw this with THROW(); that means that no details about - the dissector error will be reported. (Instead, the message will - blame you for not providing details.) - - Instead, use the DISSECTOR_ASSERT(), etc. macros in epan/proto.h. -**/ -#define DissectorError 4 - -/** - Index is out of range. - An attempt was made to read past the end of a buffer. - This error is specific to SCSI data transfers where for some CDBs - it is normal that the data PDU might be short. - I.e. ReportLuns initially called with allocation_length=8, just enough - to get the "size" of lun list back after which the initiator will - reissue the command with an allocation_length that is big enough. -**/ -#define ScsiBoundsError 5 - -/** - Running out of memory. - A dissector tried to allocate memory but that failed. -**/ -#define OutOfMemoryError 6 - - -/* Usage: - * - * TRY { - * code; - * } - * - * CATCH(exception) { - * code; - * } - * - * CATCH2(exception1, exception2) { - * code; - * } - * - * CATCH_ALL { - * code; - * } - * - * FINALLY { - * code; - * } - * - * ENDTRY; - * - * ********* Never use 'goto' or 'return' inside the TRY, CATCH, CATCH_ALL, - * ********* or FINALLY blocks. Execution must proceed through ENDTRY before - * ********* branching out. - * - * This is really something like: - * - * { - * caught = FALSE: - * x = setjmp(); - * if (x == 0) { - * - * } - * if (!caught && x == 1) { - * caught = TRUE; - * - * } - * if (!caught && x == 2) { - * caught = TRUE; - * - * } - * if (!caught && (x == 3 || x == 4)) { - * caught = TRUE; - * - * } - * if (!caught && x != 0) { - * caught = TRUE; - * - * } - * - * if(!caught) { - * RETHROW(x) - * } - * } - * - * All CATCH's must precede a CATCH_ALL. - * FINALLY must occur after any CATCH or CATCH_ALL. - * ENDTRY marks the end of the TRY code. - * TRY and ENDTRY are the mandatory parts of a TRY block. - * CATCH, CATCH_ALL, and FINALLY are all optional (although - * you'll probably use at least one, otherwise why "TRY"?) - * - * GET_MESSAGE returns string ptr to exception message - * when exception is thrown via THROW_MESSAGE() - * - * To throw/raise an exception. - * - * THROW(exception) - * RETHROW rethrow the caught exception - * - * A cleanup callback is a function called in case an exception occurs - * and is not caught. It should be used to free any dynamically-allocated data. - * A pop or call_and_pop should occur at the same statement-nesting level - * as the push. - * - * CLEANUP_CB_PUSH(func, data) - * CLEANUP_CB_POP - * CLEANUP_CB_CALL_AND_POP - */ - -/* we do up to three passes through the bit of code after except_try_push(), - * and except_state is used to keep track of where we are. - */ -#define EXCEPT_CAUGHT 1 /* exception has been caught, no need to rethrow at - * END_TRY */ - -#define EXCEPT_RETHROWN 2 /* the exception was rethrown from a CATCH - * block. Don't reenter the CATCH blocks, but do - * execute FINALLY and rethrow at END_TRY */ - -#define EXCEPT_FINALLY 4 /* we've entered the FINALLY block - don't allow - * RETHROW, and don't reenter FINALLY if a - * different exception is thrown */ - -#define TRY \ -{\ - except_t *exc; \ - volatile int except_state = 0; \ - static const except_id_t catch_spec[] = { \ - { XCEPT_GROUP_WIRESHARK, XCEPT_CODE_ANY } }; \ - except_try_push(catch_spec, 1, &exc); \ - \ - if(except_state & EXCEPT_CAUGHT) \ - except_state |= EXCEPT_RETHROWN; \ - except_state &= ~EXCEPT_CAUGHT; \ - \ - if (except_state == 0 && exc == 0) \ - /* user's code goes here */ - -#define ENDTRY \ - /* rethrow the exception if necessary */ \ - if(!(except_state&EXCEPT_CAUGHT) && exc != 0) \ - except_rethrow(exc); \ - except_try_pop();\ -} - -/* the (except_state |= EXCEPT_CAUGHT) in the below is a way of setting - * except_state before the user's code, without disrupting the user's code if - * it's a one-liner. - */ -#define CATCH(x) \ - if (except_state == 0 && exc != 0 && exc->except_id.except_code == (x) && \ - (except_state |= EXCEPT_CAUGHT)) \ - /* user's code goes here */ - -#define CATCH2(x,y) \ - if (except_state == 0 && exc != 0 && \ - (exc->except_id.except_code == (x) || exc->except_id.except_code == (y)) && \ - (except_state|=EXCEPT_CAUGHT)) \ - /* user's code goes here */ - -#define CATCH_ALL \ - if (except_state == 0 && exc != 0 && \ - (except_state|=EXCEPT_CAUGHT)) \ - /* user's code goes here */ - - -#define FINALLY \ - if( !(except_state & EXCEPT_FINALLY) && (except_state|=EXCEPT_FINALLY)) \ - /* user's code goes here */ - -#define THROW(x) \ - except_throw(XCEPT_GROUP_WIRESHARK, (x), NULL) - -#define THROW_MESSAGE(x, y) \ - except_throw(XCEPT_GROUP_WIRESHARK, (x), (y)) - -#define GET_MESSAGE except_message(exc) - -#define RETHROW \ - { \ - /* check we're in a catch block */ \ - g_assert(except_state == EXCEPT_CAUGHT); \ - /* we can't use except_rethrow here, as that pops a catch block \ - * off the stack, and we don't want to do that, because we want to \ - * excecute the FINALLY {} block first. \ - * except_throw doesn't provide an interface to rethrow an existing \ - * exception; however, longjmping back to except_try_push() has the \ - * desired effect. \ - * \ - * Note also that THROW and RETHROW should provide much the same \ - * functionality in terms of which blocks to enter, so any messing \ - * about with except_state in here would indicate that THROW is \ - * doing the wrong thing. \ - */ \ - longjmp(except_ch.except_jmp,1); \ - } - -#define EXCEPT_CODE except_code(exc) - -/* Register cleanup functions in case an exception is thrown and not caught. - * From the Kazlib documentation, with modifications for use with the - * Wireshark-specific macros: - * - * CLEANUP_PUSH(func, arg) - * - * The call to CLEANUP_PUSH shall be matched with a call to - * CLEANUP_CALL_AND_POP or CLEANUP_POP which must occur in the same - * statement block at the same level of nesting. This requirement allows - * an implementation to provide a CLEANUP_PUSH macro which opens up a - * statement block and a CLEANUP_POP which closes the statement block. - * The space for the registered pointers can then be efficiently - * allocated from automatic storage. - * - * The CLEANUP_PUSH macro registers a cleanup handler that will be - * called if an exception subsequently occurs before the matching - * CLEANUP_[CALL_AND_]POP is executed, and is not intercepted and - * handled by a try-catch region that is nested between the two. - * - * The first argument to CLEANUP_PUSH is a pointer to the cleanup - * handler, a function that returns nothing and takes a single - * argument of type void*. The second argument is a void* value that - * is registered along with the handler. This value is what is passed - * to the registered handler, should it be called. - * - * Cleanup handlers are called in the reverse order of their nesting: - * inner handlers are called before outer handlers. - * - * The program shall not leave the cleanup region between - * the call to the macro CLEANUP_PUSH and the matching call to - * CLEANUP_[CALL_AND_]POP by means other than throwing an exception, - * or calling CLEANUP_[CALL_AND_]POP. - * - * Within the call to the cleanup handler, it is possible that new - * exceptions may happen. Such exceptions must be handled before the - * cleanup handler terminates. If the call to the cleanup handler is - * terminated by an exception, the behavior is undefined. The exception - * which triggered the cleanup is not yet caught; thus the program - * would be effectively trying to replace an exception with one that - * isn't in a well-defined state. - * - * - * CLEANUP_POP and CLEANUP_CALL_AND_POP - * - * A call to the CLEANUP_POP or CLEANUP_CALL_AND_POP macro shall match - * each call to CLEANUP_PUSH which shall be in the same statement block - * at the same nesting level. It shall match the most recent such a - * call that is not matched by a previous CLEANUP_[CALL_AND_]POP at - * the same level. - * - * These macros causes the registered cleanup handler to be removed. If - * CLEANUP_CALL_AND_POP is called, the cleanup handler is called. - * In that case, the registered context pointer is passed to the cleanup - * handler. If CLEANUP_POP is called, the cleanup handler is not called. - * - * The program shall not leave the region between the call to the - * macro CLEANUP_PUSH and the matching call to CLEANUP_[CALL_AND_]POP - * other than by throwing an exception, or by executing the - * CLEANUP_CALL_AND_POP. - * - */ - - -#define CLEANUP_PUSH(f,a) except_cleanup_push((f),(a)) -#define CLEANUP_POP except_cleanup_pop(0) -#define CLEANUP_CALL_AND_POP except_cleanup_pop(1) - -#endif /* __EXCEPTIONS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/expert.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/expert.h deleted file mode 100644 index 3c32f25e..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/expert.h +++ /dev/null @@ -1,70 +0,0 @@ -/* expert.h - * Collecting of Expert information. - * - * For further info, see: http://wiki.wireshark.org/Development/ExpertInfo - * - * $Id: expert.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __EXPERT_H__ -#define __EXPERT_H__ - -#include "gnuc_format_check.h" -#include -#include "value_string.h" - - -/** only for internal and display use */ -typedef struct expert_info_s { - guint32 packet_num; - int group; - int severity; - gchar * protocol; - gchar * summary; - proto_item *pitem; -} expert_info_t; - -WS_VAR_IMPORT const value_string expert_severity_vals[]; -WS_VAR_IMPORT const value_string expert_group_vals[]; - -extern void -expert_init(void); - -extern void -expert_cleanup(void); - -extern int -expert_get_highest_severity(void); - -/** Add an expert info. - - @param pinfo packet info of the currently processed packet - @param pi current protocol item (or NULL) - @param group the expert group (like PI_CHECKSUM) - @param severity the expert severity (like PI_WARN) - @param format printf like format string with further infos - */ -extern void -expert_add_info_format(packet_info *pinfo, proto_item *pi, int group, - int severity, const char *format, ...) - GNUC_FORMAT_CHECK(printf, 5, 6); - -#endif /* __EXPERT_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/filesystem.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/filesystem.h deleted file mode 100644 index 5b9c9fa2..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/filesystem.h +++ /dev/null @@ -1,248 +0,0 @@ -/* filesystem.h - * Filesystem utility definitions - * - * $Id: filesystem.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef FILESYSTEM_H -#define FILESYSTEM_H - -/* - * Default profile name. - */ -#define DEFAULT_PROFILE "Default" - - -/* - * Get the pathname of the directory from which the executable came, - * and save it for future use. Returns NULL on success, and a - * g_mallocated string containing an error on failure. - */ -extern char *init_progfile_dir(const char *arg0); - -/* - * Get the directory in which the program resides. - */ -extern const char *get_progfile_dir(void); - -/* - * Get the directory in which plugins are stored; this must not be called - * before init_progfile_dir() is called, as they might be stored in a - * subdirectory of the program file directory. - */ -extern const char *get_plugin_dir(void); - -/* - * Get the flag indicating whether we're running from a build - * directory. - */ -extern gboolean running_in_build_directory(void); - -/* - * Get the directory in which global configuration files are - * stored. - */ -extern const char *get_datafile_dir(void); - -/* - * Construct the path name of a global configuration file, given the - * file name. - * - * The returned file name was g_malloc()'d so it must be g_free()d when the - * caller is done with it. - */ -extern char *get_datafile_path(const char *filename); - -/* - * Get the directory in which files that, at least on UNIX, are - * system files (such as "/etc/ethers") are stored; on Windows, - * there's no "/etc" directory, so we get them from the Wireshark - * global configuration and data file directory. - */ -extern const char *get_systemfile_dir(void); - -/* - * Set the configuration profile name to be used for storing - * personal configuration files. - */ -extern void set_profile_name(const gchar *profilename); - -/* - * Get the current configuration profile name used for storing - * personal configuration files. - */ -extern const char *get_profile_name(void); - -/* - * Get the directory used to store configuration profile directories. - */ -extern const char *get_profiles_dir(void); - -/* - * Check if given configuration profile exists. - */ -extern gboolean profile_exists(const gchar *profilename); - -/* - * Create a directory for the given configuration profile. - * If we attempted to create it, and failed, return -1 and - * set "*pf_dir_path_return" to the pathname of the directory we failed - * to create (it's g_mallocated, so our caller should free it); otherwise, - * return 0. - */ -extern int create_persconffile_profile(const char *profilename, - char **pf_dir_path_return); - -/* - * Delete the directory for the given configuration profile. - * If we attempted to delete it, and failed, return -1 and - * set "*pf_dir_path_return" to the pathname of the directory we failed - * to delete (it's g_mallocated, so our caller should free it); otherwise, - * return 0. - */ -extern int delete_persconffile_profile(const char *profilename, - char **pf_dir_path_return); - -/* - * Rename the directory for the given confinguration profile. - */ -extern int rename_persconffile_profile(const char *fromname, const char *toname, - char **pf_from_dir_path_return, - char **pf_to_dir_path_return); - -/* - * Create the directory that holds personal configuration files, if - * necessary. If we attempted to create it, and failed, return -1 and - * set "*pf_dir_path_return" to the pathname of the directory we failed - * to create (it's g_mallocated, so our caller should free it); otherwise, - * return 0. - */ -extern int create_persconffile_dir(char **pf_dir_path_return); - -/* - * Construct the path name of a personal configuration file, given the - * file name. If using configuration profiles this directory will be - * used if "from_profile" is TRUE. - * - * On Win32, if "for_writing" is FALSE, we check whether the file exists - * and, if not, construct a path name relative to the ".wireshark" - * subdirectory of the user's home directory, and check whether that - * exists; if it does, we return that, so that configuration files - * from earlier versions can be read. - * - * The returned file name was g_malloc()'d so it must be g_free()d when the - * caller is done with it. - */ -extern char *get_persconffile_path(const char *filename, gboolean from_profile, - gboolean for_writing); - -/* - * Get the (default) directory in which personal data is stored. - * - * On Win32, this is the "My Documents" folder in the personal profile. - * On UNIX this is simply the current directory. - */ -extern char *get_persdatafile_dir(void); - -/* - * Construct the path name of a file in $TMP/%TEMP% directory. - * Or "/tmp/" (C:\) if that fails. - * - * Return value is malloced so the caller should free it. - */ -extern char *get_tempfile_path(const char *filename); - -/* - * process command line option belonging to the filesystem settings - */ -extern int filesystem_opt(int opt, const char *optarg); - -/* - * Return an error message for UNIX-style errno indications on open or - * create operations. - */ -extern const char *file_open_error_message(int err, gboolean for_writing); - -/* - * Return an error message for UNIX-style errno indications on write - * operations. - */ -extern const char *file_write_error_message(int err); - -/* - * Given a pathname, return the last component. - */ -extern const char *get_basename(const char *); - -/* - * Given a pathname, return a string containing everything but the - * last component. NOTE: this overwrites the pathname handed into - * it.... - */ -extern char *get_dirname(char *); - -/* - * Given a pathname, return: - * - * the errno, if an attempt to "stat()" the file fails; - * - * EISDIR, if the attempt succeeded and the file turned out - * to be a directory; - * - * 0, if the attempt succeeded and the file turned out not - * to be a directory. - */ -extern int test_for_directory(const char *); - -/* - * Given a pathname, return: - * - * the errno, if an attempt to "stat()" the file fails; - * - * ESPIPE, if the attempt succeeded and the file turned out - * to be a FIFO; - * - * 0, if the attempt succeeded and the file turned out not - * to be a FIFO. - */ -extern int test_for_fifo(const char *); - -/* Delete a file */ -extern gboolean deletefile (const char *path); - -/* - * Check, if file is existing. - */ -extern gboolean file_exists(const char *fname); - -/* - * Check, if two filenames are identical (with absolute and relative paths). - */ -extern gboolean files_identical(const char *fname1, const char *fname2); - -#ifdef WIN32 -/* - * utf8 version of getenv, needed to get win32 filename paths - */ -extern char *getenv_utf8(const char *varname); -#endif - -#endif /* FILESYSTEM_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/follow.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/follow.h deleted file mode 100644 index 513e7add..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/follow.h +++ /dev/null @@ -1,58 +0,0 @@ -/* follow.h - * - * $Id: follow.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Copyright 1998 Mike Hall - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __FOLLOW_H__ -#define __FOLLOW_H__ - -#include - -#define MAX_IPADDR_LEN 16 - -/* With MSVC and a libwireshark.dll, we need a special declaration. */ -WS_VAR_IMPORT gboolean empty_tcp_stream; -WS_VAR_IMPORT gboolean incomplete_tcp_stream; - -typedef struct _tcp_stream_chunk { - guint8 src_addr[MAX_IPADDR_LEN]; - guint16 src_port; - guint32 dlen; -} tcp_stream_chunk; - -char* build_follow_filter( packet_info * ); -void reassemble_tcp( gulong, gulong, gulong, const char*, gulong, int, - address *, address *, guint, guint ); -void reset_tcp_reassembly( void ); - -typedef struct { - guint8 ip_address[2][MAX_IPADDR_LEN]; - guint32 port[2]; - unsigned int bytes_written[2]; - gboolean is_ipv6; -} follow_stats_t; - -void follow_stats(follow_stats_t* stats); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/frame_data.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/frame_data.h deleted file mode 100644 index 15d0d021..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/frame_data.h +++ /dev/null @@ -1,79 +0,0 @@ -/* frame_data.h - * Definitions for frame_data structures and routines - * - * $Id: frame_data.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __FRAME_DATA_H__ -#define __FRAME_DATA_H__ - -#include "column_info.h" -#include "tvbuff.h" -#include - - -/* XXX - some of this stuff is used only while a packet is being dissected; - should we keep that stuff in the "packet_info" structure, instead, to - save memory? */ -/* The frame number is the ordinal number of the frame in the capture, so - it's 1-origin. In various contexts, 0 as a frame number means "frame - number unknown". */ -typedef struct _frame_data { - struct _frame_data *next; /* Next element in list */ - struct _frame_data *prev; /* Previous element in list */ - GSList *pfd; /* Per frame proto data */ - guint32 num; /* Frame number */ - guint32 pkt_len; /* Packet length */ - guint32 cap_len; /* Amount actually captured */ - guint32 cum_bytes; /* Cumulative bytes into the capture */ - nstime_t abs_ts; /* Absolute timestamp */ - nstime_t rel_ts; /* Relative timestamp (yes, it can be negative) */ - nstime_t del_dis_ts; /* Delta timestamp to previous displayed frame (yes, it can be negative) */ - nstime_t del_cap_ts; /* Delta timestamp to previous captured frame (yes, it can be negative) */ - gint64 file_off; /* File offset */ - int lnk_t; /* Per-packet encapsulation/data-link type */ - struct { - unsigned int passed_dfilter : 1; /* 1 = display, 0 = no display */ - unsigned int encoding : 2; /* Character encoding (ASCII, EBCDIC...) */ - unsigned int visited : 1; /* Has this packet been visited yet? 1=Yes,0=No*/ - unsigned int marked : 1; /* 1 = marked by user, 0 = normal */ - unsigned int ref_time : 1; /* 1 = marked as a reference time frame, 0 = normal */ - } flags; - void *color_filter; /* Per-packet matching color_filter_t object */ - col_expr_t col_expr; /* Column expressions & values */ -} frame_data; - -/* - * A data source. - * Has a tvbuff and a name. - */ -typedef struct { - tvbuff_t *tvb; - char *name; -} data_source; - -/* Utility routines used by packet*.c */ - -extern void p_add_proto_data(frame_data *fd, int proto, void *proto_data); -extern void *p_get_proto_data(frame_data *fd, int proto); -extern void p_remove_proto_data(frame_data *fd, int proto); - -#endif /* __FRAME_DATA__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/frequency-utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/frequency-utils.h deleted file mode 100644 index 628bff4d..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/frequency-utils.h +++ /dev/null @@ -1,74 +0,0 @@ -/* frequency-utils.h - * Frequency conversion utility definitions - * - * $Id: frequency-utils.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2007 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __FREQUENCY_UTILS_H__ -#define __FREQUENCY_UTILS_H__ - -/** @file - * Frequency and channel conversion utilities. - */ - -/** - * Given a center frequency in MHz, return a channel number. - * @param freq Frequency in MHz. - * @return The equivalent channel or -1 if no match is found. - */ -gint -ieee80211_mhz_to_chan(guint freq); - -/** - * Given a channel number and a band type, return a center frequency. - * @param chan Channel number - * @param is_bg TRUE if the channel is a b/g channel, FALSE otherwise. - * @return The equivalent frequency or 0 if no match is found. - */ -guint -ieee80211_chan_to_mhz(gint chan, gboolean is_bg); - -/** - * Given a frequency in MHz, return a string representation. - * @param freq Frequench in MHz. - * @return A string showing the frequency, channel number, and type. The string must be freed with g_free() after use. - */ -gchar* -ieee80211_mhz_to_str(guint freq); - -/* Should this be "(freq < 4920)", or something else? */ -#define FREQ_IS_BG(freq) (freq <= 2484) - -/* - * Editor modelines - * - * Local Variables: - * c-basic-offset: 4 - * tab-width: 8 - * indent-tabs-mode: nil - * End: - * - * ex: set shiftwidth=4 tabstop=8 expandtab - * :indentSize=4:tabSize=8:noTabs=true: - */ - -#endif /* __FREQUENCY_UTILS_H__ */ - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ftypes/ftypes-int.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ftypes/ftypes-int.h deleted file mode 100644 index 20528f66..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ftypes/ftypes-int.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * $Id: ftypes-int.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2001 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef FTYPES_INT_H -#define FTYPES_INT_H - -#include -#include "ftypes.h" - -#ifdef HAVE_LIBPCRE -#include -#endif /* HAVE_LIBPCRE */ - - -#ifdef HAVE_LIBPCRE -struct _pcre_tuple_t { - char *string; - pcre *re; - pcre_extra *ex; - char *error; -}; -#endif /* HAVE_LIBPCRE */ - -void -ftype_register(enum ftenum ftype, ftype_t *ft); - -/* These are the ftype registration functions that need to be called. - * This list and the initialization function could be produced - * via a script, like the dissector registration, but there's so few - * that I don't mind doing it by hand for now. */ -void ftype_register_bytes(void); -void ftype_register_double(void); -void ftype_register_integers(void); -void ftype_register_ipv4(void); -void ftype_register_guid(void); -void ftype_register_none(void); -void ftype_register_string(void); -void ftype_register_time(void); -void ftype_register_tvbuff(void); -void ftype_register_pcre(void); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ftypes/ftypes.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ftypes/ftypes.h deleted file mode 100644 index 498c969c..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ftypes/ftypes.h +++ /dev/null @@ -1,367 +0,0 @@ -/* ftypes.h - * Definitions for field types - * - * $Id: ftypes.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2001 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - - -#ifndef FTYPES_H -#define FTYPES_H - -#include -#include "../slab.h" - -/* field types */ -enum ftenum { - FT_NONE, /* used for text labels with no value */ - FT_PROTOCOL, - FT_BOOLEAN, /* TRUE and FALSE come from */ - FT_UINT8, - FT_UINT16, - FT_UINT24, /* really a UINT32, but displayed as 3 hex-digits if FD_HEX*/ - FT_UINT32, - FT_UINT64, - FT_INT8, - FT_INT16, - FT_INT24, /* same as for UINT24 */ - FT_INT32, - FT_INT64, - FT_FLOAT, - FT_DOUBLE, - FT_ABSOLUTE_TIME, - FT_RELATIVE_TIME, - FT_STRING, - FT_STRINGZ, /* for use with proto_tree_add_item() */ - FT_EBCDIC, /* for use with proto_tree_add_item() */ - FT_UINT_STRING, /* for use with proto_tree_add_item() */ - /*FT_UCS2_LE, */ /* Unicode, 2 byte, Little Endian */ - FT_ETHER, - FT_BYTES, - FT_UINT_BYTES, - FT_IPv4, - FT_IPv6, - FT_IPXNET, - FT_FRAMENUM, /* a UINT32, but if selected lets you go to frame with that numbe */ - FT_PCRE, /* a compiled Perl-Compatible Regular Expression object */ - FT_GUID, /* GUID, UUID */ - FT_OID, /* OBJECT IDENTIFIER */ - FT_NUM_TYPES /* last item number plus one */ -}; - -#define IS_FT_INT(ft) ((ft)==FT_INT8||(ft)==FT_INT16||(ft)==FT_INT24||(ft)==FT_INT32) -#define IS_FT_UINT(ft) ((ft)==FT_UINT8||(ft)==FT_UINT16||(ft)==FT_UINT24||(ft)==FT_UINT32||(ft)==FT_FRAMENUM) -#define IS_FT_TIME(ft) ((ft)==FT_ABSOLUTE_TIME||(ft)==FT_RELATIVE_TIME) -#define IS_FT_STRING(ft) ((ft)==FT_STRING||(ft)==FT_STRINGZ) - -typedef enum ftenum ftenum_t; -typedef struct _ftype_t ftype_t; - -/* String representation types. */ -enum ftrepr { - FTREPR_DISPLAY, - FTREPR_DFILTER -}; - -typedef enum ftrepr ftrepr_t; - -#ifdef HAVE_LIBPCRE -typedef struct _pcre_tuple_t pcre_tuple_t; -#endif /* HAVE_LIBPCRE */ - -/* Initialize the ftypes subsytem. Called once. */ -void -ftypes_initialize(void); - -/* ---------------- FTYPE ----------------- */ - -/* Return a string representing the name of the type */ -const char* -ftype_name(ftenum_t ftype); - -/* Return a string presenting a "pretty" representation of the - * name of the type. The pretty name means more to the user than - * that "FT_*" name. */ -const char* -ftype_pretty_name(ftenum_t ftype); - -/* Returns length of field in packet, or 0 if not determinable/defined. */ -int -ftype_length(ftenum_t ftype); - -gboolean -ftype_can_slice(enum ftenum ftype); - -gboolean -ftype_can_eq(enum ftenum ftype); - -gboolean -ftype_can_ne(enum ftenum ftype); - -gboolean -ftype_can_gt(enum ftenum ftype); - -gboolean -ftype_can_ge(enum ftenum ftype); - -gboolean -ftype_can_lt(enum ftenum ftype); - -gboolean -ftype_can_le(enum ftenum ftype); - -gboolean -ftype_can_bitwise_and(enum ftenum ftype); - -gboolean -ftype_can_contains(enum ftenum ftype); - -gboolean -ftype_can_matches(enum ftenum ftype); - -/* ---------------- FVALUE ----------------- */ - -#include -#include - -#include -#include -#include - -typedef struct _fvalue_t { - ftype_t *ftype; - union { - /* Put a few basic types in here */ - gpointer pointer; - guint32 uinteger; - gint32 sinteger; - guint64 integer64; - gdouble floating; - gchar *string; - guchar *ustring; - GByteArray *bytes; - GString *gstring; - ipv4_addr ipv4; - e_guid_t guid; - nstime_t time; - tvbuff_t *tvb; -#ifdef HAVE_LIBPCRE - pcre_tuple_t *re; -#endif /* HAVE_LIBPCRE */ - } value; - - /* The following is provided for private use - * by the fvalue. */ - gboolean fvalue_gboolean1; - -} fvalue_t; - -typedef void (*FvalueNewFunc)(fvalue_t*); -typedef void (*FvalueFreeFunc)(fvalue_t*); -typedef void (*LogFunc)(const char*,...); - -typedef gboolean (*FvalueFromUnparsed)(fvalue_t*, char*, gboolean, LogFunc); -typedef gboolean (*FvalueFromString)(fvalue_t*, char*, LogFunc); -typedef void (*FvalueToStringRepr)(fvalue_t*, ftrepr_t, char*); -typedef int (*FvalueStringReprLen)(fvalue_t*, ftrepr_t); - -typedef void (*FvalueSetFunc)(fvalue_t*, gpointer, gboolean); -typedef void (*FvalueSetUnsignedIntegerFunc)(fvalue_t*, guint32); -typedef void (*FvalueSetSignedIntegerFunc)(fvalue_t*, gint32); -typedef void (*FvalueSetInteger64Func)(fvalue_t*, guint64); -typedef void (*FvalueSetFloatingFunc)(fvalue_t*, gdouble); - -typedef gpointer (*FvalueGetFunc)(fvalue_t*); -typedef guint32 (*FvalueGetUnsignedIntegerFunc)(fvalue_t*); -typedef gint32 (*FvalueGetSignedIntegerFunc)(fvalue_t*); -typedef guint64 (*FvalueGetInteger64Func)(fvalue_t*); -typedef double (*FvalueGetFloatingFunc)(fvalue_t*); - -typedef gboolean (*FvalueCmp)(fvalue_t*, fvalue_t*); - -typedef guint (*FvalueLen)(fvalue_t*); -typedef void (*FvalueSlice)(fvalue_t*, GByteArray *, guint offset, guint length); - -struct _ftype_t { - ftenum_t ftype; - const char *name; - const char *pretty_name; - int wire_size; - FvalueNewFunc new_value; - FvalueFreeFunc free_value; - FvalueFromUnparsed val_from_unparsed; - FvalueFromString val_from_string; - FvalueToStringRepr val_to_string_repr; - FvalueStringReprLen len_string_repr; - - /* could be union */ - FvalueSetFunc set_value; - FvalueSetUnsignedIntegerFunc set_value_uinteger; - FvalueSetSignedIntegerFunc set_value_sinteger; - FvalueSetInteger64Func set_value_integer64; - FvalueSetFloatingFunc set_value_floating; - - /* could be union */ - FvalueGetFunc get_value; - FvalueGetUnsignedIntegerFunc get_value_uinteger; - FvalueGetSignedIntegerFunc get_value_sinteger; - FvalueGetInteger64Func get_value_integer64; - FvalueGetFloatingFunc get_value_floating; - - FvalueCmp cmp_eq; - FvalueCmp cmp_ne; - FvalueCmp cmp_gt; - FvalueCmp cmp_ge; - FvalueCmp cmp_lt; - FvalueCmp cmp_le; - FvalueCmp cmp_bitwise_and; - FvalueCmp cmp_contains; - FvalueCmp cmp_matches; - - FvalueLen len; - FvalueSlice slice; -}; - - -fvalue_t* -fvalue_new(ftenum_t ftype); - -void -fvalue_init(fvalue_t *fv, ftenum_t ftype); - - -/* Define type needed for the fvalue_t free list. */ -SLAB_ITEM_TYPE_DEFINE(fvalue_t) - -/* Free all memory used by an fvalue_t. With MSVC and a - * libwireshark.dll, we need a special declaration. - */ -WS_VAR_IMPORT SLAB_FREE_LIST_DECLARE(fvalue_t) - - -#define FVALUE_CLEANUP(fv) \ - { \ - register FvalueFreeFunc free_value; \ - free_value = (fv)->ftype->free_value; \ - if (free_value) { \ - free_value((fv)); \ - } \ - } - -#define FVALUE_FREE(fv) \ - { \ - FVALUE_CLEANUP(fv) \ - SLAB_FREE(fv, fvalue_t); \ - } - - -fvalue_t* -fvalue_from_unparsed(ftenum_t ftype, char *s, gboolean allow_partial_value, LogFunc logfunc); - -fvalue_t* -fvalue_from_string(ftenum_t ftype, char *s, LogFunc logfunc); - -/* Returns the length of the string required to hold the - * string representation of the the field value. - * The length DOES NOT include the terminating NUL. */ -int -fvalue_string_repr_len(fvalue_t *fv, ftrepr_t rtype); - -/* Creates the string representation of the field value. - * If given non-NULL 'buf', the string is written at the memory - * location pointed to by 'buf'. If 'buf' is NULL, new memory - * is malloc'ed and the string representation is written there. - * The pointer to the beginning of the string representation is - * returned. If 'buf' was NULL, this points to the newly-allocated - * memory. if 'buf' was non-NULL, then the return value will be - * 'buf'. */ -extern char * -fvalue_to_string_repr(fvalue_t *fv, ftrepr_t rtype, char *buf); - -ftype_t* -fvalue_ftype(fvalue_t *fv); - -const char* -fvalue_type_name(fvalue_t *fv); - -void -fvalue_set(fvalue_t *fv, gpointer value, gboolean already_copied); - -void -fvalue_set_uinteger(fvalue_t *fv, guint32 value); - -void -fvalue_set_sinteger(fvalue_t *fv, gint32 value); - -void -fvalue_set_integer64(fvalue_t *fv, guint64 value); - -void -fvalue_set_floating(fvalue_t *fv, gdouble value); - -gpointer -fvalue_get(fvalue_t *fv); - -extern guint32 -fvalue_get_uinteger(fvalue_t *fv); - -extern gint32 -fvalue_get_sinteger(fvalue_t *fv); - -guint64 -fvalue_get_integer64(fvalue_t *fv); - -extern double -fvalue_get_floating(fvalue_t *fv); - -gboolean -fvalue_eq(fvalue_t *a, fvalue_t *b); - -gboolean -fvalue_ne(fvalue_t *a, fvalue_t *b); - -gboolean -fvalue_gt(fvalue_t *a, fvalue_t *b); - -gboolean -fvalue_ge(fvalue_t *a, fvalue_t *b); - -gboolean -fvalue_lt(fvalue_t *a, fvalue_t *b); - -gboolean -fvalue_le(fvalue_t *a, fvalue_t *b); - -gboolean -fvalue_bitwise_and(fvalue_t *a, fvalue_t *b); - -gboolean -fvalue_contains(fvalue_t *a, fvalue_t *b); - -gboolean -fvalue_matches(fvalue_t *a, fvalue_t *b); - -guint -fvalue_length(fvalue_t *fv); - -fvalue_t* -fvalue_slice(fvalue_t *fv, drange *dr); - -#endif /* ftypes.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/funnel.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/funnel.h deleted file mode 100644 index a162e100..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/funnel.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * funnel.h - * - * EPAN's GUI mini-API - * - * (c) 2006, Luis E. Garcia Ontanon - * - * $Id: funnel.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#ifndef _FUNNEL_H -#define _FUNNEL_H - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include "../stat_menu.h" - -typedef struct _funnel_text_window_t funnel_text_window_t ; -typedef struct _funnel_tree_window_t funnel_tree_window_t ; -typedef struct _funnel_node_t funnel_node_t ; - -typedef void (*text_win_close_cb_t)(void*); - -typedef void (*funnel_dlg_cb_t)(gchar** user_input, void* data); - -typedef gboolean (*funnel_bt_cb_t)(funnel_text_window_t* tw, void* data); - -typedef struct _funnel_bt_t { - funnel_text_window_t* tw; - funnel_bt_cb_t func; - void* data; - void (*free)(void*); - void (*free_data)(void*); -} funnel_bt_t; - -typedef struct _funnel_ops_t { - funnel_text_window_t* (*new_text_window)(const gchar* label); - void (*set_text)(funnel_text_window_t* win, const gchar* text); - void (*append_text)(funnel_text_window_t* win, const gchar* text); - void (*prepend_text)(funnel_text_window_t* win, const gchar* text); - void (*clear_text)(funnel_text_window_t* win); - const gchar* (*get_text)(funnel_text_window_t* win); - void (*set_close_cb)(funnel_text_window_t* win, text_win_close_cb_t cb, void* data); - void (*set_editable)(funnel_text_window_t* win, gboolean editable); - void (*destroy_text_window)(funnel_text_window_t* win); - void (*add_button)(funnel_text_window_t* win, funnel_bt_t* cb, const gchar* label); - - - - void (*new_dialog)(const gchar* title, - const gchar** fieldnames, - funnel_dlg_cb_t dlg_cb, - void* data); - - - void (*logger)(const gchar *log_domain, - GLogLevelFlags log_level, - const gchar *message, - gpointer user_data); - - - void (*retap_packets)(void); - void (*copy_to_clipboard)(GString *str); - void (*set_filter)(const char*); - gboolean (*open_file)(const char* fname, const char* filter, const char** error); - void (*reload)(void); - void (*apply_filter)(void); - gboolean (*browser_open_url)(const gchar *url); - void (*browser_open_data_file)(const gchar *filename); -} funnel_ops_t; - - -extern const funnel_ops_t* funnel_get_funnel_ops(void); -extern void funnel_set_funnel_ops(const funnel_ops_t*); - - -extern void funnel_register_menu(const char *name, - register_stat_group_t group, - void (*callback)(gpointer), - gpointer callback_data, - gboolean retap); - - -typedef void (*funnel_registration_cb_t)(const char *name, - register_stat_group_t group, - void (*callback)(gpointer), - gpointer callback_data, - gboolean retap); - -extern void funnel_register_all_menus(funnel_registration_cb_t r_cb); - -extern void initialize_funnel_ops(void); - -extern void funnel_dump_all_text_windows(void); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/g_ascii_strcasecmp.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/g_ascii_strcasecmp.h deleted file mode 100644 index aef486b2..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/g_ascii_strcasecmp.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * $Id: g_ascii_strcasecmp.h 3992 2008-06-10 03:13:11Z dgu $ - * - * "g_ascii_strcasecmp()" and "g_ascii_strncasecmp()" extracted from - * GLib 2.4.8, for use with GLibs that don't have it (e.g., GLib 1.2[.x]). - */ - -#ifndef __WIRESHARK_G_ASCII_STRCASECMP_H__ -#define __WIRESHARK_G_ASCII_STRCASECMP_H__ - -extern gint g_ascii_strcasecmp (const gchar *s1, - const gchar *s2); - -extern gint g_ascii_strncasecmp (const gchar *s1, - const gchar *s2, - gsize n); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/g_ascii_strtoull.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/g_ascii_strtoull.h deleted file mode 100644 index d52d6d41..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/g_ascii_strtoull.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * $Id: g_ascii_strtoull.h 3992 2008-06-10 03:13:11Z dgu $ - * - * "g_ascii_strtoull()" extracted from GLib 2.4.5, for use with GLibs - * that don't have it (e.g., GLib 1.2[.x]). - */ - -#ifndef __WIRESHARK_G_ASCII_STRTOULL_H__ -#define __WIRESHARK_G_ASCII_STRTOULL_H__ - -extern guint64 g_ascii_strtoull (const gchar *nptr, - gchar **endptr, - guint base); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/garrayfix.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/garrayfix.h deleted file mode 100644 index 1d740562..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/garrayfix.h +++ /dev/null @@ -1,38 +0,0 @@ -/* garrayfix.h - * Macros to work around the "data" field of a GArray having type guint8 *, - * rather than void *, so that, even though the GArray code should be - * ensuring that the data is aligned strictly enough for any data type, - * we still get warnings with -Wcast-align. - * - * $Id: garrayfix.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2007 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __GARRAYFIX_H__ -#define __GARRAYFIX_H__ - -#ifdef g_array_index -#undef g_array_index -#define g_array_index(a,t,i) (((t*) (void*) (a)->data) [(i)]) -#endif - -#define g_array_data(a) ((void*) (a)->data) - -#endif /* __GARRAYFIX_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/gcp.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/gcp.h deleted file mode 100644 index 8dd8f728..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/gcp.h +++ /dev/null @@ -1,219 +0,0 @@ -/* gcp.h - * Gateway Control Protocol -- Context Tracking - * - * $Id: gcp.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#ifndef __GCP_H_ -#define __GCP_H_ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -#include - -typedef struct _gcp_hf_ett_t { - struct { - int ctx; - int ctx_cmd; - int ctx_term; - int ctx_term_type; - int ctx_term_bir; - int ctx_term_nsap; - } hf; - - struct { - gint ctx; - gint ctx_cmds; - gint ctx_terms; - gint ctx_term; - } ett; -} gcp_hf_ett_t; - -#define NULL_CONTEXT 0 -#define CHOOSE_CONTEXT 0xFFFFFFFE -#define ALL_CONTEXTS 0xFFFFFFFF - - -typedef enum { - GCP_CMD_NONE, - GCP_CMD_ADD_REQ, - GCP_CMD_MOVE_REQ, - GCP_CMD_MOD_REQ, - GCP_CMD_SUB_REQ, - GCP_CMD_AUDITCAP_REQ, - GCP_CMD_AUDITVAL_REQ, - GCP_CMD_NOTIFY_REQ, - GCP_CMD_SVCCHG_REQ, - GCP_CMD_TOPOLOGY_REQ, - GCP_CMD_CTX_ATTR_AUDIT_REQ, - GCP_CMD_OTHER_REQ, - GCP_CMD_ADD_REPLY, - GCP_CMD_MOVE_REPLY, - GCP_CMD_MOD_REPLY, - GCP_CMD_SUB_REPLY, - GCP_CMD_AUDITCAP_REPLY, - GCP_CMD_AUDITVAL_REPLY, - GCP_CMD_NOTIFY_REPLY, - GCP_CMD_SVCCHG_REPLY, - GCP_CMD_TOPOLOGY_REPLY, - GCP_CMD_REPLY -} gcp_cmd_type_t; - -typedef enum { - GCP_TRX_NONE, - GCP_TRX_REQUEST, - GCP_TRX_PENDING, - GCP_TRX_REPLY, - GCP_TRX_ACK -} gcp_trx_type_t; - - -typedef struct _gcp_msg_t { - guint32 lo_addr; - guint32 hi_addr; - guint32 framenum; - struct _gcp_trx_msg_t* trxs; - gboolean commited; -} gcp_msg_t; - -typedef struct _gcp_trx_msg_t { - struct _gcp_trx_t* trx; - struct _gcp_trx_msg_t* next; - struct _gcp_trx_msg_t* last; -} gcp_trx_msg_t; - -typedef struct _gcp_cmd_msg_t { - struct _gcp_cmd_t* cmd; - struct _gcp_cmd_msg_t* next; - struct _gcp_cmd_msg_t* last; -} gcp_cmd_msg_t; - -typedef struct _gcp_trx_t { - gcp_msg_t* initial; - guint32 id; - gcp_trx_type_t type; - guint pendings; - struct _gcp_cmd_msg_t* cmds; - struct _gcp_trx_ctx_t* ctxs; - guint error; -} gcp_trx_t; - -#define GCP_TERM_TYPE_UNKNOWN 0 -#define GCP_TERM_TYPE_AAL1 1 -#define GCP_TERM_TYPE_AAL2 2 -#define GCP_TERM_TYPE_AAL1_STRUCT 3 -#define GCP_TERM_TYPE_IP_RTP 4 -#define GCP_TERM_TYPE_TDM 5 - -typedef enum _gcp_wildcard_t { - GCP_WILDCARD_NONE, - GCP_WILDCARD_CHOOSE, - GCP_WILDCARD_ALL -} gcp_wildcard_t; - -typedef struct _gcp_term_t { - gchar* str; - - guint8* buffer; - guint len; - - guint type; - gchar* bir; - gchar* nsap; - - gcp_msg_t* start; - -} gcp_term_t; - -typedef struct _gcp_terms_t { - gcp_term_t* term; - struct _gcp_terms_t* next; - struct _gcp_terms_t* last; -} gcp_terms_t; - -typedef struct _gcp_cmd_t { - guint offset; - gchar* str; - gcp_cmd_type_t type; - gcp_terms_t terms; - struct _gcp_msg_t* msg; - struct _gcp_trx_t* trx; - struct _gcp_ctx_t* ctx; - guint error; -} gcp_cmd_t; - - -typedef struct _gcp_ctx_t { - gcp_msg_t* initial; - guint32 id; - struct _gcp_cmd_msg_t* cmds; - struct _gcp_ctx_t* prev; - gcp_terms_t terms; -} gcp_ctx_t; - -WS_VAR_IMPORT const value_string gcp_cmd_type[]; -WS_VAR_IMPORT const value_string gcp_term_types[]; - -extern void gcp_init(void); -extern gcp_msg_t* gcp_msg(packet_info* pinfo, int o, gboolean persistent); -extern gcp_trx_t* gcp_trx(gcp_msg_t* m ,guint32 t_id , gcp_trx_type_t type, gboolean persistent); -extern gcp_ctx_t* gcp_ctx(gcp_msg_t* m, gcp_trx_t* t, guint32 c_id, gboolean persistent); -extern gcp_cmd_t* gcp_cmd(gcp_msg_t* m, gcp_trx_t* t, gcp_ctx_t* c, gcp_cmd_type_t type, guint offset, gboolean persistent); -extern gcp_term_t* gcp_cmd_add_term(gcp_msg_t* m, gcp_trx_t* tr, gcp_cmd_t* c, gcp_term_t* t, gcp_wildcard_t wildcard, gboolean persistent); -extern void gcp_analyze_msg(proto_tree* gcp_tree, tvbuff_t* gcp_tvb, gcp_msg_t* m, gcp_hf_ett_t* ids); - -extern gchar* gcp_cmd_to_str(gcp_cmd_t* c, gboolean persistent); -extern gchar* gcp_msg_to_str(gcp_msg_t* m, gboolean persistent); - -#define gcp_cmd_set_error(c,e) (c->error = e) -#define gcp_trx_set_error(t,e) (t->error = e) - -#define GCP_ETT_ARR_ELEMS(gi) &(gi.ett.ctx),&(gi.ett.ctx_cmds),&(gi.ett.ctx_terms),&(gi.ett.ctx_term) - -#define GCP_HF_ARR_ELEMS(n,gi) \ - { &(gi.hf.ctx), { "Context", n ".ctx", FT_UINT32, BASE_HEX, NULL, 0, "", HFILL }}, \ - { &(gi.hf.ctx_term), { "Termination", n ".ctx.term", FT_STRING, BASE_NONE, NULL, 0, "", HFILL }}, \ - { &(gi.hf.ctx_term_type), { "Type", n ".ctx.term.type", FT_UINT32, BASE_HEX, VALS(gcp_term_types), 0, "", HFILL }}, \ - { &(gi.hf.ctx_term_bir), { "BIR", n ".ctx.term.bir", FT_STRING, BASE_HEX, NULL, 0, "", HFILL }}, \ - { &(gi.hf.ctx_term_nsap), { "NSAP", n ".ctx.term.nsap", FT_STRING, BASE_NONE, NULL, 0, "", HFILL }}, \ - { &(gi.hf.ctx_cmd), { "Command in Frame", n ".ctx.cmd", FT_FRAMENUM, BASE_DEC, NULL, 0, "", HFILL }} - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/gnuc_format_check.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/gnuc_format_check.h deleted file mode 100644 index a550dde7..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/gnuc_format_check.h +++ /dev/null @@ -1,39 +0,0 @@ -/* gnuc_format_check.h - * Definitions of macro to conditionally do GCC format checks - * - * $Id: gnuc_format_check.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __GNUC_FORMAT_CHECK_H__ -#define __GNUC_FORMAT_CHECK_H__ - -/** GNUC has the ability to check format strings that follow the syntax used in printf and others. - Hide the differences between different compilers in this GNUC_FORMAT_CHECK macro. - @param archetype one of: printf, scanf, strftime or strfmon - @param string_index specifies which argument is the format string argument (starting from 1) - @param first_to_check is the number of the first argument to check against the format string */ -#if __GNUC__ >= 2 - #define GNUC_FORMAT_CHECK(archetype, string_index, first_to_check) __attribute__((format (archetype, string_index, first_to_check))) -#else - #define GNUC_FORMAT_CHECK(archetype, string_index, first_to_check) -#endif - -#endif /* gnuc-format-check.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/golay.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/golay.h deleted file mode 100644 index ad3d454a..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/golay.h +++ /dev/null @@ -1,49 +0,0 @@ -/* $Id: golay.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Provides routines for encoding and decoding the extended Golay - * (24,12,8) code. - * - * This implementation will detect up to 4 errors in a codeword (without - * being able to correct them); it will correct up to 3 errors. - * - * We use guint32s to hold the 24-bit codewords, with the data part in - * the bottom 12 bits and the parity in bits 12-23. - * - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#ifndef __GOLAY_H__ -#define __GOLAY_H__ - -/* encodes a 12-bit word to a 24-bit codeword - */ -guint32 golay_encode(guint w); - -/* return a mask showing the bits which are in error in a received - * 24-bit codeword, or -1 if 4 errors were detected. - */ -gint32 golay_errors(guint32 codeword); - -/* decode a received codeword. Up to 3 errors are corrected for; 4 - errors are detected as uncorrectable (return -1); 5 or more errors - cause an incorrect correction. -*/ -gint golay_decode(guint32 w); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/greproto.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/greproto.h deleted file mode 100644 index de295dad..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/greproto.h +++ /dev/null @@ -1,36 +0,0 @@ -/* greproto.h - * Protocol type values for for the Generic Routing Encapsulation (GRE) - * protocol - * Brad Robel-Forrest - * - * The protocol type in GRE is supposed to be an Ethernet type value; - * this file lists protocol type values for which nobody's found an - * official Ethernet type definition and put that in "etypes.h". - * Move these to "etypes.h" if you find an official Ethernet type - * definition for them; when this file is empty, get rid of all includes - * of it, and get rid of it. - * - * $Id: greproto.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#define GRE_NHRP 0x2001 -#define GRE_WCCP 0x883E -#define GRE_ERSPAN 0x88BE diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/guid-utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/guid-utils.h deleted file mode 100644 index c2fc95d6..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/guid-utils.h +++ /dev/null @@ -1,63 +0,0 @@ -/* guid-utils.h - * Definitions for GUID handling - * - * $Id: guid-utils.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __GUID_UTILS_H__ -#define __GUID_UTILS_H__ - -#define GUID_LEN 16 - -/* Note: this might be larger than GUID_LEN, so don't overlay data in packets - with this. */ -typedef struct _e_guid_t { - guint32 data1; - guint16 data2; - guint16 data3; - guint8 data4[8]; -} e_guid_t; - - -extern void guids_init(void); - -/* add a GUID */ -extern void guids_add_guid(e_guid_t *guid, const gchar *name); - -/* try to get registered name for this GUID */ -extern const gchar *guids_get_guid_name(e_guid_t *guid); - -/* resolve GUID to name (or if unknown to hex string) */ -/* (if you need hex string only, use guid_to_str instead) */ -extern const gchar* guids_resolve_guid_to_str(e_guid_t *guid); - -/* add a UUID (dcerpc_init_uuid() will call this too) */ -#define guids_add_uuid(uuid, name) guids_add_guid((e_guid_t *) (uuid), (name)) - -/* try to get registered name for this UUID */ -#define guids_get_uuid_name(uuid) guids_get_guid_name((e_guid_t *) (uuid)) - -/* resolve UUID to name (or if unknown to hex string) */ -/* (if you need hex string only, use guid_to_str instead) */ -#define guids_resolve_uuid_to_str(uuid) guids_resolve_guid_to_str((e_guid_t *) (uuid)) - -#endif /* __GUID_UTILS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/h225-persistentdata.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/h225-persistentdata.h deleted file mode 100644 index 576330e5..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/h225-persistentdata.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * h225-persistentdata.h - * Definitions for lists and hash tables used in wireshark's h225 dissector - * for calculation of delays in h225-calls - * - * Copyright 2003 Lars Roland - * - * $Id: h225-persistentdata.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __h225_HASH__ -#define __h225_HASH__ - -#include -#include -#include - - -/* Item of ras request list*/ -typedef struct _h225ras_call_t { - guint32 requestSeqNum; - e_guid_t guid; - guint32 req_num; /* frame number request seen */ - guint32 rsp_num; /* frame number response seen */ - nstime_t req_time; /* arrival time of request */ - gboolean responded; /* true, if request has been responded */ - struct _h225ras_call_t *next_call; /* pointer to next ras request with same SequenceNumber and conversation handle */ -} h225ras_call_t; - - -/* Item of ras-request key list*/ -typedef struct _h225ras_call_info_key { - guint reqSeqNum; - conversation_t *conversation; -} h225ras_call_info_key; - -/* functions, needed using ras-request and halfcall matching*/ -h225ras_call_t * find_h225ras_call(h225ras_call_info_key *h225ras_call_key ,int category); -h225ras_call_t * new_h225ras_call(h225ras_call_info_key *h225ras_call_key, packet_info *pinfo, e_guid_t *guid, int category); -h225ras_call_t * append_h225ras_call(h225ras_call_t *prev_call, packet_info *pinfo, e_guid_t *guid, int category); - -void h225_init_routine(void); /* init routine, used by wireshark */ - -#endif /* __h225_HASH__*/ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/iax2_codec_type.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/iax2_codec_type.h deleted file mode 100644 index 7832eeec..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/iax2_codec_type.h +++ /dev/null @@ -1,77 +0,0 @@ -/* iax2_codec_type.h - * Defines IAX2 codec types - * - * $Id: iax2_codec_type.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __IAX2_CODEC_TYPE_H__ -#define __IAX2_CODEC_TYPE_H__ - - -/* Ref: frame.h from Asterisk source */ - -/* Data formats for capabilities and frames alike */ -/* suitable for use in iax2.codec dissector table */ -/*! G.723.1 compression */ -#define AST_FORMAT_G723_1 (1 << 0) -/*! GSM compression */ -#define AST_FORMAT_GSM (1 << 1) -/*! Raw mu-law data (G.711) */ -#define AST_FORMAT_ULAW (1 << 2) -/*! Raw A-law data (G.711) */ -#define AST_FORMAT_ALAW (1 << 3) -/*! ADPCM (G.726, 32kbps) */ -#define AST_FORMAT_G726 (1 << 4) -/*! ADPCM (IMA) */ -#define AST_FORMAT_ADPCM (1 << 5) -/*! Raw 16-bit Signed Linear (8000 Hz) PCM */ -#define AST_FORMAT_SLINEAR (1 << 6) -/*! LPC10, 180 samples/frame */ -#define AST_FORMAT_LPC10 (1 << 7) -/*! G.729A audio */ -#define AST_FORMAT_G729A (1 << 8) -/*! SpeeX Free Compression */ -#define AST_FORMAT_SPEEX (1 << 9) -/*! iLBC Free Compression */ -#define AST_FORMAT_ILBC (1 << 10) -/*! Maximum audio format */ -#define AST_FORMAT_MAX_AUDIO (1 << 15) -/*! JPEG Images */ -#define AST_FORMAT_JPEG (1 << 16) -/*! PNG Images */ -#define AST_FORMAT_PNG (1 << 17) -/*! H.261 Video */ -#define AST_FORMAT_H261 (1 << 18) -/*! H.263 Video */ -#define AST_FORMAT_H263 (1 << 19) -/*! Max one */ -#define AST_FORMAT_MAX_VIDEO (1 << 24) - - -/* data format for IAX_IE_DATAFORMAT ie */ -/* suitable for use in iax2.dataformat dissector table */ -typedef enum { - AST_DATAFORMAT_NULL, /* N/A: analogue call etc */ - AST_DATAFORMAT_V110, /* ITU-T V.110 rate adaption */ - AST_DATAFORMAT_H223_H245 /* ITU-T H.223/H.245 */ -} iax_dataformat_t; - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/in_cksum.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/in_cksum.h deleted file mode 100644 index 27c8273d..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/in_cksum.h +++ /dev/null @@ -1,14 +0,0 @@ -/* in_cksum.h - * Declaration of Internet checksum routine. - * - * $Id: in_cksum.h 3992 2008-06-10 03:13:11Z dgu $ - */ - -typedef struct { - const guint8 *ptr; - int len; -} vec_t; - -extern int in_cksum(const vec_t *vec, int veclen); - -extern guint16 in_cksum_shouldbe(guint16 sum, guint16 computed_sum); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/inet_aton.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/inet_aton.h deleted file mode 100644 index b7732a98..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/inet_aton.h +++ /dev/null @@ -1,34 +0,0 @@ -/* inet_aton.h - * - * $Id: inet_aton.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* - * Version of "inet_aton()", for the benefit of OSes that don't have it. - */ - -#ifndef __INET_ATON_H__ -#define __INET_ATON_H__ - -struct in_addr; -extern int inet_aton(const char* cp_arg, struct in_addr *addr); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ip_opts.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ip_opts.h deleted file mode 100644 index 4915c227..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ip_opts.h +++ /dev/null @@ -1,59 +0,0 @@ -/* ip_opts.h - * Definitions of structures and routines for dissection of options that - * work like IPv4 or IPv6 options - * - * $Id: ip_opts.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __IP_OPTS_H__ -#define __IP_OPTS_H__ - -typedef enum { - NO_LENGTH, /* option has no data, hence no length */ - FIXED_LENGTH, /* option always has the same length */ - VARIABLE_LENGTH /* option is variable-length - optlen is minimum */ -} opt_len_type; - -/* Member of table of IP or TCP options. */ -typedef struct ip_tcp_opt { - int optcode; /* code for option */ - const char *name; /* name of option */ - int *subtree_index; /* pointer to subtree index for option */ - opt_len_type len_type; /* type of option length field */ - int optlen; /* value length should be (minimum if VARIABLE) */ - void (*dissect)(const struct ip_tcp_opt *, tvbuff_t *, int, guint, - packet_info *, proto_tree *); - /* routine to dissect option */ -} ip_tcp_opt; - -/* Routine to dissect options that work like IPv4 options, where the - length field in the option, if present, includes the type and - length bytes. */ -extern void dissect_ip_tcp_options(tvbuff_t *, int, guint, - const ip_tcp_opt *, int, int, packet_info *, proto_tree *); - -/* Routine to dissect options that work like IPv6 options, where the - length field in the option, if present, includes only the data, not - the type and length bytes. */ -extern void dissect_ipv6_options(tvbuff_t *, int, guint, - const ip_tcp_opt *, int, int, packet_info *, proto_tree *); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipproto.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipproto.h deleted file mode 100644 index a6861cd7..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipproto.h +++ /dev/null @@ -1,193 +0,0 @@ -/* ipproto.h - * Declarations of IP protocol numbers, and of routines for converting - * IP protocol numbers into strings. - * - * $Id: ipproto.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __IPPROTO_H__ -#define __IPPROTO_H__ - -/* - * IP protocol numbers. - */ -#define IP_PROTO_IP 0 /* dummy for IP */ -#define IP_PROTO_HOPOPTS 0 /* IP6 hop-by-hop options - RFC1883 */ -#define IP_PROTO_ICMP 1 /* control message protocol - RFC792 */ -#define IP_PROTO_IGMP 2 /* group mgmt protocol - RFC1112 */ -#define IP_PROTO_GGP 3 /* gateway^2 (deprecated) - RFC823*/ -#define IP_PROTO_IPIP 4 /* IP inside IP - RFC2003*/ -#define IP_PROTO_IPV4 4 /* IP header */ -#define IP_PROTO_STREAM 5 /* Stream - RFC1190, RFC1819 */ -#define IP_PROTO_TCP 6 /* TCP - RFC792 */ -#define IP_PROTO_CBT 7 /* CBT - */ -#define IP_PROTO_EGP 8 /* exterior gateway protocol - RFC888 */ -#define IP_PROTO_IGP 9 /* any private interior gateway protocol ... */ -#define IP_PROTO_IGRP 9 /* ... and used by Cisco for IGRP */ -#define IP_PROTO_BBN_RCC 10 /* BBN RCC Monitoring */ -#define IP_PROTO_NVPII 11 /* Network Voice Protocol - RFC741 */ -#define IP_PROTO_PUP 12 /* pup */ -#define IP_PROTO_ARGUS 13 /* ARGUS */ -#define IP_PROTO_EMCON 14 /* EMCON */ -#define IP_PROTO_XNET 15 /* Cross net debugger - IEN158 */ -#define IP_PROTO_CHAOS 16 /* CHAOS */ -#define IP_PROTO_UDP 17 /* user datagram protocol - RFC768 */ -#define IP_PROTO_MUX 18 /* multiplexing - IEN90 */ -#define IP_PROTO_DCNMEAS 19 /* DCN Measurement Subsystems */ -#define IP_PROTO_HMP 20 /* Host Monitoring - RFC869 */ -#define IP_PROTO_PRM 21 /* Packet radio measurement */ -#define IP_PROTO_IDP 22 /* xns idp */ -#define IP_PROTO_TRUNK1 23 -#define IP_PROTO_TRUNK2 24 -#define IP_PROTO_LEAF1 25 -#define IP_PROTO_LEAF2 26 -#define IP_PROTO_RDP 27 /* Reliable Data Protocol - RFC908 */ -#define IP_PROTO_IRT 28 /* Internet Reliable Transation - RFC938 */ -#define IP_PROTO_TP 29 /* tp-4 w/ class negotiation - RFC905 */ -#define IP_PROTO_BULK 30 /* Bulk Data Transfer Protocol - RFC969 */ -#define IP_PROTO_MFE_NSP 31 /* MFE Network Services Protocol */ -#define IP_PROTO_MERIT 32 /* MERIT Internodal Protocol */ -/* #define IP_PROTO_SEP 33 Sequential Exchange Protocol */ -#define IP_PROTO_DCCP 33 /* Datagram Congestion Control Protocol */ -#define IP_PROTO_3PC 34 /* Third party connect protocol */ -#define IP_PROTO_IDPR 35 /* Interdomain policy routing protocol */ -#define IP_PROTO_XTP 36 /* XTP */ -#define IP_PROTO_DDP 37 /* Datagram Delivery Protocol */ -#define IP_PROTO_CMTP 38 /* Control Message Transport Protocol */ -#define IP_PROTO_TPPP 39 /* TP++ Transport Protocol */ -#define IP_PROTO_IL 40 /* IL Transport Protocol */ -#define IP_PROTO_IPV6 41 /* IP6 header */ -#define IP_PROTO_SDRP 42 /* Source demand routing protocol */ -#define IP_PROTO_ROUTING 43 /* IP6 routing header */ -#define IP_PROTO_FRAGMENT 44 /* IP6 fragmentation header */ -#define IP_PROTO_IDRP 45 /* Inter-Domain Routing Protocol */ -#define IP_PROTO_RSVP 46 /* Resource ReSerVation protocol */ -#define IP_PROTO_GRE 47 /* General Routing Encapsulation */ -#define IP_PROTO_MHRP 48 /* Mobile Host Routing Protocol */ -#define IP_PROTO_BNA 49 /* BNA */ -#define IP_PROTO_ESP 50 /* Encap Security Payload for IPv6 - RFC2406 */ -#define IP_PROTO_AH 51 /* Authentication Header for IPv6 - RFC2402*/ -#define IP_PROTO_INSLP 52 /* Integrated Net Layer Security */ -#define IP_PROTO_SWIPE 53 /* IP with Encryption */ -#define IP_PROTO_NARP 54 /* NBMA Address resolution protocol - RFC1735 */ -#define IP_PROTO_MOBILE 55 /* IP Mobility */ -#define IP_PROTO_TLSP 56 /* Transport Layer Security Protocol using */ - /* Kryptonet key management */ -#define IP_PROTO_SKIP 57 /* SKIP */ -#define IP_PROTO_ICMPV6 58 /* ICMP6 - RFC1883*/ -#define IP_PROTO_NONE 59 /* IP6 no next header - RFC1883 */ -#define IP_PROTO_DSTOPTS 60 /* IP6 destination options - RFC1883 */ -/* 61 is reserved by IANA for any host internal protocol */ -/* 61 is used by UCL's SHIM6 implementation as Next Header for SHIM6 */ -#define IP_PROTO_SHIM6 61 /* SHIM6 */ - -/* - * The current Protocol Numbers list says that the IP protocol number for - * mobility headers is 135; it cites draft-ietf-mobileip-ipv6-24, but - * that draft doesn't actually give a number. - * - * It appears that 62 used to be used, even though that's assigned to - * a protocol called CFTP; however, the only reference for CFTP is a - * Network Message from BBN back in 1982, so, for now, we support 62, - * as well as 135, as a protocol number for mobility headers. - */ -#define IP_PROTO_MIPV6_OLD 62 /* Mobile IPv6 */ -/* 63 is reserved by IANA for any local network */ -#define IP_PROTO_SATEXPAK 64 -#define IP_PROTO_KRYPTOLAN 65 -#define IP_PROTO_RVD 66 /* MIT Remote virtual disk protocol */ -#define IP_PROTO_IPPC 67 /* Internet Pluribus Packet Core */ -/* 68 is reserved by IANA for any distributed file system */ -#define IP_PROTO_SATMON 69 /* SATNET Monitoring */ -#define IP_PROTO_VISA 70 /* VISA Protocol */ -#define IP_PROTO_IPCV 71 /* Internet Packet Core Utility */ -#define IP_PROTO_CPNX 72 /* Computer Protocol Network Executive */ -#define IP_PROTO_CPHB 73 /* Computer Protocol Heart Beat */ -#define IP_PROTO_WSN 74 /* WANG Span Network */ -#define IP_PROTO_PVP 75 /* Packet Video Protocol */ -#define IP_PROTO_BRSATMON 76 /* Backroon SATNET Monitoring */ -#define IP_PROTO_SUNND 77 /* SUN ND Protocol - Temporary */ -#define IP_PROTO_WBMON 78 /* Wideband Monitoring */ -#define IP_PROTO_WBEXPAK 79 /* Wideband EXPAK */ -#define IP_PROTO_EON 80 /* ISO cnlp */ -#define IP_PROTO_VMTP 81 -#define IP_PROTO_SVMTP 82 /* Secure VMTP */ -#define IP_PROTO_VINES 83 /* Vines over raw IP */ -#define IP_PROTO_TTP 84 -#define IP_PROTO_NSFNETIGP 85 /* NSFNET IGP */ -#define IP_PROTO_DGP 86 /* Dissimilar Gateway Protocol */ -#define IP_PROTO_TCF 87 -#define IP_PROTO_EIGRP 88 -#define IP_PROTO_OSPF 89 /* OSPF Interior Gateway Protocol - RFC1583 */ -#define IP_PROTO_SPRITE 90 /* SPRITE RPC protocol */ -#define IP_PROTO_LARP 91 /* Locus Address Resolution Protocol */ -#define IP_PROTO_MTP 92 /* Multicast Transport Protocol */ -#define IP_PROTO_AX25 93 /* AX.25 frames */ -#define IP_PROTO_IPINIP 94 /* IP within IP Encapsulation protocol */ -#define IP_PROTO_MICP 95 /* Mobile Internetworking Control Protocol */ -#define IP_PROTO_SCCCP 96 /* Semaphore communications security protocol */ -#define IP_PROTO_ETHERIP 97 /* Ethernet-within-IP - RFC 3378 */ -#define IP_PROTO_ENCAP 98 /* encapsulation header - RFC1241*/ -/* 99 is reserved by IANA for any private encryption scheme */ -#define IP_PROTO_GMTP 100 -#define IP_PROTO_IFMP 101 /* Ipsilon flow management protocol */ -#define IP_PROTO_PNNI 102 /* PNNI over IP */ -#define IP_PROTO_PIM 103 /* Protocol Independent Mcast */ -#define IP_PROTO_ARIS 104 -#define IP_PROTO_SCPS 105 -#define IP_PROTO_QNX 106 -#define IP_PROTO_AN 107 /* Active Networks */ -#define IP_PROTO_IPCOMP 108 /* IP payload compression - RFC2393 */ -#define IP_PROTO_SNP 109 /* Sitara Networks Protocol */ -#define IP_PROTO_COMPAQ 110 /* Compaq Peer Protocol */ -#define IP_PROTO_IPX 111 /* IPX over IP */ -#define IP_PROTO_VRRP 112 /* Virtual Router Redundancy Protocol */ -#define IP_PROTO_PGM 113 /* Pragmatic General Multicast */ -/* 114 is reserved by IANA for any zero hop protocol */ -#define IP_PROTO_L2TP 115 /* Layer Two Tunnelling Protocol */ -#define IP_PROTO_DDX 116 /* D-II Data Exchange */ -#define IP_PROTO_IATP 117 /* Interactive Agent Transfer Protocol */ -#define IP_PROTO_STP 118 /* Schedule Transfer Protocol */ -#define IP_PROTO_SRP 119 /* Spectralink Radio Protocol */ -#define IP_PROTO_UTI 120 -#define IP_PROTO_SMP 121 /* Simple Message Protocol */ -#define IP_PROTO_SM 122 -#define IP_PROTO_PTP 123 /* Performance Transparency Protocol */ -#define IP_PROTO_ISIS 124 /* ISIS over IPv4 */ -#define IP_PROTO_FIRE 125 -#define IP_PROTO_CRTP 126 /* Combat Radio Transport Protocol */ -#define IP_PROTO_CRUDP 127 /* Combat Radio User Datagram */ -#define IP_PROTO_SSCOPMCE 128 -#define IP_PROTO_IPLT 129 -#define IP_PROTO_SPS 130 /* Secure Packet Shield */ -#define IP_PROTO_PIPE 131 /* Private IP Encapsulation within IP */ -#define IP_PROTO_SCTP 132 /* Stream Control Transmission Protocol */ -#define IP_PROTO_FC 133 /* Fibre Channel */ -#define IP_PROTO_RSVPE2EI 134 /* RSVP E2E Ignore - RFC3175 */ -#define IP_PROTO_MIPV6 135 /* Mobile IPv6 */ -#define IP_PROTO_UDPLITE 136 /* Lightweight user datagram protocol - RFC3828 */ -#define IP_PROTO_MPLS_IN_IP 137 /* MPLS in IP - RFC4023 */ -#define IP_PROTO_AX4000 173 /* AX/4000 Testblock - non IANA */ -#define IP_PROTO_NCS_HEARTBEAT 224 /* Novell NCS Heartbeat - http://support.novell.com/cgi-bin/search/searchtid.cgi?/10071158.htm */ - -extern const char *ipprotostr(int proto); - -#endif /* ipproto.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipv4.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipv4.h deleted file mode 100644 index c1cbbbde..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipv4.h +++ /dev/null @@ -1,67 +0,0 @@ -/* ipv4.h - * - * IPv4 address class. They understand how to take netmasks into consideration - * during equivalence testing. - * - * Gilbert Ramirez - * - * $Id: ipv4.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __IPV4_H__ -#define __IPV4_H__ - -#include - -typedef struct { - guint32 addr; /* stored in host order */ - guint32 nmask; /* stored in host order */ -} ipv4_addr; - -/* Allocate a new ipv4_addr struct, initialize it, and return pointer */ -ipv4_addr* ipv4_addr_new(void); - -/* Frees an ipv4 struct */ -void ipv4_addr_free(ipv4_addr *ipv4); - -void ipv4_addr_set_host_order_addr(ipv4_addr *ipv4, guint32 new_addr); -void ipv4_addr_set_net_order_addr(ipv4_addr *ipv4, guint32 new_addr); -void ipv4_addr_set_netmask_bits(ipv4_addr *ipv4, guint new_nmask_bits); - -guint32 ipv4_get_net_order_addr(ipv4_addr *ipv4); -guint32 ipv4_get_host_order_addr(ipv4_addr *ipv4); - -/* Fills in a buffer with a dotted-decimal notation representation of an IPv4 - * address. */ -void ipv4_addr_str_buf(const ipv4_addr *ipv4, gchar *buf); - -/* Compares two ipv4_addrs, taking into account the less restrictive of the - * two netmasks, applying that netmask to both addrs. - */ -gboolean ipv4_addr_eq(ipv4_addr *a, ipv4_addr *b); -gboolean ipv4_addr_gt(ipv4_addr *a, ipv4_addr *b); -gboolean ipv4_addr_ge(ipv4_addr *a, ipv4_addr *b); -gboolean ipv4_addr_lt(ipv4_addr *a, ipv4_addr *b); -gboolean ipv4_addr_le(ipv4_addr *a, ipv4_addr *b); - -#define ipv4_addr_ne(a,b) !ipv4_addr_eq((a),(b)) - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipv6-utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipv6-utils.h deleted file mode 100644 index a743f806..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipv6-utils.h +++ /dev/null @@ -1,49 +0,0 @@ -/* ipv6-utils.h - * Definitions for IPv6 packet disassembly - * - * $Id: ipv6-utils.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * - * Copyright 1998 Gerald Combs - * - * MobileIPv6 support added by Tomislav Borosa - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __IPV6_UTILS_H__ -#define __IPV6_UTILS_H__ - -struct e_in6_addr { - guint8 bytes[16]; /* 128 bit IP6 address */ -}; - -/* - * Unicast Scope - * Note that we must check topmost 10 bits only, not 16 bits (see RFC2373). - */ -#define E_IN6_IS_ADDR_LINKLOCAL(a) \ - (((a)->bytes[0] == 0xfe) && (((a)->bytes[1] & 0xc0) == 0x80)) -#define E_IN6_IS_ADDR_SITELOCAL(a) \ - (((a)->bytes[0] == 0xfe) && (((a)->bytes[1] & 0xc0) == 0xc0)) - -/* - * Multicast - */ -#define E_IN6_IS_ADDR_MULTICAST(a) ((a)->bytes[0] == 0xff) - -#endif /* __IPV6_UTILS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/lapd_sapi.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/lapd_sapi.h deleted file mode 100644 index 5750f796..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/lapd_sapi.h +++ /dev/null @@ -1,38 +0,0 @@ -/* lapd_sapi.h - * Declarations of LAPD SAPI values. - * - * $Id: lapd_sapi.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2004 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __LAPD_SAPI_H__ -#define __LAPD_SAPI_H__ - -#define LAPD_SAPI_Q931 0 /* Q.931 call control procedure */ -#define LAPD_SAPI_PM_Q931 1 /* Packet mode Q.931 call control procedure */ -#define LAPD_SAPI_X25 16 /* X.25 Level 3 procedures */ -#define LAPD_SAPI_L2 63 /* Layer 2 management procedures */ - -#define LAPD_GSM_SAPI_RA_SIG_PROC 0 -#define LAPD_GSM_SAPI_NOT_USED_1 1 -#define LAPD_GSM_SAPI_NOT_USED_16 16 -#define LAPD_GSM_SAPI_OM_PROC 62 - -#endif /* lapd_sapi.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/llcsaps.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/llcsaps.h deleted file mode 100644 index ddafad20..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/llcsaps.h +++ /dev/null @@ -1,63 +0,0 @@ -/* llcsaps.h - * Defines LLC SAP values. - * - * $Id: llcsaps.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __LLCSAPS_H__ -#define __LLCSAPS_H__ - -#define SAP_NULL 0x00 -#define SAP_LLC_SLMGMT 0x02 -#define SAP_SNA_PATHCTRL 0x04 -#define SAP_IP 0x06 -#define SAP_SNA1 0x08 -#define SAP_SNA2 0x0C -#define SAP_PROWAY_NM_INIT 0x0E -#define SAP_NETWARE1 0x10 -#define SAP_OSINL1 0x14 -#define SAP_TI 0x18 -#define SAP_OSINL2 0x20 -#define SAP_OSINL3 0x34 -#define SAP_SNA3 0x40 -#define SAP_BPDU 0x42 -#define SAP_RS511 0x4E -#define SAP_OSINL4 0x54 -#define SAP_X25 0x7E -#define SAP_XNS 0x80 -#define SAP_BACNET 0x82 -#define SAP_NESTAR 0x86 -#define SAP_PROWAY_ASLM 0x8E -#define SAP_ARP 0x98 -#define SAP_SNAP 0xAA -#define SAP_HPJD 0xB4 -#define SAP_VINES1 0xBA -#define SAP_VINES2 0xBC -#define SAP_NETWARE2 0xE0 -#define SAP_NETBIOS 0xF0 -#define SAP_IBMNM 0xF4 -#define SAP_HPEXT 0xF8 -#define SAP_UB 0xFA -#define SAP_RPL 0xFC -#define SAP_OSINL5 0xFE -#define SAP_GLOBAL 0xFF - -#endif /* llcsaps.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/next_tvb.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/next_tvb.h deleted file mode 100644 index 583c9a41..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/next_tvb.h +++ /dev/null @@ -1,65 +0,0 @@ -/* next_tvb.h - * Definitions for "next tvb" list - * - * $Id: next_tvb.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -/* The buffers returned by these functions are all allocated with a - * packet lifetime or are static buffers and does not have have to be freed. - * However, take into account that when the packet dissection - * completes, these buffers will be automatically reclaimed/freed. - * If you need the buffer to remain for a longer scope than packet lifetime - * you must copy the content to an se_alloc() buffer. - */ - -#ifndef __NEXT_TVB_H__ -#define __NEXT_TVB_H__ - -typedef enum { - NTVB_HANDLE, - NTVB_PORT, - NTVB_STRING -} next_tvb_call_e; - -typedef struct next_tvb_item { - struct next_tvb_item *next; - struct next_tvb_item *previous; - next_tvb_call_e type; - dissector_handle_t handle; - dissector_table_t table; - guint32 port; - const gchar *string; - tvbuff_t *tvb; - proto_tree *tree; -} next_tvb_item_t; - -typedef struct { - next_tvb_item_t *first; - next_tvb_item_t *last; - int count; -} next_tvb_list_t; - -extern void next_tvb_init(next_tvb_list_t *list); -extern void next_tvb_add_handle(next_tvb_list_t *list, tvbuff_t *tvb, proto_tree *tree, dissector_handle_t handle); -extern void next_tvb_add_port(next_tvb_list_t *list, tvbuff_t *tvb, proto_tree *tree, dissector_table_t table, guint32 port); -extern void next_tvb_add_string(next_tvb_list_t *list, tvbuff_t *tvb, proto_tree *tree, dissector_table_t table, const gchar *string); -extern void next_tvb_call(next_tvb_list_t *list, packet_info *pinfo, proto_tree *tree, dissector_handle_t handle, dissector_handle_t data_handle); - -#endif /* __NEXT_TVB_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/nlpid.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/nlpid.h deleted file mode 100644 index c4c7ce40..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/nlpid.h +++ /dev/null @@ -1,60 +0,0 @@ -/* nlpid.h - * Definitions of OSI NLPIDs (Network Layer Protocol IDs) - * Laurent Deniel - * - * $Id: nlpid.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __NLPID_H__ -#define __NLPID_H__ - -/* X.263 / ISO/IEC TR 9577 NLPID values. */ - -#define NLPID_NULL 0x00 -#define NLPID_IPI_T_70 0x01 /* T.70, when an IPI */ -#define NLPID_SPI_X_29 0x01 /* X.29, when an SPI */ -#define NLPID_X_633 0x03 /* X.633 */ -#define NLPID_Q_931 0x08 /* Q.931, Q.932, X.36, ISO 11572, ISO 11582 */ -#define NLPID_Q_933 0x08 /* Q.933, on Frame Relay */ -#define NLPID_Q_2931 0x09 /* Q.2931 */ -#define NLPID_Q_2119 0x0c /* Q.2119 */ -#define NLPID_SNAP 0x80 -#define NLPID_ISO8473_CLNP 0x81 /* X.233 */ -#define NLPID_ISO9542_ESIS 0x82 -#define NLPID_ISO10589_ISIS 0x83 -#define NLPID_ISO10747_IDRP 0x85 -#define NLPID_ISO9542X25_ESIS 0x8a -#define NLPID_ISO10030 0x8c -#define NLPID_ISO11577 0x8d /* X.273 */ -#define NLPID_IP6 0x8e -#define NLPID_COMPRESSED 0xb0 /* "Data compression protocol" */ -#define NLPID_SNDCF 0xc1 /* "SubNetwork Dependent Convergence Function */ -#define NLPID_IP 0xcc -#define NLPID_PPP 0xcf - -extern const value_string nlpid_vals[]; - -/* - * 0x09 is, in Frame Relay, LMI, Q.2931. - */ -#define NLPID_LMI 0x09 /* LMI */ - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/nstime.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/nstime.h deleted file mode 100644 index c92375df..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/nstime.h +++ /dev/null @@ -1,92 +0,0 @@ -/* nstime.h - * Definition of data structure to hold time values with nanosecond resolution - * - * $Id: nstime.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __NSTIME_H__ -#define __NSTIME_H__ - -#include - -#include - -typedef struct { - time_t secs; - int nsecs; -} nstime_t; - -/* functions */ - -/* set the given nstime_t to zero */ -extern void nstime_set_zero(nstime_t *nstime); - -/* is the given nstime_t currently zero? */ -extern gboolean nstime_is_zero(nstime_t *nstime); - -/* set the given nstime_t to (0,maxint) to mark it as "unset" - * That way we can find the first frame even when a timestamp - * is zero (fix for bug 1056) - */ -extern void nstime_set_unset(nstime_t *nstime); - -/* is the given nstime_t currently (0,maxint)? */ -extern gboolean nstime_is_unset(nstime_t *nstime); - -/* calculate the delta between two times (can be negative!) - * - * delta = b-a - * - * Note that it is acceptable for two or more of the arguments to point at the - * same structure. - */ -extern void nstime_delta(nstime_t *delta, const nstime_t *b, const nstime_t *a ); - -/* calculate the sum of two times - * - * sum = a+b - * - * Note that it is acceptable for two or more of the arguments to point at the - * same structure. - */ -extern void nstime_sum(nstime_t *sum, const nstime_t *b, const nstime_t *a ); - -/* sum += a */ -#define nstime_add(sum, a) nstime_sum(sum, sum, a) - -/* compare two times are return a value similar to memcmp() or strcmp(). - * - * a > b : > 0 - * a = b : 0 - * a < b : < 0 - */ -extern int nstime_cmp(nstime_t *a, const nstime_t *b ); - -/* converts nstime to double, time base is milli seconds */ -extern double nstime_to_msec(const nstime_t *time); - -/* converts nstime to double, time base is seconds */ -extern double nstime_to_sec(const nstime_t *time); - -/* converts wtap_nstime to double, time base is seconds */ -extern double wtap_nstime_to_sec(const struct wtap_nstime *time); - -#endif /* __NSTIME_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/oids.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/oids.h deleted file mode 100644 index 50a4ea83..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/oids.h +++ /dev/null @@ -1,179 +0,0 @@ -/* oids.h - * Object IDentifier Support - * - * $Id: oids.h 3992 2008-06-10 03:13:11Z dgu $ - * - * (c) 2007, Luis E. Garcia Ontanon - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __OIDS_H__ -#define __OIDS_H__ - -#define BER_TAG_ANY -1 - -struct _oid_bit_t { - guint offset; - int hfid; -}; - -typedef struct _oid_bits_info_t { - guint num; - gint ett; - struct _oid_bit_t* data; -} oid_bits_info_t; - -typedef enum _oid_key_type_t { - OID_KEY_TYPE_WRONG, - OID_KEY_TYPE_INTEGER, - OID_KEY_TYPE_OID, - OID_KEY_TYPE_STRING, - OID_KEY_TYPE_BYTES, - OID_KEY_TYPE_NSAP, - OID_KEY_TYPE_IPADDR, - OID_KEY_TYPE_IMPLIED_OID, - OID_KEY_TYPE_IMPLIED_STRING, - OID_KEY_TYPE_IMPLIED_BYTES -} oid_key_type_t; - -typedef struct _oid_value_type_t { - enum ftenum ft_type; - int display; - gint8 ber_class; - gint32 ber_tag; - int min_len; - int max_len; - oid_key_type_t keytype; - int keysize; -} oid_value_type_t; - -typedef enum _oid_kind_t { - OID_KIND_UNKNOWN = 0, - OID_KIND_NODE, - OID_KIND_SCALAR, - OID_KIND_TABLE, - OID_KIND_ROW, - OID_KIND_COLUMN, - OID_KIND_NOTIFICATION, - OID_KIND_GROUP, - OID_KIND_COMPLIANCE, - OID_KIND_CAPABILITIES -} oid_kind_t; - -typedef struct _oid_key_t { - char* name; - guint32 num_subids; - oid_key_type_t key_type; - int hfid; - enum ftenum ft_type; - int display; - struct _oid_key_t* next; -} oid_key_t; - -typedef struct _oid_info_t { - guint32 subid; - char* name; - oid_kind_t kind; - void* children; /* an emem_tree_t* */ - const oid_value_type_t* value_type; - int value_hfid; - oid_key_t* key; - oid_bits_info_t* bits; - struct _oid_info_t* parent; -} oid_info_t; - -/* init funcion called from epan.h */ -extern void oids_init(void); - -/* - * The objects returned by all these functions are all allocated with a - * packet lifetime and does not have have to be freed. - * However, take into account that when the packet dissection - * completes, these buffers will be automatically reclaimed/freed. - * If you need the buffer to remain for a longer scope than packet lifetime - * you must copy the content to an se_alloc() buffer. - */ - -/* - * These functions convert through the various formats: - * string: is like "0.1.3.4.5.30" (not resolved) - * encoded: is BER encoded (as per X.690 section 8.19) - * subids: is an array of guint32s - */ - -/* return length of encoded buffer */ -guint oid_subid2encoded(guint len, guint32* subids, guint8** encoded_p); -guint oid_string2encoded(const gchar *oid_str, guint8** encoded_p); - -/* return length of subid array */ -guint oid_encoded2subid(const guint8 *oid, gint len, guint32** subids_p); -guint oid_string2subid(const gchar *oid_str, guint32** subids_p); - -extern const gchar* oid_encoded2string(const guint8* encoded, guint len); -extern const gchar* oid_subid2string(guint32 *subids, guint len); - -/* these return a formated string as human readable as posible */ -extern const gchar *oid_resolved(guint len, guint32 *subids); -extern const gchar *oid_resolved_from_encoded(const guint8 *oid, gint len); -extern const gchar *oid_resolved_from_string(const gchar *oid_str); - -/* these yield two formated strings one resolved and one numeric */ -extern void oid_both(guint oid_len, guint32 *subids, char** resolved_p, char** numeric_p); -extern void oid_both_from_encoded(const guint8 *oid, gint oid_len, char** resolved_p, char** numeric_p); -extern void oid_both_from_string(const gchar *oid_str, char** resolved_p, char** numeric_p); - -/* - * These return the info for the best match. - * *matched_p will be set to the number of nodes used by the returned oid - * *left_p will be set to the number of remaining unresolved subids - */ -extern oid_info_t* oid_get(guint oid_len, guint32 *subids, guint* matched_p, guint* left_p); -extern oid_info_t* oid_get_from_encoded(const guint8 *oid, gint oid_len, guint32 **subids, guint* matched, guint* left); -extern oid_info_t* oid_get_from_string(const gchar *oid_str, guint32 **subids, guint* matched, guint* left); - -/* these are used to add oids to the collection */ -extern void oid_add(const char* name, guint oid_len, guint32 *subids); -extern void oid_add_from_encoded(const char* name, const guint8 *oid, gint oid_len); -extern void oid_add_from_string(const char* name, const gchar *oid_str); - -/** - * Fetch the default MIB/PIB path - * - * @return A string containing the default MIB/PIB path. It must be - * g_free()d by the caller. - */ -extern gchar *oid_get_default_mib_path(void); - -extern void oid_add_from_string(const char* name, const gchar *oid_str); - -/* macros for legacy oid functions */ -#define oid_resolv_cleanup() ((void)0) -#define subid_t guint32 - - - -#ifdef DEBUG_OIDS -extern char* oid_test_a2b(guint32 num_subids, guint32* subids); -extern void add_oid_debug_subtree(oid_info_t* oid_info, proto_tree *tree); -#else -#define add_oid_debug_subtree(a,b) ((void)0) -#endif - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/osi-utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/osi-utils.h deleted file mode 100644 index 97b6b27a..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/osi-utils.h +++ /dev/null @@ -1,57 +0,0 @@ -/* osi-utils.h - * - * $Id: osi-utils.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __OSI_UTILS_H__ -#define __OSI_UTILS_H__ - -/* OSI Global defines, common for all OSI protocols */ - -#define MAX_NSAP_LEN 30 -#define MAX_SYSTEMID_LEN 15 -#define MAX_AREA_LEN 30 - -#define RFC1237_NSAP_LEN 20 -#define RFC1237_FULLAREA_LEN 13 -#define RFC1237_SYSTEMID_LEN 6 -#define RFC1237_SELECTOR_LEN 1 - -#define RFC1237_IDI_LEN 2 -#define RFC1237_AFI_LEN 1 -#define RFC1237_DFI_LEN 1 -#define RFC1237_ORG_LEN 3 -#define RFC1237_AA_LEN 3 -#define RFC1237_RSVD_LEN 2 -#define RFC1237_RD_LEN 2 -#define RFC1237_AREA_LEN 3 - -#define NSAP_IDI_ISODCC 0x39 -#define NSAP_IDI_GOSIP2 0x47 - -gchar* print_nsap_net ( const guint8 *, int ); -void print_nsap_net_buf( const guint8 *, int, gchar *, int); -gchar* print_area ( const guint8 *, int ); -void print_area_buf ( const guint8 *, int, gchar *, int); -gchar* print_system_id( const guint8 *, int ); -void print_system_id_buf( const guint8 *, int, gchar *, int); - -#endif /* __OSI_UTILS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/oui.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/oui.h deleted file mode 100644 index 1431d530..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/oui.h +++ /dev/null @@ -1,74 +0,0 @@ -/* oui.h - * Definitions of OUIs - * - * $Id: oui.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 - 2000 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __OUI_H__ -#define __OUI_H__ - -/* - * See - * - * http://standards.ieee.org/regauth/oui/oui.txt - * - * http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/vlan.htm - * - * for the PIDs for VTP and DRiP that go with an OUI of OUI_CISCO. - */ - -#define OUI_ENCAP_ETHER 0x000000 /* encapsulated Ethernet */ -#define OUI_XEROX 0x000006 /* Xerox */ -#define OUI_CISCO 0x00000C /* Cisco (future use) */ -#define OUI_NORTEL 0x000081 /* Nortel SONMP */ -#define OUI_CISCO_90 0x0000F8 /* Cisco (IOS 9.0 and above?) */ -#define OUI_ERICSSON 0x0001EC /* Ericsson Group */ -#define OUI_CATENA 0x00025A /* Catena Networks */ -#define OUI_SONY_ERICSSON 0x000AD9 /* Sony Ericsson Mobile Communications AB */ -#define OUI_SONY_ERICSSON_2 0x000E07 /* Sony Ericsson Mobile Communications AB */ -#define OUI_PROFINET 0x000ECF /* PROFIBUS Nutzerorganisation e.V. */ -#define OUI_SONY_ERICSSON_3 0x000FDE /* Sony Ericsson Mobile Communications AB */ -#define OUI_IEEE_802_3 0x00120F /* IEEE 802.3 */ -#define OUI_MEDIA_ENDPOINT 0x0012BB /* Media (TIA TR-41 Committee) */ -#define OUI_SONY_ERICSSON_4 0x0012EE /* Sony Ericsson Mobile Communications AB */ -#define OUI_ERICSSON_MOBILE 0x0015E0 /* Ericsson Mobile Platforms */ -#define OUI_SONY_ERICSSON_5 0x001620 /* Sony Ericsson Mobile Communications AB */ -#define OUI_SONY_ERICSSON_6 0x0016B8 /* Sony Ericsson Mobile Communications AB */ -#define OUI_SONY_ERICSSON_7 0x001813 /* Sony Ericsson Mobile Communications AB */ -#define OUI_SONY_ERICSSON_8 0x001963 /* Sony Ericsson Mobile Communications AB */ -#define OUI_CISCOWL 0x004096 /* Cisco Wireless (Aironet) */ -#define OUI_ERICSSON_2 0x008037 /* Ericsson Group */ -#define OUI_BRIDGED 0x0080C2 /* Bridged Frame-Relay, RFC 2427 */ - /* and Bridged ATM, RFC 2684 */ -#define OUI_IEEE_802_1 0x0080C2 /* IEEE 802.1 Committee */ -#define OUI_ATM_FORUM 0x00A03E /* ATM Forum */ -#define OUI_EXTREME 0x00E02B /* Extreme EDP/ESRP */ -#define OUI_CABLE_BPDU 0x00E02F /* DOCSIS spanning tree BPDU */ -#define OUI_SIEMENS 0x080006 /* Siemens AG */ -#define OUI_APPLE_ATALK 0x080007 /* Appletalk */ -#define OUI_HP 0x080009 /* Hewlett-Packard */ - -/* - * Defined in packet-llc.c - */ -extern const value_string oui_vals[]; - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/packet.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/packet.h deleted file mode 100644 index 5061c565..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/packet.h +++ /dev/null @@ -1,422 +0,0 @@ -/* packet.h - * Definitions for packet disassembly structures and routines - * - * $Id: packet.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef __PACKET_H__ -#define __PACKET_H__ - -/* - * If defines formats to be used to print 64-bit integers, - * include it. - */ -#ifdef INTTYPES_H_DEFINES_FORMATS -#include -#endif - -#include "wiretap/wtap.h" -#include "proto.h" -#include "tvbuff.h" -#include "pint.h" -#include "to_str.h" -#include "value_string.h" -#include "column_info.h" -#include "frame_data.h" -#include "packet_info.h" -#include "column-utils.h" -#include "epan.h" -#include "tfs.h" - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#define hi_nibble(b) (((b) & 0xf0) >> 4) -#define lo_nibble(b) ((b) & 0x0f) - -/* Useful when you have an array whose size you can tell at compile-time */ -#define array_length(x) (sizeof x / sizeof x[0]) - -/* Check whether the "len" bytes of data starting at "offset" is - * entirely inside the captured data for this packet. */ -#define BYTES_ARE_IN_FRAME(offset, captured_len, len) \ - ((guint)(offset) + (guint)(len) > (guint)(offset) && \ - (guint)(offset) + (guint)(len) <= (guint)(captured_len)) - -/* To pass one of two strings, singular or plural */ -#define plurality(d,s,p) ((d) == 1 ? (s) : (p)) - -typedef struct _packet_counts { - gint sctp; - gint tcp; - gint udp; - gint icmp; - gint ospf; - gint gre; - gint netbios; - gint ipx; - gint vines; - gint other; - gint total; - gint arp; -} packet_counts; - -/** Number of packet counts. */ -#define PACKET_COUNTS_SIZE sizeof(packet_counts) / sizeof (gint) - -/* Types of character encodings */ -typedef enum { - CHAR_ASCII = 0, /* ASCII */ - CHAR_EBCDIC = 1 /* EBCDIC */ -} char_enc; - -extern void packet_init(void); -extern void packet_cleanup(void); - -/* Handle for dissectors you call directly or register with "dissector_add()". - This handle is opaque outside of "packet.c". */ -struct dissector_handle; -typedef struct dissector_handle *dissector_handle_t; - -/* Hash table for matching port numbers and dissectors; this is opaque - outside of "packet.c". */ -struct dissector_table; -typedef struct dissector_table *dissector_table_t; - -/* - * Dissector that returns nothing. - */ -typedef void (*dissector_t)(tvbuff_t *, packet_info *, proto_tree *); - -/* - * Dissector that returns: - * - * The amount of data in the protocol's PDU, if it was able to - * dissect all the data; - * - * 0, if the tvbuff doesn't contain a PDU for that protocol; - * - * The negative of the amount of additional data needed, if - * we need more data (e.g., from subsequent TCP segments) to - * dissect the entire PDU. - */ -typedef int (*new_dissector_t)(tvbuff_t *, packet_info *, proto_tree *); - -/** Type of a heuristic dissector, used in heur_dissector_add(). - * - * @param tvb the tv_buff with the (remaining) packet data - * @param pinfo the packet info of this packet (additional info) - * @param tree the protocol tree to be build or NULL - * @return TRUE if the packet was recognized by the sub-dissector (stop dissection here) - */ -typedef gboolean (*heur_dissector_t)(tvbuff_t *tvb, packet_info *pinfo, - proto_tree *tree); - -typedef void (*DATFunc) (const gchar *table_name, ftenum_t selector_type, - gpointer key, gpointer value, gpointer user_data); -typedef void (*DATFunc_handle) (const gchar *table_name, gpointer value, - gpointer user_data); -typedef void (*DATFunc_table) (const gchar *table_name, const gchar *ui_name, - gpointer user_data); - -/* Opaque structure - provides type checking but no access to components */ -typedef struct dtbl_entry dtbl_entry_t; - -extern dissector_handle_t dtbl_entry_get_handle (dtbl_entry_t *dtbl_entry); -extern dissector_handle_t dtbl_entry_get_initial_handle (dtbl_entry_t * entry); -extern void dissector_table_foreach_changed (const char *name, DATFunc func, - gpointer user_data); -extern void dissector_table_foreach (const char *name, DATFunc func, - gpointer user_data); -extern void dissector_all_tables_foreach_changed (DATFunc func, - gpointer user_data); -extern void dissector_table_foreach_handle(const char *name, DATFunc_handle func, - gpointer user_data); -extern void dissector_all_tables_foreach_table (DATFunc_table func, - gpointer user_data); - -/* a protocol uses the function to register a sub-dissector table */ -extern dissector_table_t register_dissector_table(const char *name, - const char *ui_name, ftenum_t type, int base); - -/* Find a dissector table by table name. */ -extern dissector_table_t find_dissector_table(const char *name); - -/* Get the UI name for a sub-dissector table, given its internal name */ -extern const char *get_dissector_table_ui_name(const char *name); - -/* Get the field type for values of the selector for a dissector table, - given the table's internal name */ -extern ftenum_t get_dissector_table_selector_type(const char *name); - -/* Get the base to use when displaying values of the selector for a - sub-dissector table, given the table's internal name */ -extern int get_dissector_table_base(const char *name); - -/* Add an entry to a uint dissector table. */ -extern void dissector_add(const char *abbrev, guint32 pattern, - dissector_handle_t handle); - -/* Delete the entry for a dissector in a uint dissector table - with a particular pattern. */ -extern void dissector_delete(const char *name, guint32 pattern, - dissector_handle_t handle); - -/* Change the entry for a dissector in a uint dissector table - with a particular pattern to use a new dissector handle. */ -extern void dissector_change(const char *abbrev, guint32 pattern, - dissector_handle_t handle); - -/* Reset an entry in a uint dissector table to its initial value. */ -extern void dissector_reset(const char *name, guint32 pattern); - -/* Look for a given value in a given uint dissector table and, if found, - call the dissector with the arguments supplied, and return TRUE, - otherwise return FALSE. */ -extern gboolean dissector_try_port(dissector_table_t sub_dissectors, - guint32 port, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); - -/* Look for a given value in a given uint dissector table and, if found, - return the dissector handle for that value. */ -extern dissector_handle_t dissector_get_port_handle( - dissector_table_t sub_dissectors, guint32 port); - -/* Add an entry to a string dissector table. */ -extern void dissector_add_string(const char *name, const gchar *pattern, - dissector_handle_t handle); - -/* Delete the entry for a dissector in a string dissector table - with a particular pattern. */ -extern void dissector_delete_string(const char *name, const gchar *pattern, - dissector_handle_t handle); - -/* Change the entry for a dissector in a string dissector table - with a particular pattern to use a new dissector handle. */ -extern void dissector_change_string(const char *name, gchar *pattern, - dissector_handle_t handle); - -/* Reset an entry in a string sub-dissector table to its initial value. */ -extern void dissector_reset_string(const char *name, const gchar *pattern); - -/* Look for a given string in a given dissector table and, if found, call - the dissector with the arguments supplied, and return TRUE, otherwise - return FALSE. */ -extern gboolean dissector_try_string(dissector_table_t sub_dissectors, - const gchar *string, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); - -/* Look for a given value in a given string dissector table and, if found, - return the dissector handle for that value. */ -extern dissector_handle_t dissector_get_string_handle( - dissector_table_t sub_dissectors, const gchar *string); - -/* Add a handle to the list of handles that *could* be used with this - table. That list is used by code in the UI. */ -extern void dissector_add_handle(const char *name, dissector_handle_t handle); - -/* List of "heuristic" dissectors (which get handed a packet, look at it, - and either recognize it as being for their protocol, dissect it, and - return TRUE, or don't recognize it and return FALSE) to be called - by another dissector. */ -typedef GSList *heur_dissector_list_t; - -/** A protocol uses this function to register a heuristic sub-dissector list. - * Call this in the parent dissectors proto_register function. - * - * @param name the name of this protocol - * @param list the list of heuristic sub-dissectors to be registered - */ -extern void register_heur_dissector_list(const char *name, - heur_dissector_list_t *list); - -/** Try all the dissectors in a given heuristic dissector list. This is done, - * until we find one that recognizes the protocol. - * Call this while the parent dissector running. - * - * @param sub_dissectors the sub-dissector list - * @param tvb the tv_buff with the (remaining) packet data - * @param pinfo the packet info of this packet (additional info) - * @param tree the protocol tree to be build or NULL - * @return TRUE if the packet was recognized by the sub-dissector (stop dissection here) - */ -extern gboolean dissector_try_heuristic(heur_dissector_list_t sub_dissectors, - tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); - -/** Add a sub-dissector to a heuristic dissector list. - * Call this in the proto_handoff function of the sub-dissector. - * - * @param name the name of the "parent" protocol, e.g. "tcp" - * @param dissector the sub-dissector to be registered - * @param proto the protocol id of the sub-dissector - */ -extern void heur_dissector_add(const char *name, heur_dissector_t dissector, - int proto); - -/** Remove a sub-dissector from a heuristic dissector list. - * Call this in the prefs_reinit function of the sub-dissector. - * - * @param name the name of the "parent" protocol, e.g. "tcp" - * @param dissector the sub-dissector to be unregistered - * @param proto the protocol id of the sub-dissector - */ -extern void heur_dissector_delete(const char *name, heur_dissector_t dissector, int proto); - -/* Register a dissector. */ -extern void register_dissector(const char *name, dissector_t dissector, - int proto); -extern void new_register_dissector(const char *name, new_dissector_t dissector, - int proto); - -/* Get the short name of the protocol for a dissector handle. */ -extern const char *dissector_handle_get_short_name(dissector_handle_t handle); - -/* Get the index of the protocol for a dissector handle. */ -extern int dissector_handle_get_protocol_index(dissector_handle_t handle); - -/* Find a dissector by name. */ -extern dissector_handle_t find_dissector(const char *name); - -/* Create an anonymous handle for a dissector. */ -extern dissector_handle_t create_dissector_handle(dissector_t dissector, - int proto); -extern dissector_handle_t new_create_dissector_handle(new_dissector_t dissector, - int proto); - -/* Call a dissector through a handle and if no dissector was found - * pass if over to the "data" dissector instead. - * - * @param handle The dissector to call. - * @param tvb The buffer to dissect. - * @param pinfo Packet Info. - * @param tree The protocol tree. - * @return If the protocol for that handle isn't enabled call the data - * dissector. Otherwise, if the handle refers to a new-style - * dissector, call the dissector and return its return value, otherwise call - * it and return the length of the tvbuff pointed to by the argument. - */ -extern int call_dissector(dissector_handle_t handle, tvbuff_t *tvb, - packet_info *pinfo, proto_tree *tree); - -/* Call a dissector through a handle but if no dissector was found - * just return 0 and do not call the "data" dissector instead. - * - * @param handle The dissector to call. - * @param tvb The buffer to dissect. - * @param pinfo Packet Info. - * @param tree The protocol tree. - * @return If the protocol for that handle isn't enabled, return 0 without - * calling the dissector. Otherwise, if the handle refers to a new-style - * dissector, call the dissector and return its return value, otherwise call - * it and return the length of the tvbuff pointed to by the argument. - */ -extern int call_dissector_only(dissector_handle_t handle, tvbuff_t *tvb, - packet_info *pinfo, proto_tree *tree); - -/* Do all one-time initialization. */ -extern void dissect_init(void); - -extern void dissect_cleanup(void); - -/* - * Given a tvbuff, and a length from a packet header, adjust the length - * of the tvbuff to reflect the specified length. - */ -extern void set_actual_length(tvbuff_t *tvb, guint specified_len); - -/* Allow protocols to register "init" routines, which are called before - we make a pass through a capture file and dissect all its packets - (e.g., when we read in a new capture file, or run a "filter packets" - or "colorize packets" pass over the current capture file). */ -extern void register_init_routine(void (*func)(void)); - -/* Initialize all data structures used for dissection. */ -extern void init_dissection(void); - -/* Free data structures allocated for dissection. */ -extern void cleanup_dissection(void); - -/* Allow protocols to register a "cleanup" routine to be - * run after the initial sequential run through the packets. - * Note that the file can still be open after this; this is not - * the final cleanup. */ -extern void register_postseq_cleanup_routine(void (*func)(void)); - -/* Call all the registered "postseq_cleanup" routines. */ -extern void postseq_cleanup_all_protocols(void); - -/* Allow dissectors to register a "final_registration" routine - * that is run like the proto_register_XXX() routine, but the end - * end of the epan_init() function; that is, *after* all other - * subsystems, liked dfilters, have finished initializing. This is - * useful for dissector registration routines which need to compile - * display filters. dfilters can't initialize itself until all protocols - * have registereed themselvs. */ -extern void -register_final_registration_routine(void (*func)(void)); - -/* Call all the registered "final_registration" routines. */ -extern void -final_registration_all_protocols(void); - -/* - * Add a new data source to the list of data sources for a frame, given - * the tvbuff for the data source and its name. - */ -extern void add_new_data_source(packet_info *pinfo, tvbuff_t *tvb, - const char *name); - -/* - * Free up a frame's list of data sources. - */ -extern void free_data_sources(packet_info *pinfo); - -/* - * Dissectors should never modify the packet data. - */ -extern void dissect_packet(epan_dissect_t *edt, - union wtap_pseudo_header *pseudo_header, const guchar *pd, - frame_data *fd, column_info *cinfo); - -/* These functions are in packet-ethertype.c */ -extern void capture_ethertype(guint16 etype, const guchar *pd, int offset, - int len, packet_counts *ld); -extern void ethertype(guint16 etype, tvbuff_t *tvb, int offset_after_ethertype, - packet_info *pinfo, proto_tree *tree, proto_tree *fh_tree, - int etype_id, int trailer_id, int fcs_len); - -/* - * Dump layer/selector/dissector records in a fashion similar to the - * proto_registrar_dump_* routines. - */ -extern void dissector_dump_decodes(void); - -/* - * post dissectors are to be called by packet-frame.c after every other - * dissector has been called. - */ -extern void register_postdissector(dissector_handle_t); -extern void call_all_postdissectors(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* packet.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/packet_info.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/packet_info.h deleted file mode 100644 index 3902be51..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/packet_info.h +++ /dev/null @@ -1,184 +0,0 @@ -/* packet_info.h - * Definitions for packet info structures and routines - * - * $Id: packet_info.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __PACKET_INFO_H__ -#define __PACKET_INFO_H__ - -#include "frame_data.h" -#include "tvbuff.h" -#include "address.h" - -#define P2P_DIR_UNKNOWN -1 -#define P2P_DIR_SENT 0 -#define P2P_DIR_RECV 1 - -#define PINFO_SOF_FIRST_FRAME 0x1 -#define PINFO_SOF_SOFF 0x2 -#define PINFO_EOF_LAST_FRAME 0x80 -#define PINFO_EOF_INVALID 0x40 -#define MAX_NUMBER_OF_PPIDS 2 - -typedef struct _packet_info { - const char *current_proto; /* name of protocol currently being dissected */ - column_info *cinfo; /* Column formatting information */ - frame_data *fd; - union wtap_pseudo_header *pseudo_header; - GSList *data_src; /* Frame data sources */ - address dl_src; /* link-layer source address */ - address dl_dst; /* link-layer destination address */ - address net_src; /* network-layer source address */ - address net_dst; /* network-layer destination address */ - address src; /* source address (net if present, DL otherwise )*/ - address dst; /* destination address (net if present, DL otherwise )*/ - guint32 ethertype; /* Ethernet Type Code, if this is an Ethernet packet */ - guint32 ipproto; /* IP protocol, if this is an IP packet */ - guint32 ipxptype; /* IPX packet type, if this is an IPX packet */ - circuit_type ctype; /* type of circuit, for protocols with a VC identifier */ - guint32 circuit_id; /* circuit ID, for protocols with a VC identifier */ - const char *noreassembly_reason; /* reason why reassembly wasn't done, if any */ - gboolean fragmented; /* TRUE if the protocol is only a fragment */ - gboolean in_error_pkt; /* TRUE if we're inside an {ICMP,CLNP,...} error packet */ - port_type ptype; /* type of the following two port numbers */ - guint32 srcport; /* source port */ - guint32 destport; /* destination port */ - guint32 match_port; /* matched port for calling subdissector from table */ - const char *match_string; /* matched string for calling subdissector from table */ - guint16 can_desegment; /* >0 if this segment could be desegmented. - A dissector that can offer this API (e.g. - TCP) sets can_desegment=2, then - can_desegment is decremented by 1 each time - we pass to the next subdissector. Thus only - the dissector immediately above the - protocol which sets the flag can use it*/ - guint16 saved_can_desegment; /* Value of can_desegment before current - dissector was called. Supplied so that - dissectors for proxy protocols such as - SOCKS can restore it, allowing the - dissectors that they call to use the - TCP dissector's desegmentation (SOCKS - just retransmits TCP segments once it's - finished setting things up, so the TCP - desegmentor can desegment its payload). */ - int desegment_offset; /* offset to stuff needing desegmentation */ -#define DESEGMENT_ONE_MORE_SEGMENT 0x0fffffff -#define DESEGMENT_UNTIL_FIN 0x0ffffffe - guint32 desegment_len; /* requested desegmentation additional length - or - DESEGMENT_ONE_MORE_SEGMENT: - Desegment one more full segment - (warning! only partially implemented) - DESEGMENT_UNTIL_FIN: - Desgment all data for this tcp session - until the FIN segment. - */ - guint16 want_pdu_tracking; /* >0 if the subdissector has specified - a value in 'bytes_until_next_pdu'. - When a dissector detects that the next PDU - will start beyond the start of the next - segment, it can set this value to 2 - and 'bytes_until_next_pdu' to the number of - bytes beyond the next segment where the - next PDU starts. - - If the protocol dissector below this - one is capable of PDU tracking it can - use this hint to detect PDUs that starts - unaligned to the segment boundaries. - The TCP dissector is using this hint from - (some) protocols to detect when a new PDU - starts in the middle of a tcp segment. - - There is intelligence in the glue between - dissector layers to make sure that this - request is only passed down to the protocol - immediately below the current one and not - any further. - */ - guint32 bytes_until_next_pdu; - - - int iplen; /* total length of IP packet */ - int iphdrlen; /* length of IP header */ - int p2p_dir; /* Packet was captured as an - outbound (P2P_DIR_SENT) - inbound (P2P_DIR_RECV) - unknown (P2P_DIR_UNKNOWN) */ - guint16 oxid; /* next 2 fields reqd to identify fibre */ - guint16 rxid; /* channel conversations */ - guint8 r_ctl; /* R_CTL field in Fibre Channel Protocol */ - guint8 sof_eof; /* FC's SOF/EOF encoding passed to FC decoder - * Bit 7 set if Last frame in sequence - * Bit 6 set if invalid frame content - * Bit 2 set if SOFf - * Bit 1 set if first frame in sequence - */ - guint16 src_idx; /* Source port index (Cisco MDS-specific) */ - guint16 dst_idx; /* Dest port index (Cisco MDS-specific) */ - guint16 vsan; /* Fibre channel/Cisco MDS-specific */ - - /* Extra data for DCERPC handling and tracking of context ids */ - guint16 dcectxid; /* Context ID (DCERPC-specific) */ - int dcetransporttype; /* Transport type - * Value -1 means "not a DCERPC packet" - */ - guint16 dcetransportsalt; /* fid: if transporttype==DCE_CN_TRANSPORT_SMBPIPE */ - - /* Extra data for handling of decryption of GSSAPI wrapped tvbuffs. - Caller sets decrypt_gssapi_tvb if this service is requested. - If gssapi_encrypted_tvb is NULL, then the rest of the tvb data following - the gssapi blob itself is decrypted othervise the gssapi_encrypted_tvb - tvb will be decrypted (DCERPC has the data before the gssapi blob) - If, on return, gssapi_data_encrypted is FALSE, the wrapped tvbuff - was signed (i.e., an encrypted signature was present, to check - whether the data was modified by a man in the middle) but not sealed - (i.e., the data itself wasn't encrypted). - */ -#define DECRYPT_GSSAPI_NORMAL 1 -#define DECRYPT_GSSAPI_DCE 2 - guint16 decrypt_gssapi_tvb; - tvbuff_t *gssapi_wrap_tvb; - tvbuff_t *gssapi_encrypted_tvb; - tvbuff_t *gssapi_decrypted_tvb; - gboolean gssapi_data_encrypted; - - guint32 ppid[MAX_NUMBER_OF_PPIDS]; /* The first NUMBER_OF_PPIDS PPIDS which are present - * in the SCTP packet - */ - void *private_data; /* pointer to data passed from one dissector to another */ - GString *layer_names; /* layers of each protocol */ - guint16 link_number; - guint8 annex_a_used; - guint16 profinet_type; /* the type of PROFINET packet (0: not a PROFINET packet) */ - void *profinet_conv; /* the PROFINET conversation data (NULL: not a PROFINET packet) */ - void *usb_conv_info; - void *tcp_tree; /* proto_tree for the tcp layer */ - - const char *dcerpc_procedure_name; /* Used by PIDL to store the name of the current dcerpc procedure */ - - struct _sccp_msg_info_t* sccp_info; - guint16 clnp_srcref; /* clnp/cotp source reference (can't use srcport, this would confuse tpkt) */ - guint16 clnp_dstref; /* clnp/cotp destination reference (can't use dstport, this would confuse tpkt) */ -} packet_info; - -#endif /* __PACKET_INFO_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/pint.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/pint.h deleted file mode 100644 index f947a04e..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/pint.h +++ /dev/null @@ -1,113 +0,0 @@ -/* pint.h - * Definitions for extracting and translating integers safely and portably - * via pointers. - * - * $Id: pint.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __PINT_H__ -#define __PINT_H__ - -#include - -/* Pointer versions of g_ntohs and g_ntohl. Given a pointer to a member of a - * byte array, returns the value of the two or four bytes at the pointer. - * The pletoh[sl] versions return the little-endian representation. - */ - -#define pntohs(p) ((guint16) \ - ((guint16)*((const guint8 *)(p)+0)<<8| \ - (guint16)*((const guint8 *)(p)+1)<<0)) - -#define pntoh24(p) ((guint32)*((const guint8 *)(p)+0)<<16| \ - (guint32)*((const guint8 *)(p)+1)<<8| \ - (guint32)*((const guint8 *)(p)+2)<<0) - -#define pntohl(p) ((guint32)*((const guint8 *)(p)+0)<<24| \ - (guint32)*((const guint8 *)(p)+1)<<16| \ - (guint32)*((const guint8 *)(p)+2)<<8| \ - (guint32)*((const guint8 *)(p)+3)<<0) -#define pntoh64(p) ((guint64)*((const guint8 *)(p)+0)<<56| \ - (guint64)*((const guint8 *)(p)+1)<<48| \ - (guint64)*((const guint8 *)(p)+2)<<40| \ - (guint64)*((const guint8 *)(p)+3)<<32| \ - (guint64)*((const guint8 *)(p)+4)<<24| \ - (guint64)*((const guint8 *)(p)+5)<<16| \ - (guint64)*((const guint8 *)(p)+6)<<8| \ - (guint64)*((const guint8 *)(p)+7)<<0) - - -#define pletohs(p) ((guint16) \ - ((guint16)*((const guint8 *)(p)+1)<<8| \ - (guint16)*((const guint8 *)(p)+0)<<0)) - -#define pletoh24(p) ((guint32)*((const guint8 *)(p)+2)<<16| \ - (guint32)*((const guint8 *)(p)+1)<<8| \ - (guint32)*((const guint8 *)(p)+0)<<0) - -#define pletohl(p) ((guint32)*((const guint8 *)(p)+3)<<24| \ - (guint32)*((const guint8 *)(p)+2)<<16| \ - (guint32)*((const guint8 *)(p)+1)<<8| \ - (guint32)*((const guint8 *)(p)+0)<<0) -#define pletoh64(p) ((guint64)*((const guint8 *)(p)+7)<<56| \ - (guint64)*((const guint8 *)(p)+6)<<48| \ - (guint64)*((const guint8 *)(p)+5)<<40| \ - (guint64)*((const guint8 *)(p)+4)<<32| \ - (guint64)*((const guint8 *)(p)+3)<<24| \ - (guint64)*((const guint8 *)(p)+2)<<16| \ - (guint64)*((const guint8 *)(p)+1)<<8| \ - (guint64)*((const guint8 *)(p)+0)<<0) - -/* Pointer routines to put items out in a particular byte order. - * These will work regardless of the byte alignment of the pointer. - */ - -#define phtons(p, v) \ - { \ - ((guint8*)(p))[0] = (guint8)((v) >> 8); \ - ((guint8*)(p))[1] = (guint8)((v) >> 0); \ - } - -#define phtonl(p, v) \ - { \ - ((guint8*)(p))[0] = (guint8)((v) >> 24); \ - ((guint8*)(p))[1] = (guint8)((v) >> 16); \ - ((guint8*)(p))[2] = (guint8)((v) >> 8); \ - ((guint8*)(p))[3] = (guint8)((v) >> 0); \ - } - - -/* Macros to byte-swap 32-bit and 16-bit quantities. */ -#define BSWAP32(x) \ - ((((x)&0xFF000000)>>24) | \ - (((x)&0x00FF0000)>>8) | \ - (((x)&0x0000FF00)<<8) | \ - (((x)&0x000000FF)<<24)) -#define BSWAP16(x) \ - ((((x)&0xFF00)>>8) | \ - (((x)&0x00FF)<<8)) - -/* Turn host-byte-order values into little-endian values. */ -#define htoles(s) GUINT16_TO_LE(s) -#define htolel(l) GUINT32_TO_LE(l) - -#endif /* PINT_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/plugins.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/plugins.h deleted file mode 100644 index 100e5805..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/plugins.h +++ /dev/null @@ -1,58 +0,0 @@ -/* plugins.h - * definitions for plugins structures - * - * $Id: plugins.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1999 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __PLUGINS_H__ -#define __PLUGINS_H__ - -#include -#include - -#include "packet.h" - -typedef struct _plugin { - GModule *handle; /* handle returned by dlopen */ - gchar *name; /* plugin name */ - gchar *version; /* plugin version */ - void (*register_protoinfo)(void); /* routine to call to register protocol information */ - void (*reg_handoff)(void); /* routine to call to register dissector handoff */ - void (*register_tap_listener)(void); /* routine to call to register tap listener */ - void (*register_wtap_module)(void); /* routine to call to register a wiretap module */ - void (*register_codec_module)(void); /* routine to call to register a codec */ - struct _plugin *next; /* forward link */ -} plugin; - -WS_VAR_IMPORT plugin *plugin_list; - -extern void init_plugins(void); -extern void register_all_plugin_registrations(void); -extern void register_all_plugin_handoffs(void); -extern void register_all_plugin_tap_listeners(void); -extern void register_all_wiretap_modules(void); -extern void register_all_codecs(void); - -/* get the personal plugin dir */ -/* Return value is g_malloced so the caller should g_free() it. */ -extern char *get_plugins_pers_dir(void); - -#endif /* __PLUGINS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ppptypes.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ppptypes.h deleted file mode 100644 index 64bbcb34..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ppptypes.h +++ /dev/null @@ -1,158 +0,0 @@ -/* ppptypes.h - * Defines PPP packet types. - * - * $Id: ppptypes.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __PPPTYPES_H__ -#define __PPPTYPES_H__ - -/* Protocol types, from Linux "ppp_defs.h" and - - http://www.iana.org/assignments/ppp-numbers - - */ -#define PPP_PADDING 0x1 /* Padding Protocol */ -#define PPP_ROHC_SCID 0x3 /* ROHC small-CID */ -#define PPP_ROHC_LCID 0x5 /* ROHC large-CID */ -#define PPP_IP 0x21 /* Internet Protocol */ -#define PPP_OSI 0x23 /* OSI Protocol */ -#define PPP_DEC4 0x25 /* DECnet Phase IV */ -#define PPP_AT 0x29 /* AppleTalk Protocol */ -#define PPP_IPX 0x2b /* IPX protocol */ -#define PPP_VJC_COMP 0x2d /* VJ compressed TCP */ -#define PPP_VJC_UNCOMP 0x2f /* VJ uncompressed TCP */ -#define PPP_BPDU 0x31 /* Bridging PDU (spanning tree BPDU?) */ -#define PPP_ST 0x33 /* Stream Protocol (ST-II) */ -#define PPP_VINES 0x35 /* Banyan Vines */ -#define PPP_AT_EDDP 0x39 /* AppleTalk EDDP */ -#define PPP_AT_SB 0x3b /* AppleTalk SmartBuffered */ -#define PPP_MP 0x3d /* Multilink PPP */ -#define PPP_NB 0x3f /* NETBIOS Framing */ -#define PPP_CISCO 0x41 /* Cisco Systems */ -#define PPP_ASCOM 0x43 /* Ascom Timeplex */ -#define PPP_LBLB 0x45 /* Fujitsu Link Backup and Load Balancing */ -#define PPP_RL 0x47 /* DCA Remote Lan */ -#define PPP_SDTP 0x49 /* Serial Data Transport Protocol */ -#define PPP_LLC 0x4b /* SNA over LLC */ -#define PPP_SNA 0x4d /* SNA */ -#define PPP_IPV6HC 0x4f /* IPv6 Header Compression */ -#define PPP_KNX 0x51 /* KNX Bridging Data */ -#define PPP_ENCRYPT 0x53 /* Encryption */ -#define PPP_ILE 0x55 /* Individual Link Encryption */ -#define PPP_IPV6 0x57 /* Internet Protocol Version 6 */ -#define PPP_MUX 0x59 /* PPP Multiplexing */ -#define PPP_RTP_FH 0x61 /* RTP IPHC Full Header */ -#define PPP_RTP_CTCP 0x63 /* RTP IPHC Compressed TCP */ -#define PPP_RTP_CNTCP 0x65 /* RTP IPHC Compressed Non TCP */ -#define PPP_RTP_CUDP8 0x67 /* RTP IPHC Compressed UDP 8 */ -#define PPP_RTP_CRTP8 0x69 /* RTP IPHC Compressed RTP 8 */ -#define PPP_STAMPEDE 0x6f /* Stampede Bridging */ -#define PPP_MPPLUS 0x73 /* MP+ Protocol */ -#define PPP_NTCITS_IPI 0xc1 /* NTCITS IPI */ -#define PPP_ML_SLCOMP 0xfb /* single link compression in multilink */ -#define PPP_COMP 0xfd /* compressed packet */ -#define PPP_STP_HELLO 0x0201 /* 802.1d Hello Packet */ -#define PPP_IBM_SR 0x0203 /* IBM Source Routing BPDU */ -#define PPP_DEC_LB 0x0205 /* DEC LANBridge100 Spanning Tree */ -#define PPP_CDP 0x0207 /* Cisco Discovery Protocol */ -#define PPP_NETCS 0x0209 /* Netcs Twin Routing */ -#define PPP_STP 0x020b /* Scheduled Transfer Protocol */ -#define PPP_EDP 0x020d /* Extreme Discovery Protocol */ -#define PPP_OSCP 0x0211 /* Optical Supervisory Channel Protocol */ -#define PPP_OSCP2 0x0213 /* Optical Supervisory Channel Protocol */ -#define PPP_LUXCOM 0x0231 /* Luxcom */ -#define PPP_SIGMA 0x0233 /* Sigma Network Systems */ -#define PPP_ACSP 0x0235 /* Apple Client Server Protocol */ -#define PPP_MPLS_UNI 0x0281 /* MPLS Unicast */ -#define PPP_MPLS_MULTI 0x0283 /* MPLS Multicast */ -#define PPP_P12844 0x0285 /* IEEE p1284.4 standard - data packets */ -#define PPP_ETSI 0x0287 /* ETSI TETRA Networks Procotol Type 1 */ -#define PPP_MFTP 0x0289 /* Multichannel Flow Treatment Protocol */ -#define PPP_RTP_CTCPND 0x2063 /* RTP IPHC Compressed TCP No Delta */ -#define PPP_RTP_CS 0x2065 /* RTP IPHC Context State */ -#define PPP_RTP_CUDP16 0x2067 /* RTP IPHC Compressed UDP 16 */ -#define PPP_RTP_CRDP16 0x2069 /* RTP IPHC Compressed RTP 16 */ -#define PPP_CCCP 0x4001 /* Cray Communications Control Protocol */ -#define PPP_CDPD_MNRP 0x4003 /* CDPD Mobile Network Registration Protocol */ -#define PPP_EXPANDAP 0x4005 /* Expand accelarator protocol */ -#define PPP_ODSICP 0x4007 /* ODSICP NCP */ -#define PPP_DOCSIS 0x4009 /* DOCSIS DLL */ -#define PPP_LZS 0x4021 /* Stacker LZS */ -#define PPP_REFTEK 0x4023 /* RefTek Protocol */ -#define PPP_FC 0x4025 /* Fibre Channel */ -#define PPP_EMIT 0x4027 /* EMIT Protocols */ -#define PPP_IPCP 0x8021 /* IP Control Protocol */ -#define PPP_OSICP 0x8023 /* OSI Control Protocol */ -#define PPP_XNSIDPCP 0x8025 /* Xerox NS IDP Control Protocol */ -#define PPP_DECNETCP 0x8027 /* DECnet Phase IV Control Protocol */ -#define PPP_ATCP 0x8029 /* AppleTalk Control Protocol */ -#define PPP_IPXCP 0x802b /* IPX Control Protocol */ -#define PPP_BRIDGENCP 0x8031 /* Bridging NCP */ -#define PPP_SPCP 0x8033 /* Stream Protocol Control Protocol */ -#define PPP_BVCP 0x8035 /* Banyan Vines Control Protocol */ -#define PPP_MLCP 0x803d /* Multi-Link Control Protocol */ -#define PPP_NBCP 0x803f /* NETBIOS Framing Control Protocol */ -#define PPP_CISCOCP 0x8041 /* Cisco Systems Control Protocol */ -#define PPP_ASCOMCP 0x8043 /* Ascom Timeplex Control Protocol (?) */ -#define PPP_LBLBCP 0x8045 /* Fujitsu LBLB Control Protocol */ -#define PPP_RLNCP 0x8047 /* DCA Remote Lan Network Control Protocol */ -#define PPP_SDCP 0x8049 /* Serial Data Control Protocol */ -#define PPP_LLCCP 0x804b /* SNA over LLC Control Protocol */ -#define PPP_SNACP 0x804d /* SNA Control Protocol */ -#define PPP_KNXCP 0x8051 /* KNX Bridging Control Protocol */ -#define PPP_ECP 0x8053 /* Encryption Control Protocol */ -#define PPP_ILECP 0x8055 /* Individual Encryption Control Protocol */ -#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */ -#define PPP_MUXCP 0x8059 /* PPPMux Control Protocol */ -#define PPP_STAMPEDECP 0x806f /* Stampede Bridging Control Protocol */ -#define PPP_MPPCP 0x8073 /* MP+ Contorol Protocol */ -#define PPP_IPICP 0x80c1 /* NTCITS IPI Control Protocol */ -#define PPP_SLCC 0x80fb /* single link compression in multilink control */ -#define PPP_CCP 0x80fd /* Compression Control Protocol */ -#define PPP_CDPCP 0x8207 /* Cisco Discovery Protocol Control Protocol */ -#define PPP_NETCSCP 0x8209 /* Netcs Twin Routing */ -#define PPP_STPCP 0x820b /* STP - Control Protocol */ -#define PPP_EDPCP 0x820d /* Extreme Discovery Protocol Control Protocol */ -#define PPP_ACSPC 0x8235 /* Apple Client Server Protocol Control */ -#define PPP_MPLSCP 0x8281 /* MPLS Control Protocol */ -#define PPP_P12844CP 0x8285 /* IEEE p1284.4 standard - Protocol Control */ -#define PPP_ETSICP 0x8287 /* ETSI TETRA TNP1 Control Protocol */ -#define PPP_MFTPCP 0x8287 /* Multichannel Flow Treatment Protocol */ -#define PPP_LCP 0xc021 /* Link Control Protocol */ -#define PPP_PAP 0xc023 /* Password Authentication Protocol */ -#define PPP_LQR 0xc025 /* Link Quality Report protocol */ -#define PPP_SPAP 0xc027 /* Shiva Password Authentication Protocol */ -#define PPP_CBCP 0xc029 /* CallBack Control Protocol */ -#define PPP_BACP 0xc02b /* Bandwidth Allocation Control Protocol */ -#define PPP_BAP 0xc02d /* Bandwidth Allocation Protocol */ -#define PPP_CONTCP 0xc081 /* Container Control Protocol */ -#define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */ -#define PPP_RSAAP 0xc225 /* RSA Authentication Protocol */ -#define PPP_EAP 0xc227 /* Extensible Authentication Protocol */ -#define PPP_SIEP 0xc229 /* Mitsubishi Security Information Exchange Protocol*/ -#define PPP_SBAP 0xc26f /* Stampede Bridging Authorization Protocol */ -#define PPP_PRPAP 0x281 /* Proprietary Authentication Protocol */ -#define PPP_PRPAP2 0x283 /* Proprietary Authentication Protocol */ -#define PPP_PRPNIAP 0x481 /* Proprietary Node ID Authentication Protocol */ - -#endif /* ppptypes.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/prefs-int.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/prefs-int.h deleted file mode 100644 index 3f54c931..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/prefs-int.h +++ /dev/null @@ -1,111 +0,0 @@ -/* prefs-int.h - * Definitions for implementation of preference handling routines; - * used by "friends" of the preferences type. - * - * $Id: prefs-int.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __PREFS_INT_H__ -#define __PREFS_INT_H__ - -struct pref_module { - const char *name; /* name of module */ - const char *title; /* title of module (displayed in preferences list) */ - const char *description;/* Description of module (displayed in preferences notebook) */ - void (*apply_cb)(void); /* routine to call when preferences applied */ - GList *prefs; /* list of its preferences */ - emem_tree_t *submodules;/* list of its submodules */ - int numprefs; /* number of non-obsolete preferences */ - gboolean prefs_changed; /* if TRUE, a preference has changed since we last checked */ - gboolean obsolete; /* if TRUE, this is a module that used to - exist but no longer does */ -}; - -/* - * Module used for protocol preferences. - * With MSVC and a libwireshark.dll, we need a special declaration. - */ -WS_VAR_IMPORT module_t *protocols_module; - -/* - * PREF_OBSOLETE is used for preferences that a module used to support - * but no longer supports; we give different error messages for them. - */ -typedef enum { - PREF_UINT, - PREF_BOOL, - PREF_ENUM, - PREF_STRING, - PREF_RANGE, - PREF_STATIC_TEXT, - PREF_UAT, - PREF_OBSOLETE -} pref_type_t; - -struct preference { - const char *name; /* name of preference */ - const char *title; /* title to use in GUI */ - const char *description; /* human-readable description of preference */ - int ordinal; /* ordinal number of this preference */ - pref_type_t type; /* type of that preference */ - union { - guint *uint; - gboolean *boolp; - gint *enump; - const char **string; - range_t **range; - void* uat; - } varp; /* pointer to variable storing the value */ - union { - guint uint; - gboolean boolval; - gint enumval; - char *string; - range_t *range; - } saved_val; /* original value, when editing from the GUI */ - union { - guint base; /* input/output base, for PREF_UINT */ - guint32 max_value; /* maximum value of a range */ - struct { - const enum_val_t *enumvals; /* list of name & values */ - gboolean radio_buttons; /* TRUE if it should be shown as - radio buttons rather than as an - option menu or combo box in - the preferences tab */ - } enum_info; /* for PREF_ENUM */ - } info; /* display/text file information */ - void *control; /* handle for GUI control for this preference */ -}; - -gint find_val_for_string(const char *needle, const enum_val_t *haystack, - gint default_value); - - -/* read_prefs_file: read in a generic config file and do a callback to */ -/* pref_set_pair_fct() for every key/value pair found */ -typedef prefs_set_pref_e (*pref_set_pair_cb) (gchar *key, gchar *value, void *private_data); - -int -read_prefs_file(const char *pf_path, FILE *pf, pref_set_pair_cb pref_set_pair_fct, void *private_data); - - - -#endif /* prefs-int.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/prefs.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/prefs.h deleted file mode 100644 index 3f2ab2c9..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/prefs.h +++ /dev/null @@ -1,426 +0,0 @@ -/* prefs.h - * Definitions for preference handling routines - * - * $Id: prefs.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __PREFS_H__ -#define __PREFS_H__ - -#include - -#include "color.h" - -#include - -#define PR_DEST_CMD 0 -#define PR_DEST_FILE 1 - -#define DEF_WIDTH 750 -#define DEF_HEIGHT 550 - -#define MAX_VAL_LEN 1024 - -#define RTP_PLAYER_DEFAULT_VISIBLE 4 - -/* only GTK1 *or* GTK2 font_name should be used */ -/* (we need to keep both in the preferences file but will only use the one suitable for the programs GTK version used) */ -#if GTK_MAJOR_VERSION < 2 -#define PREFS_GUI_FONT_NAME gui_font_name1 -#else -#define PREFS_GUI_FONT_NAME gui_font_name2 -#endif - -/* - * Convert a string listing name resolution types to a bitmask of - * those types. - * - * Set "*name_resolve" to the bitmask, and return '\0', on success; - * return the bad character in the string on error. - */ -char string_to_name_resolve(char *string, guint32 *name_resolve); - -/* - * Modes for the starting directory in File Open dialogs. - */ -#define FO_STYLE_LAST_OPENED 0 /* start in last directory we looked at */ -#define FO_STYLE_SPECIFIED 1 /* start in specified directory */ - -/* - * Toolbar styles. - */ -#define TB_STYLE_ICONS 0 -#define TB_STYLE_TEXT 1 -#define TB_STYLE_BOTH 2 - -/* - * Types of layout of summary/details/hex panes. - */ -typedef enum { - layout_unused, /* entry currently unused */ - layout_type_5, - layout_type_2, - layout_type_1, - layout_type_4, - layout_type_3, - layout_type_6, - layout_type_max -} layout_type_e; - -/* - * Types of pane. - */ -typedef enum { - layout_pane_content_none, - layout_pane_content_plist, - layout_pane_content_pdetails, - layout_pane_content_pbytes -} layout_pane_content_e; - -/* - * open console behaviour (win32 only) - */ -typedef enum { - console_open_never, - console_open_auto, - console_open_always -} console_open_e; - - -typedef struct _e_prefs { - gint pr_format; - gint pr_dest; - gchar *pr_file; - gchar *pr_cmd; - GList *col_list; - gint num_cols; - color_t st_client_fg, st_client_bg, st_server_fg, st_server_bg; - gboolean gui_scrollbar_on_right; - gboolean gui_plist_sel_browse; - gboolean gui_ptree_sel_browse; - gboolean gui_altern_colors; - gboolean filter_toolbar_show_in_statusbar; - gint gui_ptree_line_style; - gint gui_ptree_expander_style; - gboolean gui_hex_dump_highlight_style; - gint gui_toolbar_main_style; - gchar *gui_font_name1; - gchar *gui_font_name2; - color_t gui_marked_fg; - color_t gui_marked_bg; - gchar *gui_colorized_fg; - gchar *gui_colorized_bg; - gboolean gui_geometry_save_position; - gboolean gui_geometry_save_size; - gboolean gui_geometry_save_maximized; - console_open_e gui_console_open; - guint gui_recent_files_count_max; - guint gui_fileopen_style; - gchar *gui_fileopen_dir; - guint gui_fileopen_preview; - gboolean gui_ask_unsaved; - gboolean gui_find_wrap; - gboolean gui_use_pref_save; - gchar *gui_webbrowser; - gchar *gui_window_title; - layout_type_e gui_layout_type; - layout_pane_content_e gui_layout_content_1; - layout_pane_content_e gui_layout_content_2; - layout_pane_content_e gui_layout_content_3; - gint console_log_level; - guint32 name_resolve; - gint name_resolve_concurrency; - gchar *capture_device; - gchar *capture_devices_descr; - gchar *capture_devices_hide; - gboolean capture_prom_mode; - gboolean capture_real_time; - gboolean capture_auto_scroll; - gboolean capture_show_info; - guint rtp_player_max_visible; -} e_prefs; - -WS_VAR_IMPORT e_prefs prefs; - -/* - * Routines to let modules that have preference settings register - * themselves by name, and to let them register preference settings - * by name. - */ -struct pref_module; - -typedef struct pref_module module_t; - -/** Sets up memory used by proto routines. Called at program startup */ -extern void prefs_init(void); - -/** Reset preferences to default values. Called at profile change */ -extern void prefs_reset(void); - -/** Frees memory used by proto routines. Called at program shutdown */ -extern void prefs_cleanup(void); - -/* - * Register a module that will have preferences. - * Specify the module under which to register it or NULL to register it - * at the top level, the name used for the module in the preferences file, - * the title used in the tab for it in a preferences dialog box, and a - * routine to call back when we apply the preferences. - * - * This should not be used for dissector preferences; - * "prefs_register_protocol()" should be used for that, so that the - * preferences go under the "Protocols" subtree, and so that the - * name is the protocol name specified at the "proto_register_protocol()" - * call so that the "Protocol Properties..." menu item works. - */ -extern module_t *prefs_register_module(module_t *parent, const char *name, - const char *title, const char *description, void (*apply_cb)(void)); - -/* - * Register a subtree that will have modules under it. - * Specify the module under which to register it or NULL to register it - * at the top level and the title used in the tab for it in a preferences - * dialog box. - */ -extern module_t *prefs_register_subtree(module_t *parent, const char *title, - const char *description); - -/* - * Register that a protocol has preferences. - */ -extern module_t *prefs_register_protocol(int id, void (*apply_cb)(void)); - -/* - * Register that a protocol has preferences and group it under a single - * subtree - */ -#define PREFERENCE_GROUPING -extern module_t *prefs_register_protocol_subtree(const char *subtree, int id, - void (*apply_cb)(void)); - -/* - * Register that a protocol used to have preferences but no longer does, - * by creating an "obsolete" module for it. - */ -extern module_t *prefs_register_protocol_obsolete(int id); - -/* - * Callback function for module list scanners. - */ -typedef guint (*module_cb)(module_t *module, gpointer user_data); - -/* - * Returns TRUE if module has any submodules - */ -extern gboolean prefs_module_has_submodules(module_t *module); - -/* - * Call a callback function, with a specified argument, for each module - * in the list of all modules. (This list does not include subtrees.) - * - * Ignores "obsolete" modules; their sole purpose is to allow old - * preferences for dissectors that no longer have preferences to be - * silently ignored in preference files. - */ -extern guint prefs_modules_foreach(module_cb callback, gpointer user_data); - -/* - * Call a callback function, with a specified argument, for each submodule - * of specified modules. If the module is NULL, goes through the top-level - * list in the display tree of modules. - * - * Ignores "obsolete" modules; their sole purpose is to allow old - * preferences for dissectors that no longer have preferences to be - * silently ignored in preference files. Does not ignore subtrees, - * as this can be used when walking the display tree of modules. - */ -extern guint prefs_modules_foreach_submodules(module_t *module, module_cb callback, gpointer user_data); - -/* - * Call the "apply" callback function for each module if any of its - * preferences have changed, and then clear the flag saying its - * preferences have changed, as the module has been notified of that - * fact. - */ -extern void prefs_apply_all(void); - -/* - * Call the "apply" callback function for a specific module if any of - * its preferences have changed, and then clear the flag saying its - * preferences have changed, as the module has been notified of that - * fact. - */ -extern void prefs_apply(module_t *module); - - -struct preference; - -typedef struct preference pref_t; - -/* - * Returns TRUE if the given protocol has registered preferences. - */ -extern gboolean prefs_is_registered_protocol(const char *name); - -/* - * Returns the module title of a registered protocol (or NULL if unknown). - */ -extern const char *prefs_get_title_by_name(const char *name); - -/** Given a module name, return a pointer to its pref_module struct, - * or NULL if it's not found. - * - * @param name The preference module name. Usually the same as the protocol - * name, e.g. "tcp". - * @return A pointer to the corresponding preference module, or NULL if it - * wasn't found. - */ -extern module_t *prefs_find_module(const char *name); - -/* - * Register a preference with an unsigned integral value. - */ -extern void prefs_register_uint_preference(module_t *module, const char *name, - const char *title, const char *description, guint base, guint *var); - -/* - * Register a preference with an Boolean value. - * Note that the name must be in lowercase letters only (underscore allowed). - */ -extern void prefs_register_bool_preference(module_t *module, const char *name, - const char *title, const char *description, gboolean *var); - -/* - * Register a preference with an enumerated value. - */ -typedef struct { - const char *name; - const char *description; - gint value; -} enum_val_t; - -extern void prefs_register_enum_preference(module_t *module, const char *name, - const char *title, const char *description, gint *var, - const enum_val_t *enumvals, gboolean radio_buttons); - -/* - * Register a preference with a character-string value. - */ -extern void prefs_register_string_preference(module_t *module, const char *name, - const char *title, const char *description, const char **var); - -/* - * Register a preference with a ranged value. - */ -extern void prefs_register_range_preference(module_t *module, const char *name, - const char *title, const char *description, range_t **var, - guint32 max_value); - -/* - * Register a static text 'preference'. It can be used to add some info/explanation. - */ -extern void prefs_register_static_text_preference(module_t *module, const char *name, - const char *title, const char *description); - -/* - * Register a uat 'preference'. It adds a button that opens the uat's window in the - * preferences tab of the module. - */ -extern void prefs_register_uat_preference(module_t *module, - const char *name, - const char* title, - const char *description, - void* uat); - -/* - * Register a preference that used to be supported but no longer is. - */ -extern void prefs_register_obsolete_preference(module_t *module, - const char *name); - -typedef guint (*pref_cb)(pref_t *pref, gpointer user_data); - -/* - * Call a callback function, with a specified argument, for each preference - * in a given module. - * - * If any of the callbacks return a non-zero value, stop and return that - * value, otherwise return 0. - */ -extern guint prefs_pref_foreach(module_t *module, pref_cb callback, - gpointer user_data); - -/* - * Register all non-dissector modules' preferences. - */ -extern void prefs_register_modules(void); - -/* Read the preferences file, fill in "prefs", and return a pointer to it. - - If we got an error (other than "it doesn't exist") trying to read - the global preferences file, stuff the errno into "*gpf_errno_return" - on an open error and into "*gpf_read_errno_return" on a read error, - stuff a pointer to the path of the file into "*gpf_path_return", and - return NULL. - - If we got an error (other than "it doesn't exist") trying to read - the user's preferences file, stuff the errno into "*pf_errno_return" - on an open error and into "*pf_read_errno_return" on a read error, - stuff a pointer to the path of the file into "*pf_path_return", and - return NULL. */ -extern e_prefs *read_prefs(int *, int *, char **, int *, int *, char **); - -/* Write out "prefs" to the user's preferences file, and return 0. - - If we got an error, stuff a pointer to the path of the preferences file - into "*pf_path_return", and return the errno. */ -extern int write_prefs(char **); - -/* Copy a set of preferences. */ -extern void copy_prefs(e_prefs *dest, e_prefs *src); - -/* Free a set of preferences. */ -extern void free_prefs(e_prefs *pr); - -/* - * Given a string of the form ":", as might appear - * as an argument to a "-o" option, parse it and set the preference in - * question. Return an indication of whether it succeeded or failed - * in some fashion. - * - * XXX - should supply, for syntax errors, a detailed explanation of - * the syntax error. - */ -typedef enum { - PREFS_SET_OK, /* succeeded */ - PREFS_SET_SYNTAX_ERR, /* syntax error in string */ - PREFS_SET_NO_SUCH_PREF, /* no such preference */ - PREFS_SET_OBSOLETE /* preference used to exist but no longer does */ -} prefs_set_pref_e; - -extern prefs_set_pref_e prefs_set_pref(char *prefarg); - -/* - * Returns TRUE if the given device is hidden - */ -extern gboolean prefs_is_capture_device_hidden(const char *name); - -#endif /* prefs.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/privileges.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/privileges.h deleted file mode 100644 index 8a0b0ecf..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/privileges.h +++ /dev/null @@ -1,74 +0,0 @@ -/* privileges.h - * Declarations of routines for handling privileges. - * - * $Id: privileges.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2006 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/** - * Called when the program starts, to save whatever credential information - * we'll need later. - */ -extern void get_credential_info(void); - -/** - * Was this program started with special privileges? get_credential_info() - * MUST be called before calling this. - * @return TRUE if the program was started with special privileges, - * FALSE otherwise. - */ -extern gboolean started_with_special_privs(void); - -/** - * Is this program running with special privileges? get_credential_info() - * MUST be called before calling this. - * @return TRUE if the program is running with special privileges, - * FALSE otherwise. - */ -extern gboolean running_with_special_privs(void); - -/** - * Permanently relinquish special privileges. get_credential_info() - * MUST be called before calling this. - */ -extern void relinquish_special_privs_perm(void); - -/** - * Get the current username. String must be g_free()d after use. - * @return A freshly g_alloc()ed string containing the username, - * or "UNKNOWN" on failure. - */ -extern gchar *get_cur_username(void); - -/** - * Get the current group. String must be g_free()d after use. - * @return A freshly g_alloc()ed string containing the group, - * or "UNKNOWN" on failure. - */ -extern gchar *get_cur_groupname(void); - -#ifdef _WIN32 -/** - * Check to see if npf.sys is running. - * @return TRUE if npf.sys is running, FALSE if it's not or if there was - * an error checking its status. - */ -extern gboolean npf_sys_is_running(); -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/proto.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/proto.h deleted file mode 100644 index f20845fb..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/proto.h +++ /dev/null @@ -1,1655 +0,0 @@ -/* proto.h - * Definitions for protocol display - * - * $Id: proto.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - - -/*! @file proto.h - The protocol tree related functions.
- A protocol tree will hold all necessary data to display the whole dissected packet. - Creating a protocol tree is done in a two stage process: - A static part at program startup, and a dynamic part when the dissection with the real packet data is done.
- The "static" information is provided by creating a hf_register_info hf[] array, and register it using the - proto_register_field_array() function. This is usually done at dissector registering.
- The "dynamic" information is added to the protocol tree by calling one of the proto_tree_add_...() functions, - e.g. proto_tree_add_bytes(). -*/ - -#ifndef __PROTO_H__ -#define __PROTO_H__ - -#ifdef HAVE_STDARG_H -# include -#else -# include -#endif - -#include - -#include "gnuc_format_check.h" -#include "ipv4.h" -#include "nstime.h" -#include "tvbuff.h" -#include "ftypes/ftypes.h" -#include "register.h" - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/** The header-field index for the special text pseudo-field. Exported by libwireshark.dll */ -WS_VAR_IMPORT int hf_text_only; - -/** the maximum length of a protocol field string representation */ -#define ITEM_LABEL_LENGTH 240 - -struct _value_string; - -/** Make a const value_string[] look like a _value_string pointer, used to set header_field_info.strings */ -#define VALS(x) (const struct _value_string*)(x) - -/** Make a const true_false_string[] look like a _true_false_string pointer, used to set header_field_info.strings */ -#define TFS(x) (const struct true_false_string*)(x) - -/** Make a const range_string[] look like a _range_string pointer, used to set - * header_field_info.strings */ -#define RVALS(x) (const struct _range_string*)(x) - -struct _protocol; - -/** Structure for information about a protocol */ -typedef struct _protocol protocol_t; - -/** check protocol activation - * @todo this macro looks like a hack */ -#define CHECK_DISPLAY_AS_X(x_handle,index, tvb, pinfo, tree) { \ - if (!proto_is_protocol_enabled(find_protocol_by_id(index))) { \ - call_dissector(x_handle,tvb, pinfo, tree); \ - return; \ - } \ - } - -/** Macro used for reporting errors in dissectors; it throws a - * DissectorError exception, with the string passed as an argument - * as the message for the exception, so that it can show up in - * the Info column and the protocol tree. - * - * If that string is dynamically allocated, it should be allocated with - * ep_alloc(); using ep_strdup_printf() would work. - * - * If the WIRESHARK_ABORT_ON_DISSECTOR_BUG environment variable is set, - * it will call abort(), instead, to make it easier to get a stack trace. - * - * @param message string to use as the message - */ -#define REPORT_DISSECTOR_BUG(message) \ - ((getenv("WIRESHARK_ABORT_ON_DISSECTOR_BUG") != NULL) ? \ - abort() : \ - THROW_MESSAGE(DissectorError, message)) - -/** Macro used for assertions in dissectors; it doesn't abort, it just - * throws a DissectorError exception, with the assertion failure - * message as a parameter, so that it can show up in the protocol tree. - * - * @param expression expression to test in the assertion - */ -#define DISSECTOR_ASSERT(expression) \ - ((void) ((expression) ? (void)0 : \ - __DISSECTOR_ASSERT (expression, __FILE__, __LINE__))) - -#if 0 -/* win32: using a debug breakpoint (int 3) can be very handy while debugging, - * as the assert handling of GTK/GLib is currently not very helpful */ -#define DISSECTOR_ASSERT(expression) \ -{ if(!(expression)) _asm { int 3}; } -#endif - -/** Same as DISSECTOR_ASSERT(), but will throw DissectorError exception - * unconditionally, much like GLIB's g_assert_not_reached works. - */ -#define DISSECTOR_ASSERT_NOT_REACHED() \ - (REPORT_DISSECTOR_BUG( \ - ep_strdup_printf("%s:%u: failed assertion \"DISSECTOR_ASSERT_NOT_REACHED\"", \ - __FILE__, __LINE__))) - -#define __DISSECTOR_ASSERT_STRINGIFY(s) # s - -#define __DISSECTOR_ASSERT(expression, file, lineno) \ - (REPORT_DISSECTOR_BUG( \ - ep_strdup_printf("%s:%u: failed assertion \"%s\"", \ - file, lineno, __DISSECTOR_ASSERT_STRINGIFY(expression)))) - -/* BASE_STRUCTURE_RESET constant is used in proto.c to reset the bits - * identifying special structures used in translation of value for display. - * Its value means that we may have at most 16 base_display_e values */ -#define BASE_STRUCTURE_RESET 0x0F -/* Following constants have to be ORed with a base_display_e when dissector - * want to use specials MACROs (for the moment, only RVALS) for a - * header_field_info */ -#define BASE_RANGE_STRING 0x10 -/** radix for decimal values, used in header_field_info.display */ -typedef enum { - BASE_NONE, /**< none */ - BASE_DEC, /**< decimal */ - BASE_HEX, /**< hexadecimal */ - BASE_OCT, /**< octal */ - BASE_DEC_HEX, /**< decimal (hexadecimal) */ - BASE_HEX_DEC /**< hexadecimal (decimal) */ -} base_display_e; - -#define IS_BASE_DUAL(b) ((b)==BASE_DEC_HEX||(b)==BASE_HEX_DEC) - -/** information describing a header field */ -typedef struct _header_field_info header_field_info; - -/** information describing a header field */ -struct _header_field_info { - /* ---------- set by dissector --------- */ - const char *name; /**< full name of this field */ - const char *abbrev; /**< abbreviated name of this field */ - enum ftenum type; /**< field type, one of FT_ (from ftypes.h) */ - int display; /**< one of BASE_, or number of field bits for FT_BOOLEAN */ - const void *strings; /**< value_string, range_string or true_false_string, - typically converted by VALS(), RVALS() or TFS(). - If this is an FT_PROTOCOL then it points to the - associated protocol_t structure */ - guint32 bitmask; /**< bitmask of interesting bits */ - const char *blurb; /**< Brief description of field */ - - /* ------- set by proto routines (prefilled by HFILL macro, see below) ------ */ - int id; /**< Field ID */ - int parent; /**< parent protocol tree */ - int ref_count; /**< is this field referenced by a filter and how often */ - int bitshift; /**< bits to shift */ - header_field_info *same_name_next; /**< Link to next hfinfo with same abbrev */ - header_field_info *same_name_prev; /**< Link to previous hfinfo with same abbrev */ -}; - -/** - * HFILL initializes all the "set by proto routines" fields in a - * _header_field_info. If new fields are added or removed, it should - * be changed as necessary. - */ -#define HFILL 0, 0, 0, 0, NULL, NULL - -/** Used when registering many fields at once, using proto_register_field_array() */ -typedef struct hf_register_info { - int *p_id; /**< written to by register() function */ - header_field_info hfinfo; /**< the field info to be registered */ -} hf_register_info; - - - - -/** string representation, if one of the proto_tree_add_..._format() functions used */ -typedef struct _item_label_t { - char representation[ITEM_LABEL_LENGTH]; -} item_label_t; - - -/** Contains the field information for the proto_item. */ -typedef struct field_info { - header_field_info *hfinfo; /**< pointer to registered field information */ - gint start; /**< current start of data in field_info.ds_tvb */ - gint length; /**< current data length of item in field_info.ds_tvb */ - gint appendix_start; /**< start of appendix data */ - gint appendix_length; /**< length of appendix data */ - gint tree_type; /**< one of ETT_ or -1 */ - item_label_t *rep; /**< string for GUI tree */ - guint32 flags; /**< bitfield like FI_GENERATED, ... */ - tvbuff_t *ds_tvb; /**< data source tvbuff */ - fvalue_t value; -} field_info; - - -/* - * Flag fields. Do not assign values greater than 0x00000080 unless you - * shuffle the expert information upward; see below. - */ - -/** The protocol field should not be shown in the tree (it's used for filtering only), - * used in field_info.flags. */ -/* HIDING PROTOCOL FIELDS IS DEPRECATED, IT'S CONSIDERED TO BE BAD GUI DESIGN! */ -#define FI_HIDDEN 0x00000001 -/** The protocol field should be displayed as "generated by Wireshark", - * used in field_info.flags. */ -#define FI_GENERATED 0x00000002 -/** The protocol field is actually a URL */ -#define FI_URL 0x00000004 - - -/** convenience macro to get field_info.flags */ -#define FI_GET_FLAG(fi, flag) (fi->flags & flag) -/** convenience macro to set field_info.flags */ -#define FI_SET_FLAG(fi, flag) (fi->flags = fi->flags | flag) - -/** One of these exists for the entire protocol tree. Each proto_node - * in the protocol tree points to the same copy. */ -typedef struct { - GHashTable *interesting_hfids; - gboolean visible; - gint count; -} tree_data_t; - -/** Each proto_tree, proto_item is one of these. */ -typedef struct _proto_node { - struct _proto_node *first_child; - struct _proto_node *last_child; - struct _proto_node *next; - struct _proto_node *parent; - field_info *finfo; - tree_data_t *tree_data; -} proto_node; - -/** A protocol tree element. */ -typedef proto_node proto_tree; -/** A protocol item element. */ -typedef proto_node proto_item; - -/* - * Expert information. - * This is in the flags field; we allocate this from the top down, - * so as not to collide with FI_ flags, which are allocated from - * the bottom up. - */ - -/* expert severities */ -#define PI_SEVERITY_MASK 0x00000E00 /* mask usually for internal use only! */ -/** Usual workflow, e.g. TCP connection establishing */ -#define PI_CHAT 0x00000200 -/** Notable messages, e.g. an application returned an "usual" error code like HTTP 404 */ -#define PI_NOTE 0x00000400 -/** Warning, e.g. application returned an "unusual" error code */ -#define PI_WARN 0x00000600 -/** Serious problems, e.g. [Malformed Packet] */ -#define PI_ERROR 0x00000800 - -/* expert "event groups" */ -#define PI_GROUP_MASK 0xFFFFF000 /* mask usually for internal use only! */ -/** The protocol field has a bad checksum, usually PI_WARN */ -#define PI_CHECKSUM 0x00001000 -/** The protocol field indicates a sequence problem (e.g. TCP window is zero) */ -#define PI_SEQUENCE 0x00002000 -/** The protocol field indicates a bad application response code (e.g. HTTP 404), usually PI_NOTE */ -#define PI_RESPONSE_CODE 0x00004000 -/** The protocol field indicates an application request (e.g. File Handle == xxxx), usually PI_CHAT */ -#define PI_REQUEST_CODE 0x00005000 -/** The data is undecoded, the protocol dissection is incomplete here, usually PI_WARN */ -#define PI_UNDECODED 0x00008000 -/** The protocol field indicates a reassemble (e.g. DCE/RPC defragmentation), usually PI_CHAT (or PI_ERROR) */ -#define PI_REASSEMBLE 0x00010000 -/** The packet data is malformed, the dissector has "given up", usually PI_ERROR */ -#define PI_MALFORMED 0x00020000 -/** A generic debugging message (shouldn't remain in production code!), usually PI_ERROR */ -#define PI_DEBUG 0x00040000 -/* The protocol field indicates a security probem (e.g. unsecure implementation) */ -/*#define PI_SECURITY 0x00080000*/ - -/* add more, see http://wiki.wireshark.org/Development/ExpertInfo */ - - -/** is this protocol field hidden from the protocol tree display (used for filtering only)? */ -/* HIDING PROTOCOL FIELDS IS DEPRECATED, IT'S CONSIDERED TO BE BAD GUI DESIGN! */ -#define PROTO_ITEM_IS_HIDDEN(proto_item) \ - ((proto_item) ? FI_GET_FLAG((proto_item)->finfo, FI_HIDDEN) : 0) -/** mark this protocol field to be hidden from the protocol tree display (used for filtering only) */ -/* HIDING PROTOCOL FIELDS IS DEPRECATED, IT'S CONSIDERED TO BE BAD GUI DESIGN! */ -#define PROTO_ITEM_SET_HIDDEN(proto_item) \ - ((proto_item) ? FI_SET_FLAG((proto_item)->finfo, FI_HIDDEN) : 0) -/** is this protocol field generated by Wireshark (and not read from the packet data)? */ -#define PROTO_ITEM_IS_GENERATED(proto_item) \ - ((proto_item) ? FI_GET_FLAG((proto_item)->finfo, FI_GENERATED) : 0) -/** mark this protocol field as generated by Wireshark (and not read from the packet data) */ -#define PROTO_ITEM_SET_GENERATED(proto_item) \ - ((proto_item) ? FI_SET_FLAG((proto_item)->finfo, FI_GENERATED) : 0) -/** is this protocol field actually a URL? */ -#define PROTO_ITEM_IS_URL(proto_item) \ - ((proto_item) ? FI_GET_FLAG((proto_item)->finfo, FI_URL) : 0) -/** mark this protocol field as a URL */ -#define PROTO_ITEM_SET_URL(proto_item) \ - ((proto_item) ? FI_SET_FLAG((proto_item)->finfo, FI_URL) : 0) - -typedef void (*proto_tree_foreach_func)(proto_node *, gpointer); -typedef gboolean (*proto_tree_traverse_func)(proto_node *, gpointer); - -extern gboolean proto_tree_traverse_in_order(proto_tree *tree, - proto_tree_traverse_func func, gpointer data); -extern void proto_tree_children_foreach(proto_tree *tree, - proto_tree_foreach_func func, gpointer data); - -/** Retrieve the field_info from a proto_item */ -#define PITEM_FINFO(proto_item) ((proto_item)->finfo) - -/** Retrieve the tree_data_t from a proto_tree */ -#define PTREE_DATA(proto_tree) ((proto_tree)->tree_data) - -/** Sets up memory used by proto routines. Called at program startup */ -extern void proto_init(void (register_all_protocols)(register_cb cb, gpointer client_data), - void (register_all_handoffs)(register_cb cb, gpointer client_data), - register_cb cb, void *client_data); - - -/** Frees memory used by proto routines. Called at program shutdown */ -extern void proto_cleanup(void); - -/** This function takes a tree and a protocol id as parameter and - will return TRUE/FALSE for whether the protocol or any of the filterable - fields in the protocol is referenced by any fitlers. - If this function returns FALSE then it is safe to skip any - proto_tree_add_...() calls and just treat the call as if the - dissector was called with tree==NULL. - If you reset the tree to NULL by this dissector returning FALSE, - you will still need to call any subdissector with the original value of - tree or filtering will break. - - The purpose of this is to optimize wireshark for speed and make it - faster for when filters are being used. -*/ -extern gboolean proto_field_is_referenced(proto_tree *tree, int proto_id); - - - -/** Create a subtree under an existing item. - @param ti the parent item of the new subtree - @param idx one of the ett_ array elements registered with proto_register_subtree_array() - @return the new subtree */ -extern proto_tree* proto_item_add_subtree(proto_item *ti, gint idx); - -/** Get an existing subtree under an item. - @param ti the parent item of the subtree - @return the subtree or NULL */ -extern proto_tree* proto_item_get_subtree(proto_item *ti); - -/** Get the parent of a subtree item. - @param ti the child item in the subtree - @return parent item or NULL */ -extern proto_item* proto_item_get_parent(proto_item *ti); - -/** Get Nth generation parent item. - @param ti the child item in the subtree - @param gen the generation to get (using 1 here is the same as using proto_item_get_parent()) - @return parent item */ -extern proto_item* proto_item_get_parent_nth(proto_item *ti, int gen); - -/** Replace text of item after it already has been created. - @param ti the item to set the text - @param format printf like format string - @param ... printf like parameters */ -extern void proto_item_set_text(proto_item *ti, const char *format, ...) - GNUC_FORMAT_CHECK(printf, 2,3); - -/** Append to text of item after it has already been created. - @param ti the item to append the text to - @param format printf like format string - @param ... printf like parameters */ -extern void proto_item_append_text(proto_item *ti, const char *format, ...) - GNUC_FORMAT_CHECK(printf, 2,3); - -/** Set proto_item's length inside tvb, after it has already been created. - @param ti the item to set the length - @param length the new length ot the item */ -extern void proto_item_set_len(proto_item *ti, gint length); - -/** - * Sets the length of the item based on its start and on the specified - * offset, which is the offset past the end of the item; as the start - * in the item is relative to the beginning of the data source tvbuff, - * we need to pass in a tvbuff. - @param ti the item to set the length - @param tvb end is relative to this tvbuff - @param end this end offset is relative to the beginning of tvb - @todo make usage clearer, I don't understand it! - */ -extern void proto_item_set_end(proto_item *ti, tvbuff_t *tvb, gint end); - -/** Get length of a proto_item. Useful after using proto_tree_add_item() - * to add a variable-length field (e.g., FT_NSTRING_UINT8). - @param ti the item to get the length from - @return the current length */ -extern int proto_item_get_len(proto_item *ti); - -/** - * Sets an expert info to the proto_item. - @param ti the item to set the expert info - @param group the group of this info (e.g. PI_CHECKSUM) - @param severity of this info (e.g. PI_ERROR) - @return TRUE if value was written - */ -extern gboolean proto_item_set_expert_flags(proto_item *ti, int group, guint severity); - - - - -/** Creates a new proto_tree root. - @return the new tree root */ -extern proto_tree* proto_tree_create_root(void); - -/** Clear memory for entry proto_tree. Clears proto_tree struct also. - @param tree the tree to free */ -extern void proto_tree_free(proto_tree *tree); - -/** Set the tree visible or invisible. - Is the parsing being done for a visible proto_tree or an invisible one? - By setting this correctly, the proto_tree creation is sped up by not - having to call g_vsnprintf and copy strings around. - @param tree the tree to be set - @param visible ... or not */ -extern void -proto_tree_set_visible(proto_tree *tree, gboolean visible); - -/** Mark a field/protocol ID as "interesting". - @param tree the tree to be set - @param hfid the interesting field id - @todo what *does* interesting mean? */ -extern void -proto_tree_prime_hfid(proto_tree *tree, int hfid); - -/** Get a parent item of a subtree. - @param tree the tree to get the parent from - @return parent item */ -extern proto_item* proto_tree_get_parent(proto_tree *tree); - -/** Get the root tree from any subtree. - @param tree the tree to get the root from - @return root tree */ -extern proto_tree* proto_tree_get_root(proto_tree *tree); - -/** Move an existing item behind another existing item. - @param tree the tree to which both items belong - @param fixed_item the item which keeps it's position - @param item_to_move the item which will be moved */ -extern void proto_tree_move_item(proto_tree *tree, proto_item *fixed_item, proto_item *item_to_move); - - -/** Set start and length of an appendix for a proto_tree. - @param tree the tree to set the appendix start and length - @param tvb the tv buffer of the current data - @param start the start offset of the appendix - @param length the length of the appendix */ -extern void proto_tree_set_appendix(proto_tree *tree, tvbuff_t *tvb, gint start, gint length); - - -/** Add an item to a proto_tree, using the text label registered to that item. - The item is extracted from the tvbuff handed to it. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param little_endian big or little endian byte representation - @return the newly created item */ -extern proto_item * -proto_tree_add_item(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, gboolean little_endian); - -/** Add a hidden item to a proto_tree. - @deprecated use proto_tree_add_item() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ -extern proto_item * -proto_tree_add_item_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, gboolean little_endian); - -/** Add a text-only node to a proto_tree. - @param tree the tree to append this item to - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_text(proto_tree *tree, tvbuff_t *tvb, gint start, gint length, const char *format, - ...) GNUC_FORMAT_CHECK(printf,5,6); - -/** Add a text-only node to a proto_tree using a variable argument list. - @param tree the tree to append this item to - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param format printf like format string - @param ap variable argument list - @return the newly created item */ -extern proto_item * -proto_tree_add_text_valist(proto_tree *tree, tvbuff_t *tvb, gint start, - gint length, const char *format, va_list ap); - - -/** Add a FT_NONE field to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_none_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const char *format, ...) GNUC_FORMAT_CHECK(printf,6,7); - -/** Add a FT_PROTOCOL to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_protocol_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const char *format, ...) GNUC_FORMAT_CHECK(printf,6,7); - - - - -/** Add a FT_BYTES to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param start_ptr pointer to the data to display - @return the newly created item */ -extern proto_item * -proto_tree_add_bytes(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const guint8* start_ptr); - -/** Add a hidden FT_BYTES to a proto_tree. - @deprecated use proto_tree_add_bytes() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ -extern proto_item * -proto_tree_add_bytes_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const guint8* start_ptr); - -/** Add a formatted FT_BYTES to a proto_tree, with the format generating - the string for the value and with the field name being included - automatically. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param start_ptr pointer to the data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_bytes_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, const guint8* start_ptr, const char *format, - ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a formatted FT_BYTES to a proto_tree, with the format generating - the entire string for the entry, including any field name. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param start_ptr pointer to the data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_bytes_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const guint8* start_ptr, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a FT_ABSOLUTE_TIME or FT_RELATIVE_TIME to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value_ptr pointer to the data to display - @return the newly created item */ -extern proto_item * -proto_tree_add_time(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, nstime_t* value_ptr); - -/** Add a hidden FT_ABSOLUTE_TIME or FT_RELATIVE_TIME to a proto_tree. - @deprecated use proto_tree_add_time() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ -extern proto_item * -proto_tree_add_time_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, nstime_t* value_ptr); - -/** Add a formatted FT_ABSOLUTE_TIME or FT_RELATIVE_TIME to a proto_tree, with - the format generating the string for the value and with the field name - being included automatically. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value_ptr pointer to the data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_time_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, nstime_t* value_ptr, const char *format, ...) - GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a formatted FT_ABSOLUTE_TIME or FT_RELATIVE_TIME to a proto_tree, with - the format generating the entire string for the entry, including any field - name. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value_ptr pointer to the data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_time_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, nstime_t* value_ptr, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a FT_IPXNET to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @return the newly created item */ -extern proto_item * -proto_tree_add_ipxnet(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, guint32 value); - -/** Add a hidden FT_IPXNET to a proto_tree. - @deprecated use proto_tree_add_ipxnet() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ -extern proto_item * -proto_tree_add_ipxnet_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, guint32 value); - -/** Add a formatted FT_IPXNET to a proto_tree, with the format generating - the string for the value and with the field name being included - automatically. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_ipxnet_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, guint32 value, const char *format, ...) - GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a formatted FT_IPXNET to a proto_tree, with the format generating - the entire string for the entry, including any field name. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_ipxnet_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, guint32 value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a FT_IPv4 to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @return the newly created item */ -extern proto_item * -proto_tree_add_ipv4(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, guint32 value); - -/** Add a hidden FT_IPv4 to a proto_tree. - @deprecated use proto_tree_add_ipv4() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ -extern proto_item * -proto_tree_add_ipv4_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, guint32 value); - -/** Add a formatted FT_IPv4 to a proto_tree, with the format generating - the string for the value and with the field name being included - automatically. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_ipv4_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, guint32 value, const char *format, ...) - GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a formatted FT_IPv4 to a proto_tree, with the format generating - the entire string for the entry, including any field name. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_ipv4_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, guint32 value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a FT_IPv6 to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value_ptr data to display - @return the newly created item */ -extern proto_item * -proto_tree_add_ipv6(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const guint8* value_ptr); - -/** Add a hidden FT_IPv6 to a proto_tree. - @deprecated use proto_tree_add_ipv6() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ -extern proto_item * -proto_tree_add_ipv6_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const guint8* value_ptr); - -/** Add a formatted FT_IPv6 to a proto_tree, with the format generating - the string for the value and with the field name being included - automatically. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value_ptr data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_ipv6_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, const guint8* value_ptr, const char *format, - ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a formatted FT_IPv6 to a proto_tree, with the format generating - the entire string for the entry, including any field name. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value_ptr data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_ipv6_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const guint8* value_ptr, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a FT_ETHER to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @return the newly created item */ -extern proto_item * -proto_tree_add_ether(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const guint8* value); - -/** Add a hidden FT_ETHER to a proto_tree. - @deprecated use proto_tree_add_ether() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ -extern proto_item * -proto_tree_add_ether_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const guint8* value); - -/** Add a formatted FT_ETHER to a proto_tree, with the format generating - the string for the value and with the field name being included - automatically. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_ether_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, const guint8* value, const char *format, ...) - GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a formatted FT_ETHER to a proto_tree, with the format generating - the entire string for the entry, including any field name. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_ether_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const guint8* value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a FT_GUID to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value_ptr data to display - @return the newly created item */ -extern proto_item * -proto_tree_add_guid(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const e_guid_t *value_ptr); - -/** Add a hidden FT_GUID to a proto_tree. - @deprecated use proto_tree_add_guid() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ -extern proto_item * -proto_tree_add_guid_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const e_guid_t *value_ptr); - -/** Add a formatted FT_GUID to a proto_tree, with the format generating - the string for the value and with the field name being included - automatically. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value_ptr data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_guid_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, const e_guid_t *value_ptr, const char *format, - ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a formatted FT_GUID to a proto_tree, with the format generating - the entire string for the entry, including any field name. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value_ptr data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_guid_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const e_guid_t *value_ptr, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a FT_OID to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value_ptr data to display - @return the newly created item */ -extern proto_item * -proto_tree_add_oid(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const guint8* value_ptr); - -/** Add a hidden FT_OID to a proto_tree. - @deprecated use proto_tree_add_oid() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ -extern proto_item * -proto_tree_add_oid_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const guint8* value_ptr); - -/** Add a formatted FT_OID to a proto_tree, with the format generating - the string for the value and with the field name being included - automatically. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value_ptr data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_oid_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, const guint8* value_ptr, const char *format, - ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a formatted FT_OID to a proto_tree, with the format generating - the entire string for the entry, including any field name. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value_ptr data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_oid_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const guint8* value_ptr, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a FT_STRING to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @return the newly created item */ -extern proto_item * -proto_tree_add_string(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const char* value); - -/** Add a hidden FT_STRING to a proto_tree. - @deprecated use proto_tree_add_string() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ -extern proto_item * -proto_tree_add_string_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const char* value); - -/** Add a formatted FT_STRING to a proto_tree, with the format generating - the string for the value and with the field name being included - automatically. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_string_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, const char* value, const char *format, ...) - GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a formatted FT_STRING to a proto_tree, with the format generating - the entire string for the entry, including any field name. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_string_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const char* value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a FT_BOOLEAN to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @return the newly created item */ -extern proto_item * -proto_tree_add_boolean(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, guint32 value); - -/** Add a hidden FT_BOOLEAN to a proto_tree. - @deprecated use proto_tree_add_boolean() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ -extern proto_item * -proto_tree_add_boolean_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, guint32 value); - -/** Add a formatted FT_BOOLEAN to a proto_tree, with the format generating - the string for the value and with the field name being included - automatically. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_boolean_format_value(proto_tree *tree, int hfindex, - tvbuff_t *tvb, gint start, gint length, guint32 value, - const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a formatted FT_BOOLEAN to a proto_tree, with the format generating - the entire string for the entry, including any field name. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_boolean_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, guint32 value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a FT_FLOAT to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @return the newly created item */ -extern proto_item * -proto_tree_add_float(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, float value); - -/** Add a hidden FT_FLOAT to a proto_tree. - @deprecated use proto_tree_add_float() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ -extern proto_item * -proto_tree_add_float_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, float value); - -/** Add a formatted FT_FLOAT to a proto_tree, with the format generating - the string for the value and with the field name being included - automatically. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_float_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, float value, const char *format, ...) - GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a formatted FT_FLOAT to a proto_tree, with the format generating - the entire string for the entry, including any field name. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_float_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, float value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a FT_DOUBLE to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @return the newly created item */ -extern proto_item * -proto_tree_add_double(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, double value); - -/** Add a hidden FT_DOUBLE to a proto_tree. - @deprecated use proto_tree_add_double() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ -extern proto_item * -proto_tree_add_double_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, double value); - -/** Add a formatted FT_DOUBLE to a proto_tree, with the format generating - the string for the value and with the field name being included - automatically. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_double_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, double value, const char *format, ...) - GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a formatted FT_DOUBLE to a proto_tree, with the format generating - the entire string for the entry, including any field name. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_double_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, double value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add one of FT_UINT8, FT_UINT16, FT_UINT24 or FT_UINT32 to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @return the newly created item */ -extern proto_item * -proto_tree_add_uint(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, guint32 value); - -/** Add a hidden FT_UINT8, FT_UINT16, FT_UINT24 or FT_UINT32 to a proto_tree. - @deprecated use proto_tree_add_uint() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ -extern proto_item * -proto_tree_add_uint_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, guint32 value); - -/** Add a formatted FT_UINT8, FT_UINT16, FT_UINT24 or FT_UINT32 to a proto_tree, - with the format generating the string for the value and with the field - name being included automatically. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_uint_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, guint32 value, const char *format, ...) - GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a formatted FT_UINT8, FT_UINT16, FT_UINT24 or FT_UINT32 to a proto_tree, - with the format generating the entire string for the entry, including any - field name. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_uint_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, guint32 value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add an FT_UINT64 to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @return the newly created item */ -extern proto_item * -proto_tree_add_uint64(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, guint64 value); - -/** Add a formatted FT_UINT64 to a proto_tree, with the format generating - the string for the value and with the field name being included - automatically. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_uint64_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, guint64 value, const char *format, ...) - GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a formatted FT_UINT64 to a proto_tree, with the format generating - the entire string for the entry, including any field name. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_uint64_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, guint64 value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add one of FT_INT8, FT_INT16, FT_INT24 or FT_INT32 to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @return the newly created item */ -extern proto_item * -proto_tree_add_int(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, gint32 value); - -/** Add a hidden FT_INT8, FT_INT16, FT_INT24 or FT_INT32 to a proto_tree. - @deprecated use proto_tree_add_int() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ -extern proto_item * -proto_tree_add_int_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, gint32 value); - -/** Add a formatted FT_INT8, FT_INT16, FT_INT24 or FT_INT32 to a proto_tree, - with the format generating the string for the value and with the field - name being included automatically. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_int_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, gint32 value, const char *format, ...) - GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a formatted FT_INT8, FT_INT16, FT_INT24 or FT_INT32 to a proto_tree, - with the format generating the entire string for the entry, including - any field name. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_int_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, gint32 value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add an FT_INT64 to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @return the newly created item */ -extern proto_item * -proto_tree_add_int64(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, gint64 value); - -/** Add a formatted FT_INT64 to a proto_tree, with the format generating - the string for the value and with the field name being included - automatically. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_int64_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, gint64 value, const char *format, ...) - GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a formatted FT_INT64 to a proto_tree, with the format generating - the entire string for the entry, including any field name. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_int64_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, gint64 value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Useful for quick debugging. Also sends string to STDOUT, so don't - leave call to this function in production code. - @param tree the tree to append the text to - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_debug_text(proto_tree *tree, const char *format, - ...) GNUC_FORMAT_CHECK(printf,2,3); - - - -/** Append a string to a protocol item.
- NOTE: this function will break with the TRY_TO_FAKE_THIS_ITEM() - speed optimization. - Currently only WSP use this function so it is not that bad but try to - avoid using this one if possible. - IF you must use this function you MUST also disable the - TRY_TO_FAKE_THIS_ITEM() optimization for your dissector/function - using proto_item_append_string(). - Do that by faking that the tree is visible by calling - proto_tree_set_visible(tree, TRUE) (see packet-wsp.c) - BEFORE you create the item you are later going to use - proto_item_append_string() on. - @param pi the item to append the string to - @param str the string to append */ -extern void -proto_item_append_string(proto_item *pi, const char *str); - - - -/** Fill given label_str with string representation of field - @param fi the item to get the info from - @param label_str the string to fill - @todo think about changing the parameter profile */ -extern void -proto_item_fill_label(field_info *fi, gchar *label_str); - - -/** Register a new protocol. - @param name the full name of the new protocol - @param short_name abbreviated name of the new protocol - @param filter_name protocol name used for a display filter string - @return the new protocol handle */ -extern int -proto_register_protocol(const char *name, const char *short_name, const char *filter_name); - -/** Register a header_field array. - @param parent the protocol handle from proto_register_protocol() - @param hf the hf_register_info array - @param num_records the number of records in hf */ -extern void -proto_register_field_array(int parent, hf_register_info *hf, int num_records); - -/** Register a protocol subtree (ett) array. - @param indices array of ett indices - @param num_indices the number of records in indices */ -extern void -proto_register_subtree_array(gint *const *indices, int num_indices); - -/** Returns number of items (protocols or header fields) registered. - @return the number of items */ -extern int proto_registrar_n(void); - -/** Get name of registered header_field number n. - @param n item # n (0-indexed) - @return the name of this registered item */ -extern const char* proto_registrar_get_name(int n); - -/** Get abbreviation of registered header_field number n. - @param n item # n (0-indexed) - @return the abbreviation of this registered item */ -extern const char* proto_registrar_get_abbrev(int n); - -/** Get the header_field information based upon a field or protocol id. - @param hfindex item # n (0-indexed) - @return the registered item */ -extern header_field_info* proto_registrar_get_nth(guint hfindex); - -/** Get the header_field information based upon a field name. - @param field_name the field name to search for - @return the registered item */ -extern header_field_info* proto_registrar_get_byname(const char *field_name); - -/** Get enum ftenum FT_ of registered header_field number n. - @param n item # n (0-indexed) - @return the registered item */ -extern int proto_registrar_get_ftype(int n); - -/** Get parent protocol of registered header_field number n. - @param n item # n (0-indexed) - @return -1 if item _is_ a protocol */ -extern int proto_registrar_get_parent(int n); - -/** Is item # n a protocol? - @param n item # n (0-indexed) - @return TRUE if it's a protocol, FALSE if it's not */ -extern gboolean proto_registrar_is_protocol(int n); - -/** Get length of registered field according to field type. - @param n item # n (0-indexed) - @return 0 means undeterminable at registration time, -1 means unknown field */ -extern gint proto_registrar_get_length(int n); - - -/** Routines to use to iterate over the protocols and their fields; - * they return the item number of the protocol in question or the - * appropriate hfinfo pointer, and keep state in "*cookie". */ -extern int proto_get_first_protocol(void **cookie); -extern int proto_get_next_protocol(void **cookie); -extern header_field_info *proto_get_first_protocol_field(int proto_id, void **cookle); -extern header_field_info *proto_get_next_protocol_field(void **cookle); - -/** Given a protocol's filter_name. - @param filter_name the filter name to search for - @return proto_id */ -extern int proto_get_id_by_filter_name(const gchar* filter_name); - -/** Can item # n decoding be disabled? - @param proto_id protocol id (0-indexed) - @return TRUE if it's a protocol, FALSE if it's not */ -extern gboolean proto_can_toggle_protocol(int proto_id); - -/** Get the "protocol_t" structure for the given protocol's item number. - @param proto_id protocol id (0-indexed) */ -extern protocol_t *find_protocol_by_id(int proto_id); - -/** Get the protocol's name for the given protocol's item number. - @param proto_id protocol id (0-indexed) - @return its name */ -extern const char *proto_get_protocol_name(int proto_id); - -/** Get the protocol's item number, for the given protocol's "protocol_t". - @return its proto_id */ -extern int proto_get_id(protocol_t *protocol); - -/** Get the protocol's short name, for the given protocol's "protocol_t". - @return its short name. */ -extern const char *proto_get_protocol_short_name(protocol_t *protocol); - -/** Is protocol's decoding enabled ? - @param protocol - @return TRUE if decoding is enabled, FALSE if not */ -extern gboolean proto_is_protocol_enabled(protocol_t *protocol); - -/** Get a protocol's filter name by it's item number. - @param proto_id protocol id (0-indexed) - @return its filter name. */ -extern const char *proto_get_protocol_filter_name(int proto_id); - -/** Enable / Disable protocol of the given item number. - @param proto_id protocol id (0-indexed) - @param enabled enable / disable the protocol */ -extern void proto_set_decoding(int proto_id, gboolean enabled); - -/** Enable all protocols */ -extern void proto_enable_all(void); - -/** Disable disabling/enabling of protocol of the given item number. - @param proto_id protocol id (0-indexed) */ -extern void proto_set_cant_toggle(int proto_id); - -/** Checks for existence any protocol or field within a tree. - @param tree "Protocols" are assumed to be a child of the [empty] root node. - @param id hfindex of protocol or field - @return TRUE = found, FALSE = not found - @todo add explanation of id parameter */ -extern gboolean proto_check_for_protocol_or_field(proto_tree* tree, int id); - -/** Return GPtrArray* of field_info pointers for all hfindex that appear in - tree. Only works with primed trees, and is fast. - @param tree tree of interest - @param hfindex primed hfindex - @return GPtrArry pointer */ -extern GPtrArray* proto_get_finfo_ptr_array(proto_tree *tree, int hfindex); - -/** Return GPtrArray* of field_info pointers for all hfindex that appear in - tree. Works with any tree, primed or unprimed, and is slower than - proto_get_finfo_ptr_array because it has to search through the tree. - @param tree tree of interest - @param hfidex index of field info of interest - @return GPtrArry pointer */ -extern GPtrArray* proto_find_finfo(proto_tree *tree, int hfindex); - -/** Return GPtrArray* of field_info pointers containg all hfindexes that appear - in tree. - @param tree tree of interest - @return GPtrArry pointer */ -extern GPtrArray* proto_all_finfos(proto_tree *tree); - -/** Dumps a glossary of the protocol registrations to STDOUT */ -extern void proto_registrar_dump_protocols(void); - -/** Dumps a glossary of the field value strings or true/false strings to STDOUT */ -extern void proto_registrar_dump_values(void); - -/** Dumps a glossary of the protocol and field registrations to STDOUT. - * Format 1 is the original format. Format 2 includes the base (for integers) - * and the blurb. */ -extern void proto_registrar_dump_fields(int format); - - - -/** Points to the first element of an array of Booleans, indexed by - a subtree item type. That array element is TRUE if subtrees of - an item of that type are to be expanded. With MSVC and a - libwireshark.dll, we need a special declaration. */ -WS_VAR_IMPORT gboolean *tree_is_expanded; - -/** Number of elements in the tree_is_expanded array. With MSVC and a - * libwireshark.dll, we need a special declaration. */ -WS_VAR_IMPORT int num_tree_types; - -/** glib doesn't have g_ptr_array_len of all things!*/ -#ifndef g_ptr_array_len -#define g_ptr_array_len(a) ((a)->len) -#endif - -/** Get number of bits of a header_field. - @param hfinfo header_field - @return the bitwidth */ -extern int -hfinfo_bitwidth(header_field_info *hfinfo); - - - - -#include "epan.h" - -/** Can we do a "match selected" on this field. - @param finfo field_info - @param edt epan dissecting - @return TRUE if we can do a "match selected" on the field, FALSE otherwise. */ -extern gboolean -proto_can_match_selected(field_info *finfo, epan_dissect_t *edt); - -/** Construct a "match selected" display filter string. - @param finfo field_info - @param edt epan dissecting - @return the display filter string */ -extern char* -proto_construct_match_selected_string(field_info *finfo, epan_dissect_t *edt); - -/** Find field from offset in tvb. - @param tree tree of interest - @param offset offset in the tvb - @param tvb the tv buffer - @return the corresponding field_info */ -extern field_info* -proto_find_field_from_offset(proto_tree *tree, guint offset, tvbuff_t *tvb); - -/** This function will dissect a sequence of bytes that describe a bitmask. - @param tree the tree to append this item to - @param tvb the tv buffer of the current data - @param offset start of data in tvb - @param hf_hdr an 8/16/24/32 bit integer that describes the bitmask to be dissected. - This field will form an expansion under which the individual fields of the - bitmask is dissected and displayed. - This field must be of the type FT_[U]INT{8|16|24|32}. - @param fields an array of pointers to int that lists all the fields of the - bitmask. These fields can be either of the type FT_BOOLEAN for flags - or another integer of the same type/size as hf_hdr with a mask specified. - This array is terminated by a NULL entry. - FT_BOOLEAN bits that are set to 1 will have the name added to the expansion. - FT_integer fields that have a value_string attached will have the - matched string displayed on the expansion line. - @param little_endian big or little endian byte representation - @return the newly created item */ -extern proto_item * -proto_tree_add_bitmask(proto_tree *tree, tvbuff_t *tvb, int offset, int hf_hdr, gint ett, const int **fields, gboolean little_endian); - -/** Add bits to a proto_tree, using the text label registered to that item. - The item is extracted from the tvbuff handed to it. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param bit_offset start of data in tvb expressed in bits - @param no_of_bits length of data in tvb expressed in bits - @param little_endian big or little endian byte representation - @return the newly created item */ -extern proto_item * -proto_tree_add_bits_item(proto_tree *tree, int hf_index, tvbuff_t *tvb, gint bit_offset, gint no_of_bits, gboolean little_endian); - -/** Add bits to a proto_tree, using the text label registered to that item. - The item is extracted from the tvbuff handed to it. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param bit_offset start of data in tvb expressed in bits - @param no_of_bits length of data in tvb expressed in bits - @param return_value if a pointer is passed here the value is returned. - @param little_endian big or little endian byte representation - @return the newly created item */ -extern proto_item * -proto_tree_add_bits_ret_val(proto_tree *tree, int hf_index, tvbuff_t *tvb, gint bit_offset, gint no_of_bits, guint64 *return_value, gboolean little_endian); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* proto.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ptvcursor.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ptvcursor.h deleted file mode 100644 index d94940bf..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ptvcursor.h +++ /dev/null @@ -1,110 +0,0 @@ -/* ptvcursor.h - * - * Proto Tree TVBuff cursor - * Gilbert Ramirez - * - * $Id: ptvcursor.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2000 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __PTVCURSOR_H__ -#define __PTVCURSOR_H__ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#include - -#define SUBTREE_UNDEFINED_LENGTH -1 - -typedef struct ptvcursor ptvcursor_t; - -/* Allocates an initializes a ptvcursor_t with 3 variables: - * proto_tree, tvbuff, and offset. */ -ptvcursor_t* -ptvcursor_new(proto_tree*, tvbuff_t*, gint); - -/* Gets data from tvbuff, adds it to proto_tree, increments offset, - * and returns proto_item* */ -proto_item* -ptvcursor_add(ptvcursor_t*, int hf, gint length, gboolean endianness); - - -/* Gets data from tvbuff, adds it to proto_tree, *DOES NOT* increment - * offset, and returns proto_item* */ -proto_item* -ptvcursor_add_no_advance(ptvcursor_t*, int hf, gint length, gboolean endianness); - -/* Advance the ptvcursor's offset within its tvbuff without - * adding anything to the proto_tree. */ -void -ptvcursor_advance(ptvcursor_t* ptvc, gint length); - -/* Frees memory for ptvcursor_t, but nothing deeper than that. */ -void -ptvcursor_free(ptvcursor_t*); - -/* Returns tvbuff. */ -tvbuff_t* -ptvcursor_tvbuff(ptvcursor_t*); - -/* Returns current offset. */ -gint -ptvcursor_current_offset(ptvcursor_t*); - -/* Returns the proto_tree* */ -proto_tree* -ptvcursor_tree(ptvcursor_t* ptvc); - -/* Sets a new proto_tree* for the ptvcursor_t */ -void -ptvcursor_set_tree(ptvcursor_t* ptvc, proto_tree *tree); - -/* push a subtree in the tree stack of the cursor */ -proto_tree* -ptvcursor_push_subtree(ptvcursor_t *ptvc, proto_item *it, gint ett_subtree); - -/* pop a subtree in the tree stack of the cursor */ -void ptvcursor_pop_subtree(ptvcursor_t *ptvc); - -/* Add an item to the tree and create a subtree - * If the length is unknown, length may be defined as SUBTREE_UNDEFINED_LENGTH. - * In this case, when the subtree will be closed, the parent item length will - * be equal to the advancement of the cursor since the creation of the subtree. - */ -proto_tree* ptvcursor_add_with_subtree(ptvcursor_t * ptvc, int hfindex, gint length, -gboolean little_endian, gint ett_subtree); - -/* Add a text node to the tree and create a subtree - * If the length is unknown, length may be defined as SUBTREE_UNDEFINED_LENGTH. - * In this case, when the subtree will be closed, the item length will be equal - * to the advancement of the cursor since the creation of the subtree. - */ -proto_tree * ptvcursor_add_text_with_subtree(ptvcursor_t * ptvc, gint length, - gint ett_subtree, const char *format, ...); - -/* Creates a subtree and adds it to the cursor as the working tree but does not - * save the old working tree */ -proto_tree* -ptvcursor_set_subtree(ptvcursor_t *ptvc, proto_item *it, gint ett_subtree); - -#endif /* __PTVCURSOR_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/radius_dict_lex.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/radius_dict_lex.h deleted file mode 100644 index 1ddab2be..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/radius_dict_lex.h +++ /dev/null @@ -1,6 +0,0 @@ -/* This is generated by runlex.sh. Do not edit it. */ -#define yylex Radiuslex -#ifndef YY_DECL -#define YY_DECL int yylex(void) -#endif -YY_DECL; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/range.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/range.h deleted file mode 100644 index daf339c5..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/range.h +++ /dev/null @@ -1,73 +0,0 @@ -/* range.h - * Range routines - * - * $Id: range.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Dick Gooris - * Ulf Lamping - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __RANGE_H__ -#define __RANGE_H__ - -#include - -/* XXX where's the best place for these? */ -#define MAX_SCTP_PORT 65535 -#define MAX_TCP_PORT 65535 -#define MAX_UDP_PORT 65535 - -typedef struct range_admin_tag { - guint32 low; - guint32 high; -} range_admin_t; - -typedef struct range { - /* user specified range(s) */ - guint nranges; /* number of entries in ranges */ - range_admin_t ranges[1]; /* variable-length array */ -} range_t; - -/* - * Return value from range_convert_str(). - */ -typedef enum { - CVT_NO_ERROR, - CVT_SYNTAX_ERROR, - CVT_NUMBER_TOO_BIG -} convert_ret_t; - -extern range_t *range_empty(void); - -extern convert_ret_t range_convert_str(range_t **range, const gchar *es, - guint32 max_value); - -extern gboolean value_is_in_range(range_t *range, guint32 val); - -extern gboolean ranges_are_equal(range_t *a, range_t *b); - -extern void range_foreach(range_t *range, void (*callback)(guint32 val)); - -extern char *range_convert_range(range_t *range); - -extern range_t *range_copy(range_t *src); - -#endif /* __RANGE_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/reassemble.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/reassemble.h deleted file mode 100644 index c8581727..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/reassemble.h +++ /dev/null @@ -1,316 +0,0 @@ -/* reassemble.h - * Declarations of outines for {fragment,segment} reassembly - * - * $Id: reassemble.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* make sure that all flags that are set in a fragment entry is also set for - * the flags field of fd_head !!! - */ - -/* only in fd_head: packet is defragmented */ -#define FD_DEFRAGMENTED 0x0001 - -/* there are overlapping fragments */ -#define FD_OVERLAP 0x0002 - -/* overlapping fragments contain different data */ -#define FD_OVERLAPCONFLICT 0x0004 - -/* more than one fragment which indicates end-of data */ -#define FD_MULTIPLETAILS 0x0008 - -/* fragment contains data past the end of the datagram */ -#define FD_TOOLONGFRAGMENT 0x0010 - -/* fragment data not alloced, fd->data pointing to fd_head->data+fd->offset */ -#define FD_NOT_MALLOCED 0x0020 - -/* this flag is used to request fragment_add to continue the reassembly process */ -#define FD_PARTIAL_REASSEMBLY 0x0040 - -/* fragment offset is indicated by sequence number and not byte offset - into the defragmented packet */ -#define FD_BLOCKSEQUENCE 0x0100 - -/* if REASSEMBLE_FLAGS_CHECK_DATA_PRESENT is set, and the first fragment is - * incomplete, this flag is set in the flags word on the fd_head returned. - * - * It's all a fudge to preserve historical behaviour. - */ -#define FD_DATA_NOT_PRESENT 0x0200 - -/* This flag is set in the to denote that datalen has ben set to a valid value. - * It's implied by FD_DEFRAGMENTED (we must know the total length of the - * datagram if we have defragmented it...) - */ -#define FD_DATALEN_SET 0x0400 - -typedef struct _fragment_data { - struct _fragment_data *next; - guint32 frame; - guint32 offset; - guint32 len; - guint32 datalen; /* Only valid in first item of list and when - * flags&FD_DATALEN_SET is set; - * number of bytes or (if flags&FD_BLOCKSEQUENCE set) - * segments in the datagram */ - guint32 reassembled_in; /* frame where this PDU was reassembled, - only valid in the first item of the list - and when FD_DEFRAGMENTED is set*/ - guint32 flags; - unsigned char *data; -} fragment_data; - - -/* - * Flags for fragment_add_seq_* - */ - -/* we don't have any sequence numbers - fragments are assumed to appear in - * order */ -#define REASSEMBLE_FLAGS_NO_FRAG_NUMBER 0x0001 - -/* a special fudge for the 802.11 dissector */ -#define REASSEMBLE_FLAGS_802_11_HACK 0x0002 - -/* causes fragment_add_seq_key to check that all the fragment data is present - * in the tvb, and if not, do something a bit odd. */ -#define REASSEMBLE_FLAGS_CHECK_DATA_PRESENT 0x0004 - -/* a function for copying hash keys */ -typedef void *(*fragment_key_copier)(const void *key); - - -/* - * Initialize a fragment table. - */ -extern void fragment_table_init(GHashTable **fragment_table); -extern void dcerpc_fragment_table_init(GHashTable **fragment_table); - -/* - * Initialize a reassembled-packet table. - */ -extern void reassembled_table_init(GHashTable **reassembled_table); - -/* - * Free up all space allocated for fragment keys and data. - */ -void reassemble_init(void); - -/* - * This function adds a new fragment to the fragment hash table. - * If this is the first fragment seen for this datagram, a new entry - * is created in the hash table, otherwise this fragment is just added - * to the linked list of fragments for this packet. - * The list of fragments for a specific datagram is kept sorted for - * easier handling. - * - * Returns a pointer to the head of the fragment data list if we have all the - * fragments, NULL otherwise. - */ -extern fragment_data *fragment_add(tvbuff_t *tvb, int offset, packet_info *pinfo, - guint32 id, GHashTable *fragment_table, guint32 frag_offset, - guint32 frag_data_len, gboolean more_frags); -extern fragment_data *fragment_add_multiple_ok(tvbuff_t *tvb, int offset, - packet_info *pinfo, guint32 id, GHashTable *fragment_table, - guint32 frag_offset, guint32 frag_data_len, gboolean more_frags); - -/* - * This routine extends fragment_add to use a "reassembled_table". - * - * If, after processing this fragment, we have all the fragments, they - * remove that from the fragment hash table if necessary and add it - * to the table of reassembled fragments, and return a pointer to the - * head of the fragment list. - */ -extern fragment_data *fragment_add_check(tvbuff_t *tvb, int offset, - packet_info *pinfo, guint32 id, GHashTable *fragment_table, - GHashTable *reassembled_table, guint32 frag_offset, - guint32 frag_data_len, gboolean more_frags); - -/* same as fragment_add() but this one assumes frag_number is a block - sequence number. note that frag_number is 0 for the first fragment. */ - -/* - * These functions add a new fragment to the fragment hash table, - * assuming that frag_number is a block sequence number (starting from zero for - * the first fragment of each datagram). - * - * If this is the first fragment seen for this datagram, a new - * "fragment_data" structure is allocated to refer to the reassembled - * packet, and: - * - * if "more_frags" is false, and either we have no sequence numbers, or - * are using the 802.11 hack, it is assumed that this is the only fragment - * in the datagram. The structure is not added to the hash - * table, and not given any fragments to refer to, but is just returned. - * - * In this latter case reassembly wasn't done (since there was only one - * fragment in the packet); dissectors can check the 'next' pointer on the - * returned list to see if this case was hit or not. - * - * Otherwise, this fragment is just added to the linked list of fragments - * for this packet; the fragment_data is also added to the fragment hash if - * necessary. - * - * If this packet completes assembly, these functions return the head of the - * fragment data; otherwise, they return null. - */ - -/* "key" should be an arbitrary key used for indexing the fragment hash; - * "key_copier" is called to copy the key to a more appropriate store before - * inserting a new entry to the hash. - */ -extern fragment_data * -fragment_add_seq_key(tvbuff_t *tvb, int offset, packet_info *pinfo, - void *key, fragment_key_copier key_copier, - GHashTable *fragment_table, guint32 frag_number, - guint32 frag_data_len, gboolean more_frags, - guint32 flags); - -/* a wrapper for fragment_add_seq_key - uses a key of source, dest and frame number */ -extern fragment_data *fragment_add_seq(tvbuff_t *tvb, int offset, packet_info *pinfo, - guint32 id, GHashTable *fragment_table, guint32 frag_number, - guint32 frag_data_len, gboolean more_frags); - -/* another wrapper for fragment_add_seq_key - uses a key of source, dest, frame - * number and act_id */ -extern fragment_data * -fragment_add_dcerpc_dg(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id, - void *act_id, - GHashTable *fragment_table, guint32 frag_number, - guint32 frag_data_len, gboolean more_frags); - -/* - * These routines extend fragment_add_seq_key to use a "reassembled_table". - * - * If, after processing this fragment, we have all the fragments, they - * remove that from the fragment hash table if necessary and add it - * to the table of reassembled fragments, and return a pointer to the - * head of the fragment list. - */ -extern fragment_data * -fragment_add_seq_check(tvbuff_t *tvb, int offset, packet_info *pinfo, - guint32 id, GHashTable *fragment_table, - GHashTable *reassembled_table, guint32 frag_number, - guint32 frag_data_len, gboolean more_frags); - -extern fragment_data * -fragment_add_seq_802_11(tvbuff_t *tvb, int offset, packet_info *pinfo, - guint32 id, GHashTable *fragment_table, - GHashTable *reassembled_table, guint32 frag_number, - guint32 frag_data_len, gboolean more_frags); - -extern fragment_data * -fragment_add_seq_next(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id, - GHashTable *fragment_table, GHashTable *reassembled_table, - guint32 frag_data_len, gboolean more_frags); - -extern void -fragment_start_seq_check(packet_info *pinfo, guint32 id, GHashTable *fragment_table, - guint32 tot_len); - -extern fragment_data * -fragment_end_seq_next(packet_info *pinfo, guint32 id, GHashTable *fragment_table, - GHashTable *reassembled_table); -/* to specify how much to reassemble, for fragmentation where last fragment can not be - * identified by flags or such. - * note that for FD_BLOCKSEQUENCE tot_len is the index for the tail fragment. - * i.e. since the block numbers start at 0, if we specify tot_len==2, that - * actually means we want to defragment 3 blocks, block 0, 1 and 2. - * - */ -extern void -fragment_set_tot_len(packet_info *pinfo, guint32 id, GHashTable *fragment_table, - guint32 tot_len); - -/* to resad whatever totlen previously set */ -extern guint32 -fragment_get_tot_len(packet_info *pinfo, guint32 id, GHashTable *fragment_table); - -/* - * This function will set the partial reassembly flag(FD_PARTIAL_REASSEMBLY) for a fh. - * When this function is called, the fh MUST already exist, i.e. - * the fh MUST be created by the initial call to fragment_add() before - * this function is called. Also note that this function MUST be called to indicate - * a fh will be extended (increase the already stored data). After calling this function, - * and if FD_DEFRAGMENTED is set, the reassembly process will be continued. - */ -extern void -fragment_set_partial_reassembly(packet_info *pinfo, guint32 id, GHashTable *fragment_table); - -/* This function is used to check if there is partial or completed reassembly state - * matching this packet. I.e. Are there reassembly going on or not for this packet? - */ -extern fragment_data * -fragment_get(packet_info *pinfo, guint32 id, GHashTable *fragment_table); - -/* The same for the reassemble table */ -/* id *must* be the frame number for this to work! */ -extern fragment_data * -fragment_get_reassembled(packet_info *pinfo, guint32 id, GHashTable *reassembled_table); - -extern fragment_data * -fragment_get_reassembled_id(packet_info *pinfo, guint32 id, GHashTable *reassembled_table); - -/* This will free up all resources and delete reassembly state for this PDU. - * Except if the PDU is completely reassembled, then it would NOT deallocate the - * buffer holding the reassembled data but instead return the pointer to that - * buffer. - * - * So, if you call fragment_delete and it returns non-NULL, YOU are responsible to - * g_free() that buffer. - */ -extern unsigned char * -fragment_delete(packet_info *pinfo, guint32 id, GHashTable *fragment_table); - -/* hf_fragment, hf_fragment_error, and hf_reassembled_in should be - FT_FRAMENUM, the others should be FT_BOOLEAN -*/ -typedef struct _fragment_items { - gint *ett_fragment; - gint *ett_fragments; - - int *hf_fragments; - int *hf_fragment; - int *hf_fragment_overlap; - int *hf_fragment_overlap_conflict; - int *hf_fragment_multiple_tails; - int *hf_fragment_too_long_fragment; - int *hf_fragment_error; - int *hf_reassembled_in; - - const char *tag; -} fragment_items; - -extern tvbuff_t * -process_reassembled_data(tvbuff_t *tvb, int offset, packet_info *pinfo, - const char *name, fragment_data *fd_head, const fragment_items *fit, - gboolean *update_col_infop, proto_tree *tree); - -extern gboolean -show_fragment_tree(fragment_data *ipfd_head, const fragment_items *fit, - proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, proto_item **fi); - -extern gboolean -show_fragment_seq_tree(fragment_data *ipfd_head, const fragment_items *fit, - proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, proto_item **fi); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/reedsolomon.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/reedsolomon.h deleted file mode 100644 index 433f6e1e..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/reedsolomon.h +++ /dev/null @@ -1,86 +0,0 @@ -#ifdef __cplusplus -extern "C" { -#endif - -/* Global definitions for Reed-Solomon encoder/decoder - * Phil Karn KA9Q, September 1996 - */ -/* Set one of these to enable encoder/decoder debugging and error checking, - * at the expense of speed */ -/* #undef DEBUG 1*/ -/* #undef DEBUG 2*/ -#undef DEBUG - -/* To select the CCSDS standard (255,223) code, define CCSDS. This - * implies standard values for MM, KK, B0 and PRIM. - */ -/* #undef CCSDS 1*/ -#undef CCSDS -#ifndef CCSDS - -/* Otherwise, leave CCSDS undefined and set the parameters below: - * - * Set MM to be the size of each code symbol in bits. The Reed-Solomon - * block size will then be NN = 2**M - 1 symbols. Supported values are - * defined in rs.c. - */ -#define MM 8 /* Symbol size in bits */ - -/* - * Set KK to be the number of data symbols in each block, which must be - * less than the block size. The code will then be able to correct up - * to NN-KK erasures or (NN-KK)/2 errors, or combinations thereof with - * each error counting as two erasures. - */ -#define KK 207 /* Number of data symbols per block */ - -/* Set B0 to the first root of the generator polynomial, in alpha form, and - * set PRIM to the power of alpha used to generate the roots of the - * generator polynomial. The generator polynomial will then be - * @**PRIM*B0, @**PRIM*(B0+1), @**PRIM*(B0+2)...@**PRIM*(B0+NN-KK) - * where "@" represents a lower case alpha. - */ -#define B0 1 /* First root of generator polynomial, alpha form */ -#define PRIM 1 /* power of alpha used to generate roots of generator poly */ -#define STANDARD_ORDER - -/* If you want to select your own field generator polynomial, you'll have - * to edit that in rs.c. - */ - -#else /* CCSDS */ -/* Don't change these, they're CCSDS standard */ -#define MM 8 -#define KK 223 -#define B0 112 -#define PRIM 11 -#endif - -#define NN ((1 << MM) - 1) - -#if MM <= 8 -typedef unsigned char dtype; -#else -typedef unsigned int dtype; -#endif - -/* Reed-Solomon encoding - * data[] is the input block, parity symbols are placed in bb[] - * bb[] may lie past the end of the data, e.g., for (255,223): - * encode_rs(&data[0],&data[223]); - */ -int encode_rs(dtype data[], dtype bb[]); - -/* Reed-Solomon erasures-and-errors decoding - * The received block goes into data[], and a list of zero-origin - * erasure positions, if any, goes in eras_pos[] with a count in no_eras. - * - * The decoder corrects the symbols in place, if possible and returns - * the number of corrected symbols. If the codeword is illegal or - * uncorrectible, the data array is unchanged and -1 is returned - */ -int eras_dec_rs(dtype data[], int eras_pos[], int no_eras); - -#ifdef __cplusplus -} -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/report_err.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/report_err.h deleted file mode 100644 index c29df457..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/report_err.h +++ /dev/null @@ -1,61 +0,0 @@ -/* report_err.h - * Declarations of routines for dissectors to use to report errors to - * the user (e.g., problems with preference settings) - * - * $Id: report_err.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __REPORT_ERR_H__ -#define __REPORT_ERR_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* - * Initialize the report err routines - */ -extern void init_report_err( - void (*report_failure)(const char *, va_list), - void (*report_open_failure)(const char *, int, gboolean), - void (*report_read_failure)(const char *, int)); - -/* - * Report an error when trying to open a file. - */ -extern void report_open_failure(const char *filename, int err, - gboolean for_writing); - -/* - * Report an error when trying to read a file. - */ -extern void report_read_failure(const char *filename, int err); - -/* - * Report a general error. - */ -extern void report_failure(const char *msg_format, ...); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __REPORT_ERR_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/req_resp_hdrs.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/req_resp_hdrs.h deleted file mode 100644 index 40e68884..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/req_resp_hdrs.h +++ /dev/null @@ -1,43 +0,0 @@ -/* req_resp_hdrs.h - * Declarations of routines handling protocols with a request/response line, - * headers, a blank line, and an optional body. - * - * $Id: req_resp_hdrs.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __REQ_RESP_HDRS_H__ -#define __REQ_RESP_HDRS_H__ - -/** - * Optionally do reassembly of the request/response line, headers, and body. - * - * @param tvb The buffer. - * @param offset The offset in the buffer to begin inspection. - * @param pinfo Packet info from the parent protocol. - * @param desegment_headers Do desegmentation on headers. - * @param desegment_body Do desegmenation on body. - * @return TRUE if desegmentation is complete otherwise FALSE - */ -extern gboolean -req_resp_hdrs_do_reassembly(tvbuff_t *tvb, const int offset, packet_info *pinfo, - const gboolean desegment_headers, const gboolean desegment_body); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/rtp_pt.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/rtp_pt.h deleted file mode 100644 index 0ddb9b9a..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/rtp_pt.h +++ /dev/null @@ -1,68 +0,0 @@ -/* rtp_pt.h - * Defines RTP payload types - * - * $Id: rtp_pt.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __RTP_PT_H__ -#define __RTP_PT_H__ - -#include "epan/value_string.h" - -/* - * RTP Payload types - * Table B.2 / H.225.0 - * Also RFC 1890, and - * - * http://www.iana.org/assignments/rtp-parameters - */ -#define PT_PCMU 0 /* RFC 1890 */ -#define PT_1016 1 /* RFC 1890 */ -#define PT_G721 2 /* RFC 1890 */ -#define PT_GSM 3 /* RFC 1890 */ -#define PT_G723 4 /* From Vineet Kumar of Intel; see the Web page */ -#define PT_DVI4_8000 5 /* RFC 1890 */ -#define PT_DVI4_16000 6 /* RFC 1890 */ -#define PT_LPC 7 /* RFC 1890 */ -#define PT_PCMA 8 /* RFC 1890 */ -#define PT_G722 9 /* RFC 1890 */ -#define PT_L16_STEREO 10 /* RFC 1890 */ -#define PT_L16_MONO 11 /* RFC 1890 */ -#define PT_QCELP 12 /* Qualcomm Code Excited Linear Predictive coding? */ -#define PT_CN 13 /* RFC 3389 */ -#define PT_MPA 14 /* RFC 1890, RFC 2250 */ -#define PT_G728 15 /* RFC 1890 */ -#define PT_DVI4_11025 16 /* from Joseph Di Pol of Sun; see the Web page */ -#define PT_DVI4_22050 17 /* from Joseph Di Pol of Sun; see the Web page */ -#define PT_G729 18 -#define PT_CN_OLD 19 /* Payload type reserved (old version Comfort Noise) */ -#define PT_CELB 25 /* RFC 2029 */ -#define PT_JPEG 26 /* RFC 2435 */ -#define PT_NV 28 /* RFC 1890 */ -#define PT_H261 31 /* RFC 2032 */ -#define PT_MPV 32 /* RFC 2250 */ -#define PT_MP2T 33 /* RFC 2250 */ -#define PT_H263 34 /* from Chunrong Zhu of Intel; see the Web page */ - -WS_VAR_IMPORT const value_string rtp_payload_type_vals[]; -WS_VAR_IMPORT const value_string rtp_payload_type_short_vals[]; - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sctpppids.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sctpppids.h deleted file mode 100644 index 523a04a8..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sctpppids.h +++ /dev/null @@ -1,50 +0,0 @@ -/* sctpppids.h - * Declarations of SCTP payload protocol IDs. - * - * $Id: sctpppids.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __SCTPPPIDS_H__ -#define __SCTPPPIDS_H__ - -/* - * SCTP payload protocol IDs. - */ -#define NOT_SPECIFIED_PROTOCOL_ID 0 -#define IUA_PAYLOAD_PROTOCOL_ID 1 -#define M2UA_PAYLOAD_PROTOCOL_ID 2 -#define M3UA_PAYLOAD_PROTOCOL_ID 3 -#define SUA_PAYLOAD_PROTOCOL_ID 4 -#define M2PA_PAYLOAD_PROTOCOL_ID 5 -#define V5UA_PAYLOAD_PROTOCOL_ID 6 -#define H248_PAYLOAD_PROTOCOL_ID 7 -#define BICC_PAYLOAD_PROTOCOL_ID 8 -#define TALI_PAYLOAD_PROTOCOL_ID 9 -#define DUA_PAYLOAD_PROTOCOL_ID 10 -#define ASAP_PAYLOAD_PROTOCOL_ID 11 -#define ENRP_PAYLOAD_PROTOCOL_ID 12 -#define H323_PAYLOAD_PROTOCOL_ID 13 -#define QIPC_PAYLOAD_PROTOCOL_ID 14 -#define SIMCO_PAYLOAD_PROTOCOL_ID 15 -#define DDP_SEG_CHUNK_PROTOCOL_ID 16 -#define DDP_STREAM_SES_CTRL_PROTOCOL_ID 17 -#define M2TP_PAYLOAD_PROTOCOL_ID 99 /* s-link */ -#endif /* sctpppids.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sigcomp-udvm.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sigcomp-udvm.h deleted file mode 100644 index bcbb58fb..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sigcomp-udvm.h +++ /dev/null @@ -1,49 +0,0 @@ -/* udvm.h - * Routines making up the Univerasl Decompressor Virtual Machine (UDVM) used for - * Signaling Compression (SigComp) dissection. - * Copyright 2004, Anders Broman - * - * $Id: sigcomp-udvm.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * References: - * http://www.ietf.org/rfc/rfc3320.txt?number=3320 - * http://www.ietf.org/rfc/rfc3321.txt?number=3321 - * Useful links : - * http://www.ietf.org/internet-drafts/draft-ietf-rohc-sigcomp-impl-guide-02.txt - * http://www.ietf.org/internet-drafts/draft-ietf-rohc-sigcomp-sip-01.txt - */ - -#ifndef SIGCOMP_UDVM_H -#define SIGCOMP_UDVM_H - -#define UDVM_MEMORY_SIZE 65536 - -extern tvbuff_t* decompress_sigcomp_message(tvbuff_t *bytecode_tvb, tvbuff_t *message_tvb, packet_info *pinfo, - proto_tree *tree, gint destination, - gint print_flags, gint hf_id, gint header_len, - gint byte_code_state_len, gint byte_code_id_len, - gint udvm_start_ip); - - - -/* example: extern const value_string q931_cause_location_vals[]; */ -#endif -/* SIGCOMP_UDVM_H */ - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sigcomp_state_hdlr.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sigcomp_state_hdlr.h deleted file mode 100644 index 1a5beaf2..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sigcomp_state_hdlr.h +++ /dev/null @@ -1,49 +0,0 @@ -/* sigcomp_state_hdlr.c - * Routines making up the State handler of the Univerasl Decompressor Virtual Machine (UDVM) - * used for Signaling Compression (SigComp) dissection. - * Copyright 2004, Anders Broman - * - * $Id: sigcomp_state_hdlr.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * References: - * http://www.ietf.org/rfc/rfc3320.txt?number=3320 - * http://www.ietf.org/rfc/rfc3321.txt?number=3321 - * Useful links : - * http://www.ietf.org/internet-drafts/draft-ietf-rohc-sigcomp-impl-guide-03.txt - * http://www.ietf.org/internet-drafts/draft-ietf-rohc-sigcomp-sip-01.txt - */ - -#ifndef SIGCOMP_STATE_HDLR_H -#define SIGCOMP_STATE_HDLR_H - -extern const value_string result_code_vals[]; -extern int udvm_state_access(tvbuff_t *tvb, proto_tree *tree,guint8 *buff,guint16 p_id_start, guint16 p_id_length, guint16 state_begin, guint16 *state_length, - guint16 *state_address, guint16 *state_instruction, gint hf_id); - -extern void udvm_state_create(guint8 *state_buff,guint8 *state_identifier_buff,guint16 p_id_length); -extern void udvm_state_free(guint8 buff[],guint16 p_id_start,guint16 p_id_length); - -extern void sigcomp_init_udvm(void); - -#define STATE_BUFFER_SIZE 20 -#define STATE_MIN_ACCESS_LEN 6 - -#endif -/* SIGCOMP_STATE_HDLR_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/slab.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/slab.h deleted file mode 100644 index c84e50ca..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/slab.h +++ /dev/null @@ -1,75 +0,0 @@ -/* slab.h - * Definitions for very simple slab handling - * - * $Id: slab.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __SLAB_H__ -#define __SLAB_H__ - -#define NITEMS_PER_SLAB 100 - -/* - * Generate declaration of a union type containing the specified type of - * slab-allocated item, and a pointer to an object of that type, for use - * in the macros below. - */ -#define SLAB_ITEM_TYPE_DEFINE(type) \ - union type ## slab_item { \ - type slab_item; \ - union type ## slab_item *next_free; \ - }; - -/* - * Generate definition of the free list pointer. - */ -#define SLAB_FREE_LIST_DEFINE(type) \ - union type ## slab_item *type ## _free_list = NULL; - -/* - * Generate an external declaration of the free list pointer. - */ -#define SLAB_FREE_LIST_DECLARE(type) \ - union type ## slab_item *type ## _free_list; - -/* we never free any memory we have allocated, when it is returned to us - we just store it in the free list until (hopefully) it gets used again -*/ -#define SLAB_ALLOC(item, type) \ - if(!type ## _free_list){ \ - int i; \ - union type ## slab_item *tmp; \ - tmp=g_malloc(NITEMS_PER_SLAB*sizeof(*tmp)); \ - for(i=0;islab_item); \ - type ## _free_list = type ## _free_list->next_free; - -#define SLAB_FREE(item, type) \ -{ \ - ((union type ## slab_item *)item)->next_free = type ## _free_list; \ - type ## _free_list = (union type ## slab_item *)item; \ -} - -#endif /* slab.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sminmpec.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sminmpec.h deleted file mode 100644 index b81ea7c2..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sminmpec.h +++ /dev/null @@ -1,83 +0,0 @@ -/* sminmpec.h - * SMI Network Management Private Enterprise Codes for organizations - * - * $Id: sminmpec.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2004 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __SMINMPEC_H__ -#define __SMINMPEC_H__ - -/* - * These are SMI Network Management Private Enterprise Codes for - * organizations; see - * - * http://www.iana.org/assignments/enterprise-numbers - * - * for a list. - */ -#define VENDOR_IETF 0 /* reserved - used by the IETF in L2TP? */ -#define VENDOR_ACC 5 -#define VENDOR_CISCO 9 -#define VENDOR_HEWLETT_PACKARD 11 -#define VENDOR_SUN_MICROSYSTEMS 42 -#define VENDOR_MERIT 61 -#define VENDOR_MOTOROLA 161 -#define VENDOR_SHIVA 166 -#define VENDOR_ERICSSON 193 -#define VENDOR_CISCO_VPN5000 255 -#define VENDOR_LIVINGSTON 307 -#define VENDOR_MICROSOFT 311 -#define VENDOR_3COM 429 -#define VENDOR_ASCEND 529 -#define VENDOR_BAY 1584 -#define VENDOR_FOUNDRY 1991 -#define VENDOR_VERSANET 2180 -#define VENDOR_REDBACK 2352 -#define VENDOR_JUNIPER 2636 -#define VENDOR_APTIS 2637 -#define VENDOR_DT_AG 2937 -#define VENDOR_CISCO_VPN3000 3076 -#define VENDOR_COSINE 3085 -#define VENDOR_SHASTA 3199 -#define VENDOR_NETSCREEN 3224 -#define VENDOR_NOMADIX 3309 -#define VENDOR_T_MOBILE 3414 /* Former VoiceStream Wireless, Inc. */ -#define VENDOR_SIEMENS 4329 -#define VENDOR_CABLELABS 4491 -#define VENDOR_UNISPHERE 4874 -#define VENDOR_CISCO_BBSM 5263 -#define VENDOR_THE3GPP2 5535 -#define VENDOR_IP_UNPLUGGED 5925 -#define VENDOR_ISSANNI 5948 -#define VENDOR_DE_TE_MOBIL 6490 -#define VENDOR_QUINTUM 6618 -#define VENDOR_INTERLINK 6728 -#define VENDOR_COLUBRIS 8744 -#define VENDOR_COLUMBIA_UNIVERSITY 11862 -#define VENDOR_THE3GPP 10415 -#define VENDOR_GEMTEK_SYSTEMS 10529 -#define VENDOR_WIFI_ALLIANCE 14122 -#define VENDOR_T_SYSTEMS_NOVA 16787 - - -WS_VAR_IMPORT const value_string sminmpec_values[]; - -#endif /* __SMINMPEC_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sna-utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sna-utils.h deleted file mode 100644 index 8782af88..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sna-utils.h +++ /dev/null @@ -1,41 +0,0 @@ -/* sna-utils.h - * Definitions for SNA dissection. - * - * $Id: sna-utils.h 3992 2008-06-10 03:13:11Z dgu $ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __SNA_UTILS__ -#define __SNA_UTILS__ - -#include -#include - -/* - * Structure used to represent an FID Type 4 address; gives the layout of the - * data pointed to by an AT_SNA "address" structure if the size is - * SNA_FID_TYPE_4_ADDR_LEN. - */ -#define SNA_FID_TYPE_4_ADDR_LEN 6 -struct sna_fid_type_4_addr { - guint32 saf; - guint16 ef; -}; - -extern gchar *sna_fid_to_str(const address *addr); -extern void sna_fid_to_str_buf(const address *addr, gchar *buf, int buf_len); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stat_cmd_args.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stat_cmd_args.h deleted file mode 100644 index 56233f61..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stat_cmd_args.h +++ /dev/null @@ -1,35 +0,0 @@ -/* stat_cmd_args.h - * Declarations of routines to register "-z" command-line argument handlers - * for stats - * - * $Id: stat_cmd_args.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef _STAT_H_ -#define _STAT_H_ - -extern void register_stat_cmd_arg(const char *cmd, - void (*func)(const char *arg,void* userdata), void* userdata); -extern gboolean process_stat_cmd_arg(char *optarg); -extern void list_stat_cmd_args(void); -extern void start_requested_stats(void); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stats_tree.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stats_tree.h deleted file mode 100644 index ff36fd95..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stats_tree.h +++ /dev/null @@ -1,147 +0,0 @@ -/* stats_tree.h - * A counter tree API for Wireshark dissectors - * 2005, Luis E. G. Ontanon - * - * $Id: stats_tree.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#ifndef __STATS_TREE_H -#define __STATS_TREE_H - -#include -#include -#include -#include -#include -#include "../register.h" - -#define STAT_TREE_ROOT "root" - -/* obscure information regarding the stats_tree */ -typedef struct _stats_tree stats_tree; - -/* tap packet callback for stats_tree */ -typedef int (*stat_tree_packet_cb)(stats_tree*, - packet_info*, - epan_dissect_t*, - const void *); - -/* stats_tree initilaization callback */ -typedef void (*stat_tree_init_cb)(stats_tree*); - -/* stats_tree initilaization callback */ -typedef void (*stat_tree_cleanup_cb)(stats_tree*); - -/* registers a new stats tree - * abbr: protocol abbr - * name: protocol name - * packet: per packet callback - * init: tree initialization callback - */ -extern void stats_tree_register(const guint8* tapname, - const guint8* abbr, - const guint8* name, - stat_tree_packet_cb packet, - stat_tree_init_cb init, - stat_tree_cleanup_cb cleanup); - -extern int stats_tree_parent_id_by_name(stats_tree* st, const gchar* parent_name); - -/* Creates a node in the tree (to be used in the in init_cb) -* st: the stats_tree in which to create it -* name: the name of the new node -* parent_name: the name of the parent_node (NULL for root) -* with_children: TRUE if this node will have "dynamically created" children -*/ -extern int stats_tree_create_node(stats_tree* st, - const gchar* name, - int parent_id, - gboolean with_children); - -/* creates a node using it's parent's tree name */ -extern int stats_tree_create_node_by_pname(stats_tree* st, - const gchar* name, - const gchar* parent_name, - gboolean with_children); - -/* creates a node in the tree, that will contain a ranges list. - example: - stats_tree_create_range_node(st,name,parent, - "-99","100-199","200-299","300-399","400-", NULL); -*/ -extern int stats_tree_create_range_node(stats_tree* st, - const gchar* name, - int parent_id, - ...); - -extern int stats_tree_range_node_with_pname(stats_tree* st, - const gchar* name, - const gchar* parent_name, - ...); - -/* increases by one the ranged node and the sub node to whose range the value belongs */ -extern int stats_tree_tick_range(stats_tree* st, - const gchar* name, - int parent_id, - int value_in_range); - -#define stats_tree_tick_range_by_pname(st,name,parent_name,value_in_range) \ - stats_tree_tick_range((st),(name),stats_tree_parent_id_by_name((st),(parent_name),(value_in_range)) - -/* */ -extern int stats_tree_create_pivot(stats_tree* st, - const gchar* name, - int parent_id); - -extern int stats_tree_create_pivot_by_pname(stats_tree* st, - const gchar* name, - const gchar* parent_name); - -extern int stats_tree_tick_pivot(stats_tree* st, - int pivot_id, - const gchar* pivot_value); - -/* - * manipulates the value of the node whose name is given - * if the node does not exist yet it's created (with counter=1) - * using parent_name as parent node (NULL for root). - * with_children=TRUE to indicate that the created node will be a parent - */ -typedef enum _manip_node_mode { MN_INCREASE, MN_SET } manip_node_mode; -extern int stats_tree_manip_node(manip_node_mode mode, - stats_tree* st, - const guint8* name, - int parent_id, - gboolean with_children, - gint value); - -#define increase_stat_node(st,name,parent_id,with_children,value) \ -(stats_tree_manip_node(MN_INCREASE,(st),(name),(parent_id),(with_children),(value))) - -#define tick_stat_node(st,name,parent_id,with_children) \ -(stats_tree_manip_node(MN_INCREASE,(st),(name),(parent_id),(with_children),1)) - -#define set_stat_node(st,name,parent_id,with_children,value) \ -(stats_tree_manip_node(MN_SET,(st),(name),(parent_id),(with_children),value)) - -#define zero_stat_node(st,name,parent_id,with_children) \ -(stats_tree_manip_node(MN_SET,(st),(name),(parent_id),(with_children),0)) - -#endif /* __STATS_TREE_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stats_tree_priv.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stats_tree_priv.h deleted file mode 100644 index 80ca6a11..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stats_tree_priv.h +++ /dev/null @@ -1,202 +0,0 @@ -/* stats_tree_priv.h - * implementor's API for stats_tree - * 2005, Luis E. G. Ontanon - * - * $Id: stats_tree_priv.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __STATS_TREE_PRIV_H -#define __STATS_TREE_PRIV_H - -#include "stats_tree.h" - -#define INDENT_MAX 32 -#define NUM_BUF_SIZE 32 - -/* implementations should define this to contain its own node related data - * as well as some operations on it */ -typedef struct _st_node_pres st_node_pres; - -/* implementations should define this to contain its own dynamic tree related data -* as well as some operations on it */ -typedef struct _tree_pres tree_pres; - -/* implementations should define this to contain its own static tree related data -* as well as some operations on it */ -typedef struct _tree_cfg_pres tree_cfg_pres; - - -typedef struct _stat_node stat_node; -typedef struct _stats_tree_cfg stats_tree_cfg; - -typedef struct _range_pair { - gint floor; - gint ceil; -} range_pair_t; - -struct _stat_node { - gchar* name; - int id; - - /* the counter it keeps */ - gint counter; - - /* children nodes by name */ - GHashTable* hash; - - /* the owner of this node */ - stats_tree* st; - - /* relatives */ - stat_node* parent; - stat_node* children; - stat_node* next; - - /* used to check if value is within range */ - range_pair_t* rng; - - /* node presentation data */ - st_node_pres* pr; -}; - -struct _stats_tree { - /* the "class" from which it's derived */ - stats_tree_cfg* cfg; - - char* filter; - - /* times */ - double start; - double elapsed; - - /* used to lookup named parents: - * key: parent node name - * value: parent node - */ - GHashTable* names; - - /* used for quicker lookups of parent nodes */ - GPtrArray* parents; - - /* - * tree representation - * to be defined (if needed) by the implementations - */ - tree_pres* pr; - - /* every tree in nature has one */ - stat_node root; -}; - -struct _stats_tree_cfg { - guint8* abbr; - guint8* name; - guint8* tapname; - - gboolean in_use; - - /* dissector defined callbacks */ - stat_tree_packet_cb packet; - stat_tree_init_cb init; - stat_tree_cleanup_cb cleanup; - - /* - * node presentation callbacks - */ - - /* last to be called at node creation */ - void (*setup_node_pr)(stat_node*); - - /* last to be called at node destruction */ - void (*free_node_pr)(stat_node*); - - /* to be called for every node in the tree */ - void (*draw_node)(stat_node*); - void (*reset_node)(stat_node*); - - /* - * tree presentation callbacks - */ - tree_cfg_pres* pr; - - - tree_pres* (*new_tree_pr)(stats_tree*); - void (*free_tree_pr)(stats_tree*); - void (*draw_tree)(stats_tree*); - void (*reset_tree)(stats_tree*); -}; - -/* guess what, this is it! */ -extern void stats_tree_presentation(void (*registry_iterator)(gpointer,gpointer,gpointer), - void (*setup_node_pr)(stat_node*), - void (*free_node_pr)(stat_node*), - void (*draw_node)(stat_node*), - void (*reset_node)(stat_node*), - tree_pres* (*new_tree_pr)(stats_tree*), - void (*free_tree_pr)(stats_tree*), - void (*draw_tree)(stats_tree*), - void (*reset_tree)(stats_tree*), - void* data); - -extern stats_tree* stats_tree_new(stats_tree_cfg* cfg, tree_pres* pr, char* filter); - -/* callback for taps */ -extern int stats_tree_packet(void*, packet_info*, epan_dissect_t*, const void *); - -/* callback for reset */ -extern void stats_tree_reset(void* p_st); - -/* callback for clear */ -extern void stats_tree_reinit(void* p_st); - -/* callback for destoy */ -extern void stats_tree_free(stats_tree* st); - -/* given an optarg splits the abbr part - and returns a newly allocated buffer containing it */ -extern guint8* stats_tree_get_abbr(const guint8* optarg); - -/* obtains a stats tree from the registry given its abbr */ -extern stats_tree_cfg* stats_tree_get_cfg_by_abbr(guint8* abbr); - -/* extracts node data as strings from a stat_node into - the buffers given by value, rate and precent - if NULL they are ignored */ -extern void stats_tree_get_strs_from_node(const stat_node* node, - guint8* value, - guint8* rate, - guint8* percent); - -/* populates the given GString with a tree representation of a branch given by node, - using indent spaces as indentation */ -extern void stats_tree_branch_to_str(const stat_node* node, - GString* s, - guint indent); - -/* used to calcuate the size of the indentation and the longest string */ -extern guint stats_tree_branch_max_namelen(const stat_node* node, guint indent); - -/* a text representation of a node, - if buffer is NULL returns a newly allocated string */ -extern guint8* stats_tree_node_to_str(const stat_node* node, - guint8* buffer, guint len); - -#endif /* __STATS_TREE_PRIV_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stream.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stream.h deleted file mode 100644 index 9fd1cc90..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stream.h +++ /dev/null @@ -1,138 +0,0 @@ -/* stream.h - * - * Definititions for handling circuit-switched protocols - * which are handled as streams, and don't have lengths - * and IDs such as are required for reassemble.h - * - * $Id: stream.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef STREAM_H -#define STREAM_H - -#include - -struct _fragment_items; - -/* A stream represents the concept of an arbitrary stream of data, - divided up into frames for transmission, where the frames have - little or no correspondence to the PDUs of the protocol being - streamed, and those PDUs are just delineated by a magic number. - - For example, we stream H.223 over IAX2. IAX2 has no concept of - H.223 PDUs and just divides the H.223 stream into 160-byte - frames. H.223 PDUs are delineated by two-byte magic numbers (which - may, of course, straddle an IAX2 frame boundary). - - Essentially we act as a wrapper to reassemble.h, by making up - PDU ids and keeping some additional data on fragments to allow the - PDUs to be defragmented again. -*/ - - -/* A stream_t represents a stream. There might be one or two streams - in a circuit, depending on whether that circuit is mono- or bi-directional. -*/ -typedef struct stream stream_t; - -/* Fragments in a PDU are represented using a stream_pdu_fragment_t, - and placed in a linked-list with other fragments in the PDU. - - (They're also placed in a hash so we can find them again later) -*/ -typedef struct stream_pdu_fragment stream_pdu_fragment_t; - - - -struct circuit; -struct conversation; - -/* initialise a new stream. Call this when you first identify a distinct - * stream. The circit pointer is just used as a key to look up the stream. */ -extern stream_t *stream_new_circ ( const struct circuit *circuit, int p2p_dir ); -extern stream_t *stream_new_conv ( const struct conversation *conv, int p2p_dir ); - -/* retrieve a previously-created stream. - * - * Returns null if no matching stream was found. - */ -extern stream_t *find_stream_circ ( const struct circuit *circuit, int p2p_dir ); -extern stream_t *find_stream_conv ( const struct conversation *conv, int p2p_dir ); - - - -/* see if we've seen this fragment before. - - The framenum and offset are just hash keys, so can be any values unique - to this frame, but the idea is that you use the number of the frame being - disassembled, and the byte-offset within that frame. -*/ -extern stream_pdu_fragment_t *stream_find_frag( stream_t *stream, guint32 framenum, guint32 offset ); - -/* add a new fragment to the fragment tables for the stream. The framenum and - * offset are keys allowing future access with stream_find_frag(), tvb is the - * fragment to be added, and pinfo is the information for the frame containing - * this fragment. more_frags should be set if this is the final fragment in the - * PDU. - * - * * the fragment must be later in the stream than any previous fragment - * (ie, framenum.offset must be greater than those passed on the previous - * call) - * - * This essentially means that you can only add fragments on the first pass - * through the stream. - */ -extern stream_pdu_fragment_t *stream_add_frag( stream_t *stream, guint32 framenum, guint32 offset, - tvbuff_t *tvb, packet_info *pinfo, gboolean more_frags ); - -/* Get the length of a fragment previously found by stream_find_frag(). - */ -extern guint32 stream_get_frag_length( const stream_pdu_fragment_t *frag); - -/* Get a handle on the top of the chain of fragment_datas underlying this PDU - * frag can be any fragment within a PDU, and it will always return the head of - * the chain - * - * Returns NULL until the last fragment is added. - */ -extern struct _fragment_data *stream_get_frag_data( const stream_pdu_fragment_t *frag); - -/* - * Process reassembled data; if this is the last fragment, put the fragment - * information into the protocol tree, and construct a tvbuff with the - * reassembled data, otherwise just put a "reassembled in" item into the - * protocol tree. - */ -extern tvbuff_t *stream_process_reassembled( - tvbuff_t *tvb, int offset, packet_info *pinfo, - char *name, const stream_pdu_fragment_t *frag, - const struct _fragment_items *fit, - gboolean *update_col_infop, proto_tree *tree); - -/* Get the PDU number. PDUs are numbered from zero within a stream. - * frag can be any fragment within a PDU. - */ -extern guint32 stream_get_pdu_no( const stream_pdu_fragment_t *frag); - -/* initialise the stream routines */ -void stream_init( void ); - -#endif /* STREAM_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/strutil.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/strutil.h deleted file mode 100644 index 4b108175..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/strutil.h +++ /dev/null @@ -1,243 +0,0 @@ -/* strutil.h - * String utility definitions - * - * $Id: strutil.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __STRUTIL_H__ -#define __STRUTIL_H__ - -/* ... thus, config.h needs to be #included */ - -/** @file - * String handling and conversion utilities. - */ - -/** Given a pointer into a data buffer, and to the end of the buffer, - * find the end of the (putative) line at that position in the data - * buffer. - * - * @param data A pointer to the beginning of the data - * @param dataend A pointer to the end of the data - * @param eol A pointer that will receive the EOL location - * @return A pointer to the EOL character(s) in "*eol". - */ -const guchar *find_line_end(const guchar *data, const guchar *dataend, - const guchar **eol); - -/** Get the length of the next token in a line, and the beginning of the - * next token after that (if any). - * @param linep A pointer to the beginning of the line - * @param lineend A pointer to the end of the line - * @param next_token Receives the location of the next token - * @return 0 if there is no next token. - */ -int get_token_len(const guchar *linep, const guchar *lineend, - const guchar **next_token); - -/** Given a string, generate a string from it that shows non-printable - * characters as C-style escapes, and return a pointer to it. - * - * @param line A pointer to the input string - * @param len The length of the input string - * @return A pointer to the formatted string - * - * @see tvb_format_text() - */ -gchar* format_text(const guchar *line, int len); - -gchar* format_text_wsp(const guchar *line, int len); - -/** Turn an array of bytes into a string showing the bytes in hex. - * - * @param bd A pointer to the byte array - * @param bd_len The length of the byte array - * @return A pointer to the formatted string - * - * @see bytes_to_str_punct() - */ -gchar* bytes_to_str(const guint8 *bd, int bd_len); - -/** Turn an array of bytes into a string showing the bytes in hex, - * separated by a punctuation character. - * - * @param bd A pointer to the byte array - * @param bd_len The length of the byte array - * @param punct The punctuation character - * @return A pointer to the formatted string - * - * @see bytes_to_str() - */ -gchar* bytes_to_str_punct(const guint8 *bd, int bd_len, gchar punct); - -/** Turn a string of hex digits with optional separators (defined by - * is_byte_sep() into a byte array. - * - * @param hex_str The string of hex digits. - * @param bytes The GByteArray that will receive the bytes. This - * must be initialized by the caller. - * @param force_separators If set to TRUE, separators MUST exist between - * bytes. - * @return True if the string was converted successfully - */ -gboolean hex_str_to_bytes(const char *hex_str, GByteArray *bytes, - gboolean force_separators); - -/** Turn an RFC 3986 percent-encoded string into a byte array. - * - * @param uri_str The string of hex digits. - * @param bytes The GByteArray that will receive the bytes. This - * must be initialized by the caller. - * @return True if the string was converted successfully - * @see format_uri() - */ -gboolean uri_str_to_bytes(const char *uri_str, GByteArray *bytes); - -/** Turn a byte array into an RFC 3986 percent-encoded string. - * - * @param bytes The GByteArray that will receive the bytes. This - * must be initialized by the caller. - * @param reserved_chars Normally the "gen-delims" and "sub-delims" - * from RFC 3986 (":/?#[]@" and "!$&'()*+,;=" respectively) - * plus space (hex value 20) are treated as reserved characters. - * If this variable is non-NULL, its contents will be used - * instead. - * @note Any non-printing character determined by isprint(), along - * with the % character itself are always reserved. - * @see uri_str_to_bytes(), format_text(), isprint() - */ -gchar* format_uri(const GByteArray *bytes, const gchar *reserved_chars); - -/** Turn a OID string representation (dot notation) into a byte array. - * - * @param oid_str The OID string (dot notaion). - * @param bytes The GByteArray that will receive the bytes. This - * must be initialized by the caller. - * @return True if the string was converted successfully - */ -gboolean oid_str_to_bytes(const char *oid_str, GByteArray *bytes); - -/** - * Create a copy of a GByteArray - * - * @param ba The byte array to be copied. - * @return If ba exists, a freshly allocated copy. NULL otherwise. - * - * XXX - Should this be in strutil.c? - */ -GByteArray *byte_array_dup(GByteArray *ba); - -/** - * Compare the contents of two GByteArrays - * - * @param ba1 A byte array - * @param ba2 A byte array - * @return If both arrays are non-NULL and their lengths are equal and - * their contents are equal, returns TRUE. Otherwise, returns - * FALSE. - * - * XXX - Should this be in strutil.c? - */ -gboolean byte_array_equal(GByteArray *ba1, GByteArray *ba2); - - -/** Return a XML escaped representation of the unescaped string. - * The returned string must be freed when no longer in use. - * - * @param unescaped The unescaped string - * @return An XML-escaped representation of the input string - */ -gchar* xml_escape(const gchar *unescaped); - -/** - * Return the first occurrence of needle in haystack. - * Algorithm copied from GNU's glibc 2.3.2 memcmp() - * - * @param haystack The data to search - * @param haystack_len The length of the search data - * @param needle The string to look for - * @param needle_len The length of the search string - * @return A pointer to the first occurrence of "needle" in - * "haystack". If "needle" isn't found or is NULL, or if - * "needle_len" is 0, NULL is returned. - */ -const guint8 * epan_memmem(const guint8 *haystack, guint haystack_len, - const guint8 *needle, guint needle_len); - -/* Surround a string or a macro, resolved to a string, with double quotes */ -#define _STRINGIFY(a) # a -#define STRINGIFY(a) _STRINGIFY(a) - -/** Scan a string to make sure it's valid hex. - * - * @param string The string to validate - * @param nbytes The length of the return buffer - * @return A pointer to a buffer containing the converted raw bytes. This - * buffer must be g_free()d by the caller. - */ -guint8 * convert_string_to_hex(const char *string, size_t *nbytes); - -/** Prep a string for case-sensitive vs case-insensitive searching. - * - * @param string The search string - * @param case_insensitive TRUE if case-insensitive, FALSE if not - * @return A direct copy of the string if it's a case-sensitive search and - * an uppercased version if not. In either case the string must be g_free()d - * by the caller. - */ -char * convert_string_case(const char *string, gboolean case_insensitive); - -/** Finds the first occurence of string 'needle' in string 'haystack'. - * The matching is done in a case insensitive manner. - * - * @param haystack The string possibly containing the substring - * @param needle The substring to be searched - * @return A pointer into 'haystack' where 'needle' is first found. - * Otherwise it returns NULL. - */ -char * epan_strcasestr(const char *haystack, const char *needle); - -/* g_strlcat() does not exist in GLib 1.2[.x] */ -#if GLIB_MAJOR_VERSION < 2 -gsize g_strlcat(gchar *dst, const gchar *src, gsize size); -gsize g_strlcpy(gchar *dest, const gchar *src, gsize dest_size); -#endif - -#if GLIB_MAJOR_VERSION < 2 -/* g_ascii_isprint() does not exist in GLib 1.2[.x]. - * assume all codes >=0x20 and <0x80 are ASCII printables. - */ -#define g_ascii_isprint(c) \ - (((c<0x20)||(c>=0x80))?FALSE:TRUE) -/* g_ascii_isxdigit() does not exist in Glib 1.2 */ -#define g_ascii_isxdigit(c) \ - ( ((c>='0')&&(c<='9'))?TRUE: \ - ( ((c>='a')&&(c<='f'))?TRUE: \ - (((c>='A')&&(c<='F'))?TRUE:FALSE) ) ) - -#endif - -#if GLIB_MAJOR_VERSION < 2 -/* g_byte_array_sized_new() doesnt exist in glib-1.2 */ -GByteArray *g_byte_array_sized_new(guint reserved_size); -#endif - -#endif /* __STRUTIL_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/t35.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/t35.h deleted file mode 100644 index 692c0b8d..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/t35.h +++ /dev/null @@ -1,35 +0,0 @@ -/* t35.h - * T.35 and H.221 tables - * 2003 Tomas Kukosa - * - * $Id: t35.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __T35_H__ -#define __T35_H__ - -#include "epan/value_string.h" - -extern const value_string T35CountryCode_vals[]; -extern const value_string T35Extension_vals[]; -extern const value_string H221ManufacturerCode_vals[]; - -#endif /* __T35_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tap-voip.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tap-voip.h deleted file mode 100644 index 21888588..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tap-voip.h +++ /dev/null @@ -1,59 +0,0 @@ -/* tap-voip.h - * VoIP packet tap interface 2007 Tomas Kukosa - * - * $Id: tap-voip.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef _TAP_VOIP_H_ -#define _TAP_VOIP_H_ - -/* defines voip call state */ -typedef enum _voip_call_state { - VOIP_NO_STATE, - VOIP_CALL_SETUP, - VOIP_RINGING, - VOIP_IN_CALL, - VOIP_CANCELLED, - VOIP_COMPLETED, - VOIP_REJECTED, - VOIP_UNKNOWN -} voip_call_state; - -typedef enum _voip_call_active_state { - VOIP_ACTIVE, - VOIP_INACTIVE -} voip_call_active_state; - -/* structure for common/proprietary VoIP calls TAP */ -typedef struct _voip_packet_info_t -{ - gchar *protocol_name; - gchar *call_id; - voip_call_state call_state; - voip_call_active_state call_active_state; - gchar *from_identity; - gchar *to_identity; - gchar *call_comment; - gchar *frame_label; - gchar *frame_comment; -} voip_packet_info_t; - -#endif /* _TAP_VOIP_H_ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tap.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tap.h deleted file mode 100644 index 11ca6fcb..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tap.h +++ /dev/null @@ -1,61 +0,0 @@ -/* tap.h - * packet tap interface 2002 Ronnie Sahlberg - * - * $Id: tap.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef _TAP_H_ -#define _TAP_H_ - -#include "epan/epan.h" - -#ifdef INTTYPES_H_DEFINES_FORMATS -#include -#endif - -/* With MSVC and a libwireshark.dll, we need a - * special declaration of num_tap_filters. - */ -WS_VAR_IMPORT int num_tap_filters; - -typedef void (*tap_reset_cb)(void *tapdata); -typedef int (*tap_packet_cb)(void *tapdata, packet_info *pinfo, epan_dissect_t *edt, const void *data); -typedef void (*tap_draw_cb)(void *tapdata); - - -extern void tap_init(void); -extern int register_tap(const char *name); -extern int find_tap_id(const char *name); -extern void tap_queue_packet(int tap_id, packet_info *pinfo, const void *tap_specific_data); -extern void tap_queue_init(epan_dissect_t *edt); -extern void tap_push_tapped_queue(epan_dissect_t *edt); -extern void reset_tap_listeners(void); -extern void draw_tap_listeners(gboolean draw_all); -extern GString *register_tap_listener(const char *tapname, void *tapdata, - const char *fstring, tap_reset_cb tap_reset, tap_packet_cb tap_packet, - tap_draw_cb tap_draw); -extern GString *set_tap_dfilter(void *tapdata, const char *fstring); -extern void remove_tap_listener(void *tapdata); -extern gboolean have_tap_listeners(void); -extern gboolean have_tap_listener(int tap_id); -extern const void *fetch_tapped_data(int tap_id, int idx); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tcap-persistentdata.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tcap-persistentdata.h deleted file mode 100644 index 4e9c278f..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tcap-persistentdata.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - * tcap-persistentdata.h - * Definitions for lists and hash tables used in wireshark's tcap dissector - * for calculation of delays in tcap-transactions - * Copyright 2006 Florent Drouin (based on h225-persistentdata from Lars Roland) - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * $Id: tcap-persistentdata.h 3992 2008-06-10 03:13:11Z dgu $ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __tcapsrt_HASH__ -#define __tcapsrt_HASH__ - -#include "epan/packet.h" -#include "epan/conversation.h" -#include "epan/dissectors/packet-tcap.h" - -#define LENGTH_OID 16 -struct tcaphash_context_t { - struct tcaphash_context_key_t * key; - guint32 session_id; - guint32 first_frame; - guint32 last_frame; - nstime_t begin_time; /* time of arrival of TC_BEGIN */ - nstime_t end_time; /* time of closing message */ - gboolean responded; /* true, if request has been responded */ - gboolean closed; - gboolean upper_dissector; - gboolean oid_present; - gchar oid[LENGTH_OID+1]; - gboolean subdissector_present; - dissector_handle_t subdissector_handle; - void (* callback) (tvbuff_t *,packet_info *, proto_tree *, struct tcaphash_context_t *); - struct tcaphash_begincall_t * begincall; - struct tcaphash_contcall_t * contcall; - struct tcaphash_endcall_t * endcall; - struct tcaphash_ansicall_t * ansicall; -}; - -struct tcaphash_begincall_t { - struct tcaphash_begin_info_key_t * beginkey; - struct tcaphash_context_t * context; - gboolean father; - struct tcaphash_begincall_t * next_begincall; - struct tcaphash_begincall_t * previous_begincall; -}; - -struct tcaphash_contcall_t { - struct tcaphash_cont_info_key_t * contkey; - struct tcaphash_context_t * context; - gboolean father; - struct tcaphash_contcall_t * next_contcall; - struct tcaphash_contcall_t * previous_contcall; -}; - -struct tcaphash_endcall_t { - struct tcaphash_end_info_key_t * endkey; - struct tcaphash_context_t * context; - gboolean father; - struct tcaphash_endcall_t * next_endcall; - struct tcaphash_endcall_t * previous_endcall; -}; - -struct tcaphash_ansicall_t { - struct tcaphash_ansi_info_key_t * ansikey; - struct tcaphash_context_t * context; - gboolean father; - struct tcaphash_ansicall_t * next_ansicall; - struct tcaphash_ansicall_t * previous_ansicall; -}; - -/* The Key for the hash table is the TCAP origine transaction identifier - of the TC_BEGIN containing the InitialDP */ - -struct tcaphash_context_key_t { - guint32 session_id; -}; - -struct tcaphash_begin_info_key_t { - guint32 hashKey; - guint32 tid; - guint32 opc_hash; - guint32 dpc_hash; -}; - -struct tcaphash_cont_info_key_t { - guint32 hashKey; - guint32 src_tid; - guint32 dst_tid; - guint32 opc_hash; - guint32 dpc_hash; -}; - -struct tcaphash_end_info_key_t { - guint32 hashKey; - guint32 tid; - guint32 opc_hash; - guint32 dpc_hash; -}; - -struct tcaphash_ansi_info_key_t { - guint32 hashKey; - guint32 tid; - guint32 opc_hash; - guint32 dpc_hash; -}; - - -/* List of infos to store for the analyse */ -struct tcapsrt_info_t { - guint32 tcap_session_id; - guint32 src_tid; - guint32 dst_tid; - guint8 ope; -}; - -void tcapsrt_init_routine(void); - -struct tcapsrt_info_t * tcapsrt_razinfo(void); - -void tcapsrt_close(struct tcaphash_context_t * p_tcaphash_context, - packet_info * pinfo _U_); - -struct tcaphash_context_t * tcapsrt_call_matching(tvbuff_t *tvb, - packet_info * pinfo _U_, - proto_tree *tree, - struct tcapsrt_info_t * p_tcap_info); - -WS_VAR_IMPORT gboolean gtcap_StatSRT; - -#endif /* __tcapsrt_HASH__*/ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tfs.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tfs.h deleted file mode 100644 index e77f0b9c..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tfs.h +++ /dev/null @@ -1,65 +0,0 @@ -/* tfs.h - * true_false strings - * Copyright 2007, Jaap Keuter - * - * $Id: tfs.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef __TFS_H__ -#define __TFS_H__ - -/* Struct for boolean enumerations */ -typedef struct true_false_string { - const char *true_string; - const char *false_string; -} true_false_string; - -/* - * A default set of true/false strings that dissectors can use for - * FT_BOOLEAN header fields. - */ -WS_VAR_IMPORT const true_false_string tfs_true_false; -WS_VAR_IMPORT const true_false_string tfs_yes_no; -WS_VAR_IMPORT const true_false_string tfs_set_notset; -WS_VAR_IMPORT const true_false_string tfs_enabled_disabled; -WS_VAR_IMPORT const true_false_string tfs_ok_error; -WS_VAR_IMPORT const true_false_string tfs_success_fail; -WS_VAR_IMPORT const true_false_string tfs_on_off; -WS_VAR_IMPORT const true_false_string tfs_ack_nack; -WS_VAR_IMPORT const true_false_string tfs_odd_even; -WS_VAR_IMPORT const true_false_string tfs_allow_block; -WS_VAR_IMPORT const true_false_string tfs_restricted_allowed; -WS_VAR_IMPORT const true_false_string tfs_accept_reject; -WS_VAR_IMPORT const true_false_string tfs_more_nomore; -WS_VAR_IMPORT const true_false_string tfs_present_absent; -WS_VAR_IMPORT const true_false_string tfs_active_inactive; -WS_VAR_IMPORT const true_false_string tfs_found_not_found; -WS_VAR_IMPORT const true_false_string tfs_command_response; -WS_VAR_IMPORT const true_false_string tfs_capable_not_capable; -WS_VAR_IMPORT const true_false_string tfs_supported_not_supported; - -/* - * Old true_false_string from packet.c - * Retained for backward compatibility until all dissectors are updated. - */ -WS_VAR_IMPORT const true_false_string flags_set_truth; - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/timestamp.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/timestamp.h deleted file mode 100644 index e357ee21..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/timestamp.h +++ /dev/null @@ -1,68 +0,0 @@ -/* timestamp.h - * Defines for packet timestamps - * - * $Id: timestamp.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __TIMESTAMP_H__ -#define __TIMESTAMP_H__ - -/* - * Type of time-stamp shown in the summary display. - */ -typedef enum { - TS_RELATIVE, /* Since start of capture */ - TS_ABSOLUTE, - TS_ABSOLUTE_WITH_DATE, - TS_DELTA, /* Since previous captured packet */ - TS_DELTA_DIS, /* Since previous displayed packet */ - TS_EPOCH, /* Seconds (and fractions) since epoch */ - -/* - * Special value used for the command-line setting in Wireshark, to indicate - * that no value has been set from the command line. - */ - TS_NOT_SET -} ts_type; - -typedef enum { - TS_PREC_AUTO, /* recent */ - TS_PREC_FIXED_SEC, /* recent and internal */ - TS_PREC_FIXED_DSEC, /* recent and internal */ - TS_PREC_FIXED_CSEC, /* recent and internal */ - TS_PREC_FIXED_MSEC, /* recent and internal */ - TS_PREC_FIXED_USEC, /* recent and internal */ - TS_PREC_FIXED_NSEC, /* recent and internal */ - TS_PREC_AUTO_SEC, /* internal */ - TS_PREC_AUTO_DSEC, /* internal */ - TS_PREC_AUTO_CSEC, /* internal */ - TS_PREC_AUTO_MSEC, /* internal */ - TS_PREC_AUTO_USEC, /* internal */ - TS_PREC_AUTO_NSEC /* internal */ -} ts_precision; - -extern ts_type timestamp_get_type(void); -extern void timestamp_set_type(ts_type); - -extern int timestamp_get_precision(void); -extern void timestamp_set_precision(int tsp); - -#endif /* timestamp.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/to_str.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/to_str.h deleted file mode 100644 index a1e8028b..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/to_str.h +++ /dev/null @@ -1,94 +0,0 @@ -/* to_str.h - * Definitions for utilities to convert various other types to strings. - * - * $Id: to_str.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __TO_STR_H__ -#define __TO_STR_H__ - -#include - -#include "nstime.h" -#include "epan/packet_info.h" - -#define GUID_STR_LEN 37 -#define MAX_IP_STR_LEN 16 -#define MAX_ADDR_STR_LEN 256 - -/* - * Resolution of a time stamp. - */ -typedef enum { - SECS, /* seconds */ - DSECS, /* deciseconds */ - CSECS, /* centiseconds */ - MSECS, /* milliseconds */ - USECS, /* microseconds */ - NSECS /* nanoseconds */ -} time_res_t; - -/* - * These are utility functions which convert various types to strings, - * but for which no more specific module applies. - */ - -struct e_in6_addr; - -extern gchar* address_to_str(const address *); -extern void address_to_str_buf(const address *addr, gchar *buf, int buf_len); -extern gchar* bytestring_to_str(const guint8 *, guint32, char); -extern gchar* ether_to_str(const guint8 *); -extern gchar* ip_to_str(const guint8 *); -extern void ip_to_str_buf(const guint8 *ad, gchar *buf, int buf_len); -extern gchar* fc_to_str(const guint8 *); -extern gchar* fcwwn_to_str (const guint8 *); -extern gchar* ip6_to_str(const struct e_in6_addr *); -extern void ip6_to_str_buf(const struct e_in6_addr *, gchar *); -extern gchar* ipx_addr_to_str(guint32, const guint8 *); -extern gchar* ipxnet_to_string(const guint8 *ad); -extern gchar* ipxnet_to_str_punct(const guint32 ad, char punct); -extern gchar* vines_addr_to_str(const guint8 *addrp); -extern void vines_addr_to_str_buf(const guint8 *addrp, gchar *buf, int buf_len); -extern gchar* time_secs_to_str(gint32); -extern gchar* time_msecs_to_str(gint32); -extern gchar* abs_time_to_str(nstime_t*); -extern gchar* abs_time_secs_to_str(time_t); -extern void display_signed_time(gchar *, int, gint32, gint32, time_res_t); -extern void display_epoch_time(gchar *, int, time_t, gint32, time_res_t); - -extern gchar* rel_time_to_str(nstime_t*); -extern gchar* rel_time_to_secs_str(nstime_t*); -extern gchar* guid_to_str(const e_guid_t*); -extern gchar* guid_to_str_buf(const e_guid_t*, gchar*, int); - -void tipc_addr_to_str_buf( const guint8 *data, gchar *buf, int buf_len); - -extern char *other_decode_bitfield_value(char *buf, guint32 val, guint32 mask, - int width); -extern char *decode_bitfield_value(char *buf, guint32 val, guint32 mask, - int width); -extern const char *decode_boolean_bitfield(guint32 val, guint32 mask, int width, - const char *truedesc, const char *falsedesc); -extern const char *decode_numeric_bitfield(guint32 val, guint32 mask, int width, - const char *fmt); - -#endif /* __TO_STR_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tvbparse.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tvbparse.h deleted file mode 100644 index 4e04a1b3..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tvbparse.h +++ /dev/null @@ -1,475 +0,0 @@ - -/* tvbparse.h -* -* an API for text tvb parsers -* -* Copyright 2005, Luis E. Garcia Ontanon -* -* $Id: tvbparse.h 3992 2008-06-10 03:13:11Z dgu $ -* -* Wireshark - Network traffic analyzer -* By Gerald Combs -* Copyright 1998 Gerald Combs -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version 2 -* of the License, or (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -/* - The intention behind this is to ease the writing of dissectors that have to - parse text without the need of writing into buffers. - - It was originally written to avoid using lex and yacc for the xml dissector. - - the parser is able to look for wanted elements these can be: - - simple tokens: - - a char out of a string of needles - - a char not belonging to a string of needles - - a sequence of chars that belong to a set of chars - - a sequence of chars that do not belong to a set of chars - - a string - - a caseless string - - all the characters up to a certain wanted element (included or excluded) - - composed elements: - - one of a given group of wanted elements - - a sequence of wanted elements - - some (at least one) instances of a wanted element - - Once a wanted element is successfully extracted, by either tvbparse_get or - tvbparse_find, the parser will invoke a given callback - before and another one after every of its component's subelement's callbacks - are being called. - - If tvbparse_get or tvbparse_find fail to extract the wanted element the - subelements callbacks are not going to be invoked. - - The wanted elements are instantiated once by the proto_register_xxx function. - - The parser is isntantiated for every packet and it mantains its state. - - The element's data is destroyed before the next packet is dissected. - */ - -#ifndef _TVB_PARSE_H_ -#define _TVB_PARSE_H_ - -#include -#include - -typedef struct _tvbparse_elem_t tvbparse_elem_t; -typedef struct _tvbparse_wanted_t tvbparse_wanted_t; -typedef struct _tvbparse_t tvbparse_t; - - -/* - * a callback function to be called before or after an element has been - * successfuly extracted. - * - * Note that if the token belongs to a composed token the callbacks of the - * components won't be called unless the composed token is successfully - * extracted. - * - * tvbparse_data: the private data of the parser - * wanted_data: the private data of the wanted element - * elem: the extracted element - */ -typedef void (*tvbparse_action_t)(void* tvbparse_data, const void* wanted_data, struct _tvbparse_elem_t* elem); - -typedef int (*tvbparse_condition_t) -(tvbparse_t*, int, - const tvbparse_wanted_t*, - tvbparse_elem_t**); - - -typedef enum { - TP_UNTIL_INCLUDE, /* last elem is included, its span is spent by the parser */ - TP_UNTIL_SPEND, /* last elem is not included, but its span is spent by the parser */ - TP_UNTIL_LEAVE /* last elem is not included, neither its span is spent by the parser */ -} until_mode_t; - - -struct _tvbparse_wanted_t { - int id; - tvbparse_condition_t condition; - - union { - const gchar* str; - struct _tvbparse_wanted_t** handle; - struct { - union { - gint64 i; - guint64 u; - gdouble f; - } value; - gboolean (*comp)(void*,const void*); - void* (*extract)(tvbuff_t*,guint); - } number; - enum ftenum ftenum; - struct { - until_mode_t mode; - const tvbparse_wanted_t* subelem; - } until; - struct { - GHashTable* table; - struct _tvbparse_wanted_t* key; - struct _tvbparse_wanted_t* other; - } hash; - GPtrArray* elems; - const tvbparse_wanted_t* subelem; - void* p; - } control; - - int len; - - guint min; - guint max; - - const void* data; - - tvbparse_action_t before; - tvbparse_action_t after; - -}; - -/* an instance of a per packet parser */ -struct _tvbparse_t { - tvbuff_t* tvb; - int offset; - int end_offset; - void* data; - const tvbparse_wanted_t* ignore; -}; - - -/* a matching token returned by either tvbparser_get or tvb_parser_find */ -struct _tvbparse_elem_t { - int id; - - tvbuff_t* tvb; - int offset; - int len; - - void* data; - - struct _tvbparse_elem_t* sub; - - struct _tvbparse_elem_t* next; - struct _tvbparse_elem_t* last; - - const tvbparse_wanted_t* wanted; -}; - - -/* - * definition of wanted token types - * - * the following functions define the tokens we will be able to look for in a tvb - * common parameters are: - * - * id: an arbitrary id that will be copied to the eventual token (don't use 0) - * private_data: persistent data to be passed to the callback action (wanted_data) - * before_cb: an callback function to be called before those of the subelements - * after_cb: an callback function to be called after those of the subelements - */ - - -/* - * a char element. - * - * When looked for it returns a simple element one character long if the char - * at the current offset matches one of the the needles. - */ -tvbparse_wanted_t* tvbparse_char(int id, - const gchar* needles, - const void* private_data, - tvbparse_action_t before_cb, - tvbparse_action_t after_cb); - -/* - * a not_char element. - * - * When looked for it returns a simple element one character long if the char - * at the current offset does not match one of the the needles. - */ -tvbparse_wanted_t* tvbparse_not_char(int id, - const gchar* needle, - const void* private_data, - tvbparse_action_t before_cb, - tvbparse_action_t after_cb); - -/* - * a chars element - * - * When looked for it returns a simple element one or more characters long if - * one or more char(s) starting from the current offset match one of the needles. - * An element will be returned if at least min_len chars are given (1 if it's 0) - * It will get at most max_len chars or as much as it can if max_len is 0. - */ -tvbparse_wanted_t* tvbparse_chars(int id, - guint min_len, - guint max_len, - const gchar* needles, - const void* private_data, - tvbparse_action_t before_cb, - tvbparse_action_t after_cb); - -/* - * a not_chars element - * - * When looked for it returns a simple element one or more characters long if - * one or more char(s) starting from the current offset do not match one of the - * needles. - * An element will be returned if at least min_len chars are given (1 if it's 0) - * It will get at most max_len chars or as much as it can if max_len is 0. - */ -tvbparse_wanted_t* tvbparse_not_chars(int id, - guint min_len, - guint max_len, - const gchar* needles, - const void* private_data, - tvbparse_action_t before_cb, - tvbparse_action_t after_cb); - -/* - * a string element - * - * When looked for it returns a simple element if we have the given string at - * the current offset - */ -tvbparse_wanted_t* tvbparse_string(int id, - const gchar* string, - const void* private_data, - tvbparse_action_t before_cb, - tvbparse_action_t after_cb); - -/* - * casestring - * - * When looked for it returns a simple element if we have a matching string at - * the current offset - */ -tvbparse_wanted_t* tvbparse_casestring(int id, - const gchar* str, - const void* data, - tvbparse_action_t before_cb, - tvbparse_action_t after_cb); - -/* - * until - * - * When looked for it returns a simple element containing all the characters - * found until the first match of the ending element if the ending element is - * found. - * - * When looking for until elements it calls tvbparse_find so it can be very slow. - * - * It won't have a subelement, the ending's callbacks won't get called. - */ - -/* - * op_mode values determine how the terminating element and the current offset - * of the parser are handled - */ -tvbparse_wanted_t* tvbparse_until(int id, - const void* private_data, - tvbparse_action_t before_cb, - tvbparse_action_t after_cb, - const tvbparse_wanted_t* ending, - until_mode_t until_mode); - -/* - * one_of - * - * When looked for it will try to match to the given candidates and return a - * composed element whose subelement is the first match. - * - * The list of candidates is terminated with a NULL - * - */ -tvbparse_wanted_t* tvbparse_set_oneof(int id, - const void* private_data, - tvbparse_action_t before_cb, - tvbparse_action_t after_cb, - ...); - -/* - * hashed - */ - -tvbparse_wanted_t* tvbparse_hashed(int id, - const void* data, - tvbparse_action_t before_cb, - tvbparse_action_t after_cb, - tvbparse_wanted_t* key, - tvbparse_wanted_t* other, - ...); - -void tvbparse_hashed_add(tvbparse_wanted_t* w, ...); - -/* - * sequence - * - * When looked for it will try to match in order all the given candidates. If - * every candidate is found in the given order it will return a composed - * element whose subelements are the matcheed elemets. - * - * The list of candidates is terminated with a NULL. - * - */ -tvbparse_wanted_t* tvbparse_set_seq(int id, - const void* private_data, - tvbparse_action_t before_cb, - tvbparse_action_t after_cb, - ...); -/* - * some - * - * When looked for it will try to match the given candidate at least min times - * and at most max times. If the given candidate is matched at least min times - * a composed element is returned. - * - */ -tvbparse_wanted_t* tvbparse_some(int id, - guint min, - guint max, - const void* private_data, - tvbparse_action_t before_cb, - tvbparse_action_t after_cb, - const tvbparse_wanted_t* wanted); - -#define tvbparse_one_or_more(id, private_data, before_cb, after_cb, wanted)\ - tvbparse_some(id, 1, G_MAXINT, private_data, before_cb, after_cb, wanted) - - -/* - * handle - * - * this is a pointer to a pointer to a wanted element (that might have not - * been initialized yet) so that recursive structures - */ -tvbparse_wanted_t* tvbparse_handle(tvbparse_wanted_t** handle); - -#if 0 - -enum ft_cmp_op { - TVBPARSE_CMP_GT, - TVBPARSE_CMP_GE, - TVBPARSE_CMP_EQ, - TVBPARSE_CMP_NE, - TVBPARSE_CMP_LE, - TVBPARSE_CMP_LT -}; - -/* not yet tested */ -tvbparse_wanted_t* tvbparse_ft(int id, - const void* data, - tvbparse_action_t before_cb, - tvbparse_action_t after_cb, - enum ftenum ftenum); - -/* not yet tested */ -tvbparse_wanted_t* tvbparse_end_of_buffer(int id, - const void* data, - tvbparse_action_t before_cb, - tvbparse_action_t after_cb); -/* not yet tested */ -tvbparse_wanted_t* tvbparse_ft_numcmp(int id, - const void* data, - tvbparse_action_t before_cb, - tvbparse_action_t after_cb, - enum ftenum ftenum, - int little_endian, - enum ft_cmp_op ft_cmp_op, - ... ); - -#endif - -/* quoted - * this is a composed candidate, that will try to match a quoted string - * (included the quotes) including into it every escaped quote. - * - * C strings are matched with tvbparse_quoted(-1,NULL,NULL,NULL,"\"","\\") - */ -tvbparse_wanted_t* tvbparse_quoted(int id, - const void* data, - tvbparse_action_t before_cb, - tvbparse_action_t after_cb, - char quote, - char escape); - -/* - * a helper callback for quoted strings that will shrink the token to contain - * only the string andnot the quotes - */ -void tvbparse_shrink_token_cb(void* tvbparse_data, - const void* wanted_data, - tvbparse_elem_t* tok); - - - - -/* initialize the parser (at every packet) -* tvb: what are we parsing? -* offset: from where -* len: for how many bytes -* private_data: will be passed to the action callbacks -* ignore: a wanted token type to be ignored (the associated cb WILL be called when it matches) -*/ -tvbparse_t* tvbparse_init(tvbuff_t* tvb, - int offset, - int len, - void* private_data, - const tvbparse_wanted_t* ignore); - -/* reset the parser */ -gboolean tvbparse_reset(tvbparse_t* tt, int offset, int len); - -guint tvbparse_curr_offset(tvbparse_t* tt); -guint tvbparse_len_left(tvbparse_t* tt); - - - -/* - * This will look for the wanted token at the current offset or after any given - * number of ignored tokens returning FALSE if there's no match or TRUE if there - * is a match. - * The parser will be left in its original state and no callbacks will be called. - */ -gboolean tvbparse_peek(tvbparse_t* tt, - const tvbparse_wanted_t* wanted); - -/* - * This will look for the wanted token at the current offset or after any given - * number of ignored tokens returning NULL if there's no match. - * if there is a match it will set the offset of the current parser after - * the end of the token - */ -tvbparse_elem_t* tvbparse_get(tvbparse_t* tt, - const tvbparse_wanted_t* wanted); - -/* - * Like tvbparse_get but this will look for a wanted token even beyond the - * current offset. - * This function is slow. - */ - -tvbparse_elem_t* tvbparse_find(tvbparse_t* tt, - const tvbparse_wanted_t* wanted); - - -void tvbparse_tree_add_elem(proto_tree* tree, tvbparse_elem_t* curr); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tvbuff.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tvbuff.h deleted file mode 100644 index fc1c28f9..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tvbuff.h +++ /dev/null @@ -1,634 +0,0 @@ -/* tvbuff.h - * - * Testy, Virtual(-izable) Buffer of guint8*'s - * - * "Testy" -- the buffer gets mad when an attempt is made to access data - * beyond the bounds of the buffer. An exception is thrown. - * - * "Virtual" -- the buffer can have its own data, can use a subset of - * the data of a backing tvbuff, or can be a composite of - * other tvbuffs. - * - * $Id: tvbuff.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Copyright (c) 2000 by Gilbert Ramirez - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __TVBUFF_H__ -#define __TVBUFF_H__ - -#include -#include -#include -#include "exceptions.h" - -#ifdef NEED_G_ASCII_STRCASECMP_H -#include "g_ascii_strcasecmp.h" -#endif - -/** @file - * "testy, virtual(-izable) buffer". They are testy in that they get mad when - * an attempt is made to access data beyond the bounds of their array. In that - * case, they throw an exception. - * - * They are virtualizable in that new tvbuff's can be made from other tvbuffs, - * while only the original tvbuff may have data. That is, the new tvbuff has - * virtual data. - */ - - -/** The different types of tvbuff's */ -typedef enum { - TVBUFF_REAL_DATA, - TVBUFF_SUBSET, - TVBUFF_COMPOSITE -} tvbuff_type; - -typedef struct { - /* The backing tvbuff_t */ - struct tvbuff *tvb; - - /* The offset/length of 'tvb' to which I'm privy */ - guint offset; - guint length; - -} tvb_backing_t; - -typedef struct { - GSList *tvbs; - - /* Used for quick testing to see if this - * is the tvbuff that a COMPOSITE is - * interested in. */ - guint *start_offsets; - guint *end_offsets; - -} tvb_comp_t; - -typedef void (*tvbuff_free_cb_t)(void*); - -typedef struct tvbuff { - /* Record-keeping */ - tvbuff_type type; - gboolean initialized; - guint usage_count; - struct tvbuff *ds_tvb; /* data source top-level tvbuff */ - - /* The tvbuffs in which this tvbuff is a member - * (that is, a backing tvbuff for a TVBUFF_SUBSET - * or a member for a TVB_COMPOSITE) */ - GSList *used_in; - - /* TVBUFF_SUBSET and TVBUFF_COMPOSITE keep track - * of the other tvbuff's they use */ - union { - tvb_backing_t subset; - tvb_comp_t composite; - } tvbuffs; - - /* We're either a TVBUFF_REAL_DATA or a - * TVBUFF_SUBSET that has a backing buffer that - * has real_data != NULL, or a TVBUFF_COMPOSITE - * which has flattened its data due to a call - * to tvb_get_ptr(). - */ - const guint8 *real_data; - - /* Length of virtual buffer (and/or real_data). */ - guint length; - - /* Reported length. */ - guint reported_length; - - /* Offset from beginning of first TVBUFF_REAL. */ - gint raw_offset; - - /* Func to call when actually freed */ - tvbuff_free_cb_t free_cb; -} tvbuff_t; - - - -/** TVBUFF_REAL_DATA contains a guint8* that points to real data. - * The data is allocated and contiguous. - * - * TVBUFF_SUBSET has a backing tvbuff. The TVBUFF_SUBSET is a "window" - * through which the program sees only a portion of the backing tvbuff. - * - * TVBUFF_COMPOSITE combines multiple tvbuffs sequentually to produce - * a larger byte array. - * - * tvbuff's of any type can be used as the backing-tvbuff of a - * TVBUFF_SUBSET or as the member of a TVBUFF_COMPOSITE. - * TVBUFF_COMPOSITEs can have member-tvbuffs of different types. - * - * Once a tvbuff is create/initialized/finalized, the tvbuff is read-only. - * That is, it cannot point to any other data. A new tvbuff must be created if - * you want a tvbuff that points to other data. - */ - - -/** "class" initialization. Called once during execution of program - * so that tvbuff.c can initialize its data. */ -extern void tvbuff_init(void); - -/** "class" cleanup. Called once during execution of program - * so that tvbuff.c can clean up its data. */ -extern void tvbuff_cleanup(void); - - -/** Returns a pointer to a newly initialized tvbuff. Note that - * tvbuff's of types TVBUFF_SUBSET and TVBUFF_COMPOSITE - * require further initialization via the appropriate functions */ -extern tvbuff_t* tvb_new(tvbuff_type); - -/** Marks a tvbuff for freeing. The guint8* data of a TVBUFF_REAL_DATA - * is *never* freed by the tvbuff routines. The tvbuff itself is actually freed - * once its usage count drops to 0. - * - * Usage counts increment for any time the tvbuff is - * used as a member of another tvbuff, i.e., as the backing buffer for - * a TVBUFF_SUBSET or as a member of a TVBUFF_COMPOSITE. - * - * Although you may call tvb_free(), the tvbuff may still be in use - * by other tvbuff's (TVBUFF_SUBSET or TVBUFF_COMPOSITE), so it is not - * safe, unless you know otherwise, to free your guint8* data. If you - * cannot be sure that your TVBUFF_REAL_DATA is not in use by another - * tvbuff, register a callback with tvb_set_free_cb(); when your tvbuff - * is _really_ freed, then your callback will be called, and at that time - * you can free your original data. - * - * The caller can artificially increment/decrement the usage count - * with tvbuff_increment_usage_count()/tvbuff_decrement_usage_count(). - */ -extern void tvb_free(tvbuff_t*); - -/** Free the tvbuff_t and all tvbuff's created from it. */ -extern void tvb_free_chain(tvbuff_t*); - -/** Both return the new usage count, after the increment or decrement */ -extern guint tvb_increment_usage_count(tvbuff_t*, guint count); - -/** If a decrement causes the usage count to drop to 0, a the tvbuff - * is immediately freed. Be sure you know exactly what you're doing - * if you decide to use this function, as another tvbuff could - * still have a pointer to the just-freed tvbuff, causing corrupted data - * or a segfault in the future */ -extern guint tvb_decrement_usage_count(tvbuff_t*, guint count); - -/** Set a callback function to call when a tvbuff is actually freed - * (once the usage count drops to 0). One argument is passed to - * that callback --- a void* that points to the real data. - * Obviously, this only applies to a TVBUFF_REAL_DATA tvbuff. */ -extern void tvb_set_free_cb(tvbuff_t*, tvbuff_free_cb_t); - - -/** Attach a TVBUFF_REAL_DATA tvbuff to a parent tvbuff. This connection - * is used during a tvb_free_chain()... the "child" TVBUFF_REAL_DATA acts - * as if is part of the chain-of-creation of the parent tvbuff, although it - * isn't. This is useful if you need to take the data from some tvbuff, - * run some operation on it, like decryption or decompression, and make a new - * tvbuff from it, yet want the new tvbuff to be part of the chain. The reality - * is that the new tvbuff *is* part of the "chain of creation", but in a way - * that these tvbuff routines is ignorant of. Use this function to make - * the tvbuff routines knowledgable of this fact. */ -extern void tvb_set_child_real_data_tvbuff(tvbuff_t* parent, tvbuff_t* child); - -/**Sets parameters for TVBUFF_REAL_DATA. Can throw ReportedBoundsError. */ -extern void tvb_set_real_data(tvbuff_t*, const guint8* data, guint length, - gint reported_length); - -/** Combination of tvb_new() and tvb_set_real_data(). Can throw ReportedBoundsError. */ -extern tvbuff_t* tvb_new_real_data(const guint8* data, guint length, - gint reported_length); - - -/** Define the subset of the backing buffer to use. - * - * 'backing_offset' can be negative, to indicate bytes from - * the end of the backing buffer. - * - * 'backing_length' can be 0, although the usefulness of the buffer would - * be rather limited. - * - * 'backing_length' of -1 means "to the end of the backing buffer" - * - * Will throw BoundsError if 'backing_offset'/'length' - * is beyond the bounds of the backing tvbuff. - * Can throw ReportedBoundsError. */ -extern void tvb_set_subset(tvbuff_t* tvb, tvbuff_t* backing, - gint backing_offset, gint backing_length, gint reported_length); - -/** Combination of tvb_new() and tvb_set_subset() - * Can throw ReportedBoundsError. */ -extern tvbuff_t* tvb_new_subset(tvbuff_t* backing, - gint backing_offset, gint backing_length, gint reported_length); - - -/** Both tvb_composite_append and tvb_composite_prepend can throw - * BoundsError if member_offset/member_length goes beyond bounds of - * the 'member' tvbuff. */ - -/** Append to the list of tvbuffs that make up this composite tvbuff */ -extern void tvb_composite_append(tvbuff_t* tvb, tvbuff_t* member); - -/** Prepend to the list of tvbuffs that make up this composite tvbuff */ -extern void tvb_composite_prepend(tvbuff_t* tvb, tvbuff_t* member); - -/** Helper function that calls tvb_new(TVBUFF_COMPOSITE). - * Provided only to maintain symmetry with other constructors */ -extern tvbuff_t* tvb_new_composite(void); - -/** Mark a composite tvbuff as initialized. No further appends or prepends - * occur, data access can finally happen after this finalization. */ -extern void tvb_composite_finalize(tvbuff_t* tvb); - - -/* Get total length of buffer */ -extern guint tvb_length(tvbuff_t*); - -/** Computes bytes to end of buffer, from offset (which can be negative, - * to indicate bytes from end of buffer). Function returns -1 to - * indicate that offset is out of bounds. No exception is thrown. */ -extern gint tvb_length_remaining(tvbuff_t*, gint offset); - -/** Same as above, but throws an exception if the offset is out of bounds. */ -extern guint tvb_ensure_length_remaining(tvbuff_t*, gint offset); - -/* Checks (w/o throwing exception) that the bytes referred to by - * 'offset'/'length' actually exist in the buffer */ -extern gboolean tvb_bytes_exist(tvbuff_t*, gint offset, gint length); - -/** Checks that the bytes referred to by 'offset'/'length' actually exist - * in the buffer, and throws an exception if they aren't. */ -extern void tvb_ensure_bytes_exist(tvbuff_t *tvb, gint offset, gint length); - -/* Checks (w/o throwing exception) that offset exists in buffer */ -extern gboolean tvb_offset_exists(tvbuff_t*, gint offset); - -/* Get reported length of buffer */ -extern guint tvb_reported_length(tvbuff_t*); - -/** Computes bytes of reported packet data to end of buffer, from offset - * (which can be negative, to indicate bytes from end of buffer). Function - * returns -1 to indicate that offset is out of bounds. No exception is - * thrown. */ -extern gint tvb_reported_length_remaining(tvbuff_t *tvb, gint offset); - -/** Set the reported length of a tvbuff to a given value; used for protocols - whose headers contain an explicit length and where the calling - dissector's payload may include padding as well as the packet for - this protocol. - - Also adjusts the data length. */ -extern void tvb_set_reported_length(tvbuff_t*, guint); - -extern int offset_from_real_beginning(tvbuff_t *tvb, int counter); - -/* Returns the offset from the first byte of real data. */ -#define TVB_RAW_OFFSET(tvb) \ - ((tvb->raw_offset==-1)?(tvb->raw_offset = offset_from_real_beginning(tvb, 0)):tvb->raw_offset) - -/************** START OF ACCESSORS ****************/ -/* All accessors will throw an exception if appropriate */ - -extern guint8 tvb_get_guint8(tvbuff_t*, gint offset); - -extern guint16 tvb_get_ntohs(tvbuff_t*, gint offset); -extern guint32 tvb_get_ntoh24(tvbuff_t*, gint offset); -extern guint32 tvb_get_ntohl(tvbuff_t*, gint offset); -extern guint64 tvb_get_ntoh64(tvbuff_t*, gint offset); -extern gfloat tvb_get_ntohieee_float(tvbuff_t*, gint offset); -extern gdouble tvb_get_ntohieee_double(tvbuff_t*, gint offset); - -extern guint16 tvb_get_letohs(tvbuff_t*, gint offset); -extern guint32 tvb_get_letoh24(tvbuff_t*, gint offset); -extern guint32 tvb_get_letohl(tvbuff_t*, gint offset); -extern guint64 tvb_get_letoh64(tvbuff_t*, gint offset); -extern gfloat tvb_get_letohieee_float(tvbuff_t*, gint offset); -extern gdouble tvb_get_letohieee_double(tvbuff_t*, gint offset); - -/** - * Fetch an IPv4 address, in network byte order. - * We do *not* convert it to host byte order; we leave it in - * network byte order, as that's what its callers expect. */ -extern guint32 tvb_get_ipv4(tvbuff_t*, gint offset); - -/* Fetch an IPv6 address. */ -extern void tvb_get_ipv6(tvbuff_t*, gint offset, struct e_in6_addr *addr); - -/* Fetch a GUID. */ -extern void tvb_get_ntohguid(tvbuff_t *tvb, gint offset, e_guid_t *guid); -extern void tvb_get_letohguid(tvbuff_t *tvb, gint offset, e_guid_t *guid); -extern void tvb_get_guid(tvbuff_t *tvb, gint offset, e_guid_t *guid, gboolean little_endian); - -/* Fetch a specified number of bits from bit offset in a tvb */ -extern guint8 tvb_get_bits8(tvbuff_t *tvb, gint bit_offset, gint no_of_bits); -extern guint16 tvb_get_bits16(tvbuff_t *tvb, gint bit_offset, gint no_of_bits, gboolean little_endian); -extern guint32 tvb_get_bits32(tvbuff_t *tvb, gint bit_offset, gint no_of_bits, gboolean little_endian); -extern guint64 tvb_get_bits64(tvbuff_t *tvb, gint bit_offset, gint no_of_bits, gboolean little_endian); - -/** Returns target for convenience. Does not suffer from possible - * expense of tvb_get_ptr(), since this routine is smart enough - * to copy data in chunks if the request range actually exists in - * different TVBUFF_REAL_DATA tvbuffs. This function assumes that the - * target memory is already allocated; it does not allocate or free the - * target memory. */ -extern void* tvb_memcpy(tvbuff_t*, void* target, gint offset, gint length); - -/** It is the user's responsibility to g_free() the memory allocated by - * tvb_memdup(). Calls tvb_memcpy() */ -extern void* tvb_memdup(tvbuff_t*, gint offset, gint length); - -/* Same as above but the buffer returned from this function does not have to -* be freed. It will be automatically freed after the packet is dissected. -* Buffers allocated by this function are NOT persistent. -*/ -extern void* ep_tvb_memdup(tvbuff_t *tvb, gint offset, gint length); - -/** WARNING! This function is possibly expensive, temporarily allocating - * another copy of the packet data. Furthermore, it's dangerous because once - * this pointer is given to the user, there's no guarantee that the user will - * honor the 'length' and not overstep the boundaries of the buffer. - * - * The returned pointer is data that is internal to the tvbuff, so do not - * attempt to free it. Don't modify the data, either, because another tvbuff - * that might be using this tvbuff may have already copied that portion of - * the data (sometimes tvbuff's need to make copies of data, but that's the - * internal implementation that you need not worry about). Assume that the - * guint8* points to read-only data that the tvbuff manages. - * - * Return a pointer into our buffer if the data asked for via 'offset'/'length' - * is contiguous (which might not be the case for TVBUFF_COMPOSITE). If the - * data is not contiguous, a tvb_memdup() is called for the entire buffer - * and the pointer to the newly-contiguous data is returned. This dynamically- - * allocated memory will be freed when the tvbuff is freed, after the - * tvbuff_free_cb_t() is called, if any. */ -extern const guint8* tvb_get_ptr(tvbuff_t*, gint offset, gint length); - -/** Find first occurence of any of the needles in tvbuff, starting at offset. - * Searches at most maxlength number of bytes; if maxlength is -1, searches - * to end of tvbuff. - * Returns the offset of the found needle, or -1 if not found. - * Will not throw an exception, even if maxlength exceeds boundary of tvbuff; - * in that case, -1 will be returned if the boundary is reached before - * finding needle. */ -extern gint tvb_find_guint8(tvbuff_t*, gint offset, gint maxlength, - guint8 needle); - -/** Find first occurence of any of the needles in tvbuff, starting at offset. - * Searches at most maxlength number of bytes. Returns the offset of the - * found needle, or -1 if not found. Will not throw an exception, even if - * maxlength exceeds boundary of tvbuff; in that case, -1 will be returned if - * the boundary is reached before finding needle. */ -extern gint tvb_pbrk_guint8(tvbuff_t *, gint offset, gint maxlength, - const guint8 *needles); - -/** Find size of stringz (NUL-terminated string) by looking for terminating - * NUL. The size of the string includes the terminating NUL. - * - * If the NUL isn't found, it throws the appropriate exception. - */ -extern guint tvb_strsize(tvbuff_t *tvb, gint offset); - -/** Find length of string by looking for end of zero terminated string, up to - * 'maxlength' characters'; if 'maxlength' is -1, searches to end - * of tvbuff. - * Returns -1 if 'maxlength' reached before finding EOS. */ -extern gint tvb_strnlen(tvbuff_t*, gint offset, guint maxlength); - -/** Convert a string from Unicode to ASCII. At the moment we fake it by - * assuming all characters are ASCII )-: The len parameter is the number - * of guint16's to convert from Unicode. - * - * tvb_fake_unicode() returns a buffer allocated by g_malloc() and must - * be g_free() by the caller. - * tvb_get_ephemeral_faked_unicode() returns a buffer that does not need - * to be explicitely freed. Instead this buffer is - * automatically freed when wireshark starts dissecting - * the next packet. - */ -extern char *tvb_fake_unicode(tvbuff_t *tvb, int offset, int len, - gboolean little_endian); -extern char *tvb_get_ephemeral_faked_unicode(tvbuff_t *tvb, int offset, int len, - gboolean little_endian); - -/** - * Format the data in the tvb from offset for size ... - */ -extern gchar * tvb_format_text(tvbuff_t *tvb, gint offset, gint size); - -/** - * Like "tvb_format_text()", but for 'wsp'; don't show - * the characters as C-style escapes. - */ -extern gchar * tvb_format_text_wsp(tvbuff_t *tvb, gint offset, gint size); - -/** - * Like "tvb_format_text()", but for null-padded strings; don't show - * the null padding characters as "\000". - */ -extern gchar *tvb_format_stringzpad(tvbuff_t *tvb, gint offset, gint size); - - -/** - * Given a tvbuff, an offset, and a length, allocate a buffer big enough - * to hold a non-null-terminated string of that length at that offset, - * plus a trailing zero, copy the string into it, and return a pointer - * to the string. - * - * Throws an exception if the tvbuff ends before the string does. - * - * tvb_get_string() returns a string allocated by g_malloc() and therefore - * MUST be g_free() by the caller in order not to leak - * memory. - * - * tvb_get_ephemeral_string() returns a string that does not need to be freed, - * instead it will automatically be freed once the next - * packet is dissected. - */ -extern guint8 *tvb_get_string(tvbuff_t *tvb, gint offset, gint length); -extern guint8 *tvb_get_ephemeral_string(tvbuff_t *tvb, gint offset, gint length); - - -/** - * Given a tvbuff and an offset, with the offset assumed to refer to - * a null-terminated string, find the length of that string (and throw - * an exception if the tvbuff ends before we find the null), allocate - * a buffer big enough to hold the string, copy the string into it, - * and return a pointer to the string. Also return the length of the - * string (including the terminating null) through a pointer. - * - * tvb_get_stringz() returns a string allocated by g_malloc() and therefore - * MUST be g_free() by the caller in order not to leak - * memory. - * - * tvb_get_ephemeral_stringz() returns a string that does not need to be freed, - * instead it will automatically be freed once the next - * packet is dissected. - */ -extern guint8 *tvb_get_stringz(tvbuff_t *tvb, gint offset, gint *lengthp); -extern guint8 *tvb_get_ephemeral_stringz(tvbuff_t *tvb, gint offset, gint *lengthp); - -/** Looks for a stringz (NUL-terminated string) in tvbuff and copies - * no more than bufsize number of bytes, including terminating NUL, to buffer. - * Returns length of string (not including terminating NUL), or -1 if the string was - * truncated in the buffer due to not having reached the terminating NUL. - * In this way, it acts like g_snprintf(). - * - * When processing a packet where the remaining number of bytes is less - * than bufsize, an exception is not thrown if the end of the packet - * is reached before the NUL is found. If no NUL is found before reaching - * the end of the short packet, -1 is still returned, and the string - * is truncated with a NUL, albeit not at buffer[bufsize - 1], but - * at the correct spot, terminating the string. - */ -extern gint tvb_get_nstringz(tvbuff_t *tvb, gint offset, guint bufsize, - guint8* buffer); - -/** Like tvb_get_nstringz(), but never returns -1. The string is guaranteed to - * have a terminating NUL. If the string was truncated when copied into buffer, - * a NUL is placed at the end of buffer to terminate it. - * - * bufsize MUST be greater than 0. - */ -extern gint tvb_get_nstringz0(tvbuff_t *tvb, gint offset, guint bufsize, - guint8* buffer); - -/** - * Given a tvbuff, an offset into the tvbuff, and a length that starts - * at that offset (which may be -1 for "all the way to the end of the - * tvbuff"), find the end of the (putative) line that starts at the - * specified offset in the tvbuff, going no further than the specified - * length. - * - * Return the length of the line (not counting the line terminator at - * the end), or, if we don't find a line terminator: - * - * if "deseg" is true, return -1; - * - * if "deseg" is false, return the amount of data remaining in - * the buffer. - * - * Set "*next_offset" to the offset of the character past the line - * terminator, or past the end of the buffer if we don't find a line - * terminator. (It's not set if we return -1.) - */ -extern gint tvb_find_line_end(tvbuff_t *tvb, gint offset, int len, - gint *next_offset, gboolean desegment); - -/** - * Given a tvbuff, an offset into the tvbuff, and a length that starts - * at that offset (which may be -1 for "all the way to the end of the - * tvbuff"), find the end of the (putative) line that starts at the - * specified offset in the tvbuff, going no further than the specified - * length. - * - * However, treat quoted strings inside the buffer specially - don't - * treat newlines in quoted strings as line terminators. - * - * Return the length of the line (not counting the line terminator at - * the end), or the amount of data remaining in the buffer if we don't - * find a line terminator. - * - * Set "*next_offset" to the offset of the character past the line - * terminator, or past the end of the buffer if we don't find a line - * terminator. - */ -extern gint tvb_find_line_end_unquoted(tvbuff_t *tvb, gint offset, int len, - gint *next_offset); - -/** - * Copied from the mgcp dissector. (This function should be moved to /epan ) - * tvb_skip_wsp - Returns the position in tvb of the first non-whitespace - * character following offset or offset + maxlength -1 whichever - * is smaller. - * - * Parameters: - * tvb - The tvbuff in which we are skipping whitespace. - * offset - The offset in tvb from which we begin trying to skip whitespace. - * maxlength - The maximum distance from offset that we may try to skip - * whitespace. - * - * Returns: The position in tvb of the first non-whitespace - * character following offset or offset + maxlength -1 whichever - * is smaller. - */ - -extern gint tvb_skip_wsp(tvbuff_t* tvb, gint offset, gint maxlength); - -extern gint tvb_skip_wsp_return(tvbuff_t* tvb, gint offset); - -/** - * Call strncmp after checking if enough chars left, returning 0 if - * it returns 0 (meaning "equal") and -1 otherwise, otherwise return -1. - */ -extern gint tvb_strneql(tvbuff_t *tvb, gint offset, const gchar *str, - gint size); - -/** - * Call g_ascii_strncasecmp after checking if enough chars left, returning - * 0 if it returns 0 (meaning "equal") and -1 otherwise, otherwise return -1. - */ -extern gint tvb_strncaseeql(tvbuff_t *tvb, gint offset, const gchar *str, - gint size); - -/** - * Call memcmp after checking if enough chars left, returning 0 if - * it returns 0 (meaning "equal") and -1 otherwise, otherwise return -1. - */ -extern gint tvb_memeql(tvbuff_t *tvb, gint offset, const guint8 *str, - gint size); - -/** - * Format a bunch of data from a tvbuff as bytes, returning a pointer - * to the string with the formatted data, with "punct" as a byte - * separator. - */ -extern gchar *tvb_bytes_to_str_punct(tvbuff_t *tvb, gint offset, gint len, - gchar punct); - -/* - * Format a bunch of data from a tvbuff as bytes, returning a pointer - * to the string with the formatted data. - */ -extern gchar *tvb_bytes_to_str(tvbuff_t *tvb, gint offset, gint len); - -#define TVB_GET_DS_TVB(tvb) \ - (tvb->ds_tvb) - -/** Locate a sub-tvbuff within another tvbuff, starting at position - * 'haystack_offset'. Returns the index of the beginning of 'needle' within - * 'haystack', or -1 if 'needle' is not found. The index is relative - * to the start of 'haystack', not 'haystack_offset'. */ -extern gint tvb_find_tvb(tvbuff_t *haystack_tvb, tvbuff_t *needle_tvb, - gint haystack_offset); - -/** - * Uncompresses a zlib compressed packet inside a tvbuff at offset with - * length comprlen. Returns an uncompressed tvbuffer if uncompression - * succeeded or NULL if uncompression failed. - */ -extern tvbuff_t* tvb_uncompress(tvbuff_t *tvb, int offset, int comprlen); - -/************** END OF ACCESSORS ****************/ - -#endif /* __TVBUFF_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat-int.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat-int.h deleted file mode 100644 index e875996b..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat-int.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * uat-int.h - * - * $Id: uat-int.h 3992 2008-06-10 03:13:11Z dgu $ - * - * User Accessible Tables - * Mantain an array of user accessible data strucures - * Internal interface - * - * (c) 2007, Luis E. Garcia Ontanon - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2001 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ -#ifndef _UAT_INT_H_ -#define _UAT_INT_H_ - -#include "uat.h" - -typedef struct _uat_fld_rep_t uat_fld_rep_t; -typedef struct _uat_rep_t uat_rep_t; - -typedef void (*uat_rep_fld_free_cb_t)(uat_fld_rep_t*); -typedef void (*uat_rep_free_cb_t)(uat_rep_t*); - -typedef struct _fld_data_t { - guint colnum; - uat_fld_rep_t* rep; - uat_rep_fld_free_cb_t free_rep; -} fld_data_t; - -struct _uat_t { - const char* name; - size_t record_size; - const char* filename; - gboolean from_profile; - const char* help; - const char* category; - void** user_ptr; - guint* nrows_p; - uat_copy_cb_t copy_cb; - uat_update_cb_t update_cb; - uat_free_cb_t free_cb; - - uat_field_t* fields; - guint ncols; - GArray* user_data; - gboolean changed; - uat_rep_t* rep; - uat_rep_free_cb_t free_rep; - gboolean loaded; -}; - -gchar* uat_get_actual_filename(uat_t* uat, gboolean for_writing); - -void uat_init(void); - -void uat_reset(void); - -void* uat_add_record(uat_t*, const void* orig_rec_ptr); - -void uat_swap(uat_t*, guint idx_a, guint idx_b); - -void uat_remove_record_idx(uat_t*, guint rec_idx); - -void uat_destroy(uat_t*); - -void uat_clear(uat_t*); - -gboolean uat_save(uat_t* , char** ); - -void uat_load_all(void); - -#define UAT_UPDATE(uat) do { *((uat)->user_ptr) = (void*)((uat)->user_data->data); *((uat)->nrows_p) = (uat)->user_data->len; } while(0) -#define UAT_INDEX_PTR(uat,idx) (uat->user_data->data + (uat->record_size * (idx))) -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat.h deleted file mode 100644 index d6952dae..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat.h +++ /dev/null @@ -1,486 +0,0 @@ -/* - * uat.h - * - * $Id: uat.h 3992 2008-06-10 03:13:11Z dgu $ - * - * User Accessible Tables - * Mantain an array of user accessible data strucures - * - * (c) 2007, Luis E. Garcia Ontanon - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2001 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef _UAT_H_ -#define _UAT_H_ - -/* - * uat mantains a dynamically allocated table accessible to the user - * via a file and/or gui tables. - * - * the file is located either in userdir(when first read or when writen) or - * in datadir for defaults (read only , it will be always written to userdir). - * - * the behaviour of the table is controlled by a series of callbacks - * the caller must provide. - * - * BEWARE that the user can change an uat at (almost) any time, - * That is pointers to records in an uat are valid only during the call - * to the function that obtains them (do not store them). - * - * UATs are meant for short tables of user data (passwords and such) there's - * no quick access, you must iterate through them each time to fetch the record - * you are looking for. Use uat_dup() or uat_se_dup() if necessary. - * - * Only users via gui or editing the file can add/remove records your code cannot. - */ - -/* obscure data type to handle an uat */ -typedef struct _uat_t uat_t; -/******************************************** - * Callbacks: - * these instruct uat on how to deal with user info and data in records - ********************************************/ - -/******** - * Callbacks for the entire table (these deal with entire records) - ********/ - -/* - * Copy CB - * used to copy a record - * optional, memcpy will be used if not given - * copy(dest,orig,len) - */ -typedef void* (*uat_copy_cb_t)(void*, const void*, unsigned); - -/* - * - * Free CB - * - * destroy a record's child data - * (do not free the container, it will be handled by uat) - * it is optional, no child data will be freed if no present - * free(record) - */ -typedef void (*uat_free_cb_t)(void*); - -/* - * Update CB - * - * to be called after all record fields has been updated - * optional, record will be updated always if not given - * update(record,&error) - */ -typedef void (*uat_update_cb_t)(void* , const char** ); - - -/******* - * Callbacks for single fields (these deal with single values) - * the caller should provide one of these for every field! - ********/ - -/* - * given an input string (ptr, len) checks if the value is OK for a field in the record. - * it will return TRUE if OK or else - * it will return FALSE and may set *error to inform the user on what's - * wrong with the given input - * optional, if not given any input is considered OK and the set cb will be called - * chk(record, ptr, len, chk_data, fld_data, &error) - */ -typedef gboolean (*uat_fld_chk_cb_t)(void*, const char*, unsigned, void*, void*, const char**); - -/* - * Set Field CB - * - * given an input string (ptr, len) sets the value of a field in the record, - * it will return TRUE if OK or else - * it will return FALSE and may set *error to inform the user on what's - * wrong with the given input - * it is mandatory - * set(record, ptr, len, set_data, fld_data) - */ -typedef void (*uat_fld_set_cb_t)(void*, const char*, unsigned, void*, void*); - -/* - * given a record returns a string representation of the field - * mandatory - * tostr(record, &out_ptr, &out_len, tostr_data, fld_data) - */ -typedef void (*uat_fld_tostr_cb_t)(void*, const char**, unsigned*, void*, void*); - -/*********** - * Text Mode - * - * used for file and dialog representation of fileds in columns, - * when the file is read it modifies the way the value is passed back to the fld_set_cb - * (see definition bellow for description) - ***********/ - -typedef enum _uat_text_mode_t { - PT_TXTMOD_NONE, - /* not used */ - - PT_TXTMOD_STRING, - /* - file: - reads: - ,"\x20\x00\x30", as " \00",3 - ,"", as "",0 - ,, as NULL,0 - writes: - ,"\x20\x30\x00\x20", for " 0\0 ",4 - ,"", for *, 0 - ,, for NULL, * - dialog: - accepts \x?? and other escapes - gets "",0 on empty string - */ - PT_TXTMOD_HEXBYTES, - /* - file: - reads: - ,A1b2C3d4, as "\001\002\003\004",4 - ,, as NULL,0 - writes: - ,, on NULL, * - ,a1b2c3d4, on "\001\002\003\004",4 - dialog: - "a1b2c3d4" as "\001\002\003\004",4 - "a1 b2:c3d4" as "\001\002\003\004",4 - "" as NULL,0 - "invalid" as NULL,3 - "a1b" as NULL, 1 - */ - PT_TXTMOD_ENUM -} uat_text_mode_t; - -/* - * Fields - * - * - */ -typedef struct _uat_field_t { - const char* name; - uat_text_mode_t mode; - - struct { - uat_fld_chk_cb_t chk; - uat_fld_set_cb_t set; - uat_fld_tostr_cb_t tostr; - } cb; - - struct { - void* chk; - void* set; - void* tostr; - } cbdata; - - void* fld_data; - - const char* desc; - struct _fld_data_t* priv; -} uat_field_t; - -#define FLDFILL NULL -#define UAT_END_FIELDS {0,PT_TXTMOD_NONE,{0,0,0},{0,0,0},0,0,FLDFILL} - - -#define UAT_CAT_GENERAL "General" -#define UAT_CAT_PORTS "Port Assignments" -#define UAT_CAT_CRYPTO "Decryption" -#define UAT_CAT_FFMT "File Formats" - -/** Create a new uat - * - * @param name The name of the table - * @param data_ptr A pointer to a null terminated array of pointers to the data - * @param default_data A pointer to a struct containing default values - * @param size The size of the structure - * @param filename The filename to be used (either in userdir or datadir) - * @param copy_cb A function that copies the data in the struct - * @param update_cb Will be called when a record is updated - * @param free_cb Will be called to destroy a struct in the dataset - * - * @return A freshly-allocated and populated uat_t struct. - */ -uat_t* uat_new(const char* name, - size_t size, - const char* filename, - gboolean from_profile, - void** data_ptr, - guint* num_items, - const char* category, - const char* help, - uat_copy_cb_t copy_cb, - uat_update_cb_t update_cb, - uat_free_cb_t free_cb, - uat_field_t* flds_array); - -/** Populate a uat using its file. - * - * @param uat_in Pointer to a uat. Must not be NULL. - * @param err Upon failure, points to an error string. - * - * @return TRUE on success, FALSE on failure. - */ -gboolean uat_load(uat_t* uat_in, char** err); - -/** Create or update a single uat entry using a string. - * - * @param uat_in Pointer to a uat. Must not be NULL. - * @param entry The string representation of the entry. Format must match - * what's written to the uat's output file. - * @param err Upon failure, points to an error string. - * - * @return TRUE on success, FALSE on failure. - */ -gboolean uat_load_str(uat_t* uat_in, char* entry, char** err); - -/** Given a uat name or filename, find its pointer. - * - * @param name The name or filename of the uat - * - * @return A pointer to the uat on success, NULL on failure. - */ -uat_t *uat_find(gchar *name); - -/* - * uat_dup() - * uat_se_dup() - * make a reliable copy of an uat for internal use, - * so that pointers to records can be kept through calls. - * return NULL on zero len. - */ -void* uat_dup(uat_t*, guint* len_p); /* to be freed */ -void* uat_se_dup(uat_t*, guint* len_p); -uat_t* uat_get_table_by_name(const char* name); - -/* - * Some common uat_fld_chk_cbs - */ -gboolean uat_fld_chk_str(void*, const char*, unsigned, void*,void*, const char** err); -gboolean uat_fld_chk_proto(void*, const char*, unsigned, void*,void*, const char** err); -gboolean uat_fld_chk_num_dec(void*, const char*, unsigned, void*, void*, const char** err); -gboolean uat_fld_chk_num_hex(void*, const char*, unsigned, void*, void*, const char** err); -gboolean uat_fld_chk_enum(void*, const char*, unsigned, void*, void*, const char**); -gboolean uat_fld_chk_range(void*, const char*, unsigned, void*, void*, const char**); - -#define CHK_STR_IS_DECL(what) \ -gboolean uat_fld_chk_str_ ## what (void*, const char*, unsigned, void*, void*, const char**) - -typedef void (*uat_cb_t)(void* uat,void* user_data); -void uat_foreach_table(uat_cb_t cb,void* user_data); -void uat_unload_all(void); - -char* uat_undquote(const char* si, guint in_len, guint* len_p); -char* uat_unbinstring(const char* si, guint in_len, guint* len_p); -char* uat_unesc(const char* si, guint in_len, guint* len_p); -char* uat_esc(const char* buf, guint len); - -/* Some strings entirely made of ... already declared */ -CHK_STR_IS_DECL(isprint); -CHK_STR_IS_DECL(isalpha); -CHK_STR_IS_DECL(isalnum); -CHK_STR_IS_DECL(isdigit); -CHK_STR_IS_DECL(isxdigit); - -#define CHK_STR_IS_DEF(what) \ -gboolean uat_fld_chk_str_ ## what (void* u1 _U_, const char* strptr, unsigned len, void* u2 _U_, void* u3 _U_, const char** err) { \ - guint i; for (i=0;i(field_name)) - */ -#define UAT_CSTRING_CB_DEF(basename,field_name,rec_t) \ -static void basename ## _ ## field_name ## _set_cb(void* rec, const char* buf, unsigned len, void* u1 _U_, void* u2 _U_) {\ - if ((((rec_t*)rec)->field_name)) g_free((((rec_t*)rec)->field_name)); \ - (((rec_t*)rec)->field_name) = g_strndup(buf,len); } \ -static void basename ## _ ## field_name ## _tostr_cb(void* rec, const char** out_ptr, unsigned* out_len, void* u1 _U_, void* u2 _U_) {\ - if (((rec_t*)rec)->field_name ) { \ - *out_ptr = (((rec_t*)rec)->field_name); *out_len = strlen((((rec_t*)rec)->field_name)); \ - } else { \ - *out_ptr = ""; *out_len = 0; } } - -#define UAT_FLD_CSTRING(basename,field_name,desc) \ - {#field_name, PT_TXTMOD_STRING,{uat_fld_chk_str,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{0,0,0},0,desc,FLDFILL} - -#define UAT_FLD_CSTRING_ISPRINT(basename,field_name,desc) \ - {#field_name, PT_TXTMOD_STRING,{uat_fld_chk_str_isprint,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{0,0,0},0,desc,FLDFILL} - -#define UAT_FLD_CSTRING_OTHER(basename,field_name,chk,desc) \ - {#field_name, PT_TXTMOD_STRING,{ chk ,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{0,0,0},0,desc,FLDFILL} - -/* - * LSTRING MACROS - */ -#define UAT_LSTRING_CB_DEF(basename,field_name,rec_t,ptr_element,len_element) \ -static void basename ## _ ## field_name ## _set_cb(void* rec, const char* buf, unsigned len, void* u1 _U_, void* u2 _U_) {\ - if ((((rec_t*)rec)->ptr_element)) g_free((((rec_t*)rec)->ptr_element)); \ - (((rec_t*)rec)->ptr_element) = uat_unesc(buf,len,&(((rec_t*)rec)->len_element)); }\ -static void basename ## _ ## field_name ## _tostr_cb(void* rec, const char** out_ptr, unsigned* out_len, void* u1 _U_, void* u2 _U_) {\ - if (((rec_t*)rec)->ptr_element ) { \ - *out_ptr = uat_esc(((rec_t*)rec)->ptr_element, (((rec_t*)rec)->len_element)); \ - *out_len = strlen(*out_ptr); \ - } else { \ - *out_ptr = ""; *out_len = 0; } } - -#define UAT_FLD_LSTRING(basename,field_name,desc) \ -{#field_name, PT_TXTMOD_STRING,{0,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{0,0,0},0,desc,FLDFILL} - - -/* - * BUFFER macros, - * a buffer_ptr contained in (((rec_t*)rec)->(field_name)) - * and its len in (((rec_t*)rec)->(len_name)) - * XXX: UNTESTED - */ -#define UAT_BUFFER_CB_DEF(basename,field_name,rec_t,ptr_element,len_element) \ -static void basename ## _ ## field_name ## _set_cb(void* rec, const char* buf, unsigned len, void* u1 _U_, void* u2 _U_) {\ - if ((((rec_t*)rec)->ptr_element) ) g_free((((rec_t*)rec)->ptr_element)); \ - (((rec_t*)rec)->ptr_element) = len ? g_memdup(buf,len) : NULL; \ - (((rec_t*)rec)->len_element) = len; } \ -static void basename ## _ ## field_name ## _tostr_cb(void* rec, const char** out_ptr, unsigned* out_len, void* u1 _U_, void* u2 _U_) {\ - *out_ptr = ((rec_t*)rec)->ptr_element ? ep_memdup(((rec_t*)rec)->ptr_element,((rec_t*)rec)->len_element) : ""; \ - *out_len = ((rec_t*)rec)->len_element; } - -#define UAT_FLD_BUFFER(basename,field_name,desc) \ - {#field_name, PT_TXTMOD_HEXBYTES,{0,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{0,0,0},0,desc,FLDFILL} - - -/* - * DEC Macros, - * a decimal number contained in - */ -#define UAT_DEC_CB_DEF(basename,field_name,rec_t) \ -static void basename ## _ ## field_name ## _set_cb(void* rec, const char* buf, unsigned len, void* u1 _U_, void* u2 _U_) {\ - ((rec_t*)rec)->field_name = strtol(ep_strndup(buf,len),NULL,10); } \ -static void basename ## _ ## field_name ## _tostr_cb(void* rec, const char** out_ptr, unsigned* out_len, void* u1 _U_, void* u2 _U_) {\ - *out_ptr = ep_strdup_printf("%d",((rec_t*)rec)->field_name); \ - *out_len = strlen(*out_ptr); } - -#define UAT_FLD_DEC(basename,field_name,desc) \ - {#field_name, PT_TXTMOD_STRING,{uat_fld_chk_num_dec,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{0,0,0},0,desc,FLDFILL} - - -/* - * HEX Macros, - * an hexadecimal number contained in - */ -#define UAT_HEX_CB_DEF(basename,field_name,rec_t) \ -static void basename ## _ ## field_name ## _set_cb(void* rec, const char* buf, unsigned len, void* u1 _U_, void* u2 _U_) {\ - ((rec_t*)rec)->field_name = strtol(ep_strndup(buf,len),NULL,16); } \ -static void basename ## _ ## field_name ## _tostr_cb(void* rec, const char** out_ptr, unsigned* out_len, void* u1 _U_, void* u2 _U_) {\ - *out_ptr = ep_strdup_printf("%x",((rec_t*)rec)->field_name); \ - *out_len = strlen(*out_ptr); } - -#define UAT_FLD_HEX(basename,field_name,desc) \ -{#field_name, PT_TXTMOD_STRING,{uat_fld_chk_num_hex,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{0,0,0},0,desc,FLDFILL} - - -/* - * ENUM macros - * enum_t: name = ((enum_t*)ptr)->strptr - * value = ((enum_t*)ptr)->value - * rec_t: - * value - */ -#define UAT_VS_DEF(basename,field_name,rec_t,default_val,default_str) \ -static void basename ## _ ## field_name ## _set_cb(void* rec, const char* buf, unsigned len, void* vs, void* u2 _U_) {\ - guint i; \ - char* str = ep_strndup(buf,len); \ - const char* cstr; ((rec_t*)rec)->field_name = default_val; \ - for(i=0; ( cstr = ((value_string*)vs)[i].strptr ) ;i++) { \ - if (g_str_equal(cstr,str)) { \ - ((rec_t*)rec)->field_name = ((value_string*)vs)[i].value; return; } } } \ -static void basename ## _ ## field_name ## _tostr_cb(void* rec, const char** out_ptr, unsigned* out_len, void* vs, void* u2 _U_) {\ - guint i; \ - *out_ptr = ep_strdup(default_str); *out_len = strlen(default_str);\ - for(i=0;((value_string*)vs)[i].strptr;i++) { \ - if ( ((value_string*)vs)[i].value == ((rec_t*)rec)->field_name ) { \ - *out_ptr = ep_strdup(((value_string*)vs)[i].strptr); \ - *out_len = strlen(*out_ptr); return; } } } - - -#define UAT_FLD_VS(basename,field_name,enum,desc) \ - {#field_name, PT_TXTMOD_ENUM,{uat_fld_chk_enum,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{&(enum),&(enum),&(enum)},&(enum),desc,FLDFILL} - - -/* - * PROTO macros - */ - -#define UAT_PROTO_DEF(basename, field_name, dissector_field, name_field, rec_t) \ -static void basename ## _ ## field_name ## _set_cb(void* rec, const char* buf, unsigned len, void* u1 _U_, void* u2 _U_) {\ - if (len) { \ - ((rec_t*)rec)->name_field = ep_strndup(buf,len); g_strdown(((rec_t*)rec)->name_field ); g_strchug(((rec_t*)rec)->name_field); \ - ((rec_t*)rec)->dissector_field = find_dissector(((rec_t*)rec)->name_field); \ - } else { \ - ((rec_t*)rec)->dissector_field = find_dissector("data"); \ - ((rec_t*)rec)->name_field = NULL; \ - } } \ -static void basename ## _ ## field_name ## _tostr_cb(void* rec, const char** out_ptr, unsigned* out_len, void* u1 _U_, void* u2 _U_) {\ - if ( ((rec_t*)rec)->name_field ) { \ - *out_ptr = (((rec_t*)rec)->name_field); \ - *out_len = strlen(*out_ptr); \ - } else { \ - *out_ptr = ""; *out_len = 0; } } - - -#define UAT_FLD_PROTO(basename,field_name,desc) \ - {#field_name, PT_TXTMOD_STRING,{uat_fld_chk_proto,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{0,0,0},0,desc,FLDFILL} - -/* - * RANGE macros - */ - -#define UAT_RANGE_CB_DEF(basename,field_name,rec_t) \ -static void basename ## _ ## field_name ## _set_cb(void* rec, const char* buf, unsigned len, void* u1 _U_, void* u2) {\ - char* rng = ep_strndup(buf,len);\ - range_convert_str(&(((rec_t*)rec)->field_name), rng,GPOINTER_TO_UINT(u2)); \ - } \ -static void basename ## _ ## field_name ## _tostr_cb(void* rec, const char** out_ptr, unsigned* out_len, void* u1 _U_, void* u2 _U_) {\ - if ( ((rec_t*)rec)->field_name ) { \ - *out_ptr = range_convert_range(((rec_t*)rec)->field_name); *out_len = strlen(*out_ptr); \ - } else { \ - *out_ptr = ""; *out_len = 0; } } - - -#define UAT_FLD_RANGE(basename,field_name,max,desc) \ - {#field_name, PT_TXTMOD_STRING,{uat_fld_chk_range,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},\ - {GUINT_TO_POINTER(max),GUINT_TO_POINTER(max),GUINT_TO_POINTER(max)},0,desc,FLDFILL} - - - - - -#endif - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat_load_lex.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat_load_lex.h deleted file mode 100644 index a8d694b1..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat_load_lex.h +++ /dev/null @@ -1,6 +0,0 @@ -/* This is generated by runlex.sh. Do not edit it. */ -#define yylex uat_load_lex -#ifndef YY_DECL -#define YY_DECL int yylex(void) -#endif -YY_DECL; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/unicode-utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/unicode-utils.h deleted file mode 100644 index b3962ae6..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/unicode-utils.h +++ /dev/null @@ -1,54 +0,0 @@ -/* unicode-utils.h - * Unicode utility definitions - * - * $Id: unicode-utils.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2006 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __UNICODEUTIL_H__ -#define __UNICODEUTIL_H__ - -#ifdef _WIN32 - -/** - * @file Unicode convenience routines. - */ - -/** Given a UTF-8 string, convert it to UTF-16. This is meant to be used - * to convert between GTK+ 2.x (UTF-8) to Windows (UTF-16). - * - * @param utf8str The string to convert. May be NULL. - * @return The string converted to UTF-16. If utf8str is NULL, returns - * NULL. The return value should NOT be freed by the caller. - */ -wchar_t * utf_8to16(const char *utf8str); - -/** Given a UTF-16 string, convert it to UTF-8. This is meant to be used - * to convert between GTK+ 2.x (UTF-8) to Windows (UTF-16). - * - * @param utf16str The string to convert. May be NULL. - * @return The string converted to UTF-8. If utf16str is NULL, returns - * NULL. The return value should NOT be freed by the caller. - */ -gchar * utf_16to8(const wchar_t *utf16str); - -#endif /* _WIN32 */ - -#endif /* __UNICODEUTIL_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/value_string.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/value_string.h deleted file mode 100644 index 86a2f1e6..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/value_string.h +++ /dev/null @@ -1,88 +0,0 @@ -/* value_string.h - * Definitions for value_string structures and routines - * - * $Id: value_string.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __VALUE_STRING_H__ -#define __VALUE_STRING_H__ - -#include - -/* Struct for the val_to_str, match_strval_idx, and match_strval functions */ - -typedef struct _value_string { - guint32 value; - const gchar *strptr; -} value_string; - -/* Struct for the rval_to_str, match_strrval_idx, and match_strrval functions */ -typedef struct _range_string { - guint32 value_min; - guint32 value_max; - const gchar *strptr; -} range_string; - -/* #define VS_DEF(x) { x, #x } */ -/* #define VS_END { 0, NULL } */ - -/* Tries to match val against each element in the value_string array vs. - Returns the associated string ptr, and sets "*idx" to the index in - that table, on a match, and returns NULL, and sets "*idx" to -1, - on failure. */ -extern const gchar* match_strval_idx(guint32 val, const value_string *vs, gint *idx); - -/* Like match_strval_idx(), but doesn't return the index. */ -extern const gchar* match_strval(guint32 val, const value_string *vs); - -/* Tries to match val against each element in the value_string array vs. - Returns the associated string ptr on a match. - Formats val with fmt, and returns the resulting string, on failure. */ -extern const gchar* val_to_str(guint32 val, const value_string *vs, const char *fmt); - -/* Generate a string describing an enumerated bitfield (an N-bit field - with various specific values having particular names). */ -extern const char *decode_enumerated_bitfield(guint32 val, guint32 mask, - int width, const value_string *tab, const char *fmt); - -/* Generate a string describing an enumerated bitfield (an N-bit field - with various specific values having particular names). */ -extern const char *decode_enumerated_bitfield_shifted(guint32 val, guint32 mask, - int width, const value_string *tab, const char *fmt); - - -/* ranges aware versions */ - -/* Tries to match val against each range in the range_string array rs. - Returns the associated string ptr on a match. - Formats val with fmt, and returns the resulting string, on failure. */ -extern const gchar* rval_to_str(guint32 val, const range_string *rs, const char *fmt); - -/* Tries to match val against each range in the range_string array rs. - Returns the associated string ptr, and sets "*idx" to the index in - that table, on a match, and returns NULL, and sets "*idx" to -1, - on failure. */ -extern const gchar *match_strrval_idx(guint32 val, const range_string *rs, gint *idx); - -/* Like match_strrval_idx(), but doesn't return the index. */ -extern const gchar *match_strrval(guint32 val, const range_string *rs); - -#endif /* __VALUE_STRING_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ws_strsplit.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ws_strsplit.h deleted file mode 100644 index b2108c79..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ws_strsplit.h +++ /dev/null @@ -1,41 +0,0 @@ -/* ws_strsplit.h - * String Split utility function - * Code borrowed from GTK2 to override the GTK1 version of g_strsplit, which is - * known to be buggy. - * - * $Id: ws_strsplit.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __WS_STRSPLIT_H__ -#define __WS_STRSPLIT_H__ - -#if GLIB_MAJOR_VERSION < 2 - -#define g_strsplit(s, d, t) ws_strsplit(s, d, t) - -gchar ** ws_strsplit (const gchar *string, - const gchar *delimiter, - gint max_tokens); - -#endif /* GLIB_MAJOR_VERSION */ - -#endif /* __WS_STRSPLIT_H__ */ - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/wslua/declare_wslua.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/wslua/declare_wslua.h deleted file mode 100644 index d403ce65..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/wslua/declare_wslua.h +++ /dev/null @@ -1,59 +0,0 @@ -/* This file is automatically genrated by make-reg.pl do not edit */ - -#define WSLUA_DECLARE_CLASSES() \ - WSLUA_CLASS_DECLARE(ByteArray);\ - WSLUA_CLASS_DECLARE(Tvb);\ - WSLUA_CLASS_DECLARE(TvbRange);\ - WSLUA_CLASS_DECLARE(Pref);\ - WSLUA_CLASS_DECLARE(Prefs);\ - WSLUA_CLASS_DECLARE(ProtoField);\ - WSLUA_CLASS_DECLARE(Proto);\ - WSLUA_CLASS_DECLARE(Dissector);\ - WSLUA_CLASS_DECLARE(DissectorTable);\ - WSLUA_CLASS_DECLARE(TreeItem);\ - WSLUA_CLASS_DECLARE(Address);\ - WSLUA_CLASS_DECLARE(Column);\ - WSLUA_CLASS_DECLARE(Columns);\ - WSLUA_CLASS_DECLARE(Pinfo);\ - WSLUA_CLASS_DECLARE(Listener);\ - WSLUA_CLASS_DECLARE(TextWindow);\ - WSLUA_CLASS_DECLARE(Dir);\ - WSLUA_CLASS_DECLARE(FieldInfo);\ - WSLUA_CLASS_DECLARE(Field);\ - WSLUA_CLASS_DECLARE(PseudoHeader);\ - WSLUA_CLASS_DECLARE(Dumper);\ - - -#define WSLUA_DECLARE_FUNCTIONS() \ - WSLUA_FUNCTION wslua_register_postdissector(lua_State* L);\ - WSLUA_FUNCTION wslua_gui_enabled(lua_State* L);\ - WSLUA_FUNCTION wslua_register_menu(lua_State* L);\ - WSLUA_FUNCTION wslua_new_dialog(lua_State* L);\ - WSLUA_FUNCTION wslua_retap_packets(lua_State* L);\ - WSLUA_FUNCTION wslua_copy_to_clipboard(lua_State* L);\ - WSLUA_FUNCTION wslua_open_capture_file(lua_State* L);\ - WSLUA_FUNCTION wslua_set_filter(lua_State* L);\ - WSLUA_FUNCTION wslua_apply_filter(lua_State* L);\ - WSLUA_FUNCTION wslua_reload(lua_State* L);\ - WSLUA_FUNCTION wslua_browser_open_url(lua_State* L);\ - WSLUA_FUNCTION wslua_browser_open_data_file(lua_State* L);\ - WSLUA_FUNCTION wslua_format_date(lua_State* L);\ - WSLUA_FUNCTION wslua_format_time(lua_State* L);\ - WSLUA_FUNCTION wslua_report_failure(lua_State* L);\ - WSLUA_FUNCTION wslua_critical(lua_State* L);\ - WSLUA_FUNCTION wslua_warn(lua_State* L);\ - WSLUA_FUNCTION wslua_message(lua_State* L);\ - WSLUA_FUNCTION wslua_info(lua_State* L);\ - WSLUA_FUNCTION wslua_debug(lua_State* L);\ - WSLUA_FUNCTION wslua_loadfile(lua_State* L);\ - WSLUA_FUNCTION wslua_dofile(lua_State* L);\ - WSLUA_FUNCTION wslua_persconffile_path(lua_State* L);\ - WSLUA_FUNCTION wslua_datafile_path(lua_State* L);\ - WSLUA_FUNCTION wslua_register_stat_cmd_arg(lua_State* L);\ - WSLUA_FUNCTION wslua_all_field_infos(lua_State* L);\ - - -extern void wslua_register_classes(lua_State* L); -extern void wslua_register_functions(lua_State* L); - - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/wslua/wslua.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/wslua/wslua.h deleted file mode 100644 index a58fba23..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/wslua/wslua.h +++ /dev/null @@ -1,372 +0,0 @@ -/* - * wslua.h - * - * Wireshark's interface to the Lua Programming Language - * - * (c) 2006, Luis E. Garcia Ontanon - * (c) 2007, Tamas Regos - * - * $Id: wslua.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef _PACKET_LUA_H -#define _PACKET_LUA_H - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if GLIB_MAJOR_VERSION < 2 -#include -#endif - -#include "declare_wslua.h" - -#define WSLUA_INIT_ROUTINES "init_routines" -#define LOG_DOMAIN_LUA "wslua" - -struct _wslua_tvbrange { - tvbuff_t* tvb; - int offset; - int len; -}; - -typedef struct _wslua_field_t { - int hfid; - int ett; - char* name; - char* abbr; - char* blob; - enum ftenum type; - base_display_e base; - value_string* vs; - guint32 mask; -} wslua_field_t; - -/* - * PREF_OBSOLETE is used for preferences that a module used to support - * but no longer supports; we give different error messages for them. - */ -typedef enum { - PREF_UINT, - PREF_BOOL, - PREF_ENUM, - PREF_STRING, - PREF_RANGE, - PREF_STATIC_TEXT, - PREF_OBSOLETE -} pref_type_t; - -typedef struct _wslua_pref_t { - gchar* name; - gchar* label; - gchar* desc; - pref_type_t type; - union { - gboolean b; - guint u; - const gchar* s; - gint e; - range_t *r; - void* p; - } value; - union { - guint32 max_value; /* maximum value of a range */ - struct { - const enum_val_t *enumvals; /* list of name & values */ - gboolean radio_buttons; /* TRUE if it should be shown as - radio buttons rather than as an - option menu or combo box in - the preferences tab */ - } enum_info; /* for PREF_ENUM */ - } info; /* display/text file information */ - - struct _wslua_pref_t* next; - struct _wslua_proto_t* proto; -} wslua_pref_t; - -typedef struct _wslua_proto_t { - gchar* name; - gchar* desc; - int hfid; - int ett; - wslua_pref_t prefs; - int fields; - module_t *prefs_module; - dissector_handle_t handle; - gboolean is_postdissector; -} wslua_proto_t; - -struct _wslua_distbl_t { - dissector_table_t table; - gchar* name; -}; - -struct _wslua_col_info { - column_info* cinfo; - gint col; -}; - -struct _wslua_treeitem { - proto_item* item; - proto_tree* tree; -}; - -typedef void (*tap_extractor_t)(lua_State*,const void*); - -struct _wslua_tap { - gchar* name; - gchar* filter; - tap_extractor_t extractor; - lua_State* L; - int packet_ref; - int draw_ref; - int init_ref; -}; - -#if GLIB_MAJOR_VERSION < 2 -# define DIRECTORY_T DIR -# define FILE_T struct dirent -# define OPENDIR_OP(name) opendir(name) -# define DIRGETNEXT_OP(dir) readdir(dir) -# define GETFNAME_OP(file) (gchar *)file->d_name -# define CLOSEDIR_OP(dir) closedir(dir) -#else /* GLIB 2 */ -# define DIRECTORY_T GDir -# define FILE_T gchar -# define OPENDIR_OP(name) g_dir_open(name, 0, dir->dummy) -# define DIRGETNEXT_OP(dir) g_dir_read_name(dir) -# define GETFNAME_OP(file) (file); -# define CLOSEDIR_OP(dir) g_dir_close(dir) -#endif - -struct _wslua_dir { - DIRECTORY_T* dir; - char* ext; -#if GLIB_MAJOR_VERSION >= 2 - GError** dummy; -#endif - -}; - -typedef struct { const char* name; tap_extractor_t extractor; } tappable_t; - -typedef struct {const gchar* str; enum ftenum id; } wslua_ft_types_t; - -typedef wslua_pref_t* Pref; -typedef wslua_pref_t* Prefs; -typedef struct _wslua_field_t* ProtoField; -typedef struct _wslua_proto_t* Proto; -typedef struct _wslua_distbl_t* DissectorTable; -typedef dissector_handle_t Dissector; -typedef GByteArray* ByteArray; -typedef tvbuff_t* Tvb; -typedef struct _wslua_tvbrange* TvbRange; -typedef struct _wslua_col_info* Column; -typedef column_info* Columns; -typedef packet_info* Pinfo; -typedef struct _wslua_treeitem* TreeItem; -typedef address* Address; -typedef header_field_info** Field; -typedef field_info* FieldInfo; -typedef struct _wslua_tap* Listener; -typedef funnel_text_window_t* TextWindow; -typedef wtap_dumper* Dumper; -typedef struct lua_pseudo_header* PseudoHeader; -typedef tvbparse_t* Parser; -typedef tvbparse_wanted_t* Rule; -typedef tvbparse_elem_t* Node; -typedef tvbparse_action_t* Shortcut; -typedef struct _wslua_main* WireShark; -typedef struct _wslua_dir* Dir; - -/* - * toXxx(L,idx) gets a Xxx from an index (Lua Error if fails) - * checkXxx(L,idx) gets a Xxx from an index after calling check_code (No Lua Error if it fails) - * pushXxx(L,xxx) pushes an Xxx into the stack - * isXxx(L,idx) tests whether we have an Xxx at idx - * - * LUA_CLASS_DEFINE must be used without trailing ';' - */ -#define WSLUA_CLASS_DEFINE(C,check_code,push_code) \ -C to##C(lua_State* L, int index) { \ - C* v = (C*)lua_touserdata (L, index); \ - if (!v) luaL_typerror(L,index,#C); \ - return *v; \ -} \ -C check##C(lua_State* L, int index) { \ - C* p; \ - luaL_checktype(L,index,LUA_TUSERDATA); \ - p = (C*)luaL_checkudata(L, index, #C); \ - check_code; \ - return p ? *p : NULL; \ -} \ -C* push##C(lua_State* L, C v) { \ - C* p = lua_newuserdata(L,sizeof(C)); *p = v; \ - luaL_getmetatable(L, #C); lua_setmetatable(L, -2); \ - push_code; \ - return p; \ -}\ -gboolean is##C(lua_State* L,int i) { \ - void *p; \ - if(!lua_isuserdata(L,i)) return FALSE; \ - p = lua_touserdata(L, i); \ - lua_getfield(L, LUA_REGISTRYINDEX, #C); \ - if (p == NULL || !lua_getmetatable(L, i) || !lua_rawequal(L, -1, -2)) p=NULL; \ - lua_pop(L, 2); \ - return p ? TRUE : FALSE; \ -} \ -C shift##C(lua_State* L,int i) { \ - C* p; \ - if(!lua_isuserdata(L,i)) return NULL; \ - p = lua_touserdata(L, i); \ - lua_getfield(L, LUA_REGISTRYINDEX, #C); \ - if (p == NULL || !lua_getmetatable(L, i) || !lua_rawequal(L, -1, -2)) p=NULL; \ - lua_pop(L, 2); \ - if (p) { lua_remove(L,i); return *p; }\ - else return NULL;\ -} \ -int dummy##C - -#ifdef HAVE_LUA_5_1 - -#define WSLUA_REGISTER_CLASS(C) { \ - luaL_register (L, #C, C ## _methods); \ - luaL_newmetatable (L, #C); \ - luaL_register (L, NULL, C ## _meta); \ - lua_pushliteral(L, "__index"); \ - lua_pushvalue(L, -3); \ - lua_rawset(L, -3); \ - lua_pushliteral(L, "__metatable"); \ - lua_pushvalue(L, -3); \ - lua_rawset(L, -3); \ - lua_pop(L, 1); \ -} - -#define WSLUA_REGISTER_META(C) luaL_newmetatable (L, #C); luaL_register (L, NULL, C ## _meta); - -#define WSLUA_INIT(L) \ - luaL_openlibs(L); \ - wslua_register_classes(L); \ - wslua_register_functions(L); - - -#endif - -#define WSLUA_FUNCTION extern int -#define WSLUA_REGISTER_FUNCTION(name) { lua_pushstring(L, #name); lua_pushcfunction(L, wslua_## name); lua_settable(L, LUA_GLOBALSINDEX); } -#define WSLUA_REGISTER extern int - -#define WSLUA_METHOD static int -#define WSLUA_CONSTRUCTOR static int -#define WSLUA_ATTR_SET static int -#define WSLUA_ATTR_GET static int -#define WSLUA_METAMETHOD static int - -#define WSLUA_METHODS static const luaL_reg -#define WSLUA_META static const luaL_reg -#define WSLUA_CLASS_FNREG(class,name) { #name, class##_##name } - -#define WSLUA_ERROR(name,error) { luaL_error(L, ep_strdup_printf("%s%s", #name ": " ,error) ); return 0; } -#define WSLUA_ARG_ERROR(name,attr,error) { luaL_argerror(L,WSLUA_ARG_ ## name ## _ ## attr, #name ": " error); return 0; } -#define WSLUA_OPTARG_ERROR(name,attr,error) { luaL_argerror(L,WSLUA_OPTARG_##name##_ ##attr, #name ": " error); return 0; } - -#define WSLUA_REG_GLOBAL_BOOL(L,n,v) { lua_pushstring(L,n); lua_pushboolean(L,v); lua_settable(L, LUA_GLOBALSINDEX); } -#define WSLUA_REG_GLOBAL_STRING(n,v) { lua_pushstring(L,n); lua_pushstring(L,v); lua_settable(L, LUA_GLOBALSINDEX); } -#define WSLUA_REG_GLOBAL_NUMBER(n,v) { lua_pushstring(L,n); lua_pushnumber(L,v); lua_settable(L, LUA_GLOBALSINDEX); } - -#define WSLUA_RETURN(i) return (i); - -#define WSLUA_API extern - -#define NOP -#define FAIL_ON_NULL(s) if (! *p) luaL_argerror(L,index,s) - - - -#define WSLUA_CLASS_DECLARE(C) \ -extern C to##C(lua_State* L, int index); \ -extern C check##C(lua_State* L, int index); \ -extern C* push##C(lua_State* L, C v); \ -extern int C##_register(lua_State* L); \ -extern gboolean is##C(lua_State* L,int i); \ -extern C shift##C(lua_State* L,int i) - - -extern packet_info* lua_pinfo; -extern TreeItem lua_tree; -extern tvbuff_t* lua_tvb; -extern int lua_malformed; -extern dissector_handle_t lua_data_handle; -extern gboolean lua_initialized; -extern int lua_dissectors_table_ref; - -WSLUA_DECLARE_CLASSES() -WSLUA_DECLARE_FUNCTIONS() - -extern lua_State* wslua_state(void); - -extern gboolean wslua_optbool(lua_State* L, int n, gboolean def); -extern const gchar* lua_shiftstring(lua_State* L,int idx); -extern int dissect_lua(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree); - -extern void proto_register_lua(void); -extern GString* lua_register_all_taps(void); -extern void lua_prime_all_fields(proto_tree* tree); - -extern int Proto_commit(lua_State* L); - -extern void* push_Tvb(lua_State* L, Tvb tvb); -extern void clear_outstanding_tvbs(void); - -extern void* push_Pinfo(lua_State* L, Pinfo p); -extern void clear_outstanding_pinfos(void); - -extern void* push_TreeItem(lua_State* L, TreeItem ti); -extern void clear_outstanding_trees(void); - -extern void wslua_print_stack(char* s, lua_State* L); - -extern int wslua_init(lua_State* L); - -extern tap_extractor_t wslua_get_tap_extractor(const gchar* name); -extern int wslua_set_tap_enums(lua_State* L); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/x264_prt_id.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/x264_prt_id.h deleted file mode 100644 index 7be6bc0b..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/x264_prt_id.h +++ /dev/null @@ -1,35 +0,0 @@ -/* x264_prt_id.h - * Definitions of X.264/ISO 11570 transport protocol IDs - * - * $Id: x264_prt_id.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __X264_PRT_ID_H__ -#define __X264_PRT_ID_H__ - -/* X.264 / ISO 11570 transport protocol ID values. */ - -#define PRT_ID_ISO_8073 0x01 /* X.224/ISO 8073 COTP */ -#define PRT_ID_ISO_8602 0x02 /* X.234/ISO 8602 CLTP */ -#define PRT_ID_ISO_10736_ISO_8073 0x03 /* X.274/ISO 10736 + X.224/ISO 8073 */ -#define PRT_ID_ISO_10736_ISO_8602 0x04 /* X.274/ISO 10736 + X.234/ISO 8602 */ - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/xdlc.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/xdlc.h deleted file mode 100644 index b9265f7e..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/xdlc.h +++ /dev/null @@ -1,140 +0,0 @@ -/* xdlc.h - * Define *DLC frame types, and routine to dissect the control field of - * a *DLC frame. - * - * $Id: xdlc.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __XDLC_H__ -#define __XDLC_H__ - -/* - * Low-order bits of first (extended) or only (basic) octet of control - * field, specifying the frame type. - */ -#define XDLC_I_MASK 0x01 /* Mask to test for I or not I */ -#define XDLC_I 0x00 /* Information frames */ -#define XDLC_S_U_MASK 0x03 /* Mask to test for S or U */ -#define XDLC_S 0x01 /* Supervisory frames */ -#define XDLC_U 0x03 /* Unnumbered frames */ - -/* - * N(S) and N(R) fields, in basic and extended operation. - */ -#define XDLC_N_R_MASK 0xE0 /* basic */ -#define XDLC_N_R_SHIFT 5 -#define XDLC_N_R_EXT_MASK 0xFE00 /* extended */ -#define XDLC_N_R_EXT_SHIFT 9 -#define XDLC_N_S_MASK 0x0E /* basic */ -#define XDLC_N_S_SHIFT 1 -#define XDLC_N_S_EXT_MASK 0x00FE /* extended */ -#define XDLC_N_S_EXT_SHIFT 1 - -/* - * Poll/Final bit, in basic and extended operation. - */ -#define XDLC_P_F 0x10 /* basic */ -#define XDLC_P_F_EXT 0x0100 /* extended */ - -/* - * S-format frame types. - */ -#define XDLC_S_FTYPE_MASK 0x0C -#define XDLC_RR 0x00 /* Receiver ready */ -#define XDLC_RNR 0x04 /* Receiver not ready */ -#define XDLC_REJ 0x08 /* Reject */ -#define XDLC_SREJ 0x0C /* Selective reject */ - -/* - * U-format modifiers. - */ -#define XDLC_U_MODIFIER_MASK 0xEC -#define XDLC_UI 0x00 /* Unnumbered Information */ -#define XDLC_UP 0x20 /* Unnumbered Poll */ -#define XDLC_DISC 0x40 /* Disconnect (command) */ -#define XDLC_RD 0x40 /* Request Disconnect (response) */ -#define XDLC_UA 0x60 /* Unnumbered Acknowledge */ -#define XDLC_SNRM 0x80 /* Set Normal Response Mode */ -#define XDLC_TEST 0xE0 /* Test */ -#define XDLC_SIM 0x04 /* Set Initialization Mode (command) */ -#define XDLC_RIM 0x04 /* Request Initialization Mode (response) */ -#define XDLC_FRMR 0x84 /* Frame reject */ -#define XDLC_CFGR 0xC4 /* Configure */ -#define XDLC_SARM 0x0C /* Set Asynchronous Response Mode (command) */ -#define XDLC_DM 0x0C /* Disconnected mode (response) */ -#define XDLC_SABM 0x2C /* Set Asynchronous Balanced Mode */ -#define XDLC_SARME 0x4C /* Set Asynchronous Response Mode Extended */ -#define XDLC_SABME 0x6C /* Set Asynchronous Balanced Mode Extended */ -#define XDLC_RESET 0x8C /* Reset */ -#define XDLC_XID 0xAC /* Exchange identification */ -#define XDLC_SNRME 0xCC /* Set Normal Response Mode Extended */ -#define XDLC_BCN 0xEC /* Beacon */ - -/* - * This macro takes the control field of an xDLC frame, as returned by - * "get_xdlc_control()" or "dissect_xdlc_control()", and evaluates to - * TRUE if the frame is an "information" frame and FALSE if it isn't. - * Note that frames other than information frames can have data in them, - * e.g. TEST frames. - */ -#define XDLC_IS_INFORMATION(control) \ - (((control) & XDLC_I_MASK) == XDLC_I || (control) == (XDLC_UI|XDLC_U)) - -/* - * This macro takes the control field of an xDLC frame, and a flag saying - * whether we're doing basic or extended operation, and evaluates to - * the length of that field (if it's an Unnumbered frame, or we're not - * in extended mode, it's 1 byte long, otherwise it's 2 bytes long). - */ -#define XDLC_CONTROL_LEN(control, is_extended) \ - ((((control) & XDLC_S_U_MASK) == XDLC_U || !(is_extended)) ? 1 : 2) - -/* - * Structure containing pointers to hf_ values for various subfields of - * the control field. - */ -typedef struct { - int *hf_xdlc_n_r; - int *hf_xdlc_n_s; - int *hf_xdlc_p; - int *hf_xdlc_f; - int *hf_xdlc_s_ftype; - int *hf_xdlc_u_modifier_cmd; - int *hf_xdlc_u_modifier_resp; - int *hf_xdlc_ftype_i; - int *hf_xdlc_ftype_s_u; -} xdlc_cf_items; - -extern const value_string ftype_vals[]; -extern const value_string stype_vals[]; -extern const value_string modifier_vals_cmd[]; -extern const value_string modifier_vals_resp[]; - -extern int get_xdlc_control(const guchar *pd, int offset, int extended); - -extern int dissect_xdlc_control(tvbuff_t *tvb, int offset, packet_info *pinfo, - proto_tree *xdlc_tree, int hf_xdlc_control, gint ett_xdlc_control, - const xdlc_cf_items *cf_items_nonext, const xdlc_cf_items *cf_items_ext, - const value_string *u_modifier_short_vals_cmd, - const value_string *u_modifier_short_vals_resp, int is_response, - int is_extended, int append_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/xmlstub.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/xmlstub.h deleted file mode 100644 index feb7e278..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/xmlstub.h +++ /dev/null @@ -1,1123 +0,0 @@ -/* - * This is part of tree.h from the libxml2 distribution. It is used - * for structure reference when dynamically linking to libxml. - * - * The GPL agreement for this file and for libxml2 can be found at - * http://www.xmlsoft.org - */ - -#include "config.h" - -/****************** specific to wireshark ********************************/ -/* - * Uncomment the following line to restore XML_DO_VALIDITY_CHECKING - * behavior which is causing issues on WIN32 platforms. See: - * http://www.ethereal.com/lists/ethereal-dev/200410/msg00194.html - */ -/* #define WIRESHARK_XML_DO_VALIDITY_CHECKING */ -/****************** From xml headers ************************************/ - -/* - * use those to be sure nothing nasty will happen if - * your library and includes mismatch - */ -#ifndef LIBXML2_COMPILING_MSCCDEF -extern void xmlCheckVersion(int version); -#endif /* LIBXML2_COMPILING_MSCCDEF */ -#define LIBXML_DOTTED_VERSION "2.3.8" -#define LIBXML_VERSION 20308 -#define LIBXML_VERSION_STRING "20308" -#define LIBXML_TEST_VERSION xmlCheckVersion(20308); - -/* - * Whether the trio support need to be configured in - */ -#if 0 -#define WITH_TRIO -#else -#define WITHOUT_TRIO -#endif - -/* - * Whether the FTP support is configured in - */ -#if 1 -#define LIBXML_FTP_ENABLED -#else -#define LIBXML_FTP_DISABLED -#endif - -/* - * Whether the HTTP support is configured in - */ -#if 1 -#define LIBXML_HTTP_ENABLED -#else -#define LIBXML_HTTP_DISABLED -#endif - -/* - * Whether the HTML support is configured in - */ -#if 1 -#define LIBXML_HTML_ENABLED -#else -#define LIBXML_HTML_DISABLED -#endif - -/* - * Whether the SGML Docbook support is configured in - */ -#if 1 -#define LIBXML_DOCB_ENABLED -#else -#define LIBXML_DOCB_DISABLED -#endif - -/* - * Whether XPath is configured in - */ -#if 1 -#define LIBXML_XPATH_ENABLED -#else -#define LIBXML_XPATH_DISABLED -#endif - -/* - * Whether XPointer is configured in - */ -#if 1 -#define LIBXML_XPTR_ENABLED -#else -#define LIBXML_XPTR_DISABLED -#endif - -/* - * Whether XInclude is configured in - */ -#if 1 -#define LIBXML_XINCLUDE_ENABLED -#else -#define LIBXML_XINCLUDE_DISABLED -#endif - -/* - * Whether iconv support is available - */ -#ifdef HAVE_ICONV -#define LIBXML_ICONV_ENABLED -#include -#else -#define LIBXML_ICONV_DISABLED -#endif - -/* - * Whether Debugging module is configured in - */ -#if 1 -#define LIBXML_DEBUG_ENABLED -#else -#define LIBXML_DEBUG_DISABLED -#endif - -/* - * Whether the memory debugging is configured in - */ -#if 0 -#define DEBUG_MEMORY_LOCATION -#endif - -#ifndef LIBXML_DLL_IMPORT -#if defined(_WIN32) && !defined(STATIC) -#define LIBXML_DLL_IMPORT __declspec(dllimport) -#else -#define LIBXML_DLL_IMPORT -#endif -#endif - -#ifdef __GNUC__ -#ifdef HAVE_ANSIDECL_H -#include -#endif -#ifndef ATTRIBUTE_UNUSED -#define ATTRIBUTE_UNUSED -#endif -#else -#define ATTRIBUTE_UNUSED -#endif - - -#define XML_XML_NAMESPACE \ - (const xmlChar *) "http://www.w3.org/XML/1998/namespace" - -/* - * The different element types carried by an XML tree - * - * NOTE: This is synchronized with DOM Level1 values - * See http://www.w3.org/TR/REC-DOM-Level-1/ - * - * Actually this had diverged a bit, and now XML_DOCUMENT_TYPE_NODE should - * be deprecated to use an XML_DTD_NODE. - */ -typedef enum { - XML_ELEMENT_NODE= 1, - XML_ATTRIBUTE_NODE= 2, - XML_TEXT_NODE= 3, - XML_CDATA_SECTION_NODE= 4, - XML_ENTITY_REF_NODE= 5, - XML_ENTITY_NODE= 6, - XML_PI_NODE= 7, - XML_COMMENT_NODE= 8, - XML_DOCUMENT_NODE= 9, - XML_DOCUMENT_TYPE_NODE= 10, - XML_DOCUMENT_FRAG_NODE= 11, - XML_NOTATION_NODE= 12, - XML_HTML_DOCUMENT_NODE= 13, - XML_DTD_NODE= 14, - XML_ELEMENT_DECL= 15, - XML_ATTRIBUTE_DECL= 16, - XML_ENTITY_DECL= 17, - XML_NAMESPACE_DECL= 18, - XML_XINCLUDE_START= 19, - XML_XINCLUDE_END= 20 -#ifdef LIBXML_DOCB_ENABLED - ,XML_DOCB_DOCUMENT_NODE= 21 -#endif -} xmlElementType; - -/* - * Size of an internal character representation. - * - * We use 8bit chars internal representation for memory efficiency, - * Note that with 8 bits wide xmlChars one can still use UTF-8 to handle - * correctly non ISO-Latin input. - */ - -typedef unsigned char xmlChar; - -#ifndef _WIN32 -#ifndef CHAR -#define CHAR xmlChar -#endif -#endif - -#define BAD_CAST (xmlChar *) - -/* - * a DTD Notation definition - */ - -typedef struct _xmlNotation xmlNotation; -typedef xmlNotation *xmlNotationPtr; -struct _xmlNotation { - const xmlChar *name; /* Notation name */ - const xmlChar *PublicID; /* Public identifier, if any */ - const xmlChar *SystemID; /* System identifier, if any */ -}; - -/* - * a DTD Attribute definition - */ - -typedef enum { - XML_ATTRIBUTE_CDATA = 1, - XML_ATTRIBUTE_ID, - XML_ATTRIBUTE_IDREF , - XML_ATTRIBUTE_IDREFS, - XML_ATTRIBUTE_ENTITY, - XML_ATTRIBUTE_ENTITIES, - XML_ATTRIBUTE_NMTOKEN, - XML_ATTRIBUTE_NMTOKENS, - XML_ATTRIBUTE_ENUMERATION, - XML_ATTRIBUTE_NOTATION -} xmlAttributeType; - -typedef enum { - XML_ATTRIBUTE_NONE = 1, - XML_ATTRIBUTE_REQUIRED, - XML_ATTRIBUTE_IMPLIED, - XML_ATTRIBUTE_FIXED -} xmlAttributeDefault; - -typedef struct _xmlEnumeration xmlEnumeration; -typedef xmlEnumeration *xmlEnumerationPtr; -struct _xmlEnumeration { - struct _xmlEnumeration *next; /* next one */ - const xmlChar *name; /* Enumeration name */ -}; - -typedef struct _xmlAttribute xmlAttribute; -typedef xmlAttribute *xmlAttributePtr; -struct _xmlAttribute { -#ifndef XML_WITHOUT_CORBA - void *_private; /* for Corba, must be first ! */ -#endif - xmlElementType type; /* XML_ATTRIBUTE_DECL, must be second ! */ - const xmlChar *name; /* Attribute name */ - struct _xmlNode *children; /* NULL */ - struct _xmlNode *last; /* NULL */ - struct _xmlDtd *parent; /* -> DTD */ - struct _xmlNode *next; /* next sibling link */ - struct _xmlNode *prev; /* previous sibling link */ - struct _xmlDoc *doc; /* the containing document */ - - struct _xmlAttribute *nexth; /* next in hash table */ - xmlAttributeType atype; /* The attribute type */ - xmlAttributeDefault def; /* the default */ - const xmlChar *defaultValue; /* or the default value */ - xmlEnumerationPtr tree; /* or the enumeration tree if any */ - const xmlChar *prefix; /* the namespace prefix if any */ - const xmlChar *elem; /* Element holding the attribute */ -}; - -/* - * a DTD Element definition. - */ -typedef enum { - XML_ELEMENT_CONTENT_PCDATA = 1, - XML_ELEMENT_CONTENT_ELEMENT, - XML_ELEMENT_CONTENT_SEQ, - XML_ELEMENT_CONTENT_OR -} xmlElementContentType; - -typedef enum { - XML_ELEMENT_CONTENT_ONCE = 1, - XML_ELEMENT_CONTENT_OPT, - XML_ELEMENT_CONTENT_MULT, - XML_ELEMENT_CONTENT_PLUS -} xmlElementContentOccur; - -typedef struct _xmlElementContent xmlElementContent; -typedef xmlElementContent *xmlElementContentPtr; -struct _xmlElementContent { - xmlElementContentType type; /* PCDATA, ELEMENT, SEQ or OR */ - xmlElementContentOccur ocur; /* ONCE, OPT, MULT or PLUS */ - const xmlChar *name; /* Element name */ - struct _xmlElementContent *c1; /* first child */ - struct _xmlElementContent *c2; /* second child */ - struct _xmlElementContent *parent; /* parent */ -}; - -typedef enum { - XML_ELEMENT_TYPE_UNDEFINED = 0, - XML_ELEMENT_TYPE_EMPTY = 1, - XML_ELEMENT_TYPE_ANY, - XML_ELEMENT_TYPE_MIXED, - XML_ELEMENT_TYPE_ELEMENT -} xmlElementTypeVal; - -typedef struct _xmlElement xmlElement; -typedef xmlElement *xmlElementPtr; -struct _xmlElement { -#ifndef XML_WITHOUT_CORBA - void *_private; /* for Corba, must be first ! */ -#endif - xmlElementType type; /* XML_ELEMENT_DECL, must be second ! */ - const xmlChar *name; /* Element name */ - struct _xmlNode *children; /* NULL */ - struct _xmlNode *last; /* NULL */ - struct _xmlDtd *parent; /* -> DTD */ - struct _xmlNode *next; /* next sibling link */ - struct _xmlNode *prev; /* previous sibling link */ - struct _xmlDoc *doc; /* the containing document */ - - xmlElementTypeVal etype; /* The type */ - xmlElementContentPtr content; /* the allowed element content */ - xmlAttributePtr attributes; /* List of the declared attributes */ - const xmlChar *prefix; /* the namespace prefix if any */ -}; - -/* - * An XML namespace. - * Note that prefix == NULL is valid, it defines the default namespace - * within the subtree (until overriden). - * - * XML_GLOBAL_NAMESPACE is now deprecated for good - * xmlNsType is unified with xmlElementType - */ - -#define XML_LOCAL_NAMESPACE XML_NAMESPACE_DECL -typedef xmlElementType xmlNsType; - -typedef struct _xmlNs xmlNs; -typedef xmlNs *xmlNsPtr; -struct _xmlNs { - struct _xmlNs *next; /* next Ns link for this node */ - xmlNsType type; /* global or local */ - const xmlChar *href; /* URL for the namespace */ - const xmlChar *prefix; /* prefix for the namespace */ -}; - -/* - * An XML DtD, as defined by parent link */ - struct _xmlNode *next; /* next sibling link */ - struct _xmlNode *prev; /* previous sibling link */ - struct _xmlDoc *doc; /* the containing document */ - - /* End of common part */ - void *notations; /* Hash table for notations if any */ - void *elements; /* Hash table for elements if any */ - void *attributes; /* Hash table for attributes if any */ - void *entities; /* Hash table for entities if any */ - const xmlChar *ExternalID; /* External identifier for PUBLIC DTD */ - const xmlChar *SystemID; /* URI for a SYSTEM or PUBLIC DTD */ - void *pentities; /* Hash table for param entities if any */ -}; - -/* - * A attribute of an XML node. - */ -typedef struct _xmlAttr xmlAttr; -typedef xmlAttr *xmlAttrPtr; -struct _xmlAttr { -#ifndef XML_WITHOUT_CORBA - void *_private; /* for Corba, must be first ! */ -#endif - xmlElementType type; /* XML_ATTRIBUTE_NODE, must be second ! */ - const xmlChar *name; /* the name of the property */ - struct _xmlNode *children; /* the value of the property */ - struct _xmlNode *last; /* NULL */ - struct _xmlNode *parent; /* child->parent link */ - struct _xmlAttr *next; /* next sibling link */ - struct _xmlAttr *prev; /* previous sibling link */ - struct _xmlDoc *doc; /* the containing document */ - xmlNs *ns; /* pointer to the associated namespace */ - xmlAttributeType atype; /* the attribute type if validating */ -}; - -/* - * An XML ID instance. - */ - -typedef struct _xmlID xmlID; -typedef xmlID *xmlIDPtr; -struct _xmlID { - struct _xmlID *next; /* next ID */ - const xmlChar *value; /* The ID name */ - xmlAttrPtr attr; /* The attribut holding it */ -}; - -/* - * An XML IDREF instance. - */ - -typedef struct _xmlRef xmlRef; -typedef xmlRef *xmlRefPtr; -struct _xmlRef { - struct _xmlRef *next; /* next Ref */ - const xmlChar *value; /* The Ref name */ - xmlAttrPtr attr; /* The attribut holding it */ -}; - -/* - * A buffer structure - */ - -typedef enum { - XML_BUFFER_ALLOC_DOUBLEIT, - XML_BUFFER_ALLOC_EXACT -} xmlBufferAllocationScheme; - -typedef struct _xmlBuffer xmlBuffer; -typedef xmlBuffer *xmlBufferPtr; -struct _xmlBuffer { - xmlChar *content; /* The buffer content UTF8 */ - unsigned int use; /* The buffer size used */ - unsigned int size; /* The buffer size */ - xmlBufferAllocationScheme alloc; /* The realloc method */ -}; - -/* - * A node in an XML tree. - */ -typedef struct _xmlNode xmlNode; -typedef xmlNode *xmlNodePtr; -struct _xmlNode { -#ifndef XML_WITHOUT_CORBA - void *_private; /* for Corba, must be first ! */ -#endif - xmlElementType type; /* type number, must be second ! */ - const xmlChar *name; /* the name of the node, or the entity */ - struct _xmlNode *children; /* parent->childs link */ - struct _xmlNode *last; /* last child link */ - struct _xmlNode *parent; /* child->parent link */ - struct _xmlNode *next; /* next sibling link */ - struct _xmlNode *prev; /* previous sibling link */ - struct _xmlDoc *doc; /* the containing document */ - xmlNs *ns; /* pointer to the associated namespace */ -#ifndef XML_USE_BUFFER_CONTENT - xmlChar *content; /* the content */ -#else - xmlBufferPtr content; /* the content in a buffer */ -#endif - - /* End of common part */ - struct _xmlAttr *properties;/* properties list */ - xmlNs *nsDef; /* namespace definitions on this node */ -}; - -/* - * An XML document. - */ -typedef struct _xmlDoc xmlDoc; -typedef xmlDoc *xmlDocPtr; -struct _xmlDoc { -#ifndef XML_WITHOUT_CORBA - void *_private; /* for Corba, must be first ! */ -#endif - xmlElementType type; /* XML_DOCUMENT_NODE, must be second ! */ - char *name; /* name/filename/URI of the document */ - struct _xmlNode *children; /* the document tree */ - struct _xmlNode *last; /* last child link */ - struct _xmlNode *parent; /* child->parent link */ - struct _xmlNode *next; /* next sibling link */ - struct _xmlNode *prev; /* previous sibling link */ - struct _xmlDoc *doc; /* autoreference to itself */ - - /* End of common part */ - int compression;/* level of zlib compression */ - int standalone; /* standalone document (no external refs) */ - struct _xmlDtd *intSubset; /* the document internal subset */ - struct _xmlDtd *extSubset; /* the document external subset */ - struct _xmlNs *oldNs; /* Global namespace, the old way */ - const xmlChar *version; /* the XML version string */ - const xmlChar *encoding; /* external initial encoding, if any */ - void *ids; /* Hash table for ID attributes if any */ - void *refs; /* Hash table for IDREFs attributes if any */ - const xmlChar *URL; /* The URI for that document */ - int charset; /* encoding of the in-memory content - actually an xmlCharEncoding */ -}; - -/** - * Predefined values for some standard encodings - * Libxml don't do beforehand translation on UTF8, ISOLatinX - * It also support UTF16 (LE and BE) by default. - * - * Anything else would have to be translated to UTF8 before being - * given to the parser itself. The BOM for UTF16 and the encoding - * declaration are looked at and a converter is looked for at that - * point. If not found the parser stops here as asked by the XML REC - * Converter can be registered by the user using xmlRegisterCharEncodingHandler - * but the currentl form doesn't allow stateful transcoding (a serious - * problem agreed !). If iconv has been found it will be used - * automatically and allow stateful transcoding, the simplest is then - * to be sure to enable icon and to provide iconv libs for the encoding - * support needed. - */ -typedef enum { - XML_CHAR_ENCODING_ERROR= -1, /* No char encoding detected */ - XML_CHAR_ENCODING_NONE= 0, /* No char encoding detected */ - XML_CHAR_ENCODING_UTF8= 1, /* UTF-8 */ - XML_CHAR_ENCODING_UTF16LE= 2, /* UTF-16 little endian */ - XML_CHAR_ENCODING_UTF16BE= 3, /* UTF-16 big endian */ - XML_CHAR_ENCODING_UCS4LE= 4, /* UCS-4 little endian */ - XML_CHAR_ENCODING_UCS4BE= 5, /* UCS-4 big endian */ - XML_CHAR_ENCODING_EBCDIC= 6, /* EBCDIC uh! */ - XML_CHAR_ENCODING_UCS4_2143=7, /* UCS-4 unusual ordering */ - XML_CHAR_ENCODING_UCS4_3412=8, /* UCS-4 unusual ordering */ - XML_CHAR_ENCODING_UCS2= 9, /* UCS-2 */ - XML_CHAR_ENCODING_8859_1= 10,/* ISO-8859-1 ISO Latin 1 */ - XML_CHAR_ENCODING_8859_2= 11,/* ISO-8859-2 ISO Latin 2 */ - XML_CHAR_ENCODING_8859_3= 12,/* ISO-8859-3 */ - XML_CHAR_ENCODING_8859_4= 13,/* ISO-8859-4 */ - XML_CHAR_ENCODING_8859_5= 14,/* ISO-8859-5 */ - XML_CHAR_ENCODING_8859_6= 15,/* ISO-8859-6 */ - XML_CHAR_ENCODING_8859_7= 16,/* ISO-8859-7 */ - XML_CHAR_ENCODING_8859_8= 17,/* ISO-8859-8 */ - XML_CHAR_ENCODING_8859_9= 18,/* ISO-8859-9 */ - XML_CHAR_ENCODING_2022_JP= 19,/* ISO-2022-JP */ - XML_CHAR_ENCODING_SHIFT_JIS=20,/* Shift_JIS */ - XML_CHAR_ENCODING_EUC_JP= 21,/* EUC-JP */ - XML_CHAR_ENCODING_ASCII= 22 /* pure ASCII */ -} xmlCharEncoding; - -/** - * xmlCharEncodingInputFunc: - * @param out a pointer ot an array of bytes to store the UTF-8 result - * @param outlen the length of out - * @param in a pointer ot an array of chars in the original encoding - * @param inlen the length of in - * - * Take a block of chars in the original encoding and try to convert - * it to an UTF-8 block of chars out. - * - * Returns the number of byte written, or -1 by lack of space, or -2 - * if the transcoding failed. - * The value of inlen after return is the number of octets consumed - * as the return value is positive, else unpredictiable. - * The value of outlen after return is the number of ocetes consumed. - */ -typedef int (* xmlCharEncodingInputFunc)(unsigned char* out, int *outlen, - const unsigned char* in, int *inlen); - - -/** - * xmlCharEncodingOutputFunc: - * @param out a pointer ot an array of bytes to store the result - * @param outlen the length of out - * @param in a pointer ot an array of UTF-8 chars - * @param inlen the length of in - * - * Take a block of UTF-8 chars in and try to convert it to an other - * encoding. - * Note: a first call designed to produce heading info is called with - * in = NULL. If stateful this should also initialize the encoder state - * - * Returns the number of byte written, or -1 by lack of space, or -2 - * if the transcoding failed. - * The value of inlen after return is the number of octets consumed - * as the return value is positive, else unpredictiable. - * The value of outlen after return is the number of ocetes consumed. - */ -typedef int (* xmlCharEncodingOutputFunc)(unsigned char* out, int *outlen, - const unsigned char* in, int *inlen); - - -/* - * Block defining the handlers for non UTF-8 encodings. - * If iconv is supported, there is two extra fields - */ - -typedef struct _xmlCharEncodingHandler xmlCharEncodingHandler; -typedef xmlCharEncodingHandler *xmlCharEncodingHandlerPtr; -struct _xmlCharEncodingHandler { - char *name; - xmlCharEncodingInputFunc input; - xmlCharEncodingOutputFunc output; -#ifdef LIBXML_ICONV_ENABLED - iconv_t iconv_in; - iconv_t iconv_out; -#endif /* LIBXML_ICONV_ENABLED */ -}; - -typedef int (*xmlInputMatchCallback) (char const *filename); -typedef void * (*xmlInputOpenCallback) (char const *filename); -typedef int (*xmlInputReadCallback) (void * context, char * buffer, int len); -typedef void (*xmlInputCloseCallback) (void * context); - -typedef struct _xmlParserInputBuffer xmlParserInputBuffer; -typedef xmlParserInputBuffer *xmlParserInputBufferPtr; -struct _xmlParserInputBuffer { - void* context; - xmlInputReadCallback readcallback; - xmlInputCloseCallback closecallback; - - xmlCharEncodingHandlerPtr encoder; /* I18N conversions to UTF-8 */ - - xmlBufferPtr buffer; /* Local buffer encoded in UTF-8 */ - xmlBufferPtr raw; /* if encoder != NULL buffer for raw input */ -}; - - -/* - * Those are the functions and datatypes for the library output - * I/O structures. - */ - -typedef int (*xmlOutputMatchCallback) (char const *filename); -typedef void * (*xmlOutputOpenCallback) (char const *filename); -typedef int (*xmlOutputWriteCallback) (void * context, const char * buffer, - int len); -typedef void (*xmlOutputCloseCallback) (void * context); - -typedef struct _xmlOutputBuffer xmlOutputBuffer; -typedef xmlOutputBuffer *xmlOutputBufferPtr; -struct _xmlOutputBuffer { - void* context; - xmlOutputWriteCallback writecallback; - xmlOutputCloseCallback closecallback; - - xmlCharEncodingHandlerPtr encoder; /* I18N conversions to UTF-8 */ - - xmlBufferPtr buffer; /* Local buffer encoded in UTF-8 or ISOLatin */ - xmlBufferPtr conv; /* if encoder != NULL buffer for output */ - int written; /* total number of byte written */ -}; - -#define XML_DEFAULT_VERSION "1.0" - -/** - * an xmlParserInput is an input flow for the XML processor. - * Each entity parsed is associated an xmlParserInput (except the - * few predefined ones). This is the case both for internal entities - * - in which case the flow is already completely in memory - or - * external entities - in which case we use the buf structure for - * progressive reading and I18N conversions to the internal UTF-8 format. - */ - -typedef void (* xmlParserInputDeallocate)(xmlChar *); -typedef struct _xmlParserInput xmlParserInput; -typedef xmlParserInput *xmlParserInputPtr; -struct _xmlParserInput { - /* Input buffer */ - xmlParserInputBufferPtr buf; /* UTF-8 encoded buffer */ - - const char *filename; /* The file analyzed, if any */ - const char *directory; /* the directory/base of teh file */ - const xmlChar *base; /* Base of the array to parse */ - const xmlChar *cur; /* Current char being parsed */ - const xmlChar *end; /* end of the arry to parse */ - int length; /* length if known */ - int line; /* Current line */ - int col; /* Current column */ - int consumed; /* How many xmlChars already consumed */ - xmlParserInputDeallocate free; /* function to deallocate the base */ - const xmlChar *encoding; /* the encoding string for entity */ - const xmlChar *version; /* the version string for entity */ - int standalone; /* Was that entity marked standalone */ -}; - -/** - * the parser can be asked to collect Node informations, i.e. at what - * place in the file they were detected. - * NOTE: This is off by default and not very well tested. - */ -typedef struct _xmlParserNodeInfo xmlParserNodeInfo; -typedef xmlParserNodeInfo *xmlParserNodeInfoPtr; - -struct _xmlParserNodeInfo { - const struct _xmlNode* node; - /* Position & line # that text that created the node begins & ends on */ - unsigned long begin_pos; - unsigned long begin_line; - unsigned long end_pos; - unsigned long end_line; -}; - -typedef struct _xmlParserNodeInfoSeq xmlParserNodeInfoSeq; -typedef xmlParserNodeInfoSeq *xmlParserNodeInfoSeqPtr; -struct _xmlParserNodeInfoSeq { - unsigned long maximum; - unsigned long length; - xmlParserNodeInfo* buffer; -}; - -/* - * Validation state added for non-determinist content model - */ -typedef struct _xmlValidState xmlValidState; -typedef xmlValidState *xmlValidStatePtr; - -/** - * an xmlValidCtxt is used for error reporting when validating - */ - -typedef void (*xmlValidityErrorFunc) (void *ctx, const char *msg, ...); -typedef void (*xmlValidityWarningFunc) (void *ctx, const char *msg, ...); - -typedef struct _xmlValidCtxt xmlValidCtxt; -typedef xmlValidCtxt *xmlValidCtxtPtr; -struct _xmlValidCtxt { - void *userData; /* user specific data block */ - xmlValidityErrorFunc error; /* the callback in case of errors */ - xmlValidityWarningFunc warning; /* the callback in case of warning */ - - /* Node analysis stack used when validating within entities */ - xmlNodePtr node; /* Current parsed Node */ - int nodeNr; /* Depth of the parsing stack */ - int nodeMax; /* Max depth of the parsing stack */ - xmlNodePtr *nodeTab; /* array of nodes */ - - int finishDtd; /* finished validating the Dtd ? */ - xmlDocPtr doc; /* the document */ - int valid; /* temporary validity check result */ - - /* state state used for non-determinist content validation */ - xmlValidState *vstate; /* current state */ - int vstateNr; /* Depth of the validation stack */ - int vstateMax; /* Max depth of the validation stack */ - xmlValidState *vstateTab; /* array of validation states */ -}; - -typedef struct _xmlLink xmlLink; -typedef xmlLink *xmlLinkPtr; - -typedef struct _xmlList xmlList; -typedef xmlList *xmlListPtr; - -typedef void (*xmlListDeallocator) (xmlLinkPtr lk); -typedef int (*xmlListDataCompare) (const void *data0, const void *data1); -typedef int (*xmlListWalker) (const void *data, const void *user); - -/* - * ALl notation declarations are stored in a table - * there is one table per DTD - */ - -typedef struct _xmlHashTable xmlNotationTable; -typedef xmlNotationTable *xmlNotationTablePtr; - -/* - * ALl element declarations are stored in a table - * there is one table per DTD - */ - -typedef struct _xmlHashTable xmlElementTable; -typedef xmlElementTable *xmlElementTablePtr; - -/* - * ALl attribute declarations are stored in a table - * there is one table per DTD - */ - -typedef struct _xmlHashTable xmlAttributeTable; -typedef xmlAttributeTable *xmlAttributeTablePtr; - -/* - * ALl IDs attributes are stored in a table - * there is one table per document - */ - -typedef struct _xmlHashTable xmlIDTable; -typedef xmlIDTable *xmlIDTablePtr; - -/* - * ALl Refs attributes are stored in a table - * there is one table per document - */ - -typedef struct _xmlHashTable xmlRefTable; -typedef xmlRefTable *xmlRefTablePtr; - -/* helper */ -xmlChar * xmlSplitQName2 (const xmlChar *name, - xmlChar **prefix); - -/** - * The parser is now working also as a state based parser - * The recursive one use the stagte info for entities processing - */ -typedef enum { - XML_PARSER_EOF = -1, /* nothing is to be parsed */ - XML_PARSER_START = 0, /* nothing has been parsed */ - XML_PARSER_MISC, /* Misc* before int subset */ - XML_PARSER_PI, /* Whithin a processing instruction */ - XML_PARSER_DTD, /* within some DTD content */ - XML_PARSER_PROLOG, /* Misc* after internal subset */ - XML_PARSER_COMMENT, /* within a comment */ - XML_PARSER_START_TAG, /* within a start tag */ - XML_PARSER_CONTENT, /* within the content */ - XML_PARSER_CDATA_SECTION, /* within a CDATA section */ - XML_PARSER_END_TAG, /* within a closing tag */ - XML_PARSER_ENTITY_DECL, /* within an entity declaration */ - XML_PARSER_ENTITY_VALUE, /* within an entity value in a decl */ - XML_PARSER_ATTRIBUTE_VALUE, /* within an attribute value */ - XML_PARSER_SYSTEM_LITERAL, /* within a SYSTEM value */ - XML_PARSER_EPILOG, /* the Misc* after the last end tag */ - XML_PARSER_IGNORE /* within an IGNORED section */ -} xmlParserInputState; - -/** - * The parser context. - * NOTE This doesn't completely defines the parser state, the (current ?) - * design of the parser uses recursive function calls since this allow - * and easy mapping from the production rules of the specification - * to the actual code. The drawback is that the actual function call - * also reflect the parser state. However most of the parsing routines - * takes as the only argument the parser context pointer, so migrating - * to a state based parser for progressive parsing shouldn't be too hard. - */ -typedef struct _xmlParserCtxt xmlParserCtxt; -typedef xmlParserCtxt *xmlParserCtxtPtr; -struct _xmlParserCtxt { - struct _xmlSAXHandler *sax; /* The SAX handler */ - void *userData; /* For SAX interface only, used by DOM build */ - xmlDocPtr myDoc; /* the document being built */ - int wellFormed; /* is the document well formed */ - int replaceEntities; /* shall we replace entities ? */ - const xmlChar *version; /* the XML version string */ - const xmlChar *encoding; /* the declared encoding, if any */ - int standalone; /* standalone document */ - int html; /* an HTML(1)/Docbook(2) document */ - - /* Input stream stack */ - xmlParserInputPtr input; /* Current input stream */ - int inputNr; /* Number of current input streams */ - int inputMax; /* Max number of input streams */ - xmlParserInputPtr *inputTab; /* stack of inputs */ - - /* Node analysis stack only used for DOM building */ - xmlNodePtr node; /* Current parsed Node */ - int nodeNr; /* Depth of the parsing stack */ - int nodeMax; /* Max depth of the parsing stack */ - xmlNodePtr *nodeTab; /* array of nodes */ - - int record_info; /* Whether node info should be kept */ - xmlParserNodeInfoSeq node_seq; /* info about each node parsed */ - - int errNo; /* error code */ - - int hasExternalSubset; /* reference and external subset */ - int hasPErefs; /* the internal subset has PE refs */ - int external; /* are we parsing an external entity */ - - int valid; /* is the document valid */ - int validate; /* shall we try to validate ? */ - xmlValidCtxt vctxt; /* The validity context */ - - xmlParserInputState instate; /* current type of input */ - int token; /* next char look-ahead */ - - char *directory; /* the data directory */ - - /* Node name stack */ - xmlChar *name; /* Current parsed Node */ - int nameNr; /* Depth of the parsing stack */ - int nameMax; /* Max depth of the parsing stack */ - xmlChar * *nameTab; /* array of nodes */ - - long nbChars; /* number of xmlChar processed */ - long checkIndex; /* used by progressive parsing lookup */ - int keepBlanks; /* ugly but ... */ - int disableSAX; /* SAX callbacks are disabled */ - int inSubset; /* Parsing is in int 1/ext 2 subset */ - xmlChar * intSubName; /* name of subset */ - xmlChar * extSubURI; /* URI of external subset */ - xmlChar * extSubSystem; /* SYSTEM ID of external subset */ - - /* xml:space values */ - int * space; /* Should the parser preserve spaces */ - int spaceNr; /* Depth of the parsing stack */ - int spaceMax; /* Max depth of the parsing stack */ - int * spaceTab; /* array of space infos */ - - int depth; /* to prevent entity substitution loops */ - xmlParserInputPtr entity; /* used to check entities boundaries */ - int charset; /* encoding of the in-memory content - actually an xmlCharEncoding */ - int nodelen; /* Those two fields are there to */ - int nodemem; /* Speed up large node parsing */ - int pedantic; /* signal pedantic warnings */ - void *_private; /* For user data, libxml won't touch it */ - - int loadsubset; /* should the external subset be loaded */ -}; - -/** - * a SAX Locator. - */ -typedef struct _xmlSAXLocator xmlSAXLocator; -typedef xmlSAXLocator *xmlSAXLocatorPtr; -struct _xmlSAXLocator { - const xmlChar *(*getPublicId)(void *ctx); - const xmlChar *(*getSystemId)(void *ctx); - int (*getLineNumber)(void *ctx); - int (*getColumnNumber)(void *ctx); -}; - -/* - * The different valid entity types - */ -typedef enum { - XML_INTERNAL_GENERAL_ENTITY = 1, - XML_EXTERNAL_GENERAL_PARSED_ENTITY = 2, - XML_EXTERNAL_GENERAL_UNPARSED_ENTITY = 3, - XML_INTERNAL_PARAMETER_ENTITY = 4, - XML_EXTERNAL_PARAMETER_ENTITY = 5, - XML_INTERNAL_PREDEFINED_ENTITY = 6 -} xmlEntityType; - -/* - * An unit of storage for an entity, contains the string, the value - * and the linkind data needed for the linking in the hash table. - */ - -typedef struct _xmlEntity xmlEntity; -typedef xmlEntity *xmlEntityPtr; -struct _xmlEntity { -#ifndef XML_WITHOUT_CORBA - void *_private; /* for Corba, must be first ! */ -#endif - xmlElementType type; /* XML_ENTITY_DECL, must be second ! */ - const xmlChar *name; /* Attribute name */ - struct _xmlNode *children; /* NULL */ - struct _xmlNode *last; /* NULL */ - struct _xmlDtd *parent; /* -> DTD */ - struct _xmlNode *next; /* next sibling link */ - struct _xmlNode *prev; /* previous sibling link */ - struct _xmlDoc *doc; /* the containing document */ - - xmlChar *orig; /* content without ref substitution */ - xmlChar *content; /* content or ndata if unparsed */ - int length; /* the content length */ - xmlEntityType etype; /* The entity type */ - const xmlChar *ExternalID; /* External identifier for PUBLIC */ - const xmlChar *SystemID; /* URI for a SYSTEM or PUBLIC Entity */ - - struct _xmlEntity *nexte; /* unused */ - const xmlChar *URI; /* the full URI as computed */ -}; - -/* - * ALl entities are stored in an hash table - * there is 2 separate hash tables for global and parmeter entities - */ - -typedef struct _xmlHashTable xmlEntitiesTable; -typedef xmlEntitiesTable *xmlEntitiesTablePtr; - -/* - * External functions : - */ - -/** - * a SAX handler is bunch of callbacks called by the parser when processing - * of the input generate data or structure informations. - */ - -typedef xmlParserInputPtr (*resolveEntitySAXFunc) (void *ctx, - const xmlChar *publicId, const xmlChar *systemId); -typedef void (*internalSubsetSAXFunc) (void *ctx, const xmlChar *name, - const xmlChar *ExternalID, const xmlChar *SystemID); -typedef void (*externalSubsetSAXFunc) (void *ctx, const xmlChar *name, - const xmlChar *ExternalID, const xmlChar *SystemID); -typedef xmlEntityPtr (*getEntitySAXFunc) (void *ctx, - const xmlChar *name); -typedef xmlEntityPtr (*getParameterEntitySAXFunc) (void *ctx, - const xmlChar *name); -typedef void (*entityDeclSAXFunc) (void *ctx, - const xmlChar *name, int type, const xmlChar *publicId, - const xmlChar *systemId, xmlChar *content); -typedef void (*notationDeclSAXFunc)(void *ctx, const xmlChar *name, - const xmlChar *publicId, const xmlChar *systemId); -typedef void (*attributeDeclSAXFunc)(void *ctx, const xmlChar *elem, - const xmlChar *name, int type, int def, - const xmlChar *defaultValue, xmlEnumerationPtr tree); -typedef void (*elementDeclSAXFunc)(void *ctx, const xmlChar *name, - int type, xmlElementContentPtr content); -typedef void (*unparsedEntityDeclSAXFunc)(void *ctx, - const xmlChar *name, const xmlChar *publicId, - const xmlChar *systemId, const xmlChar *notationName); -typedef void (*setDocumentLocatorSAXFunc) (void *ctx, - xmlSAXLocatorPtr loc); -typedef void (*startDocumentSAXFunc) (void *ctx); -typedef void (*endDocumentSAXFunc) (void *ctx); -typedef void (*startElementSAXFunc) (void *ctx, const xmlChar *name, - const xmlChar **atts); -typedef void (*endElementSAXFunc) (void *ctx, const xmlChar *name); -typedef void (*attributeSAXFunc) (void *ctx, const xmlChar *name, - const xmlChar *value); -typedef void (*referenceSAXFunc) (void *ctx, const xmlChar *name); -typedef void (*charactersSAXFunc) (void *ctx, const xmlChar *ch, - int len); -typedef void (*ignorableWhitespaceSAXFunc) (void *ctx, - const xmlChar *ch, int len); -typedef void (*processingInstructionSAXFunc) (void *ctx, - const xmlChar *target, const xmlChar *data); -typedef void (*commentSAXFunc) (void *ctx, const xmlChar *value); -typedef void (*cdataBlockSAXFunc) (void *ctx, const xmlChar *value, int len); -typedef void (*warningSAXFunc) (void *ctx, const char *msg, ...); -typedef void (*errorSAXFunc) (void *ctx, const char *msg, ...); -typedef void (*fatalErrorSAXFunc) (void *ctx, const char *msg, ...); -typedef int (*isStandaloneSAXFunc) (void *ctx); -typedef int (*hasInternalSubsetSAXFunc) (void *ctx); -typedef int (*hasExternalSubsetSAXFunc) (void *ctx); - -typedef struct _xmlSAXHandler xmlSAXHandler; -typedef xmlSAXHandler *xmlSAXHandlerPtr; -struct _xmlSAXHandler { - internalSubsetSAXFunc internalSubset; - isStandaloneSAXFunc isStandalone; - hasInternalSubsetSAXFunc hasInternalSubset; - hasExternalSubsetSAXFunc hasExternalSubset; - resolveEntitySAXFunc resolveEntity; - getEntitySAXFunc getEntity; - entityDeclSAXFunc entityDecl; - notationDeclSAXFunc notationDecl; - attributeDeclSAXFunc attributeDecl; - elementDeclSAXFunc elementDecl; - unparsedEntityDeclSAXFunc unparsedEntityDecl; - setDocumentLocatorSAXFunc setDocumentLocator; - startDocumentSAXFunc startDocument; - endDocumentSAXFunc endDocument; - startElementSAXFunc startElement; - endElementSAXFunc endElement; - referenceSAXFunc reference; - charactersSAXFunc characters; - ignorableWhitespaceSAXFunc ignorableWhitespace; - processingInstructionSAXFunc processingInstruction; - commentSAXFunc comment; - warningSAXFunc warning; - errorSAXFunc error; - fatalErrorSAXFunc fatalError; - getParameterEntitySAXFunc getParameterEntity; - cdataBlockSAXFunc cdataBlock; - externalSubsetSAXFunc externalSubset; -}; - -/** - * External entity loaders types - */ -typedef xmlParserInputPtr (*xmlExternalEntityLoader)(const char *URL, - const char *ID, - xmlParserCtxtPtr context); - -/* - * Compatibility naming layer with libxml1 - */ -#ifndef xmlChildrenNode -#define xmlChildrenNode children -#define xmlRootNode children -#endif - - -/*********************Xml routines and function pointers */ -#ifdef IN_XMLSTUB -#define XML_EXTERN -#else -#define XML_EXTERN extern -#endif - -typedef struct { - /* Functions */ - xmlDocPtr (*xmlParseFile)(const char *filename); - int (*xmlStrcmp)(const xmlChar *str1, const xmlChar *str2); - xmlParserCtxtPtr (*xmlCreatePushParserCtxt)(xmlSAXHandlerPtr, void *, const char *, - int, const char *); - int (*xmlParseChunk)(xmlParserCtxtPtr, const char *, int, int); - void (*xmlFreeParserCtxt)(xmlParserCtxtPtr); - xmlNodePtr (*xmlDocGetRootElement)(xmlDocPtr); - void (*xmlFreeDoc)(xmlDocPtr); - char *(*xmlNodeListGetString)(xmlDocPtr, xmlNodePtr, int); - char *(*xmlGetProp)(xmlNodePtr, const char *); - int (*xmlKeepBlanksDefault)(int); - int (*xmlSubstituteEntitiesDefault)(int); -#ifdef WIRESHARK_XML_DO_VALIDITY_CHECKING - int *xmlDoValidityCheckingDefaultValue; -#endif -} XML_STUB; - -XML_EXTERN XML_STUB XmlStub; -XML_EXTERN int XmlStubInitialized; - -#ifdef _WIN32 -/* We're in windows, use the windows filename */ -#define XML_LIBRARY "libxml2.dll" -#else -#define XML_LIBRARY "libxml2.so" -#endif - -/* - * This needs to be called before the library is used. It - * returns zero on success. Any non-zero return means that - * either dynamic libraries are not supported, or that libxml - * is not installed on the current system. (Or it's not in - * the LD path) - */ -int loadLibXML(void); - - - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/file.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/file.h deleted file mode 100644 index e7c4de6d..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/file.h +++ /dev/null @@ -1,486 +0,0 @@ -/* file.h - * Definitions for file structures and routines - * - * $Id: file.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __FILE_H__ -#define __FILE_H__ - -#include "packet-range.h" -#include "wiretap/wtap.h" -#include -#include "print.h" -#include -#include - -#include "cfile.h" - - -/** Return values from functions that only can succeed or fail. */ -typedef enum { - CF_OK, /**< operation succeeded */ - CF_ERROR /**< operation got an error (function may provide err with details) */ -} cf_status_t; - -/** Return values from functions that read capture files. */ -typedef enum { - CF_READ_OK, /**< operation succeeded */ - CF_READ_ERROR, /**< operation got an error (function may provide err with details) */ - CF_READ_ABORTED /**< operation aborted by user */ -} cf_read_status_t; - -/** Return values from functions that print sets of packets. */ -typedef enum { - CF_PRINT_OK, /**< print operation succeeded */ - CF_PRINT_OPEN_ERROR, /**< print operation failed while opening printer */ - CF_PRINT_WRITE_ERROR /**< print operation failed while writing to the printer */ -} cf_print_status_t; - -typedef enum { - cf_cb_file_closing, - cf_cb_file_closed, - cf_cb_file_read_start, - cf_cb_file_read_finished, -#ifdef HAVE_LIBPCAP - cf_cb_live_capture_prepared, - cf_cb_live_capture_update_started, - cf_cb_live_capture_update_continue, - cf_cb_live_capture_update_finished, - cf_cb_live_capture_fixed_started, - cf_cb_live_capture_fixed_continue, - cf_cb_live_capture_fixed_finished, - cf_cb_live_capture_stopping, -#endif - cf_cb_packet_selected, - cf_cb_packet_unselected, - cf_cb_field_unselected, - cf_cb_file_safe_started, - cf_cb_file_safe_finished, - cf_cb_file_safe_reload_finished, - cf_cb_file_safe_failed -} cf_cbs; - -typedef void (*cf_callback_t) (gint event, gpointer data, gpointer user_data); - -extern void -cf_callback_invoke(int event, gpointer data); - -extern void -cf_callback_add(cf_callback_t func, gpointer user_data); - -extern void -cf_callback_remove(cf_callback_t func); - -/** - * Open a capture file. - * - * @param cf the capture file to be opened - * @param fname the filename to be opened - * @param is_tempfile is this a temporary file? - * @return one of cf_status_t - */ -cf_status_t cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err); - -/** - * Close a capture file. - * - * @param cf the capture file to be closed - */ -void cf_close(capture_file *cf); - -/** - * Reload a capture file. - * - * @param cf the capture file to be reloaded - */ -void cf_reload(capture_file *cf); - -/** - * Read all packets of a capture file into the internal structures. - * - * @param cf the capture file to be read - * @return one of cf_read_status_t - */ -cf_read_status_t cf_read(capture_file *cf); - -/** - * Start reading from the end of a capture file. - * This is used in "Update list of packets in Real-Time". - * - * @param cf the capture file to be read from - * @param fname the filename to be read from - * @param is_tempfile is this a temporary file? - * @param err the error code, if an error had occured - * @return one of cf_status_t - */ -cf_status_t cf_start_tail(capture_file *cf, const char *fname, gboolean is_tempfile, int *err); - -/** - * Read packets from the "end" of a capture file. - * - * @param cf the capture file to be read from - * @param to_read the number of packets to read - * @param err the error code, if an error had occured - * @return one of cf_read_status_t - */ -cf_read_status_t cf_continue_tail(capture_file *cf, volatile int to_read, int *err); - -/** - * Finish reading from "end" of a capture file. - * - * @param cf the capture file to be read from - * @param err the error code, if an error had occured - * @return one of cf_read_status_t - */ -cf_read_status_t cf_finish_tail(capture_file *cf, int *err); - -/** - * Determine whether this capture file (or a range of it) can be saved - * (except by copying the raw file data). - * - * @param cf the capture file to check - * @return TRUE if it can be saved, FALSE if it can't - */ -gboolean cf_can_save_as(capture_file *cf); - -/** - * Save a capture file (or a range of it). - * - * @param cf the capture file to save to - * @param fname the filename to save to - * @param range the range of packets to save - * @param save_format the format of the file to save (libpcap, ...) - * @param compressed wether to gzip compress the file - * @return one of cf_status_t - */ -cf_status_t cf_save(capture_file * cf, const char *fname, packet_range_t *range, guint save_format, gboolean compressed); - -/** - * Get a displayable name of the capture file. - * - * @param cf the capture file - * @return the displayable name (don't have to be g_free'd) - */ -const gchar *cf_get_display_name(capture_file *cf); - -/** - * Get the number of packets in the capture file. - * - * @param cf the capture file - * @return the number of packets in the capture file - */ -int cf_get_packet_count(capture_file *cf); - -/** - * Set the number of packets in the capture file. - * - * @param cf the capture file - * @param the number of packets in the capture file - */ -void cf_set_packet_count(capture_file *cf, int packet_count); - -/** - * Is this capture file a temporary file? - * - * @param cf the capture file - * @return TRUE if it's a temporary file, FALSE otherwise - */ -gboolean cf_is_tempfile(capture_file *cf); - -/** - * Set flag, that this file is a tempfile. - */ -void cf_set_tempfile(capture_file *cf, gboolean is_tempfile); - -/** - * Set flag, if the number of packet drops while capturing are known or not. - * - * @param cf the capture file - * @param drops_known TRUE if the number of packet drops are known, FALSE otherwise - */ -void cf_set_drops_known(capture_file *cf, gboolean drops_known); - -/** - * Set the number of packet drops while capturing. - * - * @param cf the capture file - * @param drops the number of packet drops occured while capturing - */ -void cf_set_drops(capture_file *cf, guint32 drops); - -/** - * Get flag state, if the number of packet drops while capturing are known or not. - * - * @param cf the capture file - * @return TRUE if the number of packet drops are known, FALSE otherwise - */ -gboolean cf_get_drops_known(capture_file *cf); - -/** - * Get the number of packet drops while capturing. - * - * @param cf the capture file - * @return the number of packet drops occured while capturing - */ -guint32 cf_get_drops(capture_file *cf); - -/** - * Set the read filter. - * @todo this shouldn't be required, remove it somehow - * - * @param cf the capture file - * @param rfcode the readfilter - */ -void cf_set_rfcode(capture_file *cf, dfilter_t *rfcode); - -/** - * "Display Filter" packets in the capture file. - * - * @param cf the capture file - * @param dfilter the display filter - * @param force TRUE if do in any case, FALSE only if dfilter changed - * @return one of cf_status_t - */ -cf_status_t cf_filter_packets(capture_file *cf, gchar *dfilter, gboolean force); - -/** - * At least one "Refence Time" flag has changed, rescan all packets. - * - * @param cf the capture file - */ -void cf_reftime_packets(capture_file *cf); - -/** - * At least one "Refence Time" flag has changed, rescan all packets. - * - * @param cf the capture file - */ -void cf_colorize_packets(capture_file *cf); - -/** - * "Something" has changed, rescan all packets. - * - * @param cf the capture file - */ -void cf_redissect_packets(capture_file *cf); - -/** - * Rescan all packets and just run taps - don't reconstruct the display. - * - * @param cf the capture file - * @param do_columns TRUE if columns are to be generated, FALSE otherwise - * @return one of cf_read_status_t - */ -cf_read_status_t cf_retap_packets(capture_file *cf, gboolean do_columns); - -/** - * The time format has changed, rescan all packets. - * - * @param cf the capture file - */ -void cf_change_time_formats(capture_file *cf); - -/** - * Print the capture file. - * - * @param cf the capture file - * @param print_args the arguments what and how to print - * @return one of cf_print_status_t - */ -cf_print_status_t cf_print_packets(capture_file *cf, print_args_t *print_args); - -/** - * Print (export) the capture file into PDML format. - * - * @param cf the capture file - * @param print_args the arguments what and how to export - * @return one of cf_print_status_t - */ -cf_print_status_t cf_write_pdml_packets(capture_file *cf, print_args_t *print_args); - -/** - * Print (export) the capture file into PSML format. - * - * @param cf the capture file - * @param print_args the arguments what and how to export - * @return one of cf_print_status_t - */ -cf_print_status_t cf_write_psml_packets(capture_file *cf, print_args_t *print_args); - -/** - * Print (export) the capture file into CSV format. - * - * @param cf the capture file - * @param print_args the arguments what and how to export - * @return one of cf_print_status_t - */ -cf_print_status_t cf_write_csv_packets(capture_file *cf, print_args_t *print_args); - -/** - * Print (export) the capture file into C Arrays format. - * - * @param cf the capture file - * @param print_args the arguments what and how to export - * @return one of cf_print_status_t - */ -cf_print_status_t cf_write_carrays_packets(capture_file *cf, print_args_t *print_args); - -/** - * Find Packet in protocol tree. - * - * @param cf the capture file - * @param string the string to find - * @return TRUE if a packet was found, FALSE otherwise - */ -gboolean cf_find_packet_protocol_tree(capture_file *cf, const char *string); - -/** - * Find Packet in summary line. - * - * @param cf the capture file - * @param string the string to find - * @return TRUE if a packet was found, FALSE otherwise - */ -gboolean cf_find_packet_summary_line(capture_file *cf, const char *string); - -/** - * Find Packet in packet data. - * - * @param cf the capture file - * @param string the string to find - * @param string_size the size of the string to find - * @return TRUE if a packet was found, FALSE otherwise - */ -gboolean cf_find_packet_data(capture_file *cf, const guint8 *string, - size_t string_size); - -/** - * Find Packet by display filter. - * - * @param cf the capture file - * @param sfcode the display filter to find a packet for - * @return TRUE if a packet was found, FALSE otherwise - */ -gboolean cf_find_packet_dfilter(capture_file *cf, dfilter_t *sfcode); - -/** - * GoTo Packet in first row. - * - * @param cf the capture file - * @return TRUE if the first row exists, FALSE otherwise - */ -gboolean cf_goto_top_frame(capture_file *cf); - -/** - * GoTo Packet in last row. - * - * @param cf the capture file - * @return TRUE if last row exists, FALSE otherwise - */ -gboolean cf_goto_bottom_frame(capture_file *cf); - -/** - * GoTo Packet with the given row. - * - * @param cf the capture file - * @param row the row to go to - * @return TRUE if this row exists, FALSE otherwise - */ -gboolean cf_goto_frame(capture_file *cf, guint row); - -/** - * Go to frame specified by currently selected protocol tree field. - * (Go To Corresponding Packet) - * @todo this is ugly and should be improved! - * - * @param cf the capture file - * @return TRUE if this packet exists, FALSE otherwise - */ -gboolean cf_goto_framenum(capture_file *cf); - -/** - * Select the packet in the given row. - * - * @param cf the capture file - * @param row the row to select - */ -void cf_select_packet(capture_file *cf, int row); - -/** - * Unselect all packets, if any. - * - * @param cf the capture file - * @param row the row to select - */ -void cf_unselect_packet(capture_file *cf); - -/** - * Unselect all protocol tree fields, if any. - * - * @param cf the capture file - * @param row the row to select - */ -void cf_unselect_field(capture_file *cf); - -/** - * Mark a particular frame in a particular capture. - * - * @param cf the capture file - * @param frame the frame to be marked - */ -void cf_mark_frame(capture_file *cf, frame_data *frame); - -/** - * Unmark a particular frame in a particular capture. - * - * @param cf the capture file - * @param frame the frame to be unmarked - */ -void cf_unmark_frame(capture_file *cf, frame_data *frame); - -/** - * Convert error number and info to a complete message. - * - * @param err the error number - * @param err_info the additional info about this error (e.g. filename) - * @return statically allocated error message - */ -char *cf_read_error_message(int err, const gchar *err_info); - -/** - * Merge two (or more) capture files into one. - * @todo is this the right place for this function? It doesn't have to do a lot with capture_file. - * - * @param out_filename pointer to output filename; if output filename is - * NULL, a temporary file name is generated and *out_filename is set - * to point to the generated file name - * @param in_file_count the number of input files to merge - * @param in_filnames array of input filenames - * @param file_type the output filetype - * @param do_append FALSE to merge chronologically, TRUE simply append - * @return one of cf_status_t - */ -cf_status_t -cf_merge_files(char **out_filename, int in_file_count, - char *const *in_filenames, int file_type, gboolean do_append); - -#endif /* file.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/fileset.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/fileset.h deleted file mode 100644 index 47015f99..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/fileset.h +++ /dev/null @@ -1,75 +0,0 @@ -/* fileset.h - * Definitions for routines for file sets. - * - * $Id: fileset.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __FILESET_H__ -#define __FILESET_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - - -typedef struct _fileset_entry { - const char *fullname; /* File name with path (g_strdup'ed) */ - const char *name; /* File name without path (g_strdup'ed) */ - time_t ctime; /* create time */ - time_t mtime; /* last modified time */ - long size; /* size of file in bytes */ - gboolean current; /* is this the currently loaded file? */ -} fileset_entry; - - -/* helper: is this a probable file of a file set (does the naming pattern match)? */ -extern gboolean fileset_filename_match_pattern(const char *fname); - -/* helper: test, if both files could be in the same file set */ -extern gboolean fileset_is_file_in_set(const char *fname1, const char *fname2); - -extern void fileset_add_dir(const char *fname); - -extern void fileset_delete(void); - -/* get the current directory name */ -extern const char *fileset_get_dirname(void); - -extern fileset_entry *fileset_get_next(void); -extern fileset_entry *fileset_get_previous(void); - - - -/* this file is a part of the current file set */ -extern void fileset_dlg_add_file(fileset_entry *entry); - -extern void fileset_file_opened(const char *fname); - -extern void fileset_file_closed(void); - -extern void fileset_update_dlg(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __FILESET_H__ */ - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/filters.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/filters.h deleted file mode 100644 index 0ca489b2..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/filters.h +++ /dev/null @@ -1,87 +0,0 @@ -/* filters.h - * Declarations of routines for reading and writing the filters file. - * - * $Id: filters.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* - * Filter lists. - */ -typedef enum { - CFILTER_LIST, /* capture filter list - saved */ - DFILTER_LIST, /* display filter list - saved */ - CFILTER_EDITED_LIST, /* capture filter list - currently edited */ - DFILTER_EDITED_LIST /* display filter list - currently edited */ -} filter_list_type_t; - -/* - * Item in a list of filters. - */ -typedef struct { - char *name; /* filter name */ - char *strval; /* filter expression */ -} filter_def; - -/* - * Read in a list of filters. - * - * On success, "*pref_path_return" is set to NULL. - * On error, "*pref_path_return" is set to point to the pathname of - * the file we tried to read - it should be freed by our caller - - * and "*errno_return" is set to the error. - */ -void read_filter_list(filter_list_type_t list_type, char **pref_path_return, - int *errno_return); - -/* - * Get a pointer to the first entry in a filter list. - */ -GList *get_filter_list_first(filter_list_type_t list); - -/* - * Add a new filter to the end of a list. - * Returns a pointer to the newly-added entry. - */ -GList *add_to_filter_list(filter_list_type_t list, const char *name, - const char *expression); - -/* - * Remove a filter from a list. - */ -void remove_from_filter_list(filter_list_type_t list, GList *fl_entry); - -/* - * Write out a list of filters. - * - * On success, "*pref_path_return" is set to NULL. - * On error, "*pref_path_return" is set to point to the pathname of - * the file we tried to read - it should be freed by our caller - - * and "*errno_return" is set to the error. - */ -void save_filter_list(filter_list_type_t list_type, char **pref_path_return, - int *errno_return); - -/* - * Clone the filter list so it can be edited. - */ -void copy_filter_list(filter_list_type_t dest_type, filter_list_type_t src_type); - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/g711.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/g711.h deleted file mode 100644 index b55bd13c..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/g711.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * g711.h - * - * Definitions for routines for u-law, A-law and linear PCM conversions - * - * $Id: g711.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -unsigned char linear2alaw( int ); -int alaw2linear( unsigned char ); -unsigned char linear2ulaw( int ); -int ulaw2linear( unsigned char ); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/getopt.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/getopt.h deleted file mode 100644 index 45541f5a..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/getopt.h +++ /dev/null @@ -1,129 +0,0 @@ -/* Declarations for getopt. - Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2, or (at your option) any - later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#ifndef _GETOPT_H -#define _GETOPT_H 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* For communication from `getopt' to the caller. - When `getopt' finds an option that takes an argument, - the argument value is returned here. - Also, when `ordering' is RETURN_IN_ORDER, - each non-option ARGV-element is returned here. */ - -extern char *optarg; - -/* Index in ARGV of the next element to be scanned. - This is used for communication to and from the caller - and for communication between successive calls to `getopt'. - - On entry to `getopt', zero means this is the first call; initialize. - - When `getopt' returns EOF, this is the index of the first of the - non-option elements that the caller should itself scan. - - Otherwise, `optind' communicates from one call to the next - how much of ARGV has been scanned so far. */ - -extern int optind; - -/* Callers store zero here to inhibit the error message `getopt' prints - for unrecognized options. */ - -extern int opterr; - -/* Set to an option character which was unrecognized. */ - -extern int optopt; - -/* Describe the long-named options requested by the application. - The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector - of `struct option' terminated by an element containing a name which is - zero. - - The field `has_arg' is: - no_argument (or 0) if the option does not take an argument, - required_argument (or 1) if the option requires an argument, - optional_argument (or 2) if the option takes an optional argument. - - If the field `flag' is not NULL, it points to a variable that is set - to the value given in the field `val' when the option is found, but - left unchanged if the option is not found. - - To have a long-named option do something other than set an `int' to - a compiled-in constant, such as set a value from `optarg', set the - option's `flag' field to zero and its `val' field to a nonzero - value (the equivalent single-letter option character, if there is - one). For long options that have a zero `flag' field, `getopt' - returns the contents of the `val' field. */ - -struct option -{ -#if __STDC__ - const char *name; -#else - char *name; -#endif - /* has_arg can't be an enum because some compilers complain about - type mismatches in all the code that assumes it is an int. */ - int has_arg; - int *flag; - int val; -}; - -/* Names for the values of the `has_arg' field of `struct option'. */ - -#define no_argument 0 -#define required_argument 1 -#define optional_argument 2 - -#if __STDC__ -#if defined(__GNU_LIBRARY__) -/* Many other libraries have conflicting prototypes for getopt, with - differences in the consts, in stdlib.h. To avoid compilation - errors, only prototype getopt for the GNU C library. */ -extern int getopt (int argc, char *const *argv, const char *shortopts); -#else /* not __GNU_LIBRARY__ */ -extern int getopt (); -#endif /* not __GNU_LIBRARY__ */ -extern int getopt_long (int argc, char *const *argv, const char *shortopts, - const struct option *longopts, int *longind); -extern int getopt_long_only (int argc, char *const *argv, - const char *shortopts, - const struct option *longopts, int *longind); - -/* Internal only. Users should not call this directly. */ -extern int _getopt_internal (int argc, char *const *argv, - const char *shortopts, - const struct option *longopts, int *longind, - int long_only); -#else /* not __STDC__ */ -extern int getopt (); -extern int getopt_long (); -extern int getopt_long_only (); - -extern int _getopt_internal (); -#endif /* not __STDC__ */ - -#ifdef __cplusplus -} -#endif - -#endif /* _GETOPT_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/globals.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/globals.h deleted file mode 100644 index ff6ac7f3..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/globals.h +++ /dev/null @@ -1,37 +0,0 @@ -/* globals.h - * Global defines, etc. - * - * $Id: globals.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __GLOBALS_H__ -#define __GLOBALS_H__ - -#include "file.h" -#include - -extern capture_file cfile; -#ifdef HAVE_LIBPCAP -/** @todo move this to the gtk dir */ -extern gboolean auto_scroll_live; -#endif - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/inet_v6defs.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/inet_v6defs.h deleted file mode 100644 index 22f82abc..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/inet_v6defs.h +++ /dev/null @@ -1,54 +0,0 @@ -/* inet_v6defs.h - * - * $Id: inet_v6defs.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __INET_V6DEFS_H__ -#define __INET_V6DEFS_H__ - -/* - * Versions of "inet_pton()" and "inet_ntop()", for the benefit of OSes that - * don't have it. - */ -extern int inet_pton(int af, const char *src, void *dst); -#ifndef HAVE_INET_NTOP_PROTO -extern const char *inet_ntop(int af, const void *src, char *dst, - size_t size); -#endif - -/* - * Those OSes may also not have AF_INET6, so declare it here if it's not - * already declared, so that we can pass it to "inet_ntop()" and "inet_pton()". - */ -#ifndef AF_INET6 -#define AF_INET6 127 /* pick a value unlikely to duplicate an existing AF_ value */ -#endif - -/* - * And if __P isn't defined, define it here, so we can use it in - * "inet_ntop.c" and "inet_pton.c" (rather than having to change them - * not to use it). - */ -#ifndef __P -#define __P(args) args -#endif - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/isprint.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/isprint.h deleted file mode 100644 index 8a2d0a25..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/isprint.h +++ /dev/null @@ -1,46 +0,0 @@ -/* isprint.h - * Temporary redefinition of "isprint()" to cope with GTK+ 1.3 and - * later using UTF-8 strings - * - * $Id: isprint.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __ISPRINT_H__ -#define __ISPRINT_H__ - -#if GLIB_MAJOR_VERSION >= 2 -/* - * XXX - "isprint()" can return "true" for non-ASCII characters, but - * those don't work with GTK+ 1.3 or later, as they take UTF-8 strings - * as input. Until we fix up Wireshark to properly handle non-ASCII - * characters in all output (both GUI displays and text printouts) - * in those versions of GTK+, we work around the problem by escaping - * all characters that aren't printable ASCII. - * - * We don't know what version of GTK+ we're using, as dissectors don't - * use any GTK+ stuff; we use GLib as a proxy for that, with GLib 2.x - * implying GTK+ 1.3 or later (we don't support GLib 1.3[.x]). - */ -#undef isprint -#define isprint(c) (c >= 0x20 && c < 0x7f) -#endif - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/log.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/log.h deleted file mode 100644 index 569c4c20..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/log.h +++ /dev/null @@ -1,42 +0,0 @@ -/* log.h - * log output definitions - * - * $Id: log.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __LOG_H__ -#define __LOG_H__ - -/* capture domain (except for capture child, see below) */ -#define LOG_DOMAIN_CAPTURE "Capture" - -/* capture child domain (the capture child might also contain file domain messages!) */ -#define LOG_DOMAIN_CAPTURE_CHILD "CaptureChild" - -/* main domain */ -#define LOG_DOMAIN_MAIN "Main" - -/* enable very verbose capture log debug output */ -/* (might slightly degrade performance) */ -/*#define LOG_CAPTURE_VERBOSE*/ - - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/main_window.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/main_window.h deleted file mode 100644 index eb196b10..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/main_window.h +++ /dev/null @@ -1,41 +0,0 @@ -/* main_window.h - * Definitions for main window routines with toolkit-independent APIs but - * toolkit-dependent implementations. - * - * $Id: main_window.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __MAIN_WINDOW_H__ -#define __MAIN_WINDOW_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/** Tell the main window that we have a capture file (or not) */ -extern void -main_set_for_capture_file(gboolean have_capture_file_in); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __MAIN_WINDOW_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/menu.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/menu.h deleted file mode 100644 index 99cf2a90..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/menu.h +++ /dev/null @@ -1,64 +0,0 @@ -/* menu.h - * Definitions for menu routines with toolkit-independent APIs but - * toolkit-dependent implementations. - * - * $Id: menu.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __MENU_H__ -#define __MENU_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - - -/* Add a new recent capture filename to the "Recent Files" submenu - (duplicates will be ignored) */ -void add_menu_recent_capture_file(gchar *file); - -/* Routines to enable or disable sets of menu items. */ - -/* Enable or disable menu items based on whether you have a capture file - you've finished reading and, if you have one, whether it's been saved - and whether it could be saved except by copying the raw packet data. */ -void set_menus_for_capture_file(capture_file *); - -/* Enable or disable menu items based on whether there's a capture in - progress. */ -void set_menus_for_capture_in_progress(gboolean); - -/* Enable or disable menu items based on whether you have some captured - packets. */ -void set_menus_for_captured_packets(gboolean); - -/* Enable or disable menu items based on whether a packet is selected. */ -void set_menus_for_selected_packet(capture_file *cf); - -/* Enable or disable menu items based on whether a tree row is selected - and and on whether a "Match Selected" can be done. */ -void set_menus_for_selected_tree_row(capture_file *cf); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __MENU_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/merge.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/merge.h deleted file mode 100644 index 22620aae..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/merge.h +++ /dev/null @@ -1,125 +0,0 @@ -/* merge.h - * Definitions for routines for merging files. - * - * $Id: merge.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __MERGE_H__ -#define __MERGE_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -typedef enum { - PACKET_PRESENT, - PACKET_NOT_PRESENT, - AT_EOF, - GOT_ERROR -} in_file_state_e; - -/** - * Structures to manage our input files. - */ -typedef struct merge_in_file_s { - const char *filename; - wtap *wth; - gint64 data_offset; - in_file_state_e state; - gint64 size; /* file size */ -} merge_in_file_t; - -/** Open a number of input files to merge. - * - * @param in_file_count number of entries in in_file_names and in_files - * @param in_file_names filenames of the input files - * @param in_files input file array to be filled (>= sizeof(merge_in_file_t) * in_file_count) - * @param err wiretap error, if failed - * @param err_info wiretap error string, if failed - * @param err_fileno file on which open failed, if failed - * @return TRUE if all files could be opened, FALSE otherwise - */ -extern gboolean -merge_open_in_files(int in_file_count, char *const *in_file_names, - merge_in_file_t **in_files, int *err, gchar **err_info, - int *err_fileno); - -/** Close the input files again. - * - * @param in_file_count number of entries in in_files - * @param in_files input file array to be closed - */ -extern void -merge_close_in_files(int in_file_count, merge_in_file_t in_files[]); - -/** Try to get the frame type from the input files. - * - * @param in_file_count number of entries in in_files - * @param in_files input file array - * @return the frame type - */ -extern int -merge_select_frame_type(int in_file_count, merge_in_file_t in_files[]); - -/** Try to get the snapshot length from the input files. - * - * @param in_file_count number of entries in in_files - * @param in_files input file array - * @return the snapshot length - */ -extern int -merge_max_snapshot_length(int in_file_count, merge_in_file_t in_files[]); - -/** Read the next packet, in chronological order, from the set of files to - * be merged. - * - * @param in_file_count number of entries in in_files - * @param in_files input file array - * @param err wiretap error, if failed - * @param err_info wiretap error string, if failed - * @return pointer to wtap for file from which that packet came, or NULL on - * error or EOF - */ -extern wtap * -merge_read_packet(int in_file_count, merge_in_file_t in_files[], int *err, - gchar **err_info); - - -/** Read the next packet, in file sequence order, from the set of files - * to be merged. - * - * @param in_file_count number of entries in in_files - * @param in_files input file array - * @param err wiretap error, if failed - * @param err_info wiretap error string, if failed - * @return pointer to wtap for file from which that packet came, or NULL on - * error or EOF - */ -extern wtap * -merge_append_read_packet(int in_file_count, merge_in_file_t in_files[], - int *err, gchar **err_info); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __MERGE_H__ */ - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/mkstemp.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/mkstemp.h deleted file mode 100644 index be2cae0f..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/mkstemp.h +++ /dev/null @@ -1,24 +0,0 @@ -/* Copyright (C) 1991, 1992, 1996, 1998 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - - -/* Generate a unique temporary file name from TEMPLATE. - The last six characters of TEMPLATE must be "XXXXXX"; - they are replaced with a string that makes the filename unique. - Returns a file descriptor open on the file for reading and writing. */ -int mkstemp (char *template); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/packet-range.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/packet-range.h deleted file mode 100644 index 64702d14..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/packet-range.h +++ /dev/null @@ -1,101 +0,0 @@ -/* packet-range.h - * Packet range routines (save, print, ...) - * - * $Id: packet-range.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Dick Gooris - * Ulf Lamping - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __PACKET_RANGE_H__ -#define __PACKET_RANGE_H__ - -#include - -#include - -#include - -extern guint32 curr_selected_frame; - -typedef enum { - range_process_all, - range_process_selected, - range_process_marked, - range_process_marked_range, - range_process_user_range -} packet_range_e; - -typedef struct packet_range_tag { - /* values coming from the UI */ - packet_range_e process; /* which range to process */ - gboolean process_filtered; /* captured or filtered packets */ - - /* user specified range(s) and, if null, error status */ - range_t *user_range; - convert_ret_t user_range_status; - - /* calculated values */ - guint32 selected_packet; /* the currently selected packet */ - - /* current packet counts (captured) */ - /* cfile.count */ /* packets in capture file */ - /* cfile.marked_count */ /* packets marked */ - guint32 mark_range_cnt; /* packets in marked range */ - guint32 user_range_cnt; /* packets in user specified range */ - - /* current packet counts (displayed) */ - guint32 displayed_cnt; - guint32 displayed_marked_cnt; - guint32 displayed_mark_range_cnt; - guint32 displayed_user_range_cnt; - - /* "enumeration" values */ - gboolean marked_range_active; /* marked range is currently processed */ - guint32 marked_range_left; /* marked range packets left to do */ - gboolean selected_done; /* selected packet already processed */ -} packet_range_t; - -typedef enum { - range_process_this, /* process this packet */ - range_process_next, /* skip this packet, process next */ - range_processing_finished /* stop processing, required packets done */ -} range_process_e; - -/* init the range structure */ -extern void packet_range_init(packet_range_t *range); - -/* check whether the packet range is OK */ -extern convert_ret_t packet_range_check(packet_range_t *range); - -/* init the processing run */ -extern void packet_range_process_init(packet_range_t *range); - -/* do we have to process all packets? */ -extern gboolean packet_range_process_all(packet_range_t *range); - -/* do we have to process this packet? */ -extern range_process_e packet_range_process_packet(packet_range_t *range, frame_data *fdata); - -/* convert user given string to the internal user specified range representation */ -extern void packet_range_convert_str(packet_range_t *range, const gchar *es); - -#endif /* __PACKET_RANGE_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/pcapio.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/pcapio.h deleted file mode 100644 index a675ce30..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/pcapio.h +++ /dev/null @@ -1,44 +0,0 @@ -/* pcapio.h - * Declarations of our own routins for writing libpcap files. - * - * $Id: pcapio.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * Derived from code in the Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* Returns a FILE * to write to on success, NULL on failure; sets "*err" to - an error code, or 0 for a short write, on failure */ -extern FILE * -libpcap_fdopen(int fd, int linktype, int snaplen, long *bytes_written, - int *err); - -/* Write a record for a packet to a dump file. - Returns TRUE on success, FALSE on failure. */ -extern gboolean -libpcap_write_packet(FILE *fp, const struct pcap_pkthdr *phdr, const u_char *pd, - long *bytes_written, int *err); - -extern gboolean -libpcap_dump_flush(FILE *pd, int *err); - -extern gboolean -libpcap_dump_close(FILE *pd, int *err); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/print.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/print.h deleted file mode 100644 index a337dffc..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/print.h +++ /dev/null @@ -1,148 +0,0 @@ -/* print.h - * Definitions for printing packet analysis trees. - * - * $Id: print.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Gilbert Ramirez - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __PRINT_H__ -#define __PRINT_H__ - -#include - -#include "packet-range.h" - -/* - * Print stream code; this provides a "print stream" class with subclasses - * of various sorts. Additional subclasses might be implemented elsewhere. - */ -struct print_stream; - -typedef struct print_stream_ops { - gboolean (*print_preamble)(struct print_stream *self, gchar *filename); - gboolean (*print_line)(struct print_stream *self, int indent, - const char *line); - gboolean (*print_bookmark)(struct print_stream *self, - const gchar *name, const gchar *title); - gboolean (*new_page)(struct print_stream *self); - gboolean (*print_finale)(struct print_stream *self); - gboolean (*destroy)(struct print_stream *self); -} print_stream_ops_t; - -typedef struct print_stream { - const print_stream_ops_t *ops; - void *data; -} print_stream_t; - -extern print_stream_t *print_stream_text_new(int to_file, const char *dest); -extern print_stream_t *print_stream_text_stdio_new(FILE *fh); -extern print_stream_t *print_stream_ps_new(int to_file, const char *dest); -extern print_stream_t *print_stream_ps_stdio_new(FILE *fh); - -extern gboolean print_preamble(print_stream_t *self, gchar *filename); -extern gboolean print_line(print_stream_t *self, int indent, const char *line); -extern gboolean print_bookmark(print_stream_t *self, const gchar *name, - const gchar *title); -extern gboolean new_page(print_stream_t *self); -extern gboolean print_finale(print_stream_t *self); -extern gboolean destroy_print_stream(print_stream_t *self); - -/* print output format */ -typedef enum { - PR_FMT_TEXT, /* plain text */ - PR_FMT_PS /* postscript */ -} print_format_e; - -/* print_range, enum which frames should be printed */ -typedef enum { - print_range_selected_only, /* selected frame(s) only (currently only one) */ - print_range_marked_only, /* marked frames only */ - print_range_all_displayed, /* all frames currently displayed */ - print_range_all_captured /* all frames in capture */ -} print_range_e; - -/* print_dissections, enum how the dissections should be printed */ -typedef enum { - print_dissections_none, /* no dissections at all */ - print_dissections_collapsed, /* no dissection details */ - print_dissections_as_displayed, /* details as displayed */ - print_dissections_expanded /* all dissection details */ -} print_dissections_e; - -typedef struct { - print_stream_t *stream; /* the stream to which we're printing */ - print_format_e format; /* plain text or PostScript */ - gboolean to_file; /* TRUE if we're printing to a file */ - char *file; /* file output pathname */ - char *cmd; /* print command string (not win32) */ - packet_range_t range; - - gboolean print_summary; /* TRUE if we should just print summary; - FALSE if we should print protocol tree. */ - print_dissections_e print_dissections; - gboolean print_hex; /* TRUE if we should also print hex data; - FALSE if we should print only if not dissected. */ - gboolean print_formfeed; /* TRUE if a formfeed should be printed - before each new packet */ -} print_args_t; - -/* - * Print user selected list of fields - */ -struct _output_fields; -typedef struct _output_fields output_fields_t; - -extern output_fields_t* output_fields_new(void); -extern void output_fields_free(output_fields_t* info); -extern void output_fields_add(output_fields_t* info, const gchar* field); -extern gsize output_fields_num_fields(output_fields_t* info); -extern gboolean output_fields_set_option(output_fields_t* info, gchar* option); -extern void output_fields_list_options(FILE *fh); -/* - * Higher-level packet-printing code. - */ - -extern gboolean proto_tree_print(print_args_t *print_args, epan_dissect_t *edt, - print_stream_t *stream); -extern gboolean print_hex_data(print_stream_t *stream, epan_dissect_t *edt); - -extern void write_pdml_preamble(FILE *fh); -extern void proto_tree_write_pdml(epan_dissect_t *edt, FILE *fh); -extern void write_pdml_finale(FILE *fh); - -extern void write_psml_preamble(FILE *fh); -extern void proto_tree_write_psml(epan_dissect_t *edt, FILE *fh); -extern void write_psml_finale(FILE *fh); - -extern void write_csv_preamble(FILE *fh); -extern void proto_tree_write_csv(epan_dissect_t *edt, FILE *fh); -extern void write_csv_finale(FILE *fh); - -extern void write_carrays_preamble(FILE *fh); -extern void proto_tree_write_carrays(const guint8 *pd, guint32 len, guint32 num, FILE *fh); -extern void write_carrays_finale(FILE *fh); - -extern void write_fields_preamble(output_fields_t* fields, FILE *fh); -extern void proto_tree_write_fields(output_fields_t* fields, epan_dissect_t *edt, FILE *fh); -extern void write_fields_finale(output_fields_t* fields, FILE *fh); - -#endif /* print.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/progress_dlg.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/progress_dlg.h deleted file mode 100644 index 0303230e..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/progress_dlg.h +++ /dev/null @@ -1,94 +0,0 @@ -/* progress_dlg.h - * Definitions for progress dialog box routines - * - * $Id: progress_dlg.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __PROGRESS_DLG_H__ -#define __PROGRESS_DLG_H__ - -/** @file - * Progress (modal) dialog box routines. - * @ingroup dialog_group - */ - -/** Progress dialog data. */ -struct progdlg; - -/** Progress dialog data. */ -typedef struct progdlg progdlg_t; - -/** - * Create and pop up the progress dialog. Allocates a "progdlg_t" - * and initialize it to contain all information the implementation - * needs in order to manipulate the dialog, and return a pointer to - * it. - * - * @param task_title the task to do, e.g. "Loading" - * @param item_title the item to do, e.g. "capture.cap" - * @param terminate_is_stop TRUE if the operation can't be cancelled, just - * stopped (i.e., it has a "Stop" button and clicking it doesn't undo - * anything already done), FALSE if it can - * @param stop_flag a pointer to a Boolean variable that will be - * set to TRUE if the user hits that button - * @return the newly created progress dialog - */ -progdlg_t *create_progress_dlg(const gchar *task_title, const gchar *item_title, - gboolean terminate_is_stop, gboolean *stop_flag); - -/** - * Create a progress dialog, but only if it's not likely to disappear - * immediately. This can be disconcerting for the user. - * - * @param task_title the task to do, e.g. "Loading" - * @param item_title the item to do, e.g. "capture.cap" - * @param terminate_is_stop TRUE if the operation can't be cancelled, just - * stopped (i.e., it has a "Stop" button and clicking it doesn't undo - * anything already done), FALSE if it can - * @param stop_flag a pointer to a Boolean variable that will be - * set to TRUE if the user hits that button - * @param start_time a pointer to a GTimeVal structure which holds - * the time at which the caller started to process the data - * @param progress the current progress (0..1) - * @return the newly created progress dialog - */ -progdlg_t * -delayed_create_progress_dlg(const gchar *task_title, const gchar *item_title, - gboolean terminate_is_stop, gboolean *stop_flag, - const GTimeVal *start_time, gfloat progress); - -/** - * Update the progress information of the progress dialog box. - * - * @param dlg the progress dialog from create_progress_dlg() - * @param percentage the current percentage value (0..1) - * @param status the new status string to show, e.g. "3000KB of 6000KB" - */ -void update_progress_dlg(progdlg_t *dlg, gfloat percentage, const gchar *status); - -/** - * Destroy the progress bar. - * - * @param dlg the progress dialog from create_progress_dlg() - */ -void destroy_progress_dlg(progdlg_t *dlg); - -#endif /* __PROGRESS_DLG_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/proto_hier_stats.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/proto_hier_stats.h deleted file mode 100644 index 10fb1e39..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/proto_hier_stats.h +++ /dev/null @@ -1,51 +0,0 @@ -/* proto_hier_stats.h - * - * $Id: proto_hier_stats.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef PROTO_HIER_STATS_H -#define PROTO_HIER_STATS_H - -#include - -typedef struct { - header_field_info *hfinfo; - guint num_pkts_total; - guint num_pkts_last; - guint num_bytes_total; - guint num_bytes_last; -} ph_stats_node_t; - - -typedef struct { - guint tot_packets; - guint tot_bytes; - GNode *stats_tree; - double first_time; /* seconds (msec resolution) of first packet */ - double last_time; /* seconds (msec resolution) of last packet */ -} ph_stats_t; - - -ph_stats_t* ph_stats_new(void); - -void ph_stats_free(ph_stats_t *ps); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ps.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ps.h deleted file mode 100644 index ceafdff6..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ps.h +++ /dev/null @@ -1,35 +0,0 @@ -/* ps.h - * Definitions for generating PostScript(R) packet output. - * - * $Id: ps.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Gilbert Ramirez - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __PS_H__ -#define __PS_H__ - -/* Functions in ps.c; automatically generated by rdps */ - -void print_ps_preamble(FILE *); -void print_ps_finale(FILE *); - -#endif /* ps.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/register.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/register.h deleted file mode 100644 index 2b8906ea..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/register.h +++ /dev/null @@ -1,48 +0,0 @@ -/* register.h - * Definitions for protocol registration - * - * $Id: register.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __REGISTER_H__ -#define __REGISTER_H__ - -#include - -typedef enum { - RA_NONE, /* for initialization */ - RA_DISSECTORS, /* Initializing dissectors */ - RA_LISTENERS, /* Tap listeners */ - RA_REGISTER, /* register */ - RA_PLUGIN_REGISTER, /* plugin register */ - RA_HANDOFF, /* handoff */ - RA_PLUGIN_HANDOFF, /* plugin handoff */ - RA_PREFERENCES, /* module preferences */ - RA_CONFIGURATION /* configuration files */ -} register_action_e; - -typedef void (*register_cb)(register_action_e action, const char *message, gpointer client_data); - -extern void register_all_protocols(register_cb cb, gpointer client_data); -extern void register_all_protocol_handoffs(register_cb cb, gpointer client_data); -extern void register_all_tap_listeners(void); -extern gulong register_count(void); -#endif /* __REGISTER_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ringbuffer.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ringbuffer.h deleted file mode 100644 index 85178edc..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ringbuffer.h +++ /dev/null @@ -1,53 +0,0 @@ -/* ringbuffer.h - * Definitions for capture ringbuffer files - * - * $Id: ringbuffer.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __RINGBUFFER_H__ -#define __RINGBUFFER_H__ - -#ifdef HAVE_LIBPCAP - -#include -#include "file.h" -#include "wiretap/wtap.h" - -#define RINGBUFFER_UNLIMITED_FILES 0 -/* minimum number of ringbuffer files */ -#define RINGBUFFER_MIN_NUM_FILES 0 -/* maximum number of ringbuffer files */ -/* (only to avoid crashes on very large numbers) */ -#define RINGBUFFER_MAX_NUM_FILES 10000 - -int ringbuf_init(const char *capture_name, guint num_files); -const gchar *ringbuf_current_filename(void); -FILE *ringbuf_init_libpcap_fdopen(int linktype, int snaplen, - long *bytes_written, int *err); -gboolean ringbuf_switch_file(FILE **pdh, gchar **save_file, int *save_file_fd, - long *bytes_written, int *err); -gboolean ringbuf_libpcap_dump_close(gchar **save_file, int *err); -void ringbuf_free(void); -void ringbuf_error_cleanup(void); - -#endif /* HAVE_LIBPCAP */ - -#endif /* ringbuffer.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/simple_dialog.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/simple_dialog.h deleted file mode 100644 index fcd35ece..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/simple_dialog.h +++ /dev/null @@ -1,184 +0,0 @@ -/* simple_dialog.h - * Definitions for alert box routines with toolkit-independent APIs but - * toolkit-dependent implementations. - * - * $Id: simple_dialog.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __DIALOG_H__ -#define __DIALOG_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/** @file - * Simple dialog box. - * @ingroup dialog_group - */ - - -/** Dialog types. */ -typedef enum { - ESD_TYPE_INFO, /**< tells the user something they should know, but not requiring - any action; the only button should be "OK" */ - ESD_TYPE_WARN, /**< tells the user about a problem; the only button should be "OK" */ - ESD_TYPE_CONFIRMATION, /**< asks the user for confirmation; there should be more than - one button */ - ESD_TYPE_ERROR, /**< tells the user about a serious problem; the only button should be "OK" */ - ESD_TYPE_STOP /**< tells the user a stop action is in progress, there should be no button */ -} ESD_TYPE_E; - -/** display no buttons at all */ -#define ESD_BTN_NONE 0x00 -/** display an "Ok" button */ -#define ESD_BTN_OK 0x01 -/** display a "Cancel" button */ -#define ESD_BTN_CANCEL 0x02 -/** display a "Yes" button */ -#define ESD_BTN_YES 0x04 -/** display a "No" button */ -#define ESD_BTN_NO 0x08 -/** display a "Clear" button */ -#define ESD_BTN_CLEAR 0x10 -/** display a "Save" button */ -#define ESD_BTN_SAVE 0x20 -/** display a "Continue without Saving" button */ -#define ESD_BTN_DONT_SAVE 0x40 - -/** Standard button combination "Ok" + "Cancel". */ -#define ESD_BTNS_OK_CANCEL (ESD_BTN_OK|ESD_BTN_CANCEL) -/** Standard button combination "Yes" + "No". */ -#define ESD_BTNS_YES_NO (ESD_BTN_YES|ESD_BTN_NO) -/** Standard button combination "Yes" + "No" + "Cancel". */ -#define ESD_BTNS_YES_NO_CANCEL (ESD_BTN_YES|ESD_BTN_NO|ESD_BTN_CANCEL) -/** Standard button combination "No" + "Cancel" + "Save". */ -#define ESD_BTNS_SAVE_DONTSAVE_CANCEL (ESD_BTN_DONT_SAVE|ESD_BTN_CANCEL|ESD_BTN_SAVE) - -#if __GNUC__ >= 2 -/** Create and show a simple dialog. - * - * @param type type of dialog - * @param btn_mask the buttons to display - * @param msg_format printf like message format - * @param ... printf like parameters - * @return the newly created dialog - */ -extern gpointer simple_dialog(ESD_TYPE_E type, gint btn_mask, - const gchar *msg_format, ...) - __attribute__((format (printf, 3, 4))); -/** Create and show a simple dialog using a va_list. - * - * @param type type of dialog - * @param btn_mask the buttons to display - * @param msg_format printf like message format - * @param ap parameters - * @return the newly created dialog - */ -extern gpointer vsimple_dialog(ESD_TYPE_E type, gint btn_mask, - const gchar *msg_format, va_list ap); -#else -/** Create and show a simple dialog. - * - * @param type type of dialog - * @param btn_mask the buttons to display - * @param msg_format printf like message format - * @param ... printf like parameters - * @return the newly created dialog - */ -extern gpointer simple_dialog(ESD_TYPE_E type, gint btn_mask, - const gchar *msg_format, ...); -/** Create and show a simple dialog using a va_list. - * - * @param type type of dialog - * @param btn_mask the buttons to display - * @param msg_format printf like message format - * @param ap parameters - * @return the newly created dialog - */ -extern gpointer vsimple_dialog(ESD_TYPE_E type, gint btn_mask, - const gchar *msg_format, va_list ap); -#endif - -/** Callback function type for simple_dialog_set_cb() */ -typedef void (* simple_dialog_cb_t) (gpointer dialog, gint btn, gpointer data); - -/** Set the callback function for the dialog, called when a button was pressed. - * - * @param dialog the dialog from simple_dialog() - * @param callback_fct the callback function to set - * @param data data to be passed to the callback function - */ -extern void simple_dialog_set_cb(gpointer dialog, simple_dialog_cb_t callback_fct, gpointer data); - -/** Close the dialog, useful for "no button" dialogs. - * - * @param dialog the dialog to close from simple_dialog() - */ -extern void simple_dialog_close(gpointer dialog); - -/** Add a check button to the dialog (e.g. "Don't show this message again") - * - * @param dialog the dialog from simple_dialog() - * @param text the text to display - */ -extern void simple_dialog_check_set(gpointer dialog, gchar *text); - -/** Get the check buttons state. - * - * @param dialog the dialog from simple_dialog() - * @return current button state (TRUE is checked) - */ -extern gboolean simple_dialog_check_get(gpointer dialog); - -/** Surround the primary dialog message text by - * simple_dialog_primary_start() and simple_dialog_primary_end(). - * To highlight the first sentence (will take effect on GTK2 only). - */ -extern char *simple_dialog_primary_start(void); -/** Surround the primary dialog message text by - * simple_dialog_primary_start() and simple_dialog_primary_end(). - * To highlight the first sentence (will take effect on GTK2 only). - */ -extern char *simple_dialog_primary_end(void); - -/** Escape the message text, if it probably contains Pango escape sequences. - * For example html like tags starting with a <. - * - * @param msg the string to escape - * @return the escaped message text, must be freed with g_free() later - */ -extern char *simple_dialog_format_message(const char *msg); - -/** - * Display all queued messages. - * If a routine is called to display a dialog before there are any windows - * open, information to use to display the dialog is queued up. This - * routine should be called once there are windows open, so that the queued - * up dialogs are displayed on top of those windows. - */ -extern void display_queued_messages(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __DIALOG_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/stat_menu.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/stat_menu.h deleted file mode 100644 index 1a7bd7f1..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/stat_menu.h +++ /dev/null @@ -1,64 +0,0 @@ -/* stat_menu.h - * Menu definitions for use by stats - * - * $Id: stat_menu.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef __STATMENU_H__ -#define __STATMENU_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/** @file - * Add a new menu item for a stat. - */ - -/* - * XXX - defines stuff usable regardless of the GUI toolkit. Right now, - * that's only the menu group, which is used by tap_dfilter_dlg.h. - * - * XXX - stats should be able to register additional menu groups, although - * the question then would be "in what order should they appear in the menu?" - */ - -/** The menu group this stat should be registered in. */ -typedef enum { - REGISTER_STAT_GROUP_NONE, - REGISTER_STAT_GROUP_GENERIC, - REGISTER_STAT_GROUP_CONVERSATION_LIST, - REGISTER_STAT_GROUP_ENDPOINT_LIST, - REGISTER_STAT_GROUP_RESPONSE_TIME, - REGISTER_STAT_GROUP_TELEPHONY, - /* XXX - split into telephony and VoIP? */ - REGISTER_ANALYZE_GROUP_NONE, - REGISTER_ANALYZE_GROUP_CONVERSATION_FILTER -#ifdef HAVE_LUA_5_1 - ,REGISTER_TOOLS_GROUP_NONE -#endif -} register_stat_group_t; - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __STATMENU_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/statusbar.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/statusbar.h deleted file mode 100644 index cde19b35..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/statusbar.h +++ /dev/null @@ -1,56 +0,0 @@ -/* statusbar.h - * Definitions for status bar UI routines - * - * $Id: statusbar.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __STATUSBAR_H__ -#define __STATUSBAR_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* - * Push a message referring to file access onto the statusbar. - */ -void statusbar_push_file_msg(const gchar *msg); - -/* - * Pop a message referring to file access off the statusbar. - */ -void statusbar_pop_file_msg(void); - -/* - * Push a message referring to the currently-selected field onto the statusbar. - */ -void statusbar_push_field_msg(const gchar *msg); - -/* - * Pop a message referring to the currently-selected field off the statusbar. - */ -void statusbar_pop_field_msg(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __STATUSBAR_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/strerror.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/strerror.h deleted file mode 100644 index 2f509795..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/strerror.h +++ /dev/null @@ -1,33 +0,0 @@ -/* strerror.h - * - * $Id: strerror.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __STRERROR_H__ -#define __STRERROR_H__ - -/* - * Version of "strerror()", for the benefit of OSes that don't have it - * (e.g., SunOS 4.x). - */ -extern char *strerror(int); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/strptime.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/strptime.h deleted file mode 100644 index 0bfc58b1..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/strptime.h +++ /dev/null @@ -1,32 +0,0 @@ -/* strptime.h - * - * $Id: strptime.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __STRPTIME_H__ -#define __STRPTIME_H__ - -/* - * Version of "strptime()", for the benefit of OSes that don't have it. - */ -extern char *strptime(const char *, const char *, struct tm *); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/summary.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/summary.h deleted file mode 100644 index 1cc43328..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/summary.h +++ /dev/null @@ -1,76 +0,0 @@ -/* summary.h - * Definitions for capture file summary data - * - * $Id: summary.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __SUMMARY_H__ -#define __SUMMARY_H__ - -#ifdef HAVE_LIBPCAP -#include "capture.h" -#endif - -typedef struct _summary_tally { - guint64 bytes; /* total bytes */ - double start_time; /* seconds, with msec resolution */ - double stop_time; /* seconds, with msec resolution */ - double elapsed_time; /* seconds, with msec resolution, - includes time before first packet - and after last packet */ - int marked_count; /* number of marked packets */ - guint64 marked_bytes; /* total bytes in the marked packets */ - double marked_start; /* time in seconds, with msec resolution */ - double marked_stop; /* time in seconds, with msec resolution */ - int packet_count; /* total number of packets in trace */ - int filtered_count; /* number of filtered packets */ - guint64 filtered_bytes; /* total bytes in the filtered packets */ - double filtered_start; /* time in seconds, with msec resolution */ - double filtered_stop; /* time in seconds, with msec resolution */ - const char *filename; - gint64 file_length; /* file length in bytes */ - int encap_type; /* wiretap encapsulation type */ - gboolean has_snap; /* TRUE if maximum capture packet length is known */ - int snap; /* Maximum captured packet length */ - gboolean drops_known; /* TRUE if number of packet drops is known */ - guint64 drops; /* number of packet drops */ - const char *dfilter; /* display filter */ - - /* capture related, use summary_fill_in_capture() to get values */ - const char *cfilter; /* capture filter */ - const char *iface; /* interface name */ - const char *iface_descr;/* descriptive interface name */ -} summary_tally; - -extern void -summary_fill_in(capture_file *cf, summary_tally *st); - -#ifdef HAVE_LIBPCAP -extern void -summary_fill_in_capture(capture_options *capture_opts, summary_tally *st); -#endif - -#endif /* summary.h */ - - - - - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/svnversion.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/svnversion.h deleted file mode 100644 index b3f53a6d..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/svnversion.h +++ /dev/null @@ -1 +0,0 @@ -/* #define SVNVERSION "" */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/sync_pipe.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/sync_pipe.h deleted file mode 100644 index 71d91ccd..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/sync_pipe.h +++ /dev/null @@ -1,80 +0,0 @@ -/* sync_pipe.h - * Low-level synchronization pipe routines for use by Wireshark/TShark - * and dumpcap - * - * $Id: sync_pipe.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - - -/** @file - * - * Low-level sync pipe interfaces. - */ - -#ifndef __SYNC_PIPE_H__ -#define __SYNC_PIPE_H__ - - -/* - * Maximum length of sync pipe message data. Must be < 2^24, as the - * message length is 3 bytes. - * XXX - this must be large enough to handle a Really Big Filter - * Expression, as the error message for an incorrect filter expression - * is a bit larger than the filter expression. - */ -#define SP_MAX_MSG_LEN 4096 - - -/* Size of buffer to hold decimal representation of - signed/unsigned 64-bit int */ -#define SP_DECISIZE 20 - -/* - * Indications sent out on the sync pipe (from child to parent). - */ -#define SP_FILE 'F' /* the name of the recently opened file */ -#define SP_ERROR_MSG 'E' /* error message */ -#define SP_BAD_FILTER 'B' /* error message for bad capture filter */ -#define SP_PACKET_COUNT 'P' /* count of packets captured since last message */ -#define SP_DROPS 'D' /* count of packets dropped in capture */ -/* - * Win32 only: Indications sent out on the signal pipe (from parent to child) - * (UNIX-like sends signals for this) - */ -#define SP_QUIT 'Q' /* "gracefully" capture quit message (SIGUSR1) */ - -/* write a single message header to the recipient pipe */ -extern int -pipe_write_header(int pipe, char indicator, int length); - -/* write a message to the recipient pipe in the standard format - (3 digit message length (excluding length and indicator field), - 1 byte message indicator and the rest is the message). - If msg is NULL, the message has only a length and indicator. */ -extern void -pipe_write_block(int pipe, char indicator, const char *msg); - -/** the child encountered an error, notify the parent */ -extern void -sync_pipe_errmsg_to_parent(int pipe, const char *error_msg, - const char *secondary_error_msg); - -#endif /* sync_pipe.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tap-rtp-common.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tap-rtp-common.h deleted file mode 100644 index b20db362..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tap-rtp-common.h +++ /dev/null @@ -1,49 +0,0 @@ -/* tap-rtp-common.h - * RTP streams handler functions used by tshark and wireshark - * - * $Id: tap-rtp-common.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Copyright 2008, Ericsson AB - * By Balint Reczey - * - * most functions are copied from gtk/rtp_stream.c and gtk/rtp_analisys.c - * Copyright 2003, Alcatel Business Systems - * By Lars Ruoff - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef TAP_RTP_COMMON_H_INCLUDED -#define TAP_RTP_COMMON_H_INCLUDED - -#include "gtk/rtp_stream.h" - -gint rtp_stream_info_cmp(gconstpointer, gconstpointer); -void rtpstream_reset_cb(void*); -void rtp_write_header(rtp_stream_info_t*, FILE*); -void rtp_write_sample(rtp_sample_t*, FILE*); -int rtpstream_packet(void*, packet_info*, epan_dissect_t *, const void *); - -/* The one and only global rtpstream_tapinfo_t structure for tshark and wireshark. - */ -static rtpstream_tapinfo_t the_tapinfo_struct = - {0, NULL, 0, TAP_ANALYSE, NULL, NULL, NULL, 0, FALSE}; - - -#endif /*TAP_RTP_COMMON_H_INCLUDED*/ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tap_dfilter_dlg.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tap_dfilter_dlg.h deleted file mode 100644 index ae39ce3d..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tap_dfilter_dlg.h +++ /dev/null @@ -1,73 +0,0 @@ -/* tap_dfilter_dlg.h - * Header file for display filter dialog used by gui taps - * Copyright 2003 Lars Roland - * - * $Id: tap_dfilter_dlg.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* - * You can easily add a display filter dialog for your gui tap by using - * the following infrastructure: - * - * Define a global structure of tap_dfilter_dlg within your tap source file. - * Initiate it with: - * 1) a title string for the Dialog Window - * 2) the init string, which is the same as the string after "-z" option without - * the filter string and without the separating comma. - * 3) a pointer to the init function of the tap, which will be called when you click - * on the start button in the display filter dialog. - * 4) the index with "-1" - * - * Within register_tap_menu_yourtap(void), call register_dfilter_stat() - * with a pointer to the tap_dfilter_dlg structure, a string for the - * menu item (don't put "..." at the end, register_dfilter_stat() will - * add it for you), and the REGISTER_STAT_GROUP_ value for the stat - * group to which your stat should belong. - * - * Usage: - * - * tap_dfilter_dlg my_tap_dfilter_dlg = {"My Title", "myproto,mytap", gtk_mytap_init, -1}; - * - * register_tap_menu_mytap(void) { - * register_dfilter_stat(&my_tap_dfilter_dlg, "My Menu Item", - * REGISTER_STAT_GROUP_my_group); - * } - * - * See also: h225_ras_srt.c or h225_counter.c - * - */ - -typedef struct _tap_dfilter_dlg { - const char *win_title; /* title */ - const char *init_string; /* the string to call the tap without a filter via "-z" option */ - void (* tap_init_cb)(const char *,void*); /* callback to init function of the tap */ - gint index; /* initiate this value always with "-1" */ -} tap_dfilter_dlg; - -/* - * Register a stat that has a display filter dialog. - * We register it both as a command-line stat and a menu item stat. - */ -void register_dfilter_stat(tap_dfilter_dlg *info, const char *name, - register_stat_group_t group); - -/* This will update the titles of the dialog windows when we load a new capture file. */ -void tap_dfilter_dlg_update (void); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tempfile.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tempfile.h deleted file mode 100644 index ce13a49d..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tempfile.h +++ /dev/null @@ -1,43 +0,0 @@ -/* tempfile.h - * Declarations of routines to create temporary files - * - * $Id: tempfile.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __TEMPFILE_H__ -#define __TEMPFILE_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* create a tempfile with the given prefix (e.g. "ether") - * namebuf (and namebuflen) should be 128+1 bytes long (BTW: why?) - * returns the file descriptor of the new tempfile and - * the name of the new file in namebuf - */ -int create_tempfile(char *namebuf, int namebuflen, const char *pfx); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __TEMPFILE_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/text2pcap.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/text2pcap.h deleted file mode 100644 index 4ca4f1fa..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/text2pcap.h +++ /dev/null @@ -1,49 +0,0 @@ -/**-*-C-*-********************************************************************** - * - * text2pcap.h - * - * Utility to convert an ASCII hexdump into a libpcap-format capture file - * - * (c) Copyright 2001 Ashok Narayanan - * - * $Id: text2pcap.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - *******************************************************************************/ - - -#ifndef TEXT2PCAP_H -#define TEXT2PCAP_H - -typedef enum { - T_BYTE = 1, - T_OFFSET, - T_DIRECTIVE, - T_TEXT, - T_EOL -} token_t; - -void parse_token(token_t token, char *str); - -int yylex(void); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/timestats.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/timestats.h deleted file mode 100644 index 7c418f09..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/timestats.h +++ /dev/null @@ -1,54 +0,0 @@ -/* timestats.h - * Routines and definitions for time statistics - * Copyrigth 2003 Lars Roland - * - * $Id: timestats.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef _time_stat -#define _time_stat - -#include -#include "epan/packet_info.h" -#include "epan/nstime.h" - - /* Summary of time statistics*/ -typedef struct _timestat_t { - guint32 num; /* number of samples */ - guint32 min_num; /* frame number of minimum */ - guint32 max_num; /* frame number of maximum */ - nstime_t min; - nstime_t max; - nstime_t tot; - gdouble variance; -} timestat_t; - -/* functions */ - -/* Initialize a timestat_t struct */ -extern void time_stat_init(timestat_t *stats); - -/* Update a timestat_t struct with a new sample */ -extern void time_stat_update(timestat_t *stats, const nstime_t *delta, packet_info *pinfo); - -extern gdouble get_average(const nstime_t *sum, guint32 num); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tools/make-dissector-reg b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tools/make-dissector-reg deleted file mode 100755 index d2efa7c6..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tools/make-dissector-reg +++ /dev/null @@ -1,186 +0,0 @@ -#! /bin/sh - -# -# $Id: make-dissector-reg 21716 2007-05-07 17:55:42Z gal $ -# - -# -# The first argument is the directory in which the source files live. -# -srcdir="$1" -shift - -# -# The second argument is either "plugin" or "dissectors"; if it's -# "plugin", we build a plugin.c for a plugin, and if it's -# "dissectors", we build a register.c for libwireshark. -# -registertype="$1" -shift -if [ "$registertype" = plugin ] -then - outfile="plugin.c" -elif [ "$registertype" = dissectors ] -then - outfile="register.c" -else - echo "Unknown output type '$registertype'" 1>&2 - exit 1 -fi - -# -# All subsequent arguments are the files to scan. -# -rm -f ${outfile}-tmp -echo '/* Do not modify this file. */' >${outfile}-tmp -echo '/* It is created automatically by the Makefile. */'>>${outfile}-tmp -if [ "$registertype" = plugin ] -then - cat <<"EOF" >>${outfile}-tmp -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include - -#include "moduleinfo.h" - -#ifndef ENABLE_STATIC -G_MODULE_EXPORT const gchar version[] = VERSION; - -/* Start the functions we need for the plugin stuff */ - -G_MODULE_EXPORT void -plugin_register (void) -{ -EOF -# -# Build code to call all the protocol registration routines. -# -for f in "$@" -do - if [ -f $f ] - then - srcfile=$f - else - srcfile=$srcdir/$f - fi - grep '^proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' -done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp -for f in "$@" -do - if [ -f $f ] - then - srcfile=$f - else - srcfile=$srcdir/$f - fi - grep '^void proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' -done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp -else - cat <<"EOF" >>${outfile}-tmp -#include "register.h" -void -register_all_protocols(register_cb cb, gpointer client_data) -{ -EOF -# -# Build code to call all the protocol registration routines. -# -for f in "$@" -do - if [ -f $f ] - then - srcfile=$f - else - srcfile=$srcdir/$f - fi - grep '^proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' -done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_REGISTER, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp -for f in "$@" -do - if [ -f $f ] - then - srcfile=$f - else - srcfile=$srcdir/$f - fi - grep '^void proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' -done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_REGISTER, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp - -fi -echo '}' >>${outfile}-tmp - - -# -# Build code to call all the protocol handoff registration routines. -# -if [ "$registertype" = plugin ] -then - cat <<"EOF" >>${outfile}-tmp -G_MODULE_EXPORT void -plugin_reg_handoff(void) -{ -EOF -for f in "$@" -do - if [ -f $f ] - then - srcfile=$f - else - srcfile=$srcdir/$f - fi - grep '^proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' -done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp -for f in "$@" -do - if [ -f $f ] - then - srcfile=$f - else - srcfile=$srcdir/$f - fi - grep '^void proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' -done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp -else - cat <<"EOF" >>${outfile}-tmp -void -register_all_protocol_handoffs(register_cb cb, gpointer client_data) -{ -EOF -for f in "$@" -do - if [ -f $f ] - then - srcfile=$f - else - srcfile=$srcdir/$f - fi - grep '^proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' -done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_HANDOFF, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp -for f in "$@" -do - if [ -f $f ] - then - srcfile=$f - else - srcfile=$srcdir/$f - fi - grep '^void proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' -done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_HANDOFF, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp -fi -echo '}' >>${outfile}-tmp -if [ "$registertype" = plugin ] -then - echo '#endif' >>${outfile}-tmp -else - cat <<"EOF" >>${outfile}-tmp -gulong register_count(void) -{ -EOF - proto_regs=`grep RA_REGISTER ${outfile}-tmp | wc -l` - handoff_regs=`grep RA_HANDOFF ${outfile}-tmp | wc -l` - echo " return $proto_regs + $handoff_regs;" >>${outfile}-tmp - echo '}' >>${outfile}-tmp -fi -mv ${outfile}-tmp ${outfile} diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tools/make-dissector-reg.py b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tools/make-dissector-reg.py deleted file mode 100755 index c3354279..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tools/make-dissector-reg.py +++ /dev/null @@ -1,238 +0,0 @@ -#!/usr/bin/env python -# -# Looks for registration routines in the protocol dissectors, -# and assembles C code to call all the routines. -# -# This is a Python version of the make-reg-dotc shell script. -# Running the shell script on Win32 is very very slow because of -# all the process-launching that goes on --- multiple greps and -# seds for each input file. I wrote this python version so that -# less processes would have to be started. -# -# $Id: make-dissector-reg.py 24390 2008-02-19 13:44:02Z wmeier $ - -import os -import sys -import re -import pickle -from stat import * - -# -# The first argument is the directory in which the source files live. -# -srcdir = sys.argv[1] - -# -# The second argument is either "plugin" or "dissectors"; if it's -# "plugin", we build a plugin.c for a plugin, and if it's -# "dissectors", we build a register.c for libwireshark. -# -registertype = sys.argv[2] -if registertype == "plugin": - tmp_filename = "plugin.c-tmp" - final_filename = "plugin.c" - cache_filename = None -elif registertype == "dissectors": - tmp_filename = "register.c-tmp" - final_filename = "register.c" - cache_filename = "register-cache.pkl" -else: - print "Unknown output type '%s'" % registertype - sys.exit(1) - - -# -# All subsequent arguments are the files to scan. -# -files = sys.argv[3:] - -# Create the proper list of filenames -filenames = [] -for file in files: - if os.path.isfile(file): - filenames.append(file) - else: - filenames.append("%s/%s" % (srcdir, file)) - -if len(filenames) < 1: - print "No files found" - sys.exit(1) - - -# Look through all files, applying the regex to each line. -# If the pattern matches, save the "symbol" section to the -# appropriate array. -regs = { - 'proto_reg': [], - 'handoff_reg': [], - } - -# For those that don't know Python, r"" indicates a raw string, -# devoid of Python escapes. -proto_regex0 = r"^(?Pproto_register_[_A-Za-z0-9]+)\s*\([^;]+$" -proto_regex1 = r"void\s+(?Pproto_register_[_A-Za-z0-9]+)\s*\([^;]+$" - -handoff_regex0 = r"^(?Pproto_reg_handoff_[_A-Za-z0-9]+)\s*\([^;]+$" -handoff_regex1 = r"void\s+(?Pproto_reg_handoff_[_A-Za-z0-9]+)\s*\([^;]+$" - -# This table drives the pattern-matching and symbol-harvesting -patterns = [ - ( 'proto_reg', re.compile(proto_regex0) ), - ( 'proto_reg', re.compile(proto_regex1) ), - ( 'handoff_reg', re.compile(handoff_regex0) ), - ( 'handoff_reg', re.compile(handoff_regex1) ), - ] - -# Open our registration symbol cache -cache = None -if cache_filename: - try: - cache_file = open(cache_filename, 'rb') - cache = pickle.load(cache_file) - cache_file.close() - except: - cache = {} - -# Grep -for filename in filenames: - file = open(filename) - cur_mtime = os.fstat(file.fileno())[ST_MTIME] - if cache and cache.has_key(filename): - cdict = cache[filename] - if cur_mtime == cdict['mtime']: -# print "Pulling %s from cache" % (filename) - regs['proto_reg'].extend(cdict['proto_reg']) - regs['handoff_reg'].extend(cdict['handoff_reg']) - file.close() - continue - # We don't have a cache entry - if cache is not None: - cache[filename] = { - 'mtime': cur_mtime, - 'proto_reg': [], - 'handoff_reg': [], - } -# print "Searching %s" % (filename) - for line in file.readlines(): - for action in patterns: - regex = action[1] - match = regex.search(line) - if match: - symbol = match.group("symbol") - sym_type = action[0] - regs[sym_type].append(symbol) - if cache is not None: -# print "Caching %s for %s: %s" % (sym_type, filename, symbol) - cache[filename][sym_type].append(symbol) - file.close() - -if cache is not None and cache_filename is not None: - cache_file = open(cache_filename, 'wb') - pickle.dump(cache, cache_file) - cache_file.close() - -# Make sure we actually processed something -if len(regs['proto_reg']) < 1: - print "No protocol registrations found" - sys.exit(1) - -# Sort the lists to make them pretty -regs['proto_reg'].sort() -regs['handoff_reg'].sort() - -reg_code = open(tmp_filename, "w") - -reg_code.write("/* Do not modify this file. */\n") -reg_code.write("/* It is created automatically by the Makefile. */\n") - -# Make the routine to register all protocols -if registertype == "plugin": - reg_code.write(""" -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include - -#include "moduleinfo.h" - -#ifndef ENABLE_STATIC -G_MODULE_EXPORT const gchar version[] = VERSION; - -/* Start the functions we need for the plugin stuff */ - -G_MODULE_EXPORT void -plugin_register (void) -{ -"""); -else: - reg_code.write(""" -#include "register.h" -void -register_all_protocols(register_cb cb, gpointer client_data) -{ -"""); - -for symbol in regs['proto_reg']: - if registertype == "plugin": - line = " {extern void %s (void); %s ();}\n" % (symbol, symbol) - else: - line = " {extern void %s (void); if(cb) (*cb)(RA_REGISTER, \"%s\", client_data); %s ();}\n" % (symbol, symbol, symbol) - reg_code.write(line) - -reg_code.write("}\n") - - -# Make the routine to register all protocol handoffs -if registertype == "plugin": - reg_code.write(""" -G_MODULE_EXPORT void -plugin_reg_handoff(void) -{ -"""); -else: - reg_code.write(""" -void -register_all_protocol_handoffs(register_cb cb, gpointer client_data) -{ -"""); - -for symbol in regs['handoff_reg']: - if registertype == "plugin": - line = " {extern void %s (void); %s ();}\n" % (symbol, symbol) - else: - line = " {extern void %s (void); if(cb) (*cb)(RA_HANDOFF, \"%s\", client_data); %s ();}\n" % (symbol, symbol, symbol) - reg_code.write(line) - -reg_code.write("}\n") - -if registertype == "plugin": - reg_code.write("#endif\n"); -else: - reg_code.write(""" -gulong register_count(void) -{ -"""); - - line = " return %d + %d;\n" % (len(regs['proto_reg']), len(regs['handoff_reg'])) - reg_code.write(line) - - reg_code.write(""" -} -"""); - - -# Close the file -reg_code.close() - -# Remove the old final_file if it exists. -try: - os.stat(final_filename) - os.remove(final_filename) -except OSError: - pass - -# Move from tmp file to final file -os.rename(tmp_filename, final_filename) - - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ui_util.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ui_util.h deleted file mode 100644 index fa591a51..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ui_util.h +++ /dev/null @@ -1,79 +0,0 @@ -/* ui_util.h - * Declarations of UI utility routines; these routines have GUI-independent - * APIs, but GUI-dependent implementations, so that they can be called by - * GUI-independent code to affect the GUI. - * - * $Id: ui_util.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __UI_UTIL_H__ -#define __UI_UTIL_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* gui_utils.c */ - -/* Set the name of the top-level window and its icon. */ -void set_main_window_name(const gchar *); -/* Update the name of the main window if the user-specified decoration - changed. */ -void update_main_window_name(void); -/* update the main window */ -extern void main_window_update(void); -/* exit the main window */ -extern void main_window_exit(void); -/* quit a nested main window */ -extern void main_window_nested_quit(void); -/* quit the main window */ -extern void main_window_quit(void); - -/* read from a pipe (callback) */ -typedef gboolean (*pipe_input_cb_t) (gint source, gpointer user_data); -/* install callback function, called if pipe input is available */ -extern void pipe_input_set_handler(gint source, gpointer user_data, int *child_process, pipe_input_cb_t input_cb); - -/* packet_list.c */ - -/* packet list related functions */ -void packet_list_clear(void); -void packet_list_freeze(void); -void packet_list_thaw(void); -void packet_list_select_row(gint); -void packet_list_moveto_end(void); -gint packet_list_append(const gchar *text[], gpointer data); -void packet_list_set_colors(gint, color_t *, color_t *); -gint packet_list_find_row_from_data(gpointer); -void packet_list_set_text(gint, gint, const gchar *); -void packet_list_set_cls_time_width(gint); -gpointer packet_list_get_row_data(gint); -void packet_list_set_selected_row(gint); -gint packet_list_get_sort_column(void); -void packet_list_set_sort_column(void); -gboolean packet_list_check_end(void); - - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __UI_UTIL_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/util.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/util.h deleted file mode 100644 index 2a4198f0..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/util.h +++ /dev/null @@ -1,60 +0,0 @@ -/* util.h - * Utility definitions - * - * $Id: util.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __UTIL_H__ -#define __UTIL_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* Collect command-line arguments as a string consisting of the arguments, - * separated by spaces. - */ -char *get_args_as_string(int argc, char **argv, int optind); - -/* Compute the difference between two seconds/microseconds time stamps. - * Beware: we're using nanosecond resolution now and function is currently unused - */ -void compute_timestamp_diff(gint *diffsec, gint *diffusec, - guint32 sec1, guint32 usec1, guint32 sec2, guint32 usec2); - -/* Try to figure out if we're remotely connected, e.g. via ssh or - Terminal Server, and create a capture filter that matches aspects of the - connection. We match the following environment variables: - - SSH_CONNECTION (ssh): - SSH_CLIENT (ssh): - REMOTEHOST (tcsh, others?): - DISPLAY (x11): [remote name]: - CLIENTNAME (terminal server): - */ -const char *get_conn_cfilter(void); - - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __UTIL_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/version_info.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/version_info.h deleted file mode 100644 index b036fbd2..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/version_info.h +++ /dev/null @@ -1,79 +0,0 @@ -/* version_info.h - * Declarations of outines to report version information for stuff used - * by Wireshark - * - * $Id: version_info.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __VERSION_INFO_H__ -#define __VERSION_INFO_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* - * The svn version string or "" - */ -extern const gchar *wireshark_svnversion; - -/* - * Get various library compile-time versions and append them to - * the specified GString. - * - * "additional_info" is called at the end to append any additional - * information; this is required in order to, for example, put the - * Portaudio information at the end of the string, as we currently - * don't use Portaudio in TShark. - */ -void get_compiled_version_info(GString *str, - void (*additional_info)(GString *)); - -/* - * Get compile-time information used only by applications that use - * libwireshark. - */ -void get_epan_compiled_version_info(GString *str); - -/* - * Get various library run-time versions, and the OS version, and append - * them to the specified GString. - */ -void get_runtime_version_info(GString *str, - void (*additional_info)(GString *)); - -/* - * Get copyright information. - */ -const char *get_copyright_info(void); - -#if defined(_WIN32) -/* - * Get the major OS version. - */ -guint32 get_os_major_version(); -#endif - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __VERSION_INFO_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/5views.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/5views.h deleted file mode 100644 index 2ae18a3a..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/5views.h +++ /dev/null @@ -1,30 +0,0 @@ -/* 5views.h - * - * $Id: 5views.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __5VIEWS_H__ -#define __5VIEWS_H__ - -int _5views_open(wtap *wth, int *err, gchar **err_info); -gboolean _5views_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); -int _5views_dump_can_write_encap(int encap); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/airopeek9.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/airopeek9.h deleted file mode 100644 index df7a946b..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/airopeek9.h +++ /dev/null @@ -1,29 +0,0 @@ -/* airopeek9.h - * - * $Id: airopeek9.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __W_AIROPEEK9_H__ -#define __W_AIROPEEK9_H__ - -int airopeek9_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-grammar.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-grammar.h deleted file mode 100644 index c705d457..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-grammar.h +++ /dev/null @@ -1,90 +0,0 @@ -/* A Bison parser, made by GNU Bison 2.3. */ - -/* Skeleton interface for Bison's Yacc-like parsers in C - - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 - Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. */ - -/* As a special exception, you may create a larger work that contains - part or all of the Bison parser skeleton and distribute that work - under terms of your choice, so long as that work isn't itself a - parser generator using the skeleton or a modified version thereof - as a parser skeleton. Alternatively, if you modify or redistribute - the parser skeleton itself, you may (at your option) remove this - special exception, which will cause the skeleton and the resulting - Bison output files to be licensed under the GNU General Public - License without this special exception. - - This special exception was added by the Free Software Foundation in - version 2.2 of Bison. */ - -/* Tokens. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - STRING = 258, - KEYWORD = 259, - WDD_DATE = 260, - WDD_CHUNK = 261, - COUNTER = 262, - SLASH_SUFFIX = 263, - WDS_PREFIX = 264, - ISDN_PREFIX = 265, - ETHER_PREFIX = 266, - DECNUM = 267, - HEXNUM = 268, - HEXBYTE = 269 - }; -#endif -/* Tokens. */ -#define STRING 258 -#define KEYWORD 259 -#define WDD_DATE 260 -#define WDD_CHUNK 261 -#define COUNTER 262 -#define SLASH_SUFFIX 263 -#define WDS_PREFIX 264 -#define ISDN_PREFIX 265 -#define ETHER_PREFIX 266 -#define DECNUM 267 -#define HEXNUM 268 -#define HEXBYTE 269 - - - - -#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef union YYSTYPE -#line 162 "./ascend-grammar.y" -{ -gchar *s; -guint32 d; -guint8 b; -} -/* Line 1489 of yacc.c. */ -#line 83 "ascend-grammar.h" - YYSTYPE; -# define yystype YYSTYPE /* obsolescent; will be withdrawn */ -# define YYSTYPE_IS_DECLARED 1 -# define YYSTYPE_IS_TRIVIAL 1 -#endif - -extern YYSTYPE ascendlval; - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-int.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-int.h deleted file mode 100644 index 6210d8dd..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-int.h +++ /dev/null @@ -1,54 +0,0 @@ -/* ascend-int.h - * Definitions for routines common to multiple modules in the Lucent/Ascend - * capture file reading code code, but not used outside that code. - * - * $Id: ascend-int.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __ASCEND_INT_H__ -#define __ASCEND_INT_H__ - -typedef struct { - time_t start_time; - time_t secs; - int usecs; - guint32 caplen; - guint32 len; -} ascend_pkthdr; - -extern int at_eof; - -extern const gchar *ascend_parse_error; - -/* - * Pointer to the pseudo-header for the current packet. - */ -extern struct ascend_phdr *pseudo_header; - -/* Here we provide interfaces to make our scanner act and look like lex */ -int ascendlex(void); - -void init_parse_ascend(void); -void ascend_init_lexer(FILE_T fh); -int parse_ascend(FILE_T fh, guint8 *pd, struct ascend_phdr *phdr, - ascend_pkthdr *hdr, gint64 *start_of_data); - -#endif /* ! __ASCEND_INT_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-scanner_lex.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-scanner_lex.h deleted file mode 100644 index 68794f14..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-scanner_lex.h +++ /dev/null @@ -1,6 +0,0 @@ -/* This is generated by runlex.sh. Do not edit it. */ -#define yylex ascendlex -#ifndef YY_DECL -#define YY_DECL int yylex(void) -#endif -YY_DECL; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend.h deleted file mode 100644 index 1c749aac..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend.h +++ /dev/null @@ -1,33 +0,0 @@ -/* ascend.h - * - * $Id: ascend.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __ASCEND_H__ -#define __ASCEND_H__ - -#define ASCEND_MAX_DATA_ROWS 8 -#define ASCEND_MAX_DATA_COLS 16 -#define ASCEND_MAX_PKT_LEN (ASCEND_MAX_DATA_ROWS * ASCEND_MAX_DATA_COLS) - -int ascend_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/atm.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/atm.h deleted file mode 100644 index f6aa08c8..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/atm.h +++ /dev/null @@ -1,40 +0,0 @@ -/* atm.h - * - * $Id: atm.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __ATM_H__ -#define __ATM_H__ - -/* - * Routines to use with ATM capture file types that don't include information - * about the *type* of ATM traffic (or, at least, where we haven't found - * that information). - */ - -extern void -atm_guess_traffic_type(const guint8 *pd, guint32 len, - union wtap_pseudo_header *pseudo_header); - -extern void -atm_guess_lane_type(const guint8 *pd, guint32 len, - union wtap_pseudo_header *pseudo_header); - -#endif /* __ATM_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ber.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ber.h deleted file mode 100644 index b3e139de..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ber.h +++ /dev/null @@ -1,28 +0,0 @@ -/* ber.h - * - * Basic Encoding Rules (BER) file reading - * - * $Id: ber.h 3992 2008-06-10 03:13:11Z dgu $ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __BER_H__ -#define __BER_H__ - -int ber_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/btsnoop.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/btsnoop.h deleted file mode 100644 index d213206e..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/btsnoop.h +++ /dev/null @@ -1,30 +0,0 @@ -/* btsnoop.h - * - * $Id: btsnoop.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __W_BTSNOOP_H__ -#define __W_BTSNOOP_H__ - -int btsnoop_open(wtap *wth, int *err, gchar **err_info); -gboolean btsnoop_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); -int btsnoop_dump_can_write_encap(int encap); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/buffer.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/buffer.h deleted file mode 100644 index 55fb523c..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/buffer.h +++ /dev/null @@ -1,58 +0,0 @@ -/* buffer.h - * - * $Id: buffer.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __W_BUFFER_H__ -#define __W_BUFFER_H__ - -#define SOME_FUNCTIONS_ARE_DEFINES - -typedef struct Buffer { - guchar *data; - unsigned int allocated; - unsigned int start; - unsigned int first_free; -} Buffer; - -void buffer_init(Buffer* buffer, unsigned int space); -void buffer_free(Buffer* buffer); -void buffer_assure_space(Buffer* buffer, unsigned int space); -void buffer_append(Buffer* buffer, guchar *from, unsigned int bytes); -void buffer_remove_start(Buffer* buffer, unsigned int bytes); - -#ifdef SOME_FUNCTIONS_ARE_DEFINES -# define buffer_clean(buffer) buffer_remove_start((buffer), buffer_length(buffer)) -# define buffer_increase_length(buffer,bytes) (buffer)->first_free += (bytes) -# define buffer_length(buffer) ((buffer)->first_free - (buffer)->start) -# define buffer_start_ptr(buffer) ((buffer)->data + (buffer)->start) -# define buffer_end_ptr(buffer) ((buffer)->data + (buffer)->first_free) -# define buffer_append_buffer(buffer,src_buffer) buffer_append((buffer), buffer_start_ptr(src_buffer), buffer_length(src_buffer)) -#else - void buffer_clean(Buffer* buffer); - void buffer_increase_length(Buffer* buffer, unsigned int bytes); - unsigned int buffer_length(Buffer* buffer); - guchar* buffer_start_ptr(Buffer* buffer); - guchar* buffer_end_ptr(Buffer* buffer); - void buffer_append_buffer(Buffer* buffer, Buffer* src_buffer); -#endif - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/catapult_dct2000.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/catapult_dct2000.h deleted file mode 100644 index 89223f5f..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/catapult_dct2000.h +++ /dev/null @@ -1,30 +0,0 @@ -/* catapult_dct2000.h -* -* $Id: catapult_dct2000.h 3992 2008-06-10 03:13:11Z dgu $ -* -* Wiretap Library -* Copyright (c) 1998 by Gilbert Ramirez -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version 2 -* of the License, or (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -int catapult_dct2000_open(wtap *wth, int *err, gchar **err_info); -gboolean catapult_dct2000_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); -int catapult_dct2000_dump_can_write_encap(int encap); - -#define DCT2000_ENCAP_UNHANDLED 0 -#define DCT2000_ENCAP_SSCOP 101 -#define DCT2000_ENCAP_MTP2 102 -#define DCT2000_ENCAP_NBAP 103 diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/commview.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/commview.h deleted file mode 100644 index a07d0d25..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/commview.h +++ /dev/null @@ -1,33 +0,0 @@ -/* commview.h - * - * $Id: commview.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#ifndef __COMMVIEW_H__ -#define __COMMVIEW_H__ - -int commview_open(wtap *wth, int *err, gchar **err_info _U_); -int commview_dump_can_write_encap(int encap); -gboolean commview_dump_open(wtap_dumper *wdh, gboolean cant_seek _U_, int *err); - -#endif /* __COMMVIEW_H__ */ - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/cosine.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/cosine.h deleted file mode 100644 index 5f5cdadc..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/cosine.h +++ /dev/null @@ -1,32 +0,0 @@ -/* cosine.h - * - * $Id: cosine.h 3992 2008-06-10 03:13:11Z dgu $ - * - * CoSine IPNOS L2 debug output parsing - * Copyright (c) 2002 by Motonori Shindo - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __W_COSINE_H__ -#define __W_COSINE_H__ - -int cosine_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/csids.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/csids.h deleted file mode 100644 index 149d07bd..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/csids.h +++ /dev/null @@ -1,29 +0,0 @@ - /* csids.h - * - * $Id: csids.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Copyright (c) 2000 by Mike Hall - * Copyright (c) Cisco Systems - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __CSIDS_H__ -#define __CSIDS_H__ - -int csids_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/dbs-etherwatch.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/dbs-etherwatch.h deleted file mode 100644 index 971ea7a0..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/dbs-etherwatch.h +++ /dev/null @@ -1,29 +0,0 @@ -/* dbs-etherwatch.h - * - * $Id: dbs-etherwatch.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __W_DBS_ETHERWATCH_H__ -#define __W_DBS_ETHERWATCH_H__ - -int dbs_etherwatch_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/erf.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/erf.h deleted file mode 100644 index 9f6b17cb..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/erf.h +++ /dev/null @@ -1,102 +0,0 @@ -/* -* -* Copyright (c) 2003 Endace Technology Ltd, Hamilton, New Zealand. -* All rights reserved. -* -* This software and documentation has been developed by Endace Technology Ltd. -* along with the DAG PCI network capture cards. For further information please -* visit http://www.endace.com/. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, -* this list of conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* -* 3. The name of Endace Technology Ltd may not be used to endorse or promote -* products derived from this software without specific prior written -* permission. -* -* THIS SOFTWARE IS PROVIDED BY ENDACE TECHNOLOGY LTD ``AS IS'' AND ANY EXPRESS -* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -* EVENT SHALL ENDACE TECHNOLOGY LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -* POSSIBILITY OF SUCH DAMAGE. -* -* $Id: erf.h 3992 2008-06-10 03:13:11Z dgu $ -*/ - -#ifndef __W_ERF_H__ -#define __W_ERF_H__ - -/* Record type defines */ -#define ERF_TYPE_LEGACY 0 -#define ERF_TYPE_HDLC_POS 1 -#define ERF_TYPE_ETH 2 -#define ERF_TYPE_ATM 3 -#define ERF_TYPE_AAL5 4 -#define ERF_TYPE_MC_HDLC 5 -#define ERF_TYPE_MC_RAW 6 -#define ERF_TYPE_MC_ATM 7 -#define ERF_TYPE_MC_RAW_CHANNEL 8 -#define ERF_TYPE_MC_AAL5 9 -#define ERF_TYPE_COLOR_HDLC_POS 10 -#define ERF_TYPE_COLOR_ETH 11 -#define ERF_TYPE_MC_AAL2 12 -#define ERF_TYPE_IP_COUNTER 13 -#define ERF_TYPE_TCP_FLOW_COUNTER 14 -#define ERF_TYPE_DSM_COLOR_HDLC_POS 15 -#define ERF_TYPE_DSM_COLOR_ETH 16 -#define ERF_TYPE_COLOR_MC_HDLC_POS 17 -#define ERF_TYPE_AAL2 18 -#define ERF_TYPE_INFINIBAND 21 - -#define ERF_TYPE_PAD 48 - -#define ERF_TYPE_MIN 1 /* sanity checking */ -#define ERF_TYPE_MAX 48 /* sanity checking */ - - /* - * The timestamp is 64bit unsigned fixed point little-endian value with - * 32 bits for second and 32 bits for fraction. - */ -typedef guint64 erf_timestamp_t; - -typedef struct erf_record { - erf_timestamp_t ts; - guint8 type; - guint8 flags; - guint16 rlen; - guint16 lctr; - guint16 wlen; -} erf_header_t; - -typedef struct erf_mc_hdr { - guint32 mc; -} erf_mc_header_t; - -typedef struct erf_eth_hdr { - guint16 eth; -} erf_eth_header_t; - -union erf_subhdr { - struct erf_mc_hdr mc_hdr; - struct erf_eth_hdr eth_hdr; -}; - -#define MIN_RECORDS_FOR_ERF_CHECK 3 -#define RECORDS_FOR_ERF_CHECK 20 -#define FCS_BITS 32 - -int erf_open(wtap *wth, int *err, gchar **err_info); - -#endif /* __W_ERF_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/etherpeek.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/etherpeek.h deleted file mode 100644 index 465ad39c..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/etherpeek.h +++ /dev/null @@ -1,29 +0,0 @@ -/* etherpeek.h - * - * $Id: etherpeek.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __W_ETHERPEEK_H__ -#define __W_ETHERPEEK_H__ - -int etherpeek_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/eyesdn.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/eyesdn.h deleted file mode 100644 index 7b28b520..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/eyesdn.h +++ /dev/null @@ -1,29 +0,0 @@ -/* eyesdn.h - * - * $Id: eyesdn.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __W_EYESDN_H__ -#define __W_EYESDN_H__ - -int eyesdn_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/file_util.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/file_util.h deleted file mode 100644 index e472e3ca..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/file_util.h +++ /dev/null @@ -1,136 +0,0 @@ -/* file_util.h - * File utility definitions - * - * $Id: file_util.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __FILE_UTIL_H__ -#define __FILE_UTIL_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#include - -#ifdef _WIN32 -#include -#endif - -#ifdef HAVE_SYS_STAT_H -#include -#endif - - -/* Win32: Since GLib2.6, we use UTF8 throughout the code, so file functions - * must tweak a given filename from UTF8 to UTF16 as we use NT Unicode (Win9x - * - now unsupported - used locale based encoding here). - */ -#if defined _WIN32 && (GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 6)) -#include - -extern int eth_stdio_open (const gchar *filename, int flags, int mode); -extern int eth_stdio_rename (const gchar *oldfilename, const gchar *newfilename); -extern int eth_stdio_mkdir (const gchar *filename, int mode); -extern int eth_stdio_stat (const gchar *filename, struct stat *buf); -extern int eth_stdio_unlink (const gchar *filename); -extern int eth_stdio_remove (const gchar *filename); -extern FILE * eth_stdio_fopen (const gchar *filename, const gchar *mode); -extern FILE * eth_stdio_freopen (const gchar *filename, const gchar *mode, FILE *stream); - -#define eth_open eth_stdio_open -#define eth_rename eth_stdio_rename -#define eth_mkdir eth_stdio_mkdir -#define eth_stat eth_stdio_stat -#define eth_unlink eth_stdio_unlink -#define eth_remove eth_stdio_remove -#define eth_fopen eth_stdio_fopen -#define eth_freopen eth_stdio_freopen - -#else /* _WIN32 && GLIB_MAJOR_VERSION */ - -/* GLib 2.4 or below, using "old school" functions */ -#ifdef _WIN32 -#define eth_open _open -#define eth_stat _stat -#define eth_unlink _unlink -#define eth_mkdir(dir,mode) _mkdir(dir) -#else -#define eth_open open -#define eth_stat stat -#define eth_unlink unlink -#define eth_mkdir(dir,mode) mkdir(dir,mode) -#endif /* _WIN32 */ - -#define eth_rename rename -#define eth_remove remove -#define eth_fopen fopen -#define eth_freopen freopen - -#endif /* _WIN32 && GLIB_MAJOR_VERSION */ - - -/* some common file function differences between UNIX and WIN32 */ -#ifdef _WIN32 -/* the Win32 API prepends underscores for whatever reasons */ -#define eth_read _read -#define eth_write _write -#define eth_close _close -#define eth_dup _dup -#define eth_lseek _lseek -#else -#define eth_read read -#define eth_write write -#define eth_close close -#define eth_dup dup -#define eth_lseek lseek -#define O_BINARY 0 /* Win32 needs the O_BINARY flag for open() */ -#endif /* _WIN32 */ - -/* directory handling */ -#if GLIB_MAJOR_VERSION >= 2 -#define ETH_DIR GDir -#define ETH_DIRENT const char -#define eth_dir_open g_dir_open -#define eth_dir_read_name g_dir_read_name -#define eth_dir_get_name(dirent) dirent -#define eth_dir_rewind g_dir_rewind -#define eth_dir_close g_dir_close -#else -#define ETH_DIR DIR -#define ETH_DIRENT struct dirent -#define eth_dir_open(name,flags,error) opendir(name) -#define eth_dir_read_name readdir -#define eth_dir_get_name(dirent) (gchar *)(dirent)->d_name -#define eth_dir_rewind rewinddir -#define eth_dir_close closedir -#endif /* GLIB_MAJOR_VERSION */ - -/* XXX - remove include "dirent.h" */ -/* XXX - remove include "direct.h" */ -/* XXX - remove include "sys/stat.h" */ -/* XXX - update docs (e.g. README.developer) */ - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __FILE_UTIL_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/file_wrappers.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/file_wrappers.h deleted file mode 100644 index 193af09f..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/file_wrappers.h +++ /dev/null @@ -1,57 +0,0 @@ -/* file_wrappers.h - * - * $Id: file_wrappers.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __FILE_H__ -#define __FILE_H__ - -extern gint64 file_seek(void *stream, gint64 offset, int whence, int *err); -extern gint64 file_tell(void *stream); -extern int file_error(void *fh); - -#ifdef HAVE_LIBZ - -extern FILE_T file_open(const char *path, const char *mode); -#define filed_open gzdopen -/* XX: gzread and gzwrite return number of *bytes* (not number of elements) */ -#define file_read(buf, bsize, count, file) gzread((file),(buf),((count)*(bsize))) -#define file_write(buf, bsize, count, file) gzwrite((file),(buf),((count)*(bsize))) -#define file_close gzclose -#define file_getc gzgetc -#define file_gets(buf, len, file) gzgets((file), (buf), (len)) -#define file_eof gzeof - -#else /* No zLib */ - -#define file_open(path, mode) eth_fopen(path, mode) -#define filed_open fdopen -/* XX: file_read and file_write defined to return number of *bytes* to be consistent with gzread & gzwrite */ -#define file_read(buf, bsize, count, file) ((bsize) * fread((buf), (bsize), (count), (file))) -#define file_write(buf, bsize, count, file) ((bsize) * fwrite((buf), (bsize), (count), (file))) -#define file_close fclose -#define file_getc fgetc -#define file_gets fgets -#define file_eof feof - -#endif /* HAVE_LIBZ */ - -#endif /* __FILE_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/hcidump.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/hcidump.h deleted file mode 100644 index 08a0a61c..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/hcidump.h +++ /dev/null @@ -1,28 +0,0 @@ -/* hcidump.h - * - * $Id: hcidump.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Copyright (c) 2003 by Marcel Holtmann - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __HCIDUMP_H__ -#define __HCIDUMP_H__ - -int hcidump_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/i4b_trace.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/i4b_trace.h deleted file mode 100644 index 359f09ea..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/i4b_trace.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 1997, 1999 Hellmuth Michaelis. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - *--------------------------------------------------------------------------- - * - * i4b_trace.h - header file for trace data read device - * ---------------------------------------------------- - * - * $Id: i4b_trace.h 3992 2008-06-10 03:13:11Z dgu $ - * - * last edit-date: [Sun Feb 14 10:39:26 1999] - * - *---------------------------------------------------------------------------*/ - -#ifndef _I4B_TRACE_H_ -#define _I4B_TRACE_H_ - -/*---------------------------------------------------------------------------* - * structure of the header at the beginning of every trace mbuf - *---------------------------------------------------------------------------*/ -typedef struct { - guint32 length; /* length of the following mbuf */ - gint32 unit; /* controller unit number */ - gint32 type; /* type of channel */ -#define TRC_CH_I 0 /* Layer 1 INFO's */ -#define TRC_CH_D 1 /* D channel */ -#define TRC_CH_B1 2 /* B1 channel */ -#define TRC_CH_B2 3 /* B2 channel */ - gint32 dir; /* direction */ -#define FROM_TE 0 /* user -> network */ -#define FROM_NT 1 /* network -> user */ - gint32 trunc; /* # of truncated bytes (frame > MCLBYTES) */ - guint32 count; /* frame count for this unit/type */ - guint32 ts_sec; /* timestamp seconds */ - guint32 ts_usec; /* timestamp microseconds */ -} i4b_trace_hdr_t; - -#define INFO0 0 /* layer 1 */ -#define INFO1_8 1 -#define INFO1_10 2 -#define INFO2 3 -#define INFO3 4 -#define INFO4_8 5 -#define INFO4_10 6 - -/*---------------------------------------------------------------------------* - * ioctl via /dev/i4btrc device(s): - * get/set current trace flag settings - *---------------------------------------------------------------------------*/ - -#define I4B_TRC_GET _IOR('T', 0, int) /* get trace settings */ -#define I4B_TRC_SET _IOW('T', 1, int) /* set trace settings */ - -#define TRACE_OFF 0x00 /* tracing off */ -#define TRACE_I 0x01 /* trace L1 INFO's on */ -#define TRACE_D_TX 0x02 /* trace D channel on */ -#define TRACE_D_RX 0x04 /* trace D channel on */ -#define TRACE_B_TX 0x08 /* trace B channel on */ -#define TRACE_B_RX 0x10 /* trace B channel on */ - -typedef struct { - gint32 rxunit; /* unit # for rx frames */ - gint32 rxflags; /* d and/or b channel */ - gint32 txunit; /* unit # for tx frames */ - gint32 txflags; /* d and/or b channel */ -} i4b_trace_setupa_t; - -#define I4B_TRC_SETA _IOW('T', 2, i4b_trace_setupa_t) /* set analyze mode */ -#define I4B_TRC_RESETA _IOW('T', 3, int) /* reset analyze mode */ - -#endif /* _I4B_TRACE_H_ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/i4btrace.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/i4btrace.h deleted file mode 100644 index 716e7c47..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/i4btrace.h +++ /dev/null @@ -1,29 +0,0 @@ -/* i4btrace.h - * - * $Id: i4btrace.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1999 by Bert Driehuis - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __I4BTRACE_H__ -#define __I4BTRACE_H__ - -int i4btrace_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/iptrace.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/iptrace.h deleted file mode 100644 index 57ac0d59..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/iptrace.h +++ /dev/null @@ -1,29 +0,0 @@ -/* iptrace.h - * - * $Id: iptrace.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __IPTRACE_H__ -#define __IPTRACE_H__ - -int iptrace_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/iseries.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/iseries.h deleted file mode 100644 index ffb43e31..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/iseries.h +++ /dev/null @@ -1,28 +0,0 @@ -/* iseries.h - * - * $Id: iseries.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 2005 by Martin Warnes - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __W_ISERIES_H__ -#define __W_ISERIES_H__ - -int iseries_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/k12.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/k12.h deleted file mode 100644 index c2647322..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/k12.h +++ /dev/null @@ -1,28 +0,0 @@ -/* k12.c -* -* $Id: k12.h 3992 2008-06-10 03:13:11Z dgu $ -* -* Wiretap Library -* Copyright (c) 1998 by Gilbert Ramirez -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version 2 -* of the License, or (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -int k12_open(wtap *wth, int *err, gchar **err_info); -int k12_dump_can_write_encap(int encap); -gboolean k12_dump_open(wtap_dumper *wdh, gboolean cant_seek _U_, int *err); -int k12text_open(wtap *wth, int *err, gchar **err_info _U_); -int k12text_dump_can_write_encap(int encap); -gboolean k12text_dump_open(wtap_dumper *wdh, gboolean cant_seek _U_, int *err); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/k12text_lex.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/k12text_lex.h deleted file mode 100644 index ccd97c5d..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/k12text_lex.h +++ /dev/null @@ -1,6 +0,0 @@ -/* This is generated by runlex.sh. Do not edit it. */ -#define yylex K12Text_lex -#ifndef YY_DECL -#define YY_DECL int yylex(void) -#endif -YY_DECL; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/lanalyzer.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/lanalyzer.h deleted file mode 100644 index 758a9833..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/lanalyzer.h +++ /dev/null @@ -1,176 +0,0 @@ -/* lanalyzer.h - * - * $Id: lanalyzer.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __LANALYZER_H__ -#define __LANALYZER_H__ - -/* Record type codes: */ - -#define RT_HeaderRegular 0x1001 -#define RT_HeaderCyclic 0x1007 -#define RT_RxChannelName 0x1006 -#define RT_TxChannelName 0x100b -#define RT_FilterName 0x1032 -#define RT_RxTemplateName 0x1035 -#define RT_TxTemplateName 0x1036 -#define RT_DisplayOptions 0x100a -#define RT_Summary 0x1002 -#define RT_SubfileSummary 0x1003 -#define RT_CyclicInformation 0x1009 -#define RT_Index 0x1004 -#define RT_PacketData 0x1005 - -#define LA_ProFileLimit (1024 * 1024 * 32) - -typedef guint8 Eadr[6]; -typedef guint16 TimeStamp[3]; /* 0.5 microseconds since start of trace */ - -/* - * These records have only 2-byte alignment for 4-byte quantities, - * so the structures aren't necessarily valid; they're kept as comments - * for reference purposes. - */ - -/* - * typedef struct { - * guint8 day; - * guint8 mon; - * gint16 year; - * } Date; - */ - -/* - * typedef struct { - * guint8 second; - * guint8 minute; - * guint8 hour; - * guint8 day; - * gint16 reserved; - * } Time; - */ - -/* - * typedef struct { - * guint16 rx_channels; - * guint16 rx_errors; - * gint16 rx_frm_len; - * gint16 rx_frm_sln; - * TimeStamp rx_time; - * guint32 pktno; - * gint16 prvlen; - * gint16 offset; - * gint16 tx_errs; - * gint16 rx_filters; - * gint8 unused[2]; - * gint16 hwcolls; - * gint16 hwcollschans; - * Packetdata ....; - * } LA_PacketRecord; - */ - -#define LA_PacketRecordSize 32 - -/* - * typedef struct { - * Date datcre; - * Date datclo; - * Time timeopn; - * Time timeclo; - * Eadr statadr; - * gint16 mxseqno; - * gint16 slcoff; - * gint16 mxslc; - * gint32 totpktt; - * gint32 statrg; - * gint32 stptrg; - * gint32 mxpkta[36]; - * gint16 board_type; - * gint16 board_version; - * gint8 reserved[18]; - * } Summary; - */ - -#define SummarySize (18+22+(4*36)+6+6+6+4+4) - - -/* - * typedef struct { - * gint16 rid; - * gint16 rlen; - * Summary s; - * } LA_SummaryRecord; - */ - -#define LA_SummaryRecordSize (SummarySize + 4) - - -/* - * typedef struct { - * gint16 rid; - * gint16 rlen; - * gint16 seqno; - * gint32 totpktf; - * } LA_SubfileSummaryRecord; - */ - -#define LA_SubfileSummaryRecordSize 10 - - -#define LA_IndexSize 500 - -/* - * typedef struct { - * gint16 rid; - * gint16 rlen; - * gint16 idxsp; = LA_IndexSize - * gint16 idxct; - * gint8 idxgranu; - * gint8 idxvd; - * gint32 trcidx[LA_IndexSize + 2]; +2 undocumented but used by La 2.2 - * } LA_IndexRecord; - */ - -#define LA_IndexRecordSize (10 + 4 * (LA_IndexSize + 2)) - -/* - * typedef struct { - * gint16 rid; - * gint16 rlen; - * } LA_RecordHeader; - */ - -#define LA_RecordHeaderSize 4 - -typedef struct { - gboolean init; - struct timeval start; - guint32 pkts; - int encap; - int lastlen; - } LA_TmpInfo; - -int lanalyzer_open(wtap *wth, int *err, gchar **err_info); -gboolean lanalyzer_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); -int lanalyzer_dump_can_write_encap(int encap); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/libpcap.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/libpcap.h deleted file mode 100644 index 3d4038f1..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/libpcap.h +++ /dev/null @@ -1,106 +0,0 @@ -/* libpcap.h - * - * $Id: libpcap.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __W_LIBPCAP_H__ -#define __W_LIBPCAP_H__ - -/* Magic numbers in "libpcap" files. - - "libpcap" file records are written in the byte order of the host that - writes them, and the reader is expected to fix this up. - - PCAP_MAGIC is the magic number, in host byte order; PCAP_SWAPPED_MAGIC - is a byte-swapped version of that. - - PCAP_MODIFIED_MAGIC is for Alexey Kuznetsov's modified "libpcap" - format, as generated on Linux systems that have a "libpcap" with - his patches, at - - http://ftp.sunet.se/pub/os/Linux/ip-routing/lbl-tools/ - - applied; PCAP_SWAPPED_MODIFIED_MAGIC is the byte-swapped version. - - PCAP_NSEC_MAGIC is for Ulf Lamping's modified "libpcap" format, - which uses the same common file format as PCAP_MAGIC, but the - timestamps are saved in nanosecond resolution instead of microseconds. - PCAP_SWAPPED_NSEC_MAGIC is a byte-swapped version of that. */ -#define PCAP_MAGIC 0xa1b2c3d4 -#define PCAP_SWAPPED_MAGIC 0xd4c3b2a1 -#define PCAP_MODIFIED_MAGIC 0xa1b2cd34 -#define PCAP_SWAPPED_MODIFIED_MAGIC 0x34cdb2a1 -#define PCAP_NSEC_MAGIC 0xa1b23c4d -#define PCAP_SWAPPED_NSEC_MAGIC 0x4d3cb2a1 - -/* "libpcap" file header (minus magic number). */ -struct pcap_hdr { - guint16 version_major; /* major version number */ - guint16 version_minor; /* minor version number */ - gint32 thiszone; /* GMT to local correction */ - guint32 sigfigs; /* accuracy of timestamps */ - guint32 snaplen; /* max length of captured packets, in octets */ - guint32 network; /* data link type */ -}; - -/* "libpcap" record header. */ -struct pcaprec_hdr { - guint32 ts_sec; /* timestamp seconds */ - guint32 ts_usec; /* timestamp microseconds (nsecs for PCAP_NSEC_MAGIC) */ - guint32 incl_len; /* number of octets of packet saved in file */ - guint32 orig_len; /* actual length of packet */ -}; - -/* "libpcap" record header for Alexey's patched version. */ -struct pcaprec_modified_hdr { - struct pcaprec_hdr hdr; /* the regular header */ - guint32 ifindex; /* index, in *capturing* machine's list of - interfaces, of the interface on which this - packet came in. */ - guint16 protocol; /* Ethernet packet type */ - guint8 pkt_type; /* broadcast/multicast/etc. indication */ - guint8 pad; /* pad to a 4-byte boundary */ -}; - -/* "libpcap" record header for Alexey's patched version in its ss990915 - incarnation; this version shows up in SuSE Linux 6.3. */ -struct pcaprec_ss990915_hdr { - struct pcaprec_hdr hdr; /* the regular header */ - guint32 ifindex; /* index, in *capturing* machine's list of - interfaces, of the interface on which this - packet came in. */ - guint16 protocol; /* Ethernet packet type */ - guint8 pkt_type; /* broadcast/multicast/etc. indication */ - guint8 cpu1, cpu2; /* SMP debugging gunk? */ - guint8 pad[3]; /* pad to a 4-byte boundary */ -}; - -/* "libpcap" record header for version used on some Nokia boxes (firewalls?) */ -struct pcaprec_nokia_hdr { - struct pcaprec_hdr hdr; /* the regular header */ - guint8 stuff[4]; /* mysterious stuff */ -}; - -int libpcap_open(wtap *wth, int *err, gchar **err_info); -gboolean libpcap_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); -int libpcap_dump_can_write_encap(int encap); -int wtap_pcap_encap_to_wtap_encap(int encap); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/mpeg-audio.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/mpeg-audio.h deleted file mode 100644 index 3ead2ff5..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/mpeg-audio.h +++ /dev/null @@ -1,98 +0,0 @@ -/* mpeg-audio.h - * - * MPEG Audio header dissection - * Written by Shaun Jackman - * Copyright 2007 Shaun Jackman - * - * $Id: mpeg-audio.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef MPA_H -#define MPA_H 1 - -struct mpa { - unsigned emphasis :2; - unsigned original :1; - unsigned copyright :1; - unsigned modeext :2; - unsigned mode :2; - unsigned private :1; - unsigned padding :1; - unsigned frequency :2; - unsigned bitrate :4; - unsigned protection :1; - unsigned layer :2; - unsigned version :2; - unsigned sync :11; -}; - -#define MPA_UNMARSHAL_SYNC(n) ((n) >> 21 & 0x7ff) -#define MPA_UNMARSHAL_VERSION(n) ((n) >> 19 & 0x3) -#define MPA_UNMARSHAL_LAYER(n) ((n) >> 17 & 0x3) -#define MPA_UNMARSHAL_PROTECTION(n) ((n) >> 16 & 0x1) -#define MPA_UNMARSHAL_BITRATE(n) ((n) >> 12 & 0xf) -#define MPA_UNMARSHAL_FREQUENCY(n) ((n) >> 10 & 0x3) -#define MPA_UNMARSHAL_PADDING(n) ((n) >> 9 & 0x1) -#define MPA_UNMARSHAL_PRIVATE(n) ((n) >> 8 & 0x1) -#define MPA_UNMARSHAL_MODE(n) ((n) >> 6 & 0x3) -#define MPA_UNMARSHAL_MODEEXT(n) ((n) >> 4 & 0x3) -#define MPA_UNMARSHAL_COPYRIGHT(n) ((n) >> 3 & 0x1) -#define MPA_UNMARSHAL_ORIGINAL(n) ((n) >> 2 & 0x1) -#define MPA_UNMARSHAL_EMPHASIS(n) ((n) >> 0 & 0x3) - -#define MPA_UNMARSHAL(mpa, n) do { \ - (mpa)->sync = MPA_UNMARSHAL_SYNC(n); \ - (mpa)->version = MPA_UNMARSHAL_VERSION(n); \ - (mpa)->layer = MPA_UNMARSHAL_LAYER(n); \ - (mpa)->protection = MPA_UNMARSHAL_PROTECTION(n); \ - (mpa)->bitrate = MPA_UNMARSHAL_BITRATE(n); \ - (mpa)->frequency = MPA_UNMARSHAL_FREQUENCY(n); \ - (mpa)->padding = MPA_UNMARSHAL_PADDING(n); \ - (mpa)->private = MPA_UNMARSHAL_PRIVATE(n); \ - (mpa)->mode = MPA_UNMARSHAL_MODE(n); \ - (mpa)->modeext = MPA_UNMARSHAL_MODEEXT(n); \ - (mpa)->copyright = MPA_UNMARSHAL_COPYRIGHT(n); \ - (mpa)->original = MPA_UNMARSHAL_ORIGINAL(n); \ - (mpa)->emphasis = MPA_UNMARSHAL_EMPHASIS(n); \ - } while (0) - -int mpa_version(const struct mpa *); -int mpa_layer(const struct mpa *); -unsigned mpa_samples(const struct mpa *); -unsigned mpa_bitrate(const struct mpa *); -unsigned mpa_frequency(const struct mpa *); -unsigned mpa_padding(const struct mpa *); - -#define MPA_DATA_BYTES(mpa) (mpa_bitrate(mpa) * mpa_samples(mpa) \ - / mpa_frequency(mpa) / 8) -#define MPA_BYTES(mpa) (MPA_DATA_BYTES(mpa) + mpa_padding(mpa)) -#define MPA_DURATION_NS(mpa) \ - (1000000000 / mpa_frequency(mpa) * mpa_samples(mpa)) - -enum { MPA_SYNC = 0x7ff }; - -#define MPA_SYNC_VALID(mpa) ((mpa)->sync == MPA_SYNC) -#define MPA_VERSION_VALID(mpa) (mpa_version(mpa) >= 0) -#define MPA_LAYER_VALID(mpa) (mpa_layer(mpa) >= 0) -#define MPA_BITRATE_VALID(mpa) (mpa_bitrate(mpa) > 0) -#define MPA_FREQUENCY_VALID(mpa) (mpa_frequency(mpa) > 0) -#define MPA_VALID(mpa) (MPA_SYNC_VALID(mpa) \ - && MPA_VERSION_VALID(mpa) && MPA_LAYER_VALID(mpa) \ - && MPA_BITRATE_VALID(mpa) && MPA_FREQUENCY_VALID(mpa)) - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/mpeg.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/mpeg.h deleted file mode 100644 index c24fe87d..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/mpeg.h +++ /dev/null @@ -1,32 +0,0 @@ -/* mpeg.h - * - * MPEG file format decoder for the Wiretap library. - * Written by Shaun Jackman - * Copyright 2007 Shaun Jackman - * - * $Id: mpeg.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __W_MPEG_H__ -#define __W_MPEG_H__ - -#include "wtap-int.h" - -int mpeg_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netmon.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netmon.h deleted file mode 100644 index ab0904cc..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netmon.h +++ /dev/null @@ -1,30 +0,0 @@ -/* netmon.h - * - * $Id: netmon.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __NETMON_H__ -#define __NETMON_H__ - -int netmon_open(wtap *wth, int *err, gchar **err_info); -gboolean netmon_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); -int netmon_dump_can_write_encap(int encap); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netscreen.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netscreen.h deleted file mode 100644 index dce7c361..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netscreen.h +++ /dev/null @@ -1,53 +0,0 @@ -/* netscreen.h - * - * $Id: netscreen.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Juniper NetScreen snoop output parser - * Created by re-using a lot of code from cosine.c - * Copyright (c) 2007 by Sake Blok - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __W_NETSCREEN_H__ -#define __W_NETSCREEN_H__ - -/* Magic text to check for NetScreen snoop output */ -#define NETSCREEN_HDR_MAGIC_STR1 "(i) len=" -#define NETSCREEN_HDR_MAGIC_STR2 "(o) len=" - -/* Magic text for start of packet */ -#define NETSCREEN_REC_MAGIC_STR1 NETSCREEN_HDR_MAGIC_STR1 -#define NETSCREEN_REC_MAGIC_STR2 NETSCREEN_HDR_MAGIC_STR2 - -#define NETSCREEN_LINE_LENGTH 128 -#define NETSCREEN_HEADER_LINES_TO_CHECK 32 -#define NETSCREEN_MAX_INFOLINES 8 -#define NETSCREEN_SPACES_ON_INFO_LINE 14 -#define NETSCREEN_MAX_INT_NAME_LENGTH 16 - -#define NETSCREEN_INGRESS FALSE -#define NETSCREEN_EGRESS TRUE - - -#define NETSCREEN_MAX_PACKET_LEN 65536 - -int netscreen_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/nettl.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/nettl.h deleted file mode 100644 index 1ac9f756..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/nettl.h +++ /dev/null @@ -1,124 +0,0 @@ -/* nettl.h - * - * $Id: nettl.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * Enhancements by Mark C. Brown - * Copyright (C) 2003, 2005 Hewlett-Packard Development Company, L.P. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef __NETTL_H__ -#define __NETTL_H__ - -/* nettl subsystems are defined in /etc/nettlgen.conf */ - -#define NETTL_SUBSYS_NS_LS_LOGGING 0 -#define NETTL_SUBSYS_NS_LS_NFT 1 -#define NETTL_SUBSYS_NS_LS_LOOPBACK 2 -#define NETTL_SUBSYS_NS_LS_NI 3 -#define NETTL_SUBSYS_NS_LS_IPC 4 -#define NETTL_SUBSYS_NS_LS_SOCKREGD 5 -#define NETTL_SUBSYS_NS_LS_TCP 6 -#define NETTL_SUBSYS_NS_LS_PXP 7 -#define NETTL_SUBSYS_NS_LS_UDP 8 -#define NETTL_SUBSYS_NS_LS_IP 9 -#define NETTL_SUBSYS_NS_LS_PROBE 10 -#define NETTL_SUBSYS_NS_LS_DRIVER 11 -#define NETTL_SUBSYS_NS_LS_RLBD 12 -#define NETTL_SUBSYS_NS_LS_BUFS 13 -#define NETTL_SUBSYS_NS_LS_CASE21 14 -#define NETTL_SUBSYS_NS_LS_ROUTER21 15 -#define NETTL_SUBSYS_NS_LS_NFS 16 -#define NETTL_SUBSYS_NS_LS_NETISR 17 -#define NETTL_SUBSYS_NS_LS_NSE 18 -#define NETTL_SUBSYS_NS_LS_STRLOG 19 -#define NETTL_SUBSYS_NS_LS_TIRDWR 21 -#define NETTL_SUBSYS_NS_LS_TIMOD 22 -#define NETTL_SUBSYS_NS_LS_ICMP 23 -#define NETTL_SUBSYS_FILTER 26 -#define NETTL_SUBSYS_NAME 27 -#define NETTL_SUBSYS_IGMP 29 -#define NETTL_SUBSYS_SX25L2 34 -#define NETTL_SUBSYS_SX25L3 35 -#define NETTL_SUBSYS_FTAM_INIT 64 -#define NETTL_SUBSYS_FTAM_RESP 65 -#define NETTL_SUBSYS_FTAM_VFS 70 -#define NETTL_SUBSYS_FTAM_USER 72 -#define NETTL_SUBSYS_OTS 90 -#define NETTL_SUBSYS_NETWORK 91 -#define NETTL_SUBSYS_TRANSPORT 92 -#define NETTL_SUBSYS_SESSION 93 -#define NETTL_SUBSYS_ACSE_PRES 94 -#define NETTL_SUBSYS_SHM 116 -#define NETTL_SUBSYS_ACSE_US 119 -#define NETTL_SUBSYS_HPS 121 -#define NETTL_SUBSYS_CM 122 -#define NETTL_SUBSYS_ULA_UTILS 123 -#define NETTL_SUBSYS_EM 124 -#define NETTL_SUBSYS_HP_APAPORT 189 -#define NETTL_SUBSYS_HP_APALACP 190 -#define NETTL_SUBSYS_NS_LS_IPV6 244 -#define NETTL_SUBSYS_NS_LS_ICMPV6 245 -#define NETTL_SUBSYS_NS_LS_TELNET 267 -#define NETTL_SUBSYS_NS_LS_SCTP 268 - -/* Ethernet cards */ -#define NETTL_SUBSYS_100VG 37 -#define NETTL_SUBSYS_LAN100 164 -#define NETTL_SUBSYS_EISA100BT 172 -#define NETTL_SUBSYS_BASE100 173 -#define NETTL_SUBSYS_GSC100BT 178 -#define NETTL_SUBSYS_PCI100BT 179 -#define NETTL_SUBSYS_SPP100BT 180 -#define NETTL_SUBSYS_GELAN 185 -#define NETTL_SUBSYS_BTLAN 210 -#define NETTL_SUBSYS_INTL100 233 -#define NETTL_SUBSYS_IGELAN 252 -#define NETTL_SUBSYS_IETHER 253 -#define NETTL_SUBSYS_IXGBE 265 - -/* FDDI cards */ -#define NETTL_SUBSYS_HPPB_FDDI 95 -#define NETTL_SUBSYS_EISA_FDDI 174 -#define NETTL_SUBSYS_PCI_FDDI 176 -#define NETTL_SUBSYS_HSC_FDDI 177 - -/* Token Ring cards */ -#define NETTL_SUBSYS_TOKEN 31 -#define NETTL_SUBSYS_PCI_TR 187 - -/* from /usr/include/sys/subsys_id.h */ - -#define NETTL_HDR_HDRIN 0x80000000 -#define NETTL_HDR_HDROUT 0x40000000 -#define NETTL_HDR_PDUIN 0x20000000 -#define NETTL_HDR_PDUOUT 0x10000000 -#define NETTL_HDR_PROCEDURE_TRACE 0x08000000 -#define NETTL_HDR_STATE_TRACE 0x04000000 -#define NETTL_HDR_ERROR_TRACE 0x02000000 -#define NETTL_HDR_LOG_TRACE 0x01000000 -#define NETTL_HDR_LOOPBACK 0x00800000 -#define NETTL_HDR_PTOP 0x00400000 -#define NETTL_HDR_SUBSYSTEM_BITS_MASK 0x000fffff - -int nettl_open(wtap *wth, int *err, gchar **err_info); -gboolean nettl_dump_open(wtap_dumper *wdh, gboolean cant_seek _U_, int *err); -int nettl_dump_can_write_encap(int encap); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/network_instruments.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/network_instruments.h deleted file mode 100644 index ab9708b7..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/network_instruments.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * $Id: network_instruments.h 3992 2008-06-10 03:13:11Z dgu $ - */ - -/*************************************************************************** - NetworkInstruments.h - description - ------------------- - begin : Wed Oct 29 2003 - copyright : (C) 2003 by root - email : scotte[AT}netinst.com - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#ifndef __NETWORK_INSTRUMENTS_H__ -#define __NETWORK_INSTRUMENTS_H__ - -int network_instruments_open(wtap *wth, int *err, gchar **err_info); -int network_instruments_dump_can_write_encap(int encap); -gboolean network_instruments_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); - -typedef struct capture_file_header -{ - char observer_version[32]; - guint16 offset_to_first_packet; - char probe_instance; - guint8 number_of_information_elements; /* number of TLVs in the header */ -} capture_file_header; - -typedef struct tlv_header -{ - guint16 type; - guint16 length; /* includes the length of the TLV header */ -} tlv_header; - -/* - * TLV type values. - */ -#define INFORMATION_TYPE_ALIAS_LIST 0x01 -#define INFORMATION_TYPE_COMMENT 0x02 /* ASCII text */ - -typedef struct packet_entry_header -{ - guint32 packet_magic; - guint32 network_speed; - guint16 captured_size; - guint16 network_size; - guint16 offset_to_frame; - guint16 offset_to_next_packet; - guint8 network_type; - guint8 flags; - guint8 number_of_information_elements; /* number of TLVs in the header */ - guint8 packet_type; - guint16 errors; - guint16 reserved; - guint64 packet_number; - guint64 original_packet_number; - guint64 nano_seconds_since_2000; -} packet_entry_header; - -/* - * Network type values. - */ -#define OBSERVER_UNDEFINED 0xFF -#define OBSERVER_ETHERNET 0x00 -#define OBSERVER_TOKENRING 0x01 -#define OBSERVER_FDDI 0x02 - -/* - * Packet type values. - */ -#define PACKET_TYPE_DATA_PACKET 0 -#define PACKET_TYPE_EXPERT_INFORMATION_PACKET 1 - -/* - * The Observer document indicates that the types of expert information - * packets are: - * - * Network Load (markers used by Expert Time Interval and What If - * analysis modes) - * - * Start/Stop Packet Capture marker frames (with time stamps when - * captures start and stop) - * - * Wireless Channel Change (markers showing what channel was being - * currently listened to) - * - * That information appears to be contained in TLVs. - */ - -/* - * TLV type values. - */ -#define INFORMATION_TYPE_NETWORK_LOAD 0x0100 -#define INFORMATION_TYPE_CAPTURE_START_STOP 0x0104 - -/* - * Might some of these be broadcast and multicast packet counts? - */ -typedef struct tlv_network_load -{ - guint32 utilization; /* network utilization, in .1% units */ - guint32 unknown1; - guint32 unknown2; - guint32 packets_per_second; - guint32 unknown3; - guint32 bytes_per_second; - guint32 unknown4; -} tlv_network_load; - -typedef struct tlv_capture_start_stop -{ - guint32 start_stop; -} tlv_capture_start_stop; - -#define START_STOP_TYPE_STOP 0 -#define START_STOP_TYPE_START 1 - -#endif - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netxray.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netxray.h deleted file mode 100644 index 0c38bb34..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netxray.h +++ /dev/null @@ -1,32 +0,0 @@ -/* netxray.h - * - * $Id: netxray.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __NETXRAY_H__ -#define __NETXRAY_H__ - -int netxray_open(wtap *wth, int *err, gchar **err_info); -int netxray_dump_can_write_encap_1_1(int encap); -gboolean netxray_dump_open_1_1(wtap_dumper *wdh, gboolean cant_seek, int *err); -int netxray_dump_can_write_encap_2_0(int encap); -gboolean netxray_dump_open_2_0(wtap_dumper *wdh, gboolean cant_seek, int *err); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ngsniffer.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ngsniffer.h deleted file mode 100644 index a4a25f6e..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ngsniffer.h +++ /dev/null @@ -1,30 +0,0 @@ -/* ngsniffer.h - * - * $Id: ngsniffer.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __NGSNIFFER_H__ -#define __NGSNIFFER_H__ - -int ngsniffer_open(wtap *wth, int *err, gchar **err_info); -gboolean ngsniffer_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); -int ngsniffer_dump_can_write_encap(int encap); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/pcapng.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/pcapng.h deleted file mode 100644 index 65d7de3d..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/pcapng.h +++ /dev/null @@ -1,30 +0,0 @@ -/* pcapng.h - * - * $Id: pcapng.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __W_PCAPNG_H__ -#define __W_PCAPNG_H__ - -int pcapng_open(wtap *wth, int *err, gchar **err_info); -gboolean pcapng_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); -int pcapng_dump_can_write_encap(int encap); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/pppdump.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/pppdump.h deleted file mode 100644 index c5b8aad0..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/pppdump.h +++ /dev/null @@ -1,28 +0,0 @@ -/* pppdump.h - * - * $Id: pppdump.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Copyright (c) 2000 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __PPPDUMP_H__ -#define __PPPDUMP_H__ - -int pppdump_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/radcom.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/radcom.h deleted file mode 100644 index 0e6724c7..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/radcom.h +++ /dev/null @@ -1,29 +0,0 @@ -/* radcom.h - * - * $Id: radcom.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __RADCOM_H__ -#define __RADCOM_H__ - -int radcom_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/snoop.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/snoop.h deleted file mode 100644 index a1a68f87..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/snoop.h +++ /dev/null @@ -1,30 +0,0 @@ -/* snoop.h - * - * $Id: snoop.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __W_SNOOP_H__ -#define __W_SNOOP_H__ - -int snoop_open(wtap *wth, int *err, gchar **err_info); -gboolean snoop_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); -int snoop_dump_can_write_encap(int encap); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/toshiba.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/toshiba.h deleted file mode 100644 index eea69129..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/toshiba.h +++ /dev/null @@ -1,28 +0,0 @@ -/* toshiba.h - * - * $Id: toshiba.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __W_TOSHIBA_H__ -#define __W_TOSHIBA_H__ - -int toshiba_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/visual.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/visual.h deleted file mode 100644 index 0c094a9e..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/visual.h +++ /dev/null @@ -1,35 +0,0 @@ -/* visual.h - * - * File read write routines for Visual Networks .cap files. - * Copyright 2001, Tom Nisbet tnisbet@visualnetworks.com - * - * Based on the code that handles netmon files. - * - * $Id: visual.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __VISUAL_H__ -#define __VISUAL_H__ - -int visual_open(wtap *wth, int *err, gchar **err_info); -gboolean visual_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); -int visual_dump_can_write_encap(int encap); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/vms.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/vms.h deleted file mode 100644 index 34083b07..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/vms.h +++ /dev/null @@ -1,29 +0,0 @@ -/* vms.h - * - * $Id: vms.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 2001 by Marc Milgram - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __W_VMS_H__ -#define __W_VMS_H__ - -int vms_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/wtap-int.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/wtap-int.h deleted file mode 100644 index 3f48d12c..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/wtap-int.h +++ /dev/null @@ -1,482 +0,0 @@ -/* wtap-int.h - * - * $Id: wtap-int.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __WTAP_INT_H__ -#define __WTAP_INT_H__ - -#ifdef HAVE_SYS_TIME_H -#include -#endif - -#include -#include -#include - -#ifdef HAVE_LIBZ -#ifdef HAVE_WINSOCK2_H -#include -#endif -#include -#define FILE_T gzFile -#else /* No zLib */ -#define FILE_T FILE * -#endif /* HAVE_LIBZ */ - -#include "wtap.h" - -/* Information for a compressed Sniffer data stream. */ -typedef struct { - unsigned char *buf; /* buffer into which we uncompress data */ - size_t nbytes; /* number of bytes of data in that buffer */ - int nextout; /* offset in that buffer of stream's current position */ - gint64 comp_offset; /* current offset in compressed data stream */ - gint64 uncomp_offset; /* current offset in uncompressed data stream */ -} ngsniffer_comp_stream_t; - -typedef struct { - char *sdate; /* Packet start date */ - gboolean tcp_formatted; /* TCP/IP data formated Y/N */ - int format; /* Trace format type */ -} iseries_t; - -typedef struct { - guint maj_vers; - guint min_vers; - guint32 timeunit; - time_t start; - guint network; /* network type */ - ngsniffer_comp_stream_t seq; /* sequential access */ - ngsniffer_comp_stream_t rand; /* random access */ - GList *first_blob; /* list element for first blob */ - GList *last_blob; /* list element for last blob */ - GList *current_blob; /* list element for current blob */ -} ngsniffer_t; - -typedef struct { - gboolean byte_swapped; -} i4btrace_t; - -typedef struct { - gboolean is_hpux_11; -} nettl_t; - -typedef struct { - time_t start; -} lanalyzer_t; - -typedef enum { - NOT_SWAPPED, - SWAPPED, - MAYBE_SWAPPED -} swapped_type_t; - -typedef struct { - gboolean byte_swapped; - swapped_type_t lengths_swapped; - guint16 version_major; - guint16 version_minor; -} libpcap_t; - -typedef struct { - gboolean byte_swapped; - guint16 version_major; - guint16 version_minor; - guint8 if_fcslen; -} pcapng_t; - -typedef struct { - time_t start_secs; - guint32 start_usecs; - guint8 version_major; - guint32 *frame_table; - guint32 frame_table_size; - guint current_frame; -} netmon_t; - -typedef struct { - time_t start_time; - double ticks_per_sec; - double start_timestamp; - gboolean wrapped; - guint32 nframes; - gint64 start_offset; - gint64 end_offset; - int version_major; - gboolean fcs_valid; /* if packets have valid FCS at the end */ - guint isdn_type; /* 1 = E1 PRI, 2 = T1 PRI, 3 = BRI */ -} netxray_t; - -typedef struct { - time_t inittime; - int adjusted; - gint64 next_packet_seek_start; -} ascend_t; - -typedef struct { - gboolean byteswapped; -} csids_t; - -typedef struct { - struct timeval reference_time; -} etherpeek_t; - -typedef struct { - gboolean has_fcs; -} airopeek9_t; - -typedef struct _k12_t k12_t; - -typedef struct { - time_t start_secs; - guint32 start_usecs; -} catapult_dct2000_t; - -typedef struct { - struct wtap_nstime now; - time_t t0; -} mpeg_t; - -typedef gboolean (*subtype_read_func)(struct wtap*, int*, char**, gint64*); -typedef gboolean (*subtype_seek_read_func)(struct wtap*, gint64, union wtap_pseudo_header*, - guint8*, int, int *, char **); -struct wtap { - FILE_T fh; - int fd; /* File descriptor for cap file */ - FILE_T random_fh; /* Secondary FILE_T for random access */ - int file_type; - int snapshot_length; - struct Buffer *frame_buffer; - struct wtap_pkthdr phdr; - union wtap_pseudo_header pseudo_header; - - gint64 data_offset; - - union { - libpcap_t *pcap; - lanalyzer_t *lanalyzer; - ngsniffer_t *ngsniffer; - iseries_t *iseries; - i4btrace_t *i4btrace; - nettl_t *nettl; - netmon_t *netmon; - netxray_t *netxray; - ascend_t *ascend; - csids_t *csids; - etherpeek_t *etherpeek; - airopeek9_t *airopeek9; - k12_t *k12; - catapult_dct2000_t *catapult_dct2000; - mpeg_t *mpeg; - void *generic; - pcapng_t *pcapng; - } capture; - - subtype_read_func subtype_read; - subtype_seek_read_func subtype_seek_read; - void (*subtype_sequential_close)(struct wtap*); - void (*subtype_close)(struct wtap*); - int file_encap; /* per-file, for those - file formats that have - per-file encapsulation - types */ - int tsprecision; /* timestamp precision of the lower 32bits - * e.g. WTAP_FILE_TSPREC_USEC */ -}; - -struct wtap_dumper; - -typedef gboolean (*subtype_write_func)(struct wtap_dumper*, - const struct wtap_pkthdr*, const union wtap_pseudo_header*, - const guchar*, int*); -typedef gboolean (*subtype_close_func)(struct wtap_dumper*, int*); - -typedef struct { - gboolean first_frame; - time_t start; -} ngsniffer_dump_t; - -typedef struct { - gboolean first_frame; - struct wtap_nstime start; - guint32 nframes; -} netxray_dump_t; - -typedef struct { - gboolean got_first_record_time; - struct wtap_nstime first_record_time; - guint32 frame_table_offset; - guint32 *frame_table; - guint frame_table_index; - guint frame_table_size; -} netmon_dump_t; - -typedef struct { - guint32 nframes; -} _5views_dump_t; - -typedef struct { - guint64 packet_count; - guint8 network_type; -} niobserver_dump_t; - -typedef struct { - guint32 file_len; - guint32 num_of_records; - guint32 file_offset; -} k12_dump_t; - -typedef struct { - gboolean first_packet_written; - struct wtap_nstime start_time; -} dct2000_dump_t; - -struct wtap_dumper { - FILE* fh; - int file_type; - int snaplen; - int encap; - gboolean compressed; - gint64 bytes_dumped; - - union { - void *opaque; - ngsniffer_dump_t *ngsniffer; - netmon_dump_t *netmon; - netxray_dump_t *netxray; - _5views_dump_t *_5views; - niobserver_dump_t *niobserver; - k12_dump_t *k12; - dct2000_dump_t *dct2000; - } dump; - - subtype_write_func subtype_write; - subtype_close_func subtype_close; - - int tsprecision; /* timestamp precision of the lower 32bits - * e.g. WTAP_FILE_TSPREC_USEC */ -}; - -extern size_t wtap_dump_file_write(wtap_dumper *wdh, const void *buf, unsigned bufsize); -extern int wtap_dump_file_ferror(wtap_dumper *wdh); - -extern gint wtap_num_file_types; - -/* Macros to byte-swap 64-bit, 32-bit and 16-bit quantities. */ -#define BSWAP64(x) \ - ((((x)&G_GINT64_CONSTANT(0xFF00000000000000U))>>56) | \ - (((x)&G_GINT64_CONSTANT(0x00FF000000000000U))>>40) | \ - (((x)&G_GINT64_CONSTANT(0x0000FF0000000000U))>>24) | \ - (((x)&G_GINT64_CONSTANT(0x000000FF00000000U))>>8) | \ - (((x)&G_GINT64_CONSTANT(0x00000000FF000000U))<<8) | \ - (((x)&G_GINT64_CONSTANT(0x0000000000FF0000U))<<24) | \ - (((x)&G_GINT64_CONSTANT(0x000000000000FF00U))<<40) | \ - (((x)&G_GINT64_CONSTANT(0x00000000000000FFU))<<56)) -#define BSWAP32(x) \ - ((((x)&0xFF000000)>>24) | \ - (((x)&0x00FF0000)>>8) | \ - (((x)&0x0000FF00)<<8) | \ - (((x)&0x000000FF)<<24)) -#define BSWAP16(x) \ - ((((x)&0xFF00)>>8) | \ - (((x)&0x00FF)<<8)) - -/* Macros to byte-swap possibly-unaligned 32-bit and 16-bit quantities; - * they take a pointer to the quantity, and byte-swap it in place. - */ -#define PBSWAP32(p) \ - { \ - guint8 tmp; \ - tmp = (p)[3]; \ - (p)[3] = (p)[0]; \ - (p)[0] = tmp; \ - tmp = (p)[2]; \ - (p)[2] = (p)[1]; \ - (p)[1] = tmp; \ - } -#define PBSWAP16(p) \ - { \ - guint8 tmp; \ - tmp = (p)[1]; \ - (p)[1] = (p)[0]; \ - (p)[0] = tmp; \ - } - -/* Turn host-byte-order values into little-endian values. */ -#define htoles(s) GUINT16_TO_LE(s) -#define htolel(l) GUINT32_TO_LE(l) -#define htolell(ll) GUINT64_TO_LE(ll) - -/* Pointer versions of ntohs and ntohl. Given a pointer to a member of a - * byte array, returns the value of the two or four bytes at the pointer. - * The pletoh[sl] versions return the little-endian representation. - * We also provide pntohll and pletohll, which extract 64-bit integral - * quantities. - * - * These will work regardless of the byte alignment of the pointer. - */ - -#ifndef pntohs -#define pntohs(p) ((guint16) \ - ((guint16)*((const guint8 *)(p)+0)<<8| \ - (guint16)*((const guint8 *)(p)+1)<<0)) -#endif - -#ifndef pntoh24 -#define pntoh24(p) ((guint32)*((const guint8 *)(p)+0)<<16| \ - (guint32)*((const guint8 *)(p)+1)<<8| \ - (guint32)*((const guint8 *)(p)+2)<<0) -#endif - -#ifndef pntohl -#define pntohl(p) ((guint32)*((const guint8 *)(p)+0)<<24| \ - (guint32)*((const guint8 *)(p)+1)<<16| \ - (guint32)*((const guint8 *)(p)+2)<<8| \ - (guint32)*((const guint8 *)(p)+3)<<0) -#endif - -#ifndef pntohll -#define pntohll(p) ((guint64)*((const guint8 *)(p)+0)<<56| \ - (guint64)*((const guint8 *)(p)+1)<<48| \ - (guint64)*((const guint8 *)(p)+2)<<40| \ - (guint64)*((const guint8 *)(p)+3)<<32| \ - (guint64)*((const guint8 *)(p)+4)<<24| \ - (guint64)*((const guint8 *)(p)+5)<<16| \ - (guint64)*((const guint8 *)(p)+6)<<8| \ - (guint64)*((const guint8 *)(p)+7)<<0) -#endif - - -#ifndef pletohs -#define pletohs(p) ((guint16) \ - ((guint16)*((const guint8 *)(p)+1)<<8| \ - (guint16)*((const guint8 *)(p)+0)<<0)) -#endif - -#ifndef pletoh24 -#define pletoh24(p) ((guint32)*((const guint8 *)(p)+2)<<16| \ - (guint32)*((const guint8 *)(p)+1)<<8| \ - (guint32)*((const guint8 *)(p)+0)<<0) -#endif - - -#ifndef pletohl -#define pletohl(p) ((guint32)*((const guint8 *)(p)+3)<<24| \ - (guint32)*((const guint8 *)(p)+2)<<16| \ - (guint32)*((const guint8 *)(p)+1)<<8| \ - (guint32)*((const guint8 *)(p)+0)<<0) -#endif - - -#ifndef pletohll -#define pletohll(p) ((guint64)*((const guint8 *)(p)+7)<<56| \ - (guint64)*((const guint8 *)(p)+6)<<48| \ - (guint64)*((const guint8 *)(p)+5)<<40| \ - (guint64)*((const guint8 *)(p)+4)<<32| \ - (guint64)*((const guint8 *)(p)+3)<<24| \ - (guint64)*((const guint8 *)(p)+2)<<16| \ - (guint64)*((const guint8 *)(p)+1)<<8| \ - (guint64)*((const guint8 *)(p)+0)<<0) -#endif - -/* Pointer routines to put items out in a particular byte order. - * These will work regardless of the byte alignment of the pointer. - */ - -#ifndef phtons -#define phtons(p, v) \ - { \ - (p)[0] = (guint8)((v) >> 8); \ - (p)[1] = (guint8)((v) >> 0); \ - } -#endif - -#ifndef phtonl -#define phtonl(p, v) \ - { \ - (p)[0] = (guint8)((v) >> 24); \ - (p)[1] = (guint8)((v) >> 16); \ - (p)[2] = (guint8)((v) >> 8); \ - (p)[3] = (guint8)((v) >> 0); \ - } -#endif - -#ifndef phtonll -#define phtonll(p, v) \ - { \ - (p)[0] = (guint8)((v) >> 56); \ - (p)[1] = (guint8)((v) >> 48); \ - (p)[2] = (guint8)((v) >> 40); \ - (p)[3] = (guint8)((v) >> 32); \ - (p)[4] = (guint8)((v) >> 24); \ - (p)[5] = (guint8)((v) >> 16); \ - (p)[6] = (guint8)((v) >> 8); \ - (p)[7] = (guint8)((v) >> 0); \ - } -#endif - -#ifndef pletonll -#define pletonll(p, v) \ - { \ - (p)[0] = (guint8)((v) >> 0); \ - (p)[1] = (guint8)((v) >> 8); \ - (p)[2] = (guint8)((v) >> 16); \ - (p)[3] = (guint8)((v) >> 24); \ - (p)[4] = (guint8)((v) >> 32); \ - (p)[5] = (guint8)((v) >> 40); \ - (p)[6] = (guint8)((v) >> 48); \ - (p)[7] = (guint8)((v) >> 56); \ - } -#endif - -#define wtap_file_read_unknown_bytes(target, num_bytes, fh, err) \ - G_STMT_START \ - { \ - int _bytes_read; \ - _bytes_read = file_read((target), 1, (num_bytes), (fh)); \ - if (_bytes_read != (int) (num_bytes)) { \ - *(err) = file_error((fh)); \ - return FALSE; \ - } \ - } \ - G_STMT_END - -#define wtap_file_read_expected_bytes(target, num_bytes, fh, err) \ - G_STMT_START \ - { \ - int _bytes_read; \ - _bytes_read = file_read((target), 1, (num_bytes), (fh)); \ - if (_bytes_read != (int) (num_bytes)) { \ - *(err) = file_error((fh)); \ - if (*(err) == 0 && _bytes_read > 0) { \ - *(err) = WTAP_ERR_SHORT_READ; \ - } \ - return FALSE; \ - } \ - } \ - G_STMT_END - -/* glib doesn't have g_ptr_array_len of all things!*/ -#ifndef g_ptr_array_len -#define g_ptr_array_len(a) ((a)->len) -#endif - -#endif /* __WTAP_INT_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/wtap.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/wtap.h deleted file mode 100644 index 9f51c19f..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/wtap.h +++ /dev/null @@ -1,944 +0,0 @@ -/* wtap.h - * - * $Id: wtap.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef __WTAP_H__ -#define __WTAP_H__ - -#ifdef HAVE_SYS_TIME_H -#include -#endif - -#ifdef HAVE_WINSOCK2_H -# include -#endif - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* Encapsulation types. Choose names that truly reflect - * what is contained in the packet trace file. - * - * WTAP_ENCAP_PER_PACKET is a value passed to "wtap_dump_open()" or - * "wtap_dump_fd_open()" to indicate that there is no single encapsulation - * type for all packets in the file; this may cause those routines to - * fail if the capture file format being written can't support that. - * It's also returned by "wtap_file_encap()" for capture files that - * don't have a single encapsulation type for all packets in the file. - * - * WTAP_ENCAP_UNKNOWN is returned by "wtap_pcap_encap_to_wtap_encap()" - * if it's handed an unknown encapsulation. - * - * WTAP_ENCAP_FDDI_BITSWAPPED is for FDDI captures on systems where the - * MAC addresses you get from the hardware are bit-swapped. Ideally, - * the driver would tell us that, but I know of none that do, so, for - * now, we base it on the machine on which we're *reading* the - * capture, rather than on the machine on which the capture was taken - * (they're probably likely to be the same). We assume that they're - * bit-swapped on everything except for systems running Ultrix, Alpha - * systems, and BSD/OS systems (that's what "tcpdump" does; I guess - * Digital decided to bit-swap addresses in the hardware or in the - * driver, and I guess BSDI bit-swapped them in the driver, given that - * BSD/OS generally runs on Boring Old PC's). If we create a wiretap - * save file format, we'd use the WTAP_ENCAP values to flag the - * encapsulation of a packet, so there we'd at least be able to base - * it on the machine on which the capture was taken. - * - * WTAP_ENCAP_LINUX_ATM_CLIP is the encapsulation you get with the - * ATM on Linux code from ; - * that code adds a DLT_ATM_CLIP DLT_ code of 19, and that - * encapsulation isn't the same as the DLT_ATM_RFC1483 encapsulation - * presumably used on some BSD systems, which we turn into - * WTAP_ENCAP_ATM_RFC1483. - * - * WTAP_ENCAP_NULL corresponds to DLT_NULL from "libpcap". This - * corresponds to - * - * 1) PPP-over-HDLC encapsulation, at least with some versions - * of ISDN4BSD (but not the current ones, it appears, unless - * I've missed something); - * - * 2) a 4-byte header containing the AF_ address family, in - * the byte order of the machine that saved the capture, - * for the packet, as used on many BSD systems for the - * loopback device and some other devices, or a 4-byte header - * containing the AF_ address family in network byte order, - * as used on recent OpenBSD systems for the loopback device; - * - * 3) a 4-byte header containing 2 octets of 0 and an Ethernet - * type in the byte order from an Ethernet header, that being - * what older versions of "libpcap" on Linux turn the Ethernet - * header for loopback interfaces into (0.6.0 and later versions - * leave the Ethernet header alone and make it DLT_EN10MB). */ -#define WTAP_ENCAP_PER_PACKET -1 -#define WTAP_ENCAP_UNKNOWN 0 -#define WTAP_ENCAP_ETHERNET 1 -#define WTAP_ENCAP_TOKEN_RING 2 -#define WTAP_ENCAP_SLIP 3 -#define WTAP_ENCAP_PPP 4 -#define WTAP_ENCAP_FDDI 5 -#define WTAP_ENCAP_FDDI_BITSWAPPED 6 -#define WTAP_ENCAP_RAW_IP 7 -#define WTAP_ENCAP_ARCNET 8 -#define WTAP_ENCAP_ARCNET_LINUX 9 -#define WTAP_ENCAP_ATM_RFC1483 10 -#define WTAP_ENCAP_LINUX_ATM_CLIP 11 -#define WTAP_ENCAP_LAPB 12 -#define WTAP_ENCAP_ATM_PDUS 13 -#define WTAP_ENCAP_ATM_PDUS_UNTRUNCATED 14 -#define WTAP_ENCAP_NULL 15 -#define WTAP_ENCAP_ASCEND 16 -#define WTAP_ENCAP_ISDN 17 -#define WTAP_ENCAP_IP_OVER_FC 18 -#define WTAP_ENCAP_PPP_WITH_PHDR 19 -#define WTAP_ENCAP_IEEE_802_11 20 -#define WTAP_ENCAP_PRISM_HEADER 21 -#define WTAP_ENCAP_IEEE_802_11_WITH_RADIO 22 -#define WTAP_ENCAP_IEEE_802_11_WLAN_RADIOTAP 23 -#define WTAP_ENCAP_IEEE_802_11_WLAN_AVS 24 -#define WTAP_ENCAP_SLL 25 -#define WTAP_ENCAP_FRELAY 26 -#define WTAP_ENCAP_FRELAY_WITH_PHDR 27 -#define WTAP_ENCAP_CHDLC 28 -#define WTAP_ENCAP_CISCO_IOS 29 -#define WTAP_ENCAP_LOCALTALK 30 -#define WTAP_ENCAP_OLD_PFLOG 31 -#define WTAP_ENCAP_HHDLC 32 -#define WTAP_ENCAP_DOCSIS 33 -#define WTAP_ENCAP_COSINE 34 -#define WTAP_ENCAP_WFLEET_HDLC 35 -#define WTAP_ENCAP_SDLC 36 -#define WTAP_ENCAP_TZSP 37 -#define WTAP_ENCAP_ENC 38 -#define WTAP_ENCAP_PFLOG 39 -#define WTAP_ENCAP_CHDLC_WITH_PHDR 40 -#define WTAP_ENCAP_BLUETOOTH_H4 41 -#define WTAP_ENCAP_MTP2 42 -#define WTAP_ENCAP_MTP3 43 -#define WTAP_ENCAP_IRDA 44 -#define WTAP_ENCAP_USER0 45 -#define WTAP_ENCAP_USER1 46 -#define WTAP_ENCAP_USER2 47 -#define WTAP_ENCAP_USER3 48 -#define WTAP_ENCAP_USER4 49 -#define WTAP_ENCAP_USER5 50 -#define WTAP_ENCAP_USER6 51 -#define WTAP_ENCAP_USER7 52 -#define WTAP_ENCAP_USER8 53 -#define WTAP_ENCAP_USER9 54 -#define WTAP_ENCAP_USER10 55 -#define WTAP_ENCAP_USER11 56 -#define WTAP_ENCAP_USER12 57 -#define WTAP_ENCAP_USER13 58 -#define WTAP_ENCAP_USER14 59 -#define WTAP_ENCAP_USER15 60 -#define WTAP_ENCAP_SYMANTEC 61 -#define WTAP_ENCAP_APPLE_IP_OVER_IEEE1394 62 -#define WTAP_ENCAP_BACNET_MS_TP 63 -#define WTAP_ENCAP_NETTL_RAW_ICMP 64 -#define WTAP_ENCAP_NETTL_RAW_ICMPV6 65 -#define WTAP_ENCAP_GPRS_LLC 66 -#define WTAP_ENCAP_JUNIPER_ATM1 67 -#define WTAP_ENCAP_JUNIPER_ATM2 68 -#define WTAP_ENCAP_REDBACK 69 -#define WTAP_ENCAP_NETTL_RAW_IP 70 -#define WTAP_ENCAP_NETTL_ETHERNET 71 -#define WTAP_ENCAP_NETTL_TOKEN_RING 72 -#define WTAP_ENCAP_NETTL_FDDI 73 -#define WTAP_ENCAP_NETTL_UNKNOWN 74 -#define WTAP_ENCAP_MTP2_WITH_PHDR 75 -#define WTAP_ENCAP_JUNIPER_PPPOE 76 -#define WTAP_GCOM_TIE1 77 -#define WTAP_GCOM_SERIAL 78 -#define WTAP_ENCAP_NETTL_X25 79 -#define WTAP_ENCAP_K12 80 -#define WTAP_ENCAP_JUNIPER_MLPPP 81 -#define WTAP_ENCAP_JUNIPER_MLFR 82 -#define WTAP_ENCAP_JUNIPER_ETHER 83 -#define WTAP_ENCAP_JUNIPER_PPP 84 -#define WTAP_ENCAP_JUNIPER_FRELAY 85 -#define WTAP_ENCAP_JUNIPER_CHDLC 86 -#define WTAP_ENCAP_JUNIPER_GGSN 87 -#define WTAP_ENCAP_LINUX_LAPD 88 -#define WTAP_ENCAP_CATAPULT_DCT2000 89 -#define WTAP_ENCAP_BER 90 -#define WTAP_ENCAP_JUNIPER_VP 91 -#define WTAP_ENCAP_USB 92 -#define WTAP_ENCAP_IEEE802_16_MAC_CPS 93 -#define WTAP_ENCAP_NETTL_RAW_TELNET 94 -#define WTAP_ENCAP_USB_LINUX 95 -#define WTAP_ENCAP_MPEG 96 -#define WTAP_ENCAP_PPI 97 -#define WTAP_ENCAP_ERF 98 -#define WTAP_ENCAP_BLUETOOTH_H4_WITH_PHDR 99 -#define WTAP_ENCAP_SITA 100 -#define WTAP_ENCAP_SCCP 101 -#define WTAP_ENCAP_BLUETOOTH_HCI 102 /*raw packets without a transport layer header e.g. H4*/ -#define WTAP_ENCAP_IPMB 103 -#define WTAP_ENCAP_IEEE802_15_4 104 -#define WTAP_ENCAP_X2E_XORAYA 105 -#define WTAP_ENCAP_FLEXRAY 106 -#define WTAP_ENCAP_LIN 107 -#define WTAP_ENCAP_MOST 108 -#define WTAP_ENCAP_CAN20B 109 - -#define WTAP_NUM_ENCAP_TYPES wtap_get_num_encap_types() - -/* File types that can be read by wiretap. - We support writing some many of these file types, too, so we - distinguish between different versions of them. */ -#define WTAP_FILE_UNKNOWN 0 -#define WTAP_FILE_WTAP 1 -#define WTAP_FILE_PCAP 2 -#define WTAP_FILE_PCAP_NSEC 3 -#define WTAP_FILE_PCAP_AIX 4 -#define WTAP_FILE_PCAP_SS991029 5 -#define WTAP_FILE_PCAP_NOKIA 6 -#define WTAP_FILE_PCAP_SS990417 7 -#define WTAP_FILE_PCAP_SS990915 8 -#define WTAP_FILE_5VIEWS 9 -#define WTAP_FILE_IPTRACE_1_0 10 -#define WTAP_FILE_IPTRACE_2_0 11 -#define WTAP_FILE_BER 12 -#define WTAP_FILE_HCIDUMP 13 -#define WTAP_FILE_CATAPULT_DCT2000 14 -#define WTAP_FILE_NETXRAY_OLD 15 -#define WTAP_FILE_NETXRAY_1_0 16 -#define WTAP_FILE_COSINE 17 -#define WTAP_FILE_CSIDS 18 -#define WTAP_FILE_DBS_ETHERWATCH 19 -#define WTAP_FILE_ERF 20 -#define WTAP_FILE_EYESDN 21 -#define WTAP_FILE_NETTL 22 -#define WTAP_FILE_ISERIES 23 -#define WTAP_FILE_ISERIES_UNICODE 24 -#define WTAP_FILE_I4BTRACE 25 -#define WTAP_FILE_ASCEND 26 -#define WTAP_FILE_NETMON_1_x 27 -#define WTAP_FILE_NETMON_2_x 28 -#define WTAP_FILE_NGSNIFFER_UNCOMPRESSED 29 -#define WTAP_FILE_NGSNIFFER_COMPRESSED 30 -#define WTAP_FILE_NETXRAY_1_1 31 -#define WTAP_FILE_NETXRAY_2_00x 32 -#define WTAP_FILE_NETWORK_INSTRUMENTS_V9 33 -#define WTAP_FILE_LANALYZER 34 -#define WTAP_FILE_PPPDUMP 35 -#define WTAP_FILE_RADCOM 36 -#define WTAP_FILE_SNOOP 37 -#define WTAP_FILE_SHOMITI 38 -#define WTAP_FILE_VMS 39 -#define WTAP_FILE_K12 40 -#define WTAP_FILE_TOSHIBA 41 -#define WTAP_FILE_VISUAL_NETWORKS 42 -#define WTAP_FILE_ETHERPEEK_V56 43 -#define WTAP_FILE_ETHERPEEK_V7 44 -#define WTAP_FILE_AIROPEEK_V9 45 -#define WTAP_FILE_MPEG 46 -#define WTAP_FILE_K12TEXT 47 -#define WTAP_FILE_NETSCREEN 48 -#define WTAP_FILE_COMMVIEW 49 -#define WTAP_FILE_PCAPNG 50 -#define WTAP_FILE_BTSNOOP 51 -#define WTAP_FILE_X2E_XORAYA 52 - -#define WTAP_NUM_FILE_TYPES wtap_get_num_file_types() - -/* timestamp precision (currently only these values are supported) */ -#define WTAP_FILE_TSPREC_SEC 0 -#define WTAP_FILE_TSPREC_DSEC 1 -#define WTAP_FILE_TSPREC_CSEC 2 -#define WTAP_FILE_TSPREC_MSEC 3 -#define WTAP_FILE_TSPREC_USEC 6 -#define WTAP_FILE_TSPREC_NSEC 9 - -/* - * Maximum packet size we'll support. - * It must be at least 65535. - */ -#define WTAP_MAX_PACKET_SIZE 65535 - -/* - * "Pseudo-headers" are used to supply to the clients of wiretap - * per-packet information that's not part of the packet payload - * proper. - * - * NOTE: do not use pseudo-header structures to hold information - * used by the code to read a particular capture file type; to - * keep that sort of state information, add a new structure for - * that private information to "wtap-int.h", add a pointer to that - * type of structure to the "capture" member of the "struct wtap" - * structure, and allocate one of those structures and set that member - * in the "open" routine for that capture file type if the open - * succeeds. See various other capture file type handlers for examples - * of that. - */ - -/* Packet "pseudo-header" information for Ethernet capture files. */ -struct eth_phdr { - gint fcs_len; /* Number of bytes of FCS - -1 means "unknown" */ -}; - -/* Packet "pseudo-header" information for X.25 capture files. */ -#define FROM_DCE 0x80 -struct x25_phdr { - guint8 flags; /* ENCAP_LAPB, ENCAP_V120 : 1st bit means From DCE */ -}; - -/* Packet "pseudo-header" information for ISDN capture files. */ - -/* Direction */ -struct isdn_phdr { - gboolean uton; - guint8 channel; /* 0 = D-channel; n = B-channel n */ -}; - -/* Packet "pseudo-header" for ATM capture files. - Not all of this information is supplied by all capture types. */ - -/* - * Status bits. - */ -#define ATM_RAW_CELL 0x01 /* TRUE if the packet is a single cell */ - -/* - * AAL types. - */ -#define AAL_UNKNOWN 0 /* AAL unknown */ -#define AAL_1 1 /* AAL1 */ -#define AAL_2 2 /* AAL2 */ -#define AAL_3_4 3 /* AAL3/4 */ -#define AAL_5 4 /* AAL5 */ -#define AAL_USER 5 /* User AAL */ -#define AAL_SIGNALLING 6 /* Signaling AAL */ -#define AAL_OAMCELL 7 /* OAM cell */ - -/* - * Traffic types. - */ -#define TRAF_UNKNOWN 0 /* Unknown */ -#define TRAF_LLCMX 1 /* LLC multiplexed (RFC 1483) */ -#define TRAF_VCMX 2 /* VC multiplexed (RFC 1483) */ -#define TRAF_LANE 3 /* LAN Emulation */ -#define TRAF_ILMI 4 /* ILMI */ -#define TRAF_FR 5 /* Frame Relay */ -#define TRAF_SPANS 6 /* FORE SPANS */ -#define TRAF_IPSILON 7 /* Ipsilon */ -#define TRAF_UMTS_FP 8 /* UMTS Frame Protocol */ - -/* - * Traffic subtypes. - */ -#define TRAF_ST_UNKNOWN 0 /* Unknown */ - -/* - * For TRAF_VCMX: - */ -#define TRAF_ST_VCMX_802_3_FCS 1 /* 802.3 with an FCS */ -#define TRAF_ST_VCMX_802_4_FCS 2 /* 802.4 with an FCS */ -#define TRAF_ST_VCMX_802_5_FCS 3 /* 802.5 with an FCS */ -#define TRAF_ST_VCMX_FDDI_FCS 4 /* FDDI with an FCS */ -#define TRAF_ST_VCMX_802_6_FCS 5 /* 802.6 with an FCS */ -#define TRAF_ST_VCMX_802_3 7 /* 802.3 without an FCS */ -#define TRAF_ST_VCMX_802_4 8 /* 802.4 without an FCS */ -#define TRAF_ST_VCMX_802_5 9 /* 802.5 without an FCS */ -#define TRAF_ST_VCMX_FDDI 10 /* FDDI without an FCS */ -#define TRAF_ST_VCMX_802_6 11 /* 802.6 without an FCS */ -#define TRAF_ST_VCMX_FRAGMENTS 12 /* Fragments */ -#define TRAF_ST_VCMX_BPDU 13 /* BPDU */ - -/* - * For TRAF_LANE: - */ -#define TRAF_ST_LANE_LE_CTRL 1 /* LANE: LE Ctrl */ -#define TRAF_ST_LANE_802_3 2 /* LANE: 802.3 */ -#define TRAF_ST_LANE_802_5 3 /* LANE: 802.5 */ -#define TRAF_ST_LANE_802_3_MC 4 /* LANE: 802.3 multicast */ -#define TRAF_ST_LANE_802_5_MC 5 /* LANE: 802.5 multicast */ - -/* - * For TRAF_IPSILON: - */ -#define TRAF_ST_IPSILON_FT0 1 /* Ipsilon: Flow Type 0 */ -#define TRAF_ST_IPSILON_FT1 2 /* Ipsilon: Flow Type 1 */ -#define TRAF_ST_IPSILON_FT2 3 /* Ipsilon: Flow Type 2 */ - -struct atm_phdr { - guint32 flags; /* status flags */ - guint8 aal; /* AAL of the traffic */ - guint8 type; /* traffic type */ - guint8 subtype; /* traffic subtype */ - guint16 vpi; /* virtual path identifier */ - guint16 vci; /* virtual circuit identifier */ - guint8 aal2_cid; /* channel id */ - guint16 channel; /* link: 0 for DTE->DCE, 1 for DCE->DTE */ - guint16 cells; /* number of cells */ - guint16 aal5t_u2u; /* user-to-user indicator */ - guint16 aal5t_len; /* length of the packet */ - guint32 aal5t_chksum; /* checksum for AAL5 packet */ -}; - -/* Packet "pseudo-header" for the output from "wandsession", "wannext", - "wandisplay", and similar commands on Lucent/Ascend access equipment. */ - -#define ASCEND_MAX_STR_LEN 64 - -#define ASCEND_PFX_WDS_X 1 -#define ASCEND_PFX_WDS_R 2 -#define ASCEND_PFX_WDD 3 -#define ASCEND_PFX_ISDN_X 4 -#define ASCEND_PFX_ISDN_R 5 -#define ASCEND_PFX_ETHER 6 - -struct ascend_phdr { - guint16 type; /* ASCEND_PFX_*, as defined above */ - char user[ASCEND_MAX_STR_LEN]; /* Username, from wandsession header */ - guint32 sess; /* Session number, from wandsession header */ - char call_num[ASCEND_MAX_STR_LEN]; /* Called number, from WDD header */ - guint32 chunk; /* Chunk number, from WDD header */ - guint32 task; /* Task number */ -}; - -/* Packet "pseudo-header" for point-to-point links with direction flags. */ -struct p2p_phdr { - gboolean sent; /* TRUE=sent, FALSE=received */ -}; - -/* - * Packet "pseudo-header" information for 802.11. - * Radio information is only present for WTAP_ENCAP_IEEE_802_11_WITH_RADIO. - * - * Signal strength, etc. information: - * - * Raw signal strength can be measured in milliwatts. - * It can also be represented as dBm, which is 10 times the log base 10 - * of the signal strength in mW. - * - * The Receive Signal Strength Indicator is an integer in the range 0 to 255. - * The actual RSSI value for a given signal strength is dependent on the - * vendor (and perhaps on the adapter). The maximum possible RSSI value - * is also dependent on the vendor and perhaps the adapter. - * - * The signal strength can be represented as a percentage, which is 100 - * times the ratio of the RSSI and the maximum RSSI. - */ -struct ieee_802_11_phdr { - gint fcs_len; /* Number of bytes of FCS - -1 means "unknown" */ - guint8 channel; /* Channel number */ - guint8 data_rate; /* in .5 Mb/s units */ - guint8 signal_level; /* percentage */ -}; - -/* Packet "pseudo-header" for the output from CoSine L2 debug output. */ - -#define COSINE_MAX_IF_NAME_LEN 128 - -#define COSINE_ENCAP_TEST 1 -#define COSINE_ENCAP_PPoATM 2 -#define COSINE_ENCAP_PPoFR 3 -#define COSINE_ENCAP_ATM 4 -#define COSINE_ENCAP_FR 5 -#define COSINE_ENCAP_HDLC 6 -#define COSINE_ENCAP_PPP 7 -#define COSINE_ENCAP_ETH 8 -#define COSINE_ENCAP_UNKNOWN 99 - -#define COSINE_DIR_TX 1 -#define COSINE_DIR_RX 2 - -struct cosine_phdr { - guint8 encap; /* COSINE_ENCAP_* as defined above */ - guint8 direction; /* COSINE_DIR_*, as defined above */ - char if_name[COSINE_MAX_IF_NAME_LEN]; /* Encap & Logical I/F name */ - guint16 pro; /* Protocol */ - guint16 off; /* Offset */ - guint16 pri; /* Priority */ - guint16 rm; /* Rate Marking */ - guint16 err; /* Error Code */ -}; - -/* Packet "pseudo-header" for IrDA capture files. */ - -/* - * Direction of the packet - */ -#define IRDA_INCOMING 0x0000 -#define IRDA_OUTGOING 0x0004 - -/* - * "Inline" log messages produced by IrCOMM2k on Windows - */ -#define IRDA_LOG_MESSAGE 0x0100 /* log message */ -#define IRDA_MISSED_MSG 0x0101 /* missed log entry or frame */ - -/* - * Differentiate between frames and log messages - */ -#define IRDA_CLASS_FRAME 0x0000 -#define IRDA_CLASS_LOG 0x0100 -#define IRDA_CLASS_MASK 0xFF00 - -struct irda_phdr { - guint16 pkttype; /* packet type */ -}; - -/* Packet "pseudo-header" for nettl (HP-UX) capture files. */ - -struct nettl_phdr { - guint16 subsys; - guint32 devid; - guint32 kind; - gint32 pid; - guint16 uid; -}; - -/* Packet "pseudo-header" for MTP2 files. */ - -#define MTP2_ANNEX_A_NOT_USED 0 -#define MTP2_ANNEX_A_USED 1 -#define MTP2_ANNEX_A_USED_UNKNOWN 2 - -struct mtp2_phdr { - guint8 sent; - guint8 annex_a_used; - guint16 link_number; -}; - -/* Packet "pseudo-header" for K12 files. */ - -typedef union { - struct { - guint16 vp; - guint16 vc; - guint16 cid; - } atm; - - guint32 ds0mask; -} k12_input_info_t; - -struct k12_phdr { - guint32 input; - const gchar* input_name; - const gchar* stack_file; - guint32 input_type; - k12_input_info_t input_info; - gchar* extra_info; - guint32 extra_length; - void* stuff; -}; - -#define K12_PORT_DS0S 0x00010008 -#define K12_PORT_DS1 0x00100008 -#define K12_PORT_ATMPVC 0x01020000 - -struct lapd_phdr { - guint16 pkttype; /* packet type */ - guint8 we_network; -}; - -struct wtap; -struct catapult_dct2000_phdr -{ - union - { - struct isdn_phdr isdn; - struct atm_phdr atm; - struct p2p_phdr p2p; - } inner_pseudo_header; - gint64 seek_off; - struct wtap *wth; -}; - -/* - * possible event type - */ -#define URB_SUBMIT 'S' -#define URB_COMPLETE 'C' -#define URB_ERROR 'E' - -/* - * possible transfer mode - */ -#define URB_ISOCHRONOUS 0x0 -#define URB_INTERRUPT 0x1 -#define URB_CONTROL 0x2 -#define URB_BULK 0x3 - -#define URB_TRANSFER_IN 0x80 /* to host */ - -/* - * USB setup header as defined in USB specification - */ -struct usb_request_hdr { - gint8 bmRequestType; - guint8 bRequest; - guint16 wValue; - guint16 wIndex; - guint16 wLength; -}; - -/* - * Header prepended by Linux kernel to each USB event. - * Followed by a struct usb_request_hdr, although that header is valid - * only if setup_flag is 0. - * (Setup flag is '-', 'D', 'Z', or 0. Data flag is '<', '>', 'Z', or 0.) - * - * We present this as a pseudo-header; the values are in host byte order. - */ -struct linux_usb_phdr { - guint64 id; /* urb id, to link submission and completion events*/ - guint8 event_type; /* Submit ('S'), Completed ('C'), Error ('E') */ - guint8 transfer_type; /* ISO (0), Intr, Control, Bulk (3) */ - guint8 endpoint_number; /* Endpoint number (0-15) and transfer direction */ - guint8 device_address; /* 0-127 */ - guint16 bus_id; - gint8 setup_flag; /*if !=0 the urb setup header is not present*/ - gint8 data_flag; /*if !=0 no urb data is present*/ - gint64 ts_sec; - gint32 ts_usec; - gint32 status; - guint32 urb_len; /* whole len of urb this event refers to */ - guint32 data_len; /* amount of urb data really present in this event*/ -}; - -/* - * Header prepended by libpcap to each bluetooth hci h:4 frame. - * Values in network byte order - */ -struct libpcap_bt_phdr { - guint32 direction; /* Bit 0 hold the frame direction. */ -}; - -/* - * Endace Record Format pseudo header - */ -struct erf_phdr { - guint64 ts; /* Time stamp */ - guint8 type; - guint8 flags; - guint16 rlen; - guint16 lctr; - guint16 wlen; -}; - -/* - * ERF pseudo header with optional subheader - * (Multichannel or Ethernet) - */ -struct erf_mc_phdr { - struct erf_phdr phdr; - union - { - guint16 eth_hdr; - guint32 mc_hdr; - } subhdr; -}; - -#define SITA_FRAME_DIR_TXED (0x00) /* values of sita_phdr.flags */ -#define SITA_FRAME_DIR_RXED (0x01) -#define SITA_FRAME_DIR (0x01) /* mask */ -#define SITA_ERROR_NO_BUFFER (0x80) - -#define SITA_SIG_DSR (0x01) /* values of sita_phdr.signals */ -#define SITA_SIG_DTR (0x02) -#define SITA_SIG_CTS (0x04) -#define SITA_SIG_RTS (0x08) -#define SITA_SIG_DCD (0x10) -#define SITA_SIG_UNDEF1 (0x20) -#define SITA_SIG_UNDEF2 (0x40) -#define SITA_SIG_UNDEF3 (0x80) - -#define SITA_ERROR_TX_UNDERRUN (0x01) /* values of sita_phdr.errors2 (if SITA_FRAME_DIR_TXED) */ -#define SITA_ERROR_TX_CTS_LOST (0x02) -#define SITA_ERROR_TX_UART_ERROR (0x04) -#define SITA_ERROR_TX_RETX_LIMIT (0x08) -#define SITA_ERROR_TX_UNDEF1 (0x10) -#define SITA_ERROR_TX_UNDEF2 (0x20) -#define SITA_ERROR_TX_UNDEF3 (0x40) -#define SITA_ERROR_TX_UNDEF4 (0x80) - -#define SITA_ERROR_RX_FRAMING (0x01) /* values of sita_phdr.errors1 (if SITA_FRAME_DIR_RXED) */ -#define SITA_ERROR_RX_PARITY (0x02) -#define SITA_ERROR_RX_COLLISION (0x04) -#define SITA_ERROR_RX_FRAME_LONG (0x08) -#define SITA_ERROR_RX_FRAME_SHORT (0x10) -#define SITA_ERROR_RX_UNDEF1 (0x20) -#define SITA_ERROR_RX_UNDEF2 (0x40) -#define SITA_ERROR_RX_UNDEF3 (0x80) - -#define SITA_ERROR_RX_NONOCTET_ALIGNED (0x01) /* values of sita_phdr.errors2 (if SITA_FRAME_DIR_RXED) */ -#define SITA_ERROR_RX_ABORT (0x02) -#define SITA_ERROR_RX_CD_LOST (0x04) -#define SITA_ERROR_RX_DPLL (0x08) -#define SITA_ERROR_RX_OVERRUN (0x10) -#define SITA_ERROR_RX_FRAME_LEN_VIOL (0x20) -#define SITA_ERROR_RX_CRC (0x40) -#define SITA_ERROR_RX_BREAK (0x80) - -#define SITA_PROTO_UNUSED (0x00) /* values of sita_phdr.proto */ -#define SITA_PROTO_BOP_LAPB (0x01) -#define SITA_PROTO_ETHERNET (0x02) -#define SITA_PROTO_ASYNC_INTIO (0x03) -#define SITA_PROTO_ASYNC_BLKIO (0x04) -#define SITA_PROTO_ALC (0x05) -#define SITA_PROTO_UTS (0x06) -#define SITA_PROTO_PPP_HDLC (0x07) -#define SITA_PROTO_SDLC (0x08) -#define SITA_PROTO_TOKENRING (0x09) -#define SITA_PROTO_I2C (0x10) -#define SITA_PROTO_DPM_LINK (0x11) -#define SITA_PROTO_BOP_FRL (0x12) - -struct sita_phdr { - guint8 flags; - guint8 signals; - guint8 errors1; - guint8 errors2; - guint8 proto; -}; - -/*pseudo header for Bluetooth HCI*/ -struct bthci_phdr { - gboolean sent; - guint8 channel; -}; - -#define BTHCI_CHANNEL_COMMAND 1 -#define BTHCI_CHANNEL_ACL 2 -#define BTHCI_CHANNEL_SCO 3 -#define BTHCI_CHANNEL_EVENT 4 - -union wtap_pseudo_header { - struct eth_phdr eth; - struct x25_phdr x25; - struct isdn_phdr isdn; - struct atm_phdr atm; - struct ascend_phdr ascend; - struct p2p_phdr p2p; - struct ieee_802_11_phdr ieee_802_11; - struct cosine_phdr cosine; - struct irda_phdr irda; - struct nettl_phdr nettl; - struct mtp2_phdr mtp2; - struct k12_phdr k12; - struct lapd_phdr lapd; - struct catapult_dct2000_phdr dct2000; - struct linux_usb_phdr linux_usb; - struct erf_mc_phdr erf; - struct sita_phdr sita; - struct bthci_phdr bthci; -}; - -struct wtap_nstime { - time_t secs; - int nsecs; -}; - -struct wtap_pkthdr { - struct wtap_nstime ts; - guint32 caplen; - guint32 len; - int pkt_encap; -}; - -struct wtap; -struct Buffer; -struct wtap_dumper; - -typedef struct wtap wtap; -typedef struct wtap_dumper wtap_dumper; - -struct file_type_info { - /* the file type name */ - /* should be NULL for all "pseudo" types that are only internally used and not read/writeable */ - const char *name; - - /* the file type short name, used as a shortcut for the command line tools */ - /* should be NULL for all "pseudo" types that are only internally used and not read/writeable */ - const char *short_name; - - /* the common file extensions for this type (seperated by semicolon) */ - /* should be *.* if no common extension is applicable */ - const char *file_extensions; - - /* the default file extension, used to save this type */ - /* should be NULL if no default extension is known */ - const char *file_extension_default; - - /* can this type be compressed with gzip? */ - gboolean can_compress; - - /* can this type write this encapsulation format? */ - /* should be NULL is this file type don't have write support */ - int (*can_write_encap)(int); - - /* the function to open the capture file for writing */ - /* should be NULL is this file type don't have write support */ - int (*dump_open)(wtap_dumper *, gboolean, int *); -}; - - -typedef int (*wtap_open_routine_t)(struct wtap*, int *, char **); - - -/* - * On failure, "wtap_open_offline()" returns NULL, and puts into the - * "int" pointed to by its second argument: - * - * a positive "errno" value if the capture file can't be opened; - * a negative number, indicating the type of error, on other failures. - */ -struct wtap* wtap_open_offline(const char *filename, int *err, - gchar **err_info, gboolean do_random); - -/* Returns TRUE if read was successful. FALSE if failure. data_offset is - * set to the offset in the file where the data for the read packet is - * located. */ -gboolean wtap_read(wtap *wth, int *err, gchar **err_info, - gint64 *data_offset); - -gboolean wtap_seek_read (wtap *wth, gint64 seek_off, - union wtap_pseudo_header *pseudo_header, guint8 *pd, int len, - int *err, gchar **err_info); - -/*** get various information snippets about the current packet ***/ -struct wtap_pkthdr *wtap_phdr(wtap *wth); -union wtap_pseudo_header *wtap_pseudoheader(wtap *wth); -guint8 *wtap_buf_ptr(wtap *wth); - -/*** get various information snippets about the current file ***/ - -/* Return an approximation of the amount of data we've read sequentially - * from the file so far. */ -gint64 wtap_read_so_far(wtap *wth, int *err); -gint64 wtap_file_size(wtap *wth, int *err); -int wtap_snapshot_length(wtap *wth); /* per file */ -int wtap_file_type(wtap *wth); -int wtap_file_encap(wtap *wth); -int wtap_file_tsprecision(wtap *wth); - -/*** close the current file ***/ -void wtap_sequential_close(wtap *wth); -void wtap_close(wtap *wth); - -/*** dump packets into a capture file ***/ -gboolean wtap_dump_can_open(int filetype); -gboolean wtap_dump_can_write_encap(int filetype, int encap); -gboolean wtap_dump_can_compress(int filetype); -wtap_dumper* wtap_dump_open(const char *filename, int filetype, int encap, - int snaplen, gboolean compressed, int *err); -wtap_dumper* wtap_dump_fdopen(int fd, int filetype, int encap, int snaplen, - gboolean compressed, int *err); -gboolean wtap_dump(wtap_dumper *, const struct wtap_pkthdr *, - const union wtap_pseudo_header *pseudo_header, const guchar *, int *err); -void wtap_dump_flush(wtap_dumper *); -gint64 wtap_get_bytes_dumped(wtap_dumper *); -void wtap_set_bytes_dumped(wtap_dumper *wdh, gint64 bytes_dumped); -gboolean wtap_dump_close(wtap_dumper *, int *); - -/*** various string converter functions ***/ -const char *wtap_file_type_string(int filetype); -const char *wtap_file_type_short_string(int filetype); -int wtap_short_string_to_file_type(const char *short_name); - -const char *wtap_file_extensions_string(int filetype); -const char *wtap_file_extension_default_string(int filetype); - -const char *wtap_encap_string(int encap); -const char *wtap_encap_short_string(int encap); -int wtap_short_string_to_encap(const char *short_name); - -const char *wtap_strerror(int err); - -/*** get available number of file types and encapsulations ***/ -int wtap_get_num_encap_types(void); -int wtap_get_num_file_types(void); - -/*** dynamically register new file types and encapsulations ***/ -void wtap_register_open_routine(wtap_open_routine_t, gboolean has_magic); -int wtap_register_file_type(const struct file_type_info* fi); -int wtap_register_encap_type(char* name, char* short_name); - - -/* - * Wiretap error codes. - */ -#define WTAP_ERR_NOT_REGULAR_FILE -1 - /* The file being opened for reading isn't a plain file (or pipe) */ -#define WTAP_ERR_RANDOM_OPEN_PIPE -2 - /* The file is being opened for random access and it's a pipe */ -#define WTAP_ERR_FILE_UNKNOWN_FORMAT -3 - /* The file being opened is not a capture file in a known format */ -#define WTAP_ERR_UNSUPPORTED -4 - /* Supported file type, but there's something in the file we - can't support */ -#define WTAP_ERR_CANT_WRITE_TO_PIPE -5 - /* Wiretap can't save to a pipe in the specified format */ -#define WTAP_ERR_CANT_OPEN -6 - /* The file couldn't be opened, reason unknown */ -#define WTAP_ERR_UNSUPPORTED_FILE_TYPE -7 - /* Wiretap can't save files in the specified format */ -#define WTAP_ERR_UNSUPPORTED_ENCAP -8 - /* Wiretap can't read or save files in the specified format with the - specified encapsulation */ -#define WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED -9 - /* The specified format doesn't support per-packet encapsulations */ -#define WTAP_ERR_CANT_CLOSE -10 - /* The file couldn't be closed, reason unknown */ -#define WTAP_ERR_CANT_READ -11 - /* An attempt to read failed, reason unknown */ -#define WTAP_ERR_SHORT_READ -12 - /* An attempt to read read less data than it should have */ -#define WTAP_ERR_BAD_RECORD -13 - /* We read an invalid record */ -#define WTAP_ERR_SHORT_WRITE -14 - /* An attempt to write wrote less data than it should have */ -#define WTAP_ERR_UNC_TRUNCATED -15 - /* Sniffer compressed data was oddly truncated */ -#define WTAP_ERR_UNC_OVERFLOW -16 - /* Uncompressing Sniffer data would overflow buffer */ -#define WTAP_ERR_UNC_BAD_OFFSET -17 - /* LZ77 compressed data has bad offset to string */ -#define WTAP_ERR_RANDOM_OPEN_STDIN -18 - /* We're trying to open the standard input for random access */ -#define WTAP_ERR_COMPRESSION_NOT_SUPPORTED -19 - /* The filetype doesn't support output compression */ - -/* Errors from zlib; zlib error Z_xxx turns into Wiretap error - WTAP_ERR_ZLIB + Z_xxx. - - WTAP_ERR_ZLIB_MIN and WTAP_ERR_ZLIB_MAX bound the range of zlib - errors; we leave room for 100 positive and 100 negative error - codes. */ - -#define WTAP_ERR_ZLIB -200 -#define WTAP_ERR_ZLIB_MAX -100 -#define WTAP_ERR_ZLIB_MIN -300 - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __WTAP_H__ */ From 839b0f1d138e95f5d43e6a7af0cba4355c5466b1 Mon Sep 17 00:00:00 2001 From: J980419xq <1908393204@qq.com> Date: Thu, 21 Jul 2022 16:09:57 +0800 Subject: [PATCH 35/44] xiugai --- mininet/mininet/distrinet.py | 2 +- mininet/mininet/lxc_container.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mininet/mininet/distrinet.py b/mininet/mininet/distrinet.py index 6690e725..e186097d 100755 --- a/mininet/mininet/distrinet.py +++ b/mininet/mininet/distrinet.py @@ -571,7 +571,7 @@ def buildFromTopo( self, topo=None ): for node in nodes: _ip = "{}/{}".format(ipAdd( self.adminNextIP, ipBaseNum=self.adminIpBaseNum, prefixLen=self.adminPrefixLen),self.adminPrefixLen) self.adminNextIP += 1 - node.configureContainer(admin_ip=_ip,wait=False,autoSetDocker=self.autoSetDocker + node.configureContainer(admin_ip=_ip,wait=False,autoSetDocker=self.autoSetDocker) count+=1 if count>100: sleep(10) diff --git a/mininet/mininet/lxc_container.py b/mininet/mininet/lxc_container.py index 36d1015b..9aaf266f 100644 --- a/mininet/mininet/lxc_container.py +++ b/mininet/mininet/lxc_container.py @@ -350,7 +350,7 @@ def createContainer(self,autoSetDocker=False, **params): if self.image=="ubuntu": cmd = "docker create -v /root/alcor-control-agent/:/mnt/host/code -it --privileged --cap-add=NET_ADMIN --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --name {} --net=none {} ".format(self.name, self.image) else: - cmd="docker create -it --privileged --cap-add=NET_ADMIN --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --name {} --net=none {} ".format(self.name, self.image) + cmd="docker create -it --privileged --cap-add=NET_ADMIN --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --name {} --net=none {} ".format(self.name, self.image) else: cmd = "lxc init {} {} < /dev/null ".format(self.image, self.name) info("{}\n".format(cmd)) From 0a16a6694badc4339d46c946bb4199e60d4d8eb5 Mon Sep 17 00:00:00 2001 From: J980419xq <1908393204@qq.com> Date: Thu, 21 Jul 2022 18:44:21 +0800 Subject: [PATCH 36/44] onos cluster --- deploy_onos.md | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/deploy_onos.md b/deploy_onos.md index 5dde55d3..85208cd0 100644 --- a/deploy_onos.md +++ b/deploy_onos.md @@ -1,3 +1,4 @@ +## deploy in bare machine ### Step1:install dependcies ```bash apt install wget openjdk-11-jdk @@ -24,5 +25,65 @@ export ONOS_APPS="drivers,openflow-base,openflow,proxyarp,lldpprovider,fwd,optic /opt/onos/bin/onos-service start ``` +## deploy in docker cluster +### Step1:import docker images +```bash +docker pull atomix/atomix +docker pull onosproject/onos +``` + +### Step2:create atomix container +```bash +docker run -t -d --name atomix-1 atomix/atomix +docker run -t -d --name atomix-2 atomix/atomix +docker run -t -d --name atomix-3 atomix/atomix +``` + +### Step3:git onos source code +```bash +cd ~ +git clone https://gerrit.onosproject.org/onos +``` + +### Step4:generate atomix config files +```bash +export OC1=172.17.0.2 #atomix-1 ip +export OC2=172.17.0.3 #atomix-2 ip +export OC3=172.17.0.4 #atomix-3 ip +cd ~/onos +./tools/test/bin/atomix-gen-config 172.17.0.2 ~/atomix-1.conf 172.17.0.2 172.17.0.3 172.17.0.4 #maybe need python2 +./tools/test/bin/atomix-gen-config 172.17.0.3 ~/atomix-2.conf 172.17.0.2 172.17.0.3 172.17.0.4 +./tools/test/bin/atomix-gen-config 172.17.0.4 ~/atomix-3.conf 172.17.0.2 172.17.0.3 172.17.0.4 +docker cp ~/atomix-1.conf atomix-1:/opt/atomix/conf/atomix.conf +docker cp ~/atomix-2.conf atomix-2:/opt/atomix/conf/atomix.conf +docker cp ~/atomix-3.conf atomix-3:/opt/atomix/conf/atomix.conf +docker restart atomix-1 +docker restart atomix-2 +docker restart atomix-3 +``` + +### Step5:create onos container +```bash +docker run -t -d -p 6653:6653 --name onos1 onosproject/onos +docker run -t -d -p 6654:6653 --name onos2 onosproject/onos +docker run -t -d -p 6655:6653 --name onos3 onosproject/onos +``` + +### Step6:generate onos config files +```bash +cd ~/onos +./tools/test/bin/onos-gen-config 172.17.0.5 ~/cluster-1.json -n 172.17.0.2 172.17.0.3 172.17.0.4 #maybe need python2 +./tools/test/bin/onos-gen-config 172.17.0.6 ~/cluster-2.json -n 172.17.0.2 172.17.0.3 172.17.0.4 +./tools/test/bin/onos-gen-config 172.17.0.7 ~/cluster-3.json -n 172.17.0.2 172.17.0.3 172.17.0.4 +docker exec onos1 mkdir /root/onos/config +docker exec onos2 mkdir /root/onos/config +docker exec onos3 mkdir /root/onos/config +docker cp ~/cluster-1.json onos1:/root/onos/config/cluster.json +docker cp ~/cluster-2.json onos2:/root/onos/config/cluster.json +docker cp ~/cluster-3.json onos3:/root/onos/config/cluster.json +docker restart onos1 +docker restart onos2 +docker restart onos3 +``` \ No newline at end of file From 919cc2af7ee5975626160d5f06b381f6c922c51d Mon Sep 17 00:00:00 2001 From: J980419xq <1908393204@qq.com> Date: Thu, 21 Jul 2022 19:05:20 +0800 Subject: [PATCH 37/44] onos cluster --- deploy_onos.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deploy_onos.md b/deploy_onos.md index 85208cd0..d25b3fa8 100644 --- a/deploy_onos.md +++ b/deploy_onos.md @@ -64,9 +64,9 @@ docker restart atomix-3 ### Step5:create onos container ```bash -docker run -t -d -p 6653:6653 --name onos1 onosproject/onos -docker run -t -d -p 6654:6653 --name onos2 onosproject/onos -docker run -t -d -p 6655:6653 --name onos3 onosproject/onos +docker run -t -d -p 6653:6653 -e ONOS_APPS="drivers,openflow-base,netcfghostprovider,openflow,proxyarp,lldpprovider,fwd,optical-model,hostprovider,gui2" --name onos1 onosproject/onos +docker run -t -d -p 6654:6653 -e ONOS_APPS="drivers,openflow-base,netcfghostprovider,openflow,proxyarp,lldpprovider,fwd,optical-model,hostprovider,gui2" --name onos2 onosproject/onos +docker run -t -d -p 6655:6653 -e ONOS_APPS="drivers,openflow-base,netcfghostprovider,openflow,proxyarp,lldpprovider,fwd,optical-model,hostprovider,gui2" --name onos3 onosproject/onos ``` ### Step6:generate onos config files From 11e9c9fcbc93ef7dca43cac13e2065c6db71ee78 Mon Sep 17 00:00:00 2001 From: J980419xq <1908393204@qq.com> Date: Sun, 18 Sep 2022 19:49:29 +0800 Subject: [PATCH 38/44] openstack --- mininet/bin/dmn | 10 ++++++---- mininet/mininet/assh.py | 1 + mininet/mininet/distrinet.py | 34 +++++++++++++++++++++----------- mininet/mininet/lxc_container.py | 14 +++++++------ 4 files changed, 37 insertions(+), 22 deletions(-) diff --git a/mininet/bin/dmn b/mininet/bin/dmn index cdfc6759..96024ec1 100755 --- a/mininet/bin/dmn +++ b/mininet/bin/dmn @@ -298,8 +298,10 @@ class DistrinetRunner( object ): dest='test', help='|'.join( TESTS.keys() ) ) opts.add_option( '--xterms', '-x', action='store_true', default=False, help='spawn xterms for each node' ) - opts.add_option( '--ipbase', '-i', type='string', default='12.0.0.0/8', + opts.add_option( '--ipbase', '-i', type='string', default='192.168.123.20/24', help='base IP address for hosts' ) + opts.add_option( '--providerIpbase', '-p', type='string', default='172.16.62.20/24', + help='base Provider IP address for hosts' ) opts.add_option( '--mac', action='store_true', default=False, help='automatically set host MACs' ) opts.add_option('--docker',action='store_true', @@ -550,7 +552,7 @@ class DistrinetRunner( object ): if opts.workers: workers = opts.workers.split( ',' ) master = workers[0] - workers=workers[1:] + if opts.workers or opts.provision or opts.placement_file_path: warn( '*** WARNING: Experimental cloud mode!\n' @@ -558,7 +560,7 @@ class DistrinetRunner( object ): host, switch, link = LxcNode, LxcOVSSwitch, CloudLink ## - adminIpBase='192.168.100.1/8' + adminIpBase='192.168.0.1/24' waitConnected=False build=False if not opts.placement_file_path: @@ -616,7 +618,7 @@ class DistrinetRunner( object ): switch=switch, host=host, controller=controller, link=link, - ipBase=opts.ipbase, inNamespace=opts.innamespace, + ipBase=opts.ipbase,providerIpBase=opts.providerIpbase, inNamespace=opts.innamespace, xterms=opts.xterms, autoSetMacs=opts.mac, autoSetDocker=opts.docker, autoStaticArp=opts.arp, autoPinCpus=opts.pin, diff --git a/mininet/mininet/assh.py b/mininet/mininet/assh.py index 67e7c3a6..955703de 100644 --- a/mininet/mininet/assh.py +++ b/mininet/mininet/assh.py @@ -136,6 +136,7 @@ async def _connect(self, host, port): try: async with connect(host=host, port=port) as conn: self.conn = conn + info ("connect for {}@{} via {}:{}: \n".format(self.username, self.host, self.bastion, port)) while self.run: await asyncio.sleep(1) except Exception as e: diff --git a/mininet/mininet/distrinet.py b/mininet/mininet/distrinet.py index e186097d..3b854c0a 100755 --- a/mininet/mininet/distrinet.py +++ b/mininet/mininet/distrinet.py @@ -139,7 +139,7 @@ def __init__( self, topo=None, switch=LxcSwitch, host=LxcNode, controller=LxcRemoteController, link=CloudLink, intf=TCIntf, mapper=None, build=True, xterms=False, cleanup=False, ipBase='10.0.0.0/8', - adminIpBase='192.168.0.1/8', + adminIpBase='192.168.0.1/8',providerIpBase='172.16.62.1/8', autoSetMacs=False, autoSetDocker=False,autoPinCpus=False, listenPort=None, waitConnected=False, waitConnectionTimeout=5, jump=None, user="root", client_keys=None, master=None, pub_id=None, @@ -178,6 +178,11 @@ def __init__( self, topo=None, switch=LxcSwitch, host=LxcNode, # Start for address allocation self.nextIP = hostIP if hostIP > 0 else 1 + self.providerIpBase = providerIpBase + self.providerIpBaseNum, self.providerPrefixLen = netParse( self.providerIpBase ) + providerIP = ( 0xffffffff >> self.providerPrefixLen ) & self.providerIpBaseNum + # Start for address allocation + self.providerNextIP = providerIP if providerIP > 0 else 1 self.adminIpBase = adminIpBase self.adminIpBaseNum, self.adminPrefixLen = netParse( self.adminIpBase ) @@ -221,11 +226,11 @@ def runforever(loop): self.client_keys = client_keys self.masterhost = master - _info ("Connecting to master node\n") + info ("Connecting to master node\n") self.masterSsh = ASsh(loop=self.loop, host=self.masterhost, username=self.user, bastion=self.jump, client_keys=self.client_keys) self.masterSsh.connect() self.masterSsh.waitConnected() - _info ("connected to master node\n") + info ("connected to master node\n") self.connectedToAdminNetwork=set() @@ -461,7 +466,8 @@ def buildFromTopo( self, topo=None ): _ip = "{}/{}".format(ipAdd(self.adminNextIP, ipBaseNum=self.adminIpBaseNum, prefixLen=self.adminPrefixLen), self.adminPrefixLen) self.adminNextIP += 1 self.host.createMasterAdminNetwork(self.masterSsh, brname="admin-br", ip=_ip) - _info (" admin network created on {}\n".format(self.masterhost)) + self.connectedToAdminNetwork.add(self.masterhost) + info (" admin network created on {}\n".format(self.masterhost)) assert (isinstance(self.controllers, list)) @@ -489,6 +495,7 @@ def buildFromTopo( self, topo=None ): ''' _ip = "{}/{}".format(ipAdd( self.adminNextIP, ipBaseNum=self.adminIpBaseNum, prefixLen=self.adminPrefixLen),self.adminPrefixLen) self.adminNextIP += 1''' # __ip= newAdminIp(admin_ip) + self.addHost( name=hostName, loop=self.loop, master=self.masterSsh, @@ -529,7 +536,10 @@ def buildFromTopo( self, topo=None ): count = 0 for node in nodes: _info ("createContainer {} ".format( node.name)) - node.createContainer(autoSetDocker=self.autoSetDocker) + _ip = "{}/{}".format(ipAdd( self.providerNextIP, ipBaseNum=self.providerIpBaseNum, prefixLen=self.providerPrefixLen),self.providerPrefixLen) + self.providerNextIP += 1 + _info("providerip: {}".format(_ip)) + node.createContainer(autoSetDocker=self.autoSetDocker,providerIP=_ip) count += 1 if count > 100: output("100 nodes created...\n") @@ -539,7 +549,7 @@ def buildFromTopo( self, topo=None ): for node in nodes: node.waitCreated() _info ("createdContainer {} ".format(node.name)) - _info ("nodes created\n") + info ("nodes created\n") cmds = [] for node in nodes: @@ -581,15 +591,15 @@ def buildFromTopo( self, topo=None ): node.targetSshWaitOutput() for node in nodes: - _info ("connecting {} ".format( node.name)) + info ("connecting {} ".format( node.name)) node.connect() for node in nodes: node.waitConnected() - _info ("connected {} ".format( node.name)) + info ("connected {} ".format( node.name)) count=0 for node in nodes: - _info ("startshell {} ".format( node.name) ) + info ("startshell {} ".format( node.name) ) node.asyncStartShell() count+=1 if count>100: @@ -597,17 +607,17 @@ def buildFromTopo( self, topo=None ): count=0 for node in nodes: node.waitStarted() - _info ("startedshell {}".format( node.name)) + info ("startedshell {}".format( node.name)) count=0 for node in nodes: - _info ("finalize {}".format( node.name)) + info ("finalize {}".format( node.name)) node.finalizeStartShell() count+=1 if count>100: sleep(10) count=0 - _info ("\n") + info ("\n") info( '\n*** Adding links:\n' ) for srcName, dstName, params in topo.links( diff --git a/mininet/mininet/lxc_container.py b/mininet/mininet/lxc_container.py index 9aaf266f..3f1fa9a4 100644 --- a/mininet/mininet/lxc_container.py +++ b/mininet/mininet/lxc_container.py @@ -83,7 +83,7 @@ class LxcNode (Node): adminNetworkCreated = False connectedToAdminNetwork = {} - def __init__(self, name, loop, + def __init__(self, name, loop, master, target=None, port=22, username=None, pub_id=None, bastion=None, bastion_port=22, client_keys=None, @@ -152,7 +152,6 @@ def _preInit(self, self.username = username self.pub_id = pub_id self.client_keys = client_keys - # ssh bastion information self.bastion = bastion self.bastion_port = bastion_port @@ -202,8 +201,9 @@ def configureContainer(self,admin_ip, adminbr="admin-br", wait=True,autoSetDocke admin_ip, prefix = admin_ip.split("/") self.ssh = ASsh(loop=self.loop, host=admin_ip, username=self.username, bastion=self.bastion, client_keys=self.client_keys) if autoSetDocker: + cmds.append("docker exec {} mkdir /root/.ssh".format(self.name)) cmds.append("docker exec {} bash -c 'echo \"{}\" >> /root/.ssh/authorized_keys'".format(self.name, self.pub_id)) - #cmds.append("docker exec {} service ssh start".format(self.name)) + cmds.append("docker exec {} service ssh start".format(self.name)) cmds.append("docker exec {} ifconfig admin {}".format(self.name,self.admin_ip)) # configure the container to have else: @@ -341,16 +341,18 @@ def connectTarget(self): def waitConnectedTarget(self): self.targetSsh.waitConnected() - def createContainer(self,autoSetDocker=False, **params): + def createContainer(self,autoSetDocker=False,providerIP=None, **params): ################################################################################ time.sleep(1.0) info ("create container ({} {} {}) ".format(self.image, self.cpu, self.memory)) cmds = [] + providerIP, prefix = providerIP.split("/") # initialise the container if autoSetDocker: if self.image=="ubuntu": - cmd = "docker create -v /root/alcor-control-agent/:/mnt/host/code -it --privileged --cap-add=NET_ADMIN --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --name {} --net=none {} ".format(self.name, self.image) + ##--privileged=true --init --cap-add=NET_ADMIN --cap-add=SYS_MODULE --cap-add=SYS_NICE jiawei96liu/cnimage:v3 bash + cmd = "docker create -it --privileged --cap-add=NET_ADMIN --cap-add=SYS_MODULE --cap-add=SYS_NICE --init --net network62 --ip {} --name {} -h {} {} ".format(providerIP, self.name, self.name, self.image) else: - cmd="docker create -it --privileged --cap-add=NET_ADMIN --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --name {} --net=none {} ".format(self.name, self.image) + cmd="docker create -it --privileged --cap-add=NET_ADMIN --cap-add=SYS_MODULE --cap-add=SYS_NICE --net=none --name {} -h {} {} ".format(self.name, self.name, self.image) else: cmd = "lxc init {} {} < /dev/null ".format(self.image, self.name) info("{}\n".format(cmd)) From 846bdea8a37f16e6ddd7364bba90b562e47ac62b Mon Sep 17 00:00:00 2001 From: J980419xq <1908393204@qq.com> Date: Tue, 27 Sep 2022 19:00:53 +0800 Subject: [PATCH 39/44] 2022/9/27 --- mininet/bin/dmn | 6 +- mininet/custom/fat-tree.py | 2 +- mininet/mininet/lxc_container.py | 4 +- openflow/.gitignore | 44 + openflow/COPYING | 1054 +++++ openflow/ChangeLog | 202 + openflow/INSTALL | 513 +++ openflow/Makefile.am | 68 + openflow/README | 110 + openflow/README.hwtables | 39 + openflow/README.kernel | 18 + openflow/acinclude.m4 | 309 ++ openflow/boot.sh | 14 + openflow/configure.ac | 94 + openflow/controller/.dirstamp | 0 openflow/controller/.gitignore | 4 + openflow/controller/automake.mk | 8 + openflow/controller/controller.8.in | 150 + openflow/controller/controller.c | 336 ++ openflow/datapath/.gitignore | 7 + openflow/datapath/Makefile.am | 27 + openflow/datapath/Modules.mk | 42 + openflow/datapath/chain.c | 270 ++ openflow/datapath/chain.h | 43 + openflow/datapath/compat.h | 12 + openflow/datapath/crc32.c | 45 + openflow/datapath/crc32.h | 22 + openflow/datapath/datapath.c | 2137 ++++++++++ openflow/datapath/datapath.h | 114 + openflow/datapath/dp_act.c | 543 +++ openflow/datapath/dp_act.h | 15 + openflow/datapath/dp_dev.c | 252 ++ openflow/datapath/dp_dev.h | 17 + openflow/datapath/dp_notify.c | 43 + openflow/datapath/flow.c | 504 +++ openflow/datapath/flow.h | 199 + openflow/datapath/forward.c | 642 +++ openflow/datapath/forward.h | 38 + openflow/datapath/hwtable_dummy/Modules.mk | 7 + .../datapath/hwtable_dummy/hwtable_dummy.c | 320 ++ openflow/datapath/hwtable_nf2/Modules.mk | 19 + openflow/datapath/hwtable_nf2/README | 78 + openflow/datapath/hwtable_nf2/nf2.h | 424 ++ openflow/datapath/hwtable_nf2/nf2_flowtable.c | 452 +++ openflow/datapath/hwtable_nf2/nf2_flowtable.h | 63 + openflow/datapath/hwtable_nf2/nf2_hwapi.h | 43 + openflow/datapath/hwtable_nf2/nf2_lib.c | 918 +++++ openflow/datapath/hwtable_nf2/nf2_lib.h | 59 + openflow/datapath/hwtable_nf2/nf2_openflow.c | 847 ++++ openflow/datapath/hwtable_nf2/nf2_openflow.h | 169 + openflow/datapath/hwtable_nf2/nf2_procfs.c | 240 ++ openflow/datapath/hwtable_nf2/nf2_procfs.h | 39 + openflow/datapath/hwtable_nf2/nf2_reg.h | 767 ++++ .../datapath/hwtable_nf2/openflow_switch.bit | Bin 0 -> 2377746 bytes openflow/datapath/linux-2.6/.gitignore | 30 + openflow/datapath/linux-2.6/Kbuild.in | 35 + openflow/datapath/linux-2.6/Makefile.in | 9 + openflow/datapath/linux-2.6/Makefile.main.in | 85 + openflow/datapath/linux-2.6/Modules.mk | 32 + .../datapath/linux-2.6/compat-2.6/compat26.h | 31 + .../linux-2.6/compat-2.6/genetlink-brcompat.c | 20 + .../linux-2.6/compat-2.6/genetlink-openflow.c | 22 + .../compat-2.6/include/asm-generic/bug.h | 20 + .../linux-2.6/compat-2.6/include/linux/dmi.h | 114 + .../linux-2.6/compat-2.6/include/linux/icmp.h | 13 + .../compat-2.6/include/linux/if_arp.h | 16 + .../linux-2.6/compat-2.6/include/linux/ip.h | 18 + .../linux-2.6/compat-2.6/include/linux/ipv6.h | 13 + .../compat-2.6/include/linux/jiffies.h | 26 + .../compat-2.6/include/linux/lockdep.h | 450 +++ .../compat-2.6/include/linux/mutex.h | 59 + .../compat-2.6/include/linux/netdevice.h | 10 + .../include/linux/netfilter_bridge.h | 24 + .../compat-2.6/include/linux/netfilter_ipv4.h | 19 + .../compat-2.6/include/linux/netlink.h | 24 + .../compat-2.6/include/linux/random.h | 17 + .../compat-2.6/include/linux/rculist.h | 12 + .../compat-2.6/include/linux/skbuff.h | 137 + .../linux-2.6/compat-2.6/include/linux/tcp.h | 18 + .../compat-2.6/include/linux/timer.h | 96 + .../compat-2.6/include/linux/types.h | 14 + .../linux-2.6/compat-2.6/include/linux/udp.h | 13 + .../compat-2.6/include/linux/workqueue.h | 42 + .../compat-2.6/include/net/checksum.h | 16 + .../compat-2.6/include/net/genetlink.h | 123 + .../compat-2.6/include/net/netlink.h | 22 + .../datapath/linux-2.6/compat-2.6/random32.c | 146 + openflow/datapath/linux-2.6/compat-2.6/veth.c | 537 +++ .../config/config-linux-2.6.23-rc9-kvm | 1408 +++++++ openflow/datapath/openflow-ext.c | 83 + openflow/datapath/openflow-ext.h | 38 + openflow/datapath/private-msg.c | 137 + openflow/datapath/private-msg.h | 38 + openflow/datapath/table-hash.c | 489 +++ openflow/datapath/table-linear.c | 233 ++ openflow/datapath/table.h | 119 + openflow/debian/.gitignore | 38 + openflow/debian/changelog | 23 + openflow/debian/commands/reconfigure | 128 + openflow/debian/commands/update | 4 + openflow/debian/compat | 1 + openflow/debian/control.in | 93 + openflow/debian/control.modules.in | 19 + openflow/debian/copyright | 38 + openflow/debian/corekeeper.cron.daily | 5 + openflow/debian/corekeeper.init | 63 + openflow/debian/dirs | 2 + openflow/debian/ofp-switch-setup | 615 +++ openflow/debian/ofp-switch-setup.8 | 41 + openflow/debian/openflow-common.dirs | 1 + openflow/debian/openflow-common.install | 3 + openflow/debian/openflow-common.manpages | 2 + .../debian/openflow-controller.README.Debian | 10 + openflow/debian/openflow-controller.default | 33 + openflow/debian/openflow-controller.dirs | 1 + openflow/debian/openflow-controller.init | 269 ++ openflow/debian/openflow-controller.install | 1 + openflow/debian/openflow-controller.manpages | 1 + openflow/debian/openflow-controller.postinst | 52 + ...atapath-module-_KVERS_.postinst.modules.in | 25 + .../openflow-datapath-source.README.Debian | 31 + .../debian/openflow-datapath-source.copyright | 16 + openflow/debian/openflow-datapath-source.dirs | 1 + .../debian/openflow-datapath-source.install | 6 + openflow/debian/openflow-pki-server.apache2 | 1 + openflow/debian/openflow-pki-server.dirs | 1 + openflow/debian/openflow-pki-server.install | 1 + openflow/debian/openflow-pki-server.postinst | 44 + openflow/debian/openflow-pki.postinst | 41 + openflow/debian/openflow-switch-config.dirs | 1 + .../debian/openflow-switch-config.install | 1 + .../debian/openflow-switch-config.manpages | 1 + .../debian/openflow-switch-config.overrides | 1 + .../debian/openflow-switch-config.templates | 228 ++ openflow/debian/openflow-switch.README.Debian | 18 + openflow/debian/openflow-switch.dirs | 2 + openflow/debian/openflow-switch.init | 437 ++ openflow/debian/openflow-switch.install | 6 + openflow/debian/openflow-switch.logrotate | 11 + openflow/debian/openflow-switch.manpages | 4 + openflow/debian/openflow-switch.postinst | 51 + openflow/debian/openflow-switch.postrm | 43 + openflow/debian/openflow-switch.template | 169 + openflow/debian/po/POTFILES.in | 1 + openflow/debian/rules | 163 + openflow/doc/of-spec/.gitignore | 8 + openflow/doc/of-spec/Makefile | 40 + openflow/doc/of-spec/README | 3 + openflow/doc/of-spec/appendix.tex | 429 ++ openflow/doc/of-spec/credits.tex | 22 + .../doc/of-spec/figure_flow_table_secchan.png | Bin 0 -> 67886 bytes .../of-spec/header_parsing_flowchart.graffle | 3536 +++++++++++++++++ openflow/doc/of-spec/make_latex_input.pl | 117 + openflow/doc/of-spec/openflow-spec-v1.0.0.tex | 418 ++ .../doc/of-spec/packet_flow_flowchart.graffle | 1887 +++++++++ openflow/hw-lib/automake.mk | 28 + openflow/hw-lib/nf2/README | 56 + openflow/hw-lib/nf2/debug.h | 105 + openflow/hw-lib/nf2/hw_flow.c | 514 +++ openflow/hw-lib/nf2/hw_flow.h | 56 + openflow/hw-lib/nf2/nf2.h | 452 +++ openflow/hw-lib/nf2/nf2_drv.c | 847 ++++ openflow/hw-lib/nf2/nf2_drv.h | 150 + openflow/hw-lib/nf2/nf2_lib.c | 1049 +++++ openflow/hw-lib/nf2/nf2_lib.h | 59 + openflow/hw-lib/nf2/nf2util.c | 400 ++ openflow/hw-lib/nf2/nf2util.h | 46 + .../hw-lib/nf2/reg_defines_openflow_switch.h | 767 ++++ openflow/hw-lib/skeleton/debug.h | 106 + openflow/hw-lib/skeleton/hw_drv.c | 309 ++ openflow/hw-lib/skeleton/hw_drv.h | 97 + openflow/hw-lib/skeleton/hw_flow.c | 708 ++++ openflow/hw-lib/skeleton/hw_flow.h | 111 + openflow/hw-lib/skeleton/of_hw_platform.h | 38 + openflow/hw-lib/skeleton/os.h | 29 + openflow/hw-lib/skeleton/port.c | 497 +++ openflow/hw-lib/skeleton/port.h | 45 + openflow/hw-lib/skeleton/sample_plat.c | 82 + openflow/hw-lib/skeleton/sample_plat.h | 61 + openflow/hw-lib/skeleton/txrx.c | 129 + openflow/hw-lib/skeleton/txrx.h | 12 + openflow/include/.gitignore | 2 + openflow/include/automake.mk | 1 + openflow/include/openflow/automake.mk | 5 + openflow/include/openflow/nicira-ext.h | 195 + openflow/include/openflow/of_hw_api.h | 313 ++ openflow/include/openflow/openflow-ext.h | 149 + openflow/include/openflow/openflow-netlink.h | 69 + openflow/include/openflow/openflow.h | 970 +++++ openflow/include/openflow/private-ext.h | 68 + openflow/m4/libopenflow.m4 | 168 + openflow/m4/nx-build.m4 | 71 + openflow/regress/CREDITS | 22 + openflow/regress/INSTALL | 264 ++ openflow/regress/LICENSE | 30 + openflow/regress/README | 329 ++ openflow/regress/bin/eth.map | 8 + openflow/regress/bin/nf2.map | 8 + openflow/regress/bin/of_hp_eth.map | 8 + openflow/regress/bin/of_hp_setup.pl | 86 + openflow/regress/bin/of_hp_teardown.pl | 50 + openflow/regress/bin/of_hp_test.pl | 62 + openflow/regress/bin/of_hp_test_6600.pl | 62 + openflow/regress/bin/of_kmod_setup.pl | 22 + openflow/regress/bin/of_kmod_teardown.pl | 20 + openflow/regress/bin/of_kmod_test.pl | 27 + openflow/regress/bin/of_kmod_veth_setup.pl | 26 + openflow/regress/bin/of_kmod_veth_teardown.pl | 24 + openflow/regress/bin/of_kmod_veth_test.pl | 27 + openflow/regress/bin/of_nf2_setup.pl | 26 + openflow/regress/bin/of_nf2_teardown.pl | 20 + openflow/regress/bin/of_nf2_test.pl | 28 + openflow/regress/bin/of_ovs_eth.map | 8 + openflow/regress/bin/of_ovs_setup.pl | 76 + openflow/regress/bin/of_ovs_teardown.pl | 59 + openflow/regress/bin/of_ovs_test.pl | 54 + openflow/regress/bin/of_ovs_user_setup.pl | 60 + openflow/regress/bin/of_ovs_user_teardown.pl | 34 + openflow/regress/bin/of_ovs_user_test.pl | 50 + openflow/regress/bin/of_ovs_user_veth_test.pl | 47 + openflow/regress/bin/of_ovs_veth_test.pl | 47 + openflow/regress/bin/of_user_setup.pl | 22 + openflow/regress/bin/of_user_teardown.pl | 20 + openflow/regress/bin/of_user_test.pl | 27 + openflow/regress/bin/of_user_veth_setup.pl | 26 + openflow/regress/bin/of_user_veth_teardown.pl | 24 + openflow/regress/bin/of_user_veth_test.pl | 27 + openflow/regress/bin/veth.map | 8 + openflow/regress/bin/veth_setup.pl | 10 + openflow/regress/bin/veth_teardown.pl | 4 + .../projects/black_box/regress/common/setup | 47 + .../black_box/regress/common/teardown | 47 + .../regress/test_add_flow_latency/run.pl | 47 + .../black_box/regress/test_barrier/run.pl | 52 + .../regress/test_cookie_flow_expired/run.pl | 39 + .../regress/test_cookie_flow_stats/run.pl | 151 + .../black_box/regress/test_delete/run.pl | 172 + .../regress/test_delete_send_flow_exp/run.pl | 104 + .../regress/test_delete_strict/run.pl | 175 + .../black_box/regress/test_drop_exact/run.pl | 54 + .../regress/test_failover_close/run.pl | 68 + .../regress/test_failover_startup/run.pl | 53 + .../test_failover_stop_responding/run.pl | 65 + .../regress/test_flow_expired/run.pl | 34 + .../test_flow_expired_idle_timeout/run.pl | 34 + .../test_flow_expired_precision/run.pl | 66 + .../test_flow_expired_send_flow_exp/run.pl | 44 + .../regress/test_flow_mod_check/run.pl | 83 + .../test_flow_mod_latency/run-port3.pl | 136 + .../regress/test_flow_mod_latency/run.pl | 129 + .../black_box/regress/test_flow_stats/run.pl | 145 + .../regress/test_flow_stats_precision/run.pl | 191 + .../test_forward_after_expiration/run.pl | 111 + .../regress/test_forward_any_port/run.pl | 20 + .../test_forward_bandwidth_fixed/run.pl | 83 + .../test_forward_bandwidth_random/run.pl | 84 + .../test_forward_broadcast_exact_port/run.pl | 64 + .../regress/test_forward_exact_all/run.pl | 30 + .../regress/test_forward_exact_arp_all/run.pl | 19 + .../test_forward_exact_arp_controller/run.pl | 19 + .../test_forward_exact_arp_fool/run.pl | 19 + .../test_forward_exact_arp_port/run.pl | 19 + .../test_forward_exact_controller/run.pl | 32 + .../test_forward_exact_icmp_all/run.pl | 19 + .../test_forward_exact_icmp_controller/run.pl | 19 + .../test_forward_exact_icmp_fool/run.pl | 19 + .../test_forward_exact_icmp_port/run.pl | 19 + .../test_forward_exact_modify_action/run.pl | 42 + .../regress/test_forward_exact_port/run.pl | 27 + .../run.pl | 86 + .../regress/test_forward_wildcard_all/run.pl | 172 + .../test_forward_wildcard_arp_all/run.pl | 20 + .../run.pl | 19 + .../test_forward_wildcard_arp_fool/run.pl | 20 + .../test_forward_wildcard_arp_port/run.pl | 20 + .../test_forward_wildcard_controller/run.pl | 30 + .../test_forward_wildcard_icmp_all/run.pl | 20 + .../run.pl | 19 + .../test_forward_wildcard_icmp_fool/run.pl | 20 + .../test_forward_wildcard_icmp_port/run.pl | 20 + .../run.pl | 35 + .../regress/test_forward_wildcard_port/run.pl | 97 + .../black_box/regress/test_hello/run.pl | 16 + .../black_box/regress/test_ip_offset/run.pl | 85 + .../black_box/regress/test_ip_options/run.pl | 76 + .../regress/test_ip_protocol/case-c.pl | 150 + .../regress/test_ip_protocol/case-d.pl | 152 + .../regress/test_ip_protocol/case-e.pl | 152 + .../regress/test_ip_protocol/case-tcp.pl | 153 + .../regress/test_ip_protocol/case-udp.pl | 67 + .../black_box/regress/test_llc/run.pl | 128 + .../regress/test_miss_send_length/run.pl | 79 + .../black_box/regress/test_packet_in/run.pl | 45 + .../black_box/regress/test_packet_out/run.pl | 53 + .../black_box/regress/test_port_stats/run.pl | 132 + .../regress/test_queue_config/run.pl | 52 + .../regress/test_queue_forward/run.pl | 19 + .../black_box/regress/test_queue_stats/run.pl | 116 + .../test_receive_bandwidth_fixed/run.pl | 89 + .../regress/test_send_bandwidth_fixed/run.pl | 140 + .../regress/test_send_bandwidth_random/run.pl | 141 + .../regress/test_set_dl_nw_flip/run.pl | 143 + .../regress/test_set_n_match_nw_tos/run.pl | 95 + .../black_box/regress/test_set_nw_dst/run.pl | 95 + .../black_box/regress/test_stats_desc/run.pl | 71 + .../regress/test_switch_config/run.pl | 40 + .../black_box/regress/test_tcp_options/run.pl | 170 + .../projects/black_box/regress/tests.txt | 103 + .../regress/common/setup | 49 + .../regress/common/teardown | 47 + .../regress/test_emergency_table/run.pl | 107 + .../controller_disconnect/regress/tests.txt | 2 + .../learning_switch/regress/common/setup | 46 + .../learning_switch/regress/common/teardown | 46 + .../regress/test_broadcast/run.pl | 50 + .../regress/test_forward_bandwidth/run.pl | 62 + .../regress/test_forward_latency/run.pl | 69 + .../regress/test_hub_connected/run.pl | 64 + .../regress/test_unicast_known/run.pl | 71 + .../regress/test_unicast_move/run.pl | 79 + .../test_unicast_multiple_hosts/run.pl | 93 + .../regress/test_unicast_self/run.pl | 61 + .../regress/test_unicast_unknown/run.pl | 32 + .../learning_switch/regress/tests.txt | 12 + openflow/regress/projects/regress.txt | 3 + openflow/regress/scripts/copy_NF2_code.sh | 5 + openflow/regress/scripts/env_vars | 12 + openflow/regress/scripts/install_deps.pl | 264 ++ .../regress/scripts/install_perlmods_apt.pl | 32 + openflow/regress/scripts/make_release.pl | 155 + openflow/secchan/.dirstamp | 0 openflow/secchan/.gitignore | 7 + openflow/secchan/automake.mk | 32 + openflow/secchan/commands/automake.mk | 3 + openflow/secchan/commands/reboot | 3 + openflow/secchan/discovery.c | 251 ++ openflow/secchan/discovery.h | 50 + openflow/secchan/emerg-flow.c | 144 + openflow/secchan/emerg-flow.h | 44 + openflow/secchan/fail-open.c | 159 + openflow/secchan/fail-open.h | 46 + openflow/secchan/failover.c | 144 + openflow/secchan/failover.h | 44 + openflow/secchan/in-band.c | 331 ++ openflow/secchan/in-band.h | 47 + openflow/secchan/ofprotocol.8.in | 462 +++ openflow/secchan/port-watcher.c | 620 +++ openflow/secchan/port-watcher.h | 77 + openflow/secchan/protocol-stat.c | 204 + openflow/secchan/protocol-stat.h | 44 + openflow/secchan/ratelimit.c | 263 ++ openflow/secchan/ratelimit.h | 45 + openflow/secchan/secchan.c | 882 ++++ openflow/secchan/secchan.h | 135 + openflow/secchan/status.c | 230 ++ openflow/secchan/status.h | 56 + openflow/secchan/stp-secchan.c | 293 ++ openflow/secchan/stp-secchan.h | 48 + openflow/soexpand.pl | 26 + openflow/tests/.dirstamp | 0 openflow/tests/.gitignore | 6 + openflow/tests/automake.mk | 46 + openflow/tests/flowgen.pl | 224 ++ openflow/tests/test-dhcp-client.c | 206 + openflow/tests/test-flows | Bin 0 -> 286976 bytes openflow/tests/test-flows.c | 76 + openflow/tests/test-flows.sh | 9 + openflow/tests/test-hmap | Bin 0 -> 68296 bytes openflow/tests/test-hmap.c | 282 ++ openflow/tests/test-list.c | 159 + openflow/tests/test-stp-ieee802.1d-1998 | 12 + .../tests/test-stp-ieee802.1d-2004-fig17.4 | 31 + .../tests/test-stp-ieee802.1d-2004-fig17.6 | 14 + .../tests/test-stp-ieee802.1d-2004-fig17.7 | 17 + openflow/tests/test-stp-iol-io-1.1 | 25 + openflow/tests/test-stp-iol-io-1.2 | 14 + openflow/tests/test-stp-iol-io-1.4 | 13 + openflow/tests/test-stp-iol-io-1.5 | 40 + openflow/tests/test-stp-iol-op-1.1 | 7 + openflow/tests/test-stp-iol-op-1.4 | 8 + openflow/tests/test-stp-iol-op-3.1 | 11 + openflow/tests/test-stp-iol-op-3.3 | 11 + openflow/tests/test-stp-iol-op-3.4 | 11 + openflow/tests/test-stp.c | 665 ++++ openflow/tests/test-stp.sh | 7 + openflow/tests/test-type-props.c | 41 + openflow/third-party/.gitignore | 2 + openflow/third-party/README | 35 + openflow/third-party/automake.mk | 3 + openflow/third-party/ofp-tcpdump.patch | 119 + openflow/udatapath/.dirstamp | 0 openflow/udatapath/.gitignore | 4 + openflow/udatapath/automake.mk | 75 + openflow/udatapath/chain.c | 261 ++ openflow/udatapath/chain.h | 74 + openflow/udatapath/crc32.c | 68 + openflow/udatapath/crc32.h | 50 + openflow/udatapath/datapath.c | 2375 +++++++++++ openflow/udatapath/datapath.h | 167 + openflow/udatapath/dp_act.c | 531 +++ openflow/udatapath/dp_act.h | 49 + openflow/udatapath/of_ext_msg.c | 267 ++ openflow/udatapath/of_ext_msg.h | 43 + openflow/udatapath/ofdatapath.8.in | 148 + openflow/udatapath/private-msg.c | 140 + openflow/udatapath/private-msg.h | 42 + openflow/udatapath/switch-flow.c | 341 ++ openflow/udatapath/switch-flow.h | 100 + openflow/udatapath/table-hash.c | 469 +++ openflow/udatapath/table-linear.c | 262 ++ openflow/udatapath/table.h | 150 + openflow/udatapath/udatapath.c | 345 ++ openflow/utilities/.dirstamp | 0 openflow/utilities/.gitignore | 13 + openflow/utilities/automake.mk | 45 + openflow/utilities/dpctl.8.in | 582 +++ openflow/utilities/dpctl.c | 1772 +++++++++ openflow/utilities/ofp-discover.8.in | 119 + openflow/utilities/ofp-discover.c | 420 ++ openflow/utilities/ofp-kill.8.in | 61 + openflow/utilities/ofp-kill.c | 228 ++ openflow/utilities/ofp-parse-leaks | 285 ++ openflow/utilities/ofp-parse-leaks.in | 285 ++ openflow/utilities/ofp-pki-cgi.in | 41 + openflow/utilities/ofp-pki.8.in | 325 ++ openflow/utilities/ofp-pki.in | 582 +++ openflow/utilities/vlogconf.8.in | 183 + openflow/utilities/vlogconf.c | 235 ++ .../utilities/wireshark_dissectors/Makefile | 32 + .../utilities/wireshark_dissectors/README | 37 + .../wireshark_dissectors/openflow/.gitignore | 1 + .../wireshark_dissectors/openflow/Makefile | 79 + .../wireshark_dissectors/openflow/Makefile.am | 110 + .../openflow/Makefile.common | 13 + .../openflow/build_distribution_tarball.sh | 63 + .../openflow/moduleinfo.h | 15 + .../openflow/packet-openflow.c | 3426 ++++++++++++++++ .../wireshark_dissectors/openflow/plugin.c | 28 + .../wireshark-1.0.0-includes/airpcap.h | 907 +++++ .../wireshark-1.0.0-includes/airpcap_loader.h | 560 +++ .../wireshark-1.0.0-includes/alert_box.h | 70 + .../capture-pcap-util-int.h | 56 + .../capture-pcap-util.h | 131 + .../wireshark-1.0.0-includes/capture-wpcap.h | 34 + .../wireshark-1.0.0-includes/capture.h | 118 + .../wireshark-1.0.0-includes/capture_errs.h | 34 + .../wireshark-1.0.0-includes/capture_info.h | 76 + .../wireshark-1.0.0-includes/capture_opts.h | 194 + .../capture_stop_conditions.h | 29 + .../wireshark-1.0.0-includes/capture_sync.h | 87 + .../capture_ui_utils.h | 89 + .../capture_wpcap_packet.h | 47 + .../wireshark-1.0.0-includes/cfile.h | 91 + .../wireshark-1.0.0-includes/clopts_common.h | 40 + .../wireshark-1.0.0-includes/cmdarg_err.h | 56 + .../wireshark-1.0.0-includes/color.h | 55 + .../wireshark-1.0.0-includes/color_filters.h | 196 + .../wireshark-1.0.0-includes/conditions.h | 134 + .../wireshark-1.0.0-includes/config.h | 322 ++ .../wireshark-1.0.0-includes/config.h.in | 321 ++ .../wireshark-1.0.0-includes/config.h.win32 | 274 ++ .../disabled_protos.h | 61 + .../epan/addr_and_mask.h | 53 + .../epan/addr_resolv.h | 198 + .../wireshark-1.0.0-includes/epan/address.h | 172 + .../wireshark-1.0.0-includes/epan/adler32.h | 42 + .../wireshark-1.0.0-includes/epan/afn.h | 71 + .../wireshark-1.0.0-includes/epan/aftypes.h | 47 + .../epan/arcnet_pids.h | 70 + .../wireshark-1.0.0-includes/epan/arptypes.h | 75 + .../wireshark-1.0.0-includes/epan/asm_utils.h | 38 + .../wireshark-1.0.0-includes/epan/asn1.h | 207 + .../epan/atalk-utils.h | 63 + .../wireshark-1.0.0-includes/epan/base64.h | 38 + .../wireshark-1.0.0-includes/epan/bitswap.h | 40 + .../epan/bridged_pids.h | 58 + .../epan/camel-persistentdata.h | 127 + .../wireshark-1.0.0-includes/epan/charsets.h | 42 + .../epan/chdlctypes.h | 40 + .../wireshark-1.0.0-includes/epan/circuit.h | 80 + .../wireshark-1.0.0-includes/epan/codecs.h | 43 + .../epan/column-utils.h | 241 ++ .../wireshark-1.0.0-includes/epan/column.h | 56 + .../epan/column_info.h | 134 + .../epan/conversation.h | 109 + .../wireshark-1.0.0-includes/epan/crc10.h | 27 + .../wireshark-1.0.0-includes/epan/crc16.h | 109 + .../wireshark-1.0.0-includes/epan/crc32.h | 94 + .../wireshark-1.0.0-includes/epan/crc6.h | 26 + .../wireshark-1.0.0-includes/epan/crcdrm.h | 7 + .../epan/crypt/airpdcap_debug.h | 106 + .../epan/crypt/airpdcap_int.h | 158 + .../epan/crypt/airpdcap_interop.h | 101 + .../epan/crypt/airpdcap_rijndael.h | 93 + .../epan/crypt/airpdcap_system.h | 356 ++ .../epan/crypt/airpdcap_user.h | 231 ++ .../epan/crypt/airpdcap_ws.h | 43 + .../epan/crypt/crypt-des.h | 26 + .../epan/crypt/crypt-md4.h | 23 + .../epan/crypt/crypt-md5.h | 71 + .../epan/crypt/crypt-rc4.h | 36 + .../epan/crypt/crypt-sha1.h | 45 + .../epan/crypt/wep-wpadefs.h | 115 + .../epan/dfilter/dfilter-int.h | 82 + .../epan/dfilter/dfilter-macro.h | 59 + .../epan/dfilter/dfilter.h | 94 + .../epan/dfilter/dfunctions.h | 56 + .../epan/dfilter/dfvm.h | 108 + .../epan/dfilter/drange.h | 102 + .../epan/dfilter/gencode.h | 10 + .../epan/dfilter/glib-util.h | 4 + .../epan/dfilter/grammar.h | 24 + .../epan/dfilter/scanner_lex.h | 6 + .../epan/dfilter/semcheck.h | 31 + .../epan/dfilter/sttype-function.h | 42 + .../epan/dfilter/sttype-range.h | 45 + .../epan/dfilter/sttype-test.h | 56 + .../epan/dfilter/syntax-tree.h | 136 + .../wireshark-1.0.0-includes/epan/diam_dict.h | 89 + .../epan/diam_dict_lex.h | 6 + .../epan/dissector_filters.h | 60 + .../epan/dissectors/packet-tcp.h | 232 ++ .../wireshark-1.0.0-includes/epan/dtd.h | 62 + .../epan/dtd_grammar.h | 23 + .../wireshark-1.0.0-includes/epan/dtd_parse.h | 37 + .../epan/dtd_parse_lex.h | 6 + .../epan/dtd_preparse_lex.h | 6 + .../wireshark-1.0.0-includes/epan/eap.h | 53 + .../wireshark-1.0.0-includes/epan/emem.h | 373 ++ .../wireshark-1.0.0-includes/epan/epan.h | 93 + .../epan/epan_dissect.h | 44 + .../wireshark-1.0.0-includes/epan/etypes.h | 408 ++ .../wireshark-1.0.0-includes/epan/ex-opt.h | 44 + .../wireshark-1.0.0-includes/epan/except.h | 158 + .../epan/exceptions.h | 319 ++ .../wireshark-1.0.0-includes/epan/expert.h | 70 + .../epan/filesystem.h | 248 ++ .../wireshark-1.0.0-includes/epan/follow.h | 58 + .../epan/frame_data.h | 79 + .../epan/frequency-utils.h | 74 + .../epan/ftypes/ftypes-int.h | 61 + .../epan/ftypes/ftypes.h | 367 ++ .../wireshark-1.0.0-includes/epan/funnel.h | 116 + .../epan/g_ascii_strcasecmp.h | 18 + .../epan/g_ascii_strtoull.h | 15 + .../wireshark-1.0.0-includes/epan/garrayfix.h | 38 + .../wireshark-1.0.0-includes/epan/gcp.h | 219 + .../epan/gnuc_format_check.h | 39 + .../wireshark-1.0.0-includes/epan/golay.h | 49 + .../wireshark-1.0.0-includes/epan/greproto.h | 36 + .../epan/guid-utils.h | 63 + .../epan/h225-persistentdata.h | 62 + .../epan/iax2_codec_type.h | 77 + .../wireshark-1.0.0-includes/epan/in_cksum.h | 14 + .../wireshark-1.0.0-includes/epan/inet_aton.h | 34 + .../wireshark-1.0.0-includes/epan/ip_opts.h | 59 + .../wireshark-1.0.0-includes/epan/ipproto.h | 193 + .../wireshark-1.0.0-includes/epan/ipv4.h | 67 + .../epan/ipv6-utils.h | 49 + .../wireshark-1.0.0-includes/epan/lapd_sapi.h | 38 + .../wireshark-1.0.0-includes/epan/llcsaps.h | 63 + .../wireshark-1.0.0-includes/epan/next_tvb.h | 65 + .../wireshark-1.0.0-includes/epan/nlpid.h | 60 + .../wireshark-1.0.0-includes/epan/nstime.h | 92 + .../wireshark-1.0.0-includes/epan/oids.h | 179 + .../wireshark-1.0.0-includes/epan/osi-utils.h | 57 + .../wireshark-1.0.0-includes/epan/oui.h | 74 + .../wireshark-1.0.0-includes/epan/packet.h | 422 ++ .../epan/packet_info.h | 184 + .../wireshark-1.0.0-includes/epan/pint.h | 113 + .../wireshark-1.0.0-includes/epan/plugins.h | 58 + .../wireshark-1.0.0-includes/epan/ppptypes.h | 158 + .../wireshark-1.0.0-includes/epan/prefs-int.h | 111 + .../wireshark-1.0.0-includes/epan/prefs.h | 426 ++ .../epan/privileges.h | 74 + .../wireshark-1.0.0-includes/epan/proto.h | 1655 ++++++++ .../wireshark-1.0.0-includes/epan/ptvcursor.h | 110 + .../epan/radius_dict_lex.h | 6 + .../wireshark-1.0.0-includes/epan/range.h | 73 + .../epan/reassemble.h | 316 ++ .../epan/reedsolomon.h | 86 + .../epan/report_err.h | 61 + .../epan/req_resp_hdrs.h | 43 + .../wireshark-1.0.0-includes/epan/rtp_pt.h | 68 + .../wireshark-1.0.0-includes/epan/sctpppids.h | 50 + .../epan/sigcomp-udvm.h | 49 + .../epan/sigcomp_state_hdlr.h | 49 + .../wireshark-1.0.0-includes/epan/slab.h | 75 + .../wireshark-1.0.0-includes/epan/sminmpec.h | 83 + .../wireshark-1.0.0-includes/epan/sna-utils.h | 41 + .../epan/stat_cmd_args.h | 35 + .../epan/stats_tree.h | 147 + .../epan/stats_tree_priv.h | 202 + .../wireshark-1.0.0-includes/epan/stream.h | 138 + .../wireshark-1.0.0-includes/epan/strutil.h | 243 ++ .../wireshark-1.0.0-includes/epan/t35.h | 35 + .../wireshark-1.0.0-includes/epan/tap-voip.h | 59 + .../wireshark-1.0.0-includes/epan/tap.h | 61 + .../epan/tcap-persistentdata.h | 148 + .../wireshark-1.0.0-includes/epan/tfs.h | 65 + .../wireshark-1.0.0-includes/epan/timestamp.h | 68 + .../wireshark-1.0.0-includes/epan/to_str.h | 94 + .../wireshark-1.0.0-includes/epan/tvbparse.h | 475 +++ .../wireshark-1.0.0-includes/epan/tvbuff.h | 634 +++ .../wireshark-1.0.0-includes/epan/uat-int.h | 92 + .../wireshark-1.0.0-includes/epan/uat.h | 486 +++ .../epan/uat_load_lex.h | 6 + .../epan/unicode-utils.h | 54 + .../epan/value_string.h | 88 + .../epan/ws_strsplit.h | 41 + .../epan/wslua/declare_wslua.h | 59 + .../epan/wslua/wslua.h | 372 ++ .../epan/x264_prt_id.h | 35 + .../wireshark-1.0.0-includes/epan/xdlc.h | 140 + .../wireshark-1.0.0-includes/epan/xmlstub.h | 1123 ++++++ .../wireshark-1.0.0-includes/file.h | 486 +++ .../wireshark-1.0.0-includes/fileset.h | 75 + .../wireshark-1.0.0-includes/filters.h | 87 + .../wireshark-1.0.0-includes/g711.h | 30 + .../wireshark-1.0.0-includes/getopt.h | 129 + .../wireshark-1.0.0-includes/globals.h | 37 + .../wireshark-1.0.0-includes/inet_v6defs.h | 54 + .../wireshark-1.0.0-includes/isprint.h | 46 + .../wireshark-1.0.0-includes/log.h | 42 + .../wireshark-1.0.0-includes/main_window.h | 41 + .../wireshark-1.0.0-includes/menu.h | 64 + .../wireshark-1.0.0-includes/merge.h | 125 + .../wireshark-1.0.0-includes/mkstemp.h | 24 + .../wireshark-1.0.0-includes/packet-range.h | 101 + .../wireshark-1.0.0-includes/pcapio.h | 44 + .../wireshark-1.0.0-includes/print.h | 148 + .../wireshark-1.0.0-includes/progress_dlg.h | 94 + .../proto_hier_stats.h | 51 + .../wireshark-1.0.0-includes/ps.h | 35 + .../wireshark-1.0.0-includes/register.h | 48 + .../wireshark-1.0.0-includes/ringbuffer.h | 53 + .../wireshark-1.0.0-includes/simple_dialog.h | 184 + .../wireshark-1.0.0-includes/stat_menu.h | 64 + .../wireshark-1.0.0-includes/statusbar.h | 56 + .../wireshark-1.0.0-includes/strerror.h | 33 + .../wireshark-1.0.0-includes/strptime.h | 32 + .../wireshark-1.0.0-includes/summary.h | 76 + .../wireshark-1.0.0-includes/svnversion.h | 1 + .../wireshark-1.0.0-includes/sync_pipe.h | 80 + .../wireshark-1.0.0-includes/tap-rtp-common.h | 49 + .../tap_dfilter_dlg.h | 73 + .../wireshark-1.0.0-includes/tempfile.h | 43 + .../wireshark-1.0.0-includes/text2pcap.h | 49 + .../wireshark-1.0.0-includes/timestats.h | 54 + .../tools/make-dissector-reg | 186 + .../tools/make-dissector-reg.py | 238 ++ .../wireshark-1.0.0-includes/ui_util.h | 79 + .../wireshark-1.0.0-includes/util.h | 60 + .../wireshark-1.0.0-includes/version_info.h | 79 + .../wireshark-1.0.0-includes/wiretap/5views.h | 30 + .../wiretap/airopeek9.h | 29 + .../wiretap/ascend-grammar.h | 90 + .../wiretap/ascend-int.h | 54 + .../wiretap/ascend-scanner_lex.h | 6 + .../wireshark-1.0.0-includes/wiretap/ascend.h | 33 + .../wireshark-1.0.0-includes/wiretap/atm.h | 40 + .../wireshark-1.0.0-includes/wiretap/ber.h | 28 + .../wiretap/btsnoop.h | 30 + .../wireshark-1.0.0-includes/wiretap/buffer.h | 58 + .../wiretap/catapult_dct2000.h | 30 + .../wiretap/commview.h | 33 + .../wireshark-1.0.0-includes/wiretap/cosine.h | 32 + .../wireshark-1.0.0-includes/wiretap/csids.h | 29 + .../wiretap/dbs-etherwatch.h | 29 + .../wireshark-1.0.0-includes/wiretap/erf.h | 102 + .../wiretap/etherpeek.h | 29 + .../wireshark-1.0.0-includes/wiretap/eyesdn.h | 29 + .../wiretap/file_util.h | 136 + .../wiretap/file_wrappers.h | 57 + .../wiretap/hcidump.h | 28 + .../wiretap/i4b_trace.h | 92 + .../wiretap/i4btrace.h | 29 + .../wiretap/iptrace.h | 29 + .../wiretap/iseries.h | 28 + .../wireshark-1.0.0-includes/wiretap/k12.h | 28 + .../wiretap/k12text_lex.h | 6 + .../wiretap/lanalyzer.h | 176 + .../wiretap/libpcap.h | 106 + .../wiretap/mpeg-audio.h | 98 + .../wireshark-1.0.0-includes/wiretap/mpeg.h | 32 + .../wireshark-1.0.0-includes/wiretap/netmon.h | 30 + .../wiretap/netscreen.h | 53 + .../wireshark-1.0.0-includes/wiretap/nettl.h | 124 + .../wiretap/network_instruments.h | 127 + .../wiretap/netxray.h | 32 + .../wiretap/ngsniffer.h | 30 + .../wireshark-1.0.0-includes/wiretap/pcapng.h | 30 + .../wiretap/pppdump.h | 28 + .../wireshark-1.0.0-includes/wiretap/radcom.h | 29 + .../wireshark-1.0.0-includes/wiretap/snoop.h | 30 + .../wiretap/toshiba.h | 28 + .../wireshark-1.0.0-includes/wiretap/visual.h | 35 + .../wireshark-1.0.0-includes/wiretap/vms.h | 29 + .../wiretap/wtap-int.h | 482 +++ .../wireshark-1.0.0-includes/wiretap/wtap.h | 944 +++++ requirements.txt | 3 +- 701 files changed, 95066 insertions(+), 9 deletions(-) create mode 100644 openflow/.gitignore create mode 100644 openflow/COPYING create mode 100644 openflow/ChangeLog create mode 100644 openflow/INSTALL create mode 100644 openflow/Makefile.am create mode 100644 openflow/README create mode 100644 openflow/README.hwtables create mode 100644 openflow/README.kernel create mode 100644 openflow/acinclude.m4 create mode 100755 openflow/boot.sh create mode 100644 openflow/configure.ac create mode 100644 openflow/controller/.dirstamp create mode 100644 openflow/controller/.gitignore create mode 100644 openflow/controller/automake.mk create mode 100644 openflow/controller/controller.8.in create mode 100644 openflow/controller/controller.c create mode 100644 openflow/datapath/.gitignore create mode 100644 openflow/datapath/Makefile.am create mode 100644 openflow/datapath/Modules.mk create mode 100644 openflow/datapath/chain.c create mode 100644 openflow/datapath/chain.h create mode 100644 openflow/datapath/compat.h create mode 100644 openflow/datapath/crc32.c create mode 100644 openflow/datapath/crc32.h create mode 100644 openflow/datapath/datapath.c create mode 100644 openflow/datapath/datapath.h create mode 100644 openflow/datapath/dp_act.c create mode 100644 openflow/datapath/dp_act.h create mode 100644 openflow/datapath/dp_dev.c create mode 100644 openflow/datapath/dp_dev.h create mode 100644 openflow/datapath/dp_notify.c create mode 100644 openflow/datapath/flow.c create mode 100644 openflow/datapath/flow.h create mode 100644 openflow/datapath/forward.c create mode 100644 openflow/datapath/forward.h create mode 100644 openflow/datapath/hwtable_dummy/Modules.mk create mode 100644 openflow/datapath/hwtable_dummy/hwtable_dummy.c create mode 100644 openflow/datapath/hwtable_nf2/Modules.mk create mode 100644 openflow/datapath/hwtable_nf2/README create mode 100644 openflow/datapath/hwtable_nf2/nf2.h create mode 100644 openflow/datapath/hwtable_nf2/nf2_flowtable.c create mode 100644 openflow/datapath/hwtable_nf2/nf2_flowtable.h create mode 100644 openflow/datapath/hwtable_nf2/nf2_hwapi.h create mode 100644 openflow/datapath/hwtable_nf2/nf2_lib.c create mode 100644 openflow/datapath/hwtable_nf2/nf2_lib.h create mode 100644 openflow/datapath/hwtable_nf2/nf2_openflow.c create mode 100644 openflow/datapath/hwtable_nf2/nf2_openflow.h create mode 100644 openflow/datapath/hwtable_nf2/nf2_procfs.c create mode 100644 openflow/datapath/hwtable_nf2/nf2_procfs.h create mode 100644 openflow/datapath/hwtable_nf2/nf2_reg.h create mode 100644 openflow/datapath/hwtable_nf2/openflow_switch.bit create mode 100644 openflow/datapath/linux-2.6/.gitignore create mode 100644 openflow/datapath/linux-2.6/Kbuild.in create mode 100644 openflow/datapath/linux-2.6/Makefile.in create mode 100644 openflow/datapath/linux-2.6/Makefile.main.in create mode 100644 openflow/datapath/linux-2.6/Modules.mk create mode 100644 openflow/datapath/linux-2.6/compat-2.6/compat26.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/genetlink-brcompat.c create mode 100644 openflow/datapath/linux-2.6/compat-2.6/genetlink-openflow.c create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/asm-generic/bug.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/dmi.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/icmp.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/if_arp.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/ip.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/ipv6.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/jiffies.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/lockdep.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/mutex.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/netdevice.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/netfilter_bridge.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/netfilter_ipv4.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/netlink.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/random.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/rculist.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/skbuff.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/tcp.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/timer.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/types.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/udp.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/workqueue.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/net/checksum.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/net/genetlink.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/net/netlink.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/random32.c create mode 100644 openflow/datapath/linux-2.6/compat-2.6/veth.c create mode 100644 openflow/datapath/linux-2.6/config/config-linux-2.6.23-rc9-kvm create mode 100644 openflow/datapath/openflow-ext.c create mode 100644 openflow/datapath/openflow-ext.h create mode 100644 openflow/datapath/private-msg.c create mode 100644 openflow/datapath/private-msg.h create mode 100644 openflow/datapath/table-hash.c create mode 100644 openflow/datapath/table-linear.c create mode 100644 openflow/datapath/table.h create mode 100644 openflow/debian/.gitignore create mode 100644 openflow/debian/changelog create mode 100755 openflow/debian/commands/reconfigure create mode 100755 openflow/debian/commands/update create mode 100644 openflow/debian/compat create mode 100644 openflow/debian/control.in create mode 100644 openflow/debian/control.modules.in create mode 100644 openflow/debian/copyright create mode 100755 openflow/debian/corekeeper.cron.daily create mode 100755 openflow/debian/corekeeper.init create mode 100644 openflow/debian/dirs create mode 100755 openflow/debian/ofp-switch-setup create mode 100644 openflow/debian/ofp-switch-setup.8 create mode 100644 openflow/debian/openflow-common.dirs create mode 100644 openflow/debian/openflow-common.install create mode 100644 openflow/debian/openflow-common.manpages create mode 100644 openflow/debian/openflow-controller.README.Debian create mode 100644 openflow/debian/openflow-controller.default create mode 100644 openflow/debian/openflow-controller.dirs create mode 100755 openflow/debian/openflow-controller.init create mode 100644 openflow/debian/openflow-controller.install create mode 100644 openflow/debian/openflow-controller.manpages create mode 100755 openflow/debian/openflow-controller.postinst create mode 100755 openflow/debian/openflow-datapath-module-_KVERS_.postinst.modules.in create mode 100644 openflow/debian/openflow-datapath-source.README.Debian create mode 100644 openflow/debian/openflow-datapath-source.copyright create mode 100644 openflow/debian/openflow-datapath-source.dirs create mode 100644 openflow/debian/openflow-datapath-source.install create mode 100644 openflow/debian/openflow-pki-server.apache2 create mode 100644 openflow/debian/openflow-pki-server.dirs create mode 100644 openflow/debian/openflow-pki-server.install create mode 100755 openflow/debian/openflow-pki-server.postinst create mode 100755 openflow/debian/openflow-pki.postinst create mode 100644 openflow/debian/openflow-switch-config.dirs create mode 100644 openflow/debian/openflow-switch-config.install create mode 100644 openflow/debian/openflow-switch-config.manpages create mode 100644 openflow/debian/openflow-switch-config.overrides create mode 100644 openflow/debian/openflow-switch-config.templates create mode 100644 openflow/debian/openflow-switch.README.Debian create mode 100644 openflow/debian/openflow-switch.dirs create mode 100755 openflow/debian/openflow-switch.init create mode 100644 openflow/debian/openflow-switch.install create mode 100644 openflow/debian/openflow-switch.logrotate create mode 100644 openflow/debian/openflow-switch.manpages create mode 100755 openflow/debian/openflow-switch.postinst create mode 100755 openflow/debian/openflow-switch.postrm create mode 100644 openflow/debian/openflow-switch.template create mode 100644 openflow/debian/po/POTFILES.in create mode 100755 openflow/debian/rules create mode 100644 openflow/doc/of-spec/.gitignore create mode 100644 openflow/doc/of-spec/Makefile create mode 100644 openflow/doc/of-spec/README create mode 100755 openflow/doc/of-spec/appendix.tex create mode 100644 openflow/doc/of-spec/credits.tex create mode 100755 openflow/doc/of-spec/figure_flow_table_secchan.png create mode 100644 openflow/doc/of-spec/header_parsing_flowchart.graffle create mode 100755 openflow/doc/of-spec/make_latex_input.pl create mode 100644 openflow/doc/of-spec/openflow-spec-v1.0.0.tex create mode 100644 openflow/doc/of-spec/packet_flow_flowchart.graffle create mode 100644 openflow/hw-lib/automake.mk create mode 100644 openflow/hw-lib/nf2/README create mode 100644 openflow/hw-lib/nf2/debug.h create mode 100644 openflow/hw-lib/nf2/hw_flow.c create mode 100644 openflow/hw-lib/nf2/hw_flow.h create mode 100644 openflow/hw-lib/nf2/nf2.h create mode 100644 openflow/hw-lib/nf2/nf2_drv.c create mode 100644 openflow/hw-lib/nf2/nf2_drv.h create mode 100644 openflow/hw-lib/nf2/nf2_lib.c create mode 100644 openflow/hw-lib/nf2/nf2_lib.h create mode 100644 openflow/hw-lib/nf2/nf2util.c create mode 100644 openflow/hw-lib/nf2/nf2util.h create mode 100644 openflow/hw-lib/nf2/reg_defines_openflow_switch.h create mode 100644 openflow/hw-lib/skeleton/debug.h create mode 100644 openflow/hw-lib/skeleton/hw_drv.c create mode 100644 openflow/hw-lib/skeleton/hw_drv.h create mode 100644 openflow/hw-lib/skeleton/hw_flow.c create mode 100644 openflow/hw-lib/skeleton/hw_flow.h create mode 100644 openflow/hw-lib/skeleton/of_hw_platform.h create mode 100644 openflow/hw-lib/skeleton/os.h create mode 100644 openflow/hw-lib/skeleton/port.c create mode 100644 openflow/hw-lib/skeleton/port.h create mode 100644 openflow/hw-lib/skeleton/sample_plat.c create mode 100644 openflow/hw-lib/skeleton/sample_plat.h create mode 100644 openflow/hw-lib/skeleton/txrx.c create mode 100644 openflow/hw-lib/skeleton/txrx.h create mode 100644 openflow/include/.gitignore create mode 100644 openflow/include/automake.mk create mode 100644 openflow/include/openflow/automake.mk create mode 100644 openflow/include/openflow/nicira-ext.h create mode 100644 openflow/include/openflow/of_hw_api.h create mode 100644 openflow/include/openflow/openflow-ext.h create mode 100644 openflow/include/openflow/openflow-netlink.h create mode 100644 openflow/include/openflow/openflow.h create mode 100644 openflow/include/openflow/private-ext.h create mode 100644 openflow/m4/libopenflow.m4 create mode 100644 openflow/m4/nx-build.m4 create mode 100644 openflow/regress/CREDITS create mode 100644 openflow/regress/INSTALL create mode 100644 openflow/regress/LICENSE create mode 100644 openflow/regress/README create mode 100644 openflow/regress/bin/eth.map create mode 100644 openflow/regress/bin/nf2.map create mode 100644 openflow/regress/bin/of_hp_eth.map create mode 100755 openflow/regress/bin/of_hp_setup.pl create mode 100755 openflow/regress/bin/of_hp_teardown.pl create mode 100755 openflow/regress/bin/of_hp_test.pl create mode 100755 openflow/regress/bin/of_hp_test_6600.pl create mode 100755 openflow/regress/bin/of_kmod_setup.pl create mode 100755 openflow/regress/bin/of_kmod_teardown.pl create mode 100755 openflow/regress/bin/of_kmod_test.pl create mode 100755 openflow/regress/bin/of_kmod_veth_setup.pl create mode 100755 openflow/regress/bin/of_kmod_veth_teardown.pl create mode 100755 openflow/regress/bin/of_kmod_veth_test.pl create mode 100755 openflow/regress/bin/of_nf2_setup.pl create mode 100755 openflow/regress/bin/of_nf2_teardown.pl create mode 100755 openflow/regress/bin/of_nf2_test.pl create mode 100644 openflow/regress/bin/of_ovs_eth.map create mode 100755 openflow/regress/bin/of_ovs_setup.pl create mode 100755 openflow/regress/bin/of_ovs_teardown.pl create mode 100755 openflow/regress/bin/of_ovs_test.pl create mode 100755 openflow/regress/bin/of_ovs_user_setup.pl create mode 100755 openflow/regress/bin/of_ovs_user_teardown.pl create mode 100755 openflow/regress/bin/of_ovs_user_test.pl create mode 100755 openflow/regress/bin/of_ovs_user_veth_test.pl create mode 100755 openflow/regress/bin/of_ovs_veth_test.pl create mode 100755 openflow/regress/bin/of_user_setup.pl create mode 100755 openflow/regress/bin/of_user_teardown.pl create mode 100755 openflow/regress/bin/of_user_test.pl create mode 100755 openflow/regress/bin/of_user_veth_setup.pl create mode 100755 openflow/regress/bin/of_user_veth_teardown.pl create mode 100755 openflow/regress/bin/of_user_veth_test.pl create mode 100644 openflow/regress/bin/veth.map create mode 100755 openflow/regress/bin/veth_setup.pl create mode 100755 openflow/regress/bin/veth_teardown.pl create mode 100755 openflow/regress/projects/black_box/regress/common/setup create mode 100755 openflow/regress/projects/black_box/regress/common/teardown create mode 100755 openflow/regress/projects/black_box/regress/test_add_flow_latency/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_barrier/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_cookie_flow_expired/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_cookie_flow_stats/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_delete/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_delete_send_flow_exp/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_delete_strict/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_drop_exact/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_failover_close/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_failover_startup/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_failover_stop_responding/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_flow_expired/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_flow_expired_idle_timeout/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_flow_expired_precision/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_flow_expired_send_flow_exp/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_flow_mod_check/run.pl create mode 100644 openflow/regress/projects/black_box/regress/test_flow_mod_latency/run-port3.pl create mode 100755 openflow/regress/projects/black_box/regress/test_flow_mod_latency/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_flow_stats/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_flow_stats_precision/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_after_expiration/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_any_port/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_bandwidth_fixed/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_bandwidth_random/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_broadcast_exact_port/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_all/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_arp_all/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_arp_controller/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_arp_fool/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_arp_port/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_controller/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_icmp_all/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_icmp_controller/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_icmp_fool/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_icmp_port/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_modify_action/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_port/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_overlapping_flow_entries/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_all/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_all/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_controller/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_fool/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_port/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_controller/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_all/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_controller/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_fool/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_port/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_modify_action/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_port/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_hello/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_ip_offset/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_ip_options/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_ip_protocol/case-c.pl create mode 100755 openflow/regress/projects/black_box/regress/test_ip_protocol/case-d.pl create mode 100755 openflow/regress/projects/black_box/regress/test_ip_protocol/case-e.pl create mode 100755 openflow/regress/projects/black_box/regress/test_ip_protocol/case-tcp.pl create mode 100755 openflow/regress/projects/black_box/regress/test_ip_protocol/case-udp.pl create mode 100755 openflow/regress/projects/black_box/regress/test_llc/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_miss_send_length/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_packet_in/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_packet_out/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_port_stats/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_queue_config/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_queue_forward/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_queue_stats/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_receive_bandwidth_fixed/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_send_bandwidth_fixed/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_send_bandwidth_random/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_set_dl_nw_flip/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_set_n_match_nw_tos/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_set_nw_dst/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_stats_desc/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_switch_config/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_tcp_options/run.pl create mode 100644 openflow/regress/projects/black_box/regress/tests.txt create mode 100755 openflow/regress/projects/controller_disconnect/regress/common/setup create mode 100755 openflow/regress/projects/controller_disconnect/regress/common/teardown create mode 100755 openflow/regress/projects/controller_disconnect/regress/test_emergency_table/run.pl create mode 100644 openflow/regress/projects/controller_disconnect/regress/tests.txt create mode 100755 openflow/regress/projects/learning_switch/regress/common/setup create mode 100755 openflow/regress/projects/learning_switch/regress/common/teardown create mode 100755 openflow/regress/projects/learning_switch/regress/test_broadcast/run.pl create mode 100755 openflow/regress/projects/learning_switch/regress/test_forward_bandwidth/run.pl create mode 100755 openflow/regress/projects/learning_switch/regress/test_forward_latency/run.pl create mode 100755 openflow/regress/projects/learning_switch/regress/test_hub_connected/run.pl create mode 100755 openflow/regress/projects/learning_switch/regress/test_unicast_known/run.pl create mode 100755 openflow/regress/projects/learning_switch/regress/test_unicast_move/run.pl create mode 100755 openflow/regress/projects/learning_switch/regress/test_unicast_multiple_hosts/run.pl create mode 100755 openflow/regress/projects/learning_switch/regress/test_unicast_self/run.pl create mode 100755 openflow/regress/projects/learning_switch/regress/test_unicast_unknown/run.pl create mode 100644 openflow/regress/projects/learning_switch/regress/tests.txt create mode 100644 openflow/regress/projects/regress.txt create mode 100755 openflow/regress/scripts/copy_NF2_code.sh create mode 100644 openflow/regress/scripts/env_vars create mode 100755 openflow/regress/scripts/install_deps.pl create mode 100755 openflow/regress/scripts/install_perlmods_apt.pl create mode 100755 openflow/regress/scripts/make_release.pl create mode 100644 openflow/secchan/.dirstamp create mode 100644 openflow/secchan/.gitignore create mode 100644 openflow/secchan/automake.mk create mode 100644 openflow/secchan/commands/automake.mk create mode 100755 openflow/secchan/commands/reboot create mode 100644 openflow/secchan/discovery.c create mode 100644 openflow/secchan/discovery.h create mode 100644 openflow/secchan/emerg-flow.c create mode 100644 openflow/secchan/emerg-flow.h create mode 100644 openflow/secchan/fail-open.c create mode 100644 openflow/secchan/fail-open.h create mode 100644 openflow/secchan/failover.c create mode 100644 openflow/secchan/failover.h create mode 100644 openflow/secchan/in-band.c create mode 100644 openflow/secchan/in-band.h create mode 100644 openflow/secchan/ofprotocol.8.in create mode 100644 openflow/secchan/port-watcher.c create mode 100644 openflow/secchan/port-watcher.h create mode 100644 openflow/secchan/protocol-stat.c create mode 100644 openflow/secchan/protocol-stat.h create mode 100644 openflow/secchan/ratelimit.c create mode 100644 openflow/secchan/ratelimit.h create mode 100644 openflow/secchan/secchan.c create mode 100644 openflow/secchan/secchan.h create mode 100644 openflow/secchan/status.c create mode 100644 openflow/secchan/status.h create mode 100644 openflow/secchan/stp-secchan.c create mode 100644 openflow/secchan/stp-secchan.h create mode 100755 openflow/soexpand.pl create mode 100644 openflow/tests/.dirstamp create mode 100644 openflow/tests/.gitignore create mode 100644 openflow/tests/automake.mk create mode 100755 openflow/tests/flowgen.pl create mode 100644 openflow/tests/test-dhcp-client.c create mode 100755 openflow/tests/test-flows create mode 100644 openflow/tests/test-flows.c create mode 100755 openflow/tests/test-flows.sh create mode 100755 openflow/tests/test-hmap create mode 100644 openflow/tests/test-hmap.c create mode 100644 openflow/tests/test-list.c create mode 100644 openflow/tests/test-stp-ieee802.1d-1998 create mode 100644 openflow/tests/test-stp-ieee802.1d-2004-fig17.4 create mode 100644 openflow/tests/test-stp-ieee802.1d-2004-fig17.6 create mode 100644 openflow/tests/test-stp-ieee802.1d-2004-fig17.7 create mode 100644 openflow/tests/test-stp-iol-io-1.1 create mode 100644 openflow/tests/test-stp-iol-io-1.2 create mode 100644 openflow/tests/test-stp-iol-io-1.4 create mode 100644 openflow/tests/test-stp-iol-io-1.5 create mode 100644 openflow/tests/test-stp-iol-op-1.1 create mode 100644 openflow/tests/test-stp-iol-op-1.4 create mode 100644 openflow/tests/test-stp-iol-op-3.1 create mode 100644 openflow/tests/test-stp-iol-op-3.3 create mode 100644 openflow/tests/test-stp-iol-op-3.4 create mode 100644 openflow/tests/test-stp.c create mode 100755 openflow/tests/test-stp.sh create mode 100644 openflow/tests/test-type-props.c create mode 100644 openflow/third-party/.gitignore create mode 100644 openflow/third-party/README create mode 100644 openflow/third-party/automake.mk create mode 100644 openflow/third-party/ofp-tcpdump.patch create mode 100644 openflow/udatapath/.dirstamp create mode 100644 openflow/udatapath/.gitignore create mode 100644 openflow/udatapath/automake.mk create mode 100644 openflow/udatapath/chain.c create mode 100644 openflow/udatapath/chain.h create mode 100644 openflow/udatapath/crc32.c create mode 100644 openflow/udatapath/crc32.h create mode 100644 openflow/udatapath/datapath.c create mode 100644 openflow/udatapath/datapath.h create mode 100644 openflow/udatapath/dp_act.c create mode 100644 openflow/udatapath/dp_act.h create mode 100644 openflow/udatapath/of_ext_msg.c create mode 100644 openflow/udatapath/of_ext_msg.h create mode 100644 openflow/udatapath/ofdatapath.8.in create mode 100644 openflow/udatapath/private-msg.c create mode 100644 openflow/udatapath/private-msg.h create mode 100644 openflow/udatapath/switch-flow.c create mode 100644 openflow/udatapath/switch-flow.h create mode 100644 openflow/udatapath/table-hash.c create mode 100644 openflow/udatapath/table-linear.c create mode 100644 openflow/udatapath/table.h create mode 100644 openflow/udatapath/udatapath.c create mode 100644 openflow/utilities/.dirstamp create mode 100644 openflow/utilities/.gitignore create mode 100644 openflow/utilities/automake.mk create mode 100644 openflow/utilities/dpctl.8.in create mode 100644 openflow/utilities/dpctl.c create mode 100644 openflow/utilities/ofp-discover.8.in create mode 100644 openflow/utilities/ofp-discover.c create mode 100644 openflow/utilities/ofp-kill.8.in create mode 100644 openflow/utilities/ofp-kill.c create mode 100644 openflow/utilities/ofp-parse-leaks create mode 100755 openflow/utilities/ofp-parse-leaks.in create mode 100755 openflow/utilities/ofp-pki-cgi.in create mode 100644 openflow/utilities/ofp-pki.8.in create mode 100755 openflow/utilities/ofp-pki.in create mode 100644 openflow/utilities/vlogconf.8.in create mode 100644 openflow/utilities/vlogconf.c create mode 100644 openflow/utilities/wireshark_dissectors/Makefile create mode 100644 openflow/utilities/wireshark_dissectors/README create mode 100644 openflow/utilities/wireshark_dissectors/openflow/.gitignore create mode 100644 openflow/utilities/wireshark_dissectors/openflow/Makefile create mode 100644 openflow/utilities/wireshark_dissectors/openflow/Makefile.am create mode 100644 openflow/utilities/wireshark_dissectors/openflow/Makefile.common create mode 100755 openflow/utilities/wireshark_dissectors/openflow/build_distribution_tarball.sh create mode 100644 openflow/utilities/wireshark_dissectors/openflow/moduleinfo.h create mode 100644 openflow/utilities/wireshark_dissectors/openflow/packet-openflow.c create mode 100644 openflow/utilities/wireshark_dissectors/openflow/plugin.c create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/airpcap.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/airpcap_loader.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/alert_box.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-pcap-util-int.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-pcap-util.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-wpcap.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_errs.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_info.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_opts.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_stop_conditions.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_sync.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_ui_utils.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_wpcap_packet.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/cfile.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/clopts_common.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/cmdarg_err.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/color.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/color_filters.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/conditions.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h.in create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h.win32 create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/disabled_protos.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/addr_and_mask.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/addr_resolv.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/address.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/adler32.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/afn.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/aftypes.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/arcnet_pids.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/arptypes.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/asm_utils.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/asn1.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/atalk-utils.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/base64.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/bitswap.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/bridged_pids.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/camel-persistentdata.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/charsets.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/chdlctypes.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/circuit.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/codecs.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column-utils.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column_info.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/conversation.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc10.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc16.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc32.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc6.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crcdrm.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_debug.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_int.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_interop.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_rijndael.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_system.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_user.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_ws.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-des.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-md4.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-md5.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-rc4.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-sha1.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/wep-wpadefs.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter-int.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter-macro.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfunctions.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfvm.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/drange.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/gencode.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/glib-util.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/grammar.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/scanner_lex.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/semcheck.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-function.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-range.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-test.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/syntax-tree.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/diam_dict.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/diam_dict_lex.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dissector_filters.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dissectors/packet-tcp.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_grammar.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_parse.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_parse_lex.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_preparse_lex.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/eap.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/emem.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/epan.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/epan_dissect.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/etypes.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ex-opt.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/except.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/exceptions.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/expert.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/filesystem.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/follow.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/frame_data.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/frequency-utils.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ftypes/ftypes-int.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ftypes/ftypes.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/funnel.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/g_ascii_strcasecmp.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/g_ascii_strtoull.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/garrayfix.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/gcp.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/gnuc_format_check.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/golay.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/greproto.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/guid-utils.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/h225-persistentdata.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/iax2_codec_type.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/in_cksum.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/inet_aton.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ip_opts.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipproto.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipv4.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipv6-utils.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/lapd_sapi.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/llcsaps.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/next_tvb.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/nlpid.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/nstime.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/oids.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/osi-utils.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/oui.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/packet.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/packet_info.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/pint.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/plugins.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ppptypes.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/prefs-int.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/prefs.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/privileges.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/proto.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ptvcursor.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/radius_dict_lex.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/range.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/reassemble.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/reedsolomon.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/report_err.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/req_resp_hdrs.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/rtp_pt.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sctpppids.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sigcomp-udvm.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sigcomp_state_hdlr.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/slab.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sminmpec.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sna-utils.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stat_cmd_args.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stats_tree.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stats_tree_priv.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stream.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/strutil.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/t35.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tap-voip.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tap.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tcap-persistentdata.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tfs.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/timestamp.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/to_str.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tvbparse.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tvbuff.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat-int.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat_load_lex.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/unicode-utils.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/value_string.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ws_strsplit.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/wslua/declare_wslua.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/wslua/wslua.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/x264_prt_id.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/xdlc.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/xmlstub.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/file.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/fileset.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/filters.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/g711.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/getopt.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/globals.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/inet_v6defs.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/isprint.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/log.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/main_window.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/menu.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/merge.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/mkstemp.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/packet-range.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/pcapio.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/print.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/progress_dlg.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/proto_hier_stats.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ps.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/register.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ringbuffer.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/simple_dialog.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/stat_menu.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/statusbar.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/strerror.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/strptime.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/summary.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/svnversion.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/sync_pipe.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tap-rtp-common.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tap_dfilter_dlg.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tempfile.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/text2pcap.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/timestats.h create mode 100755 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tools/make-dissector-reg create mode 100755 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tools/make-dissector-reg.py create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ui_util.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/util.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/version_info.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/5views.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/airopeek9.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-grammar.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-int.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-scanner_lex.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/atm.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ber.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/btsnoop.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/buffer.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/catapult_dct2000.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/commview.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/cosine.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/csids.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/dbs-etherwatch.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/erf.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/etherpeek.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/eyesdn.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/file_util.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/file_wrappers.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/hcidump.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/i4b_trace.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/i4btrace.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/iptrace.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/iseries.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/k12.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/k12text_lex.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/lanalyzer.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/libpcap.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/mpeg-audio.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/mpeg.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netmon.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netscreen.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/nettl.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/network_instruments.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netxray.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ngsniffer.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/pcapng.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/pppdump.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/radcom.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/snoop.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/toshiba.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/visual.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/vms.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/wtap-int.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/wtap.h diff --git a/mininet/bin/dmn b/mininet/bin/dmn index 96024ec1..0ef98de8 100755 --- a/mininet/bin/dmn +++ b/mininet/bin/dmn @@ -298,9 +298,9 @@ class DistrinetRunner( object ): dest='test', help='|'.join( TESTS.keys() ) ) opts.add_option( '--xterms', '-x', action='store_true', default=False, help='spawn xterms for each node' ) - opts.add_option( '--ipbase', '-i', type='string', default='192.168.123.20/24', + opts.add_option( '--ipbase', '-i', type='string', default='10.10.1.5/16', help='base IP address for hosts' ) - opts.add_option( '--providerIpbase', '-p', type='string', default='172.16.62.20/24', + opts.add_option( '--providerIpbase', '-p', type='string', default='20.20.1.5/16', help='base Provider IP address for hosts' ) opts.add_option( '--mac', action='store_true', default=False, help='automatically set host MACs' ) @@ -560,7 +560,7 @@ class DistrinetRunner( object ): host, switch, link = LxcNode, LxcOVSSwitch, CloudLink ## - adminIpBase='192.168.0.1/24' + adminIpBase='192.168.1.1/16' waitConnected=False build=False if not opts.placement_file_path: diff --git a/mininet/custom/fat-tree.py b/mininet/custom/fat-tree.py index 14f5ef16..73f194a3 100644 --- a/mininet/custom/fat-tree.py +++ b/mininet/custom/fat-tree.py @@ -36,7 +36,7 @@ def __init__(self): super(MyTopo, self).__init__() # K setting - K = 4 + K = 12 # S setting S = K//2 diff --git a/mininet/mininet/lxc_container.py b/mininet/mininet/lxc_container.py index 3f1fa9a4..25e5674d 100644 --- a/mininet/mininet/lxc_container.py +++ b/mininet/mininet/lxc_container.py @@ -350,7 +350,7 @@ def createContainer(self,autoSetDocker=False,providerIP=None, **params): if autoSetDocker: if self.image=="ubuntu": ##--privileged=true --init --cap-add=NET_ADMIN --cap-add=SYS_MODULE --cap-add=SYS_NICE jiawei96liu/cnimage:v3 bash - cmd = "docker create -it --privileged --cap-add=NET_ADMIN --cap-add=SYS_MODULE --cap-add=SYS_NICE --init --net network62 --ip {} --name {} -h {} {} ".format(providerIP, self.name, self.name, self.image) + cmd = "docker create -it --privileged --cap-add=NET_ADMIN --cap-add=SYS_MODULE --cap-add=SYS_NICE --init --net network20 --ip {} --name {} -h {} {} ".format(providerIP, self.name, self.name, self.image) else: cmd="docker create -it --privileged --cap-add=NET_ADMIN --cap-add=SYS_MODULE --cap-add=SYS_NICE --net=none --name {} -h {} {} ".format(self.name, self.name, self.image) else: @@ -369,8 +369,6 @@ def createContainer(self,autoSetDocker=False,providerIP=None, **params): if self.image=="switch": cmds.append("docker exec {} bash -c 'export PATH=$PATH:/usr/share/openvswitch/scripts;ovs-ctl start'".format(self.name)) - else: - cmds.append("docker exec {} bash -c 'cd /mnt/host/code;/etc/init.d/openvswitch-switch restart;ovs-vswitchd --pidfile --detach'".format(self.name)) else: if self.cpu: cmds.append("lxc config set {} limits.cpu {}".format(self.name, self.cpu)) diff --git a/openflow/.gitignore b/openflow/.gitignore new file mode 100644 index 00000000..be6113cd --- /dev/null +++ b/openflow/.gitignore @@ -0,0 +1,44 @@ +#*# +*.a +*.d +*.ko +*.la +*.lo +*.loT +*.mod.c +*.o +*.o +*.pyc +*.so +*~ +.#* +.*.cmd +.deps +.libs +.tmp_versions +/Makefile +/Makefile.in +/aclocal.m4 +/autom4te.cache +/build-arch-stamp +/build-aux +/build-indep-stamp +/compile +/config.guess +/config.h +/config.h.in +/config.log +/config.status +/config.sub +/configure +/configure-stamp +/depcomp +/install-sh +/missing +/stamp-h1 +Module.symvers +TAGS +cscope.* +ext.m4 +ext.mk +tags diff --git a/openflow/COPYING b/openflow/COPYING new file mode 100644 index 00000000..ab5f3705 --- /dev/null +++ b/openflow/COPYING @@ -0,0 +1,1054 @@ +Source file copyrights are indicated at the top of each file. + +Files not in the datapath/ and vswitchd/ directories or associated +subdirectories are covered under the OpenFlow license included below: + +We are making the OpenFlow specification and associated documentation +(Software) available for public use and benefit with the expectation +that others will use, modify and enhance the Software and contribute +those enhancements back to the community. However, since we would like +to make the Software available for broadest use, with as few +restrictions as possible permission is hereby granted, free of charge, +to any person obtaining a copy of this Software to deal in the Software +under the copyrights without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +The name and trademarks of copyright holder(s) may NOT be used in +advertising or publicity pertaining to the Software or any derivatives +without specific, written prior permission. + +Files in the datapath/ and its sub-directories are covered under the GNU +General Public License Version 2. Included below: + + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + +Files in vswitchd/ and its sub-directories are covered under the GNU +General Public License Version 3. Included below: + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/openflow/ChangeLog b/openflow/ChangeLog new file mode 100644 index 00000000..c2d4b49a --- /dev/null +++ b/openflow/ChangeLog @@ -0,0 +1,202 @@ +1.0.0-rev1 - XX XXX 2010 +------------------------ + - Changes to regression suite: + - Added testing support for Open vSwitch + - Updated HP-ProCurve scripts + - Minor fixes applied to libraries + - Fixes applied to the following tests: + test_switch_config, test_forward_broadcast_exact_port, + test_set_n_match_nw_tos, test_set_nw_dst, + test_failover_startup + - Added test to verify flipping of src/dst MAC and IP + - Ability to disable slicing, VLAN, and barrier in tests + - Can easily run a single test + For more information, see regress/README + +1.0.0 - 31 Dec 2009 +------------------- + - Fixed Wireshark plugin warnings + - Clarified purpose of actions field in ofp_switch_features in spec + + Known issues: + - isolation provided by the slicing mechanism has been + observed to degrade when run on systems with low performance CPUs. + Investigations are underway to improve isolation on such systems. + +1.0.0-RC1 - 19 Dec 2009 +----------------------- + - Changed wire protocol version to 0x01 + - Added slicing support + - Improved resolution of flow duration in stats/expiry + - Added flow cookies to flows + - Enable matching on IP fields inside ARP packets + - Enable port stats to be retrieved for individual ports + - Added ability to match on IP ToS bits + - Added datapath description to desc stats + - Added ability to control slicing queues from dpctl + - Set datapath description from dpctl + - Removed kernel datapath from reference switch + (will be release separately) + - Fix bug related to identifying overlapping flows + - Updated Wireshark dissector to support 1.0.0 features + - Added regression tests for ARP handling, flow cookies, slicing, + selective port stats, flow duration precision, matching on ToS bits, and + the datapath description + + Known issues: + - isolation provided by the slicing mechanism has been + observed to degrade when run on systems with low performance CPUs. + Investigations are underway to improve isolation on such systems. + +0.9.0-rev1 - 04 Sep 2009 +------------------------ + - Added NetFPGA hardware table support (wire protocol 0x98) + - Fixed a few userspace datapath bugs + +0.9.0 - 20 Jul 2009 +------------------- + - Changed wire protocol version to 0x98 + - Removed monolithic switch process called switch + - Added userspace data plane process named ofdatapath + - Changed userspace control plane process name to ofprotocol + - Changed kernelspace data plane extension name to ofdatapath.ko + - Changed NetFPGA kernelspace extestion name to ofdatapath_netfpga.ko + - Removed Linux 2.4 kerel support + - Added simple controller failover feature + - Added emergency flow cache feature + - Added barrier command + - Added 802.1Q VLAN priority bits match feature + - Clarified flow expiration, renamed flow expiration to flow removed + - Added protocol statistics collector + - Added IP ToS/DSCP rewrite feature + - Changed port enumeration at 1 instead of 0 + - Clarified emergeency flow cache behavior + - Clarified definition of datapath ID + - Clarified meaning of a zero-size miss_send_len + - Clarified meaning of a zero-size max_len in output action + - Changed protocol structure alignment to ensure 64-bit + +v0.8.9 r2 - 23 Jan 2009 +----------------------- + - Added NetFPGA hardware table support (wire protocol 0x97) + - Added regression tests on port_stats, flow_stats, drop, ICMP handling + - Bug fixes + +v0.8.9~1 - 01 Dec 2008 +---------------------- + - Added support for IP netmasks + - Added new physical port stats + - Added IN_PORT virtual port + - Added echo request/response + - Added detection of link and port status changes + - Added ability to configure port status from controller + - Added support for vendor extensions + - Added support for variable length actions + - Added support for matching ICMP type and code + - Added support for listing and deleting flows based on output port action + - Added support for modifying VLAN priority tag + - Increased max supported ports to 65280 + - More explicit handling for IP fragments + - Added support for 802.1D spanning tree + - Added OFPFC_MODIFY command to Flow Mod message + - Provided more flexible description of tables to controller + - Make port modification more explicit + - Made Packet Out message more consistent + - Added hard timeout value to Flow Mod message + - Added reason field for Flow Expired message + - Reworked initial handshake to support backwards compatibility + - Added OFPST_DESC stat for returning description of hw/sw + - Added support for loadable hardware table support modules** + - In-band control now supported** + - 802.1D spanning tree support** + - Automatic controller discovery (via DHCP) now supported** + - Improved support for older 2.6.x kernels** + - Switch can now "fail open" as a MAC-learning switch if the controller cannot be contacted** + - Debian packages may now be built** + - Fixed bugs in SSL support + - Most programs now take --detach and --pidfile options to run as daemon + - Numerous bug fixes + + ** Only supported in the kernel module for the time-being. + +v0.8.1 - 14 May 2008 +-------------------- + - No longer set nwsrc/nwdst fields in flow structs on ARP packets + - Various bug fixes and tweaks + +v0.8.0 - 04 May 2008 +-------------------- + - Added support for flow entry priorities + - Added support for all stats messages + - Added support for OFPP_TABLE virtual port + - Removed MAC tables + - Various bug fixes and tweaks + +v0.2.1 - 28 Mar 2008 +-------------------- + - Fixed build problem when SSL enabled + +v0.2.0 - 28 Mar 2008 +-------------------- + - Added userspace switch reference implementation + +v0.1.9 - 19 Mar 2008 +-------------------- + - Added SSL/TLS support + - Various bug fixes and tweaks + +v0.1.8 - 03 Mar 2008 +-------------------- + - Added support for cross-compilation + - Various bug fixes and tweaks + +v0.1.7 - 07 Feb 2008 +-------------------- + - Allow permanent flow entries to be set + - Added patch for tcpdump that allows parsing of OpenFlow messages + - Various bug fixes and tweaks + +v0.1.6 - 05 Feb 2008 +-------------------- + - Added support for Linux 2.6.24 + - Set nwsrc/nwdst fields in flow structs on ARP packets + - Various bug fixes and tweaks + +v0.1.5 - 17 Jan 2008 +-------------------- + - Added support for Linux 2.4.20 + - Added support for GCC 2.95 + +v0.1.4 - 15 Jan 2008 +-------------------- + - Decode and print port_status messages + - Fixed build problems on big-endian systems + - Fixed compatibility for older 2.6 kernels + - Various bug fixes and tweaks + +v0.1.3 - 08 Jan 2008 +-------------------- + - Added support for flow expiration messages + - Decode and print all datapath-generated messages in dpctl's "monitor" + - Added "--noflow" option to controller + - Various bug fixes and tweaks + +v0.1.2 - 07 Jan 2008 +-------------------- + - Fixed distribution to include ofp_pcap.h + - Removed autoconf C++ checks + +v0.1.1 - 18 Dec 2007 +-------------------- + - Fixed support for Linux 2.4.35 and 2.6.22 + - Added support for Linux 2.6.15 + - Added "vlogconf" utility to modify logging configuration + - Added better support for SNAP headers + - Improved printing of flow information in dpctl + - Made kernel code consistently use tabs instead of spaces + - Removed libpcap requirement for building + - Various bug fixes and tweaks + +v0.1.0 - 30 Nov 2007 +-------------------- + - Initial release diff --git a/openflow/INSTALL b/openflow/INSTALL new file mode 100644 index 00000000..f236e16a --- /dev/null +++ b/openflow/INSTALL @@ -0,0 +1,513 @@ + Installation Instructions for OpenFlow Reference Release + +This document describes how to build, install, and execute the +reference implementation of OpenFlow. Please send any comments to: + + + +Contents +======== + +The OpenFlow reference implementation includes one OpenFlow switch +implementations: + + - The "userspace datapath-based switch": This divides the switch + into a userspace "datapath" (built as udatapath/ofdatapath) + and a userspace program that implements the secure channel + component (ofprotocol). The userspace datapath-based switch + does not require building a kernel module, but it is not as + fast as a kernel-based switch. + +The reference implementation also contains a simple OpenFlow +controller (built as controller/controller) and a number of related +utilities. + +Build Methods +============= + +There are two principal ways to build and install this distribution: + + - Using "configure" and "make" in the ordinary way. See + Building Conventionally below for detailed instructions. + + - As a set of Debian packages. Refer to Building Debian + Packages, below, for instructions. + +Base Prerequisites +------------------ + +Regardless of how it is built, OpenFlow has a common set of +prerequisites. To compile the userspace programs in the OpenFlow +reference distribution, you will need the following software: + + - A make program, e.g. GNU make + (http://www.gnu.org/software/make/). BSD make should also work. + + - The GNU C compiler (http://gcc.gnu.org/). We generally test + with version 4.1 or 4.2. + + - libssl, from OpenSSL (http://www.openssl.org/), is optional but + recommended. libssl is required to establish confidentiality + and authenticity in the connections among OpenFlow switches and + controllers. To enable, configure with --enable-ssl=yes. + +If you are working from a Git tree or snapshot (instead of from a +distribution tarball), or if you modify the OpenFlow build system, you +will also need the following software: + + - Autoconf version 2.60 or later (http://www.gnu.org/software/autoconf). + + - Automake version 1.10 or later (http://www.gnu.org/software/automake). + + - pkg-config (http://pkg-config.freedesktop.org/wiki/). We test + with version 0.22. + +Debian Prerequisites +-------------------- + +To build Debian packages from the OpenFlow distribution, you will need +to install a number of Debian packages in addition to the base +prerequisites listed above. These additional prerequisites may be +found listed as "Build-Depends" in debian/control in the source tree. +To check that they are installed, first install the dpkg-dev package, +then run dpkg-checkbuilddeps from the top level of the OpenFlow source +tree. + +To build Debian packages without being root, also install the +"fakeroot" package. + +Userspace Switch Prerequisites +--------------------------------- + + - To enable slicing support, "tc" frontend should be installed + (from iproute2, part of all major distributions, + http://www.linux-foundation.org/en/Net:Iproute2). + You also need to enable the following kernel configuration + options under the QoS and/or Fair queueing section : + CONFIG_NET_SCHED,CONFIG_NET_SCH_HTB (already configured that + way in most distributions). + (NOTE: You can disable slicing (and these dependencies) at runtime + using the --no-slicing option) + +Building Conventionally +======================= + +This section explains how to build and install the OpenFlow +distribution in the ordinary way using "configure" and "make". + +0. Check that you have installed all the prerequisites listed above in + the Base Prerequisites section. Run `boot.sh` if necessary to create + the configure script. + + % ./boot.sh + +1. In the top source directory, configure the package by running the + configure script. You can usually invoke configure without any + arguments: + + % ./configure + + To use a specific C compiler for compiling OpenFlow user programs, + also specify it on the configure command line, like so: + + % ./configure CC=gcc-4.2 + + If you have hardware that supports accelerated OpenFlow switching + and you have obtained a hardware table library for your hardware + and extracted it into the OpenFlow reference distribution source + tree, then you may also enable building support for the hardware + switch table with --enable-hw-lib. For more information, read + README.hwtables at the root of the OpenFlow distribution tree. + + The configure script accepts a number of other options and honors + additional environment variables. For a full list, invoke + configure with the --help option. + +2. Run make in the top source directory: + + % make + + The following binaries will be built: + + - Userspace datapath: udatapath/ofdatapath. + + - Secure channel executable: secchan/ofprotocol. + + - Controller executable: controller/controller. + + - Datapath administration utility: utilities/dpctl. + + - Runtime logging configuration utility: utilities/vlogconf. + + - Miscellaneous utilities: utilities/ofp-discover, + utilities/ofp-kill. + + - Tests: various binaries in tests/. + + If your distribution includes the OpenFlow extensions, the + following additional binaries will be built: + + - ANSI terminal support for EZIO 16x2 LCD panel: + ext/ezio/ezio-term. + + - Switch monitoring UI for small text displays: + ext/ezio/ofp-switchui. + +3. Run "make install" to install the executables and manpages into the + running system, by default under /usr/local. + +4. Test the userspace programs, as described under Testing Userspace + Programs below. + +Building Debian Packages +======================== + +Follow these instructions to build Debian packages for OpenFlow. + +0. Check that you have installed all the prerequisites listed above in + the Base Prerequisites and Debian Prerequisites sections above. + +1. In the top source directory, run the following command, as root: + + % dpkg-buildpackage + + Alternatively, if you installed the "fakeroot" package, you may run + dpkg-buildpackage as an ordinary user with the following syntax: + + % dpkg-buildpackage -rfakeroot + + The following packages will be built in the directory above the + source tree: + + - openflow-controller: The OpenFlow controller. Depends on + openflow-pki (see below). + + - openflow-switch: Install this package on a machine that acts + as an OpenFlow kernel switch. + + - openflow-datapath-source: Source code for OpenFlow's Linux + kernel module. + + - openflow-pki: Public-key infrastructure for OpenFlow. Install + this package on a machine that acts as an OpenFlow PKI server + (see "Establishing a Public Key Infrastructure" below). + + - openflow-common: Files and utilities required by more than one + of the above packages. + +2. To set up an OpenFlow controller, install the openflow-controller + package and its dependencies. You may configure it by editing + /etc/default/openflow-controller, e.g. to enable non-SSL + connections, which are disabled by default. If you change the + default settings, you will need to restart the controller by + running: + + % /etc/init.d/openflow-controller restart + +3. To set up an OpenFlow switch, install the openflow-switch package + and its dependencies. If it is to be a kernel-based switch, also + install openflow-datapath-source, then follow the instructions in + /usr/share/doc/openflow-datapath-source/README.Debian to build and + install the kernel module. + + You may configure the switch one of the following ways: + + - Completely by hand, as described under the Testing section + below. + + For the userspace datapath-based switch, this is the only + supported form of configuration. + + - By editing /etc/default/openflow-switch. You must at least + configure some network devices, by uncommenting NETDEVS and + adding the appropriate devices to the list, e.g. NETDEVS="eth0 + eth1". + + After you edit this file, you will need to start the switch by + running: + + % /etc/init.d/openflow-switch restart + + This form of configuration is not supported for the userspace + datapath-based switch. + + - By running the ofp-switch-setup program. This interactive + program will walk you through all the steps of configuring an + OpenFlow switch, including configuration of SSL certificates. + Run it without arguments, as root: + + % ofp-switch-setup + + This form of configuration is not supported for the userspace + datapath-based switch. + +Testing +======= + +The following sets of instructions show how to use the OpenFlow +reference implementation as a switch on a single machine. This can be +used to verify that the distribution built properly. For full +installation instructions, refer to the Installation section below. + +Userspace Datapath +------------------ + +These instructions use the OpenFlow userspace datapath ("ofdatapath"). + +1. Start the OpenFlow controller running in the background, by running + the "controller" program with a command like the following: + + # controller punix:/var/run/controller.sock & + + This command causes the controller to bind to the specified Unix + domain socket, awaiting connections from OpenFlow switches. See + controller(8) for details. + + The "controller" program does not require any special privilege, so + you do not need to run it as root. + +2. The commands below must run as root, so log in as root, or use a + program such as "su" to become root temporarily. + +3. Create a datapath instance running in the background. The command + below creates a datapath that listens for connections from ofprotocol + on a Unix domain socket located in /var/run and services physical + ports eth1 and eth2: + + # ofdatapath punix:/var/run/dp0.sock -i eth1,eth2 & + +4. Run ofprotocol to start the secure channel connecting the datapath and + the controller: + + # ofprotocol unix:/var/run/controller.sock unix:/var/run/dp0.sock & + +5. Devices plugged into the network ports specified in step 2 should + now be able to send packets to each other, as if they were plugged + into ports on a conventional Ethernet switch. + +Installation +============ + +This section explains how to install OpenFlow in a network with one +controller and one or more switches, each of which runs on a separate +machine. Before you begin, you must decide on one of two ways for +each switch to reach the controller over the network: + + - Use a "control network" that is completely separate from the + "data network" to be controlled ("out-of-band control"). The + location of the controller must be configured manually in this + case. + + - Use the same network for control and for data ("in-band + control"). When in-band control is used, the location of the + controller may be configured manually or discovered + automatically. We will assume manual configuration here; + please refer to ofprotocol(8) for instructions on setting up + controller discovery. + +Controller Setup +---------------- + +On the machine that is to be the OpenFlow controller, start the +"controller" program listening for connections from switches on TCP +port 6633 (the default), as shown below. + + # controller -v ptcp: + +(See controller(8) for more details) + +Make sure the machine hosting the controller is reachable by the +switch. + +Userspace Datapath-Based Setup +------------------------------ + +On a machine that is to host an OpenFlow userspace datapath-based +switch, follow the procedure below. + +0. The commands below must run as root, so log in as root, or use a + program such as "su" to become root temporarily. + +1. Create a datapath instance running in the background. The command + below creates a datapath that listens for connections from ofprotocol + on a Unix domain socket located in /var/run, services physical + ports eth1 and eth2, and creates a TAP network device named "tap0" + for use in in-band control: + + # ofdatapath punix:/var/run/dp0.sock -i eth1,eth2 --local-port=tap:tap0 & + + (See ofdatapath(8) for details.) + + If the switch will connect to the controller out-of-band, then the + --local-port option may be omitted, or --no-local-port may be + substituted. + +3. Arrange so that the switch can reach the controller over the + network. + + - If you are using out-of-band control, at this point make sure + that the switch machine can reach the controller over the + network. + + - If you are using in-band control with manual configuration, at + this point the TAP network device created in step 1 is not + bridged to any physical network, so the next step depends on + whether connectivity is required to configure the device's IP + address: + + * If the switch has a static IP address, you may configure + its IP address now, e.g.: + + # ifconfig tap0 192.168.1.1 + + * If the switch does not have a static IP address, e.g. its + IP address is obtained dynamically via DHCP, then proceed + to step 4. The DHCP client will not be able to contact + the DHCP server until the secure channel has started up. + + - If you are using in-band control with controller discovery, no + configuration is required at this point. You may proceed to + step 4. + +4. Run ofprotocol to start the secure channel connecting the datapath to + a remote controller. If the controller is running on host + 192.168.1.2 port 6633 (the default port), the ofprotocol invocation + would look like this: + + # ofprotocol unix:/var/run/dp0.sock tcp:192.168.1.2 + + - If you are using in-band control with controller discovery, omit + the second argument to the ofprotocol command. + + - If you are using out-of-band control, add --out-of-band to the + command line. + +5. If you are using in-band control with manual configuration, and the + switch obtains its IP address dynamically, then you may now obtain + the switch's IP address, e.g. by invoking a DHCP client. The + secure channel will only be able to connect to the controller after + an IP address has been obtained. + +6. The secure channel should connect to the controller within a few + seconds. It may take a little longer if controller discovery is in + use, because the switch must then also obtain its own IP address + and the controller's location via DHCP. + +Configuration +============= + +Secure operation over SSL +------------------------- + +The instructions above set up OpenFlow for operation over a plaintext +TCP connection. Production use of OpenFlow should use SSL[*] to +ensure confidentiality and authenticity of traffic among switches and +controllers. The source must be configured with --enable-ssl=yes to +build with SSL support. + +To use SSL with OpenFlow, you must set up a public-key infrastructure +(PKI) including a pair of certificate authorities (CAs), one for +controllers and one for switches. If you have an established PKI, +OpenFlow can use it directly. Otherwise, refer to "Establishing a +Public Key Infrastructure" below. + +To configure the controller to listen for SSL connections on port 6633 +(the default), invoke it as follows: + + # controller -v pssl: --private-key=PRIVKEY --certificate=CERT \ + --ca-cert=CACERT + +where PRIVKEY is a file containing the controller's private key, CERT +is a file containing the controller CA's certificate for the +controller's public key, and CACERT is a file containing the root +certificate for the switch CA. If, for example, your PKI was created +with the instructions below, then the invocation would look like: + + # controller -v pssl: --private-key=ctl-privkey.pem \ + --certificate=ctl-cert.pem --ca-cert=pki/switchca/cacert.pem + +To configure a switch to connect to a controller running on port 6633 +(the default) on host 192.168.1.2 over SSL, invoke ofprotocol as follows: + + # ofprotocol -v DATAPATH ssl:192.168.1.2 --private-key=PRIVKEY \ + --certificate=CERT --ca-cert=CACERT + +where DATAPATH is the datapath to connect to (e.g. nl:0 or +unix:/var/run/dp0.sock), PRIVKEY is a file containing the switch's +private key, CERT is a file containing the switch CA's certificate for +the switch's public key, and CACERT is a file containing the root +certificate for the controller CA. If, for example, your PKI was +created with the instructions below, then the invocation would look +like: + + # ofprotocol -v DATAPATH ssl:192.168.1.2 --private-key=sc-privkey.pem \ + --certificate=sc-cert.pem --ca-cert=pki/controllerca/cacert.pem + +[*] To be specific, OpenFlow uses TLS version 1.0 or later (TLSv1), as + specified by RFC 2246, which is very similar to SSL version 3.0. + TLSv1 was released in January 1999, so all current software and + hardware should implement it. + +Establishing a Public Key Infrastructure +---------------------------------------- + +If you do not have a PKI, the ofp-pki script included with OpenFlow +can help. To create an initial PKI structure, invoke it as: + % ofp-pki init +which will create and populate a new PKI directory. The default +location for the PKI directory depends on how the OpenFlow tree was +configured (to see the configured default, look for the --dir option +description in the output of "ofp-pki --help"). + +The pki directory contains two important subdirectories. The +controllerca subdirectory contains controller certificate authority +related files, including the following: + + - cacert.pem: Root certificate for the controller certificate + authority. This file must be provided to ofprotocol with the + --ca-cert option to enable it to authenticate valid controllers. + + - private/cakey.pem: Private signing key for the controller + certificate authority. This file must be kept secret. There is + no need for switches or controllers to have a copy of it. + +The switchca subdirectory contains switch certificate authority +related files, analogous to those in the controllerca subdirectory: + + - cacert.pem: Root certificate for the switch certificate + authority. This file must be provided to the controller program + with the --ca-cert option to enable it to authenticate valid + switches. + + - private/cakey.pem: Private signing key for the switch + certificate authority. This file must be kept secret. There is + no need for switches or controllers to have a copy of it. + +After you create the initial structure, you can create keys and +certificates for switches and controllers with ofp-pki. To create a +controller private key and certificate in files named ctl-privkey.pem +and ctl-cert.pem, for example, you could run: + % ofp-pki req+sign ctl controller +ctl-privkey.pem and ctl-cert.pem would need to be copied to the +controller for its use at runtime (they could then be deleted from +their original locations). The --private-key and --certificate +options of controller, respectively, would point to these files. + +Analogously, to create a switch private key and certificate in files +named sc-privkey.pem and sc-cert.pem, for example, you could run: + % ofp-pki req+sign sc switch +sc-privkey.pem and sc-cert.pem would need to be copied to the switch +for its use at runtime (they could then be deleted from their original +locations). The --private-key and --certificate options, +respectively, of ofprotocol would point to these files. + +Bug Reporting +------------- + +Please report problems to: + +openflow-discuss@openflowswitch.org + +or post them to our online bug tracking system at: + +http://www.openflowswitch.org/bugs/openflow diff --git a/openflow/Makefile.am b/openflow/Makefile.am new file mode 100644 index 00000000..97ac1f01 --- /dev/null +++ b/openflow/Makefile.am @@ -0,0 +1,68 @@ +# The goal of -Wno-syntax here is just to suppress the Automake warning +# about overriding distdir, below. +AUTOMAKE_OPTIONS = foreign -Wno-syntax subdir-objects +ACLOCAL_AMFLAGS = -I m4 +#SUBDIRS = datapath +SUBDIRS = + +if HAVE_DPKG_BUILDPACKAGE +distcheck-hook: + cd $(srcdir) && dpkg-buildpackage -rfakeroot -us -uc + cd $(srcdir) && fakeroot ./debian/rules clean +else +distcheck-hook: +endif + +AM_CPPFLAGS = $(SSL_CFLAGS) -g +AM_CPPFLAGS += -I $(top_srcdir)/include +AM_CPPFLAGS += -I $(top_srcdir)/lib + +AM_CFLAGS = -Wstrict-prototypes + +if NDEBUG +AM_CPPFLAGS += -DNDEBUG +AM_CFLAGS += -fomit-frame-pointer +else +AM_LDFLAGS = -export-dynamic +endif + +CLEANFILES = +DISTCLEANFILES = +EXTRA_DIST = +TESTS = +TESTS_ENVIRONMENT = +bin_PROGRAMS = +bin_SCRIPTS = +dist_commands_DATA = +dist_man_MANS = +dist_pkgdata_SCRIPTS = +dist_sbin_SCRIPTS = +man_MANS = +noinst_HEADERS = +noinst_LIBRARIES = +noinst_PROGRAMS = +noinst_SCRIPTS = + +EXTRA_DIST += README.hwtables soexpand.pl regress + +ro_c = echo '/* -*- mode: c; buffer-read-only: t -*- */' + +SUFFIXES = .in +.in: + $(PERL) $(srcdir)/soexpand.pl -I$(srcdir) < $< | \ + sed -e 's,[@]LOGDIR[@],$(LOGDIR),g' \ + -e 's,[@]PKIDIR[@],$(PKIDIR),g' \ + -e 's,[@]RUNDIR[@],$(RUNDIR),g' \ + -e 's,[@]pkgdatadir[@],$(pkgdatadir),g' \ + -e 's,[@]PERL[@],$(PERL),g' > $@ + +include lib/automake.mk +include secchan/automake.mk +include controller/automake.mk +include utilities/automake.mk +include udatapath/automake.mk +include tests/automake.mk +include include/automake.mk +include third-party/automake.mk +include debian/automake.mk +include hw-lib/automake.mk diff --git a/openflow/README b/openflow/README new file mode 100644 index 00000000..a9cca172 --- /dev/null +++ b/openflow/README @@ -0,0 +1,110 @@ + OpenFlow Reference Release + +What is OpenFlow? +----------------- + +OpenFlow is a flow-based switch specification designed to enable +researchers to run experiments in live networks. OpenFlow is based on a +simple Ethernet flow switch that exposes a standardized interface for +adding and removing flow entries. + +An OpenFlow switch consists of three parts: (1) A "flow table" in +which each flow entry is associated with an action telling the switch +how to process the flow, (2) a "secure channel" connecting the switch +to a remote process (a controller), allowing commands and packets to +be sent between the controller and the switch, and (3) an OpenFlow +protocol implementation, providing an open and standard way for a +controller to talk to the switch. + +An OpenFlow switch can thus serve as a simple datapath element that +forwards packets between ports according to flow actions defined by +the controller using OpenFlow commands. Example actions are: + + - Forward this flow's packets to the given port(s) + - Drop this flow's packets + - Encapsulate and forward this flow's packets to the controller. + +The OpenFlow switch is defined in detail in the OpenFlow switch +Specification [2]. + +What's here? +------------ + +This distribution includes one reference implementations of an +OpenFlow switch. This implementation has the following components: + + - ofdatapath, which implements the flow table in user space. + + - ofprotocol, a program that implements the secure channel + component of the reference switch. + + - dpctl, a tool for configuring the switch. + +This distribution includes some additional software as well: + + - controller, a simple program that connects to any number of + OpenFlow switches, commanding them to act as regular MAC + learning switches. + + - vlogconf, a utility that can adjust the logging levels of a + running ofprotocol or controller. + + - ofp-pki, a utility for creating and managing the public-key + infrastructure for OpenFlow switches. + + - A patch to tcpdump that enables it to parse OpenFlow + messages. + + - A regression suite that tests OpenFlow functionality, please + see regress/README. + + - A Wireshark dissector that can decode the OpenFlow wire + protocol. Please see utilities/wireshark_dissectors/README. + +For installation instructions, read INSTALL. Each userspace program +is also accompanied by a manpage. + +What's NOT here? +---------------- + +The reference implementation no longer includes the Linux kernel module +or the NetFPGA implementation. The OpenFlow consortium intends to +release these separately from the reference design. + +Platform support +---------------- + +Other than the userspace switch implementation, the software in the +OpenFlow distribution should compile under Unix-like environments such +as Linux, FreeBSD, Mac OS X, and Solaris. Our primary test environment +is Debian GNU/Linux. Please contact us with portability-related bug +reports or patches. + +The userspace datapath implementation should be easy to port to +Unix-like systems. The interface to network devices, in netdev.c, is +the code most likely to need changes. So far, only Linux is +supported. We welcome ports to other platforms. + +GCC is the expected compiler. + +Bugs/Shortcomings +----------------- + +- The flow table does not support the "normal processing" action. + +References +---------- + + [1] OpenFlow: Enabling Innovation in College Networks. Whitepaper. + + + [2] OpenFlow Switch Specification. + + +Contact +------- + +Public discussion list: openflow-discuss@openflowswitch.org +Direct e-mail: info@openflowswitch.org + +Web: http://openflowswitch.org/ diff --git a/openflow/README.hwtables b/openflow/README.hwtables new file mode 100644 index 00000000..6d982507 --- /dev/null +++ b/openflow/README.hwtables @@ -0,0 +1,39 @@ +Hardware Table Support -*- text -*- +---------------------- + +The OpenFlow reference implementation in this distribution provides a +mechanism to support hardware that can accelerate OpenFlow switching. +The mechanism consists of the ability to add a "hardware acceleration" +switching table ahead of the software switching tables implemented by +the reference implementation. The hardware switching table is +expected to handle any incoming packets that it can on its own. Any +packets that it cannot handle itself it may pass up to the software +table implementations. + +Hardware table implementation are provided as a library and built +in the userspace datapath executable. + +Creating a hardware table module is straightforward. Create a +directory in the openflow source tree named hw-lib/NAME, +where NAME identifies the hardware that the module supports. Populate +that directory with the C source files that comprise the module, plus +a file named automake.mk that specifies how to build the module in +the hw-lib directory. This distribution includes a "skeleton" hardware +library that demonstrates how this works. + +When you perform 'configure', specify each NAME that identifies a +library to be included on the OpenFlow configure script command as +the argument to --enable-hw-lib, e.g.: + ./configure --enable-hw-lib=NAME + +Each hardware table library's code is encapsulated in a directory, so +it is easy to separate a hardware table implementation from OpenFlow. +Simply package up the contents of the hw-lib/NAME directory and +distribute it for builders to extract into their distribution +directory. + +Included in this distribution is a dummy hardware table to aid in beginning +your own hardware table port, it is located in the hw-lib/skeleton +folder. Also included is a fully functional NetFPGA hardware table that can run +as a 1Gbx4 port line-rate OpenFlow switch. Information and instructions for its +use can be found in the hw-lib/nf2/README file. diff --git a/openflow/README.kernel b/openflow/README.kernel new file mode 100644 index 00000000..95ce7564 --- /dev/null +++ b/openflow/README.kernel @@ -0,0 +1,18 @@ +Kernel-mode Support -*- text -*- +------------------- + +The OpenFlow reference implementation no longer includes a kernel module +that implements the datapath. A separate release with kernel-mode support +is expected in 1H2010. + +The release you downloaded *may* include the kernel module source files +depending upon the method used to obtain the release. If you downloaded the +release as a compressed tar file (.tar.gz) then you will *not* have the +source for the kernel module. If you downloaded the release directly from +git then you will have the source. + +Please note that if you obtained the release via git that the kernel module +source is not built by default and does not implement all features. + +Please check the OpenFlow website or subscribe to the openflow-announce +mailing list for updates on the kernel-mode implementation. diff --git a/openflow/acinclude.m4 b/openflow/acinclude.m4 new file mode 100644 index 00000000..7ccfbaa4 --- /dev/null +++ b/openflow/acinclude.m4 @@ -0,0 +1,309 @@ +# -*- autoconf -*- + +# Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford +# Junior University +# +# We are making the OpenFlow specification and associated documentation +# (Software) available for public use and benefit with the expectation +# that others will use, modify and enhance the Software and contribute +# those enhancements back to the community. However, since we would +# like to make the Software available for broadest use, with as few +# restrictions as possible permission is hereby granted, free of +# charge, to any person obtaining a copy of this Software to deal in +# the Software under the copyrights without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# The name and trademarks of copyright holder(s) may NOT be used in +# advertising or publicity pertaining to the Software or any +# derivatives without specific, written prior permission. + +dnl OFP_CHECK_LINUX(OPTION, VERSION, VARIABLE, CONDITIONAL) +dnl +dnl Configure linux kernel source tree +AC_DEFUN([OFP_CHECK_LINUX], [ + AC_ARG_WITH([$1], + [AC_HELP_STRING([--with-$1=/path/to/linux-$2], + [Specify the linux $2 kernel module build envrionment and sources])], + [path="$withval"], [path=])dnl + if test -n "$path"; then + path=`eval echo "$path"` + + AC_MSG_CHECKING([for $path directory]) + if test -d "$path" && test -d "$path/build" ; then + AC_MSG_RESULT([yes]) + if test -d "$path/source" ; then + $3=$path/build + $4=$path/source + else + $3=$path/build + $4=$path/build + fi + AC_SUBST($3) + AC_SUBST($4) + else + AC_MSG_RESULT([no]) + AC_ERROR([source dir $path doesn't exist]) + fi + + AC_MSG_CHECKING([for $path kernel version]) + patchlevel=`sed -n 's/^PATCHLEVEL = //p' "$KBLD26/Makefile"` + sublevel=`sed -n 's/^SUBLEVEL = //p' "$KBLD26/Makefile"` + AC_MSG_RESULT([2.$patchlevel.$sublevel]) + if test "2.$patchlevel" != '$2'; then + AC_ERROR([Linux kernel source in $path is not version $2]) + fi + if ! test -e $KBLD26/include/linux/version.h || \ + ! test -e $KBLD26/include/linux/autoconf.h; then + AC_MSG_ERROR([Linux kernel source in $path is not configured]) + fi + m4_if($2, [2.6], [OFP_CHECK_LINUX26_COMPAT]) + fi + AM_CONDITIONAL($5, test -n "$path") +]) + +dnl OFP_GREP_IFELSE(FILE, REGEX, IF-MATCH, IF-NO-MATCH) +dnl +dnl Greps FILE for REGEX. If it matches, runs IF-MATCH, otherwise IF-NO-MATCH. +AC_DEFUN([OFP_GREP_IFELSE], [ + AC_MSG_CHECKING([whether $2 matches in $1]) + grep '$2' $1 >/dev/null 2>&1 + status=$? + case $status in + 0) + AC_MSG_RESULT([yes]) + $3 + ;; + 1) + AC_MSG_RESULT([no]) + $4 + ;; + *) + AC_MSG_ERROR([grep exited with status $status]) + ;; + esac +]) + +dnl OFP_DEFINE(NAME) +dnl +dnl Defines NAME to 1 in kcompat.h. +AC_DEFUN([OFP_DEFINE], [ + echo '#define $1 1' >> datapath/linux-2.6/kcompat.h.new +]) + +AC_DEFUN([OFP_CHECK_VETH], [ + AC_MSG_CHECKING([whether to build veth module]) + if test "$sublevel" = 18; then + AC_MSG_RESULT([yes]) + AC_SUBST([BUILD_VETH], 1) + else + AC_MSG_RESULT([no]) + fi +]) + +dnl OFP_CHECK_LINUX26_COMPAT +dnl +dnl Runs various Autoconf checks on the Linux 2.6 kernel source in +dnl the directory in $KSRC26. +AC_DEFUN([OFP_CHECK_LINUX26_COMPAT], [ + rm -f datapath/linux-2.6/kcompat.h.new + mkdir -p datapath/linux-2.6 + : > datapath/linux-2.6/kcompat.h.new + OFP_GREP_IFELSE([$KSRC26/include/linux/skbuff.h], [skb_transport_header], + [OFP_DEFINE([HAVE_SKBUFF_HEADER_HELPERS])]) + OFP_GREP_IFELSE([$KSRC26/include/linux/skbuff.h], [raw], + [OFP_DEFINE([HAVE_MAC_RAW])]) + OFP_GREP_IFELSE([$KSRC26/include/linux/skbuff.h], + [skb_copy_from_linear_data_offset], + [OFP_DEFINE([HAVE_SKB_COPY_FROM_LINEAR_DATA_OFFSET])]) + OFP_GREP_IFELSE([$KSRC26/include/net/netlink.h], [NLA_NUL_STRING], + [OFP_DEFINE([HAVE_NLA_NUL_STRING])]) + OFP_CHECK_VETH + if cmp -s datapath/linux-2.6/kcompat.h.new \ + datapath/linux-2.6/kcompat.h >/dev/null 2>&1; then + rm datapath/linux-2.6/kcompat.h.new + else + mv datapath/linux-2.6/kcompat.h.new datapath/linux-2.6/kcompat.h + fi +]) + +dnl Checks for --enable-hw-tables and substitutes HW_TABLES to any +dnl requested hardware table modules. +AC_DEFUN([OFP_CHECK_HWTABLES], + [AC_ARG_ENABLE( + [hw-tables], + [AC_HELP_STRING([--enable-hw-tables=MODULE...], + [Configure and build the specified externally supplied + hardware table support modules])]) + case "${enable_hw_tables}" in # ( + yes) + AC_MSG_ERROR([--enable-hw-tables has a required argument]) + ;; # ( + ''|no) + hw_tables= + ;; # ( + *) + hw_tables=`echo "$enable_hw_tables" | sed 's/,/ /g'` + ;; + esac + for d in $hw_tables; do + mk=datapath/hwtable_$d/Modules.mk + if test ! -e $srcdir/$mk; then + AC_MSG_ERROR([--enable-hw-tables=$d specified but $mk is missing]) + fi + HW_TABLES="$HW_TABLES \$(top_srcdir)/$mk" + done + AC_SUBST(HW_TABLES)]) + +dnl Checks for --enable-hw-lib and substitutes BUILD_HW_LIBS and plat name +AC_DEFUN([OFP_CHECK_HWLIBS], + [AC_ARG_ENABLE( + [hw-lib], + [AC_HELP_STRING([--enable-hw-lib=PLATFORM], + [Configure and build the specified externally supplied + hardware library: lb4g, t2ref, scorref or nf2])]) + case "${enable_hw_lib}" in # ( + yes) + AC_MSG_ERROR([--enable-hw-lib has a required argument]) + ;; # ( + ''|no) + hw_lib= + NF2=no + LB4G=no + T2REF=no + SCORREF=no + BUILD_HW_LIBS=no + ;; # ( + nf2) + NF2=yes + LB4G=no + T2REF=no + SCORREF=no + hw_lib=$enable_hw_lib + BUILD_HW_LIBS=yes + ;; # ( + lb4g) + NF2=no + LB4G=yes + T2REF=no + SCORREF=no + hw_lib=$enable_hw_lib + BUILD_HW_LIBS=yes + ;; # ( + t2ref) + NF2=no + LB4G=no + T2REF=yes + SCORREF=no + hw_lib=$enable_hw_lib + BUILD_HW_LIBS=yes + ;; # ( + scorref) + NF2=no + LB4G=no + SCORREF=yes + T2REF=no + hw_lib=$enable_hw_lib + BUILD_HW_LIBS=yes + ;; # ( + *) + AC_MSG_ERROR([--enable-hw-lib: Unknown platform: ${enable_hw_lib}]) + BUILD_HW_LIBS=no + ;; + esac + if test $BUILD_HW_LIBS = yes; then + if test -e "$srcdir/hw-lib/automake.mk"; then + : + else + AC_MSG_ERROR([cannot configure HW libraries without "hw-lib" directory]) + fi + AC_DEFINE([BUILD_HW_LIBS], [1], + [Whether the OpenFlow hardware libraries are available]) + fi + if test $NF2 = yes; then + AC_DEFINE([NF2], [1], + [Support NetFPGA platform]) + fi + if test $LB4G = yes; then + AC_DEFINE([LB4G], [1], + [Support Stanford-LB4G platform]) + fi + if test $T2REF = yes; then + AC_DEFINE([T2REF], [1], + [Support Broadcom 56634 reference platform]) + fi + if test $SCORREF = yes; then + AC_DEFINE([SCORREF], [1], + [Support Broadcom 56820 reference platform]) + fi + AM_CONDITIONAL([NF2], [test $NF2 = yes]) + AM_CONDITIONAL([LB4G], [test $LB4G = yes]) + AM_CONDITIONAL([T2REF], [test $T2REF = yes]) + AM_CONDITIONAL([SCORREF], [test $SCORREF = yes]) + AM_CONDITIONAL([BUILD_HW_LIBS], [test $BUILD_HW_LIBS = yes]) + AC_SUBST(HW_LIB)]) + +dnl Checks for net/if_packet.h. +AC_DEFUN([OFP_CHECK_IF_PACKET], + [AC_CHECK_HEADER([net/if_packet.h], + [HAVE_IF_PACKET=yes], + [HAVE_IF_PACKET=no]) + AM_CONDITIONAL([HAVE_IF_PACKET], [test "$HAVE_IF_PACKET" = yes]) + if test "$HAVE_IF_PACKET" = yes; then + AC_DEFINE([HAVE_IF_PACKET], [1], + [Define to 1 if net/if_packet.h is available.]) + fi]) + +dnl Checks for dpkg-buildpackage. If this is available then we check +dnl that the Debian packaging is functional at "make distcheck" time. +AC_DEFUN([OFP_CHECK_DPKG_BUILDPACKAGE], + [AC_CHECK_PROG([HAVE_DPKG_BUILDPACKAGE], [dpkg-buildpackage], [yes], [no]) + AM_CONDITIONAL([HAVE_DPKG_BUILDPACKAGE], + [test $HAVE_DPKG_BUILDPACKAGE = yes])]) + +dnl ---------------------------------------------------------------------- +dnl These macros are from GNU PSPP, with the following original license: +dnl Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl OFP_CHECK_CC_OPTION([OPTION], [ACTION-IF-ACCEPTED], [ACTION-IF-REJECTED]) +dnl Check whether the given C compiler OPTION is accepted. +dnl If so, execute ACTION-IF-ACCEPTED, otherwise ACTION-IF-REJECTED. +AC_DEFUN([OFP_CHECK_CC_OPTION], +[ + m4_define([ofp_cv_name], [ofp_cv_[]m4_translit([$1], [-], [_])])dnl + AC_CACHE_CHECK([whether $CC accepts $1], [ofp_cv_name], + [ofp_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $1" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,)], [ofp_cv_name[]=yes], [ofp_cv_name[]=no]) + CFLAGS="$ofp_save_CFLAGS"]) + if test $ofp_cv_name = yes; then + m4_if([$2], [], [;], [$2]) + else + m4_if([$3], [], [:], [$3]) + fi +]) + +dnl OFP_ENABLE_OPTION([OPTION]) +dnl Check whether the given C compiler OPTION is accepted. +dnl If so, add it to CFLAGS. +dnl Example: OFP_ENABLE_OPTION([-Wdeclaration-after-statement]) +AC_DEFUN([OFP_ENABLE_OPTION], + [OFP_CHECK_CC_OPTION([$1], [CFLAGS="$CFLAGS $1"])]) +dnl ---------------------------------------------------------------------- diff --git a/openflow/boot.sh b/openflow/boot.sh new file mode 100755 index 00000000..97921fac --- /dev/null +++ b/openflow/boot.sh @@ -0,0 +1,14 @@ +#! /bin/sh + +set -e + +# Generate list of files in debian/ to distribute. +(echo '# Automatically generated by boot.sh (from Git tree).' && + printf 'EXTRA_DIST += \\\n' && + git ls-files debian | grep -v '^debian/\.gitignore$' | + sed -e 's/\(.*\)/ \1 \\/' -e '$s/ \\//') > debian/automake.mk + +cat debian/control.in > debian/control + +# Bootstrap configure system from .ac/.am files +autoreconf --install --force diff --git a/openflow/configure.ac b/openflow/configure.ac new file mode 100644 index 00000000..13064f68 --- /dev/null +++ b/openflow/configure.ac @@ -0,0 +1,94 @@ +# Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford +# Junior University +# +# We are making the OpenFlow specification and associated documentation +# (Software) available for public use and benefit with the expectation +# that others will use, modify and enhance the Software and contribute +# those enhancements back to the community. However, since we would +# like to make the Software available for broadest use, with as few +# restrictions as possible permission is hereby granted, free of +# charge, to any person obtaining a copy of this Software to deal in +# the Software under the copyrights without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# The name and trademarks of copyright holder(s) may NOT be used in +# advertising or publicity pertaining to the Software or any +# derivatives without specific, written prior permission. + +AC_PREREQ(2.60) +AC_INIT([openflow], [1.0.0], [openflow-discuss@openflowswitch.org]) +NX_BUILDNR +AC_CONFIG_SRCDIR([README.hwtables]) +AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_AUX_DIR([build-aux]) +AC_CONFIG_HEADERS([config.h]) +AM_INIT_AUTOMAKE + +AC_PROG_CC +AM_PROG_CC_C_O +AC_PROG_CPP +AC_PROG_RANLIB +AC_PROG_MKDIR_P + +AC_ARG_VAR([PERL], [path to Perl interpreter]) +AC_PATH_PROG([PERL], perl, no) +if test "$PERL" = no; then + AC_MSG_ERROR([Perl interpreter not found in $PATH or $PERL.]) +fi + +OFP_CHECK_LIBOPENFLOW +OFP_CHECK_IF_PACKET +OFP_CHECK_HWTABLES +OFP_CHECK_HWLIBS +AC_SYS_LARGEFILE + +AC_CHECK_FUNCS([strsignal]) + +AC_ARG_VAR(KARCH, [Kernel Architecture String]) +AC_SUBST(KARCH) +#OFP_CHECK_LINUX(l26, 2.6, KBLD26, KSRC26, L26_ENABLED) + +OFP_CHECK_DPKG_BUILDPACKAGE + +OFP_ENABLE_OPTION([-Wall]) +OFP_ENABLE_OPTION([-Wno-sign-compare]) +OFP_ENABLE_OPTION([-Wpointer-arith]) +OFP_ENABLE_OPTION([-Wdeclaration-after-statement]) +OFP_ENABLE_OPTION([-Wformat-security]) +OFP_ENABLE_OPTION([-Wswitch-enum]) +OFP_ENABLE_OPTION([-Wunused-parameter]) +OFP_ENABLE_OPTION([-Wstrict-aliasing]) +OFP_ENABLE_OPTION([-Wbad-function-cast]) +OFP_ENABLE_OPTION([-Wcast-align]) +OFP_ENABLE_OPTION([-Wstrict-prototypes]) +OFP_ENABLE_OPTION([-Wold-style-definition]) +OFP_ENABLE_OPTION([-Wmissing-prototypes]) +OFP_ENABLE_OPTION([-Wmissing-field-initializers]) +OFP_ENABLE_OPTION([-Wno-override-init]) + +AC_CONFIG_FILES([Makefile +]) + +#AC_CONFIG_FILES([Makefile +#datapath/Makefile +#datapath/linux-2.6/Kbuild +#datapath/linux-2.6/Makefile +#datapath/linux-2.6/Makefile.main +#]) + +AC_OUTPUT diff --git a/openflow/controller/.dirstamp b/openflow/controller/.dirstamp new file mode 100644 index 00000000..e69de29b diff --git a/openflow/controller/.gitignore b/openflow/controller/.gitignore new file mode 100644 index 00000000..8736bbc1 --- /dev/null +++ b/openflow/controller/.gitignore @@ -0,0 +1,4 @@ +/Makefile +/Makefile.in +/controller +/controller.8 diff --git a/openflow/controller/automake.mk b/openflow/controller/automake.mk new file mode 100644 index 00000000..ff9f627c --- /dev/null +++ b/openflow/controller/automake.mk @@ -0,0 +1,8 @@ +bin_PROGRAMS += controller/controller +man_MANS += controller/controller.8 +DISTCLEANFILES += controller/controller.8 + +controller_controller_SOURCES = controller/controller.c +controller_controller_LDADD = lib/libopenflow.a $(FAULT_LIBS) $(SSL_LIBS) + +EXTRA_DIST += controller/controller.8.in diff --git a/openflow/controller/controller.8.in b/openflow/controller/controller.8.in new file mode 100644 index 00000000..c2b65cfb --- /dev/null +++ b/openflow/controller/controller.8.in @@ -0,0 +1,150 @@ +.ds PN controller + +.TH controller 8 "May 2008" "OpenFlow" "OpenFlow Manual" + +.SH NAME +controller \- simple OpenFlow controller reference implementation + +.SH SYNOPSIS +.B controller +[\fIoptions\fR] \fImethod\fR \fB[\fImethod\fR]\&... + +.SH DESCRIPTION +A sample OpenFlow controller which functions as an L2 MAC-learning +switch or hub. \fBcontroller\fR can manage a remote datapath through +a secure channel (see \fBofprotocol(8)\fR). It can also connect directly +to a local datapath via Netlink. + +\fBcontroller\fR controls one or more OpenFlow switches, specified as +one or more of the following OpenFlow connection methods: + +.TP +\fBpssl:\fR[\fIport\fR] +Listens for SSL connections from remote OpenFlow switches on +\fIport\fR (default: 6633). The \fB--private-key\fR, +\fB--certificate\fR, and \fB--ca-cert\fR options are mandatory when +this form is used. + +.TP +\fBptcp:\fR[\fIport\fR] +Listens for TCP connections from remote OpenFlow switches on +\fIport\fR (default: 6633). + +.TP +\fBpunix:\fIfile\fR +Listens for connections from OpenFlow switches on the Unix domain +server socket named \fIfile\fR. + +.TP +\fBnl:\fIdp_idx\fR +The local Netlink datapath numbered \fIdp_idx\fR, as configured with +.BR dpctl (8). +This form requires that the local host has the OpenFlow kernel +module for Linux loaded. + +.TP +\fBssl:\fIhost\fR[\fB:\fIport\fR] +The specified SSL \fIport\fR (default: 6633) on the given remote +\fIhost\fR. The \fB--private-key\fR, \fB--certificate\fR, and +\fB--ca-cert\fR options are mandatory when this form is used. + +.TP +\fBtcp:\fIhost\fR[\fB:\fIport\fR] +The specified TCP \fIport\fR (default: 6633) on the given remote +\fIhost\fR. + +.TP +\fBunix:\fIfile\fR +The Unix domain server socket named \fIfile\fR. + +.SH OPTIONS +.TP +\fB-p\fR, \fB--private-key=\fIprivkey.pem\fR +Specifies a PEM file containing the private key used as the switch's +identity for SSL connections to the controller. + +.TP +\fB-c\fR, \fB--certificate=\fIcert.pem\fR +Specifies a PEM file containing a certificate, signed by the +controller's certificate authority (CA), that certifies the switch's +private key to identify a trustworthy switch. + +.TP +\fB-C\fR, \fB--ca-cert=\fIswitch-cacert.pem\fR +Specifies a PEM file containing the CA certificate used to verify that +the switch is connected to a trustworthy controller. + +.TP +\fB--peer-ca-cert=\fIcontroller-cacert.pem\fR +Specifies a PEM file that contains one or more additional certificates +to send to switches. \fIcontroller-cacert.pem\fR should be the CA +certificate used to sign the controller's own certificate (the +certificate specified on \fB-c\fR or \fB--certificate\fR). + +This option is not useful in normal operation, because the switch must +already have the controller CA certificate for it to have any +confidence in the controller's identity. However, this option allows +a newly installed switch to obtain the controller CA certificate on +first boot using, e.g., the \fB--bootstrap-ca-cert\fR option to +\fBofprotocol\fR(8). + +.TP +.BR \-n ", " \-\^\-noflow +By default, the controller sets up a flow in each OpenFlow switch +whenever it receives a packet whose destination is known due through +MAC learning. This option disables flow setup, so that every packet +in the network passes through the controller. + +This option is most useful for debugging. It reduces switching +performance, so it should not be used in production. + +.TP +\fB--max-idle=\fIsecs\fR|\fBpermanent\fR +Sets \fIsecs\fR as the number of seconds that a flow set up by the +controller will remain in the switch's flow table without any matching +packets being seen. If \fBpermanent\fR is specified, which is not +recommended, flows will never expire. The default is 60 seconds. + +This option affects only flows set up by the OpenFlow controller. In +some configurations, the OpenFlow secure channel can set up some flows +on its own. To set the idle time for those flows, pass +\fB--max-idle\fR to \fBofprotocol\fR(8). + +This option has no effect when \fB-n\fR (or \fB--noflow\fR) is in use +(because the controller does not set up flows in that case). + +.TP +.BR \-H ", " \-\^\-hub +By default, the controller acts as an L2 MAC-learning switch. This +option changes its behavior to that of a hub that floods packets on +all but the incoming port. + +If \fB-H\fR (or \fB--hub\fR) and \fB-n\fR (or \fB--noflow\fR) are used +together, then the cumulative effect is that every packet passes +through the controller and every packet is flooded. + +This option is most useful for debugging. It reduces switching +performance, so it should not be used in production. + +.so lib/daemon.man +.so lib/vlog.man +.so lib/common.man + +.SH EXAMPLES + +.TP +To connect directly to local datapath 0 over netlink (Linux only): + +.B % controller nl:0 + +.TP +To bind locally to port 6633 (the default) and wait for incoming connections from OpenFlow switches: + +.B % controller ptcp: + +.SH "SEE ALSO" + +.BR dpctl (8), +.BR ofprotocol (8), +.BR ofdatapath (8), +.BR vlogconf (8) diff --git a/openflow/controller/controller.c b/openflow/controller/controller.c new file mode 100644 index 00000000..6eec5906 --- /dev/null +++ b/openflow/controller/controller.c @@ -0,0 +1,336 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "command-line.h" +#include "compiler.h" +#include "daemon.h" +#include "fault.h" +#include "learning-switch.h" +#include "ofpbuf.h" +#include "openflow/openflow.h" +#include "poll-loop.h" +#include "rconn.h" +#include "timeval.h" +#include "util.h" +#include "vconn-ssl.h" +#include "vconn.h" +#include "vlog-socket.h" + +#include "vlog.h" +#define THIS_MODULE VLM_controller + +#define MAX_SWITCHES 4096 +#define MAX_LISTENERS 4096 + +struct switch_ { + struct lswitch *lswitch; + struct rconn *rconn; +}; + +/* Learn the ports on which MAC addresses appear? */ +static bool learn_macs = true; + +/* Set up flows? (If not, every packet is processed at the controller.) */ +static bool setup_flows = true; + +/* --max-idle: Maximum idle time, in seconds, before flows expire. */ +static int max_idle = 60; + +static int do_switching(struct switch_ *); +static void new_switch(struct switch_ *, struct vconn *, const char *name); +static void parse_options(int argc, char *argv[]); +static void usage(void) NO_RETURN; + +int +main(int argc, char *argv[]) +{ + struct switch_ switches[MAX_SWITCHES]; + struct pvconn *listeners[MAX_LISTENERS]; + int n_switches, n_listeners; + int retval; + int i; + + set_program_name(argv[0]); + register_fault_handlers(); + time_init(); + vlog_init(); + parse_options(argc, argv); + signal(SIGPIPE, SIG_IGN); + + if (argc - optind < 1) { + ofp_fatal(0, "at least one vconn argument required; " + "use --help for usage"); + } + + n_switches = n_listeners = 0; + for (i = optind; i < argc; i++) { + const char *name = argv[i]; + struct vconn *vconn; + int retval; + + retval = vconn_open(name, OFP_VERSION, &vconn); + if (!retval) { + if (n_switches >= MAX_SWITCHES) { + ofp_fatal(0, "max %d switch connections", n_switches); + } + new_switch(&switches[n_switches++], vconn, name); + continue; + } else if (retval == EAFNOSUPPORT) { + struct pvconn *pvconn; + retval = pvconn_open(name, &pvconn); + if (!retval) { + if (n_listeners >= MAX_LISTENERS) { + ofp_fatal(0, "max %d passive connections", n_listeners); + } + listeners[n_listeners++] = pvconn; + } + } + if (retval) { + VLOG_ERR("%s: connect: %s", name, strerror(retval)); + } + } + if (n_switches == 0 && n_listeners == 0) { + ofp_fatal(0, "no active or passive switch connections"); + } + + die_if_already_running(); + daemonize(); + + retval = vlog_server_listen(NULL, NULL); + if (retval) { + ofp_fatal(retval, "Could not listen for vlog connections"); + } + + while (n_switches > 0 || n_listeners > 0) { + int iteration; + int i; + + /* Accept connections on listening vconns. */ + for (i = 0; i < n_listeners && n_switches < MAX_SWITCHES; ) { + struct vconn *new_vconn; + int retval; + + retval = pvconn_accept(listeners[i], OFP_VERSION, &new_vconn); + if (!retval || retval == EAGAIN) { + if (!retval) { + new_switch(&switches[n_switches++], new_vconn, "tcp"); + } + i++; + } else { + pvconn_close(listeners[i]); + listeners[i] = listeners[--n_listeners]; + } + } + + /* Do some switching work. Limit the number of iterations so that + * callbacks registered with the poll loop don't starve. */ + for (iteration = 0; iteration < 50; iteration++) { + bool progress = false; + for (i = 0; i < n_switches; ) { + struct switch_ *this = &switches[i]; + int retval = do_switching(this); + if (!retval || retval == EAGAIN) { + if (!retval) { + progress = true; + } + i++; + } else { + rconn_destroy(this->rconn); + lswitch_destroy(this->lswitch); + switches[i] = switches[--n_switches]; + } + } + if (!progress) { + break; + } + } + for (i = 0; i < n_switches; i++) { + struct switch_ *this = &switches[i]; + lswitch_run(this->lswitch, this->rconn); + } + + /* Wait for something to happen. */ + if (n_switches < MAX_SWITCHES) { + for (i = 0; i < n_listeners; i++) { + pvconn_wait(listeners[i]); + } + } + for (i = 0; i < n_switches; i++) { + struct switch_ *sw = &switches[i]; + rconn_run_wait(sw->rconn); + rconn_recv_wait(sw->rconn); + lswitch_wait(sw->lswitch); + } + poll_block(); + } + + return 0; +} + +static void +new_switch(struct switch_ *sw, struct vconn *vconn, const char *name) +{ + sw->rconn = rconn_new_from_vconn(name, vconn); + sw->lswitch = lswitch_create(sw->rconn, learn_macs, + setup_flows ? max_idle : -1); +} + +static int +do_switching(struct switch_ *sw) +{ + unsigned int packets_sent; + struct ofpbuf *msg; + + packets_sent = rconn_packets_sent(sw->rconn); + + msg = rconn_recv(sw->rconn); + if (msg) { + lswitch_process_packet(sw->lswitch, sw->rconn, msg); + ofpbuf_delete(msg); + } + rconn_run(sw->rconn); + + return (!rconn_is_alive(sw->rconn) ? EOF + : rconn_packets_sent(sw->rconn) != packets_sent ? 0 + : EAGAIN); +} + +static void +parse_options(int argc, char *argv[]) +{ + enum { + OPT_MAX_IDLE = UCHAR_MAX + 1, + OPT_PEER_CA_CERT, + VLOG_OPTION_ENUMS + }; + static struct option long_options[] = { + {"hub", no_argument, 0, 'H'}, + {"noflow", no_argument, 0, 'n'}, + {"max-idle", required_argument, 0, OPT_MAX_IDLE}, + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + DAEMON_LONG_OPTIONS, + VLOG_LONG_OPTIONS, +#ifdef HAVE_OPENSSL + VCONN_SSL_LONG_OPTIONS + {"peer-ca-cert", required_argument, 0, OPT_PEER_CA_CERT}, +#endif + {0, 0, 0, 0}, + }; + char *short_options = long_options_to_short_options(long_options); + + for (;;) { + int indexptr; + int c; + + c = getopt_long(argc, argv, short_options, long_options, &indexptr); + if (c == -1) { + break; + } + + switch (c) { + case 'H': + learn_macs = false; + break; + + case 'n': + setup_flows = false; + break; + + case OPT_MAX_IDLE: + if (!strcmp(optarg, "permanent")) { + max_idle = OFP_FLOW_PERMANENT; + } else { + max_idle = atoi(optarg); + if (max_idle < 1 || max_idle > 65535) { + ofp_fatal(0, "--max-idle argument must be between 1 and " + "65535 or the word 'permanent'"); + } + } + break; + + case 'h': + usage(); + + case 'V': + printf("%s "VERSION" compiled "__DATE__" "__TIME__"\n", argv[0]); + exit(EXIT_SUCCESS); + + VLOG_OPTION_HANDLERS + DAEMON_OPTION_HANDLERS + +#ifdef HAVE_OPENSSL + VCONN_SSL_OPTION_HANDLERS + + case OPT_PEER_CA_CERT: + vconn_ssl_set_peer_ca_cert_file(optarg); + break; +#endif + + case '?': + exit(EXIT_FAILURE); + + default: + abort(); + } + } + free(short_options); +} + +static void +usage(void) +{ + printf("%s: OpenFlow controller\n" + "usage: %s [OPTIONS] METHOD\n" + "where METHOD is any OpenFlow connection method.\n", + program_name, program_name); + vconn_usage(true, true, false); + daemon_usage(); + vlog_usage(); + printf("\nOther options:\n" + " -H, --hub act as hub instead of learning switch\n" + " -n, --noflow pass traffic, but don't add flows\n" + " --max-idle=SECS max idle time for new flows\n" + " -h, --help display this help message\n" + " -V, --version display version information\n"); + exit(EXIT_SUCCESS); +} diff --git a/openflow/datapath/.gitignore b/openflow/datapath/.gitignore new file mode 100644 index 00000000..5a59a0d3 --- /dev/null +++ b/openflow/datapath/.gitignore @@ -0,0 +1,7 @@ +/Makefile +/Makefile.in +*.cmd +*.ko +*.mod.c +Module.symvers + diff --git a/openflow/datapath/Makefile.am b/openflow/datapath/Makefile.am new file mode 100644 index 00000000..7eed78d1 --- /dev/null +++ b/openflow/datapath/Makefile.am @@ -0,0 +1,27 @@ +SUBDIRS = +if L26_ENABLED +SUBDIRS += linux-2.6 +endif + +EXTRA_DIST = $(dist_headers) $(dist_sources) +EXTRA_DIST += hwtable_dummy/Modules.mk hwtable_dummy/hwtable_dummy.c +EXTRA_DIST += \ + hwtable_nf2/Modules.mk \ + hwtable_nf2/nf2.h \ + hwtable_nf2/nf2_hwapi.h \ + hwtable_nf2/nf2_reg.h \ + hwtable_nf2/nf2_flowtable.c \ + hwtable_nf2/nf2_flowtable.h \ + hwtable_nf2/nf2_lib.c \ + hwtable_nf2/nf2_lib.h \ + hwtable_nf2/nf2_procfs.c \ + hwtable_nf2/nf2_procfs.h \ + hwtable_nf2/nf2_openflow.c \ + hwtable_nf2/nf2_openflow.h \ + hwtable_nf2/openflow_switch.bit + +# Suppress warnings about GNU extensions in Modules.mk files. +AUTOMAKE_OPTIONS = -Wno-portability + +include Modules.mk +include linux-2.6/Modules.mk diff --git a/openflow/datapath/Modules.mk b/openflow/datapath/Modules.mk new file mode 100644 index 00000000..777dc658 --- /dev/null +++ b/openflow/datapath/Modules.mk @@ -0,0 +1,42 @@ +# Some modules should be built and distributed, e.g. openflow. +# +# Some modules should be distributed but not built, e.g. we do not build +# veth if the kernel in question already has it. +# +# Some modules should be built but not distributed, e.g. third-party +# hwtable modules. +both_modules = ofdatapath +build_modules = $(both_modules) # Modules to build +dist_modules = $(both_modules) # Modules to distribute + +ofdatapath_sources = \ + chain.c \ + crc32.c \ + datapath.c \ + dp_act.c \ + dp_dev.c \ + dp_notify.c \ + flow.c \ + forward.c \ + private-msg.c \ + table-hash.c \ + table-linear.c + +ofdatapath_headers = \ + chain.h \ + compat.h \ + crc32.h \ + datapath.h \ + dp_dev.h \ + flow.h \ + forward.h \ + dp_act.h \ + private-msg.h \ + table.h + +dist_sources = $(foreach module,$(dist_modules),$($(module)_sources)) +dist_headers = $(foreach module,$(dist_modules),$($(module)_headers)) +build_sources = $(foreach module,$(build_modules),$($(module)_sources)) +build_headers = $(foreach module,$(build_modules),$($(module)_headers)) +build_links = $(notdir $(build_sources)) +build_objects = $(notdir $(patsubst %.c,%.o,$(build_sources))) diff --git a/openflow/datapath/chain.c b/openflow/datapath/chain.c new file mode 100644 index 00000000..e75f77dc --- /dev/null +++ b/openflow/datapath/chain.c @@ -0,0 +1,270 @@ +/* + * Distributed under the terms of the GNU GPL version 2. + * Copyright (c) 2007, 2008, 2009 The Board of Trustees of The Leland + * Stanford Junior University + */ + +#include "chain.h" +#include "datapath.h" +#include "flow.h" +#include "table.h" +#include +#include +#include +#include + +static struct sw_table *(*create_hw_table_hook)(void); +static struct module *hw_table_owner; +static DEFINE_SPINLOCK(hook_lock); + +/* Attempts to append 'table' to the set of tables in 'chain'. Returns 0 or + * negative error. If 'table' is null it is assumed that table creation failed + * due to out-of-memory. */ +static int add_table(struct sw_chain *chain, struct sw_table *table, int emerg) +{ + if (table == NULL) + return -ENOMEM; + if (chain->n_tables >= CHAIN_MAX_TABLES) { + printk(KERN_EMERG "%s: too many tables in chain\n", + chain->dp->netdev->name); + table->destroy(table); + return -ENOBUFS; + } + if (emerg) + chain->emerg_table = table; + else + chain->tables[chain->n_tables++] = table; + return 0; +} + +/* Creates and returns a new chain associated with 'dp'. Returns NULL if the + * chain cannot be created. */ +struct sw_chain *chain_create(struct datapath *dp) +{ + struct sw_chain *chain = kzalloc(sizeof *chain, GFP_KERNEL); + if (chain == NULL) + goto error; + chain->dp = dp; + chain->owner = try_module_get(hw_table_owner) ? hw_table_owner : NULL; + if (chain->owner && create_hw_table_hook) { + struct sw_table *hwtable = create_hw_table_hook(); + if (!hwtable || add_table(chain, hwtable, 0)) + goto error; + } + + if (add_table(chain, table_hash2_create(0x1EDC6F41, TABLE_HASH_MAX_FLOWS, + 0x741B8CD7, TABLE_HASH_MAX_FLOWS), + 0) + || add_table(chain, table_linear_create(TABLE_LINEAR_MAX_FLOWS), 0) + || add_table(chain, table_linear_create(TABLE_LINEAR_MAX_FLOWS), 1)) + goto error; + return chain; + +error: + if (chain) + chain_destroy(chain); + return NULL; +} + +/* Searches 'chain' for a flow matching 'key', which must not have any wildcard + * fields. Returns the flow if successful, otherwise a null pointer. + * + * Caller must hold rcu_read_lock or dp_mutex. */ +struct sw_flow *chain_lookup(struct sw_chain *chain, + const struct sw_flow_key *key, int emerg) +{ + int i; + + BUG_ON(key->wildcards); + if (emerg) { + struct sw_table *t = chain->emerg_table; + struct sw_flow *flow = t->lookup(t, key); + t->n_lookup++; + if (flow) { + t->n_matched++; + return flow; + } + } else { + for (i = 0; i < chain->n_tables; i++) { + struct sw_table *t = chain->tables[i]; + struct sw_flow *flow = t->lookup(t, key); + t->n_lookup++; + if (flow) { + t->n_matched++; + return flow; + } + } + } + return NULL; +} + +/* Inserts 'flow' into 'chain', replacing any duplicate flow. Returns 0 if + * successful or a negative error. + * + * If successful, 'flow' becomes owned by the chain, otherwise it is retained + * by the caller. + * + * Caller must hold dp_mutex. */ +int chain_insert(struct sw_chain *chain, struct sw_flow *flow, int emerg) +{ + int i; + + might_sleep(); + if (emerg) { + struct sw_table *t = chain->emerg_table; + if (t->insert(t, flow)) + return 0; + } else { + for (i = 0; i < chain->n_tables; i++) { + struct sw_table *t = chain->tables[i]; + if (t->insert(t, flow)) + return 0; + } + } + return -ENOBUFS; +} + +/* Modifies actions in 'chain' that match 'key'. If 'strict' set, wildcards + * and priority must match. Returns the number of flows that were modified. + * + * Expensive in the general case as currently implemented, since it requires + * iterating through the entire contents of each table for keys that contain + * wildcards. Relatively cheap for fully specified keys. */ +int +chain_modify(struct sw_chain *chain, const struct sw_flow_key *key, + uint16_t priority, int strict, + const struct ofp_action_header *actions, size_t actions_len, + int emerg) +{ + int count = 0; + int i; + + if (emerg) { + struct sw_table *t = chain->emerg_table; + count += t->modify(t, key, priority, strict, + actions, actions_len); + } else { + for (i = 0; i < chain->n_tables; i++) { + struct sw_table *t = chain->tables[i]; + count += t->modify(t, key, priority, strict, + actions, actions_len); + } + } + return count; +} + +/* Checks whether the chain has an entry with the same priority which conflicts + * with 'key'. If 'strict' set, wildcards should also match. If 'strict' is not + * set, comparison is done 'module wildcards'. + * + * Returns 'true' if such an entry exists, 'false' otherwise. */ +int +chain_has_conflict(struct sw_chain *chain, const struct sw_flow_key *key, + uint16_t priority, int strict) +{ + int i; + + for (i = 0; i < chain->n_tables; i++) { + struct sw_table *t = chain->tables[i]; + if (t->has_conflict(t, key, priority, strict)) { + return true; + } + } + + return false; +} + +/* Deletes from 'chain' any and all flows that match 'key'. If 'out_port' + * is not OFPP_NONE, then matching entries must have that port as an + * argument for an output action. If 'strict" is set, then wildcards and + * priority must match. Returns the number of flows that were deleted. + * + * Expensive in the general case as currently implemented, since it requires + * iterating through the entire contents of each table for keys that contain + * wildcards. Relatively cheap for fully specified keys. + * + * Caller must hold dp_mutex. */ +int chain_delete(struct sw_chain *chain, const struct sw_flow_key *key, + uint16_t out_port, uint16_t priority, int strict, int emerg) +{ + int count = 0; + int i; + + might_sleep(); + if (emerg) { + struct sw_table *t = chain->emerg_table; + count += t->delete(chain->dp, t, key, + out_port, priority, strict); + } else { + for (i = 0; i < chain->n_tables; i++) { + struct sw_table *t = chain->tables[i]; + count += t->delete(chain->dp, t, key, + out_port, priority, strict); + } + } + return count; +} + +/* Performs timeout processing on all the tables in 'chain'. Returns the + * number of flow entries deleted through expiration. + * + * Expensive as currently implemented, since it iterates through the entire + * contents of each table. + * + * Caller must not hold dp_mutex, because individual tables take and release it + * as necessary. */ +int chain_timeout(struct sw_chain *chain) +{ + int count = 0; + int i; + + might_sleep(); + for (i = 0; i < chain->n_tables; i++) { + struct sw_table *t = chain->tables[i]; + count += t->timeout(chain->dp, t); + } + return count; +} + +/* Destroys 'chain', which must not have any users. */ +void chain_destroy(struct sw_chain *chain) +{ + int i; + struct sw_table *t = NULL; + + synchronize_rcu(); + for (i = 0; i < chain->n_tables; i++) { + t = chain->tables[i]; + if (t->destroy) + t->destroy(t); + } + t = chain->emerg_table; + if (t->destroy) + t->destroy(t); + module_put(chain->owner); + kfree(chain); +} + +int chain_set_hw_hook(struct sw_table *(*create_hw_table)(void), + struct module *owner) +{ + int retval = -EBUSY; + + spin_lock(&hook_lock); + if (!create_hw_table_hook) { + create_hw_table_hook = create_hw_table; + hw_table_owner = owner; + retval = 0; + } + spin_unlock(&hook_lock); + + return retval; +} +EXPORT_SYMBOL(chain_set_hw_hook); + +void chain_clear_hw_hook(void) +{ + create_hw_table_hook = NULL; + hw_table_owner = NULL; +} +EXPORT_SYMBOL(chain_clear_hw_hook); diff --git a/openflow/datapath/chain.h b/openflow/datapath/chain.h new file mode 100644 index 00000000..4b00aef6 --- /dev/null +++ b/openflow/datapath/chain.h @@ -0,0 +1,43 @@ +#ifndef CHAIN_H +#define CHAIN_H 1 + +#include + +struct sw_flow; +struct sw_flow_key; +struct ofp_action_header; +struct datapath; + + +#define TABLE_LINEAR_MAX_FLOWS 100 +#define TABLE_HASH_MAX_FLOWS 65536 + +/* Set of tables chained together in sequence from cheap to expensive. */ +#define CHAIN_MAX_TABLES 4 +struct sw_chain { + int n_tables; + struct sw_table *tables[CHAIN_MAX_TABLES]; + struct sw_table *emerg_table; + + struct datapath *dp; + struct module *owner; +}; + +struct sw_chain *chain_create(struct datapath *); +struct sw_flow *chain_lookup(struct sw_chain *, const struct sw_flow_key *, + int); +int chain_insert(struct sw_chain *, struct sw_flow *, int); +int chain_modify(struct sw_chain *, const struct sw_flow_key *, + uint16_t, int, const struct ofp_action_header *, size_t, int); +int chain_has_conflict(struct sw_chain *, const struct sw_flow_key *, + uint16_t, int); +int chain_delete(struct sw_chain *, const struct sw_flow_key *, uint16_t, + uint16_t, int, int); +int chain_timeout(struct sw_chain *); +void chain_destroy(struct sw_chain *); + +int chain_set_hw_hook(struct sw_table *(*create_hw_table)(void), + struct module *owner); +void chain_clear_hw_hook(void); + +#endif /* chain.h */ diff --git a/openflow/datapath/compat.h b/openflow/datapath/compat.h new file mode 100644 index 00000000..1915cd31 --- /dev/null +++ b/openflow/datapath/compat.h @@ -0,0 +1,12 @@ +#ifndef COMPAT_H +#define COMPAT_H 1 + +#include + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + +#include "compat26.h" + +#endif + +#endif /* compat.h */ diff --git a/openflow/datapath/crc32.c b/openflow/datapath/crc32.c new file mode 100644 index 00000000..3cb26c5a --- /dev/null +++ b/openflow/datapath/crc32.c @@ -0,0 +1,45 @@ +/* + * Distributed under the terms of the GNU GPL version 2. + * Copyright (c) 2007, 2008 The Board of Trustees of The Leland + * Stanford Junior University + */ + +#include +#include "crc32.h" + +void crc32_init(struct crc32 *crc, unsigned int polynomial) +{ + int i; + + for (i = 0; i < CRC32_TABLE_SIZE; ++i) { + unsigned int reg = i << 24; + int j; + for (j = 0; j < CRC32_TABLE_BITS; j++) { + int topBit = (reg & 0x80000000) != 0; + reg <<= 1; + if (topBit) + reg ^= polynomial; + } + crc->table[i] = reg; + } +} + +EXPORT_SYMBOL(crc32_init); + +unsigned int crc32_calculate(const struct crc32 *crc, + const void *data_, size_t n_bytes) +{ + // FIXME: this can be optimized by unrolling, see linux-2.6/lib/crc32.c. + const uint8_t *data = data_; + unsigned int result = 0; + size_t i; + + for (i = 0; i < n_bytes; i++) { + unsigned int top = result >> 24; + top ^= data[i]; + result = (result << 8) ^ crc->table[top]; + } + return result; +} + +EXPORT_SYMBOL(crc32_calculate); diff --git a/openflow/datapath/crc32.h b/openflow/datapath/crc32.h new file mode 100644 index 00000000..21a350a9 --- /dev/null +++ b/openflow/datapath/crc32.h @@ -0,0 +1,22 @@ +#ifndef CRC32_H +#define CRC32_H 1 + +#include +#ifndef __KERNEL__ +#include +#endif +#include + +#define CRC32_TABLE_BITS 8 +#define CRC32_TABLE_SIZE (1u << CRC32_TABLE_BITS) + +struct crc32 { + unsigned int table[CRC32_TABLE_SIZE]; +}; + +void crc32_init(struct crc32 *, unsigned int polynomial); +unsigned int crc32_calculate(const struct crc32 *, + const void *data_, size_t n_bytes); + + +#endif /* crc32.h */ diff --git a/openflow/datapath/datapath.c b/openflow/datapath/datapath.c new file mode 100644 index 00000000..5678ea68 --- /dev/null +++ b/openflow/datapath/datapath.c @@ -0,0 +1,2137 @@ +/* + * Distributed under the terms of the GNU GPL version 2. + * Copyright (c) 2007, 2008, 2009 The Board of Trustees of The Leland + * Stanford Junior University + */ + +/* Functions for managing the dp interface/device. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "openflow/nicira-ext.h" +#include "openflow/openflow-netlink.h" +#include "datapath.h" +#include "table.h" +#include "chain.h" +#include "dp_dev.h" +#include "forward.h" +#include "flow.h" + +#include "compat.h" + + +/* Strings to describe the manufacturer, hardware, and software. This data + * is queriable through the switch description stats message. */ +static char mfr_desc[DESC_STR_LEN] = "Stanford University"; +static char hw_desc[DESC_STR_LEN] = "Reference Kernelspace Switch"; +static char sw_desc[DESC_STR_LEN] = VERSION BUILDNR; +static char serial_num[SERIAL_NUM_LEN] = "None"; + +module_param_string(mfr_desc, mfr_desc, sizeof mfr_desc, 0444); +module_param_string(hw_desc, hw_desc, sizeof hw_desc, 0444); +module_param_string(sw_desc, sw_desc, sizeof sw_desc, 0444); +module_param_string(serial_num, serial_num, sizeof serial_num, 0444); + +int (*dp_ioctl_hook)(struct net_device *dev, struct ifreq *rq, int cmd); +EXPORT_SYMBOL(dp_ioctl_hook); + +int (*dp_add_dp_hook)(struct datapath *dp); +EXPORT_SYMBOL(dp_add_dp_hook); + +int (*dp_del_dp_hook)(struct datapath *dp); +EXPORT_SYMBOL(dp_del_dp_hook); + +int (*dp_add_if_hook)(struct net_bridge_port *p); +EXPORT_SYMBOL(dp_add_if_hook); + +int (*dp_del_if_hook)(struct net_bridge_port *p); +EXPORT_SYMBOL(dp_del_if_hook); + +/* Number of milliseconds between runs of the maintenance thread. */ +#define MAINT_SLEEP_MSECS 1000 + +static struct genl_family dp_genl_family; + +/* + * Datapath multicast groups. + * + * Really we want one multicast group per in-use datapath (or even more than + * one). Locking issues, however, mean that we can't allocate a multicast + * group at the point in the code where we we actually create a datapath[*], so + * we have to pre-allocate them. It's massive overkill to allocate DP_MAX of + * them in advance, since we will hardly ever actually create DP_MAX datapaths, + * so instead we allocate a few multicast groups at startup and choose one for + * each datapath by hashing its datapath index. + * + * [*] dp_genl_add, to add a new datapath, is called under the genl_lock + * mutex, and genl_register_mc_group, called to acquire a new multicast + * group ID, also acquires genl_lock, thus deadlock. + */ +#define N_MC_GROUPS 16 /* Must be power of 2. */ +static struct genl_multicast_group mc_groups[N_MC_GROUPS]; + +/* Datapaths. Protected on the read side by rcu_read_lock, on the write side + * by dp_mutex. dp_mutex is almost completely redundant with genl_mutex + * maintained by the Generic Netlink code, but the timeout path needs mutual + * exclusion too. + * + * dp_mutex nests inside the RTNL lock: if you need both you must take the RTNL + * lock first. + * + * It is safe to access the datapath and net_bridge_port structures with just + * dp_mutex. + */ +static struct datapath *dps[DP_MAX]; +DEFINE_MUTEX(dp_mutex); +EXPORT_SYMBOL(dp_mutex); + +static int dp_maint_func(void *data); +static void init_port_status(struct net_bridge_port *p); +static int dp_genl_openflow_done(struct netlink_callback *); +static struct net_bridge_port *new_nbp(struct datapath *, + struct net_device *, int port_no); + +/* nla_shrink - reduce amount of space reserved by nla_reserve + * @skb: socket buffer from which to recover room + * @nla: netlink attribute to adjust + * @len: new length of attribute payload + * + * Reduces amount of space reserved by a call to nla_reserve. + * + * No other attributes may be added between calling nla_reserve and this + * function, since it will create a hole in the message. + */ +void nla_shrink(struct sk_buff *skb, struct nlattr *nla, int len) +{ + int delta = nla_total_size(len) - nla_total_size(nla_len(nla)); + BUG_ON(delta > 0); + skb->tail += delta; + skb->len += delta; + nla->nla_len = nla_attr_size(len); +} + +/* Puts a set of openflow headers for a message of the given 'type' into 'skb'. + * If 'sender' is nonnull, then it is used as the message's destination. 'dp' + * must specify the datapath to use. + * + * '*max_openflow_len' receives the maximum number of bytes that are available + * for the embedded OpenFlow message. The caller must call + * resize_openflow_skb() to set the actual size of the message to this number + * of bytes or less. + * + * Returns the openflow header if successful, otherwise (if 'skb' is too small) + * an error code. */ +static void * +put_openflow_headers(struct datapath *dp, struct sk_buff *skb, uint8_t type, + const struct sender *sender, int *max_openflow_len) +{ + struct ofp_header *oh; + struct nlattr *attr; + int openflow_len; + + /* Assemble the Generic Netlink wrapper. */ + if (!genlmsg_put(skb, + sender ? sender->pid : 0, + sender ? sender->seq : 0, + &dp_genl_family, 0, DP_GENL_C_OPENFLOW)) + return ERR_PTR(-ENOBUFS); + if (nla_put_u32(skb, DP_GENL_A_DP_IDX, dp->dp_idx) < 0) + return ERR_PTR(-ENOBUFS); + openflow_len = (skb_tailroom(skb) - NLA_HDRLEN) & ~(NLA_ALIGNTO - 1); + if (openflow_len < sizeof *oh) + return ERR_PTR(-ENOBUFS); + *max_openflow_len = openflow_len; + attr = nla_reserve(skb, DP_GENL_A_OPENFLOW, openflow_len); + BUG_ON(!attr); + + /* Fill in the header. The caller is responsible for the length. */ + oh = nla_data(attr); + oh->version = OFP_VERSION; + oh->type = type; + oh->xid = sender ? sender->xid : 0; + + return oh; +} + +/* Resizes OpenFlow header 'oh', which must be at the tail end of 'skb', to new + * length 'new_length' (in bytes), adjusting pointers and size values as + * necessary. */ +static void +resize_openflow_skb(struct sk_buff *skb, + struct ofp_header *oh, size_t new_length) +{ + struct nlattr *attr = ((void *) oh) - NLA_HDRLEN; + nla_shrink(skb, attr, new_length); + oh->length = htons(new_length); + nlmsg_end(skb, (struct nlmsghdr *) skb->data); +} + +/* Allocates a new skb to contain an OpenFlow message 'openflow_len' bytes in + * length. Returns a null pointer if memory is unavailable, otherwise returns + * the OpenFlow header and stores a pointer to the skb in '*pskb'. + * + * 'type' is the OpenFlow message type. If 'sender' is nonnull, then it is + * used as the message's destination. 'dp' must specify the datapath to + * use. */ +static void * +alloc_openflow_skb(struct datapath *dp, size_t openflow_len, uint8_t type, + const struct sender *sender, struct sk_buff **pskb) +{ + struct ofp_header *oh; + size_t genl_len; + struct sk_buff *skb; + int max_openflow_len; + + if ((openflow_len + sizeof(struct ofp_header)) > UINT16_MAX) { + if (net_ratelimit()) + printk(KERN_ERR "%s: alloc_openflow_skb: openflow " + "message too large: %zu\n", + dp->netdev->name, openflow_len); + return NULL; + } + + genl_len = nlmsg_total_size(GENL_HDRLEN + dp_genl_family.hdrsize); + genl_len += nla_total_size(sizeof(uint32_t)); /* DP_GENL_A_DP_IDX */ + genl_len += nla_total_size(openflow_len); /* DP_GENL_A_OPENFLOW */ + skb = *pskb = genlmsg_new(genl_len, GFP_ATOMIC); + if (!skb) { + return NULL; + } + + oh = put_openflow_headers(dp, skb, type, sender, &max_openflow_len); + BUG_ON(!oh || IS_ERR(oh)); + resize_openflow_skb(skb, oh, openflow_len); + + return oh; +} + +/* Returns the ID of the multicast group used by datapath 'dp'. */ +static u32 +dp_mc_group(const struct datapath *dp) +{ + return mc_groups[dp->dp_idx & (N_MC_GROUPS - 1)].id; +} + +/* Sends 'skb' to 'sender' if it is nonnull, otherwise multicasts 'skb' to all + * listeners. */ +static int +send_openflow_skb(const struct datapath *dp, + struct sk_buff *skb, const struct sender *sender) +{ + return (sender + ? genlmsg_unicast(skb, sender->pid) + : genlmsg_multicast(skb, 0, dp_mc_group(dp), GFP_ATOMIC)); +} + +/* Retrieves the datapath id, which is the MAC address of the "of" device. */ +static +uint64_t get_datapath_id(struct net_device *dev) +{ + uint64_t id = 0; + int i; + + for (i=0; idev_addr[i] << (8*(ETH_ALEN-1 - i)); + + return id; +} + +/* Find the first free datapath index. Return the index or -1 if a free + * index could not be found. */ +int gen_dp_idx(void) +{ + int i; + + for (i=0; i= DP_MAX) + goto err_unlock; + + err = -ENODEV; + if (!try_module_get(THIS_MODULE)) + goto err_unlock; + + /* Exit early if a datapath with that number already exists. */ + err = -EEXIST; + if (dps[dp_idx]) + goto err_put; + + err = -ENOMEM; + dp = kzalloc(sizeof *dp, GFP_KERNEL); + if (dp == NULL) + goto err_put; + + dp->dp_idx = dp_idx; + /* copied from sys_gethostname() */ + u = utsname(); + /* shouldn't need to lock b/c no userspace interactions */ + snprintf(dp->dp_desc, sizeof dp->dp_desc, "%s idx=%d", u->nodename, dp_idx); + + /* Setup our datapath device */ + err = dp_dev_setup(dp, dp_name); + if (err) + goto err_free_dp; + + dp->chain = chain_create(dp); + if (dp->chain == NULL) + goto err_destroy_dp_dev; + INIT_LIST_HEAD(&dp->port_list); + + dp->local_port = new_nbp(dp, dp->netdev, OFPP_LOCAL); + if (IS_ERR(dp->local_port)) { + err = PTR_ERR(dp->local_port); + goto err_destroy_local_port; + } + + dp->flags = 0; + dp->miss_send_len = OFP_DEFAULT_MISS_SEND_LEN; + + dp->dp_task = kthread_run(dp_maint_func, dp, "dp%d", dp_idx); + if (IS_ERR(dp->dp_task)) + goto err_destroy_chain; + + dps[dp_idx] = dp; + mutex_unlock(&dp_mutex); + rtnl_unlock(); + + if (dp_add_dp_hook) + dp_add_dp_hook(dp); + + return 0; + +err_destroy_local_port: + dp_del_switch_port(dp->local_port); +err_destroy_chain: + chain_destroy(dp->chain); +err_destroy_dp_dev: + dp_dev_destroy(dp); +err_free_dp: + kfree(dp); +err_put: + module_put(THIS_MODULE); +err_unlock: + mutex_unlock(&dp_mutex); + rtnl_unlock(); + return err; +} + +/* Find and return a free port number under 'dp'. */ +static int find_portno(struct datapath *dp) +{ + int i; + for (i = 1; i < DP_MAX_PORTS; i++) + if (dp->ports[i] == NULL) + return i; + return -EXFULL; +} + +/* Called with RTNL lock and dp_mutex. */ +static struct net_bridge_port *new_nbp(struct datapath *dp, + struct net_device *dev, int port_no) +{ + struct net_bridge_port *p; + + if (dev->br_port != NULL) + return ERR_PTR(-EBUSY); + + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (p == NULL) + return ERR_PTR(-ENOMEM); + + dev_set_promiscuity(dev, 1); + dev_hold(dev); + p->dp = dp; + p->dev = dev; + p->port_no = port_no; + spin_lock_init(&p->lock); + if (port_no != OFPP_LOCAL) + rcu_assign_pointer(dev->br_port, p); + if (port_no < DP_MAX_PORTS) + rcu_assign_pointer(dp->ports[port_no], p); + list_add_rcu(&p->node, &dp->port_list); + + return p; +} + +/* Called with RTNL lock and dp_mutex. */ +int add_switch_port(struct datapath *dp, struct net_device *dev) +{ + struct net_bridge_port *p; + int port_no; + + if (dev->flags & IFF_LOOPBACK || dev->type != ARPHRD_ETHER + || is_dp_dev(dev)) + return -EINVAL; + + port_no = find_portno(dp); + if (port_no < 0) + return port_no; + + p = new_nbp(dp, dev, port_no); + if (IS_ERR(p)) + return PTR_ERR(p); + + init_port_status(p); + + if (dp_add_if_hook) + dp_add_if_hook(p); + + /* Notify the ctlpath that this port has been added */ + dp_send_port_status(p, OFPPR_ADD); + + return 0; +} + +/* Delete 'p' from switch. + * Called with RTNL lock and dp_mutex. */ +int dp_del_switch_port(struct net_bridge_port *p) +{ + +#if CONFIG_SYSFS + if ((p->port_no != OFPP_LOCAL) && dp_del_if_hook) + sysfs_remove_link(&p->dp->ifobj, p->dev->name); +#endif + + /* First drop references to device. */ + dev_set_promiscuity(p->dev, -1); + list_del_rcu(&p->node); + if (p->port_no != OFPP_LOCAL) + rcu_assign_pointer(p->dp->ports[p->port_no], NULL); + rcu_assign_pointer(p->dev->br_port, NULL); + + /* Then wait until no one is still using it, and destroy it. */ + synchronize_rcu(); + + /* Notify the ctlpath that this port no longer exists */ + dp_send_port_status(p, OFPPR_DELETE); + + if ((p->port_no != OFPP_LOCAL) && dp_del_if_hook) { + dp_del_if_hook(p); + } else { + dev_put(p->dev); + kfree(p); + } + + return 0; +} + +static void del_dp(struct datapath *dp) +{ + struct net_bridge_port *p, *n; + + send_sig(SIGKILL, dp->dp_task, 0); + kthread_stop(dp->dp_task); + + /* Drop references to DP. */ + list_for_each_entry_safe (p, n, &dp->port_list, node) + dp_del_switch_port(p); + + if (dp_del_dp_hook) + dp_del_dp_hook(dp); + + rcu_assign_pointer(dps[dp->dp_idx], NULL); + + /* Kill off local_port dev references from buffered packets that have + * associated dst entries. */ + synchronize_rcu(); + fwd_discard_all(); + + /* Destroy dp->netdev. (Must follow deleting switch ports since + * dp->local_port has a reference to it.) */ + dp_dev_destroy(dp); + + /* Wait until no longer in use, then destroy it. */ + synchronize_rcu(); + chain_destroy(dp->chain); + kfree(dp); + module_put(THIS_MODULE); +} + +static int dp_maint_func(void *data) +{ + struct datapath *dp = (struct datapath *) data; + + allow_signal(SIGKILL); + while (!signal_pending(current)) { + /* Timeout old entries */ + chain_timeout(dp->chain); + msleep_interruptible(MAINT_SLEEP_MSECS); + } + while (!kthread_should_stop()) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule(); + } + return 0; +} + +static void +do_port_input(struct net_bridge_port *p, struct sk_buff *skb) +{ + /* Make our own copy of the packet. Otherwise we will mangle the + * packet for anyone who came before us (e.g. tcpdump via AF_PACKET). + * (No one comes after us, since we tell handle_bridge() that we took + * the packet.) */ + skb = skb_share_check(skb, GFP_ATOMIC); + if (!skb) + return; + + /* Push the Ethernet header back on. */ + skb_push(skb, ETH_HLEN); + skb_reset_mac_header(skb); + fwd_port_input(p->dp->chain, skb, p); +} + +/* + * Used as br_handle_frame_hook. (Cannot run bridge at the same time, even on + * different set of devices!) + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) +/* Called with rcu_read_lock. */ +static struct sk_buff *dp_frame_hook(struct net_bridge_port *p, + struct sk_buff *skb) +{ + do_port_input(p, skb); + return NULL; +} +#else +static int dp_frame_hook(struct net_bridge_port *p, struct sk_buff **pskb) +{ + do_port_input(p, *pskb); + return 1; +} +#endif + +/* Forwarding output path. + * Based on net/bridge/br_forward.c. */ + +static inline unsigned packet_length(const struct sk_buff *skb) +{ + unsigned length = skb->len - ETH_HLEN; + if (skb->protocol == htons(ETH_P_8021Q)) + length -= VLAN_HLEN; + return length; +} + +/* Send packets out all the ports except the originating one. If the + * "flood" argument is set, only send along the minimum spanning tree. + */ +static int +output_all(struct datapath *dp, struct sk_buff *skb, int flood) +{ + u32 disable = flood ? OFPPC_NO_FLOOD : 0; + struct net_bridge_port *p; + int prev_port = -1; + + list_for_each_entry_rcu (p, &dp->port_list, node) { + if (skb->dev == p->dev || p->config & disable) + continue; + if (prev_port != -1) { + struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); + if (!clone) { + kfree_skb(skb); + return -ENOMEM; + } + dp_output_port(dp, clone, prev_port, 0); + } + prev_port = p->port_no; + } + if (prev_port != -1) + dp_output_port(dp, skb, prev_port, 0); + else + kfree_skb(skb); + + return 0; +} + +/* Marks 'skb' as having originated from 'in_port' in 'dp'. + FIXME: how are devices reference counted? */ +void dp_set_origin(struct datapath *dp, uint16_t in_port, + struct sk_buff *skb) +{ + struct net_bridge_port *p; + p = (in_port < DP_MAX_PORTS ? dp->ports[in_port] + : in_port == OFPP_LOCAL ? dp->local_port + : NULL); + if (p) + skb->dev = p->dev; + else + skb->dev = NULL; +} + +int +dp_xmit_skb(struct sk_buff *skb) +{ + struct datapath *dp = skb->dev->br_port->dp; + int len = skb->len; + + if (packet_length(skb) > skb->dev->mtu && !skb_is_gso(skb)) { + printk(KERN_WARNING "%s: dropped over-mtu packet: %d > %d\n", + dp->netdev->name, packet_length(skb), skb->dev->mtu); + kfree_skb(skb); + return -E2BIG; + } + + dev_queue_xmit(skb); + + return len; +} + +/* Takes ownership of 'skb' and transmits it to 'out_port' on 'dp'. + */ +int dp_output_port(struct datapath *dp, struct sk_buff *skb, int out_port, + int ignore_no_fwd) +{ + BUG_ON(!skb); + switch (out_port){ + case OFPP_IN_PORT: + /* Send it out the port it came in on, which is already set in + * the skb. */ + if (!skb->dev) { + if (net_ratelimit()) + printk(KERN_NOTICE "%s: skb device not set " + "forwarding to in_port\n", + dp->netdev->name); + kfree_skb(skb); + return -ESRCH; + } + return dp_xmit_skb(skb); + + case OFPP_TABLE: { + int retval = run_flow_through_tables(dp->chain, skb, + skb->dev->br_port); + if (retval) + kfree_skb(skb); + return retval; + } + + case OFPP_FLOOD: + return output_all(dp, skb, 1); + + case OFPP_ALL: + return output_all(dp, skb, 0); + + case OFPP_CONTROLLER: + return dp_output_control(dp, skb, UINT16_MAX, OFPR_ACTION); + + case OFPP_LOCAL: { + struct net_device *dev = dp->netdev; + return dev ? dp_dev_recv(dev, skb) : -ESRCH; + } + + case 0 ... DP_MAX_PORTS - 1: { + struct net_bridge_port *p = dp->ports[out_port]; + if (p == NULL) + goto bad_port; + if (p->dev == skb->dev) { + /* To send to the input port, must use OFPP_IN_PORT */ + kfree_skb(skb); + if (net_ratelimit()) + printk(KERN_NOTICE "%s: can't directly " + "forward to input port\n", + dp->netdev->name); + return -EINVAL; + } + if (p->config & OFPPC_NO_FWD && !ignore_no_fwd) { + kfree_skb(skb); + return 0; + } + skb->dev = p->dev; + return dp_xmit_skb(skb); + } + + default: + goto bad_port; + } + +bad_port: + kfree_skb(skb); + if (net_ratelimit()) + printk(KERN_NOTICE "%s: can't forward to bad port %d\n", + dp->netdev->name, out_port); + return -ENOENT; +} + +/* Takes ownership of 'skb' and transmits it to 'dp''s control path. 'reason' + * indicates why 'skb' is being sent. 'max_len' sets the maximum number of + * bytes that the caller wants to be sent. + */ +int +dp_output_control(struct datapath *dp, struct sk_buff *skb, + size_t max_len, int reason) +{ + /* FIXME? Can we avoid creating a new skbuff in the case where we + * forward the whole packet? */ + struct sk_buff *f_skb; + struct ofp_packet_in *opi; + size_t fwd_len, opi_len; + uint32_t buffer_id; + int err; + + WARN_ON_ONCE(skb_shared(skb)); + + buffer_id = fwd_save_skb(skb); + + fwd_len = skb->len; + if (buffer_id != (uint32_t) -1) + fwd_len = min(fwd_len, max_len); + + opi_len = offsetof(struct ofp_packet_in, data) + fwd_len; + opi = alloc_openflow_skb(dp, opi_len, OFPT_PACKET_IN, NULL, &f_skb); + if (!opi) { + err = -ENOMEM; + goto out; + } + opi->buffer_id = htonl(buffer_id); + opi->total_len = htons(skb->len); + opi->in_port = htons(skb->dev && skb->dev->br_port + ? skb->dev->br_port->port_no + : OFPP_LOCAL); + opi->reason = reason; + opi->pad = 0; + skb_copy_bits(skb, 0, opi->data, fwd_len); + err = send_openflow_skb(dp, f_skb, NULL); + +out: + kfree_skb(skb); + return err; +} + +static void fill_port_desc(struct net_bridge_port *p, struct ofp_phy_port *desc) +{ + unsigned long flags; + desc->port_no = htons(p->port_no); + strncpy(desc->name, p->dev->name, OFP_MAX_PORT_NAME_LEN); + desc->name[OFP_MAX_PORT_NAME_LEN-1] = '\0'; + memcpy(desc->hw_addr, p->dev->dev_addr, ETH_ALEN); + desc->curr = 0; + desc->supported = 0; + desc->advertised = 0; + desc->peer = 0; + + spin_lock_irqsave(&p->lock, flags); + desc->config = htonl(p->config); + desc->state = htonl(p->state); + spin_unlock_irqrestore(&p->lock, flags); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,24) + if (p->dev->ethtool_ops && p->dev->ethtool_ops->get_settings) { + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; + + if (!p->dev->ethtool_ops->get_settings(p->dev, &ecmd)) { + /* Set the supported features */ + if (ecmd.supported & SUPPORTED_10baseT_Half) + desc->supported |= OFPPF_10MB_HD; + if (ecmd.supported & SUPPORTED_10baseT_Full) + desc->supported |= OFPPF_10MB_FD; + if (ecmd.supported & SUPPORTED_100baseT_Half) + desc->supported |= OFPPF_100MB_HD; + if (ecmd.supported & SUPPORTED_100baseT_Full) + desc->supported |= OFPPF_100MB_FD; + if (ecmd.supported & SUPPORTED_1000baseT_Half) + desc->supported |= OFPPF_1GB_HD; + if (ecmd.supported & SUPPORTED_1000baseT_Full) + desc->supported |= OFPPF_1GB_FD; + if (ecmd.supported & SUPPORTED_10000baseT_Full) + desc->supported |= OFPPF_10GB_FD; + if (ecmd.supported & SUPPORTED_TP) + desc->supported |= OFPPF_COPPER; + if (ecmd.supported & SUPPORTED_FIBRE) + desc->supported |= OFPPF_FIBER; + if (ecmd.supported & SUPPORTED_Autoneg) + desc->supported |= OFPPF_AUTONEG; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14) + if (ecmd.supported & SUPPORTED_Pause) + desc->supported |= OFPPF_PAUSE; + if (ecmd.supported & SUPPORTED_Asym_Pause) + desc->supported |= OFPPF_PAUSE_ASYM; +#endif /* kernel >= 2.6.14 */ + + /* Set the advertised features */ + if (ecmd.advertising & ADVERTISED_10baseT_Half) + desc->advertised |= OFPPF_10MB_HD; + if (ecmd.advertising & ADVERTISED_10baseT_Full) + desc->advertised |= OFPPF_10MB_FD; + if (ecmd.advertising & ADVERTISED_100baseT_Half) + desc->advertised |= OFPPF_100MB_HD; + if (ecmd.advertising & ADVERTISED_100baseT_Full) + desc->advertised |= OFPPF_100MB_FD; + if (ecmd.advertising & ADVERTISED_1000baseT_Half) + desc->advertised |= OFPPF_1GB_HD; + if (ecmd.advertising & ADVERTISED_1000baseT_Full) + desc->advertised |= OFPPF_1GB_FD; + if (ecmd.advertising & ADVERTISED_10000baseT_Full) + desc->advertised |= OFPPF_10GB_FD; + if (ecmd.advertising & ADVERTISED_TP) + desc->advertised |= OFPPF_COPPER; + if (ecmd.advertising & ADVERTISED_FIBRE) + desc->advertised |= OFPPF_FIBER; + if (ecmd.advertising & ADVERTISED_Autoneg) + desc->advertised |= OFPPF_AUTONEG; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14) + if (ecmd.advertising & ADVERTISED_Pause) + desc->advertised |= OFPPF_PAUSE; + if (ecmd.advertising & ADVERTISED_Asym_Pause) + desc->advertised |= OFPPF_PAUSE_ASYM; +#endif /* kernel >= 2.6.14 */ + + /* Set the current features */ + if (ecmd.speed == SPEED_10) + desc->curr = (ecmd.duplex) ? OFPPF_10MB_FD : OFPPF_10MB_HD; + else if (ecmd.speed == SPEED_100) + desc->curr = (ecmd.duplex) ? OFPPF_100MB_FD : OFPPF_100MB_HD; + else if (ecmd.speed == SPEED_1000) + desc->curr = (ecmd.duplex) ? OFPPF_1GB_FD : OFPPF_1GB_HD; + else if (ecmd.speed == SPEED_10000) + desc->curr = OFPPF_10GB_FD; + + if (ecmd.port == PORT_TP) + desc->curr |= OFPPF_COPPER; + else if (ecmd.port == PORT_FIBRE) + desc->curr |= OFPPF_FIBER; + + if (ecmd.autoneg) + desc->curr |= OFPPF_AUTONEG; + } + } +#endif + desc->curr = htonl(desc->curr); + desc->supported = htonl(desc->supported); + desc->advertised = htonl(desc->advertised); + desc->peer = htonl(desc->peer); +} + +static int +fill_features_reply(struct datapath *dp, struct ofp_switch_features *ofr) +{ + struct net_bridge_port *p; + uint64_t dpid = get_datapath_id(dp->netdev); + int port_count = 0; + + ofr->datapath_id = cpu_to_be64(dpid); + + ofr->n_buffers = htonl(N_PKT_BUFFERS); + ofr->n_tables = dp->chain->n_tables; + ofr->capabilities = htonl(OFP_SUPPORTED_CAPABILITIES); + ofr->actions = htonl(OFP_SUPPORTED_ACTIONS); + memset(ofr->pad, 0, sizeof ofr->pad); + + list_for_each_entry_rcu (p, &dp->port_list, node) { + fill_port_desc(p, &ofr->ports[port_count]); + port_count++; + } + + return port_count; +} + +int +dp_send_features_reply(struct datapath *dp, const struct sender *sender) +{ + struct sk_buff *skb; + struct ofp_switch_features *ofr; + size_t ofr_len, port_max_len; + int port_count; + + /* Overallocate. */ + port_max_len = sizeof(struct ofp_phy_port) * DP_MAX_PORTS; + ofr = alloc_openflow_skb(dp, sizeof(*ofr) + port_max_len, + OFPT_FEATURES_REPLY, sender, &skb); + if (!ofr) + return -ENOMEM; + + /* Fill. */ + port_count = fill_features_reply(dp, ofr); + + /* Shrink to fit. */ + ofr_len = sizeof(*ofr) + (sizeof(struct ofp_phy_port) * port_count); + resize_openflow_skb(skb, &ofr->header, ofr_len); + return send_openflow_skb(dp, skb, sender); +} + +int +dp_send_config_reply(struct datapath *dp, const struct sender *sender) +{ + struct sk_buff *skb; + struct ofp_switch_config *osc; + + osc = alloc_openflow_skb(dp, sizeof *osc, OFPT_GET_CONFIG_REPLY, sender, + &skb); + if (!osc) + return -ENOMEM; + + osc->flags = htons(dp->flags); + osc->miss_send_len = htons(dp->miss_send_len); + + return send_openflow_skb(dp, skb, sender); +} + +int +dp_send_hello(struct datapath *dp, const struct sender *sender, + const struct ofp_header *request) +{ + if (request->version < OFP_VERSION) { + char err[64]; + sprintf(err, "Only version 0x%02x supported", OFP_VERSION); + dp_send_error_msg(dp, sender, OFPET_HELLO_FAILED, + OFPHFC_INCOMPATIBLE, err, strlen(err)); + return -EINVAL; + } else { + struct sk_buff *skb; + struct ofp_header *reply; + + reply = alloc_openflow_skb(dp, sizeof *reply, + OFPT_HELLO, sender, &skb); + if (!reply) + return -ENOMEM; + + return send_openflow_skb(dp, skb, sender); + } +} + +int +dp_send_barrier_reply(struct datapath *dp, const struct sender *sender, + const struct ofp_header *request) +{ + struct sk_buff *skb; + struct ofp_header *reply; + + reply = alloc_openflow_skb(dp, sizeof *reply, + OFPT_BARRIER_REPLY, sender, &skb); + if (!reply) + return -ENOMEM; + + return send_openflow_skb(dp, skb, sender); +} + +int +dp_update_port_flags(struct datapath *dp, const struct ofp_port_mod *opm) +{ + unsigned long int flags; + int port_no = ntohs(opm->port_no); + struct net_bridge_port *p; + p = (port_no < DP_MAX_PORTS ? dp->ports[port_no] + : port_no == OFPP_LOCAL ? dp->local_port + : NULL); + + /* Make sure the port id hasn't changed since this was sent */ + if (!p || memcmp(opm->hw_addr, p->dev->dev_addr, ETH_ALEN)) + return -1; + + spin_lock_irqsave(&p->lock, flags); + if (opm->mask) { + uint32_t config_mask = ntohl(opm->mask); + p->config &= ~config_mask; + p->config |= ntohl(opm->config) & config_mask; + } + spin_unlock_irqrestore(&p->lock, flags); + + return 0; +} + +/* Initialize the port status field of the bridge port. */ +static void +init_port_status(struct net_bridge_port *p) +{ + unsigned long int flags; + + spin_lock_irqsave(&p->lock, flags); + + if (p->dev->flags & IFF_UP) + p->config &= ~OFPPC_PORT_DOWN; + else + p->config |= OFPPC_PORT_DOWN; + + if (netif_carrier_ok(p->dev)) + p->state &= ~OFPPS_LINK_DOWN; + else + p->state |= OFPPS_LINK_DOWN; + + spin_unlock_irqrestore(&p->lock, flags); +} + +int +dp_send_port_status(struct net_bridge_port *p, uint8_t status) +{ + struct sk_buff *skb; + struct ofp_port_status *ops; + + ops = alloc_openflow_skb(p->dp, sizeof *ops, OFPT_PORT_STATUS, NULL, + &skb); + if (!ops) + return -ENOMEM; + ops->reason = status; + memset(ops->pad, 0, sizeof ops->pad); + fill_port_desc(p, &ops->desc); + + return send_openflow_skb(p->dp, skb, NULL); +} + +/* Convert jiffies_64 to seconds. */ +static u32 inline jiffies_64_to_secs(u64 j) +{ + /* Call to do_div is necessary as we can't do a 64-bit division in a + * 32-bit kernel (at least not without linking to libgcc) */ + do_div(j, HZ); + return j; +} + +/* Convert jiffies_64 to just the nanosec part between seconds. */ +static u32 inline jiffies_64_to_nsecs(u64 j) +{ + /* Call to do_div is necessary as we can't do a 64-bit division in a + * 32-bit kernel (at least not without linking to libgcc) */ + return (j - jiffies_64_to_secs(j)); +} + +int +dp_send_flow_end(struct datapath *dp, struct sw_flow *flow, + enum ofp_flow_removed_reason reason) +{ + struct sk_buff *skb; + struct ofp_flow_removed *ofr; + + if (!flow->send_flow_rem) + return 0; + + if (flow->emerg_flow) + return 0; + + ofr = alloc_openflow_skb(dp, sizeof *ofr, OFPT_FLOW_REMOVED, 0, &skb); + if (!ofr) + return -ENOMEM; + + flow_fill_match(&ofr->match, &flow->key); + + ofr->priority = htons(flow->priority); + ofr->reason = reason; + + ofr->duration_sec = htonl(jiffies_64_to_secs(get_jiffies_64()-flow->created)); + ofr->duration_nsec = htonl(jiffies_64_to_nsecs(get_jiffies_64()-flow->created)); + ofr->idle_timeout = htons(flow->idle_timeout); + + ofr->packet_count = cpu_to_be64(flow->packet_count); + ofr->byte_count = cpu_to_be64(flow->byte_count); + + return send_openflow_skb(dp, skb, NULL); +} +EXPORT_SYMBOL(dp_send_flow_end); + +int +dp_send_error_msg(struct datapath *dp, const struct sender *sender, + uint16_t type, uint16_t code, const void *data, size_t len) +{ + struct sk_buff *skb; + struct ofp_error_msg *oem; + + + oem = alloc_openflow_skb(dp, sizeof(*oem)+len, OFPT_ERROR, + sender, &skb); + if (!oem) + return -ENOMEM; + + oem->type = htons(type); + oem->code = htons(code); + memcpy(oem->data, data, len); + + return send_openflow_skb(dp, skb, sender); +} + +int +dp_send_echo_reply(struct datapath *dp, const struct sender *sender, + const struct ofp_header *rq) +{ + struct sk_buff *skb; + struct ofp_header *reply; + + reply = alloc_openflow_skb(dp, ntohs(rq->length), OFPT_ECHO_REPLY, + sender, &skb); + if (!reply) + return -ENOMEM; + + memcpy(reply + 1, rq + 1, ntohs(rq->length) - sizeof *rq); + return send_openflow_skb(dp, skb, sender); +} + +/* Generic Netlink interface. + * + * See netlink(7) for an introduction to netlink. See + * http://linux-net.osdl.org/index.php/Netlink for more information and + * pointers on how to work with netlink and Generic Netlink in the kernel and + * in userspace. */ + +static struct genl_family dp_genl_family = { + .id = GENL_ID_GENERATE, + .hdrsize = 0, + .name = DP_GENL_FAMILY_NAME, + .version = 1, + .maxattr = DP_GENL_A_MAX, +}; + +/* Attribute policy: what each attribute may contain. */ +static struct nla_policy dp_genl_policy[DP_GENL_A_MAX + 1] = { + [DP_GENL_A_DP_IDX] = { .type = NLA_U32 }, + [DP_GENL_A_DP_NAME] = { .type = NLA_NUL_STRING }, + [DP_GENL_A_MC_GROUP] = { .type = NLA_U32 }, + [DP_GENL_A_PORTNAME] = { .type = NLA_NUL_STRING } +}; + +static int dp_genl_add(struct sk_buff *skb, struct genl_info *info) +{ + int dp_idx = info->attrs[DP_GENL_A_DP_IDX] ? + nla_get_u32(info->attrs[DP_GENL_A_DP_IDX]) : -1; + const char *dp_name = info->attrs[DP_GENL_A_DP_NAME] ? + nla_data(info->attrs[DP_GENL_A_DP_NAME]) : NULL; + + if (VERIFY_NUL_STRING(info->attrs[DP_GENL_A_DP_NAME])) + return -EINVAL; + + if ((dp_idx == -1) && (!dp_name)) + return -EINVAL; + + return new_dp(dp_idx, dp_name); +} + +static struct genl_ops dp_genl_ops_add_dp = { + .cmd = DP_GENL_C_ADD_DP, + .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ + .policy = dp_genl_policy, + .doit = dp_genl_add, + .dumpit = NULL, +}; + +/* Must be called with rcu_read_lock or dp_mutex. */ +struct datapath *dp_get_by_idx(int dp_idx) +{ + if (dp_idx < 0 || dp_idx >= DP_MAX) + return NULL; + return rcu_dereference(dps[dp_idx]); +} +EXPORT_SYMBOL(dp_get_by_idx); + +/* Must be called with rcu_read_lock or dp_mutex. */ +struct datapath *dp_get_by_name(const char *dp_name) +{ + int i; + for (i=0; inetdev->name, dp_name)) + return dp; + } + return NULL; +} + +/* Must be called with rcu_read_lock or dp_mutex. */ +static struct datapath * +lookup_dp(struct genl_info *info) +{ + int dp_idx = info->attrs[DP_GENL_A_DP_IDX] ? + nla_get_u32(info->attrs[DP_GENL_A_DP_IDX]) : -1; + const char *dp_name = info->attrs[DP_GENL_A_DP_NAME] ? + nla_data(info->attrs[DP_GENL_A_DP_NAME]) : NULL; + + if (VERIFY_NUL_STRING(info->attrs[DP_GENL_A_DP_NAME])) + return ERR_PTR(-EINVAL); + + if (dp_idx != -1) { + struct datapath *dp = dp_get_by_idx(dp_idx); + if (!dp) + return ERR_PTR(-ENOENT); + else if (dp_name && strcmp(dp->netdev->name, dp_name)) + return ERR_PTR(-EINVAL); + else + return dp; + } else if (dp_name) { + struct datapath *dp = dp_get_by_name(dp_name); + return dp ? dp : ERR_PTR(-ENOENT); + } else { + return ERR_PTR(-EINVAL); + } +} + +static int dp_genl_del(struct sk_buff *skb, struct genl_info *info) +{ + struct net_device *dev = NULL; + struct datapath *dp; + int err; + + rtnl_lock(); + mutex_lock(&dp_mutex); + dp = lookup_dp(info); + if (IS_ERR(dp)) + err = PTR_ERR(dp); + else { + dev = dp->netdev; + del_dp(dp); + err = 0; + } + mutex_unlock(&dp_mutex); + rtnl_unlock(); + if (dev) + free_netdev(dev); + return err; +} + +static struct genl_ops dp_genl_ops_del_dp = { + .cmd = DP_GENL_C_DEL_DP, + .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ + .policy = dp_genl_policy, + .doit = dp_genl_del, + .dumpit = NULL, +}; + +/* Queries a datapath for related information. Currently the only relevant + * information is the datapath's multicast group ID, datapath ID, and + * datapath device name. */ +static int dp_genl_query(struct sk_buff *skb, struct genl_info *info) +{ + struct datapath *dp; + struct sk_buff *ans_skb = NULL; + int err; + + rcu_read_lock(); + dp = lookup_dp(info); + if (IS_ERR(dp)) + err = PTR_ERR(dp); + else { + void *data; + ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); + if (!ans_skb) { + err = -ENOMEM; + goto err; + } + err = -ENOMEM; + data = genlmsg_put_reply(ans_skb, info, &dp_genl_family, + 0, DP_GENL_C_QUERY_DP); + if (data == NULL) + goto err; + NLA_PUT_U32(ans_skb, DP_GENL_A_DP_IDX, dp->dp_idx); + NLA_PUT_STRING(ans_skb, DP_GENL_A_DP_NAME, dp->netdev->name); + NLA_PUT_U32(ans_skb, DP_GENL_A_MC_GROUP, dp_mc_group(dp)); + + genlmsg_end(ans_skb, data); + err = genlmsg_reply(ans_skb, info); + ans_skb = NULL; + } +err: +nla_put_failure: + kfree_skb(ans_skb); + rcu_read_unlock(); + return err; +} + +static struct genl_ops dp_genl_ops_query_dp = { + .cmd = DP_GENL_C_QUERY_DP, + .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ + .policy = dp_genl_policy, + .doit = dp_genl_query, + .dumpit = NULL, +}; + +static int dp_genl_add_del_port(struct sk_buff *skb, struct genl_info *info) +{ + struct datapath *dp; + struct net_device *port; + int err; + + if (!info->attrs[DP_GENL_A_PORTNAME] || + VERIFY_NUL_STRING(info->attrs[DP_GENL_A_PORTNAME])) + return -EINVAL; + + rtnl_lock(); + mutex_lock(&dp_mutex); + + /* Get datapath. */ + dp = lookup_dp(info); + if (IS_ERR(dp)) { + err = PTR_ERR(dp); + goto out_unlock; + } + + /* Get interface to add/remove. */ + port = dev_get_by_name(&init_net, + nla_data(info->attrs[DP_GENL_A_PORTNAME])); + if (!port) { + err = -ENOENT; + goto out_unlock; + } + + /* Execute operation. */ + if (info->genlhdr->cmd == DP_GENL_C_ADD_PORT) + err = add_switch_port(dp, port); + else { + if (port->br_port == NULL || port->br_port->dp != dp) { + err = -ENOENT; + goto out_put; + } + err = dp_del_switch_port(port->br_port); + } + +out_put: + dev_put(port); +out_unlock: + mutex_unlock(&dp_mutex); + rtnl_unlock(); + return err; +} + +static struct genl_ops dp_genl_ops_add_port = { + .cmd = DP_GENL_C_ADD_PORT, + .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ + .policy = dp_genl_policy, + .doit = dp_genl_add_del_port, + .dumpit = NULL, +}; + +static struct genl_ops dp_genl_ops_del_port = { + .cmd = DP_GENL_C_DEL_PORT, + .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ + .policy = dp_genl_policy, + .doit = dp_genl_add_del_port, + .dumpit = NULL, +}; + +static int dp_genl_openflow(struct sk_buff *skb, struct genl_info *info) +{ + struct nlattr *va = info->attrs[DP_GENL_A_OPENFLOW]; + struct datapath *dp; + struct ofp_header *oh; + struct sender sender; + int err; + + if (!info->attrs[DP_GENL_A_DP_IDX] || !va) + return -EINVAL; + + dp = dp_get_by_idx(nla_get_u32(info->attrs[DP_GENL_A_DP_IDX])); + if (!dp) + return -ENOENT; + + if (nla_len(va) < sizeof(struct ofp_header)) + return -EINVAL; + oh = nla_data(va); + + sender.xid = oh->xid; + sender.pid = info->snd_pid; + sender.seq = info->snd_seq; + + mutex_lock(&dp_mutex); + err = fwd_control_input(dp->chain, &sender, + nla_data(va), nla_len(va)); + mutex_unlock(&dp_mutex); + return err; +} + +static struct nla_policy dp_genl_openflow_policy[DP_GENL_A_MAX + 1] = { + [DP_GENL_A_DP_IDX] = { .type = NLA_U32 }, +}; + +static int desc_stats_dump(struct datapath *dp, void *state, + void *body, int *body_len) +{ + struct ofp_desc_stats *ods = body; + int n_bytes = sizeof *ods; + + if (n_bytes > *body_len) { + return -ENOBUFS; + } + *body_len = n_bytes; + + strncpy(ods->mfr_desc, mfr_desc, sizeof ods->mfr_desc); + strncpy(ods->hw_desc, hw_desc, sizeof ods->hw_desc); + strncpy(ods->sw_desc, sw_desc, sizeof ods->sw_desc); + strncpy(ods->dp_desc, dp->dp_desc, sizeof ods->dp_desc); + strncpy(ods->serial_num, serial_num, sizeof ods->serial_num); + + return 0; +} + +struct flow_stats_state { + int table_idx; + struct sw_table_position position; + const struct ofp_flow_stats_request *rq; + + void *body; + int bytes_used, bytes_allocated; +}; + +#define EMERG_TABLE_ID_FOR_STATS 0xfe + +static int flow_stats_init(struct datapath *dp, const void *body, int body_len, + void **state) +{ + const struct ofp_flow_stats_request *fsr = body; + struct flow_stats_state *s = kmalloc(sizeof *s, GFP_ATOMIC); + if (!s) + return -ENOMEM; + s->table_idx = fsr->table_id == 0xff ? 0 : fsr->table_id; + memset(&s->position, 0, sizeof s->position); + s->rq = fsr; + *state = s; + return 0; +} + +static int flow_stats_dump_callback(struct sw_flow *flow, void *private) +{ + struct sw_flow_actions *sf_acts = rcu_dereference(flow->sf_acts); + struct flow_stats_state *s = private; + struct ofp_flow_stats *ofs; + int length; + uint64_t duration; + + length = sizeof *ofs + sf_acts->actions_len; + if (length + s->bytes_used > s->bytes_allocated) + return 1; + + ofs = s->body + s->bytes_used; + ofs->length = htons(length); + ofs->table_id = s->table_idx; + ofs->pad = 0; + ofs->match.wildcards = htonl(flow->key.wildcards); + ofs->match.in_port = flow->key.in_port; + memcpy(ofs->match.dl_src, flow->key.dl_src, ETH_ALEN); + memcpy(ofs->match.dl_dst, flow->key.dl_dst, ETH_ALEN); + ofs->match.dl_vlan = flow->key.dl_vlan; + ofs->match.dl_type = flow->key.dl_type; + ofs->match.nw_tos = flow->key.nw_tos; + ofs->match.nw_proto = flow->key.nw_proto; + ofs->match.nw_src = flow->key.nw_src; + ofs->match.nw_dst = flow->key.nw_dst; + ofs->match.dl_vlan_pcp = flow->key.dl_vlan_pcp; + ofs->match.tp_src = flow->key.tp_src; + ofs->match.tp_dst = flow->key.tp_dst; + + /* The kernel doesn't support 64-bit division, so use the 'do_div' + * macro instead. The first argument is replaced with the quotient, + * while the remainder is the return value. */ + duration = get_jiffies_64() - flow->created; + do_div(duration, HZ); + ofs->duration_sec = htonl(jiffies_64_to_secs(duration)); + ofs->duration_nsec = htonl(jiffies_64_to_nsecs(duration)); + + ofs->priority = htons(flow->priority); + ofs->idle_timeout = htons(flow->idle_timeout); + ofs->hard_timeout = htons(flow->hard_timeout); + memset(&ofs->pad2, 0, sizeof ofs->pad2); + ofs->packet_count = cpu_to_be64(flow->packet_count); + ofs->byte_count = cpu_to_be64(flow->byte_count); + memcpy(ofs->actions, sf_acts->actions, sf_acts->actions_len); + + s->bytes_used += length; + return 0; +} + +static int flow_stats_dump(struct datapath *dp, void *state, + void *body, int *body_len) +{ + struct flow_stats_state *s = state; + struct sw_flow_key match_key; + int error = 0; + + s->bytes_used = 0; + s->bytes_allocated = *body_len; + s->body = body; + + flow_extract_match(&match_key, &s->rq->match); + if (s->rq->table_id == EMERG_TABLE_ID_FOR_STATS) { + struct sw_table *table = dp->chain->emerg_table; + + error = table->iterate(table, &match_key, s->rq->out_port, + &s->position, flow_stats_dump_callback, + s); + } else { + while (s->table_idx < dp->chain->n_tables + && (s->rq->table_id == 0xff + || s->rq->table_id == s->table_idx)) { + struct sw_table *table = dp->chain->tables[s->table_idx]; + + error = table->iterate(table, &match_key, + s->rq->out_port, &s->position, + flow_stats_dump_callback, s); + if (error) + break; + + s->table_idx++; + memset(&s->position, 0, sizeof s->position); + } + } + *body_len = s->bytes_used; + + /* If error is 0, we're done. + * Otherwise, if some bytes were used, there are more flows to come. + * Otherwise, we were not able to fit even a single flow in the body, + * which indicates that we have a single flow with too many actions to + * fit. We won't ever make any progress at that rate, so give up. */ + return !error ? 0 : s->bytes_used ? 1 : -ENOMEM; +} + +static void flow_stats_done(void *state) +{ + kfree(state); +} + +static int aggregate_stats_init(struct datapath *dp, + const void *body, int body_len, + void **state) +{ + *state = (void *)body; + return 0; +} + +static int aggregate_stats_dump_callback(struct sw_flow *flow, void *private) +{ + struct ofp_aggregate_stats_reply *rpy = private; + rpy->packet_count += flow->packet_count; + rpy->byte_count += flow->byte_count; + rpy->flow_count++; + return 0; +} + +static int aggregate_stats_dump(struct datapath *dp, void *state, + void *body, int *body_len) +{ + struct ofp_aggregate_stats_request *rq = state; + struct ofp_aggregate_stats_reply *rpy; + struct sw_table_position position; + struct sw_flow_key match_key; + int table_idx; + int error = 0; + + if (*body_len < sizeof *rpy) + return -ENOBUFS; + rpy = body; + *body_len = sizeof *rpy; + + memset(rpy, 0, sizeof *rpy); + + flow_extract_match(&match_key, &rq->match); + table_idx = rq->table_id == 0xff ? 0 : rq->table_id; + memset(&position, 0, sizeof position); + + if (rq->table_id == EMERG_TABLE_ID_FOR_STATS) { + struct sw_table *table = dp->chain->emerg_table; + + error = table->iterate(table, &match_key, rq->out_port, + &position, + aggregate_stats_dump_callback, rpy); + if (error) + return error; + } else { + while (table_idx < dp->chain->n_tables + && (rq->table_id == 0xff || rq->table_id == table_idx)) { + struct sw_table *table = dp->chain->tables[table_idx]; + + error = table->iterate(table, &match_key, rq->out_port, + &position, + aggregate_stats_dump_callback, + rpy); + if (error) + return error; + + table_idx++; + memset(&position, 0, sizeof position); + } + } + + rpy->packet_count = cpu_to_be64(rpy->packet_count); + rpy->byte_count = cpu_to_be64(rpy->byte_count); + rpy->flow_count = htonl(rpy->flow_count); + return 0; +} + +static int table_stats_dump(struct datapath *dp, void *state, + void *body, int *body_len) +{ + struct ofp_table_stats *ots; + int n_bytes = dp->chain->n_tables * sizeof *ots; + int i; + if (n_bytes > *body_len) + return -ENOBUFS; + *body_len = n_bytes; + for (i = 0, ots = body; i < dp->chain->n_tables; i++, ots++) { + struct sw_table_stats stats; + dp->chain->tables[i]->stats(dp->chain->tables[i], &stats); + strncpy(ots->name, stats.name, sizeof ots->name); + ots->table_id = i; + ots->wildcards = htonl(stats.wildcards); + memset(ots->pad, 0, sizeof ots->pad); + ots->max_entries = htonl(stats.max_flows); + ots->active_count = htonl(stats.n_flows); + ots->lookup_count = cpu_to_be64(stats.n_lookup); + ots->matched_count = cpu_to_be64(stats.n_matched); + } + return 0; +} + +struct port_stats_state { + int start_port; /* port to start dumping from */ + int port_no; /* from ofp_port_stats_request */ +}; + +static int port_stats_init(struct datapath *dp, const void *body, int body_len, + void **state) +{ + struct port_stats_state *s = kmalloc(sizeof *s, GFP_ATOMIC); + struct ofp_port_stats_request *psr + = (struct ofp_port_stats_request *)body; + + if (!s) + return -ENOMEM; + s->start_port = 1; + s->port_no = ntohs(psr->port_no); + *state = s; + return 0; +} + +static void +dump_port_stats(struct ofp_port_stats *ops, struct net_bridge_port *p) +{ + struct net_device_stats *stats; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) + stats = p->dev->netdev_ops->ndo_get_stats(p->dev); +#else + stats = p->dev->get_stats(p->dev); +#endif + ops->port_no = htons(p->port_no); + memset(ops->pad, 0, sizeof ops->pad); + ops->rx_packets = cpu_to_be64(stats->rx_packets); + ops->tx_packets = cpu_to_be64(stats->tx_packets); + ops->rx_bytes = cpu_to_be64(stats->rx_bytes); + ops->tx_bytes = cpu_to_be64(stats->tx_bytes); + ops->rx_dropped = cpu_to_be64(stats->rx_dropped); + ops->tx_dropped = cpu_to_be64(stats->tx_dropped); + ops->rx_errors = cpu_to_be64(stats->rx_errors); + ops->tx_errors = cpu_to_be64(stats->tx_errors); + ops->rx_frame_err = cpu_to_be64(stats->rx_frame_errors); + ops->rx_over_err = cpu_to_be64(stats->rx_over_errors); + ops->rx_crc_err = cpu_to_be64(stats->rx_crc_errors); + ops->collisions = cpu_to_be64(stats->collisions); +} + +static struct net_bridge_port * +lookup_port(struct datapath *dp, uint16_t port_no) +{ + return (port_no < DP_MAX_PORTS ? dp->ports[port_no] + : port_no == OFPP_LOCAL ? dp->local_port + : NULL); +} + + +static int port_stats_dump(struct datapath *dp, void *state, + void *body, int *body_len) +{ + struct port_stats_state *s = state; + struct net_bridge_port *p = NULL; + struct ofp_port_stats *ops = NULL; + int n_ports = 0; + int max_ports = 0; + int i = 0; + + max_ports = *body_len / sizeof *ops; + if (!max_ports) + return -ENOMEM; + ops = body; + + if (s->port_no == OFPP_NONE) { + for (i = s->start_port; i < DP_MAX_PORTS && n_ports < max_ports; + i++) { + p = dp->ports[i]; + if (!p) + continue; + dump_port_stats(ops, p); + n_ports++; + ops++; + } + s->start_port = i; + if (dp->local_port) { + dump_port_stats(ops, dp->local_port); + n_ports++; + ops++; + s->start_port = OFPP_LOCAL + 1; /* == OFPP_NONE, > DP_MAX_PORTS */ + } + } else { + p = lookup_port(dp, s->port_no); + if (p) { + dump_port_stats(ops, p); + n_ports++; + ops++; + } + } + + *body_len = n_ports * sizeof *ops; + return n_ports >= max_ports; +} + +static void port_stats_done(void *state) +{ + kfree(state); +} + +/* + * We don't define any vendor_stats_state, we let the actual + * vendor implementation do that. + * The only requirement is that the first member of that object + * should be the vendor id. + * Jean II + * + * Basically, it would look like : + * struct acme_stats_state { + * uint32_t vendor; // ACME_VENDOR_ID. + * <...> // Other stuff. + * }; + */ +static int vendor_stats_init(struct datapath *dp, const void *body, + int body_len, void **state) +{ + /* min_body was checked, this is safe */ + const uint32_t vendor = ntohl(*((uint32_t *)body)); + int err; + + switch (vendor) { + default: + err = -EINVAL; + } + + return err; +} + +static int vendor_stats_dump(struct datapath *dp, void *state, void *body, + int *body_len) +{ + const uint32_t vendor = *((uint32_t *)state); + int newbuf; + + switch (vendor) { + default: + /* Should never happen */ + newbuf = 0; + } + + return newbuf; +} + +static void vendor_stats_done(void *state) +{ + const uint32_t vendor = *((uint32_t *)state); + + switch (vendor) { + default: + /* Should never happen */ + kfree(state); + } + + return; +} + +struct stats_type { + /* Minimum and maximum acceptable number of bytes in body member of + * struct ofp_stats_request. */ + size_t min_body, max_body; + + /* Prepares to dump some kind of statistics on 'dp'. 'body' and + * 'body_len' are the 'body' member of the struct ofp_stats_request. + * Returns zero if successful, otherwise a negative error code. + * May initialize '*state' to state information. May be null if no + * initialization is required.*/ + int (*init)(struct datapath *dp, const void *body, int body_len, + void **state); + + /* Dumps statistics for 'dp' into the '*body_len' bytes at 'body', and + * modifies '*body_len' to reflect the number of bytes actually used. + * ('body' will be transmitted as the 'body' member of struct + * ofp_stats_reply.) */ + int (*dump)(struct datapath *dp, void *state, + void *body, int *body_len); + + /* Cleans any state created by the init or dump functions. May be null + * if no cleanup is required. */ + void (*done)(void *state); +}; + +static const struct stats_type stats[] = { + [OFPST_DESC] = { + 0, + 0, + NULL, + desc_stats_dump, + NULL + }, + [OFPST_FLOW] = { + sizeof(struct ofp_flow_stats_request), + sizeof(struct ofp_flow_stats_request), + flow_stats_init, + flow_stats_dump, + flow_stats_done + }, + [OFPST_AGGREGATE] = { + sizeof(struct ofp_aggregate_stats_request), + sizeof(struct ofp_aggregate_stats_request), + aggregate_stats_init, + aggregate_stats_dump, + NULL + }, + [OFPST_TABLE] = { + 0, + 0, + NULL, + table_stats_dump, + NULL + }, + [OFPST_PORT] = { + sizeof(struct ofp_port_stats_request), + sizeof(struct ofp_port_stats_request), + port_stats_init, + port_stats_dump, + port_stats_done + }, +}; + +/* For OFPST_VENDOR... Jean II */ +static const struct stats_type stats_vendor = { + 8, /* vendor + subtype */ + 32, /* whatever */ + vendor_stats_init, + vendor_stats_dump, + vendor_stats_done +}; + +static int +dp_genl_openflow_dumpit(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct datapath *dp; + struct sender sender; + const struct stats_type *s; + struct ofp_stats_reply *osr; + int dp_idx; + int max_openflow_len, body_len; + void *body; + int err; + + /* Set up the cleanup function for this dump. Linux 2.6.20 and later + * support setting up cleanup functions via the .doneit member of + * struct genl_ops. This kluge supports earlier versions also. */ + cb->done = dp_genl_openflow_done; + + sender.pid = NETLINK_CB(cb->skb).pid; + sender.seq = cb->nlh->nlmsg_seq; + if (!cb->args[0]) { + struct nlattr *attrs[DP_GENL_A_MAX + 1]; + struct ofp_stats_request *rq; + struct nlattr *va; + size_t len, body_len; + int type; + + err = nlmsg_parse(cb->nlh, GENL_HDRLEN, attrs, DP_GENL_A_MAX, + dp_genl_openflow_policy); + if (err < 0) + return err; + + if (!attrs[DP_GENL_A_DP_IDX]) + return -EINVAL; + dp_idx = nla_get_u16(attrs[DP_GENL_A_DP_IDX]); + dp = dp_get_by_idx(dp_idx); + if (!dp) + return -ENOENT; + + va = attrs[DP_GENL_A_OPENFLOW]; + len = nla_len(va); + if (!va || len < sizeof *rq) + return -EINVAL; + + rq = nla_data(va); + sender.xid = rq->header.xid; + type = ntohs(rq->type); + if (rq->header.version != OFP_VERSION) { + dp_send_error_msg(dp, &sender, OFPET_BAD_REQUEST, + OFPBRC_BAD_VERSION, rq, len); + return -EINVAL; + } + if (rq->header.type != OFPT_STATS_REQUEST + || ntohs(rq->header.length) != len) + return -EINVAL; + + if (type == OFPST_VENDOR) { + /* Vendor is not in the array, take care of it */ + s = &stats_vendor; + } else { + if (type >= ARRAY_SIZE(stats) || !stats[type].dump) { + dp_send_error_msg(dp, &sender, + OFPET_BAD_REQUEST, + OFPBRC_BAD_STAT, rq, len); + return -EINVAL; + } + s = &stats[type]; + } + body_len = len - offsetof(struct ofp_stats_request, body); + if (body_len < s->min_body || body_len > s->max_body) + return -EINVAL; + + cb->args[0] = 1; + cb->args[1] = dp_idx; + cb->args[2] = type; + cb->args[3] = rq->header.xid; + if (s->init) { + void *state; + err = s->init(dp, rq->body, body_len, &state); + if (err) + return err; + cb->args[4] = (long) state; + } + } else if (cb->args[0] == 1) { + sender.xid = cb->args[3]; + dp_idx = cb->args[1]; + if (cb->args[2] == OFPST_VENDOR) { + /* Vendor is not in the array, take care of it */ + s = &stats_vendor; + } else { + s = &stats[cb->args[2]]; + } + + dp = dp_get_by_idx(dp_idx); + if (!dp) + return -ENOENT; + } else { + return 0; + } + + osr = put_openflow_headers(dp, skb, OFPT_STATS_REPLY, &sender, + &max_openflow_len); + if (IS_ERR(osr)) + return PTR_ERR(osr); + osr->type = htons(cb->args[2]); + osr->flags = 0; + resize_openflow_skb(skb, &osr->header, max_openflow_len); + body = osr->body; + body_len = max_openflow_len - offsetof(struct ofp_stats_reply, body); + + err = s->dump(dp, (void *) cb->args[4], body, &body_len); + if (err >= 0) { + if (!err) + cb->args[0] = 2; + else + osr->flags = ntohs(OFPSF_REPLY_MORE); + resize_openflow_skb(skb, &osr->header, + (offsetof(struct ofp_stats_reply, body) + + body_len)); + err = skb->len; + } + + return err; +} + +static int +dp_genl_openflow_done(struct netlink_callback *cb) +{ + if (cb->args[0]) { + const struct stats_type *s; + if (cb->args[2] == OFPST_VENDOR) { + /* Vendor is not in the array, take care of it */ + s = &stats_vendor; + } else { + s = &stats[cb->args[2]]; + } + if (s->done) + s->done((void *) cb->args[4]); + } + return 0; +} + +static struct genl_ops dp_genl_ops_openflow = { + .cmd = DP_GENL_C_OPENFLOW, + .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ + .policy = dp_genl_openflow_policy, + .doit = dp_genl_openflow, + .dumpit = dp_genl_openflow_dumpit, +}; + +static struct genl_ops *dp_genl_all_ops[] = { + /* Keep this operation first. Generic Netlink dispatching + * looks up operations with linear search, so we want it at the + * front. */ + &dp_genl_ops_openflow, + + &dp_genl_ops_add_dp, + &dp_genl_ops_del_dp, + &dp_genl_ops_query_dp, + &dp_genl_ops_add_port, + &dp_genl_ops_del_port, +}; + +static int dp_init_netlink(void) +{ + int err; + int i; + + err = genl_register_family(&dp_genl_family); + if (err) + return err; + + for (i = 0; i < ARRAY_SIZE(dp_genl_all_ops); i++) { + err = genl_register_ops(&dp_genl_family, dp_genl_all_ops[i]); + if (err) + goto err_unregister; + } + + for (i = 0; i < N_MC_GROUPS; i++) { + snprintf(mc_groups[i].name, sizeof mc_groups[i].name, + "openflow%d", i); + err = genl_register_mc_group(&dp_genl_family, &mc_groups[i]); + if (err < 0) + goto err_unregister; + } + + return 0; + +err_unregister: + genl_unregister_family(&dp_genl_family); + return err; +} + +static void dp_uninit_netlink(void) +{ + genl_unregister_family(&dp_genl_family); +} + +/* Set the description strings if appropriate values are available from + * the DMI. */ +static void set_desc(void) +{ + const char *uuid = dmi_get_system_info(DMI_PRODUCT_UUID); + const char *vendor = dmi_get_system_info(DMI_SYS_VENDOR); + const char *name = dmi_get_system_info(DMI_PRODUCT_NAME); + const char *version = dmi_get_system_info(DMI_PRODUCT_VERSION); + const char *serial = dmi_get_system_info(DMI_PRODUCT_SERIAL); + const char *uptr; + + if (!uuid || *uuid == '\0' || strlen(uuid) != 36) + return; + + /* We are only interested version 1 UUIDs, since the last six bytes + * are an IEEE 802 MAC address. */ + if (uuid[14] != '1') + return; + + /* Only set if the UUID is from Nicira. */ + uptr = uuid + 24; + if (strncmp(uptr, NICIRA_OUI_STR, strlen(NICIRA_OUI_STR))) + return; + + if (vendor) + strlcpy(mfr_desc, vendor, sizeof(mfr_desc)); + if (name || version) + snprintf(hw_desc, sizeof(hw_desc), "%s %s", + name ? name : "", + version ? version : ""); + if (serial) + strlcpy(serial_num, serial, sizeof(serial_num)); +} + +static int __init dp_init(void) +{ + int err; + + printk("OpenFlow %s, built "__DATE__" "__TIME__", " + "protocol 0x%02x\n", VERSION BUILDNR, OFP_VERSION); + + err = flow_init(); + if (err) + goto error; + + err = register_netdevice_notifier(&dp_device_notifier); + if (err) + goto error_flow_exit; + + err = dp_init_netlink(); + if (err) + goto error_unreg_notifier; + + dp_ioctl_hook = NULL; + dp_add_dp_hook = NULL; + dp_del_dp_hook = NULL; + dp_add_if_hook = NULL; + dp_del_if_hook = NULL; + + /* Check if better descriptions of the switch are available than the + * defaults. */ + set_desc(); + + /* Hook into callback used by the bridge to intercept packets. + * Parasites we are. */ + if (br_handle_frame_hook) + printk("openflow: hijacking bridge hook\n"); + br_handle_frame_hook = dp_frame_hook; + + return 0; + +error_unreg_notifier: + unregister_netdevice_notifier(&dp_device_notifier); +error_flow_exit: + flow_exit(); +error: + printk(KERN_EMERG "openflow: failed to install!"); + return err; +} + +static void dp_cleanup(void) +{ + fwd_exit(); + dp_uninit_netlink(); + unregister_netdevice_notifier(&dp_device_notifier); + flow_exit(); + br_handle_frame_hook = NULL; +} + +module_init(dp_init); +module_exit(dp_cleanup); + +MODULE_DESCRIPTION("OpenFlow Switching Datapath"); +MODULE_AUTHOR("Copyright (c) 2007, 2008 The Board of Trustees of The Leland Stanford Junior University"); +MODULE_LICENSE("GPL"); diff --git a/openflow/datapath/datapath.h b/openflow/datapath/datapath.h new file mode 100644 index 00000000..79ae0b78 --- /dev/null +++ b/openflow/datapath/datapath.h @@ -0,0 +1,114 @@ +/* Interface exported by OpenFlow module. */ + +#ifndef DATAPATH_H +#define DATAPATH_H 1 + +#include +#include +#include +#include +#include +#include +#include "openflow/openflow.h" +#include "openflow/nicira-ext.h" +#include "flow.h" + + +#define NL_FLOWS_PER_MESSAGE 100 + +/* Capabilities supported by this implementation. */ +#define OFP_SUPPORTED_CAPABILITIES ( OFPC_FLOW_STATS \ + | OFPC_TABLE_STATS \ + | OFPC_PORT_STATS ) + +/* Actions supported by this implementation. */ +#define OFP_SUPPORTED_ACTIONS ( (1 << OFPAT_OUTPUT) \ + | (1 << OFPAT_SET_VLAN_VID) \ + | (1 << OFPAT_SET_VLAN_PCP) \ + | (1 << OFPAT_STRIP_VLAN) \ + | (1 << OFPAT_SET_DL_SRC) \ + | (1 << OFPAT_SET_DL_DST) \ + | (1 << OFPAT_SET_NW_SRC) \ + | (1 << OFPAT_SET_NW_DST) \ + | (1 << OFPAT_SET_TP_SRC) \ + | (1 << OFPAT_SET_TP_DST) ) + +struct sk_buff; + +#define DP_MAX_PORTS 255 + +struct datapath { + int dp_idx; + + struct timer_list timer; /* Expiration timer. */ + struct sw_chain *chain; /* Forwarding rules. */ + struct task_struct *dp_task; /* Kernel thread for maintenance. */ + + /* Data related to the "of" device of this datapath */ + struct net_device *netdev; + char dp_desc[DESC_STR_LEN]; /* human readible comment to ID this DP */ + + /* Configuration set from controller */ + uint16_t flags; + uint16_t miss_send_len; + + struct kobject ifobj; + + /* Switch ports. */ + struct net_bridge_port *ports[DP_MAX_PORTS]; + struct net_bridge_port *local_port; /* OFPP_LOCAL port. */ + struct list_head port_list; /* All ports, including local_port. */ +}; + +/* Information necessary to reply to the sender of an OpenFlow message. */ +struct sender { + uint32_t xid; /* OpenFlow transaction ID of request. */ + uint32_t pid; /* Netlink process ID of sending socket. */ + uint32_t seq; /* Netlink sequence ID of request. */ +}; + +struct net_bridge_port { + u16 port_no; + u32 config; /* Some subset of OFPPC_* flags. */ + u32 state; /* Some subset of OFPPS_* flags. */ + spinlock_t lock; + struct datapath *dp; + struct net_device *dev; + struct kobject kobj; + struct list_head node; /* Element in datapath.ports. */ +}; + +extern struct mutex dp_mutex; +extern struct notifier_block dp_device_notifier; +extern int (*dp_ioctl_hook)(struct net_device *dev, struct ifreq *rq, int cmd); +extern int (*dp_add_dp_hook)(struct datapath *dp); +extern int (*dp_del_dp_hook)(struct datapath *dp); +extern int (*dp_add_if_hook)(struct net_bridge_port *p); +extern int (*dp_del_if_hook)(struct net_bridge_port *p); + +int dp_del_switch_port(struct net_bridge_port *); +int dp_xmit_skb(struct sk_buff *skb); +int dp_output_port(struct datapath *, struct sk_buff *, int out_port, + int ignore_no_fwd); +int dp_output_control(struct datapath *, struct sk_buff *, size_t, int); +void dp_set_origin(struct datapath *, uint16_t, struct sk_buff *); +int dp_send_features_reply(struct datapath *, const struct sender *); +int dp_send_config_reply(struct datapath *, const struct sender *); +int dp_send_port_status(struct net_bridge_port *p, uint8_t status); +int dp_send_flow_end(struct datapath *, struct sw_flow *, + enum ofp_flow_removed_reason); +int dp_send_error_msg(struct datapath *, const struct sender *, + uint16_t, uint16_t, const void *, size_t); +int dp_update_port_flags(struct datapath *dp, const struct ofp_port_mod *opm); +int dp_send_echo_reply(struct datapath *, const struct sender *, + const struct ofp_header *); +int dp_send_hello(struct datapath *, const struct sender *, + const struct ofp_header *); +int dp_send_barrier_reply(struct datapath *, const struct sender *, + const struct ofp_header *); + +/* Should hold at least RCU read lock when calling */ +struct datapath *dp_get_by_idx(int dp_idx); +struct datapath *dp_get_by_name(const char *dp_name); + +#endif /* datapath.h */ diff --git a/openflow/datapath/dp_act.c b/openflow/datapath/dp_act.c new file mode 100644 index 00000000..7532c00c --- /dev/null +++ b/openflow/datapath/dp_act.c @@ -0,0 +1,543 @@ +/* + * Distributed under the terms of the GNU GPL version 2. + * Copyright (c) 2007, 2008, 2009 The Board of Trustees of The Leland + * Stanford Junior University + */ + +/* Functions for executing OpenFlow actions. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "forward.h" +#include "dp_act.h" +#include "openflow/nicira-ext.h" +#include "flow.h" + + +static uint16_t +validate_output(struct datapath *dp, const struct sw_flow_key *key, + const struct ofp_action_header *ah) +{ + struct ofp_action_output *oa = (struct ofp_action_output *)ah; + + if (oa->port == htons(OFPP_NONE) || + (!(key->wildcards & OFPFW_IN_PORT) && oa->port == key->in_port)) + return OFPBAC_BAD_OUT_PORT; + + return ACT_VALIDATION_OK; +} + +static int +do_output(struct datapath *dp, struct sk_buff *skb, size_t max_len, + int out_port, int ignore_no_fwd) +{ + if (!skb) + return -ENOMEM; + return (likely(out_port != OFPP_CONTROLLER) + ? dp_output_port(dp, skb, out_port, ignore_no_fwd) + : dp_output_control(dp, skb, max_len, OFPR_ACTION)); +} + + +static struct sk_buff * +vlan_pull_tag(struct sk_buff *skb) +{ + struct vlan_ethhdr *vh = vlan_eth_hdr(skb); + struct ethhdr *eh; + + + /* Verify we were given a vlan packet */ + if (vh->h_vlan_proto != htons(ETH_P_8021Q)) + return skb; + + memmove(skb->data + VLAN_HLEN, skb->data, 2 * VLAN_ETH_ALEN); + + eh = (struct ethhdr *)skb_pull(skb, VLAN_HLEN); + + skb->protocol = eh->h_proto; + skb->mac_header += VLAN_HLEN; + + return skb; +} + + +static struct sk_buff * +modify_vlan_tci(struct sk_buff *skb, struct sw_flow_key *key, + uint16_t tci, uint16_t mask) +{ + struct vlan_ethhdr *vh = vlan_eth_hdr(skb); + + if (key->dl_vlan != htons(OFP_VLAN_NONE)) { + /* Modify vlan id, but maintain other TCI values */ + vh->h_vlan_TCI = (vh->h_vlan_TCI & ~(htons(mask))) | htons(tci); + } else { + /* Add vlan header */ + + /* xxx The vlan_put_tag function, doesn't seem to work + * xxx reliably when it attempts to use the hardware-accelerated + * xxx version. We'll directly use the software version + * xxx until the problem can be diagnosed. + */ + skb = __vlan_put_tag(skb, tci); + vh = vlan_eth_hdr(skb); + } + key->dl_vlan = vh->h_vlan_TCI & htons(VLAN_VID_MASK); + key->dl_vlan_pcp = (uint8_t)((ntohs(vh->h_vlan_TCI) >> VLAN_PCP_SHIFT) + & VLAN_PCP_BITMASK); + + return skb; +} + +static struct sk_buff * +set_vlan_vid(struct sk_buff *skb, struct sw_flow_key *key, + const struct ofp_action_header *ah) +{ + struct ofp_action_vlan_vid *va = (struct ofp_action_vlan_vid *)ah; + uint16_t tci = ntohs(va->vlan_vid); + + return modify_vlan_tci(skb, key, tci, VLAN_VID_MASK); +} + +/* Mask for the priority bits in a vlan header. The kernel doesn't + * define this like it does for VID. */ +#define VLAN_PCP_MASK 0xe000 + +static struct sk_buff * +set_vlan_pcp(struct sk_buff *skb, struct sw_flow_key *key, + const struct ofp_action_header *ah) +{ + struct ofp_action_vlan_pcp *va = (struct ofp_action_vlan_pcp *)ah; + uint16_t tci = (uint16_t)va->vlan_pcp << 13; + + return modify_vlan_tci(skb, key, tci, VLAN_PCP_MASK); +} + +static struct sk_buff * +strip_vlan(struct sk_buff *skb, struct sw_flow_key *key, + const struct ofp_action_header *ah) +{ + vlan_pull_tag(skb); + key->dl_vlan = htons(OFP_VLAN_NONE); + + return skb; +} + +static struct sk_buff * +set_dl_addr(struct sk_buff *skb, struct sw_flow_key *key, + const struct ofp_action_header *ah) +{ + struct ofp_action_dl_addr *da = (struct ofp_action_dl_addr *)ah; + struct ethhdr *eh = eth_hdr(skb); + + if (da->type == htons(OFPAT_SET_DL_SRC)) + memcpy(eh->h_source, da->dl_addr, sizeof eh->h_source); + else + memcpy(eh->h_dest, da->dl_addr, sizeof eh->h_dest); + + return skb; +} + +/* Updates 'sum', which is a field in 'skb''s data, given that a 4-byte field + * covered by the sum has been changed from 'from' to 'to'. If set, + * 'pseudohdr' indicates that the field is in the TCP or UDP pseudo-header. + * Based on nf_proto_csum_replace4. */ +static void update_csum(__sum16 *sum, struct sk_buff *skb, + __be32 from, __be32 to, int pseudohdr) +{ + __be32 diff[] = { ~from, to }; + if (skb->ip_summed != CHECKSUM_PARTIAL) { + *sum = csum_fold(csum_partial((char *)diff, sizeof(diff), + ~csum_unfold(*sum))); + if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr) + skb->csum = ~csum_partial((char *)diff, sizeof(diff), + ~skb->csum); + } else if (pseudohdr) + *sum = ~csum_fold(csum_partial((char *)diff, sizeof(diff), + csum_unfold(*sum))); +} + +static struct sk_buff * +set_nw_addr(struct sk_buff *skb, struct sw_flow_key *key, + const struct ofp_action_header *ah) +{ + struct ofp_action_nw_addr *na = (struct ofp_action_nw_addr *)ah; + uint16_t eth_proto = ntohs(key->dl_type); + + if (eth_proto == ETH_P_IP) { + struct iphdr *nh = ip_hdr(skb); + uint32_t new, *field; + + new = na->nw_addr; + + if (ah->type == htons(OFPAT_SET_NW_SRC)) + field = &nh->saddr; + else + field = &nh->daddr; + + if (key->nw_proto == IPPROTO_TCP) { + struct tcphdr *th = tcp_hdr(skb); + update_csum(&th->check, skb, *field, new, 1); + } else if (key->nw_proto == IPPROTO_UDP) { + struct udphdr *th = udp_hdr(skb); + update_csum(&th->check, skb, *field, new, 1); + } + update_csum(&nh->check, skb, *field, new, 0); + *field = new; + } + + return skb; +} + +static struct sk_buff * +set_nw_tos(struct sk_buff *skb, struct sw_flow_key *key, + const struct ofp_action_header *ah) +{ + struct ofp_action_nw_tos *nt = (struct ofp_action_nw_tos *)ah; + uint16_t eth_proto = ntohs(key->dl_type); + + if (eth_proto == ETH_P_IP) { + struct iphdr *nh = ip_hdr(skb); + uint8_t new, *field; + + /* JeanII : Set only 6 bits, don't clobber ECN */ + new = (nt->nw_tos & 0xFC) | (nh->tos & 0x03); + + /* Get address of field */ + field = &nh->tos; + /* jklee : ip tos field is not included in TCP pseudo header. + * Need magic as update_csum() don't work with 8 bits. */ + update_csum(&nh->check, skb, htons((uint16_t)*field), + htons((uint16_t)new), 0); + + /* Update in packet */ + *field = new; + } + + return skb; +} + +static struct sk_buff * +set_tp_port(struct sk_buff *skb, struct sw_flow_key *key, + const struct ofp_action_header *ah) +{ + struct ofp_action_tp_port *ta = (struct ofp_action_tp_port *)ah; + uint16_t eth_proto = ntohs(key->dl_type); + + if (eth_proto == ETH_P_IP) { + uint16_t new, *field; + + new = ta->tp_port; + + if (key->nw_proto == IPPROTO_TCP) { + struct tcphdr *th = tcp_hdr(skb); + + if (ah->type == htons(OFPAT_SET_TP_SRC)) + field = &th->source; + else + field = &th->dest; + + update_csum(&th->check, skb, *field, new, 1); + *field = new; + } else if (key->nw_proto == IPPROTO_UDP) { + struct udphdr *th = udp_hdr(skb); + + if (ah->type == htons(OFPAT_SET_TP_SRC)) + field = &th->source; + else + field = &th->dest; + + update_csum(&th->check, skb, *field, new, 1); + *field = new; + } + } + + return skb; +} + +struct openflow_action { + size_t min_size; + size_t max_size; + uint16_t (*validate)(struct datapath *dp, + const struct sw_flow_key *key, + const struct ofp_action_header *ah); + struct sk_buff *(*execute)(struct sk_buff *skb, + struct sw_flow_key *key, + const struct ofp_action_header *ah); +}; + +static const struct openflow_action of_actions[] = { + [OFPAT_OUTPUT] = { + sizeof(struct ofp_action_output), + sizeof(struct ofp_action_output), + validate_output, + NULL /* This is optimized into execute_actions */ + }, + [OFPAT_SET_VLAN_VID] = { + sizeof(struct ofp_action_vlan_vid), + sizeof(struct ofp_action_vlan_vid), + NULL, + set_vlan_vid + }, + [OFPAT_SET_VLAN_PCP] = { + sizeof(struct ofp_action_vlan_pcp), + sizeof(struct ofp_action_vlan_pcp), + NULL, + set_vlan_pcp + }, + [OFPAT_STRIP_VLAN] = { + sizeof(struct ofp_action_header), + sizeof(struct ofp_action_header), + NULL, + strip_vlan + }, + [OFPAT_SET_DL_SRC] = { + sizeof(struct ofp_action_dl_addr), + sizeof(struct ofp_action_dl_addr), + NULL, + set_dl_addr + }, + [OFPAT_SET_DL_DST] = { + sizeof(struct ofp_action_dl_addr), + sizeof(struct ofp_action_dl_addr), + NULL, + set_dl_addr + }, + [OFPAT_SET_NW_SRC] = { + sizeof(struct ofp_action_nw_addr), + sizeof(struct ofp_action_nw_addr), + NULL, + set_nw_addr + }, + [OFPAT_SET_NW_DST] = { + sizeof(struct ofp_action_nw_addr), + sizeof(struct ofp_action_nw_addr), + NULL, + set_nw_addr + }, + [OFPAT_SET_NW_TOS] = { + sizeof(struct ofp_action_nw_tos), + sizeof(struct ofp_action_nw_tos), + NULL, + set_nw_tos + }, + [OFPAT_SET_TP_SRC] = { + sizeof(struct ofp_action_tp_port), + sizeof(struct ofp_action_tp_port), + NULL, + set_tp_port + }, + [OFPAT_SET_TP_DST] = { + sizeof(struct ofp_action_tp_port), + sizeof(struct ofp_action_tp_port), + NULL, + set_tp_port + } + /* OFPAT_VENDOR is not here, since it would blow up the array size. */ +}; + +/* Validate built-in OpenFlow actions. Either returns ACT_VALIDATION_OK + * or an OFPET_BAD_ACTION error code. */ +static uint16_t +validate_ofpat(struct datapath *dp, const struct sw_flow_key *key, + const struct ofp_action_header *ah, uint16_t type, uint16_t len) +{ + uint16_t ret = ACT_VALIDATION_OK; + const struct openflow_action *act = &of_actions[type]; + + if ((len < act->min_size) || (len > act->max_size)) + return OFPBAC_BAD_LEN; + + if (act->validate) + ret = act->validate(dp, key, ah); + + return ret; +} + +/* Validate vendor-defined actions. Either returns ACT_VALIDATION_OK + * or an OFPET_BAD_ACTION error code. */ +static uint16_t +validate_vendor(struct datapath *dp, const struct sw_flow_key *key, + const struct ofp_action_header *ah, uint16_t len) +{ + struct ofp_action_vendor_header *avh; + int ret = ACT_VALIDATION_OK; + + if (len < sizeof(struct ofp_action_vendor_header)) + return OFPBAC_BAD_LEN; + + avh = (struct ofp_action_vendor_header *)ah; + + switch(ntohl(avh->vendor)) { + default: + return OFPBAC_BAD_VENDOR; + } + + return ret; +} + +/* Validates a list of actions. If a problem is found, a code for the + * OFPET_BAD_ACTION error type is returned. If the action list validates, + * ACT_VALIDATION_OK is returned. */ +uint16_t +validate_actions(struct datapath *dp, const struct sw_flow_key *key, + const struct ofp_action_header *actions, size_t actions_len) +{ + uint8_t *p = (uint8_t *)actions; + int err; + + while (actions_len >= sizeof(struct ofp_action_header)) { + struct ofp_action_header *ah = (struct ofp_action_header *)p; + size_t len = ntohs(ah->len); + uint16_t type; + + /* Make there's enough remaining data for the specified length + * and that the action length is a multiple of 64 bits. */ + if ((actions_len < len) || (len % 8) != 0) + return OFPBAC_BAD_LEN; + + type = ntohs(ah->type); + if (type < ARRAY_SIZE(of_actions)) { + err = validate_ofpat(dp, key, ah, type, len); + if (err != ACT_VALIDATION_OK) + return err; + } else if (type == OFPAT_VENDOR) { + err = validate_vendor(dp, key, ah, len); + if (err != ACT_VALIDATION_OK) + return err; + } else + return OFPBAC_BAD_TYPE; + + p += len; + actions_len -= len; + } + + /* Check if there's any trailing garbage. */ + if (actions_len != 0) + return OFPBAC_BAD_LEN; + + return ACT_VALIDATION_OK; +} + +/* Execute a built-in OpenFlow action against 'skb'. */ +static struct sk_buff * +execute_ofpat(struct sk_buff *skb, struct sw_flow_key *key, + const struct ofp_action_header *ah, uint16_t type) +{ + const struct openflow_action *act = &of_actions[type]; + if (act->execute && make_writable(&skb)) + skb = act->execute(skb, key, ah); + return skb; +} + +/* Execute a vendor-defined action against 'skb'. */ +static struct sk_buff * +execute_vendor(struct sk_buff *skb, const struct sw_flow_key *key, + const struct ofp_action_header *ah) +{ + struct ofp_action_vendor_header *avh + = (struct ofp_action_vendor_header *)ah; + struct datapath *dp = skb->dev->br_port->dp; + + /* NB: If changes need to be made to the packet, a call should be + * made to make_writable or its equivalent first. */ + + switch(ntohl(avh->vendor)) { + default: + /* This should not be possible due to prior validation. */ + if (net_ratelimit()) + printk(KERN_WARNING "%s: attempt to execute action " + "with unknown vendor: %#x\n", + dp->netdev->name, ntohl(avh->vendor)); + break; + } + + return skb; +} + +/* Execute a list of actions against 'skb'. */ +void execute_actions(struct datapath *dp, struct sk_buff *skb, + struct sw_flow_key *key, + const struct ofp_action_header *actions, size_t actions_len, + int ignore_no_fwd) +{ + /* Every output action needs a separate clone of 'skb', but the common + * case is just a single output action, so that doing a clone and + * then freeing the original skbuff is wasteful. So the following code + * is slightly obscure just to avoid that. */ + int prev_port; + size_t max_len = UINT16_MAX; + uint8_t *p = (uint8_t *)actions; + + prev_port = -1; + + /* The action list was already validated, so we can be a bit looser + * in our sanity-checking. */ + while (actions_len > 0) { + struct ofp_action_header *ah = (struct ofp_action_header *)p; + size_t len = htons(ah->len); + + WARN_ON_ONCE(skb_shared(skb)); + if (prev_port != -1) { + do_output(dp, skb_clone(skb, GFP_ATOMIC), + max_len, prev_port, ignore_no_fwd); + prev_port = -1; + } + + if (likely(ah->type == htons(OFPAT_OUTPUT))) { + struct ofp_action_output *oa = (struct ofp_action_output *)p; + prev_port = ntohs(oa->port); + max_len = ntohs(oa->max_len); + } else { + uint16_t type = ntohs(ah->type); + + if (type < ARRAY_SIZE(of_actions)) + skb = execute_ofpat(skb, key, ah, type); + else if (type == OFPAT_VENDOR) + skb = execute_vendor(skb, key, ah); + + if (!skb) { + if (net_ratelimit()) + printk(KERN_WARNING "%s: " + "execute_actions lost skb\n", + dp->netdev->name); + return; + } + } + + p += len; + actions_len -= len; + } + if (prev_port != -1) + do_output(dp, skb, max_len, prev_port, ignore_no_fwd); + else + kfree_skb(skb); +} + +/* Utility functions. */ + +/* Makes '*pskb' writable, possibly copying it and setting '*pskb' to point to + * the copy. + * Returns 1 if successful, 0 on failure. */ +int +make_writable(struct sk_buff **pskb) +{ + struct sk_buff *skb = *pskb; + if (skb_shared(skb) || skb_cloned(skb)) { + struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC); + if (!nskb) + return 0; + kfree_skb(skb); + *pskb = nskb; + return 1; + } else { + unsigned int hdr_len = (skb_transport_offset(skb) + + sizeof(struct tcphdr)); + return pskb_may_pull(skb, min(hdr_len, skb->len)); + } +} diff --git a/openflow/datapath/dp_act.h b/openflow/datapath/dp_act.h new file mode 100644 index 00000000..d601eca0 --- /dev/null +++ b/openflow/datapath/dp_act.h @@ -0,0 +1,15 @@ +#ifndef DP_ACT_H +#define DP_ACT_H 1 + +#include "datapath.h" + +#define ACT_VALIDATION_OK ((uint16_t)-1) + +uint16_t validate_actions(struct datapath *, const struct sw_flow_key *, + const struct ofp_action_header *, size_t); +void execute_actions(struct datapath *, struct sk_buff *, + struct sw_flow_key *, const struct ofp_action_header *, + size_t action_len, int ignore_no_fwd); +int make_writable(struct sk_buff **pskb); + +#endif /* dp_act.h */ diff --git a/openflow/datapath/dp_dev.c b/openflow/datapath/dp_dev.c new file mode 100644 index 00000000..5db5b19b --- /dev/null +++ b/openflow/datapath/dp_dev.c @@ -0,0 +1,252 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "datapath.h" +#include "dp_dev.h" +#include "forward.h" + + +static struct dp_dev *dp_dev_priv(struct net_device *netdev) +{ + return netdev_priv(netdev); +} + +struct datapath *dp_dev_get_dp(struct net_device *netdev) +{ + return dp_dev_priv(netdev)->dp; +} +EXPORT_SYMBOL(dp_dev_get_dp); + +static struct net_device_stats *dp_dev_get_stats(struct net_device *netdev) +{ + struct dp_dev *dp_dev = dp_dev_priv(netdev); + return &dp_dev->stats; +} + +int dp_dev_recv(struct net_device *netdev, struct sk_buff *skb) +{ + int len = skb->len; + struct dp_dev *dp_dev = dp_dev_priv(netdev); + skb->dev = netdev; + skb->pkt_type = PACKET_HOST; + skb->protocol = eth_type_trans(skb, netdev); + if (in_interrupt()) + netif_rx(skb); + else + netif_rx_ni(skb); + netdev->last_rx = jiffies; + dp_dev->stats.rx_packets++; + dp_dev->stats.rx_bytes += len; + return len; +} + +static int dp_dev_mac_addr(struct net_device *dev, void *p) +{ + struct sockaddr *addr = p; + + if (netif_running(dev)) + return -EBUSY; + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + return 0; +} + +static int dp_dev_xmit(struct sk_buff *skb, struct net_device *netdev) +{ + struct dp_dev *dp_dev = dp_dev_priv(netdev); + struct datapath *dp = dp_dev->dp; + + /* By orphaning 'skb' we will screw up socket accounting slightly, but + * the effect is limited to the device queue length. If we don't + * do this, then the sk_buff will be destructed eventually, but it is + * harder to predict when. */ + skb_orphan(skb); + + /* We are going to modify 'skb', by sticking it on &dp_dev->xmit_queue, + * so we need to have our own clone. (At any rate, fwd_port_input() + * will need its own clone, so there's no benefit to queuing any other + * way.) */ + skb = skb_share_check(skb, GFP_ATOMIC); + if (!skb) + return 0; + + dp_dev->stats.tx_packets++; + dp_dev->stats.tx_bytes += skb->len; + + if (skb_queue_len(&dp_dev->xmit_queue) >= dp->netdev->tx_queue_len) { + /* Queue overflow. Stop transmitter. */ + netif_stop_queue(dp->netdev); + + /* We won't see all dropped packets individually, so overrun + * error is appropriate. */ + dp_dev->stats.tx_fifo_errors++; + } + skb_queue_tail(&dp_dev->xmit_queue, skb); + dp->netdev->trans_start = jiffies; + + schedule_work(&dp_dev->xmit_work); + + return 0; +} + +static void dp_dev_do_xmit(struct work_struct *work) +{ + struct dp_dev *dp_dev = container_of(work, struct dp_dev, xmit_work); + struct datapath *dp = dp_dev->dp; + struct sk_buff *skb; + + while ((skb = skb_dequeue(&dp_dev->xmit_queue)) != NULL) { + skb_reset_mac_header(skb); + rcu_read_lock(); + fwd_port_input(dp->chain, skb, dp->local_port); + rcu_read_unlock(); + } + netif_wake_queue(dp->netdev); +} + +static int dp_dev_open(struct net_device *netdev) +{ + netif_start_queue(netdev); + return 0; +} + +static int dp_dev_stop(struct net_device *netdev) +{ + netif_stop_queue(netdev); + return 0; +} + +static void dp_getinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + strcpy(info->driver, "openflow"); + sprintf(info->version, "0x%d", OFP_VERSION); + strcpy(info->fw_version, "N/A"); + strcpy(info->bus_info, "N/A"); +} + +static struct ethtool_ops dp_ethtool_ops = { + .get_drvinfo = dp_getinfo, + .get_link = ethtool_op_get_link, + .get_sg = ethtool_op_get_sg, + .get_tx_csum = ethtool_op_get_tx_csum, + .get_tso = ethtool_op_get_tso, +}; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) +static const struct net_device_ops dp_netdev_ops = { + .ndo_init = NULL, + .ndo_uninit = NULL, + .ndo_open = dp_dev_open, + .ndo_stop = dp_dev_stop, + .ndo_start_xmit = dp_dev_xmit, + .ndo_select_queue = NULL, + .ndo_change_rx_flags = NULL, + .ndo_set_rx_mode = NULL, + .ndo_set_multicast_list = NULL, + .ndo_set_mac_address = dp_dev_mac_addr, + .ndo_validate_addr = NULL, + .ndo_do_ioctl = NULL, + .ndo_set_config = NULL, + .ndo_change_mtu = NULL, + .ndo_tx_timeout = NULL, + .ndo_get_stats = dp_dev_get_stats, + .ndo_vlan_rx_register = NULL, + .ndo_vlan_rx_add_vid = NULL, + .ndo_vlan_rx_kill_vid = NULL, + .ndo_poll_controller = NULL +}; +#endif + +static void +do_setup(struct net_device *netdev) +{ + ether_setup(netdev); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) + netdev->netdev_ops = &dp_netdev_ops; +#else + netdev->do_ioctl = dp_ioctl_hook; + netdev->get_stats = dp_dev_get_stats; + netdev->hard_start_xmit = dp_dev_xmit; + netdev->open = dp_dev_open; + netdev->stop = dp_dev_stop; + netdev->set_mac_address = dp_dev_mac_addr; +#endif + SET_ETHTOOL_OPS(netdev, &dp_ethtool_ops); + netdev->tx_queue_len = 100; + + netdev->flags = IFF_BROADCAST | IFF_MULTICAST; + + random_ether_addr(netdev->dev_addr); + + /* Set the OUI to the Nicira one. */ + netdev->dev_addr[0] = 0x00; + netdev->dev_addr[1] = 0x23; + netdev->dev_addr[2] = 0x20; + + /* Set the top bits to indicate random Nicira address. */ + netdev->dev_addr[3] |= 0xc0; +} + +/* Create a datapath device associated with 'dp'. If 'dp_name' is null, + * the device name will be of the form 'of'. + * + * Called with RTNL lock and dp_mutex.*/ +int dp_dev_setup(struct datapath *dp, const char *dp_name) +{ + struct dp_dev *dp_dev; + struct net_device *netdev; + char dev_name[IFNAMSIZ]; + int err; + + if (dp_name) { + if (strlen(dp_name) >= IFNAMSIZ) + return -EINVAL; + strncpy(dev_name, dp_name, sizeof(dev_name)); + } else + snprintf(dev_name, sizeof dev_name, "of%d", dp->dp_idx); + + netdev = alloc_netdev(sizeof(struct dp_dev), dev_name, do_setup); + if (!netdev) + return -ENOMEM; + + err = register_netdevice(netdev); + if (err) { + free_netdev(netdev); + return err; + } + + dp_dev = dp_dev_priv(netdev); + dp_dev->dp = dp; + skb_queue_head_init(&dp_dev->xmit_queue); + INIT_WORK(&dp_dev->xmit_work, dp_dev_do_xmit); + dp->netdev = netdev; + return 0; +} + +/* Called with RTNL lock and dp_mutex.*/ +void dp_dev_destroy(struct datapath *dp) +{ + struct dp_dev *dp_dev = dp_dev_priv(dp->netdev); + + netif_tx_disable(dp->netdev); + synchronize_net(); + skb_queue_purge(&dp_dev->xmit_queue); + unregister_netdevice(dp->netdev); +} + +int is_dp_dev(struct net_device *netdev) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) + return netdev->netdev_ops->ndo_open == dp_dev_open; + +#else + return netdev->open == dp_dev_open; +#endif +} diff --git a/openflow/datapath/dp_dev.h b/openflow/datapath/dp_dev.h new file mode 100644 index 00000000..26f72485 --- /dev/null +++ b/openflow/datapath/dp_dev.h @@ -0,0 +1,17 @@ +#ifndef DP_DEV_H +#define DP_DEV_H 1 + +struct dp_dev { + struct net_device_stats stats; + struct datapath *dp; + struct sk_buff_head xmit_queue; + struct work_struct xmit_work; +}; + +int dp_dev_setup(struct datapath *, const char *); +void dp_dev_destroy(struct datapath *); +int dp_dev_recv(struct net_device *, struct sk_buff *); +int is_dp_dev(struct net_device *); +struct datapath *dp_dev_get_dp(struct net_device *); + +#endif /* dp_dev.h */ diff --git a/openflow/datapath/dp_notify.c b/openflow/datapath/dp_notify.c new file mode 100644 index 00000000..54c88402 --- /dev/null +++ b/openflow/datapath/dp_notify.c @@ -0,0 +1,43 @@ +/* + * Distributed under the terms of the GNU GPL version 2. + * Copyright (c) 2007, 2008, 2009 The Board of Trustees of The Leland + * Stanford Junior University + */ + +/* Handle changes to managed devices */ + +#include + +#include "datapath.h" + + +static int dp_device_event(struct notifier_block *unused, unsigned long event, + void *ptr) +{ + struct net_device *dev = ptr; + struct net_bridge_port *p = dev->br_port; + unsigned long int flags; + + + /* Check if monitored port */ + if (!p) + return NOTIFY_DONE; + + spin_lock_irqsave(&p->lock, flags); + switch (event) { + case NETDEV_UNREGISTER: + spin_unlock_irqrestore(&p->lock, flags); + mutex_lock(&dp_mutex); + dp_del_switch_port(p); + mutex_unlock(&dp_mutex); + return NOTIFY_DONE; + break; + } + spin_unlock_irqrestore(&p->lock, flags); + + return NOTIFY_DONE; +} + +struct notifier_block dp_device_notifier = { + .notifier_call = dp_device_event +}; diff --git a/openflow/datapath/flow.c b/openflow/datapath/flow.c new file mode 100644 index 00000000..c927ce65 --- /dev/null +++ b/openflow/datapath/flow.c @@ -0,0 +1,504 @@ + +/* + * Distributed under the terms of the GNU GPL version 2. + * Copyright (c) 2007, 2008 The Board of Trustees of The Leland + * Stanford Junior University + */ + +#include "flow.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "openflow/openflow.h" +#include "openflow/nicira-ext.h" +#include "compat.h" + +struct kmem_cache *flow_cache; + +/* Internal function used to compare fields in flow. */ +static inline +int flow_fields_match(const struct sw_flow_key *a, const struct sw_flow_key *b, + uint32_t w, uint32_t src_mask, uint32_t dst_mask) +{ + return ((w & OFPFW_IN_PORT || a->in_port == b->in_port) + && (w & OFPFW_DL_VLAN || a->dl_vlan == b->dl_vlan) + && (w & OFPFW_DL_VLAN_PCP || a->dl_vlan_pcp == b->dl_vlan_pcp) + && (w & OFPFW_DL_SRC || !memcmp(a->dl_src, b->dl_src, ETH_ALEN)) + && (w & OFPFW_DL_DST || !memcmp(a->dl_dst, b->dl_dst, ETH_ALEN)) + && (w & OFPFW_DL_TYPE || a->dl_type == b->dl_type) + && (w & OFPFW_NW_TOS || a->nw_tos == b->nw_tos) + && (w & OFPFW_NW_PROTO || a->nw_proto == b->nw_proto) + && !((a->nw_src ^ b->nw_src) & src_mask) + && !((a->nw_dst ^ b->nw_dst) & dst_mask) + && (w & OFPFW_TP_SRC || a->tp_src == b->tp_src) + && (w & OFPFW_TP_DST || a->tp_dst == b->tp_dst)); +} + +/* Returns nonzero if 'a' and 'b' match, that is, if their fields are equal + * modulo wildcards in 'b', zero otherwise. */ +int flow_matches_1wild(const struct sw_flow_key *a, + const struct sw_flow_key *b) +{ + return flow_fields_match(a, b, b->wildcards, + b->nw_src_mask, b->nw_dst_mask); +} +EXPORT_SYMBOL(flow_matches_1wild); + +/* Returns nonzero if 'a' and 'b' match, that is, if their fields are equal + * modulo wildcards in 'a' or 'b', zero otherwise. */ +int flow_matches_2wild(const struct sw_flow_key *a, + const struct sw_flow_key *b) +{ + return flow_fields_match(a, b, + a->wildcards | b->wildcards, + a->nw_src_mask & b->nw_src_mask, + a->nw_dst_mask & b->nw_dst_mask); +} +EXPORT_SYMBOL(flow_matches_2wild); + +/* Returns nonzero if 't' (the table entry's key) and 'd' (the key + * describing the match) match, that is, if their fields are + * equal modulo wildcards, zero otherwise. If 'strict' is nonzero, the + * wildcards must match in both 't_key' and 'd_key'. Note that the + * table's wildcards are ignored unless 'strict' is set. */ +int flow_matches_desc(const struct sw_flow_key *t, const struct sw_flow_key *d, + int strict) +{ + if (strict && d->wildcards != t->wildcards) + return 0; + return flow_matches_1wild(t, d); +} +EXPORT_SYMBOL(flow_matches_desc); + +/* Returns nonzero if 't' (the table entry's key) and 'd' (the key + * describing the match) match, that is, if their fields are + * equal modulo 't' or 'd' wildcards, zero otherwise. If 'strict' is nonzero, the + * wildcards must match in both 't_key' and 'd_key'. Note that the + * table's wildcards are ignored unless 'strict' is set. */ +int +flow_matches_2desc(const struct sw_flow_key *t, const struct sw_flow_key *d, + int strict) +{ + if (strict && d->wildcards != t->wildcards) { + return 0; + } + return flow_matches_2wild(t, d); +} +EXPORT_SYMBOL(flow_matches_2desc); + +static uint32_t make_nw_mask(int n_wild_bits) +{ + n_wild_bits &= (1u << OFPFW_NW_SRC_BITS) - 1; + return n_wild_bits < 32 ? htonl(~((1u << n_wild_bits) - 1)) : 0; +} + +void flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from) +{ + to->wildcards = ntohl(from->wildcards) & OFPFW_ALL; + to->dl_vlan_pcp = from->dl_vlan_pcp; + to->in_port = from->in_port; + to->dl_vlan = from->dl_vlan; + memcpy(to->dl_src, from->dl_src, ETH_ALEN); + memcpy(to->dl_dst, from->dl_dst, ETH_ALEN); + to->dl_type = from->dl_type; + + to->nw_tos = to->nw_proto = to->nw_src = to->nw_dst = 0; + to->tp_src = to->tp_dst = 0; + memset(to->pad, 0, sizeof(to->pad)); + +#define OFPFW_TP (OFPFW_TP_SRC | OFPFW_TP_DST) +#define OFPFW_NW (OFPFW_NW_TOS | OFPFW_NW_PROTO | OFPFW_NW_SRC_MASK | OFPFW_NW_DST_MASK) + if (to->wildcards & OFPFW_DL_TYPE) { + /* Can't sensibly match on network or transport headers if the + * data link type is unknown. */ + to->wildcards |= OFPFW_NW | OFPFW_TP; + } else if (from->dl_type == htons(ETH_P_IP)) { + to->nw_tos = from->nw_tos & 0xfc; + to->nw_proto = from->nw_proto; + to->nw_src = from->nw_src; + to->nw_dst = from->nw_dst; + + if (to->wildcards & OFPFW_NW_PROTO) { + /* Can't sensibly match on transport headers if the + * network protocol is unknown. */ + to->wildcards |= OFPFW_TP; + } else if (from->nw_proto == IPPROTO_TCP + || from->nw_proto == IPPROTO_UDP + || from->nw_proto == IPPROTO_ICMP) { + to->tp_src = from->tp_src; + to->tp_dst = from->tp_dst; + } else { + /* Transport layer fields are undefined. Mark them as + * exact-match to allow such flows to reside in + * table-hash, instead of falling into table-linear. */ + to->wildcards &= ~OFPFW_TP; + } + } else { + /* Network and transport layer fields are undefined. Mark them + * as exact-match to allow such flows to reside in table-hash, + * instead of falling into table-linear. */ + to->wildcards &= ~(OFPFW_NW | OFPFW_TP); + } + + /* We set these late because code above adjusts to->wildcards. */ + to->nw_src_mask = make_nw_mask(to->wildcards >> OFPFW_NW_SRC_SHIFT); + to->nw_dst_mask = make_nw_mask(to->wildcards >> OFPFW_NW_DST_SHIFT); +} + +void flow_fill_match(struct ofp_match* to, const struct sw_flow_key* from) +{ + to->wildcards = htonl(from->wildcards); + to->in_port = from->in_port; + to->dl_vlan = from->dl_vlan; + memcpy(to->dl_src, from->dl_src, ETH_ALEN); + memcpy(to->dl_dst, from->dl_dst, ETH_ALEN); + to->dl_type = from->dl_type; + to->nw_tos = from->nw_tos; + to->nw_proto = from->nw_proto; + to->nw_src = from->nw_src; + to->nw_dst = from->nw_dst; + to->tp_src = from->tp_src; + to->tp_dst = from->tp_dst; + to->dl_vlan_pcp = from->dl_vlan_pcp; +} + +int flow_timeout(struct sw_flow *flow) +{ + if (flow->idle_timeout != OFP_FLOW_PERMANENT + && time_after64(get_jiffies_64(), flow->used + flow->idle_timeout * HZ)) + return OFPRR_IDLE_TIMEOUT; + else if (flow->hard_timeout != OFP_FLOW_PERMANENT + && time_after64(get_jiffies_64(), + flow->created + flow->hard_timeout * HZ)) + return OFPRR_HARD_TIMEOUT; + else + return -1; +} +EXPORT_SYMBOL(flow_timeout); + +/* Returns nonzero if 'flow' contains an output action to 'out_port' or + * has the value OFPP_NONE. 'out_port' is in network-byte order. */ +int flow_has_out_port(struct sw_flow *flow, uint16_t out_port) +{ + struct sw_flow_actions *sf_acts; + size_t actions_len; + uint8_t *p; + + if (out_port == htons(OFPP_NONE)) + return 1; + + sf_acts = rcu_dereference(flow->sf_acts); + + actions_len = sf_acts->actions_len; + p = (uint8_t *)sf_acts->actions; + + while (actions_len > 0) { + struct ofp_action_header *ah = (struct ofp_action_header *)p; + size_t len = ntohs(ah->len); + + if (ah->type == htons(OFPAT_OUTPUT)) { + struct ofp_action_output *oa = (struct ofp_action_output *)p; + if (oa->port == out_port) + return 1; + } + + p += len; + actions_len -= len; + } + + return 0; +} +EXPORT_SYMBOL(flow_has_out_port); + +/* Allocates and returns a new flow with room for 'actions_len' actions, + * using allocation flags 'flags'. Returns the new flow or a null pointer + * on failure. */ +struct sw_flow *flow_alloc(size_t actions_len, gfp_t flags) +{ + struct sw_flow_actions *sfa; + size_t size = sizeof *sfa + actions_len; + struct sw_flow *flow = kmem_cache_alloc(flow_cache, flags); + if (unlikely(!flow)) + return NULL; + + sfa = kmalloc(size, flags); + if (unlikely(!sfa)) { + kmem_cache_free(flow_cache, flow); + return NULL; + } + sfa->actions_len = actions_len; + flow->sf_acts = sfa; + + return flow; +} + +/* Frees 'flow' immediately. */ +void flow_free(struct sw_flow *flow) +{ + if (unlikely(!flow)) + return; + kfree(flow->sf_acts); + kmem_cache_free(flow_cache, flow); +} +EXPORT_SYMBOL(flow_free); + +/* RCU callback used by flow_deferred_free. */ +static void rcu_free_flow_callback(struct rcu_head *rcu) +{ + struct sw_flow *flow = container_of(rcu, struct sw_flow, rcu); + flow_free(flow); +} + +/* Schedules 'flow' to be freed after the next RCU grace period. + * The caller must hold rcu_read_lock for this to be sensible. */ +void flow_deferred_free(struct sw_flow *flow) +{ + call_rcu(&flow->rcu, rcu_free_flow_callback); +} +EXPORT_SYMBOL(flow_deferred_free); + +/* RCU callback used by flow_deferred_free_acts. */ +static void rcu_free_acts_callback(struct rcu_head *rcu) +{ + struct sw_flow_actions *sf_acts = container_of(rcu, + struct sw_flow_actions, rcu); + kfree(sf_acts); +} + +/* Schedules 'sf_acts' to be freed after the next RCU grace period. + * The caller must hold rcu_read_lock for this to be sensible. */ +void flow_deferred_free_acts(struct sw_flow_actions *sf_acts) +{ + call_rcu(&sf_acts->rcu, rcu_free_acts_callback); +} +EXPORT_SYMBOL(flow_deferred_free_acts); + +/* Setup the action on the flow, just after it was created with flow_alloc(). + * Jean II */ +void flow_setup_actions(struct sw_flow * flow, + const struct ofp_action_header * actions, + int actions_len) +{ + /* Basic init of the flow stucture */ + flow->used = flow->created = get_jiffies_64(); + flow->byte_count = 0; + flow->packet_count = 0; + spin_lock_init(&flow->lock); + + /* Make sure we don't blow the allocation done earlier */ + if(actions_len > flow->sf_acts->actions_len) { + printk(KERN_ERR "flow_setup_actions: actions_len is too big (%d > %d)", + actions_len, flow->sf_acts->actions_len); + return; + } + + /* Setup the actions - No need for RCU at this point ;-) */ + memcpy(flow->sf_acts->actions, actions, actions_len); +} + +/* Copies 'actions' into a newly allocated structure for use by 'flow' + * and safely frees the structure that defined the previous actions. */ +void flow_replace_acts(struct sw_flow *flow, + const struct ofp_action_header *actions, size_t actions_len) +{ + struct sw_flow_actions *sfa; + struct sw_flow_actions *orig_sfa = flow->sf_acts; + size_t size = sizeof *sfa + actions_len; + + sfa = kmalloc(size, GFP_ATOMIC); + if (unlikely(!sfa)) + return; + + sfa->actions_len = actions_len; + memcpy(sfa->actions, actions, actions_len); + + rcu_assign_pointer(flow->sf_acts, sfa); + flow_deferred_free_acts(orig_sfa); + + return; +} +EXPORT_SYMBOL(flow_replace_acts); + +/* Prints a representation of 'key' to the kernel log. */ +void print_flow(const struct sw_flow_key *key) +{ + printk("wild %08x port %04x vlan-vid %04x vlan-pcp %02x " + "src-mac %02x:%02x:%02x:%02x:%02x:%02x " + "dst-mac %02x:%02x:%02x:%02x:%02x:%02x " + "frm-type %04x ip-tos %02x ip-proto %02x " + "src-ip %u.%u.%u.%u dst-ip %u.%u.%u.%u tp-src %d tp-dst %d\n", + key->wildcards, ntohs(key->in_port), ntohs(key->dl_vlan), + key->dl_vlan_pcp, + key->dl_src[0], key->dl_src[1], key->dl_src[2], + key->dl_src[3], key->dl_src[4], key->dl_src[5], + key->dl_dst[0], key->dl_dst[1], key->dl_dst[2], + key->dl_dst[3], key->dl_dst[4], key->dl_dst[5], + ntohs(key->dl_type), + key->nw_tos, key->nw_proto, + ((unsigned char *)&key->nw_src)[0], + ((unsigned char *)&key->nw_src)[1], + ((unsigned char *)&key->nw_src)[2], + ((unsigned char *)&key->nw_src)[3], + ((unsigned char *)&key->nw_dst)[0], + ((unsigned char *)&key->nw_dst)[1], + ((unsigned char *)&key->nw_dst)[2], + ((unsigned char *)&key->nw_dst)[3], + ntohs(key->tp_src), ntohs(key->tp_dst)); +} +EXPORT_SYMBOL(print_flow); + +#define SNAP_OUI_LEN 3 + +struct eth_snap_hdr +{ + struct ethhdr eth; + uint8_t dsap; /* Always 0xAA */ + uint8_t ssap; /* Always 0xAA */ + uint8_t ctrl; + uint8_t oui[SNAP_OUI_LEN]; + uint16_t ethertype; +} __attribute__ ((packed)); + +static int is_snap(const struct eth_snap_hdr *esh) +{ + return (esh->dsap == LLC_SAP_SNAP + && esh->ssap == LLC_SAP_SNAP + && !memcmp(esh->oui, "\0\0\0", 3)); +} + +/* Parses the Ethernet frame in 'skb', which was received on 'in_port', + * and initializes 'key' to match. Returns 1 if 'skb' contains an IP + * fragment, 0 otherwise. */ +int flow_extract(struct sk_buff *skb, uint16_t in_port, + struct sw_flow_key *key) +{ + struct ethhdr *eth; + struct eth_snap_hdr *esh; + int retval = 0; + int nh_ofs; + + memset(key, 0, sizeof *key); + key->dl_vlan = htons(OFP_VLAN_NONE); + key->in_port = htons(in_port); + + if (skb->len < sizeof *eth) + return 0; + if (!pskb_may_pull(skb, skb->len >= 64 ? 64 : skb->len)) { + return 0; + } + + skb_reset_mac_header(skb); + eth = eth_hdr(skb); + esh = (struct eth_snap_hdr *) eth; + nh_ofs = sizeof *eth; + if (likely(ntohs(eth->h_proto) >= OFP_DL_TYPE_ETH2_CUTOFF)) + key->dl_type = eth->h_proto; + else if (skb->len >= sizeof *esh && is_snap(esh)) { + key->dl_type = esh->ethertype; + nh_ofs = sizeof *esh; + } else { + key->dl_type = htons(OFP_DL_TYPE_NOT_ETH_TYPE); + if (skb->len >= nh_ofs + sizeof(struct llc_pdu_un)) { + nh_ofs += sizeof(struct llc_pdu_un); + } + } + + /* Check for a VLAN tag */ + if (key->dl_type == htons(ETH_P_8021Q) && + skb->len >= nh_ofs + sizeof(struct vlan_hdr)) { + struct vlan_hdr *vh = (struct vlan_hdr*)(skb->data + nh_ofs); + key->dl_type = vh->h_vlan_encapsulated_proto; + key->dl_vlan = vh->h_vlan_TCI & htons(VLAN_VID_MASK); + key->dl_vlan_pcp = (uint8_t)((ntohs(vh->h_vlan_TCI) >> VLAN_PCP_SHIFT) + & VLAN_PCP_BITMASK); + nh_ofs += sizeof(struct vlan_hdr); + } + memcpy(key->dl_src, eth->h_source, ETH_ALEN); + memcpy(key->dl_dst, eth->h_dest, ETH_ALEN); + skb_set_network_header(skb, nh_ofs); + + /* Network layer. */ + if (key->dl_type == htons(ETH_P_IP) && iphdr_ok(skb)) { + struct iphdr *nh = ip_hdr(skb); + int th_ofs = nh_ofs + nh->ihl * 4; + key->nw_tos = nh->tos & 0xfc; + key->nw_proto = nh->protocol; + key->nw_src = nh->saddr; + key->nw_dst = nh->daddr; + skb_set_transport_header(skb, th_ofs); + + /* Transport layer. */ + if (!(nh->frag_off & htons(IP_MF | IP_OFFSET))) { + if (key->nw_proto == IPPROTO_TCP) { + if (tcphdr_ok(skb)) { + struct tcphdr *tcp = tcp_hdr(skb); + key->tp_src = tcp->source; + key->tp_dst = tcp->dest; + } else { + /* Avoid tricking other code into + * thinking that this packet has an L4 + * header. */ + key->nw_proto = 0; + } + } else if (key->nw_proto == IPPROTO_UDP) { + if (udphdr_ok(skb)) { + struct udphdr *udp = udp_hdr(skb); + key->tp_src = udp->source; + key->tp_dst = udp->dest; + } else { + /* Avoid tricking other code into + * thinking that this packet has an L4 + * header. */ + key->nw_proto = 0; + } + } else if (key->nw_proto == IPPROTO_ICMP) { + if (icmphdr_ok(skb)) { + struct icmphdr *icmp = icmp_hdr(skb); + /* The ICMP type and code fields use the 16-bit + * transport port fields, so we need to store them + * in 16-bit network byte order. */ + key->icmp_type = htons(icmp->type); + key->icmp_code = htons(icmp->code); + } else { + /* Avoid tricking other code into + * thinking that this packet has an L4 + * header. */ + key->nw_proto = 0; + } + } + } else { + retval = 1; + } + } else { + skb_reset_transport_header(skb); + } + return retval; +} + +/* Initializes the flow module. + * Returns zero if successful or a negative error code. */ +int flow_init(void) +{ + flow_cache = kmem_cache_create("sw_flow", sizeof(struct sw_flow), 0, + 0, NULL); + if (flow_cache == NULL) + return -ENOMEM; + + return 0; +} + +/* Uninitializes the flow module. */ +void flow_exit(void) +{ + kmem_cache_destroy(flow_cache); +} + diff --git a/openflow/datapath/flow.h b/openflow/datapath/flow.h new file mode 100644 index 00000000..5f8597a3 --- /dev/null +++ b/openflow/datapath/flow.h @@ -0,0 +1,199 @@ +#ifndef FLOW_H +#define FLOW_H 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "openflow/openflow.h" + +#define VLAN_PCP_SHIFT 13 +#define VLAN_PCP_BITMASK 0x0007 /* the least 3-bit is valid */ + +struct sk_buff; +struct ofp_flow_mod; + +/* Identification data for a flow. + * Network byte order except for the "wildcards" field. + * Ordered to make bytewise comparisons (e.g. with memcmp()) fail quickly and + * to keep the amount of padding to a minimum. + * If you change the ordering of fields here, change flow_keys_equal() to + * compare the proper fields. + */ +struct sw_flow_key { + uint32_t nw_src; /* IP source address. */ + uint32_t nw_dst; /* IP destination address. */ + uint16_t in_port; /* Input switch port */ + uint16_t dl_vlan; /* Input VLAN id. */ + uint16_t dl_type; /* Ethernet frame type. */ + uint16_t tp_src; /* TCP/UDP source port. */ + uint16_t tp_dst; /* TCP/UDP destination port. */ + uint8_t dl_src[ETH_ALEN]; /* Ethernet source address. */ + uint8_t dl_dst[ETH_ALEN]; /* Ethernet destination address. */ + uint8_t dl_vlan_pcp; /* Input VLAN priority. */ + uint8_t nw_tos; /* IPv4 DSCP */ + uint8_t nw_proto; /* IP protocol. */ + uint8_t pad[3]; + uint32_t wildcards; /* Wildcard fields (host byte order). */ + uint32_t nw_src_mask; /* 1-bit in each significant nw_src bit. */ + uint32_t nw_dst_mask; /* 1-bit in each significant nw_dst bit. */ +}; + +/* The match fields for ICMP type and code use the transport source and + * destination port fields, respectively. */ +#define icmp_type tp_src +#define icmp_code tp_dst + +/* Compare two sw_flow_keys and return true if they are the same flow, false + * otherwise. Wildcards and netmasks are not considered. */ +static inline int flow_keys_equal(const struct sw_flow_key *a, + const struct sw_flow_key *b) +{ + return !memcmp(a, b, offsetof(struct sw_flow_key, wildcards)); +} + +/* We need to manually make sure that the structure is 32-bit aligned, + * since we don't want garbage values in compiler-generated pads from + * messing up hash matches. + */ +static inline void check_key_align(void) +{ + BUILD_BUG_ON(sizeof(struct sw_flow_key) != 48); +} + +/* We keep actions as a separate structure because we need to be able to + * swap them out atomically when the modify command comes from a Flow + * Modify message. */ +struct sw_flow_actions { + size_t actions_len; + struct rcu_head rcu; + + struct ofp_action_header actions[0]; +}; + +/* Locking: + * + * - Readers must take rcu_read_lock and hold it the entire time that the flow + * must continue to exist. + * + * - Writers must hold dp_mutex. + */ +struct sw_flow { + struct sw_flow_key key; + + uint16_t priority; /* Only used on entries with wildcards. */ + uint16_t idle_timeout; /* Idle time before discarding (seconds). */ + uint16_t hard_timeout; /* Hard expiration time (seconds) */ + uint64_t used; /* Last used time (in jiffies). */ + uint8_t send_flow_rem; /* Send a flow removed to the controller */ + uint8_t emerg_flow; /* Emergency flow indicator */ + + struct sw_flow_actions *sf_acts; + + /* For use by table implementation. */ + struct list_head node; + struct list_head iter_node; + unsigned long serial; + void *private; + + spinlock_t lock; /* Lock this entry...mostly for stat updates */ + uint64_t created; /* When the flow was created (in jiffies_64). */ + uint64_t packet_count; /* Number of packets associated with this entry */ + uint64_t byte_count; /* Number of bytes associated with this entry */ + + struct rcu_head rcu; +}; + +int flow_matches_1wild(const struct sw_flow_key *, const struct sw_flow_key *); +int flow_matches_2wild(const struct sw_flow_key *, const struct sw_flow_key *); +int flow_matches_desc(const struct sw_flow_key *, const struct sw_flow_key *, + int); +int flow_matches_2desc(const struct sw_flow_key *, const struct sw_flow_key *, + int); +int flow_has_out_port(struct sw_flow *, uint16_t); +struct sw_flow *flow_alloc(size_t actions_len, gfp_t flags); +void flow_free(struct sw_flow *); +void flow_deferred_free(struct sw_flow *); +void flow_deferred_free_acts(struct sw_flow_actions *); +void flow_setup_actions(struct sw_flow *, const struct ofp_action_header *, + int); +void flow_replace_acts(struct sw_flow *, const struct ofp_action_header *, + size_t); +int flow_extract(struct sk_buff *, uint16_t in_port, struct sw_flow_key *); +void flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from); +void flow_fill_match(struct ofp_match* to, const struct sw_flow_key* from); +int flow_timeout(struct sw_flow *); + +void print_flow(const struct sw_flow_key *); + +static inline int iphdr_ok(struct sk_buff *skb) +{ + int nh_ofs = skb_network_offset(skb); + if (skb->len >= nh_ofs + sizeof(struct iphdr)) { + int ip_len = ip_hdrlen(skb); + return (ip_len >= sizeof(struct iphdr) + && pskb_may_pull(skb, nh_ofs + ip_len)); + } + return 0; +} + +static inline int tcphdr_ok(struct sk_buff *skb) +{ + int th_ofs = skb_transport_offset(skb); + if (pskb_may_pull(skb, th_ofs + sizeof(struct tcphdr))) { + int tcp_len = tcp_hdrlen(skb); + return (tcp_len >= sizeof(struct tcphdr) + && skb->len >= th_ofs + tcp_len); + } + return 0; +} + +static inline int udphdr_ok(struct sk_buff *skb) +{ + int th_ofs = skb_transport_offset(skb); + return pskb_may_pull(skb, th_ofs + sizeof(struct udphdr)); +} + +static inline int icmphdr_ok(struct sk_buff *skb) +{ + int th_ofs = skb_transport_offset(skb); + return pskb_may_pull(skb, th_ofs + sizeof(struct icmphdr)); +} + +#define TCP_FLAGS_OFFSET 13 +#define TCP_FLAG_MASK 0x3f + +static inline struct ofp_tcphdr *ofp_tcp_hdr(const struct sk_buff *skb) +{ + return (struct ofp_tcphdr *)skb_transport_header(skb); +} + +static inline void flow_used(struct sw_flow *flow, struct sk_buff *skb) +{ + unsigned long flags; + + flow->used = get_jiffies_64(); + + spin_lock_irqsave(&flow->lock, flags); + flow->packet_count++; + flow->byte_count += skb->len; + spin_unlock_irqrestore(&flow->lock, flags); +} + +extern struct kmem_cache *flow_cache; + +int flow_init(void); +void flow_exit(void); + +#endif /* flow.h */ diff --git a/openflow/datapath/forward.c b/openflow/datapath/forward.c new file mode 100644 index 00000000..40d2a332 --- /dev/null +++ b/openflow/datapath/forward.c @@ -0,0 +1,642 @@ +/* + * Distributed under the terms of the GNU GPL version 2. + * Copyright (c) 2007, 2008, 2009 The Board of Trustees of The Leland + * Stanford Junior University + */ + +#include +#include +#include +#include +#include +#include +#include "forward.h" +#include "datapath.h" +#include "openflow/nicira-ext.h" +#include "openflow/private-ext.h" +#include "dp_act.h" +#include "private-msg.h" +#include "openflow-ext.h" +#include "chain.h" +#include "flow.h" + +/* FIXME: do we need to use GFP_ATOMIC everywhere here? */ + + +static struct sk_buff *retrieve_skb(uint32_t id); +static void discard_skb(uint32_t id); + +/* 'skb' was received on port 'p', which may be a physical switch port, the + * local port, or a null pointer. Process it according to 'chain'. Returns 0 + * if successful, in which case 'skb' is destroyed, or -ESRCH if there is no + * matching flow, in which case 'skb' still belongs to the caller. */ +int run_flow_through_tables(struct sw_chain *chain, struct sk_buff *skb, + struct net_bridge_port *p) +{ + /* Ethernet address used as the destination for STP frames. */ + static const uint8_t stp_eth_addr[ETH_ALEN] + = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x01 }; + struct sw_flow_key key; + struct sw_flow *flow; + + if (flow_extract(skb, p ? p->port_no : OFPP_NONE, &key) + && (chain->dp->flags & OFPC_FRAG_MASK) == OFPC_FRAG_DROP) { + /* Drop fragment. */ + kfree_skb(skb); + return 0; + } + if (p && p->config & (OFPPC_NO_RECV | OFPPC_NO_RECV_STP) && + p->config & (compare_ether_addr(key.dl_dst, stp_eth_addr) + ? OFPPC_NO_RECV : OFPPC_NO_RECV_STP)) { + kfree_skb(skb); + return 0; + } + + flow = chain_lookup(chain, &key, 0); + if (likely(flow != NULL)) { + struct sw_flow_actions *sf_acts = rcu_dereference(flow->sf_acts); + flow_used(flow, skb); + execute_actions(chain->dp, skb, &key, + sf_acts->actions, sf_acts->actions_len, 0); + return 0; + } else { + return -ESRCH; + } +} + +/* 'skb' was received on port 'p', which may be a physical switch port, the + * local port, or a null pointer. Process it according to 'chain', sending it + * up to the controller if no flow matches. Takes ownership of 'skb'. */ +void fwd_port_input(struct sw_chain *chain, struct sk_buff *skb, + struct net_bridge_port *p) +{ + WARN_ON_ONCE(skb_shared(skb)); + WARN_ON_ONCE(skb->destructor); + if (run_flow_through_tables(chain, skb, p)) + dp_output_control(chain->dp, skb, chain->dp->miss_send_len, + OFPR_NO_MATCH); +} + +static int +recv_hello(struct sw_chain *chain, const struct sender *sender, + const void *msg) +{ + return dp_send_hello(chain->dp, sender, msg); +} + +static int +recv_barrier_request(struct sw_chain *chain, const struct sender *sender, + const void *msg) +{ + return dp_send_barrier_reply(chain->dp, sender, msg); +} + +static int +recv_features_request(struct sw_chain *chain, const struct sender *sender, + const void *msg) +{ + return dp_send_features_reply(chain->dp, sender); +} + +static int +recv_get_config_request(struct sw_chain *chain, const struct sender *sender, + const void *msg) +{ + return dp_send_config_reply(chain->dp, sender); +} + +static int +recv_set_config(struct sw_chain *chain, const struct sender *sender, + const void *msg) +{ + const struct ofp_switch_config *osc = msg; + int flags; + + flags = ntohs(osc->flags) & OFPC_FRAG_MASK; + if ((flags & OFPC_FRAG_MASK) != OFPC_FRAG_NORMAL + && (flags & OFPC_FRAG_MASK) != OFPC_FRAG_DROP) { + flags = (flags & ~OFPC_FRAG_MASK) | OFPC_FRAG_DROP; + } + chain->dp->flags = flags; + + chain->dp->miss_send_len = ntohs(osc->miss_send_len); + + return 0; +} + +static int +recv_packet_out(struct sw_chain *chain, const struct sender *sender, + const void *msg) +{ + const struct ofp_packet_out *opo = msg; + struct sk_buff *skb; + uint16_t v_code; + struct sw_flow_key key; + size_t actions_len = ntohs(opo->actions_len); + + if (actions_len > (ntohs(opo->header.length) - sizeof *opo)) { + if (net_ratelimit()) + printk(KERN_NOTICE "%s: message too short for number " + "of actions\n", chain->dp->netdev->name); + return -EINVAL; + } + + if (ntohl(opo->buffer_id) == (uint32_t) -1) { + int data_len = ntohs(opo->header.length) - sizeof *opo - actions_len; + + /* FIXME: there is likely a way to reuse the data in msg. */ + skb = alloc_skb(data_len, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + /* FIXME? We don't reserve NET_IP_ALIGN or NET_SKB_PAD since + * we're just transmitting this raw without examining anything + * at those layers. */ + skb_put(skb, data_len); + skb_copy_to_linear_data(skb, + (uint8_t *)opo->actions + actions_len, + data_len); + skb_reset_mac_header(skb); + } else { + skb = retrieve_skb(ntohl(opo->buffer_id)); + if (!skb) + return -ESRCH; + } + + dp_set_origin(chain->dp, ntohs(opo->in_port), skb); + + flow_extract(skb, ntohs(opo->in_port), &key); + + v_code = validate_actions(chain->dp, &key, opo->actions, actions_len); + if (v_code != ACT_VALIDATION_OK) { + dp_send_error_msg(chain->dp, sender, OFPET_BAD_ACTION, v_code, + msg, ntohs(opo->header.length)); + goto error; + } + + execute_actions(chain->dp, skb, &key, opo->actions, actions_len, 1); + + return 0; + +error: + kfree_skb(skb); + return -EINVAL; +} + +static int +recv_port_mod(struct sw_chain *chain, const struct sender *sender, + const void *msg) +{ + const struct ofp_port_mod *opm = msg; + + dp_update_port_flags(chain->dp, opm); + + return 0; +} + +static int +recv_echo_request(struct sw_chain *chain, const struct sender *sender, + const void *msg) +{ + return dp_send_echo_reply(chain->dp, sender, msg); +} + +static int +recv_echo_reply(struct sw_chain *chain, const struct sender *sender, + const void *msg) +{ + return 0; +} + +static int +add_flow(struct sw_chain *chain, const struct sender *sender, + const struct ofp_flow_mod *ofm) +{ + int error = -ENOMEM; + uint16_t v_code; + struct sw_flow *flow; + size_t actions_len = ntohs(ofm->header.length) - sizeof *ofm; + int overlap; + + /* Allocate memory. */ + flow = flow_alloc(actions_len, GFP_ATOMIC); + if (flow == NULL) + goto error; + + flow_extract_match(&flow->key, &ofm->match); + + v_code = validate_actions(chain->dp, &flow->key, ofm->actions, actions_len); + if (v_code != ACT_VALIDATION_OK) { + dp_send_error_msg(chain->dp, sender, OFPET_BAD_ACTION, v_code, + ofm, ntohs(ofm->header.length)); + goto error_free_flow; + } + + flow->priority = flow->key.wildcards ? ntohs(ofm->priority) : -1; + + if (ntohs(ofm->flags) & OFPFF_CHECK_OVERLAP) { + /* check whether there is any conflict */ + overlap = chain_has_conflict(chain, &flow->key, flow->priority, + false); + if (overlap){ + dp_send_error_msg(chain->dp, sender, + OFPET_FLOW_MOD_FAILED, + OFPFMFC_OVERLAP, + ofm, ntohs(ofm->header.length)); + goto error_free_flow; + } + } + + if (ntohs(ofm->flags) & OFPFF_EMERG) { + if (ntohs(ofm->idle_timeout) != OFP_FLOW_PERMANENT + || ntohs(ofm->hard_timeout) != OFP_FLOW_PERMANENT) { + dp_send_error_msg(chain->dp, sender, + OFPET_FLOW_MOD_FAILED, + OFPFMFC_BAD_EMERG_TIMEOUT, + ofm, ntohs(ofm->header.length)); + goto error_free_flow; + } + } + + /* Fill out flow. */ + flow->idle_timeout = ntohs(ofm->idle_timeout); + flow->hard_timeout = ntohs(ofm->hard_timeout); + flow->send_flow_rem = (ntohs(ofm->flags) & OFPFF_SEND_FLOW_REM) ? 1 : 0; + flow->emerg_flow = (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0; + flow_setup_actions(flow, ofm->actions, actions_len); + + /* Act. */ + error = chain_insert(chain, flow, + (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0); + if (error == -ENOBUFS) { + dp_send_error_msg(chain->dp, sender, OFPET_FLOW_MOD_FAILED, + OFPFMFC_ALL_TABLES_FULL, ofm, ntohs(ofm->header.length)); + goto error_free_flow; + } else if (error) + goto error_free_flow; + + error = 0; + if (ntohl(ofm->buffer_id) != (uint32_t) -1) { + struct sk_buff *skb = retrieve_skb(ntohl(ofm->buffer_id)); + if (skb) { + struct sw_flow_key key; + flow_used(flow, skb); + dp_set_origin(chain->dp, ntohs(ofm->match.in_port), skb); + flow_extract(skb, ntohs(ofm->match.in_port), &key); + execute_actions(chain->dp, skb, &key, ofm->actions, actions_len, 0); + } + else + error = -ESRCH; + } + return error; + +error_free_flow: + flow_free(flow); +error: + if (ntohl(ofm->buffer_id) != (uint32_t) -1) + discard_skb(ntohl(ofm->buffer_id)); + return error; +} + +static int +mod_flow(struct sw_chain *chain, const struct sender *sender, + const struct ofp_flow_mod *ofm) +{ + int error = -ENOMEM; + uint16_t v_code; + size_t actions_len = ntohs(ofm->header.length) - sizeof *ofm; + struct sw_flow *flow; + int strict; + + /* Allocate memory. */ + flow = flow_alloc(actions_len,GFP_ATOMIC); + if (flow == NULL) + goto error; + + flow_extract_match(&flow->key, &ofm->match); + + v_code = validate_actions(chain->dp, &flow->key, ofm->actions, actions_len); + if (v_code != ACT_VALIDATION_OK) { + dp_send_error_msg(chain->dp, sender, OFPET_BAD_ACTION, v_code, + ofm, ntohs(ofm->header.length)); + goto error_free_flow; + } + + flow->priority = flow->key.wildcards ? ntohs(ofm->priority) : -1; + strict = (ofm->command == htons(OFPFC_MODIFY_STRICT)) ? 1 : 0; + + /* First try to modify existing flows if any */ + /* if there is no matching flow, add it */ + if (!chain_modify(chain, &flow->key, flow->priority, strict, + ofm->actions, actions_len, + (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0)) { + /* Fill out flow. */ + flow->idle_timeout = ntohs(ofm->idle_timeout); + flow->hard_timeout = ntohs(ofm->hard_timeout); + flow->send_flow_rem = (ntohs(ofm->flags) & OFPFF_SEND_FLOW_REM) + ? 1 : 0; + flow->emerg_flow = (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0; + flow_setup_actions(flow, ofm->actions, actions_len); + error = chain_insert(chain, flow, + (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0); + if (error == -ENOBUFS) { + dp_send_error_msg(chain->dp, sender, + OFPET_FLOW_MOD_FAILED, + OFPFMFC_ALL_TABLES_FULL, + ofm, ntohs(ofm->header.length)); + goto error_free_flow; + } else if (error) { + goto error_free_flow; + } + } + + error = 0; + if (ntohl(ofm->buffer_id) != (uint32_t) -1) { + struct sk_buff *skb = retrieve_skb(ntohl(ofm->buffer_id)); + if (skb) { + struct sw_flow_key skb_key; + flow_extract(skb, ntohs(ofm->match.in_port), &skb_key); + execute_actions(chain->dp, skb, &skb_key, + ofm->actions, actions_len, 0); + } + else + error = -ESRCH; + } + return error; + +error_free_flow: + flow_free(flow); +error: + if (ntohl(ofm->buffer_id) != (uint32_t) -1) + discard_skb(ntohl(ofm->buffer_id)); + return error; +} + +static int +recv_flow(struct sw_chain *chain, const struct sender *sender, const void *msg) +{ + const struct ofp_flow_mod *ofm = msg; + uint16_t command = ntohs(ofm->command); + + if (command == OFPFC_ADD) { + return add_flow(chain, sender, ofm); + } else if ((command == OFPFC_MODIFY) || (command == OFPFC_MODIFY_STRICT)) { + return mod_flow(chain, sender, ofm); + } else if (command == OFPFC_DELETE) { + struct sw_flow_key key; + flow_extract_match(&key, &ofm->match); + return chain_delete(chain, &key, ofm->out_port, 0, 0, + (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0) + ? 0 : -ESRCH; + } else if (command == OFPFC_DELETE_STRICT) { + struct sw_flow_key key; + uint16_t priority; + flow_extract_match(&key, &ofm->match); + priority = key.wildcards ? ntohs(ofm->priority) : -1; + return chain_delete(chain, &key, ofm->out_port, priority, 1, + (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0) + ? 0 : -ESRCH; + } else { + return -ENOTSUPP; + } +} + +static int +recv_vendor(struct sw_chain *chain, const struct sender *sender, + const void *msg) +{ + const struct ofp_vendor_header *ovh = msg; + + switch(ntohl(ovh->vendor)) + { + case PRIVATE_VENDOR_ID: + return private_recv_msg(chain, sender, msg); + case OPENFLOW_VENDOR_ID: + return openflow_ext_recv_msg(chain, sender, msg); + default: + if (net_ratelimit()) + printk(KERN_NOTICE "%s: unknown vendor: 0x%x\n", + chain->dp->netdev->name, ntohl(ovh->vendor)); + dp_send_error_msg(chain->dp, sender, OFPET_BAD_REQUEST, + OFPBRC_BAD_VENDOR, msg, ntohs(ovh->header.length)); + return -EINVAL; + } +} + +/* 'msg', which is 'length' bytes long, was received across Netlink from + * 'sender'. Apply it to 'chain'. */ +int +fwd_control_input(struct sw_chain *chain, const struct sender *sender, + const void *msg, size_t length) +{ + + struct openflow_packet { + size_t min_size; + int (*handler)(struct sw_chain *, const struct sender *, + const void *); + }; + + static const struct openflow_packet packets[] = { + [OFPT_HELLO] = { + sizeof (struct ofp_header), + recv_hello, + }, + [OFPT_BARRIER_REQUEST] = { + sizeof (struct ofp_header), + recv_barrier_request, + }, + [OFPT_ECHO_REQUEST] = { + sizeof (struct ofp_header), + recv_echo_request, + }, + [OFPT_ECHO_REPLY] = { + sizeof (struct ofp_header), + recv_echo_reply, + }, + [OFPT_VENDOR] = { + sizeof (struct ofp_vendor_header), + recv_vendor, + }, + [OFPT_FEATURES_REQUEST] = { + sizeof (struct ofp_header), + recv_features_request, + }, + [OFPT_GET_CONFIG_REQUEST] = { + sizeof (struct ofp_header), + recv_get_config_request, + }, + [OFPT_SET_CONFIG] = { + sizeof (struct ofp_switch_config), + recv_set_config, + }, + [OFPT_PACKET_OUT] = { + sizeof (struct ofp_packet_out), + recv_packet_out, + }, + [OFPT_FLOW_MOD] = { + sizeof (struct ofp_flow_mod), + recv_flow, + }, + [OFPT_PORT_MOD] = { + sizeof (struct ofp_port_mod), + recv_port_mod, + } + }; + + struct ofp_header *oh; + + oh = (struct ofp_header *) msg; + if (oh->version != OFP_VERSION + && oh->type != OFPT_HELLO + && oh->type != OFPT_ERROR + && oh->type != OFPT_ECHO_REQUEST + && oh->type != OFPT_ECHO_REPLY + && oh->type != OFPT_VENDOR) + { + dp_send_error_msg(chain->dp, sender, OFPET_BAD_REQUEST, + OFPBRC_BAD_VERSION, msg, length); + return -EINVAL; + } + if (ntohs(oh->length) != length) { + if (net_ratelimit()) + printk(KERN_NOTICE "%s: received message length " + "wrong: %d/%d\n", chain->dp->netdev->name, + ntohs(oh->length), length); + return -EINVAL; + } + + if (oh->type < ARRAY_SIZE(packets)) { + const struct openflow_packet *pkt = &packets[oh->type]; + if (pkt->handler) { + if (length < pkt->min_size) + return -EFAULT; + return pkt->handler(chain, sender, msg); + } + } + dp_send_error_msg(chain->dp, sender, OFPET_BAD_REQUEST, + OFPBRC_BAD_TYPE, msg, length); + return -EINVAL; +} + +/* Packet buffering. */ + +#define OVERWRITE_SECS 1 +#define OVERWRITE_JIFFIES (OVERWRITE_SECS * HZ) + +struct packet_buffer { + struct sk_buff *skb; + uint32_t cookie; + unsigned long exp_jiffies; +}; + +static struct packet_buffer buffers[N_PKT_BUFFERS]; +static unsigned int buffer_idx; +static DEFINE_SPINLOCK(buffer_lock); + +uint32_t fwd_save_skb(struct sk_buff *skb) +{ + struct sk_buff *old_skb = NULL; + struct packet_buffer *p; + unsigned long int flags; + uint32_t id; + + /* FIXME: Probably just need a skb_clone() here. */ + skb = skb_copy(skb, GFP_ATOMIC); + if (!skb) + return -1; + + spin_lock_irqsave(&buffer_lock, flags); + buffer_idx = (buffer_idx + 1) & PKT_BUFFER_MASK; + p = &buffers[buffer_idx]; + if (p->skb) { + /* Don't buffer packet if existing entry is less than + * OVERWRITE_SECS old. */ + if (time_before(jiffies, p->exp_jiffies)) { + spin_unlock_irqrestore(&buffer_lock, flags); + kfree_skb(skb); + return -1; + } else { + /* Defer kfree_skb() until interrupts re-enabled. + * FIXME: we only need to do that if it has a + * destructor, but it never should since we orphan + * sk_buffs on entry. */ + old_skb = p->skb; + } + } + /* Don't use maximum cookie value since the all-bits-1 id is + * special. */ + if (++p->cookie >= (1u << PKT_COOKIE_BITS) - 1) + p->cookie = 0; + p->skb = skb; + p->exp_jiffies = jiffies + OVERWRITE_JIFFIES; + id = buffer_idx | (p->cookie << PKT_BUFFER_BITS); + spin_unlock_irqrestore(&buffer_lock, flags); + + if (old_skb) + kfree_skb(old_skb); + + return id; +} + +static struct sk_buff *retrieve_skb(uint32_t id) +{ + unsigned long int flags; + struct sk_buff *skb = NULL; + struct packet_buffer *p; + + spin_lock_irqsave(&buffer_lock, flags); + p = &buffers[id & PKT_BUFFER_MASK]; + if (p->cookie == id >> PKT_BUFFER_BITS) { + skb = p->skb; + p->skb = NULL; + } else { + if (net_ratelimit()) + printk(KERN_NOTICE "cookie mismatch: %x != %x\n", + id >> PKT_BUFFER_BITS, p->cookie); + } + spin_unlock_irqrestore(&buffer_lock, flags); + + return skb; +} + +void fwd_discard_all(void) +{ + int i; + + for (i = 0; i < N_PKT_BUFFERS; i++) { + struct sk_buff *skb; + unsigned long int flags; + + /* Defer kfree_skb() until interrupts re-enabled. */ + spin_lock_irqsave(&buffer_lock, flags); + skb = buffers[i].skb; + buffers[i].skb = NULL; + spin_unlock_irqrestore(&buffer_lock, flags); + + kfree_skb(skb); + } +} + +static void discard_skb(uint32_t id) +{ + struct sk_buff *old_skb = NULL; + unsigned long int flags; + struct packet_buffer *p; + + spin_lock_irqsave(&buffer_lock, flags); + p = &buffers[id & PKT_BUFFER_MASK]; + if (p->cookie == id >> PKT_BUFFER_BITS) { + /* Defer kfree_skb() until interrupts re-enabled. */ + old_skb = p->skb; + p->skb = NULL; + } + spin_unlock_irqrestore(&buffer_lock, flags); + + if (old_skb) + kfree_skb(old_skb); +} + +void fwd_exit(void) +{ + fwd_discard_all(); +} diff --git a/openflow/datapath/forward.h b/openflow/datapath/forward.h new file mode 100644 index 00000000..2aa9ee37 --- /dev/null +++ b/openflow/datapath/forward.h @@ -0,0 +1,38 @@ +#ifndef FORWARD_H +#define FORWARD_H 1 + +#include +#include "datapath.h" +#include "flow.h" + +struct sk_buff; +struct sw_chain; +struct sender; + +/* Buffers are identified to userspace by a 31-bit opaque ID. We divide the ID + * into a buffer number (low bits) and a cookie (high bits). The buffer number + * is an index into an array of buffers. The cookie distinguishes between + * different packets that have occupied a single buffer. Thus, the more + * buffers we have, the lower-quality the cookie... */ +#define PKT_BUFFER_BITS 8 +#define N_PKT_BUFFERS (1 << PKT_BUFFER_BITS) +#define PKT_BUFFER_MASK (N_PKT_BUFFERS - 1) + +#define PKT_COOKIE_BITS (32 - PKT_BUFFER_BITS) + +#define UINT32_MAX 4294967295U +#define UINT16_MAX 65535 +#define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) + +void fwd_port_input(struct sw_chain *, struct sk_buff *, + struct net_bridge_port *); +int run_flow_through_tables(struct sw_chain *, struct sk_buff *, + struct net_bridge_port *); +int fwd_control_input(struct sw_chain *, const struct sender *, + const void *, size_t); + +uint32_t fwd_save_skb(struct sk_buff *skb); +void fwd_discard_all(void); +void fwd_exit(void); + +#endif /* forward.h */ diff --git a/openflow/datapath/hwtable_dummy/Modules.mk b/openflow/datapath/hwtable_dummy/Modules.mk new file mode 100644 index 00000000..08e56b1e --- /dev/null +++ b/openflow/datapath/hwtable_dummy/Modules.mk @@ -0,0 +1,7 @@ +# Specify the module to build. +build_modules += ofdatapath_dummy +dist_modules += ofdatapath_dummy + +# Specify the source files that comprise the module. +ofdatapath_dummy_sources = \ + hwtable_dummy/hwtable_dummy.c diff --git a/openflow/datapath/hwtable_dummy/hwtable_dummy.c b/openflow/datapath/hwtable_dummy/hwtable_dummy.c new file mode 100644 index 00000000..82150d0f --- /dev/null +++ b/openflow/datapath/hwtable_dummy/hwtable_dummy.c @@ -0,0 +1,320 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "chain.h" +#include "table.h" +#include "flow.h" +#include "datapath.h" + +/* Max number of flow entries supported by the hardware */ +#define TMPL_MAX_FLOWS 8192 + +/* sw_flow private data for dummy table entries. */ +struct tmpl_flow { + struct list_head nodes; + /* XXX: If per-entry data is needed, define it here. */ +}; + +struct tmpl_flowtable { + struct sw_table flowtab; + unsigned int max_flows; + atomic_t num_flows; + struct list_head flows; + struct list_head iter_flows; + unsigned long int next_serial; +}; + +static struct sw_flow *tmpl_flowtable_lookup(struct sw_table *, + const struct sw_flow_key *); +static int tmpl_install_flow(struct sw_table *, struct sw_flow *); +static int tmpl_modify_flow(struct sw_table *, const struct sw_flow_key *, + uint16_t, int, const struct ofp_action_header *, + size_t); +static int do_uninstall(struct datapath *, struct sw_table *, struct sw_flow *, + enum ofp_flow_removed_reason); +static int tmpl_uninstall_flow(struct datapath *, struct sw_table *, + const struct sw_flow_key *, + uint16_t, uint16_t, int); +static int tmpl_flow_timeout(struct datapath *, struct sw_table *); +static void tmpl_destroy_flowtable(struct sw_table *); +static int tmpl_iterate_flowtable(struct sw_table *, const struct sw_flow_key *, + uint16_t, struct sw_table_position *, + int (*)(struct sw_flow *, void *), void *); +static void tmpl_get_flowstats(struct sw_table *, struct sw_table_stats *); +static struct sw_table *tmpl_create_flowtable(void); +static int __init tmpl_startup(void); +static void tmpl_cleanup(void); + +static struct sw_flow * +tmpl_flowtable_lookup(struct sw_table *flowtab, const struct sw_flow_key *key) +{ + struct tmpl_flowtable *myflowtab = (struct tmpl_flowtable *)flowtab; + struct sw_flow *flow; + + list_for_each_entry(flow, &myflowtab->flows, node) { + if (flow_matches_1wild(key, &flow->key)) { + return flow; + } + } + + return NULL; +} + +static int +tmpl_install_flow(struct sw_table *flowtab, struct sw_flow *flow) +{ + /* XXX: Use a data cache? */ + flow->private = kzalloc(sizeof(struct tmpl_flow), GFP_ATOMIC); + if (flow->private == NULL) + return 0; + + /* XXX: Do whatever needs to be done to insert an entry in hardware. + * If the entry can't be inserted, return 0. This stub code doesn't + * do anything yet, so we're going to return 0... you shouldn't (and + * you should update n_flows in struct tmpl_flowtable, too). + */ + kfree(flow->private); + return 0; +} + +static int +tmpl_modify_flow(struct sw_table *flowtab, const struct sw_flow_key *key, + uint16_t priority, int strict, + const struct ofp_action_header *actions, size_t actions_len) +{ + struct tmpl_flowtable *myflowtab = (struct tmpl_flowtable *)flowtab; + struct sw_flow *flow; + unsigned int count = 0; + + list_for_each_entry(flow, &myflowtab->flows, node) { + if (flow_matches_desc(&flow->key, key, strict) + && (!strict || (flow->priority == priority))) { + flow_replace_acts(flow, actions, actions_len); + /* XXX: Do whatever is necessary to modify the entry + * in hardware + */ + count++; + } + } + + return count; +} + +static int +do_uninstall(struct datapath *dpinst, struct sw_table *flowtab, + struct sw_flow *flow, enum ofp_flow_removed_reason reason) +{ + /* XXX: Remove the entry from hardware. If you need to do any other + * clean-up associated with the entry, do it here. + */ + dp_send_flow_end(dpinst, flow, reason); + list_del_rcu(&flow->node); + list_del_rcu(&flow->iter_node); + flow_deferred_free(flow); + return 1; +} + +static int +tmpl_uninstall_flow(struct datapath *dpinst, struct sw_table *flowtab, + const struct sw_flow_key *key, uint16_t out_port, + uint16_t priority, int strict) +{ + struct tmpl_flowtable *myflowtab = (struct tmpl_flowtable *)flowtab; + struct sw_flow *flow; + unsigned int count = 0; + + list_for_each_entry(flow, &myflowtab->flows, node) { + if (flow_matches_desc(&flow->key, key, strict) + && (!strict || (flow->priority == priority))) + count += do_uninstall(dpinst, flowtab, + flow, OFPRR_DELETE); + } + + if (count != 0) + atomic_sub(count, &myflowtab->num_flows); + return count; +} + +static int +tmpl_flow_timeout(struct datapath *dpinst, struct sw_table *flowtab) +{ + struct tmpl_flowtable *myflowtab = (struct tmpl_flowtable *)flowtab; + struct sw_flow *flow; + int num_uninst_flows = 0; + uint64_t num_forw_packets = 0; + uint64_t num_forw_bytes = 0; + int reason; + + mutex_lock(&dp_mutex); + list_for_each_entry(flow, &myflowtab->flows, node) { + /* XXX: Retrieve the packet and byte counts associated with this + * entry and store them in "packet_count" and "byte_count". + */ +#if 0 + num_forw_pakcets = flow->packet_count + get_hwmib(...); + num_forw_bytes = flow->byte_count + get_hwmib(...); +#endif + if (num_forw_packets > flow->packet_count + && flow->idle_timeout != OFP_FLOW_PERMANENT) { + flow->packet_count = num_forw_packets; + flow->byte_count = num_forw_bytes; + flow->used = get_jiffies_64(); + } + reason = flow_timeout(flow); + if (reason >= 0) { + num_uninst_flows += do_uninstall(dpinst, flowtab, + flow, reason); + } + } + mutex_unlock(&dp_mutex); + + if (num_uninst_flows != 0) + atomic_sub(num_uninst_flows, &myflowtab->num_flows); + return num_uninst_flows; +} + +static void +tmpl_destroy_flowtable(struct sw_table *flowtab) +{ + struct tmpl_flowtable *myflowtab = (struct tmpl_flowtable *)flowtab; + + if (myflowtab == NULL) { + return; + } + + /* XXX: This table is being destroyed, so free any data that you + * don't want to leak. + */ + while (!list_empty(&myflowtab->flows)) { + struct sw_flow *flow = list_entry(myflowtab->flows.next, + struct sw_flow, node); + list_del(&flow->node); + flow_free(flow); + } + + kfree(myflowtab); +} + +static int +tmpl_iterate_flowtable(struct sw_table *flowtab, const struct sw_flow_key *key, + uint16_t out_port, struct sw_table_position *position, + int (*callback) (struct sw_flow *, void *), + void *private) +{ + struct tmpl_flowtable *myflowtab = (struct tmpl_flowtable *)flowtab; + struct sw_flow *flow; + unsigned long start; + int error = 0; + + start = ~position->private[0]; + list_for_each_entry(flow, &myflowtab->iter_flows, iter_node) { + if (flow->serial <= start + && flow_matches_2wild(key, &flow->key)) { + error = callback(flow, private); + if (error) { + position->private[0] = ~flow->serial; + return error; + } + } + } + + return error; +} + +static void +tmpl_get_flowstats(struct sw_table *flowtab, struct sw_table_stats *stats) +{ + struct tmpl_flowtable *myflowtab = (struct tmpl_flowtable *)flowtab; + + stats->name = "template"; + stats->wildcards = OFPFW_ALL; /* XXX: Set this appropriately */ + stats->n_flows = atomic_read(&myflowtab->num_flows); + stats->max_flows = myflowtab->max_flows; + stats->n_matched = flowtab->n_matched; +} + +static struct sw_table * +tmpl_create_flowtable(void) +{ + struct tmpl_flowtable *myflowtab; + struct sw_table *flowtab; + + myflowtab = kzalloc(sizeof(*myflowtab), GFP_KERNEL); + if (myflowtab == NULL) + return NULL; + + flowtab = &myflowtab->flowtab; + flowtab->lookup = tmpl_flowtable_lookup; + flowtab->insert = tmpl_install_flow; + flowtab->modify = tmpl_modify_flow; + flowtab->delete = tmpl_uninstall_flow; + flowtab->timeout = tmpl_flow_timeout; + flowtab->destroy = tmpl_destroy_flowtable; + flowtab->iterate = tmpl_iterate_flowtable; + flowtab->stats = tmpl_get_flowstats; + + myflowtab->max_flows = TMPL_MAX_FLOWS; + atomic_set(&myflowtab->num_flows, 0); + INIT_LIST_HEAD(&myflowtab->flows); + INIT_LIST_HEAD(&myflowtab->iter_flows); + myflowtab->next_serial = 0; + + return flowtab; +} + +static int __init +tmpl_startup(void) +{ + return chain_set_hw_hook(tmpl_create_flowtable, THIS_MODULE); +} + +static void +tmpl_cleanup(void) +{ + chain_clear_hw_hook(); +} + +module_init(tmpl_startup); +module_exit(tmpl_cleanup); + +MODULE_DESCRIPTION("Fastpath Extension Template for OpenFlow Switch"); +MODULE_AUTHOR("Copyright (c) 2008, 2009 " + "The Board of Trustees of The Leland Stanford Junior University"); +MODULE_LICENSE("GPL"); diff --git a/openflow/datapath/hwtable_nf2/Modules.mk b/openflow/datapath/hwtable_nf2/Modules.mk new file mode 100644 index 00000000..35674911 --- /dev/null +++ b/openflow/datapath/hwtable_nf2/Modules.mk @@ -0,0 +1,19 @@ +# Specify the module to build. +build_modules += ofdatapath_netfpga +dist_modules += ofdatapath_netfpga + +# Specify the source files that comprise the module. +ofdatapath_netfpga_sources = \ + hwtable_nf2/nf2_flowtable.c \ + hwtable_nf2/nf2_procfs.c \ + hwtable_nf2/nf2_openflow.c \ + hwtable_nf2/nf2_lib.c + +ofdatapath_netfpga_headers = \ + hwtable_nf2/nf2.h \ + hwtable_nf2/nf2_reg.h \ + hwtable_nf2/nf2_hwapi.h \ + hwtable_nf2/nf2_flowtable.h \ + hwtable_nf2/nf2_procfs.h \ + hwtable_nf2/nf2_openflow.h \ + hwtable_nf2/nf2_lib.h diff --git a/openflow/datapath/hwtable_nf2/README b/openflow/datapath/hwtable_nf2/README new file mode 100644 index 00000000..da700f01 --- /dev/null +++ b/openflow/datapath/hwtable_nf2/README @@ -0,0 +1,78 @@ +NetFPGA Hardware Table + Date - 09/04/09 +---------------------------------------- + +The NetFPGA Hardware Table creates a single software table that contains all +the flows that are currently held in the NetFPGA card. The card itself splits +exact match flows into SRAM and wildcard match flows into TCAMs. Currently +there are 24 usable wildcard flow entries and 32,768 available exact match +entries. + +Installation +---------------------------------------- + +First build OpenFlow ensuring you include the directive to build the +openflow_netfpga2 hardware table in your configure statement: + + % ./configure --with-l26=/lib/modules/`uname -r` --enable-hw-tables=nf2 + +To get debugging output from the NetFPGA hardware table uncomment the following +line from within /datapath/hwtable_nf2/nf2_flowtable.h, then recompile: + + #define NF2_DEBUG 1 + +For further help regarding building OpenFlow please see the INSTALL file in +the OpenFlow root directory. + +Platform support +---------------- + +OpenFlow v0.9 with hwtable_nf2 has been tested on CentOS 5.2(Linux 2.6.18), +which is the officially supported platform of NetFPGA. + +Running +---------------------------------------- + +Use nf2_download to download the openflow_switch.bit file that is located in +the /datapath/hwtable_nf2 folder: + + % nf2_download -r /datapath/hwtable_nf2/openflow_switch.bit + +'-r' option enables PHY interrupt for its link status changing, and OpenFlow +switch can detect it. + +Install the OpenFlow kernel module: + + % insmod /datapath/linux-2.6/openflow_mod.ko + +Install the NetFPGA Hardware Table kernel module: + + % insmod /datapath/linux-2.6/openflow_netfpga2_mod.ko + +Create an OpenFlow datapath: + + % /utilities/dpctl adddp nl:0 + +Add the NetFPGA interfaces to the datapath: + + % /utilities/dpctl addif nl:0 nf2c0 + % /utilities/dpctl addif nl:0 nf2c1 + % /utilities/dpctl addif nl:0 nf2c2 + % /utilities/dpctl addif nl:0 nf2c3 + +At this point your OpenFlow switch should be ready to go. + +While you are running OpenFlow switch, you can check the hardware information +including its bitfile version as follows: + + % cat /proc/net/openflow-netfpga + +Known Bugs +---------------------------------------- +* There is currently no support for priority amongst wildcard-match entries. + +Contact +------- +e-mail: openflow-discuss@lists.stanford.edu +www: http://openflowswitch.org/ + diff --git a/openflow/datapath/hwtable_nf2/nf2.h b/openflow/datapath/hwtable_nf2/nf2.h new file mode 100644 index 00000000..847d2b10 --- /dev/null +++ b/openflow/datapath/hwtable_nf2/nf2.h @@ -0,0 +1,424 @@ +/* **************************************************************************** + * $Id: nf2.h 3546 2008-04-03 00:12:27Z grg $ + * + * Module: nf2.h + * Project: NetFPGA 2 Linux Kernel Driver + * Description: Header file for kernel driver + * + * Change history: + * + */ + +#ifndef _NF2_H +#define _NF2_H 1 + +#define NF2_DEV_NAME "nf2" + +#include + +/* Maximum number of interfaces */ +#ifndef MAX_IFACE +#define MAX_IFACE 4 +#endif + +/* + * Register names and locations. + * + * Note that these names are not necessarily identical to + * those in NF2/hw/common/src/defines + */ + +/* CPCI registers */ +#define CPCI_REG_ID 0x000 +#define CPCI_REG_BOARD_ID 0x004 +#define CPCI_REG_CTRL 0x008 +#define CPCI_REG_RESET 0x00c +#define CPCI_REG_ERROR 0x010 +#define CPCI_REG_DUMMY 0x020 +#define CPCI_REG_INTERRUPT_MASK 0x040 +#define CPCI_REG_INTERRUPT_STATUS 0x044 +#define CPCI_REG_PROG_DATA 0x100 +#define CPCI_REG_PROG_STATUS 0x104 +#define CPCI_REG_PROG_CTRL 0x108 +#define CPCI_REG_DMA_I_ADDR 0x140 +#define CPCI_REG_DMA_E_ADDR 0x144 +#define CPCI_REG_DMA_I_SIZE 0x148 +#define CPCI_REG_DMA_E_SIZE 0x14c +#define CPCI_REG_DMA_I_CTRL 0x150 +#define CPCI_REG_DMA_E_CTRL 0x154 +#define CPCI_REG_DMA_MAX_XFER_TIME 0x180 +#define CPCI_REG_DMA_MAX_RETRIES 0x184 +#define CPCI_REG_CNET_MAX_XFER_TIME 0x188 +#define CPCI_REG_DMA_I_PKT_CNT 0x400 +#define CPCI_REG_DMA_E_PKT_CNT 0x404 +#define CPCI_REG_CPCI_REG_RD_CNT 0x408 +#define CPCI_REG_CPCI_REG_WR_CNT 0x40c +#define CPCI_REG_CNET_REG_RD_CNT 0x410 +#define CPCI_REG_CNET_REG_WR_CNT 0x414 + +#define CPCI_REG_N_CLK_COUNT 0x500 +#define CPCI_REG_P_MAX 0x504 +#define CPCI_REG_N_EXP 0x508 +#define CPCI_REG_P_CLK_CTR 0x510 +#define CPCI_REG_RESET_CTR 0x520 + +/* Base address for CNET registers */ +#define CNET_REG_BASE 0x400000 + +/* Added by nweaver for building memory manipulation + utilities */ +/* 2 MB SRAM size on current board, MAX and SIZE will + need to be changed if upgraded to 4 MB SRAMs */ +#define SRAM_SIZE 0x200000 + +#define SRAM_1_BASE 0x800000 +#define SRAM_1_MAX 0x9FFFFF + +#define SRAM_2_BASE 0xC00000 +#define SRAM_2_MAX 0xDFFFFF +/* end nweaver addition */ + +/* Device ID registers */ +#define NF2_DEVICE_ID 0x0400000 +#define NF2_REVISION 0x0400004 +#define NF2_DEVICE_STR 0x0400008 + +/* CNET registers */ +#define CNET_REG_ID (CNET_REG_BASE + 0x000) +#define CNET_REG_CTRL (CNET_REG_BASE + 0x004) +#define CNET_REG_RESET (CNET_REG_BASE + 0x008) +#define CNET_REG_ERROR (CNET_REG_BASE + 0x00C) +#define CNET_REG_ENABLE (CNET_REG_BASE + 0x010) +#define CNET_REG_WR_SRAM1_EOP (CNET_REG_BASE + 0x0F0) +#define CNET_REG_RD_SRAM1_EOP (CNET_REG_BASE + 0x0F4) +#define CNET_REG_WR_SRAM2_EOP (CNET_REG_BASE + 0x0F8) +#define CNET_REG_RD_SRAM2_EOP (CNET_REG_BASE + 0x0FC) +#define CNET_REG_MF_STATUS_0 (CNET_REG_BASE + 0x100) +#define CNET_REG_MF_TX_PKTS_SENT_0 (CNET_REG_BASE + 0x104) +#define CNET_REG_MF_RX_PKTS_RCVD_0 (CNET_REG_BASE + 0x108) +#define CNET_REG_MF_RX_PKTS_LOST_0 (CNET_REG_BASE + 0x10C) +#define CNET_REG_MAC_CONFIG_0 (CNET_REG_BASE + 0x110) +#define CNET_REG_MF_STATUS_1 (CNET_REG_BASE + 0x140) +#define CNET_REG_MF_TX_PKTS_SENT_1 (CNET_REG_BASE + 0x144) +#define CNET_REG_MF_RX_PKTS_RCVD_1 (CNET_REG_BASE + 0x148) +#define CNET_REG_MF_RX_PKTS_LOST_1 (CNET_REG_BASE + 0x14C) +#define CNET_REG_MAC_CONFIG_1 (CNET_REG_BASE + 0x150) +#define CNET_REG_MF_STATUS_2 (CNET_REG_BASE + 0x180) +#define CNET_REG_MF_TX_PKTS_SENT_2 (CNET_REG_BASE + 0x184) +#define CNET_REG_MF_RX_PKTS_RCVD_2 (CNET_REG_BASE + 0x188) +#define CNET_REG_MF_RX_PKTS_LOST_2 (CNET_REG_BASE + 0x18C) +#define CNET_REG_MAC_CONFIG_2 (CNET_REG_BASE + 0x190) +#define CNET_REG_MF_STATUS_3 (CNET_REG_BASE + 0x1C0) +#define CNET_REG_MF_TX_PKTS_SENT_3 (CNET_REG_BASE + 0x1C4) +#define CNET_REG_MF_RX_PKTS_RCVD_3 (CNET_REG_BASE + 0x1C8) +#define CNET_REG_MF_RX_PKTS_LOST_3 (CNET_REG_BASE + 0x1CC) +#define CNET_REG_MAC_CONFIG_3 (CNET_REG_BASE + 0x1D0) +#define CNET_REG_RXQ_NUM_PKTS_0 (CNET_REG_BASE + 0x200) +#define CNET_REG_RXQ_POINTERS_0 (CNET_REG_BASE + 0x204) +#define CNET_REG_RXQ_NUM_PKTS_1 (CNET_REG_BASE + 0x240) +#define CNET_REG_RXQ_POINTERS_1 (CNET_REG_BASE + 0x244) +#define CNET_REG_RXQ_NUM_PKTS_2 (CNET_REG_BASE + 0x280) +#define CNET_REG_RXQ_POINTERS_2 (CNET_REG_BASE + 0x284) +#define CNET_REG_RXQ_NUM_PKTS_3 (CNET_REG_BASE + 0x2C0) +#define CNET_REG_RXQ_POINTERS_3 (CNET_REG_BASE + 0x2C4) + +#define CNET_REG_MF_RX_PKTS_LOST_BAD_FCS_0 (CNET_REG_BASE + 0x114) +#define CNET_REG_MF_RX_PKTS_LOST_FULL_FIFO_0 (CNET_REG_BASE+0x118) +#define CNET_REG_MF_RX_GOOD_PKTS_RCVD_0 (CNET_REG_BASE+0x11C) +#define CNET_REG_MF_RX_GOOD_BYTES_RCVD_0 (CNET_REG_BASE+0x120) +#define CNET_REG_MF_TX_BYTES_SENT_0 (CNET_REG_BASE+0x124) +#define CNET_REG_MF_RX_PKTS_LOST_BAD_FCS_1 (CNET_REG_BASE+0x154) +#define CNET_REG_MF_RX_PKTS_LOST_FULL_FIFO_1 (CNET_REG_BASE+0x158) +#define CNET_REG_MF_RX_GOOD_PKTS_RCVD_1 (CNET_REG_BASE+0x15C) +#define CNET_REG_MF_RX_GOOD_BYTES_RCVD_1 (CNET_REG_BASE+0x160) +#define CNET_REG_MF_TX_BYTES_SENT_1 (CNET_REG_BASE+0x164) +#define CNET_REG_MF_RX_PKTS_LOST_BAD_FCS_2 (CNET_REG_BASE+0x194) +#define CNET_REG_MF_RX_PKTS_LOST_FULL_FIFO_2 (CNET_REG_BASE+0x198) +#define CNET_REG_MF_RX_GOOD_PKTS_RCVD_2 (CNET_REG_BASE+0x19C) +#define CNET_REG_MF_RX_GOOD_BYTES_RCVD_2 (CNET_REG_BASE+0x1A0) +#define CNET_REG_MF_TX_BYTES_SENT_2 (CNET_REG_BASE+0x1A4) +#define CNET_REG_MF_RX_PKTS_LOST_BAD_FCS_3 (CNET_REG_BASE+0x1D4) +#define CNET_REG_MF_RX_PKTS_LOST_FULL_FIFO_3 (CNET_REG_BASE+0x1D8) +#define CNET_REG_MF_RX_GOOD_PKTS_RCVD_3 (CNET_REG_BASE+0x1DC) +#define CNET_REG_MF_RX_GOOD_BYTES_RCVD_3 (CNET_REG_BASE+0x1E0) +#define CNET_REG_MF_TX_BYTES_SENT_3 (CNET_REG_BASE+0x1E4) + +#define CNET_MAC_CLK_CHK_CTRL (CNET_REG_BASE + 0xF00) +#define CNET_MAC_CLK_CHK_CNT_VALUE (CNET_REG_BASE + 0xF04) + +/* Base address for CNET PHY registers */ +#define PHY_REG_BASE 0x600000 + +#define PHY_REG_CMD (PHY_REG_BASE) +#define PHY_REG_STATUS (PHY_REG_BASE) + +/* + * CPCI register masks + */ + +/* ID Masks */ +#define ID_VERSION 0x00FFFFFF +#define ID_REVISION 0xFF000000 + +/* Board ID Masks */ +#define BOARD_ID 0x00000F00 +#define BOARD_ID_CONTROL 0x00000001 + +/* Control masks */ +#define CTRL_CNET_RESET 0x00000100 +#define CTRL_LED 0x00000001 + +/* RESET masks */ +#define RESET_CPCI 0x00000001 + +/* Error masks */ +#define ERR_CNET_READ_TIMEOUT 0x02000000 +#define ERR_CNET_ERROR 0x01000000 +#define ERR_PROG_BUF_OVERFLOW 0x00020000 +#define ERR_PROG_ERROR 0x00010000 +#define ERR_DMA_TIMEOUT 0x00000400 +#define ERR_DMA_RETRY_CNT_EXPIRED 0x00000200 +#define ERR_DMA_BUF_OVERFLOW 0x00000100 +#define ERR_DMA_RD_SIZE_ERROR 0x00000040 +#define ERR_DMA_WR_SIZE_ERROR 0x00000020 +#define ERR_DMA_RD_ADDR_ERROR 0x00000010 +#define ERR_DMA_WR_ADDR_ERROR 0x00000008 +#define ERR_DMA_RD_MAC_ERROR 0x00000004 +#define ERR_DMA_WR_MAC_ERROR 0x00000002 +#define ERR_DMA_FATAL_ERROR 0x00000001 + +#define ERR_DMA_SETUP_ERROR ( ERR_DMA_WR_MAC_ERROR | \ + ERR_DMA_RD_MAC_ERROR | \ + ERR_DMA_WR_ADDR_ERROR | \ + ERR_DMA_RD_ADDR_ERROR | \ + ERR_DMA_WR_SIZE_ERROR | \ + ERR_DMA_RD_SIZE_ERROR ) + +/* Interrupt masks */ +#define INT_DMA_RX_COMPLETE 0x80000000 +#define INT_DMA_TX_COMPLETE 0x40000000 +#define INT_PHY_INTERRUPT 0x20000000 +#define INT_PKT_AVAIL 0x00000100 +#define INT_CNET_ERROR 0x00000020 +#define INT_CNET_READ_TIMEOUT 0x00000010 +#define INT_PROG_ERROR 0x00000008 +#define INT_DMA_TRANSFER_ERROR 0x00000004 +#define INT_DMA_SETUP_ERROR 0x00000002 +#define INT_DMA_FATAL_ERROR 0x00000001 + +#define INT_UNKNOWN ~(INT_DMA_RX_COMPLETE | \ + INT_DMA_TX_COMPLETE | \ + INT_PHY_INTERRUPT | \ + INT_PKT_AVAIL | \ + INT_CNET_ERROR | \ + INT_CNET_READ_TIMEOUT | \ + INT_PROG_ERROR | \ + INT_DMA_TRANSFER_ERROR | \ + INT_DMA_SETUP_ERROR | \ + INT_DMA_FATAL_ERROR) + +/* Programming status */ +#define PROG_INIT 0x00010000 +#define PROG_DONE 0x00000100 +#define PROG_FIFO_EMPTY 0x00000002 +#define PROG_IN_PROGRESS 0x00000001 + +/* Programming control */ +#define PROG_CTRL_RESET 0x00000001 + +/* DMA control */ +#define DMA_CTRL_MAC 0x00000300 +#define DMA_CTRL_OWNER 0x00000001 + +/* + * CNET register masks + */ + +/* Reset masks */ +#define CNET_RESET_MAC 0x0000000F +#define CNET_RESET_MAC_3 0x00000008 +#define CNET_RESET_MAC_2 0x00000004 +#define CNET_RESET_MAC_1 0x00000002 +#define CNET_RESET_MAC_0 0x00000001 + +/* Error masks */ +#define CNET_ERROR_TX_UNDERRUN_MAC 0x000000F0 +#define CNET_ERROR_TX_UNDERRUN_MAC_3 0x00000080 +#define CNET_ERROR_TX_UNDERRUN_MAC_2 0x00000040 +#define CNET_ERROR_TX_UNDERRUN_MAC_1 0x00000020 +#define CNET_ERROR_TX_UNDERRUN_MAC_0 0x00000010 +#define CNET_ERROR_TX_OVERRUN_MAC 0x0000000F +#define CNET_ERROR_TX_OVERRUN_MAC_3 0x00000008 +#define CNET_ERROR_TX_OVERRUN_MAC_2 0x00000004 +#define CNET_ERROR_TX_OVERRUN_MAC_1 0x00000002 +#define CNET_ERROR_TX_OVERRUN_MAC_0 0x00000001 + +/* Enable masks */ +#define CNET_ENABLE_RX_FIFO 0x0000F000 +#define CNET_ENABLE_RX_FIFO_3 0x00008000 +#define CNET_ENABLE_RX_FIFO_2 0x00004000 +#define CNET_ENABLE_RX_FIFO_1 0x00002000 +#define CNET_ENABLE_RX_FIFO_0 0x00001000 +#define CNET_ENABLE_TX_MAC 0x00000F00 +#define CNET_ENABLE_TX_MAC_3 0x00000800 +#define CNET_ENABLE_TX_MAC_2 0x00000400 +#define CNET_ENABLE_TX_MAC_1 0x00000200 +#define CNET_ENABLE_TX_MAC_0 0x00000100 +#define CNET_ENABLE_DEBUG_TRISTATE 0x00000004 +#define CNET_ENABLE_INGRESS_ARBITER 0x00000002 +#define CNET_ENABLE_RX_DMA 0x00000001 + +/* MF Status masks */ +#define CNET_MF_STATUS_RX_FIFO_EMPTY 0x02000000 +#define CNET_MF_STATUS_RX_PKT_AVAIL 0x01000000 +#define CNET_MF_STATUS_RX_NUM_PKTS 0x00FF0000 +#define CNET_MF_STATUS_TX_FIFO_FULL 0x00000200 +#define CNET_MF_STATUS_TX_FIFO_NO_MAX_PKT 0x00000100 +#define CNET_MF_STATUS_TX_NUM_PKTS 0x000000FF + +/* MAC Config masks */ +#define CNET_MAC_CFG_FULL_DUPLEX 0x00000020 +#define CNET_MAC_CFG_TX_FCS_SUPPLIED 0x00000010 +#define CNET_MAC_CFG_RX_WANT_FCS 0x00000008 +#define CNET_MAC_CFG_JUMBO_ENABLE 0x00000004 + +#define CNET_MAC_CFG_SPEED 0x00000002 +#define CNET_MAC_CFG_1000_MBPS 0x00000002 +#define CNET_MAC_CFG_100_MBPS 0x00000001 +#define CNET_MAC_CFG_10_MBPS 0x00000000 + +#define CNET_RXQ_WR_PTR 0x00FF0000 +#define CNET_RXQ_RD_PTR 0x000000FF + +/* Phy register masks */ +#define PHY_RD_WR 0x80000000 +#define PHY_PHY 0x03000000 +#define PHY_ADDR 0x001F0000 +#define PHY_DATA 0x0000FFFF + +#define PHY_DONE 0x80000000 +#define PHY_DONE_CNT 0x001F0000 + +/* Defines to calculate register values */ +/* CPCI Funcs */ +#define NF2_GET_VERSION(x) (x & 0xFFFFFF) +#define NF2_GET_REVISION(x) ((x & 0xFF000000) >> 24) + +#define NF2_GET_BOARD_ID(x) ((x & BOARD_ID) >> 8) +#define NF2_GET_CONTROL(x) (x & BOARD_ID_CONTROL) + +#define NF2_GET_CNET_RESET(x) ((x & CTRL_CNET_RESET) >> 8) +#define NF2_GET_LED(x) (x & CTRL_LED) + +#define NF2_GET_RESET(x) (x & RESET_CPCI) + +#define NF2_GET_CNET_READ_TIMEOUT(x) ((x & ERR_CNET_READ_TIMEOUT) >> 25) +#define NF2_GET_CNET_ERROR(x) ((x & ERR_CNET_ERROR) >> 24) +#define NF2_GET_PROG_BUF_OVERFLOW(x) ((x & ERR_PROG_BUF_OVERFLOW) >> 12) +#define NF2_GET_PROG_ERROR(x) ((x & ERR_PROG_ERROR) >> 11) +#define NF2_GET_DMA_TIMEOUT(x) ((x & ERR_DMA_TIMEOUT) >> 10) +#define NF2_GET_DMA_RETRY_CNT_EXPIRED(x) \ + ((x & ERR_DMA_RETRY_CNT_EXPIRED) >> 9) +#define NF2_GET_DMA_BUF_OVERFLOW(x) ((x & ERR_DMA_BUF_OVERFLOW) >> 8) +#define NF2_GET_DMA_RD_SIZE_ERROR(x) ((x & ERR_DMA_RD_SIZE_ERROR) >> 6) +#define NF2_GET_DMA_WR_SIZE_ERROR(x) ((x & ERR_DMA_WR_SIZE_ERROR) >> 5) +#define NF2_GET_DMA_RD_ADDR_ERROR(x) ((x & ERR_DMA_RD_ADDR_ERROR) >> 4) +#define NF2_GET_DMA_WR_ADDR_ERROR(x) ((x & ERR_DMA_WR_ADDR_ERROR) >> 3) +#define NF2_GET_DMA_RD_MAC_ERROR(x) ((x & ERR_DMA_RD_MAC_ERROR) >> 2) +#define NF2_GET_DMA_WR_MAC_ERROR(x) ((x & ERR_DMA_WR_MAC_ERROR) >> 1) +#define NF2_GET_DMA_FATAL_ERROR(x) (x & ERR_DMA_FATAL_ERROR) + +#define NF2_GET_INT_DMA_TX_COMPLETE(x) ((x & INT_DMA_TX_COMPLETE) >> 31) +#define NF2_GET_INT_DMA_RX_COMPLETE(x) ((x & INT_DMA_RX_COMPLETE) >> 30) +#define NF2_GET_INT_PHY_INTERRUPT(x) ((x & INT_PHY_INTERRUPT) >> 29) +#define NF2_GET_INT_PKT_AVAIL(x) ((x & INT_PKT_AVAIL) >> 8) +#define NF2_GET_INT_CNET_ERROR(x) ((x & INT_CNET_ERROR) >> 5) +#define NF2_GET_INT_CNET_READ_TIMEOUT(x) \ + ((x & INT_CNET_READ_TIMEOUT) >> 4) +#define NF2_GET_INT_PROG_ERROR(x) ((x & INT_PROG_ERROR) >> 3) +#define NF2_GET_INT_DMA_TRANSFER_ERROR(x) \ + ((x & INT_DMA_TRANSFER_ERROR) >> 2) +#define NF2_GET_INT_DMA_SETUP_ERROR(x) ((x & INT_DMA_SETUP_ERROR) >> 1) +#define NF2_GET_INT_DMA_FATAL_ERROR(x) (x & INT_DMA_FATAL_ERROR) + +#define NF2_GET_PROG_INIT(x) ((x & PROG_INIT) >> 16) +#define NF2_GET_PROG_DONE(x) ((x & PROG_DONE) >> 8) +#define NF2_GET_PROG_FIFO_EMPTY(x) ((x & PROG_FIFO_EMPTY) >> 1) +#define NF2_GET_PROG_IN_PROGRESS(x) (x & PROG_IN_PROGRESS) + +#define NF2_GET_DMA_CTRL_MAC(x) ((x & DMA_CTRL_MAC) >> 8) +#define NF2_GET_DMA_CTRL_OWNER(x) (x & DMA_CTRL_OWNER) + +#define NF2_SET_DMA_CTRL_MAC(x) (x << 8) + +/* CNET Funcs */ +#define NF2_GET_CNET_VERSION(x) ((x & 0xFFFF0000) >> 16) +#define NF2_GET_CNET_DEVICE_ID(x) (x & 0xFFFF) + +#define NF2_GET_CNET_RESET_MAC(x) (x & CNET_RESET_MAC) + +#define NF2_GET_CNET_ERROR_TX_UNDERRUN_MAC(x) \ + ((x & CNET_ERROR_TX_UNDERRUN_MAC) >> 4) +#define NF2_GET_CNET_ERROR_TX_OVERRUN_MAC(x) \ + (x & CNET_ERROR_TX_OVERRUN_MAC) + +#define NF2_GET_CNET_ENABLE_RX_FIFO(x) ((x & CNET_ENABLE_RX_FIFO) >> 12) +#define NF2_GET_CNET_ENABLE_TX_MAC(x) ((x & CNET_ENABLE_TX_MAC) >> 8) +#define NF2_GET_CNET_ENABLE_DEBUG_TRISTATE(x) \ + ((x & CNET_ENABLE_DEBUG_TRISTATE) >> 2) +#define NF2_GET_CNET_ENABLE_INGRESS_ARBITER(x) \ + ((x & CNET_ENABLE_INGRESS_ARBITER) >> 1) +#define NF2_GET_CNET_ENABLE_RX_DMA(x) (x & CNET_ENABLE_RX_DMA) + +#define NF2_GET_CNET_MF_STATUS_RX_FIFO_EMPTY(x) \ + ((x & CNET_MF_STATUS_RX_FIFO_EMPTY) >> 25) +#define NF2_GET_CNET_MF_STATUS_RX_PKT_AVAIL(x) \ + ((x & CNET_MF_STATUS_RX_PKT_AVAIL) >> 24) +#define NF2_GET_CNET_MF_STATUS_RX_NUM_PKTS(x) \ + ((x & CNET_MF_STATUS_RX_NUM_PKTS) >> 16) +#define NF2_GET_CNET_MF_STATUS_TX_FIFO_FULL(x) \ + ((x & CNET_MF_STATUS_TX_FIFO_FULL) >> 9) +#define NF2_GET_CNET_MF_STATUS_TX_FIFO_NO_MAX_PKT(x) \ + ((x & CNET_MF_STATUS_TX_FIFO_NO_MAX_PKT) >> 8) +#define NF2_GET_CNET_MF_STATUS_TX_NUM_PKTS(x) \ + (x & CNET_MF_STATUS_TX_NUM_PKTS) + +#define NF2_GET_CNET_MAC_CFG_FULL_DUPLEX(x) \ + ((x & CNET_MAC_CFG_FULL_DUPLEX) >> 5) +#define NF2_GET_CNET_MAC_CFG_TX_FCS_SUPPLIED(x) \ + ((x & CNET_MAC_CFG_TX_FCS_SUPPLIED) >> 4) +#define NF2_GET_CNET_MAC_CFG_RX_WANT_FCS(x) \ + ((x & CNET_MAC_CFG_RX_WANT_FCS) >> 3) +#define NF2_GET_CNET_MAC_CFG_JUMBO_ENABLE(x) \ + ((x & CNET_MAC_CFG_JUMBO_ENABLE) >> 2) +#define NF2_GET_CNET_MAC_CFG_SPEED(x) \ + (x & CNET_MAC_CFG_SPEED) + +#define NF2_GET_CNET_RXQ_WR_PTR(x) ((x & CNET_RXQ_WR_PTR) >> 16) +#define NF2_GET_CNET_RXQ_RD_PTR(x) (x & CNET_RXQ_RD_PTR) + +/* PHY functions */ +#define NF2_SET_PHY_IS_READ(x) (x << 31) +#define NF2_SET_PHY_SELECT(x) (x << 24) +#define NF2_SET_PHY_ADDR(x) (x << 16) +#define NF2_SET_PHY_DATA(x) (x) + +#define NF2_GET_PHY_DATA(x) (x & PHY_DATA) +#define NF2_GET_PHY_DONE(x) ((x & PHY_DONE) >> 31) +#define NF2_GET_PHY_DONE_CNT(x) ((x & PHY_DONE_CNT) >> 16) + +/* + * IOCTLs + */ +#define SIOCREGREAD SIOCDEVPRIVATE +#define SIOCREGWRITE (SIOCDEVPRIVATE + 1) + +/* + * Structure for transferring register data via an IOCTL + */ +struct nf2reg { + unsigned int reg; + unsigned int val; +}; + +#endif diff --git a/openflow/datapath/hwtable_nf2/nf2_flowtable.c b/openflow/datapath/hwtable_nf2/nf2_flowtable.c new file mode 100644 index 00000000..75eb3223 --- /dev/null +++ b/openflow/datapath/hwtable_nf2/nf2_flowtable.c @@ -0,0 +1,452 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "chain.h" +#include "table.h" +#include "flow.h" +#include "datapath.h" + +#include "hwtable_nf2/nf2_reg.h" +#include "hwtable_nf2/nf2_flowtable.h" +#include "hwtable_nf2/nf2_openflow.h" +#include "hwtable_nf2/nf2_lib.h" +#include "hwtable_nf2/nf2_procfs.h" + +struct nf2_flowtable { + struct sw_table flowtab; + spinlock_t lock; + unsigned int max_flows; + atomic_t num_flows; + struct list_head flows; + struct list_head iter_flows; + unsigned long int next_serial; +}; + +static struct sw_flow *nf2_lookup_flowtable(struct sw_table *, + const struct sw_flow_key *); +static int nf2_install_flow(struct sw_table *, struct sw_flow *); +static int nf2_modify_flow(struct sw_table *, const struct sw_flow_key *, + uint16_t, int, const struct ofp_action_header *, + size_t); +static void deferred_uninstall_callback(struct rcu_head *); +static void do_deferred_uninstall(struct sw_flow *); +static int do_uninstall(struct datapath *, struct sw_table *, struct sw_flow *, + enum ofp_flow_removed_reason); +static int nf2_has_conflict(struct sw_table *, const struct sw_flow_key *, + uint16_t, int); +static int nf2_uninstall_flow(struct datapath *, struct sw_table *, + const struct sw_flow_key *, uint16_t, + uint16_t, int); +static int nf2_flow_timeout(struct datapath *, struct sw_table *); +static void nf2_destroy_flowtable(struct sw_table *); +static int nf2_iterate_flowtable(struct sw_table *, + const struct sw_flow_key *, + uint16_t, struct sw_table_position *, + int (*)(struct sw_flow *, void *), void *); +unsigned long int get_lookup_matched_stats(void); +unsigned long int get_lookup_stats(void); +static void nf2_get_flowstats(struct sw_table *, struct sw_table_stats *); +static struct sw_table *nf2_create_flowtable(void); +static int __init nf2_startup(void); +static void nf2_cleanup(void); + +static struct sw_flow * +nf2_lookup_flowtable(struct sw_table *flowtab, const struct sw_flow_key *key) +{ + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + struct sw_flow *flow; + + list_for_each_entry(flow, &nf2flowtab->flows, node) { + if (flow_matches_1wild(key, &flow->key)) { + return flow; + } + } + + return NULL; +} + +static int +nf2_install_flow(struct sw_table *flowtab, struct sw_flow *flow) +{ + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + + /* Delete flows that match exactly. */ + nf2_uninstall_flow(NULL, flowtab, &flow->key, OFPP_NONE, + flow->priority, true); + + if (nf2_are_actions_supported(flow)) { + if (nf2_build_and_write_flow(flow)) { + return 0; + } + } else { + /* Unsupported actions or no netdevice. */ + return 0; + } + + atomic_inc(&nf2flowtab->num_flows); + list_add_rcu(&flow->node, &nf2flowtab->flows); + list_add_rcu(&flow->iter_node, &nf2flowtab->iter_flows); + return 1; +} + +static int +nf2_modify_flow(struct sw_table *flowtab, const struct sw_flow_key *key, + uint16_t priority, int strict, + const struct ofp_action_header *actions, size_t actions_len) +{ + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + struct sw_flow *flow; + unsigned int count = 0; + + list_for_each_entry(flow, &nf2flowtab->flows, node) { + if (flow_matches_desc(&flow->key, key, strict) + && (!strict || flow->priority == priority)) { + flow_replace_acts(flow, actions, actions_len); + if (nf2_are_actions_supported(flow)) { + count += nf2_modify_acts(flowtab, flow); + } + } else { + return 0; + } + } + + return count; +} + +static int +nf2_has_conflict(struct sw_table *flowtab, const struct sw_flow_key *key, + uint16_t priority, int strict) +{ + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + struct sw_flow *flow; + + list_for_each_entry(flow, &nf2flowtab->flows, node) { + if (flow_matches_desc(&flow->key, key, strict) + && (flow->priority == priority)) { + return true; + } + } + return false; +} + +static void +deferred_uninstall_callback(struct rcu_head *rcu) +{ + struct sw_flow *flow = container_of(rcu, struct sw_flow, rcu); + + flow_free(flow); +} + +static void +do_deferred_uninstall(struct sw_flow *flow) +{ + call_rcu(&flow->rcu, deferred_uninstall_callback); +} + +static int +do_uninstall(struct datapath *dpinst, struct sw_table *flowtab, + struct sw_flow *flow, enum ofp_flow_removed_reason reason) +{ + if (flow != NULL && flow->private != NULL) { + if (dpinst != NULL) + dp_send_flow_end(dpinst, flow, reason); + list_del_rcu(&flow->node); + list_del_rcu(&flow->iter_node); + nf2_delete_private(flow->private); + do_deferred_uninstall(flow); + return 1; + } + + return 0; +} + +static int +nf2_uninstall_flow(struct datapath *dpinst, struct sw_table *flowtab, + const struct sw_flow_key *key, uint16_t out_port, + uint16_t priority, int strict) +{ + struct net_device *netdev; + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + struct sw_flow *flow; + struct nf2_flow *nf2flow; + unsigned int count = 0; + + netdev = nf2_get_net_device(); + if (netdev == NULL) + return 0; + + list_for_each_entry(flow, &nf2flowtab->flows, node) { + if (flow_matches_desc(&flow->key, key, strict) + && (!strict || flow->priority == priority) + && flow_has_out_port(flow, out_port)) { + nf2flow = flow->private; + if (nf2flow != NULL) { + flow->packet_count + += nf2_get_packet_count(netdev, + nf2flow); + flow->byte_count += nf2_get_byte_count(netdev, + nf2flow); + } + count += do_uninstall(dpinst, flowtab, + flow, OFPRR_DELETE); + } + } + if (count != 0) + atomic_sub(count, &nf2flowtab->num_flows); + + nf2_free_net_device(netdev); + + return count; +} + +static int +nf2_flow_timeout(struct datapath *dpinst, struct sw_table *flowtab) +{ + struct net_device *netdev; + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + struct sw_flow *flow; + struct nf2_flow *nf2flow; + int num_uninst_flows = 0; + uint64_t num_forw_packets = 0; + int reason; + + netdev = nf2_get_net_device(); + if (netdev == NULL) + return num_uninst_flows; + + mutex_lock(&dp_mutex); + list_for_each_entry(flow, &nf2flowtab->flows, node) { + nf2flow = flow->private; + if (nf2flow != NULL) { + num_forw_packets = flow->packet_count + + nf2_get_packet_count(netdev, nf2flow); + flow->byte_count += nf2_get_byte_count(netdev, nf2flow); + } + if (num_forw_packets > flow->packet_count + && flow->idle_timeout != OFP_FLOW_PERMANENT) { + flow->packet_count = num_forw_packets; + flow->used = get_jiffies_64(); + } + reason = flow_timeout(flow); + if (reason >= 0) { + num_uninst_flows += do_uninstall(dpinst, flowtab, + flow, reason); + } + } + mutex_unlock(&dp_mutex); + + nf2_clear_watchdog(netdev); + + nf2_free_net_device(netdev); + + if (num_uninst_flows != 0) + atomic_sub(num_uninst_flows, &nf2flowtab->num_flows); + return num_uninst_flows; +} + +static void +nf2_destroy_flowtable(struct sw_table *flowtab) +{ + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + struct nf2_flow *nf2flow = NULL; + + if (nf2flowtab == NULL) + return; + + while (!list_empty(&nf2flowtab->flows)) { + struct sw_flow *flow = list_entry(nf2flowtab->flows.next, + struct sw_flow, node); + + list_del(&flow->node); + if (flow->private) { + nf2flow = (struct nf2_flow *)flow->private; + + if (nf2flow->type == NF2_TABLE_EXACT) { + nf2_add_free_exact(nf2flow); + } else if (nf2flow->type == NF2_TABLE_WILDCARD) { + nf2_add_free_wildcard(nf2flow); + } + flow->private = NULL; + } + flow_free(flow); + } + kfree(nf2flowtab); + + nf2_destroy_exact_freelist(); + nf2_destroy_wildcard_freelist(); +} + +static int +nf2_iterate_flowtable(struct sw_table *flowtab, const struct sw_flow_key *key, + uint16_t out_port, struct sw_table_position *position, + int (*callback) (struct sw_flow *, void *), void *private) +{ + unsigned long start; + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + struct sw_flow *flow; + int error = 0; + + start = ~position->private[0]; + list_for_each_entry(flow, &nf2flowtab->iter_flows, iter_node) { + if (flow->serial <= start && flow_matches_2wild(key, &flow->key) + && flow_has_out_port(flow, out_port)) { + error = callback(flow, private); + if (error != 0) { + position->private[0] = ~flow->serial; + return error; + } + } + } + + return error; +} + +unsigned long int +get_lookup_stats(void) +{ + struct net_device *netdev; + unsigned long int num_searched = 0; + + netdev = nf2_get_net_device(); + if (netdev == NULL) + return num_searched; + + num_searched = nf2_get_missed_count(netdev); + nf2_free_net_device(netdev); + num_searched += get_lookup_matched_stats(); + return num_searched; +} + +unsigned long int +get_lookup_matched_stats(void) +{ + struct net_device *netdev; + unsigned long int num_matched = 0; + + netdev = nf2_get_net_device(); + if (netdev == NULL) + return num_matched; + + num_matched = nf2_get_matched_count(netdev); + nf2_free_net_device(netdev); + return num_matched; +} + +static void +nf2_get_flowstats(struct sw_table *flowtab, struct sw_table_stats *stats) +{ + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + + stats->name = "nf2"; + stats->wildcards = OPENFLOW_WILDCARD_TABLE_SIZE - 8; + stats->n_flows = atomic_read(&nf2flowtab->num_flows); + stats->max_flows = nf2flowtab->max_flows; + stats->n_lookup = get_lookup_stats(); + stats->n_matched = get_lookup_matched_stats(); +} + +static struct sw_table * +nf2_create_flowtable(void) +{ + struct net_device *netdev; + struct nf2_flowtable *nf2flowtab; + struct sw_table *flowtab; + + netdev = nf2_get_net_device(); + if (netdev == NULL) + return NULL; + + nf2_reset_card(netdev); + nf2_free_net_device(netdev); + + nf2flowtab = kzalloc(sizeof(*nf2flowtab), GFP_KERNEL); + if (nf2flowtab == NULL) { + nf2_free_net_device(netdev); + return NULL; + } + + flowtab = &nf2flowtab->flowtab; + flowtab->n_lookup = (unsigned long long)get_lookup_stats(); + flowtab->n_matched = (unsigned long long)get_lookup_matched_stats(); + flowtab->lookup = nf2_lookup_flowtable; + flowtab->insert = nf2_install_flow; + flowtab->modify = nf2_modify_flow; + flowtab->has_conflict = nf2_has_conflict; + flowtab->delete = nf2_uninstall_flow; + flowtab->timeout = nf2_flow_timeout; + flowtab->destroy = nf2_destroy_flowtable; + flowtab->iterate = nf2_iterate_flowtable; + flowtab->stats = nf2_get_flowstats; +#define RESERVED_FOR_CPU2NETFPGA 8 + nf2flowtab->max_flows = OPENFLOW_NF2_EXACT_TABLE_SIZE + + OPENFLOW_WILDCARD_TABLE_SIZE - RESERVED_FOR_CPU2NETFPGA; + atomic_set(&nf2flowtab->num_flows, 0); + INIT_LIST_HEAD(&nf2flowtab->flows); + INIT_LIST_HEAD(&nf2flowtab->iter_flows); + nf2flowtab->next_serial = 0; + + nf2_init_wildcard_freelist(); + nf2_write_static_wildcard(); + nf2_init_exact_freelist(); + + return flowtab; +} + +static int __init +nf2_startup(void) +{ + nf2_create_procfs(); + return chain_set_hw_hook(nf2_create_flowtable, THIS_MODULE); +} + +static void +nf2_cleanup(void) +{ + nf2_remove_procfs(); + chain_clear_hw_hook(); +} + +module_init(nf2_startup); +module_exit(nf2_cleanup); + +MODULE_DESCRIPTION("NetFPGA Fastpath Extension for OpenFlow Switch"); +MODULE_AUTHOR("Copyright (c) 2008, 2009 " + "The Board of Trustees of The Leland Stanford Junior University"); +MODULE_LICENSE("GPL"); diff --git a/openflow/datapath/hwtable_nf2/nf2_flowtable.h b/openflow/datapath/hwtable_nf2/nf2_flowtable.h new file mode 100644 index 00000000..45aca5c7 --- /dev/null +++ b/openflow/datapath/hwtable_nf2/nf2_flowtable.h @@ -0,0 +1,63 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#ifndef HWTABLE_NF2_NF2_FLOWTABLE_ +#define HWTABLE_NF2_NF2_FLOWTABLE_ + +struct nf2_flow { + struct list_head node; + uint32_t pos; + uint32_t type; + uint32_t hw_packet_count; + uint32_t hw_byte_count; +}; + +enum nf2_of_table_type { + NF2_TABLE_EXACT, + NF2_TABLE_WILDCARD +}; + +/* #define NF2_DEBUG 1 */ + +#ifdef NF2_DEBUG +#ifdef __KERNEL__ +#define NF2DEBUGMSG(f, s...) printk(f, ## s) +#else +#define NF2DEBUGMSG(f, s...) printf(f, ## s) +#endif /* __KERNEL__ */ +#else +#define NF2DEBUGMSG(f, s...) +#endif + +/* #define NF2_WATCHDOG 1 */ + +#endif diff --git a/openflow/datapath/hwtable_nf2/nf2_hwapi.h b/openflow/datapath/hwtable_nf2/nf2_hwapi.h new file mode 100644 index 00000000..1a3e7aa1 --- /dev/null +++ b/openflow/datapath/hwtable_nf2/nf2_hwapi.h @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#ifndef HWTABLE_NF2_NF2_HWAPI_H_ +#define HWTABLE_NF2_NF2_HWAPI_H_ + +#ifdef __KERNEL__ + +int nf2k_reg_read(struct net_device *, unsigned int, void *); +int nf2k_reg_write(struct net_device *, unsigned int, void *); + +#endif /* __KERNEL__ */ + +#endif diff --git a/openflow/datapath/hwtable_nf2/nf2_lib.c b/openflow/datapath/hwtable_nf2/nf2_lib.c new file mode 100644 index 00000000..67acd433 --- /dev/null +++ b/openflow/datapath/hwtable_nf2/nf2_lib.c @@ -0,0 +1,918 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#include + +#include "crc32.h" +#include "flow.h" +#include "table.h" +#include "compat26.h" + +#include "hwtable_nf2/nf2.h" +#include "hwtable_nf2/nf2_reg.h" +#include "hwtable_nf2/nf2_hwapi.h" +#include "hwtable_nf2/nf2_flowtable.h" +#include "hwtable_nf2/nf2_openflow.h" +#include "hwtable_nf2/nf2_lib.h" + +#define MAX_INT_32 0xFFFFFFFF +#define PORT_BASE 1 + +#define VID_BITMASK 0x0FFF +#define PCP_BITSHIFT 13 +#define PCP_BITMASK 0xE000 + +struct list_head wildcard_free_list; +struct nf2_flow *exact_free_list[OPENFLOW_NF2_EXACT_TABLE_SIZE]; + +static uint32_t make_nw_wildcard(int); +static struct nf2_flow *get_free_exact(nf2_of_entry_wrap *); +static struct nf2_flow *get_free_wildcard(void); +static int is_action_forward_all(struct sw_flow *); +static void populate_action_output(nf2_of_action_wrap *, nf2_of_entry_wrap *, + uint8_t *); +static void populate_action_set_dl_src(nf2_of_action_wrap *, uint8_t *); +static void populate_action_set_dl_dst(nf2_of_action_wrap *, uint8_t *); + +struct net_device * +nf2_get_net_device(void) +{ + return dev_get_by_name(&init_net, "nf2c0"); +} + +void +nf2_free_net_device(struct net_device *dev) +{ + if (dev == NULL) + return; + + dev_put(dev); +} + +/* Checks to see if the actions requested by the flow are capable of being + * done in the NF2 hardware. Returns 1 if yes, 0 for no. + */ +int +nf2_are_actions_supported(struct sw_flow *flow) +{ + struct sw_flow_actions *sfa; + size_t actions_len; + uint8_t *p; + + sfa = flow->sf_acts; + actions_len = sfa->actions_len; + p = (uint8_t *)sfa->actions; + + while (actions_len > 0) { + struct ofp_action_header *ah = (struct ofp_action_header *)p; + struct ofp_action_output *oa = (struct ofp_action_output *)p; + size_t len = ntohs(ah->len); + + NF2DEBUGMSG("Action Support Chk: Len of this action: %i\n", + len); + NF2DEBUGMSG("Action Support Chk: Len of actions : %i\n", + actions_len); + + // Currently, output port(s) action, dl_src/dst rewrite actions + // are suported. + if (!(ntohs(ah->type) == OFPAT_OUTPUT + || ntohs(ah->type) == OFPAT_SET_DL_SRC + || ntohs(ah->type) == OFPAT_SET_DL_DST)) { + NF2DEBUGMSG + ("Flow action type %#0x not supported in hardware\n", + ntohs(ah->type)); + return 0; + } + // Only support ports 1-4(incl. IN_PORT), ALL, FLOOD. + // Let CONTROLLER/LOCAL fall through + if ((ntohs(ah->type) == OFPAT_OUTPUT) + && (!((ntohs(oa->port) >= PORT_BASE) + && (ntohs(oa->port) <= MAX_IFACE)) + && !(ntohs(oa->port) == OFPP_ALL) + && !(ntohs(oa->port) == OFPP_FLOOD) + && !(ntohs(oa->port) == OFPP_IN_PORT))) { + NF2DEBUGMSG + ("Flow action output port %#0x is not supported in hardware\n", + ntohs(oa->port)); + return 0; + } + p += len; + actions_len -= len; + } + + return 1; +} + +/* Write all 0's out to an exact entry position. */ +void +nf2_clear_of_exact(uint32_t pos) +{ + nf2_of_entry_wrap entry; + nf2_of_action_wrap action; + struct net_device *dev = NULL; + + memset(&entry, 0, sizeof(nf2_of_entry_wrap)); + memset(&action, 0, sizeof(nf2_of_action_wrap)); + + dev = nf2_get_net_device(); + if (dev == NULL) + return; + + nf2_write_of_exact(dev, pos, &entry, &action); + nf2_free_net_device(dev); +} + +/* + * Write all 0's out to a wildcard entry position + */ +void +nf2_clear_of_wildcard(uint32_t pos) +{ + nf2_of_entry_wrap entry; + nf2_of_mask_wrap mask; + nf2_of_action_wrap action; + struct net_device *dev = NULL; + + memset(&entry, 0, sizeof(nf2_of_entry_wrap)); + memset(&mask, 0, sizeof(nf2_of_mask_wrap)); + memset(&action, 0, sizeof(nf2_of_action_wrap)); + + dev = nf2_get_net_device(); + if (dev == NULL) + return; + + nf2_write_of_wildcard(dev, pos, &entry, &mask, &action); + nf2_free_net_device(dev); +} + +int +nf2_init_exact_freelist(void) +{ + struct nf2_flow *sfw = NULL; + int i; + + for (i = 0; i < (OPENFLOW_NF2_EXACT_TABLE_SIZE); ++i) { + sfw = kzalloc(sizeof(struct nf2_flow), GFP_ATOMIC); + if (sfw == NULL) { + return 1; + } + sfw->pos = i; + sfw->type = NF2_TABLE_EXACT; + nf2_add_free_exact(sfw); + sfw = NULL; + } + + return 0; +} + +int +nf2_init_wildcard_freelist(void) +{ + struct nf2_flow *sfw = NULL; + int i; + INIT_LIST_HEAD(&wildcard_free_list); + + for (i = 0; i < (OPENFLOW_WILDCARD_TABLE_SIZE - 8); ++i) { + sfw = kzalloc(sizeof(struct nf2_flow), GFP_ATOMIC); + if (sfw == NULL) { + return 1; + } + sfw->pos = i; + sfw->type = NF2_TABLE_WILDCARD; + nf2_add_free_wildcard(sfw); + sfw = NULL; + } + + return 0; +} + +/* Called when the table is being deleted. */ +void +nf2_destroy_exact_freelist(void) +{ + struct nf2_flow *sfw = NULL; + int i; + + for (i = 0; i < (OPENFLOW_NF2_EXACT_TABLE_SIZE); ++i) { + sfw = exact_free_list[i]; + if (sfw) { + kfree(sfw); + } + sfw = NULL; + } +} + +/* Called when the table is being deleted. */ +void +nf2_destroy_wildcard_freelist(void) +{ + struct nf2_flow *sfw = NULL; + struct list_head *next = NULL; + + while (!list_empty(&wildcard_free_list)) { + next = wildcard_free_list.next; + sfw = list_entry(next, struct nf2_flow, node); + list_del(&sfw->node); + kfree(sfw); + } +} + +/* Setup the wildcard table by adding static flows that will handle + * misses by sending them up to the cpu ports, and handle packets coming + * back down from the cpu by sending them out the corresponding port. + */ +int +nf2_write_static_wildcard(void) +{ + nf2_of_entry_wrap entry; + nf2_of_mask_wrap mask; + nf2_of_action_wrap action; + int i; + struct net_device *dev; + + dev = nf2_get_net_device(); + if (dev == NULL) + return 1; + + memset(&entry, 0x00, sizeof(nf2_of_entry_wrap)); + memset(&mask, 0xFF, sizeof(nf2_of_mask_wrap)); + // Only non-wildcard section is the source port + mask.entry.src_port = 0; + memset(&action, 0, sizeof(nf2_of_action_wrap)); + + // write the catch all entries to send to the cpu + for (i = 0; i < 4; ++i) { + entry.entry.src_port = i * 2; + action.action.forward_bitmask = 0x1 << ((i * 2) + 1); + nf2_write_of_wildcard(dev, (OPENFLOW_WILDCARD_TABLE_SIZE - 4) + + i, &entry, &mask, &action); + } + + // write the entries to send out packets coming from the cpu + for (i = 0; i < 4; ++i) { + entry.entry.src_port = (i * 2) + 1; + action.action.forward_bitmask = 0x1 << (i * 2); + nf2_write_of_wildcard(dev, (OPENFLOW_WILDCARD_TABLE_SIZE - 8) + + i, &entry, &mask, &action); + } + + nf2_free_net_device(dev); + return 0; +} + +/* Populate a nf2_of_entry_wrap with entries from a struct sw_flow. */ +void +nf2_populate_of_entry(nf2_of_entry_wrap *key, struct sw_flow *flow) +{ + int vlan_vid; + int vlan_pcp; + int i; + + key->entry.transp_dst = ntohs(flow->key.tp_dst); + key->entry.transp_src = ntohs(flow->key.tp_src); + key->entry.ip_proto = flow->key.nw_proto; + key->entry.ip_dst = ntohl(flow->key.nw_dst); + key->entry.ip_src = ntohl(flow->key.nw_src); + key->entry.eth_type = ntohs(flow->key.dl_type); + // Blame Jad for applying endian'ness to character arrays + for (i = 0; i < 6; ++i) { + key->entry.eth_dst[i] = flow->key.dl_dst[5 - i]; + } + for (i = 0; i < 6; ++i) { + key->entry.eth_src[i] = flow->key.dl_src[5 - i]; + } + + key->entry.src_port = (ntohs(flow->key.in_port) - PORT_BASE) * 2; + + if (ntohs(flow->key.dl_vlan) == 0xffff) { + key->entry.vlan_id = 0xffff; + } else { + vlan_vid = VID_BITMASK & ntohs(flow->key.dl_vlan); + vlan_pcp = PCP_BITMASK + & ((uint16_t)(flow->key.dl_vlan_pcp) << PCP_BITSHIFT); + key->entry.vlan_id = vlan_pcp | vlan_vid; + } +} + +static uint32_t +make_nw_wildcard(int n_wild_bits) +{ + n_wild_bits &= (1u << OFPFW_NW_SRC_BITS) - 1; + return n_wild_bits < 32 ? ((1u << n_wild_bits) - 1) : 0xFFFFFFFF; +} + +/* Populate a nf2_of_mask_wrap with entries from a struct sw_flow's wildcards. */ +void +nf2_populate_of_mask(nf2_of_mask_wrap *mask, struct sw_flow *flow) +{ + int vlan_vid = 0; + int vlan_pcp = 0; + int i; + + if (OFPFW_IN_PORT & flow->key.wildcards) { + mask->entry.src_port = 0xFF; + } + if (OFPFW_DL_VLAN & flow->key.wildcards) { + vlan_vid = 0x0FFF; + } + if (OFPFW_DL_VLAN_PCP & flow->key.wildcards) { + vlan_pcp = 0xE000; + } + mask->entry.vlan_id = vlan_pcp | vlan_vid; + if (OFPFW_DL_SRC & flow->key.wildcards) { + for (i = 0; i < 6; ++i) { + mask->entry.eth_src[i] = 0xFF; + } + } + if (OFPFW_DL_DST & flow->key.wildcards) { + for (i = 0; i < 6; ++i) { + mask->entry.eth_dst[i] = 0xFF; + } + } + if (OFPFW_DL_TYPE & flow->key.wildcards) + mask->entry.eth_type = 0xFFFF; + if ((OFPFW_NW_SRC_ALL & flow->key.wildcards) + || (OFPFW_NW_SRC_MASK & flow->key.wildcards)) + mask->entry.ip_src = make_nw_wildcard + (flow->key.wildcards >> OFPFW_NW_SRC_SHIFT); + if ((OFPFW_NW_DST_ALL & flow->key.wildcards) + || (OFPFW_NW_DST_MASK & flow->key.wildcards)) + mask->entry.ip_dst = make_nw_wildcard + (flow->key.wildcards >> OFPFW_NW_DST_SHIFT); + if (OFPFW_NW_PROTO & flow->key.wildcards) + mask->entry.ip_proto = 0xFF; + if (OFPFW_TP_SRC & flow->key.wildcards) + mask->entry.transp_src = 0xFFFF; + if (OFPFW_TP_DST & flow->key.wildcards) + mask->entry.transp_dst = 0xFFFF; + + mask->entry.pad = 0x0000; +} + +static void +populate_action_output(nf2_of_action_wrap *action, nf2_of_entry_wrap *entry, + uint8_t *flowact) +{ + uint16_t port = 0; + struct ofp_action_output *actout = (struct ofp_action_output *)flowact; + int i; + + port = ntohs(actout->port); + NF2DEBUGMSG("Action Type: %i Output Port: %i\n", + ntohs(actout->type), port); + + if ((port >= PORT_BASE) && (port <= MAX_IFACE)) { + // Bitmask for output port(s), evens are phys odds cpu + action->action.forward_bitmask + |= (1 << ((port - PORT_BASE) * 2)); + NF2DEBUGMSG("Output Port: %i Forward Bitmask: %x\n", + port, action->action.forward_bitmask); + } else if (port == OFPP_IN_PORT) { + // Send out to input port + action->action.forward_bitmask + |= (1 << (entry->entry.src_port)); + NF2DEBUGMSG("Output Port = Input Port Forward Bitmask: %x\n", + action->action.forward_bitmask); + } else if (port == OFPP_ALL || port == OFPP_FLOOD) { + // Send out all ports except the source + for (i = 0; i < 4; ++i) { + if ((i * 2) != entry->entry.src_port) { + // Bitmask for output port(s), evens are + // phys odds cpu + action->action.forward_bitmask + |= (1 << (i * 2)); + NF2DEBUGMSG + ("Output Port: %i Forward Bitmask: %x\n", + port, action->action.forward_bitmask); + } + } + } +} + +static void +populate_action_set_dl_src(nf2_of_action_wrap *action, uint8_t *flowact) +{ + struct ofp_action_dl_addr *actdl = (struct ofp_action_dl_addr *)flowact; + int i; + + for (i = 0; i < 6; ++i) { + action->action.eth_src[5 - i] = actdl->dl_addr[i]; + } + action->action.nf2_action_flag |= (1 << OFPAT_SET_DL_SRC); +} + +static void +populate_action_set_dl_dst(nf2_of_action_wrap *action, uint8_t *flowact) +{ + struct ofp_action_dl_addr *actdl = (struct ofp_action_dl_addr *)flowact; + int i; + + for (i = 0; i < 6; ++i) { + action->action.eth_dst[5 - i] = actdl->dl_addr[i]; + } + action->action.nf2_action_flag |= (1 << OFPAT_SET_DL_DST); +} + +/* Populate an nf2_of_action_wrap. */ +void +nf2_populate_of_action(nf2_of_action_wrap *action, nf2_of_entry_wrap *entry, + nf2_of_mask_wrap *mask, struct sw_flow *flow) +{ + struct sw_flow_actions *sfa; + size_t actions_len; + uint8_t *p; + + sfa = flow->sf_acts; + actions_len = sfa->actions_len; + p = (uint8_t *)sfa->actions; + + // zero it out for now + memset(action, 0, sizeof(nf2_of_action_wrap)); + action->action.nf2_action_flag = 0; + + while (actions_len > 0) { + struct ofp_action_header *acth = (struct ofp_action_header *)p; + size_t len = ntohs(acth->len); + + NF2DEBUGMSG("Action Populate: Len of this action: %i\n", len); + NF2DEBUGMSG("Action Populate: Len of actions : %i\n", + actions_len); + + if (acth->type == htons(OFPAT_OUTPUT)) { + populate_action_output(action, entry, p); + } else if (acth->type == htons(OFPAT_SET_DL_SRC)) { + populate_action_set_dl_src(action, p); + } else if (acth->type == htons(OFPAT_SET_DL_DST)) { + populate_action_set_dl_dst(action, p); + } + p += len; + actions_len -= len; + } +} + +/* Add a free hardware entry back to the exact pool. */ +void +nf2_add_free_exact(struct nf2_flow *sfw) +{ + // clear the node entry + INIT_LIST_HEAD(&sfw->node); + + // Critical section, adding to the actual list + exact_free_list[sfw->pos] = sfw; +} + +/* Add a free hardware entry back to the wildcard pool. */ +void +nf2_add_free_wildcard(struct nf2_flow *sfw) +{ + // clear the hw values + sfw->hw_packet_count = 0; + sfw->hw_byte_count = 0; + + // Critical section, adding to the actual list + list_add_tail(&sfw->node, &wildcard_free_list); +} + +/* Hashes the entry to find where it should exist in the exact table + * returns NULL on failure + */ +static struct nf2_flow * +get_free_exact(nf2_of_entry_wrap *entry) +{ + unsigned int poly1 = 0x04C11DB7; + unsigned int poly2 = 0x1EDC6F41; + struct nf2_flow *sfw = NULL; + unsigned int hash = 0x0; + unsigned int index = 0x0; + struct crc32 crc; + + crc32_init(&crc, poly1); + hash = crc32_calculate(&crc, entry, sizeof(nf2_of_entry_wrap)); + + // the bottom 15 bits of hash == the index into the table + index = 0x7FFF & hash; + + // if this index is free, grab it + sfw = exact_free_list[index]; + exact_free_list[index] = NULL; + + if (sfw != NULL) { + return sfw; + } + // try the second index + crc32_init(&crc, poly2); + hash = crc32_calculate(&crc, entry, sizeof(nf2_of_entry_wrap)); + // the bottom 15 bits of hash == the index into the table + index = 0x7FFF & hash; + + // if this index is free, grab it + sfw = exact_free_list[index]; + exact_free_list[index] = NULL; + + // return whether its good or not + return sfw; +} + +/* Get the first free position in the wildcard hardware table + * to write into. + */ +static struct nf2_flow * +get_free_wildcard(void) +{ + struct nf2_flow *sfw = NULL; + struct list_head *next = NULL; + + // Critical section, pulling the first available from the list + if (list_empty(&wildcard_free_list)) { + // empty :( + sfw = NULL; + } else { + next = wildcard_free_list.next; + sfw = list_entry(next, struct nf2_flow, node); + list_del_init(&sfw->node); + } + + return sfw; +} + +/* Retrieves the type of table this flow should go into. */ +int +nf2_get_table_type(struct sw_flow *flow) +{ + if (flow->key.wildcards != 0) { + NF2DEBUGMSG("--- TABLE TYPE: WILDCARD ---\n"); + return NF2_TABLE_WILDCARD; + } else { + NF2DEBUGMSG("--- TABLE TYPE: EXACT ---\n"); + return NF2_TABLE_EXACT; + } +} + +/* Returns 1 if this flow contains an action outputting to all ports except + * input port, 0 otherwise. We support OFPP_ALL and OFPP_FLOOD actions, however + * since we do not perform the spanning tree protocol (STP) then OFPP_FLOOD is + * equivalent to OFPP_ALL. + */ +static int +is_action_forward_all(struct sw_flow *flow) +{ + struct sw_flow_actions *sfa; + size_t actions_len; + uint8_t *p; + + sfa = flow->sf_acts; + actions_len = sfa->actions_len; + p = (uint8_t *)sfa->actions; + + while (actions_len > 0) { + struct ofp_action_header *ah = (struct ofp_action_header *)p; + struct ofp_action_output *oa = (struct ofp_action_output *)p; + size_t len = ntohs(ah->len); + + NF2DEBUGMSG("Fwd Action Chk: Action type: %x\n", + ntohs(ah->type)); + NF2DEBUGMSG("Fwd Action Chk: Output port: %x\n", + ntohs(oa->port)); + NF2DEBUGMSG("Fwd Action Chk: Len of this action: %i\n", len); + NF2DEBUGMSG("Fwd Action Chk: Len of actions : %i\n", + actions_len); + // Currently only support the output port(s) action + if (ntohs(ah->type) == OFPAT_OUTPUT + && (ntohs(oa->port) == OFPP_ALL + || ntohs(oa->port) == OFPP_FLOOD)) { + return 1; + } + p += len; + actions_len -= len; + } + + return 0; +} + +/* Attempts to build and write the flow to hardware. + * Returns 0 on success, 1 on failure. + */ +int +nf2_build_and_write_flow(struct sw_flow *flow) +{ + struct nf2_flow *sfw = NULL; + struct nf2_flow *sfw_next = NULL; + struct net_device *dev; + int num_entries = 0; + int i, table_type; + nf2_of_entry_wrap key; + nf2_of_mask_wrap mask; + nf2_of_action_wrap action; + + memset(&key, 0, sizeof(nf2_of_entry_wrap)); + memset(&mask, 0, sizeof(nf2_of_mask_wrap)); + memset(&action, 0, sizeof(nf2_of_action_wrap)); + + dev = nf2_get_net_device(); + if (dev == NULL) { + // failure getting net device + NF2DEBUGMSG("Failure getting net device struct\n"); + return 1; + } + + table_type = nf2_get_table_type(flow); + switch (table_type) { + default: + break; + + case NF2_TABLE_EXACT: + NF2DEBUGMSG("---Exact Entry---\n"); + nf2_populate_of_entry(&key, flow); + nf2_populate_of_action(&action, &key, NULL, flow); + sfw = get_free_exact(&key); + if (sfw == NULL) { + NF2DEBUGMSG + ("Collision getting free exact match entry\n"); + // collision + nf2_free_net_device(dev); + return 1; + } + // set the active bit on this entry + key.entry.pad = 0x8000; + nf2_write_of_exact(dev, sfw->pos, &key, &action); + flow->private = (void *)sfw; + break; + + case NF2_TABLE_WILDCARD: + NF2DEBUGMSG("---Wildcard Entry---\n"); + // if action is all out and source port is wildcarded + if ((is_action_forward_all(flow)) && + (flow->key.wildcards & OFPFW_IN_PORT)) { + NF2DEBUGMSG("Grab four wildcard tables\n"); + if (!(sfw = get_free_wildcard())) { + NF2DEBUGMSG("No free wildcard entries found."); + // no free entries + nf2_free_net_device(dev); + return 1; + } + // try to get 3 more positions + for (i = 0; i < 3; ++i) { + if (!(sfw_next = get_free_wildcard())) { + break; + } + list_add_tail(&sfw_next->node, &sfw->node); + ++num_entries; + } + + if (num_entries < 3) { + // failed to get enough entries, return them and exit + nf2_delete_private((void *)sfw); + nf2_free_net_device(dev); + return 1; + } + + nf2_populate_of_entry(&key, flow); + nf2_populate_of_mask(&mask, flow); + + // set first entry's src port to 0, remove wildcard mask on src + key.entry.src_port = 0; + mask.entry.src_port = 0; + nf2_populate_of_action(&action, &key, &mask, flow); + nf2_write_of_wildcard(dev, sfw->pos, &key, &mask, + &action); + + i = 1; + sfw_next = list_entry(sfw->node.next, + struct nf2_flow, node); + // walk through and write the remaining 3 entries + while (sfw_next != sfw) { + key.entry.src_port = i * 2; + nf2_populate_of_action(&action, &key, &mask, + flow); + nf2_write_of_wildcard(dev, sfw_next->pos, &key, + &mask, &action); + sfw_next = list_entry(sfw_next->node.next, + struct nf2_flow, node); + ++i; + } + flow->private = (void *)sfw; + } else { + /* Get a free position here, and write to it */ + if ((sfw = get_free_wildcard())) { + nf2_populate_of_entry(&key, flow); + nf2_populate_of_mask(&mask, flow); + nf2_populate_of_action(&action, &key, &mask, + flow); + if (nf2_write_of_wildcard + (dev, sfw->pos, &key, &mask, &action)) { + // failure writing to hardware + nf2_add_free_wildcard(sfw); + NF2DEBUGMSG + ("Failure writing to hardware\n"); + nf2_free_net_device(dev); + return 1; + } else { + // success writing to hardware, store the position + flow->private = (void *)sfw; + } + } else { + // hardware is full, return 0 + NF2DEBUGMSG("No free wildcard entries found."); + nf2_free_net_device(dev); + return 1; + } + } + break; + } + + nf2_free_net_device(dev); + return 0; +} + +void +nf2_delete_private(void *private) +{ + struct nf2_flow *sfw = (struct nf2_flow *)private; + struct nf2_flow *sfw_next; + struct list_head *next; + + switch (sfw->type) { + default: + break; + + case NF2_TABLE_EXACT: + nf2_clear_of_exact(sfw->pos); + nf2_add_free_exact(sfw); + break; + + case NF2_TABLE_WILDCARD: + while (!list_empty(&sfw->node)) { + next = sfw->node.next; + sfw_next = list_entry(next, struct nf2_flow, node); + list_del_init(&sfw_next->node); + // Immediately zero out the entry in hardware + nf2_clear_of_wildcard(sfw_next->pos); + // add it back to the pool + nf2_add_free_wildcard(sfw_next); + } + // zero the core entry + nf2_clear_of_wildcard(sfw->pos); + // add back the core entry + nf2_add_free_wildcard(sfw); + break; + } +} + +int +nf2_modify_acts(struct sw_table *swt, struct sw_flow *flow) +{ + struct nf2_flow *sfw = (struct nf2_flow *)flow->private; + struct net_device *dev; + nf2_of_entry_wrap key; + nf2_of_mask_wrap mask; + nf2_of_action_wrap action; + + memset(&key, 0, sizeof(nf2_of_entry_wrap)); + memset(&mask, 0, sizeof(nf2_of_mask_wrap)); + memset(&action, 0, sizeof(nf2_of_action_wrap)); + + dev = nf2_get_net_device(); + if (dev == NULL) + return 0; + + switch (sfw->type) { + default: + break; + + case NF2_TABLE_EXACT: + nf2_populate_of_entry(&key, flow); + nf2_populate_of_action(&action, &key, NULL, flow); + key.entry.pad = 0x8000; + nf2_modify_write_of_exact(dev, sfw->pos, &action); + break; + + case NF2_TABLE_WILDCARD: + if (flow->key.wildcards & OFPFW_IN_PORT) { + nf2_free_net_device(dev); + return 0; + } + nf2_populate_of_entry(&key, flow); + nf2_populate_of_mask(&mask, flow); + nf2_populate_of_action(&action, &key, &mask, flow); + nf2_modify_write_of_wildcard(dev, sfw->pos, + &key, &mask, &action); + break; + } + + nf2_free_net_device(dev); + return 1; +} + +uint64_t +nf2_get_packet_count(struct net_device *dev, struct nf2_flow *sfw) +{ + uint32_t count = 0; + uint32_t hw_count = 0; + uint64_t total = 0; + struct nf2_flow *sfw_next = NULL; + + switch (sfw->type) { + default: + break; + + case NF2_TABLE_EXACT: + count = nf2_get_exact_packet_count(dev, sfw->pos); + total = count; + break; + + case NF2_TABLE_WILDCARD: + sfw_next = sfw; + do { + hw_count = nf2_get_wildcard_packet_count(dev, + sfw_next->pos); + if (hw_count >= sfw_next->hw_packet_count) { + count = hw_count - sfw_next->hw_packet_count; + sfw_next->hw_packet_count = hw_count; + } else { + // wrapping occurred + count = (MAX_INT_32 - sfw_next->hw_packet_count) + + hw_count; + sfw_next->hw_packet_count = hw_count; + } + total += count; + sfw_next = list_entry(sfw_next->node.next, + struct nf2_flow, node); + } while (sfw_next != sfw); + break; + } + + NF2DEBUGMSG("Return nf2_get_packet_count value: %llu\n", total); + return total; +} + +uint64_t +nf2_get_byte_count(struct net_device *dev, struct nf2_flow *sfw) +{ + uint32_t count = 0; + uint32_t hw_count = 0; + uint64_t total = 0; + struct nf2_flow *sfw_next = NULL; + + switch (sfw->type) { + default: + break; + + case NF2_TABLE_EXACT: + count = nf2_get_exact_byte_count(dev, sfw->pos); + total = count; + break; + + case NF2_TABLE_WILDCARD: + sfw_next = sfw; + do { + hw_count = nf2_get_wildcard_byte_count(dev, + sfw_next->pos); + if (hw_count >= sfw_next->hw_byte_count) { + count = hw_count - sfw_next->hw_byte_count; + sfw_next->hw_byte_count = hw_count; + } else { + // wrapping occurred + count = (MAX_INT_32 - sfw_next->hw_byte_count) + + hw_count; + sfw_next->hw_byte_count = hw_count; + } + + total += count; + sfw_next = list_entry(sfw_next->node.next, + struct nf2_flow, node); + } while (sfw_next != sfw); + break; + } + + NF2DEBUGMSG("Return nf2_get_byte_count value: %llu\n", total); + return total; +} diff --git a/openflow/datapath/hwtable_nf2/nf2_lib.h b/openflow/datapath/hwtable_nf2/nf2_lib.h new file mode 100644 index 00000000..9c0fedc8 --- /dev/null +++ b/openflow/datapath/hwtable_nf2/nf2_lib.h @@ -0,0 +1,59 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#ifndef HWTABLE_NF2_NF2_LIB_H_ +#define HWTABLE_NF2_NF2_LIB_H_ + +struct net_device *nf2_get_net_device(void); +void nf2_free_net_device(struct net_device *); +int nf2_are_actions_supported(struct sw_flow *); +void nf2_clear_of_exact(uint32_t); +void nf2_clear_of_wildcard(uint32_t); +int nf2_init_exact_freelist(void); +int nf2_init_wildcard_freelist(void); +void nf2_destroy_exact_freelist(void); +void nf2_destroy_wildcard_freelist(void); +int nf2_write_static_wildcard(void); +void nf2_populate_of_entry(nf2_of_entry_wrap *, struct sw_flow *); +void nf2_populate_of_mask(nf2_of_mask_wrap *, struct sw_flow *); +void nf2_populate_of_action(nf2_of_action_wrap *, nf2_of_entry_wrap *, + nf2_of_mask_wrap *, struct sw_flow *); +void nf2_add_free_exact(struct nf2_flow *); +void nf2_add_free_wildcard(struct nf2_flow *); +int nf2_get_table_type(struct sw_flow *); +int nf2_build_and_write_flow(struct sw_flow *); +void nf2_delete_private(void *); +int nf2_modify_acts(struct sw_table *, struct sw_flow *); +uint64_t nf2_get_packet_count(struct net_device *, struct nf2_flow *); +uint64_t nf2_get_byte_count(struct net_device *, struct nf2_flow *); + +#endif diff --git a/openflow/datapath/hwtable_nf2/nf2_openflow.c b/openflow/datapath/hwtable_nf2/nf2_openflow.c new file mode 100644 index 00000000..7d392f19 --- /dev/null +++ b/openflow/datapath/hwtable_nf2/nf2_openflow.c @@ -0,0 +1,847 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#include +#include +#include + +#include "flow.h" +#include "table.h" + +#include "hwtable_nf2/nf2.h" +#include "hwtable_nf2/nf2_reg.h" +#include "hwtable_nf2/nf2_hwapi.h" +#include "hwtable_nf2/nf2_flowtable.h" +#include "hwtable_nf2/nf2_openflow.h" +#include "hwtable_nf2/nf2_lib.h" + +static void log_entry(nf2_of_entry_wrap *); +static void log_entry_raw(nf2_of_entry_wrap *); +static void log_mask(nf2_of_mask_wrap *); +static void log_mask_raw(nf2_of_mask_wrap *); +static void log_action(nf2_of_action_wrap *); +static void log_action_raw(nf2_of_action_wrap *); +static struct nf2_all_ports_info_addr *nf2_get_all_ports_info_addr(void); + +static void +log_entry(nf2_of_entry_wrap *entry) +{ +#ifndef NF2_DEBUG + return; +#else + int i; + + // Log the physical source port + NF2DEBUGMSG("E psrc[%i] ", entry->entry.src_port / 2); + + // Log the link layer source + NF2DEBUGMSG("dlsrc["); + for (i = 5; i > 0; --i) { + NF2DEBUGMSG("%0X:", entry->entry.eth_src[i]); + } + NF2DEBUGMSG("%0X] ", entry->entry.eth_src[0]); + + // Log the link layer dest + NF2DEBUGMSG("dldst["); + for (i = 5; i > 0; --i) { + NF2DEBUGMSG("%0X:", entry->entry.eth_dst[i]); + } + NF2DEBUGMSG("%0X] ", entry->entry.eth_dst[0]); + + // Log the link layer type + NF2DEBUGMSG("dltype[%0X] ", entry->entry.eth_type); + + // Log the link layer vlan + NF2DEBUGMSG("dlvlan[%0X] ", entry->entry.vlan_id); + + // Log the network source + NF2DEBUGMSG("nwsrc["); + NF2DEBUGMSG("%0i.", (entry->entry.ip_src >> 24) & 0xFF); + NF2DEBUGMSG("%0i.", (entry->entry.ip_src >> 16) & 0xFF); + NF2DEBUGMSG("%0i.", (entry->entry.ip_src >> 8) & 0xFF); + NF2DEBUGMSG("%0i", entry->entry.ip_src & 0xFF); + NF2DEBUGMSG("] "); + + // Log the network dest + NF2DEBUGMSG("nwdst["); + NF2DEBUGMSG("%0i.", (entry->entry.ip_dst >> 24) & 0xFF); + NF2DEBUGMSG("%0i.", (entry->entry.ip_dst >> 16) & 0xFF); + NF2DEBUGMSG("%0i.", (entry->entry.ip_dst >> 8) & 0xFF); + NF2DEBUGMSG("%0i", entry->entry.ip_dst & 0xFF); + NF2DEBUGMSG("] "); + + // Log the transport source port + NF2DEBUGMSG("tsrc[%i] ", entry->entry.transp_src); + + // Log the transport dest port + NF2DEBUGMSG("tdst[%i]\n", entry->entry.transp_dst); +#endif +} + +static void +log_entry_raw(nf2_of_entry_wrap *entry) +{ +#ifndef NF2_DEBUG + return; +#else + int i; + unsigned char *c; + + NF2DEBUGMSG("E "); + c = (unsigned char *)entry; + for (i = 0; i < sizeof(nf2_of_entry_wrap); ++i) { + if (!(i % 4)) { + NF2DEBUGMSG(" "); + } + NF2DEBUGMSG("%02x", c[i]); + } + NF2DEBUGMSG("\n"); +#endif +} + +static void +log_mask(nf2_of_mask_wrap *mask) +{ +#ifndef NF2_DEBUG + return; +#else + int i; + + // Log the physical source port + NF2DEBUGMSG("M psrc[%0X] ", mask->entry.src_port / 2); + + // Log the link layer source + NF2DEBUGMSG("dlsrc["); + for (i = 5; i > 0; --i) { + NF2DEBUGMSG("%0X:", mask->entry.eth_src[i]); + } + NF2DEBUGMSG("%0X] ", mask->entry.eth_dst[0]); + + // Log the link layer dest + NF2DEBUGMSG("dldst["); + for (i = 5; i > 0; --i) { + NF2DEBUGMSG("%0X:", mask->entry.eth_dst[i]); + } + NF2DEBUGMSG("%0X] ", mask->entry.eth_dst[0]); + + // Log the link layer type + NF2DEBUGMSG("dltype[%0X] ", mask->entry.eth_type); + + // Log the link layer vlan + NF2DEBUGMSG("dlvlan[%0X] ", mask->entry.vlan_id); + + // Log the network source + NF2DEBUGMSG("nwsrc["); + NF2DEBUGMSG("%0X.", (mask->entry.ip_src >> 24) & 0xFF); + NF2DEBUGMSG("%0X.", (mask->entry.ip_src >> 16) & 0xFF); + NF2DEBUGMSG("%0X.", (mask->entry.ip_src >> 8) & 0xFF); + NF2DEBUGMSG("%0X", mask->entry.ip_src & 0xFF); + NF2DEBUGMSG("] "); + + // Log the network dest + NF2DEBUGMSG("nwdst["); + NF2DEBUGMSG("%0X.", (mask->entry.ip_dst >> 24) & 0xFF); + NF2DEBUGMSG("%0X.", (mask->entry.ip_dst >> 16) & 0xFF); + NF2DEBUGMSG("%0X.", (mask->entry.ip_dst >> 8) & 0xFF); + NF2DEBUGMSG("%0X", mask->entry.ip_dst & 0xFF); + NF2DEBUGMSG("] "); + + // Log the transport source port + NF2DEBUGMSG("tsrc[%0X] ", mask->entry.transp_src); + + // Log the transport dest port + NF2DEBUGMSG("tdst[%0X]\n", mask->entry.transp_dst); +#endif +} + +static void +log_mask_raw(nf2_of_mask_wrap *mask) +{ +#ifndef NF2_DEBUG + return; +#else + int i; + unsigned char *c; + + NF2DEBUGMSG("M "); + c = (unsigned char *)mask; + for (i = 0; i < sizeof(nf2_of_mask_wrap); ++i) { + if (!(i % 4)) { + NF2DEBUGMSG(" "); + } + NF2DEBUGMSG("%02x", c[i]); + } + NF2DEBUGMSG("\n"); +#endif +} + +static void +log_action(nf2_of_action_wrap *action) +{ +#ifndef NF2_DEBUG + return; +#else + int i; + + NF2DEBUGMSG("A Output P["); + for (i = 0; i < 4; ++i) { + if (action->action.forward_bitmask & (1 << (i * 2))) { + NF2DEBUGMSG("%i", i); + } + } + NF2DEBUGMSG("] CPU["); + for (i = 0; i < 4; ++i) { + if (action->action.forward_bitmask & (1 << (1 + (i * 2)))) { + NF2DEBUGMSG("%i", i); + } + } + NF2DEBUGMSG("]\n"); +#endif +} + +static void +log_action_raw(nf2_of_action_wrap *action) +{ +#ifndef NF2_DEBUG + return; +#else + int i; + unsigned char *c; + + NF2DEBUGMSG("A "); + c = (unsigned char *)action; + for (i = 0; i < sizeof(nf2_of_action_wrap); ++i) { + if (!(i % 4)) { + NF2DEBUGMSG(" "); + } + NF2DEBUGMSG("%02x", c[i]); + } + NF2DEBUGMSG("\n"); +#endif +} + +void +nf2_reset_card(struct net_device *dev) +{ + volatile unsigned int val; + + if (dev == NULL) { + return; + } + + /* If we are operating on a NetFPGA enabled box, reset the card */ + printk(KERN_INFO "openflowswitch-netfpga2: Resetting the NetFPGA.\n"); + nf2k_reg_read(dev, WDT_CPCI_REG_CTRL, (void *)&val); + val |= 0x100; + nf2k_reg_write(dev, WDT_CPCI_REG_CTRL, (void *)&val); + printk(KERN_INFO "openflowswitch-netfpga2: Reset the NetFPGA.\n"); + ssleep(2); +} + +void +nf2_clear_watchdog(struct net_device *dev) +{ + volatile unsigned int enable_status; + +#ifndef NF2_WATCHDOG + return; +#endif + if (dev == NULL) { + return; + } + + nf2k_reg_read(dev, WDT_ENABLE_FLG_REG, (void *)&enable_status); + enable_status &= 0x1; + + if (enable_status == WATCHDOG_DISABLE) { + enable_status = WATCHDOG_ENABLE; + nf2k_reg_write(dev, WDT_ENABLE_FLG_REG, (void *)&enable_status); + } + return; +} + +/* Write a wildcard entry to the specified device and row. The row consists of + * the actual entry, its mask that specifies wildcards, as well as the action(s) + * to be taken if the row is matched + */ +int +nf2_write_of_wildcard(struct net_device *dev, int row, + nf2_of_entry_wrap *entry, nf2_of_mask_wrap *mask, + nf2_of_action_wrap *action) +{ + int i; + int val; + struct timeval t; + + NF2DEBUGMSG("** Begin wildcard entry write to row: %i\n", row); + log_entry(entry); + log_mask(mask); + log_action(action); + log_entry_raw(entry); + log_mask_raw(mask); + log_action_raw(action); + + for (i = 0; i < NF2_OF_ENTRY_WORD_LEN; ++i) { + nf2k_reg_write(dev, + OPENFLOW_WILDCARD_LOOKUP_CMP_0_REG + + (4 * i), &(entry->raw[i])); + } + + for (i = 0; i < NF2_OF_MASK_WORD_LEN; ++i) { + nf2k_reg_write(dev, + OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_0_REG + + (4 * i), &(mask->raw[i])); + } + + for (i = 0; i < NF2_OF_ACTION_WORD_LEN; ++i) { + nf2k_reg_write(dev, + OPENFLOW_WILDCARD_LOOKUP_ACTION_0_REG + + (4 * i), &(action->raw[i])); + } + + // Reset the stats for the row + val = 0; + nf2k_reg_write(dev, + OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG + (4 * row), + &val); + nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG + (4 * row), + &val); + nf2k_reg_write(dev, + OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_0_REG + (4 * row), + &val); + nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_WRITE_ADDR_REG, &row); + + do_gettimeofday(&t); + NF2DEBUGMSG("** End wildcard entry write to row: %i time: %i.%i\n", + row, (int)t.tv_sec, (int)t.tv_usec); + + return 0; +} + +int +nf2_write_of_exact(struct net_device *dev, int row, + nf2_of_entry_wrap *entry, nf2_of_action_wrap *action) +{ + int i; + int val; + struct timeval t; + unsigned int index = row << 7; + + NF2DEBUGMSG("** Begin exact match entry write to row: %i\n", row); + log_entry(entry); + log_action(action); + log_entry_raw(entry); + log_action_raw(action); + + for (i = 0; i < NF2_OF_ENTRY_WORD_LEN; ++i) { + nf2k_reg_write(dev, SRAM_BASE_ADDR + index + + (4 * i), &(entry->raw[i])); + } + + // blank out the counters + val = 0; + for (i = 0; i < NF2_OF_EXACT_COUNTERS_WORD_LEN; ++i) { + nf2k_reg_write(dev, SRAM_BASE_ADDR + index + + sizeof(nf2_of_entry_wrap) + + (4 * i), &val); + } + + // write the actions + for (i = 0; i < NF2_OF_ACTION_WORD_LEN; ++i) { + nf2k_reg_write(dev, SRAM_BASE_ADDR + index + + sizeof(nf2_of_entry_wrap) + + sizeof(nf2_of_exact_counters_wrap) + + (4 * i), &(action->raw[i])); + } + + do_gettimeofday(&t); + NF2DEBUGMSG("** End exact match entry write to row: %i time: %i.%i\n", + row, (int)t.tv_sec, (int)t.tv_usec); + + return 0; +} + +/* Write wildcard action(s) to the specified device and row. */ +int +nf2_modify_write_of_wildcard(struct net_device *dev, int row, + nf2_of_entry_wrap *entry, nf2_of_mask_wrap *mask, + nf2_of_action_wrap *action) +{ + int i; + int bytes_reg_val; + int pkts_reg_val; + int last_reg_val; + struct timeval t; + + NF2DEBUGMSG("** Begin wildcard modified action write to row: %i\n", + row); + log_entry(entry); + log_mask(mask); + log_action(action); + log_entry_raw(entry); + log_mask_raw(mask); + log_action_raw(action); + + nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_READ_ADDR_REG, &row); + nf2k_reg_read(dev, + OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG + (4 * row), + &bytes_reg_val); + nf2k_reg_read(dev, + OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG + (4 * row), + &pkts_reg_val); + nf2k_reg_read(dev, + OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_0_REG + (4 * row), + &last_reg_val); + + for (i = 0; i < NF2_OF_ENTRY_WORD_LEN; ++i) { + nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_CMP_0_REG + + (4 * i), &(entry->raw[i])); + } + + for (i = 0; i < NF2_OF_MASK_WORD_LEN; ++i) { + nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_0_REG + + (4 * i), &(mask->raw[i])); + } + + for (i = 0; i < NF2_OF_ACTION_WORD_LEN; ++i) { + nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_ACTION_0_REG + + (4 * i), &(action->raw[i])); + } + + nf2k_reg_write(dev, + OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG + (4 * row), + &bytes_reg_val); + nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG + (4 * row), + &pkts_reg_val); + nf2k_reg_write(dev, + OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_0_REG + (4 * row), + &last_reg_val); + nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_WRITE_ADDR_REG, &row); + + do_gettimeofday(&t); + NF2DEBUGMSG + ("** End wildcard modified action write to row: %i time: %i.%i\n", + row, (int)t.tv_sec, (int)t.tv_usec); + NF2DEBUGMSG(" Bytes hit count: %d\n", bytes_reg_val); + NF2DEBUGMSG(" Pkts hit count: %d\n", pkts_reg_val); + NF2DEBUGMSG(" Last seen : %d\n", last_reg_val); + + return 0; +} + +int +nf2_modify_write_of_exact(struct net_device *dev, int row, + nf2_of_action_wrap *action) +{ + int i; + struct timeval t; + unsigned int index = row << 7; + + NF2DEBUGMSG("** Begin exact match modified action write to row: %i\n", + row); + log_action(action); + log_action_raw(action); + + // write the actions + for (i = 0; i < NF2_OF_ACTION_WORD_LEN; ++i) { + nf2k_reg_write(dev, SRAM_BASE_ADDR + index + + sizeof(nf2_of_entry_wrap) + + sizeof(nf2_of_exact_counters_wrap) + + (4 * i), &(action->raw[i])); + } + + do_gettimeofday(&t); + NF2DEBUGMSG + ("** End exact match modified action write to row: %i time: %i.%i\n", + row, (int)t.tv_sec, (int)t.tv_usec); + + return 0; +} + +unsigned int +nf2_get_exact_packet_count(struct net_device *dev, int row) +{ + unsigned int val = 0; + unsigned int index = 0; + + /* TODO: Need to scrape data from all 4 registers + * in the case of a wildcarded source port and + * forward all action type + */ + nf2_of_exact_counters_wrap counters; + memset(&counters, 0, sizeof(nf2_of_exact_counters_wrap)); + + // build the index to our counters + index = row << 7; + + // Read the first word into our struct, to not disturb the byte count + nf2k_reg_read(dev, + SRAM_BASE_ADDR + index + sizeof(nf2_of_entry_wrap), + &counters); + val = counters.counters.pkt_count; + + NF2DEBUGMSG("** Exact match packet count request row: %i count: %i\n", + row, val); + + return val; +} + +unsigned int +nf2_get_exact_byte_count(struct net_device *dev, int row) +{ + unsigned int val = 0; + unsigned int index = 0; + + /* TODO: Need to scrape data from all 4 registers + * in the case of a wildcarded source port and + * forward all action type + */ + nf2_of_exact_counters_wrap counters; + memset(&counters, 0, sizeof(nf2_of_exact_counters_wrap)); + + // build the index to our counters + index = row << 7; + + // Read the second word into our struct, to not disturb the packet count + nf2k_reg_read(dev, SRAM_BASE_ADDR + index + + sizeof(nf2_of_entry_wrap) + 4, &counters.raw[1]); + val = counters.counters.byte_count; + + NF2DEBUGMSG("** Exact match byte count request row: %i count: %i\n", + row, val); + + return val; +} + +unsigned int +nf2_get_wildcard_packet_count(struct net_device *dev, int row) +{ + unsigned int val = 0; +#ifdef NF2_DEBUG + struct timeval t; +#endif + + nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_READ_ADDR_REG, &row); + nf2k_reg_read(dev, OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG + + (4 * row), &val); + +#ifdef NF2_DEBUG + do_gettimeofday(&t); + NF2DEBUGMSG + ("** Wildcard packet count request row: %i count: %i time: %i.%i\n", + row, val, (int)t.tv_sec, (int)t.tv_usec); +#endif + + return val; +} + +unsigned int +nf2_get_wildcard_byte_count(struct net_device *dev, int row) +{ + unsigned int val = 0; +#ifdef NF2_DEBUG + struct timeval t; +#endif + + nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_READ_ADDR_REG, &row); + nf2k_reg_read(dev, OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG + + (4 * row), &val); + +#ifdef NF2_DEBUG + do_gettimeofday(&t); + NF2DEBUGMSG + ("** Wildcard byte count request row: %i count: %i time: %i.%i\n", + row, val, (int)t.tv_sec, (int)t.tv_usec); +#endif + + return val; +} + +unsigned long int +nf2_get_matched_count(struct net_device *dev) +{ + unsigned int val_wild = 0; + unsigned int val_exact = 0; +#ifdef NF2_DEBUG + struct timeval t; +#endif + + nf2k_reg_read(dev, OPENFLOW_LOOKUP_WILDCARD_HITS_REG, &val_wild); + nf2k_reg_read(dev, OPENFLOW_LOOKUP_EXACT_HITS_REG, &val_exact); + +#ifdef NF2_DEBUG + do_gettimeofday(&t); + NF2DEBUGMSG("** Wildcard Matched count: %i time: %i.%i\n", + val_wild, (int)t.tv_sec, (int)t.tv_usec); + NF2DEBUGMSG("** Exact Matched count: %i time: %i.%i\n", + val_exact, (int)t.tv_sec, (int)t.tv_usec); +#endif + + return ((unsigned long int)(val_wild + val_exact)); +} + +unsigned long int +nf2_get_missed_count(struct net_device *dev) +{ + unsigned int val_wild = 0; + unsigned int val_exact = 0; +#ifdef NF2_DEBUG + struct timeval t; +#endif + + nf2k_reg_read(dev, OPENFLOW_LOOKUP_WILDCARD_MISSES_REG, &val_wild); + nf2k_reg_read(dev, OPENFLOW_LOOKUP_EXACT_MISSES_REG, &val_exact); + +#ifdef NF2_DEBUG + do_gettimeofday(&t); + NF2DEBUGMSG("** Wildcard Missed count: %i time: %i.%i\n", + val_wild, (int)t.tv_sec, (int)t.tv_usec); + NF2DEBUGMSG("** Exact Missed count: %i time: %i.%i\n", + val_exact, (int)t.tv_sec, (int)t.tv_usec); +#endif + + return ((unsigned long int)(val_wild + val_exact)); +} + +struct nf2_device_info * +nf2_get_device_info(struct net_device *dev) +{ + struct nf2_device_info *nf2devinfo; + int i; + + nf2devinfo = kzalloc(sizeof(struct nf2_device_info), GFP_KERNEL); + if (nf2devinfo == NULL) + return NULL; + + // Read the version and revision + nf2k_reg_read(dev, DEV_ID_DEVICE_ID_REG, &(nf2devinfo->nf2_device_id)); + nf2k_reg_read(dev, DEV_ID_REVISION_REG, &(nf2devinfo->nf2_device_rev)); + + // Read the design name string + for (i = 0; i < (DEVICE_STR_LEN / 4) - 2; i++) { + nf2k_reg_read(dev, DEV_ID_DEV_STR_0_REG + i * 4, + (uint32_t *)(nf2devinfo->nf2_device_str + i * 4)); + *(uint32_t *)(nf2devinfo->nf2_device_str + i * 4) + = ntohl(*(uint32_t *) + (nf2devinfo->nf2_device_str + i * 4)); + } + nf2devinfo->nf2_device_str[DEVICE_STR_LEN - 1] = '\0'; + + return nf2devinfo; +} + +struct nf2_match_info * +nf2_get_match_info(struct net_device *dev) +{ + struct nf2_match_info *nf2matchinfo; + + nf2matchinfo = kzalloc(sizeof(struct nf2_match_info), GFP_KERNEL); + if (nf2matchinfo == NULL) + return NULL; + + nf2k_reg_read(dev, OPENFLOW_LOOKUP_WILDCARD_MISSES_REG, + &(nf2matchinfo->wildcard_misses)); + nf2k_reg_read(dev, OPENFLOW_LOOKUP_WILDCARD_HITS_REG, + &(nf2matchinfo->wildcard_hits)); + nf2k_reg_read(dev, OPENFLOW_LOOKUP_EXACT_MISSES_REG, + &(nf2matchinfo->exact_misses)); + nf2k_reg_read(dev, OPENFLOW_LOOKUP_EXACT_HITS_REG, + &(nf2matchinfo->exact_hits)); + + return nf2matchinfo; +} + +unsigned int +nf2_get_watchdog_info(struct net_device *dev) +{ + unsigned int nf2wdtinfo = 0; + + nf2k_reg_read(dev, WDT_COUNTER_REG, &nf2wdtinfo); + return nf2wdtinfo; +} + +static struct nf2_all_ports_info_addr * +nf2_get_all_ports_info_addr(void) +{ + struct nf2_all_ports_info_addr *nf2addr; + + nf2addr = kzalloc(sizeof(struct nf2_all_ports_info_addr), GFP_KERNEL); + if (nf2addr == NULL) + return NULL; + + nf2addr->rx_q_num_pkts_stored_reg[0] + = MAC_GRP_0_RX_QUEUE_NUM_PKTS_STORED_REG; + nf2addr->rx_q_num_pkts_dropped_full_reg[0] + = MAC_GRP_0_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG; + nf2addr->rx_q_num_pkts_dropped_bad_reg[0] + = MAC_GRP_0_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG; + nf2addr->rx_q_num_words_pushed_reg[0] + = MAC_GRP_0_RX_QUEUE_NUM_WORDS_PUSHED_REG; + nf2addr->rx_q_num_bytes_pushed_reg[0] + = MAC_GRP_0_RX_QUEUE_NUM_BYTES_PUSHED_REG; + nf2addr->rx_q_num_pkts_dequeued_reg[0] + = MAC_GRP_0_RX_QUEUE_NUM_PKTS_DEQUEUED_REG; + nf2addr->rx_q_num_pkts_in_queue_reg[0] + = MAC_GRP_0_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG; + nf2addr->tx_q_num_pkts_in_queue_reg[0] + = MAC_GRP_0_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG; + nf2addr->tx_q_num_pkts_sent_reg[0] + = MAC_GRP_0_TX_QUEUE_NUM_PKTS_SENT_REG; + nf2addr->tx_q_num_words_pushed_reg[0] + = MAC_GRP_0_TX_QUEUE_NUM_WORDS_PUSHED_REG; + nf2addr->tx_q_num_bytes_pushed_reg[0] + = MAC_GRP_0_TX_QUEUE_NUM_BYTES_PUSHED_REG; + nf2addr->tx_q_num_pkts_enqueued_reg[0] + = MAC_GRP_0_TX_QUEUE_NUM_PKTS_ENQUEUED_REG; + + nf2addr->rx_q_num_pkts_stored_reg[1] + = MAC_GRP_1_RX_QUEUE_NUM_PKTS_STORED_REG; + nf2addr->rx_q_num_pkts_dropped_full_reg[1] + = MAC_GRP_1_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG; + nf2addr->rx_q_num_pkts_dropped_bad_reg[1] + = MAC_GRP_1_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG; + nf2addr->rx_q_num_words_pushed_reg[1] + = MAC_GRP_1_RX_QUEUE_NUM_WORDS_PUSHED_REG; + nf2addr->rx_q_num_bytes_pushed_reg[1] + = MAC_GRP_1_RX_QUEUE_NUM_BYTES_PUSHED_REG; + nf2addr->rx_q_num_pkts_dequeued_reg[1] + = MAC_GRP_1_RX_QUEUE_NUM_PKTS_DEQUEUED_REG; + nf2addr->rx_q_num_pkts_in_queue_reg[1] + = MAC_GRP_1_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG; + nf2addr->tx_q_num_pkts_in_queue_reg[1] + = MAC_GRP_1_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG; + nf2addr->tx_q_num_pkts_sent_reg[1] + = MAC_GRP_1_TX_QUEUE_NUM_PKTS_SENT_REG; + nf2addr->tx_q_num_words_pushed_reg[1] + = MAC_GRP_1_TX_QUEUE_NUM_WORDS_PUSHED_REG; + nf2addr->tx_q_num_bytes_pushed_reg[1] + = MAC_GRP_1_TX_QUEUE_NUM_BYTES_PUSHED_REG; + nf2addr->tx_q_num_pkts_enqueued_reg[1] + = MAC_GRP_1_TX_QUEUE_NUM_PKTS_ENQUEUED_REG; + + nf2addr->rx_q_num_pkts_stored_reg[2] + = MAC_GRP_2_RX_QUEUE_NUM_PKTS_STORED_REG; + nf2addr->rx_q_num_pkts_dropped_full_reg[2] + = MAC_GRP_2_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG; + nf2addr->rx_q_num_pkts_dropped_bad_reg[2] + = MAC_GRP_2_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG; + nf2addr->rx_q_num_words_pushed_reg[2] + = MAC_GRP_2_RX_QUEUE_NUM_WORDS_PUSHED_REG; + nf2addr->rx_q_num_bytes_pushed_reg[2] + = MAC_GRP_2_RX_QUEUE_NUM_BYTES_PUSHED_REG; + nf2addr->rx_q_num_pkts_dequeued_reg[2] + = MAC_GRP_2_RX_QUEUE_NUM_PKTS_DEQUEUED_REG; + nf2addr->rx_q_num_pkts_in_queue_reg[2] + = MAC_GRP_2_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG; + nf2addr->tx_q_num_pkts_in_queue_reg[2] + = MAC_GRP_2_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG; + nf2addr->tx_q_num_pkts_sent_reg[2] + = MAC_GRP_2_TX_QUEUE_NUM_PKTS_SENT_REG; + nf2addr->tx_q_num_words_pushed_reg[2] + = MAC_GRP_2_TX_QUEUE_NUM_WORDS_PUSHED_REG; + nf2addr->tx_q_num_bytes_pushed_reg[2] + = MAC_GRP_2_TX_QUEUE_NUM_BYTES_PUSHED_REG; + nf2addr->tx_q_num_pkts_enqueued_reg[2] + = MAC_GRP_2_TX_QUEUE_NUM_PKTS_ENQUEUED_REG; + + nf2addr->rx_q_num_pkts_stored_reg[3] + = MAC_GRP_3_RX_QUEUE_NUM_PKTS_STORED_REG; + nf2addr->rx_q_num_pkts_dropped_full_reg[3] + = MAC_GRP_3_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG; + nf2addr->rx_q_num_pkts_dropped_bad_reg[3] + = MAC_GRP_3_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG; + nf2addr->rx_q_num_words_pushed_reg[3] + = MAC_GRP_3_RX_QUEUE_NUM_WORDS_PUSHED_REG; + nf2addr->rx_q_num_bytes_pushed_reg[3] + = MAC_GRP_3_RX_QUEUE_NUM_BYTES_PUSHED_REG; + nf2addr->rx_q_num_pkts_dequeued_reg[3] + = MAC_GRP_3_RX_QUEUE_NUM_PKTS_DEQUEUED_REG; + nf2addr->rx_q_num_pkts_in_queue_reg[3] + = MAC_GRP_3_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG; + nf2addr->tx_q_num_pkts_in_queue_reg[3] + = MAC_GRP_3_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG; + nf2addr->tx_q_num_pkts_sent_reg[3] + = MAC_GRP_3_TX_QUEUE_NUM_PKTS_SENT_REG; + nf2addr->tx_q_num_words_pushed_reg[3] + = MAC_GRP_3_TX_QUEUE_NUM_WORDS_PUSHED_REG; + nf2addr->tx_q_num_bytes_pushed_reg[3] + = MAC_GRP_3_TX_QUEUE_NUM_BYTES_PUSHED_REG; + nf2addr->tx_q_num_pkts_enqueued_reg[3] + = MAC_GRP_3_TX_QUEUE_NUM_PKTS_ENQUEUED_REG; + + return nf2addr; +} + +struct nf2_all_ports_info * +nf2_get_all_ports_info(struct net_device *dev) +{ + struct nf2_all_ports_info *nf2portinfo; + struct nf2_all_ports_info_addr *nf2addr; + int i; + + nf2portinfo = kzalloc(sizeof(struct nf2_all_ports_info), GFP_KERNEL); + if (nf2portinfo == NULL) + return NULL; + nf2addr = nf2_get_all_ports_info_addr(); + if (nf2addr == NULL) + return NULL; + + for (i = 0; i < NF2_PORT_NUM; i++) { + nf2k_reg_read(dev, nf2addr->rx_q_num_pkts_stored_reg[i], + &(nf2portinfo->port[i].rx_q_num_pkts_stored)); + nf2k_reg_read(dev, nf2addr->rx_q_num_pkts_dropped_full_reg[i], + &(nf2portinfo + ->port[i].rx_q_num_pkts_dropped_full)); + nf2k_reg_read(dev, nf2addr->rx_q_num_pkts_dropped_bad_reg[i], + &(nf2portinfo + ->port[i].rx_q_num_pkts_dropped_bad)); + nf2k_reg_read(dev, nf2addr->rx_q_num_words_pushed_reg[i], + &(nf2portinfo->port[i].rx_q_num_words_pushed)); + nf2k_reg_read(dev, nf2addr->rx_q_num_bytes_pushed_reg[i], + &(nf2portinfo->port[i].rx_q_num_bytes_pushed)); + nf2k_reg_read(dev, nf2addr->rx_q_num_pkts_dequeued_reg[i], + &(nf2portinfo->port[i].rx_q_num_pkts_dequeued)); + nf2k_reg_read(dev, nf2addr->rx_q_num_pkts_in_queue_reg[i], + &(nf2portinfo->port[i].rx_q_num_pkts_in_queue)); + nf2k_reg_read(dev, nf2addr->tx_q_num_pkts_in_queue_reg[i], + &(nf2portinfo->port[i].tx_q_num_pkts_in_queue)); + nf2k_reg_read(dev, nf2addr->tx_q_num_pkts_sent_reg[i], + &(nf2portinfo->port[i].tx_q_num_pkts_sent)); + nf2k_reg_read(dev, nf2addr->tx_q_num_words_pushed_reg[i], + &(nf2portinfo->port[i].tx_q_num_words_pushed)); + nf2k_reg_read(dev, nf2addr->tx_q_num_bytes_pushed_reg[i], + &(nf2portinfo->port[i].tx_q_num_bytes_pushed)); + nf2k_reg_read(dev, nf2addr->tx_q_num_pkts_enqueued_reg[i], + &(nf2portinfo->port[i].tx_q_num_pkts_enqueued)); + } + return nf2portinfo; +} diff --git a/openflow/datapath/hwtable_nf2/nf2_openflow.h b/openflow/datapath/hwtable_nf2/nf2_openflow.h new file mode 100644 index 00000000..2be4b651 --- /dev/null +++ b/openflow/datapath/hwtable_nf2/nf2_openflow.h @@ -0,0 +1,169 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#ifndef HATABLE_NF2_NF2_OPENFLOW_H_ +#define HATABLE_NF2_NF2_OPENFLOW_H_ + +#define OPENFLOW_NF2_EXACT_TABLE_SIZE 32768 +#define WATCHDOG_ENABLE 1 +#define WATCHDOG_DISABLE 0 + +#pragma pack(push) /* push current alignment to stack */ +#pragma pack(1) /* set alignment to 1 byte boundary */ + +#define NF2_OF_ENTRY_WORD_LEN 8 +struct nf2_of_entry { + uint16_t transp_dst; + uint16_t transp_src; + uint8_t ip_proto; + uint32_t ip_dst; + uint32_t ip_src; + uint16_t eth_type; + uint8_t eth_dst[6]; + uint8_t eth_src[6]; + uint8_t src_port; + uint16_t vlan_id; + uint16_t pad; +}; + +typedef union nf2_of_entry_wrap { + struct nf2_of_entry entry; + uint32_t raw[NF2_OF_ENTRY_WORD_LEN]; +} nf2_of_entry_wrap; + +typedef nf2_of_entry_wrap nf2_of_mask_wrap; +#define NF2_OF_MASK_WORD_LEN 8 + +struct nf2_of_action { + uint16_t forward_bitmask; + uint16_t nf2_action_flag; + uint16_t vlan_id; + uint8_t vlan_pcp; + uint8_t eth_src[6]; + uint8_t eth_dst[6]; + uint32_t ip_src; + uint32_t ip_dst; + uint16_t transp_src; + uint16_t transp_dst; + uint8_t reserved[19]; +}; + +#define NF2_OF_ACTION_WORD_LEN 10 +typedef union nf2_of_action_wrap { + struct nf2_of_action action; + uint32_t raw[10]; +} nf2_of_action_wrap; + +struct nf2_of_exact_counters { + uint32_t pkt_count:25; + uint8_t last_seen:7; + uint32_t byte_count; +}; + +#define NF2_OF_EXACT_COUNTERS_WORD_LEN 2 +typedef union nf2_of_exact_counters_wrap { + struct nf2_of_exact_counters counters; + uint32_t raw[NF2_OF_EXACT_COUNTERS_WORD_LEN]; +} nf2_of_exact_counters_wrap; + +#define DEVICE_STR_LEN 100 +struct nf2_device_info { + uint32_t nf2_device_id; + uint32_t nf2_device_rev; + char nf2_device_str[DEVICE_STR_LEN]; +}; + +#define NF2_PORT_NUM 4 +struct nf2_all_ports_info_addr { + unsigned int rx_q_num_pkts_stored_reg[NF2_PORT_NUM]; + unsigned int rx_q_num_pkts_dropped_full_reg[NF2_PORT_NUM]; + unsigned int rx_q_num_pkts_dropped_bad_reg[NF2_PORT_NUM]; + unsigned int rx_q_num_words_pushed_reg[NF2_PORT_NUM]; + unsigned int rx_q_num_bytes_pushed_reg[NF2_PORT_NUM]; + unsigned int rx_q_num_pkts_dequeued_reg[NF2_PORT_NUM]; + unsigned int rx_q_num_pkts_in_queue_reg[NF2_PORT_NUM]; + unsigned int tx_q_num_pkts_in_queue_reg[NF2_PORT_NUM]; + unsigned int tx_q_num_pkts_sent_reg[NF2_PORT_NUM]; + unsigned int tx_q_num_words_pushed_reg[NF2_PORT_NUM]; + unsigned int tx_q_num_bytes_pushed_reg[NF2_PORT_NUM]; + unsigned int tx_q_num_pkts_enqueued_reg[NF2_PORT_NUM]; +}; + +struct nf2_port_info { + uint32_t rx_q_num_pkts_stored; + uint32_t rx_q_num_pkts_dropped_full; + uint32_t rx_q_num_pkts_dropped_bad; + uint32_t rx_q_num_words_pushed; + uint32_t rx_q_num_bytes_pushed; + uint32_t rx_q_num_pkts_dequeued; + uint32_t rx_q_num_pkts_in_queue; + uint32_t tx_q_num_pkts_in_queue; + uint32_t tx_q_num_pkts_sent; + uint32_t tx_q_num_words_pushed; + uint32_t tx_q_num_bytes_pushed; + uint32_t tx_q_num_pkts_enqueued; +}; + +struct nf2_all_ports_info { + struct nf2_port_info port[NF2_PORT_NUM]; +}; + +struct nf2_match_info { + uint32_t wildcard_misses; + uint32_t wildcard_hits; + uint32_t exact_misses; + uint32_t exact_hits; +}; + +#pragma pack(pop) /* XXX: Restore original alignment from stack */ + +void nf2_reset_card(struct net_device *); +void nf2_clear_watchdog(struct net_device *); +int nf2_write_of_wildcard(struct net_device *, int, nf2_of_entry_wrap *, + nf2_of_mask_wrap *, nf2_of_action_wrap *); +int nf2_write_of_exact(struct net_device *, int, nf2_of_entry_wrap *, + nf2_of_action_wrap *); +int nf2_modify_write_of_wildcard(struct net_device *, int, nf2_of_entry_wrap *, + nf2_of_mask_wrap *, nf2_of_action_wrap *); +int nf2_modify_write_of_exact(struct net_device *, int, nf2_of_action_wrap *); +unsigned int nf2_get_exact_packet_count(struct net_device *, int); +unsigned int nf2_get_exact_byte_count(struct net_device *, int); +unsigned int nf2_get_wildcard_packet_count(struct net_device *, int); +unsigned int nf2_get_wildcard_byte_count(struct net_device *, int); +unsigned long int nf2_get_matched_count(struct net_device *); +unsigned long int nf2_get_missed_count(struct net_device *); +struct nf2_device_info *nf2_get_device_info(struct net_device *); +struct nf2_match_info *nf2_get_match_info(struct net_device *); +unsigned int nf2_get_watchdog_info(struct net_device *); +struct nf2_all_ports_info *nf2_get_all_ports_info(struct net_device *); + +#endif diff --git a/openflow/datapath/hwtable_nf2/nf2_procfs.c b/openflow/datapath/hwtable_nf2/nf2_procfs.c new file mode 100644 index 00000000..0324afcb --- /dev/null +++ b/openflow/datapath/hwtable_nf2/nf2_procfs.c @@ -0,0 +1,240 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "chain.h" +#include "table.h" +#include "flow.h" +#include "datapath.h" + +#include "hwtable_nf2/nf2_reg.h" +#include "hwtable_nf2/nf2_flowtable.h" +#include "hwtable_nf2/nf2_openflow.h" +#include "hwtable_nf2/nf2_lib.h" +#include "hwtable_nf2/nf2_procfs.h" + +#define NF2_PROCFS_NAME "net/openflow-netfpga" +#define CLK_CYCLE 8 + +static struct semaphore proc_sem; + +static int disp_dev_info(char *); +static int disp_port_info(char *); +static int disp_match_info(char *); +static int disp_watchdog_info(char *); +static int proc_read(char *, char **, off_t, int, int *, void *); + +static int +disp_dev_info(char *page) +{ + struct net_device *netdev; + struct nf2_device_info *nf2devinfo; + int len = 0; + + netdev = nf2_get_net_device(); + if (netdev == NULL) + return 0; + nf2devinfo = nf2_get_device_info(netdev); + if (nf2devinfo == NULL) { + nf2_free_net_device(netdev); + return 0; + } + nf2_free_net_device(netdev); + + len += sprintf(page + len, + "NetFPGA: " + "design name: %s, device ID: %d, device revision: %d\n", + nf2devinfo->nf2_device_str, + nf2devinfo->nf2_device_id, nf2devinfo->nf2_device_rev); + len += sprintf(page + len, "\n"); + + return len; +} + +static int +disp_port_info(char *page) +{ + struct net_device *netdev; + struct nf2_all_ports_info *nf2portinfo; + int len = 0; + int i; + + netdev = nf2_get_net_device(); + if (netdev == NULL) + return 0; + nf2portinfo = nf2_get_all_ports_info(netdev); + if (nf2portinfo == NULL) { + nf2_free_net_device(netdev); + return 0; + } + nf2_free_net_device(netdev); + + for (i = 0; i < NF2_PORT_NUM; i++) { + len += sprintf(page + len, "Interface nf2c%d\n", i); + len += sprintf(page + len, + " Input queue: %u/%u (current/queued)\n", + nf2portinfo->port[i].rx_q_num_pkts_in_queue, + nf2portinfo->port[i].rx_q_num_pkts_dequeued); + len += sprintf(page + len, + " %u packets input, %u dropped " + "(%u buffer exhausted, %u bad packets)\n" + " %u pushed words, %u pushed bytes\n", + nf2portinfo->port[i].rx_q_num_pkts_stored, + nf2portinfo->port[i].rx_q_num_pkts_dropped_full + + nf2portinfo->port[i].rx_q_num_pkts_dropped_bad, + nf2portinfo->port[i].rx_q_num_pkts_dropped_full, + nf2portinfo->port[i].rx_q_num_pkts_dropped_bad, + nf2portinfo->port[i].rx_q_num_words_pushed, + nf2portinfo->port[i].rx_q_num_bytes_pushed); + len += sprintf(page + len, + " Output queue: %u/%u (current/queued)\n", + nf2portinfo->port[i].tx_q_num_pkts_in_queue, + nf2portinfo->port[i].tx_q_num_pkts_enqueued); + len += sprintf(page + len, + " %u packets output, " + "%u pushed words, %u pushed bytes\n", + nf2portinfo->port[i].tx_q_num_pkts_sent, + nf2portinfo->port[i].tx_q_num_words_pushed, + nf2portinfo->port[i].tx_q_num_bytes_pushed); + } + len += sprintf(page + len, "\n"); + + return len; +} + +static int +disp_match_info(char *page) +{ + struct net_device *netdev; + struct nf2_match_info *nf2matchinfo; + int len = 0; + + netdev = nf2_get_net_device(); + if (netdev == NULL) + return 0; + nf2matchinfo = nf2_get_match_info(netdev); + if (nf2matchinfo == NULL) { + nf2_free_net_device(netdev); + return 0; + } + nf2_free_net_device(netdev); + + len += sprintf(page + len, + "WILDCARD match table lookup: %u/%u (hits/misses)\n", + nf2matchinfo->wildcard_hits, + nf2matchinfo->wildcard_misses); + len += sprintf(page + len, + "EXACT match table lookup: %u/%u (hits/misses)\n", + nf2matchinfo->exact_hits, nf2matchinfo->exact_misses); + len += sprintf(page + len, "\n"); + + return len; +} + +static int +disp_watchdog_info(char *page) +{ + struct net_device *netdev; + unsigned int nf2wdtinfo; + unsigned int elapsed_time; + int len = 0; + +#ifndef NF2_WATCHDOG + return 0; +#endif + + netdev = nf2_get_net_device(); + if (netdev == NULL) + return 0; + nf2wdtinfo = nf2_get_watchdog_info(netdev); + nf2_free_net_device(netdev); + + elapsed_time = nf2wdtinfo * CLK_CYCLE / 1000000; + + len += sprintf(page + len, + "%u (msec) passed since the watchdog counter has been cleared last time\n", + elapsed_time); + len += sprintf(page + len, "\n"); + + return len; +} + +static int +proc_read(char *page, char **start, off_t offset, int count, int *eof, + void *data) +{ + int len = 0; + int buf_pos = 1; + + if (down_interruptible(&proc_sem)) + return -ERESTARTSYS; + + if (buf_pos != 0) { + len += disp_dev_info(page + len); + len += disp_port_info(page + len); + len += disp_match_info(page + len); + len += disp_watchdog_info(page + len); + buf_pos = 0; + } + up(&proc_sem); + + *eof = 1; + return len; +} + +void +nf2_create_procfs(void) +{ + struct proc_dir_entry *entry; + + entry = create_proc_entry(NF2_PROCFS_NAME, + S_IFREG | S_IRUGO | S_IWUGO, NULL); + if (entry == NULL) + return; + + entry->read_proc = proc_read; + sema_init(&proc_sem, 1); +} + +void +nf2_remove_procfs(void) +{ + remove_proc_entry(NF2_PROCFS_NAME, NULL); +} diff --git a/openflow/datapath/hwtable_nf2/nf2_procfs.h b/openflow/datapath/hwtable_nf2/nf2_procfs.h new file mode 100644 index 00000000..011f680f --- /dev/null +++ b/openflow/datapath/hwtable_nf2/nf2_procfs.h @@ -0,0 +1,39 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#ifndef HWTABLE_NF2_NF2_PROCFS_ +#define HWTABLE_NF2_NF2_PROCFS_ + +void nf2_create_procfs(void); +void nf2_remove_procfs(void); + +#endif diff --git a/openflow/datapath/hwtable_nf2/nf2_reg.h b/openflow/datapath/hwtable_nf2/nf2_reg.h new file mode 100644 index 00000000..0056f882 --- /dev/null +++ b/openflow/datapath/hwtable_nf2/nf2_reg.h @@ -0,0 +1,767 @@ +/******************************************************** +* +* C register defines file for openflow_switch +* +********************************************************/ + +#ifndef _REG_DEFINES_ +#define _REG_DEFINES_ + +/* ========= Constants ========= */ + +// ===== File: lib/verilog/core/common/xml/global.xml ===== + +// Maximum number of phy ports +#define MAX_PHY_PORTS 4 + +// PCI address bus width +#define PCI_ADDR_WIDTH 32 + +// PCI data bus width +#define PCI_DATA_WIDTH 32 + +// PCI byte enable bus width +#define PCI_BE_WIDTH 4 + +// CPCI--CNET address bus width. This is byte addresses even though bottom bits are zero. +#define CPCI_CNET_ADDR_WIDTH 27 + +// CPCI--CNET data bus width +#define CPCI_CNET_DATA_WIDTH 32 + +// CPCI--NF2 address bus width. This is byte addresses even though bottom bits are zero. +#define CPCI_NF2_ADDR_WIDTH 27 + +// CPCI--NF2 data bus width +#define CPCI_NF2_DATA_WIDTH 32 + +// DMA data bus width +#define DMA_DATA_WIDTH 32 + +// DMA control bus width +#define DMA_CTRL_WIDTH 4 + +// CPCI debug bus width +#define CPCI_DEBUG_DATA_WIDTH 29 + +// SRAM address width +#define SRAM_ADDR_WIDTH 19 + +// SRAM data width +#define SRAM_DATA_WIDTH 36 + +// DRAM address width +#define DRAM_ADDR_WIDTH 24 + +// ===== File: lib/verilog/core/common/xml/nf_defines.xml ===== + +// Clock period of 125 MHz clock in ns +#define FAST_CLK_PERIOD 8 + +// Clock period of 62.5 MHz clock in ns +#define SLOW_CLK_PERIOD 16 + +// Header value used by the IO queues +#define IO_QUEUE_STAGE_NUM 0xff + +// Data path data width +#define DATA_WIDTH 64 + +// Data path control width +#define CTRL_WIDTH 8 + +// ===== File: projects/openflow_switch/include/output_port_lookup.xml ===== + +#define FAST_CLOCK_PERIOD 8 + +// ===== File: projects/openflow_switch/include/vlan_remover.xml ===== + +#define VLAN_CTRL_WORD 0x42 + +#define VLAN_ETHERTYPE 0x8100 + +// ===== File: lib/verilog/core/output_queues/bram_output_queues/xml/bram_output_queues.xml ===== + +#define NUM_OUTPUT_QUEUES 8 + +// ===== File: projects/openflow_switch/include/opl_processor.xml ===== + +#define NF2_OFPAT_OUTPUT 0x0001 + +#define NF2_OFPAT_SET_VLAN_VID 0x0002 + +#define NF2_OFPAT_SET_VLAN_PCP 0x0004 + +#define NF2_OFPAT_STRIP_VLAN 0x0008 + +#define NF2_OFPAT_SET_DL_SRC 0x0010 + +#define NF2_OFPAT_SET_DL_DST 0x0020 + +#define NF2_OFPAT_SET_NW_SRC 0x0040 + +#define NF2_OFPAT_SET_NW_DST 0x0080 + +#define NF2_OFPAT_SET_TP_SRC 0x0100 + +#define NF2_OFPAT_SET_TP_DST 0x0200 + +// ===== File: projects/openflow_switch/include/wildcard_match.xml ===== + +#define OPENFLOW_WILDCARD_TABLE_SIZE 32 + +#define OPENFLOW_WILDCARD_NUM_DATA_WORDS_USED 10 + +#define OPENFLOW_WILDCARD_NUM_CMP_WORDS_USED 8 + +// ===== File: lib/verilog/core/utils/xml/device_id_reg.xml ===== + +// Total number of registers +#define DEV_ID_NUM_REGS 32 + +// Number of non string registers +#define DEV_ID_NON_DEV_STR_REGS 7 + +// Device description length (in words, not chars) +#define DEV_ID_DEV_STR_WORD_LEN 25 + +// Device description length (in bytes/chars) +#define DEV_ID_DEV_STR_BYTE_LEN 100 + +// Device description length (in bits) +#define DEV_ID_DEV_STR_BIT_LEN 800 + +// Length of MD5 sum (bits) +#define DEV_ID_MD5SUM_LENGTH 128 + +// MD5 sum of the string "device_id.v" +#define DEV_ID_MD5_VALUE 0x4071736d8a603d2b4d55f62989a73c95 +#define DEV_ID_MD5_VALUE_0 0x4071736d +#define DEV_ID_MD5_VALUE_1 0x8a603d2b +#define DEV_ID_MD5_VALUE_2 0x4d55f629 +#define DEV_ID_MD5_VALUE_3 0x89a73c95 + +// ===== File: projects/openflow_switch/include/header_parser.xml ===== + +#define ETH_TYPE_IP 0x0800 + +#define IP_PROTO_TCP 0x06 + +#define IP_PROTO_UDP 0x11 + +#define IP_PROTO_ICMP 0x01 + +// ===== File: projects/openflow_switch/include/watchdog.xml ===== + +#define WDT_CPCI_REG_CTRL 0x00000008 + +// ===== File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml ===== + +// TX queue disable bit +#define MAC_GRP_TX_QUEUE_DISABLE_BIT_NUM 0 + +// RX queue disable bit +#define MAC_GRP_RX_QUEUE_DISABLE_BIT_NUM 1 + +// Reset MAC bit +#define MAC_GRP_RESET_MAC_BIT_NUM 2 + +// MAC TX queue disable bit +#define MAC_GRP_MAC_DISABLE_TX_BIT_NUM 3 + +// MAC RX queue disable bit +#define MAC_GRP_MAC_DISABLE_RX_BIT_NUM 4 + +// MAC disable jumbo TX bit +#define MAC_GRP_MAC_DIS_JUMBO_TX_BIT_NUM 5 + +// MAC disable jumbo RX bit +#define MAC_GRP_MAC_DIS_JUMBO_RX_BIT_NUM 6 + +// MAC disable crc check disable bit +#define MAC_GRP_MAC_DIS_CRC_CHECK_BIT_NUM 7 + +// MAC disable crc generate bit +#define MAC_GRP_MAC_DIS_CRC_GEN_BIT_NUM 8 + +// ===== File: projects/openflow_switch/include/match_arbiter.xml ===== + +#define OPENFLOW_ENTRY_TRANSP_DST_WIDTH 16 + +#define OPENFLOW_ENTRY_TRANSP_DST_POS 0 + +#define OPENFLOW_ENTRY_TRANSP_SRC_WIDTH 16 + +#define OPENFLOW_ENTRY_TRANSP_SRC_POS 16 + +#define OPENFLOW_ENTRY_IP_PROTO_WIDTH 8 + +#define OPENFLOW_ENTRY_IP_PROTO_POS 32 + +#define OPENFLOW_ENTRY_IP_DST_WIDTH 32 + +#define OPENFLOW_ENTRY_IP_DST_POS 40 + +#define OPENFLOW_ENTRY_IP_SRC_WIDTH 32 + +#define OPENFLOW_ENTRY_IP_SRC_POS 72 + +#define OPENFLOW_ENTRY_ETH_TYPE_WIDTH 16 + +#define OPENFLOW_ENTRY_ETH_TYPE_POS 104 + +#define OPENFLOW_ENTRY_ETH_DST_WIDTH 48 + +#define OPENFLOW_ENTRY_ETH_DST_POS 120 + +#define OPENFLOW_ENTRY_ETH_SRC_WIDTH 48 + +#define OPENFLOW_ENTRY_ETH_SRC_POS 168 + +#define OPENFLOW_ENTRY_SRC_PORT_WIDTH 8 + +#define OPENFLOW_ENTRY_SRC_PORT_POS 216 + +#define OPENFLOW_ENTRY_VLAN_ID_WIDTH 16 + +#define OPENFLOW_ENTRY_VLAN_ID_POS 224 + +#define OPENFLOW_ENTRY_WIDTH 240 + +// The actionfield is composed of a bitmask specifying actions to take and arguments. +#define OPENFLOW_ACTION_WIDTH 320 + +// Ports to forward on +#define OPENFLOW_FORWARD_BITMASK_WIDTH 16 + +#define OPENFLOW_FORWARD_BITMASK_POS 0 + +#define OPENFLOW_NF2_ACTION_FLAG_WIDTH 16 + +#define OPENFLOW_NF2_ACTION_FLAG_POS 16 + +// Vlan ID to be replaced +#define OPENFLOW_SET_VLAN_VID_WIDTH 16 + +#define OPENFLOW_SET_VLAN_VID_POS 32 + +// Vlan priority to be replaced +#define OPENFLOW_SET_VLAN_PCP_WIDTH 8 + +#define OPENFLOW_SET_VLAN_PCP_POS 48 + +// Source MAC address to be replaced +#define OPENFLOW_SET_DL_SRC_WIDTH 48 + +#define OPENFLOW_SET_DL_SRC_POS 56 + +// Destination MAC address to be replaced +#define OPENFLOW_SET_DL_DST_WIDTH 48 + +#define OPENFLOW_SET_DL_DST_POS 104 + +// Source network address to be replaced +#define OPENFLOW_SET_NW_SRC_WIDTH 32 + +#define OPENFLOW_SET_NW_SRC_POS 152 + +// Destination network address to be replaced +#define OPENFLOW_SET_NW_DST_WIDTH 32 + +#define OPENFLOW_SET_NW_DST_POS 184 + +// Source transport port to be replaced +#define OPENFLOW_SET_TP_SRC_WIDTH 16 + +#define OPENFLOW_SET_TP_SRC_POS 216 + +// Destination transport port to be replaced +#define OPENFLOW_SET_TP_DST_WIDTH 16 + +#define OPENFLOW_SET_TP_DST_POS 232 + +// ===== File: projects/openflow_switch/include/exact_match.xml ===== + +#define OPENFLOW_EXACT_ENTRY_PKT_COUNTER_WIDTH 25 + +#define OPENFLOW_EXACT_ENTRY_PKT_COUNTER_POS 0 + +#define OPENFLOW_EXACT_ENTRY_LAST_SEEN_WIDTH 7 + +#define OPENFLOW_EXACT_ENTRY_LAST_SEEN_POS 25 + +#define OPENFLOW_EXACT_ENTRY_BYTE_COUNTER_WIDTH 32 + +#define OPENFLOW_EXACT_ENTRY_BYTE_COUNTER_POS 32 + +#define OPENFLOW_EXACT_ENTRY_HDR_BASE_POS 0x00000000 + +#define OPENFLOW_EXACT_ENTRY_COUNTERS_POS 0x00000008 + +#define OPENFLOW_EXACT_ENTRY_ACTION_BASE_POS 0x0000000a + +// ------------------------------------- +// Modules +// ------------------------------------- + +// Module tags +#define CORE_BASE_ADDR 0x0000000 +#define DEV_ID_BASE_ADDR 0x0400000 +#define MDIO_BASE_ADDR 0x0440000 +#define DMA_BASE_ADDR 0x0500000 +#define MAC_GRP_0_BASE_ADDR 0x0600000 +#define MAC_GRP_1_BASE_ADDR 0x0640000 +#define MAC_GRP_2_BASE_ADDR 0x0680000 +#define MAC_GRP_3_BASE_ADDR 0x06c0000 +#define CPU_QUEUE_0_BASE_ADDR 0x0700000 +#define CPU_QUEUE_1_BASE_ADDR 0x0740000 +#define CPU_QUEUE_2_BASE_ADDR 0x0780000 +#define CPU_QUEUE_3_BASE_ADDR 0x07c0000 +#define SRAM_BASE_ADDR 0x1000000 +#define UDP_BASE_ADDR 0x2000000 +#define OPENFLOW_LOOKUP_BASE_ADDR 0x2000000 +#define IN_ARB_BASE_ADDR 0x2000100 +#define VLAN_REMOVER_BASE_ADDR 0x2000200 +#define OPL_PROCESSOR_BASE_ADDR 0x2000240 +#define HEADER_PARSER_BASE_ADDR 0x2000280 +#define MATCH_ARBITER_BASE_ADDR 0x20002c0 +#define BRAM_OQ_BASE_ADDR 0x2000300 +#define WDT_BASE_ADDR 0x2000400 +#define EXACT_MATCH_BASE_ADDR 0x2000500 +#define OPENFLOW_WILDCARD_LOOKUP_BASE_ADDR 0x2001000 +#define DRAM_BASE_ADDR 0x4000000 + +#define CPU_QUEUE_OFFSET 0x0040000 +#define MAC_GRP_OFFSET 0x0040000 + +/* ========== Registers ========== */ + +// Name: device_id (DEV_ID) +// Description: Device identification +// File: lib/verilog/core/utils/xml/device_id_reg.xml +#define DEV_ID_MD5_0_REG 0x0400000 +#define DEV_ID_MD5_1_REG 0x0400004 +#define DEV_ID_MD5_2_REG 0x0400008 +#define DEV_ID_MD5_3_REG 0x040000c +#define DEV_ID_DEVICE_ID_REG 0x0400010 +#define DEV_ID_REVISION_REG 0x0400014 +#define DEV_ID_CPCI_ID_REG 0x0400018 +#define DEV_ID_DEV_STR_0_REG 0x040001c +#define DEV_ID_DEV_STR_1_REG 0x0400020 +#define DEV_ID_DEV_STR_2_REG 0x0400024 +#define DEV_ID_DEV_STR_3_REG 0x0400028 +#define DEV_ID_DEV_STR_4_REG 0x040002c +#define DEV_ID_DEV_STR_5_REG 0x0400030 +#define DEV_ID_DEV_STR_6_REG 0x0400034 +#define DEV_ID_DEV_STR_7_REG 0x0400038 +#define DEV_ID_DEV_STR_8_REG 0x040003c +#define DEV_ID_DEV_STR_9_REG 0x0400040 +#define DEV_ID_DEV_STR_10_REG 0x0400044 +#define DEV_ID_DEV_STR_11_REG 0x0400048 +#define DEV_ID_DEV_STR_12_REG 0x040004c +#define DEV_ID_DEV_STR_13_REG 0x0400050 +#define DEV_ID_DEV_STR_14_REG 0x0400054 +#define DEV_ID_DEV_STR_15_REG 0x0400058 +#define DEV_ID_DEV_STR_16_REG 0x040005c +#define DEV_ID_DEV_STR_17_REG 0x0400060 +#define DEV_ID_DEV_STR_18_REG 0x0400064 +#define DEV_ID_DEV_STR_19_REG 0x0400068 +#define DEV_ID_DEV_STR_20_REG 0x040006c +#define DEV_ID_DEV_STR_21_REG 0x0400070 +#define DEV_ID_DEV_STR_22_REG 0x0400074 +#define DEV_ID_DEV_STR_23_REG 0x0400078 +#define DEV_ID_DEV_STR_24_REG 0x040007c + +// Name: mdio (MDIO) +// Description: MDIO interface +// File: lib/verilog/core/io/mdio/xml/mdio.xml +#define MDIO_PHY_0_CONTROL_REG 0x0440000 +#define MDIO_PHY_0_STATUS_REG 0x0440004 +#define MDIO_PHY_0_PHY_ID_0_REG 0x0440008 +#define MDIO_PHY_0_PHY_ID_1_REG 0x044000c +#define MDIO_PHY_0_AUTONEGOTIATION_ADVERT_REG 0x0440010 +#define MDIO_PHY_0_AUTONEG_LINK_PARTNER_BASE_PAGE_ABILITY_REG 0x0440014 +#define MDIO_PHY_0_AUTONEG_EXPANSION_REG 0x0440018 +#define MDIO_PHY_0_AUTONEG_NEXT_PAGE_TX_REG 0x044001c +#define MDIO_PHY_0_AUTONEG_LINK_PARTNER_RCVD_NEXT_PAGE_REG 0x0440020 +#define MDIO_PHY_0_MASTER_SLAVE_CTRL_REG 0x0440024 +#define MDIO_PHY_0_MASTER_SLAVE_STATUS_REG 0x0440028 +#define MDIO_PHY_0_PSE_CTRL_REG 0x044002c +#define MDIO_PHY_0_PSE_STATUS_REG 0x0440030 +#define MDIO_PHY_0_MMD_ACCESS_CTRL_REG 0x0440034 +#define MDIO_PHY_0_MMD_ACCESS_STATUS_REG 0x0440038 +#define MDIO_PHY_0_EXTENDED_STATUS_REG 0x044003c +#define MDIO_PHY_1_CONTROL_REG 0x0440080 +#define MDIO_PHY_1_STATUS_REG 0x0440084 +#define MDIO_PHY_1_PHY_ID_0_REG 0x0440088 +#define MDIO_PHY_1_PHY_ID_1_REG 0x044008c +#define MDIO_PHY_1_AUTONEGOTIATION_ADVERT_REG 0x0440090 +#define MDIO_PHY_1_AUTONEG_LINK_PARTNER_BASE_PAGE_ABILITY_REG 0x0440094 +#define MDIO_PHY_1_AUTONEG_EXPANSION_REG 0x0440098 +#define MDIO_PHY_1_AUTONEG_NEXT_PAGE_TX_REG 0x044009c +#define MDIO_PHY_1_AUTONEG_LINK_PARTNER_RCVD_NEXT_PAGE_REG 0x04400a0 +#define MDIO_PHY_1_MASTER_SLAVE_CTRL_REG 0x04400a4 +#define MDIO_PHY_1_MASTER_SLAVE_STATUS_REG 0x04400a8 +#define MDIO_PHY_1_PSE_CTRL_REG 0x04400ac +#define MDIO_PHY_1_PSE_STATUS_REG 0x04400b0 +#define MDIO_PHY_1_MMD_ACCESS_CTRL_REG 0x04400b4 +#define MDIO_PHY_1_MMD_ACCESS_STATUS_REG 0x04400b8 +#define MDIO_PHY_1_EXTENDED_STATUS_REG 0x04400bc +#define MDIO_PHY_2_CONTROL_REG 0x0440100 +#define MDIO_PHY_2_STATUS_REG 0x0440104 +#define MDIO_PHY_2_PHY_ID_0_REG 0x0440108 +#define MDIO_PHY_2_PHY_ID_1_REG 0x044010c +#define MDIO_PHY_2_AUTONEGOTIATION_ADVERT_REG 0x0440110 +#define MDIO_PHY_2_AUTONEG_LINK_PARTNER_BASE_PAGE_ABILITY_REG 0x0440114 +#define MDIO_PHY_2_AUTONEG_EXPANSION_REG 0x0440118 +#define MDIO_PHY_2_AUTONEG_NEXT_PAGE_TX_REG 0x044011c +#define MDIO_PHY_2_AUTONEG_LINK_PARTNER_RCVD_NEXT_PAGE_REG 0x0440120 +#define MDIO_PHY_2_MASTER_SLAVE_CTRL_REG 0x0440124 +#define MDIO_PHY_2_MASTER_SLAVE_STATUS_REG 0x0440128 +#define MDIO_PHY_2_PSE_CTRL_REG 0x044012c +#define MDIO_PHY_2_PSE_STATUS_REG 0x0440130 +#define MDIO_PHY_2_MMD_ACCESS_CTRL_REG 0x0440134 +#define MDIO_PHY_2_MMD_ACCESS_STATUS_REG 0x0440138 +#define MDIO_PHY_2_EXTENDED_STATUS_REG 0x044013c +#define MDIO_PHY_3_CONTROL_REG 0x0440180 +#define MDIO_PHY_3_STATUS_REG 0x0440184 +#define MDIO_PHY_3_PHY_ID_0_REG 0x0440188 +#define MDIO_PHY_3_PHY_ID_1_REG 0x044018c +#define MDIO_PHY_3_AUTONEGOTIATION_ADVERT_REG 0x0440190 +#define MDIO_PHY_3_AUTONEG_LINK_PARTNER_BASE_PAGE_ABILITY_REG 0x0440194 +#define MDIO_PHY_3_AUTONEG_EXPANSION_REG 0x0440198 +#define MDIO_PHY_3_AUTONEG_NEXT_PAGE_TX_REG 0x044019c +#define MDIO_PHY_3_AUTONEG_LINK_PARTNER_RCVD_NEXT_PAGE_REG 0x04401a0 +#define MDIO_PHY_3_MASTER_SLAVE_CTRL_REG 0x04401a4 +#define MDIO_PHY_3_MASTER_SLAVE_STATUS_REG 0x04401a8 +#define MDIO_PHY_3_PSE_CTRL_REG 0x04401ac +#define MDIO_PHY_3_PSE_STATUS_REG 0x04401b0 +#define MDIO_PHY_3_MMD_ACCESS_CTRL_REG 0x04401b4 +#define MDIO_PHY_3_MMD_ACCESS_STATUS_REG 0x04401b8 +#define MDIO_PHY_3_EXTENDED_STATUS_REG 0x04401bc + +#define MDIO_PHY_GROUP_BASE_ADDR 0x0440000 +#define MDIO_PHY_GROUP_INST_OFFSET 0x0000080 + +// Name: dma (DMA) +// Description: DMA transfer module +// File: lib/verilog/core/dma/xml/dma.xml + +// Name: nf2_mac_grp (MAC_GRP_0) +// Description: Ethernet MAC group +// File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml +#define MAC_GRP_0_CONTROL_REG 0x0600000 +#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0600004 +#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_STORED_REG 0x0600008 +#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG 0x060000c +#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG 0x0600010 +#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_DEQUEUED_REG 0x0600014 +#define MAC_GRP_0_RX_QUEUE_NUM_WORDS_PUSHED_REG 0x0600018 +#define MAC_GRP_0_RX_QUEUE_NUM_BYTES_PUSHED_REG 0x060001c +#define MAC_GRP_0_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0600020 +#define MAC_GRP_0_TX_QUEUE_NUM_PKTS_ENQUEUED_REG 0x0600024 +#define MAC_GRP_0_TX_QUEUE_NUM_PKTS_SENT_REG 0x0600028 +#define MAC_GRP_0_TX_QUEUE_NUM_WORDS_PUSHED_REG 0x060002c +#define MAC_GRP_0_TX_QUEUE_NUM_BYTES_PUSHED_REG 0x0600030 + +// Name: nf2_mac_grp (MAC_GRP_1) +// Description: Ethernet MAC group +// File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml +#define MAC_GRP_1_CONTROL_REG 0x0640000 +#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0640004 +#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_STORED_REG 0x0640008 +#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG 0x064000c +#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG 0x0640010 +#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_DEQUEUED_REG 0x0640014 +#define MAC_GRP_1_RX_QUEUE_NUM_WORDS_PUSHED_REG 0x0640018 +#define MAC_GRP_1_RX_QUEUE_NUM_BYTES_PUSHED_REG 0x064001c +#define MAC_GRP_1_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0640020 +#define MAC_GRP_1_TX_QUEUE_NUM_PKTS_ENQUEUED_REG 0x0640024 +#define MAC_GRP_1_TX_QUEUE_NUM_PKTS_SENT_REG 0x0640028 +#define MAC_GRP_1_TX_QUEUE_NUM_WORDS_PUSHED_REG 0x064002c +#define MAC_GRP_1_TX_QUEUE_NUM_BYTES_PUSHED_REG 0x0640030 + +// Name: nf2_mac_grp (MAC_GRP_2) +// Description: Ethernet MAC group +// File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml +#define MAC_GRP_2_CONTROL_REG 0x0680000 +#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0680004 +#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_STORED_REG 0x0680008 +#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG 0x068000c +#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG 0x0680010 +#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_DEQUEUED_REG 0x0680014 +#define MAC_GRP_2_RX_QUEUE_NUM_WORDS_PUSHED_REG 0x0680018 +#define MAC_GRP_2_RX_QUEUE_NUM_BYTES_PUSHED_REG 0x068001c +#define MAC_GRP_2_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0680020 +#define MAC_GRP_2_TX_QUEUE_NUM_PKTS_ENQUEUED_REG 0x0680024 +#define MAC_GRP_2_TX_QUEUE_NUM_PKTS_SENT_REG 0x0680028 +#define MAC_GRP_2_TX_QUEUE_NUM_WORDS_PUSHED_REG 0x068002c +#define MAC_GRP_2_TX_QUEUE_NUM_BYTES_PUSHED_REG 0x0680030 + +// Name: nf2_mac_grp (MAC_GRP_3) +// Description: Ethernet MAC group +// File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml +#define MAC_GRP_3_CONTROL_REG 0x06c0000 +#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x06c0004 +#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_STORED_REG 0x06c0008 +#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG 0x06c000c +#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG 0x06c0010 +#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_DEQUEUED_REG 0x06c0014 +#define MAC_GRP_3_RX_QUEUE_NUM_WORDS_PUSHED_REG 0x06c0018 +#define MAC_GRP_3_RX_QUEUE_NUM_BYTES_PUSHED_REG 0x06c001c +#define MAC_GRP_3_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x06c0020 +#define MAC_GRP_3_TX_QUEUE_NUM_PKTS_ENQUEUED_REG 0x06c0024 +#define MAC_GRP_3_TX_QUEUE_NUM_PKTS_SENT_REG 0x06c0028 +#define MAC_GRP_3_TX_QUEUE_NUM_WORDS_PUSHED_REG 0x06c002c +#define MAC_GRP_3_TX_QUEUE_NUM_BYTES_PUSHED_REG 0x06c0030 + +// Name: cpu_dma_queue (CPU_QUEUE_0) +// Description: CPU DMA queue +// File: lib/verilog/core/io_queues/cpu_dma_queue/xml/cpu_dma_queue.xml + +// Name: cpu_dma_queue (CPU_QUEUE_1) +// Description: CPU DMA queue +// File: lib/verilog/core/io_queues/cpu_dma_queue/xml/cpu_dma_queue.xml + +// Name: cpu_dma_queue (CPU_QUEUE_2) +// Description: CPU DMA queue +// File: lib/verilog/core/io_queues/cpu_dma_queue/xml/cpu_dma_queue.xml + +// Name: cpu_dma_queue (CPU_QUEUE_3) +// Description: CPU DMA queue +// File: lib/verilog/core/io_queues/cpu_dma_queue/xml/cpu_dma_queue.xml + +// Name: SRAM (SRAM) +// Description: SRAM + +// Name: openflow_output_port_lookup (OPENFLOW_LOOKUP) +// Description: Output Port Lookup for OpenFlow hardware datapath +// File: projects/openflow_switch/include/output_port_lookup.xml +#define OPENFLOW_LOOKUP_WILDCARD_MISSES_REG 0x2000000 +#define OPENFLOW_LOOKUP_WILDCARD_HITS_REG 0x2000004 +#define OPENFLOW_LOOKUP_EXACT_MISSES_REG 0x2000008 +#define OPENFLOW_LOOKUP_EXACT_HITS_REG 0x200000c +#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_0_REG 0x2000010 +#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_1_REG 0x2000014 +#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_2_REG 0x2000018 +#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_3_REG 0x200001c +#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_4_REG 0x2000020 +#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_5_REG 0x2000024 +#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_6_REG 0x2000028 +#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_7_REG 0x200002c +#define OPENFLOW_LOOKUP_DUMY_SOFTWARE_0_REG 0x2000030 +#define OPENFLOW_LOOKUP_DUMY_SOFTWARE_1_REG 0x2000034 +#define OPENFLOW_LOOKUP_TIMER_REG 0x2000038 + +// Name: in_arb (IN_ARB) +// Description: Round-robin input arbiter +// File: lib/verilog/core/input_arbiter/rr_input_arbiter/xml/rr_input_arbiter.xml +#define IN_ARB_NUM_PKTS_SENT_REG 0x2000100 +#define IN_ARB_LAST_PKT_WORD_0_HI_REG 0x2000104 +#define IN_ARB_LAST_PKT_WORD_0_LO_REG 0x2000108 +#define IN_ARB_LAST_PKT_CTRL_0_REG 0x200010c +#define IN_ARB_LAST_PKT_WORD_1_HI_REG 0x2000110 +#define IN_ARB_LAST_PKT_WORD_1_LO_REG 0x2000114 +#define IN_ARB_LAST_PKT_CTRL_1_REG 0x2000118 +#define IN_ARB_STATE_REG 0x200011c + +// Name: vlan_remover (VLAN_REMOVER) +// Description: Remove vlan tag and ethtype if ethtype is vlan, and store them into module header +// File: projects/openflow_switch/include/vlan_remover.xml + +// Name: opl_processor (OPL_PROCESSOR) +// Description: opl_processor +// File: projects/openflow_switch/include/opl_processor.xml + +// Name: header_parser (HEADER_PARSER) +// Description: Chop ether/IP/UDP-TCP header into 11 tuples +// File: projects/openflow_switch/include/header_parser.xml + +// Name: match_arbiter (MATCH_ARBITER) +// Description: Arbitration between exact and wildcard lookups results +// File: projects/openflow_switch/include/match_arbiter.xml + +// Name: bram_output_queues (BRAM_OQ) +// Description: BRAM-based output queues +// File: lib/verilog/core/output_queues/bram_output_queues/xml/bram_output_queues.xml +#define BRAM_OQ_DISABLE_QUEUES_REG 0x2000300 +#define BRAM_OQ_QUEUE_0_NUM_PKT_BYTES_RECEIVED_REG 0x2000380 +#define BRAM_OQ_QUEUE_0_NUM_PKTS_RECEIVED_REG 0x2000384 +#define BRAM_OQ_QUEUE_0_NUM_PKTS_DROPPED_REG 0x2000388 +#define BRAM_OQ_QUEUE_0_NUM_WORDS_IN_QUEUE_REG 0x200038c +#define BRAM_OQ_QUEUE_1_NUM_PKT_BYTES_RECEIVED_REG 0x2000390 +#define BRAM_OQ_QUEUE_1_NUM_PKTS_RECEIVED_REG 0x2000394 +#define BRAM_OQ_QUEUE_1_NUM_PKTS_DROPPED_REG 0x2000398 +#define BRAM_OQ_QUEUE_1_NUM_WORDS_IN_QUEUE_REG 0x200039c +#define BRAM_OQ_QUEUE_2_NUM_PKT_BYTES_RECEIVED_REG 0x20003a0 +#define BRAM_OQ_QUEUE_2_NUM_PKTS_RECEIVED_REG 0x20003a4 +#define BRAM_OQ_QUEUE_2_NUM_PKTS_DROPPED_REG 0x20003a8 +#define BRAM_OQ_QUEUE_2_NUM_WORDS_IN_QUEUE_REG 0x20003ac +#define BRAM_OQ_QUEUE_3_NUM_PKT_BYTES_RECEIVED_REG 0x20003b0 +#define BRAM_OQ_QUEUE_3_NUM_PKTS_RECEIVED_REG 0x20003b4 +#define BRAM_OQ_QUEUE_3_NUM_PKTS_DROPPED_REG 0x20003b8 +#define BRAM_OQ_QUEUE_3_NUM_WORDS_IN_QUEUE_REG 0x20003bc +#define BRAM_OQ_QUEUE_4_NUM_PKT_BYTES_RECEIVED_REG 0x20003c0 +#define BRAM_OQ_QUEUE_4_NUM_PKTS_RECEIVED_REG 0x20003c4 +#define BRAM_OQ_QUEUE_4_NUM_PKTS_DROPPED_REG 0x20003c8 +#define BRAM_OQ_QUEUE_4_NUM_WORDS_IN_QUEUE_REG 0x20003cc +#define BRAM_OQ_QUEUE_5_NUM_PKT_BYTES_RECEIVED_REG 0x20003d0 +#define BRAM_OQ_QUEUE_5_NUM_PKTS_RECEIVED_REG 0x20003d4 +#define BRAM_OQ_QUEUE_5_NUM_PKTS_DROPPED_REG 0x20003d8 +#define BRAM_OQ_QUEUE_5_NUM_WORDS_IN_QUEUE_REG 0x20003dc +#define BRAM_OQ_QUEUE_6_NUM_PKT_BYTES_RECEIVED_REG 0x20003e0 +#define BRAM_OQ_QUEUE_6_NUM_PKTS_RECEIVED_REG 0x20003e4 +#define BRAM_OQ_QUEUE_6_NUM_PKTS_DROPPED_REG 0x20003e8 +#define BRAM_OQ_QUEUE_6_NUM_WORDS_IN_QUEUE_REG 0x20003ec +#define BRAM_OQ_QUEUE_7_NUM_PKT_BYTES_RECEIVED_REG 0x20003f0 +#define BRAM_OQ_QUEUE_7_NUM_PKTS_RECEIVED_REG 0x20003f4 +#define BRAM_OQ_QUEUE_7_NUM_PKTS_DROPPED_REG 0x20003f8 +#define BRAM_OQ_QUEUE_7_NUM_WORDS_IN_QUEUE_REG 0x20003fc + +#define BRAM_OQ_QUEUE_GROUP_BASE_ADDR 0x2000380 +#define BRAM_OQ_QUEUE_GROUP_INST_OFFSET 0x0000010 + +// Name: watchdog (WDT) +// Description: Watchdog timer +// File: projects/openflow_switch/include/watchdog.xml +#define WDT_ENABLE_FLG_REG 0x2000400 +#define WDT_COUNTER_REG 0x2000404 + +// Name: exact_match (EXACT_MATCH) +// Description: exact match lookup +// File: projects/openflow_switch/include/exact_match.xml + +// Name: wildcard_match (OPENFLOW_WILDCARD_LOOKUP) +// Description: wildcard match lookup +// File: projects/openflow_switch/include/wildcard_match.xml +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_0_REG 0x2001000 +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_1_REG 0x2001004 +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_2_REG 0x2001008 +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_3_REG 0x200100c +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_4_REG 0x2001010 +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_5_REG 0x2001014 +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_6_REG 0x2001018 +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_7_REG 0x200101c +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_8_REG 0x2001020 +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_9_REG 0x2001024 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_0_REG 0x2001028 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_1_REG 0x200102c +#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_2_REG 0x2001030 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_3_REG 0x2001034 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_4_REG 0x2001038 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_5_REG 0x200103c +#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_6_REG 0x2001040 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_7_REG 0x2001044 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_0_REG 0x2001048 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_1_REG 0x200104c +#define OPENFLOW_WILDCARD_LOOKUP_CMP_2_REG 0x2001050 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_3_REG 0x2001054 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_4_REG 0x2001058 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_5_REG 0x200105c +#define OPENFLOW_WILDCARD_LOOKUP_CMP_6_REG 0x2001060 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_7_REG 0x2001064 +#define OPENFLOW_WILDCARD_LOOKUP_READ_ADDR_REG 0x2001068 +#define OPENFLOW_WILDCARD_LOOKUP_WRITE_ADDR_REG 0x200106c +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG 0x2001070 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_1_REG 0x2001074 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_2_REG 0x2001078 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_3_REG 0x200107c +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_4_REG 0x2001080 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_5_REG 0x2001084 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_6_REG 0x2001088 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_7_REG 0x200108c +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_8_REG 0x2001090 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_9_REG 0x2001094 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_10_REG 0x2001098 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_11_REG 0x200109c +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_12_REG 0x20010a0 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_13_REG 0x20010a4 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_14_REG 0x20010a8 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_15_REG 0x20010ac +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_16_REG 0x20010b0 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_17_REG 0x20010b4 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_18_REG 0x20010b8 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_19_REG 0x20010bc +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_20_REG 0x20010c0 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_21_REG 0x20010c4 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_22_REG 0x20010c8 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_23_REG 0x20010cc +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_24_REG 0x20010d0 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_25_REG 0x20010d4 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_26_REG 0x20010d8 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_27_REG 0x20010dc +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_28_REG 0x20010e0 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_29_REG 0x20010e4 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_30_REG 0x20010e8 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_31_REG 0x20010ec +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG 0x20010f0 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_1_REG 0x20010f4 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_2_REG 0x20010f8 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_3_REG 0x20010fc +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_4_REG 0x2001100 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_5_REG 0x2001104 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_6_REG 0x2001108 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_7_REG 0x200110c +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_8_REG 0x2001110 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_9_REG 0x2001114 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_10_REG 0x2001118 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_11_REG 0x200111c +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_12_REG 0x2001120 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_13_REG 0x2001124 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_14_REG 0x2001128 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_15_REG 0x200112c +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_16_REG 0x2001130 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_17_REG 0x2001134 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_18_REG 0x2001138 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_19_REG 0x200113c +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_20_REG 0x2001140 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_21_REG 0x2001144 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_22_REG 0x2001148 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_23_REG 0x200114c +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_24_REG 0x2001150 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_25_REG 0x2001154 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_26_REG 0x2001158 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_27_REG 0x200115c +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_28_REG 0x2001160 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_29_REG 0x2001164 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_30_REG 0x2001168 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_31_REG 0x200116c +#define OPENFLOW_WILDCARD_LOOKUP_DUMMY_1_REG 0x2001170 +#define OPENFLOW_WILDCARD_LOOKUP_DUMMY_2_REG 0x2001174 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_0_REG 0x2001178 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_1_REG 0x200117c +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_2_REG 0x2001180 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_3_REG 0x2001184 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_4_REG 0x2001188 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_5_REG 0x200118c +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_6_REG 0x2001190 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_7_REG 0x2001194 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_8_REG 0x2001198 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_9_REG 0x200119c +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_10_REG 0x20011a0 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_11_REG 0x20011a4 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_12_REG 0x20011a8 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_13_REG 0x20011ac +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_14_REG 0x20011b0 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_15_REG 0x20011b4 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_16_REG 0x20011b8 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_17_REG 0x20011bc +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_18_REG 0x20011c0 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_19_REG 0x20011c4 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_20_REG 0x20011c8 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_21_REG 0x20011cc +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_22_REG 0x20011d0 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_23_REG 0x20011d4 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_24_REG 0x20011d8 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_25_REG 0x20011dc +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_26_REG 0x20011e0 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_27_REG 0x20011e4 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_28_REG 0x20011e8 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_29_REG 0x20011ec +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_30_REG 0x20011f0 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_31_REG 0x20011f4 + +// Name: DRAM (DRAM) +// Description: DRAM + +#endif diff --git a/openflow/datapath/hwtable_nf2/openflow_switch.bit b/openflow/datapath/hwtable_nf2/openflow_switch.bit new file mode 100644 index 0000000000000000000000000000000000000000..3d9c2a02601d2f5e12a6193d80a8bb32d474a7c4 GIT binary patch literal 2377746 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
+I`scXbnae`!KJ-bQ5`)T*Fh^p81rUWyHrL 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 %|t=Z|^S1cZ-aOS3;oaSM-1 zI6E=KU_HB_D5vGvsvVR- z&jh)Vb7^8s4^tL=&J*de4>4M&ee}S)-75!FDuKd3%0WfaW-cP*CFsMOD;jE0iqhraTtRVA9)gX(i+XvnS)1S<*>D+zRX|ev+LXWNz=y zvUVqBE`DBd)S^MF*21%_wAW~fV)Xdrb>CoB^TD%o-wjVx*6y?X8KT%ODFwM)xRX=XQC-JRVj4j(4^m4E8X=!a#<7-}{yvE!4TbzFD9t_)QQeKo{`(X4wIgF6kj?brP zLPyC(@QW8?ys5Wzi=%QQ&>F_hvq%{e3M+cDX=#AzuR?KF$Bv)q@45(zzuNVpY5E`7x*wKFiz_%jz; z4kjB|GUnqnIqkZ8Cu;{qc(XDw;sq-D;w(^RC$9yGYmuj7Ux)of7edHV%>Gf1=IPRa(-IQclV!{nBP`CPlxU`>Mzq z(%9CKCd4XYrA*~XrxRy-oN}NZb_YAse?xe$@J%0OaCRW^)zYc_B$MTk_XA;xy)anY z+xBK6hv{HDaOzt+-WFuGxv>FN;k7=5$*M_Ydt4wxDG`hSvQE)w)fy@#h!ES^>wd}}?WNRNIP&+KilW#ru1 zaB-bZ$!zDXQtt1jC_RS3;q0vsma=%VJ&NK+rJp1d5}t91!sJov(0rbZg{XX1PHON< zw!Z21FGqcmQ^U&3bX0zOZPtpK-R=Ei)O~VRYCL$AgjD9;pz2jm5B+wergn5tNJD8! zxnVgg&@osA@o5!Ru-@pN z-@B%Gm*>v)i+6G zh+?l%cJAC+KSk`Gafy8iYdnKx`9zBgdei7tDCy&2Fu{(u))nQT1H~e6)+@D_mYAKB&N9|)w^yCIL z$Dr3{NH7ankWoCecN$Kf z*_NFUJuiig3%X;ngGJ9+tx#MONgGZhAI=kpK;#oC%?U`-TBEV82(BT;hY{N zMjib0q^ER$H1}?)t+VHsq(j@f!7>H1bLyd4i>-^Yhz|3Kag{kI}7|38s98uR$$ym$7K z#cw?ocjWesYiGCj%K6#ozgRpdyS?T^INV`i9n5m5VY-#@MMnOnom5}eXsd&n-DXjb zR&>q(U?Akzh&VKxBUs}*59PSAKF^H^d^&-~$*9+5ZlG+|DQGU)HKz)jn`p|nze?TD z_l41I&G?%6--$-IHs=V|apMhlvA&b-AJ)9qaQJzPeT`qmeM8HZRxSkHcbQz`4#v;& zu?}8|TTJMurjQ~1kWq&%&Lrp>$(48tOK#^)VOD8# zei5uh!YAf7F!mM(Z|meT6Z|C51A)71bCWrCVImTlc=cAMs#JHZ!O;3?UQTx8 z6l?QlzRIP+dcKKOtE!6cT0=Sk4!_|{PU~=1Ip@|morVeeMdly^)x>*d%`CG06lFzj zW|p}Xn@S5IhP;4_mQX}Hw^Q+Y#K(YWWxhY~&KRAL%;UI#5oWX%m6O2IB34o@s&V`O7~bfRjBQ;%1aRqcz(U>gsP zdaM;wC@>eGF{&h7m}I{-9(hD)7c7df_IjIgvSJ9O9g_)b$tKr34Dq~8aVEA0_dL*>g+0%twPy68M{vDRf^^A98`hhsEU4Mzzx zGuox8GFFkn63i@AA&zKs@2P11KV93e+koPMJ>o@kfpx&Cnn4by?B44biAnM)a3s+t zjt+^JN~X2a6|5{#bOLhbjE1gi7qJB&(QKBP!=AM}w ziw!6_TF(~l5q+%)GCit5`6Q!?jU~vuj88JB0-rX%e9fvf-^`p;>-Mwvg^&YmqMw76L1u& za$FN-y9?A)Jc>F}n7mIs|MxUo3uegOY!mP)ZM;>>5=PQ217!%+SQnwlB62$;><0+( z%y%J+Y+47_=2V~?k43CEf%;mp{si)#pe;Vv8;n+(oaJydH@8spDL*gV5OVz_ASO#m z-ovqoP3MlsDoxd0Ya*7WVtgV##Rm-eF;6hn4Xm8_YN73oOH&dlY$3+oLlu!bDu{ca zPLpxzo*2=iAQ35LN|QoD!s$nWLempeFhG_$ZvUu7AP^AE$up;4$7$ANg|&0 z-U3Hiz!<{9d99O~?YL@sF=Pc%t7|u3EQO@(-8j1O*vdA8q6rqzR#&AiBRJc&FZ0?z zu^=Qu^LVu#6^0bz!(`eMzqSYdffb93^24B@_>J<=$8JY4LIopvk;Ta{KI)Z5i5UP> z%q4D~o-QFj=#__GlGTVIjL-|@r6W9J?hBb|A|r-$+wy>-QA{g^SnM+HK4afC?dfvM zGZ`UZq{NXs|LU!`?Mnj_nk{pvin!H&ZZJhGM=)#^k+=|8dbLy$BL|T?WUNv|P3m&^D1!R!X?iGQV z-*OLbh3zXN9kTT@#8$-MK^gCl#Ch!=^ad=_d6f9zg_j>Hc3+zFBzap7gLYUPtA7SF z9#0>tFGmP_=`l9MwzW4Zl%#_J9LCQyWg>@hOIyRa8)6BHiW=|?ZpP(j*~vY46zdr1 zL#A_k^-=gzZDBg`KB|k}-Z|U%6vf8}Kc_p-ig)b}cgL^C-s%cgj-H`jUWj}ccJ=aB zZ}!-D@N;nzZt3Cp!hp7ruJo2nGr!up9KXRUH)eCd zUl8AeI=zlTnH_y-=2y06(rC{c+&f}j3ck)ev{^n-yq=WY$u%B6EMrH>XR)Iz|Fqph zANuKxSWOZ;D`;eY65IQF`IRV`glto|po7$##e^a(9#F;8>=s+S^cWwr-G%u@nUe`z zbmDBbTuxOMkFLV9mqMaSRx-JiW*w%e`0n**wbf=Mbg~ZPZYD=*bXNz`| zfk8!Pej(`*N5h#2**Ar@61SMAS~`1|HW0QU@`26Vv_PPdL;)_+hq%x)LzL&-1L!5n zMR}))5$@0URoiz36HZ%?zGB1R7Kskz0n@e2dD?D|3ff6t>kZ_3>J+<|lry*8VRWnQ zp+*xD<|rbOfs>2j>a~?(bVrJ`4BRM8Gl^og_5?zaI4quG@@~e~Gi$W(cT2vQ(v5=jgYIrOJ_bLlTzS%~%PHg?X%sh6 zM_L@Dp$1Lj{jj6b?G3%;o@-NC&v%D{(bDKU4H^=;MSl7ig7|@ofA8v0qL-CM*v8lm zEgf~@R&3j@1d>IR>PZ67Fgji;dnuhH!oTJvi0@b|Zn?izbcR9XG>A@ciX!{YTRT6^ z*z4snjUkCbfh=rhl<}a^iXB+3q}h*t6)7o2dfe{3Q%!Fnd;%Fs-!o(rM4`~{{GiXUILhD>#ppYU9^Dx)w=si`KTaHIRs&y9~-qO8fGpc2?2@cfRd913Az0osJ(q9+57>>caWX z>DV1dbQgy=!)Vy<3_CjXZr$$)3!^9<+FTe>0j?3f3SxAkcrQStQf#Q>S2B}~@p7(2 zxe(k>*^Wp_`T5I4!sw0B;hdP+23s46tu+ba#x4!tm6fH%-tY_U{j%A7 z;Ry#D+bJEO!eUxDd54Ka+*mv&2EIqJJb8d!c?@^0I z(-gK_3_eV>BoP{0n_6gM^bY%M2h&q!^KjS8d3l(Xo@1F!4YQM5N}mo$`K)vzVVy50 z9F{B_u!`lEGHE2RO)KZWunQjb?3XA$T8W5?=cdJAY^eYnzq6;#tiqXV4G}Jy=}2gp zgp(@HnZoEc;3bGX6f(LETK%Ncc@>Cc&Wzw9pl{ME$?F0nN!(*G zb{VEN`jqg@243Z|;VgOFY(B-AR9TSh<*6^c66FW7vlmn*P#Roon+VA=ryDnDnQGD| zR_K^npuRo%t8i$@)zcD`ngv8(_`4sR9EmO|0k-}w&^m&PIawahWiTg)!NPmn5I4rDs@*e z3?pQ7VgyJzje@Oe&EhRYb3)4ols`8BE=e^H4b32J;xz$&fMg!A>|BG70SduMN47)S^bF+ zs_7eGGf8d3gcwQnFSEh_BY})ff2n0kD}7}8ud=fo=;}xYiRM1|2_{xvift;&z=iEJ zyn7juhtVvE#TJRCSJ5sq^(P(Dq)my4TW`2#%@~6X0=cY}M-t?G@F;&|%ecoOJnB89 zu}pGX@$$K#OVmRzcN8$llmjo(@)~jDR8B})`2AkljR6)0Jm7I>rnSh5|Q)I*X)>zOdk&g z4jt~B@%O49=E$5l;_Zxaa;wO?%aObsYW&_D%HuYpMB~ni71XZb^I8${%xiU%5a}lV zYCZ%DwYLaMVPKr|$j6nXnbq_Ol|*Bc_*=4&?s64LBUs`qB#xrWn>#FtTqGj69VBmC z+%AvgM$xV0)^*etSFD*j#kF0BVn$GElmV-NX0f~>%v#oodV7NyL?Yh6gUaY4;v3hl zi%Y(li?1y@cMK{C|1gJfpkYm6cO?VF-pS?h15#OO`2M3N^B8z5U98$cg)uC2IiA_l ze35}bBfcYWA0Bys*y9k{IB*eBb85eNtf&@w0&P7sn;B{Er|P+oviVB=T27E`sSxap|JxvMl1W!Z2ni#JA4MgHL8{ECV2pe^Hsc9Umo!g!@yyut!)1$U?(_7>gjvTD#?20R%Lf%+3(3p`ccIjQq$^ z(IknWu6dFiiVVzl=*AKpgF~7O^(FfsPWh6ZtdYG6k*$JdEWTv->q`rnO|$Idpyshz zvFxMst9r!JxTGoqOwc z^L44P^QxzZXlj}GR!xyA5=30Xp{()l1UgkLQq5U9?xAN^jNk=p#v_GP3}+YKSU~)N zw`z(+ljbg(v_jCverV28!7L$!8|;2C;t#5s(b}{yh`a^@7(wJ+IF17dg3Op9?4>1l ze&@bd-8~fTc#$(x_nmw1x#ym9?%#Lcd#5v&1DKkzspBxs$d3@`Xb!SkHJ2s(!`yU; zT5TT>RCGtiQ986V8xZ6Rlo_i6E49S#$jJ9wKlOX&@GS?GV~7L)Z=?TazH}A=HhInb zVtjn?!XJO}wJ#Bvn~X_rx4Ic~^HgTaw#tFEn~7wN!qr-^YWO-MUuxUud`tqdHEkje zxW$2=xX}@D(c@<2{iAkfF@d&bYQ;VlewVTEQSs+ zdBy+E>(A|*>nFUWeeG-i&ivrC+x~gH;VfM+WvuaSdHXh=*1nB{oMlG)H}R#`{tnKf zK69GgN6x@^)NlL-#O6y4-(q-kd;7b&!kqiu7oci?-~V6LeM(OI=kJr2F?>S(p!K=W z6+ak!?sIU4%WwR~`#;nC&0qQF@B1H~`t+v@tF3r{@xiB?fAqm;k2P<%{_npi_Mds@ zw14kA2O7#d@5ncPn5+ECT{vjNOWSoh`3@K!+05r!_Q-^rtoFZc-u@%p1?_+M;fKxr zAL4@To&B%iAE{m`RonpK?YHe&#g%o_XFs|KA;^WiEAD@N+89FFDgtIm7&o{rkEE{-kn=L#0iR zWr;egx_tf_|MnjqrnnzU<1i-2KHJ>i`OIhh{$6I)*!SQ4?nRuP-TusH5b_vRzP++v zH01N2_uu>8XFk*X-uG|}^#i;mVZZ(TLw9Q*ag=lzo#1BaJ^Vjq$56EsD7-^~W&cm+ z9jYn&l>@1L`ToDpVr2I1i%1~P$cOJXjuDWSWMzf<{!^baUwO{l!F{FqHa^_&(gx-J z{>5XsYCCPg_AkN;27lV!{zY=}+-9cB_WLVkKJ>$eU#D8Zsu%CSjZ3TAuiJvwIJW;h zyY>D3FPjYxRsAcm$?e-mOkSa>x_pDa^%oia2K}w-oD5QH@+QV`vcL2~b8GUH^V?V}7W4L|qdpU#XcfZ@%$1@ta-~BFL+J12R^Pi_+vh&# z|9t1r*vGuQw|His47{}Aa}6JT^hsvf#`{J0Pw5fAxZU~(jNI%{QT})T_Fm(3@uBR0 z0|#xnzr6o`vBNTfkQBSUPqg(vg8eJF99r$KG$*4pi%SV(a9HB6#IQX_P^otGp9|x! zEnn*(FZ78uxVp>BYh+o!>aF&SkwB_|Jz3tD4pjx4KJO-v^zPusfbwv;V;E7Hl4NR$xcnDFi7NQn{lNP?eCE7 za7tZOR_x}pBzl4shqV1hwjqz+En&C4CdC^BIXl;ovk?u(nS}`hRF*vSw0ws%wqF?i zLhXlbVzku55z*+7xZ0e~mpk%1_NtTLk+1JIe@FI2epdcrWv^&sPV)}iZas(iCF}8w zdSm8dGR!T0&rKv_=@0N8ma)~}&UNSDzm_`f4+LQ-!Hw}yDsNS-YZ8+)F4{aSK`X>e zcTG+$a<2HLUotnl6*Ip^`0b^CH5;3$E>X+p?wUO&FXgn=*J>Yg?q4s)d>&$)Tg|0L zs|ULME&1t6H+SV%mR!O$edMJqLAg4K8RK!}u>VrL51B)^rjv~2v>P)^qYC%w-;$Wy z%Wl(8R$3-cP7R;vRaSGe?Mf=&YL079b*r+pbPY`5oj!lI`LJH*9OUgzY>lEOMZ?)*ocbNJ2Jp+Zbw&P< z13zq^nB*Qo?(ll{eVt%wZ;}EbI16(`4W?VVl7RQgd0ojuC#2+@OxT$ zzT+Dd>qC(FmE`K4xce=sdy{yH#@v2O`)$ZSsyqzx=mFKOEU@ece@ljOZnC)7Z(_f! zdC%&wH2=*vw`m!Zv}|2E&;zSkE}z3m%vJ+mTG9`fSlo8Y-Wir9ZW>)K`#@Y`XRJg{ zOFuP~oespbV7%)eLJMwBk`AB?W~Z;L0Y6*&qvCM8$!ij%@q4k(<&~NPFa}nly2Z=M z&dM4@{*1Gg!(K;fVe6N3c?}1|$|`5mb=sv`0yn0PI*l=0VGeG&Hn(vt)oJ0fVJ06F zUd2~pU2s{hN?y{<#+GjNUU^Llt>lZw!G579GIAj94CbjgcMY>Nu`~M0b6a(QZ(MSE zE~}ji&!JXjcP~X2>kPrJR>x~gOUhL^S2mDXTi5koTiQ>e^d!^C5E!3namS@B!2{G=qw+}#i-8X4UlEp=BUPA+*o2S*L}l?E6!{fDvURz z57KrHFf}a=`q>7C75efrtySxmPu(jzn?-5~OwBC4vPM>t?ppCI)iqKoscwK(WsT|( zxYsA*Ke&7}t;J;lqxME4u#nlCuqfs*Z|F=6Rrb_(wHo&#O2!KUrGC z-a}U}vk8Lx%}eSqh=nk3kUvjS@&)eQ7sxtp=<7OtwEPasI;r2cDx@YJ=?5QXj=zenmO3cIV9rrBiI*K3z9@( z6Kp$dtL6YIyk;I{42cP~V+4lW2|4A}JJarnRW`AaV340S)%iXtSgNcNqG1WC9Dgqs zB^bE;uiN7R9;qRF;tU@z2b8jh&xgWL@(>`57E7k9U4(54S}43d2|-?EQ$AK+1hvTl zT;WvgkVRjk0{&(x?@d^J0lI|bk;dc2L`y3@VOCSRXdimkyf`>+B53>~i& zY6zEHycX;oM>j(`s@;Hj(e0ZI(36lwvS$yLlG7^0LK7_;&E%j+r2E>8kC>DNko*4! z#6)40EDMz>(#WtRplgaw5?7>ZqwW<;%Zi7p;wsMfL3w(rW0@qr5nS5dJ&%_>_(gxkn;l;a zT*e#OW-MIndm7lL{hk%MLJ0*kagCM1WHYp>=tZ*l&;0^f!?ih^h7B#JZMm=XyZ01+ zXWL%ev?&SA-*PFItJnxdNeSGGq+Hk-93b$v_!1%+Dc{*uDfeg>WK{_;w$c~niXB)( z=90);mKNZVc+)Cl5N7CVzQoE9kXS!1u9%j{aT zUn!Ah-F-Gm9wj#B)Ug9A*z=;8H9QtqUdFbvyJnK4m95FL$~azF)%g{9)E(!qNN;bA zf0v%N>URBRS9CAE)Rf(IwprGKvdsps`D7W^dQp2b{_OWE<8UpA>OH~5$>I z$qegR1Nh4nL_mW|-;9=+2qX_g3wq9v{AS;X+$dB0M+M_NlIjs$y$hOCl5|^f6@NW& z%k^~^>|hYP=n+u1Y!-7K+X!(?pNkKe{Ei5XcIkegip&aCBmkL-;B8IWD zy+uti2w;ma5T){0i`bn;IUSJOoPAY%Tb}lgBa)ECECiUHf!n(nv;viAvga{n68KdF zU!x-@d-FE9Kpzz5LFd=Ht2kNfu5l{n&B2}W?_(g4%6+8AB!h^tL>_sFAo3f@7CAZX z>aCyHjB{)u@ACLv`QMkujgvQ27Q17S^vx)jpQQ#Zsb!Zh6HS*=(!25`t;>Rr^Lvci zK`(X#~ZWayO#%(YP5KtxYpU)YUkH=UvU$=n?=xp}- zEh?AiWH_5`2zX*Omle^fqa!Jr64t;&Ar2Aoh{RSB(m5{hwvu!rOZxQcqSq6Dy5;B} zE!30NX@bG-6+D%-uFAmt#4K*z=FW<7G`+%$x_37oF$!auuvb_5m*lESfY7Qu9S9n5 zDrjg^VLA(ymobxhAT!w*Ankm$p-~)N-bzJU*xi3pUTHu3s~tJ{21{Xt&tB{Zo7Cyz zVV}ObkdSENEz^-A*s*~!!r&5Y7UOwMrTlYUtUu8lZyi4#-dL=z-lF5L&HdVB){Q@* zE~ZPyv5@0$PqrG1twC~&W@z{q$I^GRmcP+(-(+Y>Fdcv-sfiHrQgj2cJfFadbv}E<6gAuG5DU0GJW7x@=dznzy?g=AVJmD5oxtdfPzvGmFK^MHrdL)lBuG~xG z^?~OP$xkGtr_S(g>eC24naA$#{2>`6{X6^|t-#PIcr}#zW-=?hdug3_ts`wDYpgFL zCCKn1A9u+EB9Ef90X-=l?{vI>GWn@uZ|*4KRCV>W)^MxEXIrgz&#YkUL3(3dUc*b0 zJVevoe3!dI|IP76_n{uc{OaVoJhA5dmX2R4d0jH{d1pCoicR9!og4GAKf4|$FU9LI zg@-?Vc`dfKE_DN6y>e!M$_{29awon2q?-nbVb+ivj*lr`PSJW;Iy-9(`_Dahi%(6S zJN^3E*Uz>#Ht6nW`>)Hb{>D(w%0p*|w>SDs5eb#h^k+>q(HxpXE@siS>Ud&EeqJZH z%vSmY!7UmL-+k;RbJqZstH)))mhhI`Be!g9o~>r;k{)V3q7fND(oo|N38aiy8Bq)C zPnC~P>j6tZ9yx7NVLY1*3~a&@^`{m$JUMY;Z{ssfj25ZNrpql1i_yfCh5C-N5=crm z{wT86;F|NuR;xHAi%!}x?RI)HYER#o^CjOrzzV_?YsDdoE%QQT)X^<`G@nRkN7gB6 zdcr`4=0Rp`rwgK7)zXeYr3d508+&J;egU^ExQ)Oz4sD!rL&IH(TIPaZWyjhE7Ek;u z4FMoZ#?B~hhQlrml?ZYOwg%3v(pB~Vw$cn3pQuPLjKWm#u7iO&FVXz}u;39)OK1CV zStJw78nl$lRNor(%9xZSe-lMKbr0YGgH<8${pB5I7Epf%;l0vVq$0^U2XMYlOBh3o!?}UT3^*-6nb{+3*9Ncc1Cul z#=LLl?PQ2_Au^Q#U$ZtMg%vt3H0Z3)B-%lnbrRnLfln^R zCGtB0g}hSAqsh?`qa_>l0&T*h9Q9f?*@s_)(OAlB!D(fj1&txCg&B%j0;*TzV$(}` zn$-@~Nr|SQ>GaTG_1*#IBx*gz*$J$Z#=Ena!S1tLrN4S>z!%#j zm1lbrqa0sbl!L*#CMY$?C6#FN0i7q>zBGfkX34-s>FyJ?2UxuM%&X;F6hth~Wa?2W`afT9DK?Uxe;n)mr-WTg(t|g1N<2liI4Y$gCj&TKIPe#qK@TbcKF{` z@d|r**sVOfPuE^e4P?zz5glquLHxEhaMzLes!&XxIqL6H;1KQ}Jp8MRTx}6rV&}yY z&)oCyOINw^qG8sfjD)I7cb3X-yq0K(q7M=071He@^OMY-QF<>X{3g@-6CsUxz`U>F z85nCUs{2gJFke_nf;FxN#cIQktrulWt_pR|EK(WPd}jCX|5>jk(1AwUvgkkDwF;o^ z;KNSXL?R|Y!iKc&A0}`DH^Bx9KIo%-oNq3K2O_)3q_T)iYcWRp2Y*zAjD-xe8`fv^ zg`$}Gon5x~2;4Xssf919k=vE6!fDE_86(ScDKpl?As;cytUnyE+z%OieHKmInaZ%w zKs22hrg@kcUL6J^&yT<|jiwdMe2~AWu)#q>Mh^4q^th4RkvfvK4^rD2V)Z9u_z|Fq zJ{E@6!rO@CS_eA3)`F#mB7kLn)=)BsTL?k?A4m=SPO!p)my#T3Q$4fDBnTctB_VH(7$A*ZVe zMm!fHnfPA=M{{jcu0_n$iLk=90^@WE`6)i%mRg^&>XF(mRtZ*=-Bp801U#f_;&XTx9K5|VK&mBDL5G|T4 z7+7H4CnH>w@kk&BmZ%HUZm?sz<-%roq%97pjIsvfWcP=_L9ocI)zX#__?*m6r&1z? zpYsbe%9Ejy1n@zN$;@gI?!l~Xs=NbgS;$DFN6X74jMj=-A%~^Xkc+13*8lBS6LjSR7!7$o&~b&5B*N0petvE>+2KOH+Qyl!#`93YOO@mT$1K zRyKX`Gagzi3TmSuvm@;zkSxx;ZV>rpGK+j1u&M$m7os7WX8>-@SYuUonfq-Mq-NhG zVRimZYObM(m0^^GR5imgi)#(GmehJ?YS#Q@2?Qphsb*iVS`D>UwfL5guD0bQtHb_7 zA&o?=Ocfv;*`!4#0=qJLrnx$AS53!r5pCoI zOFKKXESbGNT-?eSfvYyJRaD_~2#NKJ-bbxA#cZ#tY;3uNn0Y0IvXt=%@?iJVcNe=^ z0yR_c!jbe8+r|KY9H`O^!S&?6uQ98{azoL76IIIIST_vhEXDj*1)ZioUy@x{EyjDYlGp&r_&&r^-hK)k zS@FC{6&su{(*|}4x}NX$HeL4hAuCvgLg+G7O2gGmfCq>ufZ3Dov(k-MiWL-|l;iEk z%1ayL;RYUjpAA>MJiGTeKIC-7)?q$JuPY~lhM2}HZls7G607Dk+>g&L*j`b1`mu)X zwQ@f4>Xp{AZIkD+QatvSu+>YOe%_JCFEDYJk3G)G-s+Z|D~fJ)IWz;z*g>AVs+#a3hQDLcZE8$W&l%3*k)v&h5@om*#$$c+jX2zT zqR{j6w`66qrNg}o+1c*oEhOS2q_t6jD_z7|#Q&&$KU)Ka~=K^L$WK znbr{0dhRMNIojD_n{euD}W|$!Sn{%nda-s@zjHd%E#*(e6+`=V*Z)>6C5Bx%ozV(Rvjn zSLs4Lc*NFWm5zH6qUJbW(DCXy{sKgNZNB!xV_`3dJTUKW^~%ZQg~S->7cU4j?d>ZP zRrq{X)1DKJa^Bt%UfCsxB z@e`RCn;4xu@U>^h*12Rdx^kH#Df-V?9}gI<+zG7p39>7)5~Ik9d5j`VwrCe$6W4=> z`1>}TOu}4PcogaEn2cW1rFX5SW`~Wfjiwj$G35YRg;%*mw&mPtZ#XJK)G(TCO}C#A z$Nn2{KaR3#Z)MuP46C`M#Nbb425Pb`h3q8~+e`=69?f3K7o`{cI1an>(( z#^Sq}WW}qdqGW2Dnn`WO96964&48I;YwSZxyItfgcOye0X>{`CqTJ!t)iFEXvixL( zPujM1DMplBxeq=anuEdc!i1W6$Dv5P`W2=kk@1d{C3izHn?u&Qo6s_jZQy8BILxBr z1`2bOP|C|DmX`U?OLjn!je1h?W?p@`_wI>y-;|j8x<~zJIJ+*dUb%AL{bhN*CmZz6 z!u3PgiTBMp`xlwI`1Gad?q=-ozQm($?%thpC!Az`r8l{t|6=k$cgAxmbxyk2;4NDi z@0$c>zCtE0ZqkAK&&k+Dw)@h)`{Njul>mMh~gZ%cpXl!kfYsl)@9$L&0Yze88r9Gm#4d2~r-bGjPJVCu5n3h5d~ zpk5k@8~2f$b%#BVWo9YN_#k**>QE$15NSBN(peqG@L1nXLX_=Jw;MM*vDcT^uJ{L6 zFN-niJ^QMQ556G1Usqk3kIfC+uQvm42(bRN3r|h=*iE|`B^FmMb-B^pDfy#P8t&dm zI7`1IVTUgD#dWzpnMAsni0|8rJeUel>*AVGJ5N*7qK3#d7Li-==;FADkL`&cJsddK zwf#|_`_&}joaYaKbg?c)nS#1IBC~rF-$wVL^4m<)QLVtx$5!Zi2EXXJ<|4RWWZ7x@ zrjOEW4vfSL&cL`b;(9vjh7po=#U{37#e6r0Zs?^cW>(essGih>MCFAP`d#{z7CH<} zTMcEz#L+`SZ}Y+941vFh*BsHnG>28RKC?x`zETW!BH*v<6bz&aDjxvhIgXV%* z!brE^=b5n^_>Vdxl#UDy8FLxPVPdl>3cYj zdvM&9==JM;9QDcOg@k;62O)VNmyj|dMAu8NJAMd3u!&6p5w<PuLd*6C2YXHM(03NptaDd$rDK8wbIH!;ox4$PvsXB?*>1{-;`pX>%{Gs> zCD@%!Y7Y`SnH3Z&OY^ys`U$b{1Gny`av^EiXrH2bX)jR7p>x|BO{$YyS2Wzu&{8F? z>CSJKg0HnrSxlcUag%+jY@b2CO^3hG&FyJwBBicA9Sf>~ypJbUVI@Z?^Vy1FvQCHxXE7TcvvwQQGYr zvT)O4hg+K|`$Ds9A$Xr_;iehyX$$KK&7Hw!OyxOE?!NN~@)oa8lvC*s{6nW0a}QBM zT4?FpJdN!2I_b)x$Ao>BE0hrJWB8BJSGm4hZu!TaLEQpI?N9U8~`iM_Ls%x&w$yOz9yR_ksbAK%}cJ!I&q?A0ePx zndG8O92Tjo7o#O5lO`~pSSS};WR^8(B~_xzOl>pbA+T^(JdACJ^rXyS%yyZ?or+m5 z+Osag6rC$$w;(c-ipfT(h2S-#Yjvz zr677qu4~S2+O`m?Rou(6tWo737m1PBfo5jvRI#f#Rb?5mYQ(i&D%3&-xeO_;ImtAy zupxHINe3kYb6A~X?ZTX5rR~?r$uWRyPG}fGZq!wzF(O+m3^bNA<(eBNXIN>ve+J6| zsAiH8FEL*&K>N(K#_~?clB)QGdLWKOsYn$qSU$WSNM9KPCUsSiBe~6vQ4S#`HS4o9 zdCjS>D1^-UM8bg8n1L+JqOf7KQb~`u8{ue79Z{}qacL6bOtslw&T!I$g=98-t=38F zT_$P1EGT9aT#TDk?UgxL6p<1a+h=PQo5)8Y6Gu`tvob78ZdXe*zL~d$(b8BHLQO)v zstl>XGgLzX!C7@M0(1Mo(nmS7IAuJ6h$R3@N4p+C(kjCeOnc20#ASZWvM5n*d@Hdi zk(*OZCKXR?$%2GhcFQx!MKq&1s0N(%##7awj7ybdG3UA^Vb&l=QV!KZPBsokP+jk` z8WXQF4EpJTic5ZRmn61){YV>eQ@~D0s-k9(h!$K-sU;8MmSDiL5V=(LGcFTT*Ky~X zHDBhyFhgY{$t?5jIyEYFWzIokwpD~G8Tr71mYvbVGZD~ZQ?x`0tOIt9{FGl+;84Pl zmQ`7%&)IcKu#^lXDHe-4$--F7EnX>$P>Dg3>#u66o6kXGy~(7;yQF;xl)#+J+O$1aYa&l&7nsiAMn95BuOKr>FL_3YqeobZxMsUj_`_D;$q-l{X$v!I>{ z4INpax;a{7GB6VU0BofNMMU}aniiV!DH@jfSf)s#YbQf;SLdC+09YLHBR8a}>ZUfg z$GS795&)_&|DvcANdGp6A|UpWB$@NlSCG(#aAcDksByl|45Kk zpco+!qnfV@x~^GrNDg&e(sSjVy*q3l`&F=pj~rdEuOVdsEBCJ zG5%mgjqU)H^jc-m8m#V@pPk!@Qw^EK0vpi=LkrY?j$sYww3VYi=E|W8^dlQD=|LY0 z>0q_c%yL^FGSPB*M9NTKDm}(kZcfVtV4Cea&e~L^ZB!V^IZptveXFk3Wf|sF%~Itg zo^05);!z~Sj{^E+&^nQ;-(#fM!f09fC9c<`mE>Js5j_MPTH%w6_?o3zV37>Grf-hY zs)+ZffW){=`$Ve!roq|Vd>P$AaMTBx<3j~+zS#_Fr(+qX#2s`MgSG6hjX(ALyNV#S z?=$bI(wmnyJhvrxgv(kw>IDr6>fA)%F%NHb6a~e6y@{GLHjdBjru!3M^s$6xkR_93 zL*!x!cW`EfWZGH4|8mWk9zYf&(;b!|lR|5$@_c5tgo_E8D#vhEnB1IExoWfA3M0d^ zfvoRqg1#TI>1%#kJBvHC!AG!VRDbIC%wGfEFh15x!=Xp936;>K7G%+O51Nq#Ym_SZ z>->_LZ?@lCI%u1i5mDOyuO+;+{kXYmyPv?{A8PEi`^`(6rOiII%snLWRS6^caRNwk z@TG}aBloqc6|ku_-V$n@HZrNr>mcox{o-L*_q%3|n+LAiGL}899by)pWNw;63(^7h z5k%{FU2BeJe3_B+59LcPvj205Z9fmpfv9YwI&7USQo)~@pQsp{@~!=UhfAH#>1FkJ zE85@xhB?E@gt%qHgWCH916&ui#$PGE^{xHq{a;ojJLWDdS&2j6N8i}@UwZx6S^s2R=6eW28s3e*@P)cIh*wscAAIo6p8x4TsVrt;uJZW5%KWT^VHZA6^2N{j?>(96 z++PsQo1SC;N%Ol8ft=MKe*of5NBtnKTGgqCT`8|uk?bHGqSTY z^Go&&3~(j2zd-t9$8O)wZrKXh2+{1h4F_$fPwxvE_;5224Px+}@WDK0w~n`(OEr@ZSJ~t8I!-q{g z8NPS>&*&sS+<(6Lm;31a!QQcp{`Px~Z~O0$2cPwf%>%EB`~LwSZg<_~TemaEqkYEz zDO%F~>a<)XLH5@+uqrQpnjq)mOYvLZYJaEs{sIq*Uw>`f(>M@snl^q5jHw5Xmbea#}UAc$~_(OY-QNTbx{tQC_UvGc@=Xc%3 zD8O~$?VaZl==O1QfS57*Z{@j-E2hGqYvMur5E32kdb@P zJIVO{->(d2VP*w`?|1R#$ph=pHov>Lcp6#o9rv&Hm=kXAth|Gdx$k_Z*uS{{Uh#t; zFuuP1?fuimXFvPlhw_6TQ1-TswEf#3d?4Td{(H#GkYwQfHTFAn>4ta6EWx2bhmsz} z>il$K$32~cBL(UM9NrqJ#wm}B>fF+nl1F@CP8SLn zpM#yWBW~x_ihQ0N zM6pfh7B>OV@`_Y~j{A-&(PV#*kqp=(3p-87;YE?Ds6CDYr?wsbk)Lz9a#ya8c{VgZ z?|&iuS6BQWhaSgpOHdFh%H+wel*msdDNo#Pu?%v=&W0*T`7*V1bStaFhlQk!)iiII zEd2dDCJ!L-A7UQ&P+N5(Bv#g<)S(1mfI{kXV485eo=D=+D;~x2<`k!GHD=L2&W_yJ ztc|{ueUPnu=~BLZGDhD#Lif>)Z7z}d*)EQa7P4kl6JMmT|K>q3=Hy-|mBh)kP2^5) zU=T|%@^ZRbmn>L;5|Ec6K1N zk3ebmB_%h2JV4#eg(#4dDN>7<^{A9Fie)vm54U^GRx1ZatnBxdU&^++`NskKeH79` zf{n0XuT|zieo2RM$GI3*Ht@8zgkgNC)1%>nNK6haLz0X&weqIr{@Ie8>rh^bmV4K% zE@8gesNm^_&MsBWPbD%8Z4KP-xluEGG{-m=o;bLvaFC+aR%GVTtt4`Nvg_T z{daQb}mGEIYgbSG4m}*=&WNEaz z_-o5_fwI3Mk67-lU+(YOvvT)a|MZt9dq(G8|KBKA!>uLfYqutK9e=R4D#k_VWxm!| z%tM)_ttOK>=kB)WYZcwq;dX_!u4(SEoU-C{tJ`s4fh>%*8^i*}Q` zhw*B1QTK?cQCFZ+d1Mnm+^c22f7uWI*`l_Fe0pz*^>&xi+w?4EHD){GmD`ASIV4)l zpwh!1VCFmOrHl+6Be{A+MSUX6wSe51^)tuW=w3aGaK6T{ve`FERLs-@!-N$R0 zEw3sYO_?m;3&>Ytw+?z!dD$p4$x(*TEuq4&#vN(aRo?K`iq5Ub&I+IFCXEo*kRnJsY!Olp7J#?ktD%Th8n1$pWVy0ufx%7=NmG=n`Dcov z64$aheOgUi?Z=7qvs?g}?WBxZF{&bglVk;JUoUg%NJ{3JkIrMt&zV#%lWb!6lvqMS zuFjG&C}Gqv$q|C^W%%_afnHBp_;FPjt0sO_m+i|r8PJgt9RX2Xx#D>-F5{K~*v5|c z%QD>q7g>^N@Fd%{yh> zn#B<1T3l_h`#@}o#R_jr@q(xFo?QbrN+V$cj#fw!v>KRnP^$2i0#9fqMn@I!L&GdN zd2~A~X)voUgfwV`ti2hlq!q2MmvX15a5zq?fwPJ*k!U>Hsz!wFKxHEkHtcG4Kuey2 z8gQq@cPoiEe}%Pum#?fV;_+l_=*Q77djIpOVh8#gsMz?tm1O(t^@eN|gD%h=f3No%f4 z&MGfK7HZ5^WtRup;ycBQ+?#Cnknh)Cbk%d<%svN7n64mXhFz*+P*D~xR1~XZWkj3x zd6|7_0O~*%UeV@bDAD^iSN-l}W1Q0{Q*Gc-OEJI^nCznT<;}SzQRSq{GAw1ZwmA5z zl1pXL`fPk-X{)NhkA`}X1UYc!ATDW%#wGI6Yt;`9dInF*UAkPZC{{q{xa)OSDHG`` z>x4Tp#}OWSl&gh{HbN(xJ97wRz0zZ1n3a988&_p#w0nQ4lg+r6w(s$-7}6v=xk|p= zCffH)YZ;6G0iCfeU0|}gTIPT~inlw$o=nMeI-!G1<4a8QlZ|#5zrsgmIvG1&-O#p- zceNcJUGJ^=LD5^2?Q3s6=SRCIpYWRQrG<+o2&(H8%OXl??KP!JskgmH7&aiWH2o z@aa{(5qC>H{^(*0pEN9_{Z-!dZ?)E~zlO&n%okxG_-0#3g2_)Vc2l>iSr%R6VDJBcN zV>B$GXhcHBj8AT)lo{EA?WyC*5SreXS$ThO{ZdkyTAHBhdy{&kc*Um|u<}J~Tc9iX`d22G{OP zUb&^Ok)!-5Z!&b+tA)+>mXwVnXX5D{6N8=?Nz8UxKp_na7SRGF5XJW3a#Iz{)10~x zfBDzG^sr8L^tWWSJH1yorqe>6>uM`Z`P@)>lSJ{HHP1&u1aa~JOsB3p@!avcMuRGg z#v(oue(O<5r{s6!@%1O7^lq~13}3pT;a0mflJe@JEqXtV^Y~3szphfS?T_LUcF@C32ME%l|D@9DjA%|j`ksw4M$2EoqHGhwK(W;yKdjZSQevaRF$a0-4ct^ zN2w9Gr*yH(AC^T|?`iMID>q{ipG{D#-wo-N-MPdqw)`@QNk)%I(lFvnC>ipu_}FX3 zCwU|CtKK0%qp=omg41>9H^n|*4XMFbaI4+juX;8DYK?jX5c=a_!xFiR0cI8~;n)1x zE3-4RVme%;)X~u*d^L&IxrtJ_Lv=Y!Pm6E1iWZ(7UgV>Owa!f+7aBFayOkCZL9a4a z!ZhKRj2_w`cyt;@P!ITK{+Th_(w!t1%G7C{SjZTWoM1jwZmsuPW#|@b;i+z1PqT08PsRr~$~EcS`;(gw@2q{5 zuME3VuFYP=uAhu&BtH0L@w)tMjB)(wO_>bb4jzR|>F$P=nXK)!Ix=gFBwV^0rwN~8 zNgn?>B^L75=Z4hPMsqdEbbaRiOE$>b8?WL$=-mR#lv}@A zG%jG6ICAp1xR4%Aa+8s%rYhGXu+wEFoQV#5o7$EBYkodG-7Oz268`37HvA-CkPKGb zy?uQ!#>v)gK0jW}=Z~zv_7JP>y0H6S z+UaW#H`d)lVb*)7^W>rvPua@8_v|9co63Z~jn*_IkOM$LVx`ZO8eP){$=HU3bf_+{jCCmcf(llduFw@r~d&06(1<5xO~j7muxMGIn%P2AR)KY9uCp*66Q zm~CZOgA@tuw}jHhc8TX9vs?^SUJ-XKKL_*)_QHNNV}@68Tb3bdh*~nZ32M6e1qiQ~ zJ1%oi0Jte1Bk`nVz$#^+hyyUzk}YxhwL(0220vTSMvpGrNJC#v-gP5?ih*8;Y{rnD^vzS9SxP z)ur{GZl+eGg!1#sD#5dDB8ev$cAK*x8Ax`otQrYUcwtN+lmL>xlY+&qa8OhjQ?LF!0I)SXni-mFd6plyqkQg0sFyY*Qe zJE=X|oMHUrN9ubinaBzq_3=4XB;g+ZBfy^gG>LV+111fRMy$zN{cJ`d&5Rc0#&Wb!cI6Fa1#f?!( zuf~RyNcRkCYCN~VEh&$ z(3@wW^$;pcYn>6D*FNfEJ+yu4t=rZM8&uhdAY#jcoovwC7D#nkW`a{MHX9~5GJ3mj zes_%q7e7&lcJFpDF7*6J`L6nINuSVVz7(Ir8LRRk&++>3&LMo|I2Db)75?DBy-5JCD z^1c8c${_ZWMQ+o9Wi6Po;;NJ<^Ww2S^|~8xuDkA&K_~J+;%Ib@6==)J%&C+Q#D+f5 zh;L93Rl-p3!8b@G2hHqBEd!t>6ZOiM=^`WVT(~Uicj+?`3AZS>>xm+$AnICiD_qsB zNQCYiNilPbrIje{PudW~I7+I}mkBGacTHh{d#rDAiTRJ$KLIv&XG{pK(I)U>^ zqJ;;*cgIXR6eJ}<%6LmS=U1X%f=79ihp)r5TcnY=C{GM&(bZB$58M0QM#RaGrWr2$ z60@tN`PyY7?U5eA+@$plTVPl@ZSg+eJMKOrf@fr1iN@j+WhZ7fl34y)S8 zh!`i;NmXSQ@l{Htlv*T4Q@R>77XKJ15A4{N1`;w`IN=0^S&_-r?NTK2Q+)$zL26N$ zZj{Jh4J?FAn#(rv10-guG7(e$ugvY`(c-oA%cRi~$yaxu-Vr~D(C#&U2eX5G5X})n zqo^V~(WHoGvTQyg_MnaM5P}^$4DR51L`2(}VXvd0MCu`DXx6fl&RT>i>HrSWf#n#R zBdpk7*nEgjF)#_O#$m^QSDln&uV2>$r9;!bybHoTKd6|u)b`-)c-MnY0Nt5 zK(=a&lMR{Ea;Y5LQTnh=4wFaAW~!48H9VxLutmNk<&ta*U^@^7V#rfyj21rJ&pdpqMq0q5)6%xY#~{)|q2=Yu8+^*wdJXF`v(md$GNzYz%g} zi%S82YATx;079x#c)3aN?p033GTBVxUnL!+U>^HXp85IUM_}Cb-zgEh=6-u+GVGd zmEpEO!JS5kn4`nFyG$r7bMaB83Inx?FRD)>aqp?IH)SEnpmZ)w;Mki?%_xP8OImSF zhmcGHq-(ss>vF`E5} z!n1&!kkzM#;T|7DO582P>4}Z;6a2w8?nm2wN!0>b*IauZ9a3Lg;O2Z%1@} zHT62Onv&Q9h_QXXH2a9ZbGMr_-X*PI@^LH}y(c6js<7L@Zlc%T z9a2}e*Yz3?fi8x)&c_#VO)lUPA=qLO%N2*O<`{$DVQ}+6acc!xq&uRs#}xG1d8|^z z$n2+@h9gzs?7K7Ef-1?3A9c+*AM9UG9PHt*#=YQY0iri#8q2-PPkeu4&pX+rpTHYG zH9c+1Ug=kN>2>r|QT)R6dNh`Eaj%cZpcKj|@<|_UVb|18M9WUxT9e5Mal$DJ%^J!% z4Sb1N<4roL?8#oI6JDKkLYQKAoJpS8>)y|sYUSws-1q&ZVwbzu3Egp3cf5OZGJGyf zIJ{>_?`{t-AWE0;L7@nDi3E4MC zL%Ga^)7HYh_{B+LfUjXh8ix6>!(6M+N=RXNzAF-CL(>&uQY5nV_+zuZq1=5XOsHw& zlW_!B*?Crb8gNG(%B^vaQ^bw9g_lI@!|@7Dy6fjfcsVg8&`+2@2un`QDQcCPwA7+B zt-+CP8nMWaY?T=KAcKf9P1Bkpf#m2}X(c6gm0>^!8KPiJe6;E!+^+YwBSgSAy^K=E zL>}4jvu$R#{yJi67UoQJ40h?>5ML|bt~-S}F#*G>SttzJZ4@kQ4Q=i`{KiLYV_Me?-K z!r$apw(A;aVn_T!uVV-|V@?+Ko63XF5dA9wUrXI`#w|}0=_L*#)GYJ`)?zIAWE@4z zBIUIK4;!Tu$rNEhv5|}QObPK@JbGGD$9xT`!+Pie4@}EoXVH)l7HD?C1T4DY_{vgb|G^bL_JE(qZNTC*+ zKK)h@A2t$$dL+fQu7BB|^gL%9H_P#;g%^6y`Q8lHCwmW4tM86Bf**C&b@^*3$TNyX zFFq9!Oa^o!Hyec6TOlRglJengo_Zvc*+uE05Gt#7;@(LPbrU*0Nh5XpdlDDP-zPFo zqcJT$9Bsk)-58a5H^SP~j5>(&7ByOr-6^)*n~C|LGfYgNd!s!TM`rUyH{zU4M|8$0 zXS#m7GfU~5Jm`7#=36J-+2*-N_XzgY0RgeNmi3XIAar9%mBr5!$ zI;NB1CWB;XDWq-NIPPN-(h_>HOldR?nUU{ZL|#>)$X58|rWWa~GTeAfE`$qT6PC+x zVMb3`k&PSnW+``bo*qbVUZjC@GD4!`oMszPp`AF?U&QjL%Rd^jpIA4BAcUP!QT+#gXSPLEp`35aj+X89*>H1Mx=mScF4}`dnRTAB$hU`B9@;WR zo=&ux6HukS@p9S7w^mQ%D6F02>Fx5WKJ9kqsCDl~xsVmqqh&W1a)L)1xNURP274*z zwl#0xd#c2J*tET%j-4s~!}i*ET*Dt(yM3OeXj)!9(GDaeZWC6JJ(+{Da=mcV9dkPd z%N5JFtqQjxor^5Vc2Lxj>r{i|jG|L)@%Lq2507YUzxr&k9ldfoNS)4B*omwo$ReHd zSND=A7PLVdW1lX@`|_^o);Aru1%g6sfLSbJEaWL%&pr~0ak<%Pb1*sGmc75jpYuQ# z_P&^gU9ps~7K!(IhOJzm!i}EJP1yR$BncNbhzBvuoLgy0l$~P1Q^}S*9Fz{cP~IKb z8ovP5<|!8=-GjC*r*3_!CrV~Ax4xxXe!Uz}RMI-l!Yx#D+K^8!{5CW7Q`^&1veV=Q z^^r&Rc21<9J+VGGGo{7a<*DCxdwybOEx7PgZNx zmRuib6-!*~m-)^sXGCZ|VfF+nNi$n0Qm`}wcB^(#3o0Pa|E($#=wDV z>s*sEL$1TH1IC6$$?28-91$FR=EeOeAtyA+WU`c(O#MjNtIkAi&nyT13z{jXTJuaxx@lY4glnvSW>;QqFeXY`15B|#S}N?%=;pFtLsV}b^D_|0=>(ijYJwktr$NKk_=5xXWR42&3B&4s{I z3@PQQph~g!l*hAvGq4OMQL0eNh9k`qt*`XbuUmQjJEgvz%d= zgh#m8|7F1g!bGlt?RV~gqtQTFdaK#t<6v3oGVf?n<6Hx~ry9!ybc1Lzk?#jwlPztQ zfaVBOccOj(x0?AQ(2S->@}S~Ctw+qjlf^BYL}e9AkkQvd%A+F+uN#n^_hQD9JG#VM z+O|p<|77=QVL&oR2so;BTp@SSkmGW)SGq=fkfi-^TN<(5u_>|~47$(=vTqjav&0xk z2+iiuCO%juvC@F?jfP}c4vAbgR%sj6r4B>B&gxj=nv^LiTW_Hz{sQI;(!CNG#JU2O zY%GvLt$NB?M3sBe8cgB^Jv3=XC=dxM8iB z;Ke)lXf50s98sQ1%$O1WfGNa(!(7%-4-!aEh2`b^sTNT>z1%CK(PvO*?*zt=yV5}D zMTrZFa{6ajvcQ1cy+lw*PK%H%fp_aymlQ2Wh&4F5+TE@u`qs^*OwJ8aVvq}!uW*SkFLL$gF z?Y0w&=x3!yI*uWYBKHR4Zd8<{57B)_iNdYO-GuQQ$7JNO8O5tIGDvg(FJbQ+E7x%y zc%G`R*SfF$*1G-p$ZaVywz}EUwg_U=B(<@U5uoa3lWr=S@uMPclwb@s>1Ra_l6VJ` z87~klRNZU|Ev;tqL^FmI$mV_Pp11t4^Idb?VgLTet4HxexHujUMA%400%nXTdz=Y{zz3xX=p} z%0bx+dgnoMGNf_AZs=Hvn*j`(en2&2F&R$Uu{%mOmwNWrbS|<$9-0eHp7KTZ!mT8r z=NUZORsdhlhh8&LNO*3??uKQ&;zLNWxTP-zcN}G3Fbc`H>jYX}5gO7FRJ#D23+7>` z67eO@1t;eD62K=E*92i%3<+XVihvL81-c?k2ZTyU-BNKt;HSQVJs#b_@XBi$KS;=3 zr@#|F1)XR;Xg)>m#h}uE7n; zLOh^(CtuhJCQp>8*RpmKs&MQ)U5jkg%NDgr{10#nghH7@{n73+NNNK|*04VYfg;&GN<3AxJIW;1v!`n&7Y{CZkp5v@*U~x=e z-C&zO(E7BO=@OIAt{$qxmxz+e2BNqAZ9uzFX6tWhbuPH{_dAAJm+ve zGyS_?w$Hi$_^=wrN>;bjNj`Prj7z?6p9)W6pvo5pVM#TAT}Bqr{)*Jk39 zi{`d8I<~~^a#`hmA;s=GqDIlw(ND^3GYpU~N8Z>?7WJW~)otN%SX2{i$@m;r-=J4( zZi-v_B>eLW&uQ^h2Nyo$9(fpkfO1YL-~vXIfz`AzsYFQ<7cfbdJx1kJj1*gxNG;!~ z>9?|gMY5=}Xf|k4Wl^1_WIJ>kVJ#JXmkqasv)CdF7@wmZs}Bas3P{CQW*-P)4_0$a zkSY}U3NcEBrQ+kjR;~IaVjQ%gL7b%GR7$F#m%RKdTfOH6o}tIqKPgLTje9 zno*hx!6uyg)Y5P%4^Xl9I3_81T+g`qW=1lGKaFtMlZS)jUqZ{p=a6j4jO+{qap=|M+H^j1(XLxV_vuR$mem zTP8~>9=~@POhP5xCqD6hTxrB88E9HM_IuD_-0cr8VRH$wC97SQ7r?Rk_q}5`Z`uD2 zt6H`H<61HdCEp?9@%^=Tx!BvcHZ5%uHnZL{a=l|{VpSG9J z{MBF89{eZBU1OnqU5D>X*!`#x6^B>Bs?_*Z% z_K$w%m|Xs5@~u5-2jL61<$Gu3OeRnN-sS9;p25BS?e9YOgFRKQ2HJ|?vls|V2A^Jd z0UuWG-jn(n#odEdrF$Q@w-+n7Yv1}-<+lCiHpmw&yv z`7DZsb7{wF^IzBg85LAhlT(1U#LL}(0|^!Zzeyh0X2V3(cfONiVJ`aXMw%5FWp!{PxnKJ_rVFvO2CHM)P5IKy{)@sk zTTy&9HHNjsAGx1721&Bbmh7SqhnY++`k{aU};TFrePy3Dd(7Kl79HjZxW%nbGH|2k&T{9_rSSD@1x_@X)3qt z$Fj?FvP=vv&y?iG%Dq@~qrcv`aa%j+3kY-*r?A(iqqTM|9GIr=OP_l@yF5#yQZjqE zXw9s&VZP?5&$WTY>K0GxEnZtiJuT8fkwhYo9;@m0nt(Wpvn0 z`GX(WGq*qXF{*eMmpUW4{bTmpc1^V%T}bW zmo}}iRD!Lh;Ilbt>8z^|f{A#nKAw&SIB?pEyrILVu-CWDtxSfZk}p7Jcj*X~03&_i zrz@1mb{H?W@K|Uzqe$cpu$nYvL?n)006j;>Qwk7lx%rnou)z-Vs?C_$YYEdpD`k1Re?Sb%TGOBSQLA1Q`1+IYl0}&d8QqAUJU+RFpMkg#~(~ zj3ed}U?*`EBrjn%NL%DR=Jqu$d|66zE0t-Ys7^|q z9A%@B@{f4*JqvfRyaqO#re;dTJ!KeFRS4tF@-bY_Y&_(#2mQ`ssTzx}TY+hUcCN$;c4lTT%B((C-L;4^>pm7dI%oBgjQ zXNx?{lNZ9lmx<&hwAQ~W^-_)f(n49aTE8c87P<64Vb2ShE3evXMcGXC>tUX7W~;We zBDe9^{r|M8baGgXFC+~Y;?mbzT3_3!Ep51Q9HG#p$y*{(l3uEzv{iQ4hVChqukrvJ z2&vwzBUsd6Wyj}fZ%IRp4N_>0Tc)3umy@2`wNj_1I{CGtZIE)u3ffakN%Kp=7j^mX ztEKKMZfqnbE?R?SiGDM9IwxBDEj~zBdAi#nQj z@p+ABfb>OOj*=#o-|-9H0p$GIa1n#>hrL`5a?n zfm>})R1knOKBXP30ihHtud!oT_#(wEm2!5+7k4a*B@W~PM94I^Z1vxlX?>yH)?LYxb7p;_Gx>#50^2xU`ry2iA}(>tGo`S-TC5a#JmU2;y2Kba5sob?&5QR> z<-=wT;`$Me8#eKY%cg9Ot5446JZOZ@a++{MMBlyCA-<3*+hiv_#Wt8Q6K4+IYB7~_ zP^RkBWBdgU!w}N~XFH7DWeR8uI(ciEHtGbExLk6}+}PMHaOq)*`T?I@b!zHpzL8%c zpSp!l`{7=nmS`9hrzzUo%UB0dfxGalOCN6rFRh?4Kb4YF3q@|ZU*b-HDe{m@CC)M= zlyqKRLRShtNvINZ&}8D0N|ZS7kxJ*J0vDDg=cBHgB0;L2!n@N-Qcz2zU?ma1rG9Wm zLq*v<6|xsJc5hhe5}?x}MPsnUc@7do6SBk|A9$dImq^!uFRB<$B0QR-jx9diH_yEy!K5^zCvrSOCYmQjPYJclB1qo&}IV! z8#!YetKygiIP>MPZb2Sz2dXKiKk<%3aTMP5?w8kiRk(ji(}e}+-k{`1X5{cZrSwR} zm?ey4-UkZAh;~1Pgs6aOdT@i-BhDO$Vgc{(VVW>!2!FqwXfv0w zEJ(&}fYnAzi||o(Nz5JDISSmG7C5Jo1>})y5XD5%tP~2-k~cY=pDzNwxRh>1vXfan zyFF;eUgmfQ;=;hhkyL|(`>HmM@@h}EU>y_vh%uiM;6xDW*NoGZz7kScou}3DjVd~u zRa1Pf1%r>EUylzUFp8wzYE-lBwkjr-A*4v0$ufsR^Tbwnp14#E1Y~JurD&lY^0nwM zb{Tp!N~9XHSKY~`@#hJ*wKh_ga0wZKdeldeykZfwu3epKI@#oeL^TZ0ZbLevITZqd z%kiy%)P$xKf{M$?%A@L8V4fgfa+Su2f}#A#Iap$q6=$Yp+ZR=$I6YjIV9poTp9uF2 z2*iOFe@lJJ1s+gNB^zb^psm5MOc{}kOo4Y7nW1B zIF$Q7@C8P*^EDaewf@uV8{91GE!ssNsW;xgsFNEbXHH=pPs^Fpuq9yq@GY^UwqLDn z&Q7c`*q_W^3OepI`ON|%2Ja6wt6}hVt=Hbj^^G}%1zKSwoWrFRO^KA6U z`gS{S)!nD^hfJUxmU&=H?76&l-z%ptwy{A)&DfZoXwoq#4z;FvEg>e)#!5eAm6Q10 zK+J(W`_mBJ%9?{w;NZZ31MQ8Lw!b7x*%3LDj0$p>|0k;OVJq9yraj;Crw%HnA;3p9y4hy%y;V(Q&{pOWEEnGa#O?*;OueLh5rXJ11EgVjT3LusdbJ1738Q^+X zU>mkt(kJ^Eg=zI+(pX-L;{b1@C~XL$@zPw#gZJ>;? z-I(+_=Pl!Y81>-NU3btZAi)}}m^1aXalis;>UlDVY|K~;6Nu-J4^?E{3I${mo+x$X zct)Fu?SWh+Sg~1@MH~<0h}T+}!H=(TSUW+!cyr!CFK_=3Aoe^n*k$bfgRIxfO7S4a(J&^ki>UPk{Bl!rKNQXl$l3iK%u0C7$DkgP$pZAgY)_F9BklfhVwX2%q zd9i_uxNRG>K9FkMsD$-vC>(QddJ-n|(Z-Y*Kdj2@4__6_2j~$id-7Fp7K3yCh+ngI zt+yV0GLAAf$kNz~SH13rB<{%}mjr1hiZIAG*1~Js)05=hcr0vG2XKCVanv&y<+gk9 z$T%zp3nNE%26RfY?qZ1EUuhP+qP7*lyP=hcl~J=+;mh((^cHjqGBi`aKAdVp8FBcn zZy3d|vRyYb8+~_GBFhWuhk*^!3u-M%dlXn40BtUTmB%i)gDaM7n8B?aq$Iotp&bG- zDDSwSV=OiY*Bs2`u?Hj)8}Kv3RQgbHBgG5xb|Kv^1fBy#CPui)u~?DnvBWGjDBXq= z4A)Q-nrcBtYmaGeJ%U|+a&1SD#YzlkpOi7=+Hr3n0ezNc&2?d1ml!w6xW(i>1;t67t|%dNqg&Lh z7L6*|SFsaX@T4M6Ngi1&Mm=LJopE9N(X5Q5%LZ@9_S^;8l3+Xr(R8>vd@PRKlZfww zMEa!nA&8GwT+A2oRkPh~wWG(jij5cF;JBbv&Fo4C^=QZFEu1@ab1{$;gR43&I$3S4 zX7{a_Rz1pa6QfLmkJ4j+JACx9;Awl=cD&ZJO<8X_mwmGR z(h+mK!fDL@`NLn8u( z*1Np#C*6G^lo}Q|6`Y$~%Q1qq()AitC?c*E zfzriHrkE~r0#L7M14rvudl3!Gm5P5<$119VAu#lu&@?63K#@ESEsL&*6W6%O(%c*| z>0c$*RVWwQuDFzgdSOcpJHs?p`U>UJD0mbA-Ykk>Uy;)cp2tZd3qnRHYT=Q<-|-g7 zY10Kil%u|_OfMK_;3%Ha5iW+8 zwgPuLGzWmvM7T&8YzRg>5euC;&`zovJ!n?dFu_9GTozT<>e1)A`Zr(ilgd2T7{*j&CL4``FgTP&^~5s7Yl zL8=aES%O0ANGZCCyP}*-Kl<2;?3x_$s#g9}yj0qnyU}EswNqn=kzy<(-3E+RDc-NG z(uAZkOPzbx>m6bB$35&-L2oVgR$_F$g&xYKt!wM&jW%6JhfYh=>qusGyzvyVXlArs z%?fC+H}73w@Y=}ok-ebtt6E&3!(A|0gj^1Cs1J_O;Usy-qK^n8B}`AaASMKHBc$=i zYjQN1;a&*iwy!NFw;YbEVX?FXKhp&e9)_Ufvf*xq&&PUE^i+_~5 zOT}OAprtf89+7jVAbfq1p-SG#hW`0}D+;N z2bjnjcV7C~*z{3+H#}({;ueGP*bN!;sFl<|?a(5MkGve_V+b*FCy@_E&21W@wuW#P zW^S6tMSdW{Ss5!dK$o!NNnxi#;4Hzb2ekqrxuv7GkpDDvwWz8|%7~*CjNa*T?*j{_ zSk~=CE$~6F<81_}vAXo;}b6bOxom6Lih0lZW#w=%I*b6of;?McV`GLnS(w)#~YQe7}ms#a4d zX(w?FidEex6qS>^ETrJlDGR1SEJ=~}ih2v-XuKLI8F*a{2Eu&G6FaoR6qE8R6{4+w z30A!5|33=OdG7q3?=a95U|87T8(B)h9JZinv4|<$#1ik4{*FkU0af_CrN!a3a(Fr0 zPG#;Ty?&w6QQ-3v|WYOY}Yj65S2{ZbS+PuS!=fIMjU?ED?#Mhzoa+ED7#F z{{IK|@Y8zUX@IGdsTIa0#APcl>RQq2+X?lMdZ#)yRssD0kze3vLuwF9ErU^r8rJGb zP(;Q^L(reT3apjq6P^h$k6KMFNu%?!^%O}R5emDlPJLR0z)z(s`>Fa$D8$D+NMz)` z6Ijh?LX%Q2G_LUO%8HabkTO+CQ$8;AHHMKJH>kISXtk_XXiJqenCsUH8PAm#@XqSW zEJ3T+^d4X2CtfeUh)Fq!+b&B=;-Dlc*j021L9Z+@nRiqUufYVG6{%uz*<}Nksg+{0 zvfBe*)vN>Jnl5ovlViR7lMsm|3)5Dr_DxFwhF+L~^Ys+^V>ig@XLY>0_KS9jt8E zat9xfArAfA$crt~VBe2bue=zzSsM&b1et|^0SkS|5>E|OxE@K;pIYHIZbh4BS*4oc zlpNU|t)G-Eo(rtDFdxFoCp^)Uk;_*$gPINzS-*e1e)?>`zPXw=ayBcBp8l&L%PLk$ z?K+P(Aez;rHFm!{$Hv=w;E8h9bI!QziGWS^XIy*6qx`9yuDUpNn^Uwqrq-(x8*-8T zkC|Ms^$|t#+oN-_DcFcu&yjdEnzv+P{F}Yd+6ZAJUM$7pDe{ATc_zq78OWTV%zenK zD_Fgf_;8rETo}0xadTQk{an9gJQ==8uC7`Q_C<_ZkyW*9aH5@hq~xDubYp)>M>_B)&V8#J6PmPWlW z7)q^ub~p{s?>{#?@$kBvVmD*|iMDym470P(VK?sW+H>JhmOV9)pY!!>lRQGhj9-4j zg?MscUo_!qU8?hn@|3kIv9us2WTd+rkQzUe13d=@5A#7o?! z99z9GJ;#!JJjG6$yfzKvurZXAb~KRDbZa^yPb>a+578M-oVT{5LHl0OHf_})8f=Ka z)Xpbf+K~VaQo>t97hfAl%(6C!&fJN+GgE3k~MR>b@UHPWbnr#o}s_jFQV8L9N&Z@vWJOkvuQ39 z?VAbIsN-8NMFz7BF8R8n-&@Y)HZInu-ZL5_B^e)5V!zSekhXtt#bUuu<_Ji(55`Yl zOzS+$xEFSq&8n+Y-pBklFU6FA_)7?DQljZ){xU zzBcX4g(gjQD!=PJ8XCjFMenz!t}Z@y>e-vqkzrbz(o0^E?U5N^fik~nFXWA^qsE)w z>1DxPh})~#YkB^T_C*~Zg?db2i_0F@qZO!_{6b)4&ggfZ=&ONSVan{XDBdf^H*qRn z?2s!a%mkI{`0u<0+n0WOFbKXyBH3&ONDf+__gF@+v_J78k6a zOPuFc+0&F7%bRpTq}1(MAKKFAv5QC_i~@=a5707O*xe#ffds6x8iZrC5{Gtx^ljAX zTu+CLX!}}L8)TmG7W+UpnEc-92iu~MdEZNbDbrvG&K|P%s7F|jbT$sJ_MdF~!Dfr6 zH(m}>*1pJfW=gItD!e%lajL1?y}EhA^lO`zxm?KJ##TGDTJ2{0C^|jQCYWK~i`~UF z9@>Yt)_`|j=7U2pr2}=?FtKiGEAIG4ZQ(cltj#$R-|`g1*eBRh>3KHqI0txC5Ko&7 z*+g5xN}o^=;}2!7BYDTem{Ow`ezv*kgN}$zj#o+NFnd$X_ral5Tfn=rRg5+)nO>{x5sZ)*!;;h=Q6jgR_mbOK<0OvwiO=fO=t{H z4{FC-EgxEruPMhlNvt;c^;Vxd7+QDVwG6uQRtp5!0ghwWZ3)^r_dwq2WCS;R$WK3` zFtkls;Msm&Gr`Op zWnkwW+iyJa!as{BKx#f>bd6H1>(@ma_5GZU%VHz)z0o6$S7RRI{+zcVHVtR7H^i`g zm*&h-KF53^52!uHAab^Jj!Yn7G-P zC@1P5%H{F&esVQ=J#WTb=11j7{#MhsFL5-cYy1)8+4+-q9o!%<<|q+zrvdt(7j1M+D;8xXOmMWl3Xx$TaRW8rxltC$M0xcp$5gjl+d}Z?Q~zS zaV?Uf=O)xJEh^@yUwJ)P#|mEH2+pH({Y(``?#%rbkz!*|?`G!7l{zNw;sa9eO-S3= zXY$@NtR}$GrpEOnV;-cgJoEEZ*XahTA9vU5K>rC3lTJo5~)-{2OxH$cfm+0L_#@ImD~vHFh}a*^oE9m zM|%Ag>6J6oJP^S{|MSu$l;X0)W-lx4Fz*9hp8F*>B3_<&Eip@OgbV3+BbGk8-Ci&V zqG2OWv%5om5+Y@d8eKqGdPFExiix|Zz_b^8Cc;wV(nXkRONu7f?ZO|pu%z7s1SlA- zd@sOn$pth8s%Wg|hngA3bzChFh0)S<17l;*gM1 zUW$N*w!M}pLC_V}a`#u+f%lr7GAAmEXH;N?v!{H4n5GIC)yG}APuwEP3E^d$kdKP@ zWQ9LvZ*3|kK0jyqLf+#`w{(T_{C=bbn?BEoF$@t*c6g1lJY;Ux!ru zB`(o}&NRdb)Y7zphNw#vkMFQ>NkiJQK}03+MR{~0D$DvL{TssfLEOPKOCNVQWa5|j zPU{i?KGZ7HUNGS8$5uQOB$rnnkUF?>={Bz;6omLZaSX=_a!cV}A20*4nsN0E!? zw+qZS$`mQtsYvmKzetkkLQ3O(3OI?aQVKLl=b`nIqKJedCMtE3K#4Dbf`SnDxUz>g zQGwqcNGYiFS%K40KMRFSU{XErP$NiEA2cOA45e1ERuG&LGZlYtmY%p}l+%cU$}3h# zt2a11P{c(g$_(Am@5E5}2<4JE#8fs#Ad~hyV7GF&l`t+-mscG&6$-LpBpsu}Om*bL zZp7Y9i?+Z_qtUw&#YSjA`UrY`n{KD^WZA|E>eFmOA(_`u0`XW8hvl9m|t6~G#HFlhmi010I2IWx&IMBY$UO|K#F9J)=}8~}C@%dx z9;Fm!S7;Nsagjmdq{AVR3SJ~~(VuGCMU7HmkPjH54tOKK1Tm#nuZv|d@B@(_ajeo3 zYeglXI)i#Bwq}?7qH~Rc3eP$Wr+^&~LHrYhi+D>2E*fmxMP_In;mUFajaAnATkwl1 ztw4p4nvaT1z@&Z^w6T>?_U1CQ%Er}B4AhX(5?n&jw8o{^8Luc6+ISpx3HbSxpAtj5 z98D6B6shA`z!#iP6q*1?jz-Y2RBj*(v<+*+GK|zD9HQLtP_W zg^vyWxEkkqJI#XP7J<4Qu1nKK z7UATljD&D&G&RNO4=_8SL;=R05=t9B-l%_CKhvG-Q zlASt~KEd*;fue8){tow!6ulw}p%s?tSs=xPC`2uD3k3?7!zD$=1u7*=6BKa;YUwFt zCbWd0o@G7-(so!QD1;)0eu(gkxuVDh*%FtK!Z~eR@S{ROBSJvbO(MfKyT* zF=1gM8PJoNBI;~=iPkD?NZ_Seq+{~aOo0$|Bw1=8B%JmXO|S=63%{BWQy)%=(a<(| zF?<<0b>TxWv}y}%*GAe0`K*0EopRcNrI|7i$d3B6k zvXqBGmK2L+FHI3OExrpM8sGZm3m<>+)-T(WD}VFLwz`6^bp8X@*P<3{TxN~|FUqSH zz`(&R8A?;LVo}XHpggD*r?G`1k}N3&y8$XEM!?_#gF*u6b_GxJ@k~zTgLo$brYRW_ z1$$*c@e?R9u_+m6(G;h2JCG_x`K7d)c~NC|+YBpAHGF3J+;e~S98M8j+6>#_rk+wh z_(iRPLM6&R37K%*x0Zz&YoVc1!HcGn%2ql=C9v86Q$=Y+fh#zx|H4Dlt*twqQOO{p z^P-OMEw!7fHi<@@L08G4QqWowLj{kFA6g$8t2|VpTy_;pxG>t5a7s+FLTgulVXuaE zb%nV#BGefrK9r>3tNmGu9PovIzN6heY5(jq4z(vInQ!|*-NR-FPCTCM2w@-Sh1=MP z+QG}`u-Eht`;OVF+~Vu3+Um@`X8cKkV*}kiWs8mHffwBS%t3 zFu3>Q_U7+jyOsJk9R@7gD8e{}74&eU#x^6gLA-+BAmC+*Eo?mCI{ zhrYzeo|5IZNgxdFq z_V?5V*`K0adkJH4cbR_L4enYG8(qGOi zU9Ig#Jb&}%u`}8CF?xj=z;E1UrHZXA>E8abl@+y`^^aKLx{K*Z%|v}Lymv2JV$KtJ z@bT>by>VQP4(?LkbB}nRf=Rl1(O8HIrA5_zx~_KVj1nd6fwA6`?gO$diW35KBjig603d3YS(XGK2v++jgNk` zcKJ8n{*A)<-M5qP+UIItz1GFRMTIXV*?Z&*_R{6W%*w}-x1$vhT=1 zt&DwlZlC>&XZPVNtfkr7CvLy+J^Ld$^my&&;NBHG@1}f{ET#1|h?C6zh1&m)r9f>T z$M7W*y5-Hw^)J=_>aUUwx721*1SZ(N_(k(=(jNV2?Q35nqF$qy-o*Z%*psOpC2MX2 zwULI}-9sOC_P4+Dw39#i*cU!4e}6+(FMSSnwZ+wGZg(YK;TFibLF{`sHNzi!SLi+*qe zR_|%g)!}}xy*7*|V!18#LyX0}gDo{?gw50P0|cg{RPI&Lo+TpnNc5aKV-f?Sjb~~x zVj@oKjjl?HAD|TeQ%$49A8*zFLcTR$`GWk#4C43RWyE0EP(YwkB}KDHNOiz27Ace> z3RZuc-PG|;IqzC&+x6YmeX)Ee`*@jvFG{La#bri`=?6GEwI+y^hV@C^+!sp>7tZdl z{%I`k8k5W8qM&&8fYsqvJ%GoFrB8?eSQrE@Hjyxw<1Zq(mN-_{Ec^`j2Bg*aB_xq> zQXUBzaCtTwb!E(QC-Gy=1BEUPcx&?9r)nqNxvk2{wR2mwlPl*wRjE4PRg%U1+-{tX z-2RQ%Szm7!Wyy*~yxwl7GY(PtfGj}+W6lU@MoOW%r|mj0rBo48z0*$;@FgJ)15s}@ zLpGL)#IeS)ZxDBHPC+0)cYNU!Ff(r>%4)r0YhLfl&DNknkAV$Jc1)4x#ts)x^Dj{8* z>4`-3jWv^9(6j|4ekxo6Q7?&+JcH#s?A=}c>sNKHzaQUo52!DhZ_|aSTE0_fR7#n$ zNDPt#qZ0ndrHAX%#+Pud9)eO%@wp|4QkrUh2gqPPIg=$U|p$ z=yo}Ni2K+S`xWzMEPUtTY!W{)g=H_u;pY?G*L(BCS>!8JZ-G0%G%TlgPu9dd7+;8_DNhu7z0#|Y8dw#A}Wi~GL z4i@~}|6=AzdSfQN|5&8h__}GPa+r9jmnWQce>SwMDuJnTqA%g-$3N{$+*f2#;%fC$ zg6+Q!Ue9%=XUekBw4^YkP+Zs+pIQwg)_K9NFfJuk`)`jF`ulywYblFujN}tv)|S2g z@0PLADd7^9wbd(g`>n;2^VV;kC~+qC-b^whqgtvXj|$rrJ2Ed*{Q4ga=xcYwl5UGb zPp9A@<^ee&t6u32U-`dF-#u|D!PYi1r&u>OrLDL8(z4#}y}Hbenkn`7;bkmGi^_I| zu6m|y&kNZBt!eFC?cZE--d-S5GiiKGgqE#<($}F!Wr_3uGYcF%QO<-+sw;%3c@z}kAJN>&OgZp{ta)>(;OJC#k z(H-1wvim;(r+JW;p@r$K@SU0xEcorjLba4deMJh5RnTX~Wo%2WbER1GO6lv!D~*2Q zC!8vZMQln39V(xeX&o zw7i6uu$Ujnk+1-=+VAR8>xYL*3;#gj@!FxjF^zQmx2by4JBC_&1pk6u{>HDzhNZb#2q zZ^>`_S0Ra-x#m`EwpvZMgnO2rJy$-atxEtmuhNkA;6o^aKH;JZD|(bjqDV;Y4slwT zkYz!qYt974QLkl4ubpL$c$PsiG?g6?0~}RK&tuQD1}vCyW>}-=>Hw^tfP_+?jUx%s zi&qAm?sh4rPir=F8Z^aUw~-5+&HdF#77*$JD&-0>*Nz!P=Y=Oby>bC*=beR`=wY`! znKs5FabA{9ni^EN&X#q`Ph7ktnU`~_yGch~v+jLRB98ugEwqXl`b9tS?AC`YrgGr( zPUYj=byRU!`Aa{Fre;}444%XwsZOQ0JL(v)XU@8dC$jk^zJCfGtlkGaB-?{io_isc zAWKh~7hZb#D;$J#(S$xmo%LablUJ>TNp!DN$CLxHwMmgrL_>LX##^?O-HnW$KCiXo zR75Sv4!9t(AFE!vQIU@OJYBoM3kSia4K(A&wAS=e}f_lhWm{l?oWpaSp;M`|aN_~Kx z;{!a%!k2=(j*11W$0VN?Dp0~H{Adi`s^%z4dbX0Zn5g$SL;^uRn0t!cb=vBEQ2ISy zGO!#v&tKY&6B&tVZYJAY)PFEOhj&t*r#o#IYD^s~tEOaTkDI)s)E$zyY*NY;Fwz&d z^GK7900sw{W06Nj(1sWUn+<`80)k$=ItiLGFuY~brW&&?PM+eEX2UinBYjx`;GQ6# zO8RPD6gMU9w%*Sa)`6;gDIEgxYs+j4YM0hk1h=! zOnEiJgeH8ZTRK7c?P)$6DcysaHPZkpNn%N%%BBs33~DVPt1x^zEo^H~cP%}$!TVPh znRHlj!~zRFFDd;1)5&OB;F^fx3`0fkw*8Q%sf_OiA0ZjNtmsOL+uKDz1V!S68Mkzv zYTO<@%;0dkp%KxpPDB3CYSrJTJp;^?^XOXfTVmRBlv4_;w*UIs>>)Fyrt2ZBFa~K= z?g7uNOo=$d$V(uMAs#`K5F<-l4oa*IDUR+Fqt=*K!~9Zpa6E6j>$ZpfvXPuL!%@Dv zDqEeE-gGnjMc#92pxD^3jutyw4O^bFhx?EY6=cGxR5RP!Fg>0I_BlH+ITaXPvg`4= zyhU%4YG7QT#ReIWf-X84MLc)Gx}RyKSTotu0?fDN%H{++c7X%I{os?b{Yylx@cRH5 zL^?5=T1K|-q`5;$L_wB&ZE865k-haa;&f*>LK4qs?bUss3lb}GO}dzk=`&xfS*o_{ z7B~SMHq>x}Dnl5Cx?1rIdrXSKJ)Pg^N~AqlueqF^Epi)3z^?@LB91m0w6y3Gs`UGM z%z*~H)u%>~)kVfNUf2$@#v3SxCff3XWya$!a=hYvCjBn2xmriY{Ys_5`#Cv+un`dK zVxMHpmdeeWK(U6@TSZPK>tS9GH97A$SoRC=yxDOjIP-EP1n{;M$w*7i_<;~PC zO*;;w;^Dz{3G^M#B`Qg>zYw_Od8lN=uJGQ0*o(x72}93hOZ)7w*+2tT`KTq3fxp@I zqU}crkPWc~H1n-?n}H!ZdVUBUwR!*Appm!EUu6np=x<9faYC8weVCJOy~e%BsafbO z;zgm+<#u@XV-EjOAg2$44JssySMAU_^2zECQzBkZP=z4rGKD3eCW9Q+?XmIt zawCK$EeGWuzasi#hFq%#9Z;`bvtBj5Z^Y0LAIk$azg5rIq7RtP2`B-TdGVE2UUzX2 zLO9&&)7ts#|77q-#tT30&`dU{4*rUEiRC8x~1)k=3Er`(&7{MLM5na1L}bG8j>@`66lF2UU=lKrI9jZ@t!c z^b0LwJ4mEJ?sdNT-fEih1%K|zhaH6;_uYbzo43MMx<-FsppC78G$w}!7!4s2gBRM3 zbpxaL~Bw(LIzA!-EfOyVq#o`trr~v{OU->L!3YWkGOl z4d>>fD;FwGe)8zC%>iaxjzO}7v%D^l%b<4! zo68ah*`s#y$k>L8*bpktz1qW|R7H+mO+ArW+&6XnaqMna-1geS*jRZZWZ6%=bl>Kc z2?diIa=l$SaMsDVH8XJ$r0iBSxH&(^I~VJzT)uD}9e81` z)7`GU`0y}aY?|>`c~^NcJYtTq9=Z~PklRqgess|Nso0GeR79cUZF=5DyL*For)88M z%Z0tOZfy9ckH>bHQHQ)P^!kt&&V1;%W3}P@YWrv-d&vEyJl1X<-G2L6qt`js%tNc| zA30X<{Sqf;pXk!HGZ`h(KG30QB(R1Gp#@19F0hPdNICPq67ht^glX_5zeSoFZeG*g zvLMLIE(tPh+%o7`cK|dq61`S@?1q3wd#M#mevMl4Cjuc~*F6^=@2nMY}qu+m$^C{E2Vtn02xp!~{$epneoCKVd9mPOk>!2 zKIHR!BzHng!8kh}78PcZ#4;A@jV5UT?zhF;#@S!6w|11(#^T7 z{SaJ+j$CKdnmh`Vh{Dj)d6FxsrgRMPYMRz$$B~iY5|^8s?hwapwT+ zQ|d0w1UDN?~9h>AsK{1#M=opC>x^h4_eN6dBzUFjYOx>Ou$tT@vU~He zG#`S322V+6m2KB!lt9JQB745uvSs3kc&e63Pel;po@9aQxXCZdvXE{NiIJgGAM8=I z{K=em42PY=t7aopy9|^TuqW3Jbj3y+%wnH4dQ16fZeArHUqul45IP4nf0xSvenju30UMIc0PgTonwzc4XFTjgNIm_$xEmCO5V?_I=a&F>t-$%Y+RmPSV?HlVNgSZHCF)%`nb80tk%Sa~;?_ZXP7#>1cvC78ih*&SS zR|V4#oFb=})3l?p2cj8xUBHJ5>#tZr{t;1NMgsDSgtp~im#DiY8KfTl!~EZyW)=MMIvL^H;sKvm`v77<@UFEOMf?PJ>M zHIA0TKq2;!2L(>8@xw1@6yJ|+;A5gG$hE8|+UNTYN_GsijSttN($u($<| zLg1Is5>q=UIVXS0xlEuUJ_szxkZ2NLV_3lISg|Yeu5WMpQsM%o zOi042jlo9m4>iaDwg(ay9kIRDNj(zf8KF8hh!B7_deLes7$*XBkT^v~EaHIT{nX&) z5hwv8S2aygKcLHly`n2lwHVctz>`Fm=%ENEcduU~%DlvDYzQgnq6Si2SF0sCEqbDz zsQ|34Na=|Q$WKREV@MFcV8|*eF(ux0mRam#lFu zrrGP)9)gIf2IW$w)uvHbtd3pfbhr~0Q$*>ctbIw67*R}LL@pL3kzVL-6fBEGGm~h+ zy=p9=7jPO~f?AZg3!vt|4>)b5Lp?GB_`-S=b>Z6Cf2&uStnE%^0-mRJkFhyl?{)38mMhoR}`7w2V?*)G2)? zF~~%NX-s{+$XV+GK#qb%l!sJlk+7FBIAR`SH>{Wm4M_d?76n+~*$dqi2+$icp=ks! zGA^*l7>KrsBsrdVu)?I~L1>5o7PNv81#TNRi4_=RO<$_U56}_4%s@_?2{C3BG)Q-h zedVJ}f+hk&a$|Bo$Z<<#(2mic549<=4j2S|-i5(fZA{T6*%)R4eb6P(#D0sh1rU|^rAd6vMRl2aiMK?b!s z+@gme5c@I=ZWzdxM}4WkQG+ZLp_~tR%`0m;H(Wg{ZXSGqJFBM`nNkk~AA5*LLYipb zSG|hD=H37V{J|db)@s1?_2UyYdE%_Jq}npUOvxeShfwT>Z0fXDrEUC1c$wm$scFp& z81zTXKs6Y#UwHy<@_NYnWalv{15+2}#0rX_Uk8;MQ)Tk@usU!9EX;+m$Vp-bD}isl z1=E;1H3XEtfO)bA zU#d@=-?0rBks$EsXQ&DaCmb)-(T{YN7`rLPJkDEr$pXQtwRj(_N^`;tEK^~FUYguPC3{Rn2c^VC5!{Mke7pvjvHnq_{IT zEZ;r-rk{eCh37Z68tVpYS}UQQWy4cG3q9<#oeQh}zQLep!ihQGD(cIL(6^yKkxx+t zbz?$LyI6WGY=TwqE<~?=0JViF$U{NGXwr*83A}b0X2_62X(XVp*eJ5i+_KP8JwyV(7_=ceJN8-#s76$@GW?C8n`Tfg&93 znC>6UxmTox>REnASOq4JH{gHoJJq?I~mTD`d5N zPVTRvavn+!j5O@faXZ>{0#CYe&Tgl87qFT~8F){1!0FLvD7Cgx&ejvN(oMp)LQM}i>GAr(au=AbCLjy1Q zbl^JNuDr=G?oTwbi^K4+k70|k@gxJ=bQ)p|ZbnagMr)mS`+y{3{kSU9Q!q z|1j$G+kSn@PLu0A-Ex-X&b2(dn{X7gq!~ z+@B*1pnNGW0gCGhaQ1>wn=Kn-$PpznkMmsH%JD%RS;$+QuR+unESni?=Q1U^Wmo;E z^q--)=oWh4*BkkcW@DLf<&_zWlX=#szt$+0WU5V`oAC%v6&xMSWt|%G^ZN<*{h}3| zX%W|-thhrAdh{E(9kkZI#R!N%Mow=If()#i&HbPiC-u->X}7~8!KPZE@If{Y@vsl2 z^Sm4ejeY~>-nCnUx$`~-gbm)e7L^I+-UMA;4=mK{Eo@D+jC3!NjkJ%h1V50_&)LVY zVa7mL&jv%}Z9ieM2W)3^-W|lwjh?GH9>ej4<`;XWw&B&-=E2Scvs(+PxD`LkhStO< z8AYO%IeIZpqPND=A-zb@5_PiFpx?;@@qS{1jybMBpyj)+)~UAvS|7QaX;T$;FyRAF zl-GAjVNO_4bBg??lc=*GiBDrLR+2W)(&| z7zxb8hL1p1GS`i z=6~TT@jsGovkRuwvoPaCm_bnbp^u-5xI$ zgl1N+MGW;aZW=yRgblLG%!kTI|FJHH4yZ{K@d&dN--v87st|{S^bL$^vL`@d-;+nz zuQwa09WWBRH}oM6OR0cSJJFT(5X*s`>`i|^OJTKu*XZPalU1w>nLBb`>RmJAD^;B{T*0nRay@afeLfI*G z&rUhZ8y7b{d(q7YeGKxHbYkWkKNZ(IREM!X=KDf)J?m+>6}^>p8AkCucMEfa35NfV zviFUV?6?m7PF3G&-5Jd@Z_myuBbtG#n@wiOFi0nx*OIS&ED(BLRD< zHBA{#?1$u8AN+yUy(7ApZ)40-gg_Za&|Fgwe1s7zus;~lhxBp@ab;{E$NAz9k;ErE z24X0D3(JZPn&#$rs&4npQdH!enXY^4)TvXaPW`?A&MgOhzGOmY*x;FxYeVTf{Y+K$ zgWtAB6c^f^D{kJBV=YX3q}6JSi?V#EbrgqwV>)OHS9dsJqb*u89JgfLdNqt!plxiB zcxL5HtF;mvTkedz;@q63me%c0RJU(F&b&{%_u2BdXu&NSfww>CIym4{>zYm&1=fo1 zgTtg~X$3zcDnCQ`k6`voKpoPtBUne~3D3-ih7{Knnyg^Vj9~*L>jKF#QcUr)w@As{ z5joy?>3F7qsj~nD;TN)^L{N<}aiD>CquKM|38L5_1V9W@YE0;omZ_$tT0&9lYj}cO zz6&{aklN1#CU|-d(B^l~f<}S8CB8($L7{o?NsX(BR-PGtY;0Con3LO<3h)~Cp)h9n z^ZXc}WK6QiO~Np=4XEYWY#A2wg2&rL zqiB{h)o9326@KzgB@#8vaz~9SA!1d>F{IvL+Tppav`U0^x+;a+o57D$JbZX`Yzpk^x>Qo}}lj8QbynbIe) z5pBWu z6E#{&EcR1`Mv_Uw(1YS92sZ|D7~}zwP=X|W5m_9!ISY=d113r?IVV~(pxhygK~F-e zbWJQ0wVs-Q@j$zKtDHuflp|4dU8=HxO{3W`1R{HDG*1nUj3N|KRJ%~-DK%KR!7g@3 zBqKP9j!o+-+}Nw=Z`9KDtU!SM12Wl&V=Bv2ILb}0m>`^LkZc(^uK<)kcF!T5su_K| zj3$0cn)OH$V$x80k$M%du#FShCjnU=Hg*ZlMzcLwW-)I$;NT*em6IXbfvA;~;UKLh zWdb^8a0^5i2=WtdEQX{Enuw98{Sv8e!it>%Cu#eT7dZ{hU<(|;S&-bDDOTPZg6(J> z7d%F*F*HC*1q;rSOS_yx^{dopNspEWL<_Y3Nl`>lgOsib#b`jFyQG3Fl2u8$ZPBtm zZjux{OEjb;kL6X13}Zglp-}^SQg3O%YCaHl@`B*RYhQ^M1XK*jh0YC)790W>k)#ml zX((A(wUcbe>sxSJQoKfqbQHsD80=dTD}ox+kc^gdl9nYBAQ)&0EierbpMaWWg_I~` z-uk%DNw*wXTr5*CF?HTVnz9AvjHMrGIMdmC*26+$FnPdy9?g0~;@z-gZ{0>Cs|@Tg z*SVteURkVNvpB$*LW77W-Z8N*(rv8@hz=KLutrm1YMjDJix7Q9i&rTyGJF$Rl>r#p zF!9WcG0(dgwdAZL-&;kHuV#hUe1D@WGZCy?*r1kxT2ZkaCS+2rrVizq*0~tvx+qo* zB=GKLKlko3k_D?p3Y_wk6_E)Ay3!jRyQZc$9IDwhaJ1?qlY>TL2M`jP@*WTmV~S9I zhXGBJ%)_)LK3rm&m{ev+&+U!gseDUOtA75a9K@k5_!7x@(ob}OaV$iwjNGw7ZUJ4! zz}!I$vg60TfzUv?WSbBavb$D*rtp0MI<7@%rokdFE5~6jQV!R}YL$WU*CM4Hn$G-L z^A77OW{Pzs12yr$qO^=Fi;Vr%(rttxWwB=w|asj>}fnVH8blAy?BE65Zd@jwae)^{}3A#*Llp^@{?NV+L~JAz@|4+|<- zhc_O*m#RcN%?66S83SA7R|;#~b*>OYguFJl$ zb)OE#>tiNfVrmLX!|5GX$l}dRBv6o58kz;BhjqdznslkPI!L9AM9YlJ5TPl-JoC|( zh+6Qa3UUexEgCz=gyptG!9_>@34Ykj>BWKji|hjf)lEDB3R~U4)Zz;`5W1k;a{TD0 z%GvDMXYta8Z=9PqZ`{O1&sV>?_O-8FKkly|XZhIOz4uukl+^F#jK+u8o8&Aix#LL~ z?sL)-`0ULXdL&tAAyldzNrG$3la3 z)4oms``Xv2!VQtfkAHhEpZQF3?*r|%$CI}&`C(!vZ<0C0$r2vLaEe5#xf)7B2|oM{ z|L$XnrS=bmlI|Z53L;up8iU~f>Cf@?^uBr^520_rg@d-Y-};%4t-ZTW@F#zQ@2DHE zC693_Ao`stfjJ^VK=PpGa2EG&?^BfaGaoZALpZa$e*CzZ?4PM-j>Eq|JQ$=jDteSTiUy? z%9FT4OAf+t)nwkyvR#s>y6~h>EuL~e{b?Na;aKnYe?Pf&vPuhHn%?fL{0L`z@7!Gb zK5YX0v;TDMf4uxG@~(f%T+<=`)mL#%_3EoXdz-)hm$<7+Zm4d|ANy=_7Kbk?M)db+ z-|{vQ6N;0nSMgLw>h2kTeTwh6cktJSFRFvOQJEVv^Sx(|+}_2NoYm5tyCuF<89YlN z`HMcern0>3;ZlN_kG{Ii-{=47gQDgGud#OXd$J<$y-m$=<+ZZ5xqI{GXqfd$q7GF1 z0PMD#{;jXm?r*&@%P6)G(ugZF}e1<1P5= za#ICUWfoYi1_EGy`>o?2U;C5S4pd86lK1#$7+)(^B-m@$KmPHx@5S5xL%g}Ue^~p$ zBV_x|6ztD$-1a!BDH|gr34P}psf_S{56cgq^xysif`7QifPe43)I6zNoWvKTzSQ2e?rg)Od~KR6Nq>7+%$MTA2_zHE5I2gw-6t7` zxO6iCjEu&&%Wq7f{qY|&0N%~LP^E*R64$i(#_yd|1{H5*@V zzlFax2Fe$cH@ED=?ZynPu3h_so94OkNoXei)q}dp{~Dd_FD%xxUZ z&}s*A&=8+oME?I8eK+X4qnkJX7rICT0pIy&skFcOq5qEj<3BD6uNAtb1J|^}2QJKx zFL8&9sQ_PAEXd>htlt4o6%X)?aVDg&BAWR_p@EGLGu1RmcCMZI>hzRjY&4`KP1wSy(D+V%-CNmeUSeS<3^KFY3|ZR3=n@)O?CB9-r0IXj8s z%19OmDZxH>6VWSe7frIUaazP(KUb}i4br|{IOOdHE>ch&sA+AxFiNmsCp zP@eyb!mZ$Fl51L2t*Zk+*nU!j`-o94<$Dc|J8rx~7?HmPM#<4i14_z5OUr>jxw2wA z8HrQNEne@D3;1RO_U%^a0Zc6e(z$+HjxV4*UKqB%8jX+g%GGhU!>ZL%j7(uu%N}+3 zV>{2}j4iokJJ^zLK0Q)2L=3qx8X`dKw#j~KS(HioLpw*)d8zY$*OX6u za#mI?N8{p~zmPH4d=r0ONpkZ|l?yfBLWam9^#|X@3tG4f4d&l9?UTIkI+^7hTpe40 z3-;Yl_|Er#??RINTi^V-6S=;>Jtj5LTHmidfHjKW>%Vm&oFK=Wmjz9eJ)6UF)g?{o z*;&8M@BT~4p5;C?ziU5h;3f++M}I&?r#=W!IBFN z{-mEZ75S4sH8PIwzN0Nc7^n+*n{W2Fv(C3&?*C8UGX2~eUXIP3VbNQ@47FCS=|}mz zNeVHab(Xq5@Bh0bMVjCJ&02#uCjEAnd~W|=W?G{-uP0U=863|$*IL~+cXiF>{GyCa z>>`QJq%UA$m%^icYW@FU;_4dVjU?;h9+@Aa)xEvwNR3&AR;`vYdSZe7F?GnaXV$^2 z=E8|vm?rE#>4&N1X#Dq)1k=jqsSnUkK6H2-)_itg9wrA~#taPGrbN@E9@hyoN~ZCA zMb05|)@YWa+U1&&VPrYrt23rUo%ax__Upzq=U7YGDxY6shZvV=otovPnx<=2xm=@$ zlyoMADL|{tx6o90POa9IC93wi6^k{V5i{+t@mQ!`n3k+##$+_$w@g*cjaoPd3&ZWr!x6x zno^rO$G(+rW!NfJ(_UU+JUUa$Ghd-Ob(k$-*{DyQqqVodHY~3}5f@S}5leio%d@Y8 zTw32Y9;S1*Z5a$pb1}ySKy#ZNOEJJ!wVgxt+(yo8^IOKY|GT|f9&>f3`JL02kNln) z(F&;{<#3wjS(AP_HIHHQnqzS=+Uty#+?IQn7m`J5OlBtD%5WH?E~86Pxir69r`oqA zGM~_FiyWlpn!iA5zFTP&E=&=s1xb5566ZJPw}cNZF%TbVQ}696JBrjx2*X=Rdq4tV zv|mAR03o5#_7`+m3X7PTn=1+EuDMV&sldTk0Iq^A$}43EGac7e)%xxyU)mwr!hO6oMTJec$N+l(-D-Fj)Lvhsq$5gODfmWCV z#5hWcM?^0d$~F6KS!2`Is)EcHm9avBZ6){>?!!?ELT&z}#Br?^`v{R|DBqW@;>>v- zCgA07-q{V-2ByoHTCeR38#K4{ZHEBvXH>Gn@l}h|;8g8qgY6zu_I_04*`t^Hn`pRG zIKRb1%lEpA7;fNsmV6K|yEW>xqBL&@<-qqOoUi0qvCW?MGBkaiN4=3pGx2u_FnwV) z(kTHOI-0H8v{Q#vPXrc?F=n-vhAln=SBQ>>Nm0qT{s{o10olRo2r6Nka<)_kD;ZO& zbVfcX3?^nK|E8F9gGAGWrN*Oaq<#Tz&W^>d1lRH8R!n*=doDIhJ~*5N5ja+`jm zr8<@dz!xG(N^WZo1F!JeQ~xG;#KF=G^NQ;XLvMvtZb&pbm$$t8ywPGs8qf)M`UmAA zGp0LH!Iq4WwKv73nEQiXIkG}kyu=aP4fp^&g{d7)-34@OoS|+55-BFpM!>%B@4Kxb znDq(T-Nk_Orf3_pcvltNOUfhBcy#i*?~U&+ChBMcCU@h0Y^`q@`^ol(jjFp<`Z!ro zmLbz%;39SV=-Oabw5OxU+rDn=ZU)lOw}!gGNE*qxvh0_qT&Zvt=eG9nv{pUT-s@9F zbT5fad4ZvA!ZXlS{p$1mE$iIXzbU6$o^x`}Y@n-DD#RwQJWP2rXz&t+>sGVC4P6tj zYUQc2JXa0NX4pD)R%LH^DRwHY=P8rz0~?A`7fm8vY@nCYo%a&S&Q1?^w_F=Hc^&47 z{ap$ENp7T&lM&QZ>D>5D}|+?eeA#vb;PHr1)I~hE?h>&AB@!>q(;JTY}EfG}X7m8r)D4 zSZ4&EU)SWM=m}HYK(AXkxSwX|$GA!{bLkFN<)bof7%~WvKa+V z?8`HpJ7&4P2x*c=wuJOL6gyyh+8&@Gc<37E6{wq`@Z#^lYb(kKBHH+m7>u>_MZx+n+6$g@5`{! z&@cNhU$r7KT#5tclS*EQ^U`vtJTTqd)1u%xm~txjS$9+Q-(s8c$?Mq0a>15@LBsDg zj!4&)Z|sEgd+wWI>#F~JI5qvGlPhB$aY)><6XEU!;!qcFTKD-mmpqZ=8P^- zCXgf>lA{SDNM$V|(zxQrSH5u7E?-?>qvh@t=0m{-k(LO>6>6ea?&!^tX@fqhgyRU_ zZp`Tejmya4ZWW*wMC%qkuDxEp-jmm{sBGt(RgrXJDi0DS2=@;+i^=_db0`ls=Gf#x z$c^L)u0ii!=Z6oR9(kCsXnCJfGlz`+!66fi`B6TK>NU7mS4xKjmOzbe&88a9+kwQQ;5TEjE4 z0?&gq*u`0K){?ekydW%E4ZBc6asy4*Q?1eQ;;~S;_6aRN+ShXay1VY;d=NJ`2j%d- z?t_iN@v+xNytsPjPGgns_P{q!ibEOc|6U_p5*bg9wEA4y!(-ffYcja!Vxyd$_l>cw zC`F9TKv|AqDOC{1*g;ygpK+iY-gvau)5ndUY0uMK?v z()fkbM()d(W#BK3m^KDShWCGRj;Ei|{7!js?$<4oO&J_*_KF1=Se|W&^M|d`dW5*Hwk@=D!Y`! z+p(@}AFVbXkd-#W!pBW{>Ax&PPd>hWXH`9NZ2N3Ap$nWY%Xz`DNj0#g^8n@tC|GRdQ+y}R(`0F)F@_k-=0gmuF%hFtfwECB1lJoDz=88b zqoRBUCK-^qzt+pYy zh;t?%ei_sM%~D5O_aRzay=Ng@>tn@mI|XCZUJxA034I$l+DRiT9ikh=L2Xvj*%7R!A}xI z@=^?Mq@oE^NI9vBPK1g4@v7BjpcB}fOz4qvyt{da(z|)5Ymbb5FK1C>9@B`;OqmUu*0ju`c^k^xAlV!;Q4 zq8d;gQ4mCc;mr#aV5&n-fnBS$mlG@7jW(H4 zz4As;L)|(t%1tjWQevZ-^tN0X*raY(ys|gNN>W{c7z1YqSS}{h@P6roVryzD@1xdA zT`RpyEqG}iEb>D+yEVg3`qJw}s)jc$HqMtt$S37pp#m)SX&abym?@?ox>$wi|s^tWR<~D?pK`&Q&qqZ zi25*gve)u~6Uu=}+i3N?*;+=XT8BQAHIuC#G86ttExta4TcVK|`%u6%@ln7D4OoYZ zNOdJaE!J9zVPwJ+ysu>!rPrx*YlH+Lh3J_f<)0g#IOh3a@%d8XBCk`U9|lY5*(qP@ zEel``ziZ26Z{#zlnCZtqi3Nm__ zYwp#erdq7^v^bPTe>9IqOpvS6TtwejxMTMKBz-A0u)Y!Hmut``V&Ij)0B&6%xp0n+FM{kaW$tR*&Fd`^etgyf!3AgBaI3Q|D zA_(;tim9vzvvu2;~;ecp&mH9ot%8BSaZ47@2-$Oj4J6<(3WbQEv*Vz_@;QJAYn)1NcG(?T5sppf1mXw&iB^?5-OCzxxpyNa$8Y}A3rHZth z55%p=Iq4=e*wMgr8`J{&>GaGDV0*=Rh)z_E)z(3FZV}BfrX-M|B6H~4Xy18F@4xJnJ!jG7sQ2Ns1A%FJyexm)T%7w zDR%mzPa)M36W~6rC`(<)4MXZbY__@I-S3lywzVR-pe${Ul%LVfC|0X&n{ZB&uyjGf%3uiHn(&nFYC*2JJ1kilkhaP7i%n`PL$|}8R<}0s>$FX8 zueM+EB4IajYyGt~?toT(E_o?gqF0eeC#r~Y+Zr`uqs>SKINhV7Tn=GxI4H5zGl~RZ z6s(jw>{q9?P(7-Q_p1BYQ2Am`+@0;xUOQo1AC7pe3L@=O@f7<&J%_^_qzy+yS?x!~ z-Imoq>=aZQZ^cEQr{>n$f^!o#-h;i-?rya*QhLNrsl2#|ue+U{U8jSvN~MP%5qWrL zbWingb5{l>j-RADqZ`})qwQ8xzEt_otx(Q$O|2fj_c3ktTf<-47*sk?-Tg0icg5fJ zl>)d-vlMb;{eHok?=+3FO^(MCN zk!NyRVHO!zky91*A4$WYnAt|aE5(ka4(J#z;BL_MWu$ObG}Qj{LQ_RJLKS2iX1b{l zGePG)dO-Or$nl@M>kCB)Oc9uhySp!MO?`V598V-o_9m)-%Zc!C?!USDldi9S_lGZl7L{sLVWh{tVEv}lIG8e4vV&v9+`HE~@DE8<8aQ}{ZJmkYrLBcs0ymaXJvqGYi z5HJy?^A+=Oc17=+P2}a7?#T)l0K2R938!-#!{;#MD>9Ye;WgY@z@wZGml4}4R!)~y z*EeOjPiL2>eyMZ2U$uElU+jzL6KJmg&~Q-De$ngN4rf)eJ>YfX7u|kY#Frmpx>!-y zpN1!%4sJ7U@$AAAx34}^t@0A@a}qnW$wRzWtp0ZHti^&md`xr9h*~fy%0RxL_+!KX za?f6j%m&lqB}UcGAfPL^9zDa-$B{g&8<$x}a8F~-JCzwnqO#-RroGNQk5}|V-+3p+ z)SVf))m>R}Dj#{ldgtvLR(^57gC2vOw!6>@BQi&B<6e>|JCDVMC<)AfXfS1or zST+UM|1`#s;j>3aR46bjTB-%aejGAU87};W@HJ=@lr+vjvm2BH3+eP0YO$B329#V^ zc%gBfzf;aSoV<#@x6K%Er%yK&wo-4xPpviZd2E73^`) zxyHDsr;x|{KHQ3*3Cm?V&Z-!WkvW6`2|v<-&kloPf-_OTI+9CKy z!*QKAgqap+{8+!^did94Wk2yKO>rl*w%?^BdSX0L$QyQlc>q5fn~vBR)Zl$*AR9fK z&RsCX!%r7un&@yuCof9fDZI1x##U#udfqz*lC8wWy&74WNQwLp)LK&UG+Dt> z^{tu4Ae}Yc_OWtZ?a10)5u@yd7>dyG!@>Qtf{`YuJ9LD7ag^7I%8^_48hRp_c_@z+ zw4J8TpjxVp4?kC~(!ycAX|q?L#OA=?KOEABLsvRSo}YL9phFYybxsWC_jMi~dOz%- z|6uFn;Dna}CJxhi=>k~Z!X!yA;d22Qb1H0Gkx;iGrB&W*1|Rw zw+<)lp`455nJq4h5#=^Xwc{MkO(R!q!QnF%EsaJi?JaA^GY{-#DjdPCNNa+0E4WQl z(p3{wN3xlDC6@p6ng@_ z12uRwN>GlG4EblpnMRQvCmTaj!t*>T!?O@_j9cM6pAvZvOt^#Wg~li05%Z|l;*%q+ zwi^?^>oAKEmz!2|dJ_gK<1t*Yyv$~Rr`8-U&Z-^170Z|J&B(~YY|loQN>=i%f^Cxy7}mEgi`H~KzvkH~nu zHN8C^k?C|Ae7RK~9B#qf-7_dEP%- z^%4C5_J3j~+x^y#+u7LN9s6R!Cd9hd6S6zoZdAKtS7E&Q*7Ne2szuMl4_l);)8c_A zK5^G_ZSa+g zJWa8|08%EcN_tf6p8z!Ctz25i)4_=zPBmlMIAh*rX#QkClLT5H^TE}zbWFjm=@N`# zK~skQB39Gb&@Cj(tqNqa(vLQij@t-21S+@I5_V&Y8w6E|DV8b}Lark8%(94@x|2jr ziYLr^YKDeo=CsGWEF#k+%AOTr#$-Gd6mNe?LN#GJqVQFiU~!h0I1r4G0l{&W>ux=D@rQg6Xq}#IU3$OqWqf@q_3gj7HW& zQA2GlQhoz|8A3WJQ=f!NMzkU)iP4B^LA1JO)e>caVk+iTKrJ}1T&!&vb3)B-hsdVI zSb0p@qzccY0g>Bj)39$Qvc|G)Vggqm=|wd9QiH%F$bnVfQak*TM2-g3K@(D0Gn0}{ zY)e6~D0|EzYiF7)a|UCySb7L82{;@KEK)aC&XZ)s!#v=@;wYP;T_2NOc2LY9q;L_m zWt`+P|HlO_7*8sstEm*^G311*y-@WK!#^uC&y#mHs{LrCRleDP7Fcx1Yb%(IUaU-O z+UMaCAhO2lsFi_XDZ^w~DY;lO8)nkV5h>B~ah(h#L0E)VjtQ}X(zHkx{xV~(?tY!R z$h=P6O3O`Pi2y5Nf{+h6)WeZOc$RxWhzqqAq!2Tf4y?lqx*hxc!XYyRBLX3Xxh{sX zekag;NTF?KGo)h*G!b%`(_|@K6LyFrs@CSJS+_X`emixXNWroXh)0RLZrc^Qh;eausTMYTMk=fYcSmmk`Pmf zc|VYv*2COr%=Sh}jhRMv$>oWZiC`Qf1(>emEQ3h26+;Ru-6xwBBn{!~28{)&#;=ww zPDxj)2!GhNQdkeUmIecrQ)*BIvxt(y92Ljh-EYqnS|HGQcPE5dV0k0CD4y5*HffC+ z>tX0}N53uIh^2~cxLrUaKGQ(SV_Vv&FEYzVxXYh56^w((G$*i8c!v^NvL0DBtt3C0 z(@{J%nkSBdsb^~|tEOi?P3s|uU$q*OmxPG0j#sc5KOxm@omhi4H9oPQ_ex^ zq9|8WEFUeCY+xgoE>)-Gm0{cRK&f29>Vk}zATy<|tTl-e5{gLXmLXJ4go4xKOKgiN zubqe@FTNr=w4%#mk3#rBPm=$9jA}^PUei&nFkDG5f|Qo75SValE9^pKzU1AQsh8z;z~IWHRC~6%JPR}@57^& z6wQs5VRm8o7I?oOwgbOp2N)S@7i_m=t-ZAE8!<8CO)D<^tGPrrr&)5?=UU=RQZi;9 z#SRKu&~T8&18dntiN-7&S#>Zi7-?1`_Iq;r1s~1x1^y(mD=%{hmOQt;;Ky=0;v_8l z2TM-Ek^`?7K1@QgMvCH0EUB{$vZ&f)oC!d~6kx)vOZGRG`K*={ji}5=X$eDU%J#mx z9YmMqWh5meG;3u-lV`aUO*OZItTNaoD`Z##^M__G;!8Tlm2EGaR&y z7P8YZiL6B_UG3-J?@8mA$@^y};Ps^xW4TqzEh3i@?l|DZ2ghs44baBeZqsQDXp zD&^wXtPYYxrKIU+j;9(?WO5Dmp)ca`Xf2n4XQ@wrx_sx`XSDprZOLid`|5TO{olVQ zZ{Oe|`{ln&Se+p6z4s}UeD`OM%gwis{GorZc=p+{C*S^GRo434arRZ7`!fUYg8} zTI+GDkZg7IXkuRb`@gr<6NhhW?_S5R(`&QOes=BM8!L|^0Do8STzk(PIX#QnuRm)( zp^^_bJW!b@IRDxdlbHV}u;ehWWg3wBjc?$=>+QFW;-u;=qVHUD|K5Ke*L3olxs9rI z&Q0;Dwd?cbvx)|&{Y0fQ(E07RR(|BaJx}_XE;xoFAoZPVi5a`R`|8b`UoZ=OP;lUz z?U~nJ3qk(p-e(&Wp88O4?mzzVgx$RPlnFRsKEMuyCYt$m`zJtJDhYn>w{S3ch`%NH z1G83K^nj(mw#9fj=rgruBpec8Xkz)yXXN6=gdKm{|JffUtlm;n?icaC_I6EM8^ zJ@vfSH`e|#dy)G%{qpxy1#kNpUcoSqb*t>4F}d=yfZm;GwUkBO4x&%ql*aDQc=?0> z=-FpeQzRC~Vd`pT@wf5Kb`y_hbVO6_-9*EY+k4fI9>=*GsW(u_hMO6YA@hSDFk1fp z@A1BNW1c$pY8-y$Kgyz?49&5{SjcdmWn6Xnersn_SJ6DO~QjAol&{0#

G_IY*m%FlldUnzd_R3+_EvaadF6)Gc%Qp;iLF#lPB@W zhL^jy-^xb(SrSsV6ySo*hU(gDQv_URNMp$)xnm7ZVcZXPOmwb8b;-mZ9A!K0%|^p2XH`Bi2lRe|KpZp zvPou&`H+MrR4E8~z+oC1C|6zx&_E=bj<%~eP=2&H=gW1lxXuWlrA&>3H&bA%Pcc$P zp65xFeQs#R&!6+3-h1Yp{}%P$4SbjDGd1{v%{-1-X4IH?h{GMxN~S9l0g1rtVnA+c49H5;}k)mj13N%d$987v+b z5o^oTT6M6XN1oNOy{v&_7nl(qg_BD$Sz=)w5-<>#=SnuG!VAnY&Wf*cXOnDcCm2)q zS`}-M$msz2lBBVvT3&;s8r9&=LL|zMhRb?jva;evULCbUlm85^(12P!EXVu6uE$VV zv{M`|5Tzhp;xuM!S?jvv#AG=!Hgx_?ztxnGS_eW6Y?Xnex?O%Z8H#v-2df5uwf^*P z*xvFt27h%FKf=Fp^y$AEJiT&@N8$g*cAlutlYe9~1lM9zO-+dMy9Ivzme?{9qU(}* z-dT9My53x-30Gp;q;d=9yht!i-t5b&(cBN-{C62^T>S31=94##B?J289N)#yS;j73 z#akMA8^w3!L@u|I{w&dWoWsRB#{u@;)1gj%^V2bx+x#w`xZ0_VwGS`Kc(XtIw?c{T zjq_FyQX6+PU5H83>Q9&0<^HP|vIgh-vyAQi-sg~KHTq8`zbO}zrp>=Gt*ngZpZ>a? z(*Rr_qkAM9c=P&ZIc}Srt@C!zw{ksPYod2vaF)8+scnk?vc9G=r29MlB1^`9S)JpL zF8`)vc|W-P7d6(roC;0B()O3BSV*Mk>blL})U2N`WI?Nvg-nCyn{FCYjokc7t*LbC z9Mt8Z6Im)DY%8wm)IQgme_GqrNk^o% z)!o|rmNQ-MxLfMJrfaoiU;Nb~_1xM+qpVBwUoWI=e$%}rZBt42O|uLOt%}S2kSy6) ziB9TTURIYq{dMIp7TWtEJ%SO!rR_ytY@hAyi*b#~Lp&((VbfIphd**TRYqi64OZ?p zme2m*mRMtpl+};Hr{gzcpK={$B;r1$^iyj6>2Z<3Ui3QT74&oO+g7 zIupy^21_~ksBgxUK<;^X=3Y+-+PD(%ur7rWHsTTnr={dNtWVBpbtn=EO z<@q!^ka8zcC1tf4DYAXq;-qqS*8=jI8k-4o^1^d6Fq#`azbJQeZ<6_B{zztKz`5sY z+M*6L17egPKtWkvb=EcmCU58Yg_MY`k|oni#|dLZiY7iO`w}u1s)Yu{nOYt-ujP4r zjQap;EfQa%?k{sJTgw_dNlwfe+rln`TFeWzrprs~7)Ub>CATM8E10vbM7q{m30_!~ zMqZ!z+%TR7t6@Qt+G_SZ`7L0r5E8|(gLcDh2SDHo9#_j6_y1pw2oy?%&FZ>NJwf}xm!=wQv6+}vn7a?mdh;=QA^o1%o22g zIeV-sYY>N)i@aVx$KJs(Ihpbr<^sV2KD0pIcWiOpzHUn`!fv7QeGC+(3!?S(e1RHd zYK)OoJ6fAE6bwCp0E#v---@-!zWMXoF>ErkdKcSvM`l~Bn;Ha|4T@SNHhK%pHV#Ef zl=g~NO(%uzID#hHkd1)XnV#m39s4MIu5g(%hQwmQnvZwZ5o8sVM>Q(p0m|5Oo+x|T zF$ux;M>?o)CZw)Hwz@BwfVe$o=e8*>P|h$Z7I?L^P{|N@3WG^94DFVagI4Wv_8L8< z?#z)P(zjp(50dXvuaYZMV|m^h?F{l$PP@`1Uh*&) zMer;iuiQ%EWESJ_Qb(G@aa`S+ZL`Gpc)@o*m&^B7&Hd@Xx-;z^2>H&k!#$R?t3u{H z>>|7OK(zi>poNvDd>oZJT4ar2D2mRSk_d2|gPb69+G<1`P9dW`Pfqu?rb4EeRWoQh z6mIBe5ygw0UUXY zei=g5Y{#?aRnW?ad?*27p!gAI33Uday>S@NhCHJVkSK(op*v-QXVz=@VM;G8rc9CktI1Ito1}k`9 z*ms+}k*usHrkZBGE4;KQh&x@dE})EHlXTl%9x`HRuBmR*a}7)tx7!VVAm_GAEDNa| zmFL=|1YTFz+IA``ZRt=OGxch-PgCs6Hmu51wGkT53e5&mCF_Fe7H)4I-Y))3W>vv> z+U9n-#{NCzXcqAUbC*ruy`Q53NuBL&8kNW=JXe(H6DvAg6B(@H+=k_Xd_%I?*99ci@qjS^dD(T8|exRH8Dm7j*4E*}IR zOod;fwY#PhWLxWC^r_Mu!+H^MKH;Op9tjiPv=Dqi*s?fma1O>%t_PZ8Zi0+2!{SH` zSy4O>a34o@Ip-CY64xoB8i)hoWZLQ+*Yn65LO4DknDe6`0=&jcxauDO?ea7CPFnb? zL6@#f58x_4tDf3)qH6!PxFOrt4;@g@MC1#0rDi;@uxB5&CU4-yNT#l{!6(73tMg1a zA6#bD;7L&%y|hqTU1$;$ZV<&Ofi;rn-2uT3TPj33cv&5x zUi6ow8LL6zHkcuf9GRa~J_~-_gk3KPa6DrlH^tCR38aUY&8H|9eohF({hIYKdq zUOXVHgZ5m7c{hlD^~CmE+J*316RHl!D8ho&r&Bik2ss`TN;}#cpU8-#*r^_jeHooc zd*|82fOkgL{UMvP~M+dRKTD4UP^T z4tLB;&%RD}=!eR)*@bSlt;~I;C9qovY!_oCFZq-10fxX!C${tfzP&E%J>Bc@5*K~R z39I$#mv#yog{ zUSy*bmr#n{)VEu8Ar_I2!eAalVoVd;f$uW#Fl;HbCSzS;K`9WM0&`cP{?;1b;9un0vG<9e3x+ zZxy^UfMFZrUUiKI@4DfB1&vKHYxjoW6bHl7w2B9rTGi?fAJ5B?^)Mbc=2vsA=-3TA zMIDQOL0%khgllbHF6zmV#<(}>mUq*snqfNm2%cq{a!PtOnvYuzZALk6*n@MBU;R>h zI=HkhSHe1N(qCsC0<^JxJgR$Y?zACS+>0+Z=GeLKANKKu)vdXoGsn4p!*(uS85vZ8 zZ|cUv>#1sd?);s-zOJ8+7vy9I#?Qm>V*E-+d7(zO?{lu`+-I{;=rwoc^vH?7@1)GG zpIv>ui2h<%is9%89~UF&4R*WA(Qr;B zTkiGZ^JSxd()<3^I2k;54pU?LH*A#Yo!XlQT1jFMWvCHU?HE`0OCP>98LU4NCtC06w#0PpoiYI!k>E(V1Uk=O@x?Y8I6v_J@JmVTp2a_s$+`jjGUk{Qgk&TXx>{(?G2PBB3I%jvX7T z0TduYqZ`&ZJ|_(PyhUy_7V{+;(Rm(q9S1(4QiOkM44e-e6SlZ zQqp%E8Hb*UU0Iv@mdTG9m;NMsfjDq)tnVqDf zme!>>d1;dplz^0t-jVqgyo5!a&e3i7x|JbT1IK^ADB8@)%&QU+>!}v5z7@f|2O$@= z6-1?|el?T~+E_Y85x_YY$E99~(&+cy6p?dX7kxy^`;ic(tI=vzn%R+wtJ6jwbXD%O zVkVwDFBo41Q}b#xYfcrT1jJZF6OuxJf}N7!7==Tg%ptLDRy3R17AJt{=mG5JV&BGL z5hZaFgj}!+%953X^@SuT$dCnio$Yo{!YSh%QyL}HYDGg4;RA$%1~+N!UV@AsK_lG^ z2p)iu)~&)`WB|If7I&oZv3DmKJ3?^|&tf}hSg}Dzg0$i4$h2!pVoI8OyNC433fG>g z2GJ4u=>U`d7?-apyc%hDoRBEKr(M~|!(mQW>CNX*=T`~ViE;wK5H=E!%vGi47qmtz zFgsoMY~rEWvZCCa;rVwBsgFe1J&s4DZEG7+hDv_crCwHh2;~&_8YR=~}Ai!;F)tgSP{qANRK})?jqxY?ywL?`WB~pvZNn2Cv*&FX6jKn8RwtqFu;I8ly0c47_xs z9eJCtm~#erem^it?}^0w@q~)?tc?n@y7jRHb~0m)z%VEyo0!J=7tFp#Myu6&v+8Qt zLRTrLGO~$Uu>nn&GVerWRb?aiV)H?13-o|9zwp#n!P#2e*)hRvynXb6!NuZBWlhHt z>r+yK0y}K` z1K#|Cvlm<^x{9HSq7@3kxOU&QbWM_0IT`l*(O&h}K<`)USYb$@oV{6zv5;>CE{Q!7 z7s^2ts`0^)m@wdvfinuJYRAP@;6x;Dt+*Hg2_@()5M!@lNsBp;B`j$RCXVw%_!3>N ziiu*Klgwroiyu^OZqWq&XosN%fnVg8VcQPmNdG=&BB6~ogP5vWM-t^w<{VF<)4Eu1 z(Nqx{O^ETolUP#kuDM8RyKKOe0o0pdHhF1LsWa5(OiSUCv_Dy(^LZ_9L0B9$BQQq8 z)N7!9iYOTWc(hzc% zh~e$xYKFk7;xrJ^m?nj$NRV{1LpDRkYCVxh_rDcxC7=wTDO?0e;dvcPk=$78i4-kN zfgvL2^Wn!sYV`iH;=(4Gd(mr>>5N2StiVYfUD_}6E<-ZSQv~LK2`p0r{17kbOIn?j z4@J&t?oVqVH!X1h+48q4nP{v#bzOAHeQV`1c_}%u8Ale@wB$UGL_=*!%t}U6Kk`dE zb2D_Gy9=T?!93h7bj5(OdX>2#8gqsqS!L@q)QjT7A}Jr6C+)~2LNS_bniY!ZKv{N* zdjRm<3h~yc^{~$yQ=_`#IoejyAcrVm&@QpFLB3in4%HJlEX}H9IA5+12{qp$f2?h# zXqrc=UCwEyyyE7{UeXFoxgtoglwAE78FAd8ZkmW70}@ObTjjiMrKx`~qbtPJ-UU0m zg8t$m^A99Jnv_zpsgWScPX*Z6vn<)bxNKy9O!MkZ*@&Gugv40H#R`IQUZGL43+z`` z*h-6UPn{`(jG90s=BxjT{WP+7#=cQod~qQJ>C>n#Xtfs6{FRpMQ8JQu>q-%Umy0Lz zSU**n0Cp-t{PRO6;P;W-kvzMd+eI{PT*XoS63$_m@4JYjn_ zBE_DTE4#i=1xBJ=BUKIZ7(PrQ`6?aww!`{BS)_}U0 z5unm)dlVaxP{be)kpilZHjU!RH5PM9O}%&MVL@Gi{aLr-E@Q2r0j;h3cD<`8l&212 zD2Jn!omY4C7pt&g3bq8GZnS#w+)xVDKIXT$sDwwmyW_p#uB^edyY`Duj1?j+grBFr zJ-{)%OYfQ}yhT_Wpp3ZZP^_&|J+rCSS6)n;QZ2fWasCt;7CJQXL>YBtWUiC$Zeibt zMaMpEwN2H6Ys!UaT`3f}zSB~7RW@a3x&wob`)78B`tSe`J6liem9n#fdPU{CJEMCq zJUo=}OE?z{Pq*%Fo_n-xH@jPoFC0z!)koS~kH^!`K;2k$w;AQsP|ghR)?L}%@q7nJ zhoUNIiBfb8E>)VIhrw%#S(uuIH(13QRebtILZz{^>GC=&+xC{>$)73o& zTQPhhnNhl>-n%VcMf+h_&Z$~OaDIdnJbLIzf|Xyf>zBgORu31}`fD`V8SN{KN;HU- zxCbLcvDh7#)u`WA@68}e7dLwq8e97&OPrTk+p-~XuPpq;$^+np;@$Any<#13z?ssf zgjLJal5knP+#XyNZhtu{7bq~1u0|#E8X2P$lNFUyvN?4jwq~fjQRwqnAvXPs`tSx5 zg>dtHkGsAjd7f6K%%jaM83(TQ73~>kGs)^j)ehaAjeko^7f0LChiWE{Ga4ocK7k^e z1&=^VtTrQ73G$VP)(ZO1YSB&ovshcT(-A}zJSZS9jqbfYG`S{IO{w0BRr3O!&2_|f zZZWidEXPiChA@UQwb#ocdz(b~aIR@MIoHK$z)ZRulhOwoOA0JJwB6JYoq|R;l47tr z3lD9$SExs!aO{Sz^gFW39g@@AduaA6#bh$QyFl|5nQd<}?`#KV!X1fNWmSB)HGWKX zo!5tVIEk9Rs9n|l%{bBa3o?C7Aa;W>KqJHTYdFtZqCiaeT z@42R&yYLKcAW{4|8_bt}Wkvc-->p}M%sJB-&%_mmoII=qC2XfldWZy(sl*+|%>w)a zSsp{e)Otb$*VH`FBEKm=dR#ssrnkb;L4wohH~ZWwZ$ddkPepG9tBSND0$TJ~F;V5P z>jy}=lj>0;8HRA@Y;8!B>HUm3DRv)bUT^~+;5IQ%?j>7?8I|2XLN;FWcDu3&4P<+| z@SraYAgzW+b{KkG^XZXmM$-KpS+rz!k^52f0O^I5IhJU3OhG6;4<^N0h#d*7%hK6^ z{#bnF_JS)?!CbEd6vABm_&P@AFH>Yy4qgv&rworu;4(|+q2Nv9NMW5e-mJVI3^upB zCA#}?JCgU;)nPG|42heD@2l+OJOhM^1wl;#H-?kw6v8UUdd zB0PZ?S7XZqngf*u2Wenq8_n!2RAS(WxmY(C4_t}eWwIzk>6r;T_PrD`+j!zwvA`3f zQ?#pHs=jM7DM3RYhindvU1`N!6ui-2-w0#2J8Ur@h-BMTQW^a8NZV`Ltdn!w^GWPE z7+={#7bg_b!q6o1t9C<1wQ*NTHxg`0AKPkd^2MH4){g~qGH3r3y=~7>k$1}0uoE2b zE<8ciTICj+jy2NKX-8F7R~(a2$%Sj4E1?K;U&jcKbH~)p0{%Ls6mrLgpyQhDHCt4U ztB73dj?&uO!_Qcxq%-Bk%@w+ftjKQlB|cMsq>wgi?uz*Sy-ax3G|o5i?`74FCB|IG z)0Z#S%_Pu{mXY!1dX9G_Fgz{7dB{2`ECww(zdl9>t55uYS$p3gNsjBl?`3vPqoz61 zRu2Y<0g1D6dKCAAt@^6#VgNov~ezthwQEz6mVlmNSH)OrIhtK zr>`P%c4wl5wlL#|BC6iYC~=Kl_^rp-oo2?!?qigbd^2%Df&Zk=cOj$7$Z zn9EGVcDDY6>mswv%SOLF$nY_o<$N_dZlblHuyk~>n6~LY?j%!eE>9G$J;4a7aWlhg zr5CPl$i60i`arMkw~FF~#8=OgWTl*=Z!+s_3j4E9&7E})dPIA|0=Brd_;9;j(8=2F ze7oJ|qQbT9JB{0$r*_(#SMq!p!hCZblWzV5-&=O447F~lG?=3+VhB1qGHuF(I3X-# zH^w#w-qfN@Z5min*h@F>fv}7PIYgI9)iH)xA!8X^Ps6f+^#n#2KMOHnNGR#3dIT|{ zj+p_(`b&!29VP=NrT3E48B#`~t+Dsw77LXKHmnlxu@sK(kY4(Rroofa$eA8x)>wFN zN=#9F6d5DUt%}T&lD&dql5T-lb<<^&6zOq*#{h}C7RN}F9--2XK4+|ANdTnIZwZPu z%!QLiOHNSf5UjH#rX;$62=hu9<649?(ab%0KvaH)RFd9=z$;kvyO}~ zoIl9WKmcR)%1w7yWX8SXA2g;NhD@?WVEM?ObpcLO5elal;KCanMI47kr0N6#-FA`` z+Jz|7u}$r4M93zV&v~{(GAsB@Hqb0unpk07{)3yulFbNW?y|_YU#OP+$V5$P8KiQc z04Hctyj-fH%#M_@`P_gDH(@6q`sQ1a=&j_%pyZ?> zysyX(^eZXh!C<7@lfr!L3S|A{vQGs;{wTZ{l?3XzU z598}Ws~h_yLFJ)|pp-Uh1PrMrbtC|mZUjlzRKogSPeM$ZSPEJEr(c?g66ti=6jmO9 z9sgEa9%;Im_5+yIHA4g6#VF90xqeN0Mr=lnsU_nZ3a!c_ z7!Put$*QJhWWWPO$CQOTxyHvZ4`v5`W^22fVC z!WF2^V}}rqijh%4%`O!q8 zm2E?k^`hGI!=RB^Oq%JQaiC-%A37Ng9CC!MY+@HL#=MwnM#Y>Dhfx4$ff?2l(p@xF z8{p_APV&X$N6Vyc0ZfGlRHfOdAMryiTztSr=3bI6uu1FjWP9YVd4 zxbnLRB9$CQkFdj}ROTplQ+b6|T^IR!L^FJ|PBw}q7*_o(G*IN(f#IRF!4%tLY6h z{OCxzJ(Vmkm+4U_2_>k3Ix-mu#<5BasIgKTJm2FQHGpjJvxe4mtU^#ov*LNnGRWwE z(ZRq#;iw5qDpY03(nRd2&9Ka3YD2W59hpT9trEacRFjp9ijQRv1{F1Q34BkY>;$gw zeks(9Dyk}%rCYNgpZlOOe3RY91^y_Td&=1OuhS+f#YZp};)(b5Sk=e9qVf0Z#2;{om2@_TKwL+R zc8N!~u*lM9*!$=XGh7t!U3}EEdB2mjWm%iGV(p*}rtA{+=%lv~y^SPD+ zq!-?AO+ge*_5S^XBWGe%RJj$y!5GfM5-U8EEr`|`tBA35S7)+RVDf!Xy>)gvR6fX- zDdxWn+-iff)eCO_=EUqUNKCW~ zjKDvg{ne-II;hRq8v`nI6AIP-+6*J=>8e$OR@SgKr^FJH7-(MmSF3%@nY*>b%7iq# zq~@uxDjJsztPaaabXF{BnJPc5X3752hoahJ3Z9~vnG$irj2WKW%)goi@AtljH;ki< z@v>$s!!L?_LXsCYP^opYUIL<8uf8(@!6HJh~afk=ynkBp*7sJvw%}^_Mq3 z@)7yVy<^*Q$3!Shw^W|nXqIMbGP(ngT~uSUYh>tKgGXV!px;p`IA41 zv#1~YG5jla9>BlS%4wqC{x;FX<|+$e*V{GocZDyi&$iye#}wG#{;fr=LEC>o(?WcsgxI{Q(VLdyzKw@4 zZyu=NlKN0t`ghinOQ+U{@c)L3xVNwU#xWeFHNK98zVa0U>CpYZ`&}>ufBRbFn12(G zQ8$zI8!Rm%AD8~&&NCUuPzefMwtx2rL-ecIo+T=yA&8EL(ZP23fJP(LE$ zPp<#iF@NJ&$~|^k{<0c#r~eeKQk6JV`|9O{RRS4Wv!Xjgba3#IWB&SgDq;rX_UY5D z1KjkrE?>TJgO1bwQ@X*yx8<8}N3IC|FFd!2?5)YJ{6&eswxrv38&(zj${ie)fAy;b z+dqj*#RRFM4_4uaj!62Yb#cTXFt3V48((kLX8PLK=q`yQ1)uvIj@ME}IDGu>kN;O+ zldt`2929*$Y8e;*?z@R89t98HO5^aBTj+=@ zI1apajG5qi<5+%UkKDK3#2?~Yg1o*vO-}w&2Z;AXj{%ANQE~krgGU)u>#^KVNTh+6EP-x3)&hdqW}j7mX^rVP?ZKY~b| z-1Sd)(b0piVX%hc>LaF4Xjw(<_Qy=C6tlZ^7?A)m>pHk*Q;4bnKXKqSfniL|)eWC$ zF)W!_)SM*FY1#Q^KB0Pw+H)@+Dc)iCNO|~UkGha$4g>B&=CI-tjs<$+R7|+<2xc|% zl_$YCmOv@C5|I{Pu#|M=K<1HEu{`OEJLn)KX5Umr;+Ktp90O{izZLEx&l95Yqp_0N z9WSrY7ptn^LXpU0!6@tO7rNr@RSgK(10&q#NxKj3nDc&BG)ZY^$uDA6L1F<;sta}I9BDe9I(}$(Po`1!~7_5YgzbY3k*KJ^xDoyS_ z#9AUXXZaBFSqb@;S_ovML`u>6O&6vKlYOny@X|I2tAX6c1|zTbDE5s*&j0dP_g1%H z;vQd||71)O45ou#CCkVE7|yOsu5^A?Rs)#N4t=Tp2fVo@J@A6I#5TTFV~yvRY3Mr$ z6~A*|L;|bBXXk$-RAq}-kT2EyTczSh%xe4R9zSs@ZQ~Ur56CAHmvuB>sV#|zyp&S~ z!4$WPrbFHSNB5ISBdl9{rIV&CeW{&WoT;Q@L%m60WjErW|3|6b_8ZGInGD92EEhUU zth}UmSCU@vu3uUSK5;tu{Zy8HmUSJCjmc8;;)0P>u*}USYFB*;4mEGqZG?pe-KyT( zURmZo-qHuFdhhgZFWs|r?6au*ko>R9*3#Cpj+Lk(^T8Aa!-aNXq#Ex$_&o%1xidCf8hP)kTFzt!lZx7r4D_nA6q;vJ;mx&n>Z2hee{* zn@Yg_kj)Z1N_bE18nOEBB(E$&Y?IZNVFmqa<1o!z59OxM2XI!Cz~l>&vuVQ2;KL+o zG{YvT3dbiqEh70T<6?TqnHux96C1u<>a{aSm9}|mY00FoNm4__VOhcoR<&^o-54g$mQ~l=+?&Dp6~Xu!WUokF z+bfC8)DN5~qt(mTJ?s9LbgW9qvbF5#XI%%X0hF*FP)lm{R3%o7RnlX-Z~2yURqEbp zo5ZR#+zTu*>sPhDmUIX|ny@Zmm75Q0%s;eqnD(oOX<&zN%OUnYBzlICr4^a3Bt%g| zC9^;x8RN9@(2zyZ+f2h=N)MK4x&ZC&PWEIwP%{a(dnc&^8Orf*Fy=>9TbuN{ptUWR z<>_M8;wIYi!5~Rep+^y|*AIJYccmlt&UlrZ#uD}w)%D=QB~X#`adfIJE5duI4rU=p z62%TIsv&lJaEL_rY|~p9t#O7=U@F$I6qBS5NfEK&en^LP+N2^g6_52IR;==c_Obj&Q~4Q+Qs z1tY&;6HqQwx9<4xtB&^61eM<_MrafL)UkMM^JX_YWeF_wF7PhA-Ko^@c(-Wro` zqC{&*d<{2}Obx?&j?K@si|6CyJBR92dH>%+TQ4t+h1+|W4hs0LH6Q!w-DB8D{5mFq1eg@4k0BzL?EKixsyx zGaC-nUMT~pu4`6J285}pK!fF4NYLW$N*bKO)UXItlpuEVu2qhrVO3nLusp!ec#MsR zh>(%dU3l4ueiEGA#VUotd(P-gf+Ay+`DTADTWicRIn(p{qFSxpqRE?AxsimX^d*C- zN)v;TVp!Eg7D*Y9!q31*cb+_}T>kor$*{Zz5MEvUdaBIWk9w&dqYoJ7AxMuy( z^D<4=Jy&=a&taE%=A~?PsIOgcgOFVqgmdfOjLocR9wUMeg3<;q$hvZrEDCbp9oXzT z4aC`nZ03B-CK_G0ruqL5ob*&O>z}J4BgqthUUVjF`fzBtZMk1IlXs|8al?8sfRN_J zW<1;niTeRB2h3B<-%~s33uki-P0L`#eHkbQGjV)>`r!g~IKv~K?UK^3w zmU2{WK@IyuL$r?Fhw}=}f}V`QkFv!$4yWVttjbv}L%;8GTp6GY{iV%J_($Tcu!{LN za8o>91)?K3_7inr5U>T&d58L0&I-3+S5U9d}=6N^Rvn9`uG6!pZY9YD@dq znsB5xG|r2(c^Wcf`boS3X>r0upD(=c+~-g7(*B+HDs|e<-*LR}(a6?^+$eFw*Lf2@ zlX3J~yxzDU8li`~iw!xkRt$vuDVIjkoj5VXM_S%h>IsvdT0~Qz25zvehl>pt2wf2&Bwq4Jg2-=Xl@28mJ1jg#UjBXlwxdl_GF zA!mPNXoAc_4LoNsioT zbb8Y~5;x#|DVrJy^i|xb(ao(2hX6Cus;aIhj3LrLVVE^=**EMu7={4$iC3yZG78uB zH{IFZ$;RwXnKzsZ^EG!O&_UL)=Wr@p>$hi}i(6;p-bFaBy*~=Jy*e_m8u7w~u(pwR zwr;0)^s!yvD(c(yjJd_T`g!%khIr0AQbyNTRL-Xzx#YjFlI5X05ck0S$d3{i_pxpn zqe|4B(7(`bjA!SfdtvmMtDo+>$H&w2ap&>#f8-y0>6uSHhFGO|DNg2P_JZkyRv5^! z?050LRX6p+Xlw08!%w-s-Hzqw-5|<+jN0Ayg)f|2`KesXpOA9id%b_>wwn)!G*ECk zj*_SInHx%W>#*Tb$C+r1hm6L%`gp@l`m3eSUtst(V=fgbe+W4V27H)0l zY(ScLUapAK(L`b?qWQSd?=uzSMW)M1Z#^4ieyh7a+7^urG8gyzgEP^Gi~Z?fddD00 z_ZykY*uNAq*|{k3iXTpAQw`dk`Pcn+r@JUV(;Uh}J72m}i=8(2Lc;63oHu@^C!y2c zU+l=>wb?!Qy~GSJ!8M*9Dm%tG#qQ5e46gTjT+{b@C%&*R8-pH`(Z;mVJJH){d|FOC zxWCb}{p~$e_+c=m2iuz<(Pm=c1v`W&YLNpB~ zr2NcKrtT2?WJfVco2k~Y-XmNgC3g9K9CDXMnK24Dsvzcs}5k`J)U__ymt5P)=uWPW9WPRLpsF|ql zD^C_9MeGw->_T^K97vYA(97nSFV%@PWQLSy*Ip(s*kuTVI;|%r9Q|5w9l0}zSEIDW zOC*e3P)|5ox8ck$4TS~!Oi2O}2CBk{_Kk`BEa;q;j5e2jQVJEyFw`Xml8gpfvWfAS z)7DJSdH#GJO>drVob^rz<0n{#KCAS_5ot)rJLmKv7rX`(+^7 zze2jHjs>KVgxa@c>%e`waS(BNz7f!RbfUy;t`ym_Dhe&H7Gsgeqclqr%~U`TqpD9o z!BV3Ac$~@m-zgfQp%X5`xiZ9v%~|t3v&m&okci`4%;1N}yKZc#T+q%i%$QVQGDGiR z>$IG~TNGV!1?p+pG`gfh3T#mH`5_G1Yw66G2Bs-UVohr$iYW8Wa1MeDGR>%yt z&4o;E$Fzt>6K}3&WJUP1u{=M4HxIwR(Pi}=5;a350+q@ z8GHL{1FJx$8*+Ur)4ZIf=rRaPS$UY9B%P&} zb3;u*pDj)Ao4|@!GKVU4DF(a@G=_uSphwTL2?)dRnyH~bJ>I7B}HDVP-jo5Kv$f{XlOGz?p%V?DG&on{Bx z#fm6L(ahrBf&^73B*Y{Yco(!r-+$X5frOb|Qy)r5q_qP>#T~IuM!!M_|I6GgGFDqr}7EaFkSG2vI}2N(@y6ku=ZG z^fG{IoRBIAH{o_YW@NR9b}Blmtd^i8KiSy0U*%`O**294sirz99qPa)A8wp!iWZzl zte+;}psz|I!IT#qZBYP`YEx|a{rJ{?Ecb427nOr3jBnTGz zEQ@xG-h}1+duO)E$+LnjV`tyT(NqU!?1q~j$aE?y3kUqtI-_nWh9sAZb;iwo%!oe_ zl+@)fRm&P@8l0x{;B=2%AfP^{_e@kJU1_6chVE+fj%F>@%+EH4Sx;n-bTakl$D<6B z+$|d+au@AY(LpZ$D{{{Uye?9jy8>vZ(&DzpuE%nW<4Dq=#hn%5F%W6|?{fVhLoii{ zseP(l_FzFrMYbNi5&i>-qIAaDJP7-s9L0!lTyRgS zrt8r$qK@z4%OjckY=_CZX_g;A#*+7ur0n>SQ?jLITcwqUT$Jk!b!XURWUmLBiwK%k zbPrc`(XI+ucX2_Vtv3S%JJiVnI><0waN~QzxQSw6+Vhh32db=$?#;F&8##4Z#6AF1 zW0>(UFxzvstZu8-J<$OxX}Wh?**lnd895>=+8Ru~u3#q0t_*i54r>cFkTT-W#MWn4 zc`Rexvsd!@t7>PAk(&jVc^xDCRyGXHNH%Rg8a2JlWb`P`IUtjVQ6RqdtQ0ee#8r0{ zx=2fOU-a?ZV}ogPC+Bhj|KrWEG_^U)1{iV?I{H{}pU(WqdIa}vSMwchMcupDxt-?s zFJbClafyq!B4YNAX3uy<>LC7w;?+B-WQ3OqQvi>3>$@-PnfO7N(lncnWRPz`!nGg1 z@h`vjifGKgkTEXlOHa|DkL4>bvU!3nQrTVHNu=EDth;?Q8}Af8%Cn<9+gb03-j(M+ zCyzGsZfpG8t3?|xegl`c2T$N&$La3smrtD<4DQ_xS*O@}D)=@xG(@^DK1E;XJhu4- zr{mFJ{S0!p$D?lKx$scNPmI;f)REmGuT2h2M)gT@Ll425HBB3!HTAD3pT%wAZVMH; ziBJC%8+43`riQS$7bU`U@Q92Sb2mPHrhE30JvWlaM$gJ##DXebi`(an4don9FB~nz zjS~+78Zki!Ibw$~u@1Y|n69xqh)fu>*(|I+8Zma17e(k4TI6AnnHbLIn{3LB)+iJm zG6))^Ld_p>-o%w9%5uGyuv|4Zh0v^#E9e2XV7eZv{ zPo81$%&9fxL1wXMcOt{Mv)jq?DEX`F{$BKH@$)Lb5PYC@AyG3~T9)GxQx{)_gCmAL%EPtf{!S z>Ylrh^LSXgjNc}0*W6h-qvQCDWL}dHJ3Z-meai2;v5Yj*a7spaF807#4|YR=g%%r8 z7ugQy%h1A#>}=S=uBR2g(=M|}wDb49vwL^Xx&Zpj){Zzn4(RcOwGxDi?hX=$&h>2h z7UZQcyw{koWKWX0D}xd4h%Q-2&NmeE+xcv`JBC$YG}`wD_KF>0(wYoDjp0Vj<+mkY zM_t|BvG(0-w^w%-!}Zu1;0o}`v8)u{J2xq^ySRZclGdctbmQs0*4TmbOkjeh7)5*d zU(yXbB@CBK%W8pZY=0nxK$iVbryW(yADr^H?(5T)M`wBpXYCL`Xl^W?4T6+iWg_m9 za=gR-48=8T*lI8yI)zy#Wb!+&J{O?xs73n{w%{$kEB9@A6$XmqAOS+Z<$@yhNPH*N z=3gg2Ji*;)>Dan5&}G%j7IviiupYXBJ1dfz-V8~fb+|KNMFhADrgkHFPqtXAuOQ~b z`W(HB$FSr&J6*43^x>c`=qOVSBTUz!RP462%U6BqUNm4Qr_Z2xesAuFOs>j3&a0s_ z@4=yW}RW5TWD6?itscn+r(yJSB9uS!WMm6`GiPl zzpj`ir$?IBFdMR7aiu^*bKM$SElk8X2i8`iVTIe9biHe_F~IZbRNJqZi+c5}j2RRX zaY{Jg?u0xa`RvRSgIpbKnRtru+>j0vIxAbH-@D@do@=bMoPX@GoI%hky)q7I>M-0v ze$#U$qY=?<7W&U;I)8T9TJgvzugOEw?S5Ih!3o_k-TjNB?p|BM9@z$c+8B3gREw!4 zS`r&?kb^0!%ieR;(K~q@717?z!~+*jSTc;qQK>&MOM;AiOT^-Je-0&IdFtB41_Z zY3lqzDF>#IGVsg-bR$EH?n6^LQfQZ(x9y6LG?nUlk(nW%C<`{dO*jQdWj`TOI4pqS z){u5mX2U*rUXeyxyL*!D%pu;P5sKMUQMO&=I}5Zm=;CfCgq|LUL6jG zWwAT>@aFncyVN_mP1YvuI1gcmIXvIQVH=E!y<(d)R^M&8ZLe;n-EH40Pr6AX-rpN= zue`Wzx7(J@+uH8S8-2{zEneBY?ZM*KTZ{f=lkV`4bN_0qegBT#iY|(F@zmx+^FGJ0 z-tHH#Zf^3ul(@O+ie0p2d?6mDV=)h;b~7YFW}(`MNRTkYBbWiQ%EEF3h*pJzH5QO) zI7`(qjE1Pykm^X7xKyd-B(VBw31Y00EUc5r9ShuJsxD>QY2|}JNu+yKSuq`mm}HzA z2ty&NAP%6KQ*m|l+}j?SfXUkc1Bvup@&#in`Hr7g;66&>XtZt zX587#zOGu!}kTxSEgsFXEh*~Br0ICce zm>~?p8f+>lY?`UTCcOklt?G%lQ_(3#$=~ znVT{Rki+!QR51l2i=jg>k$^g{illJMnCOuVH)Yl6QJE!HF!T}>oRks-X=oA_C6lb2 zfk5nsh%|)^uT+>-XJFgY6QEDcH&h7_1lUwD3#$eLDB4V}eas^qkFN zl|~4pI-(|=fC>&FE-^Kv7RFGuKsG{3+dwXZu(axx6s^c(Pl;jtim$b+Pua}I^^uaC za}x#kT`JjGG}CHG~;2h)ju4XssA(C=-Q2JugTY*eU>u zXsHB4LKXH4*$}{E_zY)S2E97BrLi7DN~%+^_e>2BhOP#ZSHI@QW~ zi&5cCpiA6RJ9VUpahZH{)FU)uVQJ|1r6;k2Kprip#?UtK15^ftrR82!i>fCsJGHtb zk!FBxM$FxSIwOOZBS27=rOR<>*%`E27mu=pdV18ERn|L{#%f8W`U-f)%t^)HWhgQvH5jCB9kV8BhG<;k&y+4<|!3~m&cL!Yl10%ygAVt!C4dcRLq(lQ2Le{9uX|Yfbt1OkqaNjVK~yT%1EJhBvgoU zJyJ6W@Ce9>g3fcZ4T3!}y2QR0G5K1^NU>ajkb{CTJT0VpJ9vxahT3&bX*(daN*mEC z%rOkY)FqjbrX;{ZVZj^|grZSm@Dt@(BZ!DN#1THhu0gaTSu`!}4ikJ}!`)>lTBcAmE%}F>^I`6;?NltDKa*6pZ|6asrw{?j*_BVu`1v*>4#p^f0E&sDJZ4X{uRO zuO3p6&va(uy2P-~umsRr@|$a^q%zU;FqgKpiyHs?)c07qq^7)XKqs{^Kq#?{kXyq| z!jQ;6pToAUWb8-8Kmpb|>1dde$#3|or7Wee24CV-0%}#M1y#Hnx+DNYaJ?q-#xtZ@CRWRR&CiM$ zBz+Uc8$w5sK~0u&5*=$!HPfdE0kn!tDXw-%s9Guku*@{90>5WRF5(9%UehJ~1A=5j zC8ItIe*j5Jy2;(uf=O&bVE(socopsGRm8wVBg(Bp9}yFbD@O>9+>e>tE-O)cbHf8z zdh(SjsGN=^G`SyxMeUsIgS?T|?#wEF%&J!Dr4PyY+@)jLGWa-{Z)RuDU20ZoXDvED zH~mMJb}W1IQ`1{!iG<+eD{qp!^5&=fBP;)oAnOG0lTq!S2-D`FMkZp?lC?50OzE6g(XjGVzM03)z+=j zOwyVGSaj1yRK3JEgfwAO2S(Y{=4Oo}!K1Z#6g;=ho__j&`DKD5pKBlB$Zc$9crTO> z{@sJG;p6LX4?c(gov$4b9DJ_zE+N>v|GPi< zT$THF>#N_zEe`2;?D^i0{0N?SzDKlj8&x?wGq*jJW265=zVek@ZjsUTR9i|r!ai$G z(LTrl(ox#4{Td|IY2VKMr++s8%=PV$E`vHMzi@e(W|(~DIvIwwK6Cy0ALXCl{;AK% zPkrWRzew=WFZqvt>F0jI|Lhlk?ib|cmw$7GE09VV)5sn8uOl86UB2P}^S>p7`=YM( zZG`k+t0Wb>QIX{PT(Z!?F6lVJs&a7+X3?eZD5BDHTgZo{7x-k08%+irsn*H72X zP1f7jTAz?_eiMIue=tw}__ocfUvlJj`WVjpaK`kBK#>b?FYNUmKondjIg`Qy4#t{g)?ykWientTi{sow2l`Sr`4&*p!* z2X^B!4xhemTHMj;WiH(i_h){lWuBmLnDxP)+mgSw|2OYzbd}SmY3kFbuV2sQ zfZ*6MqQ{P1zurn|Kh#eY6O=T3Q_|>jw=*p98Fu3s!R6EY`}D@&IOc7DVe9#4{mU=Y zQ~vDF@CA5aUcsz8(S^|Ytv8P!r(30H$42DCU#CRsA4feUVad%_jV-(G_eJr}x6ODx z3~tE)vpFDr;AIf)b;Bf1m*FOLG)_0)JzkAT3OB}4N zwYGl^EAa$+#52NAh&=H2-iUEH-}Sq^a^ds5Y)N0th!q^X>kqzN3Hd$GJX4Jkl&P?H zTb~1as&?C#(lEp_x3%T??<{0yR)}|+4hCy=V_70-KpsMn#%yD?;vq2$$I>({nW%HH!_AV~nZd?X?Yeep4 zN-+B9Twnis8ZF6-T$-t1e|fL}u~wFqB46E2T2{{3Y$m|Xn@u3*Hj=)J%f#daj=95Z z^%`@64NFu_<_ID=FX~#(E@>X`UzQe$FKW!hwKOzW5TXchcQP5^L7s)0e1+JU8pT7Xo;9I)i$a4#YoYL{ICv$u5Thjp9Hpo zhPfh|Mv-4yR^D_ZjVx#ukz1dM${y9$l2F9)pYDC#k>q1pOA)(fiLB&auBtI@*bitD zIhm(Ny~YwI{6lWGpD4!Ov_KAnqqJD3*{$$m>WhV@1$vAuOw6sFT%1rVJniYPU7Jy1 zTp$GE#}t+HTp0mKDp;$cP2`F{ryL4^Rlw0t*?-}SsHF*Ki(KP_*p9ar6BVe%mH-wF zpVLqgb1d6;nO_|z9Fp1E={wYTj=PBAXptBzsct6!m761Q?^@iu5VydbesK^k8rI0J z)|hMl%fVhsbN}sg@?dmE7k!;8S?6J?a`BATe>8DvPY2`GE%+iZ{~^`!3ihe6Z#^1T zjZXgKY3(J;{hzPwOG*R#xcrx?j%FOhCR8H#edE`q!kYLmtFSCO2`N{;L6cROJe<#h znWEcTrg3YmS9$wVFAthH=@taSB&qJ^saL8^y|Ure(wg4=S#6CkxIIad%D4WpB+qRk zul!-9Wn=V8o$D5Vxb$Op?ptSSYy5|}EYUqbkc+0d&(1rEhQY;2nK-*Q{&8iEM)s`% zb&%(?$)W$ZS8kFjBw3t(Yp3ETYprD+@-4G7Wo;(9zch^iS9@*~8GN~Fqkki3ellUw zo%}lWCNf#J^sM=C)%s3;XIX->Razta;vgpZcslW`HJyHOSz>W%$>m&Yi8cKa`}iAG zO@D_lRPDh>W$He;xO9kJ9UQOpIQK27>BQI8mF^dpbaH-)6<;{AX^lx156gCz@-@#7 z9<1z=Euh;n`>ibqoMCq7v`E;$A-bBd@fsP25G6C*bJrkLiDSttM1DQwW@lGNtHUkt z9fx%u+6P(=N3bwFZgL|S)!B0ny$yduS&=no@W~!x24#@YlTEk z8J7xX6`jbT4>z~bCD%BoFAWC6F6~~BJXn%Jg|UOJ#(H2&ofAO{qCA!?vb>pAkzhr$ zL&r$KOpK){Vs9R#Tx?JQE@(QHER(R*+;Zw7ry`hf@u!Zw*VS~+?oU=_&Foc)1}#=$ z`J+orE=j2M4VGpSj1Eg=u}%{`MPh<%%`90-pH7pc+9wE)6sfUjNzegx2{3t%*D{N_3vJ1Y#N-J$?Zhf$9!El%+(`5^K7m4Kv#z+Se*>x5Z zPL^Y%u_YbR$=sqTtqN%}qw^6S6YJOhx6PDN+_MXvjgLLatbPb`tPu-EY0wUHUQXgY zY{;@VcSCwH>b1lbvy;UR(F}VU8u~KA%kZnu%UMC>#kx!A&({m$oqyESqiOvxh6*B3y zUI-|%Gm&f(BuEpYn4Y}|&mDq1Y0KQ55ZzqHp_R)Hi&vh8j66-qW^SbpgDmNdwNzY{ zQiVuT15HtZuMSb7sY{8VRSG>ermc!q^!*_%T^AL_WT~IbmDg#e!Ug7{A}{W`hZJm$ zff*!L{Z^0`VzSr%3=du7IC_PFI)A2sC9KpxDfgt=t0NS685`f>2l#qxY78$o2Ri=kmM+Hm-Co97Q%zIG*$k75tWa&%o$^7Lk z?#{)0xW$zFDj2$C*dR9y0B7U8{YCN;r%xAlKZ*_X6*K~Ba7D3UhBvYILbgZwX z+Xd(uc5DWJ^iXUkxzdNM)A%Y;d4h>tj}3GXc4QhZHob(GZFV^Xn&2iV4ezG}ZBP1k z>Km0ZEl!q0Y1q}=P)e1_RSD)(a99R(m4WPdCy~v0e#E}19X^dzlI-zh-&b>%5fCTi z5;8iCZ2l)t`a=s1`W%3Bh?|43uZrTplfleuq5`^tIdPWL@t|v&SUfaD2*BH_t$vSr}RGZt@0g}vJ%NMXt-)vuI-u_eSVcUva+OM z%zaJrOD4(x&1R#Pn}aJQ#IlT8`A}I*$JUA^X*l~T*H;$zUu_Iu&&!3sB=>K%nh)-W zBKFU}e%Bzs{ZTf(pDpu?{qw$P&w||f`tk01v33y_48g2NLyqW{w%{aiqSmsd543x( z(>B$FlX6^2B=2+UH_6PE0zQGD!&Ozd1M4+zmtwzT9d9j&ytFOGvCrzrJqlH0NAgG5 zzrT9@A-ZE%NYDT+z)X+HWKh}b%$=3Im&tW0_+myD=U!is{>7bJ-VYSA1v zUeN3~>XnnlC-VjGJ;<3`v(h~nJ|7EzZ9d7v^QGI0yzS!doMhQ>-ry_aX7uwR%Gx?t zTK&mSNfzCexOP=$x1MJPVav8mPYy)+FaFboi?auDI8#0~@Mq$w(C$wk#%qmcA-=S_ z2DP$`pqW!AKyUj`5%cbZYaY6JLwtNB;_5PHZsqx`(Fr5y4?zzxLrPjJ4V3a^h=Bx0 z<;pGc{wzFT^;EzBxEAZm20oL>S;CjuRo^I`5jEsKIhlr4=v#dvTk2JFHA>~H4*&)7mEr9DEe1G zayfsiPyN~MQ}AY}E}D?S*`8d$G&-nc?qU`x6+P=Gg)J`@koRD?50+Q5mOTS>(LV^^jdz$4iy! z6*XZ@*pQGuSaoA2URWmOT;TY_KurQ{qK&m{CpY^{J(8WwWVq@YiySv%Y`>r6oB)cU zJo9?Y#%4Vr^0PCNjJ=r?#O}6iuhTosy=S7)%p*x7HHA^wuL{zmp?zwt;(hZ9SXyjt z|2iR4B^)Y!EY+YlrY=Jkww_uPHY#P2$zXk)XC=ZssJglTAQuH|2-m`KQA<$wVsd)O%d1n1I~bJO@79X+t|T!s40Ua zQO)h(Yz@hAN>E0Tv!+(=WIU7k0JZwqAdd|6KxZ*nqgw)94Wc%TMkUqaM=U^c-1}Kf z=4+HfN5KZV!LTYO${avN)D~sbUX6Z3AOxr!gTsb;%&sl=}e(a~FZ{GA8h9Gt=r8Y?R_vcM!m(?v+sC4eT<@It~B{)V`(eJVf z4V{M9V&nNT24>S_^T0IE9F$a7*o$M=sm3BiR;(wfm4&wSPlmNV&k7p*+#-1C>Pl5K3d-?&S_Vo#!a2r>o9Sl z#RJ}HhUis6R6@HHV#PY9b=)Tj?`XKSoJ;vSF&)Cqk(=~*Pa;1%nvl?>=es;( zPAOTz(K2nwSRbh=>9(ZyY^JH98dIrMxlBvP6ocNNtOsL?)KygYVHggvB~nR(Ty%Y_ z&Q5qV3$ic;X7^~aRv=j=i_t-%+5YCHod)nPE$mam;y4JjL+V?V;e*A07-VQ+wu*@m)q=4F;A;|j2^RZ42$q@Z zu_-01RxDJmiPFwxu~NZQGH`W=TE_DzHEZLN&Mg#5FsZFKtmCmh+H9DBdeTH+r&|o~ z5>-sop|tQlvNJ4~(5OY>5KpFg3lWxb)f&{wRYj<;hDf>^Cwp?VEW!*@Jf4Ij+qpL& zm_njl(guz;K~QByO^DY9_CPSmqgjACJI6RTLo(~l3Gc^amB1q5y#?P-m*SA%M5~M;m#omiD z+7ckeAs8N(G4dPcAR*DQgurrnJ~XCA#$4-;~vEVukNcXDd{qH^`9{8DPdPq!! zOn`;I<&_pk2B1nO5;7~~W5a4TEM+5VsxZ@vCmq$DEY44jISiC>18GRIj1ndB$Y3H9 zicXAn1cEGeO*vI!6{0hhHB%&3Q}1DRIK=c2GeluW%B}@Y2{Z=7pV>TP7g_;r9DlZ{ z>w@XfMI~ek)&vlm4EY{GW>_{;2`_N>W3NN=kzy2T3TIB_RR=0Vf~=DjBW^m9fLjOU z^)fH@ypgH%L~6iQf?>I-AERozo*qiXr;*xy_C+Q$g(S+k?qf0@ulA_%vVU0iWZc~C z>hBKYIHoh`-9qCDa=8gC=aj9(b1Ww{cm) zWsHx5)aNhKs2o zRCX_SAA7Eyt>m+@zYwzD)!}0rMdsZ+&*nT(9Vsngeb)t_|6YD}XZ&=R$+#m^J|A&m zL2rU{@ZRmRYUN(B*O#cIpna&FQp|z+q=>Ni!@Yk*>B+8+_^4A*w>r^cIw^K{$QPf- z-Q8hO*&ML7Kz6+u))dykJ=CFr)sWkqU`cd6c-yLxn4B>DH;Se*#OSB#kXld1{+v8@j=qrpC zo9Z)pl=kNuc~7GcG17R?z1Ga1(-`UWzbCV)&cicPzuwXdJK^C`Pe!xh-e|n3J3NJK zNo?9GRy7aLNQZmpQKb`=G^{LcsFS^2+F{Pv8f2G*O7w|{_%V+3NtKz%){sH0%B^&4 zGVnT-&fJY3F}Fo@w1?Rx~o_>M>sHzkC;eba|I}EZISJ*{57Sww&=7F7Yac}<281i;+<{pc` z%er*@%s`5Vn{t6paIbvDyey(ud}c@S_82pbIa7y!H9U$U8GS8eOmca+i}iXI884g4 z-GywN%ZNum)+3*l5cg34A77Vao8E*pMG* zp=h5CXWR~)B}(?BhAz)%{2rY?2!B*H+t|RxPL}QQxbopkcJfD}9_GR~6IYj5IP;^T zhq(t_G(AQOwY1sASPnf_6W{hrfn>HtoU^iw*|Bu_8pV7s+vQSGIc*Hj46-vLc-wp< zGG1rk4ToGbXa48M_qKNnZe~u_(PaxovV8T9jC&uQRtO!*TKVnx_+imIc3CIin+TSR zxbcx_GlJXTj%s)Fl|8QcoC|r}a3TRQL{YVHw?zr9?iMZ6l(UjGH}{&1ju~z3kbamA zyNk${Ww(fPHZ#dahVLIvl%vt6dl*hd4D-PxviaEE<5o6rgZB%tojm-)xY$}96t~^h zK6UrQhQuWD8VC>|kVV9Xffx$ST}6>V(R%rvy0>4?khF5%>$;~-ojP^u)aU&=7wp61sRX|tXMee#d}N}2EiAYXE&lru;%sP+n&sx zy^BZlh)ABr5a6npl^+JV;%kBKHyldn41%RzVBS-loeB^Ff%l z&J5W-!GvscT0ggz0;~jamJC#S6=0LD4WWNJSl%DMD7!+jG>;TdXbQ<(pbAGu?%1qX zyNdL-9g1sXGT#{zwI`AcRy&Cyz%GII&=hT3%AhhGYx$feK^8RbL=RT18$z>z@dkwz zjI(4{vpQt3H4A8y1c2pVy2_e)>+DvKzL2S7wqtfsD6gC0)ygqQ6wZi21Ip!RhbVuq zwY7eiXKU{7Lu7H^J*9O*s7^nBT>F-M|w1C>2yJD|)H?*7a-EZ@Ll99rqn zwmW*JgDr=h7q|vXxjqYC48?obW+UVRIq3^@C<)f_IEjiX!HQXU$rfz$NIJdSv7BfnM#L zM&lz)?-uM~ZUk_j9bCnu>UY#VTMN!F zwYKtXx+lAPxjf)9sh6SR`w5#n+MHb!+=*UybH; z#?6QF5-9dDCfoA0wX-f8FCXG21o9 z@0TKb1m;`2;By>(ZR*S%$)_`Izak!`$Imco zjXRA;??0iN!@V8uNnL5>yYlq~6PtMK#*!gNr#aJQeuNUv2G+J|K6Nzb!|B=>kIKj( zo8qBw(BevX*5EGm+|PS_-LJhX*(uY*+#zq9Rm=GMulRQRD1J(@;JN%n>ty~ay`W|K zN8^B1Dq=DpX&~?C?MELqeHuf12|tgqV9fJATI}ZYe%=>u2;=k#Zoe^!%!k7Wy@`_rFC_L8An7P6i5&WU8+qLACyOt=}c=h4;JlG zE5H?vlV^f*cnzWkn|iA~N|;O1KO9;&Xc2LpVa-O-DGzDP&?U7zSmiG(m=G05)G|~P zhOi_pXe%r<35-k2p)7;>U)z3A59PIBs^BbXJ}oFTIRsBb5~iOGr3Q{z2vK`ml(Cm7 zNSo=JUd!49(2xUf#%CpcoM*IT%{+ih&z5jd|LU7lr z(mSPKR~F@~0`kU6YIk3A~2v?S)NN(luQXpP`GhTKU8q^r)Ch z2#7P<{}CP%T?JGY18b>GN`OQ6n&h1EGqse#q%^N&u_hIl>mIF-R3(WCdd%w!m8+85 zp1A4hJ=QMo)FrJryTg<^v9L)LRAOQd>J;B~C2&ejUK%ULR1p$gOx262{z27+jpUmY zPb4l$DNR!tSw30a2h~Kg2#L&b)IAc>$7}Tn3Gf<-H~6_PJ1|tGt6B4b7Uh7`D3O|B`Z)kiF-4`L}V*$?6P zH`C1AEzyzy4ql~sMxE*fZUeQQWwtA@#5Yy%W0(_ny^O0^UQ=?U#1*7%N5F|%+5BD_ z+hAx+Z&F5G*X#>BT^~FWtnSi6I^D+hsB*X-dO?_Rafjp}QS$|oQ*}kF6baF7tTeTh z4IG1NSpwYzu>2^oBJ1IWMAOV0*x-K6T9GvW2G-JpDgaQUbX5F(q2C1&YP@nP}Y@-#QkU+X8>jCCUh_OjV8zpT_h&I`uO! z?IaaYJI%j_Nfz2EZdZ22HYAb|&?pd;m>v~YmN=6$hE7n)G)AS54l5BzOi3#}5>vtk zT(T|MdKBOLs>T=fkb%q0HhsN ziGDETo{l`EUfQ;o$rkFEE3UO+F~p%&2^GfeB%pLKcIYXr@;6p-GW98>)I*kan%;%^ zKx*ZP%v$+>|C`xwxWizs*!+*~+2r^$a@zv^Y=CG(8I53aNK-7D7)@bFpbAnnw zBQMbo6EF`NY(yn28XT8xXfUhdrC%~Nr&d7SvXz1AUqYf$nUW=y5%ExlSGAa`s7Z>I z0d>@Zls)B0)<}ZN>LW#=^oOQa(H^0k3W~+bUt2081y;KutxE7A*t$`)pwvccXRSma##OHpb24j zii;ks^yZrzmQCTGIEiPpgFluZ|9F%7w?9B~ik>@{yhAlEUp{$~;C4J!DTW`cL*Hkc zYzGIAYqk_5Z&RBn7|w|*pH<135Uz&Q+Yi3kRwHh0g57?Oea^R52R~|@{DfqU;+-#k zu~EF0Jfr>1+ex9u7ryZA1NlVf;JwD%|K)%3=R!@B$Ecr!r5fG-@wF$Yk3VVOd1s^A z$8i^SIc;nbEeTCnasrhcAZ4*Vfp`+f*jeaG8X6BlYWKYU&S3J-402 ziC*!EPuL&+@QXCmyGg&=fmKgXB(%=q>> zAJVxmG~Rm$PfKr${CoVlC9C1x>_(A<9zAN`l}~&EGTxH@4i{FeWjKaAI7t5A)Js!w zD3YsI zKveSAhUd2L<2wqMQxyK*YxsYo(#gwJs+fuiHs`XlksKm(> z%l6xUc7rhOmP=nHDjGF8V?{q`CFEcn zzI`LrvZW3#S$p_Ilum2OgChF9_u87KMP>&@iZa6SzIebGhB?*f-Rlg&cP=wVaL~r+ zQ&(+oj~F+XZ$QJ1qOk{m`!g*0ll>>PT%0j#55uRS`aV2&yS;pXFEw@P$l!+d?)880 z58&H>QVwoU`lYsHgx}CI{_3w%UbXIza7cHfVC8s^yf~Fh4&NA{Hx|jS+x|W+gJkto zhc7yEV3I?q{m8!8EG3_lpDr3Wfg7d7#{Vk+S%a3oEcCy3)Fd~g`RkOyigiP_-pxLb zBe(3bn4f2#{DHf%ff6{BrKL$ulb7Ww_;Mjj-KW72b&I6CB%P;IHi-)~hVg6M znpPoG#BdjFKx)o6+4r&*sdC3cPXMVL?!okc0(?#rA%+h^>9tf<67e>cl8JJ=TtWdm zTYE%cl4v(3Nd*P6p);_-O07zo)(A-nI4%^4oH$X2tpbWvDgt=iIMG_%n=^b}OnA(Y z9TayJ)j}VHiaN!H?9LWgQn%nd`Oo_xahuvvG!n9;J!j1LiKwzf6$YM+LCer63sj;J zAjdTq49Un!)k>8g#8Ca=$hl6W7SfGl^3ry=g|rFFLcrf$i%M&$JQ8fUo6hUzYH_4R z?x*i*8}WgsTtDKaC2?znGHaNfgj6&dkxjR~JV6#|cz#?9h27}gPkq=W%h-fYRVG#B z6p{lGaw83H?XBh&Qa7MEV$`IC5*NhDMwgnR4T$bq5w96lB79L<;LA8;ARR>FTjQ@Y`*U=7(3-*mthbIzFZTt3&Ls#YdB9g72<2nA!acvl7Kb zzDu!^Fx9WjdoiesXyqgLKbyUdu-c1v|M!y%iT22wzc!h-Nv*km{Sm3; zeRm)}rEXm`6;@o+GE|DIYe|ZQ#&7i>@~6mqbhh@_h95RBsg@>wq#ISTS)L!9c*CQh z$?I$1U14c_Y$yBu3&oT#mur)EH}Q?z-}KMZuW9MdTGJLbt=j12wY=ZEI`U<2dPcjyPokHb z0@gWX7Lcdbz0?Sj^yAiIRbQdL{`oekwfRgj^4GRrxJk;lQn^ZC&MobCQ)*Q%XQqCU z%6LY8O)`}ykGyqF_7tgeo;nVrxOS-8v2{GA6K$?h;DO5wRs9EX!B$oRm1#}IKN~<;>J1kRGRH}zMpsP|@gexiBov!%0FISk}U8ray`ob`k@tM4` zF0x{kcdv73@pTTH4XV<#Oq(=N!XeBtnp#7l)K4F+EctY{E^X@Kx;;8>X7#-fG2_D= z`V5TKRm2g5Vo9<-1XqDdQJO<+iT%+Zt<(Pgql(YHrZZC;eQ31I8xdTU@yHtU z_ec0N2PPm@K^u7kWsYSkS9RebrwX_zQ03^xwY(!dW@LFipNA}I^flP#u&f(|uqNJo zj448xF3Toe*pnd2Gt^4VX{yqU*_lhSsWsh{uMBRx2|q-mcs`tYr!%Y5=|+siDk-aw zkm(E3h^^07x-XIE2$IP#yILleMiB(9fjc{DEmYAUXmATeml8b0pbO4Ry7#jhr9OO? z)~6hhe`(RrPVzLLzo%+_V@;f`>WcLdt0i}Nz_*uqAaHh?~Anv6PB+rtEYgr8>I^={%G#MP1G z@s2qUd%M8Bf9->uc^(?%3sQaopfYz0 zW?7KeRZY5q#0S469)gyU*$bOTV_Jc{EGl znJ1AOkzhh(;z;+_wExosP#Y%Ck4HXGLI&cZBu$|q0+tON(ho^EV}r}TLQkG#3}PQ2 z91I^_j+9|oaYcj#>JgBCfhXwZwh|l!O#Fiy9Z9lZ#uL@55xuJy?#Vjy-fO(ZTvstFtv4 z7JWbNp|tHT+Sw)PwidkVLf@k$sK+A1Ar_A-?=M+6eXpK{)o$I) zpOP(fx>V0b=90DImv`@-X9q*Uh>jG;`1Qm}@Q%FvXoNm3UO`(pBQcl+$pP9jwUZ`B zngebH#caa-UN>J#+5sI+2AL=y6)aOj{jr#gC_Klk6_)r+sJCUZcU*;JJdG|7kdR#{ zQv-)J^B+CV$zs^^lySDc-Cy;(S7-QC<4ND`EwqYt)YbOWY;k{nT(LSe z7uSxS&rT;PDHYk=MAUR4AvB)Zqnn0oXuQuKG;;SI!7l{U<_Xg19Rq#3v`?WX8pyJ~ z4TjwI9y7UT^Rf)+CsSyFX(ySE(9>B{dmNS#pW=z@^U@u(7SD|Ce{?wRnCnkbyj(T`4auVx-hP46B!8QQHO+b(I;sb3M#MbtBAl0NIugH+* z9*|Zz`e;xCMA&#l+b>PuJMd!EWRD2Db_^-b*gnOojYx}}OOt~I9vBuH0zm`Mk0^9LiU#NMCfk9>`hGHM|p{P;KQ=v8))g`;b-XB{h zN39d)w763b^<{h}z*~4k^)KY3Q+pu`r@LulF*!%oKI`Cjy$ zZ8=-Li|tS6^PxU;Z?ESPeZNnE(VsaJ&YRflgy(D+Ve*;t#`}@m{uQr}h@-c&gwjNP zODW?w0vCnGv#VUD<29}3=Xhx6<)@Wn4WsQzy8f8rO&-2#M$l<7mw0|KcfA%SE-=@q zX6EeIoSFJ(&m%c|WQt>+7Y*LwGDg%{mNjV>WL>ba#1MZkcq$@0SK`O!+eQCM zFY6QxwCk@kr#`ZP-Ci|YS2JJxr(I@{`&otxUr0E{BV)5GFPOb%KQ<=_YWB}xb8O8% z8|LkqFdsj5F@=}2VMne$c*RL<39f4g%`^1p2Tz~BkPojv z-*yg{b26|`&+rq4)%x1ge6x8{?&{V0(rgm#BdhkE{6w@NY};$ROc1bR-njDo$p-T=56m_P(vwi#aY)bUS;^4$(=z=1w4s~ic1VpLby0mnVGYDdl=xX|qMQAqlvA@Z zjjEHG$Wwz5a0}&Pgc2hSWmr|TK<16Wflcd<$KO=3@akO525n1=33x{KLWHI^#=T~uONzaban*> zEimQ+PrR*`ri4CcQ_bOXr!}(F{=v)?IB*MwS7N2r zL$($ftoD-7G7BjR;{5{Wo5e#xdrKq^2Y+Z&qX7eRIG{5)UffhUw2PXG=Pa>Bl?r9A z%1rapf7M!tU{Z{g2a3AsRD(*pw#NmfKAp24VZg^VLn}w^x$-h_T2g$>` zh?>7|iHB_!o|~EQI`GW9HlDB{GeVe=tD>*g(P9=kB~Ap4?rZUBne$E|qn^T|)W!Pd z%PRI7%e`c(_(^^l<<22oXj4JzbiaR!cdJgH?xOZBV6PThF}csv54ToJ<=+$VkkQ>y^Btlj_l}WLsv{1ABZ<>=kXmN^P#XWy$hQS;N1x$uBByB z=UI<{AkzJ+N*P95ppMEp1b>LFk?aGcfPFqdgdH2@ZH{VBKs#IsagA(_^PqU*(;iA! zEFlkQtSI*1C`PKDUux2ZSTa#tO#q?>Rre5+*jbmn6i)K1SjRE>iMBSsBC%t0Pn_Px zu19rA`Y0uvt~IF2+e=hUQ3RkMBRkP~Z$=@lh@0${n6oqYN1l7Xr80m4T$^>g)Wpb5aTy#*y=g0Gd?*L5~~N{P3}$E z5rPhe4U~m?2nOxfoXSB;w-m!TumSm;a7PkKVoRBoFDQwD$V?fN;j*;#Q0gHB#ZsV1 zsdT~!^d5bcI0TufT=rF8A@Hprl<851*NtP|2_!~lFfXp4**0Kqj#OmUkTm}~_9S#9t94yB4LS(*-9-48$~kDd`vR0oGK>4 z*)a!R=q_2x`bLfLUz98qtz!Er202oA!fy^rii$ovjfV+^VzxF593npjTJ2USv14J3g< z<4L1VQR5p3fM=<`b{@n~Oyn5pkg5rka(rN>n4&OLCd<`w?CNGZ-)N(j`?=b1K+LO| z0}KgLX{F?pG=-{r?Z})<5I{Y@ZpF@F=(Ne0wMkZCdQ;=WfSDkHJM7&)s&vn96bVW= zKj1jE1lIVNXkM9&z-=_XmLIe-sgj9HgUKOQBGiUbc_S~GF^=P$7NZV>r0y24q^xvD zGSDpyd%~#fA?O-vf(t>iN8v}4V7W+Z4W;Q+GeO*xf+z6e6wC(d&Zfn4^KHIoK*)lh zp0KZ)X1u4^^=uIZ`knb`XeGO|JF#P)pVKYHYt%kjCXDBt|Lv27%|d6Sqt8Dm<7|R+ z8hfd3SD(Egs}OD6oA2E%;e}{q;y;Tjyl2C8Hd#p*<@UqZf*YVj2wxZO0k~eHGwcLy zB@@hJo=TLqkQavYAR{{#)KC&{&@C+4vSEm1e^4eECL6KZx=B64uy^Tkts2~|Cw51< zjH4EQ2)F@D^>D!qZ0H0Vq@l%*b=TVRgVeKhCxq=s7${+0BGvRT*LP9Ea7}xdcQ7pz zFDBgyTyKO?+>*EQq|-oMS~D9*3_e$9NHArbADQV_)R?o;@U^)NbzD9_YS=C2uRlDIGtHdY`#c{9iTunnLF^Fo>PeFI92GQP0yRNH-Rm-tX&z3LUBKY`;-b1UG>}73Ud(o3 z6eUI+YIR?gY$c;Gw;h_HE+H~DmQmbjIOW{UXHh1rd}~z?Scc8$)+$Cs3<6euxGlkc zx)Xv^Eoj`p9VAN%{%X9BCI~pInw@F6xlA7qfyvbl(JgR!W#DD7%14v0#I_^hQhk(n z!Jc-g=G;8c6FIXU$vkwnj!XVT_Z4=Q((AZ|D?e?zkZH$_P;r+#ypC}^^b)!4GuYzo z*ok#Gx(d6(Q<38^98E^}r7@2O*l4u{pzSHxth#QYw{qfn5!Om^} z=Y+l(-0)uifSYY2-^ShjD3>H>eAMM32GEiRHU=RKqKglNl}UP=Dsq1Wi`d(0XTk(iMN4NtB#2gwmm-jyiNsKf@xu zD4e?$TsyajUj-5V$I`YPWSXN}?O?qZX;7^1cnmBwO?Ty+BGUDA%ZBWePPP$!l4j>2 zTQc~dj9I4_kT-fkS`3z6P5x~o-2d>ka4O1ZCks7vp7~+SUOOhv4p-M{IBpyqr{hJj z7qgQrMDwEN`2JM0(d^g`b{vqC8^M=oI_Y@&#*RPV_fZXLQL!5v$m{s-{@CK!Xx?w= zRU5}YD!%qWBph|<2OKji-4JLO86A#P$ia=APG&y0J9eidLl#JxKdvr%*=I9WhOCX` zc45fHhCrdgd!JEZe~L*Po$ggeF&KwJM>Dxk_#6&D)i5wX`JWL%EU2mho2nPPREgt= zN#07NFtau4k){vi4dIhU;^kf$I1M%uk3d9@)Ye)W_kZ-NAqKRaVaT~&W4kaSerIT~ zx5z9=L{<9YePG(*^5EUfXAgTn#u8UQ1(i+}O+zjYX9&HB%QP-|8Zw9Ru9~Ww4>?`4 z9cx|T(YJ#`nX}%H=2D|e*Savu0}Od&o2}@%cTPE&4%k9AJ{LxXb>T73lSSDP3E3$p zg>?0tTK1$*H>KhEe!&wsAG_!}_I~dh`*sjlj|aIDXJW606XRn&|LV+#Zjp850Svx+ z_|aoD1s5xs*ic}2OuEPAWR0F>85~0JK!YwyYdLReUN#{vP*b$RAcW{mm%#2bc*~~H zBaoE`Lc`Aukcd5SH>Il*jY$2d1Eex{wH$#sA+eP zUvIN=wU7E7At7R?Y1S}m5ixW>z2~@}@83J-bA79Ej#mu1x7KpB6l?rGtrbIvaj_-w zF11B}Zd{bh+(Xa9bPMlq^x?Q?7R6Q;~Ew1KFY<(~&&o@HZqDF>`)&u}A0Y$9y+G z%|o7g#Ui%CtGunU+s2JtRKIw%Kf|T9$ESKu?cud8-#<}sXi=NJeX%N$!qPv;2DCf; zLI@Z@FdGmwNP-eV|M4I}|6z*YDG~eL0`ZoZM#2XuiRcqKrjRLtqjMC3bZ879fO0%z z5n3uGkWj%=kCCC|2vTaKV=7LkSHd`Qc?tUZR0)iZ zHK>CyucKHzdpdreY)P7-yHs33dYm>Y)o3~pgH!1m;S!5eQVGVHaZG7it;ipINnV*A z^x%>vp`GHYqHiF{bgw2+U2<^z0;3DYH4 zT#SJdl#ZOGhMlO}8BUn1tg57I&LpGjI9ClJX3MeSK zmoU#}x}yonwG)SkZpNam=a&FUB2Tvy9wC}w5>B8C2!LQm6$5Ex|-WTx&~& zHXw5>Ko$Hf9byW-hB+aUD1f?EB^a*)OJI5OibXQ(F@tjhH{n$dq?DE2Fuf1+>-f4y zQn)XLlM<>_kDv{xmViwm!My5!saAxWom zi?HF>)?!BLC-H%(8i@_P(LS-3!bsJeWkpI+We9N%v}#=A9AkMNSG6`|e*0GHNNPS;Phqieiy_7@9`A#e&a0F0a#*$ellseK5z+NkY^XyJ(ZuoRY z$z0UwC7C02nU31y6@IDQ_)r98iA!NgQ?$gOI_>!BVrAmjKn3XTXAKxCK{^BvPLVKi zN?wj6PMnls(AQFoCqQh~GxQot2{Gxwo|^n|#(D_ZM&!T}`G-yz%rXEsm0gdbL!yrlZhsi;ZR060% zNL@W9l)y)?s6x^ab-Vu5UaBqw?aPk~U)OnxxHYmf}Dm}3tk zoE}A=x09yhDs`;ONff`9!lV>PV(84A$^=5x;k|(zQHNHPWq>VIsiwlTdq$;`ptCB6 zyr|NG*pMV>o^%E{RE*T<`6Y}1mIem}b~CJp0W7J`QP)F_&ZuHgsxQ+S1Zh2ti5}u8 z3Nw6=lp1W}Qz-=%3Op-EwJ>bZrE16{R-kIBNm7h4Ym$T zOjB1oK_fRoxCu{aS+iU6n?{lxN?tE^QYCXxV&HZGdCTM&*$ojZql#4$tMmcan7L+T zs;F`*Z%Co?Rv7hB60*a?oV$p9Yot*nDun8%I4pWNq=hP;i0dF}QFfn0D~4n>!Ziem z!!?dsLxpopgDDZ9mk9xFNeRjF_a+oGH0baZgqwEHB}wzDz74&6t1!xJl19RM^g%7z zf-)$+YKvF#Xv?w;uv`U}Kzc(5yIX(B#N5hF#{ zph|`^f>iy}8gY?l11UKW?j~%LkoY&zl)7fAhG112En}Th9lf+AfyT!uo+1R?@qf7- zI;oFvvZN_XCU0C@l~^>(Dh*6?lEBfFtjc~9M0FB?e53#ASOsfeWfd;OT+CD}Ly#~O(W29y)DXdm znY?`Wm;U-0`y2DWp0Mv#K3FtInKu;0|uf1eL`!Fmilmh#asJ&V% zt+vu8Q(aO)OG!eLfK9n{Qsse#qO{viqnXtr8mJoD$ZGLOjR_EnE|!EU)s)(sLVd0! zPivb%-K~|hgl)X91tk9$ACmg)A>St3L^5x@D5UYlQYzwwpah8j$N${;`qw#c`FQGZi- zK`NPlWEYoP-?lf@6;krVb&&l>{|M(f8&L^+@^<-RNh|Xjd+p50Pr;X>U;7#&Kl|0j z?Q73y?{n2gX_YS}5-Mj=(7yluOl~`PxAC)|B_*xJ)zG)q7uZh@rS(csKc-!|T)AZ+#M7@PL$j z<>3kH;NU5({wCPC3rn;VeU3ce!=n|Bq43vs#NxH=2oB4VlC6`PpsjZDlLSYO-~j35 zC-HZM8!FttebT=5)@`@phwXa@>KW-)AjkKL)bLp7@{O_!JZay(d``WzCGSwHRpTcI z+?~A`KlLg3gB4!szE|Ky>c%^GczSz;7pcoPe(9I+9kumi`{tX;qaArK<6;Z#@T&Hn zeDtH}ms(Xm39a@$`BAa;WBKMcDUI_nh2(*53x{v?Av$&G^y>C3d8K-Lge$rC)Vb5U z*OSw$WW?lN3ddD9F2no>D@0wURX3*FU>hSQY;yVX*8h?`w>^Dm_QbqtfDM)sCO2-} zYP2*KHze&_=$swM?Y9%i0lo@vzulhXxndouC+!yxj{cj*|NT~~)h6547WG8$KSOVt ztx8Q}dp*EYw@NwOf&G)qco{o5xN(wEkR<0n06Y2ZlowIA{{dK8q-NRVO|+_qk^_Hj zH%?YjIz;l^cI@+DsDW=hq1z|7Vl-f)9UOe|pz-8?mGnD#fNBRnZ`^qC&lqz*lVE>c z{`60|0J6{Ib8zn0?LYtL@Ogg_?a7}Uyq*0(4*rhOqIuu`m$x^5at=}Nz1A|>3yXul zcsm)Eucsb-@#7z7 zG~=c1;N4o;6u41jK>hTmU;JWL(bS(DeNf(dD|xxYSJ~T0VGO6~V2f;vG%R3vJk-}e_u`_{J^xhKzM zKV9s9p6P1q$Jq~8%oA_E+4_DK!pB>P`iK8eM*k1${&0ncf2hId_i5>(VAL?&(uh)7 z$xBY7&0~-MiQUOu1a<9CV^g)QZ-QLXc{A2C|`n-P6DU9cA{6Q+k)tgszg{Yq_yaoNN22k?#(C#W=N`4pR0NOej*0ZnK(^3t8T zsz?cXr4SwYS4OtciI0A;gg`S!+2*Q_)(=BitL185O3|{^k`zYe31CVWfHVPsi1@fr z9C?YEvZlz@ox3`0p>Cpeqfwy|CZVtf&HILYbD1vw$Ul|;E+lc@x%=e2h=)hy&;HVH zw^iJK9{;lUe7g&F;m?ha3A=K&@^2;FSKk0Ng%3xhe<{y<#oTx0L}4^<{3x;#P4I43 z@yW0GBpLNhPMJ zsp;<^Pc^7DJ8LQCcLv?(Q;svU!KtJ{ZS*^pKQHS(YF1?}<>f*DjU?rG99$}G5Q@RE z5_2yMRtckW;n?$920r2bYuQdY>KE78?q96Es{Qc018k}~KeN0kbyeory;#}Q{L445 zlu~Lh;+w5ZJvv)s_3u`x_{GB-sa&zabIPWYWv%^EK2q913hjcbl|=tkDNp{2%UVgY zxRrsfspdNyd84)M>koY5`IMLUaN7wpyKz+cKHHRAC;u9*nX>h{2I?hg#pRh-%e)_3 zGjY6DO1ADM+J~auvX*&gztqY)ySC(43-#+(+Ww}zhvm|$a*C>b)$;Ics^v$&N{>)h z%3WK0WBc2$ZltVhsgLWFwhGxALnII5snycBQVr5Y->PS4R6AL%D4>_A9xTyXO@?5? zx^5tu(rZrqZNCkIEp!3}YFea(=2m#b_v+_YE(ow!DL&bknR%X;;qIPx8PJCQe zK9s!4u$H2Y^&#>O84vR^gQS*a2T095FQ+BYK`xd@J7SW;!wZMUd*wm&cV&_n;y9C&G6-!F>|rG8OGr5gRwV-=rBBx@=|+^kHsdyo29>e8bX%N#oY zmDqVk!8&zaTKCa)YHs^wUKD+3&G*y`6}HD?^y|D;xrQfxDh<@&RcTNvti7fMb7w_! z?JCutdP%VaUPG;UXhcO7d|XQbDdqh>%VgQAMY`RfId+wI4LbV+K80$qK-QF3ugKg4 zr95{N{te)T;B9wY;)MWqRbG z+Lxbbs8K@^K62`rD&bw{&n`bYuKf$FJT)G(v z7G~9jcy%wAU4+DjV+TTh&t{}2iw74t&S6_AdEd4}(~D;NT^D4uuRGyE{veMH=5-gi zgx>CuMtXr8FrIA-s}>~)_cmrLn+F$34PM&-?W#V&QN*XlA)IQgA)ZW%@%hnAloe>v z(fm;>ZOLoO;bhcAQMfZ6EnX<8s}-~Vv1G%1&>B(TR)@!h_v&-H#x20W z*E0^D!%Sp0?R}KwI<;2q5IpbWJ>HYk?L*3kAnA6#*(nQfWzW&sX2I9sVupfRH5bcn zw$87m45umfmb1cLZ^h|O@<<>SHO8HkDgDR0j5}Dai9bH>er1%CcoWBpu#X|A=?D}- z3A|j@W3&=eyb6L>#OGKsfsf@;!*$l1P`yoZ3sl+MWVzwyp()QLW}dus_}0Uhl?}2b zGx2nqK@8%$+t$Rc`nOit=T~OdIm=N3x1zk*d&*9PQIrdqq>%J1P?1^49t^yzTo)*| zOjaguNG4$=;f{_)Am`GrUe&0d7BAEXf^k}pEb zcxMaqEnf+p*>c(Aqq>W`c^P2uVKW?~L3lLVvfeM!?X3~wpXu8MN2T86td|%soRStYlPVD|OCU&IOuB z+oOWrO*g4$%w{C4mJKV*-9f&Xs5C!LtR&=qII=X}woK4!X{3WF`hHmTm{Om*=K&j5 z_tY&_?XJa_M?1vFfeNTjo9@6?b7m~9)*)PYW_Pq%iNw{&CDXO68|@I*H;w1s_sZ)Qi*QWf0`5uR2h(Yk`UJRZK`I*UtA4a2)*gf@7ePB8PaF~+Bd5g=42w zah^Y(#C7UMq*!HEn51wWjEo6nDx=jwBimG;FH?K1HN!71hEe2nkf{uVoIlGI2_ESl zQAvS?q#$Y1a45*pV zvt&KUi)yTF-jkQii$gyW8&F`L+tZfjZ1RO?eTK-&clvvU9s7YQ{~}#<(83dCutLl^JS_7!X!q-MS%)#;GTI{43Ip^UT(p zv-5I4CU&j6FwxLZ@&?q+#Lx=Or1Zc#^dfzX6*kj&-t62jJ)Dq;eCFxzFojIbFsg^J z=9O#LhNJDh4oaRmJsj)Bv{N{f3fL>~2tF*4pG+_TEpSAJ_avix*0zyH-J&1~In5DI zq*GMwjBbk*44yI);+p;Y6`}Cm({zjGxS+H99o{JXT3tFPMn0H&KDF1bv8PBmSdp)b zJSFFSh(*`8TQ1}4;IGro=Q9&(Vep_Vnx+<(aX7?9(lxwCX}KC8`wiI3m(2Ne+O?Ii6|IdujzSUdW7c!{e066N^s?2g5H8A_)~(dYk5@3eZ%l z_CTMvf}emyoGj7PL$i?26xrP}s`VqSHzo-!Ud)PxDPBKqU+>pv z)*qdc3;o6;-ut6hqRa0@wEI;aO&dI7+0`{>pDo(v>>rnYUxI zixeEfBi(DZ@p5G3HBG(Nvm|yxJJ7wnH19OaDEGNyJe?Dr_+4xBChz|2pi1;Q3WNfm zHpfr0C1@P`SbcAIXZA|}$}hL%snde8O6TA^D^w844kn^PaO%(siU}<7k(~Ind{1)z%&0RA-N_5sf}%T zh_M$$=T2m}2wiwFn760vcMK%QZ7)+#k4LYD)TQp8hHntayQGXkp8INiUDJFiP#H3V!qv1x=7xFc4LF zx{Cx4YQot0^VEnA#*c?qFydY}a%~%;E`~?cs6zMeVed#nT1aCEw#ig#sfyaH6^tAS z;>7ZliB7)2q)@R1D+cwhP2jb}$-mxz!2?W`LPdE*4@n8mTAS$xx_{;j&Tf4;vxww$ zf-kBm9s;gNIP-h88SyuAJJv$ZoVnIw9jC4}J7hi#0b)>Dp)Fz~T{b=L!r_z~XLsjj ziNbL3s%x`(m5@Jk#qKQ7!2h!B9CO`!q*U$UnowOU*wLIdR4G)?4&6|b zY>)+GI!KS%FTlP#5bvmmCSr?Fi3oCXMqHN=NacJ-{2D(oH$YSx3nS2ztF|tn*B zJS+D4Bb+njpJ97_zeF2lVkhAlmKNEApMhzAnHpO55$TIe%~mtp?ng9{h!bDfO1pTE z1^aGi%zT3LUrY1TC+norptnGZdbPNL?yqZN&>(>wWp1XI4EC7Ww3g8az4C&`w=yBq8&75uQW$yj&{x#87b7ry|+P(+aUS@>cj4AL$4*+{;DbeJaB-eYl5^&etK@ znB+9QZUoB@+P8*hsapY7E z{a%C%KB$?duqotyN4T4CTkgHU4Zjaoy+~Xd=<4Qz@)4{7no7PE)D{dk?QbRYwaL!V zLHGwdgy2gwux2MLi36j9yMdOY3RT2N<-AgKeQy#YJvH)q#SfwRdW_6dDPD$U(zJ@) zMAI5$rn5R@y$?KTTK3I=+vBWKrb>!jaagmJ!jvDZpm`EtET)G|T1nLqB?%1y!W`)P zK{KsYNXHq3ng*E!!esY^9CGSz4@lhQA*E}M9`yK9?ngQjc+-0q1(up1p3?19wN}u) zk>67CAS3o};yqJq7(fd=_yBv<99~~}^$<7E-Jl=D*5|pD5JGB5<;m^}_YPDpHsl1l6vT(d2nCXENng{39?# zT||T4{K1AaqOWEfPOO({BvRrUq9WK(cXDg+evP%&+KhT-G5o#a*l4U1tF?L)eILe( zT0&8<6oRHol|-6Pp?^3E!9D=cibG;3F<%kNBVo;}c~axk6H@As%@JLLae4?$BnenH zwJsk9%29D0CP&4}IS5o2nD;@@qAM_TIW^L)5Xo=Z0OfScTS|`b1?6Q$*F$yD6=rS0 z3W6S?R2&uc=7X{)h&E^uC6tKj5<_YCl3sGxRUmshzh;gsVbW3EyP zqV247xm)$D&K`rvtTyg$cOIUE2?{*)!ZbuYAhC2BnGG0}(R4W}aUr8}xNOkdMq{EY!#tl!oesGO;WZYYr|s{G8KDX1I6KlH zaW>jt!5SVW5+X=%MAfOgM_?F^?N&Z+h|DjH#SMcELLF!kkFDw^JTu3VFfV1L_cj_5 zp0S#HzVG}Zim4wrcPv>YX7|cO+@)3&VUs71-QnxOd_^7`w6yQhA07=c;z=i5a*cvuvQHu$9s-}i+(p+qf#DN)O0~YBKMJ*(Mz#j}CB)nBq929B7 z+Z@RTWf)0wObO$GVEJQ#7|S4f^Rd<_7{p5cSm+ObD7(TUQDkajTe2Wa?EKDsuey6i zq_oKCuKUhC_uO;OJ@@l{owr^zGyjroJ({`gt?d)*jLEn@zOb}%;U&Cnz1Vxg6@!WP zv+VrhqkX^7S02Rc_teY;I3%7{jZPjNN}t=jy?#N-j&is)!Kl6kqC~N}I?3WpC7la1 zO!)LdqKjASO>necoZ!liw(iRo!!0TdN{5{GIx-WT2ERp%D7+pu;`l}F`w93?7QGSa zK6EWGe*RI>SoE<}9BF&XtpXzxw?j{MY`xG`W!jCD5}j+y#f~ladSV!UF0&y#)JfEF zl;Xnc6v3OA!-a)4)o^zpgGy{=JACv7M}q@tWxa2WC=$?%;JyAThu-zHD9SEO|d_HPzAbh|f%ced=mW$g5gDJzDm-E8Y!O>fp zm1p_cOj(d4J*c{lexCD>USE7%!i}8p4(>E$3!J0+e!7^lErF|NJK3VYU0m?(u*j%w z+ZFLw+s(D?Ue{jd7V0Y1E|$Vlv9{4#dxl6S(}leMVxQ5lrF15PesyxxU?UUmU0#B7At>jVE;>XBh1fC*E|Cx@c6X=J5y$C%BM4qh7XfX9BW3lr9Epee*#B~@I~R}XEWU- z53E*}j}dA;y5CZaY|p4EO6L3pQUPQh1QiuaqUm-Pf;|W!)(55@RafC&V6OC;wZZ)) zl^d4VhY-}0ONj(+CYnk1s?bmb z-~k@Zf+{(E==8||4O4f5!`1=sTI?#h+MwZl?$6Wz%e{fF@{Wq{FArnbP^f{JWR`wX zBwgkx9%W36DD#u}A*QoRNgqzTT_=>!{X(v>DJ?@KTI%nj4Mm>7Ect4OCxe<2sbhke zH8PJbK8p)R&?eu8qWkn;qBjmE$fgj99WH2M$tJgO?_~52+O$n8Sog86MRpYRG=Fv+ zb|OQgsLfqbDzGX{m_vp$56Snv5rPxDXF-;*!!?qOX7Ud}!m=@j%t?o}JnkSy<$V5{ zY8e}^_dDv8GRdXIW;nw4X1N4*e>@Kf|55kL)ZZ4k{6xPzKS2u=3o1Gp(@`Y9Z2B<{ zWDv#1a`3*}et@j7G~IbqZS2LXcxf}sUy8ps&cb_8JZ$#S&(5#gTb!+Gx2<|yb#-Cq zBE5YjEcih-WgkXn*Wz&-AI@KHd8*aE;3rQs##}LN;`CKm;a+E9$l|JVeec`VmkPwL zGkY-z_p08uZ3N4iDFKECZ`2^NA0( z)5Fu2x<1esT zR-k5ff-mhmWg+zAAZ7(kCbFYPTwLGr{cMfzAU|F#7cD+7MU{#UZOjlVi-6G-k_YIxO<&(~>uMQ_!du38k2__G-ezD#|VZ64rn15kBnX{9oa5^15KhAtp zi-kZ%Y1<-lh$}JjsPEWb&WJF^oEsBe_h4&*Y<%Bvg*j5j!)3XxIC1BKz0<-wzIdrhS{m| z3Rg9m8f=4`yDO`@XpJcwdyZdj@Qwx} zlqxayFd;ebdazib$)VwXjUnOO4&)#^oz^Ku{eDSA9Ny9B+_BfFDohO9Y8C3q?ZYeMbQyZx^_9)zTi(0H)a1HgaZ*3bH+{CctEAo{ov&qzeZi&`~l`Z`1_QF#aVb z&O~GLx2KdPQu##R50q-KRmez%Rpc>#j7eh-VDk*%5f!X`Y6)3fgK`kmB9A1BOCd^& z+Rvv$iUmT7#aImNvcjQMN76oQrI@_Fr2FNiD z3^HRCH;)=6NeESbYs~bNk{tnhq9xEHEk%)C@qv33B?%(8!+P+cbKsBsRzOBNMT>iy zr96R>pvY3AE3ra?6HdK|Q9MaO5|99m%kyYv_tH&&`^p6~n5BE-%=>DZG+;3<{wm-Y z;fOJsa0e?~w)6s#Y@{=yiKLoZPPQ6GDW<|D_QcmBc}6+G+mXVEvvy>5;7CxR2N6r! zCtFzt#tX!B1zf?l`2kv`n;vsuIR0qReU_N25axseg)4EXGGR;71Ugs5>Ja!NOpc6G zHZ?OE4M=$dNY`QsYV87vB>~$dW7|t7IdRl%mc`5x_NwNHRf$a9`GjfQ_IL@@!in1D zk${!Z-O@0(<)PDoMQb#*Xbc2u9i(8-XPDR(SVmy9&X7b_EZ}wyW|0a)b?BJ(1$jv# zSp$8ZB>q#=R!mh0tpcr&v0Gyff|bq!RVN|A(z1vgwiv)%9D~84(e#6xf-Pm9>Mf1b z5N%tL$S|>qOJo+WRKTLe49hBEY*MR)#O2ivmmM!)sm-q zhn>AOOR^LcTMt7Ck|dev>avo}gc_kku!Du37EE8}OH>CR9@3a zeqV_;LwU=RsU|E$j;S6xMo?)I`q2{Y9!SeXmyePkf&m`uD+^RnLN)ABtAlN^qPHkS zmHtMRmh?>2Y|m0D3LB>lgj8Ou_0V#s9_73WWe4IWC9-iQ^OnUNLFC8N38=~+^LSRD zL$G{MPphi^yonRPQIm*y1=lEJPcfj7@B(K{6vcXI6E*801hMrH&IEl5ST>wJm)T&T zI16vRFsf%ck9>0wFjBH?0nWo?gK?ytjw)k-^ZyM1mx{w9p zfj>nCmp#eCbs?IDII9}cMI<-^@MwQc854^%La?`l{DiN1dH7u)@)o8FmXqqLS6dIu zdOfsU7$QNm(8l2a%NbEUpZ2v}Rxl^j39AEy&mktgj1Uru9EOxBLe2!%^X9;|`6k%7 zDV8G2MVlm6iP~=-8rHKQffAaAk4B4X`dM6S+)9m}fQqUA!-VKOoK@1=9-j6U!|d~`J=7K^Bi#pLRDm>AuO?C z0I4t)C1IX#kDO99@jB}zuvIxYB(o3$v<^AKOlcK>zcW;6#?nhnh^s;ESoO)8@&kw3 zpovb6l=J3;Jf>&`K|(WtW~OdkL}g7vZN!Sp9!RpKMTu&i*K(LW?9aBzDXmJ(Oaj8N zX(I6D5JNCs z=t05=6U#g#YL_eKV5(^y;Ye4osl@)?8TNDkAdgilfts)iorfvfjPvLZImW7p?Ij+a z;;(XLjl(jc=YCAS{qf01vTuL<+%ML_M-!g~^F1(ph=_KEk;tj2+NYUGfr>>B22kKM z|6u$lUuD}8Yb-^R2m<}*d*!0W)O0xz{F{w=c_xqYlRW%bm@Whf+mB8f;~O8J{PYVq zKJFJ6{`TYkkOl8r_~U!Lci;ZF|Humj&nyu9qG2g`X5ru5Bb9k#ZKi1FG31a(=9-$4 zXyu>5LjES~qlx7mgXE1YrAAzc-Ri#0T&q>asjWe!=62aTQb(-67yTg!7J{!1ESs3Q zQeN|J@#LrjYP6r@T;-*0 zU%E-QWYd&_utw7P?F!m=#x}>S!;P(D(r!proj8L1yyv_{Oz4^UpUgykt(tuHrlD z#*O4aieOhZaTjzQr>*bCqYsXB^-}=A(7jW&9yddRo zw!b6IpS<|cE*`tC&6>|GZ@#zrkNHpHunZSb&3}XuzRfq9|KWfaw4{)!X5On(kkq(w z(m+|(q`{u>pZ~nn~!vG7u*?iZbe_J%Ke{T0L(fZS;n%6)5 zTff!((w9EH=`VhIKfpQG#f!4*Z`?R_%3r@uuq!Db;nb-c|F3-JGhFWf-i5bt1N7F9 z<5TOcpLhu7q&V)DE?&egrXSfhH|Kf5YL;8PKJ7=73#JrJex3Fc687Hr;=d?i$r=wK z{>_A$W2o;XO#T||NuqCBfCr>GJpcSnQS(rCT@|lSI5xx6(v!HbT0y^(jqLX>oO;gh zmMgo>uYWzIreI|=xrj1mgN0pOros2U8}kxGe)ebahLocCQo3=y`J{Yn2S02#uCKfy z-)(|jyaD#+053^5E=r?`iq;FwY0~EI^ZBs&rnM37+pb^4W7J>HPT^l|_xsf2`$_2T z^Sl9N{-lgWx*z(Gzkac?iTgJEwY}NKRnvEy_?WtArG4cqbXN0xMF95ZR|zg$IOGVD zo4odO`CrZsZRW`#)wj&`lR0wBQ5VN>_?X-4FNU?BYkp_e{-;>zz3-L39~?TBU&OPV z|HjU*4COC|xN5`S-IIQ2XZgPY``HG=1@B}uKFzbcNg3BG?RPmF`yS4!zS&@pSti<# z2$&SG=l>Od{JH!ae|pz*ETPZu%HPPLUAgcQ{<41KjU98EMORDX(1PULjS}$y_WxMk z?{)X<^2Qfr_g|+eGIgQ%ZyxXoXI-4Usn@0fMX*`9V0->~|A%qEBkrqwL z)V%l~_R9b>-(46jKA->XmodS2uQfNDfBWS_&o#e-Pd6-*Qo#gokEwz;*_s?ola1#0 z-o%I7^EmZ`<*m1x-~T>c?fc*V{%-T{{!acnSHLA#reKNP}go2l``JhIVUY8G>5_uX5VSKgS9LrnbEThG}zwDI-kL-f_} zrIGef8k=9p>jAoNHFEHO3p|(K*lBDMEMU5w`AuWoRO4_6cJT&1`7dV=QJTXzwOhdC8?X+V zvTHdmGKRnMm7o6U{Ciz;eCu0Z*yVu*#-V)Kr0n8$bN5v8+{Sp=J;XSCW47=uyf3CQ z(imPa&xok|rr;y-df7OX-zb?%F3!?8#Iu}vb7N>R1aS;^ih*qHR#oE^IW98#zVek# zx*0wko92v-YW>r;d~bR4Q2zC@{hVL^gZD4UA1tHk*AeAs-@$v`4o1wE{{RdA+b+}Y zb%r$Ah&JTnspdluk^21ZMe{btNdYGYKODxEOfW9wMTv11(=}YTUC1l^Sl>)SdU^yC+opZRa07v?By3ATADc_atfq1ctuodbRx)~5pdy>6L<|sNd zyO~j-Ex}sldKLh*%BM2P6APv(*eb>-dm>jNGGdtwmQZ#vJ#W|c>e*x$+2~v*4=6FG?qD9&e6gm0K5kVj84oF2dTV?xJmRZu0 zcmg2O+Lh3hJvEPY+eoiD=&$XUQt}T30r6IZ)LyNK>|;Mu`*4$g|B2Cytqy!&`yYBc zOD&ju7L|bu4fsUm56yk!lHJfsw0HlE+><1)efbk%$64P0`LlEEV_!Z|(d52(LMq9N z+jC!Kcqp4+8+do`=$8UwoR~+kgsuJNoc6i@XnwlxBDI+7d;q)eU)S|$EMJ*>UpxEf zdh|<4mt*bT`(vsRA3l8ljv2s}|9+0GoY(iim}ptM7h^~@8vmGtR9gmUkd$}(uUsu9 z{;}Jr=jYh#zhf8-jqJ?4=2;|OgYH?a_eZ7GSKckXKT0(RuT#MWjd>rhGuk0o z*RY@3CsgdEY?H$G;$&6>aEG$edga&)qTE9wV z>?e$s>ujBx4=dg(+{=M(6--gnBySMqQkfCSkuYlT(jF~V^86jpl9ZIAekF+fp63A2 zkA7ESoncK&*KCtTycJPt5V`*-9@92?;#zyy-0zoYUe}E>YWt--3MsD}* zwa@D!&vk6Ys$hOhF|BCUZ6nFX!>fycTQkllHMhM2gSn3h$>Stg@BuY^u@@QxPxkA=rA| zFoU~ptpc=+&XoEA_}N<1^pJ#Q0AdP%Fi?b=xT;Ag3|45Vk24TKT!$5{!YmdE{FZDj za(pLHO9(s{m^sIj@9YPRP@+!}rti**c*iiq>4}HtQ8L% zhO`r)z%)%n(iD!2)p^`rAQpI~8IAa!YQCczW6ovME#ClNtQ&ycB8&;VM5^+-gf?zr zi$QUohjG(Zp}0WByw5Q+1r6-+UY~K zu%cNo`M1f|Ff8(zOTNJ?>+E5d3Vp>k5`ITQz92uwW)s&!qW?+;Tw%|a3$iUcoVJkJ z>}r*?yG`xEI7Z33JV2I@U+-a$Y@5=MFu8G-47JRA#V zM18^2c75T&Y7=ggS|K}x232v0sG{?5ui@r|bX>Qu7sgC?SjkSN(+g^&8YZxZTNLM3 zirdQ!MkS-g6I(CIf7|si%mRJ4Sb%Y)A^35wvkk}8Tf99##$h>Ji_3Glvl;;+mjMhKfl95&S zbdjbPa*T><6bmLn)JWQ`*!#4$Fs-gkN1vYF^HPk9I(urBUJ|KtuD{>(Lk*v09^&1S zh#(%4U!O`o3dmDV`lq8iyi7v}O6mIe_C6^8h1W!rE+TEDxuJ-Xv1EGdbPAjsYMRBhAAOEh&336IP%og*Ag zpjU#og;r8wGFoajCy(N8rZ z6_+T}B)_dyF%0SoslqwiK^k~`E#q>HrTm6tPxNjFs*Nkd+V@)T|f0}qM}Iu9?B z!x-BfLl|vfsZ=BZD^XYO_iAcxm-m0F&wA(j@_=>7!z&W#@GE_mi&Rl!bV@`OWnVPf zKP_b^?!JhNf{aqE9P-+@UuB)MR%H@fr70SGrrDHEEYhJ`m4!O&0G7?i+x0>j?Cjq zvG%t4xmKp-;;L32gpQ6SL|Shk=VSz{FDY=uAYJB}`~29eeCax)q{7^AAi+vZfWkGX zb>=Hq`n@9HN&VcFE6NLy>^_*?0{;((51h^dFY>W38AMZ)VUCzw(LIXajxaqtlWy27 z9(+t1%%g3dVCUMJIoF}?hX*uL&lVf>piBFs*#>3Gidu(|K9pzM*uJaX?pU&QcdU@b z)fQQow?vQf%4vA9O-avM%kWw5a|1?r^v5rELuzIwrADKZ+0y9pMvrWE-q_XgAU++7 ztn7Q=Z?qnvA1`z1sCN&F^k{tT+*1Z>-e1kmxG`^Aq7qqCuM@0vbD} zWog7Y{Pyxo4Qcqyy~q{;32;>qqDs7ymwMH&9`}PYuKDn4HX%FvQ{$jFwR-k8@aXlT zEVesFdq4>S%DlR2gRFRYIX@S#^Y-=B)3;?clFX}58Q#s&3! znU-!My^($xi- zT`pR^vPYjR;oJu^d4tlngG94*8EAqpF*m)uJj!Un?N6><&lwS0^2!JBxpfC~>j%c} zu_M=)qHgk%09s+|hJV(}EJ@XE<}q5zERw*bZP`}B^T4zdGQ)e_qML_f$GEDv9;i#3 zeGMX>5Of4AHy0bZpwZJEamS81S|Z0_Y{=xej$P2@p8C)@{^-&N;Encw2p%_}KZ1=nmY#5VvtMvJNU9c=dC@9@K$mlO}1Y6np2($qhMgpLLaK4Yw%n0c{0JU|_bY5(+<8E0q24c%z zj!SW$r9^bOob2StIVKSTKL%e7B_pc4ToR;}Um8qQ%6VH>vgQSKVN<|1nOI=6pQ zzAomkq;EyWp-N-PUBWLRL{1}SQ<)u;2RVDKN;BRXBK6us!zDx6La1gj*%6;qYQsK` zmWw4DTlf3&=;Y`u4Z15z^+IJ~F^DOYdabTigIwu|_qBm!OfjXgVGQez#-u9S8jLu* zX@3UG{g4Y-K6b3MeQH;|#H^uQWQgQrh|9#x!7GGBtIIPZlbXc%2s{&qlNG$cqQmo_^4dF4?EsrtyO5- zarcYFzzoHSFXLxG%u1(t4$w`Y*-P8ZG7r)Xvq=lISU=^``ZPnin z+Xx8(Z-c3-LAZe$s18mG8wC!LlJr4X3o(#O=+c2T-4O{UM{QD5%urD21a{OcvSy=V zff?b8D7UT>+oXw)cQ@Qr!h;e_2!TQ57ifIUi9EQdFxNM}VqM-6J?N;50Ey{8$D*`(%#HN34MezQyB8WHj8 zS)&c8XmPD}4dte#Lx?s?x^d4Wu@6!+kw_XL5DXe)b{L0)g-4qWN zmKHDu<^WG+lB6j@4?FEHMtG?%A5? zKM?q6B-4$(<(1=IvrfbIoBP$URE4|`TA{5}1s_DQlZTkpjB~Z~jf%~BG%FC(oN6+{ zv19Pobz&sUx%Q6!Olt5d!B}N0T4?P)=6YQ8b8VOp!viI5ffnCe#+o25u)0` z0)tEf1q9Qc9&r%DUW7BBIz8^u3~_>Tyu``iDk+9X3lan?*(a4rFKHzT zvBf+=I@$`4;&u($a`q2qH_Mi#r2};{GJsjwGaM{J3&w3q*^jB4AQ)0xD49uYCzinU zV7aU!RftxibI}zk)vC@>vo6OPIdItLs4m7FNcut4ijmO|(&v7br!RA@zh`!L4TU2Xdr(F#kEjrG)IW!64}x5=krk2tF_%UHu=I?@8E zmUUZ%<SKn5Rl?@_K;<#vBOTa;0Tw+2tK19;6RNDOExQBgdOTU@8jphtgC+}d(%CJ;}u zX=Q91JA;nn0hmrN!%z-~Ko_zs1eF#SSBAM~8_&g0+LGHJX|K-MX!TV&E6%y*_EBDb zW3TSQZ9}WX>w41kP2(?{1Nl*`eaJ}F~5&N4ey(%78P7~0`_Mt|5}7~YfX7KLjJTSL|sYQ_F1 z4qjJ{avEa*OCNlKTP9prQy&-)iDFEFwt-M*`PN_HJ%rQt zW+72NCSfzKwW$&YaSP)5V8BG4;^HwnGemZl>^_q--XJKtmhHUCsZA3P1HUC5yJC;J z@=>Okn7L=kaxQq!P}$*Xc+Wg6-DB?7Y0<%lcYM}F4T$4=C^@!#rScR z!4`(?jU+zqDE8A!@Pc>#ec9P@FLFnMd_Iuv(qnRvwXOob^J)y=m>WOK4`R)hu7(>Qy-jL3MlBb<)DJL=`8&-YKsKzRDpy6+ZsMLfF-FexG zB6jZ?C#rB|<1I%GGR}&WCp$tm+KHbMyCZt9G7@P@1-Fs^+Yi%4QkP`fi+1J}GcVkZ z8q)hbcDy%ATSQgIc{Y=$9L4DlEIretGn1A$JC|i>4n&O>G8Z_|JBp_$l3p{GoiRd` zJ|O2#Lh{aaY@`2pRNRGpFuwX>}s#{+}KqlQ`WLbg3r?j#m+TNW5NA#|p9aKHXEuW)A)oMatbKi!@6{}ne) z5!j6OZ0@MN*eTY7^~UWJDtsX#>o9of!jq9~xwhod2@*p9sUezGZI<4MydnkhKHP7< zO#QOFZ_Dt?&?keA={(^*mOFPl%pr&iWc69lf2WKWPqdqbaBp?h2u(AGHN`S71On4z z<49a+wGH2))A48y#Qf0^V%~wqePf6TGWuw0`Be>VyXnX3*cR7fw$%drg44(aX6Y*# zdc5+h+7r49!-6phU;<( z5n9W7!NZyNWX>v^+scq@nX+8^nwnHzV zzqd+=)V&>enn+rWVjB8-xzlU;?vb*TK8<8oSHg)lFQo_R4DJeKN>gkigrt4G<+g+a43_-7b-p^Ia0boaut@o3nQeuqnInKBRBqbRm*^N&i8 zob7&}-US88-2wcX(<1#$PWW{!zEOk_RHUye9X{%Y`rXcu^`ywS-!1Z)_FWrj*Ux>3 z9fY{)3-|TU-+yu#uy{B>*`WGmH-ur)R#rmCmFzs+wcgoz&CSHF)*QKz(L7EI&ULQ^ zY0ZcI-*4=yi-~ zpsOBdSZiIyvZ04B33&+wo$ZUC>-iCF(IIo!fY73GR*=N?6*g#Hw{;or74s!&wMkF3 zPr!P3Bpa?xH?WKp$3k9WlenSpvAKya-9N$Py&jL+>_yexz^!QBjcbo@75OTyv7WKE z41!^krDW8iX!#b|NKw2zw|4aZu2`gyr`H{%#SA_-PqsO!tC=-6F-v1XXw( zWV~9ek8u<>D^?~$Ib4i+9cFzN7u?}tIorA*mkK<4lpnm5ub}q&SQ>|mPHP-jV&-of zFRV?GSPUC08O1;5ik;%6am2Oi8s)F7O~RUsag1NRVj2tATH~8sn=i-?52LIsudKTs z&t=dtvDhlzx@ak{H@t`0Sc*%i!P5_lNWF`iq+g&zOrl$g7G%iCnpMD zx^aUn(}m*7imV^*yO8tErC|L`vN&!&cqhn(tLwRI+GQxF_F;jt*b?n!=r2VnjuOpj zFLA>X?kAY+x#>l5a>;X>yy(gOc`MTIiwCh85R1vMI9%u&p6_C@x;~VhVSI3X!-Wy$ZF`=mKg|w8ZrddK% z3k^aF2{iF}4izldM;mVmOrHvL9|6tgF^+Sdsfnu!wxfY2H7a^VAuIgUhX2SuQ&dv| z##UpudMbDf8HP~G!5p-C;tH0hG7pttyAV>uhGF2YzF5~FJ3pXO%O&63(qaI5Z{%o! z-GcpjOg_T@Tn%%$!;{k$NP?f>vsZ!Wx)CAipA7>=CvEXEadepXZmTp0k z7Z9gL0lHQ`n}`n664Bc^`AIzSv2>L^@p!G&;H(XAZq_e+&&(2$XhmDi^pB8R54ofpZ0I2^3lappyywMfd}l_B+ftpbusCR4X zJYMf#EE?yu{bK-44YE%%ESmN;sI71m@gpG2(@kMu)dkr~oh7Lj0tPbcaBA!-WmiS1 zi+po|yQ@q;6OxOz(^)bj&QiqKx^0i|fF;ZAeBJ8w$C8m6)5@)M6eo#7vQ$y

}yitYKjeHJg2dLX+x+R$Sc^4URcVth|%KC-g+3btC1pIfSHv!su*ZY2Mb)N zD*}}$ympKr94c$JKn(U2a>BXF%_OxdWCw`8!l9{Q(b5x`{Aie35G;U~OS^S#qOCTn zNnb*xl`XrCF||uX%9cB2W(u(+D>gDT5|FHentYW$u24IcJ4xi=Q(|)?h?LSJZ*4*n zC^06%lr^uc^?8FhvrsLdXN3$6I(CX{0B$K*hksPZ_7R$OP!hmOQUL~zT?n{OIu_6P z1sABS2TRdN7%T!s6~#2RomG+#jZh2(#t)Yu;UKs6NdW?6E|q4>kw}knvq+gRlOP%E zVPNA9${2+bbFPK-rHzxFih~57^#VyIRVAA2jD26}peVnPT0mlpjYy>KP)xtbg^hHR zfs-!yz{wDdW-nQp#ztl4wCg?1ch!Ds+5{o z>@1usQXy%YBC-c&H-@dj0VS=)EG5BCx<`ObXq}o=9}+F$U~@Q7VTGoZ4s|$ZvZL}V zQuqWL8HbT9+H-2``{4B6I^t-h z5iCs?l+W`*RZB^MAwVs~I&~z95e?ML$fn8STJdMl82!DJtTsp!ubR1x9aFMk)RtE= zL7ao%v51WTc(*PS3RjG(C5;uW)YG~*IlCV>Hj$>=Tkr;w-4oUeszDI?LbThqy9WB#=Y$;|GQj_=!PjU{% zYqA++zFOC$sz_Bt&nfc)HO4*Cd_6osNa(ju;}7kb6pSF?u}jj#Tk#R0yV&}^7dU-v z@{c@%xeF}`0utfXzM-OJJplY~Gx}`Q+zpFTgw8 z1NT(?>1r}L=DCx{t|VfNYPdK<9@?Gr=2P3E=lob6Irn1($=R8C3L||#h*dPnqpAqr zreT*R4IWsk3YmvXX3#1)=Pi|M6!aT%RQ}Z*8YIkHYQpC7Zt^=I z6@{X+GUiU(%%xj|N`Tc>y(hpj#$syVHP1v?%OoJm2C?RYk`gSSUG`Y2s5MzdN{u&Z zL^1KADVngPMlB*Txp+~XnD|=WzBQ80Ngh~|oa&KsB*phN*ry@cI!LV5NXqP~S*f-k zT0(7chR`$rM>6|ItN~Kgf<0`spY3fh-fq~u{)^wvKk--p-T#sw+x_j2`WuJvtFu`- z7&`u({NlIGy$?`1S-N=dsgt?+AIeXix_HrVZsNPmFnm2-yqFRy+Mz=vAS7#!A|6M+ zalOEO4$g9tC=0$x>Zwz>IKwI0!2pkE$@iJLmI81;WQALa1`D5We(rM#<9qLxP|5rH zMcm6tmZDES$@IFpOMvsA8+)F(o`;z#po?MT-F(jf-R8`y?~>E78}buRqUl?d_SW<0Qh8~U=W*JW{5qX_9-R|rla?IDztUIt9X?g+ zKJVY65_6AHc#$$MSMzAXa6k6eTetzk1J%t5DT+&?-S1lPrdi|7|LQ2g=AR()BtD3~ zXEc0F;YDh9_bKZ4BZATO>ooFruQd+&>v(DNU;jGJvA%op@Zn^a=9||S5H-UEn6V`9 zOZoL1L~*iY{@Ql`x+x2SLnU*@_O-9!s_FWTQ%{n2X#U#%$v;VMl$w9~r>W+6WV(*C zGx(A#sUt_M$)5K*Os$nz=FPaf`@jDkQvP~Zeq8XM_1$YYS;L7GuGMx2&o$qe4W5%X z-uS|9dhHK8o9m?^;%{7Bc>|AtmAvQJp<)eu(Vaqjc?hnRO}u&uqIPe)4S!eYf@8Q% z{6y_*Fn4fu@%pJvs&(C5XHnm>On%r-ZRUS59Q?h^zLV5V{@UL6KKag!F7>}r+P=j< zdb92KqtDhp+^Wv-b|Evv&wVDpa_qN1nqRrX{33!^u)mpe5`E($-H#Htmk9nL)qZ#P zExb_Suc|5BF{}6Gi@e_xde@lmLJ{xy$G{0HVl6b3q{+ZA4|LIRRFP^$# zKFw0Xevkw}-Q7KP(H}eZ%rpMy0D0z_W5=4uj%{A&sbVDKB+P7X@@#ly+43^cC!a)j z8t_{?w4K>HvCIQ*lmGRubZs+gzIkH2UbFxJ<;h58=}+O$RHR$=@Io13uiod*c*VyNK^I zs}amU@e|G6S*kgH-S9xic)bSSH@kY1OpU_uy|KGYX>CUM=XV-^P8mbyy8)@f zXy#r-;_E)-uiwC{+IQzIXayy2c;94h!;#xXW)`Z-Wbx*}biQb&t28hdapv&xqV-tB z|4LQ;Uo+ov|H2AN!}5j@{l?C(b@9zM{1w_9_mVeKC7Cv0!IP!A@x%3_Ymk78xUYUy zY;JQ4`A)1De^?lK9F4F2#DXm^tCyVu*Bgdn#qvQ<6a9Q=`^>K$erD|>ryKui;lCf@ z0joUW-^_mf^yDK8&z$yeF8rsb;EpL586(2k`hzip2|GYwW`QwO1TX9-86-T@+|?Z(!wZ-j$<5%0JpTvG$m9&v!pGeTqyuk>c-7!PO3Z?`&8lf zDF6W|9G07C`%yJ{RZ$imOyCM+iXPA?X_u}w8n$9sy&GMyE$Q-Jupdo()t8?crK>Vl zggx@aK9j8cTO@h2vm;olqfj&A+ZBP3ExDyreFDomLut>3FnMXKZHB!grRYVE@<(Rc(83VFDp&5hzzWM1vKO^Z}@?v-=2 zfBQ=&NotTzQ5HAW1J#Na-G^V=N5P_WEdFjTxCKM9FS{eL1kzazlW2zB8&B%*oO=oOnR$G|- z^RUzcYkca9SkEx0q*n6YHJSTd`^NdY<~*`O-o&@~Me}!OIezntpP1AB>X#}HYK^RY zVvqJ8YYgvoq0&Wok03o{A@VyXj#af>^ir3*p$spREcW79g&huatea8Al)5rC8<+;2 zX6?OBmgU5eN}h^#A2DmlqI|Koq&Ah;u*u`mCkWnR-@t%dpz_9=C9tUG5Orf zbL?0=ko#RXkHh^G8WPyx=WQn7;lMjyMJYv^accmWiC{F zve7%SF{x6eW0MS!BUuAaGkBgySlwzZTamxa&w+{B)%H0p@e^2r=~F3b@(knL%}TQo zRcjy-EJEv?oYNZIgiEPD|F3z9iHAF=%<9to7PYI&4LtFb^1^Rm zlFgopX15IMVsm*3dsym0Xs*p^FV$Kd;NWDv0z}lMRdM4f6AFe8M?;NvPC{Mogl9bK zf*&zEC)l=|7zUeD=)605*+@Y{okJbTtAb(NYr-Ala* zi7BRp(Ih)Al~+D1tdCci4r|Q%_&&UAAFZ(-6|NW2k)d%%4g z$gDxeGU(ckIoVO}JMWxH*n&DSTG$YtzFW!z$|+gtX?g*As;_eJq1xa?=0Ot1tr1fb3r2v(2)m#3EP@1AC&phCwoLijXZ`GiQ|6$+qo@DebE5(|ydIrASkI z7UtcD=TA_{YFz0)FC%5UC5WkBRpoltmq$6$C~QE-5qsJWD_AR#@1x%j_^oLe9*c)H42TZ3{!T!{5%m!<+(4>76plMYflyp2XCn1rsji!X=E7Uxf%=A)z zL#vFGzG&~HJ0{B-nWvEwjBW`s?1rtNfOLKaJ%!(ZhlI&t|8N+MQDM9`Yewlg;{oDc zVCFmsbB+VFL<-_{Temurh1v9#cz&CQqKzj7XIsJKEO}Yfu&6S+FjdYQ7N6oN^?`H= zmL7a8f7tof`l9AN#z_2dFJZ94Ycv2~Lq3Fb28;hpD95mpf!cXf&ho9H~}j1wCDyP9)=F znn>UR*=(NM);z07=yP|SD6u+8A{sDEt0EJ+$V)%bx<#mH)+OEvM)dEBkN49Qe{Fr! zFRa+hDCqL4zXuJ-{Fy@H#_P&dD%;!@?7hf@)#+fG4%6}^be806(d z;4H*Kc7nD&+BT9&9z~SrxT3BYailp(QRz@S4YIV7@f=^rWx?FC?ZdM2Oom)r-KV5; zIu}Q;VvS@|QP3SZEzKk{UBx{wQexnW36+<}JRuB?-q;=8LVfnx^XQhf3%YEC)W)w@u zCEDgl?fA54nBMp5v;NXJNU$!zKNFu!n1{@mutTU@|PoI?|Kl?Ee-`7u@Nku`C~>(mLU(vT(%4 zF;pv}v;%^yzLck(sNGmFe{522XTc17;NG(E_n;!Cbxt^^WFrli#vY=;rXXTpXRupX?@!zAjcp9;+6 z%su{*LI1Rry-)SzxBFXTxqrfLap}s&igYKFX_)$k>h&;FU6yAT!+qDn-SpANmItU% zWDj;JKcHo(>>>jRp)4p~u_@Cb-C$L&_G2TXb52T;Ph$4|V=lJZyd3X5S!r6Hb`M>f zAJ0**0KsQG)%x;41?RWaG*S(Oh6sK$C{cEj`O<)WINB7l$?J^UGE?&*1(=Z@%tSuD z)tI!6Al_Zm4o7=K!5>yUgV1vxLwZ5?(li|NCHgcwFlE1)tp({{I*Ounqz8`eH`G=! zxGX-lxntluV*T2#kM&y{5m}+k`r3q$D#D3B>X6hE5i(FiRFF%`=&NZeoyBj@Y7TtMVEp08R@?g7cp(0kKZS8(L@1-D> z8s(nyY6fIXgL-3%D;&=>s>RAiK@lxCGKJiI=h`6OPo52!<)DlFbi#L}d4;$(2pxyN)eNHtKGau>))zBQDpE zNoX)Yj+!qv^Th+n9L5wmU(0RWd+ttI=GF`WG(7t8yHfJb3La_VwPsN)Yv@PcYTo&& z!Iro8^zyTpTKDwrWiv+7)L&k1=NpeptFwMNTWf#n{I;ycf4Nw!t!C@pZMP=*ATDoj zIGGjMW4zw7O|C!FStHLHik9(&#G z$s`ubEGA*Ca2Sc%n6iUR6br`Aa%7T<)~48`Yi-JoGhf~a-I9K;bS)X(XK6!N4!~_9 z$ICnKDU0?=HzFrXvu%~H*j7=G4U3;b%pHePR&NVI5L$c25?tw81)l%oyV8e+!A$Y@Mo1dPLY zrZ2~7T4LFk2olgfQL3u5W8@rxUw@sf4|~&$>AHqO&w!yQzi10#odT{9QxK!7X6n__ zN{xiZYlaEZn1EfeK4*@rAoJgV)a3`a1!I#E;l*(x(JRYrGO}c#2jQ^s+OUP7E!-YC zZeP8%gps7KzUG`^Qh=}pD&I2uBQ^)Dc6>jNfXc^D56+pVdo4cSpC>>5Hb7W zr7YNpYO}v}&oIP$eZEWU~Rp4JjJPASDDuR^?dL zLodpiMcx}!t}G^Vo6k}bvefS_2hlpiY02#EB&z|2y)(RQDPh9Zi2yZ62E4&+8iGko z;GnSfsf%iJj0*iFD?=B|YPD?LKiw)=*#L>cdPtiB%cWJF3AV6&SInEM5m+OyCB*U? zr~Taeh_f;)JdHp(Rq)20RsZihNG0U#S^&+r$I^*hwpw1^KHMNWV`qY*yykDcHj^#9*2!uStVZ-IntBBpFJ9haPPQor zw<(c*BUshN(qg)5Q4GXC%7n#WGnlD$55LfjGGH|F27S?`j~!vFBOMaxZAG_O=5#TJ zaWWmW2iR{F`~{_P#D5H#Z3jIDf+NHN#v-e=n^=N@f2FbQB^u30!4IUvnOB^`8mH>+ ziyA{TrO9mn^cpQp*sKVY6CzvLSxeVcqYFW^nTNW(DkUdhs|_~`zUmK1Fc_uq)*xek zU@Xz=G*#Y(Jr1*l?Yb%hStMHZ60q5@V=`$XD4qfnB7uWlsf-*Ek)#-{ULX=?*8It#PYSGzK#IkgA{--G`9S80VBWgrvq?7im!NJTgBT zw;QB9-4xzr{zRz)wc)rAcDt{Fpq7Q-^*Lq#s4`KVSG|9{#wN@Xp<+@~DbnY(5zR)W zom1Hh44HDuFL2Q)%$60mDIMmTSHgk~ChIfUC1vKu@xyCel+{ zB3eQPu|8Jo`dkCLo7M@MIO7}vE08u9rm1a(YC%;>WK)>x zX54CKggcn3Gx*8wYGRcnE|7%NCbfe>Od%`gUc@xY*iTdtMa|l82dP}8;7IDE<}f{k zCA2z%GS_S*+J2DgoUvUr&OH?*+vh0cOia^|A9WEC<$?S5j8V-kRLx*95=8Nu8pF4V zly%Y056J2j&S?8b-p$q2Q-R}f>Kg=j6 zWkzLse8Yv&dIsN-%ywiajM)dwj6=XULq<_xJ1l0mk&eQX9@)4Q-r{>A(c!RzCv%Lh zIuL{$u7>;O%zIDDN}GqiwkAwXjZxOk^4PU|pp=#^Yaxe+phsiCjMkjYT?&H10~HR1 zm?k2s&bQDBD=-e@r?6#y7DKP;fM2c%q4y~{zVgh<$w_k_Rila<6ffHE(`2%`WrbnO zY4ik}I+>Bm6P6cJYg1bkPXRlJX!+O*wNON2N4f$x$u>7<7jqq|wKY%Ng7QI$hCB*% z5R4f|xRe-k=UVDB6)%v;CW~F-MqimBz1<=1Nj8vi)^2x|{bBIgT)g6{$GOeSh0$50 zgd@eI=i5(b#PHp=IhYk=TR}$hXuRzLncZN{idINq=Q*Os4Ks?pj*Zb$@6#7U^g0yR zksTk~#Z$M!a~0~lLMD&Bu<}$s=T=>WSap4KbEI3=-!(MlaVG;VO^YyIpA9hW5aTt| z7Em|EZys+I6Fo^4LiNL;n5x6UnSls|Q{fULi9FOe9dx~Dht*%k$L+0>f#)7!raD}I z+z;I(m>p|8??g=ml(NHLC8Dm{FCA~$-(aEpYfrB-2=r+c(BPm z30>EY5^jxg)Z|eaG$%06fSR6$wv!bic-5*zoYcr@wO{AiKQRjK$ty< zC5G@PMWWbFVTVp=%NbEw;iOaxXOWO89cKs3;6-%zuZFv(NSFnByGLDlHkwHWGTRzs zrQr*M!G><9eGb%TPi8U<16{`!ZZuFRBR_e@ce;!PT+2{JP~pSA&=E}+BoPwn!jg&& zFnALmuhO9d;$L+4y{L30o&!Xk@ruBv=R!R1ibhe69flS+Vt0OibCV88?-}6uv3oc5P+B6Z zjx~^)Bup|9|B0kbbylBmA`n`!jRwgqA9{#5z3$>~gX(cstyxc|%ue#^#wcTqkc{~2 zo1B!(p9^d;UoBd#qO3qxC!s5A^C)4BOMo3r<5q&W!xQ(y>Z4hd$>irJ7jHYc;)e0@ z=jIn)?LF1Is};}HTkU2s^u2DcczyIZzbBVHJuXI{+UYRSJujomLNlkbx_vjIPI;s~cV3A9+4|JUqpt|BRnib{F*az*cdv8R`-)xZe)~ zqkP8XuqAQyB#*{7N3>2m*V*yaodH+5YwIt`IFBtCGFgKd|8$~`3J2a5sE#d*jz`S!lA!hDMkx&(f)m;X>In(2ks` z8n?+?w;MWzBiE0-lZ#MLe~@QW3A?tWu_?X}5R^dE8a16Zw8cZ?MR`^M|3I?ef(y1N zvh{EuJlNj^xt;lY9@{bqxz{(DbEz1;7&svxNa)qV4hx^>*>A2eZpZt(%yllnl388k zWoX--V+)_%C86I9L9sRap+3Crb`P^bW+>8d%^e=3{8(0d9Tg-c{c)K?m_ z`=zrf`{8;q%+@=s1;at!ZWkDl(IB0U0DcEL4Gc+D=7kWw*ce_9R^2OJc9BV=`pVH-F;$9Sk*Gkf(X@;w8LwP5*-x&q-VZnA9cDo_bWV1BmpmQa*BQp)R+r~R9VU-Xphz70qhZL`>e(>xI4?57 zy-JqtNQaXjsmBa-LG$G#q!UFDY$PklMHfTlESqv>A!G}tdP`qMv2%6CZ?pJO*He0@ z^Xh4@%pNq5%R=a85BBq;8k8G39Z_DAnf4F=Om}CqD;wP~3VnRHv7rn1cm0&xJKmUY zJtSylB4w(S*@LxhWHJ6_2oL3e@>Z{7c(+>)_9s*XpQ_z zZ?iwZuLAv=F^2(UvX!@cO?Fw`hp@fEmKx~`Y!Ik#68pG*06) zPHZ#BTDz4|B*)W<`ot?=1fnQ8!#&y7TPhn-9`LaUv*>@)?MQYwNY5zK3@01mWpnR_ ztRb)pxD2im4^QCT4B}~-g-J+F=xl=1MH;fh+$lZM+^m?bWU+&WQC13mJgk_wW|K_O zVx@>p+LPIi7v(5D3v5?b3O9nYbLU<2uwxc)%EUQ0msYD)%Qu_&i_ecuYLnYrS!@0L zwAmWe)>*Oh^O$_ZkJC(>r-wZWTl~`dLUhg*O@Y@vs*m}^`R3LG#%tov%T=V<*ufTf zdv&dhi{Pd-SBiNtkFA!}k+Wb1jRnrvCbMjw(?-2ZhjVunPkOTAT@?SIbC>40#LK(Z z(2m}MT^uXfMHG|imRZJptzpVSU8_Tfp^4`)&gT!fiQFFDT#Es(+{CyOw_-6_m)cfz zr(rXj^Uy$i@*U`~i{f}LVtGtM?xamUAS)Q!HfZpDS8Ji$wAI=wJ~e3{qetJ) zCoI-pr%fg>{YQa%k`NzFM1P^5B;Yln)Tg*wiYY+}L&6YwA2e14B54(x z3KESs)nx<*VJ}F0qD6C2Bj?-;Laza}lsy2C#(rTbY7xZKFwWtYFw*uR?xEzPh8==J zMO!|sypdXigkXkY@LPhn`!PwI7~@SP(sYr8EJlCAMd-Xz8gm zc@XbGFc$D4VOk}6x`-ns68AaR;g(KW>men^FYS28WK4|puS#Swp*Qg)L9KRWUtk$2 zFv4ZoMp?bDq`;QsQX?d4X%Qsp!YPg{66{jmWY;pcokb!kr6Xb5F`R;7J0-dZzcw#P z*c;tIZuj@2VU_`zR|%P}J0s^hQ6Y(P3A(_}XhI(BOxx+6@wBk*bb?r(2pNGU0@Nuj z@rISraj5YX)49vBgaA_7YnhU)0-f2rgwn|1aQ+BTsteRx*7^|yRZ>}6%UGxq)2Xbo zN(u2`mhlZ~Vh6L$b;+fi+7A*+7A5Mo(OUsC1gk;Pq0in(m<`KYy+-hlfHBAt7wlzh zz>^`?!Tk1qNuyDYlvx(o&#bUOnFtjfA?axJKMH2R#EPuIkyM1^gWv!qnfgf$dr@V% z(i9`0+b1|EgRO5jfhM-mn1SwtMXG|InSG8mFr8QF7eTotz|0al4EZmg3 zufT_ri4LSR)sN;_g^uKIqVOZHX|C;6BgOPy0&l9v5Hv+u4@1>1^b<3^cxCa)cFf`j z3K9Dd1a!4A3)qZke@T5+T_8jty#z%z1+B}DlxQTsEI@LFg@lry#S$Z|5asMe)u~|z zgraAqZOlnd@ENf#dm~MjuyzUy)u5JZ;JLSE5`_JA3m?XN;FA2z+Ylu#gOpV@X}|)( zYALmxq&%Ta0$cfvaBeZ>z%q4CSt6*Y25@DENK}iRN zF;0_xYD~)to}>(0r9E2W2M?oD`ld|*?Db?2jqlJ}k{4Enj9cr|YD5zs7v7L+99l`# z)@_h-n_F~P1;zd&k}ei7Den&l$kC_uoR$@2aJIo8qw0094bc18YNG&i#6zogJ&N`ilY&u zKiF!T(g{FFXB3PEptf<~L>eI+RC$t<*l9`@iQGLy40_wkG!r1DYe`d{uv0AK zA07TTXYrPXzczw#aY`w@@05)} zDqE&mhVA%y$6a|ttZs54HZd_K2#c3C_z|Tx z*yBcRt#sPvCp`Y*bM7jG>63gbRtlLiOp-LOTG?rh66{<}`YP8nkrJp4RtTP=COy%V zYeFWvH&;<7G)ZCNyV&lp>JZ~jWFrvKOVtMw1lM$NUVN} zk;Z`Lcf>UnOC?g}m93JD$e!AK+3@yIoF*$<(Ci0On-&NXJ%I_d#M7B*m6D7?8k(=+ zb+GivX0F;!?>TKtp4(0*_if9x@lD)*B=Sb`*Cxqd+avECx~KkcUpe&2`gg-Gec$_9 zT|AzUKB&L(M?cujfBlcYW$urXBb{%V=bSfisq@`$5&RvwWdP3M{=LN`kC1!FoVFz~>UGYLd~sKf z)NRe?NEuw}`~*JS#CLXYkn-S>x_qb1SgD^{)@TI`QU(sZ;Pi34CCL*w9l}@E?hl(a zd5?VP{`n*I%a?KZRJk}p>G$9Im!Bc+FxHToc_V8);*q)U-(DO!l&og__MA#3)N@-N|LI21j zxOq#qUk2ZpCx2n}&(yzTj+Z{@KY<6j>-XG)zcw7N-MIe5Av{ZgRX*Iz8QYCFcIzLP z?|lyiapd&QJKz0o{f5-u#!Fl6ZT~^TJhGJ@-tgD<-g~%edi(AAAtX&zTJGh0?!hfs zY91st2Uq0cXzu#LgnYgEg#Q2w<)~n7WWJ~b*L3f{_3!_EefNFzeP2?q`^lfozxFjs z{LviF{}D^(?=5QY(G!vR%RAq*4rko}upV)XH_u_o;``>@$C7pTU3UFv`D=UoZN@gf z%2vPsCts`I^FMrZy}tQ{Klz&f@&D;7*YnHgj{JE3UH!ps{f9`wBxQBWA)Kt4+rxxi zzYZq51sQ*bsTg>7A~MFfc$ua2ujB3)b4K&7d3d8YhHKZzO@SQt@2Ke|yI*99`VRiV zK4^Y}Iu0GOMDvW;Oxj0zs9cuc|M?WfW2AW~tY5!TmGHa2xx4#WBmPjZ-}nhDy|i84Nt_w4@5;BB zd1x28v3TPRdZT=X4%^&iQo*O$^*PFz=SDyOTYR(Kp#S3RECn>h^~Ei>)ZZ2SwSDmV zA?w)C{aU~OYsuFmj?$PX{(8YHD1UDr&pvpaVf452BafsuVjMOeVf58MV_pjn;T~<} z%lL4^dD`VY-zDneXLa{_^Er`HRkxPtZXi{rvm` z8uZAD$h$w5%6?Q(q(r-n18fo2k@uONt%8lMv;M-fPr@!|M`Sc56*o(ddp0>|YplCZ z`JX$C=eBbj-F8V~Vcg$Ir;A4_;(xiUR9v82D~pi9e|Z~#PZndfTPZUM?Os9Jwf+@b z*V(ym`*U}k`{g3?;K*)Yrb`4Q1T09m&jkNl+)^p;&)cmvQ;%F8@c2ow<+(ASmTHfz z3Nj)!m<+}9JUzl7CQD4WC=%6PFo%S^HJ*XZd7YrewNI*)-IPJJVvCXges=Cx{V%SZ z`&|9p>=!Z4vp;v%_mxL zz2Ha6thjNm7^edA%jKyGqjU}XG3Y`{`ufs0+r$5_>%}&?uJ}I(rN^#X`_HU`o|4{i#;o*SZ+C9FwaiiL(+a zXKJPIv&R4U%YiR#NjpkLC3Ag%UoDgGOMf-c66=1+g-YgYO9>87wfCGey38+go4>J? zW#uapqTB^nStU1sxy5u)Y0g{H5orLsREPmCB45+e0~jd!29xT?wy%|%yN|`ctn9M! ze|@2!q^g~|IM^xWTbceBl^?swSN^hB=4R&|7Bczto95vSw(f9T`g+^=(=$73mRrld z`Gx*h6Wyu5TDFYVrS#WUV`omi8D)<#W0zJ7^wU&U;`mC5`8U6got^2i8U|JFU6%%x z_q7HZC8^xEFCO%&7E=l7RJpb6H;?xpHAxNni!%4eTxI+C%AnNEZG3%F^_P%SmH%|BJ_@>CRrH_{y`Rx3t>LuKOsr;}#yow$H&OVzg(^frPQd^!lzsJQ_bkf~k zYI*-(ElYIkw4-t19U7@s^>QnzS|{kfRqM+>-BRDh*9W}*giZaaKmU~ylNbNy3l(lYd=d& z&MYx_R(0ejnLn)0a6f&U&~o^wozS3^!_p!-Wvp!($b+p7D}i{D#nv;P1W>|n;DfA^ z&&-n2dPtxNdx#!drrAr?CFh>aQN|gONK2TzLpJ_PD570Cj+8sPxK`!zd(|a|hnOYS`S5tUk8vIXxboB!2tPAj<+D3hiEZS+D-eQYzC|OS&+c>$9zrrv3>ngvNWdmYEqWGwEDlxRUpGbD>kEz2j|W{q{Lfb^STKY^Fg_Oter zqgJUd8W-zH36mb_B{t94C0MTfyI-w{?ewt&c=;BXG`puzk@Owo!=}L%QErj3WXP;R zR3xz3LQQAv=((+4#pAWeEa_Sj^LH$R0}%CHTG0WY=ZfpfI- z28;|7xn<=lSfX|=m(nB~eZg#OVj{+93Xj?a87-6*ycAfr`t0Jxpys3ZQJ(kVprizq-QuMvyJR%gfSaA(@V-^)=0n4TsnSk6oQJ%~&Wh~3loo2cT(O^6 zm+lE}F&iC#!yQ@8UmCZ#_dAZO3`O3|r%$f3h}$+@SqJ(>t8mlD^U<3qiSC+8w#EoX z725;rUI&1*ei=38ONelDG!kIJwjnWENJ7YGqM^0wX5n{M3*WtsiT+i~3G~ugFf74X z{JpV6TSM6z2jd@(ThE)>x9Kw>m!=CrtrFg}8Z%QMFw<#lWiD7E)(@7u3Ng=)9WA0K zheam7-CJANQoa>&^0<98Hg0*O+P)w%ei1I?=O}irwc4DXP5s6=%i4@8dpJ|ECu*23 zNP?KU*0{B@wymbLk{U5K#QCaB15sW=A;XaTjG4sKk&4$+ znhp$9HuHNk?Pavvjz7c9a91<)VdmixDDfdE3tGq=t2B&@7}iPWr4w%Y@=NQ~ih4NU zRFS&_uda?w)4PMLZ;>MNF)wV!yEaCMViv-58tt0`=K7&b$FkatVS9BeS{BLnXMi~! zm7ZVARld!8q~;2pqc}a$SvMcx%at2p(=N7b|?O}TGowjEi2ZaZ16~}cgbh9?MvRg zdmxd@D9}2roHS94;0SEpW9G8kaFY<+`ha=cHGS5@E4pknHZFxM_BOrpdvrrF8T^z$ z7R-F2UuA5^30{~^(H?X9=8!B5DzGd8*Xq)tM&)wZdRD%mYK2ewFRpMpCMY$PwU8eyBLxZo~NvA7SN zac@!{WXRYmJ;!Mj36Ad#%;1P;5+dS5vQaC}%P08YF1zCzHAHfT>qnnPTRsjRZmbUq zxpuYD%Lcr6-hCL)O1=+s+rQ@7tyi{fO?$YZH1??u9D}Sr#A~d~SG+-djq4s~;-$+L z6zb!{*4-k?T4gP^Fsi(}(MKzX+$`0A%9~E_G%r9tpA0+xr)BQ(*}0(3OB&X#Ar@Dr zG!Ltu!aDHV<$TPs(Ff1v3Ub|vaPS6dHn0Juic)nHj58r5eKGe^8!BT^^Mjp&8?D_TrD)AlpkZVulJ{nv-bURw0-3@+$k+|-?`iyA)&{;)1f zy3I+B-`2o~PdY%%E24`@KAlLjn@w6S=DlrHd8m-Z-Ho13b@t>j%;^GsmzU;&@@0(G zB7ZK(V&g#_>Pla}+L$#vUEDD|6vFjr+cD1y>uFziS5{*sro%6C{H@^9g$-R7#qaOS z0~42)%gH*_7$d}EbQZ^bHPbcP6cMP<&^f`xo3;2)KY0FI+r_kh+xDsLZEY&4GqU{R zq}z6J;K$`ln$Bozwm3KJJjr4)xDx%fO9R=wEsLAQZR7N%yX(w7e*QvV!!Tx4XV8{n zph%<6`Uep83X{Z@noO++Q{mBI$)MG)pa)qE|29B|vmt$6NQZauzNYSkgbkSrI?H{#CM)k$4pA`)0$mTg-nx5(0eRtzwzrahPURX?5FY$~E zms7P*WGp2Qx_)F}20jOw-bJsx_W`&1mF#qHd_j&$<4FmEPc@&RP2S~;j_cR1C{5R< zeT6#uG99H3S-fn@!|GPs9jvu}W`_KETxfL1w!dm!;H~C76p!kVH8Iwva#dcnR(}jr z)lTKvgThTUd7*CuYejHI=h&r=gRV_wAc`9-x1ByXdQ;?#3@2_TpBu!9o|pS3^bB4( zm>#_ov#WrIVnF4<#70>N>K6Hs4LZfw12@-6l7HCu9`i2y{auFXm7t%$# z&$-6r80nD~r3ZnyK*>O?gi*w9>u4H!|-~Fges|&FS^=!YFR8S6*XR*E$GjfiM={j zz*%V{k5rSl={SYA58j!+GkF>dsom4+(9dLg3tQA$(7?;uAw+ND)l5(`4YypCyj%J+}JbX0IuCUbz zwPRN|XJUj4TL+yhrdO9TY`pP0nguY) zE}&4CLOCC#p|)=4w!zzcnvRhBW7&`^wlroVyMe+?1)!v43_w|>cKUXP-RzUZjJpW+dxG`@qNHq?XH>1peq2P>ne~kU6D14U1ZpkHZg{cSPlSqHnU6*gIBGWVDxiWA zY#?4Uv|&khH24k}2vli1^ubl}tA4eZHCE-6`qHu2;iZJa6=eCi#*WoiMN z2qbWeU}uC-S~Q{q7oe<%Off^r?w7ErIkNg=Xeg1>r5NOq{vBEwT0XbV5=~@a(gx{l zCSI_!jv;>GBl42788tG9CagFzj@0(FL^^)Zj1N2cHksaIE5!jAAHes}bS-1tOSW*Hz{A~)douV0-vm+8v!U`qqKmcze%Ob%Z zlZ5XF>`1AR%AK0IjO9|6gj!%%7axYcC6v@vPB{tWDmI3S*mqpFHxn{XD??Z4r(H{ zC}z}ZA3HDQ3Q$=8Tmm!wys97==V&az_;<=ePB|qoVBTJETA13ABY{x|uCr34$0Sgs z>42!sqatd-vVs6Qw>z27(}#<8vJ2uw_7XO`Ss&o?tUwhl%lL)TTgeI>HvvY~lwi$X zLabVDX`qyDt{SgO4!$<{LtU}j!oC2xJMK#(tq@XtRo0kWfQ?m`LRlg{OGx4MHwlM zvLqP<3!pcF`i7SfI8_vVnOIu@YJovA{J`{q*Pbd$P9)RLfMqcR4Wa}YE7d58W&~aL znQ|T*)t<(n2K!dBSgDRz!wocrqhLY<0jCd(gi#}+loeJ?aBz?+DD$nVP#VS1$ie2+ z!obzQ*>ToQFrQ#H^G&^pB>KY);k;15miNyIRuB6LY^-3%* zg>L3=F3O}2g)t;Mb5G(Q0>tKi+`VL%`$bQ6S^7Y7X|hzw#b-{jM$AEd6vZ<&6{^e#>Zz*%4-|N z)1kW+?q)9(5>Kz9@{DkCBpR*EdQ?s-F39sEuyhYQN}<}J8u)gz!75UD_J&;YXdZ*r zK6QxOoFb77L#H%4`ym-*k<|@`Dge7yY-h- zn9bOtvcP!gom<nlg`JdkJG+Ef^~#5m|zWvMcm@oUEO}jEQy1 z+&VRODF5o_$XIzfBU63cTVfn(bY$Q6;!I{NdegJ3S^HJQ%G}+f0qvIMoin*>wKdIj zvnICiudUs!yycJ$NAw%Fg_87e^>Lyiul)98OJ(zgm5cf2_;jRG)7Df{lQ^B9&_QaX4Y_Nc z>8d+Xf9!{P@BQgj?jYfyD{_TcFQ!AEeF;W|oC*2bCe1l@ znOQCHHU<6wiVc^IMmo*cqj@cq+x>~NIFDDm_2S0d9K>xL-HPR7yfr3mC0iMdMiKU- zrada@l6!)it!!Y6HN6*mix0HNy+L+*>`b7c>+B!fT=X#yIC^q|29QZjXzdG*%%*5Q=5AwoM!mzJWH=wV|J_ynF> zg!Jq?#?J8MIE+N11Z`(QapdM+ww-RaE?xY1$w|NJHdeL!dK_)dhVs~>m?D#nc=D`V zWGKtY=<{e7D>g1aK=!&uE5tKR+g+y;;eI5y4KQc#rvJ;Xs2L#8qqrQ8dfjxgaoV$Xqb;}7HfT_r zbef)bK4}r};>xE3Sx9sd+l|{Y@T1nSn7g|-yQ8A*Uc&9iBLtab zPi$nmC2s2^9kSPY`t+H?Z$(9r+!lqC6Z#9C`BpvC8f`wNTwrRaHCY)jYO)jyOshl&Lwh85N3B6HbkPE{|12ADm+Uzk#yt6#W zy)qwe2vnY#As-IKc^4SK%qsXczkP*9hN)|CJ(`S?&xZin7W2fB>_YGd|^g48V zrgZq_(uE@$2p7??%jA^Qx*?z%e{ChHGm{Q<9V+IHBU0I8WwK(W+IHFIy#^O<3G4!D zy)0Oq;lSHTG)B#%vj#}*5E=Q05jx0F)(4qcZzqHm#^H{Hz(?Jk@IV-nX)d+UIH-7q zBXk`WT;`h=YmMz1p?)Roh}(fQAQHE1FnzF_f;I?!y#p64jYWU~dt&a>2T&R<3ZGq( zg-&RZMOg`Lx&RM6EX7Qa>V@ryAw^oFKbWc4!1yn`XOZsMyph{2(GE8PHyMEFVt@8e zd4rG*JDosM#E64(pFXa3UhadEH+Yi+KYkoi2x5zKSrJ) zs_I_7f5TStT7DldG%~&R+o6jIDL#T4Dj)3jC|V%6ggW)ZJ4#f`rKHs!>@SR_a!b&d z61!8=PFT6TlAtoQuIB};)3Gys84D*GV_pGb$zZ4Gw_L!79&Omnw`ACy=R4+Qs^t!I z6R0)kM}v?x(xc{mHh(-jvWJ}OxcYFSxeLQ01~xA6a?XOGTX9!?A(M72qSeZz(WIMr z-C7JzKbDiWUU(hW{p)NuOf_uDqCsT<*S+-cghn^#vj!`U0{G2so-UpRwOCe@IJAsD z))G-HBKf)^Bl$M#^=0UaJ8Nc3x>3K?bM$t5%bq9EP5c^oelw9WGvtk=HSt0AkW8R; zI|VE3Ml-;CLNs6BLbi-5L?(S{P9}2}L)>*X<$-CRje+1ktPd-z`DeFes>M28V_haJ z2JY~Nr%#LShz;7U2~vZeoIZN|Hw3J`qP^>sTIkL4=G=Fj$Vli09^&8g$+4PF% z2ebMcM`O^Uz21Cf{S+J=kB4a;ywn`taHm?*<2t*D#X?@WuX%L6zj5bXHc{p)JjyF3 zlQ<7SWuRNF=KOIqD{$6(`(c!q$zc7COU0!r%DP!r+`rUFGIQbO2Eg(XRLAmb`B`m|}P zDoDA>JP`^zta3}B_Y+SkN)JplWv&zxq)D}NU&7A8)ZIJw@=8YJ1Khi-J{jlI9x!x$zp4~KNQTUKqcJq$|%Wz@6%FnO50Nwrd}mYjLi15SpqAv-W< zTEtR=kr}bolKa)P2THYv%1-1Ob-|r9*AP~uEU?c(M=M@JTS%k4rO+b-Y&nQB+w~fv z#9@I(0C!`}Cwm2fteAue(oboqW^CBQM8+@ESp^$CL)Nz~WbOFJpp*n>bRd!I64N@F zDJfzl%h*94fmLJ)l&}h-X`mb>EYC|OXjdjdw?|ab{-;kA4gVn3UR8S(|1fPuqUmg* zGCzBplxB?FOoK*63xKH~Qv|S?ME;Tl(3QEIlSIJ~R#%_SU>YjSNS6>mVs(_*J{OXK zmn;}0qZ%tKyku!P34(=t^GiF)mNHTh21D%vp` zn-iB15@KO2G5Tr7=7v}-lRlTye9O9Zzc4U@daDa==@Pd97FwUX0t;skgMmVJzpHTx53p$I1N?b%H z1So^Oik*yHjXBb?$hh8NF9G$F`sqNklx zMMnW$zHw_=VXtCS1Zqd>eyb9(f^Y;JyO1;q8q-8rc2O(xAxJ{Slvsub@|OZHMK75j zAUKE~Le5fFOcJnGj3=Y_BXW3J~a* z#1g2m7|oE;Rb*IDR4v#)EGF`zl&+-o$JP-dl@z?5oa9?ZsQ zk36r&c|@$T6XynulyT#YA8!S)P(hpt%o1?VCMXyw&?x6L$qgx%?XVs)4!J%_>tU`@ zkb;W##vuv(r&J3grI0=ntf{7P=+~5+nIx2bffZgY0$5@+#IVvJiOz8unR~l;LrpTY z?PDm32yIv;DsW3pGVD_e+^WXWY_Ff3Y7g$XT#u!on} z&3$q&^B+LCASpp_B3Q;0iyB@YC0?4U%+c4izO#eyh;KB!&7RK2wTwrw(tu@6)`le* zhom-VuyNZJQ8PX&f*i7#1IIr}HeuZt~7hHc8&tg=UKX<9XEYTrnL$zl{vZMU_A zgq`#|Da-nvrp{IsPPsp`q^%NDHN)WFu}ai32NtLW2Wqp3TCfL@jrNkNIiWOK>hu-e z{$!C7BCm9a)pd}Yma!y>afnI&q+RAh8Udsxu{iI6nhgk0B%>O`st{7r%s5HO5gB&q zm|ZH#dY=)eM&Fb!md1vucnVei08YdUIcbQqTg?hJ4jrit$P`toqjBP^6dJFY<$+A$etXRGg{)a7V#8jbkmxA{}*03H~aoC_+Ki6|M^}r zw(YVB&t8&zSw&J3W6Jdd5nydyB`>jia}L5p3YL5xp~`0R!ZO@%z{bsJZA2~AmK>>p4%!PX=r5b z!cy?U$IYc%;!?V+Go=NYU}i>yX_=eSmbF4-K>@(HAO;qXx?h5(6)h_=qNFy_gzedY zj2Du>Huff3rdD<)r!+B00{AUTziw!m6x{EQ$bh9rFWjAd`zeC6XZM5YJ*2H$+WJoz z_7f#`Zk#lt%4poNfsG2dm^I)AhDIMpEMMalQKI{h#eIAa!!6E@6vHh zuYLN^zwnp;`b*FFFFo_{HUHYDcfW|EDY*R2jU%_f>IXPk`tEzX{%>(fgj1v>&yQft ze_LDT>*qSbKl^8L3XejtUoj_3_#1kED>>_W_ucvz@!W(nrX<>au(f4#{v*cV^LPc? z(^*yy;UDNXf0K+af4TnUFT*rSaokU*JRk2b(!BdEDuQd$2oFUK96sImMZ8??KJi6d zKcx)wGW0rbiqOiWO2zPLWYN-tQiXlja(746mgxGAKyt`b;3>fkWM2A&I;g(v;;D*^ zhrfjHDl7KxWh#FkFL%4|COr}>3*LW(;DaiPe0v$RD)!smeY&!4Du%d8<_})SWzzd^ z)sEC}EN};fW2nEYOKt1F_SbJDFKxD3eTLwV-#?6-r`MZ*g#V|{oA0wDzJ6l|S5oi3 za|j=9*Kr&7{#%LUU)Id)+avP7_K)B}?RxW%@C4QQyu3TY$`Mk7W zl5b@fZ*Ix`mHBYnO(jZiZr{UCl(pp>_>SrqZ|vs%0*7Pr^(S~RSvDn#6~&<=`Sr`4 z&*$I%c1Q9RYirs1*yoXS1p{nVN)!F$C-KAfvp<`E&|kre96sD|dR4Nq@Rj#+D~h+X z%a`*fp16KJKXhmp`&pVr@%?rEI(;1ODS88ClCf#VBiFqyF8{lFCyBfJ!yo3~dH3^Q zsK4>oxD2yVRIR{snbdREc>Aw$*|_k^rU z;AqdN4Q^n$#KoNECAu%JH^G|g#-7I^uumk=zV=l8@>5^IN7`q9?}_^Fy$1GsuU-3W z{(G;z_EdiTv&l;vKHNTdJ@NZH%*jjxmyaFFe@JO+#3h;e_$o2RqWOBmU)#GKysv$4 z2O5(erS}8+o5{D#NM&LA-g~>3>ox?JYE)Q?63{&Kj33s2K!A71AMP4vtZ<6>o$n-m zDfrmOa=PE=^UL!l4&=;Dp>4Q#72D;oR*A-VO0f zm>67_l_waRzt*q+SzRvs`k&zr^2T+h$!~wV{u$gEGOBJ|KmNA=IOK^lBa+*<=5#Qr znxrS=3H&uO4)gc7(#U;dS00eYBlW-d3&!2Lx`?p_A@H+KCWeZ2l>{?eC!h%3G~ zKC{ap!13BeZf((<4jo~H-h=Jutg7Y@fs0C3nBV>Vq*2ZLZ^hk@*B3WF*u@2-9Ijuo zsr}H6Z~T+`4o#CB^~uj)-V-BK*pHm5oAg|prz>8&`sW*w@}{?KMwVNln+wKB+%CR& zsAU*;4=pmWd5#j?(ER*a|BH=tpR4^`dcZ&(+wVKUH6yJ^4Amdg;lt^%I9f+c;sbq}F6lx5PijG}(ivd$E-S zIkRFpFV10(q7jb_3J+feNqx&PsH}lzrWB9@LrTnggQ=ZvG}yK`_rJJt?x{M#FVykU z_Vhs;7?}ZWx<>K2@Xm^TCziHTM0sh%43C?&k~=0rvp6xs&)I3&4IgV=KB3`_F`nh| zNj7})7FlaWDF!4^Sj*(LFKsS2r(O(mxss11QbC>{8tEQjzv*`v{{vwsYRZ$S*$1w-=llwc)OJ4=>OtEOeKmxqy+8mX_ho zZ3&e|KAQ}%nx+1eecfJIQc*fcz^+cW_bfEs&mH{VbJNoOhj>QvkkaFEH&6DvKmMi6 zgBcO;gjMeSSB{5yn>2U-|7QFQTm0#uJ-^eiPyWVZ_msIC7yi3$-lnKqjY#K=3)B3^ zK6)I|=`3IJU-3&U#jAjsj0r~6*-JTwjn2f4VZxXI@cd$F$567&m0#Jz2F9T*J1a4$ z3`p}umzS8z+%twHcx(?_3Was+Jes708~tI$+1r=ci3_*xmT8-NSnDy~he~yDkzCag zXG`5ogpyzJ$}%_2qDhvkjYz)jdAwYx%8r{$Z1!@6xqZ&t7^Ku=JKC*s)Azh7m?Th) zSJo!mv&w!FAhBFGs$Z<=dd$~liQCxvRMrrCiOyKTr7Yo7t6D_T=uWk5cdOcX+jFnp zN0<6`Q+F)a%=sNT+aH$-?#v&2{hNehq#)1q=ap=6D$=J~UM&bn{W%;P zHRMj28Pm{ApPL%7X$K(H9M-Gz9r(j8vs2=h0!7RS**hKf#H70*$f~`j8Uq}YVNs8( zkQibXqyp?|!tyJwXr0mmve9%qB5G2aHG!VOV*#T`#H!=02QkP3X+WgFl&cI}^h93C z!r`=*@}pBpVe&lVSGPAba)F2cO2r3*M&X zBVnHVB?Am>+(iC%f=Xj`gE#Ly{@t8BnbYoZ2N4_m#wKbOQTz@+wH5O7vXj5UcG95Q zOD8+KDGSPWX4IjY?)JZ}M_O^f6}~!JP-8(IN8=cG;9?ieLhL7$7(ZN-1jh(cF(s z&vqq?Yz!3Zukfu2*N9rg6~#D8zVL2{TIsPFX_LO4jpag1p2X*jZ_5Q2gLs|EOG7ix zI&X~S%D^^akr^M~%j&wx#Lx4Ue9*XA99JF3L_#oLBC<@QbZJJf=$JdfnV5@b^1GLs zM2ZAC-Sp}aQC{+=;{dH@XKy9v8Idv9b{8E z4j0U5O=g@kw>_9=?a|qmUzjI2n!O zstiePdh7?k2=4M#m7VUZGVIzFkJ>=6lA;JyViHy@0f@m?C%)Sm(kJn&)Vi=$W>B(% z4le;mS@5-kY^>m>3_I!Mr4z-r+7s?q%LZ5y<4xDjL_V@0e`_%%9VCUFdXrrU(E_Z;HB*!2UJ7Qulb z@8plI+Q+)m)DZnJQ^*cLWupTr38lFI1UB_oCF|S^o1xmZFs_*#1FGivp02|*!C$cM zq)%ICbd0Ewtdsj&o!WgGbOiz*d3F4oZ*Iu?lnq{Ho^k=+hh19)iCWa?r(7DvesRsn zlZh8#Qd0|4kctrD%zu;8R6$nClo4gdDly1tIIPl)Q`y*_a%3%1(V|a_=mKI=OYo`? z$3Ypx8wd6^H}I{dP!t}FPoadNHH%^TAszj#R=AZ8k#(}otb2tr+G;Ecs+C$WLP*U9 zLrY;Ao?1$|#kKPY9g->NX>b7w9Zo2iEg&*iN=_3K$}T+F3q_3xQpBx=w#B536$xks zW6rv;8N`069Z?XvwaSNm)L~p~hrJJE-XGhdW2~Yi=cB-HeFuCQIk`l0l30*FRpkZZ zMWjL;XX+iSKMQN%5ToZ+cUg2HWopY8jjYz#ruu6gkMdU{Pkydlljfsqc_(g8BZUy+ z+O;Tw6}uFg6pl*vVIe_-ZQrlm>E!BB-|xU9SJ(2Fq&Y0O2D&B2@L;2Vt0=Ra zESMQs76^dM7q@KQ>orWc?>|j%UdY4N3Ndv07-IfC3(or%lxHSWcDj5);QOgIo}wEHrSSNH{P&CzX`b!et#*}M|MxjQFr$UUoOH(#ZM zcf2+?zCb@;1U@iWi6h~= zjALRF=%5pEG>VmMyJ{oW$79s6s0HU06VRU60cb3k?evI*S|C=#@rH_dlkqcJJuWf? zzG#$@Tmv*GSacB<(VQpBJNWHYO4x@Gr}#ck_;4X6;uMVk^-zo9HGazLN^RqzYl|x~ zeCvFXMfc+Nq&TCFDq^-7=%yO5Z)dENV%V0iJfHao?v6*Bx2$gDo#7Rp0L-sW7K?su z{J{3u$tj#c%)*5?^WmqSet@>>F|b6!Msba$_YT^(#z$BvKM)y{h5O6KS(cS9JGs~= zDf2YRBt+5tC~`WEFVQ&cupjKnrC#xH)JJPFcHvX!*H7Jf)D0o1;HMvK--*#S@pWS< z!SRVkn~ym*u4I0SqYTXDVxi<(VB;;p+1$dqqFgD|KAXC((CyFI*bImkn3^g+7;d9NG~2LCS^lFXB?y%{ zrd6Ejz_27rMaLu#=$k3S&?T@Q>JoQhiJ86?MCwn*rZ*r$-tW29ZO7PRGpVGQQS59p zeLghA;C^SttWtMEMkR$i6Nyg`2u@T*J*OzwZ5&<$HNeV&ev|5Lz$QsAc~oUFa+oyg zA`zM)03wV}!^Rv)vw z)vi{SU`zzMjx08LVnU>kzDg$#G9FCEBoqrDjV0-hs6piDKWL%oFw%*mMucSL3UNcp zpV?>-PnRGzp!9<=LM)yUCATcukf3r#YC}#;utty|VL4xkF|V0)C#tTxnzuc&POZFM z9=PnP_sDAd7$(w~8jbN}%M}INCAYmW?qU0g8p_(S>Wi$8icF;V2UuTcQxo&&%ZqJ3 zWacA%1hElk>q^)9OT({Q z%l%z>OQq9i`yS= z)^#LFEDM&8%sBBJjf5ChDJ^%HG+q#UBTWT-JxD^PQi5p_N@-aIiP*gD`qwNMY!RxY z7)`QBwReUjd#z0lA|(if$~IINDUVMpSwpz_gnP}m5RX*~(ID6d>PIM~?m-DoC# zo&g}U07_IXQ%^u>)M=#-qy?&)Ic^p7LQ-@QdW-&SEIM{vhRBOuY8%8`ns9k2a{(qV znJPH-PW#dqVQO7+8(RT+w0a?k3wl7-8Z%CUT*IkSlzd`4r1<|)_P()l9oK>9sp@*q z_qAWd+mB7nldSAiH=CT6mV<4YOw7${q3TvkXer9hqar$9A%U7Q&B(LfiSr@$hagaO zv&A$OjolIyK@J9smP{Em*H|Z$VAhKONt03>+2D?i0E^^{BTX>KE<7166UFPSBKz&{ z)V=-QBP~1GL%zDFPMtb+>eSy`_ukV?0vkty9mtql=K((lz!iN4&FO3ywDHx!x>jb$UvzdcOJ#D4#Ac*FT%PrjsG0b;c4uVJAxfoWTtT!8 zvPW;Da>1uz0h$=_4Hq@q^f+*^XJA|N<#>e}m}IpTa3-rv2^0$jdUNP`-MpX$U#9U< zB;^OlD5au^FTp2bn!uCg77BOj`0uMQ{RzLus!W#ljNvYVn0Ls@X zrik1Sh9q=R&^$E@poylWNX8u)>|hDmVbU0U>8BMGC&BAAHJ6c?Py)0r@)%{`fqSRo zM{KTdfMoC08%RV_y~`^cI*TfdV!9AimNnj6KuX+cwxH47Kx2hmpU|D?POM11p|&xp zCu_qFbqsEyrHxT84}Lcr*5iL7fY5_EchIXCa`PA-@H&om!O3E2BE1`2)&X*0;-;*d z07soSQM5>;tAW7^8L8Br{gM;U?p(bP!p3MVp*RmUD7U06f-h=rw3MNe*AWV?5OM}7 zyLc-7!+;vvT63;>4Y5;>H5bWP?xk&sICNsjUGcVvTW^| z4pml*#1y(c_>V#xWw9bu3($smZlTx`*dDVADt!rRB5kxzBA7)_4aeU2iS z^g?F(6FtmR+q24w4btl~3H40qp^~xIjyXFE0rzC4-w@x=Vqf>BnFQbNn!2Ak=R>O{ zUWRr5eEvLN#+X3Rls*lXNnc0sxT|eHVya9UpqA%OfbB8I<=$GUi|+1UMtkjNhA-jt zxG9p~tXNs0&JK56WDa4?yVb5kc3(^YV(7&vlL^_v5bY?)$`<8?{)ivfW$T=u)>1XW zQ%Ib9VlLF3Ix5Nav`LMY<8n(k9h_UAaW=dE0*(~6s+n`ANWU1YyC`1pNoHJiCN8c{ z%|zUQ!!ovaC_~l|oSe6y?y0AS4!Srb3dioDr`o~;6MrkdNDZy0EVhKgd#T3BQ>fX0 zL}G9*RwcwnWNSwOeCx34`eNMynXJlP4!Iw5*=m$C(M|ewb$jNR{D%Eu$QpcMsMB+w zUz&I>Hca&H1-F`ScHLmaThVUCMfVgnuXm;Kh;PxAW|pFy{uEBu$4%3`|LjV)QR~{K zz3n~RgVwxWmpP4QoL|XgB~)9h&p++%$8>{L7VW0+s zbSBYqlZ?k#Z6CyukehtoB7cqx4J!>=H2Pq??0_vWE=eRzb_ni;vU+_9vnEvuc-4OC zV!t0k%(K-X{V*5J*qVFzt@ri;ZQKyeVF_nOAqKxSf7*JOym22HYy^>B@l|dktrrhs z2mgf3o5G<{vzq1IQN%M%WGdyc^r(jynyj0JRTuDaAoGy!Qt+78ra}=}LrC;T(-5q$ zn%^(;=tT{|S?WwDrTi}Om~1TZJf=7-la>rM)k*7&57p5cW*r@tcuJr4jSrz#Bvo*h zM$NqA8AEGp>()li#}^xy5ab`phW_CPjE8AY=GOU~w4!`zYO2 zD%Q_?D`VCz`{)*j@oE12@RsMDqR63RR|2`W>=ydDn7{aR?xW?Qmt=-k)$8(-v1 z3dd~c%}afZ#KYli)Q6FJfTRg_xvXKBQ zMQXa{yq~w2Bs{O%PNmO-X!ZY*KWi?nT$r;kom~kvKk+h2(~gY9>$k{v^)iLBkpyZiB61S6y74mMNRXC4 zp5)PVvQ_M$m6KS4luflM0snT~hx0kffSsh}L67x4UPQtn8_xhE_Tw2frt+NEThs}T zMCOpblaE}Hjz`K%O*3yhJNM`r^r3?HFPY$ZJ2j?0wP>O1NaSH@I9^%ru`t=dsFq+@ zWvl&OGf8IJ4YntND#Xwq2N7iWMcZ3JGKOeU{ftNSSy+hG8rV*#$VwEt7tyUe_O1#& zw&}P-^&=|kR$|zoOc}rCn&KIbp6N1y&t)zRP?&?;@_GKc_+D-~?dbHcwm6F8DXI72 zptz4n|01{Il?D>K^T=G{>@}LcM*-D95*F&{Kt>k2b+XfqWlSPZpX_4k2%MRWp z?Ym??@WBoS9i#+pLFP|sgtJ8 zzw41|+fx@{m!V%KSlqb+;L1^FPq;U+!l`LQ22gO|aWPJk9u9$K;kY{J6Xz2NF;&~g!5sd3la zXpPBvfaev%(uTN>peA1zF?p~shpyf9-UOlpEQ+f1^A={L6~&WV0*Ks)1gr$bL-2^# z`;e@u1<|=#T>XmAJ(-;JTE0Pg^xpc=lc@PyO)Wlws#bzgF^2yg{&I}6K#?t6f^~cY zHeSmJ?SKG&{i@ZBNMNI+W07~6YUX5!nU!uf3hXwFbVnUAQFq9h89&Nq1`@gjshwb6 zGWJrNY;#_Yh#X->B+RE_i)Dbdq(iq3LDW3KR|7LJ^O}qT>giGw)fDS4cWR2wQ7%#U zGa`N~-9 z3>?L!T8{Wh_x*UGI>0051!a;_j7QdNM|iw@HIKs6Df2-Sn9c|FbEebV z%-QAffUuS%>Rwn2o)oWFO(o|?-c=&?XCkdfOoHDrqqLD0B-1V^1#h}&E_o?NZyxH_)R%@w2GgW!knvmZcJQcv7=RDAyjIIbW;4Hi z9P#6Zw>G=6CDU^hY+l~1TGhK z)6F)+7VpG0WPz#i02e&9xs>NUUYp2sAIL9Tn{k~g2WAX@4(fZI%vx$ zldQ(C%jG|d;YN*I)gHvoxTc=;Tw|l#*sP7t#e6YZS5wCI{AJ&&onS6FA=Adn7B;P$ z*zs9@GOshCRiwci3Jz0rSug0V^m`s)wkfrPfVOYYnE|HKCM`i5DR{#lEwgDSn|lA5 z<9g87HV?A%K!88NMucqikB{i1mx1w=_Ys@2=G~)}kO4u1 z2x>L88xs#0fGp=c$XXJcN>O@h$7EyVBJGDm*$}&2h5eHD@0Ba;C93ef5cWoP@zgpf zs4E+l(}O5a42D^Vggy}LKv4-^NrJ&cEplrzCk47nEP-)VqRXpBa|s1CYQ+oO`+}6h z0;jo>Id>8Y8EX3YS|Zx07q4vshRXU|rU?+om)$T1Pa+O73q^}WAbecy8pYKwGD7nj1K=@RNw7}E4wq-k{`>QFS(36XHG*OXXV!g9q2ZlYU7 zkW`^INnF6&s|Vv7oXiHqB#2&S2_Z%62;-+IAtG>tlJMPbg%V35-6ca6 zxK$I|OT6XdM^lI>k`mq_AN^%Xzu`&>z-{2o;5C!lOgRd!T^8bgHwKp0+9hRgNy-+M z3FXyug-0)`MLpXoFwJJ7C-i+Hp~x46`3s_QFkuH8SM>>y3J7`#BV8hf8Jk?no!X!4 zvJ~-4EdsP+-bXMvvS@;slKF{vl(1!Cnn*rPsVb^PfR_-BBFr6GUJa^zHlSmB4+|RV zXziuujD;>u-Z_AuR4+2;#?E@N#9=gHuGk0}14dHLcNEGOvOe4BXoA`WAyg@0DGV)2 zQfefGc}L|WKQxsJgcMep;Dhms)9F~5rO0NL!41@6%x;%lX;ccb$|kW7hZ9D4&haG& zrh0t2AjQ&EJ%fpxI`E*pX{OQ=GzXeShMm`ONK7AKP>tO3wuMQW>Q*ZGpx`u-DYQ}K zs`G>5a?uB#=tD5F&?nU_D0+A!{YhYx)}t&h`ac>Uf}l>+JBCEk`PdtulVV!~xyUw; zo@ATKUJbhN!w0Y)#xxbE?r5$XBFsH74@s9kM59ukCNbu{rvO(7E~v8k#zMp#C9UsUb_HtAL^^O8dt{ zsaVRelyh@#RHm?y$kmXLB0{gFMoU2XSfoNJ&8pQ+P|6OwDMh2FM5xQ_GT)M<4 zXjPDwbzCy&wPY0qaPkD6`b1*7S0V{6>+%#- zTSs>tOHI-c3xtmI`xrDQfsGt(fVSb^Ei0sFmIgO;r$01N05kbh`!jPfI;Mp(GQqxk`$5ZBf@E<6L<`_|N!x4nJW^CNPYPuoZ*uTJ5VG#6{SJ5JO0|Dx)n>o zOqSSgbeE6RB%T_9ttH26g_kyU%Vu}{uqC%_*5a>Ci)TvLY$$^j5U-xr)}msn8dK;f zBMFwJ3%10k7E)#{2+1)dg;HsS53;4xHhh&)0@B0JjDHae6~U+Qfj9otL@k67aEW*J z%=lAJ{pH6<#Zy?a!42NXO!&pg*|S$Q=$&<78YJw-U`Rz~eAp)8XZ9rQWZOeq3eX&> zk&6l@FL!i{L?uA=WE^b|rWk8=o+%-k=WO!orwzZ;xoG%Q%ip^*xqibz2QnyuhEL{< zDm2pdQV%OcVMip3ikDC}1$;#V6b|H410)(`_|QcaLJH!w$r5ui-Lj$RW;PQN<$ja@pHctEztV(`Asll&+_gm1y9Fk&>mfk@td5lsCaCvDdC0!)@2~ zQ+Ti{F#P~xd*45+zVZs*d4B2tdE<@h_IID$aVqtPc-{KH)yGdrqQI{I-Ortp%iqRt z+jaoE_E-6~{QGNP`F%VAC6;5yNFum=IR&MMH+*C5>hk`5$_#1yjc?hn$lGtHFD^*O zq&O}5)9lIZ-#k_Q+uu$(KK*HEm2b$~i=X{j`O=q`?uS0TT@!T?_5Bb1*qi3G_oPU-%xidnXcrhrFP+y1`1QC91F7=k?sYP}&}{_;Kd$Tsew>^tvlZ=Z&5 z`{Nqigr#T-hTHO?57}>jdwcuw9lqVv_riwPt|i}R`|iOR+kpdEt+LNv!^0cCnVSC< zzL}1xTc*k}d3PNXzrCouE#FvxeS3k&s9#v$b?7JfvARyRu3x9Gr3xN9h9xiK`VFT| z$FxCf$L#B`fe2L_2Vym{DtZlzi{?!^*_~5U9NuZs~GA#Uzc05H)5gN4~D6Y6M1QyYu6ZzmoKN_ z82-E%JQ!`?KCoocQU)^(F15a|KD4&B-e5%jeX8zm37`8Mt&?bOn+^jOW&6+U_A%~! z{zf~_|8jZz=j=PQ$1Wgr`?~$Rces7iymmo0utSIJGuM9eRQB&*+y0P!d3&GI7@h1& zzeTVQ-*_ti$)dC;x2-HvxhdE>YqzeidPg zl5uDD*ME)wGId?Hgd{2zNsB!ZVSe}0Ki#grvAz90Jfq>S@t%7UOG+sC)Z^J(G{U7* zPcpuem$t<6h7QK+WB4Fr2ySnG-~-inJ1HSmwZuq3(|y#)s`Es!Z;3Bn&TKegju%SWSMV^F1V1 zlF$S9$aQ&gTmJs<8Hehnt$KO7e?N8s`xpIvk7e&%C*iaBKC7xvOZ!&8kFUZGlis`Q zNx;gN?R6T-es9|tyZu+k)KlGuK2-how;6cb(?9-h^*i5@d$P-OXm2ml(5h`$zkwQ5 zFa`K^d`lRX**fAYl%WSSy31yz3&nsszP~Yy3n$&EV&uILq9% zkN^5VN3|DDRX_iwkG~-Q;ZGiYRQ~hE3m=!?_zI)%YhMNX&l|!>iC~vsFyF6kbDkvM z`Of99NWZAju4?avMTk`^|LTnWOLz7Y_7~k>p0S@=Is3_~HPHUg$=P42vPb#Exlg&X zr_21B?2J}`4YCLELC}` ziBTC+!szUo%Gqbm{*U%wt(^V8G>N(;77gHtJZ4(sx8R~|rNl&0;rv&9qZVD$-4L9B zlDUvXO^QNzmpixVR*KuV1X)nKXtIYY6xtm_VSqWw_e4wPI zsv3nNTqp%vI(I7ZR2!*WniL|8nmKJm zk;86Wi{lBQs;eBTx?X3rG$=eUqy&hZyQo5%F=_}N2~|Hax1k2|G@in!wIImiC>yDo z`HL@(W;7iNBXf-}Ow0v7OQ94pWb7!_2b=1X`f0A8WL#j!s|{30rI(>7J&Y}Dlzc|9 zxtUUz7qc0UX%REx*_Gy)s+K5o+p~tBE1PN^kivd-4}2=@iO^kJ8olMdqhD))Ret<@ z_jeLz{@a&-)n8DWnfy(ORh~Jo0#gp#l{K$fT`awL*_E-z3+PJp%E$M5yi<^J{JMN7 z8Zf?*F-I3k@?v$#&-IBSHLr%w*Oafq#Ft%2rL9(9mBOE#%syEuXs#(f8HgL+r3bLr zUjF4$=l|j}ua^Ggj{L@wk1th^7d3MKc9~=K*H0EXD)rBH{aOP(%*vwl9#(m+Y07%Y zs|KH3N&B6=XFhKlQqX>DDen`{E&0OJC9UGl{q)k3FW*;c@Y%(EoxSI z%ha!MWU^*bUOJ2L zp%T00e<*3xvb4*;xyAf;>JcmmOP_G=n`o8fk-rlRsQyVQxfyt{sXDvnu2#z&d%G2> z{t$Wp$rp?-EE#4??{KSjsX^ z-8ZLNx5_hr-u+(_X6i3@f9Lg7-+w+H9-kUgk+LjTuE-9YdEc+>;EIGYw)Ac$gYzsE zxo)ny8i2_Yc8TSmEZMP_(i9Fd!}JoSM{2upYeLnMMJi|gfJ$cBD$3BQXBYC2N{ePv z@X1xKA*FNdUY1r8pf;&wl9yVi&=lWdh0a#jpk7g0{|EX0w=?#35gXv|ou7E%`7{iM8cCbyINTbV-5!sHE1Y{jBaRRRe`WmkKs2QhB6M(pV3c*p_mV z!?bOQmFsVkg3s|pPQ##(GI$^=V}i($L*nx#Azi{Uf=7!XxQ-)RV0}H_llLUwRfs0 zX_o6F{G){R(Byp$BmOBD8j%vv`L$tm$cbzM{IY^Bc#0`vvF|c*c$HN-yU=^f)KT?%mK=T(Z-uw zUq3<3WAM@QtwR;AQOZ;eHJUA%TQ@y=_-B}I6h?`KiL37oimSR4otLei$7+A~NxGLl zo`tZ>#%f%kEQN1{I7~94w=W|_tH7f`wVr36mw3Dv+QMoebcYPv zJd?SZ^JCk!jH$GSMP$soI+?NAUGNWRf~YoPw9J`I-9%NT&Pn06KHHNG8N(prb+7AF z8*M~h`+k3_uiika?vXzQFK@2o+1Q0>WzOgF6K-Ba7QB-6JX%MZBIg!pgbToe`=y%B zP%JL-ekVcYM{H^Wl?Qjpvbc=lr4;=_2^G@wmIYmV5>x_t0Po?Zovgh}a$hK8HDL+w z>n<^_9Y#K0x0Eu>o8jrxe8_#ikzdRvK0j~drQ8M*R%PPV4gqWlM3Y8LmXJsYbO^Id z<$6eZ20a57qzMo(!7Fq)lTRe{ZdN&+Ghru_KY5UE`CNjT@Me%Pcii#ZbJFC+$U^NBe9>nsq~2%}8ae zdT9nobQC`Y;c+;Dv^2mZVH0I>l*ZjeP9t#MnVna?qbG;s*?Lk;&iiaa3$Li1XKJBn z_1D;3LxzlbMDRlYQ287AU1l<*+R@*3-i&L$=~f$+2_JX0W>FmuFnJtAgQ5DY5>L+P zR{8$JXSV;6U+Ya?x>)UpR-eJnj3%M+MbktRHT2Dp>c(`n7pD4x+7wDiRK9|s*0P*y zDL3%a7&8U^GqC>&q3E|Z%#7z20ehr;Wnd0XtdAO@6)+PW;)IIK?^*)Xm)!VHUJD#|uqPyuk>Kb1SWc%X;jZSG^LbL08@ zO*s90FjRqkT6(lh!39Jwu15bmkLk|c?>g)E=2t#4Y&AnqUYzhH&4twl8n`SBvqqNT za?Uv3c2{3?Rd!WzmCs2wt%T^)%_trW9@%U*!lC*~BR&)Q)?okju|I^CK1}GnFUkTn zRwTO^Bx?f$@${tgrdx9*@wV)$X`m`RU~612LD(lCx;rlTy)Bs!t(K%g&b;nOab zJdUe@aY||=^^YF$s}EdRr|bkY0}>+PLPrd$=qyLHPk*6~j=Z)f{F)!ez_}{i3@3H7 z6_rQdGNHK6Lp}Ur@wJ?I%*5E0HjbcJadd-&;tFU8uLraJL`R)9e;dwM5VMJ@_NWbF z1s-PB0H5biv*EMJ6V$^x#_lITU7r<_kUV10{NTtY&TMizCdu8Hy)C zBzU=Vb=W%*eC|e`Sb79Vn~nL-K@=i6Jt92Q77d;cn<3^+e3mN2L>!awN(%_!oZw2%qpEsb^-$ts zt;72|d}P5_1e!-Ib4<4=uYX`qF*X`{y`<~e!sV17kQx6FVs*k`ZO&&=0Y3Q4ngh zdk<2vffr-L`Xbul#@gB4vD@L>hpWZN^tz|vjr}klu0I~f!+=u*7oh=U$nx3oc(@$lupcCI7z)JTDYyBJ>b}?U6rkQx&(D=lCKHu1XEbk1xKR)wfTJ^*A z+p{CiJ(RhynYUZnLsK)z+>z(Ua@)^GPHLjb>i*%WA6wpqJ3L)EQF~nQPV{)FobYr; ztngoVr}Anxf9Cbtxw<(@X;EIi5*j0Ue6k3~dh*a&{2IkY?Fr8qHq2l8GZ=UK1`g2z zO+7rf+Og4A*7*{JyTNq^rj27=Dp_@Ktk~G_58eHfovsVUpA*v@JrlieEEXZ+6mx9H zuikrR#J7YWq#OCGmLlv`C+$jijO(eag@|4Qs2m-aq7HFuil8n@n>SFXnA)?50O@70e!$CfA@wp*`#^{da@*2cXD7kKo( z&5Y$71Lo?z3$Z%8oFB^nU+^izj3G(;6NDWB!GVSuGdFtKD5IeFfML<5Xl&zd!KsRBQaEZk$ITcx?b4Lvli-^=fLc&ww1bk$r(BQAj-j#s_ z7VijpDZsAR(Om%sAdi~?DK<(>i;PDXAGo`y2dDP|b$$(ouicsaxT)n8zsQ&3?bX0> zzKHWOY1CpTy3=Bve|CtxRhr$irJ;-%o)1jYD5DY55OLKIGUjZKJ2Tb^5}IJFWYn9Hn;xKKaO%mt}Od*dk=j5f-n@~G^^Di=0;7}^Jr zi447I8=OU7VUaTp#5%}fKu?uQu;PWO6rDSr5gATIN|mRjV4c$)oLJKB1Ibf zU5aCCA}xtME|JZXn6}>b0+HYPwCN;(!ayeB#kvet^4f%(aYF_GPmrkYAm{yHw2;X- zQUKNy?PEzQ;d?^3k-Dd&kia^^U!GPRZgb%cNiYMG9Rj9j32^NEeG~_KGc0Ilkp)~k zU_IzM|MGQb)&|ZfYdXrvY${-fQ<2D@Kis0+Ga5}htOy%0WFNl9YZPP$*tBu_hypq# zsMZVqSZO2(w{n?h4U}~+v;Zu1PT?;h?o{t|mH{uA3)ha;lbaZn* zppjTm^fTBjGau(!KSzhQ={qDg%6dm#)i1rFmekLv=xUEToYMr z_B<;N8_RaIcS}2CG_z%h)Pt@V?ckWhOIg;EVT;Zisr^*9^)|JEY#>1)-S6ufnGpaa zr>bdZb`p8M$|k5Qx_d-i8YtdKq|XHQ!LhHOe>NynqL{8}>-MCv=4{Ar)i$N~W%3ZE z9F8(!q8WLLpr;`!2hlq#xg$i3O^l+Os$9N?Z=Qw6=Dry9x(~``7IpZ1P&OCvN^he= z>LybK3J1Q~PTh-nC8oiEyzBujW~j`7)1AspI-bUQAh@;|oql`Tc$&;Q(n24vdi(_JH@G)@x_5#>&xtAL6w z``u`ls#p-82v~v~x-Z=YTcEZ(o)uW!O)D{daR;MfaNz&w36C5 z1x2X<(IsfXv5b^g;w8RwnLcvYu z+Iz4+#mX#*s^q`*tko64-6f+Kk?rg9Ua6XV^B>dFP4(JvBp{VS)MXkxj2m#x2ANIbt{Sl{kfa1^zah{(x?v*;Es5v}!*XEl;Z#1hI+;`2q)hN-5eyQ$ zP}+jm=k$69H~(Cm_^27ut_SH#E41|GfW?GLBWKi2d;+$Isto$ZK(GVc1B9JOfsh>d zN2mc1v`d6}$UG4*`B`-%Obz{jP${0>7JB8r(a6b^Is#2N;ijNPqV5dQw<*3wlc)a3 z$7&2q*{b#jp-z@Q3?aN^y`NJW|N#{D?^F7&MS!?Vr~p3)XFu&?%qM(*owv5{d|ke#a3R{ZJWwyLim z)Q_~6x{K592FK9+qKHhi7X2Ux`eGiqufMfLHhiv=m0|}f7e3QPxe>ghbv%iWJ~mM;#@dGC7e4v zxxepPXyWAJ8Q0e%(E3yEzU-0y(=E2$&Qv#^@2_MlX0twVtw}cLSa5iOcb^W&mh&&1 znRHKI4An`4dUA$<$G8S{q!L4PaI;C{MFiJAwnDK@e`;l8!!)|BEuN)n;cS}m(N zx>i*Vw9QlW@8_$=ZmH$E)^AjA9dFnuV^=q|VAi}1#`hnjX3fwu2Ld9^%E>_c^&4i+ z@TPh`lSim3&!c+7k>sb?v7C8|O}md9_lxzdTpk%jZ@c8phHl*B41A;aMBbP@z#$7y z0IJ@)UXYD$kTZ6rf979qS*(_INgGhVXh!bom`yH74+*FVjcfh1M5hfQeHJmJ4xH9J zrgoWWxD}}$9#mcHKHGAwKJE%1#}$)X%?`(vAzewbxk&6jNQ?SbOFaK3&We89rx%1y zIA_POZccmmSNk?dm7WvM%X28e!zbMqbI6UPh$!Ci^it!%<%dJkU3w8q@}CMAtxia& zG;Kp3hd%U{gj$T^R;f~`_4_@os|=qD#_FIUe2L8rU!ORJ4$BkOJNIeBVN3n8ov_tyIU{P@;-(>{nMSyE-?ZfhI+mo z=CMVW%Io!)GULTLMEP8Q@kZ;@e~PK4*{9!6nv_4X*~m|=IXpUj*KGPkZ1lU$2Ts;k z;^?=+YS?hiN1m(6e5HOMzfEQh(`=0M?6yle->Bz)&KnCj>Z$7#(vVX;x^RR`F>=}}_uFy9MT4KfmEYXj66P2>VlW&0+{nfGp<(9g^)H&+ zV_1{ZH7bNzT7!=qa$cqn*Inar7bcR+fz!|TEmfa$psfulfy3DOB_5&4T<}5_8F|Jh zQ}VTPwAdnSQCYFAAkRBt6~dhjcClWm(iO+^*W2+|1@V7wP29BPl0049D*rGo}PUPy=0>&(wwL`>GgU|iEVkXNyR*!$-~|Cw}UkK!;_S= zP&gZC(yhcAk*%K!%rB}k=Q{~ZOSPM`lgp}dS9sa*EY0`V53Y=DPe(R2Pn>4X*<1u? zTryY?kTtCbA0sB021CI39%}Kh(^%KUy${@(&F`Ih4&qRZA6=F~lR@V@9yz^sR<-VF zQ}J>LFPKPil#hU3pN!QEG{?^5U=WMjk>pUx2BtJ>edw$(O)Zj zdN9iJ6M@&7vT$_s=W&t2=feI_M>g)_Y{)&>u*SDsH#WyrPF`9LS=8h~xoc|XjjR`J zuy-Al_Ce~N9i3m9SMTZ_vcWvsXrXnlyV>kYv)AN-y-x8Q>V>8oKh-;!`$|Qc^+jH3 z^{ltzo7VQ6Gh@qc0}qKk(_eA+r>yhYxH@qTnbkkC7T>-2*Uy{1kab2fkV~!l2df+7 zSZ#M2?2jUcC%p#!nMxnY+{1c=@{zEy-*#Vuf*pLna?*y|Tg8}Z2d}ThhdwizWk$W& zJSffhI!}5RtvRaXk{V5+<n5wxs#zGzPo;A%Sg5;rLwVWFYE{v4Jjcq(fb#k=Kr<662;!kE5~@ zc_}^L+;oxsM3Tnhv%gcN~xnQDG$rjCgQToM&=_rWQ@$s3?yFU-!S_hrJf{(^mYPsG2vuwt=Fc(QW9&%|!DGvqW4b`sgB!3CSnhq0^Z7O|Le#{2-?1Rsv|mt>M> z&#(%N;?X?5R3A+@;|lD&@;Dk_C{x#g%m=f0$7UgnPS z=&K_`;Ts2djJMgH);33@+UCRinP5=&!TpP{f7CVoyoQ6f+Wzq8%Vju+Wtq^IzvNi}i|;p80qmKv4Niqzf4@ex<*8c)<@Q18So$?m9k z*bRC{uH0R(Tw09y0W_D>MNe$pb@b#exxNJR~wdK2i#%@{Xs-CF2PeDfWp%s7oAg(b)g_zy&yc$ zmTX)S#NvXMOAJB?1Y`bSOe4=BiTh*XjGkTaB}#InB%?37AYXwR(a;h={gTGMhp2*q zh-MmXNRu$|M@ta`8QUhG>R?I{iJXF>zCmIvXaV__>MZMnNUeXF8iU>=DrdHkKqmpG z7D1$dN=m07>JTL=*Axj{igHnr#HhAfUsIa0 zj6u9uw%O3@?9s9oeap)<7B3pAx2Z^4GN8$8nz6%Q0^_;ZbRIrUXWZv=`Cy z1fQGmJEaxH!!>32+fb?^8=eU`SxDDuAlZrrQq&eP9rqe9pqVbdjA;g^fj(vk5Q$I- zJxi|?sMo;F5h+$FyAYtIRuwczf4gZ*Oe_8mL3nS5hs30mq>$Dm)vVx+J6S^F(P#`_ zFE_!=7laOvIvF%UV;)RZ_B431?4S+F!i6O;O>7gKKj+D)F(Q@*bL~k$=v!baH$;d4*%Y5R{ zX?T{KPU6xD%2@79j;3+t@?IxzAOue4t>SaYUgVRxs1?`QaY~w&ANfn*V$oo%?!_ch zZtGIHs#)Ao9ZU_tlUvnPE8tmj+2&E)ObzLx3(R6V525S~=83W^;Dd^_4{8#Km7h~o z#p!N8LD0}f1ap&$RlUY_hoOs72~M1NIF{f+Y>Fsf%2M_}q6v#Bwa~jj%M80SMoHF- z--F+Ts;W1UQnV<(OnFa^_sGSBo*)@S+v8?P)%F2$OgzDX>K~BqW`vKGeM$0a{6P$w zsKA6?v{bPkCRvO%4|P#Qk|YF|w%jC1Q#Sh`kxNT#fLg4g1tUL{5!D<~(i%ucID+m9 zrHf<^bBT?h`9(1`$b*QkK6FRG=Wn0e1v|+5xmqLLS~8?r)Hv44YfnRBe~jemQXQ{q zQO}2B6H{Y0%&j|2sHv&+myrYi>S)tMB$pUe9q3=r8WK}Os!6V=(WT~%6c2-4p6L;V>-P^Qk3RX8ym2_;3=n|X{dii2j0sQ_C|gP z?tciqsKhdnJ;4%9343A%JtXyad5Y{IKtWM`n@b_kA=yJ$6lYc?tVUBRUhHU+`BLVf zENV>h+z7iB)j3~bSDjrfK-a$;AgDlvkkdIzNJ6M#m$QaI8_eaui+e=E6%b1b)2)UN ziswqMkojF*h%SYfHHs49PFaE?)TS7O+MNq}aoNeI!)T|v0WMOi!7Fd#N!bFKl!A32 zbLyLhA!7vnbU=2+UC>AfsyFuo0j5-+_E3KBp_Dgt`=ydD^eGb}(k2TTmTSHebo>-g z$x@8zElSi@DKZpYy>^S$R20`Ti$JwgNMaL?D*PiSEv9LKv_Nt)UqOH>p1+X(gMfik zJ*^*D2x0xSB4k?3K`3ywjYeQ8qRi>=L9&J(b=8!a+!_S_3UxHbIlcx(@d?|Lrs;bD zP0MJyCUHBYlv0pNCcUI;?TIJ!h9bhvsXru6m-&&bQOiyN*Fq0dMAb!C;ecu>nl3*3 zC3p4=p125b!7yB=q-#{?TYvd6{A`>(GgdESP?_+JO5p`@ppZOMDn8A2yszzIc++C` zEPQBbjxw7HDEx1!YDkG3V;CL;MzfpOTHLLXklbe_mYM9P76Md?`tDkLj#KRiQjnyi zBK2%!*%DeBM+ejx4567J8>%JRj_0;iWFbJSS5`1(i_~4UPY%HlFkAbR_e<#Q22^A5 zGgmPaE-cjDTJoTVVT)*@?F7T6=_sNAEn_d-6fOGe9){T-JmoC~n9`HR4dw1Sf!nLW z9tkCy3QYmlDti&pf&u}XVFRK@F`{aXrN^_o+_KMJ{`M=cK)Z}$cfks;fFz@4@34 zj)?FS_Kn5*J@OZSk$gh+deu)BeweCNeEfXi1M|@*eAH&s{S1D!v;e<{#~Dt?;>a z`SN$ZW8ZzZC}W=-+eTCTL>&`6&TY#(@5s8nyzRYgUoOk#vb{a5?8b-|A9soTA&#{w zmH!!!R+v+rMcw37Dn)m-T56EINa3&T-Al*z$>r;X=eAQBJz_ii-TA&_+3!!mu3eYF zf$Gow90l&*Z{NYW6E3#oF?;D!?G(xwB zegU^^zwwoizmQx+;ic{JcJsniL4Ka1|CqpPi=__1 zm0GJspd~=d|`_1e9PlN4K?`yk$*rW!ZdN-{7vrjYIeD}NA-(64H%=@v@u7D);$!)tO z*Gui6Bo#W_$Y^>YI%ba(Uigk#Bu-`~R@N9e;dZwcmgA z(dw`M`LF)DXkdTs54OKYk4jRK(A4fJiWJ&?$4ozmH!}5ecB6jOqwtDw~+gmvA zqTIbhFb&2;gO7~Yx8Hgzd+V)NUcpP-m%oh1Fyw0$hRj*pcuRcuUHkUi+t+X|NmBBg zsQ%hWAW#pA$*&vCszWE`-4&3eltCI*$$i^RKHPQ(+Tv17r1A zP)72@xPo8IOTxfgq`ZZcdtjm5S6)d26xqd`y1jCWgkwKRzdyU0Z87Il?zQde@Be`(r~zU!GfPsC~4&wd``%zg>KiA1lxaBbUuY2ADuuX%Jc?F6Yo zQ;;fCYV#v5BTXZSjAkI+@{ayP6b}_g>PT+N??jxP;I58MA`X1(XNUauo;tMD&kIKuh@v7U zY78pBzm&b0Fn&^o28C4CLDR_`wZ?IcimND2j+B9W5u~ugzrcwrbuz`H5-`|Dcx;zTIA$j9SLiAmX0%iWJ_jnh`jiIyJN3X z%2Iz#7Wq_2mmdfsM@qmg!DBGWzMB@ikZ7xijgJjdP5$z3wys}mD4#x6zTh=)>yLL+ zjh`FM5zlu;JaqeG(fDzay!gCIR+_VBUP}HfTqzYZl$ieD+=W!``~Ko>S@W9ZP&B8D z9O2)JkEsl~W$6#?tDjls4Pr{2-9}Mb{pFHYalg)8 zLaLh?|8gO(vi|RuIadGO>1LtJKY4noOR!;B*so7L3jKoZO6CPP5|?G%^6U4>TB_S$ z{W10{ux|!g(;CUFRi?^A+Ng<^dm39YUObawVXHt|*>1G@4tQxKd~1iINTTV}h{BRW zYSC_YHl?(|3D}ZW`dUPZtFBnU6)2etnIrRvIg4>C2p@6ka(^8my^)%6DQ|<{+kzK9u%2 z0uyFhk)=#&@_8Qa6sh|&eFrAN%S=%zM;@0s^v#;jBpQcIfac{)+!q)bkez5;%bPQf ziVDeL_;gVQv+HDusgRUItzT&6A70X;TVi9UOi8k;QUGP_LQ#+1xMD@QI{Jz%?LCsw= zQCdn>i|@ed4)%jc>e))Bl4;wC!n}DOm|uBQmQgm`lLwCt60~xmzrq8ViN4^l2l8_q z|JVCLjo_Dbx)S(uxSm&X@q}HLI;wRFP^|wuWN_9OUf&j;L6{g~A8#irC$s%$=Mfh1 ze4ajRWT~?z8^i2{afDH#$CFj;rva-31+UhvUE&cJr{tcfzun1Io*dTlW|Vbfws>dR zY|)FxIw~k@#$l`+(43Ce@dI(bE|-GH+{E!zKiujZU221s?@nM9?mK`8dL*>N2D@?E=UzF9lJ`@jC zsu&6_jq-@+h2HM%5?NKH*{zHSqU1{uBdu^_ELy)q)QhG;T zq-@40vD~pC2gbUiiiP$>9d)Hb`l|IFh&wnKqR-a`r`0DCn%h7hVu4D{fG*Q6zdr70 ziQ43JUbXRb)~+T_(Ng$N5B5U2M($VatRbR(37BCm!&qLGbBseLt*{EqhS&)r$1e^K zF#65&ZF02P7^%+A&b5O6etvSfeSbAjB(D)pS2A9J%&sD`uU4NV>F`Be=@lAUOCJgN ze8P-_92PnKx$|a5;jG_ z!>q|WXL*}X#AXNA?BF+B@Xg!4;c z!ftkdHa`71apPgDda}Qjt!86h6RgGVY}ItO==sd}sKO%(LJX`*(>$t&XDzi7&3QJ7!k_F-0EH4`83)6r#g#@1#tpPbpWyZeNEX2iYZ&TOtq@L~fV+29K^d{%u7 ze{H>awBo{n$(_{7%J^|DZMJzxWL{VVReI!Y=Uhr8$6a$wx@O5+{RE@B4a8I0|?&D$C_tfen z^NMlgUzl<*qOHJp4`vZ*Bn7O~PlyJg3`TUtp;#N4M*{lsb&T4}lB|DuugNh1*%k|! z!h&ID0~<(MK-F>MuZazZJMi|d8XFGQ58^Rma^*#Qucns|&T(`Sq!Xm;nFGRtuk6Pt z9*)S+&wNBKY9Y`WFF*X_gTcaATF>{mI_7?l;&2~S}>p+J4*9bLQsgE2+7QV!>Q-cP z{TbV*PKzK9Ss%>n$dW+!;d9W2^>-|~MBGL&(xN3rCVjkm4fTV#%umtGZ{Do~ErG?b zfxq5NzdgHSf28r6fpzZ+ZY3il+}4rd+MWr0ur@o_+iz<*FJyJ}8^=wuA}=jx+UbNZ z6biBbh|p`+4GruL_dpm(5(n(U_JSQq_RK+k@;SoohtI+_Ez&)g-h!s~vDf1e@^Wn$ zyd4f1c99k#RfagAli?hUB~m{ikvs8)g$VyDfn+C6NPey9Wook*!v)78vL==N=bE&R z7zR&#jY3Nx9v@oIpYgRCuiPQc9Phj?BMJI?cMK9RIT)RXo?8P*8;yf^Sp%0^DP;f#cT!jYW1$o%wRG+*U45pVb&UXziye3j;vE!{Row+ zbR)u1L*L+wy#1}y-&BKCS9+EzO)VAS-54=(Wj&S-t~z%^yQT@T!{3#e3?tv8MAOKd z0SURx2EH>}9B9nM`Jp=#S~Q44Fe=&4g&~SrX3ZD_WwM9JkHkoc`ZMsUU@p-#gN=+8 z@)*l!zjP_b_Ai$cFS{r1kmiYe0|#iv^$)lsx2|ul<4)+n(c3ojpUQn`jhJv}59XU| zgID)A*0QiZnFQyLTTToI#}CVexH!kFES)2Zh$0yI6PDJ%!XeDE1>V;8 zFByMZ*M-%E3}#nmSZmfh+#0@GVW3YVFVx}=ri)bTGlThNVYZMU3QgV09n4$R?1*t! z*Pd_K#f9d^6*D}|2iwQb-yb$U-W$iZi{XmIW6!d6@>lk|=bUEuIvm1cU~H_!`0U2j zSnZ8^F+OuedTJt?FLp=h{r^$+J}`0}=Yi)})ivWc?Me80IOL5KWmDa1$t@oD(ju9d z&I(X&+s# zGh!fal1d_Fnb;TLaKQm_e7V2}__7LbWy^+F_T2BQ_qu0D$@bni)Ahdk>Z`B5`s&ZC zSMR;=tv5}iEVAUQO>F9Yyb?Wx!;Os?A9-zdrE_X%&S$koe5ilziXX=_S3;+It*qtwVxR|=lKrUlI;1p23ABO@wXUuKAkS9Bb%!uKk_;3|}Z7!xhg zww9Jes`(a>gOMEltW=b`BTh9mvb6_&4$Y>@Vtf=o0c#%ND z14K5X3JJ?9A5wC)1R5w2@omU#g%33)F+^459l*e>0)fO(Q7qMDrbyIypa${+<^nbI&$Dc~Ipg$l5bnGA*`U*bo9G*ptOoJLZ9-pLB)#4d&}YK+ZDj7!f;wJS zsZ8MU6!NkXaDiiLcDWj2#iQZ_n^y;sAreUl#I4qdhUKU@*;IYW&J(2g0A1NJDs}`- zFs2)3l*PME5&~W1l^_P~behR)bt)@;37wxE7P*n)Nq9;f90iq^qzie#Ig}7ftT-P& z$w2a{mEp?m1}5aCKD%xuj_G7+@CKG_++pOVd}dL@R9Wrt@;)kK?;1Iz$DNbGq2Pr@;ryOBE`+c=ZH?2!e?4;`v~(qT=)~DfCjq(B1d$6!7Mz2!&(+9%+^0D zuVk59z1nCG5F|Dn-0y|;j*B$8pScO8g+r5ZJ87(UwwARWxDBaYLRF)5fH9zi1T%O+ zILtw(9C7H{j-dm}Qqv#Ock{S}<1f%3mNRO?$|#q+ZG__i^Ybf=y$vSaJT)CWZTg7j z&PNdzuLXK)muR$8q7XY`sb-r^8a$GR6>FEp8}W}+bd>Y5rTWVGYn2iXAig_iVA=9l!cfcNDz!Aml?KzcG#}0%*M&oxC zt7$2!(i33WbksSgEV@Xb7BPY{D3U#!;?xM~1Uly+Mm)(1tI@5RLacI?<#3E8w^uAA zj!svJHpx;oSjm7Rl5r36KRJrW`Pz45kaW+W{MrARm8Mr=F@EQcds0e5Z z%YbtKe*)J3ju2B}KB`8$nb=tGc4;@ui%n`GO^m4_cXNf^5tAZO>_Xo$lwwnreYldf zI8xc0fez#rJS5GC#2uEtqPsF(y_(`trEwORaY!%|!I3p8F!d|Jr@AYb+BX4RCB_m@ zx3a+J%7JQsa+;iSM#bhi6$iY=S!zpVrqQ$!sz?Dkvqf}@ILA=EPSrheZNpjWqaJ(# ztpanbEmY;ONGOobO$4tDJ;Kyaqa-N$Yy)4US}Z~iM!I9HgRjTHPDvi3?x3I&Ly#_+ zU|3c;?5epZrC3ZVrj>>{@R!t2H1lj*jT0or!b%p2x~@bYW%a)Jisr~jhK!ki;OWSHCfH7YgN#SRZ>xKfoWaUbVzEJl;Tiw-b70kOq8gqS!odJ z#*fkhUanm3N2&rVAQzOuOK3`;&OhQJJmzZ<^(;Mxg)BbMFP3~~)HA(QUclZ{HglHE zChzl{2wMj z#HfzZ(0*9;^v5N=53=8ztVd?IzC04+mXI|Lw0v)Es~Vn>abp--FH|2spE{}U)qJxv zWOHpxaNVUFAC|?Bi}^58m|BKwGp<+Bq+DLajEd^m7?AiVn_E;MusNUG8cJvGalBKY zb{>Ol^~s)9qkHP?>DCEWAN}lw_b)_`e<~qx88j0 z{NUxxxlwb}3%!XGKYEOQv0fYfbh9b^4=C?tOuJ9kpIhH@^`*OBYBlSuy39G#*%%%7 z6XVQaY2Wdch8mZd-*A0qGg%fZn@!6#+{iw}KI3M$N=+Io`-dNR=!02sUZyMzO$a(?o?%LF2$ zwQevpOV|6p5&6KwJlEEfWMC2(l-y+J&JNmoW(w} znw~p`c&+Mb7tqd%KN1hG#6Zm2=92-53MwSGKCP5KoFf8gQ5dP2Z#mpCcon$9;`=PU z7nE)?ZNgRaG5DCXYns!jL~I|bpKgktC{v+}0|X!zKP`>)i`)f%Nl9Y7V@0f@nJ7OT zE`k*B7-iW&cRA}GTIR@zX_5Ou&m`67TRE9oHg4JVDJ(tS6{+Z z_9myPb;VoSQ_Fe5zf_N|?x`p@|Ay+5dO^~sS+(f2z zpZjj;%gPptoaAo+Fm(P58kY|)?!$nV!8F6>~ntX?UXq$ zzo+>@!B?Z6hkyxJNwGzz!Iw~YE^n&U9{V6f%BBVLyY0$t>oOU!w^O&Hp}8o_>~cie zlIL-ICC#{gqVs+h_kO%dE3x*-?#Zj(ugL!Bn`_T=CxNTPWqY1dhB0#^q^gg6>-X`n z0EGr>{$OyX-eX#zO>ZUT)G0il!ez6PLN!07vkR-XS)65^(7v*$qt_-klo&`6GYxyA| zDsUGBaG#Q~3`J~77crob1`bJ6%4!^F(5nEYMUQ+R8jl3MTH-EAGxuFEqLns2@TL^K6<*FTVWwtN z@LjS(WzH5J4WNGQEr&aI17$65%=9XvTbEAPV)Q$^2fW}sO@^V-%$I0P@A(kXy`0^x z+pL>fUasGD;m+9T`fwolhD8tG_JDLdeh>mGhDOhX1NZvy$tVxsnT;-9 z?1-;l?apZDMx%>Ex1f%1tPK}lsfP54LR{HNs^5dc9M_On4$;28J#9z9lppfk+&;+i zT&ugal>0`*R@Y+)UYb0W%J-b|tLvV&#qWm?Eq{a>eLx1fp6^ zAFCeCW49HST+`A@-lBBZHn2g(V~0RIw_QG^nAZnGwWyG|ii(yLZXU@gGGsQ$P&`^M zNqy8J!B=Yf;+F@NF!k2Z^?V?cGd`$LSTYxBXVUq#e4%bLe@T zF@x{UtyW^h_utI3YK8;XoOK<%B2y!E4qoy3C5_?>V5$RW5OGQ!D7C>?0yrNU(8qIg z#YD}_Kj*5fxGZ-ySz6Nh1&?5?&d)M(vZ<~EvZc&chWD~TvuQREtdjZVjIext*s6@f z#vokq6lJnn&=eT7vSz@(5Baw;?)z~YniO_|#|X+0GpJ?tg4L~!F}=uR-2P)Y=N(RG zV+=f4%0s(@C{vTi-CA>oLzGw{UJG{&gl}iY4Y(1P<2{Wh=5YzetWX=UX&2Q27mw&m zek~62m)4CT-&)Po2I~VGy<=|UhTa{cI6G|CDGS}qVExG6H8=gS!J{?FudYRx2g>5= zae!|1>NM7L^NMN;&gpQ3#=<)S>(N@)x9kIkqcKh?PLog|{{Rcn1|N%wQLZ3|XSLWg z=}3K=<+F`x8-mO0Vp?YXI_}n%#w>9{Et>T~qsML5{76JjPYT##(oA1&wWY%$zkTW6Y~xw86uCjE zQ)?$%z5Nn($~Mlnv#ief!N@S~JDc+~)=TZ|pugAF#_FVwiRMwyggKQv#!cF5Os``+ zMu}2uAqc|RIG7nu0PJ*|jq2vUtQw^IAlqh*tfiiMu(oJlrT5k`zn3d$XoM_C0z7DD z{350_1(x+d@H{zrFC#$xDh3`@^)sPC*Ju$>GWu!bbBo6I2Z|94eH>R9aETN&ShJ>PWO3nh4gCc~*F-0^w&t4*% znh-QVZ-tOT4N?Jbj~Uh9mvqn4fd*$rC=Fni=UTwWe;F(J**);71++Qnqe%*c8U5dB zc`bejq-;)I3I%sUcj@MJ43is+a^>tv)}ka(3Ad^k!&3tD^#yPob|t;!$L7 z0&OCub67SDQ@7|XBAy^=V?0wRpX%F8GK&W!qm2Dpc15f{{WhWmACQ+(tKMY8nWK)U zeN@1)0~%a+S76aRmBp_9q$N;5}#61b^U^Eflv?9SJ6RvOXieg-lRq3KP3#i znBp9NWRBc&RE8Ml#E6l0SDOg4K4IWD2jX71$wQ-Y#9T&u-Y%dGNYrdFa)^sGnm-Y> zQzervQWQyNmYXQaDo}hujfGGKA{`B&k04MB$9mW@&~6^l3$tpH=a)bu1%L&xg22j6 z>M;@0yp>oefqPDYL&24D=;Z351Ws5fFQqDQdLT>`jW#sc(Shp6c{HSA`WiwD9xlxm z&4_;Q;flKA=Lw?RHm%u1((`fY5+?_5Pb!wE0rQ( zk)#xO8$^=`ELUeGu5rO$G)_XxSi-AwN^uO+fZVDH#jIKFsWPfAdV7^Tl z=LM3KPj#9F8`(84%8Vh9VH6NcetrcYqao=kglr+TTtJHELhGtd${xB-)=IDl?j{_4 z&VtyY@>+c0Ps`O%x8X#lv~=u1_5H7`MiT@72?Ir#CWNPdqQw*>YO)x zl%e507fT(kjn;d;QN7dSQXMUQw|a2W8{y{vEJe^UuOhf9KCtO9(FSOC(A3nm+yUqE zfi|V_En33nE~3mOeacG`upWnk5s%0n8H#1u;kn8c#o` z^^SKS34LNvD&?x&fQ-P_45w%wjP6VrlA6QoG#w~&YMgk+8O;VU@GF{BjM~)cwHFI< zFH@SDGi;jNcb^XnWyr2j^#uGp85K%V1rib|(dyu~i0*_pN!lULv5*iyk8%vV@b8Hh zwotZ^ei|mQQw|}aHwUT@xl)qmmWVADz;!FBN~e-h+hP}#d@0v1@^?oAMTNw|1r?yJ zo-|OrG^kRNof7MO)ha1ppp8_k-FEbvAfiRFoD{-5CWW@DC z_|JPiU5f-Bd4q3Vbo4S_xXcc#W98Ien0fLcBN>i|V6_mf4G+<1x`Mf7DN?FhwMFur zt%wyN5(0Gy(jy-D>2T6xKs+Hp@|U0}k+WsOAc8pNgGBP~|5Q2)>@dq$`^v=hQGn9R zT+)_lHR!yMD27mtMW{gKDV%Jfh^CPAdGi%bS5OI6yRwY3nnjY*LV=QF7e|Svq&Y*$ z_n&@PWZW%nCwuq_9ICzfQF~H@kBw4rAu`25B{iV&qwSJ zFa7e*+aG@Bmp^L%izR{|e&(wm9lmGjt3Pk=Ui#`s&)*G==$k)Bj+`7Uy6nOu8}6&1 z>;TTSh^V(L#dh&2i+y*L_fJ;LM9#lkm@*SHJ_vY8!h9iEt8Gzu=PIN`CU3<`Utmey z30kLA6<7fBPy?;Zpp+8LAVM8z4!~L*zVX~HCl70GeANErGymbEc6liUH$FOi*V4ba z2j*x}Wl)2wR_!BYpb27#s8GdJ_qJ$b?| zyDxqC{7;UaJTd%n*FRzRjQ-}s=l6{I{Un8qNhockn5w42Ci=1~Ut}Pz=gFuiVQN&N zN@YQ+q|!7;p%A(Nsrgh>qU0!gM8Qxb=&FK+#%96o&gI;_{P+hfPJ1?C$!tZZMuo@oHKE!AVkZrrF| zzrN>P_Idn$;e;poVXM3$zx%sMiDN$_H!de^31>&!d;yxx+#C#_Yj4c(LG-78DodE; z3EVv8?RK{P%}?MYXsg|Z<)&kh-zu7 zRgzr!ynSo+v!AsedO1Z0|BP4HqN(n=k)kOZZtX4~dl^4bfcg>JuD<>{b;5@cN?v|v zuWGlrR_oJ33Z)u5uAjam_SEH~J<4qI?QbW4QcHh^Cq2A5m5F$ax-MH!*l&#AyM(8u zd29Xd@9sG!H!vbCooF=AXFgNewy$4b+O}W$O0vNZ{gB;o>)A)b;+;-+0e@&Zz0h+Ah9qQfkt?lZiw~`yRuYFA}sbf9)0&3uQ3b%W+RHWRW zX)n%h+&Fv~>=?e|E+0N@uU}6X!S(Azm6lz9v1pIf+=r^4xv}J`Z@jVRAE5ZLlhwo5 zrNw#zKYShn|DX7T{e#QzrUm8LKKpmqkNq@_a_qmNt9(vdHQA~NmgL6QKK*HOknP4> zjGr4cD4pT^zEIs$ky^F4n|W8h-KaLN=D&WJifa)Rb|)3u{_DT4Zhz|s_Q<#K#Amnv z9v1xbY3lXA%dX3|_U^BK6$-XtM1H&a3EU{!Pi*7Q>%|v;Xiwoc@ndg(?9J-O-lY4@ zJ+kfc*QQ$ZC^F5gc@DPYuTAas?WH}GvGi-zKRA2r{_H;nh8E-oLFEnP9ZoM#+)s4R zc2#>ic96?N^L=Ey^iOeim?Yzq@6x5+H6|~P!_o0M0zZ9f;zp(oI->>aEmhE`OULoupB$a6n6M#X^>fO*LUy3RC=BvqwpQCBt z`ot%=6GC6}ZQSI2^VLs$LdWo70(`yQn125AG{x7xR{iv+zfRA2{af4in}^=O596NH zC?sre|J7enOQU`O z1mIk&Sh}cCPWJQ&(^nDFd067fUmmg~_-OTM_mTfjb1K8Hu$*1eHSOxja)?!=6_XJ=ARjS$F{mwYfQ2fy7?V#=f{q%}iI-4)DB zjhS7PmYx72nx5p)63A)ofP1oRtZhY#;H@?!p11kR|C$WKwj^%}Q3lKu$c^K9btGw8 zD7CBD#FTiW%F|3y&Rbd8;$4v!&y}1=V^#B!6ZRucJ;ptA@c9a?nAay&ky{tWoKdA& zw_yP4z?PG(X>0M0hI(Hk+aRKSqH!&oq(EFi1T)wv(w$fV5(Q)JS6uWbHiWZ+qx7;- zHI2Kz>YR;U$<{p^uGE&-O>>!OiTZqv?%hVsCx*SHJXwqMiOWYQ!qnj9*;Yh~qQoY8$MCGkTqBvXN;{-5%$iFOIh%Y78MkB-9^( zXjQ1tGipv?@9ie*oa5f@AVtgI7k5YKR!xmBhxeW_V8(ra=|ihB`sZ^$YzK#P?EAlH zrm?Pkvwz!p?-|7^cbr~e|Gbn^SzqqlUGV*9rwx9(D8YoG_@o#{|3x{Y6pEW$rU<3BJ-U)lg{4GcI!rov4~GO^wQv;e&pqjzDu_ zf+9YNzVd!4yr8*H&TUm&)Lc1A$#=s~Cfx|_l>WT_VY>N+WZI)M9oMyt=D+;-k;2>8 zk6-vW_X{<(InjKI(e+C#_XyJ*>AlUBgy{xUp^NQs^^#~$(NhZSoH8dVx^q*|DkEq+ zkV+G`L)eA2gKB>h%x$%s*uVF+q6|)hvl4so&NFoiXS~e)@x||df9Wf4nW29s^<~%S zOwVYo%cP_;e^Krt^?w@vl8;`o<=^@U_0`hduLp^W$nx@| za*ra`eWCOFMQgd($;Mu*^$+o{maJQO_QJdAvCzzw;ldBw1@pfYG`a9g<08kqF8orz z%<;ujUg`)jyc`@e4<^f^?WR)x{b@8$H2K2+ReE##yFXE$5|(cohtxVj8pO;o_9)wj zU1kSP%9})s)Zb%+zQDKxP^7BQH7?s=;pvn)wvfW+asJaOH5+GfD7P!i@2LoKpx_+X zz?@5tB1y77pa7@_Gk!(6nkALSn6m{YpMemhP8r3`*=D-OD zt(YA((9*{IiX89rpanSYC?u@a)PwSkoSxQIa`@ocG6!oIuo7Z{-NRj+VbXwmK7i(( zlq~Z@C=nC;U^+5Nia*Vis%5M*p$}pkt5p!2P6wi;C3$RA?Zyi2l~Q0w7cHm_Q>G3| ztmvIdKh7jYs+?CNETE`|JiZ{@f}r2cz^r~N&5>&|W@0 zbmNsXmFN)w)NSUsWXh7NRW-Q-L&cCsAE>0(CP6F?XqPZpfZz)SzA5D4hA)i^iv<0NNxug^$;H0J#ax$EvJFw7ghx9gV z3`HNqx*1{-rL3)af;MBpm*1|X?S^z+y`xx4TIaks=ZUH-eKl^Fz|*-wx_N!*okV|@ ziQCF6=Au)Rh_q|2$2X0^Jg=frUg+@2FD;mO>I*o_;(5H(tAbqc){l}_qhPcvuzp?- zG=T~u2Q;IZztoKdL9|p*Y#IW{l<~?lalljqJd}$z&du|dEBZkU_waraV8q|VH<1mCiqh9a%_3oj5ukZC zpcA1;)1(AZ;z*H{Mi9<$w(4(mA@T9Cala5x4{m}zCvrN7?{;f8WI;}4U03UctW$Se zOeZmD2Z`hq{|q@296w|03F$pKnbXQ7sUsu6ti>`}@#(;*Qua9$`M7<-ML~DhVt->f z43Fmx6HnZ>j1Mv7%c?Iv{qR!qWWNYr9quAW2F2*qMm+~9eWhO@}i5ABzQKsG{FY8 z$%nJWNBsWCz$Uf5?|Bde(kgVw0=yn9VMmdEmqFpV8XERI@5YCcHJ+`!0VaFh`!YurOohE1_w95Zgwe1_h)F_Q1UcZwHmGw;s^B=>1quEIc@XWwY+T`%d{0e)~EbrmKi^KdnL~%q4~Zpv9P>q z>qFNGyo5Xnt9MlJVR~=BC6h|*Lh}Q^lI5<;bk4%T!~ekhnA!5p_vMcH5e;T|Y!fJf z6V@`{%o$LiT6cvO4?HX%D5atUN9*8Z64ppmFd-eX%}IMT%kuRpw&fxDHQ5N8D|x#? zD)l)dn?1z4)vOQyAhKXsFma=a5X zncghQ8N*9BQDkV%Jt&~pCGnx|gD1PQzVwd6LBSKjVa%X2Vwhrc;dPX8leL*W#omQ; z72ZL_9?Jt6@K!l9%58RJaF+E-bVrXm>=8L@+rIX6TG0zbOc->XR^FPC$lPM^6D7O= z5F#E(X7MiZryl4wx+foUl~jJr2hj#D-b9WZsmz3@RA-be{V^y)fpIX+{)%D6P(i%E z6JbhT05oz}qwt<}#8O7I`(Hb;+$oACkZQ%1#dxM=lD@*4# zeL7xLmhF$NDI#>y<8_1E$kUwt+gKYNMgv209oJ`~(%^}6J;gXf=N z9pPveXMDEe8<+NH8}YvA8obHTuB`qp)t|Ndp4Y~4 zpAGWO!1hLO=3=%S&9z~_6V|$a%q!rdNQP#kB6g-%+pns^^**#{+D6WW(Qp=$@xwrr z%ww;I)?$5Ts+(edqg6Arey1D8jp`kD$jW+%?RM4LmCjx>VMN_=a%JrqIT0oHhs<=o z;(vaXQFZ(v?){d1wwKY)n_s+G-DIS=M^tAgA*sEJxRA_1I)qLq9W^6LzYR>H1PzZo1qaPz{Bkxc3icj)3E7cr_2Yp-&W{=B zD(Xc_Z**2O(;e8MIZhGfnOuiq0f{yQ_a$NHkn|*KBSEPfsKyG=yn$bt#^mdX?S`oH ze@bqRBIjx=HBUeeC9*2GW|)o;|}lQ-mX+8fpviM@gTjKp}eN4>|LlB*!X39+3dv-L_3M7wC@UjcWS8v_iY?x??O8ZxABs7P*t_LgQp1IPsJ!&OMtZi zqqfjYxzsfuJxwLeu+f@cHCB!uCGe2+-jA59FY7_PXdw!%b|8$N{C$em<(0HH8PCC= zd(J%-I43wFk;JqClSZ=yNRy(gq*{AqAcdzDuQ(LV3h_1;^pvQ9=M^Q@j#ZATsNm^# zuQ=;dL^YJ7M>sPpI4&-Z(sro6Dz|w{*0vLmax9yZ9y72b8uc0k4H7gpEYF9D5Y=My z-T+d0pzpKQ_ouXZ0FUS|6yjX8p`3l8g}_AQMQ4S!u3QtYT{?PZ&-@(ErMe9}ypv*a zUttllJXx!pW^GWLNq)T3jOSCPXlKQ=ifgJTWn`a3> z>N$2&Vf?an5p`zD$aadmafY(6r_Q^1FxR5XW#cIop_SpJtCKL-5UhD%GBbBQI8HDq z?mQRh%MDIGt1QBw?K6es(pX~_Xn9U!rlA7VZ7iK^s7kXJ(|?xEz+0P?B`d1IE^rBd zH8q$~+DAVHWwgn=FwtI3I~b&)HKMk80bnui$DoG0CT7>qMCI#Xx(l# zP}oKAnm(f@sYb0dA!VMfUqbM6OyBJ8Cyi2D%-4@3_loukbI$L2Eb62z1r~4O-bq!( z13YQEN;s2EP-eoJcw?D^vN$QqR=US?88MtF%eL5Qji?!R zK}>kE?JlZUJn6B}Ehx#PP%#Fk^Me(H+hUAz4;04?_fJSptSK znt5zo%IzV~yL$^dux9rbGGZy8!h>Giy#oY$3o#H+4Q0WMk^Amrmi7=A7KyWKoOc!~ zE4l+L23+}aWFkiLwu)9%trK{b2_Tf*p@@>Ghr5$uQ|Xj;&BjP_Vpu7;e0kJElDeb5 zVtEl|Notc6-N2DM^eRjfcb1x|HJmc@un|!41k@8aNXK|vuY;DLN9fbC5WzDgMbn#E z@rv$1p~X&ILc);}6g3a(RRs#_KeK?UT6MTRvCCmuwz7wVxNwmsw`ZF&in^c((u;a} zp2i2$TqVJhi8-3FG6@LocRSJzq|p~TEOO+*Kz)oIu&0%-AOptfm=M(NjP>q*vQxIn z);2d8$$D*L`cqU1PxX4V(@R`LRY2;8MvnBV9j#ifPXW$ zTx0F#BZI@lNY~9mk7ZA2kTC`xQ-d#T(ll&#baVxvo|1YZTlvG2;37W6`YeP(x49gG z_Xn1JSgWrOdJIczLX>A}C}w1HE3mi3LJMhIqS*kK{*{yfWvPm;gAA_w(njbuhNGvR95(Ff-iVK7+QCCe?V?y;Mx$!aE%(M~)(p-qZ#MG> zomoC1BP{7Ux5?)6#fLiCiDx!&k#W&aU!t`vdq7W}+y_IHy!wz)H)5f_W!Hi{wEi&B zevsQAcBals(SOR?Zm-{1>oCB(^1=md-EDE_j>dcc#F_*7Cg(Me?eX|_yOsUjuoAc?i_46GE*GVnCp$6lT~9SZ*NVSXef*hjZ!I41La*s`^U#sw zqx00~o+ab(eOGVLBntTe^Pb%5?O)c5PZPY@VRxJq2w|y8lezWW^<+tzF{@+Of%bRa z3#>v=f~WS_eiYM^DdHk4YKk8;9ilxbpS0LG!A2K_V%e>jH)EN<>HUxWpQgHkAQGI4B7ZSP*LMTPr!n5p+9smWCce_N+lq~l$0dn!A&+4i1L=}?*_Fi=gT6kx$g#v=TptqP z_1!#oc~lt=_jXST!;5Jyh|y+HTM_6*n7*Oxt)FVYqp*kXSm%7MFe{v0sd%3YDsrNC4{(|Q`W(Q0ztNT=jJUEMZuOyIQr z`vK>7-G@CLC#bbURhFm9g`vm~+K)XD81SFe^I3yFij4%9PmN6y2F^F#?V`*K$iM-h zJhTXwLx)~K*YIhlkOE8STkq*^aN2b@Cc77I0Y_33OXzfk*#y*5RqT2dfA!x_$N`q^Upx>ey`Ml*{!T#e18`q*!SHm={x8cqQ z8ofrl&5asq^vKa;rmUf^b&N$Zehb;DaS_bv&Y3_FBvK3<`M!0@?r_Z!H(b}DR-1-m zZSd7@qam)M-@aQPEtcLwmps0{Y6;vyj&4VV+3k3g>RBr+ukz#QQbVt4yoJ zn9CT+%?Ion`{(N}8+M!iz)Q$%hPrP^pd)UEX4f`+GuU450sEl04|e_4S-08fcCR*& z)vGqUP1+&E#<~x#+dR+=n`iy)HeYK4yxQM1T?rSD zvSVSX*JDkwAE?S9f8iAz&rRjfM%PM^hO@SfW3Gpt3!Jy0(6G@)8TJ@ajVia^y$zn$ zVSPj!vZAK*NYisB40w#P-9vW>#omqqDj+nQ=yXb-dBA&-AtQv&(}+GaAtnNd_jVRp z=&@hukjc4#CKBt_j9V0@9kx}krCSG{4S+VwC^BpHq~2{#Z6S8K!MhynJ@337~Q~z6?nr_XR z^_t1ot~AlcOUsV0k5A>pm+0f;PG+G%9W{h(-AtxWPi+}l{5He zGbY~{;nXM3Sv!~*WiXbSi2=*RaU8T|FhJ0FT)Q`JNzEaX`i|PU`H_mbH?GMY#`+FoqDfa8aKOjU zN6DkpSY%#Bz80?u7HPDHbT&haxK|~L6q*`AkYKV(EWo-wN=V8j`HKr;BR>gYcN1qFV7Iiz3{s}< zWPsHb{D~F|ybP6;C^zw=c7k_EDH6V87&IjXig5Bsha%XGb57Gg)*H%|{?A&DbBK^k zOj`$Y()^g5NCk~`=A>Q6s^UHc>CHg;30t;72`Mm|I3pGr67-_EF;imd0;bl5H^tviUZvsjhMzzgq$FiqW2Jz5WV77!9`ThhdSoG7G_yk3hTzG-9a;i)LMGR zZ55Jebp4a5hF)gguOyu#H0>opri4+I+w|laJ`9$|t7wUsD=7n(AZQroq@;DR(7N?} zSjeV5ygb5LLMkq3gau9k?iLk7A{U{Sov<=0bBV$;7({lm&auM8JM1t4 z^Hj0^VXh*O0>zgjt!yb>l_kC(<7mHx`QcNO2M)rng7PIi6hoUsijtb3C}dHsIr-M( zPJ=E|if&v8F9vo>3L1KTrsJ3gJPf9jdRM8b^o&|Bz`{(B>aj_BvF?Pp3s9CZ^&FHK z3mY-u^olU`u*y^=fTv2P<2>S6)>9nCXi*5?#gf)ll$*|4h19tO*nrf?Az`ZKCbLE| zVn+)r3kg>$e#`MY(HCrQXIPjFp2B4ntAnCa6Y8fJLAHw)e&YPQ-4{MO z55kGHpLG2`&eQsZTdecT_{PE`)|34-ts#Z2Yjrht-pZRFJ^wMBz@;Ghgd_O{iZ?;KtsHV=?u(f*oBDL_>MlUlvd^=bYkXRz~F`(rZ z?%VX8ETR}<5IL|7bpB&YU;gkS=;KUm!YdU?Q&MBn#nQa?Be({$A9>~%KCI5{sQEyB zat$Kx<X(Giff96R|-6eo&1ZBEutj!ZIZ`nj%<`b-kl%`oiKGoJ>d>e zS2a*R4U)Yz;d_AzI~v@K{l!hu{!M~*)VPUUDp}H0`9KvyNCfg=gB@Dgxv;KcDM0bm z@F}V-h>7Q*MH0nT+nln%VqpX5u#;T6c~en^yp$t}nmvf?L7FE8rRTQ4QTJ^)ZF`8| z{2uo=C+N0c>Z`hHb1hc`gdtf=P+Ag3FHQ|wil;nv4Cn9(M>F0U%*#E|Pl8~kGD2rf zK@#x}0S;}{mm1!0e)SLW$n>j!SpE1Hlc%K=6&+|Wr`y8AdspqW1zcf6Gqe=W*&a zmdg~hx@xxzcWdyywYqx0yxyojA>Z7>58L${_ur2I_bxk~6-)o8?e+05J`K&jivUMt z>gWd>BrjKcZeW9te=!Bw$KKp`KjQb@Z`D^39;p8I_cDB7u`|B(p%2N&zxb#yu+oUPcu?DM)r8SYZ%%!jK-J`b`2J6P+tLm2RrJ4YAETfP zEZctl#TV_%FaP9rrvBRc+t+XG$)0#({Iq-yh57$)x9w*uVED^p+WgLdF6!`Ur|?^_ zUAkPq?mcI?|G3T8S6KyhyS0F0d*mxK5`MUWv#2*_1hcQ;o9(SO-t|5`Z9I*|fA9yh zZ;XHN2Wf!haj*SP?OT_AX4THV@}Bopx4(^Vw(YNf-;%vC{ed5_e>HyZd#m5Py!VOh ztxKthcRh`FsN_lSoohrbw~yiFxOByZYIukGrr`PRjW=jUq-aZ{AD-&A@s@V%n5e%t zQ7>&pkfQ2(@HXyUVJg5K0hTl_TbI!`r&*3QTEk; zlX~s7Yx34(c+-0QOW69YODA8fUb~Ni@B~M7L-mR3jc=rWlnP1;CA;zxUfJZv&~2nj zfODJeq>BFt|*&>IyWNT@| zveSU*r=`K10`q;EAr@qW0$*CkGZFMz?O5;$bnY<^2thR(d#NYne8{1TH zX<&crpClU;b~f3Y-(+5uCz9fy*p_d7tM=J!`}M@~&LiVzRmq*;$?Mk-9kQ3lj~!z$ z-r&;k&x*n1Te;UQV_WAAX&tLiMcJ}vwzx{OfI-U))uYW!1oGO#tWSVbRKlGvMpUWS= z_H)n6YrnlP{Vm8~WqjKT3-KI!liQzA-zW%qYp#Sd^6_z$1w!h*| zKE-aN^0Q#44A!MINw8e}>Kc@#lF>!Ju8h?gSpnFhunOYSW@^%-NDYs4cX?G?(xvOt znnB~8_F>j7KuY6*HrP@)T|HR1DgNgjQ z@v*)HZE%5cSlY?JaU<38*Myg1oQ~KWu-`{!fr;L{IeWyG3 zzLrY++kYvvRw|8)A`A=YE?HWeL;sV)BU|OUFL#a>Ihy}Ye6kgr1HbfAq4OiZV~)fm zPd@pNOa0yzclhQQwfs_%0Si5h*3hDKB*>CS56eP1H%QtmT#eS}rQZe&6u8A8X#q4`Ph~gUVCM z4lE*X0q6`(?Yn@^dkahAYY-`#0BC>-OaShEUW0IWz$%92{=HCx@Qe}DfI8^1(-nOy@$ClDG8aj5a`lG`I zpN~7$xfN4ma4Djq7+!^BjilW!+veHdL=zY3aRt!srG>+&ByqyYx~i4vE!>2e^;DE< z%K!dC%1e2*;IpAOf`L@CFUionagN!5oFYf%P$Ckvk|CAP^DFYo;B>7v*(_u7q4?1L$v2pDHd<(or+wUW+>7H&>e4GP@~T{H@2m~{(GCcE>l zcePK`4;E68$G<|OINTia^xDk?jq!ddWdL&vp(X!XE|0ht?Td*d3yF)MY|A_@yabX& zmIR)@uboDY>kAo3v2sHET%NM^Nesx|fuIbG(H#nft0hxQC#*<{L64!z>8ua(lwD(w z*Ms2}3jGp>8?&MnBs-f{jheiJX{-QLDauHEeI*_*Qc}3Q3r{Us)rZUYCa4SPrmci? zE)-|i#A)dntSk&CVIN$Jrs0XeRR(HWT9`r_x1FM!k7X3_oX~Y2nn%U9w)(5d~hQ$sx3EHBjp)4vVwcbo)3K(ksnsVZURB9L0 z^{YZmM_)uQ1_n1| zCgp)ou+~jkQlc_=nckF;BI!xUMQbT37wlY= z?{PcFCD85Ct4lnqt(;Q{oo?uQ%B!U*M5QVC6l%aZ4Ix@*oPSNe zlS$t>GxBHL3eMP;c_fg4w_dr?)1*e22N9-)MW<5+*9jGVV#&!1LF*qTBbe2fS|{3U zbo|U|hD$PJ2=n?D$~(=Nzy@tSaUOewdegX3zT)P|Q6&0Q(P(*|Ed*za=jySUZM@*- zHh@oz=gHG3seRXuqZ+m%Car)0r3sd#@|J?-0wFqDYRscoJRW15k2Wx~(s0cU+)D7! z@^)kRoPh8bZj%WS=l6%x`MMUeUu&j-%V~H2fX9lpd$jb-Yr+NqKoym?LE^=m@m?m~a#js&egJ)a$XuB$$$J3A|4Vq~MmM zF`CYH)3$PV55t^~I%^l0n{&Zo`Sfy0ZQ@Yr7Vsmkv8gFdGl$7za`wqce}`~ewlWH> zz{$Ut-jI7)Vtryea5ErS{LD+^GPsm5r|1(nrm!Dea08Lns>Np3XKSM1vrL^1vukRX z85CSW#|L?or=S&vm`H!Z4EJzrxf7qct zYaIo(!L)If8$7IG>A@19AUYis1%Yn|Vrp$4Fkc<MlPfa`r1V-rFDJEeXI78i z880i6susKLc;yOO%4V0GtuBJwX||!geRk>i~fKUxtuxWqt7<`(u;ih+WE#A zETPYQ-`Q$(+**aHcx6zz;?uR^n&3RJZeHO@OM7PKdmE>XysCoYoiT*9_WH!LEs$@a z4$n)A1dPgX3%)#Sz!JM&WM(|e zrmHsPTaAJ^aczxqh1VXXX0ayv}uB-QY4B5r3_WDcZ2uS zeIC*>GP=&LLRj@^Z$OwP3Lj+;T&M*y%S=^ZUnef>J`I(DrncnF0;YrnYF(OWLuRMW zY0tS0U4Hi5O6X(6cZQLnx=bu?^{INt#my6&{h=;ND1H-VW!4WN%Ir!$Bhp`I=$ZDT zMyJp=T4k#h;U!O7IkkFc3rUTfV2zh0teu1k@9@yA73R5&p(Xcu`O)W4Ifm71ui}>v5$J&RmyRYg*gAZ` z^#+S^`k~L|D5~-%8!|BB%#+yO;-V*vwLxaX7*=f5G3*`hPRt}W$uyhLJ7!l#=O&#< zqlQ@bZ5OlED6!3HP^V-@&V8%io1>Gv@n{x@ce+6sn7i0@##E$-Lt^jTmxuke@x669 zZ1Pt7DxXLR#~X)Qas3h>HnjC-|H#I^b~dyBA8T(PBiV5rct&QuF1{}HdR{e~M3W}Y zS;Z3FBnH^x3~h~e2{5asX58e`=O#s-Wx+lcsS%eFWLt($D+7x?Wz{riYq-31k)jC7 z&>zh)Wze(6N`?*CFb}7i8A2czbEZy!0pkG4T&=MOcy-j+G$lhO)%S~duc~{7L#^*_ zqr37&Mn*e`I{OY~DFxza&$YUfYCsRTv zia=G-V+lRUn6t59yH?Nh->z{Eb;$EF*vomg%#GUSGufBA#SPgLSvOAa4XK+j)4}ZC zJls0n0WI!iI_?g%T{@%A7gNaUF8k0*-OG-r_?@iu^>s*=vKYfF630(B#+_$k_vEnF zS-SI1JfC&w6UFu+xx45N%0BG7YyL>L8M>P@pU#J_%U8I66|(cvYSkWIowQtgm0^7J z+Vr`TcEOpxAw%ku>amuiA$`CA1*0NK|B2X0#l%cCw8hl*@Y(<5;KQfz9|S`TfeKk} z5Z&52T?z_zmTS5qaQ==ZX}>XH&9y1Tb)gt!k-VLq?0oI1!+HO?XRs0 zEuKqhJ_IT?KEhtz=JOhbg z4A6-=G9D9=89#-ffy$^#r!b;nS`Q4lrW_iHFo_Dw0~I`73utqDK3jz=LJjC}gozN< z1dl%EvxeubE}&l_=VyARC+s$jS6MWNwhQ}v579O*mUm!@q@{^UCL2MT8PyeWB~|I? zB=Jt#ohv^12saLsYP1iHk1%SWvXW<}XUwiZ>L+=&3n@-R;6k{>Y!lmU9%ngopQNfs zrnw7uh`cOWTbyNrzy zosJFCGnwX%p}bEeDadn7!YGFQ){AA7uahZpGVimO`()#>?K4yAcRydNMFwmODV2b<0Ue3qd~5OHormrlq0Q9SaWlJA`0Phag-XBY^ubt+U2C@y@9r3 z0J@qyd8>rtULkj8CvaMiIAeL$swH;Y5j{ep-T0Z`trHA?&X2sKgPjhr6};EVIMw-@ zSAMZ=wx}jD)Iuw2I6fm1A`#>*V8N)A=y=C3D{bmy9%KSBNKEWYQ7cg1h<-o#+piEI&v`x7C3TGm+avu8$*RPD4aVA3GAOE(ni|gnuoxGSBKXi% zDvTZK5!ALJAU+14j6 z48x2UJaq^qm(4nBxgVxc9Hux7iB}r9!4=pdJn8zA^{hE!Kj6k;%v-z@nY=v4T-k(^ zh~-udUuaAl;wHjCEO0;&Vx(+tJBkk*3?zyzd~G`gx;BwJx?4YgayBE=m{5P7#K zR!}+k=BsUv`Q6g9PLU)Yv=s(1v>A}7DJ7QR<_J4u5iPldoarEmFnzHbVKnrJp)A(E!%hx)(IP2+WPA#92 z$poEpdSeNtrYea^vnC0IVisV@;h@DGMzU*m`>LWfxf)>0uvhnYbL6w6S@#-Wt7RFI zxT7YN4zxd?s<;RHR48kpNsP6tgVFIdOeM8FEXwG!{>?O@U=xU81YvGU@I?b&hR!+D z9Jy+$HHFq9DqFCqVkKyTk)o(KTOctN#9-)E0;_XjP1IKAQZv0PLm$v4*DW=lk1JL2 zupce!aYT5=&1o8(3Q0OC7$!EQ>y&pTsJ$6Jx@s`(g637>8K0b1Rz78x|5NN*7%1r-j=^$8_<&Ira%Vzhq{t%S;1@S8qC3HQz{m4F!t7-~V0e~nm> z6f04wN>xJAU=PwYHX%l3MTR`^N?Mi}hl5^a(as^S-M1}MYc()_|o zC98(MQge^;URWw~w>3*rradKNHxTy{_qBa#p*>@0j-9kWEkY+5@}q#O z0wUj)w5P;8OOn|fz3dpQ6p?KZ;9{OkTB1+v31%_3)S%4!3sXE$0UUcX>1IRY(jd`E zw2^{FfEw9~J9QAIQn#3tYyrp6(b#@at_|Hzltp^o%U8CBq)G-kCo(&aTuhUz*LI!I z92!C(BU|SZ;zA9uxn;&x;@o(Svx1Bz0S*<;%80B!Se2tr#*EacRVs8Gu!gb7$_SG7 zv&aun`82Pxngtcph=FHc5eO8Lg)jkuL$J7$3m1IZRMBLmS*1ZaffV99*v*djweyg%SVxR@(-hq%7_}V+T({hJe5c1%>&VrAZiZ-e z=_W;A8B!GOd(kJ3zzvaPJ^z%zbrT3#dNGsRBG^`5tm+X<)CKk!xs5ZBw#fa=Nt~HB z*bXM`ZLvouW{W0EBkA4aJlo+kCb}6VsW(<~CwD4+f-cpTY$ro%=0nP2CvA|%j6qM1 z+cDlop?v$~cYD2JX=9nampt4G$FsZJoWVsO*`GxjKM@8StZ-Pf&JtY{Sd8__Q{`)wI6{Rr!9(uqS;# z{)mfPJD7-zG0vZfTf71o8@#}aILYtf9X@~0u`F(7z58Xr9heE9d)+*d`Dd4IY;4|x z{N5CwP;qP0lHo^Ixvjf={QeMnAM1B|(pa4gR<{b*$hlv7ydC1{wd`XZ8Px~%o!H>& zY0pK!`mn6V$8HnX+G*zUG)^=UE$MyVrMghpd{x^o%Ww3XoBi?K$LhtP&*nY`o&;Wf zxN`%w7QI;q(~!BCeiHNg22*?C*!9)DunA1D&7&z?s18gB0gp2@sn(d-TJ-ldx!wCyOeM9_gqFD2kwc8U?QQdHBxMFNV1R;2j+ zC$@$e5z4Xj2%B_vU@ReN#n6`X)bGSZ)J@2I9_6SKA=X7UQ4k$uNI61YC2>dSnVr0Q3O3G3f+!wTd*um<@;g)Gac zZ(vqnX6z+y9;|c!I$O$Oz9iD(LaJ|JDHldbyW|%0dkVf0x9-Do8J$9?@oG5hcoNo~ zswejX3vWZlbeM+k$vC*i)K8LIy8gcS*mhWBioKgjSJv+Co5zLN#QtH^n(tU9t$-zH zln(b)rQ=a3ju}?R5}kA1haIe$vF8*Z_rtdLtGK`75ulP|j%SpVBt@a$`HT=K z4?z#Er*Uk@ghk^a&jm^3DOO1UP+t$q`=SdJ1XF(k8E}#YV}}(reM&P}a(pZrX%i+8 z*D1-$MQ*P(*S6Asr{WZLwg{qP`=GuL7YSNlJ%{vJqJfl~9wJM6(wP;mPu-V_Lvs5z z{**#itWG9wvC^6z!oG1 z0lc`-XB>kjk$wk)?Wm;Rg@hy}^C1c7MRIaR0(rRy=SlHixzUjWo4J8X<9syftp_@r{+Pdq?j)-%XtE}4l+x@4H(MmM+qiSr3nIt7D~`_mr002yqtk}9 z#(ixVUl17|3S7+z!VSq7Ho7l#Q(JcWDF)w7To(Tj7S=rw(sB}iO|O5Aj7SD$Y;KzN*?%2$Tyr}xmOsfFg)-Y)Z@HuHHB2dx-|(dw+=v6qNTsifZ5kiX_0 z*I`wHX+u(zc}m+R@gr}p#v6%idpott^UWC#{b3W_f++`;gDb%TA9jM!2BjMoDh z_cikg&+wf@1AM-%^EoDW9hRe#9jhK)W$mWCndlRAx59N%dPV0ntiE$y$eH1qoTyyO zR6VLSlM7s5#p~PiVP(X6_&mlAy19uxZZTx?i&+*%lS#2Doi$lX2+t*qNRSnL%2_9% z7)Lu~^t_l{nzT2QaC3+z6t%5-RxpX6fibflqEZ)tC_Pb8Z5e5K(1YVtT~`L23Tm=K z)c=g>XEi245Sg^PdZY+l4kOvQ!Q_qTB{8M~xXMeCuWp+E^zxEKM2f_RF|4@!_l%NjV=m|R^EyXlxFIc z_bxmMb0|&Xqm*1mRx2uKmY`N+c&*UAh?P^RCIY3VWxa_;r72XD%GxEZ3@gd8j0HQ) zOEY<8gNiGYNZ(6cka!M?1cf}wM2|6(Z9N*63=yWoIVAQkgVHi{61r#EEWlG%qNGQ< z5$ZEN%z;!ZEP(7$C1^Sct~+Ne1u31yspQPa<02H55G3)Z!1$z)Jc4FHjixsPA!?jo z$1p8ngMFA13E6mRra44sSgPXdmE^cW9(JfYMirc9*KA&c#81PVpW-@Gmr!ymu2@p! zO0dHB_%zw=*XVNoaC!6}8rx^!d6qOsq9PT;KEAA~>YS}Q8b`8--YhE{;BuZYkM5H; zC$UCYcP|Z6HXv!SO3(DD+0x}Iv2#?=o|oWB8d-3Zkutop$N)KMQrwnIlA#bVI{#4< z6yic;(kPw(UEorzn6#bI(MpPYG7t|3vXX`dEqIhox6EaQeVJfk^i`|JiU@0cVG*V2 z!XvdZ6|A_Kl_i+T$r?*KH|PNk#&kQXI8P{(t1xlYrYb|d`ccLpq^c=2tAzOo+pnl< zPg)gdbwZ_-66X+01U+?cLKr~u6ba`s&c`*iNLsj_wE#(_8)j)`A^P=S9kV(=lH)RE zG!v;6P30++?NJXUZY4rXr55y?QXdO7CkZ8w9v8yO$lT&p?A__6+`iQRMrc$y7Ay`* zDLYT4vZW+t3Kgs2xlHu9mybG@gv+S=IW*Z8bIcD^-62|}GDskjDhuiXyb*0ZBt`e4 zz)SvhByEhzgY38*bYi#e(%owMZy80vRg?TQW_HSuu_*Jrs?T zGc61aGzA(Ek^X|${E37TIQ@1(Q3_8S%+%Nsh->9hag@mPn1LWM1&x$BG>bCdc#Kjy5 zs`*B#fI2vZ$*s7m1zktk0pm+$vj)mmrSwdugrc;Ps-ksB6}3F<4=Gh|6;xm+hl(#0 zo2UGLJ;rxuyb9^vOz%M{^P19dYzD319?Uy}Qc|v7@%BTUcND*~pL|t3)5cSni;QAL zao7)YMfPa>DODTvg)^*JvLtQHId@6p@`j2oIqpgG#J!`n>|WHcxq4TS=h3;=^SB-7 zsm^ zLt=C7=EuuqRwm&6;Q;G?Pzllgln0Avya=b*W|X99dcH6634TNj_q4~Lnnw7vubi+n z6=Sfli^g)86?~}lxhz#BJ1wouTpBi3@$#rz%`xRHagY*B!aO3uR9-~ijldq?P5o~} zaq8Ehbg9J^clClsG=YhzQ!1R3X)r7cvl)XxAG9rfv#EnN;d(-uo|e6L-}_~cuLoSU z5sd%&Jh14~k3LR<2L4y)!P7qi`@>tA+`k?@i%9&@*q-~gtMRErHQuGPASKjIi79<9 znbxEhq*5n-xL_kx_h|6xlt?(^$FnY_0J?{Fv-mVy)@a#C(8*Lk?5+0W0qLnZN_MgI z(zcD$3&s9V_19+DJ%*`EH}&B*q)>9L}Oa6c~Uy?Tl@LjrCdTzs+)g{~teYSMVR(XuV7ZCE^+Btytpi76v z%h?QzB=h!TL2)fMxa+R`-`!l%eo-A3H7@;NMQ~HJvm+n+(8Wvn;RBlbAbZBy>*l>` zf=@Wy()l;uAWD&?A13pRc12(=n2h$=*|R)^qOCv`%mGs6!%5G#-ZYwdzVf?oXtT+d zZg>$d1B+J7#$xiW=K5)mhS#Sm$52Zf76tB>E+J3tr$84dcgGeZ0k={3iQ2&}TmDNc z_-6Z#I%xZ=nI&J^m9v-d7-e4CzO#e&U*4&`hQ}zg#?qJbin;D*TPy#*@zP7GB;rf2Puiu-J5=e6O`Uv|9@Mml z;m?e`ufB>0ud}-^y^jjK`KEvAC3QG<0C`{jGJf$c?*7f2e&^EeJEXq$8fEMrfY#U% zc~I`kcmGb7WOv8iCx3Nz_bvar+ui-rm#k|L+VzxqA%DA@Sb?|tb@jk6C{-3obM_yR8C4m{}F^3twlfu`QC)GgcYYdA$T zOeWt{+U{KqPWcP4+MB-e!`A)`81@(W$)B8Kd#N@0=1fKH?xlkL`8U5wPkHUL^jf-x zN?rte^6ccn67UnpvC#;$56qw4&2OhbO0#ZS<+bW#f1ZK;lajAY#lzn2mzZdF4{KgC zI_}5R`(mzM0rMZc!noeWi5cz!AJPQL_{(MnmX+M{auqis7-}-P-Wt zMbwqrKDTl2)$XcXmon5dp4MYu1s_wP4d*Hr3b)jsXv!O}*J}Q{*!?vA+L++}q+3Zh z`a)p{zb@13-P>*u@FtKfOy{o9*IaucSRn2Y8TgW8by= zzL&U+eHQ})ua$oH5)Mbd^{uzx#;2y`r3!DnesNd6-G1{;nVn^g`|aPuU)#lxzgJ7> z+QvVi_ugcZ?7p25Y!9C&$N57#J?Fv;fpo%P=m#b8)$fuXrC)Hh-q)E9v`myn& zI9g?2`sk-Gu!ZCn(7txn!3~iq=ux zlezibHf1AEsVdje_0uKXsm0JLoBMv6t}t5Y1g0+;lEOb{$H`vBQJ%yeZ^Ytb0*gt! z7YBjAa)K_!CbrIgb9{X1k+~nXO#QIw9<=hqruhv_a~?XpmQF}dB(Fcd{rU-ijpq0t zHTYWg3Co5&+xwRJisz=3?Rb6Gx(K(isll|kAraDNtZuY8$=n(~al+q{o%oo)W$ncO zw0cYSm!C2VOm!oXPmq$d`Z*%>_#NU^ytZ zGQ(ts$#l-Q_VoqdH1bkYhpvtLqz{Z8n0xAXdc%KX*v~xC+t_X?t^SSP2TmJy;)x3z zhSjo@|E!{|o%v@a&Hd)rj+Hc0DV3t_w7$Zos>u~Jk$-t}Dfy=J^Hg$GeE0{eYWc#v zmQqi9sc!E7?X_My9ne&=Q}Y}LPq`qbv;5|qcFn)7YVMAY=Cu0x_bnyk>y0BGH&lvV zU|Ck0Jo!4q#Di7Eg9ul*@8YBy)T$G=o1gWX!^Ny$_*>p$zyUlm=ymD8>hqjRkP_wE8Evc z=k)0SX#Z<+VWyh$^tjxd9HqIqUjq}N!Cd>L+1#&SHX3#&mSe5`so}(Gd3{?rYczT2 zT*@oz?gOc%l4su59f(pC?K_H+Vt??iH?5N&s^U zOqb|N^3EZpYL3X!F!%;lY9C6eGf%LTsVG{}d?c-`W#_p$t%qUC9OveIZjCHPt6smQ zG`DsLrxvBAXBaIm!mUu|9oixcpJcR=4~mUx{4({GdxZyFyF~dxi-h?3DKS&1GtdJ#r0h}B>Kq?y}lQ+ra?y|l!Zi7S_s?J>3 zmjnhNIz?#u?u#m=ps7)5TVtjr#nxpT&LL^JJhA39FAnvHTB=0kD8?<9C%}fJZahqM z4oq)XLO@h;J6{CyW3(z^D%mK?j?27CQmFRXCTz7mbW6qL6Ji7?{}yWBc#lOFkH`hctgn#2s6 z-bMpu`Rr{UC?`rrFDZi4y77xJDR3{gzQDHf+%Q@jfCrq5)%mGH3T@?jpy zR%ASTJJp$(^MK4fw{4A^XSWomv=Uyn!wuUs216r{H}s(yP(=ZHlmhI!)jyy3C0D5~cSAv~2==v1+O`!vY_D9JuYIf^#`ckp9OlqbH zqAD@XhiUG&dnLEh(|jOSB#kNr3-lCQ<^58y zY5g`2E#Kl(8_E56Lrz!bVQuV!8r(qhydp={0v?k?d;JN$u`jE!tretbAGv$Y=@QLK zWtbM?4Xb`j_*$_HvGZ1kC!ocjsjtcj(Wy~SAcx$2Y9xyX=?X3h4*v5W~$Bjn~5Gddmh`Oqa?0Xf3<W6QE_`H=*zXrmPZnrTAnNBIqujD0yA z-H?us9a?rf%0VqjhWy;JTMjikMO@)4jH1|pI^GagSELo&dD#gjEKMQy0~zQ$$rMG9 zjy;u>K`y8~rV)lwv|dJM3nb`_6{tBxmK*FH$e|i_gKW+?!s0P0M@`9MU$=I;rJ2=a z0BQ6vc?-4Ww1}xz)Pm3Z1FZ`)@Kd}J?eNVpJiRP;esR0EUBjdQ zi?ty-r_^GA48L|tW>Nfyhy854T^mVpyPP|f%PD;$!7b}3OUWMoT@E5-lk}uNno(C7 z^I$&nYbL=8lrx96@!~9XZscg`K23 z?zjnGWb%7AAL&^5QrK?TWJmgWOE}r5$WG?7<88*#|{l4vCC3C~vCuKqbxOd@rpW0`oBr2W$DE z>5z z8FoEL9HH3t{~?UynuLuQaV0ktoVjtGg2FK;-3g2L{r%5m5;IBkXPI3;EKV_yc0Snr z={xdIu4e7E{yAk28WbCYt(RxroSMH%IIuc!mUC_$^@SNWO{v4qaHG$L?y#g@s%4>u<|02G$Knhkn5t24xBzu-b zp>6}o&@yn^(HB6n;S5xx2c3lh9vl?U=3V#iB?q?4f)@NL!@|BcR9u)5or#3utITRl zG{6N7Y5_&EL|}O@kO7Yq=W};XT3&5KXF)?lROJfJRki5SLjjX5tkgiI1>K<1X11Z^ zoB81bQOBvonLDI1+hn{PnzVjI9_k#O#Hh(B40#{#Xp|MI;y0KB!DP6CbI)4)^4v9z z&NN_2NLqfLC0UjZ7OJBKy~{b5WR;5Lr*+a;!)*9!^|D5%Ye~$9k@W%*NS@(UPOCPR z$V3y8!0Jo!T7*H2dKhWaNh7EwTRlon7Ujk)Nk9!9n^KjL`7wXYK7Vnv}?aj%4Jkfi6~3UjwSPqUWf_e_D9Jc zlopaDM~xXzp3;z^=%}x$t%XEdE>WlsdGFaLDfADm5q(df0D2NSxiA>si_$q;T<1b` z*~U%!;&l)`AE>#fry(Duz^a8IQO`z?A~$U!!MkS5wMTeN=x_@;>JrHG#tzIhL`jFB z%3j*P?1}^Dk=jxO8KeckZ39{fR*KglUPPkoOH;r!M2i~hVF|wPgJ7aN?qCGf+-&8D z3Pjh^{B-k8CWxubN_Gm5TIGpG&!bw@(~%(O!6kL+Y#b?=NeI?LR?@6!D=)E`9td<` zBwZwohhFbhBG94I*i`EPQ_#gF2~C-@R9ib$g~i-u8&HdY@Zf&Roi8Zke{C^i7>H0{NG>h0<8edv%?xS!$+9 z?~S73w2Kv!X~)a)DT!yf#oH~}=mf-50yW*mNQ4q0mB1Ba_-Nm;bV3%C7$rkVQK6Wb zMwo`kRUOs{kFdy6YKEa`dJ4-e(UF!w85yI8vq0{&W!akUMvEFJG{_*kreb)i9~1=_ z5L5vvQA$jPg)%-@8a__Fz5YjR8#G^hj!cn1HW`tDEM#>=fT&}ol}N}5V2)~W1uH4t zGK8HBdOuL7U8&QIM}qE1c_oCGI0J$L3v8Hj_xH3eBe@G?&%6E{=LJl|+8x5vfw3S~ z28r(pVUc3R@5LyEe_+aww3T}`k~Am*S^|q2i-hKz22xT&o!%gHiFZR*kxJnf@mF%u zhDxiI3HvzrGy2FJ66O@uplstxrFjBGrj832B#^+Rhy@+7kQ6SI2ST-X35G;)*u2f3 zv{;q4I0Uw$npV{btg1?N(9A)i{b|vJ+T2y+tXeiq;K4 zU2zC3nz6nxS}RMa;|8HNgccwWkF+<6M;HGXAi@%0e(7 zIbvm+;J|{EVB-jZ`(Sl}CrKq9Dx-!)(w+v8(jHl{4jy${ZcW<5D)zH2m}kOBN2AE`H;^S%M0k{~w0$tFESZcNHMPriAfen9K$mA0NR`Z3rCRT?+LfX!@;teU zYX7dlhea>2^5*nvLEWc6Dbcb;<>_i*(NdI#th)+P5`R{Qk*X3j&~$X2Y9SfFIgAwv zYOLhSgjIHC3MO%m=*ojxwB;D$e2#`=(uhI8SXN&PEIS=&Q6I|4LuBGCx#!{OIihRK z0yayGIW~gn?+S2wE*p$kZ0iA~bVaNH6&3}Tsq>e7=Nxsb1~ZISY5`U?Vo{M&!km=U zFy88>1<%DpoTHUxD$7PBm=QP{%mr0ZA1g$&hYBwbG3?73sJ`|;U@ut2ECc()EMq4T z*z3=X$;ej(v5c!4!O%QzW^?Y!d4)y?mZ(_0jcvS}7I<5dV8f`#oEBJw)uXW0j;=cx z88(n14@Hd?=NfQ|{Vd+k_Uf34OPE{d5T@&tD!cfgrQuA*>!VJ zABhnenWTo^LUPZ@QqsyP=$>PeJRAE+D`ZKpe7j~GH;S?MYclQkoQwCV;dc^y>iFSE zB?4E{BAK@yVe`#^NRhHRYgv+|xW2V{EW4lEqz_=`Mz+=Oo!H8XttGwN!`j-Q-q)Upzgs(?ciun3c~H<@1uqa~H*PSIQ`>-I6y}dH)f3Izx$s2xa(@u>&DHJe zC-U&Rzwh(_dr`N|e5p~?AMri-Z;hK9q3->LdWC3kp;GvAjr4t94E>2GHgQY0_I$kv z!((m`pUrmUW8wb0Q*q}0{?Zgl_3dFuT;WC`vZHy?Z@0&-)j-;+Ut1oE!!M6L#emj6 zjdomqhUR2&uTueCxSi`s+M;43cXX~M2>IWCE`Nu0F^D9;-DVcdWXyRzS=B@|Z?gUs1;AI49>k}>$iRvg z)0`ljJ3Dy{DhDaftfGoRQWDZQb_N|>$VVl~NlVKIQx)v%8D$z#*^FQqp7iGj~ zf=Ss2dsD&={Cs|%EeWCw2?35MTZmfz*YC~U$X$?`(V<73o@LT;2k1d=-~y?7HN zoi-^Y@@o~L&4FGYu&t8n^2picXEQf^ypS`wKQ6;zh_SJgZSf*p-i~Rx!+u@2%Ez~| zQ)CVJdQnkad)_V{A9kKiLmZVQ;#*X7t8-$+4OG|my|`7Er+T_kOItCMQDgKdPS5n} zRKD4XfpfKJOG@YAV%U>OzjaI`JS@GT&su9RME$}@Rtw?|xGY#G_z-W!WzTZ9_Wm9JJhpxw>xDCT>dDr9YkeaR z^y$ayTZIdJ9VR|M=*gCRO!Vs$0b3NV(^;F!QYUTk&;s7DPCT2%)`kQbOL0q{J*X$x z^-ULsa%*UQsqL4z`YYKqO4xcKbnfpIVZFD$b7R?d0qrFVG=w}LS<=1ThA_Dv6DK!D zGJ2PBbvCR~v}1dn1qlTX(<0;eSpNQXPPMiW93>8D4ong{6I9_wW0VdAdeTsk#zcz} zP6qt(oGHBdAd-$efU6R&5pN0N!KGd}B?7D$Don8*NlB3q@6j9g2%z_QN{PZK$FPA$ z3(kKekU7iqAv4()JOPVcuS~u{?kta*L-X+ahX8CFsvtG+6c7qRUE&!0$V8%-R)dLJ z+B&HKfq6=#9Tm%1oS5;5D{F&o&kVznu&Uz?L19CW;aC(MkMQV~aHb}(!0Xiqu~i#l zP4IQfHO1iFrjOpiowwj;)~65l!luu)`ecI9RK?n=V2rxL<@a68KgY^_PCVH&cq)dk!w@%dAog zU8x@i-iHn`6!87+b}j37eAc-+Q?f8Laf9mV!k+%sZu@R8+~3}uw5fD|v)Avn^KN(m z^_-o4hb5hlH~S%SkSj9VA)>%ryOWItaL+L;hA1Nog%y(%SnoQK5bh6bgugTPf;rY0% z(X6q}#I;tWb_l*xWQk}--*sy6DD5Tm&^yuO;ZL}2ALs$Z5&_+10Cg!a38)#v3rTfT z@S$yUk7Cko8I8+M-fXVC+h>%^=p3{w(p{I7wBtKIdP{O5J&|CzkIFotCWdGPs3epT z(^ChVNaW`j@0@vaD8Y`K;K>E*mm-9oCXHIUK#2r?k?({@!~FwTkEsK4(a{kaIR|Nl zqcl0C;`<9Pf|#Z#aAb=jS~zbiz?P^Ech<%_3t}Yhyh3uM=&dF_o1Jt!_8vC1@Or$ z`Mplkbp>0gtSKu6{o-h`#?3BQqi7}{wu-4ZvLV-P=cA)}c8HA-SHYOCwFWVl8@sQd zeCn=+C$>0gM+G`gF}}UI)8a|S=Cw}UkhRvo$L?STEMt zkQI-MY)j|EY9DH~5sQ`eVkxobFK)tH+Rk3n{`k4##;u)fymoCf?W{JNYw9VEj@Qh$lD5~jc8Hzi zvaw4WH_@%f_sOVR+qqqqQtD=H?dmtKE*0*1FR4?kjb&|HB&^cGg4r0GWjS9|Ovt#7 zk2L2mtV6mE53q$_D}3VaF}okMOn973vb}!oM)rh^WE2B@5_aeW^by73n3?^VvXEC; z2a%A|q5(SnDqE$e1^5HJfS!QJ2t#N@R}ilD+wdsTwzQRqSOZpb<)vTqdPy(1_+cc~ znivBzCqU~>Qn`z-j#u<#E@k?)RkE{3Hi_L7R8Z95y&+jr8NN3cDPb>FHBg}cu%alY zOX)V4Dz9#N_qeO-M07S)qD0+=8D!OQUS$?Eau1BEvgZ)zh|F`$}dO3?k@^Au=7!c_xu* zQY#SCoTSI_q=gzZgNDYUh=S>aO!~}Tc@&&95jqexIL8k%c?tQ4=wkp;Xh#h-wVbTW z7>h3*l*(vhIcY(4dv|mf73cG6RY5T5#xeK^rogC(hFHMtr6m(EC8AmfRF4w)X%gv? zIFh5Fs8!99WR1wSq6~qy7EzL`USy?0fyy)3u0R1+Pp0^waWimIRzJda-exUZ5|XZVLw;~ryJpbIQ6NQ&voB`GFC3|m%_8Ao?z z(8>{~*dAC)Nl}f#bZh|o*6T>Lq{dN7;xxX1xiKtPxQeOKg0!fzJ%fF(^#iDt+0r&j zvdKOu$+V;eTer28js^T20WZ4!r)8u<)!eT zZA9NsI@c+X*;NJkRBsxsre#Hy&NWYf_#o`lj*{mUrlmest=b>)pp6oi8pjXhZ3~Q!t=_M@4~qXqw1TO|HihVs&V+I0SG~ z2PLW60h1?IgubS8-lSooV?{89sDanO?R7VeT3fo(@(IhcIfzgv7%FqY@;K!QIYN_U z(&J1pi}yrxx zG)q}!B~c#xpz=V7ttyD~a?SiqAX-CH1x#*LE+jeVIz)iyJ)=Vr-R|?R`TD2Hp_%f) zd}6s%UYbwGA;wINsM>J8sZaHiv4P8Wjs}Tq(m;kKS12TEc|Nc&l-Sn8w zStTFQciEkG-OI-J>*kzf0%Cl@N6@m$F;-P~i&0+;^06`+%nef&qH0BCkOop>se*g_k(lmAoc&oA z4R~TVnNg_ixT?9*5kjEM2JU?lDr|8;eykWv8sT1fI>zY#J5|!$T2<6F7^SY{#-_0% z^U(|+M0x|_N1*Dwv!;`J#jpWA@qC_UtVmpFQ7A<@QcImR?;dca$^hX^6nk{h(kyQ& zWnao38uw5;%Obj0&3W2RRl+>}|K{j-_H%2iUlpbmm3hUcqB2k_Z}SkSBdfUsDz;{c zXT_8y@pj4_j4%&K;1(6x2#RI+SgXFS*OOv2cV@gLTjj(T*IWXA&Qx~%Sv(o2OSf%x z>9+lcw;BsRuShi(4ff>id1*5&sgpIz(89qqYS{8#4rs}ZYoklQ?2j+~%`f`{j~hl% zU;4_e5rzEB&4Y+`elM`R7SK|d!3+hne$Ez8Z&o-_BdZ#PJV#Yk10Fb6A8sf&y&)Co zS24RO&*pOvKXF+Cbwz!y;cm@>Z>S@TZ{Y9Z(GpYVZvDA)jGU-xqD+1uGL}>ry4x~Q2+mI#OjwAk`HkST(|ASY+@P>C7&uxbf`0wl-eh@crjfZgGR(rGY zr__^wa|{)C{n`gZ<`ZuB!QBJufs77x$s9=G z@J-!I&4YQ=yi&dT>H)gmr9arsFUps{-1t;Fd{N{#WT~;TyZa74(?0T%#@T0Sv~%@ikoFy-q)R`^C@h%IjY-KUnX_!PpCL{1tw>cHc1z zTX*rhKm7cI^2S#z?@#?i{(~p+tF>^72!;vHp2ctC;lr=JW;x`wC%*rEu(RsZ%=)VL z`QQJ&2{7Mm@)PpTFTK6%|LO;FyQil)__&dl=gq(NpW2l{LndGSYU7=Ee*DMrGG+n> zgU0T~1KOzS@a>z{yn_KHe*;(^0#E3m7`fgiKNRWj?U;G3<&EXt^V`$ent zivnh<(IMV`5yyep<(JG6nF+utqV=QQ96xNkOB89P?fymn75VEo8U0Q5_N4>w?9cp6 z{>{le5-z?? zH@k%O7@$9Qfboj^w%x-oy@U-8{AP~ZzQc{P|NihFfE`$oUt-|l*X`%D$C?i}d~{Yr z(8i$+!7D}|gKT$)b>+v{T;;p3SVKMdKd52x&4@!f7P9-!G~~6-Kg$1)Z$JBS`SbsU z;MK1Y{O)gE&GwhmiZaT&bc3WOx9YfMm$=4cs5s`uCbB&F66dk$q`el)Q&6NQ!W0hjVOJ zSrn3>Bt3z|97ReKRjY}Gs!PVIhc%QP=1pepuSozjWH00`kjpDr@?K8Uvq!T+nWqd@ zvw0`7YgO9VdKZ>+_G9Bmvw!}V>_*@CB%4llp8tKh{bXNSZBBJJx;7lDN~RaZ>h)kE z#Yv{}tt6vKzFOlefQU_;jp;YOWWDSK^oV@Ar$5>LMI?AP1Qo6j!)ezs%!Sk{v0gZ> znAgjVr$b4b^Bru*`Kb_hww8lsJ$J0k;nu!)?2gkdEaHy;C+=~X-uKEp^^U)xSCu(N zoI{k7&wOg*w6>JHquu+X(*X>BZ4cMVax?x=8cMIo4wXWLo*jibxXWGf@35!{#~c)gMcp!g6Jf8O>t# zwX4D<7S<@ErSkGku%KcIg3)|_Oyd;{%T`EofmEe&J~+4O$zJ6@@6O~(k7wNe{FhbV zNOIrJ6D#9j`xg$LR?MAv`qzHycb#JO@n6?U`(;mPA5z*E&mXJW^5y?j`Gl)w7e|T!D^}6Q;8~7{cn|gnyab@ebs0VVRKqfv1zGJdsL~P zj4GNQE(6W6SEKTQY^6O%&C9%98c+41=WSIq%V8u9V2>R1SFK%fZqs;oW3AG8x=1B= zzsiwtIH09*;W+dSJIUR9iO}5IFL=3L(`4hRCu$}|!i|xuy%AbF3&%>@`4t{H)Vz2Y z)TejB{6=q#&lHs$ijX`&Bv5JrEA2s5 zK$iIFQ44SjwzPjUuPMHabFxuV;F9cmT%P%Q#BKG5|3wE( zAtVjw=M+>^qlIq`B%WIJZJzDhZm*x>Np|v%qb8QYw6C~AvfJjFVtz{xGCqL;0B%c# z37>?HEO~&@$^t}qRNFBMI~hxrC2flj%B2r=#0~>720ft(RErzqyzs(e?vJOekZwOT z+}MAZw*3u5agEWKm|3&8C4GAu1Dfb=su*bf8v8 z3uD=Q%1tsS#M~AhEo9W%0H<7Me2A~(29Q=xNNE$*Ze5yEl48bOBJT>dr$w`AnWS-r zVBsRLXqYbImm?`KEzQA%amE`A;Z|kf@#-y2?VebBq8*1|2^;$4satA>z8^n-16mYE z2VN5G*mpZLXee&iO4BWdTzs%$2hXE1AEE|Lz!{g53}L+7m4&HqO&ujp9!|cu9ZsKW zj^CfxTia2W@W>P0r{el?nSLzKZXIv&4$1bAvvjgyy13?-$*KLKss|rOVLtA{LEaem5M+JMnNNG4QVT}8yI?F!BkhcG0dVy&QbLw@9L8lpa ziY2V83vl_hINWfXC0Hw2lRk7&lhk~ zj3VB%u3u}qOSfQ3iz8+^PhW|C%A!!qr-9`o@6vTcqFfZ``{QYAIDo&))1hj!U;-mH(2P7P zRf{Qu547BQ_>?*`A0_Md*SlDW=gzyCY*GY|6L$xCbtvN#@ZE?zqab$({p0-XRUYe| zsWz{;^MmW}47%QrQW(b&ByRGITr4E9uV(k)1Yb>ZYizgWB%{qLmgnnJy-0(AE*@;h zDWaQaP(9Vca%&wrMXKuRR=b>y^#fx1Lp8uON*-n#H?{lSRJ3`~k?qhdbY>xj5j`3~ za|nn<$*h=x#A%le%hVl~;wgD5_*b~?mo}(PH_iDu#!gH~lQfHi_=>9KV@pO+ZV{Q) z&vjC5T<@O>Ty1z-saaapJ;GW~+RP^S7CT>rbHX?jNkrxLRi31ou_iHL@EmxGSxlaF zAIXCrHT0{xn4y<+IE9p;+poTZ0?eWu;dzTFB=~%pA=j3t_)UcIBS&jwbn97;J;Ru4 z#vvt&lk=LlhC@?5#=4&|f*|v353O#JpP^52S%Voc!GeprEiyJ4i6zH;8wKtWmSV+&sb0lH3xJ8BID@Sf$+ssjUfca-Jo=^7r z&O#w(AdGn2kDaHgwdIr9#w2%{ugkW(uQ{o)(U#-I`%ecPwWwVgZFK!3U5^W`nLzMP zmQDps$5kI1tHxTe*@kb5PK|W?xpO_wkeks^x+!YO{m@PA)Q#lene8-`CCBnm9<_91LAk4Lwzw@pi*5cm zhfWN*y47S_igFn$Qq~r7P>UJKl-C!pcXQDJM&RmZi`&v_*CSaFB*9pWXepq13p=<3 zceyo?ZIX&3?lDo$z-8}`v#hKQ?_oD_w9wi)IEv>!ufE@&8B(<4;2t^kef6s9)vH&p zethfu{k}E>@jV8X4F}i#JREslE=!M>ZAO885NlI&xj)XD^QiA2t&E(6kjBou-Jb_~ z{UUjqkXW29dbjCNYE=&2+I`k$*rW3jBrv$gB2RW1QPwPro8wI17@eb^xfpw1Z4VBK zGd<_Ua+^%wDTx)DN}x>G58g9ewfohVAS~rzj5dtN(zhnaNFt3oJ)y!2`|p%WtNvV= zzkac?etJ|n?c<0de=|gEx`fwRfRG~Se`63H5k)Et6QMC;NsEaV`&QeQqI%hZ7!H8@ z%=?lA?>S$Ux!j@$05(i7Fio755)v0kJv&RuuA*e%$yA|@oZMfq{farDWh^3GR&^cG z*$DRhw;f!5X~jZj(kc*Df0{q~XpS7|DP5~#5SCJ37$_H{VgTTvQp_lJWzyAbdfOnc zbzL_SGaR)Th6?p|wEDaseC(3|uE`oG;3<&Boo}D?3cD7v#37j?vj;$sCr`DjA;b&*lM()J@njh!To<#iINeu8kh>c}cgmi**!t4yg<0=xK zeaxK_r({ACh8nYJoUd|`Fo;HY1Ko$L7aJ?+UfmYh4W!||#8Bz+7CSyYk!=PKE0rXO z=`f2#<~nlN&_D`hob~hie&(}gki&7sLjx{SO}9>w0P=8^PT`hH1=OKOy?mW1R-=0$ zXA~kF{m8eN%ndM)6QT+M1N8|*IAD*uqQ)Uq?Ftf zdIuw&6K6Wt&0X-CJvGAzZCc7KN4u(@z=l>E5xYcG%w3>mK>ZA!iBSzH)}~}WHFt6^ zJvnB&mrf{`_*p*iTA=GsACiP=Ea)Kf5?2x6*}N6SN5-mCtC`r)%P&#+JhzeKdI^|+ z7pG-fV1BoUl>l>N=3Oj*en_fGb}NTa_@()g^w}C)GZSZ?t+Mtgh59CpTwvZ28>v4O z-O9(g%8Zf3;_JJvLp4rqF?ISt!pvp^)r|8Ka(QZyxxR)TS9rfVsL@i4f$C+-R-Xk^ zofa&!idk8WJ$B+vij^?WXVK^3)`)tuNG*~3S}e7p_oE{;p?{mPwaCxaJ2d0FBau;E zW_Vl3qK(f)?tudS8AF)su(P;woduMj_2-=^HtTUO~59n|{s8sY=%n0+pc{LHjBrPZhoy_eAH!=iye zpw8fTOzp<<=lM&+Kr6TW(>%butr|DnE6Lgl-g`%o9s3n$JZ39=<4AIbJyXo}e3PM} z1qYlIa6z5~QdW?_nYmX@^8lu*;YIN7I6=47Y(~;fvE%u?9nuI7SV#XlUkDDeAS+;Bx}E33yX$kvR{)nHDG)! zI>o4vdNaDH!b^m*2Rh;z@S#XIVUc1oM=3UfqOC`qpcgHyAJ-=Eg_b9%EIQ>9CAe8k zB`ilrx=IxldqhH_MM3ZdgrJyLaXssqMp7Gwim2>+AQU*`N=|~po;^qyc(NUbcQz4w zDCj_|u)8yb7~G9C$!oM8ZhH$32&c$uYE3~R)Y|m*kDY4OS&#zrd+;IwG%@3vfGQFc zTp845ytu^TGSz}Xaq3hy3Rz4S0vG)P)vHq>5(GjRnxd?-PSq^xOnEe5=_2$=YCEr2^^twYn9aJUfNg|Lgh7bB5LPaE3T#3l^DvM|=z z+ypv52(l>et06559D3|fLy~e4^~z}hl+NZ+W2yI2ut?jz21O@(;?xTiGuVRcOJu>l z&`?1PTvk%!t)e9`HzmyK^x}8xE~rH&(stXJ(Wv|avZ~lj-gB<1h7xuVjXPZ=#P6mm zaTok9YJ;jbkQdRxOYoAo6N~y^BY|4ka>__TbE+NdAtuP?C9=4n@+jUH(LhmFC*h1VSrO*WZA9yRBu}b}I*5dPouhnmHBPL{WI&=-!64+85gaw5kVsF2 zYUC&j?-@Ba(VP{aYrb;vq-*OD-g40HZaEzikExf9|B zE#|+(kqg`R&Dz!g6_^mU*EsFs$6KPjoS)!lV{EHR=dCvmNMCO5hxJ)MefP{d#^}ZjL;UI-lRS+Ru;k<0)bNxb)J)+ATJ4nNeM^=f?&G?m%vTAd;Xn)v#LzpAB_&LFO51rX>fH$bi(+TF7fue`sr4|~G9lZFr%v977J5xH zJVkB8kMl<1#9D^q%S`iU@^kn2UXXjJ)!oxy>rKxdpS7hmGG1pRVRvr^RhN%4zqE9} zlYEs2qHXbmrfVa2N1X)aj(NjNV3Jq81-3SIPP)QIL_aKGO|N?v^ow5av$HKf>@>;fTwmR+Q+m^E1#NFm^H_d5BOmi*2W4X#5&PS2_%u;?}dedtA3E$*lmTkx= z*{*9IFb&VsXK(cWi>FL^Z*{|Pgkm=$BFd7B%>&wI|5TLQ=sql(#%j-tQ^!E6kmi`s zc$1cK@$JsQZV8Wu*v2|JMUSgC#lW<^)eoa!C^OKN7xm)~EFY4&1C5P-;NO`61^TEK za1tp#w0cfJF1YAYznp;q+4@qt7RDXKSP?6UztT;SEy6jlIFQZ-hsv@}V&sLE)#(#K z&Urh8EP;|vENNjds)myxz;=ji8M%K4p@jPb_sK&N}9qe!At3KRs2lbBO zr06#EfI1qUoZ-&ZF$aRqG4g!tPApj6Euk)3JLd6{SYe+$*lz=KzB$_$+{Xdv%C;Kz z7L?s=t1xZvh7{#R2IpHV5~Ju0F<>9VD=n4`_(Tg<`mI40E34TOy+IdD<+X|>Y~7Ui z^GV=2#UY2H@G4cYeS2rWKWQ()B`!so=qYRu4xC`o&uc50d4+8b{9DEy8b`a%kLhqm z8wU>_J?H$I{_=*CV{>W0a`u5}QIZbNi9-}*K|Mm>-GZk-rXNuO0o&$f8yi$!v{{(3 zZ5ha|pt{!~&umUkW_4JkmXnp5D3afolKhkka_d9a!`Jbmok%Lea^LEEEB?ORZJ~HX z3RLL*x-wKS94JOQR$Yn3%y@}RvAe^QxfPCZ?|QG@KaL(A3W0>a%zR9R*U{*GuE?vY zfS$ST0+k1vz`BZzSr&Tb;Yr5!BdRn;9?Wa`&?6*|T68^R8K(pUg=V`eScpJ}%$o^Y z=(llHc$O(qr##lsa9VRNH5^06X*OM39)onftvj?cry`25Ck<49z6sxtt*TOGy@3%P0B z%ChXjnj6n)t#V@F%GWOhbilS*-}TJbIm!zcIJ&5Frf(d%R(ttyCE_|Fmm4FBX+$e9 zoZk4<^bpO7``7Y{ds!yF-tZ@)?Jk8Tg4g2{jku;R&W3BTo2{8HUy+=S`Rtt1qH!MQ zXI=69q~6oHPEiMEwQMq3nogxD`(d!gd^KK^EwsSt)*7A?!x3udw=G}9ZI~!jxH{#rFh7@&ky8iO4PEj)+ zqhwV?Sk;igrmYAkU{!It|R>M10w|BD!1WsF*&cU-H-tX=EM^20O43!{OBrD`6^m zldp~*BGhgAJay`xmTUKtu%g=V zQSqoGU@FoPW=`cCCE7$(tU$=>!0c|EjDfgFMsMT+9S$tu}a ztTaB%$P-geG;)>VAw^66P1YSant}!b28Tryg}C5}rHv4=o~X5RRKaFNc>;_u2@#cR z>)L@(V9m^v#S%VWPmI178gkB7bd42XPuzL}AEZScnP2X^D=S z;P{EZorP3$L{>~v*^v~0B9+Yl66o3}mWW?al8j{}>NRMv1LGZRffUBFh;iM^VGsE| z=t8Ppt1k_2kyGVL^?SYUnG<$oDsqsR)Du9GG#;dYSYCZ`W?RNmix)W8=^lIs4Pfjx zx?YuI3bN9mYHeOIg)*s#s3b`ikyudtB0;Yq2EsI>MOBkZOB-}<_F$1~0ZNGlI_9Ew zSX2vQ<;I@UFwAU60q{=$RUR<-8CwzCqly5hyq$6$qDsVLD%UJzT>x<`6_yLQDv2Tr zI~^NJ;RYp@btb9-0)CXLN3h61hF(g=l`}C;Rl7>!e@Pd&%Qu1p>|9lj*+9IwDUDQO zAsJ`Hda|bfcOgxPL<8#=o0zC6R(CtJc~zewS4E;nAk)=yO>O@~GXYANYFiDJEouSL z^BPLwAtd-kv-2_QOG=Zdm-m1cDWIdDvji>Z(?6*YRhTcU(R`d{ru+p?%{|2mF%p(i11L*^SBlsa7LvH6!MG@qk_us-4j8J22D{Y^c@scxdu}$pd6EEtsd!a$eu(qlz_eDI_s)M z1!!qPXlsP^u&tvrM(ExM4>Tx0PV?GpMHoSTYC!0$I00*7?z5Q4#^K$J7NSr2P$rb}gM4iP^m=p~Gx7N9hX z6s0K^^|}K)4OU9jU`vCbfr2eAd%{I^zN7`NG`EcXSQjmFHH538DW+@r0yu$40PX6E zYEkJ|(;($j9#^o15gFV~b+VgVG?v`|Ki%bGiq zg>y>7GJvf#_ZxZ*T54gzPZOaighdUyZRONP*wdA@sx|M06e~$sSxVMu5dFFbI3h3m z5O-LYSv5srb1PjIK@w08dlsPC9rmc@1GtWD2|b1bO?4@|*te3oX;zN5i+my@Y3o)` zTgaU*X@Gjhrg$b>IuI5B3ZsGO?Yjbx+uc^ewAn>!iY5ulgmj_73_K&ht1);m0hr*F zb*S}6Yy*NOh}TOX9Z|BTMg|hJTrk{CrjpRKCbGB&rXX=EMM|P(30^4$#B*Cw2W^p@ z%BlRYG#zOLc?%9flPMSos$N6=Db z&^Ij9^;U}79UpGH7`jVYWOV{lekG*}*&K}`PDG&-rolXyW`dg~FZ{=BUE^P2o@ftArjBg?Uu~ zy9Xt5i3MSAsOy^o(ieccKUMY~il(Xey2M$N3S%hqr`}hi!I=bEq87wnb_1HA;#?CX zU5%4ysw+yAW_C@!>w09vb6e@nE%|Uue%(f+#3kuoYb%&O`xBAAWC>R>`JbA#tY1`= zU6yo3s`?A0fjj-HEm}ZKh!@7U2Fc0I)$}HQ+g=cR-at_YS6od z!y??by}R<0KPm5aEAN0MuW#I};JOU=L;L>D-@zl>zQc0mZApIEJ`BI}=d*X;{S1zP zevmvtanuH9Epb>Kx&7b=czDAr)s-u_{K1_W?t-oyK3r4hKLq$M`V7v5l6$E|uuqF6 z+TjmmA3uNi1NIYF@cW~fD3)l8Xrd8({QLvIWIulX{1@eOhd=sp`@v6q;Pcrpz4XCP zWFPqa2R<(!_&nH)FQ!Jr`O!ybUG`~c?fb9e1Ml5;lMk}zAG3eH`rv~ExbnL4DxRvY zi1`7s?E8>Cd<92eZ|{5b#TtIUUd2(;6?K`!8n{>4%D(Uum;5IEO&*>K4{uj+Z@tN&^&AWe#_Tp3T z9r+LQU;M@F&$fQ@C+(}R{_M}%ug|D=@Sj_c%l|t&{D8gkcKs{3Z%a%c|4Z7w+puI@ zrI1L9lQpdkXKeUud*_|xrR}B<)a#SIvVEQwJ#gr!?C-w)ayz3;!H-fdiFp-5DR`!@Wr?K**auQ#{Lm+|_B&0uxs)sfpa5^NuS z-~s%eCHe3o_nq$?e%$^U#s+)*@u~MOT(zbCpa-w0zqT*_CjI*#8;`3Ov)xu+jU|J{ zLe*-sWU#Wm^^kq_!8GRn3-z3puq!VvuvDHJe>hJO2Hq9C2X1e_^M?K67k5>f`YG+Q ztz9rs1pzd2>AOr0s0AgxWxw$a4hK}Fi_}ucnrbe&gG(N^l2^srzJ1*;{M0kz+j50b zn)L9vO21EPtyYS1U-udGKpiQVt6C^Q)#qzo6tp zAS-H96FN!$>i{N11GOtsB0k(?@K@WiE;vfNBCW@>Z+)vQg%Xz-8Qc5z;oYqAKjFvj zfqnQxq+s`7F?D`v1%+Wzf63bgf4`#s{Z!eNckH_>t-r@)Tl*Q@)&0z2yw|A%M1Y>& zD-Y~HOQQ?VZKP_SqXXvDx8DZSs8wTSo=r~HcCZ)m;r90S_y3Br_;uUfhYvR`MrI_{ zfd@v3H2Rc*l!5wYdlA2GSN`aYH?s3zNsf1W(< z9{p~Oz1Ac6guByg<^m!YD&t>KU%KK?LmwZdlpQe=0h*q)q$J%Oarl9+U#^Lkr;UW} znestKzdE}-DygrrrOWac*}y!x39n~1#~d%<{_YbMZE9*SSi3{oH4yN$R_;96 zQ6_h5xK`UkQ%A%a9fhJ~YFbnrNvT_ds6m3r>4$!aooLIN#b6Ov0W>;K9VL($>F30v z$TFh@{&hGx)YMqkk?ydKp1x`ljYPjm49&C$5+kjxJPr!Z|~uFEgGdrUHC7nzKLHqeMVqj zp?sNYL-%fNrP&bisnN^}3k>rA6Ps``@ugkbH;@B6u;ggJJm*DdmG{0sf!4lYuCUnp-_ z^qe8xx>%R$EQ19Xc2kQM^~{rAQ``SbukR(NqWOsPN(cko}JE3!R3+v?Mao{Y&^B=uT2gV`9dv>W=2!*w1pg3 zhrbe&cE!aDg`Q>K{6h1x%2ILv#B_>w)VT21mIn11_GxHSP8t10XvKJ=1WkikUgyxb1}8MYX6%sb zbsM1>u7M&SFPv#_k)~x!XhYM6<|`bE5-6xb7*m_R?UD4<|tKKP^|+4^-4zxd6k61 z$5)3K1Dc?Mj*1F7Dcu9RLKJ1^zpVMR-lHc=EO~t^Qk7q!`-lhyrVl`hRQ53o8mR?s znJ)&i*o8h@R{^|c;fpBa^`P^p#uiZaqDJ>h6^K&>plt)^)iUKLQLS!7=CoueMFHNV zn!FcD4G@OB=2)~S=+9*&F6XQqE3o;BpuJQgL!ps6Xz#ASHtD5&x|i#WQ`t>;ycal> zPQ*4oEEm#uFD6ONV7AXjY}Zb(Ht0aP`Z)+gs>Z3#5_mU{{IySPRVi$i)lI#msPg z!t1c)RBdIk6fVk5sZdMZ`F}I+}pp`|k z+H$lO;=tS#gc;b3N?h{!m%gqRhbY?cqkGXbwvZ{52aTJ#6ap*0H&Qmw9 z0-r;dJ`-xw?@|*r@=uj?`>CEF|P7C2S4w}ExKCfAhS*k7Js-DlSr18Kuxr4fS;1b;V29BzZ-#7SL|zdK-A5Evz`VF5 zmIWG%3!!4U23{*HAaWVaXspi<7I5IFJK$Kqw9JBuFf0!9*y$mb$nk3+iwRegNAFb!i!c!M^A2{qD=}+*YkE+ zup9jyn3{*5v^!QM&7UzHXOW7(Hh#ZCGa4cs<`Sf0nk0)R8ECWnUf>Ny@n>wG#nkvF zGa{cCVHFR1H14A`<>xaBJ)9k{+kj2TNOzs1yxJ=T*}05%u)i7UYvo;kO~yU1KINzc z=w)HnLgaJu!gD&-MzKnC2b!BA{jqM^dE?y%It>gHm8kZd`==N(42IzS@*UCS%Qn~! zmV*iLW^9|gXp4U}k#lVmJ*9Ucf+hoyzJCGTzr1C|2Hr}RUVdiTKZ3OfFOLT0v@+E1 z`%=|yFB=j!a=H;U$!tSg^l)ZR1RfbR+aug++ol)m=vu~Ikk$3nA5`UnViT{k?}n(J zbGs}7E^+iiKO_usTdcM^W;WFKo@~}aKY5t4oA3)VeSh|dwm$d+W;V)3%Z_}uJ$j+K z+->r~S0wjdxB>gvg@mhhgpue{!1B+JPRo39xKE8V^^lPP9m6Vg)UVi-oyx9eNyY`F zgxA?~(J;$7k1tJcQ$k32qAE>cE(ejG8v1r5Vj~VNko3X@m#m-??+res;&qH{s;H<6 zM}@dj49W!?Pbtv2+Vt@MPJ?tpO!I2U&oL+eTglF}p;~>=VdgbP9+o4<0TYxxR1LGE zhnnH(i}q0896V$h8!J;+ozJDkR|o?;%(9!MQstJe%J13qt?Arthx$oHe64ZOJ}(c8 z_0p4LL-A`9UfpVPBPC7kUSccbo27qfr8?kAwvqil^t>5F@oE=?O%v&UY(+YEuH70C zjb4yvAnLA+77~qxz_cnMq^FkXMd89JIlMfcxB91_J}JY;!mV=YjPFZjI(1Pi1ku(OQVp`VDAcK_&?QnVyn9YOS&N@Y!v?#I% zJUIQs@FOQIb-7~68+C)=S!BR%LsEdIK>%3s82gs2RAf_+LbaAvudDn`mnfZhaNxWFTl zd?2&!=H^VB5L%m+iS#GX7ho4ian;A9nlrL5+ZRe;9^g0lQ0cHj=)`m@tf%9CRn3K~*f&@{QcS(ZGkdbc=j&!-r@cf59 z=VO`+10Q6(vT}<2SrmWqC|%$U#DFkljD9S!$(+HpXDOw{)4NiU*Q?_&259J)Sx(ck zmaoRFB^bL(B)95d1T*e+6=Y!GOP`tUtv&pAtp+!z#r(I!3-h&Mx3Y3s=C8fhS)V?0 zBPy4hK?wI@VsF-8*$(9bT+6Jno+Tbfs6(&yq}B8DF>*<#e!NFqv!9 z7~C-;Ffyi)HUM6O9mw2&Bi*%?ahvzR?r+PTzAgE!(_iim*WAC%TvKl8%Bk+F-OR{2 z4)T&>Jj^!vZo~V?C#|8=;ed1g)5;NBXFhJMIA^MZOBH`mw{n<&&{|b{)6mF2^>bPl*gZGD<=lP3bpQg8#?=(D9a9e>nom832YFO^gpTBgenpLEC ze2wlc!E;@TWh7nti-;F(Bep9QgRGTGi=aq^$a*-BQXvQbJ4hzBNPBM>)K-*FF$NYH z!UEa3UPvpST*9H4T%?t9!OM{&bMD%LROS_fcA4cn68v1T$iH;aumqp3MX1Iql%ccK z&J>W557CH?3xNu%FBoYC7m5UODs~}E-NoL1T06gJ;1R{F4D9^14@F91URGx}L=Bmh zIlBU9qN;-RAcT3H1$rf~AUxct6o|&bwX5hD>+$0mhUIk{-i-A8BzP8Mgj^l7b)GfH z)`%r4SG0uK00&us7r#J@E7oxp0l!VOeC$@zuk+5+>J&dA%iQN0e)(4)Laq9nr6qEs zmW%v#`N#c&bi+h^kfDkhy!R4jn{c0oI2A@fS4`K4CYRtT9_b{eW9_$aaafNmhDmk; z=a{5|ey+c&8jkofrQotT9?J3%twG@|^Insa`=v5%_ri>!%E_ln8dK%`6GdW>xfWYQ zMEkIa+MX8C8%BV;Qm#b2=r(FwltqMhQIeTlk8iXxJ}wlaR*?ksny+lw;;PJa*O4;uZa&8$u)$0NU-hd% zU1`E7Lhfo~FFre%b-OJ%ik&+wankM`^|{lBd?7av!gmSVUAJuqmnk?6s{PVvP1JkBS&9UqyVQ9uq168LUFg?7gW8* zy^#X9vB8&wm}qq<2kv$upI6a_ljCw~l!rAo5;Fv1y<)lHGGq|oo|CUYC=~N2gUc}i zir<=tO%L7({U(Q&FSMepMCKhcr5;4_MRjbUF%sXA{6>#Mfjn=wVD0!Hg)Wtj52h_u zBz0_{*o^onRi-tXIzL&pGI0&2N8Q?@DGheOXj4<52~K-P0YvMb@8_?a6OzWfm%2xm zlj(~zrh#HNJ1@%3HP4iY1lCTzo(!N0(3K-}4>?)UGS%LVIk~Ye{K}IgMiM_K6DSLe z7aCX*JX+=}%dqHjqPU`!`r~@fgv=1tptOoGQB9=zYB{^xC=Z3mU*PYDgZH{!*NL)6 zCXd!MZwjalu0I-*xbxjSNmHtTlErRH!cy`sEiBMBNL)nz_Sf*9A`!}t7MP~5g0aR* zQC>&WU7}7d?8)O&%Y)MKg3Mz^wyhbi73p-H)hQi$G@&z;kDidaI;?FeO&{!M`k(rp zreT~5j4Z;4VF)NFqo^w=uO53U8IvF78QkgQrjmJI(xOs66+K>V?X`pD(fXdTFhn`}od5h91MJYw2X?+PU zh6T2RlmsqJ#tM2Mr>#Dnq+<3}aBZKi4e>f9>a@HEl3aV@Xbf3W792U1=9;9KGrM-f zN|C1Zboomui-zrG^TTk@4G(F~rwm01I!e(6BkI+ZSQ5GH>c@v&>W-TBk`nIULn$<* zjMMDIY_|hp(TqhN+Jy*ArU|+WvI;?Qgvt4?P-S90C6On+g(TKR%rzV$?md|&{Dn#0 z#5_=z4ouimSx`2X(<|O#f^e_lxhgc2YKkmcjz4j6Oz4lGiwGjTnM%n$dv=NFrRY$l}5yFt9jp9*KQGrkGNtMT_@)n?(0hP~ytIR-oQM5FxRF%eoRE8{S zDXvjgmim;sbh{q;?~#X$%9FW^rMb8jq{uErWs&Mif$}T3mRX`+Q!7eBabe9ag`o5v zQAtfVwv=&BvwAHIRHsmdI=+fvJtNMaHkkS+C zs15bpTlA5KBKR_yXkrK&^tqodS|4=D#&}@rNfBy5mwhJ#MKZioh|&Kc^oA@jgRD33 zG2G0yMbnRSNZ@NA4+#C7bdjqCu*c#}@@dNBdFkC%&Dclp21%$ILN2Y z#i`WHAXa6x6oZ>;{lU255Dzu6e?O6Yz#FQR$@;yiWnZ-sOqfWAM=2^vIG6m11#Stb z{Zzhj&tp6W8M3cK5lcbr%{7TH+|L&-Qtg|#8jYU^1W$Vl+m%$P$Bh!6LuHlw8m-0;>V$zH=GPSCh`}(=L zJvnlE}=eNORI7Hq>)#^KH|ELmXo^3|uTGjPmhn z@jxwLTiQKAO^f-`arF{WJ6wV%O#zcE#^}TcFbVn>x8iY$aR4Q#djSVAl7d(u6pBqK z34EG8SUs3h5Jjj${4|0%@j-7v#G>eRIaw??ZD+Q69r6d{FaaB>>j*YIN|dm^K(4;3 zIop>@S|^+}un$X2;!FH)4d)Vop)&=l%8S*bCVg3Dq%mMErb{67{DnvW&_n4evgJKh zi~=0aDam=bPRd053c8`R#k8$#MOr7v*#Nc~(IE?-s11FFeXuk?Xc^k}2t9)q0!;3q znnCW#!VMZj(#dUGWZSqu_*S@kU9$wafB4K`we?Y2+E{;d8r-psx?PXlYYg%*L{iLl z(~BP*qhT^Rb)2RR8N2<7!^_WY1BraD-lM}~KWyHf1=|nzX9LrC$p*s~bbxEEYW0?? zb?vktwRL_vxe;qJWp3>A05&>_lUknlPuA>{qpdJlmzwnD)v$hl#5ZKv%Bqi`6>bIW z@V1;sXPy@LMn2>xm#6G(Tt3d_$=Pq3Gqzx_G?GS0Pd%(J;! zqgaTZXe9oeCw7DmL=Y|)^2XC`Sw{S?;oz8 z%VMN}b5dnGZ1?h;qg!uO*_GW->lwiKp@|~*Fn0B4i<%otXxfiB7vkC`g<i=N*UTfSF%B%tNC;#wjDI(3k*(?_W?p<#+`rG8-0mP|l~cK-g+=&m^>^XfDi|D&{JI)xAJC#5fW> zh_RlEZSkrEN!Eb7A?IuZsUTe7uQepmdg-mS=^o0Mf-cVb+7?-Slqi*3yx3!YOYXQ$ zTDfN^xt6?shj+KMA|5#GFZx#2b7S5rU(Y#ux#i+n+!)Tp_NbL%CcfX2p0tL!cfT06 z#7;ia@%${%IunMpgSb0{hQ>kP*3Z#28a9rtZnPl|Q7lhh9bG4P^;tO&286e*TX@9f z58duze3m1(-X&$r})qp z7i{E*D7NHKdnI^&1gYhNt^Y%GL{Kh&oDp@Fp8G_Msftyb&4 zU}c>iV~l$*+I;#Ln@?vRVyqG}dZ3le7Bgefg@lNnMMv}|7z}%zHbRJwPD(J=a?+l9 zne^LacKXg(e5Jh}SGpAS=tYM-iwg$zN*YAij@Lp7JTW%WmTAyK_81%A4n#4UI<#QC z|KfYWDDHqA_fubpz4SwFskXfez^@ z-8W|DIALGOR(f5E86M4ZvA0zCC5r|N`%>*?UUponyoT_dESfunx8nAbZ!KS|hgq|g zxD9WWp06AHp6#baY^t_6<>b&dpEpkqcgUwcloh4K6J@Aq4t!ppOB)eeNmZs+D>B#pl^#pv`!9Q*! zJcK9e*=;;=$!6oVgI&`)u~u*1^3&=)S&+?i^R0Y#%iu(wn{)YG-P^^;s6!4M-Pt^@ z-Evd(dD}P4>09$x>eDVKHrCz8m%p4N&obfhqGyoirky*TNgJ}XwbX8lxe1q!Quj=` z5ySB`5&iOyQ)KNH?cgXuDXf;pvEXBmlSr3)!IB#6c8_s0M$v|6;MP4_VmKQe!3=f= z2P}M0PUxLs93~0XB!JwZSZ$+V8f>Y#q@GX7Dv${+aEeMdcxP3X4u8T3aHPV>A)0W) zEP;jonJ>EQ#f;&7zGW%505@M?*IvC=SwM^nZ1;LCDeNYdYpmTv z*+r4O0ED3Fg(#&!YJJp7Y{mJVd`XU=QJ>Nj17fNsCMu!sKIf>DOuUA|bq9uEf&BcD zT2`g_4wN!QEuL!giEAn*AujTf4ee^5k;`)_cx*K0Sy$Yl(WZ*j) zVv)Z>f+8eZfL*AErm?FL#%G(0=g$Si2ttk~xHcK%$yKH%^A77ggH~g3b_WnwjoG-O z8Vj|U&$Mn&jEv496u-ejjH#N&aHT=%Dl$;A0_j>^k|Ra+FelK8q&6c@+X%svahkQ6 z`asZ1Y9`(FbWxp`K+TjuN*j4*fRMtSAP+I&MF^U7m`D=Jdo5ycDWSmPBAQqy zUF=YOz~amQZxmsWaaW6*h>r7rY;Ck zSMUM~F_?_XxQdZL1qw1MBDy^5$y;fJ1rb^yF*(y(S1ixW%cYu;Wk(#7$^_ACNcc6u z-d0A^%95P_6h$>V6%lELvb&RUE^ESGfYGAImM0|iQj=h(IlWJsIrYMmpHoz?QgDB_@tiV#tsZ=^BwH42i%I&QN?p`J7 zMkRqI3_&9QG!Fu+^ejiRf~09WRVv!y7SNMIdpIqNav>(|=<-&yei|dXO3#Zu8G*n# z1Q+jpBqXE8qzRoxP@>n^3qE%A3cx?4EJ)ysyh)QOH|ak8Q$%^uO_(uuTujLxx&l&? zp(v+uHKYP|X%yR`E>iUh-vwNQ#RdKU&s7B|R0X0D7S~W(qtw9qLX>sMs?ygo7F(|3nrOGJ7+%^^4~#Y9 zJ-=%onQthX?kJ2;PqDR=45vQ2h9gfjaPbJpj}eRXsg7RoF%nTZQ-#Kp6E=iQNU8*| zIimwPMWO~1^7_ytqWL;$JxudOgg(*9*H41ZJCUIZP3Ctv0l)xNJGFUanfU0vDp`{Q ze+s?`^?f3RA_RdqVS+FWzC;t_gcn#W>DOMaLpM8lQX_X_VFyb{XD1rU$`~wRPo_kr zReMM~MG{h5NS|)qU|-G zQVFIemM8}Ra46EXSOI}c87o+7q`-=r$xuuR%9}*0O4Eel2Ze)*#<=y2h#({Pa_B*# zyrFClHi@%)QDxKw!g_U~7l($nv<{L2Q%jPAW2&gALfOP3Qiek_(h`(W(@@NMf|90~ zLMZ}5gL@vjqF2|>}+0!4lZsE}6Vt-a!2Pw>6P`&L4KQz=o| zFQSoG!f{xoK}z6r1M;O{QF@bE)qL;2$9Dvd(s1}t1e1>uO@aL+v|TJkQ|4XTvznzy z_~aA6b34!eV4nQ2;reZv>KD<%HyiI|7CyN&dJVSgu`8M}J3sZv237_sS_H5x$_Cim zIVNcXlmgq0?$W3#{5+l(w5f|=l3c_QJ!MgNAWJka=z^%;zTS^4)Qc}qT$gE7{n!!U z%1aZTrSC%u=ut`o=v80l1BGM;eM=3atxJrODQP5wACKF^vDCX zS08-wa`x#rfA2T4?KjH=e7GgHmoCZw_#jSm)H7NNaO$)0?2~-_BxgP6&*Szex%Vma z;l-!ScNLc00O7GHc`X`%e0RGR!k4zQzt*=@Ais@op@$wKcn6P6vW+9BZMlMfsyEcH z7Vo}vMb>Mw^}x23E1%h}X_@45D)}YC57Vyqsw924YqelUH#Pk!%{-y?YQ&FnDp z(Q;fU!SSc6~>U)N|WOSwRuby~oGYZrNRo61xVZJ@Z$E>i!4( zL@oUx?x4Dg(bRY5|9Cxn`wHznFZ&)y-l1>|g_FAZ+*IT*-jKhLx3|x;C;m^eWUu_; z|EUhp@O_mWIc*D0o76ziB%aaK4w9d!BDj1R&uwr2r=VuB{QyBS(Qj$iLc6loIuR1%Ho<;#a3rw*L4{pr{Cy^U|S!&hpTKTq_}S3mbb66mAnAN$Hz2p%|( zv#1Bole(+FABoX|AN(NMAo}{^`PADfiW9>tFXH{`ygbdmE@B^^wkEqIxN=w?dMGWt zdxFnc7jC+VXKcw?R|>xIjoN1@#!yK9+PDv@YKv{f5$bG*n>QJ;oi(R@Gnj{Pl` z+ibv#Fk0+Nt=nB+udS~;N3_)

bJwM?HXj_Ok@!8w|et02u9fd^@>xqoU6cg+|%! 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

RotlOHS5K9l`OM`f&SjV%B#4 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

*AwhXvYQ*a? zK?pq=J-L3LkFjEEh-Uvp=Z`!$Ecc$OoM5c`)l+g}Eaxf`2SYr#=p2&wu65>471fux zB$MOgi(PYmxO8`?f<_N@?+(vR&YQ`8X^iAVxO>3TR=Fvok&u8-D4GJ3hKTii>>Z*u z#^6}zT*W;!xVvKp-V9o-15Ys+CNZ2?je&B`M%z6n`=Z=k>b~o+QoZ3xlPz9|ZY{sR z?W=1m?a=(?2UdN%?V|Ie8fSj8*2Z1@nQZ^)@Jc(n!K&eXVzwjIVSV7nx&^Fc>!;+& zTj=*a`jp7P9p=TMXnBony|-M^5-YZj`Po`m#H_0?B^fT!j}XJe!5+*;`Tst%?p?ov)0;0;?h!MLXI^-O7z^=#+ z`V}Z9pU`2XZ>$Q`lkYiL7mO?$;T;`YzbSSryhqRe3g?xl*kE0#`it$}CGR66=2Cmu zyDmm+FIk&*Qf%iLy#`F5=P zLLG-yrAG}CI1SToq$0d--t|O)SmaNIOmt+ll`51F5T}W8C?n&I?KSuo3!vn#@!sN} z_4DGC1PrzHw9G}`x=|EIb&;7DtYRt?av_RGX;U9)5k_WhfGSK9qKn?ym17t0m_+8V zv--qfB|ore+RO*nSGmebC->{HkH~vF=Mg=Vt*eA7jNDT9ZX%U5v)I##Zm7}qV{Ez< zG;X7uW2i*X5K#K*Z~{d&9yExg4?6qD?XKwroCz}%aXLSM(=+sh{H;_sIMtR;vtdjQ zT7@pZ1Ofh7T)$zOi;1SjUZjc&Lozv^(6I9?3_xuip;>z zuy;j}5R@TWeFxvhoK5x&C?XRrlaw%FFjnYvO3USVT8B%VyWB^SVQ01=I&NC(J?-%Mc%UPa_2| z1su3tnpAWk=5&MvH?Um}CgM{+cXTPeGBY0O=CJ5>4y7H;PNl`*36Mu3mt+al{kSGG zyqD-GQgsY-<1*~VHf1t7KRJKB;6N_B^OBrfyK^b!B->f?=Vvd-q@}9R`l^$5OqRHy zWl(Ph&m9ORO3?{YEj8kj%Stsb->6`Sq<*bxS=(YN=QX}UN5qiZ6~Z;2%9^CTZYvk{ zH`a^Xq~f$TrNP1U=JXz$N&gVAcAmu;=%?V6s3HOCjIR#joNWZ@MKfRH_u4y2iMs*U}=gMHp8eD!>s|GTMM86}zH)*M4@r@dMx^9ZFXPyJ0-B;%)GyHrbHGtRDtBIZA{Ot5 zDLS74tq5Dw0<6D9CC6zzQLQRctjN1^C2A2Y?<;dK%ApK*Bu&varkDa{1aPmr$An%{ zohjeD9(~FbOCENRySYn>E~F7V1jIAohzaNnOo6FhPG?w+^FxeJNbs7p z6Wmk)$}4x7u5)YwI)F=d z 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

9%6ch=+Nv9zurr$P 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[Egk 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 z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2z*`$?CdnH{U=}e^LhHb^oV{y;ImBNpWh0$9qg8JgTl7Y?q=7- zyV*T!e|N2SqusOKr?&yx*8FZ%X#eRp1pdwm z9IFMfPMg|MTQ#rWu=`qF=Jums*vKd1<(CJwbTarwwKEC(cB#49-k*d~?qwK68|Bhr zP={{l47}{>Q1_FYLdfxxqx*4n0vFp&IyviVD>hAdvfn;87y3+`Q*IrO`Yy2jybwr- zZF8v3)E+75{NN|ME6tr`^MR#$W~r^_R;Ole-%eX?_1&cN&r#C!@-yI;rr+^SNP5Ck zjOTTbbkAzdWUKaMvU4TL!?8Z{QrnJSMb@pNd#9S%ThVi^3Q7LzxgBpQHM8eabz0wx zUzu-B=9adOq}CvpL=a8<1HAt zRC%OOjteQvxqWqzoC^+4E$KGV9?6x0-})wPqe;CQs@24kW%)A;3kQ;N@U2=Ot)APF zXo#!ojW&n_&#Ek6RY>xXa%@v=R%@2Jx>vG@KYIk~x%T;@+3kva;Myof^`dD^M@~4{`yx?_B<*<&X1^B)_TbP?T6-?o>EMw{Hz(4oxW^^P$CXdAq*0b#byLBb;<;GW z^A~L^#73DZYaRqmyOWYRnE5t%q;RYz);>)X8kgqoac^l*q&%XFQIJp7X7(U@nb3De z3AL(KR0X+`ad3a;Ee)pLYznEEY|6TuPPM0Exn+`7VX|qfp4Y8js>p|r?wFBp1h%4# zcTT&g-8t1Aghw7y8}gRuvq-@AUGO1rEFq7(#h9x#_@WIxQhwC`!I{0IZB8f(DwOqpbN*4F)XgLJMO|o6HGf6VegLpaleZ2YkZC;{5^7GPllT>*g zXtgezujNmg9HLy6jHq-K++UQjin+ROqT(E4w@qccOy=U=vqiY}qr;geqdt|Utozf% zOiDhB5Z0Zj1#@ZcC%f?4vZNlnRL|981?S@7OrLxJ**;TO6p71>v(vpx?)8 zeXE_>mVvEvz{GQcZ6)0k>UJ^3cS3!pL8+62_IFaIZWlE!l-A$~SJsU6z@%49F4vo)H0Szgk_BzL(3SPBIDdthV@19z2%kv; zO^Rv5Kq{(v-=#c$m8g0}KLi$I!85vH(Mj2bCfAe0(qnJe9QRV*)|#;vq}vKg_vS9I zhP09hD{>L@(Dg{Os*Cb5q3igf-Px`y?U%$By2Rhkrte&LfLJD1t6wxWE8{BlRWszz zC;{!?P?{e7kiQbT(dwGTAXw44evr=;A?1m375xMfT;GLFBWiWbcV-LkUD{`Vu4t=M zY}}+}t4jU`&l?MFQa-Wl&Guyn%d6^5{yw_y>$ynGJ$G)B?i_CJxjPrc@KZt{-D-y> zK&9)v63RqUeA!e!J3QTt%=BM#t{El^+Kw$h#VbX81jS09{O_U7q=->Z{=BTE=<&@E zJH<4YnJVR#wN;}{+uU>6CyGAfd^wsdDl1Cm(zwyRs@I|C6*K81)DvxU$fvg~>EWq+ zN>-`Oe(CI?$`depb+)68d(nT}kJ{)-X{?$_t^Sp+SGrnGL61}1B!_)_OIN}!s-(N| za%X2vh;~$~#WBj4RJnQKzL$4V&p}5a*Aai%>^hmc`H5n+X1gB8^Lp}5ygbwMnI=vf zJE?wn7I(K_kMI2tZu2`|NEWA;c6u0_x0=_cr(aF+%@_~AU!Cqhl=tyy-(EVi7=QZ4 za3`L|D%AI5+;7_WayV_`TW8@9eqz(f%dZOR3vb%)Yw_%bc>Qvy&rX|kR@v{IR{N9Y zpV`hMYwErC+Yt1%)bE6!sCVs8&aZ=o{pzPl94{4J40da~NM`BUwky+)xW1NM6ZZ#U zraKQ6lGglxD?hD2&6CcVsF3>G1jlm`S{sS&%!2l8h^c)`JITy;tJh>Em(5Q@d)S20 z#pyWa0oXP_JbU?26~CU&-CGi@=5X(wsN1a8!pQb3i@T$yxemLRU!3_6QfrRdH?LK{ z531=S)n8Y8v;Chn_L99}`}-lZ7rr;5Mnd?RyoBZrwM7-$^xEEfK~FZ$L#(3OJl_3I z^TWN_uI}9YiF%xlFJG18QAktW(Y(5Ed(HKmVRWrtsAcWpVc1jug1$$1&%UBA$)}#K zIV(9=qSnSqh*v17TI6a|4@(%1tWN1j9S%RxBf9e-_25L)wcN9LvlU`}_>$59Q%-`)jq2zu?8W^w8Ei*;OS#))FFZ&# zQ7=XBdZa4HR{7T-Gu1ZLJ?HgRt}HvSoutG>viG&AV+xJrlEzaH6Ztc-q(Iznr)bpW6j_E*iHrjopy=jtC`?5CrKWk1- zE!@)tN|$P~JELV>4(qQBzt$f9r5z1UAL+X;Yr=3Cg1uZF20b|YY4v)W4m95`w*4+O*j20@ zL`;hE{EXAn-7luscCJ%33}!zvHF<6t5T(Q0Wi&qBe;>YPaUA`74mvwFL zHc6E??FZrFjgufiCwl3v=mmZ@J{#7Pi&zirdh)fS zuf3bzuR|67Fr04tBop6>_I7kmleTyHT$B#cll1 zVtxFzcsQ}ITYR_`EY;2An{oJI^J277GYZpqVndrWhr@{&Oh%K5&Kvb4Mm;PGL-YQ| z!|5=D7vpdgrHL_)-Vc*$2yqr>U#r!%(a}V;g)q~^dk~vA8rspjp`K{qjQ{0P7=oDAcj9=~g3*J&Dt*R&p4Jv3_wdvPVjI)+`K1lc3hbW;FcTM4O2^XwM@Ia!{M;ze-fu=v-eV99XdEsfSg_QumZF#G=lI zT~s9rK5|R&V}nBWt!<3Dh)gN$>m>Ie4(7_;I?5LQ3c%bA!mcQ>&v{7)$n<+vwb!8rxFRgV$DPDJNoza+=&Qy)I4AKb5Qg52xTQ(Y~B%?^{!u zonE!AzBQ4*w5uy0+kM}DWjbNc^$1v}>$YuEW$)X}s-Pw%GdtOplSYj`KS-9Y+Nx4N z+kO;_paARSa!2kKd?Ltr7lKHY6x9h{yXocqqLAGYy)*Pd(lcB_L* zJPr;9$E~wI_g!Dfds3g%ff{_S)ARFQslvt8`Mb}}+t}`2ou`4?_568zFsQF;&4Yt< zb^e@cz0w|3pS2@(l2>2+O9Z*wRi3VPH9T~c8l&Y8TIT8!PI)@( zS6QbiYbhHKw)3X5)IE!`7FAR#q3K*5W*e1wkV|=K0r}++2V(k2TEo~ zp51wFLw&APRcq{9lVp}ND!Y`{OM8fZL^{g#A1c{s04oa8>QjQ3@_MzEqwe`sEzygr ztipGd>t>~^x=eMYhv;34GRwt%lRVOFSIChI?)R>tD-;%0c)?U^NZtky+Y8@KE1k~Q zW-;gFjJlV#t#yU82;PqMwyceirI)@$uD5h|rCiavO|H2!UTR&D9j|qwGb@`?ulHxI z1xgn;ORbI;A(si#g;HXv%Q?LdxAV_RP+4z8=sqhsF1GG-H3U!iWvd-aSmtK^N?H~w zD{a$DswL}GtZ##Q5=y~NR}vmSMyiyR{p4+qGQy(w^orDt_ms`dV&0Zn*^kEgVh3Dw zRzX`GjddwsZk5|wS0CzyF837wndWX^gGdK)80v07x7ho2^geYCMsq0_8ymRdirmf*f>eSBZWqUz#4)o+)X z@rLCx$ECQjU)lSS=c~p`-}YhAo7@7WbOq_wlGM3Q>W%X@?L7x)HoN9%7EWs8hz3 zD;7P&lZ|`yPt>QEeCT`HKfNxCi>O@R^ko<7PROlXQD*o#Ncdm`mj8dP{Oe z_M*L1q-?TiebFuaW&Mgy*NUs9%I+>6mT_{Uyfd{au3RzDg<5i<)%}BS)4Y++Lw#|W zw;d?S;!?#y(&bcXZS?I}8QDwO37%8j`|-VP>Qogk1KpP@qga`~s&FnPuPrl26HbGE z=H{K1u7kS^n|^oswy|k(S>jt0tW&SrEab%n@1q;txLA9y`9px$?aY2{2ux)cK&99?7n)trge?#P4%DL$!@OoR?DgK#Lt2WDk?PyiYNKV`s4dFxXfwF9@(}O| zcISH1s?Xr20wMY$WCv@J>Blt-r!GKL4Ep3J=`vzpZV(Lq@$Sg{C%+U6ub%ghRZ{g zE?ec4D|%tWR^P$8hwMdRi90sH_A<=9Sf7&Lf5M9{GwJ zzs$pUsJGyhr{Q{EXPnDy)ehqIvJIMJ{hOV7QFP&^7hWviY-O)L8y{%Gl|;7C3)~99 zCs1v3OVN}5UPkh*j1^+Z^+v2s|D3rN^;0dnwr^tagtNNwTV&~ms{y&t)3g;O)N!j0J8>t?^@9uzY9GPTJa}vL?Sf{{ zu{3p-PLnoOQd=CeTW0?WjWcV>$8)y41tAgw1 z9_0x+(?=dTIuc&`7l zs*|E5KNuw6{>Fz4`xb@Zqapcz+i|cS4YsV-c(AQdx%nWa=-bUfd#<)@m!r)_zj@mF zFsak?*#m2?qQ>XX+mmG9@=-pqU>1~H#kourfD(eH6y3oWT z=$*x2=cTNS^ZQ(G>>=e?Wp{jD>ms(Y`cx)4Ulr&*k}l|dh9I$zbjAxh#mS$)1hzJB zq|5CadG6d3k37mcpPeNrFBa)tmwxGTF6nFA5qbit7gn~qQ0dg#_#sjMlYVNU-&;r; zcX_#h^WO1jt4KNkd$QGGa?-j*3LbynLiku68YGQoO{i2K+WjEP_caugrNOx}9P)Bx zMpt-HnWUGCeaa*y6;<6n@!TBptzk3oQr5W84e`a>oJl&b-gHTP?UB4hC5zo$l7d<^ z*QU-pF1n;ou~Q>dLLujQ3$nT5xl2($(~&N_O;Y513%*qWZGDk7g)@C}KXlSAFLy?1 z2%8C{q86|(`p(l&BIbi};a7##om0SWpUJ-QC`&o2&+1Dl6he+aXHhpAKU%Ny!xg>h z9#s0;i3OYMH;NCmB!V>elSt|DNy<(o+x;^|jXnjUq+fY5zW|@lUult%jg%LZn^yp? zf>ctR=Nyls&*rKmo20GwYK*F>#Hgf!%i~ z<#Ew*ev{gBT=zgn@gijhx#^y#=9YCMvlWm zj=j{RB9*gIuN~xj%s%DYMGdRUu+VyyeZ9%$;8F5OW2S6M+)aHY^2ix4^3E3$!bc(y zm%li_U9Q_h-6rp*+eV)oP53xHX_A-HRiXbbP@#?<>7$Txtl=CxVQsS*{tIndNH>I| zMY{96NN*OB)NAu*v)Plh%bB*6;)Via?|E+D(r$yH)oGv+aBKgp%X<~hO51L-$` zt*!!I%Ka3dxZ7y`Enm)|nQEMCpx=KpXuNCjukAWr4y0{Tb*jY;l;!sKwW@F&n|?K} z8%SqZ2m1x2bQjwRwm)Ys_Ak_9D`^p(X+`KoNz z{mM>LOjo-nM?cfAj&_u>tvkmb$oM-ds79HW*V;Q4UbV??r3Xu|%lD~2s>)fX)$8MN zWiQK0jZl>jWA!i`>K5rbXn~O!wZe+>K1D(MP~GX<2 zCn?xi`f%OmFLs0MqaM0QRVzN3hT)`&+pV6aNBtj<;}_!h&yx0yc1fi{5+_LuU})=r z#`@aXYpJ!$g=sZArP5TDA6EL2k@L%KNPFJCOQp0vfnEsFy}U}>&+K|;>9y+cP~Vu1 z?EMq@+*hIY@PjIN7sAQ-WN&nKtzS;dAWC<=6JzoPyL9WK1yw@u0cK(Ejl9?Q>gEko zO);o&4DF~HpQ)!>p=TDyHa!^mDi<%Ese1jSOdV?E_9x*$rn>4riTiD+&R(rX_L{w^ z^6~7tiQ)8AoeYio6a2`dU%07shN)D{r-&h7nK7>vGmXwA7MZ}n&}tX``J|5JKzbb9sEdsWg}V#AP9{NU>B$S$Y$!#7mE zn*K~~UbpIMagXbMKLuedOiArX@r`8lyE^P$X)8_qUNzGqXKMVFX~=5S|6NRPgA^@4Q5UKuP-gOZFQZ(Us#%6#P;>?ytf-{axi}H@OpT89{o&l@WIvTnP$s* z*f~wp=|Gbb8!tnx4nxjiW*{*Boy|lkEP4_ ze2Qmwef_!`tnMcf_`zVJ=S#{A?e{e1D%0aj`)T^3T-I9u>N>W2dGwx|{A>!LQ|j=M z=TTHTg!-g9u3WqqbWEzkX&rscAGhsslQe=;JXWTPaY8BSEY@#(a#y4sgro1EP*-T8wk*-xwZ7tHU@<8m*<)gb#*?R=?kjnj=3O zKhP3juRYh;@HEUON44+pqhSc62h(W?%|w&E39qP;pPryb#}LFo|E!v7-)Si|4FD6K zN23&mxv9Shva&{S-O_uiLR0O|k!xf(m?Z8e+8q_9M|%HKGXFr)V_>@c9fiI)26*>#}70) zqcXi+`MuV>wTrwCiq`n@+dLKZl7q_HZ(XT*{@;#Hx0H6N(qd$TlXE@U^Fz8SKR9or zUFnH&(8660wG5Ze8Y-t3^bXqHnYCAQ>Gxi>tLEIIRH`H;)$pHP?w{|=xpIBcNG<&3 zb$^ON<@mf!@gSm}`X2kNOWWEZd6gKueZHg(L`RTGnJr;aMT>Pxa| zeYD!WyRtrLw6t6j5iJv^w6A@(tHtN`YON!;n+~2!?pzDpRfB`MCiCq1 z=HPTM4Nj~&+SApT9!C61%W%A6SE-&KSarPXetc!Sx3vV`Mf(k%&2;LyI@nWfzH1*= zZQ5y1Rn5V{^AFp>UfLQ|s$S{z+(TdI&08JIlW`4KEfg2uwpgk6l~%_(wr@z%j;^Dq z_+r>?6|`8};JlLaZ`rYKSYkWYccAKrE|XL!$@#B#we*|%p+(@XwDg;gqvQ6uQ%xn` z>AUiD;M~*-RW7(WUPkqbqFCsdq*<`E$daa23GOQ9xh9vc(uCEiC%C9^Wq z=>BpjJeqvJS~O9)$;F`F%PtiLQux(`*2jwyb5JSwBb(H}0GL z#DX24^mwDLgWg+TUril3lS-0$60QX(pG>@b@W_MPd9I?BkR6F>H-W>V*Cx*vmzJrB z#fxnz)zd2zCOhi2I!Nc*a*I02?Q<GdOWmqQxlPy)Nh3@x3HcW>-ZCi^N}PpgrRh45TDvWi552Uq z`jBLucbp#vocj7<0Y3xBl!fSLc~IsBvEXr!J)2qJDg- ziH=e?2;KpIdn$KB+1~h|k0?fMmLV?1Y|&qkj9jl_QMtQPUh_Z~4g;@jr`ty{d1gJ( zKii45C!*ZQrq(r|ZbZVaY0hf-U4Ooso0if{CMD=1M>k;5vw*!mnqY-=XBR(TEk7Tq}X~gv+DP2wyO{GUO)QJZSeUL+*IxSMDzL{>l}o7meA}C7=4EX6J;O(Qq*$1YC5psU6aKXv!;q zFzz9`*rCfL z{uB1W5BF!>C$hR{=F6GycbXDqQQB|JR90kUWMpLIkIKrbivCK$_BLs&lx-0z=-)C?&AwP7d|5y47+a4zUAMTeG}cL#+i*z!W%GbPCYp7 z2nRdz-N$wiEqx2@7GAo>?Krr8F8)0F+yc)n@P}c6d;D+h?dY%V%jT=TWWR1-+p!+^ z^8I17-j}E4J^i5f+xTJoZRGtoxtsegMfU#Y9=zaD#cd53y@PL0n;Z*2Pclt0*bYO(W!{eVrdW|w}D1$p@Q z(+BK9ziNj&v!_2a5ZhB8go_7SEga<0|>?gLO19&P#Jh1b~4@4M43*dQEM?)le?m~Gy zxFt_+?7Nk|O?vvdP7X6Qs3?<%5}`8>s_H|FH_v#;#KTDH0>)FA@fAq;;z)c7aEf}9 zQ13*h!dqEQdT&VPF9i41=?e+?Ltxfozg;wa=9BdzpmeDRL_Imkx<0fqboan2i6f#K zgq+e-{t%ksrb}OABlLf%p2iQ9^NW%Ley^7g7QkO7dRYd;KCk3mM#rWXPyZ96m2sr} zvhUx41a*1k1>3J%x^W2ZA6V0QOVj;!+i?5S4aTc}n;a#3$r~7BCf=$kP#zb0L3zKp zoOcLb=FRxOV-P0Z*=^;$=8%@A9og=B)aY?Zb$;cba z#_w0=8bwa7Ok&-Tb;*`iF89HPZCV^^^zla){10X%NK|77tivQ%Ar!;{l|M9tCN^l4rt~^=5>V; zOQUpGp+|z9`EB%;*2>1~{7HHLCGx_TDyL;{y{ZxoT7Z+K7(GcNxbO%g0LGMqJX)x{ zuWPCHe#=`bJv4CG&O*qbmGME-z9hY-mH9!{zA8zLi$c?y#0Ol``!(1t*vtkgNF}(H z_SHk(Fu5xZUy3ia3z?~K#n5a{)i}C~el^6>*zs*S=u2+n%`#0>5_>~2PEP-w5|kID zat@?tgrip0HLYp&nplj*8~X37YdRjz+bwJ5-a1-z{nH)4hv&dEs$p+Rh zYE)o+AaE$@1w~0F2Fi5;78zDP?4?b+ceeY;x9j~DV|VM!fJH#l=C=&Kz1XKI zU>>J7f_nkAi|+R(er1SnpCe4=t_U@5H1SW}!s&@@hasLLme#%PXVS>*_BONZwl z3~1Cef=Z(Su5xDMi;vkwGqV&BL5>sVQt-;KV%=g%%;=;Ro7O)sLP!tL5|)4+_5kAu zXB5o69kh@R#~mKG2uR_62Jsz@5~FL-ujq|GrFoQgV{W%Y)jZ}mmpA327b!PT^4&zg z;uw`~L&d0g-SEvQL12|bNE`uL!cBlR9hRqncJv=%Mq%EvP5cQN8=`ltx5Ls>4;t{E zjB!m1eS2|=z*s7Ar^8OK5p#}fXrnK*Q8}=#<`DjPfQ8L(1f>f^PUf>s-)7Od!GivD zD3;DH4>X;9PJ(|fek)pMBUbtYU+jx~hgezpbZu$Tw75NrR`jlOrJ^=$e~=J{-m5%x z542P%rkLof-4XbvCl|A9_&Rb}O1G$OkaD^is?j)lJLwKyX0qE&{%rO;`8Na}SX|E? zA>n$Fy{+4ZkJU1Fk7c|D8&`Rhjk=X?7nFZ^;15?Bi*3N-+;x|*BWB-3f_^V_J?Dv} zxQVzQ3iIrVwCF>(X9O=@%7O?K&1%;Yc}j58AD_bTWs!9w=suI&n6NwvgwsmTTbM<* zzPxWIQL}TX&Tc-QCT24?lc^kB*2|O1S86l!YBZmzRVKC^2)2126HM|)sUFHi_-|&E z-bXm!v2%%f581L1o$kOY0RwcPGVQp+p!X=ZS2GM?HZu9<(@e$<# zCe=!8PApaH3UZzq1Bjbd>#JQZoaU=>-{#ggmP@wJ*-gx<^$#n=kbJzlnyuu=E5Qqu zT}q#C4L`XuADNkWWtX;gmA`tI*rPq-`mg1k-28mLqVySBnWPyKaiAbaSMSXXheYp7 zwqsmP%tOPk61ZSVD;g;_l0I_`w;!0OX{!18Oq#RUE0(ozOOjMZ)#-@m!6!10HO$X` z@zEk4`PdIl9#@aq5MgP*A~F4dC#{H`H*2$n*kWMsQ%E{l&W)yToGm%C_)^oN)oGi* z#?xD0&SuT*bb4+%&3RNd<;wQ{4>0B8y>}ELVti-UWHg?$mxG1P=Cn#*UO8P??^!-c zC#W;2CVl%!MK=^*Eh_1!zBGMh-Lp>>C(7=P|F6e7N%rPqWe1dM<_&GHjhe}5)|}|{ z$fBucSFvSiM(oYLN%&$zd0eNtt>pbTSpeJl&+1V+Za%hZM*UtyO}gO=c)6orziUg1 z!BRGzPE965au=Wmbl-pwxCP%Jg@y?>T|91`vMm;RF_5J<>BGVN5Hh^$y;> zP*{#>`g&@Y=TrIR2eE>|%w1mzr-YKc+LvQlkw6mC&P80z(<1CPyc%dKGTGdUfV@>l1H?_PnaU)-8V0gBn$R{uTpk7kGyZw5vDS~vJuxn|4{tL zleJtqrLE4^lskFf=9Br`cps6g247zP=7ag{TeR(ZGBX+!|5J!GY7_q2usP?i5M)C+ z{ud|mgT(}=VpB6~hACOL>2iHco#{YH{}0I%&lmIb%Xjo0+_#59?5H~FF{J9rq#c!Vn1P$Cl?rz23;-E>XA>@>AdQTF0UqX+J7wm zaqVX^x|--@e&KWbSNYYY_2;%|n%Q3S;>#yzJ~&@wweQmx1{#w9fUB8!kft(!w>cXK z9?HOncFeu*6$9dNjHaY6w0lzgGA>Mij*CE?#wEKN{e-@7r9a0ZTaMY{3h!*I$15^^ zyoVV2MZ+&~3KLc7sB!unFp{q+dW}^Z3%! z>yivQs+tRSOX_KkeMu%eY^^w-t56^N!7(KBXfzcDY=)uIQ&l+_n6Y7!D|vM!71tw6 zBbzawG-QI4>!b1Rj;@4?pzcf&F6{_cUI-zX*2c#wHCYc$T0?1Q5w6+pJPxOQYGkaW zG_5o0Ra{L)J{2~C>v@t<(q=98NcH1)RIF|0 z+KzPI8rS~Mq#6Fo^zlqauEUvB3_e9GH2Ka@LMDE?qG7WPu?ix;I$%^AZCI9TXf~Fq zY5zlwc2`@Q5|RLj5tzO-g*c*qIwUrj4!B^9NRS{+lq8)Ehod|k>1Z@M7?SDZnF@*P zvA#W&LC&-<+*QWBH0mf<2pZDdDjA^1grFJMv5_KWY7B%SePJ|v$z-yQg0U$x9N~}+ zy%EiA%->V7kIpp@?Xix8moSFHHT98PAWqHXKyx)pQjK&rm9^$qWjJCQpmhWXXD`yJ zxWb;QAzkF(J9%=(E?h!&Dl#!H%bMpTVhRQFbc)zve?H<2B~(pXH!~z4WvUGA5QRLN zekd0*y~s1kLufmI2alyxP7$F`BN6umYteZ+t3TpxG%RSRyf_nn$r>5;UO4^c8G)?#`NbghL$`I zX0;f*+~E*`cgkwTP0iap z&8LT4#*-l8b(v2|1s|j%o5+Cu+2i_PfbXy$EhoMdXU7l6Gs$0joz2uopCZTSm+K2j zA348P6he<=B1hT1SNY}TGQECwDYRrWKDD2o`uzLfWT`zrznr5xqOCdl1pjXMb3^Q@ z)7QUZz%tGPLz>q_`Q+mziDNTbnO(xl9oV55> zgPc5_j$b=^jlK_j62W6~^yw={&CM7Mf}%Myg;^Y zoW-a!j*35)YvP#*SXG6srEy-<5>|{G9 z4v(CrSi}V_Mr{myC3FtR8s~sas(0t=vZMxe5kUa^u}Iiw;ZVa%`uh ze^o&{#hlieMV)DvXsr!^6mwyqsMcxK-C%ey5o};N0#O&{T#r#W}E0C#H~Y z(5}aE@de~=_lYelSV|ZYv4DsBg=-afqwzG7I$x+s7c2W3Z9L@QKAhsi!vpXx|cpTriLy$ zDb-J|tmY#9w}M7Xq=cP3q$t$* zlPZpgmxJ_zalb<|rjoG>LQ2Hr@F4-|OkDgqky0`ts?$3G4XGDVB@`uI3g*0J2XzjO zzG+w_GLTxrt+1ecrQj;G(Fm{>73(l7=b%*^EKZeeB5{t|ckCLKB#^iT5Q!^)C(#R0 z)Sv>|wMU>~W2UgJ2{rf`{Oo%G;4+CN68CC6i)b!Kl`|=PGt#cXw-|aTPY|1m_64|7 z$;o*v;*j+UUi_l(a^WQjuH@U&;#}(ZIoeHnsl}5S zI?@fx1K5moyUW9(j_X{Lkj+X@h$+>Vis1;iM_?vLF`Ei*?Jc@)w35o&L7a=AaSq>g zMy?=b8jWuMaj8rpx^g^T4Zp%pHs0x)uIO4Fd$N6>Pai>k{=u*h)ZoQ@l1s(MC3NHtE03Y#qp z0R@aW^R|XIUp>%HB`?~`1yvg{(W^xzD{7P@ooYvSPFheo8xe=#nG_emBFH#W=hPfW ztc+Qr{CmWmBP`Ih5twt+RitimBT-`l?SQ-f>}G$v2cBKj}4a85KJ$k)(~=Pnuv%3r{3rcaUvX$xLd z+QwK|-2uHrxl5p*tnW~(Eu~sphn5rbRDoI42dJX|V-V};1|IWAmpeADL;Eh))gzI^ zuB*hG;Q7f^D>;zXl$Innuqm{Q+@f?UY&oKtE!N@W?Pz5xqp;xXXffnU;=vv?3$_xk zjGwqD@j^pXIY%>(6$ztKVsTI2 zfo+j{&)2ElOj~&3)}*ZQqVgccyan&f7EH!*dPP7!22BUHIg^|hfs;RM#i_A~2gYGt z{!Kd;S&>*Ex(me^ET!DiIJa7ei8kg*JN}5Ejv*E@!8gICporbrAY!3JoUg&Iu`Och zE^V8}8MPjOg99dy|M^e<_tqa^e4hN=0?#e*C0gKVBkw-{R(g+rtKWuiM}KHs{_d7? zml6w}yVSdso%!~5)UVg>R_?BRU;Ay!-L-4nW0zg^yVuXzJ@R(u^WE&Xw=3U$e%N-^ zZ&&+0=X-8}=N9s#ha0G818-+H-dL9^dJ4PMpI(!2xx#VlYQ;><|X0Upg@1V+kx-Cy4^?n3y9SY`q6GX)t7!CX@`D5zp@c!JIAx&4df{d{wyZasE6%h z=ST4F!uLRNUuyDjvqifXy~&H{D#fOKRq#EYoTt*!cvlosw0@573!7C*w?wq;@!MEI zc;XO-RlJ23P-vW?ffqnhNUclGNYX8~O^5I#MD7icJ6>Po6i~G5&?m!9dPmeJ z)1DSXqj+rpgv=B1lY#2zHmvWFQ0YCy8`7;B1Tk#Ddz4XPfNgf=Q(wKK)qUkNg=fLm zn))oJFP>KF5kbYc+q7ag&w13L65eSl7NYNH)FYn4k`k|~WL_~Yb)%`H0iadzqUjUO z@x_(8FUO|-ltGz>R$UpWQmQa5eXeNX-f6(2;Nb1}N(zfE^g~O%uY~_Wv|`ODOY=b+ zeIcMq|5(!8!`d>y;4|?c?;C#D9G6Nd&%#TarTWimxw4?iclq|da2Yvjr=p3xGQW(R z&;p{`uSiy&En+GvBILLS} z7~pZaws=)#=F%o{Jao=HTT(xZcTai-PpBN(+^r1PHqD52Ut!0VPdVb)2U$O@!?=TYwZ zjkb4aJvn&KhE0$6L)t#y3&eXo$kx^hH(^)q!5ov&GMA2-1`U#<3h6W25Jl~h|dk{UftNb|03V87nFb+om$rMXdAq4_0H5hCjZP=Wn#>!g|JA zZ0gmAEwBFkQyQoDwi3uX*ncn3w7iYx)EQ-?!**a{v_N?Q#t4YuF4t;W+vB|@NoNFs z(7j5C9f%&xVaY9XXmnGLSqyzxX(czwSDW+AMyMb zNuN3L&I7YjU|Epc4z436+!-w;h=SlynwJygnA98XA^g ziDzE2b#;Lqr4m02p3hQPKL2EnusoMsUCjAn<{(~N;w8@V{m~i9OHzX9O!9)r8bNA( zCKoNQ%N*2eWRxb1g77*-Kq<|k=s{HVz$lBn67>cB{Xx`4^vUuake34l*IEj*o;!5m8iV9z2{tiiS}*Cz+NHcph!)v_?Rg^WkLp5-Of0;TwPp`B0N zC@24^$QasELW-f^1+ojL6M{uw$<`I^vPY!JR}|3ex_DV~z_K$G8yH1VF)S2C;+vJq zcqd|IarOv+{EY}=Z4pDu882{FCUk69W}qvQn-&%%v`NB0lt(`R?SQfEl+zQvf=HBm`egam?Wb+A#lZkctGVmuK8|duBVgEBKwkd4~VcT%p&Yr zT+!K}@X_5BR|7CQCS#qTT8=}!5*&?lOSjr*;Xt%LhhyJE9y&vaa*f^y#+&sPRmg_0 zvhcXtlpBc;!UY0gN*bymH-gKcoHW#f8>TR*OXU*SA~GT zN}O-1a3lFv`k4C+gR56)O78)xC+(w!SOU92JIp^%xHqm(Q0X$F(HkWKi*vwK2^Jhr z1B(QYpqxU?mjQNHNZ7n()7INaYvjxs|AEF>p#_~F;)O55HWp5-%{huvU7L)Fc5u6m z%8c4cqaNitw`JS?d=;jPa=BhRcaa*gjd9BSS>mNfrX%jX=}WO51GXgxdmDr&8#^e! z2T<(_HR|A-PGO<21%1lVnef_>*GQyqprh$Fdh6_gN6W-<4H0>=_I{nV!L}E>Yx*@} z*H{rz0>7r+HuDW}GZ<-tqUvay(v7|nE6r0b65GURyKS@S4KXmiuFrkuuxsYUHFm4@ zuW98{5(~@@I<2TrRYv2Dfh^KJf-qbM1+#7JH#noXhEPW{u4nk_4FB)D$%BYw-e zU4>SWuM-e_1_MhSC|1IoIz)pTM@LDKDZtCMtDxNS;xMeBRL%+_UPDHr}G?js8c zN>MzNTy%{E=`L)UH`%(fZOeCm!)#N3*Jo}n&^}5T-zrM6y_NX+G}2WRrgJEU=cfVP z!_>F|9MCEdFCnWa z!HWa0g;lr`V5#2~n)| z@G@bQ@41W5@@NlhbMrW9GEHbxo*Sok<;|H*=SAXTV$?*^@U2P)6~(-u^AkUp#bwlX z9=)Z>AIm3r#BrXCx&3LrLW}4|vvlJ5;u4n!niXM=o1yY}ouwxt$;|4fnjzCylI28Z zA%9<#oxewT3zNm$%~ADMwL1UH%1&^u1H-IeWm&xQ3t)$ge%ygKN4CB-wI*bDP-oy$*buGj>J5A*4p=9Gu%clccN zEs*)aVzsntYI{Ck%wnIV!k6DSkbp{ptC2={fzo4TKgg)(x=9t=uj z^mi056tRuWdkh-eE>uS3&G@P<&8iD(x3B$^Q8Tg;!dU-9Kgpv?zNKF72FQ+~s;WN4 zfG1JZteK~aW{PlgUCW#bKQc^mq%u(oQac$?j}J_hJs|Y4>W3x+J)tL4c9?JBQnB*Y zxp^$5Sp)IcR8AV02t}(l0s*#B@cxWHf zgG_YZ=O#$rsoqul0irS29#tD&?$-_5`;ya8FJg9LbhCSRu3_(_y7 z5!6{yW*C}9*onM+q=Wc^m}32{_{|2TC$g4e%L?0=SFDGxK;yae2(6kbGoB~%Zrlpd zb+ZipgNw9Zy3`6EIhn1J#K_QA_S$RStK?Xh1DRLnN#}35 zU+(jz^m4g)d-}qaFYSNRA1>ds$%!mKJhRX@cJ@)FZuaNKjD5Lu^E@>du^%|5KX!`N zDpwHbl9o=457E#3N~#$S7;QyUR0l^3QWs3vi}&f{6^;7JWTA`mnf8BH$;%5`@Rk06 zChotyjz`A>#;Bw-Ijb7_68=BzUovaY7qV`a{U7ro{OW48Ha|_3yzisGeqYl*-)^pF zSAR|67g@wD?)B$6(I)6ML0q1{EhuRO(F@>-0MHVa08~*}WhCb(UXq4nuZ`;IbQE)O z_!po`TyaJvi)0L9Rc0_ruaYW>W)lh;j4mqAD)#4=iN{t(JcpQ8^p`dWQ`HoG2;NH0 zRL)}e(3tCDe44IQ$c?hoa>>3}@(|$h8z<~hSMty3DM{OxN&Ymy8+xLk2;Q=o0eRM< z)#&ij45fPZlDINx;5p9p@F+})c|C5)F|6FjLP_cEv%&II#y?`~Lszn9M)=XY`RMfG z0A`~TP(_hJ;OerfWXeW63NmrAIg}YPCU_-#PfVgRaRNL`72|LPn^riD!w#b{7eTH$ za$HGX3$uHva5f!YRKQ5yjeHsRbVDvcD91R=^=N2y--&9*4_KWjI}(dmKhDiC7ha9Z z7=%uPTt??Csyssw!l_5wm<+R7OzAqzLpeBm3|ft>8V)6#j19>@JUy&l8yYJd8Gh#& z6Y2tjuN#KmtoVmkY-L>V?1JobTQIiYu$ zc&KFavmvweSVqQmw1@F=*RIgJd(vMM#UN@u1NsfsCa3Ws!k z8L?^xaqt-9m<DR3agh#2#b6M+H4My9p#(=f4L+Cp^k%U=`nKa%z9Ag3m$ zOBMoTY}U(0mlL^6mv(e?c{I@E4T_&1HHj_LaXO5f{7>tpU5c;mb;`pBmvB9qH+AO4 zxeK2AiqPS>uzVu&8u~CEmZ6F9YgvL4Dm-oqMPqvvcc@OWjlM?dc&ioa_)l3q;X&=A zk8q&nM_wfvd-79ZUF8TkdUryZg6|&s7?8K0`Ax1Cs2>{^}4={i*;N_YjH9g3Zs@*;*MEk zQ_?7bHo>Ch+}X)``@$II81$@zCA z{gdwv>I)^Qyl#T2@E7XqG^q0gycSA}Uh@W3XeRLhIqW3NGAhMNFGM&2Id`q_up=)=59hKo2vLkS~>5$BdZAss<@f@k%(yl$bxIj0MhJ{y=VFSI;UNxmVKmnU>tuwmRMvvQ)TMO{Bo>{5+-X_L z%S4oeupJco3Y#Jbia(*VM#*WbN@0j>*MRoSOkz38MgzM}LG~^DHoYU0tMt5EOrVLm z37OH_WrW>k(T;W7C1T-RKnt%ETkxhSH#T7jxIC;3Adg1nozq;#Rg_WwXhC#L^y8yY zKeA}>6O=Mkti+k$OUEc_VWLWyp`FT(Yu~rY#wudelI7&1{qJwl0^Nt-WVS()#V#FPJCmfJNvNAaZXvpZmw}_Bl4q+bI z{H11a(sdgZRk z>@N6S(rtvaE!(hd&h*O;GiMxTxFT-GGSL`M!cGupDig{FC$Uar ztfn#kN>}$BtFaQRu+=DdEACZhtBc_b7#CwK5+E2Jb> zE<3Dzsjy1rGpGSt%2&<`b4B)e(JjS9_Y&|=n{HSvx^;x-y_1B=m^EGe%3&?4coU9n%K zm65568XaMrs9)%3Gb^=dyv!N~P0>-}J)rDbtyryeJ=U*VTgh8WPNk6}LKRb-uc4B4 zq9PXbKomT0Qhjrd)A|;EgNEHU^}Hck5f>tXE-dI1c$e0th7>D*>?lX|Q88%eQEw?; z(8}as{FGtTfE~P1grV}=dmF46qh#yKu|f~?8GKzwDJ1%k3#9}@%#5Yn=w#`BJ_Yw`h==$g%Q+RB)Y#@-yHbQ{` z#!;|N(;x+~dtT1&F;Q(T+zrSmz(SwIT%~cx_5XFYVmj$^(f3R4P{Lr3S{j0!~z=U|rK36{3jq7gd-DHUPMcS>vZg9}<|AusfZ7O#|co6G!eUR-r!*dHf zx4>7}0{8jB+R@+G-i~}sTz5;kONj~YF7+-&dhPFr?`u2OcUS%Pe7Ab+>^JSV@pE>M zo&TuI{R$7s=c+xoz;g>cx4?4?Jh#9fg#{MBeJx@u^k4`7W$?AT@ZtAM^54pzJgiyr zul=pO@(^EUR{(kY`T!%FZ_RKAJ~jXxzjF`Dqg>hB!4Dh$ z!IyU6E9LUk_vwU6$|-^D7uOM8M6HNECRUfR=;8b@EZifu561*3tV0kO?qz`{Jc!hy6=XrEV< z%A>KOK_?(|Ddy(g(&(()4wiU|X7P$>6?un&q_l!1ekhR5uXTzf9@VLZ#)a3YZ~VhN zP>7|gA}APAJm5G~5I881!JWluZDN3zUv*9i@@&)k)}^uZi6;-GM=Y-~de)_Alm_%m zNbo5oMPWzYZmmLp|YAo0pmI2Or;24mUr*bj!H~J$;iYr zV4gsdbFn7Yiz@KYDCoaau-`yBZ}{;>Cc4_o{66mAMfEUN9y_v9%{mcRBvmh-X-@SQ zp?^DQGPUJ3URZ}$m!-`8zQuE_N+Vkb-Wh%yz2{tGKp^BLZd?7V!SS0Xz;gPhI_-=hT1)qyO-rIaZsE5qL@PKi|Bo! z!Tx8VLDaJTY(vxj^s1U3qBb8prBVDmGCIer&ko}&^<>Vg2DF=cZWz$Z;%AR`W~lw@ z6(m>m&M_YMTrM-R)7>TUdH<;NUOq#hf!z4EEl<1t+_Lz% zDmAfmU>z;K&1(K`8q}8&aH-Mx_xIa)zzgi7=}ED-Hg@HO_GdB`FEn!er$TC9LBB3_ zkf-B9vn12oHf+`e=f?N$jZMY}%7gxcsx>>{ zy?c|_Fm653=qN2A5N&ZdmS0KFsB^VONPkUoHj=U>brBL|O*FNFm$o%#t2~$u!zUFA zwCiyZ^2)r(RUoj$w{!fKv*4jDnhC0jJPLVCB5U5(=#9aOfWD>5OBwKabc2a7dXA;n z21}^M_X0?3`SiOtFR!SiP_EYtyQsg>;zcT)iLIyWe86Hn&F9u+TT|4LX{kp`SIZG# z4JDxW_vh(AxXVgTxzTTpWHP3-=5yS`)=&But#Qd|{k#24NsI-*pe8WmH|@WUd+niH z%tU^Oe>z(QynFID?X($ltQsm~kzJtjzxFNdgVOYLYfz+t{1OFj#}@B7> zfrTJtC5Xa>pzX~gFKN6b>DhY+4Y+yGVCf&OQ8M&95F}(7^O=Wj`)5#uV(OKnP*jA+2G9J`vR)E8j1bro-LGPQVdaY8-&*_cXKSU3kqfR-?V z&4RZd_*~K^$s@V}YQGFLg%Z(*3`=N%#{es!ghiok;1T`UDd@Apu;D8>&DNdC{b}eK zGkO`XNCvpZY#=s~qAZb7oTd(@5flk#*yWNS9}>uSkWuTJopA)OrfDViBcc{H_P?wuQHnFZO#wTrC@nz%2(iWbz$|)W zLluxq>N4kCyUh(#) z^;n=qQ*A&c?<=?&0sVZO(}Ll+Pj!+yqAnxBzyd6kEkVQ>GFK>;Uy8byB1@noT}e6? z`+p0W?&O%o%fip;QnJ{G1tTINu=4ptL>FB8rLDt0fkh@*N;DNyMf6OP3Tam1=A|pQ zh(c`0^F5aujQk)gmx4+ffK(xm1_De=82vZu^b2BpmATMBtR_og!HhKzWxoQciizW1 zHN!7?89`woXl2BZPJGWQ)pv}9UZkF>^C_1HUrSt#x^XVhGHdKHy+~f9KX)g!qbu4_ z(q7b;)pD51(b&CmSzS4z0Gcr>Q-X+cXcbcphS+mDjZ0~=WUzeIpxo2tW>G16A1W?z zxhTdx1uxdBR7t6tG7zhn5!ngQs9)U0`(PpaMm@htmD2el8WwVZMW7fCt9szC#C(de zgN9^{#?xp`i?O!cv}RnqkoSw=3~Nlu`Nz!vH$M3tt3>g}+?Pa179pcWJ>v8n;pe?kf9fQP|WgHx@(L=oQJ4T`H_- zDi%f3d&W^hV3ccCUGa8qDN(6S^dau!S~ALl8z@`YS@BO-RnEtK3BAxQK75qq{!_Fb z%OZ;|nMzt}OyQ_@MY0gFQoH0JJ4$9wLFEQy+n1z$7lkq%VJ2;(D4Y!o%8jPm_xmc_S}4VG$AQ5bUv zLHUj}vz3RsQ3g7Xq3$iH!k!nyb|$7or zk*{syGH+Ce2m;66>O?x%3xf+FZv{C_MO&E9e_ z9x|q-Wx`@$t`Ik$ICea-KLcDO{`Ow_(qMl=G_+L*yx@C|fKk?BcjBU*w@ zC4(j3@U4o}V7dXjLBBFs+=*;zU?5!u3eBbRt`TfQmQAC5U^44rsPbAKg-J55}$;xAnN;*yN2=|MU# z%zLxHu;#?IAI*S28?H_0Yx z8VjKg=4|mGW^NntlzUji z!`kMoe~v=vO#1W2erTX3iVW_|!C?MbQe(ZvtpPiMXo;JQh{zO4EY5<9rJ2H#vPW$1 z6ByW#TZpJTMb7FID&^DTk}vX-B|kFxU>;T+6`hdKSd~p#GT9y_v#pF~#A=!2^yLwp z=0-iy!_4|P8tN}`J~BB-NhatrM>jPScK3qQy2VIES#m{v;~7z)5!jLsJWG6OQlVYY z_#4a&1XYR@K3$UwWOH|m5}6;hAd4zaNZd92AvwP9e8~oGM%aMotSqrdWZ^4& zk7cG|MYa}bp@03>p4iz{zdqB`cdEC~>-_GhI;}r&n_xBEoUcx@$U}l+csbB!wwV1QyhHre4|P>f7km#j70jL%Haus?cCxC3nqIwt z7aW;N&OcT*bB<0c7U{C2rDjL-xPzB>rTG_&cUU6Mj0O{H-my97g^m0~7BjOsQYTYu zgfTS#fi4C`rKbgCMQ#2;+`*i<{y3_{ipIF*#h+WD#sX(yT)X`Y|5q|Q$7jgp`amVE zB}sf|nyU4s=OOoz$*Xvk;h^3llh%0b!ov;Yw=0Cg_@87fZsCAShS5wECGz39S9(wl|yQ zMV)D!rn-u|l8XzievxvW2ekYi7MsE>2h18nmk(F(k=ZJF=LhGB&5g_~@hT06MON?D zudanjhN7#t77(jFuyDtQ7O8nrmTWRkEJZp~i2QQ!Az!KcDu0M?6Bj=S*HA*&SPU!9 ze7t(jL$cMm$hY49WjcRr{V4l7zrB>j2QzH+uj-ts@D;z*;8I<=W^<~fPG0(=Jbrw6 z5DLWB=8PVW8StetT8URxU(QryRqk{?`Ib~4-~eX@Co=uXD zY%oYQA|H($I?|P=sqaCpW-nK^CwmLY6*JtPMQXKIonWP(JNo={%UXFlTh-<`A3_h_ z8QZ&PCQE;xaj5dRvLpNVn(cB$H9ojVCb51e3oySzP_RyMp&!N6J$elc6{ zWi(Usix*KkgMA|Oh80RNf$JI^YIby@hjGOJEznzdhnjI#6kl^{!8EcU2~b(fkb!T` zSi&fEJrA;E$ytUKkIL*7uu)*sbE$NMDAf_=H zAB!^NLnu6>RW(B`CY4b&H0Bf=d5;gjGl?Ue$=JR#%ICBpst1^i;1);~4~v6uJbQbt z7cR79RxIwpJc6L^pP5-Z|3!LfG-9LX zY{=AdHf2tD%zQlic2(ozF*UeSp@U;HW?sd1w2=!i9Z!xAqF8#Lj+nU=L~u|NK!FL!KY6G=G~aa@j$L z+Es>3P4#M7q3-(pC2{-=j)!WZtTEz`xh>1r&#=E$COmF=jm#|=b4fNEp8w}2>1?Vf zn+1MadTeeuS2Q+;r}T7_vv-r!Jp5PdO;J53l+GEqaH4FnkfJ^}&>5y(1 zkVGac7=3kd$o}hh&%}O}rytql=_z?B^(8%NagGLGh@vA6#UxkrDLsJAqaodHCbQ{? zE3DvG10-YCEe(fS`bSp(?g_Tp`s?4{rI%tx<>RRi#{*=qoF?{pzY<9_$G3OB|A)Z!!9LlK-MD@}?VuMwQ zQ{pGMUu&EvP~ZP1WszBNQg#`-L~5|abjySH3T(}IIi+N+1ZAX;H3zOon&dsMjITwV z6Hj&$l2~IlOJ6DLvUvYteS|bFW|tSgrpEpu%M2gOV^5C96`y3B?c`cr$76xipodd< zI=^H@b8moRAF|cQ2%`@4*Hw;v!kps5UsicxFsa^KH7BU5Lvso<}&uj zQeidR?)hpCy*?=qgbl_0=yDzf<&*r=o~*_gEc?+n&ug5UQP4@kv)h>R{~FD!X7cs% ziTNjZfYak7`9F%k`c7KPyp@Bt-zrhD1clFH zoz|om=#yB*^FU~QUXep2&A+sx`qKL;Y}9<`&6%7Y^{F5Po&z7@0;0hSM00xDd>^Uaj8ml12yEO2 zpxVyRG5gc_qb&fxmI+d51epYj)Bx8AO{(q`VcE_MW{rq+1z*C((sc`z>)_Fm z={Pr8puu?!7Fecs>4FIboWlie$>J^OMqg-Kut0QckTSwCWJSM^ggUZBCSn!G6W}Jk zg3^ZNgCk&Cu*lt2vyR5I3M#%VDG3(pEwbQ<+a{4;a~ukl&4__>4;klWERz7Ka!xQ# zq83q7_Yd(JT$q{RWJW09MR3@UH9U%NlcKFglG~Izxs!Csb1n)_^`SL3VnWMj-#dgu z?b6BDz`{K#zAZ7ha)~5b#A0ElYFU-(5935DZua4P%MrY1!Ji479GnVtQ_(hNkycZy z4cHcmdT9J_(<%@zw9=?szRg*6Q*q*T?-3EDZA0h=o9ai$&s+ zh~=75M+t=@b17RvgVRg(A$jW#89tJR3RisQAL<_ zBB>Dc*k}k0<_@3%N>0M-wg->=%p05$iD=#Q4Eoasi*uKwN(-nFr}Tn#Wk*Rk>C9u; z#>&nG;*OxvRI2bDjp&UU;%jH-?}>qiMv8`+2p9U$Hx&(tb^j47s4Hwd2qec57*7i6 z{EUuBCZM_e_PPv&XR%p6@)2xw97QmYs3~-(Vi8vCARe zz``e>kQ^_Lz~WJN_ynjTDE-B~Op00v>hWA3JfbQjb)1n{XmREP6zw7@h(j6HYXuU>*z!RF1k~s zbjNM1q#2=YMlM*?lG{AOE{ApUUWILA0O$oXc^$3-uLiG_p+NuJ@CC)5lp~VLS8Qac%^D^& zGiHSjBK9Xr687u#h$@7f5@1QMSMb!;x@2GsT!Y5hKH zcI0Cba<`Pb6xmzs#@B2AIQaJbo_g%sckZ*_j{e$qwcp;3^6st2Z=v7Lcx4>^^fyJF{_uP=);dz2EY{S-v`@`_K;opUWad&c8lG&ukBFowIRO*aggl(P+h(6pw`*+PGjSLsHPHj&Ex}a^NH?>ItN}!hr{VYCK}`LX}y;;`c-Y;%VsF zCY2L9h$t^omfVHocNAp1BY1R&a)-cg)51ko){aMqrOGKyQJh-0T=wQ90ew7$2_JRU zc=oEAnK(4~e#TQ|-rLx(rsU-P%Im(gwcWQ4feI+x!wNvFsA~g7#+|k2#KNYB?SSm*{0CEnb%E^C83t zIjR1~X{%|%8`cGU0aN+68dCINs@0aEqgi*D+u9z&xR zHxYMG^cbA_{-#I58HlPoAh{nKUlO#jlOUIbN2#LuSpZf!`gY1#zhpm!3P9ia)L6T zxu<)bHbXUpg@Q0Er>^HQ`k_RSJylep{*}j6>rfw|e8^}?WtD^gBL(JiihIS5&*OT7 zWFuEEau5W8ROWv7Op*tIpylfnu2uO%lO=X*s)L_eE2-~t#5alS5Yu*ghm42e|7Y+0 zeq%e1JkQ8vl6%PEHV$dZpalb)ER{U8*SjcrJb*Chhp19rfxhDbO4{p&W-t#W!_!dr zQ_p{pMNtOZ@B@3GUAPzfP`Z0}pqYoo{t3sPUci6G{we$U<~hY5y1cq{x5tvFZ;&T5 zGBPqUGV;gC^DBz?Qf#udZ9ncpnQSfgZ2d;r3ybKyo`(Hwjiow9p0DP?hTL6X!*8!VS8^)?l0GF-LF|OJKO(w-PzW5 zJDKeLa?$N=A*$Ir%$h7uIH_f}aZZ321?ehi8dUWJzTt#&3 zwsS`ki<7lR@yj*l@S018eE_yKN8VQH-stw`>-{!3MvtL{vi-4B_NdU2hhVk6TV?%5 z7tgva+j`Qab^0$Qm93_O?*xuoFYy<8)hjoFhESMm`*BYPr=oQD1^ zg2jcMz|o%sTv)Q`L{`v>bte^sGQV6>jIuz{e=_To=#Y{+`v#akCt25DRfX>L#T(DB zv1)ZOM)$Rf@lj-6Yb^3f7{OUA@IDNh%3C^gd{ZT!7&^VrS{jZrNp)VJQ9Y&_g!S_I z-BC<}4Pe<)pj;tnUo=P1mygNxo@R%Vxe6ou8Z?^$SaMIB5Ou2T20{Sma6)y!ir4ni zyfCg@wD(l|FO_*#z&>F;vAO0=w(sfdkGNn>Aa_OPUadxKdiAfi$YW}MoWuLhIPj8T zbRA&Zwb5b==V}pOh;le%W9XS&x`1(Th==Kq=JdOA8TP;?!8GG^8pD-O+U3sEp z{pd*%83Y5A8uy_xmIOPl(XDwMlpC^{+ij5K{Zh^gW0dnS#+xs1V?#*Ibbr#L8T&^h!{eg~8`w(ZP}YEzQVcJE$wl-+_ydux}eC;i{u1UE{aw zn@}7EpqM_81PKaaM%WfFdpd~=j>_yQP_pc%!tkaQ!OjW_kXhLM4fTlkp->9-i8;oC zLaFSu0l!m7LmVTIj3OSuId;^mOtU#(9!po+p(a;Y2|0H)%eHFZjChzu--p;ckPB%j zP_n-Ce3gbb_h|wy0QF4Hs7=x5OK(e2RDWa~v;*{VUbw<0WBQ z_V13X#$ZsYk^1@(zcf}u-s&yU?V`Y<#ivev_3Z$E?Uv)8dUVbq(NlD!WD|G|pATx$ z{5<^+K`E-FwVf->Vwr<01cth>YN{G%25R3v7Bs!4AGt)nf;C)`IHzy{LIUh#R>&3 zJ^m26X3kM9M~_n{y~HJXsvS(4b0dD<8Vbh5$DW!>>d2}=D)xQMNbA#Kq25E=&6-5L z%v76=SuiLX&=Zz-P}a7NI|g9^#YpJqV0=_iS-x-ksZ$MpF|kwnZU4;3VCh5X1m;{+ zIX5ek^iGy9=#B~fCdnx%D4FnikO(R9)j_}gEYiQimBQz*@+anA^R3jVD&0?oo_s3| zw{Xyn1@5yzM={44?=A>WH zyi69IQtJf;%bJk{6`J7JnT4BiGQ*wb4sGi?QLhc(7p~l(olMb*b2#;86Gc#E?FcIh zd=Pg>P*#qhHX&De%T1$e#@zs!*F*TKmfCl50eEb6QU=4sgi?;?2ls+ za8RUvnP!E=j9iY)3nQZ!AA(yg?8??(zX7~$B0AT z-r;oNCzvsBm&-?He-_KiAHAE>6L?V7&qh48IzOA?NosCyvZs6$EKJh^pV7&hC$HO; zFV7CDYlC9*H{0#=*GtCB*OLCwMRfd&g6pr~vpp)D&)W7!mVR#WFBwyAWqL8S__sfs zA#(ngHf@)|r@2|2*}|4-i~;d)6z2GDo~b)OGzihool8W9!Q(u0T~%M$cjQn0qQMUb zO8ZBb@5f)o*Z1bUjAJ`i&aYbkMJ(84p2j=wwqE~~?}%9t@=3bR$n2Ziv%;&Z|E3(W&1}w(!n;7F|X2nUPIDx)63y#fS3>kBfOZ{Ad zf#vMeaAqPO%-WU4CB#y`V;3d8&+UcFXSfG5FQqigc~og%7ka%gyuNucH=f`ud}Yf^ z360Jbep8lQ2Gfdi5!cJ+WINdVpW$`o!)%N-=3Si;>E|NWE?{Dx|C77i~Pg^{P z7*6c5EtO4Pv{H@=qaGFVGYIE7bFZ&tBV}7Q= znD{~&W5q-rd!J&x{1^)tu9Du{`8OFWoHgf;iCwg8RF(>Ns|w;9Zz9e~#zqrXKj-F7 zQs2C$PK1)uMY*6wvFz^s$671K4ZqT|(VTC~U(A&kH4PK}J08o>h4T~pDOYj0eF=U( z4tSizC3X3ged?FY8vJCJsXdNMT5f9}E$p*G;WLXqJ6S@@A-A?ZIk$6bpI+&DJpXTW zMq%YTPgi!17pn2U&f{IXWV!gxle|3gIG-)Qb2QiIzJKX)JV$_SpU@KK4D;$WF5T1< zr$1{Ro%@n!a{30?@OB50uCi20TrO9}dWO%bM$MLXPb`1)V3)g=$kJ?E<4C3#)HC3l}OULLcWAl~~b#o0sNAe&hAXmi9e z3R>u$QnS2yD(Qvan>*`W7L=T~a;9?fN2A0Iuu~R*QGSw}u;(+z|3x^>&F96B+M~w2 zJ%i62gHgcGJKBf-YQZeeC8aoPM2>CgM$fFJ$rp^`a-J>HjqC9hjni=e;>ys1uAryve0rTZ}qPsbeeuz=fFR7t0 z(cc;Bc&NBgGP7{HYmj80=TkfTes1#VJSPAC_kA{_tK6RcVDehKb-vf8d3hhxqK2up z@duQWhGPi(#5v`Bv3|;V<2Y`=6VH#}*?;`cp3NMi{Km#dxoD2+9?OU^koVmGh2hc+ zTI3He7f6L;m27JqyEjIZd*AcPcqH;{#=an?qBjd<2*Gwvqtm=E@2011KI8!n(*IP3 z$kMUx@}f{!3l4H;r#Z$SdRAq8j6cS9k-FP>n7(JL|HbxKmZC>HZt^)yA!~AUaU>>n zN4a2fVbBTgc$yrG=f!$Nqa*fzyVxU?*r)H%IzwSdVQ%mJBC?K_43!z6Op7%Xp3Oxd z8k@OiX+Bvd~ z82W(OeKgzYtDYtzZd!dr_c-=Ag8Z0tak~P5gDi0{?Yx);MUxO&oJ8 z|KMbT%dqebMi5W4!s{J^3Z5L|Ia1m{wc+^E4iKoeu-clPpdon1%}Q8N!Es@K9@bmO z_J6_O7{8l|%dps#?Ix`2$mZn4o!Zf5`tfOVN^@}&wrD?p%U%mVcsm@l$CtE%OL?5k zeY?d|*l~yZns$McGS*m5tHGk+aU-f3&SjAs`?y=!TOXiME^p5*n}@eij%yU-t}a#ymkAkR^_DY< z*!x%xv}DnAYx>{=Ms8(eJBCcG9En=SJzYgLn7Uza&`#|H?lcMDNJAw>xaq^#Z`1uW zZ=p7}?HYq4-f-U5+M?K6x&ma?`2HYOG9Ba~t|j*th=wv72$e~x%vzA+hE81Pj?zWJ zEx69Ors?9pT&JE#b}jLDyI%3I7;I?jD{AZ|>lEQ6Qz7UvA%%aAs+U)c1jU>P@EUUB z9$J@`Nd*C6;9BWyOjI~B#{jqQN{9z8pj0+vRC+F?yLwy>m=k{in5Iy|H8lzIQbUV1 z7QTVpBO6Ob^VnM>_VsW0`q+v3US#5GLiOb|yGa0C%U4=GYm-*Kb5t1H4sof*Wh_e3 z3trHGCUw~iV8dP@Nne5Hje!R8G7n>j0vV>lVTnYA-K^rikx?uU#d7Ist^z(3+bE{e zUKsXO2Eng5%DCqm1Z=W~xZF+WO%sbn9_@)pU!ZU!HEgXW}6!Z}T6g*u!7y=58y684#vGIq$klr zI;j!%!!S8z{%Z!C&R$%Dh%6p8?E)SOa!q4_o8)k^>-@D^3O%PYSUB%z(xpwD4<(8X zs`5Dm>#7r4>2$h*>xqGsGpZ9a&dYPX52Igwv``??TTT=+fomSBrZqFNSjtz^97tB+ zhNP-dcL>w^bPF;>t=iorBC6qIOT6zQX zD#Uvc@*cS6&N!Qf8;**(A5|sq7QSIpC4Q46F{BtwSrqA!x5!f;|E&LZj(r;w{B zR3Z$D+?4ZW=7uiz#0u!ReK>7MrBdnrqeIQ<=s;^B&t|)>#><(hj$nhC(p* zqu-FkDv+U9wJJv~hnxLcawt&?YiIKXK$6U&Ka_k9SaLSt8$_&#t3N1oO#^`p+^IrV z`f|_~*@l?DEBSl~XtTKOJ7V)yW|s6J19o}$I~dFt~N+gU!0Z>xJ4-|t)A zpFB{%hw|-|d)o0;jk(u`@Cms5zrB=?>-!FQ|K!W1@pzm&YY*}xM!gT= z)8#nzzO=o(j^LvQ`2E5z79ZfpZeM)=^5ylu%pU)>@@a4P5I=16TNyoIygXFT5%TsP zV84gT`zrY2U;V>teaHB|_k!Rha3Vf<{3U$TLDb9m{uOdY9GTcOh+9`AAJkyC}Vp@p-XJH&m~ec?;Tr*0>|7^v-ecu2iNDO_~v6S>eQ z)3Wpk@00KfTZL;{pL}76CVdIsj^uUH{+78HXi`V_r0=5d^a)4QZGRJIg^=O3=nC(TcrqV zW_iq@ptdIFPld32&Fq);(YNaDbT z%5)j?nl+xLc%^?cO7v@)7rdXtW*bjyn|EDqO1>By#+r=2tG5?0L)zuLsRH4EAGvoh z>Q(Z;ZQ$i5>v+*RtSy)Qj^Q?4vm}vJz$PjdL>|T-eR(?*x_$%t9!?{EN@eK!s+Ml4EJ6($s{uiWV;{)G(fjh+t$SN zLwVsFg>zjgp=-Wh5PMPFwk{X=^Rn`|6+Im5v=gSHriRp@NLIJ8NMd4Eq%utJNJ$kP`1{4AFEJTB(EcQ*5Pj~lsCGqA9q`m zaN2S0=f0JOY=3KtiD%+4osGn{i!2sDrRQ>EhzT1*qViJ zR&bO^#ycF1>h1Yd0?Gz5KVS|adSLM#h*QOL1;25s8BYjo5=(d!7G4ZuhP_5+VkDTI z4()OFlBl+pO0>f5zgWz|OrL(R8as{PRhfx>gO?aXD*F~E6Ebqicnl;rsj>tGrc6LZ zs?8Uv=q1Zc?w+dLE@Y@R*^1g!v8f%pT_R)hxjqmQ-S&e-d_~YnKYB~=QAH!zmNB@@ zepFHk6SC@TGFm>dc_De3`D`I~jD#5}z8x`Mais;@{i`U@dhj708kdLU5UJ&L=!FcH zia%OVd-QN#NIS<+amDTl!acMMes+o=IG+u^V}Tz3j3LauyUthBbZKly%P07EOe*w)HI=~=6cdcB246VtARpo(HX z$S)CZmd3&tf>a+BkS#6F+vquzD4(hf3dT{xo035+e0EyuEPzw2fDeH)sojlsKw&5n z(7ev9z{$CH5?U{XT7&P`k{4vu;`I!WGKrWZfH{@Ar8+SRgBP3ZTomhg4V50rjz6hM z8$F!C600kzSs~{Jx*m-~e3Kz8q@sumA<4JMpjcunY^j>6hKZ~f0sQ}MK>YxQv(fGq zZ*?QKQYgj=w&QD#39m$x$R^uO)v zl02Csk9#9}zZ}RMsfJ1kvVvAG5gQXL72X+5ZU1eQ&OK>4(O7RoW~W{I@zmn^BwcBE z(Y={sb%GH?=qEQ@;f|ri36M&4anftH!>9;#_Qy8!O;CniUo`A`p+vi6_#L*gkuqc( z+=Zb*C+sw5r$o%nF3H{m(vLw^4U2=`AS~nJP#UA3Dy?sc5`T42n~rPtB_^)x3OWT$ z9M8C6rC)F6C!C$&oPgCPv#ixmD~cMIX>rKdfIJ#qXO++jNM82Xf$djA^r=29MEkRh zWUwWlQmQ9N?kY$VWvI4)7 z-vd}2I~D7a6~)!MoBQ0A@Q))X8Y2Wcr?GMs>{|C)!@#=f0I>i!1h46vAl{&NFz-`k zL%imjh@$%fTo2H*z2q(N)scG5C$9SFoV;8JUI(*k&0j_{;0FaN2WJ!0yl zRNkA>+{UWLnDXjyT2@!Nu@jFfK)dij7N*XHShTyX1Dr3Lc*_%^B4zxT(w)WsIO$$s)ue zf3Dy|xBt-CVda5o5v`QZD9_w&%Tf5bSOM;_5LO{2aKZOpl@!V2!ZhrD^ey~~I5)gU zqYn)gR{XA3IxUW8s&Kl5_sSQ+_AW0GWHviLf4U~#!6WzO_mIrsqwhXXxcqS~3UOWh zN9%mH(!}vpE@75?d}Yq&Jif7vSCh=i^YN00^`nz=Uf&epm7F&}wRJv0FT4DvUCn+r zD($&$&(Ojr;VP$9y{tSrEKg4@JG$D>&lpR{S}gz88~f>=Aw09e%?#|1BIwxG>VpVH zE7E%0u68V^)_#%y25VW)pV@eM`t)zY6BdA!n*aE}XDiHyT-I$^on5T#iF~+RU1f{Q z%d6vf(v-{f@>ltjgHNy4w6~3)(H&Y|m*FqkMGC>}JNBMml{So+6x3@rE^$;=;k%2n zb8=)S>-4v456J!2GkgkKI?!|WHD*j7!pn{CY~RUgeEf{oeQG1a#u~U;ZM~>SG427m z*_*b54PAYZ8A*l6?R;soL zD`djhqc!ZWjEqT`7G;vNK3FXbE=P`ByK_5X-TYRS z$2DmvIvasrKpDS5`8qP^)`#etjlJFx-9-3Z7X~@4%;&Z#Od7g zX_MVErfA2uXRo8rNxcg66lFv2ns#)Kl+;lV?%&}ZTTC!@&O#4=9HejF!xHisLxYqRml-i3k>8(2M@Is0`?C^)&u$kGB{O7}b zq!XnZPkq*DBx^t`89uwflxr-(Z$a?F#a52cs0c$4y6|j^v3ag!0t%XSE`)q9ndMVA zhpjkR5jIjD;D|tgMi|j~7R7RjN)FKHZBjK3{1ikkzR77PLvB%Nv%tY6@d5YPg|Y=G z;Q#~qoOQi9W(LFO=;3KviXG7YHV5X*%9~KSVrRuxwpzi}u9}W}U5hDVf`s9)3!z}G zW$SFs=$2IjDdM-dvuUBIk=7pYAKG8*yLP4o=R;-&#eiP%{)cYfyJ(wB^-C{@;$amI zaLO{IjW!aD0FRv~j5q3VFDX#r^M? z;HvIqTH2>5l^J1|{3=FasD8*R()$`yGwE7p9xAMn!FPT133e#5ag9kTfKL5FvW_tR{>LB9voxO102*HAFs;! z0b&n2+Ietz&<4`SM--v;c(Q2^4!TcDxWrb+AGAM&#vSO%=d=?&57unGaU0jH3eN>Q zLz2BUAscgWL09w^%`aEF#mz6j1Jl=(~{)6*9*tm>rTmFrR2y$A;`YK~X@I^c?{s)usg*%ij0@|a(&lEQ$h zcy_SDQGt~;8HT8HvBnfDHA}&&$K292Nx4;Ytqy!%vr>kBOL0y~q|a;K5ES2}N<}Df zO&M}BFeOj7%QAX9N(BK)(bWyGWf^uu~VHceh9adqt zfJ%CBMOk*cLKR|8p!IQq)q#&LH>^S9G$JuWqXbaH#3nD>yGlC;jhYIltP03K%~n-8 z-x?g`X75>ORolQfr0lxFjMNI0rdnhrW)j=nDoxS_G>u_C1Iuq%5Z`c1E*7vV%t87x z+K={CsX*ZnN2thwQg2m3Sv>!y<{uHhGgVXzwGsgb(%kQCw1f%lZM$+(~k+23W-sSr>V z5&r^&?DSZr_G<9PQ9mM-Lo@3er0u69LaKMb8ci%V^h3!)tfL1`eqn=iv6qG45l5vN z>Xm)F&dGYq6qdpv`{!y{mBOeufTk5T@sRA9Wuc9gh79x*se&Tyj0Rs51wwF4j`5sy79}%dSE}so_;t&kK4!Hn;padW1@g%JRr5VrnOq za!4*th%d(F%3Y-b*B`D+@G1Exj-<$ri9f?g7B~d17V3c^mjD3;D~Vy@Y_x#ud8mvE zUPIL{Oe59#8!-=u(`mt4PytD+7R-g}N?$@5k-x$>po#kdO15^?>r<+7`J8svL|H2r-KdXK>}VB!`iN1*&0=($Dl%CUE$yq=djz|6gm36)gl zbdb@6HI`@mYGycjgd1DcR9~XfhkUUNfY7>>1N4O;tyw-VNef^6E+L|Ize= zsn#amBL)1bLoZK>JJ`%LSj@kt9BJVEWy^Eb?hthetE@XPy^~Vnc^-(aoBtLgo~zs^+Ax#}HEvaY41gg`NC3HoT8 z)c4SywgjN-C=S2Y6~r;n0X4aDNVDXy1K}o%UMh!h&8vI>DP9o;H`q0)A~N(X@LTvT zv?t%2soo#piwg8)-((ZlZY91=yOsS4ePw}H7WgB#z-NWjADBnZdu=rfY7YP4~yWbDtdq<+m%Wp9~f`!+HUs~@Y>gC4POZnbG-;)QlM+l+*Ma{Nmm)I9$ZjyqXcrH97nR4H49SPFKbVpMnwdBWPj&vgoT z2aor(#CK5KhYt;RG6a<{Fi>H?Pk5-jhw}YCb$cc2js;jq7o`q>6NW^Oy$N<%Y5(+^ zw#!1=)3&d%`}l5zlZ)iL5O#g>>^AB5HUcI)vqcpaXFQMkl+yzfx0z4CfKhbX_GJ)j zChygJ8Ph#^C%eP`Gs95h= zP9^?F-cF!qu-_B(?RcoXhw}ZNlzS!SUJGRTIdkWgj;_gjp`5mRyx417w)TExBu_+l{bR5#SMc#O^ zE#5S-j%_G%w|>$3JG@2QmaT)f+iP$evB&wu^+IDeMCUqfB|ezo?_f-ku6mR8y~7TY+0aeLphZL0|p7DTf?5JfdEE$lb8 z<>7VPTQsF?FG4Pw4g`Y2U+9dBua49n>I>sjBxnW7lj4T&HSBku-|0f^wz_!kh|-T^ zZ*$(WFk91JRo>v z?AU3MqkY}GOG>#<6wUePYLjw9HlWasSMb$ZU~kF@z`N3Z%PU2ZF_n`(bV=*FiArHY zXRR&M!LTtUW*+vPp}V#-Z{}Uo#VvAU&SYDup)hbmLf-pENgWKK5J-R%D$kPH#QvFC zE`|4(ogtKY4~oFk#|R?3-?E)WFy3d>Yr>!t733{^?sP!2LY_Yrhdi={xL`PcU*sP< z>3{B4dM9W{%Ke6PV3rF|NMC9QN-t(4oEpr2Ex!KWsN+mjHV!4c)iM*eDTe1_L~t0N z9TMnzufCebCm+~qs$!3zr4^Y};8n1*QKkX)WOcqqRLrrk)?|1b%{mwMJ3~;3Y{7XY zEVTBqg{+=b6Ws(Dg@tAl=m+Fm1-92&D%Tc)@Cv>{3$z+hg#br`#fleoV8h>XP%1$J zicMH>E0qgLk`8gpQX#TaM?f7ABsvad<>-1@x>Vn6B57)hFKgVv?FTV2=XNwb8OE*` zuzUqeed!op@A(RM`HCaIfVnMy3!h!s6m3C#f+)>kV-#{;z_$^Rk8CT0F{`9YAy=g~ zKoOvDXvhjXa@uVUo;d_rffS7n9*R!VE<&lF?;yGG(H=Ysx+)DF#}LZ!$4QnH350Zf zV_vPd!jcIRv>b^9D;j(ASx!%TX~-+Ck{x+T%uZ~_BGTl?4u$WOU6R_l4&svBkj*tU5Gsfbx%D;9+%N{1RxPzz%7w4hGAe{j#y(DkVa~r*@N@WZ z%{FC)G&cEP3-S+i_?tKG=Y$p0QNMje9%nPd7FrY>D!73vp|-M6L0_wq!${5>&K=wDELZy}uNHG<)mB}N5{ggxc~Ib$C8lku_1#K>6uh2mS?>amYs`*PMlue zkJA#Gd796C_Ot8`mo^I0K>XZ7E_D<4$ovz0;w0K}G*3^Q^=RH6o%*~SWpnq#=4fu~ z&r#0iSS?XDVY9~+;5T%p>D@>3VIA@8DZED&)Nyt|H?@=|L_x@RLc6rw#wT9sT+UFPVvP)hr<;5-9oUe|! zj-1BahV;>UcCwvtWU*dkRQ=IGp+i1$+xfEt3s+CLCH0pxe^>te9Hr(*e80Gk5!6Y? z_Z-h+xT9h8ye9%oHG}vkSZ}I}RY+3>G#^tqnE4u3K~XBhN%M$3a+6u~4OC&XV$m>= z7e;D0aW|3s5IfZSVx*$EE(FK}tX;H@6c9?O3c!cMJcHc@DKLN&bD;1*bWI9TRaqFs zER_~;*Skkv7#3Tb%{JNSxOSR+u3Ey*FJH8A|t)_-1SbN2YF<6L&Ie=Ko)xff&Ov*!Kt zGweXuI9|S%XJ^cp*$EenGsIA1)0Elc1{Z&S%|Mz#_84c5PnYz;VYI#X?ZdrYZc%K9 z?N9hTu-Ufl&*D+svE_+fJp1#4hsI}%Fj^*G?=WXsa_q0!YQKAS@J)MnvH1La{+Z2R zd$fG_M<>(&*!uaOjjW_c?(2Dq=a@cSq$0b&=JAt!xtv}hDGAWItd8O??!ofBwA(g6 z+ise(HD9IgalzG$y?K}AVeS`L#npr7&2|}cUHW?Z)|?wid;>hq*<~%u{FKO1G_LPH zKd~{>?y1>9T3=eh?n^se=gXsv?n}!oEckJ0m&<%SUo1wmu>OUe&$iz?$$03&lg#uW zylFo>^Ple&S{t8Q8MQmjTK*%~7iOi*?c9+YY%F_e;>4n94TtA~b z@Im+U#o9)`e#W&hm|S<+cwJD~^P{qu{{$a?`SiUb`%L~6-Srzjk6Ah9Jdg6CIc1jM zE=w;nm7*w-f`#+b1Zd$@oWUV4nId$n+nkzm79)#@Xcce+g_V@Z#dFC$v4$G9DPwDK zWD;g4aB57o;osCUb)9oEaJH^|voge0#h#>4l`{ItuZcQqr%QJ<_O-J_GWWvl%C8`a zwV*ArYJ;MG{whf!kZU*uwN6aM&sDI}@bGHLcj8E*5j!U^Vd7m|$QG^SFlNRSD7?wp zJ7`jV=9hi9xE&C-w#XvSk|RNq_&Ks#H8cpKqWCP-EYNYR>mZq17o&YD^ERF4@!OUi zGe&XGXw4~?sPS=Dk_l-z1xwNL_elr5NH+V8BROTaIG>O)q?es45%tue0O8QEw&Ⓢ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 +# e1000-devel Mailing List +# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 +# +################################################################################ diff --git a/openflow/datapath/linux-2.6/Modules.mk b/openflow/datapath/linux-2.6/Modules.mk new file mode 100644 index 00000000..8c854a0e --- /dev/null +++ b/openflow/datapath/linux-2.6/Modules.mk @@ -0,0 +1,32 @@ +ofdatapath_sources += \ + linux-2.6/compat-2.6/genetlink-openflow.c \ + linux-2.6/compat-2.6/random32.c +ofdatapath_headers += \ + linux-2.6/compat-2.6/compat26.h \ + linux-2.6/compat-2.6/include/asm-generic/bug.h \ + linux-2.6/compat-2.6/include/linux/dmi.h \ + linux-2.6/compat-2.6/include/linux/icmp.h \ + linux-2.6/compat-2.6/include/linux/if_arp.h \ + linux-2.6/compat-2.6/include/linux/ip.h \ + linux-2.6/compat-2.6/include/linux/ipv6.h \ + linux-2.6/compat-2.6/include/linux/jiffies.h \ + linux-2.6/compat-2.6/include/linux/lockdep.h \ + linux-2.6/compat-2.6/include/linux/mutex.h \ + linux-2.6/compat-2.6/include/linux/netfilter_ipv4.h \ + linux-2.6/compat-2.6/include/linux/netlink.h \ + linux-2.6/compat-2.6/include/linux/random.h \ + linux-2.6/compat-2.6/include/linux/rculist.h \ + linux-2.6/compat-2.6/include/linux/skbuff.h \ + linux-2.6/compat-2.6/include/linux/tcp.h \ + linux-2.6/compat-2.6/include/linux/timer.h \ + linux-2.6/compat-2.6/include/linux/types.h \ + linux-2.6/compat-2.6/include/linux/udp.h \ + linux-2.6/compat-2.6/include/linux/workqueue.h \ + linux-2.6/compat-2.6/include/net/checksum.h \ + linux-2.6/compat-2.6/include/net/genetlink.h \ + linux-2.6/compat-2.6/include/net/netlink.h + +#dist_modules += veth +#build_modules += $(if $(BUILD_VETH),veth) +veth_sources = linux-2.6/compat-2.6/veth.c +veth_headers = diff --git a/openflow/datapath/linux-2.6/compat-2.6/compat26.h b/openflow/datapath/linux-2.6/compat-2.6/compat26.h new file mode 100644 index 00000000..37f6a4f8 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/compat26.h @@ -0,0 +1,31 @@ +#ifndef __COMPAT26_H +#define __COMPAT26_H 1 + +#include + +#if defined(CONFIG_PREEMPT) && LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21) +#error "CONFIG_PREEMPT is broken with 2.6.x before 2.6.21--see commit 4498121ca3, \"[NET]: Handle disabled preemption in gfp_any()\"" +#endif + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23) +/*---------------------------------------------------------------------------- + * In 2.6.24, a namespace argument became required for dev_get_by_name. */ + +#define dev_get_by_name(net, name) \ + dev_get_by_name((name)) + +#define dev_get_by_index(net, ifindex) \ + dev_get_by_index((ifindex)) + +#endif /* linux kernel <= 2.6.23 */ + + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22) +/*---------------------------------------------------------------------------- + * In 2.6.23, the last argument was dropped from kmem_cache_create. */ +#define kmem_cache_create(n, s, a, f, c) \ + kmem_cache_create((n), (s), (a), (f), (c), NULL) + +#endif /* linux kernel <= 2.6.22 */ + +#endif /* compat26.h */ diff --git a/openflow/datapath/linux-2.6/compat-2.6/genetlink-brcompat.c b/openflow/datapath/linux-2.6/compat-2.6/genetlink-brcompat.c new file mode 100644 index 00000000..f30996ce --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/genetlink-brcompat.c @@ -0,0 +1,20 @@ +#include "net/genetlink.h" + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) + +/* We fix grp->id to 32 so that it doesn't collide with any of the multicast + * groups selected by openflow_mod, which uses groups 16 through 31. Collision + * isn't fatal--multicast listeners should check that the family is the one + * that they want and discard others--but it wastes time and memory to receive + * unwanted messages. */ +int genl_register_mc_group(struct genl_family *family, + struct genl_multicast_group *grp) +{ + grp->id = 32; + grp->family = family; + + return 0; +} + +#endif /* kernel < 2.6.23 */ diff --git a/openflow/datapath/linux-2.6/compat-2.6/genetlink-openflow.c b/openflow/datapath/linux-2.6/compat-2.6/genetlink-openflow.c new file mode 100644 index 00000000..9e09215f --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/genetlink-openflow.c @@ -0,0 +1,22 @@ +#include "net/genetlink.h" + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) + +/* We use multicast groups 16 through 31 to avoid colliding with the multicast + * group selected by brcompat_mod, which uses groups 32. Collision isn't + * fatal--multicast listeners should check that the family is the one that they + * want and discard others--but it wastes time and memory to receive unwanted + * messages. */ +int genl_register_mc_group(struct genl_family *family, + struct genl_multicast_group *grp) +{ + /* This code is called single-threaded. */ + static unsigned int next_id = 0; + grp->id = next_id++ % 16 + 16; + grp->family = family; + + return 0; +} + +#endif /* kernel < 2.6.23 */ diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/asm-generic/bug.h b/openflow/datapath/linux-2.6/compat-2.6/include/asm-generic/bug.h new file mode 100644 index 00000000..bd0a1714 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/asm-generic/bug.h @@ -0,0 +1,20 @@ +#ifndef __ASM_GENERIC_BUG_WRAPPER_H +#define __ASM_GENERIC_BUG_WRAPPER_H + +#include_next + +#ifndef WARN_ON_ONCE +#define WARN_ON_ONCE(condition) ({ \ + static int __warned; \ + int __ret_warn_once = !!(condition); \ + \ + if (unlikely(__ret_warn_once) && !__warned) { \ + WARN_ON(1); \ + __warned = 1; \ + } \ + unlikely(__ret_warn_once); \ +}) + +#endif + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/dmi.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/dmi.h new file mode 100644 index 00000000..52916fec --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/dmi.h @@ -0,0 +1,114 @@ +#ifndef __LINUX_DMI_WRAPPER_H +#define __LINUX_DMI_WRAPPER_H 1 + +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23) + +#include_next + +#else /* linux version >= 2.6.23 */ + +#ifndef __DMI_H__ +#define __DMI_H__ + +#include + +enum dmi_field { + DMI_NONE, + DMI_BIOS_VENDOR, + DMI_BIOS_VERSION, + DMI_BIOS_DATE, + DMI_SYS_VENDOR, + DMI_PRODUCT_NAME, + DMI_PRODUCT_VERSION, + DMI_PRODUCT_SERIAL, + DMI_PRODUCT_UUID, + DMI_BOARD_VENDOR, + DMI_BOARD_NAME, + DMI_BOARD_VERSION, + DMI_BOARD_SERIAL, + DMI_BOARD_ASSET_TAG, + DMI_CHASSIS_VENDOR, + DMI_CHASSIS_TYPE, + DMI_CHASSIS_VERSION, + DMI_CHASSIS_SERIAL, + DMI_CHASSIS_ASSET_TAG, + DMI_STRING_MAX, +}; + +enum dmi_device_type { + DMI_DEV_TYPE_ANY = 0, + DMI_DEV_TYPE_OTHER, + DMI_DEV_TYPE_UNKNOWN, + DMI_DEV_TYPE_VIDEO, + DMI_DEV_TYPE_SCSI, + DMI_DEV_TYPE_ETHERNET, + DMI_DEV_TYPE_TOKENRING, + DMI_DEV_TYPE_SOUND, + DMI_DEV_TYPE_IPMI = -1, + DMI_DEV_TYPE_OEM_STRING = -2 +}; + +struct dmi_header { + u8 type; + u8 length; + u16 handle; +}; + +/* + * DMI callbacks for problem boards + */ +struct dmi_strmatch { + u8 slot; + char *substr; +}; + +struct dmi_system_id { + int (*callback)(struct dmi_system_id *); + const char *ident; + struct dmi_strmatch matches[4]; + void *driver_data; +}; + +#define DMI_MATCH(a, b) { a, b } + +struct dmi_device { + struct list_head list; + int type; + const char *name; + void *device_data; /* Type specific data */ +}; + +/* No CONFIG_DMI before 2.6.16 */ +#if defined(CONFIG_DMI) || defined(CONFIG_X86_32) + +extern int dmi_check_system(struct dmi_system_id *list); +extern char * dmi_get_system_info(int field); +extern struct dmi_device * dmi_find_device(int type, const char *name, + struct dmi_device *from); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) +extern void dmi_scan_machine(void); +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17) +extern int dmi_get_year(int field); +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) +extern int dmi_name_in_vendors(char *str); +#endif + +#else + +static inline int dmi_check_system(struct dmi_system_id *list) { return 0; } +static inline char * dmi_get_system_info(int field) { return NULL; } +static inline struct dmi_device * dmi_find_device(int type, const char *name, + struct dmi_device *from) { return NULL; } +static inline int dmi_get_year(int year) { return 0; } +static inline int dmi_name_in_vendors(char *s) { return 0; } + +#endif + +#endif /* __DMI_H__ */ + +#endif /* linux kernel < 2.6.22 */ + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/icmp.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/icmp.h new file mode 100644 index 00000000..89b354e4 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/icmp.h @@ -0,0 +1,13 @@ +#ifndef __LINUX_ICMP_WRAPPER_H +#define __LINUX_ICMP_WRAPPER_H 1 + +#include_next + +#ifndef HAVE_SKBUFF_HEADER_HELPERS +static inline struct icmphdr *icmp_hdr(const struct sk_buff *skb) +{ + return (struct icmphdr *)skb_transport_header(skb); +} +#endif + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/if_arp.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/if_arp.h new file mode 100644 index 00000000..3ec9ea7a --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/if_arp.h @@ -0,0 +1,16 @@ +#ifndef __LINUX_IF_ARP_WRAPPER_H +#define __LINUX_IF_ARP_WRAPPER_H 1 + + +#include_next + +#ifndef HAVE_SKBUFF_HEADER_HELPERS +#include + +static inline struct arphdr *arp_hdr(const struct sk_buff *skb) +{ + return (struct arphdr *)skb_network_header(skb); +} +#endif /* !HAVE_SKBUFF_HEADER_HELPERS */ + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/ip.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/ip.h new file mode 100644 index 00000000..36765396 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/ip.h @@ -0,0 +1,18 @@ +#ifndef __LINUX_IP_WRAPPER_H +#define __LINUX_IP_WRAPPER_H 1 + +#include_next + +#ifndef HAVE_SKBUFF_HEADER_HELPERS +static inline struct iphdr *ip_hdr(const struct sk_buff *skb) +{ + return (struct iphdr *)skb_network_header(skb); +} + +static inline unsigned int ip_hdrlen(const struct sk_buff *skb) +{ + return ip_hdr(skb)->ihl * 4; +} +#endif /* !HAVE_SKBUFF_HEADER_HELPERS */ + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/ipv6.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/ipv6.h new file mode 100644 index 00000000..25a5431a --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/ipv6.h @@ -0,0 +1,13 @@ +#ifndef __LINUX_IPV6_WRAPPER_H +#define __LINUX_IPV6_WRAPPER_H 1 + +#include_next + +#ifndef HAVE_SKBUFF_HEADER_HELPERS +static inline struct ipv6hdr *ipv6_hdr(const struct sk_buff *skb) +{ + return (struct ipv6hdr *)skb_network_header(skb); +} +#endif + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/jiffies.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/jiffies.h new file mode 100644 index 00000000..3286e634 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/jiffies.h @@ -0,0 +1,26 @@ +#ifndef __LINUX_JIFFIES_WRAPPER_H +#define __LINUX_JIFFIES_WRAPPER_H 1 + +#include_next + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) + +/* Same as above, but does so with platform independent 64bit types. + * These must be used when utilizing jiffies_64 (i.e. return value of + * get_jiffies_64() */ +#define time_after64(a,b) \ + (typecheck(__u64, a) && \ + typecheck(__u64, b) && \ + ((__s64)(b) - (__s64)(a) < 0)) +#define time_before64(a,b) time_after64(b,a) + +#define time_after_eq64(a,b) \ + (typecheck(__u64, a) && \ + typecheck(__u64, b) && \ + ((__s64)(a) - (__s64)(b) >= 0)) +#define time_before_eq64(a,b) time_after_eq64(b,a) + +#endif /* linux kernel < 2.6.19 */ + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/lockdep.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/lockdep.h new file mode 100644 index 00000000..1c839423 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/lockdep.h @@ -0,0 +1,450 @@ +/* + * Runtime locking correctness validator + * + * Copyright (C) 2006,2007 Red Hat, Inc., Ingo Molnar + * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra + * + * see Documentation/lockdep-design.txt for more details. + */ +#ifndef __LINUX_LOCKDEP_WRAPPER_H +#define __LINUX_LOCKDEP_WRAPPER_H + +#include_next + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) + +struct task_struct; +struct lockdep_map; + +#ifdef CONFIG_LOCKDEP + +#include +#include +#include +#include + +/* + * Lock-class usage-state bits: + */ +enum lock_usage_bit +{ + LOCK_USED = 0, + LOCK_USED_IN_HARDIRQ, + LOCK_USED_IN_SOFTIRQ, + LOCK_ENABLED_SOFTIRQS, + LOCK_ENABLED_HARDIRQS, + LOCK_USED_IN_HARDIRQ_READ, + LOCK_USED_IN_SOFTIRQ_READ, + LOCK_ENABLED_SOFTIRQS_READ, + LOCK_ENABLED_HARDIRQS_READ, + LOCK_USAGE_STATES +}; + +/* + * Usage-state bitmasks: + */ +#define LOCKF_USED (1 << LOCK_USED) +#define LOCKF_USED_IN_HARDIRQ (1 << LOCK_USED_IN_HARDIRQ) +#define LOCKF_USED_IN_SOFTIRQ (1 << LOCK_USED_IN_SOFTIRQ) +#define LOCKF_ENABLED_HARDIRQS (1 << LOCK_ENABLED_HARDIRQS) +#define LOCKF_ENABLED_SOFTIRQS (1 << LOCK_ENABLED_SOFTIRQS) + +#define LOCKF_ENABLED_IRQS (LOCKF_ENABLED_HARDIRQS | LOCKF_ENABLED_SOFTIRQS) +#define LOCKF_USED_IN_IRQ (LOCKF_USED_IN_HARDIRQ | LOCKF_USED_IN_SOFTIRQ) + +#define LOCKF_USED_IN_HARDIRQ_READ (1 << LOCK_USED_IN_HARDIRQ_READ) +#define LOCKF_USED_IN_SOFTIRQ_READ (1 << LOCK_USED_IN_SOFTIRQ_READ) +#define LOCKF_ENABLED_HARDIRQS_READ (1 << LOCK_ENABLED_HARDIRQS_READ) +#define LOCKF_ENABLED_SOFTIRQS_READ (1 << LOCK_ENABLED_SOFTIRQS_READ) + +#define LOCKF_ENABLED_IRQS_READ \ + (LOCKF_ENABLED_HARDIRQS_READ | LOCKF_ENABLED_SOFTIRQS_READ) +#define LOCKF_USED_IN_IRQ_READ \ + (LOCKF_USED_IN_HARDIRQ_READ | LOCKF_USED_IN_SOFTIRQ_READ) + +#define MAX_LOCKDEP_SUBCLASSES 8UL + +/* + * Lock-classes are keyed via unique addresses, by embedding the + * lockclass-key into the kernel (or module) .data section. (For + * static locks we use the lock address itself as the key.) + */ +struct lockdep_subclass_key { + char __one_byte; +} __attribute__ ((__packed__)); + +struct lock_class_key { + struct lockdep_subclass_key subkeys[MAX_LOCKDEP_SUBCLASSES]; +}; + +/* + * The lock-class itself: + */ +struct lock_class { + /* + * class-hash: + */ + struct list_head hash_entry; + + /* + * global list of all lock-classes: + */ + struct list_head lock_entry; + + struct lockdep_subclass_key *key; + unsigned int subclass; + + /* + * IRQ/softirq usage tracking bits: + */ + unsigned long usage_mask; + struct stack_trace usage_traces[LOCK_USAGE_STATES]; + + /* + * These fields represent a directed graph of lock dependencies, + * to every node we attach a list of "forward" and a list of + * "backward" graph nodes. + */ + struct list_head locks_after, locks_before; + + /* + * Generation counter, when doing certain classes of graph walking, + * to ensure that we check one node only once: + */ + unsigned int version; + + /* + * Statistics counter: + */ + unsigned long ops; + + const char *name; + int name_version; + +#ifdef CONFIG_LOCK_STAT + unsigned long contention_point[4]; +#endif +}; + +#ifdef CONFIG_LOCK_STAT +struct lock_time { + s64 min; + s64 max; + s64 total; + unsigned long nr; +}; + +enum bounce_type { + bounce_acquired_write, + bounce_acquired_read, + bounce_contended_write, + bounce_contended_read, + nr_bounce_types, + + bounce_acquired = bounce_acquired_write, + bounce_contended = bounce_contended_write, +}; + +struct lock_class_stats { + unsigned long contention_point[4]; + struct lock_time read_waittime; + struct lock_time write_waittime; + struct lock_time read_holdtime; + struct lock_time write_holdtime; + unsigned long bounces[nr_bounce_types]; +}; + +struct lock_class_stats lock_stats(struct lock_class *class); +void clear_lock_stats(struct lock_class *class); +#endif + +/* + * Map the lock object (the lock instance) to the lock-class object. + * This is embedded into specific lock instances: + */ +struct lockdep_map { + struct lock_class_key *key; + struct lock_class *class_cache; + const char *name; +#ifdef CONFIG_LOCK_STAT + int cpu; +#endif +}; + +/* + * Every lock has a list of other locks that were taken after it. + * We only grow the list, never remove from it: + */ +struct lock_list { + struct list_head entry; + struct lock_class *class; + struct stack_trace trace; + int distance; +}; + +/* + * We record lock dependency chains, so that we can cache them: + */ +struct lock_chain { + struct list_head entry; + u64 chain_key; +}; + +struct held_lock { + /* + * One-way hash of the dependency chain up to this point. We + * hash the hashes step by step as the dependency chain grows. + * + * We use it for dependency-caching and we skip detection + * passes and dependency-updates if there is a cache-hit, so + * it is absolutely critical for 100% coverage of the validator + * to have a unique key value for every unique dependency path + * that can occur in the system, to make a unique hash value + * as likely as possible - hence the 64-bit width. + * + * The task struct holds the current hash value (initialized + * with zero), here we store the previous hash value: + */ + u64 prev_chain_key; + struct lock_class *class; + unsigned long acquire_ip; + struct lockdep_map *instance; + +#ifdef CONFIG_LOCK_STAT + u64 waittime_stamp; + u64 holdtime_stamp; +#endif + /* + * The lock-stack is unified in that the lock chains of interrupt + * contexts nest ontop of process context chains, but we 'separate' + * the hashes by starting with 0 if we cross into an interrupt + * context, and we also keep do not add cross-context lock + * dependencies - the lock usage graph walking covers that area + * anyway, and we'd just unnecessarily increase the number of + * dependencies otherwise. [Note: hardirq and softirq contexts + * are separated from each other too.] + * + * The following field is used to detect when we cross into an + * interrupt context: + */ + int irq_context; + int trylock; + int read; + int check; + int hardirqs_off; +}; + +/* + * Initialization, self-test and debugging-output methods: + */ +extern void lockdep_init(void); +extern void lockdep_info(void); +extern void lockdep_reset(void); +extern void lockdep_reset_lock(struct lockdep_map *lock); +extern void lockdep_free_key_range(void *start, unsigned long size); + +extern void lockdep_off(void); +extern void lockdep_on(void); + +/* + * These methods are used by specific locking variants (spinlocks, + * rwlocks, mutexes and rwsems) to pass init/acquire/release events + * to lockdep: + */ + +extern void lockdep_init_map(struct lockdep_map *lock, const char *name, + struct lock_class_key *key, int subclass); + +/* + * Reinitialize a lock key - for cases where there is special locking or + * special initialization of locks so that the validator gets the scope + * of dependencies wrong: they are either too broad (they need a class-split) + * or they are too narrow (they suffer from a false class-split): + */ +#define lockdep_set_class(lock, key) \ + lockdep_init_map(&(lock)->dep_map, #key, key, 0) +#define lockdep_set_class_and_name(lock, key, name) \ + lockdep_init_map(&(lock)->dep_map, name, key, 0) +#define lockdep_set_class_and_subclass(lock, key, sub) \ + lockdep_init_map(&(lock)->dep_map, #key, key, sub) +#define lockdep_set_subclass(lock, sub) \ + lockdep_init_map(&(lock)->dep_map, #lock, \ + (lock)->dep_map.key, sub) + +/* + * Acquire a lock. + * + * Values for "read": + * + * 0: exclusive (write) acquire + * 1: read-acquire (no recursion allowed) + * 2: read-acquire with same-instance recursion allowed + * + * Values for check: + * + * 0: disabled + * 1: simple checks (freeing, held-at-exit-time, etc.) + * 2: full validation + */ +extern void lock_acquire(struct lockdep_map *lock, unsigned int subclass, + int trylock, int read, int check, unsigned long ip); + +extern void lock_release(struct lockdep_map *lock, int nested, + unsigned long ip); + +# define INIT_LOCKDEP .lockdep_recursion = 0, + +#define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0) + +#else /* !LOCKDEP */ + +static inline void lockdep_off(void) +{ +} + +static inline void lockdep_on(void) +{ +} + +# define lock_acquire(l, s, t, r, c, i) do { } while (0) +# define lock_release(l, n, i) do { } while (0) +# define lockdep_init() do { } while (0) +# define lockdep_info() do { } while (0) +# define lockdep_init_map(lock, name, key, sub) do { (void)(key); } while (0) +# define lockdep_set_class(lock, key) do { (void)(key); } while (0) +# define lockdep_set_class_and_name(lock, key, name) \ + do { (void)(key); } while (0) +#define lockdep_set_class_and_subclass(lock, key, sub) \ + do { (void)(key); } while (0) +#define lockdep_set_subclass(lock, sub) do { } while (0) + +# define INIT_LOCKDEP +# define lockdep_reset() do { debug_locks = 1; } while (0) +# define lockdep_free_key_range(start, size) do { } while (0) +/* + * The class key takes no space if lockdep is disabled: + */ +struct lock_class_key { }; + +#define lockdep_depth(tsk) (0) + +#endif /* !LOCKDEP */ + +#ifdef CONFIG_LOCK_STAT + +extern void lock_contended(struct lockdep_map *lock, unsigned long ip); +extern void lock_acquired(struct lockdep_map *lock); + +#define LOCK_CONTENDED(_lock, try, lock) \ +do { \ + if (!try(_lock)) { \ + lock_contended(&(_lock)->dep_map, _RET_IP_); \ + lock(_lock); \ + } \ + lock_acquired(&(_lock)->dep_map); \ +} while (0) + +#else /* CONFIG_LOCK_STAT */ + +#define lock_contended(lockdep_map, ip) do {} while (0) +#define lock_acquired(lockdep_map) do {} while (0) + +#define LOCK_CONTENDED(_lock, try, lock) \ + lock(_lock) + +#endif /* CONFIG_LOCK_STAT */ + +#if defined(CONFIG_TRACE_IRQFLAGS) && defined(CONFIG_GENERIC_HARDIRQS) +extern void early_init_irq_lock_class(void); +#else +static inline void early_init_irq_lock_class(void) +{ +} +#endif + +#ifdef CONFIG_TRACE_IRQFLAGS +extern void early_boot_irqs_off(void); +extern void early_boot_irqs_on(void); +extern void print_irqtrace_events(struct task_struct *curr); +#else +static inline void early_boot_irqs_off(void) +{ +} +static inline void early_boot_irqs_on(void) +{ +} +static inline void print_irqtrace_events(struct task_struct *curr) +{ +} +#endif + +/* + * For trivial one-depth nesting of a lock-class, the following + * global define can be used. (Subsystems with multiple levels + * of nesting should define their own lock-nesting subclasses.) + */ +#define SINGLE_DEPTH_NESTING 1 + +/* + * Map the dependency ops to NOP or to real lockdep ops, depending + * on the per lock-class debug mode: + */ + +#ifdef CONFIG_DEBUG_LOCK_ALLOC +# ifdef CONFIG_PROVE_LOCKING +# define spin_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 2, i) +# else +# define spin_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 1, i) +# endif +# define spin_release(l, n, i) lock_release(l, n, i) +#else +# define spin_acquire(l, s, t, i) do { } while (0) +# define spin_release(l, n, i) do { } while (0) +#endif + +#ifdef CONFIG_DEBUG_LOCK_ALLOC +# ifdef CONFIG_PROVE_LOCKING +# define rwlock_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 2, i) +# define rwlock_acquire_read(l, s, t, i) lock_acquire(l, s, t, 2, 2, i) +# else +# define rwlock_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 1, i) +# define rwlock_acquire_read(l, s, t, i) lock_acquire(l, s, t, 2, 1, i) +# endif +# define rwlock_release(l, n, i) lock_release(l, n, i) +#else +# define rwlock_acquire(l, s, t, i) do { } while (0) +# define rwlock_acquire_read(l, s, t, i) do { } while (0) +# define rwlock_release(l, n, i) do { } while (0) +#endif + +#ifdef CONFIG_DEBUG_LOCK_ALLOC +# ifdef CONFIG_PROVE_LOCKING +# define mutex_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 2, i) +# else +# define mutex_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 1, i) +# endif +# define mutex_release(l, n, i) lock_release(l, n, i) +#else +# define mutex_acquire(l, s, t, i) do { } while (0) +# define mutex_release(l, n, i) do { } while (0) +#endif + +#ifdef CONFIG_DEBUG_LOCK_ALLOC +# ifdef CONFIG_PROVE_LOCKING +# define rwsem_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 2, i) +# define rwsem_acquire_read(l, s, t, i) lock_acquire(l, s, t, 1, 2, i) +# else +# define rwsem_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 1, i) +# define rwsem_acquire_read(l, s, t, i) lock_acquire(l, s, t, 1, 1, i) +# endif +# define rwsem_release(l, n, i) lock_release(l, n, i) +#else +# define rwsem_acquire(l, s, t, i) do { } while (0) +# define rwsem_acquire_read(l, s, t, i) do { } while (0) +# define rwsem_release(l, n, i) do { } while (0) +#endif + +#endif /* linux kernel < 2.6.18 */ + +#endif /* __LINUX_LOCKDEP_WRAPPER_H */ diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/mutex.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/mutex.h new file mode 100644 index 00000000..cb5b2738 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/mutex.h @@ -0,0 +1,59 @@ +#ifndef __LINUX_MUTEX_WRAPPER_H +#define __LINUX_MUTEX_WRAPPER_H + + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) + +#include + +struct mutex { + struct semaphore sema; +}; + +#define mutex_init(mutex) init_MUTEX(&mutex->sema) +#define mutex_destroy(mutex) do { } while (0) + +#define __MUTEX_INITIALIZER(name) \ + __SEMAPHORE_INITIALIZER(name,1) + +#define DEFINE_MUTEX(mutexname) \ + struct mutex mutexname = { __MUTEX_INITIALIZER(mutexname.sema) } + +/* + * See kernel/mutex.c for detailed documentation of these APIs. + * Also see Documentation/mutex-design.txt. + */ +static inline void mutex_lock(struct mutex *lock) +{ + down(&lock->sema); +} + +static inline int mutex_lock_interruptible(struct mutex *lock) +{ + return down_interruptible(&lock->sema); +} + +#define mutex_lock_nested(lock, subclass) mutex_lock(lock) +#define mutex_lock_interruptible_nested(lock, subclass) mutex_lock_interruptible(lock) + +/* + * NOTE: mutex_trylock() follows the spin_trylock() convention, + * not the down_trylock() convention! + */ +static inline int mutex_trylock(struct mutex *lock) +{ + return !down_trylock(&lock->sema); +} + +static inline void mutex_unlock(struct mutex *lock) +{ + up(&lock->sema); +} +#else + +#include_next + +#endif /* linux version < 2.6.16 */ + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/netdevice.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/netdevice.h new file mode 100644 index 00000000..7abeb3bf --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/netdevice.h @@ -0,0 +1,10 @@ +#ifndef __LINUX_NETDEVICE_WRAPPER_H +#define __LINUX_NETDEVICE_WRAPPER_H 1 + +#include_next + +#ifndef to_net_dev +#define to_net_dev(class) container_of(class, struct net_device, class_dev) +#endif + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/netfilter_bridge.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/netfilter_bridge.h new file mode 100644 index 00000000..1c8183c8 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/netfilter_bridge.h @@ -0,0 +1,24 @@ +#ifndef __LINUX_NETFILTER_BRIDGE_WRAPPER_H +#define __LINUX_NETFILTER_BRIDGE_WRAPPER_H + +#include_next + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) + +#include +#include + +static inline unsigned int nf_bridge_encap_header_len(const struct sk_buff *skb) +{ + switch (skb->protocol) { + case __constant_htons(ETH_P_8021Q): + return VLAN_HLEN; + default: + return 0; + } +} + +#endif /* linux version < 2.6.22 */ + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/netfilter_ipv4.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/netfilter_ipv4.h new file mode 100644 index 00000000..ed8a5d94 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/netfilter_ipv4.h @@ -0,0 +1,19 @@ +#ifndef __LINUX_NETFILTER_IPV4_WRAPPER_H +#define __LINUX_NETFILTER_IPV4_WRAPPER_H 1 + +#include_next + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) + +#ifdef __KERNEL__ + +#define NF_INET_PRE_ROUTING NF_IP_PRE_ROUTING +#define NF_INET_POST_ROUTING NF_IP_POST_ROUTING +#define NF_INET_FORWARD NF_IP_FORWARD + +#endif /* __KERNEL__ */ + +#endif /* linux kernel < 2.6.25 */ + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/netlink.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/netlink.h new file mode 100644 index 00000000..c5f83bd0 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/netlink.h @@ -0,0 +1,24 @@ +#ifndef __LINUX_NETLINK_WRAPPER_H +#define __LINUX_NETLINK_WRAPPER_H 1 + +#include +#include_next +#include + +#include + +#ifndef NLMSG_DEFAULT_SIZE +#define NLMSG_DEFAULT_SIZE (NLMSG_GOODSIZE - NLMSG_HDRLEN) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) +#define nlmsg_new(s, f) nlmsg_new_proper((s), (f)) +static inline struct sk_buff *nlmsg_new_proper(int size, gfp_t flags) +{ + return alloc_skb(size, flags); +} + +#endif /* linux kernel < 2.6.19 */ + + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/random.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/random.h new file mode 100644 index 00000000..4e4932c9 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/random.h @@ -0,0 +1,17 @@ +#ifndef __LINUX_RANDOM_WRAPPER_H +#define __LINUX_RANDOM_WRAPPER_H 1 + +#include_next + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) + +#ifdef __KERNEL__ +u32 random32(void); +void srandom32(u32 seed); +#endif /* __KERNEL__ */ + +#endif /* linux kernel < 2.6.19 */ + + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/rculist.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/rculist.h new file mode 100644 index 00000000..4164c0e9 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/rculist.h @@ -0,0 +1,12 @@ +#ifndef __LINUX_RCULIST_WRAPPER_H +#define __LINUX_RCULIST_WRAPPER_H + +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) +#include_next +#else +/* Prior to 2.6.26, the contents of rculist.h were part of list.h. */ +#include +#endif + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/skbuff.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/skbuff.h new file mode 100644 index 00000000..55d32eb1 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/skbuff.h @@ -0,0 +1,137 @@ +#ifndef __LINUX_SKBUFF_WRAPPER_H +#define __LINUX_SKBUFF_WRAPPER_H 1 + +#include_next + +#include + +#ifndef HAVE_SKB_COPY_FROM_LINEAR_DATA_OFFSET +static inline void skb_copy_from_linear_data_offset(const struct sk_buff *skb, + const int offset, void *to, + const unsigned int len) +{ + memcpy(to, skb->data + offset, len); +} + +static inline void skb_copy_to_linear_data_offset(struct sk_buff *skb, + const int offset, + const void *from, + const unsigned int len) +{ + memcpy(skb->data + offset, from, len); +} + +#endif /* !HAVE_SKB_COPY_FROM_LINEAR_DATA_OFFSET */ + + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) +static inline int __skb_cow(struct sk_buff *skb, unsigned int headroom, + int cloned) +{ + int delta = 0; + + if (headroom < NET_SKB_PAD) + headroom = NET_SKB_PAD; + if (headroom > skb_headroom(skb)) + delta = headroom - skb_headroom(skb); + + if (delta || cloned) + return pskb_expand_head(skb, ALIGN(delta, NET_SKB_PAD), 0, + GFP_ATOMIC); + return 0; +} + +static inline int skb_cow_head(struct sk_buff *skb, unsigned int headroom) +{ + return __skb_cow(skb, headroom, skb_header_cloned(skb)); +} +#endif /* linux < 2.6.23 */ + + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17) +/* Emulate Linux 2.6.17 and later behavior, in which kfree_skb silently ignores + * null pointer arguments. */ +#define kfree_skb(skb) kfree_skb_maybe_null(skb) +static inline void kfree_skb_maybe_null(struct sk_buff *skb) +{ + if (likely(skb != NULL)) + (kfree_skb)(skb); +} +#endif + + +#ifndef CHECKSUM_PARTIAL +/* Note that CHECKSUM_PARTIAL is not implemented, but this allows us to at + * least test against it: see update_csum() in forward.c. */ +#define CHECKSUM_PARTIAL 3 +#endif +#ifndef CHECKSUM_COMPLETE +#define CHECKSUM_COMPLETE CHECKSUM_HW +#endif + +#ifdef HAVE_MAC_RAW +#define mac_header mac.raw +#define network_header nh.raw +#endif + +#ifndef HAVE_SKBUFF_HEADER_HELPERS +static inline unsigned char *skb_transport_header(const struct sk_buff *skb) +{ + return skb->h.raw; +} + +static inline void skb_reset_transport_header(struct sk_buff *skb) +{ + skb->h.raw = skb->data; +} + +static inline void skb_set_transport_header(struct sk_buff *skb, + const int offset) +{ + skb->h.raw = skb->data + offset; +} + +static inline unsigned char *skb_network_header(const struct sk_buff *skb) +{ + return skb->nh.raw; +} + +static inline void skb_set_network_header(struct sk_buff *skb, const int offset) +{ + skb->nh.raw = skb->data + offset; +} + +static inline unsigned char *skb_mac_header(const struct sk_buff *skb) +{ + return skb->mac.raw; +} + +static inline void skb_reset_mac_header(struct sk_buff *skb) +{ + skb->mac_header = skb->data; +} + +static inline void skb_set_mac_header(struct sk_buff *skb, const int offset) +{ + skb->mac.raw = skb->data + offset; +} + +static inline int skb_transport_offset(const struct sk_buff *skb) +{ + return skb_transport_header(skb) - skb->data; +} + +static inline int skb_network_offset(const struct sk_buff *skb) +{ + return skb_network_header(skb) - skb->data; +} + +static inline void skb_copy_to_linear_data(struct sk_buff *skb, + const void *from, + const unsigned int len) +{ + memcpy(skb->data, from, len); +} +#endif /* !HAVE_SKBUFF_HEADER_HELPERS */ + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/tcp.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/tcp.h new file mode 100644 index 00000000..6fad1933 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/tcp.h @@ -0,0 +1,18 @@ +#ifndef __LINUX_TCP_WRAPPER_H +#define __LINUX_TCP_WRAPPER_H 1 + +#include_next + +#ifndef HAVE_SKBUFF_HEADER_HELPERS +static inline struct tcphdr *tcp_hdr(const struct sk_buff *skb) +{ + return (struct tcphdr *)skb_transport_header(skb); +} + +static inline unsigned int tcp_hdrlen(const struct sk_buff *skb) +{ + return tcp_hdr(skb)->doff * 4; +} +#endif /* !HAVE_SKBUFF_HEADER_HELPERS */ + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/timer.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/timer.h new file mode 100644 index 00000000..6c3a9b0f --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/timer.h @@ -0,0 +1,96 @@ +#ifndef __LINUX_TIMER_WRAPPER_H +#define __LINUX_TIMER_WRAPPER_H 1 + +#include_next + +#include + +#ifndef RHEL_RELEASE_VERSION +#define RHEL_RELEASE_VERSION(X,Y) ( 0 ) +#endif +#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) && \ + (!defined(RHEL_RELEASE_CODE) || \ + (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(5,1)))) + +extern unsigned long volatile jiffies; + +/** + * __round_jiffies - function to round jiffies to a full second + * @j: the time in (absolute) jiffies that should be rounded + * @cpu: the processor number on which the timeout will happen + * + * __round_jiffies() rounds an absolute time in the future (in jiffies) + * up or down to (approximately) full seconds. This is useful for timers + * for which the exact time they fire does not matter too much, as long as + * they fire approximately every X seconds. + * + * By rounding these timers to whole seconds, all such timers will fire + * at the same time, rather than at various times spread out. The goal + * of this is to have the CPU wake up less, which saves power. + * + * The exact rounding is skewed for each processor to avoid all + * processors firing at the exact same time, which could lead + * to lock contention or spurious cache line bouncing. + * + * The return value is the rounded version of the @j parameter. + */ +static inline unsigned long __round_jiffies(unsigned long j, int cpu) +{ + int rem; + unsigned long original = j; + + /* + * We don't want all cpus firing their timers at once hitting the + * same lock or cachelines, so we skew each extra cpu with an extra + * 3 jiffies. This 3 jiffies came originally from the mm/ code which + * already did this. + * The skew is done by adding 3*cpunr, then round, then subtract this + * extra offset again. + */ + j += cpu * 3; + + rem = j % HZ; + + /* + * If the target jiffie is just after a whole second (which can happen + * due to delays of the timer irq, long irq off times etc etc) then + * we should round down to the whole second, not up. Use 1/4th second + * as cutoff for this rounding as an extreme upper bound for this. + */ + if (rem < HZ/4) /* round down */ + j = j - rem; + else /* round up */ + j = j - rem + HZ; + + /* now that we have rounded, subtract the extra skew again */ + j -= cpu * 3; + + if (j <= jiffies) /* rounding ate our timeout entirely; */ + return original; + return j; +} + + +/** + * round_jiffies - function to round jiffies to a full second + * @j: the time in (absolute) jiffies that should be rounded + * + * round_jiffies() rounds an absolute time in the future (in jiffies) + * up or down to (approximately) full seconds. This is useful for timers + * for which the exact time they fire does not matter too much, as long as + * they fire approximately every X seconds. + * + * By rounding these timers to whole seconds, all such timers will fire + * at the same time, rather than at various times spread out. The goal + * of this is to have the CPU wake up less, which saves power. + * + * The return value is the rounded version of the @j parameter. + */ +static inline unsigned long round_jiffies(unsigned long j) +{ + return __round_jiffies(j, 0); // FIXME +} + +#endif /* linux kernel < 2.6.20 */ + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/types.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/types.h new file mode 100644 index 00000000..c1f375eb --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/types.h @@ -0,0 +1,14 @@ +#ifndef __LINUX_TYPES_WRAPPER_H +#define __LINUX_TYPES_WRAPPER_H 1 + +#include_next + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + +typedef __u16 __bitwise __sum16; +typedef __u32 __bitwise __wsum; + +#endif /* linux kernel < 2.6.20 */ + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/udp.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/udp.h new file mode 100644 index 00000000..6fe4721b --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/udp.h @@ -0,0 +1,13 @@ +#ifndef __LINUX_UDP_WRAPPER_H +#define __LINUX_UDP_WRAPPER_H 1 + +#include_next + +#ifndef HAVE_SKBUFF_HEADER_HELPERS +static inline struct udphdr *udp_hdr(const struct sk_buff *skb) +{ + return (struct udphdr *)skb_transport_header(skb); +} +#endif /* HAVE_SKBUFF_HEADER_HELPERS */ + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/workqueue.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/workqueue.h new file mode 100644 index 00000000..1ac3b6ec --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/linux/workqueue.h @@ -0,0 +1,42 @@ +#ifndef __LINUX_WORKQUEUE_WRAPPER_H +#define __LINUX_WORKQUEUE_WRAPPER_H 1 + +#include_next + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + +#ifdef __KERNEL__ +/* + * initialize a work-struct's func and data pointers: + */ +#undef PREPARE_WORK +#define PREPARE_WORK(_work, _func) \ + do { \ + (_work)->func = (void(*)(void*)) _func; \ + (_work)->data = _work; \ + } while (0) + +/* + * initialize all of a work-struct: + */ +#undef INIT_WORK +#define INIT_WORK(_work, _func) \ + do { \ + INIT_LIST_HEAD(&(_work)->entry); \ + (_work)->pending = 0; \ + PREPARE_WORK((_work), (_func)); \ + init_timer(&(_work)->timer); \ + } while (0) + +#endif /* __KERNEL__ */ + +#endif /* linux kernel < 2.6.20 */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) +/* There is no equivalent to cancel_work_sync() so just flush all + * pending work. */ +#define cancel_work_sync(_work) flush_scheduled_work() +#endif + +#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/net/checksum.h b/openflow/datapath/linux-2.6/compat-2.6/include/net/checksum.h new file mode 100644 index 00000000..c64c6bd0 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/net/checksum.h @@ -0,0 +1,16 @@ +#ifndef __NET_CHECKSUM_WRAPPER_H +#define __NET_CHECKSUM_WRAPPER_H 1 + +#include_next + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + +static inline __wsum csum_unfold(__sum16 n) +{ + return (__force __wsum)n; +} + +#endif /* linux kernel < 2.6.20 */ + +#endif /* checksum.h */ diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/net/genetlink.h b/openflow/datapath/linux-2.6/compat-2.6/include/net/genetlink.h new file mode 100644 index 00000000..57a47316 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/net/genetlink.h @@ -0,0 +1,123 @@ +#ifndef __NET_GENERIC_NETLINK_WRAPPER_H +#define __NET_GENERIC_NETLINK_WRAPPER_H 1 + + +#include +#include_next + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) + +#include + +/*---------------------------------------------------------------------------- + * In 2.6.23, registering of multicast groups was added. Our compatability + * layer just supports registering a single group, since that's all we + * need. + */ + +/** + * struct genl_multicast_group - generic netlink multicast group + * @name: name of the multicast group, names are per-family + * @id: multicast group ID, assigned by the core, to use with + * genlmsg_multicast(). + * @list: list entry for linking + * @family: pointer to family, need not be set before registering + */ +struct genl_multicast_group +{ + struct genl_family *family; /* private */ + struct list_head list; /* private */ + char name[GENL_NAMSIZ]; + u32 id; +}; + +int genl_register_mc_group(struct genl_family *family, + struct genl_multicast_group *grp); +#endif /* linux kernel < 2.6.23 */ + + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) +/** + * genlmsg_msg_size - length of genetlink message not including padding + * @payload: length of message payload + */ +static inline int genlmsg_msg_size(int payload) +{ + return GENL_HDRLEN + payload; +} + +/** + * genlmsg_total_size - length of genetlink message including padding + * @payload: length of message payload + */ +static inline int genlmsg_total_size(int payload) +{ + return NLMSG_ALIGN(genlmsg_msg_size(payload)); +} + +#define genlmsg_multicast(s, p, g, f) \ + genlmsg_multicast_flags((s), (p), (g), (f)) + +static inline int genlmsg_multicast_flags(struct sk_buff *skb, u32 pid, + unsigned int group, gfp_t flags) +{ + int err; + + NETLINK_CB(skb).dst_group = group; + + err = netlink_broadcast(genl_sock, skb, pid, group, flags); + if (err > 0) + err = 0; + + return err; +} +#endif /* linux kernel < 2.6.19 */ + + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + +#define genlmsg_put(skb, p, seq, fam, flg, c) \ + genlmsg_put((skb), (p), (seq), (fam)->id, (fam)->hdrsize, \ + (flg), (c), (fam)->version) + +/** + * genlmsg_put_reply - Add generic netlink header to a reply message + * @skb: socket buffer holding the message + * @info: receiver info + * @family: generic netlink family + * @flags: netlink message flags + * @cmd: generic netlink command + * + * Returns pointer to user specific header + */ +static inline void *genlmsg_put_reply(struct sk_buff *skb, + struct genl_info *info, struct genl_family *family, + int flags, u8 cmd) +{ + return genlmsg_put(skb, info->snd_pid, info->snd_seq, family, + flags, cmd); +} + +/** + * genlmsg_reply - reply to a request + * @skb: netlink message to be sent back + * @info: receiver information + */ +static inline int genlmsg_reply(struct sk_buff *skb, struct genl_info *info) +{ + return genlmsg_unicast(skb, info->snd_pid); +} + +/** + * genlmsg_new - Allocate a new generic netlink message + * @payload: size of the message payload + * @flags: the type of memory to allocate. + */ +static inline struct sk_buff *genlmsg_new(size_t payload, gfp_t flags) +{ + return nlmsg_new(genlmsg_total_size(payload), flags); +} +#endif /* linux kernel < 2.6.20 */ + +#endif /* genetlink.h */ diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/net/netlink.h b/openflow/datapath/linux-2.6/compat-2.6/include/net/netlink.h new file mode 100644 index 00000000..e0d594d7 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/include/net/netlink.h @@ -0,0 +1,22 @@ +#ifndef __NET_NETLINK_WRAPPER_H +#define __NET_NETLINK_WRAPPER_H 1 + +#include_next + +#ifndef HAVE_NLA_NUL_STRING +#define NLA_NUL_STRING NLA_STRING + +static inline int VERIFY_NUL_STRING(struct nlattr *attr) +{ + return (!attr || (nla_len(attr) + && memchr(nla_data(attr), '\0', nla_len(attr))) + ? 0 : EINVAL); +} +#else +static inline int VERIFY_NUL_STRING(struct nlattr *attr) +{ + return 0; +} +#endif /* !HAVE_NLA_NUL_STRING */ + +#endif /* net/netlink.h */ diff --git a/openflow/datapath/linux-2.6/compat-2.6/random32.c b/openflow/datapath/linux-2.6/compat-2.6/random32.c new file mode 100644 index 00000000..981b55c1 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/random32.c @@ -0,0 +1,146 @@ +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) + +/* + This is a maximally equidistributed combined Tausworthe generator + based on code from GNU Scientific Library 1.5 (30 Jun 2004) + + x_n = (s1_n ^ s2_n ^ s3_n) + + s1_{n+1} = (((s1_n & 4294967294) <<12) ^ (((s1_n <<13) ^ s1_n) >>19)) + s2_{n+1} = (((s2_n & 4294967288) << 4) ^ (((s2_n << 2) ^ s2_n) >>25)) + s3_{n+1} = (((s3_n & 4294967280) <<17) ^ (((s3_n << 3) ^ s3_n) >>11)) + + The period of this generator is about 2^88. + + From: P. L'Ecuyer, "Maximally Equidistributed Combined Tausworthe + Generators", Mathematics of Computation, 65, 213 (1996), 203--213. + + This is available on the net from L'Ecuyer's home page, + + http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme.ps + ftp://ftp.iro.umontreal.ca/pub/simulation/lecuyer/papers/tausme.ps + + There is an erratum in the paper "Tables of Maximally + Equidistributed Combined LFSR Generators", Mathematics of + Computation, 68, 225 (1999), 261--269: + http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme2.ps + + ... the k_j most significant bits of z_j must be non- + zero, for each j. (Note: this restriction also applies to the + computer code given in [4], but was mistakenly not mentioned in + that paper.) + + This affects the seeding procedure by imposing the requirement + s1 > 1, s2 > 7, s3 > 15. + +*/ + +#include +#include +#include +#include +#include + +#include "compat26.h" + +struct rnd_state { + u32 s1, s2, s3; +}; + +static struct rnd_state net_rand_state[NR_CPUS]; + +static u32 __random32(struct rnd_state *state) +{ +#define TAUSWORTHE(s,a,b,c,d) ((s&c)<>b) + + state->s1 = TAUSWORTHE(state->s1, 13, 19, 4294967294UL, 12); + state->s2 = TAUSWORTHE(state->s2, 2, 25, 4294967288UL, 4); + state->s3 = TAUSWORTHE(state->s3, 3, 11, 4294967280UL, 17); + + return (state->s1 ^ state->s2 ^ state->s3); +} + +static void __set_random32(struct rnd_state *state, unsigned long s) +{ + if (s == 0) + s = 1; /* default seed is 1 */ + +#define LCG(n) (69069 * n) + state->s1 = LCG(s); + state->s2 = LCG(state->s1); + state->s3 = LCG(state->s2); + + /* "warm it up" */ + __random32(state); + __random32(state); + __random32(state); + __random32(state); + __random32(state); + __random32(state); +} + +/** + * random32 - pseudo random number generator + * + * A 32 bit pseudo-random number is generated using a fast + * algorithm suitable for simulation. This algorithm is NOT + * considered safe for cryptographic use. + */ +u32 random32(void) +{ + return __random32(&net_rand_state[smp_processor_id()]); +} +EXPORT_SYMBOL(random32); + +/** + * srandom32 - add entropy to pseudo random number generator + * @seed: seed value + * + * Add some additional seeding to the random32() pool. + * Note: this pool is per cpu so it only affects current CPU. + */ +void srandom32(u32 entropy) +{ + struct rnd_state *state = &net_rand_state[smp_processor_id()]; + __set_random32(state, state->s1 ^ entropy); +} +EXPORT_SYMBOL(srandom32); + +static int __init random32_reseed(void); + +/* + * Generate some initially weak seeding values to allow + * to start the random32() engine. + */ +int __init random32_init(void) +{ + int i; + + for (i = 0; i < NR_CPUS; i++) { + struct rnd_state *state = &net_rand_state[i]; + __set_random32(state, i + jiffies); + } + random32_reseed(); + return 0; +} + +/* + * Generate better values after random number generator + * is fully initalized. + */ +static int __init random32_reseed(void) +{ + int i; + unsigned long seed; + + for (i = 0; i < NR_CPUS; i++) { + struct rnd_state *state = &net_rand_state[i]; + + get_random_bytes(&seed, sizeof(seed)); + __set_random32(state, seed); + } + return 0; +} + +#endif /* kernel < 2.6.19 */ diff --git a/openflow/datapath/linux-2.6/compat-2.6/veth.c b/openflow/datapath/linux-2.6/compat-2.6/veth.c new file mode 100644 index 00000000..3cda3365 --- /dev/null +++ b/openflow/datapath/linux-2.6/compat-2.6/veth.c @@ -0,0 +1,537 @@ +/* veth driver port to Linux 2.6.18 */ + +/* + * drivers/net/veth.c + * + * Copyright (C) 2007, 2009 OpenVZ http://openvz.org, SWsoft Inc + * + * Author: Pavel Emelianov + * Ethtool interface from: Eric W. Biederman + * + */ + +#include +#include +#include +#include + +#include +#include + +#define DRV_NAME "veth" +#define DRV_VERSION "1.0" + +struct veth_net_stats { + unsigned long rx_packets; + unsigned long tx_packets; + unsigned long rx_bytes; + unsigned long tx_bytes; + unsigned long tx_dropped; +}; + +struct veth_priv { + struct net_device *peer; + struct net_device *dev; + struct list_head list; + struct veth_net_stats *stats; + unsigned ip_summed; + struct net_device_stats dev_stats; +}; + +static LIST_HEAD(veth_list); + +/* + * ethtool interface + */ + +static struct { + const char string[ETH_GSTRING_LEN]; +} ethtool_stats_keys[] = { + { "peer_ifindex" }, +}; + +static int veth_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + cmd->supported = 0; + cmd->advertising = 0; + cmd->speed = SPEED_10000; + cmd->duplex = DUPLEX_FULL; + cmd->port = PORT_TP; + cmd->phy_address = 0; + cmd->transceiver = XCVR_INTERNAL; + cmd->autoneg = AUTONEG_DISABLE; + cmd->maxtxpkt = 0; + cmd->maxrxpkt = 0; + return 0; +} + +static void veth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + strcpy(info->driver, DRV_NAME); + strcpy(info->version, DRV_VERSION); + strcpy(info->fw_version, "N/A"); +} + +static void veth_get_strings(struct net_device *dev, u32 stringset, u8 *buf) +{ + switch(stringset) { + case ETH_SS_STATS: + memcpy(buf, ðtool_stats_keys, sizeof(ethtool_stats_keys)); + break; + } +} + +static void veth_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + struct veth_priv *priv; + + priv = netdev_priv(dev); + data[0] = priv->peer->ifindex; +} + +static u32 veth_get_rx_csum(struct net_device *dev) +{ + struct veth_priv *priv; + + priv = netdev_priv(dev); + return priv->ip_summed == CHECKSUM_UNNECESSARY; +} + +static int veth_set_rx_csum(struct net_device *dev, u32 data) +{ + struct veth_priv *priv; + + priv = netdev_priv(dev); + priv->ip_summed = data ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE; + return 0; +} + +static u32 veth_get_tx_csum(struct net_device *dev) +{ + return (dev->features & NETIF_F_NO_CSUM) != 0; +} + +static int veth_set_tx_csum(struct net_device *dev, u32 data) +{ + if (data) + dev->features |= NETIF_F_NO_CSUM; + else + dev->features &= ~NETIF_F_NO_CSUM; + return 0; +} + +static struct ethtool_ops veth_ethtool_ops = { + .get_settings = veth_get_settings, + .get_drvinfo = veth_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_rx_csum = veth_get_rx_csum, + .set_rx_csum = veth_set_rx_csum, + .get_tx_csum = veth_get_tx_csum, + .set_tx_csum = veth_set_tx_csum, + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, + .get_strings = veth_get_strings, + .get_ethtool_stats = veth_get_ethtool_stats, +}; + +/* + * xmit + */ + +static int veth_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct net_device *rcv = NULL; + struct veth_priv *priv, *rcv_priv; + struct veth_net_stats *stats; + int length, cpu; + + skb_orphan(skb); + + priv = netdev_priv(dev); + rcv = priv->peer; + rcv_priv = netdev_priv(rcv); + + cpu = smp_processor_id(); + stats = per_cpu_ptr(priv->stats, cpu); + + if (!(rcv->flags & IFF_UP)) + goto outf; + + skb->dev = rcv; + skb->pkt_type = PACKET_HOST; + skb->protocol = eth_type_trans(skb, rcv); + if (dev->features & NETIF_F_NO_CSUM) + skb->ip_summed = rcv_priv->ip_summed; + + dst_release(skb->dst); + skb->dst = NULL; + secpath_reset(skb); + nf_reset(skb); + + length = skb->len; + + stats->tx_bytes += length; + stats->tx_packets++; + + stats = per_cpu_ptr(rcv_priv->stats, cpu); + stats->rx_bytes += length; + stats->rx_packets++; + + netif_rx(skb); + return 0; + +outf: + kfree_skb(skb); + stats->tx_dropped++; + return 0; +} + +/* + * general routines + */ + +static struct net_device_stats *veth_get_stats(struct net_device *dev) +{ + struct veth_priv *priv; + struct net_device_stats *dev_stats; + int cpu; + struct veth_net_stats *stats; + + priv = netdev_priv(dev); + dev_stats = &priv->dev_stats; + + dev_stats->rx_packets = 0; + dev_stats->tx_packets = 0; + dev_stats->rx_bytes = 0; + dev_stats->tx_bytes = 0; + dev_stats->tx_dropped = 0; + + for_each_online_cpu(cpu) { + stats = per_cpu_ptr(priv->stats, cpu); + + dev_stats->rx_packets += stats->rx_packets; + dev_stats->tx_packets += stats->tx_packets; + dev_stats->rx_bytes += stats->rx_bytes; + dev_stats->tx_bytes += stats->tx_bytes; + dev_stats->tx_dropped += stats->tx_dropped; + } + + return dev_stats; +} + +static int veth_open(struct net_device *dev) +{ + struct veth_priv *priv; + + priv = netdev_priv(dev); + if (priv->peer == NULL) + return -ENOTCONN; + + if (priv->peer->flags & IFF_UP) { + netif_carrier_on(dev); + netif_carrier_on(priv->peer); + } + return 0; +} + +static int veth_dev_init(struct net_device *dev) +{ + struct veth_net_stats *stats; + struct veth_priv *priv; + + stats = alloc_percpu(struct veth_net_stats); + if (stats == NULL) + return -ENOMEM; + + priv = netdev_priv(dev); + priv->stats = stats; + return 0; +} + +static void veth_dev_free(struct net_device *dev) +{ + struct veth_priv *priv; + + priv = netdev_priv(dev); + free_percpu(priv->stats); + free_netdev(dev); +} + +static void veth_setup(struct net_device *dev) +{ + ether_setup(dev); + + dev->hard_start_xmit = veth_xmit; + dev->get_stats = veth_get_stats; + dev->open = veth_open; + dev->ethtool_ops = &veth_ethtool_ops; + dev->features |= NETIF_F_LLTX; + dev->init = veth_dev_init; + dev->destructor = veth_dev_free; +} + +static void veth_change_state(struct net_device *dev) +{ + struct net_device *peer; + struct veth_priv *priv; + + priv = netdev_priv(dev); + peer = priv->peer; + + if (netif_carrier_ok(peer)) { + if (!netif_carrier_ok(dev)) + netif_carrier_on(dev); + } else { + if (netif_carrier_ok(dev)) + netif_carrier_off(dev); + } +} + +static int veth_device_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct net_device *dev = ptr; + + if (dev->open != veth_open) + goto out; + + switch (event) { + case NETDEV_CHANGE: + veth_change_state(dev); + break; + } +out: + return NOTIFY_DONE; +} + +static struct notifier_block veth_notifier_block __read_mostly = { + .notifier_call = veth_device_event, +}; + +/* + * netlink interface + */ + +static int veth_newlink(const char *devname, const char *peername) +{ + int err; + const char *names[2]; + struct net_device *devs[2]; + int i; + + names[0] = devname; + names[1] = peername; + devs[0] = devs[1] = NULL; + + for (i = 0; i < 2; i++) { + struct net_device *dev; + + err = -ENOMEM; + devs[i] = alloc_netdev(sizeof(struct veth_priv), + names[i], veth_setup); + if (!devs[i]) { + goto err; + } + + dev = devs[i]; + + if (strchr(dev->name, '%')) { + err = dev_alloc_name(dev, dev->name); + if (err < 0) + goto err; + } + random_ether_addr(dev->dev_addr); + + err = register_netdevice(dev); + if (err < 0) + goto err; + + netif_carrier_off(dev); + } + + /* + * tie the devices together + */ + + for (i = 0; i < 2; i++) { + struct veth_priv *priv = netdev_priv(devs[i]); + priv->dev = devs[i]; + priv->peer = devs[!i]; + if (!i) + list_add(&priv->list, &veth_list); + else + INIT_LIST_HEAD(&priv->list); + } + return 0; + +err: + for (i = 0; i < 2; i++) { + if (devs[i]) { + if (devs[i]->reg_state != NETREG_UNINITIALIZED) + unregister_netdevice(devs[i]); + else + free_netdev(devs[i]); + } + } + return err; +} + +static void veth_dellink(struct net_device *dev) +{ + struct veth_priv *priv; + struct net_device *peer; + + priv = netdev_priv(dev); + peer = priv->peer; + + if (!list_empty(&priv->list)) + list_del(&priv->list); + + priv = netdev_priv(peer); + if (!list_empty(&priv->list)) + list_del(&priv->list); + + unregister_netdevice(dev); + unregister_netdevice(peer); +} + +/* + * sysfs + */ + +/* + * "show" function for the veth_pairs attribute. + * The class parameter is ignored. + */ +static ssize_t veth_show_veth_pairs(struct class *cls, char *buffer) +{ + int res = 0; + struct veth_priv *priv; + + list_for_each_entry(priv, &veth_list, list) { + if (res > (PAGE_SIZE - (IFNAMSIZ * 2 + 1))) { + /* not enough space for another interface name */ + if ((PAGE_SIZE - res) > 10) + res = PAGE_SIZE - 10; + res += sprintf(buffer + res, "++more++"); + break; + } + res += sprintf(buffer + res, "%s,%s ", + priv->dev->name, priv->peer->name); + } + res += sprintf(buffer + res, "\n"); + res++; + return res; +} + +/* + * "store" function for the veth_pairs attribute. This is what + * creates and deletes veth pairs. + * + * The class parameter is ignored. + * + */ +static ssize_t veth_store_veth_pairs(struct class *cls, const char *buffer, + size_t count) +{ + int c = *buffer++; + int retval; + printk("1\n"); + if (c == '+') { + char devname[IFNAMSIZ + 1] = ""; + char peername[IFNAMSIZ + 1] = ""; + char *comma = strchr(buffer, ','); + printk("2\n"); + if (!comma) + goto err_no_cmd; + strncat(devname, buffer, + min_t(int, sizeof devname, comma - buffer)); + strncat(peername, comma + 1, + min_t(int, sizeof peername, strcspn(comma + 1, "\n"))); + printk("3 '%s' '%s'\n", devname, peername); + if (!dev_valid_name(devname) || !dev_valid_name(peername)) + goto err_no_cmd; + printk("4\n"); + rtnl_lock(); + retval = veth_newlink(devname, peername); + rtnl_unlock(); + return retval ? retval : count; + } else if (c == '-') { + struct net_device *dev; + + rtnl_lock(); + dev = dev_get_by_name(buffer); + if (!dev) + retval = -ENODEV; + else if (dev->init != veth_dev_init) + retval = -EINVAL; + else { + veth_dellink(dev); + retval = count; + } + rtnl_unlock(); + + return retval; + } + +err_no_cmd: + printk(KERN_ERR DRV_NAME ": no command found in veth_pairs. Use +ifname,peername or -ifname.\n"); + return -EPERM; +} + +/* class attribute for veth_pairs file. This ends up in /sys/class/net */ +static CLASS_ATTR(veth_pairs, S_IWUSR | S_IRUGO, + veth_show_veth_pairs, veth_store_veth_pairs); + +static struct class *netdev_class; + +/* + * Initialize sysfs. This sets up the veth_pairs file in + * /sys/class/net. + */ +int veth_create_sysfs(void) +{ + struct net_device *dev = dev_get_by_name("lo"); + if (!dev) + return -ESRCH; + netdev_class = dev->class_dev.class; + if (!netdev_class) + return -ENODEV; + + return class_create_file(netdev_class, &class_attr_veth_pairs); +} + +/* + * Remove /sys/class/net/veth_pairs. + */ +void veth_destroy_sysfs(void) +{ + class_remove_file(netdev_class, &class_attr_veth_pairs); +} + + + +/* + * init/fini + */ + +static __init int veth_init(void) +{ + int retval = veth_create_sysfs(); + if (retval) + return retval; + register_netdevice_notifier(&veth_notifier_block); + return 0; +} + +static __exit void veth_exit(void) +{ + unregister_netdevice_notifier(&veth_notifier_block); +} + +module_init(veth_init); +module_exit(veth_exit); + +MODULE_DESCRIPTION("Virtual Ethernet Tunnel"); +MODULE_LICENSE("GPL v2"); diff --git a/openflow/datapath/linux-2.6/config/config-linux-2.6.23-rc9-kvm b/openflow/datapath/linux-2.6/config/config-linux-2.6.23-rc9-kvm new file mode 100644 index 00000000..f287cf72 --- /dev/null +++ b/openflow/datapath/linux-2.6/config/config-linux-2.6.23-rc9-kvm @@ -0,0 +1,1408 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.23-rc9 +# Fri Oct 19 15:08:37 2007 +# +CONFIG_X86_32=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_CLOCKSOURCE_WATCHDOG=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_SEMAPHORE_SLEEPERS=y +CONFIG_X86=y +CONFIG_MMU=y +CONFIG_ZONE_DMA=y +CONFIG_QUICKLIST=y +CONFIG_GENERIC_ISA_DMA=y +CONFIG_GENERIC_IOMAP=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_DMI=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +# CONFIG_USER_NS is not set +# CONFIG_AUDIT is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_CPUSETS is not set +CONFIG_SYSFS_DEPRECATED=y +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +# CONFIG_EMBEDDED is not set +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_KALLSYMS_EXTRA_PASS=y +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +CONFIG_LBD=y +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_LSF=y +# CONFIG_BLK_DEV_BSG is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + +# +# Processor type and features +# +# CONFIG_TICK_ONESHOT is not set +# CONFIG_NO_HZ is not set +# CONFIG_HIGH_RES_TIMERS is not set +CONFIG_SMP=y +CONFIG_X86_PC=y +# CONFIG_X86_ELAN is not set +# CONFIG_X86_VOYAGER is not set +# CONFIG_X86_NUMAQ is not set +# CONFIG_X86_SUMMIT is not set +# CONFIG_X86_BIGSMP is not set +# CONFIG_X86_VISWS is not set +# CONFIG_X86_GENERICARCH is not set +# CONFIG_X86_ES7000 is not set +# CONFIG_PARAVIRT is not set +# CONFIG_M386 is not set +CONFIG_M486=y +# CONFIG_M586 is not set +# CONFIG_M586TSC is not set +# CONFIG_M586MMX is not set +# CONFIG_M686 is not set +# CONFIG_MPENTIUMII is not set +# CONFIG_MPENTIUMIII is not set +# CONFIG_MPENTIUMM is not set +# CONFIG_MCORE2 is not set +# CONFIG_MPENTIUM4 is not set +# CONFIG_MK6 is not set +# CONFIG_MK7 is not set +# CONFIG_MK8 is not set +# CONFIG_MCRUSOE is not set +# CONFIG_MEFFICEON is not set +# CONFIG_MWINCHIPC6 is not set +# CONFIG_MWINCHIP2 is not set +# CONFIG_MWINCHIP3D is not set +# CONFIG_MGEODEGX1 is not set +# CONFIG_MGEODE_LX is not set +# CONFIG_MCYRIXIII is not set +# CONFIG_MVIAC3_2 is not set +# CONFIG_MVIAC7 is not set +CONFIG_X86_GENERIC=y +CONFIG_X86_CMPXCHG=y +CONFIG_X86_L1_CACHE_SHIFT=7 +CONFIG_X86_XADD=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_X86_PPRO_FENCE=y +CONFIG_X86_F00F_BUG=y +CONFIG_X86_WP_WORKS_OK=y +CONFIG_X86_INVLPG=y +CONFIG_X86_BSWAP=y +CONFIG_X86_POPAD_OK=y +CONFIG_X86_ALIGNMENT_16=y +CONFIG_X86_INTEL_USERCOPY=y +CONFIG_X86_MINIMUM_CPU_FAMILY=4 +# CONFIG_HPET_TIMER is not set +CONFIG_NR_CPUS=8 +# CONFIG_SCHED_SMT is not set +CONFIG_SCHED_MC=y +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_PREEMPT_BKL=y +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_IO_APIC=y +# CONFIG_X86_MCE is not set +CONFIG_VM86=y +# CONFIG_TOSHIBA is not set +# CONFIG_I8K is not set +# CONFIG_X86_REBOOTFIXUPS is not set +# CONFIG_MICROCODE is not set +# CONFIG_X86_MSR is not set +# CONFIG_X86_CPUID is not set + +# +# Firmware Drivers +# +# CONFIG_EDD is not set +# CONFIG_DELL_RBU is not set +# CONFIG_DCDBAS is not set +CONFIG_DMIID=y +# CONFIG_NOHIGHMEM is not set +CONFIG_HIGHMEM4G=y +# CONFIG_HIGHMEM64G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_HIGHMEM=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_SPARSEMEM_STATIC=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_NR_QUICK=1 +CONFIG_VIRT_TO_BUS=y +# CONFIG_HIGHPTE is not set +# CONFIG_MATH_EMULATION is not set +# CONFIG_MTRR is not set +CONFIG_IRQBALANCE=y +CONFIG_SECCOMP=y +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +# CONFIG_KEXEC is not set +# CONFIG_CRASH_DUMP is not set +CONFIG_PHYSICAL_START=0x100000 +# CONFIG_RELOCATABLE is not set +CONFIG_PHYSICAL_ALIGN=0x100000 +CONFIG_HOTPLUG_CPU=y +CONFIG_COMPAT_VDSO=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y + +# +# Power management options (ACPI, APM) +# +CONFIG_PM=y +# CONFIG_PM_LEGACY is not set +# CONFIG_PM_DEBUG is not set +CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_SLEEP=y +CONFIG_SUSPEND_SMP_POSSIBLE=y +CONFIG_SUSPEND=y +CONFIG_HIBERNATION_SMP_POSSIBLE=y +# CONFIG_HIBERNATION is not set +# CONFIG_ACPI is not set +CONFIG_APM=y +# CONFIG_APM_IGNORE_USER_SUSPEND is not set +# CONFIG_APM_DO_ENABLE is not set +# CONFIG_APM_CPU_IDLE is not set +# CONFIG_APM_DISPLAY_BLANK is not set +# CONFIG_APM_ALLOW_INTS is not set +# CONFIG_APM_REAL_MODE_POWER_OFF is not set + +# +# CPU Frequency scaling +# +# CONFIG_CPU_FREQ is not set + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +CONFIG_PCI=y +# CONFIG_PCI_GOBIOS is not set +# CONFIG_PCI_GOMMCONFIG is not set +# CONFIG_PCI_GODIRECT is not set +CONFIG_PCI_GOANY=y +CONFIG_PCI_BIOS=y +CONFIG_PCI_DIRECT=y +# CONFIG_PCIEPORTBUS is not set +CONFIG_ARCH_SUPPORTS_MSI=y +# CONFIG_PCI_MSI is not set +# CONFIG_PCI_DEBUG is not set +CONFIG_HT_IRQ=y +CONFIG_ISA_DMA_API=y +CONFIG_ISA=y +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_SCx200 is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set +# CONFIG_HOTPLUG_PCI is not set + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_MISC=m + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +CONFIG_XFRM=y +CONFIG_XFRM_USER=m +CONFIG_XFRM_SUB_POLICY=y +CONFIG_XFRM_MIGRATE=y +CONFIG_NET_KEY=m +CONFIG_NET_KEY_MIGRATE=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_ASK_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +# CONFIG_IP_ROUTE_VERBOSE is not set +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INET_TUNNEL=m +CONFIG_INET_XFRM_MODE_TRANSPORT=m +CONFIG_INET_XFRM_MODE_TUNNEL=m +CONFIG_INET_XFRM_MODE_BEET=m +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_BIC=m +CONFIG_TCP_CONG_CUBIC=y +CONFIG_TCP_CONG_WESTWOOD=m +CONFIG_TCP_CONG_HTCP=m +CONFIG_TCP_CONG_HSTCP=m +CONFIG_TCP_CONG_HYBLA=m +CONFIG_TCP_CONG_VEGAS=m +CONFIG_TCP_CONG_SCALABLE=m +CONFIG_TCP_CONG_LP=m +CONFIG_TCP_CONG_VENO=m +CONFIG_TCP_CONG_YEAH=m +CONFIG_TCP_CONG_ILLINOIS=m +# CONFIG_DEFAULT_BIC is not set +CONFIG_DEFAULT_CUBIC=y +# CONFIG_DEFAULT_HTCP is not set +# CONFIG_DEFAULT_VEGAS is not set +# CONFIG_DEFAULT_WESTWOOD is not set +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_TCP_CONG="cubic" +CONFIG_TCP_MD5SIG=y +# CONFIG_IP_VS is not set +CONFIG_IPV6=m +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +# CONFIG_IPV6_MIP6 is not set +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET6_TUNNEL=m +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=m +CONFIG_IPV6_TUNNEL=m +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_NETWORK_SECMARK=y +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_BRIDGE_NETFILTER=y + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +CONFIG_NETFILTER_NETLINK_LOG=m +CONFIG_NF_CONNTRACK_ENABLED=m +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CT_ACCT=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_GRE=m +CONFIG_NF_CT_PROTO_SCTP=m +# CONFIG_NF_CT_PROTO_UDPLITE is not set +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_PPTP=m +CONFIG_NF_CONNTRACK_SANE=m +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_NETLINK=m +CONFIG_NETFILTER_XTABLES=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set +# CONFIG_NETFILTER_XT_TARGET_TRACE is not set +CONFIG_NETFILTER_XT_TARGET_SECMARK=m +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_DCCP=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_SCTP=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +# CONFIG_NETFILTER_XT_MATCH_U32 is not set +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m + +# +# IP: Netfilter Configuration +# +CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +# CONFIG_IP_NF_QUEUE is not set +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_IPRANGE=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_MATCH_ADDRTYPE=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_NF_NAT=m +CONFIG_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_SAME=m +CONFIG_NF_NAT_SNMP_BASIC=m +CONFIG_NF_NAT_PROTO_GRE=m +CONFIG_NF_NAT_FTP=m +CONFIG_NF_NAT_IRC=m +CONFIG_NF_NAT_TFTP=m +CONFIG_NF_NAT_AMANDA=m +CONFIG_NF_NAT_PPTP=m +CONFIG_NF_NAT_H323=m +CONFIG_NF_NAT_SIP=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_TARGET_CLUSTERIP=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m + +# +# IPv6: Netfilter Configuration (EXPERIMENTAL) +# +CONFIG_NF_CONNTRACK_IPV6=m +# CONFIG_IP6_NF_QUEUE is not set +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_OWNER=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_AH=m +CONFIG_IP6_NF_MATCH_MH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_HL=m +CONFIG_IP6_NF_RAW=m + +# +# DECnet: Netfilter Configuration +# +# CONFIG_DECNET_NF_GRABULATOR is not set + +# +# Bridge: Netfilter Configuration +# +# CONFIG_BRIDGE_NF_EBTABLES is not set +CONFIG_IP_DCCP=m +CONFIG_INET_DCCP_DIAG=m +CONFIG_IP_DCCP_ACKVEC=y + +# +# DCCP CCIDs Configuration (EXPERIMENTAL) +# +CONFIG_IP_DCCP_CCID2=m +# CONFIG_IP_DCCP_CCID2_DEBUG is not set +CONFIG_IP_DCCP_CCID3=m +CONFIG_IP_DCCP_TFRC_LIB=m +# CONFIG_IP_DCCP_CCID3_DEBUG is not set +CONFIG_IP_DCCP_CCID3_RTO=100 + +# +# DCCP Kernel Hacking +# +# CONFIG_IP_DCCP_DEBUG is not set +CONFIG_IP_SCTP=m +# CONFIG_SCTP_DBG_MSG is not set +# CONFIG_SCTP_DBG_OBJCNT is not set +# CONFIG_SCTP_HMAC_NONE is not set +# CONFIG_SCTP_HMAC_SHA1 is not set +CONFIG_SCTP_HMAC_MD5=y +CONFIG_TIPC=m +CONFIG_TIPC_ADVANCED=y +CONFIG_TIPC_ZONES=3 +CONFIG_TIPC_CLUSTERS=1 +CONFIG_TIPC_NODES=255 +CONFIG_TIPC_SLAVE_NODES=0 +CONFIG_TIPC_PORTS=8191 +CONFIG_TIPC_LOG=0 +# CONFIG_TIPC_DEBUG is not set +CONFIG_ATM=m +CONFIG_ATM_CLIP=m +# CONFIG_ATM_CLIP_NO_ICMP is not set +CONFIG_ATM_LANE=m +# CONFIG_ATM_MPOA is not set +CONFIG_ATM_BR2684=m +CONFIG_ATM_BR2684_IPFILTER=y +CONFIG_BRIDGE=m +CONFIG_VLAN_8021Q=m +CONFIG_DECNET=m +# CONFIG_DECNET_ROUTER is not set +CONFIG_LLC=m +CONFIG_LLC2=m +CONFIG_IPX=m +CONFIG_IPX_INTERN=y +CONFIG_ATALK=m +CONFIG_DEV_APPLETALK=m +# CONFIG_LTPC is not set +# CONFIG_COPS is not set +CONFIG_IPDDP=m +CONFIG_IPDDP_ENCAP=y +CONFIG_IPDDP_DECAP=y +CONFIG_X25=m +CONFIG_LAPB=m +CONFIG_ECONET=m +CONFIG_ECONET_AUNUDP=y +CONFIG_ECONET_NATIVE=y +CONFIG_WAN_ROUTER=m + +# +# QoS and/or fair queueing +# +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_FIFO=y + +# +# Queueing/Scheduling +# +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_ATM=m +CONFIG_NET_SCH_PRIO=m +# CONFIG_NET_SCH_RR is not set +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_SCH_INGRESS=m + +# +# Classification +# +CONFIG_NET_CLS=y +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_CLS_U32_PERF=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +CONFIG_NET_EMATCH_CMP=m +CONFIG_NET_EMATCH_NBYTE=m +CONFIG_NET_EMATCH_U32=m +CONFIG_NET_EMATCH_META=m +CONFIG_NET_EMATCH_TEXT=m +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=m +CONFIG_NET_ACT_GACT=m +CONFIG_GACT_PROB=y +CONFIG_NET_ACT_MIRRED=m +CONFIG_NET_ACT_IPT=m +CONFIG_NET_ACT_PEDIT=m +CONFIG_NET_ACT_SIMP=m +# CONFIG_NET_CLS_POLICE is not set +CONFIG_NET_CLS_IND=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +CONFIG_AF_RXRPC=m +# CONFIG_AF_RXRPC_DEBUG is not set +CONFIG_RXKAD=m +CONFIG_FIB_RULES=y + +# +# Wireless +# +# CONFIG_CFG80211 is not set +# CONFIG_WIRELESS_EXT is not set +# CONFIG_MAC80211 is not set +# CONFIG_IEEE80211 is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +CONFIG_CONNECTOR=m +# CONFIG_MTD is not set +CONFIG_PARPORT=m +CONFIG_PARPORT_PC=m +# CONFIG_PARPORT_SERIAL is not set +# CONFIG_PARPORT_PC_FIFO is not set +# CONFIG_PARPORT_PC_SUPERIO is not set +# CONFIG_PARPORT_GSC is not set +# CONFIG_PARPORT_AX88796 is not set +# CONFIG_PARPORT_1284 is not set +# CONFIG_PNP is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_NBD=m +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=m +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_MISC_DEVICES=y +# CONFIG_IBM_ASM is not set +# CONFIG_PHANTOM is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +# CONFIG_BLK_DEV_HD_IDE is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_IDE_TASK_IOCTL is not set +CONFIG_IDE_PROC_FS=y + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=y +# CONFIG_BLK_DEV_CMD640 is not set +CONFIG_BLK_DEV_IDEPCI=y +# CONFIG_IDEPCI_SHARE_IRQ is not set +CONFIG_IDEPCI_PCIBUS_ORDER=y +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_GENERIC is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_IDEDMA_PCI is not set +# CONFIG_IDE_ARM is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_BLK_DEV_IDEDMA is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_DMA is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_IEEE1394 is not set +# CONFIG_I2O is not set +# CONFIG_MACINTOSH_DRIVERS is not set +CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set +# CONFIG_IFB is not set +CONFIG_DUMMY=m +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +CONFIG_TUN=m +# CONFIG_ARCNET is not set +# CONFIG_PHYLIB is not set +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_NET_TULIP is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +CONFIG_PCNET32=y +# CONFIG_PCNET32_NAPI is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_AC3200 is not set +# CONFIG_APRICOT is not set +# CONFIG_B44 is not set +# CONFIG_FORCEDETH is not set +# CONFIG_CS89x0 is not set +# CONFIG_DGRS is not set +# CONFIG_EEPRO100 is not set +# CONFIG_E100 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +CONFIG_NE2K_PCI=y +CONFIG_8139CP=y +# CONFIG_8139TOO is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_SC92031 is not set +# CONFIG_NET_POCKET is not set +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set +# CONFIG_TR is not set + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set +# CONFIG_WAN is not set +CONFIG_ATM_DRIVERS=y +# CONFIG_ATM_DUMMY is not set +# CONFIG_ATM_TCP is not set +# CONFIG_ATM_LANAI is not set +# CONFIG_ATM_ENI is not set +# CONFIG_ATM_FIRESTREAM is not set +# CONFIG_ATM_ZATM is not set +# CONFIG_ATM_NICSTAR is not set +# CONFIG_ATM_IDT77252 is not set +# CONFIG_ATM_AMBASSADOR is not set +# CONFIG_ATM_HORIZON is not set +# CONFIG_ATM_IA is not set +# CONFIG_ATM_FORE200E_MAYBE is not set +# CONFIG_ATM_HE is not set +# CONFIG_FDDI is not set +CONFIG_HIPPI=y +# CONFIG_ROADRUNNER is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_LIFEBOOK=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_APPLETOUCH is not set +# CONFIG_MOUSE_INPORT is not set +# CONFIG_MOUSE_LOGIBM is not set +# CONFIG_MOUSE_PC110PAD is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PARKBD is not set +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_PRINTER is not set +# CONFIG_PPDEV is not set +# CONFIG_TIPAR is not set +# CONFIG_IPMI_HANDLER is not set +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_NOWAYOUT=y + +# +# Watchdog Device Drivers +# +CONFIG_SOFT_WATCHDOG=y +# CONFIG_ACQUIRE_WDT is not set +# CONFIG_ADVANTECH_WDT is not set +# CONFIG_ALIM1535_WDT is not set +# CONFIG_ALIM7101_WDT is not set +# CONFIG_SC520_WDT is not set +# CONFIG_EUROTECH_WDT is not set +# CONFIG_IB700_WDT is not set +# CONFIG_IBMASR is not set +# CONFIG_WAFER_WDT is not set +# CONFIG_I6300ESB_WDT is not set +# CONFIG_ITCO_WDT is not set +# CONFIG_SC1200_WDT is not set +# CONFIG_PC87413_WDT is not set +# CONFIG_60XX_WDT is not set +# CONFIG_SBC8360_WDT is not set +# CONFIG_CPU5_WDT is not set +# CONFIG_SMSC37B787_WDT is not set +# CONFIG_W83627HF_WDT is not set +# CONFIG_W83697HF_WDT is not set +# CONFIG_W83877F_WDT is not set +# CONFIG_W83977F_WDT is not set +# CONFIG_MACHZ_WDT is not set +# CONFIG_SBC_EPX_C3_WATCHDOG is not set + +# +# ISA-based Watchdog Cards +# +# CONFIG_PCWATCHDOG is not set +# CONFIG_MIXCOMWD is not set +# CONFIG_WDT is not set + +# +# PCI-based Watchdog Cards +# +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_WDTPCI is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_SONYPI is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_MWAVE is not set +# CONFIG_PC8736x_GPIO is not set +# CONFIG_NSC_GPIO is not set +# CONFIG_CS5535_GPIO is not set +CONFIG_RAW_DRIVER=m +CONFIG_MAX_RAW_DEVS=256 +# CONFIG_HANGCHECK_TIMER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set +CONFIG_DEVPORT=y +# CONFIG_I2C is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ABITUGURU3 is not set +# CONFIG_SENSORS_K8TEMP is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_CORETEMP is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_HDAPS is not set +# CONFIG_SENSORS_APPLESMC is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DVB_CORE is not set +# CONFIG_DAB is not set + +# +# Graphics support +# +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_VGASTATE is not set +CONFIG_VIDEO_OUTPUT_CONTROL=m +# CONFIG_FB is not set + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +# CONFIG_VGACON_SOFT_SCROLLBACK is not set +# CONFIG_VIDEO_SELECT is not set +# CONFIG_MDA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y + +# +# Sound +# +# CONFIG_SOUND is not set +CONFIG_HID_SUPPORT=y +# CONFIG_HID is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +# CONFIG_USB is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set +# CONFIG_MMC is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_INFINIBAND is not set +# CONFIG_EDAC is not set +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# +# CONFIG_AUXDISPLAY is not set +CONFIG_VIRTUALIZATION=y +# CONFIG_KVM is not set + +# +# Userspace I/O +# +# CONFIG_UIO is not set + +# +# File systems +# +# CONFIG_EXT2_FS is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +CONFIG_ROMFS_FS=m +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set +CONFIG_GENERIC_ACL=y + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=y +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +CONFIG_CONFIGFS_FS=m + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_ECRYPT_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_CRAMFS=m +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_SUNRPC_BIND34 is not set +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# Distributed Lock Manager +# +# CONFIG_DLM is not set +CONFIG_INSTRUMENTATION=y +# CONFIG_PROFILING is not set +# CONFIG_KPROBES is not set + +# +# Kernel hacking +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +# CONFIG_PRINTK_TIME is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +CONFIG_DEBUG_SLAB=y +CONFIG_DEBUG_SLAB_LEAK=y +CONFIG_DEBUG_RT_MUTEXES=y +CONFIG_DEBUG_PI_LIST=y +# CONFIG_RT_MUTEX_TESTER is not set +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_MUTEXES=y +CONFIG_DEBUG_LOCK_ALLOC=y +CONFIG_PROVE_LOCKING=y +CONFIG_LOCKDEP=y +CONFIG_LOCK_STAT=y +# CONFIG_DEBUG_LOCKDEP is not set +CONFIG_TRACE_IRQFLAGS=y +CONFIG_DEBUG_SPINLOCK_SLEEP=y +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +CONFIG_STACKTRACE=y +CONFIG_DEBUG_KOBJECT=y +CONFIG_DEBUG_HIGHMEM=y +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_VM=y +CONFIG_DEBUG_LIST=y +CONFIG_FRAME_POINTER=y +CONFIG_FORCED_INLINING=y +CONFIG_RCU_TORTURE_TEST=m +# CONFIG_FAULT_INJECTION is not set +CONFIG_EARLY_PRINTK=y +CONFIG_DEBUG_STACKOVERFLOW=y +# CONFIG_DEBUG_STACK_USAGE is not set +CONFIG_DEBUG_PAGEALLOC=y +CONFIG_DEBUG_RODATA=y +CONFIG_4KSTACKS=y +CONFIG_X86_FIND_SMP_CONFIG=y +CONFIG_X86_MPPARSE=y +CONFIG_DOUBLEFAULT=y + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_KEYS_DEBUG_PROC_KEYS is not set +# CONFIG_SECURITY is not set +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_HASH=m +CONFIG_CRYPTO_MANAGER=m +CONFIG_CRYPTO_HMAC=m +# CONFIG_CRYPTO_XCBC is not set +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +CONFIG_CRYPTO_GF128MUL=m +# CONFIG_CRYPTO_ECB is not set +CONFIG_CRYPTO_CBC=m +CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_LRW=m +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_FCRYPT=m +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_TWOFISH_586 is not set +# CONFIG_CRYPTO_SERPENT is not set +CONFIG_CRYPTO_AES=m +# CONFIG_CRYPTO_AES_586 is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +CONFIG_CRYPTO_TEA=m +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_DEFLATE=m +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_TEST is not set +CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_DEV_PADLOCK is not set +# CONFIG_CRYPTO_DEV_GEODE is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_CRC_CCITT=m +CONFIG_CRC16=m +CONFIG_CRC_ITU_T=m +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=m +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=m +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=m +CONFIG_TEXTSEARCH_BM=m +CONFIG_TEXTSEARCH_FSM=m +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_PENDING_IRQ=y +CONFIG_X86_SMP=y +CONFIG_X86_HT=y +CONFIG_X86_BIOS_REBOOT=y +CONFIG_X86_TRAMPOLINE=y +CONFIG_KTIME_SCALAR=y diff --git a/openflow/datapath/openflow-ext.c b/openflow/datapath/openflow-ext.c new file mode 100644 index 00000000..e9f87a8b --- /dev/null +++ b/openflow/datapath/openflow-ext.c @@ -0,0 +1,83 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#include "openflow/openflow-ext.h" + +#include "chain.h" +#include "datapath.h" +#include "table.h" +#include "private-msg.h" + +/*** + * Copy the new dp_desc out of the passed message + */ + +int +recv_of_set_dp_desc(struct datapath *dp, const struct sender * sender, + const struct openflow_extension_header *ofexth) +{ + struct openflow_ext_set_dp_desc * set_dp_desc = (struct openflow_ext_set_dp_desc * ) + ofexth; + memcpy(dp->dp_desc, set_dp_desc->dp_desc, DESC_STR_LEN); + dp->dp_desc[DESC_STR_LEN-1] = 0; // force null for safety + return 0; +} + + +int +openflow_ext_recv_msg(struct sw_chain *chain, const struct sender *sender, + const void *ofph) +{ + int error = 0; + const struct openflow_queue_command_header *ofexth = ofph; + + switch (ntohl(ofexth->header.subtype)) { + /**** added here as a place holder + * case OFP_EXT_QUEUE_MODIFY: { + * recv_of_exp_queue_modify(dp,sender,oh); + * return 0; + * } + * case OFP_EXT_QUEUE_DELETE: { + * recv_of_exp_queue_delete(dp,sender,oh); + * return 0; + * } + */ + case OFP_EXT_SET_DESC: + return recv_of_set_dp_desc(chain->dp,sender,ofexth); + default: + VLOG_ERR("Received unknown command of type %d", + ntohl(ofexth->header.subtype)); + return -EINVAL; + } + + return error; +} diff --git a/openflow/datapath/openflow-ext.h b/openflow/datapath/openflow-ext.h new file mode 100644 index 00000000..83edfc01 --- /dev/null +++ b/openflow/datapath/openflow-ext.h @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#ifndef OPENFLOW_EXT_H_ +#define OPENFLOW_EXT_H_ + +int openflow_ext_recv_msg(struct sw_chain *, const struct sender *, const void *); + +#endif diff --git a/openflow/datapath/private-msg.c b/openflow/datapath/private-msg.c new file mode 100644 index 00000000..96110ebf --- /dev/null +++ b/openflow/datapath/private-msg.c @@ -0,0 +1,137 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#include "openflow/private-ext.h" + +#include "chain.h" +#include "datapath.h" +#include "table.h" +#include "private-msg.h" + +struct emerg_flow_context { + struct sw_chain *chain; +}; + +static void flush_working(struct sw_chain *); +static int protection_callback(struct sw_flow *, void *); +static void do_protection(struct sw_chain *); + +static void +flush_working(struct sw_chain *chain) +{ + struct sw_flow_key key; + int num_deleted = 0; + + memset(&key, 0, sizeof(key)); + key.wildcards = OFPFW_ALL; + num_deleted = chain_delete(chain, &key, OFPP_NONE, 0, 0, 0); +} + +static int +protection_callback(struct sw_flow *flow, void *private_) +{ + struct emerg_flow_context *private + = (struct emerg_flow_context *)private_; + struct sw_flow_actions *actions = flow->sf_acts; + struct ofp_match match; + struct sw_flow *tgtflow = NULL; + int error = 0; + + tgtflow = flow_alloc(actions->actions_len, GFP_ATOMIC); + if (tgtflow == NULL) { + return -ENOMEM; + } + + /* Dup w/o idle and hard timeout. */ + memset(&match, 0, sizeof(match)); + flow_fill_match(&match, &flow->key); + flow_extract_match(&tgtflow->key, &match); + /* Fill out flow. */ + tgtflow->priority = flow->priority; + tgtflow->idle_timeout = OFP_FLOW_PERMANENT; + tgtflow->hard_timeout = OFP_FLOW_PERMANENT; + tgtflow->send_flow_rem = flow->send_flow_rem; + tgtflow->emerg_flow = 0; + flow_setup_actions(tgtflow, actions->actions, actions->actions_len); + + error = chain_insert(private->chain, tgtflow, 0); + if (error) + flow_free(tgtflow); + + return error; +} + +static void +do_protection(struct sw_chain *chain) +{ + struct emerg_flow_context private; + struct sw_flow_key key; + struct sw_table_position position; + struct sw_table *table = chain->emerg_table; + int error = 0; + + memset(&private, 0, sizeof(private)); + private.chain = chain; + memset(&key, 0, sizeof(key)); + key.wildcards = OFPFW_ALL; + memset(&position, 0, sizeof(position)); + + error = table->iterate(table, &key, OFPP_NONE, + &position, protection_callback, &private); +} + +int +private_recv_msg(struct sw_chain *chain, const struct sender *sender, + const void *ofph) +{ + int error = 0; + struct private_vxhdr *vxhdr = (struct private_vxhdr *)ofph; + struct private_vxopt *vxopt = (struct private_vxopt *)(vxhdr + 1); + + switch (ntohs(vxopt->pvo_type)) { + case PRIVATEOPT_PROTOCOL_STATS_REQUEST: + case PRIVATEOPT_PROTOCOL_STATS_REPLY: + break; + case PRIVATEOPT_EMERG_FLOW_PROTECTION: + flush_working(chain); + do_protection(chain); + break; + case PRIVATEOPT_EMERG_FLOW_RESTORATION: + /* Nothing to do because we assume that a re-connected + * controller will do flush current working flow table. */ + break; + default: + error = -EINVAL; + } + + return error; +} diff --git a/openflow/datapath/private-msg.h b/openflow/datapath/private-msg.h new file mode 100644 index 00000000..246aa541 --- /dev/null +++ b/openflow/datapath/private-msg.h @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#ifndef PRIVATE_MSG_H_ +#define PRIVATE_MSG_H_ + +int private_recv_msg(struct sw_chain *, const struct sender *, const void *); + +#endif diff --git a/openflow/datapath/table-hash.c b/openflow/datapath/table-hash.c new file mode 100644 index 00000000..8e5a97b7 --- /dev/null +++ b/openflow/datapath/table-hash.c @@ -0,0 +1,489 @@ +/* + * Distributed under the terms of the GNU GPL version 2. + * Copyright (c) 2007, 2008, 2009 The Board of Trustees of The Leland + * Stanford Junior University + */ + +#include "table.h" +#include "crc32.h" +#include "flow.h" +#include "datapath.h" + +#include +#include +#include +#include +#include + +static void *kmem_alloc(size_t); +static void *kmem_zalloc(size_t); +static void kmem_free(void *, size_t); + +struct sw_table_hash { + struct sw_table swt; + struct crc32 crc32; + unsigned int n_flows; + unsigned int bucket_mask; /* Number of buckets minus 1. */ + struct sw_flow **buckets; +}; + +static struct sw_flow **find_bucket(struct sw_table *swt, + const struct sw_flow_key *key) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + unsigned int crc = crc32_calculate(&th->crc32, key, + offsetof(struct sw_flow_key, wildcards)); + return &th->buckets[crc & th->bucket_mask]; +} + +static struct sw_flow *table_hash_lookup(struct sw_table *swt, + const struct sw_flow_key *key) +{ + struct sw_flow *flow = *find_bucket(swt, key); + return flow && flow_keys_equal(&flow->key, key) ? flow : NULL; +} + +static int table_hash_insert(struct sw_table *swt, struct sw_flow *flow) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + struct sw_flow **bucket; + int retval; + + if (flow->key.wildcards != 0) + return 0; + + bucket = find_bucket(swt, &flow->key); + if (*bucket == NULL) { + th->n_flows++; + rcu_assign_pointer(*bucket, flow); + retval = 1; + } else { + struct sw_flow *old_flow = *bucket; + if (flow_keys_equal(&old_flow->key, &flow->key)) { + rcu_assign_pointer(*bucket, flow); + flow_deferred_free(old_flow); + retval = 1; + } else { + retval = 0; + } + } + return retval; +} + +static int table_hash_modify(struct sw_table *swt, + const struct sw_flow_key *key, uint16_t priority, int strict, + const struct ofp_action_header *actions, size_t actions_len) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + unsigned int count = 0; + + if (key->wildcards == 0) { + struct sw_flow **bucket = find_bucket(swt, key); + struct sw_flow *flow = *bucket; + if (flow && flow_matches_desc(&flow->key, key, strict) + && (!strict || (flow->priority == priority))) { + flow_replace_acts(flow, actions, actions_len); + count = 1; + } + } else { + unsigned int i; + + for (i = 0; i <= th->bucket_mask; i++) { + struct sw_flow **bucket = &th->buckets[i]; + struct sw_flow *flow = *bucket; + if (flow && flow_matches_desc(&flow->key, key, strict) + && (!strict || (flow->priority == priority))) { + flow_replace_acts(flow, actions, actions_len); + count++; + } + } + } + return count; +} + +static int table_hash_has_conflict(struct sw_table *swt, + const struct sw_flow_key *key, + uint16_t priority, int strict) +{ + struct sw_table_hash *th = (struct sw_table_hash *)swt; + + if (key->wildcards == 0) { + struct sw_flow **bucket = find_bucket(swt, key); + struct sw_flow *flow = *bucket; + if (flow && flow_matches_2desc(&flow->key, key,strict) + && (flow->priority == priority)) { + return true; + } + } else { + unsigned int i; + + for (i = 0; i <= th->bucket_mask; i++) { + struct sw_flow **bucket = &th->buckets[i]; + struct sw_flow *flow = *bucket; + if (flow && flow_matches_2desc(&flow->key, key, strict) + && (flow->priority == priority)) { + return true; + } + } + } + return false; +} + +/* Caller must update n_flows. */ +static int do_delete(struct datapath *dp, struct sw_flow **bucket, + struct sw_flow *flow, enum ofp_flow_removed_reason reason) +{ + dp_send_flow_end(dp, flow, reason); + rcu_assign_pointer(*bucket, NULL); + flow_deferred_free(flow); + return 1; +} + +/* Returns number of deleted flows. We can ignore the priority + * argument, since all exact-match entries are the same (highest) + * priority. */ +static int table_hash_delete(struct datapath *dp, struct sw_table *swt, + const struct sw_flow_key *key, uint16_t out_port, + uint16_t priority, int strict) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + unsigned int count = 0; + + if (key->wildcards == 0) { + struct sw_flow **bucket = find_bucket(swt, key); + struct sw_flow *flow = *bucket; + if (flow && flow_keys_equal(&flow->key, key) + && flow_has_out_port(flow, out_port)) + count = do_delete(dp, bucket, flow, OFPRR_DELETE); + } else { + unsigned int i; + + for (i = 0; i <= th->bucket_mask; i++) { + struct sw_flow **bucket = &th->buckets[i]; + struct sw_flow *flow = *bucket; + if (flow && flow_matches_desc(&flow->key, key, strict) + && flow_has_out_port(flow, out_port)) + count += do_delete(dp, bucket, flow, OFPRR_DELETE); + } + } + th->n_flows -= count; + return count; +} + +static int table_hash_timeout(struct datapath *dp, struct sw_table *swt) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + unsigned int i; + int count = 0; + + if (mutex_lock_interruptible(&dp_mutex)) + return 0; + for (i = 0; i <= th->bucket_mask; i++) { + struct sw_flow **bucket = &th->buckets[i]; + struct sw_flow *flow = *bucket; + if (flow) { + int reason = flow_timeout(flow); + if (reason >= 0) { + count += do_delete(dp, bucket, flow, reason); + } + } + } + th->n_flows -= count; + mutex_unlock(&dp_mutex); + + return count; +} + +static void table_hash_destroy(struct sw_table *swt) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + unsigned int i; + for (i = 0; i <= th->bucket_mask; i++) + if (th->buckets[i]) + flow_free(th->buckets[i]); + kmem_free(th->buckets, (th->bucket_mask + 1) * sizeof *th->buckets); + kfree(th); +} + +static int table_hash_iterate(struct sw_table *swt, + const struct sw_flow_key *key, uint16_t out_port, + struct sw_table_position *position, + int (*callback)(struct sw_flow *, void *private), + void *private) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + + if (position->private[0] > th->bucket_mask) + return 0; + + if (key->wildcards == 0) { + struct sw_flow *flow; + int error; + + flow = table_hash_lookup(swt, key); + if (!flow || !flow_has_out_port(flow, out_port)) + return 0; + + error = callback(flow, private); + if (!error) + position->private[0] = -1; + return error; + } else { + int i; + + for (i = position->private[0]; i <= th->bucket_mask; i++) { + struct sw_flow *flow = th->buckets[i]; + if (flow && flow_matches_1wild(&flow->key, key) + && flow_has_out_port(flow, out_port)) { + int error = callback(flow, private); + if (error) { + position->private[0] = i; + return error; + } + } + } + return 0; + } +} +static void table_hash_stats(struct sw_table *swt, + struct sw_table_stats *stats) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + stats->name = "hash"; + stats->wildcards = 0; /* No wildcards are supported. */ + stats->n_flows = th->n_flows; + stats->max_flows = th->bucket_mask + 1; + stats->n_lookup = swt->n_lookup; + stats->n_matched = swt->n_matched; +} + +struct sw_table *table_hash_create(unsigned int polynomial, + unsigned int n_buckets) +{ + struct sw_table_hash *th; + struct sw_table *swt; + + th = kzalloc(sizeof *th, GFP_KERNEL); + if (th == NULL) + return NULL; + + BUG_ON(n_buckets & (n_buckets - 1)); + th->buckets = kmem_zalloc(n_buckets * sizeof *th->buckets); + if (th->buckets == NULL) { + printk(KERN_EMERG "failed to allocate %u buckets\n", + n_buckets); + kfree(th); + return NULL; + } + th->bucket_mask = n_buckets - 1; + + swt = &th->swt; + swt->lookup = table_hash_lookup; + swt->insert = table_hash_insert; + swt->has_conflict = table_hash_has_conflict; + swt->delete = table_hash_delete; + swt->timeout = table_hash_timeout; + swt->destroy = table_hash_destroy; + swt->iterate = table_hash_iterate; + swt->stats = table_hash_stats; + + crc32_init(&th->crc32, polynomial); + th->n_flows = 0; + + return swt; +} + +/* Double-hashing table. */ + +struct sw_table_hash2 { + struct sw_table swt; + struct sw_table *subtable[2]; +}; + +static struct sw_flow *table_hash2_lookup(struct sw_table *swt, + const struct sw_flow_key *key) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + int i; + + for (i = 0; i < 2; i++) { + struct sw_flow *flow = *find_bucket(t2->subtable[i], key); + if (flow && flow_keys_equal(&flow->key, key)) + return flow; + } + return NULL; +} + +static int table_hash2_insert(struct sw_table *swt, struct sw_flow *flow) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + + if (table_hash_insert(t2->subtable[0], flow)) + return 1; + return table_hash_insert(t2->subtable[1], flow); +} + +static int table_hash2_modify(struct sw_table *swt, + const struct sw_flow_key *key, uint16_t priority, int strict, + const struct ofp_action_header *actions, size_t actions_len) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + return (table_hash_modify(t2->subtable[0], key, priority, strict, + actions, actions_len) + + table_hash_modify(t2->subtable[1], key, priority, strict, + actions, actions_len)); +} + +static int table_hash2_has_conflict(struct sw_table *swt, + const struct sw_flow_key *key, + uint16_t priority, int strict) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + return (table_hash_has_conflict(t2->subtable[0], key, priority, strict) || + table_hash_has_conflict(t2->subtable[1], key, priority, strict)); +} + +static int table_hash2_delete(struct datapath *dp, struct sw_table *swt, + const struct sw_flow_key *key, + uint16_t out_port, + uint16_t priority, int strict) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + return (table_hash_delete(dp, t2->subtable[0], key, out_port, + priority, strict) + + table_hash_delete(dp, t2->subtable[1], key, out_port, + priority, strict)); +} + +static int table_hash2_timeout(struct datapath *dp, struct sw_table *swt) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + return (table_hash_timeout(dp, t2->subtable[0]) + + table_hash_timeout(dp, t2->subtable[1])); +} + +static void table_hash2_destroy(struct sw_table *swt) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + table_hash_destroy(t2->subtable[0]); + table_hash_destroy(t2->subtable[1]); + kfree(t2); +} + +static int table_hash2_iterate(struct sw_table *swt, + const struct sw_flow_key *key, uint16_t out_port, + struct sw_table_position *position, + int (*callback)(struct sw_flow *, void *), + void *private) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + int i; + + for (i = position->private[1]; i < 2; i++) { + int error = table_hash_iterate(t2->subtable[i], key, out_port, + position, callback, private); + if (error) { + return error; + } + position->private[0] = 0; + position->private[1]++; + } + return 0; +} + +static void table_hash2_stats(struct sw_table *swt, + struct sw_table_stats *stats) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + struct sw_table_stats substats[2]; + int i; + + for (i = 0; i < 2; i++) + table_hash_stats(t2->subtable[i], &substats[i]); + stats->name = "hash2"; + stats->wildcards = 0; /* No wildcards are supported. */ + stats->n_flows = substats[0].n_flows + substats[1].n_flows; + stats->max_flows = substats[0].max_flows + substats[1].max_flows; + stats->n_lookup = swt->n_lookup; + stats->n_matched = swt->n_matched; +} + +struct sw_table *table_hash2_create(unsigned int poly0, unsigned int buckets0, + unsigned int poly1, unsigned int buckets1) + +{ + struct sw_table_hash2 *t2; + struct sw_table *swt; + + t2 = kzalloc(sizeof *t2, GFP_KERNEL); + if (t2 == NULL) + return NULL; + + t2->subtable[0] = table_hash_create(poly0, buckets0); + if (t2->subtable[0] == NULL) + goto out_free_t2; + + t2->subtable[1] = table_hash_create(poly1, buckets1); + if (t2->subtable[1] == NULL) + goto out_free_subtable0; + + swt = &t2->swt; + swt->lookup = table_hash2_lookup; + swt->insert = table_hash2_insert; + swt->modify = table_hash2_modify; + swt->has_conflict = table_hash2_has_conflict; + swt->delete = table_hash2_delete; + swt->timeout = table_hash2_timeout; + swt->destroy = table_hash2_destroy; + swt->iterate = table_hash2_iterate; + swt->stats = table_hash2_stats; + + return swt; + +out_free_subtable0: + table_hash_destroy(t2->subtable[0]); +out_free_t2: + kfree(t2); + return NULL; +} + +/* From fs/xfs/linux-2.4/kmem.c. */ + +static void * +kmem_alloc(size_t size) +{ + void *ptr; + +#ifdef KMALLOC_MAX_SIZE + if (size > KMALLOC_MAX_SIZE) + return NULL; +#endif + ptr = kmalloc(size, GFP_KERNEL); + if (!ptr) { + ptr = vmalloc(size); + if (ptr) + printk(KERN_NOTICE "openflow: used vmalloc for %lu " + "bytes\n", (unsigned long)size); + } + return ptr; +} + +static void * +kmem_zalloc(size_t size) +{ + void *ptr = kmem_alloc(size); + if (ptr) + memset(ptr, 0, size); + return ptr; +} + +static void +kmem_free(void *ptr, size_t size) +{ + if (((unsigned long)ptr < VMALLOC_START) || + ((unsigned long)ptr >= VMALLOC_END)) { + kfree(ptr); + } else { + vfree(ptr); + } +} diff --git a/openflow/datapath/table-linear.c b/openflow/datapath/table-linear.c new file mode 100644 index 00000000..79a95dfb --- /dev/null +++ b/openflow/datapath/table-linear.c @@ -0,0 +1,233 @@ +/* + * Distributed under the terms of the GNU GPL version 2. + * Copyright (c) 2007, 2008, 2009 The Board of Trustees of The Leland + * Stanford Junior University + */ + +#include "table.h" +#include "flow.h" +#include "datapath.h" + +#include +#include +#include + +struct sw_table_linear { + struct sw_table swt; + + unsigned int max_flows; + unsigned int n_flows; + struct list_head flows; + struct list_head iter_flows; + unsigned long int next_serial; +}; + +static struct sw_flow *table_linear_lookup(struct sw_table *swt, + const struct sw_flow_key *key) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + struct sw_flow *flow; + list_for_each_entry_rcu (flow, &tl->flows, node) { + if (flow_matches_1wild(key, &flow->key)) + return flow; + } + return NULL; +} + +static int table_linear_insert(struct sw_table *swt, struct sw_flow *flow) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + struct sw_flow *f; + + + /* Loop through the existing list of entries. New entries will + * always be placed behind those with equal priority. Just replace + * any flows that match exactly. + */ + list_for_each_entry (f, &tl->flows, node) { + if (f->priority == flow->priority + && f->key.wildcards == flow->key.wildcards + && flow_matches_2wild(&f->key, &flow->key)) { + flow->serial = f->serial; + list_replace_rcu(&f->node, &flow->node); + list_replace_rcu(&f->iter_node, &flow->iter_node); + flow_deferred_free(f); + return 1; + } + + if (f->priority < flow->priority) + break; + } + + /* Make sure there's room in the table. */ + if (tl->n_flows >= tl->max_flows) { + return 0; + } + tl->n_flows++; + + /* Insert the entry immediately in front of where we're pointing. */ + flow->serial = tl->next_serial++; + list_add_tail_rcu(&flow->node, &f->node); + list_add_rcu(&flow->iter_node, &tl->iter_flows); + return 1; +} + +static int table_linear_modify(struct sw_table *swt, + const struct sw_flow_key *key, uint16_t priority, int strict, + const struct ofp_action_header *actions, size_t actions_len) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + struct sw_flow *flow; + unsigned int count = 0; + + list_for_each_entry (flow, &tl->flows, node) { + if (flow_matches_desc(&flow->key, key, strict) + && (!strict || (flow->priority == priority))) { + flow_replace_acts(flow, actions, actions_len); + count++; + } + } + return count; +} + +static int table_linear_has_conflict(struct sw_table *swt, + const struct sw_flow_key *key, uint16_t priority, int strict) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + struct sw_flow *flow; + + list_for_each_entry (flow, &tl->flows, node) { + if (flow_matches_2desc(&flow->key, key, strict) + && (flow->priority == priority)) { + return true; + } + } + return false; +} + +static int do_delete(struct datapath *dp, struct sw_table *swt, + struct sw_flow *flow, enum ofp_flow_removed_reason reason) +{ + dp_send_flow_end(dp, flow, reason); + list_del_rcu(&flow->node); + list_del_rcu(&flow->iter_node); + flow_deferred_free(flow); + return 1; +} + +static int table_linear_delete(struct datapath *dp, struct sw_table *swt, + const struct sw_flow_key *key, uint16_t out_port, + uint16_t priority, int strict) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + struct sw_flow *flow; + unsigned int count = 0; + + list_for_each_entry (flow, &tl->flows, node) { + if (flow_matches_desc(&flow->key, key, strict) + && flow_has_out_port(flow, out_port) + && (!strict || (flow->priority == priority))) + count += do_delete(dp, swt, flow, OFPRR_DELETE); + } + tl->n_flows -= count; + return count; +} + +static int table_linear_timeout(struct datapath *dp, struct sw_table *swt) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + struct sw_flow *flow; + int count = 0; + + if (mutex_lock_interruptible(&dp_mutex)) + return 0; + list_for_each_entry (flow, &tl->flows, node) { + int reason = flow_timeout(flow); + if (reason >= 0) { + count += do_delete(dp, swt, flow, reason); + } + } + tl->n_flows -= count; + mutex_unlock(&dp_mutex); + return count; +} + +static void table_linear_destroy(struct sw_table *swt) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + + while (!list_empty(&tl->flows)) { + struct sw_flow *flow = list_entry(tl->flows.next, + struct sw_flow, node); + list_del(&flow->node); + flow_free(flow); + } + kfree(tl); +} + +static int table_linear_iterate(struct sw_table *swt, + const struct sw_flow_key *key, uint16_t out_port, + struct sw_table_position *position, + int (*callback)(struct sw_flow *, void *), + void *private) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + struct sw_flow *flow; + unsigned long start; + + start = position->private[0]; + list_for_each_entry (flow, &tl->iter_flows, iter_node) { + if (flow->serial >= start + && flow_matches_2wild(key, &flow->key) + && flow_has_out_port(flow, out_port)) { + int error = callback(flow, private); + if (error) { + position->private[0] = flow->serial; + return error; + } + } + } + return 0; +} + +static void table_linear_stats(struct sw_table *swt, + struct sw_table_stats *stats) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + stats->name = "linear"; + stats->wildcards = OFPFW_ALL; + stats->n_flows = tl->n_flows; + stats->max_flows = tl->max_flows; + stats->n_lookup = swt->n_lookup; + stats->n_matched = swt->n_matched; +} + + +struct sw_table *table_linear_create(unsigned int max_flows) +{ + struct sw_table_linear *tl; + struct sw_table *swt; + + tl = kzalloc(sizeof *tl, GFP_KERNEL); + if (tl == NULL) + return NULL; + + swt = &tl->swt; + swt->lookup = table_linear_lookup; + swt->insert = table_linear_insert; + swt->modify = table_linear_modify; + swt->has_conflict = table_linear_has_conflict; + swt->delete = table_linear_delete; + swt->timeout = table_linear_timeout; + swt->destroy = table_linear_destroy; + swt->iterate = table_linear_iterate; + swt->stats = table_linear_stats; + + tl->max_flows = max_flows; + tl->n_flows = 0; + INIT_LIST_HEAD(&tl->flows); + INIT_LIST_HEAD(&tl->iter_flows); + tl->next_serial = 0; + + return swt; +} diff --git a/openflow/datapath/table.h b/openflow/datapath/table.h new file mode 100644 index 00000000..1cc90a01 --- /dev/null +++ b/openflow/datapath/table.h @@ -0,0 +1,119 @@ +/* Individual switching tables. Generally grouped together in a chain (see + * chain.h). */ + +#ifndef TABLE_H +#define TABLE_H 1 + +#include + +struct sw_flow; +struct sw_flow_key; +struct ofp_action_header; +struct datapath; + +/* Table statistics. */ +struct sw_table_stats { + const char *name; /* Human-readable name. */ + uint32_t wildcards; /* Bitmap of OFPFW_* wildcards that are + supported by the table. */ + unsigned int n_flows; /* Number of active flows. */ + unsigned int max_flows; /* Flow capacity. */ + unsigned long int n_lookup; /* Number of packets looked up. */ + unsigned long int n_matched; /* Number of packets that have hit. */ +}; + +/* Position within an iteration of a sw_table. + * + * The contents are private to the table implementation, except that a position + * initialized to all-zero-bits represents the start of a table. */ +struct sw_table_position { + unsigned long private[4]; +}; + +/* A single table of flows. + * + * All functions, except destroy, must be called holding the + * rcu_read_lock. destroy must be fully serialized. + */ +struct sw_table { + /* The number of packets that have been looked up and matched, + * respecitvely. To make these 100% accurate, they should be atomic. + * However, we're primarily concerned about speed. */ + unsigned long long n_lookup; + unsigned long long n_matched; + + /* Searches 'table' for a flow matching 'key', which must not have any + * wildcard fields. Returns the flow if successful, a null pointer + * otherwise. */ + struct sw_flow *(*lookup)(struct sw_table *table, + const struct sw_flow_key *key); + + /* Inserts 'flow' into 'table', replacing any duplicate flow. Returns + * 0 if successful or a negative error. Error can be due to an + * over-capacity table or because the flow is not one of the kind that + * the table accepts. + * + * If successful, 'flow' becomes owned by 'table', otherwise it is + * retained by the caller. */ + int (*insert)(struct sw_table *table, struct sw_flow *flow); + + /* Modifies the actions in 'table' that match 'key'. If 'strict' + * set, wildcards and priority must match. Returns the number of flows + * that were modified. */ + int (*modify)(struct sw_table *table, const struct sw_flow_key *key, + uint16_t priority, int strict, + const struct ofp_action_header *actions, size_t actions_len); + + /* Checks whether 'table' has an equal priotiry entry of thethat conflicts + * with 'key'. If 'strict' is set, wildcards must match. + * Returns the number of flows that were modified. */ + int (*has_conflict)(struct sw_table *table, const struct sw_flow_key *key, + uint16_t priority, int strict); + + /* Deletes from 'table' any and all flows that match 'key' from + * 'table'. If 'out_port' is not OFPP_NONE, then matching entries + * must have that port as an argument for an output action. If + * 'strict' is set, wildcards and priority must match. Returns the + * number of flows that were deleted. */ + int (*delete)(struct datapath *dp, struct sw_table *table, + const struct sw_flow_key *key, + uint16_t out_port, uint16_t priority, int strict); + + /* Performs timeout processing on all the flow entries in 'table'. + * Returns the number of flow entries deleted through expiration. */ + int (*timeout)(struct datapath *dp, struct sw_table *table); + + /* Destroys 'table', which must not have any users. */ + void (*destroy)(struct sw_table *table); + + /* Iterates through the flow entries in 'table', passing each one + * matches 'key' and output port 'out_port' to 'callback'. The + * callback function should return 0 to continue iteration or a + * nonzero error code to stop. The iterator function returns either + * 0 if the table iteration completed or the value returned by the + * callback function otherwise. + * + * The iteration starts at 'position', which may be initialized to + * all-zero-bits to iterate from the beginning of the table. If the + * iteration terminates due to an error from the callback function, + * 'position' is updated to a value that can be passed back to the + * iterator function to continue iteration later from the same position + * that caused the error (assuming that that flow entry has not been + * deleted in the meantime). */ + int (*iterate)(struct sw_table *table, + const struct sw_flow_key *key, uint16_t out_port, + struct sw_table_position *position, + int (*callback)(struct sw_flow *flow, void *private), + void *private); + + /* Dumps statistics for 'table' into 'stats'. */ + void (*stats)(struct sw_table *table, struct sw_table_stats *stats); +}; + +struct sw_table *table_hash_create(unsigned int polynomial, + unsigned int n_buckets); +struct sw_table *table_hash2_create(unsigned int poly0, unsigned int buckets0, + unsigned int poly1, unsigned int buckets1); +struct sw_table *table_linear_create(unsigned int max_flows); + +#endif /* table.h */ diff --git a/openflow/debian/.gitignore b/openflow/debian/.gitignore new file mode 100644 index 00000000..1df6fba1 --- /dev/null +++ b/openflow/debian/.gitignore @@ -0,0 +1,38 @@ +*.debhelper +*.debhelper.log +*.substvars +/automake.mk +/control +/corekeeper +/files +/nicira-switch +/openflow +/openflow-common +/openflow-common.copyright +/openflow-controller +/openflow-datapath-source +/openflow-dbg +/openflow-monitor +/openflow-monitor.copyright +/openflow-monitor.default +/openflow-monitor.dirs +/openflow-monitor.init +/openflow-monitor.install +/openflow-pki +/openflow-pki-server +/openflow-switch +/openflow-switch-config +/openflow-switch.copyright +/openflow-switchui +/openflow-switchui.copyright +/openflow-switchui.default +/openflow-switchui.dirs +/openflow-switchui.init +/openflow-switchui.install +/openflow-wdt +/openflow-wdt.copyright +/openflow-wdt.default +/openflow-wdt.dirs +/openflow-wdt.init +/openflow-wdt.install +/rules.ext diff --git a/openflow/debian/changelog b/openflow/debian/changelog new file mode 100644 index 00000000..235187e5 --- /dev/null +++ b/openflow/debian/changelog @@ -0,0 +1,23 @@ +openflow (1.0.0) unstable; urgency=low + + * Development version + + -- OpenFlow team Thu, 31 Dec 2009 23:59:59 -0800 + +openflow (0.9.0-rev1) unstable; urgency=low + + * Development version. + + -- OpenFlow team Fri, 04 Sep 2009 12:00:00 -0800 + +openflow (0.8.9-rev4) unstable; urgency=low + + * Develoment version. + + -- OpenFlow team Tue, 15 Sep 2009 12:00:00 -0800 + +openflow (0.8.1) unstable; urgency=low + + * Development version. + + -- OpenFlow team Mon, 19 Nov 2007 14:57:52 -0800 diff --git a/openflow/debian/commands/reconfigure b/openflow/debian/commands/reconfigure new file mode 100755 index 00000000..a9610524 --- /dev/null +++ b/openflow/debian/commands/reconfigure @@ -0,0 +1,128 @@ +#! /usr/bin/perl + +use POSIX; +use strict; +use warnings; + +my $default = '/etc/default/openflow-switch'; + +my (%config) = load_config($default); +if (@ARGV) { + foreach my $arg (@ARGV) { + my ($key, $value) = $arg =~ /^([^=]+)=(.*)/ + or die "bad argument '$arg'\n"; + if ($value ne '') { + $config{$key} = $value; + } else { + delete $config{$key}; + } + } + save_config($default, %config); +} +print "$_=$config{$_}\n" foreach sort(keys(%config)); + +sub load_config { + my ($file) = @_; + + # Get the list of the variables that the shell sets automatically. + my (%auto_vars) = read_vars("set -a && env"); + + # Get the variables from $default. + my (%config) = read_vars("set -a && . '$default' && env"); + + # Subtract. + delete @config{keys %auto_vars}; + + return %config; +} + +sub read_vars { + my ($cmd) = @_; + local @ENV; + if (!open(VARS, '-|', $cmd)) { + print STDERR "$cmd: failed to execute: $!\n"; + return (); + } + my (%config); + while () { + my ($var, $value) = /^([^=]+)=(.*)$/ or next; + $config{$var} = $value; + } + close(VARS); + return %config; +} + +sub shell_escape { + local $_ = $_[0]; + if ($_ eq '') { + return '""'; + } elsif (m&^[-a-zA-Z0-9:./%^_+,]*$&) { + return $_; + } else { + s/'/'\\''/; + return "'$_'"; + } +} + +sub shell_assign { + my ($var, $value) = @_; + return $var . '=' . shell_escape($value); +} + +sub save_config { + my ($file, %config) = @_; + my (@lines); + if (open(FILE, '<', $file)) { + @lines = ; + chomp @lines; + close(FILE); + } + + # Replace all existing variable assignments. + for (my ($i) = 0; $i <= $#lines; $i++) { + local $_ = $lines[$i]; + my ($var, $value) = /^\s*([^=#]+)=(.*)$/ or next; + if (exists($config{$var})) { + $lines[$i] = shell_assign($var, $config{$var}); + delete $config{$var}; + } else { + $lines[$i] = "#$lines[$i]"; + } + } + + # Find a place to put any remaining variable assignments. + VAR: + for my $var (keys(%config)) { + my $assign = shell_assign($var, $config{$var}); + + # Replace the last commented-out variable assignment to $var, if any. + for (my ($i) = $#lines; $i >= 0; $i--) { + local $_ = $lines[$i]; + if (/^\s*#\s*$var=/) { + $lines[$i] = $assign; + next VAR; + } + } + + # Find a place to add the var: after the final commented line + # just after a line that contains "$var:". + for (my ($i) = 0; $i <= $#lines; $i++) { + if ($lines[$i] =~ /^\s*#\s*$var:/) { + for (my ($j) = $i + 1; $j <= $#lines; $j++) { + if ($lines[$j] !~ /^\s*#/) { + splice(@lines, $j, 0, $assign); + next VAR; + } + } + } + } + + # Just append it. + push(@lines, $assign); + } + + open(NEWFILE, '>', "$file.tmp") or die "$file.tmp: create: $!\n"; + print NEWFILE join('', map("$_\n", @lines)); + close(NEWFILE); + rename("$file.tmp", $file) or die "$file.tmp: rename to $file: $!\n"; +} diff --git a/openflow/debian/commands/update b/openflow/debian/commands/update new file mode 100755 index 00000000..545e3c23 --- /dev/null +++ b/openflow/debian/commands/update @@ -0,0 +1,4 @@ +#! /bin/sh +set -e +apt-get update -qy +apt-get upgrade -qy diff --git a/openflow/debian/compat b/openflow/debian/compat new file mode 100644 index 00000000..7ed6ff82 --- /dev/null +++ b/openflow/debian/compat @@ -0,0 +1 @@ +5 diff --git a/openflow/debian/control.in b/openflow/debian/control.in new file mode 100644 index 00000000..2e14410d --- /dev/null +++ b/openflow/debian/control.in @@ -0,0 +1,93 @@ +Source: openflow +Section: net +Priority: extra +Maintainer: OpenFlow Team +Build-Depends: debhelper (>= 5), autoconf (>= 2.60), automake1.10 | automake1.11 | automake (>= 1.10), libssl-dev, pkg-config (>= 0.21), po-debconf, bzip2, openssl, libncurses5-dev, libpcre3-dev +Standards-Version: 3.7.3 + +Package: openflow-datapath-source +Architecture: all +Depends: module-assistant, bzip2, debhelper (>= 5.0.37) +Suggests: openflow-switch +Description: Source code for OpenFlow datapath Linux module + This package provides the OpenFlow datapath module source code that + is needed by the kernel-based OpenFlow switch. The kernel module can + be built from it using module-assistant or make-kpkg. README.Debian + in this package provides further instructions. + . + OpenFlow is a protocol for flow-based control over network switching. + +Package: openflow-common +Architecture: any +Depends: ${shlibs:Depends}, openssl +Description: OpenFlow common components + openflow-common provides components required by both openflow-switch + and openflow-controller. + . + OpenFlow is a protocol for flow-based control over network switching. + +Package: openflow-switch +Architecture: any +Suggests: openflow-datapath-module +Depends: ${shlibs:Depends}, ${misc:Depends}, openflow-common, dhcp3-client, module-init-tools, dmidecode, procps, debianutils +Description: OpenFlow switch implementations + openflow-switch provides the userspace components and utilities for + the OpenFlow kernel-based switch. + . + OpenFlow is a protocol for flow-based control over network switching. + +Package: openflow-switch-config +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, openflow-switch, libwww-perl, libdigest-sha1-perl +Description: OpenFlow switch implementations + openflow-switch-config provides a utility for interactively configuring + the OpenFlow switch provided in the openflow-switch package. + . + OpenFlow is a protocol for flow-based control over network switching. + +Package: openflow-pki +Architecture: all +Depends: ${shlibs:Depends}, ${misc:Depends}, openflow-common +Description: OpenFlow public key infrastructure + openflow-pki provides PKI (public key infrastructure) support for + OpenFlow switches and controllers, reducing the risk of + man-in-the-middle attacks on the OpenFlow network infrastructure. + . + OpenFlow is a protocol for flow-based control over network switching. + +Package: openflow-pki-server +Architecture: all +Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, openflow-pki, apache2 +Description: OpenFlow public key infrastructure (HTTP server support) + openflow-pki-server provides HTTP access to the OpenFlow PKI (public + key infrastructure) maintained on the local machine by the + openflow-pki package. This HTTP access is needed for secure and + convenient OpenFlow switch setup using the ofp-switch-setup program + in the openflow-switch package. + . + OpenFlow is a protocol for flow-based control over network switching. + +Package: openflow-controller +Architecture: any +Depends: ${shlibs:Depends}, openflow-common, openflow-pki +Description: OpenFlow controller implementation + The OpenFlow controller enables OpenFlow switches that connect to it + to act as MAC-learning Ethernet switches. + . + OpenFlow is a protocol for flow-based control over network switching. + +Package: corekeeper +Architecture: all +Depends: tmpreaper +Description: Core file centralizer and reaper + The corekeeper package configures the system to dump all core files to + /var/log/core. It also deletes core files older than 7 days. + +Package: openflow-dbg +Architecture: any +Depends: ${shlibs:Depends} +Description: Debug symbols for OpenFlow packages + This package contains the debug symbols for all the other openflow-* + packages. Install it to debug one of them or to examine a core dump + produced by one of them. + diff --git a/openflow/debian/control.modules.in b/openflow/debian/control.modules.in new file mode 100644 index 00000000..cc149cac --- /dev/null +++ b/openflow/debian/control.modules.in @@ -0,0 +1,19 @@ +Source: openflow +Section: net +Priority: extra +Maintainer: OpenFlow Team +Build-Depends: debhelper (>= 5.0.37) +Standards-Version: 3.7.3 + +Package: openflow-datapath-module-_KVERS_ +Architecture: any +Recommends: kernel-image-_KVERS_, openflow-switch +Provides: openflow-datapath-module +Description: OpenFlow Linux datapath kernel module + This package contains the OpenFlow loadable datapath kernel modules for + the kernel-image-_KVERS_ package. + . + If you compiled a custom kernel, you will most likely need to compile + a custom version of this module as well. The openflow-datapath-source + package has been provided for this purpose. Refer to README.Debian + provided in that package for further instructions. diff --git a/openflow/debian/copyright b/openflow/debian/copyright new file mode 100644 index 00000000..b369ec39 --- /dev/null +++ b/openflow/debian/copyright @@ -0,0 +1,38 @@ +Upstream Authors: + + The Board of Trustees of The Leland Stanford Junior University + +Copyright: + + Copyright (C) 2008 The Board of Trustees of The Leland Stanford + Junior University + +License: + + We are making the OpenFlow specification and associated documentation + (Software) available for public use and benefit with the expectation + that others will use, modify and enhance the Software and contribute + those enhancements back to the community. However, since we would like + to make the Software available for broadest use, with as few + restrictions as possible permission is hereby granted, free of charge, + to any person obtaining a copy of this Software to deal in the Software + under the copyrights without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + The name and trademarks of copyright holder(s) may NOT be used in + advertising or publicity pertaining to the Software or any derivatives + without specific, written prior permission. + diff --git a/openflow/debian/corekeeper.cron.daily b/openflow/debian/corekeeper.cron.daily new file mode 100755 index 00000000..badc192d --- /dev/null +++ b/openflow/debian/corekeeper.cron.daily @@ -0,0 +1,5 @@ +#! /bin/sh + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin + +tmpreaper 7d --mtime --all /var/log/core diff --git a/openflow/debian/corekeeper.init b/openflow/debian/corekeeper.init new file mode 100755 index 00000000..27d62a12 --- /dev/null +++ b/openflow/debian/corekeeper.init @@ -0,0 +1,63 @@ +#!/bin/sh +# +# Example init.d script with LSB support. +# +# Please read this init.d carefully and modify the sections to +# adjust it to the program you want to run. +# +# Copyright (c) 2007 Javier Fernandez-Sanguino +# +# This is free software; you may redistribute it and/or modify +# it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2, +# or (at your option) any later version. +# +# This is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License with +# the Debian operating system, in /usr/share/common-licenses/GPL; if +# not, write to the Free Software Foundation, Inc., 59 Temple Place, +# Suite 330, Boston, MA 02111-1307 USA +# +### BEGIN INIT INFO +# Provides: corekeeper +# Required-Start: +# Required-Stop: +# Should-Start: $syslog +# Should-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Configure core file dump location +### END INIT INFO + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin + +. /lib/lsb/init-functions + +set -e + +case "$1" in + start) + log_daemon_msg "Initializing core dump location..." + if echo "/var/log/core/core.%e.%t" > /proc/sys/kernel/core_pattern + then + log_progress_msg "success" + log_end_msg 0 + exit 0 + else + log_end_msg 1 + exit 1 + fi + ;; + stop|restart|force-reload|status|reload) + exit 0 + ;; + *) + N=/etc/init.d/$NAME + echo "Usage: $N {start|stop|restart|force-reload|status}" >&2 + exit 1 + ;; +esac diff --git a/openflow/debian/dirs b/openflow/debian/dirs new file mode 100644 index 00000000..ca882bbb --- /dev/null +++ b/openflow/debian/dirs @@ -0,0 +1,2 @@ +usr/bin +usr/sbin diff --git a/openflow/debian/ofp-switch-setup b/openflow/debian/ofp-switch-setup new file mode 100755 index 00000000..5a999ab4 --- /dev/null +++ b/openflow/debian/ofp-switch-setup @@ -0,0 +1,615 @@ +#! /usr/bin/perl + +use POSIX; +use Debconf::Client::ConfModule ':all'; +use HTTP::Request; +use LWP::UserAgent; +use Digest::SHA1 'sha1_hex'; +use strict; +use warnings; + +# XXX should support configuring SWITCH_NETMASK and SWITCH_GATEWAY +# when the mode is in-band. + +my $debconf_owner = 'openflow-switch'; + +my $default = '/etc/default/openflow-switch'; +my $template = '/usr/share/openflow/switch/default.template'; +my $etc = '/etc/openflow-switch'; +my $rundir = '/var/run'; +my $privkey_file = "$etc/of0-privkey.pem"; +my $req_file = "$etc/of0-req.pem"; +my $cert_file = "$etc/of0-cert.pem"; +my $cacert_file = "$etc/cacert.pem"; +my $ofp_discover_pidfile = "$rundir/ofp-discover.pid"; + +my $ua = LWP::UserAgent->new; +$ua->timeout(10); +$ua->env_proxy; + +system("/etc/init.d/openflow-switch stop 1>&2"); +kill_ofp_discover(); + +version('2.0'); +capb('backup'); +title('OpenFlow Switch Setup'); + +my (%netdevs) = find_netdevs(); +db_subst('netdevs', 'choices', + join(', ', map($netdevs{$_}, sort(keys(%netdevs))))); +db_set('netdevs', join(', ', grep(!/IP/, values(%netdevs)))); + +my %oldconfig; +if (-e $default) { + %oldconfig = load_config($default); + + my (%map) = + (NETDEVS => sub { + db_set('netdevs', join(', ', map($netdevs{$_}, + grep(exists $netdevs{$_}, split)))) + }, + MODE => sub { + db_set('mode', + $_ eq 'in-band' || $_ eq 'out-of-band' ? $_ : 'discovery') + }, + SWITCH_IP => sub { db_set('switch-ip', $_) }, + CONTROLLER => sub { db_set('controller-vconn', $_) }, + PRIVKEY => sub { $privkey_file = $_ }, + CERT => sub { $cert_file = $_ }, + CACERT => sub { $cacert_file = $_ }, + ); + + for my $key (keys(%map)) { + local $_ = $oldconfig{$key}; + &{$map{$key}}() if defined && !/^\s*$/; + } +} elsif (-e $template) { + %oldconfig = load_config($template); +} + +my $cacert_preverified = -e $cacert_file; +my ($req, $req_fingerprint); + +my %options; + +my (@states) = + (sub { + # User backed up from first dialog box. + exit(10); + }, + sub { + # Prompt for ports to include in switch. + db_input('netdevs'); + return; + }, + sub { + # Validate the chosen ports. + my (@netdevs) = split(', ', db_get('netdevs')); + if (!@netdevs) { + # No ports chosen. Disable switch. + db_input('no-netdevs'); + return 'prev' if db_go(); + return 'done'; + } elsif (my (@conf_netdevs) = grep(/IP/, @netdevs)) { + # Point out that some ports have configured IP addresses. + db_subst('configured-netdevs', 'configured-netdevs', + join(', ', @conf_netdevs)); + db_input('configured-netdevs'); + return; + } else { + # Otherwise proceed. + return 'skip'; + } + }, + sub { + # Discovery or in-band or out-of-band controller? + db_input('mode'); + return; + }, + sub { + return 'skip' if db_get('mode') ne 'discovery'; + for (;;) { + # Notify user that we are going to do discovery. + db_input('discover'); + return 'prev' if db_go(); + print STDERR "Please wait up to 30 seconds for discovery...\n"; + + # Make sure that there's no running discovery process. + kill_ofp_discover(); + + # Do discovery. + %options = (); + open(DISCOVER, '-|', 'ofp-discover --timeout=30 --pidfile ' + . join(' ', netdev_names())); + while () { + chomp; + if (my ($name, $value) = /^([^=]+)=(.*)$/) { + if ($value =~ /^"(.*)"$/) { + $value = $1; + $value =~ s/\\([0-7][0-7][0-7])/chr($1)/ge; + } else { + $value =~ s/^(0x[[:xdigit:]]+)$/hex($1)/e; + $value = '' if $value eq 'empty'; + next if $value eq 'null'; # Shouldn't happen. + } + $options{$name} = $value; + } + last if /^$/; + } + + # Check results. + my $vconn = $options{'ofp-controller-vconn'}; + my $pki_uri = $options{'ofp-pki-uri'}; + return 'next' + if (defined($vconn) + && is_valid_vconn($vconn) + && (!is_ssl_vconn($vconn) || defined($pki_uri))); + + # Try again? + kill_ofp_discover(); + db_input('discovery-failure'); + db_go(); + } + }, + sub { + return 'skip' if db_get('mode') ne 'discovery'; + + my $vconn = $options{'ofp-controller-vconn'}; + my $pki_uri = $options{'ofp-pki-uri'}; + db_subst('discovery-success', 'controller-vconn', $vconn); + db_subst('discovery-success', + 'pki-uri', is_ssl_vconn($vconn) ? $pki_uri : "no PKI in use"); + db_input('discovery-success'); + return 'prev' if db_go(); + db_set('controller-vconn', $vconn); + db_set('pki-uri', $pki_uri); + return 'next'; + }, + sub { + return 'skip' if db_get('mode') ne 'in-band'; + for (;;) { + db_input('switch-ip'); + return 'prev' if db_go(); + + my $ip = db_get('switch-ip'); + return 'next' if $ip =~ /^dhcp|\d+\.\d+.\d+.\d+$/i; + + db_input('switch-ip-error'); + db_go(); + } + }, + sub { + return 'skip' if db_get('mode') eq 'discovery'; + for (;;) { + my $old_vconn = db_get('controller-vconn'); + db_input('controller-vconn'); + return 'prev' if db_go(); + + my $vconn = db_get('controller-vconn'); + if (is_valid_vconn($vconn)) { + if ($old_vconn ne $vconn || db_get('pki-uri') eq '') { + db_set('pki-uri', pki_host_to_uri($2)); + } + return 'next'; + } + + db_input('controller-vconn-error'); + db_go(); + } + }, + sub { + return 'skip' if !ssl_enabled(); + + if (! -e $privkey_file) { + my $old_umask = umask(077); + run_cmd("ofp-pki req $etc/of0 >&2 2>/dev/null"); + chmod(0644, $req_file) or die "$req_file: chmod: $!\n"; + umask($old_umask); + } + + if (! -e $cert_file) { + open(REQ, '<', $req_file) or die "$req_file: open: $!\n"; + $req = join('', ); + close(REQ); + $req_fingerprint = sha1_hex($req); + } + return 'skip'; + }, + sub { + return 'skip' if !ssl_enabled(); + return 'skip' if -e $cacert_file && -e $cert_file; + + db_input('pki-uri'); + return 'prev' if db_go(); + return; + }, + sub { + return 'skip' if !ssl_enabled(); + return 'skip' if -e $cacert_file; + + my $pki_uri = db_get('pki-uri'); + if ($pki_uri !~ /:/) { + $pki_uri = pki_host_to_uri($pki_uri); + } else { + # Trim trailing slashes. + $pki_uri =~ s%/+$%%; + } + db_set('pki-uri', $pki_uri); + + my $url = "$pki_uri/controllerca/cacert.pem"; + my $response = $ua->get($url, ':content_file' => $cacert_file); + if ($response->is_success) { + return 'next'; + } + + db_subst('fetch-cacert-failed', 'url', $url); + db_subst('fetch-cacert-failed', 'error', $response->status_line); + db_subst('fetch-cacert-failed', 'pki-uri', $pki_uri); + db_input('fetch-cacert-failed'); + db_go(); + return 'prev'; + }, + sub { + return 'skip' if !ssl_enabled(); + return 'skip' if -e $cert_file; + + for (;;) { + db_set('send-cert-req', 'yes'); + db_input('send-cert-req'); + return 'prev' if db_go(); + return 'next' if db_get('send-cert-req') eq 'no'; + + my $pki_uri = db_get('pki-uri'); + my ($pki_base_uri) = $pki_uri =~ m%^([^/]+://[^/]+)/%; + my $url = "$pki_base_uri/cgi-bin/ofp-pki-cgi"; + my $response = $ua->post($url, {'type' => 'switch', + 'req' => $req}); + return 'next' if $response->is_success; + + db_subst('send-cert-req-failed', 'url', $url); + db_subst('send-cert-req-failed', 'error', + $response->status_line); + db_subst('send-cert-req-failed', 'pki-uri', $pki_uri); + db_input('send-cert-req-failed'); + db_go(); + } + }, + sub { + return 'skip' if !ssl_enabled(); + return 'skip' if $cacert_preverified; + + my ($cacert_fingerprint) = x509_fingerprint($cacert_file); + db_subst('verify-controller-ca', 'fingerprint', $cacert_fingerprint); + db_input('verify-controller-ca'); + return 'prev' if db_go(); + return 'next' if db_get('verify-controller-ca') eq 'yes'; + unlink($cacert_file); + return 'prev'; + }, + sub { + return 'skip' if !ssl_enabled(); + return 'skip' if -e $cert_file; + + for (;;) { + db_set('fetch-switch-cert', 'yes'); + db_input('fetch-switch-cert'); + return 'prev' if db_go(); + exit(1) if db_get('fetch-switch-cert') eq 'no'; + + my $pki_uri = db_get('pki-uri'); + my $url = "$pki_uri/switchca/certs/$req_fingerprint-cert.pem"; + my $response = $ua->get($url, ':content_file' => $cert_file); + if ($response->is_success) { + return 'next'; + } + + db_subst('fetch-switch-cert-failed', 'url', $url); + db_subst('fetch-switch-cert-failed', 'error', + $response->status_line); + db_subst('fetch-switch-cert-failed', 'pki-uri', $pki_uri); + db_input('fetch-switch-cert-failed'); + db_go(); + } + }, + sub { + db_input('complete'); + db_go(); + return; + }, + sub { + return 'done'; + }, +); + +my $state = 1; +my $direction = 1; +for (;;) { + my $ret = &{$states[$state]}(); + $ret = db_go() ? 'prev' : 'next' if !defined $ret; + if ($ret eq 'next') { + $direction = 1; + } elsif ($ret eq 'prev') { + $direction = -1; + } elsif ($ret eq 'skip') { + # Nothing to do. + } elsif ($ret eq 'done') { + last; + } else { + die "unknown ret $ret"; + } + $state += $direction; +} + +my %config = %oldconfig; +$config{NETDEVS} = join(' ', netdev_names()); +$config{MODE} = db_get('mode'); +if (db_get('mode') eq 'in-band') { + $config{SWITCH_IP} = db_get('switch-ip'); +} +if (db_get('mode') ne 'discovery') { + $config{CONTROLLER} = db_get('controller-vconn'); +} +$config{PRIVKEY} = $privkey_file; +$config{CERT} = $cert_file; +$config{CACERT} = $cacert_file; +save_config($default, %config); + +dup2(2, 1); # Get stdout back. +kill_ofp_discover(); +system("/etc/init.d/openflow-switch start"); + +sub ssl_enabled { + return is_ssl_vconn(db_get('controller-vconn')); +} + +sub db_subst { + my ($question, $key, $value) = @_; + $question = "$debconf_owner/$question"; + my ($ret, $seen) = subst($question, $key, $value); + if ($ret && $ret != 30) { + die "Error substituting $value for $key in debconf question " + . "$question: $seen"; + } +} + +sub db_set { + my ($question, $value) = @_; + $question = "$debconf_owner/$question"; + my ($ret, $seen) = set($question, $value); + if ($ret && $ret != 30) { + die "Error setting debconf question $question to $value: $seen"; + } +} + +sub db_get { + my ($question) = @_; + $question = "$debconf_owner/$question"; + my ($ret, $seen) = get($question); + if ($ret) { + die "Error getting debconf question $question answer: $seen"; + } + return $seen; +} + +sub db_fset { + my ($question, $flag, $value) = @_; + $question = "$debconf_owner/$question"; + my ($ret, $seen) = fset($question, $flag, $value); + if ($ret && $ret != 30) { + die "Error setting debconf question $question flag $flag to $value: " + . "$seen"; + } +} + +sub db_fget { + my ($question, $flag) = @_; + $question = "$debconf_owner/$question"; + my ($ret, $seen) = fget($question, $flag); + if ($ret) { + die "Error getting debconf question $question flag $flag: $seen"; + } + return $seen; +} + +sub db_input { + my ($question) = @_; + db_fset($question, "seen", "false"); + + $question = "$debconf_owner/$question"; + my ($ret, $seen) = input('high', $question); + if ($ret && $ret != 30) { + die "Error requesting debconf question $question: $seen"; + } + return $ret; +} + +sub db_go { + my ($ret, $seen) = go(); + if (!defined($ret)) { + exit(1); # Cancel button was pushed. + } + if ($ret && $ret != 30) { + die "Error asking debconf questions: $seen"; + } + return $ret; +} + +sub run_cmd { + my ($cmd) = @_; + return if system($cmd) == 0; + + if ($? == -1) { + die "$cmd: failed to execute: $!\n"; + } elsif ($? & 127) { + die sprintf("$cmd: child died with signal %d, %s coredump\n", + ($? & 127), ($? & 128) ? 'with' : 'without'); + } else { + die sprintf("$cmd: child exited with value %d\n", $? >> 8); + } +} + +sub x509_fingerprint { + my ($file) = @_; + my $cmd = "openssl x509 -noout -in $file -fingerprint"; + open(OPENSSL, '-|', $cmd) or die "$cmd: failed to execute: $!\n"; + my $line = ; + close(OPENSSL); + my ($fingerprint) = $line =~ /SHA1 Fingerprint=(.*)/; + return $line if !defined $fingerprint; + $fingerprint =~ s/://g; + return $fingerprint; +} + +sub find_netdevs { + my ($netdev, %netdevs); + open(IFCONFIG, "/sbin/ifconfig -a|") or die "ifconfig failed: $!"; + while () { + if (my ($nd) = /^([^\s]+)/) { + $netdev = $nd; + $netdevs{$netdev} = "$netdev"; + if (my ($hwaddr) = /HWaddr (\S+)/) { + $netdevs{$netdev} .= " (MAC: $hwaddr)"; + } + } elsif (my ($ip4) = /^\s*inet addr:(\S+)/) { + $netdevs{$netdev} .= " (IP: $ip4)"; + } elsif (my ($ip6) = /^\s*inet6 addr:(\S+)/) { + $netdevs{$netdev} .= " (IPv6: $ip6)"; + } + } + foreach my $nd (keys(%netdevs)) { + delete $netdevs{$nd} if $nd eq 'lo' || $nd =~ /^wmaster/; + } + close(IFCONFIG); + return %netdevs; +} + +sub load_config { + my ($file) = @_; + + # Get the list of the variables that the shell sets automatically. + my (%auto_vars) = read_vars("set -a && env"); + + # Get the variables from $default. + my (%config) = read_vars("set -a && . '$default' && env"); + + # Subtract. + delete @config{keys %auto_vars}; + + return %config; +} + +sub read_vars { + my ($cmd) = @_; + local @ENV; + if (!open(VARS, '-|', $cmd)) { + print STDERR "$cmd: failed to execute: $!\n"; + return (); + } + my (%config); + while () { + my ($var, $value) = /^([^=]+)=(.*)$/ or next; + $config{$var} = $value; + } + close(VARS); + return %config; +} + +sub shell_escape { + local $_ = $_[0]; + if ($_ eq '') { + return '""'; + } elsif (m&^[-a-zA-Z0-9:./%^_+,]*$&) { + return $_; + } else { + s/'/'\\''/; + return "'$_'"; + } +} + +sub shell_assign { + my ($var, $value) = @_; + return $var . '=' . shell_escape($value); +} + +sub save_config { + my ($file, %config) = @_; + my (@lines); + if (open(FILE, '<', $file)) { + @lines = ; + chomp @lines; + close(FILE); + } + + # Replace all existing variable assignments. + for (my ($i) = 0; $i <= $#lines; $i++) { + local $_ = $lines[$i]; + my ($var, $value) = /^\s*([^=#]+)=(.*)$/ or next; + if (exists($config{$var})) { + $lines[$i] = shell_assign($var, $config{$var}); + delete $config{$var}; + } else { + $lines[$i] = "#$lines[$i]"; + } + } + + # Find a place to put any remaining variable assignments. + VAR: + for my $var (keys(%config)) { + my $assign = shell_assign($var, $config{$var}); + + # Replace the last commented-out variable assignment to $var, if any. + for (my ($i) = $#lines; $i >= 0; $i--) { + local $_ = $lines[$i]; + if (/^\s*#\s*$var=/) { + $lines[$i] = $assign; + next VAR; + } + } + + # Find a place to add the var: after the final commented line + # just after a line that contains "$var:". + for (my ($i) = 0; $i <= $#lines; $i++) { + if ($lines[$i] =~ /^\s*#\s*$var:/) { + for (my ($j) = $i + 1; $j <= $#lines; $j++) { + if ($lines[$j] !~ /^\s*#/) { + splice(@lines, $j, 0, $assign); + next VAR; + } + } + } + } + + # Just append it. + push(@lines, $assign); + } + + open(NEWFILE, '>', "$file.tmp") or die "$file.tmp: create: $!\n"; + print NEWFILE join('', map("$_\n", @lines)); + close(NEWFILE); + rename("$file.tmp", $file) or die "$file.tmp: rename to $file: $!\n"; +} + +sub pki_host_to_uri { + my ($pki_host) = @_; + return "http://$pki_host/openflow/pki"; +} + +sub kill_ofp_discover { + # Delegate this to a subprocess because there is no portable way + # to invoke fcntl(F_GETLK) from Perl. + system("ofp-kill --force $ofp_discover_pidfile"); +} + +sub netdev_names { + return map(/^(\S+)/, split(', ', db_get('netdevs'))); +} + +sub is_valid_vconn { + my ($vconn) = @_; + return scalar($vconn =~ /^(tcp|ssl):([^:]+)(:.*)?/); +} + +sub is_ssl_vconn { + my ($vconn) = @_; + return scalar($vconn =~ /^ssl:/); +} diff --git a/openflow/debian/ofp-switch-setup.8 b/openflow/debian/ofp-switch-setup.8 new file mode 100644 index 00000000..50904cfb --- /dev/null +++ b/openflow/debian/ofp-switch-setup.8 @@ -0,0 +1,41 @@ +.TH ofp-switch-setup 8 "June 2008" "OpenFlow" "OpenFlow Manual" + +.SH NAME +ofp\-switch\-setup \- interactive setup for OpenFlow switch + +.SH SYNOPSIS +.B ofp\-switch\-setup + +.SH DESCRIPTION +The \fBofp\-switch\-setup\fR program is an interactive program that +assists the system administrator in configuring an OpenFlow switch, +including the underlying public key infrastructure (PKI). + +.SH OPTIONS +ofp\-switch\-setup does not accept any command-line options. + +.SH FILES +.IP /etc/default/openflow-switch +Main configuration file for OpenFlow switch. + +.IP /etc/openflow-switch/cacert.pem +Default location of CA certificate for OpenFlow controllers. + +.IP /etc/openflow-switch/of0-cert.pem +Default location of certificate for the OpenFlow switch's private key. + +.IP /etc/openflow-switch/of0-privkey.pem +Default location of the OpenFlow switch's private key. This file +should be readable only by \fBroot\fR. + +.IP /etc/openflow-switch/of0-req.pem +Default location of certificate request for the OpenFlow switch's +certificate. This file is not used after the signed certificate +(typically \fB/etc/openflow-switch/of0-cert.pem\fR, above) has been +obtained from the OpenFlow PKI server. + +.SH "SEE ALSO" + +.BR ofp-pki (8), +.BR dpctl (8), +.BR secchan (8) diff --git a/openflow/debian/openflow-common.dirs b/openflow/debian/openflow-common.dirs new file mode 100644 index 00000000..527fe313 --- /dev/null +++ b/openflow/debian/openflow-common.dirs @@ -0,0 +1 @@ +var/log/openflow diff --git a/openflow/debian/openflow-common.install b/openflow/debian/openflow-common.install new file mode 100644 index 00000000..eed7413e --- /dev/null +++ b/openflow/debian/openflow-common.install @@ -0,0 +1,3 @@ +_debian/utilities/ofp-parse-leaks usr/bin +_debian/utilities/ofp-pki usr/sbin +_debian/utilities/vlogconf usr/sbin diff --git a/openflow/debian/openflow-common.manpages b/openflow/debian/openflow-common.manpages new file mode 100644 index 00000000..fbb88201 --- /dev/null +++ b/openflow/debian/openflow-common.manpages @@ -0,0 +1,2 @@ +_debian/utilities/vlogconf.8 +_debian/utilities/ofp-pki.8 diff --git a/openflow/debian/openflow-controller.README.Debian b/openflow/debian/openflow-controller.README.Debian new file mode 100644 index 00000000..19d5cb9b --- /dev/null +++ b/openflow/debian/openflow-controller.README.Debian @@ -0,0 +1,10 @@ +README.Debian for openflow-controller +------------------------------------- + +* To (re)configure the controller, edit /etc/default/openflow-controller + and run "/etc/init.d/openflow-controller restart". + +* To enable OpenFlow switches to automatically discover the location + of the controller, you must install and configure a DHCP server. + The secchan(8) manpage (found in the openflow-switch package) gives + a working example configuration file for the ISC DHCP server. diff --git a/openflow/debian/openflow-controller.default b/openflow/debian/openflow-controller.default new file mode 100644 index 00000000..3b84b62a --- /dev/null +++ b/openflow/debian/openflow-controller.default @@ -0,0 +1,33 @@ +# This is a POSIX shell fragment -*- sh -*- + +# LISTEN: What OpenFlow connection methods should the controller listen on? +# +# This is a space-delimited list of connection methods: +# +# * "pssl:[PORT]": Listen for SSL connections on the specified PORT +# (default: 6633). The private key, certificate, and CA certificate +# must be specified below. +# +# * "pctp:[PORT]": Listen for TCP connections on the specified PORT +# (default: 6633). Not recommended for security reasons. +# +# * "nl:DP_IDX": Listen on local datapath DP_IDX. Used only if this +# machine is also an OpenFlow switch and not running the secure +# channel, and only if you know what you're doing. +# +LISTEN="pssl:" + +# PRIVKEY: Name of file containing controller's private key. +# Required if SSL enabled. +PRIVKEY=/etc/openflow-controller/privkey.pem + +# CERT: Name of file containing certificate for private key. +# Required if SSL enabled. +CERT=/etc/openflow-controller/cert.pem + +# CACERT: Name of file containing switch CA certificate. +# Required if SSL enabled. +CACERT=/etc/openflow-controller/cacert.pem + +# Additional options to pass to controller, e.g. "--hub" +DAEMON_OPTS="" diff --git a/openflow/debian/openflow-controller.dirs b/openflow/debian/openflow-controller.dirs new file mode 100644 index 00000000..0a19a9fc --- /dev/null +++ b/openflow/debian/openflow-controller.dirs @@ -0,0 +1 @@ +etc/openflow-controller diff --git a/openflow/debian/openflow-controller.init b/openflow/debian/openflow-controller.init new file mode 100755 index 00000000..121fd76b --- /dev/null +++ b/openflow/debian/openflow-controller.init @@ -0,0 +1,269 @@ +#!/bin/sh +# +# Copyright (c) 2007 Javier Fernandez-Sanguino +# +# This is free software; you may redistribute it and/or modify +# it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2, +# or (at your option) any later version. +# +# This is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License with +# the Debian operating system, in /usr/share/common-licenses/GPL; if +# not, write to the Free Software Foundation, Inc., 59 Temple Place, +# Suite 330, Boston, MA 02111-1307 USA +# +### BEGIN INIT INFO +# Provides: openflow-controller +# Required-Start: $network $local_fs +# Required-Stop: +# Should-Start: $named +# Should-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: OpenFlow controller +### END INIT INFO + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin + +DAEMON=/usr/sbin/controller # Introduce the server's location here +NAME=controller # Introduce the short server's name here +DESC=controller # Introduce a short description here +LOGDIR=/var/log/openflow # Log directory to use + +PIDFILE=/var/run/$NAME.pid + +test -x $DAEMON || exit 0 + +. /lib/lsb/init-functions + +# Default options, these can be overriden by the information +# at /etc/default/$NAME +DAEMON_OPTS="" # Additional options given to the server + +DODTIME=10 # Time to wait for the server to die, in seconds + # If this value is set too low you might not + # let some servers to die gracefully and + # 'restart' will not work + +LOGFILE=$LOGDIR/$NAME.log # Server logfile +#DAEMONUSER= # User to run the daemons as. If this value + # is set start-stop-daemon will chuid the server + +# Include defaults if available +default=/etc/default/openflow-controller +if [ -f $default ] ; then + . $default +fi + +# Check that the user exists (if we set a user) +# Does the user exist? +if [ -n "$DAEMONUSER" ] ; then + if getent passwd | grep -q "^$DAEMONUSER:"; then + # Obtain the uid and gid + DAEMONUID=`getent passwd |grep "^$DAEMONUSER:" | awk -F : '{print $3}'` + DAEMONGID=`getent passwd |grep "^$DAEMONUSER:" | awk -F : '{print $4}'` + else + log_failure_msg "The user $DAEMONUSER, required to run $NAME does not exist." + exit 1 + fi +fi + + +set -e + +running_pid() { +# Check if a given process pid's cmdline matches a given name + pid=$1 + name=$2 + [ -z "$pid" ] && return 1 + [ ! -d /proc/$pid ] && return 1 + cmd=`cat /proc/$pid/cmdline | tr "\000" "\n"|head -n 1 |cut -d : -f 1` + # Is this the expected server + [ "$cmd" != "$name" ] && return 1 + return 0 +} + +running() { +# Check if the process is running looking at /proc +# (works for all users) + + # No pidfile, probably no daemon present + [ ! -f "$PIDFILE" ] && return 1 + pid=`cat $PIDFILE` + running_pid $pid $DAEMON || return 1 + return 0 +} + +start_server() { + if [ -z "$LISTEN" ]; then + echo "$default: No connection methods configured, controller disabled" >&2 + exit 0 + fi + + SSL_OPTS= + case $LISTEN in + *ssl*) + : ${PRIVKEY:=/etc/openflow-controller/privkey.pem} + : ${CERT:=/etc/openflow-controller/cert.pem} + : ${CACERT:=/etc/openflow-controller/cacert.pem} + if test ! -e "$PRIVKEY" || test ! -e "$CERT" || + test ! -e "$CACERT"; then + if test ! -e "$PRIVKEY"; then + echo "$PRIVKEY: private key missing" >&2 + fi + if test ! -e "$CERT"; then + echo "$CERT: certificate for private key missing" >&2 + fi + if test ! -e "$CACERT"; then + echo "$CACERT: CA certificate missing" >&2 + fi + exit 1 + fi + SSL_OPTS="--private-key=$PRIVKEY --certificate=$CERT --ca-cert=$CACERT" + ;; + esac + +# Start the process using the wrapper + if [ -z "$DAEMONUSER" ] ; then + start-stop-daemon --start --pidfile $PIDFILE \ + --exec $DAEMON -- --detach --pidfile=$PIDFILE \ + $LISTEN $DAEMON_OPTS $SSL_OPTS + errcode=$? + else +# if we are using a daemonuser then change the user id + start-stop-daemon --start --quiet --pidfile $PIDFILE \ + --chuid $DAEMONUSER --exec $DAEMON -- \ + --detach --pidfile=$PIDFILE $LISTEN $DAEMON_OPTS \ + $SSL_OPTS + errcode=$? + fi + return $errcode +} + +stop_server() { +# Stop the process using the wrapper + if [ -z "$DAEMONUSER" ] ; then + start-stop-daemon --stop --quiet --pidfile $PIDFILE \ + --exec $DAEMON + errcode=$? + else +# if we are using a daemonuser then look for process that match + start-stop-daemon --stop --quiet --pidfile $PIDFILE \ + --user $DAEMONUSER --exec $DAEMON + errcode=$? + fi + + return $errcode +} + +reload_server() { + [ ! -f "$PIDFILE" ] && return 1 + pid=`cat $PIDFILE` # This is the daemon's pid + # Send a SIGHUP + kill -1 $pid + return $? +} + +force_stop() { +# Force the process to die killing it manually + [ ! -e "$PIDFILE" ] && return + if running ; then + kill -15 $pid + # Is it really dead? + sleep "$DIETIME"s + if running ; then + kill -9 $pid + sleep "$DIETIME"s + if running ; then + echo "Cannot kill $NAME (pid=$pid)!" + exit 1 + fi + fi + fi + rm -f $PIDFILE +} + + +case "$1" in + start) + log_daemon_msg "Starting $DESC " "$NAME" + # Check if it's running first + if running ; then + log_progress_msg "apparently already running" + log_end_msg 0 + exit 0 + fi + if start_server && running ; then + # It's ok, the server started and is running + log_end_msg 0 + else + # Either we could not start it or it is not running + # after we did + # NOTE: Some servers might die some time after they start, + # this code does not try to detect this and might give + # a false positive (use 'status' for that) + log_end_msg 1 + fi + ;; + stop) + log_daemon_msg "Stopping $DESC" "$NAME" + if running ; then + # Only stop the server if we see it running + stop_server + log_end_msg $? + else + # If it's not running don't do anything + log_progress_msg "apparently not running" + log_end_msg 0 + exit 0 + fi + ;; + force-stop) + # First try to stop gracefully the program + $0 stop + if running; then + # If it's still running try to kill it more forcefully + log_daemon_msg "Stopping (force) $DESC" "$NAME" + force_stop + log_end_msg $? + fi + ;; + restart|force-reload) + log_daemon_msg "Restarting $DESC" "$NAME" + stop_server + # Wait some sensible amount, some server need this + [ -n "$DIETIME" ] && sleep $DIETIME + start_server + running + log_end_msg $? + ;; + status) + + log_daemon_msg "Checking status of $DESC" "$NAME" + if running ; then + log_progress_msg "running" + log_end_msg 0 + else + log_progress_msg "apparently not running" + log_end_msg 1 + exit 1 + fi + ;; + # Use this if the daemon cannot reload + reload) + log_warning_msg "Reloading $NAME daemon: not implemented, as the daemon" + log_warning_msg "cannot re-read the config file (use restart)." + ;; + *) + N=/etc/init.d/$NAME + echo "Usage: $N {start|stop|force-stop|restart|force-reload|status}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/openflow/debian/openflow-controller.install b/openflow/debian/openflow-controller.install new file mode 100644 index 00000000..3932ab6a --- /dev/null +++ b/openflow/debian/openflow-controller.install @@ -0,0 +1 @@ +_debian/controller/controller usr/sbin diff --git a/openflow/debian/openflow-controller.manpages b/openflow/debian/openflow-controller.manpages new file mode 100644 index 00000000..3fbaaeaf --- /dev/null +++ b/openflow/debian/openflow-controller.manpages @@ -0,0 +1 @@ +_debian/controller/controller.8 diff --git a/openflow/debian/openflow-controller.postinst b/openflow/debian/openflow-controller.postinst new file mode 100755 index 00000000..93e39116 --- /dev/null +++ b/openflow/debian/openflow-controller.postinst @@ -0,0 +1,52 @@ +#!/bin/sh +# postinst script for openflow-controller +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `configure' +# * `abort-upgrade' +# * `abort-remove' `in-favour' +# +# * `abort-remove' +# * `abort-deconfigure' `in-favour' +# `removing' +# +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + configure) + cd /etc/openflow-controller + if ! test -e cacert.pem; then + ln -s /usr/share/openflow/pki/switchca/cacert.pem cacert.pem + fi + if ! test -e privkey.pem || ! test -e cert.pem; then + oldumask=$(umask) + umask 077 + ofp-pki req+sign tmp controller >/dev/null + mv tmp-privkey.pem privkey.pem + mv tmp-cert.pem cert.pem + mv tmp-req.pem req.pem + chmod go+r cert.pem req.pem + umask $oldumask + fi + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +#DEBHELPER# + +exit 0 + + diff --git a/openflow/debian/openflow-datapath-module-_KVERS_.postinst.modules.in b/openflow/debian/openflow-datapath-module-_KVERS_.postinst.modules.in new file mode 100755 index 00000000..6974e13a --- /dev/null +++ b/openflow/debian/openflow-datapath-module-_KVERS_.postinst.modules.in @@ -0,0 +1,25 @@ +#!/bin/sh +# postinst script for #PACKAGE# +# +# see: dh_installdeb(1) + +set -e + +depmod -a + +#DEBHELPER# + +# If the switch is running, restart it. This ensures that we are using the +# latest kernel module, because the init script will unload and reload the +# module. +# +# (Ideally we'd only want to do this if this package corresponds to the +# running kernel, but I don't know a reliable way to check.) +INIT=/etc/init.d/openflow-switch +if test -x $INIT && $INIT status; then + $INIT restart || true +fi + +exit 0 + + diff --git a/openflow/debian/openflow-datapath-source.README.Debian b/openflow/debian/openflow-datapath-source.README.Debian new file mode 100644 index 00000000..59965df9 --- /dev/null +++ b/openflow/debian/openflow-datapath-source.README.Debian @@ -0,0 +1,31 @@ +OpenFlow for Debian +------------------- + +* How do I build this module the Debian way? + + - Building with module-assistant: + + $ module-assistant auto-install openflow + or + $ m-a a-i openflow + + If kernel source or headers are in a non-standard directory, add + the option -k /path/to/kernel/source with the correct path. + + - Building with make-kpkg + + $ cd /usr/src/ + $ tar jxvf openflow.tar.bz2 + $ cd /usr/src/kernel-source-2.6.9 + $ make-kpkg --added-modules=openflow modules + + - Building without make-kpkg + + $ cd /usr/src/ + $ tar jxvf openflow.tar.bz2 + $ cd modules/openflow + $ fakeroot debian/rules kdist_image + + If you run this as root, fakeroot is not needed. + + -- OpenFlow Team , Thu, 12 Jun 2008 16:42:38 -0700 diff --git a/openflow/debian/openflow-datapath-source.copyright b/openflow/debian/openflow-datapath-source.copyright new file mode 100644 index 00000000..f7bcdda3 --- /dev/null +++ b/openflow/debian/openflow-datapath-source.copyright @@ -0,0 +1,16 @@ +Upstream Authors: + + The Board of Trustees of The Leland Stanford Junior University + +Copyright: + + Copyright (C) 2008 The Board of Trustees of The Leland Stanford + Junior University + +License: + + Files in the datapath/ and its sub-directories are covered under the GNU + General Public License Version 2. + + On Debian systems, the complete text of the GNU General + Public License can be found in `/usr/share/common-licenses/GPL'. diff --git a/openflow/debian/openflow-datapath-source.dirs b/openflow/debian/openflow-datapath-source.dirs new file mode 100644 index 00000000..4ddf234a --- /dev/null +++ b/openflow/debian/openflow-datapath-source.dirs @@ -0,0 +1 @@ +usr/src/modules/openflow-datapath/debian diff --git a/openflow/debian/openflow-datapath-source.install b/openflow/debian/openflow-datapath-source.install new file mode 100644 index 00000000..a74f13dc --- /dev/null +++ b/openflow/debian/openflow-datapath-source.install @@ -0,0 +1,6 @@ +debian/changelog usr/src/modules/openflow-datapath/debian +debian/control usr/src/modules/openflow-datapath/debian +debian/compat usr/src/modules/openflow-datapath/debian +debian/*.modules.in usr/src/modules/openflow-datapath/debian +debian/rules usr/src/modules/openflow-datapath/debian +_debian/openflow.tar.gz usr/src/modules/openflow-datapath diff --git a/openflow/debian/openflow-pki-server.apache2 b/openflow/debian/openflow-pki-server.apache2 new file mode 100644 index 00000000..a341c508 --- /dev/null +++ b/openflow/debian/openflow-pki-server.apache2 @@ -0,0 +1 @@ +Alias /openflow/pki/ /usr/share/openflow/pki/ diff --git a/openflow/debian/openflow-pki-server.dirs b/openflow/debian/openflow-pki-server.dirs new file mode 100644 index 00000000..7307777b --- /dev/null +++ b/openflow/debian/openflow-pki-server.dirs @@ -0,0 +1 @@ +etc/apache2/sites-available diff --git a/openflow/debian/openflow-pki-server.install b/openflow/debian/openflow-pki-server.install new file mode 100644 index 00000000..cd530ca4 --- /dev/null +++ b/openflow/debian/openflow-pki-server.install @@ -0,0 +1 @@ +_debian/utilities/ofp-pki-cgi usr/lib/cgi-bin diff --git a/openflow/debian/openflow-pki-server.postinst b/openflow/debian/openflow-pki-server.postinst new file mode 100755 index 00000000..d161a98a --- /dev/null +++ b/openflow/debian/openflow-pki-server.postinst @@ -0,0 +1,44 @@ +#!/bin/sh +# postinst script for openflow +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `configure' +# * `abort-upgrade' +# * `abort-remove' `in-favour' +# +# * `abort-remove' +# * `abort-deconfigure' `in-favour' +# `removing' +# +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package + +case "$1" in + configure) + # Enable site under Apache. + a2ensite openflow-pki >/dev/null + if command -v invoke-rc.d >/dev/null 2>&1; then + invoke-rc.d apache2 force-reload || : + else + [ -x /etc/init.d/apache2 ] && /etc/init.d/apache2 force-reload || : + fi + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +#DEBHELPER# + +exit 0 + + diff --git a/openflow/debian/openflow-pki.postinst b/openflow/debian/openflow-pki.postinst new file mode 100755 index 00000000..5cf6515d --- /dev/null +++ b/openflow/debian/openflow-pki.postinst @@ -0,0 +1,41 @@ +#!/bin/sh +# postinst script for openflow +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `configure' +# * `abort-upgrade' +# * `abort-remove' `in-favour' +# +# * `abort-remove' +# * `abort-deconfigure' `in-favour' +# `removing' +# +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package + +case "$1" in + configure) + # Create certificate authorities. + if test ! -d /usr/share/openflow/pki; then + ofp-pki init + fi + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +#DEBHELPER# + +exit 0 + + diff --git a/openflow/debian/openflow-switch-config.dirs b/openflow/debian/openflow-switch-config.dirs new file mode 100644 index 00000000..881ded8a --- /dev/null +++ b/openflow/debian/openflow-switch-config.dirs @@ -0,0 +1 @@ +/usr/share/lintian/overrides diff --git a/openflow/debian/openflow-switch-config.install b/openflow/debian/openflow-switch-config.install new file mode 100644 index 00000000..75c50083 --- /dev/null +++ b/openflow/debian/openflow-switch-config.install @@ -0,0 +1 @@ +debian/ofp-switch-setup usr/sbin diff --git a/openflow/debian/openflow-switch-config.manpages b/openflow/debian/openflow-switch-config.manpages new file mode 100644 index 00000000..e176dad9 --- /dev/null +++ b/openflow/debian/openflow-switch-config.manpages @@ -0,0 +1 @@ +debian/ofp-switch-setup.8 diff --git a/openflow/debian/openflow-switch-config.overrides b/openflow/debian/openflow-switch-config.overrides new file mode 100644 index 00000000..4ac77aba --- /dev/null +++ b/openflow/debian/openflow-switch-config.overrides @@ -0,0 +1 @@ +debconf-is-not-a-registry diff --git a/openflow/debian/openflow-switch-config.templates b/openflow/debian/openflow-switch-config.templates new file mode 100644 index 00000000..78761097 --- /dev/null +++ b/openflow/debian/openflow-switch-config.templates @@ -0,0 +1,228 @@ +Template: openflow-switch/netdevs +Type: multiselect +_Choices: ${choices} +_Description: OpenFlow switch network devices: + Choose the network devices that should become part of the OpenFlow + switch. At least two devices must be selected for this machine to be + a useful switch. Unselecting all network devices will disable the + OpenFlow switch entirely. + . + The network devices that you select should not be configured with IP + or IPv6 addresses, even if the switch contacts the controller over + one of the selected network devices. This is because a running + OpenFlow switch takes over network devices at a low level: they + become part of the switch and cannot be used for other purposes. + +Template: openflow-switch/no-netdevs +Type: error +_Description: No network devices were selected. + No network devices were selected for inclusion in the OpenFlow switch. + The switch will be disabled. + +Template: openflow-switch/configured-netdevs +Type: note +_Description: Some Network Devices Have IP or IPv6 Addresses + The following network devices selected to be part of the OpenFlow switch + have IP or IPv6 addresses configured: + . + ${configured-netdevs} + . + This is usually a mistake, even if the switch contacts the controller over + one of the selected network devices. This is because a running + OpenFlow switch takes over network devices at a low level: they + become part of the switch and cannot be used for other purposes. + . + If this is an unintentional mistake, move back and fix the selection, + or de-configure the IP or IPv6 from these network devices. + +Template: openflow-switch/mode +Type: select +_Choices: discovery, in-band, out-of-band +Default: discovery +_Description: Switch-to-controller access method: + The OpenFlow switch must be able to contact the OpenFlow controller over + the network. It can do so in one of three ways: + . + discovery: A single network is used for OpenFlow traffic and other + data traffic; that is, the switch contacts the controller over one of + the network devices selected as OpenFlow switch network devices in + the previous question. The switch automatically determines the + location of the controller using a DHCP request with an + OpenFlow-specific vendor option. This is the most common case. + . + in-band: As above, but the location of the controller is manually + configured. + . + out-of-band: OpenFlow traffic uses a network separate from the data traffic + that it controls. If this is the case, the control network must already + be configured on a network device other than one of those selected as + an OpenFlow switch netdev in the previous question. + +Template: openflow-switch/discover +Type: note +_Description: Preparing to discover controller. + The setup program will now attempt to discover the OpenFlow controller. + Controller discovery may take up to 30 seconds. Please be patient. + . + See secchan(8) for instructions on how to configure a DHCP server for + controller discovery. + +Template: openflow-switch/discovery-failure +Type: error +_Description: Controller discovery failed. + The controller's location could not be determined automatically. + . + Ensure that the OpenFlow DHCP server is properly configured. See + secchan(8) for instructions on how to configure a DHCP server for + controller discovery. + +Template: openflow-switch/discovery-success +Type: boolean +Default: true +_Description: Use discovered settings? + Controller discovery obtained the following settings: + . + Controller location: ${controller-vconn} + . + PKI URL: ${pki-uri} + . + Please verify that these settings are correct. + +Template: openflow-switch/switch-ip +Type: string +Default: dhcp +_Description: Switch IP address: + For in-band communication with the controller, the OpenFlow switch must + be able to determine its own IP address. Its IP address may be configured + statically or dynamically. + . + For static configuration, specify the switch's IP address as a string. + . + For dynamic configuration with DHCP (the most common case), specify "dhcp". + Configuration with DHCP will only work reliably if the network topology + allows the switch to contact the DHCP server before it connects to the + OpenFlow controller. + +Template: openflow-switch/switch-ip-error +Type: error +_Description: The switch IP address is invalid. + The switch IP address must specified as "dhcp" or a valid IP address in + dotted-octet form (e.g. "1.2.3.4"). + +Template: openflow-switch/controller-vconn +Type: string +_Description: Controller location: + Specify how the OpenFlow switch should connect to the OpenFlow controller. + The value should be in form "ssl:HOST[:PORT]" to connect to the controller + over SSL (recommended for security) or "tcp:HOST[:PORT]" to connect over + cleartext TCP. + +Template: openflow-switch/controller-vconn-error +Type: error +_Description: The controller location is invalid. + The controller location must be specifed as "ssl:HOST[:PORT]" to + connect to the controller over SSL (recommended for security) or + "tcp:HOST[:PORT]" to connect over cleartext TCP. + +Template: openflow-switch/pki-uri +Type: string +_Description: OpenFlow PKI server host name or URL: + Specify a URL to the OpenFlow public key infrastructure (PKI). If a + host name or IP address is specified in place of a URL, then + http:///openflow/pki/ will be used, + where is the specified host name or IP address. + . + The OpenFlow PKI is usually on the same machine as the OpenFlow + controller. + . + The setup process will connect to the OpenFlow PKI server over + HTTP, using the system's configured default HTTP proxy (if any). + +Template: openflow-switch/fetch-cacert-failed +Type: error +_Description: The switch CA certificate could not be retrieved. + Retrieval of ${url} failed, with the following status: "${error}". + . + Ensure that the OpenFlow PKI server is correctly configured and + available at ${pki-uri}. If the system is configured to use an HTTP + proxy, also make sure that the HTTP proxy is available and that the + PKI server can be reached through it. + +Template: openflow-switch/verify-controller-ca +Type: select +_Choices: yes, no +Default: yes +_Description: Is ${fingerprint} the controller CA's fingerprint? + If a man-in-the-middle attack is possible in your network + environment, check that the controller CA's fingerprint is really + ${fingerprint}. Answer "yes" if it matches, "no" if + there is a discrepancy. + . + If a man-in-the-middle attack is not a concern, there is no need to + verify the fingerprint. Simply answer "yes". + +Template: openflow-switch/send-cert-req +Type: select +_Choices: yes, no +Default: yes +_Description: Send certificate request to switch CA? + Before it can connect to the controller over SSL, the OpenFlow + switch's key must be signed by the switch certificate authority (CA) + located on the OpenFlow PKI server, which is usually collocated with + the OpenFlow controller. A signing request can be sent to the PKI + server now. + . + Answer "yes" to send a signing request to the switch CA now. This is + ordinarily the correct choice. There is no harm in sending a given + signing request more than once. + . + Answer "no" to skip sending a signing request to the switch CA. + Unless the request has already been sent to the switch CA, manual + sending of the request and signing will be necessary. + +Template: openflow-switch/send-cert-req-failed +Type: error +_Description: The certificate request could not be sent. + Posting to ${url} failed, with the following status: "${error}". + . + Ensure that the OpenFlow PKI server is correctly configured and + available at ${pki-uri}. + +Template: openflow-switch/fetch-switch-cert +Type: select +_Choices: yes, no +_Description: Fetch signed switch certificate from PKI server? + Before it can connect to the controller over SSL, the OpenFlow + switch's key must be signed by the switch certificate authority (CA) + located on the OpenFlow PKI server, which is usually collocated with + the OpenFlow controller. + . + At this point, a signing request has been sent to the switch CA (or + sending a request has been manually skipped), but the signed + certificate has not yet been retrieved. Manual action may need to be + taken at the PKI server to approve the signing request. + . + Answer "yes" to attempt to retrieve the signed switch certificate + from the switch CA. If the switch certificate request has been + signed at the PKI server, this is the correct choice. + . + Answer "no" to postpone switch configuration. The configuration + process must be restarted later, when the switch certificate request + has been signed. + +Template: openflow-switch/fetch-switch-cert-failed +Type: error +_Description: Signed switch certificate could not be retrieved. + The signed switch certificate could not be retrieved from the switch + CA: retrieval of ${url} failed, with the following status: "${error}". + . + This probably indicates that the switch's certificate request has not + yet been signed. If this is the problem, it may be fixed by signing + the certificate request at ${pki-uri}, then trying to fetch the + signed switch certificate again. + +Template: openflow-switch/complete +Type: note +_Description: OpenFlow Switch Setup Finished + Setup of this OpenFlow switch is finished. Complete the setup procedure + to enable the switch. diff --git a/openflow/debian/openflow-switch.README.Debian b/openflow/debian/openflow-switch.README.Debian new file mode 100644 index 00000000..d9a931c1 --- /dev/null +++ b/openflow/debian/openflow-switch.README.Debian @@ -0,0 +1,18 @@ +README.Debian for openflow-switch +--------------------------------- + +* The switch must be configured before it can be used. To configure + it interactively, install the openflow-switch-config package and run + the ofp-switch-setup program. Alternatively, edit + /etc/default/openflow-switch by hand, then start the switch manually + with "/etc/init.d/openflow-switch start". + +* To use the Linux kernel-based switch implementation, you will need + to build and install the OpenFlow kernel module. To do so, install + the openflow-datapath-source package, then follow the instructions + given in /usr/share/doc/openflow-datapath-source/README.Debian + +* This package does not yet support the userspace datapath-based + switch implementation. + + -- Ben Pfaff , Tue, 6 Jan 2009 13:52:33 -0800 diff --git a/openflow/debian/openflow-switch.dirs b/openflow/debian/openflow-switch.dirs new file mode 100644 index 00000000..a53002ff --- /dev/null +++ b/openflow/debian/openflow-switch.dirs @@ -0,0 +1,2 @@ +/etc/openflow-switch +/usr/share/openflow/switch diff --git a/openflow/debian/openflow-switch.init b/openflow/debian/openflow-switch.init new file mode 100755 index 00000000..cd518a71 --- /dev/null +++ b/openflow/debian/openflow-switch.init @@ -0,0 +1,437 @@ +#! /bin/sh +# +# /etc/init.d/openflow-switch +# +# Written by Miquel van Smoorenburg . +# Modified for Debian by Ian Murdock . +# Further changes by Javier Fernandez-Sanguino +# Modified for openflow-switch. +# +# Version: @(#)skeleton 1.9 26-Feb-2001 miquels@cistron.nl +# +### BEGIN INIT INFO +# Provides: openflow-switch +# Required-Start: $network $named $remote_fs $syslog +# Required-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: OpenFlow switch +### END INIT INFO + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +DAEMON=/usr/sbin/secchan +NAME=secchan +DESC=secchan + +test -x $DAEMON || exit 0 + +NICIRA_OUI="002320" + +LOGDIR=/var/log/openflow +PIDFILE=/var/run/$NAME.pid +DHCLIENT_PIDFILE=/var/run/dhclient.of0.pid +DODTIME=1 # Time to wait for the server to die, in seconds + # If this value is set too low you might not + # let some servers to die gracefully and + # 'restart' will not work + +# Include secchan defaults if available +unset NETDEVS +unset MODE +unset SWITCH_IP +unset CONTROLLER +unset PRIVKEY +unset CERT +unset CACERT +unset CACERT_MODE +unset MGMT_VCONNS +unset COMMANDS +unset DAEMON_OPTS +unset CORE_LIMIT +unset DATAPATH_ID +default=/etc/default/openflow-switch +if [ -f $default ] ; then + . $default +fi + +set -e + +running_pid() +{ + # Check if a given process pid's cmdline matches a given name + pid=$1 + name=$2 + [ -z "$pid" ] && return 1 + [ ! -d /proc/$pid ] && return 1 + cmd=`cat /proc/$pid/cmdline | tr "\000" "\n"|head -n 1 |cut -d : -f 1` + # Is this the expected child? + case $cmd in + $name|*/$name) + return 0 + ;; + *) + return 1 + ;; + esac +} + +running() +{ +# Check if the process is running looking at /proc +# (works for all users) + + # No pidfile, probably no daemon present + [ ! -f "$PIDFILE" ] && return 1 + # Obtain the pid and check it against the binary name + pid=`cat $PIDFILE` + running_pid $pid $NAME || return 1 + return 0 +} + +force_stop() { +# Forcefully kill the process + [ ! -f "$PIDFILE" ] && return + if running ; then + kill -15 $pid + # Is it really dead? + [ -n "$DODTIME" ] && sleep "$DODTIME"s + if running ; then + kill -9 $pid + [ -n "$DODTIME" ] && sleep "$DODTIME"s + if running ; then + echo "Cannot kill $NAME (pid=$pid)!" + exit 1 + fi + fi + fi + rm -f $PIDFILE + return 0 +} + +must_succeed() { + echo -n "$1: " + shift + if "$@"; then + echo "success." + else + echo " ERROR." + exit 1 + fi +} + +check_op() { + echo -n "$1: " + shift + if "$@"; then + echo "success." + else + echo " ERROR." + fi +} + +configure_ssl() { + if (test "$CACERT_MODE" != secure && test "$CACERT_MODE" != bootstrap) \ + || test ! -e "$PRIVKEY" || test ! -e "$CERT" \ + || (test ! -e "$CACERT" && test "$CACERT_MODE" != bootstrap); then + if test "$CACERT_MODE" != secure && test "$CACERT_MODE" != bootstrap + then + echo "CACERT_MODE is not set to 'secure' or 'bootstrap'" + fi + if test ! -e "$PRIVKEY"; then + echo "$PRIVKEY: private key missing" >&2 + fi + if test ! -e "$CERT"; then + echo "$CERT: certificate for private key missing" >&2 + fi + if test ! -e "$CACERT" && test "$CACERT_MODE" != bootstrap; then + echo "$CACERT: CA certificate missing (and CA certificate bootstrapping not enabled)" >&2 + fi + echo "Run ofp-switch-setup (in the openflow-switch-config package) or edit /etc/default/openflow-switch to configure" >&2 + if test "$MODE" = discovery; then + echo "You may also delete or rename $PRIVKEY to disable SSL requirement" >&2 + fi + exit 1 + fi + + SSL_OPTS="--private-key=$PRIVKEY --certificate=$CERT" + if test ! -e "$CACERT" && test "$CACERT_MODE" = bootstrap; then + SSL_OPTS="$SSL_OPTS --bootstrap-ca-cert=$CACERT" + else + SSL_OPTS="$SSL_OPTS --ca-cert=$CACERT" + fi +} + +check_int_var() { + eval value=\$$1 + if test -n "$value"; then + if expr "X$value" : 'X[0-9][0-9]*$'; then + if test $value -lt $2; then + echo "warning: The $1 option may not be set to a value below $2, treating as $2" >&2 + eval $1=$2 + fi + else + echo "warning: The $1 option must be set to a number, ignoring" >&2 + unset $1 + fi + fi +} + +check_new_option() { + case $DAEMON_OPTS in + *$1*) + echo "warning: The $1 option in DAEMON_OPTS may now be set with the $2 variable in $default. The setting in DAEMON_OPTS will override the $2 variable, which will prevent the switch UI from configuring $1." >&2 + ;; + esac +} + +case "$1" in + start) + if test -z "$NETDEVS"; then + echo "$default: No network devices configured, switch disabled" >&2 + echo "Run ofp-switch-setup (in the openflow-switch-config package) or edit /etc/default/openflow-switch to configure" >&2 + exit 0 + fi + if test "$MODE" = discovery; then + unset CONTROLLER + elif test "$MODE" = in-band || test "$MODE" = out-of-band; then + if test -z "$CONTROLLER"; then + echo "$default: No controller configured and not configured for discovery, switch disabled" >&2 + echo "Run ofp-switch-setup (in the openflow-switch-config package) or edit /etc/default/openflow-switch to configure" >&2 + exit 0 + fi + else + echo "$default: MODE must set to 'discovery', 'in-band', or 'out-of-band'" >&2 + echo "Run ofp-switch-setup (in the openflow-switch-config package) or edit /etc/default/openflow-switch to configure" >&2 + exit 1 + fi + : ${PRIVKEY:=/etc/openflow-switch/of0-privkey.pem} + : ${CERT:=/etc/openflow-switch/of0-cert.pem} + : ${CACERT:=/etc/openflow-switch/cacert.pem} + case $CONTROLLER in + '') + # Discovery mode. + if test -e "$PRIVKEY"; then + configure_ssl + fi + ;; + tcp:*) + ;; + ssl:*) + configure_ssl + ;; + *) + echo "$default: CONTROLLER must be in the form 'ssl:HOST[:PORT]' or 'tcp:HOST[:PORT]' when not in discovery mode" >&2 + echo "Run ofp-switch-setup (in the openflow-switch-config package) or edit /etc/default/openflow-switch to configure" >&2 + exit 1 + esac + case $DISCONNECTED_MODE in + ''|switch|drop) ;; + *) echo "$default: warning: DISCONNECTED_MODE is not 'switch' or 'drop'" >&2 ;; + esac + + check_int_var RATE_LIMIT 100 + check_int_var INACTIVITY_PROBE 5 + check_int_var MAX_BACKOFF 1 + + check_new_option --fail DISCONNECTED_MODE + check_new_option --stp STP + check_new_option --rate-limit RATE_LIMIT + check_new_option --inactivity INACTIVITY_PROBE + check_new_option --max-backoff MAX_BACKOFF + case $DAEMON_OPTS in + *--rate-limit*) + echo "$default: --rate-limit may now be set with RATE_LIMIT" >&2 + esac + + echo -n "Loading openflow_mod: " + if grep -q '^openflow_mod$' /proc/modules; then + echo "already loaded, nothing to do." + elif modprobe openflow_mod; then + echo "success." + else + echo "ERROR." + echo "openflow_mod has probably not been built for this kernel." + if ! test -d /usr/share/doc/openflow-datapath-source; then + echo "Install the openflow-datapath-source package, then read" + echo "/usr/share/doc/openflow-datapath-source/README.Debian" + else + echo "For instructions, read" + echo "/usr/share/doc/openflow-datapath-source/README.Debian" + fi + exit 1 + fi + + for netdev in $NETDEVS; do + check_op "Removing IP address from $netdev" ifconfig $netdev 0.0.0.0 + done + + must_succeed "Adding datapath" dpctl adddp nl:0 + for netdev in $NETDEVS; do + must_succeed "Adding $netdev to datapath" dpctl addif nl:0 $netdev + done + + xx='[0-9abcdefABCDEF][0-9abcdefABCDEF]' + case $DATAPATH_ID in + '') + # Check if the DMI System UUID contains a Nicira mac address + # that should be used for this datapath. The UUID is assumed + # to be RFC 4122 compliant. + DMIDECODE=`which dmidecode` + if [ -n $DMIDECODE ]; then + UUID_MAC=`$DMIDECODE -s system-uuid | cut -d'-' -f 5` + case $UUID_MAC in + $NICIRA_OUI*) + ifconfig of0 down + must_succeed "Setting of0 MAC address to $UUID_MAC" ifconfig of0 hw ether $UUID_MAC + ifconfig of0 up + ;; + esac + fi + ;; + $xx:$xx:$xx:$xx:$xx:$xx) + ifconfig of0 down + must_succeed "Setting of0 MAC address to $DATAPATH_ID" ifconfig of0 hw ether $DATAPATH_ID + ifconfig of0 up + ;; + *) + echo "DATAPATH_ID is not a valid MAC address in the form XX:XX:XX:XX:XX:XX, ignoring" >&2 + ;; + esac + + if test "$MODE" = in-band; then + if test "$SWITCH_IP" = dhcp; then + must_succeed "Temporarily disabling of0" ifconfig of0 down + else + COMMAND="ifconfig of0 $SWITCH_IP" + if test -n "$SWITCH_NETMASK"; then + COMMAND="$COMMAND netmask $SWITCH_NETMASK" + fi + must_succeed "Configuring of0: $COMMAND" $COMMAND + if test -n "$SWITCH_GATEWAY"; then + # This can fail because the route already exists, + # so we don't insist that it succeed. + COMMAND="route add default gw $SWITCH_GATEWAY" + check_op "Adding default route: $COMMAND" $COMMAND + fi + fi + else + must_succeed "Disabling of0" ifconfig of0 down + fi + + if test -n "$CORE_LIMIT"; then + check_op "Setting core limit to $CORE_LIMIT" ulimit -c "$CORE_LIMIT" + fi + + # Compose secchan options. + set -- + set -- "$@" --verbose=ANY:console:emer --verbose=ANY:syslog:err + set -- "$@" --log-file + set -- "$@" --detach --pidfile=$PIDFILE + for vconn in $MGMT_VCONNS; do + set -- "$@" --listen="$vconn" + done + if test -n "$MONITOR_VCONN"; then + set -- "$@" --monitor="$MONITOR_VCONN" + fi + if test -n "$COMMANDS"; then + set -- "$@" --command-acl="$COMMANDS" + fi + case $STP in + yes) set -- "$@" --stp ;; + no) set -- "$@" --no-stp ;; + esac + case $DISCONNECTED_MODE in + switch) set -- "$@" --fail=open ;; + drop) set -- "$@" --fail=closed ;; + esac + if test -n "$RATE_LIMIT"; then + set -- "$@" --rate-limit=$RATE_LIMIT + fi + if test -n "$INACTIVITY_PROBE"; then + set -- "$@" --inactivity-probe=$INACTIVITY_PROBE + fi + if test -n "$MAX_BACKOFF"; then + set -- "$@" --max-backoff=$MAX_BACKOFF + fi + set -- "$@" $SSL_OPTS $DAEMON_OPTS + if test "$MODE" = out-of-band; then + set -- "$@" --out-of-band + fi + set -- "$@" nl:0 "$CONTROLLER" + echo -n "Starting $DESC: " + start-stop-daemon --start --quiet --pidfile $PIDFILE \ + --exec $DAEMON -- "$@" + if running; then + echo "$NAME." + else + echo " ERROR." + fi + + if test "$MODE" = in-band && test "$SWITCH_IP" = dhcp; then + echo -n "Starting dhclient on of0: " + start-stop-daemon --start --quiet --pidfile $DHCLIENT_PIDFILE \ + --exec /sbin/dhclient -- -q -pf $DHCLIENT_PIDFILE of0 + if running; then + echo "dhclient." + else + echo " ERROR." + fi + fi + ;; + stop) + if test -e /var/run/dhclient.of0.pid; then + echo -n "Stopping dhclient on of0: " + start-stop-daemon --stop --quiet --oknodo \ + --pidfile $DHCLIENT_PIDFILE --exec /sbin/dhclient + echo "dhclient." + fi + + echo -n "Stopping $DESC: " + start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE \ + --exec $DAEMON + echo "$NAME." + + for netdev in $NETDEVS; do + check_op "Removing $netdev from datapath" dpctl delif nl:0 $netdev + done + check_op "Deleting datapath" dpctl deldp nl:0 + check_op "Unloading kernel module" modprobe -r openflow_mod + ;; + force-stop) + echo -n "Forcefully stopping $DESC: " + force_stop + if ! running; then + echo "$NAME." + else + echo " ERROR." + fi + ;; + reload) + ;; + force-reload) + start-stop-daemon --stop --test --quiet --pidfile \ + $PIDFILE --exec $DAEMON \ + && $0 restart \ + || exit 0 + ;; + restart) + $0 stop || true + $0 start + ;; + status) + echo -n "$NAME is " + if running ; then + echo "running" + else + echo " not running." + exit 1 + fi + ;; + *) + N=/etc/init.d/$NAME + echo "Usage: $N {start|stop|restart|force-reload|status|force-stop}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/openflow/debian/openflow-switch.install b/openflow/debian/openflow-switch.install new file mode 100644 index 00000000..b325e3cc --- /dev/null +++ b/openflow/debian/openflow-switch.install @@ -0,0 +1,6 @@ +_debian/secchan/ofprotocol usr/sbin +_debian/utilities/dpctl usr/sbin +_debian/utilities/ofp-discover usr/sbin +_debian/utilities/ofp-kill usr/sbin +debian/openflow/usr/share/openflow/commands/* usr/share/openflow/commands +debian/commands/* usr/share/openflow/commands diff --git a/openflow/debian/openflow-switch.logrotate b/openflow/debian/openflow-switch.logrotate new file mode 100644 index 00000000..b2136907 --- /dev/null +++ b/openflow/debian/openflow-switch.logrotate @@ -0,0 +1,11 @@ +/var/log/openflow/secchan.log { + daily + compress + create 640 root adm + delaycompress + missingok + rotate 30 + postrotate + vlogconf --target /var/run/secchan.pid --reopen + endscript +} diff --git a/openflow/debian/openflow-switch.manpages b/openflow/debian/openflow-switch.manpages new file mode 100644 index 00000000..dd636ac8 --- /dev/null +++ b/openflow/debian/openflow-switch.manpages @@ -0,0 +1,4 @@ +_debian/secchan/ofprotocol.8 +_debian/utilities/ofp-discover.8 +_debian/utilities/ofp-kill.8 +_debian/utilities/dpctl.8 diff --git a/openflow/debian/openflow-switch.postinst b/openflow/debian/openflow-switch.postinst new file mode 100755 index 00000000..4f96db3a --- /dev/null +++ b/openflow/debian/openflow-switch.postinst @@ -0,0 +1,51 @@ +#!/bin/sh +# postinst script for openflow-switch +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `configure' +# * `abort-upgrade' +# * `abort-remove' `in-favour' +# +# * `abort-remove' +# * `abort-deconfigure' `in-favour' +# `removing' +# +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + configure) + DEFAULT=/etc/default/openflow-switch + TEMPLATE=/usr/share/openflow/switch/default.template + if ! test -e $DEFAULT; then + cp $TEMPLATE $DEFAULT + else + for var in $(awk -F'[ :]' '/^# [_A-Z0-9]+:/{print $2}' $TEMPLATE) + do + if ! grep $var $DEFAULT >/dev/null 2>&1; then + echo >> $DEFAULT + sed -n "/$var:/,/$var=/p" $TEMPLATE >> $DEFAULT + fi + done + fi + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +#DEBHELPER# + +exit 0 + + diff --git a/openflow/debian/openflow-switch.postrm b/openflow/debian/openflow-switch.postrm new file mode 100755 index 00000000..20bab0e0 --- /dev/null +++ b/openflow/debian/openflow-switch.postrm @@ -0,0 +1,43 @@ +#!/bin/sh +# postrm script for openflow-switch +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `remove' +# * `purge' +# * `upgrade' +# * `failed-upgrade' +# * `abort-install' +# * `abort-install' +# * `abort-upgrade' +# * `disappear' +# +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + purge) + rm -f /etc/default/openflow-switch + ;; + + remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) + ;; + + *) + echo "postrm called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 + + diff --git a/openflow/debian/openflow-switch.template b/openflow/debian/openflow-switch.template new file mode 100644 index 00000000..f3f641e8 --- /dev/null +++ b/openflow/debian/openflow-switch.template @@ -0,0 +1,169 @@ +# This is a POSIX shell fragment -*- sh -*- + +# To configure the secure channel, fill in the following properly and +# uncomment them. Afterward, the secure channel will come up +# automatically at boot time. It can be started immediately with +# /etc/init.d/openflow-switch start +# Alternatively, use the ofp-switch-setup program (from the +# openflow-switch-config package) to do everything automatically. + +# NETDEVS: Which network devices should the OpenFlow switch include? +# +# List the network devices that should become part of the OpenFlow +# switch, separated by spaces. At least two devices must be selected +# for this machine to be a useful switch. Unselecting all network +# devices will disable the OpenFlow switch entirely. +# +# The network devices that you select should not be configured with IP +# or IPv6 addresses, even if the switch contacts the controller over +# one of the selected network devices. This is because a running +# OpenFlow switch takes over network devices at a low level: they +# become part of the switch and cannot be used for other purposes. +#NETDEVS="" + +# MODE: The OpenFlow switch has three modes that determine how it +# reaches the controller: +# +# * in-band with discovery: A single network is used for OpenFlow +# traffic and other data traffic; that is, the switch contacts the +# controller over one of the network devices selected as OpenFlow +# switch ports. The switch automatically determines the location of +# the controller using a DHCP request with an OpenFlow-specific +# vendor option. This is the most common case. +# +# * in-band: As above, but the location of the controller is manually +# configured. +# +# * out-of-band: OpenFlow traffic uses a network separate from the +# data traffic that it controls. If this is the case, the control +# network must already be configured on a network device other than +# one of those selected as an OpenFlow switch port in the previous +# question. +# +# Set MODE to 'discovery', 'in-band', or 'out-of-band' for these +# respective cases. +MODE=discovery + +# SWITCH_IP: In 'in-band' mode, the switch's IP address may be +# configured statically or dynamically: +# +# * For static configuration, specify the switch's IP address as a +# string. In this case you may also set SWITCH_NETMASK and +# SWITCH_GATEWAY appropriately (see below). +# +# * For dynamic configuration with DHCP (the most common case), +# specify "dhcp". Configuration with DHCP will only work reliably +# if the network topology allows the switch to contact the DHCP +# server before it connects to the OpenFlow controller. +# +# This setting has no effect unless MODE is set to 'in-band'. +SWITCH_IP=dhcp + +# SWITCH_NETMASK: IP netmask to use in 'in-band' mode when the switch +# IP address is not 'dhcp'. +#SWITCH_NETMASK=255.255.255.0 + +# SWITCH_GATEWAY: IP gateway to use in 'in-band' mode when the switch +# IP address is not 'dhcp'. +#SWITCH_GATEWAY=192.168.1.1 + +# CONTROLLER: Location of controller. +# One of the following formats: +# tcp:HOST[:PORT] via TCP to PORT (default: 6633) on HOST +# ssl:HOST[:PORT] via SSL to PORT (default: 6633) on HOST +# The default below assumes that the controller is running locally. +# This setting has no effect when MODE is set to 'discovery'. +#CONTROLLER="tcp:127.0.0.1" + +# PRIVKEY: Name of file containing switch's private key. +# Required if SSL enabled. +#PRIVKEY=/etc/openflow-switch/of0-privkey.pem + +# CERT: Name of file containing certificate for private key. +# Required if SSL enabled. +#CERT=/etc/openflow-switch/of0-cert.pem + +# CACERT: Name of file containing controller CA certificate. +# Required if SSL enabled. +#CACERT=/etc/openflow-switch/cacert.pem + +# CACERT_MODE: Two modes are available: +# +# * secure: The controller CA certificate named in CACERT above must exist. +# (You must copy it manually from the PKI server or another trusted source.) +# +# * bootstrap: If the controller CA certificate named in CACERT above does +# not exist, the switch will obtain it from the controller the first time +# it connects and save a copy to the file named in CACERT. This is insecure, +# in the same way that initial connections with ssh are insecure, but +# it is convenient. +# +# Set CACERT_MODE to 'secure' or 'bootstrap' for these respective cases. +#CACERT_MODE=secure + +# MGMT_VCONNS: List of vconns (space-separated) on which secchan +# should listen for management connections from dpctl, etc. +# openflow-switchui by default connects to +# unix:/var/run/secchan.mgmt, so do not disable this if you want to +# use openflow-switchui. +MGMT_VCONNS="punix:/var/run/secchan.mgmt" + +# MONITOR_VCONN: Name of vconn on which secchan should listen for +# monitoring connections from dpctl. +MONITOR_VCONN="punix:/var/run/secchan.monitor" + +# COMMANDS: Access control list for the commands that can be executed +# remotely over the OpenFlow protocol, as a comma-separated list of +# shell glob patterns. Negative patterns (beginning with !) act as a +# blacklist. To be executable, a command name must match one positive +# pattern and not match any negative patterns. +#COMMANDS="reboot,update" + +# DISCONNECTED_MODE: Switch behavior when attempts to connect to the +# controller repeatedly fail, either 'switch', to act as an L2 switch +# in this case, or 'drop', to drop all packets (except those necessary +# to connect to the controller). If unset, the default is 'drop'. +#DISCONNECTED_MODE=switch + +# STP: Enable or disabled 802.1D-1998 Spanning Tree Protocol. Set to +# 'yes' to enable STP, 'no' to disable it. If unset, secchan's +# current default is 'no' (but this may change in the future). +#STP=no + +# RATE_LIMIT: Maximum number of received frames, that do not match any +# existing switch flow, to forward up to the controller per second. +# The valid range is 100 and up. If unset, this rate will not be +# limited. +#RATE_LIMIT=1000 + +# INACTIVITY_PROBE: The maximum number of seconds of inactivity on the +# controller connection before secchan sends an inactivity probe +# message to the controller. The valid range is 5 and up. If unset, +# secchan defaults to 15 seconds. +#INACTIVITY_PROBE=5 + +# MAX_BACKOFF: The maximum time that secchan will wait between +# attempts to connect to the controller. The valid range is 1 and up. +# If unset, secchan defaults to 15 seconds. +#MAX_BACKOFF=15 + +# DAEMON_OPTS: Additional options to pass to secchan, e.g. "--fail=open" +DAEMON_OPTS="" + +# CORE_LIMIT: Maximum size for core dumps. +# +# Leaving this unset will use the system default. Setting it to 0 +# will disable core dumps. Setting it to "unlimited" will dump all +# core files regardless of size. +#CORE_LIMIT=unlimited + +# DATAPATH_ID: Identifier for this switch. +# +# By default, the switch checks if the DMI System UUID contains a Nicira +# mac address to use as a datapath ID. If not, then the switch generates +# a new, random datapath ID every time it starts up. By setting this +# value, the supplied datapath ID will always be used. +# +# Set DATAPATH_ID to a MAC address in the form XX:XX:XX:XX:XX:XX where each +# X is a hexadecimal digit (0-9 or a-f). +#DATAPATH_ID=XX:XX:XX:XX:XX:XX diff --git a/openflow/debian/po/POTFILES.in b/openflow/debian/po/POTFILES.in new file mode 100644 index 00000000..e3ea07e3 --- /dev/null +++ b/openflow/debian/po/POTFILES.in @@ -0,0 +1 @@ +[type: gettext/rfc822deb] openflow-switch-config.templates diff --git a/openflow/debian/rules b/openflow/debian/rules new file mode 100755 index 00000000..539c8f3d --- /dev/null +++ b/openflow/debian/rules @@ -0,0 +1,163 @@ +#!/usr/bin/make -f +# -*- makefile -*- +# Sample debian/rules that uses debhelper. +# +# This file was originally written by Joey Hess and Craig Small. +# As a special exception, when this file is copied by dh-make into a +# dh-make output file, you may use that output file without restriction. +# This special exception was added by Craig Small in version 0.37 of dh-make. +# +# Modified to make a template file for a multi-binary package with separated +# build-arch and build-indep targets by Bill Allombert 2001 + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +# This has to be exported to make some magic below work. +export DH_OPTIONS + +# prefix of the target package name +PACKAGE=openflow-datapath-module +# modifieable for experiments or debugging m-a +MA_DIR ?= /usr/share/modass +# load generic variable handling +-include $(MA_DIR)/include/generic.make +# load default rules +-include $(MA_DIR)/include/common-rules.make + +-include debian/rules.ext + +DATAPATH_CONFIGURE_OPTS = --enable-snat + +# Official build number. Leave set to 0 if not an official build. +BUILD_NUMBER = 0 + +configure: configure-stamp +configure-stamp: + dh_testdir + test -e configure || ./boot.sh + test -d _debian || mkdir _debian + cd _debian && ( \ + test -e Makefile || \ + ../configure --prefix=/usr --localstatedir=/var --enable-ssl \ + --with-build-number=$(BUILD_NUMBER) \ + $(DATAPATH_CONFIGURE_OPTS)) + $(ext_configure) + touch configure-stamp + +#Architecture +build: build-arch build-indep + +build-arch: build-arch-stamp +build-arch-stamp: configure-stamp + $(MAKE) -C _debian + $(ext_build_arch) + touch $@ + +build-indep: build-indep-stamp +build-indep-stamp: configure-stamp + $(MAKE) -C _debian dist distdir=openflow + $(ext_build_indep) + touch $@ + +clean: + dh_testdir + dh_testroot + rm -f build-arch-stamp build-indep-stamp configure-stamp + rm -rf _debian + [ ! -f Makefile ] || $(MAKE) distclean + $(ext_clean) + dh_clean + debconf-updatepo + +MAJOR=$(shell echo $(KVERS) | sed -e 's/\(...\).*/\1/') +ifeq ($(MAJOR),2.6) +KO=k +l2x=l26 +dpdir=datapath/linux-2.6 +else +KO= +l2x=l24 +dpdir=datapath/linux-2.4 +endif + +kdist_clean: + dh_clean + rm -rf openflow + +kdist_config: prep-deb-files + +binary-modules: DSTDIR = $(CURDIR)/debian/$(PKGNAME)/lib/modules/$(KVERS) +binary-modules: prep-deb-files + dh_testdir + dh_testroot + dh_clean -k + tar xzf openflow.tar.gz + cd openflow && ./configure --with-$(l2x)=$(KSRC) $(DATAPATH_CONFIGURE_OPTS) --with-build-number=$(BUILD_NUMBER) + cd openflow && $(MAKE) -C $(dpdir) + install -d -m755 $(DSTDIR) + install -m644 openflow/$(dpdir)/*_mod.$(KO)o $(DSTDIR)/ + dh_installdocs + dh_installchangelogs + dh_compress + dh_fixperms + dh_installdeb + dh_gencontrol + dh_md5sums + dh_builddeb --destdir=$(DEB_DESTDIR) + +install: install-indep install-arch +install-indep: build-indep + dh_testdir + dh_testroot + dh_clean -k -i + dh_installdirs -i + dh_install -i + cd debian/openflow-datapath-source/usr/src && tar -c modules | bzip2 -9 > openflow-datapath.tar.bz2 && rm -rf modules + install -m644 debian/openflow-pki-server.apache2 debian/openflow-pki-server/etc/apache2/sites-available/openflow-pki + install -m1777 -d debian/corekeeper/var/log/core + $(ext_install_indep) + +install-arch: build-arch + dh_testdir + dh_testroot + dh_clean -k -s + dh_installdirs -s + $(MAKE) -C _debian DESTDIR=$(CURDIR)/debian/openflow install + cp debian/openflow-switch-config.overrides debian/openflow-switch-config/usr/share/lintian/overrides/openflow-switch-config + cp debian/openflow-switch.template debian/openflow-switch/usr/share/openflow/switch/default.template + dh_install -s + $(ext_install_arch) + +# Must not depend on anything. This is to be called by +# binary-arch/binary-indep +# in another 'make' thread. +binary-common: + dh_testdir + dh_testroot + dh_installchangelogs + dh_installdocs + dh_installexamples + dh_installdebconf + dh_installlogrotate + dh_installinit + dh_installcron + dh_installman + dh_link + dh_strip --dbg-package=openflow-dbg + dh_compress + dh_fixperms -X var/log/core + dh_perl + dh_makeshlibs + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb +binary-indep: install-indep + $(MAKE) -f debian/rules DH_OPTIONS=-i binary-common +binary-arch: install-arch + $(MAKE) -f debian/rules DH_OPTIONS=-s binary-common + +binary: binary-arch binary-indep +.PHONY: build clean binary-indep binary-arch binary install install-indep install-arch configure diff --git a/openflow/doc/of-spec/.gitignore b/openflow/doc/of-spec/.gitignore new file mode 100644 index 00000000..7723a762 --- /dev/null +++ b/openflow/doc/of-spec/.gitignore @@ -0,0 +1,8 @@ +/*.aux +/*.log +/*.out +/*.pdf +/*.ps +/define +/enum +/struct diff --git a/openflow/doc/of-spec/Makefile b/openflow/doc/of-spec/Makefile new file mode 100644 index 00000000..0e4c9462 --- /dev/null +++ b/openflow/doc/of-spec/Makefile @@ -0,0 +1,40 @@ +TARGET=openflow-spec-v1.0.0 + +BIBTEX := bibtex +TGIF := tgif +XFIG := xfig +GNUPLOT:= gnuplot + +SOURCES=openflow-spec-v1.0.0.tex\ + appendix.tex + +all: $(TARGET).ps +pdf: all + +$(TARGET).pdf: Makefile $(SOURCES) + ./make_latex_input.pl + texi2pdf $(TARGET).tex + +color: $(TARGET).pdf + pdflatex $(TARGET).tex + pdftops $(TARGET).pdf + +$(TARGET).ps: $(TARGET).pdf + pdftops $(TARGET).pdf + +%.pdf : %.fig #Makefile + fig2dev -L pdf -b 1 $< $@ + +%.eps : %.dia #Makefile + dia --nosplash -e $@ $< + +%.eps : %.obj + TMPDIR=/tmp $(TGIF) -print -eps $< + + +%.pdf : %.eps #Makefile + epstopdf $< + +clean: + rm -f *.aux *.log *.out *.bbl *.blg *~ *.bak $(TARGET).ps $(TARGET).pdf + rm -rf define enum struct diff --git a/openflow/doc/of-spec/README b/openflow/doc/of-spec/README new file mode 100644 index 00000000..a010f5dd --- /dev/null +++ b/openflow/doc/of-spec/README @@ -0,0 +1,3 @@ +To build the latest OpenFlow specification, you should just be able to +type "make". For this to work, you'll need to have the texinfo and +"listings.sty" packages installed. diff --git a/openflow/doc/of-spec/appendix.tex b/openflow/doc/of-spec/appendix.tex new file mode 100755 index 00000000..ffac6bbb --- /dev/null +++ b/openflow/doc/of-spec/appendix.tex @@ -0,0 +1,429 @@ +%\appendix +\section{Appendix A: The OpenFlow Protocol} +The heart of the OpenFlow spec is the set of structures used for OpenFlow Protocol messages. +\\\\ +The structures, defines, and enumerations described below are derived from the file \verb|include/openflow/openflow.h|, which is part of the standard OpenFlow distribution. All structures are packed with padding and 8-byte aligned, as checked by the assertion statements. All OpenFlow messages are sent in big-endian format. + +\subsection{OpenFlow Header} +Each OpenFlow message begins with the OpenFlow header: + +\input{struct/ofp_header} +The version specifies the OpenFlow protocol version being used. During the current draft phase of the OpenFlow Protocol, the most significant bit will be set to indicate an experimental version and the lower bits will indicate a revision number. The current version is \input{define/OFP_VERSION}. The final version for a Type 0 switch will be 0x00. The length field indicates the total length of the message, so no additional framing is used to distinguish one frame from the next. The type can have the following values: + +\input{enum/ofp_type} + +\subsection{Common Structures} +This section describes structures used by multiple messages. + +\subsubsection{Port Structures} +Physical ports are described with the following structure: + +\input{struct/ofp_phy_port} +The \verb|port_no| field is a value the datapath associates with a physical port. The \verb|hw_addr| field typically is the MAC address for the port; \verb|OFP_MAX_ETH_ALEN| is 6. The name field is a null-terminated string containing a human-readable name for the interface. The value of \verb|OFP_MAX_PORT_NAME_LEN| is 16. +\\\\ +The \verb|config| field describes spanning tree and administrative settings with the following structure: + +\input{enum/ofp_port_config} +The port config bits indicate whether a port has been administratively brought down, options for handling 802.1D spanning tree packets, and how to handle incoming and outgoing packets. These bits, configured over multiple switches, enable an OpenFlow network to safely flood packets along either a custom or 802.1D spanning tree. +\\\\ +The controller may set \verb|OFPPFL_NO_STP| to 0 to enable STP on a port or to 1 to disable STP on a port. (The latter corresponds to the Disabled STP port state.) The default is switch implementation-defined; the OpenFlow reference implementation by default sets this bit to 0 (enabling STP). +\\\\ +When \verb|OFPPFL_NO_STP| is 0, STP controls the \verb|OFPPFL_NO_FLOOD| and \verb|OFPPFL_STP_*| bits directly. \verb|OFPPFL_NO_FLOOD| is set to 0 when the STP port state is Forwarding, otherwise to 1. The bits in \verb|OFPPFL_STP_MASK| are set to one of the other \verb|OFPPFL_STP_*| values according to the current STP port state. +\\\\ +When the port flags are changed by STP, the switch sends an \verb|OFPT_PORT_STATUS| message to notify the controller of the change. The \verb|OFPPFL_NO_RECV|, \verb|OFPPFL_NO_RECV_STP|, \verb|OFPPFL_NO_FWD|, and \verb|OFPPFL_NO_PACKET_IN| bits in the OpenFlow port flags may be useful for the controller to implement STP, although they interact poorly with in-band control. +\\\\ +The \verb|state| field describes the spanning tree state and whether a physical link is present, with the following structure: + +\input{enum/ofp_port_state} +All port state bits are read-only, representing spanning tree and physical link state. +\\\\ +The port numbers use the following conventions: + +\input{enum/ofp_port} +The \verb|curr|, \verb|advertised|, \verb|supported|, and \verb|peer| fields indicate link modes (10M to 10G full and half-duplex), link type (copper/fiber) and link features (autonegotiation and pause). Port features are represent by the following structure: + +\input{enum/ofp_port_features} +Multiple of these flags may be set simultaneously. + +\subsubsection{\qosupd{Queue Structures}} +\label{cts:qos} +\qosupd{An OpenFlow switch provides limited Quality-of-Service support + (QoS) through a simple queuing +mechanism. One (or more) queues can attach to a port and be used to map flows +on it. Flows mapped to a specific queue will be treated according to +that queue's configuration (e.g. min rate). +\\\\ +A queue is described by the} \verb|ofp_packet_queue| \qosupd{structure: +\input{struct/ofp_packet_queue} +Each queue is further described by a set of properties, each of a +specific type and configuration. +\input{enum/ofp_queue_properties} +Each queue property description starts with a common header: +\input{struct/ofp_queue_prop_header} +Currently, there is only a minimum-rate type queue, described by the} +\verb|ofp_queue_prop_min_rate| \qosupd{structure: +\input{struct/ofp_queue_prop_min_rate}} + +\subsubsection{Flow Match Structures} +When describing a flow entry, the following structure is used: + +\input{struct/ofp_match} +The \verb|wildcards| field has a number of flags that may be set: + +\input{enum/ofp_flow_wildcards} +If no wildcards are set, then the \verb|ofp_match| exactly describes a flow, over the entire OpenFlow 12-tuple. On the other extreme, if all the wildcard flags are set, then every flow will match. +\\\\ +The source and destination netmasks are each specified with a 6-bit number in the wildcard description. It is interpreted similar to the CIDR suffix, but with the opposite meaning, since this is being used to indicate which bits in the IP address should be treated as ``wild". For example, a CIDR suffix of "24" means to use a netmask of ``255.255.255.0". However, a wildcard mask value of ``24" means that the least-significant 24-bits are wild, so it forms a netmask of ``255.0.0.0". + +\subsubsection{Flow Action Structures} +A number of actions may be associated with flows or packets. The currently defined action types are: + +\input{enum/ofp_action_type} +Output \qosupd{and enqueue} actions are described in Section \ref{ft:actions}, while Field-Modify actions are described in Table \ref{table:field modify actions}. An action definition contains the action type, length, and any associated data: + +\input{struct/ofp_action_header} +An \verb|action_output| has the following fields: + +\input{struct/ofp_action_output} +The \verb|max_len| indicates the maximum amount of data from a packet that should be sent when the port is \verb|OFPP_CONTROLLER|. If \verb|max_len| is zero, the switch must send a zero-size \verb|packet_in| message. The \verb|port| specifies the physical port from which packets should be sent. + \\\\ +\qosupd{The enqueue action maps a flow to an already-configured queue, regardless of the TOS and VLAN PCP bits. + The packet should not change after an enqueue action. If the switch + needs to set the TOS/PCP bits for internal handling, the original values + should be restored before sending the packet out. +\\\\ +A switch may support only queues that are tied to specific PCP/TOS +bits. In that case, we cannot map an arbitrary flow to a specific +queue, therefore the action ENQUEUE is not supported. The user can +still use these queues and map +flows to them by setting the relevant fields (TOS, VLAN PCP). +\\\\ +The enqueue action has the following fields: + +\input{struct/ofp_action_enqueue}} +An \verb|action_vlan_vid| has the following fields: + +\input{struct/ofp_action_vlan_vid} +The \verb|vlan_vid| field is 16 bits long, when an actual VLAN id is only 12 bits. The value \verb|0xffff| is used to indicate that no VLAN id was set. +\\\\ +An \verb|action_vlan_pcp| has the following fields: + +\input{struct/ofp_action_vlan_pcp} +The \verb|vlan_pcp| field is 8 bits long, but only the lower 3 bits have meaning. +\\\\ +An \verb|action_strip_vlan| takes no arguments and consists only of a generic \verb|ofp_action_header|. This action strips the VLAN tag if one is present. +\\\\ +An \verb|action_dl_addr| has the following fields: + +\input{struct/ofp_action_dl_addr} +The \verb|dl_addr| field is the MAC address to set. +\\\\ +An \verb|action_nw_addr| has the following fields: + +\input{struct/ofp_action_nw_addr} +The \verb|nw_addr| field is the IP address to set. +\\\\ +An \verb|action_nw_tos| has the following fields: + +\input{struct/ofp_action_nw_tos} +The \verb|nw_tos| field is the 6 upper bits of the ToS field to set, in the original bit positions (shifted to the left by 2). +\\\\ +An \verb|action_tp_port| has the following fields: + +\input{struct/ofp_action_tp_port} +The \verb|tp_port| field is the TCP/UDP/other port to set. +\\\\ +An \verb|action_vendor| has the following fields: + +\input{struct/ofp_action_vendor_header} +The \verb|vendor| field is the Vendor ID, which takes the same form as in struct \verb|ofp_vendor|. + +\subsection{Controller-to-Switch Messages} + +\subsubsection{Handshake} +\label{cts:handshake} +Upon TLS session establishment, the controller sends an \verb|OFPT_FEATURES_REQUEST| message. This message does not contain a body beyond the OpenFlow header. The switch responds with an \verb|OFPT_FEATURES_REPLY| message: + +\input{struct/ofp_switch_features} +The \verb|datapath_id| field uniquely identifies a datapath. The lower 48 bits are intended for the switch MAC address, while the top 16 bits are up to the implementer. An example use of the top 16 bits would be a VLAN ID to distinguish multiple virtual switch instances on a single physical switch. This field should be treated as an opaque bit string by controllers. +\\\\ +The \verb|n_tables| field describes the number of tables supported by the switch, each of which can have a different set of supported wildcard bits and number of entries. When the controller and switch first communicate, the controller will find out how many tables the switch supports from the Features Reply. If it wishes to understand the size, types, and order in which tables are consulted, the controller sends a \verb|OFPST_TABLE| stats request. A switch must return these tables in the order the packets traverse the tables, with all exact-match tables listed before all tables with wildcards. +\\\\ +The \verb|capabilities| field uses the following flags: + +\input{enum/ofp_capabilities} +The \verb|actions| field is a bitmap of actions supported by the switch. The list of actions is found in Section~\ref{ft:actions}; all actions marked Required must be supported. Vendor actions should \emph{not} be reported via this bitmask. The bitmask uses the values from \verb|ofp_action_type| as the number of bits to shift left for an associated action. For example, \verb|OFPAT_SET_DL_VLAN| would use the flag \verb|0x00000002|. +\\\\ +The \verb|ports| field is an array of \verb|ofp_phy_port| structures that describe all the physical ports in the system that support OpenFlow. The number of port elements is inferred from the length field in the OpenFlow header. + +\subsubsection{Switch Configuration} +The controller is able to set and query configuration parameters in the switch with the \verb|OFPT_SET_CONFIG| and \verb|OFPT_GET_CONFIG_REQUEST| messages, respectively. The switch responds to a configuration request with an \verb|OFPT_GET_CONFIG_REPLY| message; it does not reply to a request to set the configuration. +\\\\ +There is no body for \verb|OFPT_GET_CONFIG_REQUEST| beyond the OpenFlow header. The \verb|OFPT_SET_CONFIG| and \verb|OFPT_GET_CONFIG_REPLY| use the following: + +\input{struct/ofp_switch_config} +The configuration flags include the following: + +\input{enum/ofp_config_flags} +The \verb|OFPC_FRAG_*| flags indicate whether IP fragments should be treated normally, dropped, or reassembled. ``Normal" handling of fragments means that an attempt should be made to pass the fragments through the OpenFlow tables. If any field is not present (e.g., the TCP/UDP ports didn't fit), then the packet should not match any entry that has that field set. +\\\\ +The \verb|miss_send_len| field defines the number of bytes of each packet sent to the controller as a result of both flow table misses and flow table hits with the controller as the destination. If this field equals 0, the switch must send a zero-size \verb|packet_in| message. + +\subsubsection{Modify State Messages} +\paragraph{Modify Flow Entry Message} +Modifications to the flow table from the controller are done with the \verb|OFPT_FLOW_MOD| message: + +\input{struct/ofp_flow_mod} +The \verb|cookie| field is an opaque data value that is set by the +controller. It is not used in any matching functions, and thus does not +need to reside in hardware. The value -1 (0xffffffffffffffff) is +reserved and must not be used. It is required that when \verb|command| is +\verb|OFPC_MODIFY| or \verb|OFPC_MODIFY_STRICT| that matched flows have +their \verb|cookie| field updated appropriately. +\\\\ +The \verb|command| field must be one of the following: + +\input{enum/ofp_flow_mod_command} +The differences between \verb|OFPFC_MODIFY| and \verb|OFPFC_MODIFY_STRICT| are explained in Section \ref{flow_table:sec_chan:flow_mod} and differences between \verb|OFPFC_DELETE| and \verb|OFPFC_DELETE_STRICT| are explained in Section \ref{flow_table:sec_chan:flow_removal}. +\\\\ +The \verb|idle_timeout| and \verb|hard_timeout| fields control how quickly flows expire. +\\\\ +If the \verb|idle_timeout| is set and the \verb|hard_timeout| is zero, the entry must expire after \verb|idle_timeout| seconds with no received traffic. If the \verb|idle_timeout| is zero and the \verb|hard_timeout| is set, the entry must expire in \verb|hard_timeout| seconds regardless of whether or not packets are hitting the entry. +\\\\ +If both \verb|idle_timeout| and \verb|hard_timeout| are set, the flow will timeout after \verb|idle_timeout| seconds with no traffic, or \verb|hard_timeout| seconds, whichever comes first. If both \verb|idle_timeout| and \verb|hard_timeout| are zero, the entry is considered permanent and will never time out. It can still be removed with a \verb|flow_mod| message of type \verb|OFPFC_DELETE|. +\\\\ +The \verb|priority| field is only relevant for flow entries with wildcard fields. The priority field indicates table priority, where higher numbers are higher priorities; the switch must keep the highest-priority wildcard entries in the lowest-numbered (fastest) wildcard table, to ensure correctness. It is the responsibility of each switch implementer to ensure that exact entries always match before wildcards entries, regardless of the table configuration. +\\\\ +The \verb|buffer_id| refers to a buffered packet sent by the \verb|OFPT_PACKET_IN| message. +\\\\ +The \verb|out_port| field optionally filters the scope of DELETE and DELETE\_STRICT messages by output port. If \verb|out_port| contains a value other than \verb|OFPP_NONE|, it introduces a constraint when matching. This constraint is that the rule must contain an output action directed at that port. Other constraints such as \verb|ofp_match| structs and priorities are still used; this is purely an \emph{additional} constraint. Note that to disable output port filtering, \verb|out_port| must be set to \verb|OFPP_NONE|, since 0 is a valid port id. This field is ignored by ADD, MODIFY, and MODIFY\_STRICT messages. +\\\\ +The \verb|flags| field may include the follow flags: + +\input{enum/ofp_flow_mod_flags} +When the \verb|OFPFF_SEND_FLOW_REM| flag is set, the switch must send a flow removed message when the flow expires. The default is for the switch to not send flow removed messages for newly added flows. +\\\\ +When the \verb|OFPFF_CHECK_OVERLAP| flag is set, the switch must check that there are no conflicting entries with the same priority. If there is one, the flow mod fails and an error code is returned. +\\\\ +When the \verb|OFPFF_EMERG_| flag is set, the switch must consider this flow entry as an emergency entry, and only use it for forwarding when disconnected from the controller. + +\paragraph{Port Modification Message} +The controller uses the \verb|OFPT_PORT_MOD| message to modify the behavior of the physical port: + +\input{struct/ofp_port_mod} +The \verb|mask| field is used to select bits in the \verb|config| field to change. The \verb|advertise| field has no mask; all port features change together. + +\subsubsection{\qosupd{Queue Configuration Messages}} +\qosupd{Queue configuration takes place outside the OpenFlow protocol, either + through a command line tool or through an external dedicated configuration +protocol. +\\\\ +The controller can query the switch for configured queues on a port +using the following structure: +\input{struct/ofp_queue_get_config_request} +The switch replies back with an} \verb|ofp_queue_get_config_reply| \qosupd{command, containing +a list of configured queues. + +\input{struct/ofp_queue_get_config_reply} +} + +\subsubsection{Read State Messages} +While the system is running, the datapath may be queried about its current state using the \verb|OFPT_STATS_REQUEST| message: + +\input{struct/ofp_stats_request} +The switch responds with one or more \verb|OFPT_STATS_REPLY| messages: + +\input{struct/ofp_stats_reply} +The only value defined for \verb|flags| in a reply is whether more replies will follow this one - this has the value \verb|0x0001|. To ease implementation, the switch is allowed to send replies with no additional entries. However, it must always send another reply following a message with the �more� flag set. The transaction ids (xid) of replies must always match the request that prompted them. +\\\\ +In both the request and response, the \verb|type| field specifies the kind of information being passed and determines how the \verb|body| field is interpreted: + +\input{enum/ofp_stats_types} + +\paragraph{Description Statistics} +Information about the switch manufacturer, hardware revision, software revision, serial number, and a description field is available from the \verb|OFPST_DESC| stats request type: + +\input{struct/ofp_desc_stats} +Each entry is ASCII formatted and padded on the right with null bytes (\textbackslash0). \verb|DESC_STR_LEN| is \input{define/DESC_STR_LEN}and \verb|SERIAL_NUM_LEN| is \input{define/SERIAL_NUM_LEN}. Note: \footnote{Added to address concerns raised in \url{https://mailman.stanford.edu/pipermail/openflow-spec/2009-September/000504.html}} the \verb|dp_desc| field is a free-form string to describe the datapath for debugging purposes, e.g., ``switch3 in room 3120''. As such, it is not guaranteed to be unique and should not be used as the primary identifier for the datapath---use the \verb|datapath_id| field from the switch features instead (\S~\ref{cts:handshake}). + +\paragraph{Individual Flow Statistics} +Information about individual flows is requested with the \verb|OFPST_FLOW| stats request type: + +\input{struct/ofp_flow_stats_request} +The \verb|match| field contains a description of the flows that should be matched and may contain wildcards. This field's matching behavior is described in Section \ref{flow_table:sec_chan:flow_add}. +\\\\ +The \verb|table_id| field indicates the index of a single table to read, or \verb|0xff| for all tables. +\\\\ +The \verb|out_port| field optionally filters by output port. If \verb|out_port| contains a value other than \verb|OFPP_NONE|, it introduces a constraint when matching. This constraint is that the rule must contain an output action directed at that port. Other constraints such as \verb|ofp_match| structs are still used; this is purely an \emph{additional} constraint. Note that to disable output port filtering, \verb|out_port| must be set to \verb|OFPP_NONE|, since 0 is a valid port id. +\\\\ +The \verb|body| of the reply consists of an array of the following: + +\input{struct/ofp_flow_stats} +The fields consist of those provided in the \verb|flow_mod| that created these, plus the table into which the entry was inserted, the packet count, and the byte count. +\\\\ +\label{flow_duration_info}The \verb|duration_sec| and \verb|duration_nsec| fields indicate the elapsed time the flow has been installed in the switch. The total duration in nanoseconds can be computed as $\verb|duration_sec|*10^{9}$ + \verb|duration_nsec|. Implementations are required to provide millisecond precision; higher precision is encouraged where available. + +\paragraph{Aggregate Flow Statistics} +Aggregate information about multiple flows is requested with the \verb|OFPST_AGGREGATE| stats request type: + +\input{struct/ofp_aggregate_stats_request} +The \verb|match| field contains a description of the flows that should be matched and may contain wildcards. This field's matching behavior is described in Section \ref{flow_table:sec_chan:flow_add}. +\\\\ +The \verb|table_id| field indicates the index of a single table to read, or \verb|0xff| for all tables. +\\\\ +The \verb|out_port| field optionally filters by output port. If \verb|out_port| contains a value other than \verb|OFPP_NONE|, it introduces a constraint when matching. This constraint is that the rule must contain an output action directed at that port. Other constraints such as \verb|ofp_match| structs are still used; this is purely an \emph{additional} constraint. Note that to disable output port filtering, \verb|out_port| must be set to \verb|OFPP_NONE|, since 0 is a valid port id. +\\\\ +The \verb|body| of the reply consists of the following: + +\input{struct/ofp_aggregate_stats_reply} + +\paragraph{Table Statistics} +Information about tables is requested with the \verb|OFPST_TABLE| stats request type. The request does not contain any data in the body. +\\\\ +The body of the reply consists of an array of the following: + +\input{struct/ofp_table_stats} +The \verb|body| contains a \verb|wildcards| field, which indicates the fields for which that particular table supports wildcarding. For example, a direct look-up hash table would have that field set to zero, while a sequentially searched table would have it set to \verb|OFPFW_ALL|. The entries are returned in the order that packets traverse the tables. +\\\\ +\verb|OFP_MAX_TABLE_NAME_LEN| is \input{define/OFP_MAX_TABLE_NAME_LEN}. + +\paragraph{Port Statistics} +Information about physical ports is requested with the \verb|OFPST_PORT| stats request type: + +\input{struct/ofp_port_stats_request} +The \verb|port_no| field optionally filters the stats request to the given port. To request all port statistics, \verb|port_no| must be set to \verb|OFPP_NONE|. +\\\\ +The \verb|body| of the reply consists of an array of the following: + +\input{struct/ofp_port_stats} +The switch should return a value of -1 for unavailable counters. + +\paragraph{\qosupd{Queue Statistics}} +\qosupd{The} \verb|OFPST_QUEUE| \qosupd{stats request message provides + queue statistics for one or more ports. + The request body consists of a} \verb|port_no| \qosupd{field +identifying the port and a} \verb|queue_id|. \verb|OFPP_ALL| +\qosupd{refers to all ports, while} \verb|OFPQ_ALL| \qosupd{refers to all queues configured +at a port. + +\input{struct/ofp_queue_stats_request} +The body of the reply consists of an array of +the following structure: + +\input{struct/ofp_queue_stats}} + +\paragraph{Vendor Statistics} +Vendor-specific stats messages are requested with the \verb|OFPST_VENDOR| stats type. The first four bytes of the message are the vendor identifier. The rest of the body is vendor-defined. +\\\\ +The \verb|vendor| field is a 32-bit value that uniquely identifies the vendor. If the most significant byte is zero, the next three bytes are the vendor's IEEE OUI. If vendor does not have (or wish to use) their OUI, they should contact the OpenFlow consortium to obtain one. + +\subsubsection{Send Packet Message} +When the controller wishes to send a packet out through the datapath, it uses the \verb|OFPT_PACKET_OUT| message: + +\input{struct/ofp_packet_out} +The \verb|buffer_id| is the same given in the \verb|ofp_packet_in| message. If the \verb|buffer_id| is -1, then the packet data is included in the data array. If \verb|OFPP_TABLE| is specified as the output port of an action, the \verb|in_port| in the \verb|packet_out| message is used in the flow table lookup. + +\subsubsection{Barrier Message} +When the controller wants to ensure message dependencies have been met or wants to receive notifications for completed operations, it may use an \verb|OFPT_BARRIER_REQUEST| message. This message has no body. Upon receipt, the switch must finish processing all previously-received messages before executing any messages beyond the Barrier Request. When such processing is complete, the switch must send an \verb|OFPT_BARRIER_REPLY| message with the \verb|xid| of the original request. + +\subsection{Asynchronous Messages} +\subsubsection{Packet-In Message} +When packets are received by the datapath and sent to the controller, they use the \verb|OFPT_PACKET_IN| message: + +\input{struct/ofp_packet_in} +The \verb|buffer_id| is an opaque value used by the datapath to identify a buffered packet. When a packet is buffered, some number of bytes from the message will be included in the data portion of the message. If the packet is sent because of a ``send to controller'' action, then \verb|max_len| bytes from the \verb|action_output| of the flow setup request are sent. If the packet is sent because of a flow table miss, then at least \verb|miss_send_len| bytes from the \verb|OFPT_SET_CONFIG| message are sent. The default \verb|miss_send_len| is \input{define/OFP_DEFAULT_MISS_SEND_LEN}bytes. If the packet is not buffered, the entire packet is included in the data portion, and the \verb|buffer_id| is -1. +\\\\ +Switches that implement buffering are expected to expose, through documentation, both the amount of available buffering, and the length of time before buffers may be reused. A switch must gracefully handle the case where a buffered \verb|packet_in| message yields no response from the controller. A switch should prevent a buffer from being reused until it has been handled by the controller, or some amount of time (indicated in documentation) has passed. +\\\\ +The reason field can be any of these values: + +\input{enum/ofp_packet_in_reason} + +\subsubsection{Flow Removed Message} +If the controller has requested to be notified when flows time out, the datapath does this with the \verb|OFPT_FLOW_REMOVED| message: + +\input{struct/ofp_flow_removed} +The \verb|match|, \verb|cookie|, and \verb|priority| fields are the same as those used in the flow setup request. +\\\\ +The \verb|reason| field is one of the following: + +\input{enum/ofp_flow_removed_reason} +The \verb|duration_sec| and \verb|duration_nsec| fields are described in Section \ref{flow_duration_info}. +\\\\ +The \verb|idle_timeout| field is directly copied from the flow mod that created this entry. +\\\\ +With the above three fields, one can find both the amount of time the flow was active, as well as the amount of time the flow received traffic. +\\\\ +The \verb|packet_count| and \verb|byte_count| indicate the number of packets and bytes that were associated with this flow, respectively. + +\subsubsection{Port Status Message} +As physical ports are added, modified, and removed from the datapath, the controller needs to be informed with the \verb|OFPT_PORT_STATUS| message: + +\input{struct/ofp_port_status} +The \verb|status| can be one of the following values: + +\input{enum/ofp_port_reason} + +\subsubsection{Error Message} +There are times that the switch needs to notify the controller of a problem. This is done with the \verb|OFPT_ERROR_MSG| message: + +\input{struct/ofp_error_msg} +The \verb|type| value indicates the high-level type of error. The \verb|code| value is interpreted based on the type. The \verb|data| is variable length and interpreted based on the \verb|type| and \verb|code|; in most cases this is the message that caused the problem. +\\\\ +Error codes ending in \verb|_EPERM| correspond to a permissions error generated by an entity between a controller and switch, such as an OpenFlow hypervisor. +\\\\ +Currently defined error types are: + +\input{enum/ofp_error_type} +For the \verb|OFPET_HELLO_FAILED| error \verb|type|, the following \verb|code|s are currently defined: + +\input{enum/ofp_hello_failed_code} +The \verb|data| field contains an ASCII text string that adds detail on why the error occurred. +\\\\ +For the \verb|OFPET_BAD_REQUEST| error \verb|type|, the following \verb|code|s are currently defined: + +\input{enum/ofp_bad_request_code} +The \verb|data| field contains at least 64 bytes of the failed request. +\\\\ +For the \verb|OFPET_BAD_ACTION| error \verb|type|, the following \verb|code|s are currently defined: + +\input{enum/ofp_bad_action_code} +The \verb|data| field contains at least 64 bytes of the failed request. +\\\\ +For the \verb|OFPET_FLOW_MOD_FAILED| error \verb|type|, the following \verb|code|s are currently defined: + +\input{enum/ofp_flow_mod_failed_code} +The \verb|data| field contains at least 64 bytes of the failed request. +\\\\ +For the \verb|OFPET_PORT_MOD_FAILED| error \verb|type|, the following \verb|code|s are currently defined: + +\input{enum/ofp_port_mod_failed_code} +The \verb|data| field contains at least 64 bytes of the failed request. +\\\\ +For the \verb|OFPET_QUEUE_OP_FAILED| error \verb|type|, the following \verb|code|s are currently defined: + +\input{enum/ofp_queue_op_failed_code} +The \verb|data| field contains at least 64 bytes of the failed request. +\\\\ +If the error message is in response to a specific message from the controller, e.g., \verb|OFPET_BAD_REQUEST|, \verb|OFPET_BAD_ACTION|, or \verb|OFPET_FLOW_MOD_FAILED|, then the \verb|xid| field of the header should match that of the offending message. + +\subsection{Symmetric Messages} +\subsubsection{Hello} +The \verb|OFPT_HELLO| message has no body; that is, it consists only of an OpenFlow header. Implementations must be prepared to receive a hello message that includes a body, ignoring its contents, to allow for later extensions. + +\subsubsection{Echo Request} +An Echo Request message consists of an OpenFlow header plus an arbitrary-length data field. The data field might be a message timestamp to check latency, various lengths to measure bandwidth, or zero-size to verify liveness between the switch and controller. + +\subsubsection{Echo Reply} +An Echo Reply message consists of an OpenFlow header plus the unmodified data field of an echo request message. +\\\\ +In an OpenFlow protocol implementation divided into multiple layers, the echo request/reply logic should be implemented in the "deepest" practical layer. For example, in the OpenFlow reference implementation that includes a userspace process that relays to a kernel module, echo request/reply is implemented in the kernel module. Receiving a correctly formatted echo reply then shows a greater likelihood of correct end-to-end functionality than if the echo request/reply were implemented in the userspace process, as well as providing more accurate end-to-end latency timing. + +\subsubsection{Vendor} +The Vendor message is defined as follows: + +\input{struct/ofp_vendor_header} +The \verb|vendor| field is a 32-bit value that uniquely identifies the vendor. If the most significant byte is zero, the next three bytes are the vendor's IEEE OUI. If vendor does not have (or wish to use) their OUI, they should contact the OpenFlow consortium to obtain one. The rest of the body is uninterpreted. +\\\\ +If a switch does not understand a vendor extension, it must send an \verb|OFPT_ERROR| message with a \verb|OFPBRC_BAD_VENDOR| error code and \verb|OFPET_BAD_REQUEST| error type. + diff --git a/openflow/doc/of-spec/credits.tex b/openflow/doc/of-spec/credits.tex new file mode 100644 index 00000000..eb917c70 --- /dev/null +++ b/openflow/doc/of-spec/credits.tex @@ -0,0 +1,22 @@ +\section{Appendix B: Credits} + +Current Maintainer: Brandon Heller (brandonh@stanford.edu). +\\\\ +Spec contributions, in alphabetical order: +\\\\ +Ben Pfaff, +Brandon Heller, +Dan Talayco, +David Erickson, +Glen Gibb, +Guido Appenzeller, +Jean Tourrilhes, +Justin Pettit, +KK Yap, +Martin Casado, +Masayoshi Kobayashi, +Nick McKeown, +Peter Balland, +Reid Price, +Rob Sherwood, +Yiannis Yiakoumis. \ No newline at end of file diff --git a/openflow/doc/of-spec/figure_flow_table_secchan.png b/openflow/doc/of-spec/figure_flow_table_secchan.png new file mode 100755 index 0000000000000000000000000000000000000000..a21dde001128e353fb0a172fd4b6551931467604 GIT binary patch literal 67886 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 3~M{>^b~jIm2Vp1dl%!TTqD_` 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 + + + + ActiveLayerIndex + 0 + ApplicationVersion + + com.omnigroup.OmniGrafflePro + 138.12.0.121252 + + AutoAdjust + + BackgroundGraphic + + Bounds + {{0, 0}, {1188, 733}} + Class + SolidGraphic + ID + 2 + Style + + shadow + + Draws + NO + + stroke + + Draws + NO + + + + CanvasOrigin + {0, 0} + ColumnAlign + 1 + ColumnSpacing + 36 + CreationDate + 2009-11-19 17:13:27 -0800 + Creator + brandonh + DisplayScale + 1 0/72 in = 1.0000 in + GraphDocumentVersion + 6 + GraphicsList + + + Class + LineGraphic + Head + + ID + 88 + Position + 0.57036429643630981 + + ID + 102 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {584.932, 656.613} + {584.977, 688.774} + + Style + + stroke + + HeadArrow + 0 + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 42 + Info + 2 + + + + Class + LineGraphic + Head + + ID + 88 + Position + 0.84439820051193237 + + ID + 101 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {458.932, 674.613} + {458.658, 688.774} + + Style + + stroke + + HeadArrow + 0 + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 41 + Info + 1 + + + + Class + LineGraphic + Head + + ID + 67 + Position + 0.93292379379272461 + + ID + 100 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {242.932, 336.714} + {255.646, 688.774} + + Style + + stroke + + HeadArrow + FilledArrow + HopLines + + HopType + 1 + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 93 + Info + 3 + + + + Class + LineGraphic + Head + + ID + 93 + Info + 4 + + ID + 94 + Points + + {125.932, 336.714} + {143.932, 336.714} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 92 + + + + Bounds + {{143.932, 300.714}, {99, 72}} + Class + ShapedGraphic + ID + 93 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Rectangle + Style + + stroke + + Pattern + 1 + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 Set IP source, destination from within ARP packet} + + VFlip + YES + + + Bounds + {{17.9318, 282.714}, {108, 108}} + Class + ShapedGraphic + ID + 92 + Line + + ID + 19 + Position + 0.51827484369277954 + RotationType + 0 + + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Diamond + Style + + stroke + + Pattern + 1 + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 Eth type = 0x0806?} + VerticalPad + 0 + + + + Class + LineGraphic + Head + + ID + 53 + Info + 3 + + ID + 88 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {629.932, 494.613} + {386.932, 688.774} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 37 + Info + 3 + + + + Bounds + {{447.932, 175.932}, {72, 14}} + Class + ShapedGraphic + FitText + Vertical + Flow + Resize + ID + 83 + Shape + Rectangle + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Pad + 0 + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 no} + VerticalPad + 0 + + + + Bounds + {{509.932, 85.932}, {72, 14}} + Class + ShapedGraphic + FitText + Vertical + Flow + Resize + ID + 82 + Shape + Rectangle + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Pad + 0 + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 yes} + VerticalPad + 0 + + + + Class + LineGraphic + ID + 81 + Points + + {515.932, 108.932} + {566.932, 108.932} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 73 + Info + 3 + + + + Class + LineGraphic + ID + 80 + Points + + {461.932, 162.932} + {461.932, 216.932} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 73 + + + + Bounds + {{407.932, 54.932}, {108, 108}} + Class + ShapedGraphic + ID + 73 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Diamond + Style + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 decision} + VerticalPad + 0 + + + + Class + LineGraphic + Head + + ID + 19 + Position + 0.11005332320928574 + + ID + 71 + OrthogonalBarAutomatic + + OrthogonalBarPosition + 0.0 + Points + + {197.932, 206.932} + {71.9318, 248.668} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 1 + Info + 2 + + + + Class + LineGraphic + Head + + ID + 53 + + ID + 67 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {71.9318, 548.613} + {278.932, 688.774} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 18 + Info + 1 + + + + Class + LineGraphic + Head + + ID + 53 + + ID + 63 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {332.932, 549.113} + {332.932, 661.774} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 47 + + + + Bounds + {{278.932, 661.774}, {108, 54}} + Class + ShapedGraphic + ID + 53 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Rectangle + Style + + stroke + + Width + 3 + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\b\fs24 \cf0 Packet Lookup +\b0 Use assigned header fields} + + VFlip + YES + + + Class + LineGraphic + Head + + ID + 39 + + ID + 50 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {386.932, 494.613} + {404.932, 494.613} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 47 + + + + Class + LineGraphic + Head + + ID + 47 + + ID + 49 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {242.932, 494.613} + {278.932, 494.613} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 35 + + + + Class + LineGraphic + Head + + ID + 35 + + ID + 48 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {125.932, 494.613} + {143.932, 494.613} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 18 + + + + Class + LineGraphic + Head + + ID + 41 + + ID + 45 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {458.932, 548.613} + {458.932, 566.613} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 39 + + + + Class + LineGraphic + Head + + ID + 42 + + ID + 44 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {512.932, 620.613} + {539.932, 620.613} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 41 + + + + Class + LineGraphic + Head + + ID + 37 + + ID + 43 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {512.932, 494.613} + {539.932, 494.613} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 39 + + + + Bounds + {{539.932, 584.613}, {90, 72}} + Class + ShapedGraphic + ID + 42 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Rectangle + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 Use ICMP type and code for L4 fields} + + VFlip + YES + + + Bounds + {{404.932, 566.613}, {108, 108}} + Class + ShapedGraphic + ID + 41 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Diamond + Style + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 IP Proto = \ +1?} + VerticalPad + 0 + + + + Bounds + {{404.932, 440.613}, {108, 108}} + Class + ShapedGraphic + ID + 39 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Diamond + Style + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 IP Proto = \ +6 or 7?} + VerticalPad + 0 + + + + Bounds + {{539.932, 458.613}, {90, 72}} + Class + ShapedGraphic + ID + 37 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Rectangle + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 Use UDP/TCP source and destination for L4 fields} + + VFlip + YES + + + Bounds + {{143.932, 458.613}, {99, 72}} + Class + ShapedGraphic + ID + 35 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Rectangle + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 Set IP source, destination, protocol, and ToS fields} + + VFlip + YES + + + Bounds + {{278.932, 440.613}, {108, 108}} + Class + ShapedGraphic + ID + 47 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Diamond + Style + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 Not IP Fragment?} + VerticalPad + 0 + + + + Class + LineGraphic + Head + + ID + 18 + + ID + 19 + Points + + {71.9318, 224.932} + {71.9318, 440.613} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 6 + + + + Bounds + {{17.9318, 440.613}, {108, 108}} + Class + ShapedGraphic + ID + 18 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Diamond + Style + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 Eth type = 0x0800?} + VerticalPad + 0 + + + + Class + LineGraphic + Head + + ID + 1 + + ID + 17 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {125.932, 170.932} + {143.932, 170.932} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 6 + + + + Class + LineGraphic + Head + + ID + 6 + + ID + 16 + Points + + {71.9318, 98.932} + {71.9318, 116.932} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 7 + + + + Bounds + {{8.93179, 8.93201}, {126, 90}} + Class + ShapedGraphic + ID + 7 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Rectangle + Style + + stroke + + Width + 3 + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\b\fs24 \cf0 Initialize Headers +\b0 \ +Set input port, Ethernet source, destination, and type;\ +set all others to zero} + + + + Bounds + {{17.9318, 116.932}, {108, 108}} + Class + ShapedGraphic + ID + 6 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Diamond + Style + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 Eth type = 0x8100?} + VerticalPad + 0 + + + + Bounds + {{143.932, 134.932}, {108, 72}} + Class + ShapedGraphic + ID + 1 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Rectangle + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 Set VLAN ID and PCP. Use encapsulated Eth type for next Eth type check} + + VFlip + YES + + + GridInfo + + ShowsGrid + YES + + GuidesLocked + NO + GuidesVisible + YES + HPages + 1 + ImageCounter + 1 + KeepToScale + + Layers + + + Lock + NO + Name + Layer 1 + Print + YES + View + YES + + + LayoutInfo + + Animate + NO + circoMinDist + 18 + circoSeparation + 0.0 + layoutEngine + dot + neatoSeparation + 0.0 + twopiSeparation + 0.0 + + LinksVisible + YES + MagnetsVisible + NO + MasterSheets + + ModificationDate + 2009-12-16 14:42:02 -0800 + Modifier + brandonh + NotesVisible + NO + Orientation + 2 + OriginVisible + NO + PageBreaks + YES + PrintInfo + + NSBottomMargin + + float + 41 + + NSLeftMargin + + float + 18 + + NSOrientation + + int + 1 + + NSPaperName + + string + eleven_by_seventeen + + NSPaperSize + + size + {1224, 792} + + NSRightMargin + + float + 18 + + NSTopMargin + + float + 18 + + + PrintOnePage + + QuickLookPreview + + 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 + +qSeZg3KM+lp1mCFsp41mJI+c9ZghTrVdC/PGpibp8N9ueoqKWc6QE6f6rBoVuOjNNNT + /vXueHv3cCbpuRl5DNZ3+AhGgfKn35VfBGYCz6muyPvRkuJJHnEBFXnhMfcxFs850/lh + 2YXM3YVqdLFrWHLv0iVjg4DDlI5YMwzsDxWsYZjqkvFqnfUUS7HMj32b5tc04tt4+BPP + 3REWfVtpNV3TtcxXunKsCuxQunIMg3ocurWYtg6ofcXrCsz3qf6mYgolMeExrBIIPvI1 + VumyTiBXmT7aJVyjCx7l8VQKY5e0H4HjsxxckjsaiUKLF30fKcldi7tKsigYCru0k0qt + Xg26sgJFY5KNdJT4KdmEH8Ogt8xPr37hVCrJa/kVF5aTYSjsUtefYKHtHWhL6apgUqYT + v5J/l2ezgB5+pIn0kudmQpDXhQjrMJum+DAMvEc+6RJ9+3/P6L6+CmVuZHN0cmVhbQpl + bmRvYmoKNiAwIG9iagozNzM1CmVuZG9iagozIDAgb2JqCjw8IC9UeXBlIC9QYWdlIC9Q + YXJlbnQgNCAwIFIgL1Jlc291cmNlcyA3IDAgUiAvQ29udGVudHMgNSAwIFIgL01lZGlh + Qm94IFswIDAgMTE4OCA3MzNdCj4+CmVuZG9iago3IDAgb2JqCjw8IC9Qcm9jU2V0IFsg + L1BERiAvVGV4dCAvSW1hZ2VCIC9JbWFnZUMgL0ltYWdlSSBdIC9Db2xvclNwYWNlIDw8 + IC9DczEgOCAwIFIKL0NzMiAzNyAwIFIgPj4gL0ZvbnQgPDwgL0YxLjAgMzggMCBSIC9G + Mi4wIDM5IDAgUiA+PiAvWE9iamVjdCA8PCAvSW0xMiAzMSAwIFIKL0ltNiAxOSAwIFIg + L0ltMyAxMyAwIFIgL0ltMSA5IDAgUiAvSW00IDE1IDAgUiAvSW0xMCAyNyAwIFIgL0lt + OSAyNSAwIFIgL0ltMTEKMjkgMCBSIC9JbTE0IDM1IDAgUiAvSW0yIDExIDAgUiAvSW01 + IDE3IDAgUiAvSW0xMyAzMyAwIFIgL0ltNyAyMSAwIFIgL0ltOAoyMyAwIFIgPj4gPj4K + ZW5kb2JqCjMxIDAgb2JqCjw8IC9MZW5ndGggMzIgMCBSIC9UeXBlIC9YT2JqZWN0IC9T + dWJ0eXBlIC9JbWFnZSAvV2lkdGggMjYwIC9IZWlnaHQgMjYwIC9Db2xvclNwYWNlCjQw + IDAgUiAvU01hc2sgNDEgMCBSIC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxh + dGVEZWNvZGUgPj4Kc3RyZWFtCngB7dAxAQAAAMKg9U/taQmIQGHAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDgAwMYXQABCmVuZHN0cmVhbQplbmRvYmoKMzIgMCBvYmoKOTA4CmVuZG9iagoxOSAw + IG9iago8PCAvTGVuZ3RoIDIwIDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1h + Z2UgL1dpZHRoIDI0MiAvSGVpZ2h0IDE4OCAvQ29sb3JTcGFjZQo0MyAwIFIgL1NNYXNr + IDQ0IDAgUiAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+ + CnN0cmVhbQp4Ae3QAQ0AAADCoPdP7ewBESgMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwY+MBVGAAEKZW5kc3RyZWFtCmVuZG9iagoyMCAwIG9iago2MTgKZW5kb2Jq + CjEzIDAgb2JqCjw8IC9MZW5ndGggMTQgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBl + IC9JbWFnZSAvV2lkdGggMzAwIC9IZWlnaHQgMjI4IC9Db2xvclNwYWNlCjQ2IDAgUiAv + U01hc2sgNDcgMCBSIC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNv + ZGUgPj4Kc3RyZWFtCngB7dAxAQAAAMKg9U9tCj+IQGHAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAwGtgIb0AAQplbmRzdHJlYW0KZW5kb2JqCjE0IDAgb2JqCjkxOAplbmRvYmoK + OSAwIG9iago8PCAvTGVuZ3RoIDEwIDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAv + SW1hZ2UgL1dpZHRoIDI2MCAvSGVpZ2h0IDE4OCAvQ29sb3JTcGFjZQo0OSAwIFIgL1NN + YXNrIDUwIDAgUiAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2Rl + ID4+CnN0cmVhbQp4Ae3QMQEAAADCoPVPbQo/iEBhwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGPgODDzuAAEKZW5kc3RyZWFtCmVuZG9iagoxMCAwIG9iago2NjMKZW5kb2JqCjE1 + IDAgb2JqCjw8IC9MZW5ndGggMTYgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9J + bWFnZSAvV2lkdGggMjYwIC9IZWlnaHQgMjYwIC9Db2xvclNwYWNlCjQwIDAgUiAvU01h + c2sgNTIgMCBSIC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUg + Pj4Kc3RyZWFtCngB7dAxAQAAAMKg9U/taQmIQGHAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDgAwMYXQAB + CmVuZHN0cmVhbQplbmRvYmoKMTYgMCBvYmoKOTA4CmVuZG9iagoyNyAwIG9iago8PCAv + TGVuZ3RoIDI4IDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRo + IDIyNCAvSGVpZ2h0IDE4OCAvQ29sb3JTcGFjZQo1NCAwIFIgL1NNYXNrIDU1IDAgUiAv + Qml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4 + Ae3QAQ0AAADCoPdPbQ43iEBhwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDDwNDDtjwABCmVuZHN0cmVhbQplbmRvYmoKMjggMCBvYmoKNTc0CmVuZG9iagoy + NSAwIG9iago8PCAvTGVuZ3RoIDI2IDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAv + SW1hZ2UgL1dpZHRoIDI2MCAvSGVpZ2h0IDI2MCAvQ29sb3JTcGFjZQo0MCAwIFIgL1NN + YXNrIDU3IDAgUiAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2Rl + ID4+CnN0cmVhbQp4Ae3QMQEAAADCoPVP7WkJiEBhwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg4AMDGF0A + AQplbmRzdHJlYW0KZW5kb2JqCjI2IDAgb2JqCjkwOAplbmRvYmoKMjkgMCBvYmoKPDwg + L0xlbmd0aCAzMCAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUgL0ltYWdlIC9XaWR0 + aCAyNjQgL0hlaWdodCAxNTYgL0NvbG9yU3BhY2UKNTkgMCBSIC9TTWFzayA2MCAwIFIg + L0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0K + eAHt0AENAAAAwqD3T20PBxEoDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMDA/8AA4q8A + AQplbmRzdHJlYW0KZW5kb2JqCjMwIDAgb2JqCjU2MgplbmRvYmoKMzUgMCBvYmoKPDwg + L0xlbmd0aCAzNiAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUgL0ltYWdlIC9XaWR0 + aCAyNDIgL0hlaWdodCAxODggL0NvbG9yU3BhY2UKNjIgMCBSIC9TTWFzayA2MyAwIFIg + L0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0K + eAHt0AENAAAAwqD3T+3sAREoDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + PjAVRgABCmVuZHN0cmVhbQplbmRvYmoKMzYgMCBvYmoKNjE4CmVuZG9iagoxMSAwIG9i + ago8PCAvTGVuZ3RoIDEyIDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2Ug + L1dpZHRoIDI2MCAvSGVpZ2h0IDI2MCAvQ29sb3JTcGFjZQo0MCAwIFIgL1NNYXNrIDY1 + IDAgUiAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0 + cmVhbQp4Ae3QMQEAAADCoPVP7WkJiEBhwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg4AMDGF0AAQplbmRz + dHJlYW0KZW5kb2JqCjEyIDAgb2JqCjkwOAplbmRvYmoKMTcgMCBvYmoKPDwgL0xlbmd0 + aCAxOCAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUgL0ltYWdlIC9XaWR0aCAyNjAg + L0hlaWdodCAyNjAgL0NvbG9yU3BhY2UKNDAgMCBSIC9TTWFzayA2NyAwIFIgL0JpdHNQ + ZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAHt0DEB + AAAAwqD1T+1pCYhAYcCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYOADAxhdAAEKZW5kc3RyZWFtCmVuZG9i + agoxOCAwIG9iago5MDgKZW5kb2JqCjMzIDAgb2JqCjw8IC9MZW5ndGggMzQgMCBSIC9U + eXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMjYwIC9IZWlnaHQgMjYw + IC9Db2xvclNwYWNlCjY5IDAgUiAvU01hc2sgNzAgMCBSIC9CaXRzUGVyQ29tcG9uZW50 + IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7dAxAQAAAMKg9U/taQmI + QGHAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDgAwMYXQABCmVuZHN0cmVhbQplbmRvYmoKMzQgMCBvYmoK + OTA4CmVuZG9iagoyMSAwIG9iago8PCAvTGVuZ3RoIDIyIDAgUiAvVHlwZSAvWE9iamVj + dCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRoIDIyNCAvSGVpZ2h0IDE4OCAvQ29sb3JTcGFj + ZQo1NCAwIFIgL1NNYXNrIDcyIDAgUiAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIg + L0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae3QAQ0AAADCoPdPbQ43iEBhwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDDwNDDtjwABCmVuZHN0cmVhbQplbmRv + YmoKMjIgMCBvYmoKNTc0CmVuZG9iagoyMyAwIG9iago8PCAvTGVuZ3RoIDI0IDAgUiAv + VHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRoIDI2MCAvSGVpZ2h0IDI2 + MCAvQ29sb3JTcGFjZQo0MCAwIFIgL1NNYXNrIDc0IDAgUiAvQml0c1BlckNvbXBvbmVu + dCA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae3QMQEAAADCoPVP7WkJ + iEBhwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBg4AMDGF0AAQplbmRzdHJlYW0KZW5kb2JqCjI0IDAgb2Jq + CjkwOAplbmRvYmoKNDQgMCBvYmoKPDwgL0xlbmd0aCA0NSAwIFIgL1R5cGUgL1hPYmpl + Y3QgL1N1YnR5cGUgL0ltYWdlIC9XaWR0aCAyNDIgL0hlaWdodCAxODggL0NvbG9yU3Bh + Y2UKL0RldmljZUdyYXkgL0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURl + Y29kZSA+PgpzdHJlYW0KeAHtne9vEtkax21LocAAQ0sHyo8LDlAYkLIjKG2pCw0ExVKt + VVxcW1KdapZKRY1EsrUupiqR+KN1bbRGa9dYjbqNNY0as5r7r93nUHP3SnHd+46zPd8X + RpKanM98n/M5U3xxtmwhIU+APAHyBMgTwPcJNGCd/+u5A2njn2nCLH+uvBFA/gb4Oi1Q + ikTNGEckAgQE/y3oCu86rFgiaVmPFKN8XrJEIoa6APsbzJ95m5vFACuVyeRyOUVRCqwC + C4Zly2TSlhZE/dfMCLgJZhlwAZZSKJUqmlZjF5pWKZUK4JYB9DrzV0a7Agz9Il6FUqVW + t7ZpNO3tDKPFKAzT3q7RtLWq1SqlAjFDzzDatZFRw6hgxEsDLaPVdej1BqPRhFGMRoNe + 36HTMkBNV5ihZoRcQ9oVYNjAcgp4ARdYTWaLZStrxSrsVovFbAJugAZmSo62c23kBrSH + JVIoWN3G6PRAy1rtnQ4nx7lcbkzicnGc09Fpt7JArdcxbWqoWSpB/tpYMlQMwC1yhUqt + 0epNFtbWybm2ebxenue3YxNYrNfr2ebiOm2sxaTXatQqBbTcLKox11AxSEtWATaYWbvT + 7fHyvh07Az29kCAWQSvtCezc4eO9HrfTzpoNFWQZ6KtGyQ1QcYuMUqo1OoPZ6nB38f5A + T3BXKNwfiUSimASW2h8O7Qr2BPx8l9thNRt0GrWSkrVAydVjvV6xHIC1BouN8/D+7mCo + PxrbEx9IDO7DJoOJgfieWLQ/FOz28x7OZkEtK+W1SkbEMNM0AJttnNcX6AtHdu8d3D98 + MHk4hVEOJw8O7x/cuzsS7gv4vJwNDTatgJI3jDUMtbhFrmxl9GYr1+XvDUXjiQOHUkdH + 02PHBWEckwjC8bH06NHUoQOJeDTU6+/irGY904pK3jDWDY1wMkHFOhPr8Ph6w7GBoeSR + 0THhZOZUdvJ0DpOcnsyeypwUxkaPJIcGYuFen8fBmnRQMpxQ1RsZDTXsYkZvsbv5QCiW + GE6NHDuRyebOnc9fKGCTC/nz53LZzIljI6nhRCwU4N12i55BOxnG+svXrgqxqk1rYp1d + /r4oAKeFzOTZfGFq+lLxMjYpXpqeKuTPTmaENCBH+/xdTtakbVPVJBZLKVrTYba5+e5w + fCiVHp/I5QvTxZmrpetlbHK9dHWmOF3I5ybG06mheLibd9vMHRqakoo3dCwSSxVoqDs9 + /mBkMDkiTJzJTxWvlMo3b8/ewSazt2+WS1eKU/kzE8JIcjAS9Hs60VgrpKCuqqkWSWTK + Vq2RdXoD3+8+cOTYT7n81OVr5Vtzd+fv31/AJPfvz9+du1W+dnkqn/vp2JEDu78PeJ2s + UduqlElqEMuVsI2tLr6nf++h0RNZAC7dmL1778HDxcdLmOTx4sMH9+7O3igBcvbE6KG9 + /T28ywobWSmvQQyq1nT8y77NB0OdGsucLfxy7cbc/MKjpSdPl59hkuWnT5YeLczP3bj2 + S+FsZiwFY+3bZv9XhwZkvaFjOJxUGrSNd+yK7f9RyOYvzpRn5x8s/rb8/MXLV5jk5Yvn + y78tPpifLc9czGeFH/fHdu1AG1mDZF29j4GYBmKHNxDaMzx6Mlcolm7dXVh88uzlq5XX + q5jk9cqrl8+eLC7cvVUqFnInR4f3hAJeBxDTNYkpul2/FcQVjh9MZ879PFOeu/cIgFdW + 36xhkzerK4D86N5ceebnc5n0wXgY1LVV305TtTqm1O0Glvuup38gOTZx/uLVm78+WFp+ + sbK69vbde0zy7u3a6sqL5aUHv968evH8xFhyoL/nO441tKu/QswYWY7vjSQOH8/mL5Vu + zT988vz312tv33/AJu/frr3+/fmTh/O3Spfy2eOHE5FenmONzNeJ4XAC4h+EyQvF67fv + LT59sfIGgP/4iEn++PD+7ZuVF08X792+XrwwKfyAiF3WbxIPpoTThcvlufuPl1++XnsH + wJ8wycc/Prxbe/1y+fH9ufLlwmkBjqevEcMviy2UmjFWOq5B/G8s8umvib/43qehqRle + q+GVy709GN2XGs9Bx3cWlp69Wl17/+HjJyx4YZGfPn54v7b66tnSwh3oODee2hcNbnfD + Sxe8WDc3EWLSMZlqHPYy2cfEXP/zLQg5nch5jIO2yBsIeecib5nkNwnyuxMWtiZvmeQt + k7xlkm99yPdc9a9r4mriauJq4mriauLq+nsC5HQipxM5ncjpRE6n+nNz9YqIq4mriauJ + q4mrq81Yf5+Jq4mriauJq4mr68/N1SsiriauJq4mriaurjZj/X0mriauJq4mriaurj83 + V6+IuJq4mriauJq4utqM9feZuJq4mriauJq4uv7cXL0i4mriauJq4mri6moz1t9n4mri + auJq4mri6vpzc/WKiKuJq4mriauJq6vNWH+fiauJq4mriauJq+vPzdUrIq4mriauJq4m + rq42Y/19Jq4mriauJq4mrq4/N1eviLiauJq4mrj6n+3qTXej1ZZvEP/zbi37gnhT3Uy3 + 2W4f3HQ3TG66W0Q3302xm+02YNGmu/FZJNl0t3pvvpvbxXDFJIOu9fbDRebJEWHiTH6q + eKVUvnl79g42mb19s1y6UpzKn5kQRpJwjbkfXerNwCWi4g33mDeJpRSt6TDb3Hx3OD6U + So9P5PKF6eLM1dL1Mja5Xro6U5wu5HMT4+nUUDzczbtt5g4NTUnFTdX3mDehq9vbtCbW + 2eXviyaGU2khM3k2X5iavlS8jE2Kl6anCvmzkxkhnRpORPv8XU7WpG1DF7fXJFaisba7 + +UAoBsgjx05ksrlz5/MXCtjkQv78uVw2c+LYCADHQgHebUdDraxBDBcgS6QKWqMzsQ6P + rzccGxhKHhkdE05mTmUnT+cwyenJ7KnMSWFs9EhyaCAW7vV5HKxJp6EVUklz4xeXAW/Z + 0tAoEsOJ3MrozVauy98bisYTBw6ljo6mx44LwjgmEYTjY+nRo6lDBxLxaKjX38VZzXqm + FSoGcW0gho0sg5K1BrON8/oCfeHI7r2D+4cPJg+nMMrh5MHh/YN7d0fCfQGfl7OZDVqo + WIa2cQ1iVLIakC02zsP7u4Oh/mhsT3wgMbgPmwwmBuJ7YtH+ULDbz3s4mwWA0S4WbyRG + Yw0lU4CsM5itDncX7w/0BHeFwv2RSCSKSWCp/eHQrmBPwM93uR1Ws0EHwBRUvGGo0UZu + ahbDXKtQy2bW7nR7vLxvx85ATy8kiEXQSnsCO3f4eK/H7bSzaKTVKpjpWhUDMZQsaZFX + kPUmC2vr5FzbPF4vz/PbsQks1uv1bHNxnTbWYtJXgOUtEqi4ehvDl/VQMiBL5Qqluo3R + 6U1mC2u1dzqcHOdyuTGJy8VxTken3cpazCa9jmlTKxVyOJlEG7yF/ncCSoa5hpYpJd2q + YbR6gxGoLVtZK1Zht1qA1mjQaxlNK62koGE00zUq/owMgy2DmunWNoDWdeiB22jCKEZg + 1XfoALcNeBVyGYz014C3NFRaBn1VmFVqNVBr2tsZRotRGKa9XQO0arWqwgvSqgBXHcaf + /8utgixqhpqBWU4plEoVTauxC02rlEoFJYd+UcGwhxsbagPDXEPLyF9oO7dIZYAtpyhK + gVVgwbBsmUwKuNAv4v06MNLXOjNAAzVgVyLFKJ+XLEG0zaJv8laUjZgbm5qaRAgb2wBs + E6r3L/v9vJtR0RVq9PMQ+JdYZX3VlT8B5L9Qf+cv8PMY5+8Qkp8hT4A8AfIEyBOo1yfw + HxfQr7EKZW5kc3RyZWFtCmVuZG9iago0NSAwIG9iagoyNzk1CmVuZG9iago2NyAwIG9i + ago8PCAvTGVuZ3RoIDY4IDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2Ug + L1dpZHRoIDI2MCAvSGVpZ2h0IDI2MCAvQ29sb3JTcGFjZQovRGV2aWNlR3JheSAvQml0 + c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae3d + /1NSWRQA8L4o8k1ERVSSlaJscSC0MFOyNBq/t1oOI30znDKjRi0dWkfLKdQpsfJL5bjm + aE7soJlp6qhtu7P/2p77sEwXFBXeu/fC+SUNSvh47rnvPeCcPXvCERYIC4QFwgJhgbBA + WCAsgJHAXhT7IJgvMHpgLD2U1WcPAPv3IwYI+CuWfjgWP8bz69+/PyIiIhIC/vBIhJAC + WgAAAM+ex4uC4PEQBMMQIqmAkgAB8KL4fL5AIBQKBPBFFDhEwLIIiVRgCBgBgVAkEkdD + iEUioYBRCA0EIIAk4PH5QpFYIomRxkJIYyQSsUjI5/NQKlCfCR6CKBCIlkhj42SyBAiZ + LC5WKokGhagQQFglEEAOSONkCYlJCiaSEhNkcVLIBQH9CB4CvkCEBORJihRlqgoiVZmi + SJIjBZGAT3kmrBIIRZLYeHnSAaXqkPpIGsQR9SGV8kCSPD5WAuuBaoTvBGJJrCxRoVSp + 0zTpWt2xYzptuiZNrVIqEmWxEjHVCD8IYuISklOQgFafecKQlWU4kanXIoWU5IS4GJoR + fiKQK5QH0zS6TEN2rjEPwpibbcjUadIOKhVymhHWCOLlil/UR7UZhlPGs+fOF0KcP3fW + eMqQoT2q/kUhj6c2E34iSFSkqjW649nGfFNRaXkFRHlpkSnfmH1cp1GnKhJpRVhPcFij + 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 + a7jf3NLSfL/BVme9aq4oMZ0m8qrRVlmAbt+YCfosY0HxhSrL9dpb9ba7d231t2qvW6ou + FBcYs/QEXjjzh+B/CDAnNTe/sKzSbLlWY62ttdZcs5grywrzc2HeKHnXDv0j2ICQehgQ + cs6Yissrq8wWCHNVZXmx6UwOIkgl7fKpvwQbEdQa3fFsY76pqLS8AqK8tMiUb8w+rtOo + KSZYhyCHyclHtRmGU8az584XQpw/d9Z4ypChPQrTh+VkXUT3PwvQPdcKI0zQVh5M0+gy + Ddm5xjwIY262IVOnSTuoZEZxE/Q6wvYI1iEkJKeo1GkarT7zhCEry3AiU6/VpKlVKckJ + ayPZcX1xfbtPe/39f2QCTNFOVCiRQrpWd+yYTpuOBJSKRJhATdKrSeufnn/ffUeAUeLx + 8qQDStUh9ZE0iCPqQyrlgSR5PMxepngheJBWEQQiiTROJk9SpChTVRCpyhRFklwWJ4WJ + 9Hi/y8S/3/Xm9/IgRAlEYqSQkJikYCIpMQEJiEVoDDnGb7TZ/Mn5e+sqAl8oipZIY+Nk + sgQImSwuViqJhnUQCgTfdwceHxTEEkmMNBZCGiOBHBDy+bwQyAKULZAJMCUxkhfFFwhF + InE0hFgkEgr4UbxIGMOO7zvO/E11f+7HIEQwCny+QCAUCgR8PiMApSA0CFAq7INUgLEv + 4MCLguBBBsAqAAFvw3b9cSXwPigVGIYIBBEZEeEBCJkk8PzK9noYGAnkAQF/ReCvc5cP + GZ60R4L5Ypf/WfifhwXCAmGBsEBYICwQFggLBFbgP0gqPFwKZW5kc3RyZWFtCmVuZG9i + ago2OCAwIG9iagozNzExCmVuZG9iago3MCAwIG9iago8PCAvTGVuZ3RoIDcxIDAgUiAv + VHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRoIDI2MCAvSGVpZ2h0IDI2 + MCAvQ29sb3JTcGFjZQovRGV2aWNlR3JheSAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0 + ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae2d+VsUx9bHXdiRYdVhVRBFQRRQzCiK + gEQQQVAgcQEjChoRXFAxEL0oj4orwYvixUB4JRdRiaAoatTXJ//aPVXd1V09U70NPTM9 + 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 + 2tbeeaXrWlfXlY72ttafj9XV8vECcSwwdQSZ9YnLPXPsDgUlFdUHf2psPtN2sf3y5faL + 5880Nx09VFPB5Rf4IAJ72YzqNu/4fs++H+samk61nDl7trXlVFND/YH95buEM0fJKYvy + taDlgJv2OZ4dhH2RUMHbll9cVllzsL7heNOJE43Hj9YfrKkqK863wYmjpKKNh9KwXceQ + QOCizQjC9qKS8qqaA4fq6uvrDv1YU1VeUrSdRuDFPoIcRgmElLR12bl5O4pLyyv3V9fU + VO+r3FNaXJC3OXtdWkqih3alyL1xI5/bQcjI2mTbVlBcsrtsz56y0l07C7bZNmVlrIaj + d2MiIYLsg1aAYNIQEpNXrc3MzrXl5RcW7dxZWJCfZ8vNzly7CiPwDYHMth+AQBSjNWHF + yrT09dmbNtu25m3dYtu8MXt9elrqigSwAl9GIBFL1vik5NS09MwNWTlwZW3IBALJSfHW + aO4gbp8QyAqWgKbIiKilsYjC6jXp6RkZ6WvTVgOBhNilUT6PQBRLYeGRMcuAworklalw + rUxekRQftywmMty7FtTYn7TaUzwmBMBxJ5aIqJhl1viExCS4EuPjrMtioiIscBi7z0kj + RyQ8hODQMEtEZDRgsMbGWgFAdGSEJSw0eC4gIN0hMCgEKIRHRkZFwxUVGRFuWRIaArIA + DhHzIR/B0Qa4J8gSUKQVKAAGS3h4uMUStiQUbACMAM4gnwMIOEvw8/cPCAwKBgz4CgEA + gQH+cITYIsXjYuS4et9zsARkChhDEL4CMQBsBEon5nhfU+Xf8UJMAWPwDwiAzx8sAAGY + G/2A57IQU1i0ePFiP3TBVwxgjvQDwTh4DKjt+ILvhZ/NpRtoN7nmUrPn2zpPYJ7APIF5 + AvME5gnME/AKAv8Df6F/1QplbmRzdHJlYW0KZW5kb2JqCjcxIDAgb2JqCjY4MjQKZW5k + b2JqCjc0IDAgb2JqCjw8IC9MZW5ndGggNzUgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0 + eXBlIC9JbWFnZSAvV2lkdGggMjYwIC9IZWlnaHQgMjYwIC9Db2xvclNwYWNlCi9EZXZp + Y2VHcmF5IC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4K + 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 + EKnKFEWSXBYnhYn0eL/LxL/f9eb38iBECURipJCQmKRgIikxAQmIRWgMOcZvtNn8yfl7 + 6yoCXyiKlkhj42SyBAiZLC5WKomGdRAKBN93Bx4fFMQSSYw0FkIaI4EcEPL5vBDIApQt + kAkwJTGSF8UXCEUicTSEWCQSCvhRvEgYw47vO878TXV/7scgRDAKfL5AIBQKBHw+IwCl + IDQIUCrsg1SAsS/gwIuC4EEGwCoAAW/Ddv1xJfA+KBUYhggEERkR4QEImSTw/Mr2ehgY + CeQBAX9F4K9zlw8ZnrRHgvlil/9Z+J+HBcICYYGwQFggLBAWCAsEVuA/SCo8XAplbmRz + dHJlYW0KZW5kb2JqCjc1IDAgb2JqCjM3MTEKZW5kb2JqCjYwIDAgb2JqCjw8IC9MZW5n + dGggNjEgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMjY0 + IC9IZWlnaHQgMTU2IC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5IC9CaXRzUGVyQ29tcG9u + ZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7Z3bT1NZFIeFll7o + nZ6209PT0gv0RhEKhHKJRayiYBWJaBslpKaMqabKjAOBMAwMGsTUYUAJQQjDxSAGCAFD + kBAx/muzdlvHIwW8zLwcZv0eCC9Nuj6+tfY5POx14gQGCSABJIAEkMC/IpB17PKNOKD+ + 7E/hHYN8qiYbivsaHGkGPB6fz885ZoGSeDyC5IssUiLwCAGBQCgUpSLmeNJlCIUCARTG + T6M4wgrSDgSCgBAQ50ogUqlUxvlAEaSWXDGUJQQWSRSHtgeRIU0BGEhlcrlCoVQdkygV + CrlcJiUsPpI4bFCkMIALAEEuV6ry1BRFabRaHeej1WqgFHWeSimXAwpCgihxsBFpDCIx + UFCq1JRGp9PTtMHAMEaOh2EMBprW63QaSg0opBKx6HAQKQxEBrlCBRD0NGM0mc0Wq9XG + +VitFrPZZGSAhYZSKeREicOMyCKzATCADGqNjmZMZqut0O5wulxut7uIw4Gv73I5HfZC + m9VsYmidRg1KpEEc0BkwI3MEBIOK0tJMvqXA7nR7ik+WlHq9ZRyP11tacrLY43baCyz5 + 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 + uVyhUKqOSZQKhVwuAwhiQiFlw2crxNLHxcfWIEoQEiLCAiKVSmWcDxRBagEGon8oHNIU + KRxEiWR3AAuBkNAgEXM8qSpEQqEATEiqAKPhUBk+kkih4PH5IMbxCpTEg+lIIHyBwmcs + yCcgvGOQVCXJn1/JIEUi+RM+cczCKg5/RQJIAAkgASTwPQT+Bp5VVMAKZW5kc3RyZWFt + CmVuZG9iago2MSAwIG9iagoyMjk5CmVuZG9iago1MCAwIG9iago8PCAvTGVuZ3RoIDUx + IDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRoIDI2MCAvSGVp + Z2h0IDE4OCAvQ29sb3JTcGFjZQovRGV2aWNlR3JheSAvQml0c1BlckNvbXBvbmVudCA4 + IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae2d+1NS+RvHvaDI7QCKgFyC + DqBcRPYEhooGDAzmLS9pi6WOhjZhGNnExKxZOJZMjJm2Ol6mzJys0dbJxqmm2Zr9177P + wdidFLfm+9tpn/cPjT/QzHlevp/X54O/nJwcDBJAAkgACSCBHyGQ+5PlR2b++zMwe94/ + yWd8/pklD0b7e8zjfziYH+ZmsQp+qrBYMBSN43sY0gQOxi9ks4sOwmF0vg7BZhfCrxRA + fIfCVwIFBYUwPofL5fF4fD5fwPDACDAIl8spKqI5/DsFGkE+bAAAgPH5AoIQikTinyAi + kZAgBECCCxgOKByzEGkE0AGagIAQisXFJRJJaalUKmN0pNLSUomkpFgsFhICmgJ0ARYi + OwS6BXQJaAIimF8qk5cpFEqVSs3oqFRKhaJMLpMCB1GaAlSBhpDlXEgjABHw+EAAAMD0 + ao1We5LUMTzkSa1WowYSgAEo8Hm0FrJDyKVdwOZACcQlUrkC5id1hvIKo8lkNlsYG7PZ + ZDJWlBt0JHBQyKUlYqgCh02b8WgRoAaAoIgnEIolMoVaS+rLTeZKq81GUdQpBgce32az + VppN5XpSq1bIJGKhAJpQwMqyDVAD0CE3jUCpIQ1Gi9VG2atPO2vrIC6Ghn72Wufpajtl + s1qMBlKjTEPgghizFCEXalDE5RNiiVyp0VVYqiiHs9bV4PZ4fT6fn7GBh/d63A2uWqeD + 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 + dGggMjYwIC9IZWlnaHQgMjYwIC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5IC9CaXRzUGVy + Q29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7d3/U1JZ + FADwvijyTURFVJKVomxxILQwU7I0Gr+3Wg4jfTOcMqNGLR1aR8sp1Cmx8kvluOZoTuyg + mWnqqG27s//anvuwTBcUFd6798L5JQ1K+Hjuue894Jw9e8IRFggLhAXCAmGBsEBYICyA + kcBeFPsgmC8wemAsPZTVZw8A+/cjBgj4K5Z+OBY/xvPr378/IiIiEgL+8EiEkAJaAAAA + z57Hi4Lg8RAEwxAiqYCSAAHwovh8vkAgFAoE8EUUOETAsgiJVGAIGAGBUCQSR0OIRSKh + gFEIDQQggCTg8flCkVgiiZHGQkhjJBKxSMjn81AqUJ8JHoIoEIiWSGPjZLIECJksLlYq + iQaFqBBAWCUQQA5I42QJiUkKJpISE2RxUsgFAf0IHgK+QIQE5EmKFGWqCiJVmaJIkiMF + kYBPeSasEghFkth4edIBpeqQ+kgaxBH1IZXyQJI8PlYC64FqhO8EYkmsLFGhVKnTNOla + 3bFjOm26Jk2tUioSZbESMdUIPwhi4hKSU5CAVp95wpCVZTiRqdcihZTkhLgYmhF+IpAr + lAfTNLpMQ3auMQ/CmJttyNRp0g4qFXKaEdYI4uWKX9RHtRmGU8az584XQpw/d9Z4ypCh + Par+RSGPpzYTfiJIVKSqNbrj2cZ8U1FpeQVEeWmRKd+YfVynUacqEmlFWE9wWKM35Jwx + FZdXVpktEOaqyvJi05kcg15zmFqEdQQqRJCbX1hWabZcq7HW1lprrlnMlWWF+bkIQUVn + JmwgSNdnGQuKL1RZrtfeqrfdvWurv1V73VJ1objAmKVPpxNhI0HGydOmkgrzVWudreF+ + c0tL8/0GW531qrmixHT6ZAaVCP8nyDOVVFbX3LQ1Nttb29rb21rtzY22mzXVlSWmPCoR + vBGUXrTcqLv3wN7W8dTR1eV42tFmf3Cv7oblYimVCN4Iyi5dtt5uaGntcHQ/d/b2Op93 + OzpaWxpuWy9fKqMQwRdBfaO9/Um382XfwODgQN9LZ/eTdntjPZUIvgjuNNkfOZ696H89 + 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 + fXF9u097/f1/ZAJM0U5UKJFCulZ37JhOm44ElIpEmEBN0qtJ65+ef999R4BR4vHypANK + 1SH1kTSII+pDKuWBJHk8zF6meCF4kFYRBCKJNE4mT1KkKFNVEKnKFEWSXBYnhYn0eL/L + xL/f9eb38iBECURipJCQmKRgIikxAQmIRWgMOcZvtNn8yfl76yoCXyiKlkhj42SyBAiZ + LC5WKomGdRAKBN93Bx4fFMQSSYw0FkIaI4EcEPL5vBDIApQtkAkwJTGSF8UXCEUicTSE + WCQSCvhRvEgYw47vO878TXV/7scgRDAKfL5AIBQKBHw+IwClIDQIUCrsg1SAsS/gwIuC + 4EEGwCoAAW/Ddv1xJfA+KBUYhggEERkR4QEImSTw/Mr2ehgYCeQBAX9F4K9zlw8ZnrRH + gvlil/9Z+J+HBcICYYGwQFggLBAWCAsEVuA/SCo8XAplbmRzdHJlYW0KZW5kb2JqCjUz + IDAgb2JqCjM3MTEKZW5kb2JqCjU3IDAgb2JqCjw8IC9MZW5ndGggNTggMCBSIC9UeXBl + IC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMjYwIC9IZWlnaHQgMjYwIC9D + b2xvclNwYWNlCi9EZXZpY2VHcmF5IC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAv + RmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7d3/U1JZFADwvijyTURFVJKVomxxILQwU7I0 + Gr+3Wg4jfTOcMqNGLR1aR8sp1Cmx8kvluOZoTuygmWnqqG27s//anvuwTBcUFd6798L5 + JQ1K+Hjuue894Jw9e8IRFggLhAXCAmGBsEBYICyAkcBeFPsgmC8wemAsPZTVZw8A+/cj + Bgj4K5Z+OBY/xvPr378/IiIiEgL+8EiEkAJaAAAAz57Hi4Lg8RAEwxAiqYCSAAHwovh8 + vkAgFAoE8EUUOETAsgiJVGAIGAGBUCQSR0OIRSKhgFEIDQQggCTg8flCkVgiiZHGQkhj + JBKxSMjn81AqUJ8JHoIoEIiWSGPjZLIECJksLlYqiQaFqBBAWCUQQA5I42QJiUkKJpIS + E2RxUsgFAf0IHgK+QIQE5EmKFGWqCiJVmaJIkiMFkYBPeSasEghFkth4edIBpeqQ+kga + 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 + 4BPAJ4BP4J88gf8Cx7sMUAplbmRzdHJlYW0KZW5kb2JqCjczIDAgb2JqCjI1MTQKZW5k + b2JqCjY1IDAgb2JqCjw8IC9MZW5ndGggNjYgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0 + eXBlIC9JbWFnZSAvV2lkdGggMjYwIC9IZWlnaHQgMjYwIC9Db2xvclNwYWNlCi9EZXZp + Y2VHcmF5IC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4K + c3RyZWFtCngB7d3/U1JZFADwvijyTURFVJKVomxxILQwU7I0Gr+3Wg4jfTOcMqNGLR1a + R8sp1Cmx8kvluOZoTuygmWnqqG27s//anvuwTBcUFd6798L5JQ1K+Hjuue894Jw9e8IR + FggLhAXCAmGBsEBYICyAkcBeFPsgmC8wemAsPZTVZw8A+/cjBgj4K5Z+OBY/xvPr378/ + IiIiEgL+8EiEkAJaAAAAz57Hi4Lg8RAEwxAiqYCSAAHwovh8vkAgFAoE8EUUOETAsgiJ + VGAIGAGBUCQSR0OIRSKhgFEIDQQggCTg8flCkVgiiZHGQkhjJBKxSMjn81AqUJ8JHoIo + EIiWSGPjZLIECJksLlYqiQaFqBBAWCUQQA5I42QJiUkKJpISE2RxUsgFAf0IHgK+QIQE + 5EmKFGWqCiJVmaJIkiMFkYBPeSasEghFkth4edIBpeqQ+kgaxBH1IZXyQJI8PlYC64Fq + hO8EYkmsLFGhVKnTNOla3bFjOm26Jk2tUioSZbESMdUIPwhi4hKSU5CAVp95wpCVZTiR + qdcihZTkhLgYmhF+IpArlAfTNLpMQ3auMQ/CmJttyNRp0g4qFXKaEdYI4uWKX9RHtRmG + U8az584XQpw/d9Z4ypChPar+RSGPpzYTfiJIVKSqNbrj2cZ8U1FpeQVEeWmRKd+YfVyn + UacqEmlFWE9wWKM35JwxFZdXVpktEOaqyvJi05kcg15zmFqEdQQqRJCbX1hWabZcq7HW + 1lprrlnMlWWF+bkIQUVnJmwgSNdnGQuKL1RZrtfeqrfdvWurv1V73VJ1objAmKVPpxNh + I0HGydOmkgrzVWudreF+c0tL8/0GW531qrmixHT6ZAaVCP8nyDOVVFbX3LQ1Nttb29rb + 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 + ory0yJRvzD6u06gpJliHIIfJyUe1GYZTxrPnzhdCnD931njKkKE9CtOH5WRdRPc/C9A9 + 1wojTNBWHkzT6DIN2bnGPAhjbrYhU6dJO6hkRnET9DrC9gjWISQkp6jUaRqtPvOEISvL + cCJTr9WkqVUpyQlrI9lxfXF9u097/f1/ZAJM0U5UKJFCulZ37JhOm44ElIpEmEBN0qtJ + 65+ef999R4BR4vHypANK1SH1kTSII+pDKuWBJHk8zF6meCF4kFYRBCKJNE4mT1KkKFNV + EKnKFEWSXBYnhYn0eL/LxL/f9eb38iBECURipJCQmKRgIikxAQmIRWgMOcZvtNn8yfl7 + 6yoCXyiKlkhj42SyBAiZLC5WKomGdRAKBN93Bx4fFMQSSYw0FkIaI4EcEPL5vBDIApQt + kAkwJTGSF8UXCEUicTSEWCQSCvhRvEgYw47vO878TXV/7scgRDAKfL5AIBQKBHw+IwCl + IDQIUCrsg1SAsS/gwIuC4EEGwCoAAW/Ddv1xJfA+KBUYhggEERkR4QEImSTw/Mr2ehgY + CeQBAX9F4K9zlw8ZnrRHgvlil/9Z+J+HBcICYYGwQFggLBAWCAsEVuA/SCo8XAplbmRz + dHJlYW0KZW5kb2JqCjY2IDAgb2JqCjM3MTEKZW5kb2JqCjU1IDAgb2JqCjw8IC9MZW5n + dGggNTYgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMjI0 + IC9IZWlnaHQgMTg4IC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5IC9CaXRzUGVyQ29tcG9u + ZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7Z3tTxPpGodBCqXt + 9A3aaenLtkxb2mkp3bHFUgrbNm14RxSErbtC0KpZWJDV2EgWdTGsEokiuBBeosgS0YBL + wBAlRs351849hbNGGNRNTmbH5v59IGaCmeea3309U/rlycnB4BPAJ4BPAJ/A//cJ5H5F + +UfkwHXkQ/IEnQ/rPALL/gLMXTZgEonyv5qIRLBgFvVziBm6XbQCsbhwNxLBZm+BYnEB + VAGQnyHco8vPLwA0iVQqk8kIgpALOLA8WKRUKiksZBk/Tcji5cFUAhygEXKFQqlSqQUe + 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 + tNhpnz9YE43XN7W2tXd0diUFm67Ojva21qb6eLQm6PfRdotRB8fbS9nj3z863jAnJxcO + gC9gT7gHQKud9jKBqnAklqhraGxuaT0u0LS2NDc21CVikXBVgPHSdivgsafbFxzkA0AR + FEgAoN5osTk9FUwgGArXRqKxeDyeEGRgYbFopDYcCgaYCo/TZjHqAY+A+kT76/tfgVK5 + km3QQjlcHq+P8VceC4aqIWEBhl1XKHis0s/4vB6Xg2KHU62E6eSqD/qDAsWFsgygwWyl + 7GW0u9zr8zEMc1SggaX5fN5yN11mp6xmQwZPViiG+g72xxoIgBKZXKEuJvUGs8VK2Rxl + ThdNu90eQcbtpmmXs8xho6wWs0FPFqsVcpkE8A7sLuz3hFAgbDHQIKFQFWlIncFoAkZr + KWUTcKhSK7CZjAYdqSlSKQhoj51Ojvr2AGFEpVChqqgYEPUlBqA0mQUbE5AZSvQAVwx0 + cpkUhvMwvJzcTIPwlsgQKtVqYNRotSSpE2xIUqvVAJtarczQwdaSwdv38tv7GjsDKMqH + CoFQRsgVCqVKpRZ4VCqlQiEnZNAdWx64dySXGw8mFBpkdxlWw0KJFCBlBEHIBRxYHixS + KpUAHHTH0h2Ox24yu4SACIwAmYlEsNlboJhlyxd9li6zjbKER/Ly8kQs5FcSQMtjq/tk + d3sWsiVmGNnfh8D/FHB215j5Ccv+G+FL/gG//9XkS3jwd/AJ4BPAJ4BP4J88gf8Cx7sM + UAplbmRzdHJlYW0KZW5kb2JqCjU2IDAgb2JqCjI1MTQKZW5kb2JqCjQxIDAgb2JqCjw8 + IC9MZW5ndGggNDIgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lk + dGggMjYwIC9IZWlnaHQgMjYwIC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5IC9CaXRzUGVy + Q29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7d3/U1JZ + FADwvijyTURFVJKVomxxILQwU7I0Gr+3Wg4jfTOcMqNGLR1aR8sp1Cmx8kvluOZoTuyg + mWnqqG27s//anvuwTBcUFd6798L5JQ1K+Hjuue894Jw9e8IRFggLhAXCAmGBsEBYICyA + kcBeFPsgmC8wemAsPZTVZw8A+/cjBgj4K5Z+OBY/xvPr378/IiIiEgL+8EiEkAJaAAAA + z57Hi4Lg8RAEwxAiqYCSAAHwovh8vkAgFAoE8EUUOETAsgiJVGAIGAGBUCQSR0OIRSKh + gFEIDQQggCTg8flCkVgiiZHGQkhjJBKxSMjn81AqUJ8JHoIoEIiWSGPjZLIECJksLlYq + iQaFqBBAWCUQQA5I42QJiUkKJpISE2RxUsgFAf0IHgK+QIQE5EmKFGWqCiJVmaJIkiMF + kYBPeSasEghFkth4edIBpeqQ+kgaxBH1IZXyQJI8PlYC64FqhO8EYkmsLFGhVKnTNOla + 3bFjOm26Jk2tUioSZbESMdUIPwhi4hKSU5CAVp95wpCVZTiRqdcihZTkhLgYmhF+IpAr + lAfTNLpMQ3auMQ/CmJttyNRp0g4qFXKaEdYI4uWKX9RHtRmGU8az584XQpw/d9Z4ypCh + Par+RSGPpzYTfiJIVKSqNbrj2cZ8U1FpeQVEeWmRKd+YfVynUacqEmlFWE9wWKM35Jwx + FZdXVpktEOaqyvJi05kcg15zmFqEdQQqRJCbX1hWabZcq7HW1lprrlnMlWWF+bkIQUVn + JmwgSNdnGQuKL1RZrtfeqrfdvWurv1V73VJ1objAmKVPpxNhI0HGydOmkgrzVWudreF+ + c0tL8/0GW531qrmixHT6ZAaVCP8nyDOVVFbX3LQ1Nttb29rb21rtzY22mzXVlSWmPCoR + vBGUXrTcqLv3wN7W8dTR1eV42tFmf3Cv7oblYimVCN4Iyi5dtt5uaGntcHQ/d/b2Op93 + OzpaWxpuWy9fKqMQwRdBfaO9/Um382XfwODgQN9LZ/eTdntjPZUIvgjuNNkfOZ696H89 + NAwx9Lr/xTPHI3vTHQoRvBNcsd5pevi4s+fV4NDI6BjE6MjQ4KuezscPAeEKZcvBB0Gt + ren3ji5n35vh0fEJF8TE+Ojwmz5nV8fvTbZauhA2J+h/OzI24XJPTk1Nul0TYyNv+ylE + 2JSgt3/o3fgH99T0DMT0lPvD+Luh/l7aMmFzgoGhd+9d7o8zs3MQszMf3a7374YGKEPY + kmDCNTn9eW5+AWJ+7vP0pGuCNgQ/CKY+zX5ZWFyCWFz4MvtpijaErQn+BIL5haWl5ZWV + 5aWlhXlA+JOqTPCLYG5+cWn5KxPLS4vzc3Qh+E2w8vXrX9++/fX16wptCNsgAIG//0YK + lCFsi+BvJmhD2AEBpAJVmbBdgn8gIBdoQtgJAWUIOyOgCmGnBBQh7JyAGoTdEFCCsDsC + KhB2SvDvv2h7REH8FrlzAmoQdkNACcLuCKhA2C0BBQi7JyAeIRAEhCMEhoBohEAREIwQ + OAJiEQJJQChCYAmIRAg0AYEIgScgDiEYBIQhBIeAKIRgERCEEDwCYhCCSUAIQnAJiEAI + NgEBCMEnwB6BDQLMEdghwBqBLQKMEdgjwBaBTQJMEdglwBKBbQIMEdgnwA6BCwLMELgh + wAqBKwKMELgjwAaBSwJMELglwAKBawIMELgn4BwBBwKOEfAg4BQBFwIOEfAh4AwBJwKO + EPAi4AQBNwIOEPAjYB0BRwKWEfAkYBUBVwIWEfAlYA0BZwKWEPAmYAUBdwIWEPAnCDoC + CQRBRiCDIKgIpBAEEYEcgqAhkEQQJASyCIKDwAwK4QvFMXGJCtXh9IyTeaayS1c8zf56 + ocfZBLR2Qn2NVqCnD3w82fM55X/++Zez+P4I/Pqs9Fov900mNHkIBEAgV6SSQLCdTEhl + GtqvDrnwiQBDgyIio2BKBkOg0TNZcNnKtHzEMgtQ+m2VCavtSZk25vI4mPQB405gBJIP + BDQ3KTKKD1MyEqAzvkafddpUCh1w76Cul9gSbImAerSWmk5n6TXQ1T8BJn3A4Bs0Ask7 + AqwEGBoEBLJkJRAYjKaSi/gT+INwscRkhF7uamUyTPoQwQgkmIDk3cCzEsQx8YkpB4/q + DLkFJZUWa33TQ6yzYMvl8LCp3mqpLCnINeiOHkxBkw08q8GrwY80kCtUadrjOflFFdU3 + bjfaH3c5ofEndjvCz1uRz5oAPVof2xtv36iuKMrPOa5NUynkmyYCMogSRktlSbASMrLP + FF4w19Q12B91MgQuzDbFnwl8LAfUlLLf2fnI3lBXY75QeCY7A1ZDkkwaLUQVweti2Aub + AlSDOPkBVZoOikFZ1dWb91raHT19b6H3KWr5iNFxwXoCbwioM+f7d2/7ehztLfduXq0q + g5KgS1MdQHsDzD/ybrBvXyRPIPakQWZ2fjEUA9uD1ifPXr0ZGXdN4k3gHWHSNT7y5tWz + J60PbFASivOzMz2JIBbwIvft81IQVpcC7ItQDSANys3X6xrtHd0vBofHPrinsc4C74Vx + dtr9YWx48EV3h72x7rq5HBIBVYSEWJ+LARmgpZCYcuhXffbZogpLra25zdHTPzQ64f74 + +csCPgfIGxeC5/uNhXHhy+eP7onRof4eR1uzrdZSUXQ2W//roZREZjF4LQhQDuDgICYe + KmJ6Zk5BadW1Ww2QBi9f/zHumpqZW4Dep5icI3gn2LgclpcW5mamXON/vH4JidBw61pV + aUFOZjpUxfgYOETwWhCQASoHyalHtCfQUqipv9/69HkfSoPVlYDHaZIvgvUITHdSWA2Q + CH3Pn7ber69Bi+GE9khqskwKBcGXQZRAzJQDnSGv8LdqK1oKzgGoBpOffqTB94Tz/UC4 + vOX7o2N6UqJE+DQJFWHAiRaDtfq3wjy0M0BBgMMkHwZwuhTNGBzLyiuEcnC3ub2zFyqi + ZynA6fLa2TKXT3Szn72KAA8UNSdlFgNUxd7O9ua7UBAK87KOeYoiHCp62xz37gsbQD0I + r4VwTdwT3hv3gEH4GCl8rAwnEOFzJrQYwufOq4shxK+hrF5SDeFraVAQ0KsLIX1Nldkd + Q/3aevg1Ftgdw6+1MQj7YX8M6ddcmQNmQAjp1973hN+DgVYDHCl5MiGegHdhrF07C+hA + F5IQgkRAUiYEjYAchCASkIIQVAIyEIJMQAJC0AnwR2CBAHcEVgjwRmCJAGcE1gjwRWCR + AFcEVgnwRGCZAEcE1gnwQ+CAADcETgjwQuCIACcEzgjwQeCQABcETgnwQOCYAAcEzgm4 + R8CAgGsELAi4RcCEgEsEbAi4Q8CIgCsErAi4QcCMgAsE7AjYR8CQgG0ELAnYRcCUgE0E + bAnYQ8CYgC0ErAnYQcCcgA0E7AmCj0AAQbARiCAILgIhBMFEIIYgeAgEEQQLgSiC4CAQ + RhAMBOIIAo9AIEGgEYgkCCwCoQSBRCCWIHAIBBMECoFogsAgEE4QCATiCXaPQAHBbhGo + INgdAiUEu0GghmDnCBQR7BbBr67x0B1ZCA1hoQmm17a48IFtrmOnn5VGmUAJwW4ygRqC + nSNQRLBTBKoIdoZAGcH2EQCAaQG7srQ4P/dp6k9okj7Q29Xxe5Ot9sqlMlPeyYz0wyoF + 6peP+Y7w84603d2BQoJtZgL0bP72DTXBpSgLUEZsIxOgdzcI0EewDYTlr0ws05YFfmfC + 7PzC0tLyysry0tLCPIxLoKMcrpXGrZcDmmrxZWFxCWJx4QuaGEHFjrBG4M9ycE1Of56b + X4CYn/s8PUkfgR8I713ujzOzcxCzMx/dMDeEguOCn7Ng65oAo37GP7inpmcgpqfcH8Zh + fgzxh0YbCbbIBGf/25GxCZd7cmpq0u2aGBt5C3OECD86/D/BVgh9b4ZHxydcEBPjo8Nv + +qgk8IkAI+AePu7seTU4NDI6BjE6MjT4qqfz8cOmO1ZyzxG8ZYHvmoCGwNkfOZ696H89 + NAwx9Lr/xTPHIzsQXCb2NMkXga9MuGytb7S3P+l2vuwbGBwc6Hvp7H7Sbm+sp5LAN8Lt + hpbWDkf3c2dvr/N5t6OjtaXhNqUE3hFKL1pu1N17YG/reOro6nI87WizP7hXd8NysZTQ + 6wW+F4LnFm+HzSWV1TU3bY3N9ta29va2Vntzo+1mTXVlCaUE3jLhtKmkwnzVWmdruN/c + 0tJ8v8FWZ71qrigxnSbyqtFWWYBu35gJ+ixjQfGFKsv12lv1trt3bfW3aq9bqi4UFxiz + 9AReOPOH4H8IMCc1N7+wrNJsuVZjra211lyzmCvLCvNzYd4oedcO/SPYgJB6GBByzpiK + yyurzBYIc1VlebHpTA4iSCXt8qm/BBsR1Brd8WxjvqmotLwCory0yJRvzD6u06gpJliH + IIfJyUe1GYZTxrPnzhdCnD931njKkKE9CtOH5WRdRPc/C9A91wojTNBWHkzT6DIN2bnG + PAhjbrYhU6dJO6hkRnET9DrC9gjWISQkp6jUaRqtPvOEISvLcCJTr9WkqVUpyQlrI9lx + fXF9u097/f1/ZAJM0U5UKJFCulZ37JhOm44ElIpEmEBN0qtJ65+ef999R4BR4vHypANK + 1SH1kTSII+pDKuWBJHk8zF6meCF4kFYRBCKJNE4mT1KkKFNVEKnKFEWSXBYnhYn0eL/L + xL/f9eb38iBECURipJCQmKRgIikxAQmIRWgMOcZvtNn8yfl76yoCXyiKlkhj42SyBAiZ + LC5WKomGdRAKBN93Bx4fFMQSSYw0FkIaI4EcEPL5vBDIApQtkAkwJTGSF8UXCEUicTSE + WCQSCvhRvEgYw47vO878TXV/7scgRDAKfL5AIBQKBHw+IwClIDQIUCrsg1SAsS/gwIuC + 4EEGwCoAAW/Ddv1xJfA+KBUYhggEERkR4QEImSTw/Mr2ehgYCeQBAX9F4K9zlw8ZnrRH + gvlil/9Z+J+HBcICYYGwQFggLBAWCAsEVuA/SCo8XAplbmRzdHJlYW0KZW5kb2JqCjQy + IDAgb2JqCjM3MTEKZW5kb2JqCjQ3IDAgb2JqCjw8IC9MZW5ndGggNDggMCBSIC9UeXBl + IC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMzAwIC9IZWlnaHQgMjI4IC9D + b2xvclNwYWNlCi9EZXZpY2VHcmF5IC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAv + RmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7dn9T5P31wdwpKUPUPpAn0YppQ9YSi1CgVAe + YhE7UbAOiWgbJaSmzlRTZXMQCGMwNIipY+AIQQgDMYgBQtAQJETI/rX7XKBzB8rZ/b3v + 70/tOT9sO3tHk88r53yuq21GBhcLsAALsAALsEASgVNpWUkgqP8FRplfS5Qm9fXEmQBA + +XzJPjuJRGKxOCsNC44tEgls/+p1OFAiQUkikUplhyVPg/p8VKlUIoHDiz9zfZmgJP8W + Vk+AkghK8uwcKIVCkZsWBQcVzpsth6NLweuA68RVFIbqsxQ4KXKVSpVKrUmjUqtUSmWu + QvD6onXSxXVIBTMFUEqlWpOn1el0eoPBmBZlMOjhuNo8jVqpBC5BSxit5JP1mUomBym1 + RqvTG435JlNBgdlcmAZlNhcUmEz5RqNepwUuRY5cdjLWIZUwVEqVBqDyTeZCi9Vqs9sd + aVF2u81qtRSawUuv06iUwmidNFmnhLsKqGCotHqjyWyx2h2nnSWu0lK3230mxQuOWFrq + KnGedtitFrPJqNfCaH3GSrKFcK9nSQQqjc5gMhfZip0ut6fsbHmF11uZBuX1VpSfLfO4 + Xc5iW5HZZNBpBCxJFlxZx14YYKy+UBlNhbbiEren3FtVXeOrrasXqiGF6+CAdbW+muoq + b7nHXVJsKzQZv2IdG6xTmbCB8hyYKqPJ4nC6y7xVNbX15/znmy4EAt+mfAUCF5rO+8/V + 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 + FeIgG7YieVDIVoiDbNiK5EEhWyEOsmErkgeFbIU4yIatSB4UshXiIBu2InlQyFaIg2zY + iuRBIVshDrJhK5IHhf+ZlUyhMZgdbm994Go4+qh/JPHy1eLbtc2tj7t7e/vo703BZn9v + b/fj1uba28VXLxMj/Y+i4auBeq/bYTZoFLIs0amMf1Zm1slWn9LB6hNhlflPqYyMf7Ha + T+nJ2t/f3/tvWsHfl8r1f7UKhqIP+4afT8wsLK9ufNje2f20l/L1aXdn+8PG6vLCzMTz + 4b6H0VDwH/dV0h0ssJd66y4Eb96J9w6N/T49/+bd+uYWYKVB7Wxvba6/ezM//fvYUG/8 + zs3ghTpvqb3g4G5PYqXWg1VFbVPrjciDnwZHf5uaW4TBer+1/XEn5evj9tZ7GKvFuanf + Rgd/ehC50dpUWwFWejU8B49b5aj1Jpur3He+5XpX7PHAk8TkzJ9LK2sbmx+20qA+bG6s + rSz9OTOZeDLwONZ1veW8r9xlM+nVOUmtVDqTteRsjf9Se+e97r7hsfGp2YU3K6vrG5vv + U742N9ZXV94szE6Njw33dd/rbL/krzlbYjXpVCdZ5Rc5PdXnmttuReM9g08TE9NzC0vL + 71bX1lO+1lbfLS8tzE1PJJ4O9sSjt9qaz1V7nEX5Sa3Eshyl9hvL6TNV9YFgKBL7oX9o + 9MXk9Oz866XltyspX2+Xl17Pz05Pvhgd6v8hFhEeg1VnTlu+0SpzZOKj95VYmq3MMxY6 + Sr21cGF13o33DIw8ezExNTM3v7D4OuVrcWF+bmZq4sWzkYGe+N1OuK5qvaWOQmOeMlua + zCoXPhDaXeU1/uZr4Uisu/fnkWeJ8cmp6ZlXsylfr2ampybHE89Gfu7tjkXC15r9NeUu + O3wczE1iJZLIczV6k9XpEZaw43b0PmANPx1LjE9Mvvwj5evl5MR4YuzpMFDdj97uEFbQ + 47Sa9JpcuUR0dAdFElmOWpdvgW8afI2X20JdgNXTPzj8ZHTseSIN6vnY6JPhwf4eoOoK + tV1u9MG3DJZ8HbwyJLHKgss9z2i2lZRVNwRa28Nd0Vj8x97+gV+Gfh1Jg/p16JeB/t4f + 47FoV7i9NdBQXVZiM8N1Ba8MR+fqVGYWXO6whEXF7gqf/+KV9tDtyPf3492Pe3r7+tOg + +np7HnfH738fuR1qv3LR76twFxfBCsLVnpWJv77KACuJXKHSwWA5PZV1jRdb2zrCnZHo + vdiD+MNH3Slfjx7GH8TuRSOd4Y621ouNdZUeJ4yVTqWQS5JYiYUl1OjzCx2usqo6f+By + 8FpH6FZnV+RONHo35SsavRPp6rwV6rgWvBzw11WVuRyF+TBWsILi43MlypLCYGkNJgtg + VfoaGgPNLcG29us3bobCaVChmzeut7cFW5oDjQ2+SqCymAxaGCspXFdHdjAjM1MMT8Jc + tc5oKnK4PBXVvgZ/U6D5UsuVYPDqdylfV4PBKy2XmgNN/gZfdYXH5SgyGXXqXHgKijOP + vDJkwIUlhsGCLQQsi8PpLvNW1dTWn/Ofb7oQCHyb8hUIXGg67z9XX1tT5S1zO2GqjDrY + QBirYysoWImyJLJsxQFWoa24xO0p91ZV1/hq6+qFakjhOjhgXa2vprrKW+5xlxTbCg+o + FNkySZIVhF8nvmIZTOYiW7HT5faUnS2v8Hor06C83orys2Uet8tZbCsymwwwVZ+pjq3g + wWDBFgqTpdbqjSazxWp3nHaWuEpL3W73mRQvOGJpqavEedpht1rMJqNeqxaoYAOP3+zw + A9gpGKwDrBylSqPTG/NN5kKL1Wqz2x1pUXa7zWq1FJpN+Ua9TqNS5nymOvYUFH4sPMSS + yOQ5MFoaLXCBl6mgwGwuTIMymwsKTOAEUFoNDFWOHO4qmKqkVH9jwR6CFnDlaXU6nd5g + MKZFGQx6OK42D6BACoaKoso4dThZWRKpTA5cuUqlSqXWpFGpVSqlMheg5ILU4VQdfQ/9 + ++d6wBIuLUFLJnhBKRSK3LQoOKhwXnCS/S11wgIeegmjdciVJZFIBTGh5GlQhyeVSaUS + mKiDkYKr6sSh+qJ1yCUSi2HA0q/g2CK40QWof5FCXsKfgBKlSR2e9uCf/0unv+8ueC6m + Zf0DgP+TBViABViABVjgq8D/AOqBT24KZW5kc3RyZWFtCmVuZG9iago0OCAwIG9iagoz + ODc3CmVuZG9iago3NiAwIG9iago8PCAvTGVuZ3RoIDc3IDAgUiAvTiAzIC9BbHRlcm5h + dGUgL0RldmljZVJHQiAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAGtk89r + 02Acxp+0Q4fOCXPzIAg5OPBQpbQFfyDYtetGN+lK263VW5ukTbVJQ5JWWzz0HxC8CepB + 8bLD9Kx4UQTx4kEmongV8eJlhzEYIz5JTOvB4cVvefN++uR5v++b7/u+QHinahitEABN + t83CYkqsXL0mHvyCCRziL4GZqmQZc/n8FVr2ie1PENxXm2fcXPeNXZy7u5nYftT7funp + xcP7DArkSZMTAkKEwnTD56TLNZ9LLt+0DZse1WVJrcrk2+SIWSqkyevkyYbPz12u+fzO + 5a7UcMd+Jkd1uakDoXHyeVmxJHKSrMqWpJGZRwhpWpv5wxvUT0uGybHhj+RTbl3YM3pH + gcv36H890ipvgY1nwPGfI22W3mNfgRfdkba149VKOPnNqsdjXjrhyGPgQN9xtmaAcc69 + t+Y4uynH2ePcY0zy8o7UMbuelwsU3gP/+u9/s58d+MA8DG+P/s5+XTxXFHgyANZeAUsU + HrLN8lunHgArSaA4QCgeD5pfQ1pY56KkGLapiJVYorzoSf/vobU63Csvpvic0Gu5FfYn + 2H4Ydr4UsNUtZgKuNxeyAcvV+eWA+2o6F3DdXCgEfL26lA9Y0VeLARst7+z/nis19CtW + Zujpq6Vy4Dc7hdWAb7SXh35ZmR+uTW/l3Pvk5Wza2eH6UYQEBQZsmOxFVBDjHSyDBfXP + JUchN83jOEbIvFnXBq7yZ9jKLW+/022jZzYbqi3O8VYqETGrS2cjYiwavYBfakqyNwpl + bmRzdHJlYW0KZW5kb2JqCjc3IDAgb2JqCjU2NQplbmRvYmoKNDMgMCBvYmoKWyAvSUND + QmFzZWQgNzYgMCBSIF0KZW5kb2JqCjc4IDAgb2JqCjw8IC9MZW5ndGggNzkgMCBSIC9O + IDMgL0FsdGVybmF0ZSAvRGV2aWNlUkdCIC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0 + cmVhbQp4Aa2Tz2vTYBzGn7RDh84Jc/MgCDk48FCltAV/INi160Y36UrbrdVbm6RNtUlD + klZbPPQfELwJ6kHxssP0rHhRBPHiQSaieBXx4mWHMRgjPklM68HhxW9583765Hm/75vv + +75AeKdqGK0QAE23zcJiSqxcvSYe/IIJHOIvgZmqZBlz+fwVWvaJ7U8Q3FebZ9xc941d + nLu7mdh+1Pt+6enFw/sMCuRJkxMCQoTCdMPnpMs1n0su37QNmx7VZUmtyuTb5IhZKqTJ + 6+TJhs/PXa75/M7lrtRwx34mR3W5qQOhcfJ5WbEkcpKsypakkZlHCGlam/nDG9RPS4bJ + seGP5FNuXdgzekeBy/fofz3SKm+BjWfA8Z8jbZbeY1+BF92RtrXj1Uo4+c2qx2NeOuHI + Y+BA33G2ZoBxzr235ji7KcfZ49xjTPLyjtQxu56XCxTeA//673+znx34wDwMb4/+zn5d + PFcUeDIA1l4BSxQess3yW6ceACtJoDhAKB4Pml9DWljnoqQYtqmIlViivOhJ/++htTrc + Ky+m+JzQa7kV9ifYfhh2vhSw1S1mAq43F7IBy9X55YD7ajoXcN1cKAR8vbqUD1jRV4sB + Gy3v7P+eKzX0K1Zm6OmrpXLgNzuF1YBvtJeHflmZH65Nb+Xc++TlbNrZ4fpRhAQFBmyY + 7EVUEOMdLIMF9c8lRyE3zeM4Rsi8WdcGrvJn2Motb7/TbaNnNhuqLc7xVioRMatLZyNi + LBq9gF9qSrI3CmVuZHN0cmVhbQplbmRvYmoKNzkgMCBvYmoKNTY1CmVuZG9iago1OSAw + IG9iagpbIC9JQ0NCYXNlZCA3OCAwIFIgXQplbmRvYmoKODAgMCBvYmoKPDwgL0xlbmd0 + aCA4MSAwIFIgL04gMyAvQWx0ZXJuYXRlIC9EZXZpY2VSR0IgL0ZpbHRlciAvRmxhdGVE + ZWNvZGUgPj4Kc3RyZWFtCngBrZPPa9NgHMaftEOHzglz8yAIOTjwUKW0BX8g2LXrRjfp + Stut1VubpE21SUOSVls89B8QvAnqQfGyw/SseFEE8eJBJqJ4FfHiZYcxGCM+SUzrweHF + b3nzfvrkeb/vm+/7vkB4p2oYrRAATbfNwmJKrFy9Jh78ggkc4i+BmapkGXP5/BVa9ont + TxDcV5tn3Fz3jV2cu7uZ2H7U+37p6cXD+wwK5EmTEwJChMJ0w+ekyzWfSy7ftA2bHtVl + Sa3K5NvkiFkqpMnr5MmGz89drvn8zuWu1HDHfiZHdbmpA6Fx8nlZsSRykqzKlqSRmUcI + aVqb+cMb1E9Lhsmx4Y/kU25d2DN6R4HL9+h/PdIqb4GNZ8DxnyNtlt5jX4EX3ZG2tePV + Sjj5zarHY1464chj4EDfcbZmgHHOvbfmOLspx9nj3GNM8vKO1DG7npcLFN4D//rvf7Of + HfjAPAxvj/7Ofl08VxR4MgDWXgFLFB6yzfJbpx4AK0mgOEAoHg+aX0NaWOeipBi2qYiV + WKK86En/76G1OtwrL6b4nNBruRX2J9h+GHa+FLDVLWYCrjcXsgHL1fnlgPtqOhdw3Vwo + BHy9upQPWNFXiwEbLe/s/54rNfQrVmbo6aulcuA3O4XVgG+0l4d+WZkfrk1v5dz75OVs + 2tnh+lGEBAUGbJjsRVQQ4x0sgwX1zyVHITfN4zhGyLxZ1wau8mfYyi1vv9Nto2c2G6ot + zvFWKhExq0tnI2IsGr2AX2pKsjcKZW5kc3RyZWFtCmVuZG9iago4MSAwIG9iago1NjUK + ZW5kb2JqCjU0IDAgb2JqClsgL0lDQ0Jhc2VkIDgwIDAgUiBdCmVuZG9iago4MiAwIG9i + ago8PCAvTGVuZ3RoIDgzIDAgUiAvTiAzIC9BbHRlcm5hdGUgL0RldmljZVJHQiAvRmls + dGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAGtk89r02Acxp+0Q4fOCXPzIAg5OPBQ + pbQFfyDYtetGN+lK263VW5ukTbVJQ5JWWzz0HxC8CepB8bLD9Kx4UQTx4kEmongV8eJl + hzEYIz5JTOvB4cVvefN++uR5v++b7/u+QHinahitEABNt83CYkqsXL0mHvyCCRziL4GZ + qmQZc/n8FVr2ie1PENxXm2fcXPeNXZy7u5nYftT7funpxcP7DArkSZMTAkKEwnTD56TL + NZ9LLt+0DZse1WVJrcrk2+SIWSqkyevkyYbPz12u+fzO5a7UcMd+Jkd1uakDoXHyeVmx + JHKSrMqWpJGZRwhpWpv5wxvUT0uGybHhj+RTbl3YM3pHgcv36H890ipvgY1nwPGfI22W + 3mNfgRfdkba149VKOPnNqsdjXjrhyGPgQN9xtmaAcc69t+Y4uynH2ePcY0zy8o7UMbue + lwsU3gP/+u9/s58d+MA8DG+P/s5+XTxXFHgyANZeAUsUHrLN8lunHgArSaA4QCgeD5pf + Q1pY56KkGLapiJVYorzoSf/vobU63Csvpvic0Gu5FfYn2H4Ydr4UsNUtZgKuNxeyAcvV + +eWA+2o6F3DdXCgEfL26lA9Y0VeLARst7+z/nis19CtWZujpq6Vy4Dc7hdWAb7SXh35Z + mR+uTW/l3Pvk5Wza2eH6UYQEBQZsmOxFVBDjHSyDBfXPJUchN83jOEbIvFnXBq7yZ9jK + LW+/022jZzYbqi3O8VYqETGrS2cjYiwavYBfakqyNwplbmRzdHJlYW0KZW5kb2JqCjgz + IDAgb2JqCjU2NQplbmRvYmoKNjIgMCBvYmoKWyAvSUNDQmFzZWQgODIgMCBSIF0KZW5k + b2JqCjg0IDAgb2JqCjw8IC9MZW5ndGggODUgMCBSIC9OIDMgL0FsdGVybmF0ZSAvRGV2 + aWNlUkdCIC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Aa2Tz2vTYBzGn7RD + h84Jc/MgCDk48FCltAV/INi160Y36UrbrdVbm6RNtUlDklZbPPQfELwJ6kHxssP0rHhR + BPHiQSaieBXx4mWHMRgjPklM68HhxW9583765Hm/75vv+75AeKdqGK0QAE23zcJiSqxc + vSYe/IIJHOIvgZmqZBlz+fwVWvaJ7U8Q3FebZ9xc941dnLu7mdh+1Pt+6enFw/sMCuRJ + kxMCQoTCdMPnpMs1n0su37QNmx7VZUmtyuTb5IhZKqTJ6+TJhs/PXa75/M7lrtRwx34m + R3W5qQOhcfJ5WbEkcpKsypakkZlHCGlam/nDG9RPS4bJseGP5FNuXdgzekeBy/fofz3S + Km+BjWfA8Z8jbZbeY1+BF92RtrXj1Uo4+c2qx2NeOuHIY+BA33G2ZoBxzr235ji7KcfZ + 49xjTPLyjtQxu56XCxTeA//673+znx34wDwMb4/+zn5dPFcUeDIA1l4BSxQess3yW6ce + ACtJoDhAKB4Pml9DWljnoqQYtqmIlViivOhJ/++htTrcKy+m+JzQa7kV9ifYfhh2vhSw + 1S1mAq43F7IBy9X55YD7ajoXcN1cKAR8vbqUD1jRV4sBGy3v7P+eKzX0K1Zm6OmrpXLg + NzuF1YBvtJeHflmZH65Nb+Xc++TlbNrZ4fpRhAQFBmyY7EVUEOMdLIMF9c8lRyE3zeM4 + Rsi8WdcGrvJn2Motb7/TbaNnNhuqLc7xVioRMatLZyNiLBq9gF9qSrI3CmVuZHN0cmVh + bQplbmRvYmoKODUgMCBvYmoKNTY1CmVuZG9iago0NiAwIG9iagpbIC9JQ0NCYXNlZCA4 + NCAwIFIgXQplbmRvYmoKODYgMCBvYmoKPDwgL0xlbmd0aCA4NyAwIFIgL04gMyAvQWx0 + ZXJuYXRlIC9EZXZpY2VSR0IgL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB + rZPPa9NgHMaftEOHzglz8yAIOTjwUKW0BX8g2LXrRjfpStut1VubpE21SUOSVls89B8Q + vAnqQfGyw/SseFEE8eJBJqJ4FfHiZYcxGCM+SUzrweHFb3nzfvrkeb/vm+/7vkB4p2oY + rRAATbfNwmJKrFy9Jh78ggkc4i+BmapkGXP5/BVa9ontTxDcV5tn3Fz3jV2cu7uZ2H7U + +37p6cXD+wwK5EmTEwJChMJ0w+ekyzWfSy7ftA2bHtVlSa3K5NvkiFkqpMnr5MmGz89d + rvn8zuWu1HDHfiZHdbmpA6Fx8nlZsSRykqzKlqSRmUcIaVqb+cMb1E9Lhsmx4Y/kU25d + 2DN6R4HL9+h/PdIqb4GNZ8DxnyNtlt5jX4EX3ZG2tePVSjj5zarHY1464chj4EDfcbZm + gHHOvbfmOLspx9nj3GNM8vKO1DG7npcLFN4D//rvf7OfHfjAPAxvj/7Ofl08VxR4MgDW + XgFLFB6yzfJbpx4AK0mgOEAoHg+aX0NaWOeipBi2qYiVWKK86En/76G1OtwrL6b4nNBr + uRX2J9h+GHa+FLDVLWYCrjcXsgHL1fnlgPtqOhdw3VwoBHy9upQPWNFXiwEbLe/s/54r + NfQrVmbo6aulcuA3O4XVgG+0l4d+WZkfrk1v5dz75OVs2tnh+lGEBAUGbJjsRVQQ4x0s + gwX1zyVHITfN4zhGyLxZ1wau8mfYyi1vv9Nto2c2G6otzvFWKhExq0tnI2IsGr2AX2pK + sjcKZW5kc3RyZWFtCmVuZG9iago4NyAwIG9iago1NjUKZW5kb2JqCjQ5IDAgb2JqClsg + L0lDQ0Jhc2VkIDg2IDAgUiBdCmVuZG9iago4OCAwIG9iago8PCAvTGVuZ3RoIDg5IDAg + UiAvTiAzIC9BbHRlcm5hdGUgL0RldmljZVJHQiAvRmlsdGVyIC9GbGF0ZURlY29kZSA+ + PgpzdHJlYW0KeAGFlE1IFGEYx/+zjQSxBtGXCMXQwSRUJgtSAtP1K1O2ZdVMCWKdfXed + HGenmd0tRSKE6Jh1jC5WRIeITuGhQ6c6RASZdYmgo0UQBV4itv87k7tjVL4wM795nv/7 + fL3DAFWPUo5jRTRgys67yd6Ydnp0TNv8GlWoRhRcKcNzOhKJAZ+plc/1a/UtFGlZapSx + 1vs2fKt2mRBQNCp3ZAM+LHk84OOSL+SdPDVnJBsTqTTZITe4Q8lO8i3y1myIx0OcFp4B + VLVTkzMcl3EiO8gtRSMrYz4g63batMnvpT3tGVPUsN/INzkL2rjy/UDbHmDTi4ptzAMe + 3AN211Vs9TXAzhFg8VDF9j3pz0fZ9crLHGr2wynRGGv6UCp9rwM23wB+Xi+VftwulX7e + YQ7W8dQyCm7R17Iw5SUQ1BvsZvzkGv2Lg558VQuwwDmObAH6rwA3PwL7HwLbHwOJamCo + FZHLbDe48uIi5wJ05pxp18xO5LVmXT+idfBohdZnG00NWsqyNN/laa7whFsU6SZMWQXO + 2V/beI8Ke3iQT/YXuSS87t+szKVTXZwlmtjWp7To6iY3kO9nzJ4+cj2v9xm3Zzhg5YCZ + 7xsKOHLKtuI8F6mJ1Njj8ZNkxldUJx+T85A85xUHZUzffi51IkGupT05meuXml3c2z4z + McQzkqxYMxOd8d/8xi0kZd591Nx1LP+bZ22RZxiFBQETNu82NCTRixga4cBFDhl6TCpM + WqVf0GrCw+RflRYS5V0WFb1Y4Z4Vf895FLhbxj+FWBxzDeUImv5O/6Iv6wv6Xf3zfG2h + vuKZc8+axqtrXxlXZpbVyLhBjTK+rCmIb7DaDnotZGmd4hX05JX1jeHqMvZ8bdmjyRzi + anw11KUIZWrEOOPJrmX3RbLFN+HnW8v2r+lR+3z2SU0l17K6eGYp+nw2XA1r/7OrYNKy + q/DkjZAuPGuh7lUPqn1qi9oKTT2mtqttahffjqoD5R3DnJWJC6zbZfUp9mBjmt7KSVdm + i+Dfwi+G/6VeYQvXNDT5D024uYxpCd8R3DZwh5T/w1+zAw3eCmVuZHN0cmVhbQplbmRv + YmoKODkgMCBvYmoKNzkyCmVuZG9iago4IDAgb2JqClsgL0lDQ0Jhc2VkIDg4IDAgUiBd + CmVuZG9iago5MCAwIG9iago8PCAvTGVuZ3RoIDkxIDAgUiAvTiAzIC9BbHRlcm5hdGUg + L0RldmljZVJHQiAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAGtk89r02Ac + xp+0Q4fOCXPzIAg5OPBQpbQFfyDYtetGN+lK263VW5ukTbVJQ5JWWzz0HxC8CepB8bLD + 9Kx4UQTx4kEmongV8eJlhzEYIz5JTOvB4cVvefN++uR5v++b7/u+QHinahitEABNt83C + YkqsXL0mHvyCCRziL4GZqmQZc/n8FVr2ie1PENxXm2fcXPeNXZy7u5nYftT7funpxcP7 + DArkSZMTAkKEwnTD56TLNZ9LLt+0DZse1WVJrcrk2+SIWSqkyevkyYbPz12u+fzO5a7U + cMd+Jkd1uakDoXHyeVmxJHKSrMqWpJGZRwhpWpv5wxvUT0uGybHhj+RTbl3YM3pHgcv3 + 6H890ipvgY1nwPGfI22W3mNfgRfdkba149VKOPnNqsdjXjrhyGPgQN9xtmaAcc69t+Y4 + uynH2ePcY0zy8o7UMbuelwsU3gP/+u9/s58d+MA8DG+P/s5+XTxXFHgyANZeAUsUHrLN + 8lunHgArSaA4QCgeD5pfQ1pY56KkGLapiJVYorzoSf/vobU63Csvpvic0Gu5FfYn2H4Y + dr4UsNUtZgKuNxeyAcvV+eWA+2o6F3DdXCgEfL26lA9Y0VeLARst7+z/nis19CtWZujp + q6Vy4Dc7hdWAb7SXh35ZmR+uTW/l3Pvk5Wza2eH6UYQEBQZsmOxFVBDjHSyDBfXPJUch + N83jOEbIvFnXBq7yZ9jKLW+/022jZzYbqi3O8VYqETGrS2cjYiwavYBfakqyNwplbmRz + dHJlYW0KZW5kb2JqCjkxIDAgb2JqCjU2NQplbmRvYmoKNjkgMCBvYmoKWyAvSUNDQmFz + ZWQgOTAgMCBSIF0KZW5kb2JqCjkyIDAgb2JqCjw8IC9MZW5ndGggOTMgMCBSIC9OIDMg + L0FsdGVybmF0ZSAvRGV2aWNlUkdCIC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVh + bQp4Aa2Tz2vTYBzGn7RDh84Jc/MgCDk48FCltAV/INi160Y36UrbrdVbm6RNtUlDklZb + PPQfELwJ6kHxssP0rHhRBPHiQSaieBXx4mWHMRgjPklM68HhxW9583765Hm/75vv+75A + eKdqGK0QAE23zcJiSqxcvSYe/IIJHOIvgZmqZBlz+fwVWvaJ7U8Q3FebZ9xc941dnLu7 + mdh+1Pt+6enFw/sMCuRJkxMCQoTCdMPnpMs1n0su37QNmx7VZUmtyuTb5IhZKqTJ6+TJ + hs/PXa75/M7lrtRwx34mR3W5qQOhcfJ5WbEkcpKsypakkZlHCGlam/nDG9RPS4bJseGP + 5FNuXdgzekeBy/fofz3SKm+BjWfA8Z8jbZbeY1+BF92RtrXj1Uo4+c2qx2NeOuHIY+BA + 33G2ZoBxzr235ji7KcfZ49xjTPLyjtQxu56XCxTeA//673+znx34wDwMb4/+zn5dPFcU + eDIA1l4BSxQess3yW6ceACtJoDhAKB4Pml9DWljnoqQYtqmIlViivOhJ/++htTrcKy+m + +JzQa7kV9ifYfhh2vhSw1S1mAq43F7IBy9X55YD7ajoXcN1cKAR8vbqUD1jRV4sBGy3v + 7P+eKzX0K1Zm6OmrpXLgNzuF1YBvtJeHflmZH65Nb+Xc++TlbNrZ4fpRhAQFBmyY7EVU + EOMdLIMF9c8lRyE3zeM4Rsi8WdcGrvJn2Motb7/TbaNnNhuqLc7xVioRMatLZyNiLBq9 + gF9qSrI3CmVuZHN0cmVhbQplbmRvYmoKOTMgMCBvYmoKNTY1CmVuZG9iago0MCAwIG9i + agpbIC9JQ0NCYXNlZCA5MiAwIFIgXQplbmRvYmoKOTQgMCBvYmoKPDwgL0xlbmd0aCA5 + NSAwIFIgL04gMSAvQWx0ZXJuYXRlIC9EZXZpY2VHcmF5IC9GaWx0ZXIgL0ZsYXRlRGVj + b2RlID4+CnN0cmVhbQp4AYVST0gUURz+zTYShIhBhXiIdwoJlSmsrKDadnVZlW1bldKi + GGffuqOzM9Ob2TXFkwRdojx1D6JjdOzQoZuXosCsS9cgqSAIPHXo+83s6iiEb3k73/v9 + /X7fe0RtnabvOylBVHNDlSulp25OTYuDHylFHdROWKYV+OlicYyx67mSv7vX1mfS2LLe + x7V2+/Y9tZVlYCHqLba3EPohkWYAH5mfKGWAs8Adlq/YPgE8WA6sGvAjogMPmrkw09Gc + dKWyLZFT5qIoKq9iO0mu+/m5xr6LtYmD/lyPZtaOvbPqqtFM1LT3RKG8D65EGc9fVPZs + NRSnDeOcSEMaKfKu1d8rTMcRkSsQSgZSNWS5n2pOnXXgdRi7XbqT4/j2EKU+yWCoibXp + spkdhX0AdirL7BDwBejxsmIP54F7Yf9bUcOTwCdhP2SHedatH/YXrlPge4Q9NeDOFK7F + 8dqKH14tAUP3VCNojHNNxNPXOXOkiO8x1BmY90Y5pgsxd5aqEzeAO2EfWapmCrFd+67q + Je57AnfT4zvRmzkLXKAcSXKxFdkU0DwJWBR9i7BJDjw+zh5V4HeomMAcuYnczSj3HtUR + G2ejUoFWeo1Xxk/jufHF+GVsGM+Afqx213t8/+njFXXXtj48+Y163DmuvZ0bVWFWcWUL + 3f/HMoSP2Sc5psHToVlYa9h25A+azEywDCjEfwU+l/qSE1Xc1e7tuEUSzFA+LGwluktU + binU6j2DSqwcK9gAdnCSxCxaHLhTa7o5eHfYInpt+U1XsuuG/vr2evva8h5tyqgpKBPN + s0RmlLFbo+TdeNv9ZpERnzg6vue9ilrJ/klFED+FOVoq8hRV9FZQ1sRvZw5+G7Z+XD+l + 5/VB/TwJPa2f0a/ooxG+DHRJz8JzUR+jSfCwaSHiEqCKgzPUTlRjjQPiKfHytFtkkf0P + QBn9ZgplbmRzdHJlYW0KZW5kb2JqCjk1IDAgb2JqCjcwNAplbmRvYmoKMzcgMCBvYmoK + WyAvSUNDQmFzZWQgOTQgMCBSIF0KZW5kb2JqCjQgMCBvYmoKPDwgL1R5cGUgL1BhZ2Vz + IC9NZWRpYUJveCBbMCAwIDYxMiA3OTJdIC9Db3VudCAxIC9LaWRzIFsgMyAwIFIgXSA+ + PgplbmRvYmoKOTYgMCBvYmoKPDwgL1R5cGUgL0NhdGFsb2cgL091dGxpbmVzIDIgMCBS + IC9QYWdlcyA0IDAgUiAvVmVyc2lvbiAvMS40ID4+CmVuZG9iagoyIDAgb2JqCjw8IC9M + YXN0IDk3IDAgUiAvRmlyc3QgOTggMCBSID4+CmVuZG9iago5OCAwIG9iago8PCAvQ291 + bnQgMCAvRGVzdCBbIDMgMCBSIC9YWVogMCA3MzMgMCBdIC9UaXRsZSAoQ2FudmFzIDEp + ID4+CmVuZG9iago5NyAwIG9iago8PCAvQ291bnQgMCAvRGVzdCBbIDMgMCBSIC9YWVog + MCA3MzMgMCBdIC9UaXRsZSAoQ2FudmFzIDEpID4+CmVuZG9iago5OSAwIG9iago8PCAv + TGVuZ3RoIDEwMCAwIFIgL0xlbmd0aDEgMTU3MDQgL0ZpbHRlciAvRmxhdGVEZWNvZGUg + Pj4Kc3RyZWFtCngBvXt5YFXFufjMnPWeu+/7lpu7Zd8XEsglJIRdFoUEiYZ9UWQRA1jg + RWWNiAqyCIjgwhLUhBAlSLHUgoi1CiqoqLVWoHRJbfvQ10Luzfvm3IDQ9vXnH/31njtz + 5szMmeX7vvm2mYMwQkiFmhCDYpNnT5zbv+Tu+yDnXYSwYXLjAt9jv+23A9K/Qoi5d9rc + 6bP1v/rZOwhxwxCSVNPvXTxtd48V6mprEQq/PWPqxCn/fem+nQgV+6CNohmQIaUIULcY + ylHqjNkLFn3xoWkePC+B59P3zpk88cpff/cGQiVQB82aPXHRXHGL9Dd47oRn330TZ0+t + b1y8GJ4/geeUuXPuX8C1chfguRuem+fOnzr3x4/cl4tQ6WoY3/uQh+GiPxUkeTn1L6Nk + 5WQVghiWg3cEJCokhJTQhhppkFanNyBkRMhktiArstkdTtf3bbqRx+vzpwRSUTAUjkTT + UHpGZhbKzsnN+77O/7dU/g9omTuGdNxRFOGakIPNRl6Eej6FcJ7eE3f0XOJOIl1ids+f + mTJo7DANJFFRjo6hx9A21Ip4tBfSEXQX2oJO4VnoMJ6AOtA57EFZQDMs6kTD0Lu4p+cM + moZegPoL0JtoIzoAsIug2cgMpetwsOdBeI5BehJa3vMcSkUlaCU6ikqh1XWoq2dfz0Eo + HY3uQC1oP7z/cxwgB1hjzys9F5CIRkGby6HkTM+wnlZkQBmoEo2E3OXoDRxkzvfMQDZU + BqPbjp5Fu9BP0R/ww7ijZ0ZPY8/pnq8QgVIXGgPXUtyBv2Ja2ZU923t+15MASERQGvTa + gDag56H9VriOAflU43vwArwBbyQx8jDpYFdw1kQc4BBFNXANQnPQaoDAYXQc/QX9DX9D + bIyOWcCc6Cns+W+gmaEwSzqTqagRrlVwrYM5HcE8zsED8Ei8FD+FN+IPSRq5g9SShWQR + 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 + dEJCb3ggWzAgLTIyMSA3NjggNzM3XSAvRm9udE5hbWUgL1pCWE9FUCtIZWx2ZXRpY2Eg + L0l0YWxpY0FuZ2xlIDAgL1N0ZW1WCjAgL01heFdpZHRoIDE1MDAgL1hIZWlnaHQgNTEz + IC9Gb250RmlsZTIgOTkgMCBSID4+CmVuZG9iagoxMDIgMCBvYmoKWyAyNzggMCAwIDAg + MCAwIDAgMCAwIDAgMCAwIDI3OCAwIDI3OCAyNzggNTU2IDU1NiAwIDAgNTU2IDAgNTU2 + IDU1NiA1NTYgMAowIDI3OCAwIDU4NCAwIDU1NiAwIDY2NyAwIDcyMiA3MjIgNjY3IDYx + MSAwIDAgMjc4IDAgMCA1NTYgODMzIDcyMiAwIDY2NyAwCjcyMiA2NjcgNjExIDcyMiA2 + NjcgMCAwIDAgMCAwIDAgMCAwIDAgMCA1NTYgMCA1MDAgNTU2IDU1NiAyNzggNTU2IDU1 + NiAyMjIKMCA1MDAgMjIyIDgzMyA1NTYgNTU2IDU1NiAwIDMzMyA1MDAgMjc4IDU1NiAw + IDcyMiA1MDAgNTAwIDUwMCAwIDAgMCAwIDAgMAowIDAgMCAwIDAgMCAwIDAgMCAwIDAg + MCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAw + CjAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAg + MCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAKMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAw + IDAgMCAwIDAgMCA1MDAgXQplbmRvYmoKMzggMCBvYmoKPDwgL1R5cGUgL0ZvbnQgL1N1 + YnR5cGUgL1RydWVUeXBlIC9CYXNlRm9udCAvWkJYT0VQK0hlbHZldGljYSAvRm9udERl + c2NyaXB0b3IKMTAxIDAgUiAvV2lkdGhzIDEwMiAwIFIgL0ZpcnN0Q2hhciAzMiAvTGFz + dENoYXIgMjIyIC9FbmNvZGluZyAvTWFjUm9tYW5FbmNvZGluZwo+PgplbmRvYmoKMTAz + IDAgb2JqCjw8IC9MZW5ndGggMTA0IDAgUiAvTGVuZ3RoMSA4Njg0IC9GaWx0ZXIgL0Zs + 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 + pVjbU66bbL8ty7Q9UlZhG8ugvDHb6EwSB2x7ym6yPbBZyflFliLudwVwZMx2nywO2HZT + /3dtUgrujDTcGBGDm5WBrtuviOX7A8yDB2wDrnTbQmqIktbW7Vpm63K5bW0zA5g2ZvPK + zQ7YGjOO2RrkocdsUmSg0kjvJS4FcVFk2BzXIduUyAipcm0p3mZ3Ndqs1H/OfXfZclzX + 2GZmBXDvo/VTslz1GXeVBvCcMoYsCKgslkdEb8bj+EvSZyYuoGv73fvrMwkz7hizbSIx + sr9+SllagD0txdn2Z9RnbKZQSiGNwvwAtkk54k5xkThfnCpmi5liuugQU8QkMUEVp9Kp + YlRRKo1KpaLlrmJUoEoIhP8qZcs2mSDoZCGQwdMbECWuIxtExRDJXOlFAgNzICDAzYmr + qkxVcTP07tqab/jrUTJ7arK/+pHjnvyZ0Oq/i16G+/dZO/1FciRs7Zws/f9F+qqpfUPL + mv0ta860K99TnJ6+Hvqs4t+2ij57bVhot4+eWSMXyG/2exb29svS1+df4+yr8Z9x1thH + W5R2Xytul4tbnDWj0O5p6xhtl/pqxlqkFvl7Sef+Zk89bUc0yMWxtk6OVe/5hrE8cmf1 + 8ljNSruvjdUkFzfLYzXJYzXJYzVLzcpY2dmeJa3V8L9upOJhCmVuZHN0cmVhbQplbmRv + YmoKMTA0IDAgb2JqCjU2NzcKZW5kb2JqCjEwNSAwIG9iago8PCAvVHlwZSAvRm9udERl + c2NyaXB0b3IgL0FzY2VudCA3NzAgL0NhcEhlaWdodCA2ODQgL0Rlc2NlbnQgLTIzMCAv + RmxhZ3MgMzIKL0ZvbnRCQm94IFsxMCAtMjA5IDY1NSA3MzRdIC9Gb250TmFtZSAvQk5G + UEVKK0hlbHZldGljYS1Cb2xkIC9JdGFsaWNBbmdsZQowIC9TdGVtViAwIC9NYXhXaWR0 + aCAxNTAwIC9YSGVpZ2h0IDUxMyAvRm9udEZpbGUyIDEwMyAwIFIgPj4KZW5kb2JqCjEw + NiAwIG9iagpbIDI3OCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAw + IDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwCjAgMCAwIDAgMCA3MjIgMjc4IDAg + MCA2MTEgMCAwIDAgNjY3IDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgNTU2 + IDAKNTU2IDYxMSA1NTYgMCAwIDAgMjc4IDAgNTU2IDI3OCAwIDYxMSA2MTEgNjExIDAg + Mzg5IDU1NiAzMzMgNjExIDAgMCAwIDAgNTAwCl0KZW5kb2JqCjM5IDAgb2JqCjw8IC9U + eXBlIC9Gb250IC9TdWJ0eXBlIC9UcnVlVHlwZSAvQmFzZUZvbnQgL0JORlBFSitIZWx2 + ZXRpY2EtQm9sZCAvRm9udERlc2NyaXB0b3IKMTA1IDAgUiAvV2lkdGhzIDEwNiAwIFIg + L0ZpcnN0Q2hhciAzMiAvTGFzdENoYXIgMTIyIC9FbmNvZGluZyAvTWFjUm9tYW5FbmNv + ZGluZwo+PgplbmRvYmoKMSAwIG9iago8PCAvVGl0bGUgKFVudGl0bGVkKSAvQXV0aG9y + IChicmFuZG9uaCkgL0NyZWF0b3IgKE9tbmlHcmFmZmxlIFByb2Zlc3Npb25hbCkKL1By + b2R1Y2VyIChNYWMgT1MgWCAxMC41LjggUXVhcnR6IFBERkNvbnRleHQpIC9DcmVhdGlv + bkRhdGUgKEQ6MjAwOTEyMTYyMjQyMDlaMDAnMDAnKQovTW9kRGF0ZSAoRDoyMDA5MTIx + NjIyNDIwOVowMCcwMCcpID4+CmVuZG9iagp4cmVmCjAgMTA3CjAwMDAwMDAwMDAgNjU1 + MzUgZiAKMDAwMDA5NjU1OCAwMDAwMCBuIAowMDAwMDc3OTE1IDAwMDAwIG4gCjAwMDAw + MDM4NTEgMDAwMDAgbiAKMDAwMDA3Nzc1MiAwMDAwMCBuIAowMDAwMDAwMDIyIDAwMDAw + IG4gCjAwMDAwMDM4MzEgMDAwMDAgbiAKMDAwMDAwMzk1NiAwMDAwMCBuIAowMDAwMDc1 + NDAxIDAwMDAwIG4gCjAwMDAwMDczNDQgMDAwMDAgbiAKMDAwMDAwODE4OSAwMDAwMCBu + IAowMDAwMDEyNzk0IDAwMDAwIG4gCjAwMDAwMTM4ODUgMDAwMDAgbiAKMDAwMDAwNjIy + MyAwMDAwMCBuIAowMDAwMDA3MzI0IDAwMDAwIG4gCjAwMDAwMDgyMDkgMDAwMDAgbiAK + MDAwMDAwOTMwMCAwMDAwMCBuIAowMDAwMDEzOTA1IDAwMDAwIG4gCjAwMDAwMTQ5OTYg + MDAwMDAgbiAKMDAwMDAwNTQwMiAwMDAwMCBuIAowMDAwMDA2MjAzIDAwMDAwIG4gCjAw + MDAwMTYxMjcgMDAwMDAgbiAKMDAwMDAxNjg4NCAwMDAwMCBuIAowMDAwMDE2OTA0IDAw + MDAwIG4gCjAwMDAwMTc5OTUgMDAwMDAgbiAKMDAwMDAxMDA5NyAwMDAwMCBuIAowMDAw + MDExMTg4IDAwMDAwIG4gCjAwMDAwMDkzMjAgMDAwMDAgbiAKMDAwMDAxMDA3NyAwMDAw + MCBuIAowMDAwMDExMjA4IDAwMDAwIG4gCjAwMDAwMTE5NTMgMDAwMDAgbiAKMDAwMDAw + NDI5MSAwMDAwMCBuIAowMDAwMDA1MzgyIDAwMDAwIG4gCjAwMDAwMTUwMTYgMDAwMDAg + biAKMDAwMDAxNjEwNyAwMDAwMCBuIAowMDAwMDExOTczIDAwMDAwIG4gCjAwMDAwMTI3 + NzQgMDAwMDAgbiAKMDAwMDA3NzcxNSAwMDAwMCBuIAowMDAwMDg5OTM3IDAwMDAwIG4g + CjAwMDAwOTYzNzYgMDAwMDAgbiAKMDAwMDA3Njg1MCAwMDAwMCBuIAowMDAwMDYyMTU4 + IDAwMDAwIG4gCjAwMDAwNjYwNDMgMDAwMDAgbiAKMDAwMDA3MDgyNCAwMDAwMCBuIAow + MDAwMDE4MDE1IDAwMDAwIG4gCjAwMDAwMjA5ODQgMDAwMDAgbiAKMDAwMDA3MzcyNCAw + MDAwMCBuIAowMDAwMDY2MDY0IDAwMDAwIG4gCjAwMDAwNzAxMTUgMDAwMDAgbiAKMDAw + MDA3NDQ0OSAwMDAwMCBuIAowMDAwMDM4MzMwIDAwMDAwIG4gCjAwMDAwNDE1NDEgMDAw + MDAgbiAKMDAwMDA0NTAyMiAwMDAwMCBuIAowMDAwMDQ4OTA3IDAwMDAwIG4gCjAwMDAw + NzIyNzQgMDAwMDAgbiAKMDAwMDA1OTQ0OSAwMDAwMCBuIAowMDAwMDYyMTM3IDAwMDAw + IG4gCjAwMDAwNDg5MjggMDAwMDAgbiAKMDAwMDA1MjgxMyAwMDAwMCBuIAowMDAwMDcx + NTQ5IDAwMDAwIG4gCjAwMDAwMzU4MzYgMDAwMDAgbiAKMDAwMDAzODMwOSAwMDAwMCBu + IAowMDAwMDcyOTk5IDAwMDAwIG4gCjAwMDAwNDE1NjIgMDAwMDAgbiAKMDAwMDA0NTAw + MSAwMDAwMCBuIAowMDAwMDU1NTQzIDAwMDAwIG4gCjAwMDAwNTk0MjggMDAwMDAgbiAK + MDAwMDAyMTAwNSAwMDAwMCBuIAowMDAwMDI0ODkwIDAwMDAwIG4gCjAwMDAwNzYxMjUg + MDAwMDAgbiAKMDAwMDAyNDkxMSAwMDAwMCBuIAowMDAwMDMxOTA5IDAwMDAwIG4gCjAw + MDAwNTI4MzQgMDAwMDAgbiAKMDAwMDA1NTUyMiAwMDAwMCBuIAowMDAwMDMxOTMwIDAw + MDAwIG4gCjAwMDAwMzU4MTUgMDAwMDAgbiAKMDAwMDA3MDEzNiAwMDAwMCBuIAowMDAw + MDcwODA0IDAwMDAwIG4gCjAwMDAwNzA4NjEgMDAwMDAgbiAKMDAwMDA3MTUyOSAwMDAw + MCBuIAowMDAwMDcxNTg2IDAwMDAwIG4gCjAwMDAwNzIyNTQgMDAwMDAgbiAKMDAwMDA3 + MjMxMSAwMDAwMCBuIAowMDAwMDcyOTc5IDAwMDAwIG4gCjAwMDAwNzMwMzYgMDAwMDAg + biAKMDAwMDA3MzcwNCAwMDAwMCBuIAowMDAwMDczNzYxIDAwMDAwIG4gCjAwMDAwNzQ0 + MjkgMDAwMDAgbiAKMDAwMDA3NDQ4NiAwMDAwMCBuIAowMDAwMDc1MzgxIDAwMDAwIG4g + CjAwMDAwNzU0MzcgMDAwMDAgbiAKMDAwMDA3NjEwNSAwMDAwMCBuIAowMDAwMDc2MTYy + IDAwMDAwIG4gCjAwMDAwNzY4MzAgMDAwMDAgbiAKMDAwMDA3Njg4NyAwMDAwMCBuIAow + MDAwMDc3Njk1IDAwMDAwIG4gCjAwMDAwNzc4MzUgMDAwMDAgbiAKMDAwMDA3ODA0MSAw + MDAwMCBuIAowMDAwMDc3OTYzIDAwMDAwIG4gCjAwMDAwNzgxMTkgMDAwMDAgbiAKMDAw + MDA4OTE4OCAwMDAwMCBuIAowMDAwMDg5MjExIDAwMDAwIG4gCjAwMDAwODk0MzIgMDAw + MDAgbiAKMDAwMDA5MDExNCAwMDAwMCBuIAowMDAwMDk1ODgzIDAwMDAwIG4gCjAwMDAw + OTU5MDUgMDAwMDAgbiAKMDAwMDA5NjEzMyAwMDAwMCBuIAp0cmFpbGVyCjw8IC9TaXpl + IDEwNyAvUm9vdCA5NiAwIFIgL0luZm8gMSAwIFIgL0lEIFsgPDE3ZDJjNDJhMzE3NDJh + NTgyMWQxNTc1OWQwMGFhYWE5Pgo8MTdkMmM0MmEzMTc0MmE1ODIxZDE1NzU5ZDAwYWFh + YTk+IF0gPj4Kc3RhcnR4cmVmCjk2NzczCiUlRU9GCjEgMCBvYmoKPDwvQXV0aG9yIChi + cmFuZG9uaCkvQ3JlYXRpb25EYXRlIChEOjIwMDkxMTIwMDExMzAwWikvQ3JlYXRvciAo + T21uaUdyYWZmbGUgUHJvZmVzc2lvbmFsIDUuMi4xKS9Nb2REYXRlIChEOjIwMDkxMjE2 + MjI0MjAwWikvUHJvZHVjZXIgKE1hYyBPUyBYIDEwLjUuOCBRdWFydHogUERGQ29udGV4 + dCkvVGl0bGUgKGhlYWRlcl9wYXJzaW5nX2Zsb3djaGFydC5ncmFmZmxlKT4+CmVuZG9i + agp4cmVmCjEgMQowMDAwMDk5MDczIDAwMDAwIG4gCnRyYWlsZXIKPDwvSUQgWzwxN2Qy + YzQyYTMxNzQyYTU4MjFkMTU3NTlkMDBhYWFhOT4gPDE3ZDJjNDJhMzE3NDJhNTgyMWQx + NTc1OWQwMGFhYWE5Pl0gL0luZm8gMSAwIFIgL1ByZXYgOTY3NzMgL1Jvb3QgOTYgMCBS + IC9TaXplIDEwNz4+CnN0YXJ0eHJlZgo5OTI5OQolJUVPRgo= + + QuickLookThumbnail + + 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 + AAASmwAAT0AAAFOAAAIzMwACMzMAAjMzZGVzYwAAAAAAAAAOU2NlcHRyZSBYMjRXRwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABtbHVjAAAAAAAAABIAAAAMbmJOTwAAABoA + AADocHRQVAAAABoAAADoc3ZTRQAAABoAAADoZmlGSQAAABoAAADoZGFESwAAABoAAADo + emhDTgAAABoAAADoZnJGUgAAABoAAADoamFKUAAAABoAAADoZW5VUwAAABoAAADocGxQ + TAAAABoAAADocHRCUgAAABoAAADoZXNFUwAAABoAAADoemhUVwAAABoAAADocnVSVQAA + ABoAAADoa29LUgAAABoAAADoZGVERQAAABoAAADobmxOTAAAABoAAADoaXRJVAAAABoA + AADoAFMAYwBlAHAAdAByAGUAIABYADIANABXAEcAAG1tb2QAAAAAAABOFAAAJAQAAABF + w6htgAAAAAAAAAAAAAAAAAAAAAB0ZXh0AAAAAENvcHlyaWdodCBBcHBsZSwgSW5jLiwg + MjAwOQA= + + ReadOnly + NO + RowAlign + 1 + RowSpacing + 36 + SheetTitle + Canvas 1 + SmartAlignmentGuidesActive + YES + SmartDistanceGuidesActive + YES + UniqueID + 1 + UseEntirePage + + VPages + 1 + WindowInfo + + CurrentSheet + 0 + ExpandedCanvases + + + name + Canvas 1 + + + FitInWindow + + Frame + {{94, 4}, {1714, 1174}} + ListView + + OutlineWidth + 142 + RightSidebar + + ShowRuler + + Sidebar + + SidebarWidth + 120 + VisibleRegion + {{0, -16}, {1187.25, 766.937}} + Zoom + 1.3299663066864014 + ZoomValues + + + Canvas 1 + 0.0 + 1 + + + + saveQuickLookFiles + YES + + diff --git a/openflow/doc/of-spec/make_latex_input.pl b/openflow/doc/of-spec/make_latex_input.pl new file mode 100755 index 00000000..7a1c48b7 --- /dev/null +++ b/openflow/doc/of-spec/make_latex_input.pl @@ -0,0 +1,117 @@ +#!/usr/bin/perl -w + +use strict; + +sub handle_comment { + my ($comment) = @_; + + my $next_line; + do { + $next_line = ; + chomp $next_line; + $comment .= $next_line . "\n"; + } until ( $next_line =~ m/\*\// ); + + return $comment; +} + +sub handle_define { + my ( $var, $val ) = @_; + open( OUTFILE, ">define/$var" ); + print OUTFILE $val; + close(OUTFILE); +} + +sub handle_multiline { + my ( $dir, $filename, $line_orig, $last_comment ) = @_; + + open( OUTFILE, ">$dir/$filename" ); + + #print OUTFILE "\\scriptsize\n"; + print OUTFILE "\\begin{footnotesize}\n"; + print OUTFILE "\\begin{verbatim}\n"; + + #print OUTFILE "\\begin{lstlisting}[frame=htb]{$filename}\n"; + print OUTFILE $last_comment; + print OUTFILE $line_orig; + my $next_line; + do { + + $next_line = ; + chomp $next_line; + + print OUTFILE $next_line . "\n"; + + } until ( $next_line eq '};' ); + + # add assertion line for structs + if ( $dir eq 'struct' ) { + $next_line = ; + print OUTFILE $next_line; + } + print OUTFILE "\\end{verbatim}\n"; + + #print OUTFILE "\\end{lstlisting}\n"; + print OUTFILE "\\end{footnotesize}\n"; + close(OUTFILE); +} + +#---------------------------------------- +use File::Path; + +foreach my $type ( 'enum', 'struct', 'define' ) { + if ( -d $type ) { + rmtree($type); + } + mkdir $type; +} + +open( INFILE, "<../../include/openflow/openflow.h" ); + +my $last_comment; +while () { + + # Good practice to store $_ value because + # subsequent operations may change it. + my ($line) = $_; + my $line_orig = $line; + my @line_split = split ' ', $line; + + if ( not defined( $line_split[0] ) ) { + $last_comment = ''; + } + + # Handle single-line comment + elsif ( $line =~ m/^\/\*.*\*\// ) { + $last_comment = $line; + + #print $last_comment; + } + + # Handle multi-line comment + elsif ( $line =~ m/^\/\*/ ) { + $last_comment = handle_comment($line_orig); + + #print $last_comment; + } + + # Handle define + elsif ( $line_split[0] eq '#define' ) { + handle_define( $line_split[1], $line_split[2] ); + $last_comment = ''; + } + + # Handle enum + elsif ( $line_split[0] eq 'enum' ) { + handle_multiline( 'enum', $line_split[1], $line_orig, $last_comment ); + $last_comment = ''; + } + + # Handle struct + elsif ( $line_split[0] eq 'struct' ) { + handle_multiline( 'struct', $line_split[1], $line_orig, $last_comment ); + $last_comment = ''; + } + +} +print "completed\n"; diff --git a/openflow/doc/of-spec/openflow-spec-v1.0.0.tex b/openflow/doc/of-spec/openflow-spec-v1.0.0.tex new file mode 100644 index 00000000..56dca85c --- /dev/null +++ b/openflow/doc/of-spec/openflow-spec-v1.0.0.tex @@ -0,0 +1,418 @@ +\documentclass[10pt]{article} +\usepackage{amsmath} +\usepackage{listings} +\usepackage{hyperref} +\usepackage{fancyhdr} +\usepackage{graphicx} +\usepackage{tabularx} +\usepackage{color} + +\hbadness=10000 % No "underfull hbox" messages + +\begin{document} + +%\lstset{language=C} + +% Define the OpenFlow version here +\newcommand{\ofversion}{1.0.0} + +\pagestyle{fancy} +\fancyhead{} +\lhead{OpenFlow Switch Specification} +%\chead{DO NOT BUILD A SWITCH FROM THIS SPECIFICATION!} +\rhead{Version \ofversion} +\renewcommand{\headrulewidth}{0.4pt} +\renewcommand{\footrulewidth}{0.4pt} + +\fontfamily{cmr} % what about cmss? +\selectfont + +\newcommand{\qosupd}[1]{{#1}} +%\newcommand{\qosupd}[1]{{\color{blue} #1}} + +\title{OpenFlow Switch Specification} +\author{Version \ofversion{} ( Wire Protocol \input{define/OFP_VERSION})} +\date{\today} +\maketitle + +\section{Introduction} +This document describes the requirements of an OpenFlow Switch. We recommend that you read the latest version of the OpenFlow whitepaper before reading this specification. The whitepaper is available on the OpenFlow Consortium website (\url{http://OpenFlowSwitch.org}). This specification covers the components and the basic functions of the switch, and the OpenFlow protocol to manage an OpenFlow switch from a remote controller. +\\\\ +Version 1.0 of this document will be the first for which official vendor support is expected. Versions before 1.0 will be marked ``Draft", and will include the header: ``Do not build a switch from this specification!" We hope to generate feedback prior to Version 1.0 from switch designers and network researchers, so that the set of features defined in Version 1.0 enables production deployments on a variety of vendor hardware. + +\begin{figure}[htbp] +\centering +\includegraphics[height=2.5in]{figure_flow_table_secchan.png} +\caption{An OpenFlow switch communicates with a controller over a secure connection using the OpenFlow protocol.} +\label{fig:flow table and controller} +\end{figure} + +\section{Switch Components} +An OpenFlow Switch consists of a \emph{flow table}, which performs packet lookup and forwarding, and a \emph{secure channel} to an external controller (Figure \ref{fig:flow table and controller}). The controller manages the switch over the secure channel using the OpenFlow protocol. +\\\\ +The flow table contains a set of flow entries (header values to match packets against), activity counters, and a set of zero or more actions to apply to matching packets. All packets processed by the switch are compared against the flow table. If a matching entry is found, any actions for that entry are performed on the packet (e.g., the action might be to forward a packet out a specified port). If no match is found, the packet is forwarded to the controller over the secure channel. The controller is responsible for determining how to handle packets without valid flow entries, and it manages the switch flow table by adding and removing flow entries. +\\\\ +Flow entries may forward packets to one or more OpenFlow ports. In general, these are physical ports, but the protocol does not preclude abstractions like port aggregations or VLAN traffic on a port appearing as an OpenFlow port. OpenFlow ports have limited state such as ``up'', ``down'' and whether spanning tree flood packets should be forwarded out the port. Additional configuration of ports may handled by the OpenFlow configuration protocol. There are several OpenFlow virtual ports used to indicate, for example, flooding or the ingress port (see \ref{ft:actions}). + +\section{Flow Table} +This section describes the components of flow table entries and the process by which incoming packets are matched against flow table entries. + +\begin{table}[hbp] +\centering +\begin{tabular}{|c|c|c|} +\hline +Header Fields & Counters & Actions\\ +\hline +\end{tabular} +\caption{A flow entry consists of header fields, counters, and actions.} +\label{table:flow entry} +\end{table} + +Each flow table entry (see Table \ref{table:flow entry}) contains: +\begin{itemize} +\item \textbf{header fields} to match against packets +\item \textbf{counters} to update for matching packet +\item \textbf{actions} to apply to matching packets +\end{itemize} + +\subsection{Header Fields} +\begin{table}[hbp] +\centering +\footnotesize +\begin{tabularx}{\textwidth}{ |X|X|X|X|X|X|X|X|X|X|X|X| } +\hline +Ingress Port & +Ether source & +Ether dst & +Ether type & +VLAN id & +VLAN priority & +IP src & +IP dst & +IP proto & +IP ToS bits & +TCP/ UDP src port & +TCP/ UDP dst port +\\ +\hline +\end{tabularx} +\caption{Fields from packets used to match against flow entries.} +\label{table:header fields} +\end{table} + +Table \ref{table:header fields} shows the header fields an incoming packet is compared against. Each entry contains a specific value, or ANY, which matches any value. If the switch supports subnet masks on the IP source and/or destination fields, these can more precisely specify matches. The fields in the OpenFlow 12-tuple are listed in Table \ref{table:header fields} and details on the properties of each field are described in Table \ref{table:header field details}. +\\\\ +\begin{table}[hbp] +\centering +\footnotesize +\begin{tabularx}{\textwidth}{ |X|X|X|X| } +\hline Field & Bits & When applicable & Notes \\ +\hline Ingress Port & (Implementation dependent) & All packets & Numerical representation of incoming port, starting at 1. \\ +\hline Ethernet source address & 48 & All packets on enabled ports & \\ +\hline Ethernet destination address & 48 & All packets on enabled ports & \\ +\hline Ethernet type & 16 & All packets on enabled ports & An OpenFlow switch is required to match the type in both standard Ethernet and 802.2 with a SNAP header and OUI of 0x000000. The special value of 0x05FF is used to match all 802.3 packets without SNAP headers. \\ +\hline VLAN id & 12 & All packets of Ethernet type 0x8100 & \\ +\hline VLAN priority & 3 & All packets of Ethernet type 0x8100 & VLAN PCP field \\ +\hline IP source address & 32 & All IP and ARP packets & Can be subnet masked \\ +\hline IP destination address & 32 & All IP and ARP packets & Can be subnet masked \\ +\hline IP protocol & 8 & All IP and IP over Ethernet, ARP packets & Only the lower 8 bits of the ARP opcode are used \\ +\hline IP ToS bits & 6 & All IP packets & Specify as 8-bit value and place ToS in upper 6 bits. \\ +\hline Transport source port / ICMP Type & 16 & All TCP, UDP, and ICMP packets & Only lower 8 bits used for ICMP Type \\ +\hline Transport destination port / ICMP Code & 16 & All TCP, UDP, and ICMP packets & Only lower 8 bits used for ICMP Code \\ +\hline +\end{tabularx} +\caption{Field lengths and the way they must be applied to flow entries.} +\label{table:header field details} +\end{table}Switch designers are free to implement the internals in any way convenient provided that correct functionality is preserved. For example, while a flow may have multiple forward actions, each specifying a different port, a switch designer may choose to implement this as a single bitmask within the hardware forwarding table. + +\subsection{Counters} + +Counters are maintained per-table, per-flow, \qosupd{per-port and + per queue}. OpenFlow-compliant counters may be implemented in software and maintained by polling hardware counters with more limited ranges. +\\\\ +Table \ref{table:counters} contains the required set of counters. Duration refers to the time the flow has been installed in the switch. The Receive Errors field includes all explicitly specified errors, including frame, overrun, and CRC errors, plus any others. Counters wrap around with no overflow indicator. In this document, the phrase byte refers to 8-bit octets. +\begin{table}[!hbp] +\centering +\footnotesize +%\begin{tabularx}{\textwidth}{ |X|X| } +\begin{tabular}{ |l|c| } +\hline Counter & Bits \\ +\hline \multicolumn{2}{|c|}{Per Table} \\ +\hline Active Entries & 32 \\ +\hline Packet Lookups & 64 \\ +\hline Packet Matches & 64 \\ +\hline \multicolumn{2}{|c|}{Per Flow} \\ +\hline Received Packets & 64 \\ +\hline Received Bytes & 64 \\ +\hline Duration (seconds) & 32 \\ +\hline Duration (nanoseconds) & 32 \\ +\hline \multicolumn{2}{|c|}{Per Port} \\ +\hline Received Packets & 64 \\ +\hline Transmitted Packets & 64 \\ +\hline Received Bytes & 64 \\ +\hline Transmitted Bytes & 64 \\ +\hline Receive Drops & 64 \\ +\hline Transmit Drops & 64 \\ +\hline Receive Errors & 64 \\ +\hline Transmit Errors & 64 \\ +\hline Receive Frame Alignment Errors & 64 \\ +\hline Receive Overrun Errors & 64 \\ +\hline Receive CRC Errors & 64 \\ +\hline Collisions & 64 \\ +\hline \multicolumn{2}{|c|}{\qosupd{Per Queue}} \\ +\hline \qosupd{Transmit Packets} & \qosupd{64} \\ +\hline \qosupd{Transmit Bytes} & \qosupd{64} \\ +\hline \qosupd{Transmit Overrun Errors} & \qosupd{64}\\ +\hline +\end{tabular} +\caption{Required list of counters for use in statistics messages.} +\label{table:counters} +\end{table} + +\subsection{Actions} +\label{ft:actions} +Each flow entry is associated with zero or more actions that dictate how the switch handles matching packets. If no forward actions are present, the packet is dropped. Action lists for \emph{inserted} flow entries MUST be processed in the order specified. However, there is no packet output ordering guaranteed within a port. For example, an action list may result in two packets sent to two different VLANs on a single port. These two packets may be arbitrarily re-ordered, but the packet bodies must match those generated from a sequential execution of the actions. +\\\\ +A switch may reject a flow entry if it cannot process the action list in the order specified, in which case it should immediately return an unsupported flow error (see \ref{unsupported_flow}). Ordering within a port may vary between vendor switch implementations. +\\\\ +A switch is not required to support all action types --- just those marked ``Required Actions'' below. When connecting to the controller, a switch indicates which of the ``Optional Actions'' it supports. OpenFlow-compliant switches come in two types: \emph{OpenFlow-only}, and \emph{OpenFlow-enabled}. +\\\\ +OpenFlow-only switches support only the required actions below, while OpenFlow-enabled switches, routers, and access points may also support the \textbf{NORMAL} action. Either type of switch can also support the \textbf{FLOOD} action. +\\\\ +\textbf{Required Action:} \textit{Forward}. +OpenFlow switches must support forwarding the packet to physical ports and the following virtual ones: +\begin{itemize} +\item \textbf{ALL:} Send the packet out all interfaces, not including the incoming interface. +\item \textbf{CONTROLLER:} Encapsulate and send the packet to the controller. +\item \textbf{LOCAL:} Send the packet to the switchÕs local networking stack. +\item \textbf{TABLE:} Perform actions in flow table. Only for packet-out messages. +\item \textbf{IN\_PORT:} Send the packet out the input port. +\end{itemize} +\textbf{Optional Action:} \textit{Forward}. +The switch may optionally support the following virtual ports: +\begin{itemize} +\item \textbf{NORMAL:} Process the packet using the traditional forwarding path supported by the switch (i.e., traditional L2, VLAN, and L3 processing.) The switch may check the VLAN field to determine whether or not to forward the packet along the normal processing route. If the switch cannot forward entries for the OpenFlow-specific VLAN back to the normal processing route, it must indicate that it does not support this action. +\item \textbf{FLOOD:} Flood the packet along the minimum spanning tree, not including the incoming interface. +\end{itemize} +The controller will only ask the switch to send to multiple physical ports simultaneously if the switch indicates it supports this behavior in the initial handshake (see section \ref{cts:handshake}). +\\\\ +\textbf{\qosupd{Optional Action:}} \emph{\qosupd{Enqueue}}. \qosupd{The enqueue action forwards +a packet through a queue attached to a port. Forwarding behavior is +dictated by the configuration of the queue and is used to provide +basic Quality-of-Service (QoS) support (see section \ref{cts:qos}).} +\\\\ +\textbf{Required Action:} \emph{Drop}. A flow-entry with no specified action indicates that all matching packets should be dropped. +\\\\ +\textbf{Optional Action:} \emph{Modify-Field}. While not strictly required, the actions shown in Table \ref{table:field modify actions} greatly increase the usefulness of an OpenFlow implementation. To aid integration with existing networks, we suggest that VLAN modification actions be supported. + +\begin{table}[hbp] +\centering +\footnotesize +\begin{tabularx}{\linewidth}{ |X|X|X| } +\hline +Action & Associated Data & Description \\ +\hline +Set VLAN ID & +12 bits & +If no VLAN is present, a new header is added with the specified VLAN ID and priority of zero. + +If a VLAN header already exists, the VLAN ID is replaced with the specified value. \\ +\hline +Set VLAN priority & +3 bits & +If no VLAN is present, a new header is added with the specified priority and a VLAN ID of zero. + +If a VLAN header already exists, the priority field is replaced with the specified value. \\ +\hline +Strip VLAN header & +- & +Strip VLAN header if present. \\ +\hline +Modify Ethernet source MAC address & +48 bits: Value with which to replace existing source MAC address & +Replace the existing Ethernet source MAC address with the new value \\ +\hline +Modify Ethernet destination MAC address & +48 bits: Value with which to replace existing destination MAC address & +Replace the existing Ethernet destination MAC address with the new value. \\ +\hline +Modify IPv4 source address & +32 bits: Value with which to replace existing IPv4 source address & +Replace the existing IP source address with new value and update the IP checksum (and TCP/UDP +checksum if applicable). + +This action is only applicable to IPv4 packets. \\ +\hline +Modify IPv4 destination address & +32 bits: Value with which to replace existing IPv4 destination address & +Replace the existing IP destination address with new value and update the IP checksum (and TCP/UDP checksum if applicable). + +This action is only applied to IPv4 packets. \\ +\hline +Modify IPv4 ToS bits & +6 bits: Value with which to replace existing IPv4 ToS field & +Replace the existing IP ToS field. +This action is only applied to IPv4 packets. \\ +\hline +Modify transport source port & +16 bits: Value with which to replace existing TCP or UDP source port & +Replace the existing TCP/UDP source port with new value and update the TCP/UDP checksum. + +This action is only applicable to TCP and UDP packets.\\ +\hline +Modify transport destination port & +16 bits: Value with which to replace existing TCP or UDP destination port & +Replace the existing TCP/UDP destination port with new value and update the TCP/UDP checksum + +This action is only applied to TCP and UDP packets.\\ +\hline +\end{tabularx} +\caption{Field-modify actions.} +\label{table:field modify actions} +\end{table} + +\subsection{Matching} +\begin{figure}[!htb] +\centering +\includegraphics[height=1.85in]{packet_flow_flowchart} +\caption{Packet flow in an OpenFlow switch. As discussed in Section \ref{flow_table:stp_support}, support for 802.1D is optional.} +\label{fig:packet_flow} +\end{figure} + +\begin{figure}[!htb] +\centering +\includegraphics[height=2.9in]{header_parsing_flowchart} +\caption{Flowchart showing how header fields are parsed for matching.} +\label{fig:header_parsing} +\end{figure} + +On receipt of a packet, an OpenFlow Switch performs the functions shown in Figure \ref{fig:packet_flow}. Header fields used for the table lookup depend on the packet type as described below (and shown in Figure \ref{fig:header_parsing}). + +\begin{itemize} +\item Rules specifying an ingress port are matched against the physical port that received the packet. +\item The Ethernet headers as specified in Table \ref{table:header fields} are used for all packets. +\item If the packet is a VLAN (Ethernet type 0x8100), the VLAN ID and PCP fields are used in the lookup. +\item (Optional) For ARP packets (Ethernet type equal to 0x0806), the lookup fields may also include the contained IP source and destination fields. +\item For IP packets (Ethernet type equal to 0x0800), the lookup fields also include those in the IP header. +\item For IP packets that are TCP or UDP (IP protocol is equal to 6 or 17), the lookup includes the transport ports. +\item For IP packets that are ICMP (IP prototcol is equal to 1), the lookup includes the Type and Code fields. +\item For IP packets with nonzero fragment offset or More Fragments bit set, the transport ports are set to zero for the lookup. +\end{itemize} +A packet matches a flow table entry if the values in the header fields used for the lookup (as defined above) match those defined in the flow table. If a flow table field has a value of ANY, it matches all possible values in the header. +\\\\ +To handle the various Ethernet framing types, matching the Ethernet type is handled in a slightly different manner. If the packet is an Ethernet II frame, the Ethernet type is handled in the expected way. If the packet is an 802.3 frame with a SNAP header and Organizationally Unique Identifier (OUI) of 0x000000, the SNAP protocol id is matched against the flowÕs Ethernet type. A flow entry that specifies an Ethernet type of 0x05FF, matches all Ethernet 802.2 frames without a SNAP header and those with SNAP headers that do not have an OUI of 0x000000. +\\\\ +Packets are matched against flow entries based on prioritization. An entry that specifies an exact match (i.e., it has no wildcards) is always the highest priority. All wildcard entries have a priority associated with them. Higher priority entries must match before lower priority ones. If multiple entries have the same priority, the switch is free to choose any ordering. Higher numbers have higher priorities. +\\\\ +For each packet that matches a flow entry, the associated counters for that entry are updated. If no matching entry can be found for a packet, the packet is sent to the controller over the secure channel. + +\section{Secure Channel} +The secure channel is the interface that connects each OpenFlow switch to a controller. Through this interface, the controller configures and manages the switch, receives events from the switch, and send packets out the switch. +\\\\ +Between the datapath and the secure channel, the interface is implementation-specific, however all secure channel messages must be formatted according to the OpenFlow protocol. +\\\\ +Support for multiple simultaneous controllers is currently undefined. + +\subsection{OpenFlow Protocol Overview} +The OpenFlow protocol supports three message types, \emph{controller-to-switch}, \emph{asynchronous}, and \emph{symmetric}, each with multiple sub-types. Controller-to-switch messages are initiated by the controller and used to directly manage or inspect the state of the switch. Asynchronous messages are initiated by the switch and used to update the controller of network events and changes to the switch state. Symmetric messages are initiated by either the switch or the controller and sent without solicitation. The message types used by OpenFlow are described below. + +\subsubsection{Controller-to-Switch} +Controller/switch messages are initiated by the controller and may or may not require a response from the switch. +\\\\ +\textbf{Features:} Upon Transport Layer Security (TLS) session establishment, the controller sends a features request message to the switch. The switch must reply with a features reply that specifies the capabilities supported by the switch. +\\\\ +\textbf{Configuration:} The controller is able to set and query configuration parameters in the switch. The switch only responds to a query from the controller. +\\\\ +\textbf{Modify-State:} Modify-State messages are sent by the controller to manage state on the switches. Their primary purpose is to add/delete and modify flows in the flow tables and to set switch port properties. +\\\\ +\textbf{Read-State:} Read-State messages are used by the controller to collect statistics from the switchÕs flow-tables, ports and the individual flow entries. +\\\\\ +\textbf{Send-Packet}: These are used by the controller to send packets out of a specified port on the switch. +\\\\ +\textbf{Barrier}: Barrier request/reply messages are used by the controller to ensure message dependencies have been met or to receive notifications for completed operations. + +\subsubsection{Asynchronous} +Asynchronous messages are sent without the controller soliciting them from a switch. Switches send asynchronous messages to the controller to denote a packet arrival, switch state change, or error. The four main asynchronous message types are described below. +\\\\ +\textbf{Packet-in:} For all packets that do not have a matching flow entry, a packet-in event is sent to the controller (or if a packet matches an entry with a ``send to controller" action). If the switch has sufficient memory to buffer packets that are sent to the controller, the packet-in events contain some fraction of the packet header (by default \input{define/OFP_DEFAULT_MISS_SEND_LEN} bytes) and a buffer ID to be used by the controller when it is ready for the switch to forward the packet. Switches that do not support internal buffering (or have run out of internal buffering) must send the full packet to the controller as part of the event. +\\\\ +\textbf{Flow-Removed:} When a flow entry is added to the switch by a flow modify message, an idle timeout value indicates when the entry should be removed due to a lack of activity, as well as a hard timeout value that indicates when the entry should be removed, regardless of activity. The flow modify message also specifies whether the switch should send a flow removed message to the controller when the flow expires. Flow modify messages which delete flows may also cause flow removed messages. +\\\\ +\textbf{Port-status:} The switch is expected to send port-status messages to the controller as port configuration state changes. These events include change in port status (for example, if it was brought down directly by a user) or a change in port status as specified by 802.1D (see Section \ref{flow_table:stp_support} for a description of 802.1D support requirements). +\\\\ +\textbf{Error:} The switch is able to notify the controller of problems using error messages. + +\subsubsection{Symmetric} +Symmetric messages are sent without solicitation, in either direction. +\\\\ +\textbf{Hello:} Hello messages are exchanged between the switch and controller upon connection startup. +\\\\ +\textbf{Echo:} Echo request/reply messages can be sent from either the switch or the controller, and must return an echo reply. They can be used to indicate the latency, bandwidth, and/or liveness of a controller-switch connection. +\\\\ +\textbf{Vendor:} Vendor messages provide a standard way for OpenFlow switches to offer additional functionality within the OpenFlow message type space. This is a staging area for features meant for future OpenFlow revisions. + +\subsection{Connection Setup} +The switch must be able to establish the communication at a user-configurable (but otherwise fixed) IP address, using a user-specified port. Traffic to and from the secure channel is not checked against the flow table. Therefore, the switch must identify incoming traffic as local before checking it against the flow table. Future versions of the protocol specification will describe a dynamic controller discovery protocol in which the IP address and port for communicating with the controller is determined at runtime. +\\\\ +When an OpenFlow connection is first established, each side of the connection must immediately send an \verb|OFPT_HELLO| message with the \verb|version| field set to the highest OpenFlow protocol version supported by the sender. Upon receipt of this message, the recipient may calculate the OpenFlow protocol version to be used as the smaller of the version number that it sent and the one that it received. +\\\\ +If the negotiated version is supported by the recipient, then the connection proceeds. Otherwise, the recipient must reply with an \verb|OFPT_ERROR| message with a \verb|type| field of \verb|OFPET_HELLO_FAILED|, a \verb|code| field of \verb| OFPHFC_COMPATIBLE|, and optionally an ASCII string explaining the situation in \verb|data|, and then terminate the connection. + +\subsection{Connection Interruption} +In the case that a switch loses contact with the controller, as a result of a echo request timeout, TLS session timeout, or other disconnection, it should attempt to contact one or more backup controllers. The ordering of the controller IP addresses is not specified by the protocol. +\\\\ +If some number of attempts to contact a controller (zero or more) fail, the switch must enter ``emergency mode'' and immediately reset the current TCP connection. In emergency mode, the matching process is dictated by the emergency flow table entries (those marked with the emergency bit when added to the switch). All normal entries are deleted when entering emergency mode. +\\\\ +Upon connecting to a controller again, the emergency flow entries remain. The controller then has the option of deleting all flow entries, if desired. +\\\\ +The first time a switch starts up, it is considered to be in emergency mode. Configuration of the default set of flow entries is outside the scope of the OpenFlow protocol. + +\subsection{Encryption} +The switch and controller communicate through a TLS connection. The TLS connection is initiated by the switch on startup to the controller's server, which is located by default on TCP port \input{define/OFP_TCP_PORT}. The switch and controller mutually authenticate by exchanging certificates signed by a site-specific private key. Each switch must be user-configurable with one certificate for authenticating the controller (controller certificate) and the other for authenticating to the controller (switch certificate). + +\subsection{Spanning Tree} +\label{flow_table:stp_support} +OpenFlow switches may optionally support 802.1D Spanning Tree Protocol. Those switches that do support it are expected to process all 802.1D packets locally before performing flow lookup. A switch that implements STP must set the \verb|OFPC_STP| bit in the 'capabilities' field of its \verb|OFPT_FEATURES_REPLY| message. A switch that implements STP must make it available on all of its physical ports, but it need not implement it on virtual ports (e.g. \verb|OFPP_LOCAL|). +\\\\ +Port status, as specified by the spanning tree protocol, is then used to limit packets forwarded to the \verb|OFP_FLOOD| port to only those ports along the spanning tree. Port changes as a result of the spanning tree are sent to the controller via port-update messages. Note that forward actions that specify the outgoing port or \verb|OFP_ALL| ignore the port status set by the spanning tree protocol. Packets received on ports that are disabled by spanning tree must follow the normal flow table processing path. +\\\\ +Switches that do not support 802.1D spanning tree must allow the controller to specify the port status for packet flooding through the port-mod messages. + +\subsection{Flow Table Modification Messages} +\label{flow_table:sec_chan:flow_add} +\label{flow_table:sec_chan:flow_mod} +\label{flow_table:sec_chan:flow_removal} +Flow table modification messages can have the following types: +\input{enum/ofp_flow_mod_command} +For ADD requests with the \verb|OFPFF_CHECK_OVERLAP| flag set, the switch must first check for any overlapping flow entries. Two flow entries overlap if a single packet may match both, and both entries have the same priority. If an overlap conflict exists between an existing flow entry and the ADD request, the switch must refuse the addition and respond with an \verb|ofp_error_msg| with \verb|OFPET_FLOW_MOD_FAILED| type and \verb|OFPFMFC_OVERLAP| code. +\\\\ +For valid (non-overlapping) ADD requests, or those with no overlap checking, the switch must insert the flow entry at the lowest numbered table for which the switch supports all wildcards set in the \verb|flow_match| struct, and for which the priority would be observed during the matching process. If a flow entry with identical header fields and priority already resides in any table, then that entry, including its counters, must be removed, and the new flow entry added. +\\\\ +If a switch cannot find any table in which to add the incoming flow entry, the switch should send an \verb|ofp_error_msg| with \verb|OFPET_FLOW_MOD_FAILED| type and \verb|OFPFMFC_ALL_TABLES_FULL| code. +\\\\ +If the action list in a flow mod message references a port that will never be valid on a switch, the switch must return an \verb|ofp_error_msg| with \verb|OFPET_BAD_ACTION| type and \verb|OFPBAC_BAD_OUT_PORT| code. If the referenced port may be valid in the future, e.g. when a linecard is added to a chassis switch, or a port is dynamically added to a software switch, the switch may either silently drop packets sent to the referenced port, or immediately return an \verb|OFPBAC_BAD_OUT_PORT| error and refuse the flow mod. +\\\\ +For MODIFY requests, if a flow entry with identical header fields does not current reside in any table, the MODIFY acts like an ADD, and the new flow entry must be inserted with zeroed counters. Otherwise, the actions field is changed on the existing entry and its counters and idle time fields are left unchanged. +\\\\ +For DELETE requests, if no flow entry matches, no error is recorded, and no flow table modification occurs. If flow entries match, and must be deleted, then each normal entry with the \verb|OFPFF_SEND_FLOW_REM| flag set should generate a flow removed message. Deleted emergency flow entries generate no flow removed messages. +\\\\ +MODIFY and DELETE flow mod commands have corresponding \_STRICT versions. Without \_STRICT appended, the wildcards are active and all flows that match the description are modified or removed. If \_STRICT is appended, all fields, including the wildcards and priority, are strictly matched against the entry, and only an identical flow is modified or removed. For example, if a message to remove entries is sent that has all the wildcard flags set, the DELETE command would delete all flows from all tables, while the DELETE\_STRICT command would only delete a rule that applies to all packets at the specified priority. +\\\\ +For non-strict MODIFY and DELETE commands that contain wildcards, a match will occur when a flow entry exactly matches or is more specific than the description in the flow\_mod command. For example, if a DELETE command says to delete all flows with a destination port of 80, then a flow entry that is all wildcards will not be deleted. However, a DELETE command that is all wildcards will delete an entry that matches all port 80 traffic. This same interpretation of mixed wildcard and exact header fields also applies to individual and aggregate flows stats. +\\\\ +DELETE and DELETE\_STRICT commands can be optionally filtered by output port. If the \verb|out_port| field contains a value other than \verb|OFPP_NONE|, it introduces a constraint when matching. This constraint is that the rule must contain an output action directed at that port. This field is ignored by ADD, MODIFY, and MODIFY\_STRICT messages. +\\\\ +Emergency flow mod messages must have timeout values set to zero. Otherwise, the switch must refuse the addition and respond with an \verb|ofp_error_msg| with \verb|OFPET_FLOW_MOD_FAILED| type and \verb|OFPFMFC_BAD_EMERG_TIMEOUT| code. +\\\\ +\label{unsupported_flow}If a switch cannot process the action list for any flow mod message in the order specified, it MUST immediately return an \verb|OFPET_FLOW_MOD_FAILED| : +\verb|OFPFMFC_UNSUPPORTED| error and reject the flow. + +\subsection{Flow Removal} + +Each flow entry has an \verb|idle_timeout| and a \verb|hard_timeout| associated with it. If no packet has matched the rule in the last \verb|idle_timeout| seconds, or it has been \verb|hard_timeout| seconds since the flow was inserted, the switch removes the entry and sends a flow removed message. In addition, the controller is able to actively remove entries by sending a flow message with the \verb|DELETE| or \verb|DELETE_STRICT| command. Like the message used to add the entry, a removal message contains a description, which may include wild cards. + +\input{appendix} + +\input{credits} + +\end{document} diff --git a/openflow/doc/of-spec/packet_flow_flowchart.graffle b/openflow/doc/of-spec/packet_flow_flowchart.graffle new file mode 100644 index 00000000..57a76098 --- /dev/null +++ b/openflow/doc/of-spec/packet_flow_flowchart.graffle @@ -0,0 +1,1887 @@ + + + + + ActiveLayerIndex + 0 + ApplicationVersion + + com.omnigroup.OmniGraffle + 138.12.0.121252 + + AutoAdjust + + BackgroundGraphic + + Bounds + {{0, 0}, {756, 553}} + Class + SolidGraphic + ID + 2 + Style + + shadow + + Draws + NO + + stroke + + Draws + NO + + + + CanvasOrigin + {0, 0} + ColumnAlign + 1 + ColumnSpacing + 36 + CreationDate + 2009-11-20 14:54:05 -0800 + Creator + brandonh + DisplayScale + 1 0/72 in = 1 0/72 in + GraphDocumentVersion + 6 + GraphicsList + + + Class + LineGraphic + Head + + ID + 50 + + ID + 67 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {104.25, 130.5} + {141.75, 130.5} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 66 + + + + Bounds + {{5.25, 99}, {99, 63}} + Class + ShapedGraphic + ID + 66 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Rectangle + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 Packet in from network} + + VFlip + YES + + + Bounds + {{470.5, 317.375}, {30.1875, 14}} + Class + ShapedGraphic + FitText + Vertical + Flow + Resize + ID + 64 + Shape + Rectangle + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Pad + 0 + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 no} + VerticalPad + 0 + + + + Bounds + {{470.5, 192.5}, {30.1875, 14}} + Class + ShapedGraphic + FitText + Vertical + Flow + Resize + ID + 63 + Shape + Rectangle + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Pad + 0 + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 no} + VerticalPad + 0 + + + + Bounds + {{521.062, 277}, {30.1875, 14}} + Class + ShapedGraphic + FitText + Vertical + Flow + Resize + ID + 62 + Shape + Rectangle + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Pad + 0 + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 yes} + VerticalPad + 0 + + + + Class + LineGraphic + Head + + ID + 55 + Position + 0.46666735410690308 + + ID + 61 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {514.5, 268.5} + {535.5, 130.5} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 52 + Info + 3 + + + + Bounds + {{514.5, 105.438}, {30.1875, 14}} + Class + ShapedGraphic + FitText + Vertical + Flow + Resize + ID + 60 + Shape + Rectangle + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Pad + 0 + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 yes} + VerticalPad + 0 + + + + Class + LineGraphic + Head + + ID + 53 + + ID + 57 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {460.5, 322.5} + {460.5, 345} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 52 + Info + 1 + + + + Class + LineGraphic + Head + + ID + 52 + + ID + 56 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {460.5, 184.5} + {460.5, 214.5} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + Pattern + 2 + TailArrow + 0 + + + Tail + + ID + 47 + + + + Class + LineGraphic + Head + + ID + 54 + + ID + 55 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {514.5, 130.5} + {559.5, 130.5} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 47 + Info + 3 + + + + Bounds + {{559.5, 99}, {99, 63}} + Class + ShapedGraphic + ID + 54 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Rectangle + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 Apply actions} + + VFlip + YES + + + Bounds + {{411, 345}, {99, 63}} + Class + ShapedGraphic + ID + 53 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Rectangle + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 Send to controller via Secure Channel} + + VFlip + YES + + + Bounds + {{406.5, 214.5}, {108, 108}} + Class + ShapedGraphic + ID + 52 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Diamond + Style + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 Match table N?} + VerticalPad + 0 + + + + Class + LineGraphic + Head + + ID + 35 + Info + 4 + + ID + 51 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {240.75, 130.5} + {271.5, 130.5} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 50 + Info + 3 + + + + Bounds + {{141.75, 99}, {99, 63}} + Class + ShapedGraphic + ID + 50 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Rectangle + Style + + stroke + + Pattern + 1 + + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 Optional\ +802.1d STP processing} + + VFlip + YES + + + Class + LineGraphic + Head + + ID + 47 + + ID + 49 + OrthogonalBarAutomatic + + OrthogonalBarPosition + -1 + Points + + {370.5, 130.5} + {406.5, 130.5} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 2 + TailArrow + 0 + + + Tail + + ID + 35 + + + + Bounds + {{271.5, 99}, {99, 63}} + Class + ShapedGraphic + ID + 35 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Rectangle + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 Parse header fields\ +(see below)} + + VFlip + YES + + + Bounds + {{406.5, 76.5}, {108, 108}} + Class + ShapedGraphic + ID + 47 + Magnets + + {0, 1} + {0, -1} + {1, 0} + {-1, 0} + + Shape + Diamond + Style + + Text + + Text + {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural + +\f0\fs24 \cf0 Match table 0?} + VerticalPad + 0 + + + + GridInfo + + GuidesLocked + NO + GuidesVisible + YES + HPages + 1 + ImageCounter + 1 + KeepToScale + + Layers + + + Lock + NO + Name + Layer 1 + Print + YES + View + YES + + + LayoutInfo + + Animate + NO + circoMinDist + 18 + circoSeparation + 0.0 + layoutEngine + dot + neatoSeparation + 0.0 + twopiSeparation + 0.0 + + LinksVisible + NO + MagnetsVisible + NO + MasterSheets + + ModificationDate + 2009-11-20 15:11:07 -0800 + Modifier + brandonh + NotesVisible + NO + Orientation + 2 + OriginVisible + NO + PageBreaks + YES + PrintInfo + + NSBottomMargin + + float + 41 + + NSLeftMargin + + float + 18 + + NSOrientation + + int + 1 + + NSPaperSize + + size + {792, 612} + + NSRightMargin + + float + 18 + + NSTopMargin + + float + 18 + + + PrintOnePage + + QuickLookPreview + + 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 + ago8PCAvUHJvY1NldCBbIC9QREYgL1RleHQgL0ltYWdlQiAvSW1hZ2VDIC9JbWFnZUkg + XSAvQ29sb3JTcGFjZSA8PCAvQ3MyIDIzIDAgUgovQ3MxIDggMCBSID4+IC9Gb250IDw8 + IC9GMS4wIDI0IDAgUiA+PiAvWE9iamVjdCA8PCAvSW0xIDkgMCBSIC9JbTYgMTkgMCBS + Ci9JbTQgMTUgMCBSIC9JbTUgMTcgMCBSIC9JbTMgMTMgMCBSIC9JbTIgMTEgMCBSIC9J + bTcgMjEgMCBSID4+ID4+CmVuZG9iago5IDAgb2JqCjw8IC9MZW5ndGggMTAgMCBSIC9U + eXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMjYwIC9IZWlnaHQgMjYw + IC9Db2xvclNwYWNlCjI1IDAgUiAvU01hc2sgMjYgMCBSIC9CaXRzUGVyQ29tcG9uZW50 + IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7dAxAQAAAMKg9U/taQmI + QGHAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY + MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED + BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA + gAEDBgwYMGDAgAEDBgwYMGDgAwMYXQABCmVuZHN0cmVhbQplbmRvYmoKMTAgMCBvYmoK + OTA4CmVuZG9iagoxOSAwIG9iago8PCAvTGVuZ3RoIDIwIDAgUiAvVHlwZSAvWE9iamVj + dCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRoIDI0MiAvSGVpZ2h0IDE3MCAvQ29sb3JTcGFj + ZQoyOCAwIFIgL1NNYXNrIDI5IDAgUiAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIg + L0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae3QMQEAAADCoPVPbQo/iEBhwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwa+AwPiKwABCmVuZHN0cmVhbQplbmRvYmoKMjAgMCBvYmoK + NTYyCmVuZG9iagoxNSAwIG9iago8PCAvTGVuZ3RoIDE2IDAgUiAvVHlwZSAvWE9iamVj + dCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRoIDI2MCAvSGVpZ2h0IDI2MCAvQ29sb3JTcGFj + ZQoyNSAwIFIgL1NNYXNrIDMxIDAgUiAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIg + L0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae3QMQEAAADCoPVP7WkJiEBhwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg + wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM + GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB + AwYMGDBg4AMDGF0AAQplbmRzdHJlYW0KZW5kb2JqCjE2IDAgb2JqCjkwOAplbmRvYmoK + MTcgMCBvYmoKPDwgL0xlbmd0aCAxOCAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUg + L0ltYWdlIC9XaWR0aCAyNDIgL0hlaWdodCAxNzAgL0NvbG9yU3BhY2UKMjggMCBSIC9T + TWFzayAzMyAwIFIgL0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29k + ZSA+PgpzdHJlYW0KeAHt0DEBAAAAwqD1T20KP4hAYcCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGvgMD4isAAQplbmRzdHJlYW0KZW5kb2JqCjE4IDAgb2JqCjU2MgplbmRvYmoK + MTMgMCBvYmoKPDwgL0xlbmd0aCAxNCAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUg + L0ltYWdlIC9XaWR0aCAyNDIgL0hlaWdodCAxNzAgL0NvbG9yU3BhY2UKMzUgMCBSIC9T + TWFzayAzNiAwIFIgL0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29k + ZSA+PgpzdHJlYW0KeAHt0DEBAAAAwqD1T20KP4hAYcCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGvgMD4isAAQplbmRzdHJlYW0KZW5kb2JqCjE0IDAgb2JqCjU2MgplbmRvYmoK + MTEgMCBvYmoKPDwgL0xlbmd0aCAxMiAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUg + L0ltYWdlIC9XaWR0aCAyNDIgL0hlaWdodCAxNzAgL0NvbG9yU3BhY2UKMjggMCBSIC9T + TWFzayAzOCAwIFIgL0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29k + ZSA+PgpzdHJlYW0KeAHt0DEBAAAAwqD1T20KP4hAYcCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGvgMD4isAAQplbmRzdHJlYW0KZW5kb2JqCjEyIDAgb2JqCjU2MgplbmRvYmoK + MjEgMCBvYmoKPDwgL0xlbmd0aCAyMiAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUg + L0ltYWdlIC9XaWR0aCAyNDIgL0hlaWdodCAxNzAgL0NvbG9yU3BhY2UKMjggMCBSIC9T + TWFzayA0MCAwIFIgL0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29k + ZSA+PgpzdHJlYW0KeAHt0DEBAAAAwqD1T20KP4hAYcCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG + DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA + AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw + YMCAAQMGvgMD4isAAQplbmRzdHJlYW0KZW5kb2JqCjIyIDAgb2JqCjU2MgplbmRvYmoK + NDAgMCBvYmoKPDwgL0xlbmd0aCA0MSAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUg + L0ltYWdlIC9XaWR0aCAyNDIgL0hlaWdodCAxNzAgL0NvbG9yU3BhY2UKL0RldmljZUdy + YXkgL0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJl + YW0KeAHtnf9PU9cbx/lS6Lfb215ob8ttu5ZbCr0tpbsCVkAHBIIi4BcUVzchaNUMBnYa + G5uhDsOU2CiCg/AlioyIBhwBQ5AQNZ9/7fOcYrZRim6/9azP+wfiTTB5Xuf9nPc5vSR9 + srJQuAK4ArgCuAL0rkA21fpX6w6kOX8plzL9VXkOgPwD8B1aoFQo8iiWQgEIBP5L0Ane + Hdh8pVK1IzVF+lSyUpkPdgH2F5g/8ebl5QOsWqPRarUMw+ioEhQMZWs0apWKUH+emQDn + Qi8DLsAyOpbVGwwcdTIY9CyrA24NQO8w79PaCWDwl/DqWD3HFRQajSYTz5spEs+bTEZj + YQHH6VkdYQafobVTIxOHicGE1wC0vNlSJAhWm81OkWw2qyAUWcw8UBsSzGAzQU4R2glg + 2MBaBngBF1jtDqezWHRRJbHY6XTYgRuggZnRku2cGjmb7GGlGgzmCnmLALSiy11a5pEk + r9dHibxeSfKUlbpdIlALFr6QA5vVSpJfe00GiwFYpdXpOaNZsDvFklLJW+4PBGRZPkCN + oNhAwF/ulUpLRKddMBs5vQ5czlOk6GuwGEJLkwC2OkS3x+cPyJXVB4M1taA6KkQqrQke + rK6UA36fxy06rAlkDcRXCpOzwWKVhmE5o8XqcJX5KuSqYE3dkfqGxqampmZKBKU2NtQf + qasJVskVvjKXw2oxciyjUYHJyW29Y7EWgM1WZ4nkl6sO1dU3Nrcca21r7zhBjTra21qP + tTQ31tcdqpL9UomTuMxqU5lMiKGnDQDsKJEClcHDDU1Hj3ec7DzTdS5Ekc51nek82XH8 + aFPD4WBlQCohjW3Qgcl72hqaOl+lZQt4weGSKqpq65tb20+fDX3f3dN7KRy+TInC4Uu9 + Pd3fh86ebm9trq+tqpBcDoEvICbvaevsHDiZwGKLXSzzV9Y2tLSd6jrf3Ru+2vfjwOC1 + CCW6NjjwY9/VcG/3+a5TbS0NtZX+MtFuAZPhhEreyKSpYRfzgtPtk4P1Le2doQsXr/QN + RG7cjN6KUaNb0Zs3IgN9Vy5eCHW2t9QHZZ/bKfBkJ0Nb7752JYj1hWa76KmoOtwMwD3h + vsHr0djQnbvD96jR8N07Q7Ho9cG+cA8gNx+uqvCIdnOhPiVxvpoxGIscJT75UEPrqVDP + 5f5INHZneOT+6MM4NXo4en9k+E4sGum/3BM61dpwSPaVOIqMBkadv8djRb5aR5q61F9V + 19TRdSHc/1N0aPjX0fjjJ+NPqdH4k8fx0V+Hh6I/9YcvdHU01VX5S0lb69QQXUldrVBq + 2AKzTfQEgt8cPX3+4g+R6NC9B/GxicmpmZlZSjQzMzU5MRZ/cG8oGvnh4vnTR78JBjyi + zVzAapQpiLUsbGOXV65pPH62+8oAAI8+Gp+cnns2/2KBEr2YfzY3PTn+aBSQB650nz3e + WCN7XbCRWW0KYohqY9FX7vJKaOpQb9/12C8PHk1MzT5fWHy59IoSLb1cXHg+OzXx6MEv + set9vSFo68py91dFRgjrPR7D4aQ3km1cfaTl5Hfhgejtkfj41Nz870uvl1feUKKV5ddL + v8/PTY3HR25HB8LfnWw5Uk02spGEdfI+BmIDEJcFgvXHOruvRmLDo2OTs/OLr1berK6t + U6K11TcrrxbnZyfHRodjkavdncfqg4EyIDakJGYMJqEYgquh9UxP342fR+IT088BeHX9 + 7QY1eru+CsjPpyfiIz/f6Os509oA0VUsmAxMKo8ZzmQVpa9rGtu6evtv3r7/+Le5haXl + 1fWNzXdblOjd5sb66vLSwtxvj+/fvtnf29XWWPO1JFpN3D7EvE2U5Nqm9nOXBqJ3R8em + ni2+/mNtY3NrmxptbW6s/fF68dnU2Ojd6MClc+1NtbIk2vj9ieFwAuJvw4O3hh8+mZ5/ + ubz6FoDff6BE77e3Nt+uLr+cn37ycPjWYPhbQux1fZG4IxS+FrsXn5h5sbSytvEOgD9S + og/vt99trK0svZiZiN+LXQvD8bQfMXxYVDEcb0t4nIL4f1To4+eJd733yc7Ng2s1XLl8 + B+qaT4QuR8Djp7MLr96sb2xtf/hIBS8U+fHD9tbG+ptXC7NPwePI5dCJ5roDPrh0wcU6 + LxeJ0WPsahr2Mu5jTK6/vQXB0wnPYxpiC28geOfCWyZ+ksDPTlSkNd4y8ZaJt0x864Pv + udI/rjGrMasxqzGrMasxq9NvBfB0wtMJTyc8nfB0Sr9sTq4IsxqzGrMasxqzOjkZ0+8Z + sxqzGrMasxqzOv2yObkizGrMasxqzGrM6uRkTL9nzGrMasxqzGrM6vTL5uSKMKsxqzGr + Masxq5OTMf2eMasxqzGrMasxq9Mvm5MrwqzGrMasxqzGrE5OxvR7xqzGrMasxqzGrE6/ + bE6uCLMasxqzGrMaszo5GdPvGbMasxqzGrP6v53VGfdtzllfIP7vfWP3LuKM+lb2TPvm + /YybrpBxEzQyb0pKpk3CUWTctCOFMuMmWmXe1LKMm0yXm3HTB8lMzQybMJlpU0Qzb1Js + Jk4DzryJz2RweyZN9c7KuMntQExM1uj0ZHa7Q3R7fP6AXFl9MFhDZt7XUSFSaU3wYHWl + HPD7PG6RDDHn9DDFPH/vGPMsIM5R5ClV2gSyYHeKJaWSt9wfCMiyfIAaQbGBgL/cK5WW + iE67kADWqpR5ipzkod7wsh5MBmS1VsdyhbxFsDucostdWuaRJK/XR4m8XknylJW6XaLT + YRcsfCHH6rQww1yxZ1I9+esEmAx9DS4zrKHAyJsFqw2oncWiiyqJxU6gtVkFM28sMLAM + OEx6OoXFn5ChsTVgs6GgEKAtRQJw2+wUyQasQpEFcAuBV6fVQEvvB5yVnXAZ4ivBrOc4 + oDaaTDxvpkg8bzIZgZbj9AleCK0E8K7Jg3/+wS2BrMgDm4FZy+hYVm8wcNTJYNCzrI7R + gr/EYNjDOdmpgaGvwWWSX2Q7q9QawNYyDKOjSlAwlK3RqAEX/CW8+wOT+NphBmigBuyE + 1BTpU8lKQpun+CJvIrIJc05ubq6CYFMrgM0l9n7W37/t5wQ1+X0Q/E+qtFN14mf2vvv3 + T9Zd/4Dfp1i7UPABVwBXAFcAV4CyFfg/bog27wplbmRzdHJlYW0KZW5kb2JqCjQxIDAg + b2JqCjIzMjAKZW5kb2JqCjMxIDAgb2JqCjw8IC9MZW5ndGggMzIgMCBSIC9UeXBlIC9Y + T2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMjYwIC9IZWlnaHQgMjYwIC9Db2xv + clNwYWNlCi9EZXZpY2VHcmF5IC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxh + dGVEZWNvZGUgPj4Kc3RyZWFtCngB7d3/U1JZFADwvijyTURFVJKVomxxILQwU7I0Gr+3 + Wg4jfTOcMqNGLR1aR8sp1Cmx8kvluOZoTuygmWnqqG27s//anvuwTBcUFd6798L5JQ1K + +Hjuue894Jw9e8IRFggLhAXCAmGBsEBYICyAkcBeFPsgmC8wemAsPZTVZw8A+/cjBgj4 + K5Z+OBY/xvPr378/IiIiEgL+8EiEkAJaAAAAz57Hi4Lg8RAEwxAiqYCSAAHwovh8vkAg + FAoE8EUUOETAsgiJVGAIGAGBUCQSR0OIRSKhgFEIDQQggCTg8flCkVgiiZHGQkhjJBKx + SMjn81AqUJ8JHoIoEIiWSGPjZLIECJksLlYqiQaFqBBAWCUQQA5I42QJiUkKJpISE2Rx + UsgFAf0IHgK+QIQE5EmKFGWqCiJVmaJIkiMFkYBPeSasEghFkth4edIBpeqQ+kgaxBH1 + IZXyQJI8PlYC64FqhO8EYkmsLFGhVKnTNOla3bFjOm26Jk2tUioSZbESMdUIPwhi4hKS + U5CAVp95wpCVZTiRqdcihZTkhLgYmhF+IpArlAfTNLpMQ3auMQ/CmJttyNRp0g4qFXKa + EdYI4uWKX9RHtRmGU8az584XQpw/d9Z4ypChPar+RSGPpzYTfiJIVKSqNbrj2cZ8U1Fp + eQVEeWmRKd+YfVynUacqEmlFWE9wWKM35JwxFZdXVpktEOaqyvJi05kcg15zmFqEdQQq + RJCbX1hWabZcq7HW1lprrlnMlWWF+bkIQUVnJmwgSNdnGQuKL1RZrtfeqrfdvWurv1V7 + 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 + 1lyzmCvLCvNzYd4oedcO/SPYgJB6GBByzpiKyyurzBYIc1VlebHpTA4iSCXt8qm/BBsR + 1Brd8WxjvqmotLwCory0yJRvzD6u06gpJliHIIfJyUe1GYZTxrPnzhdCnD931njKkKE9 + CtOH5WRdRPc/C9A91wojTNBWHkzT6DIN2bnGPAhjbrYhU6dJO6hkRnET9DrC9gjWISQk + p6jUaRqtPvOEISvLcCJTr9WkqVUpyQlrI9lxfXF9u097/f1/ZAJM0U5UKJFCulZ37JhO + m44ElIpEmEBN0qtJ65+ef999R4BR4vHypANK1SH1kTSII+pDKuWBJHk8zF6meCF4kFYR + BCKJNE4mT1KkKFNVEKnKFEWSXBYnhYn0eL/LxL/f9eb38iBECURipJCQmKRgIikxAQmI + RWgMOcZvtNn8yfl76yoCXyiKlkhj42SyBAiZLC5WKomGdRAKBN93Bx4fFMQSSYw0FkIa + I4EcEPL5vBDIApQtkAkwJTGSF8UXCEUicTSEWCQSCvhRvEgYw47vO878TXV/7scgRDAK + fL5AIBQKBHw+IwClIDQIUCrsg1SAsS/gwIuC4EEGwCoAAW/Ddv1xJfA+KBUYhggEERkR + 4QEImSTw/Mr2ehgYCeQBAX9F4K9zlw8ZnrRHgvlil/9Z+J+HBcICYYGwQFggLBAWCAsE + VuA/SCo8XAplbmRzdHJlYW0KZW5kb2JqCjMyIDAgb2JqCjM3MTEKZW5kb2JqCjI5IDAg + b2JqCjw8IC9MZW5ndGggMzAgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFn + ZSAvV2lkdGggMjQyIC9IZWlnaHQgMTcwIC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5IC9C + aXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB + 7Z3/T1PXG8f5Uui329teaG/LbbuWWwq9LaW7AlZABwSCIuAXFFc3IWjVDAZ2GhuboQ7D + lNgogoPwJYqMiAYcAUOQEDWff+3znGK2UYpuv/Wsz/sH4k0weV7n/Zz3Ob0kfbKyULgC + uAK4ArgC9K5ANtX6V+sOpDl/KZcy/VV5DoD8A/AdWqBUKPIolkIBCAT+S9AJ3h3YfKVS + tSM1RfpUslKZD3YB9heYP/Hm5eUDrFqj0Wq1DMPoqBIUDGVrNGqVilB/npkA50IvAy7A + MjqW1RsMHHUyGPQsqwNuDUDvMO/T2glg8Jfw6lg9xxUUGo0mE8+bKRLPm0xGY2EBx+lZ + HWEGn6G1UyMTh4nBhNcAtLzZUiQIVpvNTpFsNqsgFFnMPFAbEsxgM0FOEdoJYNjAWgZ4 + ARdY7Q6ns1h0USWx2Ol02IEboIGZ0ZLtnBo5m+xhpRoM5gp5iwC0ostdWuaRJK/XR4m8 + XknylJW6XSJQCxa+kAOb1UqSX3tNBosBWKXV6TmjWbA7xZJSyVvuDwRkWT5AjaDYQMBf + 7pVKS0SnXTAbOb0OXM5TpOhrsBhCS5MAtjpEt8fnD8iV1QeDNbWgOipEKq0JHqyulAN+ + n8ctOqwJZA3EVwqTs8FilYZhOaPF6nCV+SrkqmBN3ZH6hsampqZmSgSlNjbUH6mrCVbJ + Fb4yl8NqMXIso1GBycltvWOxFoDNVmeJ5JerDtXVNza3HGtta+84QY062ttaj7U0N9bX + HaqS/VKJk7jMalOZTIihpw0A7CiRApXBww1NR493nOw803UuRJHOdZ3pPNlx/GhTw+Fg + ZUAqIY1t0IHJe9oamjpfpWULeMHhkiqqauubW9tPnw19393TeykcvkyJwuFLvT3d34fO + nm5vba6vraqQXA6BLyAm72nr7Bw4mcBii10s81fWNrS0neo6390bvtr348DgtQglujY4 + 8GPf1XBv9/muU20tDbWV/jLRbgGT4YRK3sikqWEX84LT7ZOD9S3tnaELF6/0DURu3Ize + ilGjW9GbNyIDfVcuXgh1trfUB2Wf2ynwZCdDW+++diWI9YVmu+ipqDrcDMA94b7B69HY + 0J27w/eo0fDdO0Ox6PXBvnAPIDcfrqrwiHZzoT4lcb6aMRiLHCU++VBD66lQz+X+SDR2 + Z3jk/ujDODV6OHp/ZPhOLBrpv9wTOtXacEj2lTiKjAZGnb/HY0W+WkeautRfVdfU0XUh + 3P9TdGj419H44yfjT6nR+JPH8dFfh4eiP/WHL3R1NNVV+UtJW+vUEF1JXa1QatgCs030 + BILfHD19/uIPkejQvQfxsYnJqZmZWUo0MzM1OTEWf3BvKBr54eL500e/CQY8os1cwGqU + KYi1LGxjl1euaTx+tvvKAACPPhqfnJ57Nv9igRK9mH82Nz05/mgUkAeudJ893lgje12w + kVltCmKIamPRV+7ySmjqUG/f9dgvDx5NTM0+X1h8ufSKEi29XFx4Pjs18ejBL7Hrfb0h + aOvKcvdXRUYI6z0ew+GkN5JtXH2k5eR34YHo7ZH4+NTc/O9Lr5dX3lCileXXS7/Pz02N + x0duRwfC351sOVJNNrKRhHXyPgZiAxCXBYL1xzq7r0Ziw6Njk7Pzi69W3qyurVOitdU3 + K68W52cnx0aHY5Gr3Z3H6oOBMiA2pCRmDCahGIKrofVMT9+Nn0fiE9PPAXh1/e0GNXq7 + vgrIz6cn4iM/3+jrOdPaANFVLJgMTCqPGc5kFaWvaxrbunr7b96+//i3uYWl5dX1jc13 + W5To3ebG+ury0sLcb4/v377Z39vV1ljztSRaTdw+xLxNlOTapvZzlwaid0fHpp4tvv5j + bWNza5sabW1urP3xevHZ1Njo3ejApXPtTbWyJNr4/YnhcALib8ODt4YfPpmef7m8+haA + 33+gRO+3tzbfri6/nJ9+8nD41mD4W0LsdX2RuCMUvha7F5+YebG0srbxDoA/UqIP77ff + baytLL2YmYjfi10Lw/G0HzF8WFQxHG9LeJyC+H9U6OPniXe998nOzYNrNVy5fAfqmk+E + LkfA46ezC6/erG9sbX/4SAUvFPnxw/bWxvqbVwuzT8HjyOXQiea6Az64dMHFOi8XidFj + 7Goa9jLuY0yuv70FwdMJz2MaYgtvIHjnwlsmfpLAz05UpDXeMvGWibdMfOuD77nSP64x + qzGrMasxqzGrMavTbwXwdMLTCU8nPJ3wdEq/bE6uCLMasxqzGrMaszo5GdPvGbMasxqz + GrMaszr9sjm5IsxqzGrMasxqzOrkZEy/Z8xqzGrMasxqzOr0y+bkijCrMasxqzGrMauT + kzH9njGrMasxqzGrMavTL5uTK8KsxqzGrMasxqxOTsb0e8asxqzGrMasxqxOv2xOrgiz + GrMasxqzGrM6ORnT7xmzGrMasxqz+r+d1Rn3bc5ZXyD+731j9y7ijPpW9kz75v2Mm66Q + cRM0Mm9KSqZNwlFk3LQjhTLjJlpl3tSyjJtMl5tx0wfJTM0MmzCZaVNEM29SbCZOA868 + ic9kcHsmTfXOyrjJ7UBMTNbo9GR2u0N0e3z+gFxZfTBYQ2be11EhUmlN8GB1pRzw+zxu + kQwx5/QwxTx/7xjzLCDOUeQpVdoEsmB3iiWlkrfcHwjIsnyAGkGxgYC/3CuVlohOu5AA + 1qqUeYqc5KHe8LIeTAZktVbHcoW8RbA7nKLLXVrmkSSv10eJvF5J8pSVul2i02EXLHwh + x+q0MMNcsWdSPfnrBJgMfQ0uM6yhwMibBasNqJ3FoosqicVOoLVZBTNvLDCwDDhMejqF + xZ+QobE1YLOhoBCgLUUCcNvsFMkGrEKRBXALgVen1UBL7weclZ1wGeIrwaznOKA2mkw8 + b6ZIPG8yGYGW4/QJXgitBPCuyYN//sEtgazIA5uBWcvoWFZvMHDUyWDQs6yO0YK/xGDY + wznZqYGhr8Flkl9kO6vUGsDWMgyjo0pQMJSt0agBF/wlvPsDk/jaYQZooAbshNQU6VPJ + SkKbp/gibyKyCXNObm6ugmBTK4DNJfZ+1t+/7ecENfl9EPxPqrRTdeJn9r7790/WXf+A + 36dYu1DwAVcAVwBXAFeAshX4P26INu8KZW5kc3RyZWFtCmVuZG9iagozMCAwIG9iagoy + MzIwCmVuZG9iagozOCAwIG9iago8PCAvTGVuZ3RoIDM5IDAgUiAvVHlwZSAvWE9iamVj + dCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRoIDI0MiAvSGVpZ2h0IDE3MCAvQ29sb3JTcGFj + ZQovRGV2aWNlR3JheSAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIgL0ZsYXRlRGVj + b2RlID4+CnN0cmVhbQp4Ae2d/09T1xvH+VLot9vbXmhvy227llsKvS2luwJWQAcEgiLg + FxRXNyFo1QwGdhobm6EOw5TYKIKD8CWKjIgGHAFDkBA1n3/t85xitlGKbr/1rM/7B+JN + MHle5/2c9zm9JH2yslC4ArgCuAK4AvSuQDbV+lfrDqQ5fymXMv1VeQ6A/APwHVqgVCjy + KJZCAQgE/kvQCd4d2HylUrUjNUX6VLJSmQ92AfYXmD/x5uXlA6xao9FqtQzD6KgSFAxl + azRqlYpQf56ZAOdCLwMuwDI6ltUbDBx1Mhj0LKsDbg1A7zDv09oJYPCX8OpYPccVFBqN + JhPPmykSz5tMRmNhAcfpWR1hBp+htVMjE4eJwYTXALS82VIkCFabzU6RbDarIBRZzDxQ + GxLMYDNBThHaCWDYwFoGeAEXWO0Op7NYdFElsdjpdNiBG6CBmdGS7ZwaOZvsYaUaDOYK + eYsAtKLLXVrmkSSv10eJvF5J8pSVul0iUAsWvpADm9VKkl97TQaLAVil1ek5o1mwO8WS + Uslb7g8EZFk+QI2g2EDAX+6VSktEp10wGzm9DlzOU6Toa7AYQkuTALY6RLfH5w/IldUH + gzW1oDoqRCqtCR6srpQDfp/HLTqsCWQNxFcKk7PBYpWGYTmjxepwlfkq5KpgTd2R+obG + pqamZkoEpTY21B+pqwlWyRW+MpfDajFyLKNRgcnJbb1jsRaAzVZnieSXqw7V1Tc2txxr + bWvvOEGNOtrbWo+1NDfW1x2qkv1SiZO4zGpTmUyIoacNAOwokQKVwcMNTUePd5zsPNN1 + LkSRznWd6TzZcfxoU8PhYGVAKiGNbdCByXvaGpo6X6VlC3jB4ZIqqmrrm1vbT58Nfd/d + 03spHL5MicLhS7093d+Hzp5ub22ur62qkFwOgS8gJu9p6+wcOJnAYotdLPNX1ja0tJ3q + Ot/dG77a9+PA4LUIJbo2OPBj39Vwb/f5rlNtLQ21lf4y0W4Bk+GESt7IpKlhF/OC0+2T + g/Ut7Z2hCxev9A1EbtyM3opRo1vRmzciA31XLl4Idba31Adln9sp8GQnQ1vvvnYliPWF + Zrvoqag63AzAPeG+wevR2NCdu8P3qNHw3TtDsej1wb5wDyA3H66q8Ih2c6E+JXG+mjEY + ixwlPvlQQ+upUM/l/kg0dmd45P7owzg1ejh6f2T4Tiwa6b/cEzrV2nBI9pU4iowGRp2/ + x2NFvlpHmrrUX1XX1NF1Idz/U3Ro+NfR+OMn40+p0fiTx/HRX4eHoj/1hy90dTTVVflL + SVvr1BBdSV2tUGrYArNN9ASC3xw9ff7iD5Ho0L0H8bGJyamZmVlKNDMzNTkxFn9wbyga + +eHi+dNHvwkGPKLNXMBqlCmItSxsY5dXrmk8frb7ygAAjz4an5yeezb/YoESvZh/Njc9 + Of5oFJAHrnSfPd5YI3tdsJFZbQpiiGpj0Vfu8kpo6lBv3/XYLw8eTUzNPl9YfLn0ihIt + vVxceD47NfHowS+x6329IWjrynL3V0VGCOs9HsPhpDeSbVx9pOXkd+GB6O2R+PjU3Pzv + S6+XV95QopXl10u/z89NjcdHbkcHwt+dbDlSTTaykYR18j4GYgMQlwWC9cc6u69GYsOj + Y5Oz84uvVt6srq1TorXVNyuvFudnJ8dGh2ORq92dx+qDgTIgNqQkZgwmoRiCq6H1TE/f + jZ9H4hPTzwF4df3tBjV6u74KyM+nJ+IjP9/o6znT2gDRVSyYDEwqjxnOZBWlr2sa27p6 + +2/evv/4t7mFpeXV9Y3Nd1uU6N3mxvrq8tLC3G+P79++2d/b1dZY87UkWk3cPsS8TZTk + 2qb2c5cGondHx6aeLb7+Y21jc2ubGm1tbqz98Xrx2dTY6N3owKVz7U21siTa+P2J4XAC + 4m/Dg7eGHz6Znn+5vPoWgN9/oETvt7c2364uv5yffvJw+NZg+FtC7HV9kbgjFL4Wuxef + mHmxtLK28Q6AP1KiD++3322srSy9mJmI34tdC8PxtB8xfFhUMRxvS3icgvh/VOjj54l3 + vffJzs2DazVcuXwH6ppPhC5HwOOnswuv3qxvbG1/+EgFLxT58cP21sb6m1cLs0/B48jl + 0InmugM+uHTBxTovF4nRY+xqGvYy7mNMrr+9BcHTCc9jGmILbyB458JbJn6SwM9OVKQ1 + 3jLxlom3THzrg++50j+uMasxqzGrMasxqzGr028F8HTC0wlPJzyd8HRKv2xOrgizGrMa + sxqzGrM6ORnT7xmzGrMasxqzGrM6/bI5uSLMasxqzGrMaszq5GRMv2fMasxqzGrMaszq + 9Mvm5IowqzGrMasxqzGrk5Mx/Z4xqzGrMasxqzGr0y+bkyvCrMasxqzGrMasTk7G9HvG + rMasxqzGrMasTr9sTq4IsxqzGrMasxqzOjkZ0+8ZsxqzGrMas/q/ndUZ923OWV8g/u99 + Y/cu4oz6VvZM++b9jJuukHETNDJvSkqmTcJRZNy0I4Uy4yZaZd7UsoybTJebcdMHyUzN + DJswmWlTRDNvUmwmTgPOvInPZHB7Jk31zsq4ye1ATEzW6PRkdrtDdHt8/oBcWX0wWENm + 3tdRIVJpTfBgdaUc8Ps8bpEMMef0MMU8f+8Y8ywgzlHkKVXaBLJgd4olpZK33B8IyLJ8 + gBpBsYGAv9wrlZaITruQANaqlHmKnOSh3vCyHkwGZLVWx3KFvEWwO5yiy11a5pEkr9dH + ibxeSfKUlbpdotNhFyx8IcfqtDDDXLFnUj356wSYDH0NLjOsocDImwWrDaidxaKLKonF + TqC1WQUzbywwsAw4THo6hcWfkKGxNWCzoaAQoC1FAnDb7BTJBqxCkQVwC4FXp9VAS+8H + nJWdcBniK8Gs5zigNppMPG+mSDxvMhmBluP0CV4IrQTwrsmDf/7BLYGsyAObgVnL6FhW + bzBw1Mlg0LOsjtGCv8Rg2MM52amBoa/BZZJfZDur1BrA1jIMo6NKUDCUrdGoARf8Jbz7 + A5P42mEGaKAG7ITUFOlTyUpCm6f4Im8isglzTm5uroJgUyuAzSX2ftbfv+3nBDX5fRD8 + T6q0U3XiZ/a++/dP1l3/gN+nWLtQ8AFXAFcAVwBXgLIV+D9uiDbvCmVuZHN0cmVhbQpl + bmRvYmoKMzkgMCBvYmoKMjMyMAplbmRvYmoKMzMgMCBvYmoKPDwgL0xlbmd0aCAzNCAw + IFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUgL0ltYWdlIC9XaWR0aCAyNDIgL0hlaWdo + dCAxNzAgL0NvbG9yU3BhY2UKL0RldmljZUdyYXkgL0JpdHNQZXJDb21wb25lbnQgOCAv + RmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAHtnf9PU9cbx/lS6Lfb215ob8tt + u5ZbCr0tpbsCVkAHBIIi4BcUVzchaNUMBnYaG5uhDsOU2CiCg/AlioyIBhwBQ5AQNZ9/ + 7fOcYrZRim6/9azP+wfiTTB5Xuf9nPc5vSR9srJQuAK4ArgCuAL0rkA21fpX6w6kOX8p + lzL9VXkOgPwD8B1aoFQo8iiWQgEIBP5L0AneHdh8pVK1IzVF+lSyUpkPdgH2F5g/8ebl + 5QOsWqPRarUMw+ioEhQMZWs0apWKUH+emQDnQi8DLsAyOpbVGwwcdTIY9CyrA24NQO8w + 79PaCWDwl/DqWD3HFRQajSYTz5spEs+bTEZjYQHH6VkdYQafobVTIxOHicGE1wC0vNlS + JAhWm81OkWw2qyAUWcw8UBsSzGAzQU4R2glg2MBaBngBF1jtDqezWHRRJbHY6XTYgRug + gZnRku2cGjmb7GGlGgzmCnmLALSiy11a5pEkr9dHibxeSfKUlbpdIlALFr6QA5vVSpJf + e00GiwFYpdXpOaNZsDvFklLJW+4PBGRZPkCNoNhAwF/ulUpLRKddMBs5vQ5czlOk6Guw + GEJLkwC2OkS3x+cPyJXVB4M1taA6KkQqrQkerK6UA36fxy06rAlkDcRXCpOzwWKVhmE5 + o8XqcJX5KuSqYE3dkfqGxqampmZKBKU2NtQfqasJVskVvjKXw2oxciyjUYHJyW29Y7EW + gM1WZ4nkl6sO1dU3Nrcca21r7zhBjTra21qPtTQ31tcdqpL9UomTuMxqU5lMiKGnDQDs + KJEClcHDDU1Hj3ec7DzTdS5Ekc51nek82XH8aFPD4WBlQCohjW3Qgcl72hqaOl+lZQt4 + weGSKqpq65tb20+fDX3f3dN7KRy+TInC4Uu9Pd3fh86ebm9trq+tqpBcDoEvICbvaevs + HDiZwGKLXSzzV9Y2tLSd6jrf3Ru+2vfjwOC1CCW6NjjwY9/VcG/3+a5TbS0NtZX+MtFu + AZPhhEreyKSpYRfzgtPtk4P1Le2doQsXr/QNRG7cjN6KUaNb0Zs3IgN9Vy5eCHW2t9QH + ZZ/bKfBkJ0Nb7752JYj1hWa76KmoOtwMwD3hvsHr0djQnbvD96jR8N07Q7Ho9cG+cA8g + Nx+uqvCIdnOhPiVxvpoxGIscJT75UEPrqVDP5f5INHZneOT+6MM4NXo4en9k+E4sGum/ + 3BM61dpwSPaVOIqMBkadv8djRb5aR5q61F9V19TRdSHc/1N0aPjX0fjjJ+NPqdH4k8fx + 0V+Hh6I/9YcvdHU01VX5S0lb69QQXUldrVBq2AKzTfQEgt8cPX3+4g+R6NC9B/Gxicmp + mZlZSjQzMzU5MRZ/cG8oGvnh4vnTR78JBjyizVzAapQpiLUsbGOXV65pPH62+8oAAI8+ + Gp+cnns2/2KBEr2YfzY3PTn+aBSQB650nz3eWCN7XbCRWW0KYohqY9FX7vJKaOpQb9/1 + 2C8PHk1MzT5fWHy59IoSLb1cXHg+OzXx6MEvset9vSFo68py91dFRgjrPR7D4aQ3km1c + faTl5Hfhgejtkfj41Nz870uvl1feUKKV5ddLv8/PTY3HR25HB8LfnWw5Uk02spGEdfI+ + BmIDEJcFgvXHOruvRmLDo2OTs/OLr1berK6tU6K11TcrrxbnZyfHRodjkavdncfqg4Ey + IDakJGYMJqEYgquh9UxP342fR+IT088BeHX97QY1eru+CsjPpyfiIz/f6Os509oA0VUs + mAxMKo8ZzmQVpa9rGtu6evtv3r7/+Le5haXl1fWNzXdblOjd5sb66vLSwtxvj+/fvtnf + 29XWWPO1JFpN3D7EvE2U5Nqm9nOXBqJ3R8emni2+/mNtY3NrmxptbW6s/fF68dnU2Ojd + 6MClc+1NtbIk2vj9ieFwAuJvw4O3hh8+mZ5/ubz6FoDff6BE77e3Nt+uLr+cn37ycPjW + YPhbQux1fZG4IxS+FrsXn5h5sbSytvEOgD9Sog/vt99trK0svZiZiN+LXQvD8bQfMXxY + VDEcb0t4nIL4f1To4+eJd733yc7Ng2s1XLl8B+qaT4QuR8Djp7MLr96sb2xtf/hIBS8U + +fHD9tbG+ptXC7NPwePI5dCJ5roDPrh0wcU6LxeJ0WPsahr2Mu5jTK6/vQXB0wnPYxpi + C28geOfCWyZ+ksDPTlSkNd4y8ZaJt0x864PvudI/rjGrMasxqzGrMasxq9NvBfB0wtMJ + Tyc8nfB0Sr9sTq4IsxqzGrMasxqzOjkZ0+8ZsxqzGrMasxqzOv2yObkizGrMasxqzGrM + 6uRkTL9nzGrMasxqzGrM6vTL5uSKMKsxqzGrMasxq5OTMf2eMasxqzGrMasxq9Mvm5Mr + wqzGrMasxqzGrE5OxvR7xqzGrMasxqzGrE6/bE6uCLMasxqzGrMaszo5GdPvGbMasxqz + GrP6v53VGfdtzllfIP7vfWP3LuKM+lb2TPvm/YybrpBxEzQyb0pKpk3CUWTctCOFMuMm + WmXe1LKMm0yXm3HTB8lMzQybMJlpU0Qzb1JsJk4DzryJz2RweyZN9c7KuMntQExM1uj0 + ZHa7Q3R7fP6AXFl9MFhDZt7XUSFSaU3wYHWlHPD7PG6RDDHn9DDFPH/vGPMsIM5R5ClV + 2gSyYHeKJaWSt9wfCMiyfIAaQbGBgL/cK5WWiE67kADWqpR5ipzkod7wsh5MBmS1Vsdy + hbxFsDucostdWuaRJK/XR4m8XknylJW6XaLTYRcsfCHH6rQww1yxZ1I9+esEmAx9DS4z + rKHAyJsFqw2oncWiiyqJxU6gtVkFM28sMLAMOEx6OoXFn5ChsTVgs6GgEKAtRQJw2+wU + yQasQpEFcAuBV6fVQEvvB5yVnXAZ4ivBrOc4oDaaTDxvpkg8bzIZgZbj9AleCK0E8K7J + g3/+wS2BrMgDm4FZy+hYVm8wcNTJYNCzrI7Rgr/EYNjDOdmpgaGvwWWSX2Q7q9QawNYy + DKOjSlAwlK3RqAEX/CW8+wOT+NphBmigBuyE1BTpU8lKQpun+CJvIrIJc05ubq6CYFMr + gM0l9n7W37/t5wQ1+X0Q/E+qtFN14mf2vvv3T9Zd/4Dfp1i7UPABVwBXAFcAV4CyFfg/ + bog27wplbmRzdHJlYW0KZW5kb2JqCjM0IDAgb2JqCjIzMjAKZW5kb2JqCjI2IDAgb2Jq + Cjw8IC9MZW5ndGggMjcgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAv + V2lkdGggMjYwIC9IZWlnaHQgMjYwIC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5IC9CaXRz + UGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7d3/ + U1JZFADwvijyTURFVJKVomxxILQwU7I0Gr+3Wg4jfTOcMqNGLR1aR8sp1Cmx8kvluOZo + TuygmWnqqG27s//anvuwTBcUFd6798L5JQ1K+Hjuue894Jw9e8IRFggLhAXCAmGBsEBY + ICyAkcBeFPsgmC8wemAsPZTVZw8A+/cjBgj4K5Z+OBY/xvPr378/IiIiEgL+8EiEkAJa + AAAAz57Hi4Lg8RAEwxAiqYCSAAHwovh8vkAgFAoE8EUUOETAsgiJVGAIGAGBUCQSR0OI + RSKhgFEIDQQggCTg8flCkVgiiZHGQkhjJBKxSMjn81AqUJ8JHoIoEIiWSGPjZLIECJks + LlYqiQaFqBBAWCUQQA5I42QJiUkKJpISE2RxUsgFAf0IHgK+QIQE5EmKFGWqCiJVmaJI + kiMFkYBPeSasEghFkth4edIBpeqQ+kgaxBH1IZXyQJI8PlYC64FqhO8EYkmsLFGhVKnT + NOla3bFjOm26Jk2tUioSZbESMdUIPwhi4hKSU5CAVp95wpCVZTiRqdcihZTkhLgYmhF+ + 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 + N8LthpbWDkf3c2dvr/N5t6OjtaXhNqUE3hFKL1pu1N17YG/reOro6nI87WizP7hXd8Ny + sZTQ6wW+F4LnFm+HzSWV1TU3bY3N9ta29va2Vntzo+1mTXVlCaUE3jLhtKmkwnzVWmdr + uN/c0tJ8v8FWZ71qrigxnSbyqtFWWYBu35gJ+ixjQfGFKsv12lv1trt3bfW3aq9bqi4U + Fxiz9AReOPOH4H8IMCc1N7+wrNJsuVZjra211lyzmCvLCvNzYd4oedcO/SPYgJB6GBBy + zpiKyyurzBYIc1VlebHpTA4iSCXt8qm/BBsR1Brd8WxjvqmotLwCory0yJRvzD6u06gp + JliHIIfJyUe1GYZTxrPnzhdCnD931njKkKE9CtOH5WRdRPc/C9A91wojTNBWHkzT6DIN + 2bnGPAhjbrYhU6dJO6hkRnET9DrC9gjWISQkp6jUaRqtPvOEISvLcCJTr9WkqVUpyQlr + I9lxfXF9u097/f1/ZAJM0U5UKJFCulZ37JhOm44ElIpEmEBN0qtJ65+ef999R4BR4vHy + pANK1SH1kTSII+pDKuWBJHk8zF6meCF4kFYRBCKJNE4mT1KkKFNVEKnKFEWSXBYnhYn0 + eL/LxL/f9eb38iBECURipJCQmKRgIikxAQmIRWgMOcZvtNn8yfl76yoCXyiKlkhj42Sy + BAiZLC5WKomGdRAKBN93Bx4fFMQSSYw0FkIaI4EcEPL5vBDIApQtkAkwJTGSF8UXCEUi + cTSEWCQSCvhRvEgYw47vO878TXV/7scgRDAKfL5AIBQKBHw+IwClIDQIUCrsg1SAsS/g + wIuC4EEGwCoAAW/Ddv1xJfA+KBUYhggEERkR4QEImSTw/Mr2ehgYCeQBAX9F4K9zlw8Z + nrRHgvlil/9Z+J+HBcICYYGwQFggLBAWCAsEVuA/SCo8XAplbmRzdHJlYW0KZW5kb2Jq + CjI3IDAgb2JqCjM3MTEKZW5kb2JqCjM2IDAgb2JqCjw8IC9MZW5ndGggMzcgMCBSIC9U + eXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMjQyIC9IZWlnaHQgMTcw + IC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5IC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRl + 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 + d8WApwNg7RWwTOERxyzfdfIhsJoEigOEEgkxgh7Swj4XFdV0LFWuxucqS770/x56u8uz + 8mOSzwljPbfK+TzHd9PJlwTbvWJGcKO1mBVcry2sCO5r6ZzghrVYELxRW84LVo1yUbDZ + 9u/+71qpoV+1M0NPXytVhN/qFsqCb3dWhv66ujDcm9HOed+Tn7PlZIf7RxEKVJhwYHGW + UUUcc6iADQ3uJVchN83rOEbIvNnWB57yZzjqpn/e6Y65ZbWamiPP86tUo3LWUC5H5Xgs + dg2/AEmasesKZW5kc3RyZWFtCmVuZG9iago0MyAwIG9iago1NjMKZW5kb2JqCjM1IDAg + b2JqClsgL0lDQ0Jhc2VkIDQyIDAgUiBdCmVuZG9iago0NCAwIG9iago8PCAvTGVuZ3Ro + IDQ1IDAgUiAvTiAzIC9BbHRlcm5hdGUgL0RldmljZVJHQiAvRmlsdGVyIC9GbGF0ZURl + Y29kZSA+PgpzdHJlYW0KeAGtkz9oE1Ecx7+XFC1YI7TVQSjcYMEhakg66GSaNC1pJQ35 + 00S39HLJpeYux90ltsEhg6uzgzqIS4eiq8VFEcTFoSiiuDq4dOkgBSnn9+58iYPFxR+8 + e598832/37vfeweED2um2Q4B0A3HKiyl5OrNW/LJLziFKY4ZTNQU25zP52/Qckz8+ATJ + ++vDJS/XpmonIntXHu9v7KbvPS+/OGaRkCMWCwJSlMJ0M+Ckx+sBlzy+45gOPZrHilar + k++So1apkCZvkyPNgL16kfWA33ncU5re2s/kmFFvGUBonHy1rtoKOUnW6raik5lHCul6 + h/nDO9QvKqbFteGP5AteXzgzts4A1x/Q/3qkVd8CO8+Ac/sjbZbeqa/Abm+kHRz6vZJm + vtmNRNxPJ51+Apzou+7BWWCctY/WXPdnynWPWHuMSV7eV7pWz/dyg9J74F+/g3cOsgN7 + zMPwz+jvHPTFd8WApwNg7RWwTOERxyzfdfIhsJoEigOEEgkxgh7Swj4XFdV0LFWuxucq + S770/x56u8uz8mOSzwljPbfK+TzHd9PJlwTbvWJGcKO1mBVcry2sCO5r6ZzghrVYELxR + W84LVo1yUbDZ9u/+71qpoV+1M0NPXytVhN/qFsqCb3dWhv66ujDcm9HOed+Tn7PlZIf7 + RxEKVJhwYHGWUUUcc6iADQ3uJVchN83rOEbIvNnWB57yZzjqpn/e6Y65ZbWamiPP86tU + o3LWUC5H5Xgsdg2/AEmasesKZW5kc3RyZWFtCmVuZG9iago0NSAwIG9iago1NjMKZW5k + b2JqCjI1IDAgb2JqClsgL0lDQ0Jhc2VkIDQ0IDAgUiBdCmVuZG9iago0NiAwIG9iago8 + PCAvTGVuZ3RoIDQ3IDAgUiAvTiAzIC9BbHRlcm5hdGUgL0RldmljZVJHQiAvRmlsdGVy + IC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAGFlE1IFGEYx/+zjQSxBtGXCMXQwSRUJgtS + AtP1K1O2ZdVMCWKdfXedHGenmd0tRSKE6Jh1jC5WRIeITuGhQ6c6RASZdYmgo0UQBV4i + tv87k7tjVL4wM795nv/7fL3DAFWPUo5jRTRgys67yd6Ydnp0TNv8GlWoRhRcKcNzOhKJ + AZ+plc/1a/UtFGlZapSx1vs2fKt2mRBQNCp3ZAM+LHk84OOSL+SdPDVnJBsTqTTZITe4 + Q8lO8i3y1myIx0OcFp4BVLVTkzMcl3EiO8gtRSMrYz4g63batMnvpT3tGVPUsN/INzkL + 2rjy/UDbHmDTi4ptzAMe3AN211Vs9TXAzhFg8VDF9j3pz0fZ9crLHGr2wynRGGv6UCp9 + rwM23wB+Xi+VftwulX7eYQ7W8dQyCm7R17Iw5SUQ1BvsZvzkGv2Lg558VQuwwDmObAH6 + rwA3PwL7HwLbHwOJamCoFZHLbDe48uIi5wJ05pxp18xO5LVmXT+idfBohdZnG00NWsqy + NN/laa7whFsU6SZMWQXO2V/beI8Ke3iQT/YXuSS87t+szKVTXZwlmtjWp7To6iY3kO9n + zJ4+cj2v9xm3Zzhg5YCZ7xsKOHLKtuI8F6mJ1Njj8ZNkxldUJx+T85A85xUHZUzffi51 + IkGupT05meuXml3c2z4zMcQzkqxYMxOd8d/8xi0kZd591Nx1LP+bZ22RZxiFBQETNu82 + NCTRixga4cBFDhl6TCpMWqVf0GrCw+RflRYS5V0WFb1Y4Z4Vf895FLhbxj+FWBxzDeUI + mv5O/6Iv6wv6Xf3zfG2hvuKZc8+axqtrXxlXZpbVyLhBjTK+rCmIb7DaDnotZGmd4hX0 + 5JX1jeHqMvZ8bdmjyRzianw11KUIZWrEOOPJrmX3RbLFN+HnW8v2r+lR+3z2SU0l17K6 + eGYp+nw2XA1r/7OrYNKyq/DkjZAuPGuh7lUPqn1qi9oKTT2mtqttahffjqoD5R3DnJWJ + C6zbZfUp9mBjmt7KSVdmi+Dfwi+G/6VeYQvXNDT5D024uYxpCd8R3DZwh5T/w1+zAw3e + CmVuZHN0cmVhbQplbmRvYmoKNDcgMCBvYmoKNzkyCmVuZG9iago4IDAgb2JqClsgL0lD + Q0Jhc2VkIDQ2IDAgUiBdCmVuZG9iago0OCAwIG9iago8PCAvTGVuZ3RoIDQ5IDAgUiAv + TiAzIC9BbHRlcm5hdGUgL0RldmljZVJHQiAvRmlsdGVyIC9GbGF0ZURlY29kZSA+Pgpz + dHJlYW0KeAGtkz9oE1Ecx7+XFC1YI7TVQSjcYMEhakg66GSaNC1pJQ3500S39HLJpeYu + x90ltsEhg6uzgzqIS4eiq8VFEcTFoSiiuDq4dOkgBSnn9+58iYPFxR+8e598832/37vf + eweED2um2Q4B0A3HKiyl5OrNW/LJLziFKY4ZTNQU25zP52/Qckz8+ATJ++vDJS/Xpmon + IntXHu9v7KbvPS+/OGaRkCMWCwJSlMJ0M+Ckx+sBlzy+45gOPZrHilark++So1apkCZv + kyPNgL16kfWA33ncU5re2s/kmFFvGUBonHy1rtoKOUnW6raik5lHCul6h/nDO9QvKqbF + teGP5AteXzgzts4A1x/Q/3qkVd8CO8+Ac/sjbZbeqa/Abm+kHRz6vZJmvtmNRNxPJ51+ + Apzou+7BWWCctY/WXPdnynWPWHuMSV7eV7pWz/dyg9J74F+/g3cOsgN7zMPwz+jvHPTF + d8WApwNg7RWwTOERxyzfdfIhsJoEigOEEgkxgh7Swj4XFdV0LFWuxucqS770/x56u8uz + 8mOSzwljPbfK+TzHd9PJlwTbvWJGcKO1mBVcry2sCO5r6ZzghrVYELxRW84LVo1yUbDZ + 9u/+71qpoV+1M0NPXytVhN/qFsqCb3dWhv66ujDcm9HOed+Tn7PlZIf7RxEKVJhwYHGW + UUUcc6iADQ3uJVchN83rOEbIvNnWB57yZzjqpn/e6Y65ZbWamiPP86tUo3LWUC5H5Xgs + dg2/AEmasesKZW5kc3RyZWFtCmVuZG9iago0OSAwIG9iago1NjMKZW5kb2JqCjI4IDAg + b2JqClsgL0lDQ0Jhc2VkIDQ4IDAgUiBdCmVuZG9iago1MCAwIG9iago8PCAvTGVuZ3Ro + IDUxIDAgUiAvTiAxIC9BbHRlcm5hdGUgL0RldmljZUdyYXkgL0ZpbHRlciAvRmxhdGVE + ZWNvZGUgPj4Kc3RyZWFtCngBhVJPSBRRHP7NNhKEiEGFeIh3CgmVKaysoNp2dVmVbVuV + 0qIYZ9+6o7Mz05vZNcWTBF2iPHUPomN07NChm5eiwKxL1yCpIAg8dej7zezqKIRveTvf + +/39ft97RG2dpu87KUFUc0OVK6Wnbk5Ni4MfKUUd1E5YphX46WJxjLHruZK/u9fWZ9LY + st7HtXb79j21lWVgIeottrcQ+iGRZgAfmZ8oZYCzwB2Wr9g+ATxYDqwa8COiAw+auTDT + 0Zx0pbItkVPmoigqr2I7Sa77+bnGvou1iYP+XI9m1o69s+qq0UzUtPdEobwPrkQZz19U + 9mw1FKcN45xIQxop8q7V3ytMxxGRKxBKBlI1ZLmfak6ddeB1GLtdupPj+PYQpT7JYKiJ + temymR2FfQB2KsvsEPAF6PGyYg/ngXth/1tRw5PAJ2E/ZId51q0f9heuU+B7hD014M4U + rsXx2oofXi0BQ/dUI2iMc03E09c5c6SI7zHUGZj3RjmmCzF3lqoTN4A7YR9ZqmYKsV37 + ruol7nsCd9PjO9GbOQtcoBxJcrEV2RTQPAlYFH2LsEkOPD7OHlXgd6iYwBy5idzNKPce + 1REbZ6NSgVZ6jVfGT+O58cX4ZWwYz4B+rHbXe3z/6eMVdde2Pjz5jXrcOa69nRtVYVZx + ZQvd/8cyhI/ZJzmmwdOhWVhr2HbkD5rMTLAMKMR/BT6X+pITVdzV7u24RRLMUD4sbCW6 + S1RuKdTqPYNKrBwr2AB2cJLELFocuFNrujl4d9giem35TVey64b++vZ6+9ryHm3KqCko + E82zRGaUsVuj5N142/1mkRGfODq+572KWsn+SUUQP4U5WiryFFX0VlDWxG9nDn4btn5c + P6Xn9UH9PAk9rZ/Rr+ijEb4MdEnPwnNRH6NJ8LBpIeISoIqDM9ROVGONA+Ip8fK0W2SR + /Q9AGf1mCmVuZHN0cmVhbQplbmRvYmoKNTEgMCBvYmoKNzA0CmVuZG9iagoyMyAwIG9i + agpbIC9JQ0NCYXNlZCA1MCAwIFIgXQplbmRvYmoKNCAwIG9iago8PCAvVHlwZSAvUGFn + ZXMgL01lZGlhQm94IFswIDAgNjEyIDc5Ml0gL0NvdW50IDEgL0tpZHMgWyAzIDAgUiBd + ID4+CmVuZG9iago1MiAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvT3V0bGluZXMgMiAw + IFIgL1BhZ2VzIDQgMCBSIC9WZXJzaW9uIC8xLjQgPj4KZW5kb2JqCjIgMCBvYmoKPDwg + L0xhc3QgNTMgMCBSIC9GaXJzdCA1NCAwIFIgPj4KZW5kb2JqCjU0IDAgb2JqCjw8IC9D + b3VudCAwIC9EZXN0IFsgMyAwIFIgL1hZWiAwIDU1MyAwIF0gL1RpdGxlIChDYW52YXMg + MSkgPj4KZW5kb2JqCjUzIDAgb2JqCjw8IC9Db3VudCAwIC9EZXN0IFsgMyAwIFIgL1hZ + WiAwIDU1MyAwIF0gL1RpdGxlIChDYW52YXMgMSkgPj4KZW5kb2JqCjU1IDAgb2JqCjw8 + IC9MZW5ndGggNTYgMCBSIC9MZW5ndGgxIDE0NTA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2Rl + ID4+CnN0cmVhbQp4Ab17eWBVxfX/zN3fvu97Xt6WfSchgTxCFrZEFpUECSZAICAoIEZB + oFGBQEQUkUXAXVnFhBDlAYVSDCLWKlpxwb2Ctbapbb+oLZD7vmfuCxGs3/78o7++++7M + 3Lnz5p45c+aczzl3HsIIISVqRTSKTpvbOO+Nz49+BDWvI4T101oWeh/449DHofwZQvSc + GfNmztV99vJrCLFjEJIrZ85ZNGNeZ+VvENLUIuS/q7mpcfr/PP+XcoRyTkMfBc1QIU/i + hyGUK8B1cvPchXe9wKlnwHUaXD8757ZpjTuf7XoSrkn76+c23jVPeED+T4TykuHae2vj + 3KYJi5rb4Rr6REnzbrt9IeNgH4TrZrheOG9B07xf3ndrNlwDzfSbUIfhIB8lFDmp9G+T + RGOEKJo0YxDL8VJ7Qi58ZEiOFIkipEqVWoOQVjdQAQW9wWgyW6w2O3I4XW6PF/mS/MmB + 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 + u+quNIW44P/js/AOaNBUlkos6/6WebNnSFv7/RVNDbDDv/P+FvirRetUr3ff7HnkBtlT + 3jB1WjPJG5s65/mbyjtn+8u9+1qk3/3o9gxyu8Vfvg/NqLi+dt+MaFN5V0u0pYL8xWH/ + 1LIF9dc8a/XAsxaU/cSzykhnC8izpkq/+9Gz6sntqeRZ9eRZ9eRZU6NTpWcRFlTMmlB2 + +0KQTtj+D9vvwxM6R46bVAv/cqkrj+Ht5D8Bd6D/BVDOTaIKZW5kc3RyZWFtCmVuZG9i + ago1NiAwIG9iagoxMDA3MQplbmRvYmoKNTcgMCBvYmoKPDwgL1R5cGUgL0ZvbnREZXNj + cmlwdG9yIC9Bc2NlbnQgNzcwIC9DYXBIZWlnaHQgNjg0IC9EZXNjZW50IC0yMzAgL0Zs + YWdzIDMyCi9Gb250QkJveCBbNSAtMjIxIDc2OCA3MzddIC9Gb250TmFtZSAvQk5OUkxV + K0hlbHZldGljYSAvSXRhbGljQW5nbGUgMCAvU3RlbVYKMCAvTWF4V2lkdGggMTUwMCAv + WEhlaWdodCA1MTMgL0ZvbnRGaWxlMiA1NSAwIFIgPj4KZW5kb2JqCjU4IDAgb2JqClsg + Mjc4IDAgMCAwIDAgMCAwIDAgMzMzIDMzMyAwIDAgMCAwIDI3OCAwIDU1NiA1NTYgNTU2 + IDAgMCAwIDAgMCA1NTYgMCAwIDAKMCAwIDAgNTU2IDAgNjY3IDAgNzIyIDAgMCAwIDAg + MCAwIDAgMCAwIDgzMyA3MjIgNzc4IDY2NyAwIDAgNjY3IDYxMSAwIDAgMAowIDAgMCAw + IDAgMCAwIDAgMCA1NTYgNTU2IDUwMCA1NTYgNTU2IDI3OCA1NTYgNTU2IDIyMiAwIDUw + MCAyMjIgODMzIDU1NiA1NTYKNTU2IDAgMzMzIDUwMCAyNzggNTU2IDUwMCA3MjIgMCA1 + MDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMAowIDAgMCAwIDAg + MCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAw + IDAgMCAwIDAgMCAwCjAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAg + MCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAKMCAwIDAgMCAwIDAgMCA1 + MDAgXQplbmRvYmoKMjQgMCBvYmoKPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1RydWVU + eXBlIC9CYXNlRm9udCAvQk5OUkxVK0hlbHZldGljYSAvRm9udERlc2NyaXB0b3IKNTcg + MCBSIC9XaWR0aHMgNTggMCBSIC9GaXJzdENoYXIgMzIgL0xhc3RDaGFyIDIyMiAvRW5j + b2RpbmcgL01hY1JvbWFuRW5jb2RpbmcKPj4KZW5kb2JqCjEgMCBvYmoKPDwgL1RpdGxl + IChVbnRpdGxlZCkgL0F1dGhvciAoYnJhbmRvbmgpIC9DcmVhdG9yIChPbW5pR3JhZmZs + ZSkgL1Byb2R1Y2VyIChNYWMgT1MgWCAxMC41LjggUXVhcnR6IFBERkNvbnRleHQpCi9D + cmVhdGlvbkRhdGUgKEQ6MjAwOTExMjAyMzExMTVaMDAnMDAnKSAvTW9kRGF0ZSAoRDoy + MDA5MTEyMDIzMTExNVowMCcwMCcpCj4+CmVuZG9iagp4cmVmCjAgNTkKMDAwMDAwMDAw + MCA2NTUzNSBmIAowMDAwMDQ0NDU1IDAwMDAwIG4gCjAwMDAwMzMxOTAgMDAwMDAgbiAK + MDAwMDAwMTYyNCAwMDAwMCBuIAowMDAwMDMzMDI3IDAwMDAwIG4gCjAwMDAwMDAwMjIg + MDAwMDAgbiAKMDAwMDAwMTYwNCAwMDAwMCBuIAowMDAwMDAxNzI4IDAwMDAwIG4gCjAw + MDAwMzE0MDMgMDAwMDAgbiAKMDAwMDAwMTk2MSAwMDAwMCBuIAowMDAwMDAzMDUxIDAw + MDAwIG4gCjAwMDAwMDY0NzcgMDAwMDAgbiAKMDAwMDAwNzIyMiAwMDAwMCBuIAowMDAw + MDA1NzEyIDAwMDAwIG4gCjAwMDAwMDY0NTcgMDAwMDAgbiAKMDAwMDAwMzgzNiAwMDAw + MCBuIAowMDAwMDA0OTI3IDAwMDAwIG4gCjAwMDAwMDQ5NDcgMDAwMDAgbiAKMDAwMDAw + NTY5MiAwMDAwMCBuIAowMDAwMDAzMDcxIDAwMDAwIG4gCjAwMDAwMDM4MTYgMDAwMDAg + biAKMDAwMDAwNzI0MiAwMDAwMCBuIAowMDAwMDA3OTg3IDAwMDAwIG4gCjAwMDAwMzI5 + OTAgMDAwMDAgbiAKMDAwMDA0NDI4MCAwMDAwMCBuIAowMDAwMDMwNDUxIDAwMDAwIG4g + CjAwMDAwMjE5NzMgMDAwMDAgbiAKMDAwMDAyNTg1OCAwMDAwMCBuIAowMDAwMDMyMTI1 + IDAwMDAwIG4gCjAwMDAwMTQ0MjggMDAwMDAgbiAKMDAwMDAxNjkyMiAwMDAwMCBuIAow + MDAwMDEwNTIyIDAwMDAwIG4gCjAwMDAwMTQ0MDcgMDAwMDAgbiAKMDAwMDAxOTQ1OCAw + MDAwMCBuIAowMDAwMDIxOTUyIDAwMDAwIG4gCjAwMDAwMjk3MjggMDAwMDAgbiAKMDAw + MDAyNTg3OSAwMDAwMCBuIAowMDAwMDI5MDIxIDAwMDAwIG4gCjAwMDAwMTY5NDMgMDAw + MDAgbiAKMDAwMDAxOTQzNyAwMDAwMCBuIAowMDAwMDA4MDA3IDAwMDAwIG4gCjAwMDAw + MTA1MDEgMDAwMDAgbiAKMDAwMDAyOTA0MiAwMDAwMCBuIAowMDAwMDI5NzA4IDAwMDAw + IG4gCjAwMDAwMjk3NjUgMDAwMDAgbiAKMDAwMDAzMDQzMSAwMDAwMCBuIAowMDAwMDMw + NDg4IDAwMDAwIG4gCjAwMDAwMzEzODMgMDAwMDAgbiAKMDAwMDAzMTQzOSAwMDAwMCBu + IAowMDAwMDMyMTA1IDAwMDAwIG4gCjAwMDAwMzIxNjIgMDAwMDAgbiAKMDAwMDAzMjk3 + MCAwMDAwMCBuIAowMDAwMDMzMTEwIDAwMDAwIG4gCjAwMDAwMzMzMTYgMDAwMDAgbiAK + MDAwMDAzMzIzOCAwMDAwMCBuIAowMDAwMDMzMzk0IDAwMDAwIG4gCjAwMDAwNDM1NTYg + MDAwMDAgbiAKMDAwMDA0MzU3OCAwMDAwMCBuIAowMDAwMDQzNzk4IDAwMDAwIG4gCnRy + YWlsZXIKPDwgL1NpemUgNTkgL1Jvb3QgNTIgMCBSIC9JbmZvIDEgMCBSIC9JRCBbIDw0 + MjZkMDljZjFjMDY3M2I0NTU4MGUzOGJlY2FkZWY4OD4KPDQyNmQwOWNmMWMwNjczYjQ1 + NTgwZTM4YmVjYWRlZjg4PiBdID4+CnN0YXJ0eHJlZgo0NDY1NwolJUVPRgoxIDAgb2Jq + Cjw8L0F1dGhvciAoYnJhbmRvbmgpL0NyZWF0aW9uRGF0ZSAoRDoyMDA5MTEyMDIyNTQw + MFopL0NyZWF0b3IgKE9tbmlHcmFmZmxlIDUuMi4xKS9Nb2REYXRlIChEOjIwMDkxMTIw + MjMxMTAwWikvUHJvZHVjZXIgKE1hYyBPUyBYIDEwLjUuOCBRdWFydHogUERGQ29udGV4 + dCkvVGl0bGUgKHBhY2tldF9mbG93X2Zsb3djaGFydCk+PgplbmRvYmoKeHJlZgoxIDEK + MDAwMDA0NTk5NSAwMDAwMCBuIAp0cmFpbGVyCjw8L0lEIFs8NDI2ZDA5Y2YxYzA2NzNi + NDU1ODBlMzhiZWNhZGVmODg+IDw0MjZkMDljZjFjMDY3M2I0NTU4MGUzOGJlY2FkZWY4 + OD5dIC9JbmZvIDEgMCBSIC9QcmV2IDQ0NjU3IC9Sb290IDUyIDAgUiAvU2l6ZSA1OT4+ + CnN0YXJ0eHJlZgo0NjE5NwolJUVPRgo= + + QuickLookThumbnail + + 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 + Yy4sIDIwMDkA + + ReadOnly + NO + RowAlign + 1 + RowSpacing + 36 + SheetTitle + Canvas 1 + SmartAlignmentGuidesActive + YES + SmartDistanceGuidesActive + YES + UniqueID + 1 + UseEntirePage + + VPages + 1 + WindowInfo + + CurrentSheet + 0 + ExpandedCanvases + + + name + Canvas 1 + + + FitInWindow + + Frame + {{759, 198}, {710, 887}} + ListView + + OutlineWidth + 142 + RightSidebar + + ShowRuler + + Sidebar + + SidebarWidth + 120 + VisibleRegion + {{0, -204}, {754.688, 962.062}} + Zoom + 0.76190477609634399 + ZoomValues + + + Canvas 1 + 0.0 + 1 + + + + saveQuickLookFiles + YES + + diff --git a/openflow/hw-lib/automake.mk b/openflow/hw-lib/automake.mk new file mode 100644 index 00000000..204e1217 --- /dev/null +++ b/openflow/hw-lib/automake.mk @@ -0,0 +1,28 @@ +# +# Hardware library dependency file definitions. +# + +if NF2 +# +# NetFPGA hardware library +# +noinst_LIBRARIES += hw-lib/libnf2.a + +hw_lib_libnf2_a_SOURCES = \ + hw-lib/nf2/hw_flow.c \ + hw-lib/nf2/hw_flow.h \ + hw-lib/nf2/nf2_lib.c \ + hw-lib/nf2/nf2_lib.h \ + hw-lib/nf2/nf2_drv.c \ + hw-lib/nf2/nf2_drv.h \ + hw-lib/nf2/nf2.h \ + hw-lib/nf2/debug.h \ + hw-lib/nf2/reg_defines_openflow_switch.h \ + hw-lib/nf2/nf2util.c \ + hw-lib/nf2/nf2util.h + +hw_lib_nf2_a_CPPFLAGS = $(AM_CPPFLAGS) $(OF_CPP_FLAGS) -DHWTABLE_NO_DEBUG +hw_lib_nf2_a_CPPFLAGS += -I hw-lib/nf2 +hw_lib_nf2_a_CPPFLAGS += -I $(HW_SYSTEM)/include + +endif diff --git a/openflow/hw-lib/nf2/README b/openflow/hw-lib/nf2/README new file mode 100644 index 00000000..7e111b30 --- /dev/null +++ b/openflow/hw-lib/nf2/README @@ -0,0 +1,56 @@ +NetFPGA Hardware Table + Date - 03/09/10 +---------------------------------------- + +This library creates and maintains a single software table that contains all +the flows that are currently held in the NetFPGA card. The card itself splits +exact match flows into SRAM and wildcard match flows into TCAMs. Currently +there are 24 usable wildcard flow entries and 32,768 available exact match +entries. The exact match table is hashed so actual available entries will be +varied. + +Installation +---------------------------------------- + +First build OpenFlow ensuring you include the directive to build the +openflow_netfpga hardware table in your configure statement: + + % ./configure --enable-hw-lib=nf2 + +For further help regarding building OpenFlow please see the INSTALL file in +the OpenFlow root directory. + +Platform support +---------------- + +OpenFlow v1.0 with NetFPGA hardware table has been tested on CentOS5.4 +(Linux 2.6.18), which is the officially supported platform of NetFPGA. + +Running +---------------------------------------- + +Use nf2_download to download the openflow_switch.bit file that is located in +the /datapath/hwtable_nf2 folder: + + % nf2_download -r /hw-lib/nf2/openflow_switch.bit + +'-r' option enables PHY interrupt for its link status changing, and OpenFlow +switch can detect it. + +Run ofdatapth with indicating *all* the NetFPGA interfaces: + + % /udatapath/ofdatapath punix:/var/run/test \ + -i nf2c0,nf2c1,nf2c2,nf2c3 + +At this point your OpenFlow switch should be ready to go. +The way you start up ofprotocol is as same as you do for software reference +switch. + +Known Issues +---------------------------------------- +* There is currently no support for priority amongst wildcard-match entries. + +Contact +------- +e-mail: openflow-discuss@lists.stanford.edu +www: http://openflowswitch.org/ diff --git a/openflow/hw-lib/nf2/debug.h b/openflow/hw-lib/nf2/debug.h new file mode 100644 index 00000000..9cb2b10d --- /dev/null +++ b/openflow/hw-lib/nf2/debug.h @@ -0,0 +1,105 @@ + +#ifndef OF_HW_DEBUG_H +#define OF_HW_DEBUG_H 1 + +#include +#include + +#if !defined(HWTABLE_NO_DEBUG) +extern int of_hw_debug; +#define dbg_send(mod, lvl, fmt, args...) \ + if (of_hw_debug >= (lvl)) fprintf(stderr, fmt, ##args) + +#define DBG_LVL_NONE -1 /* All output off */ +#define DBG_LVL_ERROR 0 /* Default value */ +#define DBG_LVL_ALWAYS 0 /* For requested dump output */ +#define DBG_LVL_WARN 1 +#define DBG_LVL_VERBOSE 2 +#define DBG_LVL_VVERB 3 /* Include success indications */ + +/* Sorry for the lazy syntax here. */ +#define DBG_CHECK(lvl) (((lvl) >= 0) && (of_hw_debug >= (lvl))) +#define DBG_ERROR(fmt, args...) dbg_send(0, DBG_LVL_ERROR, fmt, ##args) +#define DBG_ALWAYS(fmt, args...) dbg_send(0, DBG_LVL_ALWAYS, fmt, ##args) +#define DBG_WARN(fmt, args...) dbg_send(0, DBG_LVL_WARN, fmt, ##args) +#define DBG_VERBOSE(fmt, args...) dbg_send(0, DBG_LVL_VERBOSE, fmt, ##args) +#define DBG_VVERB(fmt, args...) dbg_send(0, DBG_LVL_VVERB, fmt, ##args) +#define DBG_NONE(fmt, args...) +/* Same as DEBUG_ALWAYS */ +#define DEBUGK(fmt, args...) dbg_send(0, DBG_LVL_ALWAYS, fmt, ##args) + +#define REPORT_ERROR(str) \ + DBG_ERROR("ERROR: %s:%d. %s\n", __FUNCTION__, __LINE__, str) + +/* Default debugging location string */ +#define ANNOUNCE_LOCATION DBG_VVERB("%s: %d\n", __FUNCTION__, __LINE__) +#define DBG_INCR(cnt) (++(cnt)) + +/* Should assert return? Not presently */ +#define ASSERT(cond) \ + if (!(cond)) DBG_ERROR("ASSERTION %s IN %s FAILED LINE %d\n", \ + #cond, __FUNCTION__, __LINE__) + +/* DEBUG for HW flow lists */ +#define HW_FLOW_MAGIC 0xba5eba11 +#define HW_FLOW_MAKE_VALID(hf) (hf)->magic = HW_FLOW_MAGIC +#define HW_FLOW_IS_VALID(hf) \ + (((hf) != NULL) && ((hf)->magic == HW_FLOW_MAGIC)) + +/* + * Carry out an operation and check for error, optionally returning + * from the calling routine. To avoid compiler + * warnings in routines with void return, we give two macros. + * + * WARNING: This check uses rv != 0 (not just rv < 0). + */ + +#define TRY(op, str) do { \ + int rv; \ + if (((rv = (op)) < 0)) { \ + DBG_ERROR("ERROR %d: %s\n", rv, str); \ + return rv; \ + } else { \ + DBG_NONE("%s: success\n", str); \ + } \ + } while (0) + +#define TRY_NR(op, str) do { \ + int rv; \ + if (((rv = (op)) != 0)) { \ + DBG_ERROR("ERROR %d: %s\n", rv, str); \ + } else { \ + DBG_NONE("%s: success\n", str); \ + } \ + } while (0) + +#else /* No debugging */ + +#define DBG_CHECK(lvl) 0 +#define ANNOUNCE_LOCATION +#define ACT_STRING(action) "" +#define DBG_INCR(cnt) +#define DBG_ERROR(fmt, args...) +#define DBG_ALWAYS(fmt, args...) +#define DBG_WARN(fmt, args...) +#define DBG_VERBOSE(fmt, args...) +#define DBG_VVERB(fmt, args...) +#define DBG_NONE(fmt, args...) +#define DEBUGK(fmt, args...) +#define REPORT_ERROR(str) + +#define ASSERT(cond) + +#define HW_FLOW_MAKE_VALID(hf) +#define HW_FLOW_IS_VALID(hf) 1 + +#define TRY(op, str) do { \ + int rv; \ + if (((rv = (op)) != 0)) return rv; \ + } while (0) + +#define TRY_NR(op, str) (void)op + +#endif /* !defined(HWTABLE_NO_DEBUG) */ + +#endif /* OF_HW_DEBUG_H */ diff --git a/openflow/hw-lib/nf2/hw_flow.c b/openflow/hw-lib/nf2/hw_flow.c new file mode 100644 index 00000000..d59a7713 --- /dev/null +++ b/openflow/hw-lib/nf2/hw_flow.c @@ -0,0 +1,514 @@ +/*- + * Copyright (c) 2008, 2009, 2010 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#include + +#include +#include "list.h" +#include "udatapath/switch-flow.h" +#include "udatapath/datapath.h" +#include "reg_defines_openflow_switch.h" +#include "nf2util.h" +#include "hw_flow.h" +#include "nf2_drv.h" +#include "nf2_lib.h" +#include "debug.h" + +struct nf2_flowtable { + struct of_hw_driver hw_driver; + unsigned int max_flows; + unsigned int num_flows; + struct list flows; + struct list iter_flows; + unsigned long int next_serial; +}; + +static struct sw_flow *nf2_lookup_flowtable(struct sw_table *, + const struct sw_flow_key *); +static int nf2_install_flow(struct sw_table *, struct sw_flow *); +static int nf2_modify_flow(struct sw_table *, const struct sw_flow_key *, + uint16_t, int, const struct ofp_action_header *, + size_t); +static int do_uninstall(struct sw_flow *, struct list *); +static int nf2_has_conflict(struct sw_table *, const struct sw_flow_key *, + uint16_t, int); +static int nf2_uninstall_flow_wrap(struct datapath *, struct sw_table *, + const struct sw_flow_key *, uint16_t, + uint16_t, int); +static int nf2_uninstall_flow(struct datapath *, struct sw_table *, + const struct sw_flow_key *, uint16_t, + uint16_t, int, int); +static void nf2_flow_timeout(struct sw_table *, struct list *); + +static void nf2_destroy_flowtable(struct sw_table *); +static int nf2_iterate_flowtable(struct sw_table *, + const struct sw_flow_key *, + uint16_t, struct sw_table_position *, + int (*)(struct sw_flow *, void *), void *); +static void nf2_get_flowstats(struct sw_table *, struct sw_table_stats *); +static int nf2_get_portstats(of_hw_driver_t *, int, struct ofp_port_stats *); + +#if !defined(HWTABLE_NO_DEBUG) +int of_hw_debug = DBG_LVL_WARN; +#endif + +#define DELETE_FLOW 0 +#define KEEP_FLOW 1 + +static struct sw_flow * +nf2_lookup_flowtable(struct sw_table *flowtab, const struct sw_flow_key *key) +{ + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + struct sw_flow *flow; + + LIST_FOR_EACH(flow, struct sw_flow, node, &nf2flowtab->flows) { + if (flow_matches_1wild(key, &flow->key)) { + return flow; + } + } + + return NULL; +} + +static int +nf2_install_flow(struct sw_table *flowtab, struct sw_flow *flow) +{ + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + + /* Delete flows that match exactly. */ + nf2_uninstall_flow(NULL, flowtab, &flow->key, OFPP_NONE, + flow->priority, true, KEEP_FLOW); + + if (nf2_are_actions_supported(flow)) { + if (nf2_build_and_write_flow(flow)) { + /* Not successful */ + return 0; + } + } else { + /* Unsupported actions or no device. */ + return 0; + } + + nf2flowtab->num_flows++; + list_push_front(&nf2flowtab->flows, &flow->node); + list_push_front(&nf2flowtab->iter_flows, &flow->iter_node); + + return 1; +} + +static int +nf2_modify_flow(struct sw_table *flowtab, const struct sw_flow_key *key, + uint16_t priority, int strict, + const struct ofp_action_header *actions, size_t actions_len) +{ + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + struct sw_flow *flow; + unsigned int count = 0; + + LIST_FOR_EACH(flow, struct sw_flow, node, &nf2flowtab->flows) { + if (flow_matches_desc(&flow->key, key, strict) + && (!strict || flow->priority == priority)) { + flow_replace_acts(flow, actions, actions_len); + if (nf2_are_actions_supported(flow)) { + count += nf2_modify_acts(flow); + } + } else { + return 0; + } + } + + return count; +} + +static int +nf2_has_conflict(struct sw_table *flowtab, const struct sw_flow_key *key, + uint16_t priority, int strict) +{ + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + struct sw_flow *flow; + + LIST_FOR_EACH(flow, struct sw_flow, node, &nf2flowtab->flows) { + + if (flow_matches_2desc(&flow->key, key, strict) + && (flow->priority == priority)) { + return true; + } + } + + return false; +} + +static int +do_uninstall(struct sw_flow *flow, struct list *deleted) +{ + if (flow != NULL && flow->private != NULL) { + list_remove(&flow->node); + list_remove(&flow->iter_node); + list_push_back(deleted, &flow->node); + return 1; + } + + return 0; +} + +static int +nf2_uninstall_flow_wrap(struct datapath *dpinst, struct sw_table *flowtab, + const struct sw_flow_key *key, uint16_t out_port, + uint16_t priority, int strict) +{ + return nf2_uninstall_flow(dpinst, flowtab, key, out_port, + priority, strict, DELETE_FLOW); +} + +static int +nf2_uninstall_flow(struct datapath *dpinst, struct sw_table *flowtab, + const struct sw_flow_key *key, uint16_t out_port, + uint16_t priority, int strict, int keep_flow) +{ + struct nf2device *dev; + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + struct sw_flow *flow, *n; + struct nf2_flow *nf2flow; + unsigned int count = 0; + struct list deleted; + list_init(&deleted); + + dev = nf2_get_net_device(); + if (dev == NULL) + return 0; + + LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &nf2flowtab->flows) { + if (flow_matches_desc(&flow->key, key, strict) + && (!strict || flow->priority == priority) + && flow_has_out_port(flow, out_port)) { + nf2flow = flow->private; + + if (nf2flow != NULL) { + flow->packet_count + += nf2_get_packet_count(dev, + nf2flow); + flow->byte_count += nf2_get_byte_count(dev, + nf2flow); + } + count += do_uninstall(flow, &deleted); + if (keep_flow == KEEP_FLOW) { + /* Delete private in sw_flow here */ + nf2_delete_private(flow->private); + } + } + } + nf2flowtab->num_flows -= count; + + nf2_free_net_device(dev); + + if (keep_flow == DELETE_FLOW) { + /* Notify DP of deleted flows and delete the flow */ + LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &deleted) { + dp_send_flow_end(dpinst, flow, flow->reason); + list_remove(&flow->node); + nf2_delete_private(flow->private); + flow_free(flow); + } + } + + return count; +} + +static void +nf2_flow_timeout(struct sw_table *flowtab, struct list *deleted) +{ + struct nf2device *dev; + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + struct sw_flow *flow, *n; + struct nf2_flow *nf2flow; + int num_uninst_flows = 0; + uint64_t num_forw_packets = 0; + uint64_t now = time_msec(); + + dev = nf2_get_net_device(); + if (dev == NULL) { + DBG_ERROR("Could not open NetFPGA device\n"); + return; + } + + /* LOCK; */ + /* FIXME */ + LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &nf2flowtab->flows) { + nf2flow = flow->private; + if (nf2flow != NULL) { + num_forw_packets = flow->packet_count + + nf2_get_packet_count(dev, nf2flow); + flow->byte_count += nf2_get_byte_count(dev, nf2flow); + } + if (num_forw_packets > flow->packet_count) { + flow->packet_count = num_forw_packets; + flow->used = now; + } + + if (flow_timeout(flow)) { + num_uninst_flows += do_uninstall(flow, deleted); + nf2_delete_private(flow->private); + } + } + + /* UNLOCK; */ + + nf2_clear_watchdog(dev); + nf2_free_net_device(dev); + + nf2flowtab->num_flows -= num_uninst_flows; +} + +static void +nf2_destroy_flowtable(struct sw_table *flowtab) +{ + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + struct nf2_flow *nf2flow = NULL; + + if (nf2flowtab == NULL) + return; + + while (!list_is_empty(&nf2flowtab->flows)) { + struct sw_flow *flow + = CONTAINER_OF(list_front(&nf2flowtab->flows), + struct sw_flow, node); + list_remove(&flow->node); + if (flow->private) { + nf2flow = (struct nf2_flow *)flow->private; + + if (nf2flow->type == NF2_TABLE_EXACT) { + nf2_add_free_exact(nf2flow); + } else if (nf2flow->type == NF2_TABLE_WILDCARD) { + nf2_add_free_wildcard(nf2flow); + } + flow->private = NULL; + } + flow_free(flow); + } + free(nf2flowtab); + + nf2_destroy_exact_freelist(); + nf2_destroy_wildcard_freelist(); +} + +static int +nf2_iterate_flowtable(struct sw_table *flowtab, const struct sw_flow_key *key, + uint16_t out_port, struct sw_table_position *position, + int (*callback) (struct sw_flow *, void *), + void *private) +{ + unsigned long start; + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + struct sw_flow *flow; + int error = 0; + + start = ~position->private[0]; + LIST_FOR_EACH(flow, struct sw_flow, iter_node, &nf2flowtab->iter_flows) { + if (flow->serial <= start + && flow_matches_2wild(key, &flow->key) + && flow_has_out_port(flow, out_port)) { + error = callback(flow, private); + if (error != 0) { + position->private[0] = ~flow->serial; + return error; + } + } + } + + return error; +} + +static void +nf2_get_flowstats(struct sw_table *flowtab, struct sw_table_stats *stats) +{ + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + struct nf2device *dev; + unsigned long int num_matched = 0; + unsigned long int num_missed = 0; + + dev = nf2_get_net_device(); + if (dev == NULL) { + DBG_VERBOSE("Could not open NetFPGA device\n"); + } else { + num_matched = nf2_get_matched_count(dev); + num_missed = nf2_get_missed_count(dev); + nf2_free_net_device(dev); + } + + stats->name = "nf2"; + stats->wildcards = OPENFLOW_WILDCARD_TABLE_SIZE + - RESERVED_FOR_CPU2NETFPGA; + stats->n_flows = nf2flowtab->num_flows; + stats->max_flows = nf2flowtab->max_flows; + stats->n_lookup = num_matched + num_missed; + stats->n_matched = num_matched; +} + +static int +nf2_get_portstats(of_hw_driver_t *hw_drv, int of_port, + struct ofp_port_stats *stats) +{ + int nf2_port; + struct nf2_port_info *nf2portinfo; + struct nf2device *dev; + + if ((of_port > NF2_PORT_NUM) || (of_port <= 0)) { + return 1; + } + nf2_port = of_port - 1; + + nf2portinfo = calloc(1, sizeof(struct nf2_port_info)); + if (nf2portinfo == NULL) { + return 1; + } + + dev = nf2_get_net_device(); + if (dev == NULL) { + free(nf2portinfo); + return 1; + } + + if (nf2_get_port_info(dev, nf2_port, nf2portinfo)) { + nf2_free_net_device(dev); + free(nf2portinfo); + return 1; + } + + stats->rx_packets = (uint64_t)(nf2portinfo->rx_q_num_pkts_stored); + stats->rx_dropped = (uint64_t)(nf2portinfo->rx_q_num_pkts_dropped_full + + nf2portinfo->rx_q_num_pkts_dropped_bad); + stats->rx_bytes = (uint64_t)(nf2portinfo->rx_q_num_bytes_pushed); + stats->tx_packets = (uint64_t)(nf2portinfo->tx_q_num_pkts_sent); + stats->tx_bytes = (uint64_t)(nf2portinfo->tx_q_num_bytes_pushed); + + /* Not supported */ + stats->tx_dropped = -1; + stats->rx_errors = -1; + stats->tx_errors = -1; + stats->rx_frame_err = -1; + stats->rx_over_err = -1; + stats->rx_crc_err = -1; + stats->collisions = -1; + + nf2_free_net_device(dev); + free(nf2portinfo); + return 0; +} + +/* + * Create and initialize a new hardware datapath object + */ + +of_hw_driver_t * +new_of_hw_driver(struct datapath *dp) +{ + struct sw_table *sw_tab; + of_hw_driver_t *hw_drv; + struct nf2device *dev; + struct nf2_flowtable *nf2flowtab; + + dev = nf2_get_net_device(); + if (dev == NULL) { + return NULL; + } + nf2_reset_card(dev); + nf2_free_net_device(dev); + + nf2flowtab = calloc(1, sizeof(*nf2flowtab)); + if (nf2flowtab == NULL) { + return NULL; + } + + /* These all point to the same place */ + hw_drv = &nf2flowtab->hw_driver; + sw_tab = &hw_drv->sw_table; + + sw_tab->n_lookup = 0; + sw_tab->n_matched = 0; + + /* Fill out the function pointers */ + sw_tab->lookup = nf2_lookup_flowtable; + sw_tab->insert = nf2_install_flow; + sw_tab->modify = nf2_modify_flow; + sw_tab->has_conflict = nf2_has_conflict; + + sw_tab->delete = nf2_uninstall_flow_wrap; + sw_tab->timeout = nf2_flow_timeout; + + sw_tab->destroy = nf2_destroy_flowtable; + sw_tab->iterate = nf2_iterate_flowtable; + sw_tab->stats = nf2_get_flowstats; + + nf2flowtab->max_flows = OPENFLOW_NF2_EXACT_TABLE_SIZE + + OPENFLOW_WILDCARD_TABLE_SIZE - RESERVED_FOR_CPU2NETFPGA; + nf2flowtab->num_flows = 0; + list_init(&nf2flowtab->flows); + list_init(&nf2flowtab->iter_flows); + nf2flowtab->next_serial = 0; + + if (nf2_init_wildcard_freelist()) { + DBG_ERROR("Could not create wildcard freelist\n"); + free(nf2flowtab); + return NULL; + } + if (nf2_write_static_wildcard()) { + DBG_ERROR("Could not create wildcard freelist\n"); + free(nf2flowtab); + return NULL; + } + if (nf2_init_exact_freelist()) { + DBG_ERROR("Could not create exact freelist\n"); + free(nf2flowtab); + return NULL; + } + + hw_drv->table_stats_get = NULL; + hw_drv->port_stats_get = nf2_get_portstats; + hw_drv->flow_stats_get = NULL; + hw_drv->aggregate_stats_get = NULL; + + hw_drv->port_add = NULL; + hw_drv->port_remove = NULL; + hw_drv->port_link_get = NULL; + hw_drv->port_enable_set = NULL; + hw_drv->port_enable_get = NULL; + hw_drv->port_queue_config = NULL; + hw_drv->port_queue_remove = NULL; + hw_drv->port_change_register = NULL; + + hw_drv->packet_send = NULL; + hw_drv->packet_receive_register = NULL; + + hw_drv->ioctl = NULL; + + return hw_drv; +} diff --git a/openflow/hw-lib/nf2/hw_flow.h b/openflow/hw-lib/nf2/hw_flow.h new file mode 100644 index 00000000..96e0320f --- /dev/null +++ b/openflow/hw-lib/nf2/hw_flow.h @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 2008, 2009, 2010 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#ifndef HWTABLE_NF2_NF2_FLOWTABLE_ +#define HWTABLE_NF2_NF2_FLOWTABLE_ + +#define RESERVED_FOR_CPU2NETFPGA 8 + +struct nf2_flow { + struct list node; + uint32_t pos; + uint32_t type; + uint32_t hw_packet_count; + uint32_t hw_byte_count; +}; + +enum nf2_of_table_type { + NF2_TABLE_EXACT, + NF2_TABLE_WILDCARD +}; + +/* Remove the commentout of the following 'define' line + * if you want to enable NetFPGA watchdog timer capability. + */ +/* #define NF2_WATCHDOG 1 */ + +#endif diff --git a/openflow/hw-lib/nf2/nf2.h b/openflow/hw-lib/nf2/nf2.h new file mode 100644 index 00000000..519f52da --- /dev/null +++ b/openflow/hw-lib/nf2/nf2.h @@ -0,0 +1,452 @@ +/* **************************************************************************** + * $Id: nf2.h 5575 2009-05-13 18:44:26Z grg $ + * + * Module: nf2.h + * Project: NetFPGA 2 Linux Kernel Driver + * Description: Header file for kernel driver + * + * Change history: + * + */ + +#ifndef _NF2_H +#define _NF2_H 1 + +#define NF2_DEV_NAME "nf2" + +/* Include for socket IOCTLs */ +#include + +/* Maximum number of interfaces */ +#ifndef MAX_IFACE +#define MAX_IFACE 4 +#endif + +/* + * Register names and locations. + * + * Note that these names are not necessarily identical to + * those in NF2/hw/common/src/defines + */ + +/* CPCI registers */ +#define CPCI_REG_ID 0x000 +#define CPCI_REG_BOARD_ID 0x004 +#define CPCI_REG_CTRL 0x008 +#define CPCI_REG_RESET 0x00c +#define CPCI_REG_ERROR 0x010 +#define CPCI_REG_DUMMY 0x020 +#define CPCI_REG_INTERRUPT_MASK 0x040 +#define CPCI_REG_INTERRUPT_STATUS 0x044 +#define CPCI_REG_PROG_DATA 0x100 +#define CPCI_REG_PROG_STATUS 0x104 +#define CPCI_REG_PROG_CTRL 0x108 +#define CPCI_REG_DMA_I_ADDR 0x140 +#define CPCI_REG_DMA_E_ADDR 0x144 +#define CPCI_REG_DMA_I_SIZE 0x148 +#define CPCI_REG_DMA_E_SIZE 0x14c +#define CPCI_REG_DMA_I_CTRL 0x150 +#define CPCI_REG_DMA_E_CTRL 0x154 +#define CPCI_REG_DMA_MAX_XFER_TIME 0x180 +#define CPCI_REG_DMA_MAX_RETRIES 0x184 +#define CPCI_REG_CNET_MAX_XFER_TIME 0x188 +#define CPCI_REG_DMA_I_PKT_CNT 0x400 +#define CPCI_REG_DMA_E_PKT_CNT 0x404 +#define CPCI_REG_CPCI_REG_RD_CNT 0x408 +#define CPCI_REG_CPCI_REG_WR_CNT 0x40c +#define CPCI_REG_CNET_REG_RD_CNT 0x410 +#define CPCI_REG_CNET_REG_WR_CNT 0x414 + +#define CPCI_REG_N_CLK_COUNT 0x500 +#define CPCI_REG_P_MAX 0x504 +#define CPCI_REG_N_EXP 0x508 +#define CPCI_REG_P_CLK_CTR 0x510 +#define CPCI_REG_RESET_CTR 0x520 + + + +/* Base address for CNET registers */ +#define CNET_REG_BASE 0x400000 + + +/* Added by nweaver for building memory manipulation + utilities */ +/* 2 MB SRAM size on current board, MAX and SIZE will + need to be changed if upgraded to 4 MB SRAMs */ +#define SRAM_SIZE 0x200000 + +#define SRAM_1_BASE 0x800000 +#define SRAM_1_MAX 0x9FFFFF + +#define SRAM_2_BASE 0xC00000 +#define SRAM_2_MAX 0xDFFFFF +/* end nweaver addition */ + + +/* Device ID registers */ +#define NF2_DEVICE_ID 0x0400000 +#define NF2_REVISION 0x0400004 +#define NF2_DEVICE_STR 0x0400008 + + +/* CNET registers */ +#define CNET_REG_ID (CNET_REG_BASE + 0x000) +#define CNET_REG_CTRL (CNET_REG_BASE + 0x004) +#define CNET_REG_RESET (CNET_REG_BASE + 0x008) +#define CNET_REG_ERROR (CNET_REG_BASE + 0x00C) +#define CNET_REG_ENABLE (CNET_REG_BASE + 0x010) +#define CNET_REG_WR_SRAM1_EOP (CNET_REG_BASE + 0x0F0) +#define CNET_REG_RD_SRAM1_EOP (CNET_REG_BASE + 0x0F4) +#define CNET_REG_WR_SRAM2_EOP (CNET_REG_BASE + 0x0F8) +#define CNET_REG_RD_SRAM2_EOP (CNET_REG_BASE + 0x0FC) +#define CNET_REG_MF_STATUS_0 (CNET_REG_BASE + 0x100) +#define CNET_REG_MF_TX_PKTS_SENT_0 (CNET_REG_BASE + 0x104) +#define CNET_REG_MF_RX_PKTS_RCVD_0 (CNET_REG_BASE + 0x108) +#define CNET_REG_MF_RX_PKTS_LOST_0 (CNET_REG_BASE + 0x10C) +#define CNET_REG_MAC_CONFIG_0 (CNET_REG_BASE + 0x110) +#define CNET_REG_MF_STATUS_1 (CNET_REG_BASE + 0x140) +#define CNET_REG_MF_TX_PKTS_SENT_1 (CNET_REG_BASE + 0x144) +#define CNET_REG_MF_RX_PKTS_RCVD_1 (CNET_REG_BASE + 0x148) +#define CNET_REG_MF_RX_PKTS_LOST_1 (CNET_REG_BASE + 0x14C) +#define CNET_REG_MAC_CONFIG_1 (CNET_REG_BASE + 0x150) +#define CNET_REG_MF_STATUS_2 (CNET_REG_BASE + 0x180) +#define CNET_REG_MF_TX_PKTS_SENT_2 (CNET_REG_BASE + 0x184) +#define CNET_REG_MF_RX_PKTS_RCVD_2 (CNET_REG_BASE + 0x188) +#define CNET_REG_MF_RX_PKTS_LOST_2 (CNET_REG_BASE + 0x18C) +#define CNET_REG_MAC_CONFIG_2 (CNET_REG_BASE + 0x190) +#define CNET_REG_MF_STATUS_3 (CNET_REG_BASE + 0x1C0) +#define CNET_REG_MF_TX_PKTS_SENT_3 (CNET_REG_BASE + 0x1C4) +#define CNET_REG_MF_RX_PKTS_RCVD_3 (CNET_REG_BASE + 0x1C8) +#define CNET_REG_MF_RX_PKTS_LOST_3 (CNET_REG_BASE + 0x1CC) +#define CNET_REG_MAC_CONFIG_3 (CNET_REG_BASE + 0x1D0) +#define CNET_REG_RXQ_NUM_PKTS_0 (CNET_REG_BASE + 0x200) +#define CNET_REG_RXQ_POINTERS_0 (CNET_REG_BASE + 0x204) +#define CNET_REG_RXQ_NUM_PKTS_1 (CNET_REG_BASE + 0x240) +#define CNET_REG_RXQ_POINTERS_1 (CNET_REG_BASE + 0x244) +#define CNET_REG_RXQ_NUM_PKTS_2 (CNET_REG_BASE + 0x280) +#define CNET_REG_RXQ_POINTERS_2 (CNET_REG_BASE + 0x284) +#define CNET_REG_RXQ_NUM_PKTS_3 (CNET_REG_BASE + 0x2C0) +#define CNET_REG_RXQ_POINTERS_3 (CNET_REG_BASE + 0x2C4) + +#define CNET_REG_MF_RX_PKTS_LOST_BAD_FCS_0 (CNET_REG_BASE + 0x114) +#define CNET_REG_MF_RX_PKTS_LOST_FULL_FIFO_0 (CNET_REG_BASE+0x118) +#define CNET_REG_MF_RX_GOOD_PKTS_RCVD_0 (CNET_REG_BASE+0x11C) +#define CNET_REG_MF_RX_GOOD_BYTES_RCVD_0 (CNET_REG_BASE+0x120) +#define CNET_REG_MF_TX_BYTES_SENT_0 (CNET_REG_BASE+0x124) +#define CNET_REG_MF_RX_PKTS_LOST_BAD_FCS_1 (CNET_REG_BASE+0x154) +#define CNET_REG_MF_RX_PKTS_LOST_FULL_FIFO_1 (CNET_REG_BASE+0x158) +#define CNET_REG_MF_RX_GOOD_PKTS_RCVD_1 (CNET_REG_BASE+0x15C) +#define CNET_REG_MF_RX_GOOD_BYTES_RCVD_1 (CNET_REG_BASE+0x160) +#define CNET_REG_MF_TX_BYTES_SENT_1 (CNET_REG_BASE+0x164) +#define CNET_REG_MF_RX_PKTS_LOST_BAD_FCS_2 (CNET_REG_BASE+0x194) +#define CNET_REG_MF_RX_PKTS_LOST_FULL_FIFO_2 (CNET_REG_BASE+0x198) +#define CNET_REG_MF_RX_GOOD_PKTS_RCVD_2 (CNET_REG_BASE+0x19C) +#define CNET_REG_MF_RX_GOOD_BYTES_RCVD_2 (CNET_REG_BASE+0x1A0) +#define CNET_REG_MF_TX_BYTES_SENT_2 (CNET_REG_BASE+0x1A4) +#define CNET_REG_MF_RX_PKTS_LOST_BAD_FCS_3 (CNET_REG_BASE+0x1D4) +#define CNET_REG_MF_RX_PKTS_LOST_FULL_FIFO_3 (CNET_REG_BASE+0x1D8) +#define CNET_REG_MF_RX_GOOD_PKTS_RCVD_3 (CNET_REG_BASE+0x1DC) +#define CNET_REG_MF_RX_GOOD_BYTES_RCVD_3 (CNET_REG_BASE+0x1E0) +#define CNET_REG_MF_TX_BYTES_SENT_3 (CNET_REG_BASE+0x1E4) + +#define CNET_MAC_CLK_CHK_CTRL (CNET_REG_BASE + 0xF00) +#define CNET_MAC_CLK_CHK_CNT_VALUE (CNET_REG_BASE + 0xF04) + + +/* Base address for CNET PHY registers */ +#define PHY_REG_BASE 0x600000 + +#define PHY_REG_CMD (PHY_REG_BASE) +#define PHY_REG_STATUS (PHY_REG_BASE) + +/* + * CPCI register masks + */ + +/* ID Masks */ +#define ID_VERSION 0x00FFFFFF +#define ID_REVISION 0xFF000000 + +/* Board ID Masks */ +#define BOARD_ID 0x00000F00 +#define BOARD_ID_CONTROL 0x00000001 + +/* Control masks */ +#define CTRL_CNET_RESET 0x00000100 +#define CTRL_LED 0x00000001 + +/* RESET masks */ +#define RESET_CPCI 0x00000001 + +/* Error masks */ +#define ERR_CNET_READ_TIMEOUT 0x02000000 +#define ERR_CNET_ERROR 0x01000000 +#define ERR_PROG_BUF_OVERFLOW 0x00020000 +#define ERR_PROG_ERROR 0x00010000 +#define ERR_DMA_TIMEOUT 0x00000400 +#define ERR_DMA_RETRY_CNT_EXPIRED 0x00000200 +#define ERR_DMA_BUF_OVERFLOW 0x00000100 +#define ERR_DMA_RD_SIZE_ERROR 0x00000040 +#define ERR_DMA_WR_SIZE_ERROR 0x00000020 +#define ERR_DMA_RD_ADDR_ERROR 0x00000010 +#define ERR_DMA_WR_ADDR_ERROR 0x00000008 +#define ERR_DMA_RD_MAC_ERROR 0x00000004 +#define ERR_DMA_WR_MAC_ERROR 0x00000002 +#define ERR_DMA_FATAL_ERROR 0x00000001 + +#define ERR_DMA_SETUP_ERROR ( ERR_DMA_WR_MAC_ERROR | \ + ERR_DMA_RD_MAC_ERROR | \ + ERR_DMA_WR_ADDR_ERROR | \ + ERR_DMA_RD_ADDR_ERROR | \ + ERR_DMA_WR_SIZE_ERROR | \ + ERR_DMA_RD_SIZE_ERROR ) + + +/* Interrupt masks */ +#define INT_DMA_RX_COMPLETE 0x80000000 +#define INT_DMA_TX_COMPLETE 0x40000000 +#define INT_PHY_INTERRUPT 0x20000000 +#define INT_PKT_AVAIL 0x00000100 +#define INT_CNET_ERROR 0x00000020 +#define INT_CNET_READ_TIMEOUT 0x00000010 +#define INT_PROG_ERROR 0x00000008 +#define INT_DMA_TRANSFER_ERROR 0x00000004 +#define INT_DMA_SETUP_ERROR 0x00000002 +#define INT_DMA_FATAL_ERROR 0x00000001 + +#define INT_UNKNOWN ~(INT_DMA_RX_COMPLETE | \ + INT_DMA_TX_COMPLETE | \ + INT_PHY_INTERRUPT | \ + INT_PKT_AVAIL | \ + INT_CNET_ERROR | \ + INT_CNET_READ_TIMEOUT | \ + INT_PROG_ERROR | \ + INT_DMA_TRANSFER_ERROR | \ + INT_DMA_SETUP_ERROR | \ + INT_DMA_FATAL_ERROR) + +/* Programming status */ +#define PROG_INIT 0x00010000 +#define PROG_DONE 0x00000100 +#define PROG_FIFO_EMPTY 0x00000002 +#define PROG_IN_PROGRESS 0x00000001 + +/* Programming control */ +#define PROG_CTRL_RESET 0x00000001 + +/* DMA control */ +#define DMA_CTRL_MAC 0x00000300 +#define DMA_CTRL_OWNER 0x00000001 + +/* + * CNET register masks + */ + +/* Reset masks */ +#define CNET_RESET_MAC 0x0000000F +#define CNET_RESET_MAC_3 0x00000008 +#define CNET_RESET_MAC_2 0x00000004 +#define CNET_RESET_MAC_1 0x00000002 +#define CNET_RESET_MAC_0 0x00000001 + +/* Error masks */ +#define CNET_ERROR_TX_UNDERRUN_MAC 0x000000F0 +#define CNET_ERROR_TX_UNDERRUN_MAC_3 0x00000080 +#define CNET_ERROR_TX_UNDERRUN_MAC_2 0x00000040 +#define CNET_ERROR_TX_UNDERRUN_MAC_1 0x00000020 +#define CNET_ERROR_TX_UNDERRUN_MAC_0 0x00000010 +#define CNET_ERROR_TX_OVERRUN_MAC 0x0000000F +#define CNET_ERROR_TX_OVERRUN_MAC_3 0x00000008 +#define CNET_ERROR_TX_OVERRUN_MAC_2 0x00000004 +#define CNET_ERROR_TX_OVERRUN_MAC_1 0x00000002 +#define CNET_ERROR_TX_OVERRUN_MAC_0 0x00000001 + +/* Enable masks */ +#define CNET_ENABLE_RX_FIFO 0x0000F000 +#define CNET_ENABLE_RX_FIFO_3 0x00008000 +#define CNET_ENABLE_RX_FIFO_2 0x00004000 +#define CNET_ENABLE_RX_FIFO_1 0x00002000 +#define CNET_ENABLE_RX_FIFO_0 0x00001000 +#define CNET_ENABLE_TX_MAC 0x00000F00 +#define CNET_ENABLE_TX_MAC_3 0x00000800 +#define CNET_ENABLE_TX_MAC_2 0x00000400 +#define CNET_ENABLE_TX_MAC_1 0x00000200 +#define CNET_ENABLE_TX_MAC_0 0x00000100 +#define CNET_ENABLE_DEBUG_TRISTATE 0x00000004 +#define CNET_ENABLE_INGRESS_ARBITER 0x00000002 +#define CNET_ENABLE_RX_DMA 0x00000001 + +/* MF Status masks */ +#define CNET_MF_STATUS_RX_FIFO_EMPTY 0x02000000 +#define CNET_MF_STATUS_RX_PKT_AVAIL 0x01000000 +#define CNET_MF_STATUS_RX_NUM_PKTS 0x00FF0000 +#define CNET_MF_STATUS_TX_FIFO_FULL 0x00000200 +#define CNET_MF_STATUS_TX_FIFO_NO_MAX_PKT 0x00000100 +#define CNET_MF_STATUS_TX_NUM_PKTS 0x000000FF + +/* MAC Config masks */ +#define CNET_MAC_CFG_FULL_DUPLEX 0x00000020 +#define CNET_MAC_CFG_TX_FCS_SUPPLIED 0x00000010 +#define CNET_MAC_CFG_RX_WANT_FCS 0x00000008 +#define CNET_MAC_CFG_JUMBO_ENABLE 0x00000004 + +#define CNET_MAC_CFG_SPEED 0x00000002 +#define CNET_MAC_CFG_1000_MBPS 0x00000002 +#define CNET_MAC_CFG_100_MBPS 0x00000001 +#define CNET_MAC_CFG_10_MBPS 0x00000000 + +#define CNET_RXQ_WR_PTR 0x00FF0000 +#define CNET_RXQ_RD_PTR 0x000000FF + + +/* Phy register masks */ +#define PHY_RD_WR 0x80000000 +#define PHY_PHY 0x03000000 +#define PHY_ADDR 0x001F0000 +#define PHY_DATA 0x0000FFFF + +#define PHY_DONE 0x80000000 +#define PHY_DONE_CNT 0x001F0000 + +/* Defines to calculate register values */ +/* CPCI Funcs */ +#define NF2_GET_VERSION(x) (x & 0xFFFFFF) +#define NF2_GET_REVISION(x) ((x & 0xFF000000) >> 24) + +#define NF2_GET_BOARD_ID(x) ((x & BOARD_ID) >> 8) +#define NF2_GET_CONTROL(x) (x & BOARD_ID_CONTROL) + +#define NF2_GET_CNET_RESET(x) ((x & CTRL_CNET_RESET) >> 8) +#define NF2_GET_LED(x) (x & CTRL_LED) + +#define NF2_GET_RESET(x) (x & RESET_CPCI) + +#define NF2_GET_CNET_READ_TIMEOUT(x) ((x & ERR_CNET_READ_TIMEOUT) >> 25) +#define NF2_GET_CNET_ERROR(x) ((x & ERR_CNET_ERROR) >> 24) +#define NF2_GET_PROG_BUF_OVERFLOW(x) ((x & ERR_PROG_BUF_OVERFLOW) >> 12) +#define NF2_GET_PROG_ERROR(x) ((x & ERR_PROG_ERROR) >> 11) +#define NF2_GET_DMA_TIMEOUT(x) ((x & ERR_DMA_TIMEOUT) >> 10) +#define NF2_GET_DMA_RETRY_CNT_EXPIRED(x) \ + ((x & ERR_DMA_RETRY_CNT_EXPIRED) >> 9) +#define NF2_GET_DMA_BUF_OVERFLOW(x) ((x & ERR_DMA_BUF_OVERFLOW) >> 8) +#define NF2_GET_DMA_RD_SIZE_ERROR(x) ((x & ERR_DMA_RD_SIZE_ERROR) >> 6) +#define NF2_GET_DMA_WR_SIZE_ERROR(x) ((x & ERR_DMA_WR_SIZE_ERROR) >> 5) +#define NF2_GET_DMA_RD_ADDR_ERROR(x) ((x & ERR_DMA_RD_ADDR_ERROR) >> 4) +#define NF2_GET_DMA_WR_ADDR_ERROR(x) ((x & ERR_DMA_WR_ADDR_ERROR) >> 3) +#define NF2_GET_DMA_RD_MAC_ERROR(x) ((x & ERR_DMA_RD_MAC_ERROR) >> 2) +#define NF2_GET_DMA_WR_MAC_ERROR(x) ((x & ERR_DMA_WR_MAC_ERROR) >> 1) +#define NF2_GET_DMA_FATAL_ERROR(x) (x & ERR_DMA_FATAL_ERROR) + +#define NF2_GET_INT_DMA_TX_COMPLETE(x) ((x & INT_DMA_TX_COMPLETE) >> 31) +#define NF2_GET_INT_DMA_RX_COMPLETE(x) ((x & INT_DMA_RX_COMPLETE) >> 30) +#define NF2_GET_INT_PHY_INTERRUPT(x) ((x & INT_PHY_INTERRUPT) >> 29) +#define NF2_GET_INT_PKT_AVAIL(x) ((x & INT_PKT_AVAIL) >> 8) +#define NF2_GET_INT_CNET_ERROR(x) ((x & INT_CNET_ERROR) >> 5) +#define NF2_GET_INT_CNET_READ_TIMEOUT(x) \ + ((x & INT_CNET_READ_TIMEOUT) >> 4) +#define NF2_GET_INT_PROG_ERROR(x) ((x & INT_PROG_ERROR) >> 3) +#define NF2_GET_INT_DMA_TRANSFER_ERROR(x) \ + ((x & INT_DMA_TRANSFER_ERROR) >> 2) +#define NF2_GET_INT_DMA_SETUP_ERROR(x) ((x & INT_DMA_SETUP_ERROR) >> 1) +#define NF2_GET_INT_DMA_FATAL_ERROR(x) (x & INT_DMA_FATAL_ERROR) + +#define NF2_GET_PROG_INIT(x) ((x & PROG_INIT) >> 16) +#define NF2_GET_PROG_DONE(x) ((x & PROG_DONE) >> 8) +#define NF2_GET_PROG_FIFO_EMPTY(x) ((x & PROG_FIFO_EMPTY) >> 1) +#define NF2_GET_PROG_IN_PROGRESS(x) (x & PROG_IN_PROGRESS) + +#define NF2_GET_DMA_CTRL_MAC(x) ((x & DMA_CTRL_MAC) >> 8) +#define NF2_GET_DMA_CTRL_OWNER(x) (x & DMA_CTRL_OWNER) + +#define NF2_SET_DMA_CTRL_MAC(x) (x << 8) + + +/* CNET Funcs */ +#define NF2_GET_CNET_VERSION(x) ((x & 0xFFFF0000) >> 16) +#define NF2_GET_CNET_DEVICE_ID(x) (x & 0xFFFF) + +#define NF2_GET_CNET_RESET_MAC(x) (x & CNET_RESET_MAC) + +#define NF2_GET_CNET_ERROR_TX_UNDERRUN_MAC(x) \ + ((x & CNET_ERROR_TX_UNDERRUN_MAC) >> 4) +#define NF2_GET_CNET_ERROR_TX_OVERRUN_MAC(x) \ + (x & CNET_ERROR_TX_OVERRUN_MAC) + +#define NF2_GET_CNET_ENABLE_RX_FIFO(x) ((x & CNET_ENABLE_RX_FIFO) >> 12) +#define NF2_GET_CNET_ENABLE_TX_MAC(x) ((x & CNET_ENABLE_TX_MAC) >> 8) +#define NF2_GET_CNET_ENABLE_DEBUG_TRISTATE(x) \ + ((x & CNET_ENABLE_DEBUG_TRISTATE) >> 2) +#define NF2_GET_CNET_ENABLE_INGRESS_ARBITER(x) \ + ((x & CNET_ENABLE_INGRESS_ARBITER) >> 1) +#define NF2_GET_CNET_ENABLE_RX_DMA(x) (x & CNET_ENABLE_RX_DMA) + +#define NF2_GET_CNET_MF_STATUS_RX_FIFO_EMPTY(x) \ + ((x & CNET_MF_STATUS_RX_FIFO_EMPTY) >> 25) +#define NF2_GET_CNET_MF_STATUS_RX_PKT_AVAIL(x) \ + ((x & CNET_MF_STATUS_RX_PKT_AVAIL) >> 24) +#define NF2_GET_CNET_MF_STATUS_RX_NUM_PKTS(x) \ + ((x & CNET_MF_STATUS_RX_NUM_PKTS) >> 16) +#define NF2_GET_CNET_MF_STATUS_TX_FIFO_FULL(x) \ + ((x & CNET_MF_STATUS_TX_FIFO_FULL) >> 9) +#define NF2_GET_CNET_MF_STATUS_TX_FIFO_NO_MAX_PKT(x) \ + ((x & CNET_MF_STATUS_TX_FIFO_NO_MAX_PKT) >> 8) +#define NF2_GET_CNET_MF_STATUS_TX_NUM_PKTS(x) \ + (x & CNET_MF_STATUS_TX_NUM_PKTS) + +#define NF2_GET_CNET_MAC_CFG_FULL_DUPLEX(x) \ + ((x & CNET_MAC_CFG_FULL_DUPLEX) >> 5) +#define NF2_GET_CNET_MAC_CFG_TX_FCS_SUPPLIED(x) \ + ((x & CNET_MAC_CFG_TX_FCS_SUPPLIED) >> 4) +#define NF2_GET_CNET_MAC_CFG_RX_WANT_FCS(x) \ + ((x & CNET_MAC_CFG_RX_WANT_FCS) >> 3) +#define NF2_GET_CNET_MAC_CFG_JUMBO_ENABLE(x) \ + ((x & CNET_MAC_CFG_JUMBO_ENABLE) >> 2) +#define NF2_GET_CNET_MAC_CFG_SPEED(x) \ + (x & CNET_MAC_CFG_SPEED) + +#define NF2_GET_CNET_RXQ_WR_PTR(x) ((x & CNET_RXQ_WR_PTR) >> 16) +#define NF2_GET_CNET_RXQ_RD_PTR(x) (x & CNET_RXQ_RD_PTR) + + +/* PHY functions */ +#define NF2_SET_PHY_IS_READ(x) (x << 31) +#define NF2_SET_PHY_SELECT(x) (x << 24) +#define NF2_SET_PHY_ADDR(x) (x << 16) +#define NF2_SET_PHY_DATA(x) (x) + +#define NF2_GET_PHY_DATA(x) (x & PHY_DATA) +#define NF2_GET_PHY_DONE(x) ((x & PHY_DONE) >> 31) +#define NF2_GET_PHY_DONE_CNT(x) ((x & PHY_DONE_CNT) >> 16) + + +/* + * IOCTLs + */ +#define SIOCREGREAD SIOCDEVPRIVATE +#define SIOCREGWRITE (SIOCDEVPRIVATE + 1) + + +/* MDIO registers */ +#define MDIO_0_AUX_STATUS 0x04c0064 +#define MDIO_0_INTR_STATUS 0x04c0068 +#define MDIO_0_INTR_MASK 0x04c006c + + +/* MDIO address delta between each phy base address */ +#define ADDRESS_DELTA 0x80 + + +/* MDIO bit positions */ +#define INTR_LINK_STATUS_POS 0x2 +#define AUX_LINK_STATUS_POS 0x4 + + +/* + * Structure for transferring register data via an IOCTL + */ +struct nf2reg { + unsigned int reg; + unsigned int val; +}; + +#endif diff --git a/openflow/hw-lib/nf2/nf2_drv.c b/openflow/hw-lib/nf2/nf2_drv.c new file mode 100644 index 00000000..36f3de1a --- /dev/null +++ b/openflow/hw-lib/nf2/nf2_drv.c @@ -0,0 +1,847 @@ +/*- + * Copyright (c) 2008, 2009, 2010 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#include +#include +#include + +#include "udatapath/switch-flow.h" +#include "udatapath/table.h" +#include "timeval.h" +#include "reg_defines_openflow_switch.h" +#include "nf2.h" +#include "nf2util.h" +#include "hw_flow.h" +#include "nf2_drv.h" +#include "nf2_lib.h" +#include "debug.h" + +static void log_entry(nf2_of_entry_wrap *); +static void log_entry_raw(nf2_of_entry_wrap *); +static void log_mask(nf2_of_mask_wrap *); +static void log_mask_raw(nf2_of_mask_wrap *); +static void log_action(nf2_of_action_wrap *); +static void log_action_raw(nf2_of_action_wrap *); +static void log_watchdog_info(struct nf2device *); +static void nf2_get_all_ports_info_addr(struct nf2_all_ports_info_addr *); + +static void +log_entry(nf2_of_entry_wrap *entry) +{ + int i; + + DBG_VERBOSE("log entry\n"); +#ifdef HWTABLE_NO_DEBUG + return; +#else + + // Log the physical source port + DBG_VERBOSE("E psrc[%i] ", entry->entry.src_port / 2); + + // Log the link layer source + DBG_VERBOSE("dlsrc["); + for (i = 5; i > 0; --i) { + DBG_VERBOSE("%0X:", entry->entry.eth_src[i]); + } + DBG_VERBOSE("%0X] ", entry->entry.eth_src[0]); + + // Log the link layer dest + DBG_VERBOSE("dldst["); + for (i = 5; i > 0; --i) { + DBG_VERBOSE("%0X:", entry->entry.eth_dst[i]); + } + DBG_VERBOSE("%0X] ", entry->entry.eth_dst[0]); + + // Log the link layer type + DBG_VERBOSE("dltype[%0X] ", entry->entry.eth_type); + + // Log the link layer vlan + DBG_VERBOSE("dlvlan[%0X] ", entry->entry.vlan_id); + + // Log the network source + DBG_VERBOSE("nwsrc["); + DBG_VERBOSE("%0i.", (entry->entry.ip_src >> 24) & 0xFF); + DBG_VERBOSE("%0i.", (entry->entry.ip_src >> 16) & 0xFF); + DBG_VERBOSE("%0i.", (entry->entry.ip_src >> 8) & 0xFF); + DBG_VERBOSE("%0i", entry->entry.ip_src & 0xFF); + DBG_VERBOSE("] "); + + // Log the network dest + DBG_VERBOSE("nwdst["); + DBG_VERBOSE("%0i.", (entry->entry.ip_dst >> 24) & 0xFF); + DBG_VERBOSE("%0i.", (entry->entry.ip_dst >> 16) & 0xFF); + DBG_VERBOSE("%0i.", (entry->entry.ip_dst >> 8) & 0xFF); + DBG_VERBOSE("%0i", entry->entry.ip_dst & 0xFF); + DBG_VERBOSE("] "); + + // Log the network TOS + DBG_VERBOSE("nwtos[0x%0X] ", entry->entry.ip_tos); + + // Log the transport source port + DBG_VERBOSE("tsrc[%i] ", entry->entry.transp_src); + + // Log the transport dest port + DBG_VERBOSE("tdst[%i]\n", entry->entry.transp_dst); +#endif +} + +static void +log_entry_raw(nf2_of_entry_wrap *entry) +{ +#ifdef HWTABLE_NO_DEBUG + return; +#else + int i; + unsigned char *c; + + DBG_VERBOSE("E "); + c = (unsigned char *)entry; + for (i = 0; i < sizeof(nf2_of_entry_wrap); ++i) { + if (!(i % 4)) { + DBG_VERBOSE(" "); + } + DBG_VERBOSE("%02x", c[i]); + } + DBG_VERBOSE("\n"); +#endif +} + +static void +log_mask(nf2_of_mask_wrap *mask) +{ +#ifdef HWTABLE_NO_DEBUG + return; +#else + int i; + + // Log the physical source port + DBG_VERBOSE("M psrc[%0X] ", mask->entry.src_port / 2); + + // Log the link layer source + DBG_VERBOSE("dlsrc["); + for (i = 5; i > 0; --i) { + DBG_VERBOSE("%0X:", mask->entry.eth_src[i]); + } + DBG_VERBOSE("%0X] ", mask->entry.eth_src[0]); + + // Log the link layer dest + DBG_VERBOSE("dldst["); + for (i = 5; i > 0; --i) { + DBG_VERBOSE("%0X:", mask->entry.eth_dst[i]); + } + DBG_VERBOSE("%0X] ", mask->entry.eth_dst[0]); + + // Log the link layer type + DBG_VERBOSE("dltype[%0X] ", mask->entry.eth_type); + + // Log the link layer vlan + DBG_VERBOSE("dlvlan[%0X] ", mask->entry.vlan_id); + + // Log the network source + DBG_VERBOSE("nwsrc["); + DBG_VERBOSE("%0X.", (mask->entry.ip_src >> 24) & 0xFF); + DBG_VERBOSE("%0X.", (mask->entry.ip_src >> 16) & 0xFF); + DBG_VERBOSE("%0X.", (mask->entry.ip_src >> 8) & 0xFF); + DBG_VERBOSE("%0X", mask->entry.ip_src & 0xFF); + DBG_VERBOSE("] "); + + // Log the network dest + DBG_VERBOSE("nwdst["); + DBG_VERBOSE("%0X.", (mask->entry.ip_dst >> 24) & 0xFF); + DBG_VERBOSE("%0X.", (mask->entry.ip_dst >> 16) & 0xFF); + DBG_VERBOSE("%0X.", (mask->entry.ip_dst >> 8) & 0xFF); + DBG_VERBOSE("%0X", mask->entry.ip_dst & 0xFF); + DBG_VERBOSE("] "); + + // Log the network TOS + DBG_VERBOSE("nwtos[0x%0X] ", mask->entry.ip_tos); + + // Log the transport source port + DBG_VERBOSE("tsrc[%0X] ", mask->entry.transp_src); + + // Log the transport dest port + DBG_VERBOSE("tdst[%0X]\n", mask->entry.transp_dst); +#endif +} + +static void +log_mask_raw(nf2_of_mask_wrap *mask) +{ +#ifdef HWTABLE_NO_DEBUG + return; +#else + int i; + unsigned char *c; + + DBG_VERBOSE("M "); + c = (unsigned char *)mask; + for (i = 0; i < sizeof(nf2_of_mask_wrap); ++i) { + if (!(i % 4)) { + DBG_VERBOSE(" "); + } + DBG_VERBOSE("%02x", c[i]); + } + DBG_VERBOSE("\n"); +#endif +} + +static void +log_action(nf2_of_action_wrap *action) +{ +#ifdef HWTABLE_NO_DEBUG + return; +#else + int i; + + DBG_VERBOSE("A Output P["); + for (i = 0; i < 4; ++i) { + if (action->action.forward_bitmask & (1 << (i * 2))) { + DBG_VERBOSE("%i", i); + } + } + DBG_VERBOSE("] CPU["); + for (i = 0; i < 4; ++i) { + if (action->action.forward_bitmask & (1 << (1 + (i * 2)))) { + DBG_VERBOSE("%i", i); + } + } + DBG_VERBOSE("]\n"); + + // Log the link layer source + if (action->action.nf2_action_flag & (1 << OFPAT_SET_DL_SRC)) { + DBG_VERBOSE("A Modify: dlsrc: new value ["); + for (i = 5; i > 0; --i) { + DBG_VERBOSE("%0X:", action->action.eth_src[i]); + } + DBG_VERBOSE("%0X]\n", action->action.eth_src[0]); + } + + // Log the link layer dest + if (action->action.nf2_action_flag & (1 << OFPAT_SET_DL_DST)) { + DBG_VERBOSE("A Modify: dldst: new value ["); + for (i = 5; i > 0; --i) { + DBG_VERBOSE("%0X:", action->action.eth_dst[i]); + } + DBG_VERBOSE("%0X]\n", action->action.eth_dst[0]); + } + + // Log the link layer vlan id + if (action->action.nf2_action_flag & (1 << OFPAT_SET_VLAN_VID)) { + DBG_VERBOSE("A Modify: dlvlanid: new value [%0X]\n", + action->action.vlan_id); + } + + // Log the link layer vlan pcp + if (action->action.nf2_action_flag & (1 << OFPAT_SET_VLAN_PCP)) { + DBG_VERBOSE("A Modify: dlvlanpcp: new value [%0X]\n", + action->action.vlan_pcp); + } + + // Log the link layer vlan strip + if (action->action.nf2_action_flag & (1 << OFPAT_STRIP_VLAN)) { + DBG_VERBOSE("A Modify: dlvlan strip\n"); + } + + // Log the network source + if (action->action.nf2_action_flag & (1 << OFPAT_SET_NW_SRC)) { + DBG_VERBOSE("A Modify: nwsrc: new value ["); + DBG_VERBOSE("%0i.", (action->action.ip_src >> 24) & 0xFF); + DBG_VERBOSE("%0i.", (action->action.ip_src >> 16) & 0xFF); + DBG_VERBOSE("%0i.", (action->action.ip_src >> 8) & 0xFF); + DBG_VERBOSE("%0i", action->action.ip_src & 0xFF); + DBG_VERBOSE("]\n"); + } + + // Log the network dest + if (action->action.nf2_action_flag & (1 << OFPAT_SET_NW_DST)) { + DBG_VERBOSE("A Modify: nwdst: new value ["); + DBG_VERBOSE("%0i.", (action->action.ip_dst >> 24) & 0xFF); + DBG_VERBOSE("%0i.", (action->action.ip_dst >> 16) & 0xFF); + DBG_VERBOSE("%0i.", (action->action.ip_dst >> 8) & 0xFF); + DBG_VERBOSE("%0i", action->action.ip_dst & 0xFF); + DBG_VERBOSE("]\n"); + } + + // Log the network TOS + if (action->action.nf2_action_flag & (1 << OFPAT_SET_NW_TOS)) { + DBG_VERBOSE("A Modify: nwtos: new value [%0X]\n", + action->action.ip_tos & 0xFF); + } + + // Log the transport source port + if (action->action.nf2_action_flag & (1 << OFPAT_SET_TP_SRC)) { + DBG_VERBOSE("A Modify: tsrc: new value [%0X]\n", + action->action.transp_src); + } + + // Log the transport dest port + if (action->action.nf2_action_flag & (1 << OFPAT_SET_TP_DST)) { + DBG_VERBOSE("A Modify: tdst: new value [%0X]\n", + action->action.transp_dst); + } +#endif +} + +static void +log_action_raw(nf2_of_action_wrap *action) +{ +#ifdef HWTABLE_NO_DEBUG + return; +#else + int i; + unsigned char *c; + + DBG_VERBOSE("A "); + c = (unsigned char *)action; + for (i = 0; i < sizeof(nf2_of_action_wrap); ++i) { + if (!(i % 4)) { + DBG_VERBOSE(" "); + } + DBG_VERBOSE("%02x", c[i]); + } + DBG_VERBOSE("\n"); +#endif +} + +void +nf2_reset_card(struct nf2device *dev) +{ + volatile unsigned int val; + + /* If we are operating on a NetFPGA enabled box, reset the card */ + readReg(dev, CPCI_REG_CTRL, (void *)&val); + val |= 0x100; + writeReg(dev, CPCI_REG_CTRL, val); + DBG_VERBOSE("Reset the NetFPGA.\n"); + sleep(2); +} + +void +nf2_clear_watchdog(struct nf2device *dev) +{ + volatile unsigned int enable_status; + +#ifndef NF2_WATCHDOG + return; +#endif + log_watchdog_info(dev); + + readReg(dev, WDT_ENABLE_FLG_REG, (void *)&enable_status); + enable_status &= 0x1; + + if (enable_status == WATCHDOG_DISABLE) { + enable_status = WATCHDOG_ENABLE; + writeReg(dev, WDT_ENABLE_FLG_REG, enable_status); + } +} + +/* Write a wildcard entry to the specified device and row. The row consists of + * the actual entry, its mask that specifies wildcards, as well as the action(s) + * to be taken if the row is matched + */ +int +nf2_write_of_wildcard(struct nf2device *dev, int row, + nf2_of_entry_wrap *entry, nf2_of_mask_wrap *mask, + nf2_of_action_wrap *action) +{ + int i; + unsigned int val; + + DBG_VERBOSE("** Begin wildcard entry write to row: %i\n", row); + log_entry(entry); + log_mask(mask); + log_action(action); + log_entry_raw(entry); + log_mask_raw(mask); + log_action_raw(action); + + for (i = 0; i < NF2_OF_ENTRY_WORD_LEN; ++i) { + writeReg(dev, + OPENFLOW_WILDCARD_LOOKUP_CMP_0_REG + + (4 * i), entry->raw[i]); + } + + for (i = 0; i < NF2_OF_MASK_WORD_LEN; ++i) { + writeReg(dev, + OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_0_REG + + (4 * i), mask->raw[i]); + } + + for (i = 0; i < NF2_OF_ACTION_WORD_LEN; ++i) { + writeReg(dev, + OPENFLOW_WILDCARD_LOOKUP_ACTION_0_REG + + (4 * i), action->raw[i]); + } + + // Reset the stats for the row + val = 0; + writeReg(dev, + OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG + (4 * row), + val); + writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG + (4 * row), + val); + writeReg(dev, + OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_0_REG + (4 * row), + val); + writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_WRITE_ADDR_REG, row); + + DBG_VERBOSE("** End wildcard entry write to row: %i time(msec): %llu\n", + row, time_msec()); + + return 0; +} + +int +nf2_write_of_exact(struct nf2device *dev, int row, + nf2_of_entry_wrap *entry, nf2_of_action_wrap *action) +{ + int i; + unsigned int val; + unsigned int index = row << 7; + + DBG_VERBOSE("** Begin exact match entry write to row: %i\n", row); + log_entry(entry); + log_action(action); + log_entry_raw(entry); + log_action_raw(action); + + for (i = 0; i < NF2_OF_ENTRY_WORD_LEN; ++i) { + writeReg(dev, SRAM_BASE_ADDR + index + + (4 * i), entry->raw[i]); + } + + // blank out the counters + val = 0; + for (i = 0; i < NF2_OF_EXACT_COUNTERS_WORD_LEN; ++i) { + writeReg(dev, SRAM_BASE_ADDR + index + + sizeof(nf2_of_entry_wrap) + + (4 * i), val); + } + + // write the actions + for (i = 0; i < NF2_OF_ACTION_WORD_LEN; ++i) { + writeReg(dev, SRAM_BASE_ADDR + index + + sizeof(nf2_of_entry_wrap) + + sizeof(nf2_of_exact_counters_wrap) + + (4 * i), action->raw[i]); + } + + DBG_VERBOSE + ("** End exact match entry write to row: %i time(msec): %llu\n", + row, time_msec()); + + return 0; +} + +/* Write wildcard action(s) to the specified device and row. */ +int +nf2_modify_write_of_wildcard(struct nf2device *dev, int row, + nf2_of_entry_wrap *entry, nf2_of_mask_wrap *mask, + nf2_of_action_wrap *action) +{ + int i; + unsigned int bytes_reg_val; + unsigned int pkts_reg_val; + unsigned int last_reg_val; + + DBG_VERBOSE("** Begin wildcard modified action write to row: %i\n", + row); + log_entry(entry); + log_mask(mask); + log_action(action); + log_entry_raw(entry); + log_mask_raw(mask); + log_action_raw(action); + + writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_READ_ADDR_REG, row); + readReg(dev, + OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG + (4 * row), + &bytes_reg_val); + readReg(dev, + OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG + (4 * row), + &pkts_reg_val); + readReg(dev, + OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_0_REG + (4 * row), + &last_reg_val); + + for (i = 0; i < NF2_OF_ENTRY_WORD_LEN; ++i) { + writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_CMP_0_REG + + (4 * i), entry->raw[i]); + } + + for (i = 0; i < NF2_OF_MASK_WORD_LEN; ++i) { + writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_0_REG + + (4 * i), mask->raw[i]); + } + + for (i = 0; i < NF2_OF_ACTION_WORD_LEN; ++i) { + writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_ACTION_0_REG + + (4 * i), action->raw[i]); + } + + writeReg(dev, + OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG + (4 * row), + bytes_reg_val); + writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG + (4 * row), + pkts_reg_val); + writeReg(dev, + OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_0_REG + (4 * row), + last_reg_val); + writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_WRITE_ADDR_REG, row); + + DBG_VERBOSE + ("** End wildcard modified action write to row: %i time(msec): %llu\n", + row, time_msec()); + DBG_VERBOSE(" Bytes hit count: %d\n", bytes_reg_val); + DBG_VERBOSE(" Pkts hit count: %d\n", pkts_reg_val); + DBG_VERBOSE(" Last seen : %d\n", last_reg_val); + + return 0; +} + +int +nf2_modify_write_of_exact(struct nf2device *dev, int row, + nf2_of_action_wrap *action) +{ + int i; + unsigned int index = row << 7; + + DBG_VERBOSE("** Begin exact match modified action write to row: %i\n", + row); + log_action(action); + log_action_raw(action); + + // write the actions + for (i = 0; i < NF2_OF_ACTION_WORD_LEN; ++i) { + writeReg(dev, SRAM_BASE_ADDR + index + + sizeof(nf2_of_entry_wrap) + + sizeof(nf2_of_exact_counters_wrap) + + (4 * i), action->raw[i]); + } + + DBG_VERBOSE + ("** End exact match modified action write to row: %i time(msec): %llu\n", + row, time_msec()); + + return 0; +} + +unsigned int +nf2_get_exact_packet_count(struct nf2device *dev, int row) +{ + unsigned int val = 0; + unsigned int index = 0; + + /* TODO: Need to scrape data from all 4 registers + * in the case of a wildcarded source port and + * forward all action type + */ + nf2_of_exact_counters_wrap counters; + memset(&counters, 0, sizeof(nf2_of_exact_counters_wrap)); + + // build the index to our counters + index = row << 7; + + // Read the first word into our struct, to not disturb the byte count + readReg(dev, + SRAM_BASE_ADDR + index + sizeof(nf2_of_entry_wrap), + &counters.raw[0]); + val = counters.counters.pkt_count; + + DBG_VERBOSE + ("** Exact match packet count(delta) row: %i count: %i time(msec): %llu\n", + row, val, time_msec()); + + return val; +} + +unsigned int +nf2_get_exact_byte_count(struct nf2device *dev, int row) +{ + unsigned int val = 0; + unsigned int index = 0; + + /* TODO: Need to scrape data from all 4 registers + * in the case of a wildcarded source port and + * forward all action type + */ + nf2_of_exact_counters_wrap counters; + memset(&counters, 0, sizeof(nf2_of_exact_counters_wrap)); + + // build the index to our counters + index = row << 7; + + // Read the second word into our struct, to not disturb the packet count + readReg(dev, SRAM_BASE_ADDR + index + + sizeof(nf2_of_entry_wrap) + 4, &counters.raw[1]); + val = counters.counters.byte_count; + + DBG_VERBOSE + ("** Exact match byte count(delta) row: %i count: %i time(msec): %llu\n", + row, val, time_msec()); + + return val; +} + +unsigned int +nf2_get_wildcard_packet_count(struct nf2device *dev, int row) +{ + unsigned int val = 0; + + writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_READ_ADDR_REG, row); + readReg(dev, OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG + + (4 * row), &val); + + DBG_VERBOSE + ("** Wildcard packet count(sum) row: %i count: %i time(msec): %llu\n", + row, val, time_msec()); + + return val; +} + +unsigned int +nf2_get_wildcard_byte_count(struct nf2device *dev, int row) +{ + unsigned int val = 0; + + writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_READ_ADDR_REG, row); + readReg(dev, OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG + + (4 * row), &val); + + DBG_VERBOSE + ("** Wildcard byte count(sum) row: %i count: %i time(msec): %llu\n", + row, val, time_msec()); + + return val; +} + +unsigned long int +nf2_get_matched_count(struct nf2device *dev) +{ + unsigned int val_wild = 0; + unsigned int val_exact = 0; + + readReg(dev, OPENFLOW_LOOKUP_WILDCARD_HITS_REG, &val_wild); + readReg(dev, OPENFLOW_LOOKUP_EXACT_HITS_REG, &val_exact); + + DBG_VERBOSE("** Wildcard Matched count: %i time(msec): %llu\n", + val_wild, time_msec()); + DBG_VERBOSE("** Exact Matched count: %i time(msec): %llu\n", + val_exact, time_msec()); + + return ((unsigned long int)(val_wild + val_exact)); +} + +unsigned long int +nf2_get_missed_count(struct nf2device *dev) +{ + unsigned int val_wild = 0; + unsigned int val_exact = 0; + + readReg(dev, OPENFLOW_LOOKUP_WILDCARD_MISSES_REG, &val_wild); + readReg(dev, OPENFLOW_LOOKUP_EXACT_MISSES_REG, &val_exact); + + DBG_VERBOSE("** Wildcard Missed count: %i time(msec): %llu\n", + val_wild, time_msec()); + DBG_VERBOSE("** Exact Missed count: %i time(msec): %llu\n", + val_exact, time_msec()); + + return ((unsigned long int)(val_wild + val_exact)); +} + +static void +log_watchdog_info(struct nf2device *dev) +{ +#ifdef HWTABLE_NO_DEBUG + return; +#else +#define CLK_CYCLE 8 + unsigned int nf2wdtinfo; + unsigned int elapsed_time; + readReg(dev, WDT_COUNTER_REG, &nf2wdtinfo); + elapsed_time = nf2wdtinfo * CLK_CYCLE / 1000000; + DBG_VVERB + ("%u (msec) passed since the watchdog counter has been cleared last time\n", + elapsed_time); + DBG_VVERB("NetFPGA WDT now clearing\n"); +#endif +} + +static void +nf2_get_all_ports_info_addr(struct nf2_all_ports_info_addr *nf2addr) +{ + nf2addr->rx_q_num_pkts_stored_reg[0] + = MAC_GRP_0_RX_QUEUE_NUM_PKTS_STORED_REG; + nf2addr->rx_q_num_pkts_dropped_full_reg[0] + = MAC_GRP_0_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG; + nf2addr->rx_q_num_pkts_dropped_bad_reg[0] + = MAC_GRP_0_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG; + nf2addr->rx_q_num_words_pushed_reg[0] + = MAC_GRP_0_RX_QUEUE_NUM_WORDS_PUSHED_REG; + nf2addr->rx_q_num_bytes_pushed_reg[0] + = MAC_GRP_0_RX_QUEUE_NUM_BYTES_PUSHED_REG; + nf2addr->rx_q_num_pkts_dequeued_reg[0] + = MAC_GRP_0_RX_QUEUE_NUM_PKTS_DEQUEUED_REG; + nf2addr->rx_q_num_pkts_in_queue_reg[0] + = MAC_GRP_0_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG; + nf2addr->tx_q_num_pkts_in_queue_reg[0] + = MAC_GRP_0_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG; + nf2addr->tx_q_num_pkts_sent_reg[0] + = MAC_GRP_0_TX_QUEUE_NUM_PKTS_SENT_REG; + nf2addr->tx_q_num_words_pushed_reg[0] + = MAC_GRP_0_TX_QUEUE_NUM_WORDS_PUSHED_REG; + nf2addr->tx_q_num_bytes_pushed_reg[0] + = MAC_GRP_0_TX_QUEUE_NUM_BYTES_PUSHED_REG; + nf2addr->tx_q_num_pkts_enqueued_reg[0] + = MAC_GRP_0_TX_QUEUE_NUM_PKTS_ENQUEUED_REG; + + nf2addr->rx_q_num_pkts_stored_reg[1] + = MAC_GRP_1_RX_QUEUE_NUM_PKTS_STORED_REG; + nf2addr->rx_q_num_pkts_dropped_full_reg[1] + = MAC_GRP_1_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG; + nf2addr->rx_q_num_pkts_dropped_bad_reg[1] + = MAC_GRP_1_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG; + nf2addr->rx_q_num_words_pushed_reg[1] + = MAC_GRP_1_RX_QUEUE_NUM_WORDS_PUSHED_REG; + nf2addr->rx_q_num_bytes_pushed_reg[1] + = MAC_GRP_1_RX_QUEUE_NUM_BYTES_PUSHED_REG; + nf2addr->rx_q_num_pkts_dequeued_reg[1] + = MAC_GRP_1_RX_QUEUE_NUM_PKTS_DEQUEUED_REG; + nf2addr->rx_q_num_pkts_in_queue_reg[1] + = MAC_GRP_1_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG; + nf2addr->tx_q_num_pkts_in_queue_reg[1] + = MAC_GRP_1_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG; + nf2addr->tx_q_num_pkts_sent_reg[1] + = MAC_GRP_1_TX_QUEUE_NUM_PKTS_SENT_REG; + nf2addr->tx_q_num_words_pushed_reg[1] + = MAC_GRP_1_TX_QUEUE_NUM_WORDS_PUSHED_REG; + nf2addr->tx_q_num_bytes_pushed_reg[1] + = MAC_GRP_1_TX_QUEUE_NUM_BYTES_PUSHED_REG; + nf2addr->tx_q_num_pkts_enqueued_reg[1] + = MAC_GRP_1_TX_QUEUE_NUM_PKTS_ENQUEUED_REG; + + nf2addr->rx_q_num_pkts_stored_reg[2] + = MAC_GRP_2_RX_QUEUE_NUM_PKTS_STORED_REG; + nf2addr->rx_q_num_pkts_dropped_full_reg[2] + = MAC_GRP_2_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG; + nf2addr->rx_q_num_pkts_dropped_bad_reg[2] + = MAC_GRP_2_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG; + nf2addr->rx_q_num_words_pushed_reg[2] + = MAC_GRP_2_RX_QUEUE_NUM_WORDS_PUSHED_REG; + nf2addr->rx_q_num_bytes_pushed_reg[2] + = MAC_GRP_2_RX_QUEUE_NUM_BYTES_PUSHED_REG; + nf2addr->rx_q_num_pkts_dequeued_reg[2] + = MAC_GRP_2_RX_QUEUE_NUM_PKTS_DEQUEUED_REG; + nf2addr->rx_q_num_pkts_in_queue_reg[2] + = MAC_GRP_2_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG; + nf2addr->tx_q_num_pkts_in_queue_reg[2] + = MAC_GRP_2_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG; + nf2addr->tx_q_num_pkts_sent_reg[2] + = MAC_GRP_2_TX_QUEUE_NUM_PKTS_SENT_REG; + nf2addr->tx_q_num_words_pushed_reg[2] + = MAC_GRP_2_TX_QUEUE_NUM_WORDS_PUSHED_REG; + nf2addr->tx_q_num_bytes_pushed_reg[2] + = MAC_GRP_2_TX_QUEUE_NUM_BYTES_PUSHED_REG; + nf2addr->tx_q_num_pkts_enqueued_reg[2] + = MAC_GRP_2_TX_QUEUE_NUM_PKTS_ENQUEUED_REG; + + nf2addr->rx_q_num_pkts_stored_reg[3] + = MAC_GRP_3_RX_QUEUE_NUM_PKTS_STORED_REG; + nf2addr->rx_q_num_pkts_dropped_full_reg[3] + = MAC_GRP_3_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG; + nf2addr->rx_q_num_pkts_dropped_bad_reg[3] + = MAC_GRP_3_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG; + nf2addr->rx_q_num_words_pushed_reg[3] + = MAC_GRP_3_RX_QUEUE_NUM_WORDS_PUSHED_REG; + nf2addr->rx_q_num_bytes_pushed_reg[3] + = MAC_GRP_3_RX_QUEUE_NUM_BYTES_PUSHED_REG; + nf2addr->rx_q_num_pkts_dequeued_reg[3] + = MAC_GRP_3_RX_QUEUE_NUM_PKTS_DEQUEUED_REG; + nf2addr->rx_q_num_pkts_in_queue_reg[3] + = MAC_GRP_3_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG; + nf2addr->tx_q_num_pkts_in_queue_reg[3] + = MAC_GRP_3_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG; + nf2addr->tx_q_num_pkts_sent_reg[3] + = MAC_GRP_3_TX_QUEUE_NUM_PKTS_SENT_REG; + nf2addr->tx_q_num_words_pushed_reg[3] + = MAC_GRP_3_TX_QUEUE_NUM_WORDS_PUSHED_REG; + nf2addr->tx_q_num_bytes_pushed_reg[3] + = MAC_GRP_3_TX_QUEUE_NUM_BYTES_PUSHED_REG; + nf2addr->tx_q_num_pkts_enqueued_reg[3] + = MAC_GRP_3_TX_QUEUE_NUM_PKTS_ENQUEUED_REG; +} + +int +nf2_get_port_info(struct nf2device *dev, int nf_port, + struct nf2_port_info *nf2portinfo) +{ + struct nf2_all_ports_info_addr *nf2addr; + + if ((nf_port >= NF2_PORT_NUM) || (nf_port < 0)) { + DBG_ERROR("Illegal port number\n"); + return 1; + } + + nf2addr = calloc(1, sizeof(struct nf2_all_ports_info_addr)); + if (nf2addr == NULL) { + DBG_ERROR("Could not allocate memory for port information gathering\n"); + return 1; + } + nf2_get_all_ports_info_addr(nf2addr); + + readReg(dev, nf2addr->rx_q_num_pkts_stored_reg[nf_port], + &(nf2portinfo->rx_q_num_pkts_stored)); + readReg(dev, nf2addr->rx_q_num_pkts_dropped_full_reg[nf_port], + &(nf2portinfo->rx_q_num_pkts_dropped_full)); + readReg(dev, nf2addr->rx_q_num_pkts_dropped_bad_reg[nf_port], + &(nf2portinfo->rx_q_num_pkts_dropped_bad)); + readReg(dev, nf2addr->rx_q_num_words_pushed_reg[nf_port], + &(nf2portinfo->rx_q_num_words_pushed)); + readReg(dev, nf2addr->rx_q_num_bytes_pushed_reg[nf_port], + &(nf2portinfo->rx_q_num_bytes_pushed)); + readReg(dev, nf2addr->rx_q_num_pkts_dequeued_reg[nf_port], + &(nf2portinfo->rx_q_num_pkts_dequeued)); + readReg(dev, nf2addr->rx_q_num_pkts_in_queue_reg[nf_port], + &(nf2portinfo->rx_q_num_pkts_in_queue)); + readReg(dev, nf2addr->tx_q_num_pkts_in_queue_reg[nf_port], + &(nf2portinfo->tx_q_num_pkts_in_queue)); + readReg(dev, nf2addr->tx_q_num_pkts_sent_reg[nf_port], + &(nf2portinfo->tx_q_num_pkts_sent)); + readReg(dev, nf2addr->tx_q_num_words_pushed_reg[nf_port], + &(nf2portinfo->tx_q_num_words_pushed)); + readReg(dev, nf2addr->tx_q_num_bytes_pushed_reg[nf_port], + &(nf2portinfo->tx_q_num_bytes_pushed)); + readReg(dev, nf2addr->tx_q_num_pkts_enqueued_reg[nf_port], + &(nf2portinfo->tx_q_num_pkts_enqueued)); + free(nf2addr); + return 0; +} diff --git a/openflow/hw-lib/nf2/nf2_drv.h b/openflow/hw-lib/nf2/nf2_drv.h new file mode 100644 index 00000000..6f961267 --- /dev/null +++ b/openflow/hw-lib/nf2/nf2_drv.h @@ -0,0 +1,150 @@ +/*- + * Copyright (c) 2008, 2009, 2010 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#ifndef HATABLE_NF2_NF2_OPENFLOW_H_ +#define HATABLE_NF2_NF2_OPENFLOW_H_ + +#define OPENFLOW_NF2_EXACT_TABLE_SIZE 32768 +#define WATCHDOG_ENABLE 1 +#define WATCHDOG_DISABLE 0 + +#pragma pack(push) /* push current alignment to stack */ +#pragma pack(1) /* set alignment to 1 byte boundary */ + +#define NF2_OF_ENTRY_WORD_LEN 8 +struct nf2_of_entry { + uint16_t transp_dst; + uint16_t transp_src; + uint8_t ip_proto; + uint32_t ip_dst; + uint32_t ip_src; + uint16_t eth_type; + uint8_t eth_dst[6]; + uint8_t eth_src[6]; + uint8_t src_port; + uint8_t ip_tos; + uint16_t vlan_id; + uint8_t pad; +}; + +typedef union nf2_of_entry_wrap { + struct nf2_of_entry entry; + uint32_t raw[NF2_OF_ENTRY_WORD_LEN]; +} nf2_of_entry_wrap; + +typedef nf2_of_entry_wrap nf2_of_mask_wrap; +#define NF2_OF_MASK_WORD_LEN 8 + +struct nf2_of_action { + uint16_t forward_bitmask; + uint16_t nf2_action_flag; + uint16_t vlan_id; + uint8_t vlan_pcp; + uint8_t eth_src[6]; + uint8_t eth_dst[6]; + uint32_t ip_src; + uint32_t ip_dst; + uint8_t ip_tos; + uint16_t transp_src; + uint16_t transp_dst; + uint8_t reserved[18]; +}; + +#define NF2_OF_ACTION_WORD_LEN 10 +typedef union nf2_of_action_wrap { + struct nf2_of_action action; + uint32_t raw[10]; +} nf2_of_action_wrap; + +struct nf2_of_exact_counters { + uint32_t pkt_count:25; + uint8_t last_seen:7; + uint32_t byte_count; +}; + +#define NF2_OF_EXACT_COUNTERS_WORD_LEN 2 +typedef union nf2_of_exact_counters_wrap { + struct nf2_of_exact_counters counters; + uint32_t raw[NF2_OF_EXACT_COUNTERS_WORD_LEN]; +} nf2_of_exact_counters_wrap; + +#define NF2_PORT_NUM 4 +struct nf2_all_ports_info_addr { + unsigned int rx_q_num_pkts_stored_reg[NF2_PORT_NUM]; + unsigned int rx_q_num_pkts_dropped_full_reg[NF2_PORT_NUM]; + unsigned int rx_q_num_pkts_dropped_bad_reg[NF2_PORT_NUM]; + unsigned int rx_q_num_words_pushed_reg[NF2_PORT_NUM]; + unsigned int rx_q_num_bytes_pushed_reg[NF2_PORT_NUM]; + unsigned int rx_q_num_pkts_dequeued_reg[NF2_PORT_NUM]; + unsigned int rx_q_num_pkts_in_queue_reg[NF2_PORT_NUM]; + unsigned int tx_q_num_pkts_in_queue_reg[NF2_PORT_NUM]; + unsigned int tx_q_num_pkts_sent_reg[NF2_PORT_NUM]; + unsigned int tx_q_num_words_pushed_reg[NF2_PORT_NUM]; + unsigned int tx_q_num_bytes_pushed_reg[NF2_PORT_NUM]; + unsigned int tx_q_num_pkts_enqueued_reg[NF2_PORT_NUM]; +}; + +struct nf2_port_info { + uint32_t rx_q_num_pkts_stored; + uint32_t rx_q_num_pkts_dropped_full; + uint32_t rx_q_num_pkts_dropped_bad; + uint32_t rx_q_num_words_pushed; + uint32_t rx_q_num_bytes_pushed; + uint32_t rx_q_num_pkts_dequeued; + uint32_t rx_q_num_pkts_in_queue; + uint32_t tx_q_num_pkts_in_queue; + uint32_t tx_q_num_pkts_sent; + uint32_t tx_q_num_words_pushed; + uint32_t tx_q_num_bytes_pushed; + uint32_t tx_q_num_pkts_enqueued; +}; + +#pragma pack(pop) /* XXX: Restore original alignment from stack */ + +void nf2_reset_card(struct nf2device *); +void nf2_clear_watchdog(struct nf2device *); +int nf2_write_of_wildcard(struct nf2device *, int, nf2_of_entry_wrap *, + nf2_of_mask_wrap *, nf2_of_action_wrap *); +int nf2_write_of_exact(struct nf2device *, int, nf2_of_entry_wrap *, + nf2_of_action_wrap *); +int nf2_modify_write_of_wildcard(struct nf2device *, int, nf2_of_entry_wrap *, + nf2_of_mask_wrap *, nf2_of_action_wrap *); +int nf2_modify_write_of_exact(struct nf2device *, int, nf2_of_action_wrap *); +unsigned int nf2_get_exact_packet_count(struct nf2device *, int); +unsigned int nf2_get_exact_byte_count(struct nf2device *, int); +unsigned int nf2_get_wildcard_packet_count(struct nf2device *, int); +unsigned int nf2_get_wildcard_byte_count(struct nf2device *, int); +unsigned long int nf2_get_matched_count(struct nf2device *); +unsigned long int nf2_get_missed_count(struct nf2device *); +int nf2_get_port_info(struct nf2device *, int, struct nf2_port_info *); + +#endif diff --git a/openflow/hw-lib/nf2/nf2_lib.c b/openflow/hw-lib/nf2/nf2_lib.c new file mode 100644 index 00000000..972d91bd --- /dev/null +++ b/openflow/hw-lib/nf2/nf2_lib.c @@ -0,0 +1,1049 @@ +/*- + * Copyright (c) 2008, 2009, 2010 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#include +#include + +#include "list.h" +#include "udatapath/crc32.h" +#include "udatapath/switch-flow.h" +#include "udatapath/table.h" +#include "reg_defines_openflow_switch.h" +#include "nf2.h" +#include "nf2util.h" +#include "hw_flow.h" +#include "nf2_drv.h" +#include "nf2_lib.h" +#include "debug.h" + +#define DEFAULT_IFACE "nf2c0" + +#define MAX_INT_32 0xFFFFFFFF +#define PORT_BASE 1 + +#define VID_BITMASK 0x0FFF +#define PCP_BITSHIFT 13 +#define PCP_BITMASK 0xE000 +#define TOS_BITMASK 0xFC + +struct list wildcard_free_list; +struct nf2_flow *exact_free_list[OPENFLOW_NF2_EXACT_TABLE_SIZE]; + +static uint32_t make_nw_wildcard(int); +static struct nf2_flow *get_free_exact(nf2_of_entry_wrap *); +static struct nf2_flow *get_free_wildcard(void); +static int is_action_forward_all(struct sw_flow *); +static void populate_action_output(nf2_of_action_wrap *, nf2_of_entry_wrap *, + uint8_t *); +static void populate_action_set_dl_src(nf2_of_action_wrap *, uint8_t *); +static void populate_action_set_dl_dst(nf2_of_action_wrap *, uint8_t *); +static void populate_action_set_nw_src(nf2_of_action_wrap *, uint8_t *); +static void populate_action_set_nw_dst(nf2_of_action_wrap *, uint8_t *); +static void populate_action_set_tp_src(nf2_of_action_wrap *, uint8_t *); +static void populate_action_set_tp_dst(nf2_of_action_wrap *, uint8_t *); +static void populate_action_set_nw_tos(nf2_of_action_wrap *, uint8_t *); +static void populate_action_set_vlan_vid(nf2_of_action_wrap *, uint8_t *); +static void populate_action_set_vlan_pcp(nf2_of_action_wrap *, uint8_t *); +static void populate_action_strip_vlan(nf2_of_action_wrap *); + +int iface_chk_done = 0; +int net_iface = 0; + +struct nf2device * +nf2_get_net_device(void) +{ + struct nf2device *dev; + dev = calloc(1, sizeof(struct nf2device)); + dev->device_name = DEFAULT_IFACE; + + if (iface_chk_done) { + dev->net_iface = net_iface; + } else { + if (check_iface(dev)) { + iface_chk_done = 0; + return NULL; + } else { + iface_chk_done = 1; + net_iface = dev->net_iface; + } + } + + if (openDescriptor(dev)) { + return NULL; + } + return dev; +} + +void +nf2_free_net_device(struct nf2device *dev) +{ + if (dev == NULL){ + return; + } + + closeDescriptor(dev); + free(dev); +} + +/* Checks to see if the actions requested by the flow are capable of being + * done in the NF2 hardware. Returns 1 if yes, 0 for no. + */ +int +nf2_are_actions_supported(struct sw_flow *flow) +{ + struct sw_flow_actions *sfa; + size_t actions_len; + uint8_t *p; + + sfa = flow->sf_acts; + actions_len = sfa->actions_len; + p = (uint8_t *)sfa->actions; + + while (actions_len > 0) { + struct ofp_action_header *ah = (struct ofp_action_header *)p; + struct ofp_action_output *oa = (struct ofp_action_output *)p; + size_t len = ntohs(ah->len); + + DBG_VERBOSE("Action Support Chk: Len of this action: %i\n", + len); + DBG_VERBOSE("Action Support Chk: Len of actions : %i\n", + actions_len); + + // All the modify actions are supported. + // Each of them can be specified once otherwise overwritten. + // Output action happens last. + if (!(ntohs(ah->type) == OFPAT_OUTPUT + || ntohs(ah->type) == OFPAT_SET_DL_SRC + || ntohs(ah->type) == OFPAT_SET_DL_DST + + || ntohs(ah->type) == OFPAT_SET_NW_SRC + || ntohs(ah->type) == OFPAT_SET_NW_DST + + || ntohs(ah->type) == OFPAT_SET_NW_TOS + + || ntohs(ah->type) == OFPAT_SET_TP_SRC + || ntohs(ah->type) == OFPAT_SET_TP_DST + + || ntohs(ah->type) == OFPAT_SET_VLAN_VID + || ntohs(ah->type) == OFPAT_SET_VLAN_PCP + || ntohs(ah->type) == OFPAT_STRIP_VLAN)) { + DBG_VERBOSE + ("Flow action type %#0x not supported in hardware\n", + ntohs(ah->type)); + return 0; + } + // Only support ports 1-4(incl. IN_PORT), ALL, FLOOD. + // Let CONTROLLER/LOCAL fall through + if ((ntohs(ah->type) == OFPAT_OUTPUT) + && (!((ntohs(oa->port) >= PORT_BASE) + && (ntohs(oa->port) <= MAX_IFACE)) + && !(ntohs(oa->port) == OFPP_ALL) + && !(ntohs(oa->port) == OFPP_FLOOD) + && !(ntohs(oa->port) == OFPP_IN_PORT))) { + DBG_VERBOSE + ("Flow action output port %#0x is not supported in hardware\n", + ntohs(oa->port)); + return 0; + } + p += len; + actions_len -= len; + } + + return 1; +} + +/* Write all 0's out to an exact entry position. */ +void +nf2_clear_of_exact(uint32_t pos) +{ + nf2_of_entry_wrap entry; + nf2_of_action_wrap action; + struct nf2device *dev = NULL; + + memset(&entry, 0, sizeof(nf2_of_entry_wrap)); + memset(&action, 0, sizeof(nf2_of_action_wrap)); + + dev = nf2_get_net_device(); + if (dev == NULL) { + DBG_ERROR("Could not open NetFPGA device\n"); + return; + } + nf2_write_of_exact(dev, pos, &entry, &action); + nf2_free_net_device(dev); +} + +/* + * Write all 0's out to a wildcard entry position + */ +void +nf2_clear_of_wildcard(uint32_t pos) +{ + nf2_of_entry_wrap entry; + nf2_of_mask_wrap mask; + nf2_of_action_wrap action; + struct nf2device *dev = NULL; + + memset(&entry, 0, sizeof(nf2_of_entry_wrap)); + memset(&mask, 0, sizeof(nf2_of_mask_wrap)); + memset(&action, 0, sizeof(nf2_of_action_wrap)); + + dev = nf2_get_net_device(); + if (dev == NULL) { + DBG_ERROR("Could not open NetFPGA device\n"); + return; + } + nf2_write_of_wildcard(dev, pos, &entry, &mask, &action); + nf2_free_net_device(dev); +} + +int +nf2_init_exact_freelist(void) +{ + struct nf2_flow *sfw = NULL; + int i; + + for (i = 0; i < (OPENFLOW_NF2_EXACT_TABLE_SIZE); ++i) { + sfw = calloc(1, sizeof(struct nf2_flow)); + if (sfw == NULL) { + return 1; + } + sfw->pos = i; + sfw->type = NF2_TABLE_EXACT; + nf2_add_free_exact(sfw); + sfw = NULL; + } + + return 0; +} + +int +nf2_init_wildcard_freelist(void) +{ + struct nf2_flow *sfw = NULL; + int i; + list_init(&wildcard_free_list); + + for (i = 0; i < (OPENFLOW_WILDCARD_TABLE_SIZE - RESERVED_FOR_CPU2NETFPGA); ++i) { + sfw = calloc(1, sizeof(struct nf2_flow)); + if (sfw == NULL) { + return 1; + } + sfw->pos = i; + sfw->type = NF2_TABLE_WILDCARD; + nf2_add_free_wildcard(sfw); + sfw = NULL; + } + + return 0; +} + +/* Called when the table is being deleted. */ +void +nf2_destroy_exact_freelist(void) +{ + struct nf2_flow *sfw = NULL; + int i; + + for (i = 0; i < (OPENFLOW_NF2_EXACT_TABLE_SIZE); ++i) { + sfw = exact_free_list[i]; + if (sfw) { + free(sfw); + } + sfw = NULL; + } +} + +/* Called when the table is being deleted. */ +void +nf2_destroy_wildcard_freelist(void) +{ + struct nf2_flow *sfw = NULL; + + while (!list_is_empty(&wildcard_free_list)) { + sfw = CONTAINER_OF(list_front(&wildcard_free_list), struct nf2_flow, node); + list_remove(&sfw->node); + free(sfw); + } +} + +/* Setup the wildcard table by adding static flows that will handle + * misses by sending them up to the cpu ports, and handle packets coming + * back down from the cpu by sending them out the corresponding port. + */ +int +nf2_write_static_wildcard(void) +{ + nf2_of_entry_wrap entry; + nf2_of_mask_wrap mask; + nf2_of_action_wrap action; + int i; + struct nf2device *dev; + + dev = nf2_get_net_device(); + if (dev == NULL) + return 1; + + memset(&entry, 0x00, sizeof(nf2_of_entry_wrap)); + memset(&mask, 0xFF, sizeof(nf2_of_mask_wrap)); + // Only non-wildcard section is the source port + mask.entry.src_port = 0; + memset(&action, 0, sizeof(nf2_of_action_wrap)); + + // write the catch all entries to send to the cpu + for (i = 0; i < 4; ++i) { + entry.entry.src_port = i * 2; + action.action.forward_bitmask = 0x1 << ((i * 2) + 1); + nf2_write_of_wildcard(dev, (OPENFLOW_WILDCARD_TABLE_SIZE - 4) + + i, &entry, &mask, &action); + } + + // write the entries to send out packets coming from the cpu + for (i = 0; i < 4; ++i) { + entry.entry.src_port = (i * 2) + 1; + action.action.forward_bitmask = 0x1 << (i * 2); + nf2_write_of_wildcard(dev, (OPENFLOW_WILDCARD_TABLE_SIZE - 8) + + i, &entry, &mask, &action); + } + + nf2_free_net_device(dev); + return 0; +} + +/* Populate a nf2_of_entry_wrap with entries from a struct sw_flow. */ +void +nf2_populate_of_entry(nf2_of_entry_wrap *key, struct sw_flow *flow) +{ + int vlan_vid; + int vlan_pcp; + int i; + + key->entry.transp_dst = ntohs(flow->key.flow.tp_dst); + key->entry.transp_src = ntohs(flow->key.flow.tp_src); + key->entry.ip_proto = flow->key.flow.nw_proto; + key->entry.ip_dst = ntohl(flow->key.flow.nw_dst); + key->entry.ip_src = ntohl(flow->key.flow.nw_src); + key->entry.eth_type = ntohs(flow->key.flow.dl_type); + // Blame Jad for applying endian'ness to character arrays + for (i = 0; i < 6; ++i) { + key->entry.eth_dst[i] = flow->key.flow.dl_dst[5 - i]; + } + for (i = 0; i < 6; ++i) { + key->entry.eth_src[i] = flow->key.flow.dl_src[5 - i]; + } + key->entry.src_port = (ntohs(flow->key.flow.in_port) - PORT_BASE) * 2; + key->entry.ip_tos = TOS_BITMASK & flow->key.flow.nw_tos; + if (ntohs(flow->key.flow.dl_vlan) == 0xffff) { + key->entry.vlan_id = 0xffff; + } else { + vlan_vid = VID_BITMASK & ntohs(flow->key.flow.dl_vlan); + vlan_pcp = PCP_BITMASK + & ((uint16_t)(flow->key.flow.dl_vlan_pcp) << PCP_BITSHIFT); + key->entry.vlan_id = vlan_pcp | vlan_vid; + } +} + +static uint32_t +make_nw_wildcard(int n_wild_bits) +{ + n_wild_bits &= (1u << OFPFW_NW_SRC_BITS) - 1; + return n_wild_bits < 32 ? ((1u << n_wild_bits) - 1) : 0xFFFFFFFF; +} + +/* Populate a nf2_of_mask_wrap with entries from a struct sw_flow's wildcards. */ +void +nf2_populate_of_mask(nf2_of_mask_wrap *mask, struct sw_flow *flow) +{ + int vlan_vid = 0; + int vlan_pcp = 0; + int i; + + if (OFPFW_IN_PORT & flow->key.wildcards) { + mask->entry.src_port = 0xFF; + } + if (OFPFW_DL_VLAN & flow->key.wildcards) { + vlan_vid = VID_BITMASK; + } + if (OFPFW_DL_VLAN_PCP & flow->key.wildcards) { + vlan_pcp = 0xF000; + } + mask->entry.vlan_id = vlan_pcp | vlan_vid; + if (OFPFW_DL_SRC & flow->key.wildcards) { + for (i = 0; i < 6; ++i) { + mask->entry.eth_src[i] = 0xFF; + } + } + if (OFPFW_DL_DST & flow->key.wildcards) { + for (i = 0; i < 6; ++i) { + mask->entry.eth_dst[i] = 0xFF; + } + } + if (OFPFW_DL_TYPE & flow->key.wildcards) + mask->entry.eth_type = 0xFFFF; + if ((OFPFW_NW_SRC_ALL & flow->key.wildcards) + || (OFPFW_NW_SRC_MASK & flow->key.wildcards)) + mask->entry.ip_src = make_nw_wildcard + (flow->key.wildcards >> OFPFW_NW_SRC_SHIFT); + if ((OFPFW_NW_DST_ALL & flow->key.wildcards) + || (OFPFW_NW_DST_MASK & flow->key.wildcards)) + mask->entry.ip_dst = make_nw_wildcard + (flow->key.wildcards >> OFPFW_NW_DST_SHIFT); + if (OFPFW_NW_PROTO & flow->key.wildcards) + mask->entry.ip_proto = 0xFF; + if (OFPFW_TP_SRC & flow->key.wildcards) + mask->entry.transp_src = 0xFFFF; + if (OFPFW_TP_DST & flow->key.wildcards) + mask->entry.transp_dst = 0xFFFF; + if (OFPFW_NW_TOS & flow->key.wildcards) + mask->entry.ip_tos = TOS_BITMASK; + + mask->entry.pad = 0x00; +} + +static void +populate_action_output(nf2_of_action_wrap *action, nf2_of_entry_wrap *entry, + uint8_t *flowact) +{ + uint16_t port = 0; + struct ofp_action_output *actout = (struct ofp_action_output *)flowact; + int i; + + port = ntohs(actout->port); + DBG_VERBOSE("Action Type: %i Output Port: %i\n", + ntohs(actout->type), port); + + if ((port >= PORT_BASE) && (port <= MAX_IFACE)) { + // Bitmask for output port(s), evens are phys odds cpu + action->action.forward_bitmask + |= (1 << ((port - PORT_BASE) * 2)); + DBG_VERBOSE("Output Port: %i Forward Bitmask: %x\n", + port, action->action.forward_bitmask); + } else if (port == OFPP_IN_PORT) { + // Send out to input port + action->action.forward_bitmask + |= (1 << (entry->entry.src_port)); + DBG_VERBOSE("Output Port = Input Port Forward Bitmask: %x\n", + action->action.forward_bitmask); + } else if (port == OFPP_ALL || port == OFPP_FLOOD) { + // Send out all ports except the source + for (i = 0; i < 4; ++i) { + if ((i * 2) != entry->entry.src_port) { + // Bitmask for output port(s), evens are + // phys odds cpu + action->action.forward_bitmask + |= (1 << (i * 2)); + DBG_VERBOSE + ("Output Port: %i Forward Bitmask: %x\n", + port, action->action.forward_bitmask); + } + } + } +} + +static void +populate_action_set_dl_src(nf2_of_action_wrap *action, uint8_t *flowact) +{ + struct ofp_action_dl_addr *actdl = (struct ofp_action_dl_addr *)flowact; + int i; + + for (i = 0; i < 6; ++i) { + action->action.eth_src[5 - i] = actdl->dl_addr[i]; + } + action->action.nf2_action_flag |= (1 << OFPAT_SET_DL_SRC); +} + +static void +populate_action_set_dl_dst(nf2_of_action_wrap *action, uint8_t *flowact) +{ + struct ofp_action_dl_addr *actdl = (struct ofp_action_dl_addr *)flowact; + int i; + + for (i = 0; i < 6; ++i) { + action->action.eth_dst[5 - i] = actdl->dl_addr[i]; + } + action->action.nf2_action_flag |= (1 << OFPAT_SET_DL_DST); +} + +static void +populate_action_set_nw_src(nf2_of_action_wrap *action, uint8_t *flowact) +{ + struct ofp_action_nw_addr *actnw = (struct ofp_action_nw_addr *)flowact; + action->action.ip_src = ntohl(actnw->nw_addr); + action->action.nf2_action_flag |= (1 << OFPAT_SET_NW_SRC); +} + +static void +populate_action_set_nw_dst(nf2_of_action_wrap *action, uint8_t *flowact) +{ + struct ofp_action_nw_addr *actnw = (struct ofp_action_nw_addr *)flowact; + action->action.ip_dst = ntohl(actnw->nw_addr); + action->action.nf2_action_flag |= (1 << OFPAT_SET_NW_DST); +} + +static void +populate_action_set_nw_tos(nf2_of_action_wrap *action, uint8_t *flowact) +{ + struct ofp_action_nw_tos *actnwtos = (struct ofp_action_nw_tos *)flowact; + action->action.ip_tos = actnwtos->nw_tos; + action->action.nf2_action_flag |= (1 << OFPAT_SET_NW_TOS); +} + +static void +populate_action_set_tp_src(nf2_of_action_wrap *action, uint8_t *flowact) +{ + struct ofp_action_tp_port *acttp = (struct ofp_action_tp_port *)flowact; + action->action.transp_src = ntohs(acttp->tp_port); + action->action.nf2_action_flag |= (1 << OFPAT_SET_TP_SRC); +} + +static void +populate_action_set_tp_dst(nf2_of_action_wrap *action, uint8_t *flowact) +{ + struct ofp_action_tp_port *acttp = (struct ofp_action_tp_port *)flowact; + action->action.transp_dst = ntohs(acttp->tp_port); + action->action.nf2_action_flag |= (1 << OFPAT_SET_TP_DST); +} + +static void +populate_action_set_vlan_vid(nf2_of_action_wrap *action, uint8_t *flowact) +{ + struct ofp_action_vlan_vid *actvlan = (struct ofp_action_vlan_vid *)flowact; + action->action.vlan_id = ntohs(actvlan->vlan_vid) & VID_BITMASK; + action->action.nf2_action_flag |= (1 << OFPAT_SET_VLAN_VID); +} + +static void +populate_action_set_vlan_pcp(nf2_of_action_wrap *action, uint8_t *flowact) +{ + struct ofp_action_vlan_pcp *actvlan = (struct ofp_action_vlan_pcp *)flowact; + action->action.vlan_pcp = actvlan->vlan_pcp; + action->action.nf2_action_flag |= (1 << OFPAT_SET_VLAN_PCP); +} + +static void +populate_action_strip_vlan(nf2_of_action_wrap *action) +{ + action->action.nf2_action_flag |= (1 << OFPAT_STRIP_VLAN); +} + +/* Populate an nf2_of_action_wrap. */ +void +nf2_populate_of_action(nf2_of_action_wrap *action, nf2_of_entry_wrap *entry, + struct sw_flow *flow) +{ + struct sw_flow_actions *sfa; + size_t actions_len; + uint8_t *p; + + sfa = flow->sf_acts; + actions_len = sfa->actions_len; + p = (uint8_t *)sfa->actions; + + // zero it out for now + memset(action, 0, sizeof(nf2_of_action_wrap)); + action->action.nf2_action_flag = 0; + + while (actions_len > 0) { + struct ofp_action_header *acth = (struct ofp_action_header *)p; + size_t len = ntohs(acth->len); + + DBG_VERBOSE("Action Populate: Len of this action: %i\n", len); + DBG_VERBOSE("Action Populate: Len of actions : %i\n", + actions_len); + + if (acth->type == htons(OFPAT_OUTPUT)) { + populate_action_output(action, entry, p); + } else if (acth->type == htons(OFPAT_SET_DL_SRC)) { + populate_action_set_dl_src(action, p); + } else if (acth->type == htons(OFPAT_SET_DL_DST)) { + populate_action_set_dl_dst(action, p); + } else if (acth->type == htons(OFPAT_SET_NW_SRC)) { + populate_action_set_nw_src(action, p); + } else if (acth->type == htons(OFPAT_SET_NW_DST)) { + populate_action_set_nw_dst(action, p); + } else if (acth->type == htons(OFPAT_SET_NW_TOS)) { + populate_action_set_nw_tos(action, p); + } else if (acth->type == htons(OFPAT_SET_TP_SRC)) { + populate_action_set_tp_src(action, p); + } else if (acth->type == htons(OFPAT_SET_TP_DST)) { + populate_action_set_tp_dst(action, p); + } else if (acth->type == htons(OFPAT_SET_VLAN_VID)) { + populate_action_set_vlan_vid(action, p); + } else if (acth->type == htons(OFPAT_SET_VLAN_PCP)) { + populate_action_set_vlan_pcp(action, p); + } else if (acth->type == htons(OFPAT_STRIP_VLAN)) { + populate_action_strip_vlan(action); + } + + p += len; + actions_len -= len; + } +} + +/* Add a free hardware entry back to the exact pool. */ +void +nf2_add_free_exact(struct nf2_flow *sfw) +{ + // clear the node entry + list_init(&sfw->node); + + // Critical section, adding to the actual list + exact_free_list[sfw->pos] = sfw; +} + +/* Add a free hardware entry back to the wildcard pool. */ +void +nf2_add_free_wildcard(struct nf2_flow *sfw) +{ + // clear the hw values + sfw->hw_packet_count = 0; + sfw->hw_byte_count = 0; + + // Critical section, adding to the actual list + list_insert(&wildcard_free_list, &sfw->node); +} + +/* Hashes the entry to find where it should exist in the exact table + * returns NULL on failure + */ +static struct nf2_flow * +get_free_exact(nf2_of_entry_wrap *entry) +{ + unsigned int poly1 = 0x04C11DB7; + unsigned int poly2 = 0x1EDC6F41; + struct nf2_flow *sfw = NULL; + unsigned int hash = 0x0; + unsigned int index = 0x0; + struct crc32 crc; + + crc32_init(&crc, poly1); + hash = crc32_calculate(&crc, entry, sizeof(nf2_of_entry_wrap)); + + // the bottom 15 bits of hash == the index into the table + index = 0x7FFF & hash; + + // if this index is free, grab it + sfw = exact_free_list[index]; + exact_free_list[index] = NULL; + + if (sfw != NULL) { + return sfw; + } + // try the second index + crc32_init(&crc, poly2); + hash = crc32_calculate(&crc, entry, sizeof(nf2_of_entry_wrap)); + // the bottom 15 bits of hash == the index into the table + index = 0x7FFF & hash; + + // if this index is free, grab it + sfw = exact_free_list[index]; + exact_free_list[index] = NULL; + + // return whether its good or not + return sfw; +} + +/* Get the first free position in the wildcard hardware table + * to write into. + */ +static struct nf2_flow * +get_free_wildcard(void) +{ + struct nf2_flow *sfw = NULL; + + // Critical section, pulling the first available from the list + if (list_is_empty(&wildcard_free_list)) { + // empty :( + sfw = NULL; + } else { + sfw = CONTAINER_OF(list_front(&wildcard_free_list), struct nf2_flow, node); + list_remove(&sfw->node); + list_init(&sfw->node); + } + + return sfw; +} + +/* Retrieves the type of table this flow should go into. */ +int +nf2_get_table_type(struct sw_flow *flow) +{ + if (flow->key.wildcards != 0) { + DBG_VERBOSE("--- TABLE TYPE: WILDCARD ---\n"); + return NF2_TABLE_WILDCARD; + } else { + DBG_VERBOSE("--- TABLE TYPE: EXACT ---\n"); + return NF2_TABLE_EXACT; + } +} + +/* Returns 1 if this flow contains an action outputting to all ports except + * input port, 0 otherwise. We support OFPP_ALL and OFPP_FLOOD actions, however + * since we do not perform the spanning tree protocol (STP) then OFPP_FLOOD is + * equivalent to OFPP_ALL. + */ +static int +is_action_forward_all(struct sw_flow *flow) +{ + struct sw_flow_actions *sfa; + size_t actions_len; + uint8_t *p; + + sfa = flow->sf_acts; + actions_len = sfa->actions_len; + p = (uint8_t *)sfa->actions; + + while (actions_len > 0) { + struct ofp_action_header *ah = (struct ofp_action_header *)p; + struct ofp_action_output *oa = (struct ofp_action_output *)p; + size_t len = ntohs(ah->len); + + DBG_VERBOSE("Fwd Action Chk: Action type: %x\n", + ntohs(ah->type)); + DBG_VERBOSE("Fwd Action Chk: Output port: %x\n", + ntohs(oa->port)); + DBG_VERBOSE("Fwd Action Chk: Len of this action: %i\n", len); + DBG_VERBOSE("Fwd Action Chk: Len of actions : %i\n", + actions_len); + // Currently only support the output port(s) action + if (ntohs(ah->type) == OFPAT_OUTPUT + && (ntohs(oa->port) == OFPP_ALL + || ntohs(oa->port) == OFPP_FLOOD)) { + return 1; + } + p += len; + actions_len -= len; + } + + return 0; +} + +/* Attempts to build and write the flow to hardware. + * Returns 0 on success, 1 on failure. + */ +int +nf2_build_and_write_flow(struct sw_flow *flow) +{ + struct nf2_flow *sfw = NULL; + struct nf2_flow *sfw_next = NULL; + struct nf2device *dev; + int num_entries = 0; + int i, table_type; + nf2_of_entry_wrap key; + nf2_of_mask_wrap mask; + nf2_of_action_wrap action; + + memset(&key, 0, sizeof(nf2_of_entry_wrap)); + memset(&mask, 0, sizeof(nf2_of_mask_wrap)); + memset(&action, 0, sizeof(nf2_of_action_wrap)); + + dev = nf2_get_net_device(); + if (dev == NULL) { + return 1; + } + + table_type = nf2_get_table_type(flow); + switch (table_type) { + default: + break; + + case NF2_TABLE_EXACT: + DBG_VERBOSE("---Exact Entry---\n"); + nf2_populate_of_entry(&key, flow); + nf2_populate_of_action(&action, &key, flow); + sfw = get_free_exact(&key); + if (sfw == NULL) { + DBG_VERBOSE + ("Collision getting free exact match entry\n"); + // collision + nf2_free_net_device(dev); + return 1; + } + // set the active bit on this entry + key.entry.pad = 0x80; + nf2_write_of_exact(dev, sfw->pos, &key, &action); + flow->private = (void *)sfw; + break; + + case NF2_TABLE_WILDCARD: + DBG_VERBOSE("---Wildcard Entry---\n"); + // if action is all out and source port is wildcarded + if ((is_action_forward_all(flow)) && + (flow->key.wildcards & OFPFW_IN_PORT)) { + DBG_VERBOSE("Grab four wildcard tables\n"); + if (!(sfw = get_free_wildcard())) { + DBG_VERBOSE("No free wildcard entries found."); + // no free entries + nf2_free_net_device(dev); + return 1; + } + // try to get 3 more positions + for (i = 0; i < 3; ++i) { + if (!(sfw_next = get_free_wildcard())) { + break; + } + list_insert(&sfw->node, &sfw_next->node); + ++num_entries; + } + + if (num_entries < 3) { + // failed to get enough entries, return them and exit + nf2_delete_private((void *)sfw); + nf2_free_net_device(dev); + return 1; + } + + nf2_populate_of_entry(&key, flow); + nf2_populate_of_mask(&mask, flow); + + // set first entry's src port to 0, remove wildcard mask on src + key.entry.src_port = 0; + mask.entry.src_port = 0; + nf2_populate_of_action(&action, &key, flow); + nf2_write_of_wildcard(dev, sfw->pos, &key, &mask, + &action); + + i = 1; + sfw_next = CONTAINER_OF(list_front(&sfw->node), + struct nf2_flow, node); + // walk through and write the remaining 3 entries + while (sfw_next != sfw) { + key.entry.src_port = i * 2; + nf2_populate_of_action(&action, &key, flow); + nf2_write_of_wildcard(dev, sfw_next->pos, &key, + &mask, &action); + sfw_next = CONTAINER_OF(list_front(&sfw_next->node), + struct nf2_flow, node); + ++i; + } + flow->private = (void *)sfw; + } else { + /* Get a free position here, and write to it */ + if ((sfw = get_free_wildcard())) { + nf2_populate_of_entry(&key, flow); + nf2_populate_of_mask(&mask, flow); + nf2_populate_of_action(&action, &key, flow); + if (nf2_write_of_wildcard + (dev, sfw->pos, &key, &mask, &action)) { + // failure writing to hardware + nf2_add_free_wildcard(sfw); + DBG_VERBOSE + ("Failure writing to hardware\n"); + nf2_free_net_device(dev); + return 1; + } else { + // success writing to hardware, store the position + flow->private = (void *)sfw; + } + } else { + // hardware is full, return 0 + DBG_VERBOSE("No free wildcard entries found."); + nf2_free_net_device(dev); + return 1; + } + } + break; + } + + nf2_free_net_device(dev); + return 0; +} + +void +nf2_delete_private(void *private) +{ + struct nf2_flow *sfw = (struct nf2_flow *)private; + struct nf2_flow *sfw_next; + struct list *next; + + switch (sfw->type) { + default: + break; + + case NF2_TABLE_EXACT: + nf2_clear_of_exact(sfw->pos); + nf2_add_free_exact(sfw); + break; + + case NF2_TABLE_WILDCARD: + while (!list_is_empty(&sfw->node)) { + next = sfw->node.next; + sfw_next = CONTAINER_OF(list_front(&sfw->node), struct nf2_flow, node); + list_remove(&sfw_next->node); + list_init(&sfw_next->node); + // Immediately zero out the entry in hardware + nf2_clear_of_wildcard(sfw_next->pos); + // add it back to the pool + nf2_add_free_wildcard(sfw_next); + } + // zero the core entry + nf2_clear_of_wildcard(sfw->pos); + // add back the core entry + nf2_add_free_wildcard(sfw); + break; + } +} + +int +nf2_modify_acts(struct sw_flow *flow) +{ + struct nf2_flow *sfw = (struct nf2_flow *)flow->private; + struct nf2device *dev; + nf2_of_entry_wrap key; + nf2_of_mask_wrap mask; + nf2_of_action_wrap action; + + memset(&key, 0, sizeof(nf2_of_entry_wrap)); + memset(&mask, 0, sizeof(nf2_of_mask_wrap)); + memset(&action, 0, sizeof(nf2_of_action_wrap)); + + dev = nf2_get_net_device(); + if (dev == NULL) + return 0; + + switch (sfw->type) { + default: + break; + + case NF2_TABLE_EXACT: + nf2_populate_of_entry(&key, flow); + nf2_populate_of_action(&action, &key, flow); + key.entry.pad = 0x80; + nf2_modify_write_of_exact(dev, sfw->pos, &action); + break; + + case NF2_TABLE_WILDCARD: + if (flow->key.wildcards & OFPFW_IN_PORT) { + nf2_free_net_device(dev); + return 0; + } + nf2_populate_of_entry(&key, flow); + nf2_populate_of_mask(&mask, flow); + nf2_populate_of_action(&action, &key, flow); + nf2_modify_write_of_wildcard(dev, sfw->pos, + &key, &mask, &action); + break; + } + + nf2_free_net_device(dev); + return 1; +} + +uint64_t +nf2_get_packet_count(struct nf2device *dev, struct nf2_flow *sfw) +{ + uint32_t count = 0; + uint32_t hw_count = 0; + uint64_t total = 0; + struct nf2_flow *sfw_next = NULL; + + switch (sfw->type) { + default: + break; + + case NF2_TABLE_EXACT: + // Get delta value + total = nf2_get_exact_packet_count(dev, sfw->pos); + break; + + case NF2_TABLE_WILDCARD: + sfw_next = sfw; + do { + // Get sum value + hw_count = nf2_get_wildcard_packet_count(dev, + sfw_next->pos); + if (hw_count >= sfw_next->hw_packet_count) { + count = hw_count - sfw_next->hw_packet_count; + sfw_next->hw_packet_count = hw_count; + } else { + // wrapping occurred + count = (MAX_INT_32 - sfw_next->hw_packet_count) + + hw_count; + sfw_next->hw_packet_count = hw_count; + } + total += count; + + if(!list_is_empty(&sfw_next->node)){ + sfw_next = CONTAINER_OF(list_front(&sfw_next->node), + struct nf2_flow, node); + } + } while (sfw_next != sfw); + break; + } + + return total; +} + +uint64_t +nf2_get_byte_count(struct nf2device *dev, struct nf2_flow *sfw) +{ + uint32_t count = 0; + uint32_t hw_count = 0; + uint64_t total = 0; + struct nf2_flow *sfw_next = NULL; + + switch (sfw->type) { + default: + break; + + case NF2_TABLE_EXACT: + // Get delta value + total = nf2_get_exact_byte_count(dev, sfw->pos); + break; + + case NF2_TABLE_WILDCARD: + sfw_next = sfw; + do { + // Get sum value + hw_count = nf2_get_wildcard_byte_count(dev, + sfw_next->pos); + if (hw_count >= sfw_next->hw_byte_count) { + count = hw_count - sfw_next->hw_byte_count; + sfw_next->hw_byte_count = hw_count; + } else { + // wrapping occurred + count = (MAX_INT_32 - sfw_next->hw_byte_count) + + hw_count; + sfw_next->hw_byte_count = hw_count; + } + + total += count; + + if(!list_is_empty(&sfw_next->node)) { + sfw_next = CONTAINER_OF(list_front(&sfw_next->node), + struct nf2_flow, node); + } + } while (sfw_next != sfw); + break; + } + + return total; +} diff --git a/openflow/hw-lib/nf2/nf2_lib.h b/openflow/hw-lib/nf2/nf2_lib.h new file mode 100644 index 00000000..cc75b2c6 --- /dev/null +++ b/openflow/hw-lib/nf2/nf2_lib.h @@ -0,0 +1,59 @@ +/*- + * Copyright (c) 2008, 2009, 2010 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#ifndef HWTABLE_NF2_NF2_LIB_H_ +#define HWTABLE_NF2_NF2_LIB_H_ + +struct nf2device *nf2_get_net_device(void); +void nf2_free_net_device(struct nf2device *); +int nf2_are_actions_supported(struct sw_flow *); +void nf2_clear_of_exact(uint32_t); +void nf2_clear_of_wildcard(uint32_t); +int nf2_init_exact_freelist(void); +int nf2_init_wildcard_freelist(void); +void nf2_destroy_exact_freelist(void); +void nf2_destroy_wildcard_freelist(void); +int nf2_write_static_wildcard(void); +void nf2_populate_of_entry(nf2_of_entry_wrap *, struct sw_flow *); +void nf2_populate_of_mask(nf2_of_mask_wrap *, struct sw_flow *); +void nf2_populate_of_action(nf2_of_action_wrap *, nf2_of_entry_wrap *, + struct sw_flow *); +void nf2_add_free_exact(struct nf2_flow *); +void nf2_add_free_wildcard(struct nf2_flow *); +int nf2_get_table_type(struct sw_flow *); +int nf2_build_and_write_flow(struct sw_flow *); +void nf2_delete_private(void *); +int nf2_modify_acts(struct sw_flow *); +uint64_t nf2_get_packet_count(struct nf2device *, struct nf2_flow *); +uint64_t nf2_get_byte_count(struct nf2device *, struct nf2_flow *); + +#endif diff --git a/openflow/hw-lib/nf2/nf2util.c b/openflow/hw-lib/nf2/nf2util.c new file mode 100644 index 00000000..fd3b500e --- /dev/null +++ b/openflow/hw-lib/nf2/nf2util.c @@ -0,0 +1,400 @@ +/* **************************************************************************** + * $Id: nf2util.c 3764 2008-05-22 06:48:34Z grg $ + * + * Module: nf2util.c + * Project: NetFPGA 2 Linux Kernel Driver + * Description: Utility functions for user mode programs + * + * Change history: + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include "nf2.h" +#include "nf2util.h" + +#include "reg_defines_openflow_switch.h" + +#define MD5_LEN 4 + +/* Function declarations */ +static int readRegNet(struct nf2device *nf2, unsigned reg, unsigned *val); +static int readRegFile(struct nf2device *nf2, unsigned reg, unsigned *val); +static int writeRegNet(struct nf2device *nf2, unsigned reg, unsigned val); +static int writeRegFile(struct nf2device *nf2, unsigned reg, unsigned val); + +/* Local variables */ +unsigned cpci_version = -1; +unsigned cpci_revision = -1; +unsigned nf2_device_id = -1; +unsigned nf2_revision = -1; +unsigned nf2_cpci_version = -1; +unsigned nf2_cpci_revision = -1; +char nf2_device_str[DEVICE_STR_LEN] = ""; + +/* + * readReg - read a register + */ +int readReg(struct nf2device *nf2, unsigned reg, unsigned *val) +{ + if (nf2->net_iface) + { + return readRegNet(nf2, reg, val); + } + else + { + return readRegFile(nf2, reg, val); + } +} + +/* + * readRegNet - read a register, using a network socket + */ +static int readRegNet(struct nf2device *nf2, unsigned reg, unsigned *val) +{ + struct ifreq ifreq; + struct nf2reg nf2reg; + int ret; + + nf2reg.reg = reg; + + /* Set up the ifreq structure */ + ifreq.ifr_data = (char *)&nf2reg; + strncpy(ifreq.ifr_ifrn.ifrn_name, nf2->device_name, IFNAMSIZ); + /*if (setsockopt(nf2->fd, SOL_SOCKET, SO_BINDTODEVICE, + (char *)&ifreq, sizeof(ifreq)) < 0) { + perror("sendpacket: setting SO_BINDTODEVICE"); + return -1; + } */ + + /* Call the ioctl */ + if ((ret = ioctl(nf2->fd, SIOCREGREAD, &ifreq)) == 0) + { + *val = nf2reg.val; + return 0; + } + else + { + perror("sendpacket: ioctl failed"); + return -1; + } +} + +/* + * readRegFile - read a register, using a file descriptor + */ +static int readRegFile(struct nf2device *nf2, unsigned reg, unsigned *val) +{ + struct nf2reg nf2reg; + int ret; + + nf2reg.reg = reg; + + /* Call the ioctl */ + if ((ret = ioctl(nf2->fd, SIOCREGREAD, &nf2reg)) == 0) + { + *val = nf2reg.val; + return 0; + } + else + { + perror("sendpacket: ioctl failed"); + return -1; + } +} + + +/* + * writeReg - write a register + */ +int writeReg(struct nf2device *nf2, unsigned reg, unsigned val) +{ + if (nf2->net_iface) + { + return writeRegNet(nf2, reg, val); + } + else + { + return writeRegFile(nf2, reg, val); + } +} + + +/* + * writeRegNet - write a register, using a network socket + */ +static int writeRegNet(struct nf2device *nf2, unsigned reg, unsigned val) +{ + struct ifreq ifreq; + struct nf2reg nf2reg; + int ret; + + nf2reg.reg = reg; + nf2reg.val = val; + + /* Set up the ifreq structure */ + ifreq.ifr_data = (char *)&nf2reg; + strncpy(ifreq.ifr_ifrn.ifrn_name, nf2->device_name, IFNAMSIZ); + /*if (setsockopt(nf2->fd, SOL_SOCKET, SO_BINDTODEVICE, + (char *)&ifreq, sizeof(ifreq)) < 0) { + perror("sendpacket: setting SO_BINDTODEVICE"); + return -1; + } */ + + /* Call the ioctl */ + if ((ret = ioctl(nf2->fd, SIOCREGWRITE, &ifreq)) == 0) + { + return 0; + } + else + { + perror("sendpacket: ioctl failed"); + return -1; + } +} + + +/* + * writeRegFile - write a register, using a file descriptor + */ +static int writeRegFile(struct nf2device *nf2, unsigned reg, unsigned val) +{ + struct nf2reg nf2reg; + int ret; + + nf2reg.reg = reg; + nf2reg.val = val; + + /* Call the ioctl */ + if ((ret = ioctl(nf2->fd, SIOCREGWRITE, &nf2reg)) == 0) + { + return 0; + } + else + { + perror("sendpacket: ioctl failed"); + return -1; + } +} + +/* + * Check the iface name to make sure we can find the interface + */ +int check_iface(struct nf2device *nf2) +{ + struct stat buf; + char filename[PATHLEN]; + + /* See if we can find the interface name as a network device */ + + /* Test the length first of all */ + if (strlen(nf2->device_name) > IFNAMSIZ) + { + fprintf(stderr, "Interface name is too long: %s\n", nf2->device_name); + return -1; + } + + /* Check for /sys/class/net/iface_name */ + strcpy(filename, "/sys/class/net/"); + strcat(filename, nf2->device_name); + if (stat(filename, &buf) == 0) + { + nf2->net_iface = 1; + return 0; + } + + /* Check for /dev/iface_name */ + strcpy(filename, "/dev/"); + strcat(filename, nf2->device_name); + if (stat(filename, &buf) == 0) + { + nf2->net_iface = 0; + return 0; + } + + fprintf(stderr, "Can't find device: %s\n", nf2->device_name); + return -1; +} + +/* + * Open the descriptor associated with the device name + */ +int openDescriptor(struct nf2device *nf2) +{ + struct ifreq ifreq; + char filename[PATHLEN]; + struct sockaddr_in address; + int i; + struct sockaddr_in *sin = (struct sockaddr_in *) &ifreq.ifr_addr; + int found = 0; + + if (nf2->net_iface) + { + /* Open a network socket */ + nf2->fd = socket(AF_INET, SOCK_DGRAM, 0); + if (nf2->fd == -1) + { + perror("socket: creating socket"); + return -1; + } + else + { + /* Root can bind to a network interface. + Non-root has to bind to a network address. */ + if (geteuid() == 0) + { + strncpy(ifreq.ifr_ifrn.ifrn_name, nf2->device_name, IFNAMSIZ); + if (setsockopt(nf2->fd, SOL_SOCKET, SO_BINDTODEVICE, + (char *)&ifreq, sizeof(ifreq)) < 0) { + perror("setsockopt: setting SO_BINDTODEVICE"); + return -1; + } + + } + else + { + /* Attempt to find the IP address for the interface */ + for (i = 1; ; i++) + { + /* Find interface number i*/ + ifreq.ifr_ifindex = i; + if (ioctl (nf2->fd, SIOCGIFNAME, &ifreq) < 0) + break; + + /* Check if we've found the correct interface */ + if (strcmp(ifreq.ifr_name, nf2->device_name) != 0) + continue; + + /* If we get to here we've found the IP */ + found = 1; + break; + } + + /* Verify that we found the interface */ + if (!found) + { + fprintf(stderr, "Can't find device: %s\n", nf2->device_name); + return -1; + } + + /* Attempt to get the IP address associated with the interface */ + if (ioctl (nf2->fd, SIOCGIFADDR, &ifreq) < 0) + { + perror("ioctl: calling SIOCGIFADDR"); + + fprintf(stderr, "Unable to find IP address for device: %s\n", nf2->device_name); + fprintf(stderr, "Either run this program as root or ask an administrator\n"); + fprintf(stderr, "to assign an IP address to the device\n"); + return -1; + } + + /* Set the addres and attempt to bind to the socket */ + address.sin_family = AF_INET; + address.sin_addr.s_addr = sin->sin_addr.s_addr; + address.sin_port = htons(0); + if (bind(nf2->fd,(struct sockaddr *)&address,sizeof(address)) == -1) { + perror("bind: binding"); + return -1; + } + } + } + } + else + { + strcpy(filename, "/dev/"); + strcat(filename, nf2->device_name); + nf2->fd = fileno(fopen(filename, "w+")); + if (nf2->fd == -1) + { + perror("fileno: creating descriptor"); + return -1; + } + } + + return 0; +} + +/* + * Close the descriptor associated with the device name + */ +int closeDescriptor(struct nf2device *nf2) +{ + if (nf2->net_iface) + { + close(nf2->fd); + } + else + { + close(nf2->fd); + } + + return 0; +} + +/* + * Read the version info from the Virtex and CPCI + */ +void nf2_read_info(struct nf2device *nf2) +{ + int i; + int md5_good = 1; + unsigned md5[MD5_LEN]; + unsigned cpci_id; + unsigned nf2_cpci_id; + + // Read the CPCI version/revision + readReg(nf2, CPCI_REG_ID, &cpci_id); + cpci_version = cpci_id & 0xffffff; + cpci_revision = cpci_id >> 24; + + // Verify the MD5 checksum of the device ID block + for (i = 0; i < MD5_LEN; i++) { + readReg(nf2, DEV_ID_MD5_0_REG + i * 4, &md5[i]); + } + md5_good &= md5[0] == DEV_ID_MD5_VALUE_0; + md5_good &= md5[1] == DEV_ID_MD5_VALUE_1; + md5_good &= md5[2] == DEV_ID_MD5_VALUE_2; + md5_good &= md5[3] == DEV_ID_MD5_VALUE_3; + + // Process only if the MD5 sum is good + if (md5_good) { + // Read the version and revision + readReg(nf2, DEV_ID_DEVICE_ID_REG, &nf2_device_id); + readReg(nf2, DEV_ID_REVISION_REG, &nf2_revision); + readReg(nf2, DEV_ID_CPCI_ID_REG, &nf2_cpci_id); + nf2_cpci_version = nf2_cpci_id & 0xffffff; + nf2_cpci_revision = nf2_cpci_id >> 24; + + // Read the version string + for (i = 0; i < (DEVICE_STR_LEN / 4) - 2; i++) + { + readReg(nf2, DEV_ID_DEV_STR_0_REG + i * 4, (unsigned *)(nf2_device_str + i * 4)); + + // Perform byte swapping if necessary + *(unsigned *)(nf2_device_str + i * 4) = ntohl(*(unsigned *)(nf2_device_str + i * 4)); + } + nf2_device_str[DEVICE_STR_LEN - 1] = '\0'; + } +} + +/* + * Print out a test string + */ +void printHello (struct nf2device *nf2, int *val) +{ + printf ("Hello world. Name=%s val=%d\n", nf2->device_name, *val); + *val = 10; +} diff --git a/openflow/hw-lib/nf2/nf2util.h b/openflow/hw-lib/nf2/nf2util.h new file mode 100644 index 00000000..88d3c159 --- /dev/null +++ b/openflow/hw-lib/nf2/nf2util.h @@ -0,0 +1,46 @@ +/* **************************************************************************** + * $Id: nf2util.h 3764 2008-05-22 06:48:34Z grg $ + * + * Module: nf2util.h + * Project: NetFPGA 2 Linux Kernel Driver + * Description: Header file for kernel driver + * + * Change history: + * + */ + +#ifndef _NF2UTIL_H +#define _NF2UTIL_H 1 + +#define PATHLEN 80 +#define DEVICE_STR_LEN 100 + + +/* + * Structure to represent an nf2 device to a user mode programs + */ +struct nf2device { + char *device_name; + int fd; + int net_iface; +}; + +/* Function declarations */ + +int readReg(struct nf2device *nf2, unsigned reg, unsigned *val); +int writeReg(struct nf2device *nf2, unsigned reg, unsigned val); +int check_iface(struct nf2device *nf2); +int openDescriptor(struct nf2device *nf2); +int closeDescriptor(struct nf2device *nf2); +void nf2_read_info(struct nf2device *nf2); +void printHello (struct nf2device *nf2, int *val); + +extern unsigned cpci_version; +extern unsigned cpci_revision; +extern unsigned nf2_device_id; +extern unsigned nf2_revision; +extern unsigned nf2_cpci_version; +extern unsigned nf2_cpci_revision; +extern char nf2_device_str[DEVICE_STR_LEN]; + +#endif diff --git a/openflow/hw-lib/nf2/reg_defines_openflow_switch.h b/openflow/hw-lib/nf2/reg_defines_openflow_switch.h new file mode 100644 index 00000000..0056f882 --- /dev/null +++ b/openflow/hw-lib/nf2/reg_defines_openflow_switch.h @@ -0,0 +1,767 @@ +/******************************************************** +* +* C register defines file for openflow_switch +* +********************************************************/ + +#ifndef _REG_DEFINES_ +#define _REG_DEFINES_ + +/* ========= Constants ========= */ + +// ===== File: lib/verilog/core/common/xml/global.xml ===== + +// Maximum number of phy ports +#define MAX_PHY_PORTS 4 + +// PCI address bus width +#define PCI_ADDR_WIDTH 32 + +// PCI data bus width +#define PCI_DATA_WIDTH 32 + +// PCI byte enable bus width +#define PCI_BE_WIDTH 4 + +// CPCI--CNET address bus width. This is byte addresses even though bottom bits are zero. +#define CPCI_CNET_ADDR_WIDTH 27 + +// CPCI--CNET data bus width +#define CPCI_CNET_DATA_WIDTH 32 + +// CPCI--NF2 address bus width. This is byte addresses even though bottom bits are zero. +#define CPCI_NF2_ADDR_WIDTH 27 + +// CPCI--NF2 data bus width +#define CPCI_NF2_DATA_WIDTH 32 + +// DMA data bus width +#define DMA_DATA_WIDTH 32 + +// DMA control bus width +#define DMA_CTRL_WIDTH 4 + +// CPCI debug bus width +#define CPCI_DEBUG_DATA_WIDTH 29 + +// SRAM address width +#define SRAM_ADDR_WIDTH 19 + +// SRAM data width +#define SRAM_DATA_WIDTH 36 + +// DRAM address width +#define DRAM_ADDR_WIDTH 24 + +// ===== File: lib/verilog/core/common/xml/nf_defines.xml ===== + +// Clock period of 125 MHz clock in ns +#define FAST_CLK_PERIOD 8 + +// Clock period of 62.5 MHz clock in ns +#define SLOW_CLK_PERIOD 16 + +// Header value used by the IO queues +#define IO_QUEUE_STAGE_NUM 0xff + +// Data path data width +#define DATA_WIDTH 64 + +// Data path control width +#define CTRL_WIDTH 8 + +// ===== File: projects/openflow_switch/include/output_port_lookup.xml ===== + +#define FAST_CLOCK_PERIOD 8 + +// ===== File: projects/openflow_switch/include/vlan_remover.xml ===== + +#define VLAN_CTRL_WORD 0x42 + +#define VLAN_ETHERTYPE 0x8100 + +// ===== File: lib/verilog/core/output_queues/bram_output_queues/xml/bram_output_queues.xml ===== + +#define NUM_OUTPUT_QUEUES 8 + +// ===== File: projects/openflow_switch/include/opl_processor.xml ===== + +#define NF2_OFPAT_OUTPUT 0x0001 + +#define NF2_OFPAT_SET_VLAN_VID 0x0002 + +#define NF2_OFPAT_SET_VLAN_PCP 0x0004 + +#define NF2_OFPAT_STRIP_VLAN 0x0008 + +#define NF2_OFPAT_SET_DL_SRC 0x0010 + +#define NF2_OFPAT_SET_DL_DST 0x0020 + +#define NF2_OFPAT_SET_NW_SRC 0x0040 + +#define NF2_OFPAT_SET_NW_DST 0x0080 + +#define NF2_OFPAT_SET_TP_SRC 0x0100 + +#define NF2_OFPAT_SET_TP_DST 0x0200 + +// ===== File: projects/openflow_switch/include/wildcard_match.xml ===== + +#define OPENFLOW_WILDCARD_TABLE_SIZE 32 + +#define OPENFLOW_WILDCARD_NUM_DATA_WORDS_USED 10 + +#define OPENFLOW_WILDCARD_NUM_CMP_WORDS_USED 8 + +// ===== File: lib/verilog/core/utils/xml/device_id_reg.xml ===== + +// Total number of registers +#define DEV_ID_NUM_REGS 32 + +// Number of non string registers +#define DEV_ID_NON_DEV_STR_REGS 7 + +// Device description length (in words, not chars) +#define DEV_ID_DEV_STR_WORD_LEN 25 + +// Device description length (in bytes/chars) +#define DEV_ID_DEV_STR_BYTE_LEN 100 + +// Device description length (in bits) +#define DEV_ID_DEV_STR_BIT_LEN 800 + +// Length of MD5 sum (bits) +#define DEV_ID_MD5SUM_LENGTH 128 + +// MD5 sum of the string "device_id.v" +#define DEV_ID_MD5_VALUE 0x4071736d8a603d2b4d55f62989a73c95 +#define DEV_ID_MD5_VALUE_0 0x4071736d +#define DEV_ID_MD5_VALUE_1 0x8a603d2b +#define DEV_ID_MD5_VALUE_2 0x4d55f629 +#define DEV_ID_MD5_VALUE_3 0x89a73c95 + +// ===== File: projects/openflow_switch/include/header_parser.xml ===== + +#define ETH_TYPE_IP 0x0800 + +#define IP_PROTO_TCP 0x06 + +#define IP_PROTO_UDP 0x11 + +#define IP_PROTO_ICMP 0x01 + +// ===== File: projects/openflow_switch/include/watchdog.xml ===== + +#define WDT_CPCI_REG_CTRL 0x00000008 + +// ===== File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml ===== + +// TX queue disable bit +#define MAC_GRP_TX_QUEUE_DISABLE_BIT_NUM 0 + +// RX queue disable bit +#define MAC_GRP_RX_QUEUE_DISABLE_BIT_NUM 1 + +// Reset MAC bit +#define MAC_GRP_RESET_MAC_BIT_NUM 2 + +// MAC TX queue disable bit +#define MAC_GRP_MAC_DISABLE_TX_BIT_NUM 3 + +// MAC RX queue disable bit +#define MAC_GRP_MAC_DISABLE_RX_BIT_NUM 4 + +// MAC disable jumbo TX bit +#define MAC_GRP_MAC_DIS_JUMBO_TX_BIT_NUM 5 + +// MAC disable jumbo RX bit +#define MAC_GRP_MAC_DIS_JUMBO_RX_BIT_NUM 6 + +// MAC disable crc check disable bit +#define MAC_GRP_MAC_DIS_CRC_CHECK_BIT_NUM 7 + +// MAC disable crc generate bit +#define MAC_GRP_MAC_DIS_CRC_GEN_BIT_NUM 8 + +// ===== File: projects/openflow_switch/include/match_arbiter.xml ===== + +#define OPENFLOW_ENTRY_TRANSP_DST_WIDTH 16 + +#define OPENFLOW_ENTRY_TRANSP_DST_POS 0 + +#define OPENFLOW_ENTRY_TRANSP_SRC_WIDTH 16 + +#define OPENFLOW_ENTRY_TRANSP_SRC_POS 16 + +#define OPENFLOW_ENTRY_IP_PROTO_WIDTH 8 + +#define OPENFLOW_ENTRY_IP_PROTO_POS 32 + +#define OPENFLOW_ENTRY_IP_DST_WIDTH 32 + +#define OPENFLOW_ENTRY_IP_DST_POS 40 + +#define OPENFLOW_ENTRY_IP_SRC_WIDTH 32 + +#define OPENFLOW_ENTRY_IP_SRC_POS 72 + +#define OPENFLOW_ENTRY_ETH_TYPE_WIDTH 16 + +#define OPENFLOW_ENTRY_ETH_TYPE_POS 104 + +#define OPENFLOW_ENTRY_ETH_DST_WIDTH 48 + +#define OPENFLOW_ENTRY_ETH_DST_POS 120 + +#define OPENFLOW_ENTRY_ETH_SRC_WIDTH 48 + +#define OPENFLOW_ENTRY_ETH_SRC_POS 168 + +#define OPENFLOW_ENTRY_SRC_PORT_WIDTH 8 + +#define OPENFLOW_ENTRY_SRC_PORT_POS 216 + +#define OPENFLOW_ENTRY_VLAN_ID_WIDTH 16 + +#define OPENFLOW_ENTRY_VLAN_ID_POS 224 + +#define OPENFLOW_ENTRY_WIDTH 240 + +// The actionfield is composed of a bitmask specifying actions to take and arguments. +#define OPENFLOW_ACTION_WIDTH 320 + +// Ports to forward on +#define OPENFLOW_FORWARD_BITMASK_WIDTH 16 + +#define OPENFLOW_FORWARD_BITMASK_POS 0 + +#define OPENFLOW_NF2_ACTION_FLAG_WIDTH 16 + +#define OPENFLOW_NF2_ACTION_FLAG_POS 16 + +// Vlan ID to be replaced +#define OPENFLOW_SET_VLAN_VID_WIDTH 16 + +#define OPENFLOW_SET_VLAN_VID_POS 32 + +// Vlan priority to be replaced +#define OPENFLOW_SET_VLAN_PCP_WIDTH 8 + +#define OPENFLOW_SET_VLAN_PCP_POS 48 + +// Source MAC address to be replaced +#define OPENFLOW_SET_DL_SRC_WIDTH 48 + +#define OPENFLOW_SET_DL_SRC_POS 56 + +// Destination MAC address to be replaced +#define OPENFLOW_SET_DL_DST_WIDTH 48 + +#define OPENFLOW_SET_DL_DST_POS 104 + +// Source network address to be replaced +#define OPENFLOW_SET_NW_SRC_WIDTH 32 + +#define OPENFLOW_SET_NW_SRC_POS 152 + +// Destination network address to be replaced +#define OPENFLOW_SET_NW_DST_WIDTH 32 + +#define OPENFLOW_SET_NW_DST_POS 184 + +// Source transport port to be replaced +#define OPENFLOW_SET_TP_SRC_WIDTH 16 + +#define OPENFLOW_SET_TP_SRC_POS 216 + +// Destination transport port to be replaced +#define OPENFLOW_SET_TP_DST_WIDTH 16 + +#define OPENFLOW_SET_TP_DST_POS 232 + +// ===== File: projects/openflow_switch/include/exact_match.xml ===== + +#define OPENFLOW_EXACT_ENTRY_PKT_COUNTER_WIDTH 25 + +#define OPENFLOW_EXACT_ENTRY_PKT_COUNTER_POS 0 + +#define OPENFLOW_EXACT_ENTRY_LAST_SEEN_WIDTH 7 + +#define OPENFLOW_EXACT_ENTRY_LAST_SEEN_POS 25 + +#define OPENFLOW_EXACT_ENTRY_BYTE_COUNTER_WIDTH 32 + +#define OPENFLOW_EXACT_ENTRY_BYTE_COUNTER_POS 32 + +#define OPENFLOW_EXACT_ENTRY_HDR_BASE_POS 0x00000000 + +#define OPENFLOW_EXACT_ENTRY_COUNTERS_POS 0x00000008 + +#define OPENFLOW_EXACT_ENTRY_ACTION_BASE_POS 0x0000000a + +// ------------------------------------- +// Modules +// ------------------------------------- + +// Module tags +#define CORE_BASE_ADDR 0x0000000 +#define DEV_ID_BASE_ADDR 0x0400000 +#define MDIO_BASE_ADDR 0x0440000 +#define DMA_BASE_ADDR 0x0500000 +#define MAC_GRP_0_BASE_ADDR 0x0600000 +#define MAC_GRP_1_BASE_ADDR 0x0640000 +#define MAC_GRP_2_BASE_ADDR 0x0680000 +#define MAC_GRP_3_BASE_ADDR 0x06c0000 +#define CPU_QUEUE_0_BASE_ADDR 0x0700000 +#define CPU_QUEUE_1_BASE_ADDR 0x0740000 +#define CPU_QUEUE_2_BASE_ADDR 0x0780000 +#define CPU_QUEUE_3_BASE_ADDR 0x07c0000 +#define SRAM_BASE_ADDR 0x1000000 +#define UDP_BASE_ADDR 0x2000000 +#define OPENFLOW_LOOKUP_BASE_ADDR 0x2000000 +#define IN_ARB_BASE_ADDR 0x2000100 +#define VLAN_REMOVER_BASE_ADDR 0x2000200 +#define OPL_PROCESSOR_BASE_ADDR 0x2000240 +#define HEADER_PARSER_BASE_ADDR 0x2000280 +#define MATCH_ARBITER_BASE_ADDR 0x20002c0 +#define BRAM_OQ_BASE_ADDR 0x2000300 +#define WDT_BASE_ADDR 0x2000400 +#define EXACT_MATCH_BASE_ADDR 0x2000500 +#define OPENFLOW_WILDCARD_LOOKUP_BASE_ADDR 0x2001000 +#define DRAM_BASE_ADDR 0x4000000 + +#define CPU_QUEUE_OFFSET 0x0040000 +#define MAC_GRP_OFFSET 0x0040000 + +/* ========== Registers ========== */ + +// Name: device_id (DEV_ID) +// Description: Device identification +// File: lib/verilog/core/utils/xml/device_id_reg.xml +#define DEV_ID_MD5_0_REG 0x0400000 +#define DEV_ID_MD5_1_REG 0x0400004 +#define DEV_ID_MD5_2_REG 0x0400008 +#define DEV_ID_MD5_3_REG 0x040000c +#define DEV_ID_DEVICE_ID_REG 0x0400010 +#define DEV_ID_REVISION_REG 0x0400014 +#define DEV_ID_CPCI_ID_REG 0x0400018 +#define DEV_ID_DEV_STR_0_REG 0x040001c +#define DEV_ID_DEV_STR_1_REG 0x0400020 +#define DEV_ID_DEV_STR_2_REG 0x0400024 +#define DEV_ID_DEV_STR_3_REG 0x0400028 +#define DEV_ID_DEV_STR_4_REG 0x040002c +#define DEV_ID_DEV_STR_5_REG 0x0400030 +#define DEV_ID_DEV_STR_6_REG 0x0400034 +#define DEV_ID_DEV_STR_7_REG 0x0400038 +#define DEV_ID_DEV_STR_8_REG 0x040003c +#define DEV_ID_DEV_STR_9_REG 0x0400040 +#define DEV_ID_DEV_STR_10_REG 0x0400044 +#define DEV_ID_DEV_STR_11_REG 0x0400048 +#define DEV_ID_DEV_STR_12_REG 0x040004c +#define DEV_ID_DEV_STR_13_REG 0x0400050 +#define DEV_ID_DEV_STR_14_REG 0x0400054 +#define DEV_ID_DEV_STR_15_REG 0x0400058 +#define DEV_ID_DEV_STR_16_REG 0x040005c +#define DEV_ID_DEV_STR_17_REG 0x0400060 +#define DEV_ID_DEV_STR_18_REG 0x0400064 +#define DEV_ID_DEV_STR_19_REG 0x0400068 +#define DEV_ID_DEV_STR_20_REG 0x040006c +#define DEV_ID_DEV_STR_21_REG 0x0400070 +#define DEV_ID_DEV_STR_22_REG 0x0400074 +#define DEV_ID_DEV_STR_23_REG 0x0400078 +#define DEV_ID_DEV_STR_24_REG 0x040007c + +// Name: mdio (MDIO) +// Description: MDIO interface +// File: lib/verilog/core/io/mdio/xml/mdio.xml +#define MDIO_PHY_0_CONTROL_REG 0x0440000 +#define MDIO_PHY_0_STATUS_REG 0x0440004 +#define MDIO_PHY_0_PHY_ID_0_REG 0x0440008 +#define MDIO_PHY_0_PHY_ID_1_REG 0x044000c +#define MDIO_PHY_0_AUTONEGOTIATION_ADVERT_REG 0x0440010 +#define MDIO_PHY_0_AUTONEG_LINK_PARTNER_BASE_PAGE_ABILITY_REG 0x0440014 +#define MDIO_PHY_0_AUTONEG_EXPANSION_REG 0x0440018 +#define MDIO_PHY_0_AUTONEG_NEXT_PAGE_TX_REG 0x044001c +#define MDIO_PHY_0_AUTONEG_LINK_PARTNER_RCVD_NEXT_PAGE_REG 0x0440020 +#define MDIO_PHY_0_MASTER_SLAVE_CTRL_REG 0x0440024 +#define MDIO_PHY_0_MASTER_SLAVE_STATUS_REG 0x0440028 +#define MDIO_PHY_0_PSE_CTRL_REG 0x044002c +#define MDIO_PHY_0_PSE_STATUS_REG 0x0440030 +#define MDIO_PHY_0_MMD_ACCESS_CTRL_REG 0x0440034 +#define MDIO_PHY_0_MMD_ACCESS_STATUS_REG 0x0440038 +#define MDIO_PHY_0_EXTENDED_STATUS_REG 0x044003c +#define MDIO_PHY_1_CONTROL_REG 0x0440080 +#define MDIO_PHY_1_STATUS_REG 0x0440084 +#define MDIO_PHY_1_PHY_ID_0_REG 0x0440088 +#define MDIO_PHY_1_PHY_ID_1_REG 0x044008c +#define MDIO_PHY_1_AUTONEGOTIATION_ADVERT_REG 0x0440090 +#define MDIO_PHY_1_AUTONEG_LINK_PARTNER_BASE_PAGE_ABILITY_REG 0x0440094 +#define MDIO_PHY_1_AUTONEG_EXPANSION_REG 0x0440098 +#define MDIO_PHY_1_AUTONEG_NEXT_PAGE_TX_REG 0x044009c +#define MDIO_PHY_1_AUTONEG_LINK_PARTNER_RCVD_NEXT_PAGE_REG 0x04400a0 +#define MDIO_PHY_1_MASTER_SLAVE_CTRL_REG 0x04400a4 +#define MDIO_PHY_1_MASTER_SLAVE_STATUS_REG 0x04400a8 +#define MDIO_PHY_1_PSE_CTRL_REG 0x04400ac +#define MDIO_PHY_1_PSE_STATUS_REG 0x04400b0 +#define MDIO_PHY_1_MMD_ACCESS_CTRL_REG 0x04400b4 +#define MDIO_PHY_1_MMD_ACCESS_STATUS_REG 0x04400b8 +#define MDIO_PHY_1_EXTENDED_STATUS_REG 0x04400bc +#define MDIO_PHY_2_CONTROL_REG 0x0440100 +#define MDIO_PHY_2_STATUS_REG 0x0440104 +#define MDIO_PHY_2_PHY_ID_0_REG 0x0440108 +#define MDIO_PHY_2_PHY_ID_1_REG 0x044010c +#define MDIO_PHY_2_AUTONEGOTIATION_ADVERT_REG 0x0440110 +#define MDIO_PHY_2_AUTONEG_LINK_PARTNER_BASE_PAGE_ABILITY_REG 0x0440114 +#define MDIO_PHY_2_AUTONEG_EXPANSION_REG 0x0440118 +#define MDIO_PHY_2_AUTONEG_NEXT_PAGE_TX_REG 0x044011c +#define MDIO_PHY_2_AUTONEG_LINK_PARTNER_RCVD_NEXT_PAGE_REG 0x0440120 +#define MDIO_PHY_2_MASTER_SLAVE_CTRL_REG 0x0440124 +#define MDIO_PHY_2_MASTER_SLAVE_STATUS_REG 0x0440128 +#define MDIO_PHY_2_PSE_CTRL_REG 0x044012c +#define MDIO_PHY_2_PSE_STATUS_REG 0x0440130 +#define MDIO_PHY_2_MMD_ACCESS_CTRL_REG 0x0440134 +#define MDIO_PHY_2_MMD_ACCESS_STATUS_REG 0x0440138 +#define MDIO_PHY_2_EXTENDED_STATUS_REG 0x044013c +#define MDIO_PHY_3_CONTROL_REG 0x0440180 +#define MDIO_PHY_3_STATUS_REG 0x0440184 +#define MDIO_PHY_3_PHY_ID_0_REG 0x0440188 +#define MDIO_PHY_3_PHY_ID_1_REG 0x044018c +#define MDIO_PHY_3_AUTONEGOTIATION_ADVERT_REG 0x0440190 +#define MDIO_PHY_3_AUTONEG_LINK_PARTNER_BASE_PAGE_ABILITY_REG 0x0440194 +#define MDIO_PHY_3_AUTONEG_EXPANSION_REG 0x0440198 +#define MDIO_PHY_3_AUTONEG_NEXT_PAGE_TX_REG 0x044019c +#define MDIO_PHY_3_AUTONEG_LINK_PARTNER_RCVD_NEXT_PAGE_REG 0x04401a0 +#define MDIO_PHY_3_MASTER_SLAVE_CTRL_REG 0x04401a4 +#define MDIO_PHY_3_MASTER_SLAVE_STATUS_REG 0x04401a8 +#define MDIO_PHY_3_PSE_CTRL_REG 0x04401ac +#define MDIO_PHY_3_PSE_STATUS_REG 0x04401b0 +#define MDIO_PHY_3_MMD_ACCESS_CTRL_REG 0x04401b4 +#define MDIO_PHY_3_MMD_ACCESS_STATUS_REG 0x04401b8 +#define MDIO_PHY_3_EXTENDED_STATUS_REG 0x04401bc + +#define MDIO_PHY_GROUP_BASE_ADDR 0x0440000 +#define MDIO_PHY_GROUP_INST_OFFSET 0x0000080 + +// Name: dma (DMA) +// Description: DMA transfer module +// File: lib/verilog/core/dma/xml/dma.xml + +// Name: nf2_mac_grp (MAC_GRP_0) +// Description: Ethernet MAC group +// File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml +#define MAC_GRP_0_CONTROL_REG 0x0600000 +#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0600004 +#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_STORED_REG 0x0600008 +#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG 0x060000c +#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG 0x0600010 +#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_DEQUEUED_REG 0x0600014 +#define MAC_GRP_0_RX_QUEUE_NUM_WORDS_PUSHED_REG 0x0600018 +#define MAC_GRP_0_RX_QUEUE_NUM_BYTES_PUSHED_REG 0x060001c +#define MAC_GRP_0_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0600020 +#define MAC_GRP_0_TX_QUEUE_NUM_PKTS_ENQUEUED_REG 0x0600024 +#define MAC_GRP_0_TX_QUEUE_NUM_PKTS_SENT_REG 0x0600028 +#define MAC_GRP_0_TX_QUEUE_NUM_WORDS_PUSHED_REG 0x060002c +#define MAC_GRP_0_TX_QUEUE_NUM_BYTES_PUSHED_REG 0x0600030 + +// Name: nf2_mac_grp (MAC_GRP_1) +// Description: Ethernet MAC group +// File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml +#define MAC_GRP_1_CONTROL_REG 0x0640000 +#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0640004 +#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_STORED_REG 0x0640008 +#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG 0x064000c +#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG 0x0640010 +#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_DEQUEUED_REG 0x0640014 +#define MAC_GRP_1_RX_QUEUE_NUM_WORDS_PUSHED_REG 0x0640018 +#define MAC_GRP_1_RX_QUEUE_NUM_BYTES_PUSHED_REG 0x064001c +#define MAC_GRP_1_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0640020 +#define MAC_GRP_1_TX_QUEUE_NUM_PKTS_ENQUEUED_REG 0x0640024 +#define MAC_GRP_1_TX_QUEUE_NUM_PKTS_SENT_REG 0x0640028 +#define MAC_GRP_1_TX_QUEUE_NUM_WORDS_PUSHED_REG 0x064002c +#define MAC_GRP_1_TX_QUEUE_NUM_BYTES_PUSHED_REG 0x0640030 + +// Name: nf2_mac_grp (MAC_GRP_2) +// Description: Ethernet MAC group +// File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml +#define MAC_GRP_2_CONTROL_REG 0x0680000 +#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0680004 +#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_STORED_REG 0x0680008 +#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG 0x068000c +#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG 0x0680010 +#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_DEQUEUED_REG 0x0680014 +#define MAC_GRP_2_RX_QUEUE_NUM_WORDS_PUSHED_REG 0x0680018 +#define MAC_GRP_2_RX_QUEUE_NUM_BYTES_PUSHED_REG 0x068001c +#define MAC_GRP_2_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0680020 +#define MAC_GRP_2_TX_QUEUE_NUM_PKTS_ENQUEUED_REG 0x0680024 +#define MAC_GRP_2_TX_QUEUE_NUM_PKTS_SENT_REG 0x0680028 +#define MAC_GRP_2_TX_QUEUE_NUM_WORDS_PUSHED_REG 0x068002c +#define MAC_GRP_2_TX_QUEUE_NUM_BYTES_PUSHED_REG 0x0680030 + +// Name: nf2_mac_grp (MAC_GRP_3) +// Description: Ethernet MAC group +// File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml +#define MAC_GRP_3_CONTROL_REG 0x06c0000 +#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x06c0004 +#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_STORED_REG 0x06c0008 +#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG 0x06c000c +#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG 0x06c0010 +#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_DEQUEUED_REG 0x06c0014 +#define MAC_GRP_3_RX_QUEUE_NUM_WORDS_PUSHED_REG 0x06c0018 +#define MAC_GRP_3_RX_QUEUE_NUM_BYTES_PUSHED_REG 0x06c001c +#define MAC_GRP_3_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x06c0020 +#define MAC_GRP_3_TX_QUEUE_NUM_PKTS_ENQUEUED_REG 0x06c0024 +#define MAC_GRP_3_TX_QUEUE_NUM_PKTS_SENT_REG 0x06c0028 +#define MAC_GRP_3_TX_QUEUE_NUM_WORDS_PUSHED_REG 0x06c002c +#define MAC_GRP_3_TX_QUEUE_NUM_BYTES_PUSHED_REG 0x06c0030 + +// Name: cpu_dma_queue (CPU_QUEUE_0) +// Description: CPU DMA queue +// File: lib/verilog/core/io_queues/cpu_dma_queue/xml/cpu_dma_queue.xml + +// Name: cpu_dma_queue (CPU_QUEUE_1) +// Description: CPU DMA queue +// File: lib/verilog/core/io_queues/cpu_dma_queue/xml/cpu_dma_queue.xml + +// Name: cpu_dma_queue (CPU_QUEUE_2) +// Description: CPU DMA queue +// File: lib/verilog/core/io_queues/cpu_dma_queue/xml/cpu_dma_queue.xml + +// Name: cpu_dma_queue (CPU_QUEUE_3) +// Description: CPU DMA queue +// File: lib/verilog/core/io_queues/cpu_dma_queue/xml/cpu_dma_queue.xml + +// Name: SRAM (SRAM) +// Description: SRAM + +// Name: openflow_output_port_lookup (OPENFLOW_LOOKUP) +// Description: Output Port Lookup for OpenFlow hardware datapath +// File: projects/openflow_switch/include/output_port_lookup.xml +#define OPENFLOW_LOOKUP_WILDCARD_MISSES_REG 0x2000000 +#define OPENFLOW_LOOKUP_WILDCARD_HITS_REG 0x2000004 +#define OPENFLOW_LOOKUP_EXACT_MISSES_REG 0x2000008 +#define OPENFLOW_LOOKUP_EXACT_HITS_REG 0x200000c +#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_0_REG 0x2000010 +#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_1_REG 0x2000014 +#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_2_REG 0x2000018 +#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_3_REG 0x200001c +#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_4_REG 0x2000020 +#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_5_REG 0x2000024 +#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_6_REG 0x2000028 +#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_7_REG 0x200002c +#define OPENFLOW_LOOKUP_DUMY_SOFTWARE_0_REG 0x2000030 +#define OPENFLOW_LOOKUP_DUMY_SOFTWARE_1_REG 0x2000034 +#define OPENFLOW_LOOKUP_TIMER_REG 0x2000038 + +// Name: in_arb (IN_ARB) +// Description: Round-robin input arbiter +// File: lib/verilog/core/input_arbiter/rr_input_arbiter/xml/rr_input_arbiter.xml +#define IN_ARB_NUM_PKTS_SENT_REG 0x2000100 +#define IN_ARB_LAST_PKT_WORD_0_HI_REG 0x2000104 +#define IN_ARB_LAST_PKT_WORD_0_LO_REG 0x2000108 +#define IN_ARB_LAST_PKT_CTRL_0_REG 0x200010c +#define IN_ARB_LAST_PKT_WORD_1_HI_REG 0x2000110 +#define IN_ARB_LAST_PKT_WORD_1_LO_REG 0x2000114 +#define IN_ARB_LAST_PKT_CTRL_1_REG 0x2000118 +#define IN_ARB_STATE_REG 0x200011c + +// Name: vlan_remover (VLAN_REMOVER) +// Description: Remove vlan tag and ethtype if ethtype is vlan, and store them into module header +// File: projects/openflow_switch/include/vlan_remover.xml + +// Name: opl_processor (OPL_PROCESSOR) +// Description: opl_processor +// File: projects/openflow_switch/include/opl_processor.xml + +// Name: header_parser (HEADER_PARSER) +// Description: Chop ether/IP/UDP-TCP header into 11 tuples +// File: projects/openflow_switch/include/header_parser.xml + +// Name: match_arbiter (MATCH_ARBITER) +// Description: Arbitration between exact and wildcard lookups results +// File: projects/openflow_switch/include/match_arbiter.xml + +// Name: bram_output_queues (BRAM_OQ) +// Description: BRAM-based output queues +// File: lib/verilog/core/output_queues/bram_output_queues/xml/bram_output_queues.xml +#define BRAM_OQ_DISABLE_QUEUES_REG 0x2000300 +#define BRAM_OQ_QUEUE_0_NUM_PKT_BYTES_RECEIVED_REG 0x2000380 +#define BRAM_OQ_QUEUE_0_NUM_PKTS_RECEIVED_REG 0x2000384 +#define BRAM_OQ_QUEUE_0_NUM_PKTS_DROPPED_REG 0x2000388 +#define BRAM_OQ_QUEUE_0_NUM_WORDS_IN_QUEUE_REG 0x200038c +#define BRAM_OQ_QUEUE_1_NUM_PKT_BYTES_RECEIVED_REG 0x2000390 +#define BRAM_OQ_QUEUE_1_NUM_PKTS_RECEIVED_REG 0x2000394 +#define BRAM_OQ_QUEUE_1_NUM_PKTS_DROPPED_REG 0x2000398 +#define BRAM_OQ_QUEUE_1_NUM_WORDS_IN_QUEUE_REG 0x200039c +#define BRAM_OQ_QUEUE_2_NUM_PKT_BYTES_RECEIVED_REG 0x20003a0 +#define BRAM_OQ_QUEUE_2_NUM_PKTS_RECEIVED_REG 0x20003a4 +#define BRAM_OQ_QUEUE_2_NUM_PKTS_DROPPED_REG 0x20003a8 +#define BRAM_OQ_QUEUE_2_NUM_WORDS_IN_QUEUE_REG 0x20003ac +#define BRAM_OQ_QUEUE_3_NUM_PKT_BYTES_RECEIVED_REG 0x20003b0 +#define BRAM_OQ_QUEUE_3_NUM_PKTS_RECEIVED_REG 0x20003b4 +#define BRAM_OQ_QUEUE_3_NUM_PKTS_DROPPED_REG 0x20003b8 +#define BRAM_OQ_QUEUE_3_NUM_WORDS_IN_QUEUE_REG 0x20003bc +#define BRAM_OQ_QUEUE_4_NUM_PKT_BYTES_RECEIVED_REG 0x20003c0 +#define BRAM_OQ_QUEUE_4_NUM_PKTS_RECEIVED_REG 0x20003c4 +#define BRAM_OQ_QUEUE_4_NUM_PKTS_DROPPED_REG 0x20003c8 +#define BRAM_OQ_QUEUE_4_NUM_WORDS_IN_QUEUE_REG 0x20003cc +#define BRAM_OQ_QUEUE_5_NUM_PKT_BYTES_RECEIVED_REG 0x20003d0 +#define BRAM_OQ_QUEUE_5_NUM_PKTS_RECEIVED_REG 0x20003d4 +#define BRAM_OQ_QUEUE_5_NUM_PKTS_DROPPED_REG 0x20003d8 +#define BRAM_OQ_QUEUE_5_NUM_WORDS_IN_QUEUE_REG 0x20003dc +#define BRAM_OQ_QUEUE_6_NUM_PKT_BYTES_RECEIVED_REG 0x20003e0 +#define BRAM_OQ_QUEUE_6_NUM_PKTS_RECEIVED_REG 0x20003e4 +#define BRAM_OQ_QUEUE_6_NUM_PKTS_DROPPED_REG 0x20003e8 +#define BRAM_OQ_QUEUE_6_NUM_WORDS_IN_QUEUE_REG 0x20003ec +#define BRAM_OQ_QUEUE_7_NUM_PKT_BYTES_RECEIVED_REG 0x20003f0 +#define BRAM_OQ_QUEUE_7_NUM_PKTS_RECEIVED_REG 0x20003f4 +#define BRAM_OQ_QUEUE_7_NUM_PKTS_DROPPED_REG 0x20003f8 +#define BRAM_OQ_QUEUE_7_NUM_WORDS_IN_QUEUE_REG 0x20003fc + +#define BRAM_OQ_QUEUE_GROUP_BASE_ADDR 0x2000380 +#define BRAM_OQ_QUEUE_GROUP_INST_OFFSET 0x0000010 + +// Name: watchdog (WDT) +// Description: Watchdog timer +// File: projects/openflow_switch/include/watchdog.xml +#define WDT_ENABLE_FLG_REG 0x2000400 +#define WDT_COUNTER_REG 0x2000404 + +// Name: exact_match (EXACT_MATCH) +// Description: exact match lookup +// File: projects/openflow_switch/include/exact_match.xml + +// Name: wildcard_match (OPENFLOW_WILDCARD_LOOKUP) +// Description: wildcard match lookup +// File: projects/openflow_switch/include/wildcard_match.xml +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_0_REG 0x2001000 +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_1_REG 0x2001004 +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_2_REG 0x2001008 +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_3_REG 0x200100c +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_4_REG 0x2001010 +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_5_REG 0x2001014 +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_6_REG 0x2001018 +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_7_REG 0x200101c +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_8_REG 0x2001020 +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_9_REG 0x2001024 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_0_REG 0x2001028 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_1_REG 0x200102c +#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_2_REG 0x2001030 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_3_REG 0x2001034 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_4_REG 0x2001038 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_5_REG 0x200103c +#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_6_REG 0x2001040 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_7_REG 0x2001044 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_0_REG 0x2001048 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_1_REG 0x200104c +#define OPENFLOW_WILDCARD_LOOKUP_CMP_2_REG 0x2001050 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_3_REG 0x2001054 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_4_REG 0x2001058 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_5_REG 0x200105c +#define OPENFLOW_WILDCARD_LOOKUP_CMP_6_REG 0x2001060 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_7_REG 0x2001064 +#define OPENFLOW_WILDCARD_LOOKUP_READ_ADDR_REG 0x2001068 +#define OPENFLOW_WILDCARD_LOOKUP_WRITE_ADDR_REG 0x200106c +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG 0x2001070 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_1_REG 0x2001074 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_2_REG 0x2001078 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_3_REG 0x200107c +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_4_REG 0x2001080 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_5_REG 0x2001084 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_6_REG 0x2001088 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_7_REG 0x200108c +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_8_REG 0x2001090 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_9_REG 0x2001094 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_10_REG 0x2001098 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_11_REG 0x200109c +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_12_REG 0x20010a0 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_13_REG 0x20010a4 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_14_REG 0x20010a8 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_15_REG 0x20010ac +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_16_REG 0x20010b0 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_17_REG 0x20010b4 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_18_REG 0x20010b8 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_19_REG 0x20010bc +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_20_REG 0x20010c0 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_21_REG 0x20010c4 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_22_REG 0x20010c8 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_23_REG 0x20010cc +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_24_REG 0x20010d0 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_25_REG 0x20010d4 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_26_REG 0x20010d8 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_27_REG 0x20010dc +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_28_REG 0x20010e0 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_29_REG 0x20010e4 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_30_REG 0x20010e8 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_31_REG 0x20010ec +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG 0x20010f0 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_1_REG 0x20010f4 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_2_REG 0x20010f8 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_3_REG 0x20010fc +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_4_REG 0x2001100 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_5_REG 0x2001104 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_6_REG 0x2001108 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_7_REG 0x200110c +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_8_REG 0x2001110 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_9_REG 0x2001114 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_10_REG 0x2001118 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_11_REG 0x200111c +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_12_REG 0x2001120 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_13_REG 0x2001124 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_14_REG 0x2001128 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_15_REG 0x200112c +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_16_REG 0x2001130 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_17_REG 0x2001134 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_18_REG 0x2001138 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_19_REG 0x200113c +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_20_REG 0x2001140 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_21_REG 0x2001144 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_22_REG 0x2001148 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_23_REG 0x200114c +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_24_REG 0x2001150 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_25_REG 0x2001154 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_26_REG 0x2001158 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_27_REG 0x200115c +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_28_REG 0x2001160 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_29_REG 0x2001164 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_30_REG 0x2001168 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_31_REG 0x200116c +#define OPENFLOW_WILDCARD_LOOKUP_DUMMY_1_REG 0x2001170 +#define OPENFLOW_WILDCARD_LOOKUP_DUMMY_2_REG 0x2001174 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_0_REG 0x2001178 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_1_REG 0x200117c +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_2_REG 0x2001180 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_3_REG 0x2001184 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_4_REG 0x2001188 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_5_REG 0x200118c +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_6_REG 0x2001190 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_7_REG 0x2001194 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_8_REG 0x2001198 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_9_REG 0x200119c +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_10_REG 0x20011a0 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_11_REG 0x20011a4 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_12_REG 0x20011a8 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_13_REG 0x20011ac +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_14_REG 0x20011b0 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_15_REG 0x20011b4 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_16_REG 0x20011b8 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_17_REG 0x20011bc +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_18_REG 0x20011c0 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_19_REG 0x20011c4 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_20_REG 0x20011c8 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_21_REG 0x20011cc +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_22_REG 0x20011d0 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_23_REG 0x20011d4 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_24_REG 0x20011d8 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_25_REG 0x20011dc +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_26_REG 0x20011e0 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_27_REG 0x20011e4 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_28_REG 0x20011e8 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_29_REG 0x20011ec +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_30_REG 0x20011f0 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_31_REG 0x20011f4 + +// Name: DRAM (DRAM) +// Description: DRAM + +#endif diff --git a/openflow/hw-lib/skeleton/debug.h b/openflow/hw-lib/skeleton/debug.h new file mode 100644 index 00000000..d6a8f8af --- /dev/null +++ b/openflow/hw-lib/skeleton/debug.h @@ -0,0 +1,106 @@ + +#ifndef OF_HW_DEBUG_H +#define OF_HW_DEBUG_H 1 + +#include +#include + +#if !defined(HWTABLE_NO_DEBUG) +extern int of_hw_debug; +#define dbg_send(mod, lvl, fmt, args...) \ + if (of_hw_debug >= (lvl)) fprintf(stderr, fmt, ##args) +#endif + +#define DBG_LVL_NONE -1 /* All output off */ +#define DBG_LVL_ERROR 0 /* Default value */ +#define DBG_LVL_ALWAYS 0 /* For requested dump output */ +#define DBG_LVL_WARN 1 +#define DBG_LVL_VERBOSE 2 +#define DBG_LVL_VVERB 3 /* Include success indications */ + +/* Sorry for the lazy syntax here. */ +#define DBG_CHECK(lvl) (((lvl) >= 0) && (of_hw_debug >= (lvl))) +#define DBG_ERROR(fmt, args...) dbg_send(0, DBG_LVL_ERROR, fmt, ##args) +#define DBG_ALWAYS(fmt, args...) dbg_send(0, DBG_LVL_ALWAYS, fmt, ##args) +#define DBG_WARN(fmt, args...) dbg_send(0, DBG_LVL_WARN, fmt, ##args) +#define DBG_VERBOSE(fmt, args...) dbg_send(0, DBG_LVL_VERBOSE, fmt, ##args) +#define DBG_VVERB(fmt, args...) dbg_send(0, DBG_LVL_VVERB, fmt, ##args) +#define DBG_NONE(fmt, args...) +/* Same as DEBUG_ALWAYS */ +#define DEBUGK(fmt, args...) dbg_send(0, DBG_LVL_ALWAYS, fmt, ##args) + +#define REPORT_ERROR(str) \ + DBG_ERROR("ERROR: %s:%d. %s\n", __FUNCTION__, __LINE__, str) + +/* Default debugging location string */ +#define ANNOUNCE_LOCATION DBG_VVERB("%s: %d\n", __FUNCTION__, __LINE__) +#define DBG_INCR(cnt) (++(cnt)) + +/* Should assert return? Not presently */ +#define ASSERT(cond) \ + if (!(cond)) DBG_ERROR("ASSERTION %s IN %s FAILED LINE %d\n", \ + #cond, __FUNCTION__, __LINE__) + +/* DEBUG for HW flow lists */ +#define HW_FLOW_MAGIC 0xba5eba11 +#define HW_FLOW_MAKE_VALID(hf) (hf)->magic = HW_FLOW_MAGIC +#define HW_FLOW_IS_VALID(hf) \ + (((hf) != NULL) && ((hf)->magic == HW_FLOW_MAGIC)) + +/* + * Carry out an operation and check for error, optionally returning + * from the calling routine. To avoid compiler + * warnings in routines with void return, we give two macros. + * + * WARNING: This check uses rv != 0 (not just rv < 0). + */ + +#define TRY(op, str) do { \ + int rv; \ + if (((rv = (op)) < 0)) { \ + DBG_ERROR("ERROR %d: %s\n", rv, str); \ + return rv; \ + } else { \ + DBG_NONE("%s: success\n", str); \ + } \ + } while (0) + +#define TRY_NR(op, str) do { \ + int rv; \ + if (((rv = (op)) != 0)) { \ + DBG_ERROR("ERROR %d: %s\n", rv, str); \ + } else { \ + DBG_NONE("%s: success\n", str); \ + } \ + } while (0) + +#else /* No debugging */ + +#define DBG_CHECK(lvl) 0 +#define ANNOUNCE_LOCATION +#define ACT_STRING(action) "" +#define DBG_INCR(cnt) +#define DBG_ERROR(fmt, args...) +#define DBG_ALWAYS(fmt, args...) +#define DBG_WARN(fmt, args...) +#define DBG_VERBOSE(fmt, args...) +#define DBG_VVERB(fmt, args...) +#define DBG_NONE(fmt, args...) +#define DEBUGK(fmt, args...) +#define REPORT_ERROR(str) + +#define ASSERT(cond) + +#define HW_FLOW_MAKE_VALID(hf) +#define HW_FLOW_IS_VALID(hf) 1 + +#define TRY(op, str) do { \ + int rv; \ + if (((rv = (op)) != 0)) return rv; \ + } while (0) + +#define TRY_NR(op, str) (void)op + +#endif /* !defined(HWTABLE_NO_DEBUG) */ + +#endif /* OF_HW_DEBUG_H */ diff --git a/openflow/hw-lib/skeleton/hw_drv.c b/openflow/hw-lib/skeleton/hw_drv.c new file mode 100644 index 00000000..0ecd5909 --- /dev/null +++ b/openflow/hw-lib/skeleton/hw_drv.c @@ -0,0 +1,309 @@ +/* + * Skeleton hardware datapath, internal implemenation + * + */ +#include + +#include +#include + +#include "list.h" + +#include "os.h" +#include "debug.h" +#include "of_hw_platform.h" +#include "hw_drv.h" +#include "hw_flow.h" +#include "port.h" +#include "txrx.h" +#include "udatapath/switch-flow.h" + +/**************************************************************** + * + * Hardware resource management section + * + ****************************************************************/ + +static int global_init_done = 0; +int of_hw_drv_instances = 0; + +#if !defined(HWTABLE_NO_DEBUG) +int of_hw_debug = DBG_LVL_WARN; +#endif + +/* Internal initialization of HW datapath structures */ +static int +hw_drv_global_init(int init_hw) +{ + HW_DRV_MUTEX_INIT; + of_hw_ports_init(); + + if (init_hw) { /* Do hardware initialization */ + TRY(PLATFORM_INIT(), "PLATFORM INIT"); + TRY_NR(of_hw_fp_setup(), "global FP setup"); + } + + global_init_done = 1; + return 0; +} + +/* Skeleton capabilities structure */ +static of_hw_driver_caps_t of_hw_caps = { + .flags = , + .max_flows = , + .wc_supported = OFPFW_ALL, + .actions_supported = OFPAT_XXX, + .ofpc_flags = OFPC_XXX +}; + +/* Initialize the internal HW datapath structure */ +static int +hw_drv_int_init(of_hw_driver_int_t *hw_int, struct datapath *dp) +{ + static int dp_idx = 0; + + /* Fill in caps object */ + memcpy(&hw_int->hw_driver.caps, &of_hw_caps, sizeof(of_hw_caps)); + hw_int->dp = dp; + hw_int->dp_idx = dp_idx++; + + hw_int->n_flows = 0; + list_init(&hw_int->flows); + list_init(&hw_int->iter_flows); + hw_int->next_serial = 0; + + return 0; +} + +/**************************************************************** + * + * Driver functions + * + ****************************************************************/ + +/* + * of_hw_ioctl + * + * HW IOCTL function + */ + +static int +of_hw_ioctl(of_hw_driver_t *hw_drv, uint32_t op, void **io_param, + int *io_len UNUSED) +{ + int val; + of_hw_driver_int_t *hw_int; + int rv = 0; + + hw_int = (of_hw_driver_int_t *)hw_drv; + + switch (op) { + case OF_HW_IOCTL_TABLE_DEBUG_SET: + val = *(int *)(*io_param); + DBG_WARN("Changing table debug value to %d\n", val); + /* FIXME: Use HW driver for debug level? */ + hw_int->table_debug_level = val; + of_hw_debug = val; + break; + case OF_HW_IOCTL_PORT_DEBUG_SET: + val = *(int *)(*io_param); + DBG_WARN("Changing port debug value to %d\n", val); + hw_int->port_debug_level = val; + break; + case OF_HW_IOCTL_BYTE_PKT_CNTR_SET: + val = *(int *)(*io_param); + if ((val != OF_HW_CNTR_PACKETS) && + (val != OF_HW_CNTR_BYTES)) { + DBG_ERROR("Bad byte/pkt counters select value %d\n", val); + } else { + hw_int->stat_sel = val; + } + break; + default: + rv = -1; /* Change to UNSUPPORTED */ + break; + } + + return 0; +} + +static void +of_hw_table_destroy(struct sw_table *table) +{ + of_hw_driver_int_t *hw_int; + + hw_int = (of_hw_driver_int_t *)table; + if (hw_int != NULL && hw_int->dp != NULL) { + DBG_WARN("Table destroy called for dp idx %d\n", + hw_int->dp_idx); + } else { + DBG_ERROR("Table destroy called on NULL dp\n"); + } + + delete_of_hw_driver(&hw_int->hw_driver); +} + +static int +of_hw_table_iterate(struct sw_table *table, + const struct sw_flow_key *key, uint16_t out_port, + struct sw_table_position *position, + int (*callback)(struct sw_flow *flow, void *private), + void *private) +{ + + of_hw_driver_int_t *hw_int; + struct sw_flow *flow; + unsigned long start; + + hw_int = (of_hw_driver_int_t *)table; + if (hw_int != NULL) { + start = ~position->private[0]; + LIST_FOR_EACH (flow, struct sw_flow, iter_node, &hw_int->iter_flows) { + if (flow->serial <= start + && flow_matches_2wild(key, &flow->key) + && flow_has_out_port(flow, out_port)) { + int error; + + /* Update stats as that's what's generally used */ + TRY_NR(of_hw_sw_flow_stat_update(flow, NULL, false), + "sw flow stat update"); + error = callback(flow, private); + if (error) { + position->private[0] = ~(flow->serial - 1); + return error; + } + } + } + } else { + DBG_ERROR("Table iterate called on NULL driver or SW flow table\n"); + return -1; + } + + return 0; +} + +static const char *hw_drv_name = "HW FlowDriver"; + +static void +of_hw_sw_table_stats(struct sw_table *table, struct sw_table_stats *stats) +{ + of_hw_driver_int_t *hw_int; + unsigned long matched = 0; + unsigned long missed = 0; + + hw_int = (of_hw_driver_int_t *)table; + stats->name = hw_drv_name; + stats->wildcards = OFPFW_ALL; + stats->n_flows = hw_int->n_flows; + stats->max_flows = of_hw_caps.max_flows; + /* FIXME: Collect stats */ + TRY_NR(of_hw_table_stats_update(hw_int, &matched, &missed), + "of_hw_table_stats_update"); + stats->n_lookup = missed + matched; + stats->n_matched = matched; +} + +static int +of_hw_table_stats_get(of_hw_driver_t *hw_drv, struct ofp_table_stats *stats) +{ + DBG_WARN("TABLE STATS FIXME\n"); + return 0; +} + +/* + * Create and initialize a new hardware datapath object + */ + +of_hw_driver_t * +new_of_hw_driver(struct datapath *dp) +{ + struct sw_table *sw_tab; + of_hw_driver_t *hw_drv; + of_hw_driver_int_t *hw_int; + + if (!global_init_done) { + if (hw_drv_global_init(1) < 0) { + REPORT_ERROR("HW driver global init failed\n"); + return NULL; + } + } + hw_int = ALLOC(sizeof(*hw_int)); + if (hw_int == NULL) { + REPORT_ERROR("Could not allocate HW driver\n"); + return NULL; + } + memset(hw_int, 0, sizeof(*hw_int)); + + if (hw_drv_int_init(hw_int, dp) < 0) { + FREE(hw_int); + return NULL; + } + + + /* These all point to the same place */ + hw_drv = &hw_int->hw_driver; + sw_tab = &hw_drv->sw_table; + + sw_tab->n_lookup = 0; + sw_tab->n_matched = 0; + + /* Fill out the function pointers */ + sw_tab->lookup = of_hw_flow_lookup; + sw_tab->insert = of_hw_flow_install; + sw_tab->modify = of_hw_flow_modify; + sw_tab->delete = of_hw_flow_delete; + sw_tab->timeout = of_hw_flow_timeout; + + sw_tab->destroy = of_hw_table_destroy; + sw_tab->iterate = of_hw_table_iterate; + sw_tab->stats = of_hw_sw_table_stats; + + hw_drv->table_stats_get =of_hw_table_stats_get; + hw_drv->port_stats_get = of_hw_port_stats_get; + hw_drv->flow_stats_get = NULL; + hw_drv->aggregate_stats_get = NULL; + + hw_drv->port_add = of_hw_port_add; + hw_drv->port_remove = of_hw_port_remove; + hw_drv->port_link_get = of_hw_port_link_get; + hw_drv->port_enable_set = of_hw_port_enable_set; + hw_drv->port_enable_get = of_hw_port_enable_get; + hw_drv->port_queue_config = of_hw_port_queue_config; + hw_drv->port_queue_remove = of_hw_port_queue_remove; + hw_drv->port_change_register = of_hw_port_change_register; + + hw_drv->packet_send = of_hw_packet_send; + hw_drv->packet_receive_register = of_hw_packet_receive_register; + + hw_drv->ioctl = of_hw_ioctl; + + ++of_hw_drv_instances; + + return hw_drv; +} + +/* + * Deallocate a hardware datapath object + * If clear_hw is set, the HW structures related to the + * datapath are also cleared. + * + * In general, clear_hw should be set for now. + */ +void +delete_of_hw_driver(of_hw_driver_t *hw_drv) +{ + int idx; + of_hw_driver_int_t *hw_int; + + hw_int = (of_hw_driver_int_t *)hw_drv; + + /* Clear the port table of ownership for this dp */ + FOREACH_DP_PORT(idx, hw_drv) { + of_hw_ports[idx].owner = NULL; + } + + of_hw_flow_remove_all(hw_int); + + FREE(hw_drv); + --of_hw_drv_instances; +} diff --git a/openflow/hw-lib/skeleton/hw_drv.h b/openflow/hw-lib/skeleton/hw_drv.h new file mode 100644 index 00000000..7e6ecb0e --- /dev/null +++ b/openflow/hw-lib/skeleton/hw_drv.h @@ -0,0 +1,97 @@ +#ifndef OF_HW_DRV_H +#define OF_HW_DRV_H 1 + +#include +#include "of_hw_platform.h" +#include "list.h" + +/**************************************************************** + * + * High Level Design Notes + * + * Hardware tables are managed field_control_t and entry_control_t + * structures in hw_flow.h; these roughly mirror the HW structure + * and are preallocated. + * + * The glue between these and SW flows are provided by the HW flow + * objects (also in hw_flow.h) which are dynamically allocated and + * logically extend the SW flow object. + * + * A linear table of HW flow objects is maintained, mostly drawn + * from the existing table-linear.c implementation in udatapath. + * + */ + +/**************************************************************** + * Hardware independent port mapping macros + ****************************************************************/ + +/* Map ports using software data structures and DP check; independent of HW */ +#define OF_PORT_IN_DP(_hwdrv, _i) (((_i) < OF_HW_MAX_PORT) && \ + (of_hw_ports[_i].owner == (of_hw_driver_t *)(_hwdrv))) + +#define OF_PORT_TO_HW_PORT(_hwdrv, _i) \ + (OF_PORT_IN_DP(_hwdrv, _i) ? of_hw_ports[_i].port : -1) + +/* TBD: Define flow tracking objects */ + +/**************************************************************** + * + * Hardware datapath internal control structure + * Extends generic hardware datapath structure + * (which currently extends software table structure) + * + ****************************************************************/ + +/* Counts the number of instances */ +extern int of_hw_drv_instances; + +typedef struct of_hw_driver_int { + of_hw_driver_t hw_driver; + struct datapath *dp; /* Owning datapath */ + + /* Maintain a linked list of flows for tracking */ + struct list flows; /* The main list */ + struct list iter_flows; /* For iteration operation */ + unsigned long int next_serial; + + /* Callback function for received packets. */ + of_packet_in_f rx_handler; + void *rx_cookie; + + /* Callback function for port change notification */ + of_port_change_f port_change; + void *port_change_cookie; + + /* Lock object? */ + + // struct list sw_flows; + // struct list iter_sw_flows; + // struct sw_flow *iter_state; /* Place tracker for interrupted iterations */ + + /* Stats */ + uint32_t n_flows; /* Current number of flows in table */ + uint32_t n_inserts; /* Total inserts */ + uint32_t rx_pkt_alloc_failures; + uint32_t insert_errors; + + /* Configuration */ + /* Port bitmap of ports in DP by device */ + FIXME port_bitmap; + FIXME flood_bitmap; + int stat_sel; /* Packets or bytes */ + int dp_idx; /* In HW dp, but not SW dp */ + + int table_debug_level; + int port_debug_level; +} of_hw_driver_int_t; + +/* HW_DRV_MUTEX object ? */ + +#define HW_DRV_MUTEX_INIT /* TBD */ +#define HW_DRV_LOCK /* TBD */ +#define HW_DRV_UNLOCK /* TBD */ + +#define HW_INT(hw_drv) ((of_hw_driver_int_t *)hw_drv) + +#endif /* OF_HW_DRV_H */ diff --git a/openflow/hw-lib/skeleton/hw_flow.c b/openflow/hw-lib/skeleton/hw_flow.c new file mode 100644 index 00000000..2f9d6eca --- /dev/null +++ b/openflow/hw-lib/skeleton/hw_flow.c @@ -0,0 +1,708 @@ +/* + * Functions related to hardware flow processing; this is the glue + * and administration between upper level flow operations and lower + * level field processor operations. + */ + +#include +#include +#include + +#include "os.h" +#include "debug.h" +#include "hw_drv.h" +#include "port.h" +#include "hw_flow.h" +#include "udatapath/switch-flow.h" +#include "udatapath/datapath.h" +#include "lib/packets.h" + +static field_control_t field_control; + +/**************************************************************** + * + * SW/HW flow correlation book keeping routines + * + ****************************************************************/ + +/* Allocate and initialize a HW flow control structure. */ +static hw_flow_t * +hw_flow_create(struct sw_flow *flow) +{ + hw_flow_t *hw_flow; + + if ((hw_flow = ALLOC(sizeof(*hw_flow))) != NULL) { + memset(hw_flow, 0, sizeof(*hw_flow)); + HW_FLOW_MAKE_VALID(hw_flow); + hw_flow->flow = flow; + flow->private = (void *)hw_flow; + } + + return hw_flow; +} + +/* Remove an FP entry from a device */ +static int +HW_entry_remove(entry_control_t *entry) +{ + FIXME; + + return 0; +} + +/**************************************************************** + * + * Flow stats operations + * + ****************************************************************/ + +/* + * Read and convert the stats for an FP entry; maintains state + * of last counter value read and accumulates differences. + * + * Assumes mutex held. + */ +static int +entry_stat_update(entry_control_t *ent, int *used) +{ + unsigned long int cur_counter; + + FIXME_get_current_stats(cur_counter); + + ent->total_counter += cur_counter - ent->last_counter; + ent->last_counter = cur_counter; + + if (used != NULL) { + *used |= (ent->used_check != cur_counter); + ent->used_check = cur_counter; + } + + return 0; +} + +/* + * Get the stats for an OF (SW) flow object from HW tables + * NOTE: This will clear any existing value from the flow + * counters; if SW table counters need to be added in, that + * should be done after this calculation. + * + * If used is non-NULL, it will be filled with a boolean + * indication of whether the flow's counters have changed + * from their current state. + * + * Assumes mutex held. + * + * If force_sync is true, will sync SW counters with HW first + */ +int +of_hw_sw_flow_stat_update(struct sw_flow *flow, int *used, int force_sync) +{ + entry_control_t *ent; + hw_flow_t *hw_flow; + int idx; + + if (used != NULL) { + *used = false; + } + hw_flow = (hw_flow_t *)(flow->private); + if (!HW_FLOW_IS_VALID(hw_flow)) { + DBG_ERROR("BAD HW FLOW OBJECT %p for flow %p\n", hw_flow, flow); + return -1; + } + ASSERT(hw_flow->entry_count <= HW_FLOWS_PER_FLOW_MAX); + + if (force_sync) { + FIXME_sync_hw_stats(); + } + + /* FIXME: Will this accumulate and clear HW counters? */ + hw_flow->hw_byte_count = hw_flow->hw_packet_count = 0; + for (idx = 0; idx < hw_flow->entry_count; idx++) { + ent = hw_flow->entry_list[idx]; + + if (entry_stat_update(ent, used) < 0) { + DBG_WARN("Warning: could not get stats for flow\n"); + continue; + } + FIXME_update proper hw_flow counters; + } + flow->packet_count = hw_flow->hw_packet_count; + flow->byte_count = hw_flow->hw_byte_count; + + return 0; +} + +/* Read all the stats from the chip and update counters in flow tab */ +/* Index 0 holds default rule that indicates a missed count */ +/* ASSUMES LOCK HELD */ +int +of_hw_table_stats_update(of_hw_driver_int_t *hw_drv, unsigned long *matched, + unsigned long *missed) +{ + struct sw_flow *flow, *n; + of_hw_driver_int_t *hw_int; + + hw_int = (of_hw_driver_int_t *)hw_drv; + *matched = 0; + *missed = 0; + + if (STATS_BYTES(hw_int->stat_sel)) { /* Lookup count not supported */ + return -1; + } + + LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &hw_int->flows) { + if (flow->private != NULL) { + TRY_NR(of_hw_sw_flow_stat_update(flow, NULL, false), + "update flow stat"); + *matched += flow->packet_count; + } + } + + /* + * FIXME: To get missed stats, query entry 0 of HW table. + * This isn't really correct if there are entries in the SW datapath + * + * FIXME: If there are multiple data paths, should have one + * default entry qualifying on ports in that datapath with + * another entry dropping any packets on other ports. + */ + { + field_control_t *fc; + entry_control_t *ent; + + fc = &field_control; + ent = &fc->entry_list[0]; + ASSERT(ent->in_use); + TRY_NR(entry_stat_update(ent, NULL), "tab: entry_stat_update"); + *missed += ent->total_counter; + } + + return 0; +} + +/* + * Remove the FP entry or entries associated to a SW flow from the HW; + * + */ +static int +hw_flow_remove(struct sw_flow *flow) +{ + field_control_t *fc; + entry_control_t *ent; + hw_flow_t *hw_flow; + int idx; + +#if 0 /* Do not remove entries (debugging) */ + return 0; +#endif + + if (flow == NULL) { + return 0; + } + + hw_flow = (hw_flow_t *)(flow->private); + DBG_VERBOSE("Removing hw flow %p, flow %p\n", hw_flow, flow); + if (!HW_FLOW_IS_VALID(hw_flow)) { + return 0; + } + ASSERT(hw_flow->entry_count <= HW_FLOWS_PER_FLOW_MAX); + + TRY_NR(of_hw_sw_flow_stat_update(flow, NULL, true), + "rmv flow stat update"); + for (idx = 0; idx < hw_flow->entry_count; idx++) { + ent = hw_flow->entry_list[idx]; + ASSERT(ent != NULL); + + TRY_NR(HW_entry_remove(ent), "HW_entry_remove"); + hw_flow->entry_list[idx] = NULL; + } + FREE(hw_flow); + flow->private = NULL; + + return 0; +} + + +/**************************************************************** + * + * Important support routines related to FP setup, actions, flows + * + ****************************************************************/ + +/* ASSERT: of_port belongs to datapath */ +static void +add_dport_to_extra(of_hw_driver_int_t *hw_int, int of_port, + hw_flow_extra_t *extra) +{ + ASSERT(OF_PORT_IN_DP(hw_int, of_port)); + + extra->dest_port = MAP_OF_PORT_TO_HW_PORT(hw_int, of_port); + FIXME_update extra->dest_count if appropriate; +} + +/* Set up flood/all bitmaps + * NOTE: Assumes source port is not wildcarded. + */ +static void +mcast_bitmaps_set(of_hw_driver_int_t *hw_int, hw_flow_extra_t *extra, + int dest_port) +{ + FIXME; +} + +/* + * Validate actions for a flow relative to HW capabilities; + * + * Bool: true means supported, false not supported + * + * Accumulate additional info about the flow in extra. Specifically, + * this determines the output ports on each physical device related + * to the flow. + * + * FIXME: No-flood ports are currently not specified + */ + +static int +actions_supported_check(of_hw_driver_int_t *hw_int, + const struct sw_flow_key *key, + const struct ofp_action_header *actions, + size_t actions_len, + hw_flow_extra_t *extra) +{ + uint8_t *p; + int src_port; /* Port in host order */ + int dest_port; /* Port in host order */ + int action; + int src_is_wc = false; /* Is source wildcarded? */ + + ANNOUNCE_LOCATION; + ASSERT(extra != NULL); + + FIXME("probably needs work for your platform"); + + p = (uint8_t *)actions; + src_port = ntohs(key->flow.in_port); + + src_is_wc = key->wildcards & OFPFW_IN_PORT; + if (!src_is_wc) { + if (OF_PORT_IN_DP(hw_int, src_port)) { + extra->source_port = MAP_TO_HW_PORT(hw_int, src_port); + } else { + DBG_WARN("Source port %d not in DP %d\n", src_port, + hw_int->dp_idx); + return false; + } + } else { + extra->source_port = -1; + if (of_hw_drv_instances > 1) { + DBG_WARN("Source port WC not supported w/ multi-DP\n"); + return false; /* Not currently supported w/ multiple datapaths */ + } + /* NOTE/FIXME: Source wildcard with multiple output ports requires + * using a per-port hardware flow rule to allow filtering of + * the source port. (Currently not supported and checked below.) + */ + } + + while (actions_len > 0) { + struct ofp_action_header *ah = (struct ofp_action_header *)p; + struct ofp_action_output *oa = (struct ofp_action_output *)p; + size_t len = ntohs(ah->len); + + action = ntohs(ah->type); + DBG_VVERB("action chk %d\n", action); + /* Currently supported: output port(s) action */ + if ((action < 0) || (action > ACTION_LAST)) { + DBG_WARN("Unknown action id %d\n", action); + return false; + } + + if (action_map[action] == ACTION_NOT_SUPPORTED) { + DBG_WARN("Action %d not supported\n", action); + return false; + } + + /* Support front panel ports plus IN_PORT, ALL, FLOOD. */ + if ((action == OFPAT_OUTPUT) || (action == OFPAT_ENQUEUE)) { + /* FIXME: For now, using the fact that enqueue and output + * actions are the same at the start of the structure + */ + dest_port = ntohs(oa->port); + if (dest_port == OFPP_TABLE) { /* Unsupported */ + DBG_WARN("Warning: TABLE output action seen\n"); + return false; + } else if (OF_PORT_IN_DP(hw_int, dest_port)) { + add_dport_to_extra(hw_int, dest_port, extra); + } else if ((dest_port == OFPP_FLOOD) || (dest_port == OFPP_ALL)) { + mcast_bitmaps_set(hw_int, extra, dest_port); + } else if (dest_port == OFPP_IN_PORT) { + if (src_is_wc) { + DBG_WARN("Warning: IN_PORT action on source wildcard\n"); + return false; + } + add_dport_to_extra(hw_int, src_port, extra); + } else if (dest_port == OFPP_CONTROLLER) { + /* Controller/local are implemented with a "copy to CPU" + * action and a special reason code; Don't count as output port + */ + extra->local_reason |= CPU_REASON_TO_CONTROLLER; + } else if (dest_port == OFPP_LOCAL) { + extra->local_reason |= CPU_REASON_TO_LOCAL; + } else { /* NORMAL */ + // DBG_WARN("Output action to port 0x%x not supported\n", + // dest_port); + // return false; /* FIXME: Ignore bad ports for now */ + } + if (action == OFPAT_ENQUEUE) { + uint32 qid; + struct ofp_action_enqueue *ea; + ea = (struct ofp_action_enqueue *)p; + qid = ntohl(ea->queue_id); + if ((extra->cosq = of_hw_qid_find(dest_port, qid)) < 0) { + DBG_WARN("Warning: qid %d, port %d, map to cos failed\n", + qid, dest_port); + } + } + } + p += len; + actions_len -= len; + } + + if (src_is_wc && (extra->dest_count > 1)) { + DBG_WARN("Warning: multi dest w/ src wildcard\n"); + return false; + } + + DBG_VERBOSE("Actions supported\n"); + return true; +} + +/**************************************************************** + * + * FP Table management and manipulation routines + * + ****************************************************************/ + +/* + * Functions related to hardware flow table manipulation and maintenance + */ + +/* Set up field control structure; should be idempotent */ +static void +field_control_init(void) +{ + field_control_t *fc; + int idx; + + fc = &field_control; + fc->entry_count = 0; + for (idx = 0; idx < FIELD_ENTRY_MAX; idx++) { + fc->entry_list[idx].in_use = 0; + fc->entry_list[idx].hw_flow = NULL; + fc->entry_list[idx].index = idx; + fc->entry_list[idx].last_counter = 0; + fc->entry_list[idx].counter_last_check = 0; + fc->entry_list[idx].total_counter = 0; + } +} + +/* Alloc HW entry control structure, add qualification, actions and install */ +static int +hw_entry_install(of_hw_driver_int_t *hw_int, + struct sw_flow *flow, hw_flow_t *hw_flow, + hw_flow_extra_t *extra) +{ + + /* Install HW entry */ + FIXME; +} + +/* + * hw_flow_install + * + * Install HW table entries corresponding to the given SW flow + */ +static int +hw_flow_install(of_hw_driver_int_t *hw_int, struct sw_flow *flow, + hw_flow_extra_t *extra) +{ + hw_flow_t *hw_flow; + + /* Allocate the HW flow object */ + if ((hw_flow = hw_flow_create(flow)) == NULL) { + DBG_ERROR("failed to create hw flow struct\n"); + return -1; + } + + DBG_VERBOSE("hw flow install: sw %p. hw %p\n", flow, hw_flow); + TRY(hw_entry_install(hw_int, 0, flow, hw_flow, extra), + "local entry"); + + return 0; +} + +/**************************************************************** + * + * The driver APIs + * + ****************************************************************/ + +/* + * Install a flow. + * + * First, check that the flow is supported; simultaneously, build + * up the "extra" information needed by the hardware for its installation. + * This includes bitmaps of the ports to which the packet will be + * forwarded (on local and remote devices if appropriate). + * + * Then look to see if the flow should overwrite an existing entry. + * If so, just remove that entry. + * + * Then call hw_flow_install which does all the actual HW changes + * based on the flow and on extra. + */ + +/* NOTE: Returns 1 if flow installed, not normal error code */ +int +of_hw_flow_install(struct sw_table *sw_tab, struct sw_flow *flow) +{ + hw_flow_extra_t extra; + of_hw_driver_int_t *hw_int; + int hw_rc = 0; + int sw_insert_done = 0; + struct sw_flow *f; + + hw_int = (of_hw_driver_int_t *)sw_tab; + + DBG_VERBOSE("flow install %p\n", flow); + memset(&extra, 0, sizeof(extra)); + extra.cosq = -1; + + if (!actions_supported_check(hw_int, &flow->key, flow->sf_acts->actions, + flow->sf_acts->actions_len, &extra)) { + /* Unsupported actions */ + DBG_VERBOSE("HW install failed: Unsupported actions\n"); + return 0; + } + + /* LOCK; */ + /* Go through list looking for matching flows */ + LIST_FOR_EACH (f, struct sw_flow, node, &hw_int->flows) { + if (f->priority == flow->priority + && f->key.wildcards == flow->key.wildcards + && flow_matches_2wild(&f->key, &flow->key)) { + /* Just remove the HW flow; install other below */ + TRY_NR(hw_flow_remove(f), "hw_flow_remove for replace"); + flow->serial = f->serial; + list_replace(&flow->node, &f->node); + list_replace(&flow->iter_node, &f->iter_node); + sw_insert_done = 1; + flow_free(f); + break; + } + if (f->priority < flow->priority) { + break; + } + } + + /* ASSERT: sw_insert_done OR f points to insertion point for flow */ + + hw_rc = hw_flow_install(hw_int, flow, &extra); + + if (hw_rc < 0) { + hw_int->insert_errors++; + if (sw_insert_done) { /* Remove from SW list */ + list_remove(&flow->node); + list_remove(&flow->iter_node); + flow_free(flow); + hw_int->n_flows--; + } + } else { + hw_int->n_flows++; + hw_int->n_inserts++; + if (!sw_insert_done) { + flow->serial = hw_int->next_serial++; + list_insert(&f->node, &flow->node); + list_push_front(&hw_int->iter_flows, &flow->iter_node); + } + } + /* UNLOCK */ + + if (hw_rc < 0) { + DBG_WARN("Could not install flow in HW\n"); + if (sw_insert_done) { /* Remove from SW list */ + DBG_WARN("Removed matching flow but could not replace in HW\n"); + } + return 0; + } + + return 1; +} + +/* FIXME: Change API to return list of deleted flows? */ +/* Would make this easier */ +/* Remove a flow or flows from the HW and SW tracking tables */ +int +of_hw_flow_delete(struct datapath *dp, struct sw_table *sw_tab, + const struct sw_flow_key *key, uint16_t out_port, + uint16_t priority, int strict) +{ + of_hw_driver_int_t *hw_int = (of_hw_driver_int_t *)sw_tab; + struct sw_flow *flow, *n; + int count = 0; + struct list deleted; + + DBG_VERBOSE("delete: dp %p, idx %d, key %p, out 0x%x, prio %d, strict %d\n", + dp, hw_int->dp_idx, key, out_port, priority, strict); + + list_init(&deleted); + + /* LOCK; */ + LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &hw_int->flows) { + if (flow_matches_desc(&flow->key, key, strict) + && flow_has_out_port(flow, out_port) + && (!strict || (flow->priority == priority))) { + TRY_NR(hw_flow_remove(flow), "hw flow remove"); + list_remove(&flow->node); + list_remove(&flow->iter_node); + list_push_back(&deleted, &flow->node); + count++; + } + } + /* UNLOCK; */ + + /* Notify DP of deleted flows */ + LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &deleted) { + dp_send_flow_end(dp, flow, flow->reason); + list_remove(&flow->node); + flow_free(flow); + } + + return count; +} + + +/* + * Modify an existing flow + * + * We chicken out and just de-install/re-install in HW + */ +int +of_hw_flow_modify(struct sw_table *sw_tab, const struct sw_flow_key *key, + uint16_t priority, int strict, + const struct ofp_action_header *actions, size_t actions_len) +{ + of_hw_driver_int_t *hw_int = (of_hw_driver_int_t *)sw_tab; + struct sw_flow *flow; + int count = 0; + hw_flow_extra_t extra; + + memset(&extra, 0, sizeof(extra)); + extra.cosq = -1; +#if defined(PLATFORM_HAS_REMOTES) + extra.new_vid = -1; + extra.new_pcp = -1; +#endif + + if (!actions_supported_check(hw_int, &flow->key, actions, + actions_len, &extra)) { + /* Unsupported actions */ + DBG_VERBOSE("Mod actions-supported failed: Unsupported actions\n"); + return 0; + } + + /* LOCK; */ + LIST_FOR_EACH (flow, struct sw_flow, node, &hw_int->flows) { + if (flow_matches_desc(&flow->key, key, strict) + && (!strict || (flow->priority == priority))) { + /* Change the flow, de-install from HW and re-install */ + TRY_NR(hw_flow_remove(flow), "hw_flow_remove modify"); + flow_replace_acts(flow, actions, actions_len); + TRY_NR(hw_flow_install(hw_int, flow, &extra), + "hw_flow_install modify"); + /* FIXME: Clear stats on flow if updated? */ + count++; + } + } + /* UNLOCK; */ + + return count; +} + +/* + * Update stats + * Call sw tracking table timeout + * Iterate the deleted object list and call HW flow remove + */ +void +of_hw_flow_timeout(struct sw_table *sw_tab, struct list *deleted) +{ + of_hw_driver_int_t *hw_int = (of_hw_driver_int_t *)sw_tab; + struct sw_flow *flow, *n; + int used; + uint64_t now = time_msec(); + + /* LOCK; */ + /* FIXME */ + LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &hw_int->flows) { + if (of_hw_sw_flow_stat_update(flow, &used, false) == 0) { + if (used) { + flow->used = now; + } else { + if (flow_timeout(flow)) { + DBG_VERBOSE("Flow %p expired\n", flow); + list_remove(&flow->node); + list_remove(&flow->iter_node); + list_push_back(deleted, &flow->node); + ASSERT(flow->private != NULL); + TRY_NR(hw_flow_remove(flow), "hw flow remove, timeout"); + hw_int->n_flows--; + } + } + } + } + + /* UNLOCK; */ +} + +struct sw_flow * +of_hw_flow_lookup(struct sw_table *sw_tab, const struct sw_flow_key *key) +{ + of_hw_driver_int_t *hw_int = (of_hw_driver_int_t *)sw_tab; + struct sw_flow *flow; + + LIST_FOR_EACH (flow, struct sw_flow, node, &hw_int->flows) { + if (flow_matches_1wild(key, &flow->key)) + return flow; + } + return NULL; +} + +int +of_hw_flow_stats_get(of_hw_driver_t *hw_drv, struct ofp_match match, + struct ofp_flow_stats **stats, int *count) +{ + DBG_WARN("FIXME FLOW STATS GET\n"); + return 0; +} + +int +of_hw_aggregate_stats_get(struct ofp_match match, + struct ofp_aggregate_stats_reply *stats) +{ + DBG_WARN("FIXME AGGREGATE STATS GET\n"); + return 0; +} + +void +of_hw_flow_remove_all(of_hw_driver_int_t *hw_int) +{ + struct sw_flow *flow, *n; + + /* FIXME: Other de-init? Keep count of DPs? */ + LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &hw_int->flows) { + TRY_NR(hw_flow_remove(flow), "hw_flow_remove all"); + list_remove(&flow->node); + list_remove(&flow->iter_node); + } +} diff --git a/openflow/hw-lib/skeleton/hw_flow.h b/openflow/hw-lib/skeleton/hw_flow.h new file mode 100644 index 00000000..7c801c60 --- /dev/null +++ b/openflow/hw-lib/skeleton/hw_flow.h @@ -0,0 +1,111 @@ +#ifndef SAMPLE_PLATFORM_HW_FLOW_H +#define SAMPLE_PLATFORM_HW_FLOW_H 1 + +/* + * Hardware Flow operations: The glue between software flows and + * actual hardware table entries. + */ + +#include +#include + +#include "of_hw_platform.h" + +/* DEBUG for HW flow lists */ +#define HW_FLOW_MAGIC 0xba5eba11 +#define HW_FLOW_MAKE_VALID(hf) (hf)->magic = HW_FLOW_MAGIC +#define HW_FLOW_IS_VALID(hf) \ + (((hf) != NULL) && ((hf)->magic == HW_FLOW_MAGIC)) + +/* Some flows require multiple HW entries */ +#define HW_FLOWS_PER_FLOW_MAX (2) + +/* The glue between SW flows and HW entries */ +typedef struct hw_flow { + struct sw_flow *flow; /* Corresponding SW flow */ + of_hw_driver_t *hw_drv; /* DP for this flow; MAY BE NULL for internal */ + int entry_count; /* SW flow may require multiple HW table entries */ + entry_control_t *entry_list[HW_FLOWS_PER_FLOW_MAX]; + uint32 hw_packet_count; + uint32 hw_byte_count; + uint32 magic; /* DEBUG */ +} hw_flow_t; + +/* Extra info needed by hardware about flow entry; + * determined during supported check; all in host order + * + * For smac, dmac, vid and priority, if these are changed at ingress + * and a remote rule is necessary, the remote rule must have the + * rewrite values to match. This is indicated if value is not -1. + */ +typedef struct hw_flow_extra_s { + int source_port; /* If single source port, what is it */ + int dest_port; /* If one dest port, what is it */ + /* If multi dest ports, one pbmp per device */ + FIXME dports; + int dest_count; /* Drop (0), unicast (1), multicast (>1) */ + uint32 local_reason; /* Why forwarded to CPU */ + int cosq; /* For enqueue action */ +} hw_flow_extra_t; + +/* Driver functions */ +extern int of_hw_flow_install(struct sw_table *flowtab, struct sw_flow *flow); +extern int of_hw_flow_modify(struct sw_table *flowtab, + const struct sw_flow_key *key, uint16_t priority, int strict, + const struct ofp_action_header *actions, size_t actions_len); +extern int of_hw_flow_delete(struct datapath *dp, struct sw_table *flowtab, + const struct sw_flow_key *key, uint16_t out_port, + uint16_t priority, int strict); +extern void of_hw_flow_timeout(struct sw_table *flowtab, + struct list *deleted); +extern struct sw_flow *of_hw_flow_lookup(struct sw_table *flowtab, + const struct sw_flow_key *key); + + +extern int of_hw_sw_flow_stat_update(struct sw_flow *flow, int *used, + int force_sync); +extern int of_hw_flow_stats_get(of_hw_driver_t *hw_drv, struct ofp_match, + struct ofp_flow_stats **stats, int *count); +extern int of_hw_aggregate_stats_get(struct ofp_match, + struct ofp_aggregate_stats_reply *stats); + +/* Controls a single FP (HW table flow) entry */ +struct entry_control_s { + /* These must be persistent; update fp_entry_remove if you change this */ + int index; /* This entry-s index in field_control list */ + + int in_use; + hw_flow_t *hw_flow; + + /* + * HW specific info + */ + FIXME; + + unsigned long int used_check; /* Last counter; for checking if used */ + unsigned long int last_counter; /* pkts or bytes, see stat_sel above */ + unsigned long int counter_last_check; /* Track entry usage by cntr */ + unsigned long int total_counter; /* FIXME: u64? */ +}; + +/* Driver associated with a HW entry */ +#define HW_ENTRY_DRIVER(ent) ((ent)->hw_flow->hw_drv) + +/* FP control structure */ +struct field_control_s { + /* HW Specific info */ + FIXME; + int entry_count; /* How many entries in use */ + entry_control_t entry_list[FIELD_ENTRY_MAX]; /* Instantiation of entries */ +}; + +/* FIXME: Do we need reference counts on stat objects? */ + +extern int of_hw_fp_setup(void); +extern int of_hw_table_stats_update(of_hw_driver_int_t *hw_drv, + unsigned long *matched, unsigned long *missed); + +extern void of_hw_flow_remove_all(of_hw_driver_int_t *hw_int); + + +#endif /* SAMPLE_PLATFORM_HW_FLOW_H */ diff --git a/openflow/hw-lib/skeleton/of_hw_platform.h b/openflow/hw-lib/skeleton/of_hw_platform.h new file mode 100644 index 00000000..11a3364c --- /dev/null +++ b/openflow/hw-lib/skeleton/of_hw_platform.h @@ -0,0 +1,38 @@ +#ifndef HW_LIB_SKELETON_PLATFORM_H +#define HW_LIB_SKELETON_PLATFORM_H 1 + +#if defined(OF_HW_DP_MAIN) +#define P printf +#else +#define P printf +#endif + +/* + * General Hardware Switch platform defines + * + * Also includes platform specific definitions based on make defines + */ + +#define OF_HW_MAX_PORT 64 + +/* Reasons that a packet is being forwarded to the controller; */ +#define CPU_REASON_DEFAULT (1 << 0) +#define CPU_REASON_TO_CONTROLLER (1 << 1) +#define CPU_REASON_TO_LOCAL (1 << 2) + +#define EXACT_MATCH_PRIORITY TBD + +/**************************************************************** + * + * Platform specific defines and linkage + * + * Implicitly we have a "driver" for the board which includes + * hardware specific information including HW to OF port mapping + * + ****************************************************************/ + +#if defined(OF_SAMPLE_PLAT) +#include "sample_plat.h" +#endif + +#endif /* HW_LIB_SKELETON_PLATFORM_H */ diff --git a/openflow/hw-lib/skeleton/os.h b/openflow/hw-lib/skeleton/os.h new file mode 100644 index 00000000..268daa97 --- /dev/null +++ b/openflow/hw-lib/skeleton/os.h @@ -0,0 +1,29 @@ + +/* + * OS abstractions + */ + +#ifndef OF_HW_OS_H +#define OF_HW_OS_H 1 + +#include + +#define ALLOC(bytes) malloc(bytes) +#define FREE(ptr) free(ptr) + +#define PKT_ALLOC(bytes) TBD +#define PKT_FREE(ptr) TBD + +#define MUTEX_DECLARE(name) TBD +#define MUTEX_INIT(name) TBD +#define MUTEX_LOCK(name) TBD +#define MUTEX_UNLOCK(name) TBD + +#define TIME_NOW(time) TBD +#define TIME_DIFF(diff, early, late) TBD + +/* FIXME */ +#include +#define os_pkt_free(pkt) ofpbuf_delete(pkt) + +#endif /* OF_HW_OS_H */ diff --git a/openflow/hw-lib/skeleton/port.c b/openflow/hw-lib/skeleton/port.c new file mode 100644 index 00000000..7d8c5e3b --- /dev/null +++ b/openflow/hw-lib/skeleton/port.c @@ -0,0 +1,497 @@ +/* + * Port related HW datapath functions + */ + +#include +#include + +#include "xtoxll.h" +#include "hw_drv.h" +#include "of_hw_platform.h" +#include "port.h" +#include "debug.h" + +/* Single set of HW port objects managed here; indexed by OF port num */ +of_hw_port_t of_hw_ports[OF_HW_MAX_PORT]; + +/* Check if hw DP and port are valid and if port belongs to the DP */ +#define CHECK_PORT(_drv, _p) do { \ + if ((_drv) == NULL) return -1; \ + if (((_p) < 1) || ((_p) > OF_HW_MAX_PORT)) { \ + REPORT_ERROR("bad port number"); \ + return -1; \ + } \ + if (!(OF_PORT_IN_DP(((of_hw_driver_int_t *)(_drv)), (_p)))) { \ + REPORT_ERROR("DP does not own port"); \ + return -1; \ + } \ +} while (0) + + +/* + * Queue configuration section + * + * Port queue: Per port structure for queue related information + * Queue map: Indicated queue is mapped and what OF qid its mapped to as + * well as queue properties (min-bw). Indexed by OF port number; + * per port instance of array + * + */ + +typedef struct queue_map_s { + int in_use; + uint32_t qid; /* OF queue name */ + int min_bw; /* OF value, tenths of a percent */ +} queue_map_t; + +typedef struct port_queue_s { + int speed; /* In Mbps */ + queue_map_t queue_map[NUM_COS_QUEUES]; +} port_queue_t; + +static port_queue_t port_queue[OF_HW_MAX_PORT]; + +/* Return the cos for the queue matching qid if found; else -1. + * Assumes lock held + */ +static int +qid_find(int of_port, uint32_t qid) +{ + struct queue_map_s *qm; + int cosq; + + qm = port_queue[of_port].queue_map; + for (cosq = 0; cosq < NUM_COS_QUEUES; cosq++) { + if (qm[cosq].in_use && (qid == qm[cosq].qid)) { + return cosq; + } + } + + return -1; +} + +/* Return the cos for the queue matching qid if found; else -1. + * Assumes lock held + */ +int +of_hw_qid_find(int of_port, uint32_t qid) +{ + int cosq; + + /* LOCK */ + cosq = qid_find(of_port, qid); + /* UNLOCK */ + + return cosq; +} + +/* + * Map an OF qid to a COS queue index; if not present, add it if possible + * Assumes lock held + */ +static int +qid_find_add(int of_port, uint32_t qid) +{ + struct queue_map_s *qm; + int cosq; + + cosq = qid_find(of_port, qid); + if (cosq >= 0) { + return cosq; + } + + /* Not found; add queue */ + for (cosq = 0; cosq < NUM_COS_QUEUES; cosq++) { + qm = port_queue[of_port].queue_map; + if (!qm[cosq].in_use) { + qm[cosq].in_use = true; + qm[cosq].qid = qid; + return cosq; + } + } + + return -1; +} + +/* + * Port speed has changed; requires queue b/w to change + */ +static void +port_speed_change_reconfig(of_hw_driver_int_t *hw_int, int of_port) +{ + int cosq; + struct queue_map_s *qm; + int rv; + + /* LOCK */ + for (cosq = 0; cosq < NUM_COS_QUEUES; cosq++) { + qm = port_queue[of_port].queue_map; + if (qm[cosq].in_use) { + /* FIXME: Calc and program values for HW for min-bw */ + if (rv < 0) { + DBG_ERROR("ERROR: Set min BW for queue on port %d " + "link change\n", of_port); + } + } + } + /* UNLOCK */ +} + + +/* Internal handler for port link status changes */ + +/* FIXME */ +static void +of_hw_linkscan_handler(...) +{ + int of_port; + of_hw_driver_int_t *hw_int; + + /* Assumes speed, linkstatus from HW */ + /* Map port to internal port object */ + of_port = HW_MAP_TO_PORT(); + if ((of_port < 0) || (of_port > OF_HW_MAX_PORT)) { + return; + } + + /* LOCK */ + hw_int = (of_hw_driver_int_t *)(of_hw_ports[of_port].owner); + if (hw_int != NULL) { + if (port_queue[of_port].speed != speed) { + port_queue[of_port].speed = speed; + port_speed_change_reconfig(hw_int, of_port); + } + } + /* Record in local struct */ + of_hw_ports[of_port].link = linkstatus != 0; + if ((hw_int != NULL) && (hw_int->port_change != NULL)) { + hw_int->port_change(of_port, linkstatus != 0, + hw_int->port_change_cookie); + } + /* UNLOCK */ +} + +static int linkscan_registered; + +/* + * of_hw_ports_init + * Set up hardware port map + */ +void +of_hw_ports_init(void) +{ + int i; + + for (i = 0; i < OF_HW_MAX_PORT; i++) { + of_hw_ports[i].owner = NULL; + of_hw_ports[i].port = MAP_OF_PORT_TO_HW_PORT(i); + } + + /* FIXME: REGISTER FOR LINK CHANGE CALLBACK */ + /* Always register linkscan handler */ + linkscan_registered = 1; + + /* Get current link status for each port; ignore errors for bad ports */ + for (i = 0; i < OF_HW_MAX_PORT; i++) { + /* FIXME */ + HW_LINK_STATUS_GET(of_hw_ports[i].port, &of_hw_ports[i].link); + } +} + + +#define HTON64 htonll + +/* Get port stats into a standard openflow port stats structure */ +int +of_hw_port_stats_get(of_hw_driver_t *hw_drv, int of_port, + struct ofp_port_stats *stats) +{ + uint64 v1, v2; + + CHECK_PORT(hw_drv, of_port); + + +#if 0 /* FIXME; Get stats from HW */ + HW_STAT(of_port, snmpIfInNUcastPkts, &v1); + HW_STAT(of_port, snmpIfInUcastPkts, &v2); + v1 += v2; + stats->rx_packets = HTON64(v1); + HW_STAT(of_port, snmpIfOutNUcastPkts, &v1); + HW_STAT(of_port, snmpIfOutUcastPkts, &v2); + v1 += v2; + stats->tx_packets = HTON64(v1); + HW_STAT(of_port, snmpIfInOctets, &v1); + stats->rx_bytes = HTON64(v1); + HW_STAT(of_port, snmpIfOutOctets, &v1); + stats->tx_bytes = HTON64(v1); + HW_STAT(of_port, snmpIfInDiscards, &v1); + stats->rx_dropped = HTON64(v1); + HW_STAT(of_port, snmpIfOutDiscards, &v1); + stats->tx_dropped = HTON64(v1); + HW_STAT(of_port, snmpIfInErrors, &v1); + stats->rx_errors = HTON64(v1); + HW_STAT(of_port, snmpIfOutErrors, &v1); + stats->tx_errors = HTON64(v1); +#endif + + v1 = UINT64_C(0xffffffffffffffff); + stats->rx_frame_err = HTON64(v1); + stats->rx_over_err = HTON64(v1); + stats->rx_crc_err = HTON64(v1); + stats->collisions = HTON64(v1); + + return 0; +} + +/* + * port_add/remove(table, port) + * + * The indicated port has been added to/removed from the datapath + * Add also maps the of_port number to the hw_port indicated + * + * SPEC CHANGE: If of_port passed is less than 0, use the passed + * port name to determine the port number and attach to that value; + * + * Returns the of_port number or -1 on error + */ +int +of_hw_port_add(of_hw_driver_t *hw_drv, int of_port, const char *hw_name) +{ + int hw_idx; + of_hw_port_t *port_ctl; + of_hw_driver_int_t *hw_int; + + if (hw_drv == NULL) { + return -1; + } + + hw_idx = hw_port_name_to_index(hw_name); + if (of_port < 0) { + of_port = hw_idx + 1; + } else if (hw_idx + 1 != of_port) { + DBG_WARN("Add Port: OF port %d does not match name %s\n", + of_port, hw_name); + } + + if (of_port >= OF_HW_MAX_PORT) { + DBG_ERROR("Add Port: Bad port number %d\n", of_port); + return -1; + } + + hw_int = (of_hw_driver_int_t *)hw_drv; + port_ctl = &of_hw_ports[of_port]; + + HW_DRV_LOCK; + if (port_ctl->owner == NULL) { + port_ctl->owner = hw_drv; + /* FIXME: port bitmaps in HW structure */ + } else if (port_ctl->owner != hw_drv) { + DBG_ERROR("Add Port: OF port %d owned by other DP\n", of_port); + } else { + DBG_WARN("Add Port: OF port %d already added\n", of_port); + } + HW_DRV_UNLOCK; + + return of_port; +} + +int +of_hw_port_remove(of_hw_driver_t *hw_drv, of_port_t of_port) +{ + of_hw_port_t *port_ctl; + of_hw_driver_int_t *hw_int; + int rc = 0; + + if (hw_drv == NULL) { + return -1; + } + + if ((of_port < 1) || (of_port >= OF_HW_MAX_PORT)) { + DBG_ERROR("Remove Port: Bad port number %d\n", of_port); + return -1; + } + + hw_int = (of_hw_driver_int_t *)hw_drv; + port_ctl = &of_hw_ports[of_port]; + + HW_DRV_LOCK; + if (port_ctl->owner == NULL) { + DBG_WARN("Remove Port: OF port %d already free\n", of_port); + } else if (port_ctl->owner != hw_drv) { + DBG_ERROR("Remove Port: OF port %d owned by other DP\n", of_port); + rc = -1; + } else { + port_ctl->owner = NULL; + } + /* FIXME UPDATE HW port bitmaps in hw_int */ + HW_DRV_UNLOCK; + + return rc; +} + + +/* + * port_link_get(table, port) + * port_enable_set(table, port, enable) + * port_enable_get(table, port) + * + * Get/set the indicated properties of a port. Only real ports + * set with port_add are supported. + */ +int +of_hw_port_link_get(of_hw_driver_t *hw_drv, int of_port) +{ + int rc; + int link; + + CHECK_PORT(hw_drv, of_port); + + if (linkscan_registered) { + return of_hw_ports[of_port].link; + } + + if ((rc = HW_LINK_GET(of_hw_ports[of_port].port, &link)) < 0) { + DBG_ERROR("link_get: error %d port %d\n", rc, of_port); + /* Return link down on error */ + return 0; + } + + return link ? 1 : 0; +} + +int +of_hw_port_enable_set(of_hw_driver_t *hw_drv, int of_port, int enable) +{ + int rc; + + CHECK_PORT(hw_drv, of_port); + + if ((rc = HW_PORT_ENABLE_SET(of_hw_ports[of_port].port, enable)) < 0) { + DBG_ERROR("of_hw_port_enable_set: error %d port %d\n", + rc, of_port); + return rc; + } + + return 0; +} + +int +of_hw_port_enable_get(of_hw_driver_t *hw_drv, int of_port) +{ + int rc; + int enable; + + CHECK_PORT(hw_drv, of_port); + + if ((rc = HW_PORT_ENABLE_GET(of_hw_ports[of_port].port, &enable)) < 0) { + DBG_ERROR("of_hw_port_enable_get: error %d port %d\n", + rc, of_port); + return rc; + } + + return enable ? 1 : 0; +} + + +/* + * port_change_register + * + * Register a callback function to receive port change notifications + * from ports in this datapath; only one callback per datapath is + * supported. + */ +int +of_hw_port_change_register(of_hw_driver_t *hw_drv, of_port_change_f callback, + void *cookie) +{ + of_hw_driver_int_t *dp_int; + + dp_int = (of_hw_driver_int_t *)hw_drv; + dp_int->port_change = callback; + dp_int->port_change_cookie = cookie; + + return 0; +} + +/* + * Init COS queue setup. The queues number is fixed at 8. Deficit + * round robin is the discipline, initially with all equal weights. + * As queues are configured with min bandwidth reservations, the + * weights are adjusted to ensure the requested targets. + * + * For now, these are device generic; may need to specialize in the + * future. + */ + +int +of_hw_cos_setup(int num_cos) +{ + /* FIXME: Set up COS queues */ + + return 0; +} + +/* + * Add and/or configure an output queue on a port. + * + * If qid exists, update. If not, look for an unreferenced queue and + * set the qid to that value. + * + * Note that when a port state changes, may need to re-configure + * the bandwidth values for the port's queues. + */ + +int +of_hw_port_queue_config(of_hw_driver_t *hw_drv, int of_port, uint32_t qid, + int min_bw) /* In tenths of a percent */ +{ + int min_kbps; + of_hw_driver_int_t *hw_int; + int cosq; + struct queue_map_s *qm; + int rv; + + hw_int = (of_hw_driver_int_t *)hw_drv; + + CHECK_PORT(hw_int, of_port); + + /* LOCK */ + /* Get the current bandwidth of the port (cached?) */ + if ((cosq = qid_find_add(of_port, qid)) < 0) { + DBG_ERROR("Could not add queue: of port %d, qid %d\n", of_port, qid); + /* UNLOCK */ + return -1; + } + qm = &port_queue[of_port].queue_map[qid]; + qm->min_bw = min_bw; + + HW_SET_MIN_BW(...); + /* UNLOCK */ + + return (rv != 0) ? -1 : 0; +} + +/* Remove a queue from a port; this potentially affects the queue + * configuration otherwise we would not worry about it here. + * Return -1 if not found; 0 on success + */ + +int +of_hw_port_queue_remove(of_hw_driver_t *hw_drv, int of_port, uint32_t qid) +{ + int cosq; + + (void)hw_drv; + /* LOCK */ + if ((cosq = qid_find(of_port, qid)) == -1) { + /* UNLOCK */ + return -1; + } + + /* Do we need to update stats or DRR weights or anything? */ + + port_queue[of_port].queue_map[cosq].in_use = false; + + /* UNLOCK */ + return 0; +} diff --git a/openflow/hw-lib/skeleton/port.h b/openflow/hw-lib/skeleton/port.h new file mode 100644 index 00000000..dd2c0828 --- /dev/null +++ b/openflow/hw-lib/skeleton/port.h @@ -0,0 +1,45 @@ +#ifndef OF_HW_PORT_H +#define OF_HW_PORT_H 1 + +#include +#include +#include "of_hw_platform.h" + +#define NUM_COS_QUEUES 8 + +/* Define port mapping object indexed by OF number */ +typedef struct of_hw_port_s { + of_hw_driver_t *owner; /* Owner of this port */ + int port; /* Physical port number on device */ + int link; /* Link state */ + /* TBD: Keep track of link state and don't transmit if down? */ + /* Add other physical info here as needed */ +} of_hw_port_t; + +extern of_hw_port_t of_hw_ports[OF_HW_MAX_PORT]; + +#define FOREACH_DP_PORT(_idx, _drv) \ + for (_idx = 0; _idx < OF_HW_MAX_PORT; _idx++) \ + if (of_hw_ports[_idx].owner == (of_hw_driver_t *)(_drv)) + +extern int of_hw_cos_setup(int num_cos); +extern int of_hw_qid_find(int of_port, uint32_t qid); + +extern void of_hw_ports_init(void); +extern int of_hw_port_stats_get(of_hw_driver_t *hw_drv, int of_port, + struct ofp_port_stats *stats); +extern int of_hw_port_add(of_hw_driver_t *hw_drv, int of_port, + const char *hw_name); +extern int of_hw_port_remove(of_hw_driver_t *hw_drv, of_port_t of_port); +extern int of_hw_port_link_get(of_hw_driver_t *hw_drv, int of_port); +extern int of_hw_port_enable_set(of_hw_driver_t *hw_drv, int of_port, + int enable); +extern int of_hw_port_enable_get(of_hw_driver_t *hw_drv, int of_port); +extern int of_hw_port_queue_config(of_hw_driver_t *hw_drv, int of_port, + uint32_t qid, int min_bw); /* In tenths of a percent */ +extern int of_hw_port_queue_remove(of_hw_driver_t *hw_drv, int of_port, + uint32_t qid); +extern int of_hw_port_change_register(of_hw_driver_t *hw_drv, + of_port_change_f callback, void *cookie); + +#endif /* OF_HW_PORT_H */ diff --git a/openflow/hw-lib/skeleton/sample_plat.c b/openflow/hw-lib/skeleton/sample_plat.c new file mode 100644 index 00000000..17f3747b --- /dev/null +++ b/openflow/hw-lib/skeleton/sample_plat.c @@ -0,0 +1,82 @@ +/* + * sample_plat.c + * + * FIXME: Standard confidential header + * + * $Id: $ + */ + +/* + * Sample hardware initialization functions + */ + +#include "debug.h" +#include "of_hw_platform.h" + +#if defined(SAMPLE_PLAT) + +#include "port.h" + +/* sample_plat_port_setup + * + * Set up linkscan and necessary spanning tree for ports + * Disable VLAN dropping + */ +static int +sample_plat_port_setup(...) +{ + + return 0; +} + +#if defined(OF_HW_DP_MAIN) && defined(SAMPLE_HW_PLAT) + +/* If defined, need to do init here */ + +/* + * sample_plat_pre_init + * + * Turn off everything that might cause problems during init + */ + +static int +sample_plat_pre_init(void) +{ + /* bring system down to known state */ + return 0; +} + +/* + */ +int +sample_plat_init(void) +{ + /* Init system */ + + /* First, clear out everything */ + sample_plat_pre_init(); + + /* ... */ + + sample_plat_port_setup(...); + + return 0; +} + +/* FIXME: Deal with initial FP setup */ + +#else /* Not stand alone init; Other code does init */ + +int +sample_plat_init(void) +{ + DBG_WARN("sample_plat_init\n"); + + TRY(sample_plat_port_setup(...), "sample plat init port setup"); + + return 0; +} + +#endif + +#endif /* SAMPLE_PLAT */ diff --git a/openflow/hw-lib/skeleton/sample_plat.h b/openflow/hw-lib/skeleton/sample_plat.h new file mode 100644 index 00000000..3d88eb01 --- /dev/null +++ b/openflow/hw-lib/skeleton/sample_plat.h @@ -0,0 +1,61 @@ +#ifndef SAMPLE_PLAT_H +#define SAMPLE_PLAT_H 1 + + +#include +#include +#include + +#include + +#define OF_HW_MAX_PORTS 4 + +static inline int +of_port_to_hw_port(int of_port) +{ + return of_port - 1; +} + + +/* Map port to OF port number */ +static inline int +of_hw_port_to_of_port(int port) +{ + if ((port < 0) || (port > 3)) { + return -1; + } + + return port + 1; +} + +#define _IS_DIGIT(c) ((c) >= '0' && (c) <= '9') + +/* Map name to hw port number: N => N-1 + ge0 => 0 where "ge" can be any string and 0 can be any number +*/ + +static inline int +hw_port_name_to_index(const char *name) +{ + + if (_IS_DIGIT(name[0])) { + /* Treat as 1-based, OF number */ + i = strtoul(&name[0], NULL, 10); + return i - 1; + } + + len = strlen(name); + for (idx = 0; idx < len && !_IS_DIGIT(name[idx]); idx++) ; + + if ((idx < len) && _IS_DIGIT(name[idx])) { + i = strtoul(&name[idx], NULL, 10); + return i; + } + + return -1; +} +#undef _IS_DIGIT + + + +#endif /* SAMPLE_PLAT_H */ diff --git a/openflow/hw-lib/skeleton/txrx.c b/openflow/hw-lib/skeleton/txrx.c new file mode 100644 index 00000000..950d839f --- /dev/null +++ b/openflow/hw-lib/skeleton/txrx.c @@ -0,0 +1,129 @@ +/* + * Transmit and receive related functions for hardware platforms + */ + +#include +#include "os.h" +#include "hw_drv.h" +#include "txrx.h" +#include "port.h" +#include "debug.h" +#include "of_hw_platform.h" + +static int pkt_count, failures, prev_success, free_count, error_free; +static void +tx_pkt_callback(...) +{ + of_packet_t *of_pkt = cookie; + + /* os_pkt_free(of_pkt->os_pkt); */ + FREE(of_pkt); + /* ... */ + ++free_count; +} + +/* + * tx_packet_send(table, of_port, pkt, flags) + * + * Send packet to an openflow port. + * + * Proposed flags: + * APPLY_FLOW_TABLE: If set, and if the hardware supports + * it, send the packet through the flow table with the source + * port being the local CPU port. (Would be nice to have + * a flexible source port indicated; could hide in flags...) + * + * Assumes buffer in pkt struct can be used for sending data + * + * + */ +int +of_hw_packet_send(of_hw_driver_t *hw_drv, int of_port, of_packet_t *pkt, + uint32_t flags) +{ + /* FIXME: Code to prepare and send pkt */ + return 0; +} + +/* Callback function registered with HW */ +static int +of_hw_rx(...) +{ + /* Sample RX handler */ + int of_port; + of_hw_driver_int_t *hw_drv; + of_packet_t *of_pkt; + int pkt_len; + + /* map receive port to of_port */ + /* map received packet to of_pkt */ + /* Call callback */ + + of_port = of_hw_port_to_of_port(receive_port); + if (of_port < 0) { + return hw_not_handled; + } + + /* LOCK */ + hw_drv = (of_hw_driver_int_t *)(of_hw_ports[of_port].owner); + if ((hw_drv == NULL) || (hw_drv->rx_handler == NULL)) { + /* UNLOCK */ + return hw_not_handled; + } + + of_pkt = ALLOC(sizeof(of_packet_t)); + if (of_pkt == NULL) { + ++hw_drv->rx_pkt_alloc_failures; + /* UNLOCK */ + return hw_not_handled; + } + pkt_len = pkt->tot_len; + + /* FIXME: FOR NOW, COPY DATA INTO NEW BUFFER; */ + of_pkt->data = ALLOC(pkt_len); + if (of_pkt->data == NULL) { + FREE(of_pkt); + /* UNLOCK */ + return hw_not_handled; + } + + /* Handle VLAN tagging if needed */ + /* Coy pkt data appropriately */ + + /* FIXME: Determine reason (dflt rule or directed) */ + /* FIXME: Return code interpretation? */ + /* OFPR_NO_MATCH, No matching flow. */ + /* OFPR_ACTION Action explicitly output to controller. */ + hw_drv->rx_handler(of_port, of_pkt, 0, hw_drv->rx_cookie); + /* UNLOCK */ + + return hw_handled; +} + +static int rx_registered = 0; + +/* + * packet_receive_register + * + * Register a callback function to receive packets from ports in + * this datapath + */ +int +of_hw_packet_receive_register(of_hw_driver_t *hw_drv, + of_packet_in_f callback, void *cookie) +{ + of_hw_driver_int_t *dp_int; + int rv; + + /* Register for link status changes */ + if (!rx_registered) { + /* Set up low level pkt receive for callback */ + rx_registered = 1; + } + + dp_int = (of_hw_driver_int_t *)hw_drv; + dp_int->rx_handler = callback; + dp_int->rx_cookie = cookie; + + return 0; +} diff --git a/openflow/hw-lib/skeleton/txrx.h b/openflow/hw-lib/skeleton/txrx.h new file mode 100644 index 00000000..1aef9026 --- /dev/null +++ b/openflow/hw-lib/skeleton/txrx.h @@ -0,0 +1,12 @@ +#ifndef OF_HW_TXRX_H +#define OF_HW_TXRX_H 1 + +#include +#include + +extern int of_hw_packet_send(of_hw_driver_t *hw_drv, int of_port, + of_packet_t *pkt, uint32_t flags); +extern int of_hw_packet_receive_register(of_hw_driver_t *hw_drv, + of_packet_in_f callback, void *cookie); + +#endif /* OF_HW_TXRX_H */ diff --git a/openflow/include/.gitignore b/openflow/include/.gitignore new file mode 100644 index 00000000..b336cc7c --- /dev/null +++ b/openflow/include/.gitignore @@ -0,0 +1,2 @@ +/Makefile +/Makefile.in diff --git a/openflow/include/automake.mk b/openflow/include/automake.mk new file mode 100644 index 00000000..581c1085 --- /dev/null +++ b/openflow/include/automake.mk @@ -0,0 +1 @@ +include include/openflow/automake.mk diff --git a/openflow/include/openflow/automake.mk b/openflow/include/openflow/automake.mk new file mode 100644 index 00000000..3c45b082 --- /dev/null +++ b/openflow/include/openflow/automake.mk @@ -0,0 +1,5 @@ +noinst_HEADERS += \ + include/openflow/nicira-ext.h \ + include/openflow/private-ext.h \ + include/openflow/openflow.h \ + include/openflow/openflow-netlink.h diff --git a/openflow/include/openflow/nicira-ext.h b/openflow/include/openflow/nicira-ext.h new file mode 100644 index 00000000..727864a6 --- /dev/null +++ b/openflow/include/openflow/nicira-ext.h @@ -0,0 +1,195 @@ +/* + * Distributed under the terms of the GNU GPL version 2. + * Copyright (c) 2008 Nicira Networks + */ + +#ifndef OPENFLOW_NICIRA_EXT_H +#define OPENFLOW_NICIRA_EXT_H 1 + +#include "openflow/openflow.h" + +#define NICIRA_OUI_STR "002320" + +/* The following vendor extensions, proposed by Nicira Networks, are not yet + * ready for standardization (and may never be), so they are not included in + * openflow.h. */ + +#define NX_VENDOR_ID 0x00002320 + +enum nicira_type { + /* Switch status request. The request body is an ASCII string that + * specifies a prefix of the key names to include in the output; if it is + * the null string, then all key-value pairs are included. */ + NXT_STATUS_REQUEST, + + /* Switch status reply. The reply body is an ASCII string of key-value + * pairs in the form "key=value\n". */ + NXT_STATUS_REPLY, + + /* Configure an action. Most actions do not require configuration + * beyond that supplied in the actual action call. */ + NXT_ACT_SET_CONFIG, + + /* Get configuration of action. */ + NXT_ACT_GET_CONFIG, + + /* Remote command execution. The request body is a sequence of strings + * delimited by null bytes. The first string is a command name. + * Subsequent strings are command arguments. */ + NXT_COMMAND_REQUEST, + + /* Remote command execution reply, sent when the command's execution + * completes. The reply body is struct nx_command_reply. */ + NXT_COMMAND_REPLY, + + /* Configure whether Flow End messages should be sent. */ + NXT_FLOW_END_CONFIG, + + /* Sent by switch when a flow ends. These messages are turned into + * ofp_flow_removed and NetFlow messages in user-space. */ + NXT_FLOW_END +}; + +struct nicira_header { + struct ofp_header header; + uint32_t vendor; /* NX_VENDOR_ID. */ + uint32_t subtype; /* One of NXT_* above. */ +}; +OFP_ASSERT(sizeof(struct nicira_header) == sizeof(struct ofp_vendor_header) + 4); + + +enum nx_snat_command { + NXSC_ADD, + NXSC_DELETE +}; + +/* Configuration for source-NATing */ +struct nx_snat_config { + uint8_t command; /* One of NXSC_*. */ + uint8_t pad[3]; + uint16_t port; /* Physical switch port. */ + uint16_t mac_timeout; /* Time to cache MAC addresses of SNAT'd hosts + in seconds. 0 uses the default value. */ + + /* Range of IP addresses to impersonate. Set both values to the + * same to support a single address. */ + uint32_t ip_addr_start; + uint32_t ip_addr_end; + + /* Range of transport ports that should be used as new source port. A + * value of zero, let's the switch choose.*/ + uint16_t tcp_start; + uint16_t tcp_end; + uint16_t udp_start; + uint16_t udp_end; + + /* MAC address to use for ARP requests for a SNAT IP address that + * comes in on a different interface than 'port'. A value of all + * zeros silently drops those ARP requests. Requests that arrive + * on 'port' get a response with the mac address of the datapath + * device. */ + uint8_t mac_addr[OFP_ETH_ALEN]; + uint8_t pad2[2]; +}; +OFP_ASSERT(sizeof(struct nx_snat_config) == 32); + +/* Action configuration. Not all actions require separate configuration. */ +struct nx_act_config { + struct nicira_header header; + uint16_t type; /* One of OFPAT_* */ + uint8_t pad[2]; + union { + struct nx_snat_config snat[0]; + }; /* Array of action configurations. The number + is inferred from the length field in the + header. */ +}; +OFP_ASSERT(sizeof(struct nx_act_config) == 20); + + +enum nx_action_subtype { + NXAST_SNAT /* Source-NAT */ +}; + +/* Action structure for NXAST_SNAT. */ +struct nx_action_snat { + uint16_t type; /* OFPAT_VENDOR. */ + uint16_t len; /* Length is 8. */ + uint32_t vendor; /* NX_VENDOR_ID. */ + uint16_t subtype; /* NXAST_SNAT. */ + uint16_t port; /* Output port--it must be previously + configured. */ + uint8_t pad[4]; +}; +OFP_ASSERT(sizeof(struct nx_action_snat) == 16); + +/* Header for Nicira-defined actions. */ +struct nx_action_header { + uint16_t type; /* OFPAT_VENDOR. */ + uint16_t len; /* Length is 8. */ + uint32_t vendor; /* NX_VENDOR_ID. */ + uint16_t subtype; /* NXAST_*. */ + uint8_t pad[6]; +}; +OFP_ASSERT(sizeof(struct nx_action_header) == 16); + +/* Status bits for NXT_COMMAND_REPLY. */ +enum { + NXT_STATUS_EXITED = 1 << 31, /* Exited normally. */ + NXT_STATUS_SIGNALED = 1 << 30, /* Exited due to signal. */ + NXT_STATUS_UNKNOWN = 1 << 29, /* Exited for unknown reason. */ + NXT_STATUS_COREDUMP = 1 << 28, /* Exited with core dump. */ + NXT_STATUS_ERROR = 1 << 27, /* Command could not be executed. */ + NXT_STATUS_STARTED = 1 << 26, /* Command was started. */ + NXT_STATUS_EXITSTATUS = 0xff, /* Exit code mask if NXT_STATUS_EXITED. */ + NXT_STATUS_TERMSIG = 0xff, /* Signal number if NXT_STATUS_SIGNALED. */ +}; + +/* NXT_COMMAND_REPLY. */ +struct nx_command_reply { + struct nicira_header nxh; + uint32_t status; /* Status bits defined above. */ + /* Followed by any number of bytes of process output. */ +}; +OFP_ASSERT(sizeof(struct nx_command_reply) == 20); + +enum nx_flow_end_reason { + NXFER_IDLE_TIMEOUT, /* Flow idle time exceeded idle_timeout. */ + NXFER_HARD_TIMEOUT, /* Time exceeded hard_timeout. */ + NXFER_DELETE, /* Flow was removed by delete command. */ + NXFER_EJECT /* Flow was ejected. */ +}; + +struct nx_flow_end_config { + struct nicira_header header; + uint8_t enable; /* Set to 1 to enable Flow End message + generation. 0 to disable. */ + uint8_t pad[3]; +}; +OFP_ASSERT(sizeof(struct nx_flow_end_config) == 20); + +struct nx_flow_end { + struct nicira_header header; + struct ofp_match match; /* Description of fields. */ + uint64_t cookie; /* Opaque controller-issued identifier. */ + + uint16_t priority; /* Priority level of flow entry. */ + uint8_t reason; /* One of NXFER_*. */ + + uint8_t tcp_flags; /* Union of seen TCP flags. */ + uint8_t ip_tos; /* IP TOS value. */ + + uint8_t send_flow_exp; /* Send flow expiry to controller. */ + + uint16_t idle_timeout; /* Idle time before discarding (seconds). */ + + uint64_t init_time; /* Time flow started in milliseconds. */ + uint64_t used_time; /* Time entry was last used in milliseconds. */ + uint64_t end_time; /* Time flow ended in milliseconds. */ + + uint64_t packet_count; + uint64_t byte_count; +}; +OFP_ASSERT(sizeof(struct nx_flow_end) == 112); + +#endif /* openflow/nicira-ext.h */ diff --git a/openflow/include/openflow/of_hw_api.h b/openflow/include/openflow/of_hw_api.h new file mode 100644 index 00000000..2dca1900 --- /dev/null +++ b/openflow/include/openflow/of_hw_api.h @@ -0,0 +1,313 @@ +/* Copyright (c) 2008, 2009, 2010 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#if !defined(OF_HW_API_H) +#define OF_HW_API_H + +/* + * OpenFlow hardware API definition + * + * This header file provides an abstraction of the flow table and + * port operations that can be used to build a driver for hardware + * that implements the OpenFlow protocol. + * + * Currently this driver depends (extends) the sw_table defined + * in the udatapath/table.h file. Hopefully that file will be + * moved up to library status to support kernel and userspace + * implementations. + * + */ + +#include +#include /* For sw_table */ + +/* REQUIRES: + * struct sw_table defined + * TBD: We could remove this restriction; it's mainly so that + * current chain.c operations can work. It also allows + * pointer coersion between the two types. + * + * Eventually, sw_table may be extended to include everything in + * this driver. + * + * pointer to struct datapath + */ + +/**************** basic types ****************/ + +typedef uint32_t of_port_t; +typedef struct of_hw_driver of_hw_driver_t; + +/**************** packet ****************/ + +/* The OpenFlow hardware packet abstraction */ +typedef void *os_pkt_t; /* OS representation of packet */ + +/* Requires monolithic packet data */ +typedef struct of_packet_s { + unsigned char *data; /* Pointer to packet data */ + int length; /* Length in bytes */ + os_pkt_t os_pkt; /* OS specific representation */ +} of_packet_t; + +/* Init an of_packet struct from an ofp_buffer struct */ +#define OF_PKT_INIT(pkt, ofp_buf) do { \ + (pkt)->data = (ofp_buf)->data; \ + (pkt)->length = (ofp_buf)->size; \ + (pkt)->os_pkt = (ofp_buf); \ + } while (0) + +/**************** callback protos ****************/ + +/* packet in callback function prototype */ +typedef int (*of_packet_in_f)(of_port_t port, + of_packet_t *packet, + int reason, + void *cookie); + +typedef void (*of_port_change_f)(of_port_t port, + int state, + void *cookie); + +/**************************************************************** + * + * Hardware Driver + * + ****************************************************************/ + +/* Hardware capabilities structure */ +typedef struct of_hw_driver_caps { + /* Proposed Flags: + * COUNT_PKTS_OR_BYTES Can count either pkts or bytes, not both + * INTERNAL_PRI Support internal priority mapping, and thus + * normal enqueuing action + * LOCAL_CPU_THRU_TABLE Can send packets from the CPU through + * the flow table + */ + uint32_t flags; + + /* Number of fully qualified flows supported (approx) */ + int max_flows; + uint32_t wc_supported; /* Bitmap of OFPFW_* supported wildcards */ + uint32_t actions_supported; /* Bitmap of OFPAT_* supported actions */ + uint32_t ofpc_flags; /* Bitmap of ofp_capabilities flags */ +} of_hw_driver_caps_t; + +enum of_hw_driver_flags { + OF_HW_DRV_COUNT_PKTS_OR_BYTES = 1 << 0, + OF_HW_DRV_INTERNAL_PRI = 1 << 1, + OF_HW_DRV_CPU_PKTS_THRU_TABLE = 1 << 2 +}; + +/**************** Constructor/Destructor ****************/ + +extern of_hw_driver_t *new_of_hw_driver(struct datapath *dp); +extern void delete_of_hw_driver(of_hw_driver_t *hw_drv); + +/* TBD: Add a HW/DP init function? */ + +/**************** HW DataPath Driver Structure ****************/ +/* Extends sw_table */ +struct of_hw_driver { + + /* + * Notes on sw_table inheritance: + * + * See above as well + * + * n_lookup and n_matched are not dynamically updated, but the + * call to table_stats_update should set them + */ + struct sw_table sw_table; + + /* HW datapath capabilities structure */ + of_hw_driver_caps_t caps; + + /* OPTIONAL + * init(table, flags) + * + * Initialize necessary hardware and software to run + * the switching table. Must be called prior to any other calls + * into the table (except maybe some ioctls?). + * + * Proposed flags include: + * BYTES/PACKETS: If COUNT_PKTS_OR_BYTES, which to count by default + * REATTACH: Inidicates HW was running, don't re-initialize HW + * + */ + int (*init)(of_hw_driver_t *hw_drv, uint32_t flags); + + /* + * table_stats_get(table, stats) + * port_stats_get(port, stats) + * flow_stats_get(flow_desc, stats) + * aggregate_stats_get(flow_desc, stats) + * + * Fill out the stats object(s) for this table/port/flow(s)/set of flows + * + * Returns 0 on success. + * + * For all but flow_stats, the routine fills out a pre-allocated + * stats structure. For flow stats, an array of stats is allocated + * by the called routine with *count elements. It must be freed by + * the caller. + * + * (Optional? If count is NULL for flow_stats_get, find a single + * match with exactly the given ofp_match.) + */ + int (*table_stats_get)(of_hw_driver_t *hw_drv, struct + ofp_table_stats *stats); + int (*port_stats_get)(of_hw_driver_t *hw_drv, int of_port, + struct ofp_port_stats *stats); + int (*flow_stats_get)(of_hw_driver_t *hw_drv, struct ofp_match, + struct ofp_flow_stats **stats, int *count); + int (*aggregate_stats_get)(struct ofp_match, + struct ofp_aggregate_stats_reply *stats); + + /* + * port_add/remove(table, port) + * + * The indicated port has been added to/removed from the datapath + * Add also maps the of_port number to the hw_port indicated + */ + int (*port_add)(of_hw_driver_t *hw_drv, int of_port, const char *hw_name); + int (*port_remove)(of_hw_driver_t *hw_drv, of_port_t port); + + /* + * port_link_get(table, port) + * port_enable_set(table, port, enable) + * port_enable_get(table, port) + * + * Get/set the indicated properties of a port. Only real ports + * set with port_add are supported. + */ + int (*port_link_get)(of_hw_driver_t *hw_drv, int of_port); + int (*port_enable_set)(of_hw_driver_t *hw_drv, int of_port, int enable); + int (*port_enable_get)(of_hw_driver_t *hw_drv, int of_port); + + /* + * port_queue_config(drv, port, qid, min-bw) + * port_queue_remove(drv, port, qid) + * + * Port queue control. Config will add the queue if not present + */ + int (*port_queue_config)(of_hw_driver_t *hw_drv, int of_port, + uint32_t qid, int min_bw); + int (*port_queue_remove)(of_hw_driver_t *hw_drv, int of_port, + uint32_t qid); + + /* + * port_change_register + * + * Register a callback function to receive port change notifications + * from ports in this datapath + */ + int (*port_change_register)(of_hw_driver_t *hw_drv, + of_port_change_f callback, void *cookie); + + /* + * packet_send(table, of_port, pkt, flags) + * + * Send packet to an openflow port. + * + * Proposed flags: + * APPLY_FLOW_TABLE: If set, and if the hardware supports + * it, send the packet through the flow table with the source + * port being the local CPU port. (Would be nice to have + * a flexible source port indicated; could hide in flags...) + * + * TBD: Owner of pkt and pkt->data after call; sync/async. + */ + int (*packet_send)(of_hw_driver_t *hw_drv, int of_port, of_packet_t *pkt, + uint32_t flags); + + /* + * packet_receive_register + * + * Register a callback function to receive packets from ports in + * this datapath + * + * TBD: Semantics for owning packets and return codes so indicating. + */ + int (*packet_receive_register)(of_hw_driver_t *hw_drv, + of_packet_in_f callback, void *cookie); + + /* OPTIONAL + * ioctl(table, request, io_param) + * + * Execute an ioctl on the table. A few ioctls are predefined, + * but most will be implementation specific. + * Returns 0 on success or an implementation specific other code. + * + * io_param is an input/output parameter whose value may be + * returned to the caller. + * io_len is the length of io_param in bytes. + * On input, the *io_param pointer may clobbered, so the caller must + * maintain it for deallocation if necessary. + * On output, when used -- which depends on the operation -- + * the *io_param is a pointer to a buffer allocated by the ioctl + * routine, but owned by the calling routine. + * + * Question: Should a full I/O buffer be supported? + * ioctl(table, op, in_buf, in_len, out_buf, out_len); or + * ioctl(table, op, io_buf, io_len); where buf/len set on output. + * + * Proposed operations: + * Set debug level + * Clear port/flow/table stats + * Select packet or byte counter collection + */ + int (*ioctl)(of_hw_driver_t *hw_drv, uint32_t op, void **io_param, + int *io_len); + +}; + +/**************** IOCTL values ****************/ + +enum of_hw_ioctl_e { + OF_HW_IOCTL_TABLE_DEBUG_SET = 1, + OF_HW_IOCTL_PORT_DEBUG_SET = 2, + OF_HW_IOCTL_BYTE_PKT_CNTR_SET = 3 +}; + +/* Values for OF_HW_IOCTL_BYTE_PKT_CNTR_SET */ +#define OF_HW_CNTR_PACKETS 0 +#define OF_HW_CNTR_BYTES 1 + +enum of_hw_error_e { + OF_HW_OKAY = 0, + OF_HW_ERROR = -1, + OF_HW_PORT_DOWN = -2 +}; + +#endif /* OF_HW_API_H */ diff --git a/openflow/include/openflow/openflow-ext.h b/openflow/include/openflow/openflow-ext.h new file mode 100644 index 00000000..581d49a5 --- /dev/null +++ b/openflow/include/openflow/openflow-ext.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2009 The Board of Trustees of The Leland + * Stanford Junior University + */ + +#ifndef OPENFLOW_OPENFLOW_EXT_H +#define OPENFLOW_OPENFLOW_EXT_H 1 + +#include "openflow/openflow.h" + +/* + * The following are vendor extensions from OpenFlow. This is a + * means of allowing the introduction of non-standardized + * proposed code. + * + * Structures in this file are 64-bit aligned in size. + */ + +#define OPENFLOW_VENDOR_ID 0x000026e1 + +enum ofp_extension_commands { /* Queue configuration commands */ + /* Queue Commands */ + OFP_EXT_QUEUE_MODIFY, /* Add and/or modify */ + OFP_EXT_QUEUE_DELETE, /* Remove a queue */ + OFP_EXT_SET_DESC, /* Set ofp_desc_stat->dp_desc */ + + OFP_EXT_COUNT +}; + +struct ofp_extension_header { + struct ofp_header header; + uint32_t vendor; /* OPENFLOW_VENDOR_ID. */ + uint32_t subtype; /* One of ofp_extension_commands */ +}; +OFP_ASSERT(sizeof(struct ofp_extension_header) == 16); + +/**************************************************************** + * + * OpenFlow Queue Configuration Operations + * + ****************************************************************/ + +struct openflow_queue_command_header { + struct ofp_extension_header header; + uint16_t port; /* Port for operations */ + uint8_t pad[6]; /* Align to 64-bits */ + uint8_t body[0]; /* Body of ofp_queue objects for op. */ +}; +OFP_ASSERT(sizeof(struct openflow_queue_command_header) == 24); + +/* NOTE + * Bug number: TBD. + * The definitions for openflow_queue_error_code conflict with + * those for ofp_queue_op_failed_code defined in openflow.h. + * This will be addressed after the release of OpenFlow 1.0. + * The error codes below for openflow_queue_error_code may be + * removed at that time. + */ +/* + * Entries for 'code' in ofp_error_msg with error 'type' + * OFPET_QUEUE_OP_FAILED + */ +enum openflow_queue_error_code { + OFQ_ERR_NONE, /* Success */ + OFQ_ERR_FAIL, /* Unspecified failure */ + OFQ_ERR_NOT_FOUND, /* Queue not found */ + OFQ_ERR_DISCIPLINE, /* Discipline not supported */ + OFQ_ERR_BW_UNAVAIL, /* Bandwidth unavailable */ + OFQ_ERR_QUEUE_UNAVAIL, /* Queue unavailable */ + OFQ_ERR_COUNT /* Last please */ +}; + +#define OPENFLOW_QUEUE_ERROR_STRINGS_DEF { \ + "Success", /* OFQ_ERR_NONE */ \ + "Unspecified failure", /* OFQ_ERR_FAIL */ \ + "Queue not found", /* OFQ_ERR_NOT_FOUND */ \ + "Discipline not supported", /* OFQ_ERR_DISCIPLINE */ \ + "Bandwidth unavailable", /* OFQ_ERR_BW_UNAVAIL */ \ + "Queue unavailable" /* OFQ_ERR_QUEUE_UNAVAIL */ \ +} + +extern char *openflow_queue_error_strings[]; + +struct openflow_ext_set_dp_desc { + struct ofp_extension_header header; + char dp_desc[DESC_STR_LEN]; +}; +OFP_ASSERT(sizeof(struct openflow_ext_set_dp_desc) == 272); + +#define ofq_error_string(rv) (((rv) < OFQ_ERR_COUNT) && ((rv) >= 0) ? \ + openflow_queue_error_strings[rv] : "Unknown error code") + +/**************************************************************** + * + * Unsupported, but potential extended queue properties + * + ****************************************************************/ + +#if 0 + +enum ofp_queue_prop_ext { + OFPQT_EXT_MAX_RATE = OFPQT_MIN + 1, /* maximum rate limit */ + OFPQT_EXT_BUF_ALLOC, /* buffer alloc config */ + OFPQT_EXT_SCHED_WEIGHT /* schedule weight config */ + OFPQT_EXT_COUNT /* Last please */ +}; + +#define OPENFLOW_QUEUE_PROP_STRINGS_DEF { \ + "No property specified" /* OFPQT_NONE */ \ + "Minimum Rate", /* OFPQT_MIN */ \ + "Maximum Rate", /* OFQ_PROP_MAX_RATE */ \ + "Buffer alloc weight", /* OFQ_PROP_BUF_ALLOC */ \ + "Scheduling weight" /* OFQ_PROP_SCHED_WEIGHT */ \ +} +extern char *openflow_queue_prop_strings[]; + +#define ofq_prop_string(val) (((val) < OFPQT_EXT_COUNT) && ((val) >= 0) ? \ + openflow_queue_prop_strings[val] : "Unknown property value") + +/* These are all the same a min-rate queue property description */ +/* Max-Rate queue property description */ +struct ofp_queue_prop_max_rate { + struct ofp_queue_prop_header prop_header; /* prop: OFPQT_MIN, len: 16 */ + uint16_t rate; /* in 1/10 of a percent of port BW */ + uint8_t pad[6]; /* 64-bit alignment */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_prop_max_rate) == 16); + +/* Buffer alloc weight queue property description */ +struct ofp_queue_prop_buf_alloc { + struct ofp_queue_prop_header prop_header; /* prop: OFPQT_MIN, len: 16 */ + uint16_t alloc_val; /* 0 disabled; 1 min; 0xffff max */ + uint8_t pad[6]; /* 64-bit alignment */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_prop_buf_alloc) == 16); + +/* Max-Rate queue property description */ +struct ofp_queue_prop_sched_weight { + struct ofp_queue_prop_header prop_header; /* prop: OFPQT_MIN, len: 16 */ + uint16_t weight; /* discipline specific; 0 disabled; 1 min; 0xffff max */ + uint8_t pad[6]; /* 64-bit alignment */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_prop_sched_weight) == 16); + +#endif + + + +#endif /* OPENFLOW_OPENFLOW_EXT_H */ diff --git a/openflow/include/openflow/openflow-netlink.h b/openflow/include/openflow/openflow-netlink.h new file mode 100644 index 00000000..931e6972 --- /dev/null +++ b/openflow/include/openflow/openflow-netlink.h @@ -0,0 +1,69 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#ifndef OPENFLOW_OPENFLOW_NETLINK_H +#define OPENFLOW_OPENFLOW_NETLINK_H 1 + +#define DP_GENL_FAMILY_NAME "OpenFlow" + +/* Attributes that can be attached to the datapath's netlink messages. */ +enum { + DP_GENL_A_UNSPEC, + DP_GENL_A_DP_IDX, /* Datapath device index. */ + DP_GENL_A_PORTNAME, /* Device name for datapath port. */ + DP_GENL_A_MC_GROUP, /* Generic netlink multicast group. */ + DP_GENL_A_OPENFLOW, /* OpenFlow packet. */ + DP_GENL_A_DP_NAME, /* Datapath device name. */ + + __DP_GENL_A_MAX, + DP_GENL_A_MAX = __DP_GENL_A_MAX - 1 +}; + +/* Commands that can be executed on the datapath's netlink interface. */ +enum dp_genl_command { + DP_GENL_C_UNSPEC, + DP_GENL_C_ADD_DP, /* Create datapath. */ + DP_GENL_C_DEL_DP, /* Destroy datapath. */ + DP_GENL_C_QUERY_DP, /* Get multicast group for datapath. */ + DP_GENL_C_ADD_PORT, /* Add port to datapath. */ + DP_GENL_C_DEL_PORT, /* Remove port from datapath. */ + DP_GENL_C_OPENFLOW, /* Encapsulated OpenFlow protocol. */ + + __DP_GENL_C_MAX, + DP_GENL_C_MAX = __DP_GENL_C_MAX - 1 +}; + +/* Maximum number of datapaths. */ +#define DP_MAX 256 + +#endif /* openflow/openflow-netlink.h */ diff --git a/openflow/include/openflow/openflow.h b/openflow/include/openflow/openflow.h new file mode 100644 index 00000000..c0b5090d --- /dev/null +++ b/openflow/include/openflow/openflow.h @@ -0,0 +1,970 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +/* OpenFlow: protocol between controller and datapath. */ + +#ifndef OPENFLOW_OPENFLOW_H +#define OPENFLOW_OPENFLOW_H 1 + +#ifdef __KERNEL__ +#include +#else +#include +#endif + +#ifdef SWIG +#define OFP_ASSERT(EXPR) /* SWIG can't handle OFP_ASSERT. */ +#elif !defined(__cplusplus) +/* Build-time assertion for use in a declaration context. */ +#define OFP_ASSERT(EXPR) \ + extern int (*build_assert(void))[ sizeof(struct { \ + unsigned int build_assert_failed : (EXPR) ? 1 : -1; })] +#else /* __cplusplus */ +#define OFP_ASSERT(_EXPR) typedef int build_assert_failed[(_EXPR) ? 1 : -1] +#endif /* __cplusplus */ + +#ifndef SWIG +#define OFP_PACKED __attribute__((packed)) +#else +#define OFP_PACKED /* SWIG doesn't understand __attribute. */ +#endif + +/* Version number: + * Non-experimental versions released: 0x01 + * Experimental versions released: 0x81 -- 0x99 + */ +/* The most significant bit being set in the version field indicates an + * experimental OpenFlow version. + */ +#define OFP_VERSION 0x01 + +#define OFP_MAX_TABLE_NAME_LEN 32 +#define OFP_MAX_PORT_NAME_LEN 16 + +#define OFP_TCP_PORT 6633 +#define OFP_SSL_PORT 6633 + +#define OFP_ETH_ALEN 6 /* Bytes in an Ethernet address. */ + +/* Port numbering. Physical ports are numbered starting from 1. */ +enum ofp_port { + /* Maximum number of physical switch ports. */ + OFPP_MAX = 0xff00, + + /* Fake output "ports". */ + OFPP_IN_PORT = 0xfff8, /* Send the packet out the input port. This + virtual port must be explicitly used + in order to send back out of the input + port. */ + OFPP_TABLE = 0xfff9, /* Perform actions in flow table. + NB: This can only be the destination + port for packet-out messages. */ + OFPP_NORMAL = 0xfffa, /* Process with normal L2/L3 switching. */ + OFPP_FLOOD = 0xfffb, /* All physical ports except input port and + those disabled by STP. */ + OFPP_ALL = 0xfffc, /* All physical ports except input port. */ + OFPP_CONTROLLER = 0xfffd, /* Send to controller. */ + OFPP_LOCAL = 0xfffe, /* Local openflow "port". */ + OFPP_NONE = 0xffff /* Not associated with a physical port. */ +}; + +enum ofp_type { + /* Immutable messages. */ + OFPT_HELLO, /* Symmetric message */ + OFPT_ERROR, /* Symmetric message */ + OFPT_ECHO_REQUEST, /* Symmetric message */ + OFPT_ECHO_REPLY, /* Symmetric message */ + OFPT_VENDOR, /* Symmetric message */ + + /* Switch configuration messages. */ + OFPT_FEATURES_REQUEST, /* Controller/switch message */ + OFPT_FEATURES_REPLY, /* Controller/switch message */ + OFPT_GET_CONFIG_REQUEST, /* Controller/switch message */ + OFPT_GET_CONFIG_REPLY, /* Controller/switch message */ + OFPT_SET_CONFIG, /* Controller/switch message */ + + /* Asynchronous messages. */ + OFPT_PACKET_IN, /* Async message */ + OFPT_FLOW_REMOVED, /* Async message */ + OFPT_PORT_STATUS, /* Async message */ + + /* Controller command messages. */ + OFPT_PACKET_OUT, /* Controller/switch message */ + OFPT_FLOW_MOD, /* Controller/switch message */ + OFPT_PORT_MOD, /* Controller/switch message */ + + /* Statistics messages. */ + OFPT_STATS_REQUEST, /* Controller/switch message */ + OFPT_STATS_REPLY, /* Controller/switch message */ + + /* Barrier messages. */ + OFPT_BARRIER_REQUEST, /* Controller/switch message */ + OFPT_BARRIER_REPLY, /* Controller/switch message */ + + /* Queue Configuration messages. */ + OFPT_QUEUE_GET_CONFIG_REQUEST, /* Controller/switch message */ + OFPT_QUEUE_GET_CONFIG_REPLY /* Controller/switch message */ + +}; + +/* Header on all OpenFlow packets. */ +struct ofp_header { + uint8_t version; /* OFP_VERSION. */ + uint8_t type; /* One of the OFPT_ constants. */ + uint16_t length; /* Length including this ofp_header. */ + uint32_t xid; /* Transaction id associated with this packet. + Replies use the same id as was in the request + to facilitate pairing. */ +}; +OFP_ASSERT(sizeof(struct ofp_header) == 8); + +/* OFPT_HELLO. This message has an empty body, but implementations must + * ignore any data included in the body, to allow for future extensions. */ +struct ofp_hello { + struct ofp_header header; +}; + +#define OFP_DEFAULT_MISS_SEND_LEN 128 + +enum ofp_config_flags { + /* Handling of IP fragments. */ + OFPC_FRAG_NORMAL = 0, /* No special handling for fragments. */ + OFPC_FRAG_DROP = 1, /* Drop fragments. */ + OFPC_FRAG_REASM = 2, /* Reassemble (only if OFPC_IP_REASM set). */ + OFPC_FRAG_MASK = 3 +}; + +/* Switch configuration. */ +struct ofp_switch_config { + struct ofp_header header; + uint16_t flags; /* OFPC_* flags. */ + uint16_t miss_send_len; /* Max bytes of new flow that datapath should + send to the controller. */ +}; +OFP_ASSERT(sizeof(struct ofp_switch_config) == 12); + +/* Capabilities supported by the datapath. */ +enum ofp_capabilities { + OFPC_FLOW_STATS = 1 << 0, /* Flow statistics. */ + OFPC_TABLE_STATS = 1 << 1, /* Table statistics. */ + OFPC_PORT_STATS = 1 << 2, /* Port statistics. */ + OFPC_STP = 1 << 3, /* 802.1d spanning tree. */ + OFPC_RESERVED = 1 << 4, /* Reserved, must be zero. */ + OFPC_IP_REASM = 1 << 5, /* Can reassemble IP fragments. */ + OFPC_QUEUE_STATS = 1 << 6, /* Queue statistics. */ + OFPC_ARP_MATCH_IP = 1 << 7 /* Match IP addresses in ARP pkts. */ +}; + +/* Flags to indicate behavior of the physical port. These flags are + * used in ofp_phy_port to describe the current configuration. They are + * used in the ofp_port_mod message to configure the port's behavior. + */ +enum ofp_port_config { + OFPPC_PORT_DOWN = 1 << 0, /* Port is administratively down. */ + + OFPPC_NO_STP = 1 << 1, /* Disable 802.1D spanning tree on port. */ + OFPPC_NO_RECV = 1 << 2, /* Drop all packets except 802.1D spanning + tree packets. */ + OFPPC_NO_RECV_STP = 1 << 3, /* Drop received 802.1D STP packets. */ + OFPPC_NO_FLOOD = 1 << 4, /* Do not include this port when flooding. */ + OFPPC_NO_FWD = 1 << 5, /* Drop packets forwarded to port. */ + OFPPC_NO_PACKET_IN = 1 << 6 /* Do not send packet-in msgs for port. */ +}; + +/* Current state of the physical port. These are not configurable from + * the controller. + */ +enum ofp_port_state { + OFPPS_LINK_DOWN = 1 << 0, /* No physical link present. */ + + /* The OFPPS_STP_* bits have no effect on switch operation. The + * controller must adjust OFPPC_NO_RECV, OFPPC_NO_FWD, and + * OFPPC_NO_PACKET_IN appropriately to fully implement an 802.1D spanning + * tree. */ + OFPPS_STP_LISTEN = 0 << 8, /* Not learning or relaying frames. */ + OFPPS_STP_LEARN = 1 << 8, /* Learning but not relaying frames. */ + OFPPS_STP_FORWARD = 2 << 8, /* Learning and relaying frames. */ + OFPPS_STP_BLOCK = 3 << 8, /* Not part of spanning tree. */ + OFPPS_STP_MASK = 3 << 8 /* Bit mask for OFPPS_STP_* values. */ +}; + +/* Features of physical ports available in a datapath. */ +enum ofp_port_features { + OFPPF_10MB_HD = 1 << 0, /* 10 Mb half-duplex rate support. */ + OFPPF_10MB_FD = 1 << 1, /* 10 Mb full-duplex rate support. */ + OFPPF_100MB_HD = 1 << 2, /* 100 Mb half-duplex rate support. */ + OFPPF_100MB_FD = 1 << 3, /* 100 Mb full-duplex rate support. */ + OFPPF_1GB_HD = 1 << 4, /* 1 Gb half-duplex rate support. */ + OFPPF_1GB_FD = 1 << 5, /* 1 Gb full-duplex rate support. */ + OFPPF_10GB_FD = 1 << 6, /* 10 Gb full-duplex rate support. */ + OFPPF_COPPER = 1 << 7, /* Copper medium. */ + OFPPF_FIBER = 1 << 8, /* Fiber medium. */ + OFPPF_AUTONEG = 1 << 9, /* Auto-negotiation. */ + OFPPF_PAUSE = 1 << 10, /* Pause. */ + OFPPF_PAUSE_ASYM = 1 << 11 /* Asymmetric pause. */ +}; + +/* Description of a physical port */ +struct ofp_phy_port { + uint16_t port_no; + uint8_t hw_addr[OFP_ETH_ALEN]; + char name[OFP_MAX_PORT_NAME_LEN]; /* Null-terminated */ + + uint32_t config; /* Bitmap of OFPPC_* flags. */ + uint32_t state; /* Bitmap of OFPPS_* flags. */ + + /* Bitmaps of OFPPF_* that describe features. All bits zeroed if + * unsupported or unavailable. */ + uint32_t curr; /* Current features. */ + uint32_t advertised; /* Features being advertised by the port. */ + uint32_t supported; /* Features supported by the port. */ + uint32_t peer; /* Features advertised by peer. */ +}; +OFP_ASSERT(sizeof(struct ofp_phy_port) == 48); + +/* Switch features. */ +struct ofp_switch_features { + struct ofp_header header; + uint64_t datapath_id; /* Datapath unique ID. The lower 48-bits are for + a MAC address, while the upper 16-bits are + implementer-defined. */ + + uint32_t n_buffers; /* Max packets buffered at once. */ + + uint8_t n_tables; /* Number of tables supported by datapath. */ + uint8_t pad[3]; /* Align to 64-bits. */ + + /* Features. */ + uint32_t capabilities; /* Bitmap of support "ofp_capabilities". */ + uint32_t actions; /* Bitmap of supported "ofp_action_type"s. */ + + /* Port info.*/ + struct ofp_phy_port ports[0]; /* Port definitions. The number of ports + is inferred from the length field in + the header. */ +}; +OFP_ASSERT(sizeof(struct ofp_switch_features) == 32); + +/* What changed about the physical port */ +enum ofp_port_reason { + OFPPR_ADD, /* The port was added. */ + OFPPR_DELETE, /* The port was removed. */ + OFPPR_MODIFY /* Some attribute of the port has changed. */ +}; + +/* A physical port has changed in the datapath */ +struct ofp_port_status { + struct ofp_header header; + uint8_t reason; /* One of OFPPR_*. */ + uint8_t pad[7]; /* Align to 64-bits. */ + struct ofp_phy_port desc; +}; +OFP_ASSERT(sizeof(struct ofp_port_status) == 64); + +/* Modify behavior of the physical port */ +struct ofp_port_mod { + struct ofp_header header; + uint16_t port_no; + uint8_t hw_addr[OFP_ETH_ALEN]; /* The hardware address is not + configurable. This is used to + sanity-check the request, so it must + be the same as returned in an + ofp_phy_port struct. */ + + uint32_t config; /* Bitmap of OFPPC_* flags. */ + uint32_t mask; /* Bitmap of OFPPC_* flags to be changed. */ + + uint32_t advertise; /* Bitmap of "ofp_port_features"s. Zero all + bits to prevent any action taking place. */ + uint8_t pad[4]; /* Pad to 64-bits. */ +}; +OFP_ASSERT(sizeof(struct ofp_port_mod) == 32); + +/* Why is this packet being sent to the controller? */ +enum ofp_packet_in_reason { + OFPR_NO_MATCH, /* No matching flow. */ + OFPR_ACTION /* Action explicitly output to controller. */ +}; + +/* Packet received on port (datapath -> controller). */ +struct ofp_packet_in { + struct ofp_header header; + uint32_t buffer_id; /* ID assigned by datapath. */ + uint16_t total_len; /* Full length of frame. */ + uint16_t in_port; /* Port on which frame was received. */ + uint8_t reason; /* Reason packet is being sent (one of OFPR_*) */ + uint8_t pad; + uint8_t data[0]; /* Ethernet frame, halfway through 32-bit word, + so the IP header is 32-bit aligned. The + amount of data is inferred from the length + field in the header. Because of padding, + offsetof(struct ofp_packet_in, data) == + sizeof(struct ofp_packet_in) - 2. */ +}; +OFP_ASSERT(sizeof(struct ofp_packet_in) == 20); + +enum ofp_action_type { + OFPAT_OUTPUT, /* Output to switch port. */ + OFPAT_SET_VLAN_VID, /* Set the 802.1q VLAN id. */ + OFPAT_SET_VLAN_PCP, /* Set the 802.1q priority. */ + OFPAT_STRIP_VLAN, /* Strip the 802.1q header. */ + OFPAT_SET_DL_SRC, /* Ethernet source address. */ + OFPAT_SET_DL_DST, /* Ethernet destination address. */ + OFPAT_SET_NW_SRC, /* IP source address. */ + OFPAT_SET_NW_DST, /* IP destination address. */ + OFPAT_SET_NW_TOS, /* IP ToS (DSCP field, 6 bits). */ + OFPAT_SET_TP_SRC, /* TCP/UDP source port. */ + OFPAT_SET_TP_DST, /* TCP/UDP destination port. */ + OFPAT_ENQUEUE, /* Output to queue. */ + OFPAT_VENDOR = 0xffff +}; + +/* Action structure for OFPAT_OUTPUT, which sends packets out 'port'. + * When the 'port' is the OFPP_CONTROLLER, 'max_len' indicates the max + * number of bytes to send. A 'max_len' of zero means no bytes of the + * packet should be sent.*/ +struct ofp_action_output { + uint16_t type; /* OFPAT_OUTPUT. */ + uint16_t len; /* Length is 8. */ + uint16_t port; /* Output port. */ + uint16_t max_len; /* Max length to send to controller. */ +}; +OFP_ASSERT(sizeof(struct ofp_action_output) == 8); + +/* The VLAN id is 12 bits, so we can use the entire 16 bits to indicate + * special conditions. All ones is used to match that no VLAN id was + * set. */ +#define OFP_VLAN_NONE 0xffff + +/* Action structure for OFPAT_SET_VLAN_VID. */ +struct ofp_action_vlan_vid { + uint16_t type; /* OFPAT_SET_VLAN_VID. */ + uint16_t len; /* Length is 8. */ + uint16_t vlan_vid; /* VLAN id. */ + uint8_t pad[2]; +}; +OFP_ASSERT(sizeof(struct ofp_action_vlan_vid) == 8); + +/* Action structure for OFPAT_SET_VLAN_PCP. */ +struct ofp_action_vlan_pcp { + uint16_t type; /* OFPAT_SET_VLAN_PCP. */ + uint16_t len; /* Length is 8. */ + uint8_t vlan_pcp; /* VLAN priority. */ + uint8_t pad[3]; +}; +OFP_ASSERT(sizeof(struct ofp_action_vlan_pcp) == 8); + +/* Action structure for OFPAT_SET_DL_SRC/DST. */ +struct ofp_action_dl_addr { + uint16_t type; /* OFPAT_SET_DL_SRC/DST. */ + uint16_t len; /* Length is 16. */ + uint8_t dl_addr[OFP_ETH_ALEN]; /* Ethernet address. */ + uint8_t pad[6]; +}; +OFP_ASSERT(sizeof(struct ofp_action_dl_addr) == 16); + +/* Action structure for OFPAT_SET_NW_SRC/DST. */ +struct ofp_action_nw_addr { + uint16_t type; /* OFPAT_SET_TW_SRC/DST. */ + uint16_t len; /* Length is 8. */ + uint32_t nw_addr; /* IP address. */ +}; +OFP_ASSERT(sizeof(struct ofp_action_nw_addr) == 8); + +/* Action structure for OFPAT_SET_TP_SRC/DST. */ +struct ofp_action_tp_port { + uint16_t type; /* OFPAT_SET_TP_SRC/DST. */ + uint16_t len; /* Length is 8. */ + uint16_t tp_port; /* TCP/UDP port. */ + uint8_t pad[2]; +}; +OFP_ASSERT(sizeof(struct ofp_action_tp_port) == 8); + +/* Action structure for OFPAT_SET_NW_TOS. */ +struct ofp_action_nw_tos { + uint16_t type; /* OFPAT_SET_TW_SRC/DST. */ + uint16_t len; /* Length is 8. */ + uint8_t nw_tos; /* IP ToS (DSCP field, 6 bits). */ + uint8_t pad[3]; +}; +OFP_ASSERT(sizeof(struct ofp_action_nw_tos) == 8); + +/* Action header for OFPAT_VENDOR. The rest of the body is vendor-defined. */ +struct ofp_action_vendor_header { + uint16_t type; /* OFPAT_VENDOR. */ + uint16_t len; /* Length is a multiple of 8. */ + uint32_t vendor; /* Vendor ID, which takes the same form + as in "struct ofp_vendor_header". */ +}; +OFP_ASSERT(sizeof(struct ofp_action_vendor_header) == 8); + +/* Action header that is common to all actions. The length includes the + * header and any padding used to make the action 64-bit aligned. + * NB: The length of an action *must* always be a multiple of eight. */ +struct ofp_action_header { + uint16_t type; /* One of OFPAT_*. */ + uint16_t len; /* Length of action, including this + header. This is the length of action, + including any padding to make it + 64-bit aligned. */ + uint8_t pad[4]; +}; +OFP_ASSERT(sizeof(struct ofp_action_header) == 8); + +/* Send packet (controller -> datapath). */ +struct ofp_packet_out { + struct ofp_header header; + uint32_t buffer_id; /* ID assigned by datapath (-1 if none). */ + uint16_t in_port; /* Packet's input port (OFPP_NONE if none). */ + uint16_t actions_len; /* Size of action array in bytes. */ + struct ofp_action_header actions[0]; /* Actions. */ + /* uint8_t data[0]; */ /* Packet data. The length is inferred + from the length field in the header. + (Only meaningful if buffer_id == -1.) */ +}; +OFP_ASSERT(sizeof(struct ofp_packet_out) == 16); + +enum ofp_flow_mod_command { + OFPFC_ADD, /* New flow. */ + OFPFC_MODIFY, /* Modify all matching flows. */ + OFPFC_MODIFY_STRICT, /* Modify entry strictly matching wildcards */ + OFPFC_DELETE, /* Delete all matching flows. */ + OFPFC_DELETE_STRICT /* Strictly match wildcards and priority. */ +}; + +/* Flow wildcards. */ +enum ofp_flow_wildcards { + OFPFW_IN_PORT = 1 << 0, /* Switch input port. */ + OFPFW_DL_VLAN = 1 << 1, /* VLAN id. */ + OFPFW_DL_SRC = 1 << 2, /* Ethernet source address. */ + OFPFW_DL_DST = 1 << 3, /* Ethernet destination address. */ + OFPFW_DL_TYPE = 1 << 4, /* Ethernet frame type. */ + OFPFW_NW_PROTO = 1 << 5, /* IP protocol. */ + OFPFW_TP_SRC = 1 << 6, /* TCP/UDP source port. */ + OFPFW_TP_DST = 1 << 7, /* TCP/UDP destination port. */ + + /* IP source address wildcard bit count. 0 is exact match, 1 ignores the + * LSB, 2 ignores the 2 least-significant bits, ..., 32 and higher wildcard + * the entire field. This is the *opposite* of the usual convention where + * e.g. /24 indicates that 8 bits (not 24 bits) are wildcarded. */ + OFPFW_NW_SRC_SHIFT = 8, + OFPFW_NW_SRC_BITS = 6, + OFPFW_NW_SRC_MASK = ((1 << OFPFW_NW_SRC_BITS) - 1) << OFPFW_NW_SRC_SHIFT, + OFPFW_NW_SRC_ALL = 32 << OFPFW_NW_SRC_SHIFT, + + /* IP destination address wildcard bit count. Same format as source. */ + OFPFW_NW_DST_SHIFT = 14, + OFPFW_NW_DST_BITS = 6, + OFPFW_NW_DST_MASK = ((1 << OFPFW_NW_DST_BITS) - 1) << OFPFW_NW_DST_SHIFT, + OFPFW_NW_DST_ALL = 32 << OFPFW_NW_DST_SHIFT, + + OFPFW_DL_VLAN_PCP = 1 << 20, /* VLAN priority. */ + OFPFW_NW_TOS = 1 << 21, /* IP ToS (DSCP field, 6 bits). */ + + /* Wildcard all fields. */ + OFPFW_ALL = ((1 << 22) - 1) +}; + +/* The wildcards for ICMP type and code fields use the transport source + * and destination port fields, respectively. */ +#define OFPFW_ICMP_TYPE OFPFW_TP_SRC +#define OFPFW_ICMP_CODE OFPFW_TP_DST + +/* Values below this cutoff are 802.3 packets and the two bytes + * following MAC addresses are used as a frame length. Otherwise, the + * two bytes are used as the Ethernet type. + */ +#define OFP_DL_TYPE_ETH2_CUTOFF 0x0600 + +/* Value of dl_type to indicate that the frame does not include an + * Ethernet type. + */ +#define OFP_DL_TYPE_NOT_ETH_TYPE 0x05ff + +/* The VLAN id is 12-bits, so we can use the entire 16 bits to indicate + * special conditions. All ones indicates that no VLAN id was set. + */ +#define OFP_VLAN_NONE 0xffff + +/* Fields to match against flows */ +struct ofp_match { + uint32_t wildcards; /* Wildcard fields. */ + uint16_t in_port; /* Input switch port. */ + uint8_t dl_src[OFP_ETH_ALEN]; /* Ethernet source address. */ + uint8_t dl_dst[OFP_ETH_ALEN]; /* Ethernet destination address. */ + uint16_t dl_vlan; /* Input VLAN id. */ + uint8_t dl_vlan_pcp; /* Input VLAN priority. */ + uint8_t pad1[1]; /* Align to 64-bits */ + uint16_t dl_type; /* Ethernet frame type. */ + uint8_t nw_tos; /* IP ToS (actually DSCP field, 6 bits). */ + uint8_t nw_proto; /* IP protocol or lower 8 bits of + * ARP opcode. */ + uint8_t pad2[2]; /* Align to 64-bits */ + uint32_t nw_src; /* IP source address. */ + uint32_t nw_dst; /* IP destination address. */ + uint16_t tp_src; /* TCP/UDP source port. */ + uint16_t tp_dst; /* TCP/UDP destination port. */ +}; +OFP_ASSERT(sizeof(struct ofp_match) == 40); + +/* The match fields for ICMP type and code use the transport source and + * destination port fields, respectively. */ +#define icmp_type tp_src +#define icmp_code tp_dst + +/* Value used in "idle_timeout" and "hard_timeout" to indicate that the entry + * is permanent. */ +#define OFP_FLOW_PERMANENT 0 + +/* By default, choose a priority in the middle. */ +#define OFP_DEFAULT_PRIORITY 0x8000 + +enum ofp_flow_mod_flags { + OFPFF_SEND_FLOW_REM = 1 << 0, /* Send flow removed message when flow + * expires or is deleted. */ + OFPFF_CHECK_OVERLAP = 1 << 1, /* Check for overlapping entries first. */ + OFPFF_EMERG = 1 << 2 /* Remark this is for emergency. */ +}; + +/* Flow setup and teardown (controller -> datapath). */ +struct ofp_flow_mod { + struct ofp_header header; + struct ofp_match match; /* Fields to match */ + uint64_t cookie; /* Opaque controller-issued identifier. */ + + /* Flow actions. */ + uint16_t command; /* One of OFPFC_*. */ + uint16_t idle_timeout; /* Idle time before discarding (seconds). */ + uint16_t hard_timeout; /* Max time before discarding (seconds). */ + uint16_t priority; /* Priority level of flow entry. */ + uint32_t buffer_id; /* Buffered packet to apply to (or -1). + Not meaningful for OFPFC_DELETE*. */ + uint16_t out_port; /* For OFPFC_DELETE* commands, require + matching entries to include this as an + output port. A value of OFPP_NONE + indicates no restriction. */ + uint16_t flags; /* One of OFPFF_*. */ + struct ofp_action_header actions[0]; /* The action length is inferred + from the length field in the + header. */ +}; +OFP_ASSERT(sizeof(struct ofp_flow_mod) == 72); + +/* Why was this flow removed? */ +enum ofp_flow_removed_reason { + OFPRR_IDLE_TIMEOUT, /* Flow idle time exceeded idle_timeout. */ + OFPRR_HARD_TIMEOUT, /* Time exceeded hard_timeout. */ + OFPRR_DELETE /* Evicted by a DELETE flow mod. */ +}; + +/* Flow removed (datapath -> controller). */ +struct ofp_flow_removed { + struct ofp_header header; + struct ofp_match match; /* Description of fields. */ + uint64_t cookie; /* Opaque controller-issued identifier. */ + + uint16_t priority; /* Priority level of flow entry. */ + uint8_t reason; /* One of OFPRR_*. */ + uint8_t pad[1]; /* Align to 32-bits. */ + + uint32_t duration_sec; /* Time flow was alive in seconds. */ + uint32_t duration_nsec; /* Time flow was alive in nanoseconds beyond + duration_sec. */ + uint16_t idle_timeout; /* Idle timeout from original flow mod. */ + uint8_t pad2[2]; /* Align to 64-bits. */ + uint64_t packet_count; + uint64_t byte_count; +}; +OFP_ASSERT(sizeof(struct ofp_flow_removed) == 88); + +/* Values for 'type' in ofp_error_message. These values are immutable: they + * will not change in future versions of the protocol (although new values may + * be added). */ +enum ofp_error_type { + OFPET_HELLO_FAILED, /* Hello protocol failed. */ + OFPET_BAD_REQUEST, /* Request was not understood. */ + OFPET_BAD_ACTION, /* Error in action description. */ + OFPET_FLOW_MOD_FAILED, /* Problem modifying flow entry. */ + OFPET_PORT_MOD_FAILED, /* Port mod request failed. */ + OFPET_QUEUE_OP_FAILED /* Queue operation failed. */ +}; + +/* ofp_error_msg 'code' values for OFPET_HELLO_FAILED. 'data' contains an + * ASCII text string that may give failure details. */ +enum ofp_hello_failed_code { + OFPHFC_INCOMPATIBLE, /* No compatible version. */ + OFPHFC_EPERM /* Permissions error. */ +}; + +/* ofp_error_msg 'code' values for OFPET_BAD_REQUEST. 'data' contains at least + * the first 64 bytes of the failed request. */ +enum ofp_bad_request_code { + OFPBRC_BAD_VERSION, /* ofp_header.version not supported. */ + OFPBRC_BAD_TYPE, /* ofp_header.type not supported. */ + OFPBRC_BAD_STAT, /* ofp_stats_request.type not supported. */ + OFPBRC_BAD_VENDOR, /* Vendor not supported (in ofp_vendor_header + * or ofp_stats_request or ofp_stats_reply). */ + OFPBRC_BAD_SUBTYPE, /* Vendor subtype not supported. */ + OFPBRC_EPERM, /* Permissions error. */ + OFPBRC_BAD_LEN, /* Wrong request length for type. */ + OFPBRC_BUFFER_EMPTY, /* Specified buffer has already been used. */ + OFPBRC_BUFFER_UNKNOWN /* Specified buffer does not exist. */ +}; + +/* ofp_error_msg 'code' values for OFPET_BAD_ACTION. 'data' contains at least + * the first 64 bytes of the failed request. */ +enum ofp_bad_action_code { + OFPBAC_BAD_TYPE, /* Unknown action type. */ + OFPBAC_BAD_LEN, /* Length problem in actions. */ + OFPBAC_BAD_VENDOR, /* Unknown vendor id specified. */ + OFPBAC_BAD_VENDOR_TYPE, /* Unknown action type for vendor id. */ + OFPBAC_BAD_OUT_PORT, /* Problem validating output action. */ + OFPBAC_BAD_ARGUMENT, /* Bad action argument. */ + OFPBAC_EPERM, /* Permissions error. */ + OFPBAC_TOO_MANY, /* Can't handle this many actions. */ + OFPBAC_BAD_QUEUE /* Problem validating output queue. */ +}; + +/* ofp_error_msg 'code' values for OFPET_FLOW_MOD_FAILED. 'data' contains + * at least the first 64 bytes of the failed request. */ +enum ofp_flow_mod_failed_code { + OFPFMFC_ALL_TABLES_FULL, /* Flow not added because of full tables. */ + OFPFMFC_OVERLAP, /* Attempted to add overlapping flow with + * CHECK_OVERLAP flag set. */ + OFPFMFC_EPERM, /* Permissions error. */ + OFPFMFC_BAD_EMERG_TIMEOUT, /* Flow not added because of non-zero idle/hard + * timeout. */ + OFPFMFC_BAD_COMMAND, /* Unknown command. */ + OFPFMFC_UNSUPPORTED /* Unsupported action list - cannot process in + * the order specified. */ +}; + +/* ofp_error_msg 'code' values for OFPET_PORT_MOD_FAILED. 'data' contains + * at least the first 64 bytes of the failed request. */ +enum ofp_port_mod_failed_code { + OFPPMFC_BAD_PORT, /* Specified port does not exist. */ + OFPPMFC_BAD_HW_ADDR, /* Specified hardware address is wrong. */ +}; + +/* ofp_error msg 'code' values for OFPET_QUEUE_OP_FAILED. 'data' contains + * at least the first 64 bytes of the failed request */ +enum ofp_queue_op_failed_code { + OFPQOFC_BAD_PORT, /* Invalid port (or port does not exist). */ + OFPQOFC_BAD_QUEUE, /* Queue does not exist. */ + OFPQOFC_EPERM /* Permissions error. */ +}; + +/* OFPT_ERROR: Error message (datapath -> controller). */ +struct ofp_error_msg { + struct ofp_header header; + + uint16_t type; + uint16_t code; + uint8_t data[0]; /* Variable-length data. Interpreted based + on the type and code. */ +}; +OFP_ASSERT(sizeof(struct ofp_error_msg) == 12); + +enum ofp_stats_types { + /* Description of this OpenFlow switch. + * The request body is empty. + * The reply body is struct ofp_desc_stats. */ + OFPST_DESC, + + /* Individual flow statistics. + * The request body is struct ofp_flow_stats_request. + * The reply body is an array of struct ofp_flow_stats. */ + OFPST_FLOW, + + /* Aggregate flow statistics. + * The request body is struct ofp_aggregate_stats_request. + * The reply body is struct ofp_aggregate_stats_reply. */ + OFPST_AGGREGATE, + + /* Flow table statistics. + * The request body is empty. + * The reply body is an array of struct ofp_table_stats. */ + OFPST_TABLE, + + /* Physical port statistics. + * The request body is struct ofp_port_stats_request. + * The reply body is an array of struct ofp_port_stats. */ + OFPST_PORT, + + /* Queue statistics for a port + * The request body defines the port + * The reply body is an array of struct ofp_queue_stats */ + OFPST_QUEUE, + + /* Vendor extension. + * The request and reply bodies begin with a 32-bit vendor ID, which takes + * the same form as in "struct ofp_vendor_header". The request and reply + * bodies are otherwise vendor-defined. */ + OFPST_VENDOR = 0xffff +}; + +struct ofp_stats_request { + struct ofp_header header; + uint16_t type; /* One of the OFPST_* constants. */ + uint16_t flags; /* OFPSF_REQ_* flags (none yet defined). */ + uint8_t body[0]; /* Body of the request. */ +}; +OFP_ASSERT(sizeof(struct ofp_stats_request) == 12); + +enum ofp_stats_reply_flags { + OFPSF_REPLY_MORE = 1 << 0 /* More replies to follow. */ +}; + +struct ofp_stats_reply { + struct ofp_header header; + uint16_t type; /* One of the OFPST_* constants. */ + uint16_t flags; /* OFPSF_REPLY_* flags. */ + uint8_t body[0]; /* Body of the reply. */ +}; +OFP_ASSERT(sizeof(struct ofp_stats_reply) == 12); + +#define DESC_STR_LEN 256 +#define SERIAL_NUM_LEN 32 +/* Body of reply to OFPST_DESC request. Each entry is a NULL-terminated + * ASCII string. */ +struct ofp_desc_stats { + char mfr_desc[DESC_STR_LEN]; /* Manufacturer description. */ + char hw_desc[DESC_STR_LEN]; /* Hardware description. */ + char sw_desc[DESC_STR_LEN]; /* Software description. */ + char serial_num[SERIAL_NUM_LEN]; /* Serial number. */ + char dp_desc[DESC_STR_LEN]; /* Human readable description of datapath. */ +}; +OFP_ASSERT(sizeof(struct ofp_desc_stats) == 1056); + +/* Body for ofp_stats_request of type OFPST_FLOW. */ +struct ofp_flow_stats_request { + struct ofp_match match; /* Fields to match. */ + uint8_t table_id; /* ID of table to read (from ofp_table_stats), + 0xff for all tables or 0xfe for emergency. */ + uint8_t pad; /* Align to 32 bits. */ + uint16_t out_port; /* Require matching entries to include this + as an output port. A value of OFPP_NONE + indicates no restriction. */ +}; +OFP_ASSERT(sizeof(struct ofp_flow_stats_request) == 44); + +/* Body of reply to OFPST_FLOW request. */ +struct ofp_flow_stats { + uint16_t length; /* Length of this entry. */ + uint8_t table_id; /* ID of table flow came from. */ + uint8_t pad; + struct ofp_match match; /* Description of fields. */ + uint32_t duration_sec; /* Time flow has been alive in seconds. */ + uint32_t duration_nsec; /* Time flow has been alive in nanoseconds beyond + duration_sec. */ + uint16_t priority; /* Priority of the entry. Only meaningful + when this is not an exact-match entry. */ + uint16_t idle_timeout; /* Number of seconds idle before expiration. */ + uint16_t hard_timeout; /* Number of seconds before expiration. */ + uint8_t pad2[6]; /* Align to 64-bits. */ + uint64_t cookie; /* Opaque controller-issued identifier. */ + uint64_t packet_count; /* Number of packets in flow. */ + uint64_t byte_count; /* Number of bytes in flow. */ + struct ofp_action_header actions[0]; /* Actions. */ +}; +OFP_ASSERT(sizeof(struct ofp_flow_stats) == 88); + +/* Body for ofp_stats_request of type OFPST_AGGREGATE. */ +struct ofp_aggregate_stats_request { + struct ofp_match match; /* Fields to match. */ + uint8_t table_id; /* ID of table to read (from ofp_table_stats) + 0xff for all tables or 0xfe for emergency. */ + uint8_t pad; /* Align to 32 bits. */ + uint16_t out_port; /* Require matching entries to include this + as an output port. A value of OFPP_NONE + indicates no restriction. */ +}; +OFP_ASSERT(sizeof(struct ofp_aggregate_stats_request) == 44); + +/* Body of reply to OFPST_AGGREGATE request. */ +struct ofp_aggregate_stats_reply { + uint64_t packet_count; /* Number of packets in flows. */ + uint64_t byte_count; /* Number of bytes in flows. */ + uint32_t flow_count; /* Number of flows. */ + uint8_t pad[4]; /* Align to 64 bits. */ +}; +OFP_ASSERT(sizeof(struct ofp_aggregate_stats_reply) == 24); + +/* Body of reply to OFPST_TABLE request. */ +struct ofp_table_stats { + uint8_t table_id; /* Identifier of table. Lower numbered tables + are consulted first. */ + uint8_t pad[3]; /* Align to 32-bits. */ + char name[OFP_MAX_TABLE_NAME_LEN]; + uint32_t wildcards; /* Bitmap of OFPFW_* wildcards that are + supported by the table. */ + uint32_t max_entries; /* Max number of entries supported. */ + uint32_t active_count; /* Number of active entries. */ + uint64_t lookup_count; /* Number of packets looked up in table. */ + uint64_t matched_count; /* Number of packets that hit table. */ +}; +OFP_ASSERT(sizeof(struct ofp_table_stats) == 64); + +/* Body for ofp_stats_request of type OFPST_PORT. */ +struct ofp_port_stats_request { + uint16_t port_no; /* OFPST_PORT message must request statistics + * either for a single port (specified in + * port_no) or for all ports (if port_no == + * OFPP_NONE). */ + uint8_t pad[6]; +}; +OFP_ASSERT(sizeof(struct ofp_port_stats_request) == 8); + +/* Body of reply to OFPST_PORT request. If a counter is unsupported, set + * the field to all ones. */ +struct ofp_port_stats { + uint16_t port_no; + uint8_t pad[6]; /* Align to 64-bits. */ + uint64_t rx_packets; /* Number of received packets. */ + uint64_t tx_packets; /* Number of transmitted packets. */ + uint64_t rx_bytes; /* Number of received bytes. */ + uint64_t tx_bytes; /* Number of transmitted bytes. */ + uint64_t rx_dropped; /* Number of packets dropped by RX. */ + uint64_t tx_dropped; /* Number of packets dropped by TX. */ + uint64_t rx_errors; /* Number of receive errors. This is a super-set + of more specific receive errors and should be + greater than or equal to the sum of all + rx_*_err values. */ + uint64_t tx_errors; /* Number of transmit errors. This is a super-set + of more specific transmit errors and should be + greater than or equal to the sum of all + tx_*_err values (none currently defined.) */ + uint64_t rx_frame_err; /* Number of frame alignment errors. */ + uint64_t rx_over_err; /* Number of packets with RX overrun. */ + uint64_t rx_crc_err; /* Number of CRC errors. */ + uint64_t collisions; /* Number of collisions. */ +}; +OFP_ASSERT(sizeof(struct ofp_port_stats) == 104); + +/* Vendor extension. */ +struct ofp_vendor_header { + struct ofp_header header; /* Type OFPT_VENDOR. */ + uint32_t vendor; /* Vendor ID: + * - MSB 0: low-order bytes are IEEE OUI. + * - MSB != 0: defined by OpenFlow + * consortium. */ + /* Vendor-defined arbitrary additional data. */ +}; +OFP_ASSERT(sizeof(struct ofp_vendor_header) == 12); + +/* All ones is used to indicate all queues in a port (for stats retrieval). */ +#define OFPQ_ALL 0xffffffff + +/* Min rate > 1000 means not configured. */ +#define OFPQ_MIN_RATE_UNCFG 0xffff + +enum ofp_queue_properties { + OFPQT_NONE = 0, /* No property defined for queue (default). */ + OFPQT_MIN_RATE, /* Minimum datarate guaranteed. */ + /* Other types should be added here + * (i.e. max rate, precedence, etc). */ +}; + +/* Common description for a queue. */ +struct ofp_queue_prop_header { + uint16_t property; /* One of OFPQT_. */ + uint16_t len; /* Length of property, including this header. */ + uint8_t pad[4]; /* 64-bit alignemnt. */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_prop_header) == 8); + +/* Min-Rate queue property description. */ +struct ofp_queue_prop_min_rate { + struct ofp_queue_prop_header prop_header; /* prop: OFPQT_MIN, len: 16. */ + uint16_t rate; /* In 1/10 of a percent; >1000 -> disabled. */ + uint8_t pad[6]; /* 64-bit alignment */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_prop_min_rate) == 16); + +/* Full description for a queue. */ +struct ofp_packet_queue { + uint32_t queue_id; /* id for the specific queue. */ + uint16_t len; /* Length in bytes of this queue desc. */ + uint8_t pad[2]; /* 64-bit alignment. */ + struct ofp_queue_prop_header properties[0]; /* List of properties. */ +}; +OFP_ASSERT(sizeof(struct ofp_packet_queue) == 8); + +/* Query for port queue configuration. */ +struct ofp_queue_get_config_request { + struct ofp_header header; + uint16_t port; /* Port to be queried. Should refer + to a valid physical port (i.e. < OFPP_MAX) */ + uint8_t pad[2]; /* 32-bit alignment. */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_get_config_request) == 12); + +/* Queue configuration for a given port. */ +struct ofp_queue_get_config_reply { + struct ofp_header header; + uint16_t port; + uint8_t pad[6]; + struct ofp_packet_queue queues[0]; /* List of configured queues. */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_get_config_reply) == 16); + +/* OFPAT_ENQUEUE action struct: send packets to given queue on port. */ +struct ofp_action_enqueue { + uint16_t type; /* OFPAT_ENQUEUE. */ + uint16_t len; /* Len is 16. */ + uint16_t port; /* Port that queue belongs. Should + refer to a valid physical port + (i.e. < OFPP_MAX) or OFPP_IN_PORT. */ + uint8_t pad[6]; /* Pad for 64-bit alignment. */ + uint32_t queue_id; /* Where to enqueue the packets. */ +}; +OFP_ASSERT(sizeof(struct ofp_action_enqueue) == 16); + +struct ofp_queue_stats_request { + uint16_t port_no; /* All ports if OFPT_ALL. */ + uint8_t pad[2]; /* Align to 32-bits. */ + uint32_t queue_id; /* All queues if OFPQ_ALL. */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_stats_request) == 8); + +struct ofp_queue_stats { + uint16_t port_no; + uint8_t pad[2]; /* Align to 32-bits. */ + uint32_t queue_id; /* Queue i.d */ + uint64_t tx_bytes; /* Number of transmitted bytes. */ + uint64_t tx_packets; /* Number of transmitted packets. */ + uint64_t tx_errors; /* Number of packets dropped due to overrun. */ +}; +OFP_ASSERT(sizeof(struct ofp_queue_stats) == 32); + +#endif /* openflow/openflow.h */ diff --git a/openflow/include/openflow/private-ext.h b/openflow/include/openflow/private-ext.h new file mode 100644 index 00000000..61fc8fb0 --- /dev/null +++ b/openflow/include/openflow/private-ext.h @@ -0,0 +1,68 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#ifndef OPENFLOW_PRIVATE_EXT_H_ +#define OPENFLOW_PRIVATE_EXT_H_ + +#ifdef __KERNEL__ +#include +#endif + +#include "openflow/openflow.h" + +/* + * The following PRIVATE vendor extensions are just sample and may never be + * ready for standardization, so they are not included in openflow.h. + * + * As a sample, we use private OUI (AC-DE-48) for PRIVATE vendor ID. + */ + +#define PRIVATE_VENDOR_ID 0x00acde48 +#define PRIVATEOPT_PROTOCOL_STATS_REQUEST 0x0001 +#define PRIVATEOPT_PROTOCOL_STATS_REPLY 0x0002 +#define PRIVATEOPT_EMERG_FLOW_PROTECTION 0x0003 +#define PRIVATEOPT_EMERG_FLOW_RESTORATION 0x0004 + +struct private_vxhdr { + struct ofp_header ofp_hdr; /* protocol header */ + uint32_t ofp_vxid; /* vendor extenion ID */ +} __attribute__ ((__packed__)); + +/* TLV encoding */ +struct private_vxopt { + uint16_t pvo_type; /* type of vendor extension option */ + uint16_t pvo_len; /* length of value (octet) */ + /* followed by value */ + /* uint8_t pvo_value[0]; */ +} __attribute__ ((__packed__)); + +#endif diff --git a/openflow/m4/libopenflow.m4 b/openflow/m4/libopenflow.m4 new file mode 100644 index 00000000..58014ed5 --- /dev/null +++ b/openflow/m4/libopenflow.m4 @@ -0,0 +1,168 @@ +# -*- autoconf -*- + +# Copyright (c) 2008 The Board of Trustees of The Leland Stanford +# Junior University +# +# We are making the OpenFlow specification and associated documentation +# (Software) available for public use and benefit with the expectation +# that others will use, modify and enhance the Software and contribute +# those enhancements back to the community. However, since we would +# like to make the Software available for broadest use, with as few +# restrictions as possible permission is hereby granted, free of +# charge, to any person obtaining a copy of this Software to deal in +# the Software under the copyrights without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# The name and trademarks of copyright holder(s) may NOT be used in +# advertising or publicity pertaining to the Software or any +# derivatives without specific, written prior permission. + +dnl Checks for --enable-ndebug and defines NDEBUG if it is specified. +AC_DEFUN([OFP_CHECK_NDEBUG], + [AC_ARG_ENABLE( + [ndebug], + [AC_HELP_STRING([--enable-ndebug], + [Disable debugging features for max performance])], + [case "${enableval}" in + (yes) ndebug=true ;; + (no) ndebug=false ;; + (*) AC_MSG_ERROR([bad value ${enableval} for --enable-ndebug]) ;; + esac], + [ndebug=false]) + AM_CONDITIONAL([NDEBUG], [test x$ndebug = xtrue])]) + +dnl Checks for Netlink support. +AC_DEFUN([OFP_CHECK_NETLINK], + [AC_CHECK_HEADER([linux/netlink.h], + [HAVE_NETLINK=yes], + [HAVE_NETLINK=no], + [#include + #include + ]) + AM_CONDITIONAL([HAVE_NETLINK], [test "$HAVE_NETLINK" = yes]) + if test "$HAVE_NETLINK" = yes; then + AC_DEFINE([HAVE_NETLINK], [1], + [Define to 1 if Netlink protocol is available.]) + fi]) + +dnl Checks for OpenSSL, if --enable-ssl is passed in. +AC_DEFUN([OFP_CHECK_OPENSSL], + [AC_ARG_ENABLE( + [ssl], + [AC_HELP_STRING([--enable-ssl], + [Enable ssl support (requires libssl)])], + [case "${enableval}" in + (yes) ssl=true ;; + (no) ssl=false ;; + (*) AC_MSG_ERROR([bad value ${enableval} for --enable-ssl]) ;; + esac], + [ssl=false]) + + if test "$ssl" = true; then + dnl Make sure that pkg-config is installed. + m4_pattern_forbid([PKG_CHECK_MODULES]) + PKG_CHECK_MODULES([SSL], [libssl], + [HAVE_OPENSSL=yes], + [HAVE_OPENSSL=no + AC_MSG_WARN([Cannot find libssl: + + $SSL_PKG_ERRORS + + OpenFlow will not support SSL connections.])]) + + fi + AM_CONDITIONAL([HAVE_OPENSSL], [test "$HAVE_OPENSSL" = yes]) + if test "$HAVE_OPENSSL" = yes; then + AC_DEFINE([HAVE_OPENSSL], [1], [Define to 1 if OpenSSL is installed.]) + fi]) + +dnl Checks for libraries needed by lib/fault.c. +AC_DEFUN([OFP_CHECK_FAULT_LIBS], + [AC_CHECK_LIB([dl], [dladdr], [FAULT_LIBS=-ldl]) + AC_SUBST([FAULT_LIBS])]) + +dnl Checks for libraries needed by lib/socket-util.c. +AC_DEFUN([OFP_CHECK_SOCKET_LIBS], + [AC_CHECK_LIB([socket], [connect]) + AC_SEARCH_LIBS([gethostbyname], [resolv], [RESOLVER_LIBS=-lresolv])]) + +dnl Checks for the directory in which to store the PKI. +AC_DEFUN([OFP_CHECK_PKIDIR], + [AC_ARG_WITH( + [pkidir], + AC_HELP_STRING([--with-pkidir=DIR], + [PKI hierarchy directory [[DATADIR/openflow/pki]]]), + [PKIDIR=$withval], + [PKIDIR='${pkgdatadir}/pki']) + AC_SUBST([PKIDIR])]) + +dnl Checks for the directory in which to store pidfiles. +AC_DEFUN([OFP_CHECK_RUNDIR], + [AC_ARG_WITH( + [rundir], + AC_HELP_STRING([--with-rundir=DIR], + [directory used for pidfiles [[LOCALSTATEDIR/run]]]), + [RUNDIR=$withval], + [RUNDIR='${localstatedir}/run']) + AC_SUBST([RUNDIR])]) + +dnl Checks for the directory in which to store logs. +AC_DEFUN([OFP_CHECK_LOGDIR], + [AC_ARG_WITH( + [logdir], + AC_HELP_STRING([--with-logdir=DIR], + [directory used for logs [[LOCALSTATEDIR/log/PACKAGE]]]), + [LOGDIR=$withval], + [LOGDIR='${localstatedir}/log/${PACKAGE}']) + AC_SUBST([LOGDIR])]) + +dnl Checks for __malloc_hook, etc., supported by glibc. +AC_DEFUN([OFP_CHECK_MALLOC_HOOKS], + [AC_CACHE_CHECK( + [whether libc supports hooks for malloc and related functions], + [ofp_cv_malloc_hooks], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [#include + ], + [(void) __malloc_hook; + (void) __realloc_hook; + (void) __free_hook;])], + [ofp_cv_malloc_hooks=yes], + [ofp_cv_malloc_hooks=no])]) + if test $ofp_cv_malloc_hooks = yes; then + AC_DEFINE([HAVE_MALLOC_HOOKS], [1], + [Define to 1 if you have __malloc_hook, __realloc_hook, and + __free_hook in .]) + fi]) + +dnl Runs the checks required to include the headers in include/ and +dnl link against lib/libopenflow.a. +AC_DEFUN([OFP_CHECK_LIBOPENFLOW], + [AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS]) + AC_REQUIRE([OFP_CHECK_NDEBUG]) + AC_REQUIRE([OFP_CHECK_NETLINK]) + AC_REQUIRE([OFP_CHECK_OPENSSL]) + AC_REQUIRE([OFP_CHECK_FAULT_LIBS]) + AC_REQUIRE([OFP_CHECK_SOCKET_LIBS]) + AC_REQUIRE([OFP_CHECK_PKIDIR]) + AC_REQUIRE([OFP_CHECK_RUNDIR]) + AC_REQUIRE([OFP_CHECK_LOGDIR]) + AC_REQUIRE([OFP_CHECK_MALLOC_HOOKS]) + AC_CHECK_FUNCS([strlcpy])]) + diff --git a/openflow/m4/nx-build.m4 b/openflow/m4/nx-build.m4 new file mode 100644 index 00000000..d681cecc --- /dev/null +++ b/openflow/m4/nx-build.m4 @@ -0,0 +1,71 @@ +# -*- autoconf -*- + +# Copyright (c) 2008 The Board of Trustees of The Leland Stanford +# Junior University +# +# We are making the OpenFlow specification and associated documentation +# (Software) available for public use and benefit with the expectation +# that others will use, modify and enhance the Software and contribute +# those enhancements back to the community. However, since we would +# like to make the Software available for broadest use, with as few +# restrictions as possible permission is hereby granted, free of +# charge, to any person obtaining a copy of this Software to deal in +# the Software under the copyrights without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# The name and trademarks of copyright holder(s) may NOT be used in +# advertising or publicity pertaining to the Software or any +# derivatives without specific, written prior permission. + +dnl NX_BUILDNR +dnl +dnl If --with-build-number=NUMBER is used, substitutes a Makefile +dnl variable BUILDNR with NUMBER, and sets a C preprocessor variable +dnl BUILDNR to "+buildNUMBER". +dnl +dnl Otherwise, if --with-build-number is not used, substitutes BUILDNR +dnl with 0 and sets C preprocessor variable BUILDNR to "". +AC_DEFUN([NX_BUILDNR], + [AC_ARG_WITH( + [build-number], + [AS_HELP_STRING([--with-build-number=NUMBER], + [Official build number (default is none)])]) + AC_MSG_CHECKING([build number]) + case $with_build_number in # ( + [[0-9]] | \ + [[0-9]][[0-9]] | \ + [[0-9]][[0-9]][[0-9]] | \ + [[0-9]][[0-9]][[0-9]][[0-9]] | \ + [[0-9]][[0-9]][[0-9]][[0-9]][[0-9]]) + BUILDNR=$with_build_number + buildnr='"+build'$BUILDNR'"' + AC_MSG_RESULT([$with_build_number]) + ;; # ( + ''|no) + BUILDNR=0 + buildnr='""' + AC_MSG_RESULT([none]) + ;; # ( + *) + AC_MSG_ERROR([invalid build number $with_build_number]) + ;; + esac + AC_SUBST([BUILDNR]) + AC_DEFINE_UNQUOTED([BUILDNR], [$buildnr], + [Official build number as a VERSION suffix string, e.g. "+build123", + or "" if this is not an official build.])]) diff --git a/openflow/regress/CREDITS b/openflow/regress/CREDITS new file mode 100644 index 00000000..987380af --- /dev/null +++ b/openflow/regress/CREDITS @@ -0,0 +1,22 @@ +Credit goes to those who contributed code to the regression suite. Unless +otherwise noted, the contributors are at Stanford University. + + +Test writers/editors: + Clay Collier + David Erickson + Mikio Hara (NEC) + Brandon Heller + Peyman Kazemian + Masayoshi Kobayashi (NEC) + Bob Lantz + Brandon Nefcy + Rob Sherwood (Deutsche Telekom R&D Labs) + Jean Tourrilhes (HP Labs) + Tatsuya Yabe (NEC) + Yiannis Yiakoumis + +Supporting libraries: + Adam Covington + Glen Gibb + Jad Naous diff --git a/openflow/regress/INSTALL b/openflow/regress/INSTALL new file mode 100644 index 00000000..4ddad72f --- /dev/null +++ b/openflow/regress/INSTALL @@ -0,0 +1,264 @@ + Installation Instructions for OpenFlow Reference Tests + +This document describes how to install and execute the OpenFlow reference test +suite, which provides an automated way to verify that an OpenFlow switch +adheres to the OpenFlow Protocol. Out of the box, tests work with the OpenFlow +Reference Linux Switch, but can support other platforms by defining custom +setup and teardown scripts. Additional tests verify the reference learning +Ethernet switch controller included with the OpenFlow Reference Linux Switch. + +Please send any comments to: + + + +=== Prerequisites === + +The tests require no other packets to be sent on the testing interfaces. +Built-in programs like avahi-daemon and/or network-manager may send packets, +causing the tests to report failure. The simplest way to remove these packets +is to disable the ipv6 module and reboot, as well as remove avahi-daemon. + +All test configurations require the following Perl modules: + perl-Convert-Binary-C + perl-Data-HexDump + perl-Net-Pcap (perl-Net-Pcap-0.16-1) + perl-Net-RawIP.i386 (perl-Net-RawIP-0.23-1) + perl-Error.noarch (perl-Error-0.17012-1) + +These packages can be installed from source via www.cpan.org, or you can use +pre-built packages (much faster!). + +The code has been tested on CentOS 5.1/5.2, Ubuntu Hardy Heron, and Debian +Unstable under the following configurations. + +** Config 1 - Four virtual Ethernet loopback pairs + +To set these up, you must have a kernel version >= 2.6.24 and the veth kernel +module compiled. + +To set up link pairs, you must also have iproute installed. + +Scripts to simplify this are included in bin/: +-bin/veth_setup.pl +-bin/veth_teardown.pl + +Before running any veth tests, make sure to run bin/veth_setup.pl, which will +create interfaces veth{0..7}. The usual ports of eth{1..8} are remapped to these +ports via the file veth.map in /bin/. To remove these interfaces, run +bin/veth_teardown.pl + +** Config 2 - Two quad-port Ethernet NICs connected by physical loopback cables + +Assign ports as eth{1..8} and connect cables as: + eth1 to eth5 + eth2 to eth6 + eth3 to eth7 + eth4 to eth8 + +** Config 3 - Four local ethernet ports connected to external switch + +A third configuration is to use four ports of Ethernet on the test machine, +connected to an external switch. To do this, you must provide custom setup +and teardown scripts that enable/disable OpenFlow on the external switch via +SSH, telnet, or SNMP. See the scripts in bin/ for examples of how to create +these. + +** Config 4 - One quad-port Ethernet NIC connected to a NetFPGA + +This testing configuration is used to verify the NetFPGA's OpenFlow +functionality. It requires 4 ports of Ethernet connected to corresponding ports +on the NetFPGA in the following arrangement: + eth1 to nf2c0 + eth2 to nf2c1 + eth3 to nf2c2 + eth4 to nf2c3 + +This test also assumes that you have correctly installed the NetFPGA ahead of +time. For further information about the NetFPGA please see +http://www.netfpga.org/ + +Of particular note, by default installing the NetFPGA also puts the +NF2/lib/Perl5 directory into your PERL5LIB environment variable, this must be +removed else the tests will fail. Ensure that your PERL5LIB only contains the +path set by the env_vars file that will be discussed later in this document. + + +=== Ubuntu Quickstart === + +Follow these instructions to quickly create a VM or physical machine with +OpenFlow that runs the tests. + +Ubuntu is recommended because it is based on Debian sources and has a recent +kernel version - which removes the need for some steps. + +If installing as a VM, you'll need to install VMWare Server (Windows/Linux, +free) or VMWare Fusion (Mac, $$$). + +Download the Ubuntu 8.04 Desktop or Server ISO, and install Ubuntu. + +If you prefer, install VMWare Tools to enable better mouse and display support. +Alternately, install SSH and use it for the rest of the instructions: + sudo apt-get install ssh +Install GCC, which is required for OpenFlow: + sudo apt-get install gcc +Download and untar OpenFlow v0.8.1 + wget http://openflowswitch.org/downloads/openflow-v0.8.1.tar.gz + tar xzf openflow-v0.8.1.tar.gz +Build OpenFlow user-space and kernel-space switches: + cd openflow-v0.8.1 + ./configure --with-l26=/lib/modules/`uname -r` + make + sudo make install +Now, download and untar the OpenFlow Test Suite: + wget http://openflowswitch.org/downloads/openflow-test-v0.8.1-r2.tar.gz +Install required packages for the test suite: + sudo apt-get install liberror-perl libio-interface-perl liblist-moreutils-perl libpcap0.8-dev +Download the following: + wget http://search.cpan.org/CPAN/authors/id/S/SA/SAPER/Net-Pcap-0.14.tar.gz + wget http://search.cpan.org/CPAN/authors/id/S/SZ/SZABGAB/Net-RawIP-0.21.tar.gz + wget http://search.cpan.org/CPAN/authors/id/M/MH/MHX/Convert-Binary-C-0.71.tar.gz + wget http://search.cpan.org/CPAN/authors/id/F/FT/FTASSIN/Data-HexDump-0.02.tar.gz +For each package: + tar xzf + cd + perl Makefile.PL + make + make install +Remove avahi-daemon, which often causes tests to fail by sending out messages: + sudo apt-get remove avahi-daemon +Create a root password, to be used later: + sudo passwd root + +From here, skip to the Running The Tests section below. + + +=== CentOS 5.2 === + +First, download and verify you can build the current version of OpenFlow. + +Install the RPMForge repository: + wget http://dag.wieers.com/rpm/packages/rpmforge-release/rpmforge-release-0.3.6-1.el5.rf.i386.rpm + rpm -Uhv rpmforge-release-0.3.6-1.el5.rf.i386.rpm + +Install Perl packages: + yum -y install perl-Convert-Binary-C perl-Data-HexDump perl-Net-Pcap perl-Net-RawIP.i386 perl-Error.noarch + +To run tests with Veth pairs, you'll need to upgrade to a newer version of the kernel. + +Install iproute: + yum -y install iproute + +From here, skip to the Running The Tests section below. + +=== Debian Install === + +These instructions derive from http://netfpga.org/netfpgawiki/index.php/Ubuntu_Compatibility + +Some instructions may no longer be necessary. + +*The version of libnet-pcap-perl that Debian and Ubuntu 6.06/7.04/7.10 provides is ANCIENT (version 0.04). The latest stable version is 0.14. No newer version is available as a package, so we must build it ourselves. +*The version of libpcap that Debian and Ubuntu 7.04 provides by default is old (version 0.72). The latest stable version is 0.9.8. Fortunately, the package manager has a newer version called "libpcap0.8" that is really version 0.9.5 +*Remove old packages / install new ones + +May not be necessary: + apt-get remove libpcap0.7 libpcap0.7-dev libpcap-dev libnet-pcap-perl + +Will be necessary: + apt-get install liberror-perl libio-interface-perl liblist-moreutils-perl libpcap0.8 libpcap0.8-dev psmisc +Listed individually: + apt-get install liberror-perl + apt-get install libio-interface-perl (Used to manually build a newer version of Net::PCap) + apt-get install liblist-moreutils-perl (Used to manually build a newer version of Net::RawIP) + apt-get install libpcap0.8 + apt-get install libpcap0.8-dev + apt-get install psmisc (Used to get killall) + +Required packages have Debian versions at packages.debian.org, however these packages may not be the newest, or not exist at all. libnet-rawip-perl and libnet-pacp-perl may work, but have not been tested. We'll manually install these two packages: +http://search.cpan.org/~saper/Net-Pcap-0.14/Pcap.pm +http://search.cpan.org/~szabgab/Net-RawIP-0.21/lib/Net/RawIP.pm +http://search.cpan.org/dist/Convert-Binary-C/lib/Convert/Binary/C.pm +http://search.cpan.org/dist/Data-HexDump/lib/Data/HexDump.pm + +Download the following: + wget http://search.cpan.org/CPAN/authors/id/S/SA/SAPER/Net-Pcap-0.14.tar.gz + wget http://search.cpan.org/CPAN/authors/id/S/SZ/SZABGAB/Net-RawIP-0.21.tar.gz + wget http://search.cpan.org/CPAN/authors/id/M/MH/MHX/Convert-Binary-C-0.71.tar.gz + wget http://search.cpan.org/CPAN/authors/id/F/FT/FTASSIN/Data-HexDump-0.02.tar.gz +For each package: + tar xzf + cd + perl Makefile.PL + make + make install + +Install if you want to use veth pairs: + apt-get install iproute + +=== Running the Tests === + +In the sections below, {platform} refers to: +user +user_veth +kmod +kmod_veth +nf2 + +First copy the env_vars file to your home directory: + cd ~/ + cp /regress/scripts/env_vars . + +Update the OF_ROOT (openflow) environment variable to point to your OpenFlow +directory in your setup. These exports can also be added to your ~/.bashrc +file to load automatically: + vim env_vars + +Enter a root shell session, or set up sudo. The perl-Net-RawIP library requires +root access to bind to ports. + su + +Source the environment variables: + source env_vars + +For a setup with virtual ethernet pairs, set them up: + veth_setup.pl + +Verify your setup by running regression tests on your platform of choice: + of_{platform}_test.pl +For the user-space switch, the tests should show pass for all scripts except +the _X_controller ones. For the kernel-space switch, all tests should pass. + +To see more options for the regression script, type: + of_{platform}_test.pl --help + +== Writing Your Own Tests == + +Look at an example controller test: + vim /regress/projects/learning_switch/regress/test_unicast_unknown/run.pl + +Look at an example black box switch test: + vim /regress/projects/black_box/regress/test_hello/run.pl + +To run an individual test (learning switch example): + cd /regres/projects/learning_switch/regress/test_unicast_unknown + of_{platform}_setup.pl; ./run.pl; of_{platform}_teardown.pl + +To see traffic when running a black box test, use tcpdump. Secchan and the +Perl code use the loopback interface to communicate, and you can snoop on this: + tcpdump -X -i lo -s 256 + +It can be convenient to run your test in isolation, without setup and teardown +automatically called. To set up the OF kmod and interfaces, run: + of_{platform}_setup.pl + +To remove the OF kmod cleanly, run: + of_{platform}_teardown.pl +Note that the kmod refuses removal until the interfaces and datapaths have been removed. + +== Reporting Bugs == + +Please report problems to: +openflow-discuss@openflowswitch.org + +or post them directly to our bug tracking system: + +http://www.openflowswitch.org/bugs/openflow diff --git a/openflow/regress/LICENSE b/openflow/regress/LICENSE new file mode 100644 index 00000000..b9e21768 --- /dev/null +++ b/openflow/regress/LICENSE @@ -0,0 +1,30 @@ +Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior +University + + +We are making the OpenFlow tests and associated documentation (Software) +available for public use and benefit with the expectation that others will +use, modify and enhance the Software and contribute those enhancements back +to the community. However, since we would like to make the Software +available for broadest use, with as few restrictions as possible permission +is hereby granted, free of charge, to any person obtaining a copy of this +Software) to deal in the Software under the copyrights without restriction, +including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +The name and trademarks of copyright holder(s) may NOT be used in +advertising or publicity pertaining to the Software or any derivatives +without specific, written prior permission. diff --git a/openflow/regress/README b/openflow/regress/README new file mode 100644 index 00000000..a27967fb --- /dev/null +++ b/openflow/regress/README @@ -0,0 +1,329 @@ + OpenFlow Reference Tests + +What's here? +------------ + +This distribution includes: + + - 55+ "black box" tests to verify that an OF switch conforms to the + OF protocol 0x01 + + - 7 tests to verify that the reference controller acts as a learning + Ethernet switch + +The tests are intended to simplify the process of creating an OF switch +that conforms to spec. + +Please see INSTALL for instruction on installing and running the tests. + +Changelog +--------------- +1.0.0-r1 + - Added Open vSwitch scripts : kernel + user + interface maps + - Added VETH scripts for Open vSwitch : kernel + user + - Updated HP-ProCurve scipts : 5400/3500 and 6600 + - Assorted fixes to libraries : + accept port > 10 + accept vlan interfaces + more explicit error messages + - Assorted fixes to tests : + test_switch_config/ -> add delay + test_forward_broadcast_exact_port/ -> run for allports + test_set_n_match_nw_tos/ -> fixup nw_tos usage + test_set_nw_dst/ -> cleanup + test_failover_startup/ -> argv parsing was broken + - Add new test : test_set_dl_nw_flip -> flip dl & nw addresses + - Add new command line options : no_vlan, no_slicing and no_barrier, + no_emerg + - Add ability to run a single test with --testPath + - New debugging function : dpctl_show_flows + +1.0.0 + - all tests updated to OpenFlow wire protocol 0x01 + - added tests for new features in the OpenFlow 1.0.0 spec + +0.9.0 + - all tests updated to OpenFlow wire protocol 0x98 + +v0.8.2 + - Added support for the NetFPGA + - Integrated the tests into the OpenFlow directory structure + +v0.8.1-r2 + - refactored code to make new test ports easier + - fixed documentation bug in test_LLC + - changed all interfaces IPs to 192.168.20X.X to not conflict with the + IP addrs typically assigned via DHCP by home routers + - added easy support for testing user-space switch with physical ports + - added easy support for user-space switch with virtual ports + +v0.8.1-r1 + - added instructions for Debian install + - fixed timing bug in packet_out + +v0.8.1-r0 + - all tests updated to OF spec v0.8.1 + - added black box test switch_config + - fixed timing dependence in learning switch tests + +v0.2.1 + - initial release for OF spec v0.5.1, code tested for ref OF code v0.2.1 + +Platform support +---------------- + +The code is written in Perl5, and should in theory work on any system. +It has been tested with CentOS 5.4, Ubuntu 9.10, Fedora Core 12, and Debian Unstable. + +Learning Switch Tests +---------------- + +Two tests currently fail with OF Reference v0.8.1: + +-Unicast, send to self: the switch is forwarding packets with source and destination on the same port to that port instead of dropping it. + +-Unicast, hub connected:the switch is forwarding traffic to the same port it has came out of, although the source and destination are on the same port and switch already knows about that. + +Both failing tests can be re-activated by changing +projects/learning_switch/regress/tests.txt + +=== Unicast, unknown dest === +:; Name: test_unicast_unknown +:; Owner: Peyman +:; Description +::send packet out p0 to unknown MAC addr +::verify unmodified packet received at p1..p3 +::verify counters incremented + +=== Unicast, known dest === +:; Name: test_unicast_known +:; Owner: Peyman +:; Description: Send to known unicast address, verify switch sent to only one port +::send out p0 to p1 +::verify received at p1..p3 +::send out p1 to p0 +::verify received at p0, NOT p2, p3 +::send out p2 to p0 +::verify received at p0, NOT p1, p3 +::send out p3 to p0 +::verify received at p0, NOT p1, p2 +::verify counters + +=== Broadcast === +:; Name: test_broadcast +:; Owner: Peyman +:; Description: Send to broadcast address, verify received on all ports +::send out p0 to all +::verify received at p1..p3 +::send out p0 to all, again +::verify received at p1..p3, again +::repeat for each port +::verify counters + +=== Unicast, send to self === +:; Name: test_unicast_self +:; Owner: Peyman +:; Description: Send to self, verify dropped + +=== Unicast, change attachment point === +:; Name: test_unicast_move +:; Owner: Peyman +:; Description: Send normal unicast, but then change attachment point (one MAC sent from multiple ports), verify that new location is used +::send form host A at p0 to p1 +::verify received at p1..p3 +::send from p1 to host A +::verify received at p0, NOT p1, p2, p3 +::(original p0 has now moves to p2) +::send from host A (currently at p2) to p1 +::verify received at p1, NOT p0, p2, p3 +::send from p1 to Host A (currently at p2) +::verify received p2, NOT p0, p1, p3 + +=== Unicast, hub connected === +:; Name: test_hub_connected +:; Owner: Peyman +:; Description: if a port connects to a hub, we may receive traffic for which the sender and receiver are connected to the same port. This traffic should be dropped. + +=== Unicast, multiple hosts per port === +:; Name: test_unicast_multiple_hosts +:; Owner: Peyman +:; Description: assume each port is connected to a switch, so that each port receives traffic from multiple MAC addresses - say, 20 per port. Other than multiple MAC addrs per port, this is just like test_unicast_known. Each port sends to a host at a different port. + + +Black Box Tests +---------------- + +One test currently fails with the OF Reference v0.8.1 kmod: + +-LLC: Pkt is forwarded to the controller, when it should be dropped. + +Two tests are currently failing with the OF Reference v0.8.1 user-space switch: + +-test_forward_exact_controller +-test_forward_wildcard_controller + +All failing tests can be re-activated by changing +projects/black_box/regress/tests.txt + +== Basic Functionality == + +=== Hello === +:; Name: test_hello +:; Owner: Brandon Heller +:; Description: send hello packet to switch, verify reply with correct params + +=== Send from Switch to Controller === +:; Name: test_packet_in +:; Owner: Brandon Heller +:; Description: send packet from switch to SC, verify it is received at the controller + +=== Send from Controller to Switch === +:; Name: test_packet_out +:; Owner: Brandon Heller +:; Description: send packet to switch on secure chan for each output port, ensure packet received at proper ports. + +=== Switch Config === +:; Name: test_switch_config +:; Owner: Brandon Heller +:; Description: verify default switch config, set config, verify that config has changed +:; Status: done + +=== Flow Expired === +:; Name: test_flow_expired +:; Owner: Brandon Heller +:; Description: send add flow message for short timeout, verify no error message received, plus flow timeout message received within time bounds +::send a second add flow message and keep it active with packets; verify that flow expires only if idle + +=== Miss Send Length === +:; Name: test_miss_send_length +:; Owner: Brandon Heller +:; Description: get the miss send length from the hello message, then send a packet to switch, verify correct length for forwarded chunk of packet + +== Modify State Tests == + +=== Forward Any Port === +:; Name: test_forward_any_port +:; Owner: Brandon Heller +:; Description: add a flow mod with all wildcards set, and ensure that all packets get diverted to the specified port. + +=== Forward Exact Port === +:; Name: test_forward_exact_port +:; Owner: Brandon Heller +:; Description: add an exact flow entry, verify a packet is forwarded to the correct port, for all port combinations + +=== Forward Exact ALL === +:; Name: test_forward_exact_all +:; Owner: Brandon Nefcy +:; Description: add an exact flow entry, verify a packet is sent out all ports, for all port combinations +:; Implementation: One packet is sent in to eth0, eth1, eth2, and eth3. An exact match flow entry is set up for each, with the expected action to be flooding the packet out on all ports except the input port. + +=== Forward Exact Controller === +:; Name: test_forward_exact_controller +:; Owner: Brandon Nefcy +:; Description: add an exact flow entry, verify a packet is forwarded to the secure channel +:; Implementation: One packet is sent in on each of eth0, eth1, eth2, and eth3. Test behavior expects to see each packet arrive via the secchan. + +=== Forward Wildcard Port === +:; Name: test_forward_wildcard_port +:; Owner: Brandon Nefcy +:; Description: Test each individual wildcard field. verify a matching packet is forwarded to the correct port, for all port combinations, and a mismatching packet is sent to secchan +:; Implementation: For each possible single-input-port to single-output-port combination flows are set up, one at a time, where each flow is wildcarded on a single field, with enough flows rotated in to test every wildcard field. For each, a matching packet is sent in and expected on the appropriate output port, and a mismatching packet is sent in and expected on the secchan output + +=== Forward Wildcard ALL === +:; Name: test_forward_wildcard_all +:; Owner: Brandon Nefcy +:; Description: same as test_forward_wildcard_port, but instead of sending from one input to one output, sends from one input to all outputs. +:; Implementation: Combination of test_foward_wildcard_port and test_forward_exact_all + +=== Forward Wildcard Controller === +:; Name: test_forward_wildcard_controller +:; Owner: Brandon Nefcy +:; Description: Combination of test_forward_wildcard_port and test_forward_exact_controller. Tests various single wildcard flows where matching packets and mismatching packets are both sent to secchan. +:; Status: Checked in, working, but with limitations as mentioned in test_forward_wildcard_port + +=== Forward After Expiration === +:; Name: test_forward_after_expiration +:; Owner: Brandon Nefcy +:; Description: insert short-lived flow, use it to forward packet, wait until expiration, send packet again, verify nothing received and counters zeroed +:; Implementation: An exact match flow entry is inserted for a specific input port -> output port combination (ie eth0->eth1), a packet is sent to match this entry with the test expecting the appropriate output behavior. The test waits for the flow entry to expire and verifies the expiration via a secchan flow expiration message, then proceeds to re-send the same packet from before, expecting a secchan OFPR_NO_MATCH message. The above is repeated for all combinations of input port -> output port. + +=== Overlapping Flow Entries === +:; Name: test_forward_overlapping_flow_entries +:; Owner: Brandon Nefcy +:; Description: insert both wildcard and exact match flow entries that overlap, verify that the exact match takes precedence +:; Implementation: One packet is sent in on eth0, eth1, eth2, and eth3. Before each packet is sent, two flow entries are set up, one where the entire flow is wildcarded and the action is to send to secchan, and another where the flow is set up to be an exact-match for the packet about to be sent and the action is to flood the packet. The test verifies that the sent packets are flooded out, and no secchan messages are received other than the flows expiring. + +=== Delete === +:; Name: test_delete +:; Owner: Masa +:; Description: insert two flow entries (one wildcard entry and one exact entry where the exact one is covered by the wildcard one). Send packets to verify they are forwarded correctly. Then delete the wildcard entry with DELETE (not strict) -- both the wildcard and the exeact entries should be deleted. To check this, send a packet matching to the exact entry to verify it gets sent to contoller. Re-insert the entry and verify that counters are zeroed. +::; Note -- Counter reading has not been implemented yet so the last part is not verified (5/2/2008) +:; Status: Done (rewritten with clean format) + +=== Delete Strict === +:; Name: test_delete_strict +:; Owner: Masa +:; Description: insert two flow entries (one wildcard entry and one exact entry where the exact one is covered by the wildcard one. The output ports of these two entries are different). Send packets to verify they are forwarded correctly. Then delete the wildcard entry with DELETE_STRICT (not strict) -- only the wildcard entry should be deleted (the exeact entry should not be deleted). To check this, send a packet matching to the exact entry to verify it gets forwarded. +:; Status: Done (rewritten with clean format) + +== Unusual Data == + +=== IP Options === +:; Name: test_ip_options +:; Owner: Masa +:; Description: suggested by Nicira. +::;(1) Create a flow entry that matches to a UDP flow coming from port eth7 (action = forward to port eth8). +::;(2) Send UDP packets with IP time stamp option (ip_hdr_len=7) to port eth7. +::;(3) To see whether the packet comes out from port eth8. +::; As of May 2, 2008, test succeeded. + +=== IP Protocol === +:; Name: test_ip_protocol +:; Owner: Masa +:; Description: +:: Added by Masa +:: see if src/dst port fields are used for matching only for TCP/UDP packets +:: As of May 2, 2008, the result is the following. Even if protocol is not TCP nor UDP, port number fields seems used for matching. Only when protocol number is specified to zero, port number fields are not used for matching.. It seems a strange behavior. +:; Status: Done (rewritten w/ clean format) +:; Note : TCP checksum (in TCP header) is not calculated due to lack of NF2::TCP library (but OF switch won't check it anyway). + +=== IP Offset > Pkt Len === +:; Name: test_ip_offset +:; Owner: Masa +:; Description: +:: possible security risk, shouldn't be an issue +:: suggested by Nicira +:: Create a flow entry. Send several packets matching the entry but whose IP Offset > Pkt Len. Verify all the packets are forwarded to the specified port (specified by the flow entry). + +=== TCP Options === +:; Name: test_tcp_options +:; Owner: Masa +:; Description: +:: See if TCP options affect operation +:: Install a TCP flow entry. Sent a TCP pkt that matches to the installed entry but has TCP option. Verify the packet is forwarded to the specified port. +:; Note : TCP checksum (in TCP header) is not calculated due to lack of NF2::TCP library (but OF switch won't check it anyway). + +=== LLC === +:; Name: test_llc +:; Owner: Masa +:; Description: see LLC packet format; adds 5B to Eth packet +::; Install a flow entry (exact match to an IP flow). Send an IP packet that matches to the installed entry and has the following Ethernet LLC/SNAP header. Verify it is forwarded to the specified port. +:::; Dst MAC (6 byte) +:::; Src MAC (6 byte) +:::; Length (2 byte) = data length from LLC header to the end of IP packet +:::; LLC header (3 byte) = 0xAA 0xAA 0x03 (always this value for IP packets) +:::; SNAP header(5 byte) = OUI(3B)+Type(2B)=0x000000 + 0x0800(IP) (always this value for IP packets) +:::; IP Packet +:; NOTE: It fails (pkt is forwarded to the controller) as of June 11, 2008. + + +Bugs/Shortcomings +----------------- + +- test_llc and test_ip_protocol are not actually run when enabled in a tests.txt file + +Contact +------- + +e-mail: openflow-discuss@openflowswitch.org +www: http://openflowswitch.org/ diff --git a/openflow/regress/bin/eth.map b/openflow/regress/bin/eth.map new file mode 100644 index 00000000..689ad0f0 --- /dev/null +++ b/openflow/regress/bin/eth.map @@ -0,0 +1,8 @@ +eth1:eth1 +eth2:eth2 +eth3:eth3 +eth4:eth4 +eth5:eth5 +eth6:eth6 +eth7:eth7 +eth8:eth8 diff --git a/openflow/regress/bin/nf2.map b/openflow/regress/bin/nf2.map new file mode 100644 index 00000000..797b3896 --- /dev/null +++ b/openflow/regress/bin/nf2.map @@ -0,0 +1,8 @@ +eth1:eth1 +eth2:eth2 +eth3:eth3 +eth4:eth4 +eth5:nf2c0 +eth6:nf2c1 +eth7:nf2c2 +eth8:nf2c3 diff --git a/openflow/regress/bin/of_hp_eth.map b/openflow/regress/bin/of_hp_eth.map new file mode 100644 index 00000000..4f652145 --- /dev/null +++ b/openflow/regress/bin/of_hp_eth.map @@ -0,0 +1,8 @@ +eth1:eth10 +eth2:eth11 +eth3:eth12 +eth4:eth13 +eth5:eth10 +eth6:eth11 +eth7:eth12 +eth8:eth13 diff --git a/openflow/regress/bin/of_hp_setup.pl b/openflow/regress/bin/of_hp_setup.pl new file mode 100755 index 00000000..213376c6 --- /dev/null +++ b/openflow/regress/bin/of_hp_setup.pl @@ -0,0 +1,86 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use OF::OFUtil; +use Test::TestLib; +use Time::HiRes qw(usleep); + +my $mapFile; +my $of_hp_switch_ip; +my $of_hp_vlan; +my $of_hp_controller; +my $of_hp_listener; +my $of_hp_community; + +# Process command line options +# Don't fail on unrecognised options, those failures are tricky +# to diagnose. For example projects/controller_disconnect sets --emerg +# Jean II +Getopt::Long::Configure( 'pass_through' ); +GetOptions( "map=s" => \$mapFile, ); +Getopt::Long::Configure( 'default' ); + +# If not specified on command line, use environment variable. +# Try specific first, then try generic - Jean II +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_HP_MAP_ETH'})) ) { + $mapFile = "$ENV{OFT_HP_MAP_ETH}"; +} +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_MAP_ETH'})) ) { + $mapFile = "$ENV{OFT_MAP_ETH}"; +} + +if ( defined($mapFile) ) { + nftest_process_iface_map($mapFile); +} + +setup_pcap_interfaces(); + +# Get HP switch address and configuration - Jean II +if (defined($ENV{'OFT_HP_SWITCH_IP'})) { + $of_hp_switch_ip = $ENV{'OFT_HP_SWITCH_IP'}; +} else { + $of_hp_switch_ip = "10.10.10.1"; +} +if (defined($ENV{'OFT_HP_VLAN'})) { + $of_hp_vlan = $ENV{'OFT_HP_VLAN'}; +} else { + $of_hp_vlan = 18; +} +if (defined($ENV{'OFT_HP_CONTROLLER'})) { + $of_hp_controller = $ENV{'OFT_HP_CONTROLLER'}; +} else { + my $of_port = get_of_port(); + $of_hp_controller = "tcp:10.10.10.2:$of_port"; +} +if (defined($ENV{'OFT_HP_LISTENER'})) { + # Transform into a passive string + ($proto, $host, $port) = split(/:/,$ENV{'OFT_HP_LISTENER'}); + $of_hp_listener = "p$proto:$port"; +} +if (defined($ENV{'OFT_HP_COMMUNITY'})) { + $of_hp_community = $ENV{'OFT_HP_COMMUNITY'}; +} else { + $of_hp_community = 'public'; +} + + +# disable OpenFlow module to make sure it restarts +`snmpset -v2c -c ${of_hp_community} ${of_hp_switch_ip} iso.org.dod.internet.private.enterprises.11.2.14.11.5.1.7.1.35.1.1.2.${of_hp_vlan} i 2`; + +# Make sure the snmp commands don't coalesce +usleep(200000); + +# set OpenFlow Controller string +`snmpset -v2c -c ${of_hp_community} ${of_hp_switch_ip} iso.org.dod.internet.private.enterprises.11.2.14.11.5.1.7.1.35.1.1.3.${of_hp_vlan} s ${of_hp_controller}`; + +# set OpenFlow Listener string +if (defined($of_hp_listener)) { + `snmpset -v2c -c ${of_hp_community} ${of_hp_switch_ip} iso.org.dod.internet.private.enterprises.11.2.14.11.5.1.7.1.35.1.1.4.${of_hp_vlan} s ${of_hp_listener}`; +} + +# enable OpenFlow module +`snmpset -v2c -c ${of_hp_community} ${of_hp_switch_ip} iso.org.dod.internet.private.enterprises.11.2.14.11.5.1.7.1.35.1.1.2.${of_hp_vlan} i 1`; + +# Starting OpenFlow takes time, give switch a bit of time... +usleep(900000); diff --git a/openflow/regress/bin/of_hp_teardown.pl b/openflow/regress/bin/of_hp_teardown.pl new file mode 100755 index 00000000..0365ce67 --- /dev/null +++ b/openflow/regress/bin/of_hp_teardown.pl @@ -0,0 +1,50 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use OF::OFUtil; +use Test::TestLib; + +my $mapFile; +my $of_hp_switch_ip; +my $of_hp_community; + +# Process command line options +unless ( GetOptions( "map=s" => \$mapFile, ) ) { + print "unrecognized option\n"; + exit 1; +} + +# If not specified on command line, use environment variable. +# Try specific first, then try generic - Jean II +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_HP_MAP_ETH'})) ) { + $mapFile = "$ENV{OFT_HP_MAP_ETH}"; +} +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_MAP_ETH'})) ) { + $mapFile = "$ENV{OFT_MAP_ETH}"; +} + +if ( defined($mapFile) ) { + nftest_process_iface_map($mapFile); +} + +# Get HP switch address - Jean II +if (defined($ENV{'OFT_HP_SWITCH_IP'})) { + $of_hp_switch_ip = $ENV{'OFT_HP_SWITCH_IP'}; +} else { + $of_hp_switch_ip = "10.10.10.1"; +} +if (defined($ENV{'OFT_HP_VLAN'})) { + $of_hp_vlan = $ENV{'OFT_HP_VLAN'}; +} else { + $of_hp_vlan = 18; +} +if (defined($ENV{'OFT_HP_COMMUNITY'})) { + $of_hp_community = $ENV{'OFT_HP_COMMUNITY'}; +} else { + $of_hp_community = 'public'; +} + +# disable OpenFlow module +`snmpset -v2c -c ${of_hp_community} ${of_hp_switch_ip} iso.org.dod.internet.private.enterprises.11.2.14.11.5.1.7.1.35.1.1.2.${of_hp_vlan} i 2`; + diff --git a/openflow/regress/bin/of_hp_test.pl b/openflow/regress/bin/of_hp_test.pl new file mode 100755 index 00000000..d6c3233f --- /dev/null +++ b/openflow/regress/bin/of_hp_test.pl @@ -0,0 +1,62 @@ +#!/usr/bin/perl -w + +############################################################################## +# +# Wrapper for running OpenFlow regression tests against ProCurve 3500/5400 +# Jean Tourrilhes - HP-Labs - copyright 2009-2010 +# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ +# +############################################################################## + +use OF::Base; +use Test::RegressTest; +use strict; +use OF::OFUtil; + +# check vars are set. +check_OF_vars_set(); + +sub INT_Handler { + my $signame = shift; + print "\nNo interrupt handler implemented yet...\n"; + print "\nExited with SIG$signame\n"; + exit(1); +} + +# For the 5406zl and 3500yl... + +# HP switch starts at port 1 == 'A1' or 1 == '1' +# Test need extra delay due to slow controller socket +# Add more idle time due to stat resolution +# byte count is not available - Jean II +push @ARGV, "--root=$ENV{'OFT_ROOT'}", "--common-st-args=hp", "--controller=".$ENV{'OFT_HP_CONTROLLER'}, "--port_base=1", "--send_delay=300000", "--base_idle=2", "--ignore_byte_count"; + +# Use a single random port instead of all four +push @ARGV, "--less_ports"; + +# For QinQ, you will need the premium license... +push @ARGV, "--no_vlan"; + +# The hardware can not support slicing +push @ARGV, "--no_slicing"; + +# The hardware can not support barrier +push @ARGV, "--no_barrier"; + +# The hardware can not support emergency flow table +push @ARGV, "--no_emerg"; + +# Check for listener +if ( defined($ENV{'OFT_HP_LISTENER'}) ) { + push @ARGV, "--listener=$ENV{OFT_HP_LISTENER}"; +} + +# Check for specific MAP file... +if ( defined($ENV{'OFT_HP_MAP_ETH'}) ) { + push @ARGV, "--map=$ENV{OFT_HP_MAP_ETH}"; +} + +# Other configuration is through Environment Variables, See of_hp_setup.pl +# Jean II + +run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_hp_test_6600.pl b/openflow/regress/bin/of_hp_test_6600.pl new file mode 100755 index 00000000..e141def5 --- /dev/null +++ b/openflow/regress/bin/of_hp_test_6600.pl @@ -0,0 +1,62 @@ +#!/usr/bin/perl -w + +############################################################################## +# +# Wrapper for running OpenFlow regression tests against ProCurve 6600 +# Jean Tourrilhes - HP-Labs - copyright 2009-2010 +# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ +# +############################################################################## + +use OF::Base; +use Test::RegressTest; +use strict; +use OF::OFUtil; + +# check vars are set. +check_OF_vars_set(); + +sub INT_Handler { + my $signame = shift; + print "\nNo interrupt handler implemented yet...\n"; + print "\nExited with SIG$signame\n"; + exit(1); +} + +# For the 6600... + +# HP switch starts at port 25 == '1' +# Test need extra delay due to slow controller socket +# Add more idle time due to stat resolution +# byte count is not available - Jean II +push @ARGV, "--root=$ENV{'OFT_ROOT'}", "--common-st-args=hp", "--controller=".$ENV{'OFT_HP_CONTROLLER'}, "--port_base=25", "--send_delay=650000", "--base_idle=3", "--ignore_byte_count"; + +# Use a single random port instead of all four +push @ARGV, "--less_ports"; + +# For QinQ, you will need the premium license... +push @ARGV, "--no_vlan"; + +# The hardware can not support slicing +push @ARGV, "--no_slicing"; + +# The hardware can not support barrier +push @ARGV, "--no_barrier"; + +# The hardware can not support emergency flow table +push @ARGV, "--no_emerg"; + +# Check for listener +if ( defined($ENV{'OFT_HP_LISTENER'}) ) { + push @ARGV, "--listener=$ENV{OFT_HP_LISTENER}"; +} + +# Check for specific MAP file... +if ( defined($ENV{'OFT_HP_MAP_ETH'}) ) { + push @ARGV, "--map=$ENV{OFT_HP_MAP_ETH}"; +} + +# Other configuration is through Environment Variables, See of_hp_setup.pl +# Jean II + +run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_kmod_setup.pl b/openflow/regress/bin/of_kmod_setup.pl new file mode 100755 index 00000000..fc3ef4ba --- /dev/null +++ b/openflow/regress/bin/of_kmod_setup.pl @@ -0,0 +1,22 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use OF::OFUtil; +use Test::TestLib; + +my $mapFile, $controller; + +# Process command line options +unless ( GetOptions( "map=s" => \$mapFile, + "emerg" => \$emerg, + "controller=s", \$controller) ) { + print "unrecognized option\n"; + exit 1; +} + +if ( defined($mapFile) ) { + nftest_process_iface_map($mapFile); +} + +setup_kmod($controller, $emerg); diff --git a/openflow/regress/bin/of_kmod_teardown.pl b/openflow/regress/bin/of_kmod_teardown.pl new file mode 100755 index 00000000..4fa7dbfa --- /dev/null +++ b/openflow/regress/bin/of_kmod_teardown.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use OF::OFUtil; +use Test::TestLib; + +my $mapFile; + +# Process command line options +unless ( GetOptions( "map=s" => \$mapFile, ) ) { + print "unrecognized option\n"; + exit 1; +} + +if ( defined($mapFile) ) { + nftest_process_iface_map($mapFile); +} + +teardown_kmod(); diff --git a/openflow/regress/bin/of_kmod_test.pl b/openflow/regress/bin/of_kmod_test.pl new file mode 100755 index 00000000..6ce99411 --- /dev/null +++ b/openflow/regress/bin/of_kmod_test.pl @@ -0,0 +1,27 @@ +#!/usr/bin/perl -w + +############################################################################## +# +# Wrapper for OpenFlow regression tests +# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ +# +############################################################################## + +use OF::Base; +use Test::RegressTest; +use strict; +use OF::OFUtil; + +# check vars are set. +check_OF_vars_set(); + +sub INT_Handler { + my $signame = shift; + print "\nNo interrupt handler implemented yet...\n"; + print "\nExited with SIG$signame\n"; + exit(1); +} + +push (@ARGV, "--root=$ENV{'OFT_ROOT'}", "--map=$ENV{'OFT_ROOT'}/bin/eth.map", "--port_base=1", "--common-st-args=kmod"); + +run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_kmod_veth_setup.pl b/openflow/regress/bin/of_kmod_veth_setup.pl new file mode 100755 index 00000000..79a37733 --- /dev/null +++ b/openflow/regress/bin/of_kmod_veth_setup.pl @@ -0,0 +1,26 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use OF::OFUtil; +use Test::TestLib; + +my ($mapFile, $controller); + +# Process command line options +unless ( GetOptions( "map=s" => \$mapFile, + "emerg" => \$emerg, + "controller=s", \$controller) ) { + print "unrecognized option\n"; + exit 1; +} + +if ( defined($mapFile) ) { + nftest_process_iface_map($mapFile); +} +#else, use pre-defined veth map +else { + nftest_process_iface_map("$ENV{'OFT_ROOT'}/bin/veth.map"); +} + +setup_kmod($controller, $emerg); diff --git a/openflow/regress/bin/of_kmod_veth_teardown.pl b/openflow/regress/bin/of_kmod_veth_teardown.pl new file mode 100755 index 00000000..52b57927 --- /dev/null +++ b/openflow/regress/bin/of_kmod_veth_teardown.pl @@ -0,0 +1,24 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use OF::OFUtil; +use Test::TestLib; + +my $mapFile; + +# Process command line options +unless ( GetOptions( "map=s" => \$mapFile, ) ) { + print "unrecognized option\n"; + exit 1; +} + +if ( defined($mapFile) ) { + nftest_process_iface_map($mapFile); +} +#else, use pre-defined veth map +else { + nftest_process_iface_map("$ENV{'OFT_ROOT'}/bin/veth.map"); +} + +teardown_kmod(); diff --git a/openflow/regress/bin/of_kmod_veth_test.pl b/openflow/regress/bin/of_kmod_veth_test.pl new file mode 100755 index 00000000..0f08edbb --- /dev/null +++ b/openflow/regress/bin/of_kmod_veth_test.pl @@ -0,0 +1,27 @@ +#!/usr/bin/perl -w + +############################################################################## +# +# Wrapper for OpenFlow regression tests +# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ +# +############################################################################## + +use OF::Base; +use Test::RegressTest; +use strict; +use OF::OFUtil; + +# check vars are set. +check_OF_vars_set(); + +sub INT_Handler { + my $signame = shift; + print "\nNo interrupt handler implemented yet...\n"; + print "\nExited with SIG$signame\n"; + exit(1); +} + +push (@ARGV, "--map=$ENV{'OFT_ROOT'}/bin/veth.map", "--root=$ENV{'OFT_ROOT'}", "--port_base=1", "--common-st-args=kmod_veth"); + +run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_nf2_setup.pl b/openflow/regress/bin/of_nf2_setup.pl new file mode 100755 index 00000000..34fe3351 --- /dev/null +++ b/openflow/regress/bin/of_nf2_setup.pl @@ -0,0 +1,26 @@ +#!/usr/bin/perl -w + +use Getopt::Long; +use Data::Dumper; + +use OF::OFUtil; +use Test::TestLib; + +my ($mapFile, $controller); + +print "Calling of_nf2_setup.pl\n"; +print Dumper(@ARGV) . "\n"; + +# Process command line options +unless ( GetOptions( "map=s" => \$mapFile, + "emerg" => \$emerg, + "controller=s", \$controller) ) { + print "unrecognized option\n"; + exit 1; +} + +if ( defined($mapFile) ) { + nftest_process_iface_map($mapFile); +} + +setup_NF2($controller, $emerg); diff --git a/openflow/regress/bin/of_nf2_teardown.pl b/openflow/regress/bin/of_nf2_teardown.pl new file mode 100755 index 00000000..286a87cf --- /dev/null +++ b/openflow/regress/bin/of_nf2_teardown.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use OF::OFUtil; +use Test::TestLib; + +my $mapFile; + +# Process command line options +unless ( GetOptions( "map=s" => \$mapFile, ) ) { + print "unrecognized option\n"; + exit 1; +} + +if ( defined($mapFile) ) { + nftest_process_iface_map($mapFile); +} + +teardown_NF2(); diff --git a/openflow/regress/bin/of_nf2_test.pl b/openflow/regress/bin/of_nf2_test.pl new file mode 100755 index 00000000..0704e99a --- /dev/null +++ b/openflow/regress/bin/of_nf2_test.pl @@ -0,0 +1,28 @@ +#!/usr/bin/perl -w + +############################################################################## +# +# Wrapper for OpenFlow regression tests +# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ +# +############################################################################## + +use OF::Base; +use Test::RegressTest; +use strict; +use OF::OFUtil; + +# check vars are set. +check_OF_vars_set(); + +sub INT_Handler { + my $signame = shift; + print "\nNo interrupt handler implemented yet...\n"; + print "\nExited with SIG$signame\n"; + exit(1); +} + +push (@ARGV, "--root=$ENV{'OFT_ROOT'}", "--map=$ENV{'OFT_ROOT'}/bin/nf2.map", "--port_base=1", "--common-st-args=nf2"); +push @ARGV, "--no_slicing"; + +run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_ovs_eth.map b/openflow/regress/bin/of_ovs_eth.map new file mode 100644 index 00000000..120ee51d --- /dev/null +++ b/openflow/regress/bin/of_ovs_eth.map @@ -0,0 +1,8 @@ +eth1:eth10.91 +eth2:eth10.92 +eth3:eth10.93 +eth4:eth10.94 +eth5:eth11.91 +eth6:eth11.92 +eth7:eth11.93 +eth8:eth11.94 diff --git a/openflow/regress/bin/of_ovs_setup.pl b/openflow/regress/bin/of_ovs_setup.pl new file mode 100755 index 00000000..ca2cc93f --- /dev/null +++ b/openflow/regress/bin/of_ovs_setup.pl @@ -0,0 +1,76 @@ +#!/usr/bin/perl -w +# Jean Tourrilhes - HP-Labs + +use Getopt::Long; + +use OF::OFUtil; +use Test::TestLib; + +my $mapFile; + +# The map file is necessary. It assing the real interface to the +# fictious names used by the test suite. +# eth1->eth4 are capture interfaces used to send/receive probe packets +# eth5->eth8 are configured to run the OpenFlow switch +# Jean II + +# Process command line options +# Don't fail on unrecognised options, those failures are tricky +# to diagnose. For example projects/controller_disconnect sets --emerg +# Jean II +Getopt::Long::Configure( 'pass_through' ); +GetOptions( "map=s" => \$mapFile, ); +Getopt::Long::Configure( 'default' ); + +# If not specified on command line, use enviroment variable. +# Try specific first, then try generic - Jean II +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_OVS_MAP_ETH'})) ) { + $mapFile = "$ENV{OFT_OVS_MAP_ETH}"; +} +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_MAP_ETH'})) ) { + $mapFile = "$ENV{OFT_MAP_ETH}"; +} + +# Set up the mappings +if ( defined($mapFile) ) { + nftest_process_iface_map($mapFile); +} + +# Debug... +#for ( my $i = 1 ; $i <= 8 ; $i++ ) { +# my $iface = nftest_get_iface("eth$i"); +# print "iface($i) = $iface\n"; +#} + +# Start capturing on eth1->eth4 +setup_pcap_interfaces(); + +# Get the directly where Open vSwitch resides +my $ovs_dir = $ENV{'OFT_OVS_ROOT'}; +my $of_port = get_of_port(); + +# Setup the kernel module +`insmod ${ovs_dir}/datapath/linux-2.6/openvswitch_mod.ko`; +`${ovs_dir}/utilities/ovs-dpctl add-dp dp0`; + +# Not needed after 0.99.2 +#for ( my $i = 5 ; $i <= 8 ; $i++ ) { +# my $iface = nftest_get_iface("eth$i"); +# `${ovs_dir}/utilities/ovs-dpctl add-if dp0 $iface`; +#} + +# create command line arguments containing all four ports +my $if_string = ''; +for ( my $i = 5 ; $i <= 7 ; $i++ ) { + $if_string .= nftest_get_iface("eth$i") . ','; +} +$if_string .= nftest_get_iface("eth8"); + +# create Open vSwitch openflow switch on four ports eth5->eth9 +system("${ovs_dir}/utilities/ovs-openflowd dp0 --ports=${if_string} tcp:127.0.0.1:${of_port} --listen=ptcp:6634 --fail=closed --inactivity-probe=999999 &"); + +# For 0.99.0, you'll need to manually add ports as above +#system("${ovs_dir}/utilities/ovs-openflowd dp0 tcp:127.0.0.1:${of_port} --listen=ptcp:6634 --fail=closed --inactivity-probe=999999 &"); + +# Up to 0.90.6, you would use secchan, after that you need to use ovs-openflowd +#system("${ovs_dir}/secchan/secchan dp0 tcp:127.0.0.1:${of_port} --listen=ptcp:6634 --fail=closed --inactivity-probe=999999 &"); diff --git a/openflow/regress/bin/of_ovs_teardown.pl b/openflow/regress/bin/of_ovs_teardown.pl new file mode 100755 index 00000000..303eb4ad --- /dev/null +++ b/openflow/regress/bin/of_ovs_teardown.pl @@ -0,0 +1,59 @@ +#!/usr/bin/perl -w +# Jean Tourrilhes - HP-Labs + +use Getopt::Long; + +use OF::OFUtil; +use Test::TestLib; + +my $mapFile; + +# Process command line options +unless ( GetOptions( "map=s" => \$mapFile, ) ) { + print "unrecognized option\n"; + exit 1; +} + +# If not specified on command line, use enviroment variable. +# Try specific first, then try generic - Jean II +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_OVS_MAP_ETH'})) ) { + $mapFile = "$ENV{OFT_OVS_MAP_ETH}"; +} +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_MAP_ETH'})) ) { + $mapFile = "$ENV{OFT_MAP_ETH}"; +} + +if ( defined($mapFile) ) { + nftest_process_iface_map($mapFile); +} + +# Get the directly where Open vSwitch resides +my $ovs_dir = $ENV{'OFT_OVS_ROOT'}; + +# Start by killing secchan or ovs-openflowd +`killall secchan`; +`killall ovs-openflowd`; + +# check if openflow kernel module loaded +my $of_kmod_loaded = `lsmod | grep openvswitch_mod`; +if ( $of_kmod_loaded eq "" ) { exit 0; } + +print "tearing down interfaces and datapaths\n"; + +# remove interfaces from openflow +for ( my $i = 5 ; $i <= 8 ; $i++ ) { + my $iface = nftest_get_iface("eth$i"); + `${ovs_dir}/utilities/ovs-dpctl del-if dp0 $iface`; +} + +`${ovs_dir}/utilities/ovs-dpctl del-dp dp0`; + +my $of_kmod_removed = `rmmod openvswitch_mod`; +if ( $of_kmod_removed ne "" ) { + die "failed to remove kernel module... please fix!\n"; +} + +$of_kmod_loaded = `lsmod | grep openvswitch_mod`; +if ( $of_kmod_loaded ne "" ) { + die "failed to remove kernel module... please fix!\n"; +} diff --git a/openflow/regress/bin/of_ovs_test.pl b/openflow/regress/bin/of_ovs_test.pl new file mode 100755 index 00000000..a842aa64 --- /dev/null +++ b/openflow/regress/bin/of_ovs_test.pl @@ -0,0 +1,54 @@ +#!/usr/bin/perl -w + +############################################################################## +# +# Wrapper for running OpenFlow regression tests against Open vSwitch +# Jean Tourrilhes - HP-Labs - copyright 2009-2010 +# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ +# +############################################################################## + +use OF::Base; +use Test::RegressTest; +use strict; +use OF::OFUtil; + +# check vars are set. +check_OF_vars_set(); + +sub INT_Handler { + my $signame = shift; + print "\nNo interrupt handler implemented yet...\n"; + print "\nExited with SIG$signame\n"; + exit(1); +} + +# For Open vSwitch + +# Open vSwitch starts at port 1 +# Get a bit of speedup by tweaking send_delay and base_idle +# Jean II +my $of_port = get_of_port(); +push @ARGV, "--root=$ENV{'OFT_ROOT'}", "--common-st-args=ovs", "--controller=tcp:localhost:$of_port,tcp:localhost:$of_port", "--listener=tcp:127.0.0.1:6634", "--port_base=1", "--send_delay=2000", "--base_idle=2"; + +# Use a single random port instead of all four +push @ARGV, "--less_ports"; + +# Don't bother with VLAN if we go outside the box, too many issues... +#push @ARGV, "--no_vlan"; + +# Don't bother with QoS currently, it's broken... +push @ARGV, "--no_slicing"; + +# The bother with emergency flow table tests, it's not supported... +push @ARGV, "--no_emerg"; + +# Don't forget to configure the OVS_ROOT environment variable +# Jean II + +# Check for specific MAP file... +if ( defined($ENV{'OFT_OVS_MAP_ETH'}) ) { + push @ARGV, "--map=$ENV{OFT_OVS_MAP_ETH}"; +} + +run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_ovs_user_setup.pl b/openflow/regress/bin/of_ovs_user_setup.pl new file mode 100755 index 00000000..aa31cff6 --- /dev/null +++ b/openflow/regress/bin/of_ovs_user_setup.pl @@ -0,0 +1,60 @@ +#!/usr/bin/perl -w +# Jean Tourrilhes - HP-Labs + +use Getopt::Long; + +use OF::OFUtil; +use Test::TestLib; + +my $mapFile; + +# The map file is necessary. It assing the real interface to the +# fictious names used by the test suite. +# eth1->eth4 are capture interfaces used to send/receive probe packets +# eth5->eth8 are configured to run the OpenFlow switch +# Jean II + +# Process command line options +# Don't fail on unrecognised options, those failures are tricky +# to diagnose. For example projects/controller_disconnect sets --emerg +# Jean II +Getopt::Long::Configure( 'pass_through' ); +GetOptions( "map=s" => \$mapFile, ); +Getopt::Long::Configure( 'default' ); + +# If not specified on command line, use enviroment variable. +# Try specific first, then try generic - Jean II +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_OVS_MAP_ETH'})) ) { + $mapFile = "$ENV{OFT_OVS_MAP_ETH}"; +} +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_MAP_ETH'})) ) { + $mapFile = "$ENV{OFT_MAP_ETH}"; +} + +# Set up the mappings +if ( defined($mapFile) ) { + nftest_process_iface_map($mapFile); +} + +# Debug... +#for ( my $i = 1 ; $i <= 8 ; $i++ ) { +# my $iface = nftest_get_iface("eth$i"); +# print "iface($i) = $iface\n"; +#} + +# Start capturing on eth1->eth4 +setup_pcap_interfaces(); + +# Get the directly where Open vSwitch resides +my $ovs_dir = $ENV{'OFT_OVS_ROOT'}; +my $of_port = get_of_port(); + +# create command line arguments containing all four ports +my $if_string = ''; +for ( my $i = 5 ; $i <= 7 ; $i++ ) { + $if_string .= nftest_get_iface("eth$i") . ','; +} +$if_string .= nftest_get_iface("eth8"); + +# create userspace Open vSwitch openflow switch on four ports +system("${ovs_dir}/utilities/ovs-openflowd netdev\@br0 --ports=${if_string} tcp:127.0.0.1:${of_port} --listen=ptcp:6634 --fail=closed --inactivity-probe=999999 &"); diff --git a/openflow/regress/bin/of_ovs_user_teardown.pl b/openflow/regress/bin/of_ovs_user_teardown.pl new file mode 100755 index 00000000..81124624 --- /dev/null +++ b/openflow/regress/bin/of_ovs_user_teardown.pl @@ -0,0 +1,34 @@ +#!/usr/bin/perl -w +# Jean Tourrilhes - HP-Labs + +use Getopt::Long; + +use OF::OFUtil; +use Test::TestLib; + +my $mapFile; + +# Process command line options +unless ( GetOptions( "map=s" => \$mapFile, ) ) { + print "unrecognized option\n"; + exit 1; +} + +# If not specified on command line, use enviroment variable. +# Try specific first, then try generic - Jean II +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_OVS_MAP_ETH'})) ) { + $mapFile = "$ENV{OFT_OVS_MAP_ETH}"; +} +if ( (! defined($mapFile) ) && (defined($ENV{'OFT_MAP_ETH'})) ) { + $mapFile = "$ENV{OFT_MAP_ETH}"; +} + +if ( defined($mapFile) ) { + nftest_process_iface_map($mapFile); +} + +# Get the directly where Open vSwitch resides +my $ovs_dir = $ENV{'OFT_OVS_ROOT'}; + +# Just kill ovs-openflowd +`killall ovs-openflowd`; diff --git a/openflow/regress/bin/of_ovs_user_test.pl b/openflow/regress/bin/of_ovs_user_test.pl new file mode 100755 index 00000000..e726e556 --- /dev/null +++ b/openflow/regress/bin/of_ovs_user_test.pl @@ -0,0 +1,50 @@ +#!/usr/bin/perl -w + +############################################################################## +# +# Wrapper for OpenFlow regression tests +# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ +# +############################################################################## + +use OF::Base; +use Test::RegressTest; +use strict; +use OF::OFUtil; + +# check vars are set. +check_OF_vars_set(); + +sub INT_Handler { + my $signame = shift; + print "\nNo interrupt handler implemented yet...\n"; + print "\nExited with SIG$signame\n"; + exit(1); +} + +# For Open vSwitch + +# Open vSwitch starts at port 1 +# Get a bit of speedup by tweaking send_delay and base_idle +# Jean II +my $of_port = get_of_port(); +push @ARGV, "--root=$ENV{'OFT_ROOT'}", "--common-st-args=ovs_user", "--controller=tcp:localhost:$of_port,tcp:localhost:$of_port", "--listener=tcp:127.0.0.1:6634", "--port_base=1", "--send_delay=2000", "--base_idle=2"; + +# Use a single random port instead of all four +push @ARGV, "--less_ports"; + +# Don't bother with QoS currently, it's broken... +push @ARGV, "--no_slicing"; + +# The bother with emergency flow table tests, it's not supported... +push @ARGV, "--no_emerg"; + +# Don't forget to configure the OVS_ROOT environment variable +# Jean II + +# Check for specific MAP file... +if ( defined($ENV{'OFT_OVS_MAP_ETH'}) ) { + push @ARGV, "--map=$ENV{OFT_OVS_MAP_ETH}"; +} + +run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_ovs_user_veth_test.pl b/openflow/regress/bin/of_ovs_user_veth_test.pl new file mode 100755 index 00000000..93a7a5df --- /dev/null +++ b/openflow/regress/bin/of_ovs_user_veth_test.pl @@ -0,0 +1,47 @@ +#!/usr/bin/perl -w + +############################################################################## +# +# Wrapper for running OpenFlow regression tests against Open vSwitch +# using veth +# Jean Tourrilhes - HP-Labs - copyright 2009-2010 +# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ +# +############################################################################## + +use OF::Base; +use Test::RegressTest; +use strict; +use OF::OFUtil; + +# check vars are set. +check_OF_vars_set(); + +sub INT_Handler { + my $signame = shift; + print "\nNo interrupt handler implemented yet...\n"; + print "\nExited with SIG$signame\n"; + exit(1); +} + +# For Open vSwitch + +# Open vSwitch starts at port 1 +# Get a bit of speedup by tweaking send_delay and base_idle +# Jean II +my $of_port = get_of_port(); +push @ARGV, "--root=$ENV{'OFT_ROOT'}", "--common-st-args=ovs_user", "--controller=tcp:localhost:$of_port,tcp:localhost:$of_port", "--listener=tcp:127.0.0.1:6634", "--port_base=1", "--send_delay=2000", "--base_idle=2", "--map=$ENV{'OFT_ROOT'}/bin/veth.map"; + +# Use a single random port instead of all four +push @ARGV, "--less_ports"; + +# Don't bother with QoS currently, it's broken... +push @ARGV, "--no_slicing"; + +# The bother with emergency flow table tests, it's not supported... +push @ARGV, "--no_emerg"; + +# Don't forget to configure the OVS_ROOT environment variable +# Jean II + +run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_ovs_veth_test.pl b/openflow/regress/bin/of_ovs_veth_test.pl new file mode 100755 index 00000000..4f09714a --- /dev/null +++ b/openflow/regress/bin/of_ovs_veth_test.pl @@ -0,0 +1,47 @@ +#!/usr/bin/perl -w + +############################################################################## +# +# Wrapper for running OpenFlow regression tests against Open vSwitch +# using veth +# Jean Tourrilhes - HP-Labs - copyright 2009-2010 +# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ +# +############################################################################## + +use OF::Base; +use Test::RegressTest; +use strict; +use OF::OFUtil; + +# check vars are set. +check_OF_vars_set(); + +sub INT_Handler { + my $signame = shift; + print "\nNo interrupt handler implemented yet...\n"; + print "\nExited with SIG$signame\n"; + exit(1); +} + +# For Open vSwitch + +# Open vSwitch starts at port 1 +# Get a bit of speedup by tweaking send_delay and base_idle +# Jean II +my $of_port = get_of_port(); +push @ARGV, "--root=$ENV{'OFT_ROOT'}", "--common-st-args=ovs", "--controller=tcp:localhost:$of_port,tcp:localhost:$of_port", "--listener=tcp:127.0.0.1:6634", "--port_base=1", "--send_delay=2000", "--base_idle=2", "--map=$ENV{'OFT_ROOT'}/bin/veth.map"; + +# Use a single random port instead of all four +push @ARGV, "--less_ports"; + +# Don't bother with QoS currently, it's broken... +push @ARGV, "--no_slicing"; + +# The bother with emergency flow table tests, it's not supported... +push @ARGV, "--no_emerg"; + +# Don't forget to configure the OVS_ROOT environment variable +# Jean II + +run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_user_setup.pl b/openflow/regress/bin/of_user_setup.pl new file mode 100755 index 00000000..5ff86039 --- /dev/null +++ b/openflow/regress/bin/of_user_setup.pl @@ -0,0 +1,22 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use OF::OFUtil; +use Test::TestLib; + +my ($mapFile, $controller); + +# Process command line options +unless ( GetOptions( "map=s" => \$mapFile, + "emerg" => \$emerg, + "controller=s", \$controller) ) { + print "unrecognized option\n"; + exit 1; +} + +if ( defined($mapFile) ) { + nftest_process_iface_map($mapFile); +} + +setup_user($controller, $emerg); diff --git a/openflow/regress/bin/of_user_teardown.pl b/openflow/regress/bin/of_user_teardown.pl new file mode 100755 index 00000000..760d7e25 --- /dev/null +++ b/openflow/regress/bin/of_user_teardown.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use OF::OFUtil; +use Test::TestLib; + +my $mapFile; + +# Process command line options +unless ( GetOptions( "map=s" => \$mapFile, ) ) { + print "unrecognized option\n"; + exit 1; +} + +if ( defined($mapFile) ) { + nftest_process_iface_map($mapFile); +} + +teardown_user(); diff --git a/openflow/regress/bin/of_user_test.pl b/openflow/regress/bin/of_user_test.pl new file mode 100755 index 00000000..1fb19ea0 --- /dev/null +++ b/openflow/regress/bin/of_user_test.pl @@ -0,0 +1,27 @@ +#!/usr/bin/perl -w + +############################################################################## +# +# Wrapper for OpenFlow regression tests +# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ +# +############################################################################## + +use OF::Base; +use Test::RegressTest; +use strict; +use OF::OFUtil; + +# check vars are set. +check_OF_vars_set(); + +sub INT_Handler { + my $signame = shift; + print "\nNo interrupt handler implemented yet...\n"; + print "\nExited with SIG$signame\n"; + exit(1); +} + +push (@ARGV, "--root=$ENV{'OFT_ROOT'}", "--map=$ENV{'OFT_ROOT'}/bin/eth.map", "--port_base=1", "--common-st-args=user"); + +run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_user_veth_setup.pl b/openflow/regress/bin/of_user_veth_setup.pl new file mode 100755 index 00000000..d5ae5edc --- /dev/null +++ b/openflow/regress/bin/of_user_veth_setup.pl @@ -0,0 +1,26 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use OF::OFUtil; +use Test::TestLib; + +my ($mapFile, $controller); + +# Process command line options +unless ( GetOptions( "map=s" => \$mapFile, + "emerg" => \$emerg, + "controller=s", \$controller) ) { + print "unrecognized option\n"; + exit 1; +} + +if ( defined($mapFile) ) { + nftest_process_iface_map($mapFile); +} +#else, use pre-defined veth map +else { + nftest_process_iface_map("$ENV{'OFT_ROOT'}/bin/veth.map"); +} + +setup_user($controller, $emerg); diff --git a/openflow/regress/bin/of_user_veth_teardown.pl b/openflow/regress/bin/of_user_veth_teardown.pl new file mode 100755 index 00000000..7d14c89c --- /dev/null +++ b/openflow/regress/bin/of_user_veth_teardown.pl @@ -0,0 +1,24 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use OF::OFUtil; +use Test::TestLib; + +my $mapFile; + +# Process command line options +unless ( GetOptions( "map=s" => \$mapFile, ) ) { + print "unrecognized option\n"; + exit 1; +} + +if ( defined($mapFile) ) { + nftest_process_iface_map($mapFile); +} +#else, use pre-defined veth map +else { + nftest_process_iface_map("$ENV{'OFT_ROOT'}/bin/veth.map"); +} + +teardown_user(); diff --git a/openflow/regress/bin/of_user_veth_test.pl b/openflow/regress/bin/of_user_veth_test.pl new file mode 100755 index 00000000..63551f98 --- /dev/null +++ b/openflow/regress/bin/of_user_veth_test.pl @@ -0,0 +1,27 @@ +#!/usr/bin/perl -w + +############################################################################## +# +# Wrapper for OpenFlow regression tests +# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ +# +############################################################################## + +use OF::Base; +use Test::RegressTest; +use strict; +use OF::OFUtil; + +# check vars are set. +check_OF_vars_set(); + +sub INT_Handler { + my $signame = shift; + print "\nNo interrupt handler implemented yet...\n"; + print "\nExited with SIG$signame\n"; + exit(1); +} + +push( @ARGV, "--map=$ENV{'OFT_ROOT'}/bin/veth.map", "--root=$ENV{'OFT_ROOT'}", "--port_base=1", "--common-st-args=user_veth"); + +run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/veth.map b/openflow/regress/bin/veth.map new file mode 100644 index 00000000..bb1c1b09 --- /dev/null +++ b/openflow/regress/bin/veth.map @@ -0,0 +1,8 @@ +eth1:veth0 +eth2:veth2 +eth3:veth4 +eth4:veth6 +eth5:veth1 +eth6:veth3 +eth7:veth5 +eth8:veth7 diff --git a/openflow/regress/bin/veth_setup.pl b/openflow/regress/bin/veth_setup.pl new file mode 100755 index 00000000..11e746e8 --- /dev/null +++ b/openflow/regress/bin/veth_setup.pl @@ -0,0 +1,10 @@ +#!/usr/bin/perl -w + +`/sbin/modprobe veth`; +for (my $i = 0; $i < 4; $i++) { + `/sbin/ip link add type veth`; +} + +for (my $i = 0; $i < 8; $i++) { + `sudo /sbin/ifconfig veth$i 192.168.1$i.1 netmask 255.255.255.0`; +} diff --git a/openflow/regress/bin/veth_teardown.pl b/openflow/regress/bin/veth_teardown.pl new file mode 100755 index 00000000..ad103756 --- /dev/null +++ b/openflow/regress/bin/veth_teardown.pl @@ -0,0 +1,4 @@ +#!/usr/bin/perl -w + +`/sbin/rmmod veth`; + diff --git a/openflow/regress/projects/black_box/regress/common/setup b/openflow/regress/projects/black_box/regress/common/setup new file mode 100755 index 00000000..8836cf7b --- /dev/null +++ b/openflow/regress/projects/black_box/regress/common/setup @@ -0,0 +1,47 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use Test::TestLib; +use OF::OFUtil; + +my $mapFile; +my $platform; +my $args; + +# Process command line options +unless ( + GetOptions ( + "map=s" => \$mapFile, + "common-st-args=s" => \$platform, + ) +) +{ + print "invalid command format\n"; + exit(1); +} + +if (defined($mapFile)) { + $args = "--map=$mapFile"; +} + +if (!defined($platform)) { + print "no platform defined\n"; + exit(1); +} +else { + print "platform = $platform\n"; +} + +my $filename = "of_${platform}_setup.pl"; + +# exit if of_${platform}_setup.pl not in path +if (-e "$ENV{'OFT_ROOT'}/bin/$filename") { + #system("$filename " . $args . " 2> /dev/null > /dev/null"); + system("$ENV{'OFT_ROOT'}/bin/$filename " . $args ); + #setup_kmod(); + exit (0); +} else { + print "couldn't find setup file $filename\n"; + exit (1); +} diff --git a/openflow/regress/projects/black_box/regress/common/teardown b/openflow/regress/projects/black_box/regress/common/teardown new file mode 100755 index 00000000..6f1f8391 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/common/teardown @@ -0,0 +1,47 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use Test::TestLib; +use OF::OFUtil; + +my $mapFile; +my $platform; +my $args; + +# Process command line options +unless ( + GetOptions ( + "map=s" => \$mapFile, + "common-st-args=s" => \$platform, + ) +) +{ + print "invalid command format\n"; + exit(1); +} + +if (defined($mapFile)) { + $args = "--map=$mapFile"; +} + +if (!defined($platform)) { + print "no platform defined\n"; + exit(1); +} +else { + print "platform = $platform\n"; +} + +my $filename = "of_${platform}_teardown.pl"; + +# exit if of_${platform}_setup.pl not in path +if (-e "$ENV{'OFT_ROOT'}/bin/$filename") { + #system("$filename " . $args . " 2> /dev/null > /dev/null"); + system("$ENV{'OFT_ROOT'}/bin/$filename " . $args ); + #teardown_kmod(); + exit (0); +} else { + print "couldn't find setup file $filename\n"; + exit (1); +} diff --git a/openflow/regress/projects/black_box/regress/test_add_flow_latency/run.pl b/openflow/regress/projects/black_box/regress/test_add_flow_latency/run.pl new file mode 100755 index 00000000..91ec09af --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_add_flow_latency/run.pl @@ -0,0 +1,47 @@ +#!/usr/bin/perl -w +# test_add_flow_latency + +use strict; +use OF::Includes; + +sub my_test { + + my ($sock) = @_; + + my $pkt_args = { + DA => "00:00:00:00:00:01", + SA => "00:00:00:00:00:02", + src_ip => "192.168.200.40", + dst_ip => "192.168.201.40", + ttl => 64, + len => 60 + }; + + my $test_pkt = new NF2::UDP_pkt(%$pkt_args); + + my $wildcards = 0x0; + my $in_port = 1; + my $out_port = 2; + my $max_idle = 0; + my $flags = 0x0; # don't send flow expiry + + my $flow_mod_pkt = create_flow_mod_from_udp($ofp,$test_pkt,$in_port,$out_port,$max_idle,$flags,$wildcards); + + print $sock $flow_mod_pkt; + usleep(1000000); + + + my $cnt = 0; + my $start_time = [gettimeofday()]; + for( $cnt = 0;$cnt < 1000; $cnt++){ + nftest_send( nftest_get_iface( "eth" . ($in_port+1)),$test_pkt->packed ); + nftest_expect( nftest_get_iface( "eth" . ($out_port+1)),$test_pkt->packed ); + } + my $time_elapse = tv_interval($start_time); + my $latency = $time_elapse*1000/1000; + print "Latency is $latency ms"; + + } + + +run_black_box_test( \&my_test); diff --git a/openflow/regress/projects/black_box/regress/test_barrier/run.pl b/openflow/regress/projects/black_box/regress/test_barrier/run.pl new file mode 100755 index 00000000..87b91153 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_barrier/run.pl @@ -0,0 +1,52 @@ +#!/usr/bin/perl -w +# test_barrier + +use strict; +use OF::Includes; + +sub my_test { + my ($sock, $options_ref) = @_; + + if ( not defined( $$options_ref{'no_barrier'} ) ) { + my $in_port = $$options_ref{'port_base'}; + my $out_port = $in_port + 1; + + # RUOK? + send_get_config_request($ofp, $sock, 0xdeadbeef); + wait_for_get_config_reply($ofp, $sock, 0xdeadbeef); + + my $base_packet = get_default_black_box_pkt($in_port, $out_port); + + my $wildcards = 0x0000; + my $flags = $enums{'OFPFF_CHECK_OVERLAP'}; + my $max_idle = 0x0; + my $packet = create_flow_mod_from_udp($ofp, $base_packet, $in_port, $out_port, $max_idle, $flags, $wildcards); + + # FOO + print $sock $packet; + + my $wildcards = 0x03fe; + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; + my $packet = create_flow_mod_from_udp($ofp, $base_packet, $in_port, $out_port, $max_idle, $flags, $wildcards); + + # BAR + print $sock $packet; + + my $wildcards = 0x03fd; + my $flags = 0x0000; + my $packet = create_flow_mod_from_udp($ofp, $base_packet, $in_port, $out_port, $max_idle, $flags, $wildcards); + + # BAZ + print $sock $packet; + + # SYNC + enter_barrier($ofp, $sock, 0x12345678); + wait_for_barrier_exit($ofp, $sock, 0x12345678); + + # RUOK? + send_get_config_request($ofp, $sock, 0xcafe2009); + wait_for_get_config_reply($ofp, $sock, 0xcafe2009); + } +} + +run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_cookie_flow_expired/run.pl b/openflow/regress/projects/black_box/regress/test_cookie_flow_expired/run.pl new file mode 100755 index 00000000..5a300ad9 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_cookie_flow_expired/run.pl @@ -0,0 +1,39 @@ +#!/usr/bin/perl -w +# test_flow_expired + +use strict; +use OF::Includes; + +sub my_test { + + my ($sock, $options_ref) = @_; + + my $in_port = $$options_ref{'port_base'}; + my $out_port = $in_port + 1; + + my $test_pkt = get_default_black_box_pkt( $in_port, $out_port); + + my $max_idle = 0x1; # second before flow expiration + my $wildcards = 0x0; # exact match + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry + my $cookie = 0x123456; + # Create a flow mod with a flow cookie + my $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, + $max_idle, $flags, $wildcards, undef, undef, undef, + undef, $cookie ); + + #print HexDump($pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + + my $pkt_len = 0; + my $pkt_total = 0; + wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, + $pkt_total, undef, $cookie ); + +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_cookie_flow_stats/run.pl b/openflow/regress/projects/black_box/regress/test_cookie_flow_stats/run.pl new file mode 100755 index 00000000..705146b1 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_cookie_flow_stats/run.pl @@ -0,0 +1,151 @@ +#!/usr/bin/perl -w +# test_flow_stats + +use strict; +use OF::Includes; + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + my $port_base = $$options_ref{'port_base'}; + + my $cookie = 0x123456; + + my $hdr_args = { + version => get_of_ver(), + type => $enums{'OFPT_STATS_REQUEST'}, + length => $ofp->sizeof('ofp_stats_request') + + $ofp->sizeof('ofp_flow_stats_request'), + # should generate automatically! + xid => 0x00000000 + }; + + my $match_args = { + wildcards => 0x2003ef, + in_port => 0, + dl_src => [], + dl_dst => [], + dl_vlan => 0, + dl_type => 0x800, + nw_tos => 0, + nw_src => (NF2::IP_hdr::getIP('192.168.200.1'))[0], + nw_dst => (NF2::IP_hdr::getIP('192.168.201.2'))[0], + nw_proto => 0, + tp_src => 0, + tp_dst => 0 + }; + + my $stats_request_args = { + header => $hdr_args, + type => $enums{'OFPST_FLOW'}, + flags => 0 + }; + + my $body_args = { + match => $match_args, + table_id => 0xff, #match all tables + out_port => $enums{'OFPP_NONE'}, + }; + + my $body = $ofp->pack('ofp_flow_stats_request', $body_args ); + + my $stats_request = $ofp->pack( 'ofp_stats_request', $stats_request_args ); + + my $mesg = $stats_request . $body; + + # Send 'stats_request' message + print $sock $mesg; + + # Should add timeout here - will crash if no reply + my $recvd_mesg; + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; + + # Inspect message + my $msg_size = length($recvd_mesg); + + my $msg = $ofp->unpack( 'ofp_stats_reply', $recvd_mesg ); + + #print HexDump ($recvd_mesg); + print Dumper($msg); + + # Verify fields + verify_header( $msg, 'OFPT_STATS_REPLY', $msg_size ); + + #---------------------- + + # add flow mod, send pkt + { + + my $in_port_offset = 0; + my $out_port_offset = 1; + my $wildcards = 0x2003ef, + my $wait = 5; + + #$$options_ref{'send_delay'} = 5; + + forward_simple ( $ofp, $sock, $options_ref, $in_port_offset, + $out_port_offset, $wildcards, 'any', 1, undef, undef, $cookie); + +# my $in_port = $in_port_offset + $$options_ref{'port_base'}; +# my $out_port = $out_port_offset + $$options_ref{'port_base'}; +# +# my $test_pkt = get_default_black_box_pkt_len( $in_port, $out_port, $$options_ref{'pkt_len'} ); +# my $flow_mod_pkt = +# create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $wait, $wildcards ); +# +# print $sock $flow_mod_pkt; +# +# # Give OF switch time to process the flow mod +# usleep($$options_ref{'send_delay'}); +# +# nftest_send( "eth" . ($in_port_offset + 1), $test_pkt->packed ); + } + + sleep .1; + + + # Send 'stats_request' message + print $sock $mesg; + + # Should add timeout here - will crash if no reply + my $recvd_mesg; + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; + + # Inspect message + my $msg_size = length($recvd_mesg); + + my $msg = $ofp->unpack( 'ofp_stats_reply', $recvd_mesg ); + + # Strip off the header from the received message + $recvd_mesg = substr($recvd_mesg, $ofp->sizeof('ofp_stats_reply')); + + # Unpack each of the ofp_flow_stats messages + my $flow_stats_len = $ofp->sizeof('ofp_flow_stats'); + while (length($recvd_mesg) > 0) { + if (length($recvd_mesg) < $flow_stats_len) {\ + die "Error: Partial flow stats message received"; + } + my $flow_stats = $ofp->unpack('ofp_flow_stats', $recvd_mesg); + + push @{$msg->{'body'}}, $flow_stats; + $recvd_mesg = substr($recvd_mesg, $flow_stats->{'length'}); + } + + #print HexDump ($recvd_mesg); + print Dumper($msg); + + # Verify fields + verify_header( $msg, 'OFPT_STATS_REPLY', $msg_size ); + + # Verify the cookie + compare( "stats_reply cookie", $msg->{'body'}->[0]->{'cookie'}, '==', $cookie ); + + + #wait_for_flow_expired_all( $ofp, $sock, $options_ref ); + + +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_delete/run.pl b/openflow/regress/projects/black_box/regress/test_delete/run.pl new file mode 100755 index 00000000..7b594682 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_delete/run.pl @@ -0,0 +1,172 @@ +#!/usr/bin/perl -w +# test_delete + +use strict; +use OF::Includes; + +sub send_expect_exact_with_wildcard { + + my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $out_port2_offset, $max_idle, $pkt_len ) = @_; + + my $in_port = $in_port_offset + $$options_ref{'port_base'}; + my $out_port = $out_port_offset + $$options_ref{'port_base'}; + my $out_port2 = $out_port2_offset + $$options_ref{'port_base'}; + + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + src_port => 70, + dst_port => 80 + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + my $test_pkt_args2 = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + src_port => 170, + dst_port => 180 + }; + my $test_pkt2 = new NF2::UDP_pkt(%$test_pkt_args2); + + # Flow entry -- exact match, $out_port + my $wildcards = 0x0; # exact match + my $flags = 0x0; # don't send flow expiry + my $flow_mod_exact_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); + + # 2nd flow entry -- wildcard match, $out_port2 + $wildcards = $enums{'OFPFW_TP_SRC'} | $enums{'OFPFW_TP_DST'}; # wildcard match (don't care udp src/dst ports) + print "wildcards = $wildcards\n"; + my $flow_mod_wildcard_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port2, $max_idle, $flags, $wildcards ); + + #print HexDump($flow_mod_exact_pkt); + #print HexDump($flow_mod_wildcard_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_exact_pkt; + print "sent flow_mod message (create exact match entry)\n"; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + + print $sock $flow_mod_wildcard_pkt; + print "sent flow_mod message (create wildcard entry)\n"; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + + # Check what's on the switch + #dpctl_show_flows($options_ref); + + # Send a packet - ensure packet comes out desired port + print "Verify packets are forwarded correctly\n"; + nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt->packed ); + nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); + + nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt2->packed ); + nftest_expect( "eth" . ( $out_port2_offset + 1 ), $test_pkt2->packed ); + + print "sent two packets\n"; +} + +sub delete_send_expect { + + my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $out_port2_offset, $max_idle, $pkt_len ) = @_; + + my $in_port = $in_port_offset + $$options_ref{'port_base'}; + my $out_port = $out_port_offset + $$options_ref{'port_base'}; + my $out_port2 = $out_port2_offset + $$options_ref{'port_base'}; + + # in_port refers to the flow mod entry's input + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + src_port => 70, + dst_port => 80 + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + my $test_pkt_args2 = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + src_port => 170, + dst_port => 180 + }; + my $test_pkt2 = new NF2::UDP_pkt(%$test_pkt_args2); + + my $wildcards = $enums{'OFPFW_TP_SRC'} | $enums{'OFPFW_TP_DST'}; # wildcard match (don't care udp src/dst ports) + my $flags = 0x0; # don't send flow expiry + my $flow_mod_wildcard_pkt = + create_flow_mod_from_udp_action( $ofp, $test_pkt2, $in_port, $out_port2, $max_idle, + $flags, $wildcards, "OFPFC_DELETE" ); + + #print HexDump($flow_mod_exact_pkt); + #print HexDump($flow_mod_wildcard_pkt); + + # Send 'flow_mod' message (delete wildcard entry without STRICT) + print $sock $flow_mod_wildcard_pkt; + print "sent flow_mod message (delete wildcard entry)\n"; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + # Give extra time, wildcard delete takes more time - Jean II + usleep($$options_ref{'send_delay'}); + + # Check what's on the switch + #dpctl_show_flows($options_ref); + + # Send a packet + print "Verify packets are forwarded correctly i.e., fwded to contoller\n"; + nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt->packed ); + nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt2->packed ); + + # both pkts should go to the controller + wait_for_one_packet_in( $ofp, $sock, $pkt_len, $test_pkt->packed ); + wait_for_one_packet_in( $ofp, $sock, $pkt_len, $test_pkt2->packed ); + +} + +sub test_delete { + + my ( $ofp, $sock, $options_ref, $i, $j, $o_port2, $wildcards ) = @_; + + my $max_idle = $$options_ref{'max_idle'}; + my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_total = $$options_ref{'pkt_total'}; + + print "sending from $i to $j & $i to $o_port2 -- both should match\n"; + send_expect_exact_with_wildcard( $ofp, $sock, $options_ref, $i, $j, $o_port2, $max_idle, $pkt_len ); + + # wait for switch to process last packets + usleep($$options_ref{'send_delay'}); + + print "delete wildcard entry (without STRICT) and send packets again\n"; + delete_send_expect( $ofp, $sock, $options_ref, $i, $j, $o_port2, $max_idle, $pkt_len ); +} + +sub my_test { + + my ($sock, $options_ref) = @_; + + # send from every port to every other port + for_all_port_triplets( $ofp, $sock, $options_ref, \&test_delete, 0x0); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_delete_send_flow_exp/run.pl b/openflow/regress/projects/black_box/regress/test_delete_send_flow_exp/run.pl new file mode 100755 index 00000000..6e093fcc --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_delete_send_flow_exp/run.pl @@ -0,0 +1,104 @@ +#!/usr/bin/perl -w +# test_delete + +use strict; +use OF::Includes; + +sub my_test { + + my ($sock, $options_ref) = @_; + + my $in_port = $$options_ref{'port_base'}; + my $out_port = $in_port + 1; + + my $test_pkt = get_default_black_box_pkt( $in_port, $out_port, $$options_ref{'pkt_len'} ); + + my $max_idle = 0x0; # second before flow expiration -- never time out + my $wildcards = 0x0; # exact match + # Create a flow mod without expiry + my $flags = 0x0; # don't send flow expiry + my $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); + print "send flow mode without expiry\n"; + print $sock $flow_mod_pkt; + + # Delete the flow and verify that we don't see an expiry + $flow_mod_pkt = + create_flow_mod_from_udp_action( $ofp, $test_pkt, $in_port, $out_port, $max_idle, + $flags, $wildcards, "OFPFC_DELETE" ); + print $sock $flow_mod_pkt; + + my $sel = IO::Select->new($sock); + if ($sel->can_read(2)) { + print "Error: was not expecting a message from the switch\n"; + exit 1; + } + + # Create a flow mod with expiry + $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry + $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); + print "send flow mode with expiry\n"; + print $sock $flow_mod_pkt; + + # Delete the flow and verify that we do see an expiry + $flags = 0x0; # Reset the flags to zero. Should not matter as it + # should only depend on the flags when the flow was installed. + $flow_mod_pkt = + create_flow_mod_from_udp_action( $ofp, $test_pkt, $in_port, $out_port, $max_idle, + $flags, $wildcards, "OFPFC_DELETE" ); + print $sock $flow_mod_pkt; + + my $pkt_len = 0; + my $pkt_total = 0; + wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); + + # Redo the same test with a few packets to make sure stats are correct + # Jean II + + # Create a flow mod with expiry + $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry + $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); + print "send flow mode with expiry and with 3 packets\n"; + print $sock $flow_mod_pkt; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + usleep($$options_ref{'send_delay'}); + + # Send 3 packets, because first packet can be "special" - Jean II + # We should be using $options{'pkt_total'}, but that is stuck at 1 + nftest_send("eth" . ($in_port), $test_pkt->packed); + nftest_send("eth" . ($in_port), $test_pkt->packed); + nftest_send("eth" . ($in_port), $test_pkt->packed); + + # expect 3 packets + print "expect 3 packets\n"; + nftest_expect("eth" . ($out_port), $test_pkt->packed); + nftest_expect("eth" . ($out_port), $test_pkt->packed); + nftest_expect("eth" . ($out_port), $test_pkt->packed); + + # Wait for stats to refresh + sleep($$options_ref{'max_idle'}); + #dpctl_show_flows($options_ref); + + # Delete the flow and verify that we do see an expiry + $flags = 0x0; # Reset the flags to zero. Should not matter as it + # should only depend on the flags when the flow was installed. + $flow_mod_pkt = + create_flow_mod_from_udp_action( $ofp, $test_pkt, $in_port, $out_port, $max_idle, + $flags, $wildcards, "OFPFC_DELETE" ); + print $sock $flow_mod_pkt; + + # And now check the stats in the flow removed message... + my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_total = 3; + wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); + + + +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_delete_strict/run.pl b/openflow/regress/projects/black_box/regress/test_delete_strict/run.pl new file mode 100755 index 00000000..8290dae9 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_delete_strict/run.pl @@ -0,0 +1,175 @@ +#!/usr/bin/perl -w +# test_delete_strict + +use strict; +use OF::Includes; + +sub send_expect_exact_with_wildcard { + + my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $out_port2_offset, $max_idle, $pkt_len ) = @_; + + my $in_port = $in_port_offset + $$options_ref{'port_base'}; + my $out_port = $out_port_offset + $$options_ref{'port_base'}; + my $out_port2 = $out_port2_offset + $$options_ref{'port_base'}; + + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + src_port => 70, + dst_port => 80 + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + my $test_pkt_args2 = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + src_port => 170, + dst_port => 180 + }; + my $test_pkt2 = new NF2::UDP_pkt(%$test_pkt_args2); + + # Flow entry -- exact match, $out_port + my $wildcards = 0x0; # exact match + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; + my $flow_mod_exact_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); + + # 2nd flow entry -- wildcard match, $out_port2 + $wildcards = $enums{'OFPFW_TP_SRC'} | $enums{'OFPFW_TP_DST'}; # wildcard match (don't care udp src/dst ports) + my $flow_mod_wildcard_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port2, $max_idle, $flags, $wildcards ); + + #print HexDump($flow_mod_exact_pkt); + #print HexDump($flow_mod_wildcard_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_exact_pkt; + print "sent flow_mod message (create exact match entry)\n"; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + + print $sock $flow_mod_wildcard_pkt; + print "sent flow_mod message (create wildcard entry)\n"; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + + # Check what's on the switch + #dpctl_show_flows($options_ref); + + # Send a packet - ensure packet comes out desired port + print "Verify packets are forwarded correctly\n"; + nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt->packed ); + nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); + + nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt2->packed ); + nftest_expect( "eth" . ( $out_port2_offset + 1 ), $test_pkt2->packed ); +} + +sub delete_strict_send_expect { + + my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $out_port2_offset, $max_idle, $pkt_len ) = @_; + + my $in_port = $in_port_offset + $$options_ref{'port_base'}; + my $out_port = $out_port_offset + $$options_ref{'port_base'}; + my $out_port2 = $out_port2_offset + $$options_ref{'port_base'}; + + # in_port refers to the flow mod entry's input + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + src_port => 70, + dst_port => 80 + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + my $test_pkt_args2 = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + src_port => 170, + dst_port => 180 + }; + my $test_pkt2 = new NF2::UDP_pkt(%$test_pkt_args2); + + my $wildcards = $enums{'OFPFW_TP_SRC'} | $enums{'OFPFW_TP_DST'}; # wildcard match (don't care udp src/dst ports) + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; + my $flow_mod_wildcard_pkt = + + # delete_strict_from_udp( $ofp, $test_pkt, $in_port, $out_port2, $wildcards ); + create_flow_mod_from_udp_action( $ofp, $test_pkt, $in_port, $out_port2, $max_idle, $flags, $wildcards, + 'OFPFC_DELETE_STRICT' ); + + #print HexDump($flow_mod_exact_pkt); + #print HexDump($flow_mod_wildcard_pkt); + + # Send 'flow_mod' message (delete wildcard entry with STRICT) + print $sock $flow_mod_wildcard_pkt; + print "sent flow_mod message (delete (strict) wildcard entry)\n"; + + # Expect a flow expire due to the delete + wait_for_flow_expired_readone( $ofp, $sock, $options_ref, $pkt_len, 1 ); + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + # Give extra time, delete takes more time - Jean II + usleep($$options_ref{'send_delay'}); + + # Check what's on the switch + #dpctl_show_flows($options_ref); + + # Send a packet + print + "Verify packets are forwarded correctly i.e., one fwded to contoller and one (exact match) fwd to the specified port\n"; + nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt->packed ); + nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); + + nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt2->packed ); + wait_for_one_packet_in( $ofp, $sock, $pkt_len, $test_pkt2->packed ); +} + +sub test_delete_strict { + + my ( $ofp, $sock, $options_ref, $i, $j, $o_port2, $wildcards ) = @_; + + my $max_idle = $$options_ref{'max_idle'}; + my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_total = $$options_ref{'pkt_total'}; + + print "sending from $i to $j & $i to $o_port2 -- both should match\n"; + send_expect_exact_with_wildcard( $ofp, $sock, $options_ref, $i, $j, $o_port2, $max_idle, $pkt_len ); + + # wait for switch to process last packets + usleep($$options_ref{'send_delay'}); + + print "delete wildcard entry (with STRICT) \n"; + print "sending from $i to $j & $i to $o_port2 "; + delete_strict_send_expect( $ofp, $sock, $options_ref, $i, $j, $o_port2, $max_idle, $pkt_len ); + wait_for_flow_expired_readone( $ofp, $sock, $options_ref, $pkt_len, 2 ); +} + +sub my_test { + + my ($sock, $options_ref) = @_; + + # send from every port to every other port + for_all_port_triplets( $ofp, $sock, $options_ref, \&test_delete_strict, 0x0); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_drop_exact/run.pl b/openflow/regress/projects/black_box/regress/test_drop_exact/run.pl new file mode 100755 index 00000000..98180d18 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_drop_exact/run.pl @@ -0,0 +1,54 @@ +#!/usr/bin/perl -w +# test_drop_exact + +use strict; +use OF::Includes; + +#sub drop_simple { +# +# my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $wildcards, $nowait ) = @_; +# +# my $in_port = $in_port_offset + $$options_ref{'port_base'}; +# my $out_port = $out_port_offset + $$options_ref{'port_base'}; +# # print "drop_simple : ports = ".($in_port).",".($out_port); +# +# my $test_pkt = get_default_black_box_pkt_len( $in_port, $out_port, $$options_ref{'pkt_len'} ); +# +# #print HexDump ( $test_pkt->packed ); +# +# my $flow_mod_pkt = +# create_flow_drop_from_udp_action( $ofp, $test_pkt, $in_port, $out_port, $$options_ref{'max_idle'}, $wildcards, 'drop' ); +# +# #print HexDump($flow_mod_pkt); +# #print Dumper($flow_mod_pkt); +# +# # Send 'flow_mod' message +# syswrite( $sock, $flow_mod_pkt ); +# print "sent flow_mod message\n"; +# +# # Give OF switch time to process the flow mod +# usleep($$options_ref{'send_delay'}); +# +# nftest_send( "eth" . ($in_port_offset + 1), $test_pkt->packed); +# +# # We should expect no message at all on any port ! - Jean II +# +# if (not defined($nowait)) { +# print "wait \n"; +# wait_for_flow_expired_all( $ofp, $sock, $options_ref ); +# } +#} + +sub drop_port { + + forward_simple(@_, 'drop'); +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_port_pairs( $ofp, $sock, $options_ref, \&drop_port, 0x0); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_failover_close/run.pl b/openflow/regress/projects/black_box/regress/test_failover_close/run.pl new file mode 100755 index 00000000..06fd9a71 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_failover_close/run.pl @@ -0,0 +1,68 @@ +#!/usr/bin/perl -w + +# Simple two-controller failover test +# +# For this test to work, the switch must be set up to use our +# two "controllers", e.g. +# +# ofprotocol --controller=tcp:127.0.0.1:6633,tcp:127.0.0.1:6634 +# +# If you use different ports than the defaults, then you must +# pass the --controller option into this script as well. +# +# Failover test 2: Controller is fine, but closes connection +# +# For this test, we accept the Hello sequence and then close +# the socket. Then we listen for a failover connection on the +# second socket. +# + +use strict; +use OF::Includes; + +# Save ARGV for future reference +my @ARGS = @ARGV; + +my $test = "Failover test 2 (connection closed)"; + +print "$test phase 1: calling run_black_box_test with @ARGV\n"; + +# Start up, say Hello, and close connection +sub close_failover_test_phase_1 { + my ($sock) = @_; + print "$test: Got socket $sock\n"; + print "$test: Finished Hello sequence on first controller\n"; + print "$test: Closing socket\n"; + $sock->close(); +} + +run_black_box_test( \&close_failover_test_phase_1, \@ARGV, 1); # 1 -> don't exit + +# Now, attempt to open up the second controller connection, and +# hope that we fail over + +# Restore ARGV +@ARGV = @ARGS; + +# If no controllers specified, use default +if (not "@ARGV" =~ "--controller") { + push( @ARGV, "--controller=" . nftest_default_controllers() ); +} + +# Replace --controller=foo,bar with --controller=bar so that +# run_black_box_test() will use bar's port rather than foo's +for (my $i = 0; $i < @ARGV; $i++) { + if ($ARGV[$i] =~ /controller=[^,]*,([^\s]+)/ ) { + print "failover_startup: got controller $1\n"; + $ARGV[$i] = "--controller=$1"; + } +} + + +sub close_failover_test_phase_2 { + print "$test: Failover to second controller succeeded\n"; +} + +print "$test: Calling run_black_box_test with @ARGV\n"; +run_black_box_test( \&close_failover_test_phase_2, \@ARGV ); # do exit this time + diff --git a/openflow/regress/projects/black_box/regress/test_failover_startup/run.pl b/openflow/regress/projects/black_box/regress/test_failover_startup/run.pl new file mode 100755 index 00000000..7bfee7aa --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_failover_startup/run.pl @@ -0,0 +1,53 @@ +#!/usr/bin/perl + +# Simple two-controller failover test +# +# For this test to work, the switch must be set up to use our +# two "controllers", e.g. +# +# ofprotocol --controller=tcp:127.0.0.1:6633,tcp:127.0.0.1:6634 +# +# If you use different ports than the defaults, then you must +# pass the --controller option into this script as well. +# +# Failover Test 1: Startup Failover +# +# For this test, we listen on the second controller port rather +# than the first. +# + +use strict; +use OF::Includes; +use Getopt::Long; + +my $test="Failover test 1 (startup failover)"; + +my $controllers; + +# Remove '--controller' from the option list... - Jean II +Getopt::Long::Configure( 'pass_through' ); +GetOptions( + "controller=s" => \$controllers +); +if (!defined($controllers)) +{ + # If no controllers specified, use default + $controllers = nftest_default_controllers(); +} +Getopt::Long::Configure( 'default' ); + +# Get controller +my @controller_array = split(/,/, $controllers); +my $failover_controller = @controller_array[1]; + +# Push back a controller string +push( @ARGV, "--controller=$failover_controller" ); + +print "$test: Calling run_black_box_test with @ARGV\n"; + +sub startup_failover_test { + print "$test: Failed over successfully\n"; +} + +run_black_box_test( \&startup_failover_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_failover_stop_responding/run.pl b/openflow/regress/projects/black_box/regress/test_failover_stop_responding/run.pl new file mode 100755 index 00000000..50a4a475 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_failover_stop_responding/run.pl @@ -0,0 +1,65 @@ +#!/usr/bin/perl -w + +# Simple two-controller failover test +# +# For this test to work, the switch must be set up to use our +# two "controllers", e.g. +# +# ofprotocol --controller=tcp:127.0.0.1:6633,tcp:127.0.0.1:6634 +# +# If you use different ports than the defaults, then you must +# pass the --controller option into this script as well. +# +# Failover test 3: Controller is fine, but stops responding +# +# For this test, we accept the Hello sequence on the first port +# but then listen for a failover connection on the second port. +# + +use strict; +use OF::Includes; + +# Save ARGV for future reference +my @ARGS = @ARGV; + +my $test="Failover test 3 (controller stops responding)"; + +print "$test phase 1: calling run_black_box_test with @ARGV\n"; + +# Start up, say Hello, and close connection +sub stop_responding_test_phase_1 { + my ($sock) = @_; + print "$test: Got socket $sock\n"; + print "$test: Finished Hello sequence on first controller\n"; + print "$test: Not closing socket\n"; + print "$test: Invoking phase 2\n"; + stop_responding_phase_2(); +} + +run_black_box_test( \&stop_responding_test_phase_1, \@ARGV, 1); # 1 -> don't exit + +sub stop_responding_phase_2 { + + # Now, attempt to open up the second controller connection, and + # hope that we fail over + + # Restore ARGV + @ARGV = @ARGS; + + # If no controllers specified, use default + if (not "@ARGV" =~ "--controller") { + push( @ARGV, "--controller=" . nftest_default_controllers() ); + } + + # Replace --controller=foo,bar with --controller=bar so that + # run_black_box_test() will use bar's port rather than foo's + for (my $i = 0; $i < @ARGV; $i++) { + if ($ARGV[$i] =~ /controller=[^,]*,([^\s]+)/ ) { + print "$test: got controller $1\n"; + $ARGV[$i] = "--controller=$1"; + } + } + + print "$test: Calling run_black_box_test with @ARGV\n"; + run_black_box_test( \&close_failover_test_phase_2, \@ARGV ); # do exit this time +} diff --git a/openflow/regress/projects/black_box/regress/test_flow_expired/run.pl b/openflow/regress/projects/black_box/regress/test_flow_expired/run.pl new file mode 100755 index 00000000..97ea35cc --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_flow_expired/run.pl @@ -0,0 +1,34 @@ +#!/usr/bin/perl -w +# test_flow_expired + +use strict; +use OF::Includes; + +sub my_test { + + my ($sock, $options_ref) = @_; + + my $in_port = $$options_ref{'port_base'}; + my $out_port = $in_port + 1; + + my $test_pkt = get_default_black_box_pkt( $in_port, $out_port); + + my $max_idle = 0x1; # second before flow expiration + my $wildcards = 0x0; # exact match + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry + my $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); + + #print HexDump($pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + + my $pkt_len = 0; + my $pkt_total = 0; + wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); + +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_flow_expired_idle_timeout/run.pl b/openflow/regress/projects/black_box/regress/test_flow_expired_idle_timeout/run.pl new file mode 100755 index 00000000..5fa74924 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_flow_expired_idle_timeout/run.pl @@ -0,0 +1,34 @@ +#!/usr/bin/perl -w +# test_flow_expired + +use strict; +use OF::Includes; + +sub my_test { + + my ($sock, $options_ref) = @_; + + my $in_port = $$options_ref{'port_base'}; + my $out_port = $in_port + 1; + + my $test_pkt = get_default_black_box_pkt( $in_port, $out_port); + + my $max_idle = 0x1; # second before flow expiration + my $wildcards = 0x0; # exact match + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; + my $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); + + #print HexDump($pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + + my $pkt_len = 0; + my $pkt_total = 0; + wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total, $max_idle ); + +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_flow_expired_precision/run.pl b/openflow/regress/projects/black_box/regress/test_flow_expired_precision/run.pl new file mode 100755 index 00000000..798f6b89 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_flow_expired_precision/run.pl @@ -0,0 +1,66 @@ +#!/usr/bin/perl -w +# test_flow_expired +# This test checks if the flow duration time is in a reasonable range. +# This test assumes a reference switch as a target. +# The switch polls flow expiration every 1 sec with jitter, +# so we should expect 1sec difference for flow_duration. + +use strict; +use OF::Includes; + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + my $in_port = $$options_ref{'port_base'}; + my $out_port = $in_port + 1; + + my $test_pkt = get_default_black_box_pkt( $in_port, $out_port ); + + my $max_idle = 0x1; # second before flow expiration + my $wildcards = 0x0; # exact match + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry + my $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, + $flags, $wildcards ); + + #print HexDump($pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + + my $pkt_len = 0; + my $pkt_total = 0; + + my $read_size = 1512; + + my $recvd_mesg; + sysread( $sock, $recvd_mesg, $read_size ) + || die "Failed to receive ofp_flow_removed message: $!"; + + # Inspect message + my $msg_size = length($recvd_mesg); + my $expected_size = $ofp->sizeof('ofp_flow_removed'); + compare( "ofp_flow_removed msg size", + length($recvd_mesg), '==', $expected_size ); + + my $msg = $ofp->unpack( 'ofp_flow_removed', $recvd_mesg ); + + print Dumper($msg); + + my $sample_period = 1; + + compare( "ofp_flow_removed packet_count", + $$msg{'packet_count'}, '==', $pkt_total ); + print "Duretion_sec : $$msg{'duration_sec'} sec\n"; + print "Duration_nsec: $$msg{'duration_nsec'} nano sec\n"; + + if (($$msg{'duration_sec'} < $max_idle) + || ($$msg{'duration_sec'} > ($max_idle + $sample_period))) { + die "Error, duration_sec out of acceptable range"; + } + +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_flow_expired_send_flow_exp/run.pl b/openflow/regress/projects/black_box/regress/test_flow_expired_send_flow_exp/run.pl new file mode 100755 index 00000000..4a47caef --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_flow_expired_send_flow_exp/run.pl @@ -0,0 +1,44 @@ +#!/usr/bin/perl -w +# test_flow_expired + +use strict; +use OF::Includes; +use IO::Select; + +sub my_test { + + my ($sock, $options_ref) = @_; + + my $in_port = $$options_ref{'port_base'}; + my $out_port = $in_port + 1; + + my $test_pkt = get_default_black_box_pkt( $in_port, $out_port); + + my $max_idle = 0x1; # second before flow expiration + my $wildcards = 0x0; # exact match + # Create a flow mod without expiry + my $flags = 0x0; # don't send flow expiry + my $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); + print $sock $flow_mod_pkt; + + my $sel = IO::Select->new($sock); + if ($sel->can_read(2 * $max_idle)) { + print "Error: was not expecting a message from the switch\n"; + exit 1; + } + + # Create a flow mod with expiry + $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry + $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); + print $sock $flow_mod_pkt; + + my $pkt_len = 0; + my $pkt_total = 0; + wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); + +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_flow_mod_check/run.pl b/openflow/regress/projects/black_box/regress/test_flow_mod_check/run.pl new file mode 100755 index 00000000..1c0b7f76 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_flow_mod_check/run.pl @@ -0,0 +1,83 @@ +#!/usr/bin/perl -w +# test_flow_mod_check + +use strict; +use OF::Includes; + +sub wait_for_flow_overlap_error { + my ($ofp, $sock, $flow_mod_pkt) = @_; + my $rcvd_msg; + + sysread($sock, $rcvd_msg, 1512); + + my $msg_size = length($rcvd_msg); + my $expected_size = $ofp->sizeof('ofp_error_msg') + length($flow_mod_pkt); + compare("msg size", $msg_size, '==', $expected_size); + + my $msg = $ofp->unpack('ofp_error_msg', $rcvd_msg); + verify_header($msg, 'OFPT_ERROR', $msg_size); + + compare("error type", $$msg{'type'}, '==', $enums{'OFPET_FLOW_MOD_FAILED'}); + compare("error code", $$msg{'code'}, '==', $enums{'OFPFMFC_OVERLAP'}); +} + +sub my_test { + my ($sock, $options_ref) = @_; + + my $in_port = $$options_ref{'port_base'}; + my $out_port_1 = $in_port + 1; + my $out_port_2 = $in_port + 2; + my $out_port_3 = $in_port + 3; + + my $test_pkt = get_default_black_box_pkt($in_port, $out_port_1); + + + my $wildcards = 0x0c0; + my $flags = $enums{'OFPFF_CHECK_OVERLAP'}; + my $max_idle = 0x0; # never expire + my $flow_mod_pkt = create_flow_mod_from_udp($ofp, $test_pkt, $in_port, $out_port_1, $max_idle, $flags, $wildcards); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + + # change the wildcard and send again. this should fail + $wildcards = 0x0c1; + my $flags = $enums{'OFPFF_CHECK_OVERLAP'}; + $flow_mod_pkt = create_flow_mod_from_udp($ofp, $test_pkt, $in_port+1, $out_port_2, $max_idle, $flags, $wildcards); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + + wait_for_flow_overlap_error($ofp, $sock, $flow_mod_pkt); + + # Start with coarse granularity flow + # edge-case bug reported by Justin + # https://mailman.stanford.edu/pipermail/openflow-dev/2009-November/000529.html + $wildcards = 0x0c1; + $flags = 0x0; + $flow_mod_pkt = create_flow_mod_from_udp($ofp, $test_pkt, $in_port, $out_port_1, $max_idle, $flags, $wildcards); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + + # change the wildcard and send again. this should fail + $wildcards = 0x0c0; + $flags = $enums{'OFPFF_CHECK_OVERLAP'}; + $flow_mod_pkt = create_flow_mod_from_udp($ofp, $test_pkt, $in_port+1, $out_port_2, $max_idle, $flags, $wildcards); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + + wait_for_flow_overlap_error($ofp, $sock, $flow_mod_pkt); + + + +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_flow_mod_latency/run-port3.pl b/openflow/regress/projects/black_box/regress/test_flow_mod_latency/run-port3.pl new file mode 100644 index 00000000..204873b7 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_flow_mod_latency/run-port3.pl @@ -0,0 +1,136 @@ +#!/usr/bin/perl -w +# test_flow_mod_latency +# +# Don't include this test as part of the official test suite, +# as it is not supposed to pass... +# +# Run it like this : +# ./bin/of_hp_test.pl --testPath=black_box/regress/test_flow_mod_latency/run.pl +# +# Check the number of packets received : +# tcpdump -p -i eth11 -w stanford.test.log +# tcpdump -r stanford.test.log | wc +# +# On the HP, it requires increasing the SW rate limiter : +# openflow 9 sw-rate 5000 +# +# Jean II + +use strict; +use OF::Includes; + +sub forward_flow_mod_latency { + + my ($sock, $options_ref) = @_; + my $in_port = $$options_ref{'port_base'}; + my $out_port = $in_port + 1; + my $fallback_port = $out_port + 1; + + my $len = $$options_ref{'pkt_len'}; + my $wildcards = 0x0; # exact match + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; + my $pkt_args; + my $test_pkt; + my $flow_mod_pkt; + my $i; + + if (1) { + # Create a flow mod to track all packets sent to the controller + # We create a wildcard on both transport port, that sends + # packets to the controller - Jean II + $pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $len, + src_port => 0, + dst_port => 0 + }; + $test_pkt = new NF2::UDP_pkt(%$pkt_args); + $wildcards = $enums{'OFPFW_TP_SRC'} | $enums{'OFPFW_TP_DST'}; + print"wildcards = $wildcards\n"; + # Full experiment is around 15s + $flow_mod_pkt = create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $fallback_port, 25, $flags, $wildcards ); + syswrite( $sock, $flow_mod_pkt ); + print "sent flow_mod message with wildcard\n"; + + # Make sure the flow mod is properly inserted and the + # OpenFlow instance properly started. The OpenFlow instance + # takes time to get started, we want to make sure this is + # not a factor. Jean II + sleep(1); + + # No more wildcards + $wildcards = 0x0; # exact match + } + + # Let's create 100 sequencial connections - Jean II + for ( my $c = 0 ; $c < 100 ; $c++ ) { + + # Packets for creating the flow mod + $pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $len, + src_port => 2000 + $c, + dst_port => 4000 + $c + }; + $test_pkt = new NF2::UDP_pkt(%$pkt_args); + + # Let's create a long lived flow mod + $flow_mod_pkt = create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, 20, $flags, $wildcards ); + + # Send 'flow_mod' message + syswrite( $sock, $flow_mod_pkt ); + print "sent flow_mod message for connection $c\n"; + + # Test packet to be sent - should match flow mod + $pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $len, + src_port => 2000 + $c, + dst_port => 4000 + $c + }; + $test_pkt = new NF2::UDP_pkt(%$pkt_args); + + # For this test, the TCAM is much slower. Wait a bit more + # to get more interesting results. I also increased pkt count. + # Jean II + usleep(20000); + + # Max in SW is around 5000 pkts/sec + # Note : default rate limiter value is 100 pkts/sec, which is + # one packet every 10s, so you can't run at default value + # Send 15 packets as a short burst over 60ms + for ($i = 0 ; $i < 15 ; $i++ ) { + + # Wait 4 ms between packets + usleep(4000); + + # Send test packet + nftest_send( "eth" . ($in_port), $test_pkt->packed ); + + # This does not block, so we are good... + nftest_expect( "eth" . ($out_port), $test_pkt->packed ); + } + + # We don't wait for flow expiry, that's too long waiting - Jean II + } + + # Wait for stats to refresh + # For most flow mod, we should be about half life, which means + # they have not expired yet, and have already got stats a few time. + sleep(6); + dpctl_show_flows($options_ref); +} + +run_black_box_test( \&forward_flow_mod_latency, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_flow_mod_latency/run.pl b/openflow/regress/projects/black_box/regress/test_flow_mod_latency/run.pl new file mode 100755 index 00000000..49789383 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_flow_mod_latency/run.pl @@ -0,0 +1,129 @@ +#!/usr/bin/perl -w +# test_flow_mod_latency +# +# Don't include this test as part of the official test suite, +# as it is not supposed to pass... +# +# Run it like this : +# ./bin/of_hp_test.pl --testPath=black_box/regress/test_flow_mod_latency/run.pl +# +# Check the number of packets received : +# tcpdump -p -i eth11 -w stanford.test.log +# tcpdump -r stanford.test.log | wc +# +# On the HP, it requires increasing the SW rate limiter : +# openflow 9 sw-rate 5000 +# +# Jean II + +use strict; +use OF::Includes; + +sub forward_flow_mod_latency { + + my ($sock, $options_ref) = @_; + my $in_port = $$options_ref{'port_base'}; + my $out_port = $in_port + 1; + + my $len = $$options_ref{'pkt_len'}; + my $wildcards = 0x0; # exact match + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; + my $pkt_args; + my $test_pkt; + my $flow_mod_pkt; + my $i; + + if (1) { + # Create a flow mod to track all packets sent to the controller + # We create a wildcard on both transport port, that sends + # packets to the controller - Jean II + $pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $len, + src_port => 0, + dst_port => 0 + }; + $test_pkt = new NF2::UDP_pkt(%$pkt_args); + $wildcards = $enums{'OFPFW_TP_SRC'} | $enums{'OFPFW_TP_DST'}; + print"wildcards = $wildcards\n"; + $flow_mod_pkt = create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $enums{'OFPP_CONTROLLER'}, 20, $flags, $wildcards ); + syswrite( $sock, $flow_mod_pkt ); + print "sent flow_mod message with wildcard\n"; + + # Make sure the flow mod is properly inserted and the + # OpenFlow instance properly started. The OpenFlow instance + # takes time to get started, we want to make sure this is + # not a factor. Jean II + sleep(1); + + # No more wildcards + $wildcards = 0x0; # exact match + } + + # Let's create 100 sequencial connections - Jean II + for ( my $c = 0 ; $c < 100 ; $c++ ) { + + # Packets for creating the flow mod + $pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $len, + src_port => 2000 + $c, + dst_port => 4000 + $c + }; + $test_pkt = new NF2::UDP_pkt(%$pkt_args); + + # Let's create a long lived flow mod + $flow_mod_pkt = create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, 15, $flags, $wildcards ); + + # Send 'flow_mod' message + syswrite( $sock, $flow_mod_pkt ); + print "sent flow_mod message for connection $c\n"; + + # Test packet to be sent - should match flow mod + $pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $len, + src_port => 2000 + $c, + dst_port => 4000 + $c + }; + $test_pkt = new NF2::UDP_pkt(%$pkt_args); + + # Max in SW is around 5000 pkts/sec + # Note : default rate limiter value is 100 pkts/sec, which is + # one packet every 10s, so you can't run at default value + # Send 5 packets as a short burst over 20ms + for ($i = 0 ; $i < 5 ; $i++ ) { + + # Wait 4 ms between packets + usleep(4000); + + # Send test packet + nftest_send( "eth" . ($in_port), $test_pkt->packed ); + + # This does not block, so we are good... + nftest_expect( "eth" . ($out_port), $test_pkt->packed ); + } + + # We don't wait for flow expiry, that's too long waiting - Jean II + } + + # Wait for stats to refresh + # For most flow mod, we should be about half life, which means + # they have not expired yet, and have already got stats a few time. + sleep(6); + dpctl_show_flows($options_ref); +} + +run_black_box_test( \&forward_flow_mod_latency, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_flow_stats/run.pl b/openflow/regress/projects/black_box/regress/test_flow_stats/run.pl new file mode 100755 index 00000000..eeea50a6 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_flow_stats/run.pl @@ -0,0 +1,145 @@ +#!/usr/bin/perl -w +# test_flow_stats + +use strict; +use OF::Includes; + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + my $port_base = $$options_ref{'port_base'}; + + my $hdr_args = { + version => get_of_ver(), + type => $enums{'OFPT_STATS_REQUEST'}, + length => $ofp->sizeof('ofp_stats_request') + $ofp->sizeof('ofp_flow_stats_request'), # should generate automatically! + xid => 0x00000000 + }; + + my $match_args = { + wildcards => 0x3ef, + in_port => 0, + dl_src => [], + dl_dst => [], + dl_vlan => 0, + dl_type => 0x800, + nw_src => (NF2::IP_hdr::getIP('192.168.200.1'))[0], + nw_dst => (NF2::IP_hdr::getIP('192.168.201.2'))[0], + nw_proto => 0, + tp_src => 0, + tp_dst => 0 + }; + + my $stats_request_args = { + header => $hdr_args, + type => $enums{'OFPST_FLOW'}, + flags => 0 + }; + + my $body_args = { + match => $match_args, + table_id => 0xff, #match all tables + out_port => $enums{'OFPP_NONE'}, + }; + + my $body = $ofp->pack('ofp_flow_stats_request', $body_args ); + + my $stats_request = $ofp->pack( 'ofp_stats_request', $stats_request_args ); + + my $mesg = $stats_request . $body; + + # Send 'stats_request' message + print $sock $mesg; + + # Should add timeout here - will crash if no reply + my $recvd_mesg; + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; + + # Inspect message + my $msg_size = length($recvd_mesg); + + my $msg = $ofp->unpack( 'ofp_stats_reply', $recvd_mesg ); + + #print HexDump ($recvd_mesg); + print Dumper($msg); + + # Verify fields + verify_header( $msg, 'OFPT_STATS_REPLY', $msg_size ); + + #---------------------- + + # add flow mod, send pkt + { + + my $in_port_offset = 0; + my $out_port_offset = 1; + my $wildcards = 0x3ef; + my $wait = 5; + + #$$options_ref{'send_delay'} = 5; + + forward_simple ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $wildcards, 'any', 1); + +# my $in_port = $in_port_offset + $$options_ref{'port_base'}; +# my $out_port = $out_port_offset + $$options_ref{'port_base'}; +# +# my $test_pkt = get_default_black_box_pkt_len( $in_port, $out_port, $$options_ref{'pkt_len'} ); +# my $flow_mod_pkt = +# create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $wait, $wildcards ); +# +# print $sock $flow_mod_pkt; +# +# # Give OF switch time to process the flow mod +# usleep($$options_ref{'send_delay'}); +# +# nftest_send( "eth" . ($in_port_offset + 1), $test_pkt->packed ); + } + + sleep .1; + + + # Send 'stats_request' message + print $sock $mesg; + + # Should add timeout here - will crash if no reply + my $recvd_mesg; + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; + + # Inspect message + my $msg_size = length($recvd_mesg); + + my $msg = $ofp->unpack( 'ofp_stats_reply', $recvd_mesg ); + + # Strip off the header from the received message + $recvd_mesg = substr($recvd_mesg, $ofp->sizeof('ofp_stats_reply')); + + # Unpack each of the ofp_flow_stats messages + my $flow_stats_len = $ofp->sizeof('ofp_flow_stats'); + while (length($recvd_mesg) > 0) { + if (length($recvd_mesg) < $flow_stats_len) {\ + die "Error: Partial flow stats message received"; + } + my $flow_stats = $ofp->unpack('ofp_flow_stats', $recvd_mesg); + + push @{$msg->{'body'}}, $flow_stats; + $recvd_mesg = substr($recvd_mesg, $flow_stats->{'length'}); + } + + #print HexDump ($recvd_mesg); + print Dumper($msg); + + # Verify fields + verify_header( $msg, 'OFPT_STATS_REPLY', $msg_size ); + + # Ensure that we got back one ofp_flow_stats body + compare( "stats_reply flow_stats count", scalar(@{$msg->{'body'}}), '==', 1 ); + + + #wait_for_flow_expired_all( $ofp, $sock, $options_ref ); + + +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_flow_stats_precision/run.pl b/openflow/regress/projects/black_box/regress/test_flow_stats_precision/run.pl new file mode 100755 index 00000000..06dc1ae5 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_flow_stats_precision/run.pl @@ -0,0 +1,191 @@ +#!/usr/bin/perl -w +# test_flow_stats +# This test assumes a lightly loaded switch that can measure and reply to +# flow stats requests within 500ms of receiving the request. + +use strict; +use OF::Includes; + +sub my_test { + + my ( $sock, $options_ref ) = @_; + my $time_threshold = 500000000; + my $port_base = $$options_ref{'port_base'}; + + my $hdr_args = { + version => get_of_ver(), + type => $enums{'OFPT_STATS_REQUEST'}, + length => $ofp->sizeof('ofp_stats_request') + + $ofp->sizeof('ofp_flow_stats_request') + , # should generate automatically! + xid => 0x00000000 + }; + + my $match_args = { + wildcards => 0x3ef, + in_port => 0, + dl_src => [], + dl_dst => [], + dl_vlan => 0, + dl_type => 0x800, + nw_src => ( NF2::IP_hdr::getIP("192.168.200.1") )[0], + nw_dst => ( NF2::IP_hdr::getIP("192.168.201.2") )[0], + nw_proto => 0, + tp_src => 0, + tp_dst => 0 + }; + + my $stats_request_args = { + header => $hdr_args, + type => $enums{'OFPST_FLOW'}, + flags => 0 + }; + + my $body_args = { + match => $match_args, + table_id => 0xff, #match all tables + out_port => $enums{'OFPP_NONE'}, + }; + + my $body = $ofp->pack( 'ofp_flow_stats_request', $body_args ); + + my $stats_request = $ofp->pack( 'ofp_stats_request', $stats_request_args ); + + my $mesg = $stats_request . $body; + + # Send 'stats_request' message + print $sock $mesg; + + # Should add timeout here - will crash if no reply + my $recvd_mesg; + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; + + # Inspect message + my $msg_size = length($recvd_mesg); + + my $msg = $ofp->unpack( 'ofp_stats_reply', $recvd_mesg ); + + #print HexDump ($recvd_mesg); + print Dumper($msg); + + # Verify fields + verify_header( $msg, 'OFPT_STATS_REPLY', $msg_size ); + + #---------------------- + + # add flow mod, send pkt + { + my $in_port_offset = 0; + my $out_port_offset = 1; + my $wildcards = 0x3ef; + my $wait = 5; + + forward_simple( $ofp, $sock, $options_ref, $in_port_offset, + $out_port_offset, $wildcards, 'any', 1 ); + } + + sleep .1; + + # Send 'stats_request' message + print $sock $mesg; + + # Should add timeout here - will crash if no reply + my $recvd_mesg; + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; + + # Inspect message + my $msg_size = length($recvd_mesg); + + my $msg = $ofp->unpack( 'ofp_stats_reply', $recvd_mesg ); + + # Strip off the header from the received message + $recvd_mesg = substr( $recvd_mesg, $ofp->sizeof('ofp_stats_reply') ); + + # Unpack each of the ofp_flow_stats messages + my $flow_stats_len = $ofp->sizeof('ofp_flow_stats'); + while ( length($recvd_mesg) > 0 ) { + if ( length($recvd_mesg) < $flow_stats_len ) { + die "Error: Partial flow stats message received"; + } + my $flow_stats = $ofp->unpack( 'ofp_flow_stats', $recvd_mesg ); + + push @{ $msg->{'body'} }, $flow_stats; + $recvd_mesg = substr( $recvd_mesg, $flow_stats->{'length'} ); + } + + #print HexDump ($recvd_mesg); + print Dumper($msg); + + # Verify fields + verify_header( $msg, 'OFPT_STATS_REPLY', $msg_size ); + + # Ensure that we got back one ofp_flow_stats body + compare( + "stats_reply flow_stats count", + scalar( @{ $msg->{'body'} } ), + '==', 1 + ); + if ( $msg->{'body'}[0]->{'duration_sec'} != 0 ) { + die "Error, duration_sec out of acceptable range"; + } + if ( $msg->{'body'}[0]->{'duration_nsec'} < 100000000 + || $msg->{'body'}[0]->{'duration_nsec'} > (100000000+$time_threshold) ) + { + die "Error, duration_nsec out of acceptable range"; + } + + # Sleep 1 more second to test duration_sec + sleep 1.0; + + # Send 'stats_request' message + print $sock $mesg; + + # Should add timeout here - will crash if no reply + my $recvd_mesg; + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; + + # Inspect message + my $msg_size = length($recvd_mesg); + + my $msg = $ofp->unpack( 'ofp_stats_reply', $recvd_mesg ); + + # Strip off the header from the received message + $recvd_mesg = substr( $recvd_mesg, $ofp->sizeof('ofp_stats_reply') ); + + # Unpack each of the ofp_flow_stats messages + my $flow_stats_len = $ofp->sizeof('ofp_flow_stats'); + while ( length($recvd_mesg) > 0 ) { + if ( length($recvd_mesg) < $flow_stats_len ) { + die "Error: Partial flow stats message received"; + } + my $flow_stats = $ofp->unpack( 'ofp_flow_stats', $recvd_mesg ); + + push @{ $msg->{'body'} }, $flow_stats; + $recvd_mesg = substr( $recvd_mesg, $flow_stats->{'length'} ); + } + + #print HexDump ($recvd_mesg); + print Dumper($msg); + + # Verify fields + verify_header( $msg, 'OFPT_STATS_REPLY', $msg_size ); + + # Ensure that we got back one ofp_flow_stats body + compare( + "stats_reply flow_stats count", + scalar( @{ $msg->{'body'} } ), + '==', 1 + ); + if ( $msg->{'body'}[0]->{'duration_sec'} != 1 ) { + die "Error, duration_sec out of acceptable range"; + } + if ( $msg->{'body'}[0]->{'duration_nsec'} < 100000000 + || $msg->{'body'}[0]->{'duration_nsec'} > (100000000+$time_threshold) ) + { + die "Error, duration_nsec out of acceptable range"; + } + +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_forward_after_expiration/run.pl b/openflow/regress/projects/black_box/regress/test_forward_after_expiration/run.pl new file mode 100755 index 00000000..347051ca --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_after_expiration/run.pl @@ -0,0 +1,111 @@ +#!/usr/bin/perl -w +# test_forward_after_expiration + +use strict; +use OF::Includes; + +sub send_expect_exact { + + my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset ) = @_; + + my $in_port = $in_port_offset + $$options_ref{'port_base'}; + my $out_port = $out_port_offset + $$options_ref{'port_base'}; + + my $test_pkt = get_default_black_box_pkt_len( $in_port, $out_port, $$options_ref{'pkt_len'} ); + + #print HexDump ( $test_pkt->packed ); + + my $wildcards = 0x0; # exact match + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; + + my $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, + $$options_ref{'max_idle'}, $flags, $wildcards ); + + #print HexDump($flow_mod_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent flow_mod message\n"; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + + # Send a packet - ensure packet comes out desired port + nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt->packed ); + nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); +} + +sub send_expect_secchan_nomatch { + + my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len ) = @_; + + my $in_port = $in_port_offset + $$options_ref{'port_base'}; + my $out_port = $out_port_offset + $$options_ref{'port_base'}; + + my $test_pkt2 = get_default_black_box_pkt_len( $in_port, $out_port, $$options_ref{'pkt_len'} ); + + print "sending out eth" + . ( $in_port_offset + 1 ) + . ", expecting response on secchan due to no flow matching\n"; + + # Send a packet - ensure packet comes out desired port + nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt2->packed ); + + my $recvd_mesg; + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; + + # Inspect message + my $msg_size = length($recvd_mesg); + my $expected_size = $ofp->offsetof( 'ofp_packet_in', 'data' ) + length( $test_pkt2->packed ); + compare( "msg size", $msg_size, '==', $expected_size ); + + my $msg = $ofp->unpack( 'ofp_packet_in', $recvd_mesg ); + + #print HexDump ($recvd_mesg); + #print Dumper($msg); + + # Verify fields + + print "Verifying secchan message for packet sent in to eth" . ( $in_port_offset + 1 ) . "\n"; + + verify_header( $msg, 'OFPT_PACKET_IN', $msg_size ); + + compare( "total len", $$msg{'total_len'}, '==', length( $test_pkt2->packed ) ); + compare( "in_port", $$msg{'in_port'}, '==', $in_port ); + compare( "reason", $$msg{'reason'}, '==', $enums{'OFPR_NO_MATCH'} ); + + # verify packet was unchanged! + my $recvd_pkt_data = substr( $recvd_mesg, $ofp->offsetof( 'ofp_packet_in', 'data' ) ); + if ( $recvd_pkt_data ne $test_pkt2->packed ) { + die "ERROR: sending from eth" + . $in_port + 1 + . " received packet data didn't match packet sent\n"; + } + +} + +sub test_forward_after_expiration { + + my ( $ofp, $sock, $options_ref, $i, $j, $wildcards ) = @_; + + my $max_idle = $$options_ref{'max_idle'}; + my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_total = $$options_ref{'pkt_total'}; + + send_expect_exact( $ofp, $sock, $options_ref, $i, $j); + print "waiting for flow to expire\n"; + wait_for_flow_expired_all( $ofp, $sock, $options_ref ); + usleep($$options_ref{'send_delay'}); + send_expect_secchan_nomatch( $ofp, $sock, $options_ref, $i, $j); +} + +sub my_test { + + my ($sock, $options_ref) = @_; + + # send from every port to every other port + for_all_port_pairs( $ofp, $sock, $options_ref, \&test_forward_after_expiration, 0x0); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_any_port/run.pl b/openflow/regress/projects/black_box/regress/test_forward_any_port/run.pl new file mode 100755 index 00000000..83c07e1d --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_any_port/run.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl -w +# test_forward_any_port + +use strict; +use OF::Includes; + +sub forward_any { + + forward_simple(@_, 'any'); +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_any, 0xfffff); +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_forward_bandwidth_fixed/run.pl b/openflow/regress/projects/black_box/regress/test_forward_bandwidth_fixed/run.pl new file mode 100755 index 00000000..44ac6ec9 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_bandwidth_fixed/run.pl @@ -0,0 +1,83 @@ +#!/usr/bin/perl -w +# test_forward_bandwidth_fixed + +use strict; +use OF::Includes; + +my $pkt_len = 1512; +my $pkt_total = 1000; +my $max_idle = 2; + +sub send_expect_exact { + + my ( $ofp, $sock, $in_port, $out_port, $max_idle, $pkt_len ) = @_; + my %delta; + + # in_port refers to the flow mod entry's input + + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + src_port => 1, + dst_port => 0 + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + #print HexDump ( $test_pkt->packed ); + + my $wildcards = 0x0; # exact match + #my $wildcards = 0x2; # only wildcard the vlan + #my $wildcards = 0x2FF; # exact match + #my $wildcards = 0x3FE; # exact match on switch in port + #my $wildcards = 0x3DF; # exact match on src ip + #my $wildcards = 0x1; # exact match on eth src/dest/eth frame/ipsrcdest/128ipproto/256port source + #my $wildcards = 0x3BF; # exact match on dest ip + #my $wildcards = 0x3FD; # exact match on vlan + #my $wildcards = 0x3FB; # exact match on ether source + #my $wildcards = 0x3F7; # exact match on ether dest + my $flags = 0x0; # don't send flow expiry + + my $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, + $max_idle, $flags, $wildcards ); + + #print HexDump($flow_mod_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent flow_mod message\n"; + + usleep(200000); + my @start_time = gettimeofday(); + for (my $k = 0; $k < $pkt_total; $k++) { + send_and_count( nftest_get_iface( "eth" . ( $in_port + 1 ) ), + $test_pkt->packed, \%delta ); + expect_and_count( nftest_get_iface( "eth" . ( $out_port + 1 ) ), + $test_pkt->packed, \%delta ); + } + (my $second, my $micro) = tv_interval(\@start_time); + my $time_elapsed = ($second + $micro * 1e-6); + my $bw_result = ($pkt_total * $pkt_len * 8) / $time_elapsed; + print "PACKET LENGTH: $pkt_len \n"; + print "PACKETS SENT: $pkt_total\n"; + print "TIME ELAPSED: $time_elapsed \n"; + print "RESULTING BW: $bw_result bits/sec \n"; + +} + +sub my_test { + + my ($sock, $options_ref) = @_; + + my $inport = 0; + my $outport = 1; + print "Checking forwarding bandwidth from $inport to $outport\n"; + send_expect_exact( $ofp, $sock, $inport, $outport, $max_idle, $pkt_len ); + wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); +} + +run_black_box_test( \&my_test ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_bandwidth_random/run.pl b/openflow/regress/projects/black_box/regress/test_forward_bandwidth_random/run.pl new file mode 100755 index 00000000..4fa05282 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_bandwidth_random/run.pl @@ -0,0 +1,84 @@ +#!/usr/bin/perl -w +# test_forward_bandwidth_fixed + +use strict; +use OF::Includes; + +my $pkt_total = 1000; +my $max_idle = 2; + +# Maximum and minimum packet sizes +my $min_length = 64; +my $max_length = 1512; + +sub send_expect_exact { + + my ( $ofp, $sock, $in_port, $out_port, $max_idle) = @_; + my %delta; + + # in_port refers to the flow mod entry's input + + my @packets; + my $bytes = 0; + for (my $i = 0; $i < $pkt_total; $i++) { + my $pkt_len = int(rand($max_length - $min_length)) + $min_length; + $bytes += $pkt_len; + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port + 1 ), + dst_ip => "192.168.201." . ( $out_port + 1 ), + ttl => 64, + len => $pkt_len, + src_port => 1, + dst_port => 0 + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + push @packets, $test_pkt; + } + + + my $wildcards = 0x1; # wild card on input port + my $flags = 0x0; # don't send flow expiry + + my $test_pkt = pop @packets; + my $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, + $max_idle, $flags, $wildcards ); + push @packets, $test_pkt; + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent flow_mod message\n"; + + usleep(200000); + my @start_time = gettimeofday(); + for (my $k = 0; $k < $pkt_total; $k++) { + my $packet = pop @packets; + my $randport = int(rand(2)); + send_and_count( nftest_get_iface( "eth" . ( $randport + 1 ) ), + $packet->packed, \%delta ); + expect_and_count( nftest_get_iface( "eth" . ( $out_port + 1 ) ), + $packet->packed, \%delta ); + } + (my $second, my $micro) = tv_interval(\@start_time); + my $time_elapsed = ($second + $micro * 1e-6); + my $bw_result = ($bytes * 8) / $time_elapsed; + print "PACKETS SENT: $pkt_total\n"; + print "BYTES SENT: $bytes\n"; + print "TIME ELAPSED: $time_elapsed \n"; + print "RESULTING BW: $bw_result bits/sec \n"; + return $bytes; +} + +sub my_test { + + my ($sock, $options_ref) = @_; + + my $inport = 0; + my $outport = 3; + my $bytes_sent = send_expect_exact( $ofp, $sock, $inport, $outport, $max_idle ); + wait_for_flow_expired_total_bytes( $ofp, $sock, $options_ref, $bytes_sent, $pkt_total ); +} + +run_black_box_test( \&my_test ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_broadcast_exact_port/run.pl b/openflow/regress/projects/black_box/regress/test_forward_broadcast_exact_port/run.pl new file mode 100755 index 00000000..03bf655b --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_broadcast_exact_port/run.pl @@ -0,0 +1,64 @@ +#!/usr/bin/perl -w +# test_forward_exact_port + +use strict; +use OF::Includes; + +sub forward_broadcast { + + my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $wildcards, $type, $nowait ) = @_; + + my $in_port = $in_port_offset + $$options_ref{'port_base'}; + my $out_port; + + $out_port = $out_port_offset + $$options_ref{'port_base'}; + + my $len = $$options_ref{'pkt_len'}; + my $pkt_args = { + DA => "FF:FF:FF:FF:FF:FF", + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168." . ( $in_port ) . "." . ( $out_port ), + dst_ip => "255.255.255.255", + ttl => 64, + len => $len, + src_port => 1, + dst_port => 0 + }; + my $test_pkt = new NF2::UDP_pkt(%$pkt_args); + + my $flow_mod_pkt; + + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; + $flow_mod_pkt = create_flow_mod_from_udp($ofp, $test_pkt, $in_port, $out_port, $$options_ref{'max_idle'}, $flags, $wildcards); + + # Send 'flow_mod' message + syswrite( $sock, $flow_mod_pkt ); + print "sent flow_mod message\n"; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + + nftest_send( "eth" . ($in_port_offset + 1), $test_pkt->packed ); + + # expect single packet + print "expect single packet\n"; + nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); + + print "wait \n"; + wait_for_flow_expired_all( $ofp, $sock, $options_ref ); +} + + +sub forward_port { + + forward_broadcast(@_, 'port'); +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_port, 0x0); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_all/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_all/run.pl new file mode 100755 index 00000000..052ebbeb --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_exact_all/run.pl @@ -0,0 +1,30 @@ +#!/usr/bin/perl -w +# test_forward_exact_all + +use strict; +use OF::Includes; + +sub forward_all { + + forward_simple(@_, 'all'); +} + +sub forward_all_vlan { + my $vlan_id = 0xa5f3; + #[15:13] priority, [11:0] vlan id + #The value was chosen at random + forward_simple(@_, 'all', undef, undef, $vlan_id); +} + + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_ports( $ofp, $sock, $options_ref, \&forward_all, 0x0); + if ( not defined( $$options_ref{'no_vlan'} ) ) { + for_all_ports( $ofp, $sock, $options_ref, \&forward_all_vlan, 0x0); + } +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_arp_all/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_arp_all/run.pl new file mode 100755 index 00000000..0f44f91f --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_exact_arp_all/run.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl -w +# test_forward_exact_arp_all + +use strict; +use OF::Includes; + +sub forward_all { + + forward_simple_arp(@_, 'all', 0); # 0: fool_flg = off +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_ports( $ofp, $sock, $options_ref, \&forward_all, 0x0); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_arp_controller/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_arp_controller/run.pl new file mode 100755 index 00000000..e7de7bad --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_exact_arp_controller/run.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl -w +# test_forward_exact_arp_controller + +use strict; +use OF::Includes; + +sub forward_controller { + + forward_simple_arp(@_, 'controller', 0); # 0: fool_flg = off +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_ports( $ofp, $sock, $options_ref, \&forward_controller, 0x0); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_arp_fool/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_arp_fool/run.pl new file mode 100755 index 00000000..076dfc42 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_exact_arp_fool/run.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl -w +# test_forward_exact_arp_fool + +use strict; +use OF::Includes; + +sub forward_port { + + forward_simple_arp(@_, 'port', 1); # 1: fool_flg=on +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_port, 0x0); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_arp_port/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_arp_port/run.pl new file mode 100755 index 00000000..b0af883e --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_exact_arp_port/run.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl -w +# test_forward_exact_arp_port + +use strict; +use OF::Includes; + +sub forward_port { + + forward_simple_arp(@_, 'port', 0); # 0: fool_flg = off +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_port, 0x0); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_controller/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_controller/run.pl new file mode 100755 index 00000000..e0888d16 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_exact_controller/run.pl @@ -0,0 +1,32 @@ +#!/usr/bin/perl -w +# test_forward_exact_controller + +use strict; +use OF::Includes; + +use strict; +use OF::Includes; + +sub forward_controller { + + forward_simple(@_, 'controller'); +} + +sub forward_controller_vlan { + my $vlan_id = 0xc123; + #[15:13] priority, [11:0] vlan id + #The value was chosen at random + forward_simple(@_, 'controller', undef, undef, $vlan_id); +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_ports( $ofp, $sock, $options_ref, \&forward_controller, 0x0); + if ( not defined( $$options_ref{'no_vlan'} ) ) { + for_all_ports( $ofp, $sock, $options_ref, \&forward_controller_vlan, 0x0); + } +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_all/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_all/run.pl new file mode 100755 index 00000000..3b1f6bfd --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_all/run.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl -w +# test_forward_exact_icmp_all + +use strict; +use OF::Includes; + +sub forward_all { + + forward_simple_icmp(@_, 'all', 0); # 0: fool_flg = off +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_ports( $ofp, $sock, $options_ref, \&forward_all, 0x0); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_controller/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_controller/run.pl new file mode 100755 index 00000000..c07debe8 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_controller/run.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl -w +# test_forward_exact_icmp_controller + +use strict; +use OF::Includes; + +sub forward_controller { + + forward_simple_icmp(@_, 'controller', 0); # 0: fool_flg = off +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_ports( $ofp, $sock, $options_ref, \&forward_controller, 0x0); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_fool/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_fool/run.pl new file mode 100755 index 00000000..dee5a6c2 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_fool/run.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl -w +# test_forward_exact_icmp_fool + +use strict; +use OF::Includes; + +sub forward_port { + + forward_simple_icmp(@_, 'port', 1); # 1: fool_flg=on +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_port, 0x0); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_port/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_port/run.pl new file mode 100755 index 00000000..100bc3ad --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_port/run.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl -w +# test_forward_exact_icmp_port + +use strict; +use OF::Includes; + +sub forward_port { + + forward_simple_icmp(@_, 'port', 0); # 0: fool_flg = off +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_port, 0x0); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_modify_action/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_modify_action/run.pl new file mode 100755 index 00000000..805c9ad9 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_exact_modify_action/run.pl @@ -0,0 +1,42 @@ +#!/usr/bin/perl -w +# test_forward_exact_modify_action + +use strict; +use OF::Includes; + +sub forward_port { + + my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, + $wildcards ) = @_; + + my @chg_field; + if ( not defined( $$options_ref{'no_vlan'} ) ) { + @chg_field = ('vlan_vid', 'vlan_pcp', 'dl_src', 'dl_dst', 'nw_src', 'nw_dst', 'tp_src', 'tp_dst'); + } else { + @chg_field = ('dl_src', 'dl_dst', 'nw_src', 'nw_dst', 'tp_src', 'tp_dst'); + } + foreach (@chg_field) { + forward_simple(@_, 'port', undef, $_ ); + } +} + +sub forward_port_vlan { + my @chg_field = ('strip_vlan', 'vlan_vid', 'vlan_pcp', 'dl_src', 'dl_dst', 'nw_src', 'nw_dst', 'tp_src', 'tp_dst'); + my $vlan = 0x65a1; + #[15:13]:vlan_pcp, [11:0]:vlan_vid + #The value was chosen at random + foreach (@chg_field) { + forward_simple(@_, 'port', undef, $_, $vlan ); + } +} +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_port, 0x0); + if ( not defined( $$options_ref{'no_vlan'} ) ) { + for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_port_vlan, 0x0); + } +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_port/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_port/run.pl new file mode 100755 index 00000000..c3fc215f --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_exact_port/run.pl @@ -0,0 +1,27 @@ +#!/usr/bin/perl -w +# test_forward_exact_port + +use strict; +use OF::Includes; + +sub forward_unicast_port { + forward_simple(@_, 'port'); +} + +sub forward_unicast_vlan_port { + my $vlan_id = 0xea5a; + #[15:13] priority, [11:0] vlan id + #The value was chosen at random + forward_simple(@_, 'port', undef, undef, $vlan_id); +} + +sub my_test { + my ($sock, $options_ref) = @_; + + for_all_port_pairs($ofp, $sock, $options_ref, \&forward_unicast_port, 0x0); + if ( not defined( $$options_ref{'no_vlan'} ) ) { + for_all_port_pairs($ofp, $sock, $options_ref, \&forward_unicast_vlan_port, 0x0); + } +} + +run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_forward_overlapping_flow_entries/run.pl b/openflow/regress/projects/black_box/regress/test_forward_overlapping_flow_entries/run.pl new file mode 100755 index 00000000..6ed870e6 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_overlapping_flow_entries/run.pl @@ -0,0 +1,86 @@ +#!/usr/bin/perl -w +# test_forward_overlapping_flow_entries + +use strict; +use OF::Includes; + +sub send_expect_multi_flow { + + my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len ) = @_; + + my $in_port = $in_port_offset + $$options_ref{'port_base'}; + my $out_port = $out_port_offset + $$options_ref{'port_base'}; + + my $test_pkt = get_default_black_box_pkt_len( $in_port, $out_port, $pkt_len ); + + #print HexDump ( $test_pkt->packed ); + + my $wildcards = 0x0; # exact match + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; + + my $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, + $enums{'OFPP_ALL'}, $max_idle, $flags, $wildcards ); + + #print HexDump($flow_mod_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent exact match flow_mod message\n"; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + + $wildcards = 0x1fffff; # wildcard everything + + # (send to controller) + $flow_mod_pkt = create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, + $enums{'OFPP_CONTROLLER'}, 2, $flags, $wildcards ); + + #print HexDump($flow_mod_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent wildcard match flow_mod message\n"; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + + # Send a packet - ensure packet comes out desired port + nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt->packed ); + + for ( my $k = 0 ; $k < $$options_ref{'num_ports'}; $k++ ) { + if ( $k != $in_port_offset ) { + nftest_expect( "eth" . ( $k + 1 ), $test_pkt->packed ); + } + } +} + +sub my_test { + + my ($sock, $options_ref) = @_; + + #my $max_idle = $$options_ref{'max_idle'}; + my $max_idle = 5; + my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_total = $$options_ref{'pkt_total'}; + + my $num_ports = $$options_ref{'num_ports'}; + + my $j = 0; + + # send from every port, receive on every port except the send port + #for ( my $i = 0 ; $i < $num_ports ; $i++ ) { + my $i = 0; + my $j = ($i + 1) % $num_ports; + print "sending from $i to (all ports but $i)\n"; + send_expect_multi_flow( $ofp, $sock, $options_ref, $i, $j, $max_idle, $pkt_len ); + print "waiting for first flow to expire\n"; + wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, 0 ); + print "waiting for second flow to expire\n"; + wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); + #} +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_all/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_all/run.pl new file mode 100755 index 00000000..51a504b8 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_wildcard_all/run.pl @@ -0,0 +1,172 @@ +#!/usr/bin/perl -w +# test_forward_wildcard_all + +use strict; +use OF::Includes; + +sub forward_wc_all { + + forward_simple(@_, 'all'); +} + +sub forward_wc_all_vlan { + my $vlan_id = 0x25ae; + #[15:13] priority, [11:0] vlan id + #The value was chosen at random + forward_simple(@_, 'all', undef, undef, $vlan_id); +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_all); + if ( not defined( $$options_ref{'no_vlan'} ) ) { + for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_all_vlan); + } +} + +run_black_box_test( \&my_test, \@ARGV ); + +#sub send_expect_exact { +# +# my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $wildcards ) = @_; +# +# my $in_port = $in_port_offset + $$options_ref{'port_base'}; +# my $out_port = $enums{'OFPP_ALL'}; # all physical ports except the input +# +# printf( "Wildcards are: %04x\n", $wildcards ); +# +# # in_port refers to the flow mod entry's input +# +# # This packet will always match +# my $test_pkt = get_default_black_box_pkt_len( $in_port, $out_port, $$options_ref{'pkt_len'} ); +# +# # This packet will always miss +# my $test_pkt2 = get_default_black_box_pkt_len( $in_port + 5, $out_port + 5, $$options_ref{'pkt_len'} ); +# +# print HexDump ( $test_pkt->packed ); +# print HexDump ( $test_pkt2->packed ); +# +# my $flow_mod_pkt = +# create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $$options_ref{'max_idle'}, $wildcards ); +# +# #print HexDump($flow_mod_pkt); +# +# # Send 'flow_mod' message +# print $sock $flow_mod_pkt; +# print "sent flow_mod message\n"; +# +# # Give OF switch time to process the flow mod +# usleep($$options_ref{'send_delay'}); +# +# # Send a packet - ensure packet comes out desired port +# nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt->packed ); +# +# for ( my $k = 0 ; $k < $$options_ref{'num_ports'} ; $k++ ) { +# if ( $k != $in_port_offset ) { +# nftest_expect( "eth" . ( $k + 1 ), $test_pkt->packed ); +# } +# } +# +# print "Matching packet sent\n"; +# +# #nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt2->packed ); +# +## #print "Non-matching packet sent\n"; +## my $recvd_mesg; +## sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; +## +## # Inspect message +## my $msg_size = length($recvd_mesg); +## my $expected_size = $ofp->offsetof( 'ofp_packet_in', 'data' ) + length( $test_pkt2->packed ); +## +## print HexDump ($recvd_mesg); +## +## #print "Comparing sizes $msg_size and $expected_size\n"; +## compare( "msg size", $msg_size, '==', $expected_size ); +## +## my $msg = $ofp->unpack( 'ofp_packet_in', $recvd_mesg ); +## +## #print HexDump ($recvd_mesg); +## #print Dumper($msg); +## +## # Verify fields +## verify_header( $msg, 'OFPT_PACKET_IN', $msg_size ); +## +## compare( "total len", $$msg{'total_len'}, '==', length( $test_pkt2->packed ) ); +## compare( "in_port", $$msg{'in_port'}, '==', $in_port ); +## compare( "reason", $$msg{'reason'}, '==', $enums{'OFPR_NO_MATCH'} ); +## +## # verify packet was unchanged! +## my $recvd_pkt_data = substr( $recvd_mesg, $ofp->offsetof( 'ofp_packet_in', 'data' ) ); +## if ( $recvd_pkt_data ne $test_pkt2->packed ) { +## die "ERROR: received packet data didn't match packet sent\n"; +## } +# +#} +# +#sub my_test { +# +# my ( $sock, $options_ref ) = @_; +# my $j = $enums{'OFPP_FLOOD'}; +# +# my $max_idle = $$options_ref{'max_idle'}; +# my $pkt_len = $$options_ref{'pkt_len'}; +# my $pkt_total = $$options_ref{'pkt_total'}; +# +# # send from every port to every other port +# for ( my $i = 0 ; $i < 4 ; $i++ ) { +# +# print "sending from $i to $j\n"; +# +# #Very hackish, but basically iterate through the possibilities for +# #wildcarding one at a time. +# print "wildcards 0x0001 : IN_PORT\n"; +# send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0001 ); +# wait_for_flow_expired_all( $ofp, $sock, $options_ref ); +# +# #DL_VLAN fixed at 0xffff currently. +# #print "wildcards 0x0002 : DL_VLAN\n"; +# #send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0002); +# #wait_for_flow_expired_all( $ofp, $sock, $options_ref ); +# +# print "wildcards 0x0004 : DL_SRC\n"; +# send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0004 ); +# wait_for_flow_expired_all( $ofp, $sock, $options_ref ); +# +# print "wildcards 0x0008 : DL_DST\n"; +# send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0008 ); +# wait_for_flow_expired_all( $ofp, $sock, $options_ref ); +# +# #DL_TYPE fixed at 0x0800 currently. +# #print "wildcards 0x0010 : DL_TYPE\n"; +# #send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0010); +# #wait_for_flow_expired_all( $ofp, $sock, $options_ref ); +# +# print "wildcards 0x0020 : NW_SRC\n"; +# send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0020 ); +# wait_for_flow_expired_all( $ofp, $sock, $options_ref ); +# +# print "wildcards 0x0040 : NW_DST\n"; +# send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0040 ); +# wait_for_flow_expired_all( $ofp, $sock, $options_ref ); +# +# #NW_PROTO fixed at 17 currently. +# #print "wildcards 0x0080 : NW_PROTO\n"; +# #send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0080); +# #wait_for_flow_expired_all( $ofp, $sock, $options_ref ); +# +# print "wildcards 0x0100 : TP_SRC\n"; +# send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0100 ); +# wait_for_flow_expired_all( $ofp, $sock, $options_ref ); +# +# print "wildcards 0x0200 : TP_SRC\n"; +# send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0200 ); +# wait_for_flow_expired_all( $ofp, $sock, $options_ref ); +# +# } +#} +# +#run_black_box_test( \&my_test, \@ARGV ); +# diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_all/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_all/run.pl new file mode 100755 index 00000000..ccebe303 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_all/run.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl -w +# test_forward_wildcard_arp_all + +use strict; +use OF::Includes; + +sub forward_wc_all { + + forward_simple_arp(@_, 'all', 0); # 0: fool_flg = off +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_all); +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_controller/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_controller/run.pl new file mode 100755 index 00000000..90e8b5ad --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_controller/run.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl -w +# test_forward_wildcard_arp_controller + +use strict; +use OF::Includes; + +sub forward_wc_controller { + + forward_simple_arp(@_, 'controller', 0); # 0: fool_flg = off +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_controller); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_fool/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_fool/run.pl new file mode 100755 index 00000000..0b4d5249 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_fool/run.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl -w +# test_forward_wildcard_arp_port + +use strict; +use OF::Includes; + +sub forward_wc_port { + forward_simple_arp(@_, 'port', 1); # 1: fool_flg = on +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_port); +} + +run_black_box_test( \&my_test, \@ARGV ); + + diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_port/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_port/run.pl new file mode 100755 index 00000000..ef8cb8ab --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_port/run.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl -w +# test_forward_wildcard_arp_port + +use strict; +use OF::Includes; + +sub forward_wc_port { + forward_simple_arp(@_, 'port', 0); # 0: fool_flg = off +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_port); +} + +run_black_box_test( \&my_test, \@ARGV ); + + diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_controller/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_controller/run.pl new file mode 100755 index 00000000..125c5071 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_wildcard_controller/run.pl @@ -0,0 +1,30 @@ +#!/usr/bin/perl -w +# test_forward_wildcard_controller + +use strict; +use OF::Includes; + +sub forward_wc_controller { + + forward_simple(@_, 'controller'); +} + +sub forward_wc_controller_vlan { + my $vlan_id = 0x4abc; + #[15:13] priority, [11:0] vlan id + #The value was chosen at random + forward_simple(@_, 'controller', undef, undef, $vlan_id); +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_controller); + if ( not defined( $$options_ref{'no_vlan'} ) ) { + for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_controller_vlan); + } +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_all/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_all/run.pl new file mode 100755 index 00000000..7ccdea0b --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_all/run.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl -w +# test_forward_wildcard_icmp_all + +use strict; +use OF::Includes; + +sub forward_wc_all { + + forward_simple_icmp(@_, 'all', 0); # 0: fool_flg = off +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_all); +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_controller/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_controller/run.pl new file mode 100755 index 00000000..21a0c608 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_controller/run.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl -w +# test_forward_wildcard_icmp_controller + +use strict; +use OF::Includes; + +sub forward_wc_controller { + + forward_simple_icmp(@_, 'controller', 0); # 0: fool_flg = off +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_controller); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_fool/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_fool/run.pl new file mode 100755 index 00000000..eacfb9d5 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_fool/run.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl -w +# test_forward_wildcard_icmp_port + +use strict; +use OF::Includes; + +sub forward_wc_port { + forward_simple_icmp(@_, 'port', 1); # 1: fool_flg = on +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_port); +} + +run_black_box_test( \&my_test, \@ARGV ); + + diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_port/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_port/run.pl new file mode 100755 index 00000000..c428a9e5 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_port/run.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl -w +# test_forward_wildcard_icmp_port + +use strict; +use OF::Includes; + +sub forward_wc_port { + forward_simple_icmp(@_, 'port', 0); # 0: fool_flg = off +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_port); +} + +run_black_box_test( \&my_test, \@ARGV ); + + diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_modify_action/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_modify_action/run.pl new file mode 100755 index 00000000..ca32aaaf --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_wildcard_modify_action/run.pl @@ -0,0 +1,35 @@ +#!/usr/bin/perl -w +# test_forward_wildcard_modify_action + +use strict; +use OF::Includes; + +sub forward_wc_port { + my @chg_field = ('vlan_vid', 'vlan_pcp','dl_src', 'dl_dst', 'nw_src', 'nw_dst', 'tp_src', 'tp_dst'); + foreach (@chg_field) { + forward_simple(@_, 'port', undef, $_ ); + } +} + + +sub forward_wc_port_vlan { + my @chg_field = ('strip_vlan', 'vlan_vid','vlan_pcp','dl_src', 'dl_dst', 'nw_src', 'nw_dst', 'tp_src', 'tp_dst'); + my $vlan_id = 0xa344; + #The value was chosen at random + foreach (@chg_field) { + forward_simple(@_, 'port', undef, $_, $vlan_id); + } +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_port); + if ( not defined( $$options_ref{'no_vlan'} ) ) { + for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_port_vlan); + } +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_port/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_port/run.pl new file mode 100755 index 00000000..934da7cc --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_forward_wildcard_port/run.pl @@ -0,0 +1,97 @@ +#!/usr/bin/perl -w +# test_forward_wildcard_port + +use strict; +use OF::Includes; + +sub forward_wc_port { + + forward_simple(@_, 'port'); +} + +sub forward_wc_port_vlan { + my $vlan_id = 0x8ea5; + #[15:13] priority, [11:0] vlan id + #The value was chosen at random + forward_simple(@_, 'port', undef, undef, $vlan_id); +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_port); + if ( not defined( $$options_ref{'no_vlan'} ) ) { + for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_port_vlan); + } +} + +run_black_box_test( \&my_test, \@ARGV ); + +#sub send_expect_exact { +# +# my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len, $wildcards ) = @_; +# +# my $in_port = $in_port_offset + $$options_ref{'port_base'}; +# my $out_port = $out_port_offset + $$options_ref{'port_base'}; +# +# printf( "Wildcards are: %04x\n", $wildcards ); +# +# # This packet will always match +# my $test_pkt = get_default_black_box_pkt_len( $in_port, $out_port, $pkt_len ); +# +# # This packet will always miss +# my $test_pkt2 = get_default_black_box_pkt_len( $in_port + 5, $out_port + 5, $pkt_len ); +# +# #print HexDump ( $test_pkt->packed ); +# +# my $flow_mod_pkt = +# create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $wildcards ); +# +# #print HexDump($flow_mod_pkt); +# +# # Send 'flow_mod' message +# print $sock $flow_mod_pkt; +# print "sent flow_mod message\n"; +# +# # Give OF switch time to process the flow mod +# usleep($$options_ref{'send_delay'}); +# +# # Send a packet - ensure packet comes out desired port +# nftest_send( "eth" . ($in_port_offset + 1), $test_pkt->packed ); +# nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); +# print "Matching packet sent\n"; +# +# nftest_send( "eth" . ($in_port_offset + 1), $test_pkt2->packed ); +# +# print "Non-matching packet sent\n"; +# my $recvd_mesg; +# sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; +# +# # Inspect message +# my $msg_size = length($recvd_mesg); +# my $expected_size = $ofp->offsetof( 'ofp_packet_in', 'data' ) + length( $test_pkt2->packed ); +# +# #print "Comparing sizes $msg_size and $expected_size\n"; +# compare( "msg size", $msg_size, '==', $expected_size ); +# +# my $msg = $ofp->unpack( 'ofp_packet_in', $recvd_mesg ); +# +# #print HexDump ($recvd_mesg); +# #print Dumper($msg); +# +# # Verify fields +# verify_header( $msg, 'OFPT_PACKET_IN', $msg_size ); +# +# compare( "total len", $$msg{'total_len'}, '==', length( $test_pkt2->packed ) ); +# compare( "in_port", $$msg{'in_port'}, '==', $in_port ); +# compare( "reason", $$msg{'reason'}, '==', $enums{'OFPR_NO_MATCH'} ); +# +# # verify packet was unchanged! +# my $recvd_pkt_data = substr( $recvd_mesg, $ofp->offsetof( 'ofp_packet_in', 'data' ) ); +# if ( $recvd_pkt_data ne $test_pkt2->packed ) { +# die "ERROR: received packet data didn't match packet sent\n"; +# } +# +#} + diff --git a/openflow/regress/projects/black_box/regress/test_hello/run.pl b/openflow/regress/projects/black_box/regress/test_hello/run.pl new file mode 100755 index 00000000..e1bbdb23 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_hello/run.pl @@ -0,0 +1,16 @@ +#!/usr/bin/perl -w +# test_hello + +use strict; +require OF::Includes; + +sub my_test { + + my ($sock, $options_ref) = @_; + + + + # hello sequence automatically done by test harness! +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_ip_offset/run.pl b/openflow/regress/projects/black_box/regress/test_ip_offset/run.pl new file mode 100755 index 00000000..0aa567b3 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_ip_offset/run.pl @@ -0,0 +1,85 @@ +#!/usr/bin/perl -w +# test_ip_offset + +use strict; +use OF::Includes; + +sub send_expect_exact { + + my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len ) = @_; + + my $in_port = $in_port_offset + $$options_ref{'port_base'}; + my $out_port = $out_port_offset + $$options_ref{'port_base'}; + + # in_port refers to the flow mod entry's input + + my $test_pkt_frag_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + frag => 0x2fff, # IP_frag > IP_len + src_port => 1, + dst_port => 0 + }; + my $test_pkt_frag = new NF2::UDP_pkt(%$test_pkt_frag_args); + + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + frag => 0, + src_port => 0, + dst_port => 0 + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + #print HexDump ( $test_pkt->packed ); + + my $wildcards = 0x0; # exact match + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; + + my $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); + + #print HexDump($flow_mod_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent flow_mod message\n"; + usleep($$options_ref{'send_delay'}); + + # Send a packet - ensure packet comes out desired port + nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt_frag->packed ); + nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt_frag->packed ); +} + +sub test_ip_offset { + + my ( $ofp, $sock, $options_ref, $i, $j, $wildcards ) = @_; + + my $max_idle = $$options_ref{'max_idle'}; + my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_total = $$options_ref{'pkt_total'}; + + my $port_base = $$options_ref{'port_base'}; + my $num_ports = $$options_ref{'num_ports'}; + + send_expect_exact( $ofp, $sock, $options_ref, $i, $j, $max_idle, $pkt_len ); + wait_for_flow_expired_all( $ofp, $sock, $options_ref ); +} + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + # send from every port to every other port + for_all_port_pairs( $ofp, $sock, $options_ref, \&test_ip_offset, 0x0); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_ip_options/run.pl b/openflow/regress/projects/black_box/regress/test_ip_options/run.pl new file mode 100755 index 00000000..ce8f9266 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_ip_options/run.pl @@ -0,0 +1,76 @@ +#!/usr/bin/perl -w +# test_ip_options + +use strict; +use OF::Includes; + +sub send_expect_exact { + + my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len ) = @_; + + my $in_port = $in_port_offset + $$options_ref{'port_base'}; + my $out_port = $out_port_offset + $$options_ref{'port_base'}; + + # in_port refers to the flow mod entry's input + my @ipopt = ( 0x44, 0x08, 0x08, 0x00, 0x11, 0x22, 0x33, 0x44 ); #IP timestamp option + my $num_ipopt = @ipopt; + + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + ip_hdr_len => 5 + ( $#ipopt + 1 ) / 4, + ip_options => \@ipopt, + src_port => 1, + dst_port => 0 + + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + #print ("pkt_len = $pkt_len\n"); + #print HexDump ( $test_pkt->packed ); + + my $wildcards = 0x0; # exact match + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; + + my $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); + #print HexDump($flow_mod_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent flow_mod message\n"; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + + # Send a packet - ensure packet comes out desired port + nftest_send("eth" . ( $in_port_offset + 1 ), $test_pkt->packed ); + nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); +} + +sub test_ip_options { + + my ( $ofp, $sock, $options_ref, $i, $j, $wildcards ) = @_; + + my $max_idle = $$options_ref{'max_idle'}; + #my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_len = 68; + my $pkt_total = $$options_ref{'pkt_total'}; + + send_expect_exact( $ofp, $sock, $options_ref, $i, $j, $max_idle, $pkt_len ); + wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); +} + +sub my_test { + + my ($sock, $options_ref) = @_; + + # send from every port to every other port + for_all_port_pairs( $ofp, $sock, $options_ref, \&test_ip_options, 0x0); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_ip_protocol/case-c.pl b/openflow/regress/projects/black_box/regress/test_ip_protocol/case-c.pl new file mode 100755 index 00000000..4637c860 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_ip_protocol/case-c.pl @@ -0,0 +1,150 @@ +#!/usr/bin/perl -w +# test_ip_protocol (case c, not TCP nor UDP) + +use strict; +use OF::Includes; + +sub send_expect_exact { + + my ( $ofp, $sock, $in_port, $out_port, $max_idle, $pkt_len ) = @_; + + # in_port refers to the flow mod entry's input + + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + src_port => 70, + dst_port => 80 + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + ## Change protocol field + my $iphdr=$test_pkt->{'IP_hdr'}; + $$iphdr->proto(0x13); # overwrite protocol filed in IP header + + #print HexDump ( $test_pkt->packed ); + + my $wildcards = 0x0; # exact match + + my $flow_mod_pkt = + create_flow_mod_from_pseudo_tcp( $ofp, $test_pkt, $in_port, $out_port, + $max_idle, $wildcards ); + + #print HexDump($flow_mod_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent flow_mod message\n"; + usleep(100000); + + # Send a packet - ensure packet comes out desired port + nftest_send( "eth" . ( $in_port + 1 ), + $test_pkt->packed ); + nftest_expect( "eth" . ( $out_port + 1 ), + $test_pkt->packed ); +} + +sub test_ip_protocol { + + my ( $ofp, $sock, $options_ref, $i, $j, $wildcards ) = @_; + + my $max_idle = $$options_ref{'max_idle'}; + my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_total = $$options_ref{'pkt_total'}; + + send_expect_exact( $ofp, $sock, $i, $j, $max_idle, $pkt_len ); + wait_for_flow_expired_all( $ofp, $sock, $options_ref ); +} + +sub my_test { + + my ($sock, $options_ref) = @_; + + # send from every port to every other port + for_all_port_pairs( $ofp, $sock, $options_ref, \&test_ip_protocol, 0x0); +} + +sub create_flow_mod_from_pseudo_tcp { + + my ( $ofp, $udp_pkt, $in_port, $out_port, $max_idle, $wildcards ) = @_; + + my $hdr_args = { + version => get_of_ver(), + type => $enums{'OFPT_FLOW_MOD'}, + length => $ofp->sizeof('ofp_flow_mod') + $ofp->sizeof('ofp_action'), + xid => 0x0000000 + }; + + # might be cleaner to convert the exported colon-hex MAC addrs + #print ${$udp_pkt->{Ethernet_hdr}}->SA . "\n"; + #print ${$test_pkt->{Ethernet_hdr}}->SA . "\n"; + my $ref_to_eth_hdr = ( $udp_pkt->{'Ethernet_hdr'} ); + my $ref_to_ip_hdr = ( $udp_pkt->{'IP_hdr'} ); + + # pointer to array + my $eth_hdr_bytes = $$ref_to_eth_hdr->{'bytes'}; + my $ip_hdr_bytes = $$ref_to_ip_hdr->{'bytes'}; + my @dst_mac_subarray = @{$eth_hdr_bytes}[ 0 .. 5 ]; + my @src_mac_subarray = @{$eth_hdr_bytes}[ 6 .. 11 ]; + + my @src_ip_subarray = @{$ip_hdr_bytes}[ 12 .. 15 ]; + my @dst_ip_subarray = @{$ip_hdr_bytes}[ 16 .. 19 ]; + + my $src_ip = + ( ( 2**24 ) * $src_ip_subarray[0] + ( 2**16 ) * $src_ip_subarray[1] + + ( 2**8 ) * $src_ip_subarray[2] + $src_ip_subarray[3] ); + + my $dst_ip = + ( ( 2**24 ) * $dst_ip_subarray[0] + ( 2**16 ) * $dst_ip_subarray[1] + + ( 2**8 ) * $dst_ip_subarray[2] + $dst_ip_subarray[3] ); + + # read IP_header protocol field + my $iph = $udp_pkt->{'IP_hdr'}; + my $proto = $$iph->proto(); + + my $match_args = { + wildcards => $wildcards, + in_port => $in_port, + dl_src => \@src_mac_subarray, + dl_dst => \@dst_mac_subarray, + dl_vlan => 0xffff, + dl_type => 0x0800, + nw_src => $src_ip, + nw_dst => $dst_ip, + nw_proto => $proto, #any protocol + tp_src => ${ $udp_pkt->{UDP_pdu} }->SrcPort, + tp_dst => ${ $udp_pkt->{UDP_pdu} }->DstPort + }; + + my $action_output_args = { + max_len => 0, # send entire packet + port => $out_port + }; + print "My Out Port: ${out_port}\n"; + + my $action_args = { + type => $enums{'OFPAT_OUTPUT'}, + arg => { output => $action_output_args } + }; + my $action = $ofp->pack( 'ofp_action', $action_args ); + + my $flow_mod_args = { + header => $hdr_args, + match => $match_args, + command => $enums{'OFPFC_ADD'}, + max_idle => $max_idle, + buffer_id => 0x0000, + group_id => 0 + }; + my $flow_mod = $ofp->pack( 'ofp_flow_mod', $flow_mod_args ); + + my $flow_mod_pkt = $flow_mod . $action; + + return $flow_mod_pkt; +} + +run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_ip_protocol/case-d.pl b/openflow/regress/projects/black_box/regress/test_ip_protocol/case-d.pl new file mode 100755 index 00000000..4f71280e --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_ip_protocol/case-d.pl @@ -0,0 +1,152 @@ +#!/usr/bin/perl -w +# test_ip_protocol (case d, not TCP nor UDP, but specify src port=0, dst port=0); + +use strict; +use OF::Includes; + +sub send_expect_exact { + + my ( $ofp, $sock, $in_port, $out_port, $max_idle, $pkt_len ) = @_; + + # in_port refers to the flow mod entry's input + + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + src_port => 70, + dst_port => 80 + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + ## Change protoco field + my $iphdr=$test_pkt->{'IP_hdr'}; + $$iphdr->proto(0x13); # overwrite protocol filed in IP header + + #print HexDump ( $test_pkt->packed ); + + my $wildcards = 0x0; # exact match + + my $flow_mod_pkt = + create_flow_mod_from_ip( $ofp, $test_pkt, $in_port, $out_port, + $max_idle, $wildcards, 0, 0); + + #print HexDump($flow_mod_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent flow_mod message\n"; + usleep(100000); + + + # Send a packet - ensure packet comes out desired port + nftest_send( "eth" . ( $in_port + 1 ), + $test_pkt->packed ); + nftest_expect( "eth" . ( $out_port + 1 ), + $test_pkt->packed ); +} + + +sub my_test { + + my ($sock, $options_ref) = @_; + + my $max_idle = $$options_ref{'max_idle'}; + my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_total = $$options_ref{'pkt_total'}; + + # send from every port to every other port + for ( my $i = 0 ; $i < 4 ; $i++ ) { + for ( my $j = 0 ; $j < 4 ; $j++ ) { + if ( $i != $j ) { + print "sending from $i to $j\n"; + send_expect_exact( $ofp, $sock, $i, $j, $max_idle, $pkt_len ); + wait_for_flow_expired_all( $ofp, $sock, $options_ref ); + } + } + } +} + +sub create_flow_mod_from_ip { + + my ( $ofp, $udp_pkt, $in_port, $out_port, $max_idle, $wildcards, $s_port, $d_port ) = @_; + + my $hdr_args = { + version => get_of_ver(), + type => $enums{'OFPT_FLOW_MOD'}, + length => $ofp->sizeof('ofp_flow_mod') + $ofp->sizeof('ofp_action'), + xid => 0x0000000 + }; + + # might be cleaner to convert the exported colon-hex MAC addrs + #print ${$udp_pkt->{Ethernet_hdr}}->SA . "\n"; + #print ${$test_pkt->{Ethernet_hdr}}->SA . "\n"; + my $ref_to_eth_hdr = ( $udp_pkt->{'Ethernet_hdr'} ); + my $ref_to_ip_hdr = ( $udp_pkt->{'IP_hdr'} ); + + # pointer to array + my $eth_hdr_bytes = $$ref_to_eth_hdr->{'bytes'}; + my $ip_hdr_bytes = $$ref_to_ip_hdr->{'bytes'}; + my @dst_mac_subarray = @{$eth_hdr_bytes}[ 0 .. 5 ]; + my @src_mac_subarray = @{$eth_hdr_bytes}[ 6 .. 11 ]; + + my @src_ip_subarray = @{$ip_hdr_bytes}[ 12 .. 15 ]; + my @dst_ip_subarray = @{$ip_hdr_bytes}[ 16 .. 19 ]; + + my $src_ip = + ( ( 2**24 ) * $src_ip_subarray[0] + ( 2**16 ) * $src_ip_subarray[1] + + ( 2**8 ) * $src_ip_subarray[2] + $src_ip_subarray[3] ); + + my $dst_ip = + ( ( 2**24 ) * $dst_ip_subarray[0] + ( 2**16 ) * $dst_ip_subarray[1] + + ( 2**8 ) * $dst_ip_subarray[2] + $dst_ip_subarray[3] ); + + # read IP_header protocol field + my $iph = $udp_pkt->{'IP_hdr'}; + my $proto = $$iph->proto(); + + my $match_args = { + wildcards => $wildcards, + in_port => $in_port, + dl_src => \@src_mac_subarray, + dl_dst => \@dst_mac_subarray, + dl_vlan => 0xffff, + dl_type => 0x0800, + nw_src => $src_ip, + nw_dst => $dst_ip, + nw_proto => $proto, #any protocol + tp_src => $s_port, + tp_dst => $d_port + }; + + my $action_output_args = { + max_len => 0, # send entire packet + port => $out_port + }; + print "My Out Port: ${out_port}\n"; + + my $action_args = { + type => $enums{'OFPAT_OUTPUT'}, + arg => { output => $action_output_args } + }; + my $action = $ofp->pack( 'ofp_action', $action_args ); + + my $flow_mod_args = { + header => $hdr_args, + match => $match_args, + command => $enums{'OFPFC_ADD'}, + max_idle => $max_idle, + buffer_id => 0x0000, + group_id => 0 + }; + my $flow_mod = $ofp->pack( 'ofp_flow_mod', $flow_mod_args ); + + my $flow_mod_pkt = $flow_mod . $action; + + return $flow_mod_pkt; +} + +run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_ip_protocol/case-e.pl b/openflow/regress/projects/black_box/regress/test_ip_protocol/case-e.pl new file mode 100755 index 00000000..47d1227c --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_ip_protocol/case-e.pl @@ -0,0 +1,152 @@ +#!/usr/bin/perl -w +# test_ip_protocol (case e, not TCP nor UDP, but specify src port!=0, dst port!=0); + +use strict; +use OF::Includes; + +sub send_expect_exact { + + my ( $ofp, $sock, $in_port, $out_port, $max_idle, $pkt_len ) = @_; + + # in_port refers to the flow mod entry's input + + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + src_port => 70, + dst_port => 80 + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + ## Change protoco field + my $iphdr=$test_pkt->{'IP_hdr'}; + $$iphdr->proto(0x13); # overwrite protocol filed in IP header + + #print HexDump ( $test_pkt->packed ); + + my $wildcards = 0x0; # exact match + + my $flow_mod_pkt = + create_flow_mod_from_ip( $ofp, $test_pkt, $in_port, $out_port, + $max_idle, $wildcards, 3, 4); + + #print HexDump($flow_mod_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent flow_mod message\n"; + usleep(100000); + + + # Send a packet - ensure packet comes out desired port + nftest_send( "eth" . ( $in_port + 1 ), + $test_pkt->packed ); + nftest_expect( "eth" . ( $out_port + 1 ), + $test_pkt->packed ); +} + + +sub my_test { + + my ($sock, $options_ref) = @_; + + my $max_idle = $$options_ref{'max_idle'}; + my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_total = $$options_ref{'pkt_total'}; + + # send from every port to every other port + for ( my $i = 0 ; $i < 4 ; $i++ ) { + for ( my $j = 0 ; $j < 4 ; $j++ ) { + if ( $i != $j ) { + print "sending from $i to $j\n"; + send_expect_exact( $ofp, $sock, $i, $j, $max_idle, $pkt_len ); + wait_for_flow_expired_all( $ofp, $sock, $options_ref ); + } + } + } +} + +sub create_flow_mod_from_ip { + + my ( $ofp, $udp_pkt, $in_port, $out_port, $max_idle, $wildcards, $s_port, $d_port ) = @_; + + my $hdr_args = { + version => get_of_ver(), + type => $enums{'OFPT_FLOW_MOD'}, + length => $ofp->sizeof('ofp_flow_mod') + $ofp->sizeof('ofp_action'), + xid => 0x0000000 + }; + + # might be cleaner to convert the exported colon-hex MAC addrs + #print ${$udp_pkt->{Ethernet_hdr}}->SA . "\n"; + #print ${$test_pkt->{Ethernet_hdr}}->SA . "\n"; + my $ref_to_eth_hdr = ( $udp_pkt->{'Ethernet_hdr'} ); + my $ref_to_ip_hdr = ( $udp_pkt->{'IP_hdr'} ); + + # pointer to array + my $eth_hdr_bytes = $$ref_to_eth_hdr->{'bytes'}; + my $ip_hdr_bytes = $$ref_to_ip_hdr->{'bytes'}; + my @dst_mac_subarray = @{$eth_hdr_bytes}[ 0 .. 5 ]; + my @src_mac_subarray = @{$eth_hdr_bytes}[ 6 .. 11 ]; + + my @src_ip_subarray = @{$ip_hdr_bytes}[ 12 .. 15 ]; + my @dst_ip_subarray = @{$ip_hdr_bytes}[ 16 .. 19 ]; + + my $src_ip = + ( ( 2**24 ) * $src_ip_subarray[0] + ( 2**16 ) * $src_ip_subarray[1] + + ( 2**8 ) * $src_ip_subarray[2] + $src_ip_subarray[3] ); + + my $dst_ip = + ( ( 2**24 ) * $dst_ip_subarray[0] + ( 2**16 ) * $dst_ip_subarray[1] + + ( 2**8 ) * $dst_ip_subarray[2] + $dst_ip_subarray[3] ); + + # read IP_header protocol field + my $iph = $udp_pkt->{'IP_hdr'}; + my $proto = $$iph->proto(); + + my $match_args = { + wildcards => $wildcards, + in_port => $in_port, + dl_src => \@src_mac_subarray, + dl_dst => \@dst_mac_subarray, + dl_vlan => 0xffff, + dl_type => 0x0800, + nw_src => $src_ip, + nw_dst => $dst_ip, + nw_proto => $proto, #any protocol + tp_src => $s_port, + tp_dst => $d_port + }; + + my $action_output_args = { + max_len => 0, # send entire packet + port => $out_port + }; + print "My Out Port: ${out_port}\n"; + + my $action_args = { + type => $enums{'OFPAT_OUTPUT'}, + arg => { output => $action_output_args } + }; + my $action = $ofp->pack( 'ofp_action', $action_args ); + + my $flow_mod_args = { + header => $hdr_args, + match => $match_args, + command => $enums{'OFPFC_ADD'}, + max_idle => $max_idle, + buffer_id => 0x0000, + group_id => 0 + }; + my $flow_mod = $ofp->pack( 'ofp_flow_mod', $flow_mod_args ); + + my $flow_mod_pkt = $flow_mod . $action; + + return $flow_mod_pkt; +} + +run_black_box_test(\&my_test); diff --git a/openflow/regress/projects/black_box/regress/test_ip_protocol/case-tcp.pl b/openflow/regress/projects/black_box/regress/test_ip_protocol/case-tcp.pl new file mode 100755 index 00000000..98117252 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_ip_protocol/case-tcp.pl @@ -0,0 +1,153 @@ +#!/usr/bin/perl -w +# test_ip_protocol (tcp) + +use strict; +use OF::Includes; + +sub send_expect_exact { + + my ( $ofp, $sock, $in_port, $out_port, $max_idle, $pkt_len ) = @_; + + # in_port refers to the flow mod entry's input + + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + src_port => 70, + dst_port => 80 + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + ## Make packet TCP (assuming only tcp src port, tcp dst port fields are used) + my $iphdr = $test_pkt->{'IP_hdr'}; + $$iphdr->proto(6); # overwrite protocol filed in IP header + + #print HexDump ( $test_pkt->packed ); + + my $wildcards = 0x0; # exact match + + my $flow_mod_pkt = + create_flow_mod_from_pseudo_tcp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, + $wildcards ); + + #print HexDump($flow_mod_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent flow_mod message\n"; + usleep(100000); + + # Send a packet - ensure packet comes out desired port + nftest_send( "eth" . ( $in_port + 1 ), $test_pkt->packed ); + nftest_expect( "eth" . ( $out_port + 1 ), $test_pkt->packed ); +} + +sub my_test { + + my ($sock, $options_ref) = @_; + + my $max_idle = $$options_ref{'max_idle'}; + my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_total = $$options_ref{'pkt_total'}; + + # send from every port to every other port + for ( my $i = 0 ; $i < 4 ; $i++ ) { + for ( my $j = 0 ; $j < 4 ; $j++ ) { + if ( $i != $j ) { + print "sending from $i to $j\n"; + send_expect_exact( $ofp, $sock, $i, $j, $max_idle, $pkt_len ); + wait_for_flow_expired_all( $ofp, $sock, $options_ref ); + } + } + } +} + +sub create_flow_mod_from_pseudo_tcp { + + my ( $ofp, $udp_pkt, $in_port, $out_port, $max_idle, $wildcards ) = @_; + + my $hdr_args = { + version => get_of_ver(), + type => $enums{'OFPT_FLOW_MOD'}, + length => $ofp->sizeof('ofp_flow_mod') + $ofp->sizeof('ofp_action'), + xid => 0x0000000 + }; + + # might be cleaner to convert the exported colon-hex MAC addrs + #print ${$udp_pkt->{Ethernet_hdr}}->SA . "\n"; + #print ${$test_pkt->{Ethernet_hdr}}->SA . "\n"; + my $ref_to_eth_hdr = ( $udp_pkt->{'Ethernet_hdr'} ); + my $ref_to_ip_hdr = ( $udp_pkt->{'IP_hdr'} ); + + # pointer to array + my $eth_hdr_bytes = $$ref_to_eth_hdr->{'bytes'}; + my $ip_hdr_bytes = $$ref_to_ip_hdr->{'bytes'}; + my @dst_mac_subarray = @{$eth_hdr_bytes}[ 0 .. 5 ]; + my @src_mac_subarray = @{$eth_hdr_bytes}[ 6 .. 11 ]; + + my @src_ip_subarray = @{$ip_hdr_bytes}[ 12 .. 15 ]; + my @dst_ip_subarray = @{$ip_hdr_bytes}[ 16 .. 19 ]; + + my $src_ip = + ( ( 2**24 ) * $src_ip_subarray[0] + + ( 2**16 ) * $src_ip_subarray[1] + + ( 2**8 ) * $src_ip_subarray[2] + + $src_ip_subarray[3] ); + + my $dst_ip = + ( ( 2**24 ) * $dst_ip_subarray[0] + + ( 2**16 ) * $dst_ip_subarray[1] + + ( 2**8 ) * $dst_ip_subarray[2] + + $dst_ip_subarray[3] ); + + # read IP_header protocol field + my $iph = $udp_pkt->{'IP_hdr'}; + my $proto = $$iph->proto(); + + my $match_args = { + wildcards => $wildcards, + in_port => $in_port, + dl_src => \@src_mac_subarray, + dl_dst => \@dst_mac_subarray, + dl_vlan => 0xffff, + dl_type => 0x0800, + nw_src => $src_ip, + nw_dst => $dst_ip, + nw_proto => $proto, #any protocol + tp_src => ${ $udp_pkt->{UDP_pdu} }->SrcPort, + tp_dst => ${ $udp_pkt->{UDP_pdu} }->DstPort + }; + + my $action_output_args = { + max_len => 0, # send entire packet + port => $out_port + }; + print "My Out Port: ${out_port}\n"; + + my $action_args = { + type => $enums{'OFPAT_OUTPUT'}, + arg => { output => $action_output_args } + }; + my $action = $ofp->pack( 'ofp_action', $action_args ); + + my $flow_mod_args = { + header => $hdr_args, + match => $match_args, + command => $enums{'OFPFC_ADD'}, + max_idle => $max_idle, + buffer_id => 0x0000, + group_id => 0 + }; + my $flow_mod = $ofp->pack( 'ofp_flow_mod', $flow_mod_args ); + + my $flow_mod_pkt = $flow_mod . $action; + + return $flow_mod_pkt; +} + +run_black_box_test( \&my_test, \@ARGV); + diff --git a/openflow/regress/projects/black_box/regress/test_ip_protocol/case-udp.pl b/openflow/regress/projects/black_box/regress/test_ip_protocol/case-udp.pl new file mode 100755 index 00000000..5f59ad32 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_ip_protocol/case-udp.pl @@ -0,0 +1,67 @@ +#!/usr/bin/perl -w +# test_ip_protocol (udp) + +use strict; +use OF::Includes; + +sub send_expect_exact { + + my ( $ofp, $sock, $in_port, $out_port, $max_idle, $pkt_len ) = @_; + + # in_port refers to the flow mod entry's input + + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + src_port => 70, + dst_port => 80 + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + #print HexDump ( $test_pkt->packed ); + + my $wildcards = 0x0; # exact match + my $flags = 0x0; # don't send flow expiry + + my $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, + $max_idle, $flags, $wildcards ); + + #print HexDump($flow_mod_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent flow_mod message\n"; + usleep(100000); + + # Send a packet - ensure packet comes out desired port + nftest_send( "eth" . ( $in_port + 1 ), $test_pkt->packed ); + nftest_expect( "eth" . ( $out_port + 1 ), $test_pkt->packed ); +} + +sub my_test { + + my ($sock, $options_ref) = @_; + + my $max_idle = $$options_ref{'max_idle'}; + my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_total = $$options_ref{'pkt_total'}; + + # send from every port to every other port + for ( my $i = 0 ; $i < 4 ; $i++ ) { + for ( my $j = 0 ; $j < 4 ; $j++ ) { + if ( $i != $j ) { + print "sending from $i to $j\n"; + send_expect_exact( $ofp, $sock, $i, $j, $max_idle, $pkt_len ); + wait_for_flow_expired_all( $ofp, $sock, $options_ref ); + } + } + } +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_llc/run.pl b/openflow/regress/projects/black_box/regress/test_llc/run.pl new file mode 100755 index 00000000..761f878d --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_llc/run.pl @@ -0,0 +1,128 @@ +#!/usr/bin/perl -w +# test_llc (use $EthFMT = "LLC") +# if you want to test DIX format, use use $EthFMT = "DIX" + +use strict; +use OF::Includes; + +## choose one from "DIX" or "LLC"; +#my $EthFMT = "DIX"; +my $EthFMT = "LLC"; + +my $pkt_len_llc = 68; +my $pkt_len_dix = 60; + +my $pkt_len; +if ( $EthFMT eq "LLC" ) { + $pkt_len = $pkt_len_llc; + print "test for LLC\n"; +} +else { + $pkt_len = $pkt_len_dix; + print "test for DIX\n"; +} + +sub send_expect_exact_oneshot { + + my ( $ofp, $sock, $in_port, $out_port, $max_idle, $pkt_len ) = @_; + + my $test_pkt_llc_ip = new NF2::PDU($pkt_len_llc); + @{ $test_pkt_llc_ip->{'bytes'} }[ 0 .. ( $pkt_len_llc - 1 ) ] = ( + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, # dst mac 6byte (02:02:02:02:02:02) + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, # src mac 6byte (04:04:04:04:04:04) + 0x00, 0x36, # 2byte (Length=54byte=0x0036) + 0xAA, 0xAA, 0x03, #LLC # 3byte (always this value) + 0x00, 0x00, 0x00, #SNAP(OUI) # 3byte (always this value) + 0x08, 0x00, #SNAP(PID) # 2byte (0x0800 = IP) + 0x45, 0x00, 0x00, 0x2E, # 46 byte + 0x00, 0x00, 0x40, 0x00, # + 0x40, 0x11, 0xB8, 0x1E, # TTL=64, proto=UDP(0x11) + 0xC0, 0xA8, 0xC9, 0x28, # SrcIP= 192.168.201.40 + 0xC0, 0xA8, 0xC8, 0x28, # DstIP= 192.168.200.40 + 0x00, 0x46, 0x00, 0x50, # SrcPort=70, DstPort=80 + 0x00, 0x1A, 0xCD, 0x3F, # .. + 0xAE, 0xA5, 0x7F, 0x87, + 0xEE, 0x67, 0x72, 0xA7, + 0x17, 0x91, 0xFE, 0x10, + 0xBD, 0xFA, 0xC0, 0xC2, + 0x8B, 0xA7 + ); + + my $test_pkt_dix_ip = new NF2::PDU($pkt_len_dix); + @{ $test_pkt_dix_ip->{'bytes'} }[ 0 .. ( $pkt_len_dix - 1 ) ] = ( + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, # dst mac 6byte (02:02:02:02:02:02) + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, # src mac 6byte (04:04:04:04:04:04) + 0x08, 0x00, + 0x45, 0x00, 0x00, 0x2E, # 46 byte + 0x00, 0x00, 0x40, 0x00, # + 0x40, 0x11, 0xB8, 0x1E, # TTL=64, proto=UDP(0x11) + 0xC0, 0xA8, 0xC9, 0x28, # SrcIP= 192.168.201.40 + 0xC0, 0xA8, 0xC8, 0x28, # DstIP= 192.168.200.40 + 0x00, 0x46, 0x00, 0x50, # SrcPort=70, DstPort=80 + 0x00, 0x1A, 0xCD, 0x3F, # .. + 0xAE, 0xA5, 0x7F, 0x87, + 0xEE, 0x67, 0x72, 0xA7, + 0x17, 0x91, 0xFE, 0x10, + 0xBD, 0xFA, 0xC0, 0xC2, + 0x8B, 0xA7 + ); + + # Create Test Packet (only to call "create_flow_mod_from_udp") + # which should match test_pkt_llc_ip or test_pkt_dix packet + my $test_pkt_args = { + DA => "02:02:02:02:02:02", + SA => "04:04:04:04:04:04", + src_ip => "192.168.201.40", + dst_ip => "192.168.200.40", + ttl => 64, + len => $pkt_len, + src_port => 70, + dst_port => 80 + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + my $wildcards = 0x0; # exact match + my $flags = 0x0; # don't send flow expiry + my $flow_mod_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); + + #print HexDump($flow_mod_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent flow_mod message\n"; + usleep(100000); + + # Send a packet - ensure packet comes out desired port + if ( $EthFMT eq "LLC" ) { + nftest_send( "eth" . ( $in_port + 1 ), $test_pkt_llc_ip->packed ); + nftest_expect( "eth" . ( $out_port + 1 ), $test_pkt_llc_ip->packed ); + } + else { + nftest_send( "eth" . ( $in_port + 1 ), $test_pkt_dix_ip->packed ); + nftest_expect( "eth" . ( $out_port + 1 ), $test_pkt_dix_ip->packed ); + } +} + +sub my_test { + + my ($sock, $options_ref) = @_; + + my $max_idle = $$options_ref{'max_idle'}; + #my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_total = $$options_ref{'pkt_total'}; + + # send from every port to every other port + for ( my $i = 0 ; $i < 4 ; $i++ ) { + for ( my $j = 0 ; $j < 4 ; $j++ ) { + if ( $i != $j ) { + print "sending from $i to $j\n"; + send_expect_exact_oneshot( $ofp, $sock, $i, $j, $max_idle, $pkt_len ); + wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); + } + } + } +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_miss_send_length/run.pl b/openflow/regress/projects/black_box/regress/test_miss_send_length/run.pl new file mode 100755 index 00000000..d787a624 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_miss_send_length/run.pl @@ -0,0 +1,79 @@ +#!/usr/bin/perl -w +# test_packet_in +# Send a packet of size 256B, and ensure that it gets reduced to 128B + +use strict; +use OF::Includes; + +sub verify_packet_in { + my ($sock, $options_ref, $miss_send_len, $pktsiz, $expected_pktsiz) = @_; + + my $in_port = $$options_ref{'port_base'}; + my $out_port = $in_port + 1; + + # Give OF switch time to process the set_config + usleep($$options_ref{'send_delay'}); + + my $pkt = get_default_black_box_pkt_len($in_port, $out_port, $pktsiz); + nftest_send('eth1', $pkt->packed); + print "Sent test packet for len ".$miss_send_len."...\n"; + + my $rcvd_msg; + sysread($sock, $rcvd_msg, 1512) || die "Failed to receive message: $!"; + + # Inspect message + my $msg_size = length($rcvd_msg); + compare("msg size", $msg_size, '==', $expected_pktsiz); + + my $msg = $ofp->unpack('ofp_packet_in', $rcvd_msg); + #print HexDump ($rcvd_msg); + #print Dumper($msg); + + # Verify fields + verify_header($msg, 'OFPT_PACKET_IN', $msg_size); + + # total len should be full length of original sent frame + compare("total len", $$msg{'total_len'}, '==', length($pkt->packed)); + compare("in_port", $$msg{'in_port'}, '==', $in_port); + compare("reason", $$msg{'reason'}, '==', $enums{'OFPR_NO_MATCH'}); + + # verify packet was unchanged! + my $rcvd_pkt_data = substr($rcvd_msg, $ofp->offsetof('ofp_packet_in', 'data')); + + # trim to MISS_SEND_LEN + my $pkt_trimmed = substr($pkt->packed, 0, $miss_send_len); + if ($rcvd_pkt_data ne $pkt_trimmed) { + die "ERROR: received packet data didn't match packet sent\n"; + } +} + +sub my_test { + my ($sock, $options_ref) = @_; + + my $miss_send_len = get_of_miss_send_len_default(); + my $pktsiz = 63; + my $expected_pktsiz = 8 + 10 + $pktsiz; + verify_packet_in($sock, $options_ref, $miss_send_len, $pktsiz, $expected_pktsiz); + + $miss_send_len = 0; + $pktsiz = 67; + $expected_pktsiz = 8 + 10; + set_config($ofp, $sock, $options_ref, 1, $miss_send_len); + verify_packet_in($sock, $options_ref, $miss_send_len, $pktsiz, $expected_pktsiz); + + $miss_send_len = 127; + $pktsiz = 259; + $expected_pktsiz = 8 + 10 + $miss_send_len; + set_config($ofp, $sock, $options_ref, 1, $miss_send_len); + verify_packet_in($sock, $options_ref, $miss_send_len, $pktsiz, $expected_pktsiz); + + $miss_send_len = 65535; + $pktsiz = 1500 - 8 - 10; + $expected_pktsiz = 1500; + set_config($ofp, $sock, $options_ref, 1, $miss_send_len); + verify_packet_in($sock, $options_ref, $miss_send_len, $pktsiz, $expected_pktsiz); + + set_config($ofp, $sock, $options_ref, 1, get_of_miss_send_len_default()); +} + +run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_packet_in/run.pl b/openflow/regress/projects/black_box/regress/test_packet_in/run.pl new file mode 100755 index 00000000..7ddfb830 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_packet_in/run.pl @@ -0,0 +1,45 @@ +#!/usr/bin/perl -w +# test_packet_in + +use strict; +use OF::Includes; + +sub my_test { + + my ($sock, $options_ref) = @_; + + my $in_port = $$options_ref{'port_base'}; + my $out_port = $in_port + 1; + + my $pkt = get_default_black_box_pkt( $in_port, $out_port); + nftest_send('eth1', $pkt->packed ); + print "Sent test packet...\n"; + + my $recvd_mesg; + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; + + # Inspect message + my $msg_size = length($recvd_mesg); + my $expected_size = $ofp->offsetof( 'ofp_packet_in', 'data' ) + length( $pkt->packed ); + compare( "msg size", $msg_size, '==', $expected_size ); + + my $msg = $ofp->unpack( 'ofp_packet_in', $recvd_mesg ); + + #print HexDump ($recvd_mesg); + #print Dumper($msg); + + # Verify fields + verify_header( $msg, 'OFPT_PACKET_IN', $msg_size ); + + compare( "total len", $$msg{'total_len'}, '==', length( $pkt->packed ) ); + compare( "in_port", $$msg{'in_port'}, '==', $in_port ); + compare( "reason", $$msg{'reason'}, '==', $enums{'OFPR_NO_MATCH'} ); + + # verify packet was unchanged! + my $recvd_pkt_data = substr( $recvd_mesg, $ofp->offsetof( 'ofp_packet_in', 'data' ) ); + if ( $recvd_pkt_data ne $pkt->packed ) { + die "ERROR: received packet data didn't match packet sent\n"; + } +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_packet_out/run.pl b/openflow/regress/projects/black_box/regress/test_packet_out/run.pl new file mode 100755 index 00000000..4d872ac8 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_packet_out/run.pl @@ -0,0 +1,53 @@ +#!/usr/bin/perl -w +# test_packet_out + +use strict; +use OF::Includes; + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + my $port_base = $$options_ref{'port_base'}; + my $in_port = $port_base; + my $out_port = $in_port + 1; + + my $pkt = get_default_black_box_pkt( $in_port, $out_port ); + + my $hdr_args = { + version => get_of_ver(), + type => $enums{'OFPT_PACKET_OUT'}, + length => $ofp->sizeof('ofp_packet_out') + + $ofp->sizeof('ofp_action_output') + + length( $pkt->packed ), # should generate automatically! + xid => 0x0000abcd + }; + my $packet_out_args = { + header => $hdr_args, + buffer_id => -1, # data included in this packet + in_port => $enums{'OFPP_NONE'}, + actions_len => $ofp->sizeof('ofp_action_output') + }; + my $packet_out = $ofp->pack( 'ofp_packet_out', $packet_out_args ); + my $action_output_args = { + type => $enums{'OFPAT_OUTPUT'}, + len => $ofp->sizeof('ofp_action_output'), + port => $port_base, # send out eth1 + max_len => get_of_miss_send_len_default() + }; + my $action_output = $ofp->pack( 'ofp_action_output', $action_output_args ); + + my $pkt_sent = $packet_out . $action_output . $pkt->packed; + + # Send 'packet_out' message + print $sock $pkt_sent; + + nftest_expect( 'eth1', $pkt->packed ); + + # Wait for packet to be forwarded out + sleep(.1); + +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_port_stats/run.pl b/openflow/regress/projects/black_box/regress/test_port_stats/run.pl new file mode 100755 index 00000000..5c321c8d --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_port_stats/run.pl @@ -0,0 +1,132 @@ +#!/usr/bin/perl -w +# test_port_stats + +use strict; +use OF::Includes; + +sub forward_any { + forward_simple(@_, 'any'); +} + +sub my_test { + my ($sock, $options_ref) = @_; + + my $port_base = $$options_ref{'port_base'}; + my $num_ports = $$options_ref{'num_ports'}; + + my $hdr_args = { + version => get_of_ver(), + type => $enums{'OFPT_STATS_REQUEST'}, + length => $ofp->sizeof('ofp_stats_request') + $ofp->sizeof('ofp_port_stats_request'), # should generate automatically! + xid => 0x00000000 + }; + + my $stats_reqhdr_args = { + header => $hdr_args, + type => $enums{'OFPST_PORT'}, + flags => 0 + }; + + my $stats_all_ports_reqbody_args = { + port_no => $enums{'OFPP_NONE'}, + }; + my $stats_single_port_reqbody_args = { + port_no => 1, + }; + my $stats_invalid_port_reqbody_args = { + port_no => 32768, + }; + + my $stats_reqhead = $ofp->pack('ofp_stats_request', $stats_reqhdr_args); + my $stats_all_ports_reqbody = $ofp->pack('ofp_port_stats_request', $stats_all_ports_reqbody_args); + my $stats_single_port_reqbody = $ofp->pack('ofp_port_stats_request', $stats_single_port_reqbody_args); + my $stats_invalid_port_reqbody = $ofp->pack('ofp_port_stats_request', $stats_invalid_port_reqbody_args); + my $stats_all_ports_reqmsg = $stats_reqhead . $stats_all_ports_reqbody; + my $stats_single_port_reqmsg = $stats_reqhead . $stats_single_port_reqbody; + my $stats_invalid_port_reqmsg = $stats_reqhead . $stats_invalid_port_reqbody; + + my $stats_rephdr_args = { + version => get_of_ver(), + type => $enums{'OFPT_STATS_REPLY'}, + length => $ofp->sizeof('ofp_stats_reply'), # should generate automatically! + xid => 0x00000000 + }; + + my $stats_repbody_args = { + header => $stats_rephdr_args, + type => $enums{'OFPST_PORT'}, + flags => 0 + }; + + my $stats_repbody; + for (my $i = $port_base; $i < $port_base + $num_ports; $i++ ) { + my $body_args = { + port_no => $port_base, + rx_count => 0, + tx_count => 0, + drop_count => 0 + }; + $stats_repbody .= $ofp->pack('ofp_port_stats', $body_args); + } + + my $stats_repmsg = $ofp->pack('ofp_stats_reply', $stats_repbody_args) . $stats_repbody; + my $rcvd_msg; + + # Send 'stats_request' for single port + print $sock $stats_single_port_reqmsg; + # Should add timeout here - will crash if no reply + sysread($sock, $rcvd_msg, 1512) || die "Failed to receive message: $!"; + + # Send 'stats_request' for invalid port + print $sock $stats_invalid_port_reqmsg; + # Should add timeout here - will crash if no reply + sysread($sock, $rcvd_msg, 1512) || die "Failed to receive message: $!"; + + # Send 'stats_request' for all ports + print $sock $stats_all_ports_reqmsg; + # Should add timeout here - will crash if no reply + sysread($sock, $rcvd_msg, 1512) || die "Failed to receive message: $!"; + + # Inspect message + my $msg_size = length($rcvd_msg); + my $expected_size = $ofp->sizeof('ofp_stats_reply') + 4 * $ofp->sizeof('ofp_port_stats'); + + # Removed this compare because varying numbers of ports may be activated + # compare("msg size", $msg_size, '==', $expected_size); + my $msg = $ofp->unpack('ofp_stats_reply', $rcvd_msg); + #print HexDump($rcvd_msg); + #print Dumper($msg); + + # Verify fields + verify_header($msg, 'OFPT_STATS_REPLY', $msg_size); + compare("type", $$msg{'type'}, '==', $enums{'OFPST_PORT'}); + compare("flags", $$msg{'flags'}, '==', 0); + +# if ($rcvd_msg ne $stats_reply) { +# die "stats reply is not what was expected" +# } + + # TODO: Look at each received port_stats field, to ensure they equal zero... + + # Send data plane packets + for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_any, 0x1fffff); + + # TODO: Look at each received port_stats field, to ensure correct counters + + # Send 'stats_request' for all ports + print $sock $stats_all_ports_reqmsg; + # Should add timeout here - will crash if no reply + sysread($sock, $rcvd_msg, 1512) || die "Failed to receive message: $!"; + + # Send 'stats_request' for invalid port + print $sock $stats_invalid_port_reqmsg; + # Should add timeout here - will crash if no reply + sysread($sock, $rcvd_msg, 1512) || die "Failed to receive message: $!"; + + # Send 'stats_request' for single port + print $sock $stats_single_port_reqmsg; + # Should add timeout here - will crash if no reply + sysread($sock, $rcvd_msg, 1512) || die "Failed to receive message: $!"; +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_queue_config/run.pl b/openflow/regress/projects/black_box/regress/test_queue_config/run.pl new file mode 100755 index 00000000..e3f512ee --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_queue_config/run.pl @@ -0,0 +1,52 @@ +#!/usr/bin/perl -w +# test_queue_config + +use strict; +use OF::Includes; + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + if ( not defined( $$options_ref{'no_slicing'} ) ) { + my $port_base = $$options_ref{'port_base'}; + my $num_ports = $$options_ref{'num_ports'}; + + # for each port, + + for (my $i = 1; $i <= $num_ports; $i++){ + + my $hdr_args = { + version => get_of_ver(), + type => $enums{'OFPT_QUEUE_GET_CONFIG_REQUEST'}, + length => $ofp->sizeof('ofp_queue_get_config_request'), # should generate automatically! + xid => 0x00000000 + }; + + my @pad_2 = (0,0); + my $queue_request_args = { + header => $hdr_args, + port => $i, + pad => \@pad_2 + }; + + my $queue_request = $ofp->pack( 'ofp_queue_get_config_request', $queue_request_args ); + + # Send 'stats_request' message + print $sock $queue_request; + + # Should add timeout here - will crash if no reply + my $recvd_mesg; + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; + + my $msg = $ofp->unpack( 'ofp_queue_get_config_reply', $recvd_mesg ); + + my $msg_size = length($recvd_mesg); + # Verify fields + verify_header( $msg, 'OFPT_QUEUE_GET_CONFIG_REPLY', $msg_size ); + } + } +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_queue_forward/run.pl b/openflow/regress/projects/black_box/regress/test_queue_forward/run.pl new file mode 100755 index 00000000..a3b0d737 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_queue_forward/run.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl -w +# test_queue_forward + +use strict; +use OF::Includes; + +sub forward_unicast_port { + forward_simple(@_, 'enqueue'); +} + +sub my_test { + my ($sock, $options_ref) = @_; + + if ( not defined( $$options_ref{'no_slicing'} ) ) { + for_all_port_pairs($ofp, $sock, $options_ref, \&forward_unicast_port, 0x0); + } +} + +run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_queue_stats/run.pl b/openflow/regress/projects/black_box/regress/test_queue_stats/run.pl new file mode 100755 index 00000000..0f49a329 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_queue_stats/run.pl @@ -0,0 +1,116 @@ +#!/usr/bin/perl -w +# test_queue_stats + +use strict; +use OF::Includes; + +sub my_test { + + my ( $sock, $options_ref ) = @_; + + if ( not defined( $$options_ref{'no_slicing'} ) ) { + + my $port_base = $$options_ref{'port_base'}; + my $num_ports = $$options_ref{'num_ports'}; + + # Prepare stats request + my $hdr_args = { + version => get_of_ver(), + type => $enums{'OFPT_STATS_REQUEST'}, + length => $ofp->sizeof('ofp_stats_request') + $ofp->sizeof('ofp_queue_stats_request'), # should generate automatically! + xid => 0x00000000 + }; + + my @pad_2 = (0,0); + my $body_args = { + port_no => $port_base, + pad => \@pad_2, + queue_id => 0xffffffff # TODO : export get_define to get OFPQ_ALL + }; + + + my $stats_request_args = { + header => $hdr_args, + type => $enums{'OFPST_QUEUE'}, + flags => 0 + }; + + my $request_body = $ofp->pack( 'ofp_queue_stats_request', $body_args ); + my $stats_request = $ofp->pack( 'ofp_stats_request', $stats_request_args ) . $request_body; + + + # Prepare expected stats reply + my $reply_hdr_args = { + version => get_of_ver(), + type => $enums{'OFPT_STATS_REPLY'}, + length => $ofp->sizeof('ofp_stats_reply') + $ofp->sizeof('ofp_queue_stats'), # should generate automatically! + xid => 0x00000000 + }; + + my $stats_reply_args = { + header => $reply_hdr_args, + type => $enums{'OFPST_QUEUE'}, + flags => 0 + }; + + + my $reply_body_args = { + port_no => $port_base, + pad => \@pad_2, + queue_id => 1, + tx_bytes => 0, + tx_packets => 0, + tx_errors => 0 + }; + + my $reply_body = $ofp->pack( 'ofp_queue_stats', $reply_body_args); + my $stats_reply = $ofp->pack( 'ofp_stats_reply', $stats_reply_args ) . $reply_body; + + # Send 'stats_request' message + print $sock $stats_request; + + # Should add timeout here - will crash if no reply + my $recvd_mesg; + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; + + # Inspect message + if ($recvd_mesg ne $stats_reply) { + die "ERROR: stats reply didn't match expected"; + } + + # Send a packet out + forward_simple($ofp, $sock, $options_ref, 1, 0, 0, 'enqueue'); + + # Wait the flow to expire + sleep 3; + + # Expect increased counters + $reply_body_args = { + port_no => $port_base, + pad => \@pad_2, + queue_id => 1, + tx_bytes => 64, + tx_packets => 1, + tx_errors => 0 + }; + + $reply_body = $ofp->pack( 'ofp_queue_stats', $reply_body_args); + $stats_reply = $ofp->pack( 'ofp_stats_reply', $stats_reply_args ) . $reply_body; + + + # Send 'stats_request' message + print $sock $stats_request; + + # Receive stats reply + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; + + # Inspect message + if ($recvd_mesg ne $stats_reply) { + die "ERROR: stats reply didn't match expected"; + } + } + +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_receive_bandwidth_fixed/run.pl b/openflow/regress/projects/black_box/regress/test_receive_bandwidth_fixed/run.pl new file mode 100755 index 00000000..342845e9 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_receive_bandwidth_fixed/run.pl @@ -0,0 +1,89 @@ +#!/usr/bin/perl -w +# test_receive_bandwidth_fixed + +use strict; +use OF::Includes; + +use Time::HiRes qw (sleep gettimeofday tv_interval usleep); + +my $pkts_total = 10000; +my $pkt_size = 64; +#my $pkt_size = 1512 - $ofp->sizeof( 'ofp_packet_in'); + +sub verify_packet_in { + + my ( $recvd_mesg, $pkt ) = @_; + + # Inspect message + my $msg_size = length($recvd_mesg); + my $expected_size = $ofp->offsetof( 'ofp_packet_in', 'data' ) + length( $pkt->packed ); + if ( $msg_size != $expected_size ) { return 1; } + + my $msg = $ofp->unpack( 'ofp_packet_in', $recvd_mesg ); + + # Verify fields + if ( ( $$msg{'header'}{'version'} != 1 ) + || ( $$msg{'header'}{'type'} != $enums{'OFPT_PACKET_IN'} ) + || ( $$msg{'header'}{'length'} != $msg_size ) + || ( $$msg{'total_len'} != length( $pkt->packed ) ) + || ( $$msg{'in_port'} != 0 ) + || ( $$msg{'reason'} != $enums{'OFPR_NO_MATCH'} ) ) + { + return 1; + } + + # verify packet was unchanged! + my $recvd_pkt_data = substr( $recvd_mesg, $ofp->offsetof( 'ofp_packet_in', 'data' ) ); + if ( $recvd_pkt_data ne $pkt->packed ) { return 1; } +} + +sub receive_fixed_bandwidth { + my ( $num_packets, $sock, $pkt, $interface ) = @_; + my $length = length( $pkt->packed ); + print "sending $num_packets packets\n"; + + my @start_time = gettimeofday(); + + my $errors = 0; + + for ( my $count = 0 ; $count < $num_packets ; $count++ ) { + + nftest_send( nftest_get_iface($interface), $pkt->packed ); + + my $recvd_mesg; + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; + + $errors += verify_packet_in( $recvd_mesg, $pkt ); + } + + my $sending_time = tv_interval( \@start_time ); + print "time elapsed: $sending_time\n"; + print "errors: $errors\n"; + + my $bps = ($num_packets - $errors) * $length * 8 / $sending_time; + printf "bandwidth achieved: %.0f bps \n", $bps; + + return $errors; +} + +sub my_test { + + my ($sock) = @_; + + my $pkt_args = { + DA => "00:00:00:00:00:02", + SA => "00:00:00:00:00:01", + src_ip => "192.168.200.40", + dst_ip => "192.168.201.40", + ttl => 64, + len => $pkt_size + }; + my $pkt = new NF2::IP_pkt(%$pkt_args); + + my $errors = &receive_fixed_bandwidth( $pkts_total, $sock, $pkt, 'eth1' ); + + if ($errors > 0) { die "received errors"; } +} + +run_black_box_test( \&my_test ); + diff --git a/openflow/regress/projects/black_box/regress/test_send_bandwidth_fixed/run.pl b/openflow/regress/projects/black_box/regress/test_send_bandwidth_fixed/run.pl new file mode 100755 index 00000000..2941d74a --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_send_bandwidth_fixed/run.pl @@ -0,0 +1,140 @@ +#!/usr/bin/perl -w +# test_send_bandwidth_fixed + +use strict; +use OF::Includes; + +use Time::HiRes qw (sleep gettimeofday tv_interval usleep); + +# Sends packets of the specified length, with specified data rate, over time = duration. +# Length is passed as a parameter and it should be also declared during packet's construction. + +sub send_fixed_bandwidth_unique { + my ( $rate, $duration, $sock, $pkt, $pkt_sent, $interface ) = @_; + my $length = length( $pkt->packed ); + my $num_packets = ( $rate * $duration ) / ( $length * 8 ); + my $inter_time = 1000000.0 * $duration / $num_packets; + + print "Running Test for a single packet size\n"; + print( +"Num Packets : $num_packets, Duration : $duration, Length : $length, InterTime : $inter_time Interface : $interface\n" + ); + + print "sending $num_packets packets\n"; + + my @start_time = gettimeofday(); + + my $count; + for ( $count = 0 ; $count < $num_packets ; $count++ ) { + + # Send 'packet_out' message + print $sock $pkt_sent; + nftest_expect( $interface, $pkt->packed ); + usleep($inter_time); + } + + my $sending_time = tv_interval(\@start_time); + print "time elapsed: $sending_time\n"; + + my $bps = $num_packets * $length * 8 / $sending_time; + print "bandwidth attempted: $rate (bps)\n"; + print "bandwidth achieved: $bps (bps)\n"; +} + +sub send_fixed_bandwidth_mixed { + my ( $rate, $duration, $sock, $pkt_sent_small,$pkt_sent_med,$pkt_sent_lrg,$pkt_small,$pkt_med,$pkt_lrg, $interface ) = @_; + my $len_s = length($pkt_small->packed); + my $len_m = length($pkt_med->packed); + my $len_l = length($pkt_lrg->packed); + my $num_loops = ( $rate * $duration ) / (( $len_s+$len_m+$len_l ) * 8 ); + my $num_packets = $num_loops*3; + my $inter_time = 1000000.0 * $duration / $num_packets; + + print "Running Test for different packet sizes\n"; + + print( +"Num Packets : $num_packets, Duration : $duration, Lengths : $len_s,$len_m,$len_l, InterTime : $inter_time Interface : $interface\n" + ); + + print "sending $num_packets packets\n"; + + my @start_time = gettimeofday(); + + my $count; + for ( $count = 0 ; $count < $num_loops ; $count++ ) { + + # Send 'packet_out' message + print $sock $pkt_sent_small; + nftest_expect( $interface, $pkt_small->packed ); + usleep($inter_time); + print $sock $pkt_sent_med; + nftest_expect( $interface, $pkt_med->packed ); + usleep($inter_time); + print $sock $pkt_sent_lrg; + nftest_expect( $interface, $pkt_lrg->packed ); + usleep($inter_time); + } + + my $sending_time = tv_interval(\@start_time); + print "time elapsed: $sending_time\n"; + + my $bps = $num_loops * ($len_s+$len_m+$len_l) * 8 / $sending_time; + print "bandwidth attempted: $rate(bps)\n"; + print "bandwidth achieved: $bps (bps)\n"; +} + + + +sub my_test { + + my $pkt_args = { + DA => "00:00:00:00:00:02", + SA => "00:00:00:00:00:01", + src_ip => "192.168.200.40", + dst_ip => "192.168.201.40", + ttl => 64, + len => 64 + }; + my $pkt_small = new NF2::IP_pkt(%$pkt_args); + $pkt_args->{ 'len' } = 256; + my $pkt_med = new NF2::IP_pkt(%$pkt_args); + $pkt_args->{ 'len' } = 512; + my $pkt_lrg = new NF2::IP_pkt(%$pkt_args); + + my $hdr_args = { + version => 1, + type => $enums{'OFPT_PACKET_OUT'}, + length => $ofp->sizeof('ofp_packet_out') + length( $pkt_small->packed ), # should generate automatically! + xid => 0x0000abcd + }; + my $packet_out_args = { + header => $hdr_args, + buffer_id => -1, # data included in this packet + in_port => $enums{'OFPP_NONE'}, + out_port => 0 # send out eth1 + }; + my $packet_out = $ofp->pack( 'ofp_packet_out', $packet_out_args ); + + my $pkt_sent_small = $packet_out . $pkt_small->packed; + $hdr_args->{'length'} = $ofp->sizeof('ofp_packet_out') + length( $pkt_med->packed ); + $packet_out_args->{'header'} = $hdr_args; + $packet_out = $ofp->pack( 'ofp_packet_out', $packet_out_args ); + my $pkt_sent_med = $packet_out . $pkt_med->packed; + $hdr_args->{'length'} = $ofp->sizeof('ofp_packet_out') + length( $pkt_lrg->packed ); + $packet_out_args->{'header'} = $hdr_args; + $packet_out = $ofp->pack( 'ofp_packet_out', $packet_out_args ); + my $pkt_sent_lrg = $packet_out . $pkt_lrg->packed; + + my ($sock) = @_; + + &send_fixed_bandwidth_unique( .1 * (10**6) ,5, $sock, $pkt_lrg, $pkt_sent_lrg, 'eth1' ); + + #&send_fixed_bandwidth_mixed( 5 * (10**5) ,5, $sock,$pkt_sent_small,$pkt_sent_med, $pkt_sent_lrg,$pkt_small,$pkt_med,$pkt_lrg,'eth1'); + + # Wait for test to finish + sleep(2); + +} + +run_black_box_test( \&my_test ); + diff --git a/openflow/regress/projects/black_box/regress/test_send_bandwidth_random/run.pl b/openflow/regress/projects/black_box/regress/test_send_bandwidth_random/run.pl new file mode 100755 index 00000000..0fc0b1ce --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_send_bandwidth_random/run.pl @@ -0,0 +1,141 @@ +#!/usr/bin/perl -w +# test_send_bandwidth_fixed + +use strict; +use OF::Includes; + +use Time::HiRes qw (sleep gettimeofday tv_interval usleep); + +# Sends packets of the specified length, with specified data rate, over time = duration. +# A random interarrival time between packets is used, trying to fit the requested data rate. + +sub send_random_bandwidth_unique { + my ( $rate, $duration, $sock, $pkt, $pkt_sent, $interface ) = @_; + my $length = length( $pkt->packed ); + my $num_packets = ( $rate * $duration ) / ( $length * 8 ); + my $inter_time = 1000000.0 * $duration / $num_packets; + + print "Running Test for a single packet size\n"; + print( +"Num Packets : $num_packets, Duration : $duration, Length : $length, InterTime : $inter_time Interface : $interface\n" + ); + + print "sending $num_packets packets\n"; + + my @start_time = gettimeofday(); + my $sending_time = tv_interval(\@start_time); + + my $count = 0; + while($sending_time < $duration){ + # Send 'packet_out' message + print $sock $pkt_sent; + nftest_expect( $interface, $pkt->packed ); + usleep(int(rand(2*$inter_time))); + $count++; + $sending_time = tv_interval(\@start_time); + } + print "time elapsed: $sending_time (loops : $count) \n"; + + my $bps = $count * $length * 8 / $sending_time; + print "bandwidth attempted: $rate (bps)\n"; + print "bandwidth achieved: $bps (bps)\n"; +} + +sub send_random_bandwidth_mixed { + my ( $rate, $duration, $sock, $pkt_sent_small,$pkt_sent_med,$pkt_sent_lrg,$pkt_small,$pkt_med,$pkt_lrg, $interface ) = @_; + my $len_s = length($pkt_small->packed); + my $len_m = length($pkt_med->packed); + my $len_l = length($pkt_lrg->packed); + my $num_loops = ( $rate * $duration ) / (( $len_s+$len_m+$len_l ) * 8 ); + my $num_packets = $num_loops*3; + my $inter_time = 1000000.0 * $duration / $num_packets; + + print "Running Test for different packet sizes\n"; + print( +"Num Packets : $num_packets, Duration : $duration, Lengths : $len_s,$len_m,$len_l, InterTime : $inter_time Interface : $interface\n" + ); + + print "sending $num_packets packets\n"; + + my @start_time = gettimeofday(); + my $sending_time = tv_interval(\@start_time); + + my $count = 0; + while ($sending_time < $duration){ + # Send 'packet_out' message + print $sock $pkt_sent_small; + nftest_expect( $interface, $pkt_small->packed ); + usleep(int(rand(2*$inter_time))); + print $sock $pkt_sent_med; + nftest_expect( $interface, $pkt_med->packed ); + usleep(int(rand(2*$inter_time))); + print $sock $pkt_sent_lrg; + nftest_expect( $interface, $pkt_lrg->packed ); + usleep(int(rand(2*$inter_time))); + $count++; + $sending_time = tv_interval(\@start_time); + } + + print "time elapsed: $sending_time (loops : $count)\n"; + + my $bps = $count * ($len_s+$len_m+$len_l) * 8 / $sending_time; + print "bandwidth attempted: $rate(bps)\n"; + print "bandwidth achieved: $bps (bps)\n"; +} + + + +sub my_test { + + my $pkt_args = { + DA => "00:00:00:00:00:02", + SA => "00:00:00:00:00:01", + src_ip => "192.168.200.40", + dst_ip => "192.168.201.40", + ttl => 64, + len => 64 + }; + my $pkt_small = new NF2::IP_pkt(%$pkt_args); + $pkt_args->{ 'len' } = 256; + my $pkt_med = new NF2::IP_pkt(%$pkt_args); + $pkt_args->{ 'len' } = 512; + my $pkt_lrg = new NF2::IP_pkt(%$pkt_args); + + my $hdr_args = { + version => 1, + type => $enums{'OFPT_PACKET_OUT'}, + length => $ofp->sizeof('ofp_packet_out') + length( $pkt_small->packed ), # should generate automatically! + xid => 0x0000abcd + }; + my $packet_out_args = { + header => $hdr_args, + buffer_id => -1, # data included in this packet + in_port => $enums{'OFPP_NONE'}, + out_port => 0 # send out eth1 + }; + my $packet_out = $ofp->pack( 'ofp_packet_out', $packet_out_args ); + + my $pkt_sent_small = $packet_out . $pkt_small->packed; + $hdr_args->{'length'} = $ofp->sizeof('ofp_packet_out') + length( $pkt_med->packed ); + $packet_out_args->{'header'} = $hdr_args; + $packet_out = $ofp->pack( 'ofp_packet_out', $packet_out_args ); + my $pkt_sent_med = $packet_out . $pkt_med->packed; + $hdr_args->{'length'} = $ofp->sizeof('ofp_packet_out') + length( $pkt_lrg->packed ); + $packet_out_args->{'header'} = $hdr_args; + $packet_out = $ofp->pack( 'ofp_packet_out', $packet_out_args ); + my $pkt_sent_lrg = $packet_out . $pkt_lrg->packed; + + my ($sock) = @_; + + + &send_random_bandwidth_unique( .01 * (10**6) ,15, $sock, $pkt_lrg, $pkt_sent_lrg, 'eth1' ); + + #&send_random_bandwidth_mixed( 5 * (10**5) ,5, $sock,$pkt_sent_small,$pkt_sent_med, $pkt_sent_lrg,$pkt_small,$pkt_med,$pkt_lrg,'eth1'); + + # Wait for test to finish + sleep(2); + +} + +run_black_box_test( \&my_test ); + diff --git a/openflow/regress/projects/black_box/regress/test_set_dl_nw_flip/run.pl b/openflow/regress/projects/black_box/regress/test_set_dl_nw_flip/run.pl new file mode 100755 index 00000000..fbf508b4 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_set_dl_nw_flip/run.pl @@ -0,0 +1,143 @@ +#!/usr/bin/perl -w +# test_set_nw_dst + +use strict; +use OF::Includes; + +sub send_expect_exact { + my ($ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len) = @_; + + my $in_port = $in_port_offset + $$options_ref{'port_base'}; + my $out_port = $out_port_offset + $$options_ref{'port_base'}; + + # in_port refers to the flow mod entry's input + + # Create the payload ourselves to make sure the two packets match + # Jean II + my $pkt_payload = [map {int(rand(256))} (1..($pkt_len - 8 - 4 - 16 - 14))]; + + # This is the packet we are sending... - Jean II + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + tos => 0x0, + ttl => 64, + len => $pkt_len, + src_port => 1, + dst_port => 0, + data => $pkt_payload + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + # This is the packet we are expecting to receive - Jean II + my $expect_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + src_ip => "192.168.201." . ( $out_port ), + dst_ip => "192.168.200." . ( $in_port ), + tos => 0x0, + ttl => 64, + len => $pkt_len, + src_port => 1, + dst_port => 0, + data => $pkt_payload + }; + my $expect_pkt = new NF2::UDP_pkt(%$expect_pkt_args); + + #print HexDump ($test_pkt->packed); + + my $wildcards = 0x0; # exact match + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry + + # Get the various addresses in the expected packet - Jean II + my $chg_val_dl_da = ${$expect_pkt->{Ethernet_hdr}}->DA; + my $chg_val_dl_sa = ${$expect_pkt->{Ethernet_hdr}}->SA; + my $chg_val_nw_dst = ${$expect_pkt->{IP_hdr}}->dst_ip; + my $chg_val_nw_src = ${$expect_pkt->{IP_hdr}}->src_ip; + my @dl_da_addr_chg = NF2::PDU::get_MAC_address($chg_val_dl_da); + my @dl_sa_addr_chg = NF2::PDU::get_MAC_address($chg_val_dl_sa); + my $nw_dst_addr_chg; + my $ok_org; + ($nw_dst_addr_chg, $ok_org) = NF2::IP_hdr::getIP($chg_val_nw_dst); + my $nw_src_addr_chg; + ($nw_src_addr_chg, $ok_org) = NF2::IP_hdr::getIP($chg_val_nw_src); + + # Create the desired rewrite actions + my @pad_6 = (0,0,0,0,0,0); + my $action_mod_dl_da_args = { + type => $enums{'OFPAT_SET_DL_DST'}, + len => $ofp->sizeof('ofp_action_dl_addr'), + dl_addr => \@dl_da_addr_chg, + pad => \@pad_6, + }; + my $action_mod_dl_da = $ofp->pack('ofp_action_dl_addr', $action_mod_dl_da_args); + my $action_mod_dl_sa_args = { + type => $enums{'OFPAT_SET_DL_SRC'}, + len => $ofp->sizeof('ofp_action_dl_addr'), + dl_addr => \@dl_sa_addr_chg, + pad => \@pad_6, + }; + my $action_mod_dl_sa = $ofp->pack('ofp_action_dl_addr', $action_mod_dl_sa_args); + my $action_mod_nw_dst_args = { + type => $enums{'OFPAT_SET_NW_DST'}, + len => $ofp->sizeof('ofp_action_nw_addr'), + nw_addr => $nw_dst_addr_chg, + }; + my $action_mod_nw_dst = $ofp->pack( 'ofp_action_nw_addr', $action_mod_nw_dst_args ); + my $action_mod_nw_src_args = { + type => $enums{'OFPAT_SET_NW_SRC'}, + len => $ofp->sizeof('ofp_action_nw_addr'), + nw_addr => $nw_src_addr_chg, + }; + my $action_mod_nw_src = $ofp->pack( 'ofp_action_nw_addr', $action_mod_nw_src_args ); + + # Output action to get the packet out someplace - Jean II + my $action_output_args = { + type => $enums{'OFPAT_OUTPUT'}, + len => $ofp->sizeof('ofp_action_output'), + port => $out_port, + max_len => 0, # send entire packet + }; + my $action_output = $ofp->pack( 'ofp_action_output', $action_output_args ); + + # Aggregate all actions together + my $action_bytes = $action_mod_dl_da . $action_mod_dl_sa . $action_mod_nw_dst . $action_mod_nw_src . $action_output; + + my $flow_mod_pkt = + create_flow_mod_from_udp_actionbytes( $ofp, $test_pkt, $in_port, $max_idle, $flags, $wildcards, 'OFPFC_ADD', $action_bytes); + + #print HexDump($flow_mod_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent flow_mod message\n"; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + + # Send a packet - ensure packet comes out desired port + nftest_send("eth" . ($in_port_offset + 1), $test_pkt->packed); + nftest_expect("eth" . ($out_port_offset + 1), $expect_pkt->packed); +} + +sub test_set_nw_dst { + my ($ofp, $sock, $options_ref, $i, $j, $wildcards) = @_; + + my $max_idle = $$options_ref{'max_idle'}; + my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_total = $$options_ref{'pkt_total'}; + + send_expect_exact($ofp, $sock, $options_ref, $i, $j, $max_idle, $pkt_len); + wait_for_flow_expired($ofp, $sock, $options_ref, $pkt_len, $pkt_total); +} + +sub my_test { + my ($sock, $options_ref) = @_; + + # send from every port to every other port + for_all_port_pairs($ofp, $sock, $options_ref, \&test_set_nw_dst, 0x0); +} + +run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_set_n_match_nw_tos/run.pl b/openflow/regress/projects/black_box/regress/test_set_n_match_nw_tos/run.pl new file mode 100755 index 00000000..4470c812 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_set_n_match_nw_tos/run.pl @@ -0,0 +1,95 @@ +#!/usr/bin/perl -w +# test_set_nw_tos + +use strict; +use OF::Includes; + +# Please check the following : +# http://en.wikipedia.org/wiki/Type_of_Service + +sub send_expect_exact { + my ($ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len, $vlan_id) = @_; + + my $in_port = $in_port_offset + $$options_ref{'port_base'}; + my $out_port = $out_port_offset + $$options_ref{'port_base'}; + + # in_port refers to the flow mod entry's input + + # Create the payload ourselves to make sure the two packets match + # Jean II + my $pkt_payload = [map {int(rand(256))} (1..($pkt_len - 8 - 4 - 16 - 14))]; + + # This is the packet we are sending... - Jean II + # Set an ECN bit to see if it gets clobbered + my $test_nw_tos = 0xA8; + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + tos => $test_nw_tos | 0x01, # => 0xA9 + ttl => 64, + len => $pkt_len, + src_port => 1, + dst_port => 0, + data => $pkt_payload + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + # This is the packet we are expecting to receive - Jean II + my $expect_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + tos => 0x54 | 0x01, # 0x55 + ttl => 64, + len => $pkt_len, + src_port => 1, + dst_port => 0, + data => $pkt_payload + }; + my $expect_pkt = new NF2::UDP_pkt(%$expect_pkt_args); + + #print HexDump ($test_pkt->packed); + + my $wildcards = 0x0; # exact match + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry + # Don't set ECN bits here, OVS reject it as invalid... + my $nw_tos = 0x54; + + my $flow_mod_pkt = create_flow_mod_from_udp_action($ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards, 'OFPFC_ADD', 'nw_tos', $nw_tos, $vlan_id, $test_nw_tos); + + #print HexDump($flow_mod_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent flow_mod message\n"; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + + # Send a packet - ensure packet comes out desired port + nftest_send("eth" . ($in_port_offset + 1), $test_pkt->packed); + nftest_expect("eth" . ($out_port_offset + 1), $expect_pkt->packed); +} + +sub test_set_nw_tos { + my ($ofp, $sock, $options_ref, $i, $j, $wildcards) = @_; + + my $max_idle = $$options_ref{'max_idle'}; + my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_total = $$options_ref{'pkt_total'}; + + send_expect_exact($ofp, $sock, $options_ref, $i, $j, $max_idle, $pkt_len); + wait_for_flow_expired($ofp, $sock, $options_ref, $pkt_len, $pkt_total); +} + +sub my_test { + my ($sock, $options_ref) = @_; + + # send from every port to every other port + for_all_port_pairs( $ofp, $sock, $options_ref, \&test_set_nw_tos, 0x0); +} + +run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_set_nw_dst/run.pl b/openflow/regress/projects/black_box/regress/test_set_nw_dst/run.pl new file mode 100755 index 00000000..ae101798 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_set_nw_dst/run.pl @@ -0,0 +1,95 @@ +#!/usr/bin/perl -w +# test_set_nw_dst + +use strict; +use OF::Includes; + +sub send_expect_exact { + my ($ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len) = @_; + + my $in_port = $in_port_offset + $$options_ref{'port_base'}; + my $out_port = $out_port_offset + $$options_ref{'port_base'}; + + # in_port refers to the flow mod entry's input + + # Create the payload ourselves to make sure the two packets match + # Jean II + my $pkt_payload = [map {int(rand(256))} (1..($pkt_len - 8 - 4 - 16 - 14))]; + + # This is the packet we are sending... - Jean II + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + tos => 0x0, + ttl => 64, + len => $pkt_len, + src_port => 1, + dst_port => 0, + data => $pkt_payload + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + # This is the packet we are expecting to receive - Jean II + my $expect_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + #dst_ip => "192.168.201." . ( $out_port + 1), + dst_ip => ( $out_port ) . ".201.168.192" , + tos => 0x0, + ttl => 64, + len => $pkt_len, + src_port => 1, + dst_port => 0, + data => $pkt_payload + }; + my $expect_pkt = new NF2::UDP_pkt(%$expect_pkt_args); + + #print HexDump ($test_pkt->packed); + + my $wildcards = 0x0; # exact match + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry + + # Get the IP address in the expected packet in binary form - Jean II + my $chg_val_nw_dst = ${$expect_pkt->{IP_hdr}}->dst_ip; + my $nw_dst_addr_chg; + my $ok_org; + ($nw_dst_addr_chg, $ok_org) = NF2::IP_hdr::getIP($chg_val_nw_dst); + + my $flow_mod_pkt = create_flow_mod_from_udp_action($ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards, 'OFPFC_ADD', 'nw_dst', $nw_dst_addr_chg); + + #print HexDump($flow_mod_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent flow_mod message\n"; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + + # Send a packet - ensure packet comes out desired port + nftest_send("eth" . ($in_port_offset + 1), $test_pkt->packed); + nftest_expect("eth" . ($out_port_offset + 1), $expect_pkt->packed); +} + +sub test_set_nw_dst { + my ($ofp, $sock, $options_ref, $i, $j, $wildcards) = @_; + + my $max_idle = $$options_ref{'max_idle'}; + my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_total = $$options_ref{'pkt_total'}; + + send_expect_exact($ofp, $sock, $options_ref, $i, $j, $max_idle, $pkt_len); + wait_for_flow_expired($ofp, $sock, $options_ref, $pkt_len, $pkt_total); +} + +sub my_test { + my ($sock, $options_ref) = @_; + + # send from every port to every other port + for_all_port_pairs($ofp, $sock, $options_ref, \&test_set_nw_dst, 0x0); +} + +run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_stats_desc/run.pl b/openflow/regress/projects/black_box/regress/test_stats_desc/run.pl new file mode 100755 index 00000000..9409ac9d --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_stats_desc/run.pl @@ -0,0 +1,71 @@ +#!/usr/bin/perl -w +# test_flow_stats + +use strict; +use OF::Includes; + +sub stats_desc_test { + + my ( $sock, $options_ref ) = @_; + + my $port_base = $$options_ref{'port_base'}; + + my $hdr_args = { + version => get_of_ver(), + type => $enums{'OFPT_STATS_REQUEST'}, + length => $ofp->sizeof('ofp_stats_request') , # should generate automatically! + xid => 0x00000001 + }; + + my $stats_request_args = { + header => $hdr_args, + type => $enums{'OFPST_DESC'}, + flags => 0 + }; + + my $stats_request = $ofp->pack( 'ofp_stats_request', $stats_request_args ); + + # Send 'stats_request' message + print $sock $stats_request; + + # Should add timeout here - will crash if no reply + my $recvd_mesg; + sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; + + # Inspect message + my $resp_size = length($recvd_mesg); + + my $resp_header = $ofp->unpack( 'ofp_stats_reply', $recvd_mesg ); + + #print HexDump ($recvd_mesg); + print Dumper($resp_header); + + # Verify fields + verify_header( $resp_header, 'OFPT_STATS_REPLY', $resp_size ); + + # Unmarshall embedded description + my $resp_body = $ofp->unpack('ofp_desc_stats', + substr($recvd_mesg, $ofp->offsetof('ofp_stats_reply', 'body'))); + print Dumper($resp_body); + print "keys: " . join(" ",keys %$resp_body) . "\n"; + my $key; + foreach $key (sort keys %$resp_body) + { + my $val = $resp_body->{$key}; + my $len = scalar(@{$val}); + printf("key=%s ref=%s len=%d val='%s'\n", + $key, + ref($val), + $len, + pack("c*", @{$val}) + #@{$val} + ); + } + + #die("forced death"); + die("Missing dp_desc in desc_stats") unless(defined($resp_body->{"dp_desc"})); + +} + +run_black_box_test( \&stats_desc_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_switch_config/run.pl b/openflow/regress/projects/black_box/regress/test_switch_config/run.pl new file mode 100755 index 00000000..cbb4886e --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_switch_config/run.pl @@ -0,0 +1,40 @@ +#!/usr/bin/perl -w +# test_switch_config + +use strict; +use OF::Includes; + +sub my_test { + + my ($sock, $options_ref) = @_; + + my $msg = get_config( $ofp, $sock ); + + # Verify that the miss_send_len is set to the correct default + compare( "miss send len", $$msg{'miss_send_len'}, '==', get_of_miss_send_len_default() ); + + # As of OF v0.8.1, there was no default for flags - we assume 0 + # (don't send flow expiration messages) + compare( "flags", $$msg{'flags'}, '==', 0 ); + + # Now, we change the config and check that it has been committed + + # Set flag OFPC_SEND_FLOW_EXP, which has val 1, and should cause flow exps + my $flags = 1; + + # Change miss_send_len from the default + my $miss_send_len = 0x100; + + set_config($ofp, $sock, $options_ref, $flags, $miss_send_len); + + # Give OF switch time to process the set_config + usleep($$options_ref{'send_delay'}); + + $msg = get_config( $ofp, $sock ); + + compare( "miss send len", $$msg{'miss_send_len'}, '==', $miss_send_len ); + compare( "flags", $$msg{'flags'}, '==', $flags ); +} + +run_black_box_test( \&my_test, \@ARGV ); + diff --git a/openflow/regress/projects/black_box/regress/test_tcp_options/run.pl b/openflow/regress/projects/black_box/regress/test_tcp_options/run.pl new file mode 100755 index 00000000..b9025bb0 --- /dev/null +++ b/openflow/regress/projects/black_box/regress/test_tcp_options/run.pl @@ -0,0 +1,170 @@ +#!/usr/bin/perl -w +# test_tcp_options + +use strict; +use OF::Includes; + +sub create_flow_mod_from_ip { + + my ( $ofp, $udp_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards, $s_port, $d_port ) = @_; + + my $hdr_args = { + version => get_of_ver(), + type => $enums{'OFPT_FLOW_MOD'}, + length => $ofp->sizeof('ofp_flow_mod') + $ofp->sizeof('ofp_action_output'), + xid => 0x0000000 + }; + + # might be cleaner to convert the exported colon-hex MAC addrs + #print ${$udp_pkt->{Ethernet_hdr}}->SA . "\n"; + #print ${$test_pkt->{Ethernet_hdr}}->SA . "\n"; + my $ref_to_eth_hdr = ( $udp_pkt->{'Ethernet_hdr'} ); + my $ref_to_ip_hdr = ( $udp_pkt->{'IP_hdr'} ); + + # pointer to array + my $eth_hdr_bytes = $$ref_to_eth_hdr->{'bytes'}; + my $ip_hdr_bytes = $$ref_to_ip_hdr->{'bytes'}; + my @dst_mac_subarray = @{$eth_hdr_bytes}[ 0 .. 5 ]; + my @src_mac_subarray = @{$eth_hdr_bytes}[ 6 .. 11 ]; + + my @src_ip_subarray = @{$ip_hdr_bytes}[ 12 .. 15 ]; + my @dst_ip_subarray = @{$ip_hdr_bytes}[ 16 .. 19 ]; + + my $src_ip = + ( ( 2**24 ) * $src_ip_subarray[0] + + ( 2**16 ) * $src_ip_subarray[1] + + ( 2**8 ) * $src_ip_subarray[2] + + $src_ip_subarray[3] ); + + my $dst_ip = + ( ( 2**24 ) * $dst_ip_subarray[0] + + ( 2**16 ) * $dst_ip_subarray[1] + + ( 2**8 ) * $dst_ip_subarray[2] + + $dst_ip_subarray[3] ); + + # read IP_header protocol field + my $iph = $udp_pkt->{'IP_hdr'}; + my $proto = $$iph->proto(); + + my $match_args = { + wildcards => $wildcards, + in_port => $in_port, + dl_src => \@src_mac_subarray, + dl_dst => \@dst_mac_subarray, + dl_vlan => 0xffff, + dl_vlan_pcp => 0x00, + dl_type => 0x0800, + nw_src => $src_ip, + nw_dst => $dst_ip, + nw_proto => $proto, #any protocol + tp_src => $s_port, + tp_dst => $d_port + }; + + print "My Out Port: ${out_port}\n"; + my $action_output_args = { + type => $enums{'OFPAT_OUTPUT'}, + len => $ofp->sizeof('ofp_action_output'), + port => $out_port, + max_len => 0 # send entire packet + }; + my $action_output = $ofp->pack('ofp_action_output', $action_output_args); + + my $flow_mod_args = { + header => $hdr_args, + match => $match_args, + command => $enums{'OFPFC_ADD'}, + idle_timeout => $max_idle, + hard_timeout => $max_idle, + flags => $flags, + priority => 0, + buffer_id => -1 + }; + my $flow_mod = $ofp->pack( 'ofp_flow_mod', $flow_mod_args ); + + my $flow_mod_pkt = $flow_mod . $action_output; + + return $flow_mod_pkt; +} + +sub send_tcp_op_expect_exact { + + my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len ) = @_; + + my $in_port = $in_port_offset + $$options_ref{'port_base'}; + my $out_port = $out_port_offset + $$options_ref{'port_base'}; + + my $src_tcp_port = 70; + my $dst_tcp_port = 80; + + # in_port refers to the flow mod entry's input + my @tcp_payload = ( # 30 bytes + 0x00, 0x46, 0x00, 0x50, # $src_tcp_port, $dst_tcp_port (should set automatically) + 0x01, 0x23, 0x45, 0x67, #Seq + 0x01, 0x23, 0x45, 0x00, #Ack + 0x58, 0x23, 0x00, 0x11, #Offset, Flag, Win + 0xaa, 0xbb, 0x00, 0x00, #Chksum, Urgent + 0x03, 0x03, 0x02, 0x00, #TCP Option + 0xaa, 0xbb, 0xcc, 0xdd, #TCP Content + 0xee, 0xff #TCP Content + ); + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + proto => 6, # TCP protocol id + }; + + my $test_pkt = new NF2::IP_pkt(%$test_pkt_args); + my $payload = $test_pkt->{'payload'}; + $$payload->set_bytes(@tcp_payload); + + #print HexDump ( $test_pkt->packed ); + + #my $wildcards = 0; # exact match + my $wildcards = $enums{'OFPFW_TP_SRC'} | + $enums{'OFPFW_TP_DST'};# | + # $enums{'OFPFW_NW_PROTO'}; # wildcard match (don't care udp src/dst ports) + + my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; + my $flow_mod_pkt = + create_flow_mod_from_ip( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards, + $src_tcp_port, $dst_tcp_port ); + + #print HexDump($flow_mod_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_pkt; + print "sent flow_mod message\n"; + usleep($$options_ref{'send_delay'}); + + # Send a packet - ensure packet comes out desired port + nftest_send( "eth" . ( $in_port_offset + 1), $test_pkt->packed ); + nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); +} + +sub test_tcp_options { + my ( $ofp, $sock, $options_ref, $i, $j, $wildcards ) = @_; + + my $max_idle = $$options_ref{'max_idle'}; + #my $pkt_len = $$options_ref{'pkt_len'}; + my $pkt_len = 64; # len = 14(Ethr_hdr)+ 20(IP_header)+ 30(TCP_header+Option) + # = 64 (IPlen = 50) + my $pkt_total = $$options_ref{'pkt_total'}; + + send_tcp_op_expect_exact( $ofp, $sock, $options_ref, $i, $j, $max_idle, $pkt_len ); + #sleep(5); + wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); +} + +sub my_test { + my ( $sock, $options_ref ) = @_; + + # send from every port to every other port + for_all_port_pairs( $ofp, $sock, $options_ref, \&test_tcp_options, 0x0); +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/tests.txt b/openflow/regress/projects/black_box/regress/tests.txt new file mode 100644 index 00000000..f77158ec --- /dev/null +++ b/openflow/regress/projects/black_box/regress/tests.txt @@ -0,0 +1,103 @@ +## two #'s = not tested; 1 # = worked once + +# Basic Tests +test_hello/run.pl +test_barrier/run.pl +test_packet_in/run.pl +test_packet_out/run.pl +test_switch_config/run.pl +test_flow_expired/run.pl +test_flow_expired_idle_timeout/run.pl +test_flow_expired_precision/run.pl +test_flow_expired_send_flow_exp/run.pl +test_miss_send_length/run.pl + +# Read State Tests +test_stats_desc/run.pl +test_port_stats/run.pl +test_flow_stats/run.pl +test_flow_stats_precision/run.pl + +## Forwarding Tests +test_forward_any_port/run.pl +test_forward_exact_port/run.pl +test_forward_broadcast_exact_port/run.pl +test_forward_exact_all/run.pl +test_forward_exact_controller/run.pl +test_forward_wildcard_port/run.pl +test_forward_wildcard_all/run.pl +test_forward_wildcard_controller/run.pl +test_forward_after_expiration/run.pl +test_forward_overlapping_flow_entries/run.pl +test_delete/run.pl +test_delete_strict/run.pl +test_delete_send_flow_exp/run.pl +test_drop_exact/run.pl + +## Modify Action Tests +test_forward_exact_modify_action/run.pl +test_forward_wildcard_modify_action/run.pl +test_flow_mod_check/run.pl +test_set_nw_dst/run.pl +test_set_n_match_nw_tos/run.pl +test_set_dl_nw_flip/run.pl + +## ICMP handling Tests +test_forward_exact_icmp_port/run.pl +test_forward_exact_icmp_all/run.pl +test_forward_exact_icmp_controller/run.pl +test_forward_exact_icmp_fool/run.pl +test_forward_wildcard_icmp_port/run.pl +test_forward_wildcard_icmp_all/run.pl +test_forward_wildcard_icmp_controller/run.pl +test_forward_wildcard_icmp_fool/run.pl + +## ARP handling Tests +test_forward_exact_arp_port/run.pl +test_forward_exact_arp_all/run.pl +test_forward_exact_arp_controller/run.pl +test_forward_exact_arp_fool/run.pl +test_forward_wildcard_arp_port/run.pl +test_forward_wildcard_arp_all/run.pl +test_forward_wildcard_arp_controller/run.pl +test_forward_wildcard_arp_fool/run.pl + +# Flow cookies +test_cookie_flow_expired/run.pl +test_cookie_flow_stats/run.pl + +## Slicing Tests - can be disable via --no_slicing +test_queue_config/run.pl +## These assume that there is a queue with queue_id=1 at port 1. +## Uncomment if your setup supports this. +## Should work OK with the reference implementation +#test_queue_stats/run.pl +test_queue_forward/run.pl + +## Unusual Data +test_ip_options/run.pl +##test_ip_protocol/run.pl +test_ip_offset/run.pl +test_tcp_options/run.pl +##test_llc/run.pl + +# Failover Tests +test_failover_startup/run.pl +test_failover_close/run.pl + +# BELOW NOT INCLUDED IN CURRRENT RELEASE +# WILL BE AVAILABLE SOON +# Stress Tests / Performance Evaluation +#test_send_bandwidth_fixed/run.pl +#test_send_bandwidth_random/run.pl +#test_add_flow_bandwidth/run.pl +#test_add_flow_latency/run.pl +#test_receive_bandwidth_fixed/run.pl +#test_receive_bandwidth_random/run.pl +#test_forward_bandwidth_fixed/run.pl +#test_forward_bandwidth_random/run.pl +#test_forward_latency/run.pl +#test_switch_bandwidth_random/run.pl +#test_switch_bandwidth_random/run.pl +# Additional Failover tests +#test_failover_stop_responding/run.pl diff --git a/openflow/regress/projects/controller_disconnect/regress/common/setup b/openflow/regress/projects/controller_disconnect/regress/common/setup new file mode 100755 index 00000000..f796718c --- /dev/null +++ b/openflow/regress/projects/controller_disconnect/regress/common/setup @@ -0,0 +1,49 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use Test::TestLib; +use OF::OFUtil; + +my $mapFile; +my $platform; +my $args; + +# Process command line options +unless ( + GetOptions ( + "map=s" => \$mapFile, + "common-st-args=s" => \$platform, + ) +) +{ + print "invalid command format\n"; + exit(1); +} + +if (defined($mapFile)) { + $args = "--map=$mapFile"; +} + +if (!defined($platform)) { + print "no platform defined\n"; + exit(1); +} +else { + print "platform = $platform\n"; +} + +$args .= " --emerg"; + +my $filename = "of_${platform}_setup.pl"; + +# exit if of_${platform}_setup.pl not in path +if (-e "$ENV{'OFT_ROOT'}/bin/$filename") { + #system("$filename " . $args . " 2> /dev/null > /dev/null"); + system("$ENV{'OFT_ROOT'}/bin/$filename " . $args ); + #setup_kmod(); + exit (0); +} else { + print "couldn't find setup file $filename\n"; + exit (1); +} diff --git a/openflow/regress/projects/controller_disconnect/regress/common/teardown b/openflow/regress/projects/controller_disconnect/regress/common/teardown new file mode 100755 index 00000000..6f1f8391 --- /dev/null +++ b/openflow/regress/projects/controller_disconnect/regress/common/teardown @@ -0,0 +1,47 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use Test::TestLib; +use OF::OFUtil; + +my $mapFile; +my $platform; +my $args; + +# Process command line options +unless ( + GetOptions ( + "map=s" => \$mapFile, + "common-st-args=s" => \$platform, + ) +) +{ + print "invalid command format\n"; + exit(1); +} + +if (defined($mapFile)) { + $args = "--map=$mapFile"; +} + +if (!defined($platform)) { + print "no platform defined\n"; + exit(1); +} +else { + print "platform = $platform\n"; +} + +my $filename = "of_${platform}_teardown.pl"; + +# exit if of_${platform}_setup.pl not in path +if (-e "$ENV{'OFT_ROOT'}/bin/$filename") { + #system("$filename " . $args . " 2> /dev/null > /dev/null"); + system("$ENV{'OFT_ROOT'}/bin/$filename " . $args ); + #teardown_kmod(); + exit (0); +} else { + print "couldn't find setup file $filename\n"; + exit (1); +} diff --git a/openflow/regress/projects/controller_disconnect/regress/test_emergency_table/run.pl b/openflow/regress/projects/controller_disconnect/regress/test_emergency_table/run.pl new file mode 100755 index 00000000..7e07a6c8 --- /dev/null +++ b/openflow/regress/projects/controller_disconnect/regress/test_emergency_table/run.pl @@ -0,0 +1,107 @@ +#!/usr/bin/perl -w +# test_emergency_table + +use strict; +use OF::Includes; +use OF::OFUtil; + +sub test_emergency_cache_first { + my ( $ofp, $sock, $options_ref, $i, $j, $wildcards ) = @_; + + my $max_idle = $$options_ref{'max_idle'}; + my $pkt_len = $$options_ref{'pkt_len'}; + my $in_port = $i + $$options_ref{'port_base'}; + my $out_port = $j + $$options_ref{'port_base'}; + my $test_pkt_args = { + DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), + SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), + src_ip => "192.168.200." . ( $in_port ), + dst_ip => "192.168.201." . ( $out_port ), + ttl => 64, + len => $pkt_len, + src_port => 70, + dst_port => 80 + }; + my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); + + print "Set both normal and emergency flow table. Normal key must win\n"; + + # 1st flow entry -- exact match, normal flow table + my $max_idle_no_expire = 0; + my $normal_wildcards = 0x0; # exact match + my $normal_flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry + my $flow_mod_normal_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle_no_expire, $normal_flags, $normal_wildcards ); + + # 2nd flow entry -- wildcard match all, emergency flow table + my $emergency_wildcards = $enums{'OFPFW_ALL'}; # wildcard match all to the all ports + my $emergency_flags = $enums{'OFPFF_EMERG'}; + my $flow_mod_emergency_pkt = + create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $enums{'OFPP_ALL'}, $max_idle_no_expire, $emergency_flags, $emergency_wildcards ); + + #print HexDump($flow_mod_normal_pkt); + #print HexDump($flow_mod_emergency_pkt); + + # Send 'flow_mod' message + print $sock $flow_mod_normal_pkt; + print "sent flow_mod message (normal table)\n"; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + + # Send 2nd 'flow_mod' message + print $sock $flow_mod_emergency_pkt; + print "sent flow_mod message (emergency table)\n"; + + # Give OF switch time to process the flow mod + usleep($$options_ref{'send_delay'}); + + # Send a packet - ensure packet comes out desired port + print "Verify packets are forwarded correctly\n"; + nftest_send( "eth" . ( $i + 1 ), $test_pkt->packed ); + nftest_expect( "eth" . ( $j + 1 ), $test_pkt->packed ); + + # Wait for ECHO_REQUEST but don't reply so that ofprotocol notices disconnection. + wait_for_echo_request ( $ofp, $sock, $options_ref, $ofp->sizeof('ofp_header')); + return $test_pkt; +} + +sub test_emergency_cache_second { + my ( $test_pkt, $options_ref, $i, $j ) = @_; + + print "sending from $i to $j, but expect the packet from all ports\n"; + nftest_send( "eth" . ( $i + 1 ), $test_pkt->packed ); + + # expect packets on all other interfaces + print "expect multiple packets\n"; + + for ( my $k = 0 ; $k < $$options_ref{'num_ports'} ; $k++ ) { + if ( $k != $i ) { + nftest_expect( "eth" . ( $k + 1), $test_pkt->packed ); + } + } +} + +sub my_test { + my ($sock, $options_ref) = @_; + + if ( not defined( $$options_ref{'no_emerg'} ) ) { + #This test uses two ports + my $inport = 0; + my $outport = 1; + my $wildcards = 0; #exact match + + # Wait until switch notices disconnection. it depends on implementation + my $wait_timer = 20; + + my $test_pkt = test_emergency_cache_first($ofp, $sock, $options_ref, $inport, $outport, $wildcards); + + # Wait until ofprotocol notices that connection is broken + sleep $wait_timer; + + # chek if the emergency table has become active + test_emergency_cache_second($test_pkt, $options_ref, $inport, $outport); + } +} + +run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/controller_disconnect/regress/tests.txt b/openflow/regress/projects/controller_disconnect/regress/tests.txt new file mode 100644 index 00000000..0d34d9b3 --- /dev/null +++ b/openflow/regress/projects/controller_disconnect/regress/tests.txt @@ -0,0 +1,2 @@ +test_emergency_table/run.pl +#test_reconnect/run.pl diff --git a/openflow/regress/projects/learning_switch/regress/common/setup b/openflow/regress/projects/learning_switch/regress/common/setup new file mode 100755 index 00000000..29653173 --- /dev/null +++ b/openflow/regress/projects/learning_switch/regress/common/setup @@ -0,0 +1,46 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use Test::TestLib; +use OF::OFUtil; + +my $mapFile; +my $platform; +my $args; + +# Process command line options +unless ( + GetOptions ( + "map=s" => \$mapFile, + "common-st-args=s" => \$platform, + ) +) +{ + print "invalid command format\n"; + exit(1); +} + +if (defined($mapFile)) { + $args = "--map=$mapFile"; +} + +if (!defined($platform)) { + print "no platform defined\n"; + exit(1); +} +else { + print "platform = $platform\n"; +} + +my $filename = "of_${platform}_setup.pl"; + +# exit if of_${platform}_setup.pl not in path +if (-e "$ENV{'OFT_ROOT'}/bin/$filename") { + system("$ENV{'OFT_ROOT'}/bin/$filename " . $args . " 2> /dev/null > /dev/null"); + #setup_kmod(); + exit (0); +} else { + print "couldn't find setup file $filename\n"; + exit (1); +} diff --git a/openflow/regress/projects/learning_switch/regress/common/teardown b/openflow/regress/projects/learning_switch/regress/common/teardown new file mode 100755 index 00000000..c1813189 --- /dev/null +++ b/openflow/regress/projects/learning_switch/regress/common/teardown @@ -0,0 +1,46 @@ +#!/usr/bin/perl -w + +use Getopt::Long; + +use Test::TestLib; +use OF::OFUtil; + +my $mapFile; +my $platform; +my $args; + +# Process command line options +unless ( + GetOptions ( + "map=s" => \$mapFile, + "common-st-args=s" => \$platform, + ) +) +{ + print "invalid command format\n"; + exit(1); +} + +if (defined($mapFile)) { + $args = "map=$mapFile"; +} + +if (!defined($platform)) { + print "no platform defined\n"; + exit(1); +} +else { + print "platform = $platform\n"; +} + +my $filename = "of_${platform}_teardown.pl"; + +# exit if of_${platform}_setup.pl not in path +if (-e "$ENV{'OFT_ROOT'}/bin/$filename") { + system("$ENV{'OFT_ROOT'}/bin/$filename " . $args . " 2> /dev/null > /dev/null"); + #teardown_kmod(); + exit (0); +} else { + print "couldn't find setup file $filename\n"; + exit (1); +} diff --git a/openflow/regress/projects/learning_switch/regress/test_broadcast/run.pl b/openflow/regress/projects/learning_switch/regress/test_broadcast/run.pl new file mode 100755 index 00000000..f721f4db --- /dev/null +++ b/openflow/regress/projects/learning_switch/regress/test_broadcast/run.pl @@ -0,0 +1,50 @@ +#!/usr/bin/perl -w +# test_broadcast + +use strict; +use OF::Includes; + +sub gen_broadcast_pkt { + my ($portNum) = shift; + + my $pkt_args = { + DA => "FF:FF:FF:FF:FF:FF", + SA => "00:00:00:00:00:0" . $portNum, + src_ip => "192.168." . $portNum . ".40", + dst_ip => "255.255.255.255", + ttl => 64, + len => 64 + }; + my $pkt = new NF2::IP_pkt(%$pkt_args); + return $pkt; +} + +sub send_expect_broadcast { + my ( $portNum, $pkt, $delta_ref ) = @_; + + send_and_count( 'eth' . $portNum, $pkt->packed, $delta_ref ); + for ( my $i = 1 ; $i <= 4 ; $i++ ) { + if ( $i != $portNum ) { + expect_and_count( 'eth' . $i, $pkt->packed, $delta_ref ); + } + } +} + +sub my_test { + + my %delta; + + for ( my $i = 1 ; $i < 4 ; $i++ ) { + my $pkt = gen_broadcast_pkt($i); + + # send one broadcast packet, then do it again on the same port + send_expect_broadcast( $i, $pkt, \%delta ); + sleep 0.1; + send_expect_broadcast( $i, $pkt, \%delta ); + sleep 0.1; + } + + return %delta; +} + +run_learning_switch_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/learning_switch/regress/test_forward_bandwidth/run.pl b/openflow/regress/projects/learning_switch/regress/test_forward_bandwidth/run.pl new file mode 100755 index 00000000..473afa81 --- /dev/null +++ b/openflow/regress/projects/learning_switch/regress/test_forward_bandwidth/run.pl @@ -0,0 +1,62 @@ +#!/usr/bin/perl -w +#test_unicast_unknown + +use Test::TestLib; +use Test::PacketLib; +use OF::OFUtil; +use Time::HiRes qw(sleep gettimeofday tv_interval usleep); +use strict; + +sub my_test { + my $cnt = 0; + my %delta; + my $pkt_len = 1512; + + my $pkt_args = { + DA => "00:01:00:00:00:02", + SA => "00:00:00:00:00:01", + src_ip => "192.168.0.40", + dst_ip => "192.168.0.41", + ttl => 64, + len => 64 + }; + my $pkt = new NF2::IP_pkt(%$pkt_args); + + # send one packet; controller should learn MAC, add a flow + # entry, and send this packet out the other interfaces + + send_and_count( nftest_get_iface('eth1'), $pkt->packed, \%delta ); + expect_and_count( nftest_get_iface('eth2'), $pkt->packed, \%delta ); + expect_and_count( nftest_get_iface('eth3'), $pkt->packed, \%delta ); + expect_and_count( nftest_get_iface('eth4'), $pkt->packed, \%delta ); + + my @start_time = gettimeofday(); + for ( $cnt = 10 ; $cnt < 20 ; $cnt++ ) { + for ( my $t = 10 ; $t < 100 ; $t++ ) { + my $pkt_args = { + DA => "00:00:00:00:00:01", + SA => "00:00:00:00:$t:$cnt", + src_ip => "192.168.$t.$cnt", + dst_ip => "192.168.1.40", + ttl => 64, + len => $pkt_len + }; + my $pkt = new NF2::IP_pkt(%$pkt_args); + + send_and_count( nftest_get_iface('eth2'), $pkt->packed, \%delta ); + expect_and_count( nftest_get_iface('eth1'), $pkt->packed, \%delta ); + } + } + ( my $second, my $micro ) = tv_interval( \@start_time ); + my $time_elapsed = ( $second + $micro * 1e-6 ); + + my $bw_result = (900 * $pkt_len * 8) / $time_elapsed; + print "PACKET LENGTH: $pkt_len \n"; + print "TIME ELAPSED: $time_elapsed \n"; + print "RESULTING BW: $bw_result bits/sec \n"; + + return %delta; +} + +# how do we pass the cmd-line arguments to the script? +run_learning_switch_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/learning_switch/regress/test_forward_latency/run.pl b/openflow/regress/projects/learning_switch/regress/test_forward_latency/run.pl new file mode 100755 index 00000000..e9690d80 --- /dev/null +++ b/openflow/regress/projects/learning_switch/regress/test_forward_latency/run.pl @@ -0,0 +1,69 @@ +#!/usr/bin/perl -w +#test_fwd_delay +# send 1000 packets to find latency for both new flows and existing ones + +use Test::TestLib; +use Test::PacketLib; +use OF::OFUtil; +use strict; +use Time::HiRes qw(sleep gettimeofday tv_interval usleep); + +sub my_test { + my $cnt = 0; + + my $start_time_ref = [gettimeofday]; + my %delta; + for ( my $t = 10 ; $t < 20 ; $t++ ) { + for ( $cnt = 10 ; $cnt < 100 ; $cnt++ ) { + my $pkt_args = { + DA => "00:01:00:00:$t:$cnt", + SA => "00:00:00:00:00:01", + src_ip => "192.168.0.40", + dst_ip => "192.168.$cnt.$t", + ttl => 64, + len => 64 + }; + my $pkt = new NF2::IP_pkt(%$pkt_args); + + # send one packet; controller should learn MAC, add a flow + # entry, and send this packet out the other interfaces + send_and_count( nftest_get_iface('eth1'), $pkt->packed, \%delta ); + expect_and_count( nftest_get_iface('eth2'), $pkt->packed, \%delta ); + expect_and_count( nftest_get_iface('eth3'), $pkt->packed, \%delta ); + expect_and_count( nftest_get_iface('eth4'), $pkt->packed, \%delta ); + } + } + my $total_time_unknown = tv_interval( $start_time_ref ); + + $start_time_ref = [gettimeofday()]; + for ( $cnt = 10 ; $cnt < 20 ; $cnt++ ) { + for ( my $t = 10 ; $t < 100 ; $t++ ) { + my $pkt_args = { + DA => "00:00:00:00:00:01", + SA => "00:00:00:00:$t:$cnt", + src_ip => "192.168.$t.$cnt", + dst_ip => "192.168.1.40", + ttl => 64, + len => 64 + }; + my $pkt = new NF2::IP_pkt(%$pkt_args); + + # send packet; flow entries are already added for these + send_and_count( nftest_get_iface('eth2'), $pkt->packed, \%delta ); + expect_and_count( nftest_get_iface('eth1'), $pkt->packed, \%delta ); + } + } + my $total_time_known = tv_interval( $start_time_ref ); + + # convert to ms, and consider that we sent 900 packets each + my $time_unknown_ms = $total_time_unknown * 1000 / 900; + my $time_known_ms = $total_time_known * 1000 / 900; + + printf("Delay with unknown MAC: %.3f ms\n", $time_unknown_ms); + printf("Delay with known MAC: %.3f ms\n", $time_known_ms); + + return %delta; +} + +# how do we pass the cmd-line arguments to the script? +run_learning_switch_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/learning_switch/regress/test_hub_connected/run.pl b/openflow/regress/projects/learning_switch/regress/test_hub_connected/run.pl new file mode 100755 index 00000000..f5881672 --- /dev/null +++ b/openflow/regress/projects/learning_switch/regress/test_hub_connected/run.pl @@ -0,0 +1,64 @@ +#!/usr/bin/perl -w +# test_same_port? + +use strict; +use OF::Includes; + +sub my_test { + + my %delta; + + # Host A and B are both on p0. they send unicast with unknown dest. + + my $pkt_args = { + DA => "00:00:00:00:00:09", + SA => "00:00:00:00:00:01", + src_ip => "192.168.0.40", + dst_ip => "192.168.7.40", + ttl => 64, + len => 64 + }; + my $pkt = new NF2::IP_pkt(%$pkt_args); + + # send one packet; controller should learn MAC, add a flow + # entry, and send this packet out the other interfaces + print "Sending now: \n"; + send_and_count( 'eth1', $pkt->packed, \%delta ); + expect_and_count( 'eth2', $pkt->packed, \%delta ); + expect_and_count( 'eth3', $pkt->packed, \%delta ); + expect_and_count( 'eth4', $pkt->packed, \%delta ); + + # sleep as long as needed for the test to finish + sleep 0.1; + + my $pkt_args = { + DA => "00:00:00:00:00:08", + SA => "00:00:00:00:00:02", + src_ip => "192.168.1.40", + dst_ip => "192.168.6.40", + ttl => 64, + len => 64 + }; + my $pkt = new NF2::IP_pkt(%$pkt_args); + send_and_count( 'eth1', $pkt->packed, \%delta ); + expect_and_count( 'eth2', $pkt->packed, \%delta ); + expect_and_count( 'eth3', $pkt->packed, \%delta ); + expect_and_count( 'eth4', $pkt->packed, \%delta ); + sleep 0.1; + + # Now A and B try to talk to each other. see if switch drop the packet or not + + my $pkt_args = { + DA => "00:00:00:00:00:02", + SA => "00:00:00:00:00:01", + src_ip => "192.168.0.40", + dst_ip => "192.168.1.40", + ttl => 64, + len => 64 + }; + my $pkt = new NF2::IP_pkt(%$pkt_args); + send_and_count( 'eth1', $pkt->packed, \%delta ); + return %delta; +} + +run_learning_switch_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/learning_switch/regress/test_unicast_known/run.pl b/openflow/regress/projects/learning_switch/regress/test_unicast_known/run.pl new file mode 100755 index 00000000..34c2c09d --- /dev/null +++ b/openflow/regress/projects/learning_switch/regress/test_unicast_known/run.pl @@ -0,0 +1,71 @@ +#!/usr/bin/perl -w +# test_unicast_known + +use strict; +use OF::Includes; + +sub my_test { + + my $pkt_args = { + DA => "00:00:00:00:00:02", + SA => "00:00:00:00:00:01", + src_ip => "192.168.0.40", + dst_ip => "192.168.1.40", + ttl => 64, + len => 64 + }; + my $pkt = new NF2::IP_pkt(%$pkt_args); + + my %delta; + + # send one packet; controller should learn MAC, add a flow + # entry, and send this packet out the other interfaces + print "Sending now: \n"; + send_and_count( 'eth1', $pkt->packed, \%delta ); + expect_and_count( 'eth2', $pkt->packed, \%delta ); + expect_and_count( 'eth3', $pkt->packed, \%delta ); + expect_and_count( 'eth4', $pkt->packed, \%delta ); + sleep(.1); + + $pkt_args = { + DA => "00:00:00:00:00:01", + SA => "00:00:00:00:00:02", + src_ip => "192.168.1.40", + dst_ip => "192.168.0.40", + ttl => 64, + len => 64 + }; + $pkt = new NF2::IP_pkt(%$pkt_args); + send_and_count( 'eth2', $pkt->packed, \%delta ); + expect_and_count( 'eth1', $pkt->packed, \%delta ); + sleep(.1); + + $pkt_args = { + DA => "00:00:00:00:00:01", + SA => "00:00:00:00:00:03", + src_ip => "192.168.2.40", + dst_ip => "192.168.0.40", + ttl => 64, + len => 64 + }; + $pkt = new NF2::IP_pkt(%$pkt_args); + send_and_count( 'eth3', $pkt->packed, \%delta ); + expect_and_count( 'eth1', $pkt->packed, \%delta ); + sleep(.1); + + $pkt_args = { + DA => "00:00:00:00:00:01", + SA => "00:00:00:00:00:04", + src_ip => "192.168.3.40", + dst_ip => "192.168.0.40", + ttl => 64, + len => 64 + }; + $pkt = new NF2::IP_pkt(%$pkt_args); + send_and_count( 'eth4', $pkt->packed, \%delta ); + expect_and_count( 'eth1', $pkt->packed, \%delta ); + + return %delta; +} + +run_learning_switch_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/learning_switch/regress/test_unicast_move/run.pl b/openflow/regress/projects/learning_switch/regress/test_unicast_move/run.pl new file mode 100755 index 00000000..5bc4670d --- /dev/null +++ b/openflow/regress/projects/learning_switch/regress/test_unicast_move/run.pl @@ -0,0 +1,79 @@ +#!/usr/bin/perl -w +# test_unicast_move + +use strict; +use OF::Includes; + +sub my_test { + + my %delta; + + # host A's MAC address is 00:00:00:00:00:01 + + my $pkt_args = { + DA => "00:00:00:00:00:02", + SA => "00:00:00:00:00:01", + src_ip => "192.168.0.40", + dst_ip => "192.168.1.40", + ttl => 64, + len => 64 + }; + my $pkt = new NF2::IP_pkt(%$pkt_args); + + # send one packet; controller should learn MAC, add a flow + # entry, and send this packet out the other interfaces + print "Sending now: \n"; + send_and_count( 'eth1', $pkt->packed, \%delta ); + expect_and_count( 'eth2', $pkt->packed, \%delta ); + expect_and_count( 'eth3', $pkt->packed, \%delta ); + expect_and_count( 'eth4', $pkt->packed, \%delta ); + + # sleep as long as needed for the test to finish + sleep 0.1; + + $pkt_args = { + DA => "00:00:00:00:00:01", + SA => "00:00:00:00:00:02", + src_ip => "192.168.1.40", + dst_ip => "192.168.0.40", + ttl => 64, + len => 64 + }; + $pkt = new NF2::IP_pkt(%$pkt_args); + send_and_count( 'eth2', $pkt->packed, \%delta ); + expect_and_count( 'eth1', $pkt->packed, \%delta ); + sleep 0.1; + + #Now Host A Has Changed Location and Attached to p2 + #It will send a packet to p1 form its new location + $pkt_args = { + DA => "00:00:00:00:00:02", + SA => "00:00:00:00:00:01", + src_ip => "192.168.2.40", + dst_ip => "192.168.1.40", + ttl => 64, + len => 64 + }; + $pkt = new NF2::IP_pkt(%$pkt_args); + send_and_count( 'eth3', $pkt->packed, \%delta ); + expect_and_count( 'eth2', $pkt->packed, \%delta ); + sleep 0.1; + + # Now p1 sends something to Host A which is now attached to p2 + # we expect the switch to already updated its entry for Host A + $pkt_args = { + DA => "00:00:00:00:00:01", + SA => "00:00:00:00:00:02", + src_ip => "192.168.1.40", + dst_ip => "192.168.2.40", + ttl => 64, + len => 64 + }; + $pkt = new NF2::IP_pkt(%$pkt_args); + send_and_count( 'eth2', $pkt->packed, \%delta ); + expect_and_count( 'eth3', $pkt->packed, \%delta ); + + return %delta; +} + +run_learning_switch_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/learning_switch/regress/test_unicast_multiple_hosts/run.pl b/openflow/regress/projects/learning_switch/regress/test_unicast_multiple_hosts/run.pl new file mode 100755 index 00000000..73c0807b --- /dev/null +++ b/openflow/regress/projects/learning_switch/regress/test_unicast_multiple_hosts/run.pl @@ -0,0 +1,93 @@ +#!/usr/bin/perl -w +# test_unicast_multiple_hosts + +use strict; +use OF::Includes; + +sub my_test { + + my %delta; + + my $pkt_args = { + DA => "00:00:00:00:00:02", + SA => "00:00:00:00:00:01", + src_ip => "192.168.0.40", + dst_ip => "192.168.1.40", + ttl => 64, + len => 64 + }; + my $pkt = new NF2::IP_pkt(%$pkt_args); + + # send one packet; controller should learn MAC, add a flow + # entry, and send this packet out the other interfaces + print "Sending now: \n"; + send_and_count( 'eth1', $pkt->packed, \%delta ); + expect_and_count( 'eth2', $pkt->packed, \%delta ); + expect_and_count( 'eth3', $pkt->packed, \%delta ); + expect_and_count( 'eth4', $pkt->packed, \%delta ); + + # sleep as long as needed for the test to finish + sleep 0.5; + my $count = 10; + my $cnt = 10; + + for ( $cnt = 11 ; $cnt < 21 ; $cnt++ ) { + for ( $count = 10 ; $count < 12 ; $count++ ) { + + $pkt_args = { + DA => "00:00:00:00:00:01", + SA => "00:00:00:$cnt:10:$count", + src_ip => "192.168.$count.$cnt", + dst_ip => "192.168.0.40", + ttl => 64, + len => 64 + }; + $pkt = new NF2::IP_pkt(%$pkt_args); + send_and_count( 'eth2', $pkt->packed, \%delta ); + expect_and_count( 'eth1', $pkt->packed, \%delta ); + sleep 0.1; + + } + } + + for ( $cnt = 21 ; $cnt < 31 ; $cnt++ ) { + for ( $count = 10 ; $count < 12 ; $count++ ) { + + $pkt_args = { + DA => "00:00:00:00:00:01", + SA => "00:00:00:$cnt:11:$count", + src_ip => "192.168.$count.$cnt", + dst_ip => "192.168.0.40", + ttl => 64, + len => 64 + }; + $pkt = new NF2::IP_pkt(%$pkt_args); + send_and_count( 'eth3', $pkt->packed, \%delta ); + expect_and_count( 'eth1', $pkt->packed, \%delta ); + sleep 0.1; + } + } + + for ( $cnt = 31 ; $cnt < 41 ; $cnt++ ) { + for ( $count = 10 ; $count < 12 ; $count++ ) { + + $pkt_args = { + DA => "00:00:00:00:00:01", + SA => "00:00:00:$cnt:12:$count", + src_ip => "192.168.$count.$cnt", + dst_ip => "192.168.0.40", + ttl => 64, + len => 64 + }; + $pkt = new NF2::IP_pkt(%$pkt_args); + send_and_count( 'eth4', $pkt->packed, \%delta ); + expect_and_count( 'eth1', $pkt->packed, \%delta ); + sleep 0.1; + + } + } + + return %delta; +} + +run_learning_switch_test( \&my_test, \@ARGV ); \ No newline at end of file diff --git a/openflow/regress/projects/learning_switch/regress/test_unicast_self/run.pl b/openflow/regress/projects/learning_switch/regress/test_unicast_self/run.pl new file mode 100755 index 00000000..4db2371b --- /dev/null +++ b/openflow/regress/projects/learning_switch/regress/test_unicast_self/run.pl @@ -0,0 +1,61 @@ +#!/usr/bin/perl -w +# test_unicast_self + +use strict; +use OF::Includes; + +sub my_test { + + my %delta; + + # Send packets with same DA and SA; should be ignored + my $pkt_args = { + DA => "00:00:00:00:00:01", + SA => "00:00:00:00:00:01", + src_ip => "192.168.0.40", + dst_ip => "192.168.0.40", + ttl => 64, + len => 64 + }; + my $pkt = new NF2::IP_pkt(%$pkt_args); + + print "Sending now: \n"; + send_and_count( 'eth1', $pkt->packed, \%delta ); + + $pkt_args = { + DA => "00:00:00:00:00:02", + SA => "00:00:00:00:00:02", + src_ip => "192.168.1.40", + dst_ip => "192.168.1.40", + ttl => 64, + len => 64 + }; + $pkt = new NF2::IP_pkt(%$pkt_args); + send_and_count( 'eth2', $pkt->packed, \%delta ); + + $pkt_args = { + DA => "00:00:00:00:00:03", + SA => "00:00:00:00:00:03", + src_ip => "192.168.2.40", + dst_ip => "192.168.2.40", + ttl => 64, + len => 64 + }; + $pkt = new NF2::IP_pkt(%$pkt_args); + send_and_count( 'eth3', $pkt->packed, \%delta ); + + $pkt_args = { + DA => "00:00:00:00:00:04", + SA => "00:00:00:00:00:04", + src_ip => "192.168.3.40", + dst_ip => "192.168.3.40", + ttl => 64, + len => 64 + }; + $pkt = new NF2::IP_pkt(%$pkt_args); + send_and_count( 'eth4', $pkt->packed, \%delta ); + + return %delta; +} + +run_learning_switch_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/learning_switch/regress/test_unicast_unknown/run.pl b/openflow/regress/projects/learning_switch/regress/test_unicast_unknown/run.pl new file mode 100755 index 00000000..4378ae00 --- /dev/null +++ b/openflow/regress/projects/learning_switch/regress/test_unicast_unknown/run.pl @@ -0,0 +1,32 @@ +#!/usr/bin/perl -w +#test_unicast_unknown + +use strict; +use OF::Includes; + +sub my_test { + + my $pkt_args = { + DA => "00:00:00:00:00:02", + SA => "00:00:00:00:00:01", + src_ip => "192.168.0.40", + dst_ip => "192.168.1.40", + ttl => 64, + len => 64 + }; + my $pkt = new NF2::IP_pkt(%$pkt_args); + + my %delta; + + # send one packet; controller should learn MAC, add a flow + # entry, and send this packet out the other interfaces + print "Sending now: \n"; + send_and_count( 'eth1', $pkt->packed, \%delta ); + expect_and_count( 'eth2', $pkt->packed, \%delta ); + expect_and_count( 'eth3', $pkt->packed, \%delta ); + expect_and_count( 'eth4', $pkt->packed, \%delta ); + + return %delta; +} + +run_learning_switch_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/learning_switch/regress/tests.txt b/openflow/regress/projects/learning_switch/regress/tests.txt new file mode 100644 index 00000000..fdeb3c51 --- /dev/null +++ b/openflow/regress/projects/learning_switch/regress/tests.txt @@ -0,0 +1,12 @@ +test_unicast_unknown/run.pl +test_unicast_known/run.pl +test_broadcast/run.pl +##test_unicast_self/run.pl +test_unicast_move/run.pl +##test_hub_connected/run.pl +test_unicast_multiple_hosts/run.pl + +# BELOW NOT INCLUDED IN CURRRENT RELEASE +# WILL BE AVAILABLE SOON +##test_forward_latency/run.pl +##test_forward_bandwidth/run.pl diff --git a/openflow/regress/projects/regress.txt b/openflow/regress/projects/regress.txt new file mode 100644 index 00000000..9339cd32 --- /dev/null +++ b/openflow/regress/projects/regress.txt @@ -0,0 +1,3 @@ +black_box +controller_disconnect +learning_switch diff --git a/openflow/regress/scripts/copy_NF2_code.sh b/openflow/regress/scripts/copy_NF2_code.sh new file mode 100755 index 00000000..56ff83bf --- /dev/null +++ b/openflow/regress/scripts/copy_NF2_code.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +#last use of this script copied in files from NF2 SVN rev 3904 +#note: OFT_ROOT and NF2_ROOT must be set +cp $NF2_ROOT/lib/Perl5/Test/* $OFT_ROOT/lib/Perl5/Test/ diff --git a/openflow/regress/scripts/env_vars b/openflow/regress/scripts/env_vars new file mode 100644 index 00000000..a8f2433d --- /dev/null +++ b/openflow/regress/scripts/env_vars @@ -0,0 +1,12 @@ +export OF_ROOT=/home/yourname/openflow +export OFT_ROOT=${OF_ROOT}/regress +export PATH=${OFT_ROOT}/bin:/sbin:/usr/sbin:${PATH} +export PERL5LIB=${OFT_ROOT}/lib/Perl5:${PERL5LIB} +export OFT_MAP_ETH=${OFT_ROOT}/bin/of_generic_eth.map +export OFT_HP_MAP_ETH=${OFT_ROOT}/bin/of_hp_eth.map +export OFT_HP_SWITCH_IP=10.10.10.2 +export OFT_HP_VLAN=10 +export OFT_HP_CONTROLLER="tcp:10.10.10.3:6633" +export OFT_HP_LISTENER="tcp:10.10.10.2:6633" +export OFT_OVS_ROOT=/home/yourname/openvswitch +export OFT_OVS_MAP_ETH=${OFT_ROOT}/bin/of_ovs_eth.map diff --git a/openflow/regress/scripts/install_deps.pl b/openflow/regress/scripts/install_deps.pl new file mode 100755 index 00000000..4668a58b --- /dev/null +++ b/openflow/regress/scripts/install_deps.pl @@ -0,0 +1,264 @@ +#!/usr/bin/perl -W +# +# Script to automatically install dependencies for regression tests + +use strict; +use File::Basename; +use File::Path; +use Getopt::Std; +use Cwd; + +use constant { + UBUNTU => 'Ubuntu', + DEBIAN => 'Debian', + REDHAT => 'RedHat', + FEDORA => 'Fedora', + + UNKNOWN => 'unknown', + X86_64 => 'x86_64', +}; + +# Executables +my $lsb_release = 'lsb_release'; +my $apt_get = 'apt-get'; +my $yum = 'yum'; +my $uname = '/bin/uname'; + +my $distro; +my $machine; +my $sim; +my %install_funcs = ( + 'Ubuntu' => \&install_ubuntu_debian, + 'Debian' => \&install_ubuntu_debian, + 'Fedora' => \&install_fedora, +); +our($opt_s, $opt_d); + +# Verify that this script is being run as root +if ($> != 0) { + die "This script must be run as root"; +} + +# Parse the command line arguments +parse_args(); + + +# Identify the distribution and machine +if (!defined($distro)) { + identify_distro(); + die "Unable to identify the distribution" if (!defined($distro)); +} +identify_machine(); + +# Call the appropriate install function +if ($install_funcs{$distro}) { + $install_funcs{$distro}->(); +} +else { + die "Unable to find the install function for '$distro'"; +} + +exit 0; + +#========================================================== + +# +# identify_distro: +# Attempt to identify the Linux distro +# +sub identify_distro { + # First, look for lsb release which makes querying easier + $lsb_release = `which $lsb_release`; + chomp($lsb_release); + if ( $? >> 8 == 0) { + $distro = `$lsb_release -s -i`; + chomp($distro); + SWITCH: for ($distro) { + /Ubuntu/ && do { + $distro = UBUNTU; + last SWITCH; + }; + + /Debian/ && do { + $distro = DEBIAN; + last SWITCH; + }; + + (/CentOS/ || /RedHat/) && do { + $distro = REDHAT; + last SWITCH; + }; + + /Fedora/ && do { + $distro = FEDORA; + last SWITCH; + }; + + # DEFAULT + warn "Unknown Linux distro '$distro'"; + $distro = undef; + } + } + + # Otherwise, fall back to looking for release/version files in /etc + else { + if ( -f '/etc/debian_version' || -f '/etc/debian_release' ) { + $distro = DEBIAN; + } + elsif ( -f '/etc/fedora-release') { + $distro = FEDORA; + } + elsif ( -f '/etc/redhat-release' || -f '/etc/redhat_release' ) { + $distro = REDHAT; + } + } +} + +# +# identify_machine: +# Attempt to identify the machine type +# +sub identify_machine { + # First, look for lsb release which makes querying easier + if ( -x $uname) { + $machine = `$uname -m`; + chomp($machine); + } + + # we don't know what sort of machine this is + else { + $machine = UNKNOWN; + } +} + +# +# install_ubuntu_debian: +# Install the necessary dependencies for Ubuntu and Debian +# +sub install_ubuntu_debian { + my @pkgs = ( + 'liberror-perl', + 'libio-interface-perl', + 'liblist-moreutils-perl', + 'libpcap0.8-dev', + 'iproute', + 'psmisc', + 'libnet-pcap-perl', + 'libnet-rawip-perl', + 'wget', + ); + if ($machine eq X86_64) { + push (@pkgs, 'libc6-dev-i386', 'ia32-libs'); + } + + my @modules = ( + 'http://search.cpan.org/CPAN/authors/id/F/FT/FTASSIN/Data-HexDump-0.02.tar.gz', + 'http://www.cpan.org/authors/id/J/JV/JV/Getopt-Long-2.38.tar.gz', + ); + + if ($distro eq UBUNTU) { + push (@pkgs, 'libconvert-binary-c-perl') + } + else { + push (@modules, + 'http://search.cpan.org/CPAN/authors/id/M/MH/MHX/Convert-Binary-C-0.74.tar.gz') + } + + # Run apt-get + my @flags = ('-y'); + push(@flags, '-s') if defined($sim); + system($apt_get, @flags, 'install', @pkgs); + if ($? >> 8 != 0) { + die "Error running $apt_get"; + } + + # Install modules directly from CPAN + install_perl_modules(@modules); +} + +# +# install_fedora: +# Install the necessary dependencies for Fedora Core +# +sub install_fedora { + my @pkgs = ( + 'perl-Convert-Binary-C', + 'perl-Data-HexDump', + 'perl-Net-Pcap', + 'perl-Error.noarch', + 'perl-Module-Build', + 'libpcap-devel', + 'perl-List-MoreUtils', + 'perl-Net-RawIP', + ); + + # Run yum + my @flags = ('-y'); + if (defined($sim)) { + push(@flags, 'info'); + } + else { + push(@flags, 'install'); + } + system($yum, @flags, @pkgs); + if ($? >> 8 != 0) { + die "Error running $yum"; + } +} + +# +# install_perl_modules: +# Fetch and install PERL modules +# +sub install_perl_modules { + my @modules = @_; + + my $dir = "perl_modules"; + + mkdir $dir; + chdir $dir; + + foreach my $path (@modules) { + `wget $path`; + my $module = fileparse($path); + `tar xzf $module`; + $module =~ s/.tar.gz//; + print "compiling $module\n"; + chdir $module; + if (!defined($sim)) { + system 'perl Makefile.PL'; + system 'make'; + system 'make install'; + } + chdir '../'; + } + + chdir '..'; + rmtree $dir; +} + +# +# parse_args +# Parse the command line arguments +# +sub parse_args { + getopts('sd:'); + $sim = 1 if defined($opt_s); + $distro = $opt_d if defined($opt_d); +} + +sub HELP_MESSAGE { + print < 0) { $release_num = $ARGV[0]; } + +check_OF_vars_set(); + +my $rootdir = $ENV{'OFT_ROOT'}; +print "starting at root dir $rootdir\n"; +chdir $rootdir; + +my @ignore_list = ( + './temp', + './scripts/copy_NF2_code.sh', + './scripts/make_release.pl', + './projects/learning_switch/regress/test_forward_bandwidth/run.pl', + './projects/learning_switch/regress/test_forward_bandwidth/run.pl', + './projects/black_box/regress/test_send_bandwidth_fixed/run.pl', + './projects/black_box/regress/test_send_bandwidth_random/run.pl', + './projects/black_box/regress/test_add_flow_bandwidth/run.pl', + './projects/black_box/regress/test_add_flow_latency/run.pl', + './projects/black_box/regress/test_receive_bandwidth_fixed/run.pl', + './projects/black_box/regress/test_receive_bandwidth_random/run.pl', + './projects/black_box/regress/test_forward_bandwidth_fixed/run.pl', + './projects/black_box/regress/test_forward_bandwidth_random/run.pl', + './projects/black_box/regress/test_forward_latency/run.pl', + './projects/black_box/regress/test_switch_bandwidth_random/run.pl', + './projects/black_box/regress/test_switch_bandwidth_random/run.pl' +); + +my @files = parse_dir ('.'); + +print "\n"; + +foreach my $file (@files) { + print $file . "\n"; +} + +# set x permission for non-.pl files +# originally used perl chmod, but it doesn't work +my @write_perm_list = ( + "./temp/$of_ver/projects/learning_switch/regress/common/setup", + "./temp/$of_ver/projects/learning_switch/regress/common/teardown", + "./temp/$of_ver/projects/black_box/regress/common/setup", + "./temp/$of_ver/projects/black_box/regress/common/teardown" +); +foreach my $file (@write_perm_list) { + `chmod 755 $file`; +} + +#print $write_perm_list[0] . "\n"; + +`cd $rootdir/temp; tar czf $of_ver.tar.gz *`; +exit (0); + +# DFS +sub parse_dir { + my ($path) = @_; + #print "parse_dir called with $path\n"; + my @file_list; + # exists? + if (! -e "$path") { + die "checked $path and failed\n"; + } + # file? + elsif (-f "$path") { + if (file_ok($path)) { + print "added $path to list\n"; + push @file_list, "$path"; + + copy($path, "temp/$of_ver/$path") || die "failed to copy $path\n"; + + #for perl files, make them executable + my $match = $path =~ m/.pl/; + print " match = $match\n"; + if ($match) { + # ensure file is executable + print " setting chmod for $path\n"; + chmod 755, "temp/$of_ver/$path" || die "failed to set chmod $path\n"; + }; + } + else { + #print "ignore file $path\n"; + } + } + # directory? + elsif (-d $path) { + #print "parsing directory $path\n"; + opendir(DIR, $path) || print "Can't open... maybe try chmod 777"; + my @files_in_dir=readdir(DIR); + closedir(DIR); + + if (dir_ok('', $path) && $path ne '.') { + #remove ./ at beginning + + my $path_temp = substr($path, 2); + mkdir("temp/$of_ver/$path_temp") || die "failed to make path temp/$of_ver/$path_temp\n"; + } + + #print " dir looks like: \n"; + foreach my $file (@files_in_dir) { + #print " " . $file . "\n"; + } + + foreach my $subdir (@files_in_dir) { + if (dir_ok($subdir, $path) ) { + #print "\nabout to parse $path/$subdir\n"; + push @file_list, parse_dir("$path/$subdir"); + } + } + } + else { + die ("unknown error"); + } + + return @file_list; +} + +sub dir_ok { + my ($subdir, $path) = @_; + my $ignore = 0; + foreach my $file (@ignore_list) { + if ("$path/$subdir" eq $file) { $ignore = 1; last; } + } + + # ignore these three regardless of path - other require path to ignore + if ($subdir ne '.' && $subdir ne '..' && $subdir ne '.svn' && !$ignore ) { + return 1; + } + else { + return 0; + } +} + +sub file_ok { + my ($path) = @_; + my $ok = 1; + foreach my $file (@ignore_list) { + if ("$path" eq $file) { $ok = 0; last; } + } + return $ok; +} diff --git a/openflow/secchan/.dirstamp b/openflow/secchan/.dirstamp new file mode 100644 index 00000000..e69de29b diff --git a/openflow/secchan/.gitignore b/openflow/secchan/.gitignore new file mode 100644 index 00000000..d6d189d3 --- /dev/null +++ b/openflow/secchan/.gitignore @@ -0,0 +1,7 @@ +/Makefile +/Makefile.in +/controller-lite +/ctlpath-lite +/dpctl-lite +/ofprotocol +/ofprotocol.8 diff --git a/openflow/secchan/automake.mk b/openflow/secchan/automake.mk new file mode 100644 index 00000000..6a9f2041 --- /dev/null +++ b/openflow/secchan/automake.mk @@ -0,0 +1,32 @@ +bin_PROGRAMS += secchan/ofprotocol +man_MANS += secchan/ofprotocol.8 + +secchan_ofprotocol_SOURCES = \ + secchan/discovery.c \ + secchan/discovery.h \ + secchan/emerg-flow.c \ + secchan/emerg-flow.h \ + secchan/fail-open.c \ + secchan/fail-open.h \ + secchan/failover.c \ + secchan/failover.h \ + secchan/in-band.c \ + secchan/in-band.h \ + secchan/port-watcher.c \ + secchan/port-watcher.h \ + secchan/protocol-stat.c \ + secchan/protocol-stat.h \ + secchan/ratelimit.c \ + secchan/ratelimit.h \ + secchan/secchan.c \ + secchan/secchan.h \ + secchan/status.c \ + secchan/status.h \ + secchan/stp-secchan.c \ + secchan/stp-secchan.h +secchan_ofprotocol_LDADD = lib/libopenflow.a $(FAULT_LIBS) $(SSL_LIBS) + +EXTRA_DIST += secchan/ofprotocol.8.in +DISTCLEANFILES += secchan/ofprotocol.8 + +include secchan/commands/automake.mk diff --git a/openflow/secchan/commands/automake.mk b/openflow/secchan/commands/automake.mk new file mode 100644 index 00000000..cbe44d8c --- /dev/null +++ b/openflow/secchan/commands/automake.mk @@ -0,0 +1,3 @@ +commandsdir = ${pkgdatadir}/commands +dist_commands_SCRIPTS = \ + secchan/commands/reboot diff --git a/openflow/secchan/commands/reboot b/openflow/secchan/commands/reboot new file mode 100755 index 00000000..4d5145cd --- /dev/null +++ b/openflow/secchan/commands/reboot @@ -0,0 +1,3 @@ +#! /bin/sh +ofp-kill --force --signal=USR1 ofp-switchui.pid +reboot diff --git a/openflow/secchan/discovery.c b/openflow/secchan/discovery.c new file mode 100644 index 00000000..feb9c338 --- /dev/null +++ b/openflow/secchan/discovery.c @@ -0,0 +1,251 @@ +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include "discovery.h" +#include +#include +#include +#include "dhcp-client.h" +#include "dhcp.h" +#include "netdev.h" +#include "openflow/openflow.h" +#include "packets.h" +#include "port-watcher.h" +#include "secchan.h" +#include "status.h" + +#define THIS_MODULE VLM_discovery +#include "vlog.h" + +struct discovery +{ + const struct settings *s; + struct dhclient *dhcp; + int n_changes; +}; + +static void modify_dhcp_request(struct dhcp_msg *, void *aux); +static bool validate_dhcp_offer(const struct dhcp_msg *, void *aux); + +static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60); + +static void +discovery_status_cb(struct status_reply *sr, void *d_) +{ + struct discovery *d = d_; + + status_reply_put(sr, "accept-remote=%s", d->s->accept_controller_re); + status_reply_put(sr, "n-changes=%d", d->n_changes); + if (d->dhcp) { + status_reply_put(sr, "state=%s", dhclient_get_state(d->dhcp)); + status_reply_put(sr, "state-elapsed=%u", + dhclient_get_state_elapsed(d->dhcp)); + if (dhclient_is_bound(d->dhcp)) { + uint32_t ip = dhclient_get_ip(d->dhcp); + uint32_t netmask = dhclient_get_netmask(d->dhcp); + uint32_t router = dhclient_get_router(d->dhcp); + + const struct dhcp_msg *cfg = dhclient_get_config(d->dhcp); + uint32_t dns_server; + char *domain_name; + int i; + + status_reply_put(sr, "ip="IP_FMT, IP_ARGS(&ip)); + status_reply_put(sr, "netmask="IP_FMT, IP_ARGS(&netmask)); + if (router) { + status_reply_put(sr, "router="IP_FMT, IP_ARGS(&router)); + } + + for (i = 0; dhcp_msg_get_ip(cfg, DHCP_CODE_DNS_SERVER, i, + &dns_server); + i++) { + status_reply_put(sr, "dns%d="IP_FMT, i, IP_ARGS(&dns_server)); + } + + domain_name = dhcp_msg_get_string(cfg, DHCP_CODE_DOMAIN_NAME); + if (domain_name) { + status_reply_put(sr, "domain=%s", domain_name); + free(domain_name); + } + + status_reply_put(sr, "lease-remaining=%u", + dhclient_get_lease_remaining(d->dhcp)); + } + } +} + +static void +discovery_local_port_cb(const struct ofp_phy_port *port, void *d_) +{ + struct discovery *d = d_; + if (port) { + char name[OFP_MAX_PORT_NAME_LEN + 1]; + struct netdev *netdev; + int retval; + + /* Check that this was really a change. */ + get_port_name(port, name, sizeof name); + if (d->dhcp && !strcmp(netdev_get_name(dhclient_get_netdev(d->dhcp)), + name)) { + return; + } + + /* Destroy current DHCP client. */ + dhclient_destroy(d->dhcp); + d->dhcp = NULL; + + /* Bring local network device up. */ + retval = netdev_open(name, NETDEV_ETH_TYPE_NONE, &netdev); + if (retval) { + VLOG_ERR("Could not open %s device, discovery disabled: %s", + name, strerror(retval)); + return; + } + retval = netdev_turn_flags_on(netdev, NETDEV_UP, true); + if (retval) { + VLOG_ERR("Could not bring %s device up, discovery disabled: %s", + name, strerror(retval)); + return; + } + netdev_close(netdev); + + /* Initialize DHCP client. */ + retval = dhclient_create(name, modify_dhcp_request, + validate_dhcp_offer, (void *) d->s, &d->dhcp); + if (retval) { + VLOG_ERR("Failed to initialize DHCP client, " + "discovery disabled: %s", strerror(retval)); + return; + } + dhclient_set_max_timeout(d->dhcp, 3); + dhclient_init(d->dhcp, 0); + } else { + dhclient_destroy(d->dhcp); + d->dhcp = NULL; + } +} + + +struct discovery * +discovery_init(const struct settings *s, struct port_watcher *pw, + struct switch_status *ss) +{ + struct discovery *d; + + d = xmalloc(sizeof *d); + d->s = s; + d->dhcp = NULL; + d->n_changes = 0; + + switch_status_register_category(ss, "discovery", discovery_status_cb, d); + port_watcher_register_local_port_callback(pw, discovery_local_port_cb, d); + + return d; +} + +void +discovery_question_connectivity(struct discovery *d) +{ + if (d->dhcp) { + dhclient_force_renew(d->dhcp, 15); + } +} + +bool +discovery_run(struct discovery *d, char **controller_name) +{ + if (!d->dhcp) { + *controller_name = NULL; + return true; + } + + dhclient_run(d->dhcp); + if (!dhclient_changed(d->dhcp)) { + return false; + } + + dhclient_configure_netdev(d->dhcp); + if (d->s->update_resolv_conf) { + dhclient_update_resolv_conf(d->dhcp); + } + + if (dhclient_is_bound(d->dhcp)) { + *controller_name = dhcp_msg_get_string(dhclient_get_config(d->dhcp), + DHCP_CODE_OFP_CONTROLLER_VCONN); + VLOG_INFO("%s: discovered controller", *controller_name); + d->n_changes++; + } else { + *controller_name = NULL; + if (d->n_changes) { + VLOG_INFO("discovered controller no longer available"); + d->n_changes++; + } + } + return true; +} + +void +discovery_wait(struct discovery *d) +{ + if (d->dhcp) { + dhclient_wait(d->dhcp); + } +} + +static void +modify_dhcp_request(struct dhcp_msg *msg, void *aux UNUSED) +{ + dhcp_msg_put_string(msg, DHCP_CODE_VENDOR_CLASS, "OpenFlow"); +} + +static bool +validate_dhcp_offer(const struct dhcp_msg *msg, void *s_) +{ + const struct settings *s = s_; + char *vconn_name; + bool accept; + + vconn_name = dhcp_msg_get_string(msg, DHCP_CODE_OFP_CONTROLLER_VCONN); + if (!vconn_name) { + VLOG_WARN_RL(&rl, "rejecting DHCP offer missing controller vconn"); + return false; + } + accept = !regexec(&s->accept_controller_regex, vconn_name, 0, NULL, 0); + if (!accept) { + VLOG_WARN_RL(&rl, "rejecting controller vconn that fails to match %s", + s->accept_controller_re); + } + free(vconn_name); + return accept; +} diff --git a/openflow/secchan/discovery.h b/openflow/secchan/discovery.h new file mode 100644 index 00000000..b2cb03c9 --- /dev/null +++ b/openflow/secchan/discovery.h @@ -0,0 +1,50 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#ifndef DISCOVERY_H +#define DISCOVERY_H 1 + +#include + +struct settings; +struct port_watcher; +struct switch_status; + +struct discovery *discovery_init(const struct settings *, + struct port_watcher *, + struct switch_status *); +void discovery_question_connectivity(struct discovery *); +bool discovery_run(struct discovery *, char **controller_name); +void discovery_wait(struct discovery *); + +#endif /* discovery.h */ diff --git a/openflow/secchan/emerg-flow.c b/openflow/secchan/emerg-flow.c new file mode 100644 index 00000000..9af58819 --- /dev/null +++ b/openflow/secchan/emerg-flow.c @@ -0,0 +1,144 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "openflow/openflow.h" +#include "openflow/private-ext.h" + +#include "util.h" +#include "vconn.h" +#include "rconn.h" +#include "secchan.h" +#include "status.h" +#include "timeval.h" +#include "sat-math.h" +#include "ofpbuf.h" +#include "emerg-flow.h" +#define THIS_MODULE VLM_emerg_flow +#include "vlog.h" + +struct emerg_flow_context { + const struct settings *settings; + const struct secchan *secchan; + struct rconn *local_rconn; + struct rconn *remote_rconn; + int prev_state; + int state; +}; + +static void emerg_flow_status_cb(struct status_reply *, void *); +static void emerg_flow_periodic_cb(void *); + +static void +emerg_flow_status_cb(struct status_reply *status_reply, void *context_) +{ + struct emerg_flow_context *context = context_; + + status_reply_put(status_reply, "state=%s", + context->state == PRIVATEOPT_EMERG_FLOW_RESTORATION + ? "restoration" + : context->state == PRIVATEOPT_EMERG_FLOW_PROTECTION + ? "protection" : "unknown"); +} + +static void +emerg_flow_periodic_cb(void *context_) +{ + struct emerg_flow_context *context = context_; + struct ofpbuf *buf = NULL; + struct private_vxhdr *vxhdr = NULL; + struct private_vxopt *vxopt = NULL; + int error = 0; + + if (rconn_is_connected(context->remote_rconn)) { + if (context->state == PRIVATEOPT_EMERG_FLOW_PROTECTION) { + context->prev_state = context->state; + context->state = PRIVATEOPT_EMERG_FLOW_RESTORATION; + } else { + return; + } + } else { + if (context->state == PRIVATEOPT_EMERG_FLOW_RESTORATION) { + context->prev_state = context->state; + context->state = PRIVATEOPT_EMERG_FLOW_PROTECTION; + } else { + return; + } + } + + vxhdr = (struct private_vxhdr *)make_openflow + (sizeof(*vxhdr) + sizeof(*vxopt), OFPT_VENDOR, &buf); + vxopt = (struct private_vxopt *)(vxhdr + 1); + vxhdr->ofp_vxid = htonl(PRIVATE_VENDOR_ID); + vxopt->pvo_type = htons(context->state); + vxopt->pvo_len = htons(0); + + error = rconn_send(context->local_rconn, buf, NULL); + if (error && error != EAGAIN) { + VLOG_WARN("send failed (%s)", strerror(error)); + } +} + +void +emerg_flow_start(struct secchan *secchan, const struct settings *settings, + struct switch_status *switch_status, + struct rconn *local_rconn, struct rconn *remote_rconn) +{ + struct emerg_flow_context *context = NULL; + static struct hook_class emerg_flow_hook_class = { + NULL, /* local_packet_cb */ + NULL, /* remote_packet_cb */ + emerg_flow_periodic_cb, /* periodic_cb */ + NULL, /* wait_cb */ + NULL, /* closing_cb */ + }; + + context = xmalloc(sizeof(*context)); + context->settings = settings; + context->secchan = secchan; + context->local_rconn = local_rconn; + context->remote_rconn = remote_rconn; + context->prev_state = PRIVATEOPT_EMERG_FLOW_PROTECTION; + context->state = PRIVATEOPT_EMERG_FLOW_PROTECTION; + + switch_status_register_category(switch_status, "emerg-flow", + emerg_flow_status_cb, context); + add_hook(secchan, &emerg_flow_hook_class, context); +} diff --git a/openflow/secchan/emerg-flow.h b/openflow/secchan/emerg-flow.h new file mode 100644 index 00000000..d61a7fe2 --- /dev/null +++ b/openflow/secchan/emerg-flow.h @@ -0,0 +1,44 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#ifndef EMERG_FLOW_H_ +#define EMERG_FLOW_H_ 1 + +struct rconn; +struct secchan; +struct settings; +struct switch_status; + +void emerg_flow_start(struct secchan *, const struct settings *, + struct switch_status *, struct rconn *, struct rconn *); + +#endif diff --git a/openflow/secchan/fail-open.c b/openflow/secchan/fail-open.c new file mode 100644 index 00000000..eb28bc38 --- /dev/null +++ b/openflow/secchan/fail-open.c @@ -0,0 +1,159 @@ +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include "fail-open.h" +#include +#include +#include +#include "learning-switch.h" +#include "netdev.h" +#include "packets.h" +#include "port-watcher.h" +#include "rconn.h" +#include "secchan.h" +#include "status.h" +#include "stp-secchan.h" +#include "timeval.h" + +#define THIS_MODULE VLM_fail_open +#include "vlog.h" + +struct fail_open_data { + const struct settings *s; + struct rconn *local_rconn; + struct rconn *remote_rconn; + struct lswitch *lswitch; + int last_disconn_secs; + time_t boot_deadline; +}; + +/* Causes 'r' to enter or leave fail-open mode, if appropriate. */ +static void +fail_open_periodic_cb(void *fail_open_) +{ + struct fail_open_data *fail_open = fail_open_; + int disconn_secs; + bool open; + + if (time_now() < fail_open->boot_deadline) { + return; + } + disconn_secs = rconn_failure_duration(fail_open->remote_rconn); + open = disconn_secs >= fail_open->s->probe_interval * 3; + if (open != (fail_open->lswitch != NULL)) { + if (!open) { + VLOG_WARN("No longer in fail-open mode"); + lswitch_destroy(fail_open->lswitch); + fail_open->lswitch = NULL; + } else { + VLOG_WARN("Could not connect to controller for %d seconds, " + "failing open", disconn_secs); + fail_open->lswitch = lswitch_create(fail_open->local_rconn, true, + fail_open->s->max_idle); + fail_open->last_disconn_secs = disconn_secs; + } + } else if (open && disconn_secs > fail_open->last_disconn_secs + 60) { + VLOG_INFO("Still in fail-open mode after %d seconds disconnected " + "from controller", disconn_secs); + fail_open->last_disconn_secs = disconn_secs; + } + if (fail_open->lswitch) { + lswitch_run(fail_open->lswitch, fail_open->local_rconn); + } +} + +static void +fail_open_wait_cb(void *fail_open_) +{ + struct fail_open_data *fail_open = fail_open_; + if (fail_open->lswitch) { + lswitch_wait(fail_open->lswitch); + } +} + +static bool +fail_open_local_packet_cb(struct relay *r, void *fail_open_) +{ + struct fail_open_data *fail_open = fail_open_; + if (rconn_is_connected(fail_open->remote_rconn) || !fail_open->lswitch) { + return false; + } else { + lswitch_process_packet(fail_open->lswitch, fail_open->local_rconn, + r->halves[HALF_LOCAL].rxbuf); + rconn_run(fail_open->local_rconn); + return true; + } +} + +static void +fail_open_status_cb(struct status_reply *sr, void *fail_open_) +{ + struct fail_open_data *fail_open = fail_open_; + const struct settings *s = fail_open->s; + int trigger_duration = s->probe_interval * 3; + int cur_duration = rconn_failure_duration(fail_open->remote_rconn); + + status_reply_put(sr, "trigger-duration=%d", trigger_duration); + status_reply_put(sr, "current-duration=%d", cur_duration); + status_reply_put(sr, "triggered=%s", + cur_duration >= trigger_duration ? "true" : "false"); + status_reply_put(sr, "max-idle=%d", s->max_idle); +} + +static struct hook_class fail_open_hook_class = { + fail_open_local_packet_cb, /* local_packet_cb */ + NULL, /* remote_packet_cb */ + fail_open_periodic_cb, /* periodic_cb */ + fail_open_wait_cb, /* wait_cb */ + NULL, /* closing_cb */ +}; + +void +fail_open_start(struct secchan *secchan, const struct settings *s, + struct switch_status *ss, + struct rconn *local_rconn, struct rconn *remote_rconn) +{ + struct fail_open_data *fail_open = xmalloc(sizeof *fail_open); + fail_open->s = s; + fail_open->local_rconn = local_rconn; + fail_open->remote_rconn = remote_rconn; + fail_open->lswitch = NULL; + fail_open->boot_deadline = time_now() + s->probe_interval * 3; + if (s->enable_stp) { + fail_open->boot_deadline += STP_EXTRA_BOOT_TIME; + } + switch_status_register_category(ss, "fail-open", + fail_open_status_cb, fail_open); + add_hook(secchan, &fail_open_hook_class, fail_open); +} diff --git a/openflow/secchan/fail-open.h b/openflow/secchan/fail-open.h new file mode 100644 index 00000000..69a3b310 --- /dev/null +++ b/openflow/secchan/fail-open.h @@ -0,0 +1,46 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#ifndef FAIL_OPEN_H +#define FAIL_OPEN_H 1 + +struct rconn; +struct secchan; +struct settings; +struct switch_status; + +void fail_open_start(struct secchan *, const struct settings *, + struct switch_status *, + struct rconn *local, struct rconn *remote); + +#endif /* fail-open.h */ diff --git a/openflow/secchan/failover.c b/openflow/secchan/failover.c new file mode 100644 index 00000000..718d7379 --- /dev/null +++ b/openflow/secchan/failover.c @@ -0,0 +1,144 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#include +#include +#include +#include + +#include "util.h" +#include "rconn.h" +#include "secchan.h" +#include "status.h" +#include "timeval.h" +#include "sat-math.h" +#include "failover.h" +#define THIS_MODULE VLM_failover +#include "vlog.h" + +struct failover_peer { + time_t epoch; +}; + +struct failover_context { + const struct settings *settings; + const struct secchan *secchan; + struct rconn *remote_rconn; + int index; + struct failover_peer *peers[MAX_CONTROLLERS]; +}; + +static void failover_status_cb(struct status_reply *, void *); +static bool is_timed_out(const struct failover_peer *, int); +static void failover_periodic_cb(void *); + +static void +failover_status_cb(struct status_reply *status_reply, void *context_) +{ + struct failover_context *context = context_; + int i; + + status_reply_put(status_reply, "num-controllers=%d", + context->settings->num_controllers); + + for (i = 0; i < MAX_CONTROLLERS; ++i) { + if (context->settings->controller_names[i] == NULL) + continue; + status_reply_put(status_reply, "controller#%d=%s", + i, context->settings->controller_names[i]); + } +} + +static bool +is_timed_out(const struct failover_peer *peer, int max_backoff) +{ + unsigned int sat_value = sat_add(peer->epoch, max_backoff); + return time_now() >= sat_value; +} + +static void +failover_periodic_cb(void *context_) +{ + struct failover_context *context = context_; + char *curr_peer = NULL; + char *prev_peer = NULL; + + if (rconn_is_connected(context->remote_rconn)) + return; + + if (!is_timed_out(context->peers[context->index], + context->settings->max_backoff)) { + return; + } + + rconn_disconnect(context->remote_rconn); + prev_peer = (char *)context->settings->controller_names[context->index]; + context->index = (context->index + 1) + % context->settings->num_controllers; + curr_peer = (char *)context->settings->controller_names[context->index]; + rconn_connect(context->remote_rconn, + context->settings->controller_names[context->index]); + context->peers[context->index]->epoch = time_now(); + VLOG_INFO("Switching over to %s, from %s", curr_peer, prev_peer); +} + +void +failover_start(struct secchan *secchan, const struct settings *settings, + struct switch_status *switch_status, struct rconn *remote_rconn) +{ + struct failover_context *context = NULL; + int i; + static struct hook_class failover_hook_class = { + NULL, /* local_packet_cb */ + NULL, /* remote_packet_cb */ + failover_periodic_cb, /* periodic_cb */ + NULL, /* wait_cb */ + NULL, /* closing_cb */ + }; + + context = xmalloc(sizeof(*context)); + context->settings = settings; + context->secchan = secchan; + context->remote_rconn = remote_rconn; + context->index = 0; + for (i = 0; i < MAX_CONTROLLERS; ++i) { + context->peers[i] = NULL; + if (settings->controller_names[i] == NULL) + continue; + context->peers[i] = xmalloc(sizeof(struct failover_peer)); + context->peers[i]->epoch = time_now(); + } + + switch_status_register_category(switch_status, "failover", + failover_status_cb, context); + add_hook(secchan, &failover_hook_class, context); +} diff --git a/openflow/secchan/failover.h b/openflow/secchan/failover.h new file mode 100644 index 00000000..d511b35f --- /dev/null +++ b/openflow/secchan/failover.h @@ -0,0 +1,44 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#ifndef FAILOVER_H_ +#define FAILOVER_H_ 1 + +struct rconn; +struct secchan; +struct settings; +struct switch_status; + +void failover_start(struct secchan *, const struct settings *, + struct switch_status *, struct rconn *); + +#endif diff --git a/openflow/secchan/in-band.c b/openflow/secchan/in-band.c new file mode 100644 index 00000000..46109daf --- /dev/null +++ b/openflow/secchan/in-band.c @@ -0,0 +1,331 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include "in-band.h" +#include +#include +#include +#include +#include "flow.h" +#include "mac-learning.h" +#include "netdev.h" +#include "ofpbuf.h" +#include "openflow/openflow.h" +#include "packets.h" +#include "port-watcher.h" +#include "rconn.h" +#include "secchan.h" +#include "status.h" +#include "timeval.h" +#include "vconn.h" + +#define THIS_MODULE VLM_in_band +#include "vlog.h" + +struct in_band_data { + const struct settings *s; + struct mac_learning *ml; + struct netdev *of_device; + struct rconn *controller; + int n_queued; +}; + +static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60); + +static void +queue_tx(struct rconn *rc, struct in_band_data *in_band, struct ofpbuf *b) +{ + rconn_send_with_limit(rc, b, &in_band->n_queued, 10); +} + +static const uint8_t * +get_controller_mac(struct in_band_data *in_band) +{ + static uint32_t ip, last_nonzero_ip; + static uint8_t mac[ETH_ADDR_LEN], last_nonzero_mac[ETH_ADDR_LEN]; + static time_t next_refresh = 0; + + uint32_t last_ip = ip; + + time_t now = time_now(); + + ip = rconn_get_ip(in_band->controller); + if (last_ip != ip || !next_refresh || now >= next_refresh) { + bool have_mac; + + /* Look up MAC address. */ + memset(mac, 0, sizeof mac); + if (ip && in_band->of_device) { + int retval = netdev_arp_lookup(in_band->of_device, ip, mac); + if (retval) { + VLOG_DBG_RL(&rl, "cannot look up controller hw address " + "("IP_FMT"): %s", IP_ARGS(&ip), strerror(retval)); + } + } + have_mac = !eth_addr_is_zero(mac); + + /* Log changes in IP, MAC addresses. */ + if (ip && ip != last_nonzero_ip) { + VLOG_DBG("controller IP address changed from "IP_FMT + " to "IP_FMT, IP_ARGS(&last_nonzero_ip), IP_ARGS(&ip)); + last_nonzero_ip = ip; + } + if (have_mac && memcmp(last_nonzero_mac, mac, ETH_ADDR_LEN)) { + VLOG_DBG("controller MAC address changed from "ETH_ADDR_FMT" to " + ETH_ADDR_FMT, + ETH_ADDR_ARGS(last_nonzero_mac), ETH_ADDR_ARGS(mac)); + memcpy(last_nonzero_mac, mac, ETH_ADDR_LEN); + } + + /* Schedule next refresh. + * + * If we have an IP address but not a MAC address, then refresh + * quickly, since we probably will get a MAC address soon (via ARP). + * Otherwise, we can afford to wait a little while. */ + next_refresh = now + (!ip || have_mac ? 10 : 1); + } + return !eth_addr_is_zero(mac) ? mac : NULL; +} + +static bool +is_controller_mac(const uint8_t dl_addr[ETH_ADDR_LEN], + struct in_band_data *in_band) +{ + const uint8_t *mac = get_controller_mac(in_band); + return mac && eth_addr_equals(mac, dl_addr); +} + +static void +in_band_learn_mac(struct in_band_data *in_band, + uint16_t in_port, const uint8_t src_mac[ETH_ADDR_LEN]) +{ + if (mac_learning_learn(in_band->ml, src_mac, 0, in_port)) { + VLOG_DBG_RL(&rl, "learned that "ETH_ADDR_FMT" is on port %"PRIu16, + ETH_ADDR_ARGS(src_mac), in_port); + } +} + +static bool +in_band_local_packet_cb(struct relay *r, void *in_band_) +{ + struct in_band_data *in_band = in_band_; + struct rconn *rc = r->halves[HALF_LOCAL].rconn; + struct ofp_packet_in *opi; + struct eth_header *eth; + struct ofpbuf payload; + struct flow flow; + uint16_t in_port; + int out_port; + + if (!get_ofp_packet_eth_header(r, &opi, ð) || !in_band->of_device) { + return false; + } + in_port = ntohs(opi->in_port); + get_ofp_packet_payload(opi, &payload); + flow_extract(&payload, in_port, &flow); + + /* Deal with local stuff. */ + if (in_port == OFPP_LOCAL) { + /* Sent by secure channel. */ + out_port = mac_learning_lookup(in_band->ml, eth->eth_dst, 0); + } else if (eth_addr_equals(eth->eth_dst, + netdev_get_etheraddr(in_band->of_device))) { + /* Sent to secure channel. */ + out_port = OFPP_LOCAL; + in_band_learn_mac(in_band, in_port, eth->eth_src); + } else if (eth->eth_type == htons(ETH_TYPE_ARP) + && eth_addr_is_broadcast(eth->eth_dst) + && is_controller_mac(eth->eth_src, in_band)) { + /* ARP sent by controller. */ + out_port = OFPP_FLOOD; + } else if ((is_controller_mac(eth->eth_dst, in_band) + || is_controller_mac(eth->eth_src, in_band)) + && flow.dl_type == htons(ETH_TYPE_IP) + && flow.nw_proto == IP_TYPE_TCP + && (flow.tp_src == htons(OFP_TCP_PORT) + || flow.tp_src == htons(OFP_SSL_PORT) + || flow.tp_dst == htons(OFP_TCP_PORT) + || flow.tp_dst == htons(OFP_SSL_PORT))) { + /* Traffic to or from controller. Switch it by hand. */ + in_band_learn_mac(in_band, in_port, eth->eth_src); + out_port = mac_learning_lookup(in_band->ml, eth->eth_dst, 0); + } else { + const uint8_t *controller_mac; + controller_mac = get_controller_mac(in_band); + if (eth->eth_type == htons(ETH_TYPE_ARP) + && eth_addr_is_broadcast(eth->eth_dst) + && is_controller_mac(eth->eth_src, in_band)) { + /* ARP sent by controller. */ + out_port = OFPP_FLOOD; + } else if (is_controller_mac(eth->eth_dst, in_band) + && in_port == mac_learning_lookup(in_band->ml, + controller_mac, 0)) { + /* Drop controller traffic that arrives on the controller port. */ + out_port = -1; + } else { + return false; + } + } + + if (in_port == out_port) { + /* The input and output port match. Set up a flow to drop packets. */ + queue_tx(rc, in_band, make_add_flow(&flow, ntohl(opi->buffer_id), + in_band->s->max_idle, 0)); + } else if (out_port != OFPP_FLOOD) { + /* The output port is known, so add a new flow. */ + queue_tx(rc, in_band, + make_add_simple_flow(&flow, ntohl(opi->buffer_id), + out_port, in_band->s->max_idle)); + + /* If the switch didn't buffer the packet, we need to send a copy. */ + if (ntohl(opi->buffer_id) == UINT32_MAX) { + queue_tx(rc, in_band, + make_unbuffered_packet_out(&payload, in_port, out_port)); + } + } else { + /* We don't know that MAC. Send along the packet without setting up a + * flow. */ + struct ofpbuf *b; + if (ntohl(opi->buffer_id) == UINT32_MAX) { + b = make_unbuffered_packet_out(&payload, in_port, out_port); + } else { + b = make_buffered_packet_out(ntohl(opi->buffer_id), + in_port, out_port); + } + queue_tx(rc, in_band, b); + } + return true; +} + +static void +in_band_status_cb(struct status_reply *sr, void *in_band_) +{ + struct in_band_data *in_band = in_band_; + struct in_addr local_ip; + uint32_t controller_ip; + const uint8_t *controller_mac; + + if (in_band->of_device) { + const uint8_t *mac = netdev_get_etheraddr(in_band->of_device); + if (netdev_get_in4(in_band->of_device, &local_ip)) { + status_reply_put(sr, "local-ip="IP_FMT, IP_ARGS(&local_ip.s_addr)); + } + status_reply_put(sr, "local-mac="ETH_ADDR_FMT, ETH_ADDR_ARGS(mac)); + + controller_ip = rconn_get_ip(in_band->controller); + if (controller_ip) { + status_reply_put(sr, "controller-ip="IP_FMT, + IP_ARGS(&controller_ip)); + } + controller_mac = get_controller_mac(in_band); + if (controller_mac) { + status_reply_put(sr, "controller-mac="ETH_ADDR_FMT, + ETH_ADDR_ARGS(controller_mac)); + } + } +} + +void +get_ofp_packet_payload(struct ofp_packet_in *opi, struct ofpbuf *payload) +{ + payload->data = opi->data; + payload->size = ntohs(opi->header.length) - offsetof(struct ofp_packet_in, + data); +} + +static void +in_band_local_port_cb(const struct ofp_phy_port *port, void *in_band_) +{ + struct in_band_data *in_band = in_band_; + if (port) { + char name[sizeof port->name + 1]; + get_port_name(port, name, sizeof name); + + if (!in_band->of_device + || strcmp(netdev_get_name(in_band->of_device), name)) + { + int error; + netdev_close(in_band->of_device); + error = netdev_open(name, NETDEV_ETH_TYPE_NONE, + &in_band->of_device); + if (error) { + VLOG_ERR("failed to open in-band control network device " + "\"%s\": %s", name, strerror(errno)); + } + } + } else { + netdev_close(in_band->of_device); + in_band->of_device = NULL; + } +} + +static void +in_band_periodic_cb(void *in_band_) +{ + struct in_band_data *in_band = in_band_; + mac_learning_run(in_band->ml, NULL); +} + +static void +in_band_wait_cb(void *in_band_) +{ + struct in_band_data *in_band = in_band_; + mac_learning_wait(in_band->ml); +} + +static struct hook_class in_band_hook_class = { + in_band_local_packet_cb, /* local_packet_cb */ + NULL, /* remote_packet_cb */ + in_band_periodic_cb, /* periodic_cb */ + in_band_wait_cb, /* wait_cb */ + NULL, /* closing_cb */ +}; + +void +in_band_start(struct secchan *secchan, + const struct settings *s, struct switch_status *ss, + struct port_watcher *pw, struct rconn *remote) +{ + struct in_band_data *in_band; + + in_band = xcalloc(1, sizeof *in_band); + in_band->s = s; + in_band->ml = mac_learning_create(); + in_band->of_device = NULL; + in_band->controller = remote; + switch_status_register_category(ss, "in-band", in_band_status_cb, in_band); + port_watcher_register_local_port_callback(pw, in_band_local_port_cb, + in_band); + add_hook(secchan, &in_band_hook_class, in_band); +} diff --git a/openflow/secchan/in-band.h b/openflow/secchan/in-band.h new file mode 100644 index 00000000..b4d21ab9 --- /dev/null +++ b/openflow/secchan/in-band.h @@ -0,0 +1,47 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#ifndef IN_BAND_H +#define IN_BAND_H 1 + +struct port_watcher; +struct rconn; +struct secchan; +struct settings; +struct switch_status; + +void in_band_start(struct secchan *, const struct settings *, + struct switch_status *, struct port_watcher *, + struct rconn *remote); + +#endif /* in-band.h */ diff --git a/openflow/secchan/ofprotocol.8.in b/openflow/secchan/ofprotocol.8.in new file mode 100644 index 00000000..4aae44a3 --- /dev/null +++ b/openflow/secchan/ofprotocol.8.in @@ -0,0 +1,462 @@ +.ds PN ofprotocol +.TH ofprotocol 8 "October 2008" "OpenFlow" "OpenFlow Manual" + +.SH NAME +ofprotocol \- secure channel connecting an OpenFlow datapath to a controller + +.SH SYNOPSIS +.B ofprotocol +[\fIoptions\fR] \fIdatapath\fR controller[,\fIcontroller\fR...] + +.SH DESCRIPTION +The \fBofprotocol\fR program sets up a secure channel between a local +OpenFlow datapath and a remote controller. \fBofprotocol\fR connects to +the local datapath over Netlink and to the controller over TCP or SSL, +and then forwards OpenFlow messages from one endpoint to the other. + +The mandatory \fIdatapath\fR argument argument specifies the local datapath +to relay. It takes one of the following forms: + +.TP +\fBnl:\fIdp_idx\fR +Attach to the local kernel-based datapath over the Netlink protocol. +The \fIdp_idx\fR argument is the number of a datapath created with +\fBdpctl\fR(8). + +.TP +\fBunix:\fIfile\fR +Attach to the userspace datapath implemented by \fBofdatapath\fR(8). +The \fIfile\fR argument must the same one specified on the +\fBofdatapath\fR command line. + +.PP +The optional \fIcontroller\fR argument specifies how to connect to +an OpenFlow controller. Up to four controllers may be specified, +using the following forms: + +.TP +\fBssl:\fIhost\fR[\fB:\fIport\fR] +The specified SSL \fIport\fR (default: 6633) on the given remote +\fIhost\fR. The \fB--private-key\fR, \fB--certificate\fR, and +\fB--ca-cert\fR options are mandatory when this form is used. + +.TP +\fBtcp:\fIhost\fR[\fB:\fIport\fR] +The specified TCP \fIport\fR (default: 6633) on the given remote +\fIhost\fR. + +.TP +\fBunix:\fIfile\fR +The Unix domain server socket named \fIfile\fR. + +.PP +If multiple controllers are specified, \fBofprotocol\fR will attempt to +connect to a new controller when a controller connection fails, times +out, or is closed, or when a controller stops responding to echo requests. + +If \fIcontroller\fR is omitted, \fBofprotocol\fR attempts to discover the +location of the controller automatically (see below). + +.SH "CONTACTING THE CONTROLLER" +The OpenFlow switch must be able to contact the OpenFlow controller +over the network. It can do so in one of two ways: + +.IP out-of-band +In this configuration, OpenFlow traffic uses a network separate from +the data traffic that it controls, that is, the switch does not use +any of the network devices added to the datapath with \fBdpctl +addif\fR in its communication with the controller. + +To use \fBofprotocol\fR in a network with out-of-band control, specify +\fB--out-of-band\fR on the \fBofprotocol\fR command line. The control +network must be configured separately, before or after \fBofprotocol\fR +is started. + +.IP in-band +In this configuration, a single network is used for OpenFlow traffic +and other data traffic, that is, the switch contacts the controller +over one of the network devices added to the datapath with \fBdpctl +addif\fR. This configuration is often more convenient than +out-of-band control, because it is not necessary to maintain two +independent networks. + +In-band control is the default for \fBofprotocol\fR, so no special +command-line option is required. + +With in-band control, the location of the controller can be configured +manually or discovered automatically: + +.RS +.IP "controller discovery" +To make \fBofprotocol\fR discover the location of the controller +automatically, do not specify the location of the controller on the +\fBofprotocol\fR command line. + +In this mode, \fBofprotocol\fR will broadcast a DHCP request with vendor +class identifier \fBOpenFlow\fR across the network devices added to +the datapath with \fBdpctl addif\fR. It will accept any valid DHCP +reply that has the same vendor class identifier and includes a +vendor-specific option with code 1 whose contents are a string +specifying the location of the controller in the same format used on +the \fBofprotocol\fR command line (e.g. \fBssl:192.168.0.1\fR). + +The DHCP reply may also, optionally, include a vendor-specific option +with code 2 whose contents are a string specifying the URI to the base +of the OpenFlow PKI (e.g. \fBhttp://192.168.0.1/openflow/pki\fR). +This URI is used only for bootstrapping the OpenFlow PKI at initial +switch setup; \fBofprotocol\fR does not use it at all. + +The following ISC DHCP server configuration file assigns the IP +address range 192.168.0.20 through 192.168.0.30 to OpenFlow switches +that follow the switch protocol and addresses 192.168.0.1 through +192.168.0.10 to all other DHCP clients: + +default-lease-time 600; +.br +max-lease-time 7200; +.br +option space openflow; +.br +option openflow.controller-vconn code 1 = text; +.br +option openflow.pki-uri code 2 = text; +.br +class "OpenFlow" { +.br + match if option vendor-class-identifier = "OpenFlow"; +.br + vendor-option-space openflow; +.br + option openflow.controller-vconn "tcp:192.168.0.10"; +.br + option openflow.pki-uri "http://192.168.0.10/openflow/pki"; +.br + option vendor-class-identifier "OpenFlow"; +.br +} +.br +subnet 192.168.0.0 netmask 255.255.255.0 { +.br + pool { +.br + allow members of "OpenFlow"; +.br + range 192.168.0.20 192.168.0.30; +.br + } +.br + pool { +.br + deny members of "OpenFlow"; +.br + range 192.168.0.1 192.168.0.10; +.br + } +.br +} +.br + +.IP "manual configuration" +To configure in-band control manually, specify the location of the +controller on the \fBofprotocol\fR command line as the \fIcontroller\fR +argument. You must also configure the network device for the OpenFlow +``local port'' to allow \fBofprotocol\fR to connect to that controller. +The OpenFlow local port is a virtual network port that \fBofprotocol\fR +bridges to the physical switch ports. Its network device name depends +on the \fIdatapath\fR specified on the \fBofprotocol\fR command line: + +.RS +.TP +\fBnl:\fIdp_idx\fR +The local port network device for \fBnl:\fIdp_idx\fR is always named +\fBof\fIdp_idx\fR, i.e. the device for \fBnl:0\fR is \fBof0\fR. + +.TP +\fBunix:\fIfile\fR +The local port network device name may be specified on the +\fBofdatapath\fR command line, using the \fB--local-port\fR option. It +is often \fBtap0\fR. +.RE + +.IP +Before \fBofprotocol\fR starts, the local port network device is not +bridged to any physical network, so the next step depends on whether +connectivity is required to configure the device's IP address. If the +switch has a static IP address, you may configure its IP address now +with a command such as: +.RS +.IP +ifconfig of0 192.168.1.1 +.RE +.IP +and then invoke \fBofprotocol\fR. + +On the other hand, if the switch does not have a static IP address, +e.g. it obtains its IP address dynamically via DHCP, the DHCP client +will not be able to contact the DHCP server until the secure channel +has started up. Thus, start \fBofprotocol\fR without configuring +the local port network device, and start the DHCP client afterward. +.RE + +.SH OPTIONS +.SS "Controller Discovery Options" +.TP +\fB--accept-vconn=\fIregex\fR +When \fBofprotocol\fR performs controller discovery (see \fBCONTACTING +THE CONTROLLER\fR, above, for more information about controller +discovery), it validates the controller location obtained via DHCP +with a POSIX extended regular expression. Only controllers whose +names match the regular expression will be accepted. + +The default regular expression is \fBssl:.*\fR (meaning that only SSL +controller connections will be accepted) when any of the SSL +configuration options \fB--private-key\fR, \fB--certificate\fR, or +\fB--ca-cert\fR is specified. The default is \fB.*\fR otherwise +(meaning that any controller will be accepted). + +The \fIregex\fR is implicitly anchored at the beginning of the +controller location string, as if it begins with \fB^\fR. + +When controller discovery is not performed, this option has no effect. + +.TP +\fB--no-resolv-conf\fR +When \fBofprotocol\fR performs controller discovery (see \fBCONTACTING +THE CONTROLLER\fR, above, for more information about controller +discovery), by default it overwrites the system's +\fB/etc/resolv.conf\fR with domain information and DNS servers +obtained via DHCP. If the location of the controller is specified +using a hostname, rather than an IP address, and the network's DNS +servers ever change, this behavior is essential. But because it also +interferes with any administrator or process that manages +\fB/etc/resolv.conf\fR, when this option is specified, \fBofprotocol\fR +will not modify \fB/etc/resolv.conf\fR. + +\fBofprotocol\fR will only modify \fBresolv.conf\fR if the DHCP response +that it receives specifies one or more DNS servers. + +When controller discovery is not performed, this option has no effect. + +.SS "Networking Options" +.TP +\fB-F\fR, \fB--fail=\fR[\fBopen\fR|\fBclosed\fR] +The controller is, ordinarily, responsible for setting up all flows on +the OpenFlow switch. Thus, if the connection to the controller fails, +no new network connections can be set up. If the connection to the +controller stays down long enough, no packets can pass through the +switch at all. + +If this option is set to \fBopen\fR (the default), \fBofprotocol\fR will +take over responsibility for setting up flows in the local datapath +when no message has been received from the controller for three times +the inactivity probe interval (see below), or 45 seconds by default. +In this ``fail open'' mode, \fBofprotocol\fR causes the datapath to act +like an ordinary MAC-learning switch. \fBofprotocol\fR will continue to +retry connection to the controller in the background and, when the +connection succeeds, it discontinues its fail-open behavior. The +secure channel enters the fail-open mode when + +If this option is set to \fBclosed\fR, then \fBofprotocol\fR will not +set up flows on its own when the controller connection fails. + +.TP +\fB--inactivity-probe=\fIsecs\fR +When the secure channel is connected to the controller, the secure +channel waits for a message to be received from the controller for +\fIsecs\fR seconds before it sends a inactivity probe to the +controller. After sending the inactivity probe, if no response is +received for an additional \fIsecs\fR seconds, the secure channel +assumes that the connection has been broken and attempts to reconnect. +The default is 15 seconds, and the minimum value is 1 seconds. + +When fail-open mode is configured, changing the inactivity probe +interval also changes the interval before entering fail-open mode (see +above). + +.TP +\fB--max-idle=\fIsecs\fR|\fBpermanent\fR +Sets \fIsecs\fR as the number of seconds that a flow set up by the +secure channel will remain in the switch's flow table without any +matching packets being seen. If \fBpermanent\fR is specified, which +is not recommended, flows set up by the secure channel will never +expire. The default is 15 seconds. + +Most flows are set up by the OpenFlow controller, not by the secure +channel. This option affects only the following flows, which the +secure channel sets up itself: + +.RS +.IP \(bu +When \fB--fail=open\fR is specified, flows set up when the secure +channel has not been able to contact the controller for the configured +fail-open delay. + +.IP \(bu +When in-band control is in use, flows set up to bootstrap contacting +the controller (see \fBCONTACTING THE CONTROLLER\fR, above, for +more information about in-band control). +.RE + +.IP +As a result, when both \fB--fail=closed\fR and \fB--out-of-band\fR are +specified, this option has no effect. + +.TP +\fB--max-backoff=\fIsecs\fR +Sets the maximum time between attempts to connect to the controller to +\fIsecs\fR, which must be at least 1. The actual interval between +connection attempts starts at 1 second and doubles on each failing +attempt until it reaches the maximum. The default maximum backoff +time is 15 seconds. + +.TP +\fB-l\fR, \fB--listen=\fImethod\fR +Configures the switch to additionally listen for incoming OpenFlow +connections for switch management with \fBdpctl\fR. The \fImethod\fR +must be given as one of the passive OpenFlow connection methods listed +below. This option may be specified multiple times to listen to +multiple connection methods. + +.RS +.TP +\fBpssl:\fR[\fIport\fR] +Listens for SSL connections on \fIport\fR (default: 6633). The +\fB--private-key\fR, \fB--certificate\fR, and \fB--ca-cert\fR options +are mandatory when this form is used. + +.TP +\fBptcp:\fR[\fIport\fR] +Listens for TCP connections on \fIport\fR (default: 6633). + +.TP +\fBpunix:\fIfile\fR +Listens for connections on Unix domain server socket named \fIfile\fR. +.RE + +.TP +\fB-m\fR, \fB--monitor=\fImethod\fR +Configures the switch to additionally listen for incoming OpenFlow +connections for switch monitoring with \fBdpctl\fR's \fBmonitor\fR +command. The \fImethod\fR must be given as one of the passive +OpenFlow connection methods listed above as acceptable for +\fB--listen\fR. + +When \fBdpctl monitor\fR makes a monitoring connection, \fBofprotocol\fR +sends it a copy of every OpenFlow message sent to or received from the +kernel in the normal course of its operations. It does not send a +copy of any messages sent to or from the OpenFlow connection to the +controller. Most of these messages will be seen anyhow, however, +because \fBofprotocol\fR mainly acts as a relay between the controller +and the kernel. \fBofprotocol\fR also does not send a copy of any +messages sent to or from the OpenFlow connection to the controller. +Such messages will typically \fBnot\fR be seen, because \fBofprotocol\fR +maintains a separate connection to the kernel for each management +connection. + +Messages are copied to the monitoring connections on a best-effort +basis. In particular, if the socket buffer of the monitoring +connection fills up, some messages will be lost. + +.TP +\fB--in-band\fR, \fB--out-of-band\fR +Configures \fBofprotocol\fR to operate in in-band or out-of-band control +mode (see \fBCONTACTING THE CONTROLLER\fR above). When neither option +is given, the default is in-band control. + +.TP +\fB--stp\fR, \fB--no-stp\fR +Enable or disable implementation of IEEE 802.1D Spanning Tree Protocol +at the switch. The default is \fB--no-stp\fR in this distribution, +because bugs in the STP implementation are still being worked out. +The default will change to \fB--stp\fR at some point in the future. + +.TP +\fB--emerg-flow\fR +Enable emergecny flow protection and restration at the switch. If emergency +flow enabled, \fBofprotocol\fR will attempt to switch flow table to emergency's +one when a controller connection fails. The default is disabled in this +distribution. + +.SS "Rate-Limiting Options" + +These options configure how the switch applies a ``token bucket'' to +limit the rate at which packets in unknown flows are forwarded to an +OpenFlow controller for flow-setup processing. This feature prevents +a single OpenFlow switch from overwhelming a controller. + +.TP +\fB--rate-limit\fR[\fB=\fIrate\fR] +. +Limits the maximum rate at which packets will be forwarded to the +OpenFlow controller to \fIrate\fR packets per second. If \fIrate\fR +is not specified then the default of 1,000 packets per second is used. + +If \fB--rate-limit\fR is not used, then the switch does not limit the +rate at which packets are forwarded to the controller. + +.TP +\fB--burst-limit=\fIburst\fR +. +Sets the maximum number of unused packet credits that the switch will +allow to accumulate during time in which no packets are being +forwarded to the OpenFlow controller to \fIburst\fR (measured in +packets). The default \fIburst\fR is one-quarter of the \fIrate\fR +specified on \fB--rate-limit\fR. + +This option takes effect only when \fB--rate-limit\fR is also specified. + +.SS "Daemon Options" +.so lib/daemon.man + +.SS "Public Key Infrastructure Options" + +.TP +\fB-p\fR, \fB--private-key=\fIprivkey.pem\fR +Specifies a PEM file containing the private key used as the switch's +identity for SSL connections to the controller. + +.TP +\fB-c\fR, \fB--certificate=\fIcert.pem\fR +Specifies a PEM file containing a certificate, signed by the +controller's certificate authority (CA), that certifies the switch's +private key to identify a trustworthy switch. + +.TP +\fB-C\fR, \fB--ca-cert=\fIcacert.pem\fR +Specifies a PEM file containing the CA certificate used to verify that +the switch is connected to a trustworthy controller. + +.TP +\fB--bootstrap-ca-cert=\fIcacert.pem\fR +When \fIcacert.pem\fR exists, this option has the same effect as +\fB-C\fR or \fB--ca-cert\fR. If it does not exist, then \fBofprotocol\fR +will attempt to obtain the CA certificate from the controller on its +first SSL connection and save it to the named PEM file. If it is +successful, it will immediately drop the connection and reconnect, and +from then on all SSL connections must be authenticated by a +certificate signed by the CA certificate thus obtained. + +\fBThis option exposes the SSL connection to a man-in-the-middle +attack obtaining the initial CA certificate\fR, but it may be useful +for bootstrapping. + +This option is only useful if the controller sends its CA certificate +as part of the SSL certificate chain. The SSL protocol does not +require the controller to send the CA certificate, but +\fBcontroller\fR(8) can be configured to do so with the +\fB--peer-ca-cert\fR option. + +.SS "Logging Options" +.so lib/vlog.man +.SS "Other Options" +.so lib/common.man +.so lib/leak-checker.man + +.SH "SEE ALSO" + +.BR dpctl (8), +.BR ofp-discover (8), +.BR controller (8), +.BR ofp-pki (8), +.BR ofdatapath (8), +.BR vlogconf (8) diff --git a/openflow/secchan/port-watcher.c b/openflow/secchan/port-watcher.c new file mode 100644 index 00000000..0998e161 --- /dev/null +++ b/openflow/secchan/port-watcher.c @@ -0,0 +1,620 @@ +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include "port-watcher.h" +#include +#include +#include +#include +#include "dynamic-string.h" +#include "netdev.h" +#include "ofpbuf.h" +#include "openflow/openflow.h" +#include "poll-loop.h" +#include "port-array.h" +#include "rconn.h" +#include "shash.h" +#include "svec.h" +#include "timeval.h" +#include "vconn.h" +#include "xtoxll.h" + +#define THIS_MODULE VLM_port_watcher +#include "vlog.h" + +struct port_watcher_cb { + port_changed_cb_func *port_changed; + void *aux; +}; + +struct port_watcher_local_cb { + local_port_changed_cb_func *local_port_changed; + void *aux; +}; + +struct port_watcher { + struct rconn *local_rconn; + struct rconn *remote_rconn; + struct port_array ports; + time_t last_feature_request; + bool got_feature_reply; + uint64_t datapath_id; + int n_txq; + struct port_watcher_cb cbs[2]; + int n_cbs; + struct port_watcher_local_cb local_cbs[4]; + int n_local_cbs; + char local_port_name[OFP_MAX_PORT_NAME_LEN + 1]; + struct netdev_monitor *mon; + struct shash port_by_name; +}; + +/* Returns the number of fields that differ from 'a' to 'b'. */ +static int +opp_differs(const struct ofp_phy_port *a, const struct ofp_phy_port *b) +{ + BUILD_ASSERT_DECL(sizeof *a == 48); /* Trips when we add or remove fields. */ + return ((a->port_no != b->port_no) + + (memcmp(a->hw_addr, b->hw_addr, sizeof a->hw_addr) != 0) + + (memcmp(a->name, b->name, sizeof a->name) != 0) + + (a->config != b->config) + + (a->state != b->state) + + (a->curr != b->curr) + + (a->advertised != b->advertised) + + (a->supported != b->supported) + + (a->peer != b->peer)); +} + +static void +sanitize_opp(struct ofp_phy_port *opp) +{ + size_t i; + + for (i = 0; i < sizeof opp->name; i++) { + char c = opp->name[i]; + if (c && (c < 0x20 || c > 0x7e)) { + opp->name[i] = '.'; + } + } + opp->name[sizeof opp->name - 1] = '\0'; +} + +static void +call_port_changed_callbacks(struct port_watcher *pw, int port_no, + const struct ofp_phy_port *old, + const struct ofp_phy_port *new) +{ + int i; + for (i = 0; i < pw->n_cbs; i++) { + port_changed_cb_func *port_changed = pw->cbs[i].port_changed; + (port_changed)(port_no, old, new, pw->cbs[i].aux); + } +} + +void +get_port_name(const struct ofp_phy_port *port, char *name, size_t name_size) +{ + char *p; + + memcpy(name, port->name, MIN(name_size, sizeof port->name)); + name[name_size - 1] = '\0'; + for (p = name; *p != '\0'; p++) { + if (*p < 32 || *p > 126) { + *p = '.'; + } + } +} + +static struct ofp_phy_port * +lookup_port(const struct port_watcher *pw, uint16_t port_no) +{ + return port_array_get(&pw->ports, port_no); +} + +static void +call_local_port_changed_callbacks(struct port_watcher *pw) +{ + char name[OFP_MAX_PORT_NAME_LEN + 1]; + const struct ofp_phy_port *port; + int i; + + /* Pass the local port to the callbacks, if it exists. + Pass a null pointer if there is no local port. */ + port = lookup_port(pw, OFPP_LOCAL); + + /* Log the name of the local port. */ + if (port) { + get_port_name(port, name, sizeof name); + } else { + name[0] = '\0'; + } + if (strcmp(pw->local_port_name, name)) { + if (name[0]) { + VLOG_INFO("Identified data path local port as \"%s\".", name); + } else { + VLOG_WARN("Data path has no local port."); + } + strcpy(pw->local_port_name, name); + } + + /* Invoke callbacks. */ + for (i = 0; i < pw->n_local_cbs; i++) { + local_port_changed_cb_func *cb = pw->local_cbs[i].local_port_changed; + (cb)(port, pw->local_cbs[i].aux); + } +} + +static void +update_phy_port(struct port_watcher *pw, struct ofp_phy_port *opp, + uint8_t reason) +{ + struct ofp_phy_port *old; + uint16_t port_no; + + port_no = ntohs(opp->port_no); + old = lookup_port(pw, port_no); + + if (reason == OFPPR_DELETE && old) { + call_port_changed_callbacks(pw, port_no, old, NULL); + free(old); + port_array_set(&pw->ports, port_no, NULL); + } else if (reason == OFPPR_MODIFY || reason == OFPPR_ADD) { + if (old) { + uint32_t s_mask = htonl(OFPPS_STP_MASK); + opp->state = (opp->state & ~s_mask) | (old->state & s_mask); + } + if (!old || opp_differs(opp, old)) { + struct ofp_phy_port new = *opp; + sanitize_opp(&new); + call_port_changed_callbacks(pw, port_no, old, &new); + if (old) { + *old = new; + } else { + port_array_set(&pw->ports, port_no, xmemdup(&new, sizeof new)); + } + } + } +} + +static void +update_netdev_monitor_devices(struct port_watcher *pw) +{ + struct ofp_phy_port *p; + struct svec netdevs; + unsigned int port_no; + + svec_init(&netdevs); + shash_clear(&pw->port_by_name); + for (p = port_array_first(&pw->ports, &port_no); p; + p = port_array_next(&pw->ports, &port_no)) { + const char *name = (const char *) p->name; + svec_add(&netdevs, name); + shash_add(&pw->port_by_name, name, p); + } + netdev_monitor_set_devices(pw->mon, netdevs.names, netdevs.n); + svec_destroy(&netdevs); +} + +static bool +port_watcher_local_packet_cb(struct relay *r, void *pw_) +{ + struct port_watcher *pw = pw_; + struct ofpbuf *msg = r->halves[HALF_LOCAL].rxbuf; + struct ofp_header *oh = msg->data; + + if (oh->type == OFPT_FEATURES_REPLY + && msg->size >= offsetof(struct ofp_switch_features, ports)) { + struct ofp_switch_features *osf = msg->data; + bool seen[PORT_ARRAY_SIZE]; + struct ofp_phy_port *p; + unsigned int port_no; + size_t n_ports; + size_t i; + + pw->got_feature_reply = true; + if (pw->datapath_id != osf->datapath_id) { + pw->datapath_id = osf->datapath_id; + VLOG_INFO("Datapath id is %012"PRIx64, ntohll(pw->datapath_id)); + } + + /* Update each port included in the message. */ + memset(seen, false, sizeof seen); + n_ports = ((msg->size - offsetof(struct ofp_switch_features, ports)) + / sizeof *osf->ports); + for (i = 0; i < n_ports; i++) { + struct ofp_phy_port *opp = &osf->ports[i]; + update_phy_port(pw, opp, OFPPR_MODIFY); + seen[ntohs(opp->port_no)] = true; + } + + /* Delete all the ports not included in the message. */ + for (p = port_array_first(&pw->ports, &port_no); p; + p = port_array_next(&pw->ports, &port_no)) { + if (!seen[port_no]) { + update_phy_port(pw, p, OFPPR_DELETE); + } + } + + update_netdev_monitor_devices(pw); + + call_local_port_changed_callbacks(pw); + } else if (oh->type == OFPT_PORT_STATUS + && msg->size >= sizeof(struct ofp_port_status)) { + struct ofp_port_status *ops = msg->data; + update_phy_port(pw, &ops->desc, ops->reason); + if (ops->desc.port_no == htons(OFPP_LOCAL)) { + call_local_port_changed_callbacks(pw); + } + if (ops->reason == OFPPR_ADD || OFPPR_DELETE) { + update_netdev_monitor_devices(pw); + } + } + return false; +} + +static void +bring_netdev_up_or_down(const char *name, bool down) +{ + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + struct netdev *netdev; + int retval; + + retval = netdev_open(name, NETDEV_ETH_TYPE_NONE, &netdev); + if (!retval) { + if (down) { + retval = netdev_turn_flags_off(netdev, NETDEV_UP, true); + } else { + retval = netdev_turn_flags_on(netdev, NETDEV_UP, true); + } + if (retval) { + VLOG_WARN_RL(&rl, "failed to bring network device %s %s: %s", + name, down ? "down" : "up", strerror(retval)); + } + netdev_close(netdev); + } else { + VLOG_WARN_RL(&rl, "failed to open network device %s: %s", + name, strerror(retval)); + } +} + +static bool +port_watcher_remote_packet_cb(struct relay *r, void *pw_) +{ + struct port_watcher *pw = pw_; + struct ofpbuf *msg = r->halves[HALF_REMOTE].rxbuf; + struct ofp_header *oh = msg->data; + + if (oh->type == OFPT_PORT_MOD + && msg->size >= sizeof(struct ofp_port_mod)) { + struct ofp_port_mod *opm = msg->data; + uint16_t port_no = ntohs(opm->port_no); + struct ofp_phy_port *pw_opp = lookup_port(pw, port_no); + if (pw_opp->port_no != htons(OFPP_NONE)) { + struct ofp_phy_port old = *pw_opp; + pw_opp->config = ((pw_opp->config & ~opm->mask) + | (opm->config & opm->mask)); + call_port_changed_callbacks(pw, port_no, &old, pw_opp); + if (pw_opp->port_no == htons(OFPP_LOCAL)) { + call_local_port_changed_callbacks(pw); + } + + if (opm->mask & htonl(OFPPC_PORT_DOWN)) { + bring_netdev_up_or_down((const char *) pw_opp->name, + opm->config & htonl(OFPPC_PORT_DOWN)); + } + } + } + return false; +} + +/* Sets 'bit' in '*word' to 0 or 1 according to 'value'. */ +static void +set_bit(uint32_t bit, bool value, uint32_t *word) +{ + if (value) { + *word |= bit; + } else { + *word &= ~bit; + } +} + +static void +port_watcher_periodic_cb(void *pw_) +{ + struct port_watcher *pw = pw_; + const char *name; + + if (!pw->got_feature_reply + && time_now() >= pw->last_feature_request + 5 + && rconn_is_connected(pw->local_rconn)) { + struct ofpbuf *b; + make_openflow(sizeof(struct ofp_header), OFPT_FEATURES_REQUEST, &b); + rconn_send_with_limit(pw->local_rconn, b, &pw->n_txq, 1); + pw->last_feature_request = time_now(); + } + + netdev_monitor_run(pw->mon); + while ((name = netdev_monitor_poll(pw->mon)) != NULL) { + struct ofp_phy_port *opp; + struct ofp_phy_port new_opp; + enum netdev_flags flags; + int retval; + + opp = shash_find_data(&pw->port_by_name, name); + if (!opp) { + continue; + } + + retval = netdev_nodev_get_flags(name, &flags); + if (retval) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_WARN_RL(&rl, "could not get flags for %s", name); + continue; + } + + new_opp = *opp; + set_bit(htonl(OFPPC_PORT_DOWN), ~flags & NETDEV_UP, &new_opp.config); + set_bit(htonl(OFPPS_LINK_DOWN), ~flags & NETDEV_CARRIER, + &new_opp.state); + if (opp->config != new_opp.config || opp->state != new_opp.state) { + struct ofp_port_status *ops; + struct ofpbuf *b; + + /* Notify other secchan modules. */ + update_phy_port(pw, &new_opp, OFPPR_MODIFY); + if (new_opp.port_no == htons(OFPP_LOCAL)) { + call_local_port_changed_callbacks(pw); + } + + /* Notify the controller that the flags changed. */ + ops = make_openflow(sizeof *ops, OFPT_PORT_STATUS, &b); + ops->reason = OFPPR_MODIFY; + ops->desc = new_opp; + rconn_send(pw->remote_rconn, b, NULL); + } + } +} + +static void +port_watcher_wait_cb(void *pw_) +{ + struct port_watcher *pw = pw_; + if (!pw->got_feature_reply && rconn_is_connected(pw->local_rconn)) { + if (pw->last_feature_request != TIME_MIN) { + poll_timer_wait(pw->last_feature_request + 5 - time_now()); + } else { + poll_immediate_wake(); + } + } + netdev_monitor_wait(pw->mon); +} + +static void +put_duplexes(struct ds *ds, const char *name, uint32_t features, + uint32_t hd_bit, uint32_t fd_bit) +{ + if (features & (hd_bit | fd_bit)) { + ds_put_format(ds, " %s", name); + if (features & hd_bit) { + ds_put_cstr(ds, "(HD)"); + } + if (features & fd_bit) { + ds_put_cstr(ds, "(FD)"); + } + } +} + +static void +put_features(struct ds *ds, const char *name, uint32_t features) +{ + if (features & (OFPPF_10MB_HD | OFPPF_10MB_FD + | OFPPF_100MB_HD | OFPPF_100MB_FD + | OFPPF_1GB_HD | OFPPF_1GB_FD | OFPPF_10GB_FD)) { + ds_put_cstr(ds, name); + put_duplexes(ds, "10M", features, OFPPF_10MB_HD, OFPPF_10MB_FD); + put_duplexes(ds, "100M", features, + OFPPF_100MB_HD, OFPPF_100MB_FD); + put_duplexes(ds, "1G", features, OFPPF_1GB_HD, OFPPF_1GB_FD); + if (features & OFPPF_10GB_FD) { + ds_put_cstr(ds, " 10G"); + } + if (features & OFPPF_AUTONEG) { + ds_put_cstr(ds, " AUTO_NEG"); + } + if (features & OFPPF_PAUSE) { + ds_put_cstr(ds, " PAUSE"); + } + if (features & OFPPF_PAUSE_ASYM) { + ds_put_cstr(ds, " PAUSE_ASYM"); + } + } +} + +static void +log_port_status(uint16_t port_no, + const struct ofp_phy_port *old, + const struct ofp_phy_port *new, + void *aux UNUSED) +{ + if (VLOG_IS_DBG_ENABLED()) { + if (old && new && (opp_differs(old, new) + == ((old->config != new->config) + + (old->state != new->state)))) + { + /* Don't care if only state or config changed. */ + } else if (!new) { + if (old) { + VLOG_DBG("Port %d deleted", port_no); + } + } else { + struct ds ds = DS_EMPTY_INITIALIZER; + uint32_t curr = ntohl(new->curr); + uint32_t supported = ntohl(new->supported); + ds_put_format(&ds, "\"%s\", "ETH_ADDR_FMT, new->name, + ETH_ADDR_ARGS(new->hw_addr)); + if (curr) { + put_features(&ds, ", current", curr); + } + if (supported) { + put_features(&ds, ", supports", supported); + } + VLOG_DBG("Port %d %s: %s", + port_no, old ? "changed" : "added", ds_cstr(&ds)); + ds_destroy(&ds); + } + } +} + +void +port_watcher_register_callback(struct port_watcher *pw, + port_changed_cb_func *port_changed, + void *aux) +{ + assert(pw->n_cbs < ARRAY_SIZE(pw->cbs)); + pw->cbs[pw->n_cbs].port_changed = port_changed; + pw->cbs[pw->n_cbs].aux = aux; + pw->n_cbs++; +} + +void +port_watcher_register_local_port_callback(struct port_watcher *pw, + local_port_changed_cb_func *cb, + void *aux) +{ + assert(pw->n_local_cbs < ARRAY_SIZE(pw->local_cbs)); + pw->local_cbs[pw->n_local_cbs].local_port_changed = cb; + pw->local_cbs[pw->n_local_cbs].aux = aux; + pw->n_local_cbs++; +} + +uint32_t +port_watcher_get_config(const struct port_watcher *pw, uint16_t port_no) +{ + struct ofp_phy_port *p = lookup_port(pw, port_no); + return p ? ntohl(p->config) : 0; +} + +const char * +port_watcher_get_name(const struct port_watcher *pw, uint16_t port_no) +{ + struct ofp_phy_port *p = lookup_port(pw, port_no); + return p ? (const char *) p->name : NULL; +} + +const uint8_t * +port_watcher_get_hwaddr(const struct port_watcher *pw, uint16_t port_no) +{ + struct ofp_phy_port *p = lookup_port(pw, port_no); + return p ? p->hw_addr : NULL; +} + +void +port_watcher_set_flags(struct port_watcher *pw, uint16_t port_no, + uint32_t config, uint32_t c_mask, + uint32_t state, uint32_t s_mask) +{ + struct ofp_phy_port old; + struct ofp_phy_port *p; + struct ofp_port_mod *opm; + struct ofp_port_status *ops; + struct ofpbuf *b; + + p = lookup_port(pw, port_no); + if (!p) { + return; + } + + if (!((ntohl(p->state) ^ state) & s_mask) + && (!((ntohl(p->config) ^ config) & c_mask))) { + return; + } + old = *p; + + /* Update our idea of the flags. */ + p->config = htonl((ntohl(p->config) & ~c_mask) | (config & c_mask)); + p->state = htonl((ntohl(p->state) & ~s_mask) | (state & s_mask)); + call_port_changed_callbacks(pw, port_no, &old, p); + + /* Change the flags in the datapath. */ + opm = make_openflow(sizeof *opm, OFPT_PORT_MOD, &b); + opm->port_no = p->port_no; + memcpy(opm->hw_addr, p->hw_addr, OFP_ETH_ALEN); + opm->config = p->config; + opm->mask = htonl(c_mask); + opm->advertise = htonl(0); + rconn_send(pw->local_rconn, b, NULL); + + /* Notify the controller that the flags changed. */ + ops = make_openflow(sizeof *ops, OFPT_PORT_STATUS, &b); + ops->reason = OFPPR_MODIFY; + ops->desc = *p; + rconn_send(pw->remote_rconn, b, NULL); +} + +bool +port_watcher_is_ready(const struct port_watcher *pw) +{ + return pw->got_feature_reply; +} + +static struct hook_class port_watcher_hook_class = { + port_watcher_local_packet_cb, /* local_packet_cb */ + port_watcher_remote_packet_cb, /* remote_packet_cb */ + port_watcher_periodic_cb, /* periodic_cb */ + port_watcher_wait_cb, /* wait_cb */ + NULL, /* closing_cb */ +}; + +void +port_watcher_start(struct secchan *secchan, + struct rconn *local_rconn, struct rconn *remote_rconn, + struct port_watcher **pwp) +{ + struct port_watcher *pw; + int retval; + + pw = *pwp = xcalloc(1, sizeof *pw); + pw->local_rconn = local_rconn; + pw->remote_rconn = remote_rconn; + pw->last_feature_request = TIME_MIN; + port_array_init(&pw->ports); + pw->local_port_name[0] = '\0'; + retval = netdev_monitor_create(&pw->mon); + if (retval) { + ofp_fatal(retval, "failed to start network device monitoring"); + } + shash_init(&pw->port_by_name); + port_watcher_register_callback(pw, log_port_status, NULL); + add_hook(secchan, &port_watcher_hook_class, pw); +} diff --git a/openflow/secchan/port-watcher.h b/openflow/secchan/port-watcher.h new file mode 100644 index 00000000..904e545a --- /dev/null +++ b/openflow/secchan/port-watcher.h @@ -0,0 +1,77 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#ifndef PORT_WATCHER_H +#define PORT_WATCHER_H 1 + +#include +#include "compiler.h" +#include "secchan.h" + +struct ofp_phy_port; +struct port_watcher; +struct secchan; + +void port_watcher_start(struct secchan *, + struct rconn *local, struct rconn *remote, + struct port_watcher **); +bool port_watcher_is_ready(const struct port_watcher *); +uint32_t port_watcher_get_config(const struct port_watcher *, + uint16_t port_no); +const char *port_watcher_get_name(const struct port_watcher *, + uint16_t port_no) UNUSED; +const uint8_t *port_watcher_get_hwaddr(const struct port_watcher *, + uint16_t port_no); +void port_watcher_set_flags(struct port_watcher *, uint16_t port_no, + uint32_t config, uint32_t c_mask, + uint32_t state, uint32_t s_mask); + +typedef void port_changed_cb_func(uint16_t port_no, + const struct ofp_phy_port *old, + const struct ofp_phy_port *new, + void *aux); + +void port_watcher_register_callback(struct port_watcher *, + port_changed_cb_func *port_changed, + void *aux); + +typedef void local_port_changed_cb_func(const struct ofp_phy_port *new, + void *aux); + +void port_watcher_register_local_port_callback(struct port_watcher *pw, + local_port_changed_cb_func *cb, + void *aux); + +void get_port_name(const struct ofp_phy_port *, char *name, size_t name_size); + +#endif /* port-watcher.h */ diff --git a/openflow/secchan/protocol-stat.c b/openflow/secchan/protocol-stat.c new file mode 100644 index 00000000..d54548b3 --- /dev/null +++ b/openflow/secchan/protocol-stat.c @@ -0,0 +1,204 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#include +#include +#include +#include +#include +#include + +#include "openflow/openflow.h" +#include "openflow/private-ext.h" + +#include "ofpbuf.h" +#include "util.h" +#include "xtoxll.h" +#include "rconn.h" +#include "vconn.h" +#include "secchan.h" +#include "status.h" +#include "timeval.h" +#include "sat-math.h" +#include "ofpstat.h" +#include "protocol-stat.h" +#define THIS_MODULE VLM_protocol_stat +#include "vlog.h" + +#define COPY_OFPS(dst_ofps, src_ofps, tag) \ +do { \ + (dst_ofps)->tag = htonll((src_ofps)->tag); \ +} while (0) + +#define COPY_OFP_STAT(dst_ofps, src_ofps) \ +do { \ + COPY_OFPS(dst_ofps, src_ofps, ofps_total); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_unknown); \ + \ + COPY_OFPS(dst_ofps, src_ofps, ofps_hello); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_echo_request); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_echo_reply); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_vendor); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_feats_request); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_feats_reply); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_get_config_request); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_get_config_reply); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_set_config); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_packet_in); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_flow_removed); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_port_status); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_packet_out); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_flow_mod); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_port_mod); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_stats_request); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_stats_reply); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_barrier_request); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_barrier_reply); \ + \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_type.hello_fail); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_type.bad_request); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_type.bad_action); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_type.flow_mod_fail); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_type.unknown); \ + \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.hf_incompat); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.hf_eperm); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.br_bad_version); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.br_bad_type); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.br_bad_stat); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.br_bad_vendor); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.br_eperm); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.ba_bad_type); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.ba_bad_len); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.ba_bad_vendor); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.ba_bad_vendor_type); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.ba_bad_out_port); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.ba_eperm); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.fmf_all_tables_full); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.fmf_overlap); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.fmf_eperm); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.unknown); \ + \ + COPY_OFPS(dst_ofps, src_ofps, ofps_flow_mod_ops.add); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_flow_mod_ops.modify); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_flow_mod_ops.delete); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_flow_mod_ops.delete_strict); \ + COPY_OFPS(dst_ofps, src_ofps, ofps_flow_mod_ops.unknown); \ +} while (0) + +struct protocol_stat_context { + const struct settings *settings; + const struct secchan *secchan; + struct rconn *local_rconn; + struct rconn *remote_rconn; + struct ofpstat ofps_rcvd; + struct ofpstat ofps_sent; +}; + +static bool protocol_stat_remote_packet_cb(struct relay *, void *); + +static bool +protocol_stat_remote_packet_cb(struct relay *relay, void *context_) +{ + struct protocol_stat_context *context = context_; + struct rconn *mgmt_rconn = relay->halves[HALF_REMOTE].rconn; + struct ofpbuf *qbuf = relay->halves[HALF_REMOTE].rxbuf; + struct ofpbuf *pbuf = NULL; + struct private_vxhdr *qvxhdr = NULL; + struct private_vxhdr *pvxhdr = NULL; + struct private_vxopt *qvxopt = NULL; + struct private_vxopt *pvxopt = NULL; + struct ofpstat *ofps = NULL; + struct ofpstat ofps_rcvd; + struct ofpstat ofps_sent; + int error = 0; + + if (qbuf->size < sizeof(*qvxhdr)) + return false; + qvxhdr = qbuf->data; + if (qvxhdr->ofp_hdr.type != OFPT_VENDOR) + return false; + if (ntohl(qvxhdr->ofp_vxid) != PRIVATE_VENDOR_ID) { + return false; + } + qvxopt = (struct private_vxopt *)(qvxhdr + 1); + if (ntohs(qvxopt->pvo_type) != PRIVATEOPT_PROTOCOL_STATS_REQUEST) { + return true; + } + + pvxhdr = make_openflow_xid(sizeof(*pvxhdr) + sizeof(*pvxopt) + + (sizeof(*ofps) * 2), + OFPT_VENDOR, qvxhdr->ofp_hdr.xid, &pbuf); + pvxopt = (struct private_vxopt *)(pvxhdr + 1); + pvxhdr->ofp_vxid = qvxhdr->ofp_vxid; + pvxopt->pvo_type = htons(PRIVATEOPT_PROTOCOL_STATS_REPLY); + pvxopt->pvo_len = htons(sizeof(*ofps) * 2); + + rconn_update_protocol_stat(context->remote_rconn, + &ofps_rcvd, &ofps_sent); + ofps = (struct ofpstat *)((uint8_t *)(pvxhdr + 1) + sizeof(*pvxopt)); + COPY_OFP_STAT(ofps, &ofps_rcvd); + ofps = ofps + 1; + COPY_OFP_STAT(ofps, &ofps_sent); + + error = rconn_send(mgmt_rconn, pbuf, NULL); + if (error && error != EAGAIN) { + VLOG_WARN("send failed (%s)", strerror(error)); + } + + return true; +} + +void +protocol_stat_start(struct secchan *secchan, const struct settings *settings, + struct rconn *local_rconn, struct rconn *remote_rconn) +{ + struct protocol_stat_context *context = NULL; + static struct hook_class protocol_stat_hook_class = { + NULL, /* local_packet_cb */ + protocol_stat_remote_packet_cb, /* remote_packet_cb */ + NULL, /* periodic_cb */ + NULL, /* wait_cb */ + NULL, /* closing_cb */ + }; + + context = xmalloc(sizeof(*context)); + context->settings = settings; + context->secchan = secchan; + context->local_rconn = local_rconn; + context->remote_rconn = remote_rconn; + memset(&context->ofps_rcvd, 0, sizeof(context->ofps_rcvd)); + memset(&context->ofps_sent, 0, sizeof(context->ofps_sent)); + + add_hook(secchan, &protocol_stat_hook_class, context); +} diff --git a/openflow/secchan/protocol-stat.h b/openflow/secchan/protocol-stat.h new file mode 100644 index 00000000..3037b449 --- /dev/null +++ b/openflow/secchan/protocol-stat.h @@ -0,0 +1,44 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#ifndef PROTOCOL_STAT_H_ +#define PROTOCOL_STAT_H_ + +struct rconn; +struct secchan; +struct settings; +struct switch_status; + +void protocol_stat_start(struct secchan *, const struct settings *, + struct rconn *, struct rconn *); + +#endif diff --git a/openflow/secchan/ratelimit.c b/openflow/secchan/ratelimit.c new file mode 100644 index 00000000..7a1e4951 --- /dev/null +++ b/openflow/secchan/ratelimit.c @@ -0,0 +1,263 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include "ratelimit.h" +#include +#include +#include "ofpbuf.h" +#include "openflow/openflow.h" +#include "poll-loop.h" +#include "queue.h" +#include "rconn.h" +#include "secchan.h" +#include "status.h" +#include "timeval.h" +#include "vconn.h" + +struct rate_limiter { + const struct settings *s; + struct rconn *remote_rconn; + + /* One queue per physical port. */ + struct ofp_queue queues[OFPP_MAX]; + int n_queued; /* Sum over queues[*].n. */ + int next_tx_port; /* Next port to check in round-robin. */ + + /* Token bucket. + * + * It costs 1000 tokens to send a single packet_in message. A single token + * per message would be more straightforward, but this choice lets us avoid + * round-off error in refill_bucket()'s calculation of how many tokens to + * add to the bucket, since no division step is needed. */ + long long int last_fill; /* Time at which we last added tokens. */ + int tokens; /* Current number of tokens. */ + + /* Transmission queue. */ + int n_txq; /* No. of packets waiting in rconn for tx. */ + + /* Statistics reporting. */ + unsigned long long n_normal; /* # txed w/o rate limit queuing. */ + unsigned long long n_limited; /* # queued for rate limiting. */ + unsigned long long n_queue_dropped; /* # dropped due to queue overflow. */ + unsigned long long n_tx_dropped; /* # dropped due to tx overflow. */ +}; + +/* Drop a packet from the longest queue in 'rl'. */ +static void +drop_packet(struct rate_limiter *rl) +{ + struct ofp_queue *longest; /* Queue currently selected as longest. */ + int n_longest; /* # of queues of same length as 'longest'. */ + struct ofp_queue *q; + + longest = &rl->queues[0]; + n_longest = 1; + for (q = &rl->queues[0]; q < &rl->queues[OFPP_MAX]; q++) { + if (longest->n < q->n) { + longest = q; + n_longest = 1; + } else if (longest->n == q->n) { + n_longest++; + + /* Randomly select one of the longest queues, with a uniform + * distribution (Knuth algorithm 3.4.2R). */ + if (!random_range(n_longest)) { + longest = q; + } + } + } + + /* FIXME: do we want to pop the tail instead? */ + ofpbuf_delete(queue_pop_head(longest)); + rl->n_queued--; +} + +/* Remove and return the next packet to transmit (in round-robin order). */ +static struct ofpbuf * +dequeue_packet(struct rate_limiter *rl) +{ + unsigned int i; + + for (i = 0; i < OFPP_MAX; i++) { + unsigned int port = (rl->next_tx_port + i) % OFPP_MAX; + struct ofp_queue *q = &rl->queues[port]; + if (q->n) { + rl->next_tx_port = (port + 1) % OFPP_MAX; + rl->n_queued--; + return queue_pop_head(q); + } + } + NOT_REACHED(); +} + +/* Add tokens to the bucket based on elapsed time. */ +static void +refill_bucket(struct rate_limiter *rl) +{ + const struct settings *s = rl->s; + long long int now = time_msec(); + long long int tokens = (now - rl->last_fill) * s->rate_limit + rl->tokens; + if (tokens >= 1000) { + rl->last_fill = now; + rl->tokens = MIN(tokens, s->burst_limit * 1000); + } +} + +/* Attempts to remove enough tokens from 'rl' to transmit a packet. Returns + * true if successful, false otherwise. (In the latter case no tokens are + * removed.) */ +static bool +get_token(struct rate_limiter *rl) +{ + if (rl->tokens >= 1000) { + rl->tokens -= 1000; + return true; + } else { + return false; + } +} + +static bool +rate_limit_local_packet_cb(struct relay *r, void *rl_) +{ + struct rate_limiter *rl = rl_; + const struct settings *s = rl->s; + struct ofp_packet_in *opi; + + opi = get_ofp_packet_in(r); + if (!opi) { + return false; + } + + if (opi->reason == OFPR_ACTION) { + /* Don't rate-limit 'ofp-packet_in's generated by flows that the + * controller set up. XXX we should really just rate-limit them + * *separately* so that no one can flood the controller this way. */ + return false; + } + + if (!rl->n_queued && get_token(rl)) { + /* In the common case where we are not constrained by the rate limit, + * let the packet take the normal path. */ + rl->n_normal++; + return false; + } else { + /* Otherwise queue it up for the periodic callback to drain out. */ + struct ofpbuf *msg = r->halves[HALF_LOCAL].rxbuf; + int port = ntohs(opi->in_port) % OFPP_MAX; + if (rl->n_queued >= s->burst_limit) { + drop_packet(rl); + } + queue_push_tail(&rl->queues[port], ofpbuf_clone(msg)); + rl->n_queued++; + rl->n_limited++; + return true; + } +} + +static void +rate_limit_status_cb(struct status_reply *sr, void *rl_) +{ + struct rate_limiter *rl = rl_; + + status_reply_put(sr, "normal=%llu", rl->n_normal); + status_reply_put(sr, "limited=%llu", rl->n_limited); + status_reply_put(sr, "queue-dropped=%llu", rl->n_queue_dropped); + status_reply_put(sr, "tx-dropped=%llu", rl->n_tx_dropped); +} + +static void +rate_limit_periodic_cb(void *rl_) +{ + struct rate_limiter *rl = rl_; + int i; + + /* Drain some packets out of the bucket if possible, but limit the number + * of iterations to allow other code to get work done too. */ + refill_bucket(rl); + for (i = 0; rl->n_queued && get_token(rl) && i < 50; i++) { + /* Use a small, arbitrary limit for the amount of queuing to do here, + * because the TCP connection is responsible for buffering and there is + * no point in trying to transmit faster than the TCP connection can + * handle. */ + struct ofpbuf *b = dequeue_packet(rl); + if (rconn_send_with_limit(rl->remote_rconn, b, &rl->n_txq, 10)) { + rl->n_tx_dropped++; + } + } +} + +static void +rate_limit_wait_cb(void *rl_) +{ + struct rate_limiter *rl = rl_; + if (rl->n_queued) { + if (rl->tokens >= 1000) { + /* We can transmit more packets as soon as we're called again. */ + poll_immediate_wake(); + } else { + /* We have to wait for the bucket to re-fill. We could calculate + * the exact amount of time here for increased smoothness. */ + poll_timer_wait(TIME_UPDATE_INTERVAL / 2); + } + } +} + +static struct hook_class rate_limit_hook_class = { + rate_limit_local_packet_cb, /* local_packet_cb */ + NULL, /* remote_packet_cb */ + rate_limit_periodic_cb, /* periodic_cb */ + rate_limit_wait_cb, /* wait_cb */ + NULL, /* closing_cb */ +}; + +void +rate_limit_start(struct secchan *secchan, const struct settings *s, + struct switch_status *ss, struct rconn *remote) +{ + struct rate_limiter *rl; + size_t i; + + rl = xcalloc(1, sizeof *rl); + rl->s = s; + rl->remote_rconn = remote; + for (i = 0; i < ARRAY_SIZE(rl->queues); i++) { + queue_init(&rl->queues[i]); + } + rl->last_fill = time_msec(); + rl->tokens = s->rate_limit * 100; + switch_status_register_category(ss, "rate-limit", + rate_limit_status_cb, rl); + add_hook(secchan, &rate_limit_hook_class, rl); +} diff --git a/openflow/secchan/ratelimit.h b/openflow/secchan/ratelimit.h new file mode 100644 index 00000000..25ab9777 --- /dev/null +++ b/openflow/secchan/ratelimit.h @@ -0,0 +1,45 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#ifndef RATELIMIT_H +#define RATELIMIT_H 1 + +struct rconn; +struct secchan; +struct settings; +struct switch_status; + +void rate_limit_start(struct secchan *, const struct settings *, + struct switch_status *, struct rconn *remote); + +#endif /* ratelimit.h */ diff --git a/openflow/secchan/secchan.c b/openflow/secchan/secchan.c new file mode 100644 index 00000000..15c7b696 --- /dev/null +++ b/openflow/secchan/secchan.c @@ -0,0 +1,882 @@ +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include "secchan.h" +#include +#include +#include +#include +#include +#include +#include + +#include "command-line.h" +#include "compiler.h" +#include "daemon.h" +#include "dirs.h" +#include "discovery.h" +#include "emerg-flow.h" +#include "fail-open.h" +#include "failover.h" +#include "fault.h" +#include "in-band.h" +#include "leak-checker.h" +#include "list.h" +#include "ofpbuf.h" +#include "openflow/openflow.h" +#include "packets.h" +#include "protocol-stat.h" +#include "port-watcher.h" +#include "poll-loop.h" +#include "ratelimit.h" +#include "rconn.h" +#include "stp-secchan.h" +#include "status.h" +#include "timeval.h" +#include "util.h" +#include "vconn-ssl.h" +#include "vconn.h" +#include "vlog-socket.h" + +#include "vlog.h" +#define THIS_MODULE VLM_secchan + +struct hook { + const struct hook_class *class; + void *aux; +}; + +struct secchan { + struct hook *hooks; + size_t n_hooks, allocated_hooks; +}; + +static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60); + +static void parse_options(int argc, char *argv[], struct settings *); +static void usage(void) NO_RETURN; + +static char *vconn_name_without_subscription(const char *); +static struct pvconn *open_passive_vconn(const char *name); +static struct vconn *accept_vconn(struct pvconn *pvconn); + +static struct relay *relay_create(struct rconn *async, + struct rconn *local, struct rconn *remote, + bool is_mgmt_conn); +static struct relay *relay_accept(const struct settings *, struct pvconn *); +static void relay_run(struct relay *, struct secchan *); +static void relay_wait(struct relay *); +static void relay_destroy(struct relay *); + +int +main(int argc, char *argv[]) +{ + struct settings s; + + struct list relays = LIST_INITIALIZER(&relays); + + struct secchan secchan; + + struct pvconn *monitor; + + struct pvconn *listeners[MAX_MGMT]; + size_t n_listeners; + + char *local_rconn_name; + struct rconn *async_rconn, *local_rconn, *remote_rconn; + struct relay *controller_relay; + struct discovery *discovery; + struct switch_status *switch_status; + struct port_watcher *pw; + int i; + int retval; + + set_program_name(argv[0]); + register_fault_handlers(); + time_init(); + vlog_init(); + parse_options(argc, argv, &s); + signal(SIGPIPE, SIG_IGN); + + secchan.hooks = NULL; + secchan.n_hooks = 0; + secchan.allocated_hooks = 0; + + /* Start listening for management and monitoring connections. */ + n_listeners = 0; + for (i = 0; i < s.n_listeners; i++) { + listeners[n_listeners++] = open_passive_vconn(s.listener_names[i]); + } + monitor = s.monitor_name ? open_passive_vconn(s.monitor_name) : NULL; + + /* Initialize switch status hook. */ + switch_status_start(&secchan, &s, &switch_status); + + die_if_already_running(); + daemonize(); + + /* Start listening for vlogconf requests. */ + retval = vlog_server_listen(NULL, NULL); + if (retval) { + ofp_fatal(retval, "Could not listen for vlog connections"); + } + + VLOG_INFO("OpenFlow reference implementation version %s", VERSION BUILDNR); + VLOG_INFO("OpenFlow protocol version 0x%02x", OFP_VERSION); + + /* Check datapath name, to try to catch command-line invocation errors. */ + if (strncmp(s.dp_name, "nl:", 3) && strncmp(s.dp_name, "unix:", 5) + && !s.controller_names[0]) { + VLOG_WARN("Controller not specified and datapath is not nl: or " + "unix:. (Did you forget to specify the datapath?)"); + } + + if (!strncmp(s.dp_name, "nl:", 3)) { + /* Connect to datapath with a subscription for asynchronous events. By + * separating the connection for asynchronous events from that for + * request and replies we prevent the socket receive buffer from being + * filled up by received packet data, which in turn would prevent + * getting replies to any Netlink messages we send to the kernel. */ + async_rconn = rconn_create(0, s.max_backoff); + rconn_connect(async_rconn, s.dp_name); + switch_status_register_category(switch_status, "async", + rconn_status_cb, async_rconn); + } else { + /* No need for a separate asynchronous connection: we must be connected + * to the user datapath, which is smart enough to discard packet events + * instead of message replies. In fact, having a second connection + * would work against us since we'd get double copies of asynchronous + * event messages (the user datapath provides no way to turn off + * asynchronous events). */ + async_rconn = NULL; + } + + /* Connect to datapath without a subscription, for requests and replies. */ + local_rconn_name = vconn_name_without_subscription(s.dp_name); + local_rconn = rconn_create(0, s.max_backoff); + rconn_connect(local_rconn, local_rconn_name); + free(local_rconn_name); + switch_status_register_category(switch_status, "local", + rconn_status_cb, local_rconn); + + /* Connect to controller. */ + remote_rconn = rconn_create(s.probe_interval, s.max_backoff); + if (s.controller_names[0]) { + retval = rconn_connect(remote_rconn, s.controller_names[0]); + if (retval == EAFNOSUPPORT) { + ofp_fatal(0, "No support for %s vconn", s.controller_names[0]); + } + } + switch_status_register_category(switch_status, "remote", + rconn_status_cb, remote_rconn); + + /* Start relaying. */ + controller_relay = relay_create(async_rconn, local_rconn, remote_rconn, + false); + list_push_back(&relays, &controller_relay->node); + + /* Set up hooks. */ + port_watcher_start(&secchan, local_rconn, remote_rconn, &pw); + discovery = s.discovery ? discovery_init(&s, pw, switch_status) : NULL; + if (s.enable_stp) { + stp_start(&secchan, pw, local_rconn, remote_rconn); + } + if (s.in_band) { + in_band_start(&secchan, &s, switch_status, pw, remote_rconn); + } + if (s.fail_mode == FAIL_OPEN) { + fail_open_start(&secchan, &s, switch_status, + local_rconn, remote_rconn); + } + if (s.num_controllers > 1) { + failover_start(&secchan, &s, switch_status, remote_rconn); + } + if (s.n_listeners > 0) { + protocol_stat_start(&secchan, &s, local_rconn, remote_rconn); + } + if (s.rate_limit) { + rate_limit_start(&secchan, &s, switch_status, remote_rconn); + } + if (s.emerg_flow) { + emerg_flow_start(&secchan, &s, switch_status, local_rconn, remote_rconn); + } + + while (s.discovery || rconn_is_alive(remote_rconn)) { + struct relay *r, *n; + size_t i; + + /* Do work. */ + LIST_FOR_EACH_SAFE (r, n, struct relay, node, &relays) { + relay_run(r, &secchan); + } + for (i = 0; i < n_listeners; i++) { + for (;;) { + struct relay *r = relay_accept(&s, listeners[i]); + if (!r) { + break; + } + list_push_back(&relays, &r->node); + } + } + if (monitor) { + struct vconn *new = accept_vconn(monitor); + if (new) { + /* XXX should monitor async_rconn too but rconn_add_monitor() + * takes ownership of the vconn passed in. */ + rconn_add_monitor(local_rconn, new); + } + } + for (i = 0; i < secchan.n_hooks; i++) { + if (secchan.hooks[i].class->periodic_cb) { + secchan.hooks[i].class->periodic_cb(secchan.hooks[i].aux); + } + } + if (s.discovery) { + char *controller_name; + if (rconn_is_connectivity_questionable(remote_rconn)) { + discovery_question_connectivity(discovery); + } + if (discovery_run(discovery, &controller_name)) { + if (controller_name) { + rconn_connect(remote_rconn, controller_name); + } else { + rconn_disconnect(remote_rconn); + } + } + } + + /* Wait for something to happen. */ + LIST_FOR_EACH (r, struct relay, node, &relays) { + relay_wait(r); + } + for (i = 0; i < n_listeners; i++) { + pvconn_wait(listeners[i]); + } + if (monitor) { + pvconn_wait(monitor); + } + for (i = 0; i < secchan.n_hooks; i++) { + if (secchan.hooks[i].class->wait_cb) { + secchan.hooks[i].class->wait_cb(secchan.hooks[i].aux); + } + } + if (discovery) { + discovery_wait(discovery); + } + poll_block(); + } + + return 0; +} + +static struct pvconn * +open_passive_vconn(const char *name) +{ + struct pvconn *pvconn; + int retval; + + retval = pvconn_open(name, &pvconn); + if (retval && retval != EAGAIN) { + ofp_fatal(retval, "opening %s", name); + } + return pvconn; +} + +static struct vconn * +accept_vconn(struct pvconn *pvconn) +{ + struct vconn *new; + int retval; + + retval = pvconn_accept(pvconn, OFP_VERSION, &new); + if (retval && retval != EAGAIN) { + VLOG_WARN_RL(&rl, "accept failed (%s)", strerror(retval)); + } + return new; +} + +void +add_hook(struct secchan *secchan, const struct hook_class *class, void *aux) +{ + struct hook *hook; + + if (secchan->n_hooks >= secchan->allocated_hooks) { + secchan->hooks = x2nrealloc(secchan->hooks, &secchan->allocated_hooks, + sizeof *secchan->hooks); + } + hook = &secchan->hooks[secchan->n_hooks++]; + hook->class = class; + hook->aux = aux; +} + +struct ofp_packet_in * +get_ofp_packet_in(struct relay *r) +{ + struct ofpbuf *msg = r->halves[HALF_LOCAL].rxbuf; + struct ofp_header *oh = msg->data; + if (oh->type == OFPT_PACKET_IN) { + if (msg->size >= offsetof (struct ofp_packet_in, data)) { + return msg->data; + } else { + VLOG_WARN("packet too short (%zu bytes) for packet_in", + msg->size); + } + } + return NULL; +} + +bool +get_ofp_packet_eth_header(struct relay *r, struct ofp_packet_in **opip, + struct eth_header **ethp) +{ + const int min_len = offsetof(struct ofp_packet_in, data) + ETH_HEADER_LEN; + struct ofp_packet_in *opi = get_ofp_packet_in(r); + if (opi && ntohs(opi->header.length) >= min_len) { + *opip = opi; + *ethp = (void *) opi->data; + return true; + } + return false; +} + +/* OpenFlow message relaying. */ + +/* Returns a malloc'd string containing a copy of 'vconn_name' modified not to + * subscribe to asynchronous messages such as 'ofp_packet_in' events (if + * possible). */ +static char * +vconn_name_without_subscription(const char *vconn_name) +{ + int nl_index; + if (sscanf(vconn_name, "nl:%d", &nl_index) == 1) { + /* nl:123 or nl:123:1 opens a netlink connection to local datapath 123. + * nl:123:0 opens a netlink connection to local datapath 123 without + * obtaining a subscription for ofp_packet_in or ofp_flow_removed + * messages. */ + return xasprintf("nl:%d:0", nl_index); + } else { + /* We don't have a way to specify not to subscribe to those messages + * for other transports. (That's a defect: really this should be in + * the OpenFlow protocol, not the Netlink transport). */ + VLOG_WARN_RL(&rl, "new management connection will receive " + "asynchronous messages"); + return xstrdup(vconn_name); + } +} + +static struct relay * +relay_accept(const struct settings *s, struct pvconn *pvconn) +{ + struct vconn *new_remote, *new_local; + struct rconn *r1, *r2; + char *vconn_name; + int retval; + + new_remote = accept_vconn(pvconn); + if (!new_remote) { + return NULL; + } + + vconn_name = vconn_name_without_subscription(s->dp_name); + retval = vconn_open(vconn_name, OFP_VERSION, &new_local); + if (retval) { + VLOG_ERR_RL(&rl, "could not connect to %s (%s)", + vconn_name, strerror(retval)); + vconn_close(new_remote); + free(vconn_name); + return NULL; + } + + /* Create and return relay. */ + r1 = rconn_create(0, 0); + rconn_connect_unreliably(r1, vconn_name, new_local); + free(vconn_name); + + r2 = rconn_create(0, 0); + rconn_connect_unreliably(r2, "passive", new_remote); + + return relay_create(NULL, r1, r2, true); +} + +static struct relay * +relay_create(struct rconn *async, struct rconn *local, struct rconn *remote, + bool is_mgmt_conn) +{ + struct relay *r = xcalloc(1, sizeof *r); + r->halves[HALF_LOCAL].rconn = local; + r->halves[HALF_REMOTE].rconn = remote; + r->is_mgmt_conn = is_mgmt_conn; + r->async_rconn = async; + return r; +} + +static bool +call_local_packet_cbs(struct secchan *secchan, struct relay *r) +{ + const struct hook *h; + for (h = secchan->hooks; h < &secchan->hooks[secchan->n_hooks]; h++) { + bool (*cb)(struct relay *, void *aux) = h->class->local_packet_cb; + if (cb && (cb)(r, h->aux)) { + return true; + } + } + return false; +} + +static bool +call_remote_packet_cbs(struct secchan *secchan, struct relay *r) +{ + const struct hook *h; + for (h = secchan->hooks; h < &secchan->hooks[secchan->n_hooks]; h++) { + bool (*cb)(struct relay *, void *aux) = h->class->remote_packet_cb; + if (cb && (cb)(r, h->aux)) { + return true; + } + } + return false; +} + +static void +relay_run(struct relay *r, struct secchan *secchan) +{ + int iteration; + int i; + + if (r->async_rconn) { + rconn_run(r->async_rconn); + } + for (i = 0; i < 2; i++) { + rconn_run(r->halves[i].rconn); + } + + /* Limit the number of iterations to prevent other tasks from starving. */ + for (iteration = 0; iteration < 50; iteration++) { + bool progress = false; + for (i = 0; i < 2; i++) { + struct half *this = &r->halves[i]; + struct half *peer = &r->halves[!i]; + + if (!this->rxbuf) { + this->rxbuf = rconn_recv(this->rconn); + if (!this->rxbuf && i == HALF_LOCAL && r->async_rconn) { + this->rxbuf = rconn_recv(r->async_rconn); + } + if (this->rxbuf && (i == HALF_REMOTE || !r->is_mgmt_conn)) { + if (i == HALF_LOCAL + ? call_local_packet_cbs(secchan, r) + : call_remote_packet_cbs(secchan, r)) + { + ofpbuf_delete(this->rxbuf); + this->rxbuf = NULL; + progress = true; + break; + } + } + } + + if (this->rxbuf && !this->n_txq) { + int retval = rconn_send(peer->rconn, this->rxbuf, + &this->n_txq); + if (retval != EAGAIN) { + if (!retval) { + progress = true; + } else { + ofpbuf_delete(this->rxbuf); + } + this->rxbuf = NULL; + } + } + } + if (!progress) { + break; + } + } + + if (r->is_mgmt_conn) { + for (i = 0; i < 2; i++) { + struct half *this = &r->halves[i]; + if (!rconn_is_alive(this->rconn)) { + relay_destroy(r); + return; + } + } + } +} + +static void +relay_wait(struct relay *r) +{ + int i; + + if (r->async_rconn) { + rconn_run_wait(r->async_rconn); + } + for (i = 0; i < 2; i++) { + struct half *this = &r->halves[i]; + + rconn_run_wait(this->rconn); + if (!this->rxbuf) { + rconn_recv_wait(this->rconn); + if (i == HALF_LOCAL && r->async_rconn) { + rconn_recv_wait(r->async_rconn); + } + } + } +} + +static void +relay_destroy(struct relay *r) +{ + int i; + + list_remove(&r->node); + rconn_destroy(r->async_rconn); + for (i = 0; i < 2; i++) { + struct half *this = &r->halves[i]; + rconn_destroy(this->rconn); + ofpbuf_delete(this->rxbuf); + } + free(r); +} + +/* User interface. */ + +static void +parse_options(int argc, char *argv[], struct settings *s) +{ + enum { + OPT_ACCEPT_VCONN = UCHAR_MAX + 1, + OPT_NO_RESOLV_CONF, + OPT_INACTIVITY_PROBE, + OPT_MAX_IDLE, + OPT_MAX_BACKOFF, + OPT_RATE_LIMIT, + OPT_BURST_LIMIT, + OPT_BOOTSTRAP_CA_CERT, + OPT_STP, + OPT_NO_STP, + OPT_OUT_OF_BAND, + OPT_IN_BAND, + OPT_EMERG_FLOW, + VLOG_OPTION_ENUMS, + LEAK_CHECKER_OPTION_ENUMS + }; + static struct option long_options[] = { + {"accept-vconn", required_argument, 0, OPT_ACCEPT_VCONN}, + {"no-resolv-conf", no_argument, 0, OPT_NO_RESOLV_CONF}, + {"fail", required_argument, 0, 'F'}, + {"inactivity-probe", required_argument, 0, OPT_INACTIVITY_PROBE}, + {"max-idle", required_argument, 0, OPT_MAX_IDLE}, + {"max-backoff", required_argument, 0, OPT_MAX_BACKOFF}, + {"listen", required_argument, 0, 'l'}, + {"monitor", required_argument, 0, 'm'}, + {"rate-limit", optional_argument, 0, OPT_RATE_LIMIT}, + {"burst-limit", required_argument, 0, OPT_BURST_LIMIT}, + {"stp", no_argument, 0, OPT_STP}, + {"no-stp", no_argument, 0, OPT_NO_STP}, + {"out-of-band", no_argument, 0, OPT_OUT_OF_BAND}, + {"in-band", no_argument, 0, OPT_IN_BAND}, + {"emerg-flow", no_argument, 0, OPT_EMERG_FLOW}, + {"verbose", optional_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + DAEMON_LONG_OPTIONS, + VLOG_LONG_OPTIONS, + LEAK_CHECKER_LONG_OPTIONS, +#ifdef HAVE_OPENSSL + VCONN_SSL_LONG_OPTIONS + {"bootstrap-ca-cert", required_argument, 0, OPT_BOOTSTRAP_CA_CERT}, +#endif + {0, 0, 0, 0}, + }; + char *short_options = long_options_to_short_options(long_options); + char *accept_re = NULL; + int retval; + + /* Set defaults that we can figure out before parsing options. */ + s->n_listeners = 0; + s->monitor_name = NULL; + s->fail_mode = FAIL_OPEN; + s->max_idle = 15; + s->probe_interval = 15; + s->max_backoff = 15; + s->update_resolv_conf = true; + s->rate_limit = 0; + s->burst_limit = 0; + s->enable_stp = false; + s->in_band = true; + s->emerg_flow = false; + for (;;) { + int c; + + c = getopt_long(argc, argv, short_options, long_options, NULL); + if (c == -1) { + break; + } + + switch (c) { + case OPT_ACCEPT_VCONN: + accept_re = optarg[0] == '^' ? optarg : xasprintf("^%s", optarg); + break; + + case OPT_NO_RESOLV_CONF: + s->update_resolv_conf = false; + break; + + case 'F': + if (!strcmp(optarg, "open")) { + s->fail_mode = FAIL_OPEN; + } else if (!strcmp(optarg, "closed")) { + s->fail_mode = FAIL_CLOSED; + } else { + ofp_fatal(0, "-f or --fail argument must be \"open\" " + "or \"closed\""); + } + break; + + case OPT_INACTIVITY_PROBE: + s->probe_interval = atoi(optarg); + if (s->probe_interval < 1) { + ofp_fatal(0, "--inactivity-probe argument must be at least 1"); + } + break; + + case OPT_MAX_IDLE: + if (!strcmp(optarg, "permanent")) { + s->max_idle = OFP_FLOW_PERMANENT; + } else { + s->max_idle = atoi(optarg); + if (s->max_idle < 1 || s->max_idle > 65535) { + ofp_fatal(0, "--max-idle argument must be between 1 and " + "65535 or the word 'permanent'"); + } + } + break; + + case OPT_MAX_BACKOFF: + s->max_backoff = atoi(optarg); + if (s->max_backoff < 1) { + ofp_fatal(0, "--max-backoff argument must be at least 1"); + } else if (s->max_backoff > 3600) { + s->max_backoff = 3600; + } + break; + + case OPT_RATE_LIMIT: + if (optarg) { + s->rate_limit = atoi(optarg); + if (s->rate_limit < 1) { + ofp_fatal(0, "--rate-limit argument must be at least 1"); + } + } else { + s->rate_limit = 1000; + } + break; + + case OPT_BURST_LIMIT: + s->burst_limit = atoi(optarg); + if (s->burst_limit < 1) { + ofp_fatal(0, "--burst-limit argument must be at least 1"); + } + break; + + case OPT_STP: + s->enable_stp = true; + break; + + case OPT_NO_STP: + s->enable_stp = false; + break; + + case OPT_OUT_OF_BAND: + s->in_band = false; + break; + + case OPT_IN_BAND: + s->in_band = true; + break; + + case OPT_EMERG_FLOW: + s->emerg_flow = true; + break; + + case 'l': + if (s->n_listeners >= MAX_MGMT) { + ofp_fatal(0, + "-l or --listen may be specified at most %d times", + MAX_MGMT); + } + s->listener_names[s->n_listeners++] = optarg; + break; + + case 'm': + if (s->monitor_name) { + ofp_fatal(0, "-m or --monitor may only be specified once"); + } + s->monitor_name = optarg; + break; + + case 'h': + usage(); + + case 'V': + printf("%s %s compiled "__DATE__" "__TIME__"\n", + program_name, VERSION BUILDNR); + exit(EXIT_SUCCESS); + + DAEMON_OPTION_HANDLERS + + VLOG_OPTION_HANDLERS + + LEAK_CHECKER_OPTION_HANDLERS + +#ifdef HAVE_OPENSSL + VCONN_SSL_OPTION_HANDLERS + + case OPT_BOOTSTRAP_CA_CERT: + vconn_ssl_set_ca_cert_file(optarg, true); + break; +#endif + + case '?': + exit(EXIT_FAILURE); + + default: + abort(); + } + } + free(short_options); + + argc -= optind; + argv += optind; + if (argc < 1 || argc > 2) { + ofp_fatal(0, "need one or two non-option arguments; " + "use --help for usage"); + } + + /* Local and remote vconns. */ + s->dp_name = argv[0]; + { + char *curr; + char *save; + int i; + + s->num_controllers = 0; + for (i = 0; i < MAX_CONTROLLERS; ++i) + s->controller_names[i] = NULL; + if (argc > 1) { + for (curr = strtok_r(argv[1], ",,", &save), i = 0; + curr && i < MAX_CONTROLLERS; + curr = strtok_r(NULL, ",,", &save), ++i) { + s->controller_names[i] = xstrdup(curr); + ++s->num_controllers; + } + } + } + + /* Set accept_controller_regex. */ + if (!accept_re) { + accept_re = vconn_ssl_is_configured() ? "^ssl:.*" : ".*"; + } + retval = regcomp(&s->accept_controller_regex, accept_re, + REG_NOSUB | REG_EXTENDED); + if (retval) { + size_t length = regerror(retval, &s->accept_controller_regex, NULL, 0); + char *buffer = xmalloc(length); + regerror(retval, &s->accept_controller_regex, buffer, length); + ofp_fatal(0, "%s: %s", accept_re, buffer); + } + s->accept_controller_re = accept_re; + + /* Mode of operation. */ + s->discovery = s->controller_names[0] == NULL; + if (s->discovery && !s->in_band) { + ofp_fatal(0, "Cannot perform discovery with out-of-band control"); + } + + /* Rate limiting. */ + if (s->rate_limit) { + if (s->rate_limit < 100) { + VLOG_WARN("Rate limit set to unusually low value %d", + s->rate_limit); + } + if (!s->burst_limit) { + s->burst_limit = s->rate_limit / 4; + } + s->burst_limit = MAX(s->burst_limit, 1); + s->burst_limit = MIN(s->burst_limit, INT_MAX / 1000); + } +} + +static void +usage(void) +{ + printf("%s: secure channel, a relay for OpenFlow messages.\n" + "usage: %s [OPTIONS] DATAPATH [CONTROLLER]\n" + "DATAPATH is an active connection method to a local datapath.\n" + "CONTROLLER is an active OpenFlow connection method; if it is\n" + "omitted, then secchan performs controller discovery.\n", + program_name, program_name); + vconn_usage(true, true, true); + printf("\nController discovery options:\n" + " --accept-vconn=REGEX accept matching discovered controllers\n" + " --no-resolv-conf do not update /etc/resolv.conf\n" + "\nNetworking options:\n" + " -F, --fail=open|closed when controller connection fails:\n" + " closed: drop all packets\n" + " open (default): act as learning switch\n" + " --inactivity-probe=SECS time between inactivity probes\n" + " --max-idle=SECS max idle for flows set up by secchan\n" + " --max-backoff=SECS max time between controller connection\n" + " attempts (default: 15 seconds)\n" + " -l, --listen=METHOD allow management connections on METHOD\n" + " (a passive OpenFlow connection method)\n" + " -m, --monitor=METHOD copy traffic to/from kernel to METHOD\n" + " (a passive OpenFlow connection method)\n" + " --out-of-band controller connection is out-of-band\n" + " --stp enable 802.1D Spanning Tree Protocol\n" + " --no-stp disable 802.1D Spanning Tree Protocol\n" + " --emerg-flow enable emergency flow protection/restoration\n" + "\nRate-limiting of \"packet-in\" messages to the controller:\n" + " --rate-limit[=PACKETS] max rate, in packets/s (default: 1000)\n" + " --burst-limit=BURST limit on packet credit for idle time\n", + ofp_pkgdatadir); + daemon_usage(); + vlog_usage(); + printf("\nOther options:\n" + " -h, --help display this help message\n" + " -V, --version display version information\n"); + leak_checker_usage(); + exit(EXIT_SUCCESS); +} diff --git a/openflow/secchan/secchan.h b/openflow/secchan/secchan.h new file mode 100644 index 00000000..7f89e2ef --- /dev/null +++ b/openflow/secchan/secchan.h @@ -0,0 +1,135 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#ifndef SECCHAN_H +#define SECCHAN_H 1 + +#include +#include +#include +#include "list.h" +#include "packets.h" + +struct secchan; + +/* Behavior when the connection to the controller fails. */ +enum fail_mode { + FAIL_OPEN, /* Act as learning switch. */ + FAIL_CLOSED /* Drop all packets. */ +}; + +/* Maximum number of management connection listeners. */ +#define MAX_MGMT 8 + +#define MAX_CONTROLLERS 3 + +/* Settings that may be configured by the user. */ +struct settings { + /* Overall mode of operation. */ + bool discovery; /* Discover the controller automatically? */ + bool in_band; /* Connect to controller in-band? */ + + /* Related vconns and network devices. */ + const char *dp_name; /* Local datapath. */ + int num_controllers; /* Number of configured controllers. */ + const char *controller_names[MAX_CONTROLLERS]; /* Controllers (if not discovery mode). */ + const char *listener_names[MAX_MGMT]; /* Listen for mgmt connections. */ + size_t n_listeners; /* Number of mgmt connection listeners. */ + const char *monitor_name; /* Listen for traffic monitor connections. */ + + /* Failure behavior. */ + enum fail_mode fail_mode; /* Act as learning switch if no controller? */ + int max_idle; /* Idle time for flows in fail-open mode. */ + int probe_interval; /* # seconds idle before sending echo request. */ + int max_backoff; /* Max # seconds between connection attempts. */ + + /* Packet-in rate-limiting. */ + int rate_limit; /* Tokens added to bucket per second. */ + int burst_limit; /* Maximum number token bucket size. */ + + /* Discovery behavior. */ + regex_t accept_controller_regex; /* Controller vconns to accept. */ + const char *accept_controller_re; /* String version of regex. */ + bool update_resolv_conf; /* Update /etc/resolv.conf? */ + + /* Spanning tree protocol. */ + bool enable_stp; + + /* Emergency flow protection/restoration behavior. */ + bool emerg_flow; +}; + +struct half { + struct rconn *rconn; + struct ofpbuf *rxbuf; + int n_txq; /* No. of packets queued for tx on 'rconn'. */ +}; + +struct relay { + struct list node; + +#define HALF_LOCAL 0 +#define HALF_REMOTE 1 + struct half halves[2]; + + /* The secchan has a primary connection (relay) to an OpenFlow controller. + * This primary connection actually makes two connections to the datapath: + * one for OpenFlow requests and responses, and one that is only used for + * receiving asynchronous events such as 'ofp_packet_in' events. This + * design keeps replies to OpenFlow requests from being dropped by the + * kernel due to a flooded network device. + * + * The secchan may also have any number of secondary "management" + * connections (relays). These connections do not receive asychronous + * events and thus have a null 'async_rconn'. */ + bool is_mgmt_conn; /* Is this a management connection? */ + struct rconn *async_rconn; /* For receiving asynchronous events. */ +}; + +struct hook_class { + bool (*local_packet_cb)(struct relay *, void *aux); + bool (*remote_packet_cb)(struct relay *, void *aux); + void (*periodic_cb)(void *aux); + void (*wait_cb)(void *aux); + void (*closing_cb)(struct relay *, void *aux); +}; + +void add_hook(struct secchan *, const struct hook_class *, void *); + +struct ofp_packet_in *get_ofp_packet_in(struct relay *); +bool get_ofp_packet_eth_header(struct relay *, struct ofp_packet_in **, + struct eth_header **); +void get_ofp_packet_payload(struct ofp_packet_in *, struct ofpbuf *); + + +#endif /* secchan.h */ diff --git a/openflow/secchan/status.c b/openflow/secchan/status.c new file mode 100644 index 00000000..cf228123 --- /dev/null +++ b/openflow/secchan/status.c @@ -0,0 +1,230 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include "status.h" +#include +#include +#include +#include +#include "dynamic-string.h" +#include "openflow/nicira-ext.h" +#include "ofpbuf.h" +#include "openflow/openflow.h" +#include "rconn.h" +#include "timeval.h" +#include "vconn.h" + +#define THIS_MODULE VLM_status +#include "vlog.h" + +struct switch_status_category { + char *name; + void (*cb)(struct status_reply *, void *aux); + void *aux; +}; + +struct switch_status { + const struct settings *s; + time_t booted; + struct switch_status_category *categories; + size_t n_categories, allocated_categories; +}; + +struct status_reply { + struct switch_status_category *category; + struct ds request; + struct ds output; +}; + +static bool +switch_status_remote_packet_cb(struct relay *r, void *ss_) +{ + struct switch_status *ss = ss_; + struct rconn *rc = r->halves[HALF_REMOTE].rconn; + struct ofpbuf *msg = r->halves[HALF_REMOTE].rxbuf; + struct switch_status_category *c; + struct nicira_header *request; + struct nicira_header *reply; + struct status_reply sr; + struct ofpbuf *b; + int retval; + + if (msg->size < sizeof(struct nicira_header)) { + return false; + } + request = msg->data; + if (request->header.type != OFPT_VENDOR + || request->vendor != htonl(NX_VENDOR_ID) + || request->subtype != htonl(NXT_STATUS_REQUEST)) { + return false; + } + + sr.request.string = (void *) (request + 1); + sr.request.length = msg->size - sizeof *request; + ds_init(&sr.output); + for (c = ss->categories; c < &ss->categories[ss->n_categories]; c++) { + if (!memcmp(c->name, sr.request.string, + MIN(strlen(c->name), sr.request.length))) { + sr.category = c; + c->cb(&sr, c->aux); + } + } + reply = make_openflow_xid(sizeof *reply + sr.output.length, + OFPT_VENDOR, request->header.xid, &b); + reply->vendor = htonl(NX_VENDOR_ID); + reply->subtype = htonl(NXT_STATUS_REPLY); + memcpy(reply + 1, sr.output.string, sr.output.length); + retval = rconn_send(rc, b, NULL); + if (retval && retval != EAGAIN) { + VLOG_WARN("send failed (%s)", strerror(retval)); + } + ds_destroy(&sr.output); + return true; +} + +void +rconn_status_cb(struct status_reply *sr, void *rconn_) +{ + struct rconn *rconn = rconn_; + time_t now = time_now(); + + status_reply_put(sr, "name=%s", rconn_get_name(rconn)); + status_reply_put(sr, "state=%s", rconn_get_state(rconn)); + status_reply_put(sr, "backoff=%d", rconn_get_backoff(rconn)); + status_reply_put(sr, "is-connected=%s", + rconn_is_connected(rconn) ? "true" : "false"); + status_reply_put(sr, "sent-msgs=%u", rconn_packets_sent(rconn)); + status_reply_put(sr, "received-msgs=%u", rconn_packets_received(rconn)); + status_reply_put(sr, "attempted-connections=%u", + rconn_get_attempted_connections(rconn)); + status_reply_put(sr, "successful-connections=%u", + rconn_get_successful_connections(rconn)); + status_reply_put(sr, "last-connection=%ld", + (long int) (now - rconn_get_last_connection(rconn))); + status_reply_put(sr, "time-connected=%lu", + rconn_get_total_time_connected(rconn)); + status_reply_put(sr, "state-elapsed=%u", rconn_get_state_elapsed(rconn)); +} + +static void +config_status_cb(struct status_reply *sr, void *s_) +{ + const struct settings *s = s_; + size_t i; + + for (i = 0; i < s->n_listeners; i++) { + status_reply_put(sr, "management%zu=%s", i, s->listener_names[i]); + } + if (s->probe_interval) { + status_reply_put(sr, "probe-interval=%d", s->probe_interval); + } + if (s->max_backoff) { + status_reply_put(sr, "max-backoff=%d", s->max_backoff); + } +} + +static void +switch_status_cb(struct status_reply *sr, void *ss_) +{ + struct switch_status *ss = ss_; + time_t now = time_now(); + + status_reply_put(sr, "now=%ld", (long int) now); + status_reply_put(sr, "uptime=%ld", (long int) (now - ss->booted)); + status_reply_put(sr, "pid=%ld", (long int) getpid()); +} + +static struct hook_class switch_status_hook_class = { + NULL, /* local_packet_cb */ + switch_status_remote_packet_cb, /* remote_packet_cb */ + NULL, /* periodic_cb */ + NULL, /* wait_cb */ + NULL, /* closing_cb */ +}; + +void +switch_status_start(struct secchan *secchan, const struct settings *s, + struct switch_status **ssp) +{ + struct switch_status *ss = xcalloc(1, sizeof *ss); + ss->s = s; + ss->booted = time_now(); + switch_status_register_category(ss, "config", + config_status_cb, (void *) s); + switch_status_register_category(ss, "switch", switch_status_cb, ss); + *ssp = ss; + add_hook(secchan, &switch_status_hook_class, ss); +} + +void +switch_status_register_category(struct switch_status *ss, + const char *category, + void (*cb)(struct status_reply *, void *aux), + void *aux) +{ + struct switch_status_category *c; + if (ss->n_categories >= ss->allocated_categories) { + ss->categories = x2nrealloc(ss->categories, &ss->allocated_categories, + sizeof *ss->categories); + } + c = &ss->categories[ss->n_categories++]; + c->cb = cb; + c->aux = aux; + c->name = xstrdup(category); +} + +void +status_reply_put(struct status_reply *sr, const char *content, ...) +{ + size_t old_length = sr->output.length; + size_t added; + va_list args; + + /* Append the status reply to the output. */ + ds_put_format(&sr->output, "%s.", sr->category->name); + va_start(args, content); + ds_put_format_valist(&sr->output, content, args); + va_end(args); + if (ds_last(&sr->output) != '\n') { + ds_put_char(&sr->output, '\n'); + } + + /* Drop what we just added if it doesn't match the request. */ + added = sr->output.length - old_length; + if (added < sr->request.length + || memcmp(&sr->output.string[old_length], + sr->request.string, sr->request.length)) { + ds_truncate(&sr->output, old_length); + } +} diff --git a/openflow/secchan/status.h b/openflow/secchan/status.h new file mode 100644 index 00000000..68793eff --- /dev/null +++ b/openflow/secchan/status.h @@ -0,0 +1,56 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#ifndef STATUS_H +#define STATUS_H 1 + +#include "secchan.h" + +struct secchan; +struct status_reply; +struct switch_status; + +void switch_status_start(struct secchan *, const struct settings *, + struct switch_status **); +void switch_status_register_category(struct switch_status *, + const char *category, + void (*cb)(struct status_reply *, + void *aux), + void *aux); + +void status_reply_put(struct status_reply *, const char *, ...) + PRINTF_FORMAT(2, 3); + +void rconn_status_cb(struct status_reply *, void *rconn_); + +#endif /* status.h */ diff --git a/openflow/secchan/stp-secchan.c b/openflow/secchan/stp-secchan.c new file mode 100644 index 00000000..152595e9 --- /dev/null +++ b/openflow/secchan/stp-secchan.c @@ -0,0 +1,293 @@ +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include "stp-secchan.h" +#include +#include +#include "flow.h" +#include "secchan.h" +#include "ofpbuf.h" +#include "openflow/openflow.h" +#include "poll-loop.h" +#include "port-watcher.h" +#include "rconn.h" +#include "stp.h" +#include "timeval.h" +#include "vconn.h" + +#define THIS_MODULE VLM_stp_secchan +#include "vlog.h" + +struct stp_data { + struct stp *stp; + struct port_watcher *pw; + struct rconn *local_rconn; + struct rconn *remote_rconn; + long long int last_tick; + int n_txq; +}; + +static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60); + +static bool +stp_local_packet_cb(struct relay *r, void *stp_) +{ + struct ofpbuf *msg = r->halves[HALF_LOCAL].rxbuf; + struct ofp_header *oh; + struct stp_data *stp = stp_; + struct ofp_packet_in *opi; + struct eth_header *eth; + struct llc_header *llc; + struct ofpbuf payload; + uint16_t port_no; + struct flow flow; + + oh = msg->data; + if (oh->type == OFPT_FEATURES_REPLY + && msg->size >= offsetof(struct ofp_switch_features, ports)) { + struct ofp_switch_features *osf = msg->data; + osf->capabilities |= htonl(OFPC_STP); + return false; + } + + if (!get_ofp_packet_eth_header(r, &opi, ð) + || !eth_addr_equals(eth->eth_dst, stp_eth_addr)) { + return false; + } + + port_no = ntohs(opi->in_port); + if (port_no >= STP_MAX_PORTS) { + /* STP only supports 255 ports. */ + return false; + } + if (port_watcher_get_config(stp->pw, port_no) & OFPPC_NO_STP) { + /* We're not doing STP on this port. */ + return false; + } + + if (opi->reason == OFPR_ACTION) { + /* The controller set up a flow for this, so we won't intercept it. */ + return false; + } + + get_ofp_packet_payload(opi, &payload); + flow_extract(&payload, port_no, &flow); + if (flow.dl_type != htons(OFP_DL_TYPE_NOT_ETH_TYPE)) { + VLOG_DBG("non-LLC frame received on STP multicast address"); + return false; + } + llc = ofpbuf_at_assert(&payload, sizeof *eth, sizeof *llc); + if (llc->llc_dsap != STP_LLC_DSAP) { + VLOG_DBG("bad DSAP 0x%02"PRIx8" received on STP multicast address", + llc->llc_dsap); + return false; + } + + /* Trim off padding on payload. */ + if (payload.size > ntohs(eth->eth_type) + ETH_HEADER_LEN) { + payload.size = ntohs(eth->eth_type) + ETH_HEADER_LEN; + } + if (ofpbuf_try_pull(&payload, ETH_HEADER_LEN + LLC_HEADER_LEN)) { + struct stp_port *p = stp_get_port(stp->stp, port_no); + stp_received_bpdu(p, payload.data, payload.size); + } + + return true; +} + +static void +stp_periodic_cb(void *stp_) +{ + struct stp_data *stp = stp_; + long long int now = time_msec(); + long long int elapsed = now - stp->last_tick; + struct stp_port *p; + + if (!port_watcher_is_ready(stp->pw)) { + /* Can't start STP until we know port flags, because port flags can + * disable STP. */ + return; + } + if (elapsed <= 0) { + return; + } + + stp_tick(stp->stp, MIN(INT_MAX, elapsed)); + stp->last_tick = now; + + while (stp_get_changed_port(stp->stp, &p)) { + int port_no = stp_port_no(p); + enum stp_state s_state = stp_port_get_state(p); + + if (s_state != STP_DISABLED) { + VLOG_INFO("STP: Port %d entered %s state", + port_no, stp_state_name(s_state)); + } + if (!(port_watcher_get_config(stp->pw, port_no) & OFPPC_NO_STP)) { + uint32_t p_config = 0; + uint32_t p_state; + switch (s_state) { + case STP_LISTENING: + p_state = OFPPS_STP_LISTEN; + break; + case STP_LEARNING: + p_state = OFPPS_STP_LEARN; + break; + case STP_DISABLED: + case STP_FORWARDING: + p_state = OFPPS_STP_FORWARD; + break; + case STP_BLOCKING: + p_state = OFPPS_STP_BLOCK; + break; + default: + VLOG_DBG_RL(&rl, "STP: Port %d has bad state %x", + port_no, s_state); + p_state = OFPPS_STP_FORWARD; + break; + } + if (!stp_forward_in_state(s_state)) { + p_config = OFPPC_NO_FLOOD; + } + port_watcher_set_flags(stp->pw, port_no, + p_config, OFPPC_NO_FLOOD, + p_state, OFPPS_STP_MASK); + } else { + /* We don't own those flags. */ + } + } +} + +static void +stp_wait_cb(void *stp_ UNUSED) +{ + poll_timer_wait(1000); +} + +static void +send_bpdu(struct ofpbuf *pkt, int port_no, void *stp_) +{ + struct stp_data *stp = stp_; + const uint8_t *port_mac = port_watcher_get_hwaddr(stp->pw, port_no); + if (port_mac) { + struct eth_header *eth = pkt->l2; + struct ofpbuf *opo; + + memcpy(eth->eth_src, port_mac, ETH_ADDR_LEN); + opo = make_unbuffered_packet_out(pkt, OFPP_NONE, port_no); + + rconn_send_with_limit(stp->local_rconn, opo, &stp->n_txq, OFPP_MAX); + } else { + VLOG_WARN_RL(&rl, "cannot send BPDU on missing port %d", port_no); + } + ofpbuf_delete(pkt); +} + +static bool +stp_is_port_supported(uint16_t port_no) +{ + return port_no < STP_MAX_PORTS; +} + +static void +stp_port_changed_cb(uint16_t port_no, + const struct ofp_phy_port *old UNUSED, + const struct ofp_phy_port *new, + void *stp_) +{ + struct stp_data *stp = stp_; + struct stp_port *p; + + if (!stp_is_port_supported(port_no)) { + return; + } + + p = stp_get_port(stp->stp, port_no); + if (!new + || new->config & htonl(OFPPC_NO_STP | OFPPC_PORT_DOWN) + || new->state & htonl(OFPPS_LINK_DOWN)) { + stp_port_disable(p); + } else { + int speed = 0; + stp_port_enable(p); + if (new->curr & (OFPPF_10MB_HD | OFPPF_10MB_FD)) { + speed = 10; + } else if (new->curr & (OFPPF_100MB_HD | OFPPF_100MB_FD)) { + speed = 100; + } else if (new->curr & (OFPPF_1GB_HD | OFPPF_1GB_FD)) { + speed = 1000; + } else if (new->curr & OFPPF_10GB_FD) { + speed = 10000; + } + stp_port_set_speed(p, speed); + } +} + +static void +stp_local_port_changed_cb(const struct ofp_phy_port *port, void *stp_) +{ + struct stp_data *stp = stp_; + if (port) { + stp_set_bridge_id(stp->stp, eth_addr_to_uint64(port->hw_addr)); + } +} + +static struct hook_class stp_hook_class = { + stp_local_packet_cb, /* local_packet_cb */ + NULL, /* remote_packet_cb */ + stp_periodic_cb, /* periodic_cb */ + stp_wait_cb, /* wait_cb */ + NULL, /* closing_cb */ +}; + +void +stp_start(struct secchan *secchan, struct port_watcher *pw, + struct rconn *local, struct rconn *remote) +{ + uint8_t dpid[ETH_ADDR_LEN]; + struct stp_data *stp; + + stp = xcalloc(1, sizeof *stp); + eth_addr_random(dpid); + stp->stp = stp_create("stp", eth_addr_to_uint64(dpid), send_bpdu, stp); + stp->pw = pw; + stp->local_rconn = local; + stp->remote_rconn = remote; + stp->last_tick = time_msec(); + + port_watcher_register_callback(pw, stp_port_changed_cb, stp); + port_watcher_register_local_port_callback(pw, stp_local_port_changed_cb, + stp); + add_hook(secchan, &stp_hook_class, stp); +} diff --git a/openflow/secchan/stp-secchan.h b/openflow/secchan/stp-secchan.h new file mode 100644 index 00000000..2d1105f7 --- /dev/null +++ b/openflow/secchan/stp-secchan.h @@ -0,0 +1,48 @@ +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#ifndef STP_SECCHAN_H +#define STP_SECCHAN_H 1 + +/* Extra time, in seconds, at boot before going into fail-open, to give the + * spanning tree protocol time to figure out the network layout. */ +#define STP_EXTRA_BOOT_TIME 30 + +struct port_watcher; +struct rconn; +struct secchan; + +void stp_start(struct secchan *, struct port_watcher *, + struct rconn *local, struct rconn *remote); + +#endif /* stp-secchan.h */ diff --git a/openflow/soexpand.pl b/openflow/soexpand.pl new file mode 100755 index 00000000..4e130056 --- /dev/null +++ b/openflow/soexpand.pl @@ -0,0 +1,26 @@ +use strict; +use warnings; +use Getopt::Long; + +my ($exit_code) = 0; +my (@include_dirs); +Getopt::Long::Configure ("bundling"); +GetOptions("I|include=s" => \@include_dirs) or exit(1); +@include_dirs = ('.') if !@include_dirs; +OUTER: while () { + if (my ($name) = /^\.so (\S+)$/) { + foreach my $dir (@include_dirs, '.') { + if (open(INNER, "$dir/$name")) { + while () { + print $_; + } + close(INNER); + next OUTER; + } + } + print STDERR "$name not found in: ", join(' ', @include_dirs), "\n"; + $exit_code = 1; + } + print $_; +} +exit $exit_code; diff --git a/openflow/tests/.dirstamp b/openflow/tests/.dirstamp new file mode 100644 index 00000000..e69de29b diff --git a/openflow/tests/.gitignore b/openflow/tests/.gitignore new file mode 100644 index 00000000..3e44d9e7 --- /dev/null +++ b/openflow/tests/.gitignore @@ -0,0 +1,6 @@ +/Makefile +/Makefile.in +/test-list +/test-dhcp-client +/test-stp +/test-type-props diff --git a/openflow/tests/automake.mk b/openflow/tests/automake.mk new file mode 100644 index 00000000..a4e945a9 --- /dev/null +++ b/openflow/tests/automake.mk @@ -0,0 +1,46 @@ +TESTS += tests/test-flows.sh +noinst_PROGRAMS += tests/test-flows +tests_test_flows_SOURCES = tests/test-flows.c +tests_test_flows_LDADD = lib/libopenflow.a +dist_check_SCRIPTS = tests/test-flows.sh tests/flowgen.pl + +TESTS += tests/test-hmap +noinst_PROGRAMS += tests/test-hmap +tests_test_hmap_SOURCES = tests/test-hmap.c +tests_test_hmap_LDADD = lib/libopenflow.a + +TESTS += tests/test-list +noinst_PROGRAMS += tests/test-list +tests_test_list_SOURCES = tests/test-list.c +tests_test_list_LDADD = lib/libopenflow.a + +TESTS += tests/test-type-props +noinst_PROGRAMS += tests/test-type-props +tests_test_type_props_SOURCES = tests/test-type-props.c + +noinst_PROGRAMS += tests/test-dhcp-client +tests_test_dhcp_client_SOURCES = tests/test-dhcp-client.c +tests_test_dhcp_client_LDADD = lib/libopenflow.a $(FAULT_LIBS) + +TESTS += tests/test-stp.sh +EXTRA_DIST += tests/test-stp.sh +noinst_PROGRAMS += tests/test-stp + +tests_test_stp_SOURCES = tests/test-stp.c +tests_test_stp_LDADD = lib/libopenflow.a +stp_files = \ + tests/test-stp-ieee802.1d-1998 \ + tests/test-stp-ieee802.1d-2004-fig17.4 \ + tests/test-stp-ieee802.1d-2004-fig17.6 \ + tests/test-stp-ieee802.1d-2004-fig17.7 \ + tests/test-stp-iol-op-1.1 \ + tests/test-stp-iol-op-1.4 \ + tests/test-stp-iol-op-3.1 \ + tests/test-stp-iol-op-3.3 \ + tests/test-stp-iol-io-1.1 \ + tests/test-stp-iol-io-1.2 \ + tests/test-stp-iol-io-1.4 \ + tests/test-stp-iol-io-1.5 +TESTS_ENVIRONMENT += stp_files='$(stp_files)' + +EXTRA_DIST += $(stp_files) diff --git a/openflow/tests/flowgen.pl b/openflow/tests/flowgen.pl new file mode 100755 index 00000000..eb17b2af --- /dev/null +++ b/openflow/tests/flowgen.pl @@ -0,0 +1,224 @@ +#! /usr/bin/perl + +use strict; +use warnings; + +open(FLOWS, ">&=3");# or die "failed to open fd 3 for writing: $!\n"; +open(PACKETS, ">&=4");# or die "failed to open fd 4 for writing: $!\n"; + +# Print pcap file header. +print PACKETS pack('NnnNNNN', + 0xa1b2c3d4, # magic number + 2, # major version + 4, # minor version + 0, # time zone offset + 0, # time stamp accuracy + 1518, # snaplen + 1); # Ethernet + +output(DL_HEADER => '802.2'); + +for my $dl_header qw(802.2+SNAP Ethernet) { + my %a = (DL_HEADER => $dl_header); + for my $dl_vlan qw(none zero nonzero) { + my %b = (%a, DL_VLAN => $dl_vlan); + + # Non-IP case. + output(%b, DL_TYPE => 'non-ip'); + + for my $ip_options qw(no yes) { + my %c = (%b, DL_TYPE => 'ip', IP_OPTIONS => $ip_options); + for my $ip_fragment qw(no first middle last) { + my %d = (%c, IP_FRAGMENT => $ip_fragment); + for my $tp_proto qw(TCP TCP+options UDP ICMP other) { + output(%d, TP_PROTO => $tp_proto); + } + } + } + } +} + +sub output { + my (%attrs) = @_; + + # Compose flow. + my (%flow); + $flow{DL_SRC} = "00:02:e3:0f:80:a4"; + $flow{DL_DST} = "00:1a:92:40:ac:05"; + $flow{NW_PROTO} = 0; + $flow{NW_SRC} = '0.0.0.0'; + $flow{NW_DST} = '0.0.0.0'; + $flow{TP_SRC} = 0; + $flow{TP_DST} = 0; + if (defined($attrs{DL_VLAN})) { + my (%vlan_map) = ('none' => 0xffff, + 'zero' => 0, + 'nonzero' => 0x0123); + $flow{DL_VLAN} = $vlan_map{$attrs{DL_VLAN}}; + } else { + $flow{DL_VLAN} = 0xffff; # OFP_VLAN_NONE + } + if ($attrs{DL_HEADER} eq '802.2') { + $flow{DL_TYPE} = 0x5ff; # OFP_DL_TYPE_NOT_ETH_TYPE + } elsif ($attrs{DL_TYPE} eq 'ip') { + $flow{DL_TYPE} = 0x0800; # ETH_TYPE_IP + $flow{NW_SRC} = '10.0.2.15'; + $flow{NW_DST} = '192.168.1.20'; + if ($attrs{TP_PROTO} eq 'other') { + $flow{NW_PROTO} = 42; + } elsif ($attrs{TP_PROTO} eq 'TCP' || + $attrs{TP_PROTO} eq 'TCP+options') { + $flow{NW_PROTO} = 6; # IP_TYPE_TCP + $flow{TP_SRC} = 6667; + $flow{TP_DST} = 9998; + } elsif ($attrs{TP_PROTO} eq 'UDP') { + $flow{NW_PROTO} = 17; # IP_TYPE_UDP + $flow{TP_SRC} = 1112; + $flow{TP_DST} = 2223; + } elsif ($attrs{TP_PROTO} eq 'ICMP') { + $flow{NW_PROTO} = 1; # IP_TYPE_ICMP + $flow{TP_SRC} = 8; # echo request + $flow{TP_DST} = 0; # code + } else { + die; + } + if ($attrs{IP_FRAGMENT} ne 'no') { + $flow{TP_SRC} = $flow{TP_DST} = 0; + } + } elsif ($attrs{DL_TYPE} eq 'non-ip') { + $flow{DL_TYPE} = 0x5678; + } else { + die; + } + + # Compose packet. + my $packet = ''; + $packet .= pack_ethaddr($flow{DL_DST}); + $packet .= pack_ethaddr($flow{DL_SRC}); + $packet .= pack('n', 0) if $attrs{DL_HEADER} =~ /^802.2/; + if ($attrs{DL_HEADER} eq '802.2') { + $packet .= pack('CCC', 0x42, 0x42, 0x03); # LLC for 802.1D STP. + } else { + if ($attrs{DL_HEADER} eq '802.2+SNAP') { + $packet .= pack('CCC', 0xaa, 0xaa, 0x03); # LLC for SNAP. + $packet .= pack('CCC', 0, 0, 0); # SNAP OUI. + } + if ($attrs{DL_VLAN} ne 'none') { + $packet .= pack('nn', 0x8100, $flow{DL_VLAN}); + } + $packet .= pack('n', $flow{DL_TYPE}); + if ($attrs{DL_TYPE} eq 'ip') { + my $ip = pack('CCnnnCCnNN', + (4 << 4) | 5, # version, hdrlen + 0, # type of service + 0, # total length (filled in later) + 65432, # id + 0, # frag offset + 64, # ttl + $flow{NW_PROTO}, # protocol + 0, # checksum + 0x0a00020f, # source + 0xc0a80114); # dest + if ($attrs{IP_OPTIONS} eq 'yes') { + substr($ip, 0, 1) = pack('C', (4 << 4) | 8); + $ip .= pack('CCnnnCCCx', + 130, # type + 11, # length + 0x6bc5, # top secret + 0xabcd, + 0x1234, + 1, + 2, + 3); + } + if ($attrs{IP_FRAGMENT} ne 'no') { + my (%frag_map) = ('first' => 0x2000, # more frags, ofs 0 + 'middle' => 0x2111, # more frags, ofs 0x888 + 'last' => 0x0222); # last frag, ofs 0x1110 + substr($ip, 6, 2) + = pack('n', $frag_map{$attrs{IP_FRAGMENT}}); + } + + if ($attrs{TP_PROTO} =~ '^TCP') { + my $tcp = pack('nnNNnnnn', + $flow{TP_SRC}, # source port + $flow{TP_DST}, # dest port + 87123455, # seqno + 712378912, # ackno + (5 << 12) | 0x02 | 0x10, # hdrlen, SYN, ACK + 5823, # window size + 18923, # checksum + 12893); # urgent pointer + if ($attrs{TP_PROTO} eq 'TCP+options') { + substr($tcp, 12, 2) = pack('n', (6 << 12) | 0x02 | 0x10); + $tcp .= pack('CCn', 2, 4, 1975); # MSS option + } + $tcp .= 'payload'; + $ip .= $tcp; + } elsif ($attrs{TP_PROTO} eq 'UDP') { + my $len = 15; + my $udp = pack('nnnn', $flow{TP_SRC}, $flow{TP_DST}, $len, 0); + $udp .= chr($len) while length($udp) < $len; + $ip .= $udp; + } elsif ($attrs{TP_PROTO} eq 'ICMP') { + $ip .= pack('CCnnn', + 8, # echo request + 0, # code + 0, # checksum + 736, # identifier + 931); # sequence number + } elsif ($attrs{TP_PROTO} eq 'other') { + $ip .= 'other header'; + } else { + die; + } + + substr($ip, 2, 2) = pack('n', length($ip)); + $packet .= $ip; + } + } + substr($packet, 12, 2) = pack('n', length($packet)) + if $attrs{DL_HEADER} =~ /^802.2/; + + print join(' ', map("$_=$attrs{$_}", keys(%attrs))), "\n"; + print join(' ', map("$_=$flow{$_}", keys(%flow))), "\n"; + print "\n"; + + print FLOWS pack('Nn', + 0, # wildcards + 0); # in_port + print FLOWS pack_ethaddr($flow{DL_SRC}); + print FLOWS pack_ethaddr($flow{DL_DST}); + print FLOWS pack('nnCxNNnn', + $flow{DL_VLAN}, + $flow{DL_TYPE}, + $flow{NW_PROTO}, + inet_aton($flow{NW_SRC}), + inet_aton($flow{NW_DST}), + $flow{TP_SRC}, + $flow{TP_DST}); + + print PACKETS pack('NNNN', + 0, # timestamp seconds + 0, # timestamp microseconds + length($packet), # bytes saved + length($packet)), # total length + $packet; +} + +sub pack_ethaddr { + local ($_) = @_; + my $xx = '([0-9a-fA-F][0-9a-fA-F])'; + my (@octets) = /$xx:$xx:$xx:$xx:$xx:$xx/; + @octets == 6 or die $_; + my ($out) = ''; + $out .= pack('C', hex($_)) foreach @octets; + return $out; +} + +sub inet_aton { + local ($_) = @_; + my ($a, $b, $c, $d) = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/; + defined $d or die $_; + return ($a << 24) | ($b << 16) | ($c << 8) | $d; +} diff --git a/openflow/tests/test-dhcp-client.c b/openflow/tests/test-dhcp-client.c new file mode 100644 index 00000000..f8a1f427 --- /dev/null +++ b/openflow/tests/test-dhcp-client.c @@ -0,0 +1,206 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include "dhcp-client.h" +#include +#include +#include +#include +#include "command-line.h" +#include "dhcp.h" +#include "fatal-signal.h" +#include "fault.h" +#include "poll-loop.h" +#include "util.h" +#include "vlog.h" + +/* --request-ip: IP address to request from server. If zero, then do not + * request a specific IP address. */ +static struct in_addr request_ip; + +/* --vendor-class: Vendor class string to include in request. If null, no + * vendor class string is included. */ +static const char *vendor_class; + +/* --no-resolv-conf: Update /etc/resolv.conf to match DHCP reply? */ +static bool update_resolv_conf = true; + +static void parse_options(int argc, char *argv[]); +static void usage(void); +static void release(void *cli_); +static void modify_dhcp_request(struct dhcp_msg *, void *aux); + +int +main(int argc, char *argv[]) +{ + struct dhclient *cli; + int error; + + set_program_name(argv[0]); + register_fault_handlers(); + vlog_init(); + parse_options(argc, argv); + + argc -= optind; + argv += optind; + if (argc != 1) { + ofp_fatal(0, "exactly one non-option argument required; " + "use --help for help"); + } + + error = dhclient_create(argv[0], modify_dhcp_request, NULL, NULL, &cli); + if (error) { + ofp_fatal(error, "dhclient_create failed"); + } + dhclient_init(cli, request_ip.s_addr); + fatal_signal_add_hook(release, cli, true); + + for (;;) { + fatal_signal_block(); + dhclient_run(cli); + if (dhclient_changed(cli)) { + dhclient_configure_netdev(cli); + if (update_resolv_conf) { + dhclient_update_resolv_conf(cli); + } + } + dhclient_wait(cli); + fatal_signal_unblock(); + poll_block(); + } +} + +static void +release(void *cli_) +{ + struct dhclient *cli = cli_; + dhclient_release(cli); + if (dhclient_changed(cli)) { + dhclient_configure_netdev(cli); + } +} + +static void +modify_dhcp_request(struct dhcp_msg *msg, void *aux UNUSED) +{ + if (vendor_class) { + dhcp_msg_put_string(msg, DHCP_CODE_VENDOR_CLASS, vendor_class); + } +} + +static void +parse_options(int argc, char *argv[]) +{ + enum { + OPT_REQUEST_IP = UCHAR_MAX + 1, + OPT_VENDOR_CLASS, + OPT_NO_RESOLV_CONF + }; + static struct option long_options[] = { + {"request-ip", required_argument, 0, OPT_REQUEST_IP }, + {"vendor-class", required_argument, 0, OPT_VENDOR_CLASS }, + {"no-resolv-conf", no_argument, 0, OPT_NO_RESOLV_CONF}, + {"verbose", optional_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {0, 0, 0, 0}, + }; + char *short_options = long_options_to_short_options(long_options); + + for (;;) { + int c; + + c = getopt_long(argc, argv, short_options, long_options, NULL); + if (c == -1) { + break; + } + + switch (c) { + case OPT_REQUEST_IP: + if (!inet_aton(optarg, &request_ip)) { + ofp_fatal(0, + "--request-ip argument is not a valid IP address"); + } + break; + + case OPT_VENDOR_CLASS: + vendor_class = optarg; + break; + + case OPT_NO_RESOLV_CONF: + update_resolv_conf = false; + break; + + case 'h': + usage(); + + case 'V': + printf("%s %s compiled "__DATE__" "__TIME__"\n", + program_name, VERSION BUILDNR); + exit(EXIT_SUCCESS); + + case 'v': + vlog_set_verbosity(optarg); + break; + + case '?': + exit(EXIT_FAILURE); + + default: + abort(); + } + } + free(short_options); +} + +static void +usage(void) +{ + printf("%s: standalone program for testing OpenFlow DHCP client.\n" + "usage: %s [OPTIONS] NETDEV\n" + "where NETDEV is a network device (e.g. eth0).\n" + "\nDHCP options:\n" + " --request-ip=IP request specified IP address (default:\n" + " do not request a specific IP)\n" + " --vendor-class=STRING use STRING as vendor class (default:\n" + " none); use OpenFlow to imitate secchan\n" + " --no-resolv-conf do not update /etc/resolv.conf\n", + program_name, program_name); + vlog_usage(); + printf("\nOther options:\n" + " -h, --help display this help message\n" + " -V, --version display version information\n"); + exit(EXIT_SUCCESS); +} + diff --git a/openflow/tests/test-flows b/openflow/tests/test-flows new file mode 100755 index 0000000000000000000000000000000000000000..891f9547888703c22fd04673db3fa828eceb1131 GIT binary patch literal 286976 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 +#include "flow.h" +#include +#include +#include +#include "openflow/openflow.h" +#include "timeval.h" +#include "ofpbuf.h" +#include "ofp-print.h" +#include "pcap.h" +#include "util.h" +#include "vlog.h" + +#undef NDEBUG +#include + +int +main(int argc UNUSED, char *argv[]) +{ + struct ofp_match expected_match; + FILE *flows, *pcap; + int retval; + int n = 0, errors = 0; + + set_program_name(argv[0]); + time_init(); + vlog_init(); + + flows = stdin; + pcap = fdopen(3, "rb"); + if (!pcap) { + ofp_fatal(errno, "failed to open fd 3 for reading"); + } + + retval = pcap_read_header(pcap); + if (retval) { + ofp_fatal(retval > 0 ? retval : 0, "reading pcap header failed"); + } + + while (fread(&expected_match, sizeof expected_match, 1, flows)) { + struct ofpbuf *packet; + struct ofp_match extracted_match; + struct flow flow; + + n++; + + retval = pcap_read(pcap, &packet); + if (retval == EOF) { + ofp_fatal(0, "unexpected end of file reading pcap file"); + } else if (retval) { + ofp_fatal(retval, "error reading pcap file"); + } + + flow_extract(packet, 0, &flow); + flow_fill_match(&extracted_match, &flow, 0); + + if (memcmp(&expected_match, &extracted_match, sizeof expected_match)) { + char *exp_s = ofp_match_to_string(&expected_match, 2); + char *got_s = ofp_match_to_string(&extracted_match, 2); + errors++; + printf("mismatch on packet #%d (1-based).\n", n); + printf("Packet:\n"); + ofp_print_packet(stdout, packet->data, packet->size, packet->size); + printf("Expected flow:\n%s\n", exp_s); + printf("Actually extracted flow:\n%s\n", got_s); + printf("\n"); + free(exp_s); + free(got_s); + } + + ofpbuf_delete(packet); + } + printf("checked %d packets, %d errors\n", n, errors); + return errors != 0; +} + diff --git a/openflow/tests/test-flows.sh b/openflow/tests/test-flows.sh new file mode 100755 index 00000000..0d38ad78 --- /dev/null +++ b/openflow/tests/test-flows.sh @@ -0,0 +1,9 @@ +#! /bin/sh -e +srcdir=`cd $srcdir && pwd` +trap 'rm -f flows$$ pcap$$ out$$' 0 1 2 13 15 +cd tests +"$srcdir"/tests/flowgen.pl >/dev/null 3>flows$$ 4>pcap$$ +./test-flows out$$ || true +diff -u - out$$ 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 HGyVSu&X&XL literal 0 HcmV?d00001 diff --git a/openflow/tests/test-hmap.c b/openflow/tests/test-hmap.c new file mode 100644 index 00000000..962389fa --- /dev/null +++ b/openflow/tests/test-hmap.c @@ -0,0 +1,282 @@ +/* A non-exhaustive test for some of the functions and macros declared in + * hmap.h. */ + +#include +#include "hmap.h" +#include +#include "hash.h" +#include "util.h" + +#undef NDEBUG +#include + +/* Sample hmap element. */ +struct element { + int value; + struct hmap_node node; +}; + +typedef size_t hash_func(int value); + +static int +compare_ints(const void *a_, const void *b_) +{ + const int *a = a_; + const int *b = b_; + return *a < *b ? -1 : *a > *b; +} + +/* Verifies that 'hmap' contains exactly the 'n' values in 'values'. */ +static void +check_hmap(struct hmap *hmap, const int values[], size_t n, + hash_func *hash) +{ + int *sort_values, *hmap_values; + struct element *e; + size_t i; + + /* Check that all the values are there in iteration. */ + sort_values = xmalloc(sizeof *sort_values * n); + hmap_values = xmalloc(sizeof *sort_values * n); + + i = 0; + HMAP_FOR_EACH (e, struct element, node, hmap) { + assert(i < n); + hmap_values[i++] = e->value; + } + assert(i == n); + + memcpy(sort_values, values, sizeof *sort_values * n); + qsort(sort_values, n, sizeof *sort_values, compare_ints); + qsort(hmap_values, n, sizeof *hmap_values, compare_ints); + + for (i = 0; i < n; i++) { + assert(sort_values[i] == hmap_values[i]); + } + + free(hmap_values); + free(sort_values); + + /* Check that all the values are there in lookup. */ + for (i = 0; i < n; i++) { + size_t count = 0; + + HMAP_FOR_EACH_WITH_HASH (e, struct element, node, + hash(values[i]), hmap) { + count += e->value == values[i]; + } + assert(count == 1); + } + + /* Check counters. */ + assert(hmap_is_empty(hmap) == !n); + assert(hmap_count(hmap) == n); +} + +/* Puts the 'n' values in 'values' into 'elements', and then puts those + * elements into 'hmap'. */ +static void +make_hmap(struct hmap *hmap, struct element elements[], + int values[], size_t n, hash_func *hash) +{ + size_t i; + + hmap_init(hmap); + for (i = 0; i < n; i++) { + elements[i].value = i; + hmap_insert(hmap, &elements[i].node, hash(elements[i].value)); + values[i] = i; + } +} + +static void +shuffle(int *p, size_t n) +{ + for (; n > 1; n--, p++) { + int *q = &p[rand() % n]; + int tmp = *p; + *p = *q; + *q = tmp; + } +} + +#if 0 +/* Prints the values in 'hmap', plus 'name' as a title. */ +static void +print_hmap(const char *name, struct hmap *hmap) +{ + struct element *e; + + printf("%s:", name); + HMAP_FOR_EACH (e, struct element, node, hmap) { + printf(" %d(%zu)", e->value, e->node.hash & hmap->mask); + } + printf("\n"); +} + +/* Prints the 'n' values in 'values', plus 'name' as a title. */ +static void +print_ints(const char *name, const int *values, size_t n) +{ + size_t i; + + printf("%s:", name); + for (i = 0; i < n; i++) { + printf(" %d", values[i]); + } + printf("\n"); +} +#endif + +static size_t +identity_hash(int value) +{ + return value; +} + +static size_t +good_hash(int value) +{ + const uint32_t x = value; + return hash_words(&x, 1, 0x1234abcd); +} + +static size_t +constant_hash(int value UNUSED) +{ + return 123; +} + +/* Tests basic hmap insertion and deletion. */ +static void +test_hmap_insert_delete(hash_func *hash) +{ + enum { N_ELEMS = 100 }; + + struct element elements[N_ELEMS]; + int values[N_ELEMS]; + struct hmap hmap; + size_t i; + + hmap_init(&hmap); + for (i = 0; i < N_ELEMS; i++) { + elements[i].value = i; + hmap_insert(&hmap, &elements[i].node, hash(i)); + values[i] = i; + check_hmap(&hmap, values, i + 1, hash); + } + shuffle(values, N_ELEMS); + for (i = 0; i < N_ELEMS; i++) { + hmap_remove(&hmap, &elements[values[i]].node); + check_hmap(&hmap, values + (i + 1), N_ELEMS - (i + 1), hash); + } + hmap_destroy(&hmap); +} + +/* Tests basic hmap_reserve() and hmap_shrink(). */ +static void +test_hmap_reserve_shrink(hash_func *hash) +{ + enum { N_ELEMS = 32 }; + + size_t i; + + for (i = 0; i < N_ELEMS; i++) { + struct element elements[N_ELEMS]; + int values[N_ELEMS]; + struct hmap hmap; + size_t j; + + hmap_init(&hmap); + hmap_reserve(&hmap, i); + for (j = 0; j < N_ELEMS; j++) { + elements[j].value = j; + hmap_insert(&hmap, &elements[j].node, hash(j)); + values[j] = j; + check_hmap(&hmap, values, j + 1, hash); + } + shuffle(values, N_ELEMS); + for (j = 0; j < N_ELEMS; j++) { + hmap_remove(&hmap, &elements[values[j]].node); + hmap_shrink(&hmap); + check_hmap(&hmap, values + (j + 1), N_ELEMS - (j + 1), hash); + } + hmap_destroy(&hmap); + } +} + +/* Tests that HMAP_FOR_EACH_SAFE properly allows for deletion of the current + * element of a hmap. */ +static void +test_hmap_for_each_safe(hash_func *hash) +{ + enum { MAX_ELEMS = 10 }; + size_t n; + unsigned long int pattern; + + for (n = 0; n <= MAX_ELEMS; n++) { + for (pattern = 0; pattern < 1ul << n; pattern++) { + struct element elements[MAX_ELEMS]; + int values[MAX_ELEMS]; + struct hmap hmap; + struct element *e, *next; + size_t n_remaining; + int i; + + make_hmap(&hmap, elements, values, n, hash); + + i = 0; + n_remaining = n; + HMAP_FOR_EACH_SAFE (e, next, struct element, node, &hmap) { + assert(i < n); + if (pattern & (1ul << e->value)) { + size_t j; + hmap_remove(&hmap, &e->node); + for (j = 0; ; j++) { + assert(j < n_remaining); + if (values[j] == e->value) { + values[j] = values[--n_remaining]; + break; + } + } + } + check_hmap(&hmap, values, n_remaining, hash); + i++; + } + assert(i == n); + + for (i = 0; i < n; i++) { + if (pattern & (1ul << i)) { + n_remaining++; + } + } + assert(n == n_remaining); + + hmap_destroy(&hmap); + } + } +} + +static void +run_test(void (*function)(hash_func *)) +{ + hash_func *hash_funcs[] = { identity_hash, good_hash, constant_hash }; + size_t i; + + for (i = 0; i < ARRAY_SIZE(hash_funcs); i++) { + function(hash_funcs[i]); + printf("."); + fflush(stdout); + } +} + +int +main(void) +{ + run_test(test_hmap_insert_delete); + run_test(test_hmap_for_each_safe); + run_test(test_hmap_reserve_shrink); + printf("\n"); + return 0; +} + diff --git a/openflow/tests/test-list.c b/openflow/tests/test-list.c new file mode 100644 index 00000000..62857be9 --- /dev/null +++ b/openflow/tests/test-list.c @@ -0,0 +1,159 @@ +/* A non-exhaustive test for some of the functions and macros declared in + * list.h. */ + +#include +#include "list.h" +#include + +#undef NDEBUG +#include + +/* Sample list element. */ +struct element { + int value; + struct list node; +}; + +/* Puts the 'n' values in 'values' into 'elements', and then puts those + * elements in order into 'list'. */ +static void +make_list(struct list *list, struct element elements[], + int values[], size_t n) +{ + size_t i; + + list_init(list); + for (i = 0; i < n; i++) { + elements[i].value = i; + list_push_back(list, &elements[i].node); + values[i] = i; + } +} + +/* Verifies that 'list' contains exactly the 'n' values in 'values', in the + * specified order. */ +static void +check_list(struct list *list, const int values[], size_t n) +{ + struct element *e; + size_t i; + + i = 0; + LIST_FOR_EACH (e, struct element, node, list) { + assert(i < n); + assert(e->value == values[i]); + i++; + } + assert(&e->node == list); + assert(i == n); + + i = 0; + LIST_FOR_EACH_REVERSE (e, struct element, node, list) { + assert(i < n); + assert(e->value == values[n - i - 1]); + i++; + } + assert(&e->node == list); + assert(i == n); + + assert(list_is_empty(list) == !n); + assert(list_size(list) == n); +} + +#if 0 +/* Prints the values in 'list', plus 'name' as a title. */ +static void +print_list(const char *name, struct list *list) +{ + struct element *e; + + printf("%s:", name); + LIST_FOR_EACH (e, struct element, node, list) { + printf(" %d", e->value); + } + printf("\n"); +} +#endif + +/* Tests basic list construction. */ +static void +test_list_construction(void) +{ + enum { MAX_ELEMS = 100 }; + size_t n; + + for (n = 0; n <= MAX_ELEMS; n++) { + struct element elements[MAX_ELEMS]; + int values[MAX_ELEMS]; + struct list list; + + make_list(&list, elements, values, n); + check_list(&list, values, n); + } +} + +/* Tests that LIST_FOR_EACH_SAFE properly allows for deletion of the current + * element of a list. */ +static void +test_list_for_each_safe(void) +{ + enum { MAX_ELEMS = 10 }; + size_t n; + unsigned long int pattern; + + for (n = 0; n <= MAX_ELEMS; n++) { + for (pattern = 0; pattern < 1ul << n; pattern++) { + struct element elements[MAX_ELEMS]; + int values[MAX_ELEMS]; + struct list list; + struct element *e, *next; + size_t values_idx, n_remaining; + int i; + + make_list(&list, elements, values, n); + + i = 0; + values_idx = 0; + n_remaining = n; + LIST_FOR_EACH_SAFE (e, next, struct element, node, &list) { + assert(i < n); + if (pattern & (1ul << i)) { + list_remove(&e->node); + n_remaining--; + memmove(&values[values_idx], &values[values_idx + 1], + sizeof *values * (n_remaining - values_idx)); + } else { + values_idx++; + } + check_list(&list, values, n_remaining); + i++; + } + assert(i == n); + assert(&e->node == &list); + + for (i = 0; i < n; i++) { + if (pattern & (1ul << i)) { + n_remaining++; + } + } + assert(n == n_remaining); + } + } +} + +static void +run_test(void (*function)(void)) +{ + function(); + printf("."); +} + +int +main(void) +{ + run_test(test_list_construction); + run_test(test_list_for_each_safe); + printf("\n"); + return 0; +} + diff --git a/openflow/tests/test-stp-ieee802.1d-1998 b/openflow/tests/test-stp-ieee802.1d-1998 new file mode 100644 index 00000000..f1982a03 --- /dev/null +++ b/openflow/tests/test-stp-ieee802.1d-1998 @@ -0,0 +1,12 @@ +# This is the STP example from IEEE 802.1D-1998. +bridge 0 0x42 = a b +bridge 1 0x97 = c:5 a d:5 +bridge 2 0x45 = b e +bridge 3 0x57 = b:5 e:5 +bridge 4 0x83 = a:5 e:5 +run 1000 +check 0 = root +check 1 = F F:10 F +check 2 = F:10 B +check 3 = F:5 F +check 4 = F:5 B diff --git a/openflow/tests/test-stp-ieee802.1d-2004-fig17.4 b/openflow/tests/test-stp-ieee802.1d-2004-fig17.4 new file mode 100644 index 00000000..1f708630 --- /dev/null +++ b/openflow/tests/test-stp-ieee802.1d-2004-fig17.4 @@ -0,0 +1,31 @@ +# This is the STP example from IEEE 802.1D-2004 figures 17.4 and 17.5. +bridge 0 0x111 = a b e c +bridge 1 0x222 = a b d f +bridge 2 0x333 = c d l j h g +bridge 3 0x444 = e f n m k i +bridge 4 0x555 = g i 0 0 +bridge 5 0x666 = h k 0 0 +bridge 6 0x777 = j m 0 0 +bridge 7 0x888 = l n 0 0 +run 1000 +check 0 = root +check 1 = F:10 B F F +check 2 = F:10 B F F F F +check 3 = F:10 B F F F F +check 4 = F:20 B F F +check 5 = F:20 B F F +check 6 = F:20 B F F +check 7 = F:20 B F F + +# Now connect two ports of bridge 7 to the same LAN. +bridge 7 = l n o o +# Same results except for bridge 7: +run 1000 +check 0 = root +check 1 = F:10 B F F +check 2 = F:10 B F F F F +check 3 = F:10 B F F F F +check 4 = F:20 B F F +check 5 = F:20 B F F +check 6 = F:20 B F F +check 7 = F:20 B F B diff --git a/openflow/tests/test-stp-ieee802.1d-2004-fig17.6 b/openflow/tests/test-stp-ieee802.1d-2004-fig17.6 new file mode 100644 index 00000000..6ed59177 --- /dev/null +++ b/openflow/tests/test-stp-ieee802.1d-2004-fig17.6 @@ -0,0 +1,14 @@ +# This is the STP example from IEEE 802.1D-2004 figure 17.6. +bridge 0 0x111 = a b l +bridge 1 0x222 = b c d +bridge 2 0x333 = d e f +bridge 3 0x444 = f g h +bridge 4 0x555 = j h i +bridge 5 0x666 = l j k +run 1000 +check 0 = root +check 1 = F:10 F F +check 2 = F:20 F F +check 3 = F:30 F B +check 4 = F:20 F F +check 5 = F:10 F F diff --git a/openflow/tests/test-stp-ieee802.1d-2004-fig17.7 b/openflow/tests/test-stp-ieee802.1d-2004-fig17.7 new file mode 100644 index 00000000..daa0cdf2 --- /dev/null +++ b/openflow/tests/test-stp-ieee802.1d-2004-fig17.7 @@ -0,0 +1,17 @@ +# This is the STP example from IEEE 802.1D-2004 figure 17.7. +bridge 0 0xaa = b +bridge 1 0x111 = a b d f h g e c +bridge 2 0x222 = g h j l n m k i +run 1000 +check 0 = root +check 1 = F F:10 F F F F F F +check 2 = B F:20 F F F F F F + +# This is not the port priority change described in that figure, +# but I don't understand what port priority change would cause +# that change. +bridge 2 = g X j l n m k i +run 1000 +check 0 = root +check 1 = F F:10 F F F F F F +check 2 = F:20 D F F F F F F diff --git a/openflow/tests/test-stp-iol-io-1.1 b/openflow/tests/test-stp-iol-io-1.1 new file mode 100644 index 00000000..186d6c4c --- /dev/null +++ b/openflow/tests/test-stp-iol-io-1.1 @@ -0,0 +1,25 @@ +# This test file approximates the following test from "Bridge +# Functions Consortium Spanning Tree Interoperability Test Suite +# Version 1.5": +# STP.io.1.1: Link Failure +bridge 0 0x111 = a b c +bridge 1 0x222 = a b c +run 1000 +check 0 = root +check 1 = F:10 B B +bridge 1 = 0 _ _ +run 1000 +check 0 = root +check 1 = F F:10 B +bridge 1 = X _ _ +run 1000 +check 0 = root +check 1 = D F:10 B +bridge 1 = _ 0 _ +run 1000 +check 0 = root +check 1 = D F F:10 +bridge 1 = _ X _ +run 1000 +check 0 = root +check 1 = D D F:10 diff --git a/openflow/tests/test-stp-iol-io-1.2 b/openflow/tests/test-stp-iol-io-1.2 new file mode 100644 index 00000000..285bbd88 --- /dev/null +++ b/openflow/tests/test-stp-iol-io-1.2 @@ -0,0 +1,14 @@ +# This test file approximates the following test from "Bridge +# Functions Consortium Spanning Tree Interoperability Test Suite +# Version 1.5": +# STP.io.1.2: Repeated Network +bridge 0 0x111 = a a +bridge 1 0x222 = a a +run 1000 +check 0 = rootid:0x111 F B +check 1 = rootid:0x111 F:10 B +bridge 1 = a^0x90 _ +run 1000 +check 0 = rootid:0x111 F B +check 1 = rootid:0x111 B F:10 + diff --git a/openflow/tests/test-stp-iol-io-1.4 b/openflow/tests/test-stp-iol-io-1.4 new file mode 100644 index 00000000..0065aaf5 --- /dev/null +++ b/openflow/tests/test-stp-iol-io-1.4 @@ -0,0 +1,13 @@ +# This test file approximates the following test from "Bridge +# Functions Consortium Spanning Tree Interoperability Test Suite +# Version 1.5": +# STP.io.1.4: Network Initialization +bridge 0 0x111 = a b c +bridge 1 0x222 = b d e +bridge 2 0x333 = a d f +bridge 3 0x444 = c e f +run 1000 +check 0 = root +check 1 = F:10 F F +check 2 = F:10 B F +check 3 = F:10 B B diff --git a/openflow/tests/test-stp-iol-io-1.5 b/openflow/tests/test-stp-iol-io-1.5 new file mode 100644 index 00000000..285d29de --- /dev/null +++ b/openflow/tests/test-stp-iol-io-1.5 @@ -0,0 +1,40 @@ +# This test file approximates the following test from "Bridge +# Functions Consortium Spanning Tree Interoperability Test Suite +# Version 1.5": +# STP.io.1.5: Topology Change +bridge 0 0x111 = a b d c +bridge 1 0x222 = a b f e +bridge 2 0x333 = c d g h +bridge 3 0x444 = e f g h +run 1000 +check 0 = root +check 1 = F:10 B F F +check 2 = B F:10 F F +check 3 = B F:20 B B +bridge 1^0x7000 +run 1000 +check 0 = F:10 B F F +check 1 = root +check 2 = B F:20 B B +check 3 = B F:10 F F +bridge 2^0x6000 +run 1000 +check 0 = F F B F:10 +check 1 = F:20 B B B +check 2 = root +check 3 = F F F:10 B +bridge 3^0x5000 +run 1000 +check 0 = B B B F:20 +check 1 = F F B F:10 +check 2 = F F F:10 B +check 3 = root +bridge 0^0x4000 +bridge 1^0x4001 +bridge 2^0x4002 +bridge 3^0x4003 +run 1000 +check 0 = root +check 1 = F:10 B F F +check 2 = B F:10 F F +check 3 = B F:20 B B diff --git a/openflow/tests/test-stp-iol-op-1.1 b/openflow/tests/test-stp-iol-op-1.1 new file mode 100644 index 00000000..8432bf36 --- /dev/null +++ b/openflow/tests/test-stp-iol-op-1.1 @@ -0,0 +1,7 @@ +# This test file approximates the following tests from "Bridge +# Functions Consortium Spanning Tree Protocol Operations Test Suite +# Version 2.3": +# Test STP.op.1.1 ­ Root ID Initialized to Bridge ID +# Test STP.op.1.2 ­ Root Path Cost Initialized to Zero +bridge 0 0x123 = +check 0 = root diff --git a/openflow/tests/test-stp-iol-op-1.4 b/openflow/tests/test-stp-iol-op-1.4 new file mode 100644 index 00000000..6a121164 --- /dev/null +++ b/openflow/tests/test-stp-iol-op-1.4 @@ -0,0 +1,8 @@ +# This test file approximates the following test from "Bridge +# Functions Consortium Spanning Tree Protocol Operations Test Suite +# Version 2.3": +# Test STP.op.1.4 ­ All Ports Initialized to Designated Ports +bridge 0 0x123 = a b c d e f +check 0 = Li Li Li Li Li Li +run 1000 +check 0 = F F F F F F diff --git a/openflow/tests/test-stp-iol-op-3.1 b/openflow/tests/test-stp-iol-op-3.1 new file mode 100644 index 00000000..3e1099cb --- /dev/null +++ b/openflow/tests/test-stp-iol-op-3.1 @@ -0,0 +1,11 @@ +# This test file approximates the following test from "Bridge +# Functions Consortium Spanning Tree Protocol Operations Test Suite +# Version 2.3": +# Test STP.op.3.1 ­ Root Bridge Selection: Root ID Values +bridge 0 0x111 = a +bridge 1 0x222 = a +check 0 = rootid:0x111 Li +check 1 = rootid:0x222 Li +run 1000 +check 0 = rootid:0x111 root +check 1 = rootid:0x111 F:10 diff --git a/openflow/tests/test-stp-iol-op-3.3 b/openflow/tests/test-stp-iol-op-3.3 new file mode 100644 index 00000000..2bcd45e1 --- /dev/null +++ b/openflow/tests/test-stp-iol-op-3.3 @@ -0,0 +1,11 @@ +# This test file approximates the following test from "Bridge +# Functions Consortium Spanning Tree Protocol Operations Test Suite +# Version 2.3": +# Test STP.op.3.3 ­ Root Bridge Selection: Bridge ID Values +bridge 0 0x333^0x6000 = a +bridge 1 0x222^0x7000 = b +bridge 2 0x111 = a b +run 1000 +check 0 = rootid:0x333^0x6000 root +check 1 = rootid:0x333^0x6000 F:20 +check 2 = rootid:0x333^0x6000 F:10 F diff --git a/openflow/tests/test-stp-iol-op-3.4 b/openflow/tests/test-stp-iol-op-3.4 new file mode 100644 index 00000000..2bcd45e1 --- /dev/null +++ b/openflow/tests/test-stp-iol-op-3.4 @@ -0,0 +1,11 @@ +# This test file approximates the following test from "Bridge +# Functions Consortium Spanning Tree Protocol Operations Test Suite +# Version 2.3": +# Test STP.op.3.3 ­ Root Bridge Selection: Bridge ID Values +bridge 0 0x333^0x6000 = a +bridge 1 0x222^0x7000 = b +bridge 2 0x111 = a b +run 1000 +check 0 = rootid:0x333^0x6000 root +check 1 = rootid:0x333^0x6000 F:20 +check 2 = rootid:0x333^0x6000 F:10 F diff --git a/openflow/tests/test-stp.c b/openflow/tests/test-stp.c new file mode 100644 index 00000000..ddb7db7e --- /dev/null +++ b/openflow/tests/test-stp.c @@ -0,0 +1,665 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include "stp.h" +#include +#include +#include +#include +#include +#include +#include "ofpbuf.h" +#include "packets.h" + +struct bpdu { + int port_no; + void *data; + size_t size; +}; + +struct bridge { + struct test_case *tc; + int id; + bool reached; + + struct stp *stp; + + struct lan *ports[STP_MAX_PORTS]; + int n_ports; + +#define RXQ_SIZE 16 + struct bpdu rxq[RXQ_SIZE]; + int rxq_head, rxq_tail; +}; + +struct lan_conn { + struct bridge *bridge; + int port_no; +}; + +struct lan { + struct test_case *tc; + const char *name; + bool reached; + struct lan_conn conns[16]; + int n_conns; +}; + +struct test_case { + struct bridge *bridges[16]; + int n_bridges; + struct lan *lans[26]; + int n_lans; +}; + +static const char *file_name; +static int line_number; +static char line[128]; +static char *pos, *token; +static int n_warnings; + +static struct test_case * +new_test_case(void) +{ + struct test_case *tc = xmalloc(sizeof *tc); + tc->n_bridges = 0; + tc->n_lans = 0; + return tc; +} + +static void +send_bpdu(struct ofpbuf *pkt, int port_no, void *b_) +{ + struct bridge *b = b_; + struct lan *lan; + + assert(port_no < b->n_ports); + lan = b->ports[port_no]; + if (lan) { + const void *data = pkt->l3; + size_t size = (char *) ofpbuf_tail(pkt) - (char *) data; + int i; + + for (i = 0; i < lan->n_conns; i++) { + struct lan_conn *conn = &lan->conns[i]; + if (conn->bridge != b || conn->port_no != port_no) { + struct bridge *dst = conn->bridge; + struct bpdu *bpdu = &dst->rxq[dst->rxq_head++ % RXQ_SIZE]; + assert(dst->rxq_head - dst->rxq_tail <= RXQ_SIZE); + bpdu->data = xmemdup(data, size); + bpdu->size = size; + bpdu->port_no = conn->port_no; + } + } + } + ofpbuf_delete(pkt); +} + +static struct bridge * +new_bridge(struct test_case *tc, int id) +{ + struct bridge *b = xmalloc(sizeof *b); + char name[16]; + b->tc = tc; + b->id = id; + snprintf(name, sizeof name, "stp%x", id); + b->stp = stp_create(name, id, send_bpdu, b); + assert(tc->n_bridges < ARRAY_SIZE(tc->bridges)); + b->n_ports = 0; + b->rxq_head = b->rxq_tail = 0; + tc->bridges[tc->n_bridges++] = b; + return b; +} + +static struct lan * +new_lan(struct test_case *tc, const char *name) +{ + struct lan *lan = xmalloc(sizeof *lan); + lan->tc = tc; + lan->name = xstrdup(name); + lan->n_conns = 0; + assert(tc->n_lans < ARRAY_SIZE(tc->lans)); + tc->lans[tc->n_lans++] = lan; + return lan; +} + +static void +reconnect_port(struct bridge *b, int port_no, struct lan *new_lan) +{ + struct lan *old_lan; + int j; + + assert(port_no < b->n_ports); + old_lan = b->ports[port_no]; + if (old_lan == new_lan) { + return; + } + + /* Disconnect from old_lan. */ + if (old_lan) { + for (j = 0; j < old_lan->n_conns; j++) { + struct lan_conn *c = &old_lan->conns[j]; + if (c->bridge == b && c->port_no == port_no) { + memmove(c, c + 1, sizeof *c * (old_lan->n_conns - j - 1)); + old_lan->n_conns--; + break; + } + } + } + + /* Connect to new_lan. */ + b->ports[port_no] = new_lan; + if (new_lan) { + int conn_no = new_lan->n_conns++; + assert(conn_no < ARRAY_SIZE(new_lan->conns)); + new_lan->conns[conn_no].bridge = b; + new_lan->conns[conn_no].port_no = port_no; + } +} + +static void +new_port(struct bridge *b, struct lan *lan, int path_cost) +{ + int port_no = b->n_ports++; + struct stp_port *p = stp_get_port(b->stp, port_no); + assert(port_no < ARRAY_SIZE(b->ports)); + b->ports[port_no] = NULL; + stp_port_set_path_cost(p, path_cost); + stp_port_enable(p); + reconnect_port(b, port_no, lan); +} + +static void +dump(struct test_case *tc) +{ + int i; + + for (i = 0; i < tc->n_bridges; i++) { + struct bridge *b = tc->bridges[i]; + struct stp *stp = b->stp; + int j; + + printf("%s:", stp_get_name(stp)); + if (stp_is_root_bridge(stp)) { + printf(" root"); + } + printf("\n"); + for (j = 0; j < b->n_ports; j++) { + struct stp_port *p = stp_get_port(stp, j); + enum stp_state state = stp_port_get_state(p); + + printf("\tport %d", j); + if (b->ports[j]) { + printf(" (lan %s)", b->ports[j]->name); + } else { + printf(" (disconnected)"); + } + printf(": %s", stp_state_name(state)); + if (p == stp_get_root_port(stp)) { + printf(" (root port, root_path_cost=%u)", stp_get_root_path_cost(stp)); + } + printf("\n"); + } + } +} + +static void dump_lan_tree(struct test_case *, struct lan *, int level); + +static void +dump_bridge_tree(struct test_case *tc, struct bridge *b, int level) +{ + int i; + + if (b->reached) { + return; + } + b->reached = true; + for (i = 0; i < level; i++) { + printf("\t"); + } + printf("%s\n", stp_get_name(b->stp)); + for (i = 0; i < b->n_ports; i++) { + struct lan *lan = b->ports[i]; + struct stp_port *p = stp_get_port(b->stp, i); + if (stp_port_get_state(p) == STP_FORWARDING && lan) { + dump_lan_tree(tc, lan, level + 1); + } + } +} + +static void +dump_lan_tree(struct test_case *tc, struct lan *lan, int level) +{ + int i; + + if (lan->reached) { + return; + } + lan->reached = true; + for (i = 0; i < level; i++) { + printf("\t"); + } + printf("%s\n", lan->name); + for (i = 0; i < lan->n_conns; i++) { + struct bridge *b = lan->conns[i].bridge; + dump_bridge_tree(tc, b, level + 1); + } +} + +static void +tree(struct test_case *tc) +{ + int i; + + for (i = 0; i < tc->n_bridges; i++) { + struct bridge *b = tc->bridges[i]; + b->reached = false; + } + for (i = 0; i < tc->n_lans; i++) { + struct lan *lan = tc->lans[i]; + lan->reached = false; + } + for (i = 0; i < tc->n_bridges; i++) { + struct bridge *b = tc->bridges[i]; + struct stp *stp = b->stp; + if (stp_is_root_bridge(stp)) { + dump_bridge_tree(tc, b, 0); + } + } +} + +static void +simulate(struct test_case *tc, int granularity) +{ + int time; + + for (time = 0; time < 1000 * 180; time += granularity) { + int round_trips; + int i; + + for (i = 0; i < tc->n_bridges; i++) { + stp_tick(tc->bridges[i]->stp, granularity); + } + for (round_trips = 0; round_trips < granularity; round_trips++) { + bool any = false; + for (i = 0; i < tc->n_bridges; i++) { + struct bridge *b = tc->bridges[i]; + for (; b->rxq_tail != b->rxq_head; b->rxq_tail++) { + struct bpdu *bpdu = &b->rxq[b->rxq_tail % RXQ_SIZE]; + stp_received_bpdu(stp_get_port(b->stp, bpdu->port_no), + bpdu->data, bpdu->size); + any = true; + } + } + if (!any) { + break; + } + } + } +} + +static void +err(const char *message, ...) + PRINTF_FORMAT(1, 2) + NO_RETURN; + +static void +err(const char *message, ...) +{ + va_list args; + + fprintf(stderr, "%s:%d:%td: ", file_name, line_number, pos - line); + va_start(args, message); + vfprintf(stderr, message, args); + va_end(args); + putc('\n', stderr); + + exit(EXIT_FAILURE); +} + +static void +warn(const char *message, ...) + PRINTF_FORMAT(1, 2); + +static void +warn(const char *message, ...) +{ + va_list args; + + fprintf(stderr, "%s:%d: ", file_name, line_number); + va_start(args, message); + vfprintf(stderr, message, args); + va_end(args); + putc('\n', stderr); + + n_warnings++; +} + +static bool +get_token(void) +{ + char *start; + + while (isspace((unsigned char) *pos)) { + pos++; + } + if (*pos == '\0') { + token = NULL; + return false; + } + + start = pos; + if (isalpha((unsigned char) *pos)) { + while (isalpha((unsigned char) *++pos)) { + continue; + } + } else if (isdigit((unsigned char) *pos)) { + if (*pos == '0' && (pos[1] == 'x' || pos[1] == 'X')) { + pos += 2; + while (isxdigit((unsigned char) *pos)) { + pos++; + } + } else { + while (isdigit((unsigned char) *++pos)) { + continue; + } + } + } else { + pos++; + } + + free(token); + token = xmemdup0(start, pos - start); + return true; +} + +static bool +get_int(int *intp) +{ + char *save_pos = pos; + if (token && isdigit((unsigned char) *token)) { + *intp = strtol(token, NULL, 0); + get_token(); + return true; + } else { + pos = save_pos; + return false; + } +} + +static bool +match(const char *want) +{ + if (token && !strcmp(want, token)) { + get_token(); + return true; + } else { + return false; + } +} + +static int +must_get_int(void) +{ + int x; + if (!get_int(&x)) { + err("expected integer"); + } + return x; +} + +static void +must_match(const char *want) +{ + if (!match(want)) { + err("expected \"%s\"", want); + } +} + +int +main(int argc, char *argv[]) +{ + struct test_case *tc; + FILE *input_file; + int i; + + if (argc != 2) { + ofp_fatal(0, "usage: test-stp INPUT.STP\n"); + } + file_name = argv[1]; + + input_file = fopen(file_name, "r"); + if (!input_file) { + ofp_fatal(errno, "error opening \"%s\"", file_name); + } + + tc = new_test_case(); + for (i = 0; i < 26; i++) { + char name[2]; + name[0] = 'a' + i; + name[1] = '\0'; + new_lan(tc, name); + } + + for (line_number = 1; fgets(line, sizeof line, input_file); + line_number++) + { + char *newline, *hash; + + newline = strchr(line, '\n'); + if (newline) { + *newline = '\0'; + } + hash = strchr(line, '#'); + if (hash) { + *hash = '\0'; + } + + pos = line; + if (!get_token()) { + continue; + } + if (match("bridge")) { + struct bridge *bridge; + int bridge_no, port_no; + + bridge_no = must_get_int(); + if (bridge_no < tc->n_bridges) { + bridge = tc->bridges[bridge_no]; + } else if (bridge_no == tc->n_bridges) { + bridge = new_bridge(tc, must_get_int()); + } else { + err("bridges must be numbered consecutively from 0"); + } + if (match("^")) { + stp_set_bridge_priority(bridge->stp, must_get_int()); + } + + if (match("=")) { + for (port_no = 0; port_no < STP_MAX_PORTS; port_no++) { + struct stp_port *p = stp_get_port(bridge->stp, port_no); + if (!token || match("X")) { + stp_port_disable(p); + } else if (match("_")) { + /* Nothing to do. */ + } else { + struct lan *lan; + int path_cost; + + if (!strcmp(token, "0")) { + lan = NULL; + } else if (strlen(token) == 1 && islower(*token)) { + lan = tc->lans[*token - 'a']; + } else { + err("%s is not a valid LAN name " + "(0 or a lowercase letter)", token); + } + get_token(); + + path_cost = match(":") ? must_get_int() : 10; + if (port_no < bridge->n_ports) { + stp_port_set_path_cost(p, path_cost); + stp_port_enable(p); + reconnect_port(bridge, port_no, lan); + } else if (port_no == bridge->n_ports) { + new_port(bridge, lan, path_cost); + } else { + err("ports must be numbered consecutively"); + } + if (match("^")) { + stp_port_set_priority(p, must_get_int()); + } + } + } + } + } else if (match("run")) { + simulate(tc, must_get_int()); + } else if (match("dump")) { + dump(tc); + } else if (match("tree")) { + tree(tc); + } else if (match("check")) { + struct bridge *b; + struct stp *stp; + int bridge_no, port_no; + + bridge_no = must_get_int(); + if (bridge_no >= tc->n_bridges) { + err("no bridge numbered %d", bridge_no); + } + b = tc->bridges[bridge_no]; + stp = b->stp; + + must_match("="); + + if (match("rootid")) { + uint64_t rootid; + must_match(":"); + rootid = must_get_int(); + if (match("^")) { + rootid |= (uint64_t) must_get_int() << 48; + } else { + rootid |= UINT64_C(0x8000) << 48; + } + if (stp_get_designated_root(stp) != rootid) { + warn("%s: root %"PRIx64", not %"PRIx64, + stp_get_name(stp), stp_get_designated_root(stp), + rootid); + } + } + + if (match("root")) { + if (stp_get_root_path_cost(stp)) { + warn("%s: root path cost of root is %u but should be 0", + stp_get_name(stp), stp_get_root_path_cost(stp)); + } + if (!stp_is_root_bridge(stp)) { + warn("%s: root is %"PRIx64", not %"PRIx64, + stp_get_name(stp), + stp_get_designated_root(stp), stp_get_bridge_id(stp)); + } + for (port_no = 0; port_no < b->n_ports; port_no++) { + struct stp_port *p = stp_get_port(stp, port_no); + enum stp_state state = stp_port_get_state(p); + if (!(state & (STP_DISABLED | STP_FORWARDING))) { + warn("%s: root port %d in state %s", + stp_get_name(b->stp), port_no, + stp_state_name(state)); + } + } + } else { + for (port_no = 0; port_no < STP_MAX_PORTS; port_no++) { + struct stp_port *p = stp_get_port(stp, port_no); + enum stp_state state; + if (token == NULL || match("D")) { + state = STP_DISABLED; + } else if (match("B")) { + state = STP_BLOCKING; + } else if (match("Li")) { + state = STP_LISTENING; + } else if (match("Le")) { + state = STP_LEARNING; + } else if (match("F")) { + state = STP_FORWARDING; + } else if (match("_")) { + continue; + } else { + err("unknown port state %s", token); + } + if (stp_port_get_state(p) != state) { + warn("%s port %d: state is %s but should be %s", + stp_get_name(stp), port_no, + stp_state_name(stp_port_get_state(p)), + stp_state_name(state)); + } + if (state == STP_FORWARDING) { + struct stp_port *root_port = stp_get_root_port(stp); + if (match(":")) { + int root_path_cost = must_get_int(); + if (p != root_port) { + warn("%s: port %d is not the root port", + stp_get_name(stp), port_no); + if (!root_port) { + warn("%s: (there is no root port)", + stp_get_name(stp)); + } else { + warn("%s: (port %d is the root port)", + stp_get_name(stp), + stp_port_no(root_port)); + } + } else if (root_path_cost + != stp_get_root_path_cost(stp)) { + warn("%s: root path cost is %u, should be %d", + stp_get_name(stp), + stp_get_root_path_cost(stp), + root_path_cost); + } + } else if (p == root_port) { + warn("%s: port %d is the root port but " + "not expected to be", + stp_get_name(stp), port_no); + } + } + } + } + if (n_warnings) { + exit(EXIT_FAILURE); + } + } + if (get_token()) { + err("trailing garbage on line"); + } + } + + return 0; +} diff --git a/openflow/tests/test-stp.sh b/openflow/tests/test-stp.sh new file mode 100755 index 00000000..fd6acf54 --- /dev/null +++ b/openflow/tests/test-stp.sh @@ -0,0 +1,7 @@ +#! /bin/sh +set -e +progress= +for d in ${stp_files}; do + echo "Testing $d..." + $SUPERVISOR ./tests/test-stp ${srcdir}/$d +done diff --git a/openflow/tests/test-type-props.c b/openflow/tests/test-type-props.c new file mode 100644 index 00000000..67dabae8 --- /dev/null +++ b/openflow/tests/test-type-props.c @@ -0,0 +1,41 @@ +#include +#include "type-props.h" +#include +#include + +#define MUST_SUCCEED(EXPRESSION) \ + if (!(EXPRESSION)) { \ + fprintf(stderr, "%s:%d: %s failed\n", \ + __FILE__, __LINE__, #EXPRESSION); \ + exit(EXIT_FAILURE); \ + } + +#define TEST_TYPE(type, minimum, maximum, is_signed) \ + MUST_SUCCEED(TYPE_IS_INTEGER(type)); \ + MUST_SUCCEED(TYPE_IS_SIGNED(type) == is_signed); \ + MUST_SUCCEED(TYPE_MAXIMUM(type) == maximum); \ + MUST_SUCCEED(TYPE_MINIMUM(type) == minimum); + +int +main (void) +{ + TEST_TYPE(char, CHAR_MIN, CHAR_MAX, (CHAR_MIN < 0)); + + TEST_TYPE(signed char, SCHAR_MIN, SCHAR_MAX, 1); + TEST_TYPE(short int, SHRT_MIN, SHRT_MAX, 1); + TEST_TYPE(int, INT_MIN, INT_MAX, 1); + TEST_TYPE(long int, LONG_MIN, LONG_MAX, 1); + TEST_TYPE(long long int, LLONG_MIN, LLONG_MAX, 1); + + TEST_TYPE(unsigned char, 0, UCHAR_MAX, 0); + TEST_TYPE(unsigned short int, 0, USHRT_MAX, 0); + TEST_TYPE(unsigned int, 0, UINT_MAX, 0); + TEST_TYPE(unsigned long int, 0, ULONG_MAX, 0); + TEST_TYPE(unsigned long long int, 0, ULLONG_MAX, 0); + + MUST_SUCCEED(!(TYPE_IS_INTEGER(float))); + MUST_SUCCEED(!(TYPE_IS_INTEGER(double))); + MUST_SUCCEED(!(TYPE_IS_INTEGER(long double))); + + return 0; +} diff --git a/openflow/third-party/.gitignore b/openflow/third-party/.gitignore new file mode 100644 index 00000000..b336cc7c --- /dev/null +++ b/openflow/third-party/.gitignore @@ -0,0 +1,2 @@ +/Makefile +/Makefile.in diff --git a/openflow/third-party/README b/openflow/third-party/README new file mode 100644 index 00000000..15f4d647 --- /dev/null +++ b/openflow/third-party/README @@ -0,0 +1,35 @@ +This directory contains third-party software that may be useful for +debugging. + +tcpdump +------- +The "ofp-tcpdump.patch" patch adds the ability to parse OpenFlow +messages to tcpdump. These instructions assume that tcpdump 3.9.8 +is going to be used, but it should work with other versions that are not +substantially different. To begin, download tcpdump and apply the +patch: + + wget http://www.tcpdump.org/release/tcpdump-3.9.8.tar.gz + tar xzf tcpdump-3.9.8.tar.gz + ln -s tcpdump-3.9.8 tcpdump + patch -p0 < ofp-tcpdump.patch + +Then build the new version of tcpdump: + + cd tcpdump + ./configure + make + +Clearly, tcpdump can only parse unencrypted packets, so you will need to +connect the controller and datapath using plain TCP. To look at the +traffic, tcpdump will be started in a manner similar to the following: + + sudo ./tcpdump -s0 -i eth0 port 6633 + +The "-s0" flag indicates that tcpdump should capture the entire packet. +If the OpenFlow message is not received in its entirety, "[|openflow]" will +be printed instead of the OpenFlow message contents. + +The verbosity of the output may be increased by adding additional "-v" +flags. If "-vvv" is used, the raw OpenFlow data is also printed in +hex and ASCII. diff --git a/openflow/third-party/automake.mk b/openflow/third-party/automake.mk new file mode 100644 index 00000000..02636bb5 --- /dev/null +++ b/openflow/third-party/automake.mk @@ -0,0 +1,3 @@ +EXTRA_DIST += \ + third-party/README \ + third-party/ofp-tcpdump.patch diff --git a/openflow/third-party/ofp-tcpdump.patch b/openflow/third-party/ofp-tcpdump.patch new file mode 100644 index 00000000..3f2cc57b --- /dev/null +++ b/openflow/third-party/ofp-tcpdump.patch @@ -0,0 +1,119 @@ +diff -rNu tcpdump/interface.h tcpdump/interface.h +--- tcpdump/interface.h 2007-06-13 18:03:20.000000000 -0700 ++++ tcpdump/interface.h 2008-02-06 15:06:30.000000000 -0800 +@@ -148,7 +148,8 @@ + + extern const char *dnaddr_string(u_short); + +-extern void error(const char *, ...) ++#define error(fmt, args...) tcpdump_error(fmt, ## args) ++extern void tcpdump_error(const char *, ...) + __attribute__((noreturn, format (printf, 1, 2))); + extern void warning(const char *, ...) __attribute__ ((format (printf, 1, 2))); + +@@ -176,6 +177,7 @@ + extern void hex_print_with_offset(const char *, const u_char *, u_int, u_int); + extern void hex_print(const char *, const u_char *, u_int); + extern void telnet_print(const u_char *, u_int); ++extern void openflow_print(const u_char *, u_int); + extern int ether_encap_print(u_short, const u_char *, u_int, u_int, u_short *); + extern int llc_print(const u_char *, u_int, u_int, const u_char *, + const u_char *, u_short *); +diff -rNu tcpdump/Makefile.in tcpdump/Makefile.in +--- tcpdump/Makefile.in 2007-09-25 18:59:52.000000000 -0700 ++++ tcpdump/Makefile.in 2008-02-07 11:46:03.000000000 -0800 +@@ -49,10 +49,10 @@ + CFLAGS = $(CCOPT) $(DEFS) $(INCLS) + + # Standard LDFLAGS +-LDFLAGS = @LDFLAGS@ ++LDFLAGS = @LDFLAGS@ -L../../lib + + # Standard LIBS +-LIBS = @LIBS@ ++LIBS = @LIBS@ -lopenflow + + INSTALL = @INSTALL@ + INSTALL_PROGRAM = @INSTALL_PROGRAM@ +@@ -87,7 +87,8 @@ + print-slow.c print-snmp.c print-stp.c print-sunatm.c print-sunrpc.c \ + print-symantec.c print-syslog.c print-tcp.c print-telnet.c print-tftp.c \ + print-timed.c print-token.c print-udp.c print-vjc.c print-vrrp.c \ +- print-wb.c print-zephyr.c setsignal.c tcpdump.c util.c ++ print-wb.c print-zephyr.c setsignal.c tcpdump.c util.c \ ++ print-openflow.c + + LOCALSRC = @LOCALSRC@ + GENSRC = version.c +diff -rNu tcpdump/print-openflow.c tcpdump/print-openflow.c +--- tcpdump/print-openflow.c 1969-12-31 16:00:00.000000000 -0800 ++++ tcpdump/print-openflow.c 2008-02-07 11:29:01.000000000 -0800 +@@ -0,0 +1,46 @@ ++/* Copyright (C) 2007, 2008 Board of Trustees, Leland Stanford Jr. University. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include ++ ++#include "interface.h" ++#include "../../include/openflow/openflow.h" ++#include "../../include/ofp-print.h" ++ ++void ++openflow_print(const u_char *sp, u_int length) ++{ ++ const struct ofp_header *ofp = (struct ofp_header *)sp; ++ ++ if (!TTEST2(*sp, ntohs(ofp->length))) ++ goto trunc; ++ ++ ofp_print(stdout, sp, length, vflag); ++ return; ++ ++trunc: ++ printf("[|openflow]"); ++} +diff -rNu tcpdump/print-tcp.c tcpdump/print-tcp.c +--- tcpdump/print-tcp.c 2006-09-19 12:07:57.000000000 -0700 ++++ tcpdump/print-tcp.c 2008-02-07 13:07:58.000000000 -0800 +@@ -52,6 +52,8 @@ + + #include "nameser.h" + ++#include "../../include/openflow.h" ++ + #ifdef HAVE_LIBCRYPTO + #include + +@@ -680,7 +682,8 @@ + } + else if (length > 0 && (sport == LDP_PORT || dport == LDP_PORT)) { + ldp_print(bp, length); +- } ++ } else if (sport == OFP_TCP_PORT || dport == OFP_TCP_PORT) ++ openflow_print(bp, length); + } + return; + bad: diff --git a/openflow/udatapath/.dirstamp b/openflow/udatapath/.dirstamp new file mode 100644 index 00000000..e69de29b diff --git a/openflow/udatapath/.gitignore b/openflow/udatapath/.gitignore new file mode 100644 index 00000000..e4272b0b --- /dev/null +++ b/openflow/udatapath/.gitignore @@ -0,0 +1,4 @@ +/Makefile +/Makefile.in +/ofdatapath +/ofdatapath.8 diff --git a/openflow/udatapath/automake.mk b/openflow/udatapath/automake.mk new file mode 100644 index 00000000..b4b4d8e6 --- /dev/null +++ b/openflow/udatapath/automake.mk @@ -0,0 +1,75 @@ +# +# Build udatapath as binary +# + +bin_PROGRAMS += udatapath/ofdatapath +man_MANS += udatapath/ofdatapath.8 + +udatapath_ofdatapath_SOURCES = \ + udatapath/chain.c \ + udatapath/chain.h \ + udatapath/crc32.c \ + udatapath/crc32.h \ + udatapath/datapath.c \ + udatapath/datapath.h \ + udatapath/dp_act.c \ + udatapath/dp_act.h \ + udatapath/of_ext_msg.c \ + udatapath/of_ext_msg.h \ + udatapath/udatapath.c \ + udatapath/private-msg.c \ + udatapath/private-msg.h \ + udatapath/switch-flow.c \ + udatapath/switch-flow.h \ + udatapath/table.h \ + udatapath/table-hash.c \ + udatapath/table-linear.c + +udatapath_ofdatapath_LDADD = lib/libopenflow.a $(SSL_LIBS) $(FAULT_LIBS) +udatapath_ofdatapath_CPPFLAGS = $(AM_CPPFLAGS) + +EXTRA_DIST += udatapath/ofdatapath.8.in +DISTCLEANFILES += udatapath/ofdatapath.8 + +if BUILD_HW_LIBS + +# Options for each platform +if NF2 +udatapath_ofdatapath_LDADD += hw-lib/libnf2.a +udatapath_ofdatapath_CPPFLAGS += -DOF_HW_PLAT -DUSE_NETDEV -g +noinst_LIBRARIES += hw-lib/libnf2.a +endif + +endif + +if BUILD_HW_LIBS +# +# Build udatapath as a library +# + +noinst_LIBRARIES += udatapath/libudatapath.a + +udatapath_libudatapath_a_SOURCES = \ + udatapath/chain.c \ + udatapath/chain.h \ + udatapath/crc32.c \ + udatapath/crc32.h \ + udatapath/datapath.c \ + udatapath/datapath.h \ + udatapath/dp_act.c \ + udatapath/dp_act.h \ + udatapath/of_ext_msg.c \ + udatapath/of_ext_msg.h \ + udatapath/udatapath.c \ + udatapath/private-msg.c \ + udatapath/private-msg.h \ + udatapath/switch-flow.c \ + udatapath/switch-flow.h \ + udatapath/table.h \ + udatapath/table-hash.c \ + udatapath/table-linear.c + +udatapath_libudatapath_a_CPPFLAGS = $(AM_CPPFLAGS) +udatapath_libudatapath_a_CPPFLAGS += -DOF_HW_PLAT -DUDATAPATH_AS_LIB -g + +endif diff --git a/openflow/udatapath/chain.c b/openflow/udatapath/chain.c new file mode 100644 index 00000000..b9dc39c0 --- /dev/null +++ b/openflow/udatapath/chain.c @@ -0,0 +1,261 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include "chain.h" +#include +#include +#include +#include "switch-flow.h" +#include "table.h" +#include "datapath.h" + +#if defined(OF_HW_PLAT) +#include +#endif + +#define THIS_MODULE VLM_chain +#include "vlog.h" + +/* Attempts to append 'table' to the set of tables in 'chain'. Returns 0 or + * negative error. If 'table' is null it is assumed that table creation failed + * due to out-of-memory. */ +static int add_table(struct sw_chain *chain, struct sw_table *table, int emerg) +{ + if (table == NULL) + return -ENOMEM; + if (chain->n_tables >= CHAIN_MAX_TABLES) { + VLOG_ERR("too many tables in chain\n"); + table->destroy(table); + return -ENOBUFS; + } + if (emerg) + chain->emerg_table = table; + else + chain->tables[chain->n_tables++] = table; + return 0; +} + +/* Creates and returns a new chain. Returns NULL if the chain cannot be + * created. */ +struct sw_chain *chain_create(struct datapath *dp) +{ + struct sw_chain *chain = calloc(1, sizeof *chain); + if (chain == NULL) + return NULL; + + chain->dp = dp; +#if defined(OF_HW_PLAT) + if (dp && dp->hw_drv) { + if (add_table(chain, (struct sw_table *)dp->hw_drv, 0) != 0) { + VLOG_ERR("Could not attach HW table to chain\n"); + } + } +#endif + if (add_table(chain, table_hash2_create(0x1EDC6F41, TABLE_HASH_MAX_FLOWS, + 0x741B8CD7, TABLE_HASH_MAX_FLOWS), + 0) + || add_table(chain, table_linear_create(TABLE_LINEAR_MAX_FLOWS), 0) + || add_table(chain, table_linear_create(TABLE_LINEAR_MAX_FLOWS), 1)) { + chain_destroy(chain); + return NULL; + } + + return chain; +} + +/* Searches 'chain' for a flow matching 'key', which must not have any wildcard + * fields. Returns the flow if successful, otherwise a null pointer. */ +struct sw_flow * +chain_lookup(struct sw_chain *chain, const struct sw_flow_key *key, int emerg) +{ + int i; + + assert(!key->wildcards); + + if (emerg) { + struct sw_table *t = chain->emerg_table; + struct sw_flow *flow = t->lookup(t, key); + t->n_lookup++; + if (flow) { + t->n_matched++; + return flow; + } + } else { + for (i = 0; i < chain->n_tables; i++) { + struct sw_table *t = chain->tables[i]; + struct sw_flow *flow = t->lookup(t, key); + t->n_lookup++; + if (flow) { + t->n_matched++; + return flow; + } + } + } + + return NULL; +} + +/* Inserts 'flow' into 'chain', replacing any duplicate flow. Returns 0 if + * successful or a negative error. + * + * If successful, 'flow' becomes owned by the chain, otherwise it is retained + * by the caller. */ +int +chain_insert(struct sw_chain *chain, struct sw_flow *flow, int emerg) +{ + int i; + + if (emerg) { + struct sw_table *t = chain->emerg_table; + if (t->insert(t, flow)) + return 0; + } else { + for (i = 0; i < chain->n_tables; i++) { + struct sw_table *t = chain->tables[i]; + if (t->insert(t, flow)) + return 0; + } + } + + return -ENOBUFS; +} + +/* Modifies actions in 'chain' that match 'key'. If 'strict' set, wildcards + * and priority must match. Returns the number of flows that were modified. + * + * Expensive in the general case as currently implemented, since it requires + * iterating through the entire contents of each table for keys that contain + * wildcards. Relatively cheap for fully specified keys. */ +int +chain_modify(struct sw_chain *chain, const struct sw_flow_key *key, + uint16_t priority, int strict, + const struct ofp_action_header *actions, size_t actions_len, + int emerg) +{ + int count = 0; + int i; + + if (emerg) { + struct sw_table *t = chain->emerg_table; + count += t->modify(t, key, priority, strict, actions, actions_len); + } else { + for (i = 0; i < chain->n_tables; i++) { + struct sw_table *t = chain->tables[i]; + count += t->modify(t, key, priority, strict, actions, actions_len); + } + } + + return count; +} + +/* Checks whether the chain has an entry with the same priority which conflicts + * with 'key'. If 'strict' set, wildcards should also match. If 'strict' is not + * set, comparison is done 'module wildcards'. + * + * Returns 'true' if such an entry exists, 'false' otherwise. */ +int +chain_has_conflict(struct sw_chain *chain, const struct sw_flow_key *key, + uint16_t priority, int strict) +{ + int i; + + for (i = 0; i < chain->n_tables; i++) { + struct sw_table *t = chain->tables[i]; + if (t->has_conflict(t, key, priority, strict)) { + return true; + } + } + + return false; +} + +/* Deletes from 'chain' any and all flows that match 'key'. If 'out_port' + * is not OFPP_NONE, then matching entries must have that port as an + * argument for an output action. If 'strict" is set, then wildcards and + * priority must match. Returns the number of flows that were deleted. + * + * Expensive in the general case as currently implemented, since it requires + * iterating through the entire contents of each table for keys that contain + * wildcards. Relatively cheap for fully specified keys. */ +int +chain_delete(struct sw_chain *chain, const struct sw_flow_key *key, + uint16_t out_port, uint16_t priority, int strict, int emerg) +{ + int count = 0; + int i; + + if (emerg) { + struct sw_table *t = chain->emerg_table; + count += t->delete(chain->dp, t, key, out_port, priority, strict); + } else { + for (i = 0; i < chain->n_tables; i++) { + struct sw_table *t = chain->tables[i]; + count += t->delete(chain->dp, t, key, out_port, priority, strict); + } + } + + return count; +} + +/* Deletes timed-out flow entries from all the tables in 'chain' and appends + * the deleted flows to 'deleted'. + * + * Expensive as currently implemented, since it iterates through the entire + * contents of each table. */ +void +chain_timeout(struct sw_chain *chain, struct list *deleted) +{ + int i; + + for (i = 0; i < chain->n_tables; i++) { + struct sw_table *t = chain->tables[i]; + t->timeout(t, deleted); + } +} + +/* Destroys 'chain', which must not have any users. */ +void +chain_destroy(struct sw_chain *chain) +{ + int i; + struct sw_table *t; + + for (i = 0; i < chain->n_tables; i++) { + t = chain->tables[i]; + t->destroy(t); + } + t = chain->emerg_table; + t->destroy(t); + free(chain); +} diff --git a/openflow/udatapath/chain.h b/openflow/udatapath/chain.h new file mode 100644 index 00000000..fb4e9c37 --- /dev/null +++ b/openflow/udatapath/chain.h @@ -0,0 +1,74 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#ifndef CHAIN_H +#define CHAIN_H 1 + +#include +#include + +struct sw_flow; +struct sw_flow_key; +struct ofp_action_header; +struct list; +struct datapath; + +#define TABLE_LINEAR_MAX_FLOWS 100 +#define TABLE_HASH_MAX_FLOWS 65536 +#define TABLE_MAC_MAX_FLOWS 1024 +#define TABLE_MAC_NUM_BUCKETS 1024 + +/* Set of tables chained together in sequence from cheap to expensive. */ +#define CHAIN_MAX_TABLES 4 +struct sw_chain { + int n_tables; /* Number of working tables, not includes + * protection (emergency) table. */ + struct sw_table *tables[CHAIN_MAX_TABLES]; + struct sw_table *emerg_table; + + struct datapath *dp; +}; + +struct sw_chain *chain_create(struct datapath *); +struct sw_flow *chain_lookup(struct sw_chain *, const struct sw_flow_key *, int); +int chain_insert(struct sw_chain *, struct sw_flow *, int); +int chain_modify(struct sw_chain *, const struct sw_flow_key *, + uint16_t, int, const struct ofp_action_header *, size_t, int); +int chain_has_conflict(struct sw_chain *, const struct sw_flow_key *, + uint16_t, int); +int chain_delete(struct sw_chain *, const struct sw_flow_key *, uint16_t, + uint16_t, int, int); +void chain_timeout(struct sw_chain *, struct list *deleted); +void chain_destroy(struct sw_chain *); + +#endif /* chain.h */ diff --git a/openflow/udatapath/crc32.c b/openflow/udatapath/crc32.c new file mode 100644 index 00000000..f6c2c0b3 --- /dev/null +++ b/openflow/udatapath/crc32.c @@ -0,0 +1,68 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include "crc32.h" + +void +crc32_init(struct crc32 *crc, unsigned int polynomial) +{ + int i; + + for (i = 0; i < CRC32_TABLE_SIZE; ++i) { + unsigned int reg = i << 24; + int j; + for (j = 0; j < CRC32_TABLE_BITS; j++) { + int topBit = (reg & 0x80000000) != 0; + reg <<= 1; + if (topBit) + reg ^= polynomial; + } + crc->table[i] = reg; + } +} + +unsigned int +crc32_calculate(const struct crc32 *crc, const void *data_, size_t n_bytes) +{ + const uint8_t *data = data_; + unsigned int result = 0; + size_t i; + + for (i = 0; i < n_bytes; i++) { + unsigned int top = result >> 24; + top ^= data[i]; + result = (result << 8) ^ crc->table[top]; + } + return result; +} diff --git a/openflow/udatapath/crc32.h b/openflow/udatapath/crc32.h new file mode 100644 index 00000000..355aefdf --- /dev/null +++ b/openflow/udatapath/crc32.h @@ -0,0 +1,50 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#ifndef CRC32_H +#define CRC32_H 1 + +#include +#include + +#define CRC32_TABLE_BITS 8 +#define CRC32_TABLE_SIZE (1u << CRC32_TABLE_BITS) + +struct crc32 { + unsigned int table[CRC32_TABLE_SIZE]; +}; + +void crc32_init(struct crc32 *, unsigned int polynomial); +unsigned int crc32_calculate(const struct crc32 *, const void *, size_t); + +#endif /* crc32.h */ diff --git a/openflow/udatapath/datapath.c b/openflow/udatapath/datapath.c new file mode 100644 index 00000000..5254b771 --- /dev/null +++ b/openflow/udatapath/datapath.c @@ -0,0 +1,2375 @@ +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include "datapath.h" +#include +#include +#include +#include +#include +#include +#include +#include "chain.h" +#include "csum.h" +#include "flow.h" +#include "ofpbuf.h" +#include "openflow/openflow.h" +#include "openflow/nicira-ext.h" +#include "openflow/private-ext.h" +#include "openflow/openflow-ext.h" +#include "packets.h" +#include "poll-loop.h" +#include "rconn.h" +#include "stp.h" +#include "switch-flow.h" +#include "table.h" +#include "vconn.h" +#include "xtoxll.h" +#include "private-msg.h" +#include "of_ext_msg.h" +#include "dp_act.h" + +#define THIS_MODULE VLM_datapath +#include "vlog.h" + +#if defined(OF_HW_PLAT) +#include +#include +#endif + +#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) +/* Queue to decouple receive packet thread from rconn control thread */ +/* Could make mutex per-DP */ +static pthread_mutex_t pkt_q_mutex = PTHREAD_MUTEX_INITIALIZER; +#define PKT_Q_LOCK pthread_mutex_lock(&pkt_q_mutex) +#define PKT_Q_UNLOCK pthread_mutex_unlock(&pkt_q_mutex) + +static void +enqueue_pkt(struct datapath *dp, struct ofpbuf *buffer, of_port_t port_no, + int reason) +{ + struct hw_pkt_q_entry *q_entry; + + if ((q_entry = xmalloc(sizeof(*q_entry))) == NULL) { + VLOG_WARN("Could not alloc q entry\n"); + /* FIXME: Dealloc buffer */ + return; + } + q_entry->buffer = buffer; + q_entry->next = NULL; + q_entry->port_no = port_no; + q_entry->reason = reason; + pthread_mutex_lock(&pkt_q_mutex); + if (dp->hw_pkt_list_head == NULL) { + dp->hw_pkt_list_head = q_entry; + } else { + dp->hw_pkt_list_tail->next = q_entry; + } + dp->hw_pkt_list_tail = q_entry; + pthread_mutex_unlock(&pkt_q_mutex); +} + +/* If queue non-empty, fill out params and return 1; else return 0 */ +static int +dequeue_pkt(struct datapath *dp, struct ofpbuf **buffer, of_port_t *port_no, + int *reason) +{ + struct hw_pkt_q_entry *q_entry; + int rv = 0; + + pthread_mutex_lock(&pkt_q_mutex); + q_entry = dp->hw_pkt_list_head; + if (dp->hw_pkt_list_head != NULL) { + dp->hw_pkt_list_head = dp->hw_pkt_list_head->next; + if (dp->hw_pkt_list_head == NULL) { + dp->hw_pkt_list_tail = NULL; + } + } + pthread_mutex_unlock(&pkt_q_mutex); + + if (q_entry != NULL) { + rv = 1; + *buffer = q_entry->buffer; + *port_no = q_entry->port_no; + *reason = q_entry->reason; + free(q_entry); + } + + return rv; +} +#endif + +extern char mfr_desc; +extern char hw_desc; +extern char sw_desc; +extern char dp_desc; +extern char serial_num; + +/* Capabilities supported by this implementation. */ +#define OFP_SUPPORTED_CAPABILITIES ( OFPC_FLOW_STATS \ + | OFPC_TABLE_STATS \ + | OFPC_PORT_STATS \ + | OFPC_QUEUE_STATS \ + | OFPC_ARP_MATCH_IP ) + +/* Actions supported by this implementation. */ +#define OFP_SUPPORTED_ACTIONS ( (1 << OFPAT_OUTPUT) \ + | (1 << OFPAT_SET_VLAN_VID) \ + | (1 << OFPAT_SET_VLAN_PCP) \ + | (1 << OFPAT_STRIP_VLAN) \ + | (1 << OFPAT_SET_DL_SRC) \ + | (1 << OFPAT_SET_DL_DST) \ + | (1 << OFPAT_SET_NW_SRC) \ + | (1 << OFPAT_SET_NW_DST) \ + | (1 << OFPAT_SET_TP_SRC) \ + | (1 << OFPAT_SET_TP_DST) \ + | (1 << OFPAT_ENQUEUE)) + +/* The origin of a received OpenFlow message, to enable sending a reply. */ +struct sender { + struct remote *remote; /* The device that sent the message. */ + uint32_t xid; /* The OpenFlow transaction ID. */ +}; + +/* A connection to a secure channel. */ +struct remote { + struct list node; + struct rconn *rconn; +#define TXQ_LIMIT 128 /* Max number of packets to queue for tx. */ + int n_txq; /* Number of packets queued for tx on rconn. */ + + /* Support for reliable, multi-message replies to requests. + * + * If an incoming request needs to have a reliable reply that might + * require multiple messages, it can use remote_start_dump() to set up + * a callback that will be called as buffer space for replies. */ + int (*cb_dump)(struct datapath *, void *aux); + void (*cb_done)(void *aux); + void *cb_aux; +}; + +static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60); + +static struct remote *remote_create(struct datapath *, struct rconn *); +static void remote_run(struct datapath *, struct remote *); +static void remote_wait(struct remote *); +static void remote_destroy(struct remote *); + +static void update_port_flags(struct datapath *, const struct ofp_port_mod *); +static void send_port_status(struct sw_port *p, uint8_t status); + +/* Buffers are identified by a 31-bit opaque ID. We divide the ID + * into a buffer number (low bits) and a cookie (high bits). The buffer number + * is an index into an array of buffers. The cookie distinguishes between + * different packets that have occupied a single buffer. Thus, the more + * buffers we have, the lower-quality the cookie... */ +#define PKT_BUFFER_BITS 8 +#define N_PKT_BUFFERS (1 << PKT_BUFFER_BITS) +#define PKT_BUFFER_MASK (N_PKT_BUFFERS - 1) + +#define PKT_COOKIE_BITS (32 - PKT_BUFFER_BITS) + +int run_flow_through_tables(struct datapath *, struct ofpbuf *, + struct sw_port *); +void fwd_port_input(struct datapath *, struct ofpbuf *, struct sw_port *); +int fwd_control_input(struct datapath *, const struct sender *, + const void *, size_t); + +uint32_t save_buffer(struct ofpbuf *); +static struct ofpbuf *retrieve_buffer(uint32_t id); +static void discard_buffer(uint32_t id); + +struct sw_port * +dp_lookup_port(struct datapath *dp, uint16_t port_no) +{ + return (port_no < DP_MAX_PORTS ? &dp->ports[port_no] + : port_no == OFPP_LOCAL ? dp->local_port + : NULL); +} + +struct sw_queue * +dp_lookup_queue(struct sw_port *p, uint32_t queue_id) +{ + struct sw_queue *q; + + LIST_FOR_EACH(q, struct sw_queue, node, &p->queue_list) { + if ((q != NULL) && (q->queue_id == queue_id)) { + return q; + } + } + return NULL; +} + +/* Generates and returns a random datapath id. */ +static uint64_t +gen_datapath_id(void) +{ + uint8_t ea[ETH_ADDR_LEN]; + eth_addr_random(ea); + ea[0] = 0x00; /* Set Nicira OUI. */ + ea[1] = 0x23; + ea[2] = 0x20; + return eth_addr_to_uint64(ea); +} + +/* FIXME: Should not depend on udatapath_as_lib */ +#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) && defined(UDATAPATH_AS_LIB) +/* + * Receive packet handling for hardware driver controlled ports + * + * FIXME: For now, call the pkt fwding directly; eventually may + * want to enqueue packets at this layer; at that point must + * make sure poll event is registered or timer kicked + */ +static int +hw_packet_in(of_port_t port_no, of_packet_t *packet, int reason, + void *cookie) +{ + struct sw_port *port; + struct ofpbuf *buffer = NULL; + struct datapath *dp = (struct datapath *)cookie; + const int headroom = 128 + 2; + const int hard_header = VLAN_ETH_HEADER_LEN; + const int tail_room = sizeof(uint32_t); /* For crc if needed later */ + + VLOG_INFO("dp rcv packet on port %d, size %d\n", + port_no, packet->length); + if ((port_no < 1) || port_no > DP_MAX_PORTS) { + VLOG_ERR("Bad receive port %d\n", port_no); + /* TODO increment error counter */ + return -1; + } + port = &dp->ports[port_no]; + if (!PORT_IN_USE(port)) { + VLOG_WARN("Receive port not active: %d\n", port_no); + return -1; + } + if (!IS_HW_PORT(port)) { + VLOG_ERR("Receive port not controlled by HW: %d\n", port_no); + return -1; + } + /* Note: We're really not counting these for port stats as they + * should be gotten directly from the HW */ + port->rx_packets++; + port->rx_bytes += packet->length; + /* For now, copy data into OFP buffer; eventually may steal packet + * from RX to avoid copy. As per dp_run, add headroom and offset bytes. + */ + buffer = ofpbuf_new(headroom + hard_header + packet->length + tail_room); + if (buffer == NULL) { + VLOG_WARN("Could not alloc ofpbuf on hw pkt in\n"); + fprintf(stderr, "Could not alloc ofpbuf on hw pkt in\n"); + } else { + buffer->data = (char*)buffer->data + headroom; + buffer->size = packet->length; + memcpy(buffer->data, packet->data, packet->length); + enqueue_pkt(dp, buffer, port_no, reason); + poll_immediate_wake(); + } + + return 0; +} +#endif + +#if defined(OF_HW_PLAT) +static int +dp_hw_drv_init(struct datapath *dp) +{ + dp->hw_pkt_list_head = NULL; + dp->hw_pkt_list_tail = NULL; + + dp->hw_drv = new_of_hw_driver(dp); + if (dp->hw_drv == NULL) { + VLOG_ERR("Could not create HW driver"); + return -1; + } +#if !defined(USE_NETDEV) + if (dp->hw_drv->packet_receive_register(dp->hw_drv, + hw_packet_in, dp) < 0) { + VLOG_ERR("Could not register with HW driver to receive pkts"); + } +#endif + + return 0; +} + +#endif + +int +dp_new(struct datapath **dp_, uint64_t dpid) +{ + struct datapath *dp; + + dp = calloc(1, sizeof *dp); + if (!dp) { + return ENOMEM; + } + + dp->last_timeout = time_now(); + list_init(&dp->remotes); + dp->listeners = NULL; + dp->n_listeners = 0; + dp->id = dpid <= UINT64_C(0xffffffffffff) ? dpid : gen_datapath_id(); +/* FIXME: Should not depend on udatapath_as_lib */ +#if defined(OF_HW_PLAT) && (defined(UDATAPATH_AS_LIB) || defined(USE_NETDEV)) + dp_hw_drv_init(dp); +#endif + dp->chain = chain_create(dp); + if (!dp->chain) { + VLOG_ERR("could not create chain"); + free(dp); + return ENOMEM; + } + + list_init(&dp->port_list); + dp->flags = 0; + dp->miss_send_len = OFP_DEFAULT_MISS_SEND_LEN; + + if(strlen(&dp_desc) > 0) /* use the comment, if specified */ + strncpy(dp->dp_desc, &dp_desc, sizeof dp->dp_desc); + else /* else, just use "$HOSTNAME pid=$$" */ + { + char hostnametmp[DESC_STR_LEN]; + gethostname(hostnametmp,sizeof hostnametmp); + snprintf(dp->dp_desc, sizeof dp->dp_desc,"%s pid=%u",hostnametmp, getpid()); + } + + *dp_ = dp; + return 0; +} + +static int +new_port(struct datapath *dp, struct sw_port *port, uint16_t port_no, + const char *netdev_name, const uint8_t *new_mac, uint16_t num_queues) +{ + struct netdev *netdev; + struct in6_addr in6; + struct in_addr in4; + int error; + + error = netdev_open(netdev_name, NETDEV_ETH_TYPE_ANY, &netdev); + if (error) { + return error; + } + if (new_mac && !eth_addr_equals(netdev_get_etheraddr(netdev), new_mac)) { + /* Generally the device has to be down before we change its hardware + * address. Don't bother to check for an error because it's really + * the netdev_set_etheraddr() call below that we care about. */ + netdev_set_flags(netdev, 0, false); + error = netdev_set_etheraddr(netdev, new_mac); + if (error) { + VLOG_WARN("failed to change %s Ethernet address " + "to "ETH_ADDR_FMT": %s", + netdev_name, ETH_ADDR_ARGS(new_mac), strerror(error)); + } + } + error = netdev_set_flags(netdev, NETDEV_UP | NETDEV_PROMISC, false); + if (error) { + VLOG_ERR("failed to set promiscuous mode on %s device", netdev_name); + netdev_close(netdev); + return error; + } + if (netdev_get_in4(netdev, &in4)) { + VLOG_ERR("%s device has assigned IP address %s", + netdev_name, inet_ntoa(in4)); + } + if (netdev_get_in6(netdev, &in6)) { + char in6_name[INET6_ADDRSTRLEN + 1]; + inet_ntop(AF_INET6, &in6, in6_name, sizeof in6_name); + VLOG_ERR("%s device has assigned IPv6 address %s", + netdev_name, in6_name); + } + + if (num_queues > 0) { + error = netdev_setup_slicing(netdev, num_queues); + if (error) { + VLOG_ERR("failed to configure slicing on %s device: "\ + "check INSTALL for dependencies, or rerun "\ + "using --no-slicing option to disable slicing", + netdev_name); + netdev_close(netdev); + return error; + } + } + + memset(port, '\0', sizeof *port); + + list_init(&port->queue_list); + port->dp = dp; + port->flags |= SWP_USED; + port->netdev = netdev; + port->port_no = port_no; + port->num_queues = num_queues; + list_push_back(&dp->port_list, &port->node); + + /* Notify the ctlpath that this port has been added */ + send_port_status(port, OFPPR_ADD); + + return 0; +} + +#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) +int +dp_add_port(struct datapath *dp, const char *port_name, uint16_t num_queues) +{ + int port_no; + int rc = 0; + struct sw_port *port; + + fprintf(stderr, "Adding port %s. hw_drv is %p\n", port_name, dp->hw_drv); + if (dp->hw_drv && dp->hw_drv->port_add) { + port_no = dp->hw_drv->port_add(dp->hw_drv, -1, port_name); + if (port_no >= 0) { + port = &dp->ports[port_no]; + if (port->flags & SWP_USED) { + VLOG_ERR("HW port %s (%d) already created\n", + port_name, port_no); + rc = -1; + } else { + fprintf(stderr, "Adding HW port %s as OF port number %d\n", + port_name, port_no); + /* FIXME: Determine and record HW addr, etc */ + port->flags |= SWP_USED | SWP_HW_DRV_PORT; + port->dp = dp; + port->port_no = port_no; + list_init(&port->queue_list); + port->num_queues = num_queues; + strncpy(port->hw_name, port_name, sizeof(port->hw_name)); + list_push_back(&dp->port_list, &port->node); + send_port_status(port, OFPPR_ADD); + } + } else { + VLOG_ERR("Port %s not recognized by hardware driver", port_name); + rc = -1; + } + } else { + VLOG_ERR("No hardware driver support; can't add ports"); + rc = -1; + } + + return rc; +} +#else /* Not HW platform support */ +int +dp_add_port(struct datapath *dp, const char *netdev, uint16_t num_queues) +{ + int port_no; + for (port_no = 1; port_no < DP_MAX_PORTS; port_no++) { + struct sw_port *port = &dp->ports[port_no]; + if (!port->netdev) { + return new_port(dp, port, port_no, netdev, NULL, num_queues); + } + } + return EXFULL; +} +#endif /* OF_HW_PLAT */ + +int +dp_add_local_port(struct datapath *dp, const char *netdev, uint16_t num_queues) +{ + if (!dp->local_port) { + uint8_t ea[ETH_ADDR_LEN]; + struct sw_port *port; + int error; + + port = xcalloc(1, sizeof *port); + eth_addr_from_uint64(dp->id, ea); + error = new_port(dp, port, OFPP_LOCAL, netdev, ea, num_queues); + if (!error) { + dp->local_port = port; + } else { + free(port); + } + return error; + } else { + return EXFULL; + } +} + +void +dp_add_pvconn(struct datapath *dp, struct pvconn *pvconn) +{ + dp->listeners = xrealloc(dp->listeners, + sizeof *dp->listeners * (dp->n_listeners + 1)); + dp->listeners[dp->n_listeners++] = pvconn; +} + +void +dp_run(struct datapath *dp) +{ + time_t now = time_now(); + struct sw_port *p, *pn; + struct remote *r, *rn; + struct ofpbuf *buffer = NULL; + size_t i; + + if (now != dp->last_timeout) { + struct list deleted = LIST_INITIALIZER(&deleted); + struct sw_flow *f, *n; + + chain_timeout(dp->chain, &deleted); + LIST_FOR_EACH_SAFE (f, n, struct sw_flow, node, &deleted) { + dp_send_flow_end(dp, f, f->reason); + list_remove(&f->node); + flow_free(f); + } + dp->last_timeout = now; + } + poll_timer_wait(1000); + +#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) + { /* Process packets received from callback thread */ + struct ofpbuf *buffer; + of_port_t port_no; + int reason; + struct sw_port *p; + + while (dequeue_pkt(dp, &buffer, &port_no, &reason)) { + p = dp_lookup_port(dp, port_no); + /* FIXME: We're throwing away the reason that came from HW */ + fwd_port_input(dp, buffer, p); + } + } +#endif + + LIST_FOR_EACH_SAFE (p, pn, struct sw_port, node, &dp->port_list) { + int error; + + if (IS_HW_PORT(p)) { + continue; + } + if (!buffer) { + /* Allocate buffer with some headroom to add headers in forwarding + * to the controller or adding a vlan tag, plus an extra 2 bytes to + * allow IP headers to be aligned on a 4-byte boundary. */ + const int headroom = 128 + 2; + const int hard_header = VLAN_ETH_HEADER_LEN; + const int mtu = netdev_get_mtu(p->netdev); + buffer = ofpbuf_new(headroom + hard_header + mtu); + buffer->data = (char*)buffer->data + headroom; + } + error = netdev_recv(p->netdev, buffer); + if (!error) { + p->rx_packets++; + p->rx_bytes += buffer->size; + fwd_port_input(dp, buffer, p); + buffer = NULL; + } else if (error != EAGAIN) { + VLOG_ERR_RL(&rl, "error receiving data from %s: %s", + netdev_get_name(p->netdev), strerror(error)); + } + } + ofpbuf_delete(buffer); + + /* Talk to remotes. */ + LIST_FOR_EACH_SAFE (r, rn, struct remote, node, &dp->remotes) { + remote_run(dp, r); + } + + for (i = 0; i < dp->n_listeners; ) { + struct pvconn *pvconn = dp->listeners[i]; + struct vconn *new_vconn; + int retval = pvconn_accept(pvconn, OFP_VERSION, &new_vconn); + if (!retval) { + remote_create(dp, rconn_new_from_vconn("passive", new_vconn)); + } else if (retval != EAGAIN) { + VLOG_WARN_RL(&rl, "accept failed (%s)", strerror(retval)); + dp->listeners[i] = dp->listeners[--dp->n_listeners]; + continue; + } + i++; + } +} + +static void +remote_run(struct datapath *dp, struct remote *r) +{ + int i; + + rconn_run(r->rconn); + + /* Do some remote processing, but cap it at a reasonable amount so that + * other processing doesn't starve. */ + for (i = 0; i < 50; i++) { + if (!r->cb_dump) { + struct ofpbuf *buffer; + struct ofp_header *oh; + + buffer = rconn_recv(r->rconn); + if (!buffer) { + break; + } + + if (buffer->size >= sizeof *oh) { + struct sender sender; + + oh = (struct ofp_header *)buffer->data; + sender.remote = r; + sender.xid = oh->xid; + fwd_control_input(dp, &sender, buffer->data, buffer->size); + } else { + VLOG_WARN_RL(&rl, "received too-short OpenFlow message"); + } + ofpbuf_delete(buffer); + } else { + if (r->n_txq < TXQ_LIMIT) { + int error = r->cb_dump(dp, r->cb_aux); + if (error <= 0) { + if (error) { + VLOG_WARN_RL(&rl, "dump callback error: %s", + strerror(-error)); + } + r->cb_done(r->cb_aux); + r->cb_dump = NULL; + } + } else { + break; + } + } + } + + if (!rconn_is_alive(r->rconn)) { + remote_destroy(r); + } +} + +static void +remote_wait(struct remote *r) +{ + rconn_run_wait(r->rconn); + rconn_recv_wait(r->rconn); +} + +static void +remote_destroy(struct remote *r) +{ + if (r) { + if (r->cb_dump && r->cb_done) { + r->cb_done(r->cb_aux); + } + list_remove(&r->node); + rconn_destroy(r->rconn); + free(r); + } +} + +static struct remote * +remote_create(struct datapath *dp, struct rconn *rconn) +{ + struct remote *remote = xmalloc(sizeof *remote); + list_push_back(&dp->remotes, &remote->node); + remote->rconn = rconn; + remote->cb_dump = NULL; + remote->n_txq = 0; + return remote; +} + +/* Starts a callback-based, reliable, possibly multi-message reply to a + * request made by 'remote'. + * + * 'dump' designates a function that will be called when the 'remote' send + * queue has an empty slot. It should compose a message and send it on + * 'remote'. On success, it should return 1 if it should be called again when + * another send queue slot opens up, 0 if its transmissions are complete, or a + * negative errno value on failure. + * + * 'done' designates a function to clean up any resources allocated for the + * dump. It must handle being called before the dump is complete (which will + * happen if 'remote' is closed unexpectedly). + * + * 'aux' is passed to 'dump' and 'done'. */ +static void +remote_start_dump(struct remote *remote, + int (*dump)(struct datapath *, void *), + void (*done)(void *), + void *aux) +{ + assert(!remote->cb_dump); + remote->cb_dump = dump; + remote->cb_done = done; + remote->cb_aux = aux; +} + +void +dp_wait(struct datapath *dp) +{ + struct sw_port *p; + struct remote *r; + size_t i; + + LIST_FOR_EACH (p, struct sw_port, node, &dp->port_list) { + if (IS_HW_PORT(p)) { + continue; + } + netdev_recv_wait(p->netdev); + } + LIST_FOR_EACH (r, struct remote, node, &dp->remotes) { + remote_wait(r); + } + for (i = 0; i < dp->n_listeners; i++) { + pvconn_wait(dp->listeners[i]); + } +} + +/* Send packets out all the ports except the originating one. If the + * "flood" argument is set, don't send out ports with flooding disabled. + */ +static int +output_all(struct datapath *dp, struct ofpbuf *buffer, int in_port, int flood) +{ + struct sw_port *p; + int prev_port; /* Buffer is cloned for multiple transmits */ + + prev_port = -1; + LIST_FOR_EACH (p, struct sw_port, node, &dp->port_list) { + if (p->port_no == in_port) { + continue; + } + if (flood && p->config & OFPPC_NO_FLOOD) { + continue; + } + if (prev_port != -1) { + dp_output_port(dp, ofpbuf_clone(buffer), in_port, prev_port, + 0,false); + } + prev_port = p->port_no; + } + if (prev_port != -1) + dp_output_port(dp, buffer, in_port, prev_port, 0, false); + else + ofpbuf_delete(buffer); + + return 0; +} + +static void +output_packet(struct datapath *dp, struct ofpbuf *buffer, uint16_t out_port, + uint32_t queue_id) +{ + uint16_t class_id; + struct sw_queue * q; + struct sw_port *p; + + q = NULL; + p = dp_lookup_port(dp, out_port); + +/* FIXME: Needs update for queuing */ +#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) + if ((p != NULL) && IS_HW_PORT(p)) { + if (dp && dp->hw_drv) { + if (dp->hw_drv->port_link_get(dp->hw_drv, p->port_no)) { + of_packet_t *pkt; + int rv; + + pkt = calloc(1, sizeof(*pkt)); + OF_PKT_INIT(pkt, buffer); + rv = dp->hw_drv->packet_send(dp->hw_drv, out_port, pkt, 0); + if ((rv < 0) && (rv != OF_HW_PORT_DOWN)) { + VLOG_ERR("Error %d sending pkt on HW port %d\n", + rv, out_port); + ofpbuf_delete(buffer); + free(pkt); + } + } + } + return; + } + + /* Fall through to software controlled ports if not HW port */ +#endif + + if (p && p->netdev != NULL) { + if (!(p->config & OFPPC_PORT_DOWN)) { + /* avoid the queue lookup for best-effort traffic */ + if (queue_id == 0) { + class_id = 0; + } + else { + /* silently drop the packet if queue doesn't exist */ + q = dp_lookup_queue(p, queue_id); + if (q) { + class_id = q->class_id; + } + else { + goto error; + } + } + + if (!netdev_send(p->netdev, buffer, class_id)) { + p->tx_packets++; + p->tx_bytes += buffer->size; + if (q) { + q->tx_packets++; + q->tx_bytes += buffer->size; + } + } else { + p->tx_dropped++; + } + } + ofpbuf_delete(buffer); + return; + } + + error: + ofpbuf_delete(buffer); + VLOG_DBG_RL(&rl, "can't forward to bad port:queue(%d:%d)\n", out_port, + queue_id); +} + +/** Takes ownership of 'buffer' and transmits it to 'out_port' on 'dp'. + */ +void +dp_output_port(struct datapath *dp, struct ofpbuf *buffer, + int in_port, int out_port, uint32_t queue_id, + bool ignore_no_fwd UNUSED) +{ + + assert(buffer); + switch (out_port) { + case OFPP_IN_PORT: + output_packet(dp, buffer, in_port, queue_id); + break; + + case OFPP_TABLE: { + struct sw_port *p = dp_lookup_port(dp, in_port); + if (run_flow_through_tables(dp, buffer, p)) { + ofpbuf_delete(buffer); + } + break; + } + + case OFPP_FLOOD: + output_all(dp, buffer, in_port, 1); + break; + + case OFPP_ALL: + output_all(dp, buffer, in_port, 0); + break; + + case OFPP_CONTROLLER: + dp_output_control(dp, buffer, in_port, UINT16_MAX, OFPR_ACTION); + break; + + case OFPP_LOCAL: + default: + if (in_port == out_port) { + VLOG_DBG_RL(&rl, "can't directly forward to input port"); + return; + } + output_packet(dp, buffer, out_port, queue_id); + break; + } +} + +static void * +make_openflow_reply(size_t openflow_len, uint8_t type, + const struct sender *sender, struct ofpbuf **bufferp) +{ + return make_openflow_xid(openflow_len, type, sender ? sender->xid : 0, + bufferp); +} + +static int +send_openflow_buffer_to_remote(struct ofpbuf *buffer, struct remote *remote) +{ + int retval = rconn_send_with_limit(remote->rconn, buffer, &remote->n_txq, + TXQ_LIMIT); + if (retval) { + VLOG_WARN_RL(&rl, "send to %s failed: %s", + rconn_get_name(remote->rconn), strerror(retval)); + } + return retval; +} + +static int +send_openflow_buffer(struct datapath *dp, struct ofpbuf *buffer, + const struct sender *sender) +{ + update_openflow_length(buffer); + if (sender) { + /* Send back to the sender. */ + return send_openflow_buffer_to_remote(buffer, sender->remote); + } else { + /* Broadcast to all remotes. */ + struct remote *r, *prev = NULL; + LIST_FOR_EACH (r, struct remote, node, &dp->remotes) { + if (prev) { + send_openflow_buffer_to_remote(ofpbuf_clone(buffer), prev); + } + prev = r; + } + if (prev) { + send_openflow_buffer_to_remote(buffer, prev); + } else { + ofpbuf_delete(buffer); + } + return 0; + } +} + +/* Takes ownership of 'buffer' and transmits it to 'dp''s controller. If the + * packet can be saved in a buffer, then only the first max_len bytes of + * 'buffer' are sent; otherwise, all of 'buffer' is sent. 'reason' indicates + * why 'buffer' is being sent. 'max_len' sets the maximum number of bytes that + * the caller wants to be sent. */ +void +dp_output_control(struct datapath *dp, struct ofpbuf *buffer, int in_port, + size_t max_len, int reason) +{ + struct ofp_packet_in *opi; + size_t total_len; + uint32_t buffer_id; + + buffer_id = save_buffer(buffer); + total_len = buffer->size; + if (buffer_id != UINT32_MAX && buffer->size > max_len) { + buffer->size = max_len; + } + + opi = ofpbuf_push_uninit(buffer, offsetof(struct ofp_packet_in, data)); + opi->header.version = OFP_VERSION; + opi->header.type = OFPT_PACKET_IN; + opi->header.length = htons(buffer->size); + opi->header.xid = htonl(0); + opi->buffer_id = htonl(buffer_id); + opi->total_len = htons(total_len); + opi->in_port = htons(in_port); + opi->reason = reason; + opi->pad = 0; + send_openflow_buffer(dp, buffer, NULL); +} + +static void +fill_queue_desc(struct ofpbuf *buffer, struct sw_queue *q, + struct ofp_packet_queue *desc) +{ + struct ofp_queue_prop_min_rate *mr; + int len; + + len = sizeof(struct ofp_packet_queue) + + sizeof(struct ofp_queue_prop_min_rate); + desc->queue_id = htonl(q->queue_id); + desc->len = htons(len); + + /* Property list */ + mr = ofpbuf_put_zeros(buffer, sizeof *mr); + mr->prop_header.property = htons(OFPQT_MIN_RATE); + len = sizeof(struct ofp_queue_prop_min_rate); + mr->prop_header.len = htons(len); + mr->rate = htons(q->min_rate); +} + + +static void +fill_port_desc(struct sw_port *p, struct ofp_phy_port *desc) +{ + desc->port_no = htons(p->port_no); + if (IS_HW_PORT(p)) { +#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) + of_hw_driver_t *hw_drv; + + hw_drv = p->dp->hw_drv; + strncpy((char *) desc->name, p->hw_name, sizeof desc->name); + desc->name[sizeof desc->name - 1] = '\0'; + /* Update local port state */ + if (hw_drv->port_link_get(hw_drv, p->port_no)) { + p->state &= ~OFPPS_LINK_DOWN; + } else { + p->state |= OFPPS_LINK_DOWN; + } + if (hw_drv->port_enable_get(hw_drv, p->port_no)) { + p->config &= ~OFPPC_PORT_DOWN; + } else { + p->config |= OFPPC_PORT_DOWN; + } + /* FIXME: Add current, supported and advertised features */ +#endif + } else if (p->netdev) { + strncpy((char *) desc->name, netdev_get_name(p->netdev), + sizeof desc->name); + desc->name[sizeof desc->name - 1] = '\0'; + memcpy(desc->hw_addr, netdev_get_etheraddr(p->netdev), ETH_ADDR_LEN); + desc->curr= htonl(netdev_get_features(p->netdev, + NETDEV_FEAT_CURRENT)); + desc->supported = htonl(netdev_get_features(p->netdev, + NETDEV_FEAT_SUPPORTED)); + desc->advertised = htonl(netdev_get_features(p->netdev, + NETDEV_FEAT_ADVERTISED)); + desc->peer = htonl(netdev_get_features(p->netdev, NETDEV_FEAT_PEER)); + } + desc->config = htonl(p->config); + desc->state = htonl(p->state); +} + +static void +dp_send_features_reply(struct datapath *dp, const struct sender *sender) +{ + struct ofpbuf *buffer; + struct ofp_switch_features *ofr; + struct sw_port *p; + + ofr = make_openflow_reply(sizeof *ofr, OFPT_FEATURES_REPLY, + sender, &buffer); + ofr->datapath_id = htonll(dp->id); + ofr->n_tables = dp->chain->n_tables; + ofr->n_buffers = htonl(N_PKT_BUFFERS); + ofr->capabilities = htonl(OFP_SUPPORTED_CAPABILITIES); + ofr->actions = htonl(OFP_SUPPORTED_ACTIONS); + LIST_FOR_EACH (p, struct sw_port, node, &dp->port_list) { + struct ofp_phy_port *opp = ofpbuf_put_uninit(buffer, sizeof *opp); + memset(opp, 0, sizeof *opp); + fill_port_desc(p, opp); + } + send_openflow_buffer(dp, buffer, sender); +} + +void +update_port_flags(struct datapath *dp, const struct ofp_port_mod *opm) +{ + struct sw_port *p = dp_lookup_port(dp, ntohs(opm->port_no)); + + /* Make sure the port id hasn't changed since this was sent */ + if (!p || memcmp(opm->hw_addr, netdev_get_etheraddr(p->netdev), + ETH_ADDR_LEN) != 0) { + return; + } + + + if (opm->mask) { + uint32_t config_mask = ntohl(opm->mask); + p->config &= ~config_mask; + p->config |= ntohl(opm->config) & config_mask; + } +} + +static void +send_port_status(struct sw_port *p, uint8_t status) +{ + struct ofpbuf *buffer; + struct ofp_port_status *ops; + ops = make_openflow_xid(sizeof *ops, OFPT_PORT_STATUS, 0, &buffer); + ops->reason = status; + memset(ops->pad, 0, sizeof ops->pad); + fill_port_desc(p, &ops->desc); + + send_openflow_buffer(p->dp, buffer, NULL); +} + +void +dp_send_flow_end(struct datapath *dp, struct sw_flow *flow, + enum ofp_flow_removed_reason reason) +{ + struct ofpbuf *buffer; + struct ofp_flow_removed *ofr; + uint64_t tdiff = time_msec() - flow->created; + uint32_t sec = tdiff / 1000; + + if (!flow->send_flow_rem) { + return; + } + + if (flow->emerg_flow) { + return; + } + + ofr = make_openflow_xid(sizeof *ofr, OFPT_FLOW_REMOVED, 0, &buffer); + if (!ofr) { + return; + } + + flow_fill_match(&ofr->match, &flow->key.flow, flow->key.wildcards); + + ofr->cookie = htonll(flow->cookie); + ofr->priority = htons(flow->priority); + ofr->reason = reason; + + ofr->duration_sec = htonl(sec); + ofr->duration_nsec = htonl((tdiff - (sec * 1000)) * 1000000); + ofr->idle_timeout = htons(flow->idle_timeout); + + ofr->packet_count = htonll(flow->packet_count); + ofr->byte_count = htonll(flow->byte_count); + + send_openflow_buffer(dp, buffer, NULL); +} + +void +dp_send_error_msg(struct datapath *dp, const struct sender *sender, + uint16_t type, uint16_t code, const void *data, size_t len) +{ + struct ofpbuf *buffer; + struct ofp_error_msg *oem; + oem = make_openflow_reply(sizeof(*oem)+len, OFPT_ERROR, sender, &buffer); + oem->type = htons(type); + oem->code = htons(code); + memcpy(oem->data, data, len); + send_openflow_buffer(dp, buffer, sender); +} + +static void +fill_flow_stats(struct ofpbuf *buffer, struct sw_flow *flow, + int table_idx, uint64_t now) +{ + struct ofp_flow_stats *ofs; + int length = sizeof *ofs + flow->sf_acts->actions_len; + uint64_t tdiff = now - flow->created; + uint32_t sec = tdiff / 1000; + ofs = ofpbuf_put_uninit(buffer, length); + ofs->length = htons(length); + ofs->table_id = table_idx; + ofs->pad = 0; + ofs->match.wildcards = htonl(flow->key.wildcards); + ofs->match.in_port = flow->key.flow.in_port; + memcpy(ofs->match.dl_src, flow->key.flow.dl_src, ETH_ADDR_LEN); + memcpy(ofs->match.dl_dst, flow->key.flow.dl_dst, ETH_ADDR_LEN); + ofs->match.dl_vlan = flow->key.flow.dl_vlan; + ofs->match.dl_type = flow->key.flow.dl_type; + ofs->match.nw_tos = flow->key.flow.nw_tos; + ofs->match.nw_src = flow->key.flow.nw_src; + ofs->match.nw_dst = flow->key.flow.nw_dst; + ofs->match.nw_proto = flow->key.flow.nw_proto; + ofs->match.dl_vlan_pcp = flow->key.flow.dl_vlan_pcp; + ofs->match.tp_src = flow->key.flow.tp_src; + ofs->match.tp_dst = flow->key.flow.tp_dst; + ofs->duration_sec = htonl(sec); + ofs->duration_nsec = htonl((tdiff - (sec * 1000)) * 1000000); + ofs->cookie = htonll(flow->cookie); + ofs->priority = htons(flow->priority); + ofs->idle_timeout = htons(flow->idle_timeout); + ofs->hard_timeout = htons(flow->hard_timeout); + memset(&ofs->pad2, 0, sizeof ofs->pad2); + ofs->packet_count = htonll(flow->packet_count); + ofs->byte_count = htonll(flow->byte_count); + memcpy(ofs->actions, flow->sf_acts->actions, flow->sf_acts->actions_len); +} + + +/* 'buffer' was received on 'p', which may be a a physical switch port or a + * null pointer. Process it according to 'dp''s flow table. Returns 0 if + * successful, in which case 'buffer' is destroyed, or -ESRCH if there is no + * matching flow, in which case 'buffer' still belongs to the caller. */ +int run_flow_through_tables(struct datapath *dp, struct ofpbuf *buffer, + struct sw_port *p) +{ + struct sw_flow_key key; + struct sw_flow *flow; + + key.wildcards = 0; + if (flow_extract(buffer, p ? p->port_no : OFPP_NONE, &key.flow) + && (dp->flags & OFPC_FRAG_MASK) == OFPC_FRAG_DROP) { + /* Drop fragment. */ + ofpbuf_delete(buffer); + return 0; + } + + if (p && p->config & (OFPPC_NO_RECV | OFPPC_NO_RECV_STP) + && p->config & (!eth_addr_equals(key.flow.dl_dst, stp_eth_addr) + ? OFPPC_NO_RECV : OFPPC_NO_RECV_STP)) { + ofpbuf_delete(buffer); + return 0; + } + + flow = chain_lookup(dp->chain, &key, 0); + if (flow != NULL) { + flow_used(flow, buffer); + execute_actions(dp, buffer, &key, flow->sf_acts->actions, + flow->sf_acts->actions_len, false); + return 0; + } else { + return -ESRCH; + } +} + +/* 'buffer' was received on 'p', which may be a a physical switch port or a + * null pointer. Process it according to 'dp''s flow table, sending it up to + * the controller if no flow matches. Takes ownership of 'buffer'. */ +void fwd_port_input(struct datapath *dp, struct ofpbuf *buffer, + struct sw_port *p) +{ + if (run_flow_through_tables(dp, buffer, p)) { + dp_output_control(dp, buffer, p->port_no, + dp->miss_send_len, OFPR_NO_MATCH); + } +} + +static struct ofpbuf * +make_barrier_reply(const struct ofp_header *req) +{ + size_t size = ntohs(req->length); + struct ofpbuf *buf = ofpbuf_new(size); + struct ofp_header *reply = ofpbuf_put(buf, req, size); + + reply->type = OFPT_BARRIER_REPLY; + return buf; +} + +static int +recv_barrier_request(struct datapath *dp, const struct sender *sender, + const void *ofph) +{ + return send_openflow_buffer(dp, make_barrier_reply(ofph), sender); +} + +static int +recv_features_request(struct datapath *dp, const struct sender *sender, + const void *msg UNUSED) +{ + dp_send_features_reply(dp, sender); + return 0; +} + +static int +recv_get_config_request(struct datapath *dp, const struct sender *sender, + const void *msg UNUSED) +{ + struct ofpbuf *buffer; + struct ofp_switch_config *osc; + + osc = make_openflow_reply(sizeof *osc, OFPT_GET_CONFIG_REPLY, + sender, &buffer); + + osc->flags = htons(dp->flags); + osc->miss_send_len = htons(dp->miss_send_len); + + return send_openflow_buffer(dp, buffer, sender); +} + +static int +recv_set_config(struct datapath *dp, const struct sender *sender UNUSED, + const void *msg) +{ + const struct ofp_switch_config *osc = msg; + int flags; + + flags = ntohs(osc->flags) & OFPC_FRAG_MASK; + if ((flags & OFPC_FRAG_MASK) != OFPC_FRAG_NORMAL + && (flags & OFPC_FRAG_MASK) != OFPC_FRAG_DROP) { + flags = (flags & ~OFPC_FRAG_MASK) | OFPC_FRAG_DROP; + } + dp->flags = flags; + dp->miss_send_len = ntohs(osc->miss_send_len); + return 0; +} + +static int +recv_packet_out(struct datapath *dp, const struct sender *sender, + const void *msg) +{ + const struct ofp_packet_out *opo = msg; + struct sw_flow_key key; + uint16_t v_code; + struct ofpbuf *buffer; + size_t actions_len = ntohs(opo->actions_len); + + if (actions_len > (ntohs(opo->header.length) - sizeof *opo)) { + VLOG_DBG_RL(&rl, "message too short for number of actions"); + return -EINVAL; + } + + if (ntohl(opo->buffer_id) == (uint32_t) -1) { + /* FIXME: can we avoid copying data here? */ + int data_len = ntohs(opo->header.length) - sizeof *opo - actions_len; + buffer = ofpbuf_new(data_len); + ofpbuf_put(buffer, (uint8_t *)opo->actions + actions_len, data_len); + } else { + buffer = retrieve_buffer(ntohl(opo->buffer_id)); + if (!buffer) { + return -ESRCH; + } + } + + flow_extract(buffer, ntohs(opo->in_port), &key.flow); + + v_code = validate_actions(dp, &key, opo->actions, actions_len); + if (v_code != ACT_VALIDATION_OK) { + dp_send_error_msg(dp, sender, OFPET_BAD_ACTION, v_code, + msg, ntohs(opo->header.length)); + goto error; + } + + execute_actions(dp, buffer, &key, opo->actions, actions_len, true); + + return 0; + +error: + ofpbuf_delete(buffer); + return -EINVAL; +} + +static int +recv_port_mod(struct datapath *dp, const struct sender *sender UNUSED, + const void *msg) +{ + const struct ofp_port_mod *opm = msg; + + update_port_flags(dp, opm); + + return 0; +} + +static int +add_flow(struct datapath *dp, const struct sender *sender, + const struct ofp_flow_mod *ofm) +{ + int error = -ENOMEM; + uint16_t v_code; + struct sw_flow *flow; + size_t actions_len = ntohs(ofm->header.length) - sizeof *ofm; + int overlap; + + /* Allocate memory. */ + flow = flow_alloc(actions_len); + if (flow == NULL) + goto error; + + flow_extract_match(&flow->key, &ofm->match); + + v_code = validate_actions(dp, &flow->key, ofm->actions, actions_len); + if (v_code != ACT_VALIDATION_OK) { + dp_send_error_msg(dp, sender, OFPET_BAD_ACTION, v_code, + ofm, ntohs(ofm->header.length)); + goto error_free_flow; + } + + flow->priority = flow->key.wildcards ? ntohs(ofm->priority) : -1; + + if (ntohs(ofm->flags) & OFPFF_CHECK_OVERLAP) { + /* check whether there is any conflict */ + overlap = chain_has_conflict(dp->chain, &flow->key, flow->priority, + false); + if (overlap){ + dp_send_error_msg(dp, sender, OFPET_FLOW_MOD_FAILED, + OFPFMFC_OVERLAP, ofm, ntohs(ofm->header.length)); + goto error_free_flow; + } + } + + if (ntohs(ofm->flags) & OFPFF_EMERG) { + if (ntohs(ofm->idle_timeout) != OFP_FLOW_PERMANENT + || ntohs(ofm->hard_timeout) != OFP_FLOW_PERMANENT) { + dp_send_error_msg(dp, sender, OFPET_FLOW_MOD_FAILED, + OFPFMFC_BAD_EMERG_TIMEOUT, ofm, + ntohs(ofm->header.length)); + goto error_free_flow; + } + } + + /* Fill out flow. */ + flow->cookie = ntohll(ofm->cookie); + flow->idle_timeout = ntohs(ofm->idle_timeout); + flow->hard_timeout = ntohs(ofm->hard_timeout); + flow->send_flow_rem = (ntohs(ofm->flags) & OFPFF_SEND_FLOW_REM) ? 1 : 0; + flow->emerg_flow = (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0; + flow_setup_actions(flow, ofm->actions, actions_len); + + /* Act. */ + error = chain_insert(dp->chain, flow, + (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0); + if (error == -ENOBUFS) { + dp_send_error_msg(dp, sender, OFPET_FLOW_MOD_FAILED, + OFPFMFC_ALL_TABLES_FULL, ofm, ntohs(ofm->header.length)); + goto error_free_flow; + } else if (error) { + goto error_free_flow; + } + + error = 0; + if (ntohl(ofm->buffer_id) != UINT32_MAX) { + struct ofpbuf *buffer = retrieve_buffer(ntohl(ofm->buffer_id)); + if (buffer) { + struct sw_flow_key key; + uint16_t in_port = ntohs(ofm->match.in_port); + flow_extract(buffer, in_port, &key.flow); + flow_used(flow, buffer); + execute_actions(dp, buffer, &key, + ofm->actions, actions_len, false); + } else { + error = -ESRCH; + } + } + return error; + +error_free_flow: + flow_free(flow); +error: + if (ntohl(ofm->buffer_id) != (uint32_t) -1) + discard_buffer(ntohl(ofm->buffer_id)); + return error; +} + +static int +mod_flow(struct datapath *dp, const struct sender *sender, + const struct ofp_flow_mod *ofm) +{ + int error = -ENOMEM; + uint16_t v_code; + size_t actions_len = ntohs(ofm->header.length) - sizeof *ofm; + struct sw_flow *flow; + int strict; + + /* Allocate memory. */ + flow = flow_alloc(actions_len); + if (flow == NULL) + goto error; + + flow_extract_match(&flow->key, &ofm->match); + + v_code = validate_actions(dp, &flow->key, ofm->actions, actions_len); + if (v_code != ACT_VALIDATION_OK) { + dp_send_error_msg(dp, sender, OFPET_BAD_ACTION, v_code, + ofm, ntohs(ofm->header.length)); + goto error_free_flow; + } + + flow->priority = flow->key.wildcards ? ntohs(ofm->priority) : -1; + strict = (ofm->command == htons(OFPFC_MODIFY_STRICT)) ? 1 : 0; + + /* First try to modify existing flows if any */ + /* if there is no matching flow, add it */ + if (!chain_modify(dp->chain, &flow->key, flow->priority, + strict, ofm->actions, actions_len, + (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0)) { + /* Fill out flow. */ + flow->cookie = ntohll(ofm->cookie); + flow->idle_timeout = ntohs(ofm->idle_timeout); + flow->hard_timeout = ntohs(ofm->hard_timeout); + flow->send_flow_rem = (ntohs(ofm->flags) & OFPFF_SEND_FLOW_REM) ? 1 : 0; + flow->emerg_flow = (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0; + flow_setup_actions(flow, ofm->actions, actions_len); + error = chain_insert(dp->chain, flow, + (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0); + if (error == -ENOBUFS) { + dp_send_error_msg(dp, sender, OFPET_FLOW_MOD_FAILED, + OFPFMFC_ALL_TABLES_FULL, ofm, + ntohs(ofm->header.length)); + goto error_free_flow; + } else if (error) { + goto error_free_flow; + } + } + + error = 0; + if (ntohl(ofm->buffer_id) != UINT32_MAX) { + struct ofpbuf *buffer = retrieve_buffer(ntohl(ofm->buffer_id)); + if (buffer) { + struct sw_flow_key skb_key; + uint16_t in_port = ntohs(ofm->match.in_port); + flow_extract(buffer, in_port, &skb_key.flow); + execute_actions(dp, buffer, &skb_key, + ofm->actions, actions_len, false); + } else { + error = -ESRCH; + } + } + return error; + +error_free_flow: + flow_free(flow); +error: + if (ntohl(ofm->buffer_id) != (uint32_t) -1) + discard_buffer(ntohl(ofm->buffer_id)); + return error; +} + +static int +recv_flow(struct datapath *dp, const struct sender *sender, + const void *msg) +{ + const struct ofp_flow_mod *ofm = msg; + uint16_t command = ntohs(ofm->command); + + if (command == OFPFC_ADD) { + return add_flow(dp, sender, ofm); + } else if ((command == OFPFC_MODIFY) || (command == OFPFC_MODIFY_STRICT)) { + return mod_flow(dp, sender, ofm); + } else if (command == OFPFC_DELETE) { + struct sw_flow_key key; + flow_extract_match(&key, &ofm->match); + return chain_delete(dp->chain, &key, ofm->out_port, 0, 0, + (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0) + ? 0 : -ESRCH; + } else if (command == OFPFC_DELETE_STRICT) { + struct sw_flow_key key; + uint16_t priority; + flow_extract_match(&key, &ofm->match); + priority = key.wildcards ? ntohs(ofm->priority) : -1; + return chain_delete(dp->chain, &key, ofm->out_port, priority, 1, + (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0) + ? 0 : -ESRCH; + } else { + return -ENODEV; + } +} + +static int +desc_stats_dump(struct datapath *dp UNUSED, void *state UNUSED, + struct ofpbuf *buffer) +{ + struct ofp_desc_stats *ods = ofpbuf_put_uninit(buffer, sizeof *ods); + + strncpy(ods->mfr_desc, &mfr_desc, sizeof ods->mfr_desc); + strncpy(ods->hw_desc, &hw_desc, sizeof ods->hw_desc); + strncpy(ods->sw_desc, &sw_desc, sizeof ods->sw_desc); + strncpy(ods->dp_desc, dp->dp_desc, sizeof ods->dp_desc); + strncpy(ods->serial_num, &serial_num, sizeof ods->serial_num); + + return 0; +} + +struct flow_stats_state { + int table_idx; + struct sw_table_position position; + struct ofp_flow_stats_request rq; + uint64_t now; /* Current time in milliseconds */ + + struct ofpbuf *buffer; +}; + +#define MAX_FLOW_STATS_BYTES 4096 +#define EMERG_TABLE_ID_FOR_STATS 0xfe + +static int +flow_stats_init(const void *body, int body_len UNUSED, void **state) +{ + const struct ofp_flow_stats_request *fsr = body; + struct flow_stats_state *s = xmalloc(sizeof *s); + s->table_idx = fsr->table_id == 0xff ? 0 : fsr->table_id; + memset(&s->position, 0, sizeof s->position); + s->rq = *fsr; + *state = s; + return 0; +} + +static int flow_stats_dump_callback(struct sw_flow *flow, void *private) +{ + struct flow_stats_state *s = private; + fill_flow_stats(s->buffer, flow, s->table_idx, s->now); + return s->buffer->size >= MAX_FLOW_STATS_BYTES; +} + +static int flow_stats_dump(struct datapath *dp, void *state, + struct ofpbuf *buffer) +{ + struct flow_stats_state *s = state; + struct sw_flow_key match_key; + + flow_extract_match(&match_key, &s->rq.match); + s->buffer = buffer; + s->now = time_msec(); + + if (s->rq.table_id == EMERG_TABLE_ID_FOR_STATS) { + struct sw_table *table = dp->chain->emerg_table; + + table->iterate(table, &match_key, s->rq.out_port, + &s->position, flow_stats_dump_callback, s); + } else { + while (s->table_idx < dp->chain->n_tables + && (s->rq.table_id == 0xff || s->rq.table_id == s->table_idx)) + { + struct sw_table *table = dp->chain->tables[s->table_idx]; + + if (table->iterate(table, &match_key, s->rq.out_port, + &s->position, flow_stats_dump_callback, s)) + break; + + s->table_idx++; + memset(&s->position, 0, sizeof s->position); + } + } + return s->buffer->size >= MAX_FLOW_STATS_BYTES; +} + +static void flow_stats_done(void *state) +{ + free(state); +} + +struct aggregate_stats_state { + struct ofp_aggregate_stats_request rq; +}; + +static int +aggregate_stats_init(const void *body, int body_len UNUSED, void **state) +{ + const struct ofp_aggregate_stats_request *rq = body; + struct aggregate_stats_state *s = xmalloc(sizeof *s); + s->rq = *rq; + *state = s; + return 0; +} + +static int aggregate_stats_dump_callback(struct sw_flow *flow, void *private) +{ + struct ofp_aggregate_stats_reply *rpy = private; + rpy->packet_count += flow->packet_count; + rpy->byte_count += flow->byte_count; + rpy->flow_count++; + return 0; +} + +static int aggregate_stats_dump(struct datapath *dp, void *state, + struct ofpbuf *buffer) +{ + struct aggregate_stats_state *s = state; + struct ofp_aggregate_stats_request *rq = &s->rq; + struct ofp_aggregate_stats_reply *rpy; + struct sw_table_position position; + struct sw_flow_key match_key; + int table_idx; + int error; + + rpy = ofpbuf_put_uninit(buffer, sizeof *rpy); + memset(rpy, 0, sizeof *rpy); + + flow_extract_match(&match_key, &rq->match); + table_idx = rq->table_id == 0xff ? 0 : rq->table_id; + memset(&position, 0, sizeof position); + + if (rq->table_id == EMERG_TABLE_ID_FOR_STATS) { + struct sw_table *table = dp->chain->emerg_table; + + error = table->iterate(table, &match_key, rq->out_port, &position, + aggregate_stats_dump_callback, rpy); + if (error) + return error; + } else { + while (table_idx < dp->chain->n_tables + && (rq->table_id == 0xff || rq->table_id == table_idx)) + { + struct sw_table *table = dp->chain->tables[table_idx]; + + error = table->iterate(table, &match_key, rq->out_port, &position, + aggregate_stats_dump_callback, rpy); + if (error) + return error; + + table_idx++; + memset(&position, 0, sizeof position); + } + } + + rpy->packet_count = htonll(rpy->packet_count); + rpy->byte_count = htonll(rpy->byte_count); + rpy->flow_count = htonl(rpy->flow_count); + return 0; +} + +static void aggregate_stats_done(void *state) +{ + free(state); +} + +static int +table_stats_dump(struct datapath *dp, void *state UNUSED, + struct ofpbuf *buffer) +{ + int i; + for (i = 0; i < dp->chain->n_tables; i++) { + struct ofp_table_stats *ots = ofpbuf_put_uninit(buffer, sizeof *ots); + struct sw_table_stats stats; + dp->chain->tables[i]->stats(dp->chain->tables[i], &stats); + strncpy(ots->name, stats.name, sizeof ots->name); + ots->table_id = i; + ots->wildcards = htonl(stats.wildcards); + memset(ots->pad, 0, sizeof ots->pad); + ots->max_entries = htonl(stats.max_flows); + ots->active_count = htonl(stats.n_flows); + ots->lookup_count = htonll(stats.n_lookup); + ots->matched_count = htonll(stats.n_matched); + } + return 0; +} + +struct port_stats_state { + int start_port; /* port to start dumping from */ + int port_no; /* from ofp_stats_request */ +}; + +struct queue_stats_state { + uint16_t port; + uint32_t queue_id; +}; + +static int +port_stats_init(const void *body, int body_len UNUSED, void **state) +{ + struct port_stats_state *s = xmalloc(sizeof *s); + const struct ofp_port_stats_request *psr = body; + + s->start_port = 1; + s->port_no = ntohs(psr->port_no); + *state = s; + return 0; +} + +static void +dump_port_stats(struct datapath *dp, struct sw_port *port, + struct ofpbuf *buffer) +{ + struct ofp_port_stats *ops = ofpbuf_put_uninit(buffer, sizeof *ops); + ops->port_no = htons(port->port_no); + memset(ops->pad, 0, sizeof ops->pad); + if (IS_HW_PORT(port)) { +#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) + struct ofp_port_stats stats; + + memset(&stats, 0, sizeof(stats)); + if (dp->hw_drv->port_stats_get) { + if (dp->hw_drv->port_stats_get(dp->hw_drv, port->port_no, + &stats) < 0) { + VLOG_WARN("Error getting stats on port %d\n", port->port_no); + return; + } + } + ops->rx_packets = htonll(stats.rx_packets); + ops->tx_packets = htonll(stats.tx_packets); + ops->rx_bytes = htonll(stats.rx_bytes); + ops->tx_bytes = htonll(stats.tx_bytes); + ops->rx_dropped = htonll(stats.rx_dropped); + ops->tx_dropped = htonll(stats.tx_dropped); + ops->rx_errors = htonll(stats.rx_errors); + ops->tx_errors = htonll(stats.tx_errors); + ops->rx_frame_err = htonll(stats.rx_frame_err); + ops->rx_over_err = htonll(stats.rx_over_err); + ops->rx_crc_err = htonll(stats.rx_crc_err); + ops->collisions = htonll(stats.collisions); +#endif + } else { + ops->rx_packets = htonll(port->rx_packets); + ops->tx_packets = htonll(port->tx_packets); + ops->rx_bytes = htonll(port->rx_bytes); + ops->tx_bytes = htonll(port->tx_bytes); + ops->rx_dropped = htonll(-1); + ops->tx_dropped = htonll(port->tx_dropped); + ops->rx_errors = htonll(-1); + ops->tx_errors = htonll(-1); + ops->rx_frame_err = htonll(-1); + ops->rx_over_err = htonll(-1); + ops->rx_crc_err = htonll(-1); + ops->collisions = htonll(-1); + } +} + +/* Although this makes some of the motions of being called + * multiple times preserving state, it doesn't actually support + * that process; the for loop can never break early. + */ +static int port_stats_dump(struct datapath *dp, void *state, + struct ofpbuf *buffer) +{ + struct port_stats_state *s = state; + struct sw_port *p = NULL; + int i = 0; + + if (s->port_no == OFPP_NONE) { + /* Dump statistics for all ports */ + for (i = s->start_port; i < DP_MAX_PORTS; i++) { + p = dp_lookup_port(dp, i); + if (p && PORT_IN_USE(p)) { + dump_port_stats(dp, p, buffer); + } + } + if (dp->local_port) { + dump_port_stats(dp, dp->local_port, buffer); + } + } else { + /* Dump statistics for a single port */ + p = dp_lookup_port(dp, s->port_no); + if (p && PORT_IN_USE(p)) { + dump_port_stats(dp, p, buffer); + } + } + + return 0; +} + +static void port_stats_done(void *state) +{ + free(state); +} + +static int +queue_stats_init(const void *body, int body_len UNUSED, void **state) +{ + const struct ofp_queue_stats_request *qsr = body; + struct queue_stats_state *s = xmalloc(sizeof *s); + s->port = ntohs(qsr->port_no); + s->queue_id = ntohl(qsr->queue_id); + *state = s; + return 0; +} + +static void +dump_queue_stats(struct sw_queue *q, struct ofpbuf *buffer) +{ + struct ofp_queue_stats *oqs = ofpbuf_put_uninit(buffer, sizeof *oqs); + oqs->port_no = htons(q->port->port_no); + oqs->queue_id = htonl(q->queue_id); + oqs->tx_bytes = htonll(q->tx_bytes); + oqs->tx_packets = htonll(q->tx_packets); + oqs->tx_errors = htonll(q->tx_errors); +} + +static int +queue_stats_dump(struct datapath *dp, void *state, + struct ofpbuf *buffer) +{ + struct queue_stats_state *s = state; + struct sw_queue *q; + struct sw_port *p; + + + if (s->port == OFPP_ALL) { + LIST_FOR_EACH(p, struct sw_port, node, &dp->port_list) { + if (p->port_no < OFPP_MAX) { + if (s->queue_id == OFPQ_ALL) { + LIST_FOR_EACH(q, struct sw_queue, node, &p->queue_list) { + dump_queue_stats(q,buffer); + } + } + else { + q = dp_lookup_queue(p, s->queue_id); + if (q) { + dump_queue_stats(q, buffer); + } + } + } + } + } + else { + p = dp_lookup_port(dp, s->port); + if (p) { + if (s->queue_id == OFPQ_ALL) { + LIST_FOR_EACH(q, struct sw_queue, node, &p->queue_list) { + dump_queue_stats(q,buffer); + } + } + else { + q = dp_lookup_queue(p, s->queue_id); + if (q) { + dump_queue_stats(q, buffer); + } + } + } + } + return 0; +} + +static void +queue_stats_done(void *state) +{ + free(state); +} + +/* + * We don't define any vendor_stats_state, we let the actual + * vendor implementation do that. + * The only requirement is that the first member of that object + * should be the vendor id. + * Jean II + * + * Basically, it would look like : + * struct acme_stats_state { + * uint32_t vendor; // ACME_VENDOR_ID. + * <...> // Other stuff. + * }; + */ +static int +vendor_stats_init(const void *body, int body_len UNUSED, + void **state UNUSED) +{ + /* min_body was checked, this should be safe */ + const uint32_t vendor = ntohl(*((uint32_t *)body)); + int err; + + switch (vendor) { + default: + err = -EINVAL; + } + + return err; +} + +static int +vendor_stats_dump(struct datapath *dp UNUSED, void *state, + struct ofpbuf *buffer UNUSED) +{ + const uint32_t vendor = *((uint32_t *)state); + int err; + + switch (vendor) { + default: + /* Should never happen */ + err = 0; + } + + return err; +} + +static void +vendor_stats_done(void *state) +{ + const uint32_t vendor = *((uint32_t *) state); + + switch (vendor) { + default: + /* Should never happen */ + free(state); + } + + return; +} + +struct stats_type { + /* Value for 'type' member of struct ofp_stats_request. */ + int type; + + /* Minimum and maximum acceptable number of bytes in body member of + * struct ofp_stats_request. */ + size_t min_body, max_body; + + /* Prepares to dump some kind of datapath statistics. 'body' and + * 'body_len' are the 'body' member of the struct ofp_stats_request. + * Returns zero if successful, otherwise a negative error code. + * May initialize '*state' to state information. May be null if no + * initialization is required.*/ + int (*init)(const void *body, int body_len, void **state); + + /* Appends statistics for 'dp' to 'buffer', which initially contains a + * struct ofp_stats_reply. On success, it should return 1 if it should be + * called again later with another buffer, 0 if it is done, or a negative + * errno value on failure. */ + int (*dump)(struct datapath *dp, void *state, struct ofpbuf *buffer); + + /* Cleans any state created by the init or dump functions. May be null + * if no cleanup is required. */ + void (*done)(void *state); +}; + +static const struct stats_type stats[] = { + { + OFPST_DESC, + 0, + 0, + NULL, + desc_stats_dump, + NULL + }, + { + OFPST_FLOW, + sizeof(struct ofp_flow_stats_request), + sizeof(struct ofp_flow_stats_request), + flow_stats_init, + flow_stats_dump, + flow_stats_done + }, + { + OFPST_AGGREGATE, + sizeof(struct ofp_aggregate_stats_request), + sizeof(struct ofp_aggregate_stats_request), + aggregate_stats_init, + aggregate_stats_dump, + aggregate_stats_done + }, + { + OFPST_TABLE, + 0, + 0, + NULL, + table_stats_dump, + NULL + }, + { + OFPST_PORT, + sizeof(struct ofp_port_stats_request), + sizeof(struct ofp_port_stats_request), + port_stats_init, + port_stats_dump, + port_stats_done + }, + { + OFPST_QUEUE, + sizeof(struct ofp_queue_stats_request), + sizeof(struct ofp_queue_stats_request), + queue_stats_init, + queue_stats_dump, + queue_stats_done + }, + { + OFPST_VENDOR, + 8, /* vendor + subtype */ + 32, /* whatever */ + vendor_stats_init, + vendor_stats_dump, + vendor_stats_done + }, +}; + +struct stats_dump_cb { + bool done; + struct ofp_stats_request *rq; + struct sender sender; + const struct stats_type *s; + void *state; +}; + +static int +stats_dump(struct datapath *dp, void *cb_) +{ + struct stats_dump_cb *cb = cb_; + struct ofp_stats_reply *osr; + struct ofpbuf *buffer; + int err; + + if (cb->done) { + return 0; + } + + osr = make_openflow_reply(sizeof *osr, OFPT_STATS_REPLY, &cb->sender, + &buffer); + osr->type = htons(cb->s->type); + osr->flags = 0; + + err = cb->s->dump(dp, cb->state, buffer); + if (err >= 0) { + int err2; + if (!err) { + cb->done = true; + } else { + /* Buffer might have been reallocated, so find our data again. */ + osr = ofpbuf_at_assert(buffer, 0, sizeof *osr); + osr->flags = ntohs(OFPSF_REPLY_MORE); + } + err2 = send_openflow_buffer(dp, buffer, &cb->sender); + if (err2) { + err = err2; + } + } + + return err; +} + +static void +stats_done(void *cb_) +{ + struct stats_dump_cb *cb = cb_; + if (cb) { + if (cb->s->done) { + cb->s->done(cb->state); + } + if (cb->rq) { + free(cb->rq); + } + free(cb); + } +} + +static int +recv_stats_request(struct datapath *dp UNUSED, const struct sender *sender, + const void *oh) +{ + const struct ofp_stats_request *rq = oh; + size_t rq_len = ntohs(rq->header.length); + const struct stats_type *st; + struct stats_dump_cb *cb; + int type, body_len; + int err; + + type = ntohs(rq->type); + for (st = stats; ; st++) { + if (st >= &stats[ARRAY_SIZE(stats)]) { + VLOG_WARN_RL(&rl, "received stats request of unknown type %d", + type); + return -EINVAL; + } else if (type == st->type) { + break; + } + } + + cb = xmalloc(sizeof *cb); + cb->done = false; + cb->rq = xmemdup(rq, rq_len); + cb->sender = *sender; + cb->s = st; + cb->state = NULL; + + body_len = rq_len - offsetof(struct ofp_stats_request, body); + if (body_len < cb->s->min_body || body_len > cb->s->max_body) { + VLOG_WARN_RL(&rl, "stats request type %d with bad body length %d", + type, body_len); + err = -EINVAL; + goto error; + } + + if (cb->s->init) { + err = cb->s->init(rq->body, body_len, &cb->state); + if (err) { + VLOG_WARN_RL(&rl, + "failed initialization of stats request type %d: %s", + type, strerror(-err)); + goto error; + } + } + + remote_start_dump(sender->remote, stats_dump, stats_done, cb); + return 0; + +error: + free(cb->rq); + free(cb); + return err; +} + +static int +recv_echo_request(struct datapath *dp, const struct sender *sender, + const void *oh) +{ + return send_openflow_buffer(dp, make_echo_reply(oh), sender); +} + +static int +recv_echo_reply(struct datapath *dp UNUSED, const struct sender *sender UNUSED, + const void *oh UNUSED) +{ + return 0; +} + +static int +recv_queue_get_config_request(struct datapath *dp, const struct sender *sender, + const void *oh) +{ + struct ofpbuf *buffer; + struct ofp_queue_get_config_reply *ofq_reply; + const struct ofp_queue_get_config_request *ofq_request; + struct sw_port *p; + struct sw_queue *q; + uint16_t port_no; + + ofq_request = (struct ofp_queue_get_config_request *)oh; + port_no = ntohs(ofq_request->port); + + if (port_no < OFPP_MAX) { + /* Find port under query */ + p = dp_lookup_port(dp,port_no); + + /* if the port under query doesn't exist, send an error */ + if (!p || (p->port_no != port_no)) { + dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, OFPQOFC_BAD_PORT, + oh, ntohs(ofq_request->header.length)); + goto error; + } + ofq_reply = make_openflow_reply(sizeof *ofq_reply, OFPT_QUEUE_GET_CONFIG_REPLY, + sender, &buffer); + ofq_reply->port = htons(port_no); + LIST_FOR_EACH(q, struct sw_queue, node, &p->queue_list) { + struct ofp_packet_queue * opq = ofpbuf_put_zeros(buffer, sizeof *opq); + fill_queue_desc(buffer, q, opq); + } + send_openflow_buffer(dp, buffer, sender); + } + else { + dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, OFPQOFC_BAD_PORT, + oh, ntohs(ofq_request->header.length)); + } + error: + return 0; +} + +static int +recv_vendor(struct datapath *dp, const struct sender *sender, + const void *oh) +{ + const struct ofp_vendor_header *ovh = oh; + + switch (ntohl(ovh->vendor)) + { + case PRIVATE_VENDOR_ID: + return private_recv_msg(dp, sender, oh); + + case OPENFLOW_VENDOR_ID: + return of_ext_recv_msg(dp, sender, oh); + + default: + VLOG_WARN_RL(&rl, "unknown vendor: 0x%x\n", ntohl(ovh->vendor)); + dp_send_error_msg(dp, sender, OFPET_BAD_REQUEST, + OFPBRC_BAD_VENDOR, oh, ntohs(ovh->header.length)); + return -EINVAL; + } +} + +/* 'msg', which is 'length' bytes long, was received from the control path. + * Apply it to 'chain'. */ +int +fwd_control_input(struct datapath *dp, const struct sender *sender, + const void *msg, size_t length) +{ + int (*handler)(struct datapath *, const struct sender *, const void *); + struct ofp_header *oh; + size_t min_size; + + /* Check encapsulated length. */ + oh = (struct ofp_header *) msg; + if (ntohs(oh->length) > length) { + return -EINVAL; + } + assert(oh->version == OFP_VERSION); + + /* Figure out how to handle it. */ + switch (oh->type) { + case OFPT_BARRIER_REQUEST: + min_size = sizeof(struct ofp_header); + handler = recv_barrier_request; + break; + case OFPT_FEATURES_REQUEST: + min_size = sizeof(struct ofp_header); + handler = recv_features_request; + break; + case OFPT_GET_CONFIG_REQUEST: + min_size = sizeof(struct ofp_header); + handler = recv_get_config_request; + break; + case OFPT_SET_CONFIG: + min_size = sizeof(struct ofp_switch_config); + handler = recv_set_config; + break; + case OFPT_PACKET_OUT: + min_size = sizeof(struct ofp_packet_out); + handler = recv_packet_out; + break; + case OFPT_FLOW_MOD: + min_size = sizeof(struct ofp_flow_mod); + handler = recv_flow; + break; + case OFPT_PORT_MOD: + min_size = sizeof(struct ofp_port_mod); + handler = recv_port_mod; + break; + case OFPT_STATS_REQUEST: + min_size = sizeof(struct ofp_stats_request); + handler = recv_stats_request; + break; + case OFPT_ECHO_REQUEST: + min_size = sizeof(struct ofp_header); + handler = recv_echo_request; + break; + case OFPT_ECHO_REPLY: + min_size = sizeof(struct ofp_header); + handler = recv_echo_reply; + break; + case OFPT_QUEUE_GET_CONFIG_REQUEST: + min_size = sizeof(struct ofp_header); + handler = recv_queue_get_config_request; + break; + case OFPT_VENDOR: + min_size = sizeof(struct ofp_vendor_header); + handler = recv_vendor; + break; + default: + dp_send_error_msg(dp, sender, OFPET_BAD_REQUEST, OFPBRC_BAD_TYPE, + msg, length); + return -EINVAL; + } + + /* Handle it. */ + if (length < min_size) + return -EFAULT; + return handler(dp, sender, msg); +} + +/* Packet buffering. */ + +#define OVERWRITE_SECS 1 + +struct packet_buffer { + struct ofpbuf *buffer; + uint32_t cookie; + time_t timeout; +}; + +static struct packet_buffer buffers[N_PKT_BUFFERS]; +static unsigned int buffer_idx; + +uint32_t save_buffer(struct ofpbuf *buffer) +{ + struct packet_buffer *p; + uint32_t id; + + buffer_idx = (buffer_idx + 1) & PKT_BUFFER_MASK; + p = &buffers[buffer_idx]; + if (p->buffer) { + /* Don't buffer packet if existing entry is less than + * OVERWRITE_SECS old. */ + if (time_now() < p->timeout) { /* FIXME */ + return (uint32_t)-1; + } else { + ofpbuf_delete(p->buffer); + } + } + /* Don't use maximum cookie value since the all-bits-1 id is + * special. */ + if (++p->cookie >= (1u << PKT_COOKIE_BITS) - 1) + p->cookie = 0; + p->buffer = ofpbuf_clone(buffer); /* FIXME */ + p->timeout = time_now() + OVERWRITE_SECS; /* FIXME */ + id = buffer_idx | (p->cookie << PKT_BUFFER_BITS); + + return id; +} + +static struct ofpbuf *retrieve_buffer(uint32_t id) +{ + struct ofpbuf *buffer = NULL; + struct packet_buffer *p; + + p = &buffers[id & PKT_BUFFER_MASK]; + if (p->cookie == id >> PKT_BUFFER_BITS) { + buffer = p->buffer; + p->buffer = NULL; + } else { + printf("cookie mismatch: %x != %x\n", + id >> PKT_BUFFER_BITS, p->cookie); + } + + return buffer; +} + +static void discard_buffer(uint32_t id) +{ + struct packet_buffer *p; + + p = &buffers[id & PKT_BUFFER_MASK]; + if (p->cookie == id >> PKT_BUFFER_BITS) { + ofpbuf_delete(p->buffer); + p->buffer = NULL; + } +} diff --git a/openflow/udatapath/datapath.h b/openflow/udatapath/datapath.h new file mode 100644 index 00000000..c79c5ead --- /dev/null +++ b/openflow/udatapath/datapath.h @@ -0,0 +1,167 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +/* Interface exported by OpenFlow module. */ + +#ifndef DATAPATH_H +#define DATAPATH_H 1 + +#include +#include +#include "openflow/nicira-ext.h" +#include "ofpbuf.h" +#include "timeval.h" +#include "list.h" +#include "netdev.h" + +/* FIXME: Can declare struct of_hw_driver instead */ +#if defined(OF_HW_PLAT) +#include +#endif + +struct rconn; +struct pvconn; +struct sw_flow; +struct sender; + +struct sw_queue { + struct list node; /* element in port.queues */ + unsigned long long int tx_packets; + unsigned long long int tx_bytes; + unsigned long long int tx_errors; + uint32_t queue_id; + uint16_t class_id; /* internal mapping from OF queue_id to tc class_id */ + struct sw_port *port; /* reference to the parent port */ + /* keep it simple for now, only one property (assuming min_rate) */ + uint16_t property; /* one from OFPQT_ */ + uint16_t min_rate; +}; + +#define MAX_HW_NAME_LEN 32 +enum sw_port_flags { + SWP_USED = 1 << 0, /* Is port being used */ + SWP_HW_DRV_PORT = 1 << 1, /* Port controlled by HW driver */ +}; +#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) +#define IS_HW_PORT(p) ((p)->flags & SWP_HW_DRV_PORT) +#else +#define IS_HW_PORT(p) 0 +#endif + +#define PORT_IN_USE(p) (((p) != NULL) && (p)->flags & SWP_USED) + +struct sw_port { + uint32_t config; /* Some subset of OFPPC_* flags. */ + uint32_t state; /* Some subset of OFPPS_* flags. */ + uint32_t flags; /* SWP_* flags above */ + struct datapath *dp; + struct netdev *netdev; + char hw_name[OFP_MAX_PORT_NAME_LEN]; + struct list node; /* Element in datapath.ports. */ + unsigned long long int rx_packets, tx_packets; + unsigned long long int rx_bytes, tx_bytes; + unsigned long long int tx_dropped; + uint16_t port_no; + /* port queues */ + uint16_t num_queues; + struct sw_queue queues[NETDEV_MAX_QUEUES]; + struct list queue_list; /* list of all queues for this port */ +}; + +#if defined(OF_HW_PLAT) +struct hw_pkt_q_entry { + struct ofpbuf *buffer; + struct hw_pkt_q_entry *next; + of_port_t port_no; + int reason; +}; +#endif + +#define DP_MAX_PORTS 255 +BUILD_ASSERT_DECL(DP_MAX_PORTS <= OFPP_MAX); + +struct datapath { + /* Remote connections. */ + struct list remotes; /* All connections (including controller). */ + + /* Listeners. */ + struct pvconn **listeners; + size_t n_listeners; + + time_t last_timeout; + + /* Unique identifier for this datapath */ + uint64_t id; + char dp_desc[DESC_STR_LEN]; /* human readible comment to ID this DP */ + + struct sw_chain *chain; /* Forwarding rules. */ + + /* Configuration set from controller. */ + uint16_t flags; + uint16_t miss_send_len; + + /* Switch ports. */ + struct sw_port ports[DP_MAX_PORTS]; + struct sw_port *local_port; /* OFPP_LOCAL port, if any. */ + struct list port_list; /* All ports, including local_port. */ + +#if defined(OF_HW_PLAT) + /* Although the chain maintains the pointer to the HW driver + * for flow operations, the datapath needs the port functions + * in the driver structure + */ + of_hw_driver_t *hw_drv; + struct hw_pkt_q_entry *hw_pkt_list_head, *hw_pkt_list_tail; +#endif +}; + +int dp_new(struct datapath **, uint64_t dpid); +int dp_add_port(struct datapath *, const char *netdev, uint16_t); +int dp_add_local_port(struct datapath *, const char *netdev, uint16_t); +void dp_add_pvconn(struct datapath *, struct pvconn *); +void dp_run(struct datapath *); +void dp_wait(struct datapath *); +void dp_send_error_msg(struct datapath *, const struct sender *, + uint16_t, uint16_t, const void *, size_t); +void dp_send_flow_end(struct datapath *, struct sw_flow *, + enum ofp_flow_removed_reason); +void dp_output_port(struct datapath *, struct ofpbuf *, int in_port, + int out_port, uint32_t queue_id, bool ignore_no_fwd); +void dp_output_control(struct datapath *, struct ofpbuf *, int in_port, + size_t max_len, int reason); +struct sw_port * dp_lookup_port(struct datapath *, uint16_t); +struct sw_queue * dp_lookup_queue(struct sw_port *, uint32_t); + +int udatapath_cmd(int argc, char *argv[]); + +#endif /* datapath.h */ diff --git a/openflow/udatapath/dp_act.c b/openflow/udatapath/dp_act.c new file mode 100644 index 00000000..d48beb10 --- /dev/null +++ b/openflow/udatapath/dp_act.c @@ -0,0 +1,531 @@ +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +/* Functions for executing OpenFlow actions. */ + +#include +#include "csum.h" +#include "packets.h" +#include "dp_act.h" +#include "openflow/nicira-ext.h" + +static uint16_t +validate_output(struct datapath *dp UNUSED, const struct sw_flow_key *key, + const struct ofp_action_header *ah) +{ + struct ofp_action_output *oa = (struct ofp_action_output *)ah; + + /* To prevent loops, make sure there's no action to send to the + * OFP_TABLE virtual port. + */ + if (oa->port == htons(OFPP_NONE) || + (!(key->wildcards & OFPFW_IN_PORT) + && oa->port == key->flow.in_port)) { + return OFPBAC_BAD_OUT_PORT; + } + return ACT_VALIDATION_OK; +} + +static uint16_t +validate_queue(struct datapath *dp UNUSED, const struct sw_flow_key *key UNUSED, + const struct ofp_action_header *ah) +{ + struct ofp_action_enqueue *ea = (struct ofp_action_enqueue *)ah; + + /* Only physical ports may have queues. */ + if (ntohs(ea->port) > OFPP_MAX && ntohs(ea->port) != OFPP_IN_PORT) { + return OFPBAC_BAD_OUT_PORT; + } + return ACT_VALIDATION_OK; +} + +static void +do_output(struct datapath *dp, struct ofpbuf *buffer, int in_port, + size_t max_len, int out_port, uint32_t queue_id, + bool ignore_no_fwd) +{ + if (out_port != OFPP_CONTROLLER) { + dp_output_port(dp, buffer, in_port, out_port, queue_id, ignore_no_fwd); + } else { + dp_output_control(dp, buffer, in_port, max_len, OFPR_ACTION); + } +} + +/* Modify vlan tag control information (TCI). Only sets the TCI bits + * indicated by 'mask'. If no vlan tag is present, one is added. + */ +static void +modify_vlan_tci(struct ofpbuf *buffer, struct sw_flow_key *key, + uint16_t tci, uint16_t mask) +{ + struct vlan_eth_header *veh; + + if (key->flow.dl_vlan != htons(OFP_VLAN_NONE)) { + /* Modify vlan id, but maintain other TCI values */ + veh = buffer->l2; + veh->veth_tci &= ~htons(mask); + veh->veth_tci |= htons(tci); + } else { + /* Insert new vlan id. */ + struct eth_header *eh = buffer->l2; + struct vlan_eth_header tmp; + memcpy(tmp.veth_dst, eh->eth_dst, ETH_ADDR_LEN); + memcpy(tmp.veth_src, eh->eth_src, ETH_ADDR_LEN); + tmp.veth_type = htons(ETH_TYPE_VLAN); + tmp.veth_tci = htons(tci); + tmp.veth_next_type = eh->eth_type; + + veh = ofpbuf_push_uninit(buffer, VLAN_HEADER_LEN); + memcpy(veh, &tmp, sizeof tmp); + buffer->l2 = (char*)buffer->l2 - VLAN_HEADER_LEN; + } + + key->flow.dl_vlan = veh->veth_tci & htons(VLAN_VID_MASK); + key->flow.dl_vlan_pcp = (uint8_t)((ntohs(veh->veth_tci) >> VLAN_PCP_SHIFT) + & VLAN_PCP_BITMASK); +} + + +/* Remove an existing vlan header if it exists. */ +static void +vlan_pull_tag(struct ofpbuf *buffer) +{ + struct vlan_eth_header *veh = buffer->l2; + + if (veh->veth_type == htons(ETH_TYPE_VLAN)) { + struct eth_header tmp; + + memcpy(tmp.eth_dst, veh->veth_dst, ETH_ADDR_LEN); + memcpy(tmp.eth_src, veh->veth_src, ETH_ADDR_LEN); + tmp.eth_type = veh->veth_next_type; + + buffer->size -= VLAN_HEADER_LEN; + buffer->data = (char*)buffer->data + VLAN_HEADER_LEN; + buffer->l2 = (char*)buffer->l2 + VLAN_HEADER_LEN; + memcpy(buffer->data, &tmp, sizeof tmp); + } +} + +static void +set_vlan_vid(struct ofpbuf *buffer, struct sw_flow_key *key, + const struct ofp_action_header *ah) +{ + struct ofp_action_vlan_vid *va = (struct ofp_action_vlan_vid *)ah; + uint16_t tci = ntohs(va->vlan_vid); + + modify_vlan_tci(buffer, key, tci, VLAN_VID_MASK); +} + +static void +set_vlan_pcp(struct ofpbuf *buffer, struct sw_flow_key *key, + const struct ofp_action_header *ah) +{ + struct ofp_action_vlan_pcp *va = (struct ofp_action_vlan_pcp *)ah; + uint16_t tci = (uint16_t)va->vlan_pcp << 13; + + modify_vlan_tci(buffer, key, tci, VLAN_PCP_MASK); +} + +static void +strip_vlan(struct ofpbuf *buffer, struct sw_flow_key *key, + const struct ofp_action_header *ah UNUSED) +{ + vlan_pull_tag(buffer); + key->flow.dl_vlan = htons(OFP_VLAN_NONE); +} + +static void +set_dl_addr(struct ofpbuf *buffer, struct sw_flow_key *key UNUSED, + const struct ofp_action_header *ah) +{ + struct ofp_action_dl_addr *da = (struct ofp_action_dl_addr *)ah; + struct eth_header *eh = buffer->l2; + + if (da->type == htons(OFPAT_SET_DL_SRC)) { + memcpy(eh->eth_src, da->dl_addr, sizeof eh->eth_src); + } else { + memcpy(eh->eth_dst, da->dl_addr, sizeof eh->eth_dst); + } +} + +static void +set_nw_addr(struct ofpbuf *buffer, struct sw_flow_key *key, + const struct ofp_action_header *ah) +{ + struct ofp_action_nw_addr *na = (struct ofp_action_nw_addr *)ah; + uint16_t eth_proto = ntohs(key->flow.dl_type); + + if (eth_proto == ETH_TYPE_IP) { + struct ip_header *nh = buffer->l3; + uint8_t nw_proto = key->flow.nw_proto; + uint32_t new, *field; + + new = na->nw_addr; + field = na->type == htons(OFPAT_SET_NW_SRC) ? &nh->ip_src : &nh->ip_dst; + if (nw_proto == IP_TYPE_TCP) { + struct tcp_header *th = buffer->l4; + th->tcp_csum = recalc_csum32(th->tcp_csum, *field, new); + } else if (nw_proto == IP_TYPE_UDP) { + struct udp_header *th = buffer->l4; + if (th->udp_csum) { + th->udp_csum = recalc_csum32(th->udp_csum, *field, new); + if (!th->udp_csum) { + th->udp_csum = 0xffff; + } + } + } + nh->ip_csum = recalc_csum32(nh->ip_csum, *field, new); + *field = new; + } +} + +static void +set_nw_tos(struct ofpbuf *buffer, struct sw_flow_key *key, + const struct ofp_action_header *ah) +{ + struct ofp_action_nw_tos *nt = (struct ofp_action_nw_tos *)ah; + uint16_t eth_proto = ntohs(key->flow.dl_type); + + if (eth_proto == ETH_TYPE_IP) { + struct ip_header *nh = buffer->l3; + uint8_t new, *field; + + /* JeanII : Set only 6 bits, don't clobber ECN */ + new = (nt->nw_tos & 0xFC) | (nh->ip_tos & 0x03); + + /* Get address of field */ + field = &nh->ip_tos; + + /* jklee : ip tos field is not included in TCP pseudo header. + * Need magic as update_csum() don't work with 8 bits. */ + nh->ip_csum = recalc_csum32(nh->ip_csum, htons((uint16_t)*field), + htons((uint16_t)new)); + + /* Change the IP ToS bits */ + *field = new; + } +} + +static void +set_tp_port(struct ofpbuf *buffer, struct sw_flow_key *key, + const struct ofp_action_header *ah) +{ + struct ofp_action_tp_port *ta = (struct ofp_action_tp_port *)ah; + uint16_t eth_proto = ntohs(key->flow.dl_type); + + if (eth_proto == ETH_TYPE_IP) { + uint8_t nw_proto = key->flow.nw_proto; + uint16_t new, *field; + + new = ta->tp_port; + if (nw_proto == IP_TYPE_TCP) { + struct tcp_header *th = buffer->l4; + field = ta->type == htons(OFPAT_SET_TP_SRC) ? &th->tcp_src : &th->tcp_dst; + th->tcp_csum = recalc_csum16(th->tcp_csum, *field, new); + *field = new; + } else if (nw_proto == IP_TYPE_UDP) { + struct udp_header *th = buffer->l4; + field = ta->type == htons(OFPAT_SET_TP_SRC) ? &th->udp_src : &th->udp_dst; + th->udp_csum = recalc_csum16(th->udp_csum, *field, new); + *field = new; + } + } +} + +struct openflow_action { + size_t min_size; + size_t max_size; + uint16_t (*validate)(struct datapath *dp, + const struct sw_flow_key *key, + const struct ofp_action_header *ah); + void (*execute)(struct ofpbuf *buffer, + struct sw_flow_key *key, + const struct ofp_action_header *ah); +}; + +static const struct openflow_action of_actions[] = { + [OFPAT_OUTPUT] = { + sizeof(struct ofp_action_output), + sizeof(struct ofp_action_output), + validate_output, + NULL /* This is optimized into execute_actions */ + }, + [OFPAT_ENQUEUE] = { + sizeof(struct ofp_action_enqueue), + sizeof(struct ofp_action_enqueue), + validate_queue, + NULL /* This is optimized into execute_actions */ + }, + [OFPAT_SET_VLAN_VID] = { + sizeof(struct ofp_action_vlan_vid), + sizeof(struct ofp_action_vlan_vid), + NULL, + set_vlan_vid + }, + [OFPAT_SET_VLAN_PCP] = { + sizeof(struct ofp_action_vlan_pcp), + sizeof(struct ofp_action_vlan_pcp), + NULL, + set_vlan_pcp + }, + [OFPAT_STRIP_VLAN] = { + sizeof(struct ofp_action_header), + sizeof(struct ofp_action_header), + NULL, + strip_vlan + }, + [OFPAT_SET_DL_SRC] = { + sizeof(struct ofp_action_dl_addr), + sizeof(struct ofp_action_dl_addr), + NULL, + set_dl_addr + }, + [OFPAT_SET_DL_DST] = { + sizeof(struct ofp_action_dl_addr), + sizeof(struct ofp_action_dl_addr), + NULL, + set_dl_addr + }, + [OFPAT_SET_NW_SRC] = { + sizeof(struct ofp_action_nw_addr), + sizeof(struct ofp_action_nw_addr), + NULL, + set_nw_addr + }, + [OFPAT_SET_NW_DST] = { + sizeof(struct ofp_action_nw_addr), + sizeof(struct ofp_action_nw_addr), + NULL, + set_nw_addr + }, + [OFPAT_SET_NW_TOS] = { + sizeof(struct ofp_action_nw_tos), + sizeof(struct ofp_action_nw_tos), + NULL, + set_nw_tos + }, + [OFPAT_SET_TP_SRC] = { + sizeof(struct ofp_action_tp_port), + sizeof(struct ofp_action_tp_port), + NULL, + set_tp_port + }, + [OFPAT_SET_TP_DST] = { + sizeof(struct ofp_action_tp_port), + sizeof(struct ofp_action_tp_port), + NULL, + set_tp_port + } + /* OFPAT_VENDOR is not here, since it would blow up the array size. */ +}; + +/* Validate built-in OpenFlow actions. Either returns ACT_VALIDATION_OK + * or an OFPET_BAD_ACTION error code. */ +static uint16_t +validate_ofpat(struct datapath *dp, const struct sw_flow_key *key, + const struct ofp_action_header *ah, uint16_t type, uint16_t len) +{ + uint16_t ret = ACT_VALIDATION_OK; + const struct openflow_action *act = &of_actions[type]; + + if ((len < act->min_size) || (len > act->max_size)) { + return OFPBAC_BAD_LEN; + } + + if (act->validate) { + ret = act->validate(dp, key, ah); + } + + return ret; +} + +/* Validate vendor-defined actions. Either returns ACT_VALIDATION_OK + * or an OFPET_BAD_ACTION error code. */ +static uint16_t +validate_vendor(struct datapath *dp UNUSED, const struct sw_flow_key *key UNUSED, + const struct ofp_action_header *ah, uint16_t len) +{ + struct ofp_action_vendor_header *avh; + int ret = ACT_VALIDATION_OK; + + if (len < sizeof(struct ofp_action_vendor_header)) { + return OFPBAC_BAD_LEN; + } + + avh = (struct ofp_action_vendor_header *)ah; + + switch(ntohl(avh->vendor)) { + default: + return OFPBAC_BAD_VENDOR; + } + + return ret; +} + +/* Validates a list of actions. If a problem is found, a code for the + * OFPET_BAD_ACTION error type is returned. If the action list validates, + * ACT_VALIDATION_OK is returned. */ +uint16_t +validate_actions(struct datapath *dp, const struct sw_flow_key *key, + const struct ofp_action_header *actions, size_t actions_len) +{ + uint8_t *p = (uint8_t *)actions; + int err; + + while (actions_len >= sizeof(struct ofp_action_header)) { + struct ofp_action_header *ah = (struct ofp_action_header *)p; + size_t len = ntohs(ah->len); + uint16_t type; + + /* Make there's enough remaining data for the specified length + * and that the action length is a multiple of 64 bits. */ + if ((actions_len < len) || (len % 8) != 0) { + return OFPBAC_BAD_LEN; + } + + type = ntohs(ah->type); + if (type < ARRAY_SIZE(of_actions)) { + err = validate_ofpat(dp, key, ah, type, len); + if (err != ACT_VALIDATION_OK) { + return err; + } + } else if (type == OFPAT_VENDOR) { + err = validate_vendor(dp, key, ah, len); + if (err != ACT_VALIDATION_OK) { + return err; + } + } else { + return OFPBAC_BAD_TYPE; + } + + p += len; + actions_len -= len; + } + + /* Check if there's any trailing garbage. */ + if (actions_len != 0) { + return OFPBAC_BAD_LEN; + } + + return ACT_VALIDATION_OK; +} + +/* Execute a built-in OpenFlow action against 'buffer'. */ +static void +execute_ofpat(struct ofpbuf *buffer, struct sw_flow_key *key, + const struct ofp_action_header *ah, uint16_t type) +{ + const struct openflow_action *act = &of_actions[type]; + + if (act->execute) { + act->execute(buffer, key, ah); + } +} + +/* Execute a vendor-defined action against 'buffer'. */ +static void +execute_vendor(struct ofpbuf *buffer UNUSED, const struct sw_flow_key *key UNUSED, + const struct ofp_action_header *ah) +{ + struct ofp_action_vendor_header *avh + = (struct ofp_action_vendor_header *)ah; + + switch(ntohl(avh->vendor)) { + default: + /* This should not be possible due to prior validation. */ + printf("attempt to execute action with unknown vendor: %#x\n", + ntohl(avh->vendor)); + break; + } +} + +/* Execute a list of actions against 'buffer'. */ +void execute_actions(struct datapath *dp, struct ofpbuf *buffer, + struct sw_flow_key *key, + const struct ofp_action_header *actions, size_t actions_len, + int ignore_no_fwd) +{ + /* Every output action needs a separate clone of 'buffer', but the common + * case is just a single output action, so that doing a clone and then + * freeing the original buffer is wasteful. So the following code is + * slightly obscure just to avoid that. */ + int prev_port; + uint32_t prev_queue; + size_t max_len = UINT16_MAX; + uint16_t in_port = ntohs(key->flow.in_port); + uint8_t *p = (uint8_t *)actions; + + prev_port = -1; + prev_queue = 0; + + /* The action list was already validated, so we can be a bit looser + * in our sanity-checking. */ + while (actions_len > 0) { + struct ofp_action_header *ah = (struct ofp_action_header *)p; + size_t len = htons(ah->len); + + if (prev_port != -1) { + do_output(dp, ofpbuf_clone(buffer), in_port, max_len, + prev_port, prev_queue, ignore_no_fwd); + prev_port = -1; + } + + if (ah->type == htons(OFPAT_OUTPUT)) { + struct ofp_action_output *oa = (struct ofp_action_output *)p; + prev_port = ntohs(oa->port); + prev_queue = 0; /* using the default best-effort queue */ + max_len = ntohs(oa->max_len); + } else if (ah->type == htons(OFPAT_ENQUEUE)) { + struct ofp_action_enqueue *ea = (struct ofp_action_enqueue *)p; + prev_port = ntohs(ea->port); + prev_queue = ntohl(ea->queue_id); + max_len = 0; /* we will not send to the controller anyways - useless */ + } else { + uint16_t type = ntohs(ah->type); + + if (type < ARRAY_SIZE(of_actions)) { + execute_ofpat(buffer, key, ah, type); + } else if (type == OFPAT_VENDOR) { + execute_vendor(buffer, key, ah); + } + } + + p += len; + actions_len -= len; + } + if (prev_port != -1) { + do_output(dp, buffer, in_port, max_len, prev_port, prev_queue, ignore_no_fwd); + } else { + ofpbuf_delete(buffer); + } +} diff --git a/openflow/udatapath/dp_act.h b/openflow/udatapath/dp_act.h new file mode 100644 index 00000000..e0181fad --- /dev/null +++ b/openflow/udatapath/dp_act.h @@ -0,0 +1,49 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#ifndef DP_ACT_H +#define DP_ACT_H 1 + +#include "openflow/openflow.h" +#include "switch-flow.h" +#include "datapath.h" + +#define ACT_VALIDATION_OK ((uint16_t)-1) + +uint16_t validate_actions(struct datapath *, const struct sw_flow_key *, + const struct ofp_action_header *, size_t); +void execute_actions(struct datapath *, struct ofpbuf *, + struct sw_flow_key *, const struct ofp_action_header *, + size_t action_len, int ignore_no_fwd); + +#endif /* dp_act.h */ diff --git a/openflow/udatapath/of_ext_msg.c b/openflow/udatapath/of_ext_msg.c new file mode 100644 index 00000000..36d587be --- /dev/null +++ b/openflow/udatapath/of_ext_msg.c @@ -0,0 +1,267 @@ +/* Copyright (c) 2009 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include +#include "openflow/openflow-ext.h" +#include "of_ext_msg.h" +#include "netdev.h" +#include "datapath.h" + +#define THIS_MODULE VLM_experimental +#include "vlog.h" + +static int +new_queue(struct sw_port * port, struct sw_queue * queue, + uint32_t queue_id, uint16_t class_id, + struct ofp_queue_prop_min_rate * mr) +{ + memset(queue, '\0', sizeof *queue); + queue->port = port; + queue->queue_id = queue_id; + /* class_id is the internal mapping to class. It is the offset + * in the array of queues for each port. Note that class_id is + * local to port, so we don't have any conflict. + * tc uses 16-bit class_id, so we cannot use the queue_id + * field */ + queue->class_id = class_id; + queue->property = ntohs(mr->prop_header.property); + queue->min_rate = ntohs(mr->rate); + + list_push_back(&port->queue_list, &queue->node); + + return 0; +} + +static int +port_add_queue(struct sw_port *p, uint32_t queue_id, + struct ofp_queue_prop_min_rate * mr) +{ + int queue_no; + for (queue_no = 1; queue_no < p->num_queues; queue_no++) { + struct sw_queue *q = &p->queues[queue_no]; + if (!q->port) { + return new_queue(p,q,queue_id,queue_no,mr); + } + } + return EXFULL; +} + +static int +port_delete_queue(struct sw_port *p UNUSED, struct sw_queue *q) +{ + list_remove(&q->node); + memset(q,'\0', sizeof *q); + return 0; +} + +static void +recv_of_exp_queue_delete(struct datapath *dp, + const struct sender *sender, + const void *oh) +{ + struct sw_port *p; + struct sw_queue *q; + struct openflow_queue_command_header * ofq_delete; + struct ofp_packet_queue *opq; + + uint16_t port_no; + uint32_t queue_id; + + ofq_delete = (struct openflow_queue_command_header *)oh; + opq = (struct ofp_packet_queue *)ofq_delete->body; + port_no = ntohs(ofq_delete->port); + queue_id = ntohl(opq->queue_id); + + p = dp_lookup_port(dp,port_no); + if (p->netdev) { + q = dp_lookup_queue(p,queue_id); + if (q) { + netdev_delete_class(p->netdev,q->class_id); + port_delete_queue(p,q); + } + else { + dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, + OFPQOFC_BAD_PORT, oh, + ntohs(ofq_delete->header.header.length)); + } + } + else { + dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, + OFPQOFC_BAD_PORT, oh, + ntohs(ofq_delete->header.header.length)); + } +} + +/** Modifies/adds a queue. It first searches if a queue with + * id exists for this port. If yes it modifies it, otherwise adds + * a new configuration. + * + * @param dp the related datapath + * @param sender request source + * @param oh the openflow message for queue mod. + */ +static void +recv_of_exp_queue_modify(struct datapath *dp, + const struct sender *sender UNUSED, + const void *oh) +{ + struct sw_port *p; + struct sw_queue *q; + struct openflow_queue_command_header * ofq_modify; + struct ofp_packet_queue *opq; + struct ofp_queue_prop_min_rate *mr; + + int error = 0; + uint16_t port_no; + uint32_t queue_id; + + + ofq_modify = (struct openflow_queue_command_header *)oh; + opq = (struct ofp_packet_queue *)ofq_modify->body; + mr = (struct ofp_queue_prop_min_rate*)opq->properties; + + /* Currently, we only accept queues with a single, min-rate property */ + if ((ntohs(opq->len) != 24) || + ntohs(mr->prop_header.property) != OFPQT_MIN_RATE) { + VLOG_ERR("Unknown queue configuration"); + dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, + OFQ_ERR_DISCIPLINE, oh, + ntohs(ofq_modify->header.header.length)); + return; + } + + + + port_no = ntohs(ofq_modify->port); + queue_id = ntohl(opq->queue_id); + + p = dp_lookup_port(dp, port_no); + if (PORT_IN_USE(p)) { + q = dp_lookup_queue(p, queue_id); + if (q) { + /* queue exists - modify it */ + error = netdev_change_class(p->netdev,q->class_id, ntohs(mr->rate)); + if (error) { + VLOG_ERR("Failed to update queue %d", queue_id); + dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, + OFPQOFC_EPERM, oh, + ntohs(ofq_modify->header.header.length)); + } + else { + q->property = ntohs(mr->prop_header.property); + q->min_rate = ntohs(mr->rate); + } + } + else { + /* create new queue */ + error = port_add_queue(p,queue_id, mr); + if (error == EXFULL) { + dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, + OFPQOFC_EPERM, oh, + ntohs(ofq_modify->header.header.length)); + return; + } + q = dp_lookup_queue(p, queue_id); + error = netdev_setup_class(p->netdev,q->class_id, ntohs(mr->rate)); + if (error) { + VLOG_ERR("Failed to configure queue %d", queue_id); + dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, + OFPQOFC_BAD_QUEUE, oh, + ntohs(ofq_modify->header.header.length)); + } + } + } + else { + dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, OFPQOFC_BAD_PORT, + oh, ntohs(ofq_modify->header.header.length)); + VLOG_ERR("Failed to create/modify queue - port %d doesn't exist", + port_no); + } + if (!error) { + if (IS_HW_PORT(p)) { +#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) + error = dp->hw_drv->port_queue_config(dp->hw_drv, port_no, + queue_id, ntohs(mr->rate)); + if (error < 0) { + VLOG_ERR("Failed to update HW port %d queue %d", + port_no, queue_id); + } +#endif + } + } +} +/** + * Parses a set dp_desc message and uses it to set + * the dp_desc string in dp + */ +static void +recv_of_set_dp_desc(struct datapath *dp, + const struct sender *sender UNUSED, + const struct ofp_extension_header * exth) +{ + struct openflow_ext_set_dp_desc * set_dp_desc = (struct openflow_ext_set_dp_desc * ) + exth; + strncpy(dp->dp_desc, set_dp_desc->dp_desc, DESC_STR_LEN); + dp->dp_desc[DESC_STR_LEN-1] = 0; // force null for safety +} + +/** + * Receives an experimental message and pass it + * to the appropriate handler + */ +int of_ext_recv_msg(struct datapath *dp, const struct sender *sender, + const void *oh) +{ + const struct ofp_extension_header *ofexth = oh; + + switch (ntohl(ofexth->subtype)) { + case OFP_EXT_QUEUE_MODIFY: { + recv_of_exp_queue_modify(dp,sender,oh); + return 0; + } + case OFP_EXT_QUEUE_DELETE: { + recv_of_exp_queue_delete(dp,sender,oh); + return 0; + } + case OFP_EXT_SET_DESC: + recv_of_set_dp_desc(dp,sender,ofexth); + return 0; + default: + VLOG_ERR("Received unknown command of type %d", + ntohl(ofexth->subtype)); + return -EINVAL; + } + + return -EINVAL; +} diff --git a/openflow/udatapath/of_ext_msg.h b/openflow/udatapath/of_ext_msg.h new file mode 100644 index 00000000..510615d7 --- /dev/null +++ b/openflow/udatapath/of_ext_msg.h @@ -0,0 +1,43 @@ +/* Copyright (c) 2009 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#ifndef OF_EXT_MSG_H +#define OF_EXT_MSG_H 1 + +#include "datapath.h" + +struct sender; + +int of_ext_recv_msg(struct datapath *, const struct sender *, const void *); + +#endif /* of_ext_msg.h */ diff --git a/openflow/udatapath/ofdatapath.8.in b/openflow/udatapath/ofdatapath.8.in new file mode 100644 index 00000000..55d6b4ba --- /dev/null +++ b/openflow/udatapath/ofdatapath.8.in @@ -0,0 +1,148 @@ +.ds PN ofdatapath + +.TH ofdatapath 8 "May 2008" "OpenFlow" "OpenFlow Manual" + +.SH NAME +ofdatapath \- userspace implementation of datapath for OpenFlow switch + +.SH SYNOPSIS +.B ofdatapath +[\fIoptions\fR] +\fB-i\fR \fInetdev\fR[\fB,\fInetdev\fR].\|.\|. +\fImethod\fR [\fImethod\fR].\|.\|. + +.SH DESCRIPTION +The \fBofdatapath\fR is a userspace implementation of an OpenFlow +datapath. It monitors one or more network device interfaces, +forwarding packets between them according to the entries in the flow +table that it maintains. When it is used with \fBofprotocol\fR(8), to +connect the datapath to an OpenFlow controller, the combination is an +OpenFlow switch. + +For access to network devices, the ofdatapath program must normally run as +root. + +The mandatory \fImethod\fR argument specifies how \fBofprotocol\fR(8) +communicates with \fBofdatapath\fR, as a passive OpenFlow connection +method. Ordinarily \fImethod\fR takes the following form: + +.TP +\fBpunix:\fIfile\fR +Listens for connections on the Unix domain server socket named +\fIfile\fR. + +.PP +The following connection methods are also supported, but their use +would be unusual because \fBofdatapath\fR and \fBofprotocol\fR should run +on the same machine: + +.TP +\fBpssl:\fR[\fIport\fR] +Listens for SSL connections \fIport\fR (default: 976). The +\fB--private-key\fR, \fB--certificate\fR, and \fB--ca-cert\fR options +are mandatory when this form is used. (\fBofp\-pki\fR(8) does not set +up a suitable PKI for use with this option.) + +.TP +\fBptcp:\fR[\fIport\fR] +Listens for TCP connections from remote OpenFlow switches on +\fIport\fR (default: 975). + +.SH OPTIONS +.TP +\fB-i\fR, \fB--interfaces=\fR\fInetdev\fR[\fB,\fInetdev\fR].\|.\|. +Specifies each \fInetdev\fR (e.g., \fBeth0\fR) as a switch port. The +specified network devices should not have any configured IP addresses. +This option may be given any number of times to specify additional +network devices. + +.TP +\fB-L\fR, \fB--local-port=\fInetdev\fR +Specifies the network device to use as the userspace datapath's +``local port,'' which is a network device that \fBofprotocol\fR(8) +bridges to the physical switch ports for use in in-band control. When +this option is not specified, the default is \fBtap:\fR, which causes +a new TAP virtual network device to be allocated with a default name +assigned by the kernel. To do the same, but assign a specific name +\fBname\fR to the TAP network device, specify the option as +\fB--local-port=tap:\fIname\fR. + +Either way, the existence of TAP devices created by \fBofdatapath\fR is +temporary: they are destroyed when \fBofdatapath\fR exits. If this is +undesirable, you may use \fBtunctl\fR(8) to create a persistent TAP +network device and then pass it to \fBofdatapath\fR, like so: + +.RS +.IP 1. +Create a persistent TAP network device: \fBtunctl -t mytap\fR. (The +\fBtunctl\fR(8) utility is part of User Mode Linux. It is not +included with the OpenFlow reference implementation.) +.IP 2. +Invoke \fBofdatapath\fR(8) using \fBmytap\fR, e.g. \fBofdatapath +--local-port=mytap\fR .\|.\|. (Note the lack of \fBtap:\fR prefix on +the \fB--local-port\fR argument.) +.IP 3. +Invoke \fBofprotocol\fR(8), etc., and use the switch as desired. +.IP 4. +When \fBofprotocol\fR and \fBofdatapath\fR have terminated and the TAP +network device is no longer needed, you may destroy it with: \fBtunctl +-d mytap\fR +.RE + +.IP +It does not ordinarily make sense to specify the name of a physical +network device on \fB-L\fR or \fB--local-port\fR. + +.TP +\fB--no-local-port\fR +Do not provide a local port as part of the datapath. When this option +is used, the switch will not support in-band control. + +.TP +\fB--no-slicing\fR +Disable slicing (no queue configuration to ports). When this option +is used, the switch will have 0 queues, and therefore no +slicing-related functionality is supported. This option is useful when +run-time dependencies for slicing (tc and related kernel +configuration) are not met. + +.TP +\fB-d\fR, \fB--datapath-id=\fIdpid\fR +Specifies the OpenFlow datapath ID (a 48-bit number that uniquely +identifies a controller) as \fIdpid\fR, which consists of exactly 12 +hex digits. Without this option, \fBofdatapath\fR picks an ID randomly. + +.TP +\fB-p\fR, \fB--private-key=\fIprivkey.pem\fR +Specifies a PEM file containing the private key used as the datapath's +identity for SSL connections to \fBofprotocol\fR(8). + +.TP +\fB-c\fR, \fB--certificate=\fIcert.pem\fR +Specifies a PEM file containing a certificate, signed by the +datapath's certificate authority (CA), that certifies the datapath's +private key to identify a trustworthy datapath. + +.TP +\fB-C\fR, \fB--ca-cert=\fIcacert.pem\fR +Specifies a PEM file containing the CA certificate used to verify that +the datapath is connected to a trustworthy secure channel. + +.so lib/daemon.man +.so lib/vlog.man +.so lib/common.man + +.SH BUGS +The userspace datapath's performance lags significantly behind that of +the kernel-based switch. It should only be used when the kernel-based +switch cannot be. + +On Linux, general-purpose support for VLAN tag rewriting is precluded +by the Linux kernel AF_PACKET implementation. + +.SH "SEE ALSO" + +.BR ofprotocol (8), +.BR dpctl (8), +.BR controller (8), +.BR vlogconf (8). diff --git a/openflow/udatapath/private-msg.c b/openflow/udatapath/private-msg.c new file mode 100644 index 00000000..7e868671 --- /dev/null +++ b/openflow/udatapath/private-msg.c @@ -0,0 +1,140 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#include +#include + +#include "openflow/private-ext.h" + +#include "chain.h" +#include "datapath.h" +#include "switch-flow.h" +#include "table.h" +#include "private-msg.h" + +struct emerg_flow_context { + struct datapath *dp; +}; + +static void flush_working(struct datapath *); +static int protection_callback(struct sw_flow *, void *); +static void do_protection(struct datapath *); + +static void +flush_working(struct datapath *dp) +{ + struct sw_flow_key key; + int num_deleted = 0; + + memset(&key, 0, sizeof(key)); + key.wildcards = OFPFW_ALL; + num_deleted = chain_delete(dp->chain, &key, OFPP_NONE, 0, 0, 0); +} + +static int +protection_callback(struct sw_flow *flow, void *private_) +{ + struct emerg_flow_context *private + = (struct emerg_flow_context *)private_; + struct sw_flow_actions *actions = flow->sf_acts; + struct ofp_match match; + struct sw_flow *tgtflow = NULL; + int error = 0; + + tgtflow = flow_alloc(flow->sf_acts->actions_len); + if (tgtflow == NULL) + return -ENOBUFS; + + /* Dup w/o idle and hard timeout. */ + memset(&match, 0, sizeof(match)); + flow_fill_match(&match, &flow->key.flow, flow->key.wildcards); + flow_extract_match(&tgtflow->key, &match); + /* Fill out flow. */ + tgtflow->priority = flow->priority; + tgtflow->idle_timeout = OFP_FLOW_PERMANENT; + tgtflow->hard_timeout = OFP_FLOW_PERMANENT; + tgtflow->send_flow_rem = flow->send_flow_rem; + tgtflow->emerg_flow = 0; + flow_setup_actions(tgtflow, actions->actions, actions->actions_len); + + error = chain_insert(private->dp->chain, tgtflow, 0); + if (error) + flow_free(tgtflow); + + return error; +} + +static void +do_protection(struct datapath *dp) +{ + struct emerg_flow_context private; + struct sw_flow_key key; + struct sw_table_position position; + struct sw_table *table = dp->chain->emerg_table; + int error = 0; + + memset(&private, 0, sizeof(private)); + private.dp = dp; + memset(&key, 0, sizeof(key)); + key.wildcards = OFPFW_ALL; + memset(&position, 0, sizeof(position)); + + error = table->iterate(table, &key, OFPP_NONE, + &position, protection_callback, &private); +} + +int +private_recv_msg(struct datapath *dp, const struct sender *sender UNUSED, + const void *ofph) +{ + struct private_vxhdr *vxhdr = (struct private_vxhdr *)ofph; + struct private_vxopt *vxopt = (struct private_vxopt *)(vxhdr + 1); + int error = 0; + + switch (ntohs(vxopt->pvo_type)) { + case PRIVATEOPT_PROTOCOL_STATS_REQUEST: + case PRIVATEOPT_PROTOCOL_STATS_REPLY: + break; + case PRIVATEOPT_EMERG_FLOW_PROTECTION: + flush_working(dp); + do_protection(dp); + break; + case PRIVATEOPT_EMERG_FLOW_RESTORATION: + /* Nothing to do because we assume that a re-connected + * controller will do flush current working flow table. */ + break; + default: + error = -EINVAL; + } + + return error; +} diff --git a/openflow/udatapath/private-msg.h b/openflow/udatapath/private-msg.h new file mode 100644 index 00000000..082a4531 --- /dev/null +++ b/openflow/udatapath/private-msg.h @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#ifndef PRIVATE_MSG_H_ +#define PRIVATE_MSG_H_ + +#include "datapath.h" + +struct sender; + +int private_recv_msg(struct datapath *, const struct sender *, const void *); + +#endif diff --git a/openflow/udatapath/switch-flow.c b/openflow/udatapath/switch-flow.c new file mode 100644 index 00000000..4ba9b406 --- /dev/null +++ b/openflow/udatapath/switch-flow.c @@ -0,0 +1,341 @@ +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include "switch-flow.h" +#include +#include +#include +#include +#include "ofpbuf.h" +#include "openflow/openflow.h" +#include "openflow/nicira-ext.h" +#include "packets.h" +#include "timeval.h" + +#define THIS_MODULE VLM_chain +#include "vlog.h" + +/* Internal function used to compare fields in flow. */ +static inline int +flow_fields_match(const struct flow *a, const struct flow *b, uint32_t w, + uint32_t src_mask, uint32_t dst_mask) +{ + return ((w & OFPFW_IN_PORT || a->in_port == b->in_port) + && (w & OFPFW_DL_VLAN || a->dl_vlan == b->dl_vlan) + && (w & OFPFW_DL_VLAN_PCP || a->dl_vlan_pcp == b->dl_vlan_pcp) + && (w & OFPFW_DL_SRC || eth_addr_equals(a->dl_src, b->dl_src)) + && (w & OFPFW_DL_DST || eth_addr_equals(a->dl_dst, b->dl_dst)) + && (w & OFPFW_DL_TYPE || a->dl_type == b->dl_type) + && (w & OFPFW_NW_TOS || a->nw_tos == b->nw_tos) + && (w & OFPFW_NW_PROTO || a->nw_proto == b->nw_proto) + && !((a->nw_src ^ b->nw_src) & src_mask) + && !((a->nw_dst ^ b->nw_dst) & dst_mask) + && (w & OFPFW_TP_SRC || a->tp_src == b->tp_src) + && (w & OFPFW_TP_DST || a->tp_dst == b->tp_dst)); +} + +static uint32_t make_nw_mask(int n_wild_bits) +{ + n_wild_bits &= (1u << OFPFW_NW_SRC_BITS) - 1; + return n_wild_bits < 32 ? htonl(~((1u << n_wild_bits) - 1)) : 0; +} + +/* Returns nonzero if 'a' and 'b' match, that is, if their fields are equal + * modulo wildcards in 'b', zero otherwise. */ +inline int +flow_matches_1wild(const struct sw_flow_key *a, const struct sw_flow_key *b) +{ + return flow_fields_match(&a->flow, &b->flow, b->wildcards, + b->nw_src_mask, b->nw_dst_mask); +} + +/* Returns nonzero if 'a' and 'b' match, that is, if their fields are equal + * modulo wildcards in 'a' or 'b', zero otherwise. */ +inline int +flow_matches_2wild(const struct sw_flow_key *a, const struct sw_flow_key *b) +{ + return flow_fields_match(&a->flow, &b->flow, a->wildcards | b->wildcards, + a->nw_src_mask & b->nw_src_mask, + a->nw_dst_mask & b->nw_dst_mask); +} + +/* Returns nonzero if 't' (the table entry's key) and 'd' (the key + * describing the match) match, that is, if their fields are + * equal modulo wildcards, zero otherwise. If 'strict' is nonzero, the + * wildcards must match in both 't_key' and 'd_key'. Note that the + * table's wildcards are ignored unless 'strict' is set. */ +int +flow_matches_desc(const struct sw_flow_key *t, const struct sw_flow_key *d, + int strict) +{ + if (strict && d->wildcards != t->wildcards) { + return 0; + } + return flow_matches_1wild(t, d); +} + +/* Returns nonzero if 't' (the table entry's key) and 'd' (the key + * describing the match) match, that is, if their fields are + * equal modulo 't' or 'd' wildcards, zero otherwise. If 'strict' is nonzero, the + * wildcards must match in both 't_key' and 'd_key'. Note that the + * table's wildcards are ignored unless 'strict' is set. */ +int +flow_matches_2desc(const struct sw_flow_key *t, const struct sw_flow_key *d, + int strict) +{ + if (strict && d->wildcards != t->wildcards) { + return 0; + } + return flow_matches_2wild(t, d); +} + +void +flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from) +{ + to->wildcards = ntohl(from->wildcards) & OFPFW_ALL; + to->flow.dl_vlan_pcp = from->dl_vlan_pcp; + to->flow.in_port = from->in_port; + to->flow.dl_vlan = from->dl_vlan; + memcpy(to->flow.dl_src, from->dl_src, ETH_ADDR_LEN); + memcpy(to->flow.dl_dst, from->dl_dst, ETH_ADDR_LEN); + to->flow.dl_type = from->dl_type; + + to->flow.nw_tos = to->flow.nw_proto = to->flow.nw_src = to->flow.nw_dst = 0; + to->flow.tp_src = to->flow.tp_dst = 0; + memset(to->flow.pad, 0, sizeof(to->flow.pad)); + +#define OFPFW_TP (OFPFW_TP_SRC | OFPFW_TP_DST) +#define OFPFW_NW (OFPFW_NW_TOS | OFPFW_NW_PROTO | OFPFW_NW_SRC_MASK | OFPFW_NW_DST_MASK) + if (to->wildcards & OFPFW_DL_TYPE) { + /* Can't sensibly match on network or transport headers if the + * data link type is unknown. */ + to->wildcards |= OFPFW_NW | OFPFW_TP; + } else if (from->dl_type == htons(ETH_TYPE_IP)) { + to->flow.nw_tos = from->nw_tos & 0xfc; + to->flow.nw_proto = from->nw_proto; + to->flow.nw_src = from->nw_src; + to->flow.nw_dst = from->nw_dst; + + if (to->wildcards & OFPFW_NW_PROTO) { + /* Can't sensibly match on transport headers if the network + * protocol is unknown. */ + to->wildcards |= OFPFW_TP; + } else if (from->nw_proto == IPPROTO_TCP + || from->nw_proto == IPPROTO_UDP + || from->nw_proto == IPPROTO_ICMP) { + to->flow.tp_src = from->tp_src; + to->flow.tp_dst = from->tp_dst; + } else { + /* Transport layer fields are undefined. Mark them as + * exact-match to allow such flows to reside in table-hash, + * instead of falling into table-linear. */ + to->wildcards &= ~OFPFW_TP; + } + } else if (from->dl_type == htons(ETH_TYPE_ARP)) { + to->flow.nw_src = from->nw_src; + to->flow.nw_dst = from->nw_dst; + to->flow.nw_proto = from->nw_proto; + + /* Transport layer fields are undefined. Mark them as + * exact-match to allow such flows to reside in table-hash, + * instead of falling into table-linear. */ + to->wildcards &= ~OFPFW_TP; + } else { + /* Network and transport layer fields are undefined. Mark them + * as exact-match to allow such flows to reside in table-hash, + * instead of falling into table-linear. */ + to->wildcards &= ~(OFPFW_NW | OFPFW_TP); + } + + /* We set these late because code above adjusts to->wildcards. */ + to->nw_src_mask = make_nw_mask(to->wildcards >> OFPFW_NW_SRC_SHIFT); + to->nw_dst_mask = make_nw_mask(to->wildcards >> OFPFW_NW_DST_SHIFT); +} + +/* Allocates and returns a new flow with room for 'actions_len' actions. + * Returns the new flow or a null pointer on failure. */ +struct sw_flow * +flow_alloc(size_t actions_len) +{ + struct sw_flow_actions *sfa; + size_t size = sizeof *sfa + actions_len; + struct sw_flow *flow = calloc(1, sizeof *flow); + if (!flow) + return NULL; + + sfa = calloc(1, size); + if (!sfa) { + free(flow); + return NULL; + } + sfa->actions_len = actions_len; + flow->sf_acts = sfa; + return flow; +} + +/* Setup the action on the flow, just after it was created with flow_alloc(). + * Jean II */ +void +flow_setup_actions(struct sw_flow * flow, + const struct ofp_action_header * actions, + int actions_len) +{ + /* Make sure we don't blow the allocation */ + if (actions_len > flow->sf_acts->actions_len) + ofp_fatal(0, + "flow_setup_actions: actions_len is too big (%d > %lu)", + actions_len, (unsigned long)flow->sf_acts->actions_len); + + flow->used = flow->created = time_msec(); + flow->sf_acts->actions_len = actions_len; + flow->byte_count = 0; + flow->packet_count = 0; + memcpy(flow->sf_acts->actions, actions, actions_len); +} + +/* Frees 'flow' immediately. */ +void +flow_free(struct sw_flow *flow) +{ + if (!flow) { + return; + } + free(flow->sf_acts); + free(flow); +} + +/* Copies 'actions' into a newly allocated structure for use by 'flow' + * and frees the structure that defined the previous actions. */ +void flow_replace_acts(struct sw_flow *flow, + const struct ofp_action_header *actions, size_t actions_len) +{ + struct sw_flow_actions *sfa; + int size = sizeof *sfa + actions_len; + + sfa = malloc(size); + if (unlikely(!sfa)) + return; + + sfa->actions_len = actions_len; + memcpy(sfa->actions, actions, actions_len); + + free(flow->sf_acts); + flow->sf_acts = sfa; + + return; +} + +/* Prints a representation of 'key' to the kernel log. */ +void +print_flow(const struct sw_flow_key *key) +{ + const struct flow *f = &key->flow; + + VLOG_INFO("wild %08x port %04x vlan-vid %04x vlan-pcp %02x " + "src-mac %02x:%02x:%02x:%02x:%02x:%02x " + "dst-mac %02x:%02x:%02x:%02x:%02x:%02x " + "frm-type %04x ip-tos %02x ip-src %u.%u.%u.%u ip-dst %u.%u.%u.%u " + "ip-proto %04x tp-src %d tp-dst %d pad %02x%02x%02x\n", + key->wildcards, ntohs(f->in_port), + ntohs(f->dl_vlan), f->dl_vlan_pcp, + f->dl_src[0], f->dl_src[1], f->dl_src[2], + f->dl_src[3], f->dl_src[4], f->dl_src[5], + f->dl_dst[0], f->dl_dst[1], f->dl_dst[2], + f->dl_dst[3], f->dl_dst[4], f->dl_dst[5], + ntohs(f->dl_type), + f->nw_tos, + ((unsigned char *)&f->nw_src)[0], + ((unsigned char *)&f->nw_src)[1], + ((unsigned char *)&f->nw_src)[2], + ((unsigned char *)&f->nw_src)[3], + ((unsigned char *)&f->nw_dst)[0], + ((unsigned char *)&f->nw_dst)[1], + ((unsigned char *)&f->nw_dst)[2], + ((unsigned char *)&f->nw_dst)[3], + f->nw_proto, + ntohs(f->tp_src), ntohs(f->tp_dst), + f->pad[0], f->pad[1], f->pad[2]); +} + +bool flow_timeout(struct sw_flow *flow) +{ + uint64_t now = time_msec(); + if (flow->idle_timeout != OFP_FLOW_PERMANENT + && now > flow->used + flow->idle_timeout * 1000) { + flow->reason = OFPRR_IDLE_TIMEOUT; + return true; + } else if (flow->hard_timeout != OFP_FLOW_PERMANENT + && now > flow->created + flow->hard_timeout * 1000) { + flow->reason = OFPRR_HARD_TIMEOUT; + return true; + } else { + return false; + } +} + +/* Returns nonzero if 'flow' contains an output action to 'out_port' or + * has the value OFPP_NONE. 'out_port' is in network-byte order. */ +int flow_has_out_port(struct sw_flow *flow, uint16_t out_port) +{ + struct sw_flow_actions *sf_acts = flow->sf_acts; + size_t actions_len = sf_acts->actions_len; + uint8_t *p = (uint8_t *)sf_acts->actions; + + if (out_port == htons(OFPP_NONE)) + return 1; + + while (actions_len > 0) { + struct ofp_action_header *ah = (struct ofp_action_header *)p; + size_t len = ntohs(ah->len); + + if (ah->type == htons(OFPAT_OUTPUT)) { + struct ofp_action_output *oa = (struct ofp_action_output *)p; + if (oa->port == out_port) { + return 1; + } + } + p += len; + actions_len -= len; + } + + return 0; +} + +void flow_used(struct sw_flow *flow, struct ofpbuf *buffer) +{ + flow->used = time_msec(); + + flow->packet_count++; + flow->byte_count += buffer->size; +} diff --git a/openflow/udatapath/switch-flow.h b/openflow/udatapath/switch-flow.h new file mode 100644 index 00000000..374cc737 --- /dev/null +++ b/openflow/udatapath/switch-flow.h @@ -0,0 +1,100 @@ +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#ifndef SWITCH_FLOW_H +#define SWITCH_FLOW_H 1 + +#include +#include "openflow/openflow.h" +#include "flow.h" +#include "list.h" + +struct ofp_match; + +/* Identification data for a flow. */ +struct sw_flow_key { + struct flow flow; /* Flow data (in network byte order). */ + uint32_t wildcards; /* Wildcard fields (in host byte order). */ + uint32_t nw_src_mask; /* 1-bit in each significant nw_src bit. */ + uint32_t nw_dst_mask; /* 1-bit in each significant nw_dst bit. */ +}; + +struct sw_flow_actions { + size_t actions_len; + struct ofp_action_header actions[0]; +}; + +struct sw_flow { + struct sw_flow_key key; + + uint64_t cookie; /* Opaque controller-issued identifier. */ + uint16_t priority; /* Only used on entries with wildcards. */ + uint16_t idle_timeout; /* Idle time before discarding (seconds). */ + uint16_t hard_timeout; /* Hard expiration time (seconds) */ + uint64_t used; /* Last used time. */ + uint64_t created; /* When the flow was created. */ + uint64_t packet_count; /* Number of packets seen. */ + uint64_t byte_count; /* Number of bytes seen. */ + uint8_t reason; /* Reason flow removed (one of OFPRR_*). */ + uint8_t send_flow_rem; /* Send a flow removed to the controller */ + uint8_t emerg_flow; /* Emergency flow indicator */ + + struct sw_flow_actions *sf_acts; + + /* Private to table implementations. */ + struct list node; + struct list iter_node; + unsigned long int serial; + + void *private; /* Cookie for tables */ +}; + +int flow_matches_1wild(const struct sw_flow_key *, const struct sw_flow_key *); +int flow_matches_2wild(const struct sw_flow_key *, const struct sw_flow_key *); +int flow_matches_desc(const struct sw_flow_key *, const struct sw_flow_key *, + int); +int flow_matches_2desc(const struct sw_flow_key *, const struct sw_flow_key *, + int); +int flow_has_out_port(struct sw_flow *flow, uint16_t out_port); +struct sw_flow *flow_alloc(size_t); +void flow_setup_actions(struct sw_flow *, const struct ofp_action_header *, int); +void flow_free(struct sw_flow *); +void flow_replace_acts(struct sw_flow *, const struct ofp_action_header *, + size_t); +void flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from); + +void print_flow(const struct sw_flow_key *); +bool flow_timeout(struct sw_flow *flow); +void flow_used(struct sw_flow *flow, struct ofpbuf *buffer); + +#endif /* switch-flow.h */ diff --git a/openflow/udatapath/table-hash.c b/openflow/udatapath/table-hash.c new file mode 100644 index 00000000..fc7006da --- /dev/null +++ b/openflow/udatapath/table-hash.c @@ -0,0 +1,469 @@ +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include "table.h" +#include +#include +#include +#include "openflow/nicira-ext.h" +#include "crc32.h" +#include "datapath.h" +#include "flow.h" +#include "switch-flow.h" + +struct sw_table_hash { + struct sw_table swt; + struct crc32 crc32; + unsigned int n_flows; + unsigned int bucket_mask; /* Number of buckets minus 1. */ + struct sw_flow **buckets; +}; + +static struct sw_flow **find_bucket(struct sw_table *swt, + const struct sw_flow_key *key) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + unsigned int crc = crc32_calculate(&th->crc32, key, + offsetof(struct sw_flow_key, wildcards)); + return &th->buckets[crc & th->bucket_mask]; +} + +static struct sw_flow *table_hash_lookup(struct sw_table *swt, + const struct sw_flow_key *key) +{ + struct sw_flow *flow = *find_bucket(swt, key); + return flow && !flow_compare(&flow->key.flow, &key->flow) ? flow : NULL; +} + +static int table_hash_insert(struct sw_table *swt, struct sw_flow *flow) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + struct sw_flow **bucket; + int retval; + + if (flow->key.wildcards != 0) + return 0; + + bucket = find_bucket(swt, &flow->key); + if (*bucket == NULL) { + th->n_flows++; + *bucket = flow; + retval = 1; + } else { + struct sw_flow *old_flow = *bucket; + if (!flow_compare(&old_flow->key.flow, &flow->key.flow)) { + *bucket = flow; + flow_free(old_flow); + retval = 1; + } else { + retval = 0; + } + } + return retval; +} + +static int table_hash_modify(struct sw_table *swt, + const struct sw_flow_key *key, uint16_t priority, int strict, + const struct ofp_action_header *actions, size_t actions_len) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + unsigned int count = 0; + + if (key->wildcards == 0) { + struct sw_flow **bucket = find_bucket(swt, key); + struct sw_flow *flow = *bucket; + if (flow && flow_matches_desc(&flow->key, key, strict) + && (!strict || (flow->priority == priority))) { + flow_replace_acts(flow, actions, actions_len); + count = 1; + } + } else { + unsigned int i; + + for (i = 0; i <= th->bucket_mask; i++) { + struct sw_flow **bucket = &th->buckets[i]; + struct sw_flow *flow = *bucket; + if (flow && flow_matches_desc(&flow->key, key, strict) + && (!strict || (flow->priority == priority))) { + flow_replace_acts(flow, actions, actions_len); + count++; + } + } + } + return count; +} + +static int table_hash_has_conflict(struct sw_table *swt, + const struct sw_flow_key *key, + uint16_t priority, int strict) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + + if (key->wildcards == 0) { + struct sw_flow **bucket = find_bucket(swt, key); + struct sw_flow *flow = *bucket; + if (flow && flow_matches_2desc(&flow->key, key,strict) + && (flow->priority == priority)) { + return true; + } + } else { + unsigned int i; + + for (i = 0; i <= th->bucket_mask; i++) { + struct sw_flow **bucket = &th->buckets[i]; + struct sw_flow *flow = *bucket; + if (flow && flow_matches_2desc(&flow->key, key, strict) + && (flow->priority == priority)) { + return true; + } + } + } + return false; +} + +/* Caller must update n_flows. */ +static void +do_delete(struct sw_flow **bucket) +{ + flow_free(*bucket); + *bucket = NULL; +} + +/* Returns number of deleted flows. We ignore the priority + * argument, since all exact-match entries are the same (highest) + * priority. */ +static int table_hash_delete(struct datapath *dp, struct sw_table *swt, + const struct sw_flow_key *key, + uint16_t out_port, + uint16_t priority UNUSED, int strict) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + unsigned int count = 0; + + if (key->wildcards == 0) { + struct sw_flow **bucket = find_bucket(swt, key); + struct sw_flow *flow = *bucket; + if (flow && !flow_compare(&flow->key.flow, &key->flow) + && flow_has_out_port(flow, out_port)) { + dp_send_flow_end(dp, flow, OFPRR_DELETE); + do_delete(bucket); + count = 1; + } + } else { + unsigned int i; + + for (i = 0; i <= th->bucket_mask; i++) { + struct sw_flow **bucket = &th->buckets[i]; + struct sw_flow *flow = *bucket; + if (flow && flow_matches_desc(&flow->key, key, strict) + && flow_has_out_port(flow, out_port)) { + dp_send_flow_end(dp, flow, OFPRR_DELETE); + do_delete(bucket); + count++; + } + } + } + th->n_flows -= count; + return count; +} + +static void table_hash_timeout(struct sw_table *swt, struct list *deleted) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + unsigned int i; + + for (i = 0; i <= th->bucket_mask; i++) { + struct sw_flow **bucket = &th->buckets[i]; + struct sw_flow *flow = *bucket; + if (flow && flow_timeout(flow)) { + list_push_back(deleted, &flow->node); + *bucket = NULL; + th->n_flows--; + } + } +} + +static void table_hash_destroy(struct sw_table *swt) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + unsigned int i; + for (i = 0; i <= th->bucket_mask; i++) { + if (th->buckets[i]) { + flow_free(th->buckets[i]); + } + } + free(th->buckets); + free(th); +} + +static int table_hash_iterate(struct sw_table *swt, + const struct sw_flow_key *key, uint16_t out_port, + struct sw_table_position *position, + int (*callback)(struct sw_flow *, void *private), + void *private) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + + if (position->private[0] > th->bucket_mask) + return 0; + + if (key->wildcards == 0) { + struct sw_flow *flow = table_hash_lookup(swt, key); + position->private[0] = -1; + if (!flow || !flow_has_out_port(flow, out_port)) { + return 0; + } + return callback(flow, private); + } else { + int i; + + for (i = position->private[0]; i <= th->bucket_mask; i++) { + struct sw_flow *flow = th->buckets[i]; + if (flow && flow_matches_1wild(&flow->key, key) + && flow_has_out_port(flow, out_port)) { + int error = callback(flow, private); + if (error) { + position->private[0] = i + 1; + return error; + } + } + } + return 0; + } +} + +static void table_hash_stats(struct sw_table *swt, + struct sw_table_stats *stats) +{ + struct sw_table_hash *th = (struct sw_table_hash *) swt; + stats->name = "hash"; + stats->wildcards = 0; /* No wildcards are supported. */ + stats->n_flows = th->n_flows; + stats->max_flows = th->bucket_mask + 1; + stats->n_lookup = swt->n_lookup; + stats->n_matched = swt->n_matched; +} + +struct sw_table *table_hash_create(unsigned int polynomial, + unsigned int n_buckets) +{ + struct sw_table_hash *th; + struct sw_table *swt; + + th = malloc(sizeof *th); + if (th == NULL) + return NULL; + memset(th, '\0', sizeof *th); + + assert(!(n_buckets & (n_buckets - 1))); + th->buckets = calloc(n_buckets, sizeof *th->buckets); + if (th->buckets == NULL) { + printf("failed to allocate %u buckets\n", n_buckets); + free(th); + return NULL; + } + th->n_flows = 0; + th->bucket_mask = n_buckets - 1; + + swt = &th->swt; + swt->lookup = table_hash_lookup; + swt->insert = table_hash_insert; + swt->modify = table_hash_modify; + swt->has_conflict = table_hash_has_conflict; + swt->delete = table_hash_delete; + swt->timeout = table_hash_timeout; + swt->destroy = table_hash_destroy; + swt->iterate = table_hash_iterate; + swt->stats = table_hash_stats; + + crc32_init(&th->crc32, polynomial); + + return swt; +} + +/* Double-hashing table. */ + +struct sw_table_hash2 { + struct sw_table swt; + struct sw_table *subtable[2]; +}; + +static struct sw_flow *table_hash2_lookup(struct sw_table *swt, + const struct sw_flow_key *key) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + int i; + + for (i = 0; i < 2; i++) { + struct sw_flow *flow = *find_bucket(t2->subtable[i], key); + if (flow && !flow_compare(&flow->key.flow, &key->flow)) + return flow; + } + return NULL; +} + +static int table_hash2_insert(struct sw_table *swt, struct sw_flow *flow) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + + if (table_hash_insert(t2->subtable[0], flow)) + return 1; + return table_hash_insert(t2->subtable[1], flow); +} + +static int table_hash2_modify(struct sw_table *swt, + const struct sw_flow_key *key, uint16_t priority, int strict, + const struct ofp_action_header *actions, size_t actions_len) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + return (table_hash_modify(t2->subtable[0], key, priority, strict, + actions, actions_len) + + table_hash_modify(t2->subtable[1], key, priority, strict, + actions, actions_len)); +} + +static int table_hash2_has_conflict(struct sw_table *swt, + const struct sw_flow_key *key, + uint16_t priority, int strict) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + return (table_hash_has_conflict(t2->subtable[0], key, priority, strict) || + table_hash_has_conflict(t2->subtable[1], key, priority, strict)); +} + +static int table_hash2_delete(struct datapath *dp, struct sw_table *swt, + const struct sw_flow_key *key, + uint16_t out_port, + uint16_t priority, int strict) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + return (table_hash_delete(dp, t2->subtable[0], key, out_port, + priority, strict) + + table_hash_delete(dp, t2->subtable[1], key, out_port, + priority, strict)); +} + +static void table_hash2_timeout(struct sw_table *swt, struct list *deleted) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + table_hash_timeout(t2->subtable[0], deleted); + table_hash_timeout(t2->subtable[1], deleted); +} + +static void table_hash2_destroy(struct sw_table *swt) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + table_hash_destroy(t2->subtable[0]); + table_hash_destroy(t2->subtable[1]); + free(t2); +} + +static int table_hash2_iterate(struct sw_table *swt, + const struct sw_flow_key *key, + uint16_t out_port, + struct sw_table_position *position, + int (*callback)(struct sw_flow *, void *), + void *private) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + int i; + + for (i = position->private[1]; i < 2; i++) { + int error = table_hash_iterate(t2->subtable[i], key, out_port, + position, callback, private); + if (error) { + return error; + } + position->private[0] = 0; + position->private[1]++; + } + return 0; +} + +static void table_hash2_stats(struct sw_table *swt, + struct sw_table_stats *stats) +{ + struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; + struct sw_table_stats substats[2]; + int i; + + for (i = 0; i < 2; i++) + table_hash_stats(t2->subtable[i], &substats[i]); + stats->name = "hash2"; + stats->wildcards = 0; /* No wildcards are supported. */ + stats->n_flows = substats[0].n_flows + substats[1].n_flows; + stats->max_flows = substats[0].max_flows + substats[1].max_flows; + stats->n_lookup = swt->n_lookup; + stats->n_matched = swt->n_matched; +} + +struct sw_table *table_hash2_create(unsigned int poly0, unsigned int buckets0, + unsigned int poly1, unsigned int buckets1) + +{ + struct sw_table_hash2 *t2; + struct sw_table *swt; + + t2 = malloc(sizeof *t2); + if (t2 == NULL) + return NULL; + memset(t2, '\0', sizeof *t2); + + t2->subtable[0] = table_hash_create(poly0, buckets0); + if (t2->subtable[0] == NULL) + goto out_free_t2; + + t2->subtable[1] = table_hash_create(poly1, buckets1); + if (t2->subtable[1] == NULL) + goto out_free_subtable0; + + swt = &t2->swt; + swt->lookup = table_hash2_lookup; + swt->insert = table_hash2_insert; + swt->modify = table_hash2_modify; + swt->has_conflict = table_hash2_has_conflict; + swt->delete = table_hash2_delete; + swt->timeout = table_hash2_timeout; + swt->destroy = table_hash2_destroy; + swt->iterate = table_hash2_iterate; + swt->stats = table_hash2_stats; + + return swt; + +out_free_subtable0: + table_hash_destroy(t2->subtable[0]); +out_free_t2: + free(t2); + return NULL; +} diff --git a/openflow/udatapath/table-linear.c b/openflow/udatapath/table-linear.c new file mode 100644 index 00000000..0aea0e25 --- /dev/null +++ b/openflow/udatapath/table-linear.c @@ -0,0 +1,262 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include "table.h" +#include +#include "flow.h" +#include "list.h" +#include "openflow/openflow.h" +#include "openflow/nicira-ext.h" +#include "switch-flow.h" +#include "datapath.h" + +struct sw_table_linear { + struct sw_table swt; + + unsigned int max_flows; + unsigned int n_flows; + struct list flows; + struct list iter_flows; + unsigned long int next_serial; +}; + +static struct sw_flow *table_linear_lookup(struct sw_table *swt, + const struct sw_flow_key *key) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + struct sw_flow *flow; + LIST_FOR_EACH (flow, struct sw_flow, node, &tl->flows) { + if (flow_matches_1wild(key, &flow->key)) + return flow; + } + return NULL; +} + +static int table_linear_insert(struct sw_table *swt, struct sw_flow *flow) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + struct sw_flow *f; + + /* Loop through the existing list of entries. New entries will + * always be placed behind those with equal priority. Just replace + * any flows that match exactly. + */ + LIST_FOR_EACH (f, struct sw_flow, node, &tl->flows) { + if (f->priority == flow->priority + && f->key.wildcards == flow->key.wildcards + && flow_matches_2wild(&f->key, &flow->key)) { + flow->serial = f->serial; + list_replace(&flow->node, &f->node); + list_replace(&flow->iter_node, &f->iter_node); + flow_free(f); + return 1; + } + + if (f->priority < flow->priority) + break; + } + + /* Make sure there's room in the table. */ + if (tl->n_flows >= tl->max_flows) { + return 0; + } + tl->n_flows++; + + /* Insert the entry immediately in front of where we're pointing. */ + flow->serial = tl->next_serial++; + list_insert(&f->node, &flow->node); + list_push_front(&tl->iter_flows, &flow->iter_node); + + return 1; +} + +static int table_linear_modify(struct sw_table *swt, + const struct sw_flow_key *key, uint16_t priority, int strict, + const struct ofp_action_header *actions, size_t actions_len) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + struct sw_flow *flow; + unsigned int count = 0; + + LIST_FOR_EACH (flow, struct sw_flow, node, &tl->flows) { + if (flow_matches_desc(&flow->key, key, strict) + && (!strict || (flow->priority == priority))) { + flow_replace_acts(flow, actions, actions_len); + count++; + } + } + return count; +} + +static int table_linear_has_conflict(struct sw_table *swt, + const struct sw_flow_key *key, + uint16_t priority, int strict) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + struct sw_flow *flow; + + LIST_FOR_EACH (flow, struct sw_flow, node, &tl->flows) { + if (flow_matches_2desc(&flow->key, key, strict) + && (flow->priority == priority)) { + return true; + } + } + return false; +} + +static void +do_delete(struct sw_flow *flow) +{ + list_remove(&flow->node); + list_remove(&flow->iter_node); + flow_free(flow); +} + +static int table_linear_delete(struct datapath *dp, struct sw_table *swt, + const struct sw_flow_key *key, + uint16_t out_port, + uint16_t priority, int strict) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + struct sw_flow *flow, *n; + unsigned int count = 0; + + LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &tl->flows) { + if (flow_matches_desc(&flow->key, key, strict) + && flow_has_out_port(flow, out_port) + && (!strict || (flow->priority == priority))) { + dp_send_flow_end(dp, flow, OFPRR_DELETE); + do_delete(flow); + count++; + } + } + tl->n_flows -= count; + return count; +} + +static void table_linear_timeout(struct sw_table *swt, struct list *deleted) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + struct sw_flow *flow, *n; + + LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &tl->flows) { + if (flow_timeout(flow)) { + list_remove(&flow->node); + list_remove(&flow->iter_node); + list_push_back(deleted, &flow->node); + tl->n_flows--; + } + } +} + +static void table_linear_destroy(struct sw_table *swt) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + + while (!list_is_empty(&tl->flows)) { + struct sw_flow *flow = CONTAINER_OF(list_front(&tl->flows), + struct sw_flow, node); + list_remove(&flow->node); + flow_free(flow); + } + free(tl); +} + +static int table_linear_iterate(struct sw_table *swt, + const struct sw_flow_key *key, + uint16_t out_port, + struct sw_table_position *position, + int (*callback)(struct sw_flow *, void *), + void *private) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + struct sw_flow *flow; + unsigned long start; + + start = ~position->private[0]; + LIST_FOR_EACH (flow, struct sw_flow, iter_node, &tl->iter_flows) { + if (flow->serial <= start + && flow_matches_2wild(key, &flow->key) + && flow_has_out_port(flow, out_port)) { + int error = callback(flow, private); + if (error) { + position->private[0] = ~(flow->serial - 1); + return error; + } + } + } + return 0; +} + +static void table_linear_stats(struct sw_table *swt, + struct sw_table_stats *stats) +{ + struct sw_table_linear *tl = (struct sw_table_linear *) swt; + stats->name = "linear"; + stats->wildcards = OFPFW_ALL; + stats->n_flows = tl->n_flows; + stats->max_flows = tl->max_flows; + stats->n_lookup = swt->n_lookup; + stats->n_matched = swt->n_matched; +} + + +struct sw_table *table_linear_create(unsigned int max_flows) +{ + struct sw_table_linear *tl; + struct sw_table *swt; + + tl = calloc(1, sizeof *tl); + if (tl == NULL) + return NULL; + + swt = &tl->swt; + swt->lookup = table_linear_lookup; + swt->insert = table_linear_insert; + swt->modify = table_linear_modify; + swt->has_conflict = table_linear_has_conflict; + swt->delete = table_linear_delete; + swt->timeout = table_linear_timeout; + swt->destroy = table_linear_destroy; + swt->iterate = table_linear_iterate; + swt->stats = table_linear_stats; + + tl->max_flows = max_flows; + tl->n_flows = 0; + list_init(&tl->flows); + list_init(&tl->iter_flows); + tl->next_serial = 0; + + return swt; +} diff --git a/openflow/udatapath/table.h b/openflow/udatapath/table.h new file mode 100644 index 00000000..1312e3c9 --- /dev/null +++ b/openflow/udatapath/table.h @@ -0,0 +1,150 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +/* Individual switching tables. Generally grouped together in a chain (see + * chain.h). */ + +#ifndef TABLE_H +#define TABLE_H 1 + +#include +#include + +struct datapath; /* Forward declaration for delete operation */ +struct sw_flow; +struct sw_flow_key; +struct ofp_action_header; +struct list; + +/* Table statistics. */ +struct sw_table_stats { + const char *name; /* Human-readable name. */ + uint32_t wildcards; /* Bitmap of OFPFW_* wildcards that are + supported by the table. */ + unsigned int n_flows; /* Number of active flows. */ + unsigned int max_flows; /* Flow capacity. */ + unsigned long int n_lookup; /* Number of packets looked up. */ + unsigned long int n_matched; /* Number of packets that have hit. */ +}; + +/* Position within an iteration of a sw_table. + * + * The contents are private to the table implementation, except that a position + * initialized to all-zero-bits represents the start of a table. */ +struct sw_table_position { + unsigned long private[4]; +}; + +/* A single table of flows. */ +struct sw_table { + /* The number of packets that have been looked up and matched, + * respecitvely. To make these 100% accurate, they should be atomic. + * However, we're primarily concerned about speed. */ + unsigned long long n_lookup; + unsigned long long n_matched; + + /* Searches 'table' for a flow matching 'key', which must not have any + * wildcard fields. Returns the flow if successful, a null pointer + * otherwise. */ + struct sw_flow *(*lookup)(struct sw_table *table, + const struct sw_flow_key *key); + + /* Inserts 'flow' into 'table', replacing any duplicate flow. Returns + * 0 if successful or a negative error. Error can be due to an + * over-capacity table or because the flow is not one of the kind that + * the table accepts. + * + * If successful, 'flow' becomes owned by 'table', otherwise it is + * retained by the caller. */ + int (*insert)(struct sw_table *table, struct sw_flow *flow); + + /* Modifies the actions in 'table' that match 'key'. If 'strict' + * set, wildcards and priority must match. Returns the number of flows + * that were modified. */ + int (*modify)(struct sw_table *table, const struct sw_flow_key *key, + uint16_t priority, int strict, + const struct ofp_action_header *actions, size_t actions_len); + + /* Checks whether 'table' has an equal priotiry entry of thethat conflicts + * with 'key'. If 'strict' is set, wildcards must match. + * Returns the number of flows that were modified. */ + int (*has_conflict)(struct sw_table *table, const struct sw_flow_key *key, + uint16_t priority, int strict); + + /* Deletes from 'table' any and all flows that match 'key' from + * 'table'. If 'out_port' is not OFPP_NONE, then matching entries + * must have that port as an argument for an output action. If + * 'strict' is set, wildcards and priority must match. Returns the + * number of flows that were deleted. */ + int (*delete)(struct datapath *dp, struct sw_table *table, + const struct sw_flow_key *key, + uint16_t out_port, uint16_t priority, int strict); + + /* Performs timeout processing on all the flow entries in 'table'. + * Appends all the flow entries removed from 'table' to 'deleted' for the + * caller to free. */ + void (*timeout)(struct sw_table *table, struct list *deleted); + + /* Destroys 'table', which must not have any users. */ + void (*destroy)(struct sw_table *table); + + /* Iterates through the flow entries in 'table', passing each one + * matches 'key' and output port 'out_port' to 'callback'. The + * callback function should return 0 to continue iteration or a + * nonzero error code to stop. The iterator function returns either + * 0 if the table iteration completed or the value returned by the + * callback function otherwise. + * + * The iteration starts at 'position', which may be initialized to + * all-zero-bits to iterate from the beginning of the table. If the + * iteration terminates due to an error from the callback function, + * 'position' is updated to a value that can be passed back to the + * iterator function to resume iteration later with the following + * flow. */ + int (*iterate)(struct sw_table *table, + const struct sw_flow_key *key, uint16_t out_port, + struct sw_table_position *position, + int (*callback)(struct sw_flow *flow, void *private), + void *private); + + /* Dumps statistics for 'table' into 'stats'. */ + void (*stats)(struct sw_table *table, struct sw_table_stats *stats); +}; + +struct sw_table *table_hash_create(unsigned int polynomial, + unsigned int n_buckets); +struct sw_table *table_hash2_create(unsigned int poly0, unsigned int buckets0, + unsigned int poly1, unsigned int buckets1); +struct sw_table *table_linear_create(unsigned int max_flows); + +#endif /* table.h */ diff --git a/openflow/udatapath/udatapath.c b/openflow/udatapath/udatapath.c new file mode 100644 index 00000000..a4446575 --- /dev/null +++ b/openflow/udatapath/udatapath.c @@ -0,0 +1,345 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "command-line.h" +#include "daemon.h" +#include "datapath.h" +#include "fault.h" +#include "openflow/openflow.h" +#include "poll-loop.h" +#include "queue.h" +#include "util.h" +#include "rconn.h" +#include "timeval.h" +#include "vconn.h" +#include "dirs.h" +#include "vconn-ssl.h" +#include "vlog-socket.h" + +#if defined(OF_HW_PLAT) +#include +#endif + +#define THIS_MODULE VLM_udatapath +#include "vlog.h" + +/* Strings to describe the manufacturer, hardware, and software. This data + * is queriable through the switch description stats message. */ +char mfr_desc[DESC_STR_LEN] = "Stanford University"; +char hw_desc[DESC_STR_LEN] = "Reference Userspace Switch"; +char sw_desc[DESC_STR_LEN] = VERSION BUILDNR; +char dp_desc[DESC_STR_LEN] = ""; +char serial_num[SERIAL_NUM_LEN] = "None"; + +static void parse_options(int argc, char *argv[]); +static void usage(void) NO_RETURN; + +static struct datapath *dp; +static uint64_t dpid = UINT64_MAX; +static char *port_list; +static char *local_port = "tap:"; +static uint16_t num_queues = NETDEV_MAX_QUEUES; + +static void add_ports(struct datapath *dp, char *port_list); + +/* Need to treat this more generically */ +#if defined(UDATAPATH_AS_LIB) +#define OFP_FATAL(_er, _str, args...) do { \ + fprintf(stderr, _str, ## args); \ + return -1; \ + } while (0) +#else +#define OFP_FATAL(_er, _str, args...) ofp_fatal(_er, _str, ## args) +#endif + +#if !defined(UDATAPATH_AS_LIB) +int +main(int argc, char *argv[]) +{ + return udatapath_cmd(argc, argv); +} +#endif + +int +udatapath_cmd(int argc, char *argv[]) +{ + int n_listeners; + int error; + int i; + + set_program_name(argv[0]); + register_fault_handlers(); + time_init(); + vlog_init(); + parse_options(argc, argv); + signal(SIGPIPE, SIG_IGN); + + if (argc - optind < 1) { + OFP_FATAL(0, "at least one listener argument is required; " + "use --help for usage"); + } + + error = dp_new(&dp, dpid); + + n_listeners = 0; + for (i = optind; i < argc; i++) { + const char *pvconn_name = argv[i]; + struct pvconn *pvconn; + int retval; + + retval = pvconn_open(pvconn_name, &pvconn); + if (!retval || retval == EAGAIN) { + dp_add_pvconn(dp, pvconn); + n_listeners++; + } else { + ofp_error(retval, "opening %s", pvconn_name); + } + } + if (!n_listeners) { + OFP_FATAL(0, "could not listen for any connections"); + } + + if (port_list) { + add_ports(dp, port_list); + } + if (local_port) { + error = dp_add_local_port(dp, local_port, 0); + if (error) { + OFP_FATAL(error, "failed to add local port %s", local_port); + } + } + + error = vlog_server_listen(NULL, NULL); + if (error) { + OFP_FATAL(error, "could not listen for vlog connections"); + } + + die_if_already_running(); + daemonize(); + + for (;;) { + dp_run(dp); + dp_wait(dp); + poll_block(); + } + + return 0; +} + +static void +add_ports(struct datapath *dp, char *port_list) +{ + char *port, *save_ptr; + + /* Glibc 2.7 has a bug in strtok_r when compiling with optimization that + * can cause segfaults here: + * http://sources.redhat.com/bugzilla/show_bug.cgi?id=5614. + * Using ",," instead of the obvious "," works around it. */ + for (port = strtok_r(port_list, ",,", &save_ptr); port; + port = strtok_r(NULL, ",,", &save_ptr)) { + int error = dp_add_port(dp, port, num_queues); + if (error) { + ofp_fatal(error, "failed to add port %s", port); + } + } +} + +static void +parse_options(int argc, char *argv[]) +{ + enum { + OPT_MFR_DESC = UCHAR_MAX + 1, + OPT_HW_DESC, + OPT_SW_DESC, + OPT_DP_DESC, + OPT_SERIAL_NUM, + OPT_BOOTSTRAP_CA_CERT, + OPT_NO_LOCAL_PORT, + OPT_NO_SLICING + }; + + static struct option long_options[] = { + {"interfaces", required_argument, 0, 'i'}, + {"local-port", required_argument, 0, 'L'}, + {"no-local-port", no_argument, 0, OPT_NO_LOCAL_PORT}, + {"datapath-id", required_argument, 0, 'd'}, + {"verbose", optional_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {"no-slicing", no_argument, 0, OPT_NO_SLICING}, + {"mfr-desc", required_argument, 0, OPT_MFR_DESC}, + {"hw-desc", required_argument, 0, OPT_HW_DESC}, + {"sw-desc", required_argument, 0, OPT_SW_DESC}, + {"dp_desc", required_argument, 0, OPT_DP_DESC}, + {"serial_num", required_argument, 0, OPT_SERIAL_NUM}, + DAEMON_LONG_OPTIONS, +#ifdef HAVE_OPENSSL + VCONN_SSL_LONG_OPTIONS + {"bootstrap-ca-cert", required_argument, 0, OPT_BOOTSTRAP_CA_CERT}, +#endif + {0, 0, 0, 0}, + }; + char *short_options = long_options_to_short_options(long_options); + + for (;;) { + int indexptr; + int c; + + c = getopt_long(argc, argv, short_options, long_options, &indexptr); + if (c == -1) { + break; + } + + switch (c) { + case 'd': + if (strlen(optarg) != 12 + || strspn(optarg, "0123456789abcdefABCDEF") != 12) { + ofp_fatal(0, "argument to -d or --datapath-id must be " + "exactly 12 hex digits"); + } + dpid = strtoll(optarg, NULL, 16); + if (!dpid) { + ofp_fatal(0, "argument to -d or --datapath-id must " + "be nonzero"); + } + break; + + case 'h': + usage(); + + case 'V': + printf("%s %s compiled "__DATE__" "__TIME__"\n", + program_name, VERSION BUILDNR); + exit(EXIT_SUCCESS); + + case 'v': + vlog_set_verbosity(optarg); + break; + + case 'i': + if (!port_list) { + port_list = optarg; + } else { + port_list = xasprintf("%s,%s", port_list, optarg); + } + break; + + case 'L': + local_port = optarg; + break; + + case OPT_NO_LOCAL_PORT: + local_port = NULL; + break; + + case OPT_MFR_DESC: + strncpy(mfr_desc, optarg, sizeof mfr_desc); + break; + + case OPT_HW_DESC: + strncpy(hw_desc, optarg, sizeof hw_desc); + break; + + case OPT_SW_DESC: + strncpy(sw_desc, optarg, sizeof sw_desc); + break; + + case OPT_DP_DESC: + strncpy(dp_desc, optarg, sizeof dp_desc); + break; + + case OPT_SERIAL_NUM: + strncpy(serial_num, optarg, sizeof serial_num); + break; + + case OPT_NO_SLICING: + num_queues = 0; + break; + + DAEMON_OPTION_HANDLERS + +#ifdef HAVE_OPENSSL + VCONN_SSL_OPTION_HANDLERS + + case OPT_BOOTSTRAP_CA_CERT: + vconn_ssl_set_ca_cert_file(optarg, true); + break; +#endif + + case '?': + exit(EXIT_FAILURE); + + default: + abort(); + } + } + free(short_options); +} + +static void +usage(void) +{ + printf("%s: userspace OpenFlow datapath\n" + "usage: %s [OPTIONS] LISTEN...\n" + "where LISTEN is a passive OpenFlow connection method on which\n" + "to listen for incoming connections from the secure channel.\n", + program_name, program_name); + vconn_usage(false, true, false); + printf("\nConfiguration options:\n" + " -i, --interfaces=NETDEV[,NETDEV]...\n" + " add specified initial switch ports\n" + " -L, --local-port=NETDEV set network device for local port\n" + " --no-local-port disable local port\n" + " -d, --datapath-id=ID Use ID as the OpenFlow switch ID\n" + " (ID must consist of 12 hex digits)\n" + " --no-slicing disable slicing\n" + "\nOther options:\n" + " -D, --detach run in background as daemon\n" + " -P, --pidfile[=FILE] create pidfile (default: %s/ofdatapath.pid)\n" + " -f, --force with -P, start even if already running\n" + " -v, --verbose=MODULE[:FACILITY[:LEVEL]] set logging levels\n" + " -v, --verbose set maximum verbosity level\n" + " -h, --help display this help message\n" + " -V, --version display version information\n", + ofp_rundir); + exit(EXIT_SUCCESS); +} diff --git a/openflow/utilities/.dirstamp b/openflow/utilities/.dirstamp new file mode 100644 index 00000000..e69de29b diff --git a/openflow/utilities/.gitignore b/openflow/utilities/.gitignore new file mode 100644 index 00000000..c93169bf --- /dev/null +++ b/openflow/utilities/.gitignore @@ -0,0 +1,13 @@ +/Makefile +/Makefile.in +/dpctl +/dpctl.8 +/ofp-discover +/ofp-discover.8 +/ofp-kill +/ofp-kill.8 +/ofp-pki +/ofp-pki-cgi +/ofp-pki.8 +/vlogconf +/vlogconf.8 diff --git a/openflow/utilities/automake.mk b/openflow/utilities/automake.mk new file mode 100644 index 00000000..d6f79a8c --- /dev/null +++ b/openflow/utilities/automake.mk @@ -0,0 +1,45 @@ +bin_PROGRAMS += \ + utilities/vlogconf \ + utilities/dpctl \ + utilities/ofp-discover \ + utilities/ofp-kill +bin_SCRIPTS += utilities/ofp-pki +noinst_SCRIPTS += utilities/ofp-pki-cgi utilities/ofp-parse-leaks + +EXTRA_DIST += \ + utilities/dpctl.8.in \ + utilities/ofp-discover.8.in \ + utilities/ofp-kill.8.in \ + utilities/ofp-parse-leaks.in \ + utilities/ofp-pki-cgi.in \ + utilities/ofp-pki.8.in \ + utilities/ofp-pki.in \ + utilities/vlogconf.8.in +DISTCLEANFILES += \ + utilities/dpctl.8 \ + utilities/ofp-discover.8 \ + utilities/ofp-kill.8 \ + utilities/ofp-parse-leaks \ + utilities/ofp-pki \ + utilities/ofp-pki.8 \ + utilities/ofp-pki-cgi \ + utilities/vlogconf.8 + +man_MANS += \ + utilities/dpctl.8 \ + utilities/ofp-discover.8 \ + utilities/ofp-kill.8 \ + utilities/ofp-pki.8 \ + utilities/vlogconf.8 + +utilities_dpctl_SOURCES = utilities/dpctl.c +utilities_dpctl_LDADD = lib/libopenflow.a $(FAULT_LIBS) $(SSL_LIBS) + +utilities_vlogconf_SOURCES = utilities/vlogconf.c +utilities_vlogconf_LDADD = lib/libopenflow.a + +utilities_ofp_discover_SOURCES = utilities/ofp-discover.c +utilities_ofp_discover_LDADD = lib/libopenflow.a + +utilities_ofp_kill_SOURCES = utilities/ofp-kill.c +utilities_ofp_kill_LDADD = lib/libopenflow.a diff --git a/openflow/utilities/dpctl.8.in b/openflow/utilities/dpctl.8.in new file mode 100644 index 00000000..80f06bb0 --- /dev/null +++ b/openflow/utilities/dpctl.8.in @@ -0,0 +1,582 @@ +.ds PN dpctl + +.TH dpctl 8 "May 2008" "OpenFlow" "OpenFlow Manual" + +.SH NAME +dpctl \- administer OpenFlow datapaths + +.SH SYNOPSIS +.B dpctl +[\fIoptions\fR] \fIcommand \fR[\fIswitch\fR] [\fIargs\fR&...] + +.SH DESCRIPTION +The +.B dpctl +program is a command line tool for monitoring and administering OpenFlow +datapaths. It is able to show the current state of a datapath, +including features, configuration, and tables entries. When using the +OpenFlow kernel module, +.B dpctl +is used to add, delete, modify, and monitor datapaths. + +Most \fBdpctl\fR commands take an argument that specifies the +method for connecting to an OpenFlow switch. The following connection +methods are supported: + +.TP +\fBnl:\fIdp_idx\fR +The local Netlink datapath numbered \fIdp_idx\fR. This form requires +that the local host has the OpenFlow kernel module for Linux loaded. + +.TP +\fBssl:\fIhost\fR[\fB:\fIport\fR] +The specified SSL \fIport\fR (default: 6633) on the given remote +\fIhost\fR. The \fB--private-key\fR, \fB--certificate\fR, and +\fB--ca-cert\fR options are mandatory when this form is used. + +.TP +\fBtcp:\fIhost\fR[\fB:\fIport\fR] +The specified TCP \fIport\fR (default: 6633) on the given remote +\fIhost\fR. + +.TP +\fBunix:\fIfile\fR +The Unix domain server socket named \fIfile\fR. + +.SH COMMANDS + +With the \fBdpctl\fR program, datapaths running in the kernel can be +created, deleted, and modified. A single machine may +host up to 32 datapaths (numbered 0 to 31). In most situations, +a machine hosts only one datapath. + +A newly created datapath is not associated with any of the +host's network devices thus does not process any incoming +traffic. To intercept and process traffic on a given network device, the +network device must be explicitly added to a datapath through the +\fBaddif\fR command. + +The following commands manage local datapaths. + +.TP +\fBadddp nl:\fIdp_idx\fR +Creates datapath numbered \fIdp_idx\fR on the local host. This will +fail if \fIdp_idx\fR is not in the range 0 to 31, or if the datapath +with that number already exists on the host. + +.TP +\fBdeldp nl:\fIdp_idx\fR +Deletes datapath \fIdp_idx\fR on the local host. \fIdp_idx\fR must be +an existing datapath. All of a datapath's network devices must be +explicitly removed before the datapath can be deleted (see \fBdelif\fR +command). + +.TP +\fBaddif nl:\fIdp_idx netdev\fR... +Adds each \fInetdev\fR to the list of network devices datapath +\fIdp_idx\fR monitors, where \fIdp_idx\fR is the ID of an existing +datapath, and \fInetdev\fR is the name of one of the host's +network devices, e.g. \fBeth0\fR. Once a network device has been added +to a datapath, the datapath has complete ownership of the network device's +traffic and the network device appears silent to the rest of the system. + +.TP +\fBdelif nl:\fIdp_idx netdev\fR... +Removes each \fInetdev\fR from the list of network devices datapath +\fIdp_idx\fR monitors. + +.TP +\fBget-idx \fIof_dev\fR +Prints the datapath index for OpenFlow device \fIof_dev\fR. + +.PP +The following commands can be apply to OpenFlow switches regardless of +the connection method. + +.TP +\fBshow \fIswitch\fR +Prints to the console information on datapath \fIswitch\fR including +information on its flow tables and ports. + +.TP +\fBstatus \fIswitch\fR [\fIkey\fR] +Prints to the console a series of key-value pairs that report the +status of \fIswitch\fR. If \fIkey\fR is specified, only the key-value +pairs whose key names begin with \fIkey\fR are printed. If \fIkey\fR is +omitted, all key-value pairs are printed. + +(In the OpenFlow reference implementation, the \fBstatus\fR command is +implemented in \fBofprotocol\fR(8), not in the kernel module, so the +\fBnl:\fIdp_idx\fR connection method should not be used with this +command. Instead, specify \fB-l\fR or \fB--listen\fR on the +\fBofprotocol\fR command line and tell \fBdpctl\fR to use the connection +method specified there.) + +.TP +\fBshow-protostat \fIswitch\fR +Prints to the OpenFlow protocol statiscal information of \fIswitch\fR. + +(In the OpenFlow reference implementation, the \fBshow-protostat\fR command +is implemented in \fBofprotocol\fR(8), not in the kernel module, so the +\fBnl:\fIdp_idx\fR connection method should not be used with this +command. Instead, specify \fB-l\fR or \fB--listen\fR on the +\fBofprotocol\fR command line and tell \fBdpctl\fR to use the connection +method specified there.) + +.TP +\fBdump-tables \fIswitch\fR +Prints to the console statistics for each of the flow tables used by +datapath \fIswitch\fR. + +.TP +\fBdump-ports \fIswitch\fR \fR[\fIport number\fR] +Prints to the console statistics for each interface monitored by +\fIswitch\fR. If port number is specified, print statistics only for +the interface corresponding to port number. + +.TP +\fBmod-port \fIswitch\fR \fInetdev\fR \fIaction\fR +Modify characteristics of an interface monitored by \fIswitch\fR. +\fInetdev\fR can be referred to by its OpenFlow assigned port number or +the device name, e.g. \fBeth0\fR. The \fIaction\fR may be any one of the +following: + +.RS +.IP \fBup\fR +Enables the interface. This is equivalent to ``ifconfig up'' on a Unix +system. + +.IP \fBdown\fR +Disables the interface. This is equivalent to ``ifconfig down'' on a Unix +system. + +.IP \fBflood\fR +When a \fIflood\fR action is specified, traffic will be sent out this +interface. This is the default posture for monitored ports. + +.IP \fBnoflood\fR +When a \fIflood\fR action is specified, traffic will not be sent out +this interface. This is primarily useful to prevent loops when a +spanning tree protocol is not in use. + +.RE + +.TP +\fBdump-flows \fIswitch \fR[\fIflows\fR] +Prints to the console all flow entries in datapath \fIswitch\fR's +tables that match \fIflows\fR. If \fIflows\fR is omitted, all flows +except emergency flows in the datapath flows are retrieved. +See \fBFLOW SYNTAX\fR, below, for the syntax of \fIflows\fR. + +.TP +\fBdesc \fIswitch \fIstring +Sets the switch description (as returned in ofp_desc_stats) to +\fIstring (max length is DESC_STR_LEN). + +.TP +\fBdump-aggregate \fIswitch \fR[\fIflows\fR] +Prints to the console aggregate statistics for flows in datapath +\fSWITCH\fR's tables that match \fIflows\fR. If \fIflows\fR is omitted, +the statistics are aggregated across all flows in the datapath's flow +tables. See \fBFLOW SYNTAX\fR, below, for the syntax of \fIflows\fR. + +.TP +\fBadd-flow \fIswitch flow\fR +Add the flow entry as described by \fIflow\fR to the datapath \fIswitch\fR's +tables. The flow entry is in the format described in \fBFLOW SYNTAX\fR, +below. + +.TP +\fBadd-flows \fIswitch file\fR +Add flow entries as described in \fIfile\fR to the datapath \fIswitch\fR's +tables. Each line in \fIfile\fR is a flow entry in the format +described in \fBFLOW SYNTAX\fR, below. + +.TP +\fBmod-flows \fIswitch flow\fR +Modify the actions in entries from the datapath \fIswitch\fR's tables +that match \fIflow\fR. When invoked with the \fB--strict\fR option, +wildcards are not treated as active for matching purposes. See +\fBFLOW SYNTAX\fR, below, for the syntax of \fIflows\fR. + +.TP +\fBdel-flows \fIswitch \fR[\fIflow\fR] +Deletes entries from the datapath \fIswitch\fR's tables that match +\fIflow\fR. When invoked with the \fB--strict\fR option, wildcards are +not treated as active for matching purposes. If \fIflow\fR is +omitted and the \fB--strict\fR option is not used, all flows in the +datapath's tables are removed. See \fBFLOW SYNTAX\fR, below, for the +syntax of \fIflows\fR. + +.TP +\fBmonitor \fIswitch\fR +Connects to \fIswitch\fR and prints to the console all OpenFlow +messages received. Usually, \fIswitch\fR should specify a connection +named on \fBofprotocol\fR(8)'s \fB-m\fR or \fB--monitor\fR command line +option, in which the messages printed will be all those sent or +received by \fBofprotocol\fR to or from the kernel datapath module. A +\fIswitch\fR of the form \fBnl:\fIdp_idx\fR will print all +asynchronously generated OpenFlow messages (such as packet-in +messages), but it will not print any messages sent to the kernel by +\fBofprotocol\fR and other processes, nor will it print replies sent by +the kernel in response to those messages. + +.PP +The following commands monitor and control the egress queue +configuration for an OpenFlow switch if the switch supports such +operations. After a queue is created with the add or modify +operation, the OpenFlow enqueue action may be specified to +direct packets to a particular queue. Queues are associated with +specific ports (so the same queue-id may be used on different +ports and this will refer to different queues). The only +characteristic that may be configured for queues is the minimum +bandwidth guarantee. This parameter is specified in tenths of +a percent (so full link bandwidth is 1000). + +.TP +\fBadd-queue \fIswitch\fR \fIport\fR \fIq-id\fR [\fIbandwidth\fR] +Connect to \fIswitch\fR and add an egress queue identified as \fIq-id\fR +for \fIport\fR. If +specified, \fIbandwidth\fR indicates the minimum bandwidth guarantee +for the queue and is specified in tenths of a +percent. This is the only characteristic of the queue that +may be configured. + +.TP +\fBmod-queue \fIswitch\fR \fIport\fR \fIq-id\fR \fIbandwidth\fR +Connect to \fIswitch\fR and modify the bandwidth setting for an egress +queue identified as \fIq-id\fR +for \fIport\fR. The queue need not have been created with \fBadd-queue\fR +previously. The parameter \fIbandwidth\fR indicates the minimum +bandwidth guarantee for the queue and is specified in tenths of a +percent. This is the only characteristic +of the queue that may be configured. + +.TP +\fBdel-queue \fIswitch\fR \fIport\fR \fIq-id\fR +Delete an egress queue identified as \fIq-id\fR for \fIport\fR which +had been created by \fBadd-queue\fR or \fBmod-queue\fR. + +.TP +\fBdump-queue \fIswitch\fR [\fIport\fR [\fIq-id\fR]] +Dump that current queue configuration. A port may be specified. +If it is, a queue-id may also be specified. + +.PP +The following commands can be used regardless of the connection +method. They apply to OpenFlow switches and controllers. + +.TP +\fBprobe \fIvconn\fR +Connects to \fIvconn\fR and sends a single OpenFlow echo-request +packet and waits for the response. With the \fB-t\fR or +\fB--timeout\fR option, this command can test whether an OpenFlow +switch or controller is up and running. + +.TP +\fBping \fIvconn \fR[\fIn\fR] +Sends a series of 10 echo request packets to \fIvconn\fR and times +each reply. The echo request packets consist of an OpenFlow header +plus \fIn\fR bytes (default: 64) of randomly generated payload. This +measures the latency of individual requests. + +.TP +\fBbenchmark \fIvconn n count\fR +Sends \fIcount\fR echo request packets that each consist of an +OpenFlow header plus \fIn\fR bytes of payload and waits for each +response. Reports the total time required. This is a measure of the +maximum bandwidth to \fIvconn\fR for round-trips of \fIn\fR-byte +messages. + +.SH "FLOW SYNTAX" + +Some \fBdpctl\fR commands accept an argument that describes a flow or +flows. Such flow descriptions comprise a series +\fIfield\fB=\fIvalue\fR assignments, separated by commas or white +space. + +The following field assignments describe how a flow matches a packet. +If any of these assignments is omitted from the flow syntax, the field +is treated as a wildcard; thus, if all of them are omitted, the +resulting flow matches all packets. The string \fB*\fR or \fBANY\fR +may be specified a value to explicitly mark any of these fields as a +wildcard. + +.IP \fBin_port=\fIport_no\fR +Matches physical port \fIport_no\fR. Switch ports are numbered as +displayed by \fBdpctl show\fR. + +.IP \fBdl_vlan=\fIvlan\fR +Matches IEEE 802.1q virtual LAN tag \fIvlan\fR. Specify \fB0xffff\fR +as \fIvlan\fR to match packets that are not tagged with a virtual LAN; +otherwise, specify a number between 0 and 4095, inclusive, as the +12-bit VLAN ID to match. + +.IP \fBdl_src=\fImac\fR +Matches Ethernet source address \fImac\fR, which should be specified +as 6 pairs of hexadecimal digits delimited by colons, +e.g. \fB00:0A:E4:25:6B:B0\fR. + +.IP \fBdl_dst=\fImac\fR +Matches Ethernet destination address \fImac\fR. + +.IP \fBdl_type=\fIethertype\fR +Matches Ethernet protocol type \fIethertype\fR, which should be +specified as a integer between 0 and 65535, inclusive, either in +decimal or as a hexadecimal number prefixed by \fB0x\fR, +e.g. \fB0x0806\fR to match ARP packets. + +.IP \fBnw_src=\fIip\fR[\fB/\fInetmask\fR] +Matches IPv4 source address \fIip\fR, which should be specified as an +IP address or host name, e.g. \fB192.168.1.1\fR or +\fBwww.example.com\fR. The optional \fInetmask\fR allows matching +only on an IPv4 address prefix. It may be specified as a dotted quad +(e.g. \fB192.168.1.0/255.255.255.0\fR) or as a count of bits +(e.g. \fB192.168.1.0/24\fR). + +.IP \fBnw_dst=\fIip\fR[\fB/\fInetmask\fR] +Matches IPv4 destination address \fIip\fR. + +.IP \fBnw_proto=\fIproto\fR +Matches IP protocol type \fIproto\fR, which should be specified as a +decimal number between 0 and 255, inclusive, e.g. 6 to match TCP +packets. + +.IP \fBnw_tos=\fItos/dscp\fR +Matches ToS/DSCP (only 6-bits, not modify reserved 2-bits for future +use) field of IPv4 header \fItos/dscp\fR, which should be specified as +a decimal number between 0 and 255, inclusive. + +.IP \fBtp_src=\fIport\fR +Matches UDP or TCP source port \fIport\fR, which should be specified +as a decimal number between 0 and 65535, inclusive, e.g. 80 to match +packets originating from a HTTP server. + +.IP \fBtp_dst=\fIport\fR +Matches UDP or TCP destination port \fIport\fR. + +.IP \fBicmp_type=\fItype\fR +Matches ICMP message with \fItype\fR, which should be specified as a decimal +number between 0 and 255, inclusive. + +.IP \fBicmp_code=\fIcode\fR +Matches ICMP messages with \fIcode\fR. + +.PP +The following shorthand notations are also available: + +.IP \fBip\fR +Same as \fBdl_type=0x0800\fR. + +.IP \fBicmp\fR +Same as \fBdl_type=0x0800,nw_proto=1\fR. + +.IP \fBtcp\fR +Same as \fBdl_type=0x0800,nw_proto=6\fR. + +.IP \fBudp\fR +Same as \fBdl_type=0x0800,nw_proto=17\fR. + +.IP \fBarp\fR +Same as \fBdl_type=0x0806\fR. + +.PP +The \fBadd-flow\fR and \fBadd-flows\fR commands require an additional field: + +.IP \fIactions\fB=\fItarget\fR[\fB,\fItarget\fR...]\fR +Specifies a comma-separated list of actions to take on a packet when the +flow entry matches. The \fItarget\fR may be a decimal port number +designating the physical port on which to output the packet, or one of +the following keywords: + +.RS +.IP \fBoutput\fR:\fIport\fR +Outputs the packet on the port specified by \fIport\fR. + +.IP \fBenqueue\fR:\fIport\fR:\fIq-id\fR +Enqueue the packet to the queue specified by \fIq-id\fR on the port +specified by \fIport\fR. See \fBadd-queue\fR and related commands +in this manpage above. + +.IP \fBnormal\fR +Subjects the packet to the device's normal L2/L3 processing. (This +action is not implemented by all OpenFlow switches.) + +.IP \fBflood\fR +Outputs the packet on all switch physical ports other than the port on +which it was received and any ports on which flooding is disabled +(typically, these would be ports disabled by the IEEE 802.1D spanning +tree protocol). + +.IP \fBall\fR +Outputs the packet on all switch physical ports other than the port on +which it was received. + +.IP \fBcontroller\fR:\fImax_len\fR +Sends the packet to the OpenFlow controller as a ``packet in'' +message. If \fImax_len\fR is a number, then it specifies the maximum +number of bytes that should be sent. If \fImax_len\fR is \fBALL\fR or +omitted, then the entire packet is sent. + +.IP \fBlocal\fR +Outputs the packet on the ``local port,'' which corresponds to the +\fBof\fIn\fR network device (see \fBCONTACTING THE CONTROLLER\fR in +\fBofprotocol\fR(8) for information on the \fBof\fIn\fR network device). + +.IP \fBmod_vlan_vid\fR:\fIvlan_vid\fR +Modifies the VLAN id on a packet. The VLAN tag is added or modified +as necessary to match the value specified. If the VLAN tag is added, +a priority of zero is used (see the \fBmod_vlan_pcp\fR action to set +this). + +.IP \fBmod_vlan_pcp\fR:\fIvlan_pcp\fR +Modifies the VLAN priority on a packet. The VLAN tag is added or modified +as necessary to match the value specified. Valid values are between 0 +(lowest) and 7 (highest). If the VLAN tag is added, a vid of zero is used +(see the \fBmod_vlan_vid\fR action to set this). + +.IP \fBmod_dl_dst\fR:\fIdst_mac\fR +Modifies the destination mac address on a packet, e.g., actions=mod_dl_dst:12:34:56:78:9a:bc + +.IP \fBmod_dl_src\fR:\fIsrc_mac\fR +Modifies the source mac address on a packet, e.g., actions=mod_dl_src:12:34:56:78:9a:bc + +.IP \fBmod_nw_tos\fR:\fItos/dscp\fR +Modifies the ToS/DSCP (only 6-bits, not modify reserved 2-bits for future use) field of IPv4 header on a packet. + +.IP \fBstrip_vlan\fR +Strips the VLAN tag from a packet if it is present. +.RE + +.IP +(The OpenFlow protocol supports other actions that \fBdpctl\fR does +not yet expose to the user.) + +.PP +The \fBadd-flow\fR, \fBadd-flows\fR, \fBdel-flows\fR, +and \fBdel-emerg-flows\fR commands support an additional optional field: + +.IP \fBpriority=\fIvalue\fR +Sets the priority of the flow to be added or deleted to \fIvalue\fR, +which should be a number between 0 and 65535, inclusive. If this +field is not specified, it defaults to 32768. + +.PP +The \fBadd-flow\fR and \fBadd-flows\fR commands support +additional optional fields: + +.TP +\fBidle_timeout=\fIseconds\fR +Causes the flow to expire after the given number of seconds of +inactivity. A value of 0 prevents a flow from expiring due to +inactivity. The default is 60 seconds. + +.IP \fBhard_timeout=\fIseconds\fR +Causes the flow to expire after the given number of seconds, +regardless of activity. A value of 0 (the default) gives the flow no +hard expiration deadline. + +.PP +The \fBdump-flows\fR, \fBdump-aggregate\fR and \fBdel-flows\fR +commands support the additional optional field: + +.TP +\fBout_port=\fIport\fR +If set, a matching flow must include an output action to \fIport\fR. + +.PP +\fBadd-flow\fR, \fBadd-flows\fR, \fBdel-flows\fR, \fBdump-flows\fR, +and \fBdump-aggregate\fR commands support the additional +optional field: + +.IP \fBtable=\fInumber\fR +If specified, limits the flows about which statistics are gathered to +those in the table with the given \fInumber\fR. Normal (non emergency) +tables are numbered as shown by the \fBdump-tables\fR command. + +If this field is not specified, or if \fInumber\fR is given as +\fB255\fR, statistics are gathered about flows from all normal (non +emergency) tables and flow manipulations are applied to notmal tables. + +If this field is given as \fB254\fR, statistics are gathered about +flows from emergency table and flow manipulations are applied to +emergency table. + +.SH OPTIONS +.TP +\fB--strict\fR +Uses strict matching when running flow modification commands. + +.TP +\fB-t\fR, \fB--timeout=\fIsecs\fR +Limits \fBdpctl\fR runtime to approximately \fIsecs\fR seconds. If +the timeout expires, \fBdpctl\fR will exit with a \fBSIGALRM\fR +signal. + +.TP +\fB-p\fR, \fB--private-key=\fIprivkey.pem\fR +Specifies a PEM file containing the private key used as the +identity for SSL connections to a switch. + +.TP +\fB-c\fR, \fB--certificate=\fIcert.pem\fR +Specifies a PEM file containing a certificate, signed by the +controller's certificate authority (CA), that certifies the +private key to identify a trustworthy controller. + +.TP +\fB-C\fR, \fB--ca-cert=\fIcacert.pem\fR +Specifies a PEM file containing the CA certificate used to verify that +a switch is trustworthy. + +.so lib/vlog.man +.so lib/common.man + +.SH EXAMPLES + +A typical dpctl command sequence for controlling an OpenFlow kernel module: +.nf +.TP +Create datapath numbered 0: + +.B % dpctl adddp nl:0 + +.TP +Add two network devices to the new datapath: + +.B % dpctl addif nl:0 eth0 +.B % dpctl addif nl:0 eth1 + +.TP +Monitor traffic received by the datapath (exit with control-C): + +.B % dpctl monitor nl:0 + + +.TP +View the datapath's table stats after some traffic has passed through: + +.B % dpctl dump-tables nl:0 + +.TP +View the flow entries in the datapath: + +.B % dpctl dump-flows nl:0 + +.TP +Remove network devices from the datapath when finished: + +.B % dpctl delif nl:0 eth0 +.B % dpctl delif nl:0 eth1 + +.TP +Delete the datapath: + +.B % dpctl deldp nl:0 +.fi +.SH "SEE ALSO" + +.BR ofprotocol (8), +.BR controller (8), +.BR ofdatapath (8), +.BR vlogconf (8) diff --git a/openflow/utilities/dpctl.c b/openflow/utilities/dpctl.c new file mode 100644 index 00000000..0406d9b5 --- /dev/null +++ b/openflow/utilities/dpctl.c @@ -0,0 +1,1772 @@ +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_NETLINK +#include "netdev.h" +#include "netlink.h" +#include "openflow/openflow-netlink.h" +#endif + +#include "command-line.h" +#include "compiler.h" +#include "dpif.h" +#include "openflow/nicira-ext.h" +#include "openflow/openflow-ext.h" +#include "ofp-print.h" +#include "ofpbuf.h" +#include "openflow/openflow.h" +#include "packets.h" +#include "random.h" +#include "socket-util.h" +#include "timeval.h" +#include "util.h" +#include "vconn-ssl.h" +#include "vconn.h" + +#include "xtoxll.h" +#include "ofpstat.h" +#include "openflow/private-ext.h" + +#include "vlog.h" +#define THIS_MODULE VLM_dpctl + +#define DEFAULT_IDLE_TIMEOUT 60 + +/* Maximum size of action buffer for adding and modify flows */ +#define MAX_ACT_LEN 60 + +#define MOD_PORT_CMD_UP "up" +#define MOD_PORT_CMD_DOWN "down" +#define MOD_PORT_CMD_FLOOD "flood" +#define MOD_PORT_CMD_NOFLOOD "noflood" + + +/* Settings that may be configured by the user. */ +struct settings { + bool strict; /* Use strict matching for flow mod commands */ +}; + +struct command { + const char *name; + int min_args; + int max_args; + void (*handler)(const struct settings *, int argc, char *argv[]); +}; + +static struct command all_commands[]; + +static void usage(void) NO_RETURN; +static void parse_options(int argc, char *argv[], struct settings *); + +int main(int argc, char *argv[]) +{ + struct settings s; + struct command *p; + + set_program_name(argv[0]); + time_init(); + vlog_init(); + parse_options(argc, argv, &s); + signal(SIGPIPE, SIG_IGN); + + argc -= optind; + argv += optind; + if (argc < 1) + ofp_fatal(0, "missing command name; use --help for help"); + + for (p = all_commands; p->name != NULL; p++) { + if (!strcmp(p->name, argv[0])) { + int n_arg = argc - 1; + if (n_arg < p->min_args) + ofp_fatal(0, "'%s' command requires at least %d arguments", + p->name, p->min_args); + else if (n_arg > p->max_args) + ofp_fatal(0, "'%s' command takes at most %d arguments", + p->name, p->max_args); + else { + p->handler(&s, argc, argv); + if (ferror(stdout)) { + ofp_fatal(0, "write to stdout failed"); + } + if (ferror(stderr)) { + ofp_fatal(0, "write to stderr failed"); + } + exit(0); + } + } + } + ofp_fatal(0, "unknown command '%s'; use --help for help", argv[0]); + + return 0; +} + +static void +parse_options(int argc, char *argv[], struct settings *s) +{ + enum { + OPT_STRICT = UCHAR_MAX + 1 + }; + static struct option long_options[] = { + {"timeout", required_argument, 0, 't'}, + {"verbose", optional_argument, 0, 'v'}, + {"strict", no_argument, 0, OPT_STRICT}, + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + VCONN_SSL_LONG_OPTIONS + {0, 0, 0, 0}, + }; + char *short_options = long_options_to_short_options(long_options); + + /* Set defaults that we can figure out before parsing options. */ + s->strict = false; + + for (;;) { + unsigned long int timeout; + int c; + + c = getopt_long(argc, argv, short_options, long_options, NULL); + if (c == -1) { + break; + } + + switch (c) { + case 't': + timeout = strtoul(optarg, NULL, 10); + if (timeout <= 0) { + ofp_fatal(0, "value %s on -t or --timeout is not at least 1", + optarg); + } else { + time_alarm(timeout); + } + break; + + case 'h': + usage(); + + case 'V': + printf("%s %s compiled "__DATE__" "__TIME__"\n", + program_name, VERSION BUILDNR); + exit(EXIT_SUCCESS); + + case 'v': + vlog_set_verbosity(optarg); + break; + + case OPT_STRICT: + s->strict = true; + break; + + VCONN_SSL_OPTION_HANDLERS + + case '?': + exit(EXIT_FAILURE); + + default: + abort(); + } + } + free(short_options); +} + +static void +usage(void) +{ + printf("%s: OpenFlow switch management utility\n" + "usage: %s [OPTIONS] COMMAND [ARG...]\n" +#ifdef HAVE_NETLINK + "\nFor local datapaths only:\n" + " adddp nl:DP_ID add a new local datapath DP_ID\n" + " deldp nl:DP_ID delete local datapath DP_ID\n" + " addif nl:DP_ID IFACE... add each IFACE as a port on DP_ID\n" + " delif nl:DP_ID IFACE... delete each IFACE from DP_ID\n" + " get-idx OF_DEV get datapath index for OF_DEV\n" +#endif + "\nFor local datapaths and remote switches:\n" + " show SWITCH show basic information\n" + " status SWITCH [KEY] report statistics (about KEY)\n" + " show-protostat SWITCH report protocol statistics\n" + " dump-desc SWITCH print switch description\n" + " dump-tables SWITCH print table stats\n" + " mod-port SWITCH IFACE ACT modify port behavior\n" + " dump-ports SWITCH [PORT] print port statistics\n" + " desc SWITCH STRING set switch description\n" + " dump-flows SWITCH print all flow entries\n" + " dump-flows SWITCH FLOW print matching FLOWs\n" + " dump-aggregate SWITCH print aggregate flow statistics\n" + " dump-aggregate SWITCH FLOW print aggregate stats for FLOWs\n" + " add-flow SWITCH FLOW add flow described by FLOW\n" + " add-flows SWITCH FILE add flows from FILE\n" + " mod-flows SWITCH FLOW modify actions of matching FLOWs\n" + " del-flows SWITCH [FLOW] delete matching FLOWs\n" + " monitor SWITCH print packets received from SWITCH\n" + " execute SWITCH CMD [ARG...] execute CMD with ARGS on SWITCH\n" + "Queue Ops: Q: queue-id; P: port-id; BW: perthousand bandwidth\n" + " add-queue SWITCH P Q [BW] add queue (with min bandwidth)\n" + " mod-queue SWITCH P Q BW modify queue min bandwidth\n" + " del-queue SWITCH P Q delete queue\n" + " dump-queue SWITCH [P [Q]] show queue info\n" + "\nFor local datapaths, remote switches, and controllers:\n" + " probe VCONN probe whether VCONN is up\n" + " ping VCONN [N] latency of N-byte echos\n" + " benchmark VCONN N COUNT bandwidth of COUNT N-byte echos\n" + "where each SWITCH is an active OpenFlow connection method.\n", + program_name, program_name); + vconn_usage(true, false, false); + vlog_usage(); + printf("\nOther options:\n" + " --strict use strict match for flow commands\n" + " -t, --timeout=SECS give up after SECS seconds\n" + " -h, --help display this help message\n" + " -V, --version display version information\n"); + exit(EXIT_SUCCESS); +} + +static void run(int retval, const char *message, ...) + PRINTF_FORMAT(2, 3); + +static void run(int retval, const char *message, ...) +{ + if (retval) { + va_list args; + + fprintf(stderr, "%s: ", program_name); + va_start(args, message); + vfprintf(stderr, message, args); + va_end(args); + if (retval == EOF) { + fputs(": unexpected end of file\n", stderr); + } else { + fprintf(stderr, ": %s\n", strerror(retval)); + } + + exit(EXIT_FAILURE); + } +} + +#ifdef HAVE_NETLINK +/* Netlink-only commands. */ + +static int if_up(const char *netdev_name) +{ + struct netdev *netdev; + int retval; + + retval = netdev_open(netdev_name, NETDEV_ETH_TYPE_NONE, &netdev); + if (!retval) { + retval = netdev_turn_flags_on(netdev, NETDEV_UP, true); + netdev_close(netdev); + } + return retval; +} + +static void +do_get_idx(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) +{ + int dp_idx; + + struct dpif dpif; + run(dpif_open(-1, &dpif), "opening management socket"); + dp_idx = dpif_get_idx(argv[1]); + if (dp_idx == -1) { + dpif_close(&dpif); + ofp_fatal(0, "unknown OpenFlow device: %s", argv[1]); + } + printf("%d\n", dp_idx); + dpif_close(&dpif); +} + +static int +get_dp_idx(const char *name) +{ + if (strncmp(name, "nl:", 3) + || strlen(name) < 4 + || name[strspn(name + 3, "0123456789") + 3]) { + ofp_fatal(0, "%s: argument is not of the form \"nl:DP_ID\"", name); + } + return atoi(name + 3); +} + +static void +do_add_dp(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) +{ + struct dpif dpif; + run(dpif_open(-1, &dpif), "opening management socket"); + run(dpif_add_dp(&dpif, get_dp_idx(argv[1]), NULL), "add_dp"); + dpif_close(&dpif); +} + +static void +do_del_dp(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) +{ + struct dpif dpif; + run(dpif_open(-1, &dpif), "opening management socket"); + run(dpif_del_dp(&dpif, get_dp_idx(argv[1]), NULL), "del_dp"); + dpif_close(&dpif); +} + +static void add_del_ports(int argc UNUSED, char *argv[], + int (*function)(struct dpif *, int dp_idx, + const char *netdev), + const char *operation, const char *preposition) +{ + bool failure = false; + struct dpif dpif; + int dp_idx; + int i; + + run(dpif_open(-1, &dpif), "opening management socket"); + dp_idx = get_dp_idx(argv[1]); + for (i = 2; i < argc; i++) { + int retval = function(&dpif, dp_idx, argv[i]); + if (retval) { + ofp_error(retval, "failed to %s %s %s %s", + operation, argv[i], preposition, argv[1]); + failure = true; + } + } + dpif_close(&dpif); + if (failure) { + exit(EXIT_FAILURE); + } +} + +static int ifup_and_add_port(struct dpif *dpif, int dp_idx, const char *netdev) +{ + int retval = if_up(netdev); + return retval ? retval : dpif_add_port(dpif, dp_idx, netdev); +} + +static void do_add_port(const struct settings *s UNUSED, int argc UNUSED, + char *argv[]) +{ + add_del_ports(argc, argv, ifup_and_add_port, "add", "to"); +} + +static void do_del_port(const struct settings *s UNUSED, int argc UNUSED, + char *argv[]) +{ + add_del_ports(argc, argv, dpif_del_port, "remove", "from"); +} +#endif /* HAVE_NETLINK */ + +/* Generic commands. */ + +static void +open_vconn(const char *name, struct vconn **vconnp) +{ + run(vconn_open_block(name, OFP_VERSION, vconnp), "connecting to %s", name); +} + +static void * +alloc_stats_request(size_t body_len, uint16_t type, struct ofpbuf **bufferp) +{ + struct ofp_stats_request *rq; + rq = make_openflow((offsetof(struct ofp_stats_request, body) + + body_len), OFPT_STATS_REQUEST, bufferp); + rq->type = htons(type); + rq->flags = htons(0); + return rq->body; +} + +static void +send_openflow_buffer(struct vconn *vconn, struct ofpbuf *buffer) +{ + update_openflow_length(buffer); + run(vconn_send_block(vconn, buffer), "failed to send packet to switch"); +} + +static void +dump_transaction(const char *vconn_name, struct ofpbuf *request) +{ + struct vconn *vconn; + struct ofpbuf *reply; + + update_openflow_length(request); + open_vconn(vconn_name, &vconn); + run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name); + ofp_print(stdout, reply->data, reply->size, 1); + vconn_close(vconn); +} + +static void +dump_trivial_transaction(const char *vconn_name, uint8_t request_type) +{ + struct ofpbuf *request; + make_openflow(sizeof(struct ofp_header), request_type, &request); + dump_transaction(vconn_name, request); +} + +static void +dump_stats_transaction(const char *vconn_name, struct ofpbuf *request) +{ + uint32_t send_xid = ((struct ofp_header *) request->data)->xid; + struct vconn *vconn; + bool done = false; + + open_vconn(vconn_name, &vconn); + send_openflow_buffer(vconn, request); + while (!done) { + uint32_t recv_xid; + struct ofpbuf *reply; + + run(vconn_recv_block(vconn, &reply), "OpenFlow packet receive failed"); + + recv_xid = ((struct ofp_header *) reply->data)->xid; + if (send_xid == recv_xid) { + struct ofp_stats_reply *osr; + + ofp_print(stdout, reply->data, reply->size, 1); + + osr = ofpbuf_at(reply, 0, sizeof *osr); + done = !osr || !(ntohs(osr->flags) & OFPSF_REPLY_MORE); + } else { + VLOG_DBG("received reply with xid %08"PRIx32" " + "!= expected %08"PRIx32, recv_xid, send_xid); + } + ofpbuf_delete(reply); + } + vconn_close(vconn); +} + +static void +dump_trivial_stats_transaction(const char *vconn_name, uint8_t stats_type) +{ + struct ofpbuf *request; + alloc_stats_request(0, stats_type, &request); + dump_stats_transaction(vconn_name, request); +} + +/* Get the pointer to struct member based on member offset */ +#define S_PTR(_ptr, _type, _member) \ + ((void *)(((char *)(_ptr)) + offsetof(_type, _member))) + +static void +dump_queue_stats_transaction(const char *vconn_name, uint8_t stats_type, + uint16_t port, uint32_t q_id) +{ + struct ofpbuf *request; + struct ofp_queue_stats_request *q_req; + struct ofp_stats_request *stats_req; + + alloc_stats_request(sizeof(struct ofp_queue_stats_request), + stats_type, &request); + stats_req = request->data; + q_req = S_PTR(stats_req, struct ofp_stats_request, body); + + q_req->port_no = htons(port); + q_req->queue_id = htonl(q_id); + dump_stats_transaction(vconn_name, request); +} + +static void +do_show(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) +{ + dump_trivial_transaction(argv[1], OFPT_FEATURES_REQUEST); + dump_trivial_transaction(argv[1], OFPT_GET_CONFIG_REQUEST); +} + +static void +do_status(const struct settings *s UNUSED, int argc, char *argv[]) +{ + struct nicira_header *request, *reply; + struct vconn *vconn; + struct ofpbuf *b; + + request = make_openflow(sizeof *request, OFPT_VENDOR, &b); + request->vendor = htonl(NX_VENDOR_ID); + request->subtype = htonl(NXT_STATUS_REQUEST); + if (argc > 2) { + ofpbuf_put(b, argv[2], strlen(argv[2])); + } + open_vconn(argv[1], &vconn); + run(vconn_transact(vconn, b, &b), "talking to %s", argv[1]); + vconn_close(vconn); + + if (b->size < sizeof *reply) { + ofp_fatal(0, "short reply (%zu bytes)", b->size); + } + reply = b->data; + if (reply->header.type != OFPT_VENDOR + || reply->vendor != ntohl(NX_VENDOR_ID) + || reply->subtype != ntohl(NXT_STATUS_REPLY)) { + ofp_print(stderr, b->data, b->size, 2); + ofp_fatal(0, "bad reply"); + } + + fwrite(reply + 1, b->size, 1, stdout); +} + +static void +print_protocol_stat(struct ofpstat *ofps_rcvd, struct ofpstat *ofps_sent) +{ + int i; + struct ofpstat *ifps = NULL; +#define PREFIX_STR " " +#define PREFIX_RCVD "Rcvd: " +#define PREFIX_SENT "Sent: " + + fprintf(stdout, + "OpenFlow protocol version 0x%x statisical information\n", + OFP_VERSION); + fprintf(stdout, "\n"); + + fprintf(stdout, "Protocol message:\n"); + for (i = 0; i < 2; ++i) { + ifps = i == 0 ? ofps_rcvd : ofps_sent; + fprintf(stdout, + "%s" + "%"PRIu64" total msgs, %"PRIu64" unknown msgs\n", + i == 0 ? PREFIX_RCVD : PREFIX_SENT, + ntohll(ifps->ofps_total), + ntohll(ifps->ofps_unknown)); + fprintf(stdout, + PREFIX_STR + "%"PRIu64" hello, %"PRIu64" errors, " + "%"PRIu64" echo, %"PRIu64" echo reply, " + "%"PRIu64" vendor\n", + ntohll(ifps->ofps_hello), + ntohll(ifps->ofps_error), + ntohll(ifps->ofps_echo_request), + ntohll(ifps->ofps_echo_reply), + ntohll(ifps->ofps_vendor)); + fprintf(stdout, + PREFIX_STR + "%"PRIu64" feats, %"PRIu64" feats reply\n", + ntohll(ifps->ofps_feats_request), + ntohll(ifps->ofps_feats_reply)); + fprintf(stdout, + PREFIX_STR + "%"PRIu64" get config, %"PRIu64" get config reply, " + "%"PRIu64" set config\n", + ntohll(ifps->ofps_get_config_request), + ntohll(ifps->ofps_get_config_reply), + ntohll(ifps->ofps_set_config)); + fprintf(stdout, + PREFIX_STR + "%"PRIu64" packet in, %"PRIu64" flow removed, " + "%"PRIu64" port status\n", + ntohll(ifps->ofps_packet_in), + ntohll(ifps->ofps_flow_removed), + ntohll(ifps->ofps_port_status)); + fprintf(stdout, + PREFIX_STR + "%"PRIu64" packet out, %"PRIu64" flow mod, %"PRIu64" port mod\n", + ntohll(ifps->ofps_packet_out), + ntohll(ifps->ofps_flow_mod), + ntohll(ifps->ofps_port_mod)); + fprintf(stdout, + PREFIX_STR + "%"PRIu64" stats, %"PRIu64" stats reply, " + "%"PRIu64" barrier, %"PRIu64" barrier reply\n", + ntohll(ifps->ofps_stats_request), + ntohll(ifps->ofps_stats_reply), + ntohll(ifps->ofps_barrier_request), + ntohll(ifps->ofps_barrier_reply)); + } + fprintf(stdout, "\n"); + + fprintf(stdout, "Flow manipulation:\n"); + for (i = 0; i < 2; ++i) { + ifps = i == 0 ? ofps_rcvd : ofps_sent; + fprintf(stdout, + "%s" + "%"PRIu64" add, %"PRIu64" modify, %"PRIu64" modify strict\n", + i == 0 ? PREFIX_RCVD : PREFIX_SENT, + ntohll(ifps->ofps_flow_mod_ops.add), + ntohll(ifps->ofps_flow_mod_ops.modify), + ntohll(ifps->ofps_flow_mod_ops.modify_strict)); + fprintf(stdout, + PREFIX_STR + "%"PRIu64" delete, %"PRIu64" delete strict, %"PRIu64" unknown cmd\n", + ntohll(ifps->ofps_flow_mod_ops.delete), + ntohll(ifps->ofps_flow_mod_ops.delete_strict), + ntohll(ifps->ofps_flow_mod_ops.unknown)); + } + fprintf(stdout, "\n"); + + fprintf(stdout, "Error notification:\n"); + for (i = 0; i < 2; ++i) { + ifps = i == 0 ? ofps_rcvd : ofps_sent; + fprintf(stdout, + "%s" + "%"PRIu64" hello fail: %"PRIu64" incompat, %"PRIu64" eperm\n", + i == 0 ? PREFIX_RCVD : PREFIX_SENT, + ntohll(ifps->ofps_error_type.hello_fail), + ntohll(ifps->ofps_error_code.hf_incompat), + ntohll(ifps->ofps_error_code.hf_eperm)); + fprintf(stdout, + PREFIX_STR + "%"PRIu64" bad request: %"PRIu64" version, %"PRIu64" type, " + "%"PRIu64" stat, %"PRIu64" vendor\n" + PREFIX_STR + " %"PRIu64" eperm\n", + ntohll(ifps->ofps_error_type.bad_request), + ntohll(ifps->ofps_error_code.br_bad_version), + ntohll(ifps->ofps_error_code.br_bad_type), + ntohll(ifps->ofps_error_code.br_bad_stat), + ntohll(ifps->ofps_error_code.br_bad_vendor), + ntohll(ifps->ofps_error_code.br_eperm)); + fprintf(stdout, + PREFIX_STR + "%"PRIu64" bad action: %"PRIu64" type, %"PRIu64" len, " + "%"PRIu64" vendor, %"PRIu64" vendor type\n" + PREFIX_STR + " %"PRIu64" out port, %"PRIu64" argument, %"PRIu64" eperm\n", + ntohll(ifps->ofps_error_type.bad_action), + ntohll(ifps->ofps_error_code.ba_bad_type), + ntohll(ifps->ofps_error_code.ba_bad_len), + ntohll(ifps->ofps_error_code.ba_bad_vendor), + ntohll(ifps->ofps_error_code.ba_bad_vendor_type), + ntohll(ifps->ofps_error_code.ba_bad_out_port), + ntohll(ifps->ofps_error_code.ba_bad_argument), + ntohll(ifps->ofps_error_code.ba_eperm)); + fprintf(stdout, + PREFIX_STR + "%"PRIu64" flow mod fail: %"PRIu64" all tables full, " + "%"PRIu64" overlap, %"PRIu64" eperm, %"PRIu64" emerg\n", + ntohll(ifps->ofps_error_type.flow_mod_fail), + ntohll(ifps->ofps_error_code.fmf_all_tables_full), + ntohll(ifps->ofps_error_code.fmf_overlap), + ntohll(ifps->ofps_error_code.fmf_eperm), + ntohll(ifps->ofps_error_code.fmf_emerg)); + fprintf(stdout, + PREFIX_STR + "%"PRIu64" unknown type, %"PRIu64" unknown code\n", + ntohll(ifps->ofps_error_type.unknown), + ntohll(ifps->ofps_error_code.unknown)); + } + fprintf(stdout, "\n"); +} + +static void +do_protostat(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) +{ + struct ofpbuf *buf; + struct private_vxhdr *vxhdr; + struct private_vxopt *vxopt; + struct vconn *vconn; + struct ofpstat* ofps; + + vxhdr = make_openflow(sizeof(*vxhdr) + sizeof(*vxopt), OFPT_VENDOR, &buf); + vxopt = (struct private_vxopt *)(vxhdr + 1); + vxhdr->ofp_vxid = htonl(PRIVATE_VENDOR_ID); + vxopt->pvo_type = htons(PRIVATEOPT_PROTOCOL_STATS_REQUEST); + vxopt->pvo_len = 0; + + open_vconn(argv[1], &vconn); + run(vconn_transact(vconn, buf, &buf), "talking to %s", argv[1]); + vconn_close(vconn); + if (buf->size < sizeof(*vxhdr)) { + ofp_fatal(0, "short reply (%zu bytes)", buf->size); + } + + vxhdr = buf->data; + if (vxhdr->ofp_hdr.type != OFPT_VENDOR + || ntohl(vxhdr->ofp_vxid) != PRIVATE_VENDOR_ID) { + ofp_print(stderr, buf->data, buf->size, 2); + ofp_fatal(0, "bad reply"); + } + vxopt = (struct private_vxopt *)(vxhdr + 1); + if (ntohs(vxopt->pvo_type) != PRIVATEOPT_PROTOCOL_STATS_REPLY + || ntohs(vxopt->pvo_len) != (sizeof(*ofps) * 2)) { + ofp_print(stderr, buf->data, buf->size, 2); + ofp_fatal(0, "bad reply"); + } + + ofps = (struct ofpstat *)(vxopt + 1); + print_protocol_stat(ofps, ofps + 1); +} + +static void +do_dump_desc(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) +{ + dump_trivial_stats_transaction(argv[1], OFPST_DESC); +} + +static void +do_dump_tables(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) +{ + dump_trivial_stats_transaction(argv[1], OFPST_TABLE); +} + +static uint32_t +str_to_u32(const char *str) +{ + char *tail; + uint32_t value; + + errno = 0; + value = strtoul(str, &tail, 0); + if (errno == EINVAL || errno == ERANGE || *tail) { + ofp_fatal(0, "invalid numeric format %s", str); + } + return value; +} + +static void +str_to_mac(const char *str, uint8_t mac[6]) +{ + if (sscanf(str, "%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8, + &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]) != 6) { + ofp_fatal(0, "invalid mac address %s", str); + } +} + +static uint32_t +str_to_ip(const char *str_, uint32_t *ip) +{ + char *str = xstrdup(str_); + char *save_ptr = NULL; + const char *name, *netmask; + struct in_addr in_addr; + int n_wild, retval; + + name = strtok_r(str, "//", &save_ptr); + retval = name ? lookup_ip(name, &in_addr) : EINVAL; + if (retval) { + ofp_fatal(0, "%s: could not convert to IP address", str); + } + *ip = in_addr.s_addr; + + netmask = strtok_r(NULL, "//", &save_ptr); + if (netmask) { + uint8_t o[4]; + if (sscanf(netmask, "%"SCNu8".%"SCNu8".%"SCNu8".%"SCNu8, + &o[0], &o[1], &o[2], &o[3]) == 4) { + uint32_t nm = (o[0] << 24) | (o[1] << 16) | (o[2] << 8) | o[3]; + int i; + + /* Find first 1-bit. */ + for (i = 0; i < 32; i++) { + if (nm & (1u << i)) { + break; + } + } + n_wild = i; + + /* Verify that the rest of the bits are 1-bits. */ + for (; i < 32; i++) { + if (!(nm & (1u << i))) { + ofp_fatal(0, "%s: %s is not a valid netmask", + str, netmask); + } + } + } else { + int prefix = atoi(netmask); + if (prefix <= 0 || prefix > 32) { + ofp_fatal(0, "%s: network prefix bits not between 1 and 32", + str); + } + n_wild = 32 - prefix; + } + } else { + n_wild = 0; + } + + free(str); + return n_wild; +} + +static void * +put_action(struct ofpbuf *b, size_t size, uint16_t type) +{ + struct ofp_action_header *ah = ofpbuf_put_zeros(b, size); + ah->type = htons(type); + ah->len = htons(size); + return ah; +} + +static struct ofp_action_output * +put_output_action(struct ofpbuf *b, uint16_t port) +{ + struct ofp_action_output *oao = put_action(b, sizeof *oao, OFPAT_OUTPUT); + oao->port = htons(port); + return oao; +} + +static struct ofp_action_enqueue * +put_enqueue_action(struct ofpbuf *b, uint16_t port, uint32_t queue) +{ + struct ofp_action_enqueue *oao; + + oao = put_action(b, sizeof *oao, OFPAT_ENQUEUE); + oao->len = htons(sizeof(*oao)); + oao->port = htons(port); + oao->queue_id = htonl(queue); + return oao; +} + +static void +str_to_action(char *str, struct ofpbuf *b) +{ + char *act, *arg, *arg2; + char *saveptr = NULL; + + for (act = strtok_r(str, ", \t\r\n", &saveptr); act; + act = strtok_r(NULL, ", \t\r\n", &saveptr)) + { + /* Arguments are separated by colons */ + arg = strchr(act, ':'); + if (arg) { + *arg = '\0'; + arg++; + } + + if (!strcasecmp(act, "mod_nw_tos")) { + struct ofp_action_nw_tos *va; + va = put_action(b, sizeof *va, OFPAT_SET_NW_TOS); + va->nw_tos = str_to_u32(arg); + } else if (!strcasecmp(act, "mod_vlan_vid")) { + struct ofp_action_vlan_vid *va; + va = put_action(b, sizeof *va, OFPAT_SET_VLAN_VID); + va->vlan_vid = htons(str_to_u32(arg)); + } else if (!strcasecmp(act, "mod_vlan_pcp")) { + struct ofp_action_vlan_pcp *va; + va = put_action(b, sizeof *va, OFPAT_SET_VLAN_PCP); + va->vlan_pcp = str_to_u32(arg); + } else if (!strcasecmp(act, "mod_dl_dst")) { + struct ofp_action_dl_addr *va; + va = put_action(b, sizeof *va, OFPAT_SET_DL_DST); + str_to_mac(arg, va->dl_addr); + } else if (!strcasecmp(act, "mod_dl_src")) { + struct ofp_action_dl_addr *va; + va = put_action(b, sizeof *va, OFPAT_SET_DL_SRC); + str_to_mac(arg, va->dl_addr); + } else if (!strcasecmp(act, "strip_vlan")) { + struct ofp_action_header *ah; + ah = put_action(b, sizeof *ah, OFPAT_STRIP_VLAN); + ah->type = htons(OFPAT_STRIP_VLAN); + } else if (!strcasecmp(act, "enqueue")) { + arg2 = strchr(arg, ':'); + if (arg2) { + *arg2 = '\0'; + arg2++; + } + put_enqueue_action(b, str_to_u32(arg), str_to_u32(arg2)); + } else if (!strcasecmp(act, "output")) { + put_output_action(b, str_to_u32(arg)); + } else if (!strcasecmp(act, "TABLE")) { + put_output_action(b, OFPP_TABLE); + } else if (!strcasecmp(act, "NORMAL")) { + put_output_action(b, OFPP_NORMAL); + } else if (!strcasecmp(act, "FLOOD")) { + put_output_action(b, OFPP_FLOOD); + } else if (!strcasecmp(act, "ALL")) { + put_output_action(b, OFPP_ALL); + } else if (!strcasecmp(act, "CONTROLLER")) { + struct ofp_action_output *oao; + oao = put_output_action(b, OFPP_CONTROLLER); + + /* Unless a numeric argument is specified, we send the whole + * packet to the controller. */ + if (arg && (strspn(act, "0123456789") == strlen(act))) { + oao->max_len = htons(str_to_u32(arg)); + } + } else if (!strcasecmp(act, "LOCAL")) { + put_output_action(b, OFPP_LOCAL); + } else if (strspn(act, "0123456789") == strlen(act)) { + put_output_action(b, str_to_u32(act)); + } else { + ofp_fatal(0, "Unknown action: %s", act); + } + } +} + +struct protocol { + const char *name; + uint16_t dl_type; + uint8_t nw_proto; +}; + +static bool +parse_protocol(const char *name, const struct protocol **p_out) +{ + static const struct protocol protocols[] = { + { "ip", ETH_TYPE_IP, 0 }, + { "arp", ETH_TYPE_ARP, 0 }, + { "icmp", ETH_TYPE_IP, IP_TYPE_ICMP }, + { "tcp", ETH_TYPE_IP, IP_TYPE_TCP }, + { "udp", ETH_TYPE_IP, IP_TYPE_UDP }, + }; + const struct protocol *p; + + for (p = protocols; p < &protocols[ARRAY_SIZE(protocols)]; p++) { + if (!strcmp(p->name, name)) { + *p_out = p; + return true; + } + } + *p_out = NULL; + return false; +} + +struct field { + const char *name; + uint32_t wildcard; + enum { F_U8, F_U16, F_MAC, F_IP } type; + size_t offset, shift; +}; + +static bool +parse_field(const char *name, const struct field **f_out) +{ +#define F_OFS(MEMBER) offsetof(struct ofp_match, MEMBER) + static const struct field fields[] = { + { "in_port", OFPFW_IN_PORT, F_U16, F_OFS(in_port), 0 }, + { "dl_vlan", OFPFW_DL_VLAN, F_U16, F_OFS(dl_vlan), 0 }, + { "dl_vlan_pcp", OFPFW_DL_VLAN_PCP, F_U8, F_OFS(dl_vlan_pcp), 0 }, + { "dl_src", OFPFW_DL_SRC, F_MAC, F_OFS(dl_src), 0 }, + { "dl_dst", OFPFW_DL_DST, F_MAC, F_OFS(dl_dst), 0 }, + { "dl_type", OFPFW_DL_TYPE, F_U16, F_OFS(dl_type), 0 }, + { "nw_tos", OFPFW_NW_TOS, F_U8, F_OFS(nw_tos), 0 }, + { "nw_proto", OFPFW_NW_PROTO, F_U8, F_OFS(nw_proto), 0 }, + { "nw_src", OFPFW_NW_SRC_MASK, F_IP, + F_OFS(nw_src), OFPFW_NW_SRC_SHIFT }, + { "nw_dst", OFPFW_NW_DST_MASK, F_IP, + F_OFS(nw_dst), OFPFW_NW_DST_SHIFT }, + { "tp_src", OFPFW_TP_SRC, F_U16, F_OFS(tp_src), 0 }, + { "tp_dst", OFPFW_TP_DST, F_U16, F_OFS(tp_dst), 0 }, + { "icmp_type", OFPFW_ICMP_TYPE, F_U16, F_OFS(icmp_type), 0 }, + { "icmp_code", OFPFW_ICMP_CODE, F_U16, F_OFS(icmp_code), 0 } + }; + const struct field *f; + + for (f = fields; f < &fields[ARRAY_SIZE(fields)]; f++) { + if (!strcmp(f->name, name)) { + *f_out = f; + return true; + } + } + *f_out = NULL; + return false; +} + +static void +str_to_flow(char *string, struct ofp_match *match, struct ofpbuf *actions, + uint8_t *table_idx, uint16_t *out_port, uint16_t *priority, + uint16_t *idle_timeout, uint16_t *hard_timeout, + uint64_t *cookie) +{ + char *save_ptr = NULL; + char *name; + uint32_t wildcards; + + if (table_idx) { + *table_idx = 0xff; + } + if (out_port) { + *out_port = OFPP_NONE; + } + if (priority) { + *priority = OFP_DEFAULT_PRIORITY; + } + if (idle_timeout) { + *idle_timeout = DEFAULT_IDLE_TIMEOUT; + } + if (hard_timeout) { + *hard_timeout = OFP_FLOW_PERMANENT; + } + if (cookie) { + *cookie = 0; + } + if (actions) { + char *act_str = strstr(string, "actions"); + if (!act_str) { + ofp_fatal(0, "must specify an action"); + } + *(act_str-1) = '\0'; + + act_str = strchr(act_str, '='); + if (!act_str) { + ofp_fatal(0, "must specify an action"); + } + + act_str++; + + str_to_action(act_str, actions); + } + memset(match, 0, sizeof *match); + wildcards = OFPFW_ALL; + for (name = strtok_r(string, "=, \t\r\n", &save_ptr); name; + name = strtok_r(NULL, "=, \t\r\n", &save_ptr)) { + const struct protocol *p; + + if (parse_protocol(name, &p)) { + wildcards &= ~OFPFW_DL_TYPE; + match->dl_type = htons(p->dl_type); + if (p->nw_proto) { + wildcards &= ~OFPFW_NW_PROTO; + match->nw_proto = p->nw_proto; + } + } else { + const struct field *f; + char *value; + + value = strtok_r(NULL, ", \t\r\n", &save_ptr); + if (!value) { + ofp_fatal(0, "field %s missing value", name); + } + + if (table_idx && !strcmp(name, "table")) { + *table_idx = atoi(value); + } else if (out_port && !strcmp(name, "out_port")) { + *out_port = atoi(value); + } else if (priority && !strcmp(name, "priority")) { + *priority = atoi(value); + } else if (idle_timeout && !strcmp(name, "idle_timeout")) { + *idle_timeout = atoi(value); + } else if (hard_timeout && !strcmp(name, "hard_timeout")) { + *hard_timeout = atoi(value); + } else if (cookie && !strcmp(name, "cookie")) { + *cookie = atoi(value); + } else if (parse_field(name, &f)) { + void *data = (char *) match + f->offset; + if (!strcmp(value, "*") || !strcmp(value, "ANY")) { + wildcards |= f->wildcard; + } else { + wildcards &= ~f->wildcard; + if (f->type == F_U8) { + *(uint8_t *) data = str_to_u32(value); + } else if (f->type == F_U16) { + *(uint16_t *) data = htons(str_to_u32(value)); + } else if (f->type == F_MAC) { + str_to_mac(value, data); + } else if (f->type == F_IP) { + wildcards |= str_to_ip(value, data) << f->shift; + } else { + NOT_REACHED(); + } + } + } else { + ofp_fatal(0, "unknown keyword %s", name); + } + } + } + match->wildcards = htonl(wildcards); +} + +static void +do_desc(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) +{ + struct vconn * vconn; + struct ofpbuf * msg; + struct openflow_ext_set_dp_desc * desc; + + msg = ofpbuf_new(sizeof(*desc)); + ofpbuf_put_uninit(msg, sizeof(*desc)); + desc = ofpbuf_at_assert(msg, 0, sizeof(*desc)); + desc->header.header.version = OFP_VERSION; + desc->header.header.type = OFPT_VENDOR; + desc->header.header.length = htons(sizeof(*desc)); + desc->header.vendor = htonl(OPENFLOW_VENDOR_ID); + desc->header.subtype = htonl(OFP_EXT_SET_DESC); + strncpy(desc->dp_desc, argv[2], DESC_STR_LEN); + + open_vconn(argv[1], &vconn); + send_openflow_buffer(vconn, msg); + vconn_close(vconn); +} + +static void +do_dump_flows(const struct settings *s UNUSED, int argc, char *argv[]) +{ + struct ofp_flow_stats_request *req; + uint16_t out_port; + struct ofpbuf *request; + + req = alloc_stats_request(sizeof *req, OFPST_FLOW, &request); + str_to_flow(argc > 2 ? argv[2] : "", &req->match, NULL, + &req->table_id, &out_port, NULL, NULL, NULL, NULL); + memset(&req->pad, 0, sizeof req->pad); + req->out_port = htons(out_port); + + dump_stats_transaction(argv[1], request); +} + +static void +do_dump_aggregate(const struct settings *s UNUSED, int argc, char *argv[]) +{ + struct ofp_aggregate_stats_request *req; + struct ofpbuf *request; + uint16_t out_port; + + req = alloc_stats_request(sizeof *req, OFPST_AGGREGATE, &request); + str_to_flow(argc > 2 ? argv[2] : "", &req->match, NULL, + &req->table_id, &out_port, NULL, NULL, NULL, NULL); + memset(&req->pad, 0, sizeof req->pad); + req->out_port = htons(out_port); + + dump_stats_transaction(argv[1], request); +} + +#define EMERG_TABLE_ID 0xfe + +static void +do_add_flow(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) +{ + struct vconn *vconn; + struct ofpbuf *buffer; + struct ofp_flow_mod *ofm; + uint16_t priority, idle_timeout, hard_timeout; + uint64_t cookie; + uint8_t table_id; + struct ofp_match match; + + /* Parse and send. str_to_flow() will expand and reallocate the data in + * 'buffer', so we can't keep pointers to across the str_to_flow() call. */ + make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer); + str_to_flow(argv[2], &match, buffer, + &table_id, NULL, &priority, &idle_timeout, &hard_timeout, + &cookie); + ofm = buffer->data; + ofm->match = match; + ofm->command = htons(OFPFC_ADD); + ofm->cookie = htonll(cookie); + ofm->idle_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(idle_timeout); + ofm->hard_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(hard_timeout); + ofm->buffer_id = htonl(UINT32_MAX); + ofm->priority = htons(priority); + ofm->flags = htons(OFPFF_SEND_FLOW_REM); + if (table_id == EMERG_TABLE_ID) + ofm->flags |= htons(OFPFF_EMERG); + + open_vconn(argv[1], &vconn); + send_openflow_buffer(vconn, buffer); + vconn_close(vconn); +} + +static void +do_add_flows(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) +{ + struct vconn *vconn; + FILE *file; + char line[1024]; + + file = fopen(argv[2], "r"); + if (file == NULL) { + ofp_fatal(errno, "%s: open", argv[2]); + } + + open_vconn(argv[1], &vconn); + while (fgets(line, sizeof line, file)) { + struct ofpbuf *buffer; + struct ofp_flow_mod *ofm; + uint16_t priority, idle_timeout, hard_timeout; + uint64_t cookie; + uint8_t table_id; + struct ofp_match match; + + char *comment; + + /* Delete comments. */ + comment = strchr(line, '#'); + if (comment) { + *comment = '\0'; + } + + /* Drop empty lines. */ + if (line[strspn(line, " \t\n")] == '\0') { + continue; + } + + /* Parse and send. str_to_flow() will expand and reallocate the data + * in 'buffer', so we can't keep pointers to across the str_to_flow() + * call. */ + ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer); + str_to_flow(line, &match, buffer, + &table_id, NULL, &priority, &idle_timeout, &hard_timeout, + &cookie); + ofm = buffer->data; + ofm->match = match; + ofm->command = htons(OFPFC_ADD); + ofm->cookie = htonll(cookie); + ofm->idle_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(idle_timeout); + ofm->hard_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(hard_timeout); + ofm->buffer_id = htonl(UINT32_MAX); + ofm->priority = htons(priority); + ofm->flags = htons(OFPFF_SEND_FLOW_REM); + if (table_id == EMERG_TABLE_ID) + ofm->flags |= htons(OFPFF_EMERG); + + send_openflow_buffer(vconn, buffer); + } + vconn_close(vconn); + fclose(file); +} + +static void +do_mod_flows(const struct settings *s, int argc UNUSED, char *argv[]) +{ + uint16_t priority, idle_timeout, hard_timeout; + uint64_t cookie; + uint8_t table_id; + struct vconn *vconn; + struct ofpbuf *buffer; + struct ofp_flow_mod *ofm; + + /* Parse and send. */ + ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer); + str_to_flow(argv[2], &ofm->match, buffer, + &table_id, NULL, &priority, &idle_timeout, &hard_timeout, + &cookie); + if (s->strict) { + ofm->command = htons(OFPFC_MODIFY_STRICT); + } else { + ofm->command = htons(OFPFC_MODIFY); + } + ofm->cookie = htonll(cookie); + ofm->idle_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(idle_timeout); + ofm->hard_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(hard_timeout); + ofm->buffer_id = htonl(UINT32_MAX); + if (table_id == EMERG_TABLE_ID) + ofm->flags = htons(OFPFF_EMERG); + ofm->priority = htons(priority); + + open_vconn(argv[1], &vconn); + send_openflow_buffer(vconn, buffer); + vconn_close(vconn); +} + +static void do_del_flows(const struct settings *s, int argc, char *argv[]) +{ + struct vconn *vconn; + uint16_t priority; + uint16_t out_port; + uint8_t table_id; + struct ofpbuf *buffer; + struct ofp_flow_mod *ofm; + + /* Parse and send. */ + ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer); + str_to_flow(argc > 2 ? argv[2] : "", &ofm->match, NULL, + &table_id, &out_port, &priority, NULL, NULL, NULL); + if (s->strict) { + ofm->command = htons(OFPFC_DELETE_STRICT); + } else { + ofm->command = htons(OFPFC_DELETE); + } + ofm->idle_timeout = htons(0); + ofm->hard_timeout = htons(0); + ofm->buffer_id = htonl(UINT32_MAX); + if (table_id == EMERG_TABLE_ID) + ofm->flags = htons(OFPFF_EMERG); + ofm->out_port = htons(out_port); + ofm->priority = htons(priority); + + open_vconn(argv[1], &vconn); + send_openflow_buffer(vconn, buffer); + vconn_close(vconn); +} + +static void +do_monitor(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) +{ + struct vconn *vconn; + const char *name; + + /* If the user specified, e.g., "nl:0", append ":1" to it to ensure that + * the connection will subscribe to listen for asynchronous messages, such + * as packet-in messages. */ + if (!strncmp(argv[1], "nl:", 3) && strrchr(argv[1], ':') == &argv[1][2]) { + name = xasprintf("%s:1", argv[1]); + } else { + name = argv[1]; + } + open_vconn(argv[1], &vconn); + for (;;) { + struct ofpbuf *b; + run(vconn_recv_block(vconn, &b), "vconn_recv"); + ofp_print(stderr, b->data, b->size, 2); + ofpbuf_delete(b); + } +} + +static void +str_to_port(char *string, uint16_t *start_port) +{ + char *save_ptr = NULL; + char *value = NULL; + + if (start_port) { + *start_port = OFPP_NONE; + } + + value = strtok_r(string, ", \t\r\n", &save_ptr); + if (value && start_port) { + *start_port = atoi(value); + } +} + +static void +do_dump_ports(const struct settings *s UNUSED, int argc, char *argv[]) +{ + struct ofp_port_stats_request *psr; + struct ofpbuf *buf; + + psr = alloc_stats_request(sizeof(*psr), OFPST_PORT, &buf); + str_to_port(argc > 2 ? argv[2] : "", &psr->port_no); + psr->port_no = htons(psr->port_no); + memset(psr->pad, 0, sizeof(psr->pad)); + dump_stats_transaction(argv[1], buf); +} + +static void +do_probe(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) +{ + struct ofpbuf *request; + struct vconn *vconn; + struct ofpbuf *reply; + + make_openflow(sizeof(struct ofp_header), OFPT_ECHO_REQUEST, &request); + open_vconn(argv[1], &vconn); + run(vconn_transact(vconn, request, &reply), "talking to %s", argv[1]); + if (reply->size != sizeof(struct ofp_header)) { + ofp_fatal(0, "reply does not match request"); + } + ofpbuf_delete(reply); + vconn_close(vconn); +} + +static void +do_mod_port(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) +{ + struct ofpbuf *request, *reply; + struct ofp_switch_features *osf; + struct ofp_port_mod *opm; + struct vconn *vconn; + char *endptr; + int n_ports; + int port_idx; + int port_no; + + + /* Check if the argument is a port index. Otherwise, treat it as + * the port name. */ + port_no = strtol(argv[2], &endptr, 10); + if (port_no == 0 && endptr == argv[2]) { + port_no = -1; + } + + /* Send a "Features Request" to get the information we need in order + * to modify the port. */ + make_openflow(sizeof(struct ofp_header), OFPT_FEATURES_REQUEST, &request); + open_vconn(argv[1], &vconn); + run(vconn_transact(vconn, request, &reply), "talking to %s", argv[1]); + + osf = reply->data; + n_ports = (reply->size - sizeof *osf) / sizeof *osf->ports; + + for (port_idx = 0; port_idx < n_ports; port_idx++) { + if (port_no != -1) { + /* Check argument as a port index */ + if (osf->ports[port_idx].port_no == htons(port_no)) { + break; + } + } else { + /* Check argument as an interface name */ + if (!strncmp((char *)osf->ports[port_idx].name, argv[2], + sizeof osf->ports[0].name)) { + break; + } + + } + } + if (port_idx == n_ports) { + ofp_fatal(0, "couldn't find monitored port: %s", argv[2]); + } + + opm = make_openflow(sizeof(struct ofp_port_mod), OFPT_PORT_MOD, &request); + opm->port_no = osf->ports[port_idx].port_no; + memcpy(opm->hw_addr, osf->ports[port_idx].hw_addr, sizeof opm->hw_addr); + opm->config = htonl(0); + opm->mask = htonl(0); + opm->advertise = htonl(0); + + printf("modifying port: %s\n", osf->ports[port_idx].name); + + if (!strncasecmp(argv[3], MOD_PORT_CMD_UP, sizeof MOD_PORT_CMD_UP)) { + opm->mask |= htonl(OFPPC_PORT_DOWN); + } else if (!strncasecmp(argv[3], MOD_PORT_CMD_DOWN, + sizeof MOD_PORT_CMD_DOWN)) { + opm->mask |= htonl(OFPPC_PORT_DOWN); + opm->config |= htonl(OFPPC_PORT_DOWN); + } else if (!strncasecmp(argv[3], MOD_PORT_CMD_FLOOD, + sizeof MOD_PORT_CMD_FLOOD)) { + opm->mask |= htonl(OFPPC_NO_FLOOD); + } else if (!strncasecmp(argv[3], MOD_PORT_CMD_NOFLOOD, + sizeof MOD_PORT_CMD_NOFLOOD)) { + opm->mask |= htonl(OFPPC_NO_FLOOD); + opm->config |= htonl(OFPPC_NO_FLOOD); + } else { + ofp_fatal(0, "unknown mod-port command '%s'", argv[3]); + } + + send_openflow_buffer(vconn, request); + + ofpbuf_delete(reply); + vconn_close(vconn); +} + +static void +do_ping(const struct settings *s UNUSED, int argc, char *argv[]) +{ + size_t max_payload = 65535 - sizeof(struct ofp_header); + unsigned int payload; + struct vconn *vconn; + int i; + + payload = argc > 2 ? atoi(argv[2]) : 64; + if (payload > max_payload) { + ofp_fatal(0, "payload must be between 0 and %zu bytes", max_payload); + } + + open_vconn(argv[1], &vconn); + for (i = 0; i < 10; i++) { + struct timeval start, end; + struct ofpbuf *request, *reply; + struct ofp_header *rq_hdr, *rpy_hdr; + + rq_hdr = make_openflow(sizeof(struct ofp_header) + payload, + OFPT_ECHO_REQUEST, &request); + random_bytes(rq_hdr + 1, payload); + + gettimeofday(&start, NULL); + run(vconn_transact(vconn, ofpbuf_clone(request), &reply), "transact"); + gettimeofday(&end, NULL); + + rpy_hdr = reply->data; + if (reply->size != request->size + || memcmp(rpy_hdr + 1, rq_hdr + 1, payload) + || rpy_hdr->xid != rq_hdr->xid + || rpy_hdr->type != OFPT_ECHO_REPLY) { + printf("Reply does not match request. Request:\n"); + ofp_print(stdout, request, request->size, 2); + printf("Reply:\n"); + ofp_print(stdout, reply, reply->size, 2); + } + printf("%d bytes from %s: xid=%08"PRIx32" time=%.1f ms\n", + reply->size - sizeof *rpy_hdr, argv[1], rpy_hdr->xid, + (1000*(double)(end.tv_sec - start.tv_sec)) + + (.001*(end.tv_usec - start.tv_usec))); + ofpbuf_delete(request); + ofpbuf_delete(reply); + } + vconn_close(vconn); +} + +static void +do_benchmark(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) +{ + size_t max_payload = 65535 - sizeof(struct ofp_header); + struct timeval start, end; + unsigned int payload_size, message_size; + struct vconn *vconn; + double duration; + int count; + int i; + + payload_size = atoi(argv[2]); + if (payload_size > max_payload) { + ofp_fatal(0, "payload must be between 0 and %zu bytes", max_payload); + } + message_size = sizeof(struct ofp_header) + payload_size; + + count = atoi(argv[3]); + + printf("Sending %d packets * %u bytes (with header) = %u bytes total\n", + count, message_size, count * message_size); + + open_vconn(argv[1], &vconn); + gettimeofday(&start, NULL); + for (i = 0; i < count; i++) { + struct ofpbuf *request, *reply; + struct ofp_header *rq_hdr; + + rq_hdr = make_openflow(message_size, OFPT_ECHO_REQUEST, &request); + memset(rq_hdr + 1, 0, payload_size); + run(vconn_transact(vconn, request, &reply), "transact"); + ofpbuf_delete(reply); + } + gettimeofday(&end, NULL); + vconn_close(vconn); + + duration = ((1000*(double)(end.tv_sec - start.tv_sec)) + + (.001*(end.tv_usec - start.tv_usec))); + printf("Finished in %.1f ms (%.0f packets/s) (%.0f bytes/s)\n", + duration, count / (duration / 1000.0), + count * message_size / (duration / 1000.0)); +} + +/**************************************************************** + * + * Queue operations + * + ****************************************************************/ + +static int +parse_queue_params(int argc, char *argv[], uint16_t *port, uint32_t *q_id, + uint16_t *min_rate) +{ + if (!port || !q_id) { + return -1; + } + + *port = OFPP_ALL; + *q_id = OFPQ_ALL; + if (argc > 2) { + *port = str_to_u32(argv[2]); + } + if (argc > 3) { + *q_id = str_to_u32(argv[3]); + } + if (min_rate) { + *min_rate = OFPQ_MIN_RATE_UNCFG; + if (argc > 4) { + *min_rate = str_to_u32(argv[4]); + } + } + + return 0; +} + +/* Length of queue request; works with 16-bit property values like min_rate */ +#define Q_REQ_LEN(prop_count) \ + (sizeof(struct ofp_packet_queue) + Q_PROP_LEN(prop_count)) + +#define Q_PROP_LEN(prop_count) \ + ((prop_count) * sizeof(struct ofp_queue_prop_min_rate)) + +/* + * Execute a queue add/mod/del operation + * + * All commands must specify a port and queue id. + * Add may specify a bandwidth value + * Modify must specify a bandwidth value + * + * To simplify things, always allocate space for all three parameters + * (port, queue, min-bw): + * openflow_queue_header (w/ ofp header, port) + * ofp_queue (with q_id and offset to properties list) + * ofp_queue_prop_min_rate (w/ prop header and rate info) + */ +static struct openflow_queue_command_header * +queue_req_create(int cmd, struct ofpbuf **b, uint16_t port, + uint32_t q_id, uint16_t min_rate) +{ + struct openflow_queue_command_header *request; + struct ofp_packet_queue *queue; + struct ofp_queue_prop_min_rate *min_rate_prop; + int req_bytes; + + req_bytes = sizeof(*request) + sizeof(*queue) + sizeof(*min_rate_prop); + request = make_openflow(req_bytes, OFPT_VENDOR, b); + if (request == NULL) { + return NULL; + } + request->header.vendor = htonl(OPENFLOW_VENDOR_ID); + request->header.subtype = htonl(cmd); + request->port = htons(port); + + /* Will get complicated when queue properties w/ different struct sizes */ + queue = S_PTR(request, struct openflow_queue_command_header, body); + queue->queue_id = htonl(q_id); + queue->len = htons(Q_REQ_LEN(1)); + + min_rate_prop = S_PTR(queue, struct ofp_packet_queue, properties); + min_rate_prop->prop_header.property = htons(OFPQT_MIN_RATE); + min_rate_prop->prop_header.len = htons(Q_PROP_LEN(1)); + min_rate_prop->rate = htons(min_rate); + + return request; +} + +/* Handler for add/modify/delete queue ops */ +static void +do_queue_op(int cmd, int argc, char *argv[]) +{ + struct openflow_queue_command_header *request; + struct vconn *vconn; + struct ofpbuf *b; + uint16_t port; + uint32_t q_id; + uint16_t min_rate; + + if (parse_queue_params(argc, argv, &port, &q_id, &min_rate) < 0) { + ofp_fatal(0, "Error parsing port/queue for cmd %s", argv[0]); + return; + } + + printf("que op %d (%s). port %d. q 0x%x. rate %d\n", cmd, argv[0], + port, q_id, min_rate); + + if ((request = queue_req_create(cmd, &b, port, q_id, min_rate)) == NULL) { + ofp_fatal(0, "Error creating queue req for cmd %s", argv[0]); + return; + } + + printf("made request %p, running transaction\n", request); + + open_vconn(argv[1], &vconn); + /* Unacknowledged call for now */ + send_openflow_buffer(vconn, b); + vconn_close(vconn); +} + +char *openflow_queue_error_strings[] = OPENFLOW_QUEUE_ERROR_STRINGS_DEF; + +static void +do_mod_queue(const struct settings *s UNUSED, int argc, char *argv[]) +{ + do_queue_op(OFP_EXT_QUEUE_MODIFY, argc, argv); +} + +static void +do_del_queue(const struct settings *s UNUSED, int argc, char *argv[]) +{ + do_queue_op(OFP_EXT_QUEUE_DELETE, argc, argv); +} + +static void +do_dump_queue_port(char *vconn_name, uint16_t port, uint32_t q_id) +{ + struct ofp_queue_get_config_request *request; + struct ofpbuf *buf; + + request = make_openflow(sizeof(*request), OFPT_QUEUE_GET_CONFIG_REQUEST, + &buf); + request->port = htons(port); /* FIXME */ + dump_transaction(vconn_name, buf); + + /* Then do a queue stats get */ + dump_queue_stats_transaction(vconn_name, OFPST_QUEUE, port, q_id); +} + +static void +do_dump_queue_all(char *vconn_name, uint32_t q_id) +{ + struct ofpbuf *request, *reply; + struct ofp_switch_features *osf; + int port_idx, n_ports; + uint16_t port_no; + struct vconn *vconn; + + /* Send a "Features Request" to get the list of ports in the system */ + make_openflow(sizeof(struct ofp_header), OFPT_FEATURES_REQUEST, &request); + open_vconn(vconn_name, &vconn); + run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name); + vconn_close(vconn); + + osf = reply->data; + n_ports = (reply->size - sizeof *osf) / sizeof *osf->ports; + for (port_idx = 0; port_idx < n_ports; port_idx++) { + if ((port_no = ntohs(osf->ports[port_idx].port_no)) < OFPP_MAX) { + do_dump_queue_port(vconn_name, port_no, q_id); + } + } + ofpbuf_delete(reply); +} + +static void +do_dump_queue(const struct settings *s UNUSED, int argc, char *argv[]) +{ + uint16_t port; + uint32_t q_id; + + /* Get queue params from the request */ + if (parse_queue_params(argc, argv, &port, &q_id, NULL) < 0) { + ofp_fatal(0, "Error parsing port/queue for cmd %s", argv[0]); + return; + } + + if (port == OFPP_ALL) { + do_dump_queue_all(argv[1], q_id); + } else { + do_dump_queue_port(argv[1], port, q_id); + } +} + +static void +do_help(const struct settings *s UNUSED, int argc UNUSED, char *argv[] UNUSED) +{ + usage(); +} + +static struct command all_commands[] = { +#ifdef HAVE_NETLINK + { "adddp", 1, 1, do_add_dp }, + { "deldp", 1, 1, do_del_dp }, + { "addif", 2, INT_MAX, do_add_port }, + { "delif", 2, INT_MAX, do_del_port }, + { "get-idx", 1, 1, do_get_idx }, +#endif + + { "show", 1, 1, do_show }, + { "status", 1, 2, do_status }, + + { "show-protostat", 1, 1, do_protostat }, + + { "help", 0, INT_MAX, do_help }, + { "monitor", 1, 1, do_monitor }, + { "dump-desc", 1, 1, do_dump_desc }, + { "dump-tables", 1, 1, do_dump_tables }, + { "desc", 2, 2, do_desc }, + { "dump-flows", 1, 2, do_dump_flows }, + { "dump-aggregate", 1, 2, do_dump_aggregate }, + { "add-flow", 2, 2, do_add_flow }, + { "add-flows", 2, 2, do_add_flows }, + { "mod-flows", 2, 2, do_mod_flows }, + { "del-flows", 1, 2, do_del_flows }, + { "dump-ports", 1, 2, do_dump_ports }, + { "mod-port", 3, 3, do_mod_port }, + { "add-queue", 3, 4, do_mod_queue }, + { "mod-queue", 3, 4, do_mod_queue }, + { "del-queue", 3, 3, do_del_queue }, + { "dump-queue", 1, 3, do_dump_queue }, + { "probe", 1, 1, do_probe }, + { "ping", 1, 2, do_ping }, + { "benchmark", 3, 3, do_benchmark }, + { NULL, 0, 0, NULL }, +}; diff --git a/openflow/utilities/ofp-discover.8.in b/openflow/utilities/ofp-discover.8.in new file mode 100644 index 00000000..cf5ac549 --- /dev/null +++ b/openflow/utilities/ofp-discover.8.in @@ -0,0 +1,119 @@ +.ds PN ofp\-discover + +.TH ofp\-discover 8 "May 2008" "OpenFlow" "OpenFlow Manual" + +.SH NAME +ofp\-discover \- controller discovery utility + +.SH SYNOPSIS +.B ofp\-discover +[\fIoptions\fR] \fInetdev\fR [\fInetdev\fR...] + +.SH DESCRIPTION +The \fBofp\-discover\fR program attempts to discover the location of +an OpenFlow controller on one of the network devices listed on the +command line. It repeatedly broadcasts a DHCP request with vendor +class identifier \fBOpenFlow\fR on each network device until it +receives an acceptable DHCP response. It will accept any valid DHCP +reply that has the same vendor class identifier and includes a +vendor-specific option with code 1 whose contents are a string +specifying the location of the controller in the same format used on +the \fBofprotocol\fR command line (e.g. \fBssl:192.168.0.1\fR). + +When \fBofp\-discover\fR receives an acceptable response, it prints +the details of the response on \fBstdout\fR. Then, by default, it +configures the network device on which the response was received with +the received IP address, netmask, and default gateway, and detaches +itself to the background. + +.SH OPTIONS +.TP +\fB--accept-vconn=\fIregex\fR +By default, \fBofp\-discover\fR accepts any controller location +advertised over DHCP. With this option, only controllers whose names +match POSIX extended regular expression \fIregex\fR will be accepted. +Specifying \fBssl:.*\fR for \fIregex\fR, for example, would cause only +SSL controller connections to be accepted. + +The \fIregex\fR is implicitly anchored at the beginning of the +controller location string, as if it begins with \fB^\fR. + +.TP +\fB--exit-without-bind\fR +By default, \fBofp\-discover\fR binds the network device that receives +the first acceptable response to the IP address received over DHCP. +With this option, the configuration of the network device is not +changed at all, except to bring it up if it is initially down, and +\fBofp\-discover\fR will exit immediately after it receives an +acceptable DHCP response. + +This option is mutually exclusive with \fB--exit-after-bind\fR and +\fB--no-detach\fR. + +.TP +\fB--exit-after-bind\fR +By default, after it receives an acceptable DHCP response, +\fBofp\-discover\fR detaches itself from the foreground session and +runs in the background maintaining the DHCP lease as necessary. With +this option, \fBofp\-discover\fR will exit immediately after it +receives an acceptable DHCP response and configures the network device +with the received IP address. The address obtained via DHCP could +therefore be used past the expiration of its lease. + +This option is mutually exclusive with \fB--exit-without-bind\fR and +\fB--no-detach\fR. + +.TP +\fB--no-detach\fR +By default, \fBofp\-discover\fR runs in the foreground until it obtains +an acceptable DHCP response, then it detaches itself from the +foreground session and run as a background process. This option +prevents \fBofp\-discover\fR from detaching, causing it to run in the +foreground even after it obtains a DHCP response. + +This option is mutually exclusive with \fB--exit-without-bind\fR and +\fB--exit-after-bind\fR. + +.TP +\fB-P\fR[\fIpidfile\fR], \fB--pidfile\fR[\fB=\fIpidfile\fR] +Causes a file (by default, \fBofp\-discover.pid\fR) to be created indicating +the PID of the running process. If \fIpidfile\fR is not specified, or +if it does not begin with \fB/\fR, then it is created in +\fB@RUNDIR@\fR. + +The \fIpidfile\fR is created when \fBofp\-discover\fR detaches, so +this this option has no effect when one of \fB--exit-without-bind\fR, +\fB--exit-after-bind\fR, or \fB--no-detach\fR is also given. + +.TP +\fB-f\fR, \fB--force\fR +By default, when \fB-P\fR or \fB--pidfile\fR is specified and the +specified pidfile already exists and is locked by a running process, +\fBcontroller\fR refuses to start. Specify \fB-f\fR or \fB--force\fR +to cause it to instead overwrite the pidfile. + +When \fB-P\fR or \fB--pidfile\fR is not specified, this option has no +effect. + +.so lib/vlog.man +.so lib/common.man + +.SH BUGS + +If the network devices specified on the command line have been added +to an OpenFlow switch with \fBdpctl addif\fR, then controller +discovery will fail because \fBofp\-discover\fR will not be able to +see DHCP responses, even though tools such as \fBtcpdump\fR(8) and +\fBwireshark\fR(1) can see them on the wire. This is because of the +structure of the Linux kernel networking stack, which hands packets +first to programs that listen for all arriving packets, then to +OpenFlow, then to programs that listen for a specific kind of packet. +OpenFlow consumes all the packets handed to it, so tools like +\fBtcpdump\fR that look at all packets will see packets arriving on +OpenFlow interfaces, but \fRofp\-discover\fR, which listens only for +arriving IP packets, will not. + +.SH "SEE ALSO" + +.BR ofprotocol (8), +.BR ofp-pki (8) diff --git a/openflow/utilities/ofp-discover.c b/openflow/utilities/ofp-discover.c new file mode 100644 index 00000000..55f40429 --- /dev/null +++ b/openflow/utilities/ofp-discover.c @@ -0,0 +1,420 @@ +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "command-line.h" +#include "daemon.h" +#include "dhcp-client.h" +#include "dhcp.h" +#include "dirs.h" +#include "dynamic-string.h" +#include "fatal-signal.h" +#include "netdev.h" +#include "poll-loop.h" +#include "timeval.h" +#include "util.h" +#include "vlog-socket.h" + +#include "vlog.h" +#define THIS_MODULE VLM_ofp_discover + +struct iface { + const char *name; + struct dhclient *dhcp; +}; + +/* The interfaces that we serve. */ +static struct iface *ifaces; +static int n_ifaces; + +/* --accept-vconn: Regular expression specifying the class of controller vconns + * that we will accept during autodiscovery. */ +static const char *accept_controller_re = ".*"; +static regex_t accept_controller_regex; + +/* --exit-without-bind: Exit after discovering the controller, without binding + * the network device to an IP address? */ +static bool exit_without_bind; + +/* --exit-after-bind: Exit after discovering the controller, after binding the + * network device to an IP address? */ +static bool exit_after_bind; + +static bool iface_init(struct iface *, const char *netdev_name); +static void release_ifaces(void *aux UNUSED); + +static void parse_options(int argc, char *argv[]); +static void usage(void) NO_RETURN; + +static void modify_dhcp_request(struct dhcp_msg *, void *aux); +static bool validate_dhcp_offer(const struct dhcp_msg *, void *aux); + +int +main(int argc, char *argv[]) +{ + int retval; + int i; + + set_program_name(argv[0]); + time_init(); + vlog_init(); + parse_options(argc, argv); + + argc -= optind; + argv += optind; + if (argc < 1) { + ofp_fatal(0, "need at least one non-option argument; " + "use --help for usage"); + } + + ifaces = xmalloc(argc * sizeof *ifaces); + n_ifaces = 0; + for (i = 0; i < argc; i++) { + if (iface_init(&ifaces[n_ifaces], argv[i])) { + n_ifaces++; + } + } + if (!n_ifaces) { + ofp_fatal(0, "failed to initialize any DHCP clients"); + } + + for (i = 0; i < n_ifaces; i++) { + struct iface *iface = &ifaces[i]; + dhclient_init(iface->dhcp, 0); + } + fatal_signal_add_hook(release_ifaces, NULL, true); + + retval = regcomp(&accept_controller_regex, accept_controller_re, + REG_NOSUB | REG_EXTENDED); + if (retval) { + size_t length = regerror(retval, &accept_controller_regex, NULL, 0); + char *buffer = xmalloc(length); + regerror(retval, &accept_controller_regex, buffer, length); + ofp_fatal(0, "%s: %s", accept_controller_re, buffer); + } + + retval = vlog_server_listen(NULL, NULL); + if (retval) { + ofp_fatal(retval, "Could not listen for vlog connections"); + } + + die_if_already_running(); + + signal(SIGPIPE, SIG_IGN); + for (;;) { + fatal_signal_block(); + for (i = 0; i < n_ifaces; i++) { + struct iface *iface = &ifaces[i]; + dhclient_run(iface->dhcp); + if (dhclient_changed(iface->dhcp)) { + bool is_bound = dhclient_is_bound(iface->dhcp); + int j; + + /* Configure network device. */ + if (!exit_without_bind) { + dhclient_configure_netdev(iface->dhcp); + dhclient_update_resolv_conf(iface->dhcp); + } + + if (is_bound) { + static bool detached = false; + struct ds ds; + + /* Disable timeout, since discovery was successful. */ + time_alarm(0); + + /* Print discovered parameters. */ + ds_init(&ds); + dhcp_msg_to_string(dhclient_get_config(iface->dhcp), + true, &ds); + fputs(ds_cstr(&ds), stdout); + putchar('\n'); + fflush(stdout); + ds_destroy(&ds); + + /* Exit if the user requested it. */ + if (exit_without_bind) { + VLOG_DBG("exiting because of successful binding on %s " + "and --exit-without-bind specified", + iface->name); + exit(0); + } + if (exit_after_bind) { + VLOG_DBG("exiting because of successful binding on %s " + "and --exit-after-bind specified", + iface->name); + exit(0); + } + + /* Detach into background, if we haven't already. */ + if (!detached) { + detached = true; + daemonize(); + } + } + + /* We only want an address on a single one of our interfaces. + * So: if we have an address on this interface, stop looking + * for one on the others; if we don't have an address on this + * interface, start looking everywhere. */ + for (j = 0; j < n_ifaces; j++) { + struct iface *if2 = &ifaces[j]; + if (iface != if2) { + if (is_bound) { + dhclient_release(if2->dhcp); + } else { + dhclient_init(if2->dhcp, 0); + } + } + } + } + } + for (i = 0; i < n_ifaces; i++) { + struct iface *iface = &ifaces[i]; + dhclient_wait(iface->dhcp); + } + fatal_signal_unblock(); + poll_block(); + } + + return 0; +} + +static bool +iface_init(struct iface *iface, const char *netdev_name) +{ + int retval; + + iface->name = netdev_name; + iface->dhcp = NULL; + + if (exit_after_bind) { + /* Bring this interface up permanently, so that the bound address + * persists past program termination. */ + struct netdev *netdev; + + retval = netdev_open(iface->name, NETDEV_ETH_TYPE_NONE, &netdev); + if (retval) { + ofp_error(retval, "Could not open %s device", iface->name); + return false; + } + retval = netdev_turn_flags_on(netdev, NETDEV_UP, true); + if (retval) { + ofp_error(retval, "Could not bring %s device up", iface->name); + return false; + } + netdev_close(netdev); + } + + retval = dhclient_create(iface->name, modify_dhcp_request, + validate_dhcp_offer, NULL, &iface->dhcp); + if (retval) { + ofp_error(retval, "%s: failed to initialize DHCP client", iface->name); + return false; + } + + return true; +} + +static void +release_ifaces(void *aux UNUSED) +{ + int i; + + for (i = 0; i < n_ifaces; i++) { + struct dhclient *dhcp = ifaces[i].dhcp; + dhclient_release(dhcp); + if (dhclient_changed(dhcp)) { + dhclient_configure_netdev(dhcp); + } + } +} + +static void +modify_dhcp_request(struct dhcp_msg *msg, void *aux UNUSED) +{ + dhcp_msg_put_string(msg, DHCP_CODE_VENDOR_CLASS, "OpenFlow"); +} + +static bool +validate_dhcp_offer(const struct dhcp_msg *msg, void *aux UNUSED) +{ + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60); + char *vconn_name; + bool accept; + + vconn_name = dhcp_msg_get_string(msg, DHCP_CODE_OFP_CONTROLLER_VCONN); + if (!vconn_name) { + VLOG_WARN_RL(&rl, "rejecting DHCP offer missing controller vconn"); + return false; + } + accept = !regexec(&accept_controller_regex, vconn_name, 0, NULL, 0); + free(vconn_name); + return accept; +} + +static void +parse_options(int argc, char *argv[]) +{ + enum { + OPT_ACCEPT_VCONN = UCHAR_MAX + 1, + OPT_EXIT_WITHOUT_BIND, + OPT_EXIT_AFTER_BIND, + OPT_NO_DETACH, + }; + static struct option long_options[] = { + {"accept-vconn", required_argument, 0, OPT_ACCEPT_VCONN}, + {"exit-without-bind", no_argument, 0, OPT_EXIT_WITHOUT_BIND}, + {"exit-after-bind", no_argument, 0, OPT_EXIT_AFTER_BIND}, + {"no-detach", no_argument, 0, OPT_NO_DETACH}, + {"timeout", required_argument, 0, 't'}, + {"pidfile", optional_argument, 0, 'P'}, + {"force", no_argument, 0, 'f'}, + {"verbose", optional_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {0, 0, 0, 0}, + }; + char *short_options = long_options_to_short_options(long_options); + bool detach_after_bind = true; + + for (;;) { + unsigned long int timeout; + int c; + + c = getopt_long(argc, argv, short_options, long_options, NULL); + if (c == -1) { + break; + } + + switch (c) { + case OPT_ACCEPT_VCONN: + accept_controller_re = (optarg[0] == '^' + ? optarg + : xasprintf("^%s", optarg)); + break; + + case OPT_EXIT_WITHOUT_BIND: + exit_without_bind = true; + break; + + case OPT_EXIT_AFTER_BIND: + exit_after_bind = true; + break; + + case OPT_NO_DETACH: + detach_after_bind = false; + break; + + case 'P': + set_pidfile(optarg); + break; + + case 'f': + ignore_existing_pidfile(); + break; + + case 't': + timeout = strtoul(optarg, NULL, 10); + if (timeout <= 0) { + ofp_fatal(0, "value %s on -t or --timeout is not at least 1", + optarg); + } else { + time_alarm(timeout); + } + signal(SIGALRM, SIG_DFL); + break; + + case 'h': + usage(); + + case 'V': + printf("%s %s compiled "__DATE__" "__TIME__"\n", + program_name, VERSION BUILDNR); + exit(EXIT_SUCCESS); + + case 'v': + vlog_set_verbosity(optarg); + break; + + case '?': + exit(EXIT_FAILURE); + + default: + abort(); + } + } + free(short_options); + + if ((exit_without_bind + exit_after_bind + !detach_after_bind) > 1) { + ofp_fatal(0, "--exit-without-bind, --exit-after-bind, and --no-detach " + "are mutually exclusive"); + } + if (detach_after_bind) { + set_detach(); + } +} + +static void +usage(void) +{ + printf("%s: a tool for discovering OpenFlow controllers.\n" + "usage: %s [OPTIONS] NETDEV [NETDEV...]\n" + "where each NETDEV is a network device on which to perform\n" + "controller discovery.\n" + "\nOrdinarily, ofp-discover runs in the foreground until it\n" + "obtains an IP address and discovers an OpenFlow controller via\n" + "DHCP, then it prints information about the controller to stdout\n" + "and detaches to the background to maintain the IP address lease.\n" + "\nNetworking options:\n" + " --accept-vconn=REGEX accept matching discovered controllers\n" + " --exit-without-bind exit after discovery, without binding\n" + " --exit-after-bind exit after discovery, after binding\n" + " --no-detach do not detach after discovery\n", + program_name, program_name); + vlog_usage(); + printf("\nOther options:\n" + " -t, --timeout=SECS give up discovery after SECS seconds\n" + " -P, --pidfile[=FILE] create pidfile (default: %s/%s.pid)\n" + " -f, --force with -P, start even if already running\n" + " -h, --help display this help message\n" + " -V, --version display version information\n", + ofp_rundir, program_name); + exit(EXIT_SUCCESS); +} diff --git a/openflow/utilities/ofp-kill.8.in b/openflow/utilities/ofp-kill.8.in new file mode 100644 index 00000000..6c1298ca --- /dev/null +++ b/openflow/utilities/ofp-kill.8.in @@ -0,0 +1,61 @@ +.ds PN ofp\-kill + +.TH ofp\-kill 8 "May 2008" "OpenFlow" "OpenFlow Manual" + +.SH NAME +ofp\-kill \- kills processes given their pidfiles + +.SH SYNOPSIS +.B ofp\-kill +[\fIoptions\fR] \fIpidfile\fR [\fIpidfile\fR...] + +.SH DESCRIPTION +The \fBofp\-kill\fR program reads each \fIpidfile\fR specified on the +command line and sends a signal to the program associated with it, if +any. It reads one line of text from \fIpidfile\fR, which must contain +the PID of the process to kill as a text string. It then uses +\fBfcntl\fR(2) to verify that a process with the PID from the file +owns a lock on \fIpidfile\fR before it sends the signal. + +A \fIpidfile\fR whose name begins with \fB/\fR is used literally. +Otherwise, \fB@RUNDIR@/\fR is prefixed. + +This program exists for use by \fBofp\-switch\-setup\fR, which cannot +easily implement its functionality since Perl has no portable +interface to \fBfcntl\fR-based file locking. + +.SH OPTIONS +.TP +\fB-s \fInumber\fR|\fIname\fR, \fB\-\^\-signal=\fInumber\fR|\fIname\fR +Sets the signal to be sent to each process. Signals may be given by +number (e.g. \fB1\fR) or by name (e.g. \fBHUP\fR or \fBSIGHUP\fR). +By default, \fBSIGTERM\fR is sent. + +.TP +\fB-f\fR, \fB\-\^\-force\fR +Causes \fBofp\-kill\fR to ignore all errors without printing a message +to \fBstderr\fR, and to exit with return code 0. + +.so lib/common.man + +.SH "EXIT CODE" + +Without \fB-f\fR or \fB\-\^\-force\fR, \fBofp\-kill\fR exits with +status 0 if at least one \fIpidfile\fR was given and the process +represented by every \fIpidfile\fR was signaled successfully, +otherwise with status 1. + +With \fB-f\fR or \fB\-\^\-force\fR, \fBofp\-kill\fR always exits with +status 0. + +.SH BUGS + +There is a race between verifying the lock on \fIpidfile\fR and +actually killing the process. + +\fBofp\-kill\fR does not wait for the signaled processes to die before +exiting. + +.SH "SEE ALSO" + +.BR ofp\-switch\-setup (8) diff --git a/openflow/utilities/ofp-kill.c b/openflow/utilities/ofp-kill.c new file mode 100644 index 00000000..0ad04343 --- /dev/null +++ b/openflow/utilities/ofp-kill.c @@ -0,0 +1,228 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "command-line.h" +#include "daemon.h" +#include "timeval.h" +#include "util.h" +#include "vlog.h" + +/* -s, --signal: signal to send. */ +static int sig_nr = SIGTERM; + +/* -f, --force: ignore errors. */ +static bool force; + +static void cond_error(int err_no, const char *, ...) PRINTF_FORMAT(2, 3); + +static void parse_options(int argc, char *argv[]); +static void usage(void); + +int +main(int argc, char *argv[]) +{ + bool ok = true; + int i; + + set_program_name(argv[0]); + time_init(); + vlog_init(); + parse_options(argc, argv); + + argc -= optind; + argv += optind; + if (argc < 1) { + if (!force) { + ofp_fatal(0, "need at least one non-option argument; " + "use --help for usage"); + } + } + + for (i = 0; i < argc; i++) { + char *pidfile; + pid_t pid; + + pidfile = make_pidfile_name(argv[i]); + pid = read_pidfile(pidfile); + if (pid >= 0) { + if (kill(pid, sig_nr) < 0) { + cond_error(errno, "%s: kill(%ld)", pidfile, (long int) pid); + } + } else { + cond_error(-pid, "could not read %s", pidfile); + } + free(pidfile); + } + + return ok || force ? EXIT_SUCCESS : EXIT_FAILURE; +} + +static void +parse_options(int argc, char *argv[]) +{ + static struct option long_options[] = { + {"signal", required_argument, 0, 's'}, + {"force", no_argument, 0, 'f'}, + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {0, 0, 0, 0}, + }; + char *short_options = long_options_to_short_options(long_options); + + for (;;) { + int c; + + c = getopt_long(argc, argv, short_options, long_options, NULL); + if (c == -1) { + break; + } + + switch (c) { + case 's': + if (atoi(optarg) || !strcmp(optarg, "0")) { + sig_nr = atoi(optarg); + } else { + struct signal_name { + const char *name; + int number; + }; + + static const struct signal_name signals[] = { +#define SIGNAL(NAME) { #NAME, NAME } + SIGNAL(SIGABRT), + SIGNAL(SIGALRM), + SIGNAL(SIGBUS), + SIGNAL(SIGCHLD), + SIGNAL(SIGCONT), + SIGNAL(SIGFPE), + SIGNAL(SIGHUP), + SIGNAL(SIGILL), + SIGNAL(SIGINT), + SIGNAL(SIGKILL), + SIGNAL(SIGPIPE), + SIGNAL(SIGQUIT), + SIGNAL(SIGSEGV), + SIGNAL(SIGSTOP), + SIGNAL(SIGTERM), + SIGNAL(SIGTSTP), + SIGNAL(SIGTTIN), + SIGNAL(SIGTTOU), + SIGNAL(SIGUSR1), + SIGNAL(SIGUSR2), +#ifdef SIGPOLL + SIGNAL(SIGPOLL), +#endif + SIGNAL(SIGPROF), + SIGNAL(SIGSYS), + SIGNAL(SIGTRAP), + SIGNAL(SIGURG), + SIGNAL(SIGVTALRM), + SIGNAL(SIGXCPU), + SIGNAL(SIGXFSZ), +#undef SIGNAL + }; + int i; + + for (i = 0; i < ARRAY_SIZE(signals); i++) { + const struct signal_name *s = &signals[i]; + if (!strcmp(optarg, s->name) + || !strcmp(optarg, s->name + 3)) { + sig_nr = s->number; + goto got_name; + } + } + ofp_fatal(0, "unknown signal \"%s\"", optarg); + got_name: ; + } + break; + + case 'f': + force = true; + break; + + case 'h': + usage(); + + case 'V': + printf("%s %s compiled "__DATE__" "__TIME__"\n", + program_name, VERSION BUILDNR); + exit(EXIT_SUCCESS); + + case '?': + exit(EXIT_FAILURE); + + default: + abort(); + } + } + free(short_options); +} + +static void +usage(void) +{ + printf("%s: kills a program using a pidfile\n" + "usage: %s [OPTIONS] PIDFILE [PIDFILE...]\n" + "where each PIDFILE is a pidfile created by an OpenFlow daemon.\n" + "\nOptions:\n" + " -s, --signal=NUMBER|NAME signal to send (default: TERM)\n" + " -f, --force ignore errors\n" + " -h, --help display this help message\n" + " -V, --version display version information\n", + program_name, program_name); + exit(EXIT_SUCCESS); +} + +static void +cond_error(int err_no, const char *format, ...) +{ + if (!force) { + va_list args; + + fprintf(stderr, "%s: ", program_name); + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + if (err_no != 0) + fprintf(stderr, " (%s)", strerror(err_no)); + putc('\n', stderr); + } +} diff --git a/openflow/utilities/ofp-parse-leaks b/openflow/utilities/ofp-parse-leaks new file mode 100644 index 00000000..e51ecb72 --- /dev/null +++ b/openflow/utilities/ofp-parse-leaks @@ -0,0 +1,285 @@ +#! /usr/bin/perl + +use strict; +use warnings; + +if (grep($_ eq '--help', @ARGV)) { + print < 1; +die "$0: $ARGV[0] does not exist" if @ARGV > 0 && ! -e $ARGV[0]; + +our ($binary); +our ($a2l) = search_path("addr2line"); +my ($no_syms) = "symbols will not be translated"; +if (!@ARGV) { + print "no binary specified; $no_syms\n"; +} elsif (! -e $ARGV[0]) { + print "$ARGV[0] does not exist; $no_syms"; +} elsif (!defined($a2l)) { + print "addr2line not found in PATH; $no_syms"; +} else { + $binary = $ARGV[0]; +} + +our ($objdump) = search_path("objdump"); +print "objdump not found; dynamic library symbols will not be translated\n" + if !defined($objdump); + +our %blocks; +our @segments; +while () { + my $ptr = "((?:0x)?[0-9a-fA-F]+|\\(nil\\))"; + my $callers = ":((?: $ptr)+)"; + if (/^malloc\((\d+)\) -> $ptr$callers$/) { + allocated($., $2, $1, $3); + } elsif (/^claim\($ptr\)$callers$/) { + claimed($., $1, $2); + } elsif (/realloc\($ptr, (\d+)\) -> $ptr$callers$/) { + my ($callers) = $4; + freed($., $1, $callers); + allocated($., $3, $2, $callers); + } elsif (/^free\($ptr\)$callers$/) { + freed($., $1, $2); + } elsif (/^segment: $ptr-$ptr $ptr [-r][-w][-x][sp] (.*)/) { + add_segment(hex($1), hex($2), hex($3), $4); + } else { + print "stdin:$.: syntax error\n"; + } +} +if (%blocks) { + my $n_blocks = scalar(keys(%blocks)); + my $n_bytes = 0; + $n_bytes += $_->{SIZE} foreach values(%blocks); + print "$n_bytes bytes in $n_blocks blocks not freed at end of run\n"; + my %blocks_by_callers; + foreach my $block (values(%blocks)) { + my ($trimmed_callers) = trim_callers($block->{CALLERS}); + push (@{$blocks_by_callers{$trimmed_callers}}, $block); + } + foreach my $callers (sort {@{$b} <=> @{$a}} (values(%blocks_by_callers))) { + $n_blocks = scalar(@{$callers}); + $n_bytes = 0; + $n_bytes += $_->{SIZE} foreach @{$callers}; + print "$n_bytes bytes in these $n_blocks blocks were not freed:\n"; + my $i = 0; + my $max = 5; + foreach my $block (sort {$a->{LINE} <=> $b->{LINE}} (@{$callers})) { + printf "\t%d-byte block at 0x%08x allocated on stdin:%d\n", + $block->{SIZE}, $block->{BASE}, $block->{LINE}; + last if $i++ > $max; + } + print "\t...and ", $n_blocks - $max, " others...\n" + if $n_blocks > $max; + print "The blocks listed above were allocated by:\n"; + print_callers("\t", ${$callers}[0]->{CALLERS}); + } +} +sub interp_pointer { + my ($s_ptr) = @_; + return $s_ptr eq '(nil)' ? 0 : hex($s_ptr); +} + +sub allocated { + my ($line, $s_base, $size, $callers) = @_; + my ($base) = interp_pointer($s_base); + return if !$base; + my ($info) = {LINE => $line, + BASE => $base, + SIZE => $size, + CALLERS => $callers}; + if (exists($blocks{$base})) { + print "In-use address returned by allocator:\n"; + print "\tInitial allocation:\n"; + print_block("\t\t", $blocks{$base}); + print "\tNew allocation:\n"; + print_block("\t\t", $info); + } + $blocks{$base} = $info; +} + +sub claimed { + my ($line, $s_base, $callers) = @_; + my ($base) = interp_pointer($s_base); + return if !$base; + if (exists($blocks{$base})) { + $blocks{$base}{LINE} = $line; + $blocks{$base}{CALLERS} = $callers; + } else { + printf "Claim asserted on not-in-use block 0x%08x by:\n", $base; + print_callers('', $callers); + } +} + +sub freed { + my ($line, $s_base, $callers) = @_; + my ($base) = interp_pointer($s_base); + return if !$base; + + if (!delete($blocks{$base})) { + printf "Bad free of not-allocated address 0x%08x on stdin:%d by:\n", $base, $line; + print_callers('', $callers); + } +} + +sub print_block { + my ($prefix, $info) = @_; + printf '%s%d-byte block at 0x%08x allocated on stdin:%d by:' . "\n", + $prefix, $info->{SIZE}, $info->{BASE}, $info->{LINE}; + print_callers($prefix, $info->{CALLERS}); +} + +sub print_callers { + my ($prefix, $callers) = @_; + foreach my $pc (split(' ', $callers)) { + print "$prefix\t", lookup_pc($pc), "\n"; + } +} + +our (%cache); +sub lookup_pc { + my ($s_pc) = @_; + if (defined($binary)) { + my ($pc) = hex($s_pc); + my ($output) = "$s_pc: "; + if (!exists($cache{$pc})) { + open(A2L, "$a2l -fe $binary --demangle $s_pc|"); + chomp(my $function = ); + chomp(my $line = ); + close(A2L); + if ($function eq '??') { + ($function, $line) = lookup_pc_by_segment($pc); + } + $line =~ s/^(\.\.\/)*//; + $line = "..." . substr($line, -25) if length($line) > 28; + $cache{$pc} = "$s_pc: $function ($line)"; + } + return $cache{$pc}; + } else { + return "$s_pc"; + } +} + +sub trim_callers { + my ($in) = @_; + my (@out); + foreach my $pc (split(' ', $in)) { + my $xlated = lookup_pc($pc); + if ($xlated =~ /\?\?/) { + push(@out, "...") if !@out || $out[$#out] ne '...'; + } else { + push(@out, $pc); + } + } + return join(' ', @out); +} + +sub search_path { + my ($target) = @_; + for my $dir (split (':', $ENV{PATH})) { + my ($file) = "$dir/$target"; + return $file if -e $file; + } + return undef; +} + +sub add_segment { + my ($vm_start, $vm_end, $vm_pgoff, $file) = @_; + for (my $i = 0; $i <= $#segments; $i++) { + my ($s) = $segments[$i]; + next if $vm_end <= $s->{START} || $vm_start >= $s->{END}; + if ($vm_start <= $s->{START} && $vm_end >= $s->{END}) { + splice(@segments, $i, 1); + --$i; + } else { + $s->{START} = $vm_end if $vm_end > $s->{START}; + $s->{END} = $vm_start if $vm_start <= $s->{END}; + } + } + push(@segments, {START => $vm_start, + END => $vm_end, + PGOFF => $vm_pgoff, + FILE => $file}); + @segments = sort { $a->{START} <=> $b->{START} } @segments; +} + +sub binary_search { + my ($array, $value) = @_; + my $l = 0; + my $r = $#{$array}; + while ($l <= $r) { + my $m = int(($l + $r) / 2); + my $e = $array->[$m]; + if ($value < $e->{START}) { + $r = $m - 1; + } elsif ($value >= $e->{END}) { + $l = $m + 1; + } else { + return $e; + } + } + return undef; +} + +sub read_sections { + my ($file) = @_; + my (@sections); + open(OBJDUMP, "$objdump -h $file|"); + while () { + my $ptr = "([0-9a-fA-F]+)"; + my ($name, $size, $vma, $lma, $file_off) + = /^\s*\d+\s+(\S+)\s+$ptr\s+$ptr\s+$ptr\s+$ptr/ + or next; + push(@sections, {START => hex($file_off), + END => hex($file_off) + hex($size), + NAME => $name}); + } + close(OBJDUMP); + return [sort { $a->{START} <=> $b->{START} } @sections ]; +} + +our %file_to_sections; +sub segment_to_section { + my ($file, $file_offset) = @_; + if (!defined($file_to_sections{$file})) { + $file_to_sections{$file} = read_sections($file); + } + return binary_search($file_to_sections{$file}, $file_offset); +} + +sub address_to_segment { + my ($pc) = @_; + return binary_search(\@segments, $pc); +} + +sub lookup_pc_by_segment { + return ('??', 0) if !defined($objdump); + + my ($pc) = @_; + my ($segment) = address_to_segment($pc); + return ('??', 0) if !defined($segment) || $segment->{FILE} eq ''; + + my ($file_offset) = $pc - $segment->{START} + $segment->{PGOFF}; + my ($section) = segment_to_section($segment->{FILE}, $file_offset); + return ('??', 0) if !defined($section); + + my ($section_offset) = $file_offset - $section->{START}; + open(A2L, sprintf("%s -fe %s --demangle --section=$section->{NAME} 0x%x|", + $a2l, $segment->{FILE}, $section_offset)); + chomp(my $function = ); + chomp(my $line = ); + close(A2L); + + return ($function, $line); +} + +# Local Variables: +# mode: perl +# End: diff --git a/openflow/utilities/ofp-parse-leaks.in b/openflow/utilities/ofp-parse-leaks.in new file mode 100755 index 00000000..059c8509 --- /dev/null +++ b/openflow/utilities/ofp-parse-leaks.in @@ -0,0 +1,285 @@ +#! @PERL@ + +use strict; +use warnings; + +if (grep($_ eq '--help', @ARGV)) { + print < 1; +die "$0: $ARGV[0] does not exist" if @ARGV > 0 && ! -e $ARGV[0]; + +our ($binary); +our ($a2l) = search_path("addr2line"); +my ($no_syms) = "symbols will not be translated"; +if (!@ARGV) { + print "no binary specified; $no_syms\n"; +} elsif (! -e $ARGV[0]) { + print "$ARGV[0] does not exist; $no_syms"; +} elsif (!defined($a2l)) { + print "addr2line not found in PATH; $no_syms"; +} else { + $binary = $ARGV[0]; +} + +our ($objdump) = search_path("objdump"); +print "objdump not found; dynamic library symbols will not be translated\n" + if !defined($objdump); + +our %blocks; +our @segments; +while () { + my $ptr = "((?:0x)?[0-9a-fA-F]+|\\(nil\\))"; + my $callers = ":((?: $ptr)+)"; + if (/^malloc\((\d+)\) -> $ptr$callers$/) { + allocated($., $2, $1, $3); + } elsif (/^claim\($ptr\)$callers$/) { + claimed($., $1, $2); + } elsif (/realloc\($ptr, (\d+)\) -> $ptr$callers$/) { + my ($callers) = $4; + freed($., $1, $callers); + allocated($., $3, $2, $callers); + } elsif (/^free\($ptr\)$callers$/) { + freed($., $1, $2); + } elsif (/^segment: $ptr-$ptr $ptr [-r][-w][-x][sp] (.*)/) { + add_segment(hex($1), hex($2), hex($3), $4); + } else { + print "stdin:$.: syntax error\n"; + } +} +if (%blocks) { + my $n_blocks = scalar(keys(%blocks)); + my $n_bytes = 0; + $n_bytes += $_->{SIZE} foreach values(%blocks); + print "$n_bytes bytes in $n_blocks blocks not freed at end of run\n"; + my %blocks_by_callers; + foreach my $block (values(%blocks)) { + my ($trimmed_callers) = trim_callers($block->{CALLERS}); + push (@{$blocks_by_callers{$trimmed_callers}}, $block); + } + foreach my $callers (sort {@{$b} <=> @{$a}} (values(%blocks_by_callers))) { + $n_blocks = scalar(@{$callers}); + $n_bytes = 0; + $n_bytes += $_->{SIZE} foreach @{$callers}; + print "$n_bytes bytes in these $n_blocks blocks were not freed:\n"; + my $i = 0; + my $max = 5; + foreach my $block (sort {$a->{LINE} <=> $b->{LINE}} (@{$callers})) { + printf "\t%d-byte block at 0x%08x allocated on stdin:%d\n", + $block->{SIZE}, $block->{BASE}, $block->{LINE}; + last if $i++ > $max; + } + print "\t...and ", $n_blocks - $max, " others...\n" + if $n_blocks > $max; + print "The blocks listed above were allocated by:\n"; + print_callers("\t", ${$callers}[0]->{CALLERS}); + } +} +sub interp_pointer { + my ($s_ptr) = @_; + return $s_ptr eq '(nil)' ? 0 : hex($s_ptr); +} + +sub allocated { + my ($line, $s_base, $size, $callers) = @_; + my ($base) = interp_pointer($s_base); + return if !$base; + my ($info) = {LINE => $line, + BASE => $base, + SIZE => $size, + CALLERS => $callers}; + if (exists($blocks{$base})) { + print "In-use address returned by allocator:\n"; + print "\tInitial allocation:\n"; + print_block("\t\t", $blocks{$base}); + print "\tNew allocation:\n"; + print_block("\t\t", $info); + } + $blocks{$base} = $info; +} + +sub claimed { + my ($line, $s_base, $callers) = @_; + my ($base) = interp_pointer($s_base); + return if !$base; + if (exists($blocks{$base})) { + $blocks{$base}{LINE} = $line; + $blocks{$base}{CALLERS} = $callers; + } else { + printf "Claim asserted on not-in-use block 0x%08x by:\n", $base; + print_callers('', $callers); + } +} + +sub freed { + my ($line, $s_base, $callers) = @_; + my ($base) = interp_pointer($s_base); + return if !$base; + + if (!delete($blocks{$base})) { + printf "Bad free of not-allocated address 0x%08x on stdin:%d by:\n", $base, $line; + print_callers('', $callers); + } +} + +sub print_block { + my ($prefix, $info) = @_; + printf '%s%d-byte block at 0x%08x allocated on stdin:%d by:' . "\n", + $prefix, $info->{SIZE}, $info->{BASE}, $info->{LINE}; + print_callers($prefix, $info->{CALLERS}); +} + +sub print_callers { + my ($prefix, $callers) = @_; + foreach my $pc (split(' ', $callers)) { + print "$prefix\t", lookup_pc($pc), "\n"; + } +} + +our (%cache); +sub lookup_pc { + my ($s_pc) = @_; + if (defined($binary)) { + my ($pc) = hex($s_pc); + my ($output) = "$s_pc: "; + if (!exists($cache{$pc})) { + open(A2L, "$a2l -fe $binary --demangle $s_pc|"); + chomp(my $function = ); + chomp(my $line = ); + close(A2L); + if ($function eq '??') { + ($function, $line) = lookup_pc_by_segment($pc); + } + $line =~ s/^(\.\.\/)*//; + $line = "..." . substr($line, -25) if length($line) > 28; + $cache{$pc} = "$s_pc: $function ($line)"; + } + return $cache{$pc}; + } else { + return "$s_pc"; + } +} + +sub trim_callers { + my ($in) = @_; + my (@out); + foreach my $pc (split(' ', $in)) { + my $xlated = lookup_pc($pc); + if ($xlated =~ /\?\?/) { + push(@out, "...") if !@out || $out[$#out] ne '...'; + } else { + push(@out, $pc); + } + } + return join(' ', @out); +} + +sub search_path { + my ($target) = @_; + for my $dir (split (':', $ENV{PATH})) { + my ($file) = "$dir/$target"; + return $file if -e $file; + } + return undef; +} + +sub add_segment { + my ($vm_start, $vm_end, $vm_pgoff, $file) = @_; + for (my $i = 0; $i <= $#segments; $i++) { + my ($s) = $segments[$i]; + next if $vm_end <= $s->{START} || $vm_start >= $s->{END}; + if ($vm_start <= $s->{START} && $vm_end >= $s->{END}) { + splice(@segments, $i, 1); + --$i; + } else { + $s->{START} = $vm_end if $vm_end > $s->{START}; + $s->{END} = $vm_start if $vm_start <= $s->{END}; + } + } + push(@segments, {START => $vm_start, + END => $vm_end, + PGOFF => $vm_pgoff, + FILE => $file}); + @segments = sort { $a->{START} <=> $b->{START} } @segments; +} + +sub binary_search { + my ($array, $value) = @_; + my $l = 0; + my $r = $#{$array}; + while ($l <= $r) { + my $m = int(($l + $r) / 2); + my $e = $array->[$m]; + if ($value < $e->{START}) { + $r = $m - 1; + } elsif ($value >= $e->{END}) { + $l = $m + 1; + } else { + return $e; + } + } + return undef; +} + +sub read_sections { + my ($file) = @_; + my (@sections); + open(OBJDUMP, "$objdump -h $file|"); + while () { + my $ptr = "([0-9a-fA-F]+)"; + my ($name, $size, $vma, $lma, $file_off) + = /^\s*\d+\s+(\S+)\s+$ptr\s+$ptr\s+$ptr\s+$ptr/ + or next; + push(@sections, {START => hex($file_off), + END => hex($file_off) + hex($size), + NAME => $name}); + } + close(OBJDUMP); + return [sort { $a->{START} <=> $b->{START} } @sections ]; +} + +our %file_to_sections; +sub segment_to_section { + my ($file, $file_offset) = @_; + if (!defined($file_to_sections{$file})) { + $file_to_sections{$file} = read_sections($file); + } + return binary_search($file_to_sections{$file}, $file_offset); +} + +sub address_to_segment { + my ($pc) = @_; + return binary_search(\@segments, $pc); +} + +sub lookup_pc_by_segment { + return ('??', 0) if !defined($objdump); + + my ($pc) = @_; + my ($segment) = address_to_segment($pc); + return ('??', 0) if !defined($segment) || $segment->{FILE} eq ''; + + my ($file_offset) = $pc - $segment->{START} + $segment->{PGOFF}; + my ($section) = segment_to_section($segment->{FILE}, $file_offset); + return ('??', 0) if !defined($section); + + my ($section_offset) = $file_offset - $section->{START}; + open(A2L, sprintf("%s -fe %s --demangle --section=$section->{NAME} 0x%x|", + $a2l, $segment->{FILE}, $section_offset)); + chomp(my $function = ); + chomp(my $line = ); + close(A2L); + + return ($function, $line); +} + +# Local Variables: +# mode: perl +# End: diff --git a/openflow/utilities/ofp-pki-cgi.in b/openflow/utilities/ofp-pki-cgi.in new file mode 100755 index 00000000..837b3f92 --- /dev/null +++ b/openflow/utilities/ofp-pki-cgi.in @@ -0,0 +1,41 @@ +#! @PERL@ + +use CGI; +use Digest::SHA1; +use Fcntl; + +$CGI::POST_MAX = 65536; # Limit POSTs to 64 kB. + +use strict; +use warnings; + +my $pkidir = '@PKIDIR@'; +my $q = new CGI; + +die unless $q->request_method() eq 'POST'; + +my $type = $q->param('type'); +die unless defined $type; +die unless $type eq 'switch' or $type eq 'controller'; + +my $req = $q->param('req'); +die unless defined $req; +die unless $req =~ /^-----BEGIN CERTIFICATE REQUEST-----$/m; +die unless $req =~ /^-----END CERTIFICATE REQUEST-----$/m; + +my $digest = Digest::SHA1::sha1_hex($req); +my $incoming = "$pkidir/${type}ca/incoming"; +my $dst = "$incoming/$digest-req.pem"; + +sysopen(REQUEST, "$dst.tmp", O_RDWR | O_CREAT | O_EXCL, 0600) + or die "sysopen $dst.tmp: $!"; +print REQUEST $req; +close(REQUEST) or die "close $dst.tmp: $!"; + +rename("$dst.tmp", $dst) or die "rename $dst.tmp to $dst: $!"; + +print $q->header('text/html', '204 No response'); + +# Local Variables: +# mode: perl +# End: diff --git a/openflow/utilities/ofp-pki.8.in b/openflow/utilities/ofp-pki.8.in new file mode 100644 index 00000000..82558955 --- /dev/null +++ b/openflow/utilities/ofp-pki.8.in @@ -0,0 +1,325 @@ +.TH ofp\-pki 8 "May 2008" "OpenFlow" "OpenFlow Manual" + +.SH NAME +ofp\-pki \- OpenFlow public key infrastructure management utility + +.SH SYNOPSIS +\fBofp\-pki\fR [\fIOPTIONS\fR] \fICOMMAND\fR [\fIARGS\fR] +.sp +Stand\-alone commands with their arguments: +.br +\fBofp\-pki\fR \fBinit\fR +.br +\fBofp\-pki\fR \fBreq\fR \fINAME\fR +.br +\fBofp\-pki\fR \fBsign\fR \fINAME\fR [\fITYPE\fR] +.br +\fBofp\-pki\fR \fBreq+sign\fR \fINAME\fR [\fITYPE\fR] +.br +\fBofp\-pki\fR \fBverify\fR \fINAME\fR [\fITYPE\fR] +.br +\fBofp\-pki\fR \fBfingerprint\fR \fIFILE\fR +.br +\fBofp\-pki\fR \self-sign\fR \fINAME\fR +.sp +The following additional commands manage an online PKI: +.br +\fBofp\-pki\fR \fBls\fR [\fIPREFIX\fR] [\fITYPE\fR] +.br +\fBofp\-pki\fR \fBflush\fR [\fITYPE\fR] +.br +\fBofp\-pki\fR \fBreject\fR \fIPREFIX\fR [\fITYPE\fR] +.br +\fBofp\-pki\fR \fBapprove\fR \fIPREFIX\fR [\fITYPE\fR] +.br +\fBofp\-pki\fR \fBprompt\fR [\fITYPE\fR] +.br +\fBofp\-pki\fR \fBexpire\fR [\fIAGE\fR] +.sp +Each \fITYPE\fR above is a certificate type, either \fBswitch\fR +(default) or \fBcontroller\fR. +.sp +The available options are: +.br +[\fB\-k\fR \fItype\fR | \fB\-\^\-key=\fItype\fR] +[\fB\-B\fR \fInbits\fR | \fB\-\^\-bits=\fInbits\fR] +[\fB\-D\fR \fIfile\fR | \fB\-\^\-dsaparam=\fIfile\fR] +[\fB\-b\fR | \fB\-\^\-batch\fR] +[\fB\-f\fR | \fB\-\^\-force\fR] +[\fB\-d\fR \fIdir\fR | \fB\-\^\-dir=\fR\fIdir\fR] +[\fB\-l\fR \fIfile\fR | \fB\-\^\-log=\fIfile\fR] +[\fB\-h\fR | \fB\-\^\-help\fR] +.br +Some options do not apply to every command. + +.SH DESCRIPTION +The \fBofp\-pki\fR program sets up and manages a public key +infrastructure for use with OpenFlow. It is intended to be a simple +interface for organizations that do not have an established public key +infrastructure. Other PKI tools can substitute for or supplement the +use of \fBofp\-pki\fR. + +\fBofp\-pki\fR uses \fBopenssl\fR(1) for certificate management and key +generation. + +.SH "OFFLINE COMMANDS" + +The following \fBofp\-pki\fR commands support manual PKI +administration: + +.TP +\fBinit\fR +Initializes a new PKI (by default in directory \fB@PKIDIR@\fR) and populates +it with a pair of certificate authorities for controllers and +switches. + +This command should ideally be run on a high\-security machine separate +from any OpenFlow controller or switch, called the CA machine. The +files \fBpki/controllerca/cacert.pem\fR and +\fBpki/switchca/cacert.pem\fR that it produces will need to be copied +over to the OpenFlow switches and controllers, respectively. Their +contents may safely be made public. + +By default, \fBofp\-pki\fR generates 2048\-bit RSA keys. The \fB\-B\fR +or \fB\-\^\-bits\fR option (see below) may be used to override the key +length. The \fB\-k dsa\fR or \fB\-\^\-key=dsa\fR option may be used to use +DSA in place of RSA. If DSA is selected, the \fBdsaparam.pem\fR file +generated in the new PKI hierarchy must be copied to any machine on +which the \fBreq\fR command (see below) will be executed. Its +contents may safely be made public. + +Other files generated by \fBinit\fR may remain on the CA machine. +The files \fBpki/controllerca/private/cakey.pem\fR and +\fBpki/switchca/private/cakey.pem\fR have particularly sensitive +contents that should not be exposed. + +.TP +\fBreq\fR \fINAME\fR +Generates a new private key named \fINAME\fR\fB\-privkey.pem\fR and +corresponding certificate request named \fINAME\fR\fB\-req.pem\fR. +The private key can be intended for use by a switch or a controller. + +This command should ideally be run on the switch or controller that +will use the private key to identify itself. The file +\fINAME\fR\fB\-req.pem\fR must be copied to the CA machine for signing +with the \fBsign\fR command (below). + +This command will output a fingerprint to stdout as its final step. +Write down the fingerprint and take it to the CA machine before +continuing with the \fBsign\fR step. + +When RSA keys are in use (as is the default), \fBreq\fR, unlike the +rest of \fBofp\-pki\fR's commands, does not need access to a PKI +hierarchy created by \fBofp\-pki init\fR. The \fB\-B\fR or +\fB\-\^\-bits\fR option (see below) may be used to specify the number of +bits in the generated RSA key. + +When DSA keys are used (as specified with \fB\-\^\-key=dsa\fR), \fBreq\fR +needs access to the \fBdsaparam.pem\fR file created as part of the PKI +hierarchy (but not to other files in that tree). By default, +\fBofp\-pki\fR looks for this file in \fB@PKIDIR@/dsaparam.pem\fR, but +the \fB\-D\fR or \fB\-\^\-dsaparam\fR option (see below) may be used to +specify an alternate location. + +\fINAME\fR\fB\-privkey.pem\fR has sensitive contents that should not be +exposed. \fINAME\fR\fB\-req.pem\fR may be safely made public. + +.TP +\fBsign\fR \fINAME\fR [\fITYPE\fR] +Signs the certificate request named \fINAME\fR\fB\-req.pem\fR that was +produced in the previous step, producing a certificate named +\fINAME\fR\fB\-cert.pem\fR. \fITYPE\fR, either \fBswitch\fR (default) or +\fBcontroller\fR, indicates the use for which the key is being +certified. + +This command must be run on the CA machine. + +The command will output a fingerprint to stdout and request that you +verify that it is the same fingerprint output by the \fBreq\fR +command. This ensures that the request being signed is the same one +produced by \fBreq\fR. (The \fB\-b\fR or \fB\-\^\-batch\fR option +suppresses the verification step.) + +The file \fINAME\fR\fB\-cert.pem\fR will need to be copied back to the +switch or controller for which it is intended. Its contents may +safely be made public. + +.TP +\fBreq+sign\fR \fINAME\fR [\fITYPE\fR] +Combines the \fBreq\fR and \fBsign\fR commands into a single step, +outputting all the files produced by each. The +\fINAME\fR\fB\-privkey.pem\fR and \fINAME\fR\fB\-cert.pem\fR files must +be copied securely to the switch or controller. +\fINAME\fR\fB\-privkey.pem\fR has sensitive contents and must not be +exposed in transit. Afterward, it should be deleted from the CA +machine. + +This combined method is, theoretically, less secure than the +individual steps performed separately on two different machines, +because there is additional potential for exposure of the private +key. However, it is also more convenient. + +.TP +\fBverify\fR \fINAME\fR [\fITYPE\fR] +Verifies that \fINAME\fR\fB\-cert.pem\fR is a valid certificate for the +given \fITYPE\fR of use, either \fBswitch\fR (default) or +\fBcontroller\fR. If the certificate is valid for this use, it prints +the message ``\fINAME\fR\fB\-cert.pem\fR: OK''; otherwise, it prints an +error message. + +.TP +\fBfingerprint\fR \fIFILE\fR +Prints the fingerprint for \fIFILE\fR. If \fIFILE\fR is a +certificate, then this is the SHA\-1 digest of the DER encoded version +of the certificate; otherwise, it is the SHA\-1 digest of the entire +file. + +.TP +\fBself-sign\fR \fINAME\fR +Signs the certificate request named \fINAME\fB\-req.pem\fR using the +private key \fINAME\fB-privkey.pem\fR, producing a self-signed +certificate named \fINAMEfB\-cert.pem\fR. The input files should have +been produced with \fBofp\-pki req\fR. + +Some controllers accept such self-signed certificates. + +.SH "ONLINE COMMANDS" + +An OpenFlow PKI can be administered online, in conjunction with +.BR ofp\-pki\-cgi (8) +and a web server such as Apache: + +.IP \(bu +The web server exports the contents of the PKI via HTTP. All files in +a PKI hierarchy files may be made public, except for the files +\fBpki/controllerca/private/cakey.pem\fR and +\fBpki/switchca/private/cakey.pem\fR, which must not be exposed. + +.IP \(bu +\fBofp\-pki\-cgi\fR allows newly generated certificate requests for +controllers and switches to be uploaded into the +\fBpki/controllerca/incoming\fR and \fBpki/switchca/incoming\fR +directories, respectively. Uploaded certificate requests are stored +in those directories under names of the form +\fIFINGERPRINT\fB\-req.pem\fR, which \fIFINGERPRINT\fR is the SHA\-1 +hash of the file. + +.IP \(bu +These \fBofp\-pki\fR commands allow incoming certificate requests to +be approved or rejected, in a form are suitable for use by humans or +other software. + +.PP +The following \fBofp\-pki\fR commands support online administration: + +.TP +\fBofp\-pki\fR \fBls\fR [\fIPREFIX\fR] [\fITYPE\fR] +Lists all of the incoming certificate requests of the given \fITYPE\fR +(either \fBswitch\fR, the default, or \fBcontroller\fR). If +\fIPREFIX\fR, which must be at least 4 characters long, is specified, +it causes the list to be limited to files whose names begin with +\fIPREFIX\fR. This is useful, for example, to avoid typing in an +entire fingerprint when checking that a specific certificate request +has been received. + +.TP +\fBofp\-pki\fR \fBflush\fR [\fITYPE\fR] +Deletes all certificate requests of the given \fITYPE\fR. + +.TP +\fBofp\-pki\fR \fBreject\fR \fIPREFIX\fR [\fITYPE\fR] +Rejects the certificate request whose name begins with \fIPREFIX\fR, +which must be at least 4 characters long, of the given type (either +\fBswitch\fR, the default, or \fBcontroller\fR). \fIPREFIX\fR must +match exactly one certificate request; its purpose is to allow the +user to type fewer characters, not to match multiple certificate +requests. + +.TP +\fBofp\-pki\fR \fBapprove\fR \fIPREFIX\fR [\fITYPE\fR] +Approves the certificate request whose name begins with \fIPREFIX\fR, +which must be at least 4 characters long, of the given \fITYPE\fR +(either \fBswitch\fR, the default, or \fBcontroller\fR). \fIPREFIX\fR +must match exactly one certificate request; its purpose is to allow +the user to type fewer characters, not to match multiple certificate +requests. + +The command will output a fingerprint to stdout and request that you +verify that it is correct. (The \fB\-b\fR or \fB\-\^\-batch\fR option +suppresses the verification step.) + +.TP +\fBofp\-pki\fR \fBprompt\fR [\fITYPE\fR] +Prompts the user for each incoming certificate request of the given +\fITYPE\fR (either \fBswitch\fR, the default, or \fBcontroller\fR). +Based on the certificate request's fingerprint, the user is given the +option of approving, rejecting, or skipping the certificate request. + +.TP +\fBofp\-pki\fR \fBexpire\fR [\fIAGE\fR] + +Rejects all the incoming certificate requests, of either type, that is +older than \fIAGE\fR, which must in one of the forms \fIN\fBs\fR, +\fIN\fBmin\fR, \fIN\fBh\fR, \fIN\fBday\fR. The default is \fB1day\fR. + +.SH OPTIONS +.TP +\fB\-k\fR \fItype\fR | \fB\-\^\-key=\fItype\fR +For the \fBinit\fR command, sets the public key algorithm to use for +the new PKI hierarchy. For the \fBreq\fR and \fBreq+sign\fR commands, +sets the public key algorithm to use for the key to be generated, +which must match the value specified on \fBinit\fR. With other +commands, the value has no effect. + +The \fItype\fR may be \fBrsa\fR (the default) or \fBdsa\fR. + +.TP +\fB\-B\fR \fInbits\fR | \fB\-\^\-bits=\fInbits\fR +Sets the number of bits in the key to be generated. When RSA keys are +in use, this option affects only the \fBinit\fR, \fBreq\fR, and +\fBreq+sign\fR commands, and the same value should be given each time. +With DSA keys are in use, this option affects only the \fBinit\fR +command. + +The value must be at least 1024. The default is 2048. + +.TP +\fB\-D\fR \fIfile\fR | \fB\-\^\-dsaparam=\fIfile\fR +Specifies an alternate location for the \fBdsaparam.pem\fR file +required by the \fBreq\fR and \fBreq+sign\fR commands. This option +affects only these commands, and only when DSA keys are used. + +The default is \fBdsaparam.pem\fR under the PKI hierarchy. + +.TP +\fB\-b\fR | \fB\-\^\-batch\fR +Suppresses the interactive verification of fingerprints that the +\fBsign\fR and \fBapprove\fR commands by default require. + +.TP +\fB\-d\fR \fIdir\fR | \fB\-\^\-dir=\fR\fIdir\fR +Specifies the location of the PKI hierarchy to be used or created by +the command (default: \fB@PKIDIR@\fR). All commands, except \fBreq\fR, +need access to a PKI hierarchy. + +.TP +\fB\-f\fR | \fB\-\^\-force\fR +By default, \fBofp\-pki\fR will not overwrite existing files or +directories. This option overrides this behavior. + +.TP +\fB\-l\fR \fIfile\fR | \fB\-\^\-log=\fIfile\fR +Sets the log file to \fIfile\fR. Default: +\fB@LOGDIR@/ofp\-pki.log\fR. + +.TP +\fB\-h\fR | \fB\-\^\-help\fR +Prints a help usage message and exits. + +.SH "SEE ALSO" + +.BR controller (8), +.BR dpctl (8), +.BR ofp\-pki\-cgi (8), +.BR ofprotocol (8), +.BR ofdatapath (8) diff --git a/openflow/utilities/ofp-pki.in b/openflow/utilities/ofp-pki.in new file mode 100755 index 00000000..3a50cff8 --- /dev/null +++ b/openflow/utilities/ofp-pki.in @@ -0,0 +1,582 @@ +#! /bin/sh + +set -e + +pkidir='@PKIDIR@' +command= +prev= +force=no +batch=no +log='@LOGDIR@/ofp-pki.log' +keytype=rsa +bits=2048 +for option; do + # This option-parsing mechanism borrowed from a Autoconf-generated + # configure script under the following license: + + # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, + # 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + # This configure script is free software; the Free Software Foundation + # gives unlimited permission to copy, distribute and modify it. + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + eval $prev=\$option + prev= + continue + fi + case $option in + *=*) optarg=`expr "X$option" : '[^=]*=\(.*\)'` ;; + *) optarg=yes ;; + esac + + case $dashdash$option in + --) + dashdash=yes ;; + -h|--help) + cat <&2 + exit 1 + ;; + *) + if test -z "$command"; then + command=$option + elif test -z "${arg1+set}"; then + arg1=$option + elif test -z "${arg2+set}"; then + arg2=$option + else + echo "$option: only two arguments may be specified" >&2 + exit 1 + fi + ;; + esac + shift +done +if test -n "$prev"; then + option=--`echo $prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $option" >&2 + { (exit 1); exit 1; }; } +fi +if test -z "$command"; then + echo "$0: missing command name; use --help for help" >&2 + exit 1 +fi +if test "$keytype" != rsa && test "$keytype" != dsa; then + echo "$0: argument to -k or --key must be rsa or dsa" + exit 1 +fi +if test "$bits" -lt 1024; then + echo "$0: argument to -B or --bits must be at least 1024" + exit 1 +fi +if test -z "$dsaparam"; then + dsaparam=$pkidir/dsaparam.pem +fi +case $log in + /*) ;; + *) $log="$PWD/$log" ;; +esac + +if test "$command" = "init"; then + if test -e "$pkidir" && test "$force" != "yes"; then + echo "$0: $pkidir already exists and --force not specified" >&2 + exit 1 + fi + + if test ! -d "$pkidir"; then + mkdir -p "$pkidir" + fi + cd "$pkidir" + exec 3>>$log + + if test $keytype = dsa && test ! -e dsaparam.pem; then + echo "Generating DSA parameters, please wait..." >&2 + openssl dsaparam -out dsaparam.pem $bits 1>&3 2>&3 + fi + + # Create the CAs. + for ca in controllerca switchca; do + echo "Creating $ca..." >&2 + oldpwd=$PWD + mkdir -p $ca + cd $ca + + mkdir -p certs crl newcerts + mkdir -p -m 0700 private + mkdir -p -m 0733 incoming + touch index.txt + test -e crlnumber || echo 01 > crlnumber + test -e serial || echo 01 > serial + + # Put DSA parameters in directory. + if test $keytype = dsa && test ! -e dsaparam.pem; then + cp ../dsaparam.pem . + fi + + # Write CA configuration file. + if test ! -e ca.cnf; then + sed "s/@ca@/$ca/g" > ca.cnf <<'EOF' +[ req ] +prompt = no +distinguished_name = req_distinguished_name + +[ req_distinguished_name ] +C = US +ST = CA +L = Palo Alto +O = OpenFlow +OU = @ca@ +CN = OpenFlow @ca@ CA Certificate + +[ ca ] +default_ca = the_ca + +[ the_ca ] +dir = . # top dir +database = $dir/index.txt # index file. +new_certs_dir = $dir/newcerts # new certs dir +certificate = $dir/cacert.pem # The CA cert +serial = $dir/serial # serial no file +private_key = $dir/private/cakey.pem# CA private key +RANDFILE = $dir/private/.rand # random number file +default_days = 365 # how long to certify for +default_crl_days= 30 # how long before next CRL +default_md = md5 # md to use +policy = policy # default policy +email_in_dn = no # Don't add the email into cert DN +name_opt = ca_default # Subject name display option +cert_opt = ca_default # Certificate display option +copy_extensions = none # Don't copy extensions from request + +# For the CA policy +[ policy ] +countryName = optional +stateOrProvinceName = optional +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional +EOF + fi + + # Create certificate authority. + if test $keytype = dsa; then + newkey=dsa:dsaparam.pem + else + newkey=rsa:$bits + fi + openssl req -config ca.cnf -nodes \ + -newkey $newkey -keyout private/cakey.pem -out careq.pem \ + 1>&3 2>&3 + openssl ca -config ca.cnf -create_serial -out cacert.pem \ + -days 1095 -batch -keyfile private/cakey.pem -selfsign \ + -infiles careq.pem 1>&3 2>&3 + chmod 0700 private/cakey.pem + + cd "$oldpwd" + done + exit 0 +fi + +one_arg() { + if test -z "$arg1" || test -n "$arg2"; then + echo "$0: $command must have exactly one argument; use --help for help" >&2 + exit 1 + fi +} + +zero_or_one_args() { + if test -n "$arg2"; then + echo "$0: $command must have zero or one arguments; use --help for help" >&2 + exit 1 + fi +} + +one_or_two_args() { + if test -z "$arg1"; then + echo "$0: $command must have one or two arguments; use --help for help" >&2 + exit 1 + fi +} + +must_not_exist() { + if test -e "$1" && test "$force" != "yes"; then + echo "$0: $1 already exists and --force not supplied" >&2 + exit 1 + fi +} + +resolve_prefix() { + test -n "$type" || exit 123 # Forgot to call check_type? + + case $1 in + ????*) + ;; + *) + echo "Prefix $arg1 is too short (less than 4 hex digits)" + exit 0 + ;; + esac + + fingerprint=$(cd "$pkidir/${type}ca/incoming" && echo "$1"*-req.pem | sed 's/-req\.pem$//') + case $fingerprint in + "${1}*") + echo "No certificate requests matching $1" + exit 1 + ;; + *" "*) + echo "$1 matches more than one certificate request:" + echo $fingerprint | sed 's/ /\ +/g' + exit 1 + ;; + *) + # Nothing to do. + ;; + esac + req="$pkidir/${type}ca/incoming/$fingerprint-req.pem" + cert="$pkidir/${type}ca/certs/$fingerprint-cert.pem" +} + +make_tmpdir() { + TMP=/tmp/ofp-pki.tmp$$ + rm -rf $TMP + trap "rm -rf $TMP" 0 + mkdir -m 0700 $TMP +} + +fingerprint() { + local file=$1 + local name=${1-$2} + local date=$(date -r $file) + local fingerprint + if grep -q -e '-BEGIN CERTIFICATE-' "$file"; then + fingerprint=$(openssl x509 -noout -in "$file" -fingerprint | + sed 's/SHA1 Fingerprint=//' | tr -d ':') + else + fingerprint=$(sha1sum "$file" | awk '{print $1}') + fi + printf "$name\\t$date\\n" + case $file in + $fingerprint*) + printf "\\t(correct fingerprint in filename)\\n" + ;; + *) + printf "\\tfingerprint $fingerprint\\n" + ;; + esac +} + +verify_fingerprint() { + fingerprint "$@" + if test $batch != yes; then + echo "Does fingerprint match? (yes/no)" + read answer + if test "$answer" != yes; then + echo "Match failure, aborting" >&2 + exit 1 + fi + fi +} + +check_type() { + if test x = x"$1"; then + type=switch + elif test "$1" = switch || test "$1" = controller; then + type=$1 + else + echo "$0: type argument must be 'switch' or 'controller'" >&2 + exit 1 + fi +} + +parse_age() { + number=$(echo $1 | sed 's/^\([0-9]\+\)\([[:alpha:]]\+\)/\1/') + unit=$(echo $1 | sed 's/^\([0-9]\+\)\([[:alpha:]]\+\)/\2/') + case $unit in + s) + factor=1 + ;; + min) + factor=60 + ;; + h) + factor=3600 + ;; + day) + factor=86400 + ;; + *) + echo "$1: age not in the form Ns, Nmin, Nh, Nday (e.g. 1day)" >&2 + exit 1 + ;; + esac + echo $(($number * $factor)) +} + +must_exist() { + if test ! -e "$1"; then + echo "$0: $1 does not exist" >&2 + exit 1 + fi +} + +pkidir_must_exist() { + if test ! -e "$pkidir"; then + echo "$0: $pkidir does not exist (need to run 'init' or use '--dir'?)" >&2 + exit 1 + elif test ! -d "$pkidir"; then + echo "$0: $pkidir is not a directory" >&2 + exit 1 + fi +} + +make_request() { + must_not_exist "$arg1-privkey.pem" + must_not_exist "$arg1-req.pem" + make_tmpdir + cat > "$TMP/req.cnf" <&3 2>&3 +} + +sign_request() { + must_exist "$1" + must_not_exist "$2" + pkidir_must_exist + + (cd "$pkidir/${type}ca" && + openssl ca -config ca.cnf -batch -in /dev/stdin) \ + < "$1" > "$2.tmp$$" 2>&3 + mv "$2.tmp$$" "$2" +} + +glob() { + local files=$(echo $1) + if test "$files" != "$1"; then + echo "$files" + fi +} + +exec 3>>$log || true +if test "$command" = req; then + one_arg + + make_request "$arg1" + fingerprint "$arg1-req.pem" +elif test "$command" = sign; then + one_or_two_args + check_type "$arg2" + verify_fingerprint "$arg1-req.pem" + + sign_request "$arg1-req.pem" "$arg2-cert.pem" +elif test "$command" = req+sign; then + one_or_two_args + check_type "$arg2" + + pkidir_must_exist + make_request "$arg1" + sign_request "$arg1-req.pem" "$arg1-cert.pem" + fingerprint "$arg1-req.pem" +elif test "$command" = verify; then + one_or_two_args + must_exist "$arg1-cert.pem" + check_type "$arg2" + + pkidir_must_exist + openssl verify -CAfile "$pkidir/${type}ca/cacert.pem" "$arg1-cert.pem" +elif test "$command" = fingerprint; then + one_arg + + fingerprint "$arg1" +elif test "$command" = self-sign; then + one_arg + must_exist "$arg1-req.pem" + must_exist "$arg1-privkey.pem" + must_not_exist "$arg1-cert.pem" + + openssl x509 -in "$arg1-req.pem" -out "$arg1-cert.pem" \ + -signkey "$arg1-privkey.pem" -req -text 2>&3 +elif test "$command" = ls; then + check_type "$arg2" + + cd "$pkidir/${type}ca/incoming" + for file in $(glob "$arg1*-req.pem"); do + fingerprint $file + done +elif test "$command" = flush; then + check_type "$arg1" + + rm -f "$pkidir/${type}ca/incoming/"* +elif test "$command" = reject; then + one_or_two_args + check_type "$arg2" + resolve_prefix "$arg1" + + rm -f "$req" +elif test "$command" = approve; then + one_or_two_args + check_type "$arg2" + resolve_prefix "$arg1" + + make_tmpdir + cp "$req" "$TMP/$req" + verify_fingerprint "$TMP/$req" + sign_request "$TMP/$req" + rm -f "$req" "$TMP/$req" +elif test "$command" = prompt; then + zero_or_one_args + check_type "$arg1" + + make_tmpdir + cd "$pkidir/${type}ca/incoming" + for req in $(glob "*-req.pem"); do + cp "$req" "$TMP/$req" + + cert=$(echo "$pkidir/${type}ca/certs/$req" | + sed 's/-req.pem/-cert.pem/') + if test -f $cert; then + echo "Request $req already approved--dropping duplicate request" + rm -f "$req" "$TMP/$req" + continue + fi + + echo + echo + fingerprint "$TMP/$req" "$req" + printf "Disposition for this request (skip/approve/reject)? " + read answer + case $answer in + approve) + echo "Approving $req" + sign_request "$TMP/$req" "$cert" + rm -f "$req" "$TMP/$req" + ;; + r*) + echo "Rejecting $req" + rm -f "$req" "$TMP/$req" + ;; + *) + echo "Skipping $req" + ;; + esac + done +elif test "$command" = expire; then + zero_or_one_args + cutoff=$(($(date +%s) - $(parse_age ${arg1-1day}))) + for type in switch controller; do + cd "$pkidir/${type}ca/incoming" || exit 1 + for file in $(glob "*"); do + time=$(date -r "$file" +%s) + if test "$time" -lt "$cutoff"; then + rm -f "$file" + fi + done + done +else + echo "$0: $command command unknown; use --help for help" >&2 + exit 1 +fi diff --git a/openflow/utilities/vlogconf.8.in b/openflow/utilities/vlogconf.8.in new file mode 100644 index 00000000..eb9c192e --- /dev/null +++ b/openflow/utilities/vlogconf.8.in @@ -0,0 +1,183 @@ +.ds PN vlogconf + +.TH vlogconf 8 "June 2008" "OpenFlow" "OpenFlow Manual" + +.SH NAME +vlogconf \- configuration utility for OpenFlow logging in userspace + +.SH SYNOPSIS +\fBvlogconf\fR [\fB-h\fR | \fB--help\fR] [\fItarget\fR...] [\fIaction\fR...] +.sp 1 +The available \fItarget\fR options are: +.br +[\fB-a\fR | \fB--all\fR] [\fB-t\fR \fIpid\fR | \fB--target=\fIpid\fR] +.sp 1 +The available \fIaction\fR options are: +.br +[\fB-l\fR | \fB--list\fR] [\fB-s\fR +\fImodule\fR[\fB:\fIfacility\fR[\fB:\fIlevel\fR]] | +\fB--set=\fImodule\fR[\fB:\fIfacility\fR[\fB:\fIlevel\fR]]] +[\fB-r\fR | \fB--reopen\fR] + +.SH DESCRIPTION +The \fBvlogconf\fR program configures the logging system used by +OpenFlow userspace programs. The logging configuration may be modified +while OpenFlow programs are running. + +\fBvlogconf\fR applies one or more actions to each of one or more +target processes. Targets may be specified as: + +.TP +\fB-a\fR, \fB--all\fR +All running processes that \fBvlogconf\fR can control. + +.TP +\fB-t \fItarget\fR, \fB--target=\fItarget\fR +The specified \fItarget\fR, which must take one of the following forms: + +.RS +.IP \(bu +A PID (process ID). + +.IP \(bu +An absolute path (beginning with `/') to the Unix domain socket for a +\fBvlogconf\fR-controllable process. + +.IP \(bu +An absolute path (beginning with `/') to a pidfile (created by, e.g., +passing the \fB-P\fR or \fB--pidfile\fR option to one of the OpenFlow +programs). + +.IP \(bu +None of the above, in which case \fItarget\fR prefixed by +\fB@RUNDIR@/\fR must match one of the cases for absolute paths listed +above. (The default name for a program's pidfile is +\fB@RUNDIR@/\fIprogram\fB.pid\fR, so this means that, say, +\fBofprotocol\fR's default pidfile may be referred to simply as +\fBofprotocol.pid\fR.) +.RE + +.PP +The available actions are: + +.TP +\fB-l\fR, \fB--list\fR +Print the list of known modules and their current logging levels to +stdout. + +.TP +\fB-s\fR \fImodule\fR[\fB:\fIfacility\fR[\fB:\fIlevel\fR]], \fB--set=\fImodule\fR[\fB:\fIfacility\fR[\fB:\fIlevel\fR]] + +Sets the logging level for \fImodule\fR in \fIfacility\fR to +\fIlevel\fR. The \fImodule\fR may be any valid module name (as +displayed by the \fB--list\fR option) or the special name \fBANY\fR to +set the logging levels for all modules. The \fIfacility\fR may be +\fBsyslog\fR or \fBconsole\fR to set the levels for logging to the +system log or to the console, respectively, or \fBANY\fR to set the +logging levels for both facilities. If it is omitted, +\fIfacility\fR defaults to \fBANY\fR. The \fIlevel\fR must be one of +\fBemer\fR, \fBerr\fR, \fBwarn\fR, \fBinfo\fR, or \fBdbg\fR, designating the +minimum severity of a message for it to be logged. If it is omitted, +\fIlevel\fR defaults to \fBdbg\fR. + +.TP +\fB-s PATTERN:\fIfacility\fB:\fIpattern\fR, \fB--set=PATTERN:\fIfacility\fB:\fIpattern\fR + +Sets the log pattern for \fIfacility\fR to \fIpattern\fR. Each time a +message is logged to \fIfacility\fR, \fIpattern\fR determines the +message's formatting. Most characters in \fIpattern\fR are copied +literally to the log, but special escapes beginning with \fB%\fR are +expanded as follows: + +.RS +.TP +\fB%A\fR +The name of the application logging the message, e.g. \fBofprotocol\fR. + +.TP +\fB%c\fR +The name of the module (as shown by \fBvlogconf --list\fR) logging +the message. + +.TP +\fB%d\fR +The current date and time in ISO 8601 format (YYYY-MM-DD HH:MM:SS). + +.TP +\fB%d{\fIformat\fB}\fR +The current date and time in the specified \fIformat\fR, which takes +the same format as the \fItemplate\fR argument to \fBstrftime\fR(3). + +.TP +\fB%m\fR +The message being logged. + +.TP +\fB%N\fR +A serial number for this message within this run of the program, as a +decimal number. The first message a program logs has serial number 1, +the second one has serial number 2, and so on. + +.TP +\fB%n\fR +A new-line. + +.TP +\fB%p\fR +The level at which the message is logged, e.g. \fBDBG\fR. + +.TP +\fB%P\fR +The program's process ID (pid), as a decimal number. + +.TP +\fB%r\fR +The number of milliseconds elapsed from the start of the application +to the time the message was logged. + +.TP +\fB%%\fR +A literal \fB%\fR. +.RE + +.IP +A few options may appear between the \fB%\fR and the format specifier +character, in this order: + +.RS +.TP +\fB-\fR +Left justify the escape's expansion within its field width. Right +justification is the default. + +.TP +\fB0\fR +Pad the field to the field width with \fB0\fRs. Padding with spaces +is the default. + +.TP +\fIwidth\fR +A number specifies the minimum field width. If the escape expands to +fewer characters than \fIwidth\fR then it is padded to fill the field +width. (A field wider than \fIwidth\fR is not truncated to fit.) +.RE + +.IP +The default pattern for console output is \fB%d{%b %d +%H:%M:%S}|%05N|%c|%p|%m\fR; for syslog output, \fB%05N|%c|%p|%m\fR. + +.TP +\fB-r\fR, \fB--reopen\fR +Causes the target application to close and reopen its log file. (This +is useful after rotating log files, to cause a new log file to be +used.) + +.SH OPTIONS + +.so lib/common.man + +.SH "SEE ALSO" + +.BR dpctl (8), +.BR ofprotocol (8), +.BR controller (8) diff --git a/openflow/utilities/vlogconf.c b/openflow/utilities/vlogconf.c new file mode 100644 index 00000000..5c48f724 --- /dev/null +++ b/openflow/utilities/vlogconf.c @@ -0,0 +1,235 @@ +/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ +#include +#include "vlog.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "command-line.h" +#include "compiler.h" +#include "timeval.h" +#include "util.h" +#include "vlog-socket.h" + +static void +usage(char *prog_name, int exit_code) +{ + printf("Usage: %s [TARGET] [ACTION...]\n" + "Targets:\n" + " -a, --all Apply to all targets (default)\n" + " -t, --target=TARGET Specify target program, as a pid, a\n" + " pidfile, or an absolute path to a Unix\n" + " domain socket\n" + "Actions:\n" + " -l, --list List current settings\n" + " -s, --set=MODULE[:FACILITY[:LEVEL]]\n" + " Set MODULE and FACILITY log level to LEVEL\n" + " MODULE may be any valid module name or 'ANY'\n" + " FACILITY may be 'syslog', 'console', 'file', or 'ANY' (default)\n" + " LEVEL may be 'emer', 'err', 'warn', 'info', or 'dbg' (default)\n" + " -r, --reopen Make the program reopen its log file\n" + " -h, --help Print this helpful information\n", + prog_name); + exit(exit_code); +} + +static char * +transact(struct vlog_client *client, const char *request, bool *ok) +{ + char *reply; + int error = vlog_client_transact(client, request, &reply); + if (error) { + fprintf(stderr, "%s: transaction error: %s\n", + vlog_client_target(client), strerror(error)); + *ok = false; + } + return reply ? reply : xstrdup(""); +} + +static void +transact_ack(struct vlog_client *client, const char* request, bool *ok) +{ + char *reply; + int error = vlog_client_transact(client, request, &reply); + if (error) { + fprintf(stderr, "%s: transaction error: %s\n", + vlog_client_target(client), strerror(error)); + *ok = false; + } else if (strcmp(reply, "ack")) { + fprintf(stderr, "Received unexpected reply from %s: %s\n", + vlog_client_target(client), reply); + *ok = false; + } + free(reply); +} + +static void +add_target(struct vlog_client ***clients, size_t *n_clients, + const char *path, bool *ok) +{ + struct vlog_client *client; + int error = vlog_client_connect(path, &client); + if (error) { + fprintf(stderr, "Error connecting to \"%s\": %s\n", + path, strerror(error)); + *ok = false; + } else { + *clients = xrealloc(*clients, sizeof *clients * (*n_clients + 1)); + (*clients)[*n_clients] = client; + ++*n_clients; + } +} + +static void +add_all_targets(struct vlog_client ***clients, size_t *n_clients, bool *ok) +{ + DIR *directory; + struct dirent* de; + + directory = opendir("/tmp"); + if (!directory) { + fprintf(stderr, "/tmp: opendir: %s\n", strerror(errno)); + } + + while ((de = readdir(directory)) != NULL) { + if (!strncmp(de->d_name, "vlogs.", 5)) { + char *path = xasprintf("/tmp/%s", de->d_name); + add_target(clients, n_clients, path, ok); + free(path); + } + } + + closedir(directory); +} + +int main(int argc, char *argv[]) +{ + static const struct option long_options[] = { + /* Target options must come first. */ + {"all", no_argument, NULL, 'a'}, + {"target", required_argument, NULL, 't'}, + {"help", no_argument, NULL, 'h'}, + + /* Action options come afterward. */ + {"list", no_argument, NULL, 'l'}, + {"set", required_argument, NULL, 's'}, + {"reopen", no_argument, NULL, 'r'}, + {0, 0, 0, 0}, + }; + char *short_options; + + /* Determine targets. */ + bool ok = true; + int n_actions = 0; + struct vlog_client **clients = NULL; + size_t n_clients = 0; + + set_program_name(argv[0]); + time_init(); + + short_options = long_options_to_short_options(long_options); + for (;;) { + int option; + size_t i; + + option = getopt_long(argc, argv, short_options, long_options, NULL); + if (option == -1) { + break; + } + if (!strchr("ath", option) && n_clients == 0) { + ofp_fatal(0, "no targets specified (use --help for help)"); + } else { + ++n_actions; + } + switch (option) { + case 'a': + add_all_targets(&clients, &n_clients, &ok); + break; + + case 't': + add_target(&clients, &n_clients, optarg, &ok); + break; + + case 'l': + for (i = 0; i < n_clients; i++) { + struct vlog_client *client = clients[i]; + char *reply; + + printf("%s:\n", vlog_client_target(client)); + reply = transact(client, "list", &ok); + fputs(reply, stdout); + free(reply); + } + break; + + case 's': + for (i = 0; i < n_clients; i++) { + struct vlog_client *client = clients[i]; + char *request = xasprintf("set %s", optarg); + transact_ack(client, request, &ok); + free(request); + } + break; + + case 'r': + for (i = 0; i < n_clients; i++) { + struct vlog_client *client = clients[i]; + char *request = xstrdup("reopen"); + transact_ack(client, request, &ok); + free(request); + } + break; + + case 'h': + usage(argv[0], EXIT_SUCCESS); + break; + + case '?': + exit(EXIT_FAILURE); + + default: + NOT_REACHED(); + } + } + if (!n_actions) { + fprintf(stderr, + "warning: no actions specified (use --help for help)\n"); + } + exit(ok ? 0 : 1); +} diff --git a/openflow/utilities/wireshark_dissectors/Makefile b/openflow/utilities/wireshark_dissectors/Makefile new file mode 100644 index 00000000..cf82d045 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/Makefile @@ -0,0 +1,32 @@ +# simple Makefile to build and install all of our Wireshark plugins + +# build a list of all sub-directories except the includes path +PLUGIN_DIRS = $(shell ls -l | grep "^d" | cut -d: -f2- | cut -d\ -f2 | fgrep -v 'wireshark-1.0.0-includes') +CLEAN_PLUGIN_DIRS = $(foreach dir,$(PLUGIN_DIRS),clean$(dir)) +INSTALL_PLUGIN_DIRS = $(foreach dir,$(PLUGIN_DIRS),install$(dir)) + +.PHONY: all $(PLUGIN_DIRS) clean $(CLEAN_PLUGIN_DIRS) install $(INSTALL_PLUGIN_DIRS) + +# build all the plugins +all: + @$(MAKE) --no-print-directory $(PLUGIN_DIRS) + +# cleanup all the byproducts (including the plugin itself) +clean: + @$(MAKE) --no-print-directory $(CLEAN_PLUGIN_DIRS) + +# install all plugins +install: + @$(MAKE) --no-print-directory $(INSTALL_PLUGIN_DIRS) + +# build the plugin in the specified directory using its default rule +$(PLUGIN_DIRS): + @$(MAKE) --no-print-directory -C $@ + +# cleans up the plugin in the specified directory using its 'clean' rule +$(CLEAN_PLUGIN_DIRS): + @$(MAKE) --no-print-directory -C `echo $@ | sed -e "s#^clean##"` clean + +# installs up the plugin in the specified directory using its 'install' rule +$(INSTALL_PLUGIN_DIRS): + @$(MAKE) --no-print-directory -C `echo $@ | sed -e "s#^install##"` install diff --git a/openflow/utilities/wireshark_dissectors/README b/openflow/utilities/wireshark_dissectors/README new file mode 100644 index 00000000..0aac13dd --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/README @@ -0,0 +1,37 @@ +README: OpenFlow Wireshark Plugin + + + +---------------------------------------- +I) Installation + +1) Install glib-devel; on Debian this can be done with 'sudo apt-get install libgtk2.0-dev' +2) Install wireshark v1.0.0 or greater +3) cd wireshark_dissectors/openflow +4) make +5) sudo make install +5a) Note that this prints out where the plugin was installed. + + +---------------------------------------- +II) Installation Verification + +1) Run wireshark +2) Open the "Help" --> "About" menu +3) Select the "Plugins" tab +4) Click the "Name" header to the plugins by name +5) Verify that "packet-openflow.so" appears in the list. +6) Verify that its version is listed as . + + +---------------------------------------- +III) Port Changes + +To have the dissector handle OpenFlow packets for any port other than the default, you must change the DISSECT_PORT variable in utilities/wireshark_dissectors/oepnflow/Makefile. + +---------------------------------------- +IV) Feedback and Bug Reporting + +Please post a message on the OpenFlow forums at openflowswitch.org or email +David Underhill at dgu@cs.stanford.edu if you have any feedback or discover any +bugs. diff --git a/openflow/utilities/wireshark_dissectors/openflow/.gitignore b/openflow/utilities/wireshark_dissectors/openflow/.gitignore new file mode 100644 index 00000000..aa1ec1ea --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/openflow/.gitignore @@ -0,0 +1 @@ +*.tgz diff --git a/openflow/utilities/wireshark_dissectors/openflow/Makefile b/openflow/utilities/wireshark_dissectors/openflow/Makefile new file mode 100644 index 00000000..8c533ce9 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/openflow/Makefile @@ -0,0 +1,79 @@ +WIRESHARK_SRC_DIR = ../wireshark-1.0.0-includes + +SRCS = packet-openflow.c plugin.c +CC = gcc +OBJS = $(foreach src, $(SRCS), $(src:.c=.o)) + +PLUGIN_NAME = packet-openflow + +# local installation path +LOCAL_PLUGIN_DIR = /home/$(shell whoami)/.wireshark/plugins + +# determine global installation path (use latest plugin version path) +ifneq ($(wildcard /usr/local/lib/wireshark/plugins),) + GLOBAL_PLUGIN_DIR_PARTIAL=/usr/local/lib/wireshark/plugins +else ifneq ($(wildcard /usr/lib/wireshark/plugins),) + GLOBAL_PLUGIN_DIR_PARTIAL=/usr/lib/wireshark/plugins +endif + +# Work out if there are version-specific subdirectories +GLOBAL_PLUGIN_DIR_FILES := $(wildcard $(GLOBAL_PLUGIN_DIR_PARTIAL)/*) +GLOBAL_PLUGIN_DIR_SUBDIRS := $(foreach file,$(GLOBAL_PLUGIN_DIR_FILES),$(dir $(wildcard $(file)/.))) +GLOBAL_PLUGIN_DIR_SUBDIRS := $(subst $(GLOBAL_PLUGIN_DIR_PARTIAL)/,,$(GLOBAL_PLUGIN_DIR_SUBDIRS)) +GLOBAL_PLUGIN_DIR_SUBDIRS := $(subst /,,$(GLOBAL_PLUGIN_DIR_SUBDIRS)) + +# Assume that the "last" directory is the one we ant to use if it exists +GLOBAL_PLUGIN_VER := $(lastword $(sort $(GLOBAL_PLUGIN_DIR_SUBDIRS))) + +# Create the actual global plugin dir to use +ifneq ($(GLOBAL_PLUGIN_VER),) + GLOBAL_PLUGIN_DIR=$(GLOBAL_PLUGIN_DIR_PARTIAL)/$(GLOBAL_PLUGIN_VER) +else + GLOBAL_PLUGIN_DIR=$(GLOBAL_PLUGIN_DIR_PARTIAL) +endif + +# specify the port on which event capture packets will be destined +DISSECT_PORT = -DOPENFLOW_DST_TCP_PORT=6633 + +OSTYPE = $(shell uname) +ifeq ($(OSTYPE),Linux) +ENDIAN=-D_LITTLE_ENDIAN_ +endif +ifeq ($(OSTYPE),SunOS) +ENDIAN=-D_BIG_ENDIAN_ +endif + +INC_GLIB=$(shell pkg-config --cflags glib-2.0) +INC_OPENFLOW=../../../include + +INC_DIRS = -I. $(INC_GLIB) -I$(INC_OPENFLOW) +CFLAGS = $(INC_DIRS) -DHAVE_CONFIG_H -I$(WIRESHARK_SRC_DIR) -I/usr/local/include -I/usr/local/include -DINET6 -D_U_=__attribute__\(\(unused\)\) -Wall -Wpointer-arith -g -I/usr/local/include -DXTHREADS -D_REENTRANT -DXUSE_MTSAFE_API -pthread -I/usr/include/gtk-2.0 -I/usr/lib/gtk-2.0/include -I/usr/X11R6/include -I/usr/include/atk-1.0 -I/usr/include/pango-1.0 -I/usr/include/freetype2 -I/usr/include/freetype2/config -I/usr/local/include/glib-2.0 -I/usr/lib/glib-2.0/include -fPIC -DPIC $(ENDIAN) $(DISSECT_PORT) + +LDFLAGS = -Wl,--rpath -Wl,/usr/local/lib -Wl,--rpath -Wl,/usr/local/lib -L/usr/local/lib -L$(WIRESHARK_SRC_DIR)/epan -L. -lgmodule-2.0 -ldl -lglib-2.0 -pthread -Wl,--export-dynamic -Wl,-soname -Wl,$(PLUGIN_NAME).so + +.PHONY: clean install + +$(PLUGIN_NAME).so : $(OBJS) $(SRCS) + $(CC) -shared $(OBJS) $(LDFLAGS) -o $@ + +install: $(PLUGIN_NAME).so + @if [ `id -u` -eq 0 ]; then \ + if [ -d "$(GLOBAL_PLUGIN_DIR)" ]; then \ + target="$(GLOBAL_PLUGIN_DIR)/$<"; \ + res="*** Installed plugin for ALL users ($$target)"; \ + else \ + echo "*** Error: global plugin directory $(GLOBAL_PLUGIN_DIR) does not exist"; \ + exit 1; \ + fi; \ + else \ + mkdir -p "$(LOCAL_PLUGIN_DIR)/"; \ + target="$(LOCAL_PLUGIN_DIR)/$<"; \ + res="*** Installed plugin for user "`id | cut -d\( -f2 | cut -d\) -f1`" ($$target)"; \ + fi; \ + install --mode=644 $< "$$target" && echo "" && echo "" && echo "$$res" && echo "" && echo "" + +plugin.c: moduleinfo.h Makefile.am Makefile.common + $(MAKE) -f Makefile.am + +clean: + rm -f $(PLUGIN) $(OBJS) $(PLUGIN_NAME).so diff --git a/openflow/utilities/wireshark_dissectors/openflow/Makefile.am b/openflow/utilities/wireshark_dissectors/openflow/Makefile.am new file mode 100644 index 00000000..be972bd8 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/openflow/Makefile.am @@ -0,0 +1,110 @@ +# Makefile.am +# Automake file for H.223 plugin +# +# $Id: Makefile.am 21961 2007-05-27 18:35:55Z guy $ +# +# Wireshark - Network traffic analyzer +# By Gerald Combs +# Copyright 1998 Gerald Combs + +srcdir = . +top_srcdir = ../wireshark-1.0.0-includes +includedir = ../wireshark-1.0.0-includes +INCLUDES = -I$(top_srcdir) -I$(includedir) + +include Makefile.common + +#if HAVE_WARNINGS_AS_ERRORS +#AM_CFLAGS = -Werror +#endif + +plugindir = ~/.wireshark/plugins + +plugin_LTLIBRARIES = hsapi.la +hsapi_la_SOURCES = \ + plugin.c \ + moduleinfo.h \ + $(DISSECTOR_SRC) \ + $(DISSECTOR_SUPPORT_SRC) \ + $(DISSECTOR_INCLUDES) +openflow_la_LDFLAGS = -module -avoid-version +openflow_la_LIBADD = @PLUGIN_LIBS@ + +# Libs must be cleared, or else libtool won't create a shared module. +# If your module needs to be linked against any particular libraries, +# add them here. +LIBS = + +# +# Build plugin.c, which contains the plugin version[] string, a +# function plugin_register() that calls the register routines for all +# protocols, and a function plugin_reg_handoff() that calls the handoff +# registration routines for all protocols. +# +# We do this by scanning sources. If that turns out to be too slow, +# maybe we could just require every .o file to have an register routine +# of a given name (packet-aarp.o -> proto_register_aarp, etc.). +# +# Formatting conventions: The name of the proto_register_* routines an +# proto_reg_handoff_* routines must start in column zero, or must be +# preceded only by "void " starting in column zero, and must not be +# inside #if. +# +# DISSECTOR_SRC is assumed to have all the files that need to be scanned. +# +# For some unknown reason, having a big "for" loop in the Makefile +# to scan all the files doesn't work with some "make"s; they seem to +# pass only the first few names in the list to the shell, for some +# reason. +# +# Therefore, we have a script to generate the plugin.c file. +# The shell script runs slowly, as multiple greps and seds are run +# for each input file; this is especially slow on Windows. Therefore, +# if Python is present (as indicated by PYTHON being defined), we run +# a faster Python script to do that work instead. +# +# The first argument is the directory in which the source files live. +# The second argument is "plugin", to indicate that we should build +# a plugin.c file for a plugin. +# All subsequent arguments are the files to scan. +# +plugin.c: $(DISSECTOR_SRC) $(top_srcdir)/tools/make-dissector-reg \ + $(top_srcdir)/tools/make-dissector-reg.py + @if test -n $(PYTHON); then \ + echo Making plugin.c with python ; \ + $(PYTHON) $(top_srcdir)/tools/make-dissector-reg.py $(srcdir) \ + plugin $(DISSECTOR_SRC) ; \ + else \ + echo Making plugin.c with shell script ; \ + $(top_srcdir)/tools/make-dissector-reg $(srcdir) \ + $(plugin_src) plugin $(DISSECTOR_SRC) ; \ + fi + +# +# Currently plugin.c can be included in the distribution because +# we always build all protocol dissectors. We used to have to check +# whether or not to build the snmp dissector. If we again need to +# variably build something, making plugin.c non-portable, uncomment +# the dist-hook line below. +# +# Oh, yuk. We don't want to include "plugin.c" in the distribution, as +# its contents depend on the configuration, and therefore we want it +# to be built when the first "make" is done; however, Automake insists +# on putting *all* source into the distribution. +# +# We work around this by having a "dist-hook" rule that deletes +# "plugin.c", so that "dist" won't pick it up. +# +#dist-hook: +# @rm -f $(distdir)/plugin.c + +CLEANFILES = \ + openflow \ + *~ + +MAINTAINERCLEANFILES = \ + Makefile.in \ + plugin.c + +EXTRA_DIST = \ + Makefile.common diff --git a/openflow/utilities/wireshark_dissectors/openflow/Makefile.common b/openflow/utilities/wireshark_dissectors/openflow/Makefile.common new file mode 100644 index 00000000..26c43d26 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/openflow/Makefile.common @@ -0,0 +1,13 @@ +# the name of the plugin +PLUGIN_NAME = openflow + +# the dissector sources (without any helpers) +DISSECTOR_SRC = packet-openflow.c + +# corresponding headers +DISSECTOR_INCLUDES = + +# Dissector helpers. They're included in the source files in this +# directory, but they're not dissectors themselves, i.e. they're not +# used to generate "register.c"). +DISSECTOR_SUPPORT_SRC = diff --git a/openflow/utilities/wireshark_dissectors/openflow/build_distribution_tarball.sh b/openflow/utilities/wireshark_dissectors/openflow/build_distribution_tarball.sh new file mode 100755 index 00000000..d6b1ae05 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/openflow/build_distribution_tarball.sh @@ -0,0 +1,63 @@ +#!/bin/bash +set -o errexit +set -o nounset + +# if user specifies a folder, cd to it +if [ $# -ne 0 ]; then + cd $1 +fi + +# sanity check: make sure script is running from within the plugin build directory +origdir=`pwd` +topdir=wireshark_dissectors +if [ "$topdir" != `dirname $origdir | sed -e "s#.*/##"` ]; then + echo "Error: script must be run from within the plugin's subdirectory with $topdir" + exit 1 +fi + +# sanity check: make sure build works +rm -f *.so +make > /dev/null 2> /dev/null +plugin=`grep 'PLUGIN_NAME =' Makefile | sed -e "s#PLUGIN_NAME =##" -e "s# ##g"`.so +if [ ! -f $plugin ]; then + echo "Error: make failed to build $plugin" + exit 1 +fi + +# make a temporary folder for the build file +tmpdir=/tmp/.$$ +builddir="$tmpdir/$topdir/openflow" +mkdir $tmpdir + +# copy the wireshark plugin directory to the temp folder +cp -r ../ "$tmpdir/$topdir" + +# add the openflow header to the build folder which is in the include search path +cp ../../../include/openflow/openflow.h "$builddir/" + +# cleanup the contents of the build folder +cd "$builddir" +make clean +rm -f *.tgz $0 + +# get the version of the plugin +version=`grep '#define VERSION' moduleinfo.h | cut -d\" -f2` + +# replace tag in README with date information' +date=`date` +cat ../README | sed -e "s##Plugin Version: $version#g" > ../tmp +cat ../tmp | sed -e "s##Distribution Creation Date: $date#g" > ../README + +# make a tarball from the build folder +tarball="openflow-wireshark-dissector-v$version.tar.gz" +cd ../../ +tar -zcf "$tarball" "$topdir" + +# put the tarball back in the original directory +mv "$tarball" "$origdir/" + +# cleanup the temporary folder +rm -rf "$tmpdir" + +# tell the user what we created +echo "tarballed release is now ready: $tarball" diff --git a/openflow/utilities/wireshark_dissectors/openflow/moduleinfo.h b/openflow/utilities/wireshark_dissectors/openflow/moduleinfo.h new file mode 100644 index 00000000..b7bd7f5e --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/openflow/moduleinfo.h @@ -0,0 +1,15 @@ +/* Included *after* config.h, in order to re-define these macros */ + +#ifdef PACKAGE +#undef PACKAGE +#endif + +/* Name of package */ +#define PACKAGE "openflow" + +#ifdef VERSION +#undef VERSION +#endif + +/* Version number of package */ +#define VERSION "1.0.0" /* OpenFlowMajor.OpenFlowMinor.PluginRevForThisMajorMinorRev */ diff --git a/openflow/utilities/wireshark_dissectors/openflow/packet-openflow.c b/openflow/utilities/wireshark_dissectors/openflow/packet-openflow.c new file mode 100644 index 00000000..aea00f88 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/openflow/packet-openflow.c @@ -0,0 +1,3426 @@ +/** + * Filename: packet-openflow.c + * Author: David Underhill + * Changelog: + * dgu 2008-Aug-26 created + * brandonh 2008-Oct-5 updated to 0x95 + * brandonh 2008-Nov-25 updated to 0x96 + bugfixes + * tyabe 2009-May-20 added vlan_pcp_match + * + * Defines a Wireshark 1.0.0+ dissector for the OpenFlow protocol version 0x98. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** the version of openflow this dissector was written for */ +#define DISSECTOR_OPENFLOW_MIN_VERSION OFP_VERSION +#define DISSECTOR_OPENFLOW_MAX_VERSION OFP_VERSION +#define DISSECTOR_OPENFLOW_VERSION_DRAFT_THRESHOLD OFP_VERSION + +/** if 0, padding bytes will not be shown in the dissector */ +#define SHOW_PADDING 0 + +#define PROTO_TAG_OPENFLOW "OFP" + +/* Wireshark ID of the OPENFLOW protocol */ +static int proto_openflow = -1; +static dissector_handle_t openflow_handle; +static void dissect_openflow(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); + +/* traffic will arrive with TCP port OPENFLOW_DST_TCP_PORT */ +#define TCP_PORT_FILTER "tcp.port" +static int global_openflow_proto = OPENFLOW_DST_TCP_PORT; + +/* try to find the ethernet dissector to dissect encapsulated Ethernet data */ +static dissector_handle_t data_ethernet; + +/* AM=Async message, CSM=Control/Switch Message, SM=Symmetric Message */ +/** names to bind to various values in the type field */ +static const value_string names_ofp_type[] = { + /* Immutable messages. */ + { OFPT_HELLO, "Hello (SM)" }, + { OFPT_ERROR, "Error (SM)" }, + { OFPT_ECHO_REQUEST, "Echo Request (SM)" }, + { OFPT_ECHO_REPLY, "Echo Reply (SM)" }, + { OFPT_VENDOR, "Vendor (SM)" }, + + /* Switch configuration messages. */ + { OFPT_FEATURES_REQUEST, "Features Request (CSM)" }, + { OFPT_FEATURES_REPLY, "Features Reply (CSM)" }, + { OFPT_GET_CONFIG_REQUEST, "Get Config Request (CSM)" }, + { OFPT_GET_CONFIG_REPLY, "Get Config Reply (CSM)" }, + { OFPT_SET_CONFIG, "Set Config (CSM)" }, + + /* Asynchronous messages. */ + { OFPT_PACKET_IN, "Packet In (AM)" }, + { OFPT_FLOW_REMOVED, "Flow Removed (AM)" }, + { OFPT_PORT_STATUS, "Port Status (AM)" }, + + /* Controller command messages. */ + { OFPT_PACKET_OUT, "Packet Out (CSM)" }, + { OFPT_FLOW_MOD, "Flow Mod (CSM)" }, + { OFPT_PORT_MOD, "Port Mod (CSM)" }, + + /* Statistics messages. */ + { OFPT_STATS_REQUEST, "Stats Request (CSM)" }, + { OFPT_STATS_REPLY, "Stats Reply (CSM)" }, + + /* Barrier messages. */ + { OFPT_BARRIER_REQUEST, "Barrier Request (CSM)" }, + { OFPT_BARRIER_REPLY, "Barrier Reply (CSM)" }, + + { OFPT_QUEUE_GET_CONFIG_REQUEST, "Get Queue Config Request (CSM)" }, + { OFPT_QUEUE_GET_CONFIG_REPLY, "Get Queue Config Reply (CSM)" }, + + { 0, NULL } +}; +#define OFP_TYPE_MAX_VALUE OFPT_QUEUE_GET_CONFIG_REPLY + +/** names from ofp_action_type */ +static const value_string names_ofp_action_type[] = { + { OFPAT_OUTPUT, "Output to switch port" }, + { OFPAT_SET_VLAN_VID, "Set the 802.1q VLAN id." }, + { OFPAT_SET_VLAN_PCP, "Set the 802.1q priority." }, + { OFPAT_STRIP_VLAN, "Strip the 802.1q header." }, + { OFPAT_SET_DL_SRC, "Ethernet source address" }, + { OFPAT_SET_DL_DST, "Ethernet destination address" }, + { OFPAT_SET_NW_SRC, "IP source address" }, + { OFPAT_SET_NW_DST, "IP destination address" }, + { OFPAT_SET_NW_TOS, "Set IP TOS field" }, + { OFPAT_SET_TP_SRC, "TCP/UDP source port" }, + { OFPAT_SET_TP_DST, "TCP/UDP destination port"}, + { OFPAT_ENQUEUE, "Enqueue to port queue" }, + { OFPAT_VENDOR, "Vendor-defined action"}, + { 0, NULL } +}; +#define NUM_ACTIONS_FLAGS 12 +#define NUM_PORT_CONFIG_FLAGS 7 +#define NUM_PORT_STATE_FLAGS 1 +#define NUM_PORT_FEATURES_FLAGS 12 +#define NUM_WILDCARDS 12 +#define NUM_CAPABILITIES_FLAGS 8 +#define NUM_FLOW_MOD_FLAGS 3 +#define NUM_SF_REPLY_FLAGS 1 + +/** yes/no for bitfields field */ +static const value_string names_choice[] = { + { 0, "No" }, + { 1, "Yes" }, + { 0, NULL } +}; + +/** wildcard or not for bitfields field */ +static const value_string wildcard_choice[] = { + { 0, "Exact" }, + { 1, "Wildcard" }, + { 0, NULL } +}; + +/** wildcard or not for bitfields field */ +static const value_string ts_wildcard_choice[] = { + { 0, "Exact only" }, + { 1, "Wildcard allowed" }, + { 0, NULL } +}; + +/** names from ofp_flow_mod_command */ +static const value_string names_flow_mod_command[] = { + { OFPFC_ADD, "New flow" }, + { OFPFC_MODIFY, "Modify all matching flows" }, + { OFPFC_MODIFY_STRICT, "Modify entry strictly matching wildcards" }, + { OFPFC_DELETE, "Delete all matching flows" }, + { OFPFC_DELETE_STRICT, "Delete entry strictly matching wildcards and priority" }, + { 0, NULL } +}; + +/** names of stats_types */ +static const value_string names_stats_types[] = { + { OFPST_DESC, "Description of this OpenFlow switch" }, + { OFPST_FLOW, "Individual flow statistics" }, + { OFPST_AGGREGATE, "Aggregate flow statistics" }, + { OFPST_TABLE, "Flow table statistics" }, + { OFPST_PORT, "Physical port statistics" }, + { OFPST_QUEUE, "Queue statistics" }, + { OFPST_VENDOR, "Vendor extension" }, + { 0, NULL } +}; + +/** names from ofp_flow_mod_command */ +static const value_string names_ofp_port_reason[] = { + { OFPPR_ADD, "The port was added" }, + { OFPPR_DELETE, "The port was removed" }, + { OFPPR_MODIFY, "Some attribute of the port has changed" }, + { 0, NULL } +}; + +/** names from ofp_packet_in_reason */ +static const value_string names_ofp_packet_in_reason[] = { + { OFPR_NO_MATCH, "No matching flow" }, + { OFPR_ACTION, "Action explicitly output to controller" }, + { 0, NULL } +}; + +/** names from ofp_flow_removed_reason */ +static const value_string names_ofp_flow_removed_reason[] = { + { OFPRR_IDLE_TIMEOUT, "Flow idle time exceeded idle_timeout" }, + { OFPRR_HARD_TIMEOUT, "Time exceeded hard_timeout" }, + { OFPRR_DELETE, "Evicted by a DELETE flow mod." }, + { 0, NULL } +}; + +/** names from ofp_flow_removed_reason */ +static const value_string names_ip_frag[] = { + { OFPC_FRAG_NORMAL, "No special handling for fragments." }, + { OFPC_FRAG_DROP, "Drop fragments." }, + { OFPC_FRAG_REASM, "Reassemble (only if OFPC_IP_REASM set)" }, + { 0, NULL } +}; + +/** names from ofp_error_type */ +static const value_string names_ofp_error_type_reason[] = { + { OFPET_HELLO_FAILED, "Hello protocol failed" }, + { OFPET_BAD_REQUEST, "Request was not understood" }, + { OFPET_BAD_ACTION, "Error in action description" }, + { OFPET_FLOW_MOD_FAILED, "Problem modifying flow entry" }, + { OFPET_PORT_MOD_FAILED, "Port mod request failed" }, + { OFPET_QUEUE_OP_FAILED, "Problem during queue operation" }, + { 0, NULL } +}; + +static const value_string names_ofp_packet_queue_property_type[] = { + { OFPQT_NONE, "No-op Property" }, + { OFPQT_MIN_RATE, "Min Rate Queue" }, + { 0, NULL } +}; + + +/** Address masks */ +static const value_string addr_mask[] = { + { 0, "/32" }, + { 1, "/31" }, + { 2, "/30" }, + { 3, "/29" }, + { 4, "/28" }, + { 5, "/27" }, + { 6, "/26" }, + { 7, "/25" }, + { 8, "/24" }, + { 9, "/23" }, + { 10, "/22" }, + { 11, "/21" }, + { 12, "/20" }, + { 13, "/19" }, + { 14, "/18" }, + { 15, "/17" }, + { 16, "/16" }, + { 17, "/15" }, + { 18, "/14" }, + { 19, "/13" }, + { 20, "/12" }, + { 21, "/11" }, + { 22, "/10" }, + { 23, "/9" }, + { 24, "/8" }, + { 25, "/7" }, + { 26, "/6" }, + { 27, "/5" }, + { 28, "/4" }, + { 29, "/3" }, + { 30, "/2" }, + { 31, "/1" }, + { 32, "/0" }, + { 63, "/0" }, + { 0, NULL } +}; + +/** Address masks */ +static const value_string ts_addr_mask[] = { + { 0, "Exact only" }, + { 63, "Wildcard allowed" }, + { 0, NULL } +}; + +/** Switch config frag values */ +static const value_string sc_frag_choices[] = { + { 0, "No special fragment handling" }, + { 1, "Drop fragments" }, + { 2, "Reassemble (only if OFPC_IP_REASM set)" }, + { 0, NULL } +}; + + +/* Error strings for the various error types */ +static const gchar *hello_failed_err_str[] = {"No compatible version", + "Permissions error"}; + +#define N_HELLOFAILED (sizeof hello_failed_err_str / sizeof hello_failed_err_str[0]) + +static const gchar *bad_request_err_str[] = {"ofp_header.version not supported", + "ofp_header.type not supported", + "ofp_stats_request.type not supported", + "Vendor not supported (in ofp_vendor or ofp_stats_request or ofp_stats_reply)", + "Vendor subtype not supported", + "Permissions error", + "Wrong request length for type", + "Specified buffer has already been used", + "Specified buffer does not exist"}; + +#define N_BADREQUEST (sizeof bad_request_err_str / sizeof bad_request_err_str[0]) + +static const gchar *bad_action_err_str[] = {"Unknown action type", + "Length problem in actions", + "Unknown vendor id specified", + "Unknown action type for vendor id", + "Problem validating output action", + "Bad action argument", + "Permissions error", + "Can't handle this many actions", + "Problem validating output queue"}; + +#define N_BADACTION (sizeof bad_action_err_str / sizeof bad_action_err_str[0]) + +static const gchar *flow_mod_failed_err_str[] = {"Flow not added because of full tables", + "Flow not added because of conflicting entry in tables", + "Permissions error", + "Flow not added because of non-zero idle/hard timeout", + "Unknown command", + "Unsupported action list - cannot process in the order specified"}; + +#define N_FLOWMODFAILED (sizeof flow_mod_failed_err_str / sizeof flow_mod_failed_err_str[0]) + +static const gchar *port_mod_failed_err_str[] = {"Specified port does not exist", + "Specified hardware address is wrong"}; + +#define N_PORTMODFAILED (sizeof port_mod_failed_err_str / sizeof port_mod_failed_err_str[0]) + +static const gchar *queue_op_failed_err_str[] = {"Parent port does not exist", + "queue does not exist", + "Permissions error"}; + +#define N_QUEUEOPFAILED (sizeof queue_op_failed_err_str / sizeof queue_op_failed_err_str[0]) + +/* ICMP definitions from wireshark source: epan/dissectors/packet-ip.c */ +/* ICMP definitions */ + +#define ICMP_ECHOREPLY 0 +#define ICMP_UNREACH 3 +#define ICMP_SOURCEQUENCH 4 +#define ICMP_REDIRECT 5 +#define ICMP_ECHO 8 +#define ICMP_RTRADVERT 9 +#define ICMP_RTRSOLICIT 10 +#define ICMP_TIMXCEED 11 +#define ICMP_PARAMPROB 12 +#define ICMP_TSTAMP 13 +#define ICMP_TSTAMPREPLY 14 +#define ICMP_IREQ 15 +#define ICMP_IREQREPLY 16 +#define ICMP_MASKREQ 17 +#define ICMP_MASKREPLY 18 + +/* ICMP UNREACHABLE */ + +#define ICMP_NET_UNREACH 0 /* Network Unreachable */ +#define ICMP_HOST_UNREACH 1 /* Host Unreachable */ +#define ICMP_PROT_UNREACH 2 /* Protocol Unreachable */ +#define ICMP_PORT_UNREACH 3 /* Port Unreachable */ +#define ICMP_FRAG_NEEDED 4 /* Fragmentation Needed/DF set */ +#define ICMP_SR_FAILED 5 /* Source Route failed */ +#define ICMP_NET_UNKNOWN 6 +#define ICMP_HOST_UNKNOWN 7 +#define ICMP_HOST_ISOLATED 8 +#define ICMP_NET_ANO 9 +#define ICMP_HOST_ANO 10 +#define ICMP_NET_UNR_TOS 11 +#define ICMP_HOST_UNR_TOS 12 +#define ICMP_PKT_FILTERED 13 /* Packet filtered */ +#define ICMP_PREC_VIOLATION 14 /* Precedence violation */ +#define ICMP_PREC_CUTOFF 15 /* Precedence cut off */ + +static const gchar *unreach_str[] = {"Network unreachable", + "Host unreachable", + "Protocol unreachable", + "Port unreachable", + "Fragmentation needed", + "Source route failed", + "Destination network unknown", + "Destination host unknown", + "Source host isolated", + "Network administratively prohibited", + "Host administratively prohibited", + "Network unreachable for TOS", + "Host unreachable for TOS", + "Communication administratively filtered", + "Host precedence violation", + "Precedence cutoff in effect"}; + +#define N_UNREACH (sizeof unreach_str / sizeof unreach_str[0]) + +static const gchar *redir_str[] = {"Redirect for network", + "Redirect for host", + "Redirect for TOS and network", + "Redirect for TOS and host"}; + +#define N_REDIRECT (sizeof redir_str / sizeof redir_str[0]) + +static const gchar *ttl_str[] = {"Time to live exceeded in transit", + "Fragment reassembly time exceeded"}; + +#define N_TIMXCEED (sizeof ttl_str / sizeof ttl_str[0]) + +static const gchar *par_str[] = {"IP header bad", "Required option missing"}; + +#define N_PARAMPROB (sizeof par_str / sizeof par_str[0]) + + +/* ARP definitions from wireshark source: epan/dissectors/packet-arp.c */ +/* ARP / RARP structs and definitions */ +#ifndef ARPOP_REQUEST +#define ARPOP_REQUEST 1 /* ARP request. */ +#endif +#ifndef ARPOP_REPLY +#define ARPOP_REPLY 2 /* ARP reply. */ +#endif +/* Some OSes have different names, or don't define these at all */ +#ifndef ARPOP_RREQUEST +#define ARPOP_RREQUEST 3 /* RARP request. */ +#endif +#ifndef ARPOP_RREPLY +#define ARPOP_RREPLY 4 /* RARP reply. */ +#endif +#ifndef ARPOP_IREQUEST +#define ARPOP_IREQUEST 8 /* Inverse ARP (RFC 1293) request. */ +#endif +#ifndef ARPOP_IREPLY +#define ARPOP_IREPLY 9 /* Inverse ARP reply. */ +#endif +#ifndef ATMARPOP_NAK +#define ATMARPOP_NAK 10 /* ATMARP NAK. */ +#endif + +static const value_string names_arp_opcode[] = { + {ARPOP_REQUEST, "request" }, + {ARPOP_REPLY, "reply" }, + {ARPOP_RREQUEST, "reverse request"}, + {ARPOP_RREPLY, "reverse reply" }, + {ARPOP_IREQUEST, "inverse request"}, + {ARPOP_IREPLY, "inverse reply" }, + {0, NULL } }; + +/* These variables are used to hold the IDs of our fields; they are + * set when we call proto_register_field_array() in proto_register_openflow() + */ +static gint ofp = -1; +static gint ofp_pad = -1; +static gint ofp_port = -1; + +/* OpenFlow Header */ +static gint ofp_header = -1; +static gint ofp_header_version = -1; +static gint ofp_header_type = -1; +static gint ofp_header_length = -1; +static gint ofp_header_xid = -1; +static gint ofp_header_warn_ver = -1; +static gint ofp_header_warn_type = -1; + +/* Common Structures */ +static gint ofp_phy_port = -1; +static gint ofp_phy_port_port_no = -1; +static gint ofp_phy_port_hw_addr = -1; +static gint ofp_phy_port_name = -1; +static gint ofp_phy_port_config_hdr = -1; +static gint ofp_phy_port_config[NUM_PORT_CONFIG_FLAGS]; +static gint ofp_phy_port_state_hdr = -1; +// the following array is EVIL!!!!! do not use, or a curse upon your family. +static gint ofp_phy_port_state[NUM_PORT_STATE_FLAGS]; +// seriously, don't use this bit. +static gint ofp_phy_port_state_not_evil = -1; +static gint ofp_phy_port_state_stp_state = -1; +static gint ofp_phy_port_curr_hdr = -1; +static gint ofp_phy_port_curr[NUM_PORT_FEATURES_FLAGS]; +static gint ofp_phy_port_advertised_hdr = -1; +static gint ofp_phy_port_advertised[NUM_PORT_FEATURES_FLAGS]; +static gint ofp_phy_port_supported_hdr = -1; +static gint ofp_phy_port_supported[NUM_PORT_FEATURES_FLAGS]; +static gint ofp_phy_port_peer_hdr = -1; +static gint ofp_phy_port_peer[NUM_PORT_FEATURES_FLAGS]; + +static gint ofp_match = -1; +static gint ofp_match_wildcards_hdr = -1; +static gint ofp_match_wildcards[NUM_WILDCARDS]; +static gint ofp_match_in_port = -1; +static gint ofp_match_dl_src = -1; +static gint ofp_match_dl_dst = -1; +static gint ofp_match_dl_vlan = -1; +static gint ofp_match_dl_vlan_pcp = -1; +static gint ofp_match_dl_type = -1; +static gint ofp_match_nw_src = -1; +static gint ofp_match_nw_dst = -1; +static gint ofp_match_nw_tos = -1; +static gint ofp_match_nw_proto = -1; +static gint ofp_match_arp_opcode= -1; +static gint ofp_match_tp_src = -1; +static gint ofp_match_tp_dst = -1; +static gint ofp_match_icmp_type = -1; +static gint ofp_match_icmp_code = -1; +static gint ofp_match_nw_src_mask_bits = -1; +static gint ofp_match_nw_dst_mask_bits = -1; + +static gint ofp_action = -1; +static gint ofp_action_type = -1; +static gint ofp_action_len = -1; +static gint ofp_action_vlan_vid = -1; +static gint ofp_action_vlan_pcp = -1; +static gint ofp_action_dl_addr = -1; +static gint ofp_action_nw_addr = -1; +static gint ofp_action_nw_tos = -1; +static gint ofp_action_tp_port = -1; +static gint ofp_action_vendor = -1; +static gint ofp_action_unknown = -1; +static gint ofp_action_warn = -1; +static gint ofp_action_num = -1; + +/* type: ofp_action_output */ +static gint ofp_action_output = -1; +static gint ofp_action_output_port = -1; +static gint ofp_action_output_max_len = -1; + +/* type: ofp_action_enqueue */ +static gint ofp_action_enqueue = -1; +static gint ofp_action_enqueue_port_no = -1; +static gint ofp_action_enqueue_queue_id = -1; + +/* Controller/Switch Messages */ +static gint ofp_switch_features = -1; +static gint ofp_switch_features_datapath_id = -1; +static gint ofp_switch_features_n_buffers = -1; +static gint ofp_switch_features_n_tables = -1; +static gint ofp_switch_features_capabilities_hdr = -1; +static gint ofp_switch_features_capabilities[NUM_CAPABILITIES_FLAGS]; +static gint ofp_switch_features_actions_hdr = -1; +static gint ofp_switch_features_actions[NUM_ACTIONS_FLAGS]; +static gint ofp_switch_features_actions_warn = -1; +// are these two necessary? +static gint ofp_switch_features_ports_hdr = -1; +static gint ofp_switch_features_ports_num = -1; +static gint ofp_switch_features_ports_warn = -1; + +static gint ofp_switch_config = -1; +static gint ofp_switch_config_flags_hdr = -1; +static gint ofp_switch_config_flags_ip_frag = -1; +static gint ofp_switch_config_miss_send_len = -1; + +static gint ofp_queue_get_config_request = -1; +static gint ofp_queue_get_config_request_port_no = -1; + +// there is no limit at the no of queues/port. 1024 is safe for now. +static gint ofp_queue_get_config_reply = -1; +static gint ofp_queue_get_config_reply_port_no = -1; +static gint ofp_queue_get_config_reply_queues_hdr = -1; +static gint ofp_queue_get_config_reply_queues_num = -1; + +static gint ofp_packet_queue = -1; +static gint ofp_packet_queue_queue_id = -1; +static gint ofp_packet_queue_len = -1; +static gint ofp_packet_queue_warn = -1; + +static gint ofp_packet_queue_property = -1; +static gint ofp_packet_queue_property_len = -1; +static gint ofp_packet_queue_property_type = -1; +static gint ofp_packet_queue_property_rate = -1; +static gint ofp_packet_queue_properties_hdr = -1; +static gint ofp_packet_queue_properties_num = -1; +static gint ofp_packet_queue_property_unknown = -1; +static gint ofp_packet_queue_property_warn = -1; + +static gint ofp_flow_mod = -1; +/* field: ofp_match */ +static gint ofp_flow_mod_cookie = -1; +static gint ofp_flow_mod_command = -1; +static gint ofp_flow_mod_idle_timeout = -1; +static gint ofp_flow_mod_hard_timeout = -1; +static gint ofp_flow_mod_priority = -1; +static gint ofp_flow_mod_buffer_id = -1; +static gint ofp_flow_mod_out_port = -1; +static gint ofp_flow_mod_flags[NUM_FLOW_MOD_FLAGS]; + +static gint ofp_port_mod = -1; +static gint ofp_port_mod_port_no = -1; +static gint ofp_port_mod_hw_addr = -1; +static gint ofp_port_mod_config_hdr = -1; +static gint ofp_port_mod_config[NUM_PORT_CONFIG_FLAGS]; +static gint ofp_port_mod_mask_hdr = -1; +static gint ofp_port_mod_mask[NUM_PORT_CONFIG_FLAGS]; +static gint ofp_port_mod_advertise_hdr = -1; +static gint ofp_port_mod_advertise[NUM_PORT_FEATURES_FLAGS]; + +static gint ofp_stats_request = -1; +static gint ofp_stats_request_type = -1; +static gint ofp_stats_request_flags = -1; +static gint ofp_stats_request_body = -1; + +static gint ofp_stats_reply = -1; +static gint ofp_stats_reply_type = -1; +static gint ofp_stats_reply_flags = -1; +static gint ofp_stats_reply_flag[NUM_SF_REPLY_FLAGS]; +static gint ofp_stats_reply_body = -1; + +static gint ofp_desc_stats = -1; +static gint ofp_desc_stats_mfr_desc = -1; +static gint ofp_desc_stats_hw_desc = -1; +static gint ofp_desc_stats_sw_desc = -1; +static gint ofp_desc_stats_dp_desc = -1; +static gint ofp_desc_stats_serial_num = -1; + +static gint ofp_flow_stats_request = -1; +/* field: ofp_match */ +static gint ofp_flow_stats_request_table_id = -1; +static gint ofp_flow_stats_request_out_port = -1; + +static gint ofp_flow_stats_reply = -1; +/* length won't be put in the tree */ +static gint ofp_flow_stats_reply_table_id = -1; +/* field: ofp_match */ +static gint ofp_flow_stats_reply_duration_sec = -1; +static gint ofp_flow_stats_reply_duration_nsec = -1; +static gint ofp_flow_stats_reply_cookie = -1; +static gint ofp_flow_stats_reply_priority = -1; +static gint ofp_flow_stats_reply_idle_timeout = -1; +static gint ofp_flow_stats_reply_hard_timeout = -1; +static gint ofp_flow_stats_reply_packet_count = -1; +static gint ofp_flow_stats_reply_byte_count = -1; +/* field: ofp_actions */ + +static gint ofp_aggr_stats_request = -1; +/* field: ofp_match */ +static gint ofp_aggr_stats_request_table_id = -1; + +static gint ofp_aggr_stats_reply = -1; +static gint ofp_aggr_stats_reply_packet_count = -1; +static gint ofp_aggr_stats_reply_byte_count = -1; +static gint ofp_aggr_stats_reply_flow_count = -1; + +static gint ofp_table_stats = -1; +static gint ofp_table_stats_table_id = -1; +static gint ofp_table_stats_name = -1; +static gint ofp_table_stats_wildcards_hdr = -1; +static gint ofp_table_stats_wildcards[NUM_WILDCARDS]; +static gint ofp_table_stats_max_entries = -1; +static gint ofp_table_stats_active_count = -1; +static gint ofp_table_stats_lookup_count = -1; +static gint ofp_table_stats_matched_count = -1; + +static gint ofp_port_stats_request = -1; +static gint ofp_port_stats_request_port_no = -1; +static gint ofp_port_stats = -1; +static gint ofp_port_stats_port_no = -1; +static gint ofp_port_stats_rx_packets = -1; +static gint ofp_port_stats_tx_packets = -1; +static gint ofp_port_stats_rx_bytes = -1; +static gint ofp_port_stats_tx_bytes = -1; +static gint ofp_port_stats_rx_dropped = -1; +static gint ofp_port_stats_tx_dropped = -1; +static gint ofp_port_stats_rx_errors = -1; +static gint ofp_port_stats_tx_errors = -1; +static gint ofp_port_stats_rx_frame_err = -1; +static gint ofp_port_stats_rx_over_err = -1; +static gint ofp_port_stats_rx_crc_err = -1; +static gint ofp_port_stats_collisions = -1; + +static gint ofp_queue_stats_request = -1; + +static gint ofp_queue_stats = -1; +static gint ofp_queue_stats_port_no = -1; +static gint ofp_queue_stats_queue_id = -1; +static gint ofp_queue_stats_tx_bytes = -1; +static gint ofp_queue_stats_tx_packets = -1; +static gint ofp_queue_stats_tx_errors = -1; + +static gint ofp_vendor_stats = -1; +static gint ofp_vendor_stats_vendor = -1; +static gint ofp_vendor_stats_body = -1; + +static gint ofp_packet_out = -1; +static gint ofp_packet_out_buffer_id = -1; +static gint ofp_packet_out_in_port = -1; +static gint ofp_packet_out_actions_len = -1; +static gint ofp_packet_out_actions_hdr = -1; +static gint ofp_packet_out_data_hdr = -1; + +/* Asynchronous Messages */ +static gint ofp_packet_in = -1; +static gint ofp_packet_in_buffer_id = -1; +static gint ofp_packet_in_total_len = -1; +static gint ofp_packet_in_in_port = -1; +static gint ofp_packet_in_reason = -1; +static gint ofp_packet_in_data_hdr = -1; + +static gint ofp_flow_removed = -1; +/* field: ofp_match */ +static gint ofp_flow_removed_cookie = -1; +static gint ofp_flow_removed_priority = -1; +static gint ofp_flow_removed_reason = -1; +static gint ofp_flow_removed_duration_sec = -1; +static gint ofp_flow_removed_duration_nsec = -1; +static gint ofp_flow_removed_idle_timeout = -1; +static gint ofp_flow_removed_packet_count = -1; +static gint ofp_flow_removed_byte_count = -1; + +static gint ofp_port_status = -1; +static gint ofp_port_status_reason = -1; +/* field: ofp_phy_port desc */ + +static gint ofp_error_msg = -1; +static gint ofp_error_msg_type = -1; +static gint ofp_error_msg_code = -1; +static gint ofp_error_msg_data = -1; +static gint ofp_error_msg_data_str = -1; + +static gint ofp_echo = -1; +static gint ofp_vendor = -1; + +/* These are the ids of the subtrees that we may be creating */ +static gint ett_ofp = -1; + +/* Open Flow Header */ +static gint ett_ofp_header = -1; + +/* Common Structures */ +static gint ett_ofp_phy_port = -1; +static gint ett_ofp_phy_port_config_hdr = -1; +static gint ett_ofp_phy_port_state_hdr = -1; +static gint ett_ofp_phy_port_curr_hdr = -1; +static gint ett_ofp_phy_port_advertised_hdr = -1; +static gint ett_ofp_phy_port_supported_hdr = -1; +static gint ett_ofp_phy_port_peer_hdr = -1; +static gint ett_ofp_match = -1; +static gint ett_ofp_match_wildcards_hdr = -1; +static gint ett_ofp_action = -1; +static gint ett_ofp_action_output = -1; +static gint ett_ofp_action_enqueue = -1; +static gint ett_ofp_packet_queue_root = -1; +static gint ett_ofp_packet_queue = -1; +static gint ett_ofp_packet_queue_property = -1; +static gint ett_ofp_packet_queue_properties_hdr = -1; + +/* Controller/Switch Messages */ +static gint ett_ofp_switch_features = -1; +static gint ett_ofp_switch_features_capabilities_hdr = -1; +static gint ett_ofp_switch_features_actions_hdr = -1; +static gint ett_ofp_switch_features_ports_hdr = -1; +static gint ett_ofp_switch_config = -1; +static gint ett_ofp_switch_config_flags_hdr = -1; +static gint ett_ofp_flow_mod = -1; +static gint ett_ofp_flow_mod_flags_hdr = -1; +static gint ett_ofp_port_mod = -1; +static gint ett_ofp_port_mod_config_hdr = -1; +static gint ett_ofp_port_mod_mask_hdr = -1; +static gint ett_ofp_port_mod_advertise_hdr = -1; + +static gint ett_ofp_queue_get_config_request = -1; +static gint ett_ofp_queue_get_config_reply = -1; +static gint ett_ofp_queue_get_config_reply_queues_hdr = -1; + +static gint ett_ofp_stats_request = -1; +static gint ett_ofp_stats_reply = -1; +static gint ett_ofp_stats_reply_flags = -1; +static gint ett_ofp_desc_stats = -1; +static gint ett_ofp_flow_stats_request = -1; +static gint ett_ofp_flow_stats_reply = -1; +static gint ett_ofp_aggr_stats_request = -1; +static gint ett_ofp_aggr_stats_reply = -1; +static gint ett_ofp_table_stats = -1; +static gint ett_ofp_port_stats_request = -1; +static gint ett_ofp_queue_stats_request = -1; +static gint ett_ofp_port_stats = -1; +static gint ett_ofp_queue_stats = -1; +static gint ett_ofp_vendor_stats = -1; +static gint ett_ofp_packet_out = -1; +static gint ett_ofp_packet_out_actions_hdr = -1; +static gint ett_ofp_packet_out_data_hdr = -1; + +/* Asynchronous Messages */ +static gint ett_ofp_packet_in = -1; +static gint ett_ofp_packet_in_data_hdr = -1; +static gint ett_ofp_flow_removed = -1; +static gint ett_ofp_port_status = -1; +static gint ett_ofp_error_msg = -1; +static gint ett_ofp_error_msg_data = -1; + +void proto_reg_handoff_openflow() +{ + openflow_handle = create_dissector_handle(dissect_openflow, proto_openflow); + dissector_add(TCP_PORT_FILTER, global_openflow_proto, openflow_handle); +} + +#define NO_STRINGS NULL +#define NO_MASK 0x0 + +/** Returns newly allocated string with two spaces in front of str. */ +static inline char* indent( char* str ) { + char* ret = malloc( strlen(str) + 3 ); + ret[0] = ' '; + ret[1] = ' '; + memcpy( &ret[2], str, strlen(str) + 1 ); + return ret; +} + +void proto_register_openflow() +{ + data_ethernet = find_dissector("eth"); + + /* initialize uninitialized header fields */ + int i; + for( i=0; i= 0)) + return names_ofp_type[type].strptr; + else { + snprintf( str_unknown, 17, "Unknown Type %u", type ); + return str_unknown; + } +} + +/** + * Adds "hf" to "tree" starting at "offset" into "tvb" and using "length" + * bytes. offset is incremented by length. + */ +static void add_child( proto_item* tree, gint hf, tvbuff_t *tvb, guint32* offset, guint32 len ) { + proto_tree_add_item( tree, hf, tvb, *offset, len, FALSE ); + *offset += len; +} + +/** + * Adds "hf" to "tree" starting at "offset" into "tvb" and using "length" + * bytes. offset is incremented by length. The specified string is used as the + * field's display value. + */ +static void add_child_str(proto_item* tree, gint hf, tvbuff_t *tvb, guint32* offset, guint32 len, const char* str) { + proto_tree_add_string(tree, hf, tvb, *offset, len, str); + *offset += len; +} + +/** + * Adds "hf" to "tree" starting at "offset" into "tvb" and using "length" + * bytes. The specified string is used as the + * field's display value. + */ +static void add_child_str_const(proto_item* tree, gint hf, tvbuff_t *tvb, guint32 offset, guint32 len, const char* str) { + proto_tree_add_string(tree, hf, tvb, offset, len, str); +} + + +/** + * Adds "hf" to "tree" starting at "offset" into "tvb" and using "length" bytes. + */ +static void add_child_const( proto_item* tree, gint hf, tvbuff_t *tvb, guint32 offset, guint32 len ) { + proto_tree_add_item( tree, hf, tvb, offset, len, FALSE ); +} + +/** returns the length of a PDU which starts at the specified offset in tvb. */ +static guint get_openflow_message_len(packet_info *pinfo, tvbuff_t *tvb, int offset) { + return (guint)tvb_get_ntohs(tvb, offset+2); /* length is at offset 2 in the header */ +} + +static void dissect_pad(proto_tree* tree, guint32 *offset, guint pad_byte_count) { +#if SHOW_PADDING + guint i; + for( i=0; i 0) { + port_item = proto_tree_add_item(tree, ofp_phy_port, tvb, *offset, sizeof(struct ofp_phy_port), FALSE); + port_tree = proto_item_add_subtree(port_item, ett_ofp_phy_port); + + dissect_port( port_tree, ofp_phy_port_port_no, tvb, offset ); + add_child( port_tree, ofp_phy_port_hw_addr, tvb, offset, OFP_ETH_ALEN ); + add_child( port_tree, ofp_phy_port_name, tvb, offset, OFP_MAX_PORT_NAME_LEN ); + + /* config */ + config_item = proto_tree_add_item(port_tree, ofp_phy_port_config_hdr, tvb, *offset, 4, FALSE); + config_tree = proto_item_add_subtree(config_item, ett_ofp_phy_port_config_hdr); + for(i=0; iname, get_tcp_port(port), port); + + *offset += 2; +} + +/* Based on: dissect_icmp from wireshark: epan/dissectors/packet-ip.c */ +static void dissect_icmp_type_code_match(proto_tree* tree, tvbuff_t *tvb, guint32 *offset, gint show_type, gint show_code) +{ + guint16 icmp_type; + guint16 icmp_code; + const gchar *type_str, *code_str; + + type_str=""; + code_str=""; + + /* Get the ICMP type/code */ + icmp_type = tvb_get_ntohs(tvb, *offset); + icmp_code = tvb_get_ntohs(tvb, *offset + 2); + + /* Get string representations of the ICMP types/codes */ + switch (icmp_type) { + case ICMP_ECHOREPLY: + type_str="Echo (ping) reply"; + break; + case ICMP_UNREACH: + type_str="Destination unreachable"; + if (icmp_code < N_UNREACH) { + code_str = unreach_str[icmp_code]; + } else { + code_str = "Unknown - error?"; + } + break; + case ICMP_SOURCEQUENCH: + type_str="Source quench (flow control)"; + break; + case ICMP_REDIRECT: + type_str="Redirect"; + if (icmp_code < N_REDIRECT) { + code_str = redir_str[icmp_code]; + } else { + code_str = "Unknown - error?"; + } + break; + case ICMP_ECHO: + type_str="Echo (ping) request"; + break; + case ICMP_RTRADVERT: + switch (icmp_code) { + case 0: /* Mobile-Ip */ + case 16: /* Mobile-Ip */ + type_str="Mobile IP Advertisement"; + break; + default: + type_str="Router advertisement"; + break; + } /* switch icmp_code */ + break; + case ICMP_RTRSOLICIT: + type_str="Router solicitation"; + break; + case ICMP_TIMXCEED: + type_str="Time-to-live exceeded"; + if (icmp_code < N_TIMXCEED) { + code_str = ttl_str[icmp_code]; + } else { + code_str = "Unknown - error?"; + } + break; + case ICMP_PARAMPROB: + type_str="Parameter problem"; + if (icmp_code < N_PARAMPROB) { + code_str = par_str[icmp_code]; + } else { + code_str = "Unknown - error?"; + } + break; + case ICMP_TSTAMP: + type_str="Timestamp request"; + break; + case ICMP_TSTAMPREPLY: + type_str="Timestamp reply"; + break; + case ICMP_IREQ: + type_str="Information request"; + break; + case ICMP_IREQREPLY: + type_str="Information reply"; + break; + case ICMP_MASKREQ: + type_str="Address mask request"; + break; + case ICMP_MASKREPLY: + type_str="Address mask reply"; + break; + default: + type_str="Unknown ICMP (obsolete or malformed?)"; + break; + } + + if (show_type) + proto_tree_add_uint_format(tree, ofp_match_icmp_type, tvb, *offset, 2, + icmp_type, + "ICMP Type: %u (%s)", + icmp_type, type_str); + if (show_code) + proto_tree_add_uint_format(tree, ofp_match_icmp_code, tvb, *offset, 2, + icmp_code, + "ICMP Code: %u (%s)", + icmp_code, code_str); + + *offset += 4; +} + +static void dissect_match(proto_tree* tree, proto_item* item, tvbuff_t *tvb, packet_info *pinfo, guint32 *offset) +{ + proto_item *match_item = proto_tree_add_item(tree, ofp_match, tvb, *offset, sizeof(struct ofp_match), FALSE); + proto_tree *match_tree = proto_item_add_subtree(match_item, ett_ofp_match); + + /* save wildcards field for later */ + guint32 wildcards = tvb_get_ntohl( tvb, *offset ); + + dissect_wildcards(match_tree, match_item, tvb, pinfo, offset, ofp_match_wildcards); + + /* show only items whose corresponding wildcard bit is not set */ + if( ~wildcards & OFPFW_IN_PORT ) + dissect_port(match_tree, ofp_match_in_port, tvb, offset); + else + *offset += 2; + + if( ~wildcards & OFPFW_DL_SRC ) + add_child(match_tree, ofp_match_dl_src, tvb, offset, 6); + else + *offset += 6; + + if( ~wildcards & OFPFW_DL_DST ) + add_child(match_tree, ofp_match_dl_dst, tvb, offset, 6); + else + *offset += 6; + + if( ~wildcards & OFPFW_DL_VLAN ) + add_child(match_tree, ofp_match_dl_vlan, tvb, offset, 2); + else + *offset += 2; + + if( ~wildcards & OFPFW_DL_VLAN_PCP ) + add_child(match_tree, ofp_match_dl_vlan_pcp, tvb, offset, 1); + else + *offset += 1; + + dissect_pad(match_tree, offset, 1); + + /* Save DL type for later */ + guint16 dl_type = tvb_get_ntohs( tvb, *offset); + + if( ~wildcards & OFPFW_DL_TYPE ) + dissect_dl_type(match_tree, ofp_match_dl_type, tvb, offset); + else + *offset += 2; + + if( ~wildcards & OFPFW_NW_TOS ) + add_child(match_tree, ofp_match_nw_tos, tvb, offset, 1); + else + *offset += 1; + + /* Save NW proto for later */ + guint8 nw_proto = tvb_get_guint8( tvb, *offset); + + /* Custom handling for ARP packets vs non-ARP packets */ + if ( dl_type == ETHERTYPE_ARP ) + add_child(match_tree, ofp_match_arp_opcode, tvb, offset, 1); + else if( ~wildcards & OFPFW_NW_PROTO ) + dissect_nw_proto(match_tree, ofp_match_nw_proto, tvb, offset); + else + *offset += 1; + + dissect_pad(match_tree, offset, 2); + + if( ~wildcards & OFPFW_NW_SRC_MASK ) + add_child(match_tree, ofp_match_nw_src, tvb, offset, 4); + else + *offset += 4; + + if( ~wildcards & OFPFW_NW_DST_MASK ) + add_child(match_tree, ofp_match_nw_dst, tvb, offset, 4); + else + *offset += 4; + + /* Display either ICMP type/code or TCP/UDP ports */ + if( dl_type == ETHERTYPE_IP && nw_proto == IP_PROTO_ICMP) { + dissect_icmp_type_code_match(match_tree, tvb, offset, + ~wildcards & OFPFW_TP_SRC, + ~wildcards & OFPFW_TP_DST ); + } + else { + if( ~wildcards & OFPFW_TP_SRC ) + dissect_tp_port(match_tree, ofp_match_tp_src, tvb, offset); + else + *offset += 2; + + if( ~wildcards & OFPFW_TP_DST ) + dissect_tp_port(match_tree, ofp_match_tp_dst, tvb, offset); + else + *offset += 2; + } +} + +static void dissect_action_output(proto_tree* tree, tvbuff_t *tvb, guint32 *offset) +{ + /* add the output port */ + dissect_port( tree, ofp_action_output_port, tvb, offset ); + + /* determine the maximum number of bytes to send (0 => no limit) */ + guint16 max_len = tvb_get_ntohs( tvb, *offset ); + char str[11]; + snprintf( str, 11, "%u", max_len ); + add_child_str( tree, ofp_action_output_max_len, tvb, offset, 2, str ); +} + +static void dissect_action_enqueue(proto_tree* tree, tvbuff_t *tvb, guint32 *offset) +{ + /* add the output port */ + dissect_port( tree, ofp_action_enqueue_port_no, tvb, offset ); + dissect_pad(tree, offset, 6); + dissect_queue_id(tree, ofp_action_enqueue_queue_id, tvb, offset); +} + + +/** returns the number of bytes dissected (-1 if an unknown action type is + * encountered; and 8/16 for all other actions as of 0x96) */ +static gint dissect_action(proto_tree* tree, proto_item* item, tvbuff_t *tvb, packet_info *pinfo, guint32 *offset) +{ + guint32 offset_start = *offset; + guint16 type = tvb_get_ntohs( tvb, *offset ); + guint16 len = tvb_get_ntohs( tvb, *offset + 2); + + proto_item *action_item = proto_tree_add_item(tree, ofp_action, tvb, *offset, len, FALSE); + proto_tree *action_tree = proto_item_add_subtree(action_item, ett_ofp_action); + + if (!(len == 8 || len == 16)) { + add_child_str(action_tree, ofp_action_unknown, tvb, offset, len, "Invalid Action Length"); + return -1; + } + + add_child( action_tree, ofp_action_type, tvb, offset, 2 ); + add_child( action_tree, ofp_action_len, tvb, offset, 2 ); + + switch( type ) { + case OFPAT_OUTPUT: + dissect_action_output(action_tree, tvb, offset); + break; + + case OFPAT_SET_VLAN_VID: + add_child( action_tree, ofp_action_vlan_vid, tvb, offset, 2 ); + dissect_pad(action_tree, offset, 2); + break; + + case OFPAT_SET_VLAN_PCP: + add_child( action_tree, ofp_action_vlan_pcp, tvb, offset, 1 ); + dissect_pad(action_tree, offset, 3); + break; + + case OFPAT_STRIP_VLAN: + add_child( action_tree, ofp_action_unknown, tvb, offset, 0 ); + dissect_pad(action_tree, offset, 4); + break; + + case OFPAT_SET_DL_SRC: + case OFPAT_SET_DL_DST: + add_child(action_tree, ofp_action_dl_addr, tvb, offset, 6 ); + dissect_pad(action_tree, offset, 6); + break; + + case OFPAT_SET_NW_SRC: + case OFPAT_SET_NW_DST: + add_child( action_tree, ofp_action_nw_addr, tvb, offset, 4 ); + break; + + case OFPAT_SET_NW_TOS: + add_child( action_tree, ofp_action_nw_tos, tvb, offset, 1); + dissect_pad(action_tree, offset, 3); + break; + + case OFPAT_SET_TP_SRC: + case OFPAT_SET_TP_DST: + add_child( action_tree, ofp_action_tp_port, tvb, offset, 2 ); + dissect_pad(action_tree, offset, 2); + break; + + case OFPAT_ENQUEUE: + dissect_action_enqueue(action_tree, tvb, offset); + break; + + default: + add_child( action_tree, ofp_action_unknown, tvb, offset, 0 ); + return -1; + } + + /* return the number of bytes which were consumed */ + return *offset - offset_start; +} + +static void dissect_action_array(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint len, guint offset) +{ + guint total_len = len - offset; + + proto_item* action_item = proto_tree_add_item(tree, ofp_action_output, tvb, offset, total_len, FALSE); + proto_tree* action_tree = proto_item_add_subtree(action_item, ett_ofp_action_output); + + if( total_len == 0 ) + add_child_str(action_tree, ofp_action_warn, tvb, &offset, 0, "No actions were specified"); + else if( offset > len ) { + /* not enough bytes => wireshark will already have reported the error */ + } + else { + guint offset_action_start = offset; + guint num_actions = 0; + while( total_len > 0 ) { + num_actions += 1; + int ret = dissect_action(action_tree, action_item, tvb, pinfo, &offset); + if( ret < 0 ) + break; /* stop if we run into an action we couldn't dissect */ + else + total_len -= ret; + } + proto_tree_add_uint(action_tree, ofp_action_num, tvb, offset_action_start, 0, num_actions); + } +} + +static void dissect_property_min(proto_tree* tree, tvbuff_t *tvb, guint32 *offset) +{ + add_child(tree, ofp_packet_queue_property_rate, tvb, offset, 2); + dissect_pad(tree, offset, 6); +} + +static gint32 dissect_property(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, guint32 *offset) +{ + guint32 offset_start = *offset; + guint16 type = tvb_get_ntohs(tvb, *offset); + guint16 len = tvb_get_ntohs(tvb, *offset + 2); + + proto_item *property_item = proto_tree_add_item(tree, ofp_packet_queue_property, tvb, *offset, len, FALSE); + proto_tree *property_tree = proto_item_add_subtree(property_item, ett_ofp_packet_queue_property); + + add_child(property_tree, ofp_packet_queue_property_type, tvb, offset, 2); + add_child(property_tree, ofp_packet_queue_property_len, tvb, offset, 2); + dissect_pad(tree, offset, 4); + + switch( type ) { + case OFPQT_MIN_RATE: + dissect_property_min(property_tree, tvb, offset); + break; + default: + add_child(property_tree, ofp_packet_queue_property_unknown, tvb, offset, 0); + return -1; + } + + return *offset - offset_start; +} + +/* returns the number of bytes dissected ( -1 if unknown propery is encountered */ +static void dissect_property_array(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint len, guint32 *offset) +{ + guint total_len = len; + + proto_item *property_item = proto_tree_add_item(tree, ofp_packet_queue_properties_hdr, tvb, *offset, total_len, FALSE); + proto_tree *property_tree = proto_item_add_subtree(property_item, ett_ofp_packet_queue_properties_hdr); + + if( total_len == 0 ) { + add_child_str(property_tree, ofp_packet_queue_property_warn, tvb, offset, 0, "No properties were specified"); + } + else { + guint32 offset_property_start = *offset; + guint num_properties = 0; + while( total_len > 0 ) { + num_properties += 1; + int ret = dissect_property(property_tree, tvb, pinfo, offset); + if( ret < 0 ) { + break; /* stop if we run into a property we couldn't dissect */ + } + else + total_len -= ret; + } + proto_tree_add_uint(property_tree, ofp_packet_queue_properties_num, tvb, offset_property_start, 0, num_properties); + } +} + +/** returns the number of bytes dissected (-1 if an unknown property is + * encountered; */ +static gint dissect_queue(proto_tree* tree, tvbuff_t *tvb, packet_info *pinfo, guint32 *offset) +{ + guint32 offset_start = *offset; + guint16 len = tvb_get_ntohs( tvb, *offset + 4); + + proto_item *queue_item = proto_tree_add_item(tree, ofp_packet_queue, tvb, *offset, len, FALSE); + proto_tree *queue_tree = proto_item_add_subtree(queue_item, ett_ofp_packet_queue); + + // add_child( queue_tree, ofp_packet_queue_queue_id, tvb, offset, 4 ); + dissect_queue_id(queue_tree, ofp_packet_queue_queue_id, tvb, offset); + add_child( queue_tree, ofp_packet_queue_len, tvb, offset, 2 ); + dissect_pad( queue_tree, offset, 2); + + dissect_property_array(tvb, pinfo, queue_tree, len - (*offset - offset_start), offset); + return *offset - offset_start; + +} + +static void dissect_queue_array(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint len, guint32 *offset) +{ + guint total_len = len - *offset; + + proto_item *queue_item = proto_tree_add_item(tree, ofp_queue_get_config_reply_queues_hdr, tvb, *offset, total_len, FALSE); + proto_tree *queue_tree = proto_item_add_subtree(queue_item, ett_ofp_queue_get_config_reply_queues_hdr); + + if( total_len == 0 ) { + add_child_str(queue_tree, ofp_packet_queue_warn, tvb, offset, 0, "No queues were specified"); + } + else if( *offset > len ) { + /* not enough bytes => wireshark will already have reported the error */ + } + else { + guint offset_queue_start = *offset; + guint num_queues = 0; + while( total_len > 0 ) { + num_queues += 1; + int ret = dissect_queue(queue_tree, tvb, pinfo, offset); + if( ret < 0 ) + break; /* stop if we run into an action we couldn't dissect */ + else + total_len -= ret; + } + proto_tree_add_uint(queue_tree, ofp_queue_get_config_reply_queues_num, tvb, offset_queue_start, 0, num_queues); + } +} + + +static void dissect_capability_array(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint field_size) { + proto_item *sf_cap_item = proto_tree_add_item(tree, ofp_switch_features_capabilities_hdr, tvb, offset, field_size, FALSE); + proto_tree *sf_cap_tree = proto_item_add_subtree(sf_cap_item, ett_ofp_switch_features_capabilities_hdr); + gint i; + for(i=0; icinfo, COL_PROTOCOL)) + col_append_str( pinfo->cinfo, COL_PROTOCOL, "+" ); + + if(check_col(pinfo->cinfo,COL_INFO)) + col_append_str( pinfo->cinfo, COL_INFO, " => " ); + + /* set up fences so ethernet dissectors only appends to our column info */ + col_set_fence(pinfo->cinfo, COL_PROTOCOL); + col_set_fence(pinfo->cinfo, COL_INFO); + + /* continue the dissection with the ethernet dissector */ + call_dissector(data_ethernet, next_tvb, pinfo, data_tree); +} + +static void dissect_error_code(proto_tree* tree, gint hf, tvbuff_t *tvb, guint32 *offset, guint16 err_type) { + guint16 err_code; + guint8 valid; + const gchar *code_str; + + err_code = tvb_get_ntohs(tvb, *offset); + code_str = ""; + valid = TRUE; + + switch (err_type) { + case OFPET_HELLO_FAILED: + if (err_code < N_HELLOFAILED) { + code_str = hello_failed_err_str[err_code]; + } else { + code_str = "Unknown - error?"; + } + break; + case OFPET_BAD_REQUEST: + if (err_code < N_BADREQUEST) { + code_str = bad_request_err_str[err_code]; + } else { + code_str = "Unknown - error?"; + } + break; + case OFPET_BAD_ACTION: + if (err_code < N_BADACTION) { + code_str = bad_action_err_str[err_code]; + } else { + code_str = "Unknown - error?"; + } + break; + case OFPET_FLOW_MOD_FAILED: + if (err_code < N_FLOWMODFAILED) { + code_str = flow_mod_failed_err_str[err_code]; + } else { + code_str = "Unknown - error?"; + } + break; + case OFPET_PORT_MOD_FAILED: + if (err_code < N_PORTMODFAILED) { + code_str = port_mod_failed_err_str[err_code]; + } else { + code_str = "Unknown - error?"; + } + break; + case OFPET_QUEUE_OP_FAILED: + if (err_code < N_QUEUEOPFAILED) { + code_str = queue_op_failed_err_str[err_code]; + } else { + code_str = "Unknown - error?"; + } + break; + + default: + valid = FALSE; + break; + } + + if (valid) + proto_tree_add_uint_format(tree, hf, tvb, *offset, 2, + err_code, + "Code: %s (%u)", + code_str, err_code); + else + proto_tree_add_item(tree, hf, tvb, *offset, 2, FALSE); + + *offset += 2; +} + +static void dissect_flow_mod_flags(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) { + proto_item *fm_flags_item = proto_tree_add_item(tree, ofp_switch_config_flags_hdr, tvb, *offset, 2, FALSE); + proto_tree *fm_flags_tree = proto_item_add_subtree(fm_flags_item, ett_ofp_flow_mod_flags_hdr); + int i; + + for (i = 0; i < NUM_FLOW_MOD_FLAGS; i++) + add_child_const(fm_flags_tree, ofp_flow_mod_flags[i], tvb, *offset, 2); + + *offset += 2; +} + + +static void dissect_openflow_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ +# define STR_LEN 1024 + char str[STR_LEN]; + + /* display our protocol text if the protocol column is visible */ + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + col_set_str(pinfo->cinfo, COL_PROTOCOL, PROTO_TAG_OPENFLOW); + + /* Clear out stuff in the info column */ + if(check_col(pinfo->cinfo,COL_INFO)) + col_clear(pinfo->cinfo,COL_INFO); + + /* get some of the header fields' values for later use */ + guint8 ver = tvb_get_guint8( tvb, 0 ); + guint8 type = tvb_get_guint8( tvb, 1 ); + guint16 len = tvb_get_ntohs( tvb, 2 ); + + /* add a warning if the version is what the plugin was written to handle */ + guint8 ver_warning = 0; + if( ver < DISSECTOR_OPENFLOW_MIN_VERSION || ver > DISSECTOR_OPENFLOW_MAX_VERSION || ver >= DISSECTOR_OPENFLOW_VERSION_DRAFT_THRESHOLD ) { + if( ver>=DISSECTOR_OPENFLOW_VERSION_DRAFT_THRESHOLD && ver<=DISSECTOR_OPENFLOW_MAX_VERSION ) + snprintf( str, STR_LEN, "DRAFT Dissector written for this OpenFlow version v0x%0X", ver ); + else { + ver_warning = 1; + if( DISSECTOR_OPENFLOW_MIN_VERSION == DISSECTOR_OPENFLOW_MAX_VERSION ) + snprintf( str, STR_LEN, + "Dissector written for OpenFlow v0x%0X (differs from this packet's version v0x%0X)", + DISSECTOR_OPENFLOW_MIN_VERSION, ver ); + else + snprintf( str, STR_LEN, + "Dissector written for OpenFlow v0x%0X-v0x%0X (differs from this packet's version v0x%0X)", + DISSECTOR_OPENFLOW_MIN_VERSION, DISSECTOR_OPENFLOW_MAX_VERSION, ver ); + } + } + + /* clarify protocol name display with version, length, and type information */ + if (check_col(pinfo->cinfo, COL_INFO)) { + /* special handling so we can put buffer IDs in the description */ + char str_extra[32]; + str_extra[0] = '\0'; + if( type==OFPT_PACKET_IN || type==OFPT_PACKET_OUT ) { + guint32 bid = tvb_get_ntohl(tvb, sizeof(struct ofp_header)); + if( bid != 0xFFFFFFFF ) + snprintf(str_extra, 32, "(BufID=%u) ", bid); + } + + if( ver_warning ) + col_add_fstr( pinfo->cinfo, COL_INFO, "%s %s(%uB) Ver Warning!", ofp_type_to_string(type), str_extra, len ); + else + col_add_fstr( pinfo->cinfo, COL_INFO, "%s %s(%uB)", ofp_type_to_string(type), str_extra, len ); + } + + if (tree) { /* we are being asked for details */ + proto_item *item = NULL; + proto_item *sub_item = NULL; + proto_tree *ofp_tree = NULL; + proto_tree *header_tree = NULL; + guint32 offset = 0; + proto_item *type_item = NULL; + proto_tree *type_tree = NULL; + + /* consume the entire tvb for the openflow packet, and add it to the tree */ + item = proto_tree_add_item(tree, proto_openflow, tvb, 0, -1, FALSE); + ofp_tree = proto_item_add_subtree(item, ett_ofp); + + /* put the header in its own node as a child of the openflow node */ + sub_item = proto_tree_add_item( ofp_tree, ofp_header, tvb, offset, 8, FALSE ); + header_tree = proto_item_add_subtree(sub_item, ett_ofp_header); + + if( ver_warning ) + add_child_str( header_tree, ofp_header_warn_ver, tvb, &offset, 0, str ); + + /* add the headers field as children of the header node */ + add_child( header_tree, ofp_header_version, tvb, &offset, 1 ); + add_child( header_tree, ofp_header_type, tvb, &offset, 1 ); + add_child( header_tree, ofp_header_length, tvb, &offset, 2 ); + add_child( header_tree, ofp_header_xid, tvb, &offset, 4 ); + + switch( type ) { + + case OFPT_HELLO: { + /* nothing else in this packet type */ + break; + } + + case OFPT_BARRIER_REQUEST: + case OFPT_BARRIER_REPLY: + /* nothing else in this packet type */ + break; + + case OFPT_ERROR: { + type_item = proto_tree_add_item(ofp_tree, ofp_error_msg, tvb, offset, -1, FALSE); + type_tree = proto_item_add_subtree(type_item, ett_ofp_error_msg); + + /* Extract the type for use later */ + guint16 type = tvb_get_ntohs(tvb, offset); + + add_child(type_tree, ofp_error_msg_type, tvb, &offset, 2); + dissect_error_code(type_tree, ofp_error_msg_code, tvb, &offset, type); + + if (type == OFPET_HELLO_FAILED) + add_child(type_tree, ofp_error_msg_data_str, tvb, &offset, len - offset); + else if (type == OFPET_BAD_REQUEST || + type == OFPET_BAD_ACTION || + type == OFPET_FLOW_MOD_FAILED) { + /* Dissect the data as an OpenFlow packet */ + proto_item *data_item = proto_tree_add_item(type_tree, ofp_error_msg_data, tvb, offset, -1, FALSE); + proto_tree *data_tree = proto_item_add_subtree(data_item, ett_ofp_error_msg_data); + tvbuff_t *next_tvb = tvb_new_subset(tvb, offset, -1, len - offset); + + /* Temporarily disable writing */ + gboolean writeable = col_get_writable(pinfo->cinfo); + col_set_writable( pinfo->cinfo, FALSE); + + /* Finally do the dissection */ + dissect_openflow_message(next_tvb, pinfo, data_tree); + + col_set_writable( pinfo->cinfo, writeable); + + offset += (len - offset); + } + else + add_child(type_tree, ofp_error_msg_data, tvb, &offset, len - offset); + break; + } + + case OFPT_ECHO_REQUEST: + case OFPT_ECHO_REPLY: { + if (len - offset > 0) + add_child(tree, ofp_echo, tvb, &offset, len - offset); + break; + } + + case OFPT_VENDOR: { + if (len - offset > 0) { + add_child(tree, ofp_vendor, tvb, &offset, len - offset); + } + break; + } + + case OFPT_FEATURES_REQUEST: + /* nothing else in this packet type */ + break; + + case OFPT_FEATURES_REPLY: { + + proto_item *sf_port_item = NULL; + proto_tree *sf_port_tree = NULL; + guint num_ports; + gint sz; + + type_item = proto_tree_add_item(ofp_tree, ofp_switch_features, tvb, offset, -1, FALSE); + //break; + type_tree = proto_item_add_subtree(type_item, ett_ofp_switch_features); + + /* fields we'll put directly in the subtree */ + + add_child(type_tree, ofp_switch_features_datapath_id, tvb, &offset, 8); + + add_child(type_tree, ofp_switch_features_n_buffers, tvb, &offset, 4); + add_child(type_tree, ofp_switch_features_n_tables, tvb, &offset, 1); + dissect_pad(type_tree, &offset, 3); + + + /* capabilities */ + dissect_capability_array(tvb, pinfo, type_tree, offset, 4); + offset += 4; + + /* actions */ + dissect_switch_features_actions(tvb, pinfo, type_tree, offset, 4); + offset += 4; + + /* handle ports */ + sf_port_item = proto_tree_add_item(type_tree, ofp_switch_features_ports_hdr, tvb, offset, -1, FALSE); + sf_port_tree = proto_item_add_subtree(sf_port_item, ett_ofp_switch_features_ports_hdr); + sz = len - sizeof(struct ofp_switch_features); + + if( sz > 0 ) { + num_ports = sz / sizeof(struct ofp_phy_port); /* number of ports */ + proto_tree_add_uint(sf_port_tree, ofp_switch_features_ports_num, tvb, offset, num_ports*sizeof(struct ofp_phy_port), num_ports); + + dissect_phy_ports(sf_port_tree, sf_port_item, tvb, pinfo, &offset, num_ports); + if( num_ports * sizeof(struct ofp_phy_port) < sz ) { + snprintf(str, STR_LEN, "%uB were leftover at end of packet", sz - num_ports*sizeof(struct ofp_phy_port)); + add_child_str(sf_port_tree, ofp_switch_features_ports_warn, tvb, &offset, 0, str); + } + } + else if( sz < 0 ) { + /* not enough bytes => wireshark will already have reported the error */ + } + else { + snprintf(str, STR_LEN, "No ports were specified"); + add_child_str(sf_port_tree, ofp_switch_features_ports_warn, tvb, &offset, 0, str); + } + break; + } + + case OFPT_GET_CONFIG_REQUEST: + /* nothing else in this packet type */ + break; + + case OFPT_GET_CONFIG_REPLY: + case OFPT_SET_CONFIG: { + type_item = proto_tree_add_item(ofp_tree, ofp_switch_config, tvb, offset, -1, FALSE); + type_tree = proto_item_add_subtree(type_item, ett_ofp_switch_config); + dissect_switch_config_flags(tvb, pinfo, type_tree, &offset); + add_child(type_tree, ofp_switch_config_miss_send_len, tvb, &offset, 2); + break; + } + + case OFPT_QUEUE_GET_CONFIG_REQUEST: { + type_item = proto_tree_add_item(ofp_tree, ofp_queue_get_config_request, tvb, offset, -1, FALSE); + type_tree = proto_item_add_subtree(type_item, ett_ofp_queue_get_config_request); + dissect_port(type_tree, ofp_queue_get_config_request_port_no, tvb, &offset); + dissect_pad(type_tree, &offset, 2); + break; + } + + case OFPT_QUEUE_GET_CONFIG_REPLY: { + type_item = proto_tree_add_item(ofp_tree, ofp_queue_get_config_reply, tvb, offset, -1, FALSE); + type_tree = proto_item_add_subtree(type_item, ett_ofp_queue_get_config_reply); + + dissect_port(type_tree, ofp_queue_get_config_reply_port_no, tvb, &offset); + dissect_pad(type_tree, &offset, 6); + + /* handle queues */ + dissect_queue_array(tvb, pinfo, type_tree, len, &offset); + break; + } + + case OFPT_PACKET_IN: { + type_item = proto_tree_add_item(ofp_tree, ofp_packet_in, tvb, offset, -1, FALSE); + type_tree = proto_item_add_subtree(type_item, ett_ofp_packet_in); + + add_child(type_tree, ofp_packet_in_buffer_id, tvb, &offset, 4); + + /* explicitly pull out the length so we can use it to determine data's size */ + guint16 total_len = tvb_get_ntohs( tvb, offset ); + proto_tree_add_uint(type_tree, ofp_packet_in_total_len, tvb, offset, 2, total_len); + offset += 2; + + add_child(type_tree, ofp_packet_in_in_port, tvb, &offset, 2); + add_child(type_tree, ofp_packet_in_reason, tvb, &offset, 1); + dissect_pad(type_tree, &offset, 1); + + if (len > sizeof(struct ofp_packet_in)) { + /* continue the dissection with the Ethernet dissector */ + if (data_ethernet) { + proto_item *data_item = proto_tree_add_item(type_tree, ofp_packet_in_data_hdr, tvb, offset, -1, FALSE); + proto_tree *data_tree = proto_item_add_subtree(data_item, ett_ofp_packet_in_data_hdr); + tvbuff_t *next_tvb = tvb_new_subset(tvb, offset, -1, total_len); + dissect_ethernet(next_tvb, pinfo, data_tree); + } else { + /* if we couldn't load the ethernet dissector, just display the bytes */ + add_child(type_tree, ofp_packet_in_data_hdr, tvb, &offset, total_len); + } + } + break; + } + + case OFPT_FLOW_REMOVED: { + type_item = proto_tree_add_item(ofp_tree, ofp_flow_removed, tvb, offset, -1, FALSE); + type_tree = proto_item_add_subtree(type_item, ett_ofp_flow_removed); + + dissect_match(type_tree, type_item, tvb, pinfo, &offset); + add_child(type_tree, ofp_flow_removed_cookie, tvb, &offset, 8); + add_child(type_tree, ofp_flow_removed_priority, tvb, &offset, 2); + add_child(type_tree, ofp_flow_removed_reason, tvb, &offset, 1); + dissect_pad(type_tree, &offset, 1); + add_child(type_tree, ofp_flow_removed_duration_sec, tvb, &offset, 4); + add_child(type_tree, ofp_flow_removed_duration_nsec, tvb, &offset, 4); + add_child(type_tree, ofp_flow_removed_idle_timeout, tvb, &offset, 2); + dissect_pad(type_tree, &offset, 2); + add_child(type_tree, ofp_flow_removed_packet_count, tvb, &offset, 8); + add_child(type_tree, ofp_flow_removed_byte_count, tvb, &offset, 8); + break; + } + + case OFPT_PORT_STATUS: { + type_item = proto_tree_add_item(ofp_tree, ofp_port_status, tvb, offset, -1, FALSE); + type_tree = proto_item_add_subtree(type_item, ett_ofp_port_status); + + add_child(type_tree, ofp_port_status_reason, tvb, &offset, 1); + dissect_pad(type_tree, &offset, 7); + dissect_phy_ports(type_tree, type_item, tvb, pinfo, &offset, 1); + break; + } + + case OFPT_PACKET_OUT: { + type_item = proto_tree_add_item(ofp_tree, ofp_packet_out, tvb, offset, -1, FALSE); + type_tree = proto_item_add_subtree(type_item, ett_ofp_packet_out); + + /* get buffer_id value for later use */ + guint32 buffer_id = tvb_get_ntohl( tvb, offset ); + + if( buffer_id == 0xFFFFFFFF ) + add_child_str(type_tree, ofp_packet_out_buffer_id, tvb, &offset, 4, "None"); + else { + snprintf(str, STR_LEN, "%u", buffer_id); + add_child_str(type_tree, ofp_packet_out_buffer_id, tvb, &offset, 4, str); + } + + /* display in port */ + // FIXME: bug in dissect_port for latest version + dissect_port(type_tree, ofp_packet_out_in_port, tvb, &offset); + + /* pull out actions len */ + guint16 actions_len = tvb_get_ntohs( tvb, offset); + add_child(type_tree, ofp_packet_out_actions_len, tvb, &offset, 2); + + /* dissect action array; will handle no-action case */ + dissect_action_array(tvb, pinfo, type_tree, offset + actions_len, offset); + offset += actions_len; + + /* if buffer id == -1, then display the provided packet */ + if( buffer_id == -1 ) { + /* continue the dissection with the Ethernet dissector */ + guint total_len = len - offset; + if( data_ethernet ) { + proto_item *data_item = proto_tree_add_item(type_tree, ofp_packet_out_data_hdr, tvb, offset, -1, FALSE); + proto_tree *data_tree = proto_item_add_subtree(data_item, ett_ofp_packet_out_data_hdr); + tvbuff_t *next_tvb = tvb_new_subset(tvb, offset, -1, total_len); + dissect_ethernet(next_tvb, pinfo, data_tree); + } + else { + /* if we couldn't load the ethernet dissector, just display the bytes */ + add_child(type_tree, ofp_packet_out_data_hdr, tvb, &offset, total_len); + } + } + + break; + } + + case OFPT_FLOW_MOD: { + type_item = proto_tree_add_item(ofp_tree, ofp_flow_mod, tvb, offset, -1, FALSE); + type_tree = proto_item_add_subtree(type_item, ett_ofp_flow_mod); + + dissect_match(type_tree, type_item, tvb, pinfo, &offset); + add_child(type_tree, ofp_flow_mod_cookie, tvb, &offset, 8); + add_child(type_tree, ofp_flow_mod_command, tvb, &offset, 2); + add_child(type_tree, ofp_flow_mod_idle_timeout, tvb, &offset, 2); + add_child(type_tree, ofp_flow_mod_hard_timeout, tvb, &offset, 2); + add_child(type_tree, ofp_flow_mod_priority, tvb, &offset, 2); + + /* get buffer_id value for later use */ + guint32 buffer_id = tvb_get_ntohl( tvb, offset ); + + if( buffer_id == 0xFFFFFFFF ) + add_child_str(type_tree, ofp_flow_mod_buffer_id, tvb, &offset, 4, "None"); + else { + snprintf(str, STR_LEN, "%u", buffer_id); + add_child_str(type_tree, ofp_flow_mod_buffer_id, tvb, &offset, 4, str); + } + + /* add the output port */ + dissect_port(type_tree, ofp_flow_mod_out_port, tvb, &offset ); + dissect_flow_mod_flags(tvb, pinfo, type_tree, &offset); + dissect_action_array(tvb, pinfo, type_tree, len, offset); + break; + } + + case OFPT_PORT_MOD: { + type_item = proto_tree_add_item(ofp_tree, ofp_port_mod, tvb, offset, -1, FALSE); + type_tree = proto_item_add_subtree(type_item, ett_ofp_port_mod); + + dissect_port_mod(type_tree, type_item, tvb, pinfo, &offset); + break; + } + + case OFPT_STATS_REQUEST: { + type_item = proto_tree_add_item(ofp_tree, ofp_stats_request, tvb, offset, -1, FALSE); + type_tree = proto_item_add_subtree(type_item, ett_ofp_stats_request); + + guint16 type = tvb_get_ntohs( tvb, offset ); + add_child(type_tree, ofp_stats_request_type, tvb, &offset, 2); + add_child(type_tree, ofp_stats_request_flags, tvb, &offset, 2); + + switch( type ) { + case OFPST_FLOW: { + proto_item *flow_item = proto_tree_add_item(type_tree, ofp_flow_stats_request, tvb, offset, -1, FALSE); + proto_tree *flow_tree = proto_item_add_subtree(flow_item, ett_ofp_flow_stats_request); + + dissect_match(flow_tree, flow_item, tvb, pinfo, &offset); + + guint8 id = tvb_get_guint8( tvb, offset ); + if( id == 0xFF ) + add_child_str(flow_tree, ofp_flow_stats_request_table_id, tvb, &offset, 1, "All Tables"); + else { + snprintf(str, STR_LEN, "%u", id); + add_child_str(flow_tree, ofp_flow_stats_request_table_id, tvb, &offset, 1, str); + } + + dissect_pad(flow_tree, &offset, 1); + dissect_port(flow_tree, ofp_flow_stats_request_out_port, tvb, &offset ); + break; + } + + case OFPST_AGGREGATE: { + proto_item *aggr_item = proto_tree_add_item(type_tree, ofp_aggr_stats_request, tvb, offset, -1, FALSE); + proto_tree *aggr_tree = proto_item_add_subtree(aggr_item, ett_ofp_aggr_stats_request); + + dissect_match(aggr_tree, aggr_item, tvb, pinfo, &offset); + + guint8 id = tvb_get_guint8( tvb, offset ); + if( id == 0xFF ) + add_child_str(aggr_tree, ofp_aggr_stats_request_table_id, tvb, &offset, 1, "All Tables"); + else { + snprintf(str, STR_LEN, "%u", id); + add_child_str(aggr_tree, ofp_aggr_stats_request_table_id, tvb, &offset, 1, str); + } + + dissect_pad(aggr_tree, &offset, 3); + break; + } + + case OFPST_TABLE: + /* no body for these types of requests */ + break; + + case OFPST_PORT:{ + if (len - offset > 0) { + proto_item *port_item = proto_tree_add_item(type_tree, ofp_port_stats_request, tvb, offset, -1, FALSE); + proto_tree *port_tree = proto_item_add_subtree(port_item, ett_ofp_port_stats_request); + dissect_port(port_tree, ofp_port_stats_request_port_no, tvb, &offset); + dissect_pad(port_tree, &offset, 6); + } + } + break; + + case OFPST_QUEUE: { + proto_item *queue_item = proto_tree_add_item(type_tree, ofp_queue_stats_request, tvb, offset, -1, FALSE); + proto_tree *queue_tree = proto_item_add_subtree(queue_item, ett_ofp_queue_stats_request); + + dissect_port(queue_tree, ofp_queue_stats_port_no, tvb, &offset); + dissect_pad(queue_tree, &offset, 2); + dissect_queue_id(queue_tree, ofp_queue_stats_queue_id, tvb, &offset); + break; + } + + default: + /* add as bytes if type isn't one we know how to dissect */ + add_child(type_tree, ofp_stats_request_body, tvb, &offset, len - offset); + } + + break; + } + + case OFPT_STATS_REPLY: { + type_item = proto_tree_add_item(ofp_tree, ofp_stats_reply, tvb, offset, -1, FALSE); + type_tree = proto_item_add_subtree(type_item, ett_ofp_stats_reply); + + guint16 type = tvb_get_ntohs( tvb, offset ); + add_child(type_tree, ofp_stats_reply_type, tvb, &offset, 2); + add_child(type_tree, ofp_stats_reply_flags, tvb, &offset, 2); + + switch( type ) { + + case OFPST_DESC: { + // FIXME: add desc stats + proto_item* desc_item = proto_tree_add_item(type_tree, ofp_desc_stats, tvb, offset, -1, FALSE); + proto_tree* desc_tree = proto_item_add_subtree(desc_item, ett_ofp_desc_stats); + + add_child( desc_tree, ofp_desc_stats_mfr_desc, tvb, &offset, DESC_STR_LEN ); + add_child( desc_tree, ofp_desc_stats_hw_desc, tvb, &offset, DESC_STR_LEN ); + add_child( desc_tree, ofp_desc_stats_sw_desc, tvb, &offset, DESC_STR_LEN ); + add_child( desc_tree, ofp_desc_stats_serial_num, tvb, &offset, SERIAL_NUM_LEN ); + add_child( desc_tree, ofp_desc_stats_dp_desc, tvb, &offset, DESC_STR_LEN ); + + break; + } + + case OFPST_FLOW: { + /* process each flow stats struct in the packet */ + while( offset < len ) { + proto_item* flow_item = proto_tree_add_item(type_tree, ofp_flow_stats_reply, tvb, offset, -1, FALSE); + proto_tree* flow_tree = proto_item_add_subtree(flow_item, ett_ofp_flow_stats_reply); + + /* just get the length of this part of the packet; no need + to put it in the tree */ + guint16 total_len = tvb_get_ntohs( tvb, offset ); + guint offset_start = offset; + offset += 2; + + add_child(flow_tree, ofp_flow_stats_reply_table_id, tvb, &offset, 1); + dissect_pad(flow_tree, &offset, 1); + dissect_match(flow_tree, flow_item, tvb, pinfo, &offset); + add_child(flow_tree, ofp_flow_stats_reply_duration_sec, tvb, &offset, 4); + add_child(flow_tree, ofp_flow_stats_reply_duration_nsec, tvb, &offset, 4); + add_child(flow_tree, ofp_flow_stats_reply_priority, tvb, &offset, 2); + add_child(flow_tree, ofp_flow_stats_reply_idle_timeout, tvb, &offset, 2); + add_child(flow_tree, ofp_flow_stats_reply_hard_timeout, tvb, &offset, 2); + dissect_pad(flow_tree, &offset, 6); + add_child(flow_tree, ofp_flow_stats_reply_cookie, tvb, &offset, 8); + add_child(flow_tree, ofp_flow_stats_reply_packet_count, tvb, &offset, 8); + add_child(flow_tree, ofp_flow_stats_reply_byte_count, tvb, &offset, 8); + + /* parse the actions for this flow */ + dissect_action_array(tvb, pinfo, flow_tree, total_len + offset_start, offset); + offset = total_len + offset_start; + } + break; + } + + case OFPST_AGGREGATE: { + proto_item* aggr_item = proto_tree_add_item(type_tree, ofp_aggr_stats_reply, tvb, offset, -1, FALSE); + proto_tree* aggr_tree = proto_item_add_subtree(aggr_item, ett_ofp_aggr_stats_reply); + + add_child(aggr_tree, ofp_aggr_stats_reply_packet_count, tvb, &offset, 8); + add_child(aggr_tree, ofp_aggr_stats_reply_byte_count, tvb, &offset, 8); + add_child(aggr_tree, ofp_aggr_stats_reply_flow_count, tvb, &offset, 4); + + dissect_pad(aggr_tree, &offset, 4); + break; + } + + case OFPST_TABLE: { + /* process each table stats struct in the packet */ + while( offset < len ) { + proto_item *table_item = proto_tree_add_item(type_tree, ofp_table_stats, tvb, offset, -1, FALSE); + proto_tree *table_tree = proto_item_add_subtree(table_item, ett_ofp_table_stats); + + add_child(table_tree, ofp_table_stats_table_id, tvb, &offset, 1); + dissect_pad(table_tree, &offset, 3); + add_child( table_tree, ofp_table_stats_name, tvb, &offset, OFP_MAX_TABLE_NAME_LEN); + dissect_wildcards(table_tree, table_item, tvb, pinfo, &offset, ofp_table_stats_wildcards); + add_child(table_tree, ofp_table_stats_max_entries, tvb, &offset, 4); + add_child(table_tree, ofp_table_stats_active_count, tvb, &offset, 4); + add_child(table_tree, ofp_table_stats_lookup_count, tvb, &offset, 8); + add_child(table_tree, ofp_table_stats_matched_count, tvb, &offset, 8); + } + break; + } + + case OFPST_PORT: { + /* process each port stats struct in the packet */ + while( offset < len ) { + proto_item *port_item = proto_tree_add_item(type_tree, ofp_port_stats, tvb, offset, -1, FALSE); + proto_tree *port_tree = proto_item_add_subtree(port_item, ett_ofp_port_stats); + + dissect_port(port_tree, ofp_port_stats_port_no, tvb, &offset); + dissect_pad(port_tree, &offset, 6); + add_child(port_tree, ofp_port_stats_rx_packets, tvb, &offset, 8); + add_child(port_tree, ofp_port_stats_tx_packets, tvb, &offset, 8); + add_child(port_tree, ofp_port_stats_rx_bytes, tvb, &offset, 8); + add_child(port_tree, ofp_port_stats_tx_bytes, tvb, &offset, 8); + add_child(port_tree, ofp_port_stats_rx_dropped, tvb, &offset, 8); + add_child(port_tree, ofp_port_stats_tx_dropped, tvb, &offset, 8); + add_child(port_tree, ofp_port_stats_rx_errors, tvb, &offset, 8); + add_child(port_tree, ofp_port_stats_tx_errors, tvb, &offset, 8); + add_child(port_tree, ofp_port_stats_rx_frame_err, tvb, &offset, 8); + add_child(port_tree, ofp_port_stats_rx_over_err, tvb, &offset, 8); + add_child(port_tree, ofp_port_stats_rx_crc_err, tvb, &offset, 8); + add_child(port_tree, ofp_port_stats_collisions, tvb, &offset, 8); + } + break; + } + + case OFPST_QUEUE: { + /* process each port stats struct in the packet */ + while( offset < len ) { + proto_item *queue_item = proto_tree_add_item(type_tree, ofp_queue_stats, tvb, offset, -1, FALSE); + proto_tree *queue_tree = proto_item_add_subtree(queue_item, ett_ofp_queue_stats); + + dissect_port(queue_tree, ofp_queue_stats_port_no, tvb, &offset); + dissect_pad(queue_tree, &offset, 2); + dissect_queue_id(queue_tree, ofp_queue_stats_queue_id, tvb, &offset); + add_child(queue_tree, ofp_queue_stats_tx_bytes, tvb, &offset, 8); + add_child(queue_tree, ofp_queue_stats_tx_packets, tvb, &offset, 8); + add_child(queue_tree, ofp_queue_stats_tx_errors, tvb, &offset, 8); + } + break; + } + + case OFPST_VENDOR: { + proto_item* vendor_item = proto_tree_add_item(type_tree, ofp_vendor_stats, tvb, offset, -1, FALSE); + proto_tree* vendor_tree = proto_item_add_subtree(vendor_item, ett_ofp_vendor_stats); + + add_child(vendor_tree, ofp_vendor_stats_vendor, tvb, &offset, 4); + add_child(vendor_tree, ofp_vendor_stats_body, tvb, &offset, len - offset); + + break; + } + + default: + /* add as bytes if type isn't one we know how to dissect */ + add_child(type_tree, ofp_stats_reply_body, tvb, &offset, len - offset); + } + + break; + } + + default: + /* add a warning if we encounter an unrecognized packet type */ + snprintf(str, STR_LEN, "Dissector does not recognize type %u", type); + add_child_str(tree, ofp_header_warn_type, tvb, &offset, len - offset, str); + } + } +} + +static void dissect_openflow(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + /* have wireshark reassemble our PDUs; call dissect_openflow_when full PDU assembled */ + tcp_dissect_pdus(tvb, pinfo, tree, TRUE, 4, get_openflow_message_len, dissect_openflow_message); +} diff --git a/openflow/utilities/wireshark_dissectors/openflow/plugin.c b/openflow/utilities/wireshark_dissectors/openflow/plugin.c new file mode 100644 index 00000000..deb99c25 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/openflow/plugin.c @@ -0,0 +1,28 @@ +/* Do not modify this file. */ +/* It is created automatically by the Makefile. */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "moduleinfo.h" + +#ifndef ENABLE_STATIC +G_MODULE_EXPORT const gchar version[] = VERSION; + +/* Start the functions we need for the plugin stuff */ + +G_MODULE_EXPORT void +plugin_register (void) +{ + {extern void proto_register_openflow (void); proto_register_openflow ();} +} + +G_MODULE_EXPORT void +plugin_reg_handoff(void) +{ + {extern void proto_reg_handoff_openflow (void); proto_reg_handoff_openflow ();} +} +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/airpcap.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/airpcap.h new file mode 100644 index 00000000..639a930a --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/airpcap.h @@ -0,0 +1,907 @@ +/* + * Copyright (c) 2006-2007 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#if !defined(AIRPCAP_H__EAE405F5_0171_9592_B3C2_C19EC426AD34__INCLUDED_) +#define AIRPCAP_H__EAE405F5_0171_9592_B3C2_C19EC426AD34__INCLUDED_ + +#ifdef _MSC_VER +// This disables a VS warning for zero-sized arrays. +#pragma warning( disable : 4200) +// This stops VS2005 ranting against stdio. +#pragma warning( disable : 4996) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + \mainpage AirPcap interface documentation + + \section Introduction + + This document describes the data structures and the functions exported by the CACE Technologies AirPcap library. + The AirPcap library provides low-level access to the AirPcap driver including advanced capabilities such as channel setting, + link type control and WEP configuration.
+ This manual includes the following sections: + + \note throughout this documentation, \e device refers to a physical USB AirPcap device, while \e adapter is an open API + instance. Most of the AirPcap API operations are adapter-specific but some of them, like setting the channel, are + per-device and will be reflected on all the open adapters. These functions will have "Device" in their name, e.g. + AirpcapSetDeviceChannel(). + + \b Sections: + + - \ref airpcapfuncs + - \ref airpcapdefs + - \ref radiotap +*/ + +/** @defgroup airpcapdefs AirPcap definitions and data structures + * @{ + */ + +/*! + \brief This string is the fixed prefix in the airpcap adapter name. + It can be used to parse the name field in an AirpcapDeviceDescription structure. +*/ +#define AIRPCAP_DEVICE_NAME_PREFIX "\\\\.\\airpcap" + +/*! + \brief This string is the scanf modifier to extract the adapter number from an adapter name. + It can be used to parse the name field in an AirpcapDeviceDescription structure with scanf. +*/ +#define AIRPCAP_DEVICE_NUMBER_EXTRACT_STRING "\\\\.\\airpcap%u" + +#define AIRPCAP_DEVICE_ANY_EXTRACT_STRING "\\\\.\\airpcap_any" + +/*! + \brief Entry in the list returned by \ref AirpcapGetDeviceList(); +*/ +typedef struct _AirpcapDeviceDescription +{ + struct _AirpcapDeviceDescription *next; ///< Next element in the list + PCHAR Name; ///< Device name + PCHAR Description; ///< Device description +} AirpcapDeviceDescription, *PAirpcapDeviceDescription; + +#define MAX_ENCRYPTION_KEYS 64 + +#define WEP_KEY_MAX_SIZE 32 ///< Maximum size of a WEP key, in bytes. This is the size of an entry in the + ///< AirpcapWepKeysCollection structure + +#ifndef __MINGW32__ +#pragma pack(push) +#pragma pack(1) +#endif // __MINGW32__ + + +#define AIRPCAP_KEYTYPE_WEP 0 ///< Key type: WEP. The key can have an arbitrary length smaller than 32 bytes. +#define AIRPCAP_KEYTYPE_TKIP 1 ///< Key type: TKIP (WPA). NOT SUPPORTED YET. +#define AIRPCAP_KEYTYPE_CCMP 2 ///< Key type: CCMP (WPA2). NOT SUPPORTED YET. + +/*! + \brief WEP key container +*/ +typedef struct _AirpcapKey +{ + UINT KeyType; ///< Type of key, can be on of: \ref AIRPCAP_KEYTYPE_WEP, \ref AIRPCAP_KEYTYPE_TKIP, \ref AIRPCAP_KEYTYPE_CCMP. Only AIRPCAP_KEYTYPE_WEP is supported by the driver at the moment. + UINT KeyLen; ///< Length of the key, in bytes + BYTE KeyData[WEP_KEY_MAX_SIZE]; ///< Key Data +} +#ifdef __MINGW32__ +__attribute__((__packed__)) +#endif // __MINGW32__ +AirpcapKey, *PAirpcapKey; + +/*! + \brief frequency Band. + 802.11 adapters can support different frequency bands, the most important of which are: 2.4GHz (802.11b/g/n) + and 5GHz (802.11a/n). +*/ +typedef enum _AirpcapChannelBand +{ + AIRPCAP_CB_AUTO = 1, ///< Automatically pick the best frequency band + AIRPCAP_CB_2_4_GHZ = 2, ///< 2.4 GHz frequency band + AIRPCAP_CB_4_GHZ = 4, ///< 4 GHz frequency band + AIRPCAP_CB_5_GHZ = 5 ///< 5 GHz frequency band +}AirpcapChannelBand, *PAirpcapChannelBand; + +/*! + \brief Type of frame validation the adapter performs. + An adapter can be instructed to accept different kind of frames: correct frames only, frames with wrong Frame Check Sequence (FCS) only, all frames. +*/ +typedef enum _AirpcapValidationType +{ + AIRPCAP_VT_ACCEPT_EVERYTHING = 1, ///< Accept all the frames the device captures + AIRPCAP_VT_ACCEPT_CORRECT_FRAMES = 2, ///< Accept correct frames only, i.e. frames with correct Frame Check Sequence (FCS). + AIRPCAP_VT_ACCEPT_CORRUPT_FRAMES = 3, ///< Accept corrupt frames only, i.e. frames with worng Frame Check Sequence (FCS). + AIRPCAP_VT_UNKNOWN = 4 ///< Unknown validation type. You should see it only in case of error. +}AirpcapValidationType, *PAirpcapValidationType; + +/*! + \brief Type of decryption the adapter performs. + An adapter can be instructed to turn decryption (based on the device-configured keys configured + with \ref AirpcapSetDeviceKeys()) on or off. +*/ +typedef enum _AirpcapDecryptionState +{ + AIRPCAP_DECRYPTION_ON = 1, ///< This adapter performs decryption + AIRPCAP_DECRYPTION_OFF = 2 ///< This adapter does not perform decryption +}AirpcapDecryptionState, *PAirpcapDecryptionState; + + +/*! + \brief Storage for a MAC address +*/ +typedef struct _AirpcapMacAddress +{ + BYTE Address[6]; ///< MAC address bytes +} +#ifdef __MINGW32__ +__attribute__((__packed__)) +#endif // __MINGW32__ +AirpcapMacAddress, *PAirpcapMacAddress; + +/*! + \brief This structure is used to store a collection of WEP keys. + Note that the definition of the structure doesn't contain any key, so be careful to allocate a buffer + with the size of the key, like in the following example: + + \code + PAirpcapKeysCollection KeysCollection; + UINT KeysCollectionSize; + + KeysCollectionSize = sizeof(AirpcapKeysCollection) + NumKeys * sizeof(AirpcapKey); + + KeysCollection = (PAirpcapKeysCollection)malloc(KeysCollectionSize); + if(!KeysCollection) + { + // Error + } + \endcode +*/ +typedef struct _AirpcapKeysCollection +{ + UINT nKeys; ///< Number of keys in the collection + AirpcapKey Keys[0]; ///< Array of nKeys keys. +} AirpcapKeysCollection, *PAirpcapKeysCollection; + +/*! + \brief Packet header. + + This structure defines the BPF that preceeds every packet delivered to the application. +*/ +typedef struct _AirpcapBpfHeader +{ + UINT TsSec; ///< Timestamp associated with the captured packet. SECONDS. + UINT TsUsec; ///< Timestamp associated with the captured packet. MICROSECONDS. + UINT Caplen; ///< Length of captured portion. The captured portion can be different from the original packet, because it is possible (with a proper filter) to instruct the driver to capture only a portion of the packets. + UINT Originallen; ///< Original length of packet + USHORT Hdrlen; ///< Length of bpf header (this struct plus alignment padding). In some cases, a padding could be added between the end of this structure and the packet data for performance reasons. This field can be used to retrieve the actual data of the packet. +} +#ifdef __MINGW32__ +__attribute__((__packed__)) +#endif // __MINGW32__ +AirpcapBpfHeader, *PAirpcapBpfHeader; + +/// Helper macros to extract packets coming from the driver. Rounds up to the next even multiple of AIRPCAP_ALIGNMENT. +#define AIRPCAP_ALIGNMENT sizeof(int) +#define AIRPCAP_WORDALIGN(x) (((x)+(AIRPCAP_ALIGNMENT-1))&~(AIRPCAP_ALIGNMENT-1)) + +#ifndef __MINGW32__ +#pragma pack(pop) +#endif // __MINGW32__ + +#define AIRPCAP_ERRBUF_SIZE 512 ///< Size of the error buffer, in bytes + +#ifndef __AIRPCAP_DRIVER__ + +/*! + \brief Link type. + AirPcap supports two kind of 802.11 linktypes: plain 802.11 and radiotap. +*/ +#undef _AirpcapLinkType +typedef enum _AirpcapLinkType +{ + AIRPCAP_LT_802_11 = 1, ///< plain 802.11 linktype. Every packet in the buffer contains the raw 802.11 frame, including MAC FCS. + AIRPCAP_LT_802_11_PLUS_RADIO = 2, ///< 802.11 plus radiotap linktype. Every packet in the buffer contains a radiotap header followed by the 802.11 frame. MAC FCS is included. + AIRPCAP_LT_UNKNOWN = 3, ///< Unknown linktype. You should see it only in case of error. + AIRPCAP_LT_802_11_PLUS_PPI = 4 ///< 802.11 plus PPI header linktype. Every packet in the buffer contains a PPI header followed by the 802.11 frame. MAC FCS is included. +}AirpcapLinkType, *PAirpcapLinkType; + +#if !defined(AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_) +#define AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_ +/*! + \brief Adapter handle. +*/ +typedef struct _AirpcapHandle AirpcapHandle, *PAirpcapHandle; +#endif + +/*! + \brief Capture statistics. + Returned by \ref AirpcapGetStats(); +*/ +typedef struct _AirpcapStats +{ + UINT Recvs; ///< Number of packets that the driver received by the adapter + ///< from the beginning of the current capture. This value includes the packets + ///< dropped because of buffer full. + UINT Drops; ///< number of packets that the driver dropped from the beginning of a capture. + ///< A packet is lost when the the buffer of the driver is full. + UINT IfDrops; ///< Packets dropped by the card before going to the USB bus. + ///< Not supported at the moment. + UINT Capt; ///< number of packets that pass the BPF filter, find place in the kernel buffer and + ///< therefore reach the application. +}AirpcapStats, *PAirpcapStats; + +/*! + \brief Channel information. + Used by \ref AirpcapSetDeviceChannelEx(), \ref AirpcapGetDeviceChannelEx(), \ref AirpcapGetDeviceSupportedChannels() +*/ +typedef struct _AirpcapChannelInfo +{ + UINT Frequency; ///< Channel frequency, in MHz. + /*! + \brief 802.11n specific. Offset of the extension channel in case of 40MHz channels. + + Possible values are -1, 0 +1: + - -1 means that the extension channel should be below the control channel (e.g. Control = 5 and Extension = 1) + - 0 means that no extension channel should be used (20MHz channels or legacy mode) + - +1 means that the extension channel should be above the control channel (e.g. Control = 1 and Extension = 5) + + In case of 802.11a/b/g channels (802.11n legacy mode), this field should be set to 0. + */ + CHAR ExtChannel; + UCHAR Reserved[3]; ///< Reserved. It should be set to {0,0,0}. +} + AirpcapChannelInfo, *PAirpcapChannelInfo; + + +/*@}*/ + +/** @defgroup airpcapfuncs AirPcap functions + * @{ + */ + +/*! + \brief Return a string with the API version + \param VersionMajor Pointer to a variable that will be filled with the major version number. + \param VersionMinor Pointer to a variable that will be filled with the minor version number. + \param VersionRev Pointer to a variable that will be filled with the revision number. + \param VersionBuild Pointer to a variable that will be filled with the build number. +*/ +void AirpcapGetVersion(PUINT VersionMajor, PUINT VersionMinor, PUINT VersionRev, PUINT VersionBuild); + +/*! + \brief Return the last error related to the specified handle + \param AdapterHandle Handle to an open adapter. + \return The string with the last error. +*/ +PCHAR AirpcapGetLastError(PAirpcapHandle AdapterHandle); + +/*! + \brief Return the list of available devices + \param PPAllDevs Address to a caller allocated pointer. On success this pointer will receive the head of a list of available devices. + \param Ebuf String that will contain error information if FALSE is returned. The size of the string must be AIRPCAP_ERRBUF_SIZE bytes. + \return TRUE on success. FALSE is returned on failure, in which case Ebuf is filled in with an appropriate error message. + + Here's a snippet of code that shows how to use AirpcapGetDeviceList(): + + \code + CHAR Ebuf[AIRPCAP_ERRBUF_SIZE]; + AirpcapDeviceDescription *Desc, *tDesc; + + if(AirpcapGetDeviceList(&Desc, Ebuf) == -1) + { + printf("Unable to get the list of devices: %s\n", Ebuf); + return -1; + } + + for(tDesc = Desc; tDesc; tDesc = tDesc->next) + { + printf("%u) %s (%s)\n", + ++i, + tDesc->Name, + tDesc->Description); + } + + AirpcapFreeDeviceList(Desc); + \endcode +*/ +BOOL AirpcapGetDeviceList(PAirpcapDeviceDescription *PPAllDevs, PCHAR Ebuf); + +/*! + \brief Free a list of devices returned by AirpcapGetDeviceList() + \param PAllDevs Head of the list of devices returned by \ref AirpcapGetDeviceList(). +*/ +VOID AirpcapFreeDeviceList(PAirpcapDeviceDescription PAllDevs); + +/*! + \brief Open an adapter + \param DeviceName Name of the device to open. Use \ref AirpcapGetDeviceList() to get the list of devices. + \param Ebuf String that will contain error information in case of failure. The size of the string must be AIRPCAP_ERRBUF_SIZE bytes. + \return A PAirpcapHandle handle on success. NULL is returned on failure, in which case Ebuf is filled in with an appropriate error message. +*/ +PAirpcapHandle AirpcapOpen(PCHAR DeviceName, PCHAR Ebuf); + +/*! + \brief Close an adapter + \param AdapterHandle Handle to the adapter to close. +*/ +VOID AirpcapClose(PAirpcapHandle AdapterHandle); + +/*! + \brief Sets the monitor mode for the specified adapter + \param AdapterHandle Handle to the adapter. + \param MonitorModeEnabled If TRUE, the adapter will be put in monitor mode. If FALSE, the adapter will be configured + for normal operation. + \return TRUE on success. + + When monitor mode is on, the adapter captures all the packets transmitted on the channel. This includes: + + - unicast packets + - multicast packets + - broadcast packets + - control and management packets + + When monitor mode is off, the adapter has a filter on unicast packets to capture only the packets whose MAC + destination address equals to the adapter's address. This means the following frames will be received: + + - unicast packets with the address of the adapter + - multicast packets + - broadcast packets + - beacons and probe requests + + The main reason to turn monitor mode off is that, when not in monitor mode, the adapter will acknowledge the + data frames sent to its address. This is useful when the adapter needs to interact with other devices on the + 802.11 network, bacause handling the ACKs in software is too slow. + + \note When an adapter is plugged into the system, it's always configured with monitor mode ON. The monitor mode + configuration is not stored persistently, so if you want to turn monitor mode off, you will need to do it + every time you open the adapter. +*/ +BOOL AirpcapSetMonitorMode(PAirpcapHandle AdapterHandle, BOOL MonitorModeEnabled); + +/*! + \brief Returns TRUE if the specified adapter is in monitor mode. + \param AdapterHandle Handle to the adapter. + \param PMonitorModeEnabled User-provided variable that will be set to true if the adapter is in monitor mode. + \return TRUE if the operation is successful. FALSE otherwise. + + \note When an adapter is plugged into the system, it's always configured with monitor mode ON. The monitor mode + configuration is not stored persistently, so if you want to turn monitor mode off, you will need to do it + every time you open the adapter. +*/ +BOOL AirpcapGetMonitorMode(PAirpcapHandle AdapterHandle, PBOOL PMonitorModeEnabled); + +/*! + \brief Set the link type of an adapter + \param AdapterHandle Handle to the adapter. + \param NewLinkType the "link type", i.e. the format of the frames that will be received from the adapter. + \return TRUE on success. + + the "link type" determines how the driver will encode the packets captured from the network. + Aircap supports two link types: + - \ref AIRPCAP_LT_802_11, to capture 802.11 frames (including control frames) without any + power information. Look at the Capture_no_radio example application in the developer's pack + for a reference on how to decode 802.11 frames with this link type. + - \ref AIRPCAP_LT_802_11_PLUS_RADIO, to capture 802.11 frames (including control frames) with a radiotap header + that contains power and channel information. More information about the radiotap header can be found in the + \ref radiotap section. Moreover, the "Capture_radio" example application in + the developer's pack can be used as a reference on how to decode 802.11 frames with radiotap headers. + - \ref AIRPCAP_LT_802_11_PLUS_PPI, to capture 802.11 frames (including control frames) with a Per Packet Information (PPI) + header that contains per-packet meta information like channel and power information. More details on the PPI header can + be founf in the PPI online documentation (TODO). +*/ +BOOL AirpcapSetLinkType(PAirpcapHandle AdapterHandle, AirpcapLinkType NewLinkType); + +/*! + \brief Get the link type of the specified adapter + \param AdapterHandle Handle to the adapter. + \param PLinkType Pointer to a caller allocated AirpcapLinkType variable that will contain the link type of the adapter. + \return TRUE on success. + + the "link type" determines how the driver will encode the packets captured from the network. + Aircap supports two link types: + - AIRPCAP_LT_802_11, to capture 802.11 frames (including control frames) without any + power information. Look at the Capture_no_radio example application in the developer's pack + for a reference on how to decode 802.11 frames with this link type. + - AIRPCAP_LT_802_11_PLUS_RADIO, to capture 802.11 frames (including control frames) with a radiotap header + that contains power and channel information. More information about the radiotap header can be found int the + \ref radiotap section. Moreover, the "Capture_radio" example application in + the developer's pack can be used as a reference on how to decode 802.11 frames with radiotap headers. +*/ +BOOL AirpcapGetLinkType(PAirpcapHandle AdapterHandle, PAirpcapLinkType PLinkType); + +/*! + \brief Configures the adapter on whether to include the MAC Frame Check Sequence in the captured packets. + \param AdapterHandle Handle to the adapter. + \param IsFcsPresent TRUE if the packets should include the FCS. FALSE otherwise + \return TRUE on success. + + In the default configuration, the adapter includes the FCS in the captured packets. The MAC Frame Check Sequence + is 4 bytes and is located at the end of the 802.11 packet, with both AIRPCAP_LT_802_11 and AIRPCAP_LT_802_11_PLUS_RADIO + link types. + When the FCS inclusion is turned on, and if the link type is AIRPCAP_LT_802_11_PLUS_RADIO, the radiotap header + that precedes each frame has two additional fields at the end: Padding and FCS. These two fields are not present + when FCS inclusion is off. +*/ +BOOL AirpcapSetFcsPresence(PAirpcapHandle AdapterHandle, BOOL IsFcsPresent); + +/*! + \brief Returns TRUE if the specified adapter includes the MAC Frame Check Sequence in the captured packets + \param AdapterHandle Handle to the adapter. + \param PIsFcsPresent User-provided variable that will be set to true if the adapter is including the FCS. + \return TRUE if the operation is successful. FALSE otherwise. + + In the default configuration, the adatper has FCS inclusion turned on. The MAC Frame Check Sequence is 4 bytes + and is located at the end of the 802.11 packet, with both AIRPCAP_LT_802_11 and AIRPCAP_LT_802_11_PLUS_RADIO + link types. + When the FCS inclusion is turned on, and if the link type is AIRPCAP_LT_802_11_PLUS_RADIO, the radiotap header + that precedes each frame has two additional fields at the end: Padding and FCS. These two fields are not present + when FCS inclusion is off. +*/ +BOOL AirpcapGetFcsPresence(PAirpcapHandle AdapterHandle, PBOOL PIsFcsPresent); + +/*! + \brief Configures the adapter to accept or drop frames with an incorrect Frame Check sequence (FCS). + \param AdapterHandle Handle to the adapter. + \param ValidationType The type of validation the driver will perform. See the documentation of \ref AirpcapValidationType for details. + \return TRUE on success. + + \note By default, the driver is configured in \ref AIRPCAP_VT_ACCEPT_EVERYTHING mode. +*/ +BOOL AirpcapSetFcsValidation(PAirpcapHandle AdapterHandle, AirpcapValidationType ValidationType); + +/*! + \brief Checks if the specified adapter is configured to capture frames with incorrect an incorrect Frame Check Sequence (FCS). + \param AdapterHandle Handle to the adapter. + \param ValidationType Pointer to a user supplied variable that will contain the type of validation the driver will perform. See the documentation of \ref AirpcapValidationType for details. + \return TRUE if the operation is succesful. FALSE otherwise. + + \note By default, the driver is configured in \ref AIRPCAP_VT_ACCEPT_EVERYTHING mode. +*/ +BOOL AirpcapGetFcsValidation(PAirpcapHandle AdapterHandle, PAirpcapValidationType ValidationType); + +/*! + \brief Set the list of decryption keys that the driver is going to use with the specified device. + \param AdapterHandle Handle an open adapter instance. + \param KeysCollection Pointer to a \ref PAirpcapKeysCollection structure that contains the keys to be set in the driver. + \return TRUE if the operation is successful. FALSE otherwise. + + The AirPcap driver is able to use a set of decryption keys to decrypt the traffic transmitted on a specific SSID. If one of the + keys corresponds to the one the frame has been encrypted with, the driver will perform decryption and return the cleartext frames + to the application. + + This function allows to set the adapter-specific set of keys. These keys will be used by the specified adapter only, + and will not be used by other airpcap devices besides the specified one. + + At this time, the only supported decryption method is WEP. + + The keys are applied to the packets in the same order they appear in the KeysCollection structure until the packet is + correctly decrypted, therefore putting frequently used keys at the beginning of the structure improves performance. + + \note: when you change the set of keys from an open capture instance, the change will be + immediately reflected on all the other capture instances. +*/ +BOOL AirpcapSetDeviceKeys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection); + +/*! + \brief Returns the list of decryption keys in the driver that are currently associated with the specified device + \param AdapterHandle Handle to an open adapter instance. + \param KeysCollection User-allocated PAirpcapKeysCollection structure that will be filled with the keys. + \param PKeysCollectionSize \b IN: pointer to a user-allocated variable that contains the length of the KeysCollection structure, in bytes. + \b OUT: amount of data moved by the driver in the buffer pointed by KeysBuffer, in bytes. + \return TRUE if the operation is succesful. If an error occurs, the return value is FALSE and KeysCollectionSize is zero. + If the provided buffer is too small to contain the keys, the return value is FALSE and KeysCollectionSize contains the + needed KeysCollection length, in bytes. If the device doesn't have any decryption key configured, the return value is TRUE, and + KeysCollectionSize will be zero. + + This function returns the adapter-specific set of keys. These keys are used by the specified adapter only, + and not by other airpcap devices besides the specified one. + + The AirPcap driver is able to use a set of decryption keys to decrypt the traffic transmitted on a specific SSID. If one of the + keys corresponds to the one the frame has been encrypted with, the driver will perform decryption and return the cleartext frames + to the application. + The driver supports, for every device, multiple keys at the same time. + + The configured decryption keys are device-specific, therefore AirpcapGetDeviceKeys() will return a different set of keys + when called on different devices. + + At this time, the only supported decryption method is WEP. +*/ +BOOL AirpcapGetDeviceKeys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, PUINT PKeysCollectionSize); + +/*! + \brief Set the global list of decryption keys that the driver is going to use with all the devices. + \param AdapterHandle Handle an open adapter instance. + \param KeysCollection Pointer to a \ref PAirpcapKeysCollection structure that contains the keys to be set in the driver. + \return TRUE if the operation is successful. FALSE otherwise. + + The AirPcap driver is able to use a set of decryption keys to decrypt the traffic transmitted on a specific SSID. If one of the + keys corresponds to the one the frame has been encrypted with, the driver will perform decryption and return the cleartext frames + to the application. + + This function allows to set the global driver set of keys. These keys will be used by all the adapters plugged in + the machine. + + At this time, the only supported decryption method is WEP. + + The keys are applied to the packets in the same order they appear in the KeysCollection structure until the packet is + correctly decrypted, therefore putting frequently used keys at the beginning of the structure improves performance. + + \note: when you change the set of keys from an open capture instance, the change will be + immediately reflected on all the other capture instances. +*/ +BOOL AirpcapSetDriverKeys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection); + +/*! + \brief Returns the global list of decryption keys in the driver that are associated with all the devices. + \param AdapterHandle Handle to an open adapter instance. + \param KeysCollection User-allocated PAirpcapKeysCollection structure that will be filled with the keys. + \param PKeysCollectionSize \b IN: pointer to a user-allocated variable that contains the length of the KeysCollection structure, in bytes. + \b OUT: amount of data moved by the driver in the buffer pointed by KeysBuffer, in bytes. + \return TRUE if the operation is succesful. If an error occurs, the return value is FALSE and KeysCollectionSize is zero. + If the provided buffer is too small to contain the keys, the return value is FALSE and KeysCollectionSize contains the + needed KeysCollection length, in bytes. If the device doesn't have any decryption key configured, the return value is TRUE, and + KeysCollectionSize will be zero. + + This function returns the global driver set of keys. These keys will be used by all the adapters plugged in + the machine. + + The AirPcap driver is able to use a set of decryption keys to decrypt the traffic transmitted on a specific SSID. If one of the + keys corresponds to the one the frame has been encrypted with, the driver will perform decryption and return the cleartext frames + to the application. + + At this time, the only supported decryption method is WEP. +*/ +BOOL AirpcapGetDriverKeys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, PUINT PKeysCollectionSize); + +/*! + \brief Turns on or off the decryption of the incoming frames with the adapter-specific keys. + \param AdapterHandle Handle to the adapter. + \param Enable Either \ref AIRPCAP_DECRYPTION_ON or \ref AIRPCAP_DECRYPTION_OFF + \return TRUE on success. + + The adapter-specific decryption keys can be configured with the \ref AirpcapSetDeviceKeys() function. + \note By default, the driver is configured with \ref AIRPCAP_DECRYPTION_ON. +*/ +BOOL AirpcapSetDecryptionState(PAirpcapHandle AdapterHandle, AirpcapDecryptionState Enable); + +/*! + \brief Tells if this open instance is configured to perform the decryption of the incoming frames with the adapter-specific keys. + \param AdapterHandle Handle to the adapter. + \param PEnable Pointer to a user supplied variable that will contain the decryption configuration. See \ref PAirpcapDecryptionState for details. + \return TRUE if the operation is succesful. FALSE otherwise. + + The adapter-specific decryption keys can be configured with the \ref AirpcapSetDeviceKeys() function. + \note By default, the driver is configured with \ref AIRPCAP_DECRYPTION_ON. +*/ +BOOL AirpcapGetDecryptionState(PAirpcapHandle AdapterHandle, PAirpcapDecryptionState PEnable); + +/*! + \brief Turns on or off the decryption of the incoming frames with the global driver set of keys. + \param AdapterHandle Handle to the adapter. + \param Enable Either \ref AIRPCAP_DECRYPTION_ON or \ref AIRPCAP_DECRYPTION_OFF + \return TRUE on success. + + The global decryption keys can be configured with the \ref AirpcapSetDriverKeys() function. + \note By default, the driver is configured with \ref AIRPCAP_DECRYPTION_ON. +*/ +BOOL AirpcapSetDriverDecryptionState(PAirpcapHandle AdapterHandle, AirpcapDecryptionState Enable); + +/*! + \brief Tells if this open instance is configured to perform the decryption of the incoming frames with the global driver set of keys. + \param AdapterHandle Handle to the adapter. + \param PEnable Pointer to a user supplied variable that will contain the decryption configuration. See \ref PAirpcapDecryptionState for details. + \return TRUE if the operation is succesful. FALSE otherwise. + + The global decryption keys can be configured with the \ref AirpcapSetDriverKeys() function. + \note By default, the driver is configured with \ref AIRPCAP_DECRYPTION_ON. +*/ +BOOL AirpcapGetDriverDecryptionState(PAirpcapHandle AdapterHandle, PAirpcapDecryptionState PEnable); + +/*! + \brief Set the radio channel of a device + \param AdapterHandle Handle to the adapter. + \param Channel the new channel to set. + \return TRUE on success. + + The list of available channels can be retrieved with \ref AirpcapGetDeviceSupportedChannels(). The default channel setting is 6. + + \note this is a device-related function: when you change the channel from an open capture instance, the change will be + immediately reflected on all the other capture instances. +*/ +BOOL AirpcapSetDeviceChannel(PAirpcapHandle AdapterHandle, UINT Channel); + +/*! + \brief Get the radio channel of a device + \param AdapterHandle Handle to the adapter. + \param PChannel Pointer to a user-supplied variable into which the function will copy the currently configured radio channel. + \return TRUE on success. + + The list of available channels can be retrieved with \ref AirpcapGetDeviceSupportedChannels(). The default channel setting is 6. + + \note this is a device-related function: when you change the channel from an open capture instance, the change will be + immediately reflected on all the other capture instances. +*/ +BOOL AirpcapGetDeviceChannel(PAirpcapHandle AdapterHandle, PUINT PChannel); + +/*! + \brief Set the size of the kernel packet buffer for this adapter + \param AdapterHandle Handle to the adapter. + \param BufferSize New size, in bytes. + \return TRUE on success. + + Every AirPcap open instance has an associated kernel buffer, whose default size is 1 Mbyte. + This function can be used to change the size of this buffer, and can be called at any time. + A bigger kernel buffer size decreases the risk of dropping packets during network bursts or when the + application is busy, at the cost of higher kernel memory usage. + + \note don't use this function unless you know what you are doing. Due to caching issues and bigger non-paged + memory consumption, bigger buffer sizes can decrease the capture performace instead of improving it. +*/ +BOOL AirpcapSetKernelBuffer(PAirpcapHandle AdapterHandle, UINT BufferSize); + +/*! + \brief Get the size of the kernel packet buffer for this adapter + \param AdapterHandle Handle to the adapter. + \param PSizeBytes User-allocated variable that will be filled with the size of the kernel buffer. + \return TRUE on success. + + Every AirPcap open instance has an associated kernel buffer, whose default size is 1 Mbyte. + This function can be used to get the size of this buffer. +*/ +BOOL AirpcapGetKernelBufferSize(PAirpcapHandle AdapterHandle, PUINT PSizeBytes); + +/*! + \brief Saves the configuration of the specified adapter in the registry, so that it becomes the default for this adapter. + \param AdapterHandle Handle to the adapter. + \return TRUE on success. FALSE on failure. + + Almost all the AirPcap calls that modify the configuration (\ref AirpcapSetLinkType(), \ref AirpcapSetFcsPresence(), + \ref AirpcapSetFcsValidation(), \ref AirpcapSetKernelBuffer(), \ref AirpcapSetMinToCopy()) + affect only the referenced AirPcap open instance. This means that if you do another \ref AirpcapOpen() on the same + adapter, the configuration changes will not be remembered, and the new adapter handle will have default configuration + settings. + + Exceptions to this rule are the \ref AirpcapSetDeviceChannel() and \ref AirpcapSetDeviceKeys() functions: a channel change is + reflected on all the open instances, and remembered until the next call to \ref AirpcapSetDeviceChannel(), until the adapter + is unplugged, or until the machine is powered off. Same thing for the configuration of the WEP keys. + + AirpcapStoreCurConfigAsAdapterDefault() stores the configuration of the give open instance as the default for the adapter: + all the instances opened in the future will have the same configuration that this adapter currently has. + The configuration is stored in the registry, therefore it is remembered even when the adapter is unplugged or the + machine is turned off. However, an adapter doesn't bring its configuration with it from machine to machine. + + the configuration information saved in the registry includes the following parameters: + - channel + - kernel buffer size + - mintocopy + - link type + - CRC presence + - Encryption keys + - Encryption Enabled/Disabled state + + The configuration is adapter-specific. This means that changing the configuration of an adapter + doesn't modify the one of the other adapters that are currently used or that will be used in the future. + + \note AirpcapStoreCurConfigAsAdapterDefault() must have exclusive access to the adapter -- it + will fail if more than one AirPcap handle is opened at the same time for this adapter. + AirpcapStoreCurConfigAsAdapterDefault() needs administrator privileges. It will fail if the calling user + is not a local machine administrator. +*/ +BOOL AirpcapStoreCurConfigAsAdapterDefault(PAirpcapHandle AdapterHandle); + +/*! + \brief Set the BPF kernel filter for an adapter + \param AdapterHandle Handle to the adapter. + \param Instructions pointer to the first BPF instruction in the array. Corresponds to the bf_insns + in a bpf_program structure (see the WinPcap documentation at http://www.winpcap.org/devel.htm). + \param Len Number of instructions in the array pointed by the previous field. Corresponds to the bf_len in + a a bpf_program structure (see the WinPcap documentation at http://www.winpcap.org/devel.htm). + \return TRUE on success. + + The AirPcap driver is able to perform kernel-level filtering using the standard BPF pseudo-machine format. You can read + the WinPcap documentation at http://www.winpcap.org/devel.htm for more details on the BPF filtering mechaism. + + A filter can be automatically created by using the pcap_compile() function of the WinPcap API. This function + converts a human readable text expression with the tcpdump/libpcap syntax into a BPF program. + If your program doesn't link wpcap, but you need to generate the code for a particular filter, you can run WinDump + with the -d or -dd or -ddd flags to obtain the pseudocode. + +*/ +BOOL AirpcapSetFilter(PAirpcapHandle AdapterHandle, PVOID Instructions, UINT Len); + +/*! + \brief Return the MAC address of an adapter. + \param AdapterHandle Handle to the adapter. + \param PMacAddress Pointer to a user allocated MAC address. + The size of this buffer needs to be at least 6 bytes. + \return TRUE on success. +*/ +BOOL AirpcapGetMacAddress(PAirpcapHandle AdapterHandle, PAirpcapMacAddress PMacAddress); + +/*! + \brief Set the mintocopy parameter for an open adapter + \param AdapterHandle Handle to the adapter. + \param MinToCopy is the mintocopy size in bytes. + \return TRUE on success. + + When the number of bytes in the kernel buffer changes from less than mintocopy bytes to greater than or equal to mintocopy bytes, + the read event is signalled (see \ref AirpcapGetReadEvent()). A high value for mintocopy results in poor responsiveness since the + driver may signal the application "long" after the arrival of the packet. And a high value results in low CPU loading + by minimizing the number of user/kernel context switches. + A low MinToCopy results in good responsiveness since the driver will signal the application close to the arrival time of + the packet. This has higher CPU loading over the first approach. +*/ +BOOL AirpcapSetMinToCopy(PAirpcapHandle AdapterHandle, UINT MinToCopy); + +/*! + \brief Gets an event that is signaled when that is signalled when packets are available in the kernel buffer (see \ref AirpcapSetMinToCopy()). + \param AdapterHandle Handle to the adapter. + \param PReadEvent Pointer to a user-supplied handle that in which the read event will be copied. + \return TRUE on success. + + \note the event is signalled when at least mintocopy bytes are present in the kernel buffer (see \ref AirpcapSetMinToCopy()). + This event can be used by WaitForSingleObject() and WaitForMultipleObjects() to create blocking behavior when reading + packets from one or more adapters (see \ref AirpcapRead()). +*/ +BOOL AirpcapGetReadEvent(PAirpcapHandle AdapterHandle, HANDLE* PReadEvent); + +/*! + \brief Fills a user-provided buffer with zero or more packets that have been captured on the referenced adapter. + \param AdapterHandle Handle to the adapter. + \param Buffer pointer to the buffer that will be filled with captured packets. + \param BufSize size of the input buffer that will contain the packets, in bytes. + \param PReceievedBytes Pointer to a user supplied variable that will receive the number of bytes copied by AirpcapRead. + Can be smaller than BufSize. + \return TRUE on success. + + 802.11 frames are returned by the driver in buffers. Every 802.11 frame in the buffer is preceded by a \ref AirpcapBpfHeader structure. + The suggested way to use an AirPcap adapter is through the pcap API exported by wpcap.dll. If this is not + possible, the Capture_radio and Capture_no_radio examples in the AirPcap developer's pack show how to properly decode the + packets in the read buffer returned by AirpcapRead(). + + \note this function is NOT blocking. Blocking behavior can be obtained using the event returned + by \ref AirpcapGetReadEvent(). See also \ref AirpcapSetMinToCopy(). +*/ +BOOL AirpcapRead(PAirpcapHandle AdapterHandle, PBYTE Buffer, UINT BufSize, PUINT PReceievedBytes); + +/*! + \brief Transmits a packet. + \param AdapterHandle Handle to the adapter. + \param TxPacket Pointer to a buffer that contains the packet to be transmitted. + \param PacketLen Length of the buffer pointed by the TxPacket argument, in bytes. + \return TRUE on success. + + The packet will be transmitted on the channel the device is currently set. To change the device adapter, use the + \ref AirpcapSetDeviceChannel() function. + + If the linktype of the adapter is AIRPCAP_LT_802_11, the buffer pointed by TxPacket should contain just the 802.11 + packet, without additional information. The packet will be transmitted at 1Mbps. + + If the linktype of the adapter is AIRPCAP_LT_802_11_PLUS_RADIO, the buffer pointed by TxPacket should contain a radiotap + header followed by the 802.11 packet. AirpcapWrite will use the rate information in the radiotap header when + transmitting the packet. +*/ +BOOL AirpcapWrite(PAirpcapHandle AdapterHandle, PCHAR TxPacket, ULONG PacketLen); + +/*! + \brief Get per-adapter WinPcap-compatible capture statistics. + \param AdapterHandle Handle to the adapter. + \param PStats pointer to a user-allocated AirpcapStats structure that will be filled with statistical information. + \return TRUE on success. +*/ +BOOL AirpcapGetStats(PAirpcapHandle AdapterHandle, PAirpcapStats PStats); + +/*! + \brief Get the number of LEDs the referenced adapter has available. + \param AdapterHandle Handle to the adapter. + \param NumberOfLeds Number of LEDs available on this adapter. + \return TRUE on success. +*/ +BOOL AirpcapGetLedsNumber(PAirpcapHandle AdapterHandle, PUINT NumberOfLeds); + +/*! + \brief Turn on one of the adapter's LEDs. + \param AdapterHandle Handle to the adapter. + \param LedNumber zero-based identifier of the LED to turn on. + \return TRUE on success. +*/ +BOOL AirpcapTurnLedOn(PAirpcapHandle AdapterHandle, UINT LedNumber); + +/*! + \brief Turn off one of the adapter's LEDs. + \param AdapterHandle Handle to the adapter. + \param LedNumber zero-based identifier of the LED to turn off. + \return TRUE on success. +*/ +BOOL AirpcapTurnLedOff(PAirpcapHandle AdapterHandle, UINT LedNumber); + +/*! + \brief Set the channel of a device through its radio frequency. In case of 802.11n enabled devices, it sets the extension channel, if used. + \param AdapterHandle Handle to the adapter. + \param ChannelInfo The new channel information to set. + \return TRUE on success. + + \note this is a device-related function: when you change the channel from an open capture instance, the change will be + immediately reflected on all the other capture instances. +*/ +BOOL AirpcapSetDeviceChannelEx(PAirpcapHandle AdapterHandle, AirpcapChannelInfo ChannelInfo); + +/*! + \brief Get the channel of a device through its radiofrequency. In case of 802.11n enabled devices, it gets the extension channel, if in use. + \param AdapterHandle Handle to the adapter. + \param PChannelInfo Pointer to a user-supplied variable into which the function will copy the currently configured channel information. + \return TRUE on success. + + \note this is a device-related function: when you change the channel from an open capture instance, the change will be + immediately reflected on all the other capture instances. +*/ +BOOL AirpcapGetDeviceChannelEx(PAirpcapHandle AdapterHandle, PAirpcapChannelInfo PChannelInfo); + +/*! + \brief Get the list of supported channels for a given device. In case of a 802.11n capable device, information related to supported extension channels is also reported. + + Every control channel is listed multiple times, one for each different supported extension channel. For example channel 6 (2437MHz) is usually listed three times: + - Frequency 2437 Extension +1. Control channel is 6, extension channel is 10. + - Frequency 2437 Extension 0. Control channel is 6, no extension channel is used (20MHz channel and legacy mode). + - Frequency 2437 Extension -1. Control channel is 6, extension channel is 2. + \param AdapterHandle Handle to the adapter. + \param ppChannelInfo Pointer to a user-supplied variable that will point to an array of supported channel. Such list must not be freed by the caller + \param pNumChannelInfo Number of channels returned in the array. + \return TRUE on success. + + \note The supported channels are not listed in any specific order. +*/ +BOOL AirpcapGetDeviceSupportedChannels(PAirpcapHandle AdapterHandle, PAirpcapChannelInfo *ppChannelInfo, PUINT pNumChannelInfo); + +/*! + \brief Converts a given frequency to the corresponding channel. + + \param Frequency Frequency of the channel, in MHz. + \param PChannel Pointer to a user-supplied variable that will contain the channel number on success. + \param PBand Pointer to a user-supplied variable that will contain the band (a or b/g) of the given channel. + \return TRUE on success, i.e. the frequency corresponds to a valid a or b/g channel. +*/ +BOOL AirpcapConvertFrequencyToChannel(UINT Frequency, PUINT PChannel, PAirpcapChannelBand PBand); + +/*! + \brief Converts a given channel to the corresponding frequency. + + \param Channel Channel number to be converted. + \param PFrequency Pointer to a user-supplied variable that will contain the channel frequency in MHz on success. + \return TRUE on success, i.e. the given channel number exists. +*/ +BOOL AirpcapConvertChannelToFrequency(UINT Channel, PUINT PFrequency); + + +/*@}*/ + +#endif // __AIRPCAP_DRIVER__ + +#ifdef __cplusplus +} +#endif + +#endif // !defined(AIRPCAP_H__EAE405F5_0171_9592_B3C2_C19EC426AD34__INCLUDED_) diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/airpcap_loader.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/airpcap_loader.h new file mode 100644 index 00000000..df35b0eb --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/airpcap_loader.h @@ -0,0 +1,560 @@ +/* airpcap_loader.h + * Declarations of routines for the "About" dialog + * + * $Id: airpcap_loader.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Giorgio Tino + * Copyright (c) CACE Technologies, LLC 2006 + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __AIRPCAP_LOADER_H__ +#define __AIRPCAP_LOADER_H__ + +#include + +/* Error values from "get_airpcap_interface_list()". */ +#define CANT_GET_AIRPCAP_INTERFACE_LIST 0 /* error getting list */ +#define NO_AIRPCAP_INTERFACES_FOUND 1 /* list is empty */ +#define AIRPCAP_NOT_LOADED 2 /* Airpcap DLL not loaded */ + +#define AIRPCAP_CHANNEL_ANY_NAME "ANY" + +#define AIRPCAP_WEP_KEY_STRING "WEP" +/* + * XXX - WPA_PWD is the passphrase+ssid and WPA-PSK is the hexadecimal key + */ +#define AIRPCAP_WPA_PWD_KEY_STRING "WPA-PWD" +#define AIRPCAP_WPA_BIN_KEY_STRING "WPA-PSK" + +#define AIRPCAP_DLL_OK 0 +#define AIRPCAP_DLL_OLD 1 +#define AIRPCAP_DLL_ERROR 2 +#define AIRPCAP_DLL_NOT_FOUND 3 + +typedef PCHAR (*AirpcapGetLastErrorHandler)(PAirpcapHandle AdapterHandle); +typedef BOOL (*AirpcapGetDeviceListHandler)(PAirpcapDeviceDescription *PPAllDevs, PCHAR Ebuf); +typedef VOID (*AirpcapFreeDeviceListHandler)(PAirpcapDeviceDescription PAllDevs); +typedef PAirpcapHandle (*AirpcapOpenHandler)(PCHAR DeviceName, PCHAR Ebuf); +typedef VOID (*AirpcapCloseHandler)(PAirpcapHandle AdapterHandle); +typedef BOOL (*AirpcapGetLinkTypeHandler)(PAirpcapHandle AdapterHandle, PAirpcapLinkType PLinkType); +typedef BOOL (*AirpcapSetLinkTypeHandler)(PAirpcapHandle AdapterHandle, AirpcapLinkType NewLinkType); +typedef BOOL (*AirpcapSetKernelBufferHandler)(PAirpcapHandle AdapterHandle, UINT BufferSize); +typedef BOOL (*AirpcapSetFilterHandler)(PAirpcapHandle AdapterHandle, PVOID Instructions, UINT Len); +typedef BOOL (*AirpcapGetMacAddressHandler)(PAirpcapHandle AdapterHandle, PAirpcapMacAddress PMacAddress); +typedef BOOL (*AirpcapSetMinToCopyHandler)(PAirpcapHandle AdapterHandle, UINT MinToCopy); +typedef BOOL (*AirpcapGetReadEventHandler)(PAirpcapHandle AdapterHandle, HANDLE* PReadEvent); +typedef BOOL (*AirpcapReadHandler)(PAirpcapHandle AdapterHandle, PBYTE Buffer, UINT BufSize, PUINT PReceievedBytes); +typedef BOOL (*AirpcapGetStatsHandler)(PAirpcapHandle AdapterHandle, PAirpcapStats PStats); +typedef BOOL (*AirpcapTurnLedOnHandler)(PAirpcapHandle AdapterHandle, UINT LedNumber); +typedef BOOL (*AirpcapTurnLedOffHandler)(PAirpcapHandle AdapterHandle, UINT LedNumber); +typedef BOOL (*AirpcapSetDeviceChannelHandler)(PAirpcapHandle AdapterHandle, UINT Channel); +typedef BOOL (*AirpcapGetDeviceChannelHandler)(PAirpcapHandle AdapterHandle, PUINT PChannel); +typedef BOOL (*AirpcapSetFcsPresenceHandler)(PAirpcapHandle AdapterHandle, BOOL IsFcsPresent); +typedef BOOL (*AirpcapGetFcsPresenceHandler)(PAirpcapHandle AdapterHandle, PBOOL PIsFcsPresent); +typedef BOOL (*AirpcapSetFcsValidationHandler)(PAirpcapHandle AdapterHandle, AirpcapValidationType ValidationType); +typedef BOOL (*AirpcapGetFcsValidationHandler)(PAirpcapHandle AdapterHandle, PAirpcapValidationType PValidationType); +typedef BOOL (*AirpcapSetDeviceKeysHandler)(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection); +typedef BOOL (*AirpcapGetDeviceKeysHandler)(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, PUINT PKeysCollectionSize); +typedef BOOL (*AirpcapSetDriverKeysHandler)(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection); +typedef BOOL (*AirpcapGetDriverKeysHandler)(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, PUINT PKeysCollectionSize); +typedef BOOL (*AirpcapSetDecryptionStateHandler)(PAirpcapHandle AdapterHandle, AirpcapDecryptionState Enable); +typedef BOOL (*AirpcapGetDecryptionStateHandler)(PAirpcapHandle AdapterHandle, PAirpcapDecryptionState PEnable); +typedef BOOL (*AirpcapSetDriverDecryptionStateHandler)(PAirpcapHandle AdapterHandle, AirpcapDecryptionState Enable); +typedef BOOL (*AirpcapGetDriverDecryptionStateHandler)(PAirpcapHandle AdapterHandle, PAirpcapDecryptionState PEnable); +typedef BOOL (*AirpcapStoreCurConfigAsAdapterDefaultHandler)(PAirpcapHandle AdapterHandle); +typedef VOID (*AirpcapGetVersionHandler)(PUINT VersionMajor, PUINT VersionMinor, PUINT VersionRev, PUINT VersionBuild); +typedef BOOL (*AirpcapSetDeviceChannelExHandler)(PAirpcapHandle AdapterHandle, AirpcapChannelInfo ChannelInfo); +typedef BOOL (*AirpcapGetDeviceChannelExHandler)(PAirpcapHandle AdapterHandle, PAirpcapChannelInfo PChannelInfo); +typedef BOOL (*AirpcapGetDeviceSupportedChannelsHandler)(PAirpcapHandle AdapterHandle, AirpcapChannelInfo **ppChannelInfo, PULONG pNumChannelInfo); + +#define FLAG_CAN_BE_LOW 0x00000001 +#define FLAG_CAN_BE_HIGH 0x00000002 +#define FLAG_IS_BG_CHANNEL 0x00000004 +#define FLAG_IS_A_CHANNEL 0x00000008 + +typedef struct _Dot11Channel +{ + UINT Channel; + ULONG Frequency; + ULONG Flags; +} Dot11Channel; + +/* + * The list of interfaces returned by "get_airpcap_interface_list()" is + * a list of these structures. + */ +typedef struct { + char *name; /* e.g. "eth0" */ + char *description; /* from OS, e.g. "Local Area Connection" or NULL */ + GSList *ip_addr; /* containing address values of if_addr_t */ + gboolean loopback; /* TRUE if loopback, FALSE otherwise */ + AirpcapLinkType linkType; /* The link layer type */ + AirpcapChannelInfo channelInfo; /* Channel Information */ + BOOL IsFcsPresent; /* Include 802.11 CRC in frames */ + AirpcapValidationType CrcValidationOn; /* Capture Frames with Wrong CRC */ + AirpcapDecryptionState DecryptionOn; /* TRUE if decryption is on, FALSE otherwise */ + PAirpcapKeysCollection keysCollection; /* WEP Key collection for the adapter */ + UINT keysCollectionSize; /* Size of the key collection */ + gboolean blinking; /* TRUE if is blinkng, FALSE otherwise */ + gboolean led; /* TRUE if on, FALSE if off */ + gboolean saved; /* TRUE if current configuration has been saved, FALSE otherwise */ + gint tag; /* int for the gtk blinking callback */ + Dot11Channel *pSupportedChannels; + ULONG numSupportedChannels; +} airpcap_if_info_t; + +/* + * Struct used to store infos to pass to the preferences manager callbacks + */ +typedef struct { + GList *list; + int current_index; + int number_of_keys; +} keys_cb_data_t; + +/* Airpcap interface list */ +extern GList *airpcap_if_list; + +/* Airpcap current selected interface */ +extern airpcap_if_info_t *airpcap_if_selected; + +/* Airpcap current active interface */ +extern airpcap_if_info_t *airpcap_if_active; + +/* WLAN preferences pointer */ +/*extern module_t *wlan_prefs; - TODO: What is this?? */ + +/* + * Function used to read the Decryption Keys from the preferences and store them + * properly into the airpcap adapter. + */ +BOOL +load_wlan_driver_wep_keys(); + +/* + * Function used to save to the prefereces file the Decryption Keys. + */ +BOOL +save_wlan_wep_keys(airpcap_if_info_t* info_if); + +/* + * This function will tell the airpcap driver the key list to use + * This will be stored into the registry... + */ +gboolean +write_wlan_wep_keys_to_registry(airpcap_if_info_t* info_if, GList* key_list); + +/* Returs TRUE if the WEP key is valid, false otherwise */ +gboolean +wep_key_is_valid(char* key); + +/* + * Callback used to free an instance of airpcap_if_info_t + */ +static void +free_airpcap_if_cb(gpointer data, gpointer user_data _U_); + +/* + * USED FOR DEBUG ONLY... PRINTS AN AirPcap ADAPTER STRUCTURE in a fancy way. + */ +void +airpcap_if_info_print(airpcap_if_info_t* if_info); + +/* + * Used to retrieve the two chars string from interface + */ +gchar* +airpcap_get_if_string_number_from_description(gchar* description); + +/* + * Function used to free the airpcap interface list + */ +void +free_airpcap_interface_list(GList *if_list); + +/* + * Used to retrieve the interface given the name + * (the name is used in AirpcapOpen) + */ +airpcap_if_info_t* get_airpcap_if_from_name(GList* if_list, const gchar* name); + +/* + * Airpcap wrapper, used to store the current settings for the selected adapter + */ +BOOL +airpcap_if_store_cur_config_as_adapter_default(PAirpcapHandle ah); + +/* + * Function used to load the WEP keys for a selected interface + */ +BOOL +airpcap_if_load_keys(PAirpcapHandle ad, airpcap_if_info_t *if_info); + +/* + * Function used to load the WEP keys from the global driver list + */ +BOOL +airpcap_if_load_driver_keys(PAirpcapHandle ad, airpcap_if_info_t *if_info); + +/* + * Function used to save the WEP keys for a selected interface + */ +void +airpcap_if_save_keys(PAirpcapHandle ad, airpcap_if_info_t *if_info); + +/* + * Function used to save the WEP keys for a selected interface + */ +void +airpcap_if_save_driver_keys(PAirpcapHandle ad, airpcap_if_info_t *if_info); + +/* + * Airpcap wrapper, used to get the fcs validation of an airpcap adapter + */ +BOOL +airpcap_if_get_fcs_validation(PAirpcapHandle ah, PAirpcapValidationType val); + +/* + * Airpcap wrapper, used to set the fcs validation of an airpcap adapter + */ +BOOL +airpcap_if_set_fcs_validation(PAirpcapHandle ah, AirpcapValidationType val); + +/* + * Airpcap wrapper, used to get the decryption enabling of an airpcap adapter + */ +BOOL +airpcap_if_get_decryption_state(PAirpcapHandle ah, PAirpcapDecryptionState val); + +/* + * Airpcap wrapper, used to set the decryption enabling of an airpcap adapter + */ +BOOL +airpcap_if_set_decryption_state(PAirpcapHandle ah, AirpcapDecryptionState val); + +/* + * Airpcap wrapper, used to get the fcs presence of an airpcap adapter + */ +BOOL +airpcap_if_get_fcs_presence(PAirpcapHandle ah, PBOOL ch); + +/* + * Airpcap wrapper, used to set the fcs presence of an airpcap adapter + */ +BOOL +airpcap_if_set_fcs_presence(PAirpcapHandle ah, BOOL ch); + +/* + * Airpcap wrapper, used to get the link type of an airpcap adapter + */ +BOOL +airpcap_if_get_link_type(PAirpcapHandle ah, PAirpcapLinkType lt); + +/* + * Airpcap wrapper, used to set the link type of an airpcap adapter + */ +BOOL +airpcap_if_set_link_type(PAirpcapHandle ah, AirpcapLinkType lt); + +/* + * Airpcap wrapper, used to get the channel of an airpcap adapter + */ +BOOL +airpcap_if_get_device_channel(PAirpcapHandle ah, PUINT ch); + +/* + * Airpcap wrapper, get the channels supported by the adapter + */ +BOOL +airpcap_if_get_device_supported_channels(PAirpcapHandle ah, AirpcapChannelInfo **cInfo, PULONG nInfo); + +/* + * Airpcap wrapper, get supported channels formatted into an array + */ +Dot11Channel* +airpcap_if_get_device_supported_channels_array(PAirpcapHandle ah, PULONG pNumSupportedChannels); + +/* + * Airpcap wrapper, used to set the channel of an airpcap adapter + */ +BOOL +airpcap_if_set_device_channel(PAirpcapHandle ah, UINT ch); + +/* + * Airpcap wrapper, used to get the frequency of an airpcap adapter + */ +BOOL +airpcap_if_get_device_channel_ex(PAirpcapHandle ah, PAirpcapChannelInfo pChannelInfo); + +/* + * Airpcap wrapper, used to set the frequency of an airpcap adapter + */ +BOOL +airpcap_if_set_device_channel_ex(PAirpcapHandle ah, AirpcapChannelInfo ChannelInfo); + +/* + * Airpcap wrapper, used to open an airpcap adapter + */ +PAirpcapHandle airpcap_if_open(PCHAR name, PCHAR err); + +/* + * Airpcap wrapper, used to close an airpcap adapter + */ +VOID airpcap_if_close(PAirpcapHandle handle); + +/* + * Retrieve the state of the Airpcap DLL + */ +int +airpcap_get_dll_state(); + +/* + * Airpcap wrapper, used to turn on the led of an airpcap adapter + */ +BOOL airpcap_if_turn_led_on(PAirpcapHandle AdapterHandle, UINT LedNumber); + +/* + * Airpcap wrapper, used to turn off the led of an airpcap adapter + */ +BOOL airpcap_if_turn_led_off(PAirpcapHandle AdapterHandle, UINT LedNumber); + +/* + * This function will create a new airpcap_if_info_t using a name and a description + */ +airpcap_if_info_t* airpcap_if_info_new(char *name, char *description); + +/* + * This function will create a new fake drivers' interface, to load global keys... + */ +airpcap_if_info_t* airpcap_driver_fake_if_info_new(); + +/* + * Used to dinamically load the airpcap library in order link it only when + * it's present on the system. + */ +int load_airpcap(void); + +/* + * This function will use the airpcap.dll to find all the airpcap devices. + * Will return null if no device is found. + */ +GList* +get_airpcap_interface_list(int *err, char **err_str); + +/* + * Returns the ASCII string of a key given the key bites + */ +gchar* +airpcap_get_key_string(AirpcapKey key); + +/* + * Load the configuration for the specified interface + */ +void +airpcap_load_selected_if_configuration(airpcap_if_info_t* if_info); + +/* + * Save the configuration for the specified interface + */ +void +airpcap_save_selected_if_configuration(airpcap_if_info_t* if_info); + +/* + * Used to retrieve the two chars string from interface description + */ +gchar* +airpcap_get_if_string_number(airpcap_if_info_t* if_info); + +/* + * Returns the default airpcap interface of a list, NULL if list is empty + */ +airpcap_if_info_t* +airpcap_get_default_if(GList* airpcap_if_list); + +/* + * Airpcap wrapper, used to save the settings for the selected_if + */ +BOOL +airpcap_if_set_device_keys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection); + +/* + * Airpcap wrapper, used to save the settings for the selected_if + */ +BOOL +airpcap_if_get_device_keys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, PUINT PKeysCollectionSize); + +/* + * Airpcap wrapper, used to save the settings for the selected_if + */ +BOOL +airpcap_if_set_driver_keys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection); + +/* + * Airpcap wrapper, used to save the settings for the selected_if + */ +BOOL +airpcap_if_get_driver_keys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, PUINT PKeysCollectionSize); + +/* + * Airpcap wrapper, used to get the decryption enabling of an airpcap driver + */ +BOOL +airpcap_if_get_driver_decryption_state(PAirpcapHandle ah, PAirpcapDecryptionState PEnable); +/* + * Airpcap wrapper, used to set the decryption enabling of an airpcap driver + */ +BOOL +airpcap_if_set_driver_decryption_state(PAirpcapHandle ah, AirpcapDecryptionState Enable); + +/* + * Save the configuration for the specified interface + */ +void +airpcap_save_driver_if_configuration(airpcap_if_info_t* fake_if_info); + +/* + * Free an instance of airpcap_if_info_t + */ +void +airpcap_if_info_free(airpcap_if_info_t *if_info); + +/* + * This function will tell the airpcap driver the key list to use + * This will be stored into the registry... + */ +BOOL +write_wlan_driver_wep_keys_to_registry(GList* key_list); + +/* + * Clear keys and decryption status for the specified interface + */ +void +airpcap_if_clear_decryption_settings(airpcap_if_info_t* info_if); + +/* + * Function used to save to the preference file the Decryption Keys. + */ +int +save_wlan_driver_wep_keys(); + +/* + * Function used to save to the preference file the Decryption Keys. + */ +int +save_wlan_wireshark_wep_keys(GList* key_ls); + +/* + * DECRYPTION KEYS FUNCTIONS + */ +/* + * This function is used for DEBUG PURPOSES ONLY!!! + */ +void +print_key_list(GList* key_list); + +/* + * Retrieves a GList of decryption_key_t structures containing infos about the + * keys for the given adapter... returns NULL if no keys are found. + */ +GList* +get_airpcap_device_keys(airpcap_if_info_t* if_info); + +/* + * Retrieves a GList of decryption_key_t structures containing infos about the + * keys for the global AirPcap driver... returns NULL if no keys are found. + */ +GList* +get_airpcap_driver_keys(); + +/* + * Returns the list of the decryption keys specified for wireshark, NULL if + * no key is found + */ +GList* +get_wireshark_keys(); + +/* + * Tests if two collection of keys are equal or not, to be considered equals, they have to + * contain the same keys in the SAME ORDER! (If both lists are NULL, which means empty will + * return TRUE) + */ +gboolean +key_lists_are_equal(GList* list1, GList* list2); + +/* + * Merges two lists of keys. If a key is found multiple times, it will just appear once! + */ +GList* +merge_key_list(GList* list1, GList* list2); + +/* + * If the given key is contained in the list, returns TRUE. + * Returns FALSE otherwise. + */ +gboolean +key_is_in_list(decryption_key_t *dk,GList *list); + +/* + * Returns TRUE if keys are equals, FALSE otherwise + */ +gboolean +keys_are_equals(decryption_key_t *k1,decryption_key_t *k2); + +/* + * Use this function to free a key list. + */ +void +free_key_list(GList *list); + +/* + * Returns TRUE if the Wireshark decryption is active, FALSE otherwise + */ +gboolean +wireshark_decryption_on(); + +/* + * Returns TRUE if the AirPcap decryption for the current adapter is active, FALSE otherwise + */ +gboolean +airpcap_decryption_on(); + +/* + * Enables decryption for Wireshark if on_off is TRUE, disables it otherwise. + */ +void +set_wireshark_decryption(gboolean on_off); + +/* + * Enables decryption for all the adapters if on_off is TRUE, disables it otherwise. + */ +gboolean +set_airpcap_decryption(gboolean on_off); + +/* + * Adds compiled version string to str + */ +void +get_compiled_airpcap_version(GString *str); + +void +get_runtime_airpcap_version(GString *str); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/alert_box.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/alert_box.h new file mode 100644 index 00000000..62ee1efb --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/alert_box.h @@ -0,0 +1,70 @@ +/* alert_box.h + * Routines to put up various "standard" alert boxes used in multiple + * places + * + * $Id: alert_box.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ALERT_BOX_H__ +#define __ALERT_BOX_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * Alert box for general errors. + */ +extern void failure_alert_box(const char *msg_format, va_list ap); + +/* + * Alert box for a failed attempt to open or create a file. + * "err" is assumed to be a UNIX-style errno; "for_writing" is TRUE if + * the file is being opened for writing and FALSE if it's being opened + * for reading. + */ +extern void open_failure_alert_box(const char *filename, int err, + gboolean for_writing); + +/* + * Alert box for a failed attempt to read a file. + * "err" is assumed to be a UNIX-style errno. + */ +extern void read_failure_alert_box(const char *filename, int err); + +/* + * Alert box for a failed attempt to write to a file. + * "err" is assumed to be a UNIX-style errno. + */ +extern void write_failure_alert_box(const char *filename, int err); + +/* + * Alert box for an invalid display filter expression. + * Assumes "dfilter_error_msg" has been set by "dfilter_compile()" to the + * error message for the filter. + */ +extern void bad_dfilter_alert_box(const char *dftext); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __ALERT_BOX_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-pcap-util-int.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-pcap-util-int.h new file mode 100644 index 00000000..697f2ede --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-pcap-util-int.h @@ -0,0 +1,56 @@ +/* capture-pcap-util-int.h + * Definitions of routines internal to the libpcap/WinPcap utilities + * + * $Id: capture-pcap-util-int.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PCAP_UTIL_INT_H__ +#define __PCAP_UTIL_INT_H__ + +#ifdef HAVE_LIBPCAP +#ifdef HAVE_PCAP_REMOTE +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#endif + +extern if_info_t *if_info_new(char *name, char *description); +extern void if_info_add_address(if_info_t *if_info, struct sockaddr *addr); +#ifdef HAVE_PCAP_FINDALLDEVS +#ifdef HAVE_PCAP_REMOTE +extern GList *get_interface_list_findalldevs_ex(const char *source, + struct pcap_rmtauth *auth, int *err, char **err_str); +#else +extern GList *get_interface_list_findalldevs(int *err, char **err_str); +#endif +#endif + +/* + * Get an error message string for a CANT_GET_INTERFACE_LIST error from + * "get_interface_list()". This is used to let the error message string + * be platform-dependent. + */ +extern gchar *cant_get_if_list_error_message(const char *err_str); + +#endif /* HAVE_LIBPCAP */ + +#endif /* __PCAP_UTIL_INT_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-pcap-util.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-pcap-util.h new file mode 100644 index 00000000..fd480733 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-pcap-util.h @@ -0,0 +1,131 @@ +/* capture-pcap-util.h + * Utility definitions for packet capture + * + * $Id: capture-pcap-util.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PCAP_UTIL_H__ +#define __PCAP_UTIL_H__ + +#ifdef HAVE_LIBPCAP + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include + +#include + +/* + * XXX - this is also the traditional default snapshot size in + * tcpdump - but, if IPv6 is enabled, it defaults to 96, to get an + * IPv6 header + TCP + 22 extra bytes. + * + * Some libpcap versions for particular capture devices might happen + * to impose a minimum, but it's not always 68. + */ +#define MIN_PACKET_SIZE 68 /* minimum amount of packet data we can read */ + +/* + * The list of interfaces returned by "get_interface_list()" is + * a list of these structures. + */ +typedef struct { + char *name; /* e.g. "eth0" */ + char *description; /* from OS, e.g. "Local Area Connection" or NULL */ + GSList *ip_addr; /* containing address values of if_addr_t */ + gboolean loopback; /* TRUE if loopback, FALSE otherwise */ +} if_info_t; + +/* + * An address in the "ip_addr" list. + */ +typedef struct { + address_type type; /* AT_IPv4 or AT_IPv6 */ + union { + guint32 ip4_addr; /* 4 byte IP V4 address, or */ + guint8 ip6_addr[16];/* 16 byte IP V6 address */ + } ip_addr; +} if_addr_t; + +GList *get_interface_list(int *err, char **err_str); +#ifdef HAVE_PCAP_REMOTE +GList *get_remote_interface_list(const char *hostname, const char *port, + int auth_type, const char *username, + const char *passwd, int *err, char **err_str); +#endif + +/* Error values from "get_interface_list()/capture_interface_list()". */ +#define CANT_GET_INTERFACE_LIST 1 /* error getting list */ +#define NO_INTERFACES_FOUND 2 /* list is empty */ +#define CANT_RUN_DUMPCAP 3 /* problem running dumpcap */ + +void free_interface_list(GList *if_list); + +/* + * The list of data link types returned by "get_pcap_linktype_list()" is + * a list of these structures. + */ +typedef struct { + int dlt; /* e.g. DLT_EN10MB (which is 1) */ + char *name; /* e.g. "EN10MB" or "DLT 1" */ + char *description; /* descriptive name from wiretap e.g. "Ethernet", NULL if unknown */ +} data_link_info_t; + +GList *get_pcap_linktype_list(const char *devname, char **err_str); +void free_pcap_linktype_list(GList *linktype_list); + +/* get/set the link type of an interface */ +/* (only used in capture_loop.c / capture-pcap-util.c) */ +int get_pcap_linktype(pcap_t *pch, const char *devname); +const char *set_pcap_linktype(pcap_t *pch, char *devname, int dlt); + + +#ifdef HAVE_PCAP_DATALINK_VAL_TO_NAME +const char *linktype_val_to_name(int dlt); +#endif +#ifdef HAVE_PCAP_DATALINK_NAME_TO_VAL +int linktype_name_to_val(const char *linktype); +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* HAVE_LIBPCAP */ + +/* + * Append to a GString an indication of the version of libpcap/WinPcap + * with which we were compiled, if we were, or an indication that we + * weren't compiled with libpcap/WinPcap, if we weren't. + */ +extern void get_compiled_pcap_version(GString *str); + +/* + * Append to a GString an indication of the version of libpcap/WinPcap + * with which we're running, or an indication that we're not running + * with libpcap/WinPcap, if we were compiled with libpcap/WinPcap, + * or nothing, if we weren't compiled with libpcap/WinPcap. + */ +extern void get_runtime_pcap_version(GString *str); + +#endif /* __PCAP_UTIL_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-wpcap.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-wpcap.h new file mode 100644 index 00000000..94e51244 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-wpcap.h @@ -0,0 +1,34 @@ +/* capture-wpcap.h + * + * $Id: capture-wpcap.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2001 Gerald Combs + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef CAPTURE_WPCAP_H +#define CAPTURE_WPCAP_H + +extern gboolean has_wpcap; + + +void +load_wpcap(void); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture.h new file mode 100644 index 00000000..86a0ef1e --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture.h @@ -0,0 +1,118 @@ +/* capture.h + * Definitions for packet capture windows + * + * $Id: capture.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* This file should only be included if libpcap is present */ + +#ifndef __CAPTURE_H__ +#define __CAPTURE_H__ + +/** @file + * Capture related things. + */ + +#include "capture_opts.h" + +/** + * Start a capture session. + * + * @param capture_opts the numerous capture options + * @return TRUE if the capture starts successfully, FALSE otherwise. + */ +extern gboolean capture_start(capture_options *capture_opts); + +/** Stop a capture session (usually from a menu item). */ +extern void capture_stop(capture_options *capture_opts); + +/** Restart the current captured packets and start again. */ +extern void capture_restart(capture_options *capture_opts); + +/** Terminate the capture child cleanly when exiting. */ +extern void capture_kill_child(capture_options *capture_opts); + +/** + * Capture child told us we have a new (or the first) capture file. + */ +extern gboolean capture_input_new_file(capture_options *capture_opts, gchar *new_file); + +/** + * Capture child told us we have new packets to read. + */ +extern void capture_input_new_packets(capture_options *capture_opts, int to_read); + +/** + * Capture child told us how many dropped packets it counted. + */ +extern void capture_input_drops(capture_options *capture_opts, int dropped); + +/** + * Capture child told us that an error has occurred while starting the capture. + */ +extern void capture_input_error_message(capture_options *capture_opts, char *error_message, char *secondary_error_msg); + +/** + * Capture child told us that an error has occurred while parsing a + * capture filter when starting/running the capture. + */ +extern void capture_input_cfilter_error_message(capture_options *capture_opts, char *error_message); + +/** + * Capture child closed its side of the pipe, do the required cleanup. + */ +extern void capture_input_closed(capture_options *capture_opts); + +#ifdef HAVE_LIBPCAP +/** + * Fetch the interface list from a child process. + */ +extern GList *capture_interface_list(int *err, char **err_str); + +/** + * Fetch the linktype list for the specified interface from a child process. + */ +extern GList *capture_pcap_linktype_list(const char *devname, char **err_str); + + +struct if_stat_cache_s; +typedef struct if_stat_cache_s if_stat_cache_t; + +/** + * Start gathering capture statistics for the interfaces specified. + * @param A GList of if_info_t items + * @return A pointer to the statistics state data. + */ +extern if_stat_cache_t * capture_stat_start(GList *if_list); + +/** + * Fetch capture statistics, similar to pcap_stats(). + */ +struct pcap_stat; /* Stub in case we don't or haven't yet included pcap.h */ +extern gboolean capture_stats(if_stat_cache_t *sc, char *ifname, struct pcap_stat *ps); + +/** + * Stop gathering capture statistics. + */ +void capture_stat_stop(if_stat_cache_t *sc); +#endif /* HAVE_LIBPCAP */ + +#endif /* capture.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_errs.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_errs.h new file mode 100644 index 00000000..be631336 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_errs.h @@ -0,0 +1,34 @@ +/* capture_errs.h + * Declarations of routines to return error and warning messages for + * packet capture + * + * $Id: capture_errs.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_LIBPCAP + +#ifdef _WIN32 +/* error message, if WinPcap couldn't be loaded */ +/* will use g_strdup, don't forget to g_free the returned string! */ +extern char *cant_load_winpcap_err(const char *app_name); +#endif /* _WIN32 */ + +#endif /* HAVE_LIBPCAP */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_info.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_info.h new file mode 100644 index 00000000..8d83d0f7 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_info.h @@ -0,0 +1,76 @@ +/* capture_info.h + * capture info functions + * + * $Id: capture_info.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +/** @file + * + * capture info functions + * + */ + +#ifndef __CAPTURE_INFO_H__ +#define __CAPTURE_INFO_H__ + + +/* open the info - init values (wtap, counts), create dialog */ +extern void capture_info_open(const char *iface); + +/* new file arrived - (eventually close old wtap), open wtap */ +extern gboolean capture_info_new_file(const char *new_filename); + +/* new packets arrived - read from wtap, count */ +extern void capture_info_new_packets(int to_read); + +/* close the info - close wtap, destroy dialog */ +extern void capture_info_close(void); + + + +/** Current Capture info. */ +typedef struct { + /* handle */ + gpointer ui; /**< user interface handle */ + + /* capture info */ + packet_counts *counts; /**< protocol specific counters */ + time_t running_time; /**< running time since last update */ + gint new_packets; /**< packets since last update */ +} capture_info; + + +/** Create the capture info dialog */ +extern void capture_info_ui_create( +capture_info *cinfo, +const gchar *iface); + +/** Update the capture info counters in the dialog */ +extern void capture_info_ui_update( +capture_info *cinfo); + +/** Destroy the capture info dialog again */ +extern void capture_info_ui_destroy( +capture_info *cinfo); + + +#endif /* capture_info.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_opts.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_opts.h new file mode 100644 index 00000000..e813688e --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_opts.h @@ -0,0 +1,194 @@ +/* capture_opts.h + * Capture options (all parameters needed to do the actual capture) + * + * $Id: capture_opts.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +/** @file + * + * Capture options (all parameters needed to do the actual capture) + * + */ + +#ifndef __CAPTURE_OPTS_H__ +#define __CAPTURE_OPTS_H__ + + +/* Current state of capture engine. XXX - differentiate states */ +typedef enum { + CAPTURE_STOPPED, /**< stopped */ + CAPTURE_PREPARING, /**< preparing, but still no response from capture child */ + CAPTURE_RUNNING /**< capture child signalled ok, capture is running now */ +} capture_state; + +#ifdef HAVE_PCAP_REMOTE +/* Type of capture source */ +typedef enum { + CAPTURE_IFLOCAL, /**< Local network interface */ + CAPTURE_IFREMOTE /**< Remote network interface */ +} capture_source; + +/* Type of RPCAPD Authentication */ +typedef enum { + CAPTURE_AUTH_NULL, /**< No authentication */ + CAPTURE_AUTH_PWD /**< User/password authentication */ +} capture_auth; + +#ifdef HAVE_PCAP_SETSAMPLING +/** + * Method of packet sampling (dropping some captured packets), + * may require additional integer parameter, marked here as N + */ +typedef enum { + CAPTURE_SAMP_NONE, /**< No sampling - capture all packets */ + CAPTURE_SAMP_BY_COUNT, /**< Counter-based sampling - + capture 1 packet from every N */ + CAPTURE_SAMP_BY_TIMER /**< Timer-based sampling - + capture no more than 1 packet + in N milliseconds */ +} capture_sampling; +#endif +#endif + +/** Capture options coming from user interface */ +typedef struct capture_options_tag { + /* general */ + void *cf; /**< handle to cfile (note: untyped handle) */ + gboolean has_cfilter; /**< TRUE if capture filter specified on command line */ + gchar *cfilter; /**< Capture filter string */ + gchar *iface; /**< the network interface to capture from */ + gchar *iface_descr; /**< A human readable description of iface. + *< NOTE: capture_opts.c is not able to + *< set this field because doing so + *< requires too many dependencies. + *< Readers of this field should use + *< get_iface_description() from + *< "capture_ui_utils.h" to access it. */ +#ifdef HAVE_PCAP_REMOTE + capture_source src_type; /**< Capturing on remote interface */ + gchar *remote_host; /**< Host name or network address + *< for remote capturing */ + gchar *remote_port; /**< TCP port of remote RPCAP server */ + + capture_auth auth_type; + gchar *auth_username; + gchar *auth_password; /**< Remote authentication parameters */ + + gboolean datatx_udp; /**< Whether to use UDP for data transfer */ + gboolean nocap_rpcap; /**< Whether to capture RPCAP own traffic */ + gboolean nocap_local; /**< TODO: Whether to capture local traffic */ +#ifdef HAVE_PCAP_SETSAMPLING + capture_sampling sampling_method; /**< PCAP packet sampling method */ + int sampling_param; /**< PCAP packet sampling parameter */ +#endif +#endif +#ifdef _WIN32 + int buffer_size; /**< the capture buffer size (MB) */ +#endif + gboolean has_snaplen; /**< TRUE if maximum capture packet length + is specified */ + int snaplen; /**< Maximum captured packet length */ + gboolean promisc_mode; /**< Capture in promiscuous mode */ + int linktype; /**< Data link type to use, or -1 for + "use default" */ + gboolean saving_to_file; /**< TRUE if capture is writing to a file */ + gchar *save_file; /**< the capture file name */ + + /* GUI related */ + gboolean real_time_mode; /**< Update list of packets in real time */ + gboolean show_info; /**< show the info dialog */ + gboolean quit_after_cap; /**< Makes a "capture only mode". Implies -k */ + gboolean restart; /**< restart after closing is done */ + + /* multiple files (and ringbuffer) */ + gboolean multi_files_on; /**< TRUE if ring buffer in use */ + + gboolean has_file_duration; /**< TRUE if ring duration specified */ + gint32 file_duration; /**< Switch file after n seconds */ + gboolean has_ring_num_files; /**< TRUE if ring num_files specified */ + guint32 ring_num_files; /**< Number of multiple buffer files */ + + /* autostop conditions */ + gboolean has_autostop_files; /**< TRUE if maximum number of capture files + are specified */ + gint32 autostop_files; /**< Maximum number of capture files */ + + gboolean has_autostop_packets; /**< TRUE if maximum packet count is + specified */ + int autostop_packets; /**< Maximum packet count */ + gboolean has_autostop_filesize; /**< TRUE if maximum capture file size + is specified */ + gint32 autostop_filesize; /**< Maximum capture file size */ + gboolean has_autostop_duration; /**< TRUE if maximum capture duration + is specified */ + gint32 autostop_duration; /**< Maximum capture duration */ + + /* internally used (don't touch from outside) */ + int fork_child; /**< If not -1, in parent, process ID of child */ +#ifdef _WIN32 + int signal_pipe_write_fd; /**< the pipe to signal the child */ +#endif + capture_state state; /**< current state of the capture engine */ + gboolean output_to_pipe; /**< save_file is a pipe (named or stdout) */ +#ifndef _WIN32 + uid_t owner; /**< owner of the cfile */ + gid_t group; /**< group of the cfile */ +#endif +} capture_options; + +/* initialize the capture_options with some reasonable values */ +extern void +capture_opts_init(capture_options *capture_opts, void *cfile); + +/* set a command line option value */ +extern int +capture_opts_add_opt(capture_options *capture_opts, int opt, const char *optarg, gboolean *start_capture); + +/* log content of capture_opts */ +extern void +capture_opts_log(const char *log_domain, GLogLevelFlags log_level, capture_options *capture_opts); + +/* list link layer types */ +extern int +capture_opts_list_link_layer_types(capture_options *capture_opts, gboolean machine_readable); + +/* list interfaces */ +extern int +capture_opts_list_interfaces(gboolean machine_readable); + +/* print interface statistics */ +extern int +capture_opts_print_statistics(gboolean machine_readable); + +/* trim the snaplen entry */ +extern void +capture_opts_trim_snaplen(capture_options *capture_opts, int snaplen_min); + +/* trim the ring_num_files entry */ +extern void +capture_opts_trim_ring_num_files(capture_options *capture_opts); + +/* trim the interface entry */ +extern gboolean +capture_opts_trim_iface(capture_options *capture_opts, const char *capture_device); + +#endif /* capture_opts.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_stop_conditions.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_stop_conditions.h new file mode 100644 index 00000000..1e6e1f32 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_stop_conditions.h @@ -0,0 +1,29 @@ +/* capture_stop_conditions.h + * Implementation for 'stop condition handler'. + * + * $Id: capture_stop_conditions.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +void init_capture_stop_conditions(void); +void cleanup_capture_stop_conditions(void); + +extern const char* CND_CLASS_TIMEOUT; +extern const char* CND_CLASS_CAPTURESIZE; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_sync.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_sync.h new file mode 100644 index 00000000..6f2f72fb --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_sync.h @@ -0,0 +1,87 @@ +/* capture_sync.h + * Synchronisation between Wireshark capture parent and child instances + * + * $Id: capture_sync.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +/** @file + * + * Sync mode capture (internal interface). + * + * Will start a new Wireshark child instance which will do the actual capture + * work. + */ + +#ifndef __CAPTURE_SYNC_H__ +#define __CAPTURE_SYNC_H__ + + +/** + * Start a new capture session. + * Create a capture child which is doing the real capture work. + * The various capture_input_... functions will be called, if something had + * happened. + * + * Most of the parameters are passed through the global capture_opts. + * + * @param capture_opts the options + * @return TRUE if a capture could be started, FALSE if not + */ +extern gboolean +sync_pipe_start(capture_options *capture_opts); + +/** User wants to stop capturing, gracefully close the capture child */ +extern void +sync_pipe_stop(capture_options *capture_opts); + +/** User wants to stop the program, just kill the child as soon as possible */ +extern void +sync_pipe_kill(int fork_child); + +/** Has the parent signalled the child to stop? */ +#define SIGNAL_PIPE_CTRL_ID_NONE "none" +#ifdef _WIN32 +#define SIGNAL_PIPE_FORMAT "\\\\.\\pipe\\wireshark.%s.signal" +#endif + +/** Get an interface list using dumpcap */ +extern int +sync_interface_list_open(gchar **msg); + +/** Get a linktype list using dumpcap */ +extern int +sync_linktype_list_open(const gchar *ifname, gchar **msg); + +/** Start getting interface statistics using dumpcap. */ +extern int +sync_interface_stats_open(int *read_fd, int *fork_child, gchar **msg); + +/** Stop gathering statistics. */ +extern int +sync_interface_stats_close(int *read_fd, int *fork_child, gchar **msg); + +/** Read a line from a pipe, similar to fgets. Non-blocking. */ +extern int +sync_pipe_gets_nonblock(int pipe, char *bytes, int max); + + +#endif /* capture_sync.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_ui_utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_ui_utils.h new file mode 100644 index 00000000..5da23b2a --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_ui_utils.h @@ -0,0 +1,89 @@ +/* capture_ui_utils.c + * Declarations of utilities for capture user interfaces + * + * $Id: capture_ui_utils.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __CAPTURE_UI_UTILS_H__ +#define __CAPTURE_UI_UTILS_H__ + +#include "capture_opts.h" + +/** @file + * GList of available capture interfaces. + */ + +/** Return as descriptive a name for an interface as we can get. + * If the user has specified a comment, use that. Otherwise, + * if get_interface_list() supplies a description, use that, + * otherwise use the interface name. + * + * @param if_name The name of the interface. + * + * @return The descriptive name (must be g_free'd later) + */ +char *get_interface_descriptive_name(const char *if_name); + +/** Build the GList of available capture interfaces. + * + * @param if_list An interface list from get_interface_list(). + * @param do_hide Hide the "hidden" interfaces. + * + * @return A list of if_info_t structs (use free_capture_combo_list() later). + */ +GList *build_capture_combo_list(GList *if_list, gboolean do_hide); + +/** Free the GList from build_capture_combo_list(). + * + * @param combo_list the interface list from build_capture_combo_list() + */ +void free_capture_combo_list(GList *combo_list); + + +/** Given text that contains an interface name possibly prefixed by an + * interface description, extract the interface name. + * + * @param if_text A string containing the interface description + name. + * This is usually the data from one of the list elements returned by + * build_capture_combo_list(). + * + * @return The raw interface name, without description (must NOT be g_free'd later) + */ +const char *get_if_name(const char *if_text); + +/** Convert plain interface name to the displayed name in the combo box. + * + * @param if_list The list of interfaces returned by build_capture_combo_list() + * @param if_name The name of the interface. + * + * @return The descriptive name (must be g_free'd later) + */ +char *build_capture_combo_name(GList *if_list, gchar *if_name); + +/** Return the interface description (after setting it if not already set) + * + * @param capture_opts The capture_options structure that contains the used interface + * + * @return A pointer to capture_ops->iface_descr + */ +const char *get_iface_description(capture_options *capture_opts); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_wpcap_packet.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_wpcap_packet.h new file mode 100644 index 00000000..38d1cd9d --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_wpcap_packet.h @@ -0,0 +1,47 @@ +/* capture_wpcap_packet.h + * + * $Id: capture_wpcap_packet.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2001 Gerald Combs + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef CAPTURE_WPCAP_PACKET_H +#define CAPTURE_WPCAP_PACKET_H + + +extern void wpcap_packet_load(void); + +/* get the packet.dll version info */ +extern char *wpcap_packet_get_version(void); + +/* open the interface */ +extern void * wpcap_packet_open(char *if_name); + +/* close the interface */ +extern void wpcap_packet_close(void * adapter); + +extern int wpcap_packet_request(void *a, ULONG Oid, int set, char *value, unsigned int *length); + +extern int wpcap_packet_request_uint(void *a, ULONG Oid, UINT *value); + +extern int wpcap_packet_request_ulong(void *a, ULONG Oid, ULONG *value); + + +#endif /* CAPTURE_WPCAP_PACKET_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/cfile.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/cfile.h new file mode 100644 index 00000000..0b388d5d --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/cfile.h @@ -0,0 +1,91 @@ +/* cfile.h + * capture_file definition & GUI-independent manipulation + * + * $Id: cfile.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __CFILE_H__ +#define __CFILE_H__ + +/* Current state of file. */ +typedef enum { + FILE_CLOSED, /* No file open */ + FILE_READ_IN_PROGRESS, /* Reading a file we've opened */ + FILE_READ_ABORTED, /* Read aborted by user */ + FILE_READ_DONE /* Read completed */ +} file_state; + +/* Character set for text search. */ +typedef enum { + SCS_ASCII_AND_UNICODE, + SCS_ASCII, + SCS_UNICODE + /* add EBCDIC when it's implemented */ +} search_charset_t; + +typedef struct _capture_file { + file_state state; /* Current state of capture file */ + gchar *filename; /* Name of capture file */ + gboolean is_tempfile; /* Is capture file a temporary file? */ + gboolean user_saved;/* If capture file is temporary, has it been saved by user yet? */ + gint64 f_datalen; /* Size of capture file data (uncompressed) */ + guint16 cd_t; /* File type of capture file */ + int lnk_t; /* Link-layer type with which to save capture */ + guint32 vers; /* Version. For tcpdump minor is appended to major */ + int count; /* Total number of frames */ + int displayed_count; /* Number of displayed frames */ + int marked_count; /* Number of marked frames */ + gboolean drops_known; /* TRUE if we know how many packets were dropped */ + guint32 drops; /* Dropped packets */ + nstime_t elapsed_time;/* Elapsed time */ + gboolean has_snap; /* TRUE if maximum capture packet length is known */ + int snap; /* Maximum captured packet length */ + wtap *wth; /* Wiretap session */ + dfilter_t *rfcode; /* Compiled read (display) filter program */ + gchar *dfilter; /* Display filter string */ + /* search */ + gchar *sfilter; /* Search filter string */ + gboolean sbackward; /* TRUE if search is backward, FALSE if forward */ + gboolean hex; /* TRUE is raw data search is being performed */ + gboolean string; /* TRUE is text search is being performed */ + guint32 search_pos; /* Position of last character found in search */ + search_charset_t scs_type; /* Character set for text search */ + gboolean case_type; /* TRUE if case-insensitive text search */ + gboolean decode_data; /* TRUE if searching protocol tree text */ + gboolean summary_data; /* TRUE if searching Info column text */ + /* packet data */ + union wtap_pseudo_header pseudo_header; /* Packet pseudo_header */ + guint8 pd[WTAP_MAX_PACKET_SIZE]; /* Packet data */ + GMemChunk *plist_chunk; /* Memory chunk for frame_data structures */ + frame_data *plist; /* Packet list */ + frame_data *plist_end; /* Last packet in list */ + frame_data *first_displayed; /* First frame displayed */ + frame_data *last_displayed; /* Last frame displayed */ + column_info cinfo; /* Column formatting information */ + frame_data *current_frame; /* Frame data for current frame */ + epan_dissect_t *edt; /* Protocol dissection for currently selected packet */ + field_info *finfo_selected; /* Field info for currently selected field */ + struct ph_stats_s* pstats; /* accumulated stats (reset on redisplay in GUI)*/ +} capture_file; + +void init_cap_file(capture_file *); + +#endif /* cfile.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/clopts_common.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/clopts_common.h new file mode 100644 index 00000000..825164bc --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/clopts_common.h @@ -0,0 +1,40 @@ +/* clopts_common.h + * Handle command-line arguments common to Wireshark and TShark + * + * $Id: clopts_common.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PROTO_DUMPOPTS_H__ +#define __PROTO_DUMPOPTS_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +int get_natural_int(const char *string, const char *name); + +int get_positive_int(const char *string, const char *name); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __PROTO_DUMPOPTS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/cmdarg_err.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/cmdarg_err.h new file mode 100644 index 00000000..5bd43cc0 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/cmdarg_err.h @@ -0,0 +1,56 @@ +/* cmdarg_err.h + * Declarations of routines to report command-line errors. + * + * $Id: cmdarg_err.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __CMDARG_ERR_H__ +#define __CMDARG_ERR_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * Report an error in command-line arguments. + */ +#if __GNUC__ >= 2 +extern void cmdarg_err(const char *fmt, ...) + __attribute__((format (printf, 1, 2))); +#else +extern void cmdarg_err(const char *fmt, ...); +#endif + +/* + * Report additional information for an error in command-line arguments. + */ +#if __GNUC__ >= 2 +extern void cmdarg_err_cont(const char *fmt, ...) + __attribute__((format (printf, 1, 2))); +#else +extern void cmdarg_err_cont(const char *fmt, ...); +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __CMDARG_ERR_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/color.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/color.h new file mode 100644 index 00000000..a1c09b2a --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/color.h @@ -0,0 +1,55 @@ +/* color.h + * Definitions for "toolkit-independent" colors + * + * $Id: color.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __COLOR_H__ +#define __COLOR_H__ + +/* + * Data structure holding RGB value for a color. + * + * XXX - yes, I know, there's a "pixel" value in there as well; for + * now, it's intended to look just like a GdkColor but not to require + * that any GTK+ header files be included in order to use it. + * The way we handle colors needs to be cleaned up somewhat, in order + * to keep toolkit-specific stuff separate from toolkit-independent stuff. + */ +typedef struct { + guint32 pixel; + guint16 red; + guint16 green; + guint16 blue; +} color_t; + +/** Initialize a color with R, G, and B values, including any toolkit-dependent + ** work that needs to be done. + * + * @param color the color_t to be filled + * @param red the red value for the color + * @param green the green value for the color + * @param blue the blue value for the color + * @return TRUE if it succeeds, FALSE if it fails + */ +gboolean initialize_color(color_t *color, guint16 red, guint16 green, guint16 blue); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/color_filters.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/color_filters.h new file mode 100644 index 00000000..878ce97f --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/color_filters.h @@ -0,0 +1,196 @@ +/* color_filters.h + * Definitions for color filters + * + * $Id: color_filters.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef __COLOR_FILTERS_H__ +#define __COLOR_FILTERS_H__ + +#define TEMP_COLOR_PREFIX "___tmp_color_filter___" +/** @file + * Color filters. + */ + +/* Data for a color filter. */ +typedef struct _color_filter { + gchar *filter_name; /* name of the filter */ + gchar *filter_text; /* text of the filter expression */ + color_t bg_color; /* background color for packets that match */ + color_t fg_color; /* foreground color for packets that match */ + gboolean disabled; /* set if the filter is disabled */ + gboolean selected; /* set if the filter is selected in the color dialog box */ + + /* only used inside of color_filters.c */ + dfilter_t *c_colorfilter; /* compiled filter expression */ + + /* only used outside of color_filters.c (beside init) */ + void *edit_dialog; /* if filter is being edited, dialog + * box for it */ +} color_filter_t; + + +/** Init the color filters (incl. initial read from file). */ +void color_filters_init(void); + +/** Reload the color filters */ +void color_filters_reload(void); + +/** Cleanup remaining color filter zombies */ +void color_filters_cleanup(void); + +/** Color filters currently used? + * + * @return TRUE, if filters are used + */ +gboolean color_filters_used(void); + +/** Are there any temporary coloring filters used? + * + * @return TRUE, if temporary coloring filters are used + */ +gboolean tmp_color_filters_used(void); + +/** En-/disable color filters + * + * @param enable TRUE to enable (default) + */ +void +color_filters_enable(gboolean enable); + +/** Set the filter string of a temporary color filter + * + * @param filt_nr a number 1-10 pointing to a temporary color + * @param filter the new filter-string + * @param disabled whether the filter-rule should be disabled + */ +void +color_filters_set_tmp(guint8 filt_nr, gchar *filter, gboolean disabled); + +/** Reset the temporary color filters + * + */ +void +color_filters_reset_tmp(void); + +/* Prime the epan_dissect_t with all the compiler + * color filters of the current filter list. + * + * @param the epan dissector details + */ +void color_filters_prime_edt(epan_dissect_t *edt); + +/** Colorize a specific packet. + * + * @param row the row in the packet list + * @param edt the dissected packet + * @return the matching color filter or NULL + */ +color_filter_t * +color_filters_colorize_packet(gint row, epan_dissect_t *edt); + + + +/** Clone the currently active filter list. + * + * @param user_data will be returned by each call to to color_filter_add_cb() + */ +void color_filters_clone(gpointer user_data); + +/** Load filters (import) from some other filter file. + * + * @param path the path to the import file + * @param user_data will be returned by each call to to color_filter_add_cb() + * @return TRUE, if read succeeded + */ +gboolean color_filters_import(gchar *path, gpointer user_data); + +/** Read filters from the global filter file (not the users file). + * + * @param user_data will be returned by each call to to color_filter_add_cb() + * @return TRUE, if read succeeded + */ +gboolean color_filters_read_globals(gpointer user_data); + +/** A color filter was added (while importing). + * (color_filters.c calls this for every filter coming in) + * + * @param colorf the new color filter + * @param user_data from caller + */ +void color_filter_add_cb (color_filter_t *colorf, gpointer user_data); + + + +/** Apply a changed filter list. + * + * @param tmp_cfl the temporary color filter list to apply + * @param edit_cfl the edited permanent color filter list to apply + */ +void color_filters_apply(GSList *tmp_cfl, GSList *edit_cfl); + +/** Save filters in users filter file. + * + * @param cfl the filter list to write + * @return TRUE if write succeeded + */ +gboolean color_filters_write(GSList *cfl); + +/** Save filters (export) to some other filter file. + * + * @param path the path to the filter file + * @param cfl the filter list to write + * @param only_selected TRUE if only the selected filters should be saved + * @return TRUE, if write succeeded + */ +gboolean color_filters_export(gchar *path, GSList *cfl, gboolean only_selected); + + + +/** Create a new color filter (g_malloc'ed). + * + * @param name the name of the filter + * @param filter_string the filter string + * @param bg_color background color + * @param fg_color foreground color + * @return the new color filter + */ +color_filter_t *color_filter_new( + const gchar *name, const gchar *filter_string, + color_t *bg_color, color_t *fg_color, gboolean disabled); + +/** Delete a single color filter (g_free'ed). + * + * @param colorf the color filter to be removed + */ +void color_filter_delete(color_filter_t *colorf); + + + + +/** Delete a filter list including all entries. + * + * @param cfl the filter list to delete + */ +void color_filter_list_delete(GSList **cfl); + + + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/conditions.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/conditions.h new file mode 100644 index 00000000..e07af3b6 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/conditions.h @@ -0,0 +1,134 @@ +/* conditions.h + * Header for condition handler. + * + * $Id: conditions.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef CONDITIONS_H +#define CONDITIONS_H + +#include + +#include + +/* forward declaration for type 'condition' */ +typedef struct condition condition; + +/* condition evaluation handler type */ +typedef gboolean (*_cnd_eval)(condition*, va_list); + +/* condition reset handler type */ +typedef void (*_cnd_reset)(condition*); + +/* condition class constructor type */ +typedef condition* (*_cnd_constr)(condition*, va_list); + +/* condition class destructor type */ +typedef void (*_cnd_destr)(condition*); + +/* + * Conditions must be created with this function. They can be created for + * registered classes only. + * + * parameter: const char* - Identification of a registered condition class. + * ... - Any number of class specific initial values. + * returns: Pointer to a initialized condition of the particular class on + * success or NULL on failure. + */ +condition* cnd_new(const char*, ...); + +/* + * Conditions must be deleted with this function when not used anymore. + * + * parameter: condition* - Pointer to a condition created with 'cnd_new()'. + * returns: - + */ +void cnd_delete(condition*); + +/* + * Call this function to check whether or not a particular condition is true. + * + * parameter: condition* - Pointer to an initialized condition. + * ... - Any number of condition specific arguments. + * returns: TRUE - Condition is true. + * FALSE - Condition is false. + */ +gboolean cnd_eval(condition*, ...); + +/* + * Call this function to reset this condition to its initial state, i.e. the + * state it was in right after creation. + * + * parameter: condition* - Pointer to an initialized condition. + * returns: - + */ +void cnd_reset(condition*); + +/* + * Register a new conditon class. + * New conditions of this class can be created by calling 'cnd_new()' and + * supplying the appropriate class id. + * + * parameter: const char* - The class id. + * _cnd_constr - User supplied constructor function for this + * class. + * _cnd_destr - User supplied destructor function for this + * class. + * _cnd_eval - User supplied evaluation handler function for this + class. + * _cnd_reset - User supplied reset handler for this class. + * returns: TRUE - Success. + * FALSE - Failure. + */ +gboolean cnd_register_class(const char*, + _cnd_constr, + _cnd_destr, + _cnd_eval, + _cnd_reset); + +/* + * Unregister a previously registered conditon class. After unregistration + * of a class it is no longer possible to create conditions of this kind by + * calling 'cnd_new()'. + * + * parameter: const char* - An identification for this condition class. + * returns: - + */ +void cnd_unregister_class(const char*); + +/* + * This function returns the user data of the condition. + * + * parameter: condition* - Pointer to an initialized condition. + * returns: void* - Pointer to user data of this condition. + */ +void* cnd_get_user_data(condition*); + +/* + * This function sets the user data of the condition. + * + * parameter: condition* - Pointer to an initialized condition. + * void* - Pointer to user specified data structure. + * returns: - + */ +void cnd_set_user_data(condition*, void*); + +#endif /* CONDITIONS_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h new file mode 100644 index 00000000..cf2ce4a1 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h @@ -0,0 +1,322 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Directory for data */ +#define DATAFILE_DIR "/usr/local/share/wireshark" + +/* Link plugins statically into Wireshark */ +/* #undef ENABLE_STATIC */ + +/* Format modifier for printing 64-bit numbers */ +/* #undef G_GINT64_MODIFIER */ + +/* Enable AirPDcap (WPA/WPA2 decryption) */ +#define HAVE_AIRPDCAP 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_INET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_NAMESER_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_DIRECT_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_DIRENT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `gethostbyname2' function. */ +#define HAVE_GETHOSTBYNAME2 1 + +/* Define to 1 if you have the `getprotobynumber' function. */ +#define HAVE_GETPROTOBYNUMBER 1 + +/* Define to use GNU ADNS library */ +/* #undef HAVE_GNU_ADNS */ + +/* Define to 1 if you have the header file. */ +#define HAVE_GRP_H 1 + +/* Define to use heimdal kerberos */ +/* #undef HAVE_HEIMDAL_KERBEROS */ + +/* Define if you have the iconv() function. */ +#define HAVE_ICONV 1 + +/* Define if inet_ntop() prototype exists */ +#define HAVE_INET_NTOP_PROTO 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `issetugid' function. */ +/* #undef HAVE_ISSETUGID */ + +/* Define to use kerberos */ +#define HAVE_KERBEROS 1 + +/* Define if krb5.h defines KEYTYPE_ARCFOUR_56 */ +/* #undef HAVE_KEYTYPE_ARCFOUR_56 */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LAUXLIB_H */ + +/* Define to use the libcap library */ +/* #undef HAVE_LIBCAP */ + +/* Define to use libgcrypt */ +#define HAVE_LIBGCRYPT 1 + +/* Define to use gnutls library */ +#define HAVE_LIBGNUTLS 1 + +/* Define to use libpcap library */ +#define HAVE_LIBPCAP 1 + +/* Define to use libpcre library */ +/* #undef HAVE_LIBPCRE */ + +/* Define to use libportaudio library */ +/* #undef HAVE_LIBPORTAUDIO */ + +/* Define to 1 if you have the `smi' library (-lsmi). */ +/* #undef HAVE_LIBSMI */ + +/* Define to use libz library */ +#define HAVE_LIBZ 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LUA5_1_LAUXLIB_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LUA5_1_LUALIB_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LUA5_1_LUA_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LUALIB_H */ + +/* Define to use Lua 5.1 */ +/* #undef HAVE_LUA_5_1 */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LUA_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to use MIT kerberos */ +#define HAVE_MIT_KERBEROS 1 + +/* Define to 1 if you have the `mmap' function. */ +#define HAVE_MMAP 1 + +/* Define to 1 if you have the `mprotect' function. */ +#define HAVE_MPROTECT 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETDB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define to 1 if you have OS X frameworks */ +/* #undef HAVE_OS_X_FRAMEWORKS */ + +/* Define if pcap_breakloop is known */ +#define HAVE_PCAP_BREAKLOOP 1 + +/* Define to 1 if you have the `pcap_createsrcstr' function. */ +/* #undef HAVE_PCAP_CREATESRCSTR */ + +/* Define to 1 if you have the `pcap_datalink_name_to_val' function. */ +#define HAVE_PCAP_DATALINK_NAME_TO_VAL 1 + +/* Define to 1 if you have the `pcap_datalink_val_to_name' function. */ +#define HAVE_PCAP_DATALINK_VAL_TO_NAME 1 + +/* Define to 1 if you have the `pcap_findalldevs' function and a pcap.h that + declares pcap_if_t. */ +#define HAVE_PCAP_FINDALLDEVS 1 + +/* Define to 1 if you have the `pcap_findalldevs_ex' function. */ +/* #undef HAVE_PCAP_FINDALLDEVS_EX */ + +/* Define to 1 if you have the `pcap_freecode' function. */ +#define HAVE_PCAP_FREECODE 1 + +/* Define to 1 if you have the `pcap_get_selectable_fd' function. */ +#define HAVE_PCAP_GET_SELECTABLE_FD 1 + +/* Define to 1 if you have the `pcap_lib_version' function. */ +#define HAVE_PCAP_LIB_VERSION 1 + +/* Define to 1 if you have the `pcap_list_datalinks' function. */ +#define HAVE_PCAP_LIST_DATALINKS 1 + +/* Define to 1 if you have the `pcap_open' function. */ +/* #undef HAVE_PCAP_OPEN */ + +/* Define to 1 if you have the `pcap_open_dead' function. */ +#define HAVE_PCAP_OPEN_DEAD 1 + +/* Define to 1 if you have WinPcap remote capturing support and prefer to use + these new API features. */ +/* #undef HAVE_PCAP_REMOTE */ + +/* Define to 1 if you have the `pcap_setsampling' function. */ +/* #undef HAVE_PCAP_SETSAMPLING */ + +/* Define to 1 if you have the `pcap_set_datalink' function. */ +#define HAVE_PCAP_SET_DATALINK 1 + +/* Define if libpcap version is known */ +#define HAVE_PCAP_VERSION 1 + +/* Define if plugins are enabled */ +#define HAVE_PLUGINS 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_PORTAUDIO_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_PWD_H 1 + +/* Define to 1 to enable remote capturing feature in WinPcap library */ +/* #undef HAVE_REMOTE */ + +/* Define if sa_len field exists in struct sockaddr */ +/* #undef HAVE_SA_LEN */ + +/* Define to 1 if you have the `setresgid' function. */ +#define HAVE_SETRESGID 1 + +/* Define to 1 if you have the `setresuid' function. */ +#define HAVE_SETRESUID 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDARG_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDDEF_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `sysconf' function. */ +#define HAVE_SYSCONF 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_SOCKIO_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_UTSNAME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* HTML viewer, e.g. mozilla */ +#define HTML_VIEWER "mozilla" + +/* Define as const if the declaration of iconv() needs const. */ +#define ICONV_CONST + +/* Define if defines PRI[doxu]64 macros */ +#define INTTYPES_H_DEFINES_FORMATS + +/* Define if getopt.h needs to be included */ +/* #undef NEED_GETOPT_H */ + +/* Define if g_ascii_strcasecmp.h needs to be included */ +/* #undef NEED_G_ASCII_STRCASECMP_H */ + +/* Define if g_ascii_strtoull.h needs to be included */ +/* #undef NEED_G_ASCII_STRTOULL_H */ + +/* Define if inet/aton.h needs to be included */ +/* #undef NEED_INET_ATON_H */ + +/* Define if inet/v6defs.h needs to be included */ +/* #undef NEED_INET_V6DEFS_H */ + +/* Define if strerror.h needs to be included */ +/* #undef NEED_STRERROR_H */ + +/* Define if strptime.h needs to be included */ +/* #undef NEED_STRPTIME_H */ + +/* Name of package */ +#define PACKAGE "wireshark" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "" + +/* Define if we are using version of of the Portaudio library API */ +/* #undef PORTAUDIO_API_1 */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Version number of package */ +#define VERSION "1.0.0" + +/* Define to 1 if your processor stores words with the most significant byte + first (like Motorola and SPARC, unlike Intel and VAX). */ +/* #undef WORDS_BIGENDIAN */ + +/* Define as the string to precede external variable declarations in + dynamically-linked libraries */ +#define WS_VAR_IMPORT extern + +/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a + `char[]'. */ +#define YYTEXT_POINTER 1 diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h.in b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h.in new file mode 100644 index 00000000..b5e1fbdc --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h.in @@ -0,0 +1,321 @@ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Directory for data */ +#undef DATAFILE_DIR + +/* Link plugins statically into Wireshark */ +#undef ENABLE_STATIC + +/* Format modifier for printing 64-bit numbers */ +#undef G_GINT64_MODIFIER + +/* Enable AirPDcap (WPA/WPA2 decryption) */ +#undef HAVE_AIRPDCAP + +/* Define to 1 if you have the header file. */ +#undef HAVE_ARPA_INET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ARPA_NAMESER_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_DIRECT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_DIRENT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the `gethostbyname2' function. */ +#undef HAVE_GETHOSTBYNAME2 + +/* Define to 1 if you have the `getprotobynumber' function. */ +#undef HAVE_GETPROTOBYNUMBER + +/* Define to use GNU ADNS library */ +#undef HAVE_GNU_ADNS + +/* Define to 1 if you have the header file. */ +#undef HAVE_GRP_H + +/* Define to use heimdal kerberos */ +#undef HAVE_HEIMDAL_KERBEROS + +/* Define if you have the iconv() function. */ +#undef HAVE_ICONV + +/* Define if inet_ntop() prototype exists */ +#undef HAVE_INET_NTOP_PROTO + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `issetugid' function. */ +#undef HAVE_ISSETUGID + +/* Define to use kerberos */ +#undef HAVE_KERBEROS + +/* Define if krb5.h defines KEYTYPE_ARCFOUR_56 */ +#undef HAVE_KEYTYPE_ARCFOUR_56 + +/* Define to 1 if you have the header file. */ +#undef HAVE_LAUXLIB_H + +/* Define to use the libcap library */ +#undef HAVE_LIBCAP + +/* Define to use libgcrypt */ +#undef HAVE_LIBGCRYPT + +/* Define to use gnutls library */ +#undef HAVE_LIBGNUTLS + +/* Define to use libpcap library */ +#undef HAVE_LIBPCAP + +/* Define to use libpcre library */ +#undef HAVE_LIBPCRE + +/* Define to use libportaudio library */ +#undef HAVE_LIBPORTAUDIO + +/* Define to 1 if you have the `smi' library (-lsmi). */ +#undef HAVE_LIBSMI + +/* Define to use libz library */ +#undef HAVE_LIBZ + +/* Define to 1 if you have the header file. */ +#undef HAVE_LUA5_1_LAUXLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LUA5_1_LUALIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LUA5_1_LUA_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LUALIB_H + +/* Define to use Lua 5.1 */ +#undef HAVE_LUA_5_1 + +/* Define to 1 if you have the header file. */ +#undef HAVE_LUA_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to use MIT kerberos */ +#undef HAVE_MIT_KERBEROS + +/* Define to 1 if you have the `mmap' function. */ +#undef HAVE_MMAP + +/* Define to 1 if you have the `mprotect' function. */ +#undef HAVE_MPROTECT + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETDB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IN_H + +/* Define to 1 if you have OS X frameworks */ +#undef HAVE_OS_X_FRAMEWORKS + +/* Define if pcap_breakloop is known */ +#undef HAVE_PCAP_BREAKLOOP + +/* Define to 1 if you have the `pcap_createsrcstr' function. */ +#undef HAVE_PCAP_CREATESRCSTR + +/* Define to 1 if you have the `pcap_datalink_name_to_val' function. */ +#undef HAVE_PCAP_DATALINK_NAME_TO_VAL + +/* Define to 1 if you have the `pcap_datalink_val_to_name' function. */ +#undef HAVE_PCAP_DATALINK_VAL_TO_NAME + +/* Define to 1 if you have the `pcap_findalldevs' function and a pcap.h that + declares pcap_if_t. */ +#undef HAVE_PCAP_FINDALLDEVS + +/* Define to 1 if you have the `pcap_findalldevs_ex' function. */ +#undef HAVE_PCAP_FINDALLDEVS_EX + +/* Define to 1 if you have the `pcap_freecode' function. */ +#undef HAVE_PCAP_FREECODE + +/* Define to 1 if you have the `pcap_get_selectable_fd' function. */ +#undef HAVE_PCAP_GET_SELECTABLE_FD + +/* Define to 1 if you have the `pcap_lib_version' function. */ +#undef HAVE_PCAP_LIB_VERSION + +/* Define to 1 if you have the `pcap_list_datalinks' function. */ +#undef HAVE_PCAP_LIST_DATALINKS + +/* Define to 1 if you have the `pcap_open' function. */ +#undef HAVE_PCAP_OPEN + +/* Define to 1 if you have the `pcap_open_dead' function. */ +#undef HAVE_PCAP_OPEN_DEAD + +/* Define to 1 if you have WinPcap remote capturing support and prefer to use + these new API features. */ +#undef HAVE_PCAP_REMOTE + +/* Define to 1 if you have the `pcap_setsampling' function. */ +#undef HAVE_PCAP_SETSAMPLING + +/* Define to 1 if you have the `pcap_set_datalink' function. */ +#undef HAVE_PCAP_SET_DATALINK + +/* Define if libpcap version is known */ +#undef HAVE_PCAP_VERSION + +/* Define if plugins are enabled */ +#undef HAVE_PLUGINS + +/* Define to 1 if you have the header file. */ +#undef HAVE_PORTAUDIO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_PWD_H + +/* Define to 1 to enable remote capturing feature in WinPcap library */ +#undef HAVE_REMOTE + +/* Define if sa_len field exists in struct sockaddr */ +#undef HAVE_SA_LEN + +/* Define to 1 if you have the `setresgid' function. */ +#undef HAVE_SETRESGID + +/* Define to 1 if you have the `setresuid' function. */ +#undef HAVE_SETRESUID + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDARG_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDDEF_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `sysconf' function. */ +#undef HAVE_SYSCONF + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_IOCTL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SOCKET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SOCKIO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_UTSNAME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_WAIT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* HTML viewer, e.g. mozilla */ +#undef HTML_VIEWER + +/* Define as const if the declaration of iconv() needs const. */ +#undef ICONV_CONST + +/* Define if defines PRI[doxu]64 macros */ +#undef INTTYPES_H_DEFINES_FORMATS + +/* Define if getopt.h needs to be included */ +#undef NEED_GETOPT_H + +/* Define if g_ascii_strcasecmp.h needs to be included */ +#undef NEED_G_ASCII_STRCASECMP_H + +/* Define if g_ascii_strtoull.h needs to be included */ +#undef NEED_G_ASCII_STRTOULL_H + +/* Define if inet/aton.h needs to be included */ +#undef NEED_INET_ATON_H + +/* Define if inet/v6defs.h needs to be included */ +#undef NEED_INET_V6DEFS_H + +/* Define if strerror.h needs to be included */ +#undef NEED_STRERROR_H + +/* Define if strptime.h needs to be included */ +#undef NEED_STRPTIME_H + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define if we are using version of of the Portaudio library API */ +#undef PORTAUDIO_API_1 + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef VERSION + +/* Define to 1 if your processor stores words with the most significant byte + first (like Motorola and SPARC, unlike Intel and VAX). */ +#undef WORDS_BIGENDIAN + +/* Define as the string to precede external variable declarations in + dynamically-linked libraries */ +#undef WS_VAR_IMPORT + +/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a + `char[]'. */ +#undef YYTEXT_POINTER diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h.win32 b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h.win32 new file mode 100644 index 00000000..a9569f67 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h.win32 @@ -0,0 +1,274 @@ +/* $Id: config.h.win32 23802 2007-12-07 23:58:46Z guy $ */ +/* config.h.win32 Generated manually. :-) */ +/* config.h. Generated automatically by configure. */ +/* config.h.in. Generated automatically from configure.in by autoheader. */ + +/* Generated Bison and Flex files test whether __STDC__ is defined + in order to check whether to use ANSI C features such as "const". + + GCC defines it as 1 even if extensions that render the implementation + non-conformant are enabled; Sun's C compiler (and, I think, other + AT&T-derived C compilers) define it as 0 if extensions that render + the implementation non-conformant are enabled; Microsoft Visual C++ + 6.0 doesn't define it at all if extensions that render the implementation + non-conformant are enabled. + + We define it as 0 here, so that those generated files will use + those features (and thus not get type warnings when compiled with + MSVC++). */ +#ifndef __STDC__ +#define __STDC__ 0 +#endif + +/* Use Unicode in Windows runtime functions. */ +#define UNICODE 1 +#define _UNICODE 1 + +/* Define if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if your processor stores words with the most significant + byte first (like Motorola and SPARC, unlike Intel and VAX). */ +/* #undef WORDS_BIGENDIAN */ + +/* Define if lex declares yytext as a char * by default, not a char[]. */ +#define YYTEXT_POINTER 1 + +#define HAVE_PLUGINS 1 +#define PLUGINS_NEED_ADDRESS_TABLE 1 + +/* Plugins can also use the import library of libwireshark.dll instead + of the old API. In that case we undefine PLUGINS_NEED_ADDRESS_TABLE + for the plugin. We don't undefine PLUGINS_NEED_ADDRESS_TABLE globally. + Thus Wireshark will be still able to load plugins using the old API. + The macro HAVE_WIN32_LIBWIRESHARK_LIB has to be defined in plugin's + makefile.nmake. A template is available in doc/README.plugins */ +#ifdef HAVE_WIN32_LIBWIRESHARK_LIB +#undef PLUGINS_NEED_ADDRESS_TABLE +#endif + +/* #undef HAVE_SA_LEN */ + +/* #undef NEED_STRERROR_H */ + +#define NEED_MKSTEMP 1 + +@HAVE_LIBPCAP@ +@HAVE_PCAP_BREAKLOOP@ +@HAVE_PCAP_FINDALLDEVS@ +@HAVE_PCAP_DATALINK_NAME_TO_VAL@ +@HAVE_PCAP_DATALINK_VAL_TO_NAME@ +@WPCAP_CONSTIFIED@ +@HAVE_LIBWIRESHARKDLL@ + +@HAVE_REMOTE@ +@HAVE_PCAP_REMOTE@ +@HAVE_PCAP_OPEN@ +@HAVE_PCAP_FINDALLDEVS_EX@ +@HAVE_PCAP_CREATESRCSTR@ +@HAVE_PCAP_SETSAMPLING@ + +@HAVE_AIRPCAP@ +@HAVE_AIRPDCAP@ + +/* availability of pcap_freecode() is handled at runtime */ +#define HAVE_PCAP_FREECODE 1 + +/* define macro for importing variables from an dll + * it depends on HAVE_LIBWIRESHARKDLL and _NEED_VAR_IMPORT_ + */ +#if defined (_NEED_VAR_IMPORT_) && defined (HAVE_LIBWIRESHARKDLL) +# define WS_VAR_IMPORT __declspec(dllimport) extern +#else +# define WS_VAR_IMPORT extern +#endif + +/* Define if you have the gethostbyname2 function. */ +/* #undef HAVE_GETHOSTBYNAME2 */ + +/* Define if you have the getprotobynumber function. */ +/* #undef HAVE_GETPROTOBYNUMBER */ + +/* Define if you have the header file. */ +/* #undef HAVE_ARPA_INET_H */ + +/* Define if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_ICONV */ + +/* Define if you have the header file. */ +/* #undef HAVE_NETDB_H */ + +/* Define if you have the header file. */ +/* #define HAVE_NETINET_IN_H 1 */ + +/* Define if you have the header file. */ +/* #undef HAVE_SNMP_SNMP_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SNMP_VERSION_H */ + +/* Define if you have the header file. */ +#define HAVE_STDARG_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_STDDEF_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_IOCTL_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_SOCKET_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_SOCKIO_H */ + +/* Define if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define if you have the header file. */ +/* #define HAVE_SYS_TIME_H 1 */ + +/* Define if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_WAIT_H */ + +/* Define if you have the header file. */ +/* #define HAVE_UNISTD_H 1 */ + +/* Define if defines PRI[doxu]64 macros */ +/* #define INTTYPES_H_DEFINES_FORMATS */ + +/* Format for printing 64-bit signed decimal numbers */ +#ifndef PRId64 +#ifdef _MSC_EXTENSIONS +#define PRId64 "I64d" +#else /* _MSC_EXTENSIONS */ +#define PRId64 "lld" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRId64 */ + +/* Format for printing 64-bit unsigned octal numbers */ +#ifndef PRIo64 +#ifdef _MSC_EXTENSIONS +#define PRIo64 "I64o" +#else /* _MSC_EXTENSIONS */ +#define PRIo64 "llo" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRIo64 */ + +/* Format for printing 64-bit unsigned decimal numbers */ +#ifndef PRIu64 +#ifdef _MSC_EXTENSIONS +#define PRIu64 "I64u" +#else /* _MSC_EXTENSIONS */ +#define PRIu64 "llu" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRIu64 */ + +/* Formats for printing 64-bit unsigned hexadecimal numbers */ +/* XXX - it seems that GLib has problems with the MSVC like I64x. + As we use GLib's g_sprintf and alike, it should be safe to use + llx everywhere now, making the macros pretty useless. For details see: + http://bugs.wireshark.org/bugzilla/show_bug.cgi?id=1025 */ +#ifndef PRIx64 +#ifdef _MSC_EXTENSIONS +/*#define PRIx64 "I64x"*/ +#define PRIx64 "llx" +#else /* _MSC_EXTENSIONS */ +#define PRIx64 "llx" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRIx64 */ + +#ifndef PRIX64 +#ifdef _MSC_EXTENSIONS +/*#define PRIX64 "I64X"*/ +#define PRIX64 "llX" +#else /* _MSC_EXTENSIONS */ +#define PRIX64 "llX" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRIX64 */ + +/* Define if you have the z library (-lz). */ +@HAVE_LIBZ@ + +/* Define to use GNU ADNS library */ +@HAVE_GNU_ADNS@ +#define ADNS_JGAA_WIN32 1 + +/* Define to use the PCRE library */ +@HAVE_PCRE@ + +/* Define to use the Nettle library */ +@HAVE_NETTLE@ + +/* Define to use the gnutls library */ +@HAVE_LIBGNUTLS@ + +/* Define to use the libgcrypt library */ +@HAVE_LIBGCRYPT@ + +/* Define to use mit kerberos for decryption of kerberos/sasl/dcerpc */ +@HAVE_KFW@ +#ifdef HAVE_MIT_KERBEROS +#define HAVE_KERBEROS +#endif + +/* Define to use Lua */ +@HAVE_LUA@ +@HAVE_LUA_5_1@ + +/* Define to use Portaudio library */ +@HAVE_LIBPORTAUDIO@ +/* Define version of of the Portaudio library API */ +@PORTAUDIO_API_1@ + +/* Define to have SMI */ +@HAVE_SMI@ + + +#ifndef WIN32 +#define WIN32 1 +#endif + +#define HAVE_WINDOWS_H 1 +#define HAVE_WINSOCK2_H 1 +#define HAVE_DIRECT_H 1 +#define NEED_INET_ATON_H 1 +#define NEED_INET_V6DEFS_H 1 +/* Visual C 9 (2008) now needs these prototypes */ +#if _MSC_VER == 1500 +#define NTDDI_VERSION NTDDI_WIN2K +#define _WIN32_WINNT _WIN32_WINNT_WIN2K +#endif +#define NEED_GETOPT_H 1 +#define NEED_STRPTIME_H 1 +#define strcasecmp stricmp +#define strncasecmp strnicmp +#define popen _popen +#define pclose _pclose + +/* Needed for zlib, according to http://www.winimage.com/zLibDll/ */ +/*#define ZLIB_DLL 1 +#define _WINDOWS 1*/ + +/* Name of package */ +#define PACKAGE "wireshark" + +/* Version number of package */ +#define VERSION "@VERSION@" + +/* We shouldn't need this under Windows but we'll define it anyway. */ +#define HTML_VIEWER "mozilla" + +/* Check for the required _MSC_VER */ +#if MSC_VER_REQUIRED != _MSC_VER +#define WS_TO_STRING2(x) #x +#define WS_TO_STRING(x) WS_TO_STRING2(x) +#pragma message( "_MSC_VER is:" WS_TO_STRING(_MSC_VER) " but required is:" WS_TO_STRING(MSC_VER_REQUIRED) ) +#error Your MSVC_VARIANT setting in config.nmake doesn't match the MS compiler version! +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/disabled_protos.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/disabled_protos.h new file mode 100644 index 00000000..87f5b3ab --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/disabled_protos.h @@ -0,0 +1,61 @@ +/* disabled_protos.h + * Declarations of routines for reading and writing the disabled protocols file. + * + * $Id: disabled_protos.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * Item in a list of disabled protocols. + */ +typedef struct { + char *name; /* protocol name */ +} protocol_def; + +/* + * Read in a list of disabled protocols. + * + * On success, "*pref_path_return" is set to NULL. + * On error, "*pref_path_return" is set to point to the pathname of + * the file we tried to read - it should be freed by our caller - + * and "*open_errno_return" is set to the error if we couldn't open the file + * or "*read_errno_return" is set to the error if we got an error reading + * the file. + */ +void read_disabled_protos_list(char **gpath_return, int *gopen_errno_return, + int *gread_errno_return, + char **path_return, int *open_errno_return, + int *read_errno_return); + +/* + * Disable protocols as per the stored configuration + */ +void set_disabled_protos_list(void); + +/* + * Write out a list of disabled protocols. + * + * On success, "*pref_path_return" is set to NULL. + * On error, "*pref_path_return" is set to point to the pathname of + * the file we tried to read - it should be freed by our caller - + * and "*errno_return" is set to the error. + */ +void save_disabled_protos_list(char **pref_path_return, int *errno_return); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/addr_and_mask.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/addr_and_mask.h new file mode 100644 index 00000000..b582aa6e --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/addr_and_mask.h @@ -0,0 +1,53 @@ +/* addr_and_mask.h + * Declarations of routines to fetch IPv4 and IPv6 addresses from a tvbuff + * and then mask out bits other than those covered by a prefix length + * + * $Id: addr_and_mask.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ADDR_AND_MASK_H__ +#define __ADDR_AND_MASK_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * These routines return PREFIX_LEN_OK on success, PREFIX_LEN_TOO_LONG if + * the prefix length is too long, and PREFIX_LEN_ZERO if the prefix length + * is 0. + */ + +#define PREFIX_LEN_OK 0 +#define PREFIX_LEN_TOO_LONG 1 +#define PREFIX_LEN_ZERO 2 + +extern int ipv4_addr_and_mask(tvbuff_t *tvb, int offset, guint8 *addr, + guint32 prefix_len); + +extern int ipv6_addr_and_mask(tvbuff_t *tvb, int offset, + struct e_in6_addr *addr, guint32 prefix_len); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __ADDR_AND_MASK_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/addr_resolv.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/addr_resolv.h new file mode 100644 index 00000000..4733db52 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/addr_resolv.h @@ -0,0 +1,198 @@ +/* addr_resolv.h + * Definitions for network object lookup + * + * $Id: addr_resolv.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Laurent Deniel + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +/* The buffers returned by these functions are all allocated with a + * packet lifetime and does not have have to be freed. + * However, take into account that when the packet dissection + * completes, these buffers will be automatically reclaimed/freed. + * If you need the buffer to remain for a longer scope than packet lifetime + * you must copy the content to an se_alloc() buffer. + */ + +#ifndef __RESOLV_H__ +#define __RESOLV_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifndef MAXNAMELEN +#define MAXNAMELEN 64 /* max name length (hostname and port name) */ +#endif + +/* + * Flag controlling what names to resolve. + */ +WS_VAR_IMPORT guint32 g_resolv_flags; + +/* 32 types are sufficient (as are 640k of RAM) */ +/* FIXME: Maybe MANUF/m, IP/i, IP6/6, IPX/x, UDP+TCP/t etc would be + more useful/consistent */ +#define RESOLV_NONE 0x0 +#define RESOLV_MAC 0x1 +#define RESOLV_NETWORK 0x2 +#define RESOLV_TRANSPORT 0x4 +#define RESOLV_CONCURRENT 0x8 + +#define RESOLV_ALL_ADDRS (RESOLV_MAC|RESOLV_NETWORK|RESOLV_TRANSPORT) +#define RESOLV_ALL 0xFFFFFFFF + +/* global variables */ + +extern gchar *g_ethers_path; +extern gchar *g_ipxnets_path; +extern gchar *g_pethers_path; +extern gchar *g_pipxnets_path; + +/* Functions in resolv.c */ + +/* Set the flags controlling what names to resolve */ +extern void resolv_set_flags(guint32 flags); + +/* + * get_udp_port() returns the port name corresponding to that UDP port, + * or the port number as a string if not found. + */ +extern gchar *get_udp_port(guint port); + +/* + * get_tcp_port() returns the port name corresponding to that TCP port, + * or the port number as a string if not found. + */ +extern gchar *get_tcp_port(guint port); + +/* + * get_dccp_port() returns the port name corresponding to that DCCP port, + * or the port number as a string if not found. + */ +extern gchar *get_dccp_port(guint port); + +/* + * get_sctp_port() returns the port name corresponding to that SCTP port, + * or the port number as a string if not found. + */ +extern gchar *get_sctp_port(guint port); + +/* get_addr_name takes as input an "address", as defined in address.h */ +/* it returns a string that contains: */ +/* - if the address is of a type that can be translated into a name, and the user */ +/* has activated name resolution, the translated name */ +/* - if the address is of type AT_NONE, a pointer to the string "NONE" */ +/* - if the address is of any other type, the result of address_to_str on the argument, */ +/* which should be a string representation for the answer -e.g. "10.10.10.10" for IPv4 */ +/* address 10.10.10.10 */ + +const gchar *get_addr_name(address *addr); + +/* get_addr_name_buf solves an address in the same way as get_addr_name above */ +/* The difference is that get_addr_name_buf takes as input a buffer, into which it puts */ +/* the result which is always NUL ('\0') terminated. The buffer should be large enough to */ +/* contain size characters including the terminator */ + +void get_addr_name_buf(address *addr, gchar *buf, guint size); + + +/* + * Asynchronous host name lookup initialization, processing, and cleanup + */ + +/* host_name_lookup_init fires up an ADNS socket if we're using ADNS */ +extern void host_name_lookup_init(void); + +/* host_name_lookup_process does ADNS processing in GTK+ timeouts in Wireshark, + and before processing each packet in TShark, if we're using ADNS */ +extern gint host_name_lookup_process(gpointer data); + +/* host_name_lookup_cleanup cleans up an ADNS socket if we're using ADNS */ +extern void host_name_lookup_cleanup(void); + +/* get_hostname returns the host name or "%d.%d.%d.%d" if not found */ +extern gchar *get_hostname(guint addr); + +/* get_hostname6 returns the host name, or numeric addr if not found */ +struct e_in6_addr; +const gchar* get_hostname6(struct e_in6_addr *ad); + +/* get_ether_name returns the logical name if found in ethers files else + "_%02x:%02x:%02x" if the vendor code is known else + "%02x:%02x:%02x:%02x:%02x:%02x" */ +extern gchar *get_ether_name(const guint8 *addr); + +/* get_ether_name returns the logical name if found in ethers files else NULL */ +extern gchar *get_ether_name_if_known(const guint8 *addr); + +/* get_manuf_name returns the vendor name or "%02x:%02x:%02x" if not known */ +extern const gchar *get_manuf_name(const guint8 *addr); + +/* get_manuf_name returns the vendor name or NULL if not known */ +extern const gchar *get_manuf_name_if_known(const guint8 *addr); + +/* get_ipxnet_name returns the logical name if found in an ipxnets file, + * or a string formatted with "%X" if not */ +extern const gchar *get_ipxnet_name(const guint32 addr); + +/* returns the ethernet address corresponding to name or NULL if not known */ +extern guint8 *get_ether_addr(const gchar *name); + +/* returns the ipx network corresponding to name. If name is unknown, + * 0 is returned and 'known' is set to FALSE. On success, 'known' + * is set to TRUE. */ +guint32 get_ipxnet_addr(const gchar *name, gboolean *known); + +/* adds a hostname/IPv4 in the hash table */ +extern void add_ipv4_name(guint addr, const gchar *name); + +/* adds a hostname/IPv6 in the hash table */ +extern void add_ipv6_name(struct e_in6_addr *addr, const gchar *name); + +/* add ethernet address / name corresponding to IP address */ +extern void add_ether_byip(guint ip, const guint8 *eth); + +/* Translates a string representing the hostname or dotted-decimal IP address + * into a numeric IP address value, returning TRUE if it succeeds and + * FALSE if it fails. */ +gboolean get_host_ipaddr(const char *host, guint32 *addrp); + +/* + * Translate IPv6 numeric address or FQDN hostname, into binary IPv6 address. + * Return TRUE if we succeed and set "*addrp" to that numeric IP address; + * return FALSE if we fail. + */ +gboolean get_host_ipaddr6(const char *host, struct e_in6_addr *addrp); + +/* + * Find out whether a hostname resolves to an ip or ipv6 address + * Return "ip6" if it is IPv6, "ip" otherwise (including the case + * that we don't know) + */ +const char* host_ip_af(const char *host); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __RESOLV_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/address.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/address.h new file mode 100644 index 00000000..1ce916d4 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/address.h @@ -0,0 +1,172 @@ +/* address.h + * Definitions for structures storing addresses, and for the type of + * variables holding port-type values + * + * $Id: address.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ADDRESS_H__ +#define __ADDRESS_H__ + +#include "emem.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Types of addresses Wireshark knows about. */ +/* If a new address type is added here, a string representation procedure should */ +/* also be included in address_to_str_buf defined in to_str.c, for presentation purposes */ + +typedef enum { + AT_NONE, /* no link-layer address */ + AT_ETHER, /* MAC (Ethernet, 802.x, FDDI) address */ + AT_IPv4, /* IPv4 */ + AT_IPv6, /* IPv6 */ + AT_IPX, /* IPX */ + AT_SNA, /* SNA */ + AT_ATALK, /* Appletalk DDP */ + AT_VINES, /* Banyan Vines */ + AT_OSI, /* OSI NSAP */ + AT_ARCNET, /* ARCNET */ + AT_FC, /* Fibre Channel */ + AT_SS7PC, /* SS7 Point Code */ + AT_STRINGZ, /* null-terminated string */ + AT_EUI64, /* IEEE EUI-64 */ + AT_URI, /* URI/URL/URN */ + AT_TIPC, /* TIPC Address Zone,Subnetwork,Processor */ + AT_USB /* USB Device address + * (0xffffffff represents the host) */ +} address_type; + +typedef struct _address { + address_type type; /* type of address */ + int len; /* length of address, in bytes */ + const void *data; /* pointer to address data */ +} address; + +#define SET_ADDRESS(addr, addr_type, addr_len, addr_data) { \ + (addr)->type = (addr_type); \ + (addr)->len = (addr_len); \ + (addr)->data = (addr_data); \ + } + +/* + * Given two addresses, return + * 0 if the addresses are equal, + * a positive number if addr1>addr2 in some nondefined metric, + * a negative number if addr1type > (addr2)->type)?1: \ + ((addr1)->type < (addr2)->type)?-1: \ + ((addr1)->len > (addr2)->len) ?1: \ + ((addr1)->len < (addr2)->len) ?-1: \ + memcmp((addr1)->data, (addr2)->data, (addr1)->len)\ + ) + +/* + * Given two addresses, return "true" if they're equal, "false" otherwise. + * Addresses are equal only if they have the same type; if the type is + * AT_NONE, they are then equal, otherwise they must have the same + * amount of data and the data must be the same. + */ +#define ADDRESSES_EQUAL(addr1, addr2) \ + ( \ + (addr1)->type == (addr2)->type && \ + ( \ + (addr1)->type == AT_NONE || \ + ( \ + (addr1)->len == (addr2)->len && \ + memcmp((addr1)->data, (addr2)->data, (addr1)->len) == 0 \ + ) \ + ) \ + ) + +/* + * Copy an address, allocating a new buffer for the address data. + */ +#define COPY_ADDRESS(to, from) { \ + guint8 *COPY_ADDRESS_data; \ + (to)->type = (from)->type; \ + (to)->len = (from)->len; \ + COPY_ADDRESS_data = g_malloc((from)->len); \ + memcpy(COPY_ADDRESS_data, (from)->data, (from)->len); \ + (to)->data = COPY_ADDRESS_data; \ + } + +#define SE_COPY_ADDRESS(to, from) { \ + guint8 *SE_COPY_ADDRESS_data; \ + (to)->type = (from)->type; \ + (to)->len = (from)->len; \ + SE_COPY_ADDRESS_data = se_alloc((from)->len); \ + memcpy(SE_COPY_ADDRESS_data, (from)->data, (from)->len); \ + (to)->data = SE_COPY_ADDRESS_data; \ + } + +/* + * Hash an address into a hash value (which must already have been set). + */ +#define ADD_ADDRESS_TO_HASH(hash_val, addr) { \ + const guint8 *ADD_ADDRESS_TO_HASH_data; \ + int ADD_ADDRESS_TO_HASH_index; \ + ADD_ADDRESS_TO_HASH_data = (addr)->data; \ + for (ADD_ADDRESS_TO_HASH_index = 0; \ + ADD_ADDRESS_TO_HASH_index < (addr)->len; \ + ADD_ADDRESS_TO_HASH_index++) \ + hash_val += ADD_ADDRESS_TO_HASH_data[ADD_ADDRESS_TO_HASH_index]; \ + } + +/* Types of port numbers Wireshark knows about. */ +typedef enum { + PT_NONE, /* no port number */ + PT_SCTP, /* SCTP */ + PT_TCP, /* TCP */ + PT_UDP, /* UDP */ + PT_DCCP, /* DCCP */ + PT_IPX, /* IPX sockets */ + PT_NCP, /* NCP connection */ + PT_EXCHG, /* Fibre Channel exchange */ + PT_DDP, /* DDP AppleTalk connection */ + PT_SBCCS, /* FICON */ + PT_IDP, /* XNS IDP sockets */ + PT_TIPC, /* TIPC PORT */ + PT_USB /* USB endpoint 0xffff means the host */ +} port_type; + +/* Types of circuit IDs Wireshark knows about. */ +typedef enum { + CT_NONE, /* no circuit type */ + CT_DLCI, /* Frame Relay DLCI */ + CT_ISDN, /* ISDN channel number */ + CT_X25, /* X.25 logical channel number */ + CT_ISUP, /* ISDN User Part CIC */ + CT_IAX2, /* IAX2 call id */ + CT_H223, /* H.223 logical channel number */ + CT_BICC /* BICC Circuit identifier */ + /* Could also have ATM VPI/VCI pairs */ +} circuit_type; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __ADDRESS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/adler32.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/adler32.h new file mode 100644 index 00000000..277ed53a --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/adler32.h @@ -0,0 +1,42 @@ +/* adler32.h + * Compute the Adler32 checksum (RFC 1950) + * 2003 Tomas Kukosa + * + * $Id: adler32.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef ADLER32_H +#define ADLER32_H + +#ifdef __cplusplus +extern "C"{ +#endif + +unsigned long update_adler32(unsigned long adler, const unsigned char *buf, int len); +unsigned long adler32_bytes(const unsigned char *buf, int len); +unsigned long adler32_str(const char *buf); + +#ifdef __cplusplus +} +#endif + +#endif /* ADLER32_H */ + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/afn.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/afn.h new file mode 100644 index 00000000..16538789 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/afn.h @@ -0,0 +1,71 @@ +/* afn.h + * RFC 1700 address family numbers + * + * $Id: afn.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __AFN_H__ +#define __AFN_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * Address family numbers, from + * + * http://www.iana.org/assignments/address-family-numbers + */ +#define AFNUM_RESERVED 0 /* Reserved */ +#define AFNUM_INET 1 /* IP (IP version 4) */ +#define AFNUM_INET6 2 /* IP6 (IP version 6) */ +#define AFNUM_NSAP 3 /* NSAP */ +#define AFNUM_HDLC 4 /* HDLC (8-bit multidrop) */ +#define AFNUM_BBN1822 5 /* BBN 1822 */ +#define AFNUM_802 6 /* 802 (includes all 802 media plus Ethernet "canonical format") */ +#define AFNUM_E163 7 /* E.163 */ +#define AFNUM_E164 8 /* E.164 (SMDS, Frame Relay, ATM) */ +#define AFNUM_F69 9 /* F.69 (Telex) */ +#define AFNUM_X121 10 /* X.121 (X.25, Frame Relay) */ +#define AFNUM_IPX 11 /* IPX */ +#define AFNUM_ATALK 12 /* Appletalk */ +#define AFNUM_DECNET 13 /* Decnet IV */ +#define AFNUM_BANYAN 14 /* Banyan Vines */ +#define AFNUM_E164NSAP 15 /* E.164 with NSAP format subaddress */ +#define AFNUM_DNS 16 /* DNS (Domain Name System) */ +#define AFNUM_DISTNAME 17 /* Distinguished Name */ +#define AFNUM_AS_NUMBER 18 /* AS Number */ +#define AFNUM_XTP_IP4 19 /* XTP over IP version 4 */ +#define AFNUM_XTP_IP6 20 /* XTP over IP version 6 */ +#define AFNUM_XTP 21 /* XTP native mode XTP */ +#define AFNUM_FC_WWPN 22 /* Fibre Channel World-Wide Port Name */ +#define AFNUM_FC_WWNN 23 /* Fibre Channel World-Wide Node Name */ +#define AFNUM_GWID 24 /* GWID */ +/* draft-kompella-ppvpn-l2vpn */ +#define AFNUM_L2VPN 25 +#define AFNUM_L2VPN_OLD 196 +extern const value_string afn_vals[]; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __AFN_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/aftypes.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/aftypes.h new file mode 100644 index 00000000..a28d7494 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/aftypes.h @@ -0,0 +1,47 @@ +/* aftypes.h + * AF_ values on various flavors of BSD + * + * $Id: aftypes.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * + * This file created and by Mike Hall + * Copyright 1998 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __AFTYPES_H__ +#define __AFTYPES_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* BSD AF_ values. */ +#define BSD_AF_INET 2 +#define BSD_AF_ISO 7 +#define BSD_AF_APPLETALK 16 +#define BSD_AF_IPX 23 +#define BSD_AF_INET6_BSD 24 /* OpenBSD (and probably NetBSD), BSD/OS */ +#define BSD_AF_INET6_FREEBSD 28 +#define BSD_AF_INET6_DARWIN 30 + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* aftypes.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/arcnet_pids.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/arcnet_pids.h new file mode 100644 index 00000000..7f92176a --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/arcnet_pids.h @@ -0,0 +1,70 @@ +/* arcnet_pids.h + * ARCNET protocol ID values + * Copyright 2001-2002, Peter Fales + * + * $Id: arcnet_pids.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ARCNET_PIDS_H__ +#define __ARCNET_PIDS_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* RFC 1051 */ +#define ARCNET_PROTO_IP_1051 240 +#define ARCNET_PROTO_ARP_1051 241 + +/* RFC 1201 */ +#define ARCNET_PROTO_IP_1201 212 +#define ARCNET_PROTO_ARP_1201 213 +#define ARCNET_PROTO_RARP_1201 214 + +#define ARCNET_PROTO_IPX 250 +#define ARCNET_PROTO_NOVELL_EC 236 + +#define ARCNET_PROTO_IPv6 196 /* or so BSD's arcnet.h claims */ + +/* + * Raw Ethernet over ARCNET - Linux's "if_arcnet.h" calls this + * "MS LanMan/WfWg 'NDIS' encapsuation". + */ +#define ARCNET_PROTO_ETHERNET 232 + +#define ARCNET_PROTO_DATAPOINT_BOOT 0 +#define ARCNET_PROTO_DATAPOINT_MOUNT 1 +#define ARCNET_PROTO_POWERLAN_BEACON 8 +#define ARCNET_PROTO_POWERLAN_BEACON2 243 +#define ARCNET_PROTO_LANSOFT 251 + +#define ARCNET_PROTO_APPLETALK 221 +#define ARCNET_PROTO_BANYAN 247 /* Banyan VINES */ + +#define ARCNET_PROTO_DIAGNOSE 128 /* as per ANSI/ATA 878.1 */ + +#define ARCNET_PROTO_BACNET 205 + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* arcnet_pids.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/arptypes.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/arptypes.h new file mode 100644 index 00000000..de936cb6 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/arptypes.h @@ -0,0 +1,75 @@ +/* arptypes.h + * Declarations of ARP address types. + * + * $Id: arptypes.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ARPTYPES_H__ +#define __ARPTYPES_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Definitions taken from Linux "linux/if_arp.h" header file, and from + + http://www.iana.org/assignments/arp-parameters + + */ + +/* ARP protocol HARDWARE identifiers. */ +#define ARPHRD_NETROM 0 /* from KA9Q: NET/ROM pseudo */ +#define ARPHRD_ETHER 1 /* Ethernet 10Mbps */ +#define ARPHRD_EETHER 2 /* Experimental Ethernet */ +#define ARPHRD_AX25 3 /* AX.25 Level 2 */ +#define ARPHRD_PRONET 4 /* PROnet token ring */ +#define ARPHRD_CHAOS 5 /* Chaosnet */ +#define ARPHRD_IEEE802 6 /* IEEE 802.2 Ethernet/TR/TB */ +#define ARPHRD_ARCNET 7 /* ARCnet */ +#define ARPHRD_HYPERCH 8 /* Hyperchannel */ +#define ARPHRD_LANSTAR 9 /* Lanstar */ +#define ARPHRD_AUTONET 10 /* Autonet Short Address */ +#define ARPHRD_LOCALTLK 11 /* Localtalk */ +#define ARPHRD_LOCALNET 12 /* LocalNet (IBM PCNet/Sytek LocalNET) */ +#define ARPHRD_ULTRALNK 13 /* Ultra link */ +#define ARPHRD_SMDS 14 /* SMDS */ +#define ARPHRD_DLCI 15 /* Frame Relay DLCI */ +#define ARPHRD_ATM 16 /* ATM */ +#define ARPHRD_HDLC 17 /* HDLC */ +#define ARPHRD_FIBREC 18 /* Fibre Channel */ +#define ARPHRD_ATM2225 19 /* ATM (RFC 2225) */ +#define ARPHRD_SERIAL 20 /* Serial Line */ +#define ARPHRD_ATM2 21 /* ATM */ +#define ARPHRD_MS188220 22 /* MIL-STD-188-220 */ +#define ARPHRD_METRICOM 23 /* Metricom STRIP */ +#define ARPHRD_IEEE1394 24 /* IEEE 1394.1995 */ +#define ARPHRD_MAPOS 25 /* MAPOS */ +#define ARPHRD_TWINAX 26 /* Twinaxial */ +#define ARPHRD_EUI_64 27 /* EUI-64 */ + +/* Virtual ARP types for non ARP hardware used in Linux cooked mode. */ +#define ARPHRD_IPGRE 778 /* GRE over IP */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* arptypes.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/asm_utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/asm_utils.h new file mode 100644 index 00000000..384b0d68 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/asm_utils.h @@ -0,0 +1,38 @@ +/* asm_utils.h + * Functions optionally implemented in assembler + * + * $Id: asm_utils.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ASM_UTILS_H__ +#define __ASM_UTILS_H__ + +gint wrs_strcmp(gconstpointer a, gconstpointer b); +gint wrs_strcmp_with_data(gconstpointer a, gconstpointer b, gpointer user_data); +gboolean wrs_str_equal(gconstpointer a, gconstpointer b); + +guchar wrs_check_charset(const guchar table[256], const char *str); + +guint wrs_str_hash(gconstpointer v); + +/* int wrs_count_bitshift(guint32 bitmask); */ + +#endif /* __ASM_UTILS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/asn1.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/asn1.h new file mode 100644 index 00000000..b57bbcff --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/asn1.h @@ -0,0 +1,207 @@ +/* asn1.h + * Common data for ASN.1 + * 2007 Anders Broman + * + * $Id: asn1.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ASN1_H__ +#define __ASN1_H__ + +typedef enum { + ASN1_ENC_BER, /* X.690 - BER, CER, DER */ + ASN1_ENC_PER, /* X.691 - PER */ + ASN1_ENC_ECN, /* X.692 - ECN */ + ASN1_ENC_XER /* X.693 - XER */ +} asn1_enc_e; + +typedef enum { + CB_ASN1_ENC, + CB_DISSECTOR, + CB_NEW_DISSECTOR, + CB_DISSECTOR_HANDLE +} asn1_cb_variant; + +typedef enum { + ASN1_PAR_IRR, /* irrelevant parameter */ + /* value */ + ASN1_PAR_BOOLEAN, + ASN1_PAR_INTEGER, + /* type */ + ASN1_PAR_TYPE +} asn1_par_type; + +typedef struct _asn1_par_def_t { + const gchar *name; + asn1_par_type ptype; +} asn1_par_def_t; + +typedef struct _asn1_par_t { + const gchar *name; + asn1_par_type ptype; + union { + gboolean v_boolean; + gint32 v_integer; + void *v_type; + } value; + struct _asn1_par_t *next; +} asn1_par_t; + +typedef struct _asn1_stack_frame_t { + const gchar *name; + struct _asn1_par_t *par; + struct _asn1_stack_frame_t *next; +} asn1_stack_frame_t; + +#define ASN1_CTX_SIGNATURE 0x41435458 /* "ACTX" */ + +typedef struct _asn1_ctx_t { + guint32 signature; + asn1_enc_e encoding; + gboolean aligned; + packet_info *pinfo; + proto_item *created_item; + struct _asn1_stack_frame_t *stack; + void *value_ptr; + void *private_data; + struct { + int hf_index; + gboolean data_value_descr_present; + gboolean direct_ref_present; + gboolean indirect_ref_present; + tvbuff_t *data_value_descriptor; + const char *direct_reference; + gint32 indirect_reference; + gint encoding; + /* + 0 : single-ASN1-type, + 1 : octet-aligned, + 2 : arbitrary + */ + tvbuff_t *single_asn1_type; + tvbuff_t *octet_aligned; + tvbuff_t *arbitrary; + union { + struct { + int (*ber_callback)(gboolean imp_tag, tvbuff_t *tvb, int offset, struct _asn1_ctx_t* ,proto_tree *tree, int hf_index ); + } ber; + struct { + int (*type_cb)(tvbuff_t*, int, struct _asn1_ctx_t*, proto_tree*, int); + } per; + } u; + } external; + struct { + int hf_index; + gboolean data_value_descr_present; + tvbuff_t *data_value_descriptor; + gint identification; + /* + 0 : syntaxes, + 1 : syntax, + 2 : presentation-context-id, + 3 : context-negotiation, + 4 : transfer-syntax, + 5 : fixed + */ + gint32 presentation_context_id; + const char *abstract_syntax; + const char *transfer_syntax; + tvbuff_t *data_value; + union { + struct { + int (*ber_callback)(gboolean imp_tag, tvbuff_t *tvb, int offset, struct _asn1_ctx_t* ,proto_tree *tree, int hf_index ); + } ber; + struct { + int (*type_cb)(tvbuff_t*, int, struct _asn1_ctx_t*, proto_tree*, int); + } per; + } u; + } embedded_pdv; + struct _rose_ctx_t *rose_ctx; +} asn1_ctx_t; + +#define ROSE_CTX_SIGNATURE 0x524F5345 /* "ROSE" */ + +typedef struct _rose_ctx_t { + guint32 signature; + dissector_table_t arg_global_dissector_table; + dissector_table_t arg_local_dissector_table; + dissector_table_t res_global_dissector_table; + dissector_table_t res_local_dissector_table; + dissector_table_t err_global_dissector_table; + dissector_table_t err_local_dissector_table; + /* filling in description into tree, info column, any buffer */ + int apdu_depth; + gboolean fillin_info; + gchar *fillin_ptr; + gsize fillin_buf_size; + struct { /* "dynamic" data */ + gint pdu; + /* + 1 : invoke, + 2 : returnResult, + 3 : returnError, + 4 : reject + */ + gint code; + /* + 0 : local, + 1 : global + */ + gint32 code_local; + const char *code_global; + proto_item *code_item; + } d; + void *private_data; +} rose_ctx_t; + +extern void asn1_ctx_init(asn1_ctx_t *actx, asn1_enc_e encoding, gboolean aligned, packet_info *pinfo); +extern gboolean asn1_ctx_check_signature(asn1_ctx_t *actx); +extern void asn1_ctx_clean_external(asn1_ctx_t *actx); +extern void asn1_ctx_clean_epdv(asn1_ctx_t *actx); + +extern void asn1_stack_frame_push(asn1_ctx_t *actx, const gchar *name); +extern void asn1_stack_frame_pop(asn1_ctx_t *actx, const gchar *name); +extern void asn1_stack_frame_check(asn1_ctx_t *actx, const gchar *name, const asn1_par_def_t *par_def); + +extern void asn1_param_push_boolean(asn1_ctx_t *actx, gboolean value); +extern void asn1_param_push_integer(asn1_ctx_t *actx, gint32 value); +extern gboolean asn1_param_get_boolean(asn1_ctx_t *actx, const gchar *name); +extern gint32 asn1_param_get_integer(asn1_ctx_t *actx, const gchar *name); + +extern void rose_ctx_init(rose_ctx_t *rctx); +extern gboolean rose_ctx_check_signature(rose_ctx_t *rctx); +extern void rose_ctx_clean_data(rose_ctx_t *rctx); + +extern asn1_ctx_t *get_asn1_ctx(void *ptr); +extern rose_ctx_t *get_rose_ctx(void *ptr); + +extern double asn1_get_real(const guint8 *real_ptr, gint real_len); + +/* flags */ +#define ASN1_EXT_ROOT 0x01 +#define ASN1_EXT_EXT 0x02 +#define ASN1_OPT 0x04 +#define ASN1_DFLT 0x08 + +#define ASN1_HAS_EXT(f) ((f)&(ASN1_EXT_ROOT|ASN1_EXT_EXT)) + + +#endif /* __ASN1_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/atalk-utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/atalk-utils.h new file mode 100644 index 00000000..c7cdcdf4 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/atalk-utils.h @@ -0,0 +1,63 @@ +/* atalk-utils.h + * Definitions for Appletalk utilities (DDP, currently). + * + * $Id: atalk-utils.h 3992 2008-06-10 03:13:11Z dgu $ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ATALK_UTILS_H__ +#define __ATALK_UTILS_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * Structure used to represent a DDP address; gives the layout of the + * data pointed to by an AT_ATALK "address" structure. + */ +struct atalk_ddp_addr { + guint16 net; + guint8 node; +}; + +/* + * DDP packet types. + */ +#define DDP_RTMPDATA 0x01 +#define DDP_NBP 0x02 +#define DDP_ATP 0x03 +#define DDP_AEP 0x04 +#define DDP_RTMPREQ 0x05 +#define DDP_ZIP 0x06 +#define DDP_ADSP 0x07 +#define DDP_EIGRP 0x58 + +/* + * Routines to take a DDP address and generate a string. + */ +extern gchar *atalk_addr_to_str(const struct atalk_ddp_addr *addrp); +extern void atalk_addr_to_str_buf(const struct atalk_ddp_addr *addrp, + gchar *buf, int buf_len); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/base64.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/base64.h new file mode 100644 index 00000000..38aacf8a --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/base64.h @@ -0,0 +1,38 @@ +/* base64.h + * Base-64 conversion + * + * $Id: base64.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef __BASE64_H__ +#define __BASE64_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* In-place decoding of a base64 string. */ +size_t epan_base64_decode(char *s); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __BASE64_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/bitswap.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/bitswap.h new file mode 100644 index 00000000..2f0f74db --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/bitswap.h @@ -0,0 +1,40 @@ +/* bitswap.h + * Macro to bitswap a byte by looking it up in a table + * + * $Id: bitswap.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __BITSWAP_H__ +#define __BITSWAP_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +extern guint8 swaptab[256]; + +#define BIT_SWAP(b) (swaptab[b]) + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* bitswap.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/bridged_pids.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/bridged_pids.h new file mode 100644 index 00000000..5eb3a1d0 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/bridged_pids.h @@ -0,0 +1,58 @@ +/* bridged_pids.h + * Definitions of protocol IDs for the 00-80-C2 OUI, used for + * bridging various networks over ATM (RFC 2684) or Frame Relay (RFC 2427). + * + * $Id: bridged_pids.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 - 2000 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __BRIDGED_PID_H__ +#define __BRIDGED_PID_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define BPID_ETH_WITH_FCS 0x0001 /* 802.3/Ethernet with preserved FCS */ +#define BPID_ETH_WITHOUT_FCS 0x0007 /* 802.3/Ethernet without preserved FCS */ + +#define BPID_802_4_WITH_FCS 0x0002 /* 802.4 with preserved FCS */ +#define BPID_802_4_WITHOUT_FCS 0x0008 /* 802.4 without preserved FCS */ + +#define BPID_802_5_WITH_FCS 0x0003 /* 802.5 with preserved FCS */ +#define BPID_802_5_WITHOUT_FCS 0x0009 /* 802.5 without preserved FCS */ + +#define BPID_FDDI_WITH_FCS 0x0004 /* FDDI with preserved FCS */ +#define BPID_FDDI_WITHOUT_FCS 0x000A /* FDDI without preserved FCS */ + +#define BPID_802_6_WITH_FCS 0x0005 /* 802.6 with preserved FCS */ +#define BPID_802_6_WITHOUT_FCS 0x000B /* 802.6 without preserved FCS */ + +#define BPID_FRAGMENTS 0x000D + +#define BPID_BPDU 0x000E /* 802.1(d) or 802.1(g) BPDUs */ + +#define BPID_SR_BPDU 0x000F /* Source Routing BPDUs */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* bridged_pid.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/camel-persistentdata.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/camel-persistentdata.h new file mode 100644 index 00000000..ef8bfd05 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/camel-persistentdata.h @@ -0,0 +1,127 @@ +/* + * camel-persistentdata.h + * Definitions for lists and hash tables used in wireshark's camel dissector + * for calculation of delays in camel-transactions + * Copyright 2006 Florent Drouin + * + * $Id: camel-persistentdata.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __CAMEL_PERSISTENTDATA_H__ +#define __CAMEL_PERSISTENTDATA_H__ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define NB_CAMELSRT_CATEGORY 9+1 /* Number of type of message */ +/* for example TC_BEGIN with InitalDP, and TC_CONT with RequestReportBCSMEvent + is a category, we want to measure the delay between the two messages */ + +#define CAMELSRT_SESSION 1 + +#define CAMELSRT_VOICE_INITIALDP 2 +#define CAMELSRT_VOICE_ACR1 3 +#define CAMELSRT_VOICE_ACR2 4 +#define CAMELSRT_VOICE_ACR3 5 +#define CAMELSRT_VOICE_DISC 6 + +#define CAMELSRT_GPRS_INITIALDP 7 +#define CAMELSRT_GPRS_REPORT 8 + +#define CAMELSRT_SMS_INITIALDP 9 + +WS_VAR_IMPORT const value_string camelSRTtype_naming[]; + +/* If we have a request message and its response, + (eg: ApplyCharging, ApplyChargingReport) + the frames numbers are stored in this structure */ + +struct camelsrt_category_t { + guint32 req_num; /* frame number request seen */ + guint32 rsp_num; /* frame number response seen */ + nstime_t req_time; /* arrival time of request */ + gboolean responded; /* true, if request has been responded */ +}; + +/* List of stored parameters for a Camel dialogue + All this parameters are linked to the hash table key below (use of Tid) + In case of same Tid reused, the Camel parameters are chained. + The right dialogue will be identified with the arrival time of the InitialDP */ + +struct camelsrt_call_t { + guint32 session_id; /* Identify the session, with an internal number */ + struct tcaphash_context_t * tcap_context; + struct camelsrt_category_t category[NB_CAMELSRT_CATEGORY]; +}; + + +/* The Key for the hash table is the TCAP origine transaction identifier + of the TC_BEGIN containing the InitialDP */ + +struct camelsrt_call_info_key_t { + guint32 SessionIdKey; +}; + +/* Info for a couple of messages (or category) + The request must be available, not duplicated, + and once the corresponding response received, + we can deduce the Delta Time between Request/response */ + +struct camelsrt_msginfo_t { + gboolean request_available; + gboolean is_duplicate; + gboolean is_delta_time; + nstime_t req_time; + nstime_t delta_time; +}; + +/* List of infos to store for the analyse */ + +struct camelsrt_info_t { + guint32 tcap_session_id; + void * tcap_context; + guint8 opcode; /* operation code of message received */ + guint8 bool_msginfo[NB_CAMELSRT_CATEGORY]; /* category for the received message */ + struct camelsrt_msginfo_t msginfo[NB_CAMELSRT_CATEGORY]; +}; + +void camelsrt_init_routine(void); + +struct camelsrt_info_t * camelsrt_razinfo(void); + +void camelsrt_call_matching(tvbuff_t *tvb, + packet_info * pinfo _U_, + proto_tree *tree, + struct camelsrt_info_t * p_camel_info); + +WS_VAR_IMPORT gboolean gcamel_StatSRT; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* camel-persistentdata.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/charsets.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/charsets.h new file mode 100644 index 00000000..ed50cfc3 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/charsets.h @@ -0,0 +1,42 @@ +/* charsets.h + * Routines for handling character sets + * + * $Id: charsets.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef __CHARSETS_H__ +#define __CHARSETS_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#if 0 +void ASCII_to_EBCDIC(guint8 *buf, guint bytes); +guint8 ASCII_to_EBCDIC1(guint8 c); +#endif +void EBCDIC_to_ASCII(guint8 *buf, guint bytes); +guint8 EBCDIC_to_ASCII1(guint8 c); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __CHARSETS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/chdlctypes.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/chdlctypes.h new file mode 100644 index 00000000..374c2d75 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/chdlctypes.h @@ -0,0 +1,40 @@ +/* chdlctypes.h + * Defines Cisco HDLC packet types that aren't just Ethernet types + * + * $Id: chdlctypes.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __CHDLCTYPES_H__ +#define __CHDLCTYPES_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define CHDLCTYPE_FRARP 0x0808 /* Frame Relay ARP */ +#define CHDLCTYPE_BPDU 0x4242 /* IEEE spanning tree protocol */ +#define CHDLCTYPE_OSI 0xfefe /* ISO network-layer protocols */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* chdlctypes.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/circuit.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/circuit.h new file mode 100644 index 00000000..c6fa6762 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/circuit.h @@ -0,0 +1,80 @@ +/* circuit.h + * Routines for building lists of packets that are part of a "circuit" + * + * $Id: circuit.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __CIRCUIT_H__ +#define __CIRCUIT_H__ + +#include "packet.h" /* for circuit dissector type */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * Data structure representing a circuit. + */ +typedef struct circuit_key { + circuit_type ctype; + guint32 circuit_id; +} circuit_key; + +typedef struct circuit { + struct circuit *next; /* pointer to next circuit with given circuit ID */ + guint32 first_frame; /* # of first frame for that circuit */ + guint32 last_frame; /* # of last frame for that circuit */ + guint32 index; /* unique ID for circuit */ + GSList *data_list; /* list of data associated with circuit */ + dissector_handle_t dissector_handle; + /* handle for protocol dissector client associated with circuit */ + guint options; /* wildcard flags */ + circuit_key *key_ptr; /* pointer to the key for this circuit */ +} circuit_t; + +extern void circuit_init(void); + +extern circuit_t *circuit_new(circuit_type ctype, guint32 circuit_id, + guint32 first_frame); + +extern circuit_t *find_circuit(circuit_type ctype, guint32 circuit_id, + guint32 frame); + +extern void close_circuit(circuit_t *circuit, guint32 last_frame); + +extern void circuit_add_proto_data(circuit_t *conv, int proto, + void *proto_data); +extern void *circuit_get_proto_data(circuit_t *conv, int proto); +extern void circuit_delete_proto_data(circuit_t *conv, int proto); + +extern void circuit_set_dissector(circuit_t *circuit, + dissector_handle_t handle); +extern dissector_handle_t circuit_get_dissector(circuit_t *circuit); +extern gboolean +try_circuit_dissector(circuit_type ctype, guint32 circuit_id, guint32 frame, + tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* circuit.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/codecs.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/codecs.h new file mode 100644 index 00000000..928ddf34 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/codecs.h @@ -0,0 +1,43 @@ +/* codecs.h + * codecs interface 2007 Tomas Kukosa + * + * $Id: codecs.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _CODECS_H_ +#define _CODECS_H_ + +#include "epan/epan.h" + +struct codec_handle; +typedef struct codec_handle *codec_handle_t; + +typedef void *(*codec_init_fn)(void); +typedef void (*codec_release_fn)(void *context); +typedef int (*codec_decode_fn)(void *context, const void *input, int inputSizeBytes, void *output, int *outputSizeBytes); + +extern void register_codec(const char *name, codec_init_fn init_fn, codec_release_fn release_fn, codec_decode_fn decode_fn); +extern codec_handle_t find_codec(const char *name); +extern void *codec_init(codec_handle_t codec); +extern void codec_release(codec_handle_t codec, void *context); +extern int codec_decode(codec_handle_t codec, void *context, const void *input, int inputSizeBytes, void *output, int *outputSizeBytes); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column-utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column-utils.h new file mode 100644 index 00000000..c85aa5bf --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column-utils.h @@ -0,0 +1,241 @@ +/* column-utils.h + * Definitions for column utility structures and routines + * + * $Id: column-utils.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __COLUMN_UTILS_H__ +#define __COLUMN_UTILS_H__ + +#include + +#include "gnuc_format_check.h" +#include "column_info.h" +#include "packet_info.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** Maximum length of columns (except COL_INFO). + * Internal, don't use this in dissectors! + */ + +#define COL_MAX_LEN 256 +/** Maximum length of info columns (COL_INFO only). + * Internal, don't use this in dissectors! + */ +#define COL_MAX_INFO_LEN 4096 + + +/** Allocate all the data structures for constructing column data, given + * the number of columns. + * + * Internal, don't use this in dissectors! + */ +extern void col_setup(column_info *cinfo, gint num_cols); + +/** Initialize the data structures for constructing column data. + * + * Internal, don't use this in dissectors! + */ +extern void col_init(column_info *cinfo); + +/** Set the format of the "variable time format". + * + * Internal, don't use this in dissectors! + */ +extern void col_set_cls_time(frame_data *, column_info *cinfo, gint col); + +/** Fill in all columns of the given packet. + * + * Internal, don't use this in dissectors! + */ +extern void col_fill_in(packet_info *pinfo); + +/* Utility routines used by packet*.c */ + +/** Are the columns writable? + * + * @param cinfo the current packet row + * @return TRUE if it's writable, FALSE if not + */ +extern gboolean col_get_writable(column_info *cinfo); + +/** Set the columns writable. + * + * @param cinfo the current packet row + * @param writable TRUE if it's writable, FALSE if not + */ +extern void col_set_writable(column_info *cinfo, gboolean writable); + +/** Check if the given column be filled with data. + * + * @param cinfo the current packet row + * @param col the column to use, e.g. COL_INFO + */ +extern gint check_col(column_info *cinfo, gint col); + +/** Sets a fence for the current column content, + * so this content won't be affected by further col_... function calls. + * + * This can be useful if a protocol is more than once in a single packet, + * e.g. multiple HTTP calls in a single TCP packet. + * + * @param cinfo the current packet row + * @param col the column to use, e.g. COL_INFO + */ +extern void col_set_fence(column_info *cinfo, gint col); + +/** Clears the text of a column element. + * + * @param cinfo the current packet row + * @param col the column to use, e.g. COL_INFO + */ +extern void col_clear(column_info *cinfo, gint col); + +/** Set (replace) the text of a column element, the text won't be copied. + * + * Usually used to set const strings! + * + * @param cinfo the current packet row + * @param col the column to use, e.g. COL_INFO + * @param str the string to set + */ +extern void col_set_str(column_info *cinfo, gint col, const gchar * str); + +/** Add (replace) the text of a column element, the text will be copied. + * + * @param cinfo the current packet row + * @param col the column to use, e.g. COL_INFO + * @param str the string to add + */ +extern void col_add_str(column_info *cinfo, gint col, const gchar *str); + +/** Add (replace) the text of a column element, the text will be formatted and copied. + * + * Same function as col_add_str() but using a printf-like format string. + * + * @param cinfo the current packet row + * @param col the column to use, e.g. COL_INFO + * @param format the format string + * @param ... the variable number of parameters + */ +extern void col_add_fstr(column_info *cinfo, gint col, const gchar *format, ...) + GNUC_FORMAT_CHECK(printf, 3, 4); + +/* For internal Wireshark use only. Not to be called from dissectors. */ +void col_custom_set_fstr(header_field_info *hfinfo, const gchar *format, ...) + GNUC_FORMAT_CHECK(printf, 2, 3); + +/* For internal Wireshark use only. Not to be called from dissectors. */ +void col_custom_prime_edt(epan_dissect_t *edt, column_info *cinfo); + +/* For internal Wireshark use only. Not to be called from dissectors. */ +gboolean have_custom_cols(column_info *cinfo); + +/** Append the given text to a column element, the text will be copied. + * + * @param cinfo the current packet row + * @param col the column to use, e.g. COL_INFO + * @param str the string to append + */ +extern void col_append_str(column_info *cinfo, gint col, const gchar *str); + +/** Append the given text to a column element, the text will be formatted and copied. + * + * Same function as col_append_str() but using a printf-like format string. + * + * @param cinfo the current packet row + * @param col the column to use, e.g. COL_INFO + * @param format the format string + * @param ... the variable number of parameters + */ +extern void col_append_fstr(column_info *cinfo, gint col, const gchar *format, ...) + GNUC_FORMAT_CHECK(printf, 3, 4); + +/** Prepend the given text to a column element, the text will be formatted and copied. + * + * @param cinfo the current packet row + * @param col the column to use, e.g. COL_INFO + * @param format the format string + * @param ... the variable number of parameters + */ +extern void col_prepend_fstr(column_info *cinfo, gint col, const gchar *format, ...) + GNUC_FORMAT_CHECK(printf, 3, 4); + +/**Prepend the given text to a column element, the text will be formatted and copied. + * This function is similar to col_prepend_fstr() but this function will + * unconditionally set a fence to the end of the prepended data even if there + * were no fence before. + * The col_prepend_fstr() will only prepend the data before the fence IFF + * there is already a fence created. This function will create a fence in case + * it does not yet exist. + */ +extern void col_prepend_fence_fstr(column_info *cinfo, gint col, const gchar *format, ...) + GNUC_FORMAT_CHECK(printf, 3, 4); + +/** Append the given text (prepended by a separator) to a column element. + * + * Much like col_append_str() but will prepend the given separator if the column isn't empty. + * + * @param cinfo the current packet row + * @param col the column to use, e.g. COL_INFO + * @param sep the separator string or NULL for default: ", " + * @param str the string to append + */ +extern void col_append_sep_str(column_info *cinfo, gint col, const gchar *sep, + const gchar *str); + +/** Append the given text (prepended by a separator) to a column element. + * + * Much like col_append_fstr() but will prepend the given separator if the column isn't empty. + * + * @param cinfo the current packet row + * @param col the column to use, e.g. COL_INFO + * @param sep the separator string or NULL for default: ", " + * @param format the format string + * @param ... the variable number of parameters + */ +extern void col_append_sep_fstr(column_info *cinfo, gint col, const gchar *sep, + const gchar *format, ...) + GNUC_FORMAT_CHECK(printf, 4, 5); + +/** Set the given (relative) time to a column element. + * + * Used by multiple dissectors to set the time in the columns + * COL_REL_CONV_TIME and COL_DELTA_CONV_TIME + * + * @param cinfo the current packet row + * @param col the column to use, e.g. COL_INFO + * @param ts the time to set in the column + * @param fieldname the fieldname to use for creating a filter (when + * applying/preparing/copying as filter) + */ +extern void col_set_time(column_info *cinfo, int col, + nstime_t *ts, char *fieldname); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __COLUMN_UTILS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column.h new file mode 100644 index 00000000..90fa3296 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column.h @@ -0,0 +1,56 @@ +/* column.h + * Definitions for column handling routines + * + * $Id: column.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __COLUMN_H__ +#define __COLUMN_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct _fmt_data { + gchar *title; + gchar *fmt; + gchar *custom_field; +} fmt_data; + +const gchar *col_format_to_string(gint); +const gchar *col_format_desc(gint); +gint get_column_format(gint); +void get_column_format_matches(gboolean *, gint); +gint get_column_format_from_str(gchar *); +gchar *get_column_title(gint); +gchar *get_column_custom_field(gint); +const gchar *get_column_width_string(gint, gint); +const char *get_column_longest_string(gint); +gint get_column_char_width(gint format); + +void +build_column_format_array(capture_file *cfile, gboolean reset_fences); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* column.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column_info.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column_info.h new file mode 100644 index 00000000..5f70573f --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column_info.h @@ -0,0 +1,134 @@ +/* column.h + * Definitions for column structures and routines + * + * $Id: column_info.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __COLUMN_INFO_H__ +#define __COLUMN_INFO_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define COL_MAX_LEN 256 +#define COL_MAX_INFO_LEN 4096 + +typedef struct { + gchar **col_expr; /* Filter expression */ + gchar **col_expr_val; /* Value for filter expression */ +} col_expr_t; + +typedef struct _column_info { + gint num_cols; /* Number of columns */ + gint *col_fmt; /* Format of column */ + gboolean **fmt_matx; /* Specifies which formats apply to a column */ + gint *col_first; /* First column number with a given format */ + gint *col_last; /* Last column number with a given format */ + gchar **col_title; /* Column titles */ + gchar **col_custom_field; /* Custom column field */ + const gchar **col_data; /* Column data */ + gchar **col_buf; /* Buffer into which to copy data for column */ + int *col_fence; /* Stuff in column buffer before this index is immutable */ + col_expr_t col_expr; /* Column expressions and values */ + gboolean writable; /* Are we still writing to the columns? */ + gboolean columns_changed; /* Have the columns been changed in the prefs? */ +} column_info; + +/* + * All of the possible columns in summary listing. + * + * NOTE1: The entries MUST remain in this order, or else you need to reorder + * the slist[] and dlist[] arrays in column.c to match! + * + * NOTE2: Please add the COL_XYZ entry in the appropriate spot, such that the + * dlist[] array remains in alphabetical order! + */ +enum { + COL_8021Q_VLAN_ID, /* 0) 802.1Q vlan ID */ + COL_ABS_DATE_TIME, /* 1) Absolute date and time */ + COL_ABS_TIME, /* 2) Absolute time */ + COL_CIRCUIT_ID, /* 3) Circuit ID */ + COL_DSTIDX, /* 4) Dst port idx - Cisco MDS-specific */ + COL_SRCIDX, /* 5) Src port idx - Cisco MDS-specific */ + COL_VSAN, /* 6) VSAN - Cisco MDS-specific */ + COL_CUMULATIVE_BYTES, /* 7) Cumulative number of bytes */ + COL_CUSTOM, /* 8) Custom column (any filter name's contents) */ + COL_DCE_CALL, /* 9) DCE/RPC connection oriented call id OR datagram sequence number */ + COL_DCE_CTX, /* 10) DCE/RPC connection oriented context id */ + COL_DELTA_TIME, /* 11) Delta time */ + COL_DELTA_CONV_TIME,/* 12) Delta time to last frame in conversation */ + COL_DELTA_TIME_DIS, /* 13) Delta time displayed*/ + COL_RES_DST, /* 14) Resolved dest */ + COL_UNRES_DST, /* 15) Unresolved dest */ + COL_RES_DST_PORT, /* 16) Resolved dest port */ + COL_UNRES_DST_PORT, /* 17) Unresolved dest port */ + COL_DEF_DST, /* 18) Destination address */ + COL_DEF_DST_PORT, /* 19) Destination port */ + COL_EXPERT, /* 20) Expert Info */ + COL_IF_DIR, /* 21) FW-1 monitor interface/direction */ + COL_OXID, /* 22) Fibre Channel OXID */ + COL_RXID, /* 23) Fibre Channel RXID */ + COL_FR_DLCI, /* 24) Frame Relay DLCI */ + COL_FREQ_CHAN, /* 25) IEEE 802.11 (and WiMax?) - Channel */ + COL_BSSGP_TLLI, /* 26) GPRS BSSGP IE TLLI */ + COL_HPUX_DEVID, /* 27) HP-UX Nettl Device ID */ + COL_HPUX_SUBSYS, /* 28) HP-UX Nettl Subsystem */ + COL_DEF_DL_DST, /* 29) Data link layer dest address */ + COL_DEF_DL_SRC, /* 30) Data link layer source address */ + COL_RES_DL_DST, /* 31) Resolved DL dest */ + COL_UNRES_DL_DST, /* 32) Unresolved DL dest */ + COL_RES_DL_SRC, /* 33) Resolved DL source */ + COL_UNRES_DL_SRC, /* 34) Unresolved DL source */ + COL_RSSI, /* 35) IEEE 802.11 - received signal strength */ + COL_TX_RATE, /* 36) IEEE 802.11 - TX rate in Mbps */ + COL_DSCP_VALUE, /* 37) IP DSCP Value */ + COL_INFO, /* 38) Description */ + COL_COS_VALUE, /* 39) L2 COS Value */ + COL_RES_NET_DST, /* 40) Resolved net dest */ + COL_UNRES_NET_DST, /* 41) Unresolved net dest */ + COL_RES_NET_SRC, /* 42) Resolved net source */ + COL_UNRES_NET_SRC, /* 43) Unresolved net source */ + COL_DEF_NET_DST, /* 44) Network layer dest address */ + COL_DEF_NET_SRC, /* 45) Network layer source address */ + COL_NUMBER, /* 46) Packet list item number */ + COL_PACKET_LENGTH, /* 47) Packet length in bytes */ + COL_PROTOCOL, /* 48) Protocol */ + COL_REL_TIME, /* 49) Relative time */ + COL_REL_CONV_TIME, /* 50) Relative time to beginning of conversation */ + COL_DEF_SRC, /* 51) Source address */ + COL_DEF_SRC_PORT, /* 52) Source port */ + COL_RES_SRC, /* 53) Resolved source */ + COL_UNRES_SRC, /* 54) Unresolved source */ + COL_RES_SRC_PORT, /* 55) Resolved source port */ + COL_UNRES_SRC_PORT, /* 56) Unresolved source port */ + COL_TEI, /* 57) Q.921 TEI */ + COL_CLS_TIME, /* 58) Command line-specified time (default relative) */ + NUM_COL_FMTS /* 59) Should always be last */ +}; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __COLUMN_INFO_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/conversation.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/conversation.h new file mode 100644 index 00000000..988ae94b --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/conversation.h @@ -0,0 +1,109 @@ +/* conversation.h + * Routines for building lists of packets that are part of a "conversation" + * + * $Id: conversation.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __CONVERSATION_H__ +#define __CONVERSATION_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * Flags to pass to "conversation_new()" to indicate that the address 2 + * and/or port 2 values for the conversation should be wildcards. + * The CONVERSATION_TEMPLATE option tells that any of the other supplied + * port and / or address wildcards will be used to match an infinite number + * of new connections to the conversation(s) that have the CONVERSATION_- + * TEMPLATE flag set. Any conversation created without the CONVERSATION_- + * TEMPLATE flag will be altered once the first connections (connection + * oriented protocols only) to include the newly found information which + * matched the wildcard options. + */ +#define NO_ADDR2 0x01 +#define NO_PORT2 0x02 +#define NO_PORT2_FORCE 0x04 +#define CONVERSATION_TEMPLATE 0x08 + +/* + * Flags to pass to "find_conversation()" to indicate that the address B + * and/or port B search arguments are wildcards. + */ +#define NO_ADDR_B 0x01 +#define NO_PORT_B 0x02 + +#include "packet.h" /* for conversation dissector type */ + +/* + * Data structure representing a conversation. + */ +typedef struct conversation_key { + struct conversation_key *next; + address addr1; + address addr2; + port_type ptype; + guint32 port1; + guint32 port2; +} conversation_key; + +typedef struct conversation { + struct conversation *next; /* pointer to next conversation on hash chain */ + guint32 index; /* unique ID for conversation */ + guint32 setup_frame; /* frame number that setup this conversation */ + GSList *data_list; /* list of data associated with conversation */ + dissector_handle_t dissector_handle; + /* handle for protocol dissector client associated with conversation */ + guint options; /* wildcard flags */ + conversation_key *key_ptr; /* pointer to the key for this conversation */ +} conversation_t; + +extern void conversation_init(void); + +extern conversation_t *conversation_new(guint32 setup_frame, address *addr1, address *addr2, + port_type ptype, guint32 port1, guint32 port2, guint options); + +extern conversation_t *find_conversation(guint32 frame_num, address *addr_a, address *addr_b, + port_type ptype, guint32 port_a, guint32 port_b, guint options); + +extern void conversation_add_proto_data(conversation_t *conv, int proto, + void *proto_data); +extern void *conversation_get_proto_data(conversation_t *conv, int proto); +extern void conversation_delete_proto_data(conversation_t *conv, int proto); + +extern void conversation_set_dissector(conversation_t *conversation, + dissector_handle_t handle); +extern gboolean +try_conversation_dissector(address *addr_a, address *addr_b, port_type ptype, + guint32 port_a, guint32 port_b, tvbuff_t *tvb, packet_info *pinfo, + proto_tree *tree); + +/* These routines are used to set undefined values for a conversation */ + +extern void conversation_set_port2(conversation_t *conv, guint32 port); +extern void conversation_set_addr2(conversation_t *conv, address *addr); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* conversation.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc10.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc10.h new file mode 100644 index 00000000..90e8cbc6 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc10.h @@ -0,0 +1,27 @@ +/* + * crc10.h + * + * $Id: crc10.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* update the data block's CRC-10 remainder one byte at a time */ +extern guint16 update_crc10_by_bytes(guint16 crc10, const guint8 *data_blk_ptr, int data_blk_size); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc16.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc16.h new file mode 100644 index 00000000..445b9430 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc16.h @@ -0,0 +1,109 @@ +/* crc16.h + * Declaration of CRC-16 routines and table + * + * 2004 Richard van der Hoff + * + * $Id: crc16.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * Copied from README.developer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __CRC16_H_ +#define __CRC16_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Calculate the CCITT/ITU/CRC-16 16-bit CRC + + (parameters for this CRC are: + Polynomial: x^16 + x^12 + x^5 + 1 (0x1021); + Start value 0xFFFF; + XOR result with 0xFFFF; + First bit is LSB) +*/ + +/** Compute CRC16 CCITT checksum of a buffer of data. + @param buf The buffer containing the data. + @param len The number of bytes to include in the computation. + @return The CRC16 CCITT checksum. */ +extern guint16 crc16_ccitt(const guint8 *buf, guint len); + +/** Compute CRC16 X.25 CCITT checksum of a buffer of data. + @param buf The buffer containing the data. + @param len The number of bytes to include in the computation. + @return The CRC16 X.25 CCITT checksum. */ +extern guint16 crc16_x25_ccitt(const guint8 *buf, guint len); + +/** Compute CRC16 CCITT checksum of a buffer of data. If computing the + * checksum over multiple buffers and you want to feed the partial CRC16 + * back in, remember to take the 1's complement of the partial CRC16 first. + @param buf The buffer containing the data. + @param len The number of bytes to include in the computation. + @param seed The seed to use. + @return The CRC16 CCITT checksum (using the given seed). */ +extern guint16 crc16_ccitt_seed(const guint8 *buf, guint len, guint16 seed); + +/** Compute CRC16 CCITT checksum of a tv buffer. + @param tvb The tv buffer containing the data. + @param len The number of bytes to include in the computation. + @return The CRC16 CCITT checksum. */ +extern guint16 crc16_ccitt_tvb(tvbuff_t *tvb, guint len); + +/** Compute CRC16 X.25 CCITT checksum of a tv buffer. + @param tvb The tv buffer containing the data. + @param len The number of bytes to include in the computation. + @return The CRC16 X.25 CCITT checksum. */ +extern guint16 crc16_x25_ccitt_tvb(tvbuff_t *tvb, guint len); + +/** Compute CRC16 CCITT checksum of a tv buffer. + @param tvb The tv buffer containing the data. + @param offset The offset into the tv buffer. + @param len The number of bytes to include in the computation. + @return The CRC16 CCITT checksum. */ +extern guint16 crc16_ccitt_tvb_offset(tvbuff_t *tvb, guint offset, guint len); + +/** Compute CRC16 CCITT checksum of a tv buffer. If computing the + * checksum over multiple tv buffers and you want to feed the partial CRC16 + * back in, remember to take the 1's complement of the partial CRC16 first. + @param tvb The tv buffer containing the data. + @param len The number of bytes to include in the computation. + @param seed The seed to use. + @return The CRC16 CCITT checksum (using the given seed). */ +extern guint16 crc16_ccitt_tvb_seed(tvbuff_t *tvb, guint len, guint16 seed); + +/** Compute CRC16 CCITT checksum of a tv buffer. If computing the + * checksum over multiple tv buffers and you want to feed the partial CRC16 + * back in, remember to take the 1's complement of the partial CRC16 first. + @param tvb The tv buffer containing the data. + @param offset The offset into the tv buffer. + @param len The number of bytes to include in the computation. + @param seed The seed to use. + @return The CRC16 CCITT checksum (using the given seed). */ +extern guint16 crc16_ccitt_tvb_offset_seed(tvbuff_t *tvb, guint offset, + guint len, guint16 seed); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* crc16.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc32.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc32.h new file mode 100644 index 00000000..72f4abbe --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc32.h @@ -0,0 +1,94 @@ +/* crc32.h + * Declaration of CRC-32 routine and table + * + * $Id: crc32.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * Copied from README.developer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __CRC32_H_ +#define __CRC32_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +extern const guint32 crc32_ccitt_table[256]; + +/** Compute CRC32 CCITT checksum of a buffer of data. + @param buf The buffer containing the data. + @param len The number of bytes to include in the computation. + @return The CRC32 CCITT checksum. */ +extern guint32 crc32_ccitt(const guint8 *buf, guint len); + +/** Compute CRC32 CCITT checksum of a buffer of data. If computing the + * checksum over multiple buffers and you want to feed the partial CRC32 + * back in, remember to take the 1's complement of the partial CRC32 first. + @param buf The buffer containing the data. + @param len The number of bytes to include in the computation. + @param seed The seed to use. + @return The CRC32 CCITT checksum (using the given seed). */ +extern guint32 crc32_ccitt_seed(const guint8 *buf, guint len, guint32 seed); + +/** Compute CRC32 CCITT checksum of a tv buffer. + @param tvb The tv buffer containing the data. + @param len The number of bytes to include in the computation. + @return The CRC32 CCITT checksum. */ +extern guint32 crc32_ccitt_tvb(tvbuff_t *tvb, guint len); + +/** Compute CRC32 CCITT checksum of a tv buffer. + @param tvb The tv buffer containing the data. + @param offset The offset into the tv buffer. + @param len The number of bytes to include in the computation. + @return The CRC32 CCITT checksum. */ +extern guint32 crc32_ccitt_tvb_offset(tvbuff_t *tvb, guint offset, guint len); + +/** Compute CRC32 CCITT checksum of a tv buffer. If computing the + * checksum over multiple tv buffers and you want to feed the partial CRC32 + * back in, remember to take the 1's complement of the partial CRC32 first. + @param tvb The tv buffer containing the data. + @param len The number of bytes to include in the computation. + @param seed The seed to use. + @return The CRC32 CCITT checksum (using the given seed). */ +extern guint32 crc32_ccitt_tvb_seed(tvbuff_t *tvb, guint len, guint32 seed); + +/** Compute CRC32 CCITT checksum of a tv buffer. If computing the + * checksum over multiple tv buffers and you want to feed the partial CRC32 + * back in, remember to take the 1's complement of the partial CRC32 first. + @param tvb The tv buffer containing the data. + @param offset The offset into the tv buffer. + @param len The number of bytes to include in the computation. + @param seed The seed to use. + @return The CRC32 CCITT checksum (using the given seed). */ +extern guint32 crc32_ccitt_tvb_offset_seed(tvbuff_t *tvb, guint offset, + guint len, guint32 seed); + +/** Compute IEEE 802.x CRC32 checksum of a tv buffer. + @param tvb The tv buffer containing the data. + @param len The number of bytes to include in the computation. + @return The IEEE 802.x CRC32 checksum. */ +extern guint32 crc32_802_tvb(tvbuff_t *tvb, guint len); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* crc32.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc6.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc6.h new file mode 100644 index 00000000..cb295faa --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc6.h @@ -0,0 +1,26 @@ +/* + * crc6.h + * + * $Id: crc6.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +extern guint16 update_crc6_by_bytes(guint16 crc6, guint8 byte1, guint8 byte2); + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crcdrm.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crcdrm.h new file mode 100644 index 00000000..0987f50f --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crcdrm.h @@ -0,0 +1,7 @@ +#ifndef _CRCDRM_H + +#include + +unsigned long crc_drm(const char *data, size_t bytesize, + unsigned short num_crc_bits, unsigned long crc_gen, int invert); +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_debug.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_debug.h new file mode 100644 index 00000000..849c6662 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_debug.h @@ -0,0 +1,106 @@ +/* airpcap_debug.h + * + * $Id: airpdcap_debug.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Copyright (c) 2006 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _AIRPDCAP_DEBUG_H +#define _AIRPDCAP_DEBUG_H + +#include "airpdcap_interop.h" + +void print_debug_line(CHAR *function, CHAR *msg, INT level); + +#ifdef _DEBUG +#ifdef __FUNCTION__ +#define AIRPDCAP_DEBUG_PRINT_LINE(notdefined, msg, level) print_debug_line(__FUNCTION__, msg, level); +#else +#define AIRPDCAP_DEBUG_PRINT_LINE(function, msg, level) print_debug_line(function, msg, level); +#endif +#else +#ifdef __FUNCTION__ +#define AIRPDCAP_DEBUG_PRINT_LINE(notdefined, msg, level) +#else +#define AIRPDCAP_DEBUG_PRINT_LINE(function, msg, level) +#endif +#endif + +/******************************************************************************/ +/* Debug section: internal function to print debug information */ +/* */ +#ifdef _DEBUG +#include "stdio.h" +#include + +/* Debug level definition */ +#define AIRPDCAP_DEBUG_LEVEL_1 1 +#define AIRPDCAP_DEBUG_LEVEL_2 2 +#define AIRPDCAP_DEBUG_LEVEL_3 3 +#define AIRPDCAP_DEBUG_LEVEL_4 4 +#define AIRPDCAP_DEBUG_LEVEL_5 5 + +#define AIRPDCAP_DEBUG_USED_LEVEL AIRPDCAP_DEBUG_LEVEL_3 + +#ifdef _TRACE +#ifdef __FUNCTION__ +#define AIRPDCAP_DEBUG_TRACE_START(notdefined) print_debug_line(__FUNCTION__, "Start!", AIRPDCAP_DEBUG_USED_LEVEL); +#define AIRPDCAP_DEBUG_TRACE_END(notdefined) print_debug_line(__FUNCTION__, "End!", AIRPDCAP_DEBUG_USED_LEVEL); +#else +#define AIRPDCAP_DEBUG_TRACE_START(function) print_debug_line(function, "Start!", AIRPDCAP_DEBUG_USED_LEVEL); +#define AIRPDCAP_DEBUG_TRACE_END(function) print_debug_line(function, "End!", AIRPDCAP_DEBUG_USED_LEVEL); +#endif +#else +#ifdef __FUNCTION__ +#define AIRPDCAP_DEBUG_TRACE_START(notdefined) +#define AIRPDCAP_DEBUG_TRACE_END(notdefined) +#else +#define AIRPDCAP_DEBUG_TRACE_START(function) +#define AIRPDCAP_DEBUG_TRACE_END(function) +#endif +#endif + +#else /* !defined _DEBUG */ + +#define AIRPDCAP_DEBUG_LEVEL_1 +#define AIRPDCAP_DEBUG_LEVEL_2 +#define AIRPDCAP_DEBUG_LEVEL_3 +#define AIRPDCAP_DEBUG_LEVEL_4 +#define AIRPDCAP_DEBUG_LEVEL_5 + +#define AIRPDCAP_DEBUG_TRACE_START(function) +#define AIRPDCAP_DEBUG_TRACE_END(function) + +#endif /* ?defined _DEBUG */ + + +#endif /* ?defined _AIRPDCAP_DEBUG_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_int.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_int.h new file mode 100644 index 00000000..b3d4a75b --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_int.h @@ -0,0 +1,158 @@ +/* airpcap_int.h + * + * $Id: airpdcap_int.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Copyright (c) 2006 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _AIRPDCAP_INT_H +#define _AIRPDCAP_INT_H + +/****************************************************************************/ +/* File includes */ + +#include "airpdcap_interop.h" + +/****************************************************************************/ + +/****************************************************************************/ +/* Definitions */ + +/* IEEE 802.11 packet type values */ +#define AIRPDCAP_TYPE_MANAGEMENT 0 +#define AIRPDCAP_TYPE_CONTROL 1 +#define AIRPDCAP_TYPE_DATA 2 + +/* Min length of encrypted data (TKIP=25bytes, CCMP=21bytes) */ +#define AIRPDCAP_CRYPTED_DATA_MINLEN 21 + +#define AIRPDCAP_TA_OFFSET 10 + +/* */ +/****************************************************************************/ + +/****************************************************************************/ +/* Macro definitions */ + +/** + * Macros to get various bits of a 802.11 control frame + */ +#define AIRPDCAP_TYPE(FrameControl_0) (UINT8)((FrameControl_0 >> 2) & 0x3) +#define AIRPDCAP_SUBTYPE(FrameControl_0) (UINT8)((FrameControl_0 >> 4) & 0xF) +#define AIRPDCAP_DS_BITS(FrameControl_1) (UINT8)(FrameControl_1 & 0x3) +#define AIRPDCAP_TO_DS(FrameControl_1) (UINT8)(FrameControl_1 & 0x1) +#define AIRPDCAP_FROM_DS(FrameControl_1) (UINT8)((FrameControl_1 >> 1) & 0x1) +#define AIRPDCAP_WEP(FrameControl_1) (UINT8)((FrameControl_1 >> 6) & 0x1) + +/** + * Get the Key ID from the Initialization Vector (last byte) + */ +#define AIRPDCAP_EXTIV(KeyID) ((KeyID >> 5) & 0x1) + +/* Macros to get various bits of an EAPOL frame */ +#define AIRPDCAP_EAP_KEY_DESCR_VER(KeyInfo_1) ((UCHAR)(KeyInfo_1 & 0x3)) +#define AIRPDCAP_EAP_KEY(KeyInfo_1) ((KeyInfo_1 >> 3) & 0x1) +#define AIRPDCAP_EAP_INST(KeyInfo_1) ((KeyInfo_1 >> 6) & 0x1) +#define AIRPDCAP_EAP_ACK(KeyInfo_1) ((KeyInfo_1 >> 7) & 0x1) +#define AIRPDCAP_EAP_MIC(KeyInfo_0) (KeyInfo_0 & 0x1) +#define AIRPDCAP_EAP_SEC(KeyInfo_0) ((KeyInfo_0 >> 1) & 0x1) + +/* Note: copied from net80211/ieee80211_airpdcap_tkip.c */ +#define S_SWAP(a,b) { UINT8 t = S[a]; S[a] = S[b]; S[b] = t; } + +/****************************************************************************/ + +/****************************************************************************/ +/* Structure definitions */ + +/* + * XXX - According to the thread at + * http://www.wireshark.org/lists/wireshark-dev/200612/msg00384.html we + * shouldn't have to worry about packing our structs, since the largest + * elements are 8 bits wide. + */ +#ifdef _MSC_VER /* MS Visual C++ */ +#pragma pack(push) +#pragma pack(1) +#endif + +/* Definition of IEEE 802.11 frame (without the address 4) */ +typedef struct _AIRPDCAP_MAC_FRAME { + UCHAR fc[2]; + UCHAR dur[2]; + UCHAR addr1[AIRPDCAP_MAC_LEN]; + UCHAR addr2[AIRPDCAP_MAC_LEN]; + UCHAR addr3[AIRPDCAP_MAC_LEN]; + UCHAR seq[2]; +} AIRPDCAP_MAC_FRAME, *PAIRPDCAP_MAC_FRAME; + +/* Definition of IEEE 802.11 frame (with the address 4) */ +typedef struct _AIRPDCAP_MAC_FRAME_ADDR4 { + UCHAR fc[2]; + UCHAR dur[2]; + UCHAR addr1[AIRPDCAP_MAC_LEN]; + UCHAR addr2[AIRPDCAP_MAC_LEN]; + UCHAR addr3[AIRPDCAP_MAC_LEN]; + UCHAR seq[2]; + UCHAR addr4[AIRPDCAP_MAC_LEN]; +} AIRPDCAP_MAC_FRAME_ADDR4, *PAIRPDCAP_MAC_FRAME_ADDR4; + +/* Definition of IEEE 802.11 frame (without the address 4, with QOS) */ +typedef struct _AIRPDCAP_MAC_FRAME_QOS { + UCHAR fc[2]; + UCHAR dur[2]; + UCHAR addr1[AIRPDCAP_MAC_LEN]; + UCHAR addr2[AIRPDCAP_MAC_LEN]; + UCHAR addr3[AIRPDCAP_MAC_LEN]; + UCHAR seq[2]; + UCHAR qos[2]; +} AIRPDCAP_MAC_FRAME_QOS, *PAIRPDCAP_MAC_FRAME_QOS; + +/* Definition of IEEE 802.11 frame (with the address 4 and QOS) */ +typedef struct _AIRPDCAP_MAC_FRAME_ADDR4_QOS { + UCHAR fc[2]; + UCHAR dur[2]; + UCHAR addr1[AIRPDCAP_MAC_LEN]; + UCHAR addr2[AIRPDCAP_MAC_LEN]; + UCHAR addr3[AIRPDCAP_MAC_LEN]; + UCHAR seq[2]; + UCHAR addr4[AIRPDCAP_MAC_LEN]; + UCHAR qos[2]; +} AIRPDCAP_MAC_FRAME_ADDR4_QOS, *PAIRPDCAP_MAC_FRAME_ADDR4_QOS; + +#ifdef _MSC_VER /* MS Visual C++ */ +#pragma pack(pop) +#endif + +/******************************************************************************/ + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_interop.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_interop.h new file mode 100644 index 00000000..9d693fb9 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_interop.h @@ -0,0 +1,101 @@ +/* airpdcap_interop.h + * + * $Id: airpdcap_interop.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Copyright (c) 2006 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _AIRPDCAP_INTEROP_H +#define _AIRPDCAP_INTEROP_H + +/** + * Cast data types commonly used (e.g. UINT16) to their + * GLib equivalents. + */ + +#include +#include + +#ifndef INT +typedef gint INT; +#endif + +#ifndef UINT +typedef guint UINT; +#endif + +#ifndef UINT8 +typedef guint8 UINT8; +#endif + +#ifndef UINT16 +typedef guint16 UINT16; +#endif + +#ifndef UINT32 +typedef guint32 UINT32; +#endif + +#ifndef UINT64 +typedef guint64 UINT64; +#endif + +#ifndef USHORT +typedef gushort USHORT; +#endif + +#ifndef ULONG +typedef gulong ULONG; +#endif + +#ifndef ULONGLONG +typedef guint64 ULONGLONG; +#endif + +#ifndef CHAR +typedef gchar CHAR; +#endif + +#ifndef UCHAR +typedef guchar UCHAR; +#endif + +#ifdef _WIN32 +#include /* ntohs() */ +#endif + +#ifndef ntohs +#undef ntohs +#define ntohs(value) g_ntohs(value) +#endif + +#endif /* _AIRPDCAP_INTEROP_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_rijndael.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_rijndael.h new file mode 100644 index 00000000..b031d790 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_rijndael.h @@ -0,0 +1,93 @@ +/** + * airpdcap_rijndael.h + * + * $Id: airpdcap_rijndael.h 3992 2008-06-10 03:13:11Z dgu $ + * + * @version 3.0 (December 2000) + * + * Optimised ANSI C code for the Rijndael cipher (now AES) + * + * @author Vincent Rijmen + * @author Antoon Bosselaers + * @author Paulo Barreto + * + * This code is hereby placed in the public domain. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _AIRPDCAP_RIJNDAEL +#define _AIRPDCAP_RIJNDAEL + +/******************************************************************************/ +/* File includes */ +/* */ +#include "airpdcap_interop.h" +/* */ +/* */ +/******************************************************************************/ + +/******************************************************************************/ +/* Definitions */ +/* */ +/* Note: copied AirPDcap/rijndael/rijndael.h */ +#define RIJNDAEL_MAXKC (256/32) +#define RIJNDAEL_MAXKB (256/8) +#define RIJNDAEL_MAXNR 14 +/* */ +/******************************************************************************/ + +/******************************************************************************/ +/* Type definitions */ +/* */ +/* Note: copied AirPDcap/rijndael/rijndael.h */ +typedef struct s_rijndael_ctx { + INT decrypt; + INT Nr; /* key-length-dependent number of rounds */ + UINT32 ek[4 * (RIJNDAEL_MAXNR + 1)]; /* encrypt key schedule */ + UINT32 dk[4 * (RIJNDAEL_MAXNR + 1)]; /* decrypt key schedule */ +} rijndael_ctx; +/* */ +/******************************************************************************/ + +/******************************************************************************/ +/* External function prototypes declarations */ +/* */ +void rijndael_encrypt( + const rijndael_ctx *ctx, + const UCHAR *src, + UCHAR *dst) + ; + + +void rijndael_set_key( + rijndael_ctx *ctx, + const UCHAR *key, + INT bits) + ; +/* */ +/******************************************************************************/ + +/******************************************************************************/ +/* Block XOR macro definition */ +/* */ +#define XOR_BLOCK(b, a, len) \ + { \ + INT i; \ + for (i = 0; i < (INT)(len); i++) \ + (b)[i] ^= (a)[i]; \ + } +/* */ +/******************************************************************************/ + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_system.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_system.h new file mode 100644 index 00000000..392d5d19 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_system.h @@ -0,0 +1,356 @@ +/* airpdcap_system.h + * + * $Id: airpdcap_system.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Copyright (c) 2006 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _AIRPDCAP_SYSTEM_H +#define _AIRPDCAP_SYSTEM_H + +/************************************************************************/ +/* File includes */ + +#include "airpdcap_interop.h" +#include "airpdcap_user.h" + +/************************************************************************/ +/* Constant definitions */ + +/* General definitions */ +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#define AIRPDCAP_RET_SUCCESS 0 +#define AIRPDCAP_RET_UNSUCCESS 1 + +#define AIRPDCAP_RET_NO_DATA 1 +#define AIRPDCAP_RET_WRONG_DATA_SIZE 2 +#define AIRPDCAP_RET_REQ_DATA 3 +#define AIRPDCAP_RET_NO_VALID_HANDSHAKE 4 +#define AIRPDCAP_RET_NO_DATA_ENCRYPTED 5 + +#define AIRPDCAP_RET_SUCCESS_HANDSHAKE -1 + +#define AIRPDCAP_MAX_KEYS_NR 64 +#define AIRPDCAP_MAX_SEC_ASSOCIATIONS_NR 256 + +/* Decryption algorithms fields size definition (bytes) */ +#define AIRPDCAP_WPA_NONCE_LEN 32 +#define AIRPDCAP_WPA_PTK_LEN 64 /* TKIP uses 48 bytes, CCMP uses 64 bytes */ +#define AIRPDCAP_WPA_MICKEY_LEN 16 + +#define AIRPDCAP_WEP_128_KEY_LEN 16 /* 128 bits */ + +/* General 802.11 constants */ +#define AIRPDCAP_MAC_LEN 6 +#define AIRPDCAP_RADIOTAP_HEADER_LEN 24 + +#define AIRPDCAP_EAPOL_MAX_LEN 1024 + +#define AIRPDCAP_TK_LEN 16 + +/* Max length of capture data */ +#define AIRPDCAP_MAX_CAPLEN 8192 + +#define AIRPDCAP_WEP_IVLEN 3 /* 24bit */ +#define AIRPDCAP_WEP_KIDLEN 1 /* 1 octet */ +#define AIRPDCAP_WEP_ICV 4 +#define AIRPDCAP_WEP_HEADER AIRPDCAP_WEP_IVLEN + AIRPDCAP_WEP_KIDLEN +#define AIRPDCAP_WEP_TRAILER AIRPDCAP_WEP_ICV + +/* + * 802.11i defines an extended IV for use with non-WEP ciphers. + * When the EXTIV bit is set in the key id byte an additional + * 4 bytes immediately follow the IV for TKIP. For CCMP the + * EXTIV bit is likewise set but the 8 bytes represent the + * CCMP header rather than IV+extended-IV. + */ +#define AIRPDCAP_RSNA_EXTIV 0x20 +#define AIRPDCAP_RSNA_EXTIVLEN 4 /* extended IV length */ +#define AIRPDCAP_RSNA_MICLEN 8 /* trailing MIC */ + +#define AIRPDCAP_RSNA_HEADER AIRPDCAP_WEP_HEADER + AIRPDCAP_RSNA_EXTIVLEN + +#define AIRPDCAP_CCMP_HEADER AIRPDCAP_RSNA_HEADER +#define AIRPDCAP_CCMP_TRAILER AIRPDCAP_RSNA_MICLEN + +#define AIRPDCAP_TKIP_HEADER AIRPDCAP_RSNA_HEADER +#define AIRPDCAP_TKIP_TRAILER AIRPDCAP_RSNA_MICLEN + AIRPDCAP_WEP_ICV + +#define AIRPDCAP_CRC_LEN 4 + +/************************************************************************/ +/* Macro definitions */ + +/************************************************************************/ +/* Type definitions */ + +typedef struct _AIRPDCAP_SEC_ASSOCIATION_ID { + UCHAR bssid[AIRPDCAP_MAC_LEN]; + UCHAR sta[AIRPDCAP_MAC_LEN]; +} AIRPDCAP_SEC_ASSOCIATION_ID, *PAIRPDCAP_SEC_ASSOCIATION_ID; + +typedef struct _AIRPDCAP_SEC_ASSOCIATION { + /** + * This flag define whether this item is used or not. Accepted + * values are TRUE and FALSE + */ + UINT8 used; + AIRPDCAP_SEC_ASSOCIATION_ID saId; + AIRPDCAP_KEY_ITEM *key; + UINT8 handshake; + UINT8 validKey; + + struct { + UINT8 key_ver; /* Key descriptor version */ + UINT64 pn; /* only used with CCMP AES -if needed replay check- */ + UCHAR nonce[AIRPDCAP_WPA_NONCE_LEN]; + /* used to derive PTK, ANonce stored, SNonce taken */ + /* the 2nd packet of the 4W handshake */ + + UCHAR ptk[AIRPDCAP_WPA_PTK_LEN]; /* session key used in decryption algorithm */ + } wpa; +} AIRPDCAP_SEC_ASSOCIATION, *PAIRPDCAP_SEC_ASSOCIATION; + +typedef struct _AIRPDCAP_CONTEXT { + AIRPDCAP_SEC_ASSOCIATION sa[AIRPDCAP_MAX_SEC_ASSOCIATIONS_NR]; + INT sa_index; + AIRPDCAP_KEY_ITEM keys[AIRPDCAP_MAX_KEYS_NR]; + size_t keys_nr; + + CHAR pkt_ssid[AIRPDCAP_WPA_SSID_MAX_LEN]; + size_t pkt_ssid_len; + + INT index; + INT first_free_index; +} AIRPDCAP_CONTEXT, *PAIRPDCAP_CONTEXT; + +/************************************************************************/ +/* Function prototype declarations */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Given an 802.11 packet, either extract its key data (in the case of + * WPA handshaking) or try to decrypt it. + * @param ctx [IN] Pointer to the current context + * @param data [IN] Pointer to a buffer with an 802.11 frame, including MAC + * header and payload + * @param data_off [IN] Payload offset (aka the MAC header length) + * @param data_len [IN] Total length of the MAC header and the payload + * @param decrypt_data [OUT] Pointer to a buffer that will contain + * decrypted data + * @param decrypt_len [OUT] Length of decrypted data + * @param key [OUT] Pointer to a preallocated key structure containing + * the key used during the decryption process (if done). If this parameter + * is set to NULL, the key will be not returned. + * @param mngHandshake [IN] If TRUE this function will manage the 4-way + * handshake for WPA/WPA2 + * @param mngDecrypt [IN] If TRUE this function will manage the WEP or + * WPA/WPA2 decryption + * @return + * - AIRPDCAP_RET_SUCCESS: Decryption has been done (decrypt_data and + * decrypt_length will contain the packet data decrypted and the length of + * the new packet) + * - AIRPDCAP_RET_SUCCESS_HANDSHAKE: A step of the 4-way handshake for + * WPA key has been successfully done + * - AIRPDCAP_RET_NO_DATA: The packet is not a data packet + * - AIRPDCAP_RET_WRONG_DATA_SIZE: The size of the packet is below the + * accepted minimum + * - AIRPDCAP_RET_REQ_DATA: Required data is not available and the + * processing must be interrupted + * - AIRPDCAP_RET_NO_VALID_HANDSHAKE: The authentication is not for WPA or RSNA + * - AIRPDCAP_RET_NO_DATA_ENCRYPTED: No encrypted data + * - AIRPDCAP_RET_UNSUCCESS: No decryption has been done (decrypt_data + * and decrypt_length will be not modified). + * Some other errors could be: + * data not correct + * data not encrypted + * key handshake, not encryption + * decryption not successful + * key handshake not correct + * replay check not successful + * @note + * The decrypted buffer should be allocated for a size equal or greater + * than the packet data buffer size. Before decryption process original + * data is copied in the buffer pointed by decrypt_data not to modify the + * original packet. + * @note + * The length of decrypted data will consider the entire 802.11 frame + * (thus the MAC header, the frame body and the recalculated FCS -if + * initially present-) + * @note + * This function is not thread-safe when used in parallel with context + * management functions on the same context. + */ +extern INT AirPDcapPacketProcess( + PAIRPDCAP_CONTEXT ctx, + const guint8 *data, + const guint data_off, + const guint data_len, + UCHAR *decrypt_data, + guint32 *decrypt_len, + PAIRPDCAP_KEY_ITEM key, + gboolean mngHandshake, + gboolean mngDecrypt) + ; + +/** + * It sets a new keys collection to use during packet processing. + * Any key should be well-formed, thus: it should have a defined key + * type and the specified length should be conforming WEP or WPA/WPA2 + * standards. A general WEP keys could be of any length (in the range + * defined in AIRPDCAP_KEY_ITEM), if a specific WEP key is used, the + * length of the key will be the one specified in 802.11i-2004 (40 bits or + * 104 bits). + * For WPA/WPA2 the password (passphrase and SSID), the PSK and the PMK + * are in alternative, as explain in the AIRPDCAP_KEY_ITEM structure + * description. + * @param ctx [IN] pointer to the current context + * @param keys [IN] an array of keys to set. + * @param keys_nr [IN] the size of the keys array + * @return The number of keys correctly inserted in the current database. + * @note Before inserting new keys, the current database will be cleaned. + * @note + * This function is not thread-safe when used in parallel with context + * management functions and the packet process function on the same + * context. + */ +extern INT AirPDcapSetKeys( + PAIRPDCAP_CONTEXT ctx, + AIRPDCAP_KEY_ITEM keys[], + const size_t keys_nr) + ; + +/** + * It gets the keys collection fom the specified context. + * @param ctx [IN] pointer to the current context + * @param key [IN] a preallocated array of keys to be returned + * @param keys_nr [IN] the number of keys to return (the key array must + * be able to contain at least keys_nr keys) + * @return The number of keys returned + * @note + * Any key could be modified, as stated in the AIRPDCAP_KEY_ITEM description. + * @note + * This function is not thread-safe when used in parallel with context + * management functions and the packet process function on the same + * context. + */ +INT AirPDcapGetKeys( + const PAIRPDCAP_CONTEXT ctx, + AIRPDCAP_KEY_ITEM keys[], + const size_t keys_nr) + ; + +/** + * Sets the "last seen" SSID. This allows us to pick up previous + * SSIDs and use them when "wildcard" passphrases are specified + * in the preferences. + * @param ctx [IN|OUT] pointer to a preallocated context structure + * @param pkt_ssid [IN] pointer to the packet's SSID + * @param pkt_ssid_len [IN] length of the packet's SSID + * @return + * AIRPDCAP_RET_SUCCESS: The key has been set. + * AIRPDCAP_RET_UNSUCCESS: The has not been set, e.g. the length was + * too long. + */ +INT AirPDcapSetLastSSID( + PAIRPDCAP_CONTEXT ctx, + CHAR *pkt_ssid, + size_t pkt_ssid_len) + ; + +/** + * Initialize a context used to manage decryption and keys collection. + * @param ctx [IN|OUT] pointer to a preallocated context structure + * @return + * AIRPDCAP_RET_SUCCESS: the context has been successfully initialized + * AIRPDCAP_RET_UNSUCCESS: the context has not been initialized + * @note + * Only a correctly initialized context can be used to manage decryption + * processes and keys. + * @note + * This function is not thread-safe when used in parallel with context + * management functions and the packet process function on the same context. + */ +INT AirPDcapInitContext( + PAIRPDCAP_CONTEXT ctx) + ; + +/** + * Clean up the specified context. After the cleanup the pointer should + * not be used anymore. + * @param ctx [IN|OUT] pointer to the current context structure + * @return + * AIRPDCAP_RET_SUCCESS: the context has been successfully initialized + * AIRPDCAP_RET_UNSUCCESS: the context has not been initialized + * @note + * This function is not thread-safe when used in parallel with context + * management functions and the packet process function on the same + * context. + */ +INT AirPDcapDestroyContext( + PAIRPDCAP_CONTEXT ctx) + ; + + +extern INT AirPDcapWepDecrypt( + const UCHAR *seed, + const size_t seed_len, /* max AIRPDCAP_KEYBUF_SIZE */ + UCHAR *cypher_text, + const size_t data_len) + ; +extern INT AirPDcapCcmpDecrypt( + UINT8 *m, + gint mac_header_len, + INT len, + UCHAR TK1[16]) + ; +extern INT AirPDcapTkipDecrypt( + UCHAR *tkip_mpdu, + size_t mpdu_len, + UCHAR TA[AIRPDCAP_MAC_LEN], + UCHAR TK[AIRPDCAP_TK_LEN]) + ; + +#ifdef __cplusplus +} +#endif + +#endif /* _AIRPDCAP_SYSTEM_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_user.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_user.h new file mode 100644 index 00000000..0cf1a5b8 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_user.h @@ -0,0 +1,231 @@ +/* airpdcap_user.h + * + * $Id: airpdcap_user.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Copyright (c) 2006 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _AIRPDCAP_USER_H +#define _AIRPDCAP_USER_H + +/******************************************************************************/ +/* File includes */ +/* */ +#include "airpdcap_interop.h" +/* */ +/* */ +/******************************************************************************/ + +/******************************************************************************/ +/* Constant definitions */ +/* */ +/* Decryption key types */ +#define AIRPDCAP_KEY_TYPE_WEP 0 +#define AIRPDCAP_KEY_TYPE_WEP_40 1 +#define AIRPDCAP_KEY_TYPE_WEP_104 2 +#define AIRPDCAP_KEY_TYPE_WPA_PWD 3 +#define AIRPDCAP_KEY_TYPE_WPA_PSK 4 +#define AIRPDCAP_KEY_TYPE_WPA_PMK 5 +#define AIRPDCAP_KEY_TYPE_TKIP 6 +#define AIRPDCAP_KEY_TYPE_CCMP 7 + +/* Decryption algorithms fields size definition (bytes) */ +#define AIRPDCAP_WEP_KEY_MINLEN 1 +#define AIRPDCAP_WEP_KEY_MAXLEN 32 +#define AIRPDCAP_WEP_40_KEY_LEN 5 +#define AIRPDCAP_WEP_104_KEY_LEN 13 + +#define AIRPDCAP_WPA_PASSPHRASE_MIN_LEN 8 +#define AIRPDCAP_WPA_PASSPHRASE_MAX_LEN 63 /* null-terminated string, the actual length of the storage is 64 */ +#define AIRPDCAP_WPA_SSID_MIN_LEN 0 +#define AIRPDCAP_WPA_SSID_MAX_LEN 32 +#define AIRPDCAP_WPA_PSK_LEN 64 +#define AIRPDCAP_WPA_PMK_LEN 32 +/* */ +/* */ +/******************************************************************************/ + +/******************************************************************************/ +/* Macro definitions */ +/* */ +/* */ +/******************************************************************************/ + +/******************************************************************************/ +/* Type definitions */ +/* */ +/** + * Struct to store info about a specific decryption key. + */ +typedef struct { + GString *key; + GByteArray *ssid; + guint bits; + guint type; +} decryption_key_t; + +/** + * Key item used during the decryption process. + */ +typedef struct _AIRPDCAP_KEY_ITEM { + /** + * Type of key. The type will remain unchanged during the + * processing, even if some fields could be changed (e.g., WPA + * fields). + * @note + * You can use constants AIRPDCAP_KEY_TYPE_xxx to indicate the + * key type. + */ + UINT8 KeyType; + + /** + * Key data. + * This field can be used for the following decryptographic + * algorithms: WEP-40, with a key of 40 bits (10 hex-digits); + * WEP-104, with a key of 104 bits (or 26 hex-digits); WPA or + * WPA2. + * @note + * For WPA/WPA2, the PMK is calculated from the PSK, and the PSK + * is calculated from the passphrase-SSID pair. You can enter one + * of these 3 values and subsequent fields will be automatically + * calculated. + * @note + * For WPA and WPA2 this implementation will use standards as + * defined in 802.11i (2004) and 802.1X (2004). + */ + union AIRPDCAP_KEY_ITEMDATA { + struct AIRPDCAP_KEY_ITEMDATA_WEP { + /** + * The binary value of the WEP key. + * @note + * It is accepted a key of length between + * AIRPDCAP_WEP_KEY_MINLEN and + * AIRPDCAP_WEP_KEY_MAXLEN. A WEP key + * standard-compliante should be either 40 bits + * (10 hex-digits, 5 bytes) for WEP-40 or 104 bits + * (26 hex-digits, 13 bytes) for WEP-104. + */ + UCHAR WepKey[AIRPDCAP_WEP_KEY_MAXLEN]; + /** + * The length of the WEP key. Acceptable range + * is [AIRPDCAP_WEP_KEY_MINLEN;AIRPDCAP_WEP_KEY_MAXLEN]. + */ + size_t WepKeyLen; + } Wep; + + /** + * WPA/WPA2 key data. Note that the decryption process + * will use the PMK (equal to PSK), that is calculated + * from passphrase-SSID pair. You can define one of these + * three fields and necessary fields will be automatically + * calculated. + */ + union AIRPDCAP_KEY_ITEMDATA_WPA { + + UCHAR Psk[AIRPDCAP_WPA_PSK_LEN]; + + UCHAR Pmk[AIRPDCAP_WPA_PMK_LEN]; + } Wpa; + } KeyData; + + struct AIRPDCAP_KEY_ITEMDATA_PWD { + /** + * The string (null-terminated) value of + * the passphrase. + */ + CHAR Passphrase[AIRPDCAP_WPA_PASSPHRASE_MAX_LEN+1]; + /** + * The value of the SSID (up to + * AIRPDCAP_WPA_SSID_MAX_LEN octets). + * @note + * A zero-length SSID indicates broadcast. + */ + CHAR Ssid[AIRPDCAP_WPA_SSID_MAX_LEN]; + /** + *The length of the SSID + */ + size_t SsidLen; + } UserPwd; +} AIRPDCAP_KEY_ITEM, *PAIRPDCAP_KEY_ITEM; + +/** + * Collection of keys to use to decrypt packets + */ +typedef struct _AIRPDCAP_KEYS_COLLECTION { + /** + * Number of stored keys + */ + size_t nKeys; + + /** + * Array of nKeys keys + */ + AIRPDCAP_KEY_ITEM Keys[256]; +} AIRPDCAP_KEYS_COLLECTION, *PAIRPDCAP_KEYS_COLLECTION; +/* */ +/******************************************************************************/ + +/******************************************************************************/ +/* Function prototype declarations */ + +/** + * Returns the decryption_key_t struct given a string describing the key. + * @param key_string [IN] Key string in one of the following formats: + * - 0102030405 (40/64-bit WEP) + * - 01:02:03:04:05 (40/64-bit WEP) + * - 0102030405060708090a0b0c0d (104/128-bit WEP) + * - 01:02:03:04:05:06:07:08:09:0a:0b:0c:0d (104/128-bit WEP) + * - wep:01020304... (WEP) + * - wep:01:02:03:04... (WEP) + * - wpa-pwd:MyPassword (WPA + plaintext password + "wildcard" SSID) + * - wpa-pwd:MyPassword:MySSID (WPA + plaintext password + specific SSID) + * - wpa-psk:01020304... (WPA + 256-bit raw key) + * @return A pointer to a freshly-g_malloc()ed decryption_key_t struct on + * success, or NULL on failure. + * @see get_key_string() + */ +decryption_key_t* +parse_key_string(gchar* key_string); + +/** + * Returns a newly allocated string representing the given decryption_key_t + * struct. + * @param dk [IN] Pointer to the key to be converted + * @return A g_malloc()ed string representation of the key + * @see parse_key_string() + */ +gchar* +get_key_string(decryption_key_t* dk); + +/******************************************************************************/ + +#endif /* _AIRPDCAP_USER_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_ws.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_ws.h new file mode 100644 index 00000000..22cf6e07 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_ws.h @@ -0,0 +1,43 @@ +/* airpdcap_ws.h + * + * $Id: airpdcap_ws.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Copyright (c) 2006 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _AIRPDCAP_WS_H +#define _AIRPDCAP_WS_H + +#include "airpdcap_system.h" +WS_VAR_IMPORT AIRPDCAP_CONTEXT airpdcap_ctx; + +#endif /* _AIRPDCAP_WS_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-des.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-des.h new file mode 100644 index 00000000..b08ba28b --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-des.h @@ -0,0 +1,26 @@ +/* + Unix SMB/CIFS implementation. + + a partial implementation of DES designed for use in the + SMB authentication protocol + + Copyright (C) Andrew Tridgell 1998 + + $Id: crypt-des.h 3992 2008-06-10 03:13:11Z dgu $ + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +void crypt_des_ecb(unsigned char *out, const unsigned char *in, const unsigned char *key, int forw); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-md4.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-md4.h new file mode 100644 index 00000000..c6179818 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-md4.h @@ -0,0 +1,23 @@ +/* + Unix SMB/CIFS implementation. + a implementation of MD4 designed for use in the SMB authentication protocol + Copyright (C) Andrew Tridgell 1997-1998. + + $Id: crypt-md4.h 3992 2008-06-10 03:13:11Z dgu $ + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +void crypt_md4(unsigned char *out, const unsigned char *in, int n); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-md5.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-md5.h new file mode 100644 index 00000000..d6292004 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-md5.h @@ -0,0 +1,71 @@ +/* $Id: crypt-md5.h 3992 2008-06-10 03:13:11Z dgu $ */ +/* + * Copyright (C) 2003-2005 Benny Prijono + * + * MD5 code from pjlib-util http://www.pjsip.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __MD5_H__ +#define __MD5_H__ + +/** + * @file md5.h + * @brief MD5 Functions + */ + +/** + * @defgroup PJLIB_UTIL_MD5 MD5 Functions + * @ingroup PJLIB_UTIL + * @{ + */ + +#define md5_byte_t guint8 + +/** MD5 context. */ +typedef struct md5_state_s +{ + guint32 buf[4]; + guint32 bits[2]; + guint32 in[16]; +} md5_state_t; + +/** Initialize the algorithm. + * @param pms MD5 context. + */ +void md5_init(md5_state_t *pms); + +/** Append a string to the message. + * @param pms MD5 context. + * @param data Data. + * @param nbytes Length of data. + */ +void md5_append( md5_state_t *pms, + const guint8 *data, guint nbytes); + +/** Finish the message and return the digest. + * @param pms MD5 context. + * @param digest 16 byte digest. + */ +void md5_finish(md5_state_t *pms, guint8 digest[16]); + + +void md5_hmac(const guint8* text, gint text_len, const guint8* key, gint key_len, guint8 digest[16]); + +/** + * @} + */ + +#endif /* _CRYPT_MD5_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-rc4.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-rc4.h new file mode 100644 index 00000000..1068e160 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-rc4.h @@ -0,0 +1,36 @@ +/* + Unix SMB/CIFS implementation. + + a partial implementation of RC4 designed for use in the + SMB authentication protocol + + Copyright (C) Andrew Tridgell 1998 + + $Id: crypt-rc4.h 3992 2008-06-10 03:13:11Z dgu $ + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +typedef struct _rc4_state_struct { + unsigned char s_box[256]; + unsigned char index_i; + unsigned char index_j; +} rc4_state_struct; + +void crypt_rc4_init(rc4_state_struct *rc4_state, + const unsigned char *key, int key_len); + +void crypt_rc4(rc4_state_struct *rc4_state, unsigned char *data, int data_len); + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-sha1.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-sha1.h new file mode 100644 index 00000000..010725b7 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-sha1.h @@ -0,0 +1,45 @@ +/* + * FIPS-180-1 compliant SHA-1 implementation + * + * $Id: crypt-sha1.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Copyright (C) 2001-2003 Christophe Devine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Changed to use guint instead of uint 2004 by Anders Broman + * Original code found at http://www.cr0.net:8040/code/crypto/sha1/ + * References: http://www.ietf.org/rfc/rfc3174.txt?number=3174 + */ + +#ifndef _CRYPT_SHA1_H +#define _CRYPT_SHA1_H + + +typedef struct +{ + guint32 total[2]; + guint32 state[5]; + guint8 buffer[64]; +} +sha1_context; + +void sha1_starts( sha1_context *ctx ); +void sha1_update( sha1_context *ctx, const guint8 *input, guint32 length ); +void sha1_finish( sha1_context *ctx, guint8 digest[20] ); +void sha1_hmac( const guint8 *key, guint32 keylen, const guint8 *buf, guint32 buflen, + guint8 digest[20] ); + +#endif /* crypt-sha1.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/wep-wpadefs.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/wep-wpadefs.h new file mode 100644 index 00000000..f980d401 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/wep-wpadefs.h @@ -0,0 +1,115 @@ +/* wap-wpadefs.h + * + * $Id: wep-wpadefs.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Copyright (c) 2006 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef __WEP_WPADEFS_H__ +#define __WEP_WPADEFS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** @file + * WEP and WPA definitions + * + * Copied from airpcap.h. + */ + +/** + * Maximum number of encryption keys. This determines the size of + * structures in packet-ieee80211.c, as well as the number of keys + * in the IEEE 802.11 preferences. + */ +#define MAX_ENCRYPTION_KEYS 64 + +/** + * Maximum size of a WEP key, in bytes. This is the size of an entry in the + * AirpcapWepKeysCollection structure. + */ +#define WEP_KEY_MAX_SIZE 32 + +/** + * WEP_KEY_MAX_SIZE is in bytes, but each byte is represented as a + * hexadecimal string. + */ +#define WEP_KEY_MAX_CHAR_SIZE (WEP_KEY_MAX_SIZE*2) + +/** + * WEP_KEY_MAX_SIZE is in bytes, this is in bits... + */ +#define WEP_KEY_MAX_BIT_SIZE (WEP_KEY_MAX_SIZE*8) + +#define WEP_KEY_MIN_CHAR_SIZE 2 +#define WEP_KEY_MIN_BIT_SIZE 8 + +/** + * WPA key sizes. + */ +#define WPA_KEY_MAX_SIZE 63 /* 63 chars followed by a '\0' */ + +#define WPA_KEY_MAX_CHAR_SIZE (WPA_KEY_MAX_SIZE*1) +#define WPA_KEY_MAX_BIT_SIZE (WPA_KEY_MAX_SIZE*8) +#define WPA_KEY_MIN_CHAR_SIZE 8 +#define WPA_KEY_MIN_BIT_SIZE (WPA_KEY_MIN_CHAR_SIZE*8) + +/** + * SSID sizes + */ +#define WPA_SSID_MAX_SIZE 32 + +#define WPA_SSID_MAX_CHAR_SIZE (WPA_SSID_MAX_SIZE*1) +#define WPA_SSID_MAX_BIT_SIZE (WPA_SSID_MAX_SIZE*8) +#define WPA_SSID_MIN_CHAR_SIZE 0 +#define WPA_SSID_MIN_BIT_SIZE (WPA_SSID_MIN_CHAR_SIZE*8) + +/** + * Let the user enter a raw PSK along with a passphrase + SSID + */ +#define WPA_PSK_KEY_SIZE 32 /* Fixed size, 32 bytes (256bit) */ +#define WPA_PSK_KEY_CHAR_SIZE (WPA_PSK_KEY_SIZE*2) +#define WPA_PSK_KEY_BIT_SIZE (WPA_PSK_KEY_SIZE*8) + +/** + * Prefix definitions for preferences + */ +#define STRING_KEY_TYPE_WEP "wep" +#define STRING_KEY_TYPE_WPA_PWD "wpa-pwd" +#define STRING_KEY_TYPE_WPA_PSK "wpa-psk" + +#ifdef __cplusplus +} +#endif + +#endif /* __WEP_WPADEFS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter-int.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter-int.h new file mode 100644 index 00000000..aaea0ba4 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter-int.h @@ -0,0 +1,82 @@ +/* + * $Id: dfilter-int.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2001 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef DFILTER_INT_H +#define DFILTER_INT_H + +#include "dfilter.h" +#include "syntax-tree.h" + +#include +#include + +/* Passed back to user */ +struct _dfilter_t { + GPtrArray *insns; + GPtrArray *consts; + int num_registers; + int max_registers; + GList **registers; + gboolean *attempted_load; + int *interesting_fields; + int num_interesting_fields; + GPtrArray *deprecated; +}; + +typedef struct { + /* Syntax Tree stuff */ + stnode_t *st_root; + gboolean syntax_error; + GPtrArray *insns; + GPtrArray *consts; + GHashTable *loaded_fields; + GHashTable *interesting_fields; + int next_insn_id; + int next_const_id; + int next_register; + int first_constant; /* first register used as a constant */ +} dfwork_t; + +/* Constructor/Destructor prototypes for Lemon Parser */ +#if (GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 16)) +void *DfilterAlloc(void* (*)(gsize)); +#else +void *DfilterAlloc(void* (*)(gulong)); +#endif + +void DfilterFree(void*, void (*)(void *)); +void Dfilter(void*, int, stnode_t*, dfwork_t*); + +/* Scanner's lval */ +extern stnode_t *df_lval; + +/* Return value for error in scanner. */ +#define SCAN_FAILED -1 /* not 0, as that means end-of-input */ + +/* Set dfilter_error_msg_buf and dfilter_error_msg */ +void +dfilter_fail(const char *format, ...); + +void +DfilterTrace(FILE *TraceFILE, char *zTracePrompt); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter-macro.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter-macro.h new file mode 100644 index 00000000..c2a78060 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter-macro.h @@ -0,0 +1,59 @@ +/* dfilter-macro.h + * + * $Id: dfilter-macro.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2001 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _DFILTER_MACRO_H +#define _DFILTER_MACRO_H + +#define DFILTER_MACRO_FILENAME "dfilter_macros" + + +typedef struct _dfilter_macro_t { + gchar* name; /* the macro id */ + gchar* text; /* raw data from file */ + gboolean usable; /* macro is usable */ + gchar** parts; /* various segments of text between insertion targets */ + int* args_pos; /* what's to be inserted */ + int argc; /* the expected number of arguments */ + void* priv; /* a copy of text that contains every c-string in parts */ +} dfilter_macro_t; + +/* loop over the macros list */ +typedef void (*dfilter_macro_cb_t)(dfilter_macro_t*, void*); +void dfilter_macro_foreach(dfilter_macro_cb_t, void*); + +/* save dfilter macros to a file */ +void dfilter_macro_save(const gchar*, gchar**); + +/* dumps the macros in the list (debug info, not formated as in the macros file) */ +void dfilter_macro_dump(void); + +/* applies all macros to the given text and returns the resulting string or NULL on failure */ +gchar* dfilter_macro_apply(const gchar* text, guint depth, const gchar** error); + +void dfilter_macro_init(void); + +void dfilter_macro_get_uat(void**); + +void dfilter_macro_build_ftv_cache(void* tree_root); + +#endif /* _DFILTER_MACRO_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter.h new file mode 100644 index 00000000..8ea9f947 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter.h @@ -0,0 +1,94 @@ +/* + * $Id: dfilter.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2001 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef DFILTER_H +#define DFILTER_H + +#include + +/* Passed back to user */ +typedef struct _dfilter_t dfilter_t; + +#include +#include + + +/* Module-level initialization */ +void +dfilter_init(void); + +/* Module-level cleanup */ +void +dfilter_cleanup(void); + +/* Compiles a string to a dfilter_t. + * On success, sets the dfilter* pointed to by dfp + * to either a NULL pointer (if the filter is a null + * filter, as generated by an all-blank string) or to + * a pointer to the newly-allocated dfilter_t + * structure. + * + * On failure, dfilter_error_msg points to an + * appropriate error message. This error message is + * a global string, so another invocation of + * dfilter_compile() will clear it. The dfilter* + * will be set to NULL after a failure. + * + * Returns TRUE on success, FALSE on failure. + */ +gboolean +dfilter_compile(const gchar *text, dfilter_t **dfp); + +/* Frees all memory used by dfilter, and frees + * the dfilter itself. */ +void +dfilter_free(dfilter_t *df); + + +/* dfilter_error_msg is NULL if there was no error during dfilter_compile, + * otherwise it points to a displayable error message. With MSVC and a + * libwireshark.dll, we need a special declaration. + */ + +WS_VAR_IMPORT const gchar *dfilter_error_msg; + + +/* Apply compiled dfilter */ +gboolean +dfilter_apply_edt(dfilter_t *df, epan_dissect_t* edt); + +/* Apply compiled dfilter */ +gboolean +dfilter_apply(dfilter_t *df, proto_tree *tree); + +/* Prime a proto_tree using the fields/protocols used in a dfilter. */ +void +dfilter_prime_proto_tree(const dfilter_t *df, proto_tree *tree); + +GPtrArray * +dfilter_deprecated_tokens(dfilter_t *df); + +/* Print bytecode of dfilter to stdout */ +void +dfilter_dump(dfilter_t *df); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfunctions.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfunctions.h new file mode 100644 index 00000000..f9e1e575 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfunctions.h @@ -0,0 +1,56 @@ +/* + * $Id: dfunctions.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * + * Copyright 2006 Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef DFUNCTIONS_H +#define DFUNCTIONS_H + +#include +#include +#include "syntax-tree.h" + +/* The run-time logic of the dfilter function */ +typedef gboolean (*DFFuncType)(GList *arg1list, GList *arg2list, GList **retval); + +/* The semantic check for the dfilter function */ +typedef void (*DFSemCheckType)(int param_num, stnode_t *st_node); + +/* If a function needs more args than this, increase + * this macro and add more arg members to the dfvm_insn_t + * struct in dfvm.h, and add some logic to dfw_append_function() + * and dfvm_apply() */ +#define DFUNCTION_MAX_NARGS 2 + +/* This is a "function definition" record, holding everything + * we need to know about a function */ +typedef struct { + const char *name; + DFFuncType function; + ftenum_t retval_ftype; + guint min_nargs; + guint max_nargs; + DFSemCheckType semcheck_param_function; +} df_func_def_t; + +/* Return the function definition record for a function of named "name" */ +df_func_def_t* df_func_lookup(char *name); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfvm.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfvm.h new file mode 100644 index 00000000..8e6e2507 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfvm.h @@ -0,0 +1,108 @@ +/* + * $Id: dfvm.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2001 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef DFVM_H +#define DFVM_H + +#include +#include +#include "dfilter-int.h" +#include "syntax-tree.h" +#include "drange.h" +#include "dfunctions.h" + +typedef enum { + EMPTY, + FVALUE, + HFINFO, + INSN_NUMBER, + REGISTER, + INTEGER, + DRANGE, + FUNCTION_DEF +} dfvm_value_type_t; + +typedef struct { + dfvm_value_type_t type; + + union { + fvalue_t *fvalue; + guint32 numeric; + drange *drange; + header_field_info *hfinfo; + df_func_def_t *funcdef; + } value; + +} dfvm_value_t; + + +typedef enum { + + IF_TRUE_GOTO, + IF_FALSE_GOTO, + CHECK_EXISTS, + NOT, + RETURN, + READ_TREE, + PUT_FVALUE, + ANY_EQ, + ANY_NE, + ANY_GT, + ANY_GE, + ANY_LT, + ANY_LE, + ANY_BITWISE_AND, + ANY_CONTAINS, + ANY_MATCHES, + MK_RANGE, + CALL_FUNCTION + +} dfvm_opcode_t; + +typedef struct { + int id; + dfvm_opcode_t op; + dfvm_value_t *arg1; + dfvm_value_t *arg2; + dfvm_value_t *arg3; + dfvm_value_t *arg4; +} dfvm_insn_t; + +dfvm_insn_t* +dfvm_insn_new(dfvm_opcode_t op); + +void +dfvm_insn_free(dfvm_insn_t *insn); + +dfvm_value_t* +dfvm_value_new(dfvm_value_type_t type); + +void +dfvm_dump(FILE *f, GPtrArray *insns); + +gboolean +dfvm_apply(dfilter_t *df, proto_tree *tree); + +void +dfvm_init_const(dfilter_t *df); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/drange.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/drange.h new file mode 100644 index 00000000..37ea4e8c --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/drange.h @@ -0,0 +1,102 @@ +/* drange.h + * Routines for providing general range support to the dfilter library + * + * $Id: drange.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Copyright (c) 2000 by Ed Warnicke + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1999 Gerald Combs + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __DRANGE_H__ +#define __DRANGE_H__ + +#include + +/* Please don't directly manipulate these structs. Please use + * the methods provided. If you REALLY can't do what you need to + * do with the methods provided please write new methods that do + * what you need, put them into the drange object here, and limit + * your direct manipulation of the drange and drange_node structs to + * here. + */ + +typedef enum { + UNINITIALIZED, + LENGTH, + OFFSET, + TO_THE_END +} drange_node_end_t; + +typedef struct _drange_node { + gint start_offset; + gint length; + gint end_offset; + drange_node_end_t ending; +} drange_node; + +typedef struct _drange { + GSList* range_list; + gboolean has_total_length; + gint total_length; + gint min_start_offset; + gint max_start_offset; +} drange; + +/* drange_node constructor */ +drange_node* drange_node_new(void); + +/* drange_node destructor */ +void drange_node_free(drange_node* drnode); + +/* Call drange_node destructor on all list items */ +void drange_node_free_list(GSList* list); + +/* drange_node accessors */ +gint drange_node_get_start_offset(drange_node* drnode); +gint drange_node_get_length(drange_node* drnode); +gint drange_node_get_end_offset(drange_node* drnode); +drange_node_end_t drange_node_get_ending(drange_node* drnode); + +/* drange_node mutators */ +void drange_node_set_start_offset(drange_node* drnode, gint offset); +void drange_node_set_length(drange_node* drnode, gint length); +void drange_node_set_end_offset(drange_node* drnode, gint offset); +void drange_node_set_to_the_end(drange_node* drnode); + +/* drange constructor */ +drange* drange_new(void); +drange* drange_new_from_list(GSList *list); + +/* drange destructor, only use this if you used drange_new() to creat + * the drange + */ +void drange_free(drange* dr); + +/* drange accessors */ +gboolean drange_has_total_length(drange* dr); +gint drange_get_total_length(drange* dr); +gint drange_get_min_start_offset(drange* dr); +gint drange_get_max_start_offset(drange* dr); + +/* drange mutators */ +void drange_append_drange_node(drange* dr, drange_node* drnode); +void drange_prepend_drange_node(drange* dr, drange_node* drnode); +void drange_foreach_drange_node(drange* dr, GFunc func, gpointer funcdata); + +#endif /* ! __DRANGE_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/gencode.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/gencode.h new file mode 100644 index 00000000..2148b2be --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/gencode.h @@ -0,0 +1,10 @@ +#ifndef GENCODE_H +#define GENCODE_H + +void +dfw_gencode(dfwork_t *dfw); + +int* +dfw_interesting_fields(dfwork_t *dfw, int *caller_num_fields); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/glib-util.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/glib-util.h new file mode 100644 index 00000000..f845cbe6 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/glib-util.h @@ -0,0 +1,4 @@ +/* $Id: glib-util.h 3992 2008-06-10 03:13:11Z dgu $ */ + +char* +g_substrdup(const char *s, int start, int len); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/grammar.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/grammar.h new file mode 100644 index 00000000..36c3e11f --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/grammar.h @@ -0,0 +1,24 @@ +#define TOKEN_TEST_AND 1 +#define TOKEN_TEST_OR 2 +#define TOKEN_TEST_EQ 3 +#define TOKEN_TEST_NE 4 +#define TOKEN_TEST_LT 5 +#define TOKEN_TEST_LE 6 +#define TOKEN_TEST_GT 7 +#define TOKEN_TEST_GE 8 +#define TOKEN_TEST_CONTAINS 9 +#define TOKEN_TEST_MATCHES 10 +#define TOKEN_TEST_BITWISE_AND 11 +#define TOKEN_TEST_NOT 12 +#define TOKEN_FIELD 13 +#define TOKEN_STRING 14 +#define TOKEN_UNPARSED 15 +#define TOKEN_LBRACKET 16 +#define TOKEN_RBRACKET 17 +#define TOKEN_COMMA 18 +#define TOKEN_INTEGER 19 +#define TOKEN_COLON 20 +#define TOKEN_HYPHEN 21 +#define TOKEN_FUNCTION 22 +#define TOKEN_LPAREN 23 +#define TOKEN_RPAREN 24 diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/scanner_lex.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/scanner_lex.h new file mode 100644 index 00000000..886d06b1 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/scanner_lex.h @@ -0,0 +1,6 @@ +/* This is generated by runlex.sh. Do not edit it. */ +#define yylex df_lex +#ifndef YY_DECL +#define YY_DECL int yylex(void) +#endif +YY_DECL; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/semcheck.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/semcheck.h new file mode 100644 index 00000000..5eac9804 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/semcheck.h @@ -0,0 +1,31 @@ +/* + * $Id: semcheck.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2001 Gerald Combs + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef SEMCHECK_H +#define SEMCHECK_H + +gboolean +dfw_semcheck(dfwork_t *dfw); + + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-function.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-function.h new file mode 100644 index 00000000..fdcc9c58 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-function.h @@ -0,0 +1,42 @@ +/* + * $Id: sttype-function.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2001 Gerald Combs + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef STTYPE_FUNCTION_H +#define STTYPE_FUNCTION_H + +#include "dfunctions.h" + +/* Set the parameters for a function stnode_t. */ +void +sttype_function_set_params(stnode_t *node, GSList *params); + +/* Get the function-definition record for a function stnode_t. */ +df_func_def_t* sttype_function_funcdef(stnode_t *node); + +/* Get the parameters for a function stnode_t. */ +GSList* sttype_function_params(stnode_t *node); + +/* Free the memory of a param list */ +void st_funcparams_free(GSList *params); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-range.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-range.h new file mode 100644 index 00000000..db92f76d --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-range.h @@ -0,0 +1,45 @@ +/* + * $Id: sttype-range.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2001 Gerald Combs + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef STTYPE_RANGE_H +#define STTYPE_RANGE_H + +#include "syntax-tree.h" +#include "drange.h" + +STTYPE_ACCESSOR_PROTOTYPE(header_field_info*, range, hfinfo) +STTYPE_ACCESSOR_PROTOTYPE(drange*, range, drange) + +/* Set a range */ +void +sttype_range_set(stnode_t *node, stnode_t *field, GSList* drange_list); + +void +sttype_range_set1(stnode_t *node, stnode_t *field, drange_node *rn); + +/* Clear the 'drange' variable to remove responsibility for + * freeing it. */ +void +sttype_range_remove_drange(stnode_t *node); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-test.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-test.h new file mode 100644 index 00000000..1635378b --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-test.h @@ -0,0 +1,56 @@ +/* + * $Id: sttype-test.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2001 Gerald Combs + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef STTYPE_TEST_H +#define STTYPE_TEST_H + +typedef enum { + TEST_OP_UNINITIALIZED, + TEST_OP_EXISTS, + TEST_OP_NOT, + TEST_OP_AND, + TEST_OP_OR, + TEST_OP_EQ, + TEST_OP_NE, + TEST_OP_GT, + TEST_OP_GE, + TEST_OP_LT, + TEST_OP_LE, + TEST_OP_BITWISE_AND, + TEST_OP_CONTAINS, + TEST_OP_MATCHES +} test_op_t; + +void +sttype_test_set1(stnode_t *node, test_op_t op, stnode_t *val1); + +void +sttype_test_set2(stnode_t *node, test_op_t op, stnode_t *val1, stnode_t *val2); + +void +sttype_test_set2_args(stnode_t *node, stnode_t *val1, stnode_t *val2); + +void +sttype_test_get(stnode_t *node, test_op_t *p_op, stnode_t **p_val1, stnode_t **p_val2); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/syntax-tree.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/syntax-tree.h new file mode 100644 index 00000000..0ea35f39 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/syntax-tree.h @@ -0,0 +1,136 @@ +/* + * $Id: syntax-tree.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2001 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef SYNTAX_TREE_H +#define SYNTAX_TREE_H + +#include +#include "cppmagic.h" + +typedef enum { + STTYPE_UNINITIALIZED, + STTYPE_TEST, + STTYPE_UNPARSED, + STTYPE_STRING, + STTYPE_FIELD, + STTYPE_FVALUE, + STTYPE_INTEGER, + STTYPE_RANGE, + STTYPE_FUNCTION, + STTYPE_NUM_TYPES +} sttype_id_t; + +typedef gpointer (*STTypeNewFunc)(gpointer); +typedef void (*STTypeFreeFunc)(gpointer); + + +/* Type information */ +typedef struct { + sttype_id_t id; + const char *name; + STTypeNewFunc func_new; + STTypeFreeFunc func_free; +} sttype_t; + +/* Node (type instance) information */ +typedef struct { + guint32 magic; + sttype_t *type; + + /* This could be made an enum, but I haven't + * set aside to time to do so. */ + gpointer data; + gint32 value; + const char *deprecated_token; +} stnode_t; + +/* These are the sttype_t registration function prototypes. */ +void sttype_register_function(void); +void sttype_register_integer(void); +void sttype_register_pointer(void); +void sttype_register_range(void); +void sttype_register_string(void); +void sttype_register_test(void); + +void +sttype_init(void); + +void +sttype_cleanup(void); + +void +sttype_register(sttype_t *type); + +stnode_t* +stnode_new(sttype_id_t type_id, gpointer data); + +void +stnode_init(stnode_t *node, sttype_id_t type_id, gpointer data); + +void +stnode_init_int(stnode_t *node, sttype_id_t type_id, gint32 value); + +void +stnode_free(stnode_t *node); + +const char* +stnode_type_name(stnode_t *node); + +sttype_id_t +stnode_type_id(stnode_t *node); + +gpointer +stnode_data(stnode_t *node); + +gint32 +stnode_value(stnode_t *node); + +const char * +stnode_deprecated(stnode_t *node); + +#define assert_magic(obj, mnum) \ + g_assert((obj)); \ + if ((obj)->magic != (mnum)) { \ + g_print("\nMagic num is 0x%08x, but should be 0x%08x", \ + (obj)->magic, (mnum)); \ + g_assert((obj)->magic == (mnum)); \ + } + + + + +#define STTYPE_ACCESSOR(ret,type,attr,magicnum) \ + ret \ + CONCAT(CONCAT(CONCAT(sttype_,type),_),attr) (stnode_t *node) \ +{\ + CONCAT(type,_t) *value; \ + value = stnode_data(node);\ + assert_magic(value, magicnum); \ + return value->attr; \ +} + +#define STTYPE_ACCESSOR_PROTOTYPE(ret,type,attr) \ + ret \ + CONCAT(CONCAT(CONCAT(sttype_,type),_),attr) (stnode_t *node); + + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/diam_dict.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/diam_dict.h new file mode 100644 index 00000000..b36ba254 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/diam_dict.h @@ -0,0 +1,89 @@ +/* + ** diam_dict.h + ** Diameter Dictionary Import Routines + ** + ** $Id: diam_dict.h 3992 2008-06-10 03:13:11Z dgu $ + ** + ** (c) 2007, Luis E. Garcia Ontanon + ** + ** This library is free software; you can redistribute it and/or + ** modify it under the terms of the GNU Library General Public + ** License as published by the Free Software Foundation; either + ** version 2 of the License, or (at your option) any later version. + ** + ** This library is distributed in the hope that it will be useful, + ** but WITHOUT ANY WARRANTY; without even the implied warranty of + ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + ** Library General Public License for more details. + ** + ** You should have received a copy of the GNU Library General Public + ** License along with this library; if not, write to the + ** Free Software Foundation, Inc., 59 Temple Place - Suite 330, + ** Boston, MA 02111-1307, USA. + */ + +#ifndef _DIAM_DICT_H_ +#define _DIAM_DICT_H_ + +struct _ddict_namecode_t { + char* name; + unsigned code; + struct _ddict_namecode_t* next; +}; + +typedef struct _ddict_namecode_t ddict_gavp_t; +typedef struct _ddict_namecode_t ddict_enum_t; +typedef struct _ddict_namecode_t ddict_application_t; + +typedef struct _ddict_vendor_t { + char* name; + char* desc; + unsigned code; + struct _ddict_vendor_t* next; +} ddict_vendor_t; + +typedef struct _ddict_avp_t { + char* name; + char* description; + char* vendor; + char* type; + unsigned code; + ddict_gavp_t* gavps; + ddict_enum_t* enums; + struct _ddict_avp_t* next; +} ddict_avp_t; + +typedef struct _ddict_typedefn_t { + char* name; + char* parent; + struct _ddict_typedefn_t* next; +} ddict_typedefn_t; + +typedef struct _ddict_cmd_t { + char* name; + char* vendor; + unsigned code; + struct _ddict_cmd_t* next; +} ddict_cmd_t; + +typedef struct _ddict_xmlpi_t { + char* name; + char* key; + char* value; + struct _ddict_xmlpi_t* next; +} ddict_xmlpi_t; + +typedef struct _ddict_t { + ddict_application_t* applications; + ddict_vendor_t* vendors; + ddict_cmd_t* cmds; + ddict_typedefn_t* typedefns; + ddict_avp_t* avps; + ddict_xmlpi_t* xmlpis; +} ddict_t; + +extern void ddict_print(FILE* fh, ddict_t* d); +extern ddict_t* ddict_scan(const char* directory, const char* filename, int dbg); +extern void ddict_free(ddict_t* d); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/diam_dict_lex.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/diam_dict_lex.h new file mode 100644 index 00000000..1135d99c --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/diam_dict_lex.h @@ -0,0 +1,6 @@ +/* This is generated by runlex.sh. Do not edit it. */ +#define yylex DiamDictlex +#ifndef YY_DECL +#define YY_DECL int yylex(void) +#endif +YY_DECL; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dissector_filters.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dissector_filters.h new file mode 100644 index 00000000..595c3d57 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dissector_filters.h @@ -0,0 +1,60 @@ +/* dissector_filters.h + * Routines for dissector generated display filters + * + * $Id: dissector_filters.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __DISSECTOR_FILTERS_H__ +#define __DISSECTOR_FILTERS_H__ + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* callback function definition: is a filter available for this packet? */ +typedef gboolean (*is_filter_valid_func)(packet_info *pinfo); + +/* callback function definition: return the available filter for this packet or NULL if no filter is available */ +typedef const gchar* (*build_filter_string_func)(packet_info *pinfo); + + +/* register a dissector filter */ +extern void register_dissector_filter(const char *name, is_filter_valid_func is_filter_valid, build_filter_string_func build_filter_string); + + + +/*** THE FOLLOWING SHOULD NOT BE USED BY ANY DISSECTORS!!! ***/ + +typedef struct dissector_filter_s { + const char * name; + is_filter_valid_func is_filter_valid; + build_filter_string_func build_filter_string; +} dissector_filter_t; + +WS_VAR_IMPORT GList *dissector_filter_list; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* dissector_filters.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dissectors/packet-tcp.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dissectors/packet-tcp.h new file mode 100644 index 00000000..ee0b70cb --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dissectors/packet-tcp.h @@ -0,0 +1,232 @@ +/* packet-tcp.h + * + * $Id: packet-tcp.h 23902 2007-12-17 20:43:38Z sfisher $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PACKET_TCP_H__ +#define __PACKET_TCP_H__ + +/* TCP flags */ +#define TH_FIN 0x01 +#define TH_SYN 0x02 +#define TH_RST 0x04 +#define TH_PUSH 0x08 +#define TH_ACK 0x10 +#define TH_URG 0x20 +#define TH_ECN 0x40 +#define TH_CWR 0x80 + +/* Idea for gt: either x > y, or y is much bigger (assume wrap) */ +#define GT_SEQ(x, y) ((gint32)((y) - (x)) < 0) +#define LT_SEQ(x, y) ((gint32)((x) - (y)) < 0) +#define GE_SEQ(x, y) ((gint32)((y) - (x)) <= 0) +#define LE_SEQ(x, y) ((gint32)((x) - (y)) <= 0) +#define EQ_SEQ(x, y) ((x) == (y)) + +/* the tcp header structure, passed to tap listeners */ +struct tcpheader { + guint32 th_seq; + guint32 th_ack; + gboolean th_have_seglen; /* TRUE if th_seglen is valid */ + guint32 th_seglen; + guint32 th_win; /* make it 32 bits so we can handle some scaling */ + guint16 th_sport; + guint16 th_dport; + guint8 th_hlen; + guint8 th_flags; + address ip_src; + address ip_dst; +}; + +/* + * Private data passed from the TCP dissector to subdissectors. Passed to the + * subdissectors in pinfo->private_data + */ +struct tcpinfo { + guint32 seq; /* Sequence number of first byte in the data */ + guint32 nxtseq; /* Sequence number of first byte after data */ + guint32 lastackseq; /* Sequence number of last ack */ + gboolean is_reassembled; /* This is reassembled data. */ + gboolean urgent; /* TRUE if "urgent_pointer" is valid */ + guint16 urgent_pointer; /* Urgent pointer value for the current packet. */ +}; + +/* + * Loop for dissecting PDUs within a TCP stream; assumes that a PDU + * consists of a fixed-length chunk of data that contains enough information + * to determine the length of the PDU, followed by rest of the PDU. + * + * The first three arguments are the arguments passed to the dissector + * that calls this routine. + * + * "proto_desegment" is the dissector's flag controlling whether it should + * desegment PDUs that cross TCP segment boundaries. + * + * "fixed_len" is the length of the fixed-length part of the PDU. + * + * "get_pdu_len()" is a routine called to get the length of the PDU from + * the fixed-length part of the PDU; it's passed "pinfo", "tvb" and "offset". + * + * "dissect_pdu()" is the routine to dissect a PDU. + */ +extern void +tcp_dissect_pdus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + gboolean proto_desegment, guint fixed_len, + guint (*get_pdu_len)(packet_info *, tvbuff_t *, int), + dissector_t dissect_pdu); + +extern struct tcp_multisegment_pdu * +pdu_store_sequencenumber_of_next_pdu(packet_info *pinfo, guint32 seq, guint32 nxtpdu, emem_tree_t *multisegment_pdus); + +typedef struct _tcp_unacked_t { + struct _tcp_unacked_t *next; + guint32 frame; + guint32 seq; + guint32 nextseq; + nstime_t ts; +} tcp_unacked_t; + +struct tcp_acked { + guint32 frame_acked; + nstime_t ts; + + guint32 rto_frame; + nstime_t rto_ts; /* Time since previous packet for + retransmissions. */ + guint16 flags; + guint32 dupack_num; /* dup ack number */ + guint32 dupack_frame; /* dup ack to frame # */ +}; + +/* One instance of this structure is created for each pdu that spans across + * multiple tcp segments. + */ +struct tcp_multisegment_pdu { + guint32 seq; + guint32 nxtpdu; + guint32 first_frame; + guint32 last_frame; + nstime_t last_frame_time; + guint32 flags; +#define MSP_FLAGS_REASSEMBLE_ENTIRE_SEGMENT 0x00000001 +}; + +typedef struct _tcp_flow_t { + guint32 base_seq; /* base seq number (used by relative sequence numbers) + * or 0 if not yet known. + */ + tcp_unacked_t *segments; + guint32 lastack; /* last seen ack */ + nstime_t lastacktime; /* Time of the last ack packet */ + guint32 lastnondupack; /* frame number of last seen non dupack */ + guint32 dupacknum; /* dupack number */ + guint32 nextseq; /* highest seen nextseq */ + guint32 nextseqframe; /* frame number for segment with highest + * sequence number + */ + nstime_t nextseqtime; /* Time of the nextseq packet so we can + * distinguish between retransmission, + * fast retransmissions and outoforder + */ + guint32 window; /* last seen window */ + gint16 win_scale; /* -1 is we dont know */ +/* This tcp flow/session contains only one single PDU and should + * be reassembled until the final FIN segment. + */ +#define TCP_FLOW_REASSEMBLE_UNTIL_FIN 0x0001 + guint16 flags; + guint32 lastsegmentflags; + + /* This tree is indexed by sequence number and keeps track of all + * all pdus spanning multiple segments for this flow. + */ + emem_tree_t *multisegment_pdus; +} tcp_flow_t; + + +struct tcp_analysis { + /* These two structs are managed based on comparing the source + * and destination addresses and, if they're equal, comparing + * the source and destination ports. + * + * If the source is greater than the destination, then stuff + * sent from src is in ual1. + * + * If the source is less than the destination, then stuff + * sent from src is in ual2. + * + * XXX - if the addresses and ports are equal, we don't guarantee + * the behavior. + */ + tcp_flow_t flow1; + tcp_flow_t flow2; + + /* These pointers are set by get_tcp_conversation_data() + * fwd point in the same direction as the current packet + * and rev in the reverse direction + */ + tcp_flow_t *fwd; + tcp_flow_t *rev; + + /* This pointer is NULL or points to a tcp_acked struct if this + * packet has "interesting" properties such as being a KeepAlive or + * similar + */ + struct tcp_acked *ta; + /* This structure contains a tree containing all the various ta's + * keyed by frame number. + */ + emem_tree_t *acked_table; + + /* Remember the timestamp of the first frame seen in this tcp + * conversation to be able to calculate a relative time compared + * to the start of this conversation + */ + nstime_t ts_first; + + /* Remember the timestamp of the frame that was last seen in this + * tcp conversation to be able to calculate a delta time compared + * to previous frame in this conversation + */ + nstime_t ts_prev; +}; + +/* Structure that keeps per packet data. First used to be able + * to calculate the time_delta from the last seen frame in this + * TCP conversation. Can be extended for future use. + */ +struct tcp_per_packet_data_t { + nstime_t ts_del; +}; + + +extern void dissect_tcp_payload(tvbuff_t *tvb, packet_info *pinfo, int offset, + guint32 seq, guint32 nxtseq, guint32 sport, + guint32 dport, proto_tree *tree, + proto_tree *tcp_tree, + struct tcp_analysis *tcpd); + +extern struct tcp_analysis *get_tcp_conversation_data(packet_info *pinfo); + +extern gboolean decode_tcp_ports(tvbuff_t *, int, packet_info *, proto_tree *, int, int, struct tcp_analysis *); + + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd.h new file mode 100644 index 00000000..6063fb31 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd.h @@ -0,0 +1,62 @@ +/* + * dtd.h + * + * XML dissector for Wireshark + * DTD import declarations + * + * Copyright 2005, Luis E. Garcia Ontanon + * + * $Id: dtd.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _DTD_H_ +#define _DTD_H_ + +#include +#include /* exit() */ + +typedef struct _dtd_build_data_t { + gchar* proto_name; + gchar* media_type; + gchar* description; + gchar* proto_root; + gboolean recursion; + + GPtrArray* elements; + GPtrArray* attributes; + + GString* error; +} dtd_build_data_t; + +typedef struct _dtd_token_data_t { + gchar* text; + gchar* location; +} dtd_token_data_t; + +typedef struct _dtd_named_list_t { + gchar* name; + GPtrArray* list; +} dtd_named_list_t; + +extern GString* dtd_preparse(const gchar* dname, const gchar* fname, GString* err); +extern dtd_build_data_t* dtd_parse(GString* s); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_grammar.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_grammar.h new file mode 100644 index 00000000..732b0361 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_grammar.h @@ -0,0 +1,23 @@ +#define TOKEN_TAG_START 1 +#define TOKEN_DOCTYPE_KW 2 +#define TOKEN_NAME 3 +#define TOKEN_OPEN_BRACKET 4 +#define TOKEN_CLOSE_BRACKET 5 +#define TOKEN_TAG_STOP 6 +#define TOKEN_ATTLIST_KW 7 +#define TOKEN_ELEMENT_KW 8 +#define TOKEN_ATT_TYPE 9 +#define TOKEN_ATT_DEF 10 +#define TOKEN_ATT_DEF_WITH_VALUE 11 +#define TOKEN_QUOTED 12 +#define TOKEN_IMPLIED_KW 13 +#define TOKEN_REQUIRED_KW 14 +#define TOKEN_OPEN_PARENS 15 +#define TOKEN_CLOSE_PARENS 16 +#define TOKEN_PIPE 17 +#define TOKEN_STAR 18 +#define TOKEN_PLUS 19 +#define TOKEN_QUESTION 20 +#define TOKEN_ELEM_DATA 21 +#define TOKEN_COMMA 22 +#define TOKEN_EMPTY_KW 23 diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_parse.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_parse.h new file mode 100644 index 00000000..99a9958a --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_parse.h @@ -0,0 +1,37 @@ +/* dtd_parse.h +* an XML dissector for Wireshark +* header file to declare functions defined in lexer and used in parser, +* or vice versa +* +* Copyright 2004, Luis E. Garcia Ontanon +* +* $Id: dtd_parse.h 3992 2008-06-10 03:13:11Z dgu $ +* +* Wireshark - Network traffic analyzer +* By Gerald Combs +* Copyright 1998 Gerald Combs +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +extern void DtdParse(void*,int,dtd_token_data_t*,dtd_build_data_t*); +#if (GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 16)) +extern void *DtdParseAlloc(void *(*)(gsize)); +#else +extern void *DtdParseAlloc(void *(*)(gulong)); +#endif +extern void DtdParseFree( void*, void(*)(void*) ); +extern void DtdParseTrace(FILE *TraceFILE, char *zTracePrompt); +extern int Dtd_Parse_lex(void); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_parse_lex.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_parse_lex.h new file mode 100644 index 00000000..c809f40b --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_parse_lex.h @@ -0,0 +1,6 @@ +/* This is generated by runlex.sh. Do not edit it. */ +#define yylex Dtd_Parse_lex +#ifndef YY_DECL +#define YY_DECL int yylex(void) +#endif +YY_DECL; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_preparse_lex.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_preparse_lex.h new file mode 100644 index 00000000..dc4b7bcf --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_preparse_lex.h @@ -0,0 +1,6 @@ +/* This is generated by runlex.sh. Do not edit it. */ +#define yylex Dtd_PreParse_lex +#ifndef YY_DECL +#define YY_DECL int yylex(void) +#endif +YY_DECL; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/eap.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/eap.h new file mode 100644 index 00000000..24934ceb --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/eap.h @@ -0,0 +1,53 @@ +/* sminmpec.h + * Extenal definitions for EAP Extensible Authentication Protocol dissection + * RFC 2284, RFC 3748 + * + * $Id: eap.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2004 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __EAP_H__ +#define __EAP_H__ + +#define EAP_REQUEST 1 +#define EAP_RESPONSE 2 +#define EAP_SUCCESS 3 +#define EAP_FAILURE 4 + +WS_VAR_IMPORT const value_string eap_code_vals[]; + +#define EAP_TYPE_ID 1 +#define EAP_TYPE_NOTIFY 2 +#define EAP_TYPE_NAK 3 +#define EAP_TYPE_MD5 4 +#define EAP_TYPE_TLS 13 +#define EAP_TYPE_LEAP 17 +#define EAP_TYPE_SIM 18 +#define EAP_TYPE_TTLS 21 +#define EAP_TYPE_AKA 23 +#define EAP_TYPE_PEAP 25 +#define EAP_TYPE_MSCHAPV2 26 +#define EAP_TYPE_FAST 43 +#define EAP_TYPE_EXT 254 + +WS_VAR_IMPORT const value_string eap_type_vals[]; + + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/emem.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/emem.h new file mode 100644 index 00000000..a1e0c898 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/emem.h @@ -0,0 +1,373 @@ +/* emem.h + * Definitions for Wireshark memory management and garbage collection + * Ronnie Sahlberg 2005 + * + * $Id: emem.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __EMEM_H__ +#define __EMEM_H__ + +#include "gnuc_format_check.h" + +/* Functions for handling memory allocation and garbage collection with + * a packet lifetime scope. + * These functions are used to allocate memory that will only remain persistent + * until Wireshark starts dissecting the next packet in the list. + * Everytime Wireshark starts decoding the next packet all memory allocated + * through these functions will be released back to the free pool. + * + * These functions are very fast and offer automatic garbage collection: + * Everytime a new packet is dissected, all memory allocations done in + * the previous packet is freed. + */ +/* Initialize packet-lifetime memory allocation pool. This function is called + * once when [t]Wireshark is initialized to set up the required structures. + */ +void ep_init_chunk(void); + +/* Allocate memory with a packet lifetime scope */ +void *ep_alloc(size_t size); +#define ep_new(type) ((type*)ep_alloc(sizeof(type))) + +/* Allocate memory with a packet lifetime scope and fill it with zeros*/ +void* ep_alloc0(size_t size); +#define ep_new0(type) ((type*)ep_alloc0(sizeof(type))) + +/* Duplicate a string with a packet lifetime scope */ +gchar* ep_strdup(const gchar* src); + +/* Duplicate at most n characters of a string with a packet lifetime scope */ +gchar* ep_strndup(const gchar* src, size_t len); + +/* Duplicate a buffer with a packet lifetime scope */ +void* ep_memdup(const void* src, size_t len); + +/* Create a formatted string with a packet lifetime scope */ +gchar* ep_strdup_vprintf(const gchar* fmt, va_list ap); +gchar* ep_strdup_printf(const gchar* fmt, ...) + GNUC_FORMAT_CHECK(printf, 1, 2); + +/* allocates with a packet lifetime scope an array of type made of num elements */ +#define ep_alloc_array(type,num) (type*)ep_alloc(sizeof(type)*(num)) + +/* allocates with a packet lifetime scope an array of type made of num elements, + * initialised to zero. + */ +#define ep_alloc_array0(type,num) (type*)ep_alloc0(sizeof(type)*(num)) + +/* + * Splits a string into a maximum of max_tokens pieces, using the given + * delimiter. If max_tokens is reached, the remainder of string is appended + * to the last token. Consecutive delimiters are treated as a single delimiter. + * + * the vector and all the strings are allocated with packet lifetime scope + */ +gchar** ep_strsplit(const gchar* string, const gchar* delimiter, int max_tokens); + +/* release all memory allocated in the previous packet dissector */ +void ep_free_all(void); + + +/* a stack implemented using ephemeral allocators */ + +typedef struct _ep_stack_frame_t** ep_stack_t; + +struct _ep_stack_frame_t { + void* payload; + struct _ep_stack_frame_t* below; + struct _ep_stack_frame_t* above; +}; + +/* + * creates an empty stack with a packet lifetime scope + */ +ep_stack_t ep_stack_new(void); + +/* + * pushes item into stack, returns item + */ +void* ep_stack_push(ep_stack_t stack, void* item); + +/* + * pops an item from the stack + */ +void* ep_stack_pop(ep_stack_t stack); + +/* + * returns the item on top of the stack without popping it + */ +#define ep_stack_peek(stack) ((*(stack))->payload) + + +/* Functions for handling memory allocation and garbage collection with + * a capture lifetime scope. + * These functions are used to allocate memory that will only remain persistent + * until Wireshark opens a new capture or capture file. + * Everytime Wireshark starts a new capture or opens a new capture file + * all the data allocated through these functions will be released back + * to the free pool. + * + * These functions are very fast and offer automatic garbage collection. + */ +/* Initialize capture-lifetime memory allocation pool. This function is called + * once when [t]Wireshark is initialized to set up the required structures. + */ +void se_init_chunk(void); + +/* Allocate memory with a capture lifetime scope */ +void *se_alloc(size_t size); + +/* Allocate memory with a capture lifetime scope and fill it with zeros*/ +void* se_alloc0(size_t size); + +/* Duplicate a string with a capture lifetime scope */ +gchar* se_strdup(const gchar* src); + +/* Duplicate at most n characters of a string with a capture lifetime scope */ +gchar* se_strndup(const gchar* src, size_t len); + +/* Duplicate a buffer with a capture lifetime scope */ +void* se_memdup(const void* src, size_t len); + +/* Create a formatted string with a capture lifetime scope */ +gchar* se_strdup_vprintf(const gchar* fmt, va_list ap); +gchar* se_strdup_printf(const gchar* fmt, ...) + GNUC_FORMAT_CHECK(printf, 1, 2); + +/* allocates with a capture lifetime scope an array of type made of num elements */ +#define se_alloc_array(type,num) (type*)se_alloc(sizeof(type)*(num)) + +/* release all memory allocated */ +void se_free_all(void); + + + + +/************************************************************** + * binary trees + **************************************************************/ +typedef struct _emem_tree_node_t { + struct _emem_tree_node_t *parent; + struct _emem_tree_node_t *left; + struct _emem_tree_node_t *right; + struct { +#define EMEM_TREE_RB_COLOR_RED 0 +#define EMEM_TREE_RB_COLOR_BLACK 1 + guint32 rb_color:1; +#define EMEM_TREE_NODE_IS_DATA 0 +#define EMEM_TREE_NODE_IS_SUBTREE 1 + guint32 is_subtree:1; + } u; + guint32 key32; + void *data; +} emem_tree_node_t; + +/* Right now we only do basic red/black trees but in the future we might want + * to try something different, such as a tree where each node keeps track + * of how many times it has been looked up, and letting often looked up + * nodes bubble upwards in the tree using rotate_right/left. + * That would probably be good for things like nfs filehandles + */ +#define EMEM_TREE_TYPE_RED_BLACK 1 +typedef struct _emem_tree_t { + struct _emem_tree_t *next; + int type; + const char *name; /* just a string to make debugging easier */ + emem_tree_node_t *tree; + void *(*malloc)(size_t); +} emem_tree_t; + +/* list of all trees with se allocation scope so that they can all be reset + * automatically when we free all se memory + */ +extern emem_tree_t *se_trees; + + +/* ******************************************************************* + * Tree functions for SE memory allocation scope + * ******************************************************************* */ +/* This function is used to create a se based tree with monitoring. + * When the SE heap is released back to the system the pointer to the + * tree is automatically reset to NULL. + * + * type is : EMEM_TREE_TYPE_RED_BLACK for a standard red/black tree. + */ +emem_tree_t *se_tree_create(int type, const char *name); + +/* This function is similar to the se_tree_create() call but with the + * difference that when the se memory is release everything including the + * pointer to the tree itself will be released. + * This tree will not be just reset to zero it will be completely forgotten + * by the allocator. + * Use this function for when you want to store the pointer to a tree inside + * another structure that is also se allocated so that when the structure is + * released, the tree will be completely released as well. + */ +emem_tree_t *se_tree_create_non_persistent(int type, const char *name); + +/* se_tree_insert32 + * Insert data into the tree and key it by a 32bit integer value + */ +#define se_tree_insert32 emem_tree_insert32 + +/* se_tree_lookup32 + * Retreive the data at the search key. the search key is a 32bit integer value + */ +#define se_tree_lookup32 emem_tree_lookup32 + +/* se_tree_lookup32_le + * Retreive the data for the largest key that is less than or equal + * to the search key. + */ +#define se_tree_lookup32_le emem_tree_lookup32_le + +/* se_tree_insert32_array + * Insert data into the tree and key it by a 32bit integer value + */ +#define se_tree_insert32_array emem_tree_insert32_array + +/* se_tree_lookup32_array + * Lookup data from the tree that is index by an array + */ +#define se_tree_lookup32_array emem_tree_lookup32_array + + + +/* Create a new string based hash table */ +#define se_tree_create_string() se_tree_create(SE_TREE_TYPE_RED_BLACK) + +/* Insert a new value under a string key */ +#define se_tree_insert_string emem_tree_insert_string + +/* Lookup the value under a string key */ +#define se_tree_lookup_string emem_tree_lookup_string + +/* Traverse a tree */ +#define se_tree_foreach emem_tree_foreach + + +/* ******************************************************************* + * Tree functions for PE memory allocation scope + * ******************************************************************* */ +/* These trees have PErmanent allocation scope and will never be released + */ +emem_tree_t *pe_tree_create(int type, char *name); +#define pe_tree_insert32 emem_tree_insert32 +#define pe_tree_lookup32 emem_tree_lookup32 +#define pe_tree_lookup32_le emem_tree_lookup32_le +#define pe_tree_insert32_array emem_tree_insert32_array +#define pe_tree_lookup32_array emem_tree_lookup32_array +#define pe_tree_insert_string emem_tree_insert_string +#define pe_tree_lookup_string emem_tree_lookup_string +#define pe_tree_foreach emem_tree_foreach + + + +/* ****************************************************************** + * Real tree functions + * ****************************************************************** */ + +/* This function is used to insert a node indexed by a guint32 key value. + * The data pointer should be allocated by the appropriate storage scope + * so that it will be released at the same time as the tree itself is + * destroyed. + */ +void emem_tree_insert32(emem_tree_t *se_tree, guint32 key, void *data); + +/* This function will look up a node in the tree indexed by a guint32 integer + * value. + */ +void *emem_tree_lookup32(emem_tree_t *se_tree, guint32 key); + +/* This function will look up a node in the tree indexed by a guint32 integer + * value. + * The function will return the node that has the largest key that is + * equal to or smaller than the search key, or NULL if no such key was + * found. + */ +void *emem_tree_lookup32_le(emem_tree_t *se_tree, guint32 key); + +typedef struct _emem_tree_key_t { + guint32 length; /*length in guint32 words */ + guint32 *key; +} emem_tree_key_t; + +/* This function is used to insert a node indexed by a sequence of guint32 + * key values. + * The data pointer should be allocated by SE allocators so that the + * data will be released at the same time as the tree itself is destroyed. + * + * Note: all the "key" members of the "key" argument MUST be aligned on + * 32-bit boundaries; otherwise, this code will crash on platforms such + * as SPARC that require aligned pointers. + * + * If you use ...32_array() calls you MUST make sure that every single node + * you add to a specific tree always has a key of exactly the same number of + * keylen words or things will most likely crash. Or at least that every single + * item that sits behind the same top level node always have exactly the same + * number of words. + * + * One way to guarantee this is the way that NFS does this for the + * nfs_name_snoop_known tree which holds filehandles for both v2 and v3. + * v2 filehandles are always 32 bytes (8 words) while v3 filehandles can have + * any length (though 32bytes are most common). + * The NFS dissector handles this by providing a guint32 containing the length + * as the very first item in this vector : + * + * emem_tree_key_t fhkey[3]; + * + * fhlen=nns->fh_length; + * fhkey[0].length=1; + * fhkey[0].key=&fhlen; + * fhkey[1].length=fhlen/4; + * fhkey[1].key=nns->fh; + * fhkey[2].length=0; + */ +void emem_tree_insert32_array(emem_tree_t *se_tree, emem_tree_key_t *key, void *data); + +/* This function will look up a node in the tree indexed by a sequence of + * guint32 integer values. + */ +void *emem_tree_lookup32_array(emem_tree_t *se_tree, emem_tree_key_t *key); + +/* case insensitive strings as keys */ +#define EMEM_TREE_STRING_NOCASE 0x00000001 +/* Insert a new value under a string key */ +void emem_tree_insert_string(emem_tree_t* h, const gchar* k, void* v, guint32 flags); + +/* Lookup the value under a string key */ +void* emem_tree_lookup_string(emem_tree_t* h, const gchar* k, guint32 flags); + + +/* traverse a tree. if the callback returns TRUE the traversal will end */ +typedef gboolean (*tree_foreach_func)(void *value, void *userdata); + +gboolean emem_tree_foreach(emem_tree_t* emem_tree, tree_foreach_func callback, void *user_data); + + + + +void emem_print_tree(emem_tree_t* emem_tree); + + + +#endif /* emem.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/epan.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/epan.h new file mode 100644 index 00000000..9da31108 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/epan.h @@ -0,0 +1,93 @@ +/* epan.h + * + * $Id: epan.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark Protocol Analyzer Library + * + * Copyright (c) 2001 by Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPAN_H +#define EPAN_H + +#include +#include "frame_data.h" +#include "column_info.h" +#include "register.h" + +typedef struct _epan_dissect_t epan_dissect_t; + +#include "dfilter/dfilter.h" + +/* init the whole epan module, this is used to be called only once in a program */ +void epan_init(void (*register_all_protocols)(register_cb cb, gpointer client_data), + void (*register_all_handoffs)(register_cb cb, gpointer client_data), + register_cb cb, + void *client_data, + void (*report_failure)(const char *, va_list), + void (*report_open_failure)(const char *, int, gboolean), + void (*report_read_failure)(const char *, int)); +/* cleanup the whole epan module, this is used to be called only once in a program */ +void epan_cleanup(void); +/* Initialize the table of conversations. */ +void epan_conversation_init(void); +/* Initialize the table of circuits. */ +/* XXX - what is a circuit and should this better be combined with epan_conversation_init? */ +void epan_circuit_init(void); + +/* A client will create one epan_t for an entire dissection session. + * A single epan_t will be used to analyze the entire sequence of packets, + * sequentially, in a single session. A session corresponds to a single + * packet trace file. The reaons epan_t exists is that some packets in + * some protocols cannot be decoded without knowledge of previous packets. + * This inter-packet "state" is stored in the epan_t. + */ +/* XXX - NOTE: epan_t, epan_new and epan_free are currently unused! */ +typedef struct epan_session epan_t; + +epan_t* +epan_new(void); + +void +epan_free(epan_t*); + +extern gchar* +epan_get_version(void); + +/* get a new single packet dissection */ +/* should be freed using epan_dissect_free() after packet dissection completed */ +epan_dissect_t* +epan_dissect_new(gboolean create_proto_tree, gboolean proto_tree_visible); + +/* run a single packet dissection */ +void +epan_dissect_run(epan_dissect_t *edt, void* pseudo_header, + const guint8* data, frame_data *fd, column_info *cinfo); + +/* Prime a proto_tree using the fields/protocols used in a dfilter. */ +void +epan_dissect_prime_dfilter(epan_dissect_t *edt, const dfilter_t *dfcode); + +/* fill the dissect run output into the packet list columns */ +void +epan_dissect_fill_in_columns(epan_dissect_t *edt); + +/* free a single packet dissection */ +void +epan_dissect_free(epan_dissect_t* edt); + +#endif /* EPAN_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/epan_dissect.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/epan_dissect.h new file mode 100644 index 00000000..9f40f39a --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/epan_dissect.h @@ -0,0 +1,44 @@ +/* epan_dissect.h + * + * $Id: epan_dissect.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark Protocol Analyzer Library + * + * Copyright (c) 2001 by Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPAN_DISSECT_H +#define EPAN_DISSECT_H + +#include "tvbuff.h" +#include "proto.h" +#include "packet_info.h" + +/* Dissection of a single byte array. Holds tvbuff info as + * well as proto_tree info. As long as the epan_dissect_t for a byte + * array is in existence, you must not free or move that byte array, + * as the structures that the epan_dissect_t contains might have pointers + * to addresses in your byte array. + */ +struct _epan_dissect_t { + tvbuff_t *tvb; + proto_tree *tree; + packet_info pi; +}; + + +#endif /* EPAN_DISSECT_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/etypes.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/etypes.h new file mode 100644 index 00000000..34898676 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/etypes.h @@ -0,0 +1,408 @@ +/* etypes.h + * Defines ethernet packet types, similar to tcpdump's ethertype.h + * + * $Id: etypes.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ETYPES_H__ +#define __ETYPES_H__ + +/* + * Maximum length of an IEEE 802.3 frame; Ethernet type/length values + * greater than it are types, Ethernet type/length values less than or + * equal to it are lengths. + */ +#define IEEE_802_3_MAX_LEN 1500 + +#ifndef ETHERTYPE_UNK +#define ETHERTYPE_UNK 0x0000 +#endif + +/* Sources: + * http://www.iana.org/assignments/ethernet-numbers + * TCP/IP Illustrated, Volume 1 + * RFCs 894, 1042, 826 + * tcpdump's ethertype.h + * http://www.cavebear.com/CaveBear/Ethernet/ + * http://standards.ieee.org/regauth/ethertype/type-pub.html + * http://standards.ieee.org/regauth/ethertype/eth.txt + * (The first of the two IEEE URLs is the one that the "EtherType Field + * Public Assignments" link on the page at + * + * http://standards.ieee.org/regauth/ethertype/index.shtml + * + * goes to, but it is redirected to the second of those - i.e., both + * of the IEEE URLs ultimately go to the same page.) + */ + +/* Order these values by number */ + +#ifndef ETHERTYPE_XNS_IDP +#define ETHERTYPE_XNS_IDP 0x0600 +#endif + +#ifndef ETHERTYPE_IP +#define ETHERTYPE_IP 0x0800 +#endif + +#ifndef ETHERTYPE_X25L3 +#define ETHERTYPE_X25L3 0x0805 +#endif + +#ifndef ETHERTYPE_ARP +#define ETHERTYPE_ARP 0x0806 +#endif + +#ifndef ETHERTYPE_WOL +#define ETHERTYPE_WOL 0x0842 /* Wake on LAN. Not offically registered. */ +#endif + +#ifndef ETHERTYPE_WMX_M2M +#define ETHERTYPE_WMX_M2M 0x08f0 +#endif + +#ifndef ETHERTYPE_VINES_IP +#define ETHERTYPE_VINES_IP 0x0bad +#endif + +#ifndef ETHERTYPE_VINES_ECHO +#define ETHERTYPE_VINES_ECHO 0x0baf +#endif + +#ifndef ETHERTYPE_TRAIN +/* + * Created by Microsoft Network Monitor as a summary packet. + */ +#define ETHERTYPE_TRAIN 0x1984 +#endif + +#ifndef ETHERTYPE_CGMP +#define ETHERTYPE_CGMP 0x2001 +#endif + +#ifndef ETHERTYPE_CENTRINO_PROMISC +#define ETHERTYPE_CENTRINO_PROMISC 0x2452 /* Intel Centrino promiscuous packets */ +#endif + +#ifndef ETHERTYPE_3C_NBP_DGRAM +#define ETHERTYPE_3C_NBP_DGRAM 0x3c07 +#endif + +#ifndef ETHERTYPE_EPL_V1 +#define ETHERTYPE_EPL_V1 0x3E3F +#endif + +#ifndef ETHERTYPE_DEC +#define ETHERTYPE_DEC 0x6000 +#endif + +#ifndef ETHERTYPE_DNA_DL +#define ETHERTYPE_DNA_DL 0x6001 +#endif + +#ifndef ETHERTYPE_DNA_RC +#define ETHERTYPE_DNA_RC 0x6002 +#endif + +#ifndef ETHERTYPE_DNA_RT +#define ETHERTYPE_DNA_RT 0x6003 +#endif + +#ifndef ETHERTYPE_LAT +#define ETHERTYPE_LAT 0x6004 +#endif + +#ifndef ETHERTYPE_DEC_DIAG +#define ETHERTYPE_DEC_DIAG 0x6005 +#endif + +#ifndef ETHERTYPE_DEC_CUST +#define ETHERTYPE_DEC_CUST 0x6006 +#endif + +#ifndef ETHERTYPE_DEC_SCA +#define ETHERTYPE_DEC_SCA 0x6007 +#endif + +#ifndef ETHERTYPE_ETHBRIDGE +#define ETHERTYPE_ETHBRIDGE 0x6558 /* transparent Ethernet bridging [RFC1701]*/ +#endif + +#ifndef ETHERTYPE_RAW_FR +#define ETHERTYPE_RAW_FR 0x6559 /* Raw Frame Relay [RFC1701] */ +#endif + +#ifndef ETHERTYPE_REVARP +#define ETHERTYPE_REVARP 0x8035 +#endif + +#ifndef ETHERTYPE_DEC_LB +#define ETHERTYPE_DEC_LB 0x8038 +#endif + +#ifndef ETHERTYPE_DEC_LAST +#define ETHERTYPE_DEC_LAST 0x8041 /* DEC Local Area Systems Transport */ +#endif + +#ifndef ETHERTYPE_ATALK +#define ETHERTYPE_ATALK 0x809b +#endif + +#ifndef ETHERTYPE_SNA +#define ETHERTYPE_SNA 0x80d5 +#endif + +#ifndef ETHERTYPE_AARP +#define ETHERTYPE_AARP 0x80f3 +#endif + +#ifndef ETHERTYPE_VLAN +#define ETHERTYPE_VLAN 0x8100 /* 802.1Q Virtual LAN */ +#endif + +#ifndef ETHERTYPE_NSRP +#define ETHERTYPE_NSRP 0x8133 +#endif + +#ifndef ETHERTYPE_IPX +#define ETHERTYPE_IPX 0x8137 +#endif + +#ifndef ETHERTYPE_SNMP +#define ETHERTYPE_SNMP 0x814c /* SNMP over Ethernet, RFC 1089 */ +#endif + +#ifndef ETHERTYPE_WCP +#define ETHERTYPE_WCP 0x80ff /* Wellfleet Compression Protocol */ +#endif + +#ifndef ETHERTYPE_STP +#define ETHERTYPE_STP 0x8181 /* STP, HIPPI-ST */ +#endif + +#ifndef ETHERTYPE_ISMP +#define ETHERTYPE_ISMP 0x81fd /* Cabletron Interswitch Message Protocol */ +#endif + +#ifndef ETHERTYPE_ISMP_TBFLOOD +#define ETHERTYPE_ISMP_TBFLOOD 0x81ff /* Cabletron Interswitch Message Protocol */ +#endif + +#ifndef ETHERTYPE_IPv6 +#define ETHERTYPE_IPv6 0x86dd +#endif + +#ifndef ETHERTYPE_WLCCP +#define ETHERTYPE_WLCCP 0x872d /* Cisco Wireless Lan Context Control Protocol */ +#endif + +#ifndef ETHERTYPE_MAC_CONTROL +#define ETHERTYPE_MAC_CONTROL 0x8808 +#endif + +#ifndef ETHERTYPE_SLOW_PROTOCOLS +#define ETHERTYPE_SLOW_PROTOCOLS 0x8809 +#endif + +#ifndef ETHERTYPE_PPP +#define ETHERTYPE_PPP 0x880b /* no, this is not PPPoE */ +#endif + +#ifndef ETHERTYPE_COBRANET +#define ETHERTYPE_COBRANET 0x8819 /* Cirrus cobranet */ +#endif + +#ifndef ETHERTYPE_MPLS +#define ETHERTYPE_MPLS 0x8847 /* MPLS unicast packet */ +#endif + +#ifndef ETHERTYPE_MPLS_MULTI +#define ETHERTYPE_MPLS_MULTI 0x8848 /* MPLS multicast packet */ +#endif + +#ifndef ETHERTYPE_FOUNDRY +#define ETHERTYPE_FOUNDRY 0x885a /* Some Foundry proprietary protocol */ +#endif + +#ifndef ETHERTYPE_PPPOED +#define ETHERTYPE_PPPOED 0x8863 /* PPPoE Discovery Protocol */ +#endif + +#ifndef ETHERTYPE_PPPOES +#define ETHERTYPE_PPPOES 0x8864 /* PPPoE Session Protocol */ +#endif + +#ifndef ETHERTYPE_INTEL_ANS +#define ETHERTYPE_INTEL_ANS 0x886d /* Intel ANS (NIC teaming) http://www.intel.com/support/network/adapter/ans/probes.htm */ +#endif + +#ifndef ETHERTYPE_MS_NLB_HEARTBEAT +#define ETHERTYPE_MS_NLB_HEARTBEAT 0x886f /* MS Network Load Balancing heartbeat http://www.microsoft.com/technet/treeview/default.asp?url=/TechNet/prodtechnol/windows2000serv/deploy/confeat/nlbovw.asp */ +#endif + +#ifndef ETHERTYPE_HOMEPLUG +#define ETHERTYPE_HOMEPLUG 0x887B /* IEEE assigned Ethertype */ +#endif + +#ifndef ETHERTYPE_CDMA2000_A10_UBS +#define ETHERTYPE_CDMA2000_A10_UBS 0x8881 /* the byte stream protocol that is used for IP based micro-mobility bearer interfaces (A10) in CDMA2000(R)-based wireless networks */ +#endif + +#ifndef ETHERTYPE_EAPOL +#define ETHERTYPE_EAPOL 0x888e /* 802.1x Authentication */ +#endif + +#ifndef ETHERTYPE_PROFINET +#define ETHERTYPE_PROFINET 0x8892 /* PROFIBUS PROFINET protocol */ +#endif + +#ifndef ETHERTYPE_HYPERSCSI +#define ETHERTYPE_HYPERSCSI 0x889A /* HyperSCSI */ +#endif + +#ifndef ETHERTYPE_CSM_ENCAPS +#define ETHERTYPE_CSM_ENCAPS 0x889B /* Mindspeed Technologies www.mindspeed.com */ +#endif + +#ifndef ETHERTYPE_TELKONET +#define ETHERTYPE_TELKONET 0x88A1 /* Telkonet powerline ethernet */ +#endif + +#ifndef ETHERTYPE_AOE +#define ETHERTYPE_AOE 0x88A2 +#endif + +#ifndef ETHERTYPE_ECATF +#define ETHERTYPE_ECATF 0x88A4 /* Ethernet type for EtherCAT frames */ +#endif + +#ifndef ETHERTYPE_IEEE_802_1AD +#define ETHERTYPE_IEEE_802_1AD 0x88A8 /* IEEE 802.1ad Provider Bridge, Q-in-Q */ +#endif + +#ifndef ETHERTYPE_EPL_V2 +#define ETHERTYPE_EPL_V2 0x88AB +#endif + +#ifndef ETHERTYPE_BRDWALK +#define ETHERTYPE_BRDWALK 0x88AE +#endif + +#ifndef ETHERTYPE_IEEE802_OUI_EXTENDED +#define ETHERTYPE_IEEE802_OUI_EXTENDED 0x88B7 /* IEEE 802a OUI Extended Ethertype */ +#endif + +#ifndef ETHERTYPE_IEC61850_GOOSE +#define ETHERTYPE_IEC61850_GOOSE 0x88b8 /* IEC 61850 is a global standard for the use in utility communication,*/ +#endif /* in particular for the information exchange between IED's in a power */ + /* transmission or distribution substation. */ + /* There are three types of application services + that use a specific EtherType. GOOSE uses + EtherType field 88b8, GSE management services + uses EtherType field 88b9. These two protocols + are defined in IEC 61850-8-1. SV (Sampled + Value Transmission) uses EtherType field + 88ba; the protocol is defined in IEC 61850-9-1 + and IEC 61850-9-2. */ + +#ifndef ETHERTYPE_IEC61850_GSE +#define ETHERTYPE_IEC61850_GSE 0x88b9 /* IEC 61850 is a global standard for the use in utility communication,*/ +#endif /* in particular for the information exchange between IED's in a power */ + +#ifndef ETHERTYPE_IEC61850_SV +#define ETHERTYPE_IEC61850_SV 0x88ba /* IEC 61850 is a global standard for the use in utility communication,*/ +#endif /* in particular for the information exchange between IED's in a power */ + +#ifndef ETHERTYPE_TIPC +#define ETHERTYPE_TIPC 0x88ca /* TIPC (Transparent Inter Process Communication, */ +#endif /* http://tipc.sourceforge.net/) Ericsson Research Canada Inc */ + +#ifndef ETHERTYPE_RSN_PREAUTH +#define ETHERTYPE_RSN_PREAUTH 0x88c7 /* 802.11i Pre-Authentication */ +#endif + +#ifndef ETHERTYPE_LLDP +#define ETHERTYPE_LLDP 0x88cc /* IEEE 802.1AB Link Layer Discovery Protocol (LLDP) */ +#endif + +#ifndef ETHERTYPE_SERCOS +#define ETHERTYPE_SERCOS 0x88cd /* SERCOS interface real-time protocol for motion control */ +#endif + +#ifndef ETHERTYPE_3GPP2 +#define ETHERTYPE_3GPP2 0x88d2 /* This will be used in a revision of the Interoperabi */ +#endif /* Specification (IOS) for cdma2000 Access Network Interfaces (document numbers A.S0011-B */ + /* through A.S0017-B v1.0). This document already uses the Ether type 8881 */ + +#ifndef ETHERTYPE_LLTD +#define ETHERTYPE_LLTD 0x88d9 /* Link Layer Topology Discovery (LLTD) */ +#endif + +#ifndef ETHERTYPE_MRP +#define ETHERTYPE_MRP 0x88e3 /* IEC 61158-6-10 Media Redundancy Protocol (MRP) */ +#endif + +#ifndef ETHERTYPE_IEEE_802_1AH +#define ETHERTYPE_IEEE_802_1AH 0x88F0 /* IEEE 802.1ah Provider Backbone Bridge Mac-in-Mac */ +#endif + +#ifndef ETHERTYPE_PTP +#define ETHERTYPE_PTP 0x88F7 /* IEEE1588v2 (PTPv2) over Ethernet */ +#endif /* in particular for the information exchange between IED's in a power */ + /* transmission or distribution substation. */ + /* There are three types of application services */ + +#ifndef ETHERTYPE_PRP +#define ETHERTYPE_PRP 0x88FB /* Parallel Redundancy Protocol (IEC62439 Chapter 6) */ +#endif + +#ifndef ETHERTYPE_CFM +#define ETHERTYPE_CFM 0x8902 /* IEEE 802.1ag Connectivity Fault Management */ +#endif /* (CFM) protocol. */ + +#ifndef ETHERTYPE_FCOE +#define ETHERTYPE_FCOE 0x8906 /* Fibre Channel over Ethernet */ +#endif + +#ifndef ETHERTYPE_LOOP +#define ETHERTYPE_LOOP 0x9000 /* used for layer 2 testing (do i see my own frames on the wire) */ +#endif + +#ifndef ETHERTYPE_RTMAC +#define ETHERTYPE_RTMAC 0x9021 /* RTnet: Real-Time Media Access Control */ +#endif + +#ifndef ETHERTYPE_RTCFG +#define ETHERTYPE_RTCFG 0x9022 /* RTnet: Real-Time Configuration Protocol */ +#endif + +#ifndef ETHERTYPE_LLT +#define ETHERTYPE_LLT 0xCAFE /* Veritas Low Latency Transport (not officially registered) */ +#endif + +#ifndef ETHERTYPE_FCFT +/* type used to transport FC frames+MDS hdr internal to Cisco's MDS switch */ +#define ETHERTYPE_FCFT 0xFCFC +#endif + +extern const value_string etype_vals[]; + +#endif /* etypes.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ex-opt.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ex-opt.h new file mode 100644 index 00000000..5839b726 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ex-opt.h @@ -0,0 +1,44 @@ +/* + * ex-opt.h + * + * eXtension command line options + * + * (c) 2006, Luis E. Garcia Ontanon + * + * $Id: ex-opt.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _EX_OPT_H +#define _EX_OPT_H + +/* will be called by main each time a -X option is found */ +extern gboolean ex_opt_add(const gchar* optarg); + +/* yields the number of arguments of a given key obviously returns 0 if there aren't */ +extern gint ex_opt_count(const gchar* key); + +/* fetches the nth argument of a given key returns NULL if there isn't */ +extern const gchar* ex_opt_get_index(const gchar* key, guint index); + +/* extracts the next value of a given key */ +extern const gchar* ex_opt_get_next(const gchar* key); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/except.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/except.h new file mode 100644 index 00000000..42e62ce5 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/except.h @@ -0,0 +1,158 @@ +/* + * Portable Exception Handling for ANSI C. + * Copyright (C) 1999 Kaz Kylheku + * + * Free Software License: + * + * All rights are reserved by the author, with the following exceptions: + * Permission is granted to freely reproduce and distribute this software, + * possibly in exchange for a fee, provided that this copyright notice appears + * intact. Permission is also granted to adapt this software to produce + * derivative works, as long as the modified versions carry this copyright + * notice and additional notices stating that the work has been modified. + * This source code may be translated into executable form and incorporated + * into proprietary software; there is no requirement for such software to + * contain a copyright notice related to this source. + * + * $Id: except.h 3992 2008-06-10 03:13:11Z dgu $ + * $Name: $ + */ + +/* + * Modified to support throwing an exception with a null message pointer, + * and to have the message not be const (as we generate messages with + * "g_strdup_sprintf()", which means they need to be freed; using + * a null message means that we don't have to use a special string + * for exceptions with no message, and don't have to worry about + * not freeing that). + */ + +#ifndef XCEPT_H +#define XCEPT_H + +#include +#include +#include + +#define XCEPT_GROUP_ANY 0 +#define XCEPT_CODE_ANY 0 +#define XCEPT_BAD_ALLOC 1 + +#ifdef __cplusplus +extern "C" { +#endif + +enum { except_no_call, except_call }; + +typedef struct { + unsigned long except_group; + unsigned long except_code; +} except_id_t; + +typedef struct { + except_id_t volatile except_id; + const char *volatile except_message; + void *volatile except_dyndata; +} except_t; + +struct except_cleanup { + void (*except_func)(void *); + void *except_context; +}; + +struct except_catch { + const except_id_t *except_id; + size_t except_size; + except_t except_obj; + jmp_buf except_jmp; +}; + +enum except_stacktype { + XCEPT_CLEANUP, XCEPT_CATCHER +}; + +struct except_stacknode { + struct except_stacknode *except_down; + enum except_stacktype except_type; + union { + struct except_catch *except_catcher; + struct except_cleanup *except_cleanup; + } except_info; +}; + +/* private functions made external so they can be used in macros */ +extern void except_setup_clean(struct except_stacknode *, + struct except_cleanup *, void (*)(void *), void *); +extern void except_setup_try(struct except_stacknode *, + struct except_catch *, const except_id_t [], size_t); +extern struct except_stacknode *except_pop(void); + +/* public interface functions */ +extern int except_init(void); +extern void except_deinit(void); +extern void except_rethrow(except_t *); +extern void except_throw(long, long, const char *); +extern void except_throwd(long, long, const char *, void *); +extern void except_throwf(long, long, const char *, ...); +extern void (*except_unhandled_catcher(void (*)(except_t *)))(except_t *); +extern unsigned long except_code(except_t *); +extern unsigned long except_group(except_t *); +extern const char *except_message(except_t *); +extern void *except_data(except_t *); +extern void *except_take_data(except_t *); +extern void except_set_allocator(void *(*)(size_t), void (*)(void *)); +extern void *except_alloc(size_t); +extern void except_free(void *); + +#define except_code(E) ((E)->except_id.except_code) +#define except_group(E) ((E)->except_id.except_group) +#define except_message(E) ((E)->except_message) +#define except_data(E) ((E)->except_dyndata) + +#ifdef __cplusplus +} +#endif + +/* + * void except_cleanup_push(void (*)(void *), void *); + * void except_cleanup_pop(int); + * void except_checked_cleanup_pop(void (*)(void *), int); + * void except_try_push(const except_id_t [], size_t, except_t **); + * void except_try_pop(void); + */ + +#define except_cleanup_push(F, C) \ + { \ + struct except_stacknode except_sn; \ + struct except_cleanup except_cl; \ + except_setup_clean(&except_sn, &except_cl, F, C) + +#define except_cleanup_pop(E) \ + except_pop(); \ + if (E) \ + except_cl.except_func(except_cl.except_context); \ + } + +#define except_checked_cleanup_pop(F, E) \ + except_pop(); \ + assert (except_cl.except_func == (F)); \ + if (E) \ + except_cl.except_func(except_cl.except_context); \ + } + +#define except_try_push(ID, NUM, PPE) \ + { \ + struct except_stacknode except_sn; \ + struct except_catch except_ch; \ + except_setup_try(&except_sn, &except_ch, ID, NUM); \ + if (setjmp(except_ch.except_jmp)) \ + *(PPE) = &except_ch.except_obj; \ + else \ + *(PPE) = 0 + +#define except_try_pop() \ + except_free(except_ch.except_obj.except_dyndata); \ + except_pop(); \ + } + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/exceptions.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/exceptions.h new file mode 100644 index 00000000..52abdfd7 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/exceptions.h @@ -0,0 +1,319 @@ +#ifndef __EXCEPTIONS_H__ +#define __EXCEPTIONS_H__ + +/* $Id $ */ + +#ifndef XCEPT_H +#include "except.h" +#endif + +/* Wireshark has only one exception group, to make these macros simple */ +#define XCEPT_GROUP_WIRESHARK 1 + +/* Wireshark's exceptions */ + +/** + Index is out of range. + An attempt was made to read past the end of a buffer. + This generally means that the capture was done with a "slice" + length or "snapshot" length less than the maximum packet size, + and a link-layer packet was cut short by that, so not all of the + data in the link-layer packet was available. +**/ +#define BoundsError 1 + +/** + Index is beyond reported length (not cap_len) + An attempt was made to read past the logical end of a buffer. This + differs from a BoundsError in that the parent protocol established a + limit past which this dissector should not process in the buffer and that + limit was execeeded. + This generally means that the packet is invalid, i.e. whatever + code constructed the packet and put it on the wire didn't put enough + data into it. It is therefore currently reported as a "Malformed + packet". + However, it also happens in some cases where the packet was fragmented + and the fragments weren't reassembled. We need to add another length + field to a tvbuff, so that "length of the packet from the link layer" + and "length of the packet were it fully reassembled" are different, + and going past the first of those without going past the second would + throw a different exception, which would be reported as an "Unreassembled + packet" rather than a "Malformed packet". +**/ +#define ReportedBoundsError 2 + +/** + During dfilter parsing +**/ +#define TypeError 3 + +/** + A bug was detected in a dissector. + + DO NOT throw this with THROW(); that means that no details about + the dissector error will be reported. (Instead, the message will + blame you for not providing details.) + + Instead, use the DISSECTOR_ASSERT(), etc. macros in epan/proto.h. +**/ +#define DissectorError 4 + +/** + Index is out of range. + An attempt was made to read past the end of a buffer. + This error is specific to SCSI data transfers where for some CDBs + it is normal that the data PDU might be short. + I.e. ReportLuns initially called with allocation_length=8, just enough + to get the "size" of lun list back after which the initiator will + reissue the command with an allocation_length that is big enough. +**/ +#define ScsiBoundsError 5 + +/** + Running out of memory. + A dissector tried to allocate memory but that failed. +**/ +#define OutOfMemoryError 6 + + +/* Usage: + * + * TRY { + * code; + * } + * + * CATCH(exception) { + * code; + * } + * + * CATCH2(exception1, exception2) { + * code; + * } + * + * CATCH_ALL { + * code; + * } + * + * FINALLY { + * code; + * } + * + * ENDTRY; + * + * ********* Never use 'goto' or 'return' inside the TRY, CATCH, CATCH_ALL, + * ********* or FINALLY blocks. Execution must proceed through ENDTRY before + * ********* branching out. + * + * This is really something like: + * + * { + * caught = FALSE: + * x = setjmp(); + * if (x == 0) { + * + * } + * if (!caught && x == 1) { + * caught = TRUE; + * + * } + * if (!caught && x == 2) { + * caught = TRUE; + * + * } + * if (!caught && (x == 3 || x == 4)) { + * caught = TRUE; + * + * } + * if (!caught && x != 0) { + * caught = TRUE; + * + * } + * + * if(!caught) { + * RETHROW(x) + * } + * } + * + * All CATCH's must precede a CATCH_ALL. + * FINALLY must occur after any CATCH or CATCH_ALL. + * ENDTRY marks the end of the TRY code. + * TRY and ENDTRY are the mandatory parts of a TRY block. + * CATCH, CATCH_ALL, and FINALLY are all optional (although + * you'll probably use at least one, otherwise why "TRY"?) + * + * GET_MESSAGE returns string ptr to exception message + * when exception is thrown via THROW_MESSAGE() + * + * To throw/raise an exception. + * + * THROW(exception) + * RETHROW rethrow the caught exception + * + * A cleanup callback is a function called in case an exception occurs + * and is not caught. It should be used to free any dynamically-allocated data. + * A pop or call_and_pop should occur at the same statement-nesting level + * as the push. + * + * CLEANUP_CB_PUSH(func, data) + * CLEANUP_CB_POP + * CLEANUP_CB_CALL_AND_POP + */ + +/* we do up to three passes through the bit of code after except_try_push(), + * and except_state is used to keep track of where we are. + */ +#define EXCEPT_CAUGHT 1 /* exception has been caught, no need to rethrow at + * END_TRY */ + +#define EXCEPT_RETHROWN 2 /* the exception was rethrown from a CATCH + * block. Don't reenter the CATCH blocks, but do + * execute FINALLY and rethrow at END_TRY */ + +#define EXCEPT_FINALLY 4 /* we've entered the FINALLY block - don't allow + * RETHROW, and don't reenter FINALLY if a + * different exception is thrown */ + +#define TRY \ +{\ + except_t *exc; \ + volatile int except_state = 0; \ + static const except_id_t catch_spec[] = { \ + { XCEPT_GROUP_WIRESHARK, XCEPT_CODE_ANY } }; \ + except_try_push(catch_spec, 1, &exc); \ + \ + if(except_state & EXCEPT_CAUGHT) \ + except_state |= EXCEPT_RETHROWN; \ + except_state &= ~EXCEPT_CAUGHT; \ + \ + if (except_state == 0 && exc == 0) \ + /* user's code goes here */ + +#define ENDTRY \ + /* rethrow the exception if necessary */ \ + if(!(except_state&EXCEPT_CAUGHT) && exc != 0) \ + except_rethrow(exc); \ + except_try_pop();\ +} + +/* the (except_state |= EXCEPT_CAUGHT) in the below is a way of setting + * except_state before the user's code, without disrupting the user's code if + * it's a one-liner. + */ +#define CATCH(x) \ + if (except_state == 0 && exc != 0 && exc->except_id.except_code == (x) && \ + (except_state |= EXCEPT_CAUGHT)) \ + /* user's code goes here */ + +#define CATCH2(x,y) \ + if (except_state == 0 && exc != 0 && \ + (exc->except_id.except_code == (x) || exc->except_id.except_code == (y)) && \ + (except_state|=EXCEPT_CAUGHT)) \ + /* user's code goes here */ + +#define CATCH_ALL \ + if (except_state == 0 && exc != 0 && \ + (except_state|=EXCEPT_CAUGHT)) \ + /* user's code goes here */ + + +#define FINALLY \ + if( !(except_state & EXCEPT_FINALLY) && (except_state|=EXCEPT_FINALLY)) \ + /* user's code goes here */ + +#define THROW(x) \ + except_throw(XCEPT_GROUP_WIRESHARK, (x), NULL) + +#define THROW_MESSAGE(x, y) \ + except_throw(XCEPT_GROUP_WIRESHARK, (x), (y)) + +#define GET_MESSAGE except_message(exc) + +#define RETHROW \ + { \ + /* check we're in a catch block */ \ + g_assert(except_state == EXCEPT_CAUGHT); \ + /* we can't use except_rethrow here, as that pops a catch block \ + * off the stack, and we don't want to do that, because we want to \ + * excecute the FINALLY {} block first. \ + * except_throw doesn't provide an interface to rethrow an existing \ + * exception; however, longjmping back to except_try_push() has the \ + * desired effect. \ + * \ + * Note also that THROW and RETHROW should provide much the same \ + * functionality in terms of which blocks to enter, so any messing \ + * about with except_state in here would indicate that THROW is \ + * doing the wrong thing. \ + */ \ + longjmp(except_ch.except_jmp,1); \ + } + +#define EXCEPT_CODE except_code(exc) + +/* Register cleanup functions in case an exception is thrown and not caught. + * From the Kazlib documentation, with modifications for use with the + * Wireshark-specific macros: + * + * CLEANUP_PUSH(func, arg) + * + * The call to CLEANUP_PUSH shall be matched with a call to + * CLEANUP_CALL_AND_POP or CLEANUP_POP which must occur in the same + * statement block at the same level of nesting. This requirement allows + * an implementation to provide a CLEANUP_PUSH macro which opens up a + * statement block and a CLEANUP_POP which closes the statement block. + * The space for the registered pointers can then be efficiently + * allocated from automatic storage. + * + * The CLEANUP_PUSH macro registers a cleanup handler that will be + * called if an exception subsequently occurs before the matching + * CLEANUP_[CALL_AND_]POP is executed, and is not intercepted and + * handled by a try-catch region that is nested between the two. + * + * The first argument to CLEANUP_PUSH is a pointer to the cleanup + * handler, a function that returns nothing and takes a single + * argument of type void*. The second argument is a void* value that + * is registered along with the handler. This value is what is passed + * to the registered handler, should it be called. + * + * Cleanup handlers are called in the reverse order of their nesting: + * inner handlers are called before outer handlers. + * + * The program shall not leave the cleanup region between + * the call to the macro CLEANUP_PUSH and the matching call to + * CLEANUP_[CALL_AND_]POP by means other than throwing an exception, + * or calling CLEANUP_[CALL_AND_]POP. + * + * Within the call to the cleanup handler, it is possible that new + * exceptions may happen. Such exceptions must be handled before the + * cleanup handler terminates. If the call to the cleanup handler is + * terminated by an exception, the behavior is undefined. The exception + * which triggered the cleanup is not yet caught; thus the program + * would be effectively trying to replace an exception with one that + * isn't in a well-defined state. + * + * + * CLEANUP_POP and CLEANUP_CALL_AND_POP + * + * A call to the CLEANUP_POP or CLEANUP_CALL_AND_POP macro shall match + * each call to CLEANUP_PUSH which shall be in the same statement block + * at the same nesting level. It shall match the most recent such a + * call that is not matched by a previous CLEANUP_[CALL_AND_]POP at + * the same level. + * + * These macros causes the registered cleanup handler to be removed. If + * CLEANUP_CALL_AND_POP is called, the cleanup handler is called. + * In that case, the registered context pointer is passed to the cleanup + * handler. If CLEANUP_POP is called, the cleanup handler is not called. + * + * The program shall not leave the region between the call to the + * macro CLEANUP_PUSH and the matching call to CLEANUP_[CALL_AND_]POP + * other than by throwing an exception, or by executing the + * CLEANUP_CALL_AND_POP. + * + */ + + +#define CLEANUP_PUSH(f,a) except_cleanup_push((f),(a)) +#define CLEANUP_POP except_cleanup_pop(0) +#define CLEANUP_CALL_AND_POP except_cleanup_pop(1) + +#endif /* __EXCEPTIONS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/expert.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/expert.h new file mode 100644 index 00000000..3c32f25e --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/expert.h @@ -0,0 +1,70 @@ +/* expert.h + * Collecting of Expert information. + * + * For further info, see: http://wiki.wireshark.org/Development/ExpertInfo + * + * $Id: expert.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __EXPERT_H__ +#define __EXPERT_H__ + +#include "gnuc_format_check.h" +#include +#include "value_string.h" + + +/** only for internal and display use */ +typedef struct expert_info_s { + guint32 packet_num; + int group; + int severity; + gchar * protocol; + gchar * summary; + proto_item *pitem; +} expert_info_t; + +WS_VAR_IMPORT const value_string expert_severity_vals[]; +WS_VAR_IMPORT const value_string expert_group_vals[]; + +extern void +expert_init(void); + +extern void +expert_cleanup(void); + +extern int +expert_get_highest_severity(void); + +/** Add an expert info. + + @param pinfo packet info of the currently processed packet + @param pi current protocol item (or NULL) + @param group the expert group (like PI_CHECKSUM) + @param severity the expert severity (like PI_WARN) + @param format printf like format string with further infos + */ +extern void +expert_add_info_format(packet_info *pinfo, proto_item *pi, int group, + int severity, const char *format, ...) + GNUC_FORMAT_CHECK(printf, 5, 6); + +#endif /* __EXPERT_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/filesystem.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/filesystem.h new file mode 100644 index 00000000..5b9c9fa2 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/filesystem.h @@ -0,0 +1,248 @@ +/* filesystem.h + * Filesystem utility definitions + * + * $Id: filesystem.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef FILESYSTEM_H +#define FILESYSTEM_H + +/* + * Default profile name. + */ +#define DEFAULT_PROFILE "Default" + + +/* + * Get the pathname of the directory from which the executable came, + * and save it for future use. Returns NULL on success, and a + * g_mallocated string containing an error on failure. + */ +extern char *init_progfile_dir(const char *arg0); + +/* + * Get the directory in which the program resides. + */ +extern const char *get_progfile_dir(void); + +/* + * Get the directory in which plugins are stored; this must not be called + * before init_progfile_dir() is called, as they might be stored in a + * subdirectory of the program file directory. + */ +extern const char *get_plugin_dir(void); + +/* + * Get the flag indicating whether we're running from a build + * directory. + */ +extern gboolean running_in_build_directory(void); + +/* + * Get the directory in which global configuration files are + * stored. + */ +extern const char *get_datafile_dir(void); + +/* + * Construct the path name of a global configuration file, given the + * file name. + * + * The returned file name was g_malloc()'d so it must be g_free()d when the + * caller is done with it. + */ +extern char *get_datafile_path(const char *filename); + +/* + * Get the directory in which files that, at least on UNIX, are + * system files (such as "/etc/ethers") are stored; on Windows, + * there's no "/etc" directory, so we get them from the Wireshark + * global configuration and data file directory. + */ +extern const char *get_systemfile_dir(void); + +/* + * Set the configuration profile name to be used for storing + * personal configuration files. + */ +extern void set_profile_name(const gchar *profilename); + +/* + * Get the current configuration profile name used for storing + * personal configuration files. + */ +extern const char *get_profile_name(void); + +/* + * Get the directory used to store configuration profile directories. + */ +extern const char *get_profiles_dir(void); + +/* + * Check if given configuration profile exists. + */ +extern gboolean profile_exists(const gchar *profilename); + +/* + * Create a directory for the given configuration profile. + * If we attempted to create it, and failed, return -1 and + * set "*pf_dir_path_return" to the pathname of the directory we failed + * to create (it's g_mallocated, so our caller should free it); otherwise, + * return 0. + */ +extern int create_persconffile_profile(const char *profilename, + char **pf_dir_path_return); + +/* + * Delete the directory for the given configuration profile. + * If we attempted to delete it, and failed, return -1 and + * set "*pf_dir_path_return" to the pathname of the directory we failed + * to delete (it's g_mallocated, so our caller should free it); otherwise, + * return 0. + */ +extern int delete_persconffile_profile(const char *profilename, + char **pf_dir_path_return); + +/* + * Rename the directory for the given confinguration profile. + */ +extern int rename_persconffile_profile(const char *fromname, const char *toname, + char **pf_from_dir_path_return, + char **pf_to_dir_path_return); + +/* + * Create the directory that holds personal configuration files, if + * necessary. If we attempted to create it, and failed, return -1 and + * set "*pf_dir_path_return" to the pathname of the directory we failed + * to create (it's g_mallocated, so our caller should free it); otherwise, + * return 0. + */ +extern int create_persconffile_dir(char **pf_dir_path_return); + +/* + * Construct the path name of a personal configuration file, given the + * file name. If using configuration profiles this directory will be + * used if "from_profile" is TRUE. + * + * On Win32, if "for_writing" is FALSE, we check whether the file exists + * and, if not, construct a path name relative to the ".wireshark" + * subdirectory of the user's home directory, and check whether that + * exists; if it does, we return that, so that configuration files + * from earlier versions can be read. + * + * The returned file name was g_malloc()'d so it must be g_free()d when the + * caller is done with it. + */ +extern char *get_persconffile_path(const char *filename, gboolean from_profile, + gboolean for_writing); + +/* + * Get the (default) directory in which personal data is stored. + * + * On Win32, this is the "My Documents" folder in the personal profile. + * On UNIX this is simply the current directory. + */ +extern char *get_persdatafile_dir(void); + +/* + * Construct the path name of a file in $TMP/%TEMP% directory. + * Or "/tmp/" (C:\) if that fails. + * + * Return value is malloced so the caller should free it. + */ +extern char *get_tempfile_path(const char *filename); + +/* + * process command line option belonging to the filesystem settings + */ +extern int filesystem_opt(int opt, const char *optarg); + +/* + * Return an error message for UNIX-style errno indications on open or + * create operations. + */ +extern const char *file_open_error_message(int err, gboolean for_writing); + +/* + * Return an error message for UNIX-style errno indications on write + * operations. + */ +extern const char *file_write_error_message(int err); + +/* + * Given a pathname, return the last component. + */ +extern const char *get_basename(const char *); + +/* + * Given a pathname, return a string containing everything but the + * last component. NOTE: this overwrites the pathname handed into + * it.... + */ +extern char *get_dirname(char *); + +/* + * Given a pathname, return: + * + * the errno, if an attempt to "stat()" the file fails; + * + * EISDIR, if the attempt succeeded and the file turned out + * to be a directory; + * + * 0, if the attempt succeeded and the file turned out not + * to be a directory. + */ +extern int test_for_directory(const char *); + +/* + * Given a pathname, return: + * + * the errno, if an attempt to "stat()" the file fails; + * + * ESPIPE, if the attempt succeeded and the file turned out + * to be a FIFO; + * + * 0, if the attempt succeeded and the file turned out not + * to be a FIFO. + */ +extern int test_for_fifo(const char *); + +/* Delete a file */ +extern gboolean deletefile (const char *path); + +/* + * Check, if file is existing. + */ +extern gboolean file_exists(const char *fname); + +/* + * Check, if two filenames are identical (with absolute and relative paths). + */ +extern gboolean files_identical(const char *fname1, const char *fname2); + +#ifdef WIN32 +/* + * utf8 version of getenv, needed to get win32 filename paths + */ +extern char *getenv_utf8(const char *varname); +#endif + +#endif /* FILESYSTEM_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/follow.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/follow.h new file mode 100644 index 00000000..513e7add --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/follow.h @@ -0,0 +1,58 @@ +/* follow.h + * + * $Id: follow.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Copyright 1998 Mike Hall + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __FOLLOW_H__ +#define __FOLLOW_H__ + +#include + +#define MAX_IPADDR_LEN 16 + +/* With MSVC and a libwireshark.dll, we need a special declaration. */ +WS_VAR_IMPORT gboolean empty_tcp_stream; +WS_VAR_IMPORT gboolean incomplete_tcp_stream; + +typedef struct _tcp_stream_chunk { + guint8 src_addr[MAX_IPADDR_LEN]; + guint16 src_port; + guint32 dlen; +} tcp_stream_chunk; + +char* build_follow_filter( packet_info * ); +void reassemble_tcp( gulong, gulong, gulong, const char*, gulong, int, + address *, address *, guint, guint ); +void reset_tcp_reassembly( void ); + +typedef struct { + guint8 ip_address[2][MAX_IPADDR_LEN]; + guint32 port[2]; + unsigned int bytes_written[2]; + gboolean is_ipv6; +} follow_stats_t; + +void follow_stats(follow_stats_t* stats); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/frame_data.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/frame_data.h new file mode 100644 index 00000000..15d0d021 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/frame_data.h @@ -0,0 +1,79 @@ +/* frame_data.h + * Definitions for frame_data structures and routines + * + * $Id: frame_data.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __FRAME_DATA_H__ +#define __FRAME_DATA_H__ + +#include "column_info.h" +#include "tvbuff.h" +#include + + +/* XXX - some of this stuff is used only while a packet is being dissected; + should we keep that stuff in the "packet_info" structure, instead, to + save memory? */ +/* The frame number is the ordinal number of the frame in the capture, so + it's 1-origin. In various contexts, 0 as a frame number means "frame + number unknown". */ +typedef struct _frame_data { + struct _frame_data *next; /* Next element in list */ + struct _frame_data *prev; /* Previous element in list */ + GSList *pfd; /* Per frame proto data */ + guint32 num; /* Frame number */ + guint32 pkt_len; /* Packet length */ + guint32 cap_len; /* Amount actually captured */ + guint32 cum_bytes; /* Cumulative bytes into the capture */ + nstime_t abs_ts; /* Absolute timestamp */ + nstime_t rel_ts; /* Relative timestamp (yes, it can be negative) */ + nstime_t del_dis_ts; /* Delta timestamp to previous displayed frame (yes, it can be negative) */ + nstime_t del_cap_ts; /* Delta timestamp to previous captured frame (yes, it can be negative) */ + gint64 file_off; /* File offset */ + int lnk_t; /* Per-packet encapsulation/data-link type */ + struct { + unsigned int passed_dfilter : 1; /* 1 = display, 0 = no display */ + unsigned int encoding : 2; /* Character encoding (ASCII, EBCDIC...) */ + unsigned int visited : 1; /* Has this packet been visited yet? 1=Yes,0=No*/ + unsigned int marked : 1; /* 1 = marked by user, 0 = normal */ + unsigned int ref_time : 1; /* 1 = marked as a reference time frame, 0 = normal */ + } flags; + void *color_filter; /* Per-packet matching color_filter_t object */ + col_expr_t col_expr; /* Column expressions & values */ +} frame_data; + +/* + * A data source. + * Has a tvbuff and a name. + */ +typedef struct { + tvbuff_t *tvb; + char *name; +} data_source; + +/* Utility routines used by packet*.c */ + +extern void p_add_proto_data(frame_data *fd, int proto, void *proto_data); +extern void *p_get_proto_data(frame_data *fd, int proto); +extern void p_remove_proto_data(frame_data *fd, int proto); + +#endif /* __FRAME_DATA__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/frequency-utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/frequency-utils.h new file mode 100644 index 00000000..628bff4d --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/frequency-utils.h @@ -0,0 +1,74 @@ +/* frequency-utils.h + * Frequency conversion utility definitions + * + * $Id: frequency-utils.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2007 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __FREQUENCY_UTILS_H__ +#define __FREQUENCY_UTILS_H__ + +/** @file + * Frequency and channel conversion utilities. + */ + +/** + * Given a center frequency in MHz, return a channel number. + * @param freq Frequency in MHz. + * @return The equivalent channel or -1 if no match is found. + */ +gint +ieee80211_mhz_to_chan(guint freq); + +/** + * Given a channel number and a band type, return a center frequency. + * @param chan Channel number + * @param is_bg TRUE if the channel is a b/g channel, FALSE otherwise. + * @return The equivalent frequency or 0 if no match is found. + */ +guint +ieee80211_chan_to_mhz(gint chan, gboolean is_bg); + +/** + * Given a frequency in MHz, return a string representation. + * @param freq Frequench in MHz. + * @return A string showing the frequency, channel number, and type. The string must be freed with g_free() after use. + */ +gchar* +ieee80211_mhz_to_str(guint freq); + +/* Should this be "(freq < 4920)", or something else? */ +#define FREQ_IS_BG(freq) (freq <= 2484) + +/* + * Editor modelines + * + * Local Variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * ex: set shiftwidth=4 tabstop=8 expandtab + * :indentSize=4:tabSize=8:noTabs=true: + */ + +#endif /* __FREQUENCY_UTILS_H__ */ + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ftypes/ftypes-int.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ftypes/ftypes-int.h new file mode 100644 index 00000000..20528f66 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ftypes/ftypes-int.h @@ -0,0 +1,61 @@ +/* + * $Id: ftypes-int.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2001 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef FTYPES_INT_H +#define FTYPES_INT_H + +#include +#include "ftypes.h" + +#ifdef HAVE_LIBPCRE +#include +#endif /* HAVE_LIBPCRE */ + + +#ifdef HAVE_LIBPCRE +struct _pcre_tuple_t { + char *string; + pcre *re; + pcre_extra *ex; + char *error; +}; +#endif /* HAVE_LIBPCRE */ + +void +ftype_register(enum ftenum ftype, ftype_t *ft); + +/* These are the ftype registration functions that need to be called. + * This list and the initialization function could be produced + * via a script, like the dissector registration, but there's so few + * that I don't mind doing it by hand for now. */ +void ftype_register_bytes(void); +void ftype_register_double(void); +void ftype_register_integers(void); +void ftype_register_ipv4(void); +void ftype_register_guid(void); +void ftype_register_none(void); +void ftype_register_string(void); +void ftype_register_time(void); +void ftype_register_tvbuff(void); +void ftype_register_pcre(void); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ftypes/ftypes.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ftypes/ftypes.h new file mode 100644 index 00000000..498c969c --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ftypes/ftypes.h @@ -0,0 +1,367 @@ +/* ftypes.h + * Definitions for field types + * + * $Id: ftypes.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2001 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +#ifndef FTYPES_H +#define FTYPES_H + +#include +#include "../slab.h" + +/* field types */ +enum ftenum { + FT_NONE, /* used for text labels with no value */ + FT_PROTOCOL, + FT_BOOLEAN, /* TRUE and FALSE come from */ + FT_UINT8, + FT_UINT16, + FT_UINT24, /* really a UINT32, but displayed as 3 hex-digits if FD_HEX*/ + FT_UINT32, + FT_UINT64, + FT_INT8, + FT_INT16, + FT_INT24, /* same as for UINT24 */ + FT_INT32, + FT_INT64, + FT_FLOAT, + FT_DOUBLE, + FT_ABSOLUTE_TIME, + FT_RELATIVE_TIME, + FT_STRING, + FT_STRINGZ, /* for use with proto_tree_add_item() */ + FT_EBCDIC, /* for use with proto_tree_add_item() */ + FT_UINT_STRING, /* for use with proto_tree_add_item() */ + /*FT_UCS2_LE, */ /* Unicode, 2 byte, Little Endian */ + FT_ETHER, + FT_BYTES, + FT_UINT_BYTES, + FT_IPv4, + FT_IPv6, + FT_IPXNET, + FT_FRAMENUM, /* a UINT32, but if selected lets you go to frame with that numbe */ + FT_PCRE, /* a compiled Perl-Compatible Regular Expression object */ + FT_GUID, /* GUID, UUID */ + FT_OID, /* OBJECT IDENTIFIER */ + FT_NUM_TYPES /* last item number plus one */ +}; + +#define IS_FT_INT(ft) ((ft)==FT_INT8||(ft)==FT_INT16||(ft)==FT_INT24||(ft)==FT_INT32) +#define IS_FT_UINT(ft) ((ft)==FT_UINT8||(ft)==FT_UINT16||(ft)==FT_UINT24||(ft)==FT_UINT32||(ft)==FT_FRAMENUM) +#define IS_FT_TIME(ft) ((ft)==FT_ABSOLUTE_TIME||(ft)==FT_RELATIVE_TIME) +#define IS_FT_STRING(ft) ((ft)==FT_STRING||(ft)==FT_STRINGZ) + +typedef enum ftenum ftenum_t; +typedef struct _ftype_t ftype_t; + +/* String representation types. */ +enum ftrepr { + FTREPR_DISPLAY, + FTREPR_DFILTER +}; + +typedef enum ftrepr ftrepr_t; + +#ifdef HAVE_LIBPCRE +typedef struct _pcre_tuple_t pcre_tuple_t; +#endif /* HAVE_LIBPCRE */ + +/* Initialize the ftypes subsytem. Called once. */ +void +ftypes_initialize(void); + +/* ---------------- FTYPE ----------------- */ + +/* Return a string representing the name of the type */ +const char* +ftype_name(ftenum_t ftype); + +/* Return a string presenting a "pretty" representation of the + * name of the type. The pretty name means more to the user than + * that "FT_*" name. */ +const char* +ftype_pretty_name(ftenum_t ftype); + +/* Returns length of field in packet, or 0 if not determinable/defined. */ +int +ftype_length(ftenum_t ftype); + +gboolean +ftype_can_slice(enum ftenum ftype); + +gboolean +ftype_can_eq(enum ftenum ftype); + +gboolean +ftype_can_ne(enum ftenum ftype); + +gboolean +ftype_can_gt(enum ftenum ftype); + +gboolean +ftype_can_ge(enum ftenum ftype); + +gboolean +ftype_can_lt(enum ftenum ftype); + +gboolean +ftype_can_le(enum ftenum ftype); + +gboolean +ftype_can_bitwise_and(enum ftenum ftype); + +gboolean +ftype_can_contains(enum ftenum ftype); + +gboolean +ftype_can_matches(enum ftenum ftype); + +/* ---------------- FVALUE ----------------- */ + +#include +#include + +#include +#include +#include + +typedef struct _fvalue_t { + ftype_t *ftype; + union { + /* Put a few basic types in here */ + gpointer pointer; + guint32 uinteger; + gint32 sinteger; + guint64 integer64; + gdouble floating; + gchar *string; + guchar *ustring; + GByteArray *bytes; + GString *gstring; + ipv4_addr ipv4; + e_guid_t guid; + nstime_t time; + tvbuff_t *tvb; +#ifdef HAVE_LIBPCRE + pcre_tuple_t *re; +#endif /* HAVE_LIBPCRE */ + } value; + + /* The following is provided for private use + * by the fvalue. */ + gboolean fvalue_gboolean1; + +} fvalue_t; + +typedef void (*FvalueNewFunc)(fvalue_t*); +typedef void (*FvalueFreeFunc)(fvalue_t*); +typedef void (*LogFunc)(const char*,...); + +typedef gboolean (*FvalueFromUnparsed)(fvalue_t*, char*, gboolean, LogFunc); +typedef gboolean (*FvalueFromString)(fvalue_t*, char*, LogFunc); +typedef void (*FvalueToStringRepr)(fvalue_t*, ftrepr_t, char*); +typedef int (*FvalueStringReprLen)(fvalue_t*, ftrepr_t); + +typedef void (*FvalueSetFunc)(fvalue_t*, gpointer, gboolean); +typedef void (*FvalueSetUnsignedIntegerFunc)(fvalue_t*, guint32); +typedef void (*FvalueSetSignedIntegerFunc)(fvalue_t*, gint32); +typedef void (*FvalueSetInteger64Func)(fvalue_t*, guint64); +typedef void (*FvalueSetFloatingFunc)(fvalue_t*, gdouble); + +typedef gpointer (*FvalueGetFunc)(fvalue_t*); +typedef guint32 (*FvalueGetUnsignedIntegerFunc)(fvalue_t*); +typedef gint32 (*FvalueGetSignedIntegerFunc)(fvalue_t*); +typedef guint64 (*FvalueGetInteger64Func)(fvalue_t*); +typedef double (*FvalueGetFloatingFunc)(fvalue_t*); + +typedef gboolean (*FvalueCmp)(fvalue_t*, fvalue_t*); + +typedef guint (*FvalueLen)(fvalue_t*); +typedef void (*FvalueSlice)(fvalue_t*, GByteArray *, guint offset, guint length); + +struct _ftype_t { + ftenum_t ftype; + const char *name; + const char *pretty_name; + int wire_size; + FvalueNewFunc new_value; + FvalueFreeFunc free_value; + FvalueFromUnparsed val_from_unparsed; + FvalueFromString val_from_string; + FvalueToStringRepr val_to_string_repr; + FvalueStringReprLen len_string_repr; + + /* could be union */ + FvalueSetFunc set_value; + FvalueSetUnsignedIntegerFunc set_value_uinteger; + FvalueSetSignedIntegerFunc set_value_sinteger; + FvalueSetInteger64Func set_value_integer64; + FvalueSetFloatingFunc set_value_floating; + + /* could be union */ + FvalueGetFunc get_value; + FvalueGetUnsignedIntegerFunc get_value_uinteger; + FvalueGetSignedIntegerFunc get_value_sinteger; + FvalueGetInteger64Func get_value_integer64; + FvalueGetFloatingFunc get_value_floating; + + FvalueCmp cmp_eq; + FvalueCmp cmp_ne; + FvalueCmp cmp_gt; + FvalueCmp cmp_ge; + FvalueCmp cmp_lt; + FvalueCmp cmp_le; + FvalueCmp cmp_bitwise_and; + FvalueCmp cmp_contains; + FvalueCmp cmp_matches; + + FvalueLen len; + FvalueSlice slice; +}; + + +fvalue_t* +fvalue_new(ftenum_t ftype); + +void +fvalue_init(fvalue_t *fv, ftenum_t ftype); + + +/* Define type needed for the fvalue_t free list. */ +SLAB_ITEM_TYPE_DEFINE(fvalue_t) + +/* Free all memory used by an fvalue_t. With MSVC and a + * libwireshark.dll, we need a special declaration. + */ +WS_VAR_IMPORT SLAB_FREE_LIST_DECLARE(fvalue_t) + + +#define FVALUE_CLEANUP(fv) \ + { \ + register FvalueFreeFunc free_value; \ + free_value = (fv)->ftype->free_value; \ + if (free_value) { \ + free_value((fv)); \ + } \ + } + +#define FVALUE_FREE(fv) \ + { \ + FVALUE_CLEANUP(fv) \ + SLAB_FREE(fv, fvalue_t); \ + } + + +fvalue_t* +fvalue_from_unparsed(ftenum_t ftype, char *s, gboolean allow_partial_value, LogFunc logfunc); + +fvalue_t* +fvalue_from_string(ftenum_t ftype, char *s, LogFunc logfunc); + +/* Returns the length of the string required to hold the + * string representation of the the field value. + * The length DOES NOT include the terminating NUL. */ +int +fvalue_string_repr_len(fvalue_t *fv, ftrepr_t rtype); + +/* Creates the string representation of the field value. + * If given non-NULL 'buf', the string is written at the memory + * location pointed to by 'buf'. If 'buf' is NULL, new memory + * is malloc'ed and the string representation is written there. + * The pointer to the beginning of the string representation is + * returned. If 'buf' was NULL, this points to the newly-allocated + * memory. if 'buf' was non-NULL, then the return value will be + * 'buf'. */ +extern char * +fvalue_to_string_repr(fvalue_t *fv, ftrepr_t rtype, char *buf); + +ftype_t* +fvalue_ftype(fvalue_t *fv); + +const char* +fvalue_type_name(fvalue_t *fv); + +void +fvalue_set(fvalue_t *fv, gpointer value, gboolean already_copied); + +void +fvalue_set_uinteger(fvalue_t *fv, guint32 value); + +void +fvalue_set_sinteger(fvalue_t *fv, gint32 value); + +void +fvalue_set_integer64(fvalue_t *fv, guint64 value); + +void +fvalue_set_floating(fvalue_t *fv, gdouble value); + +gpointer +fvalue_get(fvalue_t *fv); + +extern guint32 +fvalue_get_uinteger(fvalue_t *fv); + +extern gint32 +fvalue_get_sinteger(fvalue_t *fv); + +guint64 +fvalue_get_integer64(fvalue_t *fv); + +extern double +fvalue_get_floating(fvalue_t *fv); + +gboolean +fvalue_eq(fvalue_t *a, fvalue_t *b); + +gboolean +fvalue_ne(fvalue_t *a, fvalue_t *b); + +gboolean +fvalue_gt(fvalue_t *a, fvalue_t *b); + +gboolean +fvalue_ge(fvalue_t *a, fvalue_t *b); + +gboolean +fvalue_lt(fvalue_t *a, fvalue_t *b); + +gboolean +fvalue_le(fvalue_t *a, fvalue_t *b); + +gboolean +fvalue_bitwise_and(fvalue_t *a, fvalue_t *b); + +gboolean +fvalue_contains(fvalue_t *a, fvalue_t *b); + +gboolean +fvalue_matches(fvalue_t *a, fvalue_t *b); + +guint +fvalue_length(fvalue_t *fv); + +fvalue_t* +fvalue_slice(fvalue_t *fv, drange *dr); + +#endif /* ftypes.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/funnel.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/funnel.h new file mode 100644 index 00000000..a162e100 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/funnel.h @@ -0,0 +1,116 @@ +/* + * funnel.h + * + * EPAN's GUI mini-API + * + * (c) 2006, Luis E. Garcia Ontanon + * + * $Id: funnel.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef _FUNNEL_H +#define _FUNNEL_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "../stat_menu.h" + +typedef struct _funnel_text_window_t funnel_text_window_t ; +typedef struct _funnel_tree_window_t funnel_tree_window_t ; +typedef struct _funnel_node_t funnel_node_t ; + +typedef void (*text_win_close_cb_t)(void*); + +typedef void (*funnel_dlg_cb_t)(gchar** user_input, void* data); + +typedef gboolean (*funnel_bt_cb_t)(funnel_text_window_t* tw, void* data); + +typedef struct _funnel_bt_t { + funnel_text_window_t* tw; + funnel_bt_cb_t func; + void* data; + void (*free)(void*); + void (*free_data)(void*); +} funnel_bt_t; + +typedef struct _funnel_ops_t { + funnel_text_window_t* (*new_text_window)(const gchar* label); + void (*set_text)(funnel_text_window_t* win, const gchar* text); + void (*append_text)(funnel_text_window_t* win, const gchar* text); + void (*prepend_text)(funnel_text_window_t* win, const gchar* text); + void (*clear_text)(funnel_text_window_t* win); + const gchar* (*get_text)(funnel_text_window_t* win); + void (*set_close_cb)(funnel_text_window_t* win, text_win_close_cb_t cb, void* data); + void (*set_editable)(funnel_text_window_t* win, gboolean editable); + void (*destroy_text_window)(funnel_text_window_t* win); + void (*add_button)(funnel_text_window_t* win, funnel_bt_t* cb, const gchar* label); + + + + void (*new_dialog)(const gchar* title, + const gchar** fieldnames, + funnel_dlg_cb_t dlg_cb, + void* data); + + + void (*logger)(const gchar *log_domain, + GLogLevelFlags log_level, + const gchar *message, + gpointer user_data); + + + void (*retap_packets)(void); + void (*copy_to_clipboard)(GString *str); + void (*set_filter)(const char*); + gboolean (*open_file)(const char* fname, const char* filter, const char** error); + void (*reload)(void); + void (*apply_filter)(void); + gboolean (*browser_open_url)(const gchar *url); + void (*browser_open_data_file)(const gchar *filename); +} funnel_ops_t; + + +extern const funnel_ops_t* funnel_get_funnel_ops(void); +extern void funnel_set_funnel_ops(const funnel_ops_t*); + + +extern void funnel_register_menu(const char *name, + register_stat_group_t group, + void (*callback)(gpointer), + gpointer callback_data, + gboolean retap); + + +typedef void (*funnel_registration_cb_t)(const char *name, + register_stat_group_t group, + void (*callback)(gpointer), + gpointer callback_data, + gboolean retap); + +extern void funnel_register_all_menus(funnel_registration_cb_t r_cb); + +extern void initialize_funnel_ops(void); + +extern void funnel_dump_all_text_windows(void); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/g_ascii_strcasecmp.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/g_ascii_strcasecmp.h new file mode 100644 index 00000000..aef486b2 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/g_ascii_strcasecmp.h @@ -0,0 +1,18 @@ +/* + * $Id: g_ascii_strcasecmp.h 3992 2008-06-10 03:13:11Z dgu $ + * + * "g_ascii_strcasecmp()" and "g_ascii_strncasecmp()" extracted from + * GLib 2.4.8, for use with GLibs that don't have it (e.g., GLib 1.2[.x]). + */ + +#ifndef __WIRESHARK_G_ASCII_STRCASECMP_H__ +#define __WIRESHARK_G_ASCII_STRCASECMP_H__ + +extern gint g_ascii_strcasecmp (const gchar *s1, + const gchar *s2); + +extern gint g_ascii_strncasecmp (const gchar *s1, + const gchar *s2, + gsize n); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/g_ascii_strtoull.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/g_ascii_strtoull.h new file mode 100644 index 00000000..d52d6d41 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/g_ascii_strtoull.h @@ -0,0 +1,15 @@ +/* + * $Id: g_ascii_strtoull.h 3992 2008-06-10 03:13:11Z dgu $ + * + * "g_ascii_strtoull()" extracted from GLib 2.4.5, for use with GLibs + * that don't have it (e.g., GLib 1.2[.x]). + */ + +#ifndef __WIRESHARK_G_ASCII_STRTOULL_H__ +#define __WIRESHARK_G_ASCII_STRTOULL_H__ + +extern guint64 g_ascii_strtoull (const gchar *nptr, + gchar **endptr, + guint base); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/garrayfix.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/garrayfix.h new file mode 100644 index 00000000..1d740562 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/garrayfix.h @@ -0,0 +1,38 @@ +/* garrayfix.h + * Macros to work around the "data" field of a GArray having type guint8 *, + * rather than void *, so that, even though the GArray code should be + * ensuring that the data is aligned strictly enough for any data type, + * we still get warnings with -Wcast-align. + * + * $Id: garrayfix.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2007 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __GARRAYFIX_H__ +#define __GARRAYFIX_H__ + +#ifdef g_array_index +#undef g_array_index +#define g_array_index(a,t,i) (((t*) (void*) (a)->data) [(i)]) +#endif + +#define g_array_data(a) ((void*) (a)->data) + +#endif /* __GARRAYFIX_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/gcp.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/gcp.h new file mode 100644 index 00000000..8dd8f728 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/gcp.h @@ -0,0 +1,219 @@ +/* gcp.h + * Gateway Control Protocol -- Context Tracking + * + * $Id: gcp.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef __GCP_H_ +#define __GCP_H_ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +typedef struct _gcp_hf_ett_t { + struct { + int ctx; + int ctx_cmd; + int ctx_term; + int ctx_term_type; + int ctx_term_bir; + int ctx_term_nsap; + } hf; + + struct { + gint ctx; + gint ctx_cmds; + gint ctx_terms; + gint ctx_term; + } ett; +} gcp_hf_ett_t; + +#define NULL_CONTEXT 0 +#define CHOOSE_CONTEXT 0xFFFFFFFE +#define ALL_CONTEXTS 0xFFFFFFFF + + +typedef enum { + GCP_CMD_NONE, + GCP_CMD_ADD_REQ, + GCP_CMD_MOVE_REQ, + GCP_CMD_MOD_REQ, + GCP_CMD_SUB_REQ, + GCP_CMD_AUDITCAP_REQ, + GCP_CMD_AUDITVAL_REQ, + GCP_CMD_NOTIFY_REQ, + GCP_CMD_SVCCHG_REQ, + GCP_CMD_TOPOLOGY_REQ, + GCP_CMD_CTX_ATTR_AUDIT_REQ, + GCP_CMD_OTHER_REQ, + GCP_CMD_ADD_REPLY, + GCP_CMD_MOVE_REPLY, + GCP_CMD_MOD_REPLY, + GCP_CMD_SUB_REPLY, + GCP_CMD_AUDITCAP_REPLY, + GCP_CMD_AUDITVAL_REPLY, + GCP_CMD_NOTIFY_REPLY, + GCP_CMD_SVCCHG_REPLY, + GCP_CMD_TOPOLOGY_REPLY, + GCP_CMD_REPLY +} gcp_cmd_type_t; + +typedef enum { + GCP_TRX_NONE, + GCP_TRX_REQUEST, + GCP_TRX_PENDING, + GCP_TRX_REPLY, + GCP_TRX_ACK +} gcp_trx_type_t; + + +typedef struct _gcp_msg_t { + guint32 lo_addr; + guint32 hi_addr; + guint32 framenum; + struct _gcp_trx_msg_t* trxs; + gboolean commited; +} gcp_msg_t; + +typedef struct _gcp_trx_msg_t { + struct _gcp_trx_t* trx; + struct _gcp_trx_msg_t* next; + struct _gcp_trx_msg_t* last; +} gcp_trx_msg_t; + +typedef struct _gcp_cmd_msg_t { + struct _gcp_cmd_t* cmd; + struct _gcp_cmd_msg_t* next; + struct _gcp_cmd_msg_t* last; +} gcp_cmd_msg_t; + +typedef struct _gcp_trx_t { + gcp_msg_t* initial; + guint32 id; + gcp_trx_type_t type; + guint pendings; + struct _gcp_cmd_msg_t* cmds; + struct _gcp_trx_ctx_t* ctxs; + guint error; +} gcp_trx_t; + +#define GCP_TERM_TYPE_UNKNOWN 0 +#define GCP_TERM_TYPE_AAL1 1 +#define GCP_TERM_TYPE_AAL2 2 +#define GCP_TERM_TYPE_AAL1_STRUCT 3 +#define GCP_TERM_TYPE_IP_RTP 4 +#define GCP_TERM_TYPE_TDM 5 + +typedef enum _gcp_wildcard_t { + GCP_WILDCARD_NONE, + GCP_WILDCARD_CHOOSE, + GCP_WILDCARD_ALL +} gcp_wildcard_t; + +typedef struct _gcp_term_t { + gchar* str; + + guint8* buffer; + guint len; + + guint type; + gchar* bir; + gchar* nsap; + + gcp_msg_t* start; + +} gcp_term_t; + +typedef struct _gcp_terms_t { + gcp_term_t* term; + struct _gcp_terms_t* next; + struct _gcp_terms_t* last; +} gcp_terms_t; + +typedef struct _gcp_cmd_t { + guint offset; + gchar* str; + gcp_cmd_type_t type; + gcp_terms_t terms; + struct _gcp_msg_t* msg; + struct _gcp_trx_t* trx; + struct _gcp_ctx_t* ctx; + guint error; +} gcp_cmd_t; + + +typedef struct _gcp_ctx_t { + gcp_msg_t* initial; + guint32 id; + struct _gcp_cmd_msg_t* cmds; + struct _gcp_ctx_t* prev; + gcp_terms_t terms; +} gcp_ctx_t; + +WS_VAR_IMPORT const value_string gcp_cmd_type[]; +WS_VAR_IMPORT const value_string gcp_term_types[]; + +extern void gcp_init(void); +extern gcp_msg_t* gcp_msg(packet_info* pinfo, int o, gboolean persistent); +extern gcp_trx_t* gcp_trx(gcp_msg_t* m ,guint32 t_id , gcp_trx_type_t type, gboolean persistent); +extern gcp_ctx_t* gcp_ctx(gcp_msg_t* m, gcp_trx_t* t, guint32 c_id, gboolean persistent); +extern gcp_cmd_t* gcp_cmd(gcp_msg_t* m, gcp_trx_t* t, gcp_ctx_t* c, gcp_cmd_type_t type, guint offset, gboolean persistent); +extern gcp_term_t* gcp_cmd_add_term(gcp_msg_t* m, gcp_trx_t* tr, gcp_cmd_t* c, gcp_term_t* t, gcp_wildcard_t wildcard, gboolean persistent); +extern void gcp_analyze_msg(proto_tree* gcp_tree, tvbuff_t* gcp_tvb, gcp_msg_t* m, gcp_hf_ett_t* ids); + +extern gchar* gcp_cmd_to_str(gcp_cmd_t* c, gboolean persistent); +extern gchar* gcp_msg_to_str(gcp_msg_t* m, gboolean persistent); + +#define gcp_cmd_set_error(c,e) (c->error = e) +#define gcp_trx_set_error(t,e) (t->error = e) + +#define GCP_ETT_ARR_ELEMS(gi) &(gi.ett.ctx),&(gi.ett.ctx_cmds),&(gi.ett.ctx_terms),&(gi.ett.ctx_term) + +#define GCP_HF_ARR_ELEMS(n,gi) \ + { &(gi.hf.ctx), { "Context", n ".ctx", FT_UINT32, BASE_HEX, NULL, 0, "", HFILL }}, \ + { &(gi.hf.ctx_term), { "Termination", n ".ctx.term", FT_STRING, BASE_NONE, NULL, 0, "", HFILL }}, \ + { &(gi.hf.ctx_term_type), { "Type", n ".ctx.term.type", FT_UINT32, BASE_HEX, VALS(gcp_term_types), 0, "", HFILL }}, \ + { &(gi.hf.ctx_term_bir), { "BIR", n ".ctx.term.bir", FT_STRING, BASE_HEX, NULL, 0, "", HFILL }}, \ + { &(gi.hf.ctx_term_nsap), { "NSAP", n ".ctx.term.nsap", FT_STRING, BASE_NONE, NULL, 0, "", HFILL }}, \ + { &(gi.hf.ctx_cmd), { "Command in Frame", n ".ctx.cmd", FT_FRAMENUM, BASE_DEC, NULL, 0, "", HFILL }} + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/gnuc_format_check.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/gnuc_format_check.h new file mode 100644 index 00000000..a550dde7 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/gnuc_format_check.h @@ -0,0 +1,39 @@ +/* gnuc_format_check.h + * Definitions of macro to conditionally do GCC format checks + * + * $Id: gnuc_format_check.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __GNUC_FORMAT_CHECK_H__ +#define __GNUC_FORMAT_CHECK_H__ + +/** GNUC has the ability to check format strings that follow the syntax used in printf and others. + Hide the differences between different compilers in this GNUC_FORMAT_CHECK macro. + @param archetype one of: printf, scanf, strftime or strfmon + @param string_index specifies which argument is the format string argument (starting from 1) + @param first_to_check is the number of the first argument to check against the format string */ +#if __GNUC__ >= 2 + #define GNUC_FORMAT_CHECK(archetype, string_index, first_to_check) __attribute__((format (archetype, string_index, first_to_check))) +#else + #define GNUC_FORMAT_CHECK(archetype, string_index, first_to_check) +#endif + +#endif /* gnuc-format-check.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/golay.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/golay.h new file mode 100644 index 00000000..ad3d454a --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/golay.h @@ -0,0 +1,49 @@ +/* $Id: golay.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Provides routines for encoding and decoding the extended Golay + * (24,12,8) code. + * + * This implementation will detect up to 4 errors in a codeword (without + * being able to correct them); it will correct up to 3 errors. + * + * We use guint32s to hold the 24-bit codewords, with the data part in + * the bottom 12 bits and the parity in bits 12-23. + * + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef __GOLAY_H__ +#define __GOLAY_H__ + +/* encodes a 12-bit word to a 24-bit codeword + */ +guint32 golay_encode(guint w); + +/* return a mask showing the bits which are in error in a received + * 24-bit codeword, or -1 if 4 errors were detected. + */ +gint32 golay_errors(guint32 codeword); + +/* decode a received codeword. Up to 3 errors are corrected for; 4 + errors are detected as uncorrectable (return -1); 5 or more errors + cause an incorrect correction. +*/ +gint golay_decode(guint32 w); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/greproto.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/greproto.h new file mode 100644 index 00000000..de295dad --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/greproto.h @@ -0,0 +1,36 @@ +/* greproto.h + * Protocol type values for for the Generic Routing Encapsulation (GRE) + * protocol + * Brad Robel-Forrest + * + * The protocol type in GRE is supposed to be an Ethernet type value; + * this file lists protocol type values for which nobody's found an + * official Ethernet type definition and put that in "etypes.h". + * Move these to "etypes.h" if you find an official Ethernet type + * definition for them; when this file is empty, get rid of all includes + * of it, and get rid of it. + * + * $Id: greproto.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#define GRE_NHRP 0x2001 +#define GRE_WCCP 0x883E +#define GRE_ERSPAN 0x88BE diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/guid-utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/guid-utils.h new file mode 100644 index 00000000..c2fc95d6 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/guid-utils.h @@ -0,0 +1,63 @@ +/* guid-utils.h + * Definitions for GUID handling + * + * $Id: guid-utils.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __GUID_UTILS_H__ +#define __GUID_UTILS_H__ + +#define GUID_LEN 16 + +/* Note: this might be larger than GUID_LEN, so don't overlay data in packets + with this. */ +typedef struct _e_guid_t { + guint32 data1; + guint16 data2; + guint16 data3; + guint8 data4[8]; +} e_guid_t; + + +extern void guids_init(void); + +/* add a GUID */ +extern void guids_add_guid(e_guid_t *guid, const gchar *name); + +/* try to get registered name for this GUID */ +extern const gchar *guids_get_guid_name(e_guid_t *guid); + +/* resolve GUID to name (or if unknown to hex string) */ +/* (if you need hex string only, use guid_to_str instead) */ +extern const gchar* guids_resolve_guid_to_str(e_guid_t *guid); + +/* add a UUID (dcerpc_init_uuid() will call this too) */ +#define guids_add_uuid(uuid, name) guids_add_guid((e_guid_t *) (uuid), (name)) + +/* try to get registered name for this UUID */ +#define guids_get_uuid_name(uuid) guids_get_guid_name((e_guid_t *) (uuid)) + +/* resolve UUID to name (or if unknown to hex string) */ +/* (if you need hex string only, use guid_to_str instead) */ +#define guids_resolve_uuid_to_str(uuid) guids_resolve_guid_to_str((e_guid_t *) (uuid)) + +#endif /* __GUID_UTILS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/h225-persistentdata.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/h225-persistentdata.h new file mode 100644 index 00000000..576330e5 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/h225-persistentdata.h @@ -0,0 +1,62 @@ +/* + * h225-persistentdata.h + * Definitions for lists and hash tables used in wireshark's h225 dissector + * for calculation of delays in h225-calls + * + * Copyright 2003 Lars Roland + * + * $Id: h225-persistentdata.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __h225_HASH__ +#define __h225_HASH__ + +#include +#include +#include + + +/* Item of ras request list*/ +typedef struct _h225ras_call_t { + guint32 requestSeqNum; + e_guid_t guid; + guint32 req_num; /* frame number request seen */ + guint32 rsp_num; /* frame number response seen */ + nstime_t req_time; /* arrival time of request */ + gboolean responded; /* true, if request has been responded */ + struct _h225ras_call_t *next_call; /* pointer to next ras request with same SequenceNumber and conversation handle */ +} h225ras_call_t; + + +/* Item of ras-request key list*/ +typedef struct _h225ras_call_info_key { + guint reqSeqNum; + conversation_t *conversation; +} h225ras_call_info_key; + +/* functions, needed using ras-request and halfcall matching*/ +h225ras_call_t * find_h225ras_call(h225ras_call_info_key *h225ras_call_key ,int category); +h225ras_call_t * new_h225ras_call(h225ras_call_info_key *h225ras_call_key, packet_info *pinfo, e_guid_t *guid, int category); +h225ras_call_t * append_h225ras_call(h225ras_call_t *prev_call, packet_info *pinfo, e_guid_t *guid, int category); + +void h225_init_routine(void); /* init routine, used by wireshark */ + +#endif /* __h225_HASH__*/ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/iax2_codec_type.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/iax2_codec_type.h new file mode 100644 index 00000000..7832eeec --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/iax2_codec_type.h @@ -0,0 +1,77 @@ +/* iax2_codec_type.h + * Defines IAX2 codec types + * + * $Id: iax2_codec_type.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __IAX2_CODEC_TYPE_H__ +#define __IAX2_CODEC_TYPE_H__ + + +/* Ref: frame.h from Asterisk source */ + +/* Data formats for capabilities and frames alike */ +/* suitable for use in iax2.codec dissector table */ +/*! G.723.1 compression */ +#define AST_FORMAT_G723_1 (1 << 0) +/*! GSM compression */ +#define AST_FORMAT_GSM (1 << 1) +/*! Raw mu-law data (G.711) */ +#define AST_FORMAT_ULAW (1 << 2) +/*! Raw A-law data (G.711) */ +#define AST_FORMAT_ALAW (1 << 3) +/*! ADPCM (G.726, 32kbps) */ +#define AST_FORMAT_G726 (1 << 4) +/*! ADPCM (IMA) */ +#define AST_FORMAT_ADPCM (1 << 5) +/*! Raw 16-bit Signed Linear (8000 Hz) PCM */ +#define AST_FORMAT_SLINEAR (1 << 6) +/*! LPC10, 180 samples/frame */ +#define AST_FORMAT_LPC10 (1 << 7) +/*! G.729A audio */ +#define AST_FORMAT_G729A (1 << 8) +/*! SpeeX Free Compression */ +#define AST_FORMAT_SPEEX (1 << 9) +/*! iLBC Free Compression */ +#define AST_FORMAT_ILBC (1 << 10) +/*! Maximum audio format */ +#define AST_FORMAT_MAX_AUDIO (1 << 15) +/*! JPEG Images */ +#define AST_FORMAT_JPEG (1 << 16) +/*! PNG Images */ +#define AST_FORMAT_PNG (1 << 17) +/*! H.261 Video */ +#define AST_FORMAT_H261 (1 << 18) +/*! H.263 Video */ +#define AST_FORMAT_H263 (1 << 19) +/*! Max one */ +#define AST_FORMAT_MAX_VIDEO (1 << 24) + + +/* data format for IAX_IE_DATAFORMAT ie */ +/* suitable for use in iax2.dataformat dissector table */ +typedef enum { + AST_DATAFORMAT_NULL, /* N/A: analogue call etc */ + AST_DATAFORMAT_V110, /* ITU-T V.110 rate adaption */ + AST_DATAFORMAT_H223_H245 /* ITU-T H.223/H.245 */ +} iax_dataformat_t; + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/in_cksum.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/in_cksum.h new file mode 100644 index 00000000..27c8273d --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/in_cksum.h @@ -0,0 +1,14 @@ +/* in_cksum.h + * Declaration of Internet checksum routine. + * + * $Id: in_cksum.h 3992 2008-06-10 03:13:11Z dgu $ + */ + +typedef struct { + const guint8 *ptr; + int len; +} vec_t; + +extern int in_cksum(const vec_t *vec, int veclen); + +extern guint16 in_cksum_shouldbe(guint16 sum, guint16 computed_sum); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/inet_aton.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/inet_aton.h new file mode 100644 index 00000000..b7732a98 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/inet_aton.h @@ -0,0 +1,34 @@ +/* inet_aton.h + * + * $Id: inet_aton.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * Version of "inet_aton()", for the benefit of OSes that don't have it. + */ + +#ifndef __INET_ATON_H__ +#define __INET_ATON_H__ + +struct in_addr; +extern int inet_aton(const char* cp_arg, struct in_addr *addr); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ip_opts.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ip_opts.h new file mode 100644 index 00000000..4915c227 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ip_opts.h @@ -0,0 +1,59 @@ +/* ip_opts.h + * Definitions of structures and routines for dissection of options that + * work like IPv4 or IPv6 options + * + * $Id: ip_opts.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __IP_OPTS_H__ +#define __IP_OPTS_H__ + +typedef enum { + NO_LENGTH, /* option has no data, hence no length */ + FIXED_LENGTH, /* option always has the same length */ + VARIABLE_LENGTH /* option is variable-length - optlen is minimum */ +} opt_len_type; + +/* Member of table of IP or TCP options. */ +typedef struct ip_tcp_opt { + int optcode; /* code for option */ + const char *name; /* name of option */ + int *subtree_index; /* pointer to subtree index for option */ + opt_len_type len_type; /* type of option length field */ + int optlen; /* value length should be (minimum if VARIABLE) */ + void (*dissect)(const struct ip_tcp_opt *, tvbuff_t *, int, guint, + packet_info *, proto_tree *); + /* routine to dissect option */ +} ip_tcp_opt; + +/* Routine to dissect options that work like IPv4 options, where the + length field in the option, if present, includes the type and + length bytes. */ +extern void dissect_ip_tcp_options(tvbuff_t *, int, guint, + const ip_tcp_opt *, int, int, packet_info *, proto_tree *); + +/* Routine to dissect options that work like IPv6 options, where the + length field in the option, if present, includes only the data, not + the type and length bytes. */ +extern void dissect_ipv6_options(tvbuff_t *, int, guint, + const ip_tcp_opt *, int, int, packet_info *, proto_tree *); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipproto.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipproto.h new file mode 100644 index 00000000..a6861cd7 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipproto.h @@ -0,0 +1,193 @@ +/* ipproto.h + * Declarations of IP protocol numbers, and of routines for converting + * IP protocol numbers into strings. + * + * $Id: ipproto.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __IPPROTO_H__ +#define __IPPROTO_H__ + +/* + * IP protocol numbers. + */ +#define IP_PROTO_IP 0 /* dummy for IP */ +#define IP_PROTO_HOPOPTS 0 /* IP6 hop-by-hop options - RFC1883 */ +#define IP_PROTO_ICMP 1 /* control message protocol - RFC792 */ +#define IP_PROTO_IGMP 2 /* group mgmt protocol - RFC1112 */ +#define IP_PROTO_GGP 3 /* gateway^2 (deprecated) - RFC823*/ +#define IP_PROTO_IPIP 4 /* IP inside IP - RFC2003*/ +#define IP_PROTO_IPV4 4 /* IP header */ +#define IP_PROTO_STREAM 5 /* Stream - RFC1190, RFC1819 */ +#define IP_PROTO_TCP 6 /* TCP - RFC792 */ +#define IP_PROTO_CBT 7 /* CBT - */ +#define IP_PROTO_EGP 8 /* exterior gateway protocol - RFC888 */ +#define IP_PROTO_IGP 9 /* any private interior gateway protocol ... */ +#define IP_PROTO_IGRP 9 /* ... and used by Cisco for IGRP */ +#define IP_PROTO_BBN_RCC 10 /* BBN RCC Monitoring */ +#define IP_PROTO_NVPII 11 /* Network Voice Protocol - RFC741 */ +#define IP_PROTO_PUP 12 /* pup */ +#define IP_PROTO_ARGUS 13 /* ARGUS */ +#define IP_PROTO_EMCON 14 /* EMCON */ +#define IP_PROTO_XNET 15 /* Cross net debugger - IEN158 */ +#define IP_PROTO_CHAOS 16 /* CHAOS */ +#define IP_PROTO_UDP 17 /* user datagram protocol - RFC768 */ +#define IP_PROTO_MUX 18 /* multiplexing - IEN90 */ +#define IP_PROTO_DCNMEAS 19 /* DCN Measurement Subsystems */ +#define IP_PROTO_HMP 20 /* Host Monitoring - RFC869 */ +#define IP_PROTO_PRM 21 /* Packet radio measurement */ +#define IP_PROTO_IDP 22 /* xns idp */ +#define IP_PROTO_TRUNK1 23 +#define IP_PROTO_TRUNK2 24 +#define IP_PROTO_LEAF1 25 +#define IP_PROTO_LEAF2 26 +#define IP_PROTO_RDP 27 /* Reliable Data Protocol - RFC908 */ +#define IP_PROTO_IRT 28 /* Internet Reliable Transation - RFC938 */ +#define IP_PROTO_TP 29 /* tp-4 w/ class negotiation - RFC905 */ +#define IP_PROTO_BULK 30 /* Bulk Data Transfer Protocol - RFC969 */ +#define IP_PROTO_MFE_NSP 31 /* MFE Network Services Protocol */ +#define IP_PROTO_MERIT 32 /* MERIT Internodal Protocol */ +/* #define IP_PROTO_SEP 33 Sequential Exchange Protocol */ +#define IP_PROTO_DCCP 33 /* Datagram Congestion Control Protocol */ +#define IP_PROTO_3PC 34 /* Third party connect protocol */ +#define IP_PROTO_IDPR 35 /* Interdomain policy routing protocol */ +#define IP_PROTO_XTP 36 /* XTP */ +#define IP_PROTO_DDP 37 /* Datagram Delivery Protocol */ +#define IP_PROTO_CMTP 38 /* Control Message Transport Protocol */ +#define IP_PROTO_TPPP 39 /* TP++ Transport Protocol */ +#define IP_PROTO_IL 40 /* IL Transport Protocol */ +#define IP_PROTO_IPV6 41 /* IP6 header */ +#define IP_PROTO_SDRP 42 /* Source demand routing protocol */ +#define IP_PROTO_ROUTING 43 /* IP6 routing header */ +#define IP_PROTO_FRAGMENT 44 /* IP6 fragmentation header */ +#define IP_PROTO_IDRP 45 /* Inter-Domain Routing Protocol */ +#define IP_PROTO_RSVP 46 /* Resource ReSerVation protocol */ +#define IP_PROTO_GRE 47 /* General Routing Encapsulation */ +#define IP_PROTO_MHRP 48 /* Mobile Host Routing Protocol */ +#define IP_PROTO_BNA 49 /* BNA */ +#define IP_PROTO_ESP 50 /* Encap Security Payload for IPv6 - RFC2406 */ +#define IP_PROTO_AH 51 /* Authentication Header for IPv6 - RFC2402*/ +#define IP_PROTO_INSLP 52 /* Integrated Net Layer Security */ +#define IP_PROTO_SWIPE 53 /* IP with Encryption */ +#define IP_PROTO_NARP 54 /* NBMA Address resolution protocol - RFC1735 */ +#define IP_PROTO_MOBILE 55 /* IP Mobility */ +#define IP_PROTO_TLSP 56 /* Transport Layer Security Protocol using */ + /* Kryptonet key management */ +#define IP_PROTO_SKIP 57 /* SKIP */ +#define IP_PROTO_ICMPV6 58 /* ICMP6 - RFC1883*/ +#define IP_PROTO_NONE 59 /* IP6 no next header - RFC1883 */ +#define IP_PROTO_DSTOPTS 60 /* IP6 destination options - RFC1883 */ +/* 61 is reserved by IANA for any host internal protocol */ +/* 61 is used by UCL's SHIM6 implementation as Next Header for SHIM6 */ +#define IP_PROTO_SHIM6 61 /* SHIM6 */ + +/* + * The current Protocol Numbers list says that the IP protocol number for + * mobility headers is 135; it cites draft-ietf-mobileip-ipv6-24, but + * that draft doesn't actually give a number. + * + * It appears that 62 used to be used, even though that's assigned to + * a protocol called CFTP; however, the only reference for CFTP is a + * Network Message from BBN back in 1982, so, for now, we support 62, + * as well as 135, as a protocol number for mobility headers. + */ +#define IP_PROTO_MIPV6_OLD 62 /* Mobile IPv6 */ +/* 63 is reserved by IANA for any local network */ +#define IP_PROTO_SATEXPAK 64 +#define IP_PROTO_KRYPTOLAN 65 +#define IP_PROTO_RVD 66 /* MIT Remote virtual disk protocol */ +#define IP_PROTO_IPPC 67 /* Internet Pluribus Packet Core */ +/* 68 is reserved by IANA for any distributed file system */ +#define IP_PROTO_SATMON 69 /* SATNET Monitoring */ +#define IP_PROTO_VISA 70 /* VISA Protocol */ +#define IP_PROTO_IPCV 71 /* Internet Packet Core Utility */ +#define IP_PROTO_CPNX 72 /* Computer Protocol Network Executive */ +#define IP_PROTO_CPHB 73 /* Computer Protocol Heart Beat */ +#define IP_PROTO_WSN 74 /* WANG Span Network */ +#define IP_PROTO_PVP 75 /* Packet Video Protocol */ +#define IP_PROTO_BRSATMON 76 /* Backroon SATNET Monitoring */ +#define IP_PROTO_SUNND 77 /* SUN ND Protocol - Temporary */ +#define IP_PROTO_WBMON 78 /* Wideband Monitoring */ +#define IP_PROTO_WBEXPAK 79 /* Wideband EXPAK */ +#define IP_PROTO_EON 80 /* ISO cnlp */ +#define IP_PROTO_VMTP 81 +#define IP_PROTO_SVMTP 82 /* Secure VMTP */ +#define IP_PROTO_VINES 83 /* Vines over raw IP */ +#define IP_PROTO_TTP 84 +#define IP_PROTO_NSFNETIGP 85 /* NSFNET IGP */ +#define IP_PROTO_DGP 86 /* Dissimilar Gateway Protocol */ +#define IP_PROTO_TCF 87 +#define IP_PROTO_EIGRP 88 +#define IP_PROTO_OSPF 89 /* OSPF Interior Gateway Protocol - RFC1583 */ +#define IP_PROTO_SPRITE 90 /* SPRITE RPC protocol */ +#define IP_PROTO_LARP 91 /* Locus Address Resolution Protocol */ +#define IP_PROTO_MTP 92 /* Multicast Transport Protocol */ +#define IP_PROTO_AX25 93 /* AX.25 frames */ +#define IP_PROTO_IPINIP 94 /* IP within IP Encapsulation protocol */ +#define IP_PROTO_MICP 95 /* Mobile Internetworking Control Protocol */ +#define IP_PROTO_SCCCP 96 /* Semaphore communications security protocol */ +#define IP_PROTO_ETHERIP 97 /* Ethernet-within-IP - RFC 3378 */ +#define IP_PROTO_ENCAP 98 /* encapsulation header - RFC1241*/ +/* 99 is reserved by IANA for any private encryption scheme */ +#define IP_PROTO_GMTP 100 +#define IP_PROTO_IFMP 101 /* Ipsilon flow management protocol */ +#define IP_PROTO_PNNI 102 /* PNNI over IP */ +#define IP_PROTO_PIM 103 /* Protocol Independent Mcast */ +#define IP_PROTO_ARIS 104 +#define IP_PROTO_SCPS 105 +#define IP_PROTO_QNX 106 +#define IP_PROTO_AN 107 /* Active Networks */ +#define IP_PROTO_IPCOMP 108 /* IP payload compression - RFC2393 */ +#define IP_PROTO_SNP 109 /* Sitara Networks Protocol */ +#define IP_PROTO_COMPAQ 110 /* Compaq Peer Protocol */ +#define IP_PROTO_IPX 111 /* IPX over IP */ +#define IP_PROTO_VRRP 112 /* Virtual Router Redundancy Protocol */ +#define IP_PROTO_PGM 113 /* Pragmatic General Multicast */ +/* 114 is reserved by IANA for any zero hop protocol */ +#define IP_PROTO_L2TP 115 /* Layer Two Tunnelling Protocol */ +#define IP_PROTO_DDX 116 /* D-II Data Exchange */ +#define IP_PROTO_IATP 117 /* Interactive Agent Transfer Protocol */ +#define IP_PROTO_STP 118 /* Schedule Transfer Protocol */ +#define IP_PROTO_SRP 119 /* Spectralink Radio Protocol */ +#define IP_PROTO_UTI 120 +#define IP_PROTO_SMP 121 /* Simple Message Protocol */ +#define IP_PROTO_SM 122 +#define IP_PROTO_PTP 123 /* Performance Transparency Protocol */ +#define IP_PROTO_ISIS 124 /* ISIS over IPv4 */ +#define IP_PROTO_FIRE 125 +#define IP_PROTO_CRTP 126 /* Combat Radio Transport Protocol */ +#define IP_PROTO_CRUDP 127 /* Combat Radio User Datagram */ +#define IP_PROTO_SSCOPMCE 128 +#define IP_PROTO_IPLT 129 +#define IP_PROTO_SPS 130 /* Secure Packet Shield */ +#define IP_PROTO_PIPE 131 /* Private IP Encapsulation within IP */ +#define IP_PROTO_SCTP 132 /* Stream Control Transmission Protocol */ +#define IP_PROTO_FC 133 /* Fibre Channel */ +#define IP_PROTO_RSVPE2EI 134 /* RSVP E2E Ignore - RFC3175 */ +#define IP_PROTO_MIPV6 135 /* Mobile IPv6 */ +#define IP_PROTO_UDPLITE 136 /* Lightweight user datagram protocol - RFC3828 */ +#define IP_PROTO_MPLS_IN_IP 137 /* MPLS in IP - RFC4023 */ +#define IP_PROTO_AX4000 173 /* AX/4000 Testblock - non IANA */ +#define IP_PROTO_NCS_HEARTBEAT 224 /* Novell NCS Heartbeat - http://support.novell.com/cgi-bin/search/searchtid.cgi?/10071158.htm */ + +extern const char *ipprotostr(int proto); + +#endif /* ipproto.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipv4.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipv4.h new file mode 100644 index 00000000..c1cbbbde --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipv4.h @@ -0,0 +1,67 @@ +/* ipv4.h + * + * IPv4 address class. They understand how to take netmasks into consideration + * during equivalence testing. + * + * Gilbert Ramirez + * + * $Id: ipv4.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __IPV4_H__ +#define __IPV4_H__ + +#include + +typedef struct { + guint32 addr; /* stored in host order */ + guint32 nmask; /* stored in host order */ +} ipv4_addr; + +/* Allocate a new ipv4_addr struct, initialize it, and return pointer */ +ipv4_addr* ipv4_addr_new(void); + +/* Frees an ipv4 struct */ +void ipv4_addr_free(ipv4_addr *ipv4); + +void ipv4_addr_set_host_order_addr(ipv4_addr *ipv4, guint32 new_addr); +void ipv4_addr_set_net_order_addr(ipv4_addr *ipv4, guint32 new_addr); +void ipv4_addr_set_netmask_bits(ipv4_addr *ipv4, guint new_nmask_bits); + +guint32 ipv4_get_net_order_addr(ipv4_addr *ipv4); +guint32 ipv4_get_host_order_addr(ipv4_addr *ipv4); + +/* Fills in a buffer with a dotted-decimal notation representation of an IPv4 + * address. */ +void ipv4_addr_str_buf(const ipv4_addr *ipv4, gchar *buf); + +/* Compares two ipv4_addrs, taking into account the less restrictive of the + * two netmasks, applying that netmask to both addrs. + */ +gboolean ipv4_addr_eq(ipv4_addr *a, ipv4_addr *b); +gboolean ipv4_addr_gt(ipv4_addr *a, ipv4_addr *b); +gboolean ipv4_addr_ge(ipv4_addr *a, ipv4_addr *b); +gboolean ipv4_addr_lt(ipv4_addr *a, ipv4_addr *b); +gboolean ipv4_addr_le(ipv4_addr *a, ipv4_addr *b); + +#define ipv4_addr_ne(a,b) !ipv4_addr_eq((a),(b)) + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipv6-utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipv6-utils.h new file mode 100644 index 00000000..a743f806 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipv6-utils.h @@ -0,0 +1,49 @@ +/* ipv6-utils.h + * Definitions for IPv6 packet disassembly + * + * $Id: ipv6-utils.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * + * Copyright 1998 Gerald Combs + * + * MobileIPv6 support added by Tomislav Borosa + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __IPV6_UTILS_H__ +#define __IPV6_UTILS_H__ + +struct e_in6_addr { + guint8 bytes[16]; /* 128 bit IP6 address */ +}; + +/* + * Unicast Scope + * Note that we must check topmost 10 bits only, not 16 bits (see RFC2373). + */ +#define E_IN6_IS_ADDR_LINKLOCAL(a) \ + (((a)->bytes[0] == 0xfe) && (((a)->bytes[1] & 0xc0) == 0x80)) +#define E_IN6_IS_ADDR_SITELOCAL(a) \ + (((a)->bytes[0] == 0xfe) && (((a)->bytes[1] & 0xc0) == 0xc0)) + +/* + * Multicast + */ +#define E_IN6_IS_ADDR_MULTICAST(a) ((a)->bytes[0] == 0xff) + +#endif /* __IPV6_UTILS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/lapd_sapi.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/lapd_sapi.h new file mode 100644 index 00000000..5750f796 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/lapd_sapi.h @@ -0,0 +1,38 @@ +/* lapd_sapi.h + * Declarations of LAPD SAPI values. + * + * $Id: lapd_sapi.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2004 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __LAPD_SAPI_H__ +#define __LAPD_SAPI_H__ + +#define LAPD_SAPI_Q931 0 /* Q.931 call control procedure */ +#define LAPD_SAPI_PM_Q931 1 /* Packet mode Q.931 call control procedure */ +#define LAPD_SAPI_X25 16 /* X.25 Level 3 procedures */ +#define LAPD_SAPI_L2 63 /* Layer 2 management procedures */ + +#define LAPD_GSM_SAPI_RA_SIG_PROC 0 +#define LAPD_GSM_SAPI_NOT_USED_1 1 +#define LAPD_GSM_SAPI_NOT_USED_16 16 +#define LAPD_GSM_SAPI_OM_PROC 62 + +#endif /* lapd_sapi.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/llcsaps.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/llcsaps.h new file mode 100644 index 00000000..ddafad20 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/llcsaps.h @@ -0,0 +1,63 @@ +/* llcsaps.h + * Defines LLC SAP values. + * + * $Id: llcsaps.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __LLCSAPS_H__ +#define __LLCSAPS_H__ + +#define SAP_NULL 0x00 +#define SAP_LLC_SLMGMT 0x02 +#define SAP_SNA_PATHCTRL 0x04 +#define SAP_IP 0x06 +#define SAP_SNA1 0x08 +#define SAP_SNA2 0x0C +#define SAP_PROWAY_NM_INIT 0x0E +#define SAP_NETWARE1 0x10 +#define SAP_OSINL1 0x14 +#define SAP_TI 0x18 +#define SAP_OSINL2 0x20 +#define SAP_OSINL3 0x34 +#define SAP_SNA3 0x40 +#define SAP_BPDU 0x42 +#define SAP_RS511 0x4E +#define SAP_OSINL4 0x54 +#define SAP_X25 0x7E +#define SAP_XNS 0x80 +#define SAP_BACNET 0x82 +#define SAP_NESTAR 0x86 +#define SAP_PROWAY_ASLM 0x8E +#define SAP_ARP 0x98 +#define SAP_SNAP 0xAA +#define SAP_HPJD 0xB4 +#define SAP_VINES1 0xBA +#define SAP_VINES2 0xBC +#define SAP_NETWARE2 0xE0 +#define SAP_NETBIOS 0xF0 +#define SAP_IBMNM 0xF4 +#define SAP_HPEXT 0xF8 +#define SAP_UB 0xFA +#define SAP_RPL 0xFC +#define SAP_OSINL5 0xFE +#define SAP_GLOBAL 0xFF + +#endif /* llcsaps.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/next_tvb.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/next_tvb.h new file mode 100644 index 00000000..583c9a41 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/next_tvb.h @@ -0,0 +1,65 @@ +/* next_tvb.h + * Definitions for "next tvb" list + * + * $Id: next_tvb.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +/* The buffers returned by these functions are all allocated with a + * packet lifetime or are static buffers and does not have have to be freed. + * However, take into account that when the packet dissection + * completes, these buffers will be automatically reclaimed/freed. + * If you need the buffer to remain for a longer scope than packet lifetime + * you must copy the content to an se_alloc() buffer. + */ + +#ifndef __NEXT_TVB_H__ +#define __NEXT_TVB_H__ + +typedef enum { + NTVB_HANDLE, + NTVB_PORT, + NTVB_STRING +} next_tvb_call_e; + +typedef struct next_tvb_item { + struct next_tvb_item *next; + struct next_tvb_item *previous; + next_tvb_call_e type; + dissector_handle_t handle; + dissector_table_t table; + guint32 port; + const gchar *string; + tvbuff_t *tvb; + proto_tree *tree; +} next_tvb_item_t; + +typedef struct { + next_tvb_item_t *first; + next_tvb_item_t *last; + int count; +} next_tvb_list_t; + +extern void next_tvb_init(next_tvb_list_t *list); +extern void next_tvb_add_handle(next_tvb_list_t *list, tvbuff_t *tvb, proto_tree *tree, dissector_handle_t handle); +extern void next_tvb_add_port(next_tvb_list_t *list, tvbuff_t *tvb, proto_tree *tree, dissector_table_t table, guint32 port); +extern void next_tvb_add_string(next_tvb_list_t *list, tvbuff_t *tvb, proto_tree *tree, dissector_table_t table, const gchar *string); +extern void next_tvb_call(next_tvb_list_t *list, packet_info *pinfo, proto_tree *tree, dissector_handle_t handle, dissector_handle_t data_handle); + +#endif /* __NEXT_TVB_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/nlpid.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/nlpid.h new file mode 100644 index 00000000..c4c7ce40 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/nlpid.h @@ -0,0 +1,60 @@ +/* nlpid.h + * Definitions of OSI NLPIDs (Network Layer Protocol IDs) + * Laurent Deniel + * + * $Id: nlpid.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __NLPID_H__ +#define __NLPID_H__ + +/* X.263 / ISO/IEC TR 9577 NLPID values. */ + +#define NLPID_NULL 0x00 +#define NLPID_IPI_T_70 0x01 /* T.70, when an IPI */ +#define NLPID_SPI_X_29 0x01 /* X.29, when an SPI */ +#define NLPID_X_633 0x03 /* X.633 */ +#define NLPID_Q_931 0x08 /* Q.931, Q.932, X.36, ISO 11572, ISO 11582 */ +#define NLPID_Q_933 0x08 /* Q.933, on Frame Relay */ +#define NLPID_Q_2931 0x09 /* Q.2931 */ +#define NLPID_Q_2119 0x0c /* Q.2119 */ +#define NLPID_SNAP 0x80 +#define NLPID_ISO8473_CLNP 0x81 /* X.233 */ +#define NLPID_ISO9542_ESIS 0x82 +#define NLPID_ISO10589_ISIS 0x83 +#define NLPID_ISO10747_IDRP 0x85 +#define NLPID_ISO9542X25_ESIS 0x8a +#define NLPID_ISO10030 0x8c +#define NLPID_ISO11577 0x8d /* X.273 */ +#define NLPID_IP6 0x8e +#define NLPID_COMPRESSED 0xb0 /* "Data compression protocol" */ +#define NLPID_SNDCF 0xc1 /* "SubNetwork Dependent Convergence Function */ +#define NLPID_IP 0xcc +#define NLPID_PPP 0xcf + +extern const value_string nlpid_vals[]; + +/* + * 0x09 is, in Frame Relay, LMI, Q.2931. + */ +#define NLPID_LMI 0x09 /* LMI */ + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/nstime.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/nstime.h new file mode 100644 index 00000000..c92375df --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/nstime.h @@ -0,0 +1,92 @@ +/* nstime.h + * Definition of data structure to hold time values with nanosecond resolution + * + * $Id: nstime.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __NSTIME_H__ +#define __NSTIME_H__ + +#include + +#include + +typedef struct { + time_t secs; + int nsecs; +} nstime_t; + +/* functions */ + +/* set the given nstime_t to zero */ +extern void nstime_set_zero(nstime_t *nstime); + +/* is the given nstime_t currently zero? */ +extern gboolean nstime_is_zero(nstime_t *nstime); + +/* set the given nstime_t to (0,maxint) to mark it as "unset" + * That way we can find the first frame even when a timestamp + * is zero (fix for bug 1056) + */ +extern void nstime_set_unset(nstime_t *nstime); + +/* is the given nstime_t currently (0,maxint)? */ +extern gboolean nstime_is_unset(nstime_t *nstime); + +/* calculate the delta between two times (can be negative!) + * + * delta = b-a + * + * Note that it is acceptable for two or more of the arguments to point at the + * same structure. + */ +extern void nstime_delta(nstime_t *delta, const nstime_t *b, const nstime_t *a ); + +/* calculate the sum of two times + * + * sum = a+b + * + * Note that it is acceptable for two or more of the arguments to point at the + * same structure. + */ +extern void nstime_sum(nstime_t *sum, const nstime_t *b, const nstime_t *a ); + +/* sum += a */ +#define nstime_add(sum, a) nstime_sum(sum, sum, a) + +/* compare two times are return a value similar to memcmp() or strcmp(). + * + * a > b : > 0 + * a = b : 0 + * a < b : < 0 + */ +extern int nstime_cmp(nstime_t *a, const nstime_t *b ); + +/* converts nstime to double, time base is milli seconds */ +extern double nstime_to_msec(const nstime_t *time); + +/* converts nstime to double, time base is seconds */ +extern double nstime_to_sec(const nstime_t *time); + +/* converts wtap_nstime to double, time base is seconds */ +extern double wtap_nstime_to_sec(const struct wtap_nstime *time); + +#endif /* __NSTIME_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/oids.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/oids.h new file mode 100644 index 00000000..50a4ea83 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/oids.h @@ -0,0 +1,179 @@ +/* oids.h + * Object IDentifier Support + * + * $Id: oids.h 3992 2008-06-10 03:13:11Z dgu $ + * + * (c) 2007, Luis E. Garcia Ontanon + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __OIDS_H__ +#define __OIDS_H__ + +#define BER_TAG_ANY -1 + +struct _oid_bit_t { + guint offset; + int hfid; +}; + +typedef struct _oid_bits_info_t { + guint num; + gint ett; + struct _oid_bit_t* data; +} oid_bits_info_t; + +typedef enum _oid_key_type_t { + OID_KEY_TYPE_WRONG, + OID_KEY_TYPE_INTEGER, + OID_KEY_TYPE_OID, + OID_KEY_TYPE_STRING, + OID_KEY_TYPE_BYTES, + OID_KEY_TYPE_NSAP, + OID_KEY_TYPE_IPADDR, + OID_KEY_TYPE_IMPLIED_OID, + OID_KEY_TYPE_IMPLIED_STRING, + OID_KEY_TYPE_IMPLIED_BYTES +} oid_key_type_t; + +typedef struct _oid_value_type_t { + enum ftenum ft_type; + int display; + gint8 ber_class; + gint32 ber_tag; + int min_len; + int max_len; + oid_key_type_t keytype; + int keysize; +} oid_value_type_t; + +typedef enum _oid_kind_t { + OID_KIND_UNKNOWN = 0, + OID_KIND_NODE, + OID_KIND_SCALAR, + OID_KIND_TABLE, + OID_KIND_ROW, + OID_KIND_COLUMN, + OID_KIND_NOTIFICATION, + OID_KIND_GROUP, + OID_KIND_COMPLIANCE, + OID_KIND_CAPABILITIES +} oid_kind_t; + +typedef struct _oid_key_t { + char* name; + guint32 num_subids; + oid_key_type_t key_type; + int hfid; + enum ftenum ft_type; + int display; + struct _oid_key_t* next; +} oid_key_t; + +typedef struct _oid_info_t { + guint32 subid; + char* name; + oid_kind_t kind; + void* children; /* an emem_tree_t* */ + const oid_value_type_t* value_type; + int value_hfid; + oid_key_t* key; + oid_bits_info_t* bits; + struct _oid_info_t* parent; +} oid_info_t; + +/* init funcion called from epan.h */ +extern void oids_init(void); + +/* + * The objects returned by all these functions are all allocated with a + * packet lifetime and does not have have to be freed. + * However, take into account that when the packet dissection + * completes, these buffers will be automatically reclaimed/freed. + * If you need the buffer to remain for a longer scope than packet lifetime + * you must copy the content to an se_alloc() buffer. + */ + +/* + * These functions convert through the various formats: + * string: is like "0.1.3.4.5.30" (not resolved) + * encoded: is BER encoded (as per X.690 section 8.19) + * subids: is an array of guint32s + */ + +/* return length of encoded buffer */ +guint oid_subid2encoded(guint len, guint32* subids, guint8** encoded_p); +guint oid_string2encoded(const gchar *oid_str, guint8** encoded_p); + +/* return length of subid array */ +guint oid_encoded2subid(const guint8 *oid, gint len, guint32** subids_p); +guint oid_string2subid(const gchar *oid_str, guint32** subids_p); + +extern const gchar* oid_encoded2string(const guint8* encoded, guint len); +extern const gchar* oid_subid2string(guint32 *subids, guint len); + +/* these return a formated string as human readable as posible */ +extern const gchar *oid_resolved(guint len, guint32 *subids); +extern const gchar *oid_resolved_from_encoded(const guint8 *oid, gint len); +extern const gchar *oid_resolved_from_string(const gchar *oid_str); + +/* these yield two formated strings one resolved and one numeric */ +extern void oid_both(guint oid_len, guint32 *subids, char** resolved_p, char** numeric_p); +extern void oid_both_from_encoded(const guint8 *oid, gint oid_len, char** resolved_p, char** numeric_p); +extern void oid_both_from_string(const gchar *oid_str, char** resolved_p, char** numeric_p); + +/* + * These return the info for the best match. + * *matched_p will be set to the number of nodes used by the returned oid + * *left_p will be set to the number of remaining unresolved subids + */ +extern oid_info_t* oid_get(guint oid_len, guint32 *subids, guint* matched_p, guint* left_p); +extern oid_info_t* oid_get_from_encoded(const guint8 *oid, gint oid_len, guint32 **subids, guint* matched, guint* left); +extern oid_info_t* oid_get_from_string(const gchar *oid_str, guint32 **subids, guint* matched, guint* left); + +/* these are used to add oids to the collection */ +extern void oid_add(const char* name, guint oid_len, guint32 *subids); +extern void oid_add_from_encoded(const char* name, const guint8 *oid, gint oid_len); +extern void oid_add_from_string(const char* name, const gchar *oid_str); + +/** + * Fetch the default MIB/PIB path + * + * @return A string containing the default MIB/PIB path. It must be + * g_free()d by the caller. + */ +extern gchar *oid_get_default_mib_path(void); + +extern void oid_add_from_string(const char* name, const gchar *oid_str); + +/* macros for legacy oid functions */ +#define oid_resolv_cleanup() ((void)0) +#define subid_t guint32 + + + +#ifdef DEBUG_OIDS +extern char* oid_test_a2b(guint32 num_subids, guint32* subids); +extern void add_oid_debug_subtree(oid_info_t* oid_info, proto_tree *tree); +#else +#define add_oid_debug_subtree(a,b) ((void)0) +#endif + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/osi-utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/osi-utils.h new file mode 100644 index 00000000..97b6b27a --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/osi-utils.h @@ -0,0 +1,57 @@ +/* osi-utils.h + * + * $Id: osi-utils.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __OSI_UTILS_H__ +#define __OSI_UTILS_H__ + +/* OSI Global defines, common for all OSI protocols */ + +#define MAX_NSAP_LEN 30 +#define MAX_SYSTEMID_LEN 15 +#define MAX_AREA_LEN 30 + +#define RFC1237_NSAP_LEN 20 +#define RFC1237_FULLAREA_LEN 13 +#define RFC1237_SYSTEMID_LEN 6 +#define RFC1237_SELECTOR_LEN 1 + +#define RFC1237_IDI_LEN 2 +#define RFC1237_AFI_LEN 1 +#define RFC1237_DFI_LEN 1 +#define RFC1237_ORG_LEN 3 +#define RFC1237_AA_LEN 3 +#define RFC1237_RSVD_LEN 2 +#define RFC1237_RD_LEN 2 +#define RFC1237_AREA_LEN 3 + +#define NSAP_IDI_ISODCC 0x39 +#define NSAP_IDI_GOSIP2 0x47 + +gchar* print_nsap_net ( const guint8 *, int ); +void print_nsap_net_buf( const guint8 *, int, gchar *, int); +gchar* print_area ( const guint8 *, int ); +void print_area_buf ( const guint8 *, int, gchar *, int); +gchar* print_system_id( const guint8 *, int ); +void print_system_id_buf( const guint8 *, int, gchar *, int); + +#endif /* __OSI_UTILS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/oui.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/oui.h new file mode 100644 index 00000000..1431d530 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/oui.h @@ -0,0 +1,74 @@ +/* oui.h + * Definitions of OUIs + * + * $Id: oui.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 - 2000 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __OUI_H__ +#define __OUI_H__ + +/* + * See + * + * http://standards.ieee.org/regauth/oui/oui.txt + * + * http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/vlan.htm + * + * for the PIDs for VTP and DRiP that go with an OUI of OUI_CISCO. + */ + +#define OUI_ENCAP_ETHER 0x000000 /* encapsulated Ethernet */ +#define OUI_XEROX 0x000006 /* Xerox */ +#define OUI_CISCO 0x00000C /* Cisco (future use) */ +#define OUI_NORTEL 0x000081 /* Nortel SONMP */ +#define OUI_CISCO_90 0x0000F8 /* Cisco (IOS 9.0 and above?) */ +#define OUI_ERICSSON 0x0001EC /* Ericsson Group */ +#define OUI_CATENA 0x00025A /* Catena Networks */ +#define OUI_SONY_ERICSSON 0x000AD9 /* Sony Ericsson Mobile Communications AB */ +#define OUI_SONY_ERICSSON_2 0x000E07 /* Sony Ericsson Mobile Communications AB */ +#define OUI_PROFINET 0x000ECF /* PROFIBUS Nutzerorganisation e.V. */ +#define OUI_SONY_ERICSSON_3 0x000FDE /* Sony Ericsson Mobile Communications AB */ +#define OUI_IEEE_802_3 0x00120F /* IEEE 802.3 */ +#define OUI_MEDIA_ENDPOINT 0x0012BB /* Media (TIA TR-41 Committee) */ +#define OUI_SONY_ERICSSON_4 0x0012EE /* Sony Ericsson Mobile Communications AB */ +#define OUI_ERICSSON_MOBILE 0x0015E0 /* Ericsson Mobile Platforms */ +#define OUI_SONY_ERICSSON_5 0x001620 /* Sony Ericsson Mobile Communications AB */ +#define OUI_SONY_ERICSSON_6 0x0016B8 /* Sony Ericsson Mobile Communications AB */ +#define OUI_SONY_ERICSSON_7 0x001813 /* Sony Ericsson Mobile Communications AB */ +#define OUI_SONY_ERICSSON_8 0x001963 /* Sony Ericsson Mobile Communications AB */ +#define OUI_CISCOWL 0x004096 /* Cisco Wireless (Aironet) */ +#define OUI_ERICSSON_2 0x008037 /* Ericsson Group */ +#define OUI_BRIDGED 0x0080C2 /* Bridged Frame-Relay, RFC 2427 */ + /* and Bridged ATM, RFC 2684 */ +#define OUI_IEEE_802_1 0x0080C2 /* IEEE 802.1 Committee */ +#define OUI_ATM_FORUM 0x00A03E /* ATM Forum */ +#define OUI_EXTREME 0x00E02B /* Extreme EDP/ESRP */ +#define OUI_CABLE_BPDU 0x00E02F /* DOCSIS spanning tree BPDU */ +#define OUI_SIEMENS 0x080006 /* Siemens AG */ +#define OUI_APPLE_ATALK 0x080007 /* Appletalk */ +#define OUI_HP 0x080009 /* Hewlett-Packard */ + +/* + * Defined in packet-llc.c + */ +extern const value_string oui_vals[]; + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/packet.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/packet.h new file mode 100644 index 00000000..5061c565 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/packet.h @@ -0,0 +1,422 @@ +/* packet.h + * Definitions for packet disassembly structures and routines + * + * $Id: packet.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __PACKET_H__ +#define __PACKET_H__ + +/* + * If defines formats to be used to print 64-bit integers, + * include it. + */ +#ifdef INTTYPES_H_DEFINES_FORMATS +#include +#endif + +#include "wiretap/wtap.h" +#include "proto.h" +#include "tvbuff.h" +#include "pint.h" +#include "to_str.h" +#include "value_string.h" +#include "column_info.h" +#include "frame_data.h" +#include "packet_info.h" +#include "column-utils.h" +#include "epan.h" +#include "tfs.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define hi_nibble(b) (((b) & 0xf0) >> 4) +#define lo_nibble(b) ((b) & 0x0f) + +/* Useful when you have an array whose size you can tell at compile-time */ +#define array_length(x) (sizeof x / sizeof x[0]) + +/* Check whether the "len" bytes of data starting at "offset" is + * entirely inside the captured data for this packet. */ +#define BYTES_ARE_IN_FRAME(offset, captured_len, len) \ + ((guint)(offset) + (guint)(len) > (guint)(offset) && \ + (guint)(offset) + (guint)(len) <= (guint)(captured_len)) + +/* To pass one of two strings, singular or plural */ +#define plurality(d,s,p) ((d) == 1 ? (s) : (p)) + +typedef struct _packet_counts { + gint sctp; + gint tcp; + gint udp; + gint icmp; + gint ospf; + gint gre; + gint netbios; + gint ipx; + gint vines; + gint other; + gint total; + gint arp; +} packet_counts; + +/** Number of packet counts. */ +#define PACKET_COUNTS_SIZE sizeof(packet_counts) / sizeof (gint) + +/* Types of character encodings */ +typedef enum { + CHAR_ASCII = 0, /* ASCII */ + CHAR_EBCDIC = 1 /* EBCDIC */ +} char_enc; + +extern void packet_init(void); +extern void packet_cleanup(void); + +/* Handle for dissectors you call directly or register with "dissector_add()". + This handle is opaque outside of "packet.c". */ +struct dissector_handle; +typedef struct dissector_handle *dissector_handle_t; + +/* Hash table for matching port numbers and dissectors; this is opaque + outside of "packet.c". */ +struct dissector_table; +typedef struct dissector_table *dissector_table_t; + +/* + * Dissector that returns nothing. + */ +typedef void (*dissector_t)(tvbuff_t *, packet_info *, proto_tree *); + +/* + * Dissector that returns: + * + * The amount of data in the protocol's PDU, if it was able to + * dissect all the data; + * + * 0, if the tvbuff doesn't contain a PDU for that protocol; + * + * The negative of the amount of additional data needed, if + * we need more data (e.g., from subsequent TCP segments) to + * dissect the entire PDU. + */ +typedef int (*new_dissector_t)(tvbuff_t *, packet_info *, proto_tree *); + +/** Type of a heuristic dissector, used in heur_dissector_add(). + * + * @param tvb the tv_buff with the (remaining) packet data + * @param pinfo the packet info of this packet (additional info) + * @param tree the protocol tree to be build or NULL + * @return TRUE if the packet was recognized by the sub-dissector (stop dissection here) + */ +typedef gboolean (*heur_dissector_t)(tvbuff_t *tvb, packet_info *pinfo, + proto_tree *tree); + +typedef void (*DATFunc) (const gchar *table_name, ftenum_t selector_type, + gpointer key, gpointer value, gpointer user_data); +typedef void (*DATFunc_handle) (const gchar *table_name, gpointer value, + gpointer user_data); +typedef void (*DATFunc_table) (const gchar *table_name, const gchar *ui_name, + gpointer user_data); + +/* Opaque structure - provides type checking but no access to components */ +typedef struct dtbl_entry dtbl_entry_t; + +extern dissector_handle_t dtbl_entry_get_handle (dtbl_entry_t *dtbl_entry); +extern dissector_handle_t dtbl_entry_get_initial_handle (dtbl_entry_t * entry); +extern void dissector_table_foreach_changed (const char *name, DATFunc func, + gpointer user_data); +extern void dissector_table_foreach (const char *name, DATFunc func, + gpointer user_data); +extern void dissector_all_tables_foreach_changed (DATFunc func, + gpointer user_data); +extern void dissector_table_foreach_handle(const char *name, DATFunc_handle func, + gpointer user_data); +extern void dissector_all_tables_foreach_table (DATFunc_table func, + gpointer user_data); + +/* a protocol uses the function to register a sub-dissector table */ +extern dissector_table_t register_dissector_table(const char *name, + const char *ui_name, ftenum_t type, int base); + +/* Find a dissector table by table name. */ +extern dissector_table_t find_dissector_table(const char *name); + +/* Get the UI name for a sub-dissector table, given its internal name */ +extern const char *get_dissector_table_ui_name(const char *name); + +/* Get the field type for values of the selector for a dissector table, + given the table's internal name */ +extern ftenum_t get_dissector_table_selector_type(const char *name); + +/* Get the base to use when displaying values of the selector for a + sub-dissector table, given the table's internal name */ +extern int get_dissector_table_base(const char *name); + +/* Add an entry to a uint dissector table. */ +extern void dissector_add(const char *abbrev, guint32 pattern, + dissector_handle_t handle); + +/* Delete the entry for a dissector in a uint dissector table + with a particular pattern. */ +extern void dissector_delete(const char *name, guint32 pattern, + dissector_handle_t handle); + +/* Change the entry for a dissector in a uint dissector table + with a particular pattern to use a new dissector handle. */ +extern void dissector_change(const char *abbrev, guint32 pattern, + dissector_handle_t handle); + +/* Reset an entry in a uint dissector table to its initial value. */ +extern void dissector_reset(const char *name, guint32 pattern); + +/* Look for a given value in a given uint dissector table and, if found, + call the dissector with the arguments supplied, and return TRUE, + otherwise return FALSE. */ +extern gboolean dissector_try_port(dissector_table_t sub_dissectors, + guint32 port, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); + +/* Look for a given value in a given uint dissector table and, if found, + return the dissector handle for that value. */ +extern dissector_handle_t dissector_get_port_handle( + dissector_table_t sub_dissectors, guint32 port); + +/* Add an entry to a string dissector table. */ +extern void dissector_add_string(const char *name, const gchar *pattern, + dissector_handle_t handle); + +/* Delete the entry for a dissector in a string dissector table + with a particular pattern. */ +extern void dissector_delete_string(const char *name, const gchar *pattern, + dissector_handle_t handle); + +/* Change the entry for a dissector in a string dissector table + with a particular pattern to use a new dissector handle. */ +extern void dissector_change_string(const char *name, gchar *pattern, + dissector_handle_t handle); + +/* Reset an entry in a string sub-dissector table to its initial value. */ +extern void dissector_reset_string(const char *name, const gchar *pattern); + +/* Look for a given string in a given dissector table and, if found, call + the dissector with the arguments supplied, and return TRUE, otherwise + return FALSE. */ +extern gboolean dissector_try_string(dissector_table_t sub_dissectors, + const gchar *string, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); + +/* Look for a given value in a given string dissector table and, if found, + return the dissector handle for that value. */ +extern dissector_handle_t dissector_get_string_handle( + dissector_table_t sub_dissectors, const gchar *string); + +/* Add a handle to the list of handles that *could* be used with this + table. That list is used by code in the UI. */ +extern void dissector_add_handle(const char *name, dissector_handle_t handle); + +/* List of "heuristic" dissectors (which get handed a packet, look at it, + and either recognize it as being for their protocol, dissect it, and + return TRUE, or don't recognize it and return FALSE) to be called + by another dissector. */ +typedef GSList *heur_dissector_list_t; + +/** A protocol uses this function to register a heuristic sub-dissector list. + * Call this in the parent dissectors proto_register function. + * + * @param name the name of this protocol + * @param list the list of heuristic sub-dissectors to be registered + */ +extern void register_heur_dissector_list(const char *name, + heur_dissector_list_t *list); + +/** Try all the dissectors in a given heuristic dissector list. This is done, + * until we find one that recognizes the protocol. + * Call this while the parent dissector running. + * + * @param sub_dissectors the sub-dissector list + * @param tvb the tv_buff with the (remaining) packet data + * @param pinfo the packet info of this packet (additional info) + * @param tree the protocol tree to be build or NULL + * @return TRUE if the packet was recognized by the sub-dissector (stop dissection here) + */ +extern gboolean dissector_try_heuristic(heur_dissector_list_t sub_dissectors, + tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); + +/** Add a sub-dissector to a heuristic dissector list. + * Call this in the proto_handoff function of the sub-dissector. + * + * @param name the name of the "parent" protocol, e.g. "tcp" + * @param dissector the sub-dissector to be registered + * @param proto the protocol id of the sub-dissector + */ +extern void heur_dissector_add(const char *name, heur_dissector_t dissector, + int proto); + +/** Remove a sub-dissector from a heuristic dissector list. + * Call this in the prefs_reinit function of the sub-dissector. + * + * @param name the name of the "parent" protocol, e.g. "tcp" + * @param dissector the sub-dissector to be unregistered + * @param proto the protocol id of the sub-dissector + */ +extern void heur_dissector_delete(const char *name, heur_dissector_t dissector, int proto); + +/* Register a dissector. */ +extern void register_dissector(const char *name, dissector_t dissector, + int proto); +extern void new_register_dissector(const char *name, new_dissector_t dissector, + int proto); + +/* Get the short name of the protocol for a dissector handle. */ +extern const char *dissector_handle_get_short_name(dissector_handle_t handle); + +/* Get the index of the protocol for a dissector handle. */ +extern int dissector_handle_get_protocol_index(dissector_handle_t handle); + +/* Find a dissector by name. */ +extern dissector_handle_t find_dissector(const char *name); + +/* Create an anonymous handle for a dissector. */ +extern dissector_handle_t create_dissector_handle(dissector_t dissector, + int proto); +extern dissector_handle_t new_create_dissector_handle(new_dissector_t dissector, + int proto); + +/* Call a dissector through a handle and if no dissector was found + * pass if over to the "data" dissector instead. + * + * @param handle The dissector to call. + * @param tvb The buffer to dissect. + * @param pinfo Packet Info. + * @param tree The protocol tree. + * @return If the protocol for that handle isn't enabled call the data + * dissector. Otherwise, if the handle refers to a new-style + * dissector, call the dissector and return its return value, otherwise call + * it and return the length of the tvbuff pointed to by the argument. + */ +extern int call_dissector(dissector_handle_t handle, tvbuff_t *tvb, + packet_info *pinfo, proto_tree *tree); + +/* Call a dissector through a handle but if no dissector was found + * just return 0 and do not call the "data" dissector instead. + * + * @param handle The dissector to call. + * @param tvb The buffer to dissect. + * @param pinfo Packet Info. + * @param tree The protocol tree. + * @return If the protocol for that handle isn't enabled, return 0 without + * calling the dissector. Otherwise, if the handle refers to a new-style + * dissector, call the dissector and return its return value, otherwise call + * it and return the length of the tvbuff pointed to by the argument. + */ +extern int call_dissector_only(dissector_handle_t handle, tvbuff_t *tvb, + packet_info *pinfo, proto_tree *tree); + +/* Do all one-time initialization. */ +extern void dissect_init(void); + +extern void dissect_cleanup(void); + +/* + * Given a tvbuff, and a length from a packet header, adjust the length + * of the tvbuff to reflect the specified length. + */ +extern void set_actual_length(tvbuff_t *tvb, guint specified_len); + +/* Allow protocols to register "init" routines, which are called before + we make a pass through a capture file and dissect all its packets + (e.g., when we read in a new capture file, or run a "filter packets" + or "colorize packets" pass over the current capture file). */ +extern void register_init_routine(void (*func)(void)); + +/* Initialize all data structures used for dissection. */ +extern void init_dissection(void); + +/* Free data structures allocated for dissection. */ +extern void cleanup_dissection(void); + +/* Allow protocols to register a "cleanup" routine to be + * run after the initial sequential run through the packets. + * Note that the file can still be open after this; this is not + * the final cleanup. */ +extern void register_postseq_cleanup_routine(void (*func)(void)); + +/* Call all the registered "postseq_cleanup" routines. */ +extern void postseq_cleanup_all_protocols(void); + +/* Allow dissectors to register a "final_registration" routine + * that is run like the proto_register_XXX() routine, but the end + * end of the epan_init() function; that is, *after* all other + * subsystems, liked dfilters, have finished initializing. This is + * useful for dissector registration routines which need to compile + * display filters. dfilters can't initialize itself until all protocols + * have registereed themselvs. */ +extern void +register_final_registration_routine(void (*func)(void)); + +/* Call all the registered "final_registration" routines. */ +extern void +final_registration_all_protocols(void); + +/* + * Add a new data source to the list of data sources for a frame, given + * the tvbuff for the data source and its name. + */ +extern void add_new_data_source(packet_info *pinfo, tvbuff_t *tvb, + const char *name); + +/* + * Free up a frame's list of data sources. + */ +extern void free_data_sources(packet_info *pinfo); + +/* + * Dissectors should never modify the packet data. + */ +extern void dissect_packet(epan_dissect_t *edt, + union wtap_pseudo_header *pseudo_header, const guchar *pd, + frame_data *fd, column_info *cinfo); + +/* These functions are in packet-ethertype.c */ +extern void capture_ethertype(guint16 etype, const guchar *pd, int offset, + int len, packet_counts *ld); +extern void ethertype(guint16 etype, tvbuff_t *tvb, int offset_after_ethertype, + packet_info *pinfo, proto_tree *tree, proto_tree *fh_tree, + int etype_id, int trailer_id, int fcs_len); + +/* + * Dump layer/selector/dissector records in a fashion similar to the + * proto_registrar_dump_* routines. + */ +extern void dissector_dump_decodes(void); + +/* + * post dissectors are to be called by packet-frame.c after every other + * dissector has been called. + */ +extern void register_postdissector(dissector_handle_t); +extern void call_all_postdissectors(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* packet.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/packet_info.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/packet_info.h new file mode 100644 index 00000000..3902be51 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/packet_info.h @@ -0,0 +1,184 @@ +/* packet_info.h + * Definitions for packet info structures and routines + * + * $Id: packet_info.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PACKET_INFO_H__ +#define __PACKET_INFO_H__ + +#include "frame_data.h" +#include "tvbuff.h" +#include "address.h" + +#define P2P_DIR_UNKNOWN -1 +#define P2P_DIR_SENT 0 +#define P2P_DIR_RECV 1 + +#define PINFO_SOF_FIRST_FRAME 0x1 +#define PINFO_SOF_SOFF 0x2 +#define PINFO_EOF_LAST_FRAME 0x80 +#define PINFO_EOF_INVALID 0x40 +#define MAX_NUMBER_OF_PPIDS 2 + +typedef struct _packet_info { + const char *current_proto; /* name of protocol currently being dissected */ + column_info *cinfo; /* Column formatting information */ + frame_data *fd; + union wtap_pseudo_header *pseudo_header; + GSList *data_src; /* Frame data sources */ + address dl_src; /* link-layer source address */ + address dl_dst; /* link-layer destination address */ + address net_src; /* network-layer source address */ + address net_dst; /* network-layer destination address */ + address src; /* source address (net if present, DL otherwise )*/ + address dst; /* destination address (net if present, DL otherwise )*/ + guint32 ethertype; /* Ethernet Type Code, if this is an Ethernet packet */ + guint32 ipproto; /* IP protocol, if this is an IP packet */ + guint32 ipxptype; /* IPX packet type, if this is an IPX packet */ + circuit_type ctype; /* type of circuit, for protocols with a VC identifier */ + guint32 circuit_id; /* circuit ID, for protocols with a VC identifier */ + const char *noreassembly_reason; /* reason why reassembly wasn't done, if any */ + gboolean fragmented; /* TRUE if the protocol is only a fragment */ + gboolean in_error_pkt; /* TRUE if we're inside an {ICMP,CLNP,...} error packet */ + port_type ptype; /* type of the following two port numbers */ + guint32 srcport; /* source port */ + guint32 destport; /* destination port */ + guint32 match_port; /* matched port for calling subdissector from table */ + const char *match_string; /* matched string for calling subdissector from table */ + guint16 can_desegment; /* >0 if this segment could be desegmented. + A dissector that can offer this API (e.g. + TCP) sets can_desegment=2, then + can_desegment is decremented by 1 each time + we pass to the next subdissector. Thus only + the dissector immediately above the + protocol which sets the flag can use it*/ + guint16 saved_can_desegment; /* Value of can_desegment before current + dissector was called. Supplied so that + dissectors for proxy protocols such as + SOCKS can restore it, allowing the + dissectors that they call to use the + TCP dissector's desegmentation (SOCKS + just retransmits TCP segments once it's + finished setting things up, so the TCP + desegmentor can desegment its payload). */ + int desegment_offset; /* offset to stuff needing desegmentation */ +#define DESEGMENT_ONE_MORE_SEGMENT 0x0fffffff +#define DESEGMENT_UNTIL_FIN 0x0ffffffe + guint32 desegment_len; /* requested desegmentation additional length + or + DESEGMENT_ONE_MORE_SEGMENT: + Desegment one more full segment + (warning! only partially implemented) + DESEGMENT_UNTIL_FIN: + Desgment all data for this tcp session + until the FIN segment. + */ + guint16 want_pdu_tracking; /* >0 if the subdissector has specified + a value in 'bytes_until_next_pdu'. + When a dissector detects that the next PDU + will start beyond the start of the next + segment, it can set this value to 2 + and 'bytes_until_next_pdu' to the number of + bytes beyond the next segment where the + next PDU starts. + + If the protocol dissector below this + one is capable of PDU tracking it can + use this hint to detect PDUs that starts + unaligned to the segment boundaries. + The TCP dissector is using this hint from + (some) protocols to detect when a new PDU + starts in the middle of a tcp segment. + + There is intelligence in the glue between + dissector layers to make sure that this + request is only passed down to the protocol + immediately below the current one and not + any further. + */ + guint32 bytes_until_next_pdu; + + + int iplen; /* total length of IP packet */ + int iphdrlen; /* length of IP header */ + int p2p_dir; /* Packet was captured as an + outbound (P2P_DIR_SENT) + inbound (P2P_DIR_RECV) + unknown (P2P_DIR_UNKNOWN) */ + guint16 oxid; /* next 2 fields reqd to identify fibre */ + guint16 rxid; /* channel conversations */ + guint8 r_ctl; /* R_CTL field in Fibre Channel Protocol */ + guint8 sof_eof; /* FC's SOF/EOF encoding passed to FC decoder + * Bit 7 set if Last frame in sequence + * Bit 6 set if invalid frame content + * Bit 2 set if SOFf + * Bit 1 set if first frame in sequence + */ + guint16 src_idx; /* Source port index (Cisco MDS-specific) */ + guint16 dst_idx; /* Dest port index (Cisco MDS-specific) */ + guint16 vsan; /* Fibre channel/Cisco MDS-specific */ + + /* Extra data for DCERPC handling and tracking of context ids */ + guint16 dcectxid; /* Context ID (DCERPC-specific) */ + int dcetransporttype; /* Transport type + * Value -1 means "not a DCERPC packet" + */ + guint16 dcetransportsalt; /* fid: if transporttype==DCE_CN_TRANSPORT_SMBPIPE */ + + /* Extra data for handling of decryption of GSSAPI wrapped tvbuffs. + Caller sets decrypt_gssapi_tvb if this service is requested. + If gssapi_encrypted_tvb is NULL, then the rest of the tvb data following + the gssapi blob itself is decrypted othervise the gssapi_encrypted_tvb + tvb will be decrypted (DCERPC has the data before the gssapi blob) + If, on return, gssapi_data_encrypted is FALSE, the wrapped tvbuff + was signed (i.e., an encrypted signature was present, to check + whether the data was modified by a man in the middle) but not sealed + (i.e., the data itself wasn't encrypted). + */ +#define DECRYPT_GSSAPI_NORMAL 1 +#define DECRYPT_GSSAPI_DCE 2 + guint16 decrypt_gssapi_tvb; + tvbuff_t *gssapi_wrap_tvb; + tvbuff_t *gssapi_encrypted_tvb; + tvbuff_t *gssapi_decrypted_tvb; + gboolean gssapi_data_encrypted; + + guint32 ppid[MAX_NUMBER_OF_PPIDS]; /* The first NUMBER_OF_PPIDS PPIDS which are present + * in the SCTP packet + */ + void *private_data; /* pointer to data passed from one dissector to another */ + GString *layer_names; /* layers of each protocol */ + guint16 link_number; + guint8 annex_a_used; + guint16 profinet_type; /* the type of PROFINET packet (0: not a PROFINET packet) */ + void *profinet_conv; /* the PROFINET conversation data (NULL: not a PROFINET packet) */ + void *usb_conv_info; + void *tcp_tree; /* proto_tree for the tcp layer */ + + const char *dcerpc_procedure_name; /* Used by PIDL to store the name of the current dcerpc procedure */ + + struct _sccp_msg_info_t* sccp_info; + guint16 clnp_srcref; /* clnp/cotp source reference (can't use srcport, this would confuse tpkt) */ + guint16 clnp_dstref; /* clnp/cotp destination reference (can't use dstport, this would confuse tpkt) */ +} packet_info; + +#endif /* __PACKET_INFO_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/pint.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/pint.h new file mode 100644 index 00000000..f947a04e --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/pint.h @@ -0,0 +1,113 @@ +/* pint.h + * Definitions for extracting and translating integers safely and portably + * via pointers. + * + * $Id: pint.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PINT_H__ +#define __PINT_H__ + +#include + +/* Pointer versions of g_ntohs and g_ntohl. Given a pointer to a member of a + * byte array, returns the value of the two or four bytes at the pointer. + * The pletoh[sl] versions return the little-endian representation. + */ + +#define pntohs(p) ((guint16) \ + ((guint16)*((const guint8 *)(p)+0)<<8| \ + (guint16)*((const guint8 *)(p)+1)<<0)) + +#define pntoh24(p) ((guint32)*((const guint8 *)(p)+0)<<16| \ + (guint32)*((const guint8 *)(p)+1)<<8| \ + (guint32)*((const guint8 *)(p)+2)<<0) + +#define pntohl(p) ((guint32)*((const guint8 *)(p)+0)<<24| \ + (guint32)*((const guint8 *)(p)+1)<<16| \ + (guint32)*((const guint8 *)(p)+2)<<8| \ + (guint32)*((const guint8 *)(p)+3)<<0) +#define pntoh64(p) ((guint64)*((const guint8 *)(p)+0)<<56| \ + (guint64)*((const guint8 *)(p)+1)<<48| \ + (guint64)*((const guint8 *)(p)+2)<<40| \ + (guint64)*((const guint8 *)(p)+3)<<32| \ + (guint64)*((const guint8 *)(p)+4)<<24| \ + (guint64)*((const guint8 *)(p)+5)<<16| \ + (guint64)*((const guint8 *)(p)+6)<<8| \ + (guint64)*((const guint8 *)(p)+7)<<0) + + +#define pletohs(p) ((guint16) \ + ((guint16)*((const guint8 *)(p)+1)<<8| \ + (guint16)*((const guint8 *)(p)+0)<<0)) + +#define pletoh24(p) ((guint32)*((const guint8 *)(p)+2)<<16| \ + (guint32)*((const guint8 *)(p)+1)<<8| \ + (guint32)*((const guint8 *)(p)+0)<<0) + +#define pletohl(p) ((guint32)*((const guint8 *)(p)+3)<<24| \ + (guint32)*((const guint8 *)(p)+2)<<16| \ + (guint32)*((const guint8 *)(p)+1)<<8| \ + (guint32)*((const guint8 *)(p)+0)<<0) +#define pletoh64(p) ((guint64)*((const guint8 *)(p)+7)<<56| \ + (guint64)*((const guint8 *)(p)+6)<<48| \ + (guint64)*((const guint8 *)(p)+5)<<40| \ + (guint64)*((const guint8 *)(p)+4)<<32| \ + (guint64)*((const guint8 *)(p)+3)<<24| \ + (guint64)*((const guint8 *)(p)+2)<<16| \ + (guint64)*((const guint8 *)(p)+1)<<8| \ + (guint64)*((const guint8 *)(p)+0)<<0) + +/* Pointer routines to put items out in a particular byte order. + * These will work regardless of the byte alignment of the pointer. + */ + +#define phtons(p, v) \ + { \ + ((guint8*)(p))[0] = (guint8)((v) >> 8); \ + ((guint8*)(p))[1] = (guint8)((v) >> 0); \ + } + +#define phtonl(p, v) \ + { \ + ((guint8*)(p))[0] = (guint8)((v) >> 24); \ + ((guint8*)(p))[1] = (guint8)((v) >> 16); \ + ((guint8*)(p))[2] = (guint8)((v) >> 8); \ + ((guint8*)(p))[3] = (guint8)((v) >> 0); \ + } + + +/* Macros to byte-swap 32-bit and 16-bit quantities. */ +#define BSWAP32(x) \ + ((((x)&0xFF000000)>>24) | \ + (((x)&0x00FF0000)>>8) | \ + (((x)&0x0000FF00)<<8) | \ + (((x)&0x000000FF)<<24)) +#define BSWAP16(x) \ + ((((x)&0xFF00)>>8) | \ + (((x)&0x00FF)<<8)) + +/* Turn host-byte-order values into little-endian values. */ +#define htoles(s) GUINT16_TO_LE(s) +#define htolel(l) GUINT32_TO_LE(l) + +#endif /* PINT_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/plugins.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/plugins.h new file mode 100644 index 00000000..100e5805 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/plugins.h @@ -0,0 +1,58 @@ +/* plugins.h + * definitions for plugins structures + * + * $Id: plugins.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1999 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PLUGINS_H__ +#define __PLUGINS_H__ + +#include +#include + +#include "packet.h" + +typedef struct _plugin { + GModule *handle; /* handle returned by dlopen */ + gchar *name; /* plugin name */ + gchar *version; /* plugin version */ + void (*register_protoinfo)(void); /* routine to call to register protocol information */ + void (*reg_handoff)(void); /* routine to call to register dissector handoff */ + void (*register_tap_listener)(void); /* routine to call to register tap listener */ + void (*register_wtap_module)(void); /* routine to call to register a wiretap module */ + void (*register_codec_module)(void); /* routine to call to register a codec */ + struct _plugin *next; /* forward link */ +} plugin; + +WS_VAR_IMPORT plugin *plugin_list; + +extern void init_plugins(void); +extern void register_all_plugin_registrations(void); +extern void register_all_plugin_handoffs(void); +extern void register_all_plugin_tap_listeners(void); +extern void register_all_wiretap_modules(void); +extern void register_all_codecs(void); + +/* get the personal plugin dir */ +/* Return value is g_malloced so the caller should g_free() it. */ +extern char *get_plugins_pers_dir(void); + +#endif /* __PLUGINS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ppptypes.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ppptypes.h new file mode 100644 index 00000000..64bbcb34 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ppptypes.h @@ -0,0 +1,158 @@ +/* ppptypes.h + * Defines PPP packet types. + * + * $Id: ppptypes.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PPPTYPES_H__ +#define __PPPTYPES_H__ + +/* Protocol types, from Linux "ppp_defs.h" and + + http://www.iana.org/assignments/ppp-numbers + + */ +#define PPP_PADDING 0x1 /* Padding Protocol */ +#define PPP_ROHC_SCID 0x3 /* ROHC small-CID */ +#define PPP_ROHC_LCID 0x5 /* ROHC large-CID */ +#define PPP_IP 0x21 /* Internet Protocol */ +#define PPP_OSI 0x23 /* OSI Protocol */ +#define PPP_DEC4 0x25 /* DECnet Phase IV */ +#define PPP_AT 0x29 /* AppleTalk Protocol */ +#define PPP_IPX 0x2b /* IPX protocol */ +#define PPP_VJC_COMP 0x2d /* VJ compressed TCP */ +#define PPP_VJC_UNCOMP 0x2f /* VJ uncompressed TCP */ +#define PPP_BPDU 0x31 /* Bridging PDU (spanning tree BPDU?) */ +#define PPP_ST 0x33 /* Stream Protocol (ST-II) */ +#define PPP_VINES 0x35 /* Banyan Vines */ +#define PPP_AT_EDDP 0x39 /* AppleTalk EDDP */ +#define PPP_AT_SB 0x3b /* AppleTalk SmartBuffered */ +#define PPP_MP 0x3d /* Multilink PPP */ +#define PPP_NB 0x3f /* NETBIOS Framing */ +#define PPP_CISCO 0x41 /* Cisco Systems */ +#define PPP_ASCOM 0x43 /* Ascom Timeplex */ +#define PPP_LBLB 0x45 /* Fujitsu Link Backup and Load Balancing */ +#define PPP_RL 0x47 /* DCA Remote Lan */ +#define PPP_SDTP 0x49 /* Serial Data Transport Protocol */ +#define PPP_LLC 0x4b /* SNA over LLC */ +#define PPP_SNA 0x4d /* SNA */ +#define PPP_IPV6HC 0x4f /* IPv6 Header Compression */ +#define PPP_KNX 0x51 /* KNX Bridging Data */ +#define PPP_ENCRYPT 0x53 /* Encryption */ +#define PPP_ILE 0x55 /* Individual Link Encryption */ +#define PPP_IPV6 0x57 /* Internet Protocol Version 6 */ +#define PPP_MUX 0x59 /* PPP Multiplexing */ +#define PPP_RTP_FH 0x61 /* RTP IPHC Full Header */ +#define PPP_RTP_CTCP 0x63 /* RTP IPHC Compressed TCP */ +#define PPP_RTP_CNTCP 0x65 /* RTP IPHC Compressed Non TCP */ +#define PPP_RTP_CUDP8 0x67 /* RTP IPHC Compressed UDP 8 */ +#define PPP_RTP_CRTP8 0x69 /* RTP IPHC Compressed RTP 8 */ +#define PPP_STAMPEDE 0x6f /* Stampede Bridging */ +#define PPP_MPPLUS 0x73 /* MP+ Protocol */ +#define PPP_NTCITS_IPI 0xc1 /* NTCITS IPI */ +#define PPP_ML_SLCOMP 0xfb /* single link compression in multilink */ +#define PPP_COMP 0xfd /* compressed packet */ +#define PPP_STP_HELLO 0x0201 /* 802.1d Hello Packet */ +#define PPP_IBM_SR 0x0203 /* IBM Source Routing BPDU */ +#define PPP_DEC_LB 0x0205 /* DEC LANBridge100 Spanning Tree */ +#define PPP_CDP 0x0207 /* Cisco Discovery Protocol */ +#define PPP_NETCS 0x0209 /* Netcs Twin Routing */ +#define PPP_STP 0x020b /* Scheduled Transfer Protocol */ +#define PPP_EDP 0x020d /* Extreme Discovery Protocol */ +#define PPP_OSCP 0x0211 /* Optical Supervisory Channel Protocol */ +#define PPP_OSCP2 0x0213 /* Optical Supervisory Channel Protocol */ +#define PPP_LUXCOM 0x0231 /* Luxcom */ +#define PPP_SIGMA 0x0233 /* Sigma Network Systems */ +#define PPP_ACSP 0x0235 /* Apple Client Server Protocol */ +#define PPP_MPLS_UNI 0x0281 /* MPLS Unicast */ +#define PPP_MPLS_MULTI 0x0283 /* MPLS Multicast */ +#define PPP_P12844 0x0285 /* IEEE p1284.4 standard - data packets */ +#define PPP_ETSI 0x0287 /* ETSI TETRA Networks Procotol Type 1 */ +#define PPP_MFTP 0x0289 /* Multichannel Flow Treatment Protocol */ +#define PPP_RTP_CTCPND 0x2063 /* RTP IPHC Compressed TCP No Delta */ +#define PPP_RTP_CS 0x2065 /* RTP IPHC Context State */ +#define PPP_RTP_CUDP16 0x2067 /* RTP IPHC Compressed UDP 16 */ +#define PPP_RTP_CRDP16 0x2069 /* RTP IPHC Compressed RTP 16 */ +#define PPP_CCCP 0x4001 /* Cray Communications Control Protocol */ +#define PPP_CDPD_MNRP 0x4003 /* CDPD Mobile Network Registration Protocol */ +#define PPP_EXPANDAP 0x4005 /* Expand accelarator protocol */ +#define PPP_ODSICP 0x4007 /* ODSICP NCP */ +#define PPP_DOCSIS 0x4009 /* DOCSIS DLL */ +#define PPP_LZS 0x4021 /* Stacker LZS */ +#define PPP_REFTEK 0x4023 /* RefTek Protocol */ +#define PPP_FC 0x4025 /* Fibre Channel */ +#define PPP_EMIT 0x4027 /* EMIT Protocols */ +#define PPP_IPCP 0x8021 /* IP Control Protocol */ +#define PPP_OSICP 0x8023 /* OSI Control Protocol */ +#define PPP_XNSIDPCP 0x8025 /* Xerox NS IDP Control Protocol */ +#define PPP_DECNETCP 0x8027 /* DECnet Phase IV Control Protocol */ +#define PPP_ATCP 0x8029 /* AppleTalk Control Protocol */ +#define PPP_IPXCP 0x802b /* IPX Control Protocol */ +#define PPP_BRIDGENCP 0x8031 /* Bridging NCP */ +#define PPP_SPCP 0x8033 /* Stream Protocol Control Protocol */ +#define PPP_BVCP 0x8035 /* Banyan Vines Control Protocol */ +#define PPP_MLCP 0x803d /* Multi-Link Control Protocol */ +#define PPP_NBCP 0x803f /* NETBIOS Framing Control Protocol */ +#define PPP_CISCOCP 0x8041 /* Cisco Systems Control Protocol */ +#define PPP_ASCOMCP 0x8043 /* Ascom Timeplex Control Protocol (?) */ +#define PPP_LBLBCP 0x8045 /* Fujitsu LBLB Control Protocol */ +#define PPP_RLNCP 0x8047 /* DCA Remote Lan Network Control Protocol */ +#define PPP_SDCP 0x8049 /* Serial Data Control Protocol */ +#define PPP_LLCCP 0x804b /* SNA over LLC Control Protocol */ +#define PPP_SNACP 0x804d /* SNA Control Protocol */ +#define PPP_KNXCP 0x8051 /* KNX Bridging Control Protocol */ +#define PPP_ECP 0x8053 /* Encryption Control Protocol */ +#define PPP_ILECP 0x8055 /* Individual Encryption Control Protocol */ +#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */ +#define PPP_MUXCP 0x8059 /* PPPMux Control Protocol */ +#define PPP_STAMPEDECP 0x806f /* Stampede Bridging Control Protocol */ +#define PPP_MPPCP 0x8073 /* MP+ Contorol Protocol */ +#define PPP_IPICP 0x80c1 /* NTCITS IPI Control Protocol */ +#define PPP_SLCC 0x80fb /* single link compression in multilink control */ +#define PPP_CCP 0x80fd /* Compression Control Protocol */ +#define PPP_CDPCP 0x8207 /* Cisco Discovery Protocol Control Protocol */ +#define PPP_NETCSCP 0x8209 /* Netcs Twin Routing */ +#define PPP_STPCP 0x820b /* STP - Control Protocol */ +#define PPP_EDPCP 0x820d /* Extreme Discovery Protocol Control Protocol */ +#define PPP_ACSPC 0x8235 /* Apple Client Server Protocol Control */ +#define PPP_MPLSCP 0x8281 /* MPLS Control Protocol */ +#define PPP_P12844CP 0x8285 /* IEEE p1284.4 standard - Protocol Control */ +#define PPP_ETSICP 0x8287 /* ETSI TETRA TNP1 Control Protocol */ +#define PPP_MFTPCP 0x8287 /* Multichannel Flow Treatment Protocol */ +#define PPP_LCP 0xc021 /* Link Control Protocol */ +#define PPP_PAP 0xc023 /* Password Authentication Protocol */ +#define PPP_LQR 0xc025 /* Link Quality Report protocol */ +#define PPP_SPAP 0xc027 /* Shiva Password Authentication Protocol */ +#define PPP_CBCP 0xc029 /* CallBack Control Protocol */ +#define PPP_BACP 0xc02b /* Bandwidth Allocation Control Protocol */ +#define PPP_BAP 0xc02d /* Bandwidth Allocation Protocol */ +#define PPP_CONTCP 0xc081 /* Container Control Protocol */ +#define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */ +#define PPP_RSAAP 0xc225 /* RSA Authentication Protocol */ +#define PPP_EAP 0xc227 /* Extensible Authentication Protocol */ +#define PPP_SIEP 0xc229 /* Mitsubishi Security Information Exchange Protocol*/ +#define PPP_SBAP 0xc26f /* Stampede Bridging Authorization Protocol */ +#define PPP_PRPAP 0x281 /* Proprietary Authentication Protocol */ +#define PPP_PRPAP2 0x283 /* Proprietary Authentication Protocol */ +#define PPP_PRPNIAP 0x481 /* Proprietary Node ID Authentication Protocol */ + +#endif /* ppptypes.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/prefs-int.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/prefs-int.h new file mode 100644 index 00000000..3f54c931 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/prefs-int.h @@ -0,0 +1,111 @@ +/* prefs-int.h + * Definitions for implementation of preference handling routines; + * used by "friends" of the preferences type. + * + * $Id: prefs-int.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PREFS_INT_H__ +#define __PREFS_INT_H__ + +struct pref_module { + const char *name; /* name of module */ + const char *title; /* title of module (displayed in preferences list) */ + const char *description;/* Description of module (displayed in preferences notebook) */ + void (*apply_cb)(void); /* routine to call when preferences applied */ + GList *prefs; /* list of its preferences */ + emem_tree_t *submodules;/* list of its submodules */ + int numprefs; /* number of non-obsolete preferences */ + gboolean prefs_changed; /* if TRUE, a preference has changed since we last checked */ + gboolean obsolete; /* if TRUE, this is a module that used to + exist but no longer does */ +}; + +/* + * Module used for protocol preferences. + * With MSVC and a libwireshark.dll, we need a special declaration. + */ +WS_VAR_IMPORT module_t *protocols_module; + +/* + * PREF_OBSOLETE is used for preferences that a module used to support + * but no longer supports; we give different error messages for them. + */ +typedef enum { + PREF_UINT, + PREF_BOOL, + PREF_ENUM, + PREF_STRING, + PREF_RANGE, + PREF_STATIC_TEXT, + PREF_UAT, + PREF_OBSOLETE +} pref_type_t; + +struct preference { + const char *name; /* name of preference */ + const char *title; /* title to use in GUI */ + const char *description; /* human-readable description of preference */ + int ordinal; /* ordinal number of this preference */ + pref_type_t type; /* type of that preference */ + union { + guint *uint; + gboolean *boolp; + gint *enump; + const char **string; + range_t **range; + void* uat; + } varp; /* pointer to variable storing the value */ + union { + guint uint; + gboolean boolval; + gint enumval; + char *string; + range_t *range; + } saved_val; /* original value, when editing from the GUI */ + union { + guint base; /* input/output base, for PREF_UINT */ + guint32 max_value; /* maximum value of a range */ + struct { + const enum_val_t *enumvals; /* list of name & values */ + gboolean radio_buttons; /* TRUE if it should be shown as + radio buttons rather than as an + option menu or combo box in + the preferences tab */ + } enum_info; /* for PREF_ENUM */ + } info; /* display/text file information */ + void *control; /* handle for GUI control for this preference */ +}; + +gint find_val_for_string(const char *needle, const enum_val_t *haystack, + gint default_value); + + +/* read_prefs_file: read in a generic config file and do a callback to */ +/* pref_set_pair_fct() for every key/value pair found */ +typedef prefs_set_pref_e (*pref_set_pair_cb) (gchar *key, gchar *value, void *private_data); + +int +read_prefs_file(const char *pf_path, FILE *pf, pref_set_pair_cb pref_set_pair_fct, void *private_data); + + + +#endif /* prefs-int.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/prefs.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/prefs.h new file mode 100644 index 00000000..3f2ab2c9 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/prefs.h @@ -0,0 +1,426 @@ +/* prefs.h + * Definitions for preference handling routines + * + * $Id: prefs.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PREFS_H__ +#define __PREFS_H__ + +#include + +#include "color.h" + +#include + +#define PR_DEST_CMD 0 +#define PR_DEST_FILE 1 + +#define DEF_WIDTH 750 +#define DEF_HEIGHT 550 + +#define MAX_VAL_LEN 1024 + +#define RTP_PLAYER_DEFAULT_VISIBLE 4 + +/* only GTK1 *or* GTK2 font_name should be used */ +/* (we need to keep both in the preferences file but will only use the one suitable for the programs GTK version used) */ +#if GTK_MAJOR_VERSION < 2 +#define PREFS_GUI_FONT_NAME gui_font_name1 +#else +#define PREFS_GUI_FONT_NAME gui_font_name2 +#endif + +/* + * Convert a string listing name resolution types to a bitmask of + * those types. + * + * Set "*name_resolve" to the bitmask, and return '\0', on success; + * return the bad character in the string on error. + */ +char string_to_name_resolve(char *string, guint32 *name_resolve); + +/* + * Modes for the starting directory in File Open dialogs. + */ +#define FO_STYLE_LAST_OPENED 0 /* start in last directory we looked at */ +#define FO_STYLE_SPECIFIED 1 /* start in specified directory */ + +/* + * Toolbar styles. + */ +#define TB_STYLE_ICONS 0 +#define TB_STYLE_TEXT 1 +#define TB_STYLE_BOTH 2 + +/* + * Types of layout of summary/details/hex panes. + */ +typedef enum { + layout_unused, /* entry currently unused */ + layout_type_5, + layout_type_2, + layout_type_1, + layout_type_4, + layout_type_3, + layout_type_6, + layout_type_max +} layout_type_e; + +/* + * Types of pane. + */ +typedef enum { + layout_pane_content_none, + layout_pane_content_plist, + layout_pane_content_pdetails, + layout_pane_content_pbytes +} layout_pane_content_e; + +/* + * open console behaviour (win32 only) + */ +typedef enum { + console_open_never, + console_open_auto, + console_open_always +} console_open_e; + + +typedef struct _e_prefs { + gint pr_format; + gint pr_dest; + gchar *pr_file; + gchar *pr_cmd; + GList *col_list; + gint num_cols; + color_t st_client_fg, st_client_bg, st_server_fg, st_server_bg; + gboolean gui_scrollbar_on_right; + gboolean gui_plist_sel_browse; + gboolean gui_ptree_sel_browse; + gboolean gui_altern_colors; + gboolean filter_toolbar_show_in_statusbar; + gint gui_ptree_line_style; + gint gui_ptree_expander_style; + gboolean gui_hex_dump_highlight_style; + gint gui_toolbar_main_style; + gchar *gui_font_name1; + gchar *gui_font_name2; + color_t gui_marked_fg; + color_t gui_marked_bg; + gchar *gui_colorized_fg; + gchar *gui_colorized_bg; + gboolean gui_geometry_save_position; + gboolean gui_geometry_save_size; + gboolean gui_geometry_save_maximized; + console_open_e gui_console_open; + guint gui_recent_files_count_max; + guint gui_fileopen_style; + gchar *gui_fileopen_dir; + guint gui_fileopen_preview; + gboolean gui_ask_unsaved; + gboolean gui_find_wrap; + gboolean gui_use_pref_save; + gchar *gui_webbrowser; + gchar *gui_window_title; + layout_type_e gui_layout_type; + layout_pane_content_e gui_layout_content_1; + layout_pane_content_e gui_layout_content_2; + layout_pane_content_e gui_layout_content_3; + gint console_log_level; + guint32 name_resolve; + gint name_resolve_concurrency; + gchar *capture_device; + gchar *capture_devices_descr; + gchar *capture_devices_hide; + gboolean capture_prom_mode; + gboolean capture_real_time; + gboolean capture_auto_scroll; + gboolean capture_show_info; + guint rtp_player_max_visible; +} e_prefs; + +WS_VAR_IMPORT e_prefs prefs; + +/* + * Routines to let modules that have preference settings register + * themselves by name, and to let them register preference settings + * by name. + */ +struct pref_module; + +typedef struct pref_module module_t; + +/** Sets up memory used by proto routines. Called at program startup */ +extern void prefs_init(void); + +/** Reset preferences to default values. Called at profile change */ +extern void prefs_reset(void); + +/** Frees memory used by proto routines. Called at program shutdown */ +extern void prefs_cleanup(void); + +/* + * Register a module that will have preferences. + * Specify the module under which to register it or NULL to register it + * at the top level, the name used for the module in the preferences file, + * the title used in the tab for it in a preferences dialog box, and a + * routine to call back when we apply the preferences. + * + * This should not be used for dissector preferences; + * "prefs_register_protocol()" should be used for that, so that the + * preferences go under the "Protocols" subtree, and so that the + * name is the protocol name specified at the "proto_register_protocol()" + * call so that the "Protocol Properties..." menu item works. + */ +extern module_t *prefs_register_module(module_t *parent, const char *name, + const char *title, const char *description, void (*apply_cb)(void)); + +/* + * Register a subtree that will have modules under it. + * Specify the module under which to register it or NULL to register it + * at the top level and the title used in the tab for it in a preferences + * dialog box. + */ +extern module_t *prefs_register_subtree(module_t *parent, const char *title, + const char *description); + +/* + * Register that a protocol has preferences. + */ +extern module_t *prefs_register_protocol(int id, void (*apply_cb)(void)); + +/* + * Register that a protocol has preferences and group it under a single + * subtree + */ +#define PREFERENCE_GROUPING +extern module_t *prefs_register_protocol_subtree(const char *subtree, int id, + void (*apply_cb)(void)); + +/* + * Register that a protocol used to have preferences but no longer does, + * by creating an "obsolete" module for it. + */ +extern module_t *prefs_register_protocol_obsolete(int id); + +/* + * Callback function for module list scanners. + */ +typedef guint (*module_cb)(module_t *module, gpointer user_data); + +/* + * Returns TRUE if module has any submodules + */ +extern gboolean prefs_module_has_submodules(module_t *module); + +/* + * Call a callback function, with a specified argument, for each module + * in the list of all modules. (This list does not include subtrees.) + * + * Ignores "obsolete" modules; their sole purpose is to allow old + * preferences for dissectors that no longer have preferences to be + * silently ignored in preference files. + */ +extern guint prefs_modules_foreach(module_cb callback, gpointer user_data); + +/* + * Call a callback function, with a specified argument, for each submodule + * of specified modules. If the module is NULL, goes through the top-level + * list in the display tree of modules. + * + * Ignores "obsolete" modules; their sole purpose is to allow old + * preferences for dissectors that no longer have preferences to be + * silently ignored in preference files. Does not ignore subtrees, + * as this can be used when walking the display tree of modules. + */ +extern guint prefs_modules_foreach_submodules(module_t *module, module_cb callback, gpointer user_data); + +/* + * Call the "apply" callback function for each module if any of its + * preferences have changed, and then clear the flag saying its + * preferences have changed, as the module has been notified of that + * fact. + */ +extern void prefs_apply_all(void); + +/* + * Call the "apply" callback function for a specific module if any of + * its preferences have changed, and then clear the flag saying its + * preferences have changed, as the module has been notified of that + * fact. + */ +extern void prefs_apply(module_t *module); + + +struct preference; + +typedef struct preference pref_t; + +/* + * Returns TRUE if the given protocol has registered preferences. + */ +extern gboolean prefs_is_registered_protocol(const char *name); + +/* + * Returns the module title of a registered protocol (or NULL if unknown). + */ +extern const char *prefs_get_title_by_name(const char *name); + +/** Given a module name, return a pointer to its pref_module struct, + * or NULL if it's not found. + * + * @param name The preference module name. Usually the same as the protocol + * name, e.g. "tcp". + * @return A pointer to the corresponding preference module, or NULL if it + * wasn't found. + */ +extern module_t *prefs_find_module(const char *name); + +/* + * Register a preference with an unsigned integral value. + */ +extern void prefs_register_uint_preference(module_t *module, const char *name, + const char *title, const char *description, guint base, guint *var); + +/* + * Register a preference with an Boolean value. + * Note that the name must be in lowercase letters only (underscore allowed). + */ +extern void prefs_register_bool_preference(module_t *module, const char *name, + const char *title, const char *description, gboolean *var); + +/* + * Register a preference with an enumerated value. + */ +typedef struct { + const char *name; + const char *description; + gint value; +} enum_val_t; + +extern void prefs_register_enum_preference(module_t *module, const char *name, + const char *title, const char *description, gint *var, + const enum_val_t *enumvals, gboolean radio_buttons); + +/* + * Register a preference with a character-string value. + */ +extern void prefs_register_string_preference(module_t *module, const char *name, + const char *title, const char *description, const char **var); + +/* + * Register a preference with a ranged value. + */ +extern void prefs_register_range_preference(module_t *module, const char *name, + const char *title, const char *description, range_t **var, + guint32 max_value); + +/* + * Register a static text 'preference'. It can be used to add some info/explanation. + */ +extern void prefs_register_static_text_preference(module_t *module, const char *name, + const char *title, const char *description); + +/* + * Register a uat 'preference'. It adds a button that opens the uat's window in the + * preferences tab of the module. + */ +extern void prefs_register_uat_preference(module_t *module, + const char *name, + const char* title, + const char *description, + void* uat); + +/* + * Register a preference that used to be supported but no longer is. + */ +extern void prefs_register_obsolete_preference(module_t *module, + const char *name); + +typedef guint (*pref_cb)(pref_t *pref, gpointer user_data); + +/* + * Call a callback function, with a specified argument, for each preference + * in a given module. + * + * If any of the callbacks return a non-zero value, stop and return that + * value, otherwise return 0. + */ +extern guint prefs_pref_foreach(module_t *module, pref_cb callback, + gpointer user_data); + +/* + * Register all non-dissector modules' preferences. + */ +extern void prefs_register_modules(void); + +/* Read the preferences file, fill in "prefs", and return a pointer to it. + + If we got an error (other than "it doesn't exist") trying to read + the global preferences file, stuff the errno into "*gpf_errno_return" + on an open error and into "*gpf_read_errno_return" on a read error, + stuff a pointer to the path of the file into "*gpf_path_return", and + return NULL. + + If we got an error (other than "it doesn't exist") trying to read + the user's preferences file, stuff the errno into "*pf_errno_return" + on an open error and into "*pf_read_errno_return" on a read error, + stuff a pointer to the path of the file into "*pf_path_return", and + return NULL. */ +extern e_prefs *read_prefs(int *, int *, char **, int *, int *, char **); + +/* Write out "prefs" to the user's preferences file, and return 0. + + If we got an error, stuff a pointer to the path of the preferences file + into "*pf_path_return", and return the errno. */ +extern int write_prefs(char **); + +/* Copy a set of preferences. */ +extern void copy_prefs(e_prefs *dest, e_prefs *src); + +/* Free a set of preferences. */ +extern void free_prefs(e_prefs *pr); + +/* + * Given a string of the form ":", as might appear + * as an argument to a "-o" option, parse it and set the preference in + * question. Return an indication of whether it succeeded or failed + * in some fashion. + * + * XXX - should supply, for syntax errors, a detailed explanation of + * the syntax error. + */ +typedef enum { + PREFS_SET_OK, /* succeeded */ + PREFS_SET_SYNTAX_ERR, /* syntax error in string */ + PREFS_SET_NO_SUCH_PREF, /* no such preference */ + PREFS_SET_OBSOLETE /* preference used to exist but no longer does */ +} prefs_set_pref_e; + +extern prefs_set_pref_e prefs_set_pref(char *prefarg); + +/* + * Returns TRUE if the given device is hidden + */ +extern gboolean prefs_is_capture_device_hidden(const char *name); + +#endif /* prefs.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/privileges.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/privileges.h new file mode 100644 index 00000000..8a0b0ecf --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/privileges.h @@ -0,0 +1,74 @@ +/* privileges.h + * Declarations of routines for handling privileges. + * + * $Id: privileges.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2006 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/** + * Called when the program starts, to save whatever credential information + * we'll need later. + */ +extern void get_credential_info(void); + +/** + * Was this program started with special privileges? get_credential_info() + * MUST be called before calling this. + * @return TRUE if the program was started with special privileges, + * FALSE otherwise. + */ +extern gboolean started_with_special_privs(void); + +/** + * Is this program running with special privileges? get_credential_info() + * MUST be called before calling this. + * @return TRUE if the program is running with special privileges, + * FALSE otherwise. + */ +extern gboolean running_with_special_privs(void); + +/** + * Permanently relinquish special privileges. get_credential_info() + * MUST be called before calling this. + */ +extern void relinquish_special_privs_perm(void); + +/** + * Get the current username. String must be g_free()d after use. + * @return A freshly g_alloc()ed string containing the username, + * or "UNKNOWN" on failure. + */ +extern gchar *get_cur_username(void); + +/** + * Get the current group. String must be g_free()d after use. + * @return A freshly g_alloc()ed string containing the group, + * or "UNKNOWN" on failure. + */ +extern gchar *get_cur_groupname(void); + +#ifdef _WIN32 +/** + * Check to see if npf.sys is running. + * @return TRUE if npf.sys is running, FALSE if it's not or if there was + * an error checking its status. + */ +extern gboolean npf_sys_is_running(); +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/proto.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/proto.h new file mode 100644 index 00000000..f20845fb --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/proto.h @@ -0,0 +1,1655 @@ +/* proto.h + * Definitions for protocol display + * + * $Id: proto.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +/*! @file proto.h + The protocol tree related functions.
+ A protocol tree will hold all necessary data to display the whole dissected packet. + Creating a protocol tree is done in a two stage process: + A static part at program startup, and a dynamic part when the dissection with the real packet data is done.
+ The "static" information is provided by creating a hf_register_info hf[] array, and register it using the + proto_register_field_array() function. This is usually done at dissector registering.
+ The "dynamic" information is added to the protocol tree by calling one of the proto_tree_add_...() functions, + e.g. proto_tree_add_bytes(). +*/ + +#ifndef __PROTO_H__ +#define __PROTO_H__ + +#ifdef HAVE_STDARG_H +# include +#else +# include +#endif + +#include + +#include "gnuc_format_check.h" +#include "ipv4.h" +#include "nstime.h" +#include "tvbuff.h" +#include "ftypes/ftypes.h" +#include "register.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** The header-field index for the special text pseudo-field. Exported by libwireshark.dll */ +WS_VAR_IMPORT int hf_text_only; + +/** the maximum length of a protocol field string representation */ +#define ITEM_LABEL_LENGTH 240 + +struct _value_string; + +/** Make a const value_string[] look like a _value_string pointer, used to set header_field_info.strings */ +#define VALS(x) (const struct _value_string*)(x) + +/** Make a const true_false_string[] look like a _true_false_string pointer, used to set header_field_info.strings */ +#define TFS(x) (const struct true_false_string*)(x) + +/** Make a const range_string[] look like a _range_string pointer, used to set + * header_field_info.strings */ +#define RVALS(x) (const struct _range_string*)(x) + +struct _protocol; + +/** Structure for information about a protocol */ +typedef struct _protocol protocol_t; + +/** check protocol activation + * @todo this macro looks like a hack */ +#define CHECK_DISPLAY_AS_X(x_handle,index, tvb, pinfo, tree) { \ + if (!proto_is_protocol_enabled(find_protocol_by_id(index))) { \ + call_dissector(x_handle,tvb, pinfo, tree); \ + return; \ + } \ + } + +/** Macro used for reporting errors in dissectors; it throws a + * DissectorError exception, with the string passed as an argument + * as the message for the exception, so that it can show up in + * the Info column and the protocol tree. + * + * If that string is dynamically allocated, it should be allocated with + * ep_alloc(); using ep_strdup_printf() would work. + * + * If the WIRESHARK_ABORT_ON_DISSECTOR_BUG environment variable is set, + * it will call abort(), instead, to make it easier to get a stack trace. + * + * @param message string to use as the message + */ +#define REPORT_DISSECTOR_BUG(message) \ + ((getenv("WIRESHARK_ABORT_ON_DISSECTOR_BUG") != NULL) ? \ + abort() : \ + THROW_MESSAGE(DissectorError, message)) + +/** Macro used for assertions in dissectors; it doesn't abort, it just + * throws a DissectorError exception, with the assertion failure + * message as a parameter, so that it can show up in the protocol tree. + * + * @param expression expression to test in the assertion + */ +#define DISSECTOR_ASSERT(expression) \ + ((void) ((expression) ? (void)0 : \ + __DISSECTOR_ASSERT (expression, __FILE__, __LINE__))) + +#if 0 +/* win32: using a debug breakpoint (int 3) can be very handy while debugging, + * as the assert handling of GTK/GLib is currently not very helpful */ +#define DISSECTOR_ASSERT(expression) \ +{ if(!(expression)) _asm { int 3}; } +#endif + +/** Same as DISSECTOR_ASSERT(), but will throw DissectorError exception + * unconditionally, much like GLIB's g_assert_not_reached works. + */ +#define DISSECTOR_ASSERT_NOT_REACHED() \ + (REPORT_DISSECTOR_BUG( \ + ep_strdup_printf("%s:%u: failed assertion \"DISSECTOR_ASSERT_NOT_REACHED\"", \ + __FILE__, __LINE__))) + +#define __DISSECTOR_ASSERT_STRINGIFY(s) # s + +#define __DISSECTOR_ASSERT(expression, file, lineno) \ + (REPORT_DISSECTOR_BUG( \ + ep_strdup_printf("%s:%u: failed assertion \"%s\"", \ + file, lineno, __DISSECTOR_ASSERT_STRINGIFY(expression)))) + +/* BASE_STRUCTURE_RESET constant is used in proto.c to reset the bits + * identifying special structures used in translation of value for display. + * Its value means that we may have at most 16 base_display_e values */ +#define BASE_STRUCTURE_RESET 0x0F +/* Following constants have to be ORed with a base_display_e when dissector + * want to use specials MACROs (for the moment, only RVALS) for a + * header_field_info */ +#define BASE_RANGE_STRING 0x10 +/** radix for decimal values, used in header_field_info.display */ +typedef enum { + BASE_NONE, /**< none */ + BASE_DEC, /**< decimal */ + BASE_HEX, /**< hexadecimal */ + BASE_OCT, /**< octal */ + BASE_DEC_HEX, /**< decimal (hexadecimal) */ + BASE_HEX_DEC /**< hexadecimal (decimal) */ +} base_display_e; + +#define IS_BASE_DUAL(b) ((b)==BASE_DEC_HEX||(b)==BASE_HEX_DEC) + +/** information describing a header field */ +typedef struct _header_field_info header_field_info; + +/** information describing a header field */ +struct _header_field_info { + /* ---------- set by dissector --------- */ + const char *name; /**< full name of this field */ + const char *abbrev; /**< abbreviated name of this field */ + enum ftenum type; /**< field type, one of FT_ (from ftypes.h) */ + int display; /**< one of BASE_, or number of field bits for FT_BOOLEAN */ + const void *strings; /**< value_string, range_string or true_false_string, + typically converted by VALS(), RVALS() or TFS(). + If this is an FT_PROTOCOL then it points to the + associated protocol_t structure */ + guint32 bitmask; /**< bitmask of interesting bits */ + const char *blurb; /**< Brief description of field */ + + /* ------- set by proto routines (prefilled by HFILL macro, see below) ------ */ + int id; /**< Field ID */ + int parent; /**< parent protocol tree */ + int ref_count; /**< is this field referenced by a filter and how often */ + int bitshift; /**< bits to shift */ + header_field_info *same_name_next; /**< Link to next hfinfo with same abbrev */ + header_field_info *same_name_prev; /**< Link to previous hfinfo with same abbrev */ +}; + +/** + * HFILL initializes all the "set by proto routines" fields in a + * _header_field_info. If new fields are added or removed, it should + * be changed as necessary. + */ +#define HFILL 0, 0, 0, 0, NULL, NULL + +/** Used when registering many fields at once, using proto_register_field_array() */ +typedef struct hf_register_info { + int *p_id; /**< written to by register() function */ + header_field_info hfinfo; /**< the field info to be registered */ +} hf_register_info; + + + + +/** string representation, if one of the proto_tree_add_..._format() functions used */ +typedef struct _item_label_t { + char representation[ITEM_LABEL_LENGTH]; +} item_label_t; + + +/** Contains the field information for the proto_item. */ +typedef struct field_info { + header_field_info *hfinfo; /**< pointer to registered field information */ + gint start; /**< current start of data in field_info.ds_tvb */ + gint length; /**< current data length of item in field_info.ds_tvb */ + gint appendix_start; /**< start of appendix data */ + gint appendix_length; /**< length of appendix data */ + gint tree_type; /**< one of ETT_ or -1 */ + item_label_t *rep; /**< string for GUI tree */ + guint32 flags; /**< bitfield like FI_GENERATED, ... */ + tvbuff_t *ds_tvb; /**< data source tvbuff */ + fvalue_t value; +} field_info; + + +/* + * Flag fields. Do not assign values greater than 0x00000080 unless you + * shuffle the expert information upward; see below. + */ + +/** The protocol field should not be shown in the tree (it's used for filtering only), + * used in field_info.flags. */ +/* HIDING PROTOCOL FIELDS IS DEPRECATED, IT'S CONSIDERED TO BE BAD GUI DESIGN! */ +#define FI_HIDDEN 0x00000001 +/** The protocol field should be displayed as "generated by Wireshark", + * used in field_info.flags. */ +#define FI_GENERATED 0x00000002 +/** The protocol field is actually a URL */ +#define FI_URL 0x00000004 + + +/** convenience macro to get field_info.flags */ +#define FI_GET_FLAG(fi, flag) (fi->flags & flag) +/** convenience macro to set field_info.flags */ +#define FI_SET_FLAG(fi, flag) (fi->flags = fi->flags | flag) + +/** One of these exists for the entire protocol tree. Each proto_node + * in the protocol tree points to the same copy. */ +typedef struct { + GHashTable *interesting_hfids; + gboolean visible; + gint count; +} tree_data_t; + +/** Each proto_tree, proto_item is one of these. */ +typedef struct _proto_node { + struct _proto_node *first_child; + struct _proto_node *last_child; + struct _proto_node *next; + struct _proto_node *parent; + field_info *finfo; + tree_data_t *tree_data; +} proto_node; + +/** A protocol tree element. */ +typedef proto_node proto_tree; +/** A protocol item element. */ +typedef proto_node proto_item; + +/* + * Expert information. + * This is in the flags field; we allocate this from the top down, + * so as not to collide with FI_ flags, which are allocated from + * the bottom up. + */ + +/* expert severities */ +#define PI_SEVERITY_MASK 0x00000E00 /* mask usually for internal use only! */ +/** Usual workflow, e.g. TCP connection establishing */ +#define PI_CHAT 0x00000200 +/** Notable messages, e.g. an application returned an "usual" error code like HTTP 404 */ +#define PI_NOTE 0x00000400 +/** Warning, e.g. application returned an "unusual" error code */ +#define PI_WARN 0x00000600 +/** Serious problems, e.g. [Malformed Packet] */ +#define PI_ERROR 0x00000800 + +/* expert "event groups" */ +#define PI_GROUP_MASK 0xFFFFF000 /* mask usually for internal use only! */ +/** The protocol field has a bad checksum, usually PI_WARN */ +#define PI_CHECKSUM 0x00001000 +/** The protocol field indicates a sequence problem (e.g. TCP window is zero) */ +#define PI_SEQUENCE 0x00002000 +/** The protocol field indicates a bad application response code (e.g. HTTP 404), usually PI_NOTE */ +#define PI_RESPONSE_CODE 0x00004000 +/** The protocol field indicates an application request (e.g. File Handle == xxxx), usually PI_CHAT */ +#define PI_REQUEST_CODE 0x00005000 +/** The data is undecoded, the protocol dissection is incomplete here, usually PI_WARN */ +#define PI_UNDECODED 0x00008000 +/** The protocol field indicates a reassemble (e.g. DCE/RPC defragmentation), usually PI_CHAT (or PI_ERROR) */ +#define PI_REASSEMBLE 0x00010000 +/** The packet data is malformed, the dissector has "given up", usually PI_ERROR */ +#define PI_MALFORMED 0x00020000 +/** A generic debugging message (shouldn't remain in production code!), usually PI_ERROR */ +#define PI_DEBUG 0x00040000 +/* The protocol field indicates a security probem (e.g. unsecure implementation) */ +/*#define PI_SECURITY 0x00080000*/ + +/* add more, see http://wiki.wireshark.org/Development/ExpertInfo */ + + +/** is this protocol field hidden from the protocol tree display (used for filtering only)? */ +/* HIDING PROTOCOL FIELDS IS DEPRECATED, IT'S CONSIDERED TO BE BAD GUI DESIGN! */ +#define PROTO_ITEM_IS_HIDDEN(proto_item) \ + ((proto_item) ? FI_GET_FLAG((proto_item)->finfo, FI_HIDDEN) : 0) +/** mark this protocol field to be hidden from the protocol tree display (used for filtering only) */ +/* HIDING PROTOCOL FIELDS IS DEPRECATED, IT'S CONSIDERED TO BE BAD GUI DESIGN! */ +#define PROTO_ITEM_SET_HIDDEN(proto_item) \ + ((proto_item) ? FI_SET_FLAG((proto_item)->finfo, FI_HIDDEN) : 0) +/** is this protocol field generated by Wireshark (and not read from the packet data)? */ +#define PROTO_ITEM_IS_GENERATED(proto_item) \ + ((proto_item) ? FI_GET_FLAG((proto_item)->finfo, FI_GENERATED) : 0) +/** mark this protocol field as generated by Wireshark (and not read from the packet data) */ +#define PROTO_ITEM_SET_GENERATED(proto_item) \ + ((proto_item) ? FI_SET_FLAG((proto_item)->finfo, FI_GENERATED) : 0) +/** is this protocol field actually a URL? */ +#define PROTO_ITEM_IS_URL(proto_item) \ + ((proto_item) ? FI_GET_FLAG((proto_item)->finfo, FI_URL) : 0) +/** mark this protocol field as a URL */ +#define PROTO_ITEM_SET_URL(proto_item) \ + ((proto_item) ? FI_SET_FLAG((proto_item)->finfo, FI_URL) : 0) + +typedef void (*proto_tree_foreach_func)(proto_node *, gpointer); +typedef gboolean (*proto_tree_traverse_func)(proto_node *, gpointer); + +extern gboolean proto_tree_traverse_in_order(proto_tree *tree, + proto_tree_traverse_func func, gpointer data); +extern void proto_tree_children_foreach(proto_tree *tree, + proto_tree_foreach_func func, gpointer data); + +/** Retrieve the field_info from a proto_item */ +#define PITEM_FINFO(proto_item) ((proto_item)->finfo) + +/** Retrieve the tree_data_t from a proto_tree */ +#define PTREE_DATA(proto_tree) ((proto_tree)->tree_data) + +/** Sets up memory used by proto routines. Called at program startup */ +extern void proto_init(void (register_all_protocols)(register_cb cb, gpointer client_data), + void (register_all_handoffs)(register_cb cb, gpointer client_data), + register_cb cb, void *client_data); + + +/** Frees memory used by proto routines. Called at program shutdown */ +extern void proto_cleanup(void); + +/** This function takes a tree and a protocol id as parameter and + will return TRUE/FALSE for whether the protocol or any of the filterable + fields in the protocol is referenced by any fitlers. + If this function returns FALSE then it is safe to skip any + proto_tree_add_...() calls and just treat the call as if the + dissector was called with tree==NULL. + If you reset the tree to NULL by this dissector returning FALSE, + you will still need to call any subdissector with the original value of + tree or filtering will break. + + The purpose of this is to optimize wireshark for speed and make it + faster for when filters are being used. +*/ +extern gboolean proto_field_is_referenced(proto_tree *tree, int proto_id); + + + +/** Create a subtree under an existing item. + @param ti the parent item of the new subtree + @param idx one of the ett_ array elements registered with proto_register_subtree_array() + @return the new subtree */ +extern proto_tree* proto_item_add_subtree(proto_item *ti, gint idx); + +/** Get an existing subtree under an item. + @param ti the parent item of the subtree + @return the subtree or NULL */ +extern proto_tree* proto_item_get_subtree(proto_item *ti); + +/** Get the parent of a subtree item. + @param ti the child item in the subtree + @return parent item or NULL */ +extern proto_item* proto_item_get_parent(proto_item *ti); + +/** Get Nth generation parent item. + @param ti the child item in the subtree + @param gen the generation to get (using 1 here is the same as using proto_item_get_parent()) + @return parent item */ +extern proto_item* proto_item_get_parent_nth(proto_item *ti, int gen); + +/** Replace text of item after it already has been created. + @param ti the item to set the text + @param format printf like format string + @param ... printf like parameters */ +extern void proto_item_set_text(proto_item *ti, const char *format, ...) + GNUC_FORMAT_CHECK(printf, 2,3); + +/** Append to text of item after it has already been created. + @param ti the item to append the text to + @param format printf like format string + @param ... printf like parameters */ +extern void proto_item_append_text(proto_item *ti, const char *format, ...) + GNUC_FORMAT_CHECK(printf, 2,3); + +/** Set proto_item's length inside tvb, after it has already been created. + @param ti the item to set the length + @param length the new length ot the item */ +extern void proto_item_set_len(proto_item *ti, gint length); + +/** + * Sets the length of the item based on its start and on the specified + * offset, which is the offset past the end of the item; as the start + * in the item is relative to the beginning of the data source tvbuff, + * we need to pass in a tvbuff. + @param ti the item to set the length + @param tvb end is relative to this tvbuff + @param end this end offset is relative to the beginning of tvb + @todo make usage clearer, I don't understand it! + */ +extern void proto_item_set_end(proto_item *ti, tvbuff_t *tvb, gint end); + +/** Get length of a proto_item. Useful after using proto_tree_add_item() + * to add a variable-length field (e.g., FT_NSTRING_UINT8). + @param ti the item to get the length from + @return the current length */ +extern int proto_item_get_len(proto_item *ti); + +/** + * Sets an expert info to the proto_item. + @param ti the item to set the expert info + @param group the group of this info (e.g. PI_CHECKSUM) + @param severity of this info (e.g. PI_ERROR) + @return TRUE if value was written + */ +extern gboolean proto_item_set_expert_flags(proto_item *ti, int group, guint severity); + + + + +/** Creates a new proto_tree root. + @return the new tree root */ +extern proto_tree* proto_tree_create_root(void); + +/** Clear memory for entry proto_tree. Clears proto_tree struct also. + @param tree the tree to free */ +extern void proto_tree_free(proto_tree *tree); + +/** Set the tree visible or invisible. + Is the parsing being done for a visible proto_tree or an invisible one? + By setting this correctly, the proto_tree creation is sped up by not + having to call g_vsnprintf and copy strings around. + @param tree the tree to be set + @param visible ... or not */ +extern void +proto_tree_set_visible(proto_tree *tree, gboolean visible); + +/** Mark a field/protocol ID as "interesting". + @param tree the tree to be set + @param hfid the interesting field id + @todo what *does* interesting mean? */ +extern void +proto_tree_prime_hfid(proto_tree *tree, int hfid); + +/** Get a parent item of a subtree. + @param tree the tree to get the parent from + @return parent item */ +extern proto_item* proto_tree_get_parent(proto_tree *tree); + +/** Get the root tree from any subtree. + @param tree the tree to get the root from + @return root tree */ +extern proto_tree* proto_tree_get_root(proto_tree *tree); + +/** Move an existing item behind another existing item. + @param tree the tree to which both items belong + @param fixed_item the item which keeps it's position + @param item_to_move the item which will be moved */ +extern void proto_tree_move_item(proto_tree *tree, proto_item *fixed_item, proto_item *item_to_move); + + +/** Set start and length of an appendix for a proto_tree. + @param tree the tree to set the appendix start and length + @param tvb the tv buffer of the current data + @param start the start offset of the appendix + @param length the length of the appendix */ +extern void proto_tree_set_appendix(proto_tree *tree, tvbuff_t *tvb, gint start, gint length); + + +/** Add an item to a proto_tree, using the text label registered to that item. + The item is extracted from the tvbuff handed to it. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param little_endian big or little endian byte representation + @return the newly created item */ +extern proto_item * +proto_tree_add_item(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, gboolean little_endian); + +/** Add a hidden item to a proto_tree. + @deprecated use proto_tree_add_item() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ +extern proto_item * +proto_tree_add_item_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, gboolean little_endian); + +/** Add a text-only node to a proto_tree. + @param tree the tree to append this item to + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_text(proto_tree *tree, tvbuff_t *tvb, gint start, gint length, const char *format, + ...) GNUC_FORMAT_CHECK(printf,5,6); + +/** Add a text-only node to a proto_tree using a variable argument list. + @param tree the tree to append this item to + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param format printf like format string + @param ap variable argument list + @return the newly created item */ +extern proto_item * +proto_tree_add_text_valist(proto_tree *tree, tvbuff_t *tvb, gint start, + gint length, const char *format, va_list ap); + + +/** Add a FT_NONE field to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_none_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const char *format, ...) GNUC_FORMAT_CHECK(printf,6,7); + +/** Add a FT_PROTOCOL to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_protocol_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const char *format, ...) GNUC_FORMAT_CHECK(printf,6,7); + + + + +/** Add a FT_BYTES to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param start_ptr pointer to the data to display + @return the newly created item */ +extern proto_item * +proto_tree_add_bytes(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const guint8* start_ptr); + +/** Add a hidden FT_BYTES to a proto_tree. + @deprecated use proto_tree_add_bytes() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ +extern proto_item * +proto_tree_add_bytes_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const guint8* start_ptr); + +/** Add a formatted FT_BYTES to a proto_tree, with the format generating + the string for the value and with the field name being included + automatically. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param start_ptr pointer to the data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_bytes_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, const guint8* start_ptr, const char *format, + ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a formatted FT_BYTES to a proto_tree, with the format generating + the entire string for the entry, including any field name. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param start_ptr pointer to the data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_bytes_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const guint8* start_ptr, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a FT_ABSOLUTE_TIME or FT_RELATIVE_TIME to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value_ptr pointer to the data to display + @return the newly created item */ +extern proto_item * +proto_tree_add_time(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, nstime_t* value_ptr); + +/** Add a hidden FT_ABSOLUTE_TIME or FT_RELATIVE_TIME to a proto_tree. + @deprecated use proto_tree_add_time() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ +extern proto_item * +proto_tree_add_time_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, nstime_t* value_ptr); + +/** Add a formatted FT_ABSOLUTE_TIME or FT_RELATIVE_TIME to a proto_tree, with + the format generating the string for the value and with the field name + being included automatically. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value_ptr pointer to the data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_time_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, nstime_t* value_ptr, const char *format, ...) + GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a formatted FT_ABSOLUTE_TIME or FT_RELATIVE_TIME to a proto_tree, with + the format generating the entire string for the entry, including any field + name. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value_ptr pointer to the data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_time_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, nstime_t* value_ptr, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a FT_IPXNET to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @return the newly created item */ +extern proto_item * +proto_tree_add_ipxnet(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, guint32 value); + +/** Add a hidden FT_IPXNET to a proto_tree. + @deprecated use proto_tree_add_ipxnet() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ +extern proto_item * +proto_tree_add_ipxnet_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, guint32 value); + +/** Add a formatted FT_IPXNET to a proto_tree, with the format generating + the string for the value and with the field name being included + automatically. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_ipxnet_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, guint32 value, const char *format, ...) + GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a formatted FT_IPXNET to a proto_tree, with the format generating + the entire string for the entry, including any field name. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_ipxnet_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, guint32 value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a FT_IPv4 to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @return the newly created item */ +extern proto_item * +proto_tree_add_ipv4(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, guint32 value); + +/** Add a hidden FT_IPv4 to a proto_tree. + @deprecated use proto_tree_add_ipv4() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ +extern proto_item * +proto_tree_add_ipv4_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, guint32 value); + +/** Add a formatted FT_IPv4 to a proto_tree, with the format generating + the string for the value and with the field name being included + automatically. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_ipv4_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, guint32 value, const char *format, ...) + GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a formatted FT_IPv4 to a proto_tree, with the format generating + the entire string for the entry, including any field name. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_ipv4_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, guint32 value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a FT_IPv6 to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value_ptr data to display + @return the newly created item */ +extern proto_item * +proto_tree_add_ipv6(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const guint8* value_ptr); + +/** Add a hidden FT_IPv6 to a proto_tree. + @deprecated use proto_tree_add_ipv6() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ +extern proto_item * +proto_tree_add_ipv6_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const guint8* value_ptr); + +/** Add a formatted FT_IPv6 to a proto_tree, with the format generating + the string for the value and with the field name being included + automatically. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value_ptr data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_ipv6_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, const guint8* value_ptr, const char *format, + ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a formatted FT_IPv6 to a proto_tree, with the format generating + the entire string for the entry, including any field name. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value_ptr data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_ipv6_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const guint8* value_ptr, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a FT_ETHER to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @return the newly created item */ +extern proto_item * +proto_tree_add_ether(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const guint8* value); + +/** Add a hidden FT_ETHER to a proto_tree. + @deprecated use proto_tree_add_ether() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ +extern proto_item * +proto_tree_add_ether_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const guint8* value); + +/** Add a formatted FT_ETHER to a proto_tree, with the format generating + the string for the value and with the field name being included + automatically. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_ether_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, const guint8* value, const char *format, ...) + GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a formatted FT_ETHER to a proto_tree, with the format generating + the entire string for the entry, including any field name. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_ether_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const guint8* value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a FT_GUID to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value_ptr data to display + @return the newly created item */ +extern proto_item * +proto_tree_add_guid(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const e_guid_t *value_ptr); + +/** Add a hidden FT_GUID to a proto_tree. + @deprecated use proto_tree_add_guid() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ +extern proto_item * +proto_tree_add_guid_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const e_guid_t *value_ptr); + +/** Add a formatted FT_GUID to a proto_tree, with the format generating + the string for the value and with the field name being included + automatically. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value_ptr data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_guid_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, const e_guid_t *value_ptr, const char *format, + ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a formatted FT_GUID to a proto_tree, with the format generating + the entire string for the entry, including any field name. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value_ptr data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_guid_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const e_guid_t *value_ptr, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a FT_OID to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value_ptr data to display + @return the newly created item */ +extern proto_item * +proto_tree_add_oid(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const guint8* value_ptr); + +/** Add a hidden FT_OID to a proto_tree. + @deprecated use proto_tree_add_oid() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ +extern proto_item * +proto_tree_add_oid_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const guint8* value_ptr); + +/** Add a formatted FT_OID to a proto_tree, with the format generating + the string for the value and with the field name being included + automatically. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value_ptr data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_oid_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, const guint8* value_ptr, const char *format, + ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a formatted FT_OID to a proto_tree, with the format generating + the entire string for the entry, including any field name. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value_ptr data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_oid_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const guint8* value_ptr, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a FT_STRING to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @return the newly created item */ +extern proto_item * +proto_tree_add_string(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const char* value); + +/** Add a hidden FT_STRING to a proto_tree. + @deprecated use proto_tree_add_string() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ +extern proto_item * +proto_tree_add_string_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const char* value); + +/** Add a formatted FT_STRING to a proto_tree, with the format generating + the string for the value and with the field name being included + automatically. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_string_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, const char* value, const char *format, ...) + GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a formatted FT_STRING to a proto_tree, with the format generating + the entire string for the entry, including any field name. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_string_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const char* value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a FT_BOOLEAN to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @return the newly created item */ +extern proto_item * +proto_tree_add_boolean(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, guint32 value); + +/** Add a hidden FT_BOOLEAN to a proto_tree. + @deprecated use proto_tree_add_boolean() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ +extern proto_item * +proto_tree_add_boolean_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, guint32 value); + +/** Add a formatted FT_BOOLEAN to a proto_tree, with the format generating + the string for the value and with the field name being included + automatically. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_boolean_format_value(proto_tree *tree, int hfindex, + tvbuff_t *tvb, gint start, gint length, guint32 value, + const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a formatted FT_BOOLEAN to a proto_tree, with the format generating + the entire string for the entry, including any field name. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_boolean_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, guint32 value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a FT_FLOAT to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @return the newly created item */ +extern proto_item * +proto_tree_add_float(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, float value); + +/** Add a hidden FT_FLOAT to a proto_tree. + @deprecated use proto_tree_add_float() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ +extern proto_item * +proto_tree_add_float_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, float value); + +/** Add a formatted FT_FLOAT to a proto_tree, with the format generating + the string for the value and with the field name being included + automatically. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_float_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, float value, const char *format, ...) + GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a formatted FT_FLOAT to a proto_tree, with the format generating + the entire string for the entry, including any field name. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_float_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, float value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a FT_DOUBLE to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @return the newly created item */ +extern proto_item * +proto_tree_add_double(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, double value); + +/** Add a hidden FT_DOUBLE to a proto_tree. + @deprecated use proto_tree_add_double() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ +extern proto_item * +proto_tree_add_double_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, double value); + +/** Add a formatted FT_DOUBLE to a proto_tree, with the format generating + the string for the value and with the field name being included + automatically. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_double_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, double value, const char *format, ...) + GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a formatted FT_DOUBLE to a proto_tree, with the format generating + the entire string for the entry, including any field name. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_double_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, double value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add one of FT_UINT8, FT_UINT16, FT_UINT24 or FT_UINT32 to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @return the newly created item */ +extern proto_item * +proto_tree_add_uint(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, guint32 value); + +/** Add a hidden FT_UINT8, FT_UINT16, FT_UINT24 or FT_UINT32 to a proto_tree. + @deprecated use proto_tree_add_uint() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ +extern proto_item * +proto_tree_add_uint_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, guint32 value); + +/** Add a formatted FT_UINT8, FT_UINT16, FT_UINT24 or FT_UINT32 to a proto_tree, + with the format generating the string for the value and with the field + name being included automatically. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_uint_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, guint32 value, const char *format, ...) + GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a formatted FT_UINT8, FT_UINT16, FT_UINT24 or FT_UINT32 to a proto_tree, + with the format generating the entire string for the entry, including any + field name. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_uint_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, guint32 value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add an FT_UINT64 to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @return the newly created item */ +extern proto_item * +proto_tree_add_uint64(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, guint64 value); + +/** Add a formatted FT_UINT64 to a proto_tree, with the format generating + the string for the value and with the field name being included + automatically. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_uint64_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, guint64 value, const char *format, ...) + GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a formatted FT_UINT64 to a proto_tree, with the format generating + the entire string for the entry, including any field name. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_uint64_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, guint64 value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add one of FT_INT8, FT_INT16, FT_INT24 or FT_INT32 to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @return the newly created item */ +extern proto_item * +proto_tree_add_int(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, gint32 value); + +/** Add a hidden FT_INT8, FT_INT16, FT_INT24 or FT_INT32 to a proto_tree. + @deprecated use proto_tree_add_int() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ +extern proto_item * +proto_tree_add_int_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, gint32 value); + +/** Add a formatted FT_INT8, FT_INT16, FT_INT24 or FT_INT32 to a proto_tree, + with the format generating the string for the value and with the field + name being included automatically. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_int_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, gint32 value, const char *format, ...) + GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a formatted FT_INT8, FT_INT16, FT_INT24 or FT_INT32 to a proto_tree, + with the format generating the entire string for the entry, including + any field name. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_int_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, gint32 value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Add an FT_INT64 to a proto_tree. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @return the newly created item */ +extern proto_item * +proto_tree_add_int64(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, gint64 value); + +/** Add a formatted FT_INT64 to a proto_tree, with the format generating + the string for the value and with the field name being included + automatically. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_int64_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, + gint start, gint length, gint64 value, const char *format, ...) + GNUC_FORMAT_CHECK(printf,7,8); + +/** Add a formatted FT_INT64 to a proto_tree, with the format generating + the entire string for the entry, including any field name. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param value data to display + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_int64_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, gint64 value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); + +/** Useful for quick debugging. Also sends string to STDOUT, so don't + leave call to this function in production code. + @param tree the tree to append the text to + @param format printf like format string + @param ... printf like parameters + @return the newly created item */ +extern proto_item * +proto_tree_add_debug_text(proto_tree *tree, const char *format, + ...) GNUC_FORMAT_CHECK(printf,2,3); + + + +/** Append a string to a protocol item.
+ NOTE: this function will break with the TRY_TO_FAKE_THIS_ITEM() + speed optimization. + Currently only WSP use this function so it is not that bad but try to + avoid using this one if possible. + IF you must use this function you MUST also disable the + TRY_TO_FAKE_THIS_ITEM() optimization for your dissector/function + using proto_item_append_string(). + Do that by faking that the tree is visible by calling + proto_tree_set_visible(tree, TRUE) (see packet-wsp.c) + BEFORE you create the item you are later going to use + proto_item_append_string() on. + @param pi the item to append the string to + @param str the string to append */ +extern void +proto_item_append_string(proto_item *pi, const char *str); + + + +/** Fill given label_str with string representation of field + @param fi the item to get the info from + @param label_str the string to fill + @todo think about changing the parameter profile */ +extern void +proto_item_fill_label(field_info *fi, gchar *label_str); + + +/** Register a new protocol. + @param name the full name of the new protocol + @param short_name abbreviated name of the new protocol + @param filter_name protocol name used for a display filter string + @return the new protocol handle */ +extern int +proto_register_protocol(const char *name, const char *short_name, const char *filter_name); + +/** Register a header_field array. + @param parent the protocol handle from proto_register_protocol() + @param hf the hf_register_info array + @param num_records the number of records in hf */ +extern void +proto_register_field_array(int parent, hf_register_info *hf, int num_records); + +/** Register a protocol subtree (ett) array. + @param indices array of ett indices + @param num_indices the number of records in indices */ +extern void +proto_register_subtree_array(gint *const *indices, int num_indices); + +/** Returns number of items (protocols or header fields) registered. + @return the number of items */ +extern int proto_registrar_n(void); + +/** Get name of registered header_field number n. + @param n item # n (0-indexed) + @return the name of this registered item */ +extern const char* proto_registrar_get_name(int n); + +/** Get abbreviation of registered header_field number n. + @param n item # n (0-indexed) + @return the abbreviation of this registered item */ +extern const char* proto_registrar_get_abbrev(int n); + +/** Get the header_field information based upon a field or protocol id. + @param hfindex item # n (0-indexed) + @return the registered item */ +extern header_field_info* proto_registrar_get_nth(guint hfindex); + +/** Get the header_field information based upon a field name. + @param field_name the field name to search for + @return the registered item */ +extern header_field_info* proto_registrar_get_byname(const char *field_name); + +/** Get enum ftenum FT_ of registered header_field number n. + @param n item # n (0-indexed) + @return the registered item */ +extern int proto_registrar_get_ftype(int n); + +/** Get parent protocol of registered header_field number n. + @param n item # n (0-indexed) + @return -1 if item _is_ a protocol */ +extern int proto_registrar_get_parent(int n); + +/** Is item # n a protocol? + @param n item # n (0-indexed) + @return TRUE if it's a protocol, FALSE if it's not */ +extern gboolean proto_registrar_is_protocol(int n); + +/** Get length of registered field according to field type. + @param n item # n (0-indexed) + @return 0 means undeterminable at registration time, -1 means unknown field */ +extern gint proto_registrar_get_length(int n); + + +/** Routines to use to iterate over the protocols and their fields; + * they return the item number of the protocol in question or the + * appropriate hfinfo pointer, and keep state in "*cookie". */ +extern int proto_get_first_protocol(void **cookie); +extern int proto_get_next_protocol(void **cookie); +extern header_field_info *proto_get_first_protocol_field(int proto_id, void **cookle); +extern header_field_info *proto_get_next_protocol_field(void **cookle); + +/** Given a protocol's filter_name. + @param filter_name the filter name to search for + @return proto_id */ +extern int proto_get_id_by_filter_name(const gchar* filter_name); + +/** Can item # n decoding be disabled? + @param proto_id protocol id (0-indexed) + @return TRUE if it's a protocol, FALSE if it's not */ +extern gboolean proto_can_toggle_protocol(int proto_id); + +/** Get the "protocol_t" structure for the given protocol's item number. + @param proto_id protocol id (0-indexed) */ +extern protocol_t *find_protocol_by_id(int proto_id); + +/** Get the protocol's name for the given protocol's item number. + @param proto_id protocol id (0-indexed) + @return its name */ +extern const char *proto_get_protocol_name(int proto_id); + +/** Get the protocol's item number, for the given protocol's "protocol_t". + @return its proto_id */ +extern int proto_get_id(protocol_t *protocol); + +/** Get the protocol's short name, for the given protocol's "protocol_t". + @return its short name. */ +extern const char *proto_get_protocol_short_name(protocol_t *protocol); + +/** Is protocol's decoding enabled ? + @param protocol + @return TRUE if decoding is enabled, FALSE if not */ +extern gboolean proto_is_protocol_enabled(protocol_t *protocol); + +/** Get a protocol's filter name by it's item number. + @param proto_id protocol id (0-indexed) + @return its filter name. */ +extern const char *proto_get_protocol_filter_name(int proto_id); + +/** Enable / Disable protocol of the given item number. + @param proto_id protocol id (0-indexed) + @param enabled enable / disable the protocol */ +extern void proto_set_decoding(int proto_id, gboolean enabled); + +/** Enable all protocols */ +extern void proto_enable_all(void); + +/** Disable disabling/enabling of protocol of the given item number. + @param proto_id protocol id (0-indexed) */ +extern void proto_set_cant_toggle(int proto_id); + +/** Checks for existence any protocol or field within a tree. + @param tree "Protocols" are assumed to be a child of the [empty] root node. + @param id hfindex of protocol or field + @return TRUE = found, FALSE = not found + @todo add explanation of id parameter */ +extern gboolean proto_check_for_protocol_or_field(proto_tree* tree, int id); + +/** Return GPtrArray* of field_info pointers for all hfindex that appear in + tree. Only works with primed trees, and is fast. + @param tree tree of interest + @param hfindex primed hfindex + @return GPtrArry pointer */ +extern GPtrArray* proto_get_finfo_ptr_array(proto_tree *tree, int hfindex); + +/** Return GPtrArray* of field_info pointers for all hfindex that appear in + tree. Works with any tree, primed or unprimed, and is slower than + proto_get_finfo_ptr_array because it has to search through the tree. + @param tree tree of interest + @param hfidex index of field info of interest + @return GPtrArry pointer */ +extern GPtrArray* proto_find_finfo(proto_tree *tree, int hfindex); + +/** Return GPtrArray* of field_info pointers containg all hfindexes that appear + in tree. + @param tree tree of interest + @return GPtrArry pointer */ +extern GPtrArray* proto_all_finfos(proto_tree *tree); + +/** Dumps a glossary of the protocol registrations to STDOUT */ +extern void proto_registrar_dump_protocols(void); + +/** Dumps a glossary of the field value strings or true/false strings to STDOUT */ +extern void proto_registrar_dump_values(void); + +/** Dumps a glossary of the protocol and field registrations to STDOUT. + * Format 1 is the original format. Format 2 includes the base (for integers) + * and the blurb. */ +extern void proto_registrar_dump_fields(int format); + + + +/** Points to the first element of an array of Booleans, indexed by + a subtree item type. That array element is TRUE if subtrees of + an item of that type are to be expanded. With MSVC and a + libwireshark.dll, we need a special declaration. */ +WS_VAR_IMPORT gboolean *tree_is_expanded; + +/** Number of elements in the tree_is_expanded array. With MSVC and a + * libwireshark.dll, we need a special declaration. */ +WS_VAR_IMPORT int num_tree_types; + +/** glib doesn't have g_ptr_array_len of all things!*/ +#ifndef g_ptr_array_len +#define g_ptr_array_len(a) ((a)->len) +#endif + +/** Get number of bits of a header_field. + @param hfinfo header_field + @return the bitwidth */ +extern int +hfinfo_bitwidth(header_field_info *hfinfo); + + + + +#include "epan.h" + +/** Can we do a "match selected" on this field. + @param finfo field_info + @param edt epan dissecting + @return TRUE if we can do a "match selected" on the field, FALSE otherwise. */ +extern gboolean +proto_can_match_selected(field_info *finfo, epan_dissect_t *edt); + +/** Construct a "match selected" display filter string. + @param finfo field_info + @param edt epan dissecting + @return the display filter string */ +extern char* +proto_construct_match_selected_string(field_info *finfo, epan_dissect_t *edt); + +/** Find field from offset in tvb. + @param tree tree of interest + @param offset offset in the tvb + @param tvb the tv buffer + @return the corresponding field_info */ +extern field_info* +proto_find_field_from_offset(proto_tree *tree, guint offset, tvbuff_t *tvb); + +/** This function will dissect a sequence of bytes that describe a bitmask. + @param tree the tree to append this item to + @param tvb the tv buffer of the current data + @param offset start of data in tvb + @param hf_hdr an 8/16/24/32 bit integer that describes the bitmask to be dissected. + This field will form an expansion under which the individual fields of the + bitmask is dissected and displayed. + This field must be of the type FT_[U]INT{8|16|24|32}. + @param fields an array of pointers to int that lists all the fields of the + bitmask. These fields can be either of the type FT_BOOLEAN for flags + or another integer of the same type/size as hf_hdr with a mask specified. + This array is terminated by a NULL entry. + FT_BOOLEAN bits that are set to 1 will have the name added to the expansion. + FT_integer fields that have a value_string attached will have the + matched string displayed on the expansion line. + @param little_endian big or little endian byte representation + @return the newly created item */ +extern proto_item * +proto_tree_add_bitmask(proto_tree *tree, tvbuff_t *tvb, int offset, int hf_hdr, gint ett, const int **fields, gboolean little_endian); + +/** Add bits to a proto_tree, using the text label registered to that item. + The item is extracted from the tvbuff handed to it. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param bit_offset start of data in tvb expressed in bits + @param no_of_bits length of data in tvb expressed in bits + @param little_endian big or little endian byte representation + @return the newly created item */ +extern proto_item * +proto_tree_add_bits_item(proto_tree *tree, int hf_index, tvbuff_t *tvb, gint bit_offset, gint no_of_bits, gboolean little_endian); + +/** Add bits to a proto_tree, using the text label registered to that item. + The item is extracted from the tvbuff handed to it. + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param bit_offset start of data in tvb expressed in bits + @param no_of_bits length of data in tvb expressed in bits + @param return_value if a pointer is passed here the value is returned. + @param little_endian big or little endian byte representation + @return the newly created item */ +extern proto_item * +proto_tree_add_bits_ret_val(proto_tree *tree, int hf_index, tvbuff_t *tvb, gint bit_offset, gint no_of_bits, guint64 *return_value, gboolean little_endian); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* proto.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ptvcursor.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ptvcursor.h new file mode 100644 index 00000000..d94940bf --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ptvcursor.h @@ -0,0 +1,110 @@ +/* ptvcursor.h + * + * Proto Tree TVBuff cursor + * Gilbert Ramirez + * + * $Id: ptvcursor.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2000 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PTVCURSOR_H__ +#define __PTVCURSOR_H__ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#define SUBTREE_UNDEFINED_LENGTH -1 + +typedef struct ptvcursor ptvcursor_t; + +/* Allocates an initializes a ptvcursor_t with 3 variables: + * proto_tree, tvbuff, and offset. */ +ptvcursor_t* +ptvcursor_new(proto_tree*, tvbuff_t*, gint); + +/* Gets data from tvbuff, adds it to proto_tree, increments offset, + * and returns proto_item* */ +proto_item* +ptvcursor_add(ptvcursor_t*, int hf, gint length, gboolean endianness); + + +/* Gets data from tvbuff, adds it to proto_tree, *DOES NOT* increment + * offset, and returns proto_item* */ +proto_item* +ptvcursor_add_no_advance(ptvcursor_t*, int hf, gint length, gboolean endianness); + +/* Advance the ptvcursor's offset within its tvbuff without + * adding anything to the proto_tree. */ +void +ptvcursor_advance(ptvcursor_t* ptvc, gint length); + +/* Frees memory for ptvcursor_t, but nothing deeper than that. */ +void +ptvcursor_free(ptvcursor_t*); + +/* Returns tvbuff. */ +tvbuff_t* +ptvcursor_tvbuff(ptvcursor_t*); + +/* Returns current offset. */ +gint +ptvcursor_current_offset(ptvcursor_t*); + +/* Returns the proto_tree* */ +proto_tree* +ptvcursor_tree(ptvcursor_t* ptvc); + +/* Sets a new proto_tree* for the ptvcursor_t */ +void +ptvcursor_set_tree(ptvcursor_t* ptvc, proto_tree *tree); + +/* push a subtree in the tree stack of the cursor */ +proto_tree* +ptvcursor_push_subtree(ptvcursor_t *ptvc, proto_item *it, gint ett_subtree); + +/* pop a subtree in the tree stack of the cursor */ +void ptvcursor_pop_subtree(ptvcursor_t *ptvc); + +/* Add an item to the tree and create a subtree + * If the length is unknown, length may be defined as SUBTREE_UNDEFINED_LENGTH. + * In this case, when the subtree will be closed, the parent item length will + * be equal to the advancement of the cursor since the creation of the subtree. + */ +proto_tree* ptvcursor_add_with_subtree(ptvcursor_t * ptvc, int hfindex, gint length, +gboolean little_endian, gint ett_subtree); + +/* Add a text node to the tree and create a subtree + * If the length is unknown, length may be defined as SUBTREE_UNDEFINED_LENGTH. + * In this case, when the subtree will be closed, the item length will be equal + * to the advancement of the cursor since the creation of the subtree. + */ +proto_tree * ptvcursor_add_text_with_subtree(ptvcursor_t * ptvc, gint length, + gint ett_subtree, const char *format, ...); + +/* Creates a subtree and adds it to the cursor as the working tree but does not + * save the old working tree */ +proto_tree* +ptvcursor_set_subtree(ptvcursor_t *ptvc, proto_item *it, gint ett_subtree); + +#endif /* __PTVCURSOR_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/radius_dict_lex.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/radius_dict_lex.h new file mode 100644 index 00000000..1ddab2be --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/radius_dict_lex.h @@ -0,0 +1,6 @@ +/* This is generated by runlex.sh. Do not edit it. */ +#define yylex Radiuslex +#ifndef YY_DECL +#define YY_DECL int yylex(void) +#endif +YY_DECL; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/range.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/range.h new file mode 100644 index 00000000..daf339c5 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/range.h @@ -0,0 +1,73 @@ +/* range.h + * Range routines + * + * $Id: range.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Dick Gooris + * Ulf Lamping + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __RANGE_H__ +#define __RANGE_H__ + +#include + +/* XXX where's the best place for these? */ +#define MAX_SCTP_PORT 65535 +#define MAX_TCP_PORT 65535 +#define MAX_UDP_PORT 65535 + +typedef struct range_admin_tag { + guint32 low; + guint32 high; +} range_admin_t; + +typedef struct range { + /* user specified range(s) */ + guint nranges; /* number of entries in ranges */ + range_admin_t ranges[1]; /* variable-length array */ +} range_t; + +/* + * Return value from range_convert_str(). + */ +typedef enum { + CVT_NO_ERROR, + CVT_SYNTAX_ERROR, + CVT_NUMBER_TOO_BIG +} convert_ret_t; + +extern range_t *range_empty(void); + +extern convert_ret_t range_convert_str(range_t **range, const gchar *es, + guint32 max_value); + +extern gboolean value_is_in_range(range_t *range, guint32 val); + +extern gboolean ranges_are_equal(range_t *a, range_t *b); + +extern void range_foreach(range_t *range, void (*callback)(guint32 val)); + +extern char *range_convert_range(range_t *range); + +extern range_t *range_copy(range_t *src); + +#endif /* __RANGE_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/reassemble.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/reassemble.h new file mode 100644 index 00000000..c8581727 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/reassemble.h @@ -0,0 +1,316 @@ +/* reassemble.h + * Declarations of outines for {fragment,segment} reassembly + * + * $Id: reassemble.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* make sure that all flags that are set in a fragment entry is also set for + * the flags field of fd_head !!! + */ + +/* only in fd_head: packet is defragmented */ +#define FD_DEFRAGMENTED 0x0001 + +/* there are overlapping fragments */ +#define FD_OVERLAP 0x0002 + +/* overlapping fragments contain different data */ +#define FD_OVERLAPCONFLICT 0x0004 + +/* more than one fragment which indicates end-of data */ +#define FD_MULTIPLETAILS 0x0008 + +/* fragment contains data past the end of the datagram */ +#define FD_TOOLONGFRAGMENT 0x0010 + +/* fragment data not alloced, fd->data pointing to fd_head->data+fd->offset */ +#define FD_NOT_MALLOCED 0x0020 + +/* this flag is used to request fragment_add to continue the reassembly process */ +#define FD_PARTIAL_REASSEMBLY 0x0040 + +/* fragment offset is indicated by sequence number and not byte offset + into the defragmented packet */ +#define FD_BLOCKSEQUENCE 0x0100 + +/* if REASSEMBLE_FLAGS_CHECK_DATA_PRESENT is set, and the first fragment is + * incomplete, this flag is set in the flags word on the fd_head returned. + * + * It's all a fudge to preserve historical behaviour. + */ +#define FD_DATA_NOT_PRESENT 0x0200 + +/* This flag is set in the to denote that datalen has ben set to a valid value. + * It's implied by FD_DEFRAGMENTED (we must know the total length of the + * datagram if we have defragmented it...) + */ +#define FD_DATALEN_SET 0x0400 + +typedef struct _fragment_data { + struct _fragment_data *next; + guint32 frame; + guint32 offset; + guint32 len; + guint32 datalen; /* Only valid in first item of list and when + * flags&FD_DATALEN_SET is set; + * number of bytes or (if flags&FD_BLOCKSEQUENCE set) + * segments in the datagram */ + guint32 reassembled_in; /* frame where this PDU was reassembled, + only valid in the first item of the list + and when FD_DEFRAGMENTED is set*/ + guint32 flags; + unsigned char *data; +} fragment_data; + + +/* + * Flags for fragment_add_seq_* + */ + +/* we don't have any sequence numbers - fragments are assumed to appear in + * order */ +#define REASSEMBLE_FLAGS_NO_FRAG_NUMBER 0x0001 + +/* a special fudge for the 802.11 dissector */ +#define REASSEMBLE_FLAGS_802_11_HACK 0x0002 + +/* causes fragment_add_seq_key to check that all the fragment data is present + * in the tvb, and if not, do something a bit odd. */ +#define REASSEMBLE_FLAGS_CHECK_DATA_PRESENT 0x0004 + +/* a function for copying hash keys */ +typedef void *(*fragment_key_copier)(const void *key); + + +/* + * Initialize a fragment table. + */ +extern void fragment_table_init(GHashTable **fragment_table); +extern void dcerpc_fragment_table_init(GHashTable **fragment_table); + +/* + * Initialize a reassembled-packet table. + */ +extern void reassembled_table_init(GHashTable **reassembled_table); + +/* + * Free up all space allocated for fragment keys and data. + */ +void reassemble_init(void); + +/* + * This function adds a new fragment to the fragment hash table. + * If this is the first fragment seen for this datagram, a new entry + * is created in the hash table, otherwise this fragment is just added + * to the linked list of fragments for this packet. + * The list of fragments for a specific datagram is kept sorted for + * easier handling. + * + * Returns a pointer to the head of the fragment data list if we have all the + * fragments, NULL otherwise. + */ +extern fragment_data *fragment_add(tvbuff_t *tvb, int offset, packet_info *pinfo, + guint32 id, GHashTable *fragment_table, guint32 frag_offset, + guint32 frag_data_len, gboolean more_frags); +extern fragment_data *fragment_add_multiple_ok(tvbuff_t *tvb, int offset, + packet_info *pinfo, guint32 id, GHashTable *fragment_table, + guint32 frag_offset, guint32 frag_data_len, gboolean more_frags); + +/* + * This routine extends fragment_add to use a "reassembled_table". + * + * If, after processing this fragment, we have all the fragments, they + * remove that from the fragment hash table if necessary and add it + * to the table of reassembled fragments, and return a pointer to the + * head of the fragment list. + */ +extern fragment_data *fragment_add_check(tvbuff_t *tvb, int offset, + packet_info *pinfo, guint32 id, GHashTable *fragment_table, + GHashTable *reassembled_table, guint32 frag_offset, + guint32 frag_data_len, gboolean more_frags); + +/* same as fragment_add() but this one assumes frag_number is a block + sequence number. note that frag_number is 0 for the first fragment. */ + +/* + * These functions add a new fragment to the fragment hash table, + * assuming that frag_number is a block sequence number (starting from zero for + * the first fragment of each datagram). + * + * If this is the first fragment seen for this datagram, a new + * "fragment_data" structure is allocated to refer to the reassembled + * packet, and: + * + * if "more_frags" is false, and either we have no sequence numbers, or + * are using the 802.11 hack, it is assumed that this is the only fragment + * in the datagram. The structure is not added to the hash + * table, and not given any fragments to refer to, but is just returned. + * + * In this latter case reassembly wasn't done (since there was only one + * fragment in the packet); dissectors can check the 'next' pointer on the + * returned list to see if this case was hit or not. + * + * Otherwise, this fragment is just added to the linked list of fragments + * for this packet; the fragment_data is also added to the fragment hash if + * necessary. + * + * If this packet completes assembly, these functions return the head of the + * fragment data; otherwise, they return null. + */ + +/* "key" should be an arbitrary key used for indexing the fragment hash; + * "key_copier" is called to copy the key to a more appropriate store before + * inserting a new entry to the hash. + */ +extern fragment_data * +fragment_add_seq_key(tvbuff_t *tvb, int offset, packet_info *pinfo, + void *key, fragment_key_copier key_copier, + GHashTable *fragment_table, guint32 frag_number, + guint32 frag_data_len, gboolean more_frags, + guint32 flags); + +/* a wrapper for fragment_add_seq_key - uses a key of source, dest and frame number */ +extern fragment_data *fragment_add_seq(tvbuff_t *tvb, int offset, packet_info *pinfo, + guint32 id, GHashTable *fragment_table, guint32 frag_number, + guint32 frag_data_len, gboolean more_frags); + +/* another wrapper for fragment_add_seq_key - uses a key of source, dest, frame + * number and act_id */ +extern fragment_data * +fragment_add_dcerpc_dg(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id, + void *act_id, + GHashTable *fragment_table, guint32 frag_number, + guint32 frag_data_len, gboolean more_frags); + +/* + * These routines extend fragment_add_seq_key to use a "reassembled_table". + * + * If, after processing this fragment, we have all the fragments, they + * remove that from the fragment hash table if necessary and add it + * to the table of reassembled fragments, and return a pointer to the + * head of the fragment list. + */ +extern fragment_data * +fragment_add_seq_check(tvbuff_t *tvb, int offset, packet_info *pinfo, + guint32 id, GHashTable *fragment_table, + GHashTable *reassembled_table, guint32 frag_number, + guint32 frag_data_len, gboolean more_frags); + +extern fragment_data * +fragment_add_seq_802_11(tvbuff_t *tvb, int offset, packet_info *pinfo, + guint32 id, GHashTable *fragment_table, + GHashTable *reassembled_table, guint32 frag_number, + guint32 frag_data_len, gboolean more_frags); + +extern fragment_data * +fragment_add_seq_next(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id, + GHashTable *fragment_table, GHashTable *reassembled_table, + guint32 frag_data_len, gboolean more_frags); + +extern void +fragment_start_seq_check(packet_info *pinfo, guint32 id, GHashTable *fragment_table, + guint32 tot_len); + +extern fragment_data * +fragment_end_seq_next(packet_info *pinfo, guint32 id, GHashTable *fragment_table, + GHashTable *reassembled_table); +/* to specify how much to reassemble, for fragmentation where last fragment can not be + * identified by flags or such. + * note that for FD_BLOCKSEQUENCE tot_len is the index for the tail fragment. + * i.e. since the block numbers start at 0, if we specify tot_len==2, that + * actually means we want to defragment 3 blocks, block 0, 1 and 2. + * + */ +extern void +fragment_set_tot_len(packet_info *pinfo, guint32 id, GHashTable *fragment_table, + guint32 tot_len); + +/* to resad whatever totlen previously set */ +extern guint32 +fragment_get_tot_len(packet_info *pinfo, guint32 id, GHashTable *fragment_table); + +/* + * This function will set the partial reassembly flag(FD_PARTIAL_REASSEMBLY) for a fh. + * When this function is called, the fh MUST already exist, i.e. + * the fh MUST be created by the initial call to fragment_add() before + * this function is called. Also note that this function MUST be called to indicate + * a fh will be extended (increase the already stored data). After calling this function, + * and if FD_DEFRAGMENTED is set, the reassembly process will be continued. + */ +extern void +fragment_set_partial_reassembly(packet_info *pinfo, guint32 id, GHashTable *fragment_table); + +/* This function is used to check if there is partial or completed reassembly state + * matching this packet. I.e. Are there reassembly going on or not for this packet? + */ +extern fragment_data * +fragment_get(packet_info *pinfo, guint32 id, GHashTable *fragment_table); + +/* The same for the reassemble table */ +/* id *must* be the frame number for this to work! */ +extern fragment_data * +fragment_get_reassembled(packet_info *pinfo, guint32 id, GHashTable *reassembled_table); + +extern fragment_data * +fragment_get_reassembled_id(packet_info *pinfo, guint32 id, GHashTable *reassembled_table); + +/* This will free up all resources and delete reassembly state for this PDU. + * Except if the PDU is completely reassembled, then it would NOT deallocate the + * buffer holding the reassembled data but instead return the pointer to that + * buffer. + * + * So, if you call fragment_delete and it returns non-NULL, YOU are responsible to + * g_free() that buffer. + */ +extern unsigned char * +fragment_delete(packet_info *pinfo, guint32 id, GHashTable *fragment_table); + +/* hf_fragment, hf_fragment_error, and hf_reassembled_in should be + FT_FRAMENUM, the others should be FT_BOOLEAN +*/ +typedef struct _fragment_items { + gint *ett_fragment; + gint *ett_fragments; + + int *hf_fragments; + int *hf_fragment; + int *hf_fragment_overlap; + int *hf_fragment_overlap_conflict; + int *hf_fragment_multiple_tails; + int *hf_fragment_too_long_fragment; + int *hf_fragment_error; + int *hf_reassembled_in; + + const char *tag; +} fragment_items; + +extern tvbuff_t * +process_reassembled_data(tvbuff_t *tvb, int offset, packet_info *pinfo, + const char *name, fragment_data *fd_head, const fragment_items *fit, + gboolean *update_col_infop, proto_tree *tree); + +extern gboolean +show_fragment_tree(fragment_data *ipfd_head, const fragment_items *fit, + proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, proto_item **fi); + +extern gboolean +show_fragment_seq_tree(fragment_data *ipfd_head, const fragment_items *fit, + proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, proto_item **fi); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/reedsolomon.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/reedsolomon.h new file mode 100644 index 00000000..433f6e1e --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/reedsolomon.h @@ -0,0 +1,86 @@ +#ifdef __cplusplus +extern "C" { +#endif + +/* Global definitions for Reed-Solomon encoder/decoder + * Phil Karn KA9Q, September 1996 + */ +/* Set one of these to enable encoder/decoder debugging and error checking, + * at the expense of speed */ +/* #undef DEBUG 1*/ +/* #undef DEBUG 2*/ +#undef DEBUG + +/* To select the CCSDS standard (255,223) code, define CCSDS. This + * implies standard values for MM, KK, B0 and PRIM. + */ +/* #undef CCSDS 1*/ +#undef CCSDS +#ifndef CCSDS + +/* Otherwise, leave CCSDS undefined and set the parameters below: + * + * Set MM to be the size of each code symbol in bits. The Reed-Solomon + * block size will then be NN = 2**M - 1 symbols. Supported values are + * defined in rs.c. + */ +#define MM 8 /* Symbol size in bits */ + +/* + * Set KK to be the number of data symbols in each block, which must be + * less than the block size. The code will then be able to correct up + * to NN-KK erasures or (NN-KK)/2 errors, or combinations thereof with + * each error counting as two erasures. + */ +#define KK 207 /* Number of data symbols per block */ + +/* Set B0 to the first root of the generator polynomial, in alpha form, and + * set PRIM to the power of alpha used to generate the roots of the + * generator polynomial. The generator polynomial will then be + * @**PRIM*B0, @**PRIM*(B0+1), @**PRIM*(B0+2)...@**PRIM*(B0+NN-KK) + * where "@" represents a lower case alpha. + */ +#define B0 1 /* First root of generator polynomial, alpha form */ +#define PRIM 1 /* power of alpha used to generate roots of generator poly */ +#define STANDARD_ORDER + +/* If you want to select your own field generator polynomial, you'll have + * to edit that in rs.c. + */ + +#else /* CCSDS */ +/* Don't change these, they're CCSDS standard */ +#define MM 8 +#define KK 223 +#define B0 112 +#define PRIM 11 +#endif + +#define NN ((1 << MM) - 1) + +#if MM <= 8 +typedef unsigned char dtype; +#else +typedef unsigned int dtype; +#endif + +/* Reed-Solomon encoding + * data[] is the input block, parity symbols are placed in bb[] + * bb[] may lie past the end of the data, e.g., for (255,223): + * encode_rs(&data[0],&data[223]); + */ +int encode_rs(dtype data[], dtype bb[]); + +/* Reed-Solomon erasures-and-errors decoding + * The received block goes into data[], and a list of zero-origin + * erasure positions, if any, goes in eras_pos[] with a count in no_eras. + * + * The decoder corrects the symbols in place, if possible and returns + * the number of corrected symbols. If the codeword is illegal or + * uncorrectible, the data array is unchanged and -1 is returned + */ +int eras_dec_rs(dtype data[], int eras_pos[], int no_eras); + +#ifdef __cplusplus +} +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/report_err.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/report_err.h new file mode 100644 index 00000000..c29df457 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/report_err.h @@ -0,0 +1,61 @@ +/* report_err.h + * Declarations of routines for dissectors to use to report errors to + * the user (e.g., problems with preference settings) + * + * $Id: report_err.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __REPORT_ERR_H__ +#define __REPORT_ERR_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * Initialize the report err routines + */ +extern void init_report_err( + void (*report_failure)(const char *, va_list), + void (*report_open_failure)(const char *, int, gboolean), + void (*report_read_failure)(const char *, int)); + +/* + * Report an error when trying to open a file. + */ +extern void report_open_failure(const char *filename, int err, + gboolean for_writing); + +/* + * Report an error when trying to read a file. + */ +extern void report_read_failure(const char *filename, int err); + +/* + * Report a general error. + */ +extern void report_failure(const char *msg_format, ...); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __REPORT_ERR_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/req_resp_hdrs.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/req_resp_hdrs.h new file mode 100644 index 00000000..40e68884 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/req_resp_hdrs.h @@ -0,0 +1,43 @@ +/* req_resp_hdrs.h + * Declarations of routines handling protocols with a request/response line, + * headers, a blank line, and an optional body. + * + * $Id: req_resp_hdrs.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __REQ_RESP_HDRS_H__ +#define __REQ_RESP_HDRS_H__ + +/** + * Optionally do reassembly of the request/response line, headers, and body. + * + * @param tvb The buffer. + * @param offset The offset in the buffer to begin inspection. + * @param pinfo Packet info from the parent protocol. + * @param desegment_headers Do desegmentation on headers. + * @param desegment_body Do desegmenation on body. + * @return TRUE if desegmentation is complete otherwise FALSE + */ +extern gboolean +req_resp_hdrs_do_reassembly(tvbuff_t *tvb, const int offset, packet_info *pinfo, + const gboolean desegment_headers, const gboolean desegment_body); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/rtp_pt.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/rtp_pt.h new file mode 100644 index 00000000..0ddb9b9a --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/rtp_pt.h @@ -0,0 +1,68 @@ +/* rtp_pt.h + * Defines RTP payload types + * + * $Id: rtp_pt.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __RTP_PT_H__ +#define __RTP_PT_H__ + +#include "epan/value_string.h" + +/* + * RTP Payload types + * Table B.2 / H.225.0 + * Also RFC 1890, and + * + * http://www.iana.org/assignments/rtp-parameters + */ +#define PT_PCMU 0 /* RFC 1890 */ +#define PT_1016 1 /* RFC 1890 */ +#define PT_G721 2 /* RFC 1890 */ +#define PT_GSM 3 /* RFC 1890 */ +#define PT_G723 4 /* From Vineet Kumar of Intel; see the Web page */ +#define PT_DVI4_8000 5 /* RFC 1890 */ +#define PT_DVI4_16000 6 /* RFC 1890 */ +#define PT_LPC 7 /* RFC 1890 */ +#define PT_PCMA 8 /* RFC 1890 */ +#define PT_G722 9 /* RFC 1890 */ +#define PT_L16_STEREO 10 /* RFC 1890 */ +#define PT_L16_MONO 11 /* RFC 1890 */ +#define PT_QCELP 12 /* Qualcomm Code Excited Linear Predictive coding? */ +#define PT_CN 13 /* RFC 3389 */ +#define PT_MPA 14 /* RFC 1890, RFC 2250 */ +#define PT_G728 15 /* RFC 1890 */ +#define PT_DVI4_11025 16 /* from Joseph Di Pol of Sun; see the Web page */ +#define PT_DVI4_22050 17 /* from Joseph Di Pol of Sun; see the Web page */ +#define PT_G729 18 +#define PT_CN_OLD 19 /* Payload type reserved (old version Comfort Noise) */ +#define PT_CELB 25 /* RFC 2029 */ +#define PT_JPEG 26 /* RFC 2435 */ +#define PT_NV 28 /* RFC 1890 */ +#define PT_H261 31 /* RFC 2032 */ +#define PT_MPV 32 /* RFC 2250 */ +#define PT_MP2T 33 /* RFC 2250 */ +#define PT_H263 34 /* from Chunrong Zhu of Intel; see the Web page */ + +WS_VAR_IMPORT const value_string rtp_payload_type_vals[]; +WS_VAR_IMPORT const value_string rtp_payload_type_short_vals[]; + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sctpppids.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sctpppids.h new file mode 100644 index 00000000..523a04a8 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sctpppids.h @@ -0,0 +1,50 @@ +/* sctpppids.h + * Declarations of SCTP payload protocol IDs. + * + * $Id: sctpppids.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __SCTPPPIDS_H__ +#define __SCTPPPIDS_H__ + +/* + * SCTP payload protocol IDs. + */ +#define NOT_SPECIFIED_PROTOCOL_ID 0 +#define IUA_PAYLOAD_PROTOCOL_ID 1 +#define M2UA_PAYLOAD_PROTOCOL_ID 2 +#define M3UA_PAYLOAD_PROTOCOL_ID 3 +#define SUA_PAYLOAD_PROTOCOL_ID 4 +#define M2PA_PAYLOAD_PROTOCOL_ID 5 +#define V5UA_PAYLOAD_PROTOCOL_ID 6 +#define H248_PAYLOAD_PROTOCOL_ID 7 +#define BICC_PAYLOAD_PROTOCOL_ID 8 +#define TALI_PAYLOAD_PROTOCOL_ID 9 +#define DUA_PAYLOAD_PROTOCOL_ID 10 +#define ASAP_PAYLOAD_PROTOCOL_ID 11 +#define ENRP_PAYLOAD_PROTOCOL_ID 12 +#define H323_PAYLOAD_PROTOCOL_ID 13 +#define QIPC_PAYLOAD_PROTOCOL_ID 14 +#define SIMCO_PAYLOAD_PROTOCOL_ID 15 +#define DDP_SEG_CHUNK_PROTOCOL_ID 16 +#define DDP_STREAM_SES_CTRL_PROTOCOL_ID 17 +#define M2TP_PAYLOAD_PROTOCOL_ID 99 /* s-link */ +#endif /* sctpppids.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sigcomp-udvm.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sigcomp-udvm.h new file mode 100644 index 00000000..bcbb58fb --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sigcomp-udvm.h @@ -0,0 +1,49 @@ +/* udvm.h + * Routines making up the Univerasl Decompressor Virtual Machine (UDVM) used for + * Signaling Compression (SigComp) dissection. + * Copyright 2004, Anders Broman + * + * $Id: sigcomp-udvm.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * References: + * http://www.ietf.org/rfc/rfc3320.txt?number=3320 + * http://www.ietf.org/rfc/rfc3321.txt?number=3321 + * Useful links : + * http://www.ietf.org/internet-drafts/draft-ietf-rohc-sigcomp-impl-guide-02.txt + * http://www.ietf.org/internet-drafts/draft-ietf-rohc-sigcomp-sip-01.txt + */ + +#ifndef SIGCOMP_UDVM_H +#define SIGCOMP_UDVM_H + +#define UDVM_MEMORY_SIZE 65536 + +extern tvbuff_t* decompress_sigcomp_message(tvbuff_t *bytecode_tvb, tvbuff_t *message_tvb, packet_info *pinfo, + proto_tree *tree, gint destination, + gint print_flags, gint hf_id, gint header_len, + gint byte_code_state_len, gint byte_code_id_len, + gint udvm_start_ip); + + + +/* example: extern const value_string q931_cause_location_vals[]; */ +#endif +/* SIGCOMP_UDVM_H */ + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sigcomp_state_hdlr.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sigcomp_state_hdlr.h new file mode 100644 index 00000000..1a5beaf2 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sigcomp_state_hdlr.h @@ -0,0 +1,49 @@ +/* sigcomp_state_hdlr.c + * Routines making up the State handler of the Univerasl Decompressor Virtual Machine (UDVM) + * used for Signaling Compression (SigComp) dissection. + * Copyright 2004, Anders Broman + * + * $Id: sigcomp_state_hdlr.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * References: + * http://www.ietf.org/rfc/rfc3320.txt?number=3320 + * http://www.ietf.org/rfc/rfc3321.txt?number=3321 + * Useful links : + * http://www.ietf.org/internet-drafts/draft-ietf-rohc-sigcomp-impl-guide-03.txt + * http://www.ietf.org/internet-drafts/draft-ietf-rohc-sigcomp-sip-01.txt + */ + +#ifndef SIGCOMP_STATE_HDLR_H +#define SIGCOMP_STATE_HDLR_H + +extern const value_string result_code_vals[]; +extern int udvm_state_access(tvbuff_t *tvb, proto_tree *tree,guint8 *buff,guint16 p_id_start, guint16 p_id_length, guint16 state_begin, guint16 *state_length, + guint16 *state_address, guint16 *state_instruction, gint hf_id); + +extern void udvm_state_create(guint8 *state_buff,guint8 *state_identifier_buff,guint16 p_id_length); +extern void udvm_state_free(guint8 buff[],guint16 p_id_start,guint16 p_id_length); + +extern void sigcomp_init_udvm(void); + +#define STATE_BUFFER_SIZE 20 +#define STATE_MIN_ACCESS_LEN 6 + +#endif +/* SIGCOMP_STATE_HDLR_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/slab.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/slab.h new file mode 100644 index 00000000..c84e50ca --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/slab.h @@ -0,0 +1,75 @@ +/* slab.h + * Definitions for very simple slab handling + * + * $Id: slab.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __SLAB_H__ +#define __SLAB_H__ + +#define NITEMS_PER_SLAB 100 + +/* + * Generate declaration of a union type containing the specified type of + * slab-allocated item, and a pointer to an object of that type, for use + * in the macros below. + */ +#define SLAB_ITEM_TYPE_DEFINE(type) \ + union type ## slab_item { \ + type slab_item; \ + union type ## slab_item *next_free; \ + }; + +/* + * Generate definition of the free list pointer. + */ +#define SLAB_FREE_LIST_DEFINE(type) \ + union type ## slab_item *type ## _free_list = NULL; + +/* + * Generate an external declaration of the free list pointer. + */ +#define SLAB_FREE_LIST_DECLARE(type) \ + union type ## slab_item *type ## _free_list; + +/* we never free any memory we have allocated, when it is returned to us + we just store it in the free list until (hopefully) it gets used again +*/ +#define SLAB_ALLOC(item, type) \ + if(!type ## _free_list){ \ + int i; \ + union type ## slab_item *tmp; \ + tmp=g_malloc(NITEMS_PER_SLAB*sizeof(*tmp)); \ + for(i=0;islab_item); \ + type ## _free_list = type ## _free_list->next_free; + +#define SLAB_FREE(item, type) \ +{ \ + ((union type ## slab_item *)item)->next_free = type ## _free_list; \ + type ## _free_list = (union type ## slab_item *)item; \ +} + +#endif /* slab.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sminmpec.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sminmpec.h new file mode 100644 index 00000000..b81ea7c2 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sminmpec.h @@ -0,0 +1,83 @@ +/* sminmpec.h + * SMI Network Management Private Enterprise Codes for organizations + * + * $Id: sminmpec.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2004 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __SMINMPEC_H__ +#define __SMINMPEC_H__ + +/* + * These are SMI Network Management Private Enterprise Codes for + * organizations; see + * + * http://www.iana.org/assignments/enterprise-numbers + * + * for a list. + */ +#define VENDOR_IETF 0 /* reserved - used by the IETF in L2TP? */ +#define VENDOR_ACC 5 +#define VENDOR_CISCO 9 +#define VENDOR_HEWLETT_PACKARD 11 +#define VENDOR_SUN_MICROSYSTEMS 42 +#define VENDOR_MERIT 61 +#define VENDOR_MOTOROLA 161 +#define VENDOR_SHIVA 166 +#define VENDOR_ERICSSON 193 +#define VENDOR_CISCO_VPN5000 255 +#define VENDOR_LIVINGSTON 307 +#define VENDOR_MICROSOFT 311 +#define VENDOR_3COM 429 +#define VENDOR_ASCEND 529 +#define VENDOR_BAY 1584 +#define VENDOR_FOUNDRY 1991 +#define VENDOR_VERSANET 2180 +#define VENDOR_REDBACK 2352 +#define VENDOR_JUNIPER 2636 +#define VENDOR_APTIS 2637 +#define VENDOR_DT_AG 2937 +#define VENDOR_CISCO_VPN3000 3076 +#define VENDOR_COSINE 3085 +#define VENDOR_SHASTA 3199 +#define VENDOR_NETSCREEN 3224 +#define VENDOR_NOMADIX 3309 +#define VENDOR_T_MOBILE 3414 /* Former VoiceStream Wireless, Inc. */ +#define VENDOR_SIEMENS 4329 +#define VENDOR_CABLELABS 4491 +#define VENDOR_UNISPHERE 4874 +#define VENDOR_CISCO_BBSM 5263 +#define VENDOR_THE3GPP2 5535 +#define VENDOR_IP_UNPLUGGED 5925 +#define VENDOR_ISSANNI 5948 +#define VENDOR_DE_TE_MOBIL 6490 +#define VENDOR_QUINTUM 6618 +#define VENDOR_INTERLINK 6728 +#define VENDOR_COLUBRIS 8744 +#define VENDOR_COLUMBIA_UNIVERSITY 11862 +#define VENDOR_THE3GPP 10415 +#define VENDOR_GEMTEK_SYSTEMS 10529 +#define VENDOR_WIFI_ALLIANCE 14122 +#define VENDOR_T_SYSTEMS_NOVA 16787 + + +WS_VAR_IMPORT const value_string sminmpec_values[]; + +#endif /* __SMINMPEC_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sna-utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sna-utils.h new file mode 100644 index 00000000..8782af88 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sna-utils.h @@ -0,0 +1,41 @@ +/* sna-utils.h + * Definitions for SNA dissection. + * + * $Id: sna-utils.h 3992 2008-06-10 03:13:11Z dgu $ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __SNA_UTILS__ +#define __SNA_UTILS__ + +#include +#include + +/* + * Structure used to represent an FID Type 4 address; gives the layout of the + * data pointed to by an AT_SNA "address" structure if the size is + * SNA_FID_TYPE_4_ADDR_LEN. + */ +#define SNA_FID_TYPE_4_ADDR_LEN 6 +struct sna_fid_type_4_addr { + guint32 saf; + guint16 ef; +}; + +extern gchar *sna_fid_to_str(const address *addr); +extern void sna_fid_to_str_buf(const address *addr, gchar *buf, int buf_len); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stat_cmd_args.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stat_cmd_args.h new file mode 100644 index 00000000..56233f61 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stat_cmd_args.h @@ -0,0 +1,35 @@ +/* stat_cmd_args.h + * Declarations of routines to register "-z" command-line argument handlers + * for stats + * + * $Id: stat_cmd_args.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _STAT_H_ +#define _STAT_H_ + +extern void register_stat_cmd_arg(const char *cmd, + void (*func)(const char *arg,void* userdata), void* userdata); +extern gboolean process_stat_cmd_arg(char *optarg); +extern void list_stat_cmd_args(void); +extern void start_requested_stats(void); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stats_tree.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stats_tree.h new file mode 100644 index 00000000..ff36fd95 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stats_tree.h @@ -0,0 +1,147 @@ +/* stats_tree.h + * A counter tree API for Wireshark dissectors + * 2005, Luis E. G. Ontanon + * + * $Id: stats_tree.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef __STATS_TREE_H +#define __STATS_TREE_H + +#include +#include +#include +#include +#include +#include "../register.h" + +#define STAT_TREE_ROOT "root" + +/* obscure information regarding the stats_tree */ +typedef struct _stats_tree stats_tree; + +/* tap packet callback for stats_tree */ +typedef int (*stat_tree_packet_cb)(stats_tree*, + packet_info*, + epan_dissect_t*, + const void *); + +/* stats_tree initilaization callback */ +typedef void (*stat_tree_init_cb)(stats_tree*); + +/* stats_tree initilaization callback */ +typedef void (*stat_tree_cleanup_cb)(stats_tree*); + +/* registers a new stats tree + * abbr: protocol abbr + * name: protocol name + * packet: per packet callback + * init: tree initialization callback + */ +extern void stats_tree_register(const guint8* tapname, + const guint8* abbr, + const guint8* name, + stat_tree_packet_cb packet, + stat_tree_init_cb init, + stat_tree_cleanup_cb cleanup); + +extern int stats_tree_parent_id_by_name(stats_tree* st, const gchar* parent_name); + +/* Creates a node in the tree (to be used in the in init_cb) +* st: the stats_tree in which to create it +* name: the name of the new node +* parent_name: the name of the parent_node (NULL for root) +* with_children: TRUE if this node will have "dynamically created" children +*/ +extern int stats_tree_create_node(stats_tree* st, + const gchar* name, + int parent_id, + gboolean with_children); + +/* creates a node using it's parent's tree name */ +extern int stats_tree_create_node_by_pname(stats_tree* st, + const gchar* name, + const gchar* parent_name, + gboolean with_children); + +/* creates a node in the tree, that will contain a ranges list. + example: + stats_tree_create_range_node(st,name,parent, + "-99","100-199","200-299","300-399","400-", NULL); +*/ +extern int stats_tree_create_range_node(stats_tree* st, + const gchar* name, + int parent_id, + ...); + +extern int stats_tree_range_node_with_pname(stats_tree* st, + const gchar* name, + const gchar* parent_name, + ...); + +/* increases by one the ranged node and the sub node to whose range the value belongs */ +extern int stats_tree_tick_range(stats_tree* st, + const gchar* name, + int parent_id, + int value_in_range); + +#define stats_tree_tick_range_by_pname(st,name,parent_name,value_in_range) \ + stats_tree_tick_range((st),(name),stats_tree_parent_id_by_name((st),(parent_name),(value_in_range)) + +/* */ +extern int stats_tree_create_pivot(stats_tree* st, + const gchar* name, + int parent_id); + +extern int stats_tree_create_pivot_by_pname(stats_tree* st, + const gchar* name, + const gchar* parent_name); + +extern int stats_tree_tick_pivot(stats_tree* st, + int pivot_id, + const gchar* pivot_value); + +/* + * manipulates the value of the node whose name is given + * if the node does not exist yet it's created (with counter=1) + * using parent_name as parent node (NULL for root). + * with_children=TRUE to indicate that the created node will be a parent + */ +typedef enum _manip_node_mode { MN_INCREASE, MN_SET } manip_node_mode; +extern int stats_tree_manip_node(manip_node_mode mode, + stats_tree* st, + const guint8* name, + int parent_id, + gboolean with_children, + gint value); + +#define increase_stat_node(st,name,parent_id,with_children,value) \ +(stats_tree_manip_node(MN_INCREASE,(st),(name),(parent_id),(with_children),(value))) + +#define tick_stat_node(st,name,parent_id,with_children) \ +(stats_tree_manip_node(MN_INCREASE,(st),(name),(parent_id),(with_children),1)) + +#define set_stat_node(st,name,parent_id,with_children,value) \ +(stats_tree_manip_node(MN_SET,(st),(name),(parent_id),(with_children),value)) + +#define zero_stat_node(st,name,parent_id,with_children) \ +(stats_tree_manip_node(MN_SET,(st),(name),(parent_id),(with_children),0)) + +#endif /* __STATS_TREE_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stats_tree_priv.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stats_tree_priv.h new file mode 100644 index 00000000..80ca6a11 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stats_tree_priv.h @@ -0,0 +1,202 @@ +/* stats_tree_priv.h + * implementor's API for stats_tree + * 2005, Luis E. G. Ontanon + * + * $Id: stats_tree_priv.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __STATS_TREE_PRIV_H +#define __STATS_TREE_PRIV_H + +#include "stats_tree.h" + +#define INDENT_MAX 32 +#define NUM_BUF_SIZE 32 + +/* implementations should define this to contain its own node related data + * as well as some operations on it */ +typedef struct _st_node_pres st_node_pres; + +/* implementations should define this to contain its own dynamic tree related data +* as well as some operations on it */ +typedef struct _tree_pres tree_pres; + +/* implementations should define this to contain its own static tree related data +* as well as some operations on it */ +typedef struct _tree_cfg_pres tree_cfg_pres; + + +typedef struct _stat_node stat_node; +typedef struct _stats_tree_cfg stats_tree_cfg; + +typedef struct _range_pair { + gint floor; + gint ceil; +} range_pair_t; + +struct _stat_node { + gchar* name; + int id; + + /* the counter it keeps */ + gint counter; + + /* children nodes by name */ + GHashTable* hash; + + /* the owner of this node */ + stats_tree* st; + + /* relatives */ + stat_node* parent; + stat_node* children; + stat_node* next; + + /* used to check if value is within range */ + range_pair_t* rng; + + /* node presentation data */ + st_node_pres* pr; +}; + +struct _stats_tree { + /* the "class" from which it's derived */ + stats_tree_cfg* cfg; + + char* filter; + + /* times */ + double start; + double elapsed; + + /* used to lookup named parents: + * key: parent node name + * value: parent node + */ + GHashTable* names; + + /* used for quicker lookups of parent nodes */ + GPtrArray* parents; + + /* + * tree representation + * to be defined (if needed) by the implementations + */ + tree_pres* pr; + + /* every tree in nature has one */ + stat_node root; +}; + +struct _stats_tree_cfg { + guint8* abbr; + guint8* name; + guint8* tapname; + + gboolean in_use; + + /* dissector defined callbacks */ + stat_tree_packet_cb packet; + stat_tree_init_cb init; + stat_tree_cleanup_cb cleanup; + + /* + * node presentation callbacks + */ + + /* last to be called at node creation */ + void (*setup_node_pr)(stat_node*); + + /* last to be called at node destruction */ + void (*free_node_pr)(stat_node*); + + /* to be called for every node in the tree */ + void (*draw_node)(stat_node*); + void (*reset_node)(stat_node*); + + /* + * tree presentation callbacks + */ + tree_cfg_pres* pr; + + + tree_pres* (*new_tree_pr)(stats_tree*); + void (*free_tree_pr)(stats_tree*); + void (*draw_tree)(stats_tree*); + void (*reset_tree)(stats_tree*); +}; + +/* guess what, this is it! */ +extern void stats_tree_presentation(void (*registry_iterator)(gpointer,gpointer,gpointer), + void (*setup_node_pr)(stat_node*), + void (*free_node_pr)(stat_node*), + void (*draw_node)(stat_node*), + void (*reset_node)(stat_node*), + tree_pres* (*new_tree_pr)(stats_tree*), + void (*free_tree_pr)(stats_tree*), + void (*draw_tree)(stats_tree*), + void (*reset_tree)(stats_tree*), + void* data); + +extern stats_tree* stats_tree_new(stats_tree_cfg* cfg, tree_pres* pr, char* filter); + +/* callback for taps */ +extern int stats_tree_packet(void*, packet_info*, epan_dissect_t*, const void *); + +/* callback for reset */ +extern void stats_tree_reset(void* p_st); + +/* callback for clear */ +extern void stats_tree_reinit(void* p_st); + +/* callback for destoy */ +extern void stats_tree_free(stats_tree* st); + +/* given an optarg splits the abbr part + and returns a newly allocated buffer containing it */ +extern guint8* stats_tree_get_abbr(const guint8* optarg); + +/* obtains a stats tree from the registry given its abbr */ +extern stats_tree_cfg* stats_tree_get_cfg_by_abbr(guint8* abbr); + +/* extracts node data as strings from a stat_node into + the buffers given by value, rate and precent + if NULL they are ignored */ +extern void stats_tree_get_strs_from_node(const stat_node* node, + guint8* value, + guint8* rate, + guint8* percent); + +/* populates the given GString with a tree representation of a branch given by node, + using indent spaces as indentation */ +extern void stats_tree_branch_to_str(const stat_node* node, + GString* s, + guint indent); + +/* used to calcuate the size of the indentation and the longest string */ +extern guint stats_tree_branch_max_namelen(const stat_node* node, guint indent); + +/* a text representation of a node, + if buffer is NULL returns a newly allocated string */ +extern guint8* stats_tree_node_to_str(const stat_node* node, + guint8* buffer, guint len); + +#endif /* __STATS_TREE_PRIV_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stream.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stream.h new file mode 100644 index 00000000..9fd1cc90 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stream.h @@ -0,0 +1,138 @@ +/* stream.h + * + * Definititions for handling circuit-switched protocols + * which are handled as streams, and don't have lengths + * and IDs such as are required for reassemble.h + * + * $Id: stream.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef STREAM_H +#define STREAM_H + +#include + +struct _fragment_items; + +/* A stream represents the concept of an arbitrary stream of data, + divided up into frames for transmission, where the frames have + little or no correspondence to the PDUs of the protocol being + streamed, and those PDUs are just delineated by a magic number. + + For example, we stream H.223 over IAX2. IAX2 has no concept of + H.223 PDUs and just divides the H.223 stream into 160-byte + frames. H.223 PDUs are delineated by two-byte magic numbers (which + may, of course, straddle an IAX2 frame boundary). + + Essentially we act as a wrapper to reassemble.h, by making up + PDU ids and keeping some additional data on fragments to allow the + PDUs to be defragmented again. +*/ + + +/* A stream_t represents a stream. There might be one or two streams + in a circuit, depending on whether that circuit is mono- or bi-directional. +*/ +typedef struct stream stream_t; + +/* Fragments in a PDU are represented using a stream_pdu_fragment_t, + and placed in a linked-list with other fragments in the PDU. + + (They're also placed in a hash so we can find them again later) +*/ +typedef struct stream_pdu_fragment stream_pdu_fragment_t; + + + +struct circuit; +struct conversation; + +/* initialise a new stream. Call this when you first identify a distinct + * stream. The circit pointer is just used as a key to look up the stream. */ +extern stream_t *stream_new_circ ( const struct circuit *circuit, int p2p_dir ); +extern stream_t *stream_new_conv ( const struct conversation *conv, int p2p_dir ); + +/* retrieve a previously-created stream. + * + * Returns null if no matching stream was found. + */ +extern stream_t *find_stream_circ ( const struct circuit *circuit, int p2p_dir ); +extern stream_t *find_stream_conv ( const struct conversation *conv, int p2p_dir ); + + + +/* see if we've seen this fragment before. + + The framenum and offset are just hash keys, so can be any values unique + to this frame, but the idea is that you use the number of the frame being + disassembled, and the byte-offset within that frame. +*/ +extern stream_pdu_fragment_t *stream_find_frag( stream_t *stream, guint32 framenum, guint32 offset ); + +/* add a new fragment to the fragment tables for the stream. The framenum and + * offset are keys allowing future access with stream_find_frag(), tvb is the + * fragment to be added, and pinfo is the information for the frame containing + * this fragment. more_frags should be set if this is the final fragment in the + * PDU. + * + * * the fragment must be later in the stream than any previous fragment + * (ie, framenum.offset must be greater than those passed on the previous + * call) + * + * This essentially means that you can only add fragments on the first pass + * through the stream. + */ +extern stream_pdu_fragment_t *stream_add_frag( stream_t *stream, guint32 framenum, guint32 offset, + tvbuff_t *tvb, packet_info *pinfo, gboolean more_frags ); + +/* Get the length of a fragment previously found by stream_find_frag(). + */ +extern guint32 stream_get_frag_length( const stream_pdu_fragment_t *frag); + +/* Get a handle on the top of the chain of fragment_datas underlying this PDU + * frag can be any fragment within a PDU, and it will always return the head of + * the chain + * + * Returns NULL until the last fragment is added. + */ +extern struct _fragment_data *stream_get_frag_data( const stream_pdu_fragment_t *frag); + +/* + * Process reassembled data; if this is the last fragment, put the fragment + * information into the protocol tree, and construct a tvbuff with the + * reassembled data, otherwise just put a "reassembled in" item into the + * protocol tree. + */ +extern tvbuff_t *stream_process_reassembled( + tvbuff_t *tvb, int offset, packet_info *pinfo, + char *name, const stream_pdu_fragment_t *frag, + const struct _fragment_items *fit, + gboolean *update_col_infop, proto_tree *tree); + +/* Get the PDU number. PDUs are numbered from zero within a stream. + * frag can be any fragment within a PDU. + */ +extern guint32 stream_get_pdu_no( const stream_pdu_fragment_t *frag); + +/* initialise the stream routines */ +void stream_init( void ); + +#endif /* STREAM_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/strutil.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/strutil.h new file mode 100644 index 00000000..4b108175 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/strutil.h @@ -0,0 +1,243 @@ +/* strutil.h + * String utility definitions + * + * $Id: strutil.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __STRUTIL_H__ +#define __STRUTIL_H__ + +/* ... thus, config.h needs to be #included */ + +/** @file + * String handling and conversion utilities. + */ + +/** Given a pointer into a data buffer, and to the end of the buffer, + * find the end of the (putative) line at that position in the data + * buffer. + * + * @param data A pointer to the beginning of the data + * @param dataend A pointer to the end of the data + * @param eol A pointer that will receive the EOL location + * @return A pointer to the EOL character(s) in "*eol". + */ +const guchar *find_line_end(const guchar *data, const guchar *dataend, + const guchar **eol); + +/** Get the length of the next token in a line, and the beginning of the + * next token after that (if any). + * @param linep A pointer to the beginning of the line + * @param lineend A pointer to the end of the line + * @param next_token Receives the location of the next token + * @return 0 if there is no next token. + */ +int get_token_len(const guchar *linep, const guchar *lineend, + const guchar **next_token); + +/** Given a string, generate a string from it that shows non-printable + * characters as C-style escapes, and return a pointer to it. + * + * @param line A pointer to the input string + * @param len The length of the input string + * @return A pointer to the formatted string + * + * @see tvb_format_text() + */ +gchar* format_text(const guchar *line, int len); + +gchar* format_text_wsp(const guchar *line, int len); + +/** Turn an array of bytes into a string showing the bytes in hex. + * + * @param bd A pointer to the byte array + * @param bd_len The length of the byte array + * @return A pointer to the formatted string + * + * @see bytes_to_str_punct() + */ +gchar* bytes_to_str(const guint8 *bd, int bd_len); + +/** Turn an array of bytes into a string showing the bytes in hex, + * separated by a punctuation character. + * + * @param bd A pointer to the byte array + * @param bd_len The length of the byte array + * @param punct The punctuation character + * @return A pointer to the formatted string + * + * @see bytes_to_str() + */ +gchar* bytes_to_str_punct(const guint8 *bd, int bd_len, gchar punct); + +/** Turn a string of hex digits with optional separators (defined by + * is_byte_sep() into a byte array. + * + * @param hex_str The string of hex digits. + * @param bytes The GByteArray that will receive the bytes. This + * must be initialized by the caller. + * @param force_separators If set to TRUE, separators MUST exist between + * bytes. + * @return True if the string was converted successfully + */ +gboolean hex_str_to_bytes(const char *hex_str, GByteArray *bytes, + gboolean force_separators); + +/** Turn an RFC 3986 percent-encoded string into a byte array. + * + * @param uri_str The string of hex digits. + * @param bytes The GByteArray that will receive the bytes. This + * must be initialized by the caller. + * @return True if the string was converted successfully + * @see format_uri() + */ +gboolean uri_str_to_bytes(const char *uri_str, GByteArray *bytes); + +/** Turn a byte array into an RFC 3986 percent-encoded string. + * + * @param bytes The GByteArray that will receive the bytes. This + * must be initialized by the caller. + * @param reserved_chars Normally the "gen-delims" and "sub-delims" + * from RFC 3986 (":/?#[]@" and "!$&'()*+,;=" respectively) + * plus space (hex value 20) are treated as reserved characters. + * If this variable is non-NULL, its contents will be used + * instead. + * @note Any non-printing character determined by isprint(), along + * with the % character itself are always reserved. + * @see uri_str_to_bytes(), format_text(), isprint() + */ +gchar* format_uri(const GByteArray *bytes, const gchar *reserved_chars); + +/** Turn a OID string representation (dot notation) into a byte array. + * + * @param oid_str The OID string (dot notaion). + * @param bytes The GByteArray that will receive the bytes. This + * must be initialized by the caller. + * @return True if the string was converted successfully + */ +gboolean oid_str_to_bytes(const char *oid_str, GByteArray *bytes); + +/** + * Create a copy of a GByteArray + * + * @param ba The byte array to be copied. + * @return If ba exists, a freshly allocated copy. NULL otherwise. + * + * XXX - Should this be in strutil.c? + */ +GByteArray *byte_array_dup(GByteArray *ba); + +/** + * Compare the contents of two GByteArrays + * + * @param ba1 A byte array + * @param ba2 A byte array + * @return If both arrays are non-NULL and their lengths are equal and + * their contents are equal, returns TRUE. Otherwise, returns + * FALSE. + * + * XXX - Should this be in strutil.c? + */ +gboolean byte_array_equal(GByteArray *ba1, GByteArray *ba2); + + +/** Return a XML escaped representation of the unescaped string. + * The returned string must be freed when no longer in use. + * + * @param unescaped The unescaped string + * @return An XML-escaped representation of the input string + */ +gchar* xml_escape(const gchar *unescaped); + +/** + * Return the first occurrence of needle in haystack. + * Algorithm copied from GNU's glibc 2.3.2 memcmp() + * + * @param haystack The data to search + * @param haystack_len The length of the search data + * @param needle The string to look for + * @param needle_len The length of the search string + * @return A pointer to the first occurrence of "needle" in + * "haystack". If "needle" isn't found or is NULL, or if + * "needle_len" is 0, NULL is returned. + */ +const guint8 * epan_memmem(const guint8 *haystack, guint haystack_len, + const guint8 *needle, guint needle_len); + +/* Surround a string or a macro, resolved to a string, with double quotes */ +#define _STRINGIFY(a) # a +#define STRINGIFY(a) _STRINGIFY(a) + +/** Scan a string to make sure it's valid hex. + * + * @param string The string to validate + * @param nbytes The length of the return buffer + * @return A pointer to a buffer containing the converted raw bytes. This + * buffer must be g_free()d by the caller. + */ +guint8 * convert_string_to_hex(const char *string, size_t *nbytes); + +/** Prep a string for case-sensitive vs case-insensitive searching. + * + * @param string The search string + * @param case_insensitive TRUE if case-insensitive, FALSE if not + * @return A direct copy of the string if it's a case-sensitive search and + * an uppercased version if not. In either case the string must be g_free()d + * by the caller. + */ +char * convert_string_case(const char *string, gboolean case_insensitive); + +/** Finds the first occurence of string 'needle' in string 'haystack'. + * The matching is done in a case insensitive manner. + * + * @param haystack The string possibly containing the substring + * @param needle The substring to be searched + * @return A pointer into 'haystack' where 'needle' is first found. + * Otherwise it returns NULL. + */ +char * epan_strcasestr(const char *haystack, const char *needle); + +/* g_strlcat() does not exist in GLib 1.2[.x] */ +#if GLIB_MAJOR_VERSION < 2 +gsize g_strlcat(gchar *dst, const gchar *src, gsize size); +gsize g_strlcpy(gchar *dest, const gchar *src, gsize dest_size); +#endif + +#if GLIB_MAJOR_VERSION < 2 +/* g_ascii_isprint() does not exist in GLib 1.2[.x]. + * assume all codes >=0x20 and <0x80 are ASCII printables. + */ +#define g_ascii_isprint(c) \ + (((c<0x20)||(c>=0x80))?FALSE:TRUE) +/* g_ascii_isxdigit() does not exist in Glib 1.2 */ +#define g_ascii_isxdigit(c) \ + ( ((c>='0')&&(c<='9'))?TRUE: \ + ( ((c>='a')&&(c<='f'))?TRUE: \ + (((c>='A')&&(c<='F'))?TRUE:FALSE) ) ) + +#endif + +#if GLIB_MAJOR_VERSION < 2 +/* g_byte_array_sized_new() doesnt exist in glib-1.2 */ +GByteArray *g_byte_array_sized_new(guint reserved_size); +#endif + +#endif /* __STRUTIL_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/t35.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/t35.h new file mode 100644 index 00000000..692c0b8d --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/t35.h @@ -0,0 +1,35 @@ +/* t35.h + * T.35 and H.221 tables + * 2003 Tomas Kukosa + * + * $Id: t35.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __T35_H__ +#define __T35_H__ + +#include "epan/value_string.h" + +extern const value_string T35CountryCode_vals[]; +extern const value_string T35Extension_vals[]; +extern const value_string H221ManufacturerCode_vals[]; + +#endif /* __T35_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tap-voip.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tap-voip.h new file mode 100644 index 00000000..21888588 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tap-voip.h @@ -0,0 +1,59 @@ +/* tap-voip.h + * VoIP packet tap interface 2007 Tomas Kukosa + * + * $Id: tap-voip.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _TAP_VOIP_H_ +#define _TAP_VOIP_H_ + +/* defines voip call state */ +typedef enum _voip_call_state { + VOIP_NO_STATE, + VOIP_CALL_SETUP, + VOIP_RINGING, + VOIP_IN_CALL, + VOIP_CANCELLED, + VOIP_COMPLETED, + VOIP_REJECTED, + VOIP_UNKNOWN +} voip_call_state; + +typedef enum _voip_call_active_state { + VOIP_ACTIVE, + VOIP_INACTIVE +} voip_call_active_state; + +/* structure for common/proprietary VoIP calls TAP */ +typedef struct _voip_packet_info_t +{ + gchar *protocol_name; + gchar *call_id; + voip_call_state call_state; + voip_call_active_state call_active_state; + gchar *from_identity; + gchar *to_identity; + gchar *call_comment; + gchar *frame_label; + gchar *frame_comment; +} voip_packet_info_t; + +#endif /* _TAP_VOIP_H_ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tap.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tap.h new file mode 100644 index 00000000..11ca6fcb --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tap.h @@ -0,0 +1,61 @@ +/* tap.h + * packet tap interface 2002 Ronnie Sahlberg + * + * $Id: tap.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _TAP_H_ +#define _TAP_H_ + +#include "epan/epan.h" + +#ifdef INTTYPES_H_DEFINES_FORMATS +#include +#endif + +/* With MSVC and a libwireshark.dll, we need a + * special declaration of num_tap_filters. + */ +WS_VAR_IMPORT int num_tap_filters; + +typedef void (*tap_reset_cb)(void *tapdata); +typedef int (*tap_packet_cb)(void *tapdata, packet_info *pinfo, epan_dissect_t *edt, const void *data); +typedef void (*tap_draw_cb)(void *tapdata); + + +extern void tap_init(void); +extern int register_tap(const char *name); +extern int find_tap_id(const char *name); +extern void tap_queue_packet(int tap_id, packet_info *pinfo, const void *tap_specific_data); +extern void tap_queue_init(epan_dissect_t *edt); +extern void tap_push_tapped_queue(epan_dissect_t *edt); +extern void reset_tap_listeners(void); +extern void draw_tap_listeners(gboolean draw_all); +extern GString *register_tap_listener(const char *tapname, void *tapdata, + const char *fstring, tap_reset_cb tap_reset, tap_packet_cb tap_packet, + tap_draw_cb tap_draw); +extern GString *set_tap_dfilter(void *tapdata, const char *fstring); +extern void remove_tap_listener(void *tapdata); +extern gboolean have_tap_listeners(void); +extern gboolean have_tap_listener(int tap_id); +extern const void *fetch_tapped_data(int tap_id, int idx); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tcap-persistentdata.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tcap-persistentdata.h new file mode 100644 index 00000000..4e9c278f --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tcap-persistentdata.h @@ -0,0 +1,148 @@ +/* + * tcap-persistentdata.h + * Definitions for lists and hash tables used in wireshark's tcap dissector + * for calculation of delays in tcap-transactions + * Copyright 2006 Florent Drouin (based on h225-persistentdata from Lars Roland) + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * $Id: tcap-persistentdata.h 3992 2008-06-10 03:13:11Z dgu $ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __tcapsrt_HASH__ +#define __tcapsrt_HASH__ + +#include "epan/packet.h" +#include "epan/conversation.h" +#include "epan/dissectors/packet-tcap.h" + +#define LENGTH_OID 16 +struct tcaphash_context_t { + struct tcaphash_context_key_t * key; + guint32 session_id; + guint32 first_frame; + guint32 last_frame; + nstime_t begin_time; /* time of arrival of TC_BEGIN */ + nstime_t end_time; /* time of closing message */ + gboolean responded; /* true, if request has been responded */ + gboolean closed; + gboolean upper_dissector; + gboolean oid_present; + gchar oid[LENGTH_OID+1]; + gboolean subdissector_present; + dissector_handle_t subdissector_handle; + void (* callback) (tvbuff_t *,packet_info *, proto_tree *, struct tcaphash_context_t *); + struct tcaphash_begincall_t * begincall; + struct tcaphash_contcall_t * contcall; + struct tcaphash_endcall_t * endcall; + struct tcaphash_ansicall_t * ansicall; +}; + +struct tcaphash_begincall_t { + struct tcaphash_begin_info_key_t * beginkey; + struct tcaphash_context_t * context; + gboolean father; + struct tcaphash_begincall_t * next_begincall; + struct tcaphash_begincall_t * previous_begincall; +}; + +struct tcaphash_contcall_t { + struct tcaphash_cont_info_key_t * contkey; + struct tcaphash_context_t * context; + gboolean father; + struct tcaphash_contcall_t * next_contcall; + struct tcaphash_contcall_t * previous_contcall; +}; + +struct tcaphash_endcall_t { + struct tcaphash_end_info_key_t * endkey; + struct tcaphash_context_t * context; + gboolean father; + struct tcaphash_endcall_t * next_endcall; + struct tcaphash_endcall_t * previous_endcall; +}; + +struct tcaphash_ansicall_t { + struct tcaphash_ansi_info_key_t * ansikey; + struct tcaphash_context_t * context; + gboolean father; + struct tcaphash_ansicall_t * next_ansicall; + struct tcaphash_ansicall_t * previous_ansicall; +}; + +/* The Key for the hash table is the TCAP origine transaction identifier + of the TC_BEGIN containing the InitialDP */ + +struct tcaphash_context_key_t { + guint32 session_id; +}; + +struct tcaphash_begin_info_key_t { + guint32 hashKey; + guint32 tid; + guint32 opc_hash; + guint32 dpc_hash; +}; + +struct tcaphash_cont_info_key_t { + guint32 hashKey; + guint32 src_tid; + guint32 dst_tid; + guint32 opc_hash; + guint32 dpc_hash; +}; + +struct tcaphash_end_info_key_t { + guint32 hashKey; + guint32 tid; + guint32 opc_hash; + guint32 dpc_hash; +}; + +struct tcaphash_ansi_info_key_t { + guint32 hashKey; + guint32 tid; + guint32 opc_hash; + guint32 dpc_hash; +}; + + +/* List of infos to store for the analyse */ +struct tcapsrt_info_t { + guint32 tcap_session_id; + guint32 src_tid; + guint32 dst_tid; + guint8 ope; +}; + +void tcapsrt_init_routine(void); + +struct tcapsrt_info_t * tcapsrt_razinfo(void); + +void tcapsrt_close(struct tcaphash_context_t * p_tcaphash_context, + packet_info * pinfo _U_); + +struct tcaphash_context_t * tcapsrt_call_matching(tvbuff_t *tvb, + packet_info * pinfo _U_, + proto_tree *tree, + struct tcapsrt_info_t * p_tcap_info); + +WS_VAR_IMPORT gboolean gtcap_StatSRT; + +#endif /* __tcapsrt_HASH__*/ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tfs.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tfs.h new file mode 100644 index 00000000..e77f0b9c --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tfs.h @@ -0,0 +1,65 @@ +/* tfs.h + * true_false strings + * Copyright 2007, Jaap Keuter + * + * $Id: tfs.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __TFS_H__ +#define __TFS_H__ + +/* Struct for boolean enumerations */ +typedef struct true_false_string { + const char *true_string; + const char *false_string; +} true_false_string; + +/* + * A default set of true/false strings that dissectors can use for + * FT_BOOLEAN header fields. + */ +WS_VAR_IMPORT const true_false_string tfs_true_false; +WS_VAR_IMPORT const true_false_string tfs_yes_no; +WS_VAR_IMPORT const true_false_string tfs_set_notset; +WS_VAR_IMPORT const true_false_string tfs_enabled_disabled; +WS_VAR_IMPORT const true_false_string tfs_ok_error; +WS_VAR_IMPORT const true_false_string tfs_success_fail; +WS_VAR_IMPORT const true_false_string tfs_on_off; +WS_VAR_IMPORT const true_false_string tfs_ack_nack; +WS_VAR_IMPORT const true_false_string tfs_odd_even; +WS_VAR_IMPORT const true_false_string tfs_allow_block; +WS_VAR_IMPORT const true_false_string tfs_restricted_allowed; +WS_VAR_IMPORT const true_false_string tfs_accept_reject; +WS_VAR_IMPORT const true_false_string tfs_more_nomore; +WS_VAR_IMPORT const true_false_string tfs_present_absent; +WS_VAR_IMPORT const true_false_string tfs_active_inactive; +WS_VAR_IMPORT const true_false_string tfs_found_not_found; +WS_VAR_IMPORT const true_false_string tfs_command_response; +WS_VAR_IMPORT const true_false_string tfs_capable_not_capable; +WS_VAR_IMPORT const true_false_string tfs_supported_not_supported; + +/* + * Old true_false_string from packet.c + * Retained for backward compatibility until all dissectors are updated. + */ +WS_VAR_IMPORT const true_false_string flags_set_truth; + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/timestamp.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/timestamp.h new file mode 100644 index 00000000..e357ee21 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/timestamp.h @@ -0,0 +1,68 @@ +/* timestamp.h + * Defines for packet timestamps + * + * $Id: timestamp.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __TIMESTAMP_H__ +#define __TIMESTAMP_H__ + +/* + * Type of time-stamp shown in the summary display. + */ +typedef enum { + TS_RELATIVE, /* Since start of capture */ + TS_ABSOLUTE, + TS_ABSOLUTE_WITH_DATE, + TS_DELTA, /* Since previous captured packet */ + TS_DELTA_DIS, /* Since previous displayed packet */ + TS_EPOCH, /* Seconds (and fractions) since epoch */ + +/* + * Special value used for the command-line setting in Wireshark, to indicate + * that no value has been set from the command line. + */ + TS_NOT_SET +} ts_type; + +typedef enum { + TS_PREC_AUTO, /* recent */ + TS_PREC_FIXED_SEC, /* recent and internal */ + TS_PREC_FIXED_DSEC, /* recent and internal */ + TS_PREC_FIXED_CSEC, /* recent and internal */ + TS_PREC_FIXED_MSEC, /* recent and internal */ + TS_PREC_FIXED_USEC, /* recent and internal */ + TS_PREC_FIXED_NSEC, /* recent and internal */ + TS_PREC_AUTO_SEC, /* internal */ + TS_PREC_AUTO_DSEC, /* internal */ + TS_PREC_AUTO_CSEC, /* internal */ + TS_PREC_AUTO_MSEC, /* internal */ + TS_PREC_AUTO_USEC, /* internal */ + TS_PREC_AUTO_NSEC /* internal */ +} ts_precision; + +extern ts_type timestamp_get_type(void); +extern void timestamp_set_type(ts_type); + +extern int timestamp_get_precision(void); +extern void timestamp_set_precision(int tsp); + +#endif /* timestamp.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/to_str.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/to_str.h new file mode 100644 index 00000000..a1e8028b --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/to_str.h @@ -0,0 +1,94 @@ +/* to_str.h + * Definitions for utilities to convert various other types to strings. + * + * $Id: to_str.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __TO_STR_H__ +#define __TO_STR_H__ + +#include + +#include "nstime.h" +#include "epan/packet_info.h" + +#define GUID_STR_LEN 37 +#define MAX_IP_STR_LEN 16 +#define MAX_ADDR_STR_LEN 256 + +/* + * Resolution of a time stamp. + */ +typedef enum { + SECS, /* seconds */ + DSECS, /* deciseconds */ + CSECS, /* centiseconds */ + MSECS, /* milliseconds */ + USECS, /* microseconds */ + NSECS /* nanoseconds */ +} time_res_t; + +/* + * These are utility functions which convert various types to strings, + * but for which no more specific module applies. + */ + +struct e_in6_addr; + +extern gchar* address_to_str(const address *); +extern void address_to_str_buf(const address *addr, gchar *buf, int buf_len); +extern gchar* bytestring_to_str(const guint8 *, guint32, char); +extern gchar* ether_to_str(const guint8 *); +extern gchar* ip_to_str(const guint8 *); +extern void ip_to_str_buf(const guint8 *ad, gchar *buf, int buf_len); +extern gchar* fc_to_str(const guint8 *); +extern gchar* fcwwn_to_str (const guint8 *); +extern gchar* ip6_to_str(const struct e_in6_addr *); +extern void ip6_to_str_buf(const struct e_in6_addr *, gchar *); +extern gchar* ipx_addr_to_str(guint32, const guint8 *); +extern gchar* ipxnet_to_string(const guint8 *ad); +extern gchar* ipxnet_to_str_punct(const guint32 ad, char punct); +extern gchar* vines_addr_to_str(const guint8 *addrp); +extern void vines_addr_to_str_buf(const guint8 *addrp, gchar *buf, int buf_len); +extern gchar* time_secs_to_str(gint32); +extern gchar* time_msecs_to_str(gint32); +extern gchar* abs_time_to_str(nstime_t*); +extern gchar* abs_time_secs_to_str(time_t); +extern void display_signed_time(gchar *, int, gint32, gint32, time_res_t); +extern void display_epoch_time(gchar *, int, time_t, gint32, time_res_t); + +extern gchar* rel_time_to_str(nstime_t*); +extern gchar* rel_time_to_secs_str(nstime_t*); +extern gchar* guid_to_str(const e_guid_t*); +extern gchar* guid_to_str_buf(const e_guid_t*, gchar*, int); + +void tipc_addr_to_str_buf( const guint8 *data, gchar *buf, int buf_len); + +extern char *other_decode_bitfield_value(char *buf, guint32 val, guint32 mask, + int width); +extern char *decode_bitfield_value(char *buf, guint32 val, guint32 mask, + int width); +extern const char *decode_boolean_bitfield(guint32 val, guint32 mask, int width, + const char *truedesc, const char *falsedesc); +extern const char *decode_numeric_bitfield(guint32 val, guint32 mask, int width, + const char *fmt); + +#endif /* __TO_STR_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tvbparse.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tvbparse.h new file mode 100644 index 00000000..4e04a1b3 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tvbparse.h @@ -0,0 +1,475 @@ + +/* tvbparse.h +* +* an API for text tvb parsers +* +* Copyright 2005, Luis E. Garcia Ontanon +* +* $Id: tvbparse.h 3992 2008-06-10 03:13:11Z dgu $ +* +* Wireshark - Network traffic analyzer +* By Gerald Combs +* Copyright 1998 Gerald Combs +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* + The intention behind this is to ease the writing of dissectors that have to + parse text without the need of writing into buffers. + + It was originally written to avoid using lex and yacc for the xml dissector. + + the parser is able to look for wanted elements these can be: + + simple tokens: + - a char out of a string of needles + - a char not belonging to a string of needles + - a sequence of chars that belong to a set of chars + - a sequence of chars that do not belong to a set of chars + - a string + - a caseless string + - all the characters up to a certain wanted element (included or excluded) + + composed elements: + - one of a given group of wanted elements + - a sequence of wanted elements + - some (at least one) instances of a wanted element + + Once a wanted element is successfully extracted, by either tvbparse_get or + tvbparse_find, the parser will invoke a given callback + before and another one after every of its component's subelement's callbacks + are being called. + + If tvbparse_get or tvbparse_find fail to extract the wanted element the + subelements callbacks are not going to be invoked. + + The wanted elements are instantiated once by the proto_register_xxx function. + + The parser is isntantiated for every packet and it mantains its state. + + The element's data is destroyed before the next packet is dissected. + */ + +#ifndef _TVB_PARSE_H_ +#define _TVB_PARSE_H_ + +#include +#include + +typedef struct _tvbparse_elem_t tvbparse_elem_t; +typedef struct _tvbparse_wanted_t tvbparse_wanted_t; +typedef struct _tvbparse_t tvbparse_t; + + +/* + * a callback function to be called before or after an element has been + * successfuly extracted. + * + * Note that if the token belongs to a composed token the callbacks of the + * components won't be called unless the composed token is successfully + * extracted. + * + * tvbparse_data: the private data of the parser + * wanted_data: the private data of the wanted element + * elem: the extracted element + */ +typedef void (*tvbparse_action_t)(void* tvbparse_data, const void* wanted_data, struct _tvbparse_elem_t* elem); + +typedef int (*tvbparse_condition_t) +(tvbparse_t*, int, + const tvbparse_wanted_t*, + tvbparse_elem_t**); + + +typedef enum { + TP_UNTIL_INCLUDE, /* last elem is included, its span is spent by the parser */ + TP_UNTIL_SPEND, /* last elem is not included, but its span is spent by the parser */ + TP_UNTIL_LEAVE /* last elem is not included, neither its span is spent by the parser */ +} until_mode_t; + + +struct _tvbparse_wanted_t { + int id; + tvbparse_condition_t condition; + + union { + const gchar* str; + struct _tvbparse_wanted_t** handle; + struct { + union { + gint64 i; + guint64 u; + gdouble f; + } value; + gboolean (*comp)(void*,const void*); + void* (*extract)(tvbuff_t*,guint); + } number; + enum ftenum ftenum; + struct { + until_mode_t mode; + const tvbparse_wanted_t* subelem; + } until; + struct { + GHashTable* table; + struct _tvbparse_wanted_t* key; + struct _tvbparse_wanted_t* other; + } hash; + GPtrArray* elems; + const tvbparse_wanted_t* subelem; + void* p; + } control; + + int len; + + guint min; + guint max; + + const void* data; + + tvbparse_action_t before; + tvbparse_action_t after; + +}; + +/* an instance of a per packet parser */ +struct _tvbparse_t { + tvbuff_t* tvb; + int offset; + int end_offset; + void* data; + const tvbparse_wanted_t* ignore; +}; + + +/* a matching token returned by either tvbparser_get or tvb_parser_find */ +struct _tvbparse_elem_t { + int id; + + tvbuff_t* tvb; + int offset; + int len; + + void* data; + + struct _tvbparse_elem_t* sub; + + struct _tvbparse_elem_t* next; + struct _tvbparse_elem_t* last; + + const tvbparse_wanted_t* wanted; +}; + + +/* + * definition of wanted token types + * + * the following functions define the tokens we will be able to look for in a tvb + * common parameters are: + * + * id: an arbitrary id that will be copied to the eventual token (don't use 0) + * private_data: persistent data to be passed to the callback action (wanted_data) + * before_cb: an callback function to be called before those of the subelements + * after_cb: an callback function to be called after those of the subelements + */ + + +/* + * a char element. + * + * When looked for it returns a simple element one character long if the char + * at the current offset matches one of the the needles. + */ +tvbparse_wanted_t* tvbparse_char(int id, + const gchar* needles, + const void* private_data, + tvbparse_action_t before_cb, + tvbparse_action_t after_cb); + +/* + * a not_char element. + * + * When looked for it returns a simple element one character long if the char + * at the current offset does not match one of the the needles. + */ +tvbparse_wanted_t* tvbparse_not_char(int id, + const gchar* needle, + const void* private_data, + tvbparse_action_t before_cb, + tvbparse_action_t after_cb); + +/* + * a chars element + * + * When looked for it returns a simple element one or more characters long if + * one or more char(s) starting from the current offset match one of the needles. + * An element will be returned if at least min_len chars are given (1 if it's 0) + * It will get at most max_len chars or as much as it can if max_len is 0. + */ +tvbparse_wanted_t* tvbparse_chars(int id, + guint min_len, + guint max_len, + const gchar* needles, + const void* private_data, + tvbparse_action_t before_cb, + tvbparse_action_t after_cb); + +/* + * a not_chars element + * + * When looked for it returns a simple element one or more characters long if + * one or more char(s) starting from the current offset do not match one of the + * needles. + * An element will be returned if at least min_len chars are given (1 if it's 0) + * It will get at most max_len chars or as much as it can if max_len is 0. + */ +tvbparse_wanted_t* tvbparse_not_chars(int id, + guint min_len, + guint max_len, + const gchar* needles, + const void* private_data, + tvbparse_action_t before_cb, + tvbparse_action_t after_cb); + +/* + * a string element + * + * When looked for it returns a simple element if we have the given string at + * the current offset + */ +tvbparse_wanted_t* tvbparse_string(int id, + const gchar* string, + const void* private_data, + tvbparse_action_t before_cb, + tvbparse_action_t after_cb); + +/* + * casestring + * + * When looked for it returns a simple element if we have a matching string at + * the current offset + */ +tvbparse_wanted_t* tvbparse_casestring(int id, + const gchar* str, + const void* data, + tvbparse_action_t before_cb, + tvbparse_action_t after_cb); + +/* + * until + * + * When looked for it returns a simple element containing all the characters + * found until the first match of the ending element if the ending element is + * found. + * + * When looking for until elements it calls tvbparse_find so it can be very slow. + * + * It won't have a subelement, the ending's callbacks won't get called. + */ + +/* + * op_mode values determine how the terminating element and the current offset + * of the parser are handled + */ +tvbparse_wanted_t* tvbparse_until(int id, + const void* private_data, + tvbparse_action_t before_cb, + tvbparse_action_t after_cb, + const tvbparse_wanted_t* ending, + until_mode_t until_mode); + +/* + * one_of + * + * When looked for it will try to match to the given candidates and return a + * composed element whose subelement is the first match. + * + * The list of candidates is terminated with a NULL + * + */ +tvbparse_wanted_t* tvbparse_set_oneof(int id, + const void* private_data, + tvbparse_action_t before_cb, + tvbparse_action_t after_cb, + ...); + +/* + * hashed + */ + +tvbparse_wanted_t* tvbparse_hashed(int id, + const void* data, + tvbparse_action_t before_cb, + tvbparse_action_t after_cb, + tvbparse_wanted_t* key, + tvbparse_wanted_t* other, + ...); + +void tvbparse_hashed_add(tvbparse_wanted_t* w, ...); + +/* + * sequence + * + * When looked for it will try to match in order all the given candidates. If + * every candidate is found in the given order it will return a composed + * element whose subelements are the matcheed elemets. + * + * The list of candidates is terminated with a NULL. + * + */ +tvbparse_wanted_t* tvbparse_set_seq(int id, + const void* private_data, + tvbparse_action_t before_cb, + tvbparse_action_t after_cb, + ...); +/* + * some + * + * When looked for it will try to match the given candidate at least min times + * and at most max times. If the given candidate is matched at least min times + * a composed element is returned. + * + */ +tvbparse_wanted_t* tvbparse_some(int id, + guint min, + guint max, + const void* private_data, + tvbparse_action_t before_cb, + tvbparse_action_t after_cb, + const tvbparse_wanted_t* wanted); + +#define tvbparse_one_or_more(id, private_data, before_cb, after_cb, wanted)\ + tvbparse_some(id, 1, G_MAXINT, private_data, before_cb, after_cb, wanted) + + +/* + * handle + * + * this is a pointer to a pointer to a wanted element (that might have not + * been initialized yet) so that recursive structures + */ +tvbparse_wanted_t* tvbparse_handle(tvbparse_wanted_t** handle); + +#if 0 + +enum ft_cmp_op { + TVBPARSE_CMP_GT, + TVBPARSE_CMP_GE, + TVBPARSE_CMP_EQ, + TVBPARSE_CMP_NE, + TVBPARSE_CMP_LE, + TVBPARSE_CMP_LT +}; + +/* not yet tested */ +tvbparse_wanted_t* tvbparse_ft(int id, + const void* data, + tvbparse_action_t before_cb, + tvbparse_action_t after_cb, + enum ftenum ftenum); + +/* not yet tested */ +tvbparse_wanted_t* tvbparse_end_of_buffer(int id, + const void* data, + tvbparse_action_t before_cb, + tvbparse_action_t after_cb); +/* not yet tested */ +tvbparse_wanted_t* tvbparse_ft_numcmp(int id, + const void* data, + tvbparse_action_t before_cb, + tvbparse_action_t after_cb, + enum ftenum ftenum, + int little_endian, + enum ft_cmp_op ft_cmp_op, + ... ); + +#endif + +/* quoted + * this is a composed candidate, that will try to match a quoted string + * (included the quotes) including into it every escaped quote. + * + * C strings are matched with tvbparse_quoted(-1,NULL,NULL,NULL,"\"","\\") + */ +tvbparse_wanted_t* tvbparse_quoted(int id, + const void* data, + tvbparse_action_t before_cb, + tvbparse_action_t after_cb, + char quote, + char escape); + +/* + * a helper callback for quoted strings that will shrink the token to contain + * only the string andnot the quotes + */ +void tvbparse_shrink_token_cb(void* tvbparse_data, + const void* wanted_data, + tvbparse_elem_t* tok); + + + + +/* initialize the parser (at every packet) +* tvb: what are we parsing? +* offset: from where +* len: for how many bytes +* private_data: will be passed to the action callbacks +* ignore: a wanted token type to be ignored (the associated cb WILL be called when it matches) +*/ +tvbparse_t* tvbparse_init(tvbuff_t* tvb, + int offset, + int len, + void* private_data, + const tvbparse_wanted_t* ignore); + +/* reset the parser */ +gboolean tvbparse_reset(tvbparse_t* tt, int offset, int len); + +guint tvbparse_curr_offset(tvbparse_t* tt); +guint tvbparse_len_left(tvbparse_t* tt); + + + +/* + * This will look for the wanted token at the current offset or after any given + * number of ignored tokens returning FALSE if there's no match or TRUE if there + * is a match. + * The parser will be left in its original state and no callbacks will be called. + */ +gboolean tvbparse_peek(tvbparse_t* tt, + const tvbparse_wanted_t* wanted); + +/* + * This will look for the wanted token at the current offset or after any given + * number of ignored tokens returning NULL if there's no match. + * if there is a match it will set the offset of the current parser after + * the end of the token + */ +tvbparse_elem_t* tvbparse_get(tvbparse_t* tt, + const tvbparse_wanted_t* wanted); + +/* + * Like tvbparse_get but this will look for a wanted token even beyond the + * current offset. + * This function is slow. + */ + +tvbparse_elem_t* tvbparse_find(tvbparse_t* tt, + const tvbparse_wanted_t* wanted); + + +void tvbparse_tree_add_elem(proto_tree* tree, tvbparse_elem_t* curr); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tvbuff.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tvbuff.h new file mode 100644 index 00000000..fc1c28f9 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tvbuff.h @@ -0,0 +1,634 @@ +/* tvbuff.h + * + * Testy, Virtual(-izable) Buffer of guint8*'s + * + * "Testy" -- the buffer gets mad when an attempt is made to access data + * beyond the bounds of the buffer. An exception is thrown. + * + * "Virtual" -- the buffer can have its own data, can use a subset of + * the data of a backing tvbuff, or can be a composite of + * other tvbuffs. + * + * $Id: tvbuff.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Copyright (c) 2000 by Gilbert Ramirez + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __TVBUFF_H__ +#define __TVBUFF_H__ + +#include +#include +#include +#include "exceptions.h" + +#ifdef NEED_G_ASCII_STRCASECMP_H +#include "g_ascii_strcasecmp.h" +#endif + +/** @file + * "testy, virtual(-izable) buffer". They are testy in that they get mad when + * an attempt is made to access data beyond the bounds of their array. In that + * case, they throw an exception. + * + * They are virtualizable in that new tvbuff's can be made from other tvbuffs, + * while only the original tvbuff may have data. That is, the new tvbuff has + * virtual data. + */ + + +/** The different types of tvbuff's */ +typedef enum { + TVBUFF_REAL_DATA, + TVBUFF_SUBSET, + TVBUFF_COMPOSITE +} tvbuff_type; + +typedef struct { + /* The backing tvbuff_t */ + struct tvbuff *tvb; + + /* The offset/length of 'tvb' to which I'm privy */ + guint offset; + guint length; + +} tvb_backing_t; + +typedef struct { + GSList *tvbs; + + /* Used for quick testing to see if this + * is the tvbuff that a COMPOSITE is + * interested in. */ + guint *start_offsets; + guint *end_offsets; + +} tvb_comp_t; + +typedef void (*tvbuff_free_cb_t)(void*); + +typedef struct tvbuff { + /* Record-keeping */ + tvbuff_type type; + gboolean initialized; + guint usage_count; + struct tvbuff *ds_tvb; /* data source top-level tvbuff */ + + /* The tvbuffs in which this tvbuff is a member + * (that is, a backing tvbuff for a TVBUFF_SUBSET + * or a member for a TVB_COMPOSITE) */ + GSList *used_in; + + /* TVBUFF_SUBSET and TVBUFF_COMPOSITE keep track + * of the other tvbuff's they use */ + union { + tvb_backing_t subset; + tvb_comp_t composite; + } tvbuffs; + + /* We're either a TVBUFF_REAL_DATA or a + * TVBUFF_SUBSET that has a backing buffer that + * has real_data != NULL, or a TVBUFF_COMPOSITE + * which has flattened its data due to a call + * to tvb_get_ptr(). + */ + const guint8 *real_data; + + /* Length of virtual buffer (and/or real_data). */ + guint length; + + /* Reported length. */ + guint reported_length; + + /* Offset from beginning of first TVBUFF_REAL. */ + gint raw_offset; + + /* Func to call when actually freed */ + tvbuff_free_cb_t free_cb; +} tvbuff_t; + + + +/** TVBUFF_REAL_DATA contains a guint8* that points to real data. + * The data is allocated and contiguous. + * + * TVBUFF_SUBSET has a backing tvbuff. The TVBUFF_SUBSET is a "window" + * through which the program sees only a portion of the backing tvbuff. + * + * TVBUFF_COMPOSITE combines multiple tvbuffs sequentually to produce + * a larger byte array. + * + * tvbuff's of any type can be used as the backing-tvbuff of a + * TVBUFF_SUBSET or as the member of a TVBUFF_COMPOSITE. + * TVBUFF_COMPOSITEs can have member-tvbuffs of different types. + * + * Once a tvbuff is create/initialized/finalized, the tvbuff is read-only. + * That is, it cannot point to any other data. A new tvbuff must be created if + * you want a tvbuff that points to other data. + */ + + +/** "class" initialization. Called once during execution of program + * so that tvbuff.c can initialize its data. */ +extern void tvbuff_init(void); + +/** "class" cleanup. Called once during execution of program + * so that tvbuff.c can clean up its data. */ +extern void tvbuff_cleanup(void); + + +/** Returns a pointer to a newly initialized tvbuff. Note that + * tvbuff's of types TVBUFF_SUBSET and TVBUFF_COMPOSITE + * require further initialization via the appropriate functions */ +extern tvbuff_t* tvb_new(tvbuff_type); + +/** Marks a tvbuff for freeing. The guint8* data of a TVBUFF_REAL_DATA + * is *never* freed by the tvbuff routines. The tvbuff itself is actually freed + * once its usage count drops to 0. + * + * Usage counts increment for any time the tvbuff is + * used as a member of another tvbuff, i.e., as the backing buffer for + * a TVBUFF_SUBSET or as a member of a TVBUFF_COMPOSITE. + * + * Although you may call tvb_free(), the tvbuff may still be in use + * by other tvbuff's (TVBUFF_SUBSET or TVBUFF_COMPOSITE), so it is not + * safe, unless you know otherwise, to free your guint8* data. If you + * cannot be sure that your TVBUFF_REAL_DATA is not in use by another + * tvbuff, register a callback with tvb_set_free_cb(); when your tvbuff + * is _really_ freed, then your callback will be called, and at that time + * you can free your original data. + * + * The caller can artificially increment/decrement the usage count + * with tvbuff_increment_usage_count()/tvbuff_decrement_usage_count(). + */ +extern void tvb_free(tvbuff_t*); + +/** Free the tvbuff_t and all tvbuff's created from it. */ +extern void tvb_free_chain(tvbuff_t*); + +/** Both return the new usage count, after the increment or decrement */ +extern guint tvb_increment_usage_count(tvbuff_t*, guint count); + +/** If a decrement causes the usage count to drop to 0, a the tvbuff + * is immediately freed. Be sure you know exactly what you're doing + * if you decide to use this function, as another tvbuff could + * still have a pointer to the just-freed tvbuff, causing corrupted data + * or a segfault in the future */ +extern guint tvb_decrement_usage_count(tvbuff_t*, guint count); + +/** Set a callback function to call when a tvbuff is actually freed + * (once the usage count drops to 0). One argument is passed to + * that callback --- a void* that points to the real data. + * Obviously, this only applies to a TVBUFF_REAL_DATA tvbuff. */ +extern void tvb_set_free_cb(tvbuff_t*, tvbuff_free_cb_t); + + +/** Attach a TVBUFF_REAL_DATA tvbuff to a parent tvbuff. This connection + * is used during a tvb_free_chain()... the "child" TVBUFF_REAL_DATA acts + * as if is part of the chain-of-creation of the parent tvbuff, although it + * isn't. This is useful if you need to take the data from some tvbuff, + * run some operation on it, like decryption or decompression, and make a new + * tvbuff from it, yet want the new tvbuff to be part of the chain. The reality + * is that the new tvbuff *is* part of the "chain of creation", but in a way + * that these tvbuff routines is ignorant of. Use this function to make + * the tvbuff routines knowledgable of this fact. */ +extern void tvb_set_child_real_data_tvbuff(tvbuff_t* parent, tvbuff_t* child); + +/**Sets parameters for TVBUFF_REAL_DATA. Can throw ReportedBoundsError. */ +extern void tvb_set_real_data(tvbuff_t*, const guint8* data, guint length, + gint reported_length); + +/** Combination of tvb_new() and tvb_set_real_data(). Can throw ReportedBoundsError. */ +extern tvbuff_t* tvb_new_real_data(const guint8* data, guint length, + gint reported_length); + + +/** Define the subset of the backing buffer to use. + * + * 'backing_offset' can be negative, to indicate bytes from + * the end of the backing buffer. + * + * 'backing_length' can be 0, although the usefulness of the buffer would + * be rather limited. + * + * 'backing_length' of -1 means "to the end of the backing buffer" + * + * Will throw BoundsError if 'backing_offset'/'length' + * is beyond the bounds of the backing tvbuff. + * Can throw ReportedBoundsError. */ +extern void tvb_set_subset(tvbuff_t* tvb, tvbuff_t* backing, + gint backing_offset, gint backing_length, gint reported_length); + +/** Combination of tvb_new() and tvb_set_subset() + * Can throw ReportedBoundsError. */ +extern tvbuff_t* tvb_new_subset(tvbuff_t* backing, + gint backing_offset, gint backing_length, gint reported_length); + + +/** Both tvb_composite_append and tvb_composite_prepend can throw + * BoundsError if member_offset/member_length goes beyond bounds of + * the 'member' tvbuff. */ + +/** Append to the list of tvbuffs that make up this composite tvbuff */ +extern void tvb_composite_append(tvbuff_t* tvb, tvbuff_t* member); + +/** Prepend to the list of tvbuffs that make up this composite tvbuff */ +extern void tvb_composite_prepend(tvbuff_t* tvb, tvbuff_t* member); + +/** Helper function that calls tvb_new(TVBUFF_COMPOSITE). + * Provided only to maintain symmetry with other constructors */ +extern tvbuff_t* tvb_new_composite(void); + +/** Mark a composite tvbuff as initialized. No further appends or prepends + * occur, data access can finally happen after this finalization. */ +extern void tvb_composite_finalize(tvbuff_t* tvb); + + +/* Get total length of buffer */ +extern guint tvb_length(tvbuff_t*); + +/** Computes bytes to end of buffer, from offset (which can be negative, + * to indicate bytes from end of buffer). Function returns -1 to + * indicate that offset is out of bounds. No exception is thrown. */ +extern gint tvb_length_remaining(tvbuff_t*, gint offset); + +/** Same as above, but throws an exception if the offset is out of bounds. */ +extern guint tvb_ensure_length_remaining(tvbuff_t*, gint offset); + +/* Checks (w/o throwing exception) that the bytes referred to by + * 'offset'/'length' actually exist in the buffer */ +extern gboolean tvb_bytes_exist(tvbuff_t*, gint offset, gint length); + +/** Checks that the bytes referred to by 'offset'/'length' actually exist + * in the buffer, and throws an exception if they aren't. */ +extern void tvb_ensure_bytes_exist(tvbuff_t *tvb, gint offset, gint length); + +/* Checks (w/o throwing exception) that offset exists in buffer */ +extern gboolean tvb_offset_exists(tvbuff_t*, gint offset); + +/* Get reported length of buffer */ +extern guint tvb_reported_length(tvbuff_t*); + +/** Computes bytes of reported packet data to end of buffer, from offset + * (which can be negative, to indicate bytes from end of buffer). Function + * returns -1 to indicate that offset is out of bounds. No exception is + * thrown. */ +extern gint tvb_reported_length_remaining(tvbuff_t *tvb, gint offset); + +/** Set the reported length of a tvbuff to a given value; used for protocols + whose headers contain an explicit length and where the calling + dissector's payload may include padding as well as the packet for + this protocol. + + Also adjusts the data length. */ +extern void tvb_set_reported_length(tvbuff_t*, guint); + +extern int offset_from_real_beginning(tvbuff_t *tvb, int counter); + +/* Returns the offset from the first byte of real data. */ +#define TVB_RAW_OFFSET(tvb) \ + ((tvb->raw_offset==-1)?(tvb->raw_offset = offset_from_real_beginning(tvb, 0)):tvb->raw_offset) + +/************** START OF ACCESSORS ****************/ +/* All accessors will throw an exception if appropriate */ + +extern guint8 tvb_get_guint8(tvbuff_t*, gint offset); + +extern guint16 tvb_get_ntohs(tvbuff_t*, gint offset); +extern guint32 tvb_get_ntoh24(tvbuff_t*, gint offset); +extern guint32 tvb_get_ntohl(tvbuff_t*, gint offset); +extern guint64 tvb_get_ntoh64(tvbuff_t*, gint offset); +extern gfloat tvb_get_ntohieee_float(tvbuff_t*, gint offset); +extern gdouble tvb_get_ntohieee_double(tvbuff_t*, gint offset); + +extern guint16 tvb_get_letohs(tvbuff_t*, gint offset); +extern guint32 tvb_get_letoh24(tvbuff_t*, gint offset); +extern guint32 tvb_get_letohl(tvbuff_t*, gint offset); +extern guint64 tvb_get_letoh64(tvbuff_t*, gint offset); +extern gfloat tvb_get_letohieee_float(tvbuff_t*, gint offset); +extern gdouble tvb_get_letohieee_double(tvbuff_t*, gint offset); + +/** + * Fetch an IPv4 address, in network byte order. + * We do *not* convert it to host byte order; we leave it in + * network byte order, as that's what its callers expect. */ +extern guint32 tvb_get_ipv4(tvbuff_t*, gint offset); + +/* Fetch an IPv6 address. */ +extern void tvb_get_ipv6(tvbuff_t*, gint offset, struct e_in6_addr *addr); + +/* Fetch a GUID. */ +extern void tvb_get_ntohguid(tvbuff_t *tvb, gint offset, e_guid_t *guid); +extern void tvb_get_letohguid(tvbuff_t *tvb, gint offset, e_guid_t *guid); +extern void tvb_get_guid(tvbuff_t *tvb, gint offset, e_guid_t *guid, gboolean little_endian); + +/* Fetch a specified number of bits from bit offset in a tvb */ +extern guint8 tvb_get_bits8(tvbuff_t *tvb, gint bit_offset, gint no_of_bits); +extern guint16 tvb_get_bits16(tvbuff_t *tvb, gint bit_offset, gint no_of_bits, gboolean little_endian); +extern guint32 tvb_get_bits32(tvbuff_t *tvb, gint bit_offset, gint no_of_bits, gboolean little_endian); +extern guint64 tvb_get_bits64(tvbuff_t *tvb, gint bit_offset, gint no_of_bits, gboolean little_endian); + +/** Returns target for convenience. Does not suffer from possible + * expense of tvb_get_ptr(), since this routine is smart enough + * to copy data in chunks if the request range actually exists in + * different TVBUFF_REAL_DATA tvbuffs. This function assumes that the + * target memory is already allocated; it does not allocate or free the + * target memory. */ +extern void* tvb_memcpy(tvbuff_t*, void* target, gint offset, gint length); + +/** It is the user's responsibility to g_free() the memory allocated by + * tvb_memdup(). Calls tvb_memcpy() */ +extern void* tvb_memdup(tvbuff_t*, gint offset, gint length); + +/* Same as above but the buffer returned from this function does not have to +* be freed. It will be automatically freed after the packet is dissected. +* Buffers allocated by this function are NOT persistent. +*/ +extern void* ep_tvb_memdup(tvbuff_t *tvb, gint offset, gint length); + +/** WARNING! This function is possibly expensive, temporarily allocating + * another copy of the packet data. Furthermore, it's dangerous because once + * this pointer is given to the user, there's no guarantee that the user will + * honor the 'length' and not overstep the boundaries of the buffer. + * + * The returned pointer is data that is internal to the tvbuff, so do not + * attempt to free it. Don't modify the data, either, because another tvbuff + * that might be using this tvbuff may have already copied that portion of + * the data (sometimes tvbuff's need to make copies of data, but that's the + * internal implementation that you need not worry about). Assume that the + * guint8* points to read-only data that the tvbuff manages. + * + * Return a pointer into our buffer if the data asked for via 'offset'/'length' + * is contiguous (which might not be the case for TVBUFF_COMPOSITE). If the + * data is not contiguous, a tvb_memdup() is called for the entire buffer + * and the pointer to the newly-contiguous data is returned. This dynamically- + * allocated memory will be freed when the tvbuff is freed, after the + * tvbuff_free_cb_t() is called, if any. */ +extern const guint8* tvb_get_ptr(tvbuff_t*, gint offset, gint length); + +/** Find first occurence of any of the needles in tvbuff, starting at offset. + * Searches at most maxlength number of bytes; if maxlength is -1, searches + * to end of tvbuff. + * Returns the offset of the found needle, or -1 if not found. + * Will not throw an exception, even if maxlength exceeds boundary of tvbuff; + * in that case, -1 will be returned if the boundary is reached before + * finding needle. */ +extern gint tvb_find_guint8(tvbuff_t*, gint offset, gint maxlength, + guint8 needle); + +/** Find first occurence of any of the needles in tvbuff, starting at offset. + * Searches at most maxlength number of bytes. Returns the offset of the + * found needle, or -1 if not found. Will not throw an exception, even if + * maxlength exceeds boundary of tvbuff; in that case, -1 will be returned if + * the boundary is reached before finding needle. */ +extern gint tvb_pbrk_guint8(tvbuff_t *, gint offset, gint maxlength, + const guint8 *needles); + +/** Find size of stringz (NUL-terminated string) by looking for terminating + * NUL. The size of the string includes the terminating NUL. + * + * If the NUL isn't found, it throws the appropriate exception. + */ +extern guint tvb_strsize(tvbuff_t *tvb, gint offset); + +/** Find length of string by looking for end of zero terminated string, up to + * 'maxlength' characters'; if 'maxlength' is -1, searches to end + * of tvbuff. + * Returns -1 if 'maxlength' reached before finding EOS. */ +extern gint tvb_strnlen(tvbuff_t*, gint offset, guint maxlength); + +/** Convert a string from Unicode to ASCII. At the moment we fake it by + * assuming all characters are ASCII )-: The len parameter is the number + * of guint16's to convert from Unicode. + * + * tvb_fake_unicode() returns a buffer allocated by g_malloc() and must + * be g_free() by the caller. + * tvb_get_ephemeral_faked_unicode() returns a buffer that does not need + * to be explicitely freed. Instead this buffer is + * automatically freed when wireshark starts dissecting + * the next packet. + */ +extern char *tvb_fake_unicode(tvbuff_t *tvb, int offset, int len, + gboolean little_endian); +extern char *tvb_get_ephemeral_faked_unicode(tvbuff_t *tvb, int offset, int len, + gboolean little_endian); + +/** + * Format the data in the tvb from offset for size ... + */ +extern gchar * tvb_format_text(tvbuff_t *tvb, gint offset, gint size); + +/** + * Like "tvb_format_text()", but for 'wsp'; don't show + * the characters as C-style escapes. + */ +extern gchar * tvb_format_text_wsp(tvbuff_t *tvb, gint offset, gint size); + +/** + * Like "tvb_format_text()", but for null-padded strings; don't show + * the null padding characters as "\000". + */ +extern gchar *tvb_format_stringzpad(tvbuff_t *tvb, gint offset, gint size); + + +/** + * Given a tvbuff, an offset, and a length, allocate a buffer big enough + * to hold a non-null-terminated string of that length at that offset, + * plus a trailing zero, copy the string into it, and return a pointer + * to the string. + * + * Throws an exception if the tvbuff ends before the string does. + * + * tvb_get_string() returns a string allocated by g_malloc() and therefore + * MUST be g_free() by the caller in order not to leak + * memory. + * + * tvb_get_ephemeral_string() returns a string that does not need to be freed, + * instead it will automatically be freed once the next + * packet is dissected. + */ +extern guint8 *tvb_get_string(tvbuff_t *tvb, gint offset, gint length); +extern guint8 *tvb_get_ephemeral_string(tvbuff_t *tvb, gint offset, gint length); + + +/** + * Given a tvbuff and an offset, with the offset assumed to refer to + * a null-terminated string, find the length of that string (and throw + * an exception if the tvbuff ends before we find the null), allocate + * a buffer big enough to hold the string, copy the string into it, + * and return a pointer to the string. Also return the length of the + * string (including the terminating null) through a pointer. + * + * tvb_get_stringz() returns a string allocated by g_malloc() and therefore + * MUST be g_free() by the caller in order not to leak + * memory. + * + * tvb_get_ephemeral_stringz() returns a string that does not need to be freed, + * instead it will automatically be freed once the next + * packet is dissected. + */ +extern guint8 *tvb_get_stringz(tvbuff_t *tvb, gint offset, gint *lengthp); +extern guint8 *tvb_get_ephemeral_stringz(tvbuff_t *tvb, gint offset, gint *lengthp); + +/** Looks for a stringz (NUL-terminated string) in tvbuff and copies + * no more than bufsize number of bytes, including terminating NUL, to buffer. + * Returns length of string (not including terminating NUL), or -1 if the string was + * truncated in the buffer due to not having reached the terminating NUL. + * In this way, it acts like g_snprintf(). + * + * When processing a packet where the remaining number of bytes is less + * than bufsize, an exception is not thrown if the end of the packet + * is reached before the NUL is found. If no NUL is found before reaching + * the end of the short packet, -1 is still returned, and the string + * is truncated with a NUL, albeit not at buffer[bufsize - 1], but + * at the correct spot, terminating the string. + */ +extern gint tvb_get_nstringz(tvbuff_t *tvb, gint offset, guint bufsize, + guint8* buffer); + +/** Like tvb_get_nstringz(), but never returns -1. The string is guaranteed to + * have a terminating NUL. If the string was truncated when copied into buffer, + * a NUL is placed at the end of buffer to terminate it. + * + * bufsize MUST be greater than 0. + */ +extern gint tvb_get_nstringz0(tvbuff_t *tvb, gint offset, guint bufsize, + guint8* buffer); + +/** + * Given a tvbuff, an offset into the tvbuff, and a length that starts + * at that offset (which may be -1 for "all the way to the end of the + * tvbuff"), find the end of the (putative) line that starts at the + * specified offset in the tvbuff, going no further than the specified + * length. + * + * Return the length of the line (not counting the line terminator at + * the end), or, if we don't find a line terminator: + * + * if "deseg" is true, return -1; + * + * if "deseg" is false, return the amount of data remaining in + * the buffer. + * + * Set "*next_offset" to the offset of the character past the line + * terminator, or past the end of the buffer if we don't find a line + * terminator. (It's not set if we return -1.) + */ +extern gint tvb_find_line_end(tvbuff_t *tvb, gint offset, int len, + gint *next_offset, gboolean desegment); + +/** + * Given a tvbuff, an offset into the tvbuff, and a length that starts + * at that offset (which may be -1 for "all the way to the end of the + * tvbuff"), find the end of the (putative) line that starts at the + * specified offset in the tvbuff, going no further than the specified + * length. + * + * However, treat quoted strings inside the buffer specially - don't + * treat newlines in quoted strings as line terminators. + * + * Return the length of the line (not counting the line terminator at + * the end), or the amount of data remaining in the buffer if we don't + * find a line terminator. + * + * Set "*next_offset" to the offset of the character past the line + * terminator, or past the end of the buffer if we don't find a line + * terminator. + */ +extern gint tvb_find_line_end_unquoted(tvbuff_t *tvb, gint offset, int len, + gint *next_offset); + +/** + * Copied from the mgcp dissector. (This function should be moved to /epan ) + * tvb_skip_wsp - Returns the position in tvb of the first non-whitespace + * character following offset or offset + maxlength -1 whichever + * is smaller. + * + * Parameters: + * tvb - The tvbuff in which we are skipping whitespace. + * offset - The offset in tvb from which we begin trying to skip whitespace. + * maxlength - The maximum distance from offset that we may try to skip + * whitespace. + * + * Returns: The position in tvb of the first non-whitespace + * character following offset or offset + maxlength -1 whichever + * is smaller. + */ + +extern gint tvb_skip_wsp(tvbuff_t* tvb, gint offset, gint maxlength); + +extern gint tvb_skip_wsp_return(tvbuff_t* tvb, gint offset); + +/** + * Call strncmp after checking if enough chars left, returning 0 if + * it returns 0 (meaning "equal") and -1 otherwise, otherwise return -1. + */ +extern gint tvb_strneql(tvbuff_t *tvb, gint offset, const gchar *str, + gint size); + +/** + * Call g_ascii_strncasecmp after checking if enough chars left, returning + * 0 if it returns 0 (meaning "equal") and -1 otherwise, otherwise return -1. + */ +extern gint tvb_strncaseeql(tvbuff_t *tvb, gint offset, const gchar *str, + gint size); + +/** + * Call memcmp after checking if enough chars left, returning 0 if + * it returns 0 (meaning "equal") and -1 otherwise, otherwise return -1. + */ +extern gint tvb_memeql(tvbuff_t *tvb, gint offset, const guint8 *str, + gint size); + +/** + * Format a bunch of data from a tvbuff as bytes, returning a pointer + * to the string with the formatted data, with "punct" as a byte + * separator. + */ +extern gchar *tvb_bytes_to_str_punct(tvbuff_t *tvb, gint offset, gint len, + gchar punct); + +/* + * Format a bunch of data from a tvbuff as bytes, returning a pointer + * to the string with the formatted data. + */ +extern gchar *tvb_bytes_to_str(tvbuff_t *tvb, gint offset, gint len); + +#define TVB_GET_DS_TVB(tvb) \ + (tvb->ds_tvb) + +/** Locate a sub-tvbuff within another tvbuff, starting at position + * 'haystack_offset'. Returns the index of the beginning of 'needle' within + * 'haystack', or -1 if 'needle' is not found. The index is relative + * to the start of 'haystack', not 'haystack_offset'. */ +extern gint tvb_find_tvb(tvbuff_t *haystack_tvb, tvbuff_t *needle_tvb, + gint haystack_offset); + +/** + * Uncompresses a zlib compressed packet inside a tvbuff at offset with + * length comprlen. Returns an uncompressed tvbuffer if uncompression + * succeeded or NULL if uncompression failed. + */ +extern tvbuff_t* tvb_uncompress(tvbuff_t *tvb, int offset, int comprlen); + +/************** END OF ACCESSORS ****************/ + +#endif /* __TVBUFF_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat-int.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat-int.h new file mode 100644 index 00000000..e875996b --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat-int.h @@ -0,0 +1,92 @@ +/* + * uat-int.h + * + * $Id: uat-int.h 3992 2008-06-10 03:13:11Z dgu $ + * + * User Accessible Tables + * Mantain an array of user accessible data strucures + * Internal interface + * + * (c) 2007, Luis E. Garcia Ontanon + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2001 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ +#ifndef _UAT_INT_H_ +#define _UAT_INT_H_ + +#include "uat.h" + +typedef struct _uat_fld_rep_t uat_fld_rep_t; +typedef struct _uat_rep_t uat_rep_t; + +typedef void (*uat_rep_fld_free_cb_t)(uat_fld_rep_t*); +typedef void (*uat_rep_free_cb_t)(uat_rep_t*); + +typedef struct _fld_data_t { + guint colnum; + uat_fld_rep_t* rep; + uat_rep_fld_free_cb_t free_rep; +} fld_data_t; + +struct _uat_t { + const char* name; + size_t record_size; + const char* filename; + gboolean from_profile; + const char* help; + const char* category; + void** user_ptr; + guint* nrows_p; + uat_copy_cb_t copy_cb; + uat_update_cb_t update_cb; + uat_free_cb_t free_cb; + + uat_field_t* fields; + guint ncols; + GArray* user_data; + gboolean changed; + uat_rep_t* rep; + uat_rep_free_cb_t free_rep; + gboolean loaded; +}; + +gchar* uat_get_actual_filename(uat_t* uat, gboolean for_writing); + +void uat_init(void); + +void uat_reset(void); + +void* uat_add_record(uat_t*, const void* orig_rec_ptr); + +void uat_swap(uat_t*, guint idx_a, guint idx_b); + +void uat_remove_record_idx(uat_t*, guint rec_idx); + +void uat_destroy(uat_t*); + +void uat_clear(uat_t*); + +gboolean uat_save(uat_t* , char** ); + +void uat_load_all(void); + +#define UAT_UPDATE(uat) do { *((uat)->user_ptr) = (void*)((uat)->user_data->data); *((uat)->nrows_p) = (uat)->user_data->len; } while(0) +#define UAT_INDEX_PTR(uat,idx) (uat->user_data->data + (uat->record_size * (idx))) +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat.h new file mode 100644 index 00000000..d6952dae --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat.h @@ -0,0 +1,486 @@ +/* + * uat.h + * + * $Id: uat.h 3992 2008-06-10 03:13:11Z dgu $ + * + * User Accessible Tables + * Mantain an array of user accessible data strucures + * + * (c) 2007, Luis E. Garcia Ontanon + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2001 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _UAT_H_ +#define _UAT_H_ + +/* + * uat mantains a dynamically allocated table accessible to the user + * via a file and/or gui tables. + * + * the file is located either in userdir(when first read or when writen) or + * in datadir for defaults (read only , it will be always written to userdir). + * + * the behaviour of the table is controlled by a series of callbacks + * the caller must provide. + * + * BEWARE that the user can change an uat at (almost) any time, + * That is pointers to records in an uat are valid only during the call + * to the function that obtains them (do not store them). + * + * UATs are meant for short tables of user data (passwords and such) there's + * no quick access, you must iterate through them each time to fetch the record + * you are looking for. Use uat_dup() or uat_se_dup() if necessary. + * + * Only users via gui or editing the file can add/remove records your code cannot. + */ + +/* obscure data type to handle an uat */ +typedef struct _uat_t uat_t; +/******************************************** + * Callbacks: + * these instruct uat on how to deal with user info and data in records + ********************************************/ + +/******** + * Callbacks for the entire table (these deal with entire records) + ********/ + +/* + * Copy CB + * used to copy a record + * optional, memcpy will be used if not given + * copy(dest,orig,len) + */ +typedef void* (*uat_copy_cb_t)(void*, const void*, unsigned); + +/* + * + * Free CB + * + * destroy a record's child data + * (do not free the container, it will be handled by uat) + * it is optional, no child data will be freed if no present + * free(record) + */ +typedef void (*uat_free_cb_t)(void*); + +/* + * Update CB + * + * to be called after all record fields has been updated + * optional, record will be updated always if not given + * update(record,&error) + */ +typedef void (*uat_update_cb_t)(void* , const char** ); + + +/******* + * Callbacks for single fields (these deal with single values) + * the caller should provide one of these for every field! + ********/ + +/* + * given an input string (ptr, len) checks if the value is OK for a field in the record. + * it will return TRUE if OK or else + * it will return FALSE and may set *error to inform the user on what's + * wrong with the given input + * optional, if not given any input is considered OK and the set cb will be called + * chk(record, ptr, len, chk_data, fld_data, &error) + */ +typedef gboolean (*uat_fld_chk_cb_t)(void*, const char*, unsigned, void*, void*, const char**); + +/* + * Set Field CB + * + * given an input string (ptr, len) sets the value of a field in the record, + * it will return TRUE if OK or else + * it will return FALSE and may set *error to inform the user on what's + * wrong with the given input + * it is mandatory + * set(record, ptr, len, set_data, fld_data) + */ +typedef void (*uat_fld_set_cb_t)(void*, const char*, unsigned, void*, void*); + +/* + * given a record returns a string representation of the field + * mandatory + * tostr(record, &out_ptr, &out_len, tostr_data, fld_data) + */ +typedef void (*uat_fld_tostr_cb_t)(void*, const char**, unsigned*, void*, void*); + +/*********** + * Text Mode + * + * used for file and dialog representation of fileds in columns, + * when the file is read it modifies the way the value is passed back to the fld_set_cb + * (see definition bellow for description) + ***********/ + +typedef enum _uat_text_mode_t { + PT_TXTMOD_NONE, + /* not used */ + + PT_TXTMOD_STRING, + /* + file: + reads: + ,"\x20\x00\x30", as " \00",3 + ,"", as "",0 + ,, as NULL,0 + writes: + ,"\x20\x30\x00\x20", for " 0\0 ",4 + ,"", for *, 0 + ,, for NULL, * + dialog: + accepts \x?? and other escapes + gets "",0 on empty string + */ + PT_TXTMOD_HEXBYTES, + /* + file: + reads: + ,A1b2C3d4, as "\001\002\003\004",4 + ,, as NULL,0 + writes: + ,, on NULL, * + ,a1b2c3d4, on "\001\002\003\004",4 + dialog: + "a1b2c3d4" as "\001\002\003\004",4 + "a1 b2:c3d4" as "\001\002\003\004",4 + "" as NULL,0 + "invalid" as NULL,3 + "a1b" as NULL, 1 + */ + PT_TXTMOD_ENUM +} uat_text_mode_t; + +/* + * Fields + * + * + */ +typedef struct _uat_field_t { + const char* name; + uat_text_mode_t mode; + + struct { + uat_fld_chk_cb_t chk; + uat_fld_set_cb_t set; + uat_fld_tostr_cb_t tostr; + } cb; + + struct { + void* chk; + void* set; + void* tostr; + } cbdata; + + void* fld_data; + + const char* desc; + struct _fld_data_t* priv; +} uat_field_t; + +#define FLDFILL NULL +#define UAT_END_FIELDS {0,PT_TXTMOD_NONE,{0,0,0},{0,0,0},0,0,FLDFILL} + + +#define UAT_CAT_GENERAL "General" +#define UAT_CAT_PORTS "Port Assignments" +#define UAT_CAT_CRYPTO "Decryption" +#define UAT_CAT_FFMT "File Formats" + +/** Create a new uat + * + * @param name The name of the table + * @param data_ptr A pointer to a null terminated array of pointers to the data + * @param default_data A pointer to a struct containing default values + * @param size The size of the structure + * @param filename The filename to be used (either in userdir or datadir) + * @param copy_cb A function that copies the data in the struct + * @param update_cb Will be called when a record is updated + * @param free_cb Will be called to destroy a struct in the dataset + * + * @return A freshly-allocated and populated uat_t struct. + */ +uat_t* uat_new(const char* name, + size_t size, + const char* filename, + gboolean from_profile, + void** data_ptr, + guint* num_items, + const char* category, + const char* help, + uat_copy_cb_t copy_cb, + uat_update_cb_t update_cb, + uat_free_cb_t free_cb, + uat_field_t* flds_array); + +/** Populate a uat using its file. + * + * @param uat_in Pointer to a uat. Must not be NULL. + * @param err Upon failure, points to an error string. + * + * @return TRUE on success, FALSE on failure. + */ +gboolean uat_load(uat_t* uat_in, char** err); + +/** Create or update a single uat entry using a string. + * + * @param uat_in Pointer to a uat. Must not be NULL. + * @param entry The string representation of the entry. Format must match + * what's written to the uat's output file. + * @param err Upon failure, points to an error string. + * + * @return TRUE on success, FALSE on failure. + */ +gboolean uat_load_str(uat_t* uat_in, char* entry, char** err); + +/** Given a uat name or filename, find its pointer. + * + * @param name The name or filename of the uat + * + * @return A pointer to the uat on success, NULL on failure. + */ +uat_t *uat_find(gchar *name); + +/* + * uat_dup() + * uat_se_dup() + * make a reliable copy of an uat for internal use, + * so that pointers to records can be kept through calls. + * return NULL on zero len. + */ +void* uat_dup(uat_t*, guint* len_p); /* to be freed */ +void* uat_se_dup(uat_t*, guint* len_p); +uat_t* uat_get_table_by_name(const char* name); + +/* + * Some common uat_fld_chk_cbs + */ +gboolean uat_fld_chk_str(void*, const char*, unsigned, void*,void*, const char** err); +gboolean uat_fld_chk_proto(void*, const char*, unsigned, void*,void*, const char** err); +gboolean uat_fld_chk_num_dec(void*, const char*, unsigned, void*, void*, const char** err); +gboolean uat_fld_chk_num_hex(void*, const char*, unsigned, void*, void*, const char** err); +gboolean uat_fld_chk_enum(void*, const char*, unsigned, void*, void*, const char**); +gboolean uat_fld_chk_range(void*, const char*, unsigned, void*, void*, const char**); + +#define CHK_STR_IS_DECL(what) \ +gboolean uat_fld_chk_str_ ## what (void*, const char*, unsigned, void*, void*, const char**) + +typedef void (*uat_cb_t)(void* uat,void* user_data); +void uat_foreach_table(uat_cb_t cb,void* user_data); +void uat_unload_all(void); + +char* uat_undquote(const char* si, guint in_len, guint* len_p); +char* uat_unbinstring(const char* si, guint in_len, guint* len_p); +char* uat_unesc(const char* si, guint in_len, guint* len_p); +char* uat_esc(const char* buf, guint len); + +/* Some strings entirely made of ... already declared */ +CHK_STR_IS_DECL(isprint); +CHK_STR_IS_DECL(isalpha); +CHK_STR_IS_DECL(isalnum); +CHK_STR_IS_DECL(isdigit); +CHK_STR_IS_DECL(isxdigit); + +#define CHK_STR_IS_DEF(what) \ +gboolean uat_fld_chk_str_ ## what (void* u1 _U_, const char* strptr, unsigned len, void* u2 _U_, void* u3 _U_, const char** err) { \ + guint i; for (i=0;i(field_name)) + */ +#define UAT_CSTRING_CB_DEF(basename,field_name,rec_t) \ +static void basename ## _ ## field_name ## _set_cb(void* rec, const char* buf, unsigned len, void* u1 _U_, void* u2 _U_) {\ + if ((((rec_t*)rec)->field_name)) g_free((((rec_t*)rec)->field_name)); \ + (((rec_t*)rec)->field_name) = g_strndup(buf,len); } \ +static void basename ## _ ## field_name ## _tostr_cb(void* rec, const char** out_ptr, unsigned* out_len, void* u1 _U_, void* u2 _U_) {\ + if (((rec_t*)rec)->field_name ) { \ + *out_ptr = (((rec_t*)rec)->field_name); *out_len = strlen((((rec_t*)rec)->field_name)); \ + } else { \ + *out_ptr = ""; *out_len = 0; } } + +#define UAT_FLD_CSTRING(basename,field_name,desc) \ + {#field_name, PT_TXTMOD_STRING,{uat_fld_chk_str,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{0,0,0},0,desc,FLDFILL} + +#define UAT_FLD_CSTRING_ISPRINT(basename,field_name,desc) \ + {#field_name, PT_TXTMOD_STRING,{uat_fld_chk_str_isprint,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{0,0,0},0,desc,FLDFILL} + +#define UAT_FLD_CSTRING_OTHER(basename,field_name,chk,desc) \ + {#field_name, PT_TXTMOD_STRING,{ chk ,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{0,0,0},0,desc,FLDFILL} + +/* + * LSTRING MACROS + */ +#define UAT_LSTRING_CB_DEF(basename,field_name,rec_t,ptr_element,len_element) \ +static void basename ## _ ## field_name ## _set_cb(void* rec, const char* buf, unsigned len, void* u1 _U_, void* u2 _U_) {\ + if ((((rec_t*)rec)->ptr_element)) g_free((((rec_t*)rec)->ptr_element)); \ + (((rec_t*)rec)->ptr_element) = uat_unesc(buf,len,&(((rec_t*)rec)->len_element)); }\ +static void basename ## _ ## field_name ## _tostr_cb(void* rec, const char** out_ptr, unsigned* out_len, void* u1 _U_, void* u2 _U_) {\ + if (((rec_t*)rec)->ptr_element ) { \ + *out_ptr = uat_esc(((rec_t*)rec)->ptr_element, (((rec_t*)rec)->len_element)); \ + *out_len = strlen(*out_ptr); \ + } else { \ + *out_ptr = ""; *out_len = 0; } } + +#define UAT_FLD_LSTRING(basename,field_name,desc) \ +{#field_name, PT_TXTMOD_STRING,{0,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{0,0,0},0,desc,FLDFILL} + + +/* + * BUFFER macros, + * a buffer_ptr contained in (((rec_t*)rec)->(field_name)) + * and its len in (((rec_t*)rec)->(len_name)) + * XXX: UNTESTED + */ +#define UAT_BUFFER_CB_DEF(basename,field_name,rec_t,ptr_element,len_element) \ +static void basename ## _ ## field_name ## _set_cb(void* rec, const char* buf, unsigned len, void* u1 _U_, void* u2 _U_) {\ + if ((((rec_t*)rec)->ptr_element) ) g_free((((rec_t*)rec)->ptr_element)); \ + (((rec_t*)rec)->ptr_element) = len ? g_memdup(buf,len) : NULL; \ + (((rec_t*)rec)->len_element) = len; } \ +static void basename ## _ ## field_name ## _tostr_cb(void* rec, const char** out_ptr, unsigned* out_len, void* u1 _U_, void* u2 _U_) {\ + *out_ptr = ((rec_t*)rec)->ptr_element ? ep_memdup(((rec_t*)rec)->ptr_element,((rec_t*)rec)->len_element) : ""; \ + *out_len = ((rec_t*)rec)->len_element; } + +#define UAT_FLD_BUFFER(basename,field_name,desc) \ + {#field_name, PT_TXTMOD_HEXBYTES,{0,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{0,0,0},0,desc,FLDFILL} + + +/* + * DEC Macros, + * a decimal number contained in + */ +#define UAT_DEC_CB_DEF(basename,field_name,rec_t) \ +static void basename ## _ ## field_name ## _set_cb(void* rec, const char* buf, unsigned len, void* u1 _U_, void* u2 _U_) {\ + ((rec_t*)rec)->field_name = strtol(ep_strndup(buf,len),NULL,10); } \ +static void basename ## _ ## field_name ## _tostr_cb(void* rec, const char** out_ptr, unsigned* out_len, void* u1 _U_, void* u2 _U_) {\ + *out_ptr = ep_strdup_printf("%d",((rec_t*)rec)->field_name); \ + *out_len = strlen(*out_ptr); } + +#define UAT_FLD_DEC(basename,field_name,desc) \ + {#field_name, PT_TXTMOD_STRING,{uat_fld_chk_num_dec,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{0,0,0},0,desc,FLDFILL} + + +/* + * HEX Macros, + * an hexadecimal number contained in + */ +#define UAT_HEX_CB_DEF(basename,field_name,rec_t) \ +static void basename ## _ ## field_name ## _set_cb(void* rec, const char* buf, unsigned len, void* u1 _U_, void* u2 _U_) {\ + ((rec_t*)rec)->field_name = strtol(ep_strndup(buf,len),NULL,16); } \ +static void basename ## _ ## field_name ## _tostr_cb(void* rec, const char** out_ptr, unsigned* out_len, void* u1 _U_, void* u2 _U_) {\ + *out_ptr = ep_strdup_printf("%x",((rec_t*)rec)->field_name); \ + *out_len = strlen(*out_ptr); } + +#define UAT_FLD_HEX(basename,field_name,desc) \ +{#field_name, PT_TXTMOD_STRING,{uat_fld_chk_num_hex,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{0,0,0},0,desc,FLDFILL} + + +/* + * ENUM macros + * enum_t: name = ((enum_t*)ptr)->strptr + * value = ((enum_t*)ptr)->value + * rec_t: + * value + */ +#define UAT_VS_DEF(basename,field_name,rec_t,default_val,default_str) \ +static void basename ## _ ## field_name ## _set_cb(void* rec, const char* buf, unsigned len, void* vs, void* u2 _U_) {\ + guint i; \ + char* str = ep_strndup(buf,len); \ + const char* cstr; ((rec_t*)rec)->field_name = default_val; \ + for(i=0; ( cstr = ((value_string*)vs)[i].strptr ) ;i++) { \ + if (g_str_equal(cstr,str)) { \ + ((rec_t*)rec)->field_name = ((value_string*)vs)[i].value; return; } } } \ +static void basename ## _ ## field_name ## _tostr_cb(void* rec, const char** out_ptr, unsigned* out_len, void* vs, void* u2 _U_) {\ + guint i; \ + *out_ptr = ep_strdup(default_str); *out_len = strlen(default_str);\ + for(i=0;((value_string*)vs)[i].strptr;i++) { \ + if ( ((value_string*)vs)[i].value == ((rec_t*)rec)->field_name ) { \ + *out_ptr = ep_strdup(((value_string*)vs)[i].strptr); \ + *out_len = strlen(*out_ptr); return; } } } + + +#define UAT_FLD_VS(basename,field_name,enum,desc) \ + {#field_name, PT_TXTMOD_ENUM,{uat_fld_chk_enum,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{&(enum),&(enum),&(enum)},&(enum),desc,FLDFILL} + + +/* + * PROTO macros + */ + +#define UAT_PROTO_DEF(basename, field_name, dissector_field, name_field, rec_t) \ +static void basename ## _ ## field_name ## _set_cb(void* rec, const char* buf, unsigned len, void* u1 _U_, void* u2 _U_) {\ + if (len) { \ + ((rec_t*)rec)->name_field = ep_strndup(buf,len); g_strdown(((rec_t*)rec)->name_field ); g_strchug(((rec_t*)rec)->name_field); \ + ((rec_t*)rec)->dissector_field = find_dissector(((rec_t*)rec)->name_field); \ + } else { \ + ((rec_t*)rec)->dissector_field = find_dissector("data"); \ + ((rec_t*)rec)->name_field = NULL; \ + } } \ +static void basename ## _ ## field_name ## _tostr_cb(void* rec, const char** out_ptr, unsigned* out_len, void* u1 _U_, void* u2 _U_) {\ + if ( ((rec_t*)rec)->name_field ) { \ + *out_ptr = (((rec_t*)rec)->name_field); \ + *out_len = strlen(*out_ptr); \ + } else { \ + *out_ptr = ""; *out_len = 0; } } + + +#define UAT_FLD_PROTO(basename,field_name,desc) \ + {#field_name, PT_TXTMOD_STRING,{uat_fld_chk_proto,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{0,0,0},0,desc,FLDFILL} + +/* + * RANGE macros + */ + +#define UAT_RANGE_CB_DEF(basename,field_name,rec_t) \ +static void basename ## _ ## field_name ## _set_cb(void* rec, const char* buf, unsigned len, void* u1 _U_, void* u2) {\ + char* rng = ep_strndup(buf,len);\ + range_convert_str(&(((rec_t*)rec)->field_name), rng,GPOINTER_TO_UINT(u2)); \ + } \ +static void basename ## _ ## field_name ## _tostr_cb(void* rec, const char** out_ptr, unsigned* out_len, void* u1 _U_, void* u2 _U_) {\ + if ( ((rec_t*)rec)->field_name ) { \ + *out_ptr = range_convert_range(((rec_t*)rec)->field_name); *out_len = strlen(*out_ptr); \ + } else { \ + *out_ptr = ""; *out_len = 0; } } + + +#define UAT_FLD_RANGE(basename,field_name,max,desc) \ + {#field_name, PT_TXTMOD_STRING,{uat_fld_chk_range,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},\ + {GUINT_TO_POINTER(max),GUINT_TO_POINTER(max),GUINT_TO_POINTER(max)},0,desc,FLDFILL} + + + + + +#endif + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat_load_lex.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat_load_lex.h new file mode 100644 index 00000000..a8d694b1 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat_load_lex.h @@ -0,0 +1,6 @@ +/* This is generated by runlex.sh. Do not edit it. */ +#define yylex uat_load_lex +#ifndef YY_DECL +#define YY_DECL int yylex(void) +#endif +YY_DECL; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/unicode-utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/unicode-utils.h new file mode 100644 index 00000000..b3962ae6 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/unicode-utils.h @@ -0,0 +1,54 @@ +/* unicode-utils.h + * Unicode utility definitions + * + * $Id: unicode-utils.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 2006 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __UNICODEUTIL_H__ +#define __UNICODEUTIL_H__ + +#ifdef _WIN32 + +/** + * @file Unicode convenience routines. + */ + +/** Given a UTF-8 string, convert it to UTF-16. This is meant to be used + * to convert between GTK+ 2.x (UTF-8) to Windows (UTF-16). + * + * @param utf8str The string to convert. May be NULL. + * @return The string converted to UTF-16. If utf8str is NULL, returns + * NULL. The return value should NOT be freed by the caller. + */ +wchar_t * utf_8to16(const char *utf8str); + +/** Given a UTF-16 string, convert it to UTF-8. This is meant to be used + * to convert between GTK+ 2.x (UTF-8) to Windows (UTF-16). + * + * @param utf16str The string to convert. May be NULL. + * @return The string converted to UTF-8. If utf16str is NULL, returns + * NULL. The return value should NOT be freed by the caller. + */ +gchar * utf_16to8(const wchar_t *utf16str); + +#endif /* _WIN32 */ + +#endif /* __UNICODEUTIL_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/value_string.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/value_string.h new file mode 100644 index 00000000..86a2f1e6 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/value_string.h @@ -0,0 +1,88 @@ +/* value_string.h + * Definitions for value_string structures and routines + * + * $Id: value_string.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __VALUE_STRING_H__ +#define __VALUE_STRING_H__ + +#include + +/* Struct for the val_to_str, match_strval_idx, and match_strval functions */ + +typedef struct _value_string { + guint32 value; + const gchar *strptr; +} value_string; + +/* Struct for the rval_to_str, match_strrval_idx, and match_strrval functions */ +typedef struct _range_string { + guint32 value_min; + guint32 value_max; + const gchar *strptr; +} range_string; + +/* #define VS_DEF(x) { x, #x } */ +/* #define VS_END { 0, NULL } */ + +/* Tries to match val against each element in the value_string array vs. + Returns the associated string ptr, and sets "*idx" to the index in + that table, on a match, and returns NULL, and sets "*idx" to -1, + on failure. */ +extern const gchar* match_strval_idx(guint32 val, const value_string *vs, gint *idx); + +/* Like match_strval_idx(), but doesn't return the index. */ +extern const gchar* match_strval(guint32 val, const value_string *vs); + +/* Tries to match val against each element in the value_string array vs. + Returns the associated string ptr on a match. + Formats val with fmt, and returns the resulting string, on failure. */ +extern const gchar* val_to_str(guint32 val, const value_string *vs, const char *fmt); + +/* Generate a string describing an enumerated bitfield (an N-bit field + with various specific values having particular names). */ +extern const char *decode_enumerated_bitfield(guint32 val, guint32 mask, + int width, const value_string *tab, const char *fmt); + +/* Generate a string describing an enumerated bitfield (an N-bit field + with various specific values having particular names). */ +extern const char *decode_enumerated_bitfield_shifted(guint32 val, guint32 mask, + int width, const value_string *tab, const char *fmt); + + +/* ranges aware versions */ + +/* Tries to match val against each range in the range_string array rs. + Returns the associated string ptr on a match. + Formats val with fmt, and returns the resulting string, on failure. */ +extern const gchar* rval_to_str(guint32 val, const range_string *rs, const char *fmt); + +/* Tries to match val against each range in the range_string array rs. + Returns the associated string ptr, and sets "*idx" to the index in + that table, on a match, and returns NULL, and sets "*idx" to -1, + on failure. */ +extern const gchar *match_strrval_idx(guint32 val, const range_string *rs, gint *idx); + +/* Like match_strrval_idx(), but doesn't return the index. */ +extern const gchar *match_strrval(guint32 val, const range_string *rs); + +#endif /* __VALUE_STRING_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ws_strsplit.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ws_strsplit.h new file mode 100644 index 00000000..b2108c79 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ws_strsplit.h @@ -0,0 +1,41 @@ +/* ws_strsplit.h + * String Split utility function + * Code borrowed from GTK2 to override the GTK1 version of g_strsplit, which is + * known to be buggy. + * + * $Id: ws_strsplit.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __WS_STRSPLIT_H__ +#define __WS_STRSPLIT_H__ + +#if GLIB_MAJOR_VERSION < 2 + +#define g_strsplit(s, d, t) ws_strsplit(s, d, t) + +gchar ** ws_strsplit (const gchar *string, + const gchar *delimiter, + gint max_tokens); + +#endif /* GLIB_MAJOR_VERSION */ + +#endif /* __WS_STRSPLIT_H__ */ + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/wslua/declare_wslua.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/wslua/declare_wslua.h new file mode 100644 index 00000000..d403ce65 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/wslua/declare_wslua.h @@ -0,0 +1,59 @@ +/* This file is automatically genrated by make-reg.pl do not edit */ + +#define WSLUA_DECLARE_CLASSES() \ + WSLUA_CLASS_DECLARE(ByteArray);\ + WSLUA_CLASS_DECLARE(Tvb);\ + WSLUA_CLASS_DECLARE(TvbRange);\ + WSLUA_CLASS_DECLARE(Pref);\ + WSLUA_CLASS_DECLARE(Prefs);\ + WSLUA_CLASS_DECLARE(ProtoField);\ + WSLUA_CLASS_DECLARE(Proto);\ + WSLUA_CLASS_DECLARE(Dissector);\ + WSLUA_CLASS_DECLARE(DissectorTable);\ + WSLUA_CLASS_DECLARE(TreeItem);\ + WSLUA_CLASS_DECLARE(Address);\ + WSLUA_CLASS_DECLARE(Column);\ + WSLUA_CLASS_DECLARE(Columns);\ + WSLUA_CLASS_DECLARE(Pinfo);\ + WSLUA_CLASS_DECLARE(Listener);\ + WSLUA_CLASS_DECLARE(TextWindow);\ + WSLUA_CLASS_DECLARE(Dir);\ + WSLUA_CLASS_DECLARE(FieldInfo);\ + WSLUA_CLASS_DECLARE(Field);\ + WSLUA_CLASS_DECLARE(PseudoHeader);\ + WSLUA_CLASS_DECLARE(Dumper);\ + + +#define WSLUA_DECLARE_FUNCTIONS() \ + WSLUA_FUNCTION wslua_register_postdissector(lua_State* L);\ + WSLUA_FUNCTION wslua_gui_enabled(lua_State* L);\ + WSLUA_FUNCTION wslua_register_menu(lua_State* L);\ + WSLUA_FUNCTION wslua_new_dialog(lua_State* L);\ + WSLUA_FUNCTION wslua_retap_packets(lua_State* L);\ + WSLUA_FUNCTION wslua_copy_to_clipboard(lua_State* L);\ + WSLUA_FUNCTION wslua_open_capture_file(lua_State* L);\ + WSLUA_FUNCTION wslua_set_filter(lua_State* L);\ + WSLUA_FUNCTION wslua_apply_filter(lua_State* L);\ + WSLUA_FUNCTION wslua_reload(lua_State* L);\ + WSLUA_FUNCTION wslua_browser_open_url(lua_State* L);\ + WSLUA_FUNCTION wslua_browser_open_data_file(lua_State* L);\ + WSLUA_FUNCTION wslua_format_date(lua_State* L);\ + WSLUA_FUNCTION wslua_format_time(lua_State* L);\ + WSLUA_FUNCTION wslua_report_failure(lua_State* L);\ + WSLUA_FUNCTION wslua_critical(lua_State* L);\ + WSLUA_FUNCTION wslua_warn(lua_State* L);\ + WSLUA_FUNCTION wslua_message(lua_State* L);\ + WSLUA_FUNCTION wslua_info(lua_State* L);\ + WSLUA_FUNCTION wslua_debug(lua_State* L);\ + WSLUA_FUNCTION wslua_loadfile(lua_State* L);\ + WSLUA_FUNCTION wslua_dofile(lua_State* L);\ + WSLUA_FUNCTION wslua_persconffile_path(lua_State* L);\ + WSLUA_FUNCTION wslua_datafile_path(lua_State* L);\ + WSLUA_FUNCTION wslua_register_stat_cmd_arg(lua_State* L);\ + WSLUA_FUNCTION wslua_all_field_infos(lua_State* L);\ + + +extern void wslua_register_classes(lua_State* L); +extern void wslua_register_functions(lua_State* L); + + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/wslua/wslua.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/wslua/wslua.h new file mode 100644 index 00000000..a58fba23 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/wslua/wslua.h @@ -0,0 +1,372 @@ +/* + * wslua.h + * + * Wireshark's interface to the Lua Programming Language + * + * (c) 2006, Luis E. Garcia Ontanon + * (c) 2007, Tamas Regos + * + * $Id: wslua.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _PACKET_LUA_H +#define _PACKET_LUA_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if GLIB_MAJOR_VERSION < 2 +#include +#endif + +#include "declare_wslua.h" + +#define WSLUA_INIT_ROUTINES "init_routines" +#define LOG_DOMAIN_LUA "wslua" + +struct _wslua_tvbrange { + tvbuff_t* tvb; + int offset; + int len; +}; + +typedef struct _wslua_field_t { + int hfid; + int ett; + char* name; + char* abbr; + char* blob; + enum ftenum type; + base_display_e base; + value_string* vs; + guint32 mask; +} wslua_field_t; + +/* + * PREF_OBSOLETE is used for preferences that a module used to support + * but no longer supports; we give different error messages for them. + */ +typedef enum { + PREF_UINT, + PREF_BOOL, + PREF_ENUM, + PREF_STRING, + PREF_RANGE, + PREF_STATIC_TEXT, + PREF_OBSOLETE +} pref_type_t; + +typedef struct _wslua_pref_t { + gchar* name; + gchar* label; + gchar* desc; + pref_type_t type; + union { + gboolean b; + guint u; + const gchar* s; + gint e; + range_t *r; + void* p; + } value; + union { + guint32 max_value; /* maximum value of a range */ + struct { + const enum_val_t *enumvals; /* list of name & values */ + gboolean radio_buttons; /* TRUE if it should be shown as + radio buttons rather than as an + option menu or combo box in + the preferences tab */ + } enum_info; /* for PREF_ENUM */ + } info; /* display/text file information */ + + struct _wslua_pref_t* next; + struct _wslua_proto_t* proto; +} wslua_pref_t; + +typedef struct _wslua_proto_t { + gchar* name; + gchar* desc; + int hfid; + int ett; + wslua_pref_t prefs; + int fields; + module_t *prefs_module; + dissector_handle_t handle; + gboolean is_postdissector; +} wslua_proto_t; + +struct _wslua_distbl_t { + dissector_table_t table; + gchar* name; +}; + +struct _wslua_col_info { + column_info* cinfo; + gint col; +}; + +struct _wslua_treeitem { + proto_item* item; + proto_tree* tree; +}; + +typedef void (*tap_extractor_t)(lua_State*,const void*); + +struct _wslua_tap { + gchar* name; + gchar* filter; + tap_extractor_t extractor; + lua_State* L; + int packet_ref; + int draw_ref; + int init_ref; +}; + +#if GLIB_MAJOR_VERSION < 2 +# define DIRECTORY_T DIR +# define FILE_T struct dirent +# define OPENDIR_OP(name) opendir(name) +# define DIRGETNEXT_OP(dir) readdir(dir) +# define GETFNAME_OP(file) (gchar *)file->d_name +# define CLOSEDIR_OP(dir) closedir(dir) +#else /* GLIB 2 */ +# define DIRECTORY_T GDir +# define FILE_T gchar +# define OPENDIR_OP(name) g_dir_open(name, 0, dir->dummy) +# define DIRGETNEXT_OP(dir) g_dir_read_name(dir) +# define GETFNAME_OP(file) (file); +# define CLOSEDIR_OP(dir) g_dir_close(dir) +#endif + +struct _wslua_dir { + DIRECTORY_T* dir; + char* ext; +#if GLIB_MAJOR_VERSION >= 2 + GError** dummy; +#endif + +}; + +typedef struct { const char* name; tap_extractor_t extractor; } tappable_t; + +typedef struct {const gchar* str; enum ftenum id; } wslua_ft_types_t; + +typedef wslua_pref_t* Pref; +typedef wslua_pref_t* Prefs; +typedef struct _wslua_field_t* ProtoField; +typedef struct _wslua_proto_t* Proto; +typedef struct _wslua_distbl_t* DissectorTable; +typedef dissector_handle_t Dissector; +typedef GByteArray* ByteArray; +typedef tvbuff_t* Tvb; +typedef struct _wslua_tvbrange* TvbRange; +typedef struct _wslua_col_info* Column; +typedef column_info* Columns; +typedef packet_info* Pinfo; +typedef struct _wslua_treeitem* TreeItem; +typedef address* Address; +typedef header_field_info** Field; +typedef field_info* FieldInfo; +typedef struct _wslua_tap* Listener; +typedef funnel_text_window_t* TextWindow; +typedef wtap_dumper* Dumper; +typedef struct lua_pseudo_header* PseudoHeader; +typedef tvbparse_t* Parser; +typedef tvbparse_wanted_t* Rule; +typedef tvbparse_elem_t* Node; +typedef tvbparse_action_t* Shortcut; +typedef struct _wslua_main* WireShark; +typedef struct _wslua_dir* Dir; + +/* + * toXxx(L,idx) gets a Xxx from an index (Lua Error if fails) + * checkXxx(L,idx) gets a Xxx from an index after calling check_code (No Lua Error if it fails) + * pushXxx(L,xxx) pushes an Xxx into the stack + * isXxx(L,idx) tests whether we have an Xxx at idx + * + * LUA_CLASS_DEFINE must be used without trailing ';' + */ +#define WSLUA_CLASS_DEFINE(C,check_code,push_code) \ +C to##C(lua_State* L, int index) { \ + C* v = (C*)lua_touserdata (L, index); \ + if (!v) luaL_typerror(L,index,#C); \ + return *v; \ +} \ +C check##C(lua_State* L, int index) { \ + C* p; \ + luaL_checktype(L,index,LUA_TUSERDATA); \ + p = (C*)luaL_checkudata(L, index, #C); \ + check_code; \ + return p ? *p : NULL; \ +} \ +C* push##C(lua_State* L, C v) { \ + C* p = lua_newuserdata(L,sizeof(C)); *p = v; \ + luaL_getmetatable(L, #C); lua_setmetatable(L, -2); \ + push_code; \ + return p; \ +}\ +gboolean is##C(lua_State* L,int i) { \ + void *p; \ + if(!lua_isuserdata(L,i)) return FALSE; \ + p = lua_touserdata(L, i); \ + lua_getfield(L, LUA_REGISTRYINDEX, #C); \ + if (p == NULL || !lua_getmetatable(L, i) || !lua_rawequal(L, -1, -2)) p=NULL; \ + lua_pop(L, 2); \ + return p ? TRUE : FALSE; \ +} \ +C shift##C(lua_State* L,int i) { \ + C* p; \ + if(!lua_isuserdata(L,i)) return NULL; \ + p = lua_touserdata(L, i); \ + lua_getfield(L, LUA_REGISTRYINDEX, #C); \ + if (p == NULL || !lua_getmetatable(L, i) || !lua_rawequal(L, -1, -2)) p=NULL; \ + lua_pop(L, 2); \ + if (p) { lua_remove(L,i); return *p; }\ + else return NULL;\ +} \ +int dummy##C + +#ifdef HAVE_LUA_5_1 + +#define WSLUA_REGISTER_CLASS(C) { \ + luaL_register (L, #C, C ## _methods); \ + luaL_newmetatable (L, #C); \ + luaL_register (L, NULL, C ## _meta); \ + lua_pushliteral(L, "__index"); \ + lua_pushvalue(L, -3); \ + lua_rawset(L, -3); \ + lua_pushliteral(L, "__metatable"); \ + lua_pushvalue(L, -3); \ + lua_rawset(L, -3); \ + lua_pop(L, 1); \ +} + +#define WSLUA_REGISTER_META(C) luaL_newmetatable (L, #C); luaL_register (L, NULL, C ## _meta); + +#define WSLUA_INIT(L) \ + luaL_openlibs(L); \ + wslua_register_classes(L); \ + wslua_register_functions(L); + + +#endif + +#define WSLUA_FUNCTION extern int +#define WSLUA_REGISTER_FUNCTION(name) { lua_pushstring(L, #name); lua_pushcfunction(L, wslua_## name); lua_settable(L, LUA_GLOBALSINDEX); } +#define WSLUA_REGISTER extern int + +#define WSLUA_METHOD static int +#define WSLUA_CONSTRUCTOR static int +#define WSLUA_ATTR_SET static int +#define WSLUA_ATTR_GET static int +#define WSLUA_METAMETHOD static int + +#define WSLUA_METHODS static const luaL_reg +#define WSLUA_META static const luaL_reg +#define WSLUA_CLASS_FNREG(class,name) { #name, class##_##name } + +#define WSLUA_ERROR(name,error) { luaL_error(L, ep_strdup_printf("%s%s", #name ": " ,error) ); return 0; } +#define WSLUA_ARG_ERROR(name,attr,error) { luaL_argerror(L,WSLUA_ARG_ ## name ## _ ## attr, #name ": " error); return 0; } +#define WSLUA_OPTARG_ERROR(name,attr,error) { luaL_argerror(L,WSLUA_OPTARG_##name##_ ##attr, #name ": " error); return 0; } + +#define WSLUA_REG_GLOBAL_BOOL(L,n,v) { lua_pushstring(L,n); lua_pushboolean(L,v); lua_settable(L, LUA_GLOBALSINDEX); } +#define WSLUA_REG_GLOBAL_STRING(n,v) { lua_pushstring(L,n); lua_pushstring(L,v); lua_settable(L, LUA_GLOBALSINDEX); } +#define WSLUA_REG_GLOBAL_NUMBER(n,v) { lua_pushstring(L,n); lua_pushnumber(L,v); lua_settable(L, LUA_GLOBALSINDEX); } + +#define WSLUA_RETURN(i) return (i); + +#define WSLUA_API extern + +#define NOP +#define FAIL_ON_NULL(s) if (! *p) luaL_argerror(L,index,s) + + + +#define WSLUA_CLASS_DECLARE(C) \ +extern C to##C(lua_State* L, int index); \ +extern C check##C(lua_State* L, int index); \ +extern C* push##C(lua_State* L, C v); \ +extern int C##_register(lua_State* L); \ +extern gboolean is##C(lua_State* L,int i); \ +extern C shift##C(lua_State* L,int i) + + +extern packet_info* lua_pinfo; +extern TreeItem lua_tree; +extern tvbuff_t* lua_tvb; +extern int lua_malformed; +extern dissector_handle_t lua_data_handle; +extern gboolean lua_initialized; +extern int lua_dissectors_table_ref; + +WSLUA_DECLARE_CLASSES() +WSLUA_DECLARE_FUNCTIONS() + +extern lua_State* wslua_state(void); + +extern gboolean wslua_optbool(lua_State* L, int n, gboolean def); +extern const gchar* lua_shiftstring(lua_State* L,int idx); +extern int dissect_lua(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree); + +extern void proto_register_lua(void); +extern GString* lua_register_all_taps(void); +extern void lua_prime_all_fields(proto_tree* tree); + +extern int Proto_commit(lua_State* L); + +extern void* push_Tvb(lua_State* L, Tvb tvb); +extern void clear_outstanding_tvbs(void); + +extern void* push_Pinfo(lua_State* L, Pinfo p); +extern void clear_outstanding_pinfos(void); + +extern void* push_TreeItem(lua_State* L, TreeItem ti); +extern void clear_outstanding_trees(void); + +extern void wslua_print_stack(char* s, lua_State* L); + +extern int wslua_init(lua_State* L); + +extern tap_extractor_t wslua_get_tap_extractor(const gchar* name); +extern int wslua_set_tap_enums(lua_State* L); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/x264_prt_id.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/x264_prt_id.h new file mode 100644 index 00000000..7be6bc0b --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/x264_prt_id.h @@ -0,0 +1,35 @@ +/* x264_prt_id.h + * Definitions of X.264/ISO 11570 transport protocol IDs + * + * $Id: x264_prt_id.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __X264_PRT_ID_H__ +#define __X264_PRT_ID_H__ + +/* X.264 / ISO 11570 transport protocol ID values. */ + +#define PRT_ID_ISO_8073 0x01 /* X.224/ISO 8073 COTP */ +#define PRT_ID_ISO_8602 0x02 /* X.234/ISO 8602 CLTP */ +#define PRT_ID_ISO_10736_ISO_8073 0x03 /* X.274/ISO 10736 + X.224/ISO 8073 */ +#define PRT_ID_ISO_10736_ISO_8602 0x04 /* X.274/ISO 10736 + X.234/ISO 8602 */ + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/xdlc.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/xdlc.h new file mode 100644 index 00000000..b9265f7e --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/xdlc.h @@ -0,0 +1,140 @@ +/* xdlc.h + * Define *DLC frame types, and routine to dissect the control field of + * a *DLC frame. + * + * $Id: xdlc.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __XDLC_H__ +#define __XDLC_H__ + +/* + * Low-order bits of first (extended) or only (basic) octet of control + * field, specifying the frame type. + */ +#define XDLC_I_MASK 0x01 /* Mask to test for I or not I */ +#define XDLC_I 0x00 /* Information frames */ +#define XDLC_S_U_MASK 0x03 /* Mask to test for S or U */ +#define XDLC_S 0x01 /* Supervisory frames */ +#define XDLC_U 0x03 /* Unnumbered frames */ + +/* + * N(S) and N(R) fields, in basic and extended operation. + */ +#define XDLC_N_R_MASK 0xE0 /* basic */ +#define XDLC_N_R_SHIFT 5 +#define XDLC_N_R_EXT_MASK 0xFE00 /* extended */ +#define XDLC_N_R_EXT_SHIFT 9 +#define XDLC_N_S_MASK 0x0E /* basic */ +#define XDLC_N_S_SHIFT 1 +#define XDLC_N_S_EXT_MASK 0x00FE /* extended */ +#define XDLC_N_S_EXT_SHIFT 1 + +/* + * Poll/Final bit, in basic and extended operation. + */ +#define XDLC_P_F 0x10 /* basic */ +#define XDLC_P_F_EXT 0x0100 /* extended */ + +/* + * S-format frame types. + */ +#define XDLC_S_FTYPE_MASK 0x0C +#define XDLC_RR 0x00 /* Receiver ready */ +#define XDLC_RNR 0x04 /* Receiver not ready */ +#define XDLC_REJ 0x08 /* Reject */ +#define XDLC_SREJ 0x0C /* Selective reject */ + +/* + * U-format modifiers. + */ +#define XDLC_U_MODIFIER_MASK 0xEC +#define XDLC_UI 0x00 /* Unnumbered Information */ +#define XDLC_UP 0x20 /* Unnumbered Poll */ +#define XDLC_DISC 0x40 /* Disconnect (command) */ +#define XDLC_RD 0x40 /* Request Disconnect (response) */ +#define XDLC_UA 0x60 /* Unnumbered Acknowledge */ +#define XDLC_SNRM 0x80 /* Set Normal Response Mode */ +#define XDLC_TEST 0xE0 /* Test */ +#define XDLC_SIM 0x04 /* Set Initialization Mode (command) */ +#define XDLC_RIM 0x04 /* Request Initialization Mode (response) */ +#define XDLC_FRMR 0x84 /* Frame reject */ +#define XDLC_CFGR 0xC4 /* Configure */ +#define XDLC_SARM 0x0C /* Set Asynchronous Response Mode (command) */ +#define XDLC_DM 0x0C /* Disconnected mode (response) */ +#define XDLC_SABM 0x2C /* Set Asynchronous Balanced Mode */ +#define XDLC_SARME 0x4C /* Set Asynchronous Response Mode Extended */ +#define XDLC_SABME 0x6C /* Set Asynchronous Balanced Mode Extended */ +#define XDLC_RESET 0x8C /* Reset */ +#define XDLC_XID 0xAC /* Exchange identification */ +#define XDLC_SNRME 0xCC /* Set Normal Response Mode Extended */ +#define XDLC_BCN 0xEC /* Beacon */ + +/* + * This macro takes the control field of an xDLC frame, as returned by + * "get_xdlc_control()" or "dissect_xdlc_control()", and evaluates to + * TRUE if the frame is an "information" frame and FALSE if it isn't. + * Note that frames other than information frames can have data in them, + * e.g. TEST frames. + */ +#define XDLC_IS_INFORMATION(control) \ + (((control) & XDLC_I_MASK) == XDLC_I || (control) == (XDLC_UI|XDLC_U)) + +/* + * This macro takes the control field of an xDLC frame, and a flag saying + * whether we're doing basic or extended operation, and evaluates to + * the length of that field (if it's an Unnumbered frame, or we're not + * in extended mode, it's 1 byte long, otherwise it's 2 bytes long). + */ +#define XDLC_CONTROL_LEN(control, is_extended) \ + ((((control) & XDLC_S_U_MASK) == XDLC_U || !(is_extended)) ? 1 : 2) + +/* + * Structure containing pointers to hf_ values for various subfields of + * the control field. + */ +typedef struct { + int *hf_xdlc_n_r; + int *hf_xdlc_n_s; + int *hf_xdlc_p; + int *hf_xdlc_f; + int *hf_xdlc_s_ftype; + int *hf_xdlc_u_modifier_cmd; + int *hf_xdlc_u_modifier_resp; + int *hf_xdlc_ftype_i; + int *hf_xdlc_ftype_s_u; +} xdlc_cf_items; + +extern const value_string ftype_vals[]; +extern const value_string stype_vals[]; +extern const value_string modifier_vals_cmd[]; +extern const value_string modifier_vals_resp[]; + +extern int get_xdlc_control(const guchar *pd, int offset, int extended); + +extern int dissect_xdlc_control(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *xdlc_tree, int hf_xdlc_control, gint ett_xdlc_control, + const xdlc_cf_items *cf_items_nonext, const xdlc_cf_items *cf_items_ext, + const value_string *u_modifier_short_vals_cmd, + const value_string *u_modifier_short_vals_resp, int is_response, + int is_extended, int append_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/xmlstub.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/xmlstub.h new file mode 100644 index 00000000..feb7e278 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/xmlstub.h @@ -0,0 +1,1123 @@ +/* + * This is part of tree.h from the libxml2 distribution. It is used + * for structure reference when dynamically linking to libxml. + * + * The GPL agreement for this file and for libxml2 can be found at + * http://www.xmlsoft.org + */ + +#include "config.h" + +/****************** specific to wireshark ********************************/ +/* + * Uncomment the following line to restore XML_DO_VALIDITY_CHECKING + * behavior which is causing issues on WIN32 platforms. See: + * http://www.ethereal.com/lists/ethereal-dev/200410/msg00194.html + */ +/* #define WIRESHARK_XML_DO_VALIDITY_CHECKING */ +/****************** From xml headers ************************************/ + +/* + * use those to be sure nothing nasty will happen if + * your library and includes mismatch + */ +#ifndef LIBXML2_COMPILING_MSCCDEF +extern void xmlCheckVersion(int version); +#endif /* LIBXML2_COMPILING_MSCCDEF */ +#define LIBXML_DOTTED_VERSION "2.3.8" +#define LIBXML_VERSION 20308 +#define LIBXML_VERSION_STRING "20308" +#define LIBXML_TEST_VERSION xmlCheckVersion(20308); + +/* + * Whether the trio support need to be configured in + */ +#if 0 +#define WITH_TRIO +#else +#define WITHOUT_TRIO +#endif + +/* + * Whether the FTP support is configured in + */ +#if 1 +#define LIBXML_FTP_ENABLED +#else +#define LIBXML_FTP_DISABLED +#endif + +/* + * Whether the HTTP support is configured in + */ +#if 1 +#define LIBXML_HTTP_ENABLED +#else +#define LIBXML_HTTP_DISABLED +#endif + +/* + * Whether the HTML support is configured in + */ +#if 1 +#define LIBXML_HTML_ENABLED +#else +#define LIBXML_HTML_DISABLED +#endif + +/* + * Whether the SGML Docbook support is configured in + */ +#if 1 +#define LIBXML_DOCB_ENABLED +#else +#define LIBXML_DOCB_DISABLED +#endif + +/* + * Whether XPath is configured in + */ +#if 1 +#define LIBXML_XPATH_ENABLED +#else +#define LIBXML_XPATH_DISABLED +#endif + +/* + * Whether XPointer is configured in + */ +#if 1 +#define LIBXML_XPTR_ENABLED +#else +#define LIBXML_XPTR_DISABLED +#endif + +/* + * Whether XInclude is configured in + */ +#if 1 +#define LIBXML_XINCLUDE_ENABLED +#else +#define LIBXML_XINCLUDE_DISABLED +#endif + +/* + * Whether iconv support is available + */ +#ifdef HAVE_ICONV +#define LIBXML_ICONV_ENABLED +#include +#else +#define LIBXML_ICONV_DISABLED +#endif + +/* + * Whether Debugging module is configured in + */ +#if 1 +#define LIBXML_DEBUG_ENABLED +#else +#define LIBXML_DEBUG_DISABLED +#endif + +/* + * Whether the memory debugging is configured in + */ +#if 0 +#define DEBUG_MEMORY_LOCATION +#endif + +#ifndef LIBXML_DLL_IMPORT +#if defined(_WIN32) && !defined(STATIC) +#define LIBXML_DLL_IMPORT __declspec(dllimport) +#else +#define LIBXML_DLL_IMPORT +#endif +#endif + +#ifdef __GNUC__ +#ifdef HAVE_ANSIDECL_H +#include +#endif +#ifndef ATTRIBUTE_UNUSED +#define ATTRIBUTE_UNUSED +#endif +#else +#define ATTRIBUTE_UNUSED +#endif + + +#define XML_XML_NAMESPACE \ + (const xmlChar *) "http://www.w3.org/XML/1998/namespace" + +/* + * The different element types carried by an XML tree + * + * NOTE: This is synchronized with DOM Level1 values + * See http://www.w3.org/TR/REC-DOM-Level-1/ + * + * Actually this had diverged a bit, and now XML_DOCUMENT_TYPE_NODE should + * be deprecated to use an XML_DTD_NODE. + */ +typedef enum { + XML_ELEMENT_NODE= 1, + XML_ATTRIBUTE_NODE= 2, + XML_TEXT_NODE= 3, + XML_CDATA_SECTION_NODE= 4, + XML_ENTITY_REF_NODE= 5, + XML_ENTITY_NODE= 6, + XML_PI_NODE= 7, + XML_COMMENT_NODE= 8, + XML_DOCUMENT_NODE= 9, + XML_DOCUMENT_TYPE_NODE= 10, + XML_DOCUMENT_FRAG_NODE= 11, + XML_NOTATION_NODE= 12, + XML_HTML_DOCUMENT_NODE= 13, + XML_DTD_NODE= 14, + XML_ELEMENT_DECL= 15, + XML_ATTRIBUTE_DECL= 16, + XML_ENTITY_DECL= 17, + XML_NAMESPACE_DECL= 18, + XML_XINCLUDE_START= 19, + XML_XINCLUDE_END= 20 +#ifdef LIBXML_DOCB_ENABLED + ,XML_DOCB_DOCUMENT_NODE= 21 +#endif +} xmlElementType; + +/* + * Size of an internal character representation. + * + * We use 8bit chars internal representation for memory efficiency, + * Note that with 8 bits wide xmlChars one can still use UTF-8 to handle + * correctly non ISO-Latin input. + */ + +typedef unsigned char xmlChar; + +#ifndef _WIN32 +#ifndef CHAR +#define CHAR xmlChar +#endif +#endif + +#define BAD_CAST (xmlChar *) + +/* + * a DTD Notation definition + */ + +typedef struct _xmlNotation xmlNotation; +typedef xmlNotation *xmlNotationPtr; +struct _xmlNotation { + const xmlChar *name; /* Notation name */ + const xmlChar *PublicID; /* Public identifier, if any */ + const xmlChar *SystemID; /* System identifier, if any */ +}; + +/* + * a DTD Attribute definition + */ + +typedef enum { + XML_ATTRIBUTE_CDATA = 1, + XML_ATTRIBUTE_ID, + XML_ATTRIBUTE_IDREF , + XML_ATTRIBUTE_IDREFS, + XML_ATTRIBUTE_ENTITY, + XML_ATTRIBUTE_ENTITIES, + XML_ATTRIBUTE_NMTOKEN, + XML_ATTRIBUTE_NMTOKENS, + XML_ATTRIBUTE_ENUMERATION, + XML_ATTRIBUTE_NOTATION +} xmlAttributeType; + +typedef enum { + XML_ATTRIBUTE_NONE = 1, + XML_ATTRIBUTE_REQUIRED, + XML_ATTRIBUTE_IMPLIED, + XML_ATTRIBUTE_FIXED +} xmlAttributeDefault; + +typedef struct _xmlEnumeration xmlEnumeration; +typedef xmlEnumeration *xmlEnumerationPtr; +struct _xmlEnumeration { + struct _xmlEnumeration *next; /* next one */ + const xmlChar *name; /* Enumeration name */ +}; + +typedef struct _xmlAttribute xmlAttribute; +typedef xmlAttribute *xmlAttributePtr; +struct _xmlAttribute { +#ifndef XML_WITHOUT_CORBA + void *_private; /* for Corba, must be first ! */ +#endif + xmlElementType type; /* XML_ATTRIBUTE_DECL, must be second ! */ + const xmlChar *name; /* Attribute name */ + struct _xmlNode *children; /* NULL */ + struct _xmlNode *last; /* NULL */ + struct _xmlDtd *parent; /* -> DTD */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + + struct _xmlAttribute *nexth; /* next in hash table */ + xmlAttributeType atype; /* The attribute type */ + xmlAttributeDefault def; /* the default */ + const xmlChar *defaultValue; /* or the default value */ + xmlEnumerationPtr tree; /* or the enumeration tree if any */ + const xmlChar *prefix; /* the namespace prefix if any */ + const xmlChar *elem; /* Element holding the attribute */ +}; + +/* + * a DTD Element definition. + */ +typedef enum { + XML_ELEMENT_CONTENT_PCDATA = 1, + XML_ELEMENT_CONTENT_ELEMENT, + XML_ELEMENT_CONTENT_SEQ, + XML_ELEMENT_CONTENT_OR +} xmlElementContentType; + +typedef enum { + XML_ELEMENT_CONTENT_ONCE = 1, + XML_ELEMENT_CONTENT_OPT, + XML_ELEMENT_CONTENT_MULT, + XML_ELEMENT_CONTENT_PLUS +} xmlElementContentOccur; + +typedef struct _xmlElementContent xmlElementContent; +typedef xmlElementContent *xmlElementContentPtr; +struct _xmlElementContent { + xmlElementContentType type; /* PCDATA, ELEMENT, SEQ or OR */ + xmlElementContentOccur ocur; /* ONCE, OPT, MULT or PLUS */ + const xmlChar *name; /* Element name */ + struct _xmlElementContent *c1; /* first child */ + struct _xmlElementContent *c2; /* second child */ + struct _xmlElementContent *parent; /* parent */ +}; + +typedef enum { + XML_ELEMENT_TYPE_UNDEFINED = 0, + XML_ELEMENT_TYPE_EMPTY = 1, + XML_ELEMENT_TYPE_ANY, + XML_ELEMENT_TYPE_MIXED, + XML_ELEMENT_TYPE_ELEMENT +} xmlElementTypeVal; + +typedef struct _xmlElement xmlElement; +typedef xmlElement *xmlElementPtr; +struct _xmlElement { +#ifndef XML_WITHOUT_CORBA + void *_private; /* for Corba, must be first ! */ +#endif + xmlElementType type; /* XML_ELEMENT_DECL, must be second ! */ + const xmlChar *name; /* Element name */ + struct _xmlNode *children; /* NULL */ + struct _xmlNode *last; /* NULL */ + struct _xmlDtd *parent; /* -> DTD */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + + xmlElementTypeVal etype; /* The type */ + xmlElementContentPtr content; /* the allowed element content */ + xmlAttributePtr attributes; /* List of the declared attributes */ + const xmlChar *prefix; /* the namespace prefix if any */ +}; + +/* + * An XML namespace. + * Note that prefix == NULL is valid, it defines the default namespace + * within the subtree (until overriden). + * + * XML_GLOBAL_NAMESPACE is now deprecated for good + * xmlNsType is unified with xmlElementType + */ + +#define XML_LOCAL_NAMESPACE XML_NAMESPACE_DECL +typedef xmlElementType xmlNsType; + +typedef struct _xmlNs xmlNs; +typedef xmlNs *xmlNsPtr; +struct _xmlNs { + struct _xmlNs *next; /* next Ns link for this node */ + xmlNsType type; /* global or local */ + const xmlChar *href; /* URL for the namespace */ + const xmlChar *prefix; /* prefix for the namespace */ +}; + +/* + * An XML DtD, as defined by parent link */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + + /* End of common part */ + void *notations; /* Hash table for notations if any */ + void *elements; /* Hash table for elements if any */ + void *attributes; /* Hash table for attributes if any */ + void *entities; /* Hash table for entities if any */ + const xmlChar *ExternalID; /* External identifier for PUBLIC DTD */ + const xmlChar *SystemID; /* URI for a SYSTEM or PUBLIC DTD */ + void *pentities; /* Hash table for param entities if any */ +}; + +/* + * A attribute of an XML node. + */ +typedef struct _xmlAttr xmlAttr; +typedef xmlAttr *xmlAttrPtr; +struct _xmlAttr { +#ifndef XML_WITHOUT_CORBA + void *_private; /* for Corba, must be first ! */ +#endif + xmlElementType type; /* XML_ATTRIBUTE_NODE, must be second ! */ + const xmlChar *name; /* the name of the property */ + struct _xmlNode *children; /* the value of the property */ + struct _xmlNode *last; /* NULL */ + struct _xmlNode *parent; /* child->parent link */ + struct _xmlAttr *next; /* next sibling link */ + struct _xmlAttr *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + xmlNs *ns; /* pointer to the associated namespace */ + xmlAttributeType atype; /* the attribute type if validating */ +}; + +/* + * An XML ID instance. + */ + +typedef struct _xmlID xmlID; +typedef xmlID *xmlIDPtr; +struct _xmlID { + struct _xmlID *next; /* next ID */ + const xmlChar *value; /* The ID name */ + xmlAttrPtr attr; /* The attribut holding it */ +}; + +/* + * An XML IDREF instance. + */ + +typedef struct _xmlRef xmlRef; +typedef xmlRef *xmlRefPtr; +struct _xmlRef { + struct _xmlRef *next; /* next Ref */ + const xmlChar *value; /* The Ref name */ + xmlAttrPtr attr; /* The attribut holding it */ +}; + +/* + * A buffer structure + */ + +typedef enum { + XML_BUFFER_ALLOC_DOUBLEIT, + XML_BUFFER_ALLOC_EXACT +} xmlBufferAllocationScheme; + +typedef struct _xmlBuffer xmlBuffer; +typedef xmlBuffer *xmlBufferPtr; +struct _xmlBuffer { + xmlChar *content; /* The buffer content UTF8 */ + unsigned int use; /* The buffer size used */ + unsigned int size; /* The buffer size */ + xmlBufferAllocationScheme alloc; /* The realloc method */ +}; + +/* + * A node in an XML tree. + */ +typedef struct _xmlNode xmlNode; +typedef xmlNode *xmlNodePtr; +struct _xmlNode { +#ifndef XML_WITHOUT_CORBA + void *_private; /* for Corba, must be first ! */ +#endif + xmlElementType type; /* type number, must be second ! */ + const xmlChar *name; /* the name of the node, or the entity */ + struct _xmlNode *children; /* parent->childs link */ + struct _xmlNode *last; /* last child link */ + struct _xmlNode *parent; /* child->parent link */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + xmlNs *ns; /* pointer to the associated namespace */ +#ifndef XML_USE_BUFFER_CONTENT + xmlChar *content; /* the content */ +#else + xmlBufferPtr content; /* the content in a buffer */ +#endif + + /* End of common part */ + struct _xmlAttr *properties;/* properties list */ + xmlNs *nsDef; /* namespace definitions on this node */ +}; + +/* + * An XML document. + */ +typedef struct _xmlDoc xmlDoc; +typedef xmlDoc *xmlDocPtr; +struct _xmlDoc { +#ifndef XML_WITHOUT_CORBA + void *_private; /* for Corba, must be first ! */ +#endif + xmlElementType type; /* XML_DOCUMENT_NODE, must be second ! */ + char *name; /* name/filename/URI of the document */ + struct _xmlNode *children; /* the document tree */ + struct _xmlNode *last; /* last child link */ + struct _xmlNode *parent; /* child->parent link */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* autoreference to itself */ + + /* End of common part */ + int compression;/* level of zlib compression */ + int standalone; /* standalone document (no external refs) */ + struct _xmlDtd *intSubset; /* the document internal subset */ + struct _xmlDtd *extSubset; /* the document external subset */ + struct _xmlNs *oldNs; /* Global namespace, the old way */ + const xmlChar *version; /* the XML version string */ + const xmlChar *encoding; /* external initial encoding, if any */ + void *ids; /* Hash table for ID attributes if any */ + void *refs; /* Hash table for IDREFs attributes if any */ + const xmlChar *URL; /* The URI for that document */ + int charset; /* encoding of the in-memory content + actually an xmlCharEncoding */ +}; + +/** + * Predefined values for some standard encodings + * Libxml don't do beforehand translation on UTF8, ISOLatinX + * It also support UTF16 (LE and BE) by default. + * + * Anything else would have to be translated to UTF8 before being + * given to the parser itself. The BOM for UTF16 and the encoding + * declaration are looked at and a converter is looked for at that + * point. If not found the parser stops here as asked by the XML REC + * Converter can be registered by the user using xmlRegisterCharEncodingHandler + * but the currentl form doesn't allow stateful transcoding (a serious + * problem agreed !). If iconv has been found it will be used + * automatically and allow stateful transcoding, the simplest is then + * to be sure to enable icon and to provide iconv libs for the encoding + * support needed. + */ +typedef enum { + XML_CHAR_ENCODING_ERROR= -1, /* No char encoding detected */ + XML_CHAR_ENCODING_NONE= 0, /* No char encoding detected */ + XML_CHAR_ENCODING_UTF8= 1, /* UTF-8 */ + XML_CHAR_ENCODING_UTF16LE= 2, /* UTF-16 little endian */ + XML_CHAR_ENCODING_UTF16BE= 3, /* UTF-16 big endian */ + XML_CHAR_ENCODING_UCS4LE= 4, /* UCS-4 little endian */ + XML_CHAR_ENCODING_UCS4BE= 5, /* UCS-4 big endian */ + XML_CHAR_ENCODING_EBCDIC= 6, /* EBCDIC uh! */ + XML_CHAR_ENCODING_UCS4_2143=7, /* UCS-4 unusual ordering */ + XML_CHAR_ENCODING_UCS4_3412=8, /* UCS-4 unusual ordering */ + XML_CHAR_ENCODING_UCS2= 9, /* UCS-2 */ + XML_CHAR_ENCODING_8859_1= 10,/* ISO-8859-1 ISO Latin 1 */ + XML_CHAR_ENCODING_8859_2= 11,/* ISO-8859-2 ISO Latin 2 */ + XML_CHAR_ENCODING_8859_3= 12,/* ISO-8859-3 */ + XML_CHAR_ENCODING_8859_4= 13,/* ISO-8859-4 */ + XML_CHAR_ENCODING_8859_5= 14,/* ISO-8859-5 */ + XML_CHAR_ENCODING_8859_6= 15,/* ISO-8859-6 */ + XML_CHAR_ENCODING_8859_7= 16,/* ISO-8859-7 */ + XML_CHAR_ENCODING_8859_8= 17,/* ISO-8859-8 */ + XML_CHAR_ENCODING_8859_9= 18,/* ISO-8859-9 */ + XML_CHAR_ENCODING_2022_JP= 19,/* ISO-2022-JP */ + XML_CHAR_ENCODING_SHIFT_JIS=20,/* Shift_JIS */ + XML_CHAR_ENCODING_EUC_JP= 21,/* EUC-JP */ + XML_CHAR_ENCODING_ASCII= 22 /* pure ASCII */ +} xmlCharEncoding; + +/** + * xmlCharEncodingInputFunc: + * @param out a pointer ot an array of bytes to store the UTF-8 result + * @param outlen the length of out + * @param in a pointer ot an array of chars in the original encoding + * @param inlen the length of in + * + * Take a block of chars in the original encoding and try to convert + * it to an UTF-8 block of chars out. + * + * Returns the number of byte written, or -1 by lack of space, or -2 + * if the transcoding failed. + * The value of inlen after return is the number of octets consumed + * as the return value is positive, else unpredictiable. + * The value of outlen after return is the number of ocetes consumed. + */ +typedef int (* xmlCharEncodingInputFunc)(unsigned char* out, int *outlen, + const unsigned char* in, int *inlen); + + +/** + * xmlCharEncodingOutputFunc: + * @param out a pointer ot an array of bytes to store the result + * @param outlen the length of out + * @param in a pointer ot an array of UTF-8 chars + * @param inlen the length of in + * + * Take a block of UTF-8 chars in and try to convert it to an other + * encoding. + * Note: a first call designed to produce heading info is called with + * in = NULL. If stateful this should also initialize the encoder state + * + * Returns the number of byte written, or -1 by lack of space, or -2 + * if the transcoding failed. + * The value of inlen after return is the number of octets consumed + * as the return value is positive, else unpredictiable. + * The value of outlen after return is the number of ocetes consumed. + */ +typedef int (* xmlCharEncodingOutputFunc)(unsigned char* out, int *outlen, + const unsigned char* in, int *inlen); + + +/* + * Block defining the handlers for non UTF-8 encodings. + * If iconv is supported, there is two extra fields + */ + +typedef struct _xmlCharEncodingHandler xmlCharEncodingHandler; +typedef xmlCharEncodingHandler *xmlCharEncodingHandlerPtr; +struct _xmlCharEncodingHandler { + char *name; + xmlCharEncodingInputFunc input; + xmlCharEncodingOutputFunc output; +#ifdef LIBXML_ICONV_ENABLED + iconv_t iconv_in; + iconv_t iconv_out; +#endif /* LIBXML_ICONV_ENABLED */ +}; + +typedef int (*xmlInputMatchCallback) (char const *filename); +typedef void * (*xmlInputOpenCallback) (char const *filename); +typedef int (*xmlInputReadCallback) (void * context, char * buffer, int len); +typedef void (*xmlInputCloseCallback) (void * context); + +typedef struct _xmlParserInputBuffer xmlParserInputBuffer; +typedef xmlParserInputBuffer *xmlParserInputBufferPtr; +struct _xmlParserInputBuffer { + void* context; + xmlInputReadCallback readcallback; + xmlInputCloseCallback closecallback; + + xmlCharEncodingHandlerPtr encoder; /* I18N conversions to UTF-8 */ + + xmlBufferPtr buffer; /* Local buffer encoded in UTF-8 */ + xmlBufferPtr raw; /* if encoder != NULL buffer for raw input */ +}; + + +/* + * Those are the functions and datatypes for the library output + * I/O structures. + */ + +typedef int (*xmlOutputMatchCallback) (char const *filename); +typedef void * (*xmlOutputOpenCallback) (char const *filename); +typedef int (*xmlOutputWriteCallback) (void * context, const char * buffer, + int len); +typedef void (*xmlOutputCloseCallback) (void * context); + +typedef struct _xmlOutputBuffer xmlOutputBuffer; +typedef xmlOutputBuffer *xmlOutputBufferPtr; +struct _xmlOutputBuffer { + void* context; + xmlOutputWriteCallback writecallback; + xmlOutputCloseCallback closecallback; + + xmlCharEncodingHandlerPtr encoder; /* I18N conversions to UTF-8 */ + + xmlBufferPtr buffer; /* Local buffer encoded in UTF-8 or ISOLatin */ + xmlBufferPtr conv; /* if encoder != NULL buffer for output */ + int written; /* total number of byte written */ +}; + +#define XML_DEFAULT_VERSION "1.0" + +/** + * an xmlParserInput is an input flow for the XML processor. + * Each entity parsed is associated an xmlParserInput (except the + * few predefined ones). This is the case both for internal entities + * - in which case the flow is already completely in memory - or + * external entities - in which case we use the buf structure for + * progressive reading and I18N conversions to the internal UTF-8 format. + */ + +typedef void (* xmlParserInputDeallocate)(xmlChar *); +typedef struct _xmlParserInput xmlParserInput; +typedef xmlParserInput *xmlParserInputPtr; +struct _xmlParserInput { + /* Input buffer */ + xmlParserInputBufferPtr buf; /* UTF-8 encoded buffer */ + + const char *filename; /* The file analyzed, if any */ + const char *directory; /* the directory/base of teh file */ + const xmlChar *base; /* Base of the array to parse */ + const xmlChar *cur; /* Current char being parsed */ + const xmlChar *end; /* end of the arry to parse */ + int length; /* length if known */ + int line; /* Current line */ + int col; /* Current column */ + int consumed; /* How many xmlChars already consumed */ + xmlParserInputDeallocate free; /* function to deallocate the base */ + const xmlChar *encoding; /* the encoding string for entity */ + const xmlChar *version; /* the version string for entity */ + int standalone; /* Was that entity marked standalone */ +}; + +/** + * the parser can be asked to collect Node informations, i.e. at what + * place in the file they were detected. + * NOTE: This is off by default and not very well tested. + */ +typedef struct _xmlParserNodeInfo xmlParserNodeInfo; +typedef xmlParserNodeInfo *xmlParserNodeInfoPtr; + +struct _xmlParserNodeInfo { + const struct _xmlNode* node; + /* Position & line # that text that created the node begins & ends on */ + unsigned long begin_pos; + unsigned long begin_line; + unsigned long end_pos; + unsigned long end_line; +}; + +typedef struct _xmlParserNodeInfoSeq xmlParserNodeInfoSeq; +typedef xmlParserNodeInfoSeq *xmlParserNodeInfoSeqPtr; +struct _xmlParserNodeInfoSeq { + unsigned long maximum; + unsigned long length; + xmlParserNodeInfo* buffer; +}; + +/* + * Validation state added for non-determinist content model + */ +typedef struct _xmlValidState xmlValidState; +typedef xmlValidState *xmlValidStatePtr; + +/** + * an xmlValidCtxt is used for error reporting when validating + */ + +typedef void (*xmlValidityErrorFunc) (void *ctx, const char *msg, ...); +typedef void (*xmlValidityWarningFunc) (void *ctx, const char *msg, ...); + +typedef struct _xmlValidCtxt xmlValidCtxt; +typedef xmlValidCtxt *xmlValidCtxtPtr; +struct _xmlValidCtxt { + void *userData; /* user specific data block */ + xmlValidityErrorFunc error; /* the callback in case of errors */ + xmlValidityWarningFunc warning; /* the callback in case of warning */ + + /* Node analysis stack used when validating within entities */ + xmlNodePtr node; /* Current parsed Node */ + int nodeNr; /* Depth of the parsing stack */ + int nodeMax; /* Max depth of the parsing stack */ + xmlNodePtr *nodeTab; /* array of nodes */ + + int finishDtd; /* finished validating the Dtd ? */ + xmlDocPtr doc; /* the document */ + int valid; /* temporary validity check result */ + + /* state state used for non-determinist content validation */ + xmlValidState *vstate; /* current state */ + int vstateNr; /* Depth of the validation stack */ + int vstateMax; /* Max depth of the validation stack */ + xmlValidState *vstateTab; /* array of validation states */ +}; + +typedef struct _xmlLink xmlLink; +typedef xmlLink *xmlLinkPtr; + +typedef struct _xmlList xmlList; +typedef xmlList *xmlListPtr; + +typedef void (*xmlListDeallocator) (xmlLinkPtr lk); +typedef int (*xmlListDataCompare) (const void *data0, const void *data1); +typedef int (*xmlListWalker) (const void *data, const void *user); + +/* + * ALl notation declarations are stored in a table + * there is one table per DTD + */ + +typedef struct _xmlHashTable xmlNotationTable; +typedef xmlNotationTable *xmlNotationTablePtr; + +/* + * ALl element declarations are stored in a table + * there is one table per DTD + */ + +typedef struct _xmlHashTable xmlElementTable; +typedef xmlElementTable *xmlElementTablePtr; + +/* + * ALl attribute declarations are stored in a table + * there is one table per DTD + */ + +typedef struct _xmlHashTable xmlAttributeTable; +typedef xmlAttributeTable *xmlAttributeTablePtr; + +/* + * ALl IDs attributes are stored in a table + * there is one table per document + */ + +typedef struct _xmlHashTable xmlIDTable; +typedef xmlIDTable *xmlIDTablePtr; + +/* + * ALl Refs attributes are stored in a table + * there is one table per document + */ + +typedef struct _xmlHashTable xmlRefTable; +typedef xmlRefTable *xmlRefTablePtr; + +/* helper */ +xmlChar * xmlSplitQName2 (const xmlChar *name, + xmlChar **prefix); + +/** + * The parser is now working also as a state based parser + * The recursive one use the stagte info for entities processing + */ +typedef enum { + XML_PARSER_EOF = -1, /* nothing is to be parsed */ + XML_PARSER_START = 0, /* nothing has been parsed */ + XML_PARSER_MISC, /* Misc* before int subset */ + XML_PARSER_PI, /* Whithin a processing instruction */ + XML_PARSER_DTD, /* within some DTD content */ + XML_PARSER_PROLOG, /* Misc* after internal subset */ + XML_PARSER_COMMENT, /* within a comment */ + XML_PARSER_START_TAG, /* within a start tag */ + XML_PARSER_CONTENT, /* within the content */ + XML_PARSER_CDATA_SECTION, /* within a CDATA section */ + XML_PARSER_END_TAG, /* within a closing tag */ + XML_PARSER_ENTITY_DECL, /* within an entity declaration */ + XML_PARSER_ENTITY_VALUE, /* within an entity value in a decl */ + XML_PARSER_ATTRIBUTE_VALUE, /* within an attribute value */ + XML_PARSER_SYSTEM_LITERAL, /* within a SYSTEM value */ + XML_PARSER_EPILOG, /* the Misc* after the last end tag */ + XML_PARSER_IGNORE /* within an IGNORED section */ +} xmlParserInputState; + +/** + * The parser context. + * NOTE This doesn't completely defines the parser state, the (current ?) + * design of the parser uses recursive function calls since this allow + * and easy mapping from the production rules of the specification + * to the actual code. The drawback is that the actual function call + * also reflect the parser state. However most of the parsing routines + * takes as the only argument the parser context pointer, so migrating + * to a state based parser for progressive parsing shouldn't be too hard. + */ +typedef struct _xmlParserCtxt xmlParserCtxt; +typedef xmlParserCtxt *xmlParserCtxtPtr; +struct _xmlParserCtxt { + struct _xmlSAXHandler *sax; /* The SAX handler */ + void *userData; /* For SAX interface only, used by DOM build */ + xmlDocPtr myDoc; /* the document being built */ + int wellFormed; /* is the document well formed */ + int replaceEntities; /* shall we replace entities ? */ + const xmlChar *version; /* the XML version string */ + const xmlChar *encoding; /* the declared encoding, if any */ + int standalone; /* standalone document */ + int html; /* an HTML(1)/Docbook(2) document */ + + /* Input stream stack */ + xmlParserInputPtr input; /* Current input stream */ + int inputNr; /* Number of current input streams */ + int inputMax; /* Max number of input streams */ + xmlParserInputPtr *inputTab; /* stack of inputs */ + + /* Node analysis stack only used for DOM building */ + xmlNodePtr node; /* Current parsed Node */ + int nodeNr; /* Depth of the parsing stack */ + int nodeMax; /* Max depth of the parsing stack */ + xmlNodePtr *nodeTab; /* array of nodes */ + + int record_info; /* Whether node info should be kept */ + xmlParserNodeInfoSeq node_seq; /* info about each node parsed */ + + int errNo; /* error code */ + + int hasExternalSubset; /* reference and external subset */ + int hasPErefs; /* the internal subset has PE refs */ + int external; /* are we parsing an external entity */ + + int valid; /* is the document valid */ + int validate; /* shall we try to validate ? */ + xmlValidCtxt vctxt; /* The validity context */ + + xmlParserInputState instate; /* current type of input */ + int token; /* next char look-ahead */ + + char *directory; /* the data directory */ + + /* Node name stack */ + xmlChar *name; /* Current parsed Node */ + int nameNr; /* Depth of the parsing stack */ + int nameMax; /* Max depth of the parsing stack */ + xmlChar * *nameTab; /* array of nodes */ + + long nbChars; /* number of xmlChar processed */ + long checkIndex; /* used by progressive parsing lookup */ + int keepBlanks; /* ugly but ... */ + int disableSAX; /* SAX callbacks are disabled */ + int inSubset; /* Parsing is in int 1/ext 2 subset */ + xmlChar * intSubName; /* name of subset */ + xmlChar * extSubURI; /* URI of external subset */ + xmlChar * extSubSystem; /* SYSTEM ID of external subset */ + + /* xml:space values */ + int * space; /* Should the parser preserve spaces */ + int spaceNr; /* Depth of the parsing stack */ + int spaceMax; /* Max depth of the parsing stack */ + int * spaceTab; /* array of space infos */ + + int depth; /* to prevent entity substitution loops */ + xmlParserInputPtr entity; /* used to check entities boundaries */ + int charset; /* encoding of the in-memory content + actually an xmlCharEncoding */ + int nodelen; /* Those two fields are there to */ + int nodemem; /* Speed up large node parsing */ + int pedantic; /* signal pedantic warnings */ + void *_private; /* For user data, libxml won't touch it */ + + int loadsubset; /* should the external subset be loaded */ +}; + +/** + * a SAX Locator. + */ +typedef struct _xmlSAXLocator xmlSAXLocator; +typedef xmlSAXLocator *xmlSAXLocatorPtr; +struct _xmlSAXLocator { + const xmlChar *(*getPublicId)(void *ctx); + const xmlChar *(*getSystemId)(void *ctx); + int (*getLineNumber)(void *ctx); + int (*getColumnNumber)(void *ctx); +}; + +/* + * The different valid entity types + */ +typedef enum { + XML_INTERNAL_GENERAL_ENTITY = 1, + XML_EXTERNAL_GENERAL_PARSED_ENTITY = 2, + XML_EXTERNAL_GENERAL_UNPARSED_ENTITY = 3, + XML_INTERNAL_PARAMETER_ENTITY = 4, + XML_EXTERNAL_PARAMETER_ENTITY = 5, + XML_INTERNAL_PREDEFINED_ENTITY = 6 +} xmlEntityType; + +/* + * An unit of storage for an entity, contains the string, the value + * and the linkind data needed for the linking in the hash table. + */ + +typedef struct _xmlEntity xmlEntity; +typedef xmlEntity *xmlEntityPtr; +struct _xmlEntity { +#ifndef XML_WITHOUT_CORBA + void *_private; /* for Corba, must be first ! */ +#endif + xmlElementType type; /* XML_ENTITY_DECL, must be second ! */ + const xmlChar *name; /* Attribute name */ + struct _xmlNode *children; /* NULL */ + struct _xmlNode *last; /* NULL */ + struct _xmlDtd *parent; /* -> DTD */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + + xmlChar *orig; /* content without ref substitution */ + xmlChar *content; /* content or ndata if unparsed */ + int length; /* the content length */ + xmlEntityType etype; /* The entity type */ + const xmlChar *ExternalID; /* External identifier for PUBLIC */ + const xmlChar *SystemID; /* URI for a SYSTEM or PUBLIC Entity */ + + struct _xmlEntity *nexte; /* unused */ + const xmlChar *URI; /* the full URI as computed */ +}; + +/* + * ALl entities are stored in an hash table + * there is 2 separate hash tables for global and parmeter entities + */ + +typedef struct _xmlHashTable xmlEntitiesTable; +typedef xmlEntitiesTable *xmlEntitiesTablePtr; + +/* + * External functions : + */ + +/** + * a SAX handler is bunch of callbacks called by the parser when processing + * of the input generate data or structure informations. + */ + +typedef xmlParserInputPtr (*resolveEntitySAXFunc) (void *ctx, + const xmlChar *publicId, const xmlChar *systemId); +typedef void (*internalSubsetSAXFunc) (void *ctx, const xmlChar *name, + const xmlChar *ExternalID, const xmlChar *SystemID); +typedef void (*externalSubsetSAXFunc) (void *ctx, const xmlChar *name, + const xmlChar *ExternalID, const xmlChar *SystemID); +typedef xmlEntityPtr (*getEntitySAXFunc) (void *ctx, + const xmlChar *name); +typedef xmlEntityPtr (*getParameterEntitySAXFunc) (void *ctx, + const xmlChar *name); +typedef void (*entityDeclSAXFunc) (void *ctx, + const xmlChar *name, int type, const xmlChar *publicId, + const xmlChar *systemId, xmlChar *content); +typedef void (*notationDeclSAXFunc)(void *ctx, const xmlChar *name, + const xmlChar *publicId, const xmlChar *systemId); +typedef void (*attributeDeclSAXFunc)(void *ctx, const xmlChar *elem, + const xmlChar *name, int type, int def, + const xmlChar *defaultValue, xmlEnumerationPtr tree); +typedef void (*elementDeclSAXFunc)(void *ctx, const xmlChar *name, + int type, xmlElementContentPtr content); +typedef void (*unparsedEntityDeclSAXFunc)(void *ctx, + const xmlChar *name, const xmlChar *publicId, + const xmlChar *systemId, const xmlChar *notationName); +typedef void (*setDocumentLocatorSAXFunc) (void *ctx, + xmlSAXLocatorPtr loc); +typedef void (*startDocumentSAXFunc) (void *ctx); +typedef void (*endDocumentSAXFunc) (void *ctx); +typedef void (*startElementSAXFunc) (void *ctx, const xmlChar *name, + const xmlChar **atts); +typedef void (*endElementSAXFunc) (void *ctx, const xmlChar *name); +typedef void (*attributeSAXFunc) (void *ctx, const xmlChar *name, + const xmlChar *value); +typedef void (*referenceSAXFunc) (void *ctx, const xmlChar *name); +typedef void (*charactersSAXFunc) (void *ctx, const xmlChar *ch, + int len); +typedef void (*ignorableWhitespaceSAXFunc) (void *ctx, + const xmlChar *ch, int len); +typedef void (*processingInstructionSAXFunc) (void *ctx, + const xmlChar *target, const xmlChar *data); +typedef void (*commentSAXFunc) (void *ctx, const xmlChar *value); +typedef void (*cdataBlockSAXFunc) (void *ctx, const xmlChar *value, int len); +typedef void (*warningSAXFunc) (void *ctx, const char *msg, ...); +typedef void (*errorSAXFunc) (void *ctx, const char *msg, ...); +typedef void (*fatalErrorSAXFunc) (void *ctx, const char *msg, ...); +typedef int (*isStandaloneSAXFunc) (void *ctx); +typedef int (*hasInternalSubsetSAXFunc) (void *ctx); +typedef int (*hasExternalSubsetSAXFunc) (void *ctx); + +typedef struct _xmlSAXHandler xmlSAXHandler; +typedef xmlSAXHandler *xmlSAXHandlerPtr; +struct _xmlSAXHandler { + internalSubsetSAXFunc internalSubset; + isStandaloneSAXFunc isStandalone; + hasInternalSubsetSAXFunc hasInternalSubset; + hasExternalSubsetSAXFunc hasExternalSubset; + resolveEntitySAXFunc resolveEntity; + getEntitySAXFunc getEntity; + entityDeclSAXFunc entityDecl; + notationDeclSAXFunc notationDecl; + attributeDeclSAXFunc attributeDecl; + elementDeclSAXFunc elementDecl; + unparsedEntityDeclSAXFunc unparsedEntityDecl; + setDocumentLocatorSAXFunc setDocumentLocator; + startDocumentSAXFunc startDocument; + endDocumentSAXFunc endDocument; + startElementSAXFunc startElement; + endElementSAXFunc endElement; + referenceSAXFunc reference; + charactersSAXFunc characters; + ignorableWhitespaceSAXFunc ignorableWhitespace; + processingInstructionSAXFunc processingInstruction; + commentSAXFunc comment; + warningSAXFunc warning; + errorSAXFunc error; + fatalErrorSAXFunc fatalError; + getParameterEntitySAXFunc getParameterEntity; + cdataBlockSAXFunc cdataBlock; + externalSubsetSAXFunc externalSubset; +}; + +/** + * External entity loaders types + */ +typedef xmlParserInputPtr (*xmlExternalEntityLoader)(const char *URL, + const char *ID, + xmlParserCtxtPtr context); + +/* + * Compatibility naming layer with libxml1 + */ +#ifndef xmlChildrenNode +#define xmlChildrenNode children +#define xmlRootNode children +#endif + + +/*********************Xml routines and function pointers */ +#ifdef IN_XMLSTUB +#define XML_EXTERN +#else +#define XML_EXTERN extern +#endif + +typedef struct { + /* Functions */ + xmlDocPtr (*xmlParseFile)(const char *filename); + int (*xmlStrcmp)(const xmlChar *str1, const xmlChar *str2); + xmlParserCtxtPtr (*xmlCreatePushParserCtxt)(xmlSAXHandlerPtr, void *, const char *, + int, const char *); + int (*xmlParseChunk)(xmlParserCtxtPtr, const char *, int, int); + void (*xmlFreeParserCtxt)(xmlParserCtxtPtr); + xmlNodePtr (*xmlDocGetRootElement)(xmlDocPtr); + void (*xmlFreeDoc)(xmlDocPtr); + char *(*xmlNodeListGetString)(xmlDocPtr, xmlNodePtr, int); + char *(*xmlGetProp)(xmlNodePtr, const char *); + int (*xmlKeepBlanksDefault)(int); + int (*xmlSubstituteEntitiesDefault)(int); +#ifdef WIRESHARK_XML_DO_VALIDITY_CHECKING + int *xmlDoValidityCheckingDefaultValue; +#endif +} XML_STUB; + +XML_EXTERN XML_STUB XmlStub; +XML_EXTERN int XmlStubInitialized; + +#ifdef _WIN32 +/* We're in windows, use the windows filename */ +#define XML_LIBRARY "libxml2.dll" +#else +#define XML_LIBRARY "libxml2.so" +#endif + +/* + * This needs to be called before the library is used. It + * returns zero on success. Any non-zero return means that + * either dynamic libraries are not supported, or that libxml + * is not installed on the current system. (Or it's not in + * the LD path) + */ +int loadLibXML(void); + + + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/file.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/file.h new file mode 100644 index 00000000..e7c4de6d --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/file.h @@ -0,0 +1,486 @@ +/* file.h + * Definitions for file structures and routines + * + * $Id: file.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __FILE_H__ +#define __FILE_H__ + +#include "packet-range.h" +#include "wiretap/wtap.h" +#include +#include "print.h" +#include +#include + +#include "cfile.h" + + +/** Return values from functions that only can succeed or fail. */ +typedef enum { + CF_OK, /**< operation succeeded */ + CF_ERROR /**< operation got an error (function may provide err with details) */ +} cf_status_t; + +/** Return values from functions that read capture files. */ +typedef enum { + CF_READ_OK, /**< operation succeeded */ + CF_READ_ERROR, /**< operation got an error (function may provide err with details) */ + CF_READ_ABORTED /**< operation aborted by user */ +} cf_read_status_t; + +/** Return values from functions that print sets of packets. */ +typedef enum { + CF_PRINT_OK, /**< print operation succeeded */ + CF_PRINT_OPEN_ERROR, /**< print operation failed while opening printer */ + CF_PRINT_WRITE_ERROR /**< print operation failed while writing to the printer */ +} cf_print_status_t; + +typedef enum { + cf_cb_file_closing, + cf_cb_file_closed, + cf_cb_file_read_start, + cf_cb_file_read_finished, +#ifdef HAVE_LIBPCAP + cf_cb_live_capture_prepared, + cf_cb_live_capture_update_started, + cf_cb_live_capture_update_continue, + cf_cb_live_capture_update_finished, + cf_cb_live_capture_fixed_started, + cf_cb_live_capture_fixed_continue, + cf_cb_live_capture_fixed_finished, + cf_cb_live_capture_stopping, +#endif + cf_cb_packet_selected, + cf_cb_packet_unselected, + cf_cb_field_unselected, + cf_cb_file_safe_started, + cf_cb_file_safe_finished, + cf_cb_file_safe_reload_finished, + cf_cb_file_safe_failed +} cf_cbs; + +typedef void (*cf_callback_t) (gint event, gpointer data, gpointer user_data); + +extern void +cf_callback_invoke(int event, gpointer data); + +extern void +cf_callback_add(cf_callback_t func, gpointer user_data); + +extern void +cf_callback_remove(cf_callback_t func); + +/** + * Open a capture file. + * + * @param cf the capture file to be opened + * @param fname the filename to be opened + * @param is_tempfile is this a temporary file? + * @return one of cf_status_t + */ +cf_status_t cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err); + +/** + * Close a capture file. + * + * @param cf the capture file to be closed + */ +void cf_close(capture_file *cf); + +/** + * Reload a capture file. + * + * @param cf the capture file to be reloaded + */ +void cf_reload(capture_file *cf); + +/** + * Read all packets of a capture file into the internal structures. + * + * @param cf the capture file to be read + * @return one of cf_read_status_t + */ +cf_read_status_t cf_read(capture_file *cf); + +/** + * Start reading from the end of a capture file. + * This is used in "Update list of packets in Real-Time". + * + * @param cf the capture file to be read from + * @param fname the filename to be read from + * @param is_tempfile is this a temporary file? + * @param err the error code, if an error had occured + * @return one of cf_status_t + */ +cf_status_t cf_start_tail(capture_file *cf, const char *fname, gboolean is_tempfile, int *err); + +/** + * Read packets from the "end" of a capture file. + * + * @param cf the capture file to be read from + * @param to_read the number of packets to read + * @param err the error code, if an error had occured + * @return one of cf_read_status_t + */ +cf_read_status_t cf_continue_tail(capture_file *cf, volatile int to_read, int *err); + +/** + * Finish reading from "end" of a capture file. + * + * @param cf the capture file to be read from + * @param err the error code, if an error had occured + * @return one of cf_read_status_t + */ +cf_read_status_t cf_finish_tail(capture_file *cf, int *err); + +/** + * Determine whether this capture file (or a range of it) can be saved + * (except by copying the raw file data). + * + * @param cf the capture file to check + * @return TRUE if it can be saved, FALSE if it can't + */ +gboolean cf_can_save_as(capture_file *cf); + +/** + * Save a capture file (or a range of it). + * + * @param cf the capture file to save to + * @param fname the filename to save to + * @param range the range of packets to save + * @param save_format the format of the file to save (libpcap, ...) + * @param compressed wether to gzip compress the file + * @return one of cf_status_t + */ +cf_status_t cf_save(capture_file * cf, const char *fname, packet_range_t *range, guint save_format, gboolean compressed); + +/** + * Get a displayable name of the capture file. + * + * @param cf the capture file + * @return the displayable name (don't have to be g_free'd) + */ +const gchar *cf_get_display_name(capture_file *cf); + +/** + * Get the number of packets in the capture file. + * + * @param cf the capture file + * @return the number of packets in the capture file + */ +int cf_get_packet_count(capture_file *cf); + +/** + * Set the number of packets in the capture file. + * + * @param cf the capture file + * @param the number of packets in the capture file + */ +void cf_set_packet_count(capture_file *cf, int packet_count); + +/** + * Is this capture file a temporary file? + * + * @param cf the capture file + * @return TRUE if it's a temporary file, FALSE otherwise + */ +gboolean cf_is_tempfile(capture_file *cf); + +/** + * Set flag, that this file is a tempfile. + */ +void cf_set_tempfile(capture_file *cf, gboolean is_tempfile); + +/** + * Set flag, if the number of packet drops while capturing are known or not. + * + * @param cf the capture file + * @param drops_known TRUE if the number of packet drops are known, FALSE otherwise + */ +void cf_set_drops_known(capture_file *cf, gboolean drops_known); + +/** + * Set the number of packet drops while capturing. + * + * @param cf the capture file + * @param drops the number of packet drops occured while capturing + */ +void cf_set_drops(capture_file *cf, guint32 drops); + +/** + * Get flag state, if the number of packet drops while capturing are known or not. + * + * @param cf the capture file + * @return TRUE if the number of packet drops are known, FALSE otherwise + */ +gboolean cf_get_drops_known(capture_file *cf); + +/** + * Get the number of packet drops while capturing. + * + * @param cf the capture file + * @return the number of packet drops occured while capturing + */ +guint32 cf_get_drops(capture_file *cf); + +/** + * Set the read filter. + * @todo this shouldn't be required, remove it somehow + * + * @param cf the capture file + * @param rfcode the readfilter + */ +void cf_set_rfcode(capture_file *cf, dfilter_t *rfcode); + +/** + * "Display Filter" packets in the capture file. + * + * @param cf the capture file + * @param dfilter the display filter + * @param force TRUE if do in any case, FALSE only if dfilter changed + * @return one of cf_status_t + */ +cf_status_t cf_filter_packets(capture_file *cf, gchar *dfilter, gboolean force); + +/** + * At least one "Refence Time" flag has changed, rescan all packets. + * + * @param cf the capture file + */ +void cf_reftime_packets(capture_file *cf); + +/** + * At least one "Refence Time" flag has changed, rescan all packets. + * + * @param cf the capture file + */ +void cf_colorize_packets(capture_file *cf); + +/** + * "Something" has changed, rescan all packets. + * + * @param cf the capture file + */ +void cf_redissect_packets(capture_file *cf); + +/** + * Rescan all packets and just run taps - don't reconstruct the display. + * + * @param cf the capture file + * @param do_columns TRUE if columns are to be generated, FALSE otherwise + * @return one of cf_read_status_t + */ +cf_read_status_t cf_retap_packets(capture_file *cf, gboolean do_columns); + +/** + * The time format has changed, rescan all packets. + * + * @param cf the capture file + */ +void cf_change_time_formats(capture_file *cf); + +/** + * Print the capture file. + * + * @param cf the capture file + * @param print_args the arguments what and how to print + * @return one of cf_print_status_t + */ +cf_print_status_t cf_print_packets(capture_file *cf, print_args_t *print_args); + +/** + * Print (export) the capture file into PDML format. + * + * @param cf the capture file + * @param print_args the arguments what and how to export + * @return one of cf_print_status_t + */ +cf_print_status_t cf_write_pdml_packets(capture_file *cf, print_args_t *print_args); + +/** + * Print (export) the capture file into PSML format. + * + * @param cf the capture file + * @param print_args the arguments what and how to export + * @return one of cf_print_status_t + */ +cf_print_status_t cf_write_psml_packets(capture_file *cf, print_args_t *print_args); + +/** + * Print (export) the capture file into CSV format. + * + * @param cf the capture file + * @param print_args the arguments what and how to export + * @return one of cf_print_status_t + */ +cf_print_status_t cf_write_csv_packets(capture_file *cf, print_args_t *print_args); + +/** + * Print (export) the capture file into C Arrays format. + * + * @param cf the capture file + * @param print_args the arguments what and how to export + * @return one of cf_print_status_t + */ +cf_print_status_t cf_write_carrays_packets(capture_file *cf, print_args_t *print_args); + +/** + * Find Packet in protocol tree. + * + * @param cf the capture file + * @param string the string to find + * @return TRUE if a packet was found, FALSE otherwise + */ +gboolean cf_find_packet_protocol_tree(capture_file *cf, const char *string); + +/** + * Find Packet in summary line. + * + * @param cf the capture file + * @param string the string to find + * @return TRUE if a packet was found, FALSE otherwise + */ +gboolean cf_find_packet_summary_line(capture_file *cf, const char *string); + +/** + * Find Packet in packet data. + * + * @param cf the capture file + * @param string the string to find + * @param string_size the size of the string to find + * @return TRUE if a packet was found, FALSE otherwise + */ +gboolean cf_find_packet_data(capture_file *cf, const guint8 *string, + size_t string_size); + +/** + * Find Packet by display filter. + * + * @param cf the capture file + * @param sfcode the display filter to find a packet for + * @return TRUE if a packet was found, FALSE otherwise + */ +gboolean cf_find_packet_dfilter(capture_file *cf, dfilter_t *sfcode); + +/** + * GoTo Packet in first row. + * + * @param cf the capture file + * @return TRUE if the first row exists, FALSE otherwise + */ +gboolean cf_goto_top_frame(capture_file *cf); + +/** + * GoTo Packet in last row. + * + * @param cf the capture file + * @return TRUE if last row exists, FALSE otherwise + */ +gboolean cf_goto_bottom_frame(capture_file *cf); + +/** + * GoTo Packet with the given row. + * + * @param cf the capture file + * @param row the row to go to + * @return TRUE if this row exists, FALSE otherwise + */ +gboolean cf_goto_frame(capture_file *cf, guint row); + +/** + * Go to frame specified by currently selected protocol tree field. + * (Go To Corresponding Packet) + * @todo this is ugly and should be improved! + * + * @param cf the capture file + * @return TRUE if this packet exists, FALSE otherwise + */ +gboolean cf_goto_framenum(capture_file *cf); + +/** + * Select the packet in the given row. + * + * @param cf the capture file + * @param row the row to select + */ +void cf_select_packet(capture_file *cf, int row); + +/** + * Unselect all packets, if any. + * + * @param cf the capture file + * @param row the row to select + */ +void cf_unselect_packet(capture_file *cf); + +/** + * Unselect all protocol tree fields, if any. + * + * @param cf the capture file + * @param row the row to select + */ +void cf_unselect_field(capture_file *cf); + +/** + * Mark a particular frame in a particular capture. + * + * @param cf the capture file + * @param frame the frame to be marked + */ +void cf_mark_frame(capture_file *cf, frame_data *frame); + +/** + * Unmark a particular frame in a particular capture. + * + * @param cf the capture file + * @param frame the frame to be unmarked + */ +void cf_unmark_frame(capture_file *cf, frame_data *frame); + +/** + * Convert error number and info to a complete message. + * + * @param err the error number + * @param err_info the additional info about this error (e.g. filename) + * @return statically allocated error message + */ +char *cf_read_error_message(int err, const gchar *err_info); + +/** + * Merge two (or more) capture files into one. + * @todo is this the right place for this function? It doesn't have to do a lot with capture_file. + * + * @param out_filename pointer to output filename; if output filename is + * NULL, a temporary file name is generated and *out_filename is set + * to point to the generated file name + * @param in_file_count the number of input files to merge + * @param in_filnames array of input filenames + * @param file_type the output filetype + * @param do_append FALSE to merge chronologically, TRUE simply append + * @return one of cf_status_t + */ +cf_status_t +cf_merge_files(char **out_filename, int in_file_count, + char *const *in_filenames, int file_type, gboolean do_append); + +#endif /* file.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/fileset.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/fileset.h new file mode 100644 index 00000000..47015f99 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/fileset.h @@ -0,0 +1,75 @@ +/* fileset.h + * Definitions for routines for file sets. + * + * $Id: fileset.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __FILESET_H__ +#define __FILESET_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +typedef struct _fileset_entry { + const char *fullname; /* File name with path (g_strdup'ed) */ + const char *name; /* File name without path (g_strdup'ed) */ + time_t ctime; /* create time */ + time_t mtime; /* last modified time */ + long size; /* size of file in bytes */ + gboolean current; /* is this the currently loaded file? */ +} fileset_entry; + + +/* helper: is this a probable file of a file set (does the naming pattern match)? */ +extern gboolean fileset_filename_match_pattern(const char *fname); + +/* helper: test, if both files could be in the same file set */ +extern gboolean fileset_is_file_in_set(const char *fname1, const char *fname2); + +extern void fileset_add_dir(const char *fname); + +extern void fileset_delete(void); + +/* get the current directory name */ +extern const char *fileset_get_dirname(void); + +extern fileset_entry *fileset_get_next(void); +extern fileset_entry *fileset_get_previous(void); + + + +/* this file is a part of the current file set */ +extern void fileset_dlg_add_file(fileset_entry *entry); + +extern void fileset_file_opened(const char *fname); + +extern void fileset_file_closed(void); + +extern void fileset_update_dlg(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __FILESET_H__ */ + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/filters.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/filters.h new file mode 100644 index 00000000..0ca489b2 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/filters.h @@ -0,0 +1,87 @@ +/* filters.h + * Declarations of routines for reading and writing the filters file. + * + * $Id: filters.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * Filter lists. + */ +typedef enum { + CFILTER_LIST, /* capture filter list - saved */ + DFILTER_LIST, /* display filter list - saved */ + CFILTER_EDITED_LIST, /* capture filter list - currently edited */ + DFILTER_EDITED_LIST /* display filter list - currently edited */ +} filter_list_type_t; + +/* + * Item in a list of filters. + */ +typedef struct { + char *name; /* filter name */ + char *strval; /* filter expression */ +} filter_def; + +/* + * Read in a list of filters. + * + * On success, "*pref_path_return" is set to NULL. + * On error, "*pref_path_return" is set to point to the pathname of + * the file we tried to read - it should be freed by our caller - + * and "*errno_return" is set to the error. + */ +void read_filter_list(filter_list_type_t list_type, char **pref_path_return, + int *errno_return); + +/* + * Get a pointer to the first entry in a filter list. + */ +GList *get_filter_list_first(filter_list_type_t list); + +/* + * Add a new filter to the end of a list. + * Returns a pointer to the newly-added entry. + */ +GList *add_to_filter_list(filter_list_type_t list, const char *name, + const char *expression); + +/* + * Remove a filter from a list. + */ +void remove_from_filter_list(filter_list_type_t list, GList *fl_entry); + +/* + * Write out a list of filters. + * + * On success, "*pref_path_return" is set to NULL. + * On error, "*pref_path_return" is set to point to the pathname of + * the file we tried to read - it should be freed by our caller - + * and "*errno_return" is set to the error. + */ +void save_filter_list(filter_list_type_t list_type, char **pref_path_return, + int *errno_return); + +/* + * Clone the filter list so it can be edited. + */ +void copy_filter_list(filter_list_type_t dest_type, filter_list_type_t src_type); + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/g711.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/g711.h new file mode 100644 index 00000000..b55bd13c --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/g711.h @@ -0,0 +1,30 @@ +/* + * g711.h + * + * Definitions for routines for u-law, A-law and linear PCM conversions + * + * $Id: g711.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +unsigned char linear2alaw( int ); +int alaw2linear( unsigned char ); +unsigned char linear2ulaw( int ); +int ulaw2linear( unsigned char ); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/getopt.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/getopt.h new file mode 100644 index 00000000..45541f5a --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/getopt.h @@ -0,0 +1,129 @@ +/* Declarations for getopt. + Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef _GETOPT_H +#define _GETOPT_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; + +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ +#if __STDC__ + const char *name; +#else + char *name; +#endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +#if __STDC__ +#if defined(__GNU_LIBRARY__) +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int argc, char *const *argv, const char *shortopts); +#else /* not __GNU_LIBRARY__ */ +extern int getopt (); +#endif /* not __GNU_LIBRARY__ */ +extern int getopt_long (int argc, char *const *argv, const char *shortopts, + const struct option *longopts, int *longind); +extern int getopt_long_only (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind, + int long_only); +#else /* not __STDC__ */ +extern int getopt (); +extern int getopt_long (); +extern int getopt_long_only (); + +extern int _getopt_internal (); +#endif /* not __STDC__ */ + +#ifdef __cplusplus +} +#endif + +#endif /* _GETOPT_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/globals.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/globals.h new file mode 100644 index 00000000..ff6ac7f3 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/globals.h @@ -0,0 +1,37 @@ +/* globals.h + * Global defines, etc. + * + * $Id: globals.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __GLOBALS_H__ +#define __GLOBALS_H__ + +#include "file.h" +#include + +extern capture_file cfile; +#ifdef HAVE_LIBPCAP +/** @todo move this to the gtk dir */ +extern gboolean auto_scroll_live; +#endif + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/inet_v6defs.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/inet_v6defs.h new file mode 100644 index 00000000..22f82abc --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/inet_v6defs.h @@ -0,0 +1,54 @@ +/* inet_v6defs.h + * + * $Id: inet_v6defs.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __INET_V6DEFS_H__ +#define __INET_V6DEFS_H__ + +/* + * Versions of "inet_pton()" and "inet_ntop()", for the benefit of OSes that + * don't have it. + */ +extern int inet_pton(int af, const char *src, void *dst); +#ifndef HAVE_INET_NTOP_PROTO +extern const char *inet_ntop(int af, const void *src, char *dst, + size_t size); +#endif + +/* + * Those OSes may also not have AF_INET6, so declare it here if it's not + * already declared, so that we can pass it to "inet_ntop()" and "inet_pton()". + */ +#ifndef AF_INET6 +#define AF_INET6 127 /* pick a value unlikely to duplicate an existing AF_ value */ +#endif + +/* + * And if __P isn't defined, define it here, so we can use it in + * "inet_ntop.c" and "inet_pton.c" (rather than having to change them + * not to use it). + */ +#ifndef __P +#define __P(args) args +#endif + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/isprint.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/isprint.h new file mode 100644 index 00000000..8a2d0a25 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/isprint.h @@ -0,0 +1,46 @@ +/* isprint.h + * Temporary redefinition of "isprint()" to cope with GTK+ 1.3 and + * later using UTF-8 strings + * + * $Id: isprint.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ISPRINT_H__ +#define __ISPRINT_H__ + +#if GLIB_MAJOR_VERSION >= 2 +/* + * XXX - "isprint()" can return "true" for non-ASCII characters, but + * those don't work with GTK+ 1.3 or later, as they take UTF-8 strings + * as input. Until we fix up Wireshark to properly handle non-ASCII + * characters in all output (both GUI displays and text printouts) + * in those versions of GTK+, we work around the problem by escaping + * all characters that aren't printable ASCII. + * + * We don't know what version of GTK+ we're using, as dissectors don't + * use any GTK+ stuff; we use GLib as a proxy for that, with GLib 2.x + * implying GTK+ 1.3 or later (we don't support GLib 1.3[.x]). + */ +#undef isprint +#define isprint(c) (c >= 0x20 && c < 0x7f) +#endif + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/log.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/log.h new file mode 100644 index 00000000..569c4c20 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/log.h @@ -0,0 +1,42 @@ +/* log.h + * log output definitions + * + * $Id: log.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __LOG_H__ +#define __LOG_H__ + +/* capture domain (except for capture child, see below) */ +#define LOG_DOMAIN_CAPTURE "Capture" + +/* capture child domain (the capture child might also contain file domain messages!) */ +#define LOG_DOMAIN_CAPTURE_CHILD "CaptureChild" + +/* main domain */ +#define LOG_DOMAIN_MAIN "Main" + +/* enable very verbose capture log debug output */ +/* (might slightly degrade performance) */ +/*#define LOG_CAPTURE_VERBOSE*/ + + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/main_window.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/main_window.h new file mode 100644 index 00000000..eb196b10 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/main_window.h @@ -0,0 +1,41 @@ +/* main_window.h + * Definitions for main window routines with toolkit-independent APIs but + * toolkit-dependent implementations. + * + * $Id: main_window.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __MAIN_WINDOW_H__ +#define __MAIN_WINDOW_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** Tell the main window that we have a capture file (or not) */ +extern void +main_set_for_capture_file(gboolean have_capture_file_in); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __MAIN_WINDOW_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/menu.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/menu.h new file mode 100644 index 00000000..99cf2a90 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/menu.h @@ -0,0 +1,64 @@ +/* menu.h + * Definitions for menu routines with toolkit-independent APIs but + * toolkit-dependent implementations. + * + * $Id: menu.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __MENU_H__ +#define __MENU_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* Add a new recent capture filename to the "Recent Files" submenu + (duplicates will be ignored) */ +void add_menu_recent_capture_file(gchar *file); + +/* Routines to enable or disable sets of menu items. */ + +/* Enable or disable menu items based on whether you have a capture file + you've finished reading and, if you have one, whether it's been saved + and whether it could be saved except by copying the raw packet data. */ +void set_menus_for_capture_file(capture_file *); + +/* Enable or disable menu items based on whether there's a capture in + progress. */ +void set_menus_for_capture_in_progress(gboolean); + +/* Enable or disable menu items based on whether you have some captured + packets. */ +void set_menus_for_captured_packets(gboolean); + +/* Enable or disable menu items based on whether a packet is selected. */ +void set_menus_for_selected_packet(capture_file *cf); + +/* Enable or disable menu items based on whether a tree row is selected + and and on whether a "Match Selected" can be done. */ +void set_menus_for_selected_tree_row(capture_file *cf); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __MENU_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/merge.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/merge.h new file mode 100644 index 00000000..22620aae --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/merge.h @@ -0,0 +1,125 @@ +/* merge.h + * Definitions for routines for merging files. + * + * $Id: merge.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __MERGE_H__ +#define __MERGE_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef enum { + PACKET_PRESENT, + PACKET_NOT_PRESENT, + AT_EOF, + GOT_ERROR +} in_file_state_e; + +/** + * Structures to manage our input files. + */ +typedef struct merge_in_file_s { + const char *filename; + wtap *wth; + gint64 data_offset; + in_file_state_e state; + gint64 size; /* file size */ +} merge_in_file_t; + +/** Open a number of input files to merge. + * + * @param in_file_count number of entries in in_file_names and in_files + * @param in_file_names filenames of the input files + * @param in_files input file array to be filled (>= sizeof(merge_in_file_t) * in_file_count) + * @param err wiretap error, if failed + * @param err_info wiretap error string, if failed + * @param err_fileno file on which open failed, if failed + * @return TRUE if all files could be opened, FALSE otherwise + */ +extern gboolean +merge_open_in_files(int in_file_count, char *const *in_file_names, + merge_in_file_t **in_files, int *err, gchar **err_info, + int *err_fileno); + +/** Close the input files again. + * + * @param in_file_count number of entries in in_files + * @param in_files input file array to be closed + */ +extern void +merge_close_in_files(int in_file_count, merge_in_file_t in_files[]); + +/** Try to get the frame type from the input files. + * + * @param in_file_count number of entries in in_files + * @param in_files input file array + * @return the frame type + */ +extern int +merge_select_frame_type(int in_file_count, merge_in_file_t in_files[]); + +/** Try to get the snapshot length from the input files. + * + * @param in_file_count number of entries in in_files + * @param in_files input file array + * @return the snapshot length + */ +extern int +merge_max_snapshot_length(int in_file_count, merge_in_file_t in_files[]); + +/** Read the next packet, in chronological order, from the set of files to + * be merged. + * + * @param in_file_count number of entries in in_files + * @param in_files input file array + * @param err wiretap error, if failed + * @param err_info wiretap error string, if failed + * @return pointer to wtap for file from which that packet came, or NULL on + * error or EOF + */ +extern wtap * +merge_read_packet(int in_file_count, merge_in_file_t in_files[], int *err, + gchar **err_info); + + +/** Read the next packet, in file sequence order, from the set of files + * to be merged. + * + * @param in_file_count number of entries in in_files + * @param in_files input file array + * @param err wiretap error, if failed + * @param err_info wiretap error string, if failed + * @return pointer to wtap for file from which that packet came, or NULL on + * error or EOF + */ +extern wtap * +merge_append_read_packet(int in_file_count, merge_in_file_t in_files[], + int *err, gchar **err_info); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __MERGE_H__ */ + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/mkstemp.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/mkstemp.h new file mode 100644 index 00000000..be2cae0f --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/mkstemp.h @@ -0,0 +1,24 @@ +/* Copyright (C) 1991, 1992, 1996, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + + +/* Generate a unique temporary file name from TEMPLATE. + The last six characters of TEMPLATE must be "XXXXXX"; + they are replaced with a string that makes the filename unique. + Returns a file descriptor open on the file for reading and writing. */ +int mkstemp (char *template); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/packet-range.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/packet-range.h new file mode 100644 index 00000000..64702d14 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/packet-range.h @@ -0,0 +1,101 @@ +/* packet-range.h + * Packet range routines (save, print, ...) + * + * $Id: packet-range.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Dick Gooris + * Ulf Lamping + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PACKET_RANGE_H__ +#define __PACKET_RANGE_H__ + +#include + +#include + +#include + +extern guint32 curr_selected_frame; + +typedef enum { + range_process_all, + range_process_selected, + range_process_marked, + range_process_marked_range, + range_process_user_range +} packet_range_e; + +typedef struct packet_range_tag { + /* values coming from the UI */ + packet_range_e process; /* which range to process */ + gboolean process_filtered; /* captured or filtered packets */ + + /* user specified range(s) and, if null, error status */ + range_t *user_range; + convert_ret_t user_range_status; + + /* calculated values */ + guint32 selected_packet; /* the currently selected packet */ + + /* current packet counts (captured) */ + /* cfile.count */ /* packets in capture file */ + /* cfile.marked_count */ /* packets marked */ + guint32 mark_range_cnt; /* packets in marked range */ + guint32 user_range_cnt; /* packets in user specified range */ + + /* current packet counts (displayed) */ + guint32 displayed_cnt; + guint32 displayed_marked_cnt; + guint32 displayed_mark_range_cnt; + guint32 displayed_user_range_cnt; + + /* "enumeration" values */ + gboolean marked_range_active; /* marked range is currently processed */ + guint32 marked_range_left; /* marked range packets left to do */ + gboolean selected_done; /* selected packet already processed */ +} packet_range_t; + +typedef enum { + range_process_this, /* process this packet */ + range_process_next, /* skip this packet, process next */ + range_processing_finished /* stop processing, required packets done */ +} range_process_e; + +/* init the range structure */ +extern void packet_range_init(packet_range_t *range); + +/* check whether the packet range is OK */ +extern convert_ret_t packet_range_check(packet_range_t *range); + +/* init the processing run */ +extern void packet_range_process_init(packet_range_t *range); + +/* do we have to process all packets? */ +extern gboolean packet_range_process_all(packet_range_t *range); + +/* do we have to process this packet? */ +extern range_process_e packet_range_process_packet(packet_range_t *range, frame_data *fdata); + +/* convert user given string to the internal user specified range representation */ +extern void packet_range_convert_str(packet_range_t *range, const gchar *es); + +#endif /* __PACKET_RANGE_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/pcapio.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/pcapio.h new file mode 100644 index 00000000..a675ce30 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/pcapio.h @@ -0,0 +1,44 @@ +/* pcapio.h + * Declarations of our own routins for writing libpcap files. + * + * $Id: pcapio.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * Derived from code in the Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* Returns a FILE * to write to on success, NULL on failure; sets "*err" to + an error code, or 0 for a short write, on failure */ +extern FILE * +libpcap_fdopen(int fd, int linktype, int snaplen, long *bytes_written, + int *err); + +/* Write a record for a packet to a dump file. + Returns TRUE on success, FALSE on failure. */ +extern gboolean +libpcap_write_packet(FILE *fp, const struct pcap_pkthdr *phdr, const u_char *pd, + long *bytes_written, int *err); + +extern gboolean +libpcap_dump_flush(FILE *pd, int *err); + +extern gboolean +libpcap_dump_close(FILE *pd, int *err); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/print.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/print.h new file mode 100644 index 00000000..a337dffc --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/print.h @@ -0,0 +1,148 @@ +/* print.h + * Definitions for printing packet analysis trees. + * + * $Id: print.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Gilbert Ramirez + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PRINT_H__ +#define __PRINT_H__ + +#include + +#include "packet-range.h" + +/* + * Print stream code; this provides a "print stream" class with subclasses + * of various sorts. Additional subclasses might be implemented elsewhere. + */ +struct print_stream; + +typedef struct print_stream_ops { + gboolean (*print_preamble)(struct print_stream *self, gchar *filename); + gboolean (*print_line)(struct print_stream *self, int indent, + const char *line); + gboolean (*print_bookmark)(struct print_stream *self, + const gchar *name, const gchar *title); + gboolean (*new_page)(struct print_stream *self); + gboolean (*print_finale)(struct print_stream *self); + gboolean (*destroy)(struct print_stream *self); +} print_stream_ops_t; + +typedef struct print_stream { + const print_stream_ops_t *ops; + void *data; +} print_stream_t; + +extern print_stream_t *print_stream_text_new(int to_file, const char *dest); +extern print_stream_t *print_stream_text_stdio_new(FILE *fh); +extern print_stream_t *print_stream_ps_new(int to_file, const char *dest); +extern print_stream_t *print_stream_ps_stdio_new(FILE *fh); + +extern gboolean print_preamble(print_stream_t *self, gchar *filename); +extern gboolean print_line(print_stream_t *self, int indent, const char *line); +extern gboolean print_bookmark(print_stream_t *self, const gchar *name, + const gchar *title); +extern gboolean new_page(print_stream_t *self); +extern gboolean print_finale(print_stream_t *self); +extern gboolean destroy_print_stream(print_stream_t *self); + +/* print output format */ +typedef enum { + PR_FMT_TEXT, /* plain text */ + PR_FMT_PS /* postscript */ +} print_format_e; + +/* print_range, enum which frames should be printed */ +typedef enum { + print_range_selected_only, /* selected frame(s) only (currently only one) */ + print_range_marked_only, /* marked frames only */ + print_range_all_displayed, /* all frames currently displayed */ + print_range_all_captured /* all frames in capture */ +} print_range_e; + +/* print_dissections, enum how the dissections should be printed */ +typedef enum { + print_dissections_none, /* no dissections at all */ + print_dissections_collapsed, /* no dissection details */ + print_dissections_as_displayed, /* details as displayed */ + print_dissections_expanded /* all dissection details */ +} print_dissections_e; + +typedef struct { + print_stream_t *stream; /* the stream to which we're printing */ + print_format_e format; /* plain text or PostScript */ + gboolean to_file; /* TRUE if we're printing to a file */ + char *file; /* file output pathname */ + char *cmd; /* print command string (not win32) */ + packet_range_t range; + + gboolean print_summary; /* TRUE if we should just print summary; + FALSE if we should print protocol tree. */ + print_dissections_e print_dissections; + gboolean print_hex; /* TRUE if we should also print hex data; + FALSE if we should print only if not dissected. */ + gboolean print_formfeed; /* TRUE if a formfeed should be printed + before each new packet */ +} print_args_t; + +/* + * Print user selected list of fields + */ +struct _output_fields; +typedef struct _output_fields output_fields_t; + +extern output_fields_t* output_fields_new(void); +extern void output_fields_free(output_fields_t* info); +extern void output_fields_add(output_fields_t* info, const gchar* field); +extern gsize output_fields_num_fields(output_fields_t* info); +extern gboolean output_fields_set_option(output_fields_t* info, gchar* option); +extern void output_fields_list_options(FILE *fh); +/* + * Higher-level packet-printing code. + */ + +extern gboolean proto_tree_print(print_args_t *print_args, epan_dissect_t *edt, + print_stream_t *stream); +extern gboolean print_hex_data(print_stream_t *stream, epan_dissect_t *edt); + +extern void write_pdml_preamble(FILE *fh); +extern void proto_tree_write_pdml(epan_dissect_t *edt, FILE *fh); +extern void write_pdml_finale(FILE *fh); + +extern void write_psml_preamble(FILE *fh); +extern void proto_tree_write_psml(epan_dissect_t *edt, FILE *fh); +extern void write_psml_finale(FILE *fh); + +extern void write_csv_preamble(FILE *fh); +extern void proto_tree_write_csv(epan_dissect_t *edt, FILE *fh); +extern void write_csv_finale(FILE *fh); + +extern void write_carrays_preamble(FILE *fh); +extern void proto_tree_write_carrays(const guint8 *pd, guint32 len, guint32 num, FILE *fh); +extern void write_carrays_finale(FILE *fh); + +extern void write_fields_preamble(output_fields_t* fields, FILE *fh); +extern void proto_tree_write_fields(output_fields_t* fields, epan_dissect_t *edt, FILE *fh); +extern void write_fields_finale(output_fields_t* fields, FILE *fh); + +#endif /* print.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/progress_dlg.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/progress_dlg.h new file mode 100644 index 00000000..0303230e --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/progress_dlg.h @@ -0,0 +1,94 @@ +/* progress_dlg.h + * Definitions for progress dialog box routines + * + * $Id: progress_dlg.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PROGRESS_DLG_H__ +#define __PROGRESS_DLG_H__ + +/** @file + * Progress (modal) dialog box routines. + * @ingroup dialog_group + */ + +/** Progress dialog data. */ +struct progdlg; + +/** Progress dialog data. */ +typedef struct progdlg progdlg_t; + +/** + * Create and pop up the progress dialog. Allocates a "progdlg_t" + * and initialize it to contain all information the implementation + * needs in order to manipulate the dialog, and return a pointer to + * it. + * + * @param task_title the task to do, e.g. "Loading" + * @param item_title the item to do, e.g. "capture.cap" + * @param terminate_is_stop TRUE if the operation can't be cancelled, just + * stopped (i.e., it has a "Stop" button and clicking it doesn't undo + * anything already done), FALSE if it can + * @param stop_flag a pointer to a Boolean variable that will be + * set to TRUE if the user hits that button + * @return the newly created progress dialog + */ +progdlg_t *create_progress_dlg(const gchar *task_title, const gchar *item_title, + gboolean terminate_is_stop, gboolean *stop_flag); + +/** + * Create a progress dialog, but only if it's not likely to disappear + * immediately. This can be disconcerting for the user. + * + * @param task_title the task to do, e.g. "Loading" + * @param item_title the item to do, e.g. "capture.cap" + * @param terminate_is_stop TRUE if the operation can't be cancelled, just + * stopped (i.e., it has a "Stop" button and clicking it doesn't undo + * anything already done), FALSE if it can + * @param stop_flag a pointer to a Boolean variable that will be + * set to TRUE if the user hits that button + * @param start_time a pointer to a GTimeVal structure which holds + * the time at which the caller started to process the data + * @param progress the current progress (0..1) + * @return the newly created progress dialog + */ +progdlg_t * +delayed_create_progress_dlg(const gchar *task_title, const gchar *item_title, + gboolean terminate_is_stop, gboolean *stop_flag, + const GTimeVal *start_time, gfloat progress); + +/** + * Update the progress information of the progress dialog box. + * + * @param dlg the progress dialog from create_progress_dlg() + * @param percentage the current percentage value (0..1) + * @param status the new status string to show, e.g. "3000KB of 6000KB" + */ +void update_progress_dlg(progdlg_t *dlg, gfloat percentage, const gchar *status); + +/** + * Destroy the progress bar. + * + * @param dlg the progress dialog from create_progress_dlg() + */ +void destroy_progress_dlg(progdlg_t *dlg); + +#endif /* __PROGRESS_DLG_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/proto_hier_stats.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/proto_hier_stats.h new file mode 100644 index 00000000..10fb1e39 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/proto_hier_stats.h @@ -0,0 +1,51 @@ +/* proto_hier_stats.h + * + * $Id: proto_hier_stats.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef PROTO_HIER_STATS_H +#define PROTO_HIER_STATS_H + +#include + +typedef struct { + header_field_info *hfinfo; + guint num_pkts_total; + guint num_pkts_last; + guint num_bytes_total; + guint num_bytes_last; +} ph_stats_node_t; + + +typedef struct { + guint tot_packets; + guint tot_bytes; + GNode *stats_tree; + double first_time; /* seconds (msec resolution) of first packet */ + double last_time; /* seconds (msec resolution) of last packet */ +} ph_stats_t; + + +ph_stats_t* ph_stats_new(void); + +void ph_stats_free(ph_stats_t *ps); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ps.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ps.h new file mode 100644 index 00000000..ceafdff6 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ps.h @@ -0,0 +1,35 @@ +/* ps.h + * Definitions for generating PostScript(R) packet output. + * + * $Id: ps.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Gilbert Ramirez + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PS_H__ +#define __PS_H__ + +/* Functions in ps.c; automatically generated by rdps */ + +void print_ps_preamble(FILE *); +void print_ps_finale(FILE *); + +#endif /* ps.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/register.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/register.h new file mode 100644 index 00000000..2b8906ea --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/register.h @@ -0,0 +1,48 @@ +/* register.h + * Definitions for protocol registration + * + * $Id: register.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __REGISTER_H__ +#define __REGISTER_H__ + +#include + +typedef enum { + RA_NONE, /* for initialization */ + RA_DISSECTORS, /* Initializing dissectors */ + RA_LISTENERS, /* Tap listeners */ + RA_REGISTER, /* register */ + RA_PLUGIN_REGISTER, /* plugin register */ + RA_HANDOFF, /* handoff */ + RA_PLUGIN_HANDOFF, /* plugin handoff */ + RA_PREFERENCES, /* module preferences */ + RA_CONFIGURATION /* configuration files */ +} register_action_e; + +typedef void (*register_cb)(register_action_e action, const char *message, gpointer client_data); + +extern void register_all_protocols(register_cb cb, gpointer client_data); +extern void register_all_protocol_handoffs(register_cb cb, gpointer client_data); +extern void register_all_tap_listeners(void); +extern gulong register_count(void); +#endif /* __REGISTER_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ringbuffer.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ringbuffer.h new file mode 100644 index 00000000..85178edc --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ringbuffer.h @@ -0,0 +1,53 @@ +/* ringbuffer.h + * Definitions for capture ringbuffer files + * + * $Id: ringbuffer.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __RINGBUFFER_H__ +#define __RINGBUFFER_H__ + +#ifdef HAVE_LIBPCAP + +#include +#include "file.h" +#include "wiretap/wtap.h" + +#define RINGBUFFER_UNLIMITED_FILES 0 +/* minimum number of ringbuffer files */ +#define RINGBUFFER_MIN_NUM_FILES 0 +/* maximum number of ringbuffer files */ +/* (only to avoid crashes on very large numbers) */ +#define RINGBUFFER_MAX_NUM_FILES 10000 + +int ringbuf_init(const char *capture_name, guint num_files); +const gchar *ringbuf_current_filename(void); +FILE *ringbuf_init_libpcap_fdopen(int linktype, int snaplen, + long *bytes_written, int *err); +gboolean ringbuf_switch_file(FILE **pdh, gchar **save_file, int *save_file_fd, + long *bytes_written, int *err); +gboolean ringbuf_libpcap_dump_close(gchar **save_file, int *err); +void ringbuf_free(void); +void ringbuf_error_cleanup(void); + +#endif /* HAVE_LIBPCAP */ + +#endif /* ringbuffer.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/simple_dialog.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/simple_dialog.h new file mode 100644 index 00000000..fcd35ece --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/simple_dialog.h @@ -0,0 +1,184 @@ +/* simple_dialog.h + * Definitions for alert box routines with toolkit-independent APIs but + * toolkit-dependent implementations. + * + * $Id: simple_dialog.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __DIALOG_H__ +#define __DIALOG_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** @file + * Simple dialog box. + * @ingroup dialog_group + */ + + +/** Dialog types. */ +typedef enum { + ESD_TYPE_INFO, /**< tells the user something they should know, but not requiring + any action; the only button should be "OK" */ + ESD_TYPE_WARN, /**< tells the user about a problem; the only button should be "OK" */ + ESD_TYPE_CONFIRMATION, /**< asks the user for confirmation; there should be more than + one button */ + ESD_TYPE_ERROR, /**< tells the user about a serious problem; the only button should be "OK" */ + ESD_TYPE_STOP /**< tells the user a stop action is in progress, there should be no button */ +} ESD_TYPE_E; + +/** display no buttons at all */ +#define ESD_BTN_NONE 0x00 +/** display an "Ok" button */ +#define ESD_BTN_OK 0x01 +/** display a "Cancel" button */ +#define ESD_BTN_CANCEL 0x02 +/** display a "Yes" button */ +#define ESD_BTN_YES 0x04 +/** display a "No" button */ +#define ESD_BTN_NO 0x08 +/** display a "Clear" button */ +#define ESD_BTN_CLEAR 0x10 +/** display a "Save" button */ +#define ESD_BTN_SAVE 0x20 +/** display a "Continue without Saving" button */ +#define ESD_BTN_DONT_SAVE 0x40 + +/** Standard button combination "Ok" + "Cancel". */ +#define ESD_BTNS_OK_CANCEL (ESD_BTN_OK|ESD_BTN_CANCEL) +/** Standard button combination "Yes" + "No". */ +#define ESD_BTNS_YES_NO (ESD_BTN_YES|ESD_BTN_NO) +/** Standard button combination "Yes" + "No" + "Cancel". */ +#define ESD_BTNS_YES_NO_CANCEL (ESD_BTN_YES|ESD_BTN_NO|ESD_BTN_CANCEL) +/** Standard button combination "No" + "Cancel" + "Save". */ +#define ESD_BTNS_SAVE_DONTSAVE_CANCEL (ESD_BTN_DONT_SAVE|ESD_BTN_CANCEL|ESD_BTN_SAVE) + +#if __GNUC__ >= 2 +/** Create and show a simple dialog. + * + * @param type type of dialog + * @param btn_mask the buttons to display + * @param msg_format printf like message format + * @param ... printf like parameters + * @return the newly created dialog + */ +extern gpointer simple_dialog(ESD_TYPE_E type, gint btn_mask, + const gchar *msg_format, ...) + __attribute__((format (printf, 3, 4))); +/** Create and show a simple dialog using a va_list. + * + * @param type type of dialog + * @param btn_mask the buttons to display + * @param msg_format printf like message format + * @param ap parameters + * @return the newly created dialog + */ +extern gpointer vsimple_dialog(ESD_TYPE_E type, gint btn_mask, + const gchar *msg_format, va_list ap); +#else +/** Create and show a simple dialog. + * + * @param type type of dialog + * @param btn_mask the buttons to display + * @param msg_format printf like message format + * @param ... printf like parameters + * @return the newly created dialog + */ +extern gpointer simple_dialog(ESD_TYPE_E type, gint btn_mask, + const gchar *msg_format, ...); +/** Create and show a simple dialog using a va_list. + * + * @param type type of dialog + * @param btn_mask the buttons to display + * @param msg_format printf like message format + * @param ap parameters + * @return the newly created dialog + */ +extern gpointer vsimple_dialog(ESD_TYPE_E type, gint btn_mask, + const gchar *msg_format, va_list ap); +#endif + +/** Callback function type for simple_dialog_set_cb() */ +typedef void (* simple_dialog_cb_t) (gpointer dialog, gint btn, gpointer data); + +/** Set the callback function for the dialog, called when a button was pressed. + * + * @param dialog the dialog from simple_dialog() + * @param callback_fct the callback function to set + * @param data data to be passed to the callback function + */ +extern void simple_dialog_set_cb(gpointer dialog, simple_dialog_cb_t callback_fct, gpointer data); + +/** Close the dialog, useful for "no button" dialogs. + * + * @param dialog the dialog to close from simple_dialog() + */ +extern void simple_dialog_close(gpointer dialog); + +/** Add a check button to the dialog (e.g. "Don't show this message again") + * + * @param dialog the dialog from simple_dialog() + * @param text the text to display + */ +extern void simple_dialog_check_set(gpointer dialog, gchar *text); + +/** Get the check buttons state. + * + * @param dialog the dialog from simple_dialog() + * @return current button state (TRUE is checked) + */ +extern gboolean simple_dialog_check_get(gpointer dialog); + +/** Surround the primary dialog message text by + * simple_dialog_primary_start() and simple_dialog_primary_end(). + * To highlight the first sentence (will take effect on GTK2 only). + */ +extern char *simple_dialog_primary_start(void); +/** Surround the primary dialog message text by + * simple_dialog_primary_start() and simple_dialog_primary_end(). + * To highlight the first sentence (will take effect on GTK2 only). + */ +extern char *simple_dialog_primary_end(void); + +/** Escape the message text, if it probably contains Pango escape sequences. + * For example html like tags starting with a <. + * + * @param msg the string to escape + * @return the escaped message text, must be freed with g_free() later + */ +extern char *simple_dialog_format_message(const char *msg); + +/** + * Display all queued messages. + * If a routine is called to display a dialog before there are any windows + * open, information to use to display the dialog is queued up. This + * routine should be called once there are windows open, so that the queued + * up dialogs are displayed on top of those windows. + */ +extern void display_queued_messages(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __DIALOG_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/stat_menu.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/stat_menu.h new file mode 100644 index 00000000..1a7bd7f1 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/stat_menu.h @@ -0,0 +1,64 @@ +/* stat_menu.h + * Menu definitions for use by stats + * + * $Id: stat_menu.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __STATMENU_H__ +#define __STATMENU_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** @file + * Add a new menu item for a stat. + */ + +/* + * XXX - defines stuff usable regardless of the GUI toolkit. Right now, + * that's only the menu group, which is used by tap_dfilter_dlg.h. + * + * XXX - stats should be able to register additional menu groups, although + * the question then would be "in what order should they appear in the menu?" + */ + +/** The menu group this stat should be registered in. */ +typedef enum { + REGISTER_STAT_GROUP_NONE, + REGISTER_STAT_GROUP_GENERIC, + REGISTER_STAT_GROUP_CONVERSATION_LIST, + REGISTER_STAT_GROUP_ENDPOINT_LIST, + REGISTER_STAT_GROUP_RESPONSE_TIME, + REGISTER_STAT_GROUP_TELEPHONY, + /* XXX - split into telephony and VoIP? */ + REGISTER_ANALYZE_GROUP_NONE, + REGISTER_ANALYZE_GROUP_CONVERSATION_FILTER +#ifdef HAVE_LUA_5_1 + ,REGISTER_TOOLS_GROUP_NONE +#endif +} register_stat_group_t; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __STATMENU_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/statusbar.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/statusbar.h new file mode 100644 index 00000000..cde19b35 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/statusbar.h @@ -0,0 +1,56 @@ +/* statusbar.h + * Definitions for status bar UI routines + * + * $Id: statusbar.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __STATUSBAR_H__ +#define __STATUSBAR_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * Push a message referring to file access onto the statusbar. + */ +void statusbar_push_file_msg(const gchar *msg); + +/* + * Pop a message referring to file access off the statusbar. + */ +void statusbar_pop_file_msg(void); + +/* + * Push a message referring to the currently-selected field onto the statusbar. + */ +void statusbar_push_field_msg(const gchar *msg); + +/* + * Pop a message referring to the currently-selected field off the statusbar. + */ +void statusbar_pop_field_msg(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __STATUSBAR_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/strerror.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/strerror.h new file mode 100644 index 00000000..2f509795 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/strerror.h @@ -0,0 +1,33 @@ +/* strerror.h + * + * $Id: strerror.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __STRERROR_H__ +#define __STRERROR_H__ + +/* + * Version of "strerror()", for the benefit of OSes that don't have it + * (e.g., SunOS 4.x). + */ +extern char *strerror(int); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/strptime.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/strptime.h new file mode 100644 index 00000000..0bfc58b1 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/strptime.h @@ -0,0 +1,32 @@ +/* strptime.h + * + * $Id: strptime.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __STRPTIME_H__ +#define __STRPTIME_H__ + +/* + * Version of "strptime()", for the benefit of OSes that don't have it. + */ +extern char *strptime(const char *, const char *, struct tm *); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/summary.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/summary.h new file mode 100644 index 00000000..1cc43328 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/summary.h @@ -0,0 +1,76 @@ +/* summary.h + * Definitions for capture file summary data + * + * $Id: summary.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __SUMMARY_H__ +#define __SUMMARY_H__ + +#ifdef HAVE_LIBPCAP +#include "capture.h" +#endif + +typedef struct _summary_tally { + guint64 bytes; /* total bytes */ + double start_time; /* seconds, with msec resolution */ + double stop_time; /* seconds, with msec resolution */ + double elapsed_time; /* seconds, with msec resolution, + includes time before first packet + and after last packet */ + int marked_count; /* number of marked packets */ + guint64 marked_bytes; /* total bytes in the marked packets */ + double marked_start; /* time in seconds, with msec resolution */ + double marked_stop; /* time in seconds, with msec resolution */ + int packet_count; /* total number of packets in trace */ + int filtered_count; /* number of filtered packets */ + guint64 filtered_bytes; /* total bytes in the filtered packets */ + double filtered_start; /* time in seconds, with msec resolution */ + double filtered_stop; /* time in seconds, with msec resolution */ + const char *filename; + gint64 file_length; /* file length in bytes */ + int encap_type; /* wiretap encapsulation type */ + gboolean has_snap; /* TRUE if maximum capture packet length is known */ + int snap; /* Maximum captured packet length */ + gboolean drops_known; /* TRUE if number of packet drops is known */ + guint64 drops; /* number of packet drops */ + const char *dfilter; /* display filter */ + + /* capture related, use summary_fill_in_capture() to get values */ + const char *cfilter; /* capture filter */ + const char *iface; /* interface name */ + const char *iface_descr;/* descriptive interface name */ +} summary_tally; + +extern void +summary_fill_in(capture_file *cf, summary_tally *st); + +#ifdef HAVE_LIBPCAP +extern void +summary_fill_in_capture(capture_options *capture_opts, summary_tally *st); +#endif + +#endif /* summary.h */ + + + + + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/svnversion.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/svnversion.h new file mode 100644 index 00000000..b3f53a6d --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/svnversion.h @@ -0,0 +1 @@ +/* #define SVNVERSION "" */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/sync_pipe.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/sync_pipe.h new file mode 100644 index 00000000..71d91ccd --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/sync_pipe.h @@ -0,0 +1,80 @@ +/* sync_pipe.h + * Low-level synchronization pipe routines for use by Wireshark/TShark + * and dumpcap + * + * $Id: sync_pipe.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +/** @file + * + * Low-level sync pipe interfaces. + */ + +#ifndef __SYNC_PIPE_H__ +#define __SYNC_PIPE_H__ + + +/* + * Maximum length of sync pipe message data. Must be < 2^24, as the + * message length is 3 bytes. + * XXX - this must be large enough to handle a Really Big Filter + * Expression, as the error message for an incorrect filter expression + * is a bit larger than the filter expression. + */ +#define SP_MAX_MSG_LEN 4096 + + +/* Size of buffer to hold decimal representation of + signed/unsigned 64-bit int */ +#define SP_DECISIZE 20 + +/* + * Indications sent out on the sync pipe (from child to parent). + */ +#define SP_FILE 'F' /* the name of the recently opened file */ +#define SP_ERROR_MSG 'E' /* error message */ +#define SP_BAD_FILTER 'B' /* error message for bad capture filter */ +#define SP_PACKET_COUNT 'P' /* count of packets captured since last message */ +#define SP_DROPS 'D' /* count of packets dropped in capture */ +/* + * Win32 only: Indications sent out on the signal pipe (from parent to child) + * (UNIX-like sends signals for this) + */ +#define SP_QUIT 'Q' /* "gracefully" capture quit message (SIGUSR1) */ + +/* write a single message header to the recipient pipe */ +extern int +pipe_write_header(int pipe, char indicator, int length); + +/* write a message to the recipient pipe in the standard format + (3 digit message length (excluding length and indicator field), + 1 byte message indicator and the rest is the message). + If msg is NULL, the message has only a length and indicator. */ +extern void +pipe_write_block(int pipe, char indicator, const char *msg); + +/** the child encountered an error, notify the parent */ +extern void +sync_pipe_errmsg_to_parent(int pipe, const char *error_msg, + const char *secondary_error_msg); + +#endif /* sync_pipe.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tap-rtp-common.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tap-rtp-common.h new file mode 100644 index 00000000..b20db362 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tap-rtp-common.h @@ -0,0 +1,49 @@ +/* tap-rtp-common.h + * RTP streams handler functions used by tshark and wireshark + * + * $Id: tap-rtp-common.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Copyright 2008, Ericsson AB + * By Balint Reczey + * + * most functions are copied from gtk/rtp_stream.c and gtk/rtp_analisys.c + * Copyright 2003, Alcatel Business Systems + * By Lars Ruoff + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef TAP_RTP_COMMON_H_INCLUDED +#define TAP_RTP_COMMON_H_INCLUDED + +#include "gtk/rtp_stream.h" + +gint rtp_stream_info_cmp(gconstpointer, gconstpointer); +void rtpstream_reset_cb(void*); +void rtp_write_header(rtp_stream_info_t*, FILE*); +void rtp_write_sample(rtp_sample_t*, FILE*); +int rtpstream_packet(void*, packet_info*, epan_dissect_t *, const void *); + +/* The one and only global rtpstream_tapinfo_t structure for tshark and wireshark. + */ +static rtpstream_tapinfo_t the_tapinfo_struct = + {0, NULL, 0, TAP_ANALYSE, NULL, NULL, NULL, 0, FALSE}; + + +#endif /*TAP_RTP_COMMON_H_INCLUDED*/ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tap_dfilter_dlg.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tap_dfilter_dlg.h new file mode 100644 index 00000000..ae39ce3d --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tap_dfilter_dlg.h @@ -0,0 +1,73 @@ +/* tap_dfilter_dlg.h + * Header file for display filter dialog used by gui taps + * Copyright 2003 Lars Roland + * + * $Id: tap_dfilter_dlg.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * You can easily add a display filter dialog for your gui tap by using + * the following infrastructure: + * + * Define a global structure of tap_dfilter_dlg within your tap source file. + * Initiate it with: + * 1) a title string for the Dialog Window + * 2) the init string, which is the same as the string after "-z" option without + * the filter string and without the separating comma. + * 3) a pointer to the init function of the tap, which will be called when you click + * on the start button in the display filter dialog. + * 4) the index with "-1" + * + * Within register_tap_menu_yourtap(void), call register_dfilter_stat() + * with a pointer to the tap_dfilter_dlg structure, a string for the + * menu item (don't put "..." at the end, register_dfilter_stat() will + * add it for you), and the REGISTER_STAT_GROUP_ value for the stat + * group to which your stat should belong. + * + * Usage: + * + * tap_dfilter_dlg my_tap_dfilter_dlg = {"My Title", "myproto,mytap", gtk_mytap_init, -1}; + * + * register_tap_menu_mytap(void) { + * register_dfilter_stat(&my_tap_dfilter_dlg, "My Menu Item", + * REGISTER_STAT_GROUP_my_group); + * } + * + * See also: h225_ras_srt.c or h225_counter.c + * + */ + +typedef struct _tap_dfilter_dlg { + const char *win_title; /* title */ + const char *init_string; /* the string to call the tap without a filter via "-z" option */ + void (* tap_init_cb)(const char *,void*); /* callback to init function of the tap */ + gint index; /* initiate this value always with "-1" */ +} tap_dfilter_dlg; + +/* + * Register a stat that has a display filter dialog. + * We register it both as a command-line stat and a menu item stat. + */ +void register_dfilter_stat(tap_dfilter_dlg *info, const char *name, + register_stat_group_t group); + +/* This will update the titles of the dialog windows when we load a new capture file. */ +void tap_dfilter_dlg_update (void); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tempfile.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tempfile.h new file mode 100644 index 00000000..ce13a49d --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tempfile.h @@ -0,0 +1,43 @@ +/* tempfile.h + * Declarations of routines to create temporary files + * + * $Id: tempfile.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __TEMPFILE_H__ +#define __TEMPFILE_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* create a tempfile with the given prefix (e.g. "ether") + * namebuf (and namebuflen) should be 128+1 bytes long (BTW: why?) + * returns the file descriptor of the new tempfile and + * the name of the new file in namebuf + */ +int create_tempfile(char *namebuf, int namebuflen, const char *pfx); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TEMPFILE_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/text2pcap.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/text2pcap.h new file mode 100644 index 00000000..4ca4f1fa --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/text2pcap.h @@ -0,0 +1,49 @@ +/**-*-C-*-********************************************************************** + * + * text2pcap.h + * + * Utility to convert an ASCII hexdump into a libpcap-format capture file + * + * (c) Copyright 2001 Ashok Narayanan + * + * $Id: text2pcap.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + *******************************************************************************/ + + +#ifndef TEXT2PCAP_H +#define TEXT2PCAP_H + +typedef enum { + T_BYTE = 1, + T_OFFSET, + T_DIRECTIVE, + T_TEXT, + T_EOL +} token_t; + +void parse_token(token_t token, char *str); + +int yylex(void); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/timestats.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/timestats.h new file mode 100644 index 00000000..7c418f09 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/timestats.h @@ -0,0 +1,54 @@ +/* timestats.h + * Routines and definitions for time statistics + * Copyrigth 2003 Lars Roland + * + * $Id: timestats.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _time_stat +#define _time_stat + +#include +#include "epan/packet_info.h" +#include "epan/nstime.h" + + /* Summary of time statistics*/ +typedef struct _timestat_t { + guint32 num; /* number of samples */ + guint32 min_num; /* frame number of minimum */ + guint32 max_num; /* frame number of maximum */ + nstime_t min; + nstime_t max; + nstime_t tot; + gdouble variance; +} timestat_t; + +/* functions */ + +/* Initialize a timestat_t struct */ +extern void time_stat_init(timestat_t *stats); + +/* Update a timestat_t struct with a new sample */ +extern void time_stat_update(timestat_t *stats, const nstime_t *delta, packet_info *pinfo); + +extern gdouble get_average(const nstime_t *sum, guint32 num); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tools/make-dissector-reg b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tools/make-dissector-reg new file mode 100755 index 00000000..d2efa7c6 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tools/make-dissector-reg @@ -0,0 +1,186 @@ +#! /bin/sh + +# +# $Id: make-dissector-reg 21716 2007-05-07 17:55:42Z gal $ +# + +# +# The first argument is the directory in which the source files live. +# +srcdir="$1" +shift + +# +# The second argument is either "plugin" or "dissectors"; if it's +# "plugin", we build a plugin.c for a plugin, and if it's +# "dissectors", we build a register.c for libwireshark. +# +registertype="$1" +shift +if [ "$registertype" = plugin ] +then + outfile="plugin.c" +elif [ "$registertype" = dissectors ] +then + outfile="register.c" +else + echo "Unknown output type '$registertype'" 1>&2 + exit 1 +fi + +# +# All subsequent arguments are the files to scan. +# +rm -f ${outfile}-tmp +echo '/* Do not modify this file. */' >${outfile}-tmp +echo '/* It is created automatically by the Makefile. */'>>${outfile}-tmp +if [ "$registertype" = plugin ] +then + cat <<"EOF" >>${outfile}-tmp +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "moduleinfo.h" + +#ifndef ENABLE_STATIC +G_MODULE_EXPORT const gchar version[] = VERSION; + +/* Start the functions we need for the plugin stuff */ + +G_MODULE_EXPORT void +plugin_register (void) +{ +EOF +# +# Build code to call all the protocol registration routines. +# +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^void proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp +else + cat <<"EOF" >>${outfile}-tmp +#include "register.h" +void +register_all_protocols(register_cb cb, gpointer client_data) +{ +EOF +# +# Build code to call all the protocol registration routines. +# +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_REGISTER, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^void proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_REGISTER, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp + +fi +echo '}' >>${outfile}-tmp + + +# +# Build code to call all the protocol handoff registration routines. +# +if [ "$registertype" = plugin ] +then + cat <<"EOF" >>${outfile}-tmp +G_MODULE_EXPORT void +plugin_reg_handoff(void) +{ +EOF +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^void proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp +else + cat <<"EOF" >>${outfile}-tmp +void +register_all_protocol_handoffs(register_cb cb, gpointer client_data) +{ +EOF +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_HANDOFF, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp +for f in "$@" +do + if [ -f $f ] + then + srcfile=$f + else + srcfile=$srcdir/$f + fi + grep '^void proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' +done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_HANDOFF, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp +fi +echo '}' >>${outfile}-tmp +if [ "$registertype" = plugin ] +then + echo '#endif' >>${outfile}-tmp +else + cat <<"EOF" >>${outfile}-tmp +gulong register_count(void) +{ +EOF + proto_regs=`grep RA_REGISTER ${outfile}-tmp | wc -l` + handoff_regs=`grep RA_HANDOFF ${outfile}-tmp | wc -l` + echo " return $proto_regs + $handoff_regs;" >>${outfile}-tmp + echo '}' >>${outfile}-tmp +fi +mv ${outfile}-tmp ${outfile} diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tools/make-dissector-reg.py b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tools/make-dissector-reg.py new file mode 100755 index 00000000..c3354279 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tools/make-dissector-reg.py @@ -0,0 +1,238 @@ +#!/usr/bin/env python +# +# Looks for registration routines in the protocol dissectors, +# and assembles C code to call all the routines. +# +# This is a Python version of the make-reg-dotc shell script. +# Running the shell script on Win32 is very very slow because of +# all the process-launching that goes on --- multiple greps and +# seds for each input file. I wrote this python version so that +# less processes would have to be started. +# +# $Id: make-dissector-reg.py 24390 2008-02-19 13:44:02Z wmeier $ + +import os +import sys +import re +import pickle +from stat import * + +# +# The first argument is the directory in which the source files live. +# +srcdir = sys.argv[1] + +# +# The second argument is either "plugin" or "dissectors"; if it's +# "plugin", we build a plugin.c for a plugin, and if it's +# "dissectors", we build a register.c for libwireshark. +# +registertype = sys.argv[2] +if registertype == "plugin": + tmp_filename = "plugin.c-tmp" + final_filename = "plugin.c" + cache_filename = None +elif registertype == "dissectors": + tmp_filename = "register.c-tmp" + final_filename = "register.c" + cache_filename = "register-cache.pkl" +else: + print "Unknown output type '%s'" % registertype + sys.exit(1) + + +# +# All subsequent arguments are the files to scan. +# +files = sys.argv[3:] + +# Create the proper list of filenames +filenames = [] +for file in files: + if os.path.isfile(file): + filenames.append(file) + else: + filenames.append("%s/%s" % (srcdir, file)) + +if len(filenames) < 1: + print "No files found" + sys.exit(1) + + +# Look through all files, applying the regex to each line. +# If the pattern matches, save the "symbol" section to the +# appropriate array. +regs = { + 'proto_reg': [], + 'handoff_reg': [], + } + +# For those that don't know Python, r"" indicates a raw string, +# devoid of Python escapes. +proto_regex0 = r"^(?Pproto_register_[_A-Za-z0-9]+)\s*\([^;]+$" +proto_regex1 = r"void\s+(?Pproto_register_[_A-Za-z0-9]+)\s*\([^;]+$" + +handoff_regex0 = r"^(?Pproto_reg_handoff_[_A-Za-z0-9]+)\s*\([^;]+$" +handoff_regex1 = r"void\s+(?Pproto_reg_handoff_[_A-Za-z0-9]+)\s*\([^;]+$" + +# This table drives the pattern-matching and symbol-harvesting +patterns = [ + ( 'proto_reg', re.compile(proto_regex0) ), + ( 'proto_reg', re.compile(proto_regex1) ), + ( 'handoff_reg', re.compile(handoff_regex0) ), + ( 'handoff_reg', re.compile(handoff_regex1) ), + ] + +# Open our registration symbol cache +cache = None +if cache_filename: + try: + cache_file = open(cache_filename, 'rb') + cache = pickle.load(cache_file) + cache_file.close() + except: + cache = {} + +# Grep +for filename in filenames: + file = open(filename) + cur_mtime = os.fstat(file.fileno())[ST_MTIME] + if cache and cache.has_key(filename): + cdict = cache[filename] + if cur_mtime == cdict['mtime']: +# print "Pulling %s from cache" % (filename) + regs['proto_reg'].extend(cdict['proto_reg']) + regs['handoff_reg'].extend(cdict['handoff_reg']) + file.close() + continue + # We don't have a cache entry + if cache is not None: + cache[filename] = { + 'mtime': cur_mtime, + 'proto_reg': [], + 'handoff_reg': [], + } +# print "Searching %s" % (filename) + for line in file.readlines(): + for action in patterns: + regex = action[1] + match = regex.search(line) + if match: + symbol = match.group("symbol") + sym_type = action[0] + regs[sym_type].append(symbol) + if cache is not None: +# print "Caching %s for %s: %s" % (sym_type, filename, symbol) + cache[filename][sym_type].append(symbol) + file.close() + +if cache is not None and cache_filename is not None: + cache_file = open(cache_filename, 'wb') + pickle.dump(cache, cache_file) + cache_file.close() + +# Make sure we actually processed something +if len(regs['proto_reg']) < 1: + print "No protocol registrations found" + sys.exit(1) + +# Sort the lists to make them pretty +regs['proto_reg'].sort() +regs['handoff_reg'].sort() + +reg_code = open(tmp_filename, "w") + +reg_code.write("/* Do not modify this file. */\n") +reg_code.write("/* It is created automatically by the Makefile. */\n") + +# Make the routine to register all protocols +if registertype == "plugin": + reg_code.write(""" +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "moduleinfo.h" + +#ifndef ENABLE_STATIC +G_MODULE_EXPORT const gchar version[] = VERSION; + +/* Start the functions we need for the plugin stuff */ + +G_MODULE_EXPORT void +plugin_register (void) +{ +"""); +else: + reg_code.write(""" +#include "register.h" +void +register_all_protocols(register_cb cb, gpointer client_data) +{ +"""); + +for symbol in regs['proto_reg']: + if registertype == "plugin": + line = " {extern void %s (void); %s ();}\n" % (symbol, symbol) + else: + line = " {extern void %s (void); if(cb) (*cb)(RA_REGISTER, \"%s\", client_data); %s ();}\n" % (symbol, symbol, symbol) + reg_code.write(line) + +reg_code.write("}\n") + + +# Make the routine to register all protocol handoffs +if registertype == "plugin": + reg_code.write(""" +G_MODULE_EXPORT void +plugin_reg_handoff(void) +{ +"""); +else: + reg_code.write(""" +void +register_all_protocol_handoffs(register_cb cb, gpointer client_data) +{ +"""); + +for symbol in regs['handoff_reg']: + if registertype == "plugin": + line = " {extern void %s (void); %s ();}\n" % (symbol, symbol) + else: + line = " {extern void %s (void); if(cb) (*cb)(RA_HANDOFF, \"%s\", client_data); %s ();}\n" % (symbol, symbol, symbol) + reg_code.write(line) + +reg_code.write("}\n") + +if registertype == "plugin": + reg_code.write("#endif\n"); +else: + reg_code.write(""" +gulong register_count(void) +{ +"""); + + line = " return %d + %d;\n" % (len(regs['proto_reg']), len(regs['handoff_reg'])) + reg_code.write(line) + + reg_code.write(""" +} +"""); + + +# Close the file +reg_code.close() + +# Remove the old final_file if it exists. +try: + os.stat(final_filename) + os.remove(final_filename) +except OSError: + pass + +# Move from tmp file to final file +os.rename(tmp_filename, final_filename) + + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ui_util.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ui_util.h new file mode 100644 index 00000000..fa591a51 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ui_util.h @@ -0,0 +1,79 @@ +/* ui_util.h + * Declarations of UI utility routines; these routines have GUI-independent + * APIs, but GUI-dependent implementations, so that they can be called by + * GUI-independent code to affect the GUI. + * + * $Id: ui_util.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __UI_UTIL_H__ +#define __UI_UTIL_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* gui_utils.c */ + +/* Set the name of the top-level window and its icon. */ +void set_main_window_name(const gchar *); +/* Update the name of the main window if the user-specified decoration + changed. */ +void update_main_window_name(void); +/* update the main window */ +extern void main_window_update(void); +/* exit the main window */ +extern void main_window_exit(void); +/* quit a nested main window */ +extern void main_window_nested_quit(void); +/* quit the main window */ +extern void main_window_quit(void); + +/* read from a pipe (callback) */ +typedef gboolean (*pipe_input_cb_t) (gint source, gpointer user_data); +/* install callback function, called if pipe input is available */ +extern void pipe_input_set_handler(gint source, gpointer user_data, int *child_process, pipe_input_cb_t input_cb); + +/* packet_list.c */ + +/* packet list related functions */ +void packet_list_clear(void); +void packet_list_freeze(void); +void packet_list_thaw(void); +void packet_list_select_row(gint); +void packet_list_moveto_end(void); +gint packet_list_append(const gchar *text[], gpointer data); +void packet_list_set_colors(gint, color_t *, color_t *); +gint packet_list_find_row_from_data(gpointer); +void packet_list_set_text(gint, gint, const gchar *); +void packet_list_set_cls_time_width(gint); +gpointer packet_list_get_row_data(gint); +void packet_list_set_selected_row(gint); +gint packet_list_get_sort_column(void); +void packet_list_set_sort_column(void); +gboolean packet_list_check_end(void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __UI_UTIL_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/util.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/util.h new file mode 100644 index 00000000..2a4198f0 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/util.h @@ -0,0 +1,60 @@ +/* util.h + * Utility definitions + * + * $Id: util.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __UTIL_H__ +#define __UTIL_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Collect command-line arguments as a string consisting of the arguments, + * separated by spaces. + */ +char *get_args_as_string(int argc, char **argv, int optind); + +/* Compute the difference between two seconds/microseconds time stamps. + * Beware: we're using nanosecond resolution now and function is currently unused + */ +void compute_timestamp_diff(gint *diffsec, gint *diffusec, + guint32 sec1, guint32 usec1, guint32 sec2, guint32 usec2); + +/* Try to figure out if we're remotely connected, e.g. via ssh or + Terminal Server, and create a capture filter that matches aspects of the + connection. We match the following environment variables: + + SSH_CONNECTION (ssh): + SSH_CLIENT (ssh): + REMOTEHOST (tcsh, others?): + DISPLAY (x11): [remote name]: + CLIENTNAME (terminal server): + */ +const char *get_conn_cfilter(void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __UTIL_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/version_info.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/version_info.h new file mode 100644 index 00000000..b036fbd2 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/version_info.h @@ -0,0 +1,79 @@ +/* version_info.h + * Declarations of outines to report version information for stuff used + * by Wireshark + * + * $Id: version_info.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __VERSION_INFO_H__ +#define __VERSION_INFO_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * The svn version string or "" + */ +extern const gchar *wireshark_svnversion; + +/* + * Get various library compile-time versions and append them to + * the specified GString. + * + * "additional_info" is called at the end to append any additional + * information; this is required in order to, for example, put the + * Portaudio information at the end of the string, as we currently + * don't use Portaudio in TShark. + */ +void get_compiled_version_info(GString *str, + void (*additional_info)(GString *)); + +/* + * Get compile-time information used only by applications that use + * libwireshark. + */ +void get_epan_compiled_version_info(GString *str); + +/* + * Get various library run-time versions, and the OS version, and append + * them to the specified GString. + */ +void get_runtime_version_info(GString *str, + void (*additional_info)(GString *)); + +/* + * Get copyright information. + */ +const char *get_copyright_info(void); + +#if defined(_WIN32) +/* + * Get the major OS version. + */ +guint32 get_os_major_version(); +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __VERSION_INFO_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/5views.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/5views.h new file mode 100644 index 00000000..2ae18a3a --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/5views.h @@ -0,0 +1,30 @@ +/* 5views.h + * + * $Id: 5views.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __5VIEWS_H__ +#define __5VIEWS_H__ + +int _5views_open(wtap *wth, int *err, gchar **err_info); +gboolean _5views_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); +int _5views_dump_can_write_encap(int encap); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/airopeek9.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/airopeek9.h new file mode 100644 index 00000000..df7a946b --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/airopeek9.h @@ -0,0 +1,29 @@ +/* airopeek9.h + * + * $Id: airopeek9.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __W_AIROPEEK9_H__ +#define __W_AIROPEEK9_H__ + +int airopeek9_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-grammar.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-grammar.h new file mode 100644 index 00000000..c705d457 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-grammar.h @@ -0,0 +1,90 @@ +/* A Bison parser, made by GNU Bison 2.3. */ + +/* Skeleton interface for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + STRING = 258, + KEYWORD = 259, + WDD_DATE = 260, + WDD_CHUNK = 261, + COUNTER = 262, + SLASH_SUFFIX = 263, + WDS_PREFIX = 264, + ISDN_PREFIX = 265, + ETHER_PREFIX = 266, + DECNUM = 267, + HEXNUM = 268, + HEXBYTE = 269 + }; +#endif +/* Tokens. */ +#define STRING 258 +#define KEYWORD 259 +#define WDD_DATE 260 +#define WDD_CHUNK 261 +#define COUNTER 262 +#define SLASH_SUFFIX 263 +#define WDS_PREFIX 264 +#define ISDN_PREFIX 265 +#define ETHER_PREFIX 266 +#define DECNUM 267 +#define HEXNUM 268 +#define HEXBYTE 269 + + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +#line 162 "./ascend-grammar.y" +{ +gchar *s; +guint32 d; +guint8 b; +} +/* Line 1489 of yacc.c. */ +#line 83 "ascend-grammar.h" + YYSTYPE; +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + +extern YYSTYPE ascendlval; + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-int.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-int.h new file mode 100644 index 00000000..6210d8dd --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-int.h @@ -0,0 +1,54 @@ +/* ascend-int.h + * Definitions for routines common to multiple modules in the Lucent/Ascend + * capture file reading code code, but not used outside that code. + * + * $Id: ascend-int.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ASCEND_INT_H__ +#define __ASCEND_INT_H__ + +typedef struct { + time_t start_time; + time_t secs; + int usecs; + guint32 caplen; + guint32 len; +} ascend_pkthdr; + +extern int at_eof; + +extern const gchar *ascend_parse_error; + +/* + * Pointer to the pseudo-header for the current packet. + */ +extern struct ascend_phdr *pseudo_header; + +/* Here we provide interfaces to make our scanner act and look like lex */ +int ascendlex(void); + +void init_parse_ascend(void); +void ascend_init_lexer(FILE_T fh); +int parse_ascend(FILE_T fh, guint8 *pd, struct ascend_phdr *phdr, + ascend_pkthdr *hdr, gint64 *start_of_data); + +#endif /* ! __ASCEND_INT_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-scanner_lex.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-scanner_lex.h new file mode 100644 index 00000000..68794f14 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-scanner_lex.h @@ -0,0 +1,6 @@ +/* This is generated by runlex.sh. Do not edit it. */ +#define yylex ascendlex +#ifndef YY_DECL +#define YY_DECL int yylex(void) +#endif +YY_DECL; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend.h new file mode 100644 index 00000000..1c749aac --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend.h @@ -0,0 +1,33 @@ +/* ascend.h + * + * $Id: ascend.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __ASCEND_H__ +#define __ASCEND_H__ + +#define ASCEND_MAX_DATA_ROWS 8 +#define ASCEND_MAX_DATA_COLS 16 +#define ASCEND_MAX_PKT_LEN (ASCEND_MAX_DATA_ROWS * ASCEND_MAX_DATA_COLS) + +int ascend_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/atm.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/atm.h new file mode 100644 index 00000000..f6aa08c8 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/atm.h @@ -0,0 +1,40 @@ +/* atm.h + * + * $Id: atm.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ATM_H__ +#define __ATM_H__ + +/* + * Routines to use with ATM capture file types that don't include information + * about the *type* of ATM traffic (or, at least, where we haven't found + * that information). + */ + +extern void +atm_guess_traffic_type(const guint8 *pd, guint32 len, + union wtap_pseudo_header *pseudo_header); + +extern void +atm_guess_lane_type(const guint8 *pd, guint32 len, + union wtap_pseudo_header *pseudo_header); + +#endif /* __ATM_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ber.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ber.h new file mode 100644 index 00000000..b3e139de --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ber.h @@ -0,0 +1,28 @@ +/* ber.h + * + * Basic Encoding Rules (BER) file reading + * + * $Id: ber.h 3992 2008-06-10 03:13:11Z dgu $ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __BER_H__ +#define __BER_H__ + +int ber_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/btsnoop.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/btsnoop.h new file mode 100644 index 00000000..d213206e --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/btsnoop.h @@ -0,0 +1,30 @@ +/* btsnoop.h + * + * $Id: btsnoop.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __W_BTSNOOP_H__ +#define __W_BTSNOOP_H__ + +int btsnoop_open(wtap *wth, int *err, gchar **err_info); +gboolean btsnoop_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); +int btsnoop_dump_can_write_encap(int encap); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/buffer.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/buffer.h new file mode 100644 index 00000000..55fb523c --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/buffer.h @@ -0,0 +1,58 @@ +/* buffer.h + * + * $Id: buffer.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __W_BUFFER_H__ +#define __W_BUFFER_H__ + +#define SOME_FUNCTIONS_ARE_DEFINES + +typedef struct Buffer { + guchar *data; + unsigned int allocated; + unsigned int start; + unsigned int first_free; +} Buffer; + +void buffer_init(Buffer* buffer, unsigned int space); +void buffer_free(Buffer* buffer); +void buffer_assure_space(Buffer* buffer, unsigned int space); +void buffer_append(Buffer* buffer, guchar *from, unsigned int bytes); +void buffer_remove_start(Buffer* buffer, unsigned int bytes); + +#ifdef SOME_FUNCTIONS_ARE_DEFINES +# define buffer_clean(buffer) buffer_remove_start((buffer), buffer_length(buffer)) +# define buffer_increase_length(buffer,bytes) (buffer)->first_free += (bytes) +# define buffer_length(buffer) ((buffer)->first_free - (buffer)->start) +# define buffer_start_ptr(buffer) ((buffer)->data + (buffer)->start) +# define buffer_end_ptr(buffer) ((buffer)->data + (buffer)->first_free) +# define buffer_append_buffer(buffer,src_buffer) buffer_append((buffer), buffer_start_ptr(src_buffer), buffer_length(src_buffer)) +#else + void buffer_clean(Buffer* buffer); + void buffer_increase_length(Buffer* buffer, unsigned int bytes); + unsigned int buffer_length(Buffer* buffer); + guchar* buffer_start_ptr(Buffer* buffer); + guchar* buffer_end_ptr(Buffer* buffer); + void buffer_append_buffer(Buffer* buffer, Buffer* src_buffer); +#endif + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/catapult_dct2000.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/catapult_dct2000.h new file mode 100644 index 00000000..89223f5f --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/catapult_dct2000.h @@ -0,0 +1,30 @@ +/* catapult_dct2000.h +* +* $Id: catapult_dct2000.h 3992 2008-06-10 03:13:11Z dgu $ +* +* Wiretap Library +* Copyright (c) 1998 by Gilbert Ramirez +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +int catapult_dct2000_open(wtap *wth, int *err, gchar **err_info); +gboolean catapult_dct2000_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); +int catapult_dct2000_dump_can_write_encap(int encap); + +#define DCT2000_ENCAP_UNHANDLED 0 +#define DCT2000_ENCAP_SSCOP 101 +#define DCT2000_ENCAP_MTP2 102 +#define DCT2000_ENCAP_NBAP 103 diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/commview.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/commview.h new file mode 100644 index 00000000..a07d0d25 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/commview.h @@ -0,0 +1,33 @@ +/* commview.h + * + * $Id: commview.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +#ifndef __COMMVIEW_H__ +#define __COMMVIEW_H__ + +int commview_open(wtap *wth, int *err, gchar **err_info _U_); +int commview_dump_can_write_encap(int encap); +gboolean commview_dump_open(wtap_dumper *wdh, gboolean cant_seek _U_, int *err); + +#endif /* __COMMVIEW_H__ */ + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/cosine.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/cosine.h new file mode 100644 index 00000000..5f5cdadc --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/cosine.h @@ -0,0 +1,32 @@ +/* cosine.h + * + * $Id: cosine.h 3992 2008-06-10 03:13:11Z dgu $ + * + * CoSine IPNOS L2 debug output parsing + * Copyright (c) 2002 by Motonori Shindo + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __W_COSINE_H__ +#define __W_COSINE_H__ + +int cosine_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/csids.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/csids.h new file mode 100644 index 00000000..149d07bd --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/csids.h @@ -0,0 +1,29 @@ + /* csids.h + * + * $Id: csids.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Copyright (c) 2000 by Mike Hall + * Copyright (c) Cisco Systems + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __CSIDS_H__ +#define __CSIDS_H__ + +int csids_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/dbs-etherwatch.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/dbs-etherwatch.h new file mode 100644 index 00000000..971ea7a0 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/dbs-etherwatch.h @@ -0,0 +1,29 @@ +/* dbs-etherwatch.h + * + * $Id: dbs-etherwatch.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __W_DBS_ETHERWATCH_H__ +#define __W_DBS_ETHERWATCH_H__ + +int dbs_etherwatch_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/erf.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/erf.h new file mode 100644 index 00000000..9f6b17cb --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/erf.h @@ -0,0 +1,102 @@ +/* +* +* Copyright (c) 2003 Endace Technology Ltd, Hamilton, New Zealand. +* All rights reserved. +* +* This software and documentation has been developed by Endace Technology Ltd. +* along with the DAG PCI network capture cards. For further information please +* visit http://www.endace.com/. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* 3. The name of Endace Technology Ltd may not be used to endorse or promote +* products derived from this software without specific prior written +* permission. +* +* THIS SOFTWARE IS PROVIDED BY ENDACE TECHNOLOGY LTD ``AS IS'' AND ANY EXPRESS +* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +* EVENT SHALL ENDACE TECHNOLOGY LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +* $Id: erf.h 3992 2008-06-10 03:13:11Z dgu $ +*/ + +#ifndef __W_ERF_H__ +#define __W_ERF_H__ + +/* Record type defines */ +#define ERF_TYPE_LEGACY 0 +#define ERF_TYPE_HDLC_POS 1 +#define ERF_TYPE_ETH 2 +#define ERF_TYPE_ATM 3 +#define ERF_TYPE_AAL5 4 +#define ERF_TYPE_MC_HDLC 5 +#define ERF_TYPE_MC_RAW 6 +#define ERF_TYPE_MC_ATM 7 +#define ERF_TYPE_MC_RAW_CHANNEL 8 +#define ERF_TYPE_MC_AAL5 9 +#define ERF_TYPE_COLOR_HDLC_POS 10 +#define ERF_TYPE_COLOR_ETH 11 +#define ERF_TYPE_MC_AAL2 12 +#define ERF_TYPE_IP_COUNTER 13 +#define ERF_TYPE_TCP_FLOW_COUNTER 14 +#define ERF_TYPE_DSM_COLOR_HDLC_POS 15 +#define ERF_TYPE_DSM_COLOR_ETH 16 +#define ERF_TYPE_COLOR_MC_HDLC_POS 17 +#define ERF_TYPE_AAL2 18 +#define ERF_TYPE_INFINIBAND 21 + +#define ERF_TYPE_PAD 48 + +#define ERF_TYPE_MIN 1 /* sanity checking */ +#define ERF_TYPE_MAX 48 /* sanity checking */ + + /* + * The timestamp is 64bit unsigned fixed point little-endian value with + * 32 bits for second and 32 bits for fraction. + */ +typedef guint64 erf_timestamp_t; + +typedef struct erf_record { + erf_timestamp_t ts; + guint8 type; + guint8 flags; + guint16 rlen; + guint16 lctr; + guint16 wlen; +} erf_header_t; + +typedef struct erf_mc_hdr { + guint32 mc; +} erf_mc_header_t; + +typedef struct erf_eth_hdr { + guint16 eth; +} erf_eth_header_t; + +union erf_subhdr { + struct erf_mc_hdr mc_hdr; + struct erf_eth_hdr eth_hdr; +}; + +#define MIN_RECORDS_FOR_ERF_CHECK 3 +#define RECORDS_FOR_ERF_CHECK 20 +#define FCS_BITS 32 + +int erf_open(wtap *wth, int *err, gchar **err_info); + +#endif /* __W_ERF_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/etherpeek.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/etherpeek.h new file mode 100644 index 00000000..465ad39c --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/etherpeek.h @@ -0,0 +1,29 @@ +/* etherpeek.h + * + * $Id: etherpeek.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __W_ETHERPEEK_H__ +#define __W_ETHERPEEK_H__ + +int etherpeek_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/eyesdn.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/eyesdn.h new file mode 100644 index 00000000..7b28b520 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/eyesdn.h @@ -0,0 +1,29 @@ +/* eyesdn.h + * + * $Id: eyesdn.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __W_EYESDN_H__ +#define __W_EYESDN_H__ + +int eyesdn_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/file_util.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/file_util.h new file mode 100644 index 00000000..e472e3ca --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/file_util.h @@ -0,0 +1,136 @@ +/* file_util.h + * File utility definitions + * + * $Id: file_util.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __FILE_UTIL_H__ +#define __FILE_UTIL_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include + +#ifdef _WIN32 +#include +#endif + +#ifdef HAVE_SYS_STAT_H +#include +#endif + + +/* Win32: Since GLib2.6, we use UTF8 throughout the code, so file functions + * must tweak a given filename from UTF8 to UTF16 as we use NT Unicode (Win9x + * - now unsupported - used locale based encoding here). + */ +#if defined _WIN32 && (GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 6)) +#include + +extern int eth_stdio_open (const gchar *filename, int flags, int mode); +extern int eth_stdio_rename (const gchar *oldfilename, const gchar *newfilename); +extern int eth_stdio_mkdir (const gchar *filename, int mode); +extern int eth_stdio_stat (const gchar *filename, struct stat *buf); +extern int eth_stdio_unlink (const gchar *filename); +extern int eth_stdio_remove (const gchar *filename); +extern FILE * eth_stdio_fopen (const gchar *filename, const gchar *mode); +extern FILE * eth_stdio_freopen (const gchar *filename, const gchar *mode, FILE *stream); + +#define eth_open eth_stdio_open +#define eth_rename eth_stdio_rename +#define eth_mkdir eth_stdio_mkdir +#define eth_stat eth_stdio_stat +#define eth_unlink eth_stdio_unlink +#define eth_remove eth_stdio_remove +#define eth_fopen eth_stdio_fopen +#define eth_freopen eth_stdio_freopen + +#else /* _WIN32 && GLIB_MAJOR_VERSION */ + +/* GLib 2.4 or below, using "old school" functions */ +#ifdef _WIN32 +#define eth_open _open +#define eth_stat _stat +#define eth_unlink _unlink +#define eth_mkdir(dir,mode) _mkdir(dir) +#else +#define eth_open open +#define eth_stat stat +#define eth_unlink unlink +#define eth_mkdir(dir,mode) mkdir(dir,mode) +#endif /* _WIN32 */ + +#define eth_rename rename +#define eth_remove remove +#define eth_fopen fopen +#define eth_freopen freopen + +#endif /* _WIN32 && GLIB_MAJOR_VERSION */ + + +/* some common file function differences between UNIX and WIN32 */ +#ifdef _WIN32 +/* the Win32 API prepends underscores for whatever reasons */ +#define eth_read _read +#define eth_write _write +#define eth_close _close +#define eth_dup _dup +#define eth_lseek _lseek +#else +#define eth_read read +#define eth_write write +#define eth_close close +#define eth_dup dup +#define eth_lseek lseek +#define O_BINARY 0 /* Win32 needs the O_BINARY flag for open() */ +#endif /* _WIN32 */ + +/* directory handling */ +#if GLIB_MAJOR_VERSION >= 2 +#define ETH_DIR GDir +#define ETH_DIRENT const char +#define eth_dir_open g_dir_open +#define eth_dir_read_name g_dir_read_name +#define eth_dir_get_name(dirent) dirent +#define eth_dir_rewind g_dir_rewind +#define eth_dir_close g_dir_close +#else +#define ETH_DIR DIR +#define ETH_DIRENT struct dirent +#define eth_dir_open(name,flags,error) opendir(name) +#define eth_dir_read_name readdir +#define eth_dir_get_name(dirent) (gchar *)(dirent)->d_name +#define eth_dir_rewind rewinddir +#define eth_dir_close closedir +#endif /* GLIB_MAJOR_VERSION */ + +/* XXX - remove include "dirent.h" */ +/* XXX - remove include "direct.h" */ +/* XXX - remove include "sys/stat.h" */ +/* XXX - update docs (e.g. README.developer) */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __FILE_UTIL_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/file_wrappers.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/file_wrappers.h new file mode 100644 index 00000000..193af09f --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/file_wrappers.h @@ -0,0 +1,57 @@ +/* file_wrappers.h + * + * $Id: file_wrappers.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __FILE_H__ +#define __FILE_H__ + +extern gint64 file_seek(void *stream, gint64 offset, int whence, int *err); +extern gint64 file_tell(void *stream); +extern int file_error(void *fh); + +#ifdef HAVE_LIBZ + +extern FILE_T file_open(const char *path, const char *mode); +#define filed_open gzdopen +/* XX: gzread and gzwrite return number of *bytes* (not number of elements) */ +#define file_read(buf, bsize, count, file) gzread((file),(buf),((count)*(bsize))) +#define file_write(buf, bsize, count, file) gzwrite((file),(buf),((count)*(bsize))) +#define file_close gzclose +#define file_getc gzgetc +#define file_gets(buf, len, file) gzgets((file), (buf), (len)) +#define file_eof gzeof + +#else /* No zLib */ + +#define file_open(path, mode) eth_fopen(path, mode) +#define filed_open fdopen +/* XX: file_read and file_write defined to return number of *bytes* to be consistent with gzread & gzwrite */ +#define file_read(buf, bsize, count, file) ((bsize) * fread((buf), (bsize), (count), (file))) +#define file_write(buf, bsize, count, file) ((bsize) * fwrite((buf), (bsize), (count), (file))) +#define file_close fclose +#define file_getc fgetc +#define file_gets fgets +#define file_eof feof + +#endif /* HAVE_LIBZ */ + +#endif /* __FILE_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/hcidump.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/hcidump.h new file mode 100644 index 00000000..08a0a61c --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/hcidump.h @@ -0,0 +1,28 @@ +/* hcidump.h + * + * $Id: hcidump.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Copyright (c) 2003 by Marcel Holtmann + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __HCIDUMP_H__ +#define __HCIDUMP_H__ + +int hcidump_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/i4b_trace.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/i4b_trace.h new file mode 100644 index 00000000..359f09ea --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/i4b_trace.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 1997, 1999 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_trace.h - header file for trace data read device + * ---------------------------------------------------- + * + * $Id: i4b_trace.h 3992 2008-06-10 03:13:11Z dgu $ + * + * last edit-date: [Sun Feb 14 10:39:26 1999] + * + *---------------------------------------------------------------------------*/ + +#ifndef _I4B_TRACE_H_ +#define _I4B_TRACE_H_ + +/*---------------------------------------------------------------------------* + * structure of the header at the beginning of every trace mbuf + *---------------------------------------------------------------------------*/ +typedef struct { + guint32 length; /* length of the following mbuf */ + gint32 unit; /* controller unit number */ + gint32 type; /* type of channel */ +#define TRC_CH_I 0 /* Layer 1 INFO's */ +#define TRC_CH_D 1 /* D channel */ +#define TRC_CH_B1 2 /* B1 channel */ +#define TRC_CH_B2 3 /* B2 channel */ + gint32 dir; /* direction */ +#define FROM_TE 0 /* user -> network */ +#define FROM_NT 1 /* network -> user */ + gint32 trunc; /* # of truncated bytes (frame > MCLBYTES) */ + guint32 count; /* frame count for this unit/type */ + guint32 ts_sec; /* timestamp seconds */ + guint32 ts_usec; /* timestamp microseconds */ +} i4b_trace_hdr_t; + +#define INFO0 0 /* layer 1 */ +#define INFO1_8 1 +#define INFO1_10 2 +#define INFO2 3 +#define INFO3 4 +#define INFO4_8 5 +#define INFO4_10 6 + +/*---------------------------------------------------------------------------* + * ioctl via /dev/i4btrc device(s): + * get/set current trace flag settings + *---------------------------------------------------------------------------*/ + +#define I4B_TRC_GET _IOR('T', 0, int) /* get trace settings */ +#define I4B_TRC_SET _IOW('T', 1, int) /* set trace settings */ + +#define TRACE_OFF 0x00 /* tracing off */ +#define TRACE_I 0x01 /* trace L1 INFO's on */ +#define TRACE_D_TX 0x02 /* trace D channel on */ +#define TRACE_D_RX 0x04 /* trace D channel on */ +#define TRACE_B_TX 0x08 /* trace B channel on */ +#define TRACE_B_RX 0x10 /* trace B channel on */ + +typedef struct { + gint32 rxunit; /* unit # for rx frames */ + gint32 rxflags; /* d and/or b channel */ + gint32 txunit; /* unit # for tx frames */ + gint32 txflags; /* d and/or b channel */ +} i4b_trace_setupa_t; + +#define I4B_TRC_SETA _IOW('T', 2, i4b_trace_setupa_t) /* set analyze mode */ +#define I4B_TRC_RESETA _IOW('T', 3, int) /* reset analyze mode */ + +#endif /* _I4B_TRACE_H_ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/i4btrace.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/i4btrace.h new file mode 100644 index 00000000..716e7c47 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/i4btrace.h @@ -0,0 +1,29 @@ +/* i4btrace.h + * + * $Id: i4btrace.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1999 by Bert Driehuis + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __I4BTRACE_H__ +#define __I4BTRACE_H__ + +int i4btrace_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/iptrace.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/iptrace.h new file mode 100644 index 00000000..57ac0d59 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/iptrace.h @@ -0,0 +1,29 @@ +/* iptrace.h + * + * $Id: iptrace.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __IPTRACE_H__ +#define __IPTRACE_H__ + +int iptrace_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/iseries.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/iseries.h new file mode 100644 index 00000000..ffb43e31 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/iseries.h @@ -0,0 +1,28 @@ +/* iseries.h + * + * $Id: iseries.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 2005 by Martin Warnes + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __W_ISERIES_H__ +#define __W_ISERIES_H__ + +int iseries_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/k12.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/k12.h new file mode 100644 index 00000000..c2647322 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/k12.h @@ -0,0 +1,28 @@ +/* k12.c +* +* $Id: k12.h 3992 2008-06-10 03:13:11Z dgu $ +* +* Wiretap Library +* Copyright (c) 1998 by Gilbert Ramirez +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +int k12_open(wtap *wth, int *err, gchar **err_info); +int k12_dump_can_write_encap(int encap); +gboolean k12_dump_open(wtap_dumper *wdh, gboolean cant_seek _U_, int *err); +int k12text_open(wtap *wth, int *err, gchar **err_info _U_); +int k12text_dump_can_write_encap(int encap); +gboolean k12text_dump_open(wtap_dumper *wdh, gboolean cant_seek _U_, int *err); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/k12text_lex.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/k12text_lex.h new file mode 100644 index 00000000..ccd97c5d --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/k12text_lex.h @@ -0,0 +1,6 @@ +/* This is generated by runlex.sh. Do not edit it. */ +#define yylex K12Text_lex +#ifndef YY_DECL +#define YY_DECL int yylex(void) +#endif +YY_DECL; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/lanalyzer.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/lanalyzer.h new file mode 100644 index 00000000..758a9833 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/lanalyzer.h @@ -0,0 +1,176 @@ +/* lanalyzer.h + * + * $Id: lanalyzer.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __LANALYZER_H__ +#define __LANALYZER_H__ + +/* Record type codes: */ + +#define RT_HeaderRegular 0x1001 +#define RT_HeaderCyclic 0x1007 +#define RT_RxChannelName 0x1006 +#define RT_TxChannelName 0x100b +#define RT_FilterName 0x1032 +#define RT_RxTemplateName 0x1035 +#define RT_TxTemplateName 0x1036 +#define RT_DisplayOptions 0x100a +#define RT_Summary 0x1002 +#define RT_SubfileSummary 0x1003 +#define RT_CyclicInformation 0x1009 +#define RT_Index 0x1004 +#define RT_PacketData 0x1005 + +#define LA_ProFileLimit (1024 * 1024 * 32) + +typedef guint8 Eadr[6]; +typedef guint16 TimeStamp[3]; /* 0.5 microseconds since start of trace */ + +/* + * These records have only 2-byte alignment for 4-byte quantities, + * so the structures aren't necessarily valid; they're kept as comments + * for reference purposes. + */ + +/* + * typedef struct { + * guint8 day; + * guint8 mon; + * gint16 year; + * } Date; + */ + +/* + * typedef struct { + * guint8 second; + * guint8 minute; + * guint8 hour; + * guint8 day; + * gint16 reserved; + * } Time; + */ + +/* + * typedef struct { + * guint16 rx_channels; + * guint16 rx_errors; + * gint16 rx_frm_len; + * gint16 rx_frm_sln; + * TimeStamp rx_time; + * guint32 pktno; + * gint16 prvlen; + * gint16 offset; + * gint16 tx_errs; + * gint16 rx_filters; + * gint8 unused[2]; + * gint16 hwcolls; + * gint16 hwcollschans; + * Packetdata ....; + * } LA_PacketRecord; + */ + +#define LA_PacketRecordSize 32 + +/* + * typedef struct { + * Date datcre; + * Date datclo; + * Time timeopn; + * Time timeclo; + * Eadr statadr; + * gint16 mxseqno; + * gint16 slcoff; + * gint16 mxslc; + * gint32 totpktt; + * gint32 statrg; + * gint32 stptrg; + * gint32 mxpkta[36]; + * gint16 board_type; + * gint16 board_version; + * gint8 reserved[18]; + * } Summary; + */ + +#define SummarySize (18+22+(4*36)+6+6+6+4+4) + + +/* + * typedef struct { + * gint16 rid; + * gint16 rlen; + * Summary s; + * } LA_SummaryRecord; + */ + +#define LA_SummaryRecordSize (SummarySize + 4) + + +/* + * typedef struct { + * gint16 rid; + * gint16 rlen; + * gint16 seqno; + * gint32 totpktf; + * } LA_SubfileSummaryRecord; + */ + +#define LA_SubfileSummaryRecordSize 10 + + +#define LA_IndexSize 500 + +/* + * typedef struct { + * gint16 rid; + * gint16 rlen; + * gint16 idxsp; = LA_IndexSize + * gint16 idxct; + * gint8 idxgranu; + * gint8 idxvd; + * gint32 trcidx[LA_IndexSize + 2]; +2 undocumented but used by La 2.2 + * } LA_IndexRecord; + */ + +#define LA_IndexRecordSize (10 + 4 * (LA_IndexSize + 2)) + +/* + * typedef struct { + * gint16 rid; + * gint16 rlen; + * } LA_RecordHeader; + */ + +#define LA_RecordHeaderSize 4 + +typedef struct { + gboolean init; + struct timeval start; + guint32 pkts; + int encap; + int lastlen; + } LA_TmpInfo; + +int lanalyzer_open(wtap *wth, int *err, gchar **err_info); +gboolean lanalyzer_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); +int lanalyzer_dump_can_write_encap(int encap); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/libpcap.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/libpcap.h new file mode 100644 index 00000000..3d4038f1 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/libpcap.h @@ -0,0 +1,106 @@ +/* libpcap.h + * + * $Id: libpcap.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __W_LIBPCAP_H__ +#define __W_LIBPCAP_H__ + +/* Magic numbers in "libpcap" files. + + "libpcap" file records are written in the byte order of the host that + writes them, and the reader is expected to fix this up. + + PCAP_MAGIC is the magic number, in host byte order; PCAP_SWAPPED_MAGIC + is a byte-swapped version of that. + + PCAP_MODIFIED_MAGIC is for Alexey Kuznetsov's modified "libpcap" + format, as generated on Linux systems that have a "libpcap" with + his patches, at + + http://ftp.sunet.se/pub/os/Linux/ip-routing/lbl-tools/ + + applied; PCAP_SWAPPED_MODIFIED_MAGIC is the byte-swapped version. + + PCAP_NSEC_MAGIC is for Ulf Lamping's modified "libpcap" format, + which uses the same common file format as PCAP_MAGIC, but the + timestamps are saved in nanosecond resolution instead of microseconds. + PCAP_SWAPPED_NSEC_MAGIC is a byte-swapped version of that. */ +#define PCAP_MAGIC 0xa1b2c3d4 +#define PCAP_SWAPPED_MAGIC 0xd4c3b2a1 +#define PCAP_MODIFIED_MAGIC 0xa1b2cd34 +#define PCAP_SWAPPED_MODIFIED_MAGIC 0x34cdb2a1 +#define PCAP_NSEC_MAGIC 0xa1b23c4d +#define PCAP_SWAPPED_NSEC_MAGIC 0x4d3cb2a1 + +/* "libpcap" file header (minus magic number). */ +struct pcap_hdr { + guint16 version_major; /* major version number */ + guint16 version_minor; /* minor version number */ + gint32 thiszone; /* GMT to local correction */ + guint32 sigfigs; /* accuracy of timestamps */ + guint32 snaplen; /* max length of captured packets, in octets */ + guint32 network; /* data link type */ +}; + +/* "libpcap" record header. */ +struct pcaprec_hdr { + guint32 ts_sec; /* timestamp seconds */ + guint32 ts_usec; /* timestamp microseconds (nsecs for PCAP_NSEC_MAGIC) */ + guint32 incl_len; /* number of octets of packet saved in file */ + guint32 orig_len; /* actual length of packet */ +}; + +/* "libpcap" record header for Alexey's patched version. */ +struct pcaprec_modified_hdr { + struct pcaprec_hdr hdr; /* the regular header */ + guint32 ifindex; /* index, in *capturing* machine's list of + interfaces, of the interface on which this + packet came in. */ + guint16 protocol; /* Ethernet packet type */ + guint8 pkt_type; /* broadcast/multicast/etc. indication */ + guint8 pad; /* pad to a 4-byte boundary */ +}; + +/* "libpcap" record header for Alexey's patched version in its ss990915 + incarnation; this version shows up in SuSE Linux 6.3. */ +struct pcaprec_ss990915_hdr { + struct pcaprec_hdr hdr; /* the regular header */ + guint32 ifindex; /* index, in *capturing* machine's list of + interfaces, of the interface on which this + packet came in. */ + guint16 protocol; /* Ethernet packet type */ + guint8 pkt_type; /* broadcast/multicast/etc. indication */ + guint8 cpu1, cpu2; /* SMP debugging gunk? */ + guint8 pad[3]; /* pad to a 4-byte boundary */ +}; + +/* "libpcap" record header for version used on some Nokia boxes (firewalls?) */ +struct pcaprec_nokia_hdr { + struct pcaprec_hdr hdr; /* the regular header */ + guint8 stuff[4]; /* mysterious stuff */ +}; + +int libpcap_open(wtap *wth, int *err, gchar **err_info); +gboolean libpcap_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); +int libpcap_dump_can_write_encap(int encap); +int wtap_pcap_encap_to_wtap_encap(int encap); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/mpeg-audio.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/mpeg-audio.h new file mode 100644 index 00000000..3ead2ff5 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/mpeg-audio.h @@ -0,0 +1,98 @@ +/* mpeg-audio.h + * + * MPEG Audio header dissection + * Written by Shaun Jackman + * Copyright 2007 Shaun Jackman + * + * $Id: mpeg-audio.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef MPA_H +#define MPA_H 1 + +struct mpa { + unsigned emphasis :2; + unsigned original :1; + unsigned copyright :1; + unsigned modeext :2; + unsigned mode :2; + unsigned private :1; + unsigned padding :1; + unsigned frequency :2; + unsigned bitrate :4; + unsigned protection :1; + unsigned layer :2; + unsigned version :2; + unsigned sync :11; +}; + +#define MPA_UNMARSHAL_SYNC(n) ((n) >> 21 & 0x7ff) +#define MPA_UNMARSHAL_VERSION(n) ((n) >> 19 & 0x3) +#define MPA_UNMARSHAL_LAYER(n) ((n) >> 17 & 0x3) +#define MPA_UNMARSHAL_PROTECTION(n) ((n) >> 16 & 0x1) +#define MPA_UNMARSHAL_BITRATE(n) ((n) >> 12 & 0xf) +#define MPA_UNMARSHAL_FREQUENCY(n) ((n) >> 10 & 0x3) +#define MPA_UNMARSHAL_PADDING(n) ((n) >> 9 & 0x1) +#define MPA_UNMARSHAL_PRIVATE(n) ((n) >> 8 & 0x1) +#define MPA_UNMARSHAL_MODE(n) ((n) >> 6 & 0x3) +#define MPA_UNMARSHAL_MODEEXT(n) ((n) >> 4 & 0x3) +#define MPA_UNMARSHAL_COPYRIGHT(n) ((n) >> 3 & 0x1) +#define MPA_UNMARSHAL_ORIGINAL(n) ((n) >> 2 & 0x1) +#define MPA_UNMARSHAL_EMPHASIS(n) ((n) >> 0 & 0x3) + +#define MPA_UNMARSHAL(mpa, n) do { \ + (mpa)->sync = MPA_UNMARSHAL_SYNC(n); \ + (mpa)->version = MPA_UNMARSHAL_VERSION(n); \ + (mpa)->layer = MPA_UNMARSHAL_LAYER(n); \ + (mpa)->protection = MPA_UNMARSHAL_PROTECTION(n); \ + (mpa)->bitrate = MPA_UNMARSHAL_BITRATE(n); \ + (mpa)->frequency = MPA_UNMARSHAL_FREQUENCY(n); \ + (mpa)->padding = MPA_UNMARSHAL_PADDING(n); \ + (mpa)->private = MPA_UNMARSHAL_PRIVATE(n); \ + (mpa)->mode = MPA_UNMARSHAL_MODE(n); \ + (mpa)->modeext = MPA_UNMARSHAL_MODEEXT(n); \ + (mpa)->copyright = MPA_UNMARSHAL_COPYRIGHT(n); \ + (mpa)->original = MPA_UNMARSHAL_ORIGINAL(n); \ + (mpa)->emphasis = MPA_UNMARSHAL_EMPHASIS(n); \ + } while (0) + +int mpa_version(const struct mpa *); +int mpa_layer(const struct mpa *); +unsigned mpa_samples(const struct mpa *); +unsigned mpa_bitrate(const struct mpa *); +unsigned mpa_frequency(const struct mpa *); +unsigned mpa_padding(const struct mpa *); + +#define MPA_DATA_BYTES(mpa) (mpa_bitrate(mpa) * mpa_samples(mpa) \ + / mpa_frequency(mpa) / 8) +#define MPA_BYTES(mpa) (MPA_DATA_BYTES(mpa) + mpa_padding(mpa)) +#define MPA_DURATION_NS(mpa) \ + (1000000000 / mpa_frequency(mpa) * mpa_samples(mpa)) + +enum { MPA_SYNC = 0x7ff }; + +#define MPA_SYNC_VALID(mpa) ((mpa)->sync == MPA_SYNC) +#define MPA_VERSION_VALID(mpa) (mpa_version(mpa) >= 0) +#define MPA_LAYER_VALID(mpa) (mpa_layer(mpa) >= 0) +#define MPA_BITRATE_VALID(mpa) (mpa_bitrate(mpa) > 0) +#define MPA_FREQUENCY_VALID(mpa) (mpa_frequency(mpa) > 0) +#define MPA_VALID(mpa) (MPA_SYNC_VALID(mpa) \ + && MPA_VERSION_VALID(mpa) && MPA_LAYER_VALID(mpa) \ + && MPA_BITRATE_VALID(mpa) && MPA_FREQUENCY_VALID(mpa)) + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/mpeg.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/mpeg.h new file mode 100644 index 00000000..c24fe87d --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/mpeg.h @@ -0,0 +1,32 @@ +/* mpeg.h + * + * MPEG file format decoder for the Wiretap library. + * Written by Shaun Jackman + * Copyright 2007 Shaun Jackman + * + * $Id: mpeg.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __W_MPEG_H__ +#define __W_MPEG_H__ + +#include "wtap-int.h" + +int mpeg_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netmon.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netmon.h new file mode 100644 index 00000000..ab0904cc --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netmon.h @@ -0,0 +1,30 @@ +/* netmon.h + * + * $Id: netmon.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __NETMON_H__ +#define __NETMON_H__ + +int netmon_open(wtap *wth, int *err, gchar **err_info); +gboolean netmon_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); +int netmon_dump_can_write_encap(int encap); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netscreen.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netscreen.h new file mode 100644 index 00000000..dce7c361 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netscreen.h @@ -0,0 +1,53 @@ +/* netscreen.h + * + * $Id: netscreen.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Juniper NetScreen snoop output parser + * Created by re-using a lot of code from cosine.c + * Copyright (c) 2007 by Sake Blok + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __W_NETSCREEN_H__ +#define __W_NETSCREEN_H__ + +/* Magic text to check for NetScreen snoop output */ +#define NETSCREEN_HDR_MAGIC_STR1 "(i) len=" +#define NETSCREEN_HDR_MAGIC_STR2 "(o) len=" + +/* Magic text for start of packet */ +#define NETSCREEN_REC_MAGIC_STR1 NETSCREEN_HDR_MAGIC_STR1 +#define NETSCREEN_REC_MAGIC_STR2 NETSCREEN_HDR_MAGIC_STR2 + +#define NETSCREEN_LINE_LENGTH 128 +#define NETSCREEN_HEADER_LINES_TO_CHECK 32 +#define NETSCREEN_MAX_INFOLINES 8 +#define NETSCREEN_SPACES_ON_INFO_LINE 14 +#define NETSCREEN_MAX_INT_NAME_LENGTH 16 + +#define NETSCREEN_INGRESS FALSE +#define NETSCREEN_EGRESS TRUE + + +#define NETSCREEN_MAX_PACKET_LEN 65536 + +int netscreen_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/nettl.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/nettl.h new file mode 100644 index 00000000..1ac9f756 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/nettl.h @@ -0,0 +1,124 @@ +/* nettl.h + * + * $Id: nettl.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * Enhancements by Mark C. Brown + * Copyright (C) 2003, 2005 Hewlett-Packard Development Company, L.P. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __NETTL_H__ +#define __NETTL_H__ + +/* nettl subsystems are defined in /etc/nettlgen.conf */ + +#define NETTL_SUBSYS_NS_LS_LOGGING 0 +#define NETTL_SUBSYS_NS_LS_NFT 1 +#define NETTL_SUBSYS_NS_LS_LOOPBACK 2 +#define NETTL_SUBSYS_NS_LS_NI 3 +#define NETTL_SUBSYS_NS_LS_IPC 4 +#define NETTL_SUBSYS_NS_LS_SOCKREGD 5 +#define NETTL_SUBSYS_NS_LS_TCP 6 +#define NETTL_SUBSYS_NS_LS_PXP 7 +#define NETTL_SUBSYS_NS_LS_UDP 8 +#define NETTL_SUBSYS_NS_LS_IP 9 +#define NETTL_SUBSYS_NS_LS_PROBE 10 +#define NETTL_SUBSYS_NS_LS_DRIVER 11 +#define NETTL_SUBSYS_NS_LS_RLBD 12 +#define NETTL_SUBSYS_NS_LS_BUFS 13 +#define NETTL_SUBSYS_NS_LS_CASE21 14 +#define NETTL_SUBSYS_NS_LS_ROUTER21 15 +#define NETTL_SUBSYS_NS_LS_NFS 16 +#define NETTL_SUBSYS_NS_LS_NETISR 17 +#define NETTL_SUBSYS_NS_LS_NSE 18 +#define NETTL_SUBSYS_NS_LS_STRLOG 19 +#define NETTL_SUBSYS_NS_LS_TIRDWR 21 +#define NETTL_SUBSYS_NS_LS_TIMOD 22 +#define NETTL_SUBSYS_NS_LS_ICMP 23 +#define NETTL_SUBSYS_FILTER 26 +#define NETTL_SUBSYS_NAME 27 +#define NETTL_SUBSYS_IGMP 29 +#define NETTL_SUBSYS_SX25L2 34 +#define NETTL_SUBSYS_SX25L3 35 +#define NETTL_SUBSYS_FTAM_INIT 64 +#define NETTL_SUBSYS_FTAM_RESP 65 +#define NETTL_SUBSYS_FTAM_VFS 70 +#define NETTL_SUBSYS_FTAM_USER 72 +#define NETTL_SUBSYS_OTS 90 +#define NETTL_SUBSYS_NETWORK 91 +#define NETTL_SUBSYS_TRANSPORT 92 +#define NETTL_SUBSYS_SESSION 93 +#define NETTL_SUBSYS_ACSE_PRES 94 +#define NETTL_SUBSYS_SHM 116 +#define NETTL_SUBSYS_ACSE_US 119 +#define NETTL_SUBSYS_HPS 121 +#define NETTL_SUBSYS_CM 122 +#define NETTL_SUBSYS_ULA_UTILS 123 +#define NETTL_SUBSYS_EM 124 +#define NETTL_SUBSYS_HP_APAPORT 189 +#define NETTL_SUBSYS_HP_APALACP 190 +#define NETTL_SUBSYS_NS_LS_IPV6 244 +#define NETTL_SUBSYS_NS_LS_ICMPV6 245 +#define NETTL_SUBSYS_NS_LS_TELNET 267 +#define NETTL_SUBSYS_NS_LS_SCTP 268 + +/* Ethernet cards */ +#define NETTL_SUBSYS_100VG 37 +#define NETTL_SUBSYS_LAN100 164 +#define NETTL_SUBSYS_EISA100BT 172 +#define NETTL_SUBSYS_BASE100 173 +#define NETTL_SUBSYS_GSC100BT 178 +#define NETTL_SUBSYS_PCI100BT 179 +#define NETTL_SUBSYS_SPP100BT 180 +#define NETTL_SUBSYS_GELAN 185 +#define NETTL_SUBSYS_BTLAN 210 +#define NETTL_SUBSYS_INTL100 233 +#define NETTL_SUBSYS_IGELAN 252 +#define NETTL_SUBSYS_IETHER 253 +#define NETTL_SUBSYS_IXGBE 265 + +/* FDDI cards */ +#define NETTL_SUBSYS_HPPB_FDDI 95 +#define NETTL_SUBSYS_EISA_FDDI 174 +#define NETTL_SUBSYS_PCI_FDDI 176 +#define NETTL_SUBSYS_HSC_FDDI 177 + +/* Token Ring cards */ +#define NETTL_SUBSYS_TOKEN 31 +#define NETTL_SUBSYS_PCI_TR 187 + +/* from /usr/include/sys/subsys_id.h */ + +#define NETTL_HDR_HDRIN 0x80000000 +#define NETTL_HDR_HDROUT 0x40000000 +#define NETTL_HDR_PDUIN 0x20000000 +#define NETTL_HDR_PDUOUT 0x10000000 +#define NETTL_HDR_PROCEDURE_TRACE 0x08000000 +#define NETTL_HDR_STATE_TRACE 0x04000000 +#define NETTL_HDR_ERROR_TRACE 0x02000000 +#define NETTL_HDR_LOG_TRACE 0x01000000 +#define NETTL_HDR_LOOPBACK 0x00800000 +#define NETTL_HDR_PTOP 0x00400000 +#define NETTL_HDR_SUBSYSTEM_BITS_MASK 0x000fffff + +int nettl_open(wtap *wth, int *err, gchar **err_info); +gboolean nettl_dump_open(wtap_dumper *wdh, gboolean cant_seek _U_, int *err); +int nettl_dump_can_write_encap(int encap); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/network_instruments.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/network_instruments.h new file mode 100644 index 00000000..ab9708b7 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/network_instruments.h @@ -0,0 +1,127 @@ +/* + * $Id: network_instruments.h 3992 2008-06-10 03:13:11Z dgu $ + */ + +/*************************************************************************** + NetworkInstruments.h - description + ------------------- + begin : Wed Oct 29 2003 + copyright : (C) 2003 by root + email : scotte[AT}netinst.com + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef __NETWORK_INSTRUMENTS_H__ +#define __NETWORK_INSTRUMENTS_H__ + +int network_instruments_open(wtap *wth, int *err, gchar **err_info); +int network_instruments_dump_can_write_encap(int encap); +gboolean network_instruments_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); + +typedef struct capture_file_header +{ + char observer_version[32]; + guint16 offset_to_first_packet; + char probe_instance; + guint8 number_of_information_elements; /* number of TLVs in the header */ +} capture_file_header; + +typedef struct tlv_header +{ + guint16 type; + guint16 length; /* includes the length of the TLV header */ +} tlv_header; + +/* + * TLV type values. + */ +#define INFORMATION_TYPE_ALIAS_LIST 0x01 +#define INFORMATION_TYPE_COMMENT 0x02 /* ASCII text */ + +typedef struct packet_entry_header +{ + guint32 packet_magic; + guint32 network_speed; + guint16 captured_size; + guint16 network_size; + guint16 offset_to_frame; + guint16 offset_to_next_packet; + guint8 network_type; + guint8 flags; + guint8 number_of_information_elements; /* number of TLVs in the header */ + guint8 packet_type; + guint16 errors; + guint16 reserved; + guint64 packet_number; + guint64 original_packet_number; + guint64 nano_seconds_since_2000; +} packet_entry_header; + +/* + * Network type values. + */ +#define OBSERVER_UNDEFINED 0xFF +#define OBSERVER_ETHERNET 0x00 +#define OBSERVER_TOKENRING 0x01 +#define OBSERVER_FDDI 0x02 + +/* + * Packet type values. + */ +#define PACKET_TYPE_DATA_PACKET 0 +#define PACKET_TYPE_EXPERT_INFORMATION_PACKET 1 + +/* + * The Observer document indicates that the types of expert information + * packets are: + * + * Network Load (markers used by Expert Time Interval and What If + * analysis modes) + * + * Start/Stop Packet Capture marker frames (with time stamps when + * captures start and stop) + * + * Wireless Channel Change (markers showing what channel was being + * currently listened to) + * + * That information appears to be contained in TLVs. + */ + +/* + * TLV type values. + */ +#define INFORMATION_TYPE_NETWORK_LOAD 0x0100 +#define INFORMATION_TYPE_CAPTURE_START_STOP 0x0104 + +/* + * Might some of these be broadcast and multicast packet counts? + */ +typedef struct tlv_network_load +{ + guint32 utilization; /* network utilization, in .1% units */ + guint32 unknown1; + guint32 unknown2; + guint32 packets_per_second; + guint32 unknown3; + guint32 bytes_per_second; + guint32 unknown4; +} tlv_network_load; + +typedef struct tlv_capture_start_stop +{ + guint32 start_stop; +} tlv_capture_start_stop; + +#define START_STOP_TYPE_STOP 0 +#define START_STOP_TYPE_START 1 + +#endif + diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netxray.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netxray.h new file mode 100644 index 00000000..0c38bb34 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netxray.h @@ -0,0 +1,32 @@ +/* netxray.h + * + * $Id: netxray.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __NETXRAY_H__ +#define __NETXRAY_H__ + +int netxray_open(wtap *wth, int *err, gchar **err_info); +int netxray_dump_can_write_encap_1_1(int encap); +gboolean netxray_dump_open_1_1(wtap_dumper *wdh, gboolean cant_seek, int *err); +int netxray_dump_can_write_encap_2_0(int encap); +gboolean netxray_dump_open_2_0(wtap_dumper *wdh, gboolean cant_seek, int *err); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ngsniffer.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ngsniffer.h new file mode 100644 index 00000000..a4a25f6e --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ngsniffer.h @@ -0,0 +1,30 @@ +/* ngsniffer.h + * + * $Id: ngsniffer.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __NGSNIFFER_H__ +#define __NGSNIFFER_H__ + +int ngsniffer_open(wtap *wth, int *err, gchar **err_info); +gboolean ngsniffer_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); +int ngsniffer_dump_can_write_encap(int encap); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/pcapng.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/pcapng.h new file mode 100644 index 00000000..65d7de3d --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/pcapng.h @@ -0,0 +1,30 @@ +/* pcapng.h + * + * $Id: pcapng.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __W_PCAPNG_H__ +#define __W_PCAPNG_H__ + +int pcapng_open(wtap *wth, int *err, gchar **err_info); +gboolean pcapng_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); +int pcapng_dump_can_write_encap(int encap); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/pppdump.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/pppdump.h new file mode 100644 index 00000000..c5b8aad0 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/pppdump.h @@ -0,0 +1,28 @@ +/* pppdump.h + * + * $Id: pppdump.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Copyright (c) 2000 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __PPPDUMP_H__ +#define __PPPDUMP_H__ + +int pppdump_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/radcom.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/radcom.h new file mode 100644 index 00000000..0e6724c7 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/radcom.h @@ -0,0 +1,29 @@ +/* radcom.h + * + * $Id: radcom.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __RADCOM_H__ +#define __RADCOM_H__ + +int radcom_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/snoop.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/snoop.h new file mode 100644 index 00000000..a1a68f87 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/snoop.h @@ -0,0 +1,30 @@ +/* snoop.h + * + * $Id: snoop.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __W_SNOOP_H__ +#define __W_SNOOP_H__ + +int snoop_open(wtap *wth, int *err, gchar **err_info); +gboolean snoop_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); +int snoop_dump_can_write_encap(int encap); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/toshiba.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/toshiba.h new file mode 100644 index 00000000..eea69129 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/toshiba.h @@ -0,0 +1,28 @@ +/* toshiba.h + * + * $Id: toshiba.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __W_TOSHIBA_H__ +#define __W_TOSHIBA_H__ + +int toshiba_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/visual.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/visual.h new file mode 100644 index 00000000..0c094a9e --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/visual.h @@ -0,0 +1,35 @@ +/* visual.h + * + * File read write routines for Visual Networks .cap files. + * Copyright 2001, Tom Nisbet tnisbet@visualnetworks.com + * + * Based on the code that handles netmon files. + * + * $Id: visual.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __VISUAL_H__ +#define __VISUAL_H__ + +int visual_open(wtap *wth, int *err, gchar **err_info); +gboolean visual_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); +int visual_dump_can_write_encap(int encap); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/vms.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/vms.h new file mode 100644 index 00000000..34083b07 --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/vms.h @@ -0,0 +1,29 @@ +/* vms.h + * + * $Id: vms.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 2001 by Marc Milgram + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __W_VMS_H__ +#define __W_VMS_H__ + +int vms_open(wtap *wth, int *err, gchar **err_info); + +#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/wtap-int.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/wtap-int.h new file mode 100644 index 00000000..3f48d12c --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/wtap-int.h @@ -0,0 +1,482 @@ +/* wtap-int.h + * + * $Id: wtap-int.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __WTAP_INT_H__ +#define __WTAP_INT_H__ + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#include +#include +#include + +#ifdef HAVE_LIBZ +#ifdef HAVE_WINSOCK2_H +#include +#endif +#include +#define FILE_T gzFile +#else /* No zLib */ +#define FILE_T FILE * +#endif /* HAVE_LIBZ */ + +#include "wtap.h" + +/* Information for a compressed Sniffer data stream. */ +typedef struct { + unsigned char *buf; /* buffer into which we uncompress data */ + size_t nbytes; /* number of bytes of data in that buffer */ + int nextout; /* offset in that buffer of stream's current position */ + gint64 comp_offset; /* current offset in compressed data stream */ + gint64 uncomp_offset; /* current offset in uncompressed data stream */ +} ngsniffer_comp_stream_t; + +typedef struct { + char *sdate; /* Packet start date */ + gboolean tcp_formatted; /* TCP/IP data formated Y/N */ + int format; /* Trace format type */ +} iseries_t; + +typedef struct { + guint maj_vers; + guint min_vers; + guint32 timeunit; + time_t start; + guint network; /* network type */ + ngsniffer_comp_stream_t seq; /* sequential access */ + ngsniffer_comp_stream_t rand; /* random access */ + GList *first_blob; /* list element for first blob */ + GList *last_blob; /* list element for last blob */ + GList *current_blob; /* list element for current blob */ +} ngsniffer_t; + +typedef struct { + gboolean byte_swapped; +} i4btrace_t; + +typedef struct { + gboolean is_hpux_11; +} nettl_t; + +typedef struct { + time_t start; +} lanalyzer_t; + +typedef enum { + NOT_SWAPPED, + SWAPPED, + MAYBE_SWAPPED +} swapped_type_t; + +typedef struct { + gboolean byte_swapped; + swapped_type_t lengths_swapped; + guint16 version_major; + guint16 version_minor; +} libpcap_t; + +typedef struct { + gboolean byte_swapped; + guint16 version_major; + guint16 version_minor; + guint8 if_fcslen; +} pcapng_t; + +typedef struct { + time_t start_secs; + guint32 start_usecs; + guint8 version_major; + guint32 *frame_table; + guint32 frame_table_size; + guint current_frame; +} netmon_t; + +typedef struct { + time_t start_time; + double ticks_per_sec; + double start_timestamp; + gboolean wrapped; + guint32 nframes; + gint64 start_offset; + gint64 end_offset; + int version_major; + gboolean fcs_valid; /* if packets have valid FCS at the end */ + guint isdn_type; /* 1 = E1 PRI, 2 = T1 PRI, 3 = BRI */ +} netxray_t; + +typedef struct { + time_t inittime; + int adjusted; + gint64 next_packet_seek_start; +} ascend_t; + +typedef struct { + gboolean byteswapped; +} csids_t; + +typedef struct { + struct timeval reference_time; +} etherpeek_t; + +typedef struct { + gboolean has_fcs; +} airopeek9_t; + +typedef struct _k12_t k12_t; + +typedef struct { + time_t start_secs; + guint32 start_usecs; +} catapult_dct2000_t; + +typedef struct { + struct wtap_nstime now; + time_t t0; +} mpeg_t; + +typedef gboolean (*subtype_read_func)(struct wtap*, int*, char**, gint64*); +typedef gboolean (*subtype_seek_read_func)(struct wtap*, gint64, union wtap_pseudo_header*, + guint8*, int, int *, char **); +struct wtap { + FILE_T fh; + int fd; /* File descriptor for cap file */ + FILE_T random_fh; /* Secondary FILE_T for random access */ + int file_type; + int snapshot_length; + struct Buffer *frame_buffer; + struct wtap_pkthdr phdr; + union wtap_pseudo_header pseudo_header; + + gint64 data_offset; + + union { + libpcap_t *pcap; + lanalyzer_t *lanalyzer; + ngsniffer_t *ngsniffer; + iseries_t *iseries; + i4btrace_t *i4btrace; + nettl_t *nettl; + netmon_t *netmon; + netxray_t *netxray; + ascend_t *ascend; + csids_t *csids; + etherpeek_t *etherpeek; + airopeek9_t *airopeek9; + k12_t *k12; + catapult_dct2000_t *catapult_dct2000; + mpeg_t *mpeg; + void *generic; + pcapng_t *pcapng; + } capture; + + subtype_read_func subtype_read; + subtype_seek_read_func subtype_seek_read; + void (*subtype_sequential_close)(struct wtap*); + void (*subtype_close)(struct wtap*); + int file_encap; /* per-file, for those + file formats that have + per-file encapsulation + types */ + int tsprecision; /* timestamp precision of the lower 32bits + * e.g. WTAP_FILE_TSPREC_USEC */ +}; + +struct wtap_dumper; + +typedef gboolean (*subtype_write_func)(struct wtap_dumper*, + const struct wtap_pkthdr*, const union wtap_pseudo_header*, + const guchar*, int*); +typedef gboolean (*subtype_close_func)(struct wtap_dumper*, int*); + +typedef struct { + gboolean first_frame; + time_t start; +} ngsniffer_dump_t; + +typedef struct { + gboolean first_frame; + struct wtap_nstime start; + guint32 nframes; +} netxray_dump_t; + +typedef struct { + gboolean got_first_record_time; + struct wtap_nstime first_record_time; + guint32 frame_table_offset; + guint32 *frame_table; + guint frame_table_index; + guint frame_table_size; +} netmon_dump_t; + +typedef struct { + guint32 nframes; +} _5views_dump_t; + +typedef struct { + guint64 packet_count; + guint8 network_type; +} niobserver_dump_t; + +typedef struct { + guint32 file_len; + guint32 num_of_records; + guint32 file_offset; +} k12_dump_t; + +typedef struct { + gboolean first_packet_written; + struct wtap_nstime start_time; +} dct2000_dump_t; + +struct wtap_dumper { + FILE* fh; + int file_type; + int snaplen; + int encap; + gboolean compressed; + gint64 bytes_dumped; + + union { + void *opaque; + ngsniffer_dump_t *ngsniffer; + netmon_dump_t *netmon; + netxray_dump_t *netxray; + _5views_dump_t *_5views; + niobserver_dump_t *niobserver; + k12_dump_t *k12; + dct2000_dump_t *dct2000; + } dump; + + subtype_write_func subtype_write; + subtype_close_func subtype_close; + + int tsprecision; /* timestamp precision of the lower 32bits + * e.g. WTAP_FILE_TSPREC_USEC */ +}; + +extern size_t wtap_dump_file_write(wtap_dumper *wdh, const void *buf, unsigned bufsize); +extern int wtap_dump_file_ferror(wtap_dumper *wdh); + +extern gint wtap_num_file_types; + +/* Macros to byte-swap 64-bit, 32-bit and 16-bit quantities. */ +#define BSWAP64(x) \ + ((((x)&G_GINT64_CONSTANT(0xFF00000000000000U))>>56) | \ + (((x)&G_GINT64_CONSTANT(0x00FF000000000000U))>>40) | \ + (((x)&G_GINT64_CONSTANT(0x0000FF0000000000U))>>24) | \ + (((x)&G_GINT64_CONSTANT(0x000000FF00000000U))>>8) | \ + (((x)&G_GINT64_CONSTANT(0x00000000FF000000U))<<8) | \ + (((x)&G_GINT64_CONSTANT(0x0000000000FF0000U))<<24) | \ + (((x)&G_GINT64_CONSTANT(0x000000000000FF00U))<<40) | \ + (((x)&G_GINT64_CONSTANT(0x00000000000000FFU))<<56)) +#define BSWAP32(x) \ + ((((x)&0xFF000000)>>24) | \ + (((x)&0x00FF0000)>>8) | \ + (((x)&0x0000FF00)<<8) | \ + (((x)&0x000000FF)<<24)) +#define BSWAP16(x) \ + ((((x)&0xFF00)>>8) | \ + (((x)&0x00FF)<<8)) + +/* Macros to byte-swap possibly-unaligned 32-bit and 16-bit quantities; + * they take a pointer to the quantity, and byte-swap it in place. + */ +#define PBSWAP32(p) \ + { \ + guint8 tmp; \ + tmp = (p)[3]; \ + (p)[3] = (p)[0]; \ + (p)[0] = tmp; \ + tmp = (p)[2]; \ + (p)[2] = (p)[1]; \ + (p)[1] = tmp; \ + } +#define PBSWAP16(p) \ + { \ + guint8 tmp; \ + tmp = (p)[1]; \ + (p)[1] = (p)[0]; \ + (p)[0] = tmp; \ + } + +/* Turn host-byte-order values into little-endian values. */ +#define htoles(s) GUINT16_TO_LE(s) +#define htolel(l) GUINT32_TO_LE(l) +#define htolell(ll) GUINT64_TO_LE(ll) + +/* Pointer versions of ntohs and ntohl. Given a pointer to a member of a + * byte array, returns the value of the two or four bytes at the pointer. + * The pletoh[sl] versions return the little-endian representation. + * We also provide pntohll and pletohll, which extract 64-bit integral + * quantities. + * + * These will work regardless of the byte alignment of the pointer. + */ + +#ifndef pntohs +#define pntohs(p) ((guint16) \ + ((guint16)*((const guint8 *)(p)+0)<<8| \ + (guint16)*((const guint8 *)(p)+1)<<0)) +#endif + +#ifndef pntoh24 +#define pntoh24(p) ((guint32)*((const guint8 *)(p)+0)<<16| \ + (guint32)*((const guint8 *)(p)+1)<<8| \ + (guint32)*((const guint8 *)(p)+2)<<0) +#endif + +#ifndef pntohl +#define pntohl(p) ((guint32)*((const guint8 *)(p)+0)<<24| \ + (guint32)*((const guint8 *)(p)+1)<<16| \ + (guint32)*((const guint8 *)(p)+2)<<8| \ + (guint32)*((const guint8 *)(p)+3)<<0) +#endif + +#ifndef pntohll +#define pntohll(p) ((guint64)*((const guint8 *)(p)+0)<<56| \ + (guint64)*((const guint8 *)(p)+1)<<48| \ + (guint64)*((const guint8 *)(p)+2)<<40| \ + (guint64)*((const guint8 *)(p)+3)<<32| \ + (guint64)*((const guint8 *)(p)+4)<<24| \ + (guint64)*((const guint8 *)(p)+5)<<16| \ + (guint64)*((const guint8 *)(p)+6)<<8| \ + (guint64)*((const guint8 *)(p)+7)<<0) +#endif + + +#ifndef pletohs +#define pletohs(p) ((guint16) \ + ((guint16)*((const guint8 *)(p)+1)<<8| \ + (guint16)*((const guint8 *)(p)+0)<<0)) +#endif + +#ifndef pletoh24 +#define pletoh24(p) ((guint32)*((const guint8 *)(p)+2)<<16| \ + (guint32)*((const guint8 *)(p)+1)<<8| \ + (guint32)*((const guint8 *)(p)+0)<<0) +#endif + + +#ifndef pletohl +#define pletohl(p) ((guint32)*((const guint8 *)(p)+3)<<24| \ + (guint32)*((const guint8 *)(p)+2)<<16| \ + (guint32)*((const guint8 *)(p)+1)<<8| \ + (guint32)*((const guint8 *)(p)+0)<<0) +#endif + + +#ifndef pletohll +#define pletohll(p) ((guint64)*((const guint8 *)(p)+7)<<56| \ + (guint64)*((const guint8 *)(p)+6)<<48| \ + (guint64)*((const guint8 *)(p)+5)<<40| \ + (guint64)*((const guint8 *)(p)+4)<<32| \ + (guint64)*((const guint8 *)(p)+3)<<24| \ + (guint64)*((const guint8 *)(p)+2)<<16| \ + (guint64)*((const guint8 *)(p)+1)<<8| \ + (guint64)*((const guint8 *)(p)+0)<<0) +#endif + +/* Pointer routines to put items out in a particular byte order. + * These will work regardless of the byte alignment of the pointer. + */ + +#ifndef phtons +#define phtons(p, v) \ + { \ + (p)[0] = (guint8)((v) >> 8); \ + (p)[1] = (guint8)((v) >> 0); \ + } +#endif + +#ifndef phtonl +#define phtonl(p, v) \ + { \ + (p)[0] = (guint8)((v) >> 24); \ + (p)[1] = (guint8)((v) >> 16); \ + (p)[2] = (guint8)((v) >> 8); \ + (p)[3] = (guint8)((v) >> 0); \ + } +#endif + +#ifndef phtonll +#define phtonll(p, v) \ + { \ + (p)[0] = (guint8)((v) >> 56); \ + (p)[1] = (guint8)((v) >> 48); \ + (p)[2] = (guint8)((v) >> 40); \ + (p)[3] = (guint8)((v) >> 32); \ + (p)[4] = (guint8)((v) >> 24); \ + (p)[5] = (guint8)((v) >> 16); \ + (p)[6] = (guint8)((v) >> 8); \ + (p)[7] = (guint8)((v) >> 0); \ + } +#endif + +#ifndef pletonll +#define pletonll(p, v) \ + { \ + (p)[0] = (guint8)((v) >> 0); \ + (p)[1] = (guint8)((v) >> 8); \ + (p)[2] = (guint8)((v) >> 16); \ + (p)[3] = (guint8)((v) >> 24); \ + (p)[4] = (guint8)((v) >> 32); \ + (p)[5] = (guint8)((v) >> 40); \ + (p)[6] = (guint8)((v) >> 48); \ + (p)[7] = (guint8)((v) >> 56); \ + } +#endif + +#define wtap_file_read_unknown_bytes(target, num_bytes, fh, err) \ + G_STMT_START \ + { \ + int _bytes_read; \ + _bytes_read = file_read((target), 1, (num_bytes), (fh)); \ + if (_bytes_read != (int) (num_bytes)) { \ + *(err) = file_error((fh)); \ + return FALSE; \ + } \ + } \ + G_STMT_END + +#define wtap_file_read_expected_bytes(target, num_bytes, fh, err) \ + G_STMT_START \ + { \ + int _bytes_read; \ + _bytes_read = file_read((target), 1, (num_bytes), (fh)); \ + if (_bytes_read != (int) (num_bytes)) { \ + *(err) = file_error((fh)); \ + if (*(err) == 0 && _bytes_read > 0) { \ + *(err) = WTAP_ERR_SHORT_READ; \ + } \ + return FALSE; \ + } \ + } \ + G_STMT_END + +/* glib doesn't have g_ptr_array_len of all things!*/ +#ifndef g_ptr_array_len +#define g_ptr_array_len(a) ((a)->len) +#endif + +#endif /* __WTAP_INT_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/wtap.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/wtap.h new file mode 100644 index 00000000..9f51c19f --- /dev/null +++ b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/wtap.h @@ -0,0 +1,944 @@ +/* wtap.h + * + * $Id: wtap.h 3992 2008-06-10 03:13:11Z dgu $ + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __WTAP_H__ +#define __WTAP_H__ + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#ifdef HAVE_WINSOCK2_H +# include +#endif + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Encapsulation types. Choose names that truly reflect + * what is contained in the packet trace file. + * + * WTAP_ENCAP_PER_PACKET is a value passed to "wtap_dump_open()" or + * "wtap_dump_fd_open()" to indicate that there is no single encapsulation + * type for all packets in the file; this may cause those routines to + * fail if the capture file format being written can't support that. + * It's also returned by "wtap_file_encap()" for capture files that + * don't have a single encapsulation type for all packets in the file. + * + * WTAP_ENCAP_UNKNOWN is returned by "wtap_pcap_encap_to_wtap_encap()" + * if it's handed an unknown encapsulation. + * + * WTAP_ENCAP_FDDI_BITSWAPPED is for FDDI captures on systems where the + * MAC addresses you get from the hardware are bit-swapped. Ideally, + * the driver would tell us that, but I know of none that do, so, for + * now, we base it on the machine on which we're *reading* the + * capture, rather than on the machine on which the capture was taken + * (they're probably likely to be the same). We assume that they're + * bit-swapped on everything except for systems running Ultrix, Alpha + * systems, and BSD/OS systems (that's what "tcpdump" does; I guess + * Digital decided to bit-swap addresses in the hardware or in the + * driver, and I guess BSDI bit-swapped them in the driver, given that + * BSD/OS generally runs on Boring Old PC's). If we create a wiretap + * save file format, we'd use the WTAP_ENCAP values to flag the + * encapsulation of a packet, so there we'd at least be able to base + * it on the machine on which the capture was taken. + * + * WTAP_ENCAP_LINUX_ATM_CLIP is the encapsulation you get with the + * ATM on Linux code from ; + * that code adds a DLT_ATM_CLIP DLT_ code of 19, and that + * encapsulation isn't the same as the DLT_ATM_RFC1483 encapsulation + * presumably used on some BSD systems, which we turn into + * WTAP_ENCAP_ATM_RFC1483. + * + * WTAP_ENCAP_NULL corresponds to DLT_NULL from "libpcap". This + * corresponds to + * + * 1) PPP-over-HDLC encapsulation, at least with some versions + * of ISDN4BSD (but not the current ones, it appears, unless + * I've missed something); + * + * 2) a 4-byte header containing the AF_ address family, in + * the byte order of the machine that saved the capture, + * for the packet, as used on many BSD systems for the + * loopback device and some other devices, or a 4-byte header + * containing the AF_ address family in network byte order, + * as used on recent OpenBSD systems for the loopback device; + * + * 3) a 4-byte header containing 2 octets of 0 and an Ethernet + * type in the byte order from an Ethernet header, that being + * what older versions of "libpcap" on Linux turn the Ethernet + * header for loopback interfaces into (0.6.0 and later versions + * leave the Ethernet header alone and make it DLT_EN10MB). */ +#define WTAP_ENCAP_PER_PACKET -1 +#define WTAP_ENCAP_UNKNOWN 0 +#define WTAP_ENCAP_ETHERNET 1 +#define WTAP_ENCAP_TOKEN_RING 2 +#define WTAP_ENCAP_SLIP 3 +#define WTAP_ENCAP_PPP 4 +#define WTAP_ENCAP_FDDI 5 +#define WTAP_ENCAP_FDDI_BITSWAPPED 6 +#define WTAP_ENCAP_RAW_IP 7 +#define WTAP_ENCAP_ARCNET 8 +#define WTAP_ENCAP_ARCNET_LINUX 9 +#define WTAP_ENCAP_ATM_RFC1483 10 +#define WTAP_ENCAP_LINUX_ATM_CLIP 11 +#define WTAP_ENCAP_LAPB 12 +#define WTAP_ENCAP_ATM_PDUS 13 +#define WTAP_ENCAP_ATM_PDUS_UNTRUNCATED 14 +#define WTAP_ENCAP_NULL 15 +#define WTAP_ENCAP_ASCEND 16 +#define WTAP_ENCAP_ISDN 17 +#define WTAP_ENCAP_IP_OVER_FC 18 +#define WTAP_ENCAP_PPP_WITH_PHDR 19 +#define WTAP_ENCAP_IEEE_802_11 20 +#define WTAP_ENCAP_PRISM_HEADER 21 +#define WTAP_ENCAP_IEEE_802_11_WITH_RADIO 22 +#define WTAP_ENCAP_IEEE_802_11_WLAN_RADIOTAP 23 +#define WTAP_ENCAP_IEEE_802_11_WLAN_AVS 24 +#define WTAP_ENCAP_SLL 25 +#define WTAP_ENCAP_FRELAY 26 +#define WTAP_ENCAP_FRELAY_WITH_PHDR 27 +#define WTAP_ENCAP_CHDLC 28 +#define WTAP_ENCAP_CISCO_IOS 29 +#define WTAP_ENCAP_LOCALTALK 30 +#define WTAP_ENCAP_OLD_PFLOG 31 +#define WTAP_ENCAP_HHDLC 32 +#define WTAP_ENCAP_DOCSIS 33 +#define WTAP_ENCAP_COSINE 34 +#define WTAP_ENCAP_WFLEET_HDLC 35 +#define WTAP_ENCAP_SDLC 36 +#define WTAP_ENCAP_TZSP 37 +#define WTAP_ENCAP_ENC 38 +#define WTAP_ENCAP_PFLOG 39 +#define WTAP_ENCAP_CHDLC_WITH_PHDR 40 +#define WTAP_ENCAP_BLUETOOTH_H4 41 +#define WTAP_ENCAP_MTP2 42 +#define WTAP_ENCAP_MTP3 43 +#define WTAP_ENCAP_IRDA 44 +#define WTAP_ENCAP_USER0 45 +#define WTAP_ENCAP_USER1 46 +#define WTAP_ENCAP_USER2 47 +#define WTAP_ENCAP_USER3 48 +#define WTAP_ENCAP_USER4 49 +#define WTAP_ENCAP_USER5 50 +#define WTAP_ENCAP_USER6 51 +#define WTAP_ENCAP_USER7 52 +#define WTAP_ENCAP_USER8 53 +#define WTAP_ENCAP_USER9 54 +#define WTAP_ENCAP_USER10 55 +#define WTAP_ENCAP_USER11 56 +#define WTAP_ENCAP_USER12 57 +#define WTAP_ENCAP_USER13 58 +#define WTAP_ENCAP_USER14 59 +#define WTAP_ENCAP_USER15 60 +#define WTAP_ENCAP_SYMANTEC 61 +#define WTAP_ENCAP_APPLE_IP_OVER_IEEE1394 62 +#define WTAP_ENCAP_BACNET_MS_TP 63 +#define WTAP_ENCAP_NETTL_RAW_ICMP 64 +#define WTAP_ENCAP_NETTL_RAW_ICMPV6 65 +#define WTAP_ENCAP_GPRS_LLC 66 +#define WTAP_ENCAP_JUNIPER_ATM1 67 +#define WTAP_ENCAP_JUNIPER_ATM2 68 +#define WTAP_ENCAP_REDBACK 69 +#define WTAP_ENCAP_NETTL_RAW_IP 70 +#define WTAP_ENCAP_NETTL_ETHERNET 71 +#define WTAP_ENCAP_NETTL_TOKEN_RING 72 +#define WTAP_ENCAP_NETTL_FDDI 73 +#define WTAP_ENCAP_NETTL_UNKNOWN 74 +#define WTAP_ENCAP_MTP2_WITH_PHDR 75 +#define WTAP_ENCAP_JUNIPER_PPPOE 76 +#define WTAP_GCOM_TIE1 77 +#define WTAP_GCOM_SERIAL 78 +#define WTAP_ENCAP_NETTL_X25 79 +#define WTAP_ENCAP_K12 80 +#define WTAP_ENCAP_JUNIPER_MLPPP 81 +#define WTAP_ENCAP_JUNIPER_MLFR 82 +#define WTAP_ENCAP_JUNIPER_ETHER 83 +#define WTAP_ENCAP_JUNIPER_PPP 84 +#define WTAP_ENCAP_JUNIPER_FRELAY 85 +#define WTAP_ENCAP_JUNIPER_CHDLC 86 +#define WTAP_ENCAP_JUNIPER_GGSN 87 +#define WTAP_ENCAP_LINUX_LAPD 88 +#define WTAP_ENCAP_CATAPULT_DCT2000 89 +#define WTAP_ENCAP_BER 90 +#define WTAP_ENCAP_JUNIPER_VP 91 +#define WTAP_ENCAP_USB 92 +#define WTAP_ENCAP_IEEE802_16_MAC_CPS 93 +#define WTAP_ENCAP_NETTL_RAW_TELNET 94 +#define WTAP_ENCAP_USB_LINUX 95 +#define WTAP_ENCAP_MPEG 96 +#define WTAP_ENCAP_PPI 97 +#define WTAP_ENCAP_ERF 98 +#define WTAP_ENCAP_BLUETOOTH_H4_WITH_PHDR 99 +#define WTAP_ENCAP_SITA 100 +#define WTAP_ENCAP_SCCP 101 +#define WTAP_ENCAP_BLUETOOTH_HCI 102 /*raw packets without a transport layer header e.g. H4*/ +#define WTAP_ENCAP_IPMB 103 +#define WTAP_ENCAP_IEEE802_15_4 104 +#define WTAP_ENCAP_X2E_XORAYA 105 +#define WTAP_ENCAP_FLEXRAY 106 +#define WTAP_ENCAP_LIN 107 +#define WTAP_ENCAP_MOST 108 +#define WTAP_ENCAP_CAN20B 109 + +#define WTAP_NUM_ENCAP_TYPES wtap_get_num_encap_types() + +/* File types that can be read by wiretap. + We support writing some many of these file types, too, so we + distinguish between different versions of them. */ +#define WTAP_FILE_UNKNOWN 0 +#define WTAP_FILE_WTAP 1 +#define WTAP_FILE_PCAP 2 +#define WTAP_FILE_PCAP_NSEC 3 +#define WTAP_FILE_PCAP_AIX 4 +#define WTAP_FILE_PCAP_SS991029 5 +#define WTAP_FILE_PCAP_NOKIA 6 +#define WTAP_FILE_PCAP_SS990417 7 +#define WTAP_FILE_PCAP_SS990915 8 +#define WTAP_FILE_5VIEWS 9 +#define WTAP_FILE_IPTRACE_1_0 10 +#define WTAP_FILE_IPTRACE_2_0 11 +#define WTAP_FILE_BER 12 +#define WTAP_FILE_HCIDUMP 13 +#define WTAP_FILE_CATAPULT_DCT2000 14 +#define WTAP_FILE_NETXRAY_OLD 15 +#define WTAP_FILE_NETXRAY_1_0 16 +#define WTAP_FILE_COSINE 17 +#define WTAP_FILE_CSIDS 18 +#define WTAP_FILE_DBS_ETHERWATCH 19 +#define WTAP_FILE_ERF 20 +#define WTAP_FILE_EYESDN 21 +#define WTAP_FILE_NETTL 22 +#define WTAP_FILE_ISERIES 23 +#define WTAP_FILE_ISERIES_UNICODE 24 +#define WTAP_FILE_I4BTRACE 25 +#define WTAP_FILE_ASCEND 26 +#define WTAP_FILE_NETMON_1_x 27 +#define WTAP_FILE_NETMON_2_x 28 +#define WTAP_FILE_NGSNIFFER_UNCOMPRESSED 29 +#define WTAP_FILE_NGSNIFFER_COMPRESSED 30 +#define WTAP_FILE_NETXRAY_1_1 31 +#define WTAP_FILE_NETXRAY_2_00x 32 +#define WTAP_FILE_NETWORK_INSTRUMENTS_V9 33 +#define WTAP_FILE_LANALYZER 34 +#define WTAP_FILE_PPPDUMP 35 +#define WTAP_FILE_RADCOM 36 +#define WTAP_FILE_SNOOP 37 +#define WTAP_FILE_SHOMITI 38 +#define WTAP_FILE_VMS 39 +#define WTAP_FILE_K12 40 +#define WTAP_FILE_TOSHIBA 41 +#define WTAP_FILE_VISUAL_NETWORKS 42 +#define WTAP_FILE_ETHERPEEK_V56 43 +#define WTAP_FILE_ETHERPEEK_V7 44 +#define WTAP_FILE_AIROPEEK_V9 45 +#define WTAP_FILE_MPEG 46 +#define WTAP_FILE_K12TEXT 47 +#define WTAP_FILE_NETSCREEN 48 +#define WTAP_FILE_COMMVIEW 49 +#define WTAP_FILE_PCAPNG 50 +#define WTAP_FILE_BTSNOOP 51 +#define WTAP_FILE_X2E_XORAYA 52 + +#define WTAP_NUM_FILE_TYPES wtap_get_num_file_types() + +/* timestamp precision (currently only these values are supported) */ +#define WTAP_FILE_TSPREC_SEC 0 +#define WTAP_FILE_TSPREC_DSEC 1 +#define WTAP_FILE_TSPREC_CSEC 2 +#define WTAP_FILE_TSPREC_MSEC 3 +#define WTAP_FILE_TSPREC_USEC 6 +#define WTAP_FILE_TSPREC_NSEC 9 + +/* + * Maximum packet size we'll support. + * It must be at least 65535. + */ +#define WTAP_MAX_PACKET_SIZE 65535 + +/* + * "Pseudo-headers" are used to supply to the clients of wiretap + * per-packet information that's not part of the packet payload + * proper. + * + * NOTE: do not use pseudo-header structures to hold information + * used by the code to read a particular capture file type; to + * keep that sort of state information, add a new structure for + * that private information to "wtap-int.h", add a pointer to that + * type of structure to the "capture" member of the "struct wtap" + * structure, and allocate one of those structures and set that member + * in the "open" routine for that capture file type if the open + * succeeds. See various other capture file type handlers for examples + * of that. + */ + +/* Packet "pseudo-header" information for Ethernet capture files. */ +struct eth_phdr { + gint fcs_len; /* Number of bytes of FCS - -1 means "unknown" */ +}; + +/* Packet "pseudo-header" information for X.25 capture files. */ +#define FROM_DCE 0x80 +struct x25_phdr { + guint8 flags; /* ENCAP_LAPB, ENCAP_V120 : 1st bit means From DCE */ +}; + +/* Packet "pseudo-header" information for ISDN capture files. */ + +/* Direction */ +struct isdn_phdr { + gboolean uton; + guint8 channel; /* 0 = D-channel; n = B-channel n */ +}; + +/* Packet "pseudo-header" for ATM capture files. + Not all of this information is supplied by all capture types. */ + +/* + * Status bits. + */ +#define ATM_RAW_CELL 0x01 /* TRUE if the packet is a single cell */ + +/* + * AAL types. + */ +#define AAL_UNKNOWN 0 /* AAL unknown */ +#define AAL_1 1 /* AAL1 */ +#define AAL_2 2 /* AAL2 */ +#define AAL_3_4 3 /* AAL3/4 */ +#define AAL_5 4 /* AAL5 */ +#define AAL_USER 5 /* User AAL */ +#define AAL_SIGNALLING 6 /* Signaling AAL */ +#define AAL_OAMCELL 7 /* OAM cell */ + +/* + * Traffic types. + */ +#define TRAF_UNKNOWN 0 /* Unknown */ +#define TRAF_LLCMX 1 /* LLC multiplexed (RFC 1483) */ +#define TRAF_VCMX 2 /* VC multiplexed (RFC 1483) */ +#define TRAF_LANE 3 /* LAN Emulation */ +#define TRAF_ILMI 4 /* ILMI */ +#define TRAF_FR 5 /* Frame Relay */ +#define TRAF_SPANS 6 /* FORE SPANS */ +#define TRAF_IPSILON 7 /* Ipsilon */ +#define TRAF_UMTS_FP 8 /* UMTS Frame Protocol */ + +/* + * Traffic subtypes. + */ +#define TRAF_ST_UNKNOWN 0 /* Unknown */ + +/* + * For TRAF_VCMX: + */ +#define TRAF_ST_VCMX_802_3_FCS 1 /* 802.3 with an FCS */ +#define TRAF_ST_VCMX_802_4_FCS 2 /* 802.4 with an FCS */ +#define TRAF_ST_VCMX_802_5_FCS 3 /* 802.5 with an FCS */ +#define TRAF_ST_VCMX_FDDI_FCS 4 /* FDDI with an FCS */ +#define TRAF_ST_VCMX_802_6_FCS 5 /* 802.6 with an FCS */ +#define TRAF_ST_VCMX_802_3 7 /* 802.3 without an FCS */ +#define TRAF_ST_VCMX_802_4 8 /* 802.4 without an FCS */ +#define TRAF_ST_VCMX_802_5 9 /* 802.5 without an FCS */ +#define TRAF_ST_VCMX_FDDI 10 /* FDDI without an FCS */ +#define TRAF_ST_VCMX_802_6 11 /* 802.6 without an FCS */ +#define TRAF_ST_VCMX_FRAGMENTS 12 /* Fragments */ +#define TRAF_ST_VCMX_BPDU 13 /* BPDU */ + +/* + * For TRAF_LANE: + */ +#define TRAF_ST_LANE_LE_CTRL 1 /* LANE: LE Ctrl */ +#define TRAF_ST_LANE_802_3 2 /* LANE: 802.3 */ +#define TRAF_ST_LANE_802_5 3 /* LANE: 802.5 */ +#define TRAF_ST_LANE_802_3_MC 4 /* LANE: 802.3 multicast */ +#define TRAF_ST_LANE_802_5_MC 5 /* LANE: 802.5 multicast */ + +/* + * For TRAF_IPSILON: + */ +#define TRAF_ST_IPSILON_FT0 1 /* Ipsilon: Flow Type 0 */ +#define TRAF_ST_IPSILON_FT1 2 /* Ipsilon: Flow Type 1 */ +#define TRAF_ST_IPSILON_FT2 3 /* Ipsilon: Flow Type 2 */ + +struct atm_phdr { + guint32 flags; /* status flags */ + guint8 aal; /* AAL of the traffic */ + guint8 type; /* traffic type */ + guint8 subtype; /* traffic subtype */ + guint16 vpi; /* virtual path identifier */ + guint16 vci; /* virtual circuit identifier */ + guint8 aal2_cid; /* channel id */ + guint16 channel; /* link: 0 for DTE->DCE, 1 for DCE->DTE */ + guint16 cells; /* number of cells */ + guint16 aal5t_u2u; /* user-to-user indicator */ + guint16 aal5t_len; /* length of the packet */ + guint32 aal5t_chksum; /* checksum for AAL5 packet */ +}; + +/* Packet "pseudo-header" for the output from "wandsession", "wannext", + "wandisplay", and similar commands on Lucent/Ascend access equipment. */ + +#define ASCEND_MAX_STR_LEN 64 + +#define ASCEND_PFX_WDS_X 1 +#define ASCEND_PFX_WDS_R 2 +#define ASCEND_PFX_WDD 3 +#define ASCEND_PFX_ISDN_X 4 +#define ASCEND_PFX_ISDN_R 5 +#define ASCEND_PFX_ETHER 6 + +struct ascend_phdr { + guint16 type; /* ASCEND_PFX_*, as defined above */ + char user[ASCEND_MAX_STR_LEN]; /* Username, from wandsession header */ + guint32 sess; /* Session number, from wandsession header */ + char call_num[ASCEND_MAX_STR_LEN]; /* Called number, from WDD header */ + guint32 chunk; /* Chunk number, from WDD header */ + guint32 task; /* Task number */ +}; + +/* Packet "pseudo-header" for point-to-point links with direction flags. */ +struct p2p_phdr { + gboolean sent; /* TRUE=sent, FALSE=received */ +}; + +/* + * Packet "pseudo-header" information for 802.11. + * Radio information is only present for WTAP_ENCAP_IEEE_802_11_WITH_RADIO. + * + * Signal strength, etc. information: + * + * Raw signal strength can be measured in milliwatts. + * It can also be represented as dBm, which is 10 times the log base 10 + * of the signal strength in mW. + * + * The Receive Signal Strength Indicator is an integer in the range 0 to 255. + * The actual RSSI value for a given signal strength is dependent on the + * vendor (and perhaps on the adapter). The maximum possible RSSI value + * is also dependent on the vendor and perhaps the adapter. + * + * The signal strength can be represented as a percentage, which is 100 + * times the ratio of the RSSI and the maximum RSSI. + */ +struct ieee_802_11_phdr { + gint fcs_len; /* Number of bytes of FCS - -1 means "unknown" */ + guint8 channel; /* Channel number */ + guint8 data_rate; /* in .5 Mb/s units */ + guint8 signal_level; /* percentage */ +}; + +/* Packet "pseudo-header" for the output from CoSine L2 debug output. */ + +#define COSINE_MAX_IF_NAME_LEN 128 + +#define COSINE_ENCAP_TEST 1 +#define COSINE_ENCAP_PPoATM 2 +#define COSINE_ENCAP_PPoFR 3 +#define COSINE_ENCAP_ATM 4 +#define COSINE_ENCAP_FR 5 +#define COSINE_ENCAP_HDLC 6 +#define COSINE_ENCAP_PPP 7 +#define COSINE_ENCAP_ETH 8 +#define COSINE_ENCAP_UNKNOWN 99 + +#define COSINE_DIR_TX 1 +#define COSINE_DIR_RX 2 + +struct cosine_phdr { + guint8 encap; /* COSINE_ENCAP_* as defined above */ + guint8 direction; /* COSINE_DIR_*, as defined above */ + char if_name[COSINE_MAX_IF_NAME_LEN]; /* Encap & Logical I/F name */ + guint16 pro; /* Protocol */ + guint16 off; /* Offset */ + guint16 pri; /* Priority */ + guint16 rm; /* Rate Marking */ + guint16 err; /* Error Code */ +}; + +/* Packet "pseudo-header" for IrDA capture files. */ + +/* + * Direction of the packet + */ +#define IRDA_INCOMING 0x0000 +#define IRDA_OUTGOING 0x0004 + +/* + * "Inline" log messages produced by IrCOMM2k on Windows + */ +#define IRDA_LOG_MESSAGE 0x0100 /* log message */ +#define IRDA_MISSED_MSG 0x0101 /* missed log entry or frame */ + +/* + * Differentiate between frames and log messages + */ +#define IRDA_CLASS_FRAME 0x0000 +#define IRDA_CLASS_LOG 0x0100 +#define IRDA_CLASS_MASK 0xFF00 + +struct irda_phdr { + guint16 pkttype; /* packet type */ +}; + +/* Packet "pseudo-header" for nettl (HP-UX) capture files. */ + +struct nettl_phdr { + guint16 subsys; + guint32 devid; + guint32 kind; + gint32 pid; + guint16 uid; +}; + +/* Packet "pseudo-header" for MTP2 files. */ + +#define MTP2_ANNEX_A_NOT_USED 0 +#define MTP2_ANNEX_A_USED 1 +#define MTP2_ANNEX_A_USED_UNKNOWN 2 + +struct mtp2_phdr { + guint8 sent; + guint8 annex_a_used; + guint16 link_number; +}; + +/* Packet "pseudo-header" for K12 files. */ + +typedef union { + struct { + guint16 vp; + guint16 vc; + guint16 cid; + } atm; + + guint32 ds0mask; +} k12_input_info_t; + +struct k12_phdr { + guint32 input; + const gchar* input_name; + const gchar* stack_file; + guint32 input_type; + k12_input_info_t input_info; + gchar* extra_info; + guint32 extra_length; + void* stuff; +}; + +#define K12_PORT_DS0S 0x00010008 +#define K12_PORT_DS1 0x00100008 +#define K12_PORT_ATMPVC 0x01020000 + +struct lapd_phdr { + guint16 pkttype; /* packet type */ + guint8 we_network; +}; + +struct wtap; +struct catapult_dct2000_phdr +{ + union + { + struct isdn_phdr isdn; + struct atm_phdr atm; + struct p2p_phdr p2p; + } inner_pseudo_header; + gint64 seek_off; + struct wtap *wth; +}; + +/* + * possible event type + */ +#define URB_SUBMIT 'S' +#define URB_COMPLETE 'C' +#define URB_ERROR 'E' + +/* + * possible transfer mode + */ +#define URB_ISOCHRONOUS 0x0 +#define URB_INTERRUPT 0x1 +#define URB_CONTROL 0x2 +#define URB_BULK 0x3 + +#define URB_TRANSFER_IN 0x80 /* to host */ + +/* + * USB setup header as defined in USB specification + */ +struct usb_request_hdr { + gint8 bmRequestType; + guint8 bRequest; + guint16 wValue; + guint16 wIndex; + guint16 wLength; +}; + +/* + * Header prepended by Linux kernel to each USB event. + * Followed by a struct usb_request_hdr, although that header is valid + * only if setup_flag is 0. + * (Setup flag is '-', 'D', 'Z', or 0. Data flag is '<', '>', 'Z', or 0.) + * + * We present this as a pseudo-header; the values are in host byte order. + */ +struct linux_usb_phdr { + guint64 id; /* urb id, to link submission and completion events*/ + guint8 event_type; /* Submit ('S'), Completed ('C'), Error ('E') */ + guint8 transfer_type; /* ISO (0), Intr, Control, Bulk (3) */ + guint8 endpoint_number; /* Endpoint number (0-15) and transfer direction */ + guint8 device_address; /* 0-127 */ + guint16 bus_id; + gint8 setup_flag; /*if !=0 the urb setup header is not present*/ + gint8 data_flag; /*if !=0 no urb data is present*/ + gint64 ts_sec; + gint32 ts_usec; + gint32 status; + guint32 urb_len; /* whole len of urb this event refers to */ + guint32 data_len; /* amount of urb data really present in this event*/ +}; + +/* + * Header prepended by libpcap to each bluetooth hci h:4 frame. + * Values in network byte order + */ +struct libpcap_bt_phdr { + guint32 direction; /* Bit 0 hold the frame direction. */ +}; + +/* + * Endace Record Format pseudo header + */ +struct erf_phdr { + guint64 ts; /* Time stamp */ + guint8 type; + guint8 flags; + guint16 rlen; + guint16 lctr; + guint16 wlen; +}; + +/* + * ERF pseudo header with optional subheader + * (Multichannel or Ethernet) + */ +struct erf_mc_phdr { + struct erf_phdr phdr; + union + { + guint16 eth_hdr; + guint32 mc_hdr; + } subhdr; +}; + +#define SITA_FRAME_DIR_TXED (0x00) /* values of sita_phdr.flags */ +#define SITA_FRAME_DIR_RXED (0x01) +#define SITA_FRAME_DIR (0x01) /* mask */ +#define SITA_ERROR_NO_BUFFER (0x80) + +#define SITA_SIG_DSR (0x01) /* values of sita_phdr.signals */ +#define SITA_SIG_DTR (0x02) +#define SITA_SIG_CTS (0x04) +#define SITA_SIG_RTS (0x08) +#define SITA_SIG_DCD (0x10) +#define SITA_SIG_UNDEF1 (0x20) +#define SITA_SIG_UNDEF2 (0x40) +#define SITA_SIG_UNDEF3 (0x80) + +#define SITA_ERROR_TX_UNDERRUN (0x01) /* values of sita_phdr.errors2 (if SITA_FRAME_DIR_TXED) */ +#define SITA_ERROR_TX_CTS_LOST (0x02) +#define SITA_ERROR_TX_UART_ERROR (0x04) +#define SITA_ERROR_TX_RETX_LIMIT (0x08) +#define SITA_ERROR_TX_UNDEF1 (0x10) +#define SITA_ERROR_TX_UNDEF2 (0x20) +#define SITA_ERROR_TX_UNDEF3 (0x40) +#define SITA_ERROR_TX_UNDEF4 (0x80) + +#define SITA_ERROR_RX_FRAMING (0x01) /* values of sita_phdr.errors1 (if SITA_FRAME_DIR_RXED) */ +#define SITA_ERROR_RX_PARITY (0x02) +#define SITA_ERROR_RX_COLLISION (0x04) +#define SITA_ERROR_RX_FRAME_LONG (0x08) +#define SITA_ERROR_RX_FRAME_SHORT (0x10) +#define SITA_ERROR_RX_UNDEF1 (0x20) +#define SITA_ERROR_RX_UNDEF2 (0x40) +#define SITA_ERROR_RX_UNDEF3 (0x80) + +#define SITA_ERROR_RX_NONOCTET_ALIGNED (0x01) /* values of sita_phdr.errors2 (if SITA_FRAME_DIR_RXED) */ +#define SITA_ERROR_RX_ABORT (0x02) +#define SITA_ERROR_RX_CD_LOST (0x04) +#define SITA_ERROR_RX_DPLL (0x08) +#define SITA_ERROR_RX_OVERRUN (0x10) +#define SITA_ERROR_RX_FRAME_LEN_VIOL (0x20) +#define SITA_ERROR_RX_CRC (0x40) +#define SITA_ERROR_RX_BREAK (0x80) + +#define SITA_PROTO_UNUSED (0x00) /* values of sita_phdr.proto */ +#define SITA_PROTO_BOP_LAPB (0x01) +#define SITA_PROTO_ETHERNET (0x02) +#define SITA_PROTO_ASYNC_INTIO (0x03) +#define SITA_PROTO_ASYNC_BLKIO (0x04) +#define SITA_PROTO_ALC (0x05) +#define SITA_PROTO_UTS (0x06) +#define SITA_PROTO_PPP_HDLC (0x07) +#define SITA_PROTO_SDLC (0x08) +#define SITA_PROTO_TOKENRING (0x09) +#define SITA_PROTO_I2C (0x10) +#define SITA_PROTO_DPM_LINK (0x11) +#define SITA_PROTO_BOP_FRL (0x12) + +struct sita_phdr { + guint8 flags; + guint8 signals; + guint8 errors1; + guint8 errors2; + guint8 proto; +}; + +/*pseudo header for Bluetooth HCI*/ +struct bthci_phdr { + gboolean sent; + guint8 channel; +}; + +#define BTHCI_CHANNEL_COMMAND 1 +#define BTHCI_CHANNEL_ACL 2 +#define BTHCI_CHANNEL_SCO 3 +#define BTHCI_CHANNEL_EVENT 4 + +union wtap_pseudo_header { + struct eth_phdr eth; + struct x25_phdr x25; + struct isdn_phdr isdn; + struct atm_phdr atm; + struct ascend_phdr ascend; + struct p2p_phdr p2p; + struct ieee_802_11_phdr ieee_802_11; + struct cosine_phdr cosine; + struct irda_phdr irda; + struct nettl_phdr nettl; + struct mtp2_phdr mtp2; + struct k12_phdr k12; + struct lapd_phdr lapd; + struct catapult_dct2000_phdr dct2000; + struct linux_usb_phdr linux_usb; + struct erf_mc_phdr erf; + struct sita_phdr sita; + struct bthci_phdr bthci; +}; + +struct wtap_nstime { + time_t secs; + int nsecs; +}; + +struct wtap_pkthdr { + struct wtap_nstime ts; + guint32 caplen; + guint32 len; + int pkt_encap; +}; + +struct wtap; +struct Buffer; +struct wtap_dumper; + +typedef struct wtap wtap; +typedef struct wtap_dumper wtap_dumper; + +struct file_type_info { + /* the file type name */ + /* should be NULL for all "pseudo" types that are only internally used and not read/writeable */ + const char *name; + + /* the file type short name, used as a shortcut for the command line tools */ + /* should be NULL for all "pseudo" types that are only internally used and not read/writeable */ + const char *short_name; + + /* the common file extensions for this type (seperated by semicolon) */ + /* should be *.* if no common extension is applicable */ + const char *file_extensions; + + /* the default file extension, used to save this type */ + /* should be NULL if no default extension is known */ + const char *file_extension_default; + + /* can this type be compressed with gzip? */ + gboolean can_compress; + + /* can this type write this encapsulation format? */ + /* should be NULL is this file type don't have write support */ + int (*can_write_encap)(int); + + /* the function to open the capture file for writing */ + /* should be NULL is this file type don't have write support */ + int (*dump_open)(wtap_dumper *, gboolean, int *); +}; + + +typedef int (*wtap_open_routine_t)(struct wtap*, int *, char **); + + +/* + * On failure, "wtap_open_offline()" returns NULL, and puts into the + * "int" pointed to by its second argument: + * + * a positive "errno" value if the capture file can't be opened; + * a negative number, indicating the type of error, on other failures. + */ +struct wtap* wtap_open_offline(const char *filename, int *err, + gchar **err_info, gboolean do_random); + +/* Returns TRUE if read was successful. FALSE if failure. data_offset is + * set to the offset in the file where the data for the read packet is + * located. */ +gboolean wtap_read(wtap *wth, int *err, gchar **err_info, + gint64 *data_offset); + +gboolean wtap_seek_read (wtap *wth, gint64 seek_off, + union wtap_pseudo_header *pseudo_header, guint8 *pd, int len, + int *err, gchar **err_info); + +/*** get various information snippets about the current packet ***/ +struct wtap_pkthdr *wtap_phdr(wtap *wth); +union wtap_pseudo_header *wtap_pseudoheader(wtap *wth); +guint8 *wtap_buf_ptr(wtap *wth); + +/*** get various information snippets about the current file ***/ + +/* Return an approximation of the amount of data we've read sequentially + * from the file so far. */ +gint64 wtap_read_so_far(wtap *wth, int *err); +gint64 wtap_file_size(wtap *wth, int *err); +int wtap_snapshot_length(wtap *wth); /* per file */ +int wtap_file_type(wtap *wth); +int wtap_file_encap(wtap *wth); +int wtap_file_tsprecision(wtap *wth); + +/*** close the current file ***/ +void wtap_sequential_close(wtap *wth); +void wtap_close(wtap *wth); + +/*** dump packets into a capture file ***/ +gboolean wtap_dump_can_open(int filetype); +gboolean wtap_dump_can_write_encap(int filetype, int encap); +gboolean wtap_dump_can_compress(int filetype); +wtap_dumper* wtap_dump_open(const char *filename, int filetype, int encap, + int snaplen, gboolean compressed, int *err); +wtap_dumper* wtap_dump_fdopen(int fd, int filetype, int encap, int snaplen, + gboolean compressed, int *err); +gboolean wtap_dump(wtap_dumper *, const struct wtap_pkthdr *, + const union wtap_pseudo_header *pseudo_header, const guchar *, int *err); +void wtap_dump_flush(wtap_dumper *); +gint64 wtap_get_bytes_dumped(wtap_dumper *); +void wtap_set_bytes_dumped(wtap_dumper *wdh, gint64 bytes_dumped); +gboolean wtap_dump_close(wtap_dumper *, int *); + +/*** various string converter functions ***/ +const char *wtap_file_type_string(int filetype); +const char *wtap_file_type_short_string(int filetype); +int wtap_short_string_to_file_type(const char *short_name); + +const char *wtap_file_extensions_string(int filetype); +const char *wtap_file_extension_default_string(int filetype); + +const char *wtap_encap_string(int encap); +const char *wtap_encap_short_string(int encap); +int wtap_short_string_to_encap(const char *short_name); + +const char *wtap_strerror(int err); + +/*** get available number of file types and encapsulations ***/ +int wtap_get_num_encap_types(void); +int wtap_get_num_file_types(void); + +/*** dynamically register new file types and encapsulations ***/ +void wtap_register_open_routine(wtap_open_routine_t, gboolean has_magic); +int wtap_register_file_type(const struct file_type_info* fi); +int wtap_register_encap_type(char* name, char* short_name); + + +/* + * Wiretap error codes. + */ +#define WTAP_ERR_NOT_REGULAR_FILE -1 + /* The file being opened for reading isn't a plain file (or pipe) */ +#define WTAP_ERR_RANDOM_OPEN_PIPE -2 + /* The file is being opened for random access and it's a pipe */ +#define WTAP_ERR_FILE_UNKNOWN_FORMAT -3 + /* The file being opened is not a capture file in a known format */ +#define WTAP_ERR_UNSUPPORTED -4 + /* Supported file type, but there's something in the file we + can't support */ +#define WTAP_ERR_CANT_WRITE_TO_PIPE -5 + /* Wiretap can't save to a pipe in the specified format */ +#define WTAP_ERR_CANT_OPEN -6 + /* The file couldn't be opened, reason unknown */ +#define WTAP_ERR_UNSUPPORTED_FILE_TYPE -7 + /* Wiretap can't save files in the specified format */ +#define WTAP_ERR_UNSUPPORTED_ENCAP -8 + /* Wiretap can't read or save files in the specified format with the + specified encapsulation */ +#define WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED -9 + /* The specified format doesn't support per-packet encapsulations */ +#define WTAP_ERR_CANT_CLOSE -10 + /* The file couldn't be closed, reason unknown */ +#define WTAP_ERR_CANT_READ -11 + /* An attempt to read failed, reason unknown */ +#define WTAP_ERR_SHORT_READ -12 + /* An attempt to read read less data than it should have */ +#define WTAP_ERR_BAD_RECORD -13 + /* We read an invalid record */ +#define WTAP_ERR_SHORT_WRITE -14 + /* An attempt to write wrote less data than it should have */ +#define WTAP_ERR_UNC_TRUNCATED -15 + /* Sniffer compressed data was oddly truncated */ +#define WTAP_ERR_UNC_OVERFLOW -16 + /* Uncompressing Sniffer data would overflow buffer */ +#define WTAP_ERR_UNC_BAD_OFFSET -17 + /* LZ77 compressed data has bad offset to string */ +#define WTAP_ERR_RANDOM_OPEN_STDIN -18 + /* We're trying to open the standard input for random access */ +#define WTAP_ERR_COMPRESSION_NOT_SUPPORTED -19 + /* The filetype doesn't support output compression */ + +/* Errors from zlib; zlib error Z_xxx turns into Wiretap error + WTAP_ERR_ZLIB + Z_xxx. + + WTAP_ERR_ZLIB_MIN and WTAP_ERR_ZLIB_MAX bound the range of zlib + errors; we leave room for 100 positive and 100 negative error + codes. */ + +#define WTAP_ERR_ZLIB -200 +#define WTAP_ERR_ZLIB_MAX -100 +#define WTAP_ERR_ZLIB_MIN -300 + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __WTAP_H__ */ diff --git a/requirements.txt b/requirements.txt index c13c31d2..9055ea05 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,8 +16,7 @@ asyncssh==1.17.1 cryptography>=2.7 asyncio==3.4.3 pytest==5.1.0 -PyYAML==5.1.2 #awscli>=1.16.224 progressbar2==3.43.1 testresources==2.0.1 -git+https://github.com/Giuseppe1992/mapping_distrinet-1.git \ No newline at end of file +git+https://github.com/Giuseppe1992/mapping_distrinet-1.git From 597ab8fcca4364a50765831ce8c8a9f4caf77981 Mon Sep 17 00:00:00 2001 From: J980419xq <1908393204@qq.com> Date: Fri, 14 Oct 2022 18:47:32 +0800 Subject: [PATCH 40/44] test --- mininet/bin/dmn | 11 +++++++---- mininet/mininet/distrinet.py | 19 +++++++++++++++---- mininet/mininet/lxc_container.py | 11 ++++++++++- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/mininet/bin/dmn b/mininet/bin/dmn index 0ef98de8..4da1eff9 100755 --- a/mininet/bin/dmn +++ b/mininet/bin/dmn @@ -298,10 +298,12 @@ class DistrinetRunner( object ): dest='test', help='|'.join( TESTS.keys() ) ) opts.add_option( '--xterms', '-x', action='store_true', default=False, help='spawn xterms for each node' ) - opts.add_option( '--ipbase', '-i', type='string', default='10.10.1.5/16', + opts.add_option( '--ipbase', '-i', type='string', default='12.12.1.6/16', help='base IP address for hosts' ) - opts.add_option( '--providerIpbase', '-p', type='string', default='20.20.1.5/16', + opts.add_option( '--providerIpbase', '-p', type='string', default='20.20.1.6/16', help='base Provider IP address for hosts' ) + opts.add_option( '--controllIpbase', '-j', type='string', default='10.10.1.6/16', + help='base controll IP address for hosts' ) opts.add_option( '--mac', action='store_true', default=False, help='automatically set host MACs' ) opts.add_option('--docker',action='store_true', @@ -552,7 +554,7 @@ class DistrinetRunner( object ): if opts.workers: workers = opts.workers.split( ',' ) master = workers[0] - + workers=workers[1:] if opts.workers or opts.provision or opts.placement_file_path: warn( '*** WARNING: Experimental cloud mode!\n' @@ -618,7 +620,8 @@ class DistrinetRunner( object ): switch=switch, host=host, controller=controller, link=link, - ipBase=opts.ipbase,providerIpBase=opts.providerIpbase, inNamespace=opts.innamespace, + ipBase=opts.ipbase, providerIpBase=opts.providerIpbase, controllIpBase=opts.controllIpbase, + inNamespace=opts.innamespace, xterms=opts.xterms, autoSetMacs=opts.mac, autoSetDocker=opts.docker, autoStaticArp=opts.arp, autoPinCpus=opts.pin, diff --git a/mininet/mininet/distrinet.py b/mininet/mininet/distrinet.py index 3b854c0a..25e812e6 100755 --- a/mininet/mininet/distrinet.py +++ b/mininet/mininet/distrinet.py @@ -139,7 +139,7 @@ def __init__( self, topo=None, switch=LxcSwitch, host=LxcNode, controller=LxcRemoteController, link=CloudLink, intf=TCIntf, mapper=None, build=True, xterms=False, cleanup=False, ipBase='10.0.0.0/8', - adminIpBase='192.168.0.1/8',providerIpBase='172.16.62.1/8', + adminIpBase='192.168.0.1/8',providerIpBase='172.16.62.1/8',controllIpBase='172.16.41.1/8', autoSetMacs=False, autoSetDocker=False,autoPinCpus=False, listenPort=None, waitConnected=False, waitConnectionTimeout=5, jump=None, user="root", client_keys=None, master=None, pub_id=None, @@ -179,6 +179,13 @@ def __init__( self, topo=None, switch=LxcSwitch, host=LxcNode, self.nextIP = hostIP if hostIP > 0 else 1 self.providerIpBase = providerIpBase + self.controllIpBase = controllIpBase + + self.controllIpBaseNum, self.controllPrefixLen = netParse( self.controllIpBase ) + controllIP = ( 0xffffffff >> self.controllPrefixLen ) & self.controllIpBaseNum + # Start for address allocation + self.controllNextIP = controllIP if controllIP > 0 else 1 + self.providerIpBaseNum, self.providerPrefixLen = netParse( self.providerIpBase ) providerIP = ( 0xffffffff >> self.providerPrefixLen ) & self.providerIpBaseNum # Start for address allocation @@ -538,7 +545,6 @@ def buildFromTopo( self, topo=None ): _info ("createContainer {} ".format( node.name)) _ip = "{}/{}".format(ipAdd( self.providerNextIP, ipBaseNum=self.providerIpBaseNum, prefixLen=self.providerPrefixLen),self.providerPrefixLen) self.providerNextIP += 1 - _info("providerip: {}".format(_ip)) node.createContainer(autoSetDocker=self.autoSetDocker,providerIP=_ip) count += 1 if count > 100: @@ -581,7 +587,9 @@ def buildFromTopo( self, topo=None ): for node in nodes: _ip = "{}/{}".format(ipAdd( self.adminNextIP, ipBaseNum=self.adminIpBaseNum, prefixLen=self.adminPrefixLen),self.adminPrefixLen) self.adminNextIP += 1 - node.configureContainer(admin_ip=_ip,wait=False,autoSetDocker=self.autoSetDocker) + _controllIp = "{}/{}".format(ipAdd( self.controllNextIP, ipBaseNum=self.controllIpBaseNum, prefixLen=self.controllPrefixLen),self.controllPrefixLen) + self.controllNextIP += 1 + node.configureContainer(admin_ip=_ip,controll_ip=_controllIp,wait=False,autoSetDocker=self.autoSetDocker) count+=1 if count>100: sleep(10) @@ -596,7 +604,10 @@ def buildFromTopo( self, topo=None ): for node in nodes: node.waitConnected() info ("connected {} ".format( node.name)) - + '''info ("starting nova compute") + for host in self.hosts: + host.startNovacompute() + info ("started nova compute")''' count=0 for node in nodes: info ("startshell {} ".format( node.name) ) diff --git a/mininet/mininet/lxc_container.py b/mininet/mininet/lxc_container.py index 25e5674d..da2da53c 100644 --- a/mininet/mininet/lxc_container.py +++ b/mininet/mininet/lxc_container.py @@ -182,7 +182,7 @@ def _preInit(self, self.admin_ip=None self.ssh = None - def configureContainer(self,admin_ip, adminbr="admin-br", wait=True,autoSetDocker=False): + def configureContainer(self, admin_ip, controll_ip, adminbr="admin-br", wait=True,autoSetDocker=False): # # connect the node to the admin network # self.addContainerInterface(intfName="admin", brname=adminbr) @@ -199,12 +199,17 @@ def configureContainer(self,admin_ip, adminbr="admin-br", wait=True,autoSetDocke self.admin_ip=admin_ip if "/" in admin_ip: admin_ip, prefix = admin_ip.split("/") + if "/" in controll_ip: + controll_ip, prefix = controll_ip.split("/") self.ssh = ASsh(loop=self.loop, host=admin_ip, username=self.username, bastion=self.bastion, client_keys=self.client_keys) if autoSetDocker: cmds.append("docker exec {} mkdir /root/.ssh".format(self.name)) cmds.append("docker exec {} bash -c 'echo \"{}\" >> /root/.ssh/authorized_keys'".format(self.name, self.pub_id)) cmds.append("docker exec {} service ssh start".format(self.name)) cmds.append("docker exec {} ifconfig admin {}".format(self.name,self.admin_ip)) + if self.image=="ubuntu": + print("docker network connect --ip {} network10 {}\n".format(controll_ip,self.name)) + cmds.append("docker network connect --ip {} network10 {}".format(controll_ip,self.name)) # configure the container to have else: # an admin IP address @@ -379,6 +384,10 @@ def createContainer(self,autoSetDocker=False,providerIP=None, **params): cmd = ";".join(cmds) self.targetSsh.sendCmd(cmd) + def startNovacompute(self): + cmd="python3 docker_configer_container_cmd.py" + self.ssh.sendCmd(cmd) + def targetSshWaitOutput(self): """ Wait for output on targetSsh From 4cf0630d41993ef49d6c4987b89566fc82d811f2 Mon Sep 17 00:00:00 2001 From: J980419xq <1908393204@qq.com> Date: Mon, 24 Oct 2022 10:30:06 +0800 Subject: [PATCH 41/44] finish --- k8s.md | 69 ------------------- mininet/bin/dmn | 10 +-- mininet/mininet/distrinet.py | 14 ++-- mininet/mininet/lxc_container.py | 10 +-- .../provision/playbooks/configure-docker.yml | 8 +-- .../provision/playbooks/deploy_compute.yml | 10 +++ .../playbooks/docker-nova-compute-auto.sh | 16 +++++ .../provision/playbooks/install-docker.yml | 51 ++------------ .../provision/playbooks/prepare-ansiable.sh | 22 ++++++ .../provision/playbooks/prepare-docker-net.sh | 13 ++++ .../provision/playbooks/prepare-openstack.sh | 19 +++++ 11 files changed, 107 insertions(+), 135 deletions(-) delete mode 100644 k8s.md create mode 100644 mininet/mininet/provision/playbooks/deploy_compute.yml create mode 100755 mininet/mininet/provision/playbooks/docker-nova-compute-auto.sh create mode 100755 mininet/mininet/provision/playbooks/prepare-ansiable.sh create mode 100755 mininet/mininet/provision/playbooks/prepare-docker-net.sh create mode 100644 mininet/mininet/provision/playbooks/prepare-openstack.sh diff --git a/k8s.md b/k8s.md deleted file mode 100644 index 0e8a0991..00000000 --- a/k8s.md +++ /dev/null @@ -1,69 +0,0 @@ -### Step 1: deploy onos cluster in k8s -```bash -vim onos.yaml -``` -``` -#onos.yaml -apiVersion: v1 -kind: Service -metadata: - labels: - app: onos - name: onos-deployment -spec: - ports: - - port: 6653 - protocol: TCP - targetPort: 6653 - nodePort: 30026 - selector: - app: onos - type: NodePort -status: - loadBalancer: {} ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - app: onos - name: onos-deployment -spec: - replicas: 10 - selector: - matchLabels: - app: onos - template: - metadata: - labels: - app: onos - spec: - containers: - - name: onos - image: onosproject/onos - env: - - name: ONOS_APPS - value: "drivers,openflow,fwd,proxyarp,lldpprovider" - args: - - start - ports: - - containerPort: 6653 - name: openflow - - containerPort: 6640 - name: ovsdb - - containerPort: 8181 - name: gui - - containerPort: 8101 - name: onos-cli - - containerPort: 9876 - name: cluster -``` - -```bash -kubectl create -f onos.yaml -``` - -### Step 2: using k8s' onos service as distrinet controller -```bash -python3 bin/dmn --bastion=172.16.66.92 --workers="172.16.66.92,172.16.66.93,172.16.66.94" --controller=lxcremote,ip=192.168.0.1:30026 --topo=linear,2 -``` diff --git a/mininet/bin/dmn b/mininet/bin/dmn index 4da1eff9..684771c7 100755 --- a/mininet/bin/dmn +++ b/mininet/bin/dmn @@ -298,12 +298,12 @@ class DistrinetRunner( object ): dest='test', help='|'.join( TESTS.keys() ) ) opts.add_option( '--xterms', '-x', action='store_true', default=False, help='spawn xterms for each node' ) - opts.add_option( '--ipbase', '-i', type='string', default='12.12.1.6/16', + opts.add_option( '--ipbase', '-i', type='string', default='10.10.1.5/16', help='base IP address for hosts' ) - opts.add_option( '--providerIpbase', '-p', type='string', default='20.20.1.6/16', + opts.add_option( '--providerIpbase', '-p', type='string', default='20.20.1.5/16', help='base Provider IP address for hosts' ) - opts.add_option( '--controllIpbase', '-j', type='string', default='10.10.1.6/16', - help='base controll IP address for hosts' ) + '''opts.add_option( '--controllIpbase', '-j', type='string', default='10.10.1.6/16', + help='base controll IP address for hosts' )''' opts.add_option( '--mac', action='store_true', default=False, help='automatically set host MACs' ) opts.add_option('--docker',action='store_true', @@ -620,7 +620,7 @@ class DistrinetRunner( object ): switch=switch, host=host, controller=controller, link=link, - ipBase=opts.ipbase, providerIpBase=opts.providerIpbase, controllIpBase=opts.controllIpbase, + ipBase=opts.ipbase, providerIpBase=opts.providerIpbase, inNamespace=opts.innamespace, xterms=opts.xterms, autoSetMacs=opts.mac, autoSetDocker=opts.docker, diff --git a/mininet/mininet/distrinet.py b/mininet/mininet/distrinet.py index 25e812e6..8d91cd9a 100755 --- a/mininet/mininet/distrinet.py +++ b/mininet/mininet/distrinet.py @@ -139,7 +139,7 @@ def __init__( self, topo=None, switch=LxcSwitch, host=LxcNode, controller=LxcRemoteController, link=CloudLink, intf=TCIntf, mapper=None, build=True, xterms=False, cleanup=False, ipBase='10.0.0.0/8', - adminIpBase='192.168.0.1/8',providerIpBase='172.16.62.1/8',controllIpBase='172.16.41.1/8', + adminIpBase='192.168.0.1/8',providerIpBase='172.16.62.1/8', autoSetMacs=False, autoSetDocker=False,autoPinCpus=False, listenPort=None, waitConnected=False, waitConnectionTimeout=5, jump=None, user="root", client_keys=None, master=None, pub_id=None, @@ -179,12 +179,12 @@ def __init__( self, topo=None, switch=LxcSwitch, host=LxcNode, self.nextIP = hostIP if hostIP > 0 else 1 self.providerIpBase = providerIpBase - self.controllIpBase = controllIpBase + #self.controllIpBase = controllIpBase - self.controllIpBaseNum, self.controllPrefixLen = netParse( self.controllIpBase ) + '''self.controllIpBaseNum, self.controllPrefixLen = netParse( self.controllIpBase ) controllIP = ( 0xffffffff >> self.controllPrefixLen ) & self.controllIpBaseNum # Start for address allocation - self.controllNextIP = controllIP if controllIP > 0 else 1 + self.controllNextIP = controllIP if controllIP > 0 else 1''' self.providerIpBaseNum, self.providerPrefixLen = netParse( self.providerIpBase ) providerIP = ( 0xffffffff >> self.providerPrefixLen ) & self.providerIpBaseNum @@ -587,9 +587,9 @@ def buildFromTopo( self, topo=None ): for node in nodes: _ip = "{}/{}".format(ipAdd( self.adminNextIP, ipBaseNum=self.adminIpBaseNum, prefixLen=self.adminPrefixLen),self.adminPrefixLen) self.adminNextIP += 1 - _controllIp = "{}/{}".format(ipAdd( self.controllNextIP, ipBaseNum=self.controllIpBaseNum, prefixLen=self.controllPrefixLen),self.controllPrefixLen) - self.controllNextIP += 1 - node.configureContainer(admin_ip=_ip,controll_ip=_controllIp,wait=False,autoSetDocker=self.autoSetDocker) + '''_controllIp = "{}/{}".format(ipAdd( self.controllNextIP, ipBaseNum=self.controllIpBaseNum, prefixLen=self.controllPrefixLen),self.controllPrefixLen) + self.controllNextIP += 1''' + node.configureContainer(admin_ip=_ip,wait=False,autoSetDocker=self.autoSetDocker) count+=1 if count>100: sleep(10) diff --git a/mininet/mininet/lxc_container.py b/mininet/mininet/lxc_container.py index da2da53c..d05ee6d9 100644 --- a/mininet/mininet/lxc_container.py +++ b/mininet/mininet/lxc_container.py @@ -182,7 +182,7 @@ def _preInit(self, self.admin_ip=None self.ssh = None - def configureContainer(self, admin_ip, controll_ip, adminbr="admin-br", wait=True,autoSetDocker=False): + def configureContainer(self, admin_ip, adminbr="admin-br", wait=True,autoSetDocker=False): # # connect the node to the admin network # self.addContainerInterface(intfName="admin", brname=adminbr) @@ -199,17 +199,17 @@ def configureContainer(self, admin_ip, controll_ip, adminbr="admin-br", wait=Tru self.admin_ip=admin_ip if "/" in admin_ip: admin_ip, prefix = admin_ip.split("/") - if "/" in controll_ip: - controll_ip, prefix = controll_ip.split("/") + '''if "/" in controll_ip: + controll_ip, prefix = controll_ip.split("/")''' self.ssh = ASsh(loop=self.loop, host=admin_ip, username=self.username, bastion=self.bastion, client_keys=self.client_keys) if autoSetDocker: cmds.append("docker exec {} mkdir /root/.ssh".format(self.name)) cmds.append("docker exec {} bash -c 'echo \"{}\" >> /root/.ssh/authorized_keys'".format(self.name, self.pub_id)) cmds.append("docker exec {} service ssh start".format(self.name)) cmds.append("docker exec {} ifconfig admin {}".format(self.name,self.admin_ip)) - if self.image=="ubuntu": + '''if self.image=="ubuntu": print("docker network connect --ip {} network10 {}\n".format(controll_ip,self.name)) - cmds.append("docker network connect --ip {} network10 {}".format(controll_ip,self.name)) + cmds.append("docker network connect --ip {} network10 {}".format(controll_ip,self.name))''' # configure the container to have else: # an admin IP address diff --git a/mininet/mininet/provision/playbooks/configure-docker.yml b/mininet/mininet/provision/playbooks/configure-docker.yml index 4ec30307..4c0787c3 100644 --- a/mininet/mininet/provision/playbooks/configure-docker.yml +++ b/mininet/mininet/provision/playbooks/configure-docker.yml @@ -4,13 +4,13 @@ remote_user: root tasks : - name : create switch image - command: docker pull caiji0419/switch + command: docker pull jiawei96liu/hificnet-switch:generic-v1 - name : create ubuntu18.04 image - command: docker pull caiji0419/ubuntu + command: docker pull jiawei96liu/hificnet-ubuntu:openstack-v1 - name : update ubuntu tag - command: docker tag caiji0419/ubuntu ubuntu + command: docker tag jiawei96liu/hificnet-ubuntu:openstack-v1 ubuntu - name : update switch tag - command: docker tag caiji0419/switch switch + command: docker tag jiawei96liu/hificnet-switch:generic-v1 switch diff --git a/mininet/mininet/provision/playbooks/deploy_compute.yml b/mininet/mininet/provision/playbooks/deploy_compute.yml new file mode 100644 index 00000000..6014780c --- /dev/null +++ b/mininet/mininet/provision/playbooks/deploy_compute.yml @@ -0,0 +1,10 @@ +--- + +- hosts : workers + gather_facts: false + remote_user: root + tasks : + - name : update ubuntu tag + command: python3 docker_configer_container_cmd.py + + diff --git a/mininet/mininet/provision/playbooks/docker-nova-compute-auto.sh b/mininet/mininet/provision/playbooks/docker-nova-compute-auto.sh new file mode 100755 index 00000000..61c1fd85 --- /dev/null +++ b/mininet/mininet/provision/playbooks/docker-nova-compute-auto.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +function shX(){ + CMD=$* + echo -e "\e[32m[$(date +"%F %T")] " EXEC: ${CMD} " \e[0m" + ${CMD} +} + + +container_id=`docker ps -a | awk '{print $10}' | grep h` +array=(`echo $container_id | tr '\n' ' '` ) +for var in ${array[@]} +do + #echo $var + shX docker exec ${var} sh /root/nova_compute_auto_restart.sh & +done diff --git a/mininet/mininet/provision/playbooks/install-docker.yml b/mininet/mininet/provision/playbooks/install-docker.yml index 28f2bf53..a41d70f8 100644 --- a/mininet/mininet/provision/playbooks/install-docker.yml +++ b/mininet/mininet/provision/playbooks/install-docker.yml @@ -1,3 +1,6 @@ +--- +# + - hosts : all remote_user: root tasks : @@ -5,22 +8,10 @@ apt : update_cache: true name : python3-pip - - name: install basice packages - apt : name={{item}} state=present - with_items: - - aptitude - - apt-transport-https - - ca-certificates - - curl - - python3-setuptools - - python3-dev - - build-essential - - iptables - - software-properties-common -# - name: install python-pip -# apt : -# name : python-pip + - name: install docker + apt : + name: docker.io - name: install htop apt : @@ -50,37 +41,7 @@ # apt: # name: btrfs-tools -# - name: install lxd -# apt: -# name: lxd - -# - name: install lxd-client -# apt : -# name: lxd-client - - name: install ryu apt: name: python3-ryu - - name: "Check if Docker-CE is installed" - package_facts: - manager: "auto" - - - name: install Docker CE repos (1/3) - apt_key: - url: https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg - state: present - when: "'docker-ce' not in ansible_facts.packages" - - - name: install Docker CE repos (2/3) - shell: add-apt-repository "deb [arch=amd64] https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu $(lsb_release -cs) stable" - when: "'docker-ce' not in ansible_facts.packages" - - - name: install Docker CE repos (3/3) - apt: - update_cache: yes - when: "'docker-ce' not in ansible_facts.packages" - - - name: install Docker CE - apt: name=docker-ce state=present - when: "'docker-ce' not in ansible_facts.packages" diff --git a/mininet/mininet/provision/playbooks/prepare-ansiable.sh b/mininet/mininet/provision/playbooks/prepare-ansiable.sh new file mode 100755 index 00000000..039ebeb7 --- /dev/null +++ b/mininet/mininet/provision/playbooks/prepare-ansiable.sh @@ -0,0 +1,22 @@ +#/bin/bash +if [[ $# -ne 2 ]];then + echo "Usage: ./prepare-ansiable.sh {base-ip} {ip-num}" +else + base_ip=$1 + base_ip_array=(`echo $base_ip | tr '.' ' '` ) + ip_num=$2 + + echo "[master]" > /etc/ansible/hosts + echo "127.0.0.1 ansible_connection=local ansible_python_interpreter=/usr/bin/python3" >> /etc/ansible/hosts + echo "[workers]" >> /etc/ansible/hosts + + for ((cnt=0; cnt<${ip_num}; cnt++)) + do + let temp=${base_ip_array[3]}+cnt + let my_ip_1=${temp}%256 + let my_ip_2=${base_ip_array[2]}+${temp}/256 + my_ip=${base_ip_array[0]}.${base_ip_array[1]}.${my_ip_2}.${my_ip_1} + #echo $my_ip + echo "${my_ip} ansible_ssh_extra_args='-o StrictHostKeyChecking=no' ansible_python_interpreter=/usr/bin/python3" >> /etc/ansible/hosts + done +fi diff --git a/mininet/mininet/provision/playbooks/prepare-docker-net.sh b/mininet/mininet/provision/playbooks/prepare-docker-net.sh new file mode 100755 index 00000000..6d0e8702 --- /dev/null +++ b/mininet/mininet/provision/playbooks/prepare-docker-net.sh @@ -0,0 +1,13 @@ +ip addr flush eno3 +#docker network create --subnet 20.20.0.0/16 --gateway 20.20.0.4 network20 +brctl addif br-a149c07e9972 eno3 +ping 20.20.0.1 -c 2 -I br-a149c07e9972 +docker network rm network10 +#ip addr flush eno4 +#docker network create --subnet 10.10.0.0/16 --gateway 10.10.0.4 network10 +#brctl addif br-e91b254f36d6 eno4 +#ping 10.10.0.1 -c 2 -I br-e91b254f36d6 +sysctl net.ipv4.conf.all.forwarding=1 +iptables --policy FORWARD ACCEPT +mkdir /var/run/netns +ulimit -n 196835 diff --git a/mininet/mininet/provision/playbooks/prepare-openstack.sh b/mininet/mininet/provision/playbooks/prepare-openstack.sh new file mode 100644 index 00000000..15e7e4cc --- /dev/null +++ b/mininet/mininet/provision/playbooks/prepare-openstack.sh @@ -0,0 +1,19 @@ +#controller +brctl addbr admin-br &&\ +ifconfig admin-br 192.168.0.1/16 &&\ +tunctl -t admin &&\ +brctl addif admin-br admin &&\ +ifconfig admin 192.168.0.3/16 &&\ +ip link set admin-br up &&\ +ip link set admin up + +ip link delete vx_00 &&\ +ip link add vx_00 type vxlan id 00 remote 172.16.50.8 local 172.16.50.3 dstport 4789 &&\ +ip link set up vx_00 &&\ +brctl addif admin-br vx_00 &&\ +ip link set up admin-br +#master +ip link add vx_00 type vxlan id 00 remote 172.16.50.3 local 172.16.50.8 dstport 4789 &&\ +ip link set up vx_00 &&\ +brctl addif admin-br vx_00 &&\ +ip link set up admin-br From 0fe5551e62260c8fc98ad52ccc1c02fe2e7e2e06 Mon Sep 17 00:00:00 2001 From: J980419xq <1908393204@qq.com> Date: Mon, 24 Oct 2022 10:53:46 +0800 Subject: [PATCH 42/44] finish --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 9055ea05..b07778e2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,6 +16,7 @@ asyncssh==1.17.1 cryptography>=2.7 asyncio==3.4.3 pytest==5.1.0 +PyYAML==5.1.2 #awscli>=1.16.224 progressbar2==3.43.1 testresources==2.0.1 From ea1fac6944cfa15e59b195d8436bb01361c986ac Mon Sep 17 00:00:00 2001 From: J980419xq <1908393204@qq.com> Date: Mon, 24 Oct 2022 15:16:09 +0800 Subject: [PATCH 43/44] nova-fake --- openstack/fake.py | 1199 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1199 insertions(+) create mode 100644 openstack/fake.py diff --git a/openstack/fake.py b/openstack/fake.py new file mode 100644 index 00000000..ad178f5b --- /dev/null +++ b/openstack/fake.py @@ -0,0 +1,1199 @@ +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# All Rights Reserved. +# Copyright (c) 2010 Citrix Systems, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +""" +A fake (in-memory) hypervisor+api. + +Allows nova testing w/o a hypervisor. This module also documents the +semantics of real hypervisor connections. + +""" +import netaddr +import collections +import contextlib +import time +import uuid + +import fixtures +import os_resource_classes as orc +from oslo_log import log as logging +from oslo_serialization import jsonutils +from oslo_utils import versionutils + +from nova.compute import power_state +from nova.compute import task_states +from nova.compute import vm_states +import nova.conf +from nova.console import type as ctype +from nova import context as nova_context +from nova import exception +from nova import objects +from nova.objects import diagnostics as diagnostics_obj +from nova.objects import fields as obj_fields +from nova.objects import migrate_data +from nova.virt import driver +from nova.virt import hardware +from nova.virt.ironic import driver as ironic +from nova.virt import virtapi +from oslo_concurrency import processutils +from nova import utils +import re + +CONF = nova.conf.CONF + +LOG = logging.getLogger(__name__) + +def execute_wrapper(args): + LOG.info( + "fake running command: %s", + " ".join(str(arg) for arg in args), + ) + #root_helper = utils.get_root_helper() + try: + return processutils.execute(*args) + except Exception as e: + LOG.error( + "fake Unable to execute %(cmd)s. Exception: %(exception)s", + {"cmd": args, "exception": e}, + ) + raise + +@nova.privsep.sys_admin_pctxt.entrypoint +def add_namespace(ns): + full_args = ["ip", "netns", "add", ns] + execute_wrapper(full_args) + full_args = ["ip", "netns", "exec", ns, "ip", "link", "set", "lo", "up"] + execute_wrapper(full_args) + +@nova.privsep.sys_admin_pctxt.entrypoint +def delete_namespace(ns): + # deleting namespace will delete its ports and veth pairs + full_args = ["ip", "netns", "del", ns] + execute_wrapper(full_args) + +@nova.privsep.sys_admin_pctxt.entrypoint +def add_port_ip_addresses(ns, ovs_port, ip_addresses): + for address in ip_addresses: + full_args = ["ip", "netns", "exec", ns, + "ip", "addr", "add", address, "dev", ovs_port] + execute_wrapper(full_args) + +@nova.privsep.sys_admin_pctxt.entrypoint +def add_port(ns, bridge, ovs_port, port_id, mac_address): + full_args = ["ovs-vsctl", "--may-exist", "add-port", bridge, ovs_port, + "--", "set", "Interface", ovs_port, "type=internal", + "--", "set", "Interface", ovs_port, + "external_ids:iface-id=%s" % port_id, + "--", "set", "Interface", ovs_port, + "external-ids:iface-status=active", + "--", "set", "Interface", ovs_port, + "external-ids:attached-mac=%s" % mac_address] + execute_wrapper(full_args) + full_args = ["ip", "link", "set", ovs_port, "netns", ns] + execute_wrapper(full_args) + namespace = ["ip", "netns", "exec", ns] + full_args = namespace + ["ip", "link", "set", ovs_port, "up"] + execute_wrapper(full_args) + namespace = ["ip", "netns", "exec", ns] + full_args = namespace + ["ip", "link", "set", ovs_port, "address", mac_address] + execute_wrapper(full_args) + +@nova.privsep.sys_admin_pctxt.entrypoint +def delete_port(ns, bridge, ovs_port): + full_args = ["ovs-vsctl", "--if-exists", "del-port", bridge, ovs_port] + execute_wrapper(full_args) + +@nova.privsep.sys_admin_pctxt.entrypoint +def add_route(ns, ip_addresses): + namespace = ["ip", "netns", "exec", ns] + for address in ip_addresses: + m=re.search(r'(\d+).(\d+).(\d+).\d+/(\d+)',address) + if m.group(4)=="8": + ip=m.group(1)+".0.0.1" + elif m.group(4)=="16": + ip=m.group(1)+"."+m.group(2)+".0.1" + elif m.group(4)=="24": + ip=m.group(1)+"."+m.group(2)+"."+m.group(3)+".1" + full_args=namespace+["route","add","default","gw",ip] + execute_wrapper(full_args) + +class FakeInstance(object): + + def __init__(self, name, state, uuid): + LOG.info("---fake---instance_init---") + self.name = name + self.state = state + self.uuid = uuid + + def __getitem__(self, key): + return getattr(self, key) + + +class Resources(object): + vcpus = 0 + memory_mb = 0 + local_gb = 0 + vcpus_used = 0 + memory_mb_used = 0 + local_gb_used = 0 + + def __init__(self, vcpus=8, memory_mb=8000, local_gb=500): + LOG.info("---fake---resource_init----") + self.vcpus = vcpus + self.memory_mb = memory_mb + self.local_gb = local_gb + + def claim(self, vcpus=0, mem=0, disk=0): + self.vcpus_used += vcpus + self.memory_mb_used += mem + self.local_gb_used += disk + + def release(self, vcpus=0, mem=0, disk=0): + self.vcpus_used -= vcpus + self.memory_mb_used -= mem + self.local_gb_used -= disk + + def dump(self): + return { + 'vcpus': self.vcpus, + 'memory_mb': self.memory_mb, + 'local_gb': self.local_gb, + 'vcpus_used': self.vcpus_used, + 'memory_mb_used': self.memory_mb_used, + 'local_gb_used': self.local_gb_used + } + + +class FakeDriver(driver.ComputeDriver): + # These must match the traits in + # nova.tests.functional.integrated_helpers.ProviderUsageBaseTestCase + capabilities = { + "has_imagecache": True, + "supports_evacuate": True, + "supports_migrate_to_same_host": False, + "supports_attach_interface": True, + "supports_device_tagging": True, + "supports_tagged_attach_interface": True, + "supports_tagged_attach_volume": True, + "supports_extend_volume": True, + "supports_multiattach": True, + "supports_trusted_certs": True, + "supports_pcpus": False, + "supports_accelerators": True, + "supports_remote_managed_ports": True, + + # Supported image types + "supports_image_type_raw": True, + "supports_image_type_vhd": False, + } + + # Since we don't have a real hypervisor, pretend we have lots of + # disk and ram so this driver can be used to test large instances. + vcpus = 1000 + memory_mb = 800000 + local_gb = 600000 + + """Fake hypervisor driver.""" + + def __init__(self, virtapi, read_only=False): + LOG.info("------fakedriver_init------") + super(FakeDriver, self).__init__(virtapi) + self.instances = {} + self.resources = Resources( + vcpus=self.vcpus, + memory_mb=self.memory_mb, + local_gb=self.local_gb) + self.host_status_base = { + 'hypervisor_type': 'fake', + 'hypervisor_version': versionutils.convert_version_to_int('1.0'), + 'hypervisor_hostname': CONF.host, + 'cpu_info': {}, + 'disk_available_least': 0, + 'supported_instances': [( + obj_fields.Architecture.X86_64, + obj_fields.HVType.FAKE, + obj_fields.VMMode.HVM)], + 'numa_topology': None, + } + self._mounts = {} + self._interfaces = {} + self.active_migrations = {} + self._host = None + self._nodes = None + + def init_host(self, host): + self._host = host + # NOTE(gibi): this is unnecessary complex and fragile but this is + # how many current functional sample tests expect the node name. + self._nodes = (['fake-mini'] if self._host == 'compute' + else [self._host]) + + def _set_nodes(self, nodes): + # NOTE(gibi): this is not part of the driver interface but used + # by our tests to customize the discovered nodes by the fake + # driver. + self._nodes = nodes + + def list_instances(self): + return [self.instances[uuid].name for uuid in self.instances.keys()] + + def list_instance_uuids(self): + return list(self.instances.keys()) + + def get_ip_addresses(self, vif): + addresses = [] + network = vif.get("network", {}) + for subnet in network.get("subnets", []): + if subnet and subnet.get("version", "") == 4: + cidr = subnet.get("cidr", None) + for ip in subnet.get("ips", []): + ip_address = ip.get("address", None) + if cidr and ip_address: + prefixlen = netaddr.IPNetwork(cidr).prefixlen + ip_address = "%s/%s" % (ip_address, prefixlen) + addresses = addresses + [ip_address] + return addresses + + def plug_vif(self, instance, vif): + bridge = "br-int" + dev = vif.get("devname") + port = vif.get("id") + mac_address = vif.get("address") + if not dev or not port or not mac_address: + return + ns = "fake-%s" % instance.uuid + add_port(ns, bridge, dev, port, mac_address) + ip_addresses = self.get_ip_addresses(vif) + add_port_ip_addresses(ns, dev, ip_addresses) + add_route(ns,ip_addresses) + + def plug_vifs(self, instance, network_info): + """Plug VIFs into networks.""" + LOG.info("---fake-plug_vifs---TAG0") + ns = "fake-%s" % instance.uuid + add_namespace(ns) + if network_info == None: + LOG.info("---fake-plug_vifs---TAG1") + else: + LOG.info("---fake-plug_vifs---TAG2") + for vif in network_info: + LOG.info("---fake-plug_vifs---TAG3") + self.plug_vif(instance, vif) + + def unplug_vif(self, instance, vif): + bridge = "br-int" + dev = vif.get("devname") + port = vif.get("id") + if not dev: + if not port: + return + dev = "tap" + str(port[0:11]) + ns = "fake-%s" % instance.uuid + delete_port(ns, bridge, dev) + + def unplug_vifs(self, instance, network_info): + """Unplug VIFs from networks.""" + for vif in network_info: + self.unplug_vif(instance, vif) + # delete namespace after removing ovs ports + ns = "fake-%s" % instance.uuid + delete_namespace(ns) + + def spawn(self, context, instance, image_meta, injected_files, + admin_password, allocations, network_info=None, + block_device_info=None, power_on=True, accel_info=None): + LOG.info("---fake-spawn---TAG0") + self.plug_vifs(instance, network_info) + if network_info: + LOG.info("---fake-spawn---TAG2 {}".format(network_info)) + for vif in network_info: + # simulate a real driver triggering the async network + # allocation as it might cause an error + vif.fixed_ips() + # store the vif as attached so we can allow detaching it later + # with a detach_interface() call. + self._interfaces[vif['id']] = vif + + uuid = instance.uuid + state = power_state.RUNNING if power_on else power_state.SHUTDOWN + flavor = instance.flavor + self.resources.claim( + vcpus=flavor.vcpus, + mem=flavor.memory_mb, + disk=flavor.root_gb) + fake_instance = FakeInstance(instance.name, state, uuid) + self.instances[uuid] = fake_instance + + def snapshot(self, context, instance, image_id, update_task_state): + if instance.uuid not in self.instances: + raise exception.InstanceNotRunning(instance_id=instance.uuid) + update_task_state(task_state=task_states.IMAGE_UPLOADING) + + def reboot(self, context, instance, network_info, reboot_type, + block_device_info=None, bad_volumes_callback=None, + accel_info=None): + # If the guest is not on the hypervisor and we're doing a hard reboot + # then mimic the libvirt driver by spawning the guest. + if (instance.uuid not in self.instances and + reboot_type.lower() == 'hard'): + injected_files = admin_password = allocations = None + self.spawn(context, instance, instance.image_meta, injected_files, + admin_password, allocations, + block_device_info=block_device_info) + else: + # Just try to power on the guest. + self.power_on(context, instance, network_info, + block_device_info=block_device_info) + + def get_host_ip_addr(self): + return '192.168.0.1' + + def set_admin_password(self, instance, new_pass): + pass + + def resume_state_on_host_boot(self, context, instance, network_info, + block_device_info=None): + pass + + def rescue(self, context, instance, network_info, image_meta, + rescue_password, block_device_info): + pass + + def unrescue( + self, + context: nova_context.RequestContext, + instance: 'objects.Instance', + ): + self.instances[instance.uuid].state = power_state.RUNNING + + def poll_rebooting_instances(self, timeout, instances): + pass + + def migrate_disk_and_power_off(self, context, instance, dest, + flavor, network_info, + block_device_info=None, + timeout=0, retry_interval=0): + pass + + def finish_revert_migration(self, context, instance, network_info, + migration, block_device_info=None, + power_on=True): + state = power_state.RUNNING if power_on else power_state.SHUTDOWN + self.instances[instance.uuid] = FakeInstance( + instance.name, state, instance.uuid) + + def post_live_migration_at_destination(self, context, instance, + network_info, + block_migration=False, + block_device_info=None): + # Called from the destination host after a successful live migration + # so spawn the instance on this host to track it properly. + image_meta = injected_files = admin_password = allocations = None + self.spawn(context, instance, image_meta, injected_files, + admin_password, allocations) + + def power_off(self, instance, timeout=0, retry_interval=0): + if instance.uuid in self.instances: + self.instances[instance.uuid].state = power_state.SHUTDOWN + else: + raise exception.InstanceNotFound(instance_id=instance.uuid) + + def power_on(self, context, instance, network_info, + block_device_info=None, accel_info=None): + if instance.uuid in self.instances: + self.instances[instance.uuid].state = power_state.RUNNING + else: + raise exception.InstanceNotFound(instance_id=instance.uuid) + + def trigger_crash_dump(self, instance): + pass + + def soft_delete(self, instance): + pass + + def restore(self, instance): + pass + + def pause(self, instance): + pass + + def unpause(self, instance): + pass + + def suspend(self, context, instance): + pass + + def resume(self, context, instance, network_info, block_device_info=None): + pass + + def destroy(self, context, instance, network_info, block_device_info=None, + destroy_disks=True, destroy_secrets=True): + self.unplug_vifs(instance, network_info) + key = instance.uuid + if key in self.instances: + flavor = instance.flavor + self.resources.release( + vcpus=flavor.vcpus, + mem=flavor.memory_mb, + disk=flavor.root_gb) + del self.instances[key] + else: + LOG.warning("fake Key '%(key)s' not in instances '%(inst)s'", + {'key': key, + 'inst': self.instances}, instance=instance) + + def cleanup(self, context, instance, network_info, block_device_info=None, + destroy_disks=True, migrate_data=None, destroy_vifs=True, + destroy_secrets=True): + # cleanup() should not be called when the guest has not been destroyed. + if instance.uuid in self.instances: + raise exception.InstanceExists( + "Instance %s has not been destroyed." % instance.uuid) + + def attach_volume(self, context, connection_info, instance, mountpoint, + disk_bus=None, device_type=None, encryption=None): + """Attach the disk to the instance at mountpoint using info.""" + instance_name = instance.name + if instance_name not in self._mounts: + self._mounts[instance_name] = {} + self._mounts[instance_name][mountpoint] = connection_info + + def detach_volume(self, context, connection_info, instance, mountpoint, + encryption=None): + """Detach the disk attached to the instance.""" + try: + del self._mounts[instance.name][mountpoint] + except KeyError: + pass + + def swap_volume(self, context, old_connection_info, new_connection_info, + instance, mountpoint, resize_to): + """Replace the disk attached to the instance.""" + instance_name = instance.name + if instance_name not in self._mounts: + self._mounts[instance_name] = {} + self._mounts[instance_name][mountpoint] = new_connection_info + + def extend_volume(self, context, connection_info, instance, + requested_size): + """Extend the disk attached to the instance.""" + pass + + def attach_interface(self, context, instance, image_meta, vif): + if vif['id'] in self._interfaces: + raise exception.InterfaceAttachFailed( + instance_uuid=instance.uuid) + self._interfaces[vif['id']] = vif + + def detach_interface(self, context, instance, vif): + try: + del self._interfaces[vif['id']] + except KeyError: + raise exception.InterfaceDetachFailed( + instance_uuid=instance.uuid) + + def get_info(self, instance, use_cache=True): + if instance.uuid not in self.instances: + raise exception.InstanceNotFound(instance_id=instance.uuid) + i = self.instances[instance.uuid] + return hardware.InstanceInfo(state=i.state) + + def get_diagnostics(self, instance): + return {'cpu0_time': 17300000000, + 'memory': 524288, + 'vda_errors': -1, + 'vda_read': 262144, + 'vda_read_req': 112, + 'vda_write': 5778432, + 'vda_write_req': 488, + 'vnet1_rx': 2070139, + 'vnet1_rx_drop': 0, + 'vnet1_rx_errors': 0, + 'vnet1_rx_packets': 26701, + 'vnet1_tx': 140208, + 'vnet1_tx_drop': 0, + 'vnet1_tx_errors': 0, + 'vnet1_tx_packets': 662, + } + + def get_instance_diagnostics(self, instance): + diags = diagnostics_obj.Diagnostics( + state='running', driver='libvirt', hypervisor='kvm', + hypervisor_os='ubuntu', uptime=46664, config_drive=True) + diags.add_cpu(id=0, time=17300000000, utilisation=15) + diags.add_nic(mac_address='01:23:45:67:89:ab', + rx_octets=2070139, + rx_errors=100, + rx_drop=200, + rx_packets=26701, + rx_rate=300, + tx_octets=140208, + tx_errors=400, + tx_drop=500, + tx_packets = 662, + tx_rate=600) + diags.add_disk(read_bytes=262144, + read_requests=112, + write_bytes=5778432, + write_requests=488, + errors_count=1) + diags.memory_details = diagnostics_obj.MemoryDiagnostics( + maximum=524288, used=0) + return diags + + def get_all_volume_usage(self, context, compute_host_bdms): + """Return usage info for volumes attached to vms on + a given host. + """ + volusage = [] + if compute_host_bdms: + volusage = [{'volume': compute_host_bdms[0][ + 'instance_bdms'][0]['volume_id'], + 'instance': compute_host_bdms[0]['instance'], + 'rd_bytes': 0, + 'rd_req': 0, + 'wr_bytes': 0, + 'wr_req': 0}] + + return volusage + + def get_host_cpu_stats(self): + stats = {'kernel': 5664160000000, + 'idle': 1592705190000000, + 'user': 26728850000000, + 'iowait': 6121490000000} + stats['frequency'] = 800 + return stats + + def block_stats(self, instance, disk_id): + return [0, 0, 0, 0, None] + + def get_console_output(self, context, instance): + return 'FAKE CONSOLE OUTPUT\nANOTHER\nLAST LINE' + + def get_vnc_console(self, context, instance): + return ctype.ConsoleVNC(internal_access_path='FAKE', + host='fakevncconsole.com', + port=6969) + + def get_spice_console(self, context, instance): + return ctype.ConsoleSpice(internal_access_path='FAKE', + host='fakespiceconsole.com', + port=6969, + tlsPort=6970) + + def get_rdp_console(self, context, instance): + return ctype.ConsoleRDP(internal_access_path='FAKE', + host='fakerdpconsole.com', + port=6969) + + def get_serial_console(self, context, instance): + return ctype.ConsoleSerial(internal_access_path='FAKE', + host='fakerdpconsole.com', + port=6969) + + def get_mks_console(self, context, instance): + return ctype.ConsoleMKS(internal_access_path='FAKE', + host='fakemksconsole.com', + port=6969) + + def get_available_resource(self, nodename): + """Updates compute manager resource info on ComputeNode table. + + Since we don't have a real hypervisor, pretend we have lots of + disk and ram. + """ + cpu_info = collections.OrderedDict([ + ('arch', 'x86_64'), + ('model', 'Nehalem'), + ('vendor', 'Intel'), + ('features', ['pge', 'clflush']), + ('topology', { + 'cores': 1, + 'threads': 1, + 'sockets': 4, + }), + ]) + if nodename not in self.get_available_nodes(): + return {} + + host_status = self.host_status_base.copy() + host_status.update(self.resources.dump()) + host_status['hypervisor_hostname'] = nodename + host_status['host_hostname'] = nodename + host_status['host_name_label'] = nodename + host_status['cpu_info'] = jsonutils.dumps(cpu_info) + return host_status + + def update_provider_tree(self, provider_tree, nodename, allocations=None): + # NOTE(yikun): If the inv record does not exists, the allocation_ratio + # will use the CONF.xxx_allocation_ratio value if xxx_allocation_ratio + # is set, and fallback to use the initial_xxx_allocation_ratio + # otherwise. + inv = provider_tree.data(nodename).inventory + ratios = self._get_allocation_ratios(inv) + inventory = { + 'VCPU': { + 'total': self.vcpus, + 'min_unit': 1, + 'max_unit': self.vcpus, + 'step_size': 1, + 'allocation_ratio': ratios[orc.VCPU], + 'reserved': CONF.reserved_host_cpus, + }, + 'MEMORY_MB': { + 'total': self.memory_mb, + 'min_unit': 1, + 'max_unit': self.memory_mb, + 'step_size': 1, + 'allocation_ratio': ratios[orc.MEMORY_MB], + 'reserved': CONF.reserved_host_memory_mb, + }, + 'DISK_GB': { + 'total': self.local_gb, + 'min_unit': 1, + 'max_unit': self.local_gb, + 'step_size': 1, + 'allocation_ratio': ratios[orc.DISK_GB], + 'reserved': self._get_reserved_host_disk_gb_from_config(), + }, + } + provider_tree.update_inventory(nodename, inventory) + + def get_instance_disk_info(self, instance, block_device_info=None): + return + + def live_migration(self, context, instance, dest, + post_method, recover_method, block_migration=False, + migrate_data=None): + post_method(context, instance, dest, block_migration, + migrate_data) + return + + def live_migration_force_complete(self, instance): + return + + def live_migration_abort(self, instance): + return + + def cleanup_live_migration_destination_check(self, context, + dest_check_data): + return + + def check_can_live_migrate_destination(self, context, instance, + src_compute_info, dst_compute_info, + block_migration=False, + disk_over_commit=False): + data = migrate_data.LibvirtLiveMigrateData() + data.filename = 'fake' + data.image_type = CONF.libvirt.images_type + data.graphics_listen_addr_vnc = CONF.vnc.server_listen + data.graphics_listen_addr_spice = CONF.spice.server_listen + data.serial_listen_addr = None + # Notes(eliqiao): block_migration and disk_over_commit are not + # nullable, so just don't set them if they are None + if block_migration is not None: + data.block_migration = block_migration + if disk_over_commit is not None: + data.disk_over_commit = disk_over_commit + data.disk_available_mb = 100000 + data.is_shared_block_storage = True + data.is_shared_instance_path = True + + return data + + def check_can_live_migrate_source(self, context, instance, + dest_check_data, block_device_info=None): + return dest_check_data + + def finish_migration(self, context, migration, instance, disk_info, + network_info, image_meta, resize_instance, + allocations, block_device_info=None, power_on=True): + injected_files = admin_password = None + # Finish migration is just like spawning the guest on a destination + # host during resize/cold migrate, so re-use the spawn() fake to + # claim resources and track the instance on this "hypervisor". + self.spawn(context, instance, image_meta, injected_files, + admin_password, allocations, + block_device_info=block_device_info, power_on=power_on) + + def confirm_migration(self, context, migration, instance, network_info): + # Confirm migration cleans up the guest from the source host so just + # destroy the guest to remove it from the list of tracked instances + # unless it is a same-host resize. + if migration.source_compute != migration.dest_compute: + self.destroy(context, instance, network_info) + + def pre_live_migration(self, context, instance, block_device_info, + network_info, disk_info, migrate_data): + return migrate_data + + def rollback_live_migration_at_destination(self, context, instance, + network_info, + block_device_info, + destroy_disks=True, + migrate_data=None): + return + + def _test_remove_vm(self, instance_uuid): + """Removes the named VM, as if it crashed. For testing.""" + self.instances.pop(instance_uuid) + + def host_power_action(self, action): + """Reboots, shuts down or powers up the host.""" + return action + + def host_maintenance_mode(self, host, mode): + """Start/Stop host maintenance window. On start, it triggers + guest VMs evacuation. + """ + if not mode: + return 'off_maintenance' + return 'on_maintenance' + + def set_host_enabled(self, enabled): + """Sets the specified host's ability to accept new instances.""" + if enabled: + return 'enabled' + return 'disabled' + + def get_volume_connector(self, instance): + return {'ip': CONF.my_block_storage_ip, + 'initiator': 'fake', + 'host': self._host} + + def get_available_nodes(self, refresh=False): + return self._nodes + + def instance_on_disk(self, instance): + return False + + def quiesce(self, context, instance, image_meta): + pass + + def unquiesce(self, context, instance, image_meta): + pass + + +class FakeVirtAPI(virtapi.VirtAPI): + @contextlib.contextmanager + def wait_for_instance_event(self, instance, event_names, deadline=300, + error_callback=None): + # NOTE(danms): Don't actually wait for any events, just + # fall through + yield + + def exit_wait_early(self, events): + # We never wait, so there is nothing to exit early + pass + + def update_compute_provider_status(self, context, rp_uuid, enabled): + pass + + +class SmallFakeDriver(FakeDriver): + # The api samples expect specific cpu memory and disk sizes. In order to + # allow the FakeVirt driver to be used outside of the unit tests, provide + # a separate class that has the values expected by the api samples. So + # instead of requiring new samples every time those + # values are adjusted allow them to be overwritten here. + + vcpus = 2 + memory_mb = 8192 + local_gb = 1028 + + +class MediumFakeDriver(FakeDriver): + # Fake driver that has enough resources to host more than one instance + # but not that much that cannot be exhausted easily + + vcpus = 10 + memory_mb = 8192 + local_gb = 1028 + + +class SameHostColdMigrateDriver(MediumFakeDriver): + """MediumFakeDriver variant that supports same-host cold migrate.""" + capabilities = dict(FakeDriver.capabilities, + supports_migrate_to_same_host=True) + + +class RescueBFVDriver(MediumFakeDriver): + capabilities = dict(FakeDriver.capabilities, supports_bfv_rescue=True) + + +class PowerUpdateFakeDriver(SmallFakeDriver): + # A specific fake driver for the power-update external event testing. + + def __init__(self, virtapi): + super(PowerUpdateFakeDriver, self).__init__(virtapi=None) + self.driver = ironic.IronicDriver(virtapi=virtapi) + + def power_update_event(self, instance, target_power_state): + """Update power state of the specified instance in the nova DB.""" + self.driver.power_update_event(instance, target_power_state) + + +class MediumFakeDriverWithNestedCustomResources(MediumFakeDriver): + # A MediumFakeDriver variant that also reports CUSTOM_MAGIC resources on + # a nested resource provider + vcpus = 10 + memory_mb = 8192 + local_gb = 1028 + child_resources = { + 'CUSTOM_MAGIC': { + 'total': 10, + 'reserved': 0, + 'min_unit': 1, + 'max_unit': 10, + 'step_size': 1, + 'allocation_ratio': 1, + } + } + + def update_provider_tree(self, provider_tree, nodename, allocations=None): + super( + MediumFakeDriverWithNestedCustomResources, + self).update_provider_tree( + provider_tree, nodename, + allocations=allocations) + + if not provider_tree.exists(nodename + '-child'): + provider_tree.new_child(name=nodename + '-child', + parent=nodename) + + provider_tree.update_inventory(nodename + '-child', + self.child_resources) + + +class FakeFinishMigrationFailDriver(FakeDriver): + """FakeDriver variant that will raise an exception from finish_migration""" + + def finish_migration(self, *args, **kwargs): + raise exception.VirtualInterfaceCreateException() + + +class PredictableNodeUUIDDriver(SmallFakeDriver): + """SmallFakeDriver variant that reports a predictable node uuid in + get_available_resource, like IronicDriver. + """ + + def get_available_resource(self, nodename): + resources = super( + PredictableNodeUUIDDriver, self).get_available_resource(nodename) + # This is used in ComputeNode.update_from_virt_driver which is called + # from the ResourceTracker when creating a ComputeNode. + resources['uuid'] = uuid.uuid5(uuid.NAMESPACE_DNS, nodename) + return resources + + +class FakeRescheduleDriver(FakeDriver): + """FakeDriver derivative that triggers a reschedule on the first spawn + attempt. This is expected to only be used in tests that have more than + one compute service. + """ + # dict, keyed by instance uuid, mapped to a boolean telling us if the + # instance has been rescheduled or not + rescheduled = {} + + def spawn(self, context, instance, image_meta, injected_files, + admin_password, allocations, network_info=None, + block_device_info=None, power_on=True, accel_info=None): + if not self.rescheduled.get(instance.uuid, False): + # We only reschedule on the first time something hits spawn(). + self.rescheduled[instance.uuid] = True + raise exception.ComputeResourcesUnavailable( + reason='FakeRescheduleDriver') + super(FakeRescheduleDriver, self).spawn( + context, instance, image_meta, injected_files, + admin_password, allocations, network_info, block_device_info, + power_on) + + +class FakeRescheduleDriverWithNestedCustomResources( + FakeRescheduleDriver, MediumFakeDriverWithNestedCustomResources): + pass + + +class FakeBuildAbortDriver(FakeDriver): + """FakeDriver derivative that always fails on spawn() with a + BuildAbortException so no reschedule is attempted. + """ + + def spawn(self, context, instance, image_meta, injected_files, + admin_password, allocations, network_info=None, + block_device_info=None, power_on=True, accel_info=None): + raise exception.BuildAbortException( + instance_uuid=instance.uuid, reason='FakeBuildAbortDriver') + + +class FakeBuildAbortDriverWithNestedCustomResources( + FakeBuildAbortDriver, MediumFakeDriverWithNestedCustomResources): + pass + + +class FakeUnshelveSpawnFailDriver(FakeDriver): + """FakeDriver derivative that always fails on spawn() with a + VirtualInterfaceCreateException when unshelving an offloaded instance. + """ + + def spawn(self, context, instance, image_meta, injected_files, + admin_password, allocations, network_info=None, + block_device_info=None, power_on=True, accel_info=None): + if instance.vm_state == vm_states.SHELVED_OFFLOADED: + raise exception.VirtualInterfaceCreateException( + 'FakeUnshelveSpawnFailDriver') + # Otherwise spawn normally during the initial build. + super(FakeUnshelveSpawnFailDriver, self).spawn( + context, instance, image_meta, injected_files, + admin_password, allocations, network_info, block_device_info, + power_on) + + +class FakeUnshelveSpawnFailDriverWithNestedCustomResources( + FakeUnshelveSpawnFailDriver, MediumFakeDriverWithNestedCustomResources): + pass + + +class FakeLiveMigrateDriver(FakeDriver): + """FakeDriver derivative to handle force_complete and abort calls. + + This module serves those tests that need to abort or force-complete + the live migration, thus the live migration will never be finished + without the force_complete_migration or delete_migration API calls. + + """ + + def __init__(self, virtapi, read_only=False): + super(FakeLiveMigrateDriver, self).__init__(virtapi, read_only) + self._migrating = True + self._abort_migration = True + + def live_migration(self, context, instance, dest, + post_method, recover_method, block_migration=False, + migrate_data=None): + self._abort_migration = False + self._migrating = True + count = 0 + while self._migrating and count < 50: + time.sleep(0.1) + count = count + 1 + + if self._abort_migration: + recover_method(context, instance, dest, migrate_data, + migration_status='cancelled') + else: + post_method(context, instance, dest, block_migration, + migrate_data) + + def live_migration_force_complete(self, instance): + self._migrating = False + if instance.uuid in self.instances: + del self.instances[instance.uuid] + + def live_migration_abort(self, instance): + self._abort_migration = True + self._migrating = False + + def post_live_migration(self, context, instance, block_device_info, + migrate_data=None): + # Runs on the source host, called from + # ComputeManager._post_live_migration so just delete the instance + # from being tracked on the source host. + self.destroy(context, instance, network_info=None, + block_device_info=block_device_info) + + +class FakeLiveMigrateDriverWithNestedCustomResources( + FakeLiveMigrateDriver, MediumFakeDriverWithNestedCustomResources): + pass + + +class FakeDriverWithPciResources(SmallFakeDriver): + + PCI_ADDR_PF1 = '0000:01:00.0' + PCI_ADDR_PF1_VF1 = '0000:01:00.1' + PCI_ADDR_PF2 = '0000:02:00.0' + PCI_ADDR_PF2_VF1 = '0000:02:00.1' + PCI_ADDR_PF3 = '0000:03:00.0' + PCI_ADDR_PF3_VF1 = '0000:03:00.1' + + # NOTE(gibi): Always use this fixture along with the + # FakeDriverWithPciResources to make the necessary configuration for the + # driver. + class FakeDriverWithPciResourcesConfigFixture(fixtures.Fixture): + def setUp(self): + super(FakeDriverWithPciResources. + FakeDriverWithPciResourcesConfigFixture, self).setUp() + # Set passthrough_whitelist before the compute node starts to match + # with the PCI devices reported by this fake driver. + + # NOTE(gibi): 0000:01:00 is tagged to physnet1 and therefore not a + # match based on physnet to our sriov port + # 'port_with_sriov_resource_request' as the network of that port + # points to physnet2 with the attribute + # 'provider:physical_network'. Nova pci handling already enforces + # this rule. + # + # 0000:02:00 and 0000:03:00 are both tagged to physnet2 and + # therefore a good match for our sriov port based on physnet. + # Having two PFs on the same physnet will allow us to test the + # placement allocation - physical allocation matching based on the + # bandwidth allocation in the future. + CONF.set_override('passthrough_whitelist', override=[ + jsonutils.dumps( + { + "address": { + "domain": "0000", + "bus": "01", + "slot": "00", + "function": ".*"}, + "physical_network": "physnet1", + } + ), + jsonutils.dumps( + { + "address": { + "domain": "0000", + "bus": "02", + "slot": "00", + "function": ".*"}, + "physical_network": "physnet2", + } + ), + jsonutils.dumps( + { + "address": { + "domain": "0000", + "bus": "03", + "slot": "00", + "function": ".*"}, + "physical_network": "physnet2", + } + ), + ], + group='pci') + + self.useFixture(fixtures.MockPatch( + 'nova.pci.utils.get_mac_by_pci_address', + return_value='52:54:00:1e:59:c6')) + + self.useFixture(fixtures.MockPatch( + 'nova.pci.utils.get_vf_num_by_pci_address', + return_value=1)) + + def get_available_resource(self, nodename): + host_status = super( + FakeDriverWithPciResources, self).get_available_resource(nodename) + # 01:00.0 - PF - ens1 + # |---- 01:00.1 - VF + # + # 02:00.0 - PF - ens2 + # |---- 02:00.1 - VF + # + # 03:00.0 - PF - ens3 + # |---- 03:00.1 - VF + host_status['pci_passthrough_devices'] = jsonutils.dumps([ + { + 'address': self.PCI_ADDR_PF1, + 'product_id': 'fake-product_id', + 'vendor_id': 'fake-vendor_id', + 'status': 'available', + 'dev_type': 'type-PF', + 'parent_addr': None, + 'numa_node': 0, + 'label': 'fake-label', + }, + { + 'address': self.PCI_ADDR_PF1_VF1, + 'product_id': 'fake-product_id', + 'vendor_id': 'fake-vendor_id', + 'status': 'available', + 'dev_type': 'type-VF', + 'parent_addr': self.PCI_ADDR_PF1, + 'numa_node': 0, + 'label': 'fake-label', + "parent_ifname": self._host + "-ens1", + }, + { + 'address': self.PCI_ADDR_PF2, + 'product_id': 'fake-product_id', + 'vendor_id': 'fake-vendor_id', + 'status': 'available', + 'dev_type': 'type-PF', + 'parent_addr': None, + 'numa_node': 0, + 'label': 'fake-label', + }, + { + 'address': self.PCI_ADDR_PF2_VF1, + 'product_id': 'fake-product_id', + 'vendor_id': 'fake-vendor_id', + 'status': 'available', + 'dev_type': 'type-VF', + 'parent_addr': self.PCI_ADDR_PF2, + 'numa_node': 0, + 'label': 'fake-label', + "parent_ifname": self._host + "-ens2", + }, + { + 'address': self.PCI_ADDR_PF3, + 'product_id': 'fake-product_id', + 'vendor_id': 'fake-vendor_id', + 'status': 'available', + 'dev_type': 'type-PF', + 'parent_addr': None, + 'numa_node': 0, + 'label': 'fake-label', + }, + { + 'address': self.PCI_ADDR_PF3_VF1, + 'product_id': 'fake-product_id', + 'vendor_id': 'fake-vendor_id', + 'status': 'available', + 'dev_type': 'type-VF', + 'parent_addr': self.PCI_ADDR_PF3, + 'numa_node': 0, + 'label': 'fake-label', + "parent_ifname": self._host + "-ens3", + }, + ]) + return host_status + + +class FakeLiveMigrateDriverWithPciResources( + FakeLiveMigrateDriver, FakeDriverWithPciResources): + """FakeDriver derivative to handle force_complete and abort calls. + + This module serves those tests that need to abort or force-complete + the live migration, thus the live migration will never be finished + without the force_complete_migration or delete_migration API calls. + + """ + + +class FakeDriverWithCaching(FakeDriver): + def __init__(self, *a, **k): + super(FakeDriverWithCaching, self).__init__(*a, **k) + self.cached_images = set() + + def cache_image(self, context, image_id): + if image_id in self.cached_images: + return False + else: + self.cached_images.add(image_id) + return True From 924b22804e30008a21e21967f548cc44812dde0d Mon Sep 17 00:00:00 2001 From: J980419xq <1908393204@qq.com> Date: Mon, 24 Oct 2022 15:22:51 +0800 Subject: [PATCH 44/44] delete openflow --- openflow/.gitignore | 44 - openflow/COPYING | 1054 ----- openflow/ChangeLog | 202 - openflow/INSTALL | 513 --- openflow/Makefile.am | 68 - openflow/README | 110 - openflow/README.hwtables | 39 - openflow/README.kernel | 18 - openflow/acinclude.m4 | 309 -- openflow/boot.sh | 14 - openflow/configure.ac | 94 - openflow/controller/.dirstamp | 0 openflow/controller/.gitignore | 4 - openflow/controller/automake.mk | 8 - openflow/controller/controller.8.in | 150 - openflow/controller/controller.c | 336 -- openflow/datapath/.gitignore | 7 - openflow/datapath/Makefile.am | 27 - openflow/datapath/Modules.mk | 42 - openflow/datapath/chain.c | 270 -- openflow/datapath/chain.h | 43 - openflow/datapath/compat.h | 12 - openflow/datapath/crc32.c | 45 - openflow/datapath/crc32.h | 22 - openflow/datapath/datapath.c | 2137 ---------- openflow/datapath/datapath.h | 114 - openflow/datapath/dp_act.c | 543 --- openflow/datapath/dp_act.h | 15 - openflow/datapath/dp_dev.c | 252 -- openflow/datapath/dp_dev.h | 17 - openflow/datapath/dp_notify.c | 43 - openflow/datapath/flow.c | 504 --- openflow/datapath/flow.h | 199 - openflow/datapath/forward.c | 642 --- openflow/datapath/forward.h | 38 - openflow/datapath/hwtable_dummy/Modules.mk | 7 - .../datapath/hwtable_dummy/hwtable_dummy.c | 320 -- openflow/datapath/hwtable_nf2/Modules.mk | 19 - openflow/datapath/hwtable_nf2/README | 78 - openflow/datapath/hwtable_nf2/nf2.h | 424 -- openflow/datapath/hwtable_nf2/nf2_flowtable.c | 452 --- openflow/datapath/hwtable_nf2/nf2_flowtable.h | 63 - openflow/datapath/hwtable_nf2/nf2_hwapi.h | 43 - openflow/datapath/hwtable_nf2/nf2_lib.c | 918 ----- openflow/datapath/hwtable_nf2/nf2_lib.h | 59 - openflow/datapath/hwtable_nf2/nf2_openflow.c | 847 ---- openflow/datapath/hwtable_nf2/nf2_openflow.h | 169 - openflow/datapath/hwtable_nf2/nf2_procfs.c | 240 -- openflow/datapath/hwtable_nf2/nf2_procfs.h | 39 - openflow/datapath/hwtable_nf2/nf2_reg.h | 767 ---- .../datapath/hwtable_nf2/openflow_switch.bit | Bin 2377746 -> 0 bytes openflow/datapath/linux-2.6/.gitignore | 30 - openflow/datapath/linux-2.6/Kbuild.in | 35 - openflow/datapath/linux-2.6/Makefile.in | 9 - openflow/datapath/linux-2.6/Makefile.main.in | 85 - openflow/datapath/linux-2.6/Modules.mk | 32 - .../datapath/linux-2.6/compat-2.6/compat26.h | 31 - .../linux-2.6/compat-2.6/genetlink-brcompat.c | 20 - .../linux-2.6/compat-2.6/genetlink-openflow.c | 22 - .../compat-2.6/include/asm-generic/bug.h | 20 - .../linux-2.6/compat-2.6/include/linux/dmi.h | 114 - .../linux-2.6/compat-2.6/include/linux/icmp.h | 13 - .../compat-2.6/include/linux/if_arp.h | 16 - .../linux-2.6/compat-2.6/include/linux/ip.h | 18 - .../linux-2.6/compat-2.6/include/linux/ipv6.h | 13 - .../compat-2.6/include/linux/jiffies.h | 26 - .../compat-2.6/include/linux/lockdep.h | 450 --- .../compat-2.6/include/linux/mutex.h | 59 - .../compat-2.6/include/linux/netdevice.h | 10 - .../include/linux/netfilter_bridge.h | 24 - .../compat-2.6/include/linux/netfilter_ipv4.h | 19 - .../compat-2.6/include/linux/netlink.h | 24 - .../compat-2.6/include/linux/random.h | 17 - .../compat-2.6/include/linux/rculist.h | 12 - .../compat-2.6/include/linux/skbuff.h | 137 - .../linux-2.6/compat-2.6/include/linux/tcp.h | 18 - .../compat-2.6/include/linux/timer.h | 96 - .../compat-2.6/include/linux/types.h | 14 - .../linux-2.6/compat-2.6/include/linux/udp.h | 13 - .../compat-2.6/include/linux/workqueue.h | 42 - .../compat-2.6/include/net/checksum.h | 16 - .../compat-2.6/include/net/genetlink.h | 123 - .../compat-2.6/include/net/netlink.h | 22 - .../datapath/linux-2.6/compat-2.6/random32.c | 146 - openflow/datapath/linux-2.6/compat-2.6/veth.c | 537 --- .../config/config-linux-2.6.23-rc9-kvm | 1408 ------- openflow/datapath/openflow-ext.c | 83 - openflow/datapath/openflow-ext.h | 38 - openflow/datapath/private-msg.c | 137 - openflow/datapath/private-msg.h | 38 - openflow/datapath/table-hash.c | 489 --- openflow/datapath/table-linear.c | 233 -- openflow/datapath/table.h | 119 - openflow/debian/.gitignore | 38 - openflow/debian/changelog | 23 - openflow/debian/commands/reconfigure | 128 - openflow/debian/commands/update | 4 - openflow/debian/compat | 1 - openflow/debian/control.in | 93 - openflow/debian/control.modules.in | 19 - openflow/debian/copyright | 38 - openflow/debian/corekeeper.cron.daily | 5 - openflow/debian/corekeeper.init | 63 - openflow/debian/dirs | 2 - openflow/debian/ofp-switch-setup | 615 --- openflow/debian/ofp-switch-setup.8 | 41 - openflow/debian/openflow-common.dirs | 1 - openflow/debian/openflow-common.install | 3 - openflow/debian/openflow-common.manpages | 2 - .../debian/openflow-controller.README.Debian | 10 - openflow/debian/openflow-controller.default | 33 - openflow/debian/openflow-controller.dirs | 1 - openflow/debian/openflow-controller.init | 269 -- openflow/debian/openflow-controller.install | 1 - openflow/debian/openflow-controller.manpages | 1 - openflow/debian/openflow-controller.postinst | 52 - ...atapath-module-_KVERS_.postinst.modules.in | 25 - .../openflow-datapath-source.README.Debian | 31 - .../debian/openflow-datapath-source.copyright | 16 - openflow/debian/openflow-datapath-source.dirs | 1 - .../debian/openflow-datapath-source.install | 6 - openflow/debian/openflow-pki-server.apache2 | 1 - openflow/debian/openflow-pki-server.dirs | 1 - openflow/debian/openflow-pki-server.install | 1 - openflow/debian/openflow-pki-server.postinst | 44 - openflow/debian/openflow-pki.postinst | 41 - openflow/debian/openflow-switch-config.dirs | 1 - .../debian/openflow-switch-config.install | 1 - .../debian/openflow-switch-config.manpages | 1 - .../debian/openflow-switch-config.overrides | 1 - .../debian/openflow-switch-config.templates | 228 -- openflow/debian/openflow-switch.README.Debian | 18 - openflow/debian/openflow-switch.dirs | 2 - openflow/debian/openflow-switch.init | 437 -- openflow/debian/openflow-switch.install | 6 - openflow/debian/openflow-switch.logrotate | 11 - openflow/debian/openflow-switch.manpages | 4 - openflow/debian/openflow-switch.postinst | 51 - openflow/debian/openflow-switch.postrm | 43 - openflow/debian/openflow-switch.template | 169 - openflow/debian/po/POTFILES.in | 1 - openflow/debian/rules | 163 - openflow/doc/of-spec/.gitignore | 8 - openflow/doc/of-spec/Makefile | 40 - openflow/doc/of-spec/README | 3 - openflow/doc/of-spec/appendix.tex | 429 -- openflow/doc/of-spec/credits.tex | 22 - .../doc/of-spec/figure_flow_table_secchan.png | Bin 67886 -> 0 bytes .../of-spec/header_parsing_flowchart.graffle | 3536 ----------------- openflow/doc/of-spec/make_latex_input.pl | 117 - openflow/doc/of-spec/openflow-spec-v1.0.0.tex | 418 -- .../doc/of-spec/packet_flow_flowchart.graffle | 1887 --------- openflow/hw-lib/automake.mk | 28 - openflow/hw-lib/nf2/README | 56 - openflow/hw-lib/nf2/debug.h | 105 - openflow/hw-lib/nf2/hw_flow.c | 514 --- openflow/hw-lib/nf2/hw_flow.h | 56 - openflow/hw-lib/nf2/nf2.h | 452 --- openflow/hw-lib/nf2/nf2_drv.c | 847 ---- openflow/hw-lib/nf2/nf2_drv.h | 150 - openflow/hw-lib/nf2/nf2_lib.c | 1049 ----- openflow/hw-lib/nf2/nf2_lib.h | 59 - openflow/hw-lib/nf2/nf2util.c | 400 -- openflow/hw-lib/nf2/nf2util.h | 46 - .../hw-lib/nf2/reg_defines_openflow_switch.h | 767 ---- openflow/hw-lib/skeleton/debug.h | 106 - openflow/hw-lib/skeleton/hw_drv.c | 309 -- openflow/hw-lib/skeleton/hw_drv.h | 97 - openflow/hw-lib/skeleton/hw_flow.c | 708 ---- openflow/hw-lib/skeleton/hw_flow.h | 111 - openflow/hw-lib/skeleton/of_hw_platform.h | 38 - openflow/hw-lib/skeleton/os.h | 29 - openflow/hw-lib/skeleton/port.c | 497 --- openflow/hw-lib/skeleton/port.h | 45 - openflow/hw-lib/skeleton/sample_plat.c | 82 - openflow/hw-lib/skeleton/sample_plat.h | 61 - openflow/hw-lib/skeleton/txrx.c | 129 - openflow/hw-lib/skeleton/txrx.h | 12 - openflow/include/.gitignore | 2 - openflow/include/automake.mk | 1 - openflow/include/openflow/automake.mk | 5 - openflow/include/openflow/nicira-ext.h | 195 - openflow/include/openflow/of_hw_api.h | 313 -- openflow/include/openflow/openflow-ext.h | 149 - openflow/include/openflow/openflow-netlink.h | 69 - openflow/include/openflow/openflow.h | 970 ----- openflow/include/openflow/private-ext.h | 68 - openflow/m4/libopenflow.m4 | 168 - openflow/m4/nx-build.m4 | 71 - openflow/regress/CREDITS | 22 - openflow/regress/INSTALL | 264 -- openflow/regress/LICENSE | 30 - openflow/regress/README | 329 -- openflow/regress/bin/eth.map | 8 - openflow/regress/bin/nf2.map | 8 - openflow/regress/bin/of_hp_eth.map | 8 - openflow/regress/bin/of_hp_setup.pl | 86 - openflow/regress/bin/of_hp_teardown.pl | 50 - openflow/regress/bin/of_hp_test.pl | 62 - openflow/regress/bin/of_hp_test_6600.pl | 62 - openflow/regress/bin/of_kmod_setup.pl | 22 - openflow/regress/bin/of_kmod_teardown.pl | 20 - openflow/regress/bin/of_kmod_test.pl | 27 - openflow/regress/bin/of_kmod_veth_setup.pl | 26 - openflow/regress/bin/of_kmod_veth_teardown.pl | 24 - openflow/regress/bin/of_kmod_veth_test.pl | 27 - openflow/regress/bin/of_nf2_setup.pl | 26 - openflow/regress/bin/of_nf2_teardown.pl | 20 - openflow/regress/bin/of_nf2_test.pl | 28 - openflow/regress/bin/of_ovs_eth.map | 8 - openflow/regress/bin/of_ovs_setup.pl | 76 - openflow/regress/bin/of_ovs_teardown.pl | 59 - openflow/regress/bin/of_ovs_test.pl | 54 - openflow/regress/bin/of_ovs_user_setup.pl | 60 - openflow/regress/bin/of_ovs_user_teardown.pl | 34 - openflow/regress/bin/of_ovs_user_test.pl | 50 - openflow/regress/bin/of_ovs_user_veth_test.pl | 47 - openflow/regress/bin/of_ovs_veth_test.pl | 47 - openflow/regress/bin/of_user_setup.pl | 22 - openflow/regress/bin/of_user_teardown.pl | 20 - openflow/regress/bin/of_user_test.pl | 27 - openflow/regress/bin/of_user_veth_setup.pl | 26 - openflow/regress/bin/of_user_veth_teardown.pl | 24 - openflow/regress/bin/of_user_veth_test.pl | 27 - openflow/regress/bin/veth.map | 8 - openflow/regress/bin/veth_setup.pl | 10 - openflow/regress/bin/veth_teardown.pl | 4 - .../projects/black_box/regress/common/setup | 47 - .../black_box/regress/common/teardown | 47 - .../regress/test_add_flow_latency/run.pl | 47 - .../black_box/regress/test_barrier/run.pl | 52 - .../regress/test_cookie_flow_expired/run.pl | 39 - .../regress/test_cookie_flow_stats/run.pl | 151 - .../black_box/regress/test_delete/run.pl | 172 - .../regress/test_delete_send_flow_exp/run.pl | 104 - .../regress/test_delete_strict/run.pl | 175 - .../black_box/regress/test_drop_exact/run.pl | 54 - .../regress/test_failover_close/run.pl | 68 - .../regress/test_failover_startup/run.pl | 53 - .../test_failover_stop_responding/run.pl | 65 - .../regress/test_flow_expired/run.pl | 34 - .../test_flow_expired_idle_timeout/run.pl | 34 - .../test_flow_expired_precision/run.pl | 66 - .../test_flow_expired_send_flow_exp/run.pl | 44 - .../regress/test_flow_mod_check/run.pl | 83 - .../test_flow_mod_latency/run-port3.pl | 136 - .../regress/test_flow_mod_latency/run.pl | 129 - .../black_box/regress/test_flow_stats/run.pl | 145 - .../regress/test_flow_stats_precision/run.pl | 191 - .../test_forward_after_expiration/run.pl | 111 - .../regress/test_forward_any_port/run.pl | 20 - .../test_forward_bandwidth_fixed/run.pl | 83 - .../test_forward_bandwidth_random/run.pl | 84 - .../test_forward_broadcast_exact_port/run.pl | 64 - .../regress/test_forward_exact_all/run.pl | 30 - .../regress/test_forward_exact_arp_all/run.pl | 19 - .../test_forward_exact_arp_controller/run.pl | 19 - .../test_forward_exact_arp_fool/run.pl | 19 - .../test_forward_exact_arp_port/run.pl | 19 - .../test_forward_exact_controller/run.pl | 32 - .../test_forward_exact_icmp_all/run.pl | 19 - .../test_forward_exact_icmp_controller/run.pl | 19 - .../test_forward_exact_icmp_fool/run.pl | 19 - .../test_forward_exact_icmp_port/run.pl | 19 - .../test_forward_exact_modify_action/run.pl | 42 - .../regress/test_forward_exact_port/run.pl | 27 - .../run.pl | 86 - .../regress/test_forward_wildcard_all/run.pl | 172 - .../test_forward_wildcard_arp_all/run.pl | 20 - .../run.pl | 19 - .../test_forward_wildcard_arp_fool/run.pl | 20 - .../test_forward_wildcard_arp_port/run.pl | 20 - .../test_forward_wildcard_controller/run.pl | 30 - .../test_forward_wildcard_icmp_all/run.pl | 20 - .../run.pl | 19 - .../test_forward_wildcard_icmp_fool/run.pl | 20 - .../test_forward_wildcard_icmp_port/run.pl | 20 - .../run.pl | 35 - .../regress/test_forward_wildcard_port/run.pl | 97 - .../black_box/regress/test_hello/run.pl | 16 - .../black_box/regress/test_ip_offset/run.pl | 85 - .../black_box/regress/test_ip_options/run.pl | 76 - .../regress/test_ip_protocol/case-c.pl | 150 - .../regress/test_ip_protocol/case-d.pl | 152 - .../regress/test_ip_protocol/case-e.pl | 152 - .../regress/test_ip_protocol/case-tcp.pl | 153 - .../regress/test_ip_protocol/case-udp.pl | 67 - .../black_box/regress/test_llc/run.pl | 128 - .../regress/test_miss_send_length/run.pl | 79 - .../black_box/regress/test_packet_in/run.pl | 45 - .../black_box/regress/test_packet_out/run.pl | 53 - .../black_box/regress/test_port_stats/run.pl | 132 - .../regress/test_queue_config/run.pl | 52 - .../regress/test_queue_forward/run.pl | 19 - .../black_box/regress/test_queue_stats/run.pl | 116 - .../test_receive_bandwidth_fixed/run.pl | 89 - .../regress/test_send_bandwidth_fixed/run.pl | 140 - .../regress/test_send_bandwidth_random/run.pl | 141 - .../regress/test_set_dl_nw_flip/run.pl | 143 - .../regress/test_set_n_match_nw_tos/run.pl | 95 - .../black_box/regress/test_set_nw_dst/run.pl | 95 - .../black_box/regress/test_stats_desc/run.pl | 71 - .../regress/test_switch_config/run.pl | 40 - .../black_box/regress/test_tcp_options/run.pl | 170 - .../projects/black_box/regress/tests.txt | 103 - .../regress/common/setup | 49 - .../regress/common/teardown | 47 - .../regress/test_emergency_table/run.pl | 107 - .../controller_disconnect/regress/tests.txt | 2 - .../learning_switch/regress/common/setup | 46 - .../learning_switch/regress/common/teardown | 46 - .../regress/test_broadcast/run.pl | 50 - .../regress/test_forward_bandwidth/run.pl | 62 - .../regress/test_forward_latency/run.pl | 69 - .../regress/test_hub_connected/run.pl | 64 - .../regress/test_unicast_known/run.pl | 71 - .../regress/test_unicast_move/run.pl | 79 - .../test_unicast_multiple_hosts/run.pl | 93 - .../regress/test_unicast_self/run.pl | 61 - .../regress/test_unicast_unknown/run.pl | 32 - .../learning_switch/regress/tests.txt | 12 - openflow/regress/projects/regress.txt | 3 - openflow/regress/scripts/copy_NF2_code.sh | 5 - openflow/regress/scripts/env_vars | 12 - openflow/regress/scripts/install_deps.pl | 264 -- .../regress/scripts/install_perlmods_apt.pl | 32 - openflow/regress/scripts/make_release.pl | 155 - openflow/secchan/.dirstamp | 0 openflow/secchan/.gitignore | 7 - openflow/secchan/automake.mk | 32 - openflow/secchan/commands/automake.mk | 3 - openflow/secchan/commands/reboot | 3 - openflow/secchan/discovery.c | 251 -- openflow/secchan/discovery.h | 50 - openflow/secchan/emerg-flow.c | 144 - openflow/secchan/emerg-flow.h | 44 - openflow/secchan/fail-open.c | 159 - openflow/secchan/fail-open.h | 46 - openflow/secchan/failover.c | 144 - openflow/secchan/failover.h | 44 - openflow/secchan/in-band.c | 331 -- openflow/secchan/in-band.h | 47 - openflow/secchan/ofprotocol.8.in | 462 --- openflow/secchan/port-watcher.c | 620 --- openflow/secchan/port-watcher.h | 77 - openflow/secchan/protocol-stat.c | 204 - openflow/secchan/protocol-stat.h | 44 - openflow/secchan/ratelimit.c | 263 -- openflow/secchan/ratelimit.h | 45 - openflow/secchan/secchan.c | 882 ---- openflow/secchan/secchan.h | 135 - openflow/secchan/status.c | 230 -- openflow/secchan/status.h | 56 - openflow/secchan/stp-secchan.c | 293 -- openflow/secchan/stp-secchan.h | 48 - openflow/soexpand.pl | 26 - openflow/tests/.dirstamp | 0 openflow/tests/.gitignore | 6 - openflow/tests/automake.mk | 46 - openflow/tests/flowgen.pl | 224 -- openflow/tests/test-dhcp-client.c | 206 - openflow/tests/test-flows | Bin 286976 -> 0 bytes openflow/tests/test-flows.c | 76 - openflow/tests/test-flows.sh | 9 - openflow/tests/test-hmap | Bin 68296 -> 0 bytes openflow/tests/test-hmap.c | 282 -- openflow/tests/test-list.c | 159 - openflow/tests/test-stp-ieee802.1d-1998 | 12 - .../tests/test-stp-ieee802.1d-2004-fig17.4 | 31 - .../tests/test-stp-ieee802.1d-2004-fig17.6 | 14 - .../tests/test-stp-ieee802.1d-2004-fig17.7 | 17 - openflow/tests/test-stp-iol-io-1.1 | 25 - openflow/tests/test-stp-iol-io-1.2 | 14 - openflow/tests/test-stp-iol-io-1.4 | 13 - openflow/tests/test-stp-iol-io-1.5 | 40 - openflow/tests/test-stp-iol-op-1.1 | 7 - openflow/tests/test-stp-iol-op-1.4 | 8 - openflow/tests/test-stp-iol-op-3.1 | 11 - openflow/tests/test-stp-iol-op-3.3 | 11 - openflow/tests/test-stp-iol-op-3.4 | 11 - openflow/tests/test-stp.c | 665 ---- openflow/tests/test-stp.sh | 7 - openflow/tests/test-type-props.c | 41 - openflow/third-party/.gitignore | 2 - openflow/third-party/README | 35 - openflow/third-party/automake.mk | 3 - openflow/third-party/ofp-tcpdump.patch | 119 - openflow/udatapath/.dirstamp | 0 openflow/udatapath/.gitignore | 4 - openflow/udatapath/automake.mk | 75 - openflow/udatapath/chain.c | 261 -- openflow/udatapath/chain.h | 74 - openflow/udatapath/crc32.c | 68 - openflow/udatapath/crc32.h | 50 - openflow/udatapath/datapath.c | 2375 ----------- openflow/udatapath/datapath.h | 167 - openflow/udatapath/dp_act.c | 531 --- openflow/udatapath/dp_act.h | 49 - openflow/udatapath/of_ext_msg.c | 267 -- openflow/udatapath/of_ext_msg.h | 43 - openflow/udatapath/ofdatapath.8.in | 148 - openflow/udatapath/private-msg.c | 140 - openflow/udatapath/private-msg.h | 42 - openflow/udatapath/switch-flow.c | 341 -- openflow/udatapath/switch-flow.h | 100 - openflow/udatapath/table-hash.c | 469 --- openflow/udatapath/table-linear.c | 262 -- openflow/udatapath/table.h | 150 - openflow/udatapath/udatapath.c | 345 -- openflow/utilities/.dirstamp | 0 openflow/utilities/.gitignore | 13 - openflow/utilities/automake.mk | 45 - openflow/utilities/dpctl.8.in | 582 --- openflow/utilities/dpctl.c | 1772 --------- openflow/utilities/ofp-discover.8.in | 119 - openflow/utilities/ofp-discover.c | 420 -- openflow/utilities/ofp-kill.8.in | 61 - openflow/utilities/ofp-kill.c | 228 -- openflow/utilities/ofp-parse-leaks | 285 -- openflow/utilities/ofp-parse-leaks.in | 285 -- openflow/utilities/ofp-pki-cgi.in | 41 - openflow/utilities/ofp-pki.8.in | 325 -- openflow/utilities/ofp-pki.in | 582 --- openflow/utilities/vlogconf.8.in | 183 - openflow/utilities/vlogconf.c | 235 -- .../utilities/wireshark_dissectors/Makefile | 32 - .../utilities/wireshark_dissectors/README | 37 - .../wireshark_dissectors/openflow/.gitignore | 1 - .../wireshark_dissectors/openflow/Makefile | 79 - .../wireshark_dissectors/openflow/Makefile.am | 110 - .../openflow/Makefile.common | 13 - .../openflow/build_distribution_tarball.sh | 63 - .../openflow/moduleinfo.h | 15 - .../openflow/packet-openflow.c | 3426 ---------------- .../wireshark_dissectors/openflow/plugin.c | 28 - .../wireshark-1.0.0-includes/airpcap.h | 907 ----- .../wireshark-1.0.0-includes/airpcap_loader.h | 560 --- .../wireshark-1.0.0-includes/alert_box.h | 70 - .../capture-pcap-util-int.h | 56 - .../capture-pcap-util.h | 131 - .../wireshark-1.0.0-includes/capture-wpcap.h | 34 - .../wireshark-1.0.0-includes/capture.h | 118 - .../wireshark-1.0.0-includes/capture_errs.h | 34 - .../wireshark-1.0.0-includes/capture_info.h | 76 - .../wireshark-1.0.0-includes/capture_opts.h | 194 - .../capture_stop_conditions.h | 29 - .../wireshark-1.0.0-includes/capture_sync.h | 87 - .../capture_ui_utils.h | 89 - .../capture_wpcap_packet.h | 47 - .../wireshark-1.0.0-includes/cfile.h | 91 - .../wireshark-1.0.0-includes/clopts_common.h | 40 - .../wireshark-1.0.0-includes/cmdarg_err.h | 56 - .../wireshark-1.0.0-includes/color.h | 55 - .../wireshark-1.0.0-includes/color_filters.h | 196 - .../wireshark-1.0.0-includes/conditions.h | 134 - .../wireshark-1.0.0-includes/config.h | 322 -- .../wireshark-1.0.0-includes/config.h.in | 321 -- .../wireshark-1.0.0-includes/config.h.win32 | 274 -- .../disabled_protos.h | 61 - .../epan/addr_and_mask.h | 53 - .../epan/addr_resolv.h | 198 - .../wireshark-1.0.0-includes/epan/address.h | 172 - .../wireshark-1.0.0-includes/epan/adler32.h | 42 - .../wireshark-1.0.0-includes/epan/afn.h | 71 - .../wireshark-1.0.0-includes/epan/aftypes.h | 47 - .../epan/arcnet_pids.h | 70 - .../wireshark-1.0.0-includes/epan/arptypes.h | 75 - .../wireshark-1.0.0-includes/epan/asm_utils.h | 38 - .../wireshark-1.0.0-includes/epan/asn1.h | 207 - .../epan/atalk-utils.h | 63 - .../wireshark-1.0.0-includes/epan/base64.h | 38 - .../wireshark-1.0.0-includes/epan/bitswap.h | 40 - .../epan/bridged_pids.h | 58 - .../epan/camel-persistentdata.h | 127 - .../wireshark-1.0.0-includes/epan/charsets.h | 42 - .../epan/chdlctypes.h | 40 - .../wireshark-1.0.0-includes/epan/circuit.h | 80 - .../wireshark-1.0.0-includes/epan/codecs.h | 43 - .../epan/column-utils.h | 241 -- .../wireshark-1.0.0-includes/epan/column.h | 56 - .../epan/column_info.h | 134 - .../epan/conversation.h | 109 - .../wireshark-1.0.0-includes/epan/crc10.h | 27 - .../wireshark-1.0.0-includes/epan/crc16.h | 109 - .../wireshark-1.0.0-includes/epan/crc32.h | 94 - .../wireshark-1.0.0-includes/epan/crc6.h | 26 - .../wireshark-1.0.0-includes/epan/crcdrm.h | 7 - .../epan/crypt/airpdcap_debug.h | 106 - .../epan/crypt/airpdcap_int.h | 158 - .../epan/crypt/airpdcap_interop.h | 101 - .../epan/crypt/airpdcap_rijndael.h | 93 - .../epan/crypt/airpdcap_system.h | 356 -- .../epan/crypt/airpdcap_user.h | 231 -- .../epan/crypt/airpdcap_ws.h | 43 - .../epan/crypt/crypt-des.h | 26 - .../epan/crypt/crypt-md4.h | 23 - .../epan/crypt/crypt-md5.h | 71 - .../epan/crypt/crypt-rc4.h | 36 - .../epan/crypt/crypt-sha1.h | 45 - .../epan/crypt/wep-wpadefs.h | 115 - .../epan/dfilter/dfilter-int.h | 82 - .../epan/dfilter/dfilter-macro.h | 59 - .../epan/dfilter/dfilter.h | 94 - .../epan/dfilter/dfunctions.h | 56 - .../epan/dfilter/dfvm.h | 108 - .../epan/dfilter/drange.h | 102 - .../epan/dfilter/gencode.h | 10 - .../epan/dfilter/glib-util.h | 4 - .../epan/dfilter/grammar.h | 24 - .../epan/dfilter/scanner_lex.h | 6 - .../epan/dfilter/semcheck.h | 31 - .../epan/dfilter/sttype-function.h | 42 - .../epan/dfilter/sttype-range.h | 45 - .../epan/dfilter/sttype-test.h | 56 - .../epan/dfilter/syntax-tree.h | 136 - .../wireshark-1.0.0-includes/epan/diam_dict.h | 89 - .../epan/diam_dict_lex.h | 6 - .../epan/dissector_filters.h | 60 - .../epan/dissectors/packet-tcp.h | 232 -- .../wireshark-1.0.0-includes/epan/dtd.h | 62 - .../epan/dtd_grammar.h | 23 - .../wireshark-1.0.0-includes/epan/dtd_parse.h | 37 - .../epan/dtd_parse_lex.h | 6 - .../epan/dtd_preparse_lex.h | 6 - .../wireshark-1.0.0-includes/epan/eap.h | 53 - .../wireshark-1.0.0-includes/epan/emem.h | 373 -- .../wireshark-1.0.0-includes/epan/epan.h | 93 - .../epan/epan_dissect.h | 44 - .../wireshark-1.0.0-includes/epan/etypes.h | 408 -- .../wireshark-1.0.0-includes/epan/ex-opt.h | 44 - .../wireshark-1.0.0-includes/epan/except.h | 158 - .../epan/exceptions.h | 319 -- .../wireshark-1.0.0-includes/epan/expert.h | 70 - .../epan/filesystem.h | 248 -- .../wireshark-1.0.0-includes/epan/follow.h | 58 - .../epan/frame_data.h | 79 - .../epan/frequency-utils.h | 74 - .../epan/ftypes/ftypes-int.h | 61 - .../epan/ftypes/ftypes.h | 367 -- .../wireshark-1.0.0-includes/epan/funnel.h | 116 - .../epan/g_ascii_strcasecmp.h | 18 - .../epan/g_ascii_strtoull.h | 15 - .../wireshark-1.0.0-includes/epan/garrayfix.h | 38 - .../wireshark-1.0.0-includes/epan/gcp.h | 219 - .../epan/gnuc_format_check.h | 39 - .../wireshark-1.0.0-includes/epan/golay.h | 49 - .../wireshark-1.0.0-includes/epan/greproto.h | 36 - .../epan/guid-utils.h | 63 - .../epan/h225-persistentdata.h | 62 - .../epan/iax2_codec_type.h | 77 - .../wireshark-1.0.0-includes/epan/in_cksum.h | 14 - .../wireshark-1.0.0-includes/epan/inet_aton.h | 34 - .../wireshark-1.0.0-includes/epan/ip_opts.h | 59 - .../wireshark-1.0.0-includes/epan/ipproto.h | 193 - .../wireshark-1.0.0-includes/epan/ipv4.h | 67 - .../epan/ipv6-utils.h | 49 - .../wireshark-1.0.0-includes/epan/lapd_sapi.h | 38 - .../wireshark-1.0.0-includes/epan/llcsaps.h | 63 - .../wireshark-1.0.0-includes/epan/next_tvb.h | 65 - .../wireshark-1.0.0-includes/epan/nlpid.h | 60 - .../wireshark-1.0.0-includes/epan/nstime.h | 92 - .../wireshark-1.0.0-includes/epan/oids.h | 179 - .../wireshark-1.0.0-includes/epan/osi-utils.h | 57 - .../wireshark-1.0.0-includes/epan/oui.h | 74 - .../wireshark-1.0.0-includes/epan/packet.h | 422 -- .../epan/packet_info.h | 184 - .../wireshark-1.0.0-includes/epan/pint.h | 113 - .../wireshark-1.0.0-includes/epan/plugins.h | 58 - .../wireshark-1.0.0-includes/epan/ppptypes.h | 158 - .../wireshark-1.0.0-includes/epan/prefs-int.h | 111 - .../wireshark-1.0.0-includes/epan/prefs.h | 426 -- .../epan/privileges.h | 74 - .../wireshark-1.0.0-includes/epan/proto.h | 1655 -------- .../wireshark-1.0.0-includes/epan/ptvcursor.h | 110 - .../epan/radius_dict_lex.h | 6 - .../wireshark-1.0.0-includes/epan/range.h | 73 - .../epan/reassemble.h | 316 -- .../epan/reedsolomon.h | 86 - .../epan/report_err.h | 61 - .../epan/req_resp_hdrs.h | 43 - .../wireshark-1.0.0-includes/epan/rtp_pt.h | 68 - .../wireshark-1.0.0-includes/epan/sctpppids.h | 50 - .../epan/sigcomp-udvm.h | 49 - .../epan/sigcomp_state_hdlr.h | 49 - .../wireshark-1.0.0-includes/epan/slab.h | 75 - .../wireshark-1.0.0-includes/epan/sminmpec.h | 83 - .../wireshark-1.0.0-includes/epan/sna-utils.h | 41 - .../epan/stat_cmd_args.h | 35 - .../epan/stats_tree.h | 147 - .../epan/stats_tree_priv.h | 202 - .../wireshark-1.0.0-includes/epan/stream.h | 138 - .../wireshark-1.0.0-includes/epan/strutil.h | 243 -- .../wireshark-1.0.0-includes/epan/t35.h | 35 - .../wireshark-1.0.0-includes/epan/tap-voip.h | 59 - .../wireshark-1.0.0-includes/epan/tap.h | 61 - .../epan/tcap-persistentdata.h | 148 - .../wireshark-1.0.0-includes/epan/tfs.h | 65 - .../wireshark-1.0.0-includes/epan/timestamp.h | 68 - .../wireshark-1.0.0-includes/epan/to_str.h | 94 - .../wireshark-1.0.0-includes/epan/tvbparse.h | 475 --- .../wireshark-1.0.0-includes/epan/tvbuff.h | 634 --- .../wireshark-1.0.0-includes/epan/uat-int.h | 92 - .../wireshark-1.0.0-includes/epan/uat.h | 486 --- .../epan/uat_load_lex.h | 6 - .../epan/unicode-utils.h | 54 - .../epan/value_string.h | 88 - .../epan/ws_strsplit.h | 41 - .../epan/wslua/declare_wslua.h | 59 - .../epan/wslua/wslua.h | 372 -- .../epan/x264_prt_id.h | 35 - .../wireshark-1.0.0-includes/epan/xdlc.h | 140 - .../wireshark-1.0.0-includes/epan/xmlstub.h | 1123 ------ .../wireshark-1.0.0-includes/file.h | 486 --- .../wireshark-1.0.0-includes/fileset.h | 75 - .../wireshark-1.0.0-includes/filters.h | 87 - .../wireshark-1.0.0-includes/g711.h | 30 - .../wireshark-1.0.0-includes/getopt.h | 129 - .../wireshark-1.0.0-includes/globals.h | 37 - .../wireshark-1.0.0-includes/inet_v6defs.h | 54 - .../wireshark-1.0.0-includes/isprint.h | 46 - .../wireshark-1.0.0-includes/log.h | 42 - .../wireshark-1.0.0-includes/main_window.h | 41 - .../wireshark-1.0.0-includes/menu.h | 64 - .../wireshark-1.0.0-includes/merge.h | 125 - .../wireshark-1.0.0-includes/mkstemp.h | 24 - .../wireshark-1.0.0-includes/packet-range.h | 101 - .../wireshark-1.0.0-includes/pcapio.h | 44 - .../wireshark-1.0.0-includes/print.h | 148 - .../wireshark-1.0.0-includes/progress_dlg.h | 94 - .../proto_hier_stats.h | 51 - .../wireshark-1.0.0-includes/ps.h | 35 - .../wireshark-1.0.0-includes/register.h | 48 - .../wireshark-1.0.0-includes/ringbuffer.h | 53 - .../wireshark-1.0.0-includes/simple_dialog.h | 184 - .../wireshark-1.0.0-includes/stat_menu.h | 64 - .../wireshark-1.0.0-includes/statusbar.h | 56 - .../wireshark-1.0.0-includes/strerror.h | 33 - .../wireshark-1.0.0-includes/strptime.h | 32 - .../wireshark-1.0.0-includes/summary.h | 76 - .../wireshark-1.0.0-includes/svnversion.h | 1 - .../wireshark-1.0.0-includes/sync_pipe.h | 80 - .../wireshark-1.0.0-includes/tap-rtp-common.h | 49 - .../tap_dfilter_dlg.h | 73 - .../wireshark-1.0.0-includes/tempfile.h | 43 - .../wireshark-1.0.0-includes/text2pcap.h | 49 - .../wireshark-1.0.0-includes/timestats.h | 54 - .../tools/make-dissector-reg | 186 - .../tools/make-dissector-reg.py | 238 -- .../wireshark-1.0.0-includes/ui_util.h | 79 - .../wireshark-1.0.0-includes/util.h | 60 - .../wireshark-1.0.0-includes/version_info.h | 79 - .../wireshark-1.0.0-includes/wiretap/5views.h | 30 - .../wiretap/airopeek9.h | 29 - .../wiretap/ascend-grammar.h | 90 - .../wiretap/ascend-int.h | 54 - .../wiretap/ascend-scanner_lex.h | 6 - .../wireshark-1.0.0-includes/wiretap/ascend.h | 33 - .../wireshark-1.0.0-includes/wiretap/atm.h | 40 - .../wireshark-1.0.0-includes/wiretap/ber.h | 28 - .../wiretap/btsnoop.h | 30 - .../wireshark-1.0.0-includes/wiretap/buffer.h | 58 - .../wiretap/catapult_dct2000.h | 30 - .../wiretap/commview.h | 33 - .../wireshark-1.0.0-includes/wiretap/cosine.h | 32 - .../wireshark-1.0.0-includes/wiretap/csids.h | 29 - .../wiretap/dbs-etherwatch.h | 29 - .../wireshark-1.0.0-includes/wiretap/erf.h | 102 - .../wiretap/etherpeek.h | 29 - .../wireshark-1.0.0-includes/wiretap/eyesdn.h | 29 - .../wiretap/file_util.h | 136 - .../wiretap/file_wrappers.h | 57 - .../wiretap/hcidump.h | 28 - .../wiretap/i4b_trace.h | 92 - .../wiretap/i4btrace.h | 29 - .../wiretap/iptrace.h | 29 - .../wiretap/iseries.h | 28 - .../wireshark-1.0.0-includes/wiretap/k12.h | 28 - .../wiretap/k12text_lex.h | 6 - .../wiretap/lanalyzer.h | 176 - .../wiretap/libpcap.h | 106 - .../wiretap/mpeg-audio.h | 98 - .../wireshark-1.0.0-includes/wiretap/mpeg.h | 32 - .../wireshark-1.0.0-includes/wiretap/netmon.h | 30 - .../wiretap/netscreen.h | 53 - .../wireshark-1.0.0-includes/wiretap/nettl.h | 124 - .../wiretap/network_instruments.h | 127 - .../wiretap/netxray.h | 32 - .../wiretap/ngsniffer.h | 30 - .../wireshark-1.0.0-includes/wiretap/pcapng.h | 30 - .../wiretap/pppdump.h | 28 - .../wireshark-1.0.0-includes/wiretap/radcom.h | 29 - .../wireshark-1.0.0-includes/wiretap/snoop.h | 30 - .../wiretap/toshiba.h | 28 - .../wireshark-1.0.0-includes/wiretap/visual.h | 35 - .../wireshark-1.0.0-includes/wiretap/vms.h | 29 - .../wiretap/wtap-int.h | 482 --- .../wireshark-1.0.0-includes/wiretap/wtap.h | 944 ----- 697 files changed, 95060 deletions(-) delete mode 100644 openflow/.gitignore delete mode 100644 openflow/COPYING delete mode 100644 openflow/ChangeLog delete mode 100644 openflow/INSTALL delete mode 100644 openflow/Makefile.am delete mode 100644 openflow/README delete mode 100644 openflow/README.hwtables delete mode 100644 openflow/README.kernel delete mode 100644 openflow/acinclude.m4 delete mode 100755 openflow/boot.sh delete mode 100644 openflow/configure.ac delete mode 100644 openflow/controller/.dirstamp delete mode 100644 openflow/controller/.gitignore delete mode 100644 openflow/controller/automake.mk delete mode 100644 openflow/controller/controller.8.in delete mode 100644 openflow/controller/controller.c delete mode 100644 openflow/datapath/.gitignore delete mode 100644 openflow/datapath/Makefile.am delete mode 100644 openflow/datapath/Modules.mk delete mode 100644 openflow/datapath/chain.c delete mode 100644 openflow/datapath/chain.h delete mode 100644 openflow/datapath/compat.h delete mode 100644 openflow/datapath/crc32.c delete mode 100644 openflow/datapath/crc32.h delete mode 100644 openflow/datapath/datapath.c delete mode 100644 openflow/datapath/datapath.h delete mode 100644 openflow/datapath/dp_act.c delete mode 100644 openflow/datapath/dp_act.h delete mode 100644 openflow/datapath/dp_dev.c delete mode 100644 openflow/datapath/dp_dev.h delete mode 100644 openflow/datapath/dp_notify.c delete mode 100644 openflow/datapath/flow.c delete mode 100644 openflow/datapath/flow.h delete mode 100644 openflow/datapath/forward.c delete mode 100644 openflow/datapath/forward.h delete mode 100644 openflow/datapath/hwtable_dummy/Modules.mk delete mode 100644 openflow/datapath/hwtable_dummy/hwtable_dummy.c delete mode 100644 openflow/datapath/hwtable_nf2/Modules.mk delete mode 100644 openflow/datapath/hwtable_nf2/README delete mode 100644 openflow/datapath/hwtable_nf2/nf2.h delete mode 100644 openflow/datapath/hwtable_nf2/nf2_flowtable.c delete mode 100644 openflow/datapath/hwtable_nf2/nf2_flowtable.h delete mode 100644 openflow/datapath/hwtable_nf2/nf2_hwapi.h delete mode 100644 openflow/datapath/hwtable_nf2/nf2_lib.c delete mode 100644 openflow/datapath/hwtable_nf2/nf2_lib.h delete mode 100644 openflow/datapath/hwtable_nf2/nf2_openflow.c delete mode 100644 openflow/datapath/hwtable_nf2/nf2_openflow.h delete mode 100644 openflow/datapath/hwtable_nf2/nf2_procfs.c delete mode 100644 openflow/datapath/hwtable_nf2/nf2_procfs.h delete mode 100644 openflow/datapath/hwtable_nf2/nf2_reg.h delete mode 100644 openflow/datapath/hwtable_nf2/openflow_switch.bit delete mode 100644 openflow/datapath/linux-2.6/.gitignore delete mode 100644 openflow/datapath/linux-2.6/Kbuild.in delete mode 100644 openflow/datapath/linux-2.6/Makefile.in delete mode 100644 openflow/datapath/linux-2.6/Makefile.main.in delete mode 100644 openflow/datapath/linux-2.6/Modules.mk delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/compat26.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/genetlink-brcompat.c delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/genetlink-openflow.c delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/asm-generic/bug.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/dmi.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/icmp.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/if_arp.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/ip.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/ipv6.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/jiffies.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/lockdep.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/mutex.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/netdevice.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/netfilter_bridge.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/netfilter_ipv4.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/netlink.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/random.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/rculist.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/skbuff.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/tcp.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/timer.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/types.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/udp.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/workqueue.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/net/checksum.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/net/genetlink.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/net/netlink.h delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/random32.c delete mode 100644 openflow/datapath/linux-2.6/compat-2.6/veth.c delete mode 100644 openflow/datapath/linux-2.6/config/config-linux-2.6.23-rc9-kvm delete mode 100644 openflow/datapath/openflow-ext.c delete mode 100644 openflow/datapath/openflow-ext.h delete mode 100644 openflow/datapath/private-msg.c delete mode 100644 openflow/datapath/private-msg.h delete mode 100644 openflow/datapath/table-hash.c delete mode 100644 openflow/datapath/table-linear.c delete mode 100644 openflow/datapath/table.h delete mode 100644 openflow/debian/.gitignore delete mode 100644 openflow/debian/changelog delete mode 100755 openflow/debian/commands/reconfigure delete mode 100755 openflow/debian/commands/update delete mode 100644 openflow/debian/compat delete mode 100644 openflow/debian/control.in delete mode 100644 openflow/debian/control.modules.in delete mode 100644 openflow/debian/copyright delete mode 100755 openflow/debian/corekeeper.cron.daily delete mode 100755 openflow/debian/corekeeper.init delete mode 100644 openflow/debian/dirs delete mode 100755 openflow/debian/ofp-switch-setup delete mode 100644 openflow/debian/ofp-switch-setup.8 delete mode 100644 openflow/debian/openflow-common.dirs delete mode 100644 openflow/debian/openflow-common.install delete mode 100644 openflow/debian/openflow-common.manpages delete mode 100644 openflow/debian/openflow-controller.README.Debian delete mode 100644 openflow/debian/openflow-controller.default delete mode 100644 openflow/debian/openflow-controller.dirs delete mode 100755 openflow/debian/openflow-controller.init delete mode 100644 openflow/debian/openflow-controller.install delete mode 100644 openflow/debian/openflow-controller.manpages delete mode 100755 openflow/debian/openflow-controller.postinst delete mode 100755 openflow/debian/openflow-datapath-module-_KVERS_.postinst.modules.in delete mode 100644 openflow/debian/openflow-datapath-source.README.Debian delete mode 100644 openflow/debian/openflow-datapath-source.copyright delete mode 100644 openflow/debian/openflow-datapath-source.dirs delete mode 100644 openflow/debian/openflow-datapath-source.install delete mode 100644 openflow/debian/openflow-pki-server.apache2 delete mode 100644 openflow/debian/openflow-pki-server.dirs delete mode 100644 openflow/debian/openflow-pki-server.install delete mode 100755 openflow/debian/openflow-pki-server.postinst delete mode 100755 openflow/debian/openflow-pki.postinst delete mode 100644 openflow/debian/openflow-switch-config.dirs delete mode 100644 openflow/debian/openflow-switch-config.install delete mode 100644 openflow/debian/openflow-switch-config.manpages delete mode 100644 openflow/debian/openflow-switch-config.overrides delete mode 100644 openflow/debian/openflow-switch-config.templates delete mode 100644 openflow/debian/openflow-switch.README.Debian delete mode 100644 openflow/debian/openflow-switch.dirs delete mode 100755 openflow/debian/openflow-switch.init delete mode 100644 openflow/debian/openflow-switch.install delete mode 100644 openflow/debian/openflow-switch.logrotate delete mode 100644 openflow/debian/openflow-switch.manpages delete mode 100755 openflow/debian/openflow-switch.postinst delete mode 100755 openflow/debian/openflow-switch.postrm delete mode 100644 openflow/debian/openflow-switch.template delete mode 100644 openflow/debian/po/POTFILES.in delete mode 100755 openflow/debian/rules delete mode 100644 openflow/doc/of-spec/.gitignore delete mode 100644 openflow/doc/of-spec/Makefile delete mode 100644 openflow/doc/of-spec/README delete mode 100755 openflow/doc/of-spec/appendix.tex delete mode 100644 openflow/doc/of-spec/credits.tex delete mode 100755 openflow/doc/of-spec/figure_flow_table_secchan.png delete mode 100644 openflow/doc/of-spec/header_parsing_flowchart.graffle delete mode 100755 openflow/doc/of-spec/make_latex_input.pl delete mode 100644 openflow/doc/of-spec/openflow-spec-v1.0.0.tex delete mode 100644 openflow/doc/of-spec/packet_flow_flowchart.graffle delete mode 100644 openflow/hw-lib/automake.mk delete mode 100644 openflow/hw-lib/nf2/README delete mode 100644 openflow/hw-lib/nf2/debug.h delete mode 100644 openflow/hw-lib/nf2/hw_flow.c delete mode 100644 openflow/hw-lib/nf2/hw_flow.h delete mode 100644 openflow/hw-lib/nf2/nf2.h delete mode 100644 openflow/hw-lib/nf2/nf2_drv.c delete mode 100644 openflow/hw-lib/nf2/nf2_drv.h delete mode 100644 openflow/hw-lib/nf2/nf2_lib.c delete mode 100644 openflow/hw-lib/nf2/nf2_lib.h delete mode 100644 openflow/hw-lib/nf2/nf2util.c delete mode 100644 openflow/hw-lib/nf2/nf2util.h delete mode 100644 openflow/hw-lib/nf2/reg_defines_openflow_switch.h delete mode 100644 openflow/hw-lib/skeleton/debug.h delete mode 100644 openflow/hw-lib/skeleton/hw_drv.c delete mode 100644 openflow/hw-lib/skeleton/hw_drv.h delete mode 100644 openflow/hw-lib/skeleton/hw_flow.c delete mode 100644 openflow/hw-lib/skeleton/hw_flow.h delete mode 100644 openflow/hw-lib/skeleton/of_hw_platform.h delete mode 100644 openflow/hw-lib/skeleton/os.h delete mode 100644 openflow/hw-lib/skeleton/port.c delete mode 100644 openflow/hw-lib/skeleton/port.h delete mode 100644 openflow/hw-lib/skeleton/sample_plat.c delete mode 100644 openflow/hw-lib/skeleton/sample_plat.h delete mode 100644 openflow/hw-lib/skeleton/txrx.c delete mode 100644 openflow/hw-lib/skeleton/txrx.h delete mode 100644 openflow/include/.gitignore delete mode 100644 openflow/include/automake.mk delete mode 100644 openflow/include/openflow/automake.mk delete mode 100644 openflow/include/openflow/nicira-ext.h delete mode 100644 openflow/include/openflow/of_hw_api.h delete mode 100644 openflow/include/openflow/openflow-ext.h delete mode 100644 openflow/include/openflow/openflow-netlink.h delete mode 100644 openflow/include/openflow/openflow.h delete mode 100644 openflow/include/openflow/private-ext.h delete mode 100644 openflow/m4/libopenflow.m4 delete mode 100644 openflow/m4/nx-build.m4 delete mode 100644 openflow/regress/CREDITS delete mode 100644 openflow/regress/INSTALL delete mode 100644 openflow/regress/LICENSE delete mode 100644 openflow/regress/README delete mode 100644 openflow/regress/bin/eth.map delete mode 100644 openflow/regress/bin/nf2.map delete mode 100644 openflow/regress/bin/of_hp_eth.map delete mode 100755 openflow/regress/bin/of_hp_setup.pl delete mode 100755 openflow/regress/bin/of_hp_teardown.pl delete mode 100755 openflow/regress/bin/of_hp_test.pl delete mode 100755 openflow/regress/bin/of_hp_test_6600.pl delete mode 100755 openflow/regress/bin/of_kmod_setup.pl delete mode 100755 openflow/regress/bin/of_kmod_teardown.pl delete mode 100755 openflow/regress/bin/of_kmod_test.pl delete mode 100755 openflow/regress/bin/of_kmod_veth_setup.pl delete mode 100755 openflow/regress/bin/of_kmod_veth_teardown.pl delete mode 100755 openflow/regress/bin/of_kmod_veth_test.pl delete mode 100755 openflow/regress/bin/of_nf2_setup.pl delete mode 100755 openflow/regress/bin/of_nf2_teardown.pl delete mode 100755 openflow/regress/bin/of_nf2_test.pl delete mode 100644 openflow/regress/bin/of_ovs_eth.map delete mode 100755 openflow/regress/bin/of_ovs_setup.pl delete mode 100755 openflow/regress/bin/of_ovs_teardown.pl delete mode 100755 openflow/regress/bin/of_ovs_test.pl delete mode 100755 openflow/regress/bin/of_ovs_user_setup.pl delete mode 100755 openflow/regress/bin/of_ovs_user_teardown.pl delete mode 100755 openflow/regress/bin/of_ovs_user_test.pl delete mode 100755 openflow/regress/bin/of_ovs_user_veth_test.pl delete mode 100755 openflow/regress/bin/of_ovs_veth_test.pl delete mode 100755 openflow/regress/bin/of_user_setup.pl delete mode 100755 openflow/regress/bin/of_user_teardown.pl delete mode 100755 openflow/regress/bin/of_user_test.pl delete mode 100755 openflow/regress/bin/of_user_veth_setup.pl delete mode 100755 openflow/regress/bin/of_user_veth_teardown.pl delete mode 100755 openflow/regress/bin/of_user_veth_test.pl delete mode 100644 openflow/regress/bin/veth.map delete mode 100755 openflow/regress/bin/veth_setup.pl delete mode 100755 openflow/regress/bin/veth_teardown.pl delete mode 100755 openflow/regress/projects/black_box/regress/common/setup delete mode 100755 openflow/regress/projects/black_box/regress/common/teardown delete mode 100755 openflow/regress/projects/black_box/regress/test_add_flow_latency/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_barrier/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_cookie_flow_expired/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_cookie_flow_stats/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_delete/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_delete_send_flow_exp/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_delete_strict/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_drop_exact/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_failover_close/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_failover_startup/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_failover_stop_responding/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_flow_expired/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_flow_expired_idle_timeout/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_flow_expired_precision/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_flow_expired_send_flow_exp/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_flow_mod_check/run.pl delete mode 100644 openflow/regress/projects/black_box/regress/test_flow_mod_latency/run-port3.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_flow_mod_latency/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_flow_stats/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_flow_stats_precision/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_after_expiration/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_any_port/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_bandwidth_fixed/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_bandwidth_random/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_broadcast_exact_port/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_all/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_arp_all/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_arp_controller/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_arp_fool/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_arp_port/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_controller/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_icmp_all/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_icmp_controller/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_icmp_fool/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_icmp_port/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_modify_action/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_port/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_overlapping_flow_entries/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_all/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_all/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_controller/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_fool/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_port/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_controller/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_all/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_controller/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_fool/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_port/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_modify_action/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_port/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_hello/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_ip_offset/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_ip_options/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_ip_protocol/case-c.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_ip_protocol/case-d.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_ip_protocol/case-e.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_ip_protocol/case-tcp.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_ip_protocol/case-udp.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_llc/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_miss_send_length/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_packet_in/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_packet_out/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_port_stats/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_queue_config/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_queue_forward/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_queue_stats/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_receive_bandwidth_fixed/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_send_bandwidth_fixed/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_send_bandwidth_random/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_set_dl_nw_flip/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_set_n_match_nw_tos/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_set_nw_dst/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_stats_desc/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_switch_config/run.pl delete mode 100755 openflow/regress/projects/black_box/regress/test_tcp_options/run.pl delete mode 100644 openflow/regress/projects/black_box/regress/tests.txt delete mode 100755 openflow/regress/projects/controller_disconnect/regress/common/setup delete mode 100755 openflow/regress/projects/controller_disconnect/regress/common/teardown delete mode 100755 openflow/regress/projects/controller_disconnect/regress/test_emergency_table/run.pl delete mode 100644 openflow/regress/projects/controller_disconnect/regress/tests.txt delete mode 100755 openflow/regress/projects/learning_switch/regress/common/setup delete mode 100755 openflow/regress/projects/learning_switch/regress/common/teardown delete mode 100755 openflow/regress/projects/learning_switch/regress/test_broadcast/run.pl delete mode 100755 openflow/regress/projects/learning_switch/regress/test_forward_bandwidth/run.pl delete mode 100755 openflow/regress/projects/learning_switch/regress/test_forward_latency/run.pl delete mode 100755 openflow/regress/projects/learning_switch/regress/test_hub_connected/run.pl delete mode 100755 openflow/regress/projects/learning_switch/regress/test_unicast_known/run.pl delete mode 100755 openflow/regress/projects/learning_switch/regress/test_unicast_move/run.pl delete mode 100755 openflow/regress/projects/learning_switch/regress/test_unicast_multiple_hosts/run.pl delete mode 100755 openflow/regress/projects/learning_switch/regress/test_unicast_self/run.pl delete mode 100755 openflow/regress/projects/learning_switch/regress/test_unicast_unknown/run.pl delete mode 100644 openflow/regress/projects/learning_switch/regress/tests.txt delete mode 100644 openflow/regress/projects/regress.txt delete mode 100755 openflow/regress/scripts/copy_NF2_code.sh delete mode 100644 openflow/regress/scripts/env_vars delete mode 100755 openflow/regress/scripts/install_deps.pl delete mode 100755 openflow/regress/scripts/install_perlmods_apt.pl delete mode 100755 openflow/regress/scripts/make_release.pl delete mode 100644 openflow/secchan/.dirstamp delete mode 100644 openflow/secchan/.gitignore delete mode 100644 openflow/secchan/automake.mk delete mode 100644 openflow/secchan/commands/automake.mk delete mode 100755 openflow/secchan/commands/reboot delete mode 100644 openflow/secchan/discovery.c delete mode 100644 openflow/secchan/discovery.h delete mode 100644 openflow/secchan/emerg-flow.c delete mode 100644 openflow/secchan/emerg-flow.h delete mode 100644 openflow/secchan/fail-open.c delete mode 100644 openflow/secchan/fail-open.h delete mode 100644 openflow/secchan/failover.c delete mode 100644 openflow/secchan/failover.h delete mode 100644 openflow/secchan/in-band.c delete mode 100644 openflow/secchan/in-band.h delete mode 100644 openflow/secchan/ofprotocol.8.in delete mode 100644 openflow/secchan/port-watcher.c delete mode 100644 openflow/secchan/port-watcher.h delete mode 100644 openflow/secchan/protocol-stat.c delete mode 100644 openflow/secchan/protocol-stat.h delete mode 100644 openflow/secchan/ratelimit.c delete mode 100644 openflow/secchan/ratelimit.h delete mode 100644 openflow/secchan/secchan.c delete mode 100644 openflow/secchan/secchan.h delete mode 100644 openflow/secchan/status.c delete mode 100644 openflow/secchan/status.h delete mode 100644 openflow/secchan/stp-secchan.c delete mode 100644 openflow/secchan/stp-secchan.h delete mode 100755 openflow/soexpand.pl delete mode 100644 openflow/tests/.dirstamp delete mode 100644 openflow/tests/.gitignore delete mode 100644 openflow/tests/automake.mk delete mode 100755 openflow/tests/flowgen.pl delete mode 100644 openflow/tests/test-dhcp-client.c delete mode 100755 openflow/tests/test-flows delete mode 100644 openflow/tests/test-flows.c delete mode 100755 openflow/tests/test-flows.sh delete mode 100755 openflow/tests/test-hmap delete mode 100644 openflow/tests/test-hmap.c delete mode 100644 openflow/tests/test-list.c delete mode 100644 openflow/tests/test-stp-ieee802.1d-1998 delete mode 100644 openflow/tests/test-stp-ieee802.1d-2004-fig17.4 delete mode 100644 openflow/tests/test-stp-ieee802.1d-2004-fig17.6 delete mode 100644 openflow/tests/test-stp-ieee802.1d-2004-fig17.7 delete mode 100644 openflow/tests/test-stp-iol-io-1.1 delete mode 100644 openflow/tests/test-stp-iol-io-1.2 delete mode 100644 openflow/tests/test-stp-iol-io-1.4 delete mode 100644 openflow/tests/test-stp-iol-io-1.5 delete mode 100644 openflow/tests/test-stp-iol-op-1.1 delete mode 100644 openflow/tests/test-stp-iol-op-1.4 delete mode 100644 openflow/tests/test-stp-iol-op-3.1 delete mode 100644 openflow/tests/test-stp-iol-op-3.3 delete mode 100644 openflow/tests/test-stp-iol-op-3.4 delete mode 100644 openflow/tests/test-stp.c delete mode 100755 openflow/tests/test-stp.sh delete mode 100644 openflow/tests/test-type-props.c delete mode 100644 openflow/third-party/.gitignore delete mode 100644 openflow/third-party/README delete mode 100644 openflow/third-party/automake.mk delete mode 100644 openflow/third-party/ofp-tcpdump.patch delete mode 100644 openflow/udatapath/.dirstamp delete mode 100644 openflow/udatapath/.gitignore delete mode 100644 openflow/udatapath/automake.mk delete mode 100644 openflow/udatapath/chain.c delete mode 100644 openflow/udatapath/chain.h delete mode 100644 openflow/udatapath/crc32.c delete mode 100644 openflow/udatapath/crc32.h delete mode 100644 openflow/udatapath/datapath.c delete mode 100644 openflow/udatapath/datapath.h delete mode 100644 openflow/udatapath/dp_act.c delete mode 100644 openflow/udatapath/dp_act.h delete mode 100644 openflow/udatapath/of_ext_msg.c delete mode 100644 openflow/udatapath/of_ext_msg.h delete mode 100644 openflow/udatapath/ofdatapath.8.in delete mode 100644 openflow/udatapath/private-msg.c delete mode 100644 openflow/udatapath/private-msg.h delete mode 100644 openflow/udatapath/switch-flow.c delete mode 100644 openflow/udatapath/switch-flow.h delete mode 100644 openflow/udatapath/table-hash.c delete mode 100644 openflow/udatapath/table-linear.c delete mode 100644 openflow/udatapath/table.h delete mode 100644 openflow/udatapath/udatapath.c delete mode 100644 openflow/utilities/.dirstamp delete mode 100644 openflow/utilities/.gitignore delete mode 100644 openflow/utilities/automake.mk delete mode 100644 openflow/utilities/dpctl.8.in delete mode 100644 openflow/utilities/dpctl.c delete mode 100644 openflow/utilities/ofp-discover.8.in delete mode 100644 openflow/utilities/ofp-discover.c delete mode 100644 openflow/utilities/ofp-kill.8.in delete mode 100644 openflow/utilities/ofp-kill.c delete mode 100644 openflow/utilities/ofp-parse-leaks delete mode 100755 openflow/utilities/ofp-parse-leaks.in delete mode 100755 openflow/utilities/ofp-pki-cgi.in delete mode 100644 openflow/utilities/ofp-pki.8.in delete mode 100755 openflow/utilities/ofp-pki.in delete mode 100644 openflow/utilities/vlogconf.8.in delete mode 100644 openflow/utilities/vlogconf.c delete mode 100644 openflow/utilities/wireshark_dissectors/Makefile delete mode 100644 openflow/utilities/wireshark_dissectors/README delete mode 100644 openflow/utilities/wireshark_dissectors/openflow/.gitignore delete mode 100644 openflow/utilities/wireshark_dissectors/openflow/Makefile delete mode 100644 openflow/utilities/wireshark_dissectors/openflow/Makefile.am delete mode 100644 openflow/utilities/wireshark_dissectors/openflow/Makefile.common delete mode 100755 openflow/utilities/wireshark_dissectors/openflow/build_distribution_tarball.sh delete mode 100644 openflow/utilities/wireshark_dissectors/openflow/moduleinfo.h delete mode 100644 openflow/utilities/wireshark_dissectors/openflow/packet-openflow.c delete mode 100644 openflow/utilities/wireshark_dissectors/openflow/plugin.c delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/airpcap.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/airpcap_loader.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/alert_box.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-pcap-util-int.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-pcap-util.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-wpcap.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_errs.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_info.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_opts.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_stop_conditions.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_sync.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_ui_utils.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_wpcap_packet.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/cfile.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/clopts_common.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/cmdarg_err.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/color.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/color_filters.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/conditions.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h.in delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h.win32 delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/disabled_protos.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/addr_and_mask.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/addr_resolv.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/address.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/adler32.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/afn.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/aftypes.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/arcnet_pids.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/arptypes.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/asm_utils.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/asn1.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/atalk-utils.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/base64.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/bitswap.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/bridged_pids.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/camel-persistentdata.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/charsets.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/chdlctypes.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/circuit.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/codecs.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column-utils.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column_info.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/conversation.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc10.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc16.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc32.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc6.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crcdrm.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_debug.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_int.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_interop.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_rijndael.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_system.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_user.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_ws.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-des.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-md4.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-md5.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-rc4.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-sha1.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/wep-wpadefs.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter-int.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter-macro.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfunctions.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfvm.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/drange.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/gencode.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/glib-util.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/grammar.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/scanner_lex.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/semcheck.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-function.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-range.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-test.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/syntax-tree.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/diam_dict.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/diam_dict_lex.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dissector_filters.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dissectors/packet-tcp.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_grammar.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_parse.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_parse_lex.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_preparse_lex.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/eap.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/emem.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/epan.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/epan_dissect.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/etypes.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ex-opt.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/except.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/exceptions.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/expert.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/filesystem.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/follow.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/frame_data.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/frequency-utils.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ftypes/ftypes-int.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ftypes/ftypes.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/funnel.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/g_ascii_strcasecmp.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/g_ascii_strtoull.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/garrayfix.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/gcp.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/gnuc_format_check.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/golay.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/greproto.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/guid-utils.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/h225-persistentdata.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/iax2_codec_type.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/in_cksum.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/inet_aton.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ip_opts.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipproto.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipv4.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipv6-utils.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/lapd_sapi.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/llcsaps.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/next_tvb.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/nlpid.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/nstime.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/oids.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/osi-utils.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/oui.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/packet.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/packet_info.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/pint.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/plugins.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ppptypes.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/prefs-int.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/prefs.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/privileges.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/proto.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ptvcursor.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/radius_dict_lex.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/range.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/reassemble.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/reedsolomon.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/report_err.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/req_resp_hdrs.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/rtp_pt.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sctpppids.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sigcomp-udvm.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sigcomp_state_hdlr.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/slab.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sminmpec.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sna-utils.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stat_cmd_args.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stats_tree.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stats_tree_priv.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stream.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/strutil.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/t35.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tap-voip.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tap.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tcap-persistentdata.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tfs.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/timestamp.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/to_str.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tvbparse.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tvbuff.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat-int.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat_load_lex.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/unicode-utils.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/value_string.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ws_strsplit.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/wslua/declare_wslua.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/wslua/wslua.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/x264_prt_id.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/xdlc.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/xmlstub.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/file.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/fileset.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/filters.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/g711.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/getopt.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/globals.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/inet_v6defs.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/isprint.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/log.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/main_window.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/menu.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/merge.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/mkstemp.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/packet-range.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/pcapio.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/print.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/progress_dlg.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/proto_hier_stats.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ps.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/register.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ringbuffer.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/simple_dialog.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/stat_menu.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/statusbar.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/strerror.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/strptime.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/summary.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/svnversion.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/sync_pipe.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tap-rtp-common.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tap_dfilter_dlg.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tempfile.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/text2pcap.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/timestats.h delete mode 100755 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tools/make-dissector-reg delete mode 100755 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tools/make-dissector-reg.py delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ui_util.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/util.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/version_info.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/5views.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/airopeek9.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-grammar.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-int.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-scanner_lex.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/atm.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ber.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/btsnoop.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/buffer.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/catapult_dct2000.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/commview.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/cosine.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/csids.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/dbs-etherwatch.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/erf.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/etherpeek.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/eyesdn.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/file_util.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/file_wrappers.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/hcidump.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/i4b_trace.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/i4btrace.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/iptrace.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/iseries.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/k12.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/k12text_lex.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/lanalyzer.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/libpcap.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/mpeg-audio.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/mpeg.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netmon.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netscreen.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/nettl.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/network_instruments.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netxray.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ngsniffer.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/pcapng.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/pppdump.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/radcom.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/snoop.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/toshiba.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/visual.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/vms.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/wtap-int.h delete mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/wtap.h diff --git a/openflow/.gitignore b/openflow/.gitignore deleted file mode 100644 index be6113cd..00000000 --- a/openflow/.gitignore +++ /dev/null @@ -1,44 +0,0 @@ -#*# -*.a -*.d -*.ko -*.la -*.lo -*.loT -*.mod.c -*.o -*.o -*.pyc -*.so -*~ -.#* -.*.cmd -.deps -.libs -.tmp_versions -/Makefile -/Makefile.in -/aclocal.m4 -/autom4te.cache -/build-arch-stamp -/build-aux -/build-indep-stamp -/compile -/config.guess -/config.h -/config.h.in -/config.log -/config.status -/config.sub -/configure -/configure-stamp -/depcomp -/install-sh -/missing -/stamp-h1 -Module.symvers -TAGS -cscope.* -ext.m4 -ext.mk -tags diff --git a/openflow/COPYING b/openflow/COPYING deleted file mode 100644 index ab5f3705..00000000 --- a/openflow/COPYING +++ /dev/null @@ -1,1054 +0,0 @@ -Source file copyrights are indicated at the top of each file. - -Files not in the datapath/ and vswitchd/ directories or associated -subdirectories are covered under the OpenFlow license included below: - -We are making the OpenFlow specification and associated documentation -(Software) available for public use and benefit with the expectation -that others will use, modify and enhance the Software and contribute -those enhancements back to the community. However, since we would like -to make the Software available for broadest use, with as few -restrictions as possible permission is hereby granted, free of charge, -to any person obtaining a copy of this Software to deal in the Software -under the copyrights without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -The name and trademarks of copyright holder(s) may NOT be used in -advertising or publicity pertaining to the Software or any derivatives -without specific, written prior permission. - -Files in the datapath/ and its sub-directories are covered under the GNU -General Public License Version 2. Included below: - - - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. - -Files in vswitchd/ and its sub-directories are covered under the GNU -General Public License Version 3. Included below: - - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/openflow/ChangeLog b/openflow/ChangeLog deleted file mode 100644 index c2d4b49a..00000000 --- a/openflow/ChangeLog +++ /dev/null @@ -1,202 +0,0 @@ -1.0.0-rev1 - XX XXX 2010 ------------------------- - - Changes to regression suite: - - Added testing support for Open vSwitch - - Updated HP-ProCurve scripts - - Minor fixes applied to libraries - - Fixes applied to the following tests: - test_switch_config, test_forward_broadcast_exact_port, - test_set_n_match_nw_tos, test_set_nw_dst, - test_failover_startup - - Added test to verify flipping of src/dst MAC and IP - - Ability to disable slicing, VLAN, and barrier in tests - - Can easily run a single test - For more information, see regress/README - -1.0.0 - 31 Dec 2009 -------------------- - - Fixed Wireshark plugin warnings - - Clarified purpose of actions field in ofp_switch_features in spec - - Known issues: - - isolation provided by the slicing mechanism has been - observed to degrade when run on systems with low performance CPUs. - Investigations are underway to improve isolation on such systems. - -1.0.0-RC1 - 19 Dec 2009 ------------------------ - - Changed wire protocol version to 0x01 - - Added slicing support - - Improved resolution of flow duration in stats/expiry - - Added flow cookies to flows - - Enable matching on IP fields inside ARP packets - - Enable port stats to be retrieved for individual ports - - Added ability to match on IP ToS bits - - Added datapath description to desc stats - - Added ability to control slicing queues from dpctl - - Set datapath description from dpctl - - Removed kernel datapath from reference switch - (will be release separately) - - Fix bug related to identifying overlapping flows - - Updated Wireshark dissector to support 1.0.0 features - - Added regression tests for ARP handling, flow cookies, slicing, - selective port stats, flow duration precision, matching on ToS bits, and - the datapath description - - Known issues: - - isolation provided by the slicing mechanism has been - observed to degrade when run on systems with low performance CPUs. - Investigations are underway to improve isolation on such systems. - -0.9.0-rev1 - 04 Sep 2009 ------------------------- - - Added NetFPGA hardware table support (wire protocol 0x98) - - Fixed a few userspace datapath bugs - -0.9.0 - 20 Jul 2009 -------------------- - - Changed wire protocol version to 0x98 - - Removed monolithic switch process called switch - - Added userspace data plane process named ofdatapath - - Changed userspace control plane process name to ofprotocol - - Changed kernelspace data plane extension name to ofdatapath.ko - - Changed NetFPGA kernelspace extestion name to ofdatapath_netfpga.ko - - Removed Linux 2.4 kerel support - - Added simple controller failover feature - - Added emergency flow cache feature - - Added barrier command - - Added 802.1Q VLAN priority bits match feature - - Clarified flow expiration, renamed flow expiration to flow removed - - Added protocol statistics collector - - Added IP ToS/DSCP rewrite feature - - Changed port enumeration at 1 instead of 0 - - Clarified emergeency flow cache behavior - - Clarified definition of datapath ID - - Clarified meaning of a zero-size miss_send_len - - Clarified meaning of a zero-size max_len in output action - - Changed protocol structure alignment to ensure 64-bit - -v0.8.9 r2 - 23 Jan 2009 ------------------------ - - Added NetFPGA hardware table support (wire protocol 0x97) - - Added regression tests on port_stats, flow_stats, drop, ICMP handling - - Bug fixes - -v0.8.9~1 - 01 Dec 2008 ----------------------- - - Added support for IP netmasks - - Added new physical port stats - - Added IN_PORT virtual port - - Added echo request/response - - Added detection of link and port status changes - - Added ability to configure port status from controller - - Added support for vendor extensions - - Added support for variable length actions - - Added support for matching ICMP type and code - - Added support for listing and deleting flows based on output port action - - Added support for modifying VLAN priority tag - - Increased max supported ports to 65280 - - More explicit handling for IP fragments - - Added support for 802.1D spanning tree - - Added OFPFC_MODIFY command to Flow Mod message - - Provided more flexible description of tables to controller - - Make port modification more explicit - - Made Packet Out message more consistent - - Added hard timeout value to Flow Mod message - - Added reason field for Flow Expired message - - Reworked initial handshake to support backwards compatibility - - Added OFPST_DESC stat for returning description of hw/sw - - Added support for loadable hardware table support modules** - - In-band control now supported** - - 802.1D spanning tree support** - - Automatic controller discovery (via DHCP) now supported** - - Improved support for older 2.6.x kernels** - - Switch can now "fail open" as a MAC-learning switch if the controller cannot be contacted** - - Debian packages may now be built** - - Fixed bugs in SSL support - - Most programs now take --detach and --pidfile options to run as daemon - - Numerous bug fixes - - ** Only supported in the kernel module for the time-being. - -v0.8.1 - 14 May 2008 --------------------- - - No longer set nwsrc/nwdst fields in flow structs on ARP packets - - Various bug fixes and tweaks - -v0.8.0 - 04 May 2008 --------------------- - - Added support for flow entry priorities - - Added support for all stats messages - - Added support for OFPP_TABLE virtual port - - Removed MAC tables - - Various bug fixes and tweaks - -v0.2.1 - 28 Mar 2008 --------------------- - - Fixed build problem when SSL enabled - -v0.2.0 - 28 Mar 2008 --------------------- - - Added userspace switch reference implementation - -v0.1.9 - 19 Mar 2008 --------------------- - - Added SSL/TLS support - - Various bug fixes and tweaks - -v0.1.8 - 03 Mar 2008 --------------------- - - Added support for cross-compilation - - Various bug fixes and tweaks - -v0.1.7 - 07 Feb 2008 --------------------- - - Allow permanent flow entries to be set - - Added patch for tcpdump that allows parsing of OpenFlow messages - - Various bug fixes and tweaks - -v0.1.6 - 05 Feb 2008 --------------------- - - Added support for Linux 2.6.24 - - Set nwsrc/nwdst fields in flow structs on ARP packets - - Various bug fixes and tweaks - -v0.1.5 - 17 Jan 2008 --------------------- - - Added support for Linux 2.4.20 - - Added support for GCC 2.95 - -v0.1.4 - 15 Jan 2008 --------------------- - - Decode and print port_status messages - - Fixed build problems on big-endian systems - - Fixed compatibility for older 2.6 kernels - - Various bug fixes and tweaks - -v0.1.3 - 08 Jan 2008 --------------------- - - Added support for flow expiration messages - - Decode and print all datapath-generated messages in dpctl's "monitor" - - Added "--noflow" option to controller - - Various bug fixes and tweaks - -v0.1.2 - 07 Jan 2008 --------------------- - - Fixed distribution to include ofp_pcap.h - - Removed autoconf C++ checks - -v0.1.1 - 18 Dec 2007 --------------------- - - Fixed support for Linux 2.4.35 and 2.6.22 - - Added support for Linux 2.6.15 - - Added "vlogconf" utility to modify logging configuration - - Added better support for SNAP headers - - Improved printing of flow information in dpctl - - Made kernel code consistently use tabs instead of spaces - - Removed libpcap requirement for building - - Various bug fixes and tweaks - -v0.1.0 - 30 Nov 2007 --------------------- - - Initial release diff --git a/openflow/INSTALL b/openflow/INSTALL deleted file mode 100644 index f236e16a..00000000 --- a/openflow/INSTALL +++ /dev/null @@ -1,513 +0,0 @@ - Installation Instructions for OpenFlow Reference Release - -This document describes how to build, install, and execute the -reference implementation of OpenFlow. Please send any comments to: - - - -Contents -======== - -The OpenFlow reference implementation includes one OpenFlow switch -implementations: - - - The "userspace datapath-based switch": This divides the switch - into a userspace "datapath" (built as udatapath/ofdatapath) - and a userspace program that implements the secure channel - component (ofprotocol). The userspace datapath-based switch - does not require building a kernel module, but it is not as - fast as a kernel-based switch. - -The reference implementation also contains a simple OpenFlow -controller (built as controller/controller) and a number of related -utilities. - -Build Methods -============= - -There are two principal ways to build and install this distribution: - - - Using "configure" and "make" in the ordinary way. See - Building Conventionally below for detailed instructions. - - - As a set of Debian packages. Refer to Building Debian - Packages, below, for instructions. - -Base Prerequisites ------------------- - -Regardless of how it is built, OpenFlow has a common set of -prerequisites. To compile the userspace programs in the OpenFlow -reference distribution, you will need the following software: - - - A make program, e.g. GNU make - (http://www.gnu.org/software/make/). BSD make should also work. - - - The GNU C compiler (http://gcc.gnu.org/). We generally test - with version 4.1 or 4.2. - - - libssl, from OpenSSL (http://www.openssl.org/), is optional but - recommended. libssl is required to establish confidentiality - and authenticity in the connections among OpenFlow switches and - controllers. To enable, configure with --enable-ssl=yes. - -If you are working from a Git tree or snapshot (instead of from a -distribution tarball), or if you modify the OpenFlow build system, you -will also need the following software: - - - Autoconf version 2.60 or later (http://www.gnu.org/software/autoconf). - - - Automake version 1.10 or later (http://www.gnu.org/software/automake). - - - pkg-config (http://pkg-config.freedesktop.org/wiki/). We test - with version 0.22. - -Debian Prerequisites --------------------- - -To build Debian packages from the OpenFlow distribution, you will need -to install a number of Debian packages in addition to the base -prerequisites listed above. These additional prerequisites may be -found listed as "Build-Depends" in debian/control in the source tree. -To check that they are installed, first install the dpkg-dev package, -then run dpkg-checkbuilddeps from the top level of the OpenFlow source -tree. - -To build Debian packages without being root, also install the -"fakeroot" package. - -Userspace Switch Prerequisites ---------------------------------- - - - To enable slicing support, "tc" frontend should be installed - (from iproute2, part of all major distributions, - http://www.linux-foundation.org/en/Net:Iproute2). - You also need to enable the following kernel configuration - options under the QoS and/or Fair queueing section : - CONFIG_NET_SCHED,CONFIG_NET_SCH_HTB (already configured that - way in most distributions). - (NOTE: You can disable slicing (and these dependencies) at runtime - using the --no-slicing option) - -Building Conventionally -======================= - -This section explains how to build and install the OpenFlow -distribution in the ordinary way using "configure" and "make". - -0. Check that you have installed all the prerequisites listed above in - the Base Prerequisites section. Run `boot.sh` if necessary to create - the configure script. - - % ./boot.sh - -1. In the top source directory, configure the package by running the - configure script. You can usually invoke configure without any - arguments: - - % ./configure - - To use a specific C compiler for compiling OpenFlow user programs, - also specify it on the configure command line, like so: - - % ./configure CC=gcc-4.2 - - If you have hardware that supports accelerated OpenFlow switching - and you have obtained a hardware table library for your hardware - and extracted it into the OpenFlow reference distribution source - tree, then you may also enable building support for the hardware - switch table with --enable-hw-lib. For more information, read - README.hwtables at the root of the OpenFlow distribution tree. - - The configure script accepts a number of other options and honors - additional environment variables. For a full list, invoke - configure with the --help option. - -2. Run make in the top source directory: - - % make - - The following binaries will be built: - - - Userspace datapath: udatapath/ofdatapath. - - - Secure channel executable: secchan/ofprotocol. - - - Controller executable: controller/controller. - - - Datapath administration utility: utilities/dpctl. - - - Runtime logging configuration utility: utilities/vlogconf. - - - Miscellaneous utilities: utilities/ofp-discover, - utilities/ofp-kill. - - - Tests: various binaries in tests/. - - If your distribution includes the OpenFlow extensions, the - following additional binaries will be built: - - - ANSI terminal support for EZIO 16x2 LCD panel: - ext/ezio/ezio-term. - - - Switch monitoring UI for small text displays: - ext/ezio/ofp-switchui. - -3. Run "make install" to install the executables and manpages into the - running system, by default under /usr/local. - -4. Test the userspace programs, as described under Testing Userspace - Programs below. - -Building Debian Packages -======================== - -Follow these instructions to build Debian packages for OpenFlow. - -0. Check that you have installed all the prerequisites listed above in - the Base Prerequisites and Debian Prerequisites sections above. - -1. In the top source directory, run the following command, as root: - - % dpkg-buildpackage - - Alternatively, if you installed the "fakeroot" package, you may run - dpkg-buildpackage as an ordinary user with the following syntax: - - % dpkg-buildpackage -rfakeroot - - The following packages will be built in the directory above the - source tree: - - - openflow-controller: The OpenFlow controller. Depends on - openflow-pki (see below). - - - openflow-switch: Install this package on a machine that acts - as an OpenFlow kernel switch. - - - openflow-datapath-source: Source code for OpenFlow's Linux - kernel module. - - - openflow-pki: Public-key infrastructure for OpenFlow. Install - this package on a machine that acts as an OpenFlow PKI server - (see "Establishing a Public Key Infrastructure" below). - - - openflow-common: Files and utilities required by more than one - of the above packages. - -2. To set up an OpenFlow controller, install the openflow-controller - package and its dependencies. You may configure it by editing - /etc/default/openflow-controller, e.g. to enable non-SSL - connections, which are disabled by default. If you change the - default settings, you will need to restart the controller by - running: - - % /etc/init.d/openflow-controller restart - -3. To set up an OpenFlow switch, install the openflow-switch package - and its dependencies. If it is to be a kernel-based switch, also - install openflow-datapath-source, then follow the instructions in - /usr/share/doc/openflow-datapath-source/README.Debian to build and - install the kernel module. - - You may configure the switch one of the following ways: - - - Completely by hand, as described under the Testing section - below. - - For the userspace datapath-based switch, this is the only - supported form of configuration. - - - By editing /etc/default/openflow-switch. You must at least - configure some network devices, by uncommenting NETDEVS and - adding the appropriate devices to the list, e.g. NETDEVS="eth0 - eth1". - - After you edit this file, you will need to start the switch by - running: - - % /etc/init.d/openflow-switch restart - - This form of configuration is not supported for the userspace - datapath-based switch. - - - By running the ofp-switch-setup program. This interactive - program will walk you through all the steps of configuring an - OpenFlow switch, including configuration of SSL certificates. - Run it without arguments, as root: - - % ofp-switch-setup - - This form of configuration is not supported for the userspace - datapath-based switch. - -Testing -======= - -The following sets of instructions show how to use the OpenFlow -reference implementation as a switch on a single machine. This can be -used to verify that the distribution built properly. For full -installation instructions, refer to the Installation section below. - -Userspace Datapath ------------------- - -These instructions use the OpenFlow userspace datapath ("ofdatapath"). - -1. Start the OpenFlow controller running in the background, by running - the "controller" program with a command like the following: - - # controller punix:/var/run/controller.sock & - - This command causes the controller to bind to the specified Unix - domain socket, awaiting connections from OpenFlow switches. See - controller(8) for details. - - The "controller" program does not require any special privilege, so - you do not need to run it as root. - -2. The commands below must run as root, so log in as root, or use a - program such as "su" to become root temporarily. - -3. Create a datapath instance running in the background. The command - below creates a datapath that listens for connections from ofprotocol - on a Unix domain socket located in /var/run and services physical - ports eth1 and eth2: - - # ofdatapath punix:/var/run/dp0.sock -i eth1,eth2 & - -4. Run ofprotocol to start the secure channel connecting the datapath and - the controller: - - # ofprotocol unix:/var/run/controller.sock unix:/var/run/dp0.sock & - -5. Devices plugged into the network ports specified in step 2 should - now be able to send packets to each other, as if they were plugged - into ports on a conventional Ethernet switch. - -Installation -============ - -This section explains how to install OpenFlow in a network with one -controller and one or more switches, each of which runs on a separate -machine. Before you begin, you must decide on one of two ways for -each switch to reach the controller over the network: - - - Use a "control network" that is completely separate from the - "data network" to be controlled ("out-of-band control"). The - location of the controller must be configured manually in this - case. - - - Use the same network for control and for data ("in-band - control"). When in-band control is used, the location of the - controller may be configured manually or discovered - automatically. We will assume manual configuration here; - please refer to ofprotocol(8) for instructions on setting up - controller discovery. - -Controller Setup ----------------- - -On the machine that is to be the OpenFlow controller, start the -"controller" program listening for connections from switches on TCP -port 6633 (the default), as shown below. - - # controller -v ptcp: - -(See controller(8) for more details) - -Make sure the machine hosting the controller is reachable by the -switch. - -Userspace Datapath-Based Setup ------------------------------- - -On a machine that is to host an OpenFlow userspace datapath-based -switch, follow the procedure below. - -0. The commands below must run as root, so log in as root, or use a - program such as "su" to become root temporarily. - -1. Create a datapath instance running in the background. The command - below creates a datapath that listens for connections from ofprotocol - on a Unix domain socket located in /var/run, services physical - ports eth1 and eth2, and creates a TAP network device named "tap0" - for use in in-band control: - - # ofdatapath punix:/var/run/dp0.sock -i eth1,eth2 --local-port=tap:tap0 & - - (See ofdatapath(8) for details.) - - If the switch will connect to the controller out-of-band, then the - --local-port option may be omitted, or --no-local-port may be - substituted. - -3. Arrange so that the switch can reach the controller over the - network. - - - If you are using out-of-band control, at this point make sure - that the switch machine can reach the controller over the - network. - - - If you are using in-band control with manual configuration, at - this point the TAP network device created in step 1 is not - bridged to any physical network, so the next step depends on - whether connectivity is required to configure the device's IP - address: - - * If the switch has a static IP address, you may configure - its IP address now, e.g.: - - # ifconfig tap0 192.168.1.1 - - * If the switch does not have a static IP address, e.g. its - IP address is obtained dynamically via DHCP, then proceed - to step 4. The DHCP client will not be able to contact - the DHCP server until the secure channel has started up. - - - If you are using in-band control with controller discovery, no - configuration is required at this point. You may proceed to - step 4. - -4. Run ofprotocol to start the secure channel connecting the datapath to - a remote controller. If the controller is running on host - 192.168.1.2 port 6633 (the default port), the ofprotocol invocation - would look like this: - - # ofprotocol unix:/var/run/dp0.sock tcp:192.168.1.2 - - - If you are using in-band control with controller discovery, omit - the second argument to the ofprotocol command. - - - If you are using out-of-band control, add --out-of-band to the - command line. - -5. If you are using in-band control with manual configuration, and the - switch obtains its IP address dynamically, then you may now obtain - the switch's IP address, e.g. by invoking a DHCP client. The - secure channel will only be able to connect to the controller after - an IP address has been obtained. - -6. The secure channel should connect to the controller within a few - seconds. It may take a little longer if controller discovery is in - use, because the switch must then also obtain its own IP address - and the controller's location via DHCP. - -Configuration -============= - -Secure operation over SSL -------------------------- - -The instructions above set up OpenFlow for operation over a plaintext -TCP connection. Production use of OpenFlow should use SSL[*] to -ensure confidentiality and authenticity of traffic among switches and -controllers. The source must be configured with --enable-ssl=yes to -build with SSL support. - -To use SSL with OpenFlow, you must set up a public-key infrastructure -(PKI) including a pair of certificate authorities (CAs), one for -controllers and one for switches. If you have an established PKI, -OpenFlow can use it directly. Otherwise, refer to "Establishing a -Public Key Infrastructure" below. - -To configure the controller to listen for SSL connections on port 6633 -(the default), invoke it as follows: - - # controller -v pssl: --private-key=PRIVKEY --certificate=CERT \ - --ca-cert=CACERT - -where PRIVKEY is a file containing the controller's private key, CERT -is a file containing the controller CA's certificate for the -controller's public key, and CACERT is a file containing the root -certificate for the switch CA. If, for example, your PKI was created -with the instructions below, then the invocation would look like: - - # controller -v pssl: --private-key=ctl-privkey.pem \ - --certificate=ctl-cert.pem --ca-cert=pki/switchca/cacert.pem - -To configure a switch to connect to a controller running on port 6633 -(the default) on host 192.168.1.2 over SSL, invoke ofprotocol as follows: - - # ofprotocol -v DATAPATH ssl:192.168.1.2 --private-key=PRIVKEY \ - --certificate=CERT --ca-cert=CACERT - -where DATAPATH is the datapath to connect to (e.g. nl:0 or -unix:/var/run/dp0.sock), PRIVKEY is a file containing the switch's -private key, CERT is a file containing the switch CA's certificate for -the switch's public key, and CACERT is a file containing the root -certificate for the controller CA. If, for example, your PKI was -created with the instructions below, then the invocation would look -like: - - # ofprotocol -v DATAPATH ssl:192.168.1.2 --private-key=sc-privkey.pem \ - --certificate=sc-cert.pem --ca-cert=pki/controllerca/cacert.pem - -[*] To be specific, OpenFlow uses TLS version 1.0 or later (TLSv1), as - specified by RFC 2246, which is very similar to SSL version 3.0. - TLSv1 was released in January 1999, so all current software and - hardware should implement it. - -Establishing a Public Key Infrastructure ----------------------------------------- - -If you do not have a PKI, the ofp-pki script included with OpenFlow -can help. To create an initial PKI structure, invoke it as: - % ofp-pki init -which will create and populate a new PKI directory. The default -location for the PKI directory depends on how the OpenFlow tree was -configured (to see the configured default, look for the --dir option -description in the output of "ofp-pki --help"). - -The pki directory contains two important subdirectories. The -controllerca subdirectory contains controller certificate authority -related files, including the following: - - - cacert.pem: Root certificate for the controller certificate - authority. This file must be provided to ofprotocol with the - --ca-cert option to enable it to authenticate valid controllers. - - - private/cakey.pem: Private signing key for the controller - certificate authority. This file must be kept secret. There is - no need for switches or controllers to have a copy of it. - -The switchca subdirectory contains switch certificate authority -related files, analogous to those in the controllerca subdirectory: - - - cacert.pem: Root certificate for the switch certificate - authority. This file must be provided to the controller program - with the --ca-cert option to enable it to authenticate valid - switches. - - - private/cakey.pem: Private signing key for the switch - certificate authority. This file must be kept secret. There is - no need for switches or controllers to have a copy of it. - -After you create the initial structure, you can create keys and -certificates for switches and controllers with ofp-pki. To create a -controller private key and certificate in files named ctl-privkey.pem -and ctl-cert.pem, for example, you could run: - % ofp-pki req+sign ctl controller -ctl-privkey.pem and ctl-cert.pem would need to be copied to the -controller for its use at runtime (they could then be deleted from -their original locations). The --private-key and --certificate -options of controller, respectively, would point to these files. - -Analogously, to create a switch private key and certificate in files -named sc-privkey.pem and sc-cert.pem, for example, you could run: - % ofp-pki req+sign sc switch -sc-privkey.pem and sc-cert.pem would need to be copied to the switch -for its use at runtime (they could then be deleted from their original -locations). The --private-key and --certificate options, -respectively, of ofprotocol would point to these files. - -Bug Reporting -------------- - -Please report problems to: - -openflow-discuss@openflowswitch.org - -or post them to our online bug tracking system at: - -http://www.openflowswitch.org/bugs/openflow diff --git a/openflow/Makefile.am b/openflow/Makefile.am deleted file mode 100644 index 97ac1f01..00000000 --- a/openflow/Makefile.am +++ /dev/null @@ -1,68 +0,0 @@ -# The goal of -Wno-syntax here is just to suppress the Automake warning -# about overriding distdir, below. -AUTOMAKE_OPTIONS = foreign -Wno-syntax subdir-objects -ACLOCAL_AMFLAGS = -I m4 -#SUBDIRS = datapath -SUBDIRS = - -if HAVE_DPKG_BUILDPACKAGE -distcheck-hook: - cd $(srcdir) && dpkg-buildpackage -rfakeroot -us -uc - cd $(srcdir) && fakeroot ./debian/rules clean -else -distcheck-hook: -endif - -AM_CPPFLAGS = $(SSL_CFLAGS) -g -AM_CPPFLAGS += -I $(top_srcdir)/include -AM_CPPFLAGS += -I $(top_srcdir)/lib - -AM_CFLAGS = -Wstrict-prototypes - -if NDEBUG -AM_CPPFLAGS += -DNDEBUG -AM_CFLAGS += -fomit-frame-pointer -else -AM_LDFLAGS = -export-dynamic -endif - -CLEANFILES = -DISTCLEANFILES = -EXTRA_DIST = -TESTS = -TESTS_ENVIRONMENT = -bin_PROGRAMS = -bin_SCRIPTS = -dist_commands_DATA = -dist_man_MANS = -dist_pkgdata_SCRIPTS = -dist_sbin_SCRIPTS = -man_MANS = -noinst_HEADERS = -noinst_LIBRARIES = -noinst_PROGRAMS = -noinst_SCRIPTS = - -EXTRA_DIST += README.hwtables soexpand.pl regress - -ro_c = echo '/* -*- mode: c; buffer-read-only: t -*- */' - -SUFFIXES = .in -.in: - $(PERL) $(srcdir)/soexpand.pl -I$(srcdir) < $< | \ - sed -e 's,[@]LOGDIR[@],$(LOGDIR),g' \ - -e 's,[@]PKIDIR[@],$(PKIDIR),g' \ - -e 's,[@]RUNDIR[@],$(RUNDIR),g' \ - -e 's,[@]pkgdatadir[@],$(pkgdatadir),g' \ - -e 's,[@]PERL[@],$(PERL),g' > $@ - -include lib/automake.mk -include secchan/automake.mk -include controller/automake.mk -include utilities/automake.mk -include udatapath/automake.mk -include tests/automake.mk -include include/automake.mk -include third-party/automake.mk -include debian/automake.mk -include hw-lib/automake.mk diff --git a/openflow/README b/openflow/README deleted file mode 100644 index a9cca172..00000000 --- a/openflow/README +++ /dev/null @@ -1,110 +0,0 @@ - OpenFlow Reference Release - -What is OpenFlow? ------------------ - -OpenFlow is a flow-based switch specification designed to enable -researchers to run experiments in live networks. OpenFlow is based on a -simple Ethernet flow switch that exposes a standardized interface for -adding and removing flow entries. - -An OpenFlow switch consists of three parts: (1) A "flow table" in -which each flow entry is associated with an action telling the switch -how to process the flow, (2) a "secure channel" connecting the switch -to a remote process (a controller), allowing commands and packets to -be sent between the controller and the switch, and (3) an OpenFlow -protocol implementation, providing an open and standard way for a -controller to talk to the switch. - -An OpenFlow switch can thus serve as a simple datapath element that -forwards packets between ports according to flow actions defined by -the controller using OpenFlow commands. Example actions are: - - - Forward this flow's packets to the given port(s) - - Drop this flow's packets - - Encapsulate and forward this flow's packets to the controller. - -The OpenFlow switch is defined in detail in the OpenFlow switch -Specification [2]. - -What's here? ------------- - -This distribution includes one reference implementations of an -OpenFlow switch. This implementation has the following components: - - - ofdatapath, which implements the flow table in user space. - - - ofprotocol, a program that implements the secure channel - component of the reference switch. - - - dpctl, a tool for configuring the switch. - -This distribution includes some additional software as well: - - - controller, a simple program that connects to any number of - OpenFlow switches, commanding them to act as regular MAC - learning switches. - - - vlogconf, a utility that can adjust the logging levels of a - running ofprotocol or controller. - - - ofp-pki, a utility for creating and managing the public-key - infrastructure for OpenFlow switches. - - - A patch to tcpdump that enables it to parse OpenFlow - messages. - - - A regression suite that tests OpenFlow functionality, please - see regress/README. - - - A Wireshark dissector that can decode the OpenFlow wire - protocol. Please see utilities/wireshark_dissectors/README. - -For installation instructions, read INSTALL. Each userspace program -is also accompanied by a manpage. - -What's NOT here? ----------------- - -The reference implementation no longer includes the Linux kernel module -or the NetFPGA implementation. The OpenFlow consortium intends to -release these separately from the reference design. - -Platform support ----------------- - -Other than the userspace switch implementation, the software in the -OpenFlow distribution should compile under Unix-like environments such -as Linux, FreeBSD, Mac OS X, and Solaris. Our primary test environment -is Debian GNU/Linux. Please contact us with portability-related bug -reports or patches. - -The userspace datapath implementation should be easy to port to -Unix-like systems. The interface to network devices, in netdev.c, is -the code most likely to need changes. So far, only Linux is -supported. We welcome ports to other platforms. - -GCC is the expected compiler. - -Bugs/Shortcomings ------------------ - -- The flow table does not support the "normal processing" action. - -References ----------- - - [1] OpenFlow: Enabling Innovation in College Networks. Whitepaper. - - - [2] OpenFlow Switch Specification. - - -Contact -------- - -Public discussion list: openflow-discuss@openflowswitch.org -Direct e-mail: info@openflowswitch.org - -Web: http://openflowswitch.org/ diff --git a/openflow/README.hwtables b/openflow/README.hwtables deleted file mode 100644 index 6d982507..00000000 --- a/openflow/README.hwtables +++ /dev/null @@ -1,39 +0,0 @@ -Hardware Table Support -*- text -*- ----------------------- - -The OpenFlow reference implementation in this distribution provides a -mechanism to support hardware that can accelerate OpenFlow switching. -The mechanism consists of the ability to add a "hardware acceleration" -switching table ahead of the software switching tables implemented by -the reference implementation. The hardware switching table is -expected to handle any incoming packets that it can on its own. Any -packets that it cannot handle itself it may pass up to the software -table implementations. - -Hardware table implementation are provided as a library and built -in the userspace datapath executable. - -Creating a hardware table module is straightforward. Create a -directory in the openflow source tree named hw-lib/NAME, -where NAME identifies the hardware that the module supports. Populate -that directory with the C source files that comprise the module, plus -a file named automake.mk that specifies how to build the module in -the hw-lib directory. This distribution includes a "skeleton" hardware -library that demonstrates how this works. - -When you perform 'configure', specify each NAME that identifies a -library to be included on the OpenFlow configure script command as -the argument to --enable-hw-lib, e.g.: - ./configure --enable-hw-lib=NAME - -Each hardware table library's code is encapsulated in a directory, so -it is easy to separate a hardware table implementation from OpenFlow. -Simply package up the contents of the hw-lib/NAME directory and -distribute it for builders to extract into their distribution -directory. - -Included in this distribution is a dummy hardware table to aid in beginning -your own hardware table port, it is located in the hw-lib/skeleton -folder. Also included is a fully functional NetFPGA hardware table that can run -as a 1Gbx4 port line-rate OpenFlow switch. Information and instructions for its -use can be found in the hw-lib/nf2/README file. diff --git a/openflow/README.kernel b/openflow/README.kernel deleted file mode 100644 index 95ce7564..00000000 --- a/openflow/README.kernel +++ /dev/null @@ -1,18 +0,0 @@ -Kernel-mode Support -*- text -*- -------------------- - -The OpenFlow reference implementation no longer includes a kernel module -that implements the datapath. A separate release with kernel-mode support -is expected in 1H2010. - -The release you downloaded *may* include the kernel module source files -depending upon the method used to obtain the release. If you downloaded the -release as a compressed tar file (.tar.gz) then you will *not* have the -source for the kernel module. If you downloaded the release directly from -git then you will have the source. - -Please note that if you obtained the release via git that the kernel module -source is not built by default and does not implement all features. - -Please check the OpenFlow website or subscribe to the openflow-announce -mailing list for updates on the kernel-mode implementation. diff --git a/openflow/acinclude.m4 b/openflow/acinclude.m4 deleted file mode 100644 index 7ccfbaa4..00000000 --- a/openflow/acinclude.m4 +++ /dev/null @@ -1,309 +0,0 @@ -# -*- autoconf -*- - -# Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford -# Junior University -# -# We are making the OpenFlow specification and associated documentation -# (Software) available for public use and benefit with the expectation -# that others will use, modify and enhance the Software and contribute -# those enhancements back to the community. However, since we would -# like to make the Software available for broadest use, with as few -# restrictions as possible permission is hereby granted, free of -# charge, to any person obtaining a copy of this Software to deal in -# the Software under the copyrights without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# -# The name and trademarks of copyright holder(s) may NOT be used in -# advertising or publicity pertaining to the Software or any -# derivatives without specific, written prior permission. - -dnl OFP_CHECK_LINUX(OPTION, VERSION, VARIABLE, CONDITIONAL) -dnl -dnl Configure linux kernel source tree -AC_DEFUN([OFP_CHECK_LINUX], [ - AC_ARG_WITH([$1], - [AC_HELP_STRING([--with-$1=/path/to/linux-$2], - [Specify the linux $2 kernel module build envrionment and sources])], - [path="$withval"], [path=])dnl - if test -n "$path"; then - path=`eval echo "$path"` - - AC_MSG_CHECKING([for $path directory]) - if test -d "$path" && test -d "$path/build" ; then - AC_MSG_RESULT([yes]) - if test -d "$path/source" ; then - $3=$path/build - $4=$path/source - else - $3=$path/build - $4=$path/build - fi - AC_SUBST($3) - AC_SUBST($4) - else - AC_MSG_RESULT([no]) - AC_ERROR([source dir $path doesn't exist]) - fi - - AC_MSG_CHECKING([for $path kernel version]) - patchlevel=`sed -n 's/^PATCHLEVEL = //p' "$KBLD26/Makefile"` - sublevel=`sed -n 's/^SUBLEVEL = //p' "$KBLD26/Makefile"` - AC_MSG_RESULT([2.$patchlevel.$sublevel]) - if test "2.$patchlevel" != '$2'; then - AC_ERROR([Linux kernel source in $path is not version $2]) - fi - if ! test -e $KBLD26/include/linux/version.h || \ - ! test -e $KBLD26/include/linux/autoconf.h; then - AC_MSG_ERROR([Linux kernel source in $path is not configured]) - fi - m4_if($2, [2.6], [OFP_CHECK_LINUX26_COMPAT]) - fi - AM_CONDITIONAL($5, test -n "$path") -]) - -dnl OFP_GREP_IFELSE(FILE, REGEX, IF-MATCH, IF-NO-MATCH) -dnl -dnl Greps FILE for REGEX. If it matches, runs IF-MATCH, otherwise IF-NO-MATCH. -AC_DEFUN([OFP_GREP_IFELSE], [ - AC_MSG_CHECKING([whether $2 matches in $1]) - grep '$2' $1 >/dev/null 2>&1 - status=$? - case $status in - 0) - AC_MSG_RESULT([yes]) - $3 - ;; - 1) - AC_MSG_RESULT([no]) - $4 - ;; - *) - AC_MSG_ERROR([grep exited with status $status]) - ;; - esac -]) - -dnl OFP_DEFINE(NAME) -dnl -dnl Defines NAME to 1 in kcompat.h. -AC_DEFUN([OFP_DEFINE], [ - echo '#define $1 1' >> datapath/linux-2.6/kcompat.h.new -]) - -AC_DEFUN([OFP_CHECK_VETH], [ - AC_MSG_CHECKING([whether to build veth module]) - if test "$sublevel" = 18; then - AC_MSG_RESULT([yes]) - AC_SUBST([BUILD_VETH], 1) - else - AC_MSG_RESULT([no]) - fi -]) - -dnl OFP_CHECK_LINUX26_COMPAT -dnl -dnl Runs various Autoconf checks on the Linux 2.6 kernel source in -dnl the directory in $KSRC26. -AC_DEFUN([OFP_CHECK_LINUX26_COMPAT], [ - rm -f datapath/linux-2.6/kcompat.h.new - mkdir -p datapath/linux-2.6 - : > datapath/linux-2.6/kcompat.h.new - OFP_GREP_IFELSE([$KSRC26/include/linux/skbuff.h], [skb_transport_header], - [OFP_DEFINE([HAVE_SKBUFF_HEADER_HELPERS])]) - OFP_GREP_IFELSE([$KSRC26/include/linux/skbuff.h], [raw], - [OFP_DEFINE([HAVE_MAC_RAW])]) - OFP_GREP_IFELSE([$KSRC26/include/linux/skbuff.h], - [skb_copy_from_linear_data_offset], - [OFP_DEFINE([HAVE_SKB_COPY_FROM_LINEAR_DATA_OFFSET])]) - OFP_GREP_IFELSE([$KSRC26/include/net/netlink.h], [NLA_NUL_STRING], - [OFP_DEFINE([HAVE_NLA_NUL_STRING])]) - OFP_CHECK_VETH - if cmp -s datapath/linux-2.6/kcompat.h.new \ - datapath/linux-2.6/kcompat.h >/dev/null 2>&1; then - rm datapath/linux-2.6/kcompat.h.new - else - mv datapath/linux-2.6/kcompat.h.new datapath/linux-2.6/kcompat.h - fi -]) - -dnl Checks for --enable-hw-tables and substitutes HW_TABLES to any -dnl requested hardware table modules. -AC_DEFUN([OFP_CHECK_HWTABLES], - [AC_ARG_ENABLE( - [hw-tables], - [AC_HELP_STRING([--enable-hw-tables=MODULE...], - [Configure and build the specified externally supplied - hardware table support modules])]) - case "${enable_hw_tables}" in # ( - yes) - AC_MSG_ERROR([--enable-hw-tables has a required argument]) - ;; # ( - ''|no) - hw_tables= - ;; # ( - *) - hw_tables=`echo "$enable_hw_tables" | sed 's/,/ /g'` - ;; - esac - for d in $hw_tables; do - mk=datapath/hwtable_$d/Modules.mk - if test ! -e $srcdir/$mk; then - AC_MSG_ERROR([--enable-hw-tables=$d specified but $mk is missing]) - fi - HW_TABLES="$HW_TABLES \$(top_srcdir)/$mk" - done - AC_SUBST(HW_TABLES)]) - -dnl Checks for --enable-hw-lib and substitutes BUILD_HW_LIBS and plat name -AC_DEFUN([OFP_CHECK_HWLIBS], - [AC_ARG_ENABLE( - [hw-lib], - [AC_HELP_STRING([--enable-hw-lib=PLATFORM], - [Configure and build the specified externally supplied - hardware library: lb4g, t2ref, scorref or nf2])]) - case "${enable_hw_lib}" in # ( - yes) - AC_MSG_ERROR([--enable-hw-lib has a required argument]) - ;; # ( - ''|no) - hw_lib= - NF2=no - LB4G=no - T2REF=no - SCORREF=no - BUILD_HW_LIBS=no - ;; # ( - nf2) - NF2=yes - LB4G=no - T2REF=no - SCORREF=no - hw_lib=$enable_hw_lib - BUILD_HW_LIBS=yes - ;; # ( - lb4g) - NF2=no - LB4G=yes - T2REF=no - SCORREF=no - hw_lib=$enable_hw_lib - BUILD_HW_LIBS=yes - ;; # ( - t2ref) - NF2=no - LB4G=no - T2REF=yes - SCORREF=no - hw_lib=$enable_hw_lib - BUILD_HW_LIBS=yes - ;; # ( - scorref) - NF2=no - LB4G=no - SCORREF=yes - T2REF=no - hw_lib=$enable_hw_lib - BUILD_HW_LIBS=yes - ;; # ( - *) - AC_MSG_ERROR([--enable-hw-lib: Unknown platform: ${enable_hw_lib}]) - BUILD_HW_LIBS=no - ;; - esac - if test $BUILD_HW_LIBS = yes; then - if test -e "$srcdir/hw-lib/automake.mk"; then - : - else - AC_MSG_ERROR([cannot configure HW libraries without "hw-lib" directory]) - fi - AC_DEFINE([BUILD_HW_LIBS], [1], - [Whether the OpenFlow hardware libraries are available]) - fi - if test $NF2 = yes; then - AC_DEFINE([NF2], [1], - [Support NetFPGA platform]) - fi - if test $LB4G = yes; then - AC_DEFINE([LB4G], [1], - [Support Stanford-LB4G platform]) - fi - if test $T2REF = yes; then - AC_DEFINE([T2REF], [1], - [Support Broadcom 56634 reference platform]) - fi - if test $SCORREF = yes; then - AC_DEFINE([SCORREF], [1], - [Support Broadcom 56820 reference platform]) - fi - AM_CONDITIONAL([NF2], [test $NF2 = yes]) - AM_CONDITIONAL([LB4G], [test $LB4G = yes]) - AM_CONDITIONAL([T2REF], [test $T2REF = yes]) - AM_CONDITIONAL([SCORREF], [test $SCORREF = yes]) - AM_CONDITIONAL([BUILD_HW_LIBS], [test $BUILD_HW_LIBS = yes]) - AC_SUBST(HW_LIB)]) - -dnl Checks for net/if_packet.h. -AC_DEFUN([OFP_CHECK_IF_PACKET], - [AC_CHECK_HEADER([net/if_packet.h], - [HAVE_IF_PACKET=yes], - [HAVE_IF_PACKET=no]) - AM_CONDITIONAL([HAVE_IF_PACKET], [test "$HAVE_IF_PACKET" = yes]) - if test "$HAVE_IF_PACKET" = yes; then - AC_DEFINE([HAVE_IF_PACKET], [1], - [Define to 1 if net/if_packet.h is available.]) - fi]) - -dnl Checks for dpkg-buildpackage. If this is available then we check -dnl that the Debian packaging is functional at "make distcheck" time. -AC_DEFUN([OFP_CHECK_DPKG_BUILDPACKAGE], - [AC_CHECK_PROG([HAVE_DPKG_BUILDPACKAGE], [dpkg-buildpackage], [yes], [no]) - AM_CONDITIONAL([HAVE_DPKG_BUILDPACKAGE], - [test $HAVE_DPKG_BUILDPACKAGE = yes])]) - -dnl ---------------------------------------------------------------------- -dnl These macros are from GNU PSPP, with the following original license: -dnl Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc. -dnl This file is free software; the Free Software Foundation -dnl gives unlimited permission to copy and/or distribute it, -dnl with or without modifications, as long as this notice is preserved. - -dnl OFP_CHECK_CC_OPTION([OPTION], [ACTION-IF-ACCEPTED], [ACTION-IF-REJECTED]) -dnl Check whether the given C compiler OPTION is accepted. -dnl If so, execute ACTION-IF-ACCEPTED, otherwise ACTION-IF-REJECTED. -AC_DEFUN([OFP_CHECK_CC_OPTION], -[ - m4_define([ofp_cv_name], [ofp_cv_[]m4_translit([$1], [-], [_])])dnl - AC_CACHE_CHECK([whether $CC accepts $1], [ofp_cv_name], - [ofp_save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $1" - AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,)], [ofp_cv_name[]=yes], [ofp_cv_name[]=no]) - CFLAGS="$ofp_save_CFLAGS"]) - if test $ofp_cv_name = yes; then - m4_if([$2], [], [;], [$2]) - else - m4_if([$3], [], [:], [$3]) - fi -]) - -dnl OFP_ENABLE_OPTION([OPTION]) -dnl Check whether the given C compiler OPTION is accepted. -dnl If so, add it to CFLAGS. -dnl Example: OFP_ENABLE_OPTION([-Wdeclaration-after-statement]) -AC_DEFUN([OFP_ENABLE_OPTION], - [OFP_CHECK_CC_OPTION([$1], [CFLAGS="$CFLAGS $1"])]) -dnl ---------------------------------------------------------------------- diff --git a/openflow/boot.sh b/openflow/boot.sh deleted file mode 100755 index 97921fac..00000000 --- a/openflow/boot.sh +++ /dev/null @@ -1,14 +0,0 @@ -#! /bin/sh - -set -e - -# Generate list of files in debian/ to distribute. -(echo '# Automatically generated by boot.sh (from Git tree).' && - printf 'EXTRA_DIST += \\\n' && - git ls-files debian | grep -v '^debian/\.gitignore$' | - sed -e 's/\(.*\)/ \1 \\/' -e '$s/ \\//') > debian/automake.mk - -cat debian/control.in > debian/control - -# Bootstrap configure system from .ac/.am files -autoreconf --install --force diff --git a/openflow/configure.ac b/openflow/configure.ac deleted file mode 100644 index 13064f68..00000000 --- a/openflow/configure.ac +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford -# Junior University -# -# We are making the OpenFlow specification and associated documentation -# (Software) available for public use and benefit with the expectation -# that others will use, modify and enhance the Software and contribute -# those enhancements back to the community. However, since we would -# like to make the Software available for broadest use, with as few -# restrictions as possible permission is hereby granted, free of -# charge, to any person obtaining a copy of this Software to deal in -# the Software under the copyrights without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# -# The name and trademarks of copyright holder(s) may NOT be used in -# advertising or publicity pertaining to the Software or any -# derivatives without specific, written prior permission. - -AC_PREREQ(2.60) -AC_INIT([openflow], [1.0.0], [openflow-discuss@openflowswitch.org]) -NX_BUILDNR -AC_CONFIG_SRCDIR([README.hwtables]) -AC_CONFIG_MACRO_DIR([m4]) -AC_CONFIG_AUX_DIR([build-aux]) -AC_CONFIG_HEADERS([config.h]) -AM_INIT_AUTOMAKE - -AC_PROG_CC -AM_PROG_CC_C_O -AC_PROG_CPP -AC_PROG_RANLIB -AC_PROG_MKDIR_P - -AC_ARG_VAR([PERL], [path to Perl interpreter]) -AC_PATH_PROG([PERL], perl, no) -if test "$PERL" = no; then - AC_MSG_ERROR([Perl interpreter not found in $PATH or $PERL.]) -fi - -OFP_CHECK_LIBOPENFLOW -OFP_CHECK_IF_PACKET -OFP_CHECK_HWTABLES -OFP_CHECK_HWLIBS -AC_SYS_LARGEFILE - -AC_CHECK_FUNCS([strsignal]) - -AC_ARG_VAR(KARCH, [Kernel Architecture String]) -AC_SUBST(KARCH) -#OFP_CHECK_LINUX(l26, 2.6, KBLD26, KSRC26, L26_ENABLED) - -OFP_CHECK_DPKG_BUILDPACKAGE - -OFP_ENABLE_OPTION([-Wall]) -OFP_ENABLE_OPTION([-Wno-sign-compare]) -OFP_ENABLE_OPTION([-Wpointer-arith]) -OFP_ENABLE_OPTION([-Wdeclaration-after-statement]) -OFP_ENABLE_OPTION([-Wformat-security]) -OFP_ENABLE_OPTION([-Wswitch-enum]) -OFP_ENABLE_OPTION([-Wunused-parameter]) -OFP_ENABLE_OPTION([-Wstrict-aliasing]) -OFP_ENABLE_OPTION([-Wbad-function-cast]) -OFP_ENABLE_OPTION([-Wcast-align]) -OFP_ENABLE_OPTION([-Wstrict-prototypes]) -OFP_ENABLE_OPTION([-Wold-style-definition]) -OFP_ENABLE_OPTION([-Wmissing-prototypes]) -OFP_ENABLE_OPTION([-Wmissing-field-initializers]) -OFP_ENABLE_OPTION([-Wno-override-init]) - -AC_CONFIG_FILES([Makefile -]) - -#AC_CONFIG_FILES([Makefile -#datapath/Makefile -#datapath/linux-2.6/Kbuild -#datapath/linux-2.6/Makefile -#datapath/linux-2.6/Makefile.main -#]) - -AC_OUTPUT diff --git a/openflow/controller/.dirstamp b/openflow/controller/.dirstamp deleted file mode 100644 index e69de29b..00000000 diff --git a/openflow/controller/.gitignore b/openflow/controller/.gitignore deleted file mode 100644 index 8736bbc1..00000000 --- a/openflow/controller/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/Makefile -/Makefile.in -/controller -/controller.8 diff --git a/openflow/controller/automake.mk b/openflow/controller/automake.mk deleted file mode 100644 index ff9f627c..00000000 --- a/openflow/controller/automake.mk +++ /dev/null @@ -1,8 +0,0 @@ -bin_PROGRAMS += controller/controller -man_MANS += controller/controller.8 -DISTCLEANFILES += controller/controller.8 - -controller_controller_SOURCES = controller/controller.c -controller_controller_LDADD = lib/libopenflow.a $(FAULT_LIBS) $(SSL_LIBS) - -EXTRA_DIST += controller/controller.8.in diff --git a/openflow/controller/controller.8.in b/openflow/controller/controller.8.in deleted file mode 100644 index c2b65cfb..00000000 --- a/openflow/controller/controller.8.in +++ /dev/null @@ -1,150 +0,0 @@ -.ds PN controller - -.TH controller 8 "May 2008" "OpenFlow" "OpenFlow Manual" - -.SH NAME -controller \- simple OpenFlow controller reference implementation - -.SH SYNOPSIS -.B controller -[\fIoptions\fR] \fImethod\fR \fB[\fImethod\fR]\&... - -.SH DESCRIPTION -A sample OpenFlow controller which functions as an L2 MAC-learning -switch or hub. \fBcontroller\fR can manage a remote datapath through -a secure channel (see \fBofprotocol(8)\fR). It can also connect directly -to a local datapath via Netlink. - -\fBcontroller\fR controls one or more OpenFlow switches, specified as -one or more of the following OpenFlow connection methods: - -.TP -\fBpssl:\fR[\fIport\fR] -Listens for SSL connections from remote OpenFlow switches on -\fIport\fR (default: 6633). The \fB--private-key\fR, -\fB--certificate\fR, and \fB--ca-cert\fR options are mandatory when -this form is used. - -.TP -\fBptcp:\fR[\fIport\fR] -Listens for TCP connections from remote OpenFlow switches on -\fIport\fR (default: 6633). - -.TP -\fBpunix:\fIfile\fR -Listens for connections from OpenFlow switches on the Unix domain -server socket named \fIfile\fR. - -.TP -\fBnl:\fIdp_idx\fR -The local Netlink datapath numbered \fIdp_idx\fR, as configured with -.BR dpctl (8). -This form requires that the local host has the OpenFlow kernel -module for Linux loaded. - -.TP -\fBssl:\fIhost\fR[\fB:\fIport\fR] -The specified SSL \fIport\fR (default: 6633) on the given remote -\fIhost\fR. The \fB--private-key\fR, \fB--certificate\fR, and -\fB--ca-cert\fR options are mandatory when this form is used. - -.TP -\fBtcp:\fIhost\fR[\fB:\fIport\fR] -The specified TCP \fIport\fR (default: 6633) on the given remote -\fIhost\fR. - -.TP -\fBunix:\fIfile\fR -The Unix domain server socket named \fIfile\fR. - -.SH OPTIONS -.TP -\fB-p\fR, \fB--private-key=\fIprivkey.pem\fR -Specifies a PEM file containing the private key used as the switch's -identity for SSL connections to the controller. - -.TP -\fB-c\fR, \fB--certificate=\fIcert.pem\fR -Specifies a PEM file containing a certificate, signed by the -controller's certificate authority (CA), that certifies the switch's -private key to identify a trustworthy switch. - -.TP -\fB-C\fR, \fB--ca-cert=\fIswitch-cacert.pem\fR -Specifies a PEM file containing the CA certificate used to verify that -the switch is connected to a trustworthy controller. - -.TP -\fB--peer-ca-cert=\fIcontroller-cacert.pem\fR -Specifies a PEM file that contains one or more additional certificates -to send to switches. \fIcontroller-cacert.pem\fR should be the CA -certificate used to sign the controller's own certificate (the -certificate specified on \fB-c\fR or \fB--certificate\fR). - -This option is not useful in normal operation, because the switch must -already have the controller CA certificate for it to have any -confidence in the controller's identity. However, this option allows -a newly installed switch to obtain the controller CA certificate on -first boot using, e.g., the \fB--bootstrap-ca-cert\fR option to -\fBofprotocol\fR(8). - -.TP -.BR \-n ", " \-\^\-noflow -By default, the controller sets up a flow in each OpenFlow switch -whenever it receives a packet whose destination is known due through -MAC learning. This option disables flow setup, so that every packet -in the network passes through the controller. - -This option is most useful for debugging. It reduces switching -performance, so it should not be used in production. - -.TP -\fB--max-idle=\fIsecs\fR|\fBpermanent\fR -Sets \fIsecs\fR as the number of seconds that a flow set up by the -controller will remain in the switch's flow table without any matching -packets being seen. If \fBpermanent\fR is specified, which is not -recommended, flows will never expire. The default is 60 seconds. - -This option affects only flows set up by the OpenFlow controller. In -some configurations, the OpenFlow secure channel can set up some flows -on its own. To set the idle time for those flows, pass -\fB--max-idle\fR to \fBofprotocol\fR(8). - -This option has no effect when \fB-n\fR (or \fB--noflow\fR) is in use -(because the controller does not set up flows in that case). - -.TP -.BR \-H ", " \-\^\-hub -By default, the controller acts as an L2 MAC-learning switch. This -option changes its behavior to that of a hub that floods packets on -all but the incoming port. - -If \fB-H\fR (or \fB--hub\fR) and \fB-n\fR (or \fB--noflow\fR) are used -together, then the cumulative effect is that every packet passes -through the controller and every packet is flooded. - -This option is most useful for debugging. It reduces switching -performance, so it should not be used in production. - -.so lib/daemon.man -.so lib/vlog.man -.so lib/common.man - -.SH EXAMPLES - -.TP -To connect directly to local datapath 0 over netlink (Linux only): - -.B % controller nl:0 - -.TP -To bind locally to port 6633 (the default) and wait for incoming connections from OpenFlow switches: - -.B % controller ptcp: - -.SH "SEE ALSO" - -.BR dpctl (8), -.BR ofprotocol (8), -.BR ofdatapath (8), -.BR vlogconf (8) diff --git a/openflow/controller/controller.c b/openflow/controller/controller.c deleted file mode 100644 index 6eec5906..00000000 --- a/openflow/controller/controller.c +++ /dev/null @@ -1,336 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include - -#include -#include -#include -#include -#include -#include - -#include "command-line.h" -#include "compiler.h" -#include "daemon.h" -#include "fault.h" -#include "learning-switch.h" -#include "ofpbuf.h" -#include "openflow/openflow.h" -#include "poll-loop.h" -#include "rconn.h" -#include "timeval.h" -#include "util.h" -#include "vconn-ssl.h" -#include "vconn.h" -#include "vlog-socket.h" - -#include "vlog.h" -#define THIS_MODULE VLM_controller - -#define MAX_SWITCHES 4096 -#define MAX_LISTENERS 4096 - -struct switch_ { - struct lswitch *lswitch; - struct rconn *rconn; -}; - -/* Learn the ports on which MAC addresses appear? */ -static bool learn_macs = true; - -/* Set up flows? (If not, every packet is processed at the controller.) */ -static bool setup_flows = true; - -/* --max-idle: Maximum idle time, in seconds, before flows expire. */ -static int max_idle = 60; - -static int do_switching(struct switch_ *); -static void new_switch(struct switch_ *, struct vconn *, const char *name); -static void parse_options(int argc, char *argv[]); -static void usage(void) NO_RETURN; - -int -main(int argc, char *argv[]) -{ - struct switch_ switches[MAX_SWITCHES]; - struct pvconn *listeners[MAX_LISTENERS]; - int n_switches, n_listeners; - int retval; - int i; - - set_program_name(argv[0]); - register_fault_handlers(); - time_init(); - vlog_init(); - parse_options(argc, argv); - signal(SIGPIPE, SIG_IGN); - - if (argc - optind < 1) { - ofp_fatal(0, "at least one vconn argument required; " - "use --help for usage"); - } - - n_switches = n_listeners = 0; - for (i = optind; i < argc; i++) { - const char *name = argv[i]; - struct vconn *vconn; - int retval; - - retval = vconn_open(name, OFP_VERSION, &vconn); - if (!retval) { - if (n_switches >= MAX_SWITCHES) { - ofp_fatal(0, "max %d switch connections", n_switches); - } - new_switch(&switches[n_switches++], vconn, name); - continue; - } else if (retval == EAFNOSUPPORT) { - struct pvconn *pvconn; - retval = pvconn_open(name, &pvconn); - if (!retval) { - if (n_listeners >= MAX_LISTENERS) { - ofp_fatal(0, "max %d passive connections", n_listeners); - } - listeners[n_listeners++] = pvconn; - } - } - if (retval) { - VLOG_ERR("%s: connect: %s", name, strerror(retval)); - } - } - if (n_switches == 0 && n_listeners == 0) { - ofp_fatal(0, "no active or passive switch connections"); - } - - die_if_already_running(); - daemonize(); - - retval = vlog_server_listen(NULL, NULL); - if (retval) { - ofp_fatal(retval, "Could not listen for vlog connections"); - } - - while (n_switches > 0 || n_listeners > 0) { - int iteration; - int i; - - /* Accept connections on listening vconns. */ - for (i = 0; i < n_listeners && n_switches < MAX_SWITCHES; ) { - struct vconn *new_vconn; - int retval; - - retval = pvconn_accept(listeners[i], OFP_VERSION, &new_vconn); - if (!retval || retval == EAGAIN) { - if (!retval) { - new_switch(&switches[n_switches++], new_vconn, "tcp"); - } - i++; - } else { - pvconn_close(listeners[i]); - listeners[i] = listeners[--n_listeners]; - } - } - - /* Do some switching work. Limit the number of iterations so that - * callbacks registered with the poll loop don't starve. */ - for (iteration = 0; iteration < 50; iteration++) { - bool progress = false; - for (i = 0; i < n_switches; ) { - struct switch_ *this = &switches[i]; - int retval = do_switching(this); - if (!retval || retval == EAGAIN) { - if (!retval) { - progress = true; - } - i++; - } else { - rconn_destroy(this->rconn); - lswitch_destroy(this->lswitch); - switches[i] = switches[--n_switches]; - } - } - if (!progress) { - break; - } - } - for (i = 0; i < n_switches; i++) { - struct switch_ *this = &switches[i]; - lswitch_run(this->lswitch, this->rconn); - } - - /* Wait for something to happen. */ - if (n_switches < MAX_SWITCHES) { - for (i = 0; i < n_listeners; i++) { - pvconn_wait(listeners[i]); - } - } - for (i = 0; i < n_switches; i++) { - struct switch_ *sw = &switches[i]; - rconn_run_wait(sw->rconn); - rconn_recv_wait(sw->rconn); - lswitch_wait(sw->lswitch); - } - poll_block(); - } - - return 0; -} - -static void -new_switch(struct switch_ *sw, struct vconn *vconn, const char *name) -{ - sw->rconn = rconn_new_from_vconn(name, vconn); - sw->lswitch = lswitch_create(sw->rconn, learn_macs, - setup_flows ? max_idle : -1); -} - -static int -do_switching(struct switch_ *sw) -{ - unsigned int packets_sent; - struct ofpbuf *msg; - - packets_sent = rconn_packets_sent(sw->rconn); - - msg = rconn_recv(sw->rconn); - if (msg) { - lswitch_process_packet(sw->lswitch, sw->rconn, msg); - ofpbuf_delete(msg); - } - rconn_run(sw->rconn); - - return (!rconn_is_alive(sw->rconn) ? EOF - : rconn_packets_sent(sw->rconn) != packets_sent ? 0 - : EAGAIN); -} - -static void -parse_options(int argc, char *argv[]) -{ - enum { - OPT_MAX_IDLE = UCHAR_MAX + 1, - OPT_PEER_CA_CERT, - VLOG_OPTION_ENUMS - }; - static struct option long_options[] = { - {"hub", no_argument, 0, 'H'}, - {"noflow", no_argument, 0, 'n'}, - {"max-idle", required_argument, 0, OPT_MAX_IDLE}, - {"help", no_argument, 0, 'h'}, - {"version", no_argument, 0, 'V'}, - DAEMON_LONG_OPTIONS, - VLOG_LONG_OPTIONS, -#ifdef HAVE_OPENSSL - VCONN_SSL_LONG_OPTIONS - {"peer-ca-cert", required_argument, 0, OPT_PEER_CA_CERT}, -#endif - {0, 0, 0, 0}, - }; - char *short_options = long_options_to_short_options(long_options); - - for (;;) { - int indexptr; - int c; - - c = getopt_long(argc, argv, short_options, long_options, &indexptr); - if (c == -1) { - break; - } - - switch (c) { - case 'H': - learn_macs = false; - break; - - case 'n': - setup_flows = false; - break; - - case OPT_MAX_IDLE: - if (!strcmp(optarg, "permanent")) { - max_idle = OFP_FLOW_PERMANENT; - } else { - max_idle = atoi(optarg); - if (max_idle < 1 || max_idle > 65535) { - ofp_fatal(0, "--max-idle argument must be between 1 and " - "65535 or the word 'permanent'"); - } - } - break; - - case 'h': - usage(); - - case 'V': - printf("%s "VERSION" compiled "__DATE__" "__TIME__"\n", argv[0]); - exit(EXIT_SUCCESS); - - VLOG_OPTION_HANDLERS - DAEMON_OPTION_HANDLERS - -#ifdef HAVE_OPENSSL - VCONN_SSL_OPTION_HANDLERS - - case OPT_PEER_CA_CERT: - vconn_ssl_set_peer_ca_cert_file(optarg); - break; -#endif - - case '?': - exit(EXIT_FAILURE); - - default: - abort(); - } - } - free(short_options); -} - -static void -usage(void) -{ - printf("%s: OpenFlow controller\n" - "usage: %s [OPTIONS] METHOD\n" - "where METHOD is any OpenFlow connection method.\n", - program_name, program_name); - vconn_usage(true, true, false); - daemon_usage(); - vlog_usage(); - printf("\nOther options:\n" - " -H, --hub act as hub instead of learning switch\n" - " -n, --noflow pass traffic, but don't add flows\n" - " --max-idle=SECS max idle time for new flows\n" - " -h, --help display this help message\n" - " -V, --version display version information\n"); - exit(EXIT_SUCCESS); -} diff --git a/openflow/datapath/.gitignore b/openflow/datapath/.gitignore deleted file mode 100644 index 5a59a0d3..00000000 --- a/openflow/datapath/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -/Makefile -/Makefile.in -*.cmd -*.ko -*.mod.c -Module.symvers - diff --git a/openflow/datapath/Makefile.am b/openflow/datapath/Makefile.am deleted file mode 100644 index 7eed78d1..00000000 --- a/openflow/datapath/Makefile.am +++ /dev/null @@ -1,27 +0,0 @@ -SUBDIRS = -if L26_ENABLED -SUBDIRS += linux-2.6 -endif - -EXTRA_DIST = $(dist_headers) $(dist_sources) -EXTRA_DIST += hwtable_dummy/Modules.mk hwtable_dummy/hwtable_dummy.c -EXTRA_DIST += \ - hwtable_nf2/Modules.mk \ - hwtable_nf2/nf2.h \ - hwtable_nf2/nf2_hwapi.h \ - hwtable_nf2/nf2_reg.h \ - hwtable_nf2/nf2_flowtable.c \ - hwtable_nf2/nf2_flowtable.h \ - hwtable_nf2/nf2_lib.c \ - hwtable_nf2/nf2_lib.h \ - hwtable_nf2/nf2_procfs.c \ - hwtable_nf2/nf2_procfs.h \ - hwtable_nf2/nf2_openflow.c \ - hwtable_nf2/nf2_openflow.h \ - hwtable_nf2/openflow_switch.bit - -# Suppress warnings about GNU extensions in Modules.mk files. -AUTOMAKE_OPTIONS = -Wno-portability - -include Modules.mk -include linux-2.6/Modules.mk diff --git a/openflow/datapath/Modules.mk b/openflow/datapath/Modules.mk deleted file mode 100644 index 777dc658..00000000 --- a/openflow/datapath/Modules.mk +++ /dev/null @@ -1,42 +0,0 @@ -# Some modules should be built and distributed, e.g. openflow. -# -# Some modules should be distributed but not built, e.g. we do not build -# veth if the kernel in question already has it. -# -# Some modules should be built but not distributed, e.g. third-party -# hwtable modules. -both_modules = ofdatapath -build_modules = $(both_modules) # Modules to build -dist_modules = $(both_modules) # Modules to distribute - -ofdatapath_sources = \ - chain.c \ - crc32.c \ - datapath.c \ - dp_act.c \ - dp_dev.c \ - dp_notify.c \ - flow.c \ - forward.c \ - private-msg.c \ - table-hash.c \ - table-linear.c - -ofdatapath_headers = \ - chain.h \ - compat.h \ - crc32.h \ - datapath.h \ - dp_dev.h \ - flow.h \ - forward.h \ - dp_act.h \ - private-msg.h \ - table.h - -dist_sources = $(foreach module,$(dist_modules),$($(module)_sources)) -dist_headers = $(foreach module,$(dist_modules),$($(module)_headers)) -build_sources = $(foreach module,$(build_modules),$($(module)_sources)) -build_headers = $(foreach module,$(build_modules),$($(module)_headers)) -build_links = $(notdir $(build_sources)) -build_objects = $(notdir $(patsubst %.c,%.o,$(build_sources))) diff --git a/openflow/datapath/chain.c b/openflow/datapath/chain.c deleted file mode 100644 index e75f77dc..00000000 --- a/openflow/datapath/chain.c +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Distributed under the terms of the GNU GPL version 2. - * Copyright (c) 2007, 2008, 2009 The Board of Trustees of The Leland - * Stanford Junior University - */ - -#include "chain.h" -#include "datapath.h" -#include "flow.h" -#include "table.h" -#include -#include -#include -#include - -static struct sw_table *(*create_hw_table_hook)(void); -static struct module *hw_table_owner; -static DEFINE_SPINLOCK(hook_lock); - -/* Attempts to append 'table' to the set of tables in 'chain'. Returns 0 or - * negative error. If 'table' is null it is assumed that table creation failed - * due to out-of-memory. */ -static int add_table(struct sw_chain *chain, struct sw_table *table, int emerg) -{ - if (table == NULL) - return -ENOMEM; - if (chain->n_tables >= CHAIN_MAX_TABLES) { - printk(KERN_EMERG "%s: too many tables in chain\n", - chain->dp->netdev->name); - table->destroy(table); - return -ENOBUFS; - } - if (emerg) - chain->emerg_table = table; - else - chain->tables[chain->n_tables++] = table; - return 0; -} - -/* Creates and returns a new chain associated with 'dp'. Returns NULL if the - * chain cannot be created. */ -struct sw_chain *chain_create(struct datapath *dp) -{ - struct sw_chain *chain = kzalloc(sizeof *chain, GFP_KERNEL); - if (chain == NULL) - goto error; - chain->dp = dp; - chain->owner = try_module_get(hw_table_owner) ? hw_table_owner : NULL; - if (chain->owner && create_hw_table_hook) { - struct sw_table *hwtable = create_hw_table_hook(); - if (!hwtable || add_table(chain, hwtable, 0)) - goto error; - } - - if (add_table(chain, table_hash2_create(0x1EDC6F41, TABLE_HASH_MAX_FLOWS, - 0x741B8CD7, TABLE_HASH_MAX_FLOWS), - 0) - || add_table(chain, table_linear_create(TABLE_LINEAR_MAX_FLOWS), 0) - || add_table(chain, table_linear_create(TABLE_LINEAR_MAX_FLOWS), 1)) - goto error; - return chain; - -error: - if (chain) - chain_destroy(chain); - return NULL; -} - -/* Searches 'chain' for a flow matching 'key', which must not have any wildcard - * fields. Returns the flow if successful, otherwise a null pointer. - * - * Caller must hold rcu_read_lock or dp_mutex. */ -struct sw_flow *chain_lookup(struct sw_chain *chain, - const struct sw_flow_key *key, int emerg) -{ - int i; - - BUG_ON(key->wildcards); - if (emerg) { - struct sw_table *t = chain->emerg_table; - struct sw_flow *flow = t->lookup(t, key); - t->n_lookup++; - if (flow) { - t->n_matched++; - return flow; - } - } else { - for (i = 0; i < chain->n_tables; i++) { - struct sw_table *t = chain->tables[i]; - struct sw_flow *flow = t->lookup(t, key); - t->n_lookup++; - if (flow) { - t->n_matched++; - return flow; - } - } - } - return NULL; -} - -/* Inserts 'flow' into 'chain', replacing any duplicate flow. Returns 0 if - * successful or a negative error. - * - * If successful, 'flow' becomes owned by the chain, otherwise it is retained - * by the caller. - * - * Caller must hold dp_mutex. */ -int chain_insert(struct sw_chain *chain, struct sw_flow *flow, int emerg) -{ - int i; - - might_sleep(); - if (emerg) { - struct sw_table *t = chain->emerg_table; - if (t->insert(t, flow)) - return 0; - } else { - for (i = 0; i < chain->n_tables; i++) { - struct sw_table *t = chain->tables[i]; - if (t->insert(t, flow)) - return 0; - } - } - return -ENOBUFS; -} - -/* Modifies actions in 'chain' that match 'key'. If 'strict' set, wildcards - * and priority must match. Returns the number of flows that were modified. - * - * Expensive in the general case as currently implemented, since it requires - * iterating through the entire contents of each table for keys that contain - * wildcards. Relatively cheap for fully specified keys. */ -int -chain_modify(struct sw_chain *chain, const struct sw_flow_key *key, - uint16_t priority, int strict, - const struct ofp_action_header *actions, size_t actions_len, - int emerg) -{ - int count = 0; - int i; - - if (emerg) { - struct sw_table *t = chain->emerg_table; - count += t->modify(t, key, priority, strict, - actions, actions_len); - } else { - for (i = 0; i < chain->n_tables; i++) { - struct sw_table *t = chain->tables[i]; - count += t->modify(t, key, priority, strict, - actions, actions_len); - } - } - return count; -} - -/* Checks whether the chain has an entry with the same priority which conflicts - * with 'key'. If 'strict' set, wildcards should also match. If 'strict' is not - * set, comparison is done 'module wildcards'. - * - * Returns 'true' if such an entry exists, 'false' otherwise. */ -int -chain_has_conflict(struct sw_chain *chain, const struct sw_flow_key *key, - uint16_t priority, int strict) -{ - int i; - - for (i = 0; i < chain->n_tables; i++) { - struct sw_table *t = chain->tables[i]; - if (t->has_conflict(t, key, priority, strict)) { - return true; - } - } - - return false; -} - -/* Deletes from 'chain' any and all flows that match 'key'. If 'out_port' - * is not OFPP_NONE, then matching entries must have that port as an - * argument for an output action. If 'strict" is set, then wildcards and - * priority must match. Returns the number of flows that were deleted. - * - * Expensive in the general case as currently implemented, since it requires - * iterating through the entire contents of each table for keys that contain - * wildcards. Relatively cheap for fully specified keys. - * - * Caller must hold dp_mutex. */ -int chain_delete(struct sw_chain *chain, const struct sw_flow_key *key, - uint16_t out_port, uint16_t priority, int strict, int emerg) -{ - int count = 0; - int i; - - might_sleep(); - if (emerg) { - struct sw_table *t = chain->emerg_table; - count += t->delete(chain->dp, t, key, - out_port, priority, strict); - } else { - for (i = 0; i < chain->n_tables; i++) { - struct sw_table *t = chain->tables[i]; - count += t->delete(chain->dp, t, key, - out_port, priority, strict); - } - } - return count; -} - -/* Performs timeout processing on all the tables in 'chain'. Returns the - * number of flow entries deleted through expiration. - * - * Expensive as currently implemented, since it iterates through the entire - * contents of each table. - * - * Caller must not hold dp_mutex, because individual tables take and release it - * as necessary. */ -int chain_timeout(struct sw_chain *chain) -{ - int count = 0; - int i; - - might_sleep(); - for (i = 0; i < chain->n_tables; i++) { - struct sw_table *t = chain->tables[i]; - count += t->timeout(chain->dp, t); - } - return count; -} - -/* Destroys 'chain', which must not have any users. */ -void chain_destroy(struct sw_chain *chain) -{ - int i; - struct sw_table *t = NULL; - - synchronize_rcu(); - for (i = 0; i < chain->n_tables; i++) { - t = chain->tables[i]; - if (t->destroy) - t->destroy(t); - } - t = chain->emerg_table; - if (t->destroy) - t->destroy(t); - module_put(chain->owner); - kfree(chain); -} - -int chain_set_hw_hook(struct sw_table *(*create_hw_table)(void), - struct module *owner) -{ - int retval = -EBUSY; - - spin_lock(&hook_lock); - if (!create_hw_table_hook) { - create_hw_table_hook = create_hw_table; - hw_table_owner = owner; - retval = 0; - } - spin_unlock(&hook_lock); - - return retval; -} -EXPORT_SYMBOL(chain_set_hw_hook); - -void chain_clear_hw_hook(void) -{ - create_hw_table_hook = NULL; - hw_table_owner = NULL; -} -EXPORT_SYMBOL(chain_clear_hw_hook); diff --git a/openflow/datapath/chain.h b/openflow/datapath/chain.h deleted file mode 100644 index 4b00aef6..00000000 --- a/openflow/datapath/chain.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef CHAIN_H -#define CHAIN_H 1 - -#include - -struct sw_flow; -struct sw_flow_key; -struct ofp_action_header; -struct datapath; - - -#define TABLE_LINEAR_MAX_FLOWS 100 -#define TABLE_HASH_MAX_FLOWS 65536 - -/* Set of tables chained together in sequence from cheap to expensive. */ -#define CHAIN_MAX_TABLES 4 -struct sw_chain { - int n_tables; - struct sw_table *tables[CHAIN_MAX_TABLES]; - struct sw_table *emerg_table; - - struct datapath *dp; - struct module *owner; -}; - -struct sw_chain *chain_create(struct datapath *); -struct sw_flow *chain_lookup(struct sw_chain *, const struct sw_flow_key *, - int); -int chain_insert(struct sw_chain *, struct sw_flow *, int); -int chain_modify(struct sw_chain *, const struct sw_flow_key *, - uint16_t, int, const struct ofp_action_header *, size_t, int); -int chain_has_conflict(struct sw_chain *, const struct sw_flow_key *, - uint16_t, int); -int chain_delete(struct sw_chain *, const struct sw_flow_key *, uint16_t, - uint16_t, int, int); -int chain_timeout(struct sw_chain *); -void chain_destroy(struct sw_chain *); - -int chain_set_hw_hook(struct sw_table *(*create_hw_table)(void), - struct module *owner); -void chain_clear_hw_hook(void); - -#endif /* chain.h */ diff --git a/openflow/datapath/compat.h b/openflow/datapath/compat.h deleted file mode 100644 index 1915cd31..00000000 --- a/openflow/datapath/compat.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef COMPAT_H -#define COMPAT_H 1 - -#include - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) - -#include "compat26.h" - -#endif - -#endif /* compat.h */ diff --git a/openflow/datapath/crc32.c b/openflow/datapath/crc32.c deleted file mode 100644 index 3cb26c5a..00000000 --- a/openflow/datapath/crc32.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Distributed under the terms of the GNU GPL version 2. - * Copyright (c) 2007, 2008 The Board of Trustees of The Leland - * Stanford Junior University - */ - -#include -#include "crc32.h" - -void crc32_init(struct crc32 *crc, unsigned int polynomial) -{ - int i; - - for (i = 0; i < CRC32_TABLE_SIZE; ++i) { - unsigned int reg = i << 24; - int j; - for (j = 0; j < CRC32_TABLE_BITS; j++) { - int topBit = (reg & 0x80000000) != 0; - reg <<= 1; - if (topBit) - reg ^= polynomial; - } - crc->table[i] = reg; - } -} - -EXPORT_SYMBOL(crc32_init); - -unsigned int crc32_calculate(const struct crc32 *crc, - const void *data_, size_t n_bytes) -{ - // FIXME: this can be optimized by unrolling, see linux-2.6/lib/crc32.c. - const uint8_t *data = data_; - unsigned int result = 0; - size_t i; - - for (i = 0; i < n_bytes; i++) { - unsigned int top = result >> 24; - top ^= data[i]; - result = (result << 8) ^ crc->table[top]; - } - return result; -} - -EXPORT_SYMBOL(crc32_calculate); diff --git a/openflow/datapath/crc32.h b/openflow/datapath/crc32.h deleted file mode 100644 index 21a350a9..00000000 --- a/openflow/datapath/crc32.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef CRC32_H -#define CRC32_H 1 - -#include -#ifndef __KERNEL__ -#include -#endif -#include - -#define CRC32_TABLE_BITS 8 -#define CRC32_TABLE_SIZE (1u << CRC32_TABLE_BITS) - -struct crc32 { - unsigned int table[CRC32_TABLE_SIZE]; -}; - -void crc32_init(struct crc32 *, unsigned int polynomial); -unsigned int crc32_calculate(const struct crc32 *, - const void *data_, size_t n_bytes); - - -#endif /* crc32.h */ diff --git a/openflow/datapath/datapath.c b/openflow/datapath/datapath.c deleted file mode 100644 index 5678ea68..00000000 --- a/openflow/datapath/datapath.c +++ /dev/null @@ -1,2137 +0,0 @@ -/* - * Distributed under the terms of the GNU GPL version 2. - * Copyright (c) 2007, 2008, 2009 The Board of Trustees of The Leland - * Stanford Junior University - */ - -/* Functions for managing the dp interface/device. */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "openflow/nicira-ext.h" -#include "openflow/openflow-netlink.h" -#include "datapath.h" -#include "table.h" -#include "chain.h" -#include "dp_dev.h" -#include "forward.h" -#include "flow.h" - -#include "compat.h" - - -/* Strings to describe the manufacturer, hardware, and software. This data - * is queriable through the switch description stats message. */ -static char mfr_desc[DESC_STR_LEN] = "Stanford University"; -static char hw_desc[DESC_STR_LEN] = "Reference Kernelspace Switch"; -static char sw_desc[DESC_STR_LEN] = VERSION BUILDNR; -static char serial_num[SERIAL_NUM_LEN] = "None"; - -module_param_string(mfr_desc, mfr_desc, sizeof mfr_desc, 0444); -module_param_string(hw_desc, hw_desc, sizeof hw_desc, 0444); -module_param_string(sw_desc, sw_desc, sizeof sw_desc, 0444); -module_param_string(serial_num, serial_num, sizeof serial_num, 0444); - -int (*dp_ioctl_hook)(struct net_device *dev, struct ifreq *rq, int cmd); -EXPORT_SYMBOL(dp_ioctl_hook); - -int (*dp_add_dp_hook)(struct datapath *dp); -EXPORT_SYMBOL(dp_add_dp_hook); - -int (*dp_del_dp_hook)(struct datapath *dp); -EXPORT_SYMBOL(dp_del_dp_hook); - -int (*dp_add_if_hook)(struct net_bridge_port *p); -EXPORT_SYMBOL(dp_add_if_hook); - -int (*dp_del_if_hook)(struct net_bridge_port *p); -EXPORT_SYMBOL(dp_del_if_hook); - -/* Number of milliseconds between runs of the maintenance thread. */ -#define MAINT_SLEEP_MSECS 1000 - -static struct genl_family dp_genl_family; - -/* - * Datapath multicast groups. - * - * Really we want one multicast group per in-use datapath (or even more than - * one). Locking issues, however, mean that we can't allocate a multicast - * group at the point in the code where we we actually create a datapath[*], so - * we have to pre-allocate them. It's massive overkill to allocate DP_MAX of - * them in advance, since we will hardly ever actually create DP_MAX datapaths, - * so instead we allocate a few multicast groups at startup and choose one for - * each datapath by hashing its datapath index. - * - * [*] dp_genl_add, to add a new datapath, is called under the genl_lock - * mutex, and genl_register_mc_group, called to acquire a new multicast - * group ID, also acquires genl_lock, thus deadlock. - */ -#define N_MC_GROUPS 16 /* Must be power of 2. */ -static struct genl_multicast_group mc_groups[N_MC_GROUPS]; - -/* Datapaths. Protected on the read side by rcu_read_lock, on the write side - * by dp_mutex. dp_mutex is almost completely redundant with genl_mutex - * maintained by the Generic Netlink code, but the timeout path needs mutual - * exclusion too. - * - * dp_mutex nests inside the RTNL lock: if you need both you must take the RTNL - * lock first. - * - * It is safe to access the datapath and net_bridge_port structures with just - * dp_mutex. - */ -static struct datapath *dps[DP_MAX]; -DEFINE_MUTEX(dp_mutex); -EXPORT_SYMBOL(dp_mutex); - -static int dp_maint_func(void *data); -static void init_port_status(struct net_bridge_port *p); -static int dp_genl_openflow_done(struct netlink_callback *); -static struct net_bridge_port *new_nbp(struct datapath *, - struct net_device *, int port_no); - -/* nla_shrink - reduce amount of space reserved by nla_reserve - * @skb: socket buffer from which to recover room - * @nla: netlink attribute to adjust - * @len: new length of attribute payload - * - * Reduces amount of space reserved by a call to nla_reserve. - * - * No other attributes may be added between calling nla_reserve and this - * function, since it will create a hole in the message. - */ -void nla_shrink(struct sk_buff *skb, struct nlattr *nla, int len) -{ - int delta = nla_total_size(len) - nla_total_size(nla_len(nla)); - BUG_ON(delta > 0); - skb->tail += delta; - skb->len += delta; - nla->nla_len = nla_attr_size(len); -} - -/* Puts a set of openflow headers for a message of the given 'type' into 'skb'. - * If 'sender' is nonnull, then it is used as the message's destination. 'dp' - * must specify the datapath to use. - * - * '*max_openflow_len' receives the maximum number of bytes that are available - * for the embedded OpenFlow message. The caller must call - * resize_openflow_skb() to set the actual size of the message to this number - * of bytes or less. - * - * Returns the openflow header if successful, otherwise (if 'skb' is too small) - * an error code. */ -static void * -put_openflow_headers(struct datapath *dp, struct sk_buff *skb, uint8_t type, - const struct sender *sender, int *max_openflow_len) -{ - struct ofp_header *oh; - struct nlattr *attr; - int openflow_len; - - /* Assemble the Generic Netlink wrapper. */ - if (!genlmsg_put(skb, - sender ? sender->pid : 0, - sender ? sender->seq : 0, - &dp_genl_family, 0, DP_GENL_C_OPENFLOW)) - return ERR_PTR(-ENOBUFS); - if (nla_put_u32(skb, DP_GENL_A_DP_IDX, dp->dp_idx) < 0) - return ERR_PTR(-ENOBUFS); - openflow_len = (skb_tailroom(skb) - NLA_HDRLEN) & ~(NLA_ALIGNTO - 1); - if (openflow_len < sizeof *oh) - return ERR_PTR(-ENOBUFS); - *max_openflow_len = openflow_len; - attr = nla_reserve(skb, DP_GENL_A_OPENFLOW, openflow_len); - BUG_ON(!attr); - - /* Fill in the header. The caller is responsible for the length. */ - oh = nla_data(attr); - oh->version = OFP_VERSION; - oh->type = type; - oh->xid = sender ? sender->xid : 0; - - return oh; -} - -/* Resizes OpenFlow header 'oh', which must be at the tail end of 'skb', to new - * length 'new_length' (in bytes), adjusting pointers and size values as - * necessary. */ -static void -resize_openflow_skb(struct sk_buff *skb, - struct ofp_header *oh, size_t new_length) -{ - struct nlattr *attr = ((void *) oh) - NLA_HDRLEN; - nla_shrink(skb, attr, new_length); - oh->length = htons(new_length); - nlmsg_end(skb, (struct nlmsghdr *) skb->data); -} - -/* Allocates a new skb to contain an OpenFlow message 'openflow_len' bytes in - * length. Returns a null pointer if memory is unavailable, otherwise returns - * the OpenFlow header and stores a pointer to the skb in '*pskb'. - * - * 'type' is the OpenFlow message type. If 'sender' is nonnull, then it is - * used as the message's destination. 'dp' must specify the datapath to - * use. */ -static void * -alloc_openflow_skb(struct datapath *dp, size_t openflow_len, uint8_t type, - const struct sender *sender, struct sk_buff **pskb) -{ - struct ofp_header *oh; - size_t genl_len; - struct sk_buff *skb; - int max_openflow_len; - - if ((openflow_len + sizeof(struct ofp_header)) > UINT16_MAX) { - if (net_ratelimit()) - printk(KERN_ERR "%s: alloc_openflow_skb: openflow " - "message too large: %zu\n", - dp->netdev->name, openflow_len); - return NULL; - } - - genl_len = nlmsg_total_size(GENL_HDRLEN + dp_genl_family.hdrsize); - genl_len += nla_total_size(sizeof(uint32_t)); /* DP_GENL_A_DP_IDX */ - genl_len += nla_total_size(openflow_len); /* DP_GENL_A_OPENFLOW */ - skb = *pskb = genlmsg_new(genl_len, GFP_ATOMIC); - if (!skb) { - return NULL; - } - - oh = put_openflow_headers(dp, skb, type, sender, &max_openflow_len); - BUG_ON(!oh || IS_ERR(oh)); - resize_openflow_skb(skb, oh, openflow_len); - - return oh; -} - -/* Returns the ID of the multicast group used by datapath 'dp'. */ -static u32 -dp_mc_group(const struct datapath *dp) -{ - return mc_groups[dp->dp_idx & (N_MC_GROUPS - 1)].id; -} - -/* Sends 'skb' to 'sender' if it is nonnull, otherwise multicasts 'skb' to all - * listeners. */ -static int -send_openflow_skb(const struct datapath *dp, - struct sk_buff *skb, const struct sender *sender) -{ - return (sender - ? genlmsg_unicast(skb, sender->pid) - : genlmsg_multicast(skb, 0, dp_mc_group(dp), GFP_ATOMIC)); -} - -/* Retrieves the datapath id, which is the MAC address of the "of" device. */ -static -uint64_t get_datapath_id(struct net_device *dev) -{ - uint64_t id = 0; - int i; - - for (i=0; idev_addr[i] << (8*(ETH_ALEN-1 - i)); - - return id; -} - -/* Find the first free datapath index. Return the index or -1 if a free - * index could not be found. */ -int gen_dp_idx(void) -{ - int i; - - for (i=0; i= DP_MAX) - goto err_unlock; - - err = -ENODEV; - if (!try_module_get(THIS_MODULE)) - goto err_unlock; - - /* Exit early if a datapath with that number already exists. */ - err = -EEXIST; - if (dps[dp_idx]) - goto err_put; - - err = -ENOMEM; - dp = kzalloc(sizeof *dp, GFP_KERNEL); - if (dp == NULL) - goto err_put; - - dp->dp_idx = dp_idx; - /* copied from sys_gethostname() */ - u = utsname(); - /* shouldn't need to lock b/c no userspace interactions */ - snprintf(dp->dp_desc, sizeof dp->dp_desc, "%s idx=%d", u->nodename, dp_idx); - - /* Setup our datapath device */ - err = dp_dev_setup(dp, dp_name); - if (err) - goto err_free_dp; - - dp->chain = chain_create(dp); - if (dp->chain == NULL) - goto err_destroy_dp_dev; - INIT_LIST_HEAD(&dp->port_list); - - dp->local_port = new_nbp(dp, dp->netdev, OFPP_LOCAL); - if (IS_ERR(dp->local_port)) { - err = PTR_ERR(dp->local_port); - goto err_destroy_local_port; - } - - dp->flags = 0; - dp->miss_send_len = OFP_DEFAULT_MISS_SEND_LEN; - - dp->dp_task = kthread_run(dp_maint_func, dp, "dp%d", dp_idx); - if (IS_ERR(dp->dp_task)) - goto err_destroy_chain; - - dps[dp_idx] = dp; - mutex_unlock(&dp_mutex); - rtnl_unlock(); - - if (dp_add_dp_hook) - dp_add_dp_hook(dp); - - return 0; - -err_destroy_local_port: - dp_del_switch_port(dp->local_port); -err_destroy_chain: - chain_destroy(dp->chain); -err_destroy_dp_dev: - dp_dev_destroy(dp); -err_free_dp: - kfree(dp); -err_put: - module_put(THIS_MODULE); -err_unlock: - mutex_unlock(&dp_mutex); - rtnl_unlock(); - return err; -} - -/* Find and return a free port number under 'dp'. */ -static int find_portno(struct datapath *dp) -{ - int i; - for (i = 1; i < DP_MAX_PORTS; i++) - if (dp->ports[i] == NULL) - return i; - return -EXFULL; -} - -/* Called with RTNL lock and dp_mutex. */ -static struct net_bridge_port *new_nbp(struct datapath *dp, - struct net_device *dev, int port_no) -{ - struct net_bridge_port *p; - - if (dev->br_port != NULL) - return ERR_PTR(-EBUSY); - - p = kzalloc(sizeof(*p), GFP_KERNEL); - if (p == NULL) - return ERR_PTR(-ENOMEM); - - dev_set_promiscuity(dev, 1); - dev_hold(dev); - p->dp = dp; - p->dev = dev; - p->port_no = port_no; - spin_lock_init(&p->lock); - if (port_no != OFPP_LOCAL) - rcu_assign_pointer(dev->br_port, p); - if (port_no < DP_MAX_PORTS) - rcu_assign_pointer(dp->ports[port_no], p); - list_add_rcu(&p->node, &dp->port_list); - - return p; -} - -/* Called with RTNL lock and dp_mutex. */ -int add_switch_port(struct datapath *dp, struct net_device *dev) -{ - struct net_bridge_port *p; - int port_no; - - if (dev->flags & IFF_LOOPBACK || dev->type != ARPHRD_ETHER - || is_dp_dev(dev)) - return -EINVAL; - - port_no = find_portno(dp); - if (port_no < 0) - return port_no; - - p = new_nbp(dp, dev, port_no); - if (IS_ERR(p)) - return PTR_ERR(p); - - init_port_status(p); - - if (dp_add_if_hook) - dp_add_if_hook(p); - - /* Notify the ctlpath that this port has been added */ - dp_send_port_status(p, OFPPR_ADD); - - return 0; -} - -/* Delete 'p' from switch. - * Called with RTNL lock and dp_mutex. */ -int dp_del_switch_port(struct net_bridge_port *p) -{ - -#if CONFIG_SYSFS - if ((p->port_no != OFPP_LOCAL) && dp_del_if_hook) - sysfs_remove_link(&p->dp->ifobj, p->dev->name); -#endif - - /* First drop references to device. */ - dev_set_promiscuity(p->dev, -1); - list_del_rcu(&p->node); - if (p->port_no != OFPP_LOCAL) - rcu_assign_pointer(p->dp->ports[p->port_no], NULL); - rcu_assign_pointer(p->dev->br_port, NULL); - - /* Then wait until no one is still using it, and destroy it. */ - synchronize_rcu(); - - /* Notify the ctlpath that this port no longer exists */ - dp_send_port_status(p, OFPPR_DELETE); - - if ((p->port_no != OFPP_LOCAL) && dp_del_if_hook) { - dp_del_if_hook(p); - } else { - dev_put(p->dev); - kfree(p); - } - - return 0; -} - -static void del_dp(struct datapath *dp) -{ - struct net_bridge_port *p, *n; - - send_sig(SIGKILL, dp->dp_task, 0); - kthread_stop(dp->dp_task); - - /* Drop references to DP. */ - list_for_each_entry_safe (p, n, &dp->port_list, node) - dp_del_switch_port(p); - - if (dp_del_dp_hook) - dp_del_dp_hook(dp); - - rcu_assign_pointer(dps[dp->dp_idx], NULL); - - /* Kill off local_port dev references from buffered packets that have - * associated dst entries. */ - synchronize_rcu(); - fwd_discard_all(); - - /* Destroy dp->netdev. (Must follow deleting switch ports since - * dp->local_port has a reference to it.) */ - dp_dev_destroy(dp); - - /* Wait until no longer in use, then destroy it. */ - synchronize_rcu(); - chain_destroy(dp->chain); - kfree(dp); - module_put(THIS_MODULE); -} - -static int dp_maint_func(void *data) -{ - struct datapath *dp = (struct datapath *) data; - - allow_signal(SIGKILL); - while (!signal_pending(current)) { - /* Timeout old entries */ - chain_timeout(dp->chain); - msleep_interruptible(MAINT_SLEEP_MSECS); - } - while (!kthread_should_stop()) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule(); - } - return 0; -} - -static void -do_port_input(struct net_bridge_port *p, struct sk_buff *skb) -{ - /* Make our own copy of the packet. Otherwise we will mangle the - * packet for anyone who came before us (e.g. tcpdump via AF_PACKET). - * (No one comes after us, since we tell handle_bridge() that we took - * the packet.) */ - skb = skb_share_check(skb, GFP_ATOMIC); - if (!skb) - return; - - /* Push the Ethernet header back on. */ - skb_push(skb, ETH_HLEN); - skb_reset_mac_header(skb); - fwd_port_input(p->dp->chain, skb, p); -} - -/* - * Used as br_handle_frame_hook. (Cannot run bridge at the same time, even on - * different set of devices!) - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) -/* Called with rcu_read_lock. */ -static struct sk_buff *dp_frame_hook(struct net_bridge_port *p, - struct sk_buff *skb) -{ - do_port_input(p, skb); - return NULL; -} -#else -static int dp_frame_hook(struct net_bridge_port *p, struct sk_buff **pskb) -{ - do_port_input(p, *pskb); - return 1; -} -#endif - -/* Forwarding output path. - * Based on net/bridge/br_forward.c. */ - -static inline unsigned packet_length(const struct sk_buff *skb) -{ - unsigned length = skb->len - ETH_HLEN; - if (skb->protocol == htons(ETH_P_8021Q)) - length -= VLAN_HLEN; - return length; -} - -/* Send packets out all the ports except the originating one. If the - * "flood" argument is set, only send along the minimum spanning tree. - */ -static int -output_all(struct datapath *dp, struct sk_buff *skb, int flood) -{ - u32 disable = flood ? OFPPC_NO_FLOOD : 0; - struct net_bridge_port *p; - int prev_port = -1; - - list_for_each_entry_rcu (p, &dp->port_list, node) { - if (skb->dev == p->dev || p->config & disable) - continue; - if (prev_port != -1) { - struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); - if (!clone) { - kfree_skb(skb); - return -ENOMEM; - } - dp_output_port(dp, clone, prev_port, 0); - } - prev_port = p->port_no; - } - if (prev_port != -1) - dp_output_port(dp, skb, prev_port, 0); - else - kfree_skb(skb); - - return 0; -} - -/* Marks 'skb' as having originated from 'in_port' in 'dp'. - FIXME: how are devices reference counted? */ -void dp_set_origin(struct datapath *dp, uint16_t in_port, - struct sk_buff *skb) -{ - struct net_bridge_port *p; - p = (in_port < DP_MAX_PORTS ? dp->ports[in_port] - : in_port == OFPP_LOCAL ? dp->local_port - : NULL); - if (p) - skb->dev = p->dev; - else - skb->dev = NULL; -} - -int -dp_xmit_skb(struct sk_buff *skb) -{ - struct datapath *dp = skb->dev->br_port->dp; - int len = skb->len; - - if (packet_length(skb) > skb->dev->mtu && !skb_is_gso(skb)) { - printk(KERN_WARNING "%s: dropped over-mtu packet: %d > %d\n", - dp->netdev->name, packet_length(skb), skb->dev->mtu); - kfree_skb(skb); - return -E2BIG; - } - - dev_queue_xmit(skb); - - return len; -} - -/* Takes ownership of 'skb' and transmits it to 'out_port' on 'dp'. - */ -int dp_output_port(struct datapath *dp, struct sk_buff *skb, int out_port, - int ignore_no_fwd) -{ - BUG_ON(!skb); - switch (out_port){ - case OFPP_IN_PORT: - /* Send it out the port it came in on, which is already set in - * the skb. */ - if (!skb->dev) { - if (net_ratelimit()) - printk(KERN_NOTICE "%s: skb device not set " - "forwarding to in_port\n", - dp->netdev->name); - kfree_skb(skb); - return -ESRCH; - } - return dp_xmit_skb(skb); - - case OFPP_TABLE: { - int retval = run_flow_through_tables(dp->chain, skb, - skb->dev->br_port); - if (retval) - kfree_skb(skb); - return retval; - } - - case OFPP_FLOOD: - return output_all(dp, skb, 1); - - case OFPP_ALL: - return output_all(dp, skb, 0); - - case OFPP_CONTROLLER: - return dp_output_control(dp, skb, UINT16_MAX, OFPR_ACTION); - - case OFPP_LOCAL: { - struct net_device *dev = dp->netdev; - return dev ? dp_dev_recv(dev, skb) : -ESRCH; - } - - case 0 ... DP_MAX_PORTS - 1: { - struct net_bridge_port *p = dp->ports[out_port]; - if (p == NULL) - goto bad_port; - if (p->dev == skb->dev) { - /* To send to the input port, must use OFPP_IN_PORT */ - kfree_skb(skb); - if (net_ratelimit()) - printk(KERN_NOTICE "%s: can't directly " - "forward to input port\n", - dp->netdev->name); - return -EINVAL; - } - if (p->config & OFPPC_NO_FWD && !ignore_no_fwd) { - kfree_skb(skb); - return 0; - } - skb->dev = p->dev; - return dp_xmit_skb(skb); - } - - default: - goto bad_port; - } - -bad_port: - kfree_skb(skb); - if (net_ratelimit()) - printk(KERN_NOTICE "%s: can't forward to bad port %d\n", - dp->netdev->name, out_port); - return -ENOENT; -} - -/* Takes ownership of 'skb' and transmits it to 'dp''s control path. 'reason' - * indicates why 'skb' is being sent. 'max_len' sets the maximum number of - * bytes that the caller wants to be sent. - */ -int -dp_output_control(struct datapath *dp, struct sk_buff *skb, - size_t max_len, int reason) -{ - /* FIXME? Can we avoid creating a new skbuff in the case where we - * forward the whole packet? */ - struct sk_buff *f_skb; - struct ofp_packet_in *opi; - size_t fwd_len, opi_len; - uint32_t buffer_id; - int err; - - WARN_ON_ONCE(skb_shared(skb)); - - buffer_id = fwd_save_skb(skb); - - fwd_len = skb->len; - if (buffer_id != (uint32_t) -1) - fwd_len = min(fwd_len, max_len); - - opi_len = offsetof(struct ofp_packet_in, data) + fwd_len; - opi = alloc_openflow_skb(dp, opi_len, OFPT_PACKET_IN, NULL, &f_skb); - if (!opi) { - err = -ENOMEM; - goto out; - } - opi->buffer_id = htonl(buffer_id); - opi->total_len = htons(skb->len); - opi->in_port = htons(skb->dev && skb->dev->br_port - ? skb->dev->br_port->port_no - : OFPP_LOCAL); - opi->reason = reason; - opi->pad = 0; - skb_copy_bits(skb, 0, opi->data, fwd_len); - err = send_openflow_skb(dp, f_skb, NULL); - -out: - kfree_skb(skb); - return err; -} - -static void fill_port_desc(struct net_bridge_port *p, struct ofp_phy_port *desc) -{ - unsigned long flags; - desc->port_no = htons(p->port_no); - strncpy(desc->name, p->dev->name, OFP_MAX_PORT_NAME_LEN); - desc->name[OFP_MAX_PORT_NAME_LEN-1] = '\0'; - memcpy(desc->hw_addr, p->dev->dev_addr, ETH_ALEN); - desc->curr = 0; - desc->supported = 0; - desc->advertised = 0; - desc->peer = 0; - - spin_lock_irqsave(&p->lock, flags); - desc->config = htonl(p->config); - desc->state = htonl(p->state); - spin_unlock_irqrestore(&p->lock, flags); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,24) - if (p->dev->ethtool_ops && p->dev->ethtool_ops->get_settings) { - struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; - - if (!p->dev->ethtool_ops->get_settings(p->dev, &ecmd)) { - /* Set the supported features */ - if (ecmd.supported & SUPPORTED_10baseT_Half) - desc->supported |= OFPPF_10MB_HD; - if (ecmd.supported & SUPPORTED_10baseT_Full) - desc->supported |= OFPPF_10MB_FD; - if (ecmd.supported & SUPPORTED_100baseT_Half) - desc->supported |= OFPPF_100MB_HD; - if (ecmd.supported & SUPPORTED_100baseT_Full) - desc->supported |= OFPPF_100MB_FD; - if (ecmd.supported & SUPPORTED_1000baseT_Half) - desc->supported |= OFPPF_1GB_HD; - if (ecmd.supported & SUPPORTED_1000baseT_Full) - desc->supported |= OFPPF_1GB_FD; - if (ecmd.supported & SUPPORTED_10000baseT_Full) - desc->supported |= OFPPF_10GB_FD; - if (ecmd.supported & SUPPORTED_TP) - desc->supported |= OFPPF_COPPER; - if (ecmd.supported & SUPPORTED_FIBRE) - desc->supported |= OFPPF_FIBER; - if (ecmd.supported & SUPPORTED_Autoneg) - desc->supported |= OFPPF_AUTONEG; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14) - if (ecmd.supported & SUPPORTED_Pause) - desc->supported |= OFPPF_PAUSE; - if (ecmd.supported & SUPPORTED_Asym_Pause) - desc->supported |= OFPPF_PAUSE_ASYM; -#endif /* kernel >= 2.6.14 */ - - /* Set the advertised features */ - if (ecmd.advertising & ADVERTISED_10baseT_Half) - desc->advertised |= OFPPF_10MB_HD; - if (ecmd.advertising & ADVERTISED_10baseT_Full) - desc->advertised |= OFPPF_10MB_FD; - if (ecmd.advertising & ADVERTISED_100baseT_Half) - desc->advertised |= OFPPF_100MB_HD; - if (ecmd.advertising & ADVERTISED_100baseT_Full) - desc->advertised |= OFPPF_100MB_FD; - if (ecmd.advertising & ADVERTISED_1000baseT_Half) - desc->advertised |= OFPPF_1GB_HD; - if (ecmd.advertising & ADVERTISED_1000baseT_Full) - desc->advertised |= OFPPF_1GB_FD; - if (ecmd.advertising & ADVERTISED_10000baseT_Full) - desc->advertised |= OFPPF_10GB_FD; - if (ecmd.advertising & ADVERTISED_TP) - desc->advertised |= OFPPF_COPPER; - if (ecmd.advertising & ADVERTISED_FIBRE) - desc->advertised |= OFPPF_FIBER; - if (ecmd.advertising & ADVERTISED_Autoneg) - desc->advertised |= OFPPF_AUTONEG; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14) - if (ecmd.advertising & ADVERTISED_Pause) - desc->advertised |= OFPPF_PAUSE; - if (ecmd.advertising & ADVERTISED_Asym_Pause) - desc->advertised |= OFPPF_PAUSE_ASYM; -#endif /* kernel >= 2.6.14 */ - - /* Set the current features */ - if (ecmd.speed == SPEED_10) - desc->curr = (ecmd.duplex) ? OFPPF_10MB_FD : OFPPF_10MB_HD; - else if (ecmd.speed == SPEED_100) - desc->curr = (ecmd.duplex) ? OFPPF_100MB_FD : OFPPF_100MB_HD; - else if (ecmd.speed == SPEED_1000) - desc->curr = (ecmd.duplex) ? OFPPF_1GB_FD : OFPPF_1GB_HD; - else if (ecmd.speed == SPEED_10000) - desc->curr = OFPPF_10GB_FD; - - if (ecmd.port == PORT_TP) - desc->curr |= OFPPF_COPPER; - else if (ecmd.port == PORT_FIBRE) - desc->curr |= OFPPF_FIBER; - - if (ecmd.autoneg) - desc->curr |= OFPPF_AUTONEG; - } - } -#endif - desc->curr = htonl(desc->curr); - desc->supported = htonl(desc->supported); - desc->advertised = htonl(desc->advertised); - desc->peer = htonl(desc->peer); -} - -static int -fill_features_reply(struct datapath *dp, struct ofp_switch_features *ofr) -{ - struct net_bridge_port *p; - uint64_t dpid = get_datapath_id(dp->netdev); - int port_count = 0; - - ofr->datapath_id = cpu_to_be64(dpid); - - ofr->n_buffers = htonl(N_PKT_BUFFERS); - ofr->n_tables = dp->chain->n_tables; - ofr->capabilities = htonl(OFP_SUPPORTED_CAPABILITIES); - ofr->actions = htonl(OFP_SUPPORTED_ACTIONS); - memset(ofr->pad, 0, sizeof ofr->pad); - - list_for_each_entry_rcu (p, &dp->port_list, node) { - fill_port_desc(p, &ofr->ports[port_count]); - port_count++; - } - - return port_count; -} - -int -dp_send_features_reply(struct datapath *dp, const struct sender *sender) -{ - struct sk_buff *skb; - struct ofp_switch_features *ofr; - size_t ofr_len, port_max_len; - int port_count; - - /* Overallocate. */ - port_max_len = sizeof(struct ofp_phy_port) * DP_MAX_PORTS; - ofr = alloc_openflow_skb(dp, sizeof(*ofr) + port_max_len, - OFPT_FEATURES_REPLY, sender, &skb); - if (!ofr) - return -ENOMEM; - - /* Fill. */ - port_count = fill_features_reply(dp, ofr); - - /* Shrink to fit. */ - ofr_len = sizeof(*ofr) + (sizeof(struct ofp_phy_port) * port_count); - resize_openflow_skb(skb, &ofr->header, ofr_len); - return send_openflow_skb(dp, skb, sender); -} - -int -dp_send_config_reply(struct datapath *dp, const struct sender *sender) -{ - struct sk_buff *skb; - struct ofp_switch_config *osc; - - osc = alloc_openflow_skb(dp, sizeof *osc, OFPT_GET_CONFIG_REPLY, sender, - &skb); - if (!osc) - return -ENOMEM; - - osc->flags = htons(dp->flags); - osc->miss_send_len = htons(dp->miss_send_len); - - return send_openflow_skb(dp, skb, sender); -} - -int -dp_send_hello(struct datapath *dp, const struct sender *sender, - const struct ofp_header *request) -{ - if (request->version < OFP_VERSION) { - char err[64]; - sprintf(err, "Only version 0x%02x supported", OFP_VERSION); - dp_send_error_msg(dp, sender, OFPET_HELLO_FAILED, - OFPHFC_INCOMPATIBLE, err, strlen(err)); - return -EINVAL; - } else { - struct sk_buff *skb; - struct ofp_header *reply; - - reply = alloc_openflow_skb(dp, sizeof *reply, - OFPT_HELLO, sender, &skb); - if (!reply) - return -ENOMEM; - - return send_openflow_skb(dp, skb, sender); - } -} - -int -dp_send_barrier_reply(struct datapath *dp, const struct sender *sender, - const struct ofp_header *request) -{ - struct sk_buff *skb; - struct ofp_header *reply; - - reply = alloc_openflow_skb(dp, sizeof *reply, - OFPT_BARRIER_REPLY, sender, &skb); - if (!reply) - return -ENOMEM; - - return send_openflow_skb(dp, skb, sender); -} - -int -dp_update_port_flags(struct datapath *dp, const struct ofp_port_mod *opm) -{ - unsigned long int flags; - int port_no = ntohs(opm->port_no); - struct net_bridge_port *p; - p = (port_no < DP_MAX_PORTS ? dp->ports[port_no] - : port_no == OFPP_LOCAL ? dp->local_port - : NULL); - - /* Make sure the port id hasn't changed since this was sent */ - if (!p || memcmp(opm->hw_addr, p->dev->dev_addr, ETH_ALEN)) - return -1; - - spin_lock_irqsave(&p->lock, flags); - if (opm->mask) { - uint32_t config_mask = ntohl(opm->mask); - p->config &= ~config_mask; - p->config |= ntohl(opm->config) & config_mask; - } - spin_unlock_irqrestore(&p->lock, flags); - - return 0; -} - -/* Initialize the port status field of the bridge port. */ -static void -init_port_status(struct net_bridge_port *p) -{ - unsigned long int flags; - - spin_lock_irqsave(&p->lock, flags); - - if (p->dev->flags & IFF_UP) - p->config &= ~OFPPC_PORT_DOWN; - else - p->config |= OFPPC_PORT_DOWN; - - if (netif_carrier_ok(p->dev)) - p->state &= ~OFPPS_LINK_DOWN; - else - p->state |= OFPPS_LINK_DOWN; - - spin_unlock_irqrestore(&p->lock, flags); -} - -int -dp_send_port_status(struct net_bridge_port *p, uint8_t status) -{ - struct sk_buff *skb; - struct ofp_port_status *ops; - - ops = alloc_openflow_skb(p->dp, sizeof *ops, OFPT_PORT_STATUS, NULL, - &skb); - if (!ops) - return -ENOMEM; - ops->reason = status; - memset(ops->pad, 0, sizeof ops->pad); - fill_port_desc(p, &ops->desc); - - return send_openflow_skb(p->dp, skb, NULL); -} - -/* Convert jiffies_64 to seconds. */ -static u32 inline jiffies_64_to_secs(u64 j) -{ - /* Call to do_div is necessary as we can't do a 64-bit division in a - * 32-bit kernel (at least not without linking to libgcc) */ - do_div(j, HZ); - return j; -} - -/* Convert jiffies_64 to just the nanosec part between seconds. */ -static u32 inline jiffies_64_to_nsecs(u64 j) -{ - /* Call to do_div is necessary as we can't do a 64-bit division in a - * 32-bit kernel (at least not without linking to libgcc) */ - return (j - jiffies_64_to_secs(j)); -} - -int -dp_send_flow_end(struct datapath *dp, struct sw_flow *flow, - enum ofp_flow_removed_reason reason) -{ - struct sk_buff *skb; - struct ofp_flow_removed *ofr; - - if (!flow->send_flow_rem) - return 0; - - if (flow->emerg_flow) - return 0; - - ofr = alloc_openflow_skb(dp, sizeof *ofr, OFPT_FLOW_REMOVED, 0, &skb); - if (!ofr) - return -ENOMEM; - - flow_fill_match(&ofr->match, &flow->key); - - ofr->priority = htons(flow->priority); - ofr->reason = reason; - - ofr->duration_sec = htonl(jiffies_64_to_secs(get_jiffies_64()-flow->created)); - ofr->duration_nsec = htonl(jiffies_64_to_nsecs(get_jiffies_64()-flow->created)); - ofr->idle_timeout = htons(flow->idle_timeout); - - ofr->packet_count = cpu_to_be64(flow->packet_count); - ofr->byte_count = cpu_to_be64(flow->byte_count); - - return send_openflow_skb(dp, skb, NULL); -} -EXPORT_SYMBOL(dp_send_flow_end); - -int -dp_send_error_msg(struct datapath *dp, const struct sender *sender, - uint16_t type, uint16_t code, const void *data, size_t len) -{ - struct sk_buff *skb; - struct ofp_error_msg *oem; - - - oem = alloc_openflow_skb(dp, sizeof(*oem)+len, OFPT_ERROR, - sender, &skb); - if (!oem) - return -ENOMEM; - - oem->type = htons(type); - oem->code = htons(code); - memcpy(oem->data, data, len); - - return send_openflow_skb(dp, skb, sender); -} - -int -dp_send_echo_reply(struct datapath *dp, const struct sender *sender, - const struct ofp_header *rq) -{ - struct sk_buff *skb; - struct ofp_header *reply; - - reply = alloc_openflow_skb(dp, ntohs(rq->length), OFPT_ECHO_REPLY, - sender, &skb); - if (!reply) - return -ENOMEM; - - memcpy(reply + 1, rq + 1, ntohs(rq->length) - sizeof *rq); - return send_openflow_skb(dp, skb, sender); -} - -/* Generic Netlink interface. - * - * See netlink(7) for an introduction to netlink. See - * http://linux-net.osdl.org/index.php/Netlink for more information and - * pointers on how to work with netlink and Generic Netlink in the kernel and - * in userspace. */ - -static struct genl_family dp_genl_family = { - .id = GENL_ID_GENERATE, - .hdrsize = 0, - .name = DP_GENL_FAMILY_NAME, - .version = 1, - .maxattr = DP_GENL_A_MAX, -}; - -/* Attribute policy: what each attribute may contain. */ -static struct nla_policy dp_genl_policy[DP_GENL_A_MAX + 1] = { - [DP_GENL_A_DP_IDX] = { .type = NLA_U32 }, - [DP_GENL_A_DP_NAME] = { .type = NLA_NUL_STRING }, - [DP_GENL_A_MC_GROUP] = { .type = NLA_U32 }, - [DP_GENL_A_PORTNAME] = { .type = NLA_NUL_STRING } -}; - -static int dp_genl_add(struct sk_buff *skb, struct genl_info *info) -{ - int dp_idx = info->attrs[DP_GENL_A_DP_IDX] ? - nla_get_u32(info->attrs[DP_GENL_A_DP_IDX]) : -1; - const char *dp_name = info->attrs[DP_GENL_A_DP_NAME] ? - nla_data(info->attrs[DP_GENL_A_DP_NAME]) : NULL; - - if (VERIFY_NUL_STRING(info->attrs[DP_GENL_A_DP_NAME])) - return -EINVAL; - - if ((dp_idx == -1) && (!dp_name)) - return -EINVAL; - - return new_dp(dp_idx, dp_name); -} - -static struct genl_ops dp_genl_ops_add_dp = { - .cmd = DP_GENL_C_ADD_DP, - .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ - .policy = dp_genl_policy, - .doit = dp_genl_add, - .dumpit = NULL, -}; - -/* Must be called with rcu_read_lock or dp_mutex. */ -struct datapath *dp_get_by_idx(int dp_idx) -{ - if (dp_idx < 0 || dp_idx >= DP_MAX) - return NULL; - return rcu_dereference(dps[dp_idx]); -} -EXPORT_SYMBOL(dp_get_by_idx); - -/* Must be called with rcu_read_lock or dp_mutex. */ -struct datapath *dp_get_by_name(const char *dp_name) -{ - int i; - for (i=0; inetdev->name, dp_name)) - return dp; - } - return NULL; -} - -/* Must be called with rcu_read_lock or dp_mutex. */ -static struct datapath * -lookup_dp(struct genl_info *info) -{ - int dp_idx = info->attrs[DP_GENL_A_DP_IDX] ? - nla_get_u32(info->attrs[DP_GENL_A_DP_IDX]) : -1; - const char *dp_name = info->attrs[DP_GENL_A_DP_NAME] ? - nla_data(info->attrs[DP_GENL_A_DP_NAME]) : NULL; - - if (VERIFY_NUL_STRING(info->attrs[DP_GENL_A_DP_NAME])) - return ERR_PTR(-EINVAL); - - if (dp_idx != -1) { - struct datapath *dp = dp_get_by_idx(dp_idx); - if (!dp) - return ERR_PTR(-ENOENT); - else if (dp_name && strcmp(dp->netdev->name, dp_name)) - return ERR_PTR(-EINVAL); - else - return dp; - } else if (dp_name) { - struct datapath *dp = dp_get_by_name(dp_name); - return dp ? dp : ERR_PTR(-ENOENT); - } else { - return ERR_PTR(-EINVAL); - } -} - -static int dp_genl_del(struct sk_buff *skb, struct genl_info *info) -{ - struct net_device *dev = NULL; - struct datapath *dp; - int err; - - rtnl_lock(); - mutex_lock(&dp_mutex); - dp = lookup_dp(info); - if (IS_ERR(dp)) - err = PTR_ERR(dp); - else { - dev = dp->netdev; - del_dp(dp); - err = 0; - } - mutex_unlock(&dp_mutex); - rtnl_unlock(); - if (dev) - free_netdev(dev); - return err; -} - -static struct genl_ops dp_genl_ops_del_dp = { - .cmd = DP_GENL_C_DEL_DP, - .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ - .policy = dp_genl_policy, - .doit = dp_genl_del, - .dumpit = NULL, -}; - -/* Queries a datapath for related information. Currently the only relevant - * information is the datapath's multicast group ID, datapath ID, and - * datapath device name. */ -static int dp_genl_query(struct sk_buff *skb, struct genl_info *info) -{ - struct datapath *dp; - struct sk_buff *ans_skb = NULL; - int err; - - rcu_read_lock(); - dp = lookup_dp(info); - if (IS_ERR(dp)) - err = PTR_ERR(dp); - else { - void *data; - ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); - if (!ans_skb) { - err = -ENOMEM; - goto err; - } - err = -ENOMEM; - data = genlmsg_put_reply(ans_skb, info, &dp_genl_family, - 0, DP_GENL_C_QUERY_DP); - if (data == NULL) - goto err; - NLA_PUT_U32(ans_skb, DP_GENL_A_DP_IDX, dp->dp_idx); - NLA_PUT_STRING(ans_skb, DP_GENL_A_DP_NAME, dp->netdev->name); - NLA_PUT_U32(ans_skb, DP_GENL_A_MC_GROUP, dp_mc_group(dp)); - - genlmsg_end(ans_skb, data); - err = genlmsg_reply(ans_skb, info); - ans_skb = NULL; - } -err: -nla_put_failure: - kfree_skb(ans_skb); - rcu_read_unlock(); - return err; -} - -static struct genl_ops dp_genl_ops_query_dp = { - .cmd = DP_GENL_C_QUERY_DP, - .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ - .policy = dp_genl_policy, - .doit = dp_genl_query, - .dumpit = NULL, -}; - -static int dp_genl_add_del_port(struct sk_buff *skb, struct genl_info *info) -{ - struct datapath *dp; - struct net_device *port; - int err; - - if (!info->attrs[DP_GENL_A_PORTNAME] || - VERIFY_NUL_STRING(info->attrs[DP_GENL_A_PORTNAME])) - return -EINVAL; - - rtnl_lock(); - mutex_lock(&dp_mutex); - - /* Get datapath. */ - dp = lookup_dp(info); - if (IS_ERR(dp)) { - err = PTR_ERR(dp); - goto out_unlock; - } - - /* Get interface to add/remove. */ - port = dev_get_by_name(&init_net, - nla_data(info->attrs[DP_GENL_A_PORTNAME])); - if (!port) { - err = -ENOENT; - goto out_unlock; - } - - /* Execute operation. */ - if (info->genlhdr->cmd == DP_GENL_C_ADD_PORT) - err = add_switch_port(dp, port); - else { - if (port->br_port == NULL || port->br_port->dp != dp) { - err = -ENOENT; - goto out_put; - } - err = dp_del_switch_port(port->br_port); - } - -out_put: - dev_put(port); -out_unlock: - mutex_unlock(&dp_mutex); - rtnl_unlock(); - return err; -} - -static struct genl_ops dp_genl_ops_add_port = { - .cmd = DP_GENL_C_ADD_PORT, - .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ - .policy = dp_genl_policy, - .doit = dp_genl_add_del_port, - .dumpit = NULL, -}; - -static struct genl_ops dp_genl_ops_del_port = { - .cmd = DP_GENL_C_DEL_PORT, - .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ - .policy = dp_genl_policy, - .doit = dp_genl_add_del_port, - .dumpit = NULL, -}; - -static int dp_genl_openflow(struct sk_buff *skb, struct genl_info *info) -{ - struct nlattr *va = info->attrs[DP_GENL_A_OPENFLOW]; - struct datapath *dp; - struct ofp_header *oh; - struct sender sender; - int err; - - if (!info->attrs[DP_GENL_A_DP_IDX] || !va) - return -EINVAL; - - dp = dp_get_by_idx(nla_get_u32(info->attrs[DP_GENL_A_DP_IDX])); - if (!dp) - return -ENOENT; - - if (nla_len(va) < sizeof(struct ofp_header)) - return -EINVAL; - oh = nla_data(va); - - sender.xid = oh->xid; - sender.pid = info->snd_pid; - sender.seq = info->snd_seq; - - mutex_lock(&dp_mutex); - err = fwd_control_input(dp->chain, &sender, - nla_data(va), nla_len(va)); - mutex_unlock(&dp_mutex); - return err; -} - -static struct nla_policy dp_genl_openflow_policy[DP_GENL_A_MAX + 1] = { - [DP_GENL_A_DP_IDX] = { .type = NLA_U32 }, -}; - -static int desc_stats_dump(struct datapath *dp, void *state, - void *body, int *body_len) -{ - struct ofp_desc_stats *ods = body; - int n_bytes = sizeof *ods; - - if (n_bytes > *body_len) { - return -ENOBUFS; - } - *body_len = n_bytes; - - strncpy(ods->mfr_desc, mfr_desc, sizeof ods->mfr_desc); - strncpy(ods->hw_desc, hw_desc, sizeof ods->hw_desc); - strncpy(ods->sw_desc, sw_desc, sizeof ods->sw_desc); - strncpy(ods->dp_desc, dp->dp_desc, sizeof ods->dp_desc); - strncpy(ods->serial_num, serial_num, sizeof ods->serial_num); - - return 0; -} - -struct flow_stats_state { - int table_idx; - struct sw_table_position position; - const struct ofp_flow_stats_request *rq; - - void *body; - int bytes_used, bytes_allocated; -}; - -#define EMERG_TABLE_ID_FOR_STATS 0xfe - -static int flow_stats_init(struct datapath *dp, const void *body, int body_len, - void **state) -{ - const struct ofp_flow_stats_request *fsr = body; - struct flow_stats_state *s = kmalloc(sizeof *s, GFP_ATOMIC); - if (!s) - return -ENOMEM; - s->table_idx = fsr->table_id == 0xff ? 0 : fsr->table_id; - memset(&s->position, 0, sizeof s->position); - s->rq = fsr; - *state = s; - return 0; -} - -static int flow_stats_dump_callback(struct sw_flow *flow, void *private) -{ - struct sw_flow_actions *sf_acts = rcu_dereference(flow->sf_acts); - struct flow_stats_state *s = private; - struct ofp_flow_stats *ofs; - int length; - uint64_t duration; - - length = sizeof *ofs + sf_acts->actions_len; - if (length + s->bytes_used > s->bytes_allocated) - return 1; - - ofs = s->body + s->bytes_used; - ofs->length = htons(length); - ofs->table_id = s->table_idx; - ofs->pad = 0; - ofs->match.wildcards = htonl(flow->key.wildcards); - ofs->match.in_port = flow->key.in_port; - memcpy(ofs->match.dl_src, flow->key.dl_src, ETH_ALEN); - memcpy(ofs->match.dl_dst, flow->key.dl_dst, ETH_ALEN); - ofs->match.dl_vlan = flow->key.dl_vlan; - ofs->match.dl_type = flow->key.dl_type; - ofs->match.nw_tos = flow->key.nw_tos; - ofs->match.nw_proto = flow->key.nw_proto; - ofs->match.nw_src = flow->key.nw_src; - ofs->match.nw_dst = flow->key.nw_dst; - ofs->match.dl_vlan_pcp = flow->key.dl_vlan_pcp; - ofs->match.tp_src = flow->key.tp_src; - ofs->match.tp_dst = flow->key.tp_dst; - - /* The kernel doesn't support 64-bit division, so use the 'do_div' - * macro instead. The first argument is replaced with the quotient, - * while the remainder is the return value. */ - duration = get_jiffies_64() - flow->created; - do_div(duration, HZ); - ofs->duration_sec = htonl(jiffies_64_to_secs(duration)); - ofs->duration_nsec = htonl(jiffies_64_to_nsecs(duration)); - - ofs->priority = htons(flow->priority); - ofs->idle_timeout = htons(flow->idle_timeout); - ofs->hard_timeout = htons(flow->hard_timeout); - memset(&ofs->pad2, 0, sizeof ofs->pad2); - ofs->packet_count = cpu_to_be64(flow->packet_count); - ofs->byte_count = cpu_to_be64(flow->byte_count); - memcpy(ofs->actions, sf_acts->actions, sf_acts->actions_len); - - s->bytes_used += length; - return 0; -} - -static int flow_stats_dump(struct datapath *dp, void *state, - void *body, int *body_len) -{ - struct flow_stats_state *s = state; - struct sw_flow_key match_key; - int error = 0; - - s->bytes_used = 0; - s->bytes_allocated = *body_len; - s->body = body; - - flow_extract_match(&match_key, &s->rq->match); - if (s->rq->table_id == EMERG_TABLE_ID_FOR_STATS) { - struct sw_table *table = dp->chain->emerg_table; - - error = table->iterate(table, &match_key, s->rq->out_port, - &s->position, flow_stats_dump_callback, - s); - } else { - while (s->table_idx < dp->chain->n_tables - && (s->rq->table_id == 0xff - || s->rq->table_id == s->table_idx)) { - struct sw_table *table = dp->chain->tables[s->table_idx]; - - error = table->iterate(table, &match_key, - s->rq->out_port, &s->position, - flow_stats_dump_callback, s); - if (error) - break; - - s->table_idx++; - memset(&s->position, 0, sizeof s->position); - } - } - *body_len = s->bytes_used; - - /* If error is 0, we're done. - * Otherwise, if some bytes were used, there are more flows to come. - * Otherwise, we were not able to fit even a single flow in the body, - * which indicates that we have a single flow with too many actions to - * fit. We won't ever make any progress at that rate, so give up. */ - return !error ? 0 : s->bytes_used ? 1 : -ENOMEM; -} - -static void flow_stats_done(void *state) -{ - kfree(state); -} - -static int aggregate_stats_init(struct datapath *dp, - const void *body, int body_len, - void **state) -{ - *state = (void *)body; - return 0; -} - -static int aggregate_stats_dump_callback(struct sw_flow *flow, void *private) -{ - struct ofp_aggregate_stats_reply *rpy = private; - rpy->packet_count += flow->packet_count; - rpy->byte_count += flow->byte_count; - rpy->flow_count++; - return 0; -} - -static int aggregate_stats_dump(struct datapath *dp, void *state, - void *body, int *body_len) -{ - struct ofp_aggregate_stats_request *rq = state; - struct ofp_aggregate_stats_reply *rpy; - struct sw_table_position position; - struct sw_flow_key match_key; - int table_idx; - int error = 0; - - if (*body_len < sizeof *rpy) - return -ENOBUFS; - rpy = body; - *body_len = sizeof *rpy; - - memset(rpy, 0, sizeof *rpy); - - flow_extract_match(&match_key, &rq->match); - table_idx = rq->table_id == 0xff ? 0 : rq->table_id; - memset(&position, 0, sizeof position); - - if (rq->table_id == EMERG_TABLE_ID_FOR_STATS) { - struct sw_table *table = dp->chain->emerg_table; - - error = table->iterate(table, &match_key, rq->out_port, - &position, - aggregate_stats_dump_callback, rpy); - if (error) - return error; - } else { - while (table_idx < dp->chain->n_tables - && (rq->table_id == 0xff || rq->table_id == table_idx)) { - struct sw_table *table = dp->chain->tables[table_idx]; - - error = table->iterate(table, &match_key, rq->out_port, - &position, - aggregate_stats_dump_callback, - rpy); - if (error) - return error; - - table_idx++; - memset(&position, 0, sizeof position); - } - } - - rpy->packet_count = cpu_to_be64(rpy->packet_count); - rpy->byte_count = cpu_to_be64(rpy->byte_count); - rpy->flow_count = htonl(rpy->flow_count); - return 0; -} - -static int table_stats_dump(struct datapath *dp, void *state, - void *body, int *body_len) -{ - struct ofp_table_stats *ots; - int n_bytes = dp->chain->n_tables * sizeof *ots; - int i; - if (n_bytes > *body_len) - return -ENOBUFS; - *body_len = n_bytes; - for (i = 0, ots = body; i < dp->chain->n_tables; i++, ots++) { - struct sw_table_stats stats; - dp->chain->tables[i]->stats(dp->chain->tables[i], &stats); - strncpy(ots->name, stats.name, sizeof ots->name); - ots->table_id = i; - ots->wildcards = htonl(stats.wildcards); - memset(ots->pad, 0, sizeof ots->pad); - ots->max_entries = htonl(stats.max_flows); - ots->active_count = htonl(stats.n_flows); - ots->lookup_count = cpu_to_be64(stats.n_lookup); - ots->matched_count = cpu_to_be64(stats.n_matched); - } - return 0; -} - -struct port_stats_state { - int start_port; /* port to start dumping from */ - int port_no; /* from ofp_port_stats_request */ -}; - -static int port_stats_init(struct datapath *dp, const void *body, int body_len, - void **state) -{ - struct port_stats_state *s = kmalloc(sizeof *s, GFP_ATOMIC); - struct ofp_port_stats_request *psr - = (struct ofp_port_stats_request *)body; - - if (!s) - return -ENOMEM; - s->start_port = 1; - s->port_no = ntohs(psr->port_no); - *state = s; - return 0; -} - -static void -dump_port_stats(struct ofp_port_stats *ops, struct net_bridge_port *p) -{ - struct net_device_stats *stats; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) - stats = p->dev->netdev_ops->ndo_get_stats(p->dev); -#else - stats = p->dev->get_stats(p->dev); -#endif - ops->port_no = htons(p->port_no); - memset(ops->pad, 0, sizeof ops->pad); - ops->rx_packets = cpu_to_be64(stats->rx_packets); - ops->tx_packets = cpu_to_be64(stats->tx_packets); - ops->rx_bytes = cpu_to_be64(stats->rx_bytes); - ops->tx_bytes = cpu_to_be64(stats->tx_bytes); - ops->rx_dropped = cpu_to_be64(stats->rx_dropped); - ops->tx_dropped = cpu_to_be64(stats->tx_dropped); - ops->rx_errors = cpu_to_be64(stats->rx_errors); - ops->tx_errors = cpu_to_be64(stats->tx_errors); - ops->rx_frame_err = cpu_to_be64(stats->rx_frame_errors); - ops->rx_over_err = cpu_to_be64(stats->rx_over_errors); - ops->rx_crc_err = cpu_to_be64(stats->rx_crc_errors); - ops->collisions = cpu_to_be64(stats->collisions); -} - -static struct net_bridge_port * -lookup_port(struct datapath *dp, uint16_t port_no) -{ - return (port_no < DP_MAX_PORTS ? dp->ports[port_no] - : port_no == OFPP_LOCAL ? dp->local_port - : NULL); -} - - -static int port_stats_dump(struct datapath *dp, void *state, - void *body, int *body_len) -{ - struct port_stats_state *s = state; - struct net_bridge_port *p = NULL; - struct ofp_port_stats *ops = NULL; - int n_ports = 0; - int max_ports = 0; - int i = 0; - - max_ports = *body_len / sizeof *ops; - if (!max_ports) - return -ENOMEM; - ops = body; - - if (s->port_no == OFPP_NONE) { - for (i = s->start_port; i < DP_MAX_PORTS && n_ports < max_ports; - i++) { - p = dp->ports[i]; - if (!p) - continue; - dump_port_stats(ops, p); - n_ports++; - ops++; - } - s->start_port = i; - if (dp->local_port) { - dump_port_stats(ops, dp->local_port); - n_ports++; - ops++; - s->start_port = OFPP_LOCAL + 1; /* == OFPP_NONE, > DP_MAX_PORTS */ - } - } else { - p = lookup_port(dp, s->port_no); - if (p) { - dump_port_stats(ops, p); - n_ports++; - ops++; - } - } - - *body_len = n_ports * sizeof *ops; - return n_ports >= max_ports; -} - -static void port_stats_done(void *state) -{ - kfree(state); -} - -/* - * We don't define any vendor_stats_state, we let the actual - * vendor implementation do that. - * The only requirement is that the first member of that object - * should be the vendor id. - * Jean II - * - * Basically, it would look like : - * struct acme_stats_state { - * uint32_t vendor; // ACME_VENDOR_ID. - * <...> // Other stuff. - * }; - */ -static int vendor_stats_init(struct datapath *dp, const void *body, - int body_len, void **state) -{ - /* min_body was checked, this is safe */ - const uint32_t vendor = ntohl(*((uint32_t *)body)); - int err; - - switch (vendor) { - default: - err = -EINVAL; - } - - return err; -} - -static int vendor_stats_dump(struct datapath *dp, void *state, void *body, - int *body_len) -{ - const uint32_t vendor = *((uint32_t *)state); - int newbuf; - - switch (vendor) { - default: - /* Should never happen */ - newbuf = 0; - } - - return newbuf; -} - -static void vendor_stats_done(void *state) -{ - const uint32_t vendor = *((uint32_t *)state); - - switch (vendor) { - default: - /* Should never happen */ - kfree(state); - } - - return; -} - -struct stats_type { - /* Minimum and maximum acceptable number of bytes in body member of - * struct ofp_stats_request. */ - size_t min_body, max_body; - - /* Prepares to dump some kind of statistics on 'dp'. 'body' and - * 'body_len' are the 'body' member of the struct ofp_stats_request. - * Returns zero if successful, otherwise a negative error code. - * May initialize '*state' to state information. May be null if no - * initialization is required.*/ - int (*init)(struct datapath *dp, const void *body, int body_len, - void **state); - - /* Dumps statistics for 'dp' into the '*body_len' bytes at 'body', and - * modifies '*body_len' to reflect the number of bytes actually used. - * ('body' will be transmitted as the 'body' member of struct - * ofp_stats_reply.) */ - int (*dump)(struct datapath *dp, void *state, - void *body, int *body_len); - - /* Cleans any state created by the init or dump functions. May be null - * if no cleanup is required. */ - void (*done)(void *state); -}; - -static const struct stats_type stats[] = { - [OFPST_DESC] = { - 0, - 0, - NULL, - desc_stats_dump, - NULL - }, - [OFPST_FLOW] = { - sizeof(struct ofp_flow_stats_request), - sizeof(struct ofp_flow_stats_request), - flow_stats_init, - flow_stats_dump, - flow_stats_done - }, - [OFPST_AGGREGATE] = { - sizeof(struct ofp_aggregate_stats_request), - sizeof(struct ofp_aggregate_stats_request), - aggregate_stats_init, - aggregate_stats_dump, - NULL - }, - [OFPST_TABLE] = { - 0, - 0, - NULL, - table_stats_dump, - NULL - }, - [OFPST_PORT] = { - sizeof(struct ofp_port_stats_request), - sizeof(struct ofp_port_stats_request), - port_stats_init, - port_stats_dump, - port_stats_done - }, -}; - -/* For OFPST_VENDOR... Jean II */ -static const struct stats_type stats_vendor = { - 8, /* vendor + subtype */ - 32, /* whatever */ - vendor_stats_init, - vendor_stats_dump, - vendor_stats_done -}; - -static int -dp_genl_openflow_dumpit(struct sk_buff *skb, struct netlink_callback *cb) -{ - struct datapath *dp; - struct sender sender; - const struct stats_type *s; - struct ofp_stats_reply *osr; - int dp_idx; - int max_openflow_len, body_len; - void *body; - int err; - - /* Set up the cleanup function for this dump. Linux 2.6.20 and later - * support setting up cleanup functions via the .doneit member of - * struct genl_ops. This kluge supports earlier versions also. */ - cb->done = dp_genl_openflow_done; - - sender.pid = NETLINK_CB(cb->skb).pid; - sender.seq = cb->nlh->nlmsg_seq; - if (!cb->args[0]) { - struct nlattr *attrs[DP_GENL_A_MAX + 1]; - struct ofp_stats_request *rq; - struct nlattr *va; - size_t len, body_len; - int type; - - err = nlmsg_parse(cb->nlh, GENL_HDRLEN, attrs, DP_GENL_A_MAX, - dp_genl_openflow_policy); - if (err < 0) - return err; - - if (!attrs[DP_GENL_A_DP_IDX]) - return -EINVAL; - dp_idx = nla_get_u16(attrs[DP_GENL_A_DP_IDX]); - dp = dp_get_by_idx(dp_idx); - if (!dp) - return -ENOENT; - - va = attrs[DP_GENL_A_OPENFLOW]; - len = nla_len(va); - if (!va || len < sizeof *rq) - return -EINVAL; - - rq = nla_data(va); - sender.xid = rq->header.xid; - type = ntohs(rq->type); - if (rq->header.version != OFP_VERSION) { - dp_send_error_msg(dp, &sender, OFPET_BAD_REQUEST, - OFPBRC_BAD_VERSION, rq, len); - return -EINVAL; - } - if (rq->header.type != OFPT_STATS_REQUEST - || ntohs(rq->header.length) != len) - return -EINVAL; - - if (type == OFPST_VENDOR) { - /* Vendor is not in the array, take care of it */ - s = &stats_vendor; - } else { - if (type >= ARRAY_SIZE(stats) || !stats[type].dump) { - dp_send_error_msg(dp, &sender, - OFPET_BAD_REQUEST, - OFPBRC_BAD_STAT, rq, len); - return -EINVAL; - } - s = &stats[type]; - } - body_len = len - offsetof(struct ofp_stats_request, body); - if (body_len < s->min_body || body_len > s->max_body) - return -EINVAL; - - cb->args[0] = 1; - cb->args[1] = dp_idx; - cb->args[2] = type; - cb->args[3] = rq->header.xid; - if (s->init) { - void *state; - err = s->init(dp, rq->body, body_len, &state); - if (err) - return err; - cb->args[4] = (long) state; - } - } else if (cb->args[0] == 1) { - sender.xid = cb->args[3]; - dp_idx = cb->args[1]; - if (cb->args[2] == OFPST_VENDOR) { - /* Vendor is not in the array, take care of it */ - s = &stats_vendor; - } else { - s = &stats[cb->args[2]]; - } - - dp = dp_get_by_idx(dp_idx); - if (!dp) - return -ENOENT; - } else { - return 0; - } - - osr = put_openflow_headers(dp, skb, OFPT_STATS_REPLY, &sender, - &max_openflow_len); - if (IS_ERR(osr)) - return PTR_ERR(osr); - osr->type = htons(cb->args[2]); - osr->flags = 0; - resize_openflow_skb(skb, &osr->header, max_openflow_len); - body = osr->body; - body_len = max_openflow_len - offsetof(struct ofp_stats_reply, body); - - err = s->dump(dp, (void *) cb->args[4], body, &body_len); - if (err >= 0) { - if (!err) - cb->args[0] = 2; - else - osr->flags = ntohs(OFPSF_REPLY_MORE); - resize_openflow_skb(skb, &osr->header, - (offsetof(struct ofp_stats_reply, body) - + body_len)); - err = skb->len; - } - - return err; -} - -static int -dp_genl_openflow_done(struct netlink_callback *cb) -{ - if (cb->args[0]) { - const struct stats_type *s; - if (cb->args[2] == OFPST_VENDOR) { - /* Vendor is not in the array, take care of it */ - s = &stats_vendor; - } else { - s = &stats[cb->args[2]]; - } - if (s->done) - s->done((void *) cb->args[4]); - } - return 0; -} - -static struct genl_ops dp_genl_ops_openflow = { - .cmd = DP_GENL_C_OPENFLOW, - .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ - .policy = dp_genl_openflow_policy, - .doit = dp_genl_openflow, - .dumpit = dp_genl_openflow_dumpit, -}; - -static struct genl_ops *dp_genl_all_ops[] = { - /* Keep this operation first. Generic Netlink dispatching - * looks up operations with linear search, so we want it at the - * front. */ - &dp_genl_ops_openflow, - - &dp_genl_ops_add_dp, - &dp_genl_ops_del_dp, - &dp_genl_ops_query_dp, - &dp_genl_ops_add_port, - &dp_genl_ops_del_port, -}; - -static int dp_init_netlink(void) -{ - int err; - int i; - - err = genl_register_family(&dp_genl_family); - if (err) - return err; - - for (i = 0; i < ARRAY_SIZE(dp_genl_all_ops); i++) { - err = genl_register_ops(&dp_genl_family, dp_genl_all_ops[i]); - if (err) - goto err_unregister; - } - - for (i = 0; i < N_MC_GROUPS; i++) { - snprintf(mc_groups[i].name, sizeof mc_groups[i].name, - "openflow%d", i); - err = genl_register_mc_group(&dp_genl_family, &mc_groups[i]); - if (err < 0) - goto err_unregister; - } - - return 0; - -err_unregister: - genl_unregister_family(&dp_genl_family); - return err; -} - -static void dp_uninit_netlink(void) -{ - genl_unregister_family(&dp_genl_family); -} - -/* Set the description strings if appropriate values are available from - * the DMI. */ -static void set_desc(void) -{ - const char *uuid = dmi_get_system_info(DMI_PRODUCT_UUID); - const char *vendor = dmi_get_system_info(DMI_SYS_VENDOR); - const char *name = dmi_get_system_info(DMI_PRODUCT_NAME); - const char *version = dmi_get_system_info(DMI_PRODUCT_VERSION); - const char *serial = dmi_get_system_info(DMI_PRODUCT_SERIAL); - const char *uptr; - - if (!uuid || *uuid == '\0' || strlen(uuid) != 36) - return; - - /* We are only interested version 1 UUIDs, since the last six bytes - * are an IEEE 802 MAC address. */ - if (uuid[14] != '1') - return; - - /* Only set if the UUID is from Nicira. */ - uptr = uuid + 24; - if (strncmp(uptr, NICIRA_OUI_STR, strlen(NICIRA_OUI_STR))) - return; - - if (vendor) - strlcpy(mfr_desc, vendor, sizeof(mfr_desc)); - if (name || version) - snprintf(hw_desc, sizeof(hw_desc), "%s %s", - name ? name : "", - version ? version : ""); - if (serial) - strlcpy(serial_num, serial, sizeof(serial_num)); -} - -static int __init dp_init(void) -{ - int err; - - printk("OpenFlow %s, built "__DATE__" "__TIME__", " - "protocol 0x%02x\n", VERSION BUILDNR, OFP_VERSION); - - err = flow_init(); - if (err) - goto error; - - err = register_netdevice_notifier(&dp_device_notifier); - if (err) - goto error_flow_exit; - - err = dp_init_netlink(); - if (err) - goto error_unreg_notifier; - - dp_ioctl_hook = NULL; - dp_add_dp_hook = NULL; - dp_del_dp_hook = NULL; - dp_add_if_hook = NULL; - dp_del_if_hook = NULL; - - /* Check if better descriptions of the switch are available than the - * defaults. */ - set_desc(); - - /* Hook into callback used by the bridge to intercept packets. - * Parasites we are. */ - if (br_handle_frame_hook) - printk("openflow: hijacking bridge hook\n"); - br_handle_frame_hook = dp_frame_hook; - - return 0; - -error_unreg_notifier: - unregister_netdevice_notifier(&dp_device_notifier); -error_flow_exit: - flow_exit(); -error: - printk(KERN_EMERG "openflow: failed to install!"); - return err; -} - -static void dp_cleanup(void) -{ - fwd_exit(); - dp_uninit_netlink(); - unregister_netdevice_notifier(&dp_device_notifier); - flow_exit(); - br_handle_frame_hook = NULL; -} - -module_init(dp_init); -module_exit(dp_cleanup); - -MODULE_DESCRIPTION("OpenFlow Switching Datapath"); -MODULE_AUTHOR("Copyright (c) 2007, 2008 The Board of Trustees of The Leland Stanford Junior University"); -MODULE_LICENSE("GPL"); diff --git a/openflow/datapath/datapath.h b/openflow/datapath/datapath.h deleted file mode 100644 index 79ae0b78..00000000 --- a/openflow/datapath/datapath.h +++ /dev/null @@ -1,114 +0,0 @@ -/* Interface exported by OpenFlow module. */ - -#ifndef DATAPATH_H -#define DATAPATH_H 1 - -#include -#include -#include -#include -#include -#include -#include "openflow/openflow.h" -#include "openflow/nicira-ext.h" -#include "flow.h" - - -#define NL_FLOWS_PER_MESSAGE 100 - -/* Capabilities supported by this implementation. */ -#define OFP_SUPPORTED_CAPABILITIES ( OFPC_FLOW_STATS \ - | OFPC_TABLE_STATS \ - | OFPC_PORT_STATS ) - -/* Actions supported by this implementation. */ -#define OFP_SUPPORTED_ACTIONS ( (1 << OFPAT_OUTPUT) \ - | (1 << OFPAT_SET_VLAN_VID) \ - | (1 << OFPAT_SET_VLAN_PCP) \ - | (1 << OFPAT_STRIP_VLAN) \ - | (1 << OFPAT_SET_DL_SRC) \ - | (1 << OFPAT_SET_DL_DST) \ - | (1 << OFPAT_SET_NW_SRC) \ - | (1 << OFPAT_SET_NW_DST) \ - | (1 << OFPAT_SET_TP_SRC) \ - | (1 << OFPAT_SET_TP_DST) ) - -struct sk_buff; - -#define DP_MAX_PORTS 255 - -struct datapath { - int dp_idx; - - struct timer_list timer; /* Expiration timer. */ - struct sw_chain *chain; /* Forwarding rules. */ - struct task_struct *dp_task; /* Kernel thread for maintenance. */ - - /* Data related to the "of" device of this datapath */ - struct net_device *netdev; - char dp_desc[DESC_STR_LEN]; /* human readible comment to ID this DP */ - - /* Configuration set from controller */ - uint16_t flags; - uint16_t miss_send_len; - - struct kobject ifobj; - - /* Switch ports. */ - struct net_bridge_port *ports[DP_MAX_PORTS]; - struct net_bridge_port *local_port; /* OFPP_LOCAL port. */ - struct list_head port_list; /* All ports, including local_port. */ -}; - -/* Information necessary to reply to the sender of an OpenFlow message. */ -struct sender { - uint32_t xid; /* OpenFlow transaction ID of request. */ - uint32_t pid; /* Netlink process ID of sending socket. */ - uint32_t seq; /* Netlink sequence ID of request. */ -}; - -struct net_bridge_port { - u16 port_no; - u32 config; /* Some subset of OFPPC_* flags. */ - u32 state; /* Some subset of OFPPS_* flags. */ - spinlock_t lock; - struct datapath *dp; - struct net_device *dev; - struct kobject kobj; - struct list_head node; /* Element in datapath.ports. */ -}; - -extern struct mutex dp_mutex; -extern struct notifier_block dp_device_notifier; -extern int (*dp_ioctl_hook)(struct net_device *dev, struct ifreq *rq, int cmd); -extern int (*dp_add_dp_hook)(struct datapath *dp); -extern int (*dp_del_dp_hook)(struct datapath *dp); -extern int (*dp_add_if_hook)(struct net_bridge_port *p); -extern int (*dp_del_if_hook)(struct net_bridge_port *p); - -int dp_del_switch_port(struct net_bridge_port *); -int dp_xmit_skb(struct sk_buff *skb); -int dp_output_port(struct datapath *, struct sk_buff *, int out_port, - int ignore_no_fwd); -int dp_output_control(struct datapath *, struct sk_buff *, size_t, int); -void dp_set_origin(struct datapath *, uint16_t, struct sk_buff *); -int dp_send_features_reply(struct datapath *, const struct sender *); -int dp_send_config_reply(struct datapath *, const struct sender *); -int dp_send_port_status(struct net_bridge_port *p, uint8_t status); -int dp_send_flow_end(struct datapath *, struct sw_flow *, - enum ofp_flow_removed_reason); -int dp_send_error_msg(struct datapath *, const struct sender *, - uint16_t, uint16_t, const void *, size_t); -int dp_update_port_flags(struct datapath *dp, const struct ofp_port_mod *opm); -int dp_send_echo_reply(struct datapath *, const struct sender *, - const struct ofp_header *); -int dp_send_hello(struct datapath *, const struct sender *, - const struct ofp_header *); -int dp_send_barrier_reply(struct datapath *, const struct sender *, - const struct ofp_header *); - -/* Should hold at least RCU read lock when calling */ -struct datapath *dp_get_by_idx(int dp_idx); -struct datapath *dp_get_by_name(const char *dp_name); - -#endif /* datapath.h */ diff --git a/openflow/datapath/dp_act.c b/openflow/datapath/dp_act.c deleted file mode 100644 index 7532c00c..00000000 --- a/openflow/datapath/dp_act.c +++ /dev/null @@ -1,543 +0,0 @@ -/* - * Distributed under the terms of the GNU GPL version 2. - * Copyright (c) 2007, 2008, 2009 The Board of Trustees of The Leland - * Stanford Junior University - */ - -/* Functions for executing OpenFlow actions. */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "forward.h" -#include "dp_act.h" -#include "openflow/nicira-ext.h" -#include "flow.h" - - -static uint16_t -validate_output(struct datapath *dp, const struct sw_flow_key *key, - const struct ofp_action_header *ah) -{ - struct ofp_action_output *oa = (struct ofp_action_output *)ah; - - if (oa->port == htons(OFPP_NONE) || - (!(key->wildcards & OFPFW_IN_PORT) && oa->port == key->in_port)) - return OFPBAC_BAD_OUT_PORT; - - return ACT_VALIDATION_OK; -} - -static int -do_output(struct datapath *dp, struct sk_buff *skb, size_t max_len, - int out_port, int ignore_no_fwd) -{ - if (!skb) - return -ENOMEM; - return (likely(out_port != OFPP_CONTROLLER) - ? dp_output_port(dp, skb, out_port, ignore_no_fwd) - : dp_output_control(dp, skb, max_len, OFPR_ACTION)); -} - - -static struct sk_buff * -vlan_pull_tag(struct sk_buff *skb) -{ - struct vlan_ethhdr *vh = vlan_eth_hdr(skb); - struct ethhdr *eh; - - - /* Verify we were given a vlan packet */ - if (vh->h_vlan_proto != htons(ETH_P_8021Q)) - return skb; - - memmove(skb->data + VLAN_HLEN, skb->data, 2 * VLAN_ETH_ALEN); - - eh = (struct ethhdr *)skb_pull(skb, VLAN_HLEN); - - skb->protocol = eh->h_proto; - skb->mac_header += VLAN_HLEN; - - return skb; -} - - -static struct sk_buff * -modify_vlan_tci(struct sk_buff *skb, struct sw_flow_key *key, - uint16_t tci, uint16_t mask) -{ - struct vlan_ethhdr *vh = vlan_eth_hdr(skb); - - if (key->dl_vlan != htons(OFP_VLAN_NONE)) { - /* Modify vlan id, but maintain other TCI values */ - vh->h_vlan_TCI = (vh->h_vlan_TCI & ~(htons(mask))) | htons(tci); - } else { - /* Add vlan header */ - - /* xxx The vlan_put_tag function, doesn't seem to work - * xxx reliably when it attempts to use the hardware-accelerated - * xxx version. We'll directly use the software version - * xxx until the problem can be diagnosed. - */ - skb = __vlan_put_tag(skb, tci); - vh = vlan_eth_hdr(skb); - } - key->dl_vlan = vh->h_vlan_TCI & htons(VLAN_VID_MASK); - key->dl_vlan_pcp = (uint8_t)((ntohs(vh->h_vlan_TCI) >> VLAN_PCP_SHIFT) - & VLAN_PCP_BITMASK); - - return skb; -} - -static struct sk_buff * -set_vlan_vid(struct sk_buff *skb, struct sw_flow_key *key, - const struct ofp_action_header *ah) -{ - struct ofp_action_vlan_vid *va = (struct ofp_action_vlan_vid *)ah; - uint16_t tci = ntohs(va->vlan_vid); - - return modify_vlan_tci(skb, key, tci, VLAN_VID_MASK); -} - -/* Mask for the priority bits in a vlan header. The kernel doesn't - * define this like it does for VID. */ -#define VLAN_PCP_MASK 0xe000 - -static struct sk_buff * -set_vlan_pcp(struct sk_buff *skb, struct sw_flow_key *key, - const struct ofp_action_header *ah) -{ - struct ofp_action_vlan_pcp *va = (struct ofp_action_vlan_pcp *)ah; - uint16_t tci = (uint16_t)va->vlan_pcp << 13; - - return modify_vlan_tci(skb, key, tci, VLAN_PCP_MASK); -} - -static struct sk_buff * -strip_vlan(struct sk_buff *skb, struct sw_flow_key *key, - const struct ofp_action_header *ah) -{ - vlan_pull_tag(skb); - key->dl_vlan = htons(OFP_VLAN_NONE); - - return skb; -} - -static struct sk_buff * -set_dl_addr(struct sk_buff *skb, struct sw_flow_key *key, - const struct ofp_action_header *ah) -{ - struct ofp_action_dl_addr *da = (struct ofp_action_dl_addr *)ah; - struct ethhdr *eh = eth_hdr(skb); - - if (da->type == htons(OFPAT_SET_DL_SRC)) - memcpy(eh->h_source, da->dl_addr, sizeof eh->h_source); - else - memcpy(eh->h_dest, da->dl_addr, sizeof eh->h_dest); - - return skb; -} - -/* Updates 'sum', which is a field in 'skb''s data, given that a 4-byte field - * covered by the sum has been changed from 'from' to 'to'. If set, - * 'pseudohdr' indicates that the field is in the TCP or UDP pseudo-header. - * Based on nf_proto_csum_replace4. */ -static void update_csum(__sum16 *sum, struct sk_buff *skb, - __be32 from, __be32 to, int pseudohdr) -{ - __be32 diff[] = { ~from, to }; - if (skb->ip_summed != CHECKSUM_PARTIAL) { - *sum = csum_fold(csum_partial((char *)diff, sizeof(diff), - ~csum_unfold(*sum))); - if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr) - skb->csum = ~csum_partial((char *)diff, sizeof(diff), - ~skb->csum); - } else if (pseudohdr) - *sum = ~csum_fold(csum_partial((char *)diff, sizeof(diff), - csum_unfold(*sum))); -} - -static struct sk_buff * -set_nw_addr(struct sk_buff *skb, struct sw_flow_key *key, - const struct ofp_action_header *ah) -{ - struct ofp_action_nw_addr *na = (struct ofp_action_nw_addr *)ah; - uint16_t eth_proto = ntohs(key->dl_type); - - if (eth_proto == ETH_P_IP) { - struct iphdr *nh = ip_hdr(skb); - uint32_t new, *field; - - new = na->nw_addr; - - if (ah->type == htons(OFPAT_SET_NW_SRC)) - field = &nh->saddr; - else - field = &nh->daddr; - - if (key->nw_proto == IPPROTO_TCP) { - struct tcphdr *th = tcp_hdr(skb); - update_csum(&th->check, skb, *field, new, 1); - } else if (key->nw_proto == IPPROTO_UDP) { - struct udphdr *th = udp_hdr(skb); - update_csum(&th->check, skb, *field, new, 1); - } - update_csum(&nh->check, skb, *field, new, 0); - *field = new; - } - - return skb; -} - -static struct sk_buff * -set_nw_tos(struct sk_buff *skb, struct sw_flow_key *key, - const struct ofp_action_header *ah) -{ - struct ofp_action_nw_tos *nt = (struct ofp_action_nw_tos *)ah; - uint16_t eth_proto = ntohs(key->dl_type); - - if (eth_proto == ETH_P_IP) { - struct iphdr *nh = ip_hdr(skb); - uint8_t new, *field; - - /* JeanII : Set only 6 bits, don't clobber ECN */ - new = (nt->nw_tos & 0xFC) | (nh->tos & 0x03); - - /* Get address of field */ - field = &nh->tos; - /* jklee : ip tos field is not included in TCP pseudo header. - * Need magic as update_csum() don't work with 8 bits. */ - update_csum(&nh->check, skb, htons((uint16_t)*field), - htons((uint16_t)new), 0); - - /* Update in packet */ - *field = new; - } - - return skb; -} - -static struct sk_buff * -set_tp_port(struct sk_buff *skb, struct sw_flow_key *key, - const struct ofp_action_header *ah) -{ - struct ofp_action_tp_port *ta = (struct ofp_action_tp_port *)ah; - uint16_t eth_proto = ntohs(key->dl_type); - - if (eth_proto == ETH_P_IP) { - uint16_t new, *field; - - new = ta->tp_port; - - if (key->nw_proto == IPPROTO_TCP) { - struct tcphdr *th = tcp_hdr(skb); - - if (ah->type == htons(OFPAT_SET_TP_SRC)) - field = &th->source; - else - field = &th->dest; - - update_csum(&th->check, skb, *field, new, 1); - *field = new; - } else if (key->nw_proto == IPPROTO_UDP) { - struct udphdr *th = udp_hdr(skb); - - if (ah->type == htons(OFPAT_SET_TP_SRC)) - field = &th->source; - else - field = &th->dest; - - update_csum(&th->check, skb, *field, new, 1); - *field = new; - } - } - - return skb; -} - -struct openflow_action { - size_t min_size; - size_t max_size; - uint16_t (*validate)(struct datapath *dp, - const struct sw_flow_key *key, - const struct ofp_action_header *ah); - struct sk_buff *(*execute)(struct sk_buff *skb, - struct sw_flow_key *key, - const struct ofp_action_header *ah); -}; - -static const struct openflow_action of_actions[] = { - [OFPAT_OUTPUT] = { - sizeof(struct ofp_action_output), - sizeof(struct ofp_action_output), - validate_output, - NULL /* This is optimized into execute_actions */ - }, - [OFPAT_SET_VLAN_VID] = { - sizeof(struct ofp_action_vlan_vid), - sizeof(struct ofp_action_vlan_vid), - NULL, - set_vlan_vid - }, - [OFPAT_SET_VLAN_PCP] = { - sizeof(struct ofp_action_vlan_pcp), - sizeof(struct ofp_action_vlan_pcp), - NULL, - set_vlan_pcp - }, - [OFPAT_STRIP_VLAN] = { - sizeof(struct ofp_action_header), - sizeof(struct ofp_action_header), - NULL, - strip_vlan - }, - [OFPAT_SET_DL_SRC] = { - sizeof(struct ofp_action_dl_addr), - sizeof(struct ofp_action_dl_addr), - NULL, - set_dl_addr - }, - [OFPAT_SET_DL_DST] = { - sizeof(struct ofp_action_dl_addr), - sizeof(struct ofp_action_dl_addr), - NULL, - set_dl_addr - }, - [OFPAT_SET_NW_SRC] = { - sizeof(struct ofp_action_nw_addr), - sizeof(struct ofp_action_nw_addr), - NULL, - set_nw_addr - }, - [OFPAT_SET_NW_DST] = { - sizeof(struct ofp_action_nw_addr), - sizeof(struct ofp_action_nw_addr), - NULL, - set_nw_addr - }, - [OFPAT_SET_NW_TOS] = { - sizeof(struct ofp_action_nw_tos), - sizeof(struct ofp_action_nw_tos), - NULL, - set_nw_tos - }, - [OFPAT_SET_TP_SRC] = { - sizeof(struct ofp_action_tp_port), - sizeof(struct ofp_action_tp_port), - NULL, - set_tp_port - }, - [OFPAT_SET_TP_DST] = { - sizeof(struct ofp_action_tp_port), - sizeof(struct ofp_action_tp_port), - NULL, - set_tp_port - } - /* OFPAT_VENDOR is not here, since it would blow up the array size. */ -}; - -/* Validate built-in OpenFlow actions. Either returns ACT_VALIDATION_OK - * or an OFPET_BAD_ACTION error code. */ -static uint16_t -validate_ofpat(struct datapath *dp, const struct sw_flow_key *key, - const struct ofp_action_header *ah, uint16_t type, uint16_t len) -{ - uint16_t ret = ACT_VALIDATION_OK; - const struct openflow_action *act = &of_actions[type]; - - if ((len < act->min_size) || (len > act->max_size)) - return OFPBAC_BAD_LEN; - - if (act->validate) - ret = act->validate(dp, key, ah); - - return ret; -} - -/* Validate vendor-defined actions. Either returns ACT_VALIDATION_OK - * or an OFPET_BAD_ACTION error code. */ -static uint16_t -validate_vendor(struct datapath *dp, const struct sw_flow_key *key, - const struct ofp_action_header *ah, uint16_t len) -{ - struct ofp_action_vendor_header *avh; - int ret = ACT_VALIDATION_OK; - - if (len < sizeof(struct ofp_action_vendor_header)) - return OFPBAC_BAD_LEN; - - avh = (struct ofp_action_vendor_header *)ah; - - switch(ntohl(avh->vendor)) { - default: - return OFPBAC_BAD_VENDOR; - } - - return ret; -} - -/* Validates a list of actions. If a problem is found, a code for the - * OFPET_BAD_ACTION error type is returned. If the action list validates, - * ACT_VALIDATION_OK is returned. */ -uint16_t -validate_actions(struct datapath *dp, const struct sw_flow_key *key, - const struct ofp_action_header *actions, size_t actions_len) -{ - uint8_t *p = (uint8_t *)actions; - int err; - - while (actions_len >= sizeof(struct ofp_action_header)) { - struct ofp_action_header *ah = (struct ofp_action_header *)p; - size_t len = ntohs(ah->len); - uint16_t type; - - /* Make there's enough remaining data for the specified length - * and that the action length is a multiple of 64 bits. */ - if ((actions_len < len) || (len % 8) != 0) - return OFPBAC_BAD_LEN; - - type = ntohs(ah->type); - if (type < ARRAY_SIZE(of_actions)) { - err = validate_ofpat(dp, key, ah, type, len); - if (err != ACT_VALIDATION_OK) - return err; - } else if (type == OFPAT_VENDOR) { - err = validate_vendor(dp, key, ah, len); - if (err != ACT_VALIDATION_OK) - return err; - } else - return OFPBAC_BAD_TYPE; - - p += len; - actions_len -= len; - } - - /* Check if there's any trailing garbage. */ - if (actions_len != 0) - return OFPBAC_BAD_LEN; - - return ACT_VALIDATION_OK; -} - -/* Execute a built-in OpenFlow action against 'skb'. */ -static struct sk_buff * -execute_ofpat(struct sk_buff *skb, struct sw_flow_key *key, - const struct ofp_action_header *ah, uint16_t type) -{ - const struct openflow_action *act = &of_actions[type]; - if (act->execute && make_writable(&skb)) - skb = act->execute(skb, key, ah); - return skb; -} - -/* Execute a vendor-defined action against 'skb'. */ -static struct sk_buff * -execute_vendor(struct sk_buff *skb, const struct sw_flow_key *key, - const struct ofp_action_header *ah) -{ - struct ofp_action_vendor_header *avh - = (struct ofp_action_vendor_header *)ah; - struct datapath *dp = skb->dev->br_port->dp; - - /* NB: If changes need to be made to the packet, a call should be - * made to make_writable or its equivalent first. */ - - switch(ntohl(avh->vendor)) { - default: - /* This should not be possible due to prior validation. */ - if (net_ratelimit()) - printk(KERN_WARNING "%s: attempt to execute action " - "with unknown vendor: %#x\n", - dp->netdev->name, ntohl(avh->vendor)); - break; - } - - return skb; -} - -/* Execute a list of actions against 'skb'. */ -void execute_actions(struct datapath *dp, struct sk_buff *skb, - struct sw_flow_key *key, - const struct ofp_action_header *actions, size_t actions_len, - int ignore_no_fwd) -{ - /* Every output action needs a separate clone of 'skb', but the common - * case is just a single output action, so that doing a clone and - * then freeing the original skbuff is wasteful. So the following code - * is slightly obscure just to avoid that. */ - int prev_port; - size_t max_len = UINT16_MAX; - uint8_t *p = (uint8_t *)actions; - - prev_port = -1; - - /* The action list was already validated, so we can be a bit looser - * in our sanity-checking. */ - while (actions_len > 0) { - struct ofp_action_header *ah = (struct ofp_action_header *)p; - size_t len = htons(ah->len); - - WARN_ON_ONCE(skb_shared(skb)); - if (prev_port != -1) { - do_output(dp, skb_clone(skb, GFP_ATOMIC), - max_len, prev_port, ignore_no_fwd); - prev_port = -1; - } - - if (likely(ah->type == htons(OFPAT_OUTPUT))) { - struct ofp_action_output *oa = (struct ofp_action_output *)p; - prev_port = ntohs(oa->port); - max_len = ntohs(oa->max_len); - } else { - uint16_t type = ntohs(ah->type); - - if (type < ARRAY_SIZE(of_actions)) - skb = execute_ofpat(skb, key, ah, type); - else if (type == OFPAT_VENDOR) - skb = execute_vendor(skb, key, ah); - - if (!skb) { - if (net_ratelimit()) - printk(KERN_WARNING "%s: " - "execute_actions lost skb\n", - dp->netdev->name); - return; - } - } - - p += len; - actions_len -= len; - } - if (prev_port != -1) - do_output(dp, skb, max_len, prev_port, ignore_no_fwd); - else - kfree_skb(skb); -} - -/* Utility functions. */ - -/* Makes '*pskb' writable, possibly copying it and setting '*pskb' to point to - * the copy. - * Returns 1 if successful, 0 on failure. */ -int -make_writable(struct sk_buff **pskb) -{ - struct sk_buff *skb = *pskb; - if (skb_shared(skb) || skb_cloned(skb)) { - struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC); - if (!nskb) - return 0; - kfree_skb(skb); - *pskb = nskb; - return 1; - } else { - unsigned int hdr_len = (skb_transport_offset(skb) - + sizeof(struct tcphdr)); - return pskb_may_pull(skb, min(hdr_len, skb->len)); - } -} diff --git a/openflow/datapath/dp_act.h b/openflow/datapath/dp_act.h deleted file mode 100644 index d601eca0..00000000 --- a/openflow/datapath/dp_act.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef DP_ACT_H -#define DP_ACT_H 1 - -#include "datapath.h" - -#define ACT_VALIDATION_OK ((uint16_t)-1) - -uint16_t validate_actions(struct datapath *, const struct sw_flow_key *, - const struct ofp_action_header *, size_t); -void execute_actions(struct datapath *, struct sk_buff *, - struct sw_flow_key *, const struct ofp_action_header *, - size_t action_len, int ignore_no_fwd); -int make_writable(struct sk_buff **pskb); - -#endif /* dp_act.h */ diff --git a/openflow/datapath/dp_dev.c b/openflow/datapath/dp_dev.c deleted file mode 100644 index 5db5b19b..00000000 --- a/openflow/datapath/dp_dev.c +++ /dev/null @@ -1,252 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include "datapath.h" -#include "dp_dev.h" -#include "forward.h" - - -static struct dp_dev *dp_dev_priv(struct net_device *netdev) -{ - return netdev_priv(netdev); -} - -struct datapath *dp_dev_get_dp(struct net_device *netdev) -{ - return dp_dev_priv(netdev)->dp; -} -EXPORT_SYMBOL(dp_dev_get_dp); - -static struct net_device_stats *dp_dev_get_stats(struct net_device *netdev) -{ - struct dp_dev *dp_dev = dp_dev_priv(netdev); - return &dp_dev->stats; -} - -int dp_dev_recv(struct net_device *netdev, struct sk_buff *skb) -{ - int len = skb->len; - struct dp_dev *dp_dev = dp_dev_priv(netdev); - skb->dev = netdev; - skb->pkt_type = PACKET_HOST; - skb->protocol = eth_type_trans(skb, netdev); - if (in_interrupt()) - netif_rx(skb); - else - netif_rx_ni(skb); - netdev->last_rx = jiffies; - dp_dev->stats.rx_packets++; - dp_dev->stats.rx_bytes += len; - return len; -} - -static int dp_dev_mac_addr(struct net_device *dev, void *p) -{ - struct sockaddr *addr = p; - - if (netif_running(dev)) - return -EBUSY; - if (!is_valid_ether_addr(addr->sa_data)) - return -EADDRNOTAVAIL; - memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); - return 0; -} - -static int dp_dev_xmit(struct sk_buff *skb, struct net_device *netdev) -{ - struct dp_dev *dp_dev = dp_dev_priv(netdev); - struct datapath *dp = dp_dev->dp; - - /* By orphaning 'skb' we will screw up socket accounting slightly, but - * the effect is limited to the device queue length. If we don't - * do this, then the sk_buff will be destructed eventually, but it is - * harder to predict when. */ - skb_orphan(skb); - - /* We are going to modify 'skb', by sticking it on &dp_dev->xmit_queue, - * so we need to have our own clone. (At any rate, fwd_port_input() - * will need its own clone, so there's no benefit to queuing any other - * way.) */ - skb = skb_share_check(skb, GFP_ATOMIC); - if (!skb) - return 0; - - dp_dev->stats.tx_packets++; - dp_dev->stats.tx_bytes += skb->len; - - if (skb_queue_len(&dp_dev->xmit_queue) >= dp->netdev->tx_queue_len) { - /* Queue overflow. Stop transmitter. */ - netif_stop_queue(dp->netdev); - - /* We won't see all dropped packets individually, so overrun - * error is appropriate. */ - dp_dev->stats.tx_fifo_errors++; - } - skb_queue_tail(&dp_dev->xmit_queue, skb); - dp->netdev->trans_start = jiffies; - - schedule_work(&dp_dev->xmit_work); - - return 0; -} - -static void dp_dev_do_xmit(struct work_struct *work) -{ - struct dp_dev *dp_dev = container_of(work, struct dp_dev, xmit_work); - struct datapath *dp = dp_dev->dp; - struct sk_buff *skb; - - while ((skb = skb_dequeue(&dp_dev->xmit_queue)) != NULL) { - skb_reset_mac_header(skb); - rcu_read_lock(); - fwd_port_input(dp->chain, skb, dp->local_port); - rcu_read_unlock(); - } - netif_wake_queue(dp->netdev); -} - -static int dp_dev_open(struct net_device *netdev) -{ - netif_start_queue(netdev); - return 0; -} - -static int dp_dev_stop(struct net_device *netdev) -{ - netif_stop_queue(netdev); - return 0; -} - -static void dp_getinfo(struct net_device *dev, struct ethtool_drvinfo *info) -{ - strcpy(info->driver, "openflow"); - sprintf(info->version, "0x%d", OFP_VERSION); - strcpy(info->fw_version, "N/A"); - strcpy(info->bus_info, "N/A"); -} - -static struct ethtool_ops dp_ethtool_ops = { - .get_drvinfo = dp_getinfo, - .get_link = ethtool_op_get_link, - .get_sg = ethtool_op_get_sg, - .get_tx_csum = ethtool_op_get_tx_csum, - .get_tso = ethtool_op_get_tso, -}; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) -static const struct net_device_ops dp_netdev_ops = { - .ndo_init = NULL, - .ndo_uninit = NULL, - .ndo_open = dp_dev_open, - .ndo_stop = dp_dev_stop, - .ndo_start_xmit = dp_dev_xmit, - .ndo_select_queue = NULL, - .ndo_change_rx_flags = NULL, - .ndo_set_rx_mode = NULL, - .ndo_set_multicast_list = NULL, - .ndo_set_mac_address = dp_dev_mac_addr, - .ndo_validate_addr = NULL, - .ndo_do_ioctl = NULL, - .ndo_set_config = NULL, - .ndo_change_mtu = NULL, - .ndo_tx_timeout = NULL, - .ndo_get_stats = dp_dev_get_stats, - .ndo_vlan_rx_register = NULL, - .ndo_vlan_rx_add_vid = NULL, - .ndo_vlan_rx_kill_vid = NULL, - .ndo_poll_controller = NULL -}; -#endif - -static void -do_setup(struct net_device *netdev) -{ - ether_setup(netdev); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) - netdev->netdev_ops = &dp_netdev_ops; -#else - netdev->do_ioctl = dp_ioctl_hook; - netdev->get_stats = dp_dev_get_stats; - netdev->hard_start_xmit = dp_dev_xmit; - netdev->open = dp_dev_open; - netdev->stop = dp_dev_stop; - netdev->set_mac_address = dp_dev_mac_addr; -#endif - SET_ETHTOOL_OPS(netdev, &dp_ethtool_ops); - netdev->tx_queue_len = 100; - - netdev->flags = IFF_BROADCAST | IFF_MULTICAST; - - random_ether_addr(netdev->dev_addr); - - /* Set the OUI to the Nicira one. */ - netdev->dev_addr[0] = 0x00; - netdev->dev_addr[1] = 0x23; - netdev->dev_addr[2] = 0x20; - - /* Set the top bits to indicate random Nicira address. */ - netdev->dev_addr[3] |= 0xc0; -} - -/* Create a datapath device associated with 'dp'. If 'dp_name' is null, - * the device name will be of the form 'of'. - * - * Called with RTNL lock and dp_mutex.*/ -int dp_dev_setup(struct datapath *dp, const char *dp_name) -{ - struct dp_dev *dp_dev; - struct net_device *netdev; - char dev_name[IFNAMSIZ]; - int err; - - if (dp_name) { - if (strlen(dp_name) >= IFNAMSIZ) - return -EINVAL; - strncpy(dev_name, dp_name, sizeof(dev_name)); - } else - snprintf(dev_name, sizeof dev_name, "of%d", dp->dp_idx); - - netdev = alloc_netdev(sizeof(struct dp_dev), dev_name, do_setup); - if (!netdev) - return -ENOMEM; - - err = register_netdevice(netdev); - if (err) { - free_netdev(netdev); - return err; - } - - dp_dev = dp_dev_priv(netdev); - dp_dev->dp = dp; - skb_queue_head_init(&dp_dev->xmit_queue); - INIT_WORK(&dp_dev->xmit_work, dp_dev_do_xmit); - dp->netdev = netdev; - return 0; -} - -/* Called with RTNL lock and dp_mutex.*/ -void dp_dev_destroy(struct datapath *dp) -{ - struct dp_dev *dp_dev = dp_dev_priv(dp->netdev); - - netif_tx_disable(dp->netdev); - synchronize_net(); - skb_queue_purge(&dp_dev->xmit_queue); - unregister_netdevice(dp->netdev); -} - -int is_dp_dev(struct net_device *netdev) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) - return netdev->netdev_ops->ndo_open == dp_dev_open; - -#else - return netdev->open == dp_dev_open; -#endif -} diff --git a/openflow/datapath/dp_dev.h b/openflow/datapath/dp_dev.h deleted file mode 100644 index 26f72485..00000000 --- a/openflow/datapath/dp_dev.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef DP_DEV_H -#define DP_DEV_H 1 - -struct dp_dev { - struct net_device_stats stats; - struct datapath *dp; - struct sk_buff_head xmit_queue; - struct work_struct xmit_work; -}; - -int dp_dev_setup(struct datapath *, const char *); -void dp_dev_destroy(struct datapath *); -int dp_dev_recv(struct net_device *, struct sk_buff *); -int is_dp_dev(struct net_device *); -struct datapath *dp_dev_get_dp(struct net_device *); - -#endif /* dp_dev.h */ diff --git a/openflow/datapath/dp_notify.c b/openflow/datapath/dp_notify.c deleted file mode 100644 index 54c88402..00000000 --- a/openflow/datapath/dp_notify.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Distributed under the terms of the GNU GPL version 2. - * Copyright (c) 2007, 2008, 2009 The Board of Trustees of The Leland - * Stanford Junior University - */ - -/* Handle changes to managed devices */ - -#include - -#include "datapath.h" - - -static int dp_device_event(struct notifier_block *unused, unsigned long event, - void *ptr) -{ - struct net_device *dev = ptr; - struct net_bridge_port *p = dev->br_port; - unsigned long int flags; - - - /* Check if monitored port */ - if (!p) - return NOTIFY_DONE; - - spin_lock_irqsave(&p->lock, flags); - switch (event) { - case NETDEV_UNREGISTER: - spin_unlock_irqrestore(&p->lock, flags); - mutex_lock(&dp_mutex); - dp_del_switch_port(p); - mutex_unlock(&dp_mutex); - return NOTIFY_DONE; - break; - } - spin_unlock_irqrestore(&p->lock, flags); - - return NOTIFY_DONE; -} - -struct notifier_block dp_device_notifier = { - .notifier_call = dp_device_event -}; diff --git a/openflow/datapath/flow.c b/openflow/datapath/flow.c deleted file mode 100644 index c927ce65..00000000 --- a/openflow/datapath/flow.c +++ /dev/null @@ -1,504 +0,0 @@ - -/* - * Distributed under the terms of the GNU GPL version 2. - * Copyright (c) 2007, 2008 The Board of Trustees of The Leland - * Stanford Junior University - */ - -#include "flow.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "openflow/openflow.h" -#include "openflow/nicira-ext.h" -#include "compat.h" - -struct kmem_cache *flow_cache; - -/* Internal function used to compare fields in flow. */ -static inline -int flow_fields_match(const struct sw_flow_key *a, const struct sw_flow_key *b, - uint32_t w, uint32_t src_mask, uint32_t dst_mask) -{ - return ((w & OFPFW_IN_PORT || a->in_port == b->in_port) - && (w & OFPFW_DL_VLAN || a->dl_vlan == b->dl_vlan) - && (w & OFPFW_DL_VLAN_PCP || a->dl_vlan_pcp == b->dl_vlan_pcp) - && (w & OFPFW_DL_SRC || !memcmp(a->dl_src, b->dl_src, ETH_ALEN)) - && (w & OFPFW_DL_DST || !memcmp(a->dl_dst, b->dl_dst, ETH_ALEN)) - && (w & OFPFW_DL_TYPE || a->dl_type == b->dl_type) - && (w & OFPFW_NW_TOS || a->nw_tos == b->nw_tos) - && (w & OFPFW_NW_PROTO || a->nw_proto == b->nw_proto) - && !((a->nw_src ^ b->nw_src) & src_mask) - && !((a->nw_dst ^ b->nw_dst) & dst_mask) - && (w & OFPFW_TP_SRC || a->tp_src == b->tp_src) - && (w & OFPFW_TP_DST || a->tp_dst == b->tp_dst)); -} - -/* Returns nonzero if 'a' and 'b' match, that is, if their fields are equal - * modulo wildcards in 'b', zero otherwise. */ -int flow_matches_1wild(const struct sw_flow_key *a, - const struct sw_flow_key *b) -{ - return flow_fields_match(a, b, b->wildcards, - b->nw_src_mask, b->nw_dst_mask); -} -EXPORT_SYMBOL(flow_matches_1wild); - -/* Returns nonzero if 'a' and 'b' match, that is, if their fields are equal - * modulo wildcards in 'a' or 'b', zero otherwise. */ -int flow_matches_2wild(const struct sw_flow_key *a, - const struct sw_flow_key *b) -{ - return flow_fields_match(a, b, - a->wildcards | b->wildcards, - a->nw_src_mask & b->nw_src_mask, - a->nw_dst_mask & b->nw_dst_mask); -} -EXPORT_SYMBOL(flow_matches_2wild); - -/* Returns nonzero if 't' (the table entry's key) and 'd' (the key - * describing the match) match, that is, if their fields are - * equal modulo wildcards, zero otherwise. If 'strict' is nonzero, the - * wildcards must match in both 't_key' and 'd_key'. Note that the - * table's wildcards are ignored unless 'strict' is set. */ -int flow_matches_desc(const struct sw_flow_key *t, const struct sw_flow_key *d, - int strict) -{ - if (strict && d->wildcards != t->wildcards) - return 0; - return flow_matches_1wild(t, d); -} -EXPORT_SYMBOL(flow_matches_desc); - -/* Returns nonzero if 't' (the table entry's key) and 'd' (the key - * describing the match) match, that is, if their fields are - * equal modulo 't' or 'd' wildcards, zero otherwise. If 'strict' is nonzero, the - * wildcards must match in both 't_key' and 'd_key'. Note that the - * table's wildcards are ignored unless 'strict' is set. */ -int -flow_matches_2desc(const struct sw_flow_key *t, const struct sw_flow_key *d, - int strict) -{ - if (strict && d->wildcards != t->wildcards) { - return 0; - } - return flow_matches_2wild(t, d); -} -EXPORT_SYMBOL(flow_matches_2desc); - -static uint32_t make_nw_mask(int n_wild_bits) -{ - n_wild_bits &= (1u << OFPFW_NW_SRC_BITS) - 1; - return n_wild_bits < 32 ? htonl(~((1u << n_wild_bits) - 1)) : 0; -} - -void flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from) -{ - to->wildcards = ntohl(from->wildcards) & OFPFW_ALL; - to->dl_vlan_pcp = from->dl_vlan_pcp; - to->in_port = from->in_port; - to->dl_vlan = from->dl_vlan; - memcpy(to->dl_src, from->dl_src, ETH_ALEN); - memcpy(to->dl_dst, from->dl_dst, ETH_ALEN); - to->dl_type = from->dl_type; - - to->nw_tos = to->nw_proto = to->nw_src = to->nw_dst = 0; - to->tp_src = to->tp_dst = 0; - memset(to->pad, 0, sizeof(to->pad)); - -#define OFPFW_TP (OFPFW_TP_SRC | OFPFW_TP_DST) -#define OFPFW_NW (OFPFW_NW_TOS | OFPFW_NW_PROTO | OFPFW_NW_SRC_MASK | OFPFW_NW_DST_MASK) - if (to->wildcards & OFPFW_DL_TYPE) { - /* Can't sensibly match on network or transport headers if the - * data link type is unknown. */ - to->wildcards |= OFPFW_NW | OFPFW_TP; - } else if (from->dl_type == htons(ETH_P_IP)) { - to->nw_tos = from->nw_tos & 0xfc; - to->nw_proto = from->nw_proto; - to->nw_src = from->nw_src; - to->nw_dst = from->nw_dst; - - if (to->wildcards & OFPFW_NW_PROTO) { - /* Can't sensibly match on transport headers if the - * network protocol is unknown. */ - to->wildcards |= OFPFW_TP; - } else if (from->nw_proto == IPPROTO_TCP - || from->nw_proto == IPPROTO_UDP - || from->nw_proto == IPPROTO_ICMP) { - to->tp_src = from->tp_src; - to->tp_dst = from->tp_dst; - } else { - /* Transport layer fields are undefined. Mark them as - * exact-match to allow such flows to reside in - * table-hash, instead of falling into table-linear. */ - to->wildcards &= ~OFPFW_TP; - } - } else { - /* Network and transport layer fields are undefined. Mark them - * as exact-match to allow such flows to reside in table-hash, - * instead of falling into table-linear. */ - to->wildcards &= ~(OFPFW_NW | OFPFW_TP); - } - - /* We set these late because code above adjusts to->wildcards. */ - to->nw_src_mask = make_nw_mask(to->wildcards >> OFPFW_NW_SRC_SHIFT); - to->nw_dst_mask = make_nw_mask(to->wildcards >> OFPFW_NW_DST_SHIFT); -} - -void flow_fill_match(struct ofp_match* to, const struct sw_flow_key* from) -{ - to->wildcards = htonl(from->wildcards); - to->in_port = from->in_port; - to->dl_vlan = from->dl_vlan; - memcpy(to->dl_src, from->dl_src, ETH_ALEN); - memcpy(to->dl_dst, from->dl_dst, ETH_ALEN); - to->dl_type = from->dl_type; - to->nw_tos = from->nw_tos; - to->nw_proto = from->nw_proto; - to->nw_src = from->nw_src; - to->nw_dst = from->nw_dst; - to->tp_src = from->tp_src; - to->tp_dst = from->tp_dst; - to->dl_vlan_pcp = from->dl_vlan_pcp; -} - -int flow_timeout(struct sw_flow *flow) -{ - if (flow->idle_timeout != OFP_FLOW_PERMANENT - && time_after64(get_jiffies_64(), flow->used + flow->idle_timeout * HZ)) - return OFPRR_IDLE_TIMEOUT; - else if (flow->hard_timeout != OFP_FLOW_PERMANENT - && time_after64(get_jiffies_64(), - flow->created + flow->hard_timeout * HZ)) - return OFPRR_HARD_TIMEOUT; - else - return -1; -} -EXPORT_SYMBOL(flow_timeout); - -/* Returns nonzero if 'flow' contains an output action to 'out_port' or - * has the value OFPP_NONE. 'out_port' is in network-byte order. */ -int flow_has_out_port(struct sw_flow *flow, uint16_t out_port) -{ - struct sw_flow_actions *sf_acts; - size_t actions_len; - uint8_t *p; - - if (out_port == htons(OFPP_NONE)) - return 1; - - sf_acts = rcu_dereference(flow->sf_acts); - - actions_len = sf_acts->actions_len; - p = (uint8_t *)sf_acts->actions; - - while (actions_len > 0) { - struct ofp_action_header *ah = (struct ofp_action_header *)p; - size_t len = ntohs(ah->len); - - if (ah->type == htons(OFPAT_OUTPUT)) { - struct ofp_action_output *oa = (struct ofp_action_output *)p; - if (oa->port == out_port) - return 1; - } - - p += len; - actions_len -= len; - } - - return 0; -} -EXPORT_SYMBOL(flow_has_out_port); - -/* Allocates and returns a new flow with room for 'actions_len' actions, - * using allocation flags 'flags'. Returns the new flow or a null pointer - * on failure. */ -struct sw_flow *flow_alloc(size_t actions_len, gfp_t flags) -{ - struct sw_flow_actions *sfa; - size_t size = sizeof *sfa + actions_len; - struct sw_flow *flow = kmem_cache_alloc(flow_cache, flags); - if (unlikely(!flow)) - return NULL; - - sfa = kmalloc(size, flags); - if (unlikely(!sfa)) { - kmem_cache_free(flow_cache, flow); - return NULL; - } - sfa->actions_len = actions_len; - flow->sf_acts = sfa; - - return flow; -} - -/* Frees 'flow' immediately. */ -void flow_free(struct sw_flow *flow) -{ - if (unlikely(!flow)) - return; - kfree(flow->sf_acts); - kmem_cache_free(flow_cache, flow); -} -EXPORT_SYMBOL(flow_free); - -/* RCU callback used by flow_deferred_free. */ -static void rcu_free_flow_callback(struct rcu_head *rcu) -{ - struct sw_flow *flow = container_of(rcu, struct sw_flow, rcu); - flow_free(flow); -} - -/* Schedules 'flow' to be freed after the next RCU grace period. - * The caller must hold rcu_read_lock for this to be sensible. */ -void flow_deferred_free(struct sw_flow *flow) -{ - call_rcu(&flow->rcu, rcu_free_flow_callback); -} -EXPORT_SYMBOL(flow_deferred_free); - -/* RCU callback used by flow_deferred_free_acts. */ -static void rcu_free_acts_callback(struct rcu_head *rcu) -{ - struct sw_flow_actions *sf_acts = container_of(rcu, - struct sw_flow_actions, rcu); - kfree(sf_acts); -} - -/* Schedules 'sf_acts' to be freed after the next RCU grace period. - * The caller must hold rcu_read_lock for this to be sensible. */ -void flow_deferred_free_acts(struct sw_flow_actions *sf_acts) -{ - call_rcu(&sf_acts->rcu, rcu_free_acts_callback); -} -EXPORT_SYMBOL(flow_deferred_free_acts); - -/* Setup the action on the flow, just after it was created with flow_alloc(). - * Jean II */ -void flow_setup_actions(struct sw_flow * flow, - const struct ofp_action_header * actions, - int actions_len) -{ - /* Basic init of the flow stucture */ - flow->used = flow->created = get_jiffies_64(); - flow->byte_count = 0; - flow->packet_count = 0; - spin_lock_init(&flow->lock); - - /* Make sure we don't blow the allocation done earlier */ - if(actions_len > flow->sf_acts->actions_len) { - printk(KERN_ERR "flow_setup_actions: actions_len is too big (%d > %d)", - actions_len, flow->sf_acts->actions_len); - return; - } - - /* Setup the actions - No need for RCU at this point ;-) */ - memcpy(flow->sf_acts->actions, actions, actions_len); -} - -/* Copies 'actions' into a newly allocated structure for use by 'flow' - * and safely frees the structure that defined the previous actions. */ -void flow_replace_acts(struct sw_flow *flow, - const struct ofp_action_header *actions, size_t actions_len) -{ - struct sw_flow_actions *sfa; - struct sw_flow_actions *orig_sfa = flow->sf_acts; - size_t size = sizeof *sfa + actions_len; - - sfa = kmalloc(size, GFP_ATOMIC); - if (unlikely(!sfa)) - return; - - sfa->actions_len = actions_len; - memcpy(sfa->actions, actions, actions_len); - - rcu_assign_pointer(flow->sf_acts, sfa); - flow_deferred_free_acts(orig_sfa); - - return; -} -EXPORT_SYMBOL(flow_replace_acts); - -/* Prints a representation of 'key' to the kernel log. */ -void print_flow(const struct sw_flow_key *key) -{ - printk("wild %08x port %04x vlan-vid %04x vlan-pcp %02x " - "src-mac %02x:%02x:%02x:%02x:%02x:%02x " - "dst-mac %02x:%02x:%02x:%02x:%02x:%02x " - "frm-type %04x ip-tos %02x ip-proto %02x " - "src-ip %u.%u.%u.%u dst-ip %u.%u.%u.%u tp-src %d tp-dst %d\n", - key->wildcards, ntohs(key->in_port), ntohs(key->dl_vlan), - key->dl_vlan_pcp, - key->dl_src[0], key->dl_src[1], key->dl_src[2], - key->dl_src[3], key->dl_src[4], key->dl_src[5], - key->dl_dst[0], key->dl_dst[1], key->dl_dst[2], - key->dl_dst[3], key->dl_dst[4], key->dl_dst[5], - ntohs(key->dl_type), - key->nw_tos, key->nw_proto, - ((unsigned char *)&key->nw_src)[0], - ((unsigned char *)&key->nw_src)[1], - ((unsigned char *)&key->nw_src)[2], - ((unsigned char *)&key->nw_src)[3], - ((unsigned char *)&key->nw_dst)[0], - ((unsigned char *)&key->nw_dst)[1], - ((unsigned char *)&key->nw_dst)[2], - ((unsigned char *)&key->nw_dst)[3], - ntohs(key->tp_src), ntohs(key->tp_dst)); -} -EXPORT_SYMBOL(print_flow); - -#define SNAP_OUI_LEN 3 - -struct eth_snap_hdr -{ - struct ethhdr eth; - uint8_t dsap; /* Always 0xAA */ - uint8_t ssap; /* Always 0xAA */ - uint8_t ctrl; - uint8_t oui[SNAP_OUI_LEN]; - uint16_t ethertype; -} __attribute__ ((packed)); - -static int is_snap(const struct eth_snap_hdr *esh) -{ - return (esh->dsap == LLC_SAP_SNAP - && esh->ssap == LLC_SAP_SNAP - && !memcmp(esh->oui, "\0\0\0", 3)); -} - -/* Parses the Ethernet frame in 'skb', which was received on 'in_port', - * and initializes 'key' to match. Returns 1 if 'skb' contains an IP - * fragment, 0 otherwise. */ -int flow_extract(struct sk_buff *skb, uint16_t in_port, - struct sw_flow_key *key) -{ - struct ethhdr *eth; - struct eth_snap_hdr *esh; - int retval = 0; - int nh_ofs; - - memset(key, 0, sizeof *key); - key->dl_vlan = htons(OFP_VLAN_NONE); - key->in_port = htons(in_port); - - if (skb->len < sizeof *eth) - return 0; - if (!pskb_may_pull(skb, skb->len >= 64 ? 64 : skb->len)) { - return 0; - } - - skb_reset_mac_header(skb); - eth = eth_hdr(skb); - esh = (struct eth_snap_hdr *) eth; - nh_ofs = sizeof *eth; - if (likely(ntohs(eth->h_proto) >= OFP_DL_TYPE_ETH2_CUTOFF)) - key->dl_type = eth->h_proto; - else if (skb->len >= sizeof *esh && is_snap(esh)) { - key->dl_type = esh->ethertype; - nh_ofs = sizeof *esh; - } else { - key->dl_type = htons(OFP_DL_TYPE_NOT_ETH_TYPE); - if (skb->len >= nh_ofs + sizeof(struct llc_pdu_un)) { - nh_ofs += sizeof(struct llc_pdu_un); - } - } - - /* Check for a VLAN tag */ - if (key->dl_type == htons(ETH_P_8021Q) && - skb->len >= nh_ofs + sizeof(struct vlan_hdr)) { - struct vlan_hdr *vh = (struct vlan_hdr*)(skb->data + nh_ofs); - key->dl_type = vh->h_vlan_encapsulated_proto; - key->dl_vlan = vh->h_vlan_TCI & htons(VLAN_VID_MASK); - key->dl_vlan_pcp = (uint8_t)((ntohs(vh->h_vlan_TCI) >> VLAN_PCP_SHIFT) - & VLAN_PCP_BITMASK); - nh_ofs += sizeof(struct vlan_hdr); - } - memcpy(key->dl_src, eth->h_source, ETH_ALEN); - memcpy(key->dl_dst, eth->h_dest, ETH_ALEN); - skb_set_network_header(skb, nh_ofs); - - /* Network layer. */ - if (key->dl_type == htons(ETH_P_IP) && iphdr_ok(skb)) { - struct iphdr *nh = ip_hdr(skb); - int th_ofs = nh_ofs + nh->ihl * 4; - key->nw_tos = nh->tos & 0xfc; - key->nw_proto = nh->protocol; - key->nw_src = nh->saddr; - key->nw_dst = nh->daddr; - skb_set_transport_header(skb, th_ofs); - - /* Transport layer. */ - if (!(nh->frag_off & htons(IP_MF | IP_OFFSET))) { - if (key->nw_proto == IPPROTO_TCP) { - if (tcphdr_ok(skb)) { - struct tcphdr *tcp = tcp_hdr(skb); - key->tp_src = tcp->source; - key->tp_dst = tcp->dest; - } else { - /* Avoid tricking other code into - * thinking that this packet has an L4 - * header. */ - key->nw_proto = 0; - } - } else if (key->nw_proto == IPPROTO_UDP) { - if (udphdr_ok(skb)) { - struct udphdr *udp = udp_hdr(skb); - key->tp_src = udp->source; - key->tp_dst = udp->dest; - } else { - /* Avoid tricking other code into - * thinking that this packet has an L4 - * header. */ - key->nw_proto = 0; - } - } else if (key->nw_proto == IPPROTO_ICMP) { - if (icmphdr_ok(skb)) { - struct icmphdr *icmp = icmp_hdr(skb); - /* The ICMP type and code fields use the 16-bit - * transport port fields, so we need to store them - * in 16-bit network byte order. */ - key->icmp_type = htons(icmp->type); - key->icmp_code = htons(icmp->code); - } else { - /* Avoid tricking other code into - * thinking that this packet has an L4 - * header. */ - key->nw_proto = 0; - } - } - } else { - retval = 1; - } - } else { - skb_reset_transport_header(skb); - } - return retval; -} - -/* Initializes the flow module. - * Returns zero if successful or a negative error code. */ -int flow_init(void) -{ - flow_cache = kmem_cache_create("sw_flow", sizeof(struct sw_flow), 0, - 0, NULL); - if (flow_cache == NULL) - return -ENOMEM; - - return 0; -} - -/* Uninitializes the flow module. */ -void flow_exit(void) -{ - kmem_cache_destroy(flow_cache); -} - diff --git a/openflow/datapath/flow.h b/openflow/datapath/flow.h deleted file mode 100644 index 5f8597a3..00000000 --- a/openflow/datapath/flow.h +++ /dev/null @@ -1,199 +0,0 @@ -#ifndef FLOW_H -#define FLOW_H 1 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "openflow/openflow.h" - -#define VLAN_PCP_SHIFT 13 -#define VLAN_PCP_BITMASK 0x0007 /* the least 3-bit is valid */ - -struct sk_buff; -struct ofp_flow_mod; - -/* Identification data for a flow. - * Network byte order except for the "wildcards" field. - * Ordered to make bytewise comparisons (e.g. with memcmp()) fail quickly and - * to keep the amount of padding to a minimum. - * If you change the ordering of fields here, change flow_keys_equal() to - * compare the proper fields. - */ -struct sw_flow_key { - uint32_t nw_src; /* IP source address. */ - uint32_t nw_dst; /* IP destination address. */ - uint16_t in_port; /* Input switch port */ - uint16_t dl_vlan; /* Input VLAN id. */ - uint16_t dl_type; /* Ethernet frame type. */ - uint16_t tp_src; /* TCP/UDP source port. */ - uint16_t tp_dst; /* TCP/UDP destination port. */ - uint8_t dl_src[ETH_ALEN]; /* Ethernet source address. */ - uint8_t dl_dst[ETH_ALEN]; /* Ethernet destination address. */ - uint8_t dl_vlan_pcp; /* Input VLAN priority. */ - uint8_t nw_tos; /* IPv4 DSCP */ - uint8_t nw_proto; /* IP protocol. */ - uint8_t pad[3]; - uint32_t wildcards; /* Wildcard fields (host byte order). */ - uint32_t nw_src_mask; /* 1-bit in each significant nw_src bit. */ - uint32_t nw_dst_mask; /* 1-bit in each significant nw_dst bit. */ -}; - -/* The match fields for ICMP type and code use the transport source and - * destination port fields, respectively. */ -#define icmp_type tp_src -#define icmp_code tp_dst - -/* Compare two sw_flow_keys and return true if they are the same flow, false - * otherwise. Wildcards and netmasks are not considered. */ -static inline int flow_keys_equal(const struct sw_flow_key *a, - const struct sw_flow_key *b) -{ - return !memcmp(a, b, offsetof(struct sw_flow_key, wildcards)); -} - -/* We need to manually make sure that the structure is 32-bit aligned, - * since we don't want garbage values in compiler-generated pads from - * messing up hash matches. - */ -static inline void check_key_align(void) -{ - BUILD_BUG_ON(sizeof(struct sw_flow_key) != 48); -} - -/* We keep actions as a separate structure because we need to be able to - * swap them out atomically when the modify command comes from a Flow - * Modify message. */ -struct sw_flow_actions { - size_t actions_len; - struct rcu_head rcu; - - struct ofp_action_header actions[0]; -}; - -/* Locking: - * - * - Readers must take rcu_read_lock and hold it the entire time that the flow - * must continue to exist. - * - * - Writers must hold dp_mutex. - */ -struct sw_flow { - struct sw_flow_key key; - - uint16_t priority; /* Only used on entries with wildcards. */ - uint16_t idle_timeout; /* Idle time before discarding (seconds). */ - uint16_t hard_timeout; /* Hard expiration time (seconds) */ - uint64_t used; /* Last used time (in jiffies). */ - uint8_t send_flow_rem; /* Send a flow removed to the controller */ - uint8_t emerg_flow; /* Emergency flow indicator */ - - struct sw_flow_actions *sf_acts; - - /* For use by table implementation. */ - struct list_head node; - struct list_head iter_node; - unsigned long serial; - void *private; - - spinlock_t lock; /* Lock this entry...mostly for stat updates */ - uint64_t created; /* When the flow was created (in jiffies_64). */ - uint64_t packet_count; /* Number of packets associated with this entry */ - uint64_t byte_count; /* Number of bytes associated with this entry */ - - struct rcu_head rcu; -}; - -int flow_matches_1wild(const struct sw_flow_key *, const struct sw_flow_key *); -int flow_matches_2wild(const struct sw_flow_key *, const struct sw_flow_key *); -int flow_matches_desc(const struct sw_flow_key *, const struct sw_flow_key *, - int); -int flow_matches_2desc(const struct sw_flow_key *, const struct sw_flow_key *, - int); -int flow_has_out_port(struct sw_flow *, uint16_t); -struct sw_flow *flow_alloc(size_t actions_len, gfp_t flags); -void flow_free(struct sw_flow *); -void flow_deferred_free(struct sw_flow *); -void flow_deferred_free_acts(struct sw_flow_actions *); -void flow_setup_actions(struct sw_flow *, const struct ofp_action_header *, - int); -void flow_replace_acts(struct sw_flow *, const struct ofp_action_header *, - size_t); -int flow_extract(struct sk_buff *, uint16_t in_port, struct sw_flow_key *); -void flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from); -void flow_fill_match(struct ofp_match* to, const struct sw_flow_key* from); -int flow_timeout(struct sw_flow *); - -void print_flow(const struct sw_flow_key *); - -static inline int iphdr_ok(struct sk_buff *skb) -{ - int nh_ofs = skb_network_offset(skb); - if (skb->len >= nh_ofs + sizeof(struct iphdr)) { - int ip_len = ip_hdrlen(skb); - return (ip_len >= sizeof(struct iphdr) - && pskb_may_pull(skb, nh_ofs + ip_len)); - } - return 0; -} - -static inline int tcphdr_ok(struct sk_buff *skb) -{ - int th_ofs = skb_transport_offset(skb); - if (pskb_may_pull(skb, th_ofs + sizeof(struct tcphdr))) { - int tcp_len = tcp_hdrlen(skb); - return (tcp_len >= sizeof(struct tcphdr) - && skb->len >= th_ofs + tcp_len); - } - return 0; -} - -static inline int udphdr_ok(struct sk_buff *skb) -{ - int th_ofs = skb_transport_offset(skb); - return pskb_may_pull(skb, th_ofs + sizeof(struct udphdr)); -} - -static inline int icmphdr_ok(struct sk_buff *skb) -{ - int th_ofs = skb_transport_offset(skb); - return pskb_may_pull(skb, th_ofs + sizeof(struct icmphdr)); -} - -#define TCP_FLAGS_OFFSET 13 -#define TCP_FLAG_MASK 0x3f - -static inline struct ofp_tcphdr *ofp_tcp_hdr(const struct sk_buff *skb) -{ - return (struct ofp_tcphdr *)skb_transport_header(skb); -} - -static inline void flow_used(struct sw_flow *flow, struct sk_buff *skb) -{ - unsigned long flags; - - flow->used = get_jiffies_64(); - - spin_lock_irqsave(&flow->lock, flags); - flow->packet_count++; - flow->byte_count += skb->len; - spin_unlock_irqrestore(&flow->lock, flags); -} - -extern struct kmem_cache *flow_cache; - -int flow_init(void); -void flow_exit(void); - -#endif /* flow.h */ diff --git a/openflow/datapath/forward.c b/openflow/datapath/forward.c deleted file mode 100644 index 40d2a332..00000000 --- a/openflow/datapath/forward.c +++ /dev/null @@ -1,642 +0,0 @@ -/* - * Distributed under the terms of the GNU GPL version 2. - * Copyright (c) 2007, 2008, 2009 The Board of Trustees of The Leland - * Stanford Junior University - */ - -#include -#include -#include -#include -#include -#include -#include "forward.h" -#include "datapath.h" -#include "openflow/nicira-ext.h" -#include "openflow/private-ext.h" -#include "dp_act.h" -#include "private-msg.h" -#include "openflow-ext.h" -#include "chain.h" -#include "flow.h" - -/* FIXME: do we need to use GFP_ATOMIC everywhere here? */ - - -static struct sk_buff *retrieve_skb(uint32_t id); -static void discard_skb(uint32_t id); - -/* 'skb' was received on port 'p', which may be a physical switch port, the - * local port, or a null pointer. Process it according to 'chain'. Returns 0 - * if successful, in which case 'skb' is destroyed, or -ESRCH if there is no - * matching flow, in which case 'skb' still belongs to the caller. */ -int run_flow_through_tables(struct sw_chain *chain, struct sk_buff *skb, - struct net_bridge_port *p) -{ - /* Ethernet address used as the destination for STP frames. */ - static const uint8_t stp_eth_addr[ETH_ALEN] - = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x01 }; - struct sw_flow_key key; - struct sw_flow *flow; - - if (flow_extract(skb, p ? p->port_no : OFPP_NONE, &key) - && (chain->dp->flags & OFPC_FRAG_MASK) == OFPC_FRAG_DROP) { - /* Drop fragment. */ - kfree_skb(skb); - return 0; - } - if (p && p->config & (OFPPC_NO_RECV | OFPPC_NO_RECV_STP) && - p->config & (compare_ether_addr(key.dl_dst, stp_eth_addr) - ? OFPPC_NO_RECV : OFPPC_NO_RECV_STP)) { - kfree_skb(skb); - return 0; - } - - flow = chain_lookup(chain, &key, 0); - if (likely(flow != NULL)) { - struct sw_flow_actions *sf_acts = rcu_dereference(flow->sf_acts); - flow_used(flow, skb); - execute_actions(chain->dp, skb, &key, - sf_acts->actions, sf_acts->actions_len, 0); - return 0; - } else { - return -ESRCH; - } -} - -/* 'skb' was received on port 'p', which may be a physical switch port, the - * local port, or a null pointer. Process it according to 'chain', sending it - * up to the controller if no flow matches. Takes ownership of 'skb'. */ -void fwd_port_input(struct sw_chain *chain, struct sk_buff *skb, - struct net_bridge_port *p) -{ - WARN_ON_ONCE(skb_shared(skb)); - WARN_ON_ONCE(skb->destructor); - if (run_flow_through_tables(chain, skb, p)) - dp_output_control(chain->dp, skb, chain->dp->miss_send_len, - OFPR_NO_MATCH); -} - -static int -recv_hello(struct sw_chain *chain, const struct sender *sender, - const void *msg) -{ - return dp_send_hello(chain->dp, sender, msg); -} - -static int -recv_barrier_request(struct sw_chain *chain, const struct sender *sender, - const void *msg) -{ - return dp_send_barrier_reply(chain->dp, sender, msg); -} - -static int -recv_features_request(struct sw_chain *chain, const struct sender *sender, - const void *msg) -{ - return dp_send_features_reply(chain->dp, sender); -} - -static int -recv_get_config_request(struct sw_chain *chain, const struct sender *sender, - const void *msg) -{ - return dp_send_config_reply(chain->dp, sender); -} - -static int -recv_set_config(struct sw_chain *chain, const struct sender *sender, - const void *msg) -{ - const struct ofp_switch_config *osc = msg; - int flags; - - flags = ntohs(osc->flags) & OFPC_FRAG_MASK; - if ((flags & OFPC_FRAG_MASK) != OFPC_FRAG_NORMAL - && (flags & OFPC_FRAG_MASK) != OFPC_FRAG_DROP) { - flags = (flags & ~OFPC_FRAG_MASK) | OFPC_FRAG_DROP; - } - chain->dp->flags = flags; - - chain->dp->miss_send_len = ntohs(osc->miss_send_len); - - return 0; -} - -static int -recv_packet_out(struct sw_chain *chain, const struct sender *sender, - const void *msg) -{ - const struct ofp_packet_out *opo = msg; - struct sk_buff *skb; - uint16_t v_code; - struct sw_flow_key key; - size_t actions_len = ntohs(opo->actions_len); - - if (actions_len > (ntohs(opo->header.length) - sizeof *opo)) { - if (net_ratelimit()) - printk(KERN_NOTICE "%s: message too short for number " - "of actions\n", chain->dp->netdev->name); - return -EINVAL; - } - - if (ntohl(opo->buffer_id) == (uint32_t) -1) { - int data_len = ntohs(opo->header.length) - sizeof *opo - actions_len; - - /* FIXME: there is likely a way to reuse the data in msg. */ - skb = alloc_skb(data_len, GFP_ATOMIC); - if (!skb) - return -ENOMEM; - - /* FIXME? We don't reserve NET_IP_ALIGN or NET_SKB_PAD since - * we're just transmitting this raw without examining anything - * at those layers. */ - skb_put(skb, data_len); - skb_copy_to_linear_data(skb, - (uint8_t *)opo->actions + actions_len, - data_len); - skb_reset_mac_header(skb); - } else { - skb = retrieve_skb(ntohl(opo->buffer_id)); - if (!skb) - return -ESRCH; - } - - dp_set_origin(chain->dp, ntohs(opo->in_port), skb); - - flow_extract(skb, ntohs(opo->in_port), &key); - - v_code = validate_actions(chain->dp, &key, opo->actions, actions_len); - if (v_code != ACT_VALIDATION_OK) { - dp_send_error_msg(chain->dp, sender, OFPET_BAD_ACTION, v_code, - msg, ntohs(opo->header.length)); - goto error; - } - - execute_actions(chain->dp, skb, &key, opo->actions, actions_len, 1); - - return 0; - -error: - kfree_skb(skb); - return -EINVAL; -} - -static int -recv_port_mod(struct sw_chain *chain, const struct sender *sender, - const void *msg) -{ - const struct ofp_port_mod *opm = msg; - - dp_update_port_flags(chain->dp, opm); - - return 0; -} - -static int -recv_echo_request(struct sw_chain *chain, const struct sender *sender, - const void *msg) -{ - return dp_send_echo_reply(chain->dp, sender, msg); -} - -static int -recv_echo_reply(struct sw_chain *chain, const struct sender *sender, - const void *msg) -{ - return 0; -} - -static int -add_flow(struct sw_chain *chain, const struct sender *sender, - const struct ofp_flow_mod *ofm) -{ - int error = -ENOMEM; - uint16_t v_code; - struct sw_flow *flow; - size_t actions_len = ntohs(ofm->header.length) - sizeof *ofm; - int overlap; - - /* Allocate memory. */ - flow = flow_alloc(actions_len, GFP_ATOMIC); - if (flow == NULL) - goto error; - - flow_extract_match(&flow->key, &ofm->match); - - v_code = validate_actions(chain->dp, &flow->key, ofm->actions, actions_len); - if (v_code != ACT_VALIDATION_OK) { - dp_send_error_msg(chain->dp, sender, OFPET_BAD_ACTION, v_code, - ofm, ntohs(ofm->header.length)); - goto error_free_flow; - } - - flow->priority = flow->key.wildcards ? ntohs(ofm->priority) : -1; - - if (ntohs(ofm->flags) & OFPFF_CHECK_OVERLAP) { - /* check whether there is any conflict */ - overlap = chain_has_conflict(chain, &flow->key, flow->priority, - false); - if (overlap){ - dp_send_error_msg(chain->dp, sender, - OFPET_FLOW_MOD_FAILED, - OFPFMFC_OVERLAP, - ofm, ntohs(ofm->header.length)); - goto error_free_flow; - } - } - - if (ntohs(ofm->flags) & OFPFF_EMERG) { - if (ntohs(ofm->idle_timeout) != OFP_FLOW_PERMANENT - || ntohs(ofm->hard_timeout) != OFP_FLOW_PERMANENT) { - dp_send_error_msg(chain->dp, sender, - OFPET_FLOW_MOD_FAILED, - OFPFMFC_BAD_EMERG_TIMEOUT, - ofm, ntohs(ofm->header.length)); - goto error_free_flow; - } - } - - /* Fill out flow. */ - flow->idle_timeout = ntohs(ofm->idle_timeout); - flow->hard_timeout = ntohs(ofm->hard_timeout); - flow->send_flow_rem = (ntohs(ofm->flags) & OFPFF_SEND_FLOW_REM) ? 1 : 0; - flow->emerg_flow = (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0; - flow_setup_actions(flow, ofm->actions, actions_len); - - /* Act. */ - error = chain_insert(chain, flow, - (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0); - if (error == -ENOBUFS) { - dp_send_error_msg(chain->dp, sender, OFPET_FLOW_MOD_FAILED, - OFPFMFC_ALL_TABLES_FULL, ofm, ntohs(ofm->header.length)); - goto error_free_flow; - } else if (error) - goto error_free_flow; - - error = 0; - if (ntohl(ofm->buffer_id) != (uint32_t) -1) { - struct sk_buff *skb = retrieve_skb(ntohl(ofm->buffer_id)); - if (skb) { - struct sw_flow_key key; - flow_used(flow, skb); - dp_set_origin(chain->dp, ntohs(ofm->match.in_port), skb); - flow_extract(skb, ntohs(ofm->match.in_port), &key); - execute_actions(chain->dp, skb, &key, ofm->actions, actions_len, 0); - } - else - error = -ESRCH; - } - return error; - -error_free_flow: - flow_free(flow); -error: - if (ntohl(ofm->buffer_id) != (uint32_t) -1) - discard_skb(ntohl(ofm->buffer_id)); - return error; -} - -static int -mod_flow(struct sw_chain *chain, const struct sender *sender, - const struct ofp_flow_mod *ofm) -{ - int error = -ENOMEM; - uint16_t v_code; - size_t actions_len = ntohs(ofm->header.length) - sizeof *ofm; - struct sw_flow *flow; - int strict; - - /* Allocate memory. */ - flow = flow_alloc(actions_len,GFP_ATOMIC); - if (flow == NULL) - goto error; - - flow_extract_match(&flow->key, &ofm->match); - - v_code = validate_actions(chain->dp, &flow->key, ofm->actions, actions_len); - if (v_code != ACT_VALIDATION_OK) { - dp_send_error_msg(chain->dp, sender, OFPET_BAD_ACTION, v_code, - ofm, ntohs(ofm->header.length)); - goto error_free_flow; - } - - flow->priority = flow->key.wildcards ? ntohs(ofm->priority) : -1; - strict = (ofm->command == htons(OFPFC_MODIFY_STRICT)) ? 1 : 0; - - /* First try to modify existing flows if any */ - /* if there is no matching flow, add it */ - if (!chain_modify(chain, &flow->key, flow->priority, strict, - ofm->actions, actions_len, - (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0)) { - /* Fill out flow. */ - flow->idle_timeout = ntohs(ofm->idle_timeout); - flow->hard_timeout = ntohs(ofm->hard_timeout); - flow->send_flow_rem = (ntohs(ofm->flags) & OFPFF_SEND_FLOW_REM) - ? 1 : 0; - flow->emerg_flow = (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0; - flow_setup_actions(flow, ofm->actions, actions_len); - error = chain_insert(chain, flow, - (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0); - if (error == -ENOBUFS) { - dp_send_error_msg(chain->dp, sender, - OFPET_FLOW_MOD_FAILED, - OFPFMFC_ALL_TABLES_FULL, - ofm, ntohs(ofm->header.length)); - goto error_free_flow; - } else if (error) { - goto error_free_flow; - } - } - - error = 0; - if (ntohl(ofm->buffer_id) != (uint32_t) -1) { - struct sk_buff *skb = retrieve_skb(ntohl(ofm->buffer_id)); - if (skb) { - struct sw_flow_key skb_key; - flow_extract(skb, ntohs(ofm->match.in_port), &skb_key); - execute_actions(chain->dp, skb, &skb_key, - ofm->actions, actions_len, 0); - } - else - error = -ESRCH; - } - return error; - -error_free_flow: - flow_free(flow); -error: - if (ntohl(ofm->buffer_id) != (uint32_t) -1) - discard_skb(ntohl(ofm->buffer_id)); - return error; -} - -static int -recv_flow(struct sw_chain *chain, const struct sender *sender, const void *msg) -{ - const struct ofp_flow_mod *ofm = msg; - uint16_t command = ntohs(ofm->command); - - if (command == OFPFC_ADD) { - return add_flow(chain, sender, ofm); - } else if ((command == OFPFC_MODIFY) || (command == OFPFC_MODIFY_STRICT)) { - return mod_flow(chain, sender, ofm); - } else if (command == OFPFC_DELETE) { - struct sw_flow_key key; - flow_extract_match(&key, &ofm->match); - return chain_delete(chain, &key, ofm->out_port, 0, 0, - (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0) - ? 0 : -ESRCH; - } else if (command == OFPFC_DELETE_STRICT) { - struct sw_flow_key key; - uint16_t priority; - flow_extract_match(&key, &ofm->match); - priority = key.wildcards ? ntohs(ofm->priority) : -1; - return chain_delete(chain, &key, ofm->out_port, priority, 1, - (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0) - ? 0 : -ESRCH; - } else { - return -ENOTSUPP; - } -} - -static int -recv_vendor(struct sw_chain *chain, const struct sender *sender, - const void *msg) -{ - const struct ofp_vendor_header *ovh = msg; - - switch(ntohl(ovh->vendor)) - { - case PRIVATE_VENDOR_ID: - return private_recv_msg(chain, sender, msg); - case OPENFLOW_VENDOR_ID: - return openflow_ext_recv_msg(chain, sender, msg); - default: - if (net_ratelimit()) - printk(KERN_NOTICE "%s: unknown vendor: 0x%x\n", - chain->dp->netdev->name, ntohl(ovh->vendor)); - dp_send_error_msg(chain->dp, sender, OFPET_BAD_REQUEST, - OFPBRC_BAD_VENDOR, msg, ntohs(ovh->header.length)); - return -EINVAL; - } -} - -/* 'msg', which is 'length' bytes long, was received across Netlink from - * 'sender'. Apply it to 'chain'. */ -int -fwd_control_input(struct sw_chain *chain, const struct sender *sender, - const void *msg, size_t length) -{ - - struct openflow_packet { - size_t min_size; - int (*handler)(struct sw_chain *, const struct sender *, - const void *); - }; - - static const struct openflow_packet packets[] = { - [OFPT_HELLO] = { - sizeof (struct ofp_header), - recv_hello, - }, - [OFPT_BARRIER_REQUEST] = { - sizeof (struct ofp_header), - recv_barrier_request, - }, - [OFPT_ECHO_REQUEST] = { - sizeof (struct ofp_header), - recv_echo_request, - }, - [OFPT_ECHO_REPLY] = { - sizeof (struct ofp_header), - recv_echo_reply, - }, - [OFPT_VENDOR] = { - sizeof (struct ofp_vendor_header), - recv_vendor, - }, - [OFPT_FEATURES_REQUEST] = { - sizeof (struct ofp_header), - recv_features_request, - }, - [OFPT_GET_CONFIG_REQUEST] = { - sizeof (struct ofp_header), - recv_get_config_request, - }, - [OFPT_SET_CONFIG] = { - sizeof (struct ofp_switch_config), - recv_set_config, - }, - [OFPT_PACKET_OUT] = { - sizeof (struct ofp_packet_out), - recv_packet_out, - }, - [OFPT_FLOW_MOD] = { - sizeof (struct ofp_flow_mod), - recv_flow, - }, - [OFPT_PORT_MOD] = { - sizeof (struct ofp_port_mod), - recv_port_mod, - } - }; - - struct ofp_header *oh; - - oh = (struct ofp_header *) msg; - if (oh->version != OFP_VERSION - && oh->type != OFPT_HELLO - && oh->type != OFPT_ERROR - && oh->type != OFPT_ECHO_REQUEST - && oh->type != OFPT_ECHO_REPLY - && oh->type != OFPT_VENDOR) - { - dp_send_error_msg(chain->dp, sender, OFPET_BAD_REQUEST, - OFPBRC_BAD_VERSION, msg, length); - return -EINVAL; - } - if (ntohs(oh->length) != length) { - if (net_ratelimit()) - printk(KERN_NOTICE "%s: received message length " - "wrong: %d/%d\n", chain->dp->netdev->name, - ntohs(oh->length), length); - return -EINVAL; - } - - if (oh->type < ARRAY_SIZE(packets)) { - const struct openflow_packet *pkt = &packets[oh->type]; - if (pkt->handler) { - if (length < pkt->min_size) - return -EFAULT; - return pkt->handler(chain, sender, msg); - } - } - dp_send_error_msg(chain->dp, sender, OFPET_BAD_REQUEST, - OFPBRC_BAD_TYPE, msg, length); - return -EINVAL; -} - -/* Packet buffering. */ - -#define OVERWRITE_SECS 1 -#define OVERWRITE_JIFFIES (OVERWRITE_SECS * HZ) - -struct packet_buffer { - struct sk_buff *skb; - uint32_t cookie; - unsigned long exp_jiffies; -}; - -static struct packet_buffer buffers[N_PKT_BUFFERS]; -static unsigned int buffer_idx; -static DEFINE_SPINLOCK(buffer_lock); - -uint32_t fwd_save_skb(struct sk_buff *skb) -{ - struct sk_buff *old_skb = NULL; - struct packet_buffer *p; - unsigned long int flags; - uint32_t id; - - /* FIXME: Probably just need a skb_clone() here. */ - skb = skb_copy(skb, GFP_ATOMIC); - if (!skb) - return -1; - - spin_lock_irqsave(&buffer_lock, flags); - buffer_idx = (buffer_idx + 1) & PKT_BUFFER_MASK; - p = &buffers[buffer_idx]; - if (p->skb) { - /* Don't buffer packet if existing entry is less than - * OVERWRITE_SECS old. */ - if (time_before(jiffies, p->exp_jiffies)) { - spin_unlock_irqrestore(&buffer_lock, flags); - kfree_skb(skb); - return -1; - } else { - /* Defer kfree_skb() until interrupts re-enabled. - * FIXME: we only need to do that if it has a - * destructor, but it never should since we orphan - * sk_buffs on entry. */ - old_skb = p->skb; - } - } - /* Don't use maximum cookie value since the all-bits-1 id is - * special. */ - if (++p->cookie >= (1u << PKT_COOKIE_BITS) - 1) - p->cookie = 0; - p->skb = skb; - p->exp_jiffies = jiffies + OVERWRITE_JIFFIES; - id = buffer_idx | (p->cookie << PKT_BUFFER_BITS); - spin_unlock_irqrestore(&buffer_lock, flags); - - if (old_skb) - kfree_skb(old_skb); - - return id; -} - -static struct sk_buff *retrieve_skb(uint32_t id) -{ - unsigned long int flags; - struct sk_buff *skb = NULL; - struct packet_buffer *p; - - spin_lock_irqsave(&buffer_lock, flags); - p = &buffers[id & PKT_BUFFER_MASK]; - if (p->cookie == id >> PKT_BUFFER_BITS) { - skb = p->skb; - p->skb = NULL; - } else { - if (net_ratelimit()) - printk(KERN_NOTICE "cookie mismatch: %x != %x\n", - id >> PKT_BUFFER_BITS, p->cookie); - } - spin_unlock_irqrestore(&buffer_lock, flags); - - return skb; -} - -void fwd_discard_all(void) -{ - int i; - - for (i = 0; i < N_PKT_BUFFERS; i++) { - struct sk_buff *skb; - unsigned long int flags; - - /* Defer kfree_skb() until interrupts re-enabled. */ - spin_lock_irqsave(&buffer_lock, flags); - skb = buffers[i].skb; - buffers[i].skb = NULL; - spin_unlock_irqrestore(&buffer_lock, flags); - - kfree_skb(skb); - } -} - -static void discard_skb(uint32_t id) -{ - struct sk_buff *old_skb = NULL; - unsigned long int flags; - struct packet_buffer *p; - - spin_lock_irqsave(&buffer_lock, flags); - p = &buffers[id & PKT_BUFFER_MASK]; - if (p->cookie == id >> PKT_BUFFER_BITS) { - /* Defer kfree_skb() until interrupts re-enabled. */ - old_skb = p->skb; - p->skb = NULL; - } - spin_unlock_irqrestore(&buffer_lock, flags); - - if (old_skb) - kfree_skb(old_skb); -} - -void fwd_exit(void) -{ - fwd_discard_all(); -} diff --git a/openflow/datapath/forward.h b/openflow/datapath/forward.h deleted file mode 100644 index 2aa9ee37..00000000 --- a/openflow/datapath/forward.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef FORWARD_H -#define FORWARD_H 1 - -#include -#include "datapath.h" -#include "flow.h" - -struct sk_buff; -struct sw_chain; -struct sender; - -/* Buffers are identified to userspace by a 31-bit opaque ID. We divide the ID - * into a buffer number (low bits) and a cookie (high bits). The buffer number - * is an index into an array of buffers. The cookie distinguishes between - * different packets that have occupied a single buffer. Thus, the more - * buffers we have, the lower-quality the cookie... */ -#define PKT_BUFFER_BITS 8 -#define N_PKT_BUFFERS (1 << PKT_BUFFER_BITS) -#define PKT_BUFFER_MASK (N_PKT_BUFFERS - 1) - -#define PKT_COOKIE_BITS (32 - PKT_BUFFER_BITS) - -#define UINT32_MAX 4294967295U -#define UINT16_MAX 65535 -#define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) - -void fwd_port_input(struct sw_chain *, struct sk_buff *, - struct net_bridge_port *); -int run_flow_through_tables(struct sw_chain *, struct sk_buff *, - struct net_bridge_port *); -int fwd_control_input(struct sw_chain *, const struct sender *, - const void *, size_t); - -uint32_t fwd_save_skb(struct sk_buff *skb); -void fwd_discard_all(void); -void fwd_exit(void); - -#endif /* forward.h */ diff --git a/openflow/datapath/hwtable_dummy/Modules.mk b/openflow/datapath/hwtable_dummy/Modules.mk deleted file mode 100644 index 08e56b1e..00000000 --- a/openflow/datapath/hwtable_dummy/Modules.mk +++ /dev/null @@ -1,7 +0,0 @@ -# Specify the module to build. -build_modules += ofdatapath_dummy -dist_modules += ofdatapath_dummy - -# Specify the source files that comprise the module. -ofdatapath_dummy_sources = \ - hwtable_dummy/hwtable_dummy.c diff --git a/openflow/datapath/hwtable_dummy/hwtable_dummy.c b/openflow/datapath/hwtable_dummy/hwtable_dummy.c deleted file mode 100644 index 82150d0f..00000000 --- a/openflow/datapath/hwtable_dummy/hwtable_dummy.c +++ /dev/null @@ -1,320 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "chain.h" -#include "table.h" -#include "flow.h" -#include "datapath.h" - -/* Max number of flow entries supported by the hardware */ -#define TMPL_MAX_FLOWS 8192 - -/* sw_flow private data for dummy table entries. */ -struct tmpl_flow { - struct list_head nodes; - /* XXX: If per-entry data is needed, define it here. */ -}; - -struct tmpl_flowtable { - struct sw_table flowtab; - unsigned int max_flows; - atomic_t num_flows; - struct list_head flows; - struct list_head iter_flows; - unsigned long int next_serial; -}; - -static struct sw_flow *tmpl_flowtable_lookup(struct sw_table *, - const struct sw_flow_key *); -static int tmpl_install_flow(struct sw_table *, struct sw_flow *); -static int tmpl_modify_flow(struct sw_table *, const struct sw_flow_key *, - uint16_t, int, const struct ofp_action_header *, - size_t); -static int do_uninstall(struct datapath *, struct sw_table *, struct sw_flow *, - enum ofp_flow_removed_reason); -static int tmpl_uninstall_flow(struct datapath *, struct sw_table *, - const struct sw_flow_key *, - uint16_t, uint16_t, int); -static int tmpl_flow_timeout(struct datapath *, struct sw_table *); -static void tmpl_destroy_flowtable(struct sw_table *); -static int tmpl_iterate_flowtable(struct sw_table *, const struct sw_flow_key *, - uint16_t, struct sw_table_position *, - int (*)(struct sw_flow *, void *), void *); -static void tmpl_get_flowstats(struct sw_table *, struct sw_table_stats *); -static struct sw_table *tmpl_create_flowtable(void); -static int __init tmpl_startup(void); -static void tmpl_cleanup(void); - -static struct sw_flow * -tmpl_flowtable_lookup(struct sw_table *flowtab, const struct sw_flow_key *key) -{ - struct tmpl_flowtable *myflowtab = (struct tmpl_flowtable *)flowtab; - struct sw_flow *flow; - - list_for_each_entry(flow, &myflowtab->flows, node) { - if (flow_matches_1wild(key, &flow->key)) { - return flow; - } - } - - return NULL; -} - -static int -tmpl_install_flow(struct sw_table *flowtab, struct sw_flow *flow) -{ - /* XXX: Use a data cache? */ - flow->private = kzalloc(sizeof(struct tmpl_flow), GFP_ATOMIC); - if (flow->private == NULL) - return 0; - - /* XXX: Do whatever needs to be done to insert an entry in hardware. - * If the entry can't be inserted, return 0. This stub code doesn't - * do anything yet, so we're going to return 0... you shouldn't (and - * you should update n_flows in struct tmpl_flowtable, too). - */ - kfree(flow->private); - return 0; -} - -static int -tmpl_modify_flow(struct sw_table *flowtab, const struct sw_flow_key *key, - uint16_t priority, int strict, - const struct ofp_action_header *actions, size_t actions_len) -{ - struct tmpl_flowtable *myflowtab = (struct tmpl_flowtable *)flowtab; - struct sw_flow *flow; - unsigned int count = 0; - - list_for_each_entry(flow, &myflowtab->flows, node) { - if (flow_matches_desc(&flow->key, key, strict) - && (!strict || (flow->priority == priority))) { - flow_replace_acts(flow, actions, actions_len); - /* XXX: Do whatever is necessary to modify the entry - * in hardware - */ - count++; - } - } - - return count; -} - -static int -do_uninstall(struct datapath *dpinst, struct sw_table *flowtab, - struct sw_flow *flow, enum ofp_flow_removed_reason reason) -{ - /* XXX: Remove the entry from hardware. If you need to do any other - * clean-up associated with the entry, do it here. - */ - dp_send_flow_end(dpinst, flow, reason); - list_del_rcu(&flow->node); - list_del_rcu(&flow->iter_node); - flow_deferred_free(flow); - return 1; -} - -static int -tmpl_uninstall_flow(struct datapath *dpinst, struct sw_table *flowtab, - const struct sw_flow_key *key, uint16_t out_port, - uint16_t priority, int strict) -{ - struct tmpl_flowtable *myflowtab = (struct tmpl_flowtable *)flowtab; - struct sw_flow *flow; - unsigned int count = 0; - - list_for_each_entry(flow, &myflowtab->flows, node) { - if (flow_matches_desc(&flow->key, key, strict) - && (!strict || (flow->priority == priority))) - count += do_uninstall(dpinst, flowtab, - flow, OFPRR_DELETE); - } - - if (count != 0) - atomic_sub(count, &myflowtab->num_flows); - return count; -} - -static int -tmpl_flow_timeout(struct datapath *dpinst, struct sw_table *flowtab) -{ - struct tmpl_flowtable *myflowtab = (struct tmpl_flowtable *)flowtab; - struct sw_flow *flow; - int num_uninst_flows = 0; - uint64_t num_forw_packets = 0; - uint64_t num_forw_bytes = 0; - int reason; - - mutex_lock(&dp_mutex); - list_for_each_entry(flow, &myflowtab->flows, node) { - /* XXX: Retrieve the packet and byte counts associated with this - * entry and store them in "packet_count" and "byte_count". - */ -#if 0 - num_forw_pakcets = flow->packet_count + get_hwmib(...); - num_forw_bytes = flow->byte_count + get_hwmib(...); -#endif - if (num_forw_packets > flow->packet_count - && flow->idle_timeout != OFP_FLOW_PERMANENT) { - flow->packet_count = num_forw_packets; - flow->byte_count = num_forw_bytes; - flow->used = get_jiffies_64(); - } - reason = flow_timeout(flow); - if (reason >= 0) { - num_uninst_flows += do_uninstall(dpinst, flowtab, - flow, reason); - } - } - mutex_unlock(&dp_mutex); - - if (num_uninst_flows != 0) - atomic_sub(num_uninst_flows, &myflowtab->num_flows); - return num_uninst_flows; -} - -static void -tmpl_destroy_flowtable(struct sw_table *flowtab) -{ - struct tmpl_flowtable *myflowtab = (struct tmpl_flowtable *)flowtab; - - if (myflowtab == NULL) { - return; - } - - /* XXX: This table is being destroyed, so free any data that you - * don't want to leak. - */ - while (!list_empty(&myflowtab->flows)) { - struct sw_flow *flow = list_entry(myflowtab->flows.next, - struct sw_flow, node); - list_del(&flow->node); - flow_free(flow); - } - - kfree(myflowtab); -} - -static int -tmpl_iterate_flowtable(struct sw_table *flowtab, const struct sw_flow_key *key, - uint16_t out_port, struct sw_table_position *position, - int (*callback) (struct sw_flow *, void *), - void *private) -{ - struct tmpl_flowtable *myflowtab = (struct tmpl_flowtable *)flowtab; - struct sw_flow *flow; - unsigned long start; - int error = 0; - - start = ~position->private[0]; - list_for_each_entry(flow, &myflowtab->iter_flows, iter_node) { - if (flow->serial <= start - && flow_matches_2wild(key, &flow->key)) { - error = callback(flow, private); - if (error) { - position->private[0] = ~flow->serial; - return error; - } - } - } - - return error; -} - -static void -tmpl_get_flowstats(struct sw_table *flowtab, struct sw_table_stats *stats) -{ - struct tmpl_flowtable *myflowtab = (struct tmpl_flowtable *)flowtab; - - stats->name = "template"; - stats->wildcards = OFPFW_ALL; /* XXX: Set this appropriately */ - stats->n_flows = atomic_read(&myflowtab->num_flows); - stats->max_flows = myflowtab->max_flows; - stats->n_matched = flowtab->n_matched; -} - -static struct sw_table * -tmpl_create_flowtable(void) -{ - struct tmpl_flowtable *myflowtab; - struct sw_table *flowtab; - - myflowtab = kzalloc(sizeof(*myflowtab), GFP_KERNEL); - if (myflowtab == NULL) - return NULL; - - flowtab = &myflowtab->flowtab; - flowtab->lookup = tmpl_flowtable_lookup; - flowtab->insert = tmpl_install_flow; - flowtab->modify = tmpl_modify_flow; - flowtab->delete = tmpl_uninstall_flow; - flowtab->timeout = tmpl_flow_timeout; - flowtab->destroy = tmpl_destroy_flowtable; - flowtab->iterate = tmpl_iterate_flowtable; - flowtab->stats = tmpl_get_flowstats; - - myflowtab->max_flows = TMPL_MAX_FLOWS; - atomic_set(&myflowtab->num_flows, 0); - INIT_LIST_HEAD(&myflowtab->flows); - INIT_LIST_HEAD(&myflowtab->iter_flows); - myflowtab->next_serial = 0; - - return flowtab; -} - -static int __init -tmpl_startup(void) -{ - return chain_set_hw_hook(tmpl_create_flowtable, THIS_MODULE); -} - -static void -tmpl_cleanup(void) -{ - chain_clear_hw_hook(); -} - -module_init(tmpl_startup); -module_exit(tmpl_cleanup); - -MODULE_DESCRIPTION("Fastpath Extension Template for OpenFlow Switch"); -MODULE_AUTHOR("Copyright (c) 2008, 2009 " - "The Board of Trustees of The Leland Stanford Junior University"); -MODULE_LICENSE("GPL"); diff --git a/openflow/datapath/hwtable_nf2/Modules.mk b/openflow/datapath/hwtable_nf2/Modules.mk deleted file mode 100644 index 35674911..00000000 --- a/openflow/datapath/hwtable_nf2/Modules.mk +++ /dev/null @@ -1,19 +0,0 @@ -# Specify the module to build. -build_modules += ofdatapath_netfpga -dist_modules += ofdatapath_netfpga - -# Specify the source files that comprise the module. -ofdatapath_netfpga_sources = \ - hwtable_nf2/nf2_flowtable.c \ - hwtable_nf2/nf2_procfs.c \ - hwtable_nf2/nf2_openflow.c \ - hwtable_nf2/nf2_lib.c - -ofdatapath_netfpga_headers = \ - hwtable_nf2/nf2.h \ - hwtable_nf2/nf2_reg.h \ - hwtable_nf2/nf2_hwapi.h \ - hwtable_nf2/nf2_flowtable.h \ - hwtable_nf2/nf2_procfs.h \ - hwtable_nf2/nf2_openflow.h \ - hwtable_nf2/nf2_lib.h diff --git a/openflow/datapath/hwtable_nf2/README b/openflow/datapath/hwtable_nf2/README deleted file mode 100644 index da700f01..00000000 --- a/openflow/datapath/hwtable_nf2/README +++ /dev/null @@ -1,78 +0,0 @@ -NetFPGA Hardware Table - Date - 09/04/09 ----------------------------------------- - -The NetFPGA Hardware Table creates a single software table that contains all -the flows that are currently held in the NetFPGA card. The card itself splits -exact match flows into SRAM and wildcard match flows into TCAMs. Currently -there are 24 usable wildcard flow entries and 32,768 available exact match -entries. - -Installation ----------------------------------------- - -First build OpenFlow ensuring you include the directive to build the -openflow_netfpga2 hardware table in your configure statement: - - % ./configure --with-l26=/lib/modules/`uname -r` --enable-hw-tables=nf2 - -To get debugging output from the NetFPGA hardware table uncomment the following -line from within /datapath/hwtable_nf2/nf2_flowtable.h, then recompile: - - #define NF2_DEBUG 1 - -For further help regarding building OpenFlow please see the INSTALL file in -the OpenFlow root directory. - -Platform support ----------------- - -OpenFlow v0.9 with hwtable_nf2 has been tested on CentOS 5.2(Linux 2.6.18), -which is the officially supported platform of NetFPGA. - -Running ----------------------------------------- - -Use nf2_download to download the openflow_switch.bit file that is located in -the /datapath/hwtable_nf2 folder: - - % nf2_download -r /datapath/hwtable_nf2/openflow_switch.bit - -'-r' option enables PHY interrupt for its link status changing, and OpenFlow -switch can detect it. - -Install the OpenFlow kernel module: - - % insmod /datapath/linux-2.6/openflow_mod.ko - -Install the NetFPGA Hardware Table kernel module: - - % insmod /datapath/linux-2.6/openflow_netfpga2_mod.ko - -Create an OpenFlow datapath: - - % /utilities/dpctl adddp nl:0 - -Add the NetFPGA interfaces to the datapath: - - % /utilities/dpctl addif nl:0 nf2c0 - % /utilities/dpctl addif nl:0 nf2c1 - % /utilities/dpctl addif nl:0 nf2c2 - % /utilities/dpctl addif nl:0 nf2c3 - -At this point your OpenFlow switch should be ready to go. - -While you are running OpenFlow switch, you can check the hardware information -including its bitfile version as follows: - - % cat /proc/net/openflow-netfpga - -Known Bugs ----------------------------------------- -* There is currently no support for priority amongst wildcard-match entries. - -Contact -------- -e-mail: openflow-discuss@lists.stanford.edu -www: http://openflowswitch.org/ - diff --git a/openflow/datapath/hwtable_nf2/nf2.h b/openflow/datapath/hwtable_nf2/nf2.h deleted file mode 100644 index 847d2b10..00000000 --- a/openflow/datapath/hwtable_nf2/nf2.h +++ /dev/null @@ -1,424 +0,0 @@ -/* **************************************************************************** - * $Id: nf2.h 3546 2008-04-03 00:12:27Z grg $ - * - * Module: nf2.h - * Project: NetFPGA 2 Linux Kernel Driver - * Description: Header file for kernel driver - * - * Change history: - * - */ - -#ifndef _NF2_H -#define _NF2_H 1 - -#define NF2_DEV_NAME "nf2" - -#include - -/* Maximum number of interfaces */ -#ifndef MAX_IFACE -#define MAX_IFACE 4 -#endif - -/* - * Register names and locations. - * - * Note that these names are not necessarily identical to - * those in NF2/hw/common/src/defines - */ - -/* CPCI registers */ -#define CPCI_REG_ID 0x000 -#define CPCI_REG_BOARD_ID 0x004 -#define CPCI_REG_CTRL 0x008 -#define CPCI_REG_RESET 0x00c -#define CPCI_REG_ERROR 0x010 -#define CPCI_REG_DUMMY 0x020 -#define CPCI_REG_INTERRUPT_MASK 0x040 -#define CPCI_REG_INTERRUPT_STATUS 0x044 -#define CPCI_REG_PROG_DATA 0x100 -#define CPCI_REG_PROG_STATUS 0x104 -#define CPCI_REG_PROG_CTRL 0x108 -#define CPCI_REG_DMA_I_ADDR 0x140 -#define CPCI_REG_DMA_E_ADDR 0x144 -#define CPCI_REG_DMA_I_SIZE 0x148 -#define CPCI_REG_DMA_E_SIZE 0x14c -#define CPCI_REG_DMA_I_CTRL 0x150 -#define CPCI_REG_DMA_E_CTRL 0x154 -#define CPCI_REG_DMA_MAX_XFER_TIME 0x180 -#define CPCI_REG_DMA_MAX_RETRIES 0x184 -#define CPCI_REG_CNET_MAX_XFER_TIME 0x188 -#define CPCI_REG_DMA_I_PKT_CNT 0x400 -#define CPCI_REG_DMA_E_PKT_CNT 0x404 -#define CPCI_REG_CPCI_REG_RD_CNT 0x408 -#define CPCI_REG_CPCI_REG_WR_CNT 0x40c -#define CPCI_REG_CNET_REG_RD_CNT 0x410 -#define CPCI_REG_CNET_REG_WR_CNT 0x414 - -#define CPCI_REG_N_CLK_COUNT 0x500 -#define CPCI_REG_P_MAX 0x504 -#define CPCI_REG_N_EXP 0x508 -#define CPCI_REG_P_CLK_CTR 0x510 -#define CPCI_REG_RESET_CTR 0x520 - -/* Base address for CNET registers */ -#define CNET_REG_BASE 0x400000 - -/* Added by nweaver for building memory manipulation - utilities */ -/* 2 MB SRAM size on current board, MAX and SIZE will - need to be changed if upgraded to 4 MB SRAMs */ -#define SRAM_SIZE 0x200000 - -#define SRAM_1_BASE 0x800000 -#define SRAM_1_MAX 0x9FFFFF - -#define SRAM_2_BASE 0xC00000 -#define SRAM_2_MAX 0xDFFFFF -/* end nweaver addition */ - -/* Device ID registers */ -#define NF2_DEVICE_ID 0x0400000 -#define NF2_REVISION 0x0400004 -#define NF2_DEVICE_STR 0x0400008 - -/* CNET registers */ -#define CNET_REG_ID (CNET_REG_BASE + 0x000) -#define CNET_REG_CTRL (CNET_REG_BASE + 0x004) -#define CNET_REG_RESET (CNET_REG_BASE + 0x008) -#define CNET_REG_ERROR (CNET_REG_BASE + 0x00C) -#define CNET_REG_ENABLE (CNET_REG_BASE + 0x010) -#define CNET_REG_WR_SRAM1_EOP (CNET_REG_BASE + 0x0F0) -#define CNET_REG_RD_SRAM1_EOP (CNET_REG_BASE + 0x0F4) -#define CNET_REG_WR_SRAM2_EOP (CNET_REG_BASE + 0x0F8) -#define CNET_REG_RD_SRAM2_EOP (CNET_REG_BASE + 0x0FC) -#define CNET_REG_MF_STATUS_0 (CNET_REG_BASE + 0x100) -#define CNET_REG_MF_TX_PKTS_SENT_0 (CNET_REG_BASE + 0x104) -#define CNET_REG_MF_RX_PKTS_RCVD_0 (CNET_REG_BASE + 0x108) -#define CNET_REG_MF_RX_PKTS_LOST_0 (CNET_REG_BASE + 0x10C) -#define CNET_REG_MAC_CONFIG_0 (CNET_REG_BASE + 0x110) -#define CNET_REG_MF_STATUS_1 (CNET_REG_BASE + 0x140) -#define CNET_REG_MF_TX_PKTS_SENT_1 (CNET_REG_BASE + 0x144) -#define CNET_REG_MF_RX_PKTS_RCVD_1 (CNET_REG_BASE + 0x148) -#define CNET_REG_MF_RX_PKTS_LOST_1 (CNET_REG_BASE + 0x14C) -#define CNET_REG_MAC_CONFIG_1 (CNET_REG_BASE + 0x150) -#define CNET_REG_MF_STATUS_2 (CNET_REG_BASE + 0x180) -#define CNET_REG_MF_TX_PKTS_SENT_2 (CNET_REG_BASE + 0x184) -#define CNET_REG_MF_RX_PKTS_RCVD_2 (CNET_REG_BASE + 0x188) -#define CNET_REG_MF_RX_PKTS_LOST_2 (CNET_REG_BASE + 0x18C) -#define CNET_REG_MAC_CONFIG_2 (CNET_REG_BASE + 0x190) -#define CNET_REG_MF_STATUS_3 (CNET_REG_BASE + 0x1C0) -#define CNET_REG_MF_TX_PKTS_SENT_3 (CNET_REG_BASE + 0x1C4) -#define CNET_REG_MF_RX_PKTS_RCVD_3 (CNET_REG_BASE + 0x1C8) -#define CNET_REG_MF_RX_PKTS_LOST_3 (CNET_REG_BASE + 0x1CC) -#define CNET_REG_MAC_CONFIG_3 (CNET_REG_BASE + 0x1D0) -#define CNET_REG_RXQ_NUM_PKTS_0 (CNET_REG_BASE + 0x200) -#define CNET_REG_RXQ_POINTERS_0 (CNET_REG_BASE + 0x204) -#define CNET_REG_RXQ_NUM_PKTS_1 (CNET_REG_BASE + 0x240) -#define CNET_REG_RXQ_POINTERS_1 (CNET_REG_BASE + 0x244) -#define CNET_REG_RXQ_NUM_PKTS_2 (CNET_REG_BASE + 0x280) -#define CNET_REG_RXQ_POINTERS_2 (CNET_REG_BASE + 0x284) -#define CNET_REG_RXQ_NUM_PKTS_3 (CNET_REG_BASE + 0x2C0) -#define CNET_REG_RXQ_POINTERS_3 (CNET_REG_BASE + 0x2C4) - -#define CNET_REG_MF_RX_PKTS_LOST_BAD_FCS_0 (CNET_REG_BASE + 0x114) -#define CNET_REG_MF_RX_PKTS_LOST_FULL_FIFO_0 (CNET_REG_BASE+0x118) -#define CNET_REG_MF_RX_GOOD_PKTS_RCVD_0 (CNET_REG_BASE+0x11C) -#define CNET_REG_MF_RX_GOOD_BYTES_RCVD_0 (CNET_REG_BASE+0x120) -#define CNET_REG_MF_TX_BYTES_SENT_0 (CNET_REG_BASE+0x124) -#define CNET_REG_MF_RX_PKTS_LOST_BAD_FCS_1 (CNET_REG_BASE+0x154) -#define CNET_REG_MF_RX_PKTS_LOST_FULL_FIFO_1 (CNET_REG_BASE+0x158) -#define CNET_REG_MF_RX_GOOD_PKTS_RCVD_1 (CNET_REG_BASE+0x15C) -#define CNET_REG_MF_RX_GOOD_BYTES_RCVD_1 (CNET_REG_BASE+0x160) -#define CNET_REG_MF_TX_BYTES_SENT_1 (CNET_REG_BASE+0x164) -#define CNET_REG_MF_RX_PKTS_LOST_BAD_FCS_2 (CNET_REG_BASE+0x194) -#define CNET_REG_MF_RX_PKTS_LOST_FULL_FIFO_2 (CNET_REG_BASE+0x198) -#define CNET_REG_MF_RX_GOOD_PKTS_RCVD_2 (CNET_REG_BASE+0x19C) -#define CNET_REG_MF_RX_GOOD_BYTES_RCVD_2 (CNET_REG_BASE+0x1A0) -#define CNET_REG_MF_TX_BYTES_SENT_2 (CNET_REG_BASE+0x1A4) -#define CNET_REG_MF_RX_PKTS_LOST_BAD_FCS_3 (CNET_REG_BASE+0x1D4) -#define CNET_REG_MF_RX_PKTS_LOST_FULL_FIFO_3 (CNET_REG_BASE+0x1D8) -#define CNET_REG_MF_RX_GOOD_PKTS_RCVD_3 (CNET_REG_BASE+0x1DC) -#define CNET_REG_MF_RX_GOOD_BYTES_RCVD_3 (CNET_REG_BASE+0x1E0) -#define CNET_REG_MF_TX_BYTES_SENT_3 (CNET_REG_BASE+0x1E4) - -#define CNET_MAC_CLK_CHK_CTRL (CNET_REG_BASE + 0xF00) -#define CNET_MAC_CLK_CHK_CNT_VALUE (CNET_REG_BASE + 0xF04) - -/* Base address for CNET PHY registers */ -#define PHY_REG_BASE 0x600000 - -#define PHY_REG_CMD (PHY_REG_BASE) -#define PHY_REG_STATUS (PHY_REG_BASE) - -/* - * CPCI register masks - */ - -/* ID Masks */ -#define ID_VERSION 0x00FFFFFF -#define ID_REVISION 0xFF000000 - -/* Board ID Masks */ -#define BOARD_ID 0x00000F00 -#define BOARD_ID_CONTROL 0x00000001 - -/* Control masks */ -#define CTRL_CNET_RESET 0x00000100 -#define CTRL_LED 0x00000001 - -/* RESET masks */ -#define RESET_CPCI 0x00000001 - -/* Error masks */ -#define ERR_CNET_READ_TIMEOUT 0x02000000 -#define ERR_CNET_ERROR 0x01000000 -#define ERR_PROG_BUF_OVERFLOW 0x00020000 -#define ERR_PROG_ERROR 0x00010000 -#define ERR_DMA_TIMEOUT 0x00000400 -#define ERR_DMA_RETRY_CNT_EXPIRED 0x00000200 -#define ERR_DMA_BUF_OVERFLOW 0x00000100 -#define ERR_DMA_RD_SIZE_ERROR 0x00000040 -#define ERR_DMA_WR_SIZE_ERROR 0x00000020 -#define ERR_DMA_RD_ADDR_ERROR 0x00000010 -#define ERR_DMA_WR_ADDR_ERROR 0x00000008 -#define ERR_DMA_RD_MAC_ERROR 0x00000004 -#define ERR_DMA_WR_MAC_ERROR 0x00000002 -#define ERR_DMA_FATAL_ERROR 0x00000001 - -#define ERR_DMA_SETUP_ERROR ( ERR_DMA_WR_MAC_ERROR | \ - ERR_DMA_RD_MAC_ERROR | \ - ERR_DMA_WR_ADDR_ERROR | \ - ERR_DMA_RD_ADDR_ERROR | \ - ERR_DMA_WR_SIZE_ERROR | \ - ERR_DMA_RD_SIZE_ERROR ) - -/* Interrupt masks */ -#define INT_DMA_RX_COMPLETE 0x80000000 -#define INT_DMA_TX_COMPLETE 0x40000000 -#define INT_PHY_INTERRUPT 0x20000000 -#define INT_PKT_AVAIL 0x00000100 -#define INT_CNET_ERROR 0x00000020 -#define INT_CNET_READ_TIMEOUT 0x00000010 -#define INT_PROG_ERROR 0x00000008 -#define INT_DMA_TRANSFER_ERROR 0x00000004 -#define INT_DMA_SETUP_ERROR 0x00000002 -#define INT_DMA_FATAL_ERROR 0x00000001 - -#define INT_UNKNOWN ~(INT_DMA_RX_COMPLETE | \ - INT_DMA_TX_COMPLETE | \ - INT_PHY_INTERRUPT | \ - INT_PKT_AVAIL | \ - INT_CNET_ERROR | \ - INT_CNET_READ_TIMEOUT | \ - INT_PROG_ERROR | \ - INT_DMA_TRANSFER_ERROR | \ - INT_DMA_SETUP_ERROR | \ - INT_DMA_FATAL_ERROR) - -/* Programming status */ -#define PROG_INIT 0x00010000 -#define PROG_DONE 0x00000100 -#define PROG_FIFO_EMPTY 0x00000002 -#define PROG_IN_PROGRESS 0x00000001 - -/* Programming control */ -#define PROG_CTRL_RESET 0x00000001 - -/* DMA control */ -#define DMA_CTRL_MAC 0x00000300 -#define DMA_CTRL_OWNER 0x00000001 - -/* - * CNET register masks - */ - -/* Reset masks */ -#define CNET_RESET_MAC 0x0000000F -#define CNET_RESET_MAC_3 0x00000008 -#define CNET_RESET_MAC_2 0x00000004 -#define CNET_RESET_MAC_1 0x00000002 -#define CNET_RESET_MAC_0 0x00000001 - -/* Error masks */ -#define CNET_ERROR_TX_UNDERRUN_MAC 0x000000F0 -#define CNET_ERROR_TX_UNDERRUN_MAC_3 0x00000080 -#define CNET_ERROR_TX_UNDERRUN_MAC_2 0x00000040 -#define CNET_ERROR_TX_UNDERRUN_MAC_1 0x00000020 -#define CNET_ERROR_TX_UNDERRUN_MAC_0 0x00000010 -#define CNET_ERROR_TX_OVERRUN_MAC 0x0000000F -#define CNET_ERROR_TX_OVERRUN_MAC_3 0x00000008 -#define CNET_ERROR_TX_OVERRUN_MAC_2 0x00000004 -#define CNET_ERROR_TX_OVERRUN_MAC_1 0x00000002 -#define CNET_ERROR_TX_OVERRUN_MAC_0 0x00000001 - -/* Enable masks */ -#define CNET_ENABLE_RX_FIFO 0x0000F000 -#define CNET_ENABLE_RX_FIFO_3 0x00008000 -#define CNET_ENABLE_RX_FIFO_2 0x00004000 -#define CNET_ENABLE_RX_FIFO_1 0x00002000 -#define CNET_ENABLE_RX_FIFO_0 0x00001000 -#define CNET_ENABLE_TX_MAC 0x00000F00 -#define CNET_ENABLE_TX_MAC_3 0x00000800 -#define CNET_ENABLE_TX_MAC_2 0x00000400 -#define CNET_ENABLE_TX_MAC_1 0x00000200 -#define CNET_ENABLE_TX_MAC_0 0x00000100 -#define CNET_ENABLE_DEBUG_TRISTATE 0x00000004 -#define CNET_ENABLE_INGRESS_ARBITER 0x00000002 -#define CNET_ENABLE_RX_DMA 0x00000001 - -/* MF Status masks */ -#define CNET_MF_STATUS_RX_FIFO_EMPTY 0x02000000 -#define CNET_MF_STATUS_RX_PKT_AVAIL 0x01000000 -#define CNET_MF_STATUS_RX_NUM_PKTS 0x00FF0000 -#define CNET_MF_STATUS_TX_FIFO_FULL 0x00000200 -#define CNET_MF_STATUS_TX_FIFO_NO_MAX_PKT 0x00000100 -#define CNET_MF_STATUS_TX_NUM_PKTS 0x000000FF - -/* MAC Config masks */ -#define CNET_MAC_CFG_FULL_DUPLEX 0x00000020 -#define CNET_MAC_CFG_TX_FCS_SUPPLIED 0x00000010 -#define CNET_MAC_CFG_RX_WANT_FCS 0x00000008 -#define CNET_MAC_CFG_JUMBO_ENABLE 0x00000004 - -#define CNET_MAC_CFG_SPEED 0x00000002 -#define CNET_MAC_CFG_1000_MBPS 0x00000002 -#define CNET_MAC_CFG_100_MBPS 0x00000001 -#define CNET_MAC_CFG_10_MBPS 0x00000000 - -#define CNET_RXQ_WR_PTR 0x00FF0000 -#define CNET_RXQ_RD_PTR 0x000000FF - -/* Phy register masks */ -#define PHY_RD_WR 0x80000000 -#define PHY_PHY 0x03000000 -#define PHY_ADDR 0x001F0000 -#define PHY_DATA 0x0000FFFF - -#define PHY_DONE 0x80000000 -#define PHY_DONE_CNT 0x001F0000 - -/* Defines to calculate register values */ -/* CPCI Funcs */ -#define NF2_GET_VERSION(x) (x & 0xFFFFFF) -#define NF2_GET_REVISION(x) ((x & 0xFF000000) >> 24) - -#define NF2_GET_BOARD_ID(x) ((x & BOARD_ID) >> 8) -#define NF2_GET_CONTROL(x) (x & BOARD_ID_CONTROL) - -#define NF2_GET_CNET_RESET(x) ((x & CTRL_CNET_RESET) >> 8) -#define NF2_GET_LED(x) (x & CTRL_LED) - -#define NF2_GET_RESET(x) (x & RESET_CPCI) - -#define NF2_GET_CNET_READ_TIMEOUT(x) ((x & ERR_CNET_READ_TIMEOUT) >> 25) -#define NF2_GET_CNET_ERROR(x) ((x & ERR_CNET_ERROR) >> 24) -#define NF2_GET_PROG_BUF_OVERFLOW(x) ((x & ERR_PROG_BUF_OVERFLOW) >> 12) -#define NF2_GET_PROG_ERROR(x) ((x & ERR_PROG_ERROR) >> 11) -#define NF2_GET_DMA_TIMEOUT(x) ((x & ERR_DMA_TIMEOUT) >> 10) -#define NF2_GET_DMA_RETRY_CNT_EXPIRED(x) \ - ((x & ERR_DMA_RETRY_CNT_EXPIRED) >> 9) -#define NF2_GET_DMA_BUF_OVERFLOW(x) ((x & ERR_DMA_BUF_OVERFLOW) >> 8) -#define NF2_GET_DMA_RD_SIZE_ERROR(x) ((x & ERR_DMA_RD_SIZE_ERROR) >> 6) -#define NF2_GET_DMA_WR_SIZE_ERROR(x) ((x & ERR_DMA_WR_SIZE_ERROR) >> 5) -#define NF2_GET_DMA_RD_ADDR_ERROR(x) ((x & ERR_DMA_RD_ADDR_ERROR) >> 4) -#define NF2_GET_DMA_WR_ADDR_ERROR(x) ((x & ERR_DMA_WR_ADDR_ERROR) >> 3) -#define NF2_GET_DMA_RD_MAC_ERROR(x) ((x & ERR_DMA_RD_MAC_ERROR) >> 2) -#define NF2_GET_DMA_WR_MAC_ERROR(x) ((x & ERR_DMA_WR_MAC_ERROR) >> 1) -#define NF2_GET_DMA_FATAL_ERROR(x) (x & ERR_DMA_FATAL_ERROR) - -#define NF2_GET_INT_DMA_TX_COMPLETE(x) ((x & INT_DMA_TX_COMPLETE) >> 31) -#define NF2_GET_INT_DMA_RX_COMPLETE(x) ((x & INT_DMA_RX_COMPLETE) >> 30) -#define NF2_GET_INT_PHY_INTERRUPT(x) ((x & INT_PHY_INTERRUPT) >> 29) -#define NF2_GET_INT_PKT_AVAIL(x) ((x & INT_PKT_AVAIL) >> 8) -#define NF2_GET_INT_CNET_ERROR(x) ((x & INT_CNET_ERROR) >> 5) -#define NF2_GET_INT_CNET_READ_TIMEOUT(x) \ - ((x & INT_CNET_READ_TIMEOUT) >> 4) -#define NF2_GET_INT_PROG_ERROR(x) ((x & INT_PROG_ERROR) >> 3) -#define NF2_GET_INT_DMA_TRANSFER_ERROR(x) \ - ((x & INT_DMA_TRANSFER_ERROR) >> 2) -#define NF2_GET_INT_DMA_SETUP_ERROR(x) ((x & INT_DMA_SETUP_ERROR) >> 1) -#define NF2_GET_INT_DMA_FATAL_ERROR(x) (x & INT_DMA_FATAL_ERROR) - -#define NF2_GET_PROG_INIT(x) ((x & PROG_INIT) >> 16) -#define NF2_GET_PROG_DONE(x) ((x & PROG_DONE) >> 8) -#define NF2_GET_PROG_FIFO_EMPTY(x) ((x & PROG_FIFO_EMPTY) >> 1) -#define NF2_GET_PROG_IN_PROGRESS(x) (x & PROG_IN_PROGRESS) - -#define NF2_GET_DMA_CTRL_MAC(x) ((x & DMA_CTRL_MAC) >> 8) -#define NF2_GET_DMA_CTRL_OWNER(x) (x & DMA_CTRL_OWNER) - -#define NF2_SET_DMA_CTRL_MAC(x) (x << 8) - -/* CNET Funcs */ -#define NF2_GET_CNET_VERSION(x) ((x & 0xFFFF0000) >> 16) -#define NF2_GET_CNET_DEVICE_ID(x) (x & 0xFFFF) - -#define NF2_GET_CNET_RESET_MAC(x) (x & CNET_RESET_MAC) - -#define NF2_GET_CNET_ERROR_TX_UNDERRUN_MAC(x) \ - ((x & CNET_ERROR_TX_UNDERRUN_MAC) >> 4) -#define NF2_GET_CNET_ERROR_TX_OVERRUN_MAC(x) \ - (x & CNET_ERROR_TX_OVERRUN_MAC) - -#define NF2_GET_CNET_ENABLE_RX_FIFO(x) ((x & CNET_ENABLE_RX_FIFO) >> 12) -#define NF2_GET_CNET_ENABLE_TX_MAC(x) ((x & CNET_ENABLE_TX_MAC) >> 8) -#define NF2_GET_CNET_ENABLE_DEBUG_TRISTATE(x) \ - ((x & CNET_ENABLE_DEBUG_TRISTATE) >> 2) -#define NF2_GET_CNET_ENABLE_INGRESS_ARBITER(x) \ - ((x & CNET_ENABLE_INGRESS_ARBITER) >> 1) -#define NF2_GET_CNET_ENABLE_RX_DMA(x) (x & CNET_ENABLE_RX_DMA) - -#define NF2_GET_CNET_MF_STATUS_RX_FIFO_EMPTY(x) \ - ((x & CNET_MF_STATUS_RX_FIFO_EMPTY) >> 25) -#define NF2_GET_CNET_MF_STATUS_RX_PKT_AVAIL(x) \ - ((x & CNET_MF_STATUS_RX_PKT_AVAIL) >> 24) -#define NF2_GET_CNET_MF_STATUS_RX_NUM_PKTS(x) \ - ((x & CNET_MF_STATUS_RX_NUM_PKTS) >> 16) -#define NF2_GET_CNET_MF_STATUS_TX_FIFO_FULL(x) \ - ((x & CNET_MF_STATUS_TX_FIFO_FULL) >> 9) -#define NF2_GET_CNET_MF_STATUS_TX_FIFO_NO_MAX_PKT(x) \ - ((x & CNET_MF_STATUS_TX_FIFO_NO_MAX_PKT) >> 8) -#define NF2_GET_CNET_MF_STATUS_TX_NUM_PKTS(x) \ - (x & CNET_MF_STATUS_TX_NUM_PKTS) - -#define NF2_GET_CNET_MAC_CFG_FULL_DUPLEX(x) \ - ((x & CNET_MAC_CFG_FULL_DUPLEX) >> 5) -#define NF2_GET_CNET_MAC_CFG_TX_FCS_SUPPLIED(x) \ - ((x & CNET_MAC_CFG_TX_FCS_SUPPLIED) >> 4) -#define NF2_GET_CNET_MAC_CFG_RX_WANT_FCS(x) \ - ((x & CNET_MAC_CFG_RX_WANT_FCS) >> 3) -#define NF2_GET_CNET_MAC_CFG_JUMBO_ENABLE(x) \ - ((x & CNET_MAC_CFG_JUMBO_ENABLE) >> 2) -#define NF2_GET_CNET_MAC_CFG_SPEED(x) \ - (x & CNET_MAC_CFG_SPEED) - -#define NF2_GET_CNET_RXQ_WR_PTR(x) ((x & CNET_RXQ_WR_PTR) >> 16) -#define NF2_GET_CNET_RXQ_RD_PTR(x) (x & CNET_RXQ_RD_PTR) - -/* PHY functions */ -#define NF2_SET_PHY_IS_READ(x) (x << 31) -#define NF2_SET_PHY_SELECT(x) (x << 24) -#define NF2_SET_PHY_ADDR(x) (x << 16) -#define NF2_SET_PHY_DATA(x) (x) - -#define NF2_GET_PHY_DATA(x) (x & PHY_DATA) -#define NF2_GET_PHY_DONE(x) ((x & PHY_DONE) >> 31) -#define NF2_GET_PHY_DONE_CNT(x) ((x & PHY_DONE_CNT) >> 16) - -/* - * IOCTLs - */ -#define SIOCREGREAD SIOCDEVPRIVATE -#define SIOCREGWRITE (SIOCDEVPRIVATE + 1) - -/* - * Structure for transferring register data via an IOCTL - */ -struct nf2reg { - unsigned int reg; - unsigned int val; -}; - -#endif diff --git a/openflow/datapath/hwtable_nf2/nf2_flowtable.c b/openflow/datapath/hwtable_nf2/nf2_flowtable.c deleted file mode 100644 index 75eb3223..00000000 --- a/openflow/datapath/hwtable_nf2/nf2_flowtable.c +++ /dev/null @@ -1,452 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "chain.h" -#include "table.h" -#include "flow.h" -#include "datapath.h" - -#include "hwtable_nf2/nf2_reg.h" -#include "hwtable_nf2/nf2_flowtable.h" -#include "hwtable_nf2/nf2_openflow.h" -#include "hwtable_nf2/nf2_lib.h" -#include "hwtable_nf2/nf2_procfs.h" - -struct nf2_flowtable { - struct sw_table flowtab; - spinlock_t lock; - unsigned int max_flows; - atomic_t num_flows; - struct list_head flows; - struct list_head iter_flows; - unsigned long int next_serial; -}; - -static struct sw_flow *nf2_lookup_flowtable(struct sw_table *, - const struct sw_flow_key *); -static int nf2_install_flow(struct sw_table *, struct sw_flow *); -static int nf2_modify_flow(struct sw_table *, const struct sw_flow_key *, - uint16_t, int, const struct ofp_action_header *, - size_t); -static void deferred_uninstall_callback(struct rcu_head *); -static void do_deferred_uninstall(struct sw_flow *); -static int do_uninstall(struct datapath *, struct sw_table *, struct sw_flow *, - enum ofp_flow_removed_reason); -static int nf2_has_conflict(struct sw_table *, const struct sw_flow_key *, - uint16_t, int); -static int nf2_uninstall_flow(struct datapath *, struct sw_table *, - const struct sw_flow_key *, uint16_t, - uint16_t, int); -static int nf2_flow_timeout(struct datapath *, struct sw_table *); -static void nf2_destroy_flowtable(struct sw_table *); -static int nf2_iterate_flowtable(struct sw_table *, - const struct sw_flow_key *, - uint16_t, struct sw_table_position *, - int (*)(struct sw_flow *, void *), void *); -unsigned long int get_lookup_matched_stats(void); -unsigned long int get_lookup_stats(void); -static void nf2_get_flowstats(struct sw_table *, struct sw_table_stats *); -static struct sw_table *nf2_create_flowtable(void); -static int __init nf2_startup(void); -static void nf2_cleanup(void); - -static struct sw_flow * -nf2_lookup_flowtable(struct sw_table *flowtab, const struct sw_flow_key *key) -{ - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - struct sw_flow *flow; - - list_for_each_entry(flow, &nf2flowtab->flows, node) { - if (flow_matches_1wild(key, &flow->key)) { - return flow; - } - } - - return NULL; -} - -static int -nf2_install_flow(struct sw_table *flowtab, struct sw_flow *flow) -{ - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - - /* Delete flows that match exactly. */ - nf2_uninstall_flow(NULL, flowtab, &flow->key, OFPP_NONE, - flow->priority, true); - - if (nf2_are_actions_supported(flow)) { - if (nf2_build_and_write_flow(flow)) { - return 0; - } - } else { - /* Unsupported actions or no netdevice. */ - return 0; - } - - atomic_inc(&nf2flowtab->num_flows); - list_add_rcu(&flow->node, &nf2flowtab->flows); - list_add_rcu(&flow->iter_node, &nf2flowtab->iter_flows); - return 1; -} - -static int -nf2_modify_flow(struct sw_table *flowtab, const struct sw_flow_key *key, - uint16_t priority, int strict, - const struct ofp_action_header *actions, size_t actions_len) -{ - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - struct sw_flow *flow; - unsigned int count = 0; - - list_for_each_entry(flow, &nf2flowtab->flows, node) { - if (flow_matches_desc(&flow->key, key, strict) - && (!strict || flow->priority == priority)) { - flow_replace_acts(flow, actions, actions_len); - if (nf2_are_actions_supported(flow)) { - count += nf2_modify_acts(flowtab, flow); - } - } else { - return 0; - } - } - - return count; -} - -static int -nf2_has_conflict(struct sw_table *flowtab, const struct sw_flow_key *key, - uint16_t priority, int strict) -{ - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - struct sw_flow *flow; - - list_for_each_entry(flow, &nf2flowtab->flows, node) { - if (flow_matches_desc(&flow->key, key, strict) - && (flow->priority == priority)) { - return true; - } - } - return false; -} - -static void -deferred_uninstall_callback(struct rcu_head *rcu) -{ - struct sw_flow *flow = container_of(rcu, struct sw_flow, rcu); - - flow_free(flow); -} - -static void -do_deferred_uninstall(struct sw_flow *flow) -{ - call_rcu(&flow->rcu, deferred_uninstall_callback); -} - -static int -do_uninstall(struct datapath *dpinst, struct sw_table *flowtab, - struct sw_flow *flow, enum ofp_flow_removed_reason reason) -{ - if (flow != NULL && flow->private != NULL) { - if (dpinst != NULL) - dp_send_flow_end(dpinst, flow, reason); - list_del_rcu(&flow->node); - list_del_rcu(&flow->iter_node); - nf2_delete_private(flow->private); - do_deferred_uninstall(flow); - return 1; - } - - return 0; -} - -static int -nf2_uninstall_flow(struct datapath *dpinst, struct sw_table *flowtab, - const struct sw_flow_key *key, uint16_t out_port, - uint16_t priority, int strict) -{ - struct net_device *netdev; - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - struct sw_flow *flow; - struct nf2_flow *nf2flow; - unsigned int count = 0; - - netdev = nf2_get_net_device(); - if (netdev == NULL) - return 0; - - list_for_each_entry(flow, &nf2flowtab->flows, node) { - if (flow_matches_desc(&flow->key, key, strict) - && (!strict || flow->priority == priority) - && flow_has_out_port(flow, out_port)) { - nf2flow = flow->private; - if (nf2flow != NULL) { - flow->packet_count - += nf2_get_packet_count(netdev, - nf2flow); - flow->byte_count += nf2_get_byte_count(netdev, - nf2flow); - } - count += do_uninstall(dpinst, flowtab, - flow, OFPRR_DELETE); - } - } - if (count != 0) - atomic_sub(count, &nf2flowtab->num_flows); - - nf2_free_net_device(netdev); - - return count; -} - -static int -nf2_flow_timeout(struct datapath *dpinst, struct sw_table *flowtab) -{ - struct net_device *netdev; - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - struct sw_flow *flow; - struct nf2_flow *nf2flow; - int num_uninst_flows = 0; - uint64_t num_forw_packets = 0; - int reason; - - netdev = nf2_get_net_device(); - if (netdev == NULL) - return num_uninst_flows; - - mutex_lock(&dp_mutex); - list_for_each_entry(flow, &nf2flowtab->flows, node) { - nf2flow = flow->private; - if (nf2flow != NULL) { - num_forw_packets = flow->packet_count - + nf2_get_packet_count(netdev, nf2flow); - flow->byte_count += nf2_get_byte_count(netdev, nf2flow); - } - if (num_forw_packets > flow->packet_count - && flow->idle_timeout != OFP_FLOW_PERMANENT) { - flow->packet_count = num_forw_packets; - flow->used = get_jiffies_64(); - } - reason = flow_timeout(flow); - if (reason >= 0) { - num_uninst_flows += do_uninstall(dpinst, flowtab, - flow, reason); - } - } - mutex_unlock(&dp_mutex); - - nf2_clear_watchdog(netdev); - - nf2_free_net_device(netdev); - - if (num_uninst_flows != 0) - atomic_sub(num_uninst_flows, &nf2flowtab->num_flows); - return num_uninst_flows; -} - -static void -nf2_destroy_flowtable(struct sw_table *flowtab) -{ - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - struct nf2_flow *nf2flow = NULL; - - if (nf2flowtab == NULL) - return; - - while (!list_empty(&nf2flowtab->flows)) { - struct sw_flow *flow = list_entry(nf2flowtab->flows.next, - struct sw_flow, node); - - list_del(&flow->node); - if (flow->private) { - nf2flow = (struct nf2_flow *)flow->private; - - if (nf2flow->type == NF2_TABLE_EXACT) { - nf2_add_free_exact(nf2flow); - } else if (nf2flow->type == NF2_TABLE_WILDCARD) { - nf2_add_free_wildcard(nf2flow); - } - flow->private = NULL; - } - flow_free(flow); - } - kfree(nf2flowtab); - - nf2_destroy_exact_freelist(); - nf2_destroy_wildcard_freelist(); -} - -static int -nf2_iterate_flowtable(struct sw_table *flowtab, const struct sw_flow_key *key, - uint16_t out_port, struct sw_table_position *position, - int (*callback) (struct sw_flow *, void *), void *private) -{ - unsigned long start; - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - struct sw_flow *flow; - int error = 0; - - start = ~position->private[0]; - list_for_each_entry(flow, &nf2flowtab->iter_flows, iter_node) { - if (flow->serial <= start && flow_matches_2wild(key, &flow->key) - && flow_has_out_port(flow, out_port)) { - error = callback(flow, private); - if (error != 0) { - position->private[0] = ~flow->serial; - return error; - } - } - } - - return error; -} - -unsigned long int -get_lookup_stats(void) -{ - struct net_device *netdev; - unsigned long int num_searched = 0; - - netdev = nf2_get_net_device(); - if (netdev == NULL) - return num_searched; - - num_searched = nf2_get_missed_count(netdev); - nf2_free_net_device(netdev); - num_searched += get_lookup_matched_stats(); - return num_searched; -} - -unsigned long int -get_lookup_matched_stats(void) -{ - struct net_device *netdev; - unsigned long int num_matched = 0; - - netdev = nf2_get_net_device(); - if (netdev == NULL) - return num_matched; - - num_matched = nf2_get_matched_count(netdev); - nf2_free_net_device(netdev); - return num_matched; -} - -static void -nf2_get_flowstats(struct sw_table *flowtab, struct sw_table_stats *stats) -{ - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - - stats->name = "nf2"; - stats->wildcards = OPENFLOW_WILDCARD_TABLE_SIZE - 8; - stats->n_flows = atomic_read(&nf2flowtab->num_flows); - stats->max_flows = nf2flowtab->max_flows; - stats->n_lookup = get_lookup_stats(); - stats->n_matched = get_lookup_matched_stats(); -} - -static struct sw_table * -nf2_create_flowtable(void) -{ - struct net_device *netdev; - struct nf2_flowtable *nf2flowtab; - struct sw_table *flowtab; - - netdev = nf2_get_net_device(); - if (netdev == NULL) - return NULL; - - nf2_reset_card(netdev); - nf2_free_net_device(netdev); - - nf2flowtab = kzalloc(sizeof(*nf2flowtab), GFP_KERNEL); - if (nf2flowtab == NULL) { - nf2_free_net_device(netdev); - return NULL; - } - - flowtab = &nf2flowtab->flowtab; - flowtab->n_lookup = (unsigned long long)get_lookup_stats(); - flowtab->n_matched = (unsigned long long)get_lookup_matched_stats(); - flowtab->lookup = nf2_lookup_flowtable; - flowtab->insert = nf2_install_flow; - flowtab->modify = nf2_modify_flow; - flowtab->has_conflict = nf2_has_conflict; - flowtab->delete = nf2_uninstall_flow; - flowtab->timeout = nf2_flow_timeout; - flowtab->destroy = nf2_destroy_flowtable; - flowtab->iterate = nf2_iterate_flowtable; - flowtab->stats = nf2_get_flowstats; -#define RESERVED_FOR_CPU2NETFPGA 8 - nf2flowtab->max_flows = OPENFLOW_NF2_EXACT_TABLE_SIZE - + OPENFLOW_WILDCARD_TABLE_SIZE - RESERVED_FOR_CPU2NETFPGA; - atomic_set(&nf2flowtab->num_flows, 0); - INIT_LIST_HEAD(&nf2flowtab->flows); - INIT_LIST_HEAD(&nf2flowtab->iter_flows); - nf2flowtab->next_serial = 0; - - nf2_init_wildcard_freelist(); - nf2_write_static_wildcard(); - nf2_init_exact_freelist(); - - return flowtab; -} - -static int __init -nf2_startup(void) -{ - nf2_create_procfs(); - return chain_set_hw_hook(nf2_create_flowtable, THIS_MODULE); -} - -static void -nf2_cleanup(void) -{ - nf2_remove_procfs(); - chain_clear_hw_hook(); -} - -module_init(nf2_startup); -module_exit(nf2_cleanup); - -MODULE_DESCRIPTION("NetFPGA Fastpath Extension for OpenFlow Switch"); -MODULE_AUTHOR("Copyright (c) 2008, 2009 " - "The Board of Trustees of The Leland Stanford Junior University"); -MODULE_LICENSE("GPL"); diff --git a/openflow/datapath/hwtable_nf2/nf2_flowtable.h b/openflow/datapath/hwtable_nf2/nf2_flowtable.h deleted file mode 100644 index 45aca5c7..00000000 --- a/openflow/datapath/hwtable_nf2/nf2_flowtable.h +++ /dev/null @@ -1,63 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#ifndef HWTABLE_NF2_NF2_FLOWTABLE_ -#define HWTABLE_NF2_NF2_FLOWTABLE_ - -struct nf2_flow { - struct list_head node; - uint32_t pos; - uint32_t type; - uint32_t hw_packet_count; - uint32_t hw_byte_count; -}; - -enum nf2_of_table_type { - NF2_TABLE_EXACT, - NF2_TABLE_WILDCARD -}; - -/* #define NF2_DEBUG 1 */ - -#ifdef NF2_DEBUG -#ifdef __KERNEL__ -#define NF2DEBUGMSG(f, s...) printk(f, ## s) -#else -#define NF2DEBUGMSG(f, s...) printf(f, ## s) -#endif /* __KERNEL__ */ -#else -#define NF2DEBUGMSG(f, s...) -#endif - -/* #define NF2_WATCHDOG 1 */ - -#endif diff --git a/openflow/datapath/hwtable_nf2/nf2_hwapi.h b/openflow/datapath/hwtable_nf2/nf2_hwapi.h deleted file mode 100644 index 1a3e7aa1..00000000 --- a/openflow/datapath/hwtable_nf2/nf2_hwapi.h +++ /dev/null @@ -1,43 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#ifndef HWTABLE_NF2_NF2_HWAPI_H_ -#define HWTABLE_NF2_NF2_HWAPI_H_ - -#ifdef __KERNEL__ - -int nf2k_reg_read(struct net_device *, unsigned int, void *); -int nf2k_reg_write(struct net_device *, unsigned int, void *); - -#endif /* __KERNEL__ */ - -#endif diff --git a/openflow/datapath/hwtable_nf2/nf2_lib.c b/openflow/datapath/hwtable_nf2/nf2_lib.c deleted file mode 100644 index 67acd433..00000000 --- a/openflow/datapath/hwtable_nf2/nf2_lib.c +++ /dev/null @@ -1,918 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#include - -#include "crc32.h" -#include "flow.h" -#include "table.h" -#include "compat26.h" - -#include "hwtable_nf2/nf2.h" -#include "hwtable_nf2/nf2_reg.h" -#include "hwtable_nf2/nf2_hwapi.h" -#include "hwtable_nf2/nf2_flowtable.h" -#include "hwtable_nf2/nf2_openflow.h" -#include "hwtable_nf2/nf2_lib.h" - -#define MAX_INT_32 0xFFFFFFFF -#define PORT_BASE 1 - -#define VID_BITMASK 0x0FFF -#define PCP_BITSHIFT 13 -#define PCP_BITMASK 0xE000 - -struct list_head wildcard_free_list; -struct nf2_flow *exact_free_list[OPENFLOW_NF2_EXACT_TABLE_SIZE]; - -static uint32_t make_nw_wildcard(int); -static struct nf2_flow *get_free_exact(nf2_of_entry_wrap *); -static struct nf2_flow *get_free_wildcard(void); -static int is_action_forward_all(struct sw_flow *); -static void populate_action_output(nf2_of_action_wrap *, nf2_of_entry_wrap *, - uint8_t *); -static void populate_action_set_dl_src(nf2_of_action_wrap *, uint8_t *); -static void populate_action_set_dl_dst(nf2_of_action_wrap *, uint8_t *); - -struct net_device * -nf2_get_net_device(void) -{ - return dev_get_by_name(&init_net, "nf2c0"); -} - -void -nf2_free_net_device(struct net_device *dev) -{ - if (dev == NULL) - return; - - dev_put(dev); -} - -/* Checks to see if the actions requested by the flow are capable of being - * done in the NF2 hardware. Returns 1 if yes, 0 for no. - */ -int -nf2_are_actions_supported(struct sw_flow *flow) -{ - struct sw_flow_actions *sfa; - size_t actions_len; - uint8_t *p; - - sfa = flow->sf_acts; - actions_len = sfa->actions_len; - p = (uint8_t *)sfa->actions; - - while (actions_len > 0) { - struct ofp_action_header *ah = (struct ofp_action_header *)p; - struct ofp_action_output *oa = (struct ofp_action_output *)p; - size_t len = ntohs(ah->len); - - NF2DEBUGMSG("Action Support Chk: Len of this action: %i\n", - len); - NF2DEBUGMSG("Action Support Chk: Len of actions : %i\n", - actions_len); - - // Currently, output port(s) action, dl_src/dst rewrite actions - // are suported. - if (!(ntohs(ah->type) == OFPAT_OUTPUT - || ntohs(ah->type) == OFPAT_SET_DL_SRC - || ntohs(ah->type) == OFPAT_SET_DL_DST)) { - NF2DEBUGMSG - ("Flow action type %#0x not supported in hardware\n", - ntohs(ah->type)); - return 0; - } - // Only support ports 1-4(incl. IN_PORT), ALL, FLOOD. - // Let CONTROLLER/LOCAL fall through - if ((ntohs(ah->type) == OFPAT_OUTPUT) - && (!((ntohs(oa->port) >= PORT_BASE) - && (ntohs(oa->port) <= MAX_IFACE)) - && !(ntohs(oa->port) == OFPP_ALL) - && !(ntohs(oa->port) == OFPP_FLOOD) - && !(ntohs(oa->port) == OFPP_IN_PORT))) { - NF2DEBUGMSG - ("Flow action output port %#0x is not supported in hardware\n", - ntohs(oa->port)); - return 0; - } - p += len; - actions_len -= len; - } - - return 1; -} - -/* Write all 0's out to an exact entry position. */ -void -nf2_clear_of_exact(uint32_t pos) -{ - nf2_of_entry_wrap entry; - nf2_of_action_wrap action; - struct net_device *dev = NULL; - - memset(&entry, 0, sizeof(nf2_of_entry_wrap)); - memset(&action, 0, sizeof(nf2_of_action_wrap)); - - dev = nf2_get_net_device(); - if (dev == NULL) - return; - - nf2_write_of_exact(dev, pos, &entry, &action); - nf2_free_net_device(dev); -} - -/* - * Write all 0's out to a wildcard entry position - */ -void -nf2_clear_of_wildcard(uint32_t pos) -{ - nf2_of_entry_wrap entry; - nf2_of_mask_wrap mask; - nf2_of_action_wrap action; - struct net_device *dev = NULL; - - memset(&entry, 0, sizeof(nf2_of_entry_wrap)); - memset(&mask, 0, sizeof(nf2_of_mask_wrap)); - memset(&action, 0, sizeof(nf2_of_action_wrap)); - - dev = nf2_get_net_device(); - if (dev == NULL) - return; - - nf2_write_of_wildcard(dev, pos, &entry, &mask, &action); - nf2_free_net_device(dev); -} - -int -nf2_init_exact_freelist(void) -{ - struct nf2_flow *sfw = NULL; - int i; - - for (i = 0; i < (OPENFLOW_NF2_EXACT_TABLE_SIZE); ++i) { - sfw = kzalloc(sizeof(struct nf2_flow), GFP_ATOMIC); - if (sfw == NULL) { - return 1; - } - sfw->pos = i; - sfw->type = NF2_TABLE_EXACT; - nf2_add_free_exact(sfw); - sfw = NULL; - } - - return 0; -} - -int -nf2_init_wildcard_freelist(void) -{ - struct nf2_flow *sfw = NULL; - int i; - INIT_LIST_HEAD(&wildcard_free_list); - - for (i = 0; i < (OPENFLOW_WILDCARD_TABLE_SIZE - 8); ++i) { - sfw = kzalloc(sizeof(struct nf2_flow), GFP_ATOMIC); - if (sfw == NULL) { - return 1; - } - sfw->pos = i; - sfw->type = NF2_TABLE_WILDCARD; - nf2_add_free_wildcard(sfw); - sfw = NULL; - } - - return 0; -} - -/* Called when the table is being deleted. */ -void -nf2_destroy_exact_freelist(void) -{ - struct nf2_flow *sfw = NULL; - int i; - - for (i = 0; i < (OPENFLOW_NF2_EXACT_TABLE_SIZE); ++i) { - sfw = exact_free_list[i]; - if (sfw) { - kfree(sfw); - } - sfw = NULL; - } -} - -/* Called when the table is being deleted. */ -void -nf2_destroy_wildcard_freelist(void) -{ - struct nf2_flow *sfw = NULL; - struct list_head *next = NULL; - - while (!list_empty(&wildcard_free_list)) { - next = wildcard_free_list.next; - sfw = list_entry(next, struct nf2_flow, node); - list_del(&sfw->node); - kfree(sfw); - } -} - -/* Setup the wildcard table by adding static flows that will handle - * misses by sending them up to the cpu ports, and handle packets coming - * back down from the cpu by sending them out the corresponding port. - */ -int -nf2_write_static_wildcard(void) -{ - nf2_of_entry_wrap entry; - nf2_of_mask_wrap mask; - nf2_of_action_wrap action; - int i; - struct net_device *dev; - - dev = nf2_get_net_device(); - if (dev == NULL) - return 1; - - memset(&entry, 0x00, sizeof(nf2_of_entry_wrap)); - memset(&mask, 0xFF, sizeof(nf2_of_mask_wrap)); - // Only non-wildcard section is the source port - mask.entry.src_port = 0; - memset(&action, 0, sizeof(nf2_of_action_wrap)); - - // write the catch all entries to send to the cpu - for (i = 0; i < 4; ++i) { - entry.entry.src_port = i * 2; - action.action.forward_bitmask = 0x1 << ((i * 2) + 1); - nf2_write_of_wildcard(dev, (OPENFLOW_WILDCARD_TABLE_SIZE - 4) - + i, &entry, &mask, &action); - } - - // write the entries to send out packets coming from the cpu - for (i = 0; i < 4; ++i) { - entry.entry.src_port = (i * 2) + 1; - action.action.forward_bitmask = 0x1 << (i * 2); - nf2_write_of_wildcard(dev, (OPENFLOW_WILDCARD_TABLE_SIZE - 8) - + i, &entry, &mask, &action); - } - - nf2_free_net_device(dev); - return 0; -} - -/* Populate a nf2_of_entry_wrap with entries from a struct sw_flow. */ -void -nf2_populate_of_entry(nf2_of_entry_wrap *key, struct sw_flow *flow) -{ - int vlan_vid; - int vlan_pcp; - int i; - - key->entry.transp_dst = ntohs(flow->key.tp_dst); - key->entry.transp_src = ntohs(flow->key.tp_src); - key->entry.ip_proto = flow->key.nw_proto; - key->entry.ip_dst = ntohl(flow->key.nw_dst); - key->entry.ip_src = ntohl(flow->key.nw_src); - key->entry.eth_type = ntohs(flow->key.dl_type); - // Blame Jad for applying endian'ness to character arrays - for (i = 0; i < 6; ++i) { - key->entry.eth_dst[i] = flow->key.dl_dst[5 - i]; - } - for (i = 0; i < 6; ++i) { - key->entry.eth_src[i] = flow->key.dl_src[5 - i]; - } - - key->entry.src_port = (ntohs(flow->key.in_port) - PORT_BASE) * 2; - - if (ntohs(flow->key.dl_vlan) == 0xffff) { - key->entry.vlan_id = 0xffff; - } else { - vlan_vid = VID_BITMASK & ntohs(flow->key.dl_vlan); - vlan_pcp = PCP_BITMASK - & ((uint16_t)(flow->key.dl_vlan_pcp) << PCP_BITSHIFT); - key->entry.vlan_id = vlan_pcp | vlan_vid; - } -} - -static uint32_t -make_nw_wildcard(int n_wild_bits) -{ - n_wild_bits &= (1u << OFPFW_NW_SRC_BITS) - 1; - return n_wild_bits < 32 ? ((1u << n_wild_bits) - 1) : 0xFFFFFFFF; -} - -/* Populate a nf2_of_mask_wrap with entries from a struct sw_flow's wildcards. */ -void -nf2_populate_of_mask(nf2_of_mask_wrap *mask, struct sw_flow *flow) -{ - int vlan_vid = 0; - int vlan_pcp = 0; - int i; - - if (OFPFW_IN_PORT & flow->key.wildcards) { - mask->entry.src_port = 0xFF; - } - if (OFPFW_DL_VLAN & flow->key.wildcards) { - vlan_vid = 0x0FFF; - } - if (OFPFW_DL_VLAN_PCP & flow->key.wildcards) { - vlan_pcp = 0xE000; - } - mask->entry.vlan_id = vlan_pcp | vlan_vid; - if (OFPFW_DL_SRC & flow->key.wildcards) { - for (i = 0; i < 6; ++i) { - mask->entry.eth_src[i] = 0xFF; - } - } - if (OFPFW_DL_DST & flow->key.wildcards) { - for (i = 0; i < 6; ++i) { - mask->entry.eth_dst[i] = 0xFF; - } - } - if (OFPFW_DL_TYPE & flow->key.wildcards) - mask->entry.eth_type = 0xFFFF; - if ((OFPFW_NW_SRC_ALL & flow->key.wildcards) - || (OFPFW_NW_SRC_MASK & flow->key.wildcards)) - mask->entry.ip_src = make_nw_wildcard - (flow->key.wildcards >> OFPFW_NW_SRC_SHIFT); - if ((OFPFW_NW_DST_ALL & flow->key.wildcards) - || (OFPFW_NW_DST_MASK & flow->key.wildcards)) - mask->entry.ip_dst = make_nw_wildcard - (flow->key.wildcards >> OFPFW_NW_DST_SHIFT); - if (OFPFW_NW_PROTO & flow->key.wildcards) - mask->entry.ip_proto = 0xFF; - if (OFPFW_TP_SRC & flow->key.wildcards) - mask->entry.transp_src = 0xFFFF; - if (OFPFW_TP_DST & flow->key.wildcards) - mask->entry.transp_dst = 0xFFFF; - - mask->entry.pad = 0x0000; -} - -static void -populate_action_output(nf2_of_action_wrap *action, nf2_of_entry_wrap *entry, - uint8_t *flowact) -{ - uint16_t port = 0; - struct ofp_action_output *actout = (struct ofp_action_output *)flowact; - int i; - - port = ntohs(actout->port); - NF2DEBUGMSG("Action Type: %i Output Port: %i\n", - ntohs(actout->type), port); - - if ((port >= PORT_BASE) && (port <= MAX_IFACE)) { - // Bitmask for output port(s), evens are phys odds cpu - action->action.forward_bitmask - |= (1 << ((port - PORT_BASE) * 2)); - NF2DEBUGMSG("Output Port: %i Forward Bitmask: %x\n", - port, action->action.forward_bitmask); - } else if (port == OFPP_IN_PORT) { - // Send out to input port - action->action.forward_bitmask - |= (1 << (entry->entry.src_port)); - NF2DEBUGMSG("Output Port = Input Port Forward Bitmask: %x\n", - action->action.forward_bitmask); - } else if (port == OFPP_ALL || port == OFPP_FLOOD) { - // Send out all ports except the source - for (i = 0; i < 4; ++i) { - if ((i * 2) != entry->entry.src_port) { - // Bitmask for output port(s), evens are - // phys odds cpu - action->action.forward_bitmask - |= (1 << (i * 2)); - NF2DEBUGMSG - ("Output Port: %i Forward Bitmask: %x\n", - port, action->action.forward_bitmask); - } - } - } -} - -static void -populate_action_set_dl_src(nf2_of_action_wrap *action, uint8_t *flowact) -{ - struct ofp_action_dl_addr *actdl = (struct ofp_action_dl_addr *)flowact; - int i; - - for (i = 0; i < 6; ++i) { - action->action.eth_src[5 - i] = actdl->dl_addr[i]; - } - action->action.nf2_action_flag |= (1 << OFPAT_SET_DL_SRC); -} - -static void -populate_action_set_dl_dst(nf2_of_action_wrap *action, uint8_t *flowact) -{ - struct ofp_action_dl_addr *actdl = (struct ofp_action_dl_addr *)flowact; - int i; - - for (i = 0; i < 6; ++i) { - action->action.eth_dst[5 - i] = actdl->dl_addr[i]; - } - action->action.nf2_action_flag |= (1 << OFPAT_SET_DL_DST); -} - -/* Populate an nf2_of_action_wrap. */ -void -nf2_populate_of_action(nf2_of_action_wrap *action, nf2_of_entry_wrap *entry, - nf2_of_mask_wrap *mask, struct sw_flow *flow) -{ - struct sw_flow_actions *sfa; - size_t actions_len; - uint8_t *p; - - sfa = flow->sf_acts; - actions_len = sfa->actions_len; - p = (uint8_t *)sfa->actions; - - // zero it out for now - memset(action, 0, sizeof(nf2_of_action_wrap)); - action->action.nf2_action_flag = 0; - - while (actions_len > 0) { - struct ofp_action_header *acth = (struct ofp_action_header *)p; - size_t len = ntohs(acth->len); - - NF2DEBUGMSG("Action Populate: Len of this action: %i\n", len); - NF2DEBUGMSG("Action Populate: Len of actions : %i\n", - actions_len); - - if (acth->type == htons(OFPAT_OUTPUT)) { - populate_action_output(action, entry, p); - } else if (acth->type == htons(OFPAT_SET_DL_SRC)) { - populate_action_set_dl_src(action, p); - } else if (acth->type == htons(OFPAT_SET_DL_DST)) { - populate_action_set_dl_dst(action, p); - } - p += len; - actions_len -= len; - } -} - -/* Add a free hardware entry back to the exact pool. */ -void -nf2_add_free_exact(struct nf2_flow *sfw) -{ - // clear the node entry - INIT_LIST_HEAD(&sfw->node); - - // Critical section, adding to the actual list - exact_free_list[sfw->pos] = sfw; -} - -/* Add a free hardware entry back to the wildcard pool. */ -void -nf2_add_free_wildcard(struct nf2_flow *sfw) -{ - // clear the hw values - sfw->hw_packet_count = 0; - sfw->hw_byte_count = 0; - - // Critical section, adding to the actual list - list_add_tail(&sfw->node, &wildcard_free_list); -} - -/* Hashes the entry to find where it should exist in the exact table - * returns NULL on failure - */ -static struct nf2_flow * -get_free_exact(nf2_of_entry_wrap *entry) -{ - unsigned int poly1 = 0x04C11DB7; - unsigned int poly2 = 0x1EDC6F41; - struct nf2_flow *sfw = NULL; - unsigned int hash = 0x0; - unsigned int index = 0x0; - struct crc32 crc; - - crc32_init(&crc, poly1); - hash = crc32_calculate(&crc, entry, sizeof(nf2_of_entry_wrap)); - - // the bottom 15 bits of hash == the index into the table - index = 0x7FFF & hash; - - // if this index is free, grab it - sfw = exact_free_list[index]; - exact_free_list[index] = NULL; - - if (sfw != NULL) { - return sfw; - } - // try the second index - crc32_init(&crc, poly2); - hash = crc32_calculate(&crc, entry, sizeof(nf2_of_entry_wrap)); - // the bottom 15 bits of hash == the index into the table - index = 0x7FFF & hash; - - // if this index is free, grab it - sfw = exact_free_list[index]; - exact_free_list[index] = NULL; - - // return whether its good or not - return sfw; -} - -/* Get the first free position in the wildcard hardware table - * to write into. - */ -static struct nf2_flow * -get_free_wildcard(void) -{ - struct nf2_flow *sfw = NULL; - struct list_head *next = NULL; - - // Critical section, pulling the first available from the list - if (list_empty(&wildcard_free_list)) { - // empty :( - sfw = NULL; - } else { - next = wildcard_free_list.next; - sfw = list_entry(next, struct nf2_flow, node); - list_del_init(&sfw->node); - } - - return sfw; -} - -/* Retrieves the type of table this flow should go into. */ -int -nf2_get_table_type(struct sw_flow *flow) -{ - if (flow->key.wildcards != 0) { - NF2DEBUGMSG("--- TABLE TYPE: WILDCARD ---\n"); - return NF2_TABLE_WILDCARD; - } else { - NF2DEBUGMSG("--- TABLE TYPE: EXACT ---\n"); - return NF2_TABLE_EXACT; - } -} - -/* Returns 1 if this flow contains an action outputting to all ports except - * input port, 0 otherwise. We support OFPP_ALL and OFPP_FLOOD actions, however - * since we do not perform the spanning tree protocol (STP) then OFPP_FLOOD is - * equivalent to OFPP_ALL. - */ -static int -is_action_forward_all(struct sw_flow *flow) -{ - struct sw_flow_actions *sfa; - size_t actions_len; - uint8_t *p; - - sfa = flow->sf_acts; - actions_len = sfa->actions_len; - p = (uint8_t *)sfa->actions; - - while (actions_len > 0) { - struct ofp_action_header *ah = (struct ofp_action_header *)p; - struct ofp_action_output *oa = (struct ofp_action_output *)p; - size_t len = ntohs(ah->len); - - NF2DEBUGMSG("Fwd Action Chk: Action type: %x\n", - ntohs(ah->type)); - NF2DEBUGMSG("Fwd Action Chk: Output port: %x\n", - ntohs(oa->port)); - NF2DEBUGMSG("Fwd Action Chk: Len of this action: %i\n", len); - NF2DEBUGMSG("Fwd Action Chk: Len of actions : %i\n", - actions_len); - // Currently only support the output port(s) action - if (ntohs(ah->type) == OFPAT_OUTPUT - && (ntohs(oa->port) == OFPP_ALL - || ntohs(oa->port) == OFPP_FLOOD)) { - return 1; - } - p += len; - actions_len -= len; - } - - return 0; -} - -/* Attempts to build and write the flow to hardware. - * Returns 0 on success, 1 on failure. - */ -int -nf2_build_and_write_flow(struct sw_flow *flow) -{ - struct nf2_flow *sfw = NULL; - struct nf2_flow *sfw_next = NULL; - struct net_device *dev; - int num_entries = 0; - int i, table_type; - nf2_of_entry_wrap key; - nf2_of_mask_wrap mask; - nf2_of_action_wrap action; - - memset(&key, 0, sizeof(nf2_of_entry_wrap)); - memset(&mask, 0, sizeof(nf2_of_mask_wrap)); - memset(&action, 0, sizeof(nf2_of_action_wrap)); - - dev = nf2_get_net_device(); - if (dev == NULL) { - // failure getting net device - NF2DEBUGMSG("Failure getting net device struct\n"); - return 1; - } - - table_type = nf2_get_table_type(flow); - switch (table_type) { - default: - break; - - case NF2_TABLE_EXACT: - NF2DEBUGMSG("---Exact Entry---\n"); - nf2_populate_of_entry(&key, flow); - nf2_populate_of_action(&action, &key, NULL, flow); - sfw = get_free_exact(&key); - if (sfw == NULL) { - NF2DEBUGMSG - ("Collision getting free exact match entry\n"); - // collision - nf2_free_net_device(dev); - return 1; - } - // set the active bit on this entry - key.entry.pad = 0x8000; - nf2_write_of_exact(dev, sfw->pos, &key, &action); - flow->private = (void *)sfw; - break; - - case NF2_TABLE_WILDCARD: - NF2DEBUGMSG("---Wildcard Entry---\n"); - // if action is all out and source port is wildcarded - if ((is_action_forward_all(flow)) && - (flow->key.wildcards & OFPFW_IN_PORT)) { - NF2DEBUGMSG("Grab four wildcard tables\n"); - if (!(sfw = get_free_wildcard())) { - NF2DEBUGMSG("No free wildcard entries found."); - // no free entries - nf2_free_net_device(dev); - return 1; - } - // try to get 3 more positions - for (i = 0; i < 3; ++i) { - if (!(sfw_next = get_free_wildcard())) { - break; - } - list_add_tail(&sfw_next->node, &sfw->node); - ++num_entries; - } - - if (num_entries < 3) { - // failed to get enough entries, return them and exit - nf2_delete_private((void *)sfw); - nf2_free_net_device(dev); - return 1; - } - - nf2_populate_of_entry(&key, flow); - nf2_populate_of_mask(&mask, flow); - - // set first entry's src port to 0, remove wildcard mask on src - key.entry.src_port = 0; - mask.entry.src_port = 0; - nf2_populate_of_action(&action, &key, &mask, flow); - nf2_write_of_wildcard(dev, sfw->pos, &key, &mask, - &action); - - i = 1; - sfw_next = list_entry(sfw->node.next, - struct nf2_flow, node); - // walk through and write the remaining 3 entries - while (sfw_next != sfw) { - key.entry.src_port = i * 2; - nf2_populate_of_action(&action, &key, &mask, - flow); - nf2_write_of_wildcard(dev, sfw_next->pos, &key, - &mask, &action); - sfw_next = list_entry(sfw_next->node.next, - struct nf2_flow, node); - ++i; - } - flow->private = (void *)sfw; - } else { - /* Get a free position here, and write to it */ - if ((sfw = get_free_wildcard())) { - nf2_populate_of_entry(&key, flow); - nf2_populate_of_mask(&mask, flow); - nf2_populate_of_action(&action, &key, &mask, - flow); - if (nf2_write_of_wildcard - (dev, sfw->pos, &key, &mask, &action)) { - // failure writing to hardware - nf2_add_free_wildcard(sfw); - NF2DEBUGMSG - ("Failure writing to hardware\n"); - nf2_free_net_device(dev); - return 1; - } else { - // success writing to hardware, store the position - flow->private = (void *)sfw; - } - } else { - // hardware is full, return 0 - NF2DEBUGMSG("No free wildcard entries found."); - nf2_free_net_device(dev); - return 1; - } - } - break; - } - - nf2_free_net_device(dev); - return 0; -} - -void -nf2_delete_private(void *private) -{ - struct nf2_flow *sfw = (struct nf2_flow *)private; - struct nf2_flow *sfw_next; - struct list_head *next; - - switch (sfw->type) { - default: - break; - - case NF2_TABLE_EXACT: - nf2_clear_of_exact(sfw->pos); - nf2_add_free_exact(sfw); - break; - - case NF2_TABLE_WILDCARD: - while (!list_empty(&sfw->node)) { - next = sfw->node.next; - sfw_next = list_entry(next, struct nf2_flow, node); - list_del_init(&sfw_next->node); - // Immediately zero out the entry in hardware - nf2_clear_of_wildcard(sfw_next->pos); - // add it back to the pool - nf2_add_free_wildcard(sfw_next); - } - // zero the core entry - nf2_clear_of_wildcard(sfw->pos); - // add back the core entry - nf2_add_free_wildcard(sfw); - break; - } -} - -int -nf2_modify_acts(struct sw_table *swt, struct sw_flow *flow) -{ - struct nf2_flow *sfw = (struct nf2_flow *)flow->private; - struct net_device *dev; - nf2_of_entry_wrap key; - nf2_of_mask_wrap mask; - nf2_of_action_wrap action; - - memset(&key, 0, sizeof(nf2_of_entry_wrap)); - memset(&mask, 0, sizeof(nf2_of_mask_wrap)); - memset(&action, 0, sizeof(nf2_of_action_wrap)); - - dev = nf2_get_net_device(); - if (dev == NULL) - return 0; - - switch (sfw->type) { - default: - break; - - case NF2_TABLE_EXACT: - nf2_populate_of_entry(&key, flow); - nf2_populate_of_action(&action, &key, NULL, flow); - key.entry.pad = 0x8000; - nf2_modify_write_of_exact(dev, sfw->pos, &action); - break; - - case NF2_TABLE_WILDCARD: - if (flow->key.wildcards & OFPFW_IN_PORT) { - nf2_free_net_device(dev); - return 0; - } - nf2_populate_of_entry(&key, flow); - nf2_populate_of_mask(&mask, flow); - nf2_populate_of_action(&action, &key, &mask, flow); - nf2_modify_write_of_wildcard(dev, sfw->pos, - &key, &mask, &action); - break; - } - - nf2_free_net_device(dev); - return 1; -} - -uint64_t -nf2_get_packet_count(struct net_device *dev, struct nf2_flow *sfw) -{ - uint32_t count = 0; - uint32_t hw_count = 0; - uint64_t total = 0; - struct nf2_flow *sfw_next = NULL; - - switch (sfw->type) { - default: - break; - - case NF2_TABLE_EXACT: - count = nf2_get_exact_packet_count(dev, sfw->pos); - total = count; - break; - - case NF2_TABLE_WILDCARD: - sfw_next = sfw; - do { - hw_count = nf2_get_wildcard_packet_count(dev, - sfw_next->pos); - if (hw_count >= sfw_next->hw_packet_count) { - count = hw_count - sfw_next->hw_packet_count; - sfw_next->hw_packet_count = hw_count; - } else { - // wrapping occurred - count = (MAX_INT_32 - sfw_next->hw_packet_count) - + hw_count; - sfw_next->hw_packet_count = hw_count; - } - total += count; - sfw_next = list_entry(sfw_next->node.next, - struct nf2_flow, node); - } while (sfw_next != sfw); - break; - } - - NF2DEBUGMSG("Return nf2_get_packet_count value: %llu\n", total); - return total; -} - -uint64_t -nf2_get_byte_count(struct net_device *dev, struct nf2_flow *sfw) -{ - uint32_t count = 0; - uint32_t hw_count = 0; - uint64_t total = 0; - struct nf2_flow *sfw_next = NULL; - - switch (sfw->type) { - default: - break; - - case NF2_TABLE_EXACT: - count = nf2_get_exact_byte_count(dev, sfw->pos); - total = count; - break; - - case NF2_TABLE_WILDCARD: - sfw_next = sfw; - do { - hw_count = nf2_get_wildcard_byte_count(dev, - sfw_next->pos); - if (hw_count >= sfw_next->hw_byte_count) { - count = hw_count - sfw_next->hw_byte_count; - sfw_next->hw_byte_count = hw_count; - } else { - // wrapping occurred - count = (MAX_INT_32 - sfw_next->hw_byte_count) - + hw_count; - sfw_next->hw_byte_count = hw_count; - } - - total += count; - sfw_next = list_entry(sfw_next->node.next, - struct nf2_flow, node); - } while (sfw_next != sfw); - break; - } - - NF2DEBUGMSG("Return nf2_get_byte_count value: %llu\n", total); - return total; -} diff --git a/openflow/datapath/hwtable_nf2/nf2_lib.h b/openflow/datapath/hwtable_nf2/nf2_lib.h deleted file mode 100644 index 9c0fedc8..00000000 --- a/openflow/datapath/hwtable_nf2/nf2_lib.h +++ /dev/null @@ -1,59 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#ifndef HWTABLE_NF2_NF2_LIB_H_ -#define HWTABLE_NF2_NF2_LIB_H_ - -struct net_device *nf2_get_net_device(void); -void nf2_free_net_device(struct net_device *); -int nf2_are_actions_supported(struct sw_flow *); -void nf2_clear_of_exact(uint32_t); -void nf2_clear_of_wildcard(uint32_t); -int nf2_init_exact_freelist(void); -int nf2_init_wildcard_freelist(void); -void nf2_destroy_exact_freelist(void); -void nf2_destroy_wildcard_freelist(void); -int nf2_write_static_wildcard(void); -void nf2_populate_of_entry(nf2_of_entry_wrap *, struct sw_flow *); -void nf2_populate_of_mask(nf2_of_mask_wrap *, struct sw_flow *); -void nf2_populate_of_action(nf2_of_action_wrap *, nf2_of_entry_wrap *, - nf2_of_mask_wrap *, struct sw_flow *); -void nf2_add_free_exact(struct nf2_flow *); -void nf2_add_free_wildcard(struct nf2_flow *); -int nf2_get_table_type(struct sw_flow *); -int nf2_build_and_write_flow(struct sw_flow *); -void nf2_delete_private(void *); -int nf2_modify_acts(struct sw_table *, struct sw_flow *); -uint64_t nf2_get_packet_count(struct net_device *, struct nf2_flow *); -uint64_t nf2_get_byte_count(struct net_device *, struct nf2_flow *); - -#endif diff --git a/openflow/datapath/hwtable_nf2/nf2_openflow.c b/openflow/datapath/hwtable_nf2/nf2_openflow.c deleted file mode 100644 index 7d392f19..00000000 --- a/openflow/datapath/hwtable_nf2/nf2_openflow.c +++ /dev/null @@ -1,847 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#include -#include -#include - -#include "flow.h" -#include "table.h" - -#include "hwtable_nf2/nf2.h" -#include "hwtable_nf2/nf2_reg.h" -#include "hwtable_nf2/nf2_hwapi.h" -#include "hwtable_nf2/nf2_flowtable.h" -#include "hwtable_nf2/nf2_openflow.h" -#include "hwtable_nf2/nf2_lib.h" - -static void log_entry(nf2_of_entry_wrap *); -static void log_entry_raw(nf2_of_entry_wrap *); -static void log_mask(nf2_of_mask_wrap *); -static void log_mask_raw(nf2_of_mask_wrap *); -static void log_action(nf2_of_action_wrap *); -static void log_action_raw(nf2_of_action_wrap *); -static struct nf2_all_ports_info_addr *nf2_get_all_ports_info_addr(void); - -static void -log_entry(nf2_of_entry_wrap *entry) -{ -#ifndef NF2_DEBUG - return; -#else - int i; - - // Log the physical source port - NF2DEBUGMSG("E psrc[%i] ", entry->entry.src_port / 2); - - // Log the link layer source - NF2DEBUGMSG("dlsrc["); - for (i = 5; i > 0; --i) { - NF2DEBUGMSG("%0X:", entry->entry.eth_src[i]); - } - NF2DEBUGMSG("%0X] ", entry->entry.eth_src[0]); - - // Log the link layer dest - NF2DEBUGMSG("dldst["); - for (i = 5; i > 0; --i) { - NF2DEBUGMSG("%0X:", entry->entry.eth_dst[i]); - } - NF2DEBUGMSG("%0X] ", entry->entry.eth_dst[0]); - - // Log the link layer type - NF2DEBUGMSG("dltype[%0X] ", entry->entry.eth_type); - - // Log the link layer vlan - NF2DEBUGMSG("dlvlan[%0X] ", entry->entry.vlan_id); - - // Log the network source - NF2DEBUGMSG("nwsrc["); - NF2DEBUGMSG("%0i.", (entry->entry.ip_src >> 24) & 0xFF); - NF2DEBUGMSG("%0i.", (entry->entry.ip_src >> 16) & 0xFF); - NF2DEBUGMSG("%0i.", (entry->entry.ip_src >> 8) & 0xFF); - NF2DEBUGMSG("%0i", entry->entry.ip_src & 0xFF); - NF2DEBUGMSG("] "); - - // Log the network dest - NF2DEBUGMSG("nwdst["); - NF2DEBUGMSG("%0i.", (entry->entry.ip_dst >> 24) & 0xFF); - NF2DEBUGMSG("%0i.", (entry->entry.ip_dst >> 16) & 0xFF); - NF2DEBUGMSG("%0i.", (entry->entry.ip_dst >> 8) & 0xFF); - NF2DEBUGMSG("%0i", entry->entry.ip_dst & 0xFF); - NF2DEBUGMSG("] "); - - // Log the transport source port - NF2DEBUGMSG("tsrc[%i] ", entry->entry.transp_src); - - // Log the transport dest port - NF2DEBUGMSG("tdst[%i]\n", entry->entry.transp_dst); -#endif -} - -static void -log_entry_raw(nf2_of_entry_wrap *entry) -{ -#ifndef NF2_DEBUG - return; -#else - int i; - unsigned char *c; - - NF2DEBUGMSG("E "); - c = (unsigned char *)entry; - for (i = 0; i < sizeof(nf2_of_entry_wrap); ++i) { - if (!(i % 4)) { - NF2DEBUGMSG(" "); - } - NF2DEBUGMSG("%02x", c[i]); - } - NF2DEBUGMSG("\n"); -#endif -} - -static void -log_mask(nf2_of_mask_wrap *mask) -{ -#ifndef NF2_DEBUG - return; -#else - int i; - - // Log the physical source port - NF2DEBUGMSG("M psrc[%0X] ", mask->entry.src_port / 2); - - // Log the link layer source - NF2DEBUGMSG("dlsrc["); - for (i = 5; i > 0; --i) { - NF2DEBUGMSG("%0X:", mask->entry.eth_src[i]); - } - NF2DEBUGMSG("%0X] ", mask->entry.eth_dst[0]); - - // Log the link layer dest - NF2DEBUGMSG("dldst["); - for (i = 5; i > 0; --i) { - NF2DEBUGMSG("%0X:", mask->entry.eth_dst[i]); - } - NF2DEBUGMSG("%0X] ", mask->entry.eth_dst[0]); - - // Log the link layer type - NF2DEBUGMSG("dltype[%0X] ", mask->entry.eth_type); - - // Log the link layer vlan - NF2DEBUGMSG("dlvlan[%0X] ", mask->entry.vlan_id); - - // Log the network source - NF2DEBUGMSG("nwsrc["); - NF2DEBUGMSG("%0X.", (mask->entry.ip_src >> 24) & 0xFF); - NF2DEBUGMSG("%0X.", (mask->entry.ip_src >> 16) & 0xFF); - NF2DEBUGMSG("%0X.", (mask->entry.ip_src >> 8) & 0xFF); - NF2DEBUGMSG("%0X", mask->entry.ip_src & 0xFF); - NF2DEBUGMSG("] "); - - // Log the network dest - NF2DEBUGMSG("nwdst["); - NF2DEBUGMSG("%0X.", (mask->entry.ip_dst >> 24) & 0xFF); - NF2DEBUGMSG("%0X.", (mask->entry.ip_dst >> 16) & 0xFF); - NF2DEBUGMSG("%0X.", (mask->entry.ip_dst >> 8) & 0xFF); - NF2DEBUGMSG("%0X", mask->entry.ip_dst & 0xFF); - NF2DEBUGMSG("] "); - - // Log the transport source port - NF2DEBUGMSG("tsrc[%0X] ", mask->entry.transp_src); - - // Log the transport dest port - NF2DEBUGMSG("tdst[%0X]\n", mask->entry.transp_dst); -#endif -} - -static void -log_mask_raw(nf2_of_mask_wrap *mask) -{ -#ifndef NF2_DEBUG - return; -#else - int i; - unsigned char *c; - - NF2DEBUGMSG("M "); - c = (unsigned char *)mask; - for (i = 0; i < sizeof(nf2_of_mask_wrap); ++i) { - if (!(i % 4)) { - NF2DEBUGMSG(" "); - } - NF2DEBUGMSG("%02x", c[i]); - } - NF2DEBUGMSG("\n"); -#endif -} - -static void -log_action(nf2_of_action_wrap *action) -{ -#ifndef NF2_DEBUG - return; -#else - int i; - - NF2DEBUGMSG("A Output P["); - for (i = 0; i < 4; ++i) { - if (action->action.forward_bitmask & (1 << (i * 2))) { - NF2DEBUGMSG("%i", i); - } - } - NF2DEBUGMSG("] CPU["); - for (i = 0; i < 4; ++i) { - if (action->action.forward_bitmask & (1 << (1 + (i * 2)))) { - NF2DEBUGMSG("%i", i); - } - } - NF2DEBUGMSG("]\n"); -#endif -} - -static void -log_action_raw(nf2_of_action_wrap *action) -{ -#ifndef NF2_DEBUG - return; -#else - int i; - unsigned char *c; - - NF2DEBUGMSG("A "); - c = (unsigned char *)action; - for (i = 0; i < sizeof(nf2_of_action_wrap); ++i) { - if (!(i % 4)) { - NF2DEBUGMSG(" "); - } - NF2DEBUGMSG("%02x", c[i]); - } - NF2DEBUGMSG("\n"); -#endif -} - -void -nf2_reset_card(struct net_device *dev) -{ - volatile unsigned int val; - - if (dev == NULL) { - return; - } - - /* If we are operating on a NetFPGA enabled box, reset the card */ - printk(KERN_INFO "openflowswitch-netfpga2: Resetting the NetFPGA.\n"); - nf2k_reg_read(dev, WDT_CPCI_REG_CTRL, (void *)&val); - val |= 0x100; - nf2k_reg_write(dev, WDT_CPCI_REG_CTRL, (void *)&val); - printk(KERN_INFO "openflowswitch-netfpga2: Reset the NetFPGA.\n"); - ssleep(2); -} - -void -nf2_clear_watchdog(struct net_device *dev) -{ - volatile unsigned int enable_status; - -#ifndef NF2_WATCHDOG - return; -#endif - if (dev == NULL) { - return; - } - - nf2k_reg_read(dev, WDT_ENABLE_FLG_REG, (void *)&enable_status); - enable_status &= 0x1; - - if (enable_status == WATCHDOG_DISABLE) { - enable_status = WATCHDOG_ENABLE; - nf2k_reg_write(dev, WDT_ENABLE_FLG_REG, (void *)&enable_status); - } - return; -} - -/* Write a wildcard entry to the specified device and row. The row consists of - * the actual entry, its mask that specifies wildcards, as well as the action(s) - * to be taken if the row is matched - */ -int -nf2_write_of_wildcard(struct net_device *dev, int row, - nf2_of_entry_wrap *entry, nf2_of_mask_wrap *mask, - nf2_of_action_wrap *action) -{ - int i; - int val; - struct timeval t; - - NF2DEBUGMSG("** Begin wildcard entry write to row: %i\n", row); - log_entry(entry); - log_mask(mask); - log_action(action); - log_entry_raw(entry); - log_mask_raw(mask); - log_action_raw(action); - - for (i = 0; i < NF2_OF_ENTRY_WORD_LEN; ++i) { - nf2k_reg_write(dev, - OPENFLOW_WILDCARD_LOOKUP_CMP_0_REG - + (4 * i), &(entry->raw[i])); - } - - for (i = 0; i < NF2_OF_MASK_WORD_LEN; ++i) { - nf2k_reg_write(dev, - OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_0_REG - + (4 * i), &(mask->raw[i])); - } - - for (i = 0; i < NF2_OF_ACTION_WORD_LEN; ++i) { - nf2k_reg_write(dev, - OPENFLOW_WILDCARD_LOOKUP_ACTION_0_REG - + (4 * i), &(action->raw[i])); - } - - // Reset the stats for the row - val = 0; - nf2k_reg_write(dev, - OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG + (4 * row), - &val); - nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG + (4 * row), - &val); - nf2k_reg_write(dev, - OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_0_REG + (4 * row), - &val); - nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_WRITE_ADDR_REG, &row); - - do_gettimeofday(&t); - NF2DEBUGMSG("** End wildcard entry write to row: %i time: %i.%i\n", - row, (int)t.tv_sec, (int)t.tv_usec); - - return 0; -} - -int -nf2_write_of_exact(struct net_device *dev, int row, - nf2_of_entry_wrap *entry, nf2_of_action_wrap *action) -{ - int i; - int val; - struct timeval t; - unsigned int index = row << 7; - - NF2DEBUGMSG("** Begin exact match entry write to row: %i\n", row); - log_entry(entry); - log_action(action); - log_entry_raw(entry); - log_action_raw(action); - - for (i = 0; i < NF2_OF_ENTRY_WORD_LEN; ++i) { - nf2k_reg_write(dev, SRAM_BASE_ADDR + index - + (4 * i), &(entry->raw[i])); - } - - // blank out the counters - val = 0; - for (i = 0; i < NF2_OF_EXACT_COUNTERS_WORD_LEN; ++i) { - nf2k_reg_write(dev, SRAM_BASE_ADDR + index - + sizeof(nf2_of_entry_wrap) - + (4 * i), &val); - } - - // write the actions - for (i = 0; i < NF2_OF_ACTION_WORD_LEN; ++i) { - nf2k_reg_write(dev, SRAM_BASE_ADDR + index - + sizeof(nf2_of_entry_wrap) - + sizeof(nf2_of_exact_counters_wrap) - + (4 * i), &(action->raw[i])); - } - - do_gettimeofday(&t); - NF2DEBUGMSG("** End exact match entry write to row: %i time: %i.%i\n", - row, (int)t.tv_sec, (int)t.tv_usec); - - return 0; -} - -/* Write wildcard action(s) to the specified device and row. */ -int -nf2_modify_write_of_wildcard(struct net_device *dev, int row, - nf2_of_entry_wrap *entry, nf2_of_mask_wrap *mask, - nf2_of_action_wrap *action) -{ - int i; - int bytes_reg_val; - int pkts_reg_val; - int last_reg_val; - struct timeval t; - - NF2DEBUGMSG("** Begin wildcard modified action write to row: %i\n", - row); - log_entry(entry); - log_mask(mask); - log_action(action); - log_entry_raw(entry); - log_mask_raw(mask); - log_action_raw(action); - - nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_READ_ADDR_REG, &row); - nf2k_reg_read(dev, - OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG + (4 * row), - &bytes_reg_val); - nf2k_reg_read(dev, - OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG + (4 * row), - &pkts_reg_val); - nf2k_reg_read(dev, - OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_0_REG + (4 * row), - &last_reg_val); - - for (i = 0; i < NF2_OF_ENTRY_WORD_LEN; ++i) { - nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_CMP_0_REG - + (4 * i), &(entry->raw[i])); - } - - for (i = 0; i < NF2_OF_MASK_WORD_LEN; ++i) { - nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_0_REG - + (4 * i), &(mask->raw[i])); - } - - for (i = 0; i < NF2_OF_ACTION_WORD_LEN; ++i) { - nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_ACTION_0_REG - + (4 * i), &(action->raw[i])); - } - - nf2k_reg_write(dev, - OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG + (4 * row), - &bytes_reg_val); - nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG + (4 * row), - &pkts_reg_val); - nf2k_reg_write(dev, - OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_0_REG + (4 * row), - &last_reg_val); - nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_WRITE_ADDR_REG, &row); - - do_gettimeofday(&t); - NF2DEBUGMSG - ("** End wildcard modified action write to row: %i time: %i.%i\n", - row, (int)t.tv_sec, (int)t.tv_usec); - NF2DEBUGMSG(" Bytes hit count: %d\n", bytes_reg_val); - NF2DEBUGMSG(" Pkts hit count: %d\n", pkts_reg_val); - NF2DEBUGMSG(" Last seen : %d\n", last_reg_val); - - return 0; -} - -int -nf2_modify_write_of_exact(struct net_device *dev, int row, - nf2_of_action_wrap *action) -{ - int i; - struct timeval t; - unsigned int index = row << 7; - - NF2DEBUGMSG("** Begin exact match modified action write to row: %i\n", - row); - log_action(action); - log_action_raw(action); - - // write the actions - for (i = 0; i < NF2_OF_ACTION_WORD_LEN; ++i) { - nf2k_reg_write(dev, SRAM_BASE_ADDR + index - + sizeof(nf2_of_entry_wrap) - + sizeof(nf2_of_exact_counters_wrap) - + (4 * i), &(action->raw[i])); - } - - do_gettimeofday(&t); - NF2DEBUGMSG - ("** End exact match modified action write to row: %i time: %i.%i\n", - row, (int)t.tv_sec, (int)t.tv_usec); - - return 0; -} - -unsigned int -nf2_get_exact_packet_count(struct net_device *dev, int row) -{ - unsigned int val = 0; - unsigned int index = 0; - - /* TODO: Need to scrape data from all 4 registers - * in the case of a wildcarded source port and - * forward all action type - */ - nf2_of_exact_counters_wrap counters; - memset(&counters, 0, sizeof(nf2_of_exact_counters_wrap)); - - // build the index to our counters - index = row << 7; - - // Read the first word into our struct, to not disturb the byte count - nf2k_reg_read(dev, - SRAM_BASE_ADDR + index + sizeof(nf2_of_entry_wrap), - &counters); - val = counters.counters.pkt_count; - - NF2DEBUGMSG("** Exact match packet count request row: %i count: %i\n", - row, val); - - return val; -} - -unsigned int -nf2_get_exact_byte_count(struct net_device *dev, int row) -{ - unsigned int val = 0; - unsigned int index = 0; - - /* TODO: Need to scrape data from all 4 registers - * in the case of a wildcarded source port and - * forward all action type - */ - nf2_of_exact_counters_wrap counters; - memset(&counters, 0, sizeof(nf2_of_exact_counters_wrap)); - - // build the index to our counters - index = row << 7; - - // Read the second word into our struct, to not disturb the packet count - nf2k_reg_read(dev, SRAM_BASE_ADDR + index + - sizeof(nf2_of_entry_wrap) + 4, &counters.raw[1]); - val = counters.counters.byte_count; - - NF2DEBUGMSG("** Exact match byte count request row: %i count: %i\n", - row, val); - - return val; -} - -unsigned int -nf2_get_wildcard_packet_count(struct net_device *dev, int row) -{ - unsigned int val = 0; -#ifdef NF2_DEBUG - struct timeval t; -#endif - - nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_READ_ADDR_REG, &row); - nf2k_reg_read(dev, OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG - + (4 * row), &val); - -#ifdef NF2_DEBUG - do_gettimeofday(&t); - NF2DEBUGMSG - ("** Wildcard packet count request row: %i count: %i time: %i.%i\n", - row, val, (int)t.tv_sec, (int)t.tv_usec); -#endif - - return val; -} - -unsigned int -nf2_get_wildcard_byte_count(struct net_device *dev, int row) -{ - unsigned int val = 0; -#ifdef NF2_DEBUG - struct timeval t; -#endif - - nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_READ_ADDR_REG, &row); - nf2k_reg_read(dev, OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG - + (4 * row), &val); - -#ifdef NF2_DEBUG - do_gettimeofday(&t); - NF2DEBUGMSG - ("** Wildcard byte count request row: %i count: %i time: %i.%i\n", - row, val, (int)t.tv_sec, (int)t.tv_usec); -#endif - - return val; -} - -unsigned long int -nf2_get_matched_count(struct net_device *dev) -{ - unsigned int val_wild = 0; - unsigned int val_exact = 0; -#ifdef NF2_DEBUG - struct timeval t; -#endif - - nf2k_reg_read(dev, OPENFLOW_LOOKUP_WILDCARD_HITS_REG, &val_wild); - nf2k_reg_read(dev, OPENFLOW_LOOKUP_EXACT_HITS_REG, &val_exact); - -#ifdef NF2_DEBUG - do_gettimeofday(&t); - NF2DEBUGMSG("** Wildcard Matched count: %i time: %i.%i\n", - val_wild, (int)t.tv_sec, (int)t.tv_usec); - NF2DEBUGMSG("** Exact Matched count: %i time: %i.%i\n", - val_exact, (int)t.tv_sec, (int)t.tv_usec); -#endif - - return ((unsigned long int)(val_wild + val_exact)); -} - -unsigned long int -nf2_get_missed_count(struct net_device *dev) -{ - unsigned int val_wild = 0; - unsigned int val_exact = 0; -#ifdef NF2_DEBUG - struct timeval t; -#endif - - nf2k_reg_read(dev, OPENFLOW_LOOKUP_WILDCARD_MISSES_REG, &val_wild); - nf2k_reg_read(dev, OPENFLOW_LOOKUP_EXACT_MISSES_REG, &val_exact); - -#ifdef NF2_DEBUG - do_gettimeofday(&t); - NF2DEBUGMSG("** Wildcard Missed count: %i time: %i.%i\n", - val_wild, (int)t.tv_sec, (int)t.tv_usec); - NF2DEBUGMSG("** Exact Missed count: %i time: %i.%i\n", - val_exact, (int)t.tv_sec, (int)t.tv_usec); -#endif - - return ((unsigned long int)(val_wild + val_exact)); -} - -struct nf2_device_info * -nf2_get_device_info(struct net_device *dev) -{ - struct nf2_device_info *nf2devinfo; - int i; - - nf2devinfo = kzalloc(sizeof(struct nf2_device_info), GFP_KERNEL); - if (nf2devinfo == NULL) - return NULL; - - // Read the version and revision - nf2k_reg_read(dev, DEV_ID_DEVICE_ID_REG, &(nf2devinfo->nf2_device_id)); - nf2k_reg_read(dev, DEV_ID_REVISION_REG, &(nf2devinfo->nf2_device_rev)); - - // Read the design name string - for (i = 0; i < (DEVICE_STR_LEN / 4) - 2; i++) { - nf2k_reg_read(dev, DEV_ID_DEV_STR_0_REG + i * 4, - (uint32_t *)(nf2devinfo->nf2_device_str + i * 4)); - *(uint32_t *)(nf2devinfo->nf2_device_str + i * 4) - = ntohl(*(uint32_t *) - (nf2devinfo->nf2_device_str + i * 4)); - } - nf2devinfo->nf2_device_str[DEVICE_STR_LEN - 1] = '\0'; - - return nf2devinfo; -} - -struct nf2_match_info * -nf2_get_match_info(struct net_device *dev) -{ - struct nf2_match_info *nf2matchinfo; - - nf2matchinfo = kzalloc(sizeof(struct nf2_match_info), GFP_KERNEL); - if (nf2matchinfo == NULL) - return NULL; - - nf2k_reg_read(dev, OPENFLOW_LOOKUP_WILDCARD_MISSES_REG, - &(nf2matchinfo->wildcard_misses)); - nf2k_reg_read(dev, OPENFLOW_LOOKUP_WILDCARD_HITS_REG, - &(nf2matchinfo->wildcard_hits)); - nf2k_reg_read(dev, OPENFLOW_LOOKUP_EXACT_MISSES_REG, - &(nf2matchinfo->exact_misses)); - nf2k_reg_read(dev, OPENFLOW_LOOKUP_EXACT_HITS_REG, - &(nf2matchinfo->exact_hits)); - - return nf2matchinfo; -} - -unsigned int -nf2_get_watchdog_info(struct net_device *dev) -{ - unsigned int nf2wdtinfo = 0; - - nf2k_reg_read(dev, WDT_COUNTER_REG, &nf2wdtinfo); - return nf2wdtinfo; -} - -static struct nf2_all_ports_info_addr * -nf2_get_all_ports_info_addr(void) -{ - struct nf2_all_ports_info_addr *nf2addr; - - nf2addr = kzalloc(sizeof(struct nf2_all_ports_info_addr), GFP_KERNEL); - if (nf2addr == NULL) - return NULL; - - nf2addr->rx_q_num_pkts_stored_reg[0] - = MAC_GRP_0_RX_QUEUE_NUM_PKTS_STORED_REG; - nf2addr->rx_q_num_pkts_dropped_full_reg[0] - = MAC_GRP_0_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG; - nf2addr->rx_q_num_pkts_dropped_bad_reg[0] - = MAC_GRP_0_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG; - nf2addr->rx_q_num_words_pushed_reg[0] - = MAC_GRP_0_RX_QUEUE_NUM_WORDS_PUSHED_REG; - nf2addr->rx_q_num_bytes_pushed_reg[0] - = MAC_GRP_0_RX_QUEUE_NUM_BYTES_PUSHED_REG; - nf2addr->rx_q_num_pkts_dequeued_reg[0] - = MAC_GRP_0_RX_QUEUE_NUM_PKTS_DEQUEUED_REG; - nf2addr->rx_q_num_pkts_in_queue_reg[0] - = MAC_GRP_0_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG; - nf2addr->tx_q_num_pkts_in_queue_reg[0] - = MAC_GRP_0_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG; - nf2addr->tx_q_num_pkts_sent_reg[0] - = MAC_GRP_0_TX_QUEUE_NUM_PKTS_SENT_REG; - nf2addr->tx_q_num_words_pushed_reg[0] - = MAC_GRP_0_TX_QUEUE_NUM_WORDS_PUSHED_REG; - nf2addr->tx_q_num_bytes_pushed_reg[0] - = MAC_GRP_0_TX_QUEUE_NUM_BYTES_PUSHED_REG; - nf2addr->tx_q_num_pkts_enqueued_reg[0] - = MAC_GRP_0_TX_QUEUE_NUM_PKTS_ENQUEUED_REG; - - nf2addr->rx_q_num_pkts_stored_reg[1] - = MAC_GRP_1_RX_QUEUE_NUM_PKTS_STORED_REG; - nf2addr->rx_q_num_pkts_dropped_full_reg[1] - = MAC_GRP_1_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG; - nf2addr->rx_q_num_pkts_dropped_bad_reg[1] - = MAC_GRP_1_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG; - nf2addr->rx_q_num_words_pushed_reg[1] - = MAC_GRP_1_RX_QUEUE_NUM_WORDS_PUSHED_REG; - nf2addr->rx_q_num_bytes_pushed_reg[1] - = MAC_GRP_1_RX_QUEUE_NUM_BYTES_PUSHED_REG; - nf2addr->rx_q_num_pkts_dequeued_reg[1] - = MAC_GRP_1_RX_QUEUE_NUM_PKTS_DEQUEUED_REG; - nf2addr->rx_q_num_pkts_in_queue_reg[1] - = MAC_GRP_1_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG; - nf2addr->tx_q_num_pkts_in_queue_reg[1] - = MAC_GRP_1_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG; - nf2addr->tx_q_num_pkts_sent_reg[1] - = MAC_GRP_1_TX_QUEUE_NUM_PKTS_SENT_REG; - nf2addr->tx_q_num_words_pushed_reg[1] - = MAC_GRP_1_TX_QUEUE_NUM_WORDS_PUSHED_REG; - nf2addr->tx_q_num_bytes_pushed_reg[1] - = MAC_GRP_1_TX_QUEUE_NUM_BYTES_PUSHED_REG; - nf2addr->tx_q_num_pkts_enqueued_reg[1] - = MAC_GRP_1_TX_QUEUE_NUM_PKTS_ENQUEUED_REG; - - nf2addr->rx_q_num_pkts_stored_reg[2] - = MAC_GRP_2_RX_QUEUE_NUM_PKTS_STORED_REG; - nf2addr->rx_q_num_pkts_dropped_full_reg[2] - = MAC_GRP_2_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG; - nf2addr->rx_q_num_pkts_dropped_bad_reg[2] - = MAC_GRP_2_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG; - nf2addr->rx_q_num_words_pushed_reg[2] - = MAC_GRP_2_RX_QUEUE_NUM_WORDS_PUSHED_REG; - nf2addr->rx_q_num_bytes_pushed_reg[2] - = MAC_GRP_2_RX_QUEUE_NUM_BYTES_PUSHED_REG; - nf2addr->rx_q_num_pkts_dequeued_reg[2] - = MAC_GRP_2_RX_QUEUE_NUM_PKTS_DEQUEUED_REG; - nf2addr->rx_q_num_pkts_in_queue_reg[2] - = MAC_GRP_2_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG; - nf2addr->tx_q_num_pkts_in_queue_reg[2] - = MAC_GRP_2_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG; - nf2addr->tx_q_num_pkts_sent_reg[2] - = MAC_GRP_2_TX_QUEUE_NUM_PKTS_SENT_REG; - nf2addr->tx_q_num_words_pushed_reg[2] - = MAC_GRP_2_TX_QUEUE_NUM_WORDS_PUSHED_REG; - nf2addr->tx_q_num_bytes_pushed_reg[2] - = MAC_GRP_2_TX_QUEUE_NUM_BYTES_PUSHED_REG; - nf2addr->tx_q_num_pkts_enqueued_reg[2] - = MAC_GRP_2_TX_QUEUE_NUM_PKTS_ENQUEUED_REG; - - nf2addr->rx_q_num_pkts_stored_reg[3] - = MAC_GRP_3_RX_QUEUE_NUM_PKTS_STORED_REG; - nf2addr->rx_q_num_pkts_dropped_full_reg[3] - = MAC_GRP_3_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG; - nf2addr->rx_q_num_pkts_dropped_bad_reg[3] - = MAC_GRP_3_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG; - nf2addr->rx_q_num_words_pushed_reg[3] - = MAC_GRP_3_RX_QUEUE_NUM_WORDS_PUSHED_REG; - nf2addr->rx_q_num_bytes_pushed_reg[3] - = MAC_GRP_3_RX_QUEUE_NUM_BYTES_PUSHED_REG; - nf2addr->rx_q_num_pkts_dequeued_reg[3] - = MAC_GRP_3_RX_QUEUE_NUM_PKTS_DEQUEUED_REG; - nf2addr->rx_q_num_pkts_in_queue_reg[3] - = MAC_GRP_3_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG; - nf2addr->tx_q_num_pkts_in_queue_reg[3] - = MAC_GRP_3_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG; - nf2addr->tx_q_num_pkts_sent_reg[3] - = MAC_GRP_3_TX_QUEUE_NUM_PKTS_SENT_REG; - nf2addr->tx_q_num_words_pushed_reg[3] - = MAC_GRP_3_TX_QUEUE_NUM_WORDS_PUSHED_REG; - nf2addr->tx_q_num_bytes_pushed_reg[3] - = MAC_GRP_3_TX_QUEUE_NUM_BYTES_PUSHED_REG; - nf2addr->tx_q_num_pkts_enqueued_reg[3] - = MAC_GRP_3_TX_QUEUE_NUM_PKTS_ENQUEUED_REG; - - return nf2addr; -} - -struct nf2_all_ports_info * -nf2_get_all_ports_info(struct net_device *dev) -{ - struct nf2_all_ports_info *nf2portinfo; - struct nf2_all_ports_info_addr *nf2addr; - int i; - - nf2portinfo = kzalloc(sizeof(struct nf2_all_ports_info), GFP_KERNEL); - if (nf2portinfo == NULL) - return NULL; - nf2addr = nf2_get_all_ports_info_addr(); - if (nf2addr == NULL) - return NULL; - - for (i = 0; i < NF2_PORT_NUM; i++) { - nf2k_reg_read(dev, nf2addr->rx_q_num_pkts_stored_reg[i], - &(nf2portinfo->port[i].rx_q_num_pkts_stored)); - nf2k_reg_read(dev, nf2addr->rx_q_num_pkts_dropped_full_reg[i], - &(nf2portinfo - ->port[i].rx_q_num_pkts_dropped_full)); - nf2k_reg_read(dev, nf2addr->rx_q_num_pkts_dropped_bad_reg[i], - &(nf2portinfo - ->port[i].rx_q_num_pkts_dropped_bad)); - nf2k_reg_read(dev, nf2addr->rx_q_num_words_pushed_reg[i], - &(nf2portinfo->port[i].rx_q_num_words_pushed)); - nf2k_reg_read(dev, nf2addr->rx_q_num_bytes_pushed_reg[i], - &(nf2portinfo->port[i].rx_q_num_bytes_pushed)); - nf2k_reg_read(dev, nf2addr->rx_q_num_pkts_dequeued_reg[i], - &(nf2portinfo->port[i].rx_q_num_pkts_dequeued)); - nf2k_reg_read(dev, nf2addr->rx_q_num_pkts_in_queue_reg[i], - &(nf2portinfo->port[i].rx_q_num_pkts_in_queue)); - nf2k_reg_read(dev, nf2addr->tx_q_num_pkts_in_queue_reg[i], - &(nf2portinfo->port[i].tx_q_num_pkts_in_queue)); - nf2k_reg_read(dev, nf2addr->tx_q_num_pkts_sent_reg[i], - &(nf2portinfo->port[i].tx_q_num_pkts_sent)); - nf2k_reg_read(dev, nf2addr->tx_q_num_words_pushed_reg[i], - &(nf2portinfo->port[i].tx_q_num_words_pushed)); - nf2k_reg_read(dev, nf2addr->tx_q_num_bytes_pushed_reg[i], - &(nf2portinfo->port[i].tx_q_num_bytes_pushed)); - nf2k_reg_read(dev, nf2addr->tx_q_num_pkts_enqueued_reg[i], - &(nf2portinfo->port[i].tx_q_num_pkts_enqueued)); - } - return nf2portinfo; -} diff --git a/openflow/datapath/hwtable_nf2/nf2_openflow.h b/openflow/datapath/hwtable_nf2/nf2_openflow.h deleted file mode 100644 index 2be4b651..00000000 --- a/openflow/datapath/hwtable_nf2/nf2_openflow.h +++ /dev/null @@ -1,169 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#ifndef HATABLE_NF2_NF2_OPENFLOW_H_ -#define HATABLE_NF2_NF2_OPENFLOW_H_ - -#define OPENFLOW_NF2_EXACT_TABLE_SIZE 32768 -#define WATCHDOG_ENABLE 1 -#define WATCHDOG_DISABLE 0 - -#pragma pack(push) /* push current alignment to stack */ -#pragma pack(1) /* set alignment to 1 byte boundary */ - -#define NF2_OF_ENTRY_WORD_LEN 8 -struct nf2_of_entry { - uint16_t transp_dst; - uint16_t transp_src; - uint8_t ip_proto; - uint32_t ip_dst; - uint32_t ip_src; - uint16_t eth_type; - uint8_t eth_dst[6]; - uint8_t eth_src[6]; - uint8_t src_port; - uint16_t vlan_id; - uint16_t pad; -}; - -typedef union nf2_of_entry_wrap { - struct nf2_of_entry entry; - uint32_t raw[NF2_OF_ENTRY_WORD_LEN]; -} nf2_of_entry_wrap; - -typedef nf2_of_entry_wrap nf2_of_mask_wrap; -#define NF2_OF_MASK_WORD_LEN 8 - -struct nf2_of_action { - uint16_t forward_bitmask; - uint16_t nf2_action_flag; - uint16_t vlan_id; - uint8_t vlan_pcp; - uint8_t eth_src[6]; - uint8_t eth_dst[6]; - uint32_t ip_src; - uint32_t ip_dst; - uint16_t transp_src; - uint16_t transp_dst; - uint8_t reserved[19]; -}; - -#define NF2_OF_ACTION_WORD_LEN 10 -typedef union nf2_of_action_wrap { - struct nf2_of_action action; - uint32_t raw[10]; -} nf2_of_action_wrap; - -struct nf2_of_exact_counters { - uint32_t pkt_count:25; - uint8_t last_seen:7; - uint32_t byte_count; -}; - -#define NF2_OF_EXACT_COUNTERS_WORD_LEN 2 -typedef union nf2_of_exact_counters_wrap { - struct nf2_of_exact_counters counters; - uint32_t raw[NF2_OF_EXACT_COUNTERS_WORD_LEN]; -} nf2_of_exact_counters_wrap; - -#define DEVICE_STR_LEN 100 -struct nf2_device_info { - uint32_t nf2_device_id; - uint32_t nf2_device_rev; - char nf2_device_str[DEVICE_STR_LEN]; -}; - -#define NF2_PORT_NUM 4 -struct nf2_all_ports_info_addr { - unsigned int rx_q_num_pkts_stored_reg[NF2_PORT_NUM]; - unsigned int rx_q_num_pkts_dropped_full_reg[NF2_PORT_NUM]; - unsigned int rx_q_num_pkts_dropped_bad_reg[NF2_PORT_NUM]; - unsigned int rx_q_num_words_pushed_reg[NF2_PORT_NUM]; - unsigned int rx_q_num_bytes_pushed_reg[NF2_PORT_NUM]; - unsigned int rx_q_num_pkts_dequeued_reg[NF2_PORT_NUM]; - unsigned int rx_q_num_pkts_in_queue_reg[NF2_PORT_NUM]; - unsigned int tx_q_num_pkts_in_queue_reg[NF2_PORT_NUM]; - unsigned int tx_q_num_pkts_sent_reg[NF2_PORT_NUM]; - unsigned int tx_q_num_words_pushed_reg[NF2_PORT_NUM]; - unsigned int tx_q_num_bytes_pushed_reg[NF2_PORT_NUM]; - unsigned int tx_q_num_pkts_enqueued_reg[NF2_PORT_NUM]; -}; - -struct nf2_port_info { - uint32_t rx_q_num_pkts_stored; - uint32_t rx_q_num_pkts_dropped_full; - uint32_t rx_q_num_pkts_dropped_bad; - uint32_t rx_q_num_words_pushed; - uint32_t rx_q_num_bytes_pushed; - uint32_t rx_q_num_pkts_dequeued; - uint32_t rx_q_num_pkts_in_queue; - uint32_t tx_q_num_pkts_in_queue; - uint32_t tx_q_num_pkts_sent; - uint32_t tx_q_num_words_pushed; - uint32_t tx_q_num_bytes_pushed; - uint32_t tx_q_num_pkts_enqueued; -}; - -struct nf2_all_ports_info { - struct nf2_port_info port[NF2_PORT_NUM]; -}; - -struct nf2_match_info { - uint32_t wildcard_misses; - uint32_t wildcard_hits; - uint32_t exact_misses; - uint32_t exact_hits; -}; - -#pragma pack(pop) /* XXX: Restore original alignment from stack */ - -void nf2_reset_card(struct net_device *); -void nf2_clear_watchdog(struct net_device *); -int nf2_write_of_wildcard(struct net_device *, int, nf2_of_entry_wrap *, - nf2_of_mask_wrap *, nf2_of_action_wrap *); -int nf2_write_of_exact(struct net_device *, int, nf2_of_entry_wrap *, - nf2_of_action_wrap *); -int nf2_modify_write_of_wildcard(struct net_device *, int, nf2_of_entry_wrap *, - nf2_of_mask_wrap *, nf2_of_action_wrap *); -int nf2_modify_write_of_exact(struct net_device *, int, nf2_of_action_wrap *); -unsigned int nf2_get_exact_packet_count(struct net_device *, int); -unsigned int nf2_get_exact_byte_count(struct net_device *, int); -unsigned int nf2_get_wildcard_packet_count(struct net_device *, int); -unsigned int nf2_get_wildcard_byte_count(struct net_device *, int); -unsigned long int nf2_get_matched_count(struct net_device *); -unsigned long int nf2_get_missed_count(struct net_device *); -struct nf2_device_info *nf2_get_device_info(struct net_device *); -struct nf2_match_info *nf2_get_match_info(struct net_device *); -unsigned int nf2_get_watchdog_info(struct net_device *); -struct nf2_all_ports_info *nf2_get_all_ports_info(struct net_device *); - -#endif diff --git a/openflow/datapath/hwtable_nf2/nf2_procfs.c b/openflow/datapath/hwtable_nf2/nf2_procfs.c deleted file mode 100644 index 0324afcb..00000000 --- a/openflow/datapath/hwtable_nf2/nf2_procfs.c +++ /dev/null @@ -1,240 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "chain.h" -#include "table.h" -#include "flow.h" -#include "datapath.h" - -#include "hwtable_nf2/nf2_reg.h" -#include "hwtable_nf2/nf2_flowtable.h" -#include "hwtable_nf2/nf2_openflow.h" -#include "hwtable_nf2/nf2_lib.h" -#include "hwtable_nf2/nf2_procfs.h" - -#define NF2_PROCFS_NAME "net/openflow-netfpga" -#define CLK_CYCLE 8 - -static struct semaphore proc_sem; - -static int disp_dev_info(char *); -static int disp_port_info(char *); -static int disp_match_info(char *); -static int disp_watchdog_info(char *); -static int proc_read(char *, char **, off_t, int, int *, void *); - -static int -disp_dev_info(char *page) -{ - struct net_device *netdev; - struct nf2_device_info *nf2devinfo; - int len = 0; - - netdev = nf2_get_net_device(); - if (netdev == NULL) - return 0; - nf2devinfo = nf2_get_device_info(netdev); - if (nf2devinfo == NULL) { - nf2_free_net_device(netdev); - return 0; - } - nf2_free_net_device(netdev); - - len += sprintf(page + len, - "NetFPGA: " - "design name: %s, device ID: %d, device revision: %d\n", - nf2devinfo->nf2_device_str, - nf2devinfo->nf2_device_id, nf2devinfo->nf2_device_rev); - len += sprintf(page + len, "\n"); - - return len; -} - -static int -disp_port_info(char *page) -{ - struct net_device *netdev; - struct nf2_all_ports_info *nf2portinfo; - int len = 0; - int i; - - netdev = nf2_get_net_device(); - if (netdev == NULL) - return 0; - nf2portinfo = nf2_get_all_ports_info(netdev); - if (nf2portinfo == NULL) { - nf2_free_net_device(netdev); - return 0; - } - nf2_free_net_device(netdev); - - for (i = 0; i < NF2_PORT_NUM; i++) { - len += sprintf(page + len, "Interface nf2c%d\n", i); - len += sprintf(page + len, - " Input queue: %u/%u (current/queued)\n", - nf2portinfo->port[i].rx_q_num_pkts_in_queue, - nf2portinfo->port[i].rx_q_num_pkts_dequeued); - len += sprintf(page + len, - " %u packets input, %u dropped " - "(%u buffer exhausted, %u bad packets)\n" - " %u pushed words, %u pushed bytes\n", - nf2portinfo->port[i].rx_q_num_pkts_stored, - nf2portinfo->port[i].rx_q_num_pkts_dropped_full - + nf2portinfo->port[i].rx_q_num_pkts_dropped_bad, - nf2portinfo->port[i].rx_q_num_pkts_dropped_full, - nf2portinfo->port[i].rx_q_num_pkts_dropped_bad, - nf2portinfo->port[i].rx_q_num_words_pushed, - nf2portinfo->port[i].rx_q_num_bytes_pushed); - len += sprintf(page + len, - " Output queue: %u/%u (current/queued)\n", - nf2portinfo->port[i].tx_q_num_pkts_in_queue, - nf2portinfo->port[i].tx_q_num_pkts_enqueued); - len += sprintf(page + len, - " %u packets output, " - "%u pushed words, %u pushed bytes\n", - nf2portinfo->port[i].tx_q_num_pkts_sent, - nf2portinfo->port[i].tx_q_num_words_pushed, - nf2portinfo->port[i].tx_q_num_bytes_pushed); - } - len += sprintf(page + len, "\n"); - - return len; -} - -static int -disp_match_info(char *page) -{ - struct net_device *netdev; - struct nf2_match_info *nf2matchinfo; - int len = 0; - - netdev = nf2_get_net_device(); - if (netdev == NULL) - return 0; - nf2matchinfo = nf2_get_match_info(netdev); - if (nf2matchinfo == NULL) { - nf2_free_net_device(netdev); - return 0; - } - nf2_free_net_device(netdev); - - len += sprintf(page + len, - "WILDCARD match table lookup: %u/%u (hits/misses)\n", - nf2matchinfo->wildcard_hits, - nf2matchinfo->wildcard_misses); - len += sprintf(page + len, - "EXACT match table lookup: %u/%u (hits/misses)\n", - nf2matchinfo->exact_hits, nf2matchinfo->exact_misses); - len += sprintf(page + len, "\n"); - - return len; -} - -static int -disp_watchdog_info(char *page) -{ - struct net_device *netdev; - unsigned int nf2wdtinfo; - unsigned int elapsed_time; - int len = 0; - -#ifndef NF2_WATCHDOG - return 0; -#endif - - netdev = nf2_get_net_device(); - if (netdev == NULL) - return 0; - nf2wdtinfo = nf2_get_watchdog_info(netdev); - nf2_free_net_device(netdev); - - elapsed_time = nf2wdtinfo * CLK_CYCLE / 1000000; - - len += sprintf(page + len, - "%u (msec) passed since the watchdog counter has been cleared last time\n", - elapsed_time); - len += sprintf(page + len, "\n"); - - return len; -} - -static int -proc_read(char *page, char **start, off_t offset, int count, int *eof, - void *data) -{ - int len = 0; - int buf_pos = 1; - - if (down_interruptible(&proc_sem)) - return -ERESTARTSYS; - - if (buf_pos != 0) { - len += disp_dev_info(page + len); - len += disp_port_info(page + len); - len += disp_match_info(page + len); - len += disp_watchdog_info(page + len); - buf_pos = 0; - } - up(&proc_sem); - - *eof = 1; - return len; -} - -void -nf2_create_procfs(void) -{ - struct proc_dir_entry *entry; - - entry = create_proc_entry(NF2_PROCFS_NAME, - S_IFREG | S_IRUGO | S_IWUGO, NULL); - if (entry == NULL) - return; - - entry->read_proc = proc_read; - sema_init(&proc_sem, 1); -} - -void -nf2_remove_procfs(void) -{ - remove_proc_entry(NF2_PROCFS_NAME, NULL); -} diff --git a/openflow/datapath/hwtable_nf2/nf2_procfs.h b/openflow/datapath/hwtable_nf2/nf2_procfs.h deleted file mode 100644 index 011f680f..00000000 --- a/openflow/datapath/hwtable_nf2/nf2_procfs.h +++ /dev/null @@ -1,39 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#ifndef HWTABLE_NF2_NF2_PROCFS_ -#define HWTABLE_NF2_NF2_PROCFS_ - -void nf2_create_procfs(void); -void nf2_remove_procfs(void); - -#endif diff --git a/openflow/datapath/hwtable_nf2/nf2_reg.h b/openflow/datapath/hwtable_nf2/nf2_reg.h deleted file mode 100644 index 0056f882..00000000 --- a/openflow/datapath/hwtable_nf2/nf2_reg.h +++ /dev/null @@ -1,767 +0,0 @@ -/******************************************************** -* -* C register defines file for openflow_switch -* -********************************************************/ - -#ifndef _REG_DEFINES_ -#define _REG_DEFINES_ - -/* ========= Constants ========= */ - -// ===== File: lib/verilog/core/common/xml/global.xml ===== - -// Maximum number of phy ports -#define MAX_PHY_PORTS 4 - -// PCI address bus width -#define PCI_ADDR_WIDTH 32 - -// PCI data bus width -#define PCI_DATA_WIDTH 32 - -// PCI byte enable bus width -#define PCI_BE_WIDTH 4 - -// CPCI--CNET address bus width. This is byte addresses even though bottom bits are zero. -#define CPCI_CNET_ADDR_WIDTH 27 - -// CPCI--CNET data bus width -#define CPCI_CNET_DATA_WIDTH 32 - -// CPCI--NF2 address bus width. This is byte addresses even though bottom bits are zero. -#define CPCI_NF2_ADDR_WIDTH 27 - -// CPCI--NF2 data bus width -#define CPCI_NF2_DATA_WIDTH 32 - -// DMA data bus width -#define DMA_DATA_WIDTH 32 - -// DMA control bus width -#define DMA_CTRL_WIDTH 4 - -// CPCI debug bus width -#define CPCI_DEBUG_DATA_WIDTH 29 - -// SRAM address width -#define SRAM_ADDR_WIDTH 19 - -// SRAM data width -#define SRAM_DATA_WIDTH 36 - -// DRAM address width -#define DRAM_ADDR_WIDTH 24 - -// ===== File: lib/verilog/core/common/xml/nf_defines.xml ===== - -// Clock period of 125 MHz clock in ns -#define FAST_CLK_PERIOD 8 - -// Clock period of 62.5 MHz clock in ns -#define SLOW_CLK_PERIOD 16 - -// Header value used by the IO queues -#define IO_QUEUE_STAGE_NUM 0xff - -// Data path data width -#define DATA_WIDTH 64 - -// Data path control width -#define CTRL_WIDTH 8 - -// ===== File: projects/openflow_switch/include/output_port_lookup.xml ===== - -#define FAST_CLOCK_PERIOD 8 - -// ===== File: projects/openflow_switch/include/vlan_remover.xml ===== - -#define VLAN_CTRL_WORD 0x42 - -#define VLAN_ETHERTYPE 0x8100 - -// ===== File: lib/verilog/core/output_queues/bram_output_queues/xml/bram_output_queues.xml ===== - -#define NUM_OUTPUT_QUEUES 8 - -// ===== File: projects/openflow_switch/include/opl_processor.xml ===== - -#define NF2_OFPAT_OUTPUT 0x0001 - -#define NF2_OFPAT_SET_VLAN_VID 0x0002 - -#define NF2_OFPAT_SET_VLAN_PCP 0x0004 - -#define NF2_OFPAT_STRIP_VLAN 0x0008 - -#define NF2_OFPAT_SET_DL_SRC 0x0010 - -#define NF2_OFPAT_SET_DL_DST 0x0020 - -#define NF2_OFPAT_SET_NW_SRC 0x0040 - -#define NF2_OFPAT_SET_NW_DST 0x0080 - -#define NF2_OFPAT_SET_TP_SRC 0x0100 - -#define NF2_OFPAT_SET_TP_DST 0x0200 - -// ===== File: projects/openflow_switch/include/wildcard_match.xml ===== - -#define OPENFLOW_WILDCARD_TABLE_SIZE 32 - -#define OPENFLOW_WILDCARD_NUM_DATA_WORDS_USED 10 - -#define OPENFLOW_WILDCARD_NUM_CMP_WORDS_USED 8 - -// ===== File: lib/verilog/core/utils/xml/device_id_reg.xml ===== - -// Total number of registers -#define DEV_ID_NUM_REGS 32 - -// Number of non string registers -#define DEV_ID_NON_DEV_STR_REGS 7 - -// Device description length (in words, not chars) -#define DEV_ID_DEV_STR_WORD_LEN 25 - -// Device description length (in bytes/chars) -#define DEV_ID_DEV_STR_BYTE_LEN 100 - -// Device description length (in bits) -#define DEV_ID_DEV_STR_BIT_LEN 800 - -// Length of MD5 sum (bits) -#define DEV_ID_MD5SUM_LENGTH 128 - -// MD5 sum of the string "device_id.v" -#define DEV_ID_MD5_VALUE 0x4071736d8a603d2b4d55f62989a73c95 -#define DEV_ID_MD5_VALUE_0 0x4071736d -#define DEV_ID_MD5_VALUE_1 0x8a603d2b -#define DEV_ID_MD5_VALUE_2 0x4d55f629 -#define DEV_ID_MD5_VALUE_3 0x89a73c95 - -// ===== File: projects/openflow_switch/include/header_parser.xml ===== - -#define ETH_TYPE_IP 0x0800 - -#define IP_PROTO_TCP 0x06 - -#define IP_PROTO_UDP 0x11 - -#define IP_PROTO_ICMP 0x01 - -// ===== File: projects/openflow_switch/include/watchdog.xml ===== - -#define WDT_CPCI_REG_CTRL 0x00000008 - -// ===== File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml ===== - -// TX queue disable bit -#define MAC_GRP_TX_QUEUE_DISABLE_BIT_NUM 0 - -// RX queue disable bit -#define MAC_GRP_RX_QUEUE_DISABLE_BIT_NUM 1 - -// Reset MAC bit -#define MAC_GRP_RESET_MAC_BIT_NUM 2 - -// MAC TX queue disable bit -#define MAC_GRP_MAC_DISABLE_TX_BIT_NUM 3 - -// MAC RX queue disable bit -#define MAC_GRP_MAC_DISABLE_RX_BIT_NUM 4 - -// MAC disable jumbo TX bit -#define MAC_GRP_MAC_DIS_JUMBO_TX_BIT_NUM 5 - -// MAC disable jumbo RX bit -#define MAC_GRP_MAC_DIS_JUMBO_RX_BIT_NUM 6 - -// MAC disable crc check disable bit -#define MAC_GRP_MAC_DIS_CRC_CHECK_BIT_NUM 7 - -// MAC disable crc generate bit -#define MAC_GRP_MAC_DIS_CRC_GEN_BIT_NUM 8 - -// ===== File: projects/openflow_switch/include/match_arbiter.xml ===== - -#define OPENFLOW_ENTRY_TRANSP_DST_WIDTH 16 - -#define OPENFLOW_ENTRY_TRANSP_DST_POS 0 - -#define OPENFLOW_ENTRY_TRANSP_SRC_WIDTH 16 - -#define OPENFLOW_ENTRY_TRANSP_SRC_POS 16 - -#define OPENFLOW_ENTRY_IP_PROTO_WIDTH 8 - -#define OPENFLOW_ENTRY_IP_PROTO_POS 32 - -#define OPENFLOW_ENTRY_IP_DST_WIDTH 32 - -#define OPENFLOW_ENTRY_IP_DST_POS 40 - -#define OPENFLOW_ENTRY_IP_SRC_WIDTH 32 - -#define OPENFLOW_ENTRY_IP_SRC_POS 72 - -#define OPENFLOW_ENTRY_ETH_TYPE_WIDTH 16 - -#define OPENFLOW_ENTRY_ETH_TYPE_POS 104 - -#define OPENFLOW_ENTRY_ETH_DST_WIDTH 48 - -#define OPENFLOW_ENTRY_ETH_DST_POS 120 - -#define OPENFLOW_ENTRY_ETH_SRC_WIDTH 48 - -#define OPENFLOW_ENTRY_ETH_SRC_POS 168 - -#define OPENFLOW_ENTRY_SRC_PORT_WIDTH 8 - -#define OPENFLOW_ENTRY_SRC_PORT_POS 216 - -#define OPENFLOW_ENTRY_VLAN_ID_WIDTH 16 - -#define OPENFLOW_ENTRY_VLAN_ID_POS 224 - -#define OPENFLOW_ENTRY_WIDTH 240 - -// The actionfield is composed of a bitmask specifying actions to take and arguments. -#define OPENFLOW_ACTION_WIDTH 320 - -// Ports to forward on -#define OPENFLOW_FORWARD_BITMASK_WIDTH 16 - -#define OPENFLOW_FORWARD_BITMASK_POS 0 - -#define OPENFLOW_NF2_ACTION_FLAG_WIDTH 16 - -#define OPENFLOW_NF2_ACTION_FLAG_POS 16 - -// Vlan ID to be replaced -#define OPENFLOW_SET_VLAN_VID_WIDTH 16 - -#define OPENFLOW_SET_VLAN_VID_POS 32 - -// Vlan priority to be replaced -#define OPENFLOW_SET_VLAN_PCP_WIDTH 8 - -#define OPENFLOW_SET_VLAN_PCP_POS 48 - -// Source MAC address to be replaced -#define OPENFLOW_SET_DL_SRC_WIDTH 48 - -#define OPENFLOW_SET_DL_SRC_POS 56 - -// Destination MAC address to be replaced -#define OPENFLOW_SET_DL_DST_WIDTH 48 - -#define OPENFLOW_SET_DL_DST_POS 104 - -// Source network address to be replaced -#define OPENFLOW_SET_NW_SRC_WIDTH 32 - -#define OPENFLOW_SET_NW_SRC_POS 152 - -// Destination network address to be replaced -#define OPENFLOW_SET_NW_DST_WIDTH 32 - -#define OPENFLOW_SET_NW_DST_POS 184 - -// Source transport port to be replaced -#define OPENFLOW_SET_TP_SRC_WIDTH 16 - -#define OPENFLOW_SET_TP_SRC_POS 216 - -// Destination transport port to be replaced -#define OPENFLOW_SET_TP_DST_WIDTH 16 - -#define OPENFLOW_SET_TP_DST_POS 232 - -// ===== File: projects/openflow_switch/include/exact_match.xml ===== - -#define OPENFLOW_EXACT_ENTRY_PKT_COUNTER_WIDTH 25 - -#define OPENFLOW_EXACT_ENTRY_PKT_COUNTER_POS 0 - -#define OPENFLOW_EXACT_ENTRY_LAST_SEEN_WIDTH 7 - -#define OPENFLOW_EXACT_ENTRY_LAST_SEEN_POS 25 - -#define OPENFLOW_EXACT_ENTRY_BYTE_COUNTER_WIDTH 32 - -#define OPENFLOW_EXACT_ENTRY_BYTE_COUNTER_POS 32 - -#define OPENFLOW_EXACT_ENTRY_HDR_BASE_POS 0x00000000 - -#define OPENFLOW_EXACT_ENTRY_COUNTERS_POS 0x00000008 - -#define OPENFLOW_EXACT_ENTRY_ACTION_BASE_POS 0x0000000a - -// ------------------------------------- -// Modules -// ------------------------------------- - -// Module tags -#define CORE_BASE_ADDR 0x0000000 -#define DEV_ID_BASE_ADDR 0x0400000 -#define MDIO_BASE_ADDR 0x0440000 -#define DMA_BASE_ADDR 0x0500000 -#define MAC_GRP_0_BASE_ADDR 0x0600000 -#define MAC_GRP_1_BASE_ADDR 0x0640000 -#define MAC_GRP_2_BASE_ADDR 0x0680000 -#define MAC_GRP_3_BASE_ADDR 0x06c0000 -#define CPU_QUEUE_0_BASE_ADDR 0x0700000 -#define CPU_QUEUE_1_BASE_ADDR 0x0740000 -#define CPU_QUEUE_2_BASE_ADDR 0x0780000 -#define CPU_QUEUE_3_BASE_ADDR 0x07c0000 -#define SRAM_BASE_ADDR 0x1000000 -#define UDP_BASE_ADDR 0x2000000 -#define OPENFLOW_LOOKUP_BASE_ADDR 0x2000000 -#define IN_ARB_BASE_ADDR 0x2000100 -#define VLAN_REMOVER_BASE_ADDR 0x2000200 -#define OPL_PROCESSOR_BASE_ADDR 0x2000240 -#define HEADER_PARSER_BASE_ADDR 0x2000280 -#define MATCH_ARBITER_BASE_ADDR 0x20002c0 -#define BRAM_OQ_BASE_ADDR 0x2000300 -#define WDT_BASE_ADDR 0x2000400 -#define EXACT_MATCH_BASE_ADDR 0x2000500 -#define OPENFLOW_WILDCARD_LOOKUP_BASE_ADDR 0x2001000 -#define DRAM_BASE_ADDR 0x4000000 - -#define CPU_QUEUE_OFFSET 0x0040000 -#define MAC_GRP_OFFSET 0x0040000 - -/* ========== Registers ========== */ - -// Name: device_id (DEV_ID) -// Description: Device identification -// File: lib/verilog/core/utils/xml/device_id_reg.xml -#define DEV_ID_MD5_0_REG 0x0400000 -#define DEV_ID_MD5_1_REG 0x0400004 -#define DEV_ID_MD5_2_REG 0x0400008 -#define DEV_ID_MD5_3_REG 0x040000c -#define DEV_ID_DEVICE_ID_REG 0x0400010 -#define DEV_ID_REVISION_REG 0x0400014 -#define DEV_ID_CPCI_ID_REG 0x0400018 -#define DEV_ID_DEV_STR_0_REG 0x040001c -#define DEV_ID_DEV_STR_1_REG 0x0400020 -#define DEV_ID_DEV_STR_2_REG 0x0400024 -#define DEV_ID_DEV_STR_3_REG 0x0400028 -#define DEV_ID_DEV_STR_4_REG 0x040002c -#define DEV_ID_DEV_STR_5_REG 0x0400030 -#define DEV_ID_DEV_STR_6_REG 0x0400034 -#define DEV_ID_DEV_STR_7_REG 0x0400038 -#define DEV_ID_DEV_STR_8_REG 0x040003c -#define DEV_ID_DEV_STR_9_REG 0x0400040 -#define DEV_ID_DEV_STR_10_REG 0x0400044 -#define DEV_ID_DEV_STR_11_REG 0x0400048 -#define DEV_ID_DEV_STR_12_REG 0x040004c -#define DEV_ID_DEV_STR_13_REG 0x0400050 -#define DEV_ID_DEV_STR_14_REG 0x0400054 -#define DEV_ID_DEV_STR_15_REG 0x0400058 -#define DEV_ID_DEV_STR_16_REG 0x040005c -#define DEV_ID_DEV_STR_17_REG 0x0400060 -#define DEV_ID_DEV_STR_18_REG 0x0400064 -#define DEV_ID_DEV_STR_19_REG 0x0400068 -#define DEV_ID_DEV_STR_20_REG 0x040006c -#define DEV_ID_DEV_STR_21_REG 0x0400070 -#define DEV_ID_DEV_STR_22_REG 0x0400074 -#define DEV_ID_DEV_STR_23_REG 0x0400078 -#define DEV_ID_DEV_STR_24_REG 0x040007c - -// Name: mdio (MDIO) -// Description: MDIO interface -// File: lib/verilog/core/io/mdio/xml/mdio.xml -#define MDIO_PHY_0_CONTROL_REG 0x0440000 -#define MDIO_PHY_0_STATUS_REG 0x0440004 -#define MDIO_PHY_0_PHY_ID_0_REG 0x0440008 -#define MDIO_PHY_0_PHY_ID_1_REG 0x044000c -#define MDIO_PHY_0_AUTONEGOTIATION_ADVERT_REG 0x0440010 -#define MDIO_PHY_0_AUTONEG_LINK_PARTNER_BASE_PAGE_ABILITY_REG 0x0440014 -#define MDIO_PHY_0_AUTONEG_EXPANSION_REG 0x0440018 -#define MDIO_PHY_0_AUTONEG_NEXT_PAGE_TX_REG 0x044001c -#define MDIO_PHY_0_AUTONEG_LINK_PARTNER_RCVD_NEXT_PAGE_REG 0x0440020 -#define MDIO_PHY_0_MASTER_SLAVE_CTRL_REG 0x0440024 -#define MDIO_PHY_0_MASTER_SLAVE_STATUS_REG 0x0440028 -#define MDIO_PHY_0_PSE_CTRL_REG 0x044002c -#define MDIO_PHY_0_PSE_STATUS_REG 0x0440030 -#define MDIO_PHY_0_MMD_ACCESS_CTRL_REG 0x0440034 -#define MDIO_PHY_0_MMD_ACCESS_STATUS_REG 0x0440038 -#define MDIO_PHY_0_EXTENDED_STATUS_REG 0x044003c -#define MDIO_PHY_1_CONTROL_REG 0x0440080 -#define MDIO_PHY_1_STATUS_REG 0x0440084 -#define MDIO_PHY_1_PHY_ID_0_REG 0x0440088 -#define MDIO_PHY_1_PHY_ID_1_REG 0x044008c -#define MDIO_PHY_1_AUTONEGOTIATION_ADVERT_REG 0x0440090 -#define MDIO_PHY_1_AUTONEG_LINK_PARTNER_BASE_PAGE_ABILITY_REG 0x0440094 -#define MDIO_PHY_1_AUTONEG_EXPANSION_REG 0x0440098 -#define MDIO_PHY_1_AUTONEG_NEXT_PAGE_TX_REG 0x044009c -#define MDIO_PHY_1_AUTONEG_LINK_PARTNER_RCVD_NEXT_PAGE_REG 0x04400a0 -#define MDIO_PHY_1_MASTER_SLAVE_CTRL_REG 0x04400a4 -#define MDIO_PHY_1_MASTER_SLAVE_STATUS_REG 0x04400a8 -#define MDIO_PHY_1_PSE_CTRL_REG 0x04400ac -#define MDIO_PHY_1_PSE_STATUS_REG 0x04400b0 -#define MDIO_PHY_1_MMD_ACCESS_CTRL_REG 0x04400b4 -#define MDIO_PHY_1_MMD_ACCESS_STATUS_REG 0x04400b8 -#define MDIO_PHY_1_EXTENDED_STATUS_REG 0x04400bc -#define MDIO_PHY_2_CONTROL_REG 0x0440100 -#define MDIO_PHY_2_STATUS_REG 0x0440104 -#define MDIO_PHY_2_PHY_ID_0_REG 0x0440108 -#define MDIO_PHY_2_PHY_ID_1_REG 0x044010c -#define MDIO_PHY_2_AUTONEGOTIATION_ADVERT_REG 0x0440110 -#define MDIO_PHY_2_AUTONEG_LINK_PARTNER_BASE_PAGE_ABILITY_REG 0x0440114 -#define MDIO_PHY_2_AUTONEG_EXPANSION_REG 0x0440118 -#define MDIO_PHY_2_AUTONEG_NEXT_PAGE_TX_REG 0x044011c -#define MDIO_PHY_2_AUTONEG_LINK_PARTNER_RCVD_NEXT_PAGE_REG 0x0440120 -#define MDIO_PHY_2_MASTER_SLAVE_CTRL_REG 0x0440124 -#define MDIO_PHY_2_MASTER_SLAVE_STATUS_REG 0x0440128 -#define MDIO_PHY_2_PSE_CTRL_REG 0x044012c -#define MDIO_PHY_2_PSE_STATUS_REG 0x0440130 -#define MDIO_PHY_2_MMD_ACCESS_CTRL_REG 0x0440134 -#define MDIO_PHY_2_MMD_ACCESS_STATUS_REG 0x0440138 -#define MDIO_PHY_2_EXTENDED_STATUS_REG 0x044013c -#define MDIO_PHY_3_CONTROL_REG 0x0440180 -#define MDIO_PHY_3_STATUS_REG 0x0440184 -#define MDIO_PHY_3_PHY_ID_0_REG 0x0440188 -#define MDIO_PHY_3_PHY_ID_1_REG 0x044018c -#define MDIO_PHY_3_AUTONEGOTIATION_ADVERT_REG 0x0440190 -#define MDIO_PHY_3_AUTONEG_LINK_PARTNER_BASE_PAGE_ABILITY_REG 0x0440194 -#define MDIO_PHY_3_AUTONEG_EXPANSION_REG 0x0440198 -#define MDIO_PHY_3_AUTONEG_NEXT_PAGE_TX_REG 0x044019c -#define MDIO_PHY_3_AUTONEG_LINK_PARTNER_RCVD_NEXT_PAGE_REG 0x04401a0 -#define MDIO_PHY_3_MASTER_SLAVE_CTRL_REG 0x04401a4 -#define MDIO_PHY_3_MASTER_SLAVE_STATUS_REG 0x04401a8 -#define MDIO_PHY_3_PSE_CTRL_REG 0x04401ac -#define MDIO_PHY_3_PSE_STATUS_REG 0x04401b0 -#define MDIO_PHY_3_MMD_ACCESS_CTRL_REG 0x04401b4 -#define MDIO_PHY_3_MMD_ACCESS_STATUS_REG 0x04401b8 -#define MDIO_PHY_3_EXTENDED_STATUS_REG 0x04401bc - -#define MDIO_PHY_GROUP_BASE_ADDR 0x0440000 -#define MDIO_PHY_GROUP_INST_OFFSET 0x0000080 - -// Name: dma (DMA) -// Description: DMA transfer module -// File: lib/verilog/core/dma/xml/dma.xml - -// Name: nf2_mac_grp (MAC_GRP_0) -// Description: Ethernet MAC group -// File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml -#define MAC_GRP_0_CONTROL_REG 0x0600000 -#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0600004 -#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_STORED_REG 0x0600008 -#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG 0x060000c -#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG 0x0600010 -#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_DEQUEUED_REG 0x0600014 -#define MAC_GRP_0_RX_QUEUE_NUM_WORDS_PUSHED_REG 0x0600018 -#define MAC_GRP_0_RX_QUEUE_NUM_BYTES_PUSHED_REG 0x060001c -#define MAC_GRP_0_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0600020 -#define MAC_GRP_0_TX_QUEUE_NUM_PKTS_ENQUEUED_REG 0x0600024 -#define MAC_GRP_0_TX_QUEUE_NUM_PKTS_SENT_REG 0x0600028 -#define MAC_GRP_0_TX_QUEUE_NUM_WORDS_PUSHED_REG 0x060002c -#define MAC_GRP_0_TX_QUEUE_NUM_BYTES_PUSHED_REG 0x0600030 - -// Name: nf2_mac_grp (MAC_GRP_1) -// Description: Ethernet MAC group -// File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml -#define MAC_GRP_1_CONTROL_REG 0x0640000 -#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0640004 -#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_STORED_REG 0x0640008 -#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG 0x064000c -#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG 0x0640010 -#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_DEQUEUED_REG 0x0640014 -#define MAC_GRP_1_RX_QUEUE_NUM_WORDS_PUSHED_REG 0x0640018 -#define MAC_GRP_1_RX_QUEUE_NUM_BYTES_PUSHED_REG 0x064001c -#define MAC_GRP_1_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0640020 -#define MAC_GRP_1_TX_QUEUE_NUM_PKTS_ENQUEUED_REG 0x0640024 -#define MAC_GRP_1_TX_QUEUE_NUM_PKTS_SENT_REG 0x0640028 -#define MAC_GRP_1_TX_QUEUE_NUM_WORDS_PUSHED_REG 0x064002c -#define MAC_GRP_1_TX_QUEUE_NUM_BYTES_PUSHED_REG 0x0640030 - -// Name: nf2_mac_grp (MAC_GRP_2) -// Description: Ethernet MAC group -// File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml -#define MAC_GRP_2_CONTROL_REG 0x0680000 -#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0680004 -#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_STORED_REG 0x0680008 -#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG 0x068000c -#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG 0x0680010 -#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_DEQUEUED_REG 0x0680014 -#define MAC_GRP_2_RX_QUEUE_NUM_WORDS_PUSHED_REG 0x0680018 -#define MAC_GRP_2_RX_QUEUE_NUM_BYTES_PUSHED_REG 0x068001c -#define MAC_GRP_2_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0680020 -#define MAC_GRP_2_TX_QUEUE_NUM_PKTS_ENQUEUED_REG 0x0680024 -#define MAC_GRP_2_TX_QUEUE_NUM_PKTS_SENT_REG 0x0680028 -#define MAC_GRP_2_TX_QUEUE_NUM_WORDS_PUSHED_REG 0x068002c -#define MAC_GRP_2_TX_QUEUE_NUM_BYTES_PUSHED_REG 0x0680030 - -// Name: nf2_mac_grp (MAC_GRP_3) -// Description: Ethernet MAC group -// File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml -#define MAC_GRP_3_CONTROL_REG 0x06c0000 -#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x06c0004 -#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_STORED_REG 0x06c0008 -#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG 0x06c000c -#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG 0x06c0010 -#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_DEQUEUED_REG 0x06c0014 -#define MAC_GRP_3_RX_QUEUE_NUM_WORDS_PUSHED_REG 0x06c0018 -#define MAC_GRP_3_RX_QUEUE_NUM_BYTES_PUSHED_REG 0x06c001c -#define MAC_GRP_3_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x06c0020 -#define MAC_GRP_3_TX_QUEUE_NUM_PKTS_ENQUEUED_REG 0x06c0024 -#define MAC_GRP_3_TX_QUEUE_NUM_PKTS_SENT_REG 0x06c0028 -#define MAC_GRP_3_TX_QUEUE_NUM_WORDS_PUSHED_REG 0x06c002c -#define MAC_GRP_3_TX_QUEUE_NUM_BYTES_PUSHED_REG 0x06c0030 - -// Name: cpu_dma_queue (CPU_QUEUE_0) -// Description: CPU DMA queue -// File: lib/verilog/core/io_queues/cpu_dma_queue/xml/cpu_dma_queue.xml - -// Name: cpu_dma_queue (CPU_QUEUE_1) -// Description: CPU DMA queue -// File: lib/verilog/core/io_queues/cpu_dma_queue/xml/cpu_dma_queue.xml - -// Name: cpu_dma_queue (CPU_QUEUE_2) -// Description: CPU DMA queue -// File: lib/verilog/core/io_queues/cpu_dma_queue/xml/cpu_dma_queue.xml - -// Name: cpu_dma_queue (CPU_QUEUE_3) -// Description: CPU DMA queue -// File: lib/verilog/core/io_queues/cpu_dma_queue/xml/cpu_dma_queue.xml - -// Name: SRAM (SRAM) -// Description: SRAM - -// Name: openflow_output_port_lookup (OPENFLOW_LOOKUP) -// Description: Output Port Lookup for OpenFlow hardware datapath -// File: projects/openflow_switch/include/output_port_lookup.xml -#define OPENFLOW_LOOKUP_WILDCARD_MISSES_REG 0x2000000 -#define OPENFLOW_LOOKUP_WILDCARD_HITS_REG 0x2000004 -#define OPENFLOW_LOOKUP_EXACT_MISSES_REG 0x2000008 -#define OPENFLOW_LOOKUP_EXACT_HITS_REG 0x200000c -#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_0_REG 0x2000010 -#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_1_REG 0x2000014 -#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_2_REG 0x2000018 -#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_3_REG 0x200001c -#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_4_REG 0x2000020 -#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_5_REG 0x2000024 -#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_6_REG 0x2000028 -#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_7_REG 0x200002c -#define OPENFLOW_LOOKUP_DUMY_SOFTWARE_0_REG 0x2000030 -#define OPENFLOW_LOOKUP_DUMY_SOFTWARE_1_REG 0x2000034 -#define OPENFLOW_LOOKUP_TIMER_REG 0x2000038 - -// Name: in_arb (IN_ARB) -// Description: Round-robin input arbiter -// File: lib/verilog/core/input_arbiter/rr_input_arbiter/xml/rr_input_arbiter.xml -#define IN_ARB_NUM_PKTS_SENT_REG 0x2000100 -#define IN_ARB_LAST_PKT_WORD_0_HI_REG 0x2000104 -#define IN_ARB_LAST_PKT_WORD_0_LO_REG 0x2000108 -#define IN_ARB_LAST_PKT_CTRL_0_REG 0x200010c -#define IN_ARB_LAST_PKT_WORD_1_HI_REG 0x2000110 -#define IN_ARB_LAST_PKT_WORD_1_LO_REG 0x2000114 -#define IN_ARB_LAST_PKT_CTRL_1_REG 0x2000118 -#define IN_ARB_STATE_REG 0x200011c - -// Name: vlan_remover (VLAN_REMOVER) -// Description: Remove vlan tag and ethtype if ethtype is vlan, and store them into module header -// File: projects/openflow_switch/include/vlan_remover.xml - -// Name: opl_processor (OPL_PROCESSOR) -// Description: opl_processor -// File: projects/openflow_switch/include/opl_processor.xml - -// Name: header_parser (HEADER_PARSER) -// Description: Chop ether/IP/UDP-TCP header into 11 tuples -// File: projects/openflow_switch/include/header_parser.xml - -// Name: match_arbiter (MATCH_ARBITER) -// Description: Arbitration between exact and wildcard lookups results -// File: projects/openflow_switch/include/match_arbiter.xml - -// Name: bram_output_queues (BRAM_OQ) -// Description: BRAM-based output queues -// File: lib/verilog/core/output_queues/bram_output_queues/xml/bram_output_queues.xml -#define BRAM_OQ_DISABLE_QUEUES_REG 0x2000300 -#define BRAM_OQ_QUEUE_0_NUM_PKT_BYTES_RECEIVED_REG 0x2000380 -#define BRAM_OQ_QUEUE_0_NUM_PKTS_RECEIVED_REG 0x2000384 -#define BRAM_OQ_QUEUE_0_NUM_PKTS_DROPPED_REG 0x2000388 -#define BRAM_OQ_QUEUE_0_NUM_WORDS_IN_QUEUE_REG 0x200038c -#define BRAM_OQ_QUEUE_1_NUM_PKT_BYTES_RECEIVED_REG 0x2000390 -#define BRAM_OQ_QUEUE_1_NUM_PKTS_RECEIVED_REG 0x2000394 -#define BRAM_OQ_QUEUE_1_NUM_PKTS_DROPPED_REG 0x2000398 -#define BRAM_OQ_QUEUE_1_NUM_WORDS_IN_QUEUE_REG 0x200039c -#define BRAM_OQ_QUEUE_2_NUM_PKT_BYTES_RECEIVED_REG 0x20003a0 -#define BRAM_OQ_QUEUE_2_NUM_PKTS_RECEIVED_REG 0x20003a4 -#define BRAM_OQ_QUEUE_2_NUM_PKTS_DROPPED_REG 0x20003a8 -#define BRAM_OQ_QUEUE_2_NUM_WORDS_IN_QUEUE_REG 0x20003ac -#define BRAM_OQ_QUEUE_3_NUM_PKT_BYTES_RECEIVED_REG 0x20003b0 -#define BRAM_OQ_QUEUE_3_NUM_PKTS_RECEIVED_REG 0x20003b4 -#define BRAM_OQ_QUEUE_3_NUM_PKTS_DROPPED_REG 0x20003b8 -#define BRAM_OQ_QUEUE_3_NUM_WORDS_IN_QUEUE_REG 0x20003bc -#define BRAM_OQ_QUEUE_4_NUM_PKT_BYTES_RECEIVED_REG 0x20003c0 -#define BRAM_OQ_QUEUE_4_NUM_PKTS_RECEIVED_REG 0x20003c4 -#define BRAM_OQ_QUEUE_4_NUM_PKTS_DROPPED_REG 0x20003c8 -#define BRAM_OQ_QUEUE_4_NUM_WORDS_IN_QUEUE_REG 0x20003cc -#define BRAM_OQ_QUEUE_5_NUM_PKT_BYTES_RECEIVED_REG 0x20003d0 -#define BRAM_OQ_QUEUE_5_NUM_PKTS_RECEIVED_REG 0x20003d4 -#define BRAM_OQ_QUEUE_5_NUM_PKTS_DROPPED_REG 0x20003d8 -#define BRAM_OQ_QUEUE_5_NUM_WORDS_IN_QUEUE_REG 0x20003dc -#define BRAM_OQ_QUEUE_6_NUM_PKT_BYTES_RECEIVED_REG 0x20003e0 -#define BRAM_OQ_QUEUE_6_NUM_PKTS_RECEIVED_REG 0x20003e4 -#define BRAM_OQ_QUEUE_6_NUM_PKTS_DROPPED_REG 0x20003e8 -#define BRAM_OQ_QUEUE_6_NUM_WORDS_IN_QUEUE_REG 0x20003ec -#define BRAM_OQ_QUEUE_7_NUM_PKT_BYTES_RECEIVED_REG 0x20003f0 -#define BRAM_OQ_QUEUE_7_NUM_PKTS_RECEIVED_REG 0x20003f4 -#define BRAM_OQ_QUEUE_7_NUM_PKTS_DROPPED_REG 0x20003f8 -#define BRAM_OQ_QUEUE_7_NUM_WORDS_IN_QUEUE_REG 0x20003fc - -#define BRAM_OQ_QUEUE_GROUP_BASE_ADDR 0x2000380 -#define BRAM_OQ_QUEUE_GROUP_INST_OFFSET 0x0000010 - -// Name: watchdog (WDT) -// Description: Watchdog timer -// File: projects/openflow_switch/include/watchdog.xml -#define WDT_ENABLE_FLG_REG 0x2000400 -#define WDT_COUNTER_REG 0x2000404 - -// Name: exact_match (EXACT_MATCH) -// Description: exact match lookup -// File: projects/openflow_switch/include/exact_match.xml - -// Name: wildcard_match (OPENFLOW_WILDCARD_LOOKUP) -// Description: wildcard match lookup -// File: projects/openflow_switch/include/wildcard_match.xml -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_0_REG 0x2001000 -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_1_REG 0x2001004 -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_2_REG 0x2001008 -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_3_REG 0x200100c -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_4_REG 0x2001010 -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_5_REG 0x2001014 -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_6_REG 0x2001018 -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_7_REG 0x200101c -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_8_REG 0x2001020 -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_9_REG 0x2001024 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_0_REG 0x2001028 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_1_REG 0x200102c -#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_2_REG 0x2001030 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_3_REG 0x2001034 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_4_REG 0x2001038 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_5_REG 0x200103c -#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_6_REG 0x2001040 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_7_REG 0x2001044 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_0_REG 0x2001048 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_1_REG 0x200104c -#define OPENFLOW_WILDCARD_LOOKUP_CMP_2_REG 0x2001050 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_3_REG 0x2001054 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_4_REG 0x2001058 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_5_REG 0x200105c -#define OPENFLOW_WILDCARD_LOOKUP_CMP_6_REG 0x2001060 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_7_REG 0x2001064 -#define OPENFLOW_WILDCARD_LOOKUP_READ_ADDR_REG 0x2001068 -#define OPENFLOW_WILDCARD_LOOKUP_WRITE_ADDR_REG 0x200106c -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG 0x2001070 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_1_REG 0x2001074 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_2_REG 0x2001078 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_3_REG 0x200107c -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_4_REG 0x2001080 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_5_REG 0x2001084 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_6_REG 0x2001088 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_7_REG 0x200108c -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_8_REG 0x2001090 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_9_REG 0x2001094 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_10_REG 0x2001098 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_11_REG 0x200109c -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_12_REG 0x20010a0 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_13_REG 0x20010a4 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_14_REG 0x20010a8 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_15_REG 0x20010ac -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_16_REG 0x20010b0 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_17_REG 0x20010b4 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_18_REG 0x20010b8 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_19_REG 0x20010bc -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_20_REG 0x20010c0 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_21_REG 0x20010c4 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_22_REG 0x20010c8 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_23_REG 0x20010cc -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_24_REG 0x20010d0 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_25_REG 0x20010d4 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_26_REG 0x20010d8 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_27_REG 0x20010dc -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_28_REG 0x20010e0 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_29_REG 0x20010e4 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_30_REG 0x20010e8 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_31_REG 0x20010ec -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG 0x20010f0 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_1_REG 0x20010f4 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_2_REG 0x20010f8 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_3_REG 0x20010fc -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_4_REG 0x2001100 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_5_REG 0x2001104 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_6_REG 0x2001108 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_7_REG 0x200110c -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_8_REG 0x2001110 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_9_REG 0x2001114 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_10_REG 0x2001118 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_11_REG 0x200111c -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_12_REG 0x2001120 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_13_REG 0x2001124 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_14_REG 0x2001128 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_15_REG 0x200112c -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_16_REG 0x2001130 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_17_REG 0x2001134 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_18_REG 0x2001138 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_19_REG 0x200113c -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_20_REG 0x2001140 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_21_REG 0x2001144 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_22_REG 0x2001148 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_23_REG 0x200114c -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_24_REG 0x2001150 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_25_REG 0x2001154 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_26_REG 0x2001158 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_27_REG 0x200115c -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_28_REG 0x2001160 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_29_REG 0x2001164 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_30_REG 0x2001168 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_31_REG 0x200116c -#define OPENFLOW_WILDCARD_LOOKUP_DUMMY_1_REG 0x2001170 -#define OPENFLOW_WILDCARD_LOOKUP_DUMMY_2_REG 0x2001174 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_0_REG 0x2001178 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_1_REG 0x200117c -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_2_REG 0x2001180 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_3_REG 0x2001184 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_4_REG 0x2001188 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_5_REG 0x200118c -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_6_REG 0x2001190 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_7_REG 0x2001194 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_8_REG 0x2001198 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_9_REG 0x200119c -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_10_REG 0x20011a0 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_11_REG 0x20011a4 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_12_REG 0x20011a8 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_13_REG 0x20011ac -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_14_REG 0x20011b0 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_15_REG 0x20011b4 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_16_REG 0x20011b8 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_17_REG 0x20011bc -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_18_REG 0x20011c0 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_19_REG 0x20011c4 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_20_REG 0x20011c8 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_21_REG 0x20011cc -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_22_REG 0x20011d0 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_23_REG 0x20011d4 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_24_REG 0x20011d8 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_25_REG 0x20011dc -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_26_REG 0x20011e0 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_27_REG 0x20011e4 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_28_REG 0x20011e8 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_29_REG 0x20011ec -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_30_REG 0x20011f0 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_31_REG 0x20011f4 - -// Name: DRAM (DRAM) -// Description: DRAM - -#endif diff --git a/openflow/datapath/hwtable_nf2/openflow_switch.bit b/openflow/datapath/hwtable_nf2/openflow_switch.bit deleted file mode 100644 index 3d9c2a02601d2f5e12a6193d80a8bb32d474a7c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2377746 zcmeFaeXLx^btibLx?bycyLWWE`6M(68mMkInI<7@njdy#j~A|PwwNbJ!92+pAO{BA zl<8+_*K65383zlkk?Lkk+afqXi`EEI;6I)fDPV}j?hG)%E|7)YB()nQAmAXt0{O=d z*WUFEf!g?;T%0ll@nk8>PI?TTgQ)o1ie2XN)p$G1A<6%pOjQ3F2y-yLNYnNR+|9W_(x=*@3-XvTC( z86y#r|0=~(;C)u=SYQS}0fX_!;OA*VNs~k%t9P6-KG5TAl{L3Syqluq`GL8B zv(aVCO9kcGtjH{48E#ftJNPt*@V_L4#wkKuhA1(*kyTIT+fdyFg3)yD6R~(YS@rx0PF^ zyFg=~gB2iiaC1eh{8C(4d_gXW>}*A<S!FHUqp zOFV^vg}BVgp`R|);||K27lCf>^I{oc1SGUMoux64bU?nqKDkQqA?15%ep`hlOGEWQTF4BUjga!=;p+&cl3t~YICHN%IhtwX^ z6cYfq^4Wubr*dqI;db_dRFVdVGE$RvmBk^2(1#Y|atk?SQ$-xb zjU`|1s!!&+Xc;2W)ub3tVL2`q452O6BbC3SOrY@U7CAxIaipEw8efmn&Sv-_MCHapyQIP`;Tl2co;m-jdv$N`~4D+l_dT7HSlc zo0qyPpP}gSOYPmx=R1*Odnv582kuf_M1F~u*2B-m%d+6I9G{~Rg9W*y4|$eP!0si- z_Lj?lj!zYFysJK$`zI|Uy1U9iB#@6xG^TqQQ_kNvQBMea zLYF7yy#(I_eNu>q!SX8Q$$gV~?ya+{4CJ)QeLl|+iK$igAm?o^8ENuXlAH!L-&vw1 zauLT`5{L_JLfiB9CN%NUUb>yUjMN@iKaJ2We1=1JCbuh`yJO%xOEmFni57e*M1HO_ zNQjr^XdA(%%L{UxjdU8OV16$-4%mDdgyvc5G)w05Ag;o4|IjjtYoINZ!M$!?&O?s- z>0K4HRQQDcSg(}D{pvp@#+dVidG`Cjt%EtUmw~q5#eIlML@iPH zjosY63a%5HfOhILKOs!yP|bkN#VVs+N;Qd2r*hBdH1xKh`)E$fuu+ClHRByL=&oAJA8l{aa`+{;Co4O8ESuEtJJ`oyuT^~!SP0)bpxKF-W z=hmuQtk&u+tP9byxX5L(7-P(GeN}zjNa|a+1YM?~G|*sxv(PoHl7hus|3MC3RUtP{ zIeb+0EXQU1qG4&=+*NU_{LAcd-Czxu=a|B{9vd9fyRv^T zI)2=Mnp`Kf?^5J_A01`^+nsBm*mT|oTT4=^PGlD~KcSwaoGH<%sW4gwRMej}*_y`krHbWM26P8n~ zTX(aW{uEdB8Wk#mHgU6#?pV-fOpCd0(Cz4YQU(_p05sN30ycx3L!uohcoY_iE^v=F zVtaU#j-=wdstT4=b&g?$h9sy6lJq(j&VZYQb!UhH$nZI^jCYyL?GV-#nL@Cvox@}{ zcGBFcKySh<%IM4xh!B^8euyk-i~6Rzw<}~7zrW4pZj&xh4`rZvW-~hAP)0bC>4syLTwtzxFU-N&_r#CA6Dy1api@!bk!ZN5`>}brXzw5CC3MB*r5N1{le) zx&E7%p&iRCK&Xt6Y|d~%CCf+v#|QM-gu%!i!@i&hdCNLkbVFbj(<~>~IFV@NB20R( zAf`l_%P<^>ya9BBIZ`;c^4{QQXC2aJ`7C&h?!T z1JUxC?jj;;$}AFB<~&m^CpmaVIpN=3!wj>C3}8tT^-vGbIY~GT^>7@QD(9_mEWKCo zhBYnQll2KE(HZdI%W2TAf$gs)4Gp=0vZ>0yApkg~)A zW21yx&4Gk}F3;R08m`&q1q5fB!FsQSoRxAp5LR?U4CLB{s~|MA(v%*k&?}H)T1Ukp zR+S20;}G>&&U;|OkWqy|%*=peAT&M@VGx^M5@%!+m>K6KR>*tAkIP_bKyu?l*8TB} z9NUwI;)CHtaS}kv6(TzxfRR87@nh;Fr3Hp(8UtrLfrjf7B9FYZC60Fl5-^c876;?G z9!V9V3av}ssDo&8JuJ#dPhGRbNm0K0q+_9j&J%o=t`Z!Vkgz?eR;U|ie`#RfTS@-C zsqNPC7*zq%$tPoe?=5%h@f8Y_j;B^fko-cqxpxcX_mNq&zieopn|*Ye4x44+TjX6f z=5nEAKDU8_84%!j4%`K|4kC*OiAA|2XLp$kW%!H^M|@&oo|c?(GC7X@OjeJXRD#@n z56z4Q3wg5&Cfp?v5wx7&2%MN^V4O3;Bp+qkf+z`OHl3VpxJ#_b9I)>^kV zX_>u2SoGn@;PHQqA1`2VblzLXw^+$|Bm#!|EQfFAy)|*<9MRZ z*n`3>hu@T9KP3Mg$^gkuJl5=B;2w~H-!B?q#z4DIxMc9&c#pX89U^Nzj{Z60VGm3V zn}#QoQ5<_egrCE{T%~}EJDOIhsVk!hGyr;>p_gET$P=yc6WVqBEInip`##82WEL16 z7Xqe*jG;Ay?ML@=$>S8iJD);3mLYPCX|g z!U$iVEnPk_;SM3#h2>n{rKm}f^ax>Yf(%B$JZPvmumEVVfbbmj&p;t#dWI{`ZkzgSZ&ef3<`o_ZnDT(JbElKnZfgu5sQ4qFMYOQ5iSY(aYKg8m;KC zZIk_@2AQTAl5V|%c5k+#sH_hh0kW=2@YQ0hm0vTuX6vzD-)@~DTh&_iXgb|&H7u&u zG}U4h(}B%Vy{gLVmyi6L(WPl^`cgc$(4e>!f0~6B#a0v#T){QA3iO@VPqXJjYpT|F%TO!sHPP# zijOq4K0sYG1*{20m#l6MVzipBA)K&`W30=y$p{iJUeYdZ)omxEh z#Q$1#aA8=qF0#(nk7)#3+wJzq$B{9Y+OdMW7PcFDWLv`sPQKcWbkl!(Ku6+QvsgqW zwDo6vT#Ib8U2oH|7hL_w801DdYQi7en)=w+>tqkNFF0qT12j2S=3*>7d8%fgvd#L) z>L&)r{@AvM?dLJ`9lJlSy*Pok)2g}ItZ|@Fr^|62kst|Ml5z;7gId9s6A6(J(Q)28 zq-R*4o3JUm%P@pZ#)aRBvUaJ4922$NL81B}6IwQzJP>mhMlTM`Xl{}w7ii@9AJ2T0 zl6XMXgsaG7TrhCtJPrlUWZ(sJNuJ9BI7zv40;KOjQ+Q6H4+@6ic^+KPBEXHF0YUph zsli^GnCDXDn&?KpY|*pvtVM5Yi#x2^l&#UxCVbLy^8{H<-)38SHtw-G^!v8$T4Ngy zxK?n*dW)Wjw^#f9$7gPvY?Jz6ZoKL2n{Re{`gM26`T|ZqdQ^BFb4G(4g2J{;a|k1z zRKr`GT0jp)u;kvjh|#tqf@F(LzySWMx>OXy0u)WCDbz-drq>3ux*?p*0TAp_Q*>Mpr%ku*aK6G@ zXUKqSdlrWgn!;PP;b_!@(-AylXjzMvfCZ!bO_=buXB2HK4>CN_Ef&GAiDz@D9+XV0 zY2$7aY^$lkJfK{s@FUMc34}qJWI~r83e7Q1C5+Goxf%=L7jnO#jD=nPB|Zq24s4-0 zAtC88!uP=f$Ze_w&kngJx>%6)%#?%?!SWnaQiF^GICwq~adPlX!nr2-QYUO3lxis9 zLI8n;3cpj~QRrld7ZY5B^Q?`Z1E=m^_f@nP zsyFK%kyHw5_|Fpnmy;je79vuP^f_I?;6oe&%}~Y1mU~Uxa|#>yuPw{Br4yyTG z(M~dQKo#&G(kLMXb|JN$($eE9`W!97V_b-a5j#g0^*~K6g(E)(6uF4UUE*%$wUMhH zaS-A-w`GvfGD$F8V5X&VX#qDj33R5tjG!0K)gRns4&b^lq&7qDmys^IbNdo)8awzZ zYwlaCq#;eExH$ZRZd&WWOk$Wy&K(11v9v@NtnfdG2dc;iC5#wpO}_IcFxQaiLxwCj zo`+LlWX_7PB5qDYY2P-~fCN_{0lweI5BWWtF!(M`ZM2w$J9sTe&~>~XOzI07ggvsd zRxIJvh`XlF89#;@DA^hof>^F8oWMQ1g1Xq?Qkk^?sef4Eg;NGwPkarCW3f5lc!oUN)fly2=FoMT%wJ;T#%O}Y;Y!JW%hGIhQXvKW#@Kj%UE}TxZl=W=4b!y9?7YrcVS9I{i1?bQ(ho> zMM*)UFNM-h9R&^l83dCA!jO9=bLdOv-?v$Smsz;-W^u8{NBr}gk#Fgjl1wUa=`Z@I z;MO@wE^Uo}{6)C&<1gm41Y7$tiwGkT8GUK(+`yypODKF!4K%o&GEhtMl1xi8g~Ai= z9Ol(ueu!L85-I!xOSV#9#G#Og2e}(?2Xpyv|K&4gYwIr&h^^kOk^zJhjcZ?m@Tz3d z%ACfYmUnC9rx(H8Z!hUCYUDl-92^u-Zm)VQ>JAe5g@a3SNx6#}d1*N|SWutOSk7QI zBuB>Y5_Wd<4n6+3e&?M%l6&vHD~mfjg#Q_^d1Ntb?d+7VTtOK(Zk#+>25Cp1JP8{A zDLU{HOtR&~7l>TBa`GhId#{MR@dn+1MwHk)`8d>m^Eb{c}=P#@6)P z^yyFQpI1)q(7SJecJtcg5%XK3RT?>-P3dBriYx;SZO8_`{u@|N5O9%>7R%?=63C_Vml; zr(YJ~ot@8dRgpaNv+}b)_{Mk2-}p|NJo|%`mSB=a^32a5^32bGiSRQ&d-eyZE-+?9 z&;B4WAL6&O^XX5Q|NPH??bpgbnawlM6gxXlXUSQ{RwaWQ@Lq(MG;-Y>69WTo!(3yP zQK5-i(71Bt-FNBx-{098>~Q=3-tX<~Jh{T5Tq8Fs{tZ}Imr-ucSi*AM!8`9{U2+cL z!r2NZqMK_hnUXB5pgZoMLn7G)9_M_lTi*}Bm94F3ex|?i9Z7!ru11FsBM4??6x_M_ zC0~%eem#2QjbsEND_ukE&3BTt3w`2x^zzehyn(DN#}g6#IR0)VhM-vawO@<=mu=zl zz}vp>lN^>Ek|^;A0*+zy&N~t>WMy1mxdJjXIE?pT&|+xG*t~KD1Q~}i`q)Z7HDMgy zdvC;YNMr&*BBoG{FpI#edl|d$llmr%;=buzwf;J-Rzge1VJh-+IzaQGx}dRpY$hWY zLomTG4rP=k;}wJU*&oPI6_L~cH!VH$vk!kb`jd$?=q>uMbh!Q3bijg|cu0b{tMa?>7v_ZoRW?eL5K$sk+h&=O5*DU}&4)@VsC&q71|%aiqJ zQqFg2%jtK6#dyfI^{=o>`VU_&|K7nb{SW82%-aLLhKRB1^><^5WuZ3@@=^~IgzjXNUY5JqB^{@OcR+L{q zH~J52TmK4JSc8U@=ZLelt+lV81LNF4uH@i_>j$|XLrwqKZ2doaYs_+EWWRoJ>vwCc zHriTaQ(z!MTVK>a2ByDm&OMd*f+tPvHGJ`M;-8|9@{kjY00u8qq`dT+kak!d;BF~m zn==@PWH_)ri5g7mtqK>uo+WTdZyn@>8DBXFhtjGBC(B#UZJjFzHPMAefoU4`7!VDo zh!<+!+q!RStG9KLlXXrioXCRpAY*GGJD_QmH8|7(%WwBbu)^!y-+G2kJtJ10dj`5< zKuihkAeSp`#pNQ-5E;*vk(MhANe*s(HR&65_B3}b@hbICs*rF|#sVPNtee<_h6qbG z$JoEG81@elcOfn!@*MjoNnSXz*Mhw@_AiGm=j=o&Yu09enp5u>i+m8(*!_wzHEZ$> zamIX;1__2U*qwr>7K_elC`%R;rMye*oh!TJGmuCX|5^7C1{|>eYSgtaG@z^2o89&c zmT6zUpaxzr8lC?QFI;-BG#x7or%{0EXSCC`)C_oEO= z(4Ni87}ys$1_11;CS}Zk2kg8}v74O~iw1Nm*gHyJOEoNZEepDp%u1%)u23jVUZoN_ z&3~XOU>kf>SahdwBUrhHX{uz|t2X3b5R9*1(lSyF2xPPrduspo^zha$Qgud zaQEPFWeMQKoMlYWx)Th&xSn7l!pu8{1r2Q+?BY${`dPM&XVat`g2|kJk!h+`M)ya6 zbQ>P@!~_2sstcywXL)ciH-7ZOx?ti;f;sriTnZzPu~03+m@ZrE6!ZNA(;I33L(gTJ0Q}3~o&>`f zgwp!~)XQQlUY3^(fMLA5s&xUA*@DODZGq*Nf&EtK+5GwfDk7s2h@qRG)HMNaIZx z&KVjQ7dcA_EcNYHRSyGhRb;J!F;QH5*4G0lcmiQKidMF*H@x<7H^zX6o5INN505$-ouP zI;6J)?US`J<}?*=nl@W%YfWAZwc($&5lqg5B|V(aFW`P5CmG9C=NE$6MKR`to+N%g zvm1v;cvYO~i5F}o1rMVjyEK3MBQ&x>wzsqeOFUhu`I-|ApT2P+xw}rr4XB_8xS*L} zT1C$X8e%0?oUiA~LLj&dBY4g6vcgcW4A6hcmhgh#0DaH9SI{|J+`_Vz7lnr-YLKpL zHFns8%v;*RThlz)nr*zW>0m=UJY@1f0A81njzg(YH$Ib;Vrg9Mpm8wp8E}1BbqeQ9 z0UQ)suue5+YdVPZPd&LJhbNHUfPann z2)PzAoy~1sE^oetXO0#OWvN%Ud=02u^<&kMBlHy&A5kM)FLse|Rh@2-_2=*gH(J)a z=*cQ$s2koQ;r^qvi~Efx;-`Eg0t@doDm~yV`a5Q{Si32xs6yT1DM@Tf(-7=>5iex| z#x&*N><4N&wDBuUm01;2*=->9TKD9opLk=Cs`*o77Tnb0qIzAv>?QTVsw3*C5Qnhc|(ax@G`fj-ts3s}ZSSU~y@c zh4NRaaJ}KPoi8iMDTm(a-E5WC9n$zd4W11HD*W;@&oQVPFrnR{k-f#RG-tp@fpS37 z6O0oHlw*v0ngDiws3-Ao@POZ{ja;a=!B%9vt`Mj=dKkgx|NSNgjpg^7@yg1yV?B9l zlH*BzhCf%QvE@4&&eZG-Dq}rwq@bEQG1^Yva`5Dov9sISoAn+pTVa#hpwLOf0TLyQyf!~^tq=R*bCA2aq>A` za~rW~JG^Iuij;~4TP#$LQejp?Ie3ZNcGR12QRDs9QUw*~*y)QNvK?T}Pkf?M>Cb2u z+i#wKq~c~6=eBkJ3wRJZEZ}V%3_Oc|aFLuNZJ`nOy@%e6;A%X8DVq73t6Usu5U@Pp zwsDFIr(5cUan%eb`!}3^r9U%IUPC=+@ywC6NBgEeen8R78WVoEOZ)Z4=?Gn}q>FU_ zp~`Xh@LKfvN9cKGi)o%_wp8?$|_OGnR??3sp-&FRwq$c)xikqYh*(WM7Q$6Hqi zG{6+fO0(-TGnk#mEr}DDJzgB1Em0fq*!Gl(R1=gUCKaWc1$~D4{HiQS0~F+7Af7xN z+2N__MLK)*=r_&u>G4T-M(?ju_o+Xtk;Rv6y4@@k@#-%Eu>dp9nFZ3_XRs(N_yT57 zbe;m8*EB>(0bc$K`W_SUH+K&PVbtT`XKdXfk785kqnDzWFhxc}N(T-1OC`5WB{EnV zxY?Swh@915b}H_;4lGVR7HniZT_qn~(z953;|Svg-@$nbfTP!{j9#>#>*)B`MnV?< z4HIz6N%BM=CpY3jGag`E#OB*>-FKjCaYj1DGnQlA+2Tda2h9z)UT~9P?EIm#9(~b(avz~qJbfSrhAh7_V{LrG$F}jA2V#8V zK;LRr+Ozs61~*Pcrrtcaaew=<7wfjA#}}XKj$7Z<(WiO3gKK<-#!h#ymCU$QE9j_n z@uE^1Wk+U{3VMc7HJkC@6u%DH*$lFDsEiTc85R7K>lb>MjGOmsq7#~ms(?tlmbJ4t zF;d_g>q5f2&sqLZvO~`7>rj8)>>H43pz#VC(~6}B@qOT<^}cOXj?=_A1H};n<=61J zO7p=MzEL@h_3pt<-8@K7v@nA`cF-Glg6D^QwzO{h`y(4WYdao2v*Nd@Rq}Pj1RpR) zk34YMS{iQ}d{5c)6?f`{aaF2ExViLT>}UP}!mFOBM3(2km#U9P8&TX`Z=z@8LL#aw zgSz9RlW0N;9cdKB#j9gn_h{Shs0|z2;|J=x61VV;1#f&)r;$Bn^`~*;!Zi0IJ+2Um zZH0j5&;rUGT^Wz`eSr~eq;mHJE`D&p9b^SKrb)4$F)0_3+XX_)8H_>8P*0O(Ke3XW z)G&w7Xav>}zqTjxCGE)LA4ITRn1aljnC7`^DnK^lr4BwUOOShCKu z6Ehx+7XOezM~Gox++$%b5g$rL9&h516G8#QkWQkbz`@|2$DnhHFJ|CU2Pc0=uJQ#uv#yWnDF95zM(*uNnMnM9o>HuQlZG!fnf2s5|oTVhR$P;hLp*xF064Mv02} z78xzNfv;k?e?%4RhJesu#^JB@V^u^o8#NDG+zHQF?_zqzdXFW)ZqZR?VLR@P%zl0e z5o(Bzq>Kq1_c&PmVoW6O2VhpG{c%Mfd_SgF>9&~I=47d`b4<%&!l=#jh?j0~^Z;%+ z_PiII#km7_52_9rHt*8bIp|nIi*$gYtr0~YvS_{(pnw&wKAsfsczgm3MiF`yVfhQ$ z0h89Ds=GLHE5|6%d1^E*WGsw~ScJ{$Cb}7w9I8_@G5+)sB!uC?b@Cs#d${XMJHhLb zqZTzw@XssqWS@*1=uF;wLWh`QY{Gxz<4GZY6Q@!dMI9aab2M|*j%KtJ1ep4 z25UU@jmY9WZQ(A>B2yUa2e4B_;V8}nm@FbHVQ9iZ-kMk{Uik!Og+qj%JjO)jB7`YA zk4QaDMO&hE^j{QsSj3}ZH&|73?)s` zCQW}aesO3@>s8hE*IaX;;SuR|Wg1Z*QR?A_Lfc{%!7v|;J=#tkbmXA?0>0WFU?Mb7 z7;~h0MYPNFJPL7Z3maWpU}!o_tFgCe)c8^qSG32_gv6OME`AkXAMVro$PgbZo(FYQ ziF8FeCanE}0g>n6zc=8Xyb=(L)gWy=$4WjNB1|vu2}I4aD%y)2BWN1@I18}Y&>~<9 zsg(lV0*wQXPXSY!N9(3IEHiE`dNRg9GL~^<5seP&T?cIB(Vqb5=X2mRYUg-ZYVsjT z?n`GvI6aW^Xo&)3_;qRQo1t;Qp!4X3xRPw*Tu-k!eAupV!xngGHh3fT!=!?fG1Ec? zrkdSMfltlYs}ZvrPi&QnId7STeyJTS1xVTq6I=p02B+l$ni&dJNeV#@I2-U-4WQCJ zLDBmYkk$c?I(bwN6DBA_*QgOise(1SNzCHlw^(#3zbU z9($h@3@_gw=w4>bW|mxrO*3qmV3l1BmWha8j^nz;Zgfk+p-xUfZe@;4Pcn30Nn*Ba;@NA6*qNZ#aOWG!-`j<}3j5gyz; z;g&@8I*{vhJc|P`s%GrqLG}oXI0!(F&jkW71!zc`C!*ny_hjLTwLVk}V;SQb>pxzc zdr#W)M8LKtpmG@a7n)8i^Rxg2XK`p?nhB#ry~LIotfUUN48V%C^&kQDSpDNabNPca zEKH&5F-UQ6Aj(NTQKs0vi9&FmiESWhUJgnhG|@#u#)!e2{NhhpW84 z4q?WWgQ1Cw)lo|?Jp@kQ7~Xv4jjrExgLP<5*Bi8E;xDfCU~_DWvDsRC4mS~$YN&P9 z@Dxvtd3~*WuGkj%+)0a@;cCI-aE8Tly zoqQY1!_Xjb6AF;y@KKAgw5@m=L557*@}NWjG-^Hu1=T0e>YxI{h3p#JfUvPBoUE9} z)mNEYN2BU)9b(&%P&m`B#brI{H_W-BIfoELU$po#j5cWv`uEXuFaTM2&!;&o%sma) zh(^)#UBeIBR^dU$vgbY_<>TwxY9CB}3z=s$<-RY2g+*qI>~=qESKD^`UEO z(-+;N20HYRT7zyE3V1f$UH9}lTvJ^$qDIw@UwlJ3Z5kXBk2Zvq#ljh(9jY$7$PV_i z-p4)zoTOO-{}~WDK#~E5*}^e}aAQ}FA>m1c!Ai=BDCT+@{VotIvPiwuIhf2!ZKGNN zl4DX2p(WlqWVE$#!}Gbq0-Qo;wAd=d5RXN;>2Pzu0$ z3*I!;Wc+W&)8fNbT*QoDS4VL1giyBCXG#YgT;2ZSdVe~w=q1PEa;#l*)NWip*0z_A z)XP-6|E#j#wnm|o-j5~tfybM4*&fBE2&pxtOufE6F17428y&_Yep{QMlQ-+Qs)?<> z)NJ;!H;1krD76OBU})k-yM45DWD_6$ZR1b%j-qM#*m(0y>zHXr#S69j>voEZuW9X% z)yw8-+)&)#jd0ICLXT}xgX@Pm$ry~CTAkxo#Xd9k2+l^B_i*e#)bq+D*<#sS=2snw>350oEk9@Y0(qq61k zsG3b%d{U3vbYXwFJgVt>?SRwN#GMh#|82`+hc!iXZ0(P2`@lK0hpDcq?wW2+nyT@s zV)0C=sOZQU)zeNNK{%Slb8EQgQ);$K*6SnPajvGx6>b*(J=9ronekCSkWik0gY^HYRAB%_6&^kGp!4u{>Kcaz+1(hAB7#T8P^ zB)3eEJfe;@18FBYj}$qEp`_{1RMCW|Iswls4sU^1y$m*TXeodvixjuTJvqJujSS9N zOhX@|^M>y*l>LS_cv!|8?j2mm#zEkhaoZaA2yw?+^JRn{8SQw6(`XBrsEl#o>u){5 z-$@dP*4Nl=qnlB^pzvsJ8-M5^ULUGH6zFhx4Q4W)vk^Fw}kR-n-}$VYku z_xCC4;%cN2lUt*Q^d{+Q3lHjW{)ZFCYfg7#ku>JO}&M z2*JZ9OnCeS!wvk#JRy51z;y;xq0fsAj0W1q$(g7JR-=W`xHYpz7uWFm5ab|kG10X! zQPHSiTDmYojTO!w+8kCELFVOVFv>g&ANk%k3+Yxv>lS7_hdSeQSZJaQJ6_XTU#pbO zeOz{g))t7A&+7d2}aZyrCv{46NS0Llj!gUQg2uZ!y6py!XVnW>H-= zGM)-h$25-4B(;RWRlqUGAnEqJ6IX&F_-U8tqff|!i<;*&6&6aCq>33~4yJKxlAC_r^P86OaUV5fbNS85#mISsoy-&+ zoH(k3TQ+fwaXi6JVKF@i-#=5mx_15{{amdwJ8<42I`slQp`z=*gDuEv+8;Wku~q4( zXO+wQW`7=6%j<8M$aj2=+Upc=T)Z|mzW%s3h4}QQ8?B9Nv8oqh|3vLZWu1oAi&!(8 z2$PNb3_qmVh-2f{Yd9&w1=Jts3{}OJY&ap{%2Q!ivrX*E7SR(PucXEY>I$2dmC+lj zgt;lMN0?fw)d*XwIdrJ#yh08-9LM+xFyi=p7n`%`Axfs<1n=jy>-BDQ`oKgrs(N1y zuT3cIuohRbA6m7J=B!o=svd2=HS}uc(2y5Uc2y&0W9PO)$VcZvxd#x{N*A3$Rtj`aaUCv)u=H1TrC=6a)k@k5n8+EXE5>@O_YD) zYW(2DkFcj4mEl}XMZ=9kH|`GMkZM;)*k7;w=;Vp|5WWpHVb{3oqnJ6dyKTp>eYe zGjQqx-mDRmBA z@d7`qhOnN)KWi-ZAf@%lcoy=I#<9r(DMmO=MoGJRSZ}gMj5pR~_(3dcqm&6#E0#-F z^1uU0K&a0qDR;W2#g0v z>cwFdYJ~AA8D?`^utvlW#L++bA{h~9Wfo&k1rPx)E95e2=+P4~%SyPgiZQ$K_Nffg zJKD?$)`Z9jn-ODJ2urcZdzO-4Xdx*dlt5!1%Os8mKbQn##!Q0AkYy5ntRZ5?1G^;z z)iDWe6s2VTgk|2i#%jzye>AnB%VIi99Es=d$^TWU9kCTKCjnj|%;FHIIAv3n*z-`Gm#A?l$ z$bo{3OIT@14`F@SLw_ivr=!n!*0t0sbIM$cCwN9xE;NBRN_;T_A1ZxByG4DLjm(5E zL0A?G8{Y>VD>`-=qmADu>Ko%>3vgj*ycu6b>HHTVDnm%KN> z(ZH1f6znkpU@GK7+Q;=|6*qtStOVdYwJgSiL@*2(N2hHp%wRck z#*Cw}p>G-Q*|-B4_h-wdwI32JgFEYNgt|Dx!(x~7=Dfiu?!S&3KK$%q9bZ3)3^#hB z)k-l;5JIZ<)86Ke=?0g~hS-gy^FT_nY(sDN5ryXTf-qF>rYw3nV`r zK!X9sQ9N5j1|>^^@)HW1#}x+(BCanOCC~2W+2BhaKNg0Zh@Yr5*o}U zawtmkPH@;=;}*#sh@=L#2C3!TE2$pH-0Z>?EYGGi_uJR@+K260*!n?shmaj3pzZK~ zc`vozf?U|!f_FR{KzMK1dw;b>djm1SJtBiU_aIYQf!xB%;(l#|70S0EH3%p9l_1?3 zNwO)`!X89R3O7#5K1>TDFNdwhz*rK_voAkgeg_+FLG2sgiFW=W-2jO<+yU*%tElw4tM_MyU{nkgZ-7B`B`e<%Dcb+*X1jhpZx*d`;Kh+^Txg9 z8?XNUcgsJ&3{$fA(a9S({*!*=os+NXS8tqrHG1{NXFps1gFkruReJTt$37N)>su#* zUHRC@%HR6djh$#R!R|)jVt1%3C;vHiZacXXz5CWDKNgx??U+Hr$2)2<-UgsUjM|)Pe)I`{Ok{~6<4}Jo9ye9Z0RK1vPtrd z@91Q2Hrb3#gk{&KROB1qNwU}-N*wyb==g4{lkHe80BcJ3%D|c2_H_r6sId^4+R3I%qPqWEhEvG(wu>a!C=`rtDty{Tq)z zj*Sf^L6)~OiJ>dHF^2;y(&Ku}?@7!CyeqH*EFm9YI^Ja%>k-(_1joak( zKi(U<#xp+?HOO86#5cY}-~YeRS9ktFI_&TNy?*f;|W; zpTyYw$VadX;)OC6CjanucVt-3W(bL@mbWJo9ME1y9{}y;r}gjrj$lX?e9WEQWm9hO8_HY}23GIe`-3r*pjuXK|m>ab6r2z_>0=Qh>!)-c^rocRBC*<9a zWv{aF7S@~jZf-(b1MMra;~DmUbL^wz%DGS}@6tWeWMRv~>DF%v_I0!MV>UWSN|X9Z zxsss1E(8vq05W@GDp@Vhdxd@~S@;ql)5wK$Uj$3`lN;p2U|yFuX#26qMazN(bwBAumyE^)IH?| z`|@koPlaYQ|0gxPXvEF#sS;aOfBUEZ;?N70HD;IkLAPLZSA{*k?qNmd;z|!gz(Rws zAq#=~z?3M|jdU7~7Ii0qTl9GN&!quW*ey-@=HaKMT%x~t4*^QL@7uXoI%I3fPabz1e;= zNK5-svV$79iDm4__8S>Dv;vzRq%|6}QhOgd;*)aSsg#Cj1e$r40v2ccu#v%B#avzg zZK4pXqZ#cj6cRN4*ru2#Tp^1+zCsH1{kJTKoII9Ftk^iw&@+h`M`Ok!N-zsdtjzdJ zO3n!c4?g5l-59!|G@p6pF%AOl8g!&wey%cyCG}vMlyMVSDA(Im7w#q85nHw_qM0UG zJHvqFaL@1hJhKXWUTpAO%&(Mi87_Jrw|{|YJiW>QB~2vL#b5j59n^>(ML-hld1?rk z_sd!Z!SZ$7S*D8)mQ9m==Q5%$XcH+7_m>aJK5YN7f~U)D8M_B2WoRjFavZ|#I=c)F z@_0e8Cm6;GjIvj%;=_J&3VT(A+t_40mnMLDxfd{;o)Q|k3AFgh34_M>XF)F7q`u7P zpgtDjg6GR6JXmB8h(?fO@6jb@DNP?tyn+J>rXKJaH}M%aF%v6_p3nA}(=OE=$D^c- zXq4*4cUrRBE_6?SwN@=pyNTA{Se{dPJOEKKbN;ITz1Ya5;227<~@~H;%f|Y== z&t{m)eE|!HP}*r&Ny-(BrRN??WWJC~$Jy1x_-1>jg98*#;`wJ zr1=?Ago4X(_`x!J9&3LY2WK3v$^hW9M_wWXEf{7okKYJCP@18J_^jJ#+O)VeuBb1| zKK_%u5liDu4mhE?XK_g=+V^Z-d;G;vUZ4)~DK{SXA^1o(D*SdYNB2{lTHD-4BtS6( zE=nFLVmX44d3bB=(BlkveinPKre8lUkv@DF}V zZRj%QIV^*jMxGz`bHhjuGEU@}#o+KNT!?bWFQj%M#~B;y3B3gtd+O>&oF*HiB#mIPv*INKHdL4fh)~_QZ z7anar32xLOY$c=6IocXs+MZGLWF2oex_Upd7LUU>o^1D2XK>#O$FQS{LnP@idD?(i zj*6PBeLgC0m)7t~dR%m)bI}>QxeT2R3$nrEieD~&FZ9viZzRzgE* zgn0Tq4**NiAYvc!OvNkNTL9BMMqjakn!z4gtK{7V>~Jf1TSDEq*NiFpBRGVoCcZZ{ z+&46w^k_+kxd#lC;XozpVaTCKu+X#)Ug4$VqRdM4qQxI+gB}(U%5EUo?Wb8M>1sW1 zdGs8P8cbXUn-XRzV#EPf=lLRoS}-RAF`;)=6HbNK!c#fSJMcTmCJvxd8J3EzJa$r- zS8{J>MapoiRd-QQ$z|a1Xzymr^pNlIK@!Ut0-9tQ*$p0nVJasN@^eYPeZgVFPjrDU zL5!7HG>v+e3S_5+nYNEWxK%_$1J00RJw3yTppUtjZ8-;f@l@mes6sP7h!-!7vXFWq zD)rG9c&d<>D{R!d->o}6z-<-l{Dd6-y3+v5-x>aQOiNcvcr#^+7vs4Hd#WpZGI4za zr>SPaU2>Cxs_33XOwm)gEAcR2s1&G&QsUn6(=oJ1gwfO?OAl1=La3w3A#00jq8&Og zb$R+YSQu)2i=mafR=_)Jc!N~w!hU0^JNE0XxY-*xti!KqKb*d4r@Dg^^3};lvC(4z zRXtv@w9hp>-Vh$YMa36ULdR=-_(QX<^`+`1Yq$JcHm=Y`JA1_8<10MNZ{ZWc9u~q5 zvl00L#n|ux$(t`&RU97IXD6o-DzYCnuTX=hd2;<&s)L(3}f(WiZHuDTMxS4xdB3IE7rw5hf!rJq)QfYF48B8 z_})Wf^kabbyS?71?_4vsGX(w=-t6YTeyyW})JLbm`U@jm7ZGKPV&FtbEqC>FT6Vums>2cZ&Ef6upyQo^|K}=+txmu@E8@4tJKeSxg2iP%I`xed>!^>TF6@S_nn;NT@p-T2=T8?l$(xzEF}pGQ456u; zZ(f_tYF9D5Fh$yykDGlOL6PtIR_NFmC08$E?AD5SIlaT1*yzf^h&D~}Njhjc-}0Zr zc9iPalvP2%B+Wb8MUSjiJjVQbC2kyR zMVK%qG^CGUdZhavwEUt^6ct+vz8u2q!OG%eCGG_#dK7^+rqipfe~!Q6;YolFI2zdN zzB99vh-&eP2W|g>&uM6k3zbR%0YE>-SKpZE@xEf2U#x@uc{uD5Iw1hr8*(L^39TN7 zKH*Pr>}0aHM10`(h)$zRW7f0|BN&z7VGQt`sNKdaVNJs07hmY{QO-d4$_`&PK~q_n z^0DqAdR+(&5_8f%Ze|?9s)@*=k9FKjK=B#2R?bzi7>f=eXdc|YaoFn!(--hg+=h+F zBiqFs2#V7!&n$=8^7J9sQ585c8Dsl0UFjGIb7(gTuF;KPt%VGAQ6A=Mynrgpic4oF z+F4kD@H)4eAVCa>`IUL^=!?b!{W4xBC#PVO<%$^V=%)w zJbA&~kBb8ohclvs0h~AxDlTV?sEi2j5l|Ze*7|6XCJ0W&YBZOkH<2MTWY!4%DB_ig zf>j2rBbsm%7o_m>DF~BhvgPD{PTKf+TxU{rg0pqc33rx5-N+qtifVnQ#tT{Z5%!{ zW+$i4V-wDJP8=uuIPskHIavi#jwCfU>Q~7u(vC>h6ILw)pxEvTmwP2(V=U{iqJa&u zN1anxbzr-QQ=hPw=p{&0BzzvRaNGuvJZcaqgKBD;8Z5sIZvBvj5t!$Nn$(wSc6KVN zZakhNvkbmvmkH2g?-x}X;;SN8!${OKut+NE zJXz?jdyccFM)M`?FOK_2P(~lPRwz|?f*HrI=E>EAo8IFLK&Qskqz;CKqLWd~EelSLFfdPCT>09_P4zt2ptPzbX6iMqoebnF@5{|4x1cotIHL6mG!HsZ= zEL1p)o{GTqaik4SEGK}eLx~nqKmiTlH1?o&z(*a?5AjpxTPAdGL+21+6t@wpr>NPD zdrgaGvk)nw{}(51cu*pPQ3plez~?X+lp8aJ;o{6&P1vl@ygD)P)Nv8Y9ZYG4yQpTv zcAp%es1#5MgdekWWTUIjkMt+hpnBHpmoUANZ7N(74avM1zeFB?pTccuQZ&Z=41FkJ zuVGYJ7jZotVIZAR=0&Sbzvxs=^HXZ;xNb3>(WtqPxLdjsW)O@%)k4%T?-r@(HI@@o z!WGl7f*K9;c_sDo)<&r32*EPANndC|@6PVGNcN7w{>14`(^Wf5+zzffqQ1V~&C#XFVr;LCT23 zkAa<+@+0jr3Rt>@A6o+%B*uH_rf7A~TBxNEZDQF&#io+N3b!ZLt>=lvLIGM4Z7A}d ziagGc&%kCF!4LzV5(1=%<17-+qXdrw`r|s=yQP3YnQL&Yb z0N*MWIZcIwG-b(Af(%roX+|_0%RvV5AI7e46-!J}5Q3tj2vYuP60{);0WymjU&OP_sbI<+$c=w$u zbLWbzLMgz>5QGVzlzoV)B&LiG5;VMPVGoQjsw;oKEF|?Z0#a})`wl42OYfllbkBRl z+!3XrK5|{O5^yah1!(t%pyYu%QJoYqC_hsM)u_pN#SW{(szRY~d6=WrR7$QAX#}MV zu@6Qu%A_5XL5X3BK7(aY>3FC+5Gf_AUA3QRBXuKxt)$3My$UT`l%|R?vn<6FgyT^l zfzINIGYhUCO1)XFvH2rE39_8Zki*fW%0z0955{#)WI>5~K#qhGsOpOIeyG$bPMU+L zX#JTOEhkPm#7{s{lmMcqmJ(RH(%tYR6}-A*cavSMcE2TKBj>ddog^-D;Ybm>iI$NL zGeDXQ62j_B+pTJ*tEvJ@uH>1bRYFLsfS@~6T{#8yCvv3%Zl;v!bgGjKj)t{u9eM;S zCF4VP{2EsccO?KJ?e#Ap{Y05A-@n8waJ2X9Q*RNY;)LSH@K9eXT)_W12NEQR-gvQQkttcw8 zKu#L;MXETqj8}>LFCoIg|ACe&%`Z^fMh(oU0y!omkfG;wWF#o#3p5VacZzcML18;8 z#PU9kkBBw8adKcij7TZTH6|`Loujr_Bkv)5ny~R0ci7w4g485rv>L8C|MJR+%<+1@ znRyCNH(k^#+;WEDBadqfQMy6Q*`7!^zivhuy#8#j`iXwm)xG&x-IyMC<2tflJHEPc zH3SxZ$9#Th{Ir=IYq|5M7f#g1oxM+p*_h-$n7y?Pd9K0x$cVWLyKvPH^YFzQeTX!> zVPFCorL3?4;ltUSA-gMnJWz$qsfcD)G1f-WL?$YkLn}Iy=B-UuVVfDz+}_vxHI7Pz z-MiZuIj0yMia!jBbaF4QcUiZQwF9zulK1^4?OaxGNLeT9%GHjuT!-cOAA zoiEduW^-aj6T!BXG0(LM9S#`prQyt%u63?ZQTE#25a>Ie8F zG%~A*wHkGCfT6bBf08^7F`glHM$jmnYRkoi7&g6e{UzzR*kL_7sx{)VW3?xV)^i>D zHCAaDVEJEbKCrs7@(LxgXePCV)s)TEgDWe4a)2!64BEOK$Vck&B*haz!N?;}o;<{E ziq~h9zMy(koD#2!Pnv?x!KWA=f9`t)HHI>V$Oy>=q*<-R$LYBvWCzm#mP`6bx$&r` zZz)*S2P?t*29%V1n%c>a=BeqFm`8F4q7Wr&!ZhJQ+6p$c2QBtfW@#6aHHtjsV|tHa zvE$q*HVKHHpJ=mxG9t2%Z(x!;TeNG=jg#@Dc$EW~i{=G6CqZ;6S$^oM zm@9UDX>YCb3FqT#)x2=&weuYMV8%_ZF7U%LRBg25;KP@$a%}g&6WUH_=L<`+;B2-M zWN}DMnX9e!E5|3@rD0>e-wDm;zMhC9&a4Yoo;)y$9S*P7 zyVc<*&xVD?frM~IJMegc^@;7jAc3aGrhp-^{=`9%c9R>WmL{**9>TS1+%0j$gj`TDN+J-EvMXd%v>uX1?ZlO~l^p zs;9qqhrKUG?JCvr%4P=xS^N;m7rP7vS+7$yn{RAvG_KUWZ2V?#ARUIRfxq-bb9~U}3x}fEC)~dNs+rVHA5-Id>+3c91e;d* zWVIXIP%d2wZpGxbJ3e7Vnr0=dKat0Qn0{XUWXK+(hFM0%6M+UDX_D)dwYF0lO>*yc zOoXECf_Hz~YUlHNijk*YLs>1yKh z{aWjq`z|CU4(TQ&Vtb+%C7yUPKt0g)yalpZZ(-p{ht8&fmB1+hW~H(WcZcOM2YTHD zQRq?Lrq#2xUFJ4gc^=^Z1)rwEFNlx5&cDk?j%QTQ?BY8yFm#P!wyBGHf*JvD@^GY1~h|VYAyv;JpnU zimcf%)~4d892Mv-fk)68MJXZm9v**s+C={X+y35gNV?q7AjaGYSv^Z*-G1U{oFE!{kSb0<|^E&QOq6>KR=2)Q!4Y~lw zd#j)wmtoubYHny0j_yWiNXbX-%V0(*a^{Ap60)>qKrVJTHR%YuF`kHCjQu4Hgl77d zc{n_k8MzW*tB8MLO-8hk7l-nST35&RtSvJ^=EnZ4sc1&6ux)0<{!XOW}v$Zy^ zuVwq5!Ae<(TZT=d!RlFUEgN83%tSL@7-RNJf{l-{wOeL>UNZwGq+3;+)nZL9WFca@ zYA}doCDcw$9fC8nRa+aZZl#fF92cbhj2TzfW3|GkAkVDHApU0kqf_#=*Ko3!xmxAH zJ>~_Bkx|EzKPiJ_6iMV$67yoVNgi1Sng*sC*Phx-@vN=ZcwsrrSFW#tliw=WgvKlE z5@0n|!^s5*MK(4oq%lTT`eMZ}_OXJ^&6GuMz{uJdzvaERwFV<;lzwfnsS($!X5T3m zwdlhBH<|&fmfD^U7c4sb=n}L0&5)UK?#HzOk@B^b*r~b7K5BA(o!8?!X{aJvv5$AM z3xis%gV{@rhms+z_+sO2u=WgQ*lK%CZR>h%&sJ_K8++FB8YPFtHA8qUz?0?EG1k|p z1eT}RXuW`lalVG;HPjtoH(@;JnDK?J?zEO++^uFh9fKBVz$TOrenO`RodjjpfxFNA4n? zyq0slVVh z9`X`b!8X;&l{wa{ESc`n;z(kCnOA2%BzXF++_3TLl-6d^Coso*h zH1p|`wls&xjs%Ym-MhvjWcc)NRmnEO5Dl?5MKBL`Y@uon+DcJ;LB4 zBC9iSuW^`sRDFGcK9kPcH_eAGHsD!hjoKBx(V-KJm4{td>M8_ELpTR|scGG~n^I!M z$4P`P${d$p)z!{Or_5dpslC`PiRgXk)D>-Q=*T^c8e2g#0iKaA)|}Y#X>M2+7Mey4 z-6V!r1P&*m#B`M5D;y{VBtf7l)tRRZD;~O64rq**OcW)VroYSK1L+oi9L_!+50fvdzTDa&t39LDybLn@$y> zDdn2XBD=7Mk%S-MdM#W?q97bo|HJUuYeiC>op z3TevTEp{hbfu)vMFsNJTdS`^>3(Bsch0Z&Dd#ErZYPPNy5A#ZM}s@DzGU8b zp#i^V`b^U)4tCR?{~l(~p8wvFBlh;~r=Q0DlWf~tw`4oR(Rgv1jq0T}A`CBKrsxY_ zc>D&Yny?;p?i@CVKKHj6ZNebf9?4Qvp7=f~UM z$HtUw7lx*8-@flYE89oj<>uh+`|O)f-*=zf{_Cf=t6%>vCX?jU4}U1z-@pvjZEUku zzq8FL*|)Y?dwqWU*FKNwqIXH{Kb0oBl0B(p{0HmDXj}v!`McY4%YLKCN2&de(XoW>cz5hIVd3e^U$&q9tQHs*uoIB5_lbcmrH_2% z=dj#%Pg_dzk&j>!}vczbZ#=z5aTJy)lJjPiJpFodU4PrYvf+Z5#1P)R80A z`!Ja}Ytx+b|Eul$ZqrC!f1RF-bMn@&|GNF|)4%t7)$NaL|G;h^i6Wo>PeJVe@?{j- zR_kWl+dta2-*{HuwLds=-!EkUYWb^T-~GW?3HY}u-LHO??ndG|2}y}!`w{!jZS1xEu)X&q^3LrKd{%x$X9U~xEEvu^w||U)KimF6Rj#I- zAOD7I|1e={bM4hHsLeWTuBmOd>bKs&dG-8P|D&B7UQ1=Qn-{0XX%1!j4gG`q93O2t9IBJY?E0wjIn8_rAyPfwX4!WQ_oF8waS2dwWyEZ z89?8p)V}|Hje#Ebig6b$^@qON%9QON&nu=t%7%ScjC*;JLb~t1i$kUvR<^(YeR=j- z6-r6;v3sfTbI2?EzX|~EmE>JCG$_;fnPc3(opHXK`4n&0ayGq*#=hF8-EW_@pI!d+ zzkczX3%~z=GW8938I(TYfVnypHN5tc@?p|OFAg`M|}GETE$ zIA&RKeCh)0+)vowe&K*;na2mD%FUSxv0{v46{ibBeFKL`0(eu#i~iaqN|tP>bjeMH}P)q1Sho?8}2em~BZQ6cBkRUzA!zax%9z&;&R=)kP<(!;~~U zN`ntfBP2|5_3*0@OI&?LMPhQRK*N=v_W?^0^^-s4dyUPRV2O?g?;SH;#A+OpR~~jV zWompa#ha!?DrB0m3XBDpq6vc|DN{JCSks!d428ocn`^)S(z(CaB0js@*{j}>I+$Q1 zU~a0-%}upok*$nTVtuW4g@6UM9b;#ut+I37V)@#*Dr{UAndz2#ao3A7lrXo5sdH!X2@62A*mOK_h~mfLp61&`{- z3B`jF3sMVj74p8BbV-tvDY+e?C9Piy7|%6Gd@qn%p-|%6?GPg=Ub{0!V%aIM-R9f+ zZ_A%fs+UyB-;&Ru<_xg9HR?;<$#7-`EWGQly!g9)C7BI{Uy~8Uh}9VOr|GnVVw((ei_4dt|rVJ-|C#cl;X-D zJhxO}GWeyECI=p$VLSHFwpufq*-Rx#dY>t6(dBY%e+s3e2LE=c-*5l&EXLBoLQ|37 zD9ew7!3%|cVE^Vsp|kAdO>^@eI5^As-}xfHa6C7ob^P09K0d=e@Ki#})K;QRJ)=p& zJPo?QmX@Vm#AqR=pnZuC&83hsk8#7zLf>hNTuPzid1z~yP@}0$!6aegXHvEx6>Sov z#9Eya<2V?st|2+Js5M6gOl_8~sHL@1 za+qT?dC6#Bq5Y&elM;I+X2WmHV#qvhVUaDROL|3I&Thw7m5)sX=mS*=Hn9euUPH0Vdg(rQ-4~OnE)!R1Fz7(p|#^>?w@wUcL?Rp}2x! zycd>U-^+PBwv@Y;4mLHBU+}V_x1xmG z&{iTf6*tiYmCP&dI8Pwfq|K-nlBX3}JbG?6C9ciDD$w~Ntf%piG6T&Stqo}F(ibM@ z`IuHI1Z7^?L*emC0nir#9&8gQ5`o76Z?A`=%S816dYUdip-D(eIypXr+#gFT>_b%0 zS6&4;H0P@jkB?td>v0SjEI&${AJWCJ3EtL~FHjZA0*1 zt{;er)g=YD$DV^LCQc+vc&LmNc#^KF9QnHkMB#@u?SK&pNLfR1{pFObf%sI0`q%}A zrWF|B;x3waVni+e-4J(s?!r@ge23;12uL0}UBh5UYJqD;l&;HNJsWyLliWx)A|55| zfLDTE5(+!C-B{f1`5E!MGVwFUdJkJubJf@1&+%e|geC*BCo30&j2gzr1`}G=WclW; z8HS7&NeotXWcy-2U+lzw-hO~~jFgj{$wsUmX*Qk2(_=?!+Q5;ViN}VUZDw3B?B~wJ zeBx@6`l$^kt9-}YXKS$DKf#OcAQvV2d_=s=nHMKqyv_n~gO>kDHt}~5$_I#xChJQN zzEm-j#cZtUPV(`H;ex@#7X7WzAo2A`NQ~~4FFxerB;%77;szNnq9mCf*2UF}x{`v9R5KLS@UL*}~ zT{u0W{ngicSTfA*Y54dYF+6ZQpG-D|{yZU|Y=VipK^;wy-Ro?hqmy5&uTsT(V@t+YO4Y zy1v<4a_zjCT@MnL8eEjGrRLcPwt0e^%1K@z-W)>GIqE&d)Hd=s4@$^S(%??c(ub6? z=IHh|2JNnfh*|y>lUQ(Ka;Hkt-u!izCVidp*&0 zcy-PDTFjmDt=C};e8EL&@6qM2%@14arW5Wttx5xpA5_suNedJ(KfCmy5;3bplc3N1 zvTchA60Pklw=7~J(}X=3nBb;9PDZie>#V-pbT>yX0@zBQ(TU72s(vUM>96$Xr3;i7 z)-uHHfs+^Ij`1k#@Zk;L%rs7%7k>D@cG=5~qvmu^Ze&~DWYfzO)$|gA^PZn{W|r{TMf*ox+3NKsQduMc z@omzI-LbbTm8NXf{%DWuT)MFA4W`qqU6xAVuD0uS){P0Im3L#rmXsd6^-eB#har06 zUtlEZO=VBVZ^`A8V)aYpPOz0w;ocsm=&-JpyAa*9PtnGRX-jA~znF^Ud?GwrIDH-w@a7NJnn89$(dkWo2bb zj6v!QWn6ubmjp&aJ%-qid_Kj7m1f}DYQsx`M#n^_Pn`+N7%c9HKuv~6MYgyRS-W7fM;}|Fg`KuT8EhSmZg8U<2Wy&aN|kOi z^{(H?KMnF4y;!$sBfB(U>NmliG}h~HNtnf&t&B~j>nJuKDdmux{*=CJ`d-?3xW8f} zBgR7mSCJlfgI{@(I$E-i$;vWYy~S5=R>t$1nId87>!@nwPWvvM9?N6jbwJ+h{D0+Y>&QZ_^;3VM(&O@@TWa_U9}Gd>FIx zzwj87`l&}bICh6uvzvL#-<-a9Qyk48Os7H~K5k-r)Egbm^T%Hd@<)42C9-g^2dz9> ze^}bS)p%=4LtJjJ^ul;(UXmE7sA<65TDy15uTw6pb5N6O^HaK_YttN-rx_&e?sy;3)eiKuH}u`%e+ioH~QtZmsYb@``Bu$b?}Kb zx6CKn>)GmPnYGu-Quea@6`PG+D_;rmVeco5kL~G$f7!%V-V^zU>aP3n@>$t4dTvo} za=erMB_qEyS?^@0mTBRP8bQQUVYkqvwY)l%^GE1@cx1J8YJA6bE z$3VlZt9p{dbd;n#G3LheydJrMY(<7qq;D=mVXEo~tD5`485aVZOXxmp( zpsuHZ>hxl}##)|1_Vdk(8KOeg(6srNuV&-u>11^mBe6o8F`i+PV5#$mnJfI|_ zzbJfz!~6m@8!Qgti(SJH++YQX#CXyJ7>XD>bzd4L>77!O)O?#_K)o(e5KDD2@h(%G z5I^pOd}tBh03itfNg>i8`4GftEG)fs@lIT-nauJ~J&Z|9Lk2ct^w;7<0!xX2VhAFP zswJw{3R1Bp%@<5d>={VUOJ%A*!Bc?hAhr^E(>VP6=heTP8W!$F_!&K$n&+8_;w3-=nPMgqL&=+17+fv2_J|R~v#6{#J zb@kC=SG&{)eu-;I?>(T(g+UB(PP|zDi;O6BAjM&^ zlPv#9jpi1V>ZngI%U&lFAsSsNf~0|omaB7ff}~o|hP+-7aM9HJBzy|mY!Xwyi>7v! zI8y8}W8DQU*SCT^m{T2*geL^_#N)+$(5cw-lipEmK&SC8Tpy2 zO!H{1E?$QRxQ$t-;V6)hd$^9C{!x6M$swA>NK!A8|Lkm_5V{YeRERi3K{qbSEwbE( zVEh!Dol)om6Y>+h&qIqP3s~NNM0qJHtkAHq^P}LSH_|gJP4gVu<%_1bD0@OQthSe; zb1UAdHM01aZ5p!dmX@5ck@j}|k22|vBzy>QR8TH2cjJnCi=ytd>&s*8kr=-yhBC5| z0%JXkNwtwC4(QK@1OBDuJcQuGa$o3MEbx%i$a?N!_|zPvTHK>e7bB!~^!vOYg!=Uq zxcBm!p3FzB(RF@0!8utJdq}I@`+m2(B(&acKXdupEftnp$F!2?i!#VVU-&@-K|3Ft zi-FQuk9^ZfuZ&n-?vCIOjPttJ8l}NRhZr(qyCX70Tchzu@e|J_MuRFO(4Z;1hFQwS zXw`#*{+C&vq@o_}0lBPup{ud{97^j3s|;BkvP>N^E56!lb#An@D-zV1c9<;;%p8)C z*82h+Ge~CL{>KrHcKs257YervH==@hJi8 zP3pW7OrSGk97@C!nwvn!MeMrT{0vs-0UkQ-riO%zD$dkh6dABYRzK0K*9X&xL@ar0 z!VChMg|ZnscFn-N^wcAffdt*`g%E@Cs&!zd4sk@*^?`TxQH|#Kr;p@DFwdW8%OR(h z(ZMQ%O6cpHs2(OuWmyJ~iU@-><)~YQ9SBKK8zCWR!FUbgT#wO_*gC4GktY(9lO3H6 zbuB~^%yXKwiv+L+((wbzl%a)R@vwzR_`D~f;*5w!33SD|15r`NsG!do6ul(Qy!!0xQ9NDaJz%GrX@v(;fidxFZ2_tK z`-E~T7PQFKEK~s@J*XCd5|MMn z?m)&|CpIWyM^aR80dVs_CtjhM_<}yshc2{Gww1XpU4G(&S1Xer$=D5!WoC~qlGH%d zYE&`vj6`_xmyV*284+b{MA*R4Vq|<^)(gKCuNU_MD zp55ZIboatP4|PRbCnqJo;|b$rzz3GL5jMl5lAzs|X@NfS2s|umQ%Wi9rR8NxE{f^U z0RRgFx*GWlozzro6bxR83PCiSKc7l6OIm3FJuW@e?UO(45W4{>(MKP2*kOT{g2If! zhoCCJ!mz$Lh_Vg)I!7q4Ite<` z9#YgdbYg64-%IVj4Khq~1IEcUKHy8|jt;7{1h7y-DtMAdrI5Nag9RH%nN!rh3W?UU zXe&~u!Wi?suqb6UK!ssHXuTVFc0eVD;S(|p!DO+hCnaiO@ZV{k00NrgtQLENez@R` zY$iGe4^*nMWgCPSP|K6*{>dInrmF1+RyD%x5G15jyhf=NS=AMZXk#tXUoV8rrTMZP zJS!r0nhjxB)E$PVvQ_yDNTEQC#B3m;TIJjgZPxh}tGFSSo-~X)$krL>ts783`mU9w zC2_S+_IvKC*cbK<#T@SjiR-)x+B{oFnhUHSW%CL|x8OYEmwO=3>h9p#Rm|T!#PJhm zYZr2AzQ#(3pK(28Ke0Fz_pw%%FQL&=JzJ>fzwy+ey;!deSi1e=TK05x1KP=8>OE!AJIv5UgCO)b0n&@;8xLrZpTVbd(s<93{xS@BEewR`9SDX*B@lbA`;ZU;My_AiXnvB(73@_SCo6Y0YRQ3v8Z8Ki9*k)Uh z<~64#fJU`!aW(JwUcTVoX!-?t^J5rrYvmVde5-k#w&#u=Py_g{YM(tynSPQDNuJewZF8@0t+oprxwaiS%| zIj7fiRyq&`W{7xYg*;6NO5i2x6A~FM{==_`jbgl&R0plX_QOk@Qff&U?}5vD={u99PjSG@A!aSXtH4i`kU zzcn&BmxX>Hl4!bP*e7`r&)$w!03W)J z)Y6Xf`H?5o61gv}gL!POhZhdYnR92)o;}y(MOuFKtgoN#p<3ov4_teK?ZvvI4>U-o zw~hfR@tYp&WeYMIQW9CydjY)kUE`padXrc5^~Fu`wBgWv#b0Zl6EfSUi+A3T5ae7{ zNQix`wW||HC+Jj-J&^gn%dfpwe=T1-+i3Z$bzpeLpIzVReUh{Hmsj5KZ-g)CNV7sF zj+5SKY4ge_zu330#9Cc2ptgC%bx(ztrS_V(;IY&@bcGVE5oI;{*%91JJ+b5 z@mG4;llFnutD)XH-HG>0PabkFevFC3FFn`0_Ef)5QL&+St@TlMm2!4$0XK$}UADQn zId+=_Qim_T(C1(%`=nopuPo%@jLR8FE?1d#51gqpz{_(d78~_L@7;uQdh_tn1|k_EDdteAYIahhlT@8Yi%CY&>z$b@G*tudh608gXKLeOzl) z2X5t%_b*hdPvy0S!Q6YS*Pm%vcDMf0rH3eC>tZ}`zPZ;t1uT6Khv@hDJ5`ZxKFEm)~pDmyFx{MNmzBsZpXAT@T zd40a1)0n5?Jnh2Q*|2Wpo#Kp+GuR=bs&VLftfH-DRb$2WHf%K*AD}{{1Pl{GFm)v) z(4RW>DQpZz4WgUQXsGLa!=rNX?gY#?n11NFzVQ$&j5wk#90CGXP+lVj1|VrDLf>|e zir?S|5Hg8S_=Cs-l!@Fr-|eo;6HVLbHN2IU$W`0EdrccSb%L!z1f;Aa?TxH3 zASl{&mh_mSV7bcinOku^@0y5rOz*A{nA8~6@jU44BlaYbM9mnbxt}4N@zHnr1rnP- zg}pKtDXd;|TwQ<3b`I>@w=9jTrrWM()3>INTA?U|(pWTAiPw=#x_=&=-E8*k^>8xu!bv(>;Jx3V`>5^pY%h4q z!iEu%x*;^1_GIJHo@@4cE;RUU6lYgmmuhUWWzx;E-&)?& zWC*LS^p0(k=5nJ)4jU4zr?#{xCAey@*{yqV4cnx{(}Eh_b=3@8q)J0my3*{4Rt6E8 z4e1H9RL^;eIBF()*7_!~7I2&@BfXp0z~fC2Ez~qSS9`o+uG2_*_C?E!PHXugtOO0) za1j%1ku1WmM%}FarTq=NKne|?HF`Zp`#Pn5tkY=p8f14Ex(#Q$T8pd^hF&O2-|1ex zYP+`C-G6jAa<*Y@&mD6O*Q_=hzR~S^AzLUJ8*1%M#Py~X%9f&S5WArbXLZ=PO8I~R zsYfazCb@+(pqUWNih-4$vT!(Nj5Z(jFrXFgjA$|H$3GEKEdGM%UH@r+6X>VS^d{`hp z>8jn*4MoAiFkqHVd|W-HVbJu~K)Z^?sETMtIIznta{@YSh+}R?rEE>Mu*w(JTJ7fQ zV{Zw+7!+3{>&KcdM5B#86((I+WluhMI_KP3vaMDPb77H`35`rXyyyr6EX4AIw$U)m zoa$&`JeAk{=0=oLSK!;o|MI2SUU~41tyWeW4Dv16G~>guhB-0rm~CZOj&#??c5@hR zMqWyUtt`7bwxhht%JdCR+t+F<`=h}=SmrDHHU%U9W^nk=Uo!i)#`#vwtUbB%(9P`d zT7K%0s7A@IY?xYQwVDmbhu7)+Yn?5OZQSG~#q!!(J|3*>8;n;R_TjSe#@dT<_{`ec z1=Fg<@dY!;>YOi*4`Z5gFu(-d=9N?HgY3%S8P03g2ZOCE7qHK%zuapFzBy)(m7C2F zd3i}Kn@)pER<%eyjVXK6-b2=ESfVp)doa2twVc%XVHYf>Vf$8t4;GKYwOR%jeO6VoZ7fKeI^_} z`rvgevkk&}jC=MC1_QJiz&|2NNg@!! zyDcpZmUh|(xs}rkj89W;7D%mIdChAnSWaeW`Qq$kHKk&7eP9pDB3d(G!clSiB?!HO z!!0;r1tacMx6r!TQwYhmbZ4(?mcXh;=!9qWaX)I!Q0w$k0`= z7A`ClN*RygOd@nRygmp>Ff1NkHO-4;%Mi`a4um9!MQuUa;S6XHi(L>wlrtPbYX+K& z`q12`*rZJ%%yn#AWAjGgEz$}mD7&B4X~|r$5H;u|2L$RGZ(EBLp0;Y`Ro{Z3!~%m( z74C==lds5QEwxNu<)KdzuVxQh(|{#7i6m%*>qA~H zY9uBh)gq?6ug=ubtwIS2Qy;}NRvJ$`QXMp8tfeHQUHpjyM}aUMHDmJ3WS5@zdCYis z2kZ1$fS(~dL%o{yB27A|eyjXCR{jl^E zw8CXND7~pJ;CRn`NJ}bt=Bb*Qh)8Xf)HE55?q~@_o9hBwYLdh(+CkLpRDCE0J9c`2xu_Hdh? zt%P-_lgC$|g8zk7%( zU=v4*Y=<|~d^pN=7*T}`huHimazv#pr0gl9vn&H~xk+LP8cKjT8*CJ1R`ZBs@0T;T zzNigfHAui{GT=C`^c96>v;<0MsmK|yqD>IW*ip+Q?BXVL#|IPX)KbB-N+GO~V%M3H zdx{0l4ZZe57x51RB^6{9ibTpwH#ViT;&?Yj=FWo-8~P%`ML6*_s@F7#*e*uJhUuWP z&=EOBswiVQ0zsRJ@=z8UJEgGGnC4j0ozSQ(cLGx85Ww`Wa23-m+)djF-N8Z`59VDl z)HjE*Xm$!M=foMJ#iz)1o0^(>P-C(hin5*?}Id z>_Cdm0)8{4ThNu8D|a#Z%HpIG1l78Pz_Zj~PJ@KjsW@W9lOU8&eUuS)QFhmkhU*|q zcbs$TcAVEKK_w>$6100&qxziYs00m9e|nf&0NrOce;2W1EO<25EH8KJlqy<7vqj?0 zq^GH2<|$;C?wzsk2vQFh*F;{Hv9l|fgTq-k z*XQt4O=Xa@Ca#9kNRW|UHBr-QYETWdr0I=m0CgqtCp@XOQzcH<#eg;WXMfpXwl9f%#h+a_rAXcweB4@ zCi=vSx>b6Q#k2RdoAysigJkAuyr1M9^B4VsJ-O=M z2iw_qziW(q1_Mnf@%ZD|K6?IpGiziOthr5}ezv;(?d`8uf4KeSFITs}Q>$T(>?>;R z=b!)c>VN*v-`%c$6+=QOdFu$Y4}ZnJ`+Lch6uO!ZlC4_ht6!~t%YPL6Z~yQ=Y-jKO z-tT?B`t0|yBK5U#p&Fw8ua9oquN=9(ZNKGz?>p5aA5m*=|EBj@K5$WsZ0}&2?)x{B zm9{<4R&U)rf1Yn(NaF{|PTXI$Ka$-#f+?xn?>w)Ch>@!C-*0dKmRcjiLBKn=&%JKH z@SDkt*(fy@MZhn9BisHml3zWKNxa+l5peGH?ITsJrQNEkO{l8cgu=nr)7%JDRjst) zg{J19k`buFN!Fp%CX`JEq)IDNsa#4YnJIf;C)r4P?#(wbLv@RC&c2MvE{YR7OlrPO zzWd#o7rRy4RzvTys&p@JU(N1OGe4KzG?G+vQ2ZL%&zeSAjVYm|#=R`E?dXT)t1?EP zOexSxmT_j@L~G;r5_WIxcjWD0Gs{vbnmY8sIQPsEdgb;H#vKa&1Z6q z`m9#l?QFY2+xoLVd;CUr=t``e$VQh$u~uFun>>^s}6yO@w_tT47eZ~t-o7k^Qhxh$ib$gu3#%@Bpnan8u z`Zr|z-#`12>>sf*mi^$rZ2!2LET}Eiu=V!lbSDc5OFcJXsY8{a6d0qI8cL*-B`a;o zHrpTk0iEZM$vHiRoYHBr<|e{;K>>e*lkCs^?oK~UF-lWy^gjCByhmpLaP!uY>Wv#} zpORjR_G;YiJVq98+@QOu^|iuDhSzk2EV^LohiW{r=%A%pHtZ`Z3#RxO$L5`J=1t}I zzE1U7s=ExOHKuI+Y`uV z#*|rOVK!E4X(rNR4M7F)jx38c?ZiqiY2~xn3(Y-(2)6uk?q65VsW~_nlb@=xDEXBA z=BQbZDna6apv&-JmGQRHlwm4_MeaCq;{aQ5P$PsaTNN#tPe(ITQni6Q3cO}RD`Kn8dTgLD zh1o&`qH32g^{JEsinS$W`Uy&xRp$RR`t48H-!IpjEIQTt+V3x)`}^Id+D5t>T`rv! zmZ^9b&L#81r)7c#H8kf>u?fzu)Y36)N;nkC7%Y@MzxVm)fA#s%^XIylgTqSOf?{d~ z?Y9@cnGC9Z`U%wNa|cnsz$SyD?JGgh-BBrOtdx|kR7Z&~)pSl8cPwHNpKPBcOKZs) zk(%19))L$eycEV8N#l;fOEetSUM2hcIMWubBY{j1nlYeMUN z^M+jVVDj**9a-`qvKTc6h?ySjaODuN%P)trc{}-_M6X2o!_OUlTQT#g7eCj!l(2_~ z(u$Bst)Y(s%;BjbMjF5S;h3=dZSacdo3vv`rUkb6xksa@R;&Nt-|deD?LVA9P++Tn z8$O(LF>>)n{gUb@^0yuTCB@9;;e`)H%@N062K^Ng`5boBc$mpAbh09s>1YZ~lNyE7 zoY79lr6gt2oY`v&8Fu0lE%*O-iA~9TQTr|8FKIrk=BuDF=S!i%J2bl@?#+`B3;o() zNrSjthT5B6+fdTV&q6hgGRBNg`gF`f-Z;$C_b)RYsPBmF=mBX44zh!{WqN<3hQfG9n1wn^vkf)A{&>7PrszJmdjUXw3U?t zBV8$_JcGPs>rF}GA5@nlyP6|n7jGOC)r50`qtiX1V7CXefbYsGO2!sR2?-tUe2!%=yN>8Lf{w!cv!w85Vwbcibf9 zF8gm9UO*Xlp2mea)}!sFP_uSgu>`z{DX);q!GHQ&|+H`l!*&AmEu=R*+JG9vGI%>bN5M!n)! zhwLs?cYkD?|!B;^&V$bYeY-SFI8RRuB>jFWIF)y2}eD z@QaVjZnu6-GnaZUvZXxQ66(2O5&y0CdNsQdVhJg`AEni8BC;@0oaSch?jRvF?C9!CD zB-%icIjH{c4`sPi0zjEYqIr+7YyqmTOTbe?8KLmS8TDs;dMPTgcyqZEDXO4({qE37 ze76UD=8t#L=iZ_IeEKf%iknudR+&B;*{y^oH4{DGo)v+kYa=D( z-JDHdbt9JRQi|lv+QBS(VU9T~i?!In=Gvscwpg$Bb64YT?={{cOP4fLUbz$O{De0% zXIf{>E0SL{qfPxdMLeU4=SgSctyg$`BC$@ZkU%BGzTN}xWQ+VddUpIYH>dfTUAUL5 z$-RB7FN+UEjT-q^n;5XHAFDN2YM-;_%-VKzil6)qPp&Mi#E>tbl%qM8U}eLjBryOc zA=>|ls-CxS5*vy1MvLj?wqDv7! z;Y;tcYl{@|Yt050*%*FLuG*y`#e@n6#Gz34^u`(O1|fG3h-u_*BuL(GmJo0{Zy4!E zus&TKT#dX&`%DS}z@ymwOW;^QFQijkHchY4a&>;3%m` zTd|)CDj&^wH>Pkss5=7^j5?0*k~|CYGi3G*1rqf!Ri}U+GH4wk`6>lXT^}&n5xN^`9jN3o}OQnQ9Q-Pn*3##tH$8kXg-LUZd82fHpfNqzOrpv?N1!IO3}p~|cV z`C0f->_jexbi2cGK%}9oLEo#`M_7GzmoYwQ|46m=lp}l>_P9Xt_-Sq*^S^AoXJQO_ zZ;El4AYr6@47>ryj~(exz6M)5afxrWraF;L8S5tmt=6X$S@cm3R&JcOCpu&Hl%n&RFbxQF>H;?YUq zLxeshvO1EBX0aDe#0#_mb8?TXc)n;@tRFpz&9Z~{H%~7u8Gr7g?Z`@H>n*OwAt^$sf#~-Vt?!|ultMg@ofKJ z1iosCy*}5lySb}$WU3u-a!4f)We0-hrH|pEx5nM3yMO_l*WX$`Bg@Op znlvw(l}4HXEseE7?7HXVjjA*i>&F#(h!xoqE+eglOn-9IUU<$*lkY3&`uWHQKVbkR zLq0x7?C^4+e=txw$~5&wOEcDTn_c=%Xz7HP>@*LjSEg^RFWtN$FPmPi({=gL>}Y&M zuG^R|1*h}KjV-x;eb1JJ>xK%Wxu9zZw8K?W@w+4%5&i>)qe6WqEqF#q{LTLJ-9d#g z^EO}FSh>FFFI?mY0EM5v^|EZvO1yCLY>?o**eUIF7(xs$eQI=?5&BWiC>wh!3<`W~ zC_(Oz7;&g!{mJL<(vbGv<%7m4J%;v1!YII}w6re91MXsUdR>eft~j|6|yfPmvd<(FSZc^}U=WEYd2GdE;VrxUyV#Z$EJKsO7Gc4Uui} z=2=rQ(bb|ABw=u{KR8;kt?tUk)YxekLqsxVS9n@4U71bkT#~mUr(9FoMSG2Ws)gh= ze@em%U$l|Ti@Fg%?53GK6qxB=;7X4971xb&Q|>=nyV>q~f8aru0JW^$evQyqS`RZg zWKT}ogHiYX)n#|f`!1t}YmJ}sYj0n^`k{W-UFmm?ebO1@)KZ?GYHxWmlC!Ina2!VI z%h5=gjr(%8ztWbG+^}T4P76)N!`&5U&n#1w+%Bz*)Id#Md1_+K!D|=9v>#rQ>DEKH zL{2#0lBHFu!MiAvIG*Hut(f2B+Rq~_W34s>N^;60hRG0PuHq#3eP;GY?Mt2ya89*X z@_g$tZ`M~I&X!vnE?Zk1T5ivniGMJBRN6t7{j|*h7%vTKemafM$W&W;n7S`aWe3`R zUD|yadhw5Ck8sQOFMU>P$|L!s{Y|lbbENIpvKxF@L7!=4orYl=kNSm4WaiJFihQ#- z;^byDbPrdu>+Yg+``jp7@4pJ#l@Ka)(g2-RS+q1*+tJ>khM&x$6;J0e5=8&goCA#;_9WKI zQI<0?Xyl&`{%)4%^nJ;5i8{oskY3Wy*d#A%lBMJTZsoz3hLu9`G&c7|tnWKD*$XGL zhMM`2*hSV9k~^$fhg?8LhouJx8F`vW!+0m5Av_6rc?Y<4=bzvC{!h1H`PT@Uq4+PCPuIvGD2@b+Bb2m88th!Dn5QfA$ zu`zZZGg02`74ogX3%h0##GrwmRCq{q96v+u_1qOm#1eFu7_l{*~Hdup*L7WL*AQ6M;>+AbuV#(x6ja_bT?2I1#cdd%M4A~7DcCo-dK=G73H?; zX@C8bSP9LS$Sq&{2IFOY#Ws32yI*rw=0;Phh>uf9*xIDn_UxAt?^7vA1oZ>P+#ivl z$zJm<wGF&Jz7AKP(Rmbx--VKSZ-#=EAnDRXU>944?&B zVi;m0HKon6)Ef!O4%Ov2XJA{pobkEvR1Vz?_xq)M@qSj3^cxPNDe}~1(gFHO;*la1TUYF) zW&m?_w1J^VBD`%pI$+QlX_I_Sq7G1zLwSXBay7wZr$8V#OY4MWUTg?1(vd^#Q{6sF zZ|4gX?JZO3Pw6NeRrxMnMpJzKalcDfd>NzWOYs5iSh=uw9&!{e1AhS>7&>VIs}UDCsQ;D3DRWiT5!`R6G?=QSPGWLWwkAcspNE5?PzuJe7i?q?pjQ zDU(Rz%TRqxcHy9Lmp7G}@>6aUfJNaj3r-|F9u2jS<^eN?l*x#%&0pYeikQh1qy##9 zjzl07PUNAZunwn-Y7{HAH%jvm>zpEM9rTC|oZLp*j*jU;vI@QV|EKKjW92%s!_HIH z^*Z;pAFSJtO`)mP?p8OObdwN}mZ*tkhrm=fn@m%d<40QZas>n zB*6x-L1pDOFs{;F2$RUz7h&BJ6FtN-#Epssbv_J?U#ZFAl2m{|{~~Hd5XJEo2`4=1 zqqM&C(qrkTB}FDPYl7xqM`)k;A&g2J0)N&kYSmE)>Ksb0VjqT>f`TST?f_Wz7>`1s zO6mD3W5nLnX=H*_(!RiBK~i{j+(J@nZ-oXsF$JQsyiAj4py`(5ndVu`I7O%fwyY<1 zL-+`xB$5U#e1<=~4kh)IT2-EAs}R&lvRF(g4y32otR!Vq0(RC9*MqAkWbz94Q3ZS_L~ zb|h*86v)j$*VNJ4DaS6VYZkiP=wVOM8{}<_{sc^VP$X@L87czO%97-{3w{?>3{gNY zDG`f4P6jmO!%$?VD8~-bwk%uFMM1q-B+M5+6}L`q*eosscArtJNg?oW#&aU!Wno>T zb1F+bLkVh88pkxlXIOeRq7c%;MIU0l7tTx-AsdBW1S?HUZWfBKVgNMdLOYZ z7sz{B0`B26LDy_)pymLR(TNNcT0)(Yep{a%z9@}61Am%QN=DOETEvCGGlAuJZ;A5^ z>GLUc1(IBskboP6jKrb>eE!Io7#0BSQ(eL|p%BI@mcQ=irCD&HCcJGuATDJS0jXBp1Q?wu;BEN~F_rI(mmUmrqj@)#&ZuSzhgtl>q0h z4W8m71_xpz$(SVGPU5wbe)I@>I@qY<1G(#iRl&QG^UI}LzGGPpmOP`TOdBKX#QVco z0r8el8ITT-0tWM`9k#@UlT^SR=?CGTm8~JsoABKcQecesD3Q-56u5K2dleCaL%bWJ z*~)kz;{Z|Z>cIQpUA-^X4WpwqU&964t zGhl%{`|`OsGSBXRr1cpSk96n$YUY}Lm54J{n$dyr$}9Cwv$kpu9WdLZf9d3x-NXCc zxl?DWP3t-EJ&OegR%P8+_aD*jW)3lHO3Pb1>_*>LvooA0XN>inRm)1=qNIo3YQmgCI z2|jL`5H4`M=^BhGa{W~XpepA#7};sc>{;H^GQM(1;`^`WHFnqJLt;yQayV$T2I0&K zU2y6o%FF$DzH!RTR@k7;TdnYgEFUrNzucK~eCnnhGjC0)=WUTM$#A-T$hqw(FHw1o z3v3g}po>-Vy8WewUl#@~vr*kP`t!Eyw!ZS($%mVVTqlgDwt>nU&drA_F5Gz|h}@pB zL6k}0-JgBMjBj(oZ1y)c#-7e+bKWQ6*Vb&T@kS_!fi0J-&e1yH1&|}#RsETis$ITOjC^`?(~O2%(~Cdal}82d}U zRX3NO=B#rpW;}WNPT1UT$Dcmx+ibkE(cz8i;h*esKxy5P&0(`!9baVbrIb5&oaq>f zN<1c*E_P|$TMQ#15J|nt`lKWKsoY1*YB$!_rJ=c+_^b8EC(nJ`US;9B(i&66lgnnq z_E$nnXC4Nk*T+Z9cB{{6#F6d&x7>}*?6mb?kkO>uvc~wv<&kNgn{y3l)igqVot%^I1xH$N0-E3h<;H0a&u)=lf$D43;nSf*l4m%FSn$1`%wPobYo+a;_e3x2jv!b^pli!|Rxkbb9vL^;0*Q<}dq~Yre@S^V*0({p?ShQGWJ(KA1G!>n(;= z3`9NMl18m|=;5P-aOgm*y}!1x`t+AuOaw>sr?JAr&BuDSNl)TOrFAN>{006Ze_&mq zl_gAgKoGo7D*%yOzSr@FP?6S@J+&e3*1?%pYZ&AM1_<`=anSw2?fSDuY{*CLwstfp z79&i`W`z+Lc`V&kwh21nF_CE;fG32YnAa%|zb7R3Mq%#wbi0~h1Wu*I-kLoXz(*K(>OJQW5{MpVhI1Z+9jHbSK4hdyxlV>|T3w)hZL zgO29NStWx>qX0nhnOuWARGIAHCy)42JD) zr*^bbJIL?IxOF;=3_3#|?ZvPMHivhRx zlkK)&Z_E0Vu5*0NccjyOsk?s;m);Xc#x}w7zx7woF^H#-3~sAZ;?ZL z$7_QK&ITF0)9#-bxP$i2iRoZqrvp~_(M~Jd(@vPexZNKP(3Fyj)1i=+!2iy`)Y=Of zQmw`e91S1CdF{^8PP<+4$Ix?G1^rx`%VPx;TVTO#4(}t~AWWv&e zMv@0W4M8|4}%}k1^413b2_SS7*YJEeUJ&IIuQ!Fs%G9b}LUf;m3 zBHar+XdF7dJLKj}6tOXgL)<#2SUjd~oj@@W8O&fhcuVsK^G6s#kK&8ic+KyK&CbD* z{h(C7c&2we5BGvyVS5#^#MR3qt0!$2U_Ng)7R`M>*yK}{rdilt{q6Ypn_1p}9Mfcr`TCjq zx#o6^lgcf|$#av;jV3ML?oNA3X{iYvvq3>N1(Lf}Wh4)G3(Q%;uO<+o;Dgm|UY8%pGxK_V-`n8padIvnQ9)V# zOrK&Hjhg+umNg$4t-M?3t_L|& zaKx09I}A%|neUIb|r&d+y$i>Jg z7l~xL@I?WVL?(loW56HUCuYRW0v}RoXiyOrpGi9VphK%;pbI+Vq}p>SPbq$#$p~)r z(y@+kFV35N1kgmPN}k@W;17%gS`2BZB?;YA(FB_K11av3?JBfWD!Y+;upPQWRuPkzp}S!;fdbk)yhTW=k1``WQ4b(~ zudiQtLK&vqOUY%BXq-)TP=u(TA}^Z9Kyj_TREYip=9%_D!DSJ#9_TocY?L|CWM(C$ zlLc6iV3*ADntLA{aYIv__nTl9d zcer8Y@S~!p9aPb((rR8gyIa*ZM^Dg@i8`F=bXa3JFGD12xB}v%azMP31r2A^(cm?i z>3Jj#JF2*X2u$Mwe=I(5X}@Bu3sq$BFE1MZG70U)lq1GGdANwP1O^jOQ%Dw+!>2?E z=u5jNhge8U8SElTPU9$aGht2`+#R zmlD^&9VmXAOoNKx9V|ktI%V>5Bv$_lSIfh6lJ`NU5U?AzlTm{9;yQnS45YFa-Hk0l z8H0LuD{mJob=GKLo?K#!#QdH#eNk2OU9~Bk4}t$shz5KF;SOEU(pD%GFYrC-rhtG; z<18W7U)1u{?Jmn&AmS6xpNxVn)lUoz?FxZSXJEA*@fW2Wd5g@-R3qs^I>gfKRTqMs znGuZ^+PaW$ZmN2&QM6J{23hl|Ngc1eYjZe8YZK`+!=jUuqtn4E51RY*n)GLFJFxv) zU;Ej#Z^aErENBPij#}p0nhla>mWU~}ls#0fou=~)QWGUEFXTveJ@?bo1(Y@s<&@kODy8kBMP$P7W=ZtF#z z6s5h8Xq`lA`d$xBY4R+Ubs@l%!Ll|j3E&bJag<;3siOLq#sTpl zW|SpOHfhPi3qf)mA{##7MJl1N=tP4)T}A&848oX z2oGhRQqTt+&25q6-RF{IkCMxv2cA??0WOq?1S&QaG>;Hy1?n$CN)m0B8n#rqsE0CA zUnVsJ&5>ncVoc$QG`Kt36197B8qcwQ*~PV~LCe1yU5KWX$#(9-kP2kW|A;p_`n$A- zpeYAO7j5W$alm|!pX*~5Rf7I;+=P0ySoo;?|A}DE__J>W?M$wtbpMse)*X7T#*~o6 zCH7_J389-N-;yY$p$*oTA%Q1(3-pC=khG!nREg*oJQY&LiwUR*_@GvNgN{!qCWTOC(vZXv6PtSVu!s37rAwtuk{X4*3)F~;DFKkI!zrSQF!uz-;MOGZ zV#p2N0^pz+71sy_6_FGwJSoXtXKBMNgsCwbVHv?ZSz!QqAdCc6-4EM;3*l9Pm--EX zsb?dUsive0XRqb4e{~V-5bu1@G(~9+Vyw)7mI@AaT3GGVoF^b6&?kPlG(NFwMdG8e zaly6Y#vSZqkWVC8ZL^I(Lcqt{lT(hR!HfrZLn-D%=|0Huk-UjD3Gl2fQd8M81!*is z(UN(z_uqf$AuOmp^pL1i*itKvrzP*@%l7VZY)6&0ir&9p`v<@DC+oFO{mwu8-|av6 zXJ7nE?MJ`(fBq@hTR&}|dk%wFU-}Zsz5j=I@7lX}zx@~3^Lp#P{IPuDIRqqoLrJsk zugLrVce3Gz8p)d5eZi|1-tgiaJNDdvvTyw^My3AUdk_6{k;Tv7x1YX`ZMJ{=7w?N* z`Mnojko(_QLFfB#zJ>Fm+CzI0gGy@Q?FACTvJ?h?AO)NHRHv`KIG{ zQ`qIp*~QmysJ*s}uV-qsZA{z?+1L4dTZbLPO>Z&Ud-MSd7pb~$zl`&Zd~5~N7?qayvO%T=y&nrlN?_Q!v` zf%zy*yvbkwWvTcFwE8ITCAA5M6)D*M>aW1i`@Yq(`Y7TQwrkDp0sCsD!KYMAAK=~P z*o}CAH{~M<;B|Jp=!Yq6k7Ly~7G}FJ<@GCnqKg^z-p7a;DSp4&NSn2YC=GpKgb$l* z4?Tn(HtefO?R|iLbMlv|_vil0+Mm9k|F(Vc{`1eyWN%r2cANdho#-6l)@N4nK+LymfnAReRANxzNo^}*tYJdLLx4#X> z!u-Yi@*>#xd{4G=e?KpZ!+rJM|80B!ThEe#ucy9#|KDp^#QAT&Rr~FShMxnYN4`hi zz-TG&z5D4Gu-CToP|ci4-RSSWXn*^mPk+w-(SQ28FV?<}xi#os_?-Qf#puVj(!{cofkr7-&8=_5uy&cEAKtk9#v4T!ynF-WiKQ*Y)bZ}#h2*X02vd$5DGcZM@nxq?J-6(A zN%7J;9GYsA1a_OtPpEg-*^Qv5Jx9~k4sf4>*p2uAw#$1V^-ats7ADS8#0Q8!;KgoY zDz(H>|1J6R1*!efq70MvfA|~H-4&%{!u#@DzxBD#VWlmJ!bID#`;5^$y6h5vEVir5 z2TJH~;wZEFi8%@*aw&f}`4Z75o;-5$W!QOSdWeI8cnwyfxXuY)AMeF~^2)`=Pi;;w zzVvhB%1^mXwej`M&C21Gi<|cF?BcjsftC}lZpq_#lNIVOmd=m43!BrI-OrC%E=^YR z^uB4S1b3PAgO^AuXn?B~>cvUaOTH8RlnWAe*97Y_pC9#1 z(sW;!Y$nfnW0O|MDyZ17>63H+oHf*3*HOHU(uBA*HsRHP%Ht@7MRnZClAiS-R~a<| zV=F8wc|WBDXfOvuN3#V*DmvD$87k?HL|oOTl?lWldUppgl_>gUm8lNpqwIwMJnoRqw+Jw_WN)XCt z5ulPc&?RvsXRqR@wyVqT8Z@f*DVNE?7G3FmX$LFik>3O#uq?MLbT`w9!(BWtE|-46 zB|l$2)1wtVJ5zPviG%=hWtw{jUqOfs|o8=xxi6y$gm6(`QgXP)TFA+pqdz%8;ON8O#UOQ)Bys%eof-<^V~eqE2F(*td7^Y1*+4^Nh33AcS1 zgCGh<3raDOXw&hL5ptT|A=&OkvBz<`%$>;&n_a=EQDGwus}>^eypkkPx&R#+ESyHd zmTw0%jHHqcH*rS#2bEXvcy?z6#=t(%)O3Kitz>W2LRI+(uZ$ zu3J$3Lao3AAD3!i;2cr>_ZE3O^Q#HM|`d%29IgiVoigtQ9|^LQ*R zsC79l8x&Ibl%j~`1P$HIp88)%S7ksw)r26YL`*-D!kX%rBbh_tzVQRs5U7ntch zgOmiThj|5C#QG(R-(#`y>aU=_-?RK9;Khzky@&AFfr;xb#}nI4fsMRBX`0Tp{j5T zd3uWmm8otc zSGWqBk7XiT11?l$FXuG1YT#9oZvFC$Y|vgi?Ba#IDqEhnVzl03 zP0_}%elDi|M+-r`J<8QfVHQ~eRo0d)tRmbu@9-JPP0Z7%R^6Y}qV#Dx&4UcC%Nvy9 z3NOlY_k@{;nd1Y11A`!&hx8ZO=f02_$J!(V?SgiCxE?2hMxI_qgV*;0t6+R_CT@&P zIL3yVaB2OpWc@9rWB6b&mUn8V!9PtpxoZyn0Y|5R1N$NqC~pE7=LfmNx9*uP9^670 z#VD24Ha`;Bl0o2gksUB!G*|`L+%K|WkkftBaQV%f&R1ECOS5OT+}DJL<)yoD`RQ@n z&8j!&61(pn@Rh4r5HoU~MAKI%uh);rJK<4m*15bV)7X#xvHHPhu-#I*;KFq|)!}Mq z#aCr@&87RJTd3m$H5w>wm9oAnSHt?F(wovn`AlQYb8)U3Dt5IxP~$5M8mm-08#)&$ zNc)udeUu{If5CBBpf*C-7x!`J#*^2H;s6jEm3n4FeZUq5n1;^MrKE04WKVm32v%`D@dt6SS$CBGBd0UE?!Ah#w8Gdm=T z2v_RWQHZ9}u+>-*>%7<-tHY7Z%mmX|Pj1<{-+GeH#J8#1*RtD}9;0A#f2uP(oQK$U zX5lK4KJ(^P?MPbvk_}H+vMa{&&47lG-C!iRinw$rXRfSGu2f7V{a&WVNBtLvGJ1{q z*S?eYRxi9Q;^hXPHblOoxH<3x)ITBe-o&v!od(Bh?tp9?KM46oF}Nj368Y{eTp zcA;;^n+H9k&U$#aAN!B_Os;np{l!7umY(lzojQN)cNSrI<<4w$(XHfPyX51@zb+^D zFMJg!K z-&a*Ud+D>Y%IW%{Z2qc$u4<1xDXp6<7u@=!zecS*(|hb1C!VBxcX9VFsRLg<`_;wb z-TpnZWqusG#Hy@wnf9wC5M>H^OB2Me2X8Q=Mn7$Cp>G zVn^^ZENM*VjIU5Yb6TKlN0;08 zB4gB9v--?<;h*yHDL%i*TTQ+KJnk6kzVhf=wtg^(ee!Oj<1FhU=bo(67dH%2p0pIq z4utUz`dyKNZvq{iQHxh3FivYZQO6;q>*}F3oc43(6N!~R1FW!ffv)J*j30nkhs7hM ztAJ9#BDp$Xpksm4Suwqv@WP2{+XOyB;6U~Tx>5x7hBhP8H-YLaghr|fLa(ng5EsEy zL=QydU7512)ey>6jF)MAO@g%tnTrkjRQaTyh_4CBbK0iO-BU-5kVx_iMq!{2ArgGx zi4w?};gA-#C!&pDMA)tkNRDn2BfMLTVR<`<7e-kHHq)Lr@m%b;(eu8@M&l~|EyOZD zMd>KbfWK-I)?$RI5Z2Y=vbG0>Tx#VWHFaqL;-H-k+qjR7Tx1%llgIb)t}*s7hWF5P z%@>6c;=_c=mRajceJxOe+yk|3u~j+f(7i*U@?}3VH&txVFi0fiWSUim_nMI)*EK8e zpg)v2XOQe|6}o`LoeyHhswvb~jOVxN2SEymHUxrk zT)=jimIxKs4g;~h;X)4t*u;1%vCTMwHyfcIO7Q`;lCu)AeG5BPWgu4WY^pU(Ax7?X zblJb#wK*{@(~`BANgRjlDi3N(BEslFq)?qOuIm;<*0v1K>vLC?t6uXJ?33|kBrB8y zS>7UcCew_~$E2qWmx5zzCLL1GX>c@2LW4R>I0xe=hc%(D=q4tFF@@$S6KUyug4wq` z8ZX_R%I zP>EK5{$wZiWQ@h#fpoCALfd;81|~(1B2y)HZZ+(P%w_=teb`a*Dkbp8&_G)v0Rr&W z6KS93X3n!BawtLQoIn0sj~a%(8pAX-8dt-5Be&FhBrrsYF$e|QrrEpoF2`HG8&37v zf%1wjN^|DLO)v^$Sej+VQQ>R>*PQQHOc!Omn@P4FI$`8jbzmOx?nx`eR$a`llRTHM z16v5T5t8`}t6muO7R@0^t`P*-J`yxTy^3}W$_}~M@K&=tso5Qonbn+dMguGo*Fw=t z5%qmatDC#kxu-vT9zruTqO6%z@vWMu#7Ia(kJaT&kb`+Zkx1|*ErE=07DuKtq2g>7 zog#Ne0$!(+<676o&L2~+2*nnY$REPI`qdcGhTF%R2CzAr~URpmHy@1UNt zka8ps1dg0F*@Ui0_nsIw_lCB8f;>E^I=?7nTDk-m+h?m|9TdqhR;G=yrglTe{Cu8ukV&>WL_nZ+1w@EXUo&44PTz~8HaFY-@(KWM?X zlLUG#ssxT9E%6JYwGTrE@iTX1Ive7}ED$4Mbsm@U)tFZOj%rjYu$UEis-$o9YBi z$9Tuu78t8jG~;Om4XzNQX@aH<@hozha><0lc-;$1M|7rPeZsU**ug5>ptUUxV8K030B&}fz^9ySG4Fe*|& zSR#9#N<#9q+#-->%JG1g7-)kszN6dBB8SGm9%d*tZH7oP!3M_QQ(}WB9c?4+KxWZn zRaOLS{U^ugZ_~R5QZw1u+W-)5>`=3!dd7zMKxuDp$;oObNbnKkGz1Js+iZZG%wjP? z1yw;z*ofkzjCq|<4OyrO>!EN~R!*uo6yPwFk^vo&g7QQPTRA0=muM`_8pFhz(<}yx zFqcz9o^~MF=^>@4oiuL+E!xp3%icbB(S|oC8=T_Pabk_r)kaVxEa~8B28rJJOly&gMBcb8J3McIf4CbH-Ow6kQl!cVo9bko6TE z!=gV#-u!x~NAkJVXzrIS9WXYBd2M5|rB%HaGETLFB28EvKrq zC)k!THt*JqYhfEEAN7rzjAx1e$e^*|yf=&!T0?dam@v?$Hl7K_?-92$vK&%U6EyrG zBted3vEhWW@|pxZI9SQZecQ`m?7QZ9FJsOWGhTMl`Znjh4U(46n!a=L;mrG69Vgv( z=GL3nZ}~xxGsAJsgw6A#*uB|08eI&lS5IZlQ-{}E{n%zjyRv$Adio@XE55&d{-^Ud zUtw9@oKA=QSRbnj_u9*SvHq3*9cguZA8o^Ww!VI$BNqtomVVjkv95d&KNetkPo zDI2rTtc3dbWFzEN>g>)2$2Kk6TKIxBm|n?a-Tc_#wKHtc{TY2tQ0Eltq{$m!o|u#+ zs|GKtd23?v8nRE*DE}z`^k4nnhCv8maa%%^7)*%6r_oPjTW)jY6NX{Bt^GQ9!pwAI z*x=`tUX>q{s&Ol>BWAn7mv#_9)xXw>w%N zA|}R;_``F5xU-FZo1KT(JDp95=WcsBJqhhbz!qQ4Rrw*1OGm5K=7p`;Xl}3Ci&=Z4 z!>?amLW_(3**7$AoBr^aopY_}I;)$94sXA_BA2Se>R{-%_n&&$ojjaNZFIObZ;w`L zhaG*mRUKxtz6<-qYTvo$Y+R$S4hJjQtxld_9nA(u+ZTqML3rL8K71)_<=dm9F}Tiw zXLT4D)N7Bt(X7c?9khep;DhJYLC$FcgVkUnqgL&emwfxeo83$6M>{7mWYZml1MS!e z@m4tGqRi{_(cBH?LTER)7$tNK*EuTw+0MjmZ{8V4#+CY*QPka{pW8{nzy>X-tq0jKWVENSd!H**{yc#ru~des!wB%{9*so zZJBqoPLz$+BeuJBN$gGE?qJt^`cm7D#4{|KD4w@Vc6{};4>9isX}6}cR`<2xmM7up zpT2ZtVz`gt;?Yz4o5o7Z*D=L&iH31{Tn{$eu$|iUcKh@zcFy$+_v^e8S+~Q1Ida_( zuGdZ5^atxJ^ZgG`4HsLcZ4;ZT^{vAzU1#1rbf)!u?a)wO_5R42!&mElnL2y@+163h zJ#gc#{Iyfp<9f3rlW?wOk$M$YsSAyrT|Gqi8F1cV35Jqk65>E4wBw4Gb0Uw1PF%EQ zC6bkv#RwXLr@i(;jwfJS8_3avvB47LNyj8Q;>_hFp1^jbr<`=PehVj!^3=AGM>-&Ky|xxc%Tw+9#$TN^y#*9WdubL)#Q+RXp>QMWOC z(mcl8X`2Tzp~=GEw%amrGPr9%$?(uo4|X8K{exTC@X*OYyE4pdt+R1wdW~*4ZO>YA zkZ+Ycox#1fZ?!{c``XZ1KWKM6#>FVUL8r5*^oLIjI@X6833S?>PJiIe4mtxn^_^#q z+Naxt!SfEKyS^=Ls>QZ~>wD_>cJRb)Sms0eB4y|Y8J6K#I#|15rol@BDy(h8(1@_~ za4ia={e%~t3funR7w=ULw(d}8EdxCr&4+{i4s)u1=AM^3o!jlU53|9*`>sD>Zg-B} zvn?lg);wz!KTr;xc!$rL+Q2+kuT}bIQ5*|%T0ldKYWnWMHrg)OL(^Jjyr*HdX`kWt z#=s7J=sZ1mOAe6{JH#a1pzSk%bP%k!{*Vd5hJz;RVKAX;2SB5aGW9gBquIifMo0 zzX_Du$kTvn`?MtggzwVnT?CXXmAH?2Q7j!GSz&Nf!)39o zLkkkl#w6>zNR;7RTWJ)mjU>g`7T06VXcLuAq{kTVOt<$KudcDX#VR6~vx7i^3U^Tu zre+F)- zd_pra&u&!eMcFeB$fIg~@z0wu{YtKsF?PT>rk^B)Oe%|vL7Rc)LJR6NN_5c*g z1WRmhPha7sI-^yL>sd34%$h+S(y;1g))xeH{9@hY&8U{% z^0;rZaptMFo}ctSHEPw*?Bl1!VqDbsooG^9&2>t7GN0ra^k~w~_GN}dGSaD?#m~>? zo~v-6dZqtJ%$w7v>TjQUZMlXaL8k7c%cFA! zk)T>2k*BiIu-F)B^2B8w4P=^9hzveT$lDCv(P;?d7=1EVUQak_f&>2EnT<83KR0?U~~G>l)9phC8Em}ewo2H2BoJ|Ju)P$*Ec$m2{X zfCS^SLF6$R@w-nA7XE>zzL1QqvXwX_8_N6J8_7Ng{R!vBoCnpbfDJm9MJ6< zwuB@O1lM&MMks%*qeLcC5zaz1Rtu;{D6kY0iP;j_@~S^i85a$X=1&1swi@!duITDA z(|g8@(j{Yzqz(gzfkjZjqXB@HoB|^X=_k;QdKu68L^?j6G01)pmgFA{$G;a>#~)iWl0jFnB-e)6N7j#2h&IgAky!z18R$nVdIccn(WnA!-?kHmJ9ZBB?_11EI@Uo_v$oDZP9# z6-%^S6D1$AcEpj*g5+pPxaXmBevz|X@-k#^K&ekq&NMQlY!!?erm(HK2SRd}PMHye zjjYD-XEbbwmnuvFI=T|Lo2p{FK0NAIRwp5t)Drm`r6163bxv^5m8w4Jq5Qf`u9h}w zu~O@)lp)v;d06@9Sn4?W-nrHwosi*ItsDLqo(UJ_;FaN4jcJPouW<{NiC}a?hU3@r zXt(NBsWdvfjYO_R;tOFXS4q>H7=;m%6_&YCs^}uFD$jTXreH!}A91GcgAnl2k8;Ph za!<@hOc+X7Q0RI(f$sr5fh@IF5$ClXU z7-B?XC`~!G6i57CWr@%z#@y1%81X3$9_-_(EE6>zNQlwcGF`&BiDjmoY6RH$zoQ{U zk*I=rOCK@W6jQ5eDIyVvA4c78{_K>TR#91wpjd@$WlU>Pl_Fq{ur zReMm=-TaOdhjJC5+J8KRkC6P%9wQnLl;1~*@vI$+rk_@}J0!=BSquWHc{I7dbpD5j zGS8PP^qa4rto_E{`@{cSQyXO2*H2=c=rg~L`KE7wd;U55`s>M%Q*wH0eh4Yp!MUHQ znYZLf!XA3)ts1fKKZJ#{H{Otc{LSb7Sg;ti1D`);|7s=q5Va3VY>Or9Ml9zScrn$K ztQ-B_@5%jZOF9j+a||ER15|_eeiKt|a{tpBQUJ??k{1EB7v%nbPF{?xy@%~1!oKhO zAXZ*A5tmHUX+bP8tYIYsa+t4MseR=uU;lb-r2^aK%RlmB?K}SgDer#+FP55aBztHX zhSJo`)8!jD#D3#_3hXjAoYel)4U3tlf03-Teb{;ZB1WakOsAYL9YpPo_`dIh7yDUn zJpWO|yQOyV_1g1qy#D&qvQ)|{#@#ON)Rqd^wSDwarp8h%_QsY%GYV>#<6|*6N~3N3 z1m7p+puRT#-xu%8_P_f(pTmk=?e7<+ss7O#HS^wEACmG>>W=SYBuf6`FR;jV|2Zr- z@pu1%R_(`Xx*LIYs2y8R7@0~Yv9dq@T^FRL2e&u-8Wad*M6xYky6j zF;#kdrkoD}BFhmarXZa720mIY)N(#ixvpFFF23 zJB)jJec3k?+s?9@6Ad6wYbqXkPQaaZRxkQO33KqVF0WX*xH_4et z`05vQ>6g}jv6Pe!81TT!CWZ$;oXM3Q1Y-_^eH9`Li0pTD!-{zJd`hW+xX6b%vPH5? zV!AO%yIF3EMXou)P9H2}C<~riZJwP`E_`~%&wc!2H(~AWT98Nu$P=X0&{WKXT=IHw z3A}S-(Kt`iqMrC;hYe3r8oc`A6&yOVxl`@XFF~1QtW4b0ZB0xOF>L}<&Y(+Dlz2i0 zk+Q1x3X0fankUp z8N{oZ%{dHGwwQG0jSp{XL#UbhC{$jZguuJ~{z$e`K}2OsyowZM23wMx%0667w#sI@ zeoZ#Wc1@RE+q0$}m!)mgMp`0CrptDD)3U8JU52Q&i(_)6OnR8hYMzqhU2i7*5*E3o ztoTn`xBGRj<)pY8zkG9ErSLe<^7y?2rzYVG{0MZE2*~ zem8oUE7#h;@cma6Ghem+|E<6}ulBEet&n2>+oc7y_OJZCLdrv5?fX@gVt#G$cV(Gw zzp%}gULK@!Nqr=xRXRzlJpm_WRnst=zy5DZ>^J`G|3Y4(`}JX^DCesD(36QyoMQ(!!fu`IQ}uY^JwJ`Os~yBrN{sj})mDmX?gBw(vL!i*iy@E=`r7 zBHj7VFR?fKODsOS#NO;<)I%j3-TM?A+gNx=m=%&Ouy^TRMeO%L_fb%mnno46XsxK^ zbR=3xSuEwr6~c?M_w>4}iSFij$-4k4rMMkT!xCNe8m3;IAw+!%3VB`d0y_eBHPuIV zZJCd31CAsmWXrIdC|Ts~vW9sT#u&OsiiQ;S+I}e}e8)j~1<1kF(iPXU)SshwdU+%I zbB+w4c(axs`6?z78D5m5t>;%RfH9OwYYqYMa*1Udc#?fJVG<*rzhI(hp(I!&SCecU zR4J03=bm*TPiEL*OJSafLNY%qTG(sT!}Hc$l$h7_G)(`N>1J1p zu(k>BoGmVvv^R|+XM>uWiyET8+OylKR*VXw-pj5QAZG|Y}pm%OI)>MNX-DV@j@ zp~PO1&a@0$YO2*%#0G}SC5Lh)UYb^ch1N3mRYD57F|j2t#a>{SsPhko-QM9iv4h>* zT+#_WH*wf-n&|HWs#VxYm#QvPt5A+by2D$FDP&<8=2@4NIYQGiNANE5wxkQGO=?MM z+_DCDu#Fuo>|iMjj$|FK$cOCew-ZYfS!(rw6q0$F+xZ`|*Jf0P!#u$j{V23}Y3wDg ztPil-WIZSCIrm=m+uq1zGUOV?u+2I!YTNgbDHeqkz=5s?>pXx=#WdE-FmoEIvHAih zPghEdAdw&~XJobHI;*DB}_%5aBscH~w@^4RrxR3}n zX@IK+&Lphf6sXXvEQ(6O`2$8o)lE77;}rH?lD-U6LJkw>FI%!c~*?PC{TY;M=2XZm(x?xGjq|d@D)2 zNp2^ad4;GS)l#M|7WJd{KnkD|LW%A?Xc~@nA&E4V`$ zy`+;0OLOa!ek{~?q(mk8SU`I-)^?Ow$qcoMF5XxfKgi_On;f1gU7qE;?I^O1?{5Kd zhjuAyCjf-{!O`;Dfh_JO8g@d32F`7(^Z6zhH=;GQaR^6e(bM}3mCEJ$s!TVV)!N2p z{xXfR$*+Blo9>7N{>`|@q+1w(MSKZfi!*2?cnvABJ7sJt=n0e(N%UW4Aap#_^q`CMj_{s5G8=|5N$F@nap(%8gEVZt z8B_6dB0~O3YlDa^o{y$Q)o5z@%tTKv<`c6GX$9VWk80k*R)Q@yf-ek+DA&AU!E=0x}dnqP&n7AzlnDDI?(;Y-s? zWrhAu1NTBs?Xz9$!t7HI*&F#$xV^)eCSPh^)Z|p7?+RKtoE>?Hd7~=So~(~v)$uMO zAQVRhNy>LoV6_&u?i{glL)T<-2;PjXn9uF$2eXwVn|3O82urD4+*USxA+DGJ`eArj zX?bz^K)y=;b)ri20mej|Eel_xC`i**WS5*}%#N1}99D;Wvd)#pfjgqFHV4fGjEkE( zh6fu)WX=Z!(Dd^Sc&W)^>VrzXKAqF>O_CO;rV|uXPmyYnA;T6%E67gK6qYd%QxwNT zlf}N48~QU2ur?G51&5@3DTK~6*WdMwc8#A{4uK6V9QUxY;7aSV9QP#c-gvZZ!&id8Mo?wO-QpN)rD$!SBt6Q^$TBr z7hXEFt9OiW`P^M~$LNtphL%raZ z2Ju2!2GfWUT@qM>)we3J9Z{W#mj4Nmrxw zKTmO=Vs)}M7r7vn3d=cKEyNVD@8yna(~GpyJA4G{+H0%!C$M26 z?YC*e@oaNp7jHMIr_5v)2H5lt^`@+D`1c0#rZ?m3U%YtJPCD`J z^@VwSYcUC7aIkgonPD}Ac)l~8Kfx!1x$V=5=wwV!>geBMO)6`Ayit{&Q;m+T$$WiL zzp?g)@Db15pfvQ6UIpa1I&v5LS}efX@t%;-6}HV-Dg@#a>M}E!!+j7#0T}PGPqFBH z&B@RUU)--Pgdeitg8)Bgybg531>I3oVzkgV&wNvV7g(diD@N3DX*Awzbit(CrNc@0 zCysTyZwoCg_>HIpN>@?Z#A}YrjpN6TH*QGphIAXpk58xmiQ}wbThA;^fGCUIgYORS zbx&OA%=L3=&j-irGOzm4*krF^sZp@1_-IcWTaWRx&F3d;xoMvB{_)&*9y7M_1Af&! z+Zwm?cl>m<@>Y~k`IKyZK4ke7J~xhZ8NNad^vruV2T^*qx_@|HDm`tkF4DgrjpzV) zkE35i6XT^Ku3KdQn_7zZZJBi%Ps`*tqbS--# zyVX0q#^;??+dAkfRZ5#bE2cD;@>pkE1{5HD%)D)f+VN=~~3N1pwwnSzlWCXbSvdL{~HM5Vjl$DJH zZZV8PWwVI`&&D5uL8_ZAqD2ThO<6G{V-{#~sDRci;=y7+O@P@JsRXjYje~qx%!f?k z4YI~!knsozoa}l$=KfCI+ue^8Wjp&R=e@3b>QvRKQ>Xskx^>Tu{7MLViCWiV#VFVs zxQ8i8Q7?oC_=#VMpwty$krA9m0WdW?uVZ@2Zm7E(F%sZCKdur_DMEzu1U&0#TGA+W zTU1*H6!b$93T-jSG#xv&QE1(pnv5liUVw}0)YNhOpc>wrf=eRV!KQVO8GYwi<8xEy zxp)={B(#8Iup(RK?aE7!YBg-0IBI-Qnnu4Xk$a_&f%9{;1 z%_8?T+N&1NEO2(nbU_yiI=0J#5kaidq9@ZDLXQ?TdRr20p}n@I{cSWbkvK@I#WX|P=IIz^2M#~pCN{bHno z45%j-I-W`jLKc(gdte1+3nEuo#;rhyRz_h%Q^|tmd68!#WwgI-O+FyuiTh<-9jENCtd;A&nYI@=>H!79ib&o;6;^c}W}0UQ3sdKoB4G zs_O8x7{ya@5+XX97)_TmhNb{ zo%vf^i{pJQJU7~dU_5z;Zs-g9T;#VS54E`p|LhhdGj{xHX5qwz@Sr%IHDk-S%9T;Py) z)fTs28&NZ}Hn$Afl$`Xoez}w!RU3`gr%&?HM5J* z^C&sw;pyPq_|zu(jV;y56Yb5gLkfOq+sXkj;eh8}6tSEt)NB1#$=ESnMH|Ky3PS83 z1$SkQERuC5KPt_du@|{3Hu~Z}fsO$TgiCKpyhosvwxI<|5Rx0yZk{UkV_+Gb;E?U; zO<@I|Yt%9TMnbxlP9S5eqZLG*fPsZqw^ZFAYC`=d0-LN1|0=w~0f}oRrK^{nbVq=> zr3IeA?_fmr-Ul!-s8kG4+XdH1I{=gx6gdE%j@MoGEj2g1g6P8vuMpL+PPxFXa=pni zR6AelX<(g_Q}>y%#*w!8bR{l}(=tUO^g2QhRH?>XWEBmRKBN?dQ2i7aMu%Z!qn|?X z7EDk(;bYv$3PZo97lKD#W=W*c8i`;bX|%7YHIXe5i77u^Z9p+;1$?B0kA;*rIt@2W zY*X1}qU2>V{DFB<>0_TphnV%Xe=;j+Sv+0S;Oc*ZTD9~_tSZ_%R1+NppFB!zm(^DV z9!Nc|NLt%KSa}a1_i!ykmg-O+ML<`f47l4Z)C&XjmrzO-ps@Nl2qtm!B`M*d%haL$ zEk@M_z_pYSy(s8{ktZENv4g;7ZHimbqFz0JW$KA~wdSPIbl%eVycVz=+EPvosZA&> zM2Y9~2%eyh)!UMFOp^G4m61~kR$%=K{RomOlB{A1Atwj2NDWvi-31O!TA^G0P+e}U zXW%Vk%ZPx;ZZz2$3R3~@iWvT)Ow&qUi@akZ)WC0~Jjg@k zwW+x{u|Zrk1bTj~s8om&P5zH{GQXkOwabRD(SmG~mP&2=uw>zfFIk47I0=&uLM5`{ z4R9?73!puHX?KY4ATU!8Lr4^6B5p?%jY+Wx%|D>Dz@JZ79E*qjmEA&&A}%~zMhxd= zKjtZqo;w*e6NwDPoll>r@td_2@DD<31@$G*8 zEE}`BAmc97ZS0F&m+j|YVgb<9yUv^i+mRkcIMno=K4Qxu)FSb#jg1`dOZ7f))%j7Q zR}b^-&HV9b{2=xY<^4Q=Nm_?2nG7hS-@9^MJT}P?qP3^BfbxR%p*VMR--be8fOf=i z=X<=QzBTdt=R)vj&pvy~6bS5OxFLQ-vY-kxQ!n92Z#1DKg8<>sM(~U$fz44?pHM+ik9$j^f56TZuX9|SjIqw93F|*Qz%_QOl8vf9i1SMG3&d{UvZCL zG5O|^+&4#JhWnGp+byDsWw_=ndtvtx^U%9)c+~B^)YyJj{0rN@UEkfBPaCiLbDsV< z65T@|j^(sHD)P4E1LVipM}0$IG0l4-Eh%VUn4ZSyFhKPiK zUR?R#ZnIudPdjUSE@ac;22mo#aN?<24TKB>70$%TO#KKrzs{9F?Gt(pcw?B4QhW{C z#DT)R+Bs=m6yI)K80LJKBGB?*N-6r>m+K%x^{H7hVes7erB>`opS)okwq5Ub_xuQ(m#|@$;?rAvZk|-iRBYY4_XV@{u?+#9xvy^+1V^}Nn8!8@O9X7OgNAvwt`KB9Lzd5{AOtNA7y7R3IE|}lFI+K>O zg8}u*9anfhPzl^2br@$NwPt;cC>-^=^MT&h`Hb=TILGRa-Sw6aQf>J;!G8KiY>938 z$QL!X>A5#NcDSyodA(6{|4kz|nw{)-ubQSG9o;aUqi@^ut#EDd)hVB)p8J7%@rmmI0#JOC<({!7K_!Z_BD=jo3bRL`ew_lUd8UOAp zBJYHA{*}|%r<`8>-BVW{t~Y~kJ~Fc5S1#|qJUYAoE18wwjYCH79u{dX_~})h4(Ax= zL@xkp-`8tUX9-@BVC1ld8wpRTF8TMtd&8srkNh!7$$9g5j z;W7mt(#fQp?YO)3QS-E7yV4TVRSpra{`ZNPAY5BwFahY0z^)?>G6Y*_Y+cW=<)uiF zse@BygKn!n;jJ2v9y1`N6r?WN!ksoZ()~8ZmN2Boahb5+8i*b2c8jY#>_yD3xNzM0 z7_2w+MH*%x8)v+7;UCA*rT6XSarVzWkF@dT?&sTPz_+x=wayDqwBA4Dj)d)nX%E6t zeUcE`t!H`AwB43)Xy7oc+7GU6cXqP^Gl!jG@Q7`>qfhsX!WS4ETUf027q0Hz&1d^Z z!@EbrRr~6Z!@ZNSJq~S-?I2hy3;tUBNawIWdcAOm?UA;lONI7i1Myn@Cd11#Smrp_ z!-iOXGW1Ve3=*cj>>JlwJ$utR#`boD&#V*}k913sC z(G5Qr@gidwdx=2+FXW`xp7n>(G0)zN#)+&RTA6PZvfb{%JIX)D!r6_&ydTvpn-9%f z!DmHYF~t3L$b6 zPklsY?N?%k~6MRZMrzbM<%!{acDoA&!3L<8*<~xPk&&y82}a%$I*{&jQtte+a2fIVX(i;qBirK zC)m%foAEfmY~qy8p?1jT*~O8J<5?f`cq5xHniEPkkE1c)az(P~RASckA8dD}SWKUG z7Z;Um&Mk=O@+YPpvv;Js*w6ZV{&h|UM44g4r7LjI|k55kXGqoQ4&tgXI z!5pEVtoPpIZZYSfD8t}%@AAcrR#e}wce0~=Jj84>uwfyMhBJDEb?%G1d*&(Q@~Df% z`XhC7wK2N7_n-+e9;lqrDMD$sd{CFz@v)$~9TYi+d05 zNqeu3a&A46v_sNkL$&}|uFmN8Tgzw|8er377u3l2E&(-8sS z$#GkmNA=KOnS;e#q@^uVxJ`6udi9Yxkyz;yFI@F%vv|wO-Qv-MeqBpIj zbR+oij2Mp&G|p!Xe?@KNHm_h{bMrJtDTCNp(?^^;y{AIWIaxevi9TT&KQ5*$woG6J zdX8I_9@{>eG4k=*FYdfmXdZioi^OQDT~-|v5sq~M7a%awxX9=kgGX8lM~J5vc@@Wd z<4xCjiil9CATf{dj|O7kwk|Q!ajd$jn1bluE?W?plUS%PLAdKeCmoV|y3asJ@KPWh zQ~9H3QyfFSs8)GZcBZ@}QqPIREHXnj|zu%VeTnFX01`5QxDD zAw|^m8MjC!uq-p`C;bGoKs>)M=_;RAu?#~=z+Gb+3V6@29MzLwmVK!7kr5Hr>5@kY z_XU;V00hmhwIpaxAA$H03OW8T2p=CvLM=HODs`^cdzj^^GKiHTX@tArZuv7#O57D3 zQtG?XhE)W|dKXU&DbJ{tY3o7N&wfry$bgoz<#DjY6rh2C=hvAPLT6au8=r274I;X} z_u_*IuVKMb-kiz^8X`?&U}Wt|G)>y>jfnnHHsxS>N*2$mj4(Yce;yV@FUC}u2| z`H0k}`2Gl^BA#&p?y@kO4p9oa-NPA9$JhZW?as{CHhVsF>GM{cn;4rUQ=j3q-ugDAVF2F zI^-z0GF|BrPh_1uxs`?A(pkx(Fu81iL({M;Mfv|DnuE=R|9(w3dr zn{zy>x9j@x5ebuLv(~6XX4ZzlVQju+;5hT++pQ6mxV^o_`jHt-Gj)`J(n)|nDE*s- zd&Gd$G(heV$e=*D!C)#E@gmRq^8AGs-i&CrF^HS-tu#G7fg=`IrW#CNpi5`WvPadY zV1x3|3-glZ8+xgy6OMll$@6OlO3N=-*Q);Y4f_uV+OiFZ+}l@;eC{xKFftb-3Ccu!X%9V9>SPXIAJ)|kR&yFlC~G$ zEF;fhUSiu4Jc3EYyB0_#AP0UWq@sg*et}Dw2G5TLcCG_e1!(91B()^}8aoiIXeFqk z+l)bay)T%G>Z+@jdzp4gyKll3aT&YfL?Xo)3|BEKuI~EDvY)|!P+&x?M?8_COoj~wi6lF z4V%{nL5SzJM>#oSHw`{2IIiQw+bB2{ZeYhMurkA;hfrEPdh4wXnZH0tSspy_QTHw& zdUP?7lubw}Sk9NEM8De!l~*e|sjKuSb*s$EAdn@Ja7_3;FVc$(&DVs~2vva8WmM$! zE2Ts>1qvbkM1jX@Bqo4G`PCGol(0&Ra#52o`OM)JwDMFR`UiCh0c2fpq|?*~Ajzcu zG~9)%H64g>AT=c`Sp^L*hx0Y>gK5Cy0U^K-c(Jw4ak?4nwKB@xp`}?dVexbi!>y&i z3|M&+S!w3p6l&D1GBuXWg(aplwaB()wMttOQUHl6sJu)068q9gQPfG1myU@u46l_m zu4+_{Af-jM$i{sm82=@PXpwaeT$awP#L~mwr3?qIYGh*#_t;k>K>3zV8EdPwk*3sp zBLAJdusvw6tzwF@*IXi5+-nc5_;|}>siLrU7uF@hHkWAuHq~xutTHw&+&5sjatRSf#lS^6}bOvr_3-T<)Lm zeUvy{=jNGpwRZJ9!~LPM^+e#fhgG#?59zo5Og{VB-@-uKjm4+34EVR-Eaq=wa@Pk~_y z?aLT<+Eyb__MOk-B#TUHpw0dOYft>Y`vRt)a5MlrY>9^1D12%nYF(^^z4KX&MPbdY zij1+d|3Ge(JlT4?C-UFPTUn8V6_(p7Yg3>2VzQsLR4m2%5DR5%BSs&K4c~qD!OtNW zrTosfme$Q==g_AT4F}8^j5{&yE2LWZ2Sko|89{uv;P0aHxh>ZC;k=gpIc&|a$6VcLbA<9KT!DdJIG8PvVHrG z(7^84@6m?Vk?+CQtS+d`i2FnGy(ca9vTM>Th0lAG;E1DmI9=lCv z{G+lf{L};X2PKnr&mfA1QoZumq*(I=UwPsD7p=87MM}9Xvs@?p2mfIEPyck?=)Uj; znEt{qZ2zmv>nOT3FX4d)lBq_krsS}2m`p!n2~x3SUM?9$TslO#eH*i9Z@-`!lT58i6F*Kj7?6pBoxxf83{fid*14&rw zb1%P57fiO5 z`(YC3o;GtoZ?d4cw8wWyO;gekzxc(5Olq4JOPn)+FCbm`5q3&U-Z%ymb1#&#Y- zDRiWftJS##?po*@ORokkAy&wYz`HU|o+!)kDjHNc2go*%(Xzv(+^Q%CF5A|;eBNRj z>{qv0Fn~R(*oI=0mw(lkv=p$TH23m99&hdp&)dz$@E?y)ZJYyh>Yd>H+^ch+N~R*| zT9h>r|LktY@}>q1i2UUm!jHRAKG-g!gy~KvH1^vx9?M#F%QEu_fLE8bSez{hB*$Se z$>LP+p`#wEgk_}c*s)GeRN-93OOcbqX0C?fpqDCiO-oUzg+NB^4RK>wRSK^PEQIg= zC4C1;42V+dxwNX542&hKYRN8HGBCEbs`mQJLoJvVCGw+80T1OwcEx~cOqZmfgwa+; zGeAArDAU&)OZDN8F!*-La-B!YGFgIiFaM@mWc%ft)a5V`9msT7Gmk zW;UAa&cK(n`D$|_5&7cWxTKYCGFuA?Qy>>uh>95lF9WRB~SAGPmdWN6BfQAt8x&< zAU&m~tir4Lh- z{GRqp&Np<3(0r}iUrNC7hf4Z+$`=M!>!-BCru<4SbL}9d%$hcpV-(pDNVNZ3QzT5A zZb|DbF&ki5(jG*AW!m7t?gq0d=Rcv@+#e86A{*gl=SZf@B-5zbL>>LTq|NYN=t9%9 z_kasThF;21j>yX>Fi9y|OM+glH1(3TW5w@`(wJ+RKL!VU^GUDCo*st}f3+B&8u zI9cX_rhO?3+H}n-?YIgh&X>n21*593q)IZwg@(d8wk5xk>wR6z9$qP+XC$YQ!E%QDpCPndDzWr{Dgm)J#jxeUc#TSYVNH#rReSG z(>^3%gSE;dweB)r=v6c;VTtMSI2SsJDzKa5O#P`Pt+q^ST_kPNbJ>N|SHb=4wJpO|*9)4~ zxhPc|@fzYKpHI1R@=LvxSUcqbAo6+@xuS>ke8q=vA!a$TuY#BfRI_)n(bm{kijDwf zh>fFY$^LGbFTJ@ZqVlQM#Gru#N3c%BIRVDw;ER+ifGX%0yfQQM_UtA-A^u*^3co+1jbW|lJ1jPpW>{%Il%_@{fG_+QYIE@xZ@&T-X zNZ->aQ-t9e(LPO(LN|Op`ZOlnxapB=gP}iDOSjn-?B`N2w4En@r^AL5WRGRxipy6pj z!$F$ots#m(p{&}1OW1RHA^H}{{eab|#GHx)OrV9NvEJ3k0jz}7(!5L}Bb)pQUA@1c zM7%t+Pk2{_h;3TvB=jYUhfNlye0FfSXL$0KpW?-Wx1JSwtTB1dJ%_nEhFmLd8ZMy? z7?9$WI=d2#--6=BNwfp2+;vXb;3{S}>}#Xk=l#&}P|J2c-`sNhdZ>!?m`Fnx(agc} z&48^pjfc@T8FJJkVY8uZ_GV#kGo!6q6Nhg-7BrpVoJO+n=1dG*n}!sd6f!#kzZ|b@ zkitK_i>4x@OPFn%HzSRbC{1ca%m1T+QGT-EOoJ?DGiF>Rp^GmFZwOGur3JLx6{B%md*_P$)7l^$@JBW zEY1Jq#@kzl7r^wHan$%f9E>l+so*7yQFtlV50_ozdzEJ>VS#)hZidK+peBrxnP37F zRAo%k6R*wstZ~nwvOdkQ1a@m@!w{GCR8d#KOFx7pU6h@`OQ+A++ce=-;71UTnAO1f zK}SP1Zl-7cVPqGyMi*3F4BgBmKJu1`hInb#+x@^v8Jl-8SHbHy?J!vscBqyNW+c!= zh3)lXY%z22pgh)sGko07)j2BGYKlBZ!w4`in!GiWg`9hZ zGoE}~%`;7f9n?7Jwy4=;g{Mna9>Z81OqSEW&ztJmmx5YYAp+0l+qJ3G{4uO%`33U$ zE<=U`J0{e_F$?LK$607CEc9*pnntO$NwMR)!bHX0ey#nsJbtX0%Ee=CWbL-1gszqi z!#k+T-o`1|Bo+$;?GfxF-;(jIfCaX(>x~;;@Sg6|6S_L2Xx-$PuNc&QU}wn%$r=oP zI$MXK4l@}MmN2FT(}u;$RC^*6HGNoKvNc_P-N-w)$1uLCt}j8&A4X1{Z+E4z!9v>&>8)Sn*rPK>X};dh7U zq<`$#1^VrxU+JKRCXT67OV->-1_#C`+0owDRfiv@-q5{6#5ZroN&P`q{@7{{y?9Hw|6eI%sh|BZ5~{Av-3Kp5MP{S4SReL z+MOr&_ONxzp!ohDyq{l?r*&vG4}Lu|_jW_EH$+jpG8@_lFUc0h*rLtQZl2Ap&0B}t z4c~a8wb!ZV&#(`4#J^t8pExBu?Vv9+zltitgaP}05d8h9&}>Do8a6g{#QI2Klx}or zW7*iMB5iV|Die@ku^7`bY2qsgaU_9$D1krWy6!!SC!j}t1Zb%dB8{k4HY{x~`FTYc#V|=?`n2I@r5{vnnhF&P!|i~?O^VjX7A4uIS_*vrYH!LNSQ@U*+H85X2u&z zVAdJdc8DXv6RSIgIP};ILn|q#Ezim9(XK=Xr>L}ECY!vvgwMx97!svBB5%2+Dx=4g z5cD#Yf*V#t)mz;V>BwRruceZcVJUMOl`wCZv;s{#o{B@P+v;N$EMbWt2bKV3XUsBi zlkzRPUe%G50G6dLo#aS)bO~8OuhYdYX@h`Hl<~O3%qk&zZ3a%fWH%|JdEHXTp-g*q z9sDE@!7tjX(-mxuL5>R=#Ol;&x99XY0*dTeFceMCD!rO~50}N8rWU=RZO#3FJy0!9jPgf*x_z zwXBg%L=xC(*%VZfgaZS@6NKcd+2Iw?WFsDAWXa;S{SDPwfd**k0YDv?iDVWPH57;` zqZ%mccWEiNikRfY=lN-)F9k{jv_$(sSjiV)!K;9QsK}x?N>+x3cNqq`qs=co1}crb zsZ<1hG~WwP*0^g7vIXm)8o*^A7h}Xd-nopt^N@Rwq-~klK$SIgH+*MEDQkh#q%1|_ zVOm!DfMfM$2cgo$1hAbncTWBO0d) zgnzs>?T9t?rb%m|y)SjS+AT;4y0;b;P3O3LXBNq*TZaM9?a~LkW#>4w1)LNDEg0oV z_tvdi4INdTTYGpfy-wZjVGQ|pPkKH3${3qzUKNPnSreQ1(JFku;?jHWfA z5%k{5WESi&tEmujdC>f!@I|nZ?ZC8u+-;hHabg#y=FDRjvjFaWFEV+pBjeDd<6^Y} zzv|14m8EKm>QJDU6VABh2XPuDI90GTWfNruj?H^IAjLcvBDbnOk`4FPW{dg|Y3&xW z% zIf{HdL=8%gcEJQu?5u`@gG#c7xJ3ODDKja3tXj}h39(8Tn47B5DkL={ovHwh-3y8> zVJSPe5F(+XA_!dISQ5NXou0tbzX_%dB{hafOrLx!VO&+ZRJLbQILEk&@04k|)(Ci& zU!;#{yiyN~6$WyDND&vhz}z8UvPw|aPEG6dE+AL#e-df2(EGz%YF({@-aXePU9U#0 zUZOfb8nT6^SbV^{v>JITh^BXIFo+@0`M^qm?^8)pNCs%-XxFewmm$$&a?yw`&Gg?; zNo7F?%%$SqbKXppu*0$^crqbQPze&6k$Ipi0=lpbkR$JNV#*l;(MI%dA2m9opcI;V zw<{88eFAV3Rn{)az|oMbNhd^pBOcQ{i-WE`j@!CHi-`dX3xf!f_4tfLsb8 zxykWsRIxOQ-%UE;L$W0IniRAcAAyBZRs~3HFtzOiw2!1olAs zYw3YqwE9egjYtU$q^gt!xv@7`>A%WwnId(zaOKwQDy@= z)Y8=)ZYgaA+#%kQPV$a1_`9O75tcSUS+F!Pi^U(3;2Lr-Xi>YVC^|9aXoqI*xxv(A znlLrj%y7%D{z%cK>?s7YS|ElTR32U`MJ%rAX4b1$rHR3?vfvBRQEUN^5UIM1;E?W2 zOh*}|WZJ$W-6bjyg;}H>lp{j!-=JTPsS+~bM-=8suBiop0A;CD_x4&M5(lj>F51s| z)}^t;__CV4$8%o@_oY@u0x=P(T%{k$poCDbFpTF=2s|8f$5VCKsVC}1n?bO(U z0%~vQHH3j|j8Y(*8*Th)28fN4q)#a%q6fgsexx8kpJ>p6;sd?d00H2gJqi!kY4Tdl zMkPTNi9l>BJoM4^gmKPilqEQQ>%EaTCi>MH*Veo;&tS`~M?@TM>t>xmj%?H!@geLJ zp;d@K^gI!`(d!J!FtF$dmWSV)+`or##mPg1jlFE5RS>uQ-kIIZ_WQP>V|5tTJqw`v z&rya=yK$Y|^xi%d;q*gw-`_m4ThRL)Z-9rwvDDq@?7m|6CtA3MEd)7?kKS**F)^XB z|DwuF8Q4gzv$NBPl3jQC_Q`WDm-f(Zpy*cLg+{yS^T*mRdv~%8ZPp8JK4`fk4A|FM z({Z=cll&~5VAtek@;I9lq!Z7>REMCAIeGA0hK5T_^qNWG8!{H2(3l?8y4Bm>x8hH+ zN!>d&@Zr>Muwm%YP0J38DE%z@Qv<1^$G5~^phk)y5(B2XOmII53+icff%4ItWE-*4_r7{&?&taRcYMd2ru47#c@Bv&Oiez$a$cf;7|XOR%agwvM{`n?)j;hbFM!#PK%JVG&ZQWl9HJ)NX6(G-tT!CV92OW`n;a64#@xhD=e>kl{&R8xP(O=5Z@70|24VX4K#Unb6I+==M=Es_YBIJru`(x-cj z-Lxh4oSvxgM4P)P^GKK*YxK-TZ`#gI=7k2s$hRp)TZ95^U8d}b<&}ajAdiEQINdEy zS#oz{_bY5H{M;omr=FEb@lwnAQ^Wabw#@5TAnRO@otIv2jN?PjwyqCd_EM)6vEa2W z?kjFwmtVSG%;S)e!ebO}IvLCGQuM8Dglmq9eeO2T##hXh~JZqNu*l( z9DHraq(xV9uozrFvJoQ9=G4ra+){H{f7+i&u=3h$dVVkwJGx8@xXio0n=Xb+H{J?` z$fe6@9o8N@Zs z{wDW;*wuW=TKm%FVP05lL}IV4-t%*5jkwXa?z%b4Ip5CEJ$p^wiRWG(?>o2c2J(1k zb7W5TGuri6Up-|8J>W{->^6AQS0+b`&AC~j@U7h3Fm|3t_(Z{+7F)*`U`immjoz^lY>w&w2n;A*6Z7G zEYkPSdTlBb-Wywxf`GkrINXN||Z73ZCDn$TSU zfEX2&m|uEjuA%@7@xGc`O_X_?J{KU<#FNeiF)Wi1zpElQcT4SAFL9yIX4@_6!x zhL-=Vm%)1yIvld|Q95FJCyJYypL8Mu6!r;`PfM%ejC&uEY%4n(XkpTdQ}2%b&%T8Q zwjE~MIyHCG_kDJDo1$kDilVhWu-mPoKxPTstz)|fV#Gqu> z7O#gE`rC1IyN>NsiNw(XjVqQ5Sco;TxYHuoJKe~D92i@ejw6*!tfH*M4b_gd13E8d zfZl~|%QdMgQrMn7Ebh7s*KbZ(E9km*WIP!Og&h~K6O$Iw^1j)6)ptl43TYgrEo@tV zq&VC^WctkzPSOreke_oW?cwlhYus`tt_!l>+$L*N6h*(~TCL0su4m16V`y*OoE)`| z@5!_fBRg71zg@&9+B=2sQwt~F4=tKfDzNI!2zAADENuuvgRn(^|+I5>Yq zu;LaW#>n!;EC`LdVCst3Sa3HCZbI{C6qGrSWO$leXAlayeADHQu8uTZw;n<8>}mHQ z6i;HU7%U{}8ioJ5E|ZuSVMvuhRmkgvQ80*N3YJ-H21MorO_1}!DJ(*a$TA4MQnMzT zL2cY&&l(eLq|D|joC>Kp*aV^G1Uf;!N9EL!sny72t{VDOb z^Ig`>|r`Be-X!Q)StxmF=nmyUc`Fk{@(OKtSxK3?(LbJkMgk8%=a2G zdvSk}MIN-iC+19@`@0y<7T?%;swg%(wFiF|>3VfPnhu_>t5LMv_>4P^lN;t3%jT!| z_OI%3MdSMh6M=D5KOXl+5Avy}z5Eb*kF=Pd-7}+Xk-x`eN?{^9pYbd;W96{T_N6IV zZ@|)j-js=pe$xRxU7x(sPxzgLaN-BJ%Y8u?mLCD?B0*fcL91=1{t&Gw5c;>Yc5DVD>FW#tMjj3gECn^m#;)cj5blU`ltOt0gYT!k| zCpW6=G{XwYK=pVulzW0wo<2g-c(ty&suiBTRq`O0r`U9`Ac24ZKMJTWvCte(=9LQy z)QL9;$88vS`-a^3bYT#Qgi1;)h^~$vuELgaO8=5d@Cs!xPa;~x zTQR&3Qi?=7|2WyCYzQAo>JLzKo%u0Pvb`%fXw-w0zPXNizXqX{cPy`BKYvtteWLfW2* zg&R#RwO(S<%OVZ0N>kN^iX4LwyF)+>F?g;D2wHYa`np2N2HYBCPbB4rM*%U?G8FV+ zEz=`r;v%#NKT6=sl$uqF548d(6E8j2iO)&kzCj`!=^3E~lEATrm2u_*dODwvX;sC2 zNK2zEF!7a=#bq8T8KP0dRGiXp94XXKNpS0$84y(oS};9VErg^N$2yIjEe%gaP5MjT zRViZ%E1e|{gC(TId?#n=4~nohxd(#ixVQ$*zS43M4S}PE_9W=2f$X6bxBx+HNEHCS zWU&DM2$UkDqxMIFRs>IOVdYB*2@U{l>wxbrk52)2MNe58>PA5mdP)_SB?}M~=m}JW z4K@%*+i~hy1RR7?`ni&<1o6huW=Uv-HpML=;VjI&hZXyMVjquUTFkH>)iv2H@NXUs z1Hx4b!^V^&ORZ+Ae?r6A9e{2bTsP)0)%KP=va{0<+wHBMJnYQ2jo7#jFcZ!kGXd;u zceq(8P*;;L#nDHUo!IT|tgpqx0`9JUbr@MZ1c_~qihzT%iNX?1aRf&oXqjJl=?lFt zLSY*#fD@IH3U?~KfzF2$ZKebM+#+*=3UDB?T+<@y4+w0`Kv(emB0n+InIk??au*3z z{Q-{b=wKuvSyT$J(^htmTcNzCQ@jAHfIOsRK=7n~oEwT+@bp8%Ogmho?Gl4qG!E7j zah`3b`-^L(BpNA-g6E1PNPy&#D&eZ)6k9OF+`6{xI8E~*ReID#ayU&HN#kQ=&efDb zkT(rYz6s)!j3AL;1wJaG4JJvY9x)!r^H)Kit1a<^YtgcmDP0#V2jOnt!H~OgZr~0O z*8G$hwc;u;OXPmna6jTb0^J*B&3cX98)xYcGMOu0>L)0A5RlCz`KXt9Dvz5cwU?3L zUuF@suh9UvrLPLp!j{Eq@F-!WRyB;4Yu%~s!k{d0lA5$FY)hN2Sa+{$fc=+*z~YAH zkS4r$+mJQ43+8`~QTM*^^mgJkHoQRRFzdr)XVViW(0*f*;H_*Hb&jMvNRutwW5UuD zL3Uh|RL@2R0B+S2XWkniDe$^Hi>p0FJ5~=7LkRS+kSGw-Rr6f~nK77amvMGZw_SqH z;|W4_O&5&^fqa)-R3!-l83RF`l$KoaxSr5|0<{rPOb%Xgre1(ba!o=kw5G93YT~OC zO^i6umT}X1Ur9ixyi{&k^mWWo(U)Z@y-Pmo)7&aRz9ssRtBP?q1ibo8vjlBM_XBI? zZ~lAx>l2)pUFp0cJg_0-hzTZ(^Xw0aKXL)`r6p z?Vy)C;bpwaz!>??$}E>m)v8*O#6;MSl(Qz&ZDS@DwiFag$&!<3I7CsiVlj_e3L+#) z7b(BeN?T&81y})T)Jxiw5nh-Z&4Ii%^C|$g>cv?Dk?#i#zJ5jbiaYf}R@?`!kUp<& zR43=>6)7Q9@$vbzM^@22S6ZgBDH$HPDlGvUJrxA$E>XQ|$=N~vhiVw2wEB>YtgXF; z+FVQCn`%3P_QIr90ck5)BO;U#^%70u928HGVuILy2#`$A$H3Ho?zZg=M~49aKis88XZVwJ>uT&&;dKjxNR zcmb^twgQ!@SX zEC2CM_R1^C`-*0SDXGuC^Wg*8mtRQ++OS3U%9me$8*j20l@#&!*h$vcDkZLMAFa)l zt!W9vY8f`V)Bqal{GvKv`YZ~u|q{@lBF zgntFSXhyP+;8H&*{l^NPq{oU>Vt`cN{AO}K^(pz@_Y&><-xth5A>XmjeNMjn-F?Zh zYIkS*hgx%6D<@f?8)~y%I#otAy@Y+7L$Ibwwze!salb~p{K0>;e}3nm{Oj!v^I!c8 z0jaJ2_8s}HKU2ejul&q0`Tn)4QxJOW3-YIwinIw5KkT}FI8RX$?Z(tT_iLZ{gj$C= z5N~NXEYa4TtcsHO;iLd;xV`(0d!l^m*!H_>l>_QQ8Rn`nQJolpEzJD>9~QoGEun{&wd7Q3UrH%f&8PAmxQrCX31!*V1x#F09!mRm z!dS0|GHq&bM)62mS_#fQ@c9G&n#{e!Z~oA9=FK)p{n96YCMGQZKYCbcI|7Y+pemkR z`>*|$hH{iF40-$v@>kkk5{9Q%@f#1hA0t}rb#@D0Gn!)OF^vZT{Iw)5=HHKvm&8xL z(wEm#3Qk%0m{N$Gl-D%W{Et%ECBs6QIh^F9509|T1~Zd?1sVul;+ws8vcF~W|E1^4 zw3~kxU5SP5;XHcfcj(f^T1qPq-24rRUei8-q)`a1z5d6_tc381QhKqyX2nnbyW?9; zLd|H=8PVq7BZ2pk%ED)XObh!mO9$sk~;fFa9++h*@lk-%{m?qBa3AQ=HZlcG+_BKM7R9` zjc3}5>o4#tF~7nTNqG>DZT=L`xCr%00tQLkl2@!kbDpfFc&2}OnU(@KWJ(I2gp>63 zmv91E@t(FufmW7-;~AFE43BPzy!GMVty4VwPxm4NGqsSAEN8(rHp(2CuI9`6Zgazr^ZGB+0Py zREXVQQZ`ogr?P%Lu>1kaa)hWj@r_;+CSzBH%Hs89JkG37}nXi!)N(!4l ztf64Wovko=y0^s2c*@VEvJ+3DdhY|;fi&GRZ3s)Olv&ftb4yydre38L%fd*&XOsJZ zqD$aLZ4JJx)OL_QiN~Cml%uS+g75!Jxex@DI$Bo65`c%c#Cmw4@=AaO4F$QrW53)gC8+ z1I9dcBArWGQIg%!bMDsS%?UFZ(c#eFcwj;b~&g`(=KCp?AGf>n_22v9-kjdP8gma$PO8|7l0 zS{o4&_DXD#0Trfv(GOvnXlEX?q$x3_cguFAC?N_a==$F$TpbdoANr179@5Y9D0^h{ zWT0c?j|VC`@o6M*+}F14J!u#G#;(rkS*=hcOGR8i+xXGUt9DRDRB;m^;Kx8r^fEm1 zQvccfcO{!=n-udcTi={_Y)^WVqPZW0)A;*t!n5N&Oo-`y&t~9%AEj!s`$<-iyx_@* z-7LLP_n9+{gf&M#yOi=$$0v-P@*ENUEctMlPjfsgv6XK3T729laYIk!3$2-*)1V+6 zen)qKcTHk$dp6{6(4Vrjg3@IX`&6wcrRPC;fatm z@PFFV&MhRuTcMPL(r6)gp@NJy^blHM`1rcJDd!IFW)U4AQnXS8+18~O!02Ly=SK+S zZ7-2Zr@g{|T+Ej>O1d?6zqBjHk`^M#djMMp-v=w>Q3MIoyMnV_8_*hspUH;EP|$TL zPv$k^t~wM|!Knj^s>JhaXwOLIOT}l8bYnDU#Yg%eO@hM&GSO()xzmQB^LQhPN(j-B zwuIe2Ts&WhD>#C%FPeHZ4>+R)#V64;t1y%r`*3wJqQB0VnS3pZ#;UHc;B<2JL zjhyj)cc&I8%`PoW1}86=H@n^45Se^DFXGwa(OaP_H*29M{t4ax@GhKE7A4Hu9!mn^ z7I>3HTxV0eyGzT>M|eEaDeMFW_*=p;${imiuURFAn!2}%;=E@J1@eCF7Gq{N@;Le! z{{HRic$IU0hw4Ce#A9jIGC{Kqngx&IDZY2MyF~|zO!ANosimh5U!*4zf^l}T=rRBo zWF6bGb1vH0ndPnKa~iFLhoyK;)5gGb8fRBp{bATUkKLf%sb_p|$X+dG{(Wm=-!`Y? zFpGNBMsL%D4UZLZGHUjRi1YUwa^to7Wojf!2ndf}a`$??y$H8t$XN^>auz-;tc{Tl zM)X3bE~{!SL{o6Yvk1&!H8Ia+#@DPZ2=$~5{N-;}&Dcrz;fdJc&ZS_V?0pc9=U*E8 zP2WFZZGU#fAAWff8QNjXhgOwu)C%VY@?!pnwblpqCxphs(Lvt0r@692;bxDv^)6(` z_#jw2na$qveM~!^kf)l>TkQ++#0B4ciYo8bZyWhlcRaW-=KT;}2{|r|oLT?TD|sNJ z1m>n*Ofo` z>K>fXDDl9F(j(@N0osmrcrp=#Fj8~&qC6Qz7OIoU=BTq(cbly~p{j=NP79W2gNr%< zB5!hWEO~{I(P4=WMTu_9X5WuSn-h601PB#$YYQ+;qsc<0Ts*Dx@@;XDpgzFMMFfx! z+)fX3H4wBbBIj%;a*Zeey`#n4R)xGSwAxGXhKuA83 zRmPO0gRzXJ4PGbknG`{^NDNgA$*=Y}=ASEN1rZGnq`f6CcSQ@ESr_Hgrq*mU9yOQ7 z*G>1-lY6#*p;m7feRHUGV#bTdZus`axHz2GA1*jzz4_jX+uu`!`=pkso3lpM>wPjx zwG}0VbO*wIHzwY=r{3iigs!Xa?R9uH1tSbKJ(`^#Glvh?E;c4X+PgbutNVQBM{y&c zIn&*HIv;u;7xw)~$$3S`b{Q3Aug^k-g{jTl1Y>!9yExJDo#UMyUaXeA#?#N8e`C~o z?*s21J#HU1FSc#o{(v2Vyl$rX*4Y|IX!E9dqJ6E`x7nGRWbPU>tu$)cq2>Zy4Ij=V%8Q%tEW>^9HFzGL)Zk- zhAj@n1_s>5;+f7ZMjmXpVnk&8Os&xykDqBgBaKC)BmOq*<=B{1J7e8z0jPQIv3e1f z6Ph2or75i-3|Ht18Lco6W}|A~)K~y&<6J>ok2m&|fGS(!+naP+=MY>FzXa>0wixk< z0T$YE=%Aq>0$t#4(7=U~7AdVpSzFf#+T9Z*+kS6#Z|T?zs8jVr6Kg_cdaran+YxY` z^n-<@Jb9uZF{BGO7^MmtAs|VJu@cCRh)5JIa0#AEDAD9*o=abNX@?|{A&~?9Rv6HC z*c|sv1vMt_u9I`TIsx;i>e*~;f|WN}_d0KeCS#P)4F0}DTncGb(%TCLorEpWj2Vd6 zQ=eT{DlOxz&~gtHie+a~j^3?_F63Js{}9S>JO@$3Eevb{o|=Sys7OAdLcEMK8EW&d z%O)||qsT9@@Cqn+kM({uE+!dhPG*l`q463+qTUT=?xo>QobXnPFw0oBU74_D=432Q zH`98`yKbs2`M8LGD3|e`8&PTD>%l)RBS)J>Dwb$F6fxeM;J~SZB;YTePrkeih*mnc z7V-=?8+1qw>5Pw+Ywuq2HU2;9-ZxgRBRlLoRbB7Rea~;L+pS08%|O|$zHBKit$?&d z#i0=aQ+?T#o3sEw%3@X?#F!>WBTHT*$b?s|8xJOi0FjXmU7)Oc(}s zZ6JmXY?`EYhVl||;4hmG_F$X@#=;ml+89o}n~AxQ&p!< zo%(<4-gEo6ZZIwK6=D{36X{cUpci$O0FWV@pop`EhF{|=j5a1t)#Om#j%#3?o%HMh zw;~)o)APJ#ccuNd8={#>J#$%2W{1i|F=h?vb$ALFSpyD}3~)@^=q*c!80xQqF^vc} zdU(f@RzVt|-ZbZ-J!RpgqfB_?pd*cA8k#J*aYa`0>^&l-p!jaalAbCV5n#O*o3G>M zKEG+jga^F~kp#RN24p-VErBIwcA_^x%S*Vt1U-!8333{VjFO@uCCJt6C=HJsa;r*d zYsTz+eC%ehd4Lg#aeY&^_Ne(y-kn!Xh7l_7&0WtB-)3m+9tRh#gz7#F#ak|uxL|33 z3VTL|bE-q*gg6)UfS!n_HXL(acp@gH-pWqs)WW#MgMa#pZ=1KByV$p5aT-#C?P)>@ zn_X&Yt3j8|c8Wf0deU0gVtN$bw{XM!EyMe;SxHpcbMeh=z)06ZrH#(iZe`YJ-=nwY z7%va+52#yf8Fs0pw~@`|Y#H6m`Dg~a6IB=$b}(%j><$`Vvn zqG&|FRTkB&*PS_)6C~3``m;h*hb4DofA`YOI2| z?(D1#g)!sh<1G!MU(k49=+zh13F<(xQ5R8BRZ~~?mM0!Q8|bqV35*1%*2EA1Vv~1O z_ZlRvR0C@fD^|?CM2(T9o6&k$ZsI7yea}7{Pbe}>Sw)SQhHh$1c06V3H8fM7 zmnqLx(4E)bA@4YKA+5d|dR0?z)c0npnQ*CrTJA&8V>NyVmdlkVF$>9u8>us9E%l}V zuUG;!U!B8N-sGACoMn*W4e_*_$*9nJ@k&{P_24iKGci5|hGmctbns5~*9bDwArle2 zi=se~=F2aVA}Z;g2JJ6^@i=$D`%Btwr11Jrze>eQ4~3&NKqDt7shy)HyBZgj<3WX! zJmOE_mQJ8v0wzq>OID;BrJs!5 z>Eu_fQ|A_r0s|L2KfgqmCJxIjhCGtYpIHPg3>iF-Hkheld$_rx+ z^$`w48JHnvBsq_ zjE2w7c!0o$bL~tQ;w}VC-^jCteaV^U&hvh}3;GD%zHPCZ;vRXyY_aPsS+_b(H~c`5T^d6)k{@x-K1*?Uv#KMTgO2kpeRt@HdsH?(5g%~_7GJvj~38{zapKaW@waYix%wM zcsIr+S*+jCcsh3?|nXZNsY#j`_Y#||?)IJGD4ZC0*t4<;`dH^^EY6ew=G@I&XW zoG6;iLa~3y^ed_Y8 z6cl1|)j@Uh_Brga={Uqkcs#ox z_Na5Jjy;q1ZqHwL8d)LJVr1K+*n+6MutsK6O{Ks#_)#twbTxKQJs8gXuEMr zKhq|y+#d3LNx#q3BFF!1P;y5I>k3KS(p6)Cli~9m$BA#PL}9l8aE^=E0%5{4Cyr4d^Ug7aOZjG=d+=V z_s3Bda(T={TJ**^I?eE!<$YfE+b1it&@5(=(=caDE51Ok7q+HT887C}F|I`O^-Z5I zC2|wt(9!wY?{+or5`Ro9C%;4#M<}B7jjM}mmZPR&js4R@b%%WIJF&P ze|%{%isScUznizh){seW7-Vc-LL0_D+mzAQpVG#XY`3kD?i;D4)y*1*Dx8hWm}J!ad0x+u={+t&Z=r-&X#l>Vwi@kA2|0O zaFbC&jKSpLIWt)Vy68&_Yy7&}AGDazX-BZhk`Nqq09hqtZ z?mOu*zLT)b8amu+CDXdZh6NsE)iAnXpZzq9a(XuB-jXt8K+?Fod888oA!u(39-&*I z?0G>DMs%1dCxDEJC62C2D8K_{#dq642~VXcIFUUcZyPliW3G9Zl7 z7P24c*~QUflJW&Q821Vg5+^{Xjbd0^Va$8CYR1O%)O)!1Y z7z76lv6h7^kJ1YY^eGn7(O9}p!99dds^mfNh45vHP=ske*yUq#tr$pOHM9)R`YWn@ z@!_<$VIXZ={!Wqf?}<-oMT)Yp<&)?bF*`^VL;;pQrF0GP`wzV;LYK6`+*h{-1gMMUIJ6iZlW#`$W&f1Q3UB28$eTL4UhuRB_)C~s3hWlD^6kYhD zv?m(VqA+FYz1<%8!LVKK&rZWn-{ovyxx|o$?7r;y;C=h@wl9k7o%XU*41%@P)Iux8 z@YgPVSr#2{3;XK+1=@(E`DhXewA79jQ9iPU1Dy7)pck)5JsOh~C6>ku+;ChBo`0QmeFxC;MEvU&h}o-8O^E z5X+B-LUS0cM(xt8Fv9ATcvw%HaWQ!uQ-00`zJQg4$uv%tWM z2RB61AbHko4abyECM07YLEZ8&VPl_tGEcW)ur6{BIyaxGBFe%P2{7mfMw+3fMI4?mubyC!RLPgfq@n`Y+q=VLY&48!HU zGqdKhYx`Mqwtc_sWsN*5)FGU|{i`E=c$$c|55LP`|w%5-6@o2bYC!k*OYm(N5cw7fHc@Dw?0a}f#=%n=O)z*Fpd^qGegx2JMeXK*&k40;aIsl}u zx{6dLq>`#?QmD@>QDv#<>Lx7F1HJ=jA7HB(v}1-eprLpD6!Dcq*)a^AJd`geu?Az4 z4#-5Wm82eR)gF^bRG(IC3T0#|89J))jH!<5*rSWYl?Ihk%URVOJ{3hp z$J!d#N=QBd6``aoM>?=5go3e<@HZuRcK9hUB_-Ig*;Y`O9~7^gDsFX-cmp)OjZ;C! zGEcEt&|a9unZz<8EhNUXGU+ol1z*W0&EVng)4fJ$S_D3mL?AO1I3c>zO;=p>NPn&2 zptzNPC0HGr$^{Zu z$A&4XVjyKC9UVZNw~?t6ZMi6B5VGN}ywQb8e7jm75G#u2sV>o7bqth|7H@nb64g!U zWxAXvYg(U+xmYGR^|Avep7sQdfV&e1Qt^TSq@!O&zygt&HPwSJb31P&G=&6EO)zwQ zRL!6kU4#-tT#`wMiCLAI)G)5DDMZnlGl-Is!jo|Dt=pM<@Br&WibT^^3M3}G)`F25 zB`BmqMG*BuC8kDJN&*j+6g};iT!9`sV%e6GYu;6DrGAivu&^ISDv7W)FuN+}0r45o zylMHK?=dvBD1}alPZ(+QwJg&zt(>P~a{UrPWSxQ}G362~URFB=a#lV<574Titpe(B zE`E*PjcF@71nN;z8V`f7LxNEf9u*_-i|MLZMN3EuslqFN<;Lpbt4l~9ajkF$o*JQP zf%ya9A>>eLLLyhL##e3XReON`iF9ziVg?W3lUqC7#jrJ+8bcK;Drp;>$9(Guk@5v5 z4}!=&P0PU(OMy2#$d&YgB@MYKK2Nh5ODU!qUFh&AO|;-`?9`V2lspRmB6S|Ed2Fmr zD7S;)K5(|PMIJlS$8~N@GTP2S`yrp%WL3-_^7XDerHaayeDf<1j~JvSI>+Jc`Ls|h zUo=2=$;xZnMy#M@iHN!zVQZ{wYZQp>G&2$y!e9VnILvg(tmFNXo6zhtl_?KlY7GTV z#N&*5Ni5MTo`ZhK{c4h;3vC_&ZZUv^*?yIlL~TeBCSD`dgGH&aY(NpKqXYVZ@*p5H zTRe)9=C$afMii^R1v@=ndx=?~MA}MstzxAHl87}YP1OYz(`&D>GK^X(xE?@IQN5h@ zEYv+(34}u{=R*E&=<_YU>^qpbcTR;MJ_hgJvhT?}@#~V*F3F0v)|G|kQ_y%2CE#q) zF0?`TG*hw5@(?Q^L0Z%#AJGm2%1jVemzq%d)vYj)3R5pKix#B9K@vr&F4eBmSAg37 z$^a*2pK=LzrcU&VL`V`=^97?|T$5Z}5`;r8XeLn!q5dhRIBDxbvpiIql|`ZS17534 z>u6O_?a|RH>GVLcp&r4YGsPq!gRT|X!UdB4fFF=aMg^YsZY!FFEVK=3Lsp;#W$d`V zy-2>~JUWYV{PjhEM-Vw4QqDNrvPfekk5{mCrQ!u8DW&Fl(6sBEH25x9rH5Q=C>&tW#yhc=7*DP7kWee) z6QWJMk}Z`VoNqEGP({+R`*Lcj{>7oZ*7qhC_D4mc*l%l;ote6IJ{3xN7(A&QU5l#{ zR0Vy~4+3aB6?N&a-MR+F>XIZZu!f2?E!0;o30Cn|SK46kb=aL3N|daYF{&DgY$#j}I7%4)Q#{nQ+_0;*Ap_E&ilx9`shpA>Dy^pnEB7k$k%VMz56 zZ6uX^j5GQqzW>E5+kgBoUU_Bvz1J~-bn)dQpWXiMduPvXfB0cC--gjPOx|F$?bc^+ z+gmr{my;bf`M22V!pzfsKeob>7mHD9zHMdy>FiHtw=0R)v^BPaX(}uLts)=$Q;hrk z*nxqzB<aR9_cYA{hBFpA)Z~u8cp?z;DH54wtwu8l}-fyM27<{{0CBht3gAdqk9|@ITU5vHe zzOVUz%b$FkWWUu*0V%~F{DJ%dfbFPt>( zO|9`$uWY~aO2Ur(6UzSGv)fmx8%A{kZr`StssXR<+rI7;cXT{TaJV1-&12cEe+}){ zcRsEMVQ%gBe}5ft_RnBH(EgBU|L`BCjzYfcC?AJm6ixe~-1^+)A7{Vuhj_2vICjf^ z@Ky4C@kRRKEewp&59yoA87CFy$9@b$jsw1{E}y5X{^mO17VE{G)HgqS3<;7Ux7&)n z_^#Y|>SbPd!J&U$Jxfpf`qy#b_~CuGjzJ^J*RkPP8EAX)-P9RL@$yBuAlN+){>$1- z`TxuNq3T6#3m({YOIW2Vs#`-f%DR)Sjj^q130vDQ%(SbH)HWL?6Mu+WCrM%IN=b{r@he73Zs0>HiD5{-;FGRiq7a#B%`7$Qc)+WwsyJ;iU zk*3g=gHtg;y;NSL79c4VUj=#pxx+T$(gHXcUOV9Y50WLg-4{o?Juqyf>Xgb}1*{>a zEHraHLR0|N79T;YorMzF(I@#7KLjgzLY&P!FluR3h0Db0Au747CTE3DgFrClzdDHogX9IpM9l{Pbq z6=&t5tP)gM13Y1RmUAeS`_epChtF*5l#G6)_-MhR>!6!qdtybFj44Gh)qOFOtscp;SimdY> zNr%?|wAAjy)jP!TG(o%j`pN#6tS-W8^jDyb?_ zSYcKuQAKM|{S`LAT?!y=8@;G2#06CB{V5R`-2_ z&&kzC?FKc}JB7%aCk&7#Xrr2V9%T14#nifxpLfN1R@#{mqTvg&vqEj*tRa)0#B}5; z9HMBtunzoB!=glQr>@vZ?3L*0zq517na8nFHVn$*{>`Q}UFN40uR0#v+iWK$6Hl>-NX(#5n3pL_ z3bJYQrxAgdQ|1A0CB`ULDt2oYeHu2g`S1lsNDf6jE;qij@pu?>> zg~sG2$M_XK58ELNTm2#yyN_}p_M5pL-=4nf?ER zIaWQko>a@YGPA++@P<}OsjZ2HsMi8GZEs|D{*9&P6(#hgdyF~gI4Z}Yg}uh%vOZP^ zJjw5tNH5%wxy4=xqBhuL4R)}0F<9bsZg80Da2g(O1K#9zOx=oshN`cIAU&_49YPxc zR*At-g_XL!m}^Vdiv~i;8eO2a-W z88A)Iq|^o5(!`h{zGSO#-5j7BsxOl3~2cjv8paykz7oha62OSot)6mSm*_2KbB z+@w(!wz0)FYk4a%X?+!7{0Lg(hBd}LT1>U99 z?8~OKK5|cycmgmdq;b7i+Uz)_L*Umqkt0PEthmWVUiY}z@89U`cGYql|M~#U4d$R5 zedeKl-xBE)pmA==OLh}^^+fD@9sqiBCg;TvInvL4gO6QkMmE0r%q5!BjkES$n~de~ zd=j0a^|;I$OE6jPJSo>LdEVle9++;(>4sdB*3uA{<_T3Dptlsc)@y9ajb+-WYdJ!@ z(KW{&ovrxJpKFF z2TzpCuP)>9b_~*Z_6EAx!FXHmT5GxVo(08&%NXg}*P2-|M$z8AHo0^7A~GmIb@{wNp>qcX#`5 z^|PH)9|(6Wxh*Z^UWCS4sQyLT`&5=y<*w;>V^Im-qFm~TYG0z5gvEFiwfT)+9L+aq z_3lB(Tk%JZ_U7ioiTk~{NqE@ypX51+r>4BX(%329aoan5vGKBZqtMNJChzhx;;if3 z(Kp-9jgJnuZc-^>u47;?n?KGo-@LgSwl)WXd0c(vVRN=+wzig36t9!;B;Tb5dlIB# z+-`_1f3-Zn6QjRfke_9w1kN&3vSQ>jEd*pON> z8dws=>sDh|5JDDX-n;3;HSHgLc`PUOv8VXt5ly*Ezr$V)*5NL8Z#>n#C{JNiQEu%% zHId`HlNArWjt+akgZ|T8lx)4aDi%K|Yqw@436HTkHB%CyzEmLhaa7X#hH3Dw& z!vNx|ype65mON5hJxKbipn=~sUQITJ$fdH<7I(;zG60k023!?M4MX)*Ayqzl(T*%j z%tlQ)MX+v;k9{R8+o|~3lDK-j5#>f>L;;rYy|!FNp|A7wbz|;Dp~Gu5;uM3S=2JPE zw_mC^0pe-R)q#CojyHYeB?#gv+3ZD6e!5Pf-^Q|#BFJEgg`)v{cy}nU3Z^1cMv3D+ z>g3&Pe+9`XE|9c#L$MpnrCubkAo9Fi!g5fH-nc)a1=-Y~$UeYpy|jqsWi%7{s^5*h z_mEa{>$Xw2c%!M&m(V^88b+)rti$*miBg*SY4tzDSh^qQML!7AX|GZpzDTg^k57W zgPkG8phqG^52wdC@5!2VsX98Vq+Uq9;LX~J?fnj%NITj;pVBBgxkVl22*}?HpH^ zFy2P%^}Hf*?#_4gVZ!5n=Qxc8z%nY4BJ0uz-QHtE)hpFn-Dv_vP!_!^^=>CLY-{M{ zqD-^wysnyP0&EoW*wq^pUT+k#6bc9)!&ZQ)4liFwN`#9-5~o7%EjNZ#Pv2XpNU-Vy zHKrez70~PpKK&zFX|(8ej1eogOh3LCSfG3H_A6ohg2^X=yQ6v8hf&~8nh!F3C%Qld zvJ~`NJa(<;uh>;nJ_=E}z%mQ5%W4)!^;SCW}%>P0=8?^roWLgMP4_{!Pl< zz=FrgTV{f7561C>@msYOEXC~FG)M8^}N2|o%^Nr7J^f?g94H--ugo@-3%swA*W z5|{w>KvKo;W!M#~8k_Y0Nv&UFgawU-cLE+hWXPY^k(I%+f?OVt?Aj^5_;x_pe< ztkM%5B-FG4pI!k(VFpvI9n`%GZ1NM%^oYBKH!-T{I{$e@>4-$=q14zPd*3>047zXP zqOnr_PlA?%1zy#C@%^QcjO+64^wJ9 zq>h*AjC7q+Xs^8{3Qs1to)Ez)69r7rs4kk*tyRBTqME7?*RhsJ?6fv??n{9|nLt)Z zES8ETN09_6F`TFl&yVDHfl*068B~b1pnCf~)I6dFBu9}IkYCC&tO!+X&oFAd(gGaQ zE=50kafq{e?tNJHzaJT+RxWV37i!zB8}dQD*Mt-qwJ>8%G@9AWBR#Dvc|i;XkKVFu z=3D_K#t@ZQH39;2R$VsWuj|89{gxSGoQMa`T+&^|q;<3(^-~c<{%9>8q)2t7lcxgb zBf9yRJn{$=}f>%U`4%o z#gL;3yzq5dW%b;da8V;oFE9XICa#So1+ZRM=G=NEx|9J2GXqDsoy(ms<%=~QHc7mt z7sSO7QZ+haooo+7;Hx9sR!}k@Y{aUtFKxC=L3WhA2%zR zf6SFZ^r<6Iq?qO-63CD!Sd)kb8A28qX!)TNB}X-h_H58-@g*nWqIlLb$}|$-bxHc7 z?n$ib@OcRXOfNvr&vS>a6+8XmY`@(qUvhan^q(%nbCPfWv(-9lV>ChSrMX37e)vNalaO`3?b@&j8iHvH2Yz0h!MglprPSlHYaWH zklc8|JoJ1n8~veAUj*AU%x}+y$bG<*ZgZ1m-==xBOCMli)VOW_mpYB z)Gl-xYxmoB|JiQSbeUDp4R!}uos)C4ojf;)Nrsnka(N^pEroFpU%}lRm^VilVj5%* z%||iMUdZ@jM(D(_AH%MU%7DlZcQIl$ctHlIJ%w^pw{e#5qRIJ=unOk2wfqcciuu;( zM9sL&&$RcA3AX1?-(hzpX-|qNPT(Tgk1*R5RA+?L|f1=JuM(U(2CZIKeyR0ie~<% z{JkjW9?8$SGaa!u7G^ij23s^1H)tcTL_R*WF%tWg0ZUXM@d=ZG}aUeRIisI$toS{L`ap=!S{;mDdL@KK)BrpPPMUIy-f$ z8_MZmA6*XnTjs^SACJDWvC+(1tzq+>J$h7F3~Y9!*t%@Y)~_JiBbz=mqqp4e3`)bWkBw>tK`+bcWS!dz|dX0LnZ78=|Y z_LRGnCNRxXb$XVH^EOU1Pz(_pcq+gQE`KHJ(Y=YXJBY1)&x_vdDbLV8IDlzxygk~& zjtz!&$b8Nh3!CUKYcVy`RCo2cWjH19^|ijFr(C0S)>OU`NGrsT#j(#6BE5mI8}-^= zxm%N?aJ1wC1%EYtfufv|?S=Y40#c1qbOF)((W zn*$~K$?QOUSzIm~oMnk+WOD;s1k&i{TMA#=>lpGJFjiJjA)e$*Ae8zsU3*+R!l(O~`Qo!(*cM(ku#a62NFo@1MWx+jTV`s<&<_OxO8$L+ECGL&=ZoYeIsGo5Vx7TFB#Jlsx=X>qU9B;Dm-(xY8 z&5q^G@$0?kz1t=GIHRD=y)#*Rd zT#nIyhBb;Mlo5MB&-e4aS&Qi^e|+zFGyfb`?{*6e+datStTImwJ2?v-&ZPJOprmdo- zYq*Pv5`@$sFAxw3y?8_`JW6)OLwM@$y>RKt}*o~q{`;%)pH2E;?d=<>Aif#6VI8d z9cYOD+UT2VR*03umc0itsBfuGP-g{Uh1?@o=D|afpuCX0b&pcKL*uL3UQ9uU9o8Y* zH1C3j-k3uLotmyS>}#BhF8zRIqQ!*o;zo3vVUMu~DUsg_w7LSnDp52o?^^BrajcJ~7?cPzq}iJ}L#$vPJhI*E z!Dphpgis(R7f};Z(JInmTq!AnBI%B(B6oo@J%GBOC@t^@BuXWzdK1L@Dq*t1d?e$F zm4@o?E(qo>0^YDDMZd-s3;c}7`6#nW$d9mtj0`I{gr-7x<+JK%t4Ql>M0Plaprqt{ zG+*oc1)=HuV+{W(p2$zZ1d`dfBH-f=jmIqmF&C;vR#{?2Lx6CH+AG?BZa1m`s$8t^ zCfN}a;l(Lk8$PQy#bQ#GVn9quxC?a{suX>;E`i`n8Wh|?(KR%}aH)BvhiBM6ic+sD zK`=?zrKU(h{zH-tt#CUoTDm}`bxAX(=}L#)%Oo>9k!>VlDqmk&Xj23amB%Tkz!qXk zO#lJ2_mn|%T=LVaz@7(yf(zKH)p|@|g2}E0lCoWM3w}dCl!aC#IT)NskcXc{2wo1r z%XWp=)y#Sqe@;veM=18k)c(hiltm?+Vrzhl=9yrn)|J1a-sw{s(yG8(&dQfO-=|Zh z{5~RoOvG?UvPY9|wM3|b4wXEWmPdpu1trZNP9D^gqL)FwT@CX}Vu6BE0~o4dx1coj zZsWibzX5}g;81>5qMH7n|Kb@_LM;YTt_5u@4uo5UCxYs`F1h+cYA>&^+HYMORTEk< z+xB%#y(om_DiY(NEUWk$sK1q4@ml$~Kc6&v5Ddad7=lJf4Dyz$Jo{g9|Ln% z{A#}}nzw!cD{YgX!a&l$(C9QPuM!MyNs+Q z?^{2B_UxAV=V2Xc6HTC{d{Y2etT^j2NQJFapfRLp#eatriMR#LT6ysWi@|~yD9np5 zv<|T3T?PD+hW^nPCqK1;^CNEb!sJux{K&?)@oxOfFWRR!UP=KYbdc1*YRrt)dKh_- z)nS+;Er3*qsdwPZJAC(;2a|kgErhqk><7xB)v0FsD(sW&l6`6V;)}nhPFY!pNH*7^ z7A-MQWNTct9L0fTUGFYh6@t4ovBD2oc)PA9-I8;VN0pmehZ|MVYj>Sds;xW1Xie)* zgBS#cIzrTI6?!P&yK=kJI|`a6=_ss9zShCVVI$A7isJS7c$cO9IB9XVl7J!P+A8g2Uzf8*lI+qbaNwEaK*W*V?Dt@hOqFf^y-kPkn+@4oEn z)nmt!H@kJ~7^a^jc`1NKN%rX|^wqQ3jT`U2o4pHcE4F?0?A5b2(Qe%M@IEZsC0j*g zM7A#ziUp{PSb~yw-vxX5;*0NQDMd0Mb@AoTeGXGn2fDuJk^4Vyzx&?(zmDZL`H(ND zVX*A>?N7a8|K!_ha}D_3R+J;h12qfjo+0&UjD5@{%wJ+r|o~H0^L4#HkpXC+9ucR zKM_lo+_%bKezv%n>4zwfBp7-*iF3p zYxXDqqnPc*;@z`U%l0fA-F+pZ}Kp1*B~#1KSXKq-?0UzrVPR`Z0t#Qp10Q*4F>zD($My z^4MAOz3;o<&92_YTH4jyz0WdG({Gl``_5+Czeu*u;~*Istp!?Jhg)MQ6iM$pX8(Nl zUp3{s?;SfUvp@eYCHu9V{hz~HA|udZfr+?3pJCxmTf6*Ss($qAi(8cix)CGBKcyTL z=I~>Ze}OdEO-#C4OYn&p5*(I3Kjh)5zL;@9rW;C@TWT30avOI`mtZ_P#3>TBrfC}^#oGSzs9^21_v;tCdYs9KUnO8y_tNKDbL6nUKjmLI(sks&s~3|Kd=mcl0t=2_8IHmZt^! z+MA@Rosl?>*(*nWR@2s?cGxdR|Y3cCv3{nmk z%WsmlO7YEAitl{u2OeK)7AC*k|0hwg#v9+n+<{lr{jcg)fYmpzn2A48W9$uVtoTX) z|EhIh`|-6DPm2C~wGK8-9@?5T$l!?&Oe&@HpGsjF7+mAg>gHAI#0Frf)3Y7L-Us;cRrV38^Dy^zt5TCFHfupUqMtf8l{XW zw?t2z$BI^Y^uX4k73L{h3e{+p4!%viN<(>jh28Y4(EnqkF)75k-ODdDl;s+%4o?b2 zbwJY1c>XBS0?IxJ6_+A)lUt_%CrWZ`qRW|WQY1K6UDVa-j}*3hZdzlEhO2nRLFhU` z3a#?6Rf@xTFkK%=WhL2blQXrYH3?a?l^wQjf6b8jxblR_3S$(jX>!t+l@8jSXlYk~ z`O0oZ%e|HeS&XVLRPl)Lg9(d=@;E3_R0b;jT#>&9V8bCHx$j=1)pC4)PdiJe6umz6s-4u@2?rV->G) zK+F0o8b)nvNwpOLy=nfn-ThA`eC327@o6TCaWwMywmvu-E$ZILxKGdHOPSf{SwM+7 z56Wti4811c2{`p0YR)`pC!vy+j$A=*R#=+gYwDiHOQ73TFB0Izr2^Gs1uVrgxzZ(w z^&wK!HKS2Upb+@?Tpf@7t1>bjh1Bb+0}J&icy$6x5s-9?+Q)%Rln8h$dm~|kFj~OD za^!W6O->u2J2X!jk_kXL*25%lt zR9*8j0>xiMrO}ikFUBP7qmGXh*&m|kZTGbJU(|if<3=`hzY`cFv0Q^DX-(cnPR?2B zTZ!mCJt@FzI}4x19T!Z#-*f#+hp7U5-HxiRd5{me-UYsH8cF0p?$WJdfGMQ%EmT;2 zk(SSK(+*akIcY_A+X+#!hoE9t5Yi=9p5&4Z-x8{XBj#TYyg@RAtNz~sb5(+TagSG0 z+Fh5;LMucxX3cD*#>vL>oF*P#h|*8VHp)7++2zUiC}ns%x3i)mvJtSUA5J)Lt>6sF zE5J%yr@|&E-6V95O+1kF^tu+fj!;EYvxXfBh+M>74EaQjmx3mp6$Vk9-^sqty8&4% zo0z?pMzL+w1HVHMSV;xG79Tsh8{Ux(!kCqNdiOXs_xg^0zG23kzweVLi}=NyLu6jn zA^&LIG?2TD-@z+xMyz}@NRjiDt@u?f5mFFr#05F2f>+Wi?H+|jC0D1qOnG}O584<5 zKYjOI)vHf*rLLefejf)NRa57nsx`_Sn`?uPjnVctylA!?}G)-HKHqX>r2Pg&#aRY*D?EfD#=*E1x0T z(ZuwVv~v(yk?4nEH!80?Wq%AaA6q6X_I5s2*fEhq9TIKTT&1+>1M7=j9deHfy`A`9Q)>o zt2Dm*iZx5mjCn1*Wg`1~E0K6}eb{DRgly{#o+(!e(=$<3a+QZN9DqN-?kOaON}OGZ z7OkV{eD@2EKIoho8q@K-y(2T?a01rI_-c82Se~exnB?>F!{glD?5gr2>k088guUrf zSCjn*Ai=>v1%Y`^(auIz?OP zQBVxjjG0zt66IRxOJ}#w+^Ys@!ek;BJN-%jsYH;zOemMT5nV#S6?6tzLojwJ*Nr|` zZgZkX{x=;XNn=_ZrR_K0zh25ovl&M|50Mr>_teHRMp|dF<3*-)kBKa|ceRrGGQ~O? zJ*em8s5L=0tsT=y8@FiKDtu!})(v*3jq#b~(u|77tNsPG$KrF6k#HaFHXMqUMwILZ zMjZ*`(S{}Vv*?UeXR;k77_G5`@u;=Ft>FuW3 zWWy_-KEoRi0*5BQAQ9Cv-2u7h8DTBM-=0Mc5g(6$NW2KY5|5|G)=jIn)lKc(6@e%W} z#|&a~BrND7!<1W&tw*_bDcy4y-^|PSAVy`cqto&mW|LPnSNZp)WWAw%iZK7U1bv@J z-1zc2E05Tzf3UY>{F^%a1V-_E9=B9*@U#zJNo#Km9T z{UKjGD%UgF-|F)bRX4QqSgTu{aOS$1xN~EBzHKJg8~KE3gGSPtQCl|pYn!8GtGP8d z&r`_v2fQiSUgmPbji2z-cGpL(SwD);lR`^55N8FuY~Ak5ySFA!?M@o~-KUrfcDr(H z_o?nvx4KX5_Mf_lnT+F**UNAX}g934+mTTYuDT4$f&UD-`jp9X+W zxYY2x@hg-oCSLD1RTEPQvcys~kRGOE43XpKuZ!ljf^x*FYcJ27&vuIb*fS}&yXi5V zC3%mRCYOgbd5@bWYTnVQ5uID4)=9CU{bxS}fQ2AS7Bogsx6nbC4 zLkW^KoJt^BBIUA2s78nr+5~liz{eXM`E<7j$Kpv>WQ})_uQhih)uAFQD5GP%bMiLn zQXWFNQ^^f;H=d}vN)XkBr!IB@um2rfhd|mcWspCjBj`-pED0WzAodFq9*CPnrdb3o zfh4^^nt^&~koP*UpLUW(tuBh2?3J^)=UwuaeIq(Eo6+!dI^)*Q7?w+P3ei!>R>iVm z?nW}?bLGKD?Swd47^`+YF+!&w*}R*;j>5)nqP2cOx1NsB1bsQrBip0^_GS;ChjHlW ze#3^xIKD1k_0xRWjN|qw=*ez`Gi>&jINrwwBYF@r807Y6B09!=+Eajd>^dHl~yHay<85(tiUdiDM_gs`p?i}-a3wIGHmMZLY=aw$JVjm64Nl%@2uS|J)Qs19mS zb?HwbdaoB{5u>7k-wNUikzfx{<EQ)iCocojSpZ67OO+DjAPZeOuJ zIP20|Y#Hf}^$}W>?ke_2t|U;Hc%&qkB&*|sfYFmrMgVz2iXcFU>7vdWOOmQJNd=NN z65_aP!3$ibwn^Gc#3e5AeDaKma2O~Tb$kE~4>}JAe)L!m7kbg3hB-1|W?j7v;Q|ss zx&t&y6+11y4~K=7$J9clsI`;iQ{GyK%op&mdvHnx2zh{zAmXaJXavn}MLKYy`UB6s zi-bEx(?X6BJvFvg3e)D9#!IxBX2VUlT)uUj>K>=?6gAZ7p$jB^rG?7k?iorW@d*u9 zR@nT6GCp zuO5odl-`y2=*1c-k2_m_Nw#%!s3c4I5}rr(1C4&@)^kNwAhoj3KRpt|Z3x8;6q)oj z>KcM(aR4zOm?!^X46kc3t&BvT#&S>RJtAG%b{b*NSiKA^iiA4Lf@nfU9bVa`c?PYP zGD2Y=F~}|iMxtquc9=|u`&lc5DbL8w^0086MrFHU5o9klS0XAG8A!MQV<|bh(!vEE zcOhg;PQ{iDa(aKWZ&`WB!)0XsK)HNAP$5`FY@gCWQ#XUuT0EIVr+B;sJx8v#O2TsKLs4QezQ_h+JhOEcO`3@M2H{*JI%$ zZq3u<^7)44?7|&EqR^HCy`PK5b9!ULU^4b$90HclXnAF8E@8VLs9=8g7N|xPLhV>Z zIl`0elU8S=DZ5^dkf$Q?NH#DV!Mf)Rvxl@?pIQ(68y_=wgo?4PjrmXXDWi$m=Adw! z%}aUNMq#ZO87tu{ozB2*yc6;%(^fa%pf$VTSPZ}Ov@F;(M6%y{6#tcNv*Apf47!~$ z2MmL!NqWU~F$j~gh|fyD-E3x^k=wt}*L?ts)OeD$3!B26 zTdgwcbEo!EbCP9opAtsgNKr#OxbDU{WN&ACC2cJ1>!WVNZFTraP_{>B8eS0BWl1`C zZ7@jf!ofBK8kUjEVQb1l{6%kM5&9eX$&v9@lEdDG`Kgv|Cw;*m_q zIq^YE1;qnDD;lg?3PHT}xC-Uwg5z=UD2p=A2XPv>Ni-dVET4op^<%x!NNM^hpQh^f0)1LT@_1$--AfWK(|TC{NA5+B_Dgv1xWKk!xb$|GyXc}3 zIqQ7f%$@D%y{HI_U~LRqVBc0|e=mxbM~d_8i_Vu%Zx{2Y&F<5(-zt7N8;s9gID)-h zH};qbns?#@K9|jQ$4>??W`5S}=vNjlKkSAJpD_yUa>GB%vbpQ@;hgdPKSm9(dk83Z zpwE=_E8YTV`$_*&`y3YAxhf9;#`q!z4I%XAI6a@JF~DD(S9#mc_F-m5gcm6 z`co47SI&8AWg;UQ@c2T1Mpw$sHqrMyr%)Z|X;t=@O|kJB6+D#pd^R={#?;IGyj5^R zAeS&{zj@?H+fBFRfsXyf@_dIz`8)%Q5&vxLv>!0L_L6%@-}TqUn$-%~@HoZ~x1Scw z)Zi)P>q5c1xqrzxd6W5Bsl!=*wrF2je1`9Uy6(uF)6plky^$j^2#v8Dc=lz1R!JO< z;R77G-6TN2Ja-rzxgGZB`w)yFO}@Y9{648KB@H&^c(9@Eo}n8Iz0MaHi5#%bE{lLx z{Zf>Z%X~0xxnxVdCuIhvvmrjCnfsD9H;_`yWLQk-4an$2R|1UE;aUU%MK$6k(vu-3Au#^x$Z|Z3m6a!_>s1^!*;$(bKrp85TN1~Ju(m06bafmF9_6f0Hvwcft z5y8akW9wR198-&H_b(R$&rbQg3A23g3^y?ceD2(I^M2XS_%I69wC#*{gV+7AK?P-# zpf^8-sn5{@sOFuL0lSc*;GQMBC)*B-``=qS7sYo?HW6gpAP4&-ErzDzy0*cjupej@ zNEhtomaZEy>_NvhHcFeOprf-8O8d)9M^P6|$JmKC6v8r8T_(%i^#-WM$z@+MLqFO! zU9m+Of;jB8k<3fL@f12Znp&rTkx{ljXo!Nd^$trtWSqd`(t0(fb_S8>2C`&g5?&+3zjXgxVQiwQgfZ?M&RKmeF*)pLy1zAUdOw5U63fCM9Op zd_LC2#^ZZX5OVKpdt}%B9g}Z7c>F>^sp9eSYIkAzvf^0AD#QLH%q~oYRlxs8-P^}V zc3lU4=iPeUeqHK_ubNGwNl}|yH6?D7Ah0zY3Z`QLx>YPvO@@wpD2{h5*idmi%N=Hu z$O&Wd4`;z!HASX|A&{Ce!%&8S)Qm}k;tH04br8V86K03d1-h0(O&7oKM%bhdR_nmw0x#ymH?&rJjy;G~QeRXYSxBhp@aHOkVq|~*j z3f}+Z*vFi^2M*hKxk2rGupsEsqE-VxoZVq}(#UYo$IIcrj_*$j?uQ}fq4~EshYl=VYkh|0@eBFZcKv80kac5Nf1)|bkB%7HjmE`B zsBhpiu5o8ZyHD~vW8=b|8=d@C7hKZZ&bIGdzrT~*Hq0;PjXNV9@%*f_EgkgTSleE@ zEjDhQtPM9}rUwkTSqlk2i;^!*^3311emwh+a4^Ty04D3k29G5tTicQQum*2As%N38`WhD1fja<^>^+V+gI8+$=c zr(+O__yv7X@DaWz(90}MLqrBHiYhF`6j4iCB$jMJsS$?Abpa(cLh!|(;}TK=#-%ow z{#Bu3!59_03D7GPn1<|HgcQjl#gJN#`|`#Jn<;Nf1%zt>aOv+%DnMsCg()x_@W%{G zOs_?qH3pB)3=D8q0|@Q`h;Z0nBVQ-?egi4P-z9Jm7d-nN0tN2l0vG)&Ah6{D)9nzc z8u*}L2`QDcCMx3hRdoHfrvT5?siuN)YY%6%)D_QUFITl`V<<@AAVJa?BO4IWSKG$2 z#Y0JvfhIu=tW3e>Ufb9+f(z~F%ruvhm>*af#KTHk;MN!a;T?o}5>~D2?VQ;Pw9vC2eZ7;))=!D6rspE?S8x&B)e@?voZmq4_BRupGQy#rYMe z3AeT6spPTXLiFr$f^wx?`B6UJO<}I|5TY8g4{~52qDd^eT@Nf2iqREAs&P#%NE!y( z6^Pu!=rz@}p<Xrr-qKjPRmrWkJ(onQ(4dAr7;@%33E`>mZ_KKDROHw z1Cfo8UIBWCDF;$a_C;H62I*P4HXL1p)iFVPBE@L%67;v6c9>c*1(0C6sb(6pfTNdPVBy}47#67s5+yopke12dfVa>jVjEY)qY*VQ zENG5c{y{9DEGAa*lA3rBebrdatx$xDg+iR7fR!J-;pkDWhm{VNs%drZ3BqhO7J1Ej zN{%|1ykg9ns!9-MQf$w?VNI+phCDUF1`Q@|`u_RHK11*-9w`%dx&_JL9A zZ)&vyy6NAHM-yDA{sOZoM(G zdB6U9k;hVDKDEb=L1uy6noES<6!}M#|3v{{;0h`-sBj&!h7uNFtR)^Q{({9a2PKAz zIWR6`Zmr6cK;0}Q&9i&oG!~+G=8MtDMk#}tUiX$o&Y(0475h)5sZpR*x`^xzc|5AF zxu*C&;~CB(#iEPY9%PrLAXfg>N|wD|)e4fz1$Gk*a}LY7mEku+fvLZ?T^4BaDB76Y zIQ)pIhd1-~waa4IR2{Sx0TULgC4Y0$eQNx@ljoiuKRqBiExo>(3hX{t=4vl>MMh;c zhq@56YExwCxDH2dijDu~KgYYqAKeqp!bPOBf8dU)}a@$QPtBTlz4`#$&!=iBb zrQW;!usvLxY6iF>($j=viV->Zn?xXSsb zfAWbpa8rf@AM-bci=~-ct+QtD=anPB=zdTTk31_^t{G~cn@UWsy}j$w$!JG@pw5RB zb`uQiKPNx#)P8_Npbvi-e{Dp+j}NWNchvLGbGLTem)#$~RQo~pxzF{V%f9>Fn@PcW z+Gl^4;P*dw6s}&6n{CwzKme zsB0>2X21WJ@@4tq^_?G(osf2ZeABbq!x`xSUe)1dWDUqk~v!f4gdydg|J>`Y&ehTy6Z{_?^Q$q12ZC91NYW z3m&7s|DB&-a;txch&L51F|E1YtOJOXazGXn?c#o)ktf6ORisA`s?~T z40r?hc3F(_@nfj=JcFZN`|s*+efJt}4}nU6VdLM5ukZZjUos(;?%OE$PyWPa zr4!~9@$%)5?qo=QMn3cO)1N8E;YTjN@dm{_^D0_hzlBsAmK3Fv8Aal;t@MIc7Jd*f zrYSzxzVs!-Ohp_UmVVf%j9Pq9dRnV6=@@3WLWZeR#Cgd~4wHg!w(C33JttrK5|gcT z=uJto`ca|`y!rfjrnS%8NUQ%MZUGs1fBn}xZ;3iobUW$?kVpY^3mh9>yIw~1vLr~u zBi!4ye}G#7v?zrV-MRyL#?ZxUtbRJs?AeIWnTAN*wY! z`G!moh8+FjIJTm2z($!!V6#gC{|N##YlN~ABpy%*=*1y1VL)-rq_&w3Uz=)8I2R`6 z8`DTk?Gdmv7=IzsR|-rSv*~bZIW%vD6|$5IR^$-IsK+5{A*1L8GU=K|0YfFgum>f1q2o4dNzr+0VSVCL4&cE)AGfDFm5SdIx$Txr2BBEMN)Z@hHlW#WaTFJ{fqZe52WDr zZBd4FjZKofr27TUK#p&O+8MFZTL0wmS1pIMke6uQ7r*w9-TJ|Kk%Kg&1(CL4y!qOd z&syI0zmNeufJvD(YSe&H=Gc^ivc8@Y5yiduuy<51A#k4{$D zeo_gBv#c{=zP`qqyFf3>2tO%hAmE}t*+x{afnx~q#xq7{oAX|^ci=u57tp4*u4#?nl|924Do z^W^}hOIs;L%~XPVcnc)(Lr!UdRYrn=w*m|OH1Fy}HQ35umfd;LCO1_B5tV-8iR(c< z&%7X$q$&D$iNAvl%{C0)eIMTccFF_SjiY3lnTvCD|D6-A0HO=$Rer6l8g&J8VRHV zGVYUXsVXmUC|Am(cNX$=tQU&o%BI95RD7NPs>IAz?5rq7*XvT35mC`!4htebXZTHn zD7VR*W+{EXnTm%i-js7Mz0eA_q7>y{kfi4|u3&xBup(8%T?14*TH{N0MYS|%m3K4I znM^GaikxUkC23-20I!iA%=&*juq&4I6uDstX`#`kK2RBxtPm3Mj**q&Xew|hZNx6~ zaYMw1Ml+^S=av4Ga>|o^C67MQ-ycGOG)fTdy1dz~lOZKZOr_(sPQ0XezN(lPJQBcr z;DKLH4LqQjplbOXAZm?710O{(w%u9{4KPGdj0B_c)GW(qo0|M?SXPpkQTe2T3^Db> z+N#ECVXk!I!-Xm3WQ#XM&Z+VLQv$2_ zE<~J|l;AN|Eb)W`XD#<+?z$tLtE_X3)a3oav@U6HW4Rk`Tn4Q?|6A}d2>qOfG+5_j zsse&6!QxXF{07)lcl29$xHNTNl;y6r-awwdN5X3ivw_LWm$@TC(pZ<>uA~#kR}@aQ z$oNjOO^&Ft^V*tTk|1rLrZ}|K*ujPvc;6*#x3&8DaxfdRxoZU(OqZo24^bVhC!j3B z#$OsCX%vY3Gf;~QIYj1)z>&Lh19l8M%;>Yv7o;<=!flR(r(^fap{!1&Zb;R z);g26a}VUNvye^YOe>sguShyWQp#vjc%;c|%6&r#(7@W30PzI`z2t5sK6+1jCFWu4 z8yqUs!}jaQNPj6y9Flp=8{x`EISs`fYa@-4eK$})C2vWpm!isfSfGmRLaER$VIMZ3 z^%o{8(kg=$O7G*>XitBISo~yCOIl|+9TpcNoh+Hs(G)lrv1_nUgAh>DOrvIZou1hP zRQswNVJ73)Ns~&5`hF7a(<7*9D(}q8^o(4(jE7J^f;v^snDZ!|)DCk2E$(|VY~{Xo zF-&!RdgNuP1&96kL)~l0YaQV`q(G?(UFn_f#~Aq7)V0D{IV7)nm4>3011t*6EK^Xq zc~Fx-co$>ECj9nFk3!c&Zp_$uL)!cRp7WB7;lRE~} zAfFDxDQSjul?{W}R|N}O$tdAOBeDX~=COLL?hZ*d=y%!IKgFA1D+7I}KazT@%~3wE zaba$amu28Lnp^aEH>7O94}T#TGMBD(B6cI5oH=f+$0`bUAEz!}dys96U!^KY(f7-IY{)S1wd)yP1d3_u z0z05bhU-ZfgmAm}=~Va*h@Pm$@~5}^&ZRBh52xk~3(uE0XVT@93S zy5i|!2>#_42a-niTtV|!uwEhiu4mb%_0A5d!+e6(N5k}DEinJH7|5IrLNtEH7fm#P z!kA&`c>WQobxEj^wj2|Ds-q_Xn+$aTMWEUTz05UWbZH`~bH?ei+@A_Nk}UB9=<~UU zxpSG+)zyx~aS~!DBylU}5P0MMUue-kIw_17Rr)oRr6u$qTEG0zk*EEuzcIR$g;-ll z9~yWDVfNL~PVSKTlE>5HJnG5kd>%Udw!6FQPC5N(o-8+q7iq`%RXKC%Qti@KY~uEj zN~(C%mm7`RNY<7|iC=rUng34T_1vM}W(aFrgDcAyuV$O!)ZEWI(!AtxBot=#&Y|H%Nvq6lk~4Q462E!n^6H$CwLPE5;VKK% z^l`VDr0eqFMl$PU_YcP03wDDah3?@f&ij72G{@N>%^l->&e*<~|7i!OEgz5GJ#sAZ zD=$a9Cnfpa?6~}VD;3)E@O|`xYuVa(D~U^AwO8Ia$K=DEk?IySkYtm98A0etoQMY( z5n!cEJKGJCVyIQSjd?VjD{o-Ay)IXjN zJZ}tXB^D4C*o}xI>iG*IL%ju{Qnv15DRFu`1rP*=i7s5Z$Q2DNL*z22=~5=QK$^!Xtod|@7=6*5gmydi(X~5 zL&pi@2&x}9ksjE6aB0S{2{kYUt3LRvQi$_HYgEU`Bj(tUj5Iy!^k$$JEm8yh@X+Yo z4)HN(SaYN<3zMm9%W1S8&?Q1Em7a&q+4quRkjiVSU{<@9%hp!Mq#o!XkvaP5N~W6_ zjG>hu2~9IsYfvvzg{nrz>tG@>>gK#b6at)GHZwsEYYyc#Nd<tQ5i=qs0QGYLDJ0n>bZfwuF|41i}wqD~O?^`Iz39dbF~Fi_$ft9M|-lK;C1d zV;~=6%9U9uq>-}7s<%Jo|3$_IVmR9%pe#3+l(ktCqmHMj@7iDM7{OW=a?muDQnnL= znVvcqX&%0GnObgonc{y7h`MyqiRT)42ZgrDYRN{=a<`EJVsaOr+hikL6g72DpYxsZGF>V#{MhoW&n5D2alc%MJCNbLc0Yz) zB`_1IW0{oGCD>Blp`17}&1xK6!)pqC^M%FtyUT`U@_ z{(+1td)%95lZkX69p}sZu#oRj1|J{yyz@D;5q0#)#x#*lYIcUTkUm(;R#N&sUi+Bx z@i2|GBuvL_zvnXay}W(VXAkLCGRVp3MK(34V7(S9^oFaA?1RA#My357W-Ea>lNf@0=Th+z6P5io{{`BL&2K9n}7apl2PV1BrTv+=XcqnHPpN$phvGG z-m6~PrN@+Hxr)ZFde2;I3Is0jsTEknKsj%!pyUmR@=7bTt9DvtF&^g z3VC48cST-Ca=&O3?G$VLMd>MD)ko~chqyw!xE$!v8nCcMVctU9$~tAWSlzUyKq&v5 zA_f)f#i}io+7Si`5U?y=KOsuoTF3;I7+e0za(|n-inF;w0Udv;MpWtA;rr~)d3yw^c_+5EfHfSkzh>fMDTnpvvkk+9YIF1!bUiflDL_p+U8bg0@Q3QXCHoZ06$U z9F!u7&$~}j*D*{i;#=!Du*iKg*+d0yquOa;o(XR-Gfd%LMmZc@^i)(|UXqve89`Xj zeGr^vQTyl^MXB3FvA*w9_O^?&MC}pMFr?{17CIG4i-j1N=@t638UW;doy} z-S|+T0%9czjQDiP;@fF4`^Jppfh}tHB+_RdzD>-(CMRa;>{N`hzJwNGb1TYY^dj5V zd$vyl8HMdj^p_t$@y_eKJ?}+c|C1y zr^9S5UmhhmmdP6Fm`_hWToG29`|W7*luTxh(Sz33pZ9l8t0ScH0egFdGg6g zN*gP@o(JzYQ-1%;jhWN4Fs+BpJiIO|w@c_fiW`9Jk=yCyOHLkMKK^LzJwh*f%zZ+V zO@2hByTV+MIyVl|ZMx7*9(zorcVX!<-*vs-Q-N+_rKEOGYUm=clt3R+!xPFZ@!F?o zg)QyZVF{^`Y7#JvLL8-WTZsFmh|8UA5<*@-&kF!RE51&Pk)Lh4Z}13{AESxB{KS&Z z?xn>ax!2CaCDN2S|0LRQW&~$T+ks)~*zTkx!^=3352bl>l=?b;^F%$NFzz%hCb(7h zj1guM)zpSsKam&*5X4EGMoA#gw#S>xtWN=%Y(}V4Dg*HT3D@hUF-q(*bQ`jKyDVpI z$5<7YoJ;g&ozZB`4>JEm-v@3(T5ny5*-5IfdHh2CSCgk)*9X2``y9te~@w5 zT)+L^dOVx?ZcOuE$?{WCUg1^U78-7EvYFFa=HNi6YeNIB)x5{~(QN2NZg*?B>m~H0 z!63sS&jotT>uaiah+`L~PSPmZOO7drpYXxeP;!EHS!ug=^B$VwLx~^cugTIf8O})j zY)JSap0q8`JUN<4{TUwqMmalko@UGAa5GJpW|KjZEx$SQaq^_};z^19D8om1KoXO* z5oa=G68vmBTRZ7pI7O@A>t@Nl&|tJjUek}+SvlTlJ$5d}cnmd@&;G77m;-UEGYGS+ z+sJOm)mwctZS`9#k6!4up5iG$tHmUFTzGg99!61s&$o4IiA?vldIq1Ytq<$;N`?Yu zZZm|BhHZXTBjYHeaUysIs^fdfwa{cH_S<(4kn+m8b#6s@QV*ima`02LvDy+uH z0kG1$As8v~ILFEH6(XK^q%%ih>CkAR1wsU!iT5GxGGL;QmJC7Ae(2kyW+KDQm)p!4 zzQ%y_yf*4uLf*D~$i$}55Js!37#*#NMrhZxMoAFYTnM~IpTGgxdCf*^r_p~x+O|zb zD<{&!GBJ1;&{SnGu;Egqc=B z%JC;!zQ!ZfVEWdmWRHKQ1@aFF1T&s0lXTQRT6c%Ptl%G#E0WA-7_8~r_l6XgXsHCQ zp^f)G@oDprbFSB3b-guzsh#!?jhw3;;#LiqUBD_m1lH&Vy_y$48)a9rC!9~l?vfAW za5J6QLR0dwJQTv|aeT8o34IrnOPLQ3&*Ds8&w4|891s1&X+P`o1|# z+nE1h3GPD@(1)RPOTMcTE>!y_MD< zqqahSo(OiJm79J`g4e#%W8ovwY3sGUFiKs(N8b~{Nw4Kn51B-2>B!b{AmO2<9@Ksq zIft%}RhKxA0~|eyHL~Xzt!;-W1+J?FR)uIF($%n8kZ_U4I0I)dsg$LjUa*VpU1%}E zI3g3DaHKn&Pr#WzxdYZA!LS$RznG0;-eo-;PN1;{K}(Wt)-SfJ%5f)dza~tGNv*+e zC0x}VVtf!&=r7%)AZC)7WT8PfI z848^`$BWteWUda%V&mv!vPPXG4sli1Y-I4~$;Pk~Sqz5isSl5R!{p8^G#aESf#s*FRvpX9bqu%k2moDNL4e^aT8bw(K`)BUJn4G&)_Bu*yhj&MdNo$9VU&*zxjuvt&tH%va@h-U5m{i}l2i~p#RUe8hFSo){c%A{{+LS& zM6ZnFXjcuq20>{Clx{fT9teBz1v*$@EK0ke6H6(!AR?+6M1~7$WJ=Z1U8u-j+JkvI zB>$r2S(KjWfCdh8LS|LeS_CS|)`J$+B*zsADvf;@pl{cdvK2WXpw-}=2FbnIS7*sK zB>EB+sDLfKqGc2Mq@|eFG6|ZZhYLWO^V@7(qedXXp!1~og+Vlx<1S26O!S&&t3nnh ze$(XZ{X&*9NBbDFsGhOSlyh7UGIkJWB?fIxov0NaXyw15vEW%xBw=RJQUhytQF20z z>D^DH-_`^zRj=egR};k|0vYf{nl+phHHljBsmNH%&}GIzpDF?>`@JCRRw;#^xMS&>|WXW4W^_qi80* z^C1psy}e;Yz!cjtj4wwE5qYdxlU6y(iboM&WGTY9Uxm^D%BHO!c>|e?X5v4OTr}7Z z0m4>6R5USEk2VS{NGNHVs<2zjw6uYTs&hUQl0wv=m}fLMi?kKrQZm3)Dz+yit%OOD z#}h52hf<2b;|wR<1Eed2Jyb8j@@nAFtOR=zAyhHDGNvv-854<~K!I&N8{S}esO!Y7 zqstj3&_fCZm7=R3({Ct2Gi~}}at+#7bh=Hp0%ZNC&%oER8O9P(VD3_RDml*U;w4e9qO=u0@r8(K^&bzGFeV@({l#$h=4)UY@;h*_l zjd_agb1l@HB^sw>i>G;?X|+j|@)R6(wH(2V#JGim3n+RJsV*4J2UZL>G)dkljMXhl zuf~bdEM8zmnDwlHA`%#0!H0m}(I~#S82;`cFxeEn-RuQj`LE(7^c^RqJ4b zkpVdod6U~&)l-KdP@2$MET{{!eZW&TeE@E}p=j-jgD8;bAoOVjwFcs_`J6lDF+OAO8XaO!e7HBVhsS_ESWZi*kXBRsk>_Y2aD0D>j-2y#WQF zApe8LZI=UPIt%Oyh)T#<4%Ti#l5i#{#-XQP=sm8umL-;vQf?KCvBFsS0(g)BtsW#6 z`Apn7S&bZy-cjW%Az39`|kP?5v2!B#C>N3J+>Z*!8NW8xnDj z)_zalYaCzO5ssVN*8N|WOKJxx*CIXDnnH}QLQ3r>Ot+Ci@00+l=@uz6yDd| z(*)-}mHyEtEGisk!YMW3$Qs;4LQyJEMUBM>MK(($pynkjxizZ)3s89qmEr~UfQF?J zYg0$vRcoy`o}jokW<<~hjYTdF^#q_ zWvykM7Uv6L8sZu0x4&)fk^bqQ;3DeCVfoH?$ny3zf+)AV4?j`w{2TYq)t~UW(5ht6%%Rv~F1xRQE)XENbvb61V$jyR+!bd&{ePwM(9dld(5^2R4D`pm0%k^00N z@{!AUb2EQ!_-#`_Udggs4@)?hfhk$K)7t0pXrI$DOC8`(ZD+u=s&Ly!aezitI=EIU zor~dV={gC#GET?%*0)N&Y&QF?j@$X^>aXJ{%~ET)dHU(npUXQ}Z#hB&PNjal`s@+; z`qzK_>b0=hz27=;~kF z{v=Np{z1!q@ry{l{#N5l^|x^##d9bEeDY~tbkWMl42OgATeQ1DwIZ1VDZ0Nbkt(aD z!N~Tv=(nrsyZp5wHVPZyvXsw!#$1inKlL})Z^1(uPRG>C7y*U-t0*-+PD|u}-1+>M z++MGXP?c!_O*OR=GPg%U%OTc<6@19_p5*Vjk0+emPek=cCyBoEHwr%LS9K|?DkE(^r(^H@ z6v@9>uYEoH`kV$(M`_viH-CPK(Z^K$!wJsN-a>-=e*bx#R2H_nWhYY~j*MXlU;lbx zx-Z|LpA8*VxVBe6)8%HtiMQVB{1!eEaS%G2u_CDFM*iEJfGfFo-swN*e%zspzCEiZ zknL|;xuqej<|cX92K%CnG@X!IWwy+FMslrC-YjXTPaLCMUHNyD$Xh)eat~kvpm#v|R8a3LZISjQmqM zQ|bxRE}&n&ryl8U$^pUxI-8PI&2IcBsvH$0K|Pe24>EO0_PyP`meDM@jfAJ~`t(zl zgM6{D4NajU4D|7j@MMu@!qkwGNb)qBmJA%^X(EMJIf{H5DtiI3LaYh&PS(^7g|{?w zqo(?OI(_=nmoz}#?|r)W=@(SLm%sO$D=LW&y@D=7y#tPP0hJNC5e6H|S)Pf?kSBl8 zvfXk;ZD8Wpkz8zrt>!PQWHU+W!)*|>7G=HnR)w3`LS7QSDxbr9gnT-5{Uk|v(eiD) zrHR*UyxUd!Yx{d&d05W)Hl+9ex0X@{QIw_)Q{FmB*RM2-#L(f$n}Pqh7G-(mD|lop zuy3nxHd2$@Vj{d`qgn9lR?2g~Dl1KB_=(em0v1v(Echt*Orm`2a=I$x!lI1R3vX^0 z%6inUe4|?{>T%!y)-AoSJyK8pmuOPNAx~5nzN`M9OI_aIA3!h&m3}&SOPXqB=&&Sk z`Asj7@#ZG~r_7AJG+O9ff8Rn=OFF;-ZQfMtzCA@rwGb^u#grx&`Li~XtAh&r4qdEh zeP(-Kw4i@jN^9)xe@O8NVB7^}I+gc++Op_FtC~>4=|Qy8#A*9h)T-BENlOi{k&>vC zX}k2+XUEiqew#c_w0g)ryryPY?KM6OE@{ZET0a?!B0z2axQBh(}H z6|ZrQQT>_L12Aoc$}XoK1vCA=&}QW@?C&YJX|K|v{)TpvUpQHNAkzC5GnL8)us_GK z8qn`b+N4N&@6d9PJVu`7<)pIA%b`+<3Gez^>OF84w1nbISm~CjEGY|ENIAM7QHH7P zuyrN*sKinp4O*5)jzX(!m#?i0G5X0Qg-e%x7plobTD){5F9%YEEkLt8D;sn7TtQgi zWf`GL(d(*7<`s$Taj*Sq^QmehqDC%roZFk@py5j>6icgt0BS4klV$s!uQ1=Ju(YDN zTj4dnq^Bmgyit(_ls1UGBe$Rxh~FD$)1c+*P%U%pO)biBELni@aV^SK_9E}}zpgOp z3J(sHFX8aJz$6eg+LZSXZ&t>xWaTVim(N*0NS~ycObiM{!UFh_$IAdpvfP z%98{Z^{WfMn`HB-&^KX*CS|WjqC?pQ_ytyMl8~W=M&xM@&%Y94QIcg2R@ppBLfV%& z7?8^bH*SGq-H~Nhmtc<)b&<p7{~ z^F|nI)I?SCta%<8`60jmN!oHG2qZ@S(Fem)Sc|;CjH;SrA}vA%2vHl5d6fi3@D`_0 z&1Vq3YUGWu1vO}|fQ9ApZwFSSy-Cn=w52mrbIKxOY?4Oo zBtyUDHn-C^cx60rer2k9dhdvwXmv(;qXxjp494P+6xbk#rFqY?R$XCXPOG?5MtgK2 z8uxbz%V9p2m0O=xm0&NHqPPOB{O0S;(Fwe-r6)I*lH-F{dVv?zPV}Z9+FaH#-|N=9 z(_WVSQr=^rvQSS3>x~eK$NAJ_x;r%$Z~H71)G|k=MJUwQTTbn}+w>T|Cm0Jw^s(MmWtXuxV$LTijC=*$&q*SDer}Pd^KOmF&tCn0BBy&X|knpLsJu?Xg16XtpXYPs86mBD(fUUji# z-nPMfnM(;|(Q^^q^mZUk#SLT>SRYZEhpo4>1h0gCdS7?Y+B!XDUb`Evn!7KPhiW1Z ztCWC_od7bYMV#~)8uK0-z?%AVT6vP^m6{u z6_T-xr1OEq!0;}BGRzNvTcr$M_@lp^@zf9BK`YD^qpQLgTp22xwoM~RaowSIBLd`e zkN3SGx@Al$pnzg;1wN+&;w78w2fxwM$GkY7PI<)4{-nj%0(o#Ls$E;B|D?-V?m32- z`wsaGyo8Mo8P7_uXwi~>KrexBLIB*d(S~vAWDuUB7vxu{er@ay)!Zn(w9>poZm(Ub z$ySrc=o2};;u3ci`>iF>->!T8h|zjjE+8!yJA+^r?`GMhH0D#xl9MSW5${ATf%)9a z0`peG``Wx6y0=PnokO&~uc<=1tO@Ri`gH1Xe?F&#&HzFPZKd-qMI2mo{mE#!9)?55 z*FBlsCCTls!_KsGR+i-ujqcXZ((T)c&s&Lh|Ca~-W#Q)*8!@G9eG1M|p zb?`V|_0h6R=(go$H$>-jS<>$PP4^-l8_Aq~rmOcS{#=$M-mxO}qDQZl7((j#NrJTd zkkDz|ypR*P&`;DRX|*Oovw1rqEyaLt%#d^4^uhTwy(o10i43>$_Jhq+r{mG5E=^yQ zOMKTM!$2Fn8bUH3@aCI~XiWCPFNw8gZBAL2p*eNkRe6g_mU(f1Fv1?Sb3Sf)%0o@P z!(!l(V-MJ1JEDZBQ$pZ1D12pUwbyBcBOc`PoB`fhT4k&gYqrz1lc}WVF5mOwQd=(H zx7|-Jrc_sk@zQCApg7#F`KTi|k<;ut?v{;*q#IY0K|bzyo~AOeu)|z$0_N~gCki!V zanMUyvDd7h>aC7mI9*%2l#knw#-+paa~rENnxAne=AF%@c=gokoyp1Ni0hzbnQ(4e z`%_%Hf5d8tsDlPt#R}5ZIdy&Wh{PCZcv?g}rg+ff^>CxJHp>UEtZ${A4gdRWkMfVV zv)g5ReL2YX{b||=*W$T#7pGIkp9H2jos#3-`2!pA#PW)JG+kb4XK9}U9o$m(;_z&5 z^N!J@%dJ88#mmW8;h%M{cz#uceDrDxr}(@$Ib~zo%Gde!X=9qtInvAq;V@ldI`TeD zd!1${dVH|;ll5f7jW)KDD;ulbRe3A(?bT0=(^dEJ`Jc&)t(WJxjXJZnaqh0wMsIlW zr1i>tlV%USAa@Uz*L{0V>#yPmUgY$l%+*3Ot~u4Dgq19>NxF8gbkE60MlN;R;c;1R zt)}T}nn~JOOAnvuj2^f@?<9BRXX9ok=SZe;?*7_U?>pfxKag&xvsnmpQRLUY@NlG? z6>!-)dKuy34Gkw~65U^K=5mx>9=w+&E^&N+egBAt&Ihx~-4hdzk09EU{qz-rtRVN&)M)o~d4>sZW!VM-Kw(vy*N z^)@8vy@lI4EA#cTI?Nns;aI$P^C{+>GLsZlNpGny-mfV-4#^-M9IwIFYEHU7(Qm;n z@oDd%OS$>gkf;Qg!95N>d5ZTAeUfN49l{znx8H=TM5KKu+|4zfag>^ z;gJ9%HKN5?#H}uC-|#w7vr#&n#)!q*&>|Ep8FN=_V!@znyfwFwh5T9*DMN2FeMwKb zM*gwyHMy!NG;dmNHay?tJ#aN0;q3hIruX@SY%2ThHmh5bonB5KN;pYU)f0j_`AW}- zATqZ_tQc$am0Bi`Q0`^)p>gBy0w-x%RROc;;olWjTIvrvM9y-Dt8?Y`* z4Hd7M<->$}hb>v|o@JLG0>@kZIiJdB=^?lB2;E(tUgKfhBn@sjOxT7qkm%r5k9#V3 zwy$xEUD4e^8uV8>Z=nA+yp}PJeBF&#V$VnJ9Ni3F=}LN^BocLg4zEPDS@MXu&|uP! z!X_<|QDC9L-5wwG+2du7GtfMUtNCU9K;jZ_ou~qdB)OxVu5b&1>=Rpq$AjeFt&Z&1 z7AAVr{<4RayNYG!Xe)ieOj~v%bFr1IrxLe_FJMI;bvkt?ObO>|D~G((O>2-^lBU8Q zH`y3De^-iAtc@XG%Z}419b_=8U7@?tM`GGjVUfR8j8uFBp&e^K4J*$q{0 zhNdcbFEB~$lJ-}68i?XHXl2;@HG4SQ}JuhU8ZBogAdoyKoZUrH!hYHhSs63ur(o{i`=e6_KviIOE}kn39#GMlyW;1rv+Lq z2ojcPmRw^Z48@m27TpcB;v^zov~ej&UrXTLODQsSQRO*(H6-wl4TERXmkmhsfj_S0 zo=Y)>^1Kwx7b2A?<&art-qRVWG_ z5es8B_EuSm22PoP#BL45Pb7`ejLD}|me)2>Fhp$;cARu&5M!~c22fZIfuKPJMoO)l zd56Uj*CLJM89l3DxwDB^z3BKtBw>JmFOW@PPj4vZhN7F^$V?5Hh`ee;j(}APu^N?= z{3&}-HFRMKQ?5$$%9R9({O4Z*6sW7I!X6=7s`hlRho!KP6yWeW{}qhmr0ZGUReBe) zNH=JCBxb=YcNcV)3BF6li3=piQ5_L!veoym%h+$xKY4tUCjI(gDc$-5eMSI;lzj!T zEMX9}QQ7*C&r{C;8Nzl%IjzEYd@tmF$ip<-bYWc|26(wGL{jl_AXdjTjhbt$dF?pc z&15-GM+l07SM%I&lce>v9>mV2A7#L%firTxwjl*hVag1B6y%rN0?vzd2Hj|7Zj3V9 z929WZe6MF+SlRH$*_f@cJmO=)hoqS{NB@ZXj1|^i)Z3OPd)ZOBy{mmIQa6``8R8ET z6uklK(FW|oL%OXW9laRj_VqMPnbqP_8f5tbC;$4<-EEj6k$Sjo>oE+-9_*!8Xu?G2 zzr^QhvSyJ+4}UIOG2w2dE-$dz#P%T^yCT+*=QrXXX*HwthF|txP6<`B-z3h4RgYUZkNcTlWFq8r0xbnS+X@l z^;5}fgFf9sPWJMRyq5(OY^3Qro{H#%W1fa&>G90*@8MVVZpUvfx$gS$AnO+f2~Wmf z+zJo(d*Nh1d?HAztG~Ur#SrOV=mtmc3e$&?7-dOdwm&Wgo((@E$VFmX%0iFvbZlTC zJ`0Ra7n2h%_~3eygu1L@nox%k&m>Qg#|O>8uRf~W7c?MykimIHTo4(v(^eX@)r^~c zu2E9XJ}5Vh4)5YF`t6wxjP>b&t{_YWtz{}4QH7_NNiO$bJ4wmRSpjX1yr7ew(7_Gp z0cqSMqnDZE?YT6quXE=vCsWFL#kboLHtrSW!qTSrIz*qQVZwerkg&`jqll`{dR{kQ zF`iq(@d}B$AB(eB{N3y_w(>}l8;xDwRIexPbxfVzj)i6yPRe?68xMuYEoi;v{QS}W zIDLvI`V8hRFKe%ajcg;(xw1O)4-RyLoO0aau8r1CJQZ7~FgBxWD~juR@2B3K*l<(- z($KS9xqDja1^?3R?eq6;C;23vn*FEe>OQ7RPfq2tn|E)^-PtQ=*ETlRmVIM*%&$$7 zwd42=xlLR$9d0dU30{)gPp@ObG=0NpI_mXPI*GT+r{{@>A>GIG}~b zgKnFimH9u&{f5i=tUDcNvEP3+@jOy%rVle;c0<@sRv6{mxoyF-6Oz#4GRlSx?W&Iq zd(X6Z)Y6pEIzITlG};51o#2E$$Zh`K&)lBN`2;6flXXr~kKakJT#geNrRgKG^2C}v z#ln;ZnMCR7)K3?-rZ0PKVi8G;3#G9&(Dm?11~joCnu{(cGYPDZutTM_>JXhLUr*!w zgSD4tb7J20H7#QXNfMrp!s%OD^rn+z?L%~P?^zF<<01Jx`^bCy=!aS5b)M-22{5;~ zshi=thrG2_1k@ah~* zM>M8SN6F!CTP{%n9Ld(|L$`XlnT}q%+D?T&l{(*UwbJDNmUA58PeO zBo{;7&%rOUibYIx$w%tDmBvdf?XKrrG@MJ?oN17#YST=c77=ud=;q{LA=}U(= z_(?5yb~pG^5K#?|pC~b#2~EZU@(MZO<@h^=lCWIoE1A-%o3;8q2{$pi6;A?!BH+ zYqUml(fusfax^M|NGh5xK?4i*_z<9IbYs1vLno8$c;0DxruIf`%;vny6C!uE!v?8v zb2^q!&@ys9!n6X>Dv9U}rCXUHD6=Eah>{o*b%JF(qDDe42GWL$dA{_7%EQ^$ zM&!Y;<{B{%@cqYWZpfu^*J-?7-NvzKOcadV-bZG_iF(_S|dkO+KNYn2XZ$Ws*J*MnOudMNYY8Raf5qbmTcGLFz28AXu`13 z$vKoucsFF@uK5?whqVc5>dWriS=2BpEf&v zwBbmKa^7!jB)5{IajbcGa_f2C2>AHgQsXpRy9PaD?IcYlxdbl$lK8ox`m2 z5+3|wGK<@oc_Ym~l#d>KVk2g6K+Wee>do^9bG+@5sXcaU+tOw+Pe%8S(nBoj*=)PR z?;m>MX(d}j-bQHT$8mg0^*W8{vZF~hyxPDc9foPF)A_-v@i4C)MI;W}Op!Z}%Te05 zwSgIM@s>mGH1g&HG&$$IG;Sd^P# zVZh!9kQ9QIr5Ni>1zuzj%N$XOLC3lQn1SvFE2yxNB|?uzQ%w1)vQ&#`L`~QSXz3+| z=yg>E2CQ)!Dg^#k`NL#tumw!$3YBUF*CNTQ7>1e=qIlv8o;lOAy9yQ)VeIv^Sm=@% zZMdjx$?|u8VYX8peEFxdGJ6N_F@@3;^86$dm>zr^@FZKWo@UiWM1e||5cGx;;9aqb z#71im#639nQ8{T4s3Z2MM8T$N^@!*gHL8Rmo8O?_mpJli&!h!6Q=Q%^xM0+@Xum>E z*)zN-m`c``kw%TF$_=t;RGprY2m#>Y?LT;tPc!nouma^<^%?^U{PQK7y7MR%(bNJ^ z%6mg~#o7l!lDLl~Ap|3pbvIn=9Tl5vppbi2qll{x`X6u>O2ItVNYsE0MA5lPPg13n z{8bIB3R}{iWU}f5nX-b5R7GqJ<%&qJaf4ujlQnDdHDZ7&TIpp3fKse5#*Mx$b_`!hE#y;qz zq0QzoUC<3e8e)h_QPs_MidLq{Qr52$LfN?G&Pq*B|8vPJ>|rpBwL?<}l4lrm#L(<&26jvl#>x;G)HPaBVUr7Z3|m1d=(gp`WUBV(i!nBMA9fbiFnY6q~66)0Vh3;(4$V zO5uH^5hIVO|B-~k4T-a@E_0(d04!?9b zIQ_UK>7^cGVLD5Yi1`3`fY&vkVLUrw%#zYebQ~Ig4D0EfSwG;mex7!_LCIbV48jV_ z!3_hcnYBaYRhpTO7W7l)0c}BaNN8GBfF8$R4B9OtpVP&Zf6}HMyfih3PR;AElSea~ zhG3SjxOvL7XGJ;S(+O8Q-Smr!;;vwYZdqcN#+%yxNa_@ zCRz7!2IU?x5Ya#O`L?hXxDg0~RiKI$*PxdbZx=-?K&!CO93qhgxTq+t0Z2Z* z3&p3AQ!bFb=|l_A`YO;Kq+55)>%FR7Elb%7jKZMu$ncn!t7%=cGc$nF|MeFF3tL;! z3LZ1Wq}FDXfWm-dqSh-yQmUb)>V&Q$jn&fL9Z-0+&$7HXGWXw=!PfbTdZS=8@Ks82 zMfIxED6$JNdoQQnQQx^H;J@s_WW}P@C072lpqh`bU2kN&QRI-UuuI#Ax%biLys`R? z;2hWI(j$3x1KOifq`X#9IF%Xk1^j=|s><@7*F_orJy|rtyhHudKf!6+^;^t85I%J9 zob%4r%a`TLJCew3w*ATa=RSvXH8T1w$-Om{uk~#p16p9{_|N~e)*TPoi88x0Z%GX_xYV$b{JGg6r(afeP`#F z>p%GC<~HijcifMDbnUB^Cpfdxul$Pp-9Om*vFuE60`=-M*S;m!j_mxT{`6;dj>(a0 z*h;-a5xjK_pHPVZ%x6A|^SSSUsna(3#2dJmy8IE-<>}8jbsKfC!8A2%ls=bsy`b$n zMcTy*e{DG7+Bu<(VhKM(4)@|~Vd|0XM^3$^ z-K<>GV4oVN-g*mHVN(11f4~0y{>ML#gSPrF*3~~%hKsW2NoagazWBx3Kg-^^`X4rM zT-Et#U9}p>4Ap)ek8JxixLFjfTK`u5s*h{5TG7n-f4lbX24_zH_k%gFvcOh&!`^?3 zoQf7b^!Y5xTYv1H|Mj0gg0?2EY&*KW+mUZx+l}_0ledo1CI9fPUD`hEmaj9a{^2qA zlWhBw^7+}vK34y6hq3ui9qhZ`WgLE^@b&hA4=@go-BQ2)*6$pt|J4^tDU4Cms?-z> zYF~G6UBlM@@?RRu!(YcOTavizvqR5;G4Rr~Gy!{u*{mMr1Gi*9$-enbxpIZ{$WT?j z8{rrJ3?)Bu*4YjU(_3yVn_Oa}T zlg>xo+p}Np%jzF~-~-tocNmd>)u$g^r`z64`+YP<-}AKV5|he&PN0q#2TM0?+R~i# zCX(Y#S#C=aQ-*9#T_oT^RuJ6|23UA7TG3PyXeM4!Wic>$DrJlNVm(!uXf}SK zhj&-9tX~h1 zqp-Dwzd9(_Pqa;=N(PTI^#B50)HoHjkbMBdLerwrqUom|%G5zy5!fzMw|w6-Y~icy zzcAmpcJ@cM(r?;bi>;yYSq>9bMh7yD31#t!uQbJQu`e~(YQ|?y;1+o)$Tr1;sP;D% z`81;FX6z$PP=n@Km^#q11?QZ0kC7xAE1OOuzu3sjF{G~0Jh;-+D(zj+E&N+0 zpSzIw*i6YaABm4iTRE2({?L|#-AgI);keQyHF^8n?-Sl~P|{Z}%Sw}L^7j06Mf-N? zS1Wn@EB}O4&9Q!AA&>j8SmeD>VacEU$KLqxt5MP9Lbs&JSNh&Ox5=`+k3%ml7d~`0 z4d#{Sv2`hHMEWiy59nzbW^tiaNMRbUYPriMJQ-GbNiq@-H&~E|XJ0ki?_J`~(eGg{ z(3^Ps!eg9SWBK<>?i8cEE92ieA?V4-8LQj!l*%e5k-wr9Hc2jRbiKXg?%TN2dr;6N&0?;Ov0^tQnee=qKtX7%JKhF_r9@m9oK>9sp@*q z_q89Q+m9`wr6G{&W{YSM0;WkS8D)lmt1p{Mi_vTzWhtu|6R4>$3YncvoCzFbF&|vr zY;jwHu=7YWf@I8xCt3;^VGswq^J()TEs~SaS!O2)_Cr3ziILd^fnj(waXbOMvbn!g z_x5{_H03z^VTU>Ib=^~^PMtb+>d&oP_ug~&?af4dyhWl5_mTQ28tsWCrBHW{ZmQo=sQ)f#W z2^Eb^(29?3{e;%`|tVL^5isTSDE2 z*8|z|jz}oWNX4hTOD2xCSxUZ`8jDm+IrSyYKRk?;&Uvl@ZPFJbcqf41L?vy6n^eD^tD;*Ci*=C((4&1u5id0%AGnP$Su3=delr@3Y zzl6P*N@;CYQp^TpA?0NjsW2YR(OmFBQQG%~m{JM5%hTb{y9qTIVeH$aWSd!2+GpVeYyExhYwBo+8% z3RF^5(z?BPaon1?r!ctO-&#sgmxqgGZl< z*0O@QM85xVPmaX6Q}d6=_K3D<C-xn-PDIstt-VT z>GB;J5{Uw8FKL%jaPeiQymMiwN090GO=WSuvnfHj^nz4gc{-22m2DK#8bV2C)Y|NV zS2XxxJLIk%3eq|}2I+(=%M%jLJbE$KUO_1y$p+Hd$x|BV(~iKM{XN z5n96i0NtcSZbKaJs`GbhS|nay<`_{o9?vB5{qte4sErkBdCX$esjT;|(uQRH!K_p8 z;b6qbnT_DNpFP}aQf>$g>WOy??ZrHL_B4fzw-n{E=33qvZpbLCoSyouGl1nFBq>IxdbW-p}E4l1@D(fzAlWxwlsgCnT^f+K>Y-^V!`(1ox z^cj7gb{C93`*;tC9q}O+I$I?`*jarhXEhG{Y=C(4<(q9vP+w@`1#`%C#{|zu;HBt$ zhg7$q!NVsEN6Rubcj1A_c?wz_DY+#fI4zs15x+ z_X{~sQU03r=Rsdz>LiWku+wIopJEKbdoR~Rl&}aQ4}IRts=;(K-a7thT)p)E}0~q>C4<#1MjuF%MpomcR*)NAPw01B#534c8t%XglZkS(&f;$HTt7)9z$*^L_{a(K57C@#SV6GxIqa;3KEF{)W8aNE~#U z(<#RuCZ0A24@tAvY`W=G3RK&|AIxmjaQSt)A>+#n@x?wq-u-59-aQ=OSje>?oFt<$ zyl?yj)?Zzm_K_1Px9 z;_Q~`vI8*jr!UtQ?#&oxor_q^ojqWm3Kw$Mw2PTxt;NsLN2A;cg+^0A@d;RUx)QrH z%yB&!P=r7s=xBAZSOmu9YR-cfQ~GZE@MF=lDajLaLzvX_N`J8~llAE}soh$jSa$R} z3mn{_1y*x9Zal#PK3VW9bJY4gZen^(hh4lePilfNGs^nLGu*B0me0~Yag-f^%+&VV zJjk(QwPQmk4=;|bOH_7Wj(4p}Ej@V~SGU5glWt4(rotNw>CN(+i_c$trtL9)5zhOX zS>#VF#U?y>tGV4))ApOsY`BeMr=FC9>kG#NF5b`gZ@fO|MO~pydRgeY zZkyL-y2B$(c`rDcYx8mA!>Ojk=5h5-GsUlKkYRXIzijd3O}WfMOItr;q=6jkajTZt zG3octotsLpIp`fb*6dwhZ}z5gYfARR%~1M74NUJo`kCCcU*u)A!*%a3_`-Bw!c$kS zL))Ku=(WBZ7rnlh{`s5H@yKP<|JcT2qxH;<*}!g`xHetwxqSosl*u+GF25G&^sjo> zP#4cQ=ei@)eP?~}aGy7HyS-w~tv_j2A3r;K#b#UPlxe-retQ3U6E)7rMwlP5SF_^D zcCa@YIRH8=^tc4#cfr44gnTqa+M!BiWSiLbN)YNl^fv>h$=qO-h z)LftbujA0lQT#*(>O@5HMU9cdNL5H7qlAB9wFiB{V$Q{WfN)fXYhe-Nv13P_dMR3y z_l1jmrdr1hfZDNRMkPH1CxB|>5Cd4`m%@do)6>4Zz@y{PZ6$JyHGL&ZAsp1uOR8W9 zsNZ%36QxF>-Z6N^D{xyeCc#dMh2$FXX2Ou1L>%Qfn?)&(1lFnZnr4?(ZyctXG&3yY z#ZrX`K`Y&uFF=-{#QOxYJ$g8r7a$1KG{{X%((dFN7yX2pd;jBeFWo0__!3O;t%n`U zA(Kxd%zo~9LS*71ErfVFhP1?z<^WZO;zub7Mo-9Nz0HsY{d~_i<1S^&{~sGgq`n{1~Dvw zcs^Sz+V(81%IC8K(V(40mv;6kd4J-y*YHLpy)tK^XM0hvKABWmNrs2B!epI=%}1HM zf$O(%%x|E5KI4g62{I9l#qM;`2KoGx!??pn?rU=vzbPZ(e+i7jjgO(YO;?ijAI@T6_*{4IT^fTiYDm1&EWeW=G)%q!Z3pTwO z-ao3T#KeqrpFiN5v0>!`XTg_PGuC9N>13RGx-j-1ab{}_5)m&14A*{nDNM3LA68NK zH?4KHLl78=_h~&%5`$rB3-7yvYgvGsMIvL|R$B4dI#&*EJ%5Hb_1D`$#!eHL;1l9& zLaQ*5bMGlIH547l)NJIrC@DOx+{Zk2-Rr8?`?&83nkQ%MVas?l$5_{O=Q*sS`TY(@ zITgx$oj%ZvfjLLQ``Li^5c3i5fl|HIr*uTUBvZpOWgap7>kVDs)AhA$df!?^Tqi!= z#w}AZmBz$!BiQ2VZ5SlZ^HyWE=CZ*{F}C%aV)~B!#?xz$Nwy`9#z@v-H(?4g&_Ld( zHJbxjAFw9Ho8KF2*1#X0(jC>(O1rmnM;u#5jx2pT{BTnb`K8Yxp_+CRm;B zEg1%p0_Y`iyo%&#^mQaAUfv2(VR@FVzX=DMYC0I%;227+<4#jdW8(ki6k|*$ocAWO zI3rUrhOdh+CXG(s@p?NQNt3vs7q82VfvdWE{_ccS!A_!4qylB#8*)U@>F$x3gm}GW z9krOK|B0r&^mjn%+J>pRgb6U(URY?PrUAW|%?(E+q?}4K8dN$es=%6su?Z|RC|ME~ zHH;}FPpN{AqXoaRh!mQj@f~219Fn*l3Tj9G!w%tl5w9fP;Uo;@&vUA%G>uRaB<;Zv z$UhYcDWV}4Q5yb(fYcmJIap+z6!uhof&Rg0&(P)xseZ<2kA{$9ik4)yFlku^v6AK( zj%B)@YmC}}7AHUNG{RE~QzAbVJZNe&4!B~|{=s#i^m;UCPvhq}y)Bea*bGUq?0zH7 z&k#}-(?6;Dx?Mhw%*onKx5^B|^598cw-FA_GNg7xX{V&1At_u{p|Z;2bf`l0@(fn3 zFPjP>l*MqSr4t;p>wnNt=R|YdQGzn46>-m`}yU(u&0QY{i8! z(cr`xDKw>Q(4ed;pq}WcRB>uw*{f?@1#blt3VXEAS zB{qwK$e+&FT0v|2YaCz;YJJY0n%Tubx|+5dw<2?{t_&j-43l~Qm?%fkqk^Hk>DjQS zBauMQfxEz&Yzb2km`f;4i~^{nBgl&*A?a0dc&FN46Et9*;Lj&{R@t}< zlg@`sU3${9NUrO=CN4nP<_9Ik%{0s!9VvnghIY#axgQ|}ttH0c6R`o~spGcHj3ME_ zZKe12=`#&Eb0X$L?mlIBWAibvH0+GIDn9Ybz~&pW;v`@>?L_A3RkPCL(J_aMGx)TF zW;55!3vBC7<7z|d+0|Yc`)-@{S+6y zP4-g5p@I8_`n%cFtB0h0#k$`J^_4+pt`75`6*p%jnT~VCDz86~+?DZzBzjuw3UcZB zo$*x?aM8ucZfEYGh3cAD+0w3a(a!|HM)X0?_*`XCFzkw+hEC=~=eq~f#iO07&Nf)B zfzd4h7+7f-i9e;!mrlqV$>e2q#Zxb~^F&_apx5V4Uh!zqoELxE%ZBT{dBXM9 z-n5V8?QYAx;CqAT<;)rG26?yXTyIEMGQG<^-*Vg5GxBC9Ce5LYY-2NbJ&cq!ygI~u zllGub(t|zQxN$?@k=JYU?I3m%*f2X7Hq2GpXJd<1Yv4D#Udp;i{&369gilf`+^62)Q z>B_&h5#_N*x3=5zSl)~hnw)U2R|8Ow1Ks!=spw!z>7rjRwhElLW5_Aw!8!V^SD7K3k zyG&Qznb_%-smP;Zb*x}KN@N_?r8f0_hqBN@m(>uS)ANSsD>_YY7pk?lxLgU7gDyl+eBIpYQ>O9Nf$ z`k@Rv#jx-zMd1rLhKs^ayWJxpbc(K4tuV*^bZD;yGh{t7y>Xm%k+;D*{iE>$=BL)% znC6RCzPLW+u0Ua>kWdIIGr58wT+7b7QTwLm|xHJpa}0Sy&` zwVS#aLuHy}c) zUg2*wn#SZTQ_hQ1A8#4FEco0AsbM~+EdB8OW>e%h@WV7Yx;t+zT1s=)Av!a*b}KA*do^C1SVP0;W8i9}Y__Y$BZh1=UfIMAS=I>b7RK7Zw6d5_Vq-9$&l^`{B{X;n14lB?Jv$&_ zU-rm^du;jJZNZZ`%;6}L zY`fLV=DyJ!_{~PvmPNyyZw>HahbubH};)|<@PZb%+w=a zkp{j8K`4vT_yH+!i#=T-DlzOKpfoMxqfazX73f2nJt~2|nT{n|WsESDe<-6PgH#1A zjVV$yg=HCmo}Lo#42Hv(+a2;y|FUz~2 z7NU@W*TWLHU@9j|8Wky8w#tjl^Mw2*!zv}wVPbI=XbVWpA2zilm-z_h*VpnwLR|#a zX7HgTaZ8lUC7;s{M638V+$Fy_UzVlZB9kQDcqVt-^kf99(vb-VB-KeFrc+pjmf4Af zM9^F%*d?-a-0j6nNt!F}q!S55^jCpR$CyIQndKoF)kDx<0?v*}IZ{-|)V~u~nHfq< z368j<11BbBbQ3kj-MY<0~Vh%pK6RTpr+k%;iM!!;2I<-#pzV+*VV;5Y-m9l6qheJCMXM!L{&6R=>w0gH9aDGku{fU zTR}P5#~TQ>!W_tyI_K(#PFfGym?v*gvI)eh}tTX6{~OhMd@WhxWfB+V`~H=5R^>h6#@b?x*F@p2qe!hlS057QY+$01`=@aU}%q6Oi~i~h_xm``JK znUop0qxOk_Qj`}dl^ExcZM!WEIsxk}7r46UY8hy11CQ;LIJ|mV;9JdP@H+6h^oaiV zAz1_mYa>bqGBIO&gi{yFP%-?vbFDWWl~Cga$KXN1y(*%aOeb1U1yZS)LI?z05-ILA zP?(m7-Y%sih*?y~Qc#M9ib!)9Pl;tb9m|2tw3VPbfGbwUlnsTiY*%p-*1xA*hzd#P zkkESvIx{j>N(kwo(mxVtk`P&&)MbZDxeY%(64oV;2`hu8Y*M&>-9w`}NYXUrL8ZEt#52=&jNwRzhI2O)(uU0CueaVPT1vM;NN|F|Jc(U`TAs z$zP8;(50Gt%X}KEdh+S+R1Dwzg#3 zf~EyUv*RPJbdR?5_9Z2&GAUN^rPPlMtfkg>`D@!{Mh>N-mA>UvIb%z-#A2=aum7Wc zd1V>=64<4eU(sNRO@BT`2@UH;4AR| zyiB;$)7m{8zLDb&NT!2QnNa1GZC!C;$xxvst9B`UXcQn=YO3WXS8b)@-|Mt(tQkt6 zy|l?vK)H*uElFGIvShsXF{0t!kaGTEWwpPz4epe-bYt`Ud-yrJeLH@x{_T}t`mge@ z|Fm+;Bt#VK?fR`}e)s|VrR|h(;DEjHw-pQikbeBfZE{%ll{r3n7PyVFfAhg^>PKRD zhx+~BU&q;5XX&}^n~PoMqrZ(pFFtQ?edB+A!2ZeWDWP9FF`~$$NAXaV0=aG9d+&h< z?5$fzkJgp;k-;*@Zr&v`C8^|8Rb0+}^M6a&KmNzKgWC6E{i`I|H{STzXR~j7^{uz+ z=ib0$)UoU5-pH;WJ9iGZQ7g~aZ!ON9!>JS^lGC;~&NZI5AA)B%lDf~~Ti=owUrfHT zzK@TjT~}y$huZgIYVPDWZ8u@pm(pD{a^R}%Ym4=t!OhqMM{yBVe=++Cp3&^>@BWh& z+ydg_OkGoDFTVJVZ^+NA|D%6I0*;qH{1BE~x1}Msza};N9azT7m&*Of(sm0^o~4$? zU;0A3^#Sh4)+z7oe_Wu(*A@>P&2D{g`*U26;F#<;_w4Yk|E6sI$$wwN72o=A+Rk71 zKSS$3_zBtGCU{Ri)3@B2xr&Feds}T+jil-LgAbOP+06AM~@@{{)Zb(sJB&r`w!KWRV2u^i(e1@BdSfBeS?{omh9qIOe1 z5=&m%8ehR*+mHMRZo9yKo7PzhJ#YX=UP(Xsj|n5;GoM*vsf>@QN45t)LGan<>)-fl z{vG=}@?UP-Kl?X-@fY^i@b-7>A71_D!hYsEvQq!{*KU8;%KXI_?d^E`Z!OLfiQfFr z@74eM58q-K9j$cE&N1A03@8oDKln=ho8M$Cy>X5*)JJ0WTljFp_1=S@sK5KEx89;* zlIJ$Y<{RfecpzDgv4^+B4<11Aw_dIt&AxrN+3&mfCy&y%Ivu+Ek33HY)W)RdiR4q}o08```m?uu3T`Y3~jB9pn@v zh_rzMtLC+qti74%7w2K3yCpHvH7M8lgaIPWfK%eY7OxF4Mbizv#LSXScQZ)Eyn6%q zswfxb2`ks7thz&;tLI=93usZMN(o6nP`yyFX;(Rw8`E_kiK){>3e9DT!U2c&vN;#N zN(3e2>3dx+Dj$amL%YZxTPY%vlo*l?U<9g`RPsfQlcaZ4wh%@x?> zODoE3-qJhA&@ei$SrDk%=4BS1-YH>mho3k+w>_Iyp6WL4+OH;0aOy_w7a!D>@$$xs zm`X}gkz1Te*A$7B*z%B?W0!E4uy7Y*-ADMV7s_D@kBohf^rHnCzcJooIcvK0QK zmsfuESIea^s{Lj0a&qoQ!VWf0ImlGnEs47$`1GDwSS$Tjxz*7BvgwlPp&vT^#H($^ zJ~mbVYB1Mc-=h0^Xd+)c-w*9aNsYhvaWBdza^-(0{acx@Z=GNA#kGoWF#TzysJt^* zexkyffBN$k_TY3!@|7iKes>Vd9ACc@D&K4(1D|M=w)EyESHv%p&I@b&B9#$4gI=lq z|80Mw#A^Rxdfk6HrT*^!DnAyh9CEP4$Z@dDv6z}CMC*$pq3k=dDueBmD%~%v@vNJs zZY@qdUgkI>C*qoihB+!t%^4maiIVKnF<3|w>39iTdAJY5rS17(gp{q?m@P5c8kDVN z-2}U+{n)BBJ|>$^ZdEip^CYCy;Gt=%L^@l_VQ*?`1xWT4$_)qQBV%PN#b5PG>vbe6 zZU1@rORTrK^riM!+Re+-vT>!=R=3hrcqOt*<+uY?-;j^R6U*N8Tl6)*!*CCzO!Z=X za$&=x1JuYXV=thUe}Zzx#H#vgYFTp$l~xN+a#>5omQd?2u|3D0)=DP=rhI)M4op7Z zU19^~t)k=xwFwL4DEavM+Y$@QR32%q_$FN+OTOu;S;@!CjCxw54BI=sljG73=1-KV z`f+bSb^Qp?4QbJIYW-jxx2Uil7303SqIoP0z zl=YCfw83Pjecx{{>(P2iIjN<6VkcGWT-JPOmRJNUZAE)jshDU7)SFKQC(67UD|4u+ zs?=w77gptGVVO##;uBI!UCMJ>sYlhrs+Vb$mb@D(t3tDsSHnR-S(>rhzTXeZRJ%#J zS_30tM?b_Tn#?pcX?m``#LoV*N>vTYnkzGFu3h-pE~?wH36LHX$>lEw!KJfxKw?@s zNKd8Vm_|q2$5n7%_h_dJ4o%5IE*+?5J$>=I%*0l*Y>Rm4OJK!Wp@r5ZbyLxH2fSzo zg&~CinRa4esD+l`15_nPm7E~30I{VAeWx>%cY+ur0~_K3=C-D87pSH*i7LswjTVY| z^45nla(m-n5t%Us1+U{>CAE*WWf#We8zBEMx7u!{7tRV=#zA*Q(# zG(Hj@8`Pv!aW9)ngc4=y!LYou>qeoTLz*C#uC>CGk=%=m!m!z4(nPNTpc#1x zk6@%3H154#E|e*ndKY|J@253nRiX#8GLYBE2tI1*Wfb>t^gd^}E7y)ZIstQWS&%al zh77~{@DxMfdvYWKy#bxvy%X=Gc2jiC8I`YN$Fa@+D%gPguxQAOl%6H>YhwxRzL&sg zYGTMd^L7~GQ;jL#1ee0o64AF-+d48$;JGf#4WuFV%e;!^G|}ZIY>8niP9Mo~StpU; z+Xc+H#p~Znu$(sETGoT!ui4JXR?vi$?zu*AI)=ntyKc;2=!+G7@5o=L|}yH90t zkgu8ZkLDMI=F&csuMQD(brK(y6`6(TBbJzNpsR9_WVf@SMijKe-gnSV8u4;&2s$Ap zCB0f*TeY-B_hEYo%fE)%mDVLS3$&8Z1&Au`jM%_|ZWo2o;{_OHj@b_ROj!hZRg!GR zp1#N~&JMS$htV1;*{VzyQhN0re8z*~O|hGo9ZL=GJk})-sb%Arst8Y3P!P`@i1ChM z^VKyu=<`2P*1KUE-r~cIMeE?8c#er%PCdAyUx1^kn|{N>O}EYc8pCY~{R*MTw$_&d z5}yPf|Fk?;O+wUBaZkwIMpUgn0@Q3fuq(nOS}uo~GtTYTj|x-iTRQqxo4}Cl1dO#P zus|&wmd;UD;ZcY(^i&&V;S3gJ8qjWCn~dx_b1uq*ECN_fqw9{{$)jMaymmjMAhTMO zPY>CPh4lUPl8=U&Yvn1TM)SC%4s_wCxJoD}ECKUEE3bhvm#9;UKneM9eZSO-j9r$X z&sG$cJ(;0ur1ja*dbmOiPo%3<;f%E}`Ocu*=s8&{VxjAF%#-QO3Cq~X1;Nw($2>bk z=Z#ydtw$&G5o;Z8e%sn0a&!Oe&D=eP7EW%+Eb^E}a9is!SpQ`$_kISqhB;Y;7+%Qq zFPV!|na{_*h&Bwu*1Wy2ufEBd;HA$`0`oF&ag8Ettc7JLY2V;F{jDI!7Z_BEcws1Z zamF8ygAn2oS9JC90QZ=+xUuQ_{b@LMTHURz$Rhqq+-1+5_};E{rUN;$W>)24=0z4M zjWt_a6>Fzqazy--PjLk>ZE%4R7ve(Tq{R4Kct42RsNEYbTbo)R#?gz9QMw`SO4hSN z&}h>KCLQ5F-=Eph8?oUI_UX7};m2_aTlBo5F?3@r7GBKFr|kIk8c$4l zGjL;R*L>&wD!30P5b+Z4udaqd2@D7C=!`$1soA6%f;BcDfA|wXXb-1rH9(EGtnvBdY8O^(ucI|r(C4jr)$-nysl6(%PlSf0 z%(TEjqM50`zNz#ePlp#f8?7sy<7@d0wwB$;CR%UY_k;fBf&bA1^F`|{llMk&YeqUF zI^yZUQ08Gcd}h(h-Ij_@I+j7|w|nCE3yP7SSPMsZ<3i`%aH|ny5c4fvo9D&)JU5fW z`*|9Tw}Chd)I3{RjEb#Bl=+X1e+2J8aoy9Xjd3^Rt??Nqw%D4t_c!FMGmrU)Pq%V^ z(HuIk@w9)iRvbH$w}n1GY|Nt#nZy^|FzE13-#|3I<8Cn>AMl~EcI1+q`%^xDtJ`io zW?koLCj;?3Hb0za@|O3Vt@DjBPw(QOJv{cwczDA$`ith7M;>G6m-m@*s^;%7@FUt& zzNn;E;$W+{65G*u=J8%X)FieSc^Iz**#*N$EuQ$X{L=de&3Un-h1p-Y_4UU)PWtO1 zx9=WYeKQ-apKtZ2jV$i}s=RpSh|TI(R!Cn6W5rdv~T9hQ8ZL3iGfl6LtAdR*|+;lvQU zMc7X`eX*uPr3TV4)_U9`lGt1X!lS(VypA}Mg%UXrIUg(~(3`!=2n()Unwq)?^Z_8p zlnzq@bQIoOVF_$>9Lx++R=LR0Q=K)UJHs2?+_Q1oaI8kDwoDozk!*gv8By5iEPkJUKNU| zS+8FCVszGZC303o0Fn?cE;`{W>!WrEPMUTV;~9q3K95JRSEJ3w!LomTer$N!F3HYztdOzbRyqC7VEOm^G-1=qGf+1xSbU3 zGYUxS3F`ud{-V%uq?f}r?dT!atWe{A6V0?QrW0FZkveamE}r9VdG6`ANA=`#y%fS> zL1O7aF*$bYFBarozs0;MUYY2{OrilSlE9xV_+zM8Pw4wWaIlJMS{K#ysLFEz9HQly z@k`*Vqi|UPnGaRz0qeK9hR|bTq~WPZZ3|y?<>d=UJ^LCJO6Q726zX^98Pw}rZL!zsN*hyHxm?iU9Qk-e+*n*_(t9+|Qxs$wi@HXe z%%`+G!e(=3dl!(p9s-8a!hQf?Wf2lvM$QtFXT*d?Lj8pWfwlu;5sW5Fh}f`%oQthk zqBT9FK#_GFU;Uk^k^n9>q|c9J&Ww7oTxHpnt!zmtJt2zI;2r>7^X|=7HZa1~*a{5x zbVNughN$LCN|h{S`ZCn(M|xd~D#kQRCjwG-o3u)aQj`aTl-xu^NzzVse?zJa&7d0F zi(CjKb%_K`iB`i@i)20Hl?Ww-)GYfn@_5Nmwm~VtmoFE3DFL&noC@p`sg6O9YB`1< zT`baVvH{VEM4e<4ze{0&Y(p?<-V}|A*ONkSrzoL%#;C+HDPi{tc2-Z!B`G}*ce7D0 zu+x4i8lj~7h#W7gdN9Nx-9KO04PM&{>_o^&#?}VZ;ulmsmIfMp6a-BmsD*^F2#o!K z(sYt4Aymieuq5xLrmpYH;`Y#?>{MY7`A)Q7M&DRcm-1_iB}I=;1B69X-BMg^3hxed zy}M4JUQKs6bZBb?(Me7fsYawpeCs-X!;ZKrjks4@h$)XoGNa;H8uZJ$#eiTJksKvK zI*hd-suq+)x&L4wsHPr`QC=->qgI+4Ga6z@11pxbD(kCj7*FMugCNb}F@jgU+;F9d z91WImd{JVa9X5E`(O+`dO(-E)` z7P5OG6=XJJIh&yh@otXPw7;(UWr3)iX>LQQ}ZD1moMvFbX(AT~M<21WvWk za^qD;3Jp+!6ew~xL?w8tRy|+DmAH#gg3g0YN22D%Pg~Gkz)5t&p{k-*Ni$OwS}=$gY%4G^cFYRMf%d2uXtyFpj`UK0X8;3X^h zvmAq#8kpcH4q;QSxmck@WzltTWIY;!u4h9~;#M232q9pWki{W;p|WX)X9AhSgao}* z)a3;cUz&#w5|Q2vtcgbvp*#zhUdD^~7w$6TR+=MN$Qx(Fyg3;=dF^cBCZT0b7VGiB zeC7sc=$%{5O>O$q&D^XS3X!@Cr*W`if(*hqOj#XUu0;#OZllg+rdwdv;L6XB%)b$3Qjcu&1kxNZ6Ar`BdT@EPL`u(`RKo8W91 zpSWN{C~UC7UyOs(FBMWuOqhn$j|*vIE$X@lNU4BJUXh^AX~tG8*fvFvr-z0ickjp` z51ywKHiNk5eAXOqH=E(->@cEjWMl-33#FB|bMYyL=}Qs|JvU2xA{`F%(d98Cgbgg2 zW^cER4KLAZfejf9-ssM*=v{bwnPwQ#gPEWryI}?u9Pfa~N1*vGK}aiBD%uOZIcXt? z4UA_`8rKDpm1dDM0T{Q1cv{2w`b3ADLQvV@RNoS+6*gvkEx;Ef<^IGr-Em4ics7-l zz*7@r!iI8hx|yF0nStzlb}*Z+zOy1S2?6G<`5>H>)tOA(Bfo&3u(j9T7>`hYJbw1M zH?tGlyf++2VVu1X=JfDvGZa^Kg1e6(P~F0YZ3%<0&9e?+zJLcw}SKziKP;r9#fu|w=QCfxSCsUw>bBFA$o&@%vb6?OP5=V z404&flkef2hJLs5Yvf}29J1`~z^;gmw)-r*1xyy4Al-mGnX$U@Ab}oMc1Du#f}BK! z%P)9l^u3TdsH}kxH%@`Bk6EDGUU&9T8k59O(%*fk@Gp%%WNXc_Wr$CaY zTEtjr5;DlF8_x|^D(RFZ=0aH8cN#irpuzE8x9WdKIFmJP$>K`iLtUrm*^ZCmLyug=h}H=nmgdQu*)!}ok(CnpZY6IcjW zblK27H=-P84_qmR2Rg&;VmNf&e`mW^eCLMibkY5|>-qzjNAtXOhBqx<&C$(e<59*LT^$==dV|PQV#m;TJ_Gb{}nz z+M6|NAMf}BT{$6cR&<8G^KA5Z*1O17^b?+TXOM&; z{prvZFYQA%wzsj}aM}+?6kU!e#>PYH%+SA%X210j_(ph;_Q~?Da>b@hz3rzT(AuaCxJ|Ao+V^DND zy}Iv8u+Mh6p;Z)}&XdStSIc+ol&QZchB7_-R+ONC+Y@GP_>zsVmdbZzd=_@hG3O_H;mWv!9f z$VkA4AS*OoN$SaG&@z#`31HXwBxfUUy`VE#wsAExsp_O9j8+*~kkHPlw@KHOJ8%VBwRm0)~k_Ggn8 zR^X3MJLG!H2d}^I7n;vWj-k(G5g?6Cp1_O$VM2%i&i|nE-?fR2`02J zRE3a24j{oMLLx=bUC@LIw5)*E!6!mgIcBF8K{P#m0!Ghpo>fB0hh^ECN;DV%^4tNT zicwLThRKjVl1k!~s7av=5TW3cJz`|S(CF)G9}f~$Y{O5=`hs7YqiUI!tPe@enbs2C z_H{PW%CQ-AKSEiJtW;0C3^h@8wF>1gV5*7|l)i+NZoF)$Eq!H}lvr{n6l2jlFli*p z#Xuj{rmw682{gfwa2k=+ZOM$48T@U|p`KP^Y#VusG63TI>yHlR&^1*3&X@I&td~n+ z4LmwEwo}uI(Ztj}5`7tjvRXdHSu2%A=t&`zEToh)jq-gW4K>(>-Q-!Q2ZP%!bF-!qmYGcNB^+OmibPM4Y3|4` zL8y+^VK*%m?i1N7yRO#Nh1Za*n_Z3WF)a8M!w2qjt#6L96Q#45VhGE^qj zB+!TuvIGKVN@!jaWg+aaqJ8D&LnWdMwX}Ss*Jvl??=b-pfF7YP7UM zc|M#4R-8f2ujk8?IEYmy;OP*VCsYg>2>I8d^&D$Gd#`1ex!b79^xqPq__FxG)xOxI zvFbk1YL#tBeHEkI1wCralUNQau8fpRTx3N?5)fQERDse$8Wk9zY?Tlo@hdQ5k$Q^D zwpkd%$w?LQyu>iF^pkY=aOjHd^+FH5vh^P?NtYXpjb_hres$D=wl|xYGpu>HCD6>YG zO6+^M?-oEcw1hjMQV4A|bqT6Z2!lYJcH<|*?T5-lrJ-ajW16%Vw9K%VkZPs`Cb3ik zsk@3*rIW0~{tjRmMfCxna={nUu!YZ2hom34Dpx_|874)8hFtupNHo>PPw??rA?XkZ zqt%cMde9b3lh(+VIUztVF9Ps4n3$BYRA~3OJ>ujWHGZE#HVr!(nf&-R_J@FB0_X6Q zMEvgVu#;mK(bn>^O+K@yjZzyj50#)!Z&m1Go0bW%@+a((0ooF~Kq7zax+b2IW2ZMk z+-0XUy+mCC!scez2rnIo+Ag>C)CzRDJd(NE{9NDZS7J^k8H83Z8Tsh;DX4S_;gCxl33C9cv=$^;pBgpwu@OyTQCLxVJNXRFpRWS zxrj@}uf?SnyO;`vPfG)t)?x@#Gts<25>J9^uX+ksu8F3J;4vL{0!o9A$Ddf&tZk(n zDl|!63eap5JgzZlalAGm&BR!WN>1C7&?Od;IH|ncEz8~YZMReI9Z2*pR)j@5mSIV% zIunO}N!TGrFgA|whCLL2cUp?aB^A!EE^&^PQ#mz>8k>K5?49n%Dkl)h^~2s^TvZkK zZRFYoL# zf^lkOa^rGtue`hQJv#3Sy$icWY2&*yR`Ixp9`@ir5csAPKhUDBWxn)X1O9xGVmTqD}_#L{) z;`RfwSRh$&R+hXzB}amH`AFN1?v{4;)~&Q&>&)vNy6pHpqD!EM{qY|UKZ`#(B&!>= zyXt$d=-Kz)TloX|@ajKV!57`|Cke3REjpZRZ#Vu6zTW7a+sGS#pPs!eUs4yZVw^OI z{ua$4l}9#N$^L4NW=bnPUERL@{AcVR($5(WxBtwZ`_y;8lfC=y?ns0APw>fAfA4F1 zX}dj?5@5LK2jM4I_4M!9_0hiQk3~w(rV!ZtGUi*OJh0|8@2&pZ)Ly`$M1q*MeF}ZCb`A-7i&{Zd#2}47R=f{L$>| z+dtgE%^MC2zrOvYZQAk&D@{kxF3?}9&Y*qr&v@^p?2bDU`oU5WJ`Gb}F z-g^wAKiT}`Cz)QT)(3d6qaHv0<1+jkY^9Dw@3KpZ-sQ-RIcqQEdn11b&bdCwTsJFH zuCzK`=I6S3D{ir_i(CeCn<;Xk6xiFcDMz|@kQTv#-5O}JMZjJ_3UtF6h#Jf_sO}O_ zS{{>mmB=ICmX#;#*AP;?%E8q_g(ZcSTBU;0OjpSxLGvLm>Z&DW)2xcj)1sL>TcGo- zG0)7y&`H^1c@wizt33rxsJ2-XQWRLHCTxvOc$T&hGOd5)j|UG7<6hd2V#CFiAvfx^Gd$k;PkyZpQhPoAL_c9h-d7AAO*j6sthKvft5-hW ziEVP2@Sm2num9I#FbiXi&r3N3H4#p+ziAzgwbN}XdO+O^Q^vc|_-16v_ z(H%sb-=Qs=Hz~2C{=JXk2h8z@I$4x{`?~c(Wz$tMr`D2<^(A)pxg~aWht~V_r+Jo4 z?ef1c-|awYU2G{*wX`NFA8?|QENr2bWdz1X!mMD})Cy9AGxad>*rUYW44S`!{-Ts; zulurPR;foRud9}8YiVJz#N^*EOZ!+{)>1i2$!7;(UM2Uy%2w5f5lVU2lrNQbRe2J& z@Jq?u=dAMD9Vw*wwFAn#p;A)swEu$m5^DV=_IDfu>6K|u1(^w^LTcXB`vuf*Q*YCO z(N||+fNgEo$pOu_PRWB-CqpKViUz~9Of}skO0(#7d{qXAQeHTqpz}k5-K~eEF-0==cJO)wEk6vSvkDKIBhS>Xe*|$Q%h!xC2dJ( zL?)V+k^Qn#6$`1sQn@=im)a`_2C5|Yf?@RP^ypsWo(jq@);hs^QlpPUE3*bMDDMghD z;(PUB6h4iP(!mTo1+%sc+dRjrHzotche~25g8>VnjvsDkDs~ekZg98Dp->Dg%Q<^c zM6|Ix%vqytAmIhv7fa-HFFUZ*0+a2~cCpvvNB|3I{~2}X1{z{KkoQ4_fdrAqE9 z2hT?V-)LnAtZ_#&?aQP#b!JzDhoO>}nmuX;kN4$tHK36Syq2pSM4RazP+HN7y`1qy zdLHifh~Ux4$kR65)}`@XaKlJW{ZU352?^C#kfUOJL)7`Ilc7okDDsLF0%ROK@ zP-2TGuT3Pq2E-Pk%n5AJLx>vURY8K@ zhb^H}Djjn1sa|C^uF2Zb8KdQv?c7au-*U3aXUwboJm*wmJZ#TmD3{S9ovGXp9S|F~ zXH@3&+EZpL@6D|rU)E}lMEZG6{#*v$X0tI5S;}C(YT9j;5a)JH{<{`W?{0JP9DUX` zRD+il+HsW%@=ny&xV37SALf~i=e{gl6<@;A%)16pr`A?UU98R*eJ%vkk_ zV;KbL_UI;2st&WH?;Q1m(4wjD(%qT-thP#+irOtB(Nm^`eMAtT^V5T7E~MasOzq6;^4I9_TB*F?5f+{@&+|Th3K<4w?HQ)A zYutZbaFQHe*L6AW3g$z--W=6twOJ1?p)BW)$a@$=jbii}b&HHA065`WeURf$& zBo@5-B-Ox$IxACrddBVgb=Q98d`%){I7q5#JRb6c@p_2(lOyv+%{nnyfwy)-_L%18 ziQj<45J=e4+hv)1`t-bkH*Kz6*JjQ@ zcFinKebn!xg>iV=zcGjd9Ix@nzK=J&=N3|6$#?K2|Gts7@UUXc@&n=9+8}_JhlTURFpMSmD1Px~*m6F^&<*2-xJU+>hfHBb` z!5dddGgJSY&aX=O1`oY!V`e*z+USNX^1+SnXzTpTzWLbcPPlN2@JJ?4d)0()v!%I%~7#8x^ z;VWe2qUmQk27Md-sR=uyn_YjNhv*mAu08Ukk6XnNUT^NRyrO;{6D6Qb(=7cO)_OG{U zJzS|B6DsPbI(#HQHq@<~N&n_pqjn$*ZyG7OL1+u2u0RE&78m8z8n^f*S+!6Eb!TMH#{E0hz0E=&wkVmdck~t zg)x5Y=rJ^_^`*lcE$v%7>s2-ToP{gz%jdl~ao!&AuS=)ZlYZmK zr2f!`4ep6vXZ4GZzO+_%U0)8 z+0UDLx>|eI}J$c$Si+N9sU!SKk%V4nwzb6{3UPRd_1D4$szfL!b zw#enl%q~c(9tEVPoN5@DjJq)K7&YOG)MQx2Yl_$u5*$lysUx&xI3pnv;Q}J)z&%3c zt|NfRoiN!Ip$Vb-sUc&n=3;++ouaZ@^oXeuz(bgp4HRzshn2#V%Bqn;TaM=lZ86Dt zNhEOMMwIUK2<(0k#f}yGSqQxEDcJ#cn$vL0Mo&Zcc#2q07Zv1TR6K^$WHT$q$R6_& z@Bpu7>XV~}A-oh+sb3?w&w+j|F+00cv83*_-yARoxi)^ICe5ix?^sW25XvT8BqpXD zZ3i{kUN9KVt5jVqF)MpnWw{a4+?yWt#|;;+8HKQ4vX0L@?^B^b4+hN>na#!*I=SuZ z0#}@E@rvU@Vy7(<^nZbL*#2MU-ZxgR<2vv>Rb8)rU;FLo_S2)#q!pyPbt$*F0`f@8 z86_hi)vXq%$!IoBnVg}u3Ebjv6fwXe$xae~*j>1~*&>>PF#E`81lq`l7DELL*GLAK zdRXyI(6#r zt-AMI4eYrnMvV6zeN#hXNYg1?ne9uqeK8wr%QuwhTnp<@(~RjbFe8OAI0o%@_Ov5G$jp43ya0J2R|?)y zv?;HFxCrnMcMLJeh;TT=J1R>pV9^%G5g-w&-TanL7?duPH+VFN&y*93PNlZ7#Jh`U zxvk81mVPX^lgY#y$s~EVwb+&==A7Oa@+X1ckktx9=TmhmJFXTs+<<$2XToiHRL=3HFbgBSsiahTKY?fP697sdiQRlEioYx- z_wx_WmC_ua=w#Nm!|2q z{U*iS?t}Zs?WVn}{YRV(lk&T&9**HfKnrTi~ zWie}dA(;;@ z#MDws7M9kqE;`MGbd?3EUC5#uCr&3o0VXgqh zRJWuC19h2CX}=$Icgt2v)hLGtV&ezts!&A`6a6m5gOaR}Ro1H@*Fs{{pchHk9rM7g zGK!&AOIHDLNsG~!Ud4u#gD(??tO$}^RG$@j3TQER9rfg*uY${JB&H!NpK4&)rTxbZ z#F*qOn|zmczcEd16Kt)NoF(b9n?QW46}_#YD+%@A^K=s+(`8f)Gyq#vS{%@qXwlrh zr6ItEI%7P{b@NO2dr+@-XD}ad@F1>oj*4U23lgarWseJ0d<51X^KnQ$SK;I$G@3aJ zGp@G!b-3cTqCRaq6yss#;b6OX$N`tc5c;Od;1D&yAXr$WeZ!20K7_pm*z&MKoI|e( z|Npv>5-iD8)qz(!veNclg*3*)JnfMnSKN&tkoSUtu7{WEX-VKHKOCJgBtXYdX3Y}T z@=)1{c!ePYb$dNl1=w}VCA*lOG#7$0aA}=;I+s_S~8soj634&@>0#NuN8XxOJTwUHf7% z=R%lp9rTEo4k#>}yc$^54P}5#2wrGfN;}J&n<2rNuP{c-<}gq*v_X0jBoBDV5NvR3 zQA~J_Z&}EQG8#cG`VbjyACbZUM3(mk1K!1=Urd5~!C$4DtC|G_$hA z6xtbYuZu(wN+p3Mn~Sgkp?ZmmBMuN3(?3Aqw{kWCnjpCV(*(dyIpRRAkRTX9JA7`1 zC$(B^;ysaVx> zxRi4M`BJAoiTRl~>_YO+PB30x!qk&TqjfjtgtGgHUB?2Hwazt~-b73OqlNrs+$)Ou_dHjl-bbNom-ITRg^XuUN zC)VSGPaOAIUiXpW*}8OwCot~8(wT|VnoY)UE?S=tIuq#jI#_sZ@tt6}7hX_Xx+)O4 zk?}pBaj!>w(0+Ju|G2+!!wz$XVU3&>ow2Say1hw%%gudu(hquTC!RZDX-NHJZv}@A zFwyQ@D41^CCXN3EH*)NT^!%^Qch;u)TDEMB!%3ofya2cqZA&EQX!gx$fFd za0|vFd%{N~(!>4E(3k=_F)X)}>%pLtDR$U9-Mr-|Znj2O;_f@_i0@(_rbE-3YmZ0n zer|)1k077~+7PWU@S*P491SHDYzf%4X^b+E`g2C~!!(xjuh|LgcG-PWh#wUB6QMp@ zk7Lu_oE2s?>0Hk8(NNxs2OpnEd@Y2QJoiR?%}cg;Icr`&=S&<++=*dR+E=j!$QDA@ zZC&RngV`3txAm?yE%MeP-`OhI+|wC0`hz^7)M`=jrt+8^T z%@2*8qdw43hH^MW^%S^UFs(qLWQ@xirxTlJ23M@bY`w>)Je`pHp7B&T>hfV?IvfnB z*+Lsfk?CWwb3%%j2A`61oiGvZ;~aBDJ?4W0W7vAwP4fA8#}D7mUyaQh*uS%*K6jcl z*O9ktvA;eNS({o@cz~T?J!eJNdZF`Hcd^)X^)o$p^6{p#$J|BXKyTgTroAQR#33pKGsUpyma4uEUp!Ub0zs!WJ)jzG%Y?ZfP>o>%1bgaVNhv_sYvTvvW{dYr|ZQ zF}i?Jmr;|YqcSV#fs2YvllgYB02&egw<-C++Qmpg395m9$*|wxf%dJ8A#!hI1pO+eBho zGa`zA@(47!8^j`Q?s!cRvTe_R7b&l|hq9>`Ko7qmqmE=x_Q~qjsl(k)FAvvE?r7J~ zKfC?Bv^$~Gw?@LgdB=7_c=v^3(XrNdwx3y0FkNLG6!C!@73*xjZ!se#VQ4!&@%>&Tg2X9Grh0v#5{*|4z(vc%&m?LV zlZwTebcG2wWgtr|y(C4-U=fap??h>~gKs`Y)>3q`hVZP3UmoJX;Ls8qWMMD>Bi>49 z(DAl&C`8wXorRqb)Z8^G-i^;5>h{;B*9RTfy-_&p7e4%|mrih^pBAtIT0R9ba(3ZI zG#4w&YaW&xS%V6z*`P)m8d-j1h!Wjntb#WS>33Ye&B;I?6>E}E6ouy@XZL~)C-?xy zk*5x!`cANioV>#!m8EkP#gpiel2Arha6lIPDbCKqK({?j@Ijj@O0#`G)gm}M5aVe} zC;E1<2}0A+jM+ZKY+GI&va=UO=xAZ&sH*E-a!>x5_RJB>puw6M`Ok-nvF zSx4plHOJ9vL z6dlFRZ_xTev&-=*S@}ZpY4ixP#;P{=H(qaT`Kaa@V?L5wGv>FJp@Z1bRPW}_n2}-P z$tU4Xo-=W=qRq2b^7C6w**wt9&8Ri`f@zz4+cep!ixg_kGgM~y+MF5uOlBC7;I4bj zlUwwHC|)odou{6=#tpTxM>8kyKQ$*OJ(6JS|< zE#I7PNo?keW{zU86{gBUPnjNNWB5#W+*!{&8c-6)WGILWeySfJw3eq&KvF)O#-R_^ z6G|z>sjmg0w5UA=fSL3ZNAc1K0; z3AKG>ZSAe*cB^$urD(O#F9UHv^0*9Q=69lP9!BcC#zPe*ADJ9uY_0gT9>l+s^|D6O z6!W9aw`xpA+lS**OY_O$$n0yb<+V6#P~xq@nS9^YMz8f~);wdF9w#UUqo~cF`W>mK-t<-|{G4>js-~0{SGo%+bO%wh|P{!4O()H0YB!Oh5({W&l~m^I;!P0?OT1aitR|(H1=l z84zv^A^TOqnzE1uA%#?IsEsoAguSuGa<`FU2S*Z3oguYESR)d>*FY^WMgZW9#8S1A zbfaFq4Xom;%*1L&$?1gYY#U!O1@i+VzsArGX^W~gYrJs8Fk5!4>8l*3@5azG?)fm# z&kgAm2?ua~f~lucGvcFFr1ya?@1kbC6z|2CQf!Ap+If_jKma=i zfE6kzFF|xxPy%Hifs#Y#$rNvvEY^D4M^ty+5$briky$Mrx`K`TNCiOvAQI=*+jH7kVhW~i=>h$!R0&9cFZ8G4nBLp>sB^U&*zD`iBAtwgO$-IH>t-9qIr(U4mP5Mqq?ObXJ0#>cR& zD3TkQh#%*6)(JsVwC#?zUtK^D`;O8M;pc1sBNFDyLwIb2q%Np5S_V7B2pJQP)M@OF z>;e5o%q`e#xgl|;!$KO7f~JUkq8Jxbn$%dWMh28Wa6viF@GNxnP8Ca?+Fj)m1zn_E zxtZf$MWg7PsH@T)`{@;ydjsWVHkl7Mv2QJPmp|(1;pK=EiPfLdi08+3#!n@Ps!5ds zspfMs2Zzf%4~dCPSyO29iBKo!C@@5zY>Chi{UV16E|Mi#tZSqrAS};Q*^~4Uj(U#* zMvpQ~p=qaTkav|*&EIcE=|OSNpkYLs3K)iuqqwG(*E&%(i} zTr5Zpjh6llHe@qUS``d|L!!C0=u^Uop7TOmlO`c9T8@^3+bFQNn{aeSaB#)-wMbqw z=txIP?}?q2aXLhSNq=gj9;wJIWDNR@S)nH}uz_Lh#^4QBy4?X)sntp8gY#&vB?}u0 zaSS5d0D+l_EN1z1lQte=gj*N28Ht{+uDKX_G&gu5f_Ov=9i+~qPO)8rrF(~dxL^~C z@WNDqs8I^R$PZ;cG2_ozA0;~n1zc8oeot3`pBMPMQo3FJB~(f~?8X-rolEtQlR z083jh<|cR*g&87?3ldkU!H{Db0u@=hzFy#D(4j9u<%=^A1!3E_T8}8MiXt^o$|DhK zRH)(<)bRIqp^W9S>q=Pt5<*6!a2Wz!hC&(ESOq?E7X7ElKze{BIS zt)jq*+;P}Q;EF4mrCeui#W6b7;gIN}#FSUG(hFqH&+xefr)A;mBg8#T3O0{|a$iuS zMnPq<=LK5b>Z;jPVsQ&Z5z45b$dD+NVF-}Nlu>GigJhTaBOTvHMAA}#g(6RfAha=s%KxuoBp)>ttVDS z#{?q&@uW20wv#X>R@TU@HG<_fRy&C2(Cz2JeqEFh58VKrDPLoUWR*3IwW9|>t?8dG) zR(hVtTsffdFZ!irj%1!=m|_OqXT=o$N4f0$S$4|{Fzz4y>j?6p;SAQqO}zO=+t z)_?ggr(d?e_W2KS36C{C|1*2IPku71Ojsq8M4$LX_6L9P&2P#5A4?_r%fAI;3>U0N zVGHQ9rERMukeUW+3MT2k)p&RCmw%i6?JqJteO1jy-MNdYp-+GH{x|IXuYB=-7O@G} zSYjf|F5>;qV4Lmyo7hqkwcK|8O{*rc8sGTZzJ2z6eJSD1^T}Qt2C0%2sqd6Hl=lqw z?l9$b{=D3N2IzAy%crsb26Xo*$=-fZy|)vCJuj8A3N~)e6Lj||x$YHzk7Nb?y;#K6 zELXLVOlMJ|_irQ(?L{Q$D_@cCeCHk(kA9Q#DhbI*@r|z`>1VKM#&Y{R-_bihb$>^2 zt+b$a|CP!L7lyZ_h6SZ$xh+{JQ?-kl;2YonyVLt%Kllj@L&55sgO7h)%l+#syTijcJ#-HTUkbf!8Zrr+g?*L z+Vp_EwwpJZGw%NxtS}y??*9F=2=F~^J?$k+T*i0r(rmvu=zPX@{^}E-kUv}g;`YjR z6lSBoJ#YS{9enc#et?LLpF)#A#b-5tBjtf9u6qgC^C(UfFH9QP3%q;x^yv&OVp{Fy z>C^N+Rw62yn!wWPc<6sfmfHxPKAC-IlyFB++xJi1|BJ>wjC!StPIlcgwXfFrotqVI z)dCW~fBh>k*pq;o_{QM$(Z)?ox3{Pu6t=Y|12e4~R+uFu~8$V2wt&+QfF6Q8hO_yYa)zuy1uw-{|G`OTY* zKsRqP?i@Y(8yj-;yZ3*m@s%%^_PlbrgE=_Cf}m;x=nls48gIUt+H^9bc=srl5$Tq1 zo=-;G&c8_qeED;DFTRaOnLhV9JRQBXXYRwuA~xLaF5lKzx|Z5p#M7SkCf?gGl6JR4 z$@%lmquIUX=ae4|b|Y4bO-36ll_Zi?M8eSzA51|PRI88Jw!^@k_OA~Rf95lSp~QPw zX?qBBf$x{G4_P(ZCg1qRXQ`VehTMeOm)c$}(n|Qhe}B&|S%UVwJtJmk@7~?`v8?k~ z*g3l=AN!d6#s+QZo*ML12C2HOHiqo|_Y;4hPk(wZr;3iuAM7pPE2FZv+$))Wb!rVnP!)4&UD7kIAqP5;K+i47jwV$S zx}MVErB29u7xD5Wze=cb4K}O-I}RZPqqo~+lm-W);c+>w@mavx00OV6+XU=O+#;G_ zVwz+jEw2`8jwI9N@tJkKr%*`A6w2jz8b~#q4rzm~T1Om?jZRIm)AgQx`PG;I_vtsb z4tloYGFD${pHCM&rN&e+-R_>lK(QQaXnD~9!Ay0M@rGL3DT-vilSN`RDIz78*i2MO z3DUxr3`%a76A^qTnt)&6eujOEnD8rBDhv@~185siHKiajP(4`)QuiYH-&fCMBX>tSqg4-F+SFX71&$ zzks*0w3cvc@eE6AV=cC7PnV=gTW0<_+M;G{RKF92)1BE$RQT^Y)t}-+vWHeKA(MTz zjhBDvg_mD{S?#NlkwR)@ZJdgqN>r8{pWPY!Aaj*D8Do20EwZiFp#9Ql+k?Te=7`uh zlBG7v8}Av9R+b`ag#`%MrRED?JRnQyV$zGoPywqpq~+rHy7l|=g`IK={z>_z(DQR+ zy!*)O*Z%aCOYMTJ{^Htm|1?3hjf)q$G2!xy10G9*9Y?9pb#Jr}0)6DQ=dw#}#~S4I z#?LQ~E3W4L}9_j~_y#bxVHdcMM4d#OrMpNuO@VSnBU>3&1xpU8NeWUjG;VM-fhuJaR5 zl~TDs5uembsVcj3=Gd42w6gZK^*23R+UYW{t?YSWX~CD;2%kSLW$eb+&DT~q@zEeN z)}}^JmAX17dwFPKN=JrXA+rpAC0`lyL0{>T4!&+G4aw*CC@MQ==G^Cdr4DK??$yzr zojB-VB(=4;!fjpaRi*sMw6|E-Jj~nEJ$`$67%%NqqR%6-axpY$@VOguzuhK5bsf@Kh_rF!pasyoA zH}#CYk~k}OQsF}KOV4uxOWp*0^4TLI;8WzJCz(Q~F8(9G5Jkv7C;7>oop=C5tZZo6 z{ETcRoRu>WYAi2%94`h+Wwxelf~1Kc7>;ul$4phFFw#G;WfQ+}a)#;?=aYPjH9@_! zOQlKFrL=75$CA!=LqeC{8!4@EjP?maf`3V z79CgRp=W)_ps_rXu;M2?3Y56q0AD4Us`Tnyr%~l51BoTh=cYSNTx6>I?JB{J3-}66 z`6b8(1$JGD!Oc@1VTJou z%AK@kwys&RN!sDHRh_4|psQ@E^2$ys2wVhiD_H{Iu1oybW?69_h6*ptK+>)m zM7o2h>m-4dv+T+Y7)pM+OZlL#5*c18y|%&WW=lbQ;z?mi)>Tj1DEF zp9!zh@{&iDHaoe(btfyjO|!zm1gHFl;DQE{t0XN8vqD0lqnA4MBfrv15gKG>8`c$F zI+8QLy0j{w4X*Q5@~zNvxjez)PpYd#N2~43Lddjik(|91F9ckVdDzubW{bp%Szn3T zGD{;sn!HU4L{rUJiDT(S4#LE;fA1_SyF^^ACWsHbD6M3vRVDgBMnSXBj5wb%ATupn zOq5EbxpN}m#Ohjswb~#dvIT3&2OMN9by>1X{&X01=sk5d+xc3hw>&eOSvL1`2WxCO zq(9C#_iB1*B49oGu~LkpX4P%7h9LqrX1G z_-5D#*i3DSOP+gikvI|WC|KsQd>pqaoACAQFr$=*>a2RBc&+3vS(OgvUZFB$8(|8n z8{ugV*r^V4NnIj`qSEo5S0zA1B2-{KQ^MoXxBP}>)z6exH?c+$WAG^=D*2wPO~fD2 z2`w=Q$|Z!uj5bj=-9*c`>nd%Oo!+Zx%wJ03`33b#7gmHT#P_};WqhD3z$hE~ZPlrk zC?F5cpvlsqiv^Icl%w|-l*&U3@Ikj0Qg~`x1Gzee-7LIu9ViRyb=kSdvLKSpIKQ|m z9vv|H){O6Wn($kkbnqNzttd*G#~Rwx=Uh= zC9L?R?A3!vcE-G&BI8y;fp=X&(Wc{U03s(gbzv{IHx1ytnkkHBK~o+q&a0H1^rk^E za@c$;petoMLoEqfSAObvV758&b4zSNcUOfsi}0)Z3@rwcBx=aU2f=^@tzyIPTQ9Y_>Cc!^w^(Ci0+6NJ&wS z>Iz*%p4w>u4il86BG|Jx>Uje*W&2@TWKy8mDZ!K!iov!GGH6-}Zycj+n0^X7#c>Jk z$DXsY)mq;;w(#pOKt0zisuBsyazsPXf^KN?S`l6~4o)M=u{0s=jwyRGFT0K55mk_1F9q)WyMsGYPgB`u254`K5Y)TiK`|C2|)^d|@Zbz`UjnM5kB^K*8GTZA1 zpVK6y*{VzT%c-Lbk$1|wD=L~RBN>%a5eAjaCH8yzq!@47Wxy{_CE+mcsIXd4?D6yKA zr3cciHG5#XpG&e6^iTMT_HnAGGc<*?kA zP%JHJNiT(>q_f<9#zr1v>A>w7oAoRU^$oj0A;M8)2}`BQgW1BO4J|v9ck)|HnQDEt zhLP;Ga`zkBK)oiH9VRX>qJC_Q7>Q%)Zu4YR_QVz2Z|Bcjc`VFrcs?_4qNOAISp<*0 zTs2oNNni$*PK}-kLm$X^igtb5<@Km459{gv!Sg0D4`TJmekr^|o~t@@5d#bwu&D`~PY!VA@Vrf|~U&=RJ6uaziOKs}BJUj)O?PyPH z%d^MJmvN{U#PpF%;py(K9h*U%Z9d8N+otVYxFV0)c6h{~(3hg;VRT;3^81UvHCNj~ zgbXfCcIvXx%9k`6)S^g7%K`|}_b63T`;$Gl<4DFRRSRZ)$TP3C_9OE6#p0Fz(3>Y5 zUmm;AnTO4RJTlF0Nk_(TtVagLTP)8J@Nh6m*SQ+Q@6Qutmf%R16zyr5M1pg zrntNAg1@-YpZUw3V?8@P9J0=jnCx=#c;0-zu+mSn;N17JcU!RC*l}}OR52BAoS!UN zH=6yyy>fKD$!mcW^K5Tv@w6g;Uu>TnwAyq;kL7zBvA+AE?X9nSHi;fY4d z`jT1{#zrAS7MSmXwadF4z7}$9vJt!t^gU`D8zIIWS%%{7e}0-u*LJ_Lt!Xh`7A8$U zjT2F(yDp;vkQ|3y9{hsn9n`-J#>-@>@-21f#XuMyZG|>Ak!P3BSlZxGfDoNc*VUN)ALJk`mxwtWesD0c-% z!6hz(Y~0q6cB-nhx92uy8d2(Xn_jOeyx3b&(e0(*lFJ&o z6vn26v-L&qF{81HFQa<9kcE5f7;QU+`o?gG?o-*Pd&A09AGW^2isjRv2 zM0kF4Imo=k%YAD5)^UquVPl-$;gKEwW{fZr05*BUgdPcET;-iIC9Y4_wyh0r^D4Lg z`4M(0o(fEBd2yT%eXsLSN({X1jZ%@zdE9`85 z%+sw!dp!pC`q_=_j<%r#tghcU@svEBKbnt=aDc}R{ctOL{M>yyi^ z!%zJ37Ut)&NwYVO^}~bPk6(zr-+lOOsD<^5OV{_8JQG!?y;=X^XM^k3ZartFw&z)i z_b7B(nsi;RMM*lP#Ho^^l-jOnR+m&yRGlcgmXK{F zbv?EhJb_jza_uNuqEC=FJikgh2r_nl&+|_R+KU7Z}r966n ze^GReDJH`k==h@DkZE5)(=V%brN7l%aCS?Lo=jP#vf%0&72*g)v;v&A zH*Sa#*aIb3Dq|HYuh3I1{Ll=qxny)aHzb$AJZA?(Rh4Pyxl3JoCL`fRYZ@fZ+q*0a z=e3&GkUGe4s%Of+=h)uaWTF&Zm%@drSt?bK<#MjUTWIYlD0*s5WuTSvr$P1AC|rCU zV53%}j}H)!mmAHyx8)9%)0Cx^*Jisg4r$K_|7;tGT#&b$`evES|~y?6xY|h3Mt^ z!R+q1vy3jcli*k!sIr#)Fpi1FceXKlr(;oWsiSS}J;`96yA2ISS5?ePe?Q{n@G_(I z=HL{qoKod&YYmkBrS?=8!*u7+!S+&1>6M1Yllw;=S6(y>o-R!|B)qGGL>UxpSBQIDF3WmtOdAb5$maXG87!%CC)6-KD!4#n z(A$8T-{6hyz#uEVLZ+Ja)W1V->#*I#i(%e~+tKcMXSp$sVZ(?Y@VcfmeJkUhowdwk z=)$#my*4_^&l~;>#K*1AhS*9Ce$G3%CL0f>-ZO33kCzZoS&YNaaw1sMwNHRavn~SdAg9=;RP0i&{vw04mhpWw!&QaY^y9 ziVS-o3Re|XE^u8|aCNEjq8}%S?)#u)pcfBfnUJNb5{SoeQmr3KjEj0z&$E|myfLYe zXinAV@iojgV991qATY<60DvnCSo-MTK^HZUJOxVUt1D9TOtg4!VH7lPCW@qAn+Ho) z(SeRO#3De8ej{GcpHIrps7x=%;1P*m3c?au)=OZR>1lwXFh16S;HWaT%NpECVwFO( z&50Yxk)1vaqXq)a+&H67n4t%ErC+53NDLZ>Oji$s6Ntt zSGYtN$I>ZNq}6-HDyeYQRhKC~DVJ@Bl2}8lTuaOcMXq8)B`Nu)gsJv3Hgh#-rN=T| z74)zPEa=p%h`J)FCxP3v8g(K0D=!RI(D%H;kQXGYM9jG=Ys#3;6#P`vki#%KXtd*a zk6wa2z0}Hz;8dj2q1w!*?v-2F7+5`5bC2o!YMayYfhzj5Vf2k!eAY~LGCQmJ=fkIxG%S0WcFUdw;jXJB2?-HPbgD)h(cj!*2ZCIfe%HD2b?gL& zENg{+XP+)p@-v4zYejhE{LdiK{KgpRuqrbc^=DzL{^A)olQl0H=YhHDyfMhvUi6)S z@_Q$*<%1SRzqtu#x7t&f;M`y>^s~{gS${LzFE#`l1}2}qwKbqpN5{JE+_6~? z^I);)zQXO33*KeDQ?Bsc{4#B6aox$=aw_YO+cJ54AtL57<`g?yQ*O9e7;Z_ayxsA2gt5yu-K*Jw>vo@?W(Un{ruT@OA+~F*=lpgZD5~}4MuUb@cU3^0Prgt!X^d=p z%ZduPAodB7^`{ zv!0CB?ql#c7omxLt$kLs2Sz*IouxBz?*w5u7KMI)a(ZI%2F0J8Ta4`+G?O6pAm&)a zut?Jm0y`~J|AL!Iou~Xhb(=Meug^2*y3Qp?jIXMRw`z!vc^shl7{rD0u?_Lt;1I4=((FG%J z+u2KQ=;v-HzSTOg|DyQoy>1cKve`fyr$k;k9qa-%WiZ9oBKB}5F)OaIbe-Mk$k@5H z2E)l_yU6lk*ZbDv*{rae2M67*&5JJmdu^CKQS6&~$<|t3pUJcsGB6e5ZyeiV;E@g{ zi9-Db5_WRuT8~_+ACkw5ZqaQ^pX!YA_>i{@8}@ORZMFFbjIFyyt9}k;8lFj5cNCZ> zibfsw27%CiLr!{T^YKg4x4|*hm_qS3_^ar**OPOm)yn!?*gukSHgV^QcDG}$JRYo^ zdx_N?3)9VR^!1PGR-zS*Y$~6f1%aFJdT-rxUynJ7@A&y_t;~-WGj!WyH4q!4U@; zW7+3l>U1u1+nKGO?zvMuN^v81XZ^wc^?Ve@J^#v3nu8EW-8D?Fg>~vzUZ_*JoTCYB zk=Zp?w9UD(#3^ zYrMVHwsNKJ{iRXInL{*sw?HZNED)hH=!VcSEUtBXd)RM45Ej87 zvA#y5oAG<$DZ7{)w%*e=eXJEpydreO7xI{Rcil-~su9{eHC0SI3vcb9Ge8*M34Y<- zz{6&f794VSK|Z+9quQI*khi`>H=$f{#(V&ox1OB{gJI}T|z7LDgJtETo z(NXAds(Ywo?USM7H*3!qjd|PK{+iqL?cS)IWPznZL88%G1mWCF-=vQ+ zor#-n)R>PQ-NzXpxFPGyOa>5%*p1hcR=D2~%XG*pgPd8Elh;Pa%maAC=IvAckw0WG zN=bbzo%Of;(1=7IOy`=Pi}8o#+5YQ{YW2kyc;D}JVu$0rZQJh@#i2p% zvA&(u2G$PO?6dQZd%o?tUA$wCAW^VI4?{O0IIq(A$Uz|1fYf#$b?*lfd}HXbtv6!B zWH`Jw(jvUj_ug)H^afnTWlSWNoON@W!1QTf*rGvwP2GUP7B0*-i-9fdyTScvL8%$P ztaL`MU$Cz02P=I~`lKJ4Mt=i%@mvtjrcZPbsuzOoH~O(t*vagKvsP^XP{-LLnOhtR zoy=ZyH@eRD2Pb5sGl&iz@)ngwCbknA8&=G~n6T)6dU2)|Lngpoeq#C}jqT7}i!4?`%*+-h6AGaXF0vDmmS=e2 z^-&%ZFfwemyw%TD>Tud)-N1Z1#2zIUzGCy?c&mme*c8idJ^Qd}HTOmR0x6Gf<=JEj zadR>u)6EHobkbz$C+1``7HO)sn~0d-%C|RfE!S9|?!y?Ys$wn1+M~bvZ1ap?Gx=eR zPMTM-h!_S}hKTCpq=q%JT*b7L2!XUp$X8YK@EybLmfD#`h&SAxuka+CsgRQmpMBIVNWWJnIEdQ1i03MZq1m3 z`Hg3vZr0}L?83VyP7ZLp7)@u08NFK8T$pD$Bcx9Z-&#IL+s`v@Jox^{qpj^8qnXQY zwOSEn&NuF0sPK8&*K0QYot8NOB`>JxvGxGvi^PX%bmCcJh);;*QE6_u7hFMsN*6|r za-XhPp%YH;Qv&^zdKYb{$uVCZpR<~yURi4gJj>|mBG)+q(G;GG_Up)1A-yv}By~k( zGEg9p?@|Gkv~o+m28*XB)E{t)gtQzf6lD6uxs*qW%t5g5SY;HE!fUw9*Skn^i9sap z<|m~KLkbSgOg%A=$RZDn$c*SU{l-{{+ASKlP!*0Rc2rv(f{CWO2GYWa)Ln5=b~aq}&=vZC58a6#s@e{sj%Srz z6axzzvJgtvX@&}n+NuZ~xvX+mA!CPuT-C}Xr$O;>PEtV?Ez~+)VE!i+Fl^Cc`%^8{ zgaKq*RJS28>N*pYFy}5xT}*y^2?48ubGuRyMzN_FssOw^Qm4m6!_^D0i>K7daj%uM!l#bx!u)I!gvaa ziz$$J54APGqr|B16BwBakj)E6T#8ubuGbYYGp@RxdMlA?I=NO(A%2V!O=L9N0WwpM zWo$|S?2VU>4I;u`hCe5fEWJ$ijNXO7#1e_p{O6RBoM~Iyz-bXd0?8%zDtWZuB*y`h zY#27{%td?^cS9mEF}M2lR}~AXP`z=zs$eJpvR=tv_37lIRZ6l8QX~W(1EetD1TO0I z5-S+WTm>>TY9LHP;pbtxd070B=20d}8s&!ABgWT~63w=eBQcAxsMPC%U&>ZY*}*y3 zfS>ATPv?qBDU7Lm@{5sRK0|3Ka~<`KjxswtE_ygynGBZHw68iOvFQ;qCt*%Xit5=> zh*i%@g6KyMDM!GIy+@P;rz?K1SGu~_Au%D9fh_>N=d%==-xHvSOVQ{`Qz#{3;Q*sv zlk@7QF(d`c9s49v3a12RGOvh|O^Q+vC98ufR?JiQ`+6a$epI$V+7&Y&JcG)RdzZkS zOVEKWF*Z;xzxL~E%meAxWFVF(zPrM zpw5pBi^|5RBnpIdVPggO11|GqM5j`=M5Z=Y`el2ME1VmobjlF76>JO%DpjXw9+0J# z@NsTR>9l8vM81BPE)rFgc^)Jjnqo6LfQ9%F`?SFzLeL2-i=kaC#U7tUqIsLj$~22@ zZEuLz=Wd?`t8<=6&98tZ%WFC;9w^85kJBpeO3x0(ctl5;*g~{z@1x*)TjVNuq}NfK zE8~8uFeJDI1sp_P?=hKp%{M6};jBJMm`M}~FpzW;Qc#dC8(BWT5e6t=uz9Oj?0B-| zZmZGTfp}m7ZDOJ6RIQF2X!=+EfrU?%!FM}1JS;ihPX`F}VdzSyr7}FyxAd}z5sH~A zjlFnQ2l~1(lkl%E;fP$pvhPI7PS42=5RRQnaZ7QsjNDB&oS6kVKtD}#i!4}3a5o%u zl|@Vp0wSc1y5Wm$dFvqqGJ3Zd-X)*2F`pZs0VEO)^QAn`)MpdKzHACJ5$xV!{{ z2}<79Dl*w-Gua>p#iux~qTjGgQfr_BD~=VLG6IDHgfgIh1y*HNjE)a`PKT#5T=CJ% zs`fQP`K?@_-Ry>cTo+ojrw7DZ(IuWGe*Og-TL>wp^kLrAisPE|64f9Cg-Riijpx|) z)B&lu!%Zou$_Tm?MG4D7LNic0&yQZn`2AZl8TRN<0}Z=jU$U!momeKq7*38a?mIR z`ImCTn*Wsx6;RQa=@kc09XOKHTZ@D#L--*%0f-MC_S}Q0Ql8m8WLU##IKI ztaN+O3X`ti*FIfLTCUQno=XNvs`%zo$2cfOnb^ZVlzk|1-<6vfsLqF7b?_P?)7}kGX zCX;R{_~{?S{?0=mPYjZ&Avk~bJ_gk~YP#str|sR1&#DD5Ogdpg>~!{3!OYWlu}5aH zhomGa_BX#M-}iiI-CZg1`)Y~ua`=e|=e+X?ifNrLz@*8*W z%gy`L@B6v{REuD6K{;w2%HF^E53->2N@a(MWLkqvk;znB;f3XygnfIy_L~j0z9jem4x39~nL~1unx?iA1FSFYLd@}%RLOYSo?WLD+{3+c z6X|ITzqp|7=p9D zWI)4FMK*r+Z{GiQl7e6&`(H+X+hj@cj+>%wMN0*Vagp@;!Zu0{$QWxBTtj{Xbu#`1gN6 ze*6CU^K>I{ckjUT<(CuZ@7`DIfgizQ89$Ka*-Kb-~ZQoH}0WhhP0F z{WbN?)cmMB?GK3i%Uk{7A#;)sb79~3+EJ?PD7e%2zxYL~L+oC!KYNePNR^cp^$>Orfs@HZHQF{-dx-4Z zCz2GbT3#}lmRjB(wAT>FH*XHUNrxZ&gqkz^A-Q+=-;S^{_*w0J)TJ6|+e`c3wZ3+G zO`Fuw?C!lJ`a)GO@yp)z;b%&c65S)f!8*u6dgnnOh|@oaPb3 zdDt@Lq&FxM(Nm;Y9I$6Bap4UDvZ&Xn(30agMB^qPCh0FBBSG#nDGiSvk~TnW1H@$! zzRZyy!Gwc2Nb*n}0O??SH9<>h=C;ylB3V^ME8{RXDh+oc`bt$srm6!Zj(WP6^w`v^ zNZ@CKk|$Gbdij7OB7i_z{?$WV8DjA)tq<2;{yMhL)O(awYiTlVL!lJ==*vF`JC^qm zIigTjJe478E^N(K*4HrU_Cl3bEvTu5x6(^oUVVAYu^9mWYr$qx6=)N(X&M-jUtfDoj$zqgsxQ%3hmbuT4A)V!fsPlgf%0_SJf^v|DASDr1qv z=*hZI(C_`+W0#CVPtvwyiThLPH$i5)YZdJGNYRGQ)PFBf_bF{BaIZvCQNr<(p@l>UM?7^AiL6Eaba9Zzw!8>)P|mA?Ycd^&~lPalA5YS(H0e6KxqaSL!}4a;gg_Elo4Imv*Dr zrK)f`ROkqXHX72`tMZDg6c?c*)^@XhS3!JIPeLLSv&~gwTT>DlS(N8EKOX%0=RCZY7Xn3nc)e2$758Jik&K z0NFIf?uX8*)=d7AwEm~G11{|mdq}z$-q)CwtClkwQR$_l+EAChmhuGh67e)S?VQwYZoH2O1lU3S2%4hRcruEnj9*y>;7I^wAN4g&Y>w|c~-W9N`6VI zw<7UCR@XyGDozYnko3e(HP#e6AQL~G>kv#`tmw>H=eI(NO^qx;?`%|qbs}APBq^Qs zaV0a4J*}{nd>T_~C|q7a^7AVwq;e#gN8}eF=Ak6{NX3MjiGmm8-CX`hB3!VYu8A8y zWjIa5L5v>+A`deK^YzU082N3GgvJR{#ehTUjN^VfIiH$BiijY1`BhV_Tm(ReeieqX zhF2~iR&Li&BI^JG#IkM(RW|yZmPF=qU2YKV@x4U;R2+5eXp;oN;OfGm1g+TH7(f$e zdOYk2D29wQDcpvUN7`6)k<&KK9ODODhlPD}J>1s}!YM0Z>R40pW(bc?hq#C;9gdR# z1|_eITwmnp4a^x|*`+PrR!N8TDBj{8M#w@HQ(k!TA~%*iNR&9Lz+ve$mgOAGf=a;g znMUXV?Lv#49B(~$VuE~_3v{@gl>7(OHVC@x3hTKUy5P2jQ(tfS)EP4HJQrM20*=}i zJScooo3t()l9IGk3GjL-xGJkkAb114qBoiaVLg@6n}C(`D_tpdSn~u!O^!Srqs093RJs5QqkDR!7T%))+J;&_mLOTUx zYC$RDAMUM%M4J>Fip)MC{m-$=2AliwuwlI?-l;bw6C1|^6Oe)5hyps>;+f)r7*i-r zQUd@5=4)LE0NSq*iMh-q?7YGAr1~&L>BiCaG~uqRqqTCBwn2!M!%e@vJS;VBPr^G& z*koD}A5ToFlK{r*n_WE9!qGw?Hx-D?H7aSx3(0^w;AF`!om1EmFB#DS#Dnp&jem(L zk0+*Mm0wvLf3Z|6LsM%iE*(t){YyS7R& zW1YYQm)jhH<#H~&$w%4dlz?28bF^mSuxo>yL+}x}${~=EbNdlDXnFk{sm6IdkQSWm zuXALghlc5<(xcWGRJZCPbfq%mIi))X&PX_ckTrQXjP;vQW7x(aUsLzN1?i59ei)r| zJ+M+I8W$iw6nu9*i1Cyk&25q+BWTLjCw|-+;fVCH9u!m;5J9gr5Sy;a3l)fDCU00b z?t<8&kPtU%M+MrW``BZ?z+OU09Cd(^>t$f&&q}}#rJ+p(LnMW!glz|H)O*tkW+!{Kc`CSz?fKcOg~+*X-MVnK-Wz!24EY+P!~aLw`^L(3WCwny zs_XUK*YjZBZZ-!`3>T?xHtD7!V4I?BD+>auZZ_$bR*N(#(UvD;OjG8_lHtHX9ArK$ z7E|47DlLJVedK5b$uO`@4rOSWf&C#11jqpEE0P(@1FjwTOZ>sJBP5fBF>7dqjJ-3M ze=omNxBERxGxlx{`RZ1ksycP*)TzI>?&)x1(6BFfK3QqyLnS&dp5;aql=pzKyhTfG zwCIOi|KY>CMmcsZ~J$U0T;v-#K^aC{uJ25bo zc-b6nPO0~(!iAerW3WRi7N%VOFu8d-@N$yWym#%y?VU`?cNaC7yMh>?x~QkGuxaY{d{ZFy?F)}Y{6xD9@Ikbbk5#IRt&0l1J$Oj zbTJS)!ypt3ADu`DMF^PQ@r7KPh7lJy(a69ySr)T-or5B#9ge2@^rh-SYpe2P+q4bl z&$)_(82Mh0O;OKQEjL@Jz@r2KJHLucicl#c-zdg*#wQuGN#|hx7B=v<`qg&N$iX(Z z+Z!EO*l9Lmv8JSej6zNtbxC*_kRqsrpLi28&ChwL;s2L<{ z`H6KqnP+CMc9V9tz`tzWqbCjKlF+}TqrLmw?X-Fn!FqCT=qykX!6IUd3Tx3+?iJQU30JDTK4qOq1dC@DRiw{u@Z*HOW2x+ zqxD;!$>eag$^2-v|Cz1p8K#v;ByPd&&|y9s_AfuZlOJ>yKRueuuZ8BOTpwPlcooj% zw9MI^XO|w|GD{hVzsvX;v(v%8+;Z`8BiEnjDhxfXLgEwmV zKVryjgbkEW-Fr7gF&^0?oD?BjYCLMIP%23B;0dm34eggMZEC{!q};s6WZlQi)kFR1 zyTw-_Wm-LLsu_wx1rlwvdMw*`n|66|DJ~%&?(AUu6xUmM$|xPs}!*W5y%8&8QXVJU(yiG@hIsj=e`C z!^pYrYuV$AIPRD?&Q1Tzc90rhyve(co#UO%-t7+zRu;!%JU0jnRN6%87fd{tdc|av zcOQG>x;*#p-Gh~QCbl2hK6$;0*7aXa`YdahylX=8eDOWL zx~5}>p}f((-|TBI6O3E-yDu^M&zf)Wa=F>x>SB+qP>tiu&(va?OgZ|Bui{{t72qr+` zzTy%P+dEaP0zsb@%}}U$L_Y3O1fW^7fE&f!1q+`0iBv9Y_$cznB#1MyeeNj(m6xS#WS|>1R!2HBD40clj^^R|W6%u744;1T3zx7VO7&o!AEa(s@y@nc*KdH37cB-@cB|E zt)NY+U_&%*o%@(x*~#mfRb(?Qq*S?;cV+|0thW}+otyT_dS5ICl!@1ipUS61TFt9u z8%8K;>P%M<*5=d>y`i{iNiSEs&(|pcHo|}$g^RvvT_bE!3ny?PelFijguiQXU7u6K? ztrFu)P!#E*&7$M}eVqlUZe-TgP4r*%i49~C`b78j{pA;1>s z;3fyYu8vTk1G3OocKiR~kNb+(NRkWXZ?44-%%o$w)0KiwLAp?>PF7XZMF0{Z;x3*9-m`zm49b;yP?mIgs~`@N2)9gl z7XnXGVm8-$GLj_J>Czh~q);=!`jjQ0~}QOT;CRpmUwL8~Hu%Q5V@AsB>J zZ>i+a`TX^`l|HJkIvwP`Xbn~Z^hll2RqSu#0CN%|d~=C1y$!JZXpA#&)Z$_w-b|>2 ze%@Wou{dxK%hR;1HzScxp)$?brH(5_7V%zlsLqqs_JWDAuoj$HdYF6k-nrH$CiB~i zR}{B~;>_iIGYq1JM|!SQh;-b`nat&SHl_VG`%Rn0eAZF~cnrhfmv zI;>@+Z;$|0=MS#DB8C6!ZYN={{*b;W0{YjDRHc*L@AWPH8RENif9Ez`J}6^ zQ`IGNH`@=mZv`JNw72dm7K12D~%T|=(sEw}xhcJeWwQhZ$D{!m$ zutty&9nt#I+zIf~wm3om<3Ng__vn}g08OH<(oI7o&!~O~<%&%Dqt6lstPPT{*XI#R z4TS_PssXH&*B-p5- z^i2q>5uZX3m{N9RW2mCwzYK|hvj8T6XM`Tn3f1-4pRg@;1L((BvMy_&Q<08Gv=%fJ zR?&mi6QVjv0Y13W6Fect2XRs0B#4wfCC0=LD;)z4)?i>oWt$36Jn26Ij~&s^P*?#d z9hroWL~6h%XT_QN#Zh|DHB!k77|q?}U+Q?PF%eW>u?#G19SNxe<^k9Us{r{iO0Wtz zofvEiq(?P|^iT%w?&FfLP`9L(YUouYu^ir00-U(^6sxYta}8(8 z+VR1QVxKbiMMQ}g?SpLsBR7$A5=2rSEv1}O8ndHDYJW+vs<$VwrKvUS0*>cToodjOZPV^BG#VRI zPWWb6Q$q{HiO%8><(!Q3AVri!(?F+Q8$@_d13H`q*3T(6SpL<4hk-7ZyUiIgq6bjE=Or zZ3o_vgnnB!LvBSlP!@URFi$jPqUG|-J1iAKe0IFlWcpEV7J?h7a!xR8#8HgZa3lUH(rH#E^OJ^_AHMa_hbUQxE|62?eWSeH#a#@aX@>D!G?)<1X5<@{cRn+A->n3{ zqzg*e;E4Z9&YGvm^*aPC$DA29;*i>W4pSJO!g;--ukIqfhtFU6;$LsBg?Tu9D@Nx8 z#_CO1eR0?yX5Gz}dnN04#2l+P&(7Vvb9~g6$+4_c_4SUepKlLu+0JqKJw_UH=t{kV zIwI7a#)jW$x7;C0dKIHY<9c@@^0|(wU6O}be{ZQC= z&YF#Y9q+S!&WMCbQ9^UO)95~FpPID1ZHF9mlYQ>|?9Gr3%~O8Dm_o|!@v&|-gjr)#mG&rS6vn}vDMD2iw$XckBUV4b>rEPw_a^C zIBW;G`C{{*^A;h{ZrI%l&pBOB?BruM9-L5k_hKW$UsHaMPlQME&TA~9yCLK@TL!5H zI}YMI8HVa&ghWky+uX^*$YdDfoHuP@dUhZ+xAXdi7cOtkjRc5}prk#t?O_omJ)HuybSKUX9g!38#*#J1FDCq9+6+TvT)jb^Rg&5iGj z4PVc?`6fDbPF!b@omYDv5(auY(B5WR@W(yJF(JD=^s=b8jbB2m)eUWHGr88`lI%v? zwsOH(+aYToZcBUla9&5hw_CU91ue%Ex6Ln@-UxzWHdoKjo``wyetUMIkzKhMs_ll~ z%-j8qi}SPYb1kzR=Eu62zP#dR8)B%~kTR;R788H{#O>^z*|6bWGEKkK3Fv0S*WB%$ z;9mU{7Sg9d+5^tjN1WXJUbvM%wIP#Nx>?uw7~%%qJ%6RsUyiePhBrpo`%@F&Cj_g2 zi%TyeG|o++IE;;!nQr92QR_}eh}2%E*N&~FkZaguY(GD3@Uv4ig4r>C!u75l%kud* zvO(3ER%`j<;fE*VjryAijW^QuLpwP?bhdb|@9|+#mCj{V_jmbEQ}<;o>vQ0&6y0^atzax!$;*& z+Kdc?jCk7~lf}iCUC|!2I_<*{#!j0ZSb?KknT1{m;-kw4kI77eMLo#hgafqQOYj#$ zn^qu~=AkTWnHimxcH3+5SODa(pzMdroi4)LvZNf2)oMMS<3~;Gw@useJ?zcFU=WyR z+PCIID`Vd8xDMA*osIUHEsntv#gHsMbmfliz89j4q#1#cwymI&{n+lExe+%_e>kwXQVc0yWySgnRamUC41Cv3~55^@2Ne{XAPZPV4G9#OgJKoED?Hf zfEEM{skIsR2HsJH%(mTO+YyA^so2l3GHMU4liJanT(ci~33pJpA{4XEP(Iz6-TsV| zdt$`Ou-|#a7semXJ5gNU4+G;yCw8Q>tVm~eEGN8W;B<70GZ6%Q)XT%6{m#*2_R)ds zcKjXNf`enXMo;xRAuOi>vAK#h-V2M(u;B;cj=Y`8SyvHR4$d5Xtzb5s%{K-t;o5
+I`scXbnae`!KJ-bQ5`)T*Fh^p81rUWyHrL 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 %|t=Z|^S1cZ-aOS3;oaSM-1 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

bJwM?HXj_Ok@!8w|et02u9fd^@>xqoU6cg+|%! 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

RotlOHS5K9l`OM`f&SjV%B#4 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

*AwhXvYQ*a? zK?pq=J-L3LkFjEEh-Uvp=Z`!$Ecc$OoM5c`)l+g}Eaxf`2SYr#=p2&wu65>471fux zB$MOgi(PYmxO8`?f<_N@?+(vR&YQ`8X^iAVxO>3TR=Fvok&u8-D4GJ3hKTii>>Z*u z#^6}zT*W;!xVvKp-V9o-15Ys+CNZ2?je&B`M%z6n`=Z=k>b~o+QoZ3xlPz9|ZY{sR z?W=1m?a=(?2UdN%?V|Ie8fSj8*2Z1@nQZ^)@Jc(n!K&eXVzwjIVSV7nx&^Fc>!;+& zTj=*a`jp7P9p=TMXnBony|-M^5-YZj`Po`m#H_0?B^fT!j}XJe!5+*;`Tst%?p?ov)0;0;?h!MLXI^-O7z^=#+ z`V}Z9pU`2XZ>$Q`lkYiL7mO?$;T;`YzbSSryhqRe3g?xl*kE0#`it$}CGR66=2Cmu zyDmm+FIk&*Qf%iLy#`F5=P zLLG-yrAG}CI1SToq$0d--t|O)SmaNIOmt+ll`51F5T}W8C?n&I?KSuo3!vn#@!sN} z_4DGC1PrzHw9G}`x=|EIb&;7DtYRt?av_RGX;U9)5k_WhfGSK9qKn?ym17t0m_+8V zv--qfB|ore+RO*nSGmebC->{HkH~vF=Mg=Vt*eA7jNDT9ZX%U5v)I##Zm7}qV{Ez< zG;X7uW2i*X5K#K*Z~{d&9yExg4?6qD?XKwroCz}%aXLSM(=+sh{H;_sIMtR;vtdjQ zT7@pZ1Ofh7T)$zOi;1SjUZjc&Lozv^(6I9?3_xuip;>z zuy;j}5R@TWeFxvhoK5x&C?XRrlaw%FFjnYvO3USVT8B%VyWB^SVQ01=I&NC(J?-%Mc%UPa_2| z1su3tnpAWk=5&MvH?Um}CgM{+cXTPeGBY0O=CJ5>4y7H;PNl`*36Mu3mt+al{kSGG zyqD-GQgsY-<1*~VHf1t7KRJKB;6N_B^OBrfyK^b!B->f?=Vvd-q@}9R`l^$5OqRHy zWl(Ph&m9ORO3?{YEj8kj%Stsb->6`Sq<*bxS=(YN=QX}UN5qiZ6~Z;2%9^CTZYvk{ zH`a^Xq~f$TrNP1U=JXz$N&gVAcAmu;=%?V6s3HOCjIR#joNWZ@MKfRH_u4y2iMs*U}=gMHp8eD!>s|GTMM86}zH)*M4@r@dMx^9ZFXPyJ0-B;%)GyHrbHGtRDtBIZA{Ot5 zDLS74tq5Dw0<6D9CC6zzQLQRctjN1^C2A2Y?<;dK%ApK*Bu&varkDa{1aPmr$An%{ zohjeD9(~FbOCENRySYn>E~F7V1jIAohzaNnOo6FhPG?w+^FxeJNbs7p z6Wmk)$}4x7u5)YwI)F=d z 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

9%6ch=+Nv9zurr$P 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[Egk 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 z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| 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Ⓢ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 -# e1000-devel Mailing List -# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -# -################################################################################ diff --git a/openflow/datapath/linux-2.6/Modules.mk b/openflow/datapath/linux-2.6/Modules.mk deleted file mode 100644 index 8c854a0e..00000000 --- a/openflow/datapath/linux-2.6/Modules.mk +++ /dev/null @@ -1,32 +0,0 @@ -ofdatapath_sources += \ - linux-2.6/compat-2.6/genetlink-openflow.c \ - linux-2.6/compat-2.6/random32.c -ofdatapath_headers += \ - linux-2.6/compat-2.6/compat26.h \ - linux-2.6/compat-2.6/include/asm-generic/bug.h \ - linux-2.6/compat-2.6/include/linux/dmi.h \ - linux-2.6/compat-2.6/include/linux/icmp.h \ - linux-2.6/compat-2.6/include/linux/if_arp.h \ - linux-2.6/compat-2.6/include/linux/ip.h \ - linux-2.6/compat-2.6/include/linux/ipv6.h \ - linux-2.6/compat-2.6/include/linux/jiffies.h \ - linux-2.6/compat-2.6/include/linux/lockdep.h \ - linux-2.6/compat-2.6/include/linux/mutex.h \ - linux-2.6/compat-2.6/include/linux/netfilter_ipv4.h \ - linux-2.6/compat-2.6/include/linux/netlink.h \ - linux-2.6/compat-2.6/include/linux/random.h \ - linux-2.6/compat-2.6/include/linux/rculist.h \ - linux-2.6/compat-2.6/include/linux/skbuff.h \ - linux-2.6/compat-2.6/include/linux/tcp.h \ - linux-2.6/compat-2.6/include/linux/timer.h \ - linux-2.6/compat-2.6/include/linux/types.h \ - linux-2.6/compat-2.6/include/linux/udp.h \ - linux-2.6/compat-2.6/include/linux/workqueue.h \ - linux-2.6/compat-2.6/include/net/checksum.h \ - linux-2.6/compat-2.6/include/net/genetlink.h \ - linux-2.6/compat-2.6/include/net/netlink.h - -#dist_modules += veth -#build_modules += $(if $(BUILD_VETH),veth) -veth_sources = linux-2.6/compat-2.6/veth.c -veth_headers = diff --git a/openflow/datapath/linux-2.6/compat-2.6/compat26.h b/openflow/datapath/linux-2.6/compat-2.6/compat26.h deleted file mode 100644 index 37f6a4f8..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/compat26.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef __COMPAT26_H -#define __COMPAT26_H 1 - -#include - -#if defined(CONFIG_PREEMPT) && LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21) -#error "CONFIG_PREEMPT is broken with 2.6.x before 2.6.21--see commit 4498121ca3, \"[NET]: Handle disabled preemption in gfp_any()\"" -#endif - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23) -/*---------------------------------------------------------------------------- - * In 2.6.24, a namespace argument became required for dev_get_by_name. */ - -#define dev_get_by_name(net, name) \ - dev_get_by_name((name)) - -#define dev_get_by_index(net, ifindex) \ - dev_get_by_index((ifindex)) - -#endif /* linux kernel <= 2.6.23 */ - - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22) -/*---------------------------------------------------------------------------- - * In 2.6.23, the last argument was dropped from kmem_cache_create. */ -#define kmem_cache_create(n, s, a, f, c) \ - kmem_cache_create((n), (s), (a), (f), (c), NULL) - -#endif /* linux kernel <= 2.6.22 */ - -#endif /* compat26.h */ diff --git a/openflow/datapath/linux-2.6/compat-2.6/genetlink-brcompat.c b/openflow/datapath/linux-2.6/compat-2.6/genetlink-brcompat.c deleted file mode 100644 index f30996ce..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/genetlink-brcompat.c +++ /dev/null @@ -1,20 +0,0 @@ -#include "net/genetlink.h" - -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) - -/* We fix grp->id to 32 so that it doesn't collide with any of the multicast - * groups selected by openflow_mod, which uses groups 16 through 31. Collision - * isn't fatal--multicast listeners should check that the family is the one - * that they want and discard others--but it wastes time and memory to receive - * unwanted messages. */ -int genl_register_mc_group(struct genl_family *family, - struct genl_multicast_group *grp) -{ - grp->id = 32; - grp->family = family; - - return 0; -} - -#endif /* kernel < 2.6.23 */ diff --git a/openflow/datapath/linux-2.6/compat-2.6/genetlink-openflow.c b/openflow/datapath/linux-2.6/compat-2.6/genetlink-openflow.c deleted file mode 100644 index 9e09215f..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/genetlink-openflow.c +++ /dev/null @@ -1,22 +0,0 @@ -#include "net/genetlink.h" - -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) - -/* We use multicast groups 16 through 31 to avoid colliding with the multicast - * group selected by brcompat_mod, which uses groups 32. Collision isn't - * fatal--multicast listeners should check that the family is the one that they - * want and discard others--but it wastes time and memory to receive unwanted - * messages. */ -int genl_register_mc_group(struct genl_family *family, - struct genl_multicast_group *grp) -{ - /* This code is called single-threaded. */ - static unsigned int next_id = 0; - grp->id = next_id++ % 16 + 16; - grp->family = family; - - return 0; -} - -#endif /* kernel < 2.6.23 */ diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/asm-generic/bug.h b/openflow/datapath/linux-2.6/compat-2.6/include/asm-generic/bug.h deleted file mode 100644 index bd0a1714..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/asm-generic/bug.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef __ASM_GENERIC_BUG_WRAPPER_H -#define __ASM_GENERIC_BUG_WRAPPER_H - -#include_next - -#ifndef WARN_ON_ONCE -#define WARN_ON_ONCE(condition) ({ \ - static int __warned; \ - int __ret_warn_once = !!(condition); \ - \ - if (unlikely(__ret_warn_once) && !__warned) { \ - WARN_ON(1); \ - __warned = 1; \ - } \ - unlikely(__ret_warn_once); \ -}) - -#endif - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/dmi.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/dmi.h deleted file mode 100644 index 52916fec..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/dmi.h +++ /dev/null @@ -1,114 +0,0 @@ -#ifndef __LINUX_DMI_WRAPPER_H -#define __LINUX_DMI_WRAPPER_H 1 - -#include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23) - -#include_next - -#else /* linux version >= 2.6.23 */ - -#ifndef __DMI_H__ -#define __DMI_H__ - -#include - -enum dmi_field { - DMI_NONE, - DMI_BIOS_VENDOR, - DMI_BIOS_VERSION, - DMI_BIOS_DATE, - DMI_SYS_VENDOR, - DMI_PRODUCT_NAME, - DMI_PRODUCT_VERSION, - DMI_PRODUCT_SERIAL, - DMI_PRODUCT_UUID, - DMI_BOARD_VENDOR, - DMI_BOARD_NAME, - DMI_BOARD_VERSION, - DMI_BOARD_SERIAL, - DMI_BOARD_ASSET_TAG, - DMI_CHASSIS_VENDOR, - DMI_CHASSIS_TYPE, - DMI_CHASSIS_VERSION, - DMI_CHASSIS_SERIAL, - DMI_CHASSIS_ASSET_TAG, - DMI_STRING_MAX, -}; - -enum dmi_device_type { - DMI_DEV_TYPE_ANY = 0, - DMI_DEV_TYPE_OTHER, - DMI_DEV_TYPE_UNKNOWN, - DMI_DEV_TYPE_VIDEO, - DMI_DEV_TYPE_SCSI, - DMI_DEV_TYPE_ETHERNET, - DMI_DEV_TYPE_TOKENRING, - DMI_DEV_TYPE_SOUND, - DMI_DEV_TYPE_IPMI = -1, - DMI_DEV_TYPE_OEM_STRING = -2 -}; - -struct dmi_header { - u8 type; - u8 length; - u16 handle; -}; - -/* - * DMI callbacks for problem boards - */ -struct dmi_strmatch { - u8 slot; - char *substr; -}; - -struct dmi_system_id { - int (*callback)(struct dmi_system_id *); - const char *ident; - struct dmi_strmatch matches[4]; - void *driver_data; -}; - -#define DMI_MATCH(a, b) { a, b } - -struct dmi_device { - struct list_head list; - int type; - const char *name; - void *device_data; /* Type specific data */ -}; - -/* No CONFIG_DMI before 2.6.16 */ -#if defined(CONFIG_DMI) || defined(CONFIG_X86_32) - -extern int dmi_check_system(struct dmi_system_id *list); -extern char * dmi_get_system_info(int field); -extern struct dmi_device * dmi_find_device(int type, const char *name, - struct dmi_device *from); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) -extern void dmi_scan_machine(void); -#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17) -extern int dmi_get_year(int field); -#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) -extern int dmi_name_in_vendors(char *str); -#endif - -#else - -static inline int dmi_check_system(struct dmi_system_id *list) { return 0; } -static inline char * dmi_get_system_info(int field) { return NULL; } -static inline struct dmi_device * dmi_find_device(int type, const char *name, - struct dmi_device *from) { return NULL; } -static inline int dmi_get_year(int year) { return 0; } -static inline int dmi_name_in_vendors(char *s) { return 0; } - -#endif - -#endif /* __DMI_H__ */ - -#endif /* linux kernel < 2.6.22 */ - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/icmp.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/icmp.h deleted file mode 100644 index 89b354e4..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/icmp.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef __LINUX_ICMP_WRAPPER_H -#define __LINUX_ICMP_WRAPPER_H 1 - -#include_next - -#ifndef HAVE_SKBUFF_HEADER_HELPERS -static inline struct icmphdr *icmp_hdr(const struct sk_buff *skb) -{ - return (struct icmphdr *)skb_transport_header(skb); -} -#endif - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/if_arp.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/if_arp.h deleted file mode 100644 index 3ec9ea7a..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/if_arp.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef __LINUX_IF_ARP_WRAPPER_H -#define __LINUX_IF_ARP_WRAPPER_H 1 - - -#include_next - -#ifndef HAVE_SKBUFF_HEADER_HELPERS -#include - -static inline struct arphdr *arp_hdr(const struct sk_buff *skb) -{ - return (struct arphdr *)skb_network_header(skb); -} -#endif /* !HAVE_SKBUFF_HEADER_HELPERS */ - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/ip.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/ip.h deleted file mode 100644 index 36765396..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/ip.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef __LINUX_IP_WRAPPER_H -#define __LINUX_IP_WRAPPER_H 1 - -#include_next - -#ifndef HAVE_SKBUFF_HEADER_HELPERS -static inline struct iphdr *ip_hdr(const struct sk_buff *skb) -{ - return (struct iphdr *)skb_network_header(skb); -} - -static inline unsigned int ip_hdrlen(const struct sk_buff *skb) -{ - return ip_hdr(skb)->ihl * 4; -} -#endif /* !HAVE_SKBUFF_HEADER_HELPERS */ - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/ipv6.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/ipv6.h deleted file mode 100644 index 25a5431a..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/ipv6.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef __LINUX_IPV6_WRAPPER_H -#define __LINUX_IPV6_WRAPPER_H 1 - -#include_next - -#ifndef HAVE_SKBUFF_HEADER_HELPERS -static inline struct ipv6hdr *ipv6_hdr(const struct sk_buff *skb) -{ - return (struct ipv6hdr *)skb_network_header(skb); -} -#endif - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/jiffies.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/jiffies.h deleted file mode 100644 index 3286e634..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/jiffies.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef __LINUX_JIFFIES_WRAPPER_H -#define __LINUX_JIFFIES_WRAPPER_H 1 - -#include_next - -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) - -/* Same as above, but does so with platform independent 64bit types. - * These must be used when utilizing jiffies_64 (i.e. return value of - * get_jiffies_64() */ -#define time_after64(a,b) \ - (typecheck(__u64, a) && \ - typecheck(__u64, b) && \ - ((__s64)(b) - (__s64)(a) < 0)) -#define time_before64(a,b) time_after64(b,a) - -#define time_after_eq64(a,b) \ - (typecheck(__u64, a) && \ - typecheck(__u64, b) && \ - ((__s64)(a) - (__s64)(b) >= 0)) -#define time_before_eq64(a,b) time_after_eq64(b,a) - -#endif /* linux kernel < 2.6.19 */ - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/lockdep.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/lockdep.h deleted file mode 100644 index 1c839423..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/lockdep.h +++ /dev/null @@ -1,450 +0,0 @@ -/* - * Runtime locking correctness validator - * - * Copyright (C) 2006,2007 Red Hat, Inc., Ingo Molnar - * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra - * - * see Documentation/lockdep-design.txt for more details. - */ -#ifndef __LINUX_LOCKDEP_WRAPPER_H -#define __LINUX_LOCKDEP_WRAPPER_H - -#include_next - -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) - -struct task_struct; -struct lockdep_map; - -#ifdef CONFIG_LOCKDEP - -#include -#include -#include -#include - -/* - * Lock-class usage-state bits: - */ -enum lock_usage_bit -{ - LOCK_USED = 0, - LOCK_USED_IN_HARDIRQ, - LOCK_USED_IN_SOFTIRQ, - LOCK_ENABLED_SOFTIRQS, - LOCK_ENABLED_HARDIRQS, - LOCK_USED_IN_HARDIRQ_READ, - LOCK_USED_IN_SOFTIRQ_READ, - LOCK_ENABLED_SOFTIRQS_READ, - LOCK_ENABLED_HARDIRQS_READ, - LOCK_USAGE_STATES -}; - -/* - * Usage-state bitmasks: - */ -#define LOCKF_USED (1 << LOCK_USED) -#define LOCKF_USED_IN_HARDIRQ (1 << LOCK_USED_IN_HARDIRQ) -#define LOCKF_USED_IN_SOFTIRQ (1 << LOCK_USED_IN_SOFTIRQ) -#define LOCKF_ENABLED_HARDIRQS (1 << LOCK_ENABLED_HARDIRQS) -#define LOCKF_ENABLED_SOFTIRQS (1 << LOCK_ENABLED_SOFTIRQS) - -#define LOCKF_ENABLED_IRQS (LOCKF_ENABLED_HARDIRQS | LOCKF_ENABLED_SOFTIRQS) -#define LOCKF_USED_IN_IRQ (LOCKF_USED_IN_HARDIRQ | LOCKF_USED_IN_SOFTIRQ) - -#define LOCKF_USED_IN_HARDIRQ_READ (1 << LOCK_USED_IN_HARDIRQ_READ) -#define LOCKF_USED_IN_SOFTIRQ_READ (1 << LOCK_USED_IN_SOFTIRQ_READ) -#define LOCKF_ENABLED_HARDIRQS_READ (1 << LOCK_ENABLED_HARDIRQS_READ) -#define LOCKF_ENABLED_SOFTIRQS_READ (1 << LOCK_ENABLED_SOFTIRQS_READ) - -#define LOCKF_ENABLED_IRQS_READ \ - (LOCKF_ENABLED_HARDIRQS_READ | LOCKF_ENABLED_SOFTIRQS_READ) -#define LOCKF_USED_IN_IRQ_READ \ - (LOCKF_USED_IN_HARDIRQ_READ | LOCKF_USED_IN_SOFTIRQ_READ) - -#define MAX_LOCKDEP_SUBCLASSES 8UL - -/* - * Lock-classes are keyed via unique addresses, by embedding the - * lockclass-key into the kernel (or module) .data section. (For - * static locks we use the lock address itself as the key.) - */ -struct lockdep_subclass_key { - char __one_byte; -} __attribute__ ((__packed__)); - -struct lock_class_key { - struct lockdep_subclass_key subkeys[MAX_LOCKDEP_SUBCLASSES]; -}; - -/* - * The lock-class itself: - */ -struct lock_class { - /* - * class-hash: - */ - struct list_head hash_entry; - - /* - * global list of all lock-classes: - */ - struct list_head lock_entry; - - struct lockdep_subclass_key *key; - unsigned int subclass; - - /* - * IRQ/softirq usage tracking bits: - */ - unsigned long usage_mask; - struct stack_trace usage_traces[LOCK_USAGE_STATES]; - - /* - * These fields represent a directed graph of lock dependencies, - * to every node we attach a list of "forward" and a list of - * "backward" graph nodes. - */ - struct list_head locks_after, locks_before; - - /* - * Generation counter, when doing certain classes of graph walking, - * to ensure that we check one node only once: - */ - unsigned int version; - - /* - * Statistics counter: - */ - unsigned long ops; - - const char *name; - int name_version; - -#ifdef CONFIG_LOCK_STAT - unsigned long contention_point[4]; -#endif -}; - -#ifdef CONFIG_LOCK_STAT -struct lock_time { - s64 min; - s64 max; - s64 total; - unsigned long nr; -}; - -enum bounce_type { - bounce_acquired_write, - bounce_acquired_read, - bounce_contended_write, - bounce_contended_read, - nr_bounce_types, - - bounce_acquired = bounce_acquired_write, - bounce_contended = bounce_contended_write, -}; - -struct lock_class_stats { - unsigned long contention_point[4]; - struct lock_time read_waittime; - struct lock_time write_waittime; - struct lock_time read_holdtime; - struct lock_time write_holdtime; - unsigned long bounces[nr_bounce_types]; -}; - -struct lock_class_stats lock_stats(struct lock_class *class); -void clear_lock_stats(struct lock_class *class); -#endif - -/* - * Map the lock object (the lock instance) to the lock-class object. - * This is embedded into specific lock instances: - */ -struct lockdep_map { - struct lock_class_key *key; - struct lock_class *class_cache; - const char *name; -#ifdef CONFIG_LOCK_STAT - int cpu; -#endif -}; - -/* - * Every lock has a list of other locks that were taken after it. - * We only grow the list, never remove from it: - */ -struct lock_list { - struct list_head entry; - struct lock_class *class; - struct stack_trace trace; - int distance; -}; - -/* - * We record lock dependency chains, so that we can cache them: - */ -struct lock_chain { - struct list_head entry; - u64 chain_key; -}; - -struct held_lock { - /* - * One-way hash of the dependency chain up to this point. We - * hash the hashes step by step as the dependency chain grows. - * - * We use it for dependency-caching and we skip detection - * passes and dependency-updates if there is a cache-hit, so - * it is absolutely critical for 100% coverage of the validator - * to have a unique key value for every unique dependency path - * that can occur in the system, to make a unique hash value - * as likely as possible - hence the 64-bit width. - * - * The task struct holds the current hash value (initialized - * with zero), here we store the previous hash value: - */ - u64 prev_chain_key; - struct lock_class *class; - unsigned long acquire_ip; - struct lockdep_map *instance; - -#ifdef CONFIG_LOCK_STAT - u64 waittime_stamp; - u64 holdtime_stamp; -#endif - /* - * The lock-stack is unified in that the lock chains of interrupt - * contexts nest ontop of process context chains, but we 'separate' - * the hashes by starting with 0 if we cross into an interrupt - * context, and we also keep do not add cross-context lock - * dependencies - the lock usage graph walking covers that area - * anyway, and we'd just unnecessarily increase the number of - * dependencies otherwise. [Note: hardirq and softirq contexts - * are separated from each other too.] - * - * The following field is used to detect when we cross into an - * interrupt context: - */ - int irq_context; - int trylock; - int read; - int check; - int hardirqs_off; -}; - -/* - * Initialization, self-test and debugging-output methods: - */ -extern void lockdep_init(void); -extern void lockdep_info(void); -extern void lockdep_reset(void); -extern void lockdep_reset_lock(struct lockdep_map *lock); -extern void lockdep_free_key_range(void *start, unsigned long size); - -extern void lockdep_off(void); -extern void lockdep_on(void); - -/* - * These methods are used by specific locking variants (spinlocks, - * rwlocks, mutexes and rwsems) to pass init/acquire/release events - * to lockdep: - */ - -extern void lockdep_init_map(struct lockdep_map *lock, const char *name, - struct lock_class_key *key, int subclass); - -/* - * Reinitialize a lock key - for cases where there is special locking or - * special initialization of locks so that the validator gets the scope - * of dependencies wrong: they are either too broad (they need a class-split) - * or they are too narrow (they suffer from a false class-split): - */ -#define lockdep_set_class(lock, key) \ - lockdep_init_map(&(lock)->dep_map, #key, key, 0) -#define lockdep_set_class_and_name(lock, key, name) \ - lockdep_init_map(&(lock)->dep_map, name, key, 0) -#define lockdep_set_class_and_subclass(lock, key, sub) \ - lockdep_init_map(&(lock)->dep_map, #key, key, sub) -#define lockdep_set_subclass(lock, sub) \ - lockdep_init_map(&(lock)->dep_map, #lock, \ - (lock)->dep_map.key, sub) - -/* - * Acquire a lock. - * - * Values for "read": - * - * 0: exclusive (write) acquire - * 1: read-acquire (no recursion allowed) - * 2: read-acquire with same-instance recursion allowed - * - * Values for check: - * - * 0: disabled - * 1: simple checks (freeing, held-at-exit-time, etc.) - * 2: full validation - */ -extern void lock_acquire(struct lockdep_map *lock, unsigned int subclass, - int trylock, int read, int check, unsigned long ip); - -extern void lock_release(struct lockdep_map *lock, int nested, - unsigned long ip); - -# define INIT_LOCKDEP .lockdep_recursion = 0, - -#define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0) - -#else /* !LOCKDEP */ - -static inline void lockdep_off(void) -{ -} - -static inline void lockdep_on(void) -{ -} - -# define lock_acquire(l, s, t, r, c, i) do { } while (0) -# define lock_release(l, n, i) do { } while (0) -# define lockdep_init() do { } while (0) -# define lockdep_info() do { } while (0) -# define lockdep_init_map(lock, name, key, sub) do { (void)(key); } while (0) -# define lockdep_set_class(lock, key) do { (void)(key); } while (0) -# define lockdep_set_class_and_name(lock, key, name) \ - do { (void)(key); } while (0) -#define lockdep_set_class_and_subclass(lock, key, sub) \ - do { (void)(key); } while (0) -#define lockdep_set_subclass(lock, sub) do { } while (0) - -# define INIT_LOCKDEP -# define lockdep_reset() do { debug_locks = 1; } while (0) -# define lockdep_free_key_range(start, size) do { } while (0) -/* - * The class key takes no space if lockdep is disabled: - */ -struct lock_class_key { }; - -#define lockdep_depth(tsk) (0) - -#endif /* !LOCKDEP */ - -#ifdef CONFIG_LOCK_STAT - -extern void lock_contended(struct lockdep_map *lock, unsigned long ip); -extern void lock_acquired(struct lockdep_map *lock); - -#define LOCK_CONTENDED(_lock, try, lock) \ -do { \ - if (!try(_lock)) { \ - lock_contended(&(_lock)->dep_map, _RET_IP_); \ - lock(_lock); \ - } \ - lock_acquired(&(_lock)->dep_map); \ -} while (0) - -#else /* CONFIG_LOCK_STAT */ - -#define lock_contended(lockdep_map, ip) do {} while (0) -#define lock_acquired(lockdep_map) do {} while (0) - -#define LOCK_CONTENDED(_lock, try, lock) \ - lock(_lock) - -#endif /* CONFIG_LOCK_STAT */ - -#if defined(CONFIG_TRACE_IRQFLAGS) && defined(CONFIG_GENERIC_HARDIRQS) -extern void early_init_irq_lock_class(void); -#else -static inline void early_init_irq_lock_class(void) -{ -} -#endif - -#ifdef CONFIG_TRACE_IRQFLAGS -extern void early_boot_irqs_off(void); -extern void early_boot_irqs_on(void); -extern void print_irqtrace_events(struct task_struct *curr); -#else -static inline void early_boot_irqs_off(void) -{ -} -static inline void early_boot_irqs_on(void) -{ -} -static inline void print_irqtrace_events(struct task_struct *curr) -{ -} -#endif - -/* - * For trivial one-depth nesting of a lock-class, the following - * global define can be used. (Subsystems with multiple levels - * of nesting should define their own lock-nesting subclasses.) - */ -#define SINGLE_DEPTH_NESTING 1 - -/* - * Map the dependency ops to NOP or to real lockdep ops, depending - * on the per lock-class debug mode: - */ - -#ifdef CONFIG_DEBUG_LOCK_ALLOC -# ifdef CONFIG_PROVE_LOCKING -# define spin_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 2, i) -# else -# define spin_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 1, i) -# endif -# define spin_release(l, n, i) lock_release(l, n, i) -#else -# define spin_acquire(l, s, t, i) do { } while (0) -# define spin_release(l, n, i) do { } while (0) -#endif - -#ifdef CONFIG_DEBUG_LOCK_ALLOC -# ifdef CONFIG_PROVE_LOCKING -# define rwlock_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 2, i) -# define rwlock_acquire_read(l, s, t, i) lock_acquire(l, s, t, 2, 2, i) -# else -# define rwlock_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 1, i) -# define rwlock_acquire_read(l, s, t, i) lock_acquire(l, s, t, 2, 1, i) -# endif -# define rwlock_release(l, n, i) lock_release(l, n, i) -#else -# define rwlock_acquire(l, s, t, i) do { } while (0) -# define rwlock_acquire_read(l, s, t, i) do { } while (0) -# define rwlock_release(l, n, i) do { } while (0) -#endif - -#ifdef CONFIG_DEBUG_LOCK_ALLOC -# ifdef CONFIG_PROVE_LOCKING -# define mutex_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 2, i) -# else -# define mutex_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 1, i) -# endif -# define mutex_release(l, n, i) lock_release(l, n, i) -#else -# define mutex_acquire(l, s, t, i) do { } while (0) -# define mutex_release(l, n, i) do { } while (0) -#endif - -#ifdef CONFIG_DEBUG_LOCK_ALLOC -# ifdef CONFIG_PROVE_LOCKING -# define rwsem_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 2, i) -# define rwsem_acquire_read(l, s, t, i) lock_acquire(l, s, t, 1, 2, i) -# else -# define rwsem_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 1, i) -# define rwsem_acquire_read(l, s, t, i) lock_acquire(l, s, t, 1, 1, i) -# endif -# define rwsem_release(l, n, i) lock_release(l, n, i) -#else -# define rwsem_acquire(l, s, t, i) do { } while (0) -# define rwsem_acquire_read(l, s, t, i) do { } while (0) -# define rwsem_release(l, n, i) do { } while (0) -#endif - -#endif /* linux kernel < 2.6.18 */ - -#endif /* __LINUX_LOCKDEP_WRAPPER_H */ diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/mutex.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/mutex.h deleted file mode 100644 index cb5b2738..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/mutex.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef __LINUX_MUTEX_WRAPPER_H -#define __LINUX_MUTEX_WRAPPER_H - - -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) - -#include - -struct mutex { - struct semaphore sema; -}; - -#define mutex_init(mutex) init_MUTEX(&mutex->sema) -#define mutex_destroy(mutex) do { } while (0) - -#define __MUTEX_INITIALIZER(name) \ - __SEMAPHORE_INITIALIZER(name,1) - -#define DEFINE_MUTEX(mutexname) \ - struct mutex mutexname = { __MUTEX_INITIALIZER(mutexname.sema) } - -/* - * See kernel/mutex.c for detailed documentation of these APIs. - * Also see Documentation/mutex-design.txt. - */ -static inline void mutex_lock(struct mutex *lock) -{ - down(&lock->sema); -} - -static inline int mutex_lock_interruptible(struct mutex *lock) -{ - return down_interruptible(&lock->sema); -} - -#define mutex_lock_nested(lock, subclass) mutex_lock(lock) -#define mutex_lock_interruptible_nested(lock, subclass) mutex_lock_interruptible(lock) - -/* - * NOTE: mutex_trylock() follows the spin_trylock() convention, - * not the down_trylock() convention! - */ -static inline int mutex_trylock(struct mutex *lock) -{ - return !down_trylock(&lock->sema); -} - -static inline void mutex_unlock(struct mutex *lock) -{ - up(&lock->sema); -} -#else - -#include_next - -#endif /* linux version < 2.6.16 */ - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/netdevice.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/netdevice.h deleted file mode 100644 index 7abeb3bf..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/netdevice.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef __LINUX_NETDEVICE_WRAPPER_H -#define __LINUX_NETDEVICE_WRAPPER_H 1 - -#include_next - -#ifndef to_net_dev -#define to_net_dev(class) container_of(class, struct net_device, class_dev) -#endif - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/netfilter_bridge.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/netfilter_bridge.h deleted file mode 100644 index 1c8183c8..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/netfilter_bridge.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef __LINUX_NETFILTER_BRIDGE_WRAPPER_H -#define __LINUX_NETFILTER_BRIDGE_WRAPPER_H - -#include_next - -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) - -#include -#include - -static inline unsigned int nf_bridge_encap_header_len(const struct sk_buff *skb) -{ - switch (skb->protocol) { - case __constant_htons(ETH_P_8021Q): - return VLAN_HLEN; - default: - return 0; - } -} - -#endif /* linux version < 2.6.22 */ - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/netfilter_ipv4.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/netfilter_ipv4.h deleted file mode 100644 index ed8a5d94..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/netfilter_ipv4.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef __LINUX_NETFILTER_IPV4_WRAPPER_H -#define __LINUX_NETFILTER_IPV4_WRAPPER_H 1 - -#include_next - -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) - -#ifdef __KERNEL__ - -#define NF_INET_PRE_ROUTING NF_IP_PRE_ROUTING -#define NF_INET_POST_ROUTING NF_IP_POST_ROUTING -#define NF_INET_FORWARD NF_IP_FORWARD - -#endif /* __KERNEL__ */ - -#endif /* linux kernel < 2.6.25 */ - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/netlink.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/netlink.h deleted file mode 100644 index c5f83bd0..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/netlink.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef __LINUX_NETLINK_WRAPPER_H -#define __LINUX_NETLINK_WRAPPER_H 1 - -#include -#include_next -#include - -#include - -#ifndef NLMSG_DEFAULT_SIZE -#define NLMSG_DEFAULT_SIZE (NLMSG_GOODSIZE - NLMSG_HDRLEN) -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) -#define nlmsg_new(s, f) nlmsg_new_proper((s), (f)) -static inline struct sk_buff *nlmsg_new_proper(int size, gfp_t flags) -{ - return alloc_skb(size, flags); -} - -#endif /* linux kernel < 2.6.19 */ - - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/random.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/random.h deleted file mode 100644 index 4e4932c9..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/random.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef __LINUX_RANDOM_WRAPPER_H -#define __LINUX_RANDOM_WRAPPER_H 1 - -#include_next - -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) - -#ifdef __KERNEL__ -u32 random32(void); -void srandom32(u32 seed); -#endif /* __KERNEL__ */ - -#endif /* linux kernel < 2.6.19 */ - - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/rculist.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/rculist.h deleted file mode 100644 index 4164c0e9..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/rculist.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __LINUX_RCULIST_WRAPPER_H -#define __LINUX_RCULIST_WRAPPER_H - -#include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) -#include_next -#else -/* Prior to 2.6.26, the contents of rculist.h were part of list.h. */ -#include -#endif - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/skbuff.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/skbuff.h deleted file mode 100644 index 55d32eb1..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/skbuff.h +++ /dev/null @@ -1,137 +0,0 @@ -#ifndef __LINUX_SKBUFF_WRAPPER_H -#define __LINUX_SKBUFF_WRAPPER_H 1 - -#include_next - -#include - -#ifndef HAVE_SKB_COPY_FROM_LINEAR_DATA_OFFSET -static inline void skb_copy_from_linear_data_offset(const struct sk_buff *skb, - const int offset, void *to, - const unsigned int len) -{ - memcpy(to, skb->data + offset, len); -} - -static inline void skb_copy_to_linear_data_offset(struct sk_buff *skb, - const int offset, - const void *from, - const unsigned int len) -{ - memcpy(skb->data + offset, from, len); -} - -#endif /* !HAVE_SKB_COPY_FROM_LINEAR_DATA_OFFSET */ - - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) -static inline int __skb_cow(struct sk_buff *skb, unsigned int headroom, - int cloned) -{ - int delta = 0; - - if (headroom < NET_SKB_PAD) - headroom = NET_SKB_PAD; - if (headroom > skb_headroom(skb)) - delta = headroom - skb_headroom(skb); - - if (delta || cloned) - return pskb_expand_head(skb, ALIGN(delta, NET_SKB_PAD), 0, - GFP_ATOMIC); - return 0; -} - -static inline int skb_cow_head(struct sk_buff *skb, unsigned int headroom) -{ - return __skb_cow(skb, headroom, skb_header_cloned(skb)); -} -#endif /* linux < 2.6.23 */ - - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17) -/* Emulate Linux 2.6.17 and later behavior, in which kfree_skb silently ignores - * null pointer arguments. */ -#define kfree_skb(skb) kfree_skb_maybe_null(skb) -static inline void kfree_skb_maybe_null(struct sk_buff *skb) -{ - if (likely(skb != NULL)) - (kfree_skb)(skb); -} -#endif - - -#ifndef CHECKSUM_PARTIAL -/* Note that CHECKSUM_PARTIAL is not implemented, but this allows us to at - * least test against it: see update_csum() in forward.c. */ -#define CHECKSUM_PARTIAL 3 -#endif -#ifndef CHECKSUM_COMPLETE -#define CHECKSUM_COMPLETE CHECKSUM_HW -#endif - -#ifdef HAVE_MAC_RAW -#define mac_header mac.raw -#define network_header nh.raw -#endif - -#ifndef HAVE_SKBUFF_HEADER_HELPERS -static inline unsigned char *skb_transport_header(const struct sk_buff *skb) -{ - return skb->h.raw; -} - -static inline void skb_reset_transport_header(struct sk_buff *skb) -{ - skb->h.raw = skb->data; -} - -static inline void skb_set_transport_header(struct sk_buff *skb, - const int offset) -{ - skb->h.raw = skb->data + offset; -} - -static inline unsigned char *skb_network_header(const struct sk_buff *skb) -{ - return skb->nh.raw; -} - -static inline void skb_set_network_header(struct sk_buff *skb, const int offset) -{ - skb->nh.raw = skb->data + offset; -} - -static inline unsigned char *skb_mac_header(const struct sk_buff *skb) -{ - return skb->mac.raw; -} - -static inline void skb_reset_mac_header(struct sk_buff *skb) -{ - skb->mac_header = skb->data; -} - -static inline void skb_set_mac_header(struct sk_buff *skb, const int offset) -{ - skb->mac.raw = skb->data + offset; -} - -static inline int skb_transport_offset(const struct sk_buff *skb) -{ - return skb_transport_header(skb) - skb->data; -} - -static inline int skb_network_offset(const struct sk_buff *skb) -{ - return skb_network_header(skb) - skb->data; -} - -static inline void skb_copy_to_linear_data(struct sk_buff *skb, - const void *from, - const unsigned int len) -{ - memcpy(skb->data, from, len); -} -#endif /* !HAVE_SKBUFF_HEADER_HELPERS */ - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/tcp.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/tcp.h deleted file mode 100644 index 6fad1933..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/tcp.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef __LINUX_TCP_WRAPPER_H -#define __LINUX_TCP_WRAPPER_H 1 - -#include_next - -#ifndef HAVE_SKBUFF_HEADER_HELPERS -static inline struct tcphdr *tcp_hdr(const struct sk_buff *skb) -{ - return (struct tcphdr *)skb_transport_header(skb); -} - -static inline unsigned int tcp_hdrlen(const struct sk_buff *skb) -{ - return tcp_hdr(skb)->doff * 4; -} -#endif /* !HAVE_SKBUFF_HEADER_HELPERS */ - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/timer.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/timer.h deleted file mode 100644 index 6c3a9b0f..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/timer.h +++ /dev/null @@ -1,96 +0,0 @@ -#ifndef __LINUX_TIMER_WRAPPER_H -#define __LINUX_TIMER_WRAPPER_H 1 - -#include_next - -#include - -#ifndef RHEL_RELEASE_VERSION -#define RHEL_RELEASE_VERSION(X,Y) ( 0 ) -#endif -#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) && \ - (!defined(RHEL_RELEASE_CODE) || \ - (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(5,1)))) - -extern unsigned long volatile jiffies; - -/** - * __round_jiffies - function to round jiffies to a full second - * @j: the time in (absolute) jiffies that should be rounded - * @cpu: the processor number on which the timeout will happen - * - * __round_jiffies() rounds an absolute time in the future (in jiffies) - * up or down to (approximately) full seconds. This is useful for timers - * for which the exact time they fire does not matter too much, as long as - * they fire approximately every X seconds. - * - * By rounding these timers to whole seconds, all such timers will fire - * at the same time, rather than at various times spread out. The goal - * of this is to have the CPU wake up less, which saves power. - * - * The exact rounding is skewed for each processor to avoid all - * processors firing at the exact same time, which could lead - * to lock contention or spurious cache line bouncing. - * - * The return value is the rounded version of the @j parameter. - */ -static inline unsigned long __round_jiffies(unsigned long j, int cpu) -{ - int rem; - unsigned long original = j; - - /* - * We don't want all cpus firing their timers at once hitting the - * same lock or cachelines, so we skew each extra cpu with an extra - * 3 jiffies. This 3 jiffies came originally from the mm/ code which - * already did this. - * The skew is done by adding 3*cpunr, then round, then subtract this - * extra offset again. - */ - j += cpu * 3; - - rem = j % HZ; - - /* - * If the target jiffie is just after a whole second (which can happen - * due to delays of the timer irq, long irq off times etc etc) then - * we should round down to the whole second, not up. Use 1/4th second - * as cutoff for this rounding as an extreme upper bound for this. - */ - if (rem < HZ/4) /* round down */ - j = j - rem; - else /* round up */ - j = j - rem + HZ; - - /* now that we have rounded, subtract the extra skew again */ - j -= cpu * 3; - - if (j <= jiffies) /* rounding ate our timeout entirely; */ - return original; - return j; -} - - -/** - * round_jiffies - function to round jiffies to a full second - * @j: the time in (absolute) jiffies that should be rounded - * - * round_jiffies() rounds an absolute time in the future (in jiffies) - * up or down to (approximately) full seconds. This is useful for timers - * for which the exact time they fire does not matter too much, as long as - * they fire approximately every X seconds. - * - * By rounding these timers to whole seconds, all such timers will fire - * at the same time, rather than at various times spread out. The goal - * of this is to have the CPU wake up less, which saves power. - * - * The return value is the rounded version of the @j parameter. - */ -static inline unsigned long round_jiffies(unsigned long j) -{ - return __round_jiffies(j, 0); // FIXME -} - -#endif /* linux kernel < 2.6.20 */ - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/types.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/types.h deleted file mode 100644 index c1f375eb..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/types.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef __LINUX_TYPES_WRAPPER_H -#define __LINUX_TYPES_WRAPPER_H 1 - -#include_next - -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) - -typedef __u16 __bitwise __sum16; -typedef __u32 __bitwise __wsum; - -#endif /* linux kernel < 2.6.20 */ - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/udp.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/udp.h deleted file mode 100644 index 6fe4721b..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/udp.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef __LINUX_UDP_WRAPPER_H -#define __LINUX_UDP_WRAPPER_H 1 - -#include_next - -#ifndef HAVE_SKBUFF_HEADER_HELPERS -static inline struct udphdr *udp_hdr(const struct sk_buff *skb) -{ - return (struct udphdr *)skb_transport_header(skb); -} -#endif /* HAVE_SKBUFF_HEADER_HELPERS */ - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/linux/workqueue.h b/openflow/datapath/linux-2.6/compat-2.6/include/linux/workqueue.h deleted file mode 100644 index 1ac3b6ec..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/linux/workqueue.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef __LINUX_WORKQUEUE_WRAPPER_H -#define __LINUX_WORKQUEUE_WRAPPER_H 1 - -#include_next - -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) - -#ifdef __KERNEL__ -/* - * initialize a work-struct's func and data pointers: - */ -#undef PREPARE_WORK -#define PREPARE_WORK(_work, _func) \ - do { \ - (_work)->func = (void(*)(void*)) _func; \ - (_work)->data = _work; \ - } while (0) - -/* - * initialize all of a work-struct: - */ -#undef INIT_WORK -#define INIT_WORK(_work, _func) \ - do { \ - INIT_LIST_HEAD(&(_work)->entry); \ - (_work)->pending = 0; \ - PREPARE_WORK((_work), (_func)); \ - init_timer(&(_work)->timer); \ - } while (0) - -#endif /* __KERNEL__ */ - -#endif /* linux kernel < 2.6.20 */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) -/* There is no equivalent to cancel_work_sync() so just flush all - * pending work. */ -#define cancel_work_sync(_work) flush_scheduled_work() -#endif - -#endif diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/net/checksum.h b/openflow/datapath/linux-2.6/compat-2.6/include/net/checksum.h deleted file mode 100644 index c64c6bd0..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/net/checksum.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef __NET_CHECKSUM_WRAPPER_H -#define __NET_CHECKSUM_WRAPPER_H 1 - -#include_next - -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) - -static inline __wsum csum_unfold(__sum16 n) -{ - return (__force __wsum)n; -} - -#endif /* linux kernel < 2.6.20 */ - -#endif /* checksum.h */ diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/net/genetlink.h b/openflow/datapath/linux-2.6/compat-2.6/include/net/genetlink.h deleted file mode 100644 index 57a47316..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/net/genetlink.h +++ /dev/null @@ -1,123 +0,0 @@ -#ifndef __NET_GENERIC_NETLINK_WRAPPER_H -#define __NET_GENERIC_NETLINK_WRAPPER_H 1 - - -#include -#include_next - -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) - -#include - -/*---------------------------------------------------------------------------- - * In 2.6.23, registering of multicast groups was added. Our compatability - * layer just supports registering a single group, since that's all we - * need. - */ - -/** - * struct genl_multicast_group - generic netlink multicast group - * @name: name of the multicast group, names are per-family - * @id: multicast group ID, assigned by the core, to use with - * genlmsg_multicast(). - * @list: list entry for linking - * @family: pointer to family, need not be set before registering - */ -struct genl_multicast_group -{ - struct genl_family *family; /* private */ - struct list_head list; /* private */ - char name[GENL_NAMSIZ]; - u32 id; -}; - -int genl_register_mc_group(struct genl_family *family, - struct genl_multicast_group *grp); -#endif /* linux kernel < 2.6.23 */ - - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) -/** - * genlmsg_msg_size - length of genetlink message not including padding - * @payload: length of message payload - */ -static inline int genlmsg_msg_size(int payload) -{ - return GENL_HDRLEN + payload; -} - -/** - * genlmsg_total_size - length of genetlink message including padding - * @payload: length of message payload - */ -static inline int genlmsg_total_size(int payload) -{ - return NLMSG_ALIGN(genlmsg_msg_size(payload)); -} - -#define genlmsg_multicast(s, p, g, f) \ - genlmsg_multicast_flags((s), (p), (g), (f)) - -static inline int genlmsg_multicast_flags(struct sk_buff *skb, u32 pid, - unsigned int group, gfp_t flags) -{ - int err; - - NETLINK_CB(skb).dst_group = group; - - err = netlink_broadcast(genl_sock, skb, pid, group, flags); - if (err > 0) - err = 0; - - return err; -} -#endif /* linux kernel < 2.6.19 */ - - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) - -#define genlmsg_put(skb, p, seq, fam, flg, c) \ - genlmsg_put((skb), (p), (seq), (fam)->id, (fam)->hdrsize, \ - (flg), (c), (fam)->version) - -/** - * genlmsg_put_reply - Add generic netlink header to a reply message - * @skb: socket buffer holding the message - * @info: receiver info - * @family: generic netlink family - * @flags: netlink message flags - * @cmd: generic netlink command - * - * Returns pointer to user specific header - */ -static inline void *genlmsg_put_reply(struct sk_buff *skb, - struct genl_info *info, struct genl_family *family, - int flags, u8 cmd) -{ - return genlmsg_put(skb, info->snd_pid, info->snd_seq, family, - flags, cmd); -} - -/** - * genlmsg_reply - reply to a request - * @skb: netlink message to be sent back - * @info: receiver information - */ -static inline int genlmsg_reply(struct sk_buff *skb, struct genl_info *info) -{ - return genlmsg_unicast(skb, info->snd_pid); -} - -/** - * genlmsg_new - Allocate a new generic netlink message - * @payload: size of the message payload - * @flags: the type of memory to allocate. - */ -static inline struct sk_buff *genlmsg_new(size_t payload, gfp_t flags) -{ - return nlmsg_new(genlmsg_total_size(payload), flags); -} -#endif /* linux kernel < 2.6.20 */ - -#endif /* genetlink.h */ diff --git a/openflow/datapath/linux-2.6/compat-2.6/include/net/netlink.h b/openflow/datapath/linux-2.6/compat-2.6/include/net/netlink.h deleted file mode 100644 index e0d594d7..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/include/net/netlink.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef __NET_NETLINK_WRAPPER_H -#define __NET_NETLINK_WRAPPER_H 1 - -#include_next - -#ifndef HAVE_NLA_NUL_STRING -#define NLA_NUL_STRING NLA_STRING - -static inline int VERIFY_NUL_STRING(struct nlattr *attr) -{ - return (!attr || (nla_len(attr) - && memchr(nla_data(attr), '\0', nla_len(attr))) - ? 0 : EINVAL); -} -#else -static inline int VERIFY_NUL_STRING(struct nlattr *attr) -{ - return 0; -} -#endif /* !HAVE_NLA_NUL_STRING */ - -#endif /* net/netlink.h */ diff --git a/openflow/datapath/linux-2.6/compat-2.6/random32.c b/openflow/datapath/linux-2.6/compat-2.6/random32.c deleted file mode 100644 index 981b55c1..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/random32.c +++ /dev/null @@ -1,146 +0,0 @@ -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) - -/* - This is a maximally equidistributed combined Tausworthe generator - based on code from GNU Scientific Library 1.5 (30 Jun 2004) - - x_n = (s1_n ^ s2_n ^ s3_n) - - s1_{n+1} = (((s1_n & 4294967294) <<12) ^ (((s1_n <<13) ^ s1_n) >>19)) - s2_{n+1} = (((s2_n & 4294967288) << 4) ^ (((s2_n << 2) ^ s2_n) >>25)) - s3_{n+1} = (((s3_n & 4294967280) <<17) ^ (((s3_n << 3) ^ s3_n) >>11)) - - The period of this generator is about 2^88. - - From: P. L'Ecuyer, "Maximally Equidistributed Combined Tausworthe - Generators", Mathematics of Computation, 65, 213 (1996), 203--213. - - This is available on the net from L'Ecuyer's home page, - - http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme.ps - ftp://ftp.iro.umontreal.ca/pub/simulation/lecuyer/papers/tausme.ps - - There is an erratum in the paper "Tables of Maximally - Equidistributed Combined LFSR Generators", Mathematics of - Computation, 68, 225 (1999), 261--269: - http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme2.ps - - ... the k_j most significant bits of z_j must be non- - zero, for each j. (Note: this restriction also applies to the - computer code given in [4], but was mistakenly not mentioned in - that paper.) - - This affects the seeding procedure by imposing the requirement - s1 > 1, s2 > 7, s3 > 15. - -*/ - -#include -#include -#include -#include -#include - -#include "compat26.h" - -struct rnd_state { - u32 s1, s2, s3; -}; - -static struct rnd_state net_rand_state[NR_CPUS]; - -static u32 __random32(struct rnd_state *state) -{ -#define TAUSWORTHE(s,a,b,c,d) ((s&c)<>b) - - state->s1 = TAUSWORTHE(state->s1, 13, 19, 4294967294UL, 12); - state->s2 = TAUSWORTHE(state->s2, 2, 25, 4294967288UL, 4); - state->s3 = TAUSWORTHE(state->s3, 3, 11, 4294967280UL, 17); - - return (state->s1 ^ state->s2 ^ state->s3); -} - -static void __set_random32(struct rnd_state *state, unsigned long s) -{ - if (s == 0) - s = 1; /* default seed is 1 */ - -#define LCG(n) (69069 * n) - state->s1 = LCG(s); - state->s2 = LCG(state->s1); - state->s3 = LCG(state->s2); - - /* "warm it up" */ - __random32(state); - __random32(state); - __random32(state); - __random32(state); - __random32(state); - __random32(state); -} - -/** - * random32 - pseudo random number generator - * - * A 32 bit pseudo-random number is generated using a fast - * algorithm suitable for simulation. This algorithm is NOT - * considered safe for cryptographic use. - */ -u32 random32(void) -{ - return __random32(&net_rand_state[smp_processor_id()]); -} -EXPORT_SYMBOL(random32); - -/** - * srandom32 - add entropy to pseudo random number generator - * @seed: seed value - * - * Add some additional seeding to the random32() pool. - * Note: this pool is per cpu so it only affects current CPU. - */ -void srandom32(u32 entropy) -{ - struct rnd_state *state = &net_rand_state[smp_processor_id()]; - __set_random32(state, state->s1 ^ entropy); -} -EXPORT_SYMBOL(srandom32); - -static int __init random32_reseed(void); - -/* - * Generate some initially weak seeding values to allow - * to start the random32() engine. - */ -int __init random32_init(void) -{ - int i; - - for (i = 0; i < NR_CPUS; i++) { - struct rnd_state *state = &net_rand_state[i]; - __set_random32(state, i + jiffies); - } - random32_reseed(); - return 0; -} - -/* - * Generate better values after random number generator - * is fully initalized. - */ -static int __init random32_reseed(void) -{ - int i; - unsigned long seed; - - for (i = 0; i < NR_CPUS; i++) { - struct rnd_state *state = &net_rand_state[i]; - - get_random_bytes(&seed, sizeof(seed)); - __set_random32(state, seed); - } - return 0; -} - -#endif /* kernel < 2.6.19 */ diff --git a/openflow/datapath/linux-2.6/compat-2.6/veth.c b/openflow/datapath/linux-2.6/compat-2.6/veth.c deleted file mode 100644 index 3cda3365..00000000 --- a/openflow/datapath/linux-2.6/compat-2.6/veth.c +++ /dev/null @@ -1,537 +0,0 @@ -/* veth driver port to Linux 2.6.18 */ - -/* - * drivers/net/veth.c - * - * Copyright (C) 2007, 2009 OpenVZ http://openvz.org, SWsoft Inc - * - * Author: Pavel Emelianov - * Ethtool interface from: Eric W. Biederman - * - */ - -#include -#include -#include -#include - -#include -#include - -#define DRV_NAME "veth" -#define DRV_VERSION "1.0" - -struct veth_net_stats { - unsigned long rx_packets; - unsigned long tx_packets; - unsigned long rx_bytes; - unsigned long tx_bytes; - unsigned long tx_dropped; -}; - -struct veth_priv { - struct net_device *peer; - struct net_device *dev; - struct list_head list; - struct veth_net_stats *stats; - unsigned ip_summed; - struct net_device_stats dev_stats; -}; - -static LIST_HEAD(veth_list); - -/* - * ethtool interface - */ - -static struct { - const char string[ETH_GSTRING_LEN]; -} ethtool_stats_keys[] = { - { "peer_ifindex" }, -}; - -static int veth_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - cmd->supported = 0; - cmd->advertising = 0; - cmd->speed = SPEED_10000; - cmd->duplex = DUPLEX_FULL; - cmd->port = PORT_TP; - cmd->phy_address = 0; - cmd->transceiver = XCVR_INTERNAL; - cmd->autoneg = AUTONEG_DISABLE; - cmd->maxtxpkt = 0; - cmd->maxrxpkt = 0; - return 0; -} - -static void veth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) -{ - strcpy(info->driver, DRV_NAME); - strcpy(info->version, DRV_VERSION); - strcpy(info->fw_version, "N/A"); -} - -static void veth_get_strings(struct net_device *dev, u32 stringset, u8 *buf) -{ - switch(stringset) { - case ETH_SS_STATS: - memcpy(buf, ðtool_stats_keys, sizeof(ethtool_stats_keys)); - break; - } -} - -static void veth_get_ethtool_stats(struct net_device *dev, - struct ethtool_stats *stats, u64 *data) -{ - struct veth_priv *priv; - - priv = netdev_priv(dev); - data[0] = priv->peer->ifindex; -} - -static u32 veth_get_rx_csum(struct net_device *dev) -{ - struct veth_priv *priv; - - priv = netdev_priv(dev); - return priv->ip_summed == CHECKSUM_UNNECESSARY; -} - -static int veth_set_rx_csum(struct net_device *dev, u32 data) -{ - struct veth_priv *priv; - - priv = netdev_priv(dev); - priv->ip_summed = data ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE; - return 0; -} - -static u32 veth_get_tx_csum(struct net_device *dev) -{ - return (dev->features & NETIF_F_NO_CSUM) != 0; -} - -static int veth_set_tx_csum(struct net_device *dev, u32 data) -{ - if (data) - dev->features |= NETIF_F_NO_CSUM; - else - dev->features &= ~NETIF_F_NO_CSUM; - return 0; -} - -static struct ethtool_ops veth_ethtool_ops = { - .get_settings = veth_get_settings, - .get_drvinfo = veth_get_drvinfo, - .get_link = ethtool_op_get_link, - .get_rx_csum = veth_get_rx_csum, - .set_rx_csum = veth_set_rx_csum, - .get_tx_csum = veth_get_tx_csum, - .set_tx_csum = veth_set_tx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_strings = veth_get_strings, - .get_ethtool_stats = veth_get_ethtool_stats, -}; - -/* - * xmit - */ - -static int veth_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct net_device *rcv = NULL; - struct veth_priv *priv, *rcv_priv; - struct veth_net_stats *stats; - int length, cpu; - - skb_orphan(skb); - - priv = netdev_priv(dev); - rcv = priv->peer; - rcv_priv = netdev_priv(rcv); - - cpu = smp_processor_id(); - stats = per_cpu_ptr(priv->stats, cpu); - - if (!(rcv->flags & IFF_UP)) - goto outf; - - skb->dev = rcv; - skb->pkt_type = PACKET_HOST; - skb->protocol = eth_type_trans(skb, rcv); - if (dev->features & NETIF_F_NO_CSUM) - skb->ip_summed = rcv_priv->ip_summed; - - dst_release(skb->dst); - skb->dst = NULL; - secpath_reset(skb); - nf_reset(skb); - - length = skb->len; - - stats->tx_bytes += length; - stats->tx_packets++; - - stats = per_cpu_ptr(rcv_priv->stats, cpu); - stats->rx_bytes += length; - stats->rx_packets++; - - netif_rx(skb); - return 0; - -outf: - kfree_skb(skb); - stats->tx_dropped++; - return 0; -} - -/* - * general routines - */ - -static struct net_device_stats *veth_get_stats(struct net_device *dev) -{ - struct veth_priv *priv; - struct net_device_stats *dev_stats; - int cpu; - struct veth_net_stats *stats; - - priv = netdev_priv(dev); - dev_stats = &priv->dev_stats; - - dev_stats->rx_packets = 0; - dev_stats->tx_packets = 0; - dev_stats->rx_bytes = 0; - dev_stats->tx_bytes = 0; - dev_stats->tx_dropped = 0; - - for_each_online_cpu(cpu) { - stats = per_cpu_ptr(priv->stats, cpu); - - dev_stats->rx_packets += stats->rx_packets; - dev_stats->tx_packets += stats->tx_packets; - dev_stats->rx_bytes += stats->rx_bytes; - dev_stats->tx_bytes += stats->tx_bytes; - dev_stats->tx_dropped += stats->tx_dropped; - } - - return dev_stats; -} - -static int veth_open(struct net_device *dev) -{ - struct veth_priv *priv; - - priv = netdev_priv(dev); - if (priv->peer == NULL) - return -ENOTCONN; - - if (priv->peer->flags & IFF_UP) { - netif_carrier_on(dev); - netif_carrier_on(priv->peer); - } - return 0; -} - -static int veth_dev_init(struct net_device *dev) -{ - struct veth_net_stats *stats; - struct veth_priv *priv; - - stats = alloc_percpu(struct veth_net_stats); - if (stats == NULL) - return -ENOMEM; - - priv = netdev_priv(dev); - priv->stats = stats; - return 0; -} - -static void veth_dev_free(struct net_device *dev) -{ - struct veth_priv *priv; - - priv = netdev_priv(dev); - free_percpu(priv->stats); - free_netdev(dev); -} - -static void veth_setup(struct net_device *dev) -{ - ether_setup(dev); - - dev->hard_start_xmit = veth_xmit; - dev->get_stats = veth_get_stats; - dev->open = veth_open; - dev->ethtool_ops = &veth_ethtool_ops; - dev->features |= NETIF_F_LLTX; - dev->init = veth_dev_init; - dev->destructor = veth_dev_free; -} - -static void veth_change_state(struct net_device *dev) -{ - struct net_device *peer; - struct veth_priv *priv; - - priv = netdev_priv(dev); - peer = priv->peer; - - if (netif_carrier_ok(peer)) { - if (!netif_carrier_ok(dev)) - netif_carrier_on(dev); - } else { - if (netif_carrier_ok(dev)) - netif_carrier_off(dev); - } -} - -static int veth_device_event(struct notifier_block *unused, - unsigned long event, void *ptr) -{ - struct net_device *dev = ptr; - - if (dev->open != veth_open) - goto out; - - switch (event) { - case NETDEV_CHANGE: - veth_change_state(dev); - break; - } -out: - return NOTIFY_DONE; -} - -static struct notifier_block veth_notifier_block __read_mostly = { - .notifier_call = veth_device_event, -}; - -/* - * netlink interface - */ - -static int veth_newlink(const char *devname, const char *peername) -{ - int err; - const char *names[2]; - struct net_device *devs[2]; - int i; - - names[0] = devname; - names[1] = peername; - devs[0] = devs[1] = NULL; - - for (i = 0; i < 2; i++) { - struct net_device *dev; - - err = -ENOMEM; - devs[i] = alloc_netdev(sizeof(struct veth_priv), - names[i], veth_setup); - if (!devs[i]) { - goto err; - } - - dev = devs[i]; - - if (strchr(dev->name, '%')) { - err = dev_alloc_name(dev, dev->name); - if (err < 0) - goto err; - } - random_ether_addr(dev->dev_addr); - - err = register_netdevice(dev); - if (err < 0) - goto err; - - netif_carrier_off(dev); - } - - /* - * tie the devices together - */ - - for (i = 0; i < 2; i++) { - struct veth_priv *priv = netdev_priv(devs[i]); - priv->dev = devs[i]; - priv->peer = devs[!i]; - if (!i) - list_add(&priv->list, &veth_list); - else - INIT_LIST_HEAD(&priv->list); - } - return 0; - -err: - for (i = 0; i < 2; i++) { - if (devs[i]) { - if (devs[i]->reg_state != NETREG_UNINITIALIZED) - unregister_netdevice(devs[i]); - else - free_netdev(devs[i]); - } - } - return err; -} - -static void veth_dellink(struct net_device *dev) -{ - struct veth_priv *priv; - struct net_device *peer; - - priv = netdev_priv(dev); - peer = priv->peer; - - if (!list_empty(&priv->list)) - list_del(&priv->list); - - priv = netdev_priv(peer); - if (!list_empty(&priv->list)) - list_del(&priv->list); - - unregister_netdevice(dev); - unregister_netdevice(peer); -} - -/* - * sysfs - */ - -/* - * "show" function for the veth_pairs attribute. - * The class parameter is ignored. - */ -static ssize_t veth_show_veth_pairs(struct class *cls, char *buffer) -{ - int res = 0; - struct veth_priv *priv; - - list_for_each_entry(priv, &veth_list, list) { - if (res > (PAGE_SIZE - (IFNAMSIZ * 2 + 1))) { - /* not enough space for another interface name */ - if ((PAGE_SIZE - res) > 10) - res = PAGE_SIZE - 10; - res += sprintf(buffer + res, "++more++"); - break; - } - res += sprintf(buffer + res, "%s,%s ", - priv->dev->name, priv->peer->name); - } - res += sprintf(buffer + res, "\n"); - res++; - return res; -} - -/* - * "store" function for the veth_pairs attribute. This is what - * creates and deletes veth pairs. - * - * The class parameter is ignored. - * - */ -static ssize_t veth_store_veth_pairs(struct class *cls, const char *buffer, - size_t count) -{ - int c = *buffer++; - int retval; - printk("1\n"); - if (c == '+') { - char devname[IFNAMSIZ + 1] = ""; - char peername[IFNAMSIZ + 1] = ""; - char *comma = strchr(buffer, ','); - printk("2\n"); - if (!comma) - goto err_no_cmd; - strncat(devname, buffer, - min_t(int, sizeof devname, comma - buffer)); - strncat(peername, comma + 1, - min_t(int, sizeof peername, strcspn(comma + 1, "\n"))); - printk("3 '%s' '%s'\n", devname, peername); - if (!dev_valid_name(devname) || !dev_valid_name(peername)) - goto err_no_cmd; - printk("4\n"); - rtnl_lock(); - retval = veth_newlink(devname, peername); - rtnl_unlock(); - return retval ? retval : count; - } else if (c == '-') { - struct net_device *dev; - - rtnl_lock(); - dev = dev_get_by_name(buffer); - if (!dev) - retval = -ENODEV; - else if (dev->init != veth_dev_init) - retval = -EINVAL; - else { - veth_dellink(dev); - retval = count; - } - rtnl_unlock(); - - return retval; - } - -err_no_cmd: - printk(KERN_ERR DRV_NAME ": no command found in veth_pairs. Use +ifname,peername or -ifname.\n"); - return -EPERM; -} - -/* class attribute for veth_pairs file. This ends up in /sys/class/net */ -static CLASS_ATTR(veth_pairs, S_IWUSR | S_IRUGO, - veth_show_veth_pairs, veth_store_veth_pairs); - -static struct class *netdev_class; - -/* - * Initialize sysfs. This sets up the veth_pairs file in - * /sys/class/net. - */ -int veth_create_sysfs(void) -{ - struct net_device *dev = dev_get_by_name("lo"); - if (!dev) - return -ESRCH; - netdev_class = dev->class_dev.class; - if (!netdev_class) - return -ENODEV; - - return class_create_file(netdev_class, &class_attr_veth_pairs); -} - -/* - * Remove /sys/class/net/veth_pairs. - */ -void veth_destroy_sysfs(void) -{ - class_remove_file(netdev_class, &class_attr_veth_pairs); -} - - - -/* - * init/fini - */ - -static __init int veth_init(void) -{ - int retval = veth_create_sysfs(); - if (retval) - return retval; - register_netdevice_notifier(&veth_notifier_block); - return 0; -} - -static __exit void veth_exit(void) -{ - unregister_netdevice_notifier(&veth_notifier_block); -} - -module_init(veth_init); -module_exit(veth_exit); - -MODULE_DESCRIPTION("Virtual Ethernet Tunnel"); -MODULE_LICENSE("GPL v2"); diff --git a/openflow/datapath/linux-2.6/config/config-linux-2.6.23-rc9-kvm b/openflow/datapath/linux-2.6/config/config-linux-2.6.23-rc9-kvm deleted file mode 100644 index f287cf72..00000000 --- a/openflow/datapath/linux-2.6/config/config-linux-2.6.23-rc9-kvm +++ /dev/null @@ -1,1408 +0,0 @@ -# -# Automatically generated make config: don't edit -# Linux kernel version: 2.6.23-rc9 -# Fri Oct 19 15:08:37 2007 -# -CONFIG_X86_32=y -CONFIG_GENERIC_TIME=y -CONFIG_GENERIC_CMOS_UPDATE=y -CONFIG_CLOCKSOURCE_WATCHDOG=y -CONFIG_GENERIC_CLOCKEVENTS=y -CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y -CONFIG_LOCKDEP_SUPPORT=y -CONFIG_STACKTRACE_SUPPORT=y -CONFIG_SEMAPHORE_SLEEPERS=y -CONFIG_X86=y -CONFIG_MMU=y -CONFIG_ZONE_DMA=y -CONFIG_QUICKLIST=y -CONFIG_GENERIC_ISA_DMA=y -CONFIG_GENERIC_IOMAP=y -CONFIG_GENERIC_BUG=y -CONFIG_GENERIC_HWEIGHT=y -CONFIG_ARCH_MAY_HAVE_PC_FDC=y -CONFIG_DMI=y -CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" - -# -# General setup -# -CONFIG_EXPERIMENTAL=y -CONFIG_LOCK_KERNEL=y -CONFIG_INIT_ENV_ARG_LIMIT=32 -CONFIG_LOCALVERSION="" -# CONFIG_LOCALVERSION_AUTO is not set -CONFIG_SWAP=y -CONFIG_SYSVIPC=y -CONFIG_SYSVIPC_SYSCTL=y -CONFIG_POSIX_MQUEUE=y -CONFIG_BSD_PROCESS_ACCT=y -# CONFIG_BSD_PROCESS_ACCT_V3 is not set -CONFIG_TASKSTATS=y -CONFIG_TASK_DELAY_ACCT=y -CONFIG_TASK_XACCT=y -CONFIG_TASK_IO_ACCOUNTING=y -# CONFIG_USER_NS is not set -# CONFIG_AUDIT is not set -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -CONFIG_LOG_BUF_SHIFT=14 -# CONFIG_CPUSETS is not set -CONFIG_SYSFS_DEPRECATED=y -CONFIG_RELAY=y -CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="" -CONFIG_CC_OPTIMIZE_FOR_SIZE=y -CONFIG_SYSCTL=y -# CONFIG_EMBEDDED is not set -CONFIG_UID16=y -CONFIG_SYSCTL_SYSCALL=y -CONFIG_KALLSYMS=y -CONFIG_KALLSYMS_ALL=y -CONFIG_KALLSYMS_EXTRA_PASS=y -CONFIG_HOTPLUG=y -CONFIG_PRINTK=y -CONFIG_BUG=y -CONFIG_ELF_CORE=y -CONFIG_BASE_FULL=y -CONFIG_FUTEX=y -CONFIG_ANON_INODES=y -CONFIG_EPOLL=y -CONFIG_SIGNALFD=y -CONFIG_EVENTFD=y -CONFIG_SHMEM=y -CONFIG_VM_EVENT_COUNTERS=y -CONFIG_SLAB=y -# CONFIG_SLUB is not set -# CONFIG_SLOB is not set -CONFIG_RT_MUTEXES=y -# CONFIG_TINY_SHMEM is not set -CONFIG_BASE_SMALL=0 -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_MODULE_FORCE_UNLOAD is not set -# CONFIG_MODVERSIONS is not set -# CONFIG_MODULE_SRCVERSION_ALL is not set -CONFIG_KMOD=y -CONFIG_STOP_MACHINE=y -CONFIG_BLOCK=y -CONFIG_LBD=y -CONFIG_BLK_DEV_IO_TRACE=y -CONFIG_LSF=y -# CONFIG_BLK_DEV_BSG is not set - -# -# IO Schedulers -# -CONFIG_IOSCHED_NOOP=y -CONFIG_IOSCHED_AS=y -CONFIG_IOSCHED_DEADLINE=y -CONFIG_IOSCHED_CFQ=y -CONFIG_DEFAULT_AS=y -# CONFIG_DEFAULT_DEADLINE is not set -# CONFIG_DEFAULT_CFQ is not set -# CONFIG_DEFAULT_NOOP is not set -CONFIG_DEFAULT_IOSCHED="anticipatory" - -# -# Processor type and features -# -# CONFIG_TICK_ONESHOT is not set -# CONFIG_NO_HZ is not set -# CONFIG_HIGH_RES_TIMERS is not set -CONFIG_SMP=y -CONFIG_X86_PC=y -# CONFIG_X86_ELAN is not set -# CONFIG_X86_VOYAGER is not set -# CONFIG_X86_NUMAQ is not set -# CONFIG_X86_SUMMIT is not set -# CONFIG_X86_BIGSMP is not set -# CONFIG_X86_VISWS is not set -# CONFIG_X86_GENERICARCH is not set -# CONFIG_X86_ES7000 is not set -# CONFIG_PARAVIRT is not set -# CONFIG_M386 is not set -CONFIG_M486=y -# CONFIG_M586 is not set -# CONFIG_M586TSC is not set -# CONFIG_M586MMX is not set -# CONFIG_M686 is not set -# CONFIG_MPENTIUMII is not set -# CONFIG_MPENTIUMIII is not set -# CONFIG_MPENTIUMM is not set -# CONFIG_MCORE2 is not set -# CONFIG_MPENTIUM4 is not set -# CONFIG_MK6 is not set -# CONFIG_MK7 is not set -# CONFIG_MK8 is not set -# CONFIG_MCRUSOE is not set -# CONFIG_MEFFICEON is not set -# CONFIG_MWINCHIPC6 is not set -# CONFIG_MWINCHIP2 is not set -# CONFIG_MWINCHIP3D is not set -# CONFIG_MGEODEGX1 is not set -# CONFIG_MGEODE_LX is not set -# CONFIG_MCYRIXIII is not set -# CONFIG_MVIAC3_2 is not set -# CONFIG_MVIAC7 is not set -CONFIG_X86_GENERIC=y -CONFIG_X86_CMPXCHG=y -CONFIG_X86_L1_CACHE_SHIFT=7 -CONFIG_X86_XADD=y -CONFIG_RWSEM_XCHGADD_ALGORITHM=y -# CONFIG_ARCH_HAS_ILOG2_U32 is not set -# CONFIG_ARCH_HAS_ILOG2_U64 is not set -CONFIG_GENERIC_CALIBRATE_DELAY=y -CONFIG_X86_PPRO_FENCE=y -CONFIG_X86_F00F_BUG=y -CONFIG_X86_WP_WORKS_OK=y -CONFIG_X86_INVLPG=y -CONFIG_X86_BSWAP=y -CONFIG_X86_POPAD_OK=y -CONFIG_X86_ALIGNMENT_16=y -CONFIG_X86_INTEL_USERCOPY=y -CONFIG_X86_MINIMUM_CPU_FAMILY=4 -# CONFIG_HPET_TIMER is not set -CONFIG_NR_CPUS=8 -# CONFIG_SCHED_SMT is not set -CONFIG_SCHED_MC=y -CONFIG_PREEMPT_NONE=y -# CONFIG_PREEMPT_VOLUNTARY is not set -# CONFIG_PREEMPT is not set -CONFIG_PREEMPT_BKL=y -CONFIG_X86_LOCAL_APIC=y -CONFIG_X86_IO_APIC=y -# CONFIG_X86_MCE is not set -CONFIG_VM86=y -# CONFIG_TOSHIBA is not set -# CONFIG_I8K is not set -# CONFIG_X86_REBOOTFIXUPS is not set -# CONFIG_MICROCODE is not set -# CONFIG_X86_MSR is not set -# CONFIG_X86_CPUID is not set - -# -# Firmware Drivers -# -# CONFIG_EDD is not set -# CONFIG_DELL_RBU is not set -# CONFIG_DCDBAS is not set -CONFIG_DMIID=y -# CONFIG_NOHIGHMEM is not set -CONFIG_HIGHMEM4G=y -# CONFIG_HIGHMEM64G is not set -CONFIG_PAGE_OFFSET=0xC0000000 -CONFIG_HIGHMEM=y -CONFIG_ARCH_FLATMEM_ENABLE=y -CONFIG_ARCH_SPARSEMEM_ENABLE=y -CONFIG_ARCH_SELECT_MEMORY_MODEL=y -CONFIG_ARCH_POPULATES_NODE_MAP=y -CONFIG_SELECT_MEMORY_MODEL=y -CONFIG_FLATMEM_MANUAL=y -# CONFIG_DISCONTIGMEM_MANUAL is not set -# CONFIG_SPARSEMEM_MANUAL is not set -CONFIG_FLATMEM=y -CONFIG_FLAT_NODE_MEM_MAP=y -CONFIG_SPARSEMEM_STATIC=y -CONFIG_SPLIT_PTLOCK_CPUS=4 -# CONFIG_RESOURCES_64BIT is not set -CONFIG_ZONE_DMA_FLAG=1 -CONFIG_BOUNCE=y -CONFIG_NR_QUICK=1 -CONFIG_VIRT_TO_BUS=y -# CONFIG_HIGHPTE is not set -# CONFIG_MATH_EMULATION is not set -# CONFIG_MTRR is not set -CONFIG_IRQBALANCE=y -CONFIG_SECCOMP=y -# CONFIG_HZ_100 is not set -CONFIG_HZ_250=y -# CONFIG_HZ_300 is not set -# CONFIG_HZ_1000 is not set -CONFIG_HZ=250 -# CONFIG_KEXEC is not set -# CONFIG_CRASH_DUMP is not set -CONFIG_PHYSICAL_START=0x100000 -# CONFIG_RELOCATABLE is not set -CONFIG_PHYSICAL_ALIGN=0x100000 -CONFIG_HOTPLUG_CPU=y -CONFIG_COMPAT_VDSO=y -CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y - -# -# Power management options (ACPI, APM) -# -CONFIG_PM=y -# CONFIG_PM_LEGACY is not set -# CONFIG_PM_DEBUG is not set -CONFIG_PM_SLEEP_SMP=y -CONFIG_PM_SLEEP=y -CONFIG_SUSPEND_SMP_POSSIBLE=y -CONFIG_SUSPEND=y -CONFIG_HIBERNATION_SMP_POSSIBLE=y -# CONFIG_HIBERNATION is not set -# CONFIG_ACPI is not set -CONFIG_APM=y -# CONFIG_APM_IGNORE_USER_SUSPEND is not set -# CONFIG_APM_DO_ENABLE is not set -# CONFIG_APM_CPU_IDLE is not set -# CONFIG_APM_DISPLAY_BLANK is not set -# CONFIG_APM_ALLOW_INTS is not set -# CONFIG_APM_REAL_MODE_POWER_OFF is not set - -# -# CPU Frequency scaling -# -# CONFIG_CPU_FREQ is not set - -# -# Bus options (PCI, PCMCIA, EISA, MCA, ISA) -# -CONFIG_PCI=y -# CONFIG_PCI_GOBIOS is not set -# CONFIG_PCI_GOMMCONFIG is not set -# CONFIG_PCI_GODIRECT is not set -CONFIG_PCI_GOANY=y -CONFIG_PCI_BIOS=y -CONFIG_PCI_DIRECT=y -# CONFIG_PCIEPORTBUS is not set -CONFIG_ARCH_SUPPORTS_MSI=y -# CONFIG_PCI_MSI is not set -# CONFIG_PCI_DEBUG is not set -CONFIG_HT_IRQ=y -CONFIG_ISA_DMA_API=y -CONFIG_ISA=y -# CONFIG_EISA is not set -# CONFIG_MCA is not set -# CONFIG_SCx200 is not set - -# -# PCCARD (PCMCIA/CardBus) support -# -# CONFIG_PCCARD is not set -# CONFIG_HOTPLUG_PCI is not set - -# -# Executable file formats -# -CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_AOUT is not set -CONFIG_BINFMT_MISC=m - -# -# Networking -# -CONFIG_NET=y - -# -# Networking options -# -CONFIG_PACKET=y -CONFIG_PACKET_MMAP=y -CONFIG_UNIX=y -CONFIG_XFRM=y -CONFIG_XFRM_USER=m -CONFIG_XFRM_SUB_POLICY=y -CONFIG_XFRM_MIGRATE=y -CONFIG_NET_KEY=m -CONFIG_NET_KEY_MIGRATE=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_ADVANCED_ROUTER=y -CONFIG_ASK_IP_FIB_HASH=y -# CONFIG_IP_FIB_TRIE is not set -CONFIG_IP_FIB_HASH=y -CONFIG_IP_MULTIPLE_TABLES=y -CONFIG_IP_ROUTE_MULTIPATH=y -# CONFIG_IP_ROUTE_VERBOSE is not set -# CONFIG_IP_PNP is not set -CONFIG_NET_IPIP=m -CONFIG_NET_IPGRE=m -CONFIG_NET_IPGRE_BROADCAST=y -CONFIG_IP_MROUTE=y -CONFIG_IP_PIMSM_V1=y -CONFIG_IP_PIMSM_V2=y -# CONFIG_ARPD is not set -CONFIG_SYN_COOKIES=y -CONFIG_INET_AH=m -CONFIG_INET_ESP=m -CONFIG_INET_IPCOMP=m -CONFIG_INET_XFRM_TUNNEL=m -CONFIG_INET_TUNNEL=m -CONFIG_INET_XFRM_MODE_TRANSPORT=m -CONFIG_INET_XFRM_MODE_TUNNEL=m -CONFIG_INET_XFRM_MODE_BEET=m -CONFIG_INET_DIAG=y -CONFIG_INET_TCP_DIAG=y -CONFIG_TCP_CONG_ADVANCED=y -CONFIG_TCP_CONG_BIC=m -CONFIG_TCP_CONG_CUBIC=y -CONFIG_TCP_CONG_WESTWOOD=m -CONFIG_TCP_CONG_HTCP=m -CONFIG_TCP_CONG_HSTCP=m -CONFIG_TCP_CONG_HYBLA=m -CONFIG_TCP_CONG_VEGAS=m -CONFIG_TCP_CONG_SCALABLE=m -CONFIG_TCP_CONG_LP=m -CONFIG_TCP_CONG_VENO=m -CONFIG_TCP_CONG_YEAH=m -CONFIG_TCP_CONG_ILLINOIS=m -# CONFIG_DEFAULT_BIC is not set -CONFIG_DEFAULT_CUBIC=y -# CONFIG_DEFAULT_HTCP is not set -# CONFIG_DEFAULT_VEGAS is not set -# CONFIG_DEFAULT_WESTWOOD is not set -# CONFIG_DEFAULT_RENO is not set -CONFIG_DEFAULT_TCP_CONG="cubic" -CONFIG_TCP_MD5SIG=y -# CONFIG_IP_VS is not set -CONFIG_IPV6=m -CONFIG_IPV6_PRIVACY=y -CONFIG_IPV6_ROUTER_PREF=y -CONFIG_IPV6_ROUTE_INFO=y -# CONFIG_IPV6_OPTIMISTIC_DAD is not set -CONFIG_INET6_AH=m -CONFIG_INET6_ESP=m -CONFIG_INET6_IPCOMP=m -# CONFIG_IPV6_MIP6 is not set -CONFIG_INET6_XFRM_TUNNEL=m -CONFIG_INET6_TUNNEL=m -CONFIG_INET6_XFRM_MODE_TRANSPORT=m -CONFIG_INET6_XFRM_MODE_TUNNEL=m -CONFIG_INET6_XFRM_MODE_BEET=m -# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set -CONFIG_IPV6_SIT=m -CONFIG_IPV6_TUNNEL=m -CONFIG_IPV6_MULTIPLE_TABLES=y -CONFIG_IPV6_SUBTREES=y -CONFIG_NETWORK_SECMARK=y -CONFIG_NETFILTER=y -# CONFIG_NETFILTER_DEBUG is not set -CONFIG_BRIDGE_NETFILTER=y - -# -# Core Netfilter Configuration -# -CONFIG_NETFILTER_NETLINK=m -CONFIG_NETFILTER_NETLINK_QUEUE=m -CONFIG_NETFILTER_NETLINK_LOG=m -CONFIG_NF_CONNTRACK_ENABLED=m -CONFIG_NF_CONNTRACK=m -CONFIG_NF_CT_ACCT=y -CONFIG_NF_CONNTRACK_MARK=y -CONFIG_NF_CONNTRACK_SECMARK=y -CONFIG_NF_CONNTRACK_EVENTS=y -CONFIG_NF_CT_PROTO_GRE=m -CONFIG_NF_CT_PROTO_SCTP=m -# CONFIG_NF_CT_PROTO_UDPLITE is not set -CONFIG_NF_CONNTRACK_AMANDA=m -CONFIG_NF_CONNTRACK_FTP=m -CONFIG_NF_CONNTRACK_H323=m -CONFIG_NF_CONNTRACK_IRC=m -CONFIG_NF_CONNTRACK_NETBIOS_NS=m -CONFIG_NF_CONNTRACK_PPTP=m -CONFIG_NF_CONNTRACK_SANE=m -CONFIG_NF_CONNTRACK_SIP=m -CONFIG_NF_CONNTRACK_TFTP=m -CONFIG_NF_CT_NETLINK=m -CONFIG_NETFILTER_XTABLES=m -CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m -# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set -# CONFIG_NETFILTER_XT_TARGET_DSCP is not set -CONFIG_NETFILTER_XT_TARGET_MARK=m -CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_NFLOG=m -# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set -# CONFIG_NETFILTER_XT_TARGET_TRACE is not set -CONFIG_NETFILTER_XT_TARGET_SECMARK=m -CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m -CONFIG_NETFILTER_XT_TARGET_TCPMSS=m -CONFIG_NETFILTER_XT_MATCH_COMMENT=m -CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m -# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set -CONFIG_NETFILTER_XT_MATCH_CONNMARK=m -CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m -CONFIG_NETFILTER_XT_MATCH_DCCP=m -CONFIG_NETFILTER_XT_MATCH_DSCP=m -CONFIG_NETFILTER_XT_MATCH_ESP=m -CONFIG_NETFILTER_XT_MATCH_HELPER=m -CONFIG_NETFILTER_XT_MATCH_LENGTH=m -CONFIG_NETFILTER_XT_MATCH_LIMIT=m -CONFIG_NETFILTER_XT_MATCH_MAC=m -CONFIG_NETFILTER_XT_MATCH_MARK=m -CONFIG_NETFILTER_XT_MATCH_POLICY=m -CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m -# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set -CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m -CONFIG_NETFILTER_XT_MATCH_QUOTA=m -CONFIG_NETFILTER_XT_MATCH_REALM=m -CONFIG_NETFILTER_XT_MATCH_SCTP=m -CONFIG_NETFILTER_XT_MATCH_STATE=m -CONFIG_NETFILTER_XT_MATCH_STATISTIC=m -CONFIG_NETFILTER_XT_MATCH_STRING=m -CONFIG_NETFILTER_XT_MATCH_TCPMSS=m -# CONFIG_NETFILTER_XT_MATCH_U32 is not set -CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m - -# -# IP: Netfilter Configuration -# -CONFIG_NF_CONNTRACK_IPV4=m -CONFIG_NF_CONNTRACK_PROC_COMPAT=y -# CONFIG_IP_NF_QUEUE is not set -CONFIG_IP_NF_IPTABLES=m -CONFIG_IP_NF_MATCH_IPRANGE=m -CONFIG_IP_NF_MATCH_TOS=m -CONFIG_IP_NF_MATCH_RECENT=m -CONFIG_IP_NF_MATCH_ECN=m -CONFIG_IP_NF_MATCH_AH=m -CONFIG_IP_NF_MATCH_TTL=m -CONFIG_IP_NF_MATCH_OWNER=m -CONFIG_IP_NF_MATCH_ADDRTYPE=m -CONFIG_IP_NF_FILTER=m -CONFIG_IP_NF_TARGET_REJECT=m -CONFIG_IP_NF_TARGET_LOG=m -CONFIG_IP_NF_TARGET_ULOG=m -CONFIG_NF_NAT=m -CONFIG_NF_NAT_NEEDED=y -CONFIG_IP_NF_TARGET_MASQUERADE=m -CONFIG_IP_NF_TARGET_REDIRECT=m -CONFIG_IP_NF_TARGET_NETMAP=m -CONFIG_IP_NF_TARGET_SAME=m -CONFIG_NF_NAT_SNMP_BASIC=m -CONFIG_NF_NAT_PROTO_GRE=m -CONFIG_NF_NAT_FTP=m -CONFIG_NF_NAT_IRC=m -CONFIG_NF_NAT_TFTP=m -CONFIG_NF_NAT_AMANDA=m -CONFIG_NF_NAT_PPTP=m -CONFIG_NF_NAT_H323=m -CONFIG_NF_NAT_SIP=m -CONFIG_IP_NF_MANGLE=m -CONFIG_IP_NF_TARGET_TOS=m -CONFIG_IP_NF_TARGET_ECN=m -CONFIG_IP_NF_TARGET_TTL=m -CONFIG_IP_NF_TARGET_CLUSTERIP=m -CONFIG_IP_NF_RAW=m -CONFIG_IP_NF_ARPTABLES=m -CONFIG_IP_NF_ARPFILTER=m -CONFIG_IP_NF_ARP_MANGLE=m - -# -# IPv6: Netfilter Configuration (EXPERIMENTAL) -# -CONFIG_NF_CONNTRACK_IPV6=m -# CONFIG_IP6_NF_QUEUE is not set -CONFIG_IP6_NF_IPTABLES=m -CONFIG_IP6_NF_MATCH_RT=m -CONFIG_IP6_NF_MATCH_OPTS=m -CONFIG_IP6_NF_MATCH_FRAG=m -CONFIG_IP6_NF_MATCH_HL=m -CONFIG_IP6_NF_MATCH_OWNER=m -CONFIG_IP6_NF_MATCH_IPV6HEADER=m -CONFIG_IP6_NF_MATCH_AH=m -CONFIG_IP6_NF_MATCH_MH=m -CONFIG_IP6_NF_MATCH_EUI64=m -CONFIG_IP6_NF_FILTER=m -CONFIG_IP6_NF_TARGET_LOG=m -CONFIG_IP6_NF_TARGET_REJECT=m -CONFIG_IP6_NF_MANGLE=m -CONFIG_IP6_NF_TARGET_HL=m -CONFIG_IP6_NF_RAW=m - -# -# DECnet: Netfilter Configuration -# -# CONFIG_DECNET_NF_GRABULATOR is not set - -# -# Bridge: Netfilter Configuration -# -# CONFIG_BRIDGE_NF_EBTABLES is not set -CONFIG_IP_DCCP=m -CONFIG_INET_DCCP_DIAG=m -CONFIG_IP_DCCP_ACKVEC=y - -# -# DCCP CCIDs Configuration (EXPERIMENTAL) -# -CONFIG_IP_DCCP_CCID2=m -# CONFIG_IP_DCCP_CCID2_DEBUG is not set -CONFIG_IP_DCCP_CCID3=m -CONFIG_IP_DCCP_TFRC_LIB=m -# CONFIG_IP_DCCP_CCID3_DEBUG is not set -CONFIG_IP_DCCP_CCID3_RTO=100 - -# -# DCCP Kernel Hacking -# -# CONFIG_IP_DCCP_DEBUG is not set -CONFIG_IP_SCTP=m -# CONFIG_SCTP_DBG_MSG is not set -# CONFIG_SCTP_DBG_OBJCNT is not set -# CONFIG_SCTP_HMAC_NONE is not set -# CONFIG_SCTP_HMAC_SHA1 is not set -CONFIG_SCTP_HMAC_MD5=y -CONFIG_TIPC=m -CONFIG_TIPC_ADVANCED=y -CONFIG_TIPC_ZONES=3 -CONFIG_TIPC_CLUSTERS=1 -CONFIG_TIPC_NODES=255 -CONFIG_TIPC_SLAVE_NODES=0 -CONFIG_TIPC_PORTS=8191 -CONFIG_TIPC_LOG=0 -# CONFIG_TIPC_DEBUG is not set -CONFIG_ATM=m -CONFIG_ATM_CLIP=m -# CONFIG_ATM_CLIP_NO_ICMP is not set -CONFIG_ATM_LANE=m -# CONFIG_ATM_MPOA is not set -CONFIG_ATM_BR2684=m -CONFIG_ATM_BR2684_IPFILTER=y -CONFIG_BRIDGE=m -CONFIG_VLAN_8021Q=m -CONFIG_DECNET=m -# CONFIG_DECNET_ROUTER is not set -CONFIG_LLC=m -CONFIG_LLC2=m -CONFIG_IPX=m -CONFIG_IPX_INTERN=y -CONFIG_ATALK=m -CONFIG_DEV_APPLETALK=m -# CONFIG_LTPC is not set -# CONFIG_COPS is not set -CONFIG_IPDDP=m -CONFIG_IPDDP_ENCAP=y -CONFIG_IPDDP_DECAP=y -CONFIG_X25=m -CONFIG_LAPB=m -CONFIG_ECONET=m -CONFIG_ECONET_AUNUDP=y -CONFIG_ECONET_NATIVE=y -CONFIG_WAN_ROUTER=m - -# -# QoS and/or fair queueing -# -CONFIG_NET_SCHED=y -CONFIG_NET_SCH_FIFO=y - -# -# Queueing/Scheduling -# -CONFIG_NET_SCH_CBQ=m -CONFIG_NET_SCH_HTB=m -CONFIG_NET_SCH_HFSC=m -CONFIG_NET_SCH_ATM=m -CONFIG_NET_SCH_PRIO=m -# CONFIG_NET_SCH_RR is not set -CONFIG_NET_SCH_RED=m -CONFIG_NET_SCH_SFQ=m -CONFIG_NET_SCH_TEQL=m -CONFIG_NET_SCH_TBF=m -CONFIG_NET_SCH_GRED=m -CONFIG_NET_SCH_DSMARK=m -CONFIG_NET_SCH_NETEM=m -CONFIG_NET_SCH_INGRESS=m - -# -# Classification -# -CONFIG_NET_CLS=y -CONFIG_NET_CLS_BASIC=m -CONFIG_NET_CLS_TCINDEX=m -CONFIG_NET_CLS_ROUTE4=m -CONFIG_NET_CLS_ROUTE=y -CONFIG_NET_CLS_FW=m -CONFIG_NET_CLS_U32=m -CONFIG_CLS_U32_PERF=y -CONFIG_CLS_U32_MARK=y -CONFIG_NET_CLS_RSVP=m -CONFIG_NET_CLS_RSVP6=m -CONFIG_NET_EMATCH=y -CONFIG_NET_EMATCH_STACK=32 -CONFIG_NET_EMATCH_CMP=m -CONFIG_NET_EMATCH_NBYTE=m -CONFIG_NET_EMATCH_U32=m -CONFIG_NET_EMATCH_META=m -CONFIG_NET_EMATCH_TEXT=m -CONFIG_NET_CLS_ACT=y -CONFIG_NET_ACT_POLICE=m -CONFIG_NET_ACT_GACT=m -CONFIG_GACT_PROB=y -CONFIG_NET_ACT_MIRRED=m -CONFIG_NET_ACT_IPT=m -CONFIG_NET_ACT_PEDIT=m -CONFIG_NET_ACT_SIMP=m -# CONFIG_NET_CLS_POLICE is not set -CONFIG_NET_CLS_IND=y - -# -# Network testing -# -# CONFIG_NET_PKTGEN is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set -CONFIG_AF_RXRPC=m -# CONFIG_AF_RXRPC_DEBUG is not set -CONFIG_RXKAD=m -CONFIG_FIB_RULES=y - -# -# Wireless -# -# CONFIG_CFG80211 is not set -# CONFIG_WIRELESS_EXT is not set -# CONFIG_MAC80211 is not set -# CONFIG_IEEE80211 is not set -# CONFIG_RFKILL is not set -# CONFIG_NET_9P is not set - -# -# Device Drivers -# - -# -# Generic Driver Options -# -CONFIG_STANDALONE=y -CONFIG_PREVENT_FIRMWARE_BUILD=y -# CONFIG_FW_LOADER is not set -# CONFIG_DEBUG_DRIVER is not set -# CONFIG_DEBUG_DEVRES is not set -# CONFIG_SYS_HYPERVISOR is not set -CONFIG_CONNECTOR=m -# CONFIG_MTD is not set -CONFIG_PARPORT=m -CONFIG_PARPORT_PC=m -# CONFIG_PARPORT_SERIAL is not set -# CONFIG_PARPORT_PC_FIFO is not set -# CONFIG_PARPORT_PC_SUPERIO is not set -# CONFIG_PARPORT_GSC is not set -# CONFIG_PARPORT_AX88796 is not set -# CONFIG_PARPORT_1284 is not set -# CONFIG_PNP is not set -CONFIG_BLK_DEV=y -# CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_XD is not set -# CONFIG_PARIDE is not set -# CONFIG_BLK_CPQ_DA is not set -# CONFIG_BLK_CPQ_CISS_DA is not set -# CONFIG_BLK_DEV_DAC960 is not set -# CONFIG_BLK_DEV_UMEM is not set -# CONFIG_BLK_DEV_COW_COMMON is not set -CONFIG_BLK_DEV_LOOP=m -CONFIG_BLK_DEV_CRYPTOLOOP=m -CONFIG_BLK_DEV_NBD=m -# CONFIG_BLK_DEV_SX8 is not set -CONFIG_BLK_DEV_RAM=m -CONFIG_BLK_DEV_RAM_COUNT=16 -CONFIG_BLK_DEV_RAM_SIZE=4096 -CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 -# CONFIG_CDROM_PKTCDVD is not set -# CONFIG_ATA_OVER_ETH is not set -CONFIG_MISC_DEVICES=y -# CONFIG_IBM_ASM is not set -# CONFIG_PHANTOM is not set -# CONFIG_EEPROM_93CX6 is not set -# CONFIG_SGI_IOC4 is not set -# CONFIG_TIFM_CORE is not set -CONFIG_IDE=y -CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_IDE_SATA is not set -# CONFIG_BLK_DEV_HD_IDE is not set -CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set -CONFIG_BLK_DEV_IDECD=y -# CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_IDE_TASK_IOCTL is not set -CONFIG_IDE_PROC_FS=y - -# -# IDE chipset support/bugfixes -# -CONFIG_IDE_GENERIC=y -# CONFIG_BLK_DEV_CMD640 is not set -CONFIG_BLK_DEV_IDEPCI=y -# CONFIG_IDEPCI_SHARE_IRQ is not set -CONFIG_IDEPCI_PCIBUS_ORDER=y -# CONFIG_BLK_DEV_OFFBOARD is not set -# CONFIG_BLK_DEV_GENERIC is not set -# CONFIG_BLK_DEV_OPTI621 is not set -# CONFIG_BLK_DEV_RZ1000 is not set -# CONFIG_BLK_DEV_IDEDMA_PCI is not set -# CONFIG_IDE_ARM is not set -# CONFIG_IDE_CHIPSETS is not set -# CONFIG_BLK_DEV_IDEDMA is not set -# CONFIG_BLK_DEV_HD is not set - -# -# SCSI device support -# -# CONFIG_RAID_ATTRS is not set -# CONFIG_SCSI is not set -# CONFIG_SCSI_DMA is not set -# CONFIG_SCSI_NETLINK is not set -# CONFIG_ATA is not set -# CONFIG_MD is not set - -# -# Fusion MPT device support -# -# CONFIG_FUSION is not set - -# -# IEEE 1394 (FireWire) support -# -# CONFIG_FIREWIRE is not set -# CONFIG_IEEE1394 is not set -# CONFIG_I2O is not set -# CONFIG_MACINTOSH_DRIVERS is not set -CONFIG_NETDEVICES=y -# CONFIG_NETDEVICES_MULTIQUEUE is not set -# CONFIG_IFB is not set -CONFIG_DUMMY=m -# CONFIG_BONDING is not set -# CONFIG_MACVLAN is not set -# CONFIG_EQUALIZER is not set -CONFIG_TUN=m -# CONFIG_ARCNET is not set -# CONFIG_PHYLIB is not set -CONFIG_NET_ETHERNET=y -CONFIG_MII=y -# CONFIG_HAPPYMEAL is not set -# CONFIG_SUNGEM is not set -# CONFIG_CASSINI is not set -# CONFIG_NET_VENDOR_3COM is not set -# CONFIG_LANCE is not set -# CONFIG_NET_VENDOR_SMC is not set -# CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_NET_TULIP is not set -# CONFIG_AT1700 is not set -# CONFIG_DEPCA is not set -# CONFIG_HP100 is not set -# CONFIG_NET_ISA is not set -CONFIG_NET_PCI=y -CONFIG_PCNET32=y -# CONFIG_PCNET32_NAPI is not set -# CONFIG_AMD8111_ETH is not set -# CONFIG_ADAPTEC_STARFIRE is not set -# CONFIG_AC3200 is not set -# CONFIG_APRICOT is not set -# CONFIG_B44 is not set -# CONFIG_FORCEDETH is not set -# CONFIG_CS89x0 is not set -# CONFIG_DGRS is not set -# CONFIG_EEPRO100 is not set -# CONFIG_E100 is not set -# CONFIG_FEALNX is not set -# CONFIG_NATSEMI is not set -CONFIG_NE2K_PCI=y -CONFIG_8139CP=y -# CONFIG_8139TOO is not set -# CONFIG_SIS900 is not set -# CONFIG_EPIC100 is not set -# CONFIG_SUNDANCE is not set -# CONFIG_TLAN is not set -# CONFIG_VIA_RHINE is not set -# CONFIG_SC92031 is not set -# CONFIG_NET_POCKET is not set -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set -# CONFIG_TR is not set - -# -# Wireless LAN -# -# CONFIG_WLAN_PRE80211 is not set -# CONFIG_WLAN_80211 is not set -# CONFIG_WAN is not set -CONFIG_ATM_DRIVERS=y -# CONFIG_ATM_DUMMY is not set -# CONFIG_ATM_TCP is not set -# CONFIG_ATM_LANAI is not set -# CONFIG_ATM_ENI is not set -# CONFIG_ATM_FIRESTREAM is not set -# CONFIG_ATM_ZATM is not set -# CONFIG_ATM_NICSTAR is not set -# CONFIG_ATM_IDT77252 is not set -# CONFIG_ATM_AMBASSADOR is not set -# CONFIG_ATM_HORIZON is not set -# CONFIG_ATM_IA is not set -# CONFIG_ATM_FORE200E_MAYBE is not set -# CONFIG_ATM_HE is not set -# CONFIG_FDDI is not set -CONFIG_HIPPI=y -# CONFIG_ROADRUNNER is not set -# CONFIG_PLIP is not set -# CONFIG_PPP is not set -# CONFIG_SLIP is not set -# CONFIG_SHAPER is not set -# CONFIG_NETCONSOLE is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set -# CONFIG_ISDN is not set -# CONFIG_PHONE is not set - -# -# Input device support -# -CONFIG_INPUT=y -# CONFIG_INPUT_FF_MEMLESS is not set -# CONFIG_INPUT_POLLDEV is not set - -# -# Userland interfaces -# -CONFIG_INPUT_MOUSEDEV=y -CONFIG_INPUT_MOUSEDEV_PSAUX=y -CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 -CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_TSDEV is not set -# CONFIG_INPUT_EVDEV is not set -# CONFIG_INPUT_EVBUG is not set - -# -# Input Device Drivers -# -CONFIG_INPUT_KEYBOARD=y -CONFIG_KEYBOARD_ATKBD=y -# CONFIG_KEYBOARD_SUNKBD is not set -# CONFIG_KEYBOARD_LKKBD is not set -# CONFIG_KEYBOARD_XTKBD is not set -# CONFIG_KEYBOARD_NEWTON is not set -# CONFIG_KEYBOARD_STOWAWAY is not set -CONFIG_INPUT_MOUSE=y -CONFIG_MOUSE_PS2=y -CONFIG_MOUSE_PS2_ALPS=y -CONFIG_MOUSE_PS2_LOGIPS2PP=y -CONFIG_MOUSE_PS2_SYNAPTICS=y -CONFIG_MOUSE_PS2_LIFEBOOK=y -CONFIG_MOUSE_PS2_TRACKPOINT=y -# CONFIG_MOUSE_PS2_TOUCHKIT is not set -# CONFIG_MOUSE_SERIAL is not set -# CONFIG_MOUSE_APPLETOUCH is not set -# CONFIG_MOUSE_INPORT is not set -# CONFIG_MOUSE_LOGIBM is not set -# CONFIG_MOUSE_PC110PAD is not set -# CONFIG_MOUSE_VSXXXAA is not set -# CONFIG_INPUT_JOYSTICK is not set -# CONFIG_INPUT_TABLET is not set -# CONFIG_INPUT_TOUCHSCREEN is not set -# CONFIG_INPUT_MISC is not set - -# -# Hardware I/O ports -# -CONFIG_SERIO=y -CONFIG_SERIO_I8042=y -CONFIG_SERIO_SERPORT=y -# CONFIG_SERIO_CT82C710 is not set -# CONFIG_SERIO_PARKBD is not set -# CONFIG_SERIO_PCIPS2 is not set -CONFIG_SERIO_LIBPS2=y -# CONFIG_SERIO_RAW is not set -# CONFIG_GAMEPORT is not set - -# -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -CONFIG_HW_CONSOLE=y -# CONFIG_VT_HW_CONSOLE_BINDING is not set -# CONFIG_SERIAL_NONSTANDARD is not set - -# -# Serial drivers -# -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_FIX_EARLYCON_MEM=y -CONFIG_SERIAL_8250_PCI=y -CONFIG_SERIAL_8250_NR_UARTS=4 -CONFIG_SERIAL_8250_RUNTIME_UARTS=4 -# CONFIG_SERIAL_8250_EXTENDED is not set - -# -# Non-8250 serial port support -# -CONFIG_SERIAL_CORE=y -CONFIG_SERIAL_CORE_CONSOLE=y -# CONFIG_SERIAL_JSM is not set -CONFIG_UNIX98_PTYS=y -CONFIG_LEGACY_PTYS=y -CONFIG_LEGACY_PTY_COUNT=256 -# CONFIG_PRINTER is not set -# CONFIG_PPDEV is not set -# CONFIG_TIPAR is not set -# CONFIG_IPMI_HANDLER is not set -CONFIG_WATCHDOG=y -CONFIG_WATCHDOG_NOWAYOUT=y - -# -# Watchdog Device Drivers -# -CONFIG_SOFT_WATCHDOG=y -# CONFIG_ACQUIRE_WDT is not set -# CONFIG_ADVANTECH_WDT is not set -# CONFIG_ALIM1535_WDT is not set -# CONFIG_ALIM7101_WDT is not set -# CONFIG_SC520_WDT is not set -# CONFIG_EUROTECH_WDT is not set -# CONFIG_IB700_WDT is not set -# CONFIG_IBMASR is not set -# CONFIG_WAFER_WDT is not set -# CONFIG_I6300ESB_WDT is not set -# CONFIG_ITCO_WDT is not set -# CONFIG_SC1200_WDT is not set -# CONFIG_PC87413_WDT is not set -# CONFIG_60XX_WDT is not set -# CONFIG_SBC8360_WDT is not set -# CONFIG_CPU5_WDT is not set -# CONFIG_SMSC37B787_WDT is not set -# CONFIG_W83627HF_WDT is not set -# CONFIG_W83697HF_WDT is not set -# CONFIG_W83877F_WDT is not set -# CONFIG_W83977F_WDT is not set -# CONFIG_MACHZ_WDT is not set -# CONFIG_SBC_EPX_C3_WATCHDOG is not set - -# -# ISA-based Watchdog Cards -# -# CONFIG_PCWATCHDOG is not set -# CONFIG_MIXCOMWD is not set -# CONFIG_WDT is not set - -# -# PCI-based Watchdog Cards -# -# CONFIG_PCIPCWATCHDOG is not set -# CONFIG_WDTPCI is not set -# CONFIG_HW_RANDOM is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set -# CONFIG_GEN_RTC is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set -# CONFIG_SONYPI is not set -# CONFIG_AGP is not set -# CONFIG_DRM is not set -# CONFIG_MWAVE is not set -# CONFIG_PC8736x_GPIO is not set -# CONFIG_NSC_GPIO is not set -# CONFIG_CS5535_GPIO is not set -CONFIG_RAW_DRIVER=m -CONFIG_MAX_RAW_DEVS=256 -# CONFIG_HANGCHECK_TIMER is not set -# CONFIG_TCG_TPM is not set -# CONFIG_TELCLOCK is not set -CONFIG_DEVPORT=y -# CONFIG_I2C is not set - -# -# SPI support -# -# CONFIG_SPI is not set -# CONFIG_SPI_MASTER is not set -# CONFIG_W1 is not set -# CONFIG_POWER_SUPPLY is not set -CONFIG_HWMON=y -# CONFIG_HWMON_VID is not set -# CONFIG_SENSORS_ABITUGURU is not set -# CONFIG_SENSORS_ABITUGURU3 is not set -# CONFIG_SENSORS_K8TEMP is not set -# CONFIG_SENSORS_F71805F is not set -# CONFIG_SENSORS_CORETEMP is not set -# CONFIG_SENSORS_IT87 is not set -# CONFIG_SENSORS_PC87360 is not set -# CONFIG_SENSORS_PC87427 is not set -# CONFIG_SENSORS_SIS5595 is not set -# CONFIG_SENSORS_SMSC47M1 is not set -# CONFIG_SENSORS_SMSC47B397 is not set -# CONFIG_SENSORS_VIA686A is not set -# CONFIG_SENSORS_VT1211 is not set -# CONFIG_SENSORS_VT8231 is not set -# CONFIG_SENSORS_W83627HF is not set -# CONFIG_SENSORS_W83627EHF is not set -# CONFIG_SENSORS_HDAPS is not set -# CONFIG_SENSORS_APPLESMC is not set -# CONFIG_HWMON_DEBUG_CHIP is not set - -# -# Multifunction device drivers -# -# CONFIG_MFD_SM501 is not set - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set -# CONFIG_DVB_CORE is not set -# CONFIG_DAB is not set - -# -# Graphics support -# -# CONFIG_BACKLIGHT_LCD_SUPPORT is not set - -# -# Display device support -# -# CONFIG_DISPLAY_SUPPORT is not set -# CONFIG_VGASTATE is not set -CONFIG_VIDEO_OUTPUT_CONTROL=m -# CONFIG_FB is not set - -# -# Console display driver support -# -CONFIG_VGA_CONSOLE=y -# CONFIG_VGACON_SOFT_SCROLLBACK is not set -# CONFIG_VIDEO_SELECT is not set -# CONFIG_MDA_CONSOLE is not set -CONFIG_DUMMY_CONSOLE=y - -# -# Sound -# -# CONFIG_SOUND is not set -CONFIG_HID_SUPPORT=y -# CONFIG_HID is not set -CONFIG_USB_SUPPORT=y -CONFIG_USB_ARCH_HAS_HCD=y -CONFIG_USB_ARCH_HAS_OHCI=y -CONFIG_USB_ARCH_HAS_EHCI=y -# CONFIG_USB is not set - -# -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' -# - -# -# USB Gadget Support -# -# CONFIG_USB_GADGET is not set -# CONFIG_MMC is not set -# CONFIG_NEW_LEDS is not set -# CONFIG_INFINIBAND is not set -# CONFIG_EDAC is not set -# CONFIG_RTC_CLASS is not set - -# -# DMA Engine support -# -# CONFIG_DMA_ENGINE is not set - -# -# DMA Clients -# - -# -# DMA Devices -# -# CONFIG_AUXDISPLAY is not set -CONFIG_VIRTUALIZATION=y -# CONFIG_KVM is not set - -# -# Userspace I/O -# -# CONFIG_UIO is not set - -# -# File systems -# -# CONFIG_EXT2_FS is not set -CONFIG_EXT3_FS=y -CONFIG_EXT3_FS_XATTR=y -CONFIG_EXT3_FS_POSIX_ACL=y -CONFIG_EXT3_FS_SECURITY=y -# CONFIG_EXT4DEV_FS is not set -CONFIG_JBD=y -# CONFIG_JBD_DEBUG is not set -CONFIG_FS_MBCACHE=y -# CONFIG_REISERFS_FS is not set -# CONFIG_JFS_FS is not set -CONFIG_FS_POSIX_ACL=y -# CONFIG_XFS_FS is not set -# CONFIG_GFS2_FS is not set -# CONFIG_OCFS2_FS is not set -# CONFIG_MINIX_FS is not set -CONFIG_ROMFS_FS=m -CONFIG_INOTIFY=y -CONFIG_INOTIFY_USER=y -# CONFIG_QUOTA is not set -CONFIG_DNOTIFY=y -# CONFIG_AUTOFS_FS is not set -# CONFIG_AUTOFS4_FS is not set -# CONFIG_FUSE_FS is not set -CONFIG_GENERIC_ACL=y - -# -# CD-ROM/DVD Filesystems -# -CONFIG_ISO9660_FS=y -CONFIG_JOLIET=y -CONFIG_ZISOFS=y -CONFIG_UDF_FS=y -CONFIG_UDF_NLS=y - -# -# DOS/FAT/NT Filesystems -# -# CONFIG_MSDOS_FS is not set -# CONFIG_VFAT_FS is not set -# CONFIG_NTFS_FS is not set - -# -# Pseudo filesystems -# -CONFIG_PROC_FS=y -CONFIG_PROC_KCORE=y -CONFIG_PROC_SYSCTL=y -CONFIG_SYSFS=y -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y -# CONFIG_HUGETLBFS is not set -# CONFIG_HUGETLB_PAGE is not set -CONFIG_RAMFS=y -CONFIG_CONFIGFS_FS=m - -# -# Miscellaneous filesystems -# -# CONFIG_ADFS_FS is not set -# CONFIG_AFFS_FS is not set -# CONFIG_ECRYPT_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_HFSPLUS_FS is not set -# CONFIG_BEFS_FS is not set -# CONFIG_BFS_FS is not set -# CONFIG_EFS_FS is not set -CONFIG_CRAMFS=m -# CONFIG_VXFS_FS is not set -# CONFIG_HPFS_FS is not set -# CONFIG_QNX4FS_FS is not set -# CONFIG_SYSV_FS is not set -# CONFIG_UFS_FS is not set - -# -# Network File Systems -# -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -# CONFIG_NFS_V3_ACL is not set -# CONFIG_NFS_V4 is not set -# CONFIG_NFS_DIRECTIO is not set -# CONFIG_NFSD is not set -CONFIG_LOCKD=y -CONFIG_LOCKD_V4=y -CONFIG_NFS_COMMON=y -CONFIG_SUNRPC=y -# CONFIG_SUNRPC_BIND34 is not set -# CONFIG_RPCSEC_GSS_KRB5 is not set -# CONFIG_RPCSEC_GSS_SPKM3 is not set -# CONFIG_SMB_FS is not set -# CONFIG_CIFS is not set -# CONFIG_NCP_FS is not set -# CONFIG_CODA_FS is not set -# CONFIG_AFS_FS is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y - -# -# Native Language Support -# -CONFIG_NLS=y -CONFIG_NLS_DEFAULT="iso8859-1" -CONFIG_NLS_CODEPAGE_437=m -CONFIG_NLS_CODEPAGE_737=m -CONFIG_NLS_CODEPAGE_775=m -CONFIG_NLS_CODEPAGE_850=m -CONFIG_NLS_CODEPAGE_852=m -CONFIG_NLS_CODEPAGE_855=m -CONFIG_NLS_CODEPAGE_857=m -CONFIG_NLS_CODEPAGE_860=m -CONFIG_NLS_CODEPAGE_861=m -CONFIG_NLS_CODEPAGE_862=m -CONFIG_NLS_CODEPAGE_863=m -CONFIG_NLS_CODEPAGE_864=m -CONFIG_NLS_CODEPAGE_865=m -CONFIG_NLS_CODEPAGE_866=m -CONFIG_NLS_CODEPAGE_869=m -CONFIG_NLS_CODEPAGE_936=m -CONFIG_NLS_CODEPAGE_950=m -CONFIG_NLS_CODEPAGE_932=m -CONFIG_NLS_CODEPAGE_949=m -CONFIG_NLS_CODEPAGE_874=m -CONFIG_NLS_ISO8859_8=m -CONFIG_NLS_CODEPAGE_1250=m -CONFIG_NLS_CODEPAGE_1251=m -CONFIG_NLS_ASCII=m -CONFIG_NLS_ISO8859_1=m -CONFIG_NLS_ISO8859_2=m -CONFIG_NLS_ISO8859_3=m -CONFIG_NLS_ISO8859_4=m -CONFIG_NLS_ISO8859_5=m -CONFIG_NLS_ISO8859_6=m -CONFIG_NLS_ISO8859_7=m -CONFIG_NLS_ISO8859_9=m -CONFIG_NLS_ISO8859_13=m -CONFIG_NLS_ISO8859_14=m -CONFIG_NLS_ISO8859_15=m -CONFIG_NLS_KOI8_R=m -CONFIG_NLS_KOI8_U=m -CONFIG_NLS_UTF8=m - -# -# Distributed Lock Manager -# -# CONFIG_DLM is not set -CONFIG_INSTRUMENTATION=y -# CONFIG_PROFILING is not set -# CONFIG_KPROBES is not set - -# -# Kernel hacking -# -CONFIG_TRACE_IRQFLAGS_SUPPORT=y -# CONFIG_PRINTK_TIME is not set -# CONFIG_ENABLE_MUST_CHECK is not set -CONFIG_MAGIC_SYSRQ=y -# CONFIG_UNUSED_SYMBOLS is not set -CONFIG_DEBUG_FS=y -# CONFIG_HEADERS_CHECK is not set -CONFIG_DEBUG_KERNEL=y -# CONFIG_DEBUG_SHIRQ is not set -CONFIG_DETECT_SOFTLOCKUP=y -CONFIG_SCHED_DEBUG=y -# CONFIG_SCHEDSTATS is not set -# CONFIG_TIMER_STATS is not set -CONFIG_DEBUG_SLAB=y -CONFIG_DEBUG_SLAB_LEAK=y -CONFIG_DEBUG_RT_MUTEXES=y -CONFIG_DEBUG_PI_LIST=y -# CONFIG_RT_MUTEX_TESTER is not set -CONFIG_DEBUG_SPINLOCK=y -CONFIG_DEBUG_MUTEXES=y -CONFIG_DEBUG_LOCK_ALLOC=y -CONFIG_PROVE_LOCKING=y -CONFIG_LOCKDEP=y -CONFIG_LOCK_STAT=y -# CONFIG_DEBUG_LOCKDEP is not set -CONFIG_TRACE_IRQFLAGS=y -CONFIG_DEBUG_SPINLOCK_SLEEP=y -# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set -CONFIG_STACKTRACE=y -CONFIG_DEBUG_KOBJECT=y -CONFIG_DEBUG_HIGHMEM=y -CONFIG_DEBUG_BUGVERBOSE=y -CONFIG_DEBUG_INFO=y -CONFIG_DEBUG_VM=y -CONFIG_DEBUG_LIST=y -CONFIG_FRAME_POINTER=y -CONFIG_FORCED_INLINING=y -CONFIG_RCU_TORTURE_TEST=m -# CONFIG_FAULT_INJECTION is not set -CONFIG_EARLY_PRINTK=y -CONFIG_DEBUG_STACKOVERFLOW=y -# CONFIG_DEBUG_STACK_USAGE is not set -CONFIG_DEBUG_PAGEALLOC=y -CONFIG_DEBUG_RODATA=y -CONFIG_4KSTACKS=y -CONFIG_X86_FIND_SMP_CONFIG=y -CONFIG_X86_MPPARSE=y -CONFIG_DOUBLEFAULT=y - -# -# Security options -# -CONFIG_KEYS=y -# CONFIG_KEYS_DEBUG_PROC_KEYS is not set -# CONFIG_SECURITY is not set -CONFIG_CRYPTO=y -CONFIG_CRYPTO_ALGAPI=y -CONFIG_CRYPTO_BLKCIPHER=m -CONFIG_CRYPTO_HASH=m -CONFIG_CRYPTO_MANAGER=m -CONFIG_CRYPTO_HMAC=m -# CONFIG_CRYPTO_XCBC is not set -CONFIG_CRYPTO_NULL=m -CONFIG_CRYPTO_MD4=m -CONFIG_CRYPTO_MD5=y -CONFIG_CRYPTO_SHA1=m -CONFIG_CRYPTO_SHA256=m -# CONFIG_CRYPTO_SHA512 is not set -# CONFIG_CRYPTO_WP512 is not set -# CONFIG_CRYPTO_TGR192 is not set -CONFIG_CRYPTO_GF128MUL=m -# CONFIG_CRYPTO_ECB is not set -CONFIG_CRYPTO_CBC=m -CONFIG_CRYPTO_PCBC=m -CONFIG_CRYPTO_LRW=m -# CONFIG_CRYPTO_CRYPTD is not set -CONFIG_CRYPTO_DES=m -CONFIG_CRYPTO_FCRYPT=m -# CONFIG_CRYPTO_BLOWFISH is not set -# CONFIG_CRYPTO_TWOFISH is not set -# CONFIG_CRYPTO_TWOFISH_586 is not set -# CONFIG_CRYPTO_SERPENT is not set -CONFIG_CRYPTO_AES=m -# CONFIG_CRYPTO_AES_586 is not set -# CONFIG_CRYPTO_CAST5 is not set -# CONFIG_CRYPTO_CAST6 is not set -CONFIG_CRYPTO_TEA=m -# CONFIG_CRYPTO_ARC4 is not set -# CONFIG_CRYPTO_KHAZAD is not set -# CONFIG_CRYPTO_ANUBIS is not set -CONFIG_CRYPTO_DEFLATE=m -# CONFIG_CRYPTO_MICHAEL_MIC is not set -# CONFIG_CRYPTO_CRC32C is not set -# CONFIG_CRYPTO_CAMELLIA is not set -# CONFIG_CRYPTO_TEST is not set -CONFIG_CRYPTO_HW=y -# CONFIG_CRYPTO_DEV_PADLOCK is not set -# CONFIG_CRYPTO_DEV_GEODE is not set - -# -# Library routines -# -CONFIG_BITREVERSE=y -CONFIG_CRC_CCITT=m -CONFIG_CRC16=m -CONFIG_CRC_ITU_T=m -CONFIG_CRC32=y -# CONFIG_CRC7 is not set -CONFIG_LIBCRC32C=m -CONFIG_ZLIB_INFLATE=y -CONFIG_ZLIB_DEFLATE=m -CONFIG_TEXTSEARCH=y -CONFIG_TEXTSEARCH_KMP=m -CONFIG_TEXTSEARCH_BM=m -CONFIG_TEXTSEARCH_FSM=m -CONFIG_PLIST=y -CONFIG_HAS_IOMEM=y -CONFIG_HAS_IOPORT=y -CONFIG_HAS_DMA=y -CONFIG_GENERIC_HARDIRQS=y -CONFIG_GENERIC_IRQ_PROBE=y -CONFIG_GENERIC_PENDING_IRQ=y -CONFIG_X86_SMP=y -CONFIG_X86_HT=y -CONFIG_X86_BIOS_REBOOT=y -CONFIG_X86_TRAMPOLINE=y -CONFIG_KTIME_SCALAR=y diff --git a/openflow/datapath/openflow-ext.c b/openflow/datapath/openflow-ext.c deleted file mode 100644 index e9f87a8b..00000000 --- a/openflow/datapath/openflow-ext.c +++ /dev/null @@ -1,83 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#include "openflow/openflow-ext.h" - -#include "chain.h" -#include "datapath.h" -#include "table.h" -#include "private-msg.h" - -/*** - * Copy the new dp_desc out of the passed message - */ - -int -recv_of_set_dp_desc(struct datapath *dp, const struct sender * sender, - const struct openflow_extension_header *ofexth) -{ - struct openflow_ext_set_dp_desc * set_dp_desc = (struct openflow_ext_set_dp_desc * ) - ofexth; - memcpy(dp->dp_desc, set_dp_desc->dp_desc, DESC_STR_LEN); - dp->dp_desc[DESC_STR_LEN-1] = 0; // force null for safety - return 0; -} - - -int -openflow_ext_recv_msg(struct sw_chain *chain, const struct sender *sender, - const void *ofph) -{ - int error = 0; - const struct openflow_queue_command_header *ofexth = ofph; - - switch (ntohl(ofexth->header.subtype)) { - /**** added here as a place holder - * case OFP_EXT_QUEUE_MODIFY: { - * recv_of_exp_queue_modify(dp,sender,oh); - * return 0; - * } - * case OFP_EXT_QUEUE_DELETE: { - * recv_of_exp_queue_delete(dp,sender,oh); - * return 0; - * } - */ - case OFP_EXT_SET_DESC: - return recv_of_set_dp_desc(chain->dp,sender,ofexth); - default: - VLOG_ERR("Received unknown command of type %d", - ntohl(ofexth->header.subtype)); - return -EINVAL; - } - - return error; -} diff --git a/openflow/datapath/openflow-ext.h b/openflow/datapath/openflow-ext.h deleted file mode 100644 index 83edfc01..00000000 --- a/openflow/datapath/openflow-ext.h +++ /dev/null @@ -1,38 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#ifndef OPENFLOW_EXT_H_ -#define OPENFLOW_EXT_H_ - -int openflow_ext_recv_msg(struct sw_chain *, const struct sender *, const void *); - -#endif diff --git a/openflow/datapath/private-msg.c b/openflow/datapath/private-msg.c deleted file mode 100644 index 96110ebf..00000000 --- a/openflow/datapath/private-msg.c +++ /dev/null @@ -1,137 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#include "openflow/private-ext.h" - -#include "chain.h" -#include "datapath.h" -#include "table.h" -#include "private-msg.h" - -struct emerg_flow_context { - struct sw_chain *chain; -}; - -static void flush_working(struct sw_chain *); -static int protection_callback(struct sw_flow *, void *); -static void do_protection(struct sw_chain *); - -static void -flush_working(struct sw_chain *chain) -{ - struct sw_flow_key key; - int num_deleted = 0; - - memset(&key, 0, sizeof(key)); - key.wildcards = OFPFW_ALL; - num_deleted = chain_delete(chain, &key, OFPP_NONE, 0, 0, 0); -} - -static int -protection_callback(struct sw_flow *flow, void *private_) -{ - struct emerg_flow_context *private - = (struct emerg_flow_context *)private_; - struct sw_flow_actions *actions = flow->sf_acts; - struct ofp_match match; - struct sw_flow *tgtflow = NULL; - int error = 0; - - tgtflow = flow_alloc(actions->actions_len, GFP_ATOMIC); - if (tgtflow == NULL) { - return -ENOMEM; - } - - /* Dup w/o idle and hard timeout. */ - memset(&match, 0, sizeof(match)); - flow_fill_match(&match, &flow->key); - flow_extract_match(&tgtflow->key, &match); - /* Fill out flow. */ - tgtflow->priority = flow->priority; - tgtflow->idle_timeout = OFP_FLOW_PERMANENT; - tgtflow->hard_timeout = OFP_FLOW_PERMANENT; - tgtflow->send_flow_rem = flow->send_flow_rem; - tgtflow->emerg_flow = 0; - flow_setup_actions(tgtflow, actions->actions, actions->actions_len); - - error = chain_insert(private->chain, tgtflow, 0); - if (error) - flow_free(tgtflow); - - return error; -} - -static void -do_protection(struct sw_chain *chain) -{ - struct emerg_flow_context private; - struct sw_flow_key key; - struct sw_table_position position; - struct sw_table *table = chain->emerg_table; - int error = 0; - - memset(&private, 0, sizeof(private)); - private.chain = chain; - memset(&key, 0, sizeof(key)); - key.wildcards = OFPFW_ALL; - memset(&position, 0, sizeof(position)); - - error = table->iterate(table, &key, OFPP_NONE, - &position, protection_callback, &private); -} - -int -private_recv_msg(struct sw_chain *chain, const struct sender *sender, - const void *ofph) -{ - int error = 0; - struct private_vxhdr *vxhdr = (struct private_vxhdr *)ofph; - struct private_vxopt *vxopt = (struct private_vxopt *)(vxhdr + 1); - - switch (ntohs(vxopt->pvo_type)) { - case PRIVATEOPT_PROTOCOL_STATS_REQUEST: - case PRIVATEOPT_PROTOCOL_STATS_REPLY: - break; - case PRIVATEOPT_EMERG_FLOW_PROTECTION: - flush_working(chain); - do_protection(chain); - break; - case PRIVATEOPT_EMERG_FLOW_RESTORATION: - /* Nothing to do because we assume that a re-connected - * controller will do flush current working flow table. */ - break; - default: - error = -EINVAL; - } - - return error; -} diff --git a/openflow/datapath/private-msg.h b/openflow/datapath/private-msg.h deleted file mode 100644 index 246aa541..00000000 --- a/openflow/datapath/private-msg.h +++ /dev/null @@ -1,38 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#ifndef PRIVATE_MSG_H_ -#define PRIVATE_MSG_H_ - -int private_recv_msg(struct sw_chain *, const struct sender *, const void *); - -#endif diff --git a/openflow/datapath/table-hash.c b/openflow/datapath/table-hash.c deleted file mode 100644 index 8e5a97b7..00000000 --- a/openflow/datapath/table-hash.c +++ /dev/null @@ -1,489 +0,0 @@ -/* - * Distributed under the terms of the GNU GPL version 2. - * Copyright (c) 2007, 2008, 2009 The Board of Trustees of The Leland - * Stanford Junior University - */ - -#include "table.h" -#include "crc32.h" -#include "flow.h" -#include "datapath.h" - -#include -#include -#include -#include -#include - -static void *kmem_alloc(size_t); -static void *kmem_zalloc(size_t); -static void kmem_free(void *, size_t); - -struct sw_table_hash { - struct sw_table swt; - struct crc32 crc32; - unsigned int n_flows; - unsigned int bucket_mask; /* Number of buckets minus 1. */ - struct sw_flow **buckets; -}; - -static struct sw_flow **find_bucket(struct sw_table *swt, - const struct sw_flow_key *key) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - unsigned int crc = crc32_calculate(&th->crc32, key, - offsetof(struct sw_flow_key, wildcards)); - return &th->buckets[crc & th->bucket_mask]; -} - -static struct sw_flow *table_hash_lookup(struct sw_table *swt, - const struct sw_flow_key *key) -{ - struct sw_flow *flow = *find_bucket(swt, key); - return flow && flow_keys_equal(&flow->key, key) ? flow : NULL; -} - -static int table_hash_insert(struct sw_table *swt, struct sw_flow *flow) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - struct sw_flow **bucket; - int retval; - - if (flow->key.wildcards != 0) - return 0; - - bucket = find_bucket(swt, &flow->key); - if (*bucket == NULL) { - th->n_flows++; - rcu_assign_pointer(*bucket, flow); - retval = 1; - } else { - struct sw_flow *old_flow = *bucket; - if (flow_keys_equal(&old_flow->key, &flow->key)) { - rcu_assign_pointer(*bucket, flow); - flow_deferred_free(old_flow); - retval = 1; - } else { - retval = 0; - } - } - return retval; -} - -static int table_hash_modify(struct sw_table *swt, - const struct sw_flow_key *key, uint16_t priority, int strict, - const struct ofp_action_header *actions, size_t actions_len) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - unsigned int count = 0; - - if (key->wildcards == 0) { - struct sw_flow **bucket = find_bucket(swt, key); - struct sw_flow *flow = *bucket; - if (flow && flow_matches_desc(&flow->key, key, strict) - && (!strict || (flow->priority == priority))) { - flow_replace_acts(flow, actions, actions_len); - count = 1; - } - } else { - unsigned int i; - - for (i = 0; i <= th->bucket_mask; i++) { - struct sw_flow **bucket = &th->buckets[i]; - struct sw_flow *flow = *bucket; - if (flow && flow_matches_desc(&flow->key, key, strict) - && (!strict || (flow->priority == priority))) { - flow_replace_acts(flow, actions, actions_len); - count++; - } - } - } - return count; -} - -static int table_hash_has_conflict(struct sw_table *swt, - const struct sw_flow_key *key, - uint16_t priority, int strict) -{ - struct sw_table_hash *th = (struct sw_table_hash *)swt; - - if (key->wildcards == 0) { - struct sw_flow **bucket = find_bucket(swt, key); - struct sw_flow *flow = *bucket; - if (flow && flow_matches_2desc(&flow->key, key,strict) - && (flow->priority == priority)) { - return true; - } - } else { - unsigned int i; - - for (i = 0; i <= th->bucket_mask; i++) { - struct sw_flow **bucket = &th->buckets[i]; - struct sw_flow *flow = *bucket; - if (flow && flow_matches_2desc(&flow->key, key, strict) - && (flow->priority == priority)) { - return true; - } - } - } - return false; -} - -/* Caller must update n_flows. */ -static int do_delete(struct datapath *dp, struct sw_flow **bucket, - struct sw_flow *flow, enum ofp_flow_removed_reason reason) -{ - dp_send_flow_end(dp, flow, reason); - rcu_assign_pointer(*bucket, NULL); - flow_deferred_free(flow); - return 1; -} - -/* Returns number of deleted flows. We can ignore the priority - * argument, since all exact-match entries are the same (highest) - * priority. */ -static int table_hash_delete(struct datapath *dp, struct sw_table *swt, - const struct sw_flow_key *key, uint16_t out_port, - uint16_t priority, int strict) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - unsigned int count = 0; - - if (key->wildcards == 0) { - struct sw_flow **bucket = find_bucket(swt, key); - struct sw_flow *flow = *bucket; - if (flow && flow_keys_equal(&flow->key, key) - && flow_has_out_port(flow, out_port)) - count = do_delete(dp, bucket, flow, OFPRR_DELETE); - } else { - unsigned int i; - - for (i = 0; i <= th->bucket_mask; i++) { - struct sw_flow **bucket = &th->buckets[i]; - struct sw_flow *flow = *bucket; - if (flow && flow_matches_desc(&flow->key, key, strict) - && flow_has_out_port(flow, out_port)) - count += do_delete(dp, bucket, flow, OFPRR_DELETE); - } - } - th->n_flows -= count; - return count; -} - -static int table_hash_timeout(struct datapath *dp, struct sw_table *swt) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - unsigned int i; - int count = 0; - - if (mutex_lock_interruptible(&dp_mutex)) - return 0; - for (i = 0; i <= th->bucket_mask; i++) { - struct sw_flow **bucket = &th->buckets[i]; - struct sw_flow *flow = *bucket; - if (flow) { - int reason = flow_timeout(flow); - if (reason >= 0) { - count += do_delete(dp, bucket, flow, reason); - } - } - } - th->n_flows -= count; - mutex_unlock(&dp_mutex); - - return count; -} - -static void table_hash_destroy(struct sw_table *swt) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - unsigned int i; - for (i = 0; i <= th->bucket_mask; i++) - if (th->buckets[i]) - flow_free(th->buckets[i]); - kmem_free(th->buckets, (th->bucket_mask + 1) * sizeof *th->buckets); - kfree(th); -} - -static int table_hash_iterate(struct sw_table *swt, - const struct sw_flow_key *key, uint16_t out_port, - struct sw_table_position *position, - int (*callback)(struct sw_flow *, void *private), - void *private) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - - if (position->private[0] > th->bucket_mask) - return 0; - - if (key->wildcards == 0) { - struct sw_flow *flow; - int error; - - flow = table_hash_lookup(swt, key); - if (!flow || !flow_has_out_port(flow, out_port)) - return 0; - - error = callback(flow, private); - if (!error) - position->private[0] = -1; - return error; - } else { - int i; - - for (i = position->private[0]; i <= th->bucket_mask; i++) { - struct sw_flow *flow = th->buckets[i]; - if (flow && flow_matches_1wild(&flow->key, key) - && flow_has_out_port(flow, out_port)) { - int error = callback(flow, private); - if (error) { - position->private[0] = i; - return error; - } - } - } - return 0; - } -} -static void table_hash_stats(struct sw_table *swt, - struct sw_table_stats *stats) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - stats->name = "hash"; - stats->wildcards = 0; /* No wildcards are supported. */ - stats->n_flows = th->n_flows; - stats->max_flows = th->bucket_mask + 1; - stats->n_lookup = swt->n_lookup; - stats->n_matched = swt->n_matched; -} - -struct sw_table *table_hash_create(unsigned int polynomial, - unsigned int n_buckets) -{ - struct sw_table_hash *th; - struct sw_table *swt; - - th = kzalloc(sizeof *th, GFP_KERNEL); - if (th == NULL) - return NULL; - - BUG_ON(n_buckets & (n_buckets - 1)); - th->buckets = kmem_zalloc(n_buckets * sizeof *th->buckets); - if (th->buckets == NULL) { - printk(KERN_EMERG "failed to allocate %u buckets\n", - n_buckets); - kfree(th); - return NULL; - } - th->bucket_mask = n_buckets - 1; - - swt = &th->swt; - swt->lookup = table_hash_lookup; - swt->insert = table_hash_insert; - swt->has_conflict = table_hash_has_conflict; - swt->delete = table_hash_delete; - swt->timeout = table_hash_timeout; - swt->destroy = table_hash_destroy; - swt->iterate = table_hash_iterate; - swt->stats = table_hash_stats; - - crc32_init(&th->crc32, polynomial); - th->n_flows = 0; - - return swt; -} - -/* Double-hashing table. */ - -struct sw_table_hash2 { - struct sw_table swt; - struct sw_table *subtable[2]; -}; - -static struct sw_flow *table_hash2_lookup(struct sw_table *swt, - const struct sw_flow_key *key) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - int i; - - for (i = 0; i < 2; i++) { - struct sw_flow *flow = *find_bucket(t2->subtable[i], key); - if (flow && flow_keys_equal(&flow->key, key)) - return flow; - } - return NULL; -} - -static int table_hash2_insert(struct sw_table *swt, struct sw_flow *flow) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - - if (table_hash_insert(t2->subtable[0], flow)) - return 1; - return table_hash_insert(t2->subtable[1], flow); -} - -static int table_hash2_modify(struct sw_table *swt, - const struct sw_flow_key *key, uint16_t priority, int strict, - const struct ofp_action_header *actions, size_t actions_len) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - return (table_hash_modify(t2->subtable[0], key, priority, strict, - actions, actions_len) - + table_hash_modify(t2->subtable[1], key, priority, strict, - actions, actions_len)); -} - -static int table_hash2_has_conflict(struct sw_table *swt, - const struct sw_flow_key *key, - uint16_t priority, int strict) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - return (table_hash_has_conflict(t2->subtable[0], key, priority, strict) || - table_hash_has_conflict(t2->subtable[1], key, priority, strict)); -} - -static int table_hash2_delete(struct datapath *dp, struct sw_table *swt, - const struct sw_flow_key *key, - uint16_t out_port, - uint16_t priority, int strict) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - return (table_hash_delete(dp, t2->subtable[0], key, out_port, - priority, strict) - + table_hash_delete(dp, t2->subtable[1], key, out_port, - priority, strict)); -} - -static int table_hash2_timeout(struct datapath *dp, struct sw_table *swt) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - return (table_hash_timeout(dp, t2->subtable[0]) - + table_hash_timeout(dp, t2->subtable[1])); -} - -static void table_hash2_destroy(struct sw_table *swt) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - table_hash_destroy(t2->subtable[0]); - table_hash_destroy(t2->subtable[1]); - kfree(t2); -} - -static int table_hash2_iterate(struct sw_table *swt, - const struct sw_flow_key *key, uint16_t out_port, - struct sw_table_position *position, - int (*callback)(struct sw_flow *, void *), - void *private) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - int i; - - for (i = position->private[1]; i < 2; i++) { - int error = table_hash_iterate(t2->subtable[i], key, out_port, - position, callback, private); - if (error) { - return error; - } - position->private[0] = 0; - position->private[1]++; - } - return 0; -} - -static void table_hash2_stats(struct sw_table *swt, - struct sw_table_stats *stats) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - struct sw_table_stats substats[2]; - int i; - - for (i = 0; i < 2; i++) - table_hash_stats(t2->subtable[i], &substats[i]); - stats->name = "hash2"; - stats->wildcards = 0; /* No wildcards are supported. */ - stats->n_flows = substats[0].n_flows + substats[1].n_flows; - stats->max_flows = substats[0].max_flows + substats[1].max_flows; - stats->n_lookup = swt->n_lookup; - stats->n_matched = swt->n_matched; -} - -struct sw_table *table_hash2_create(unsigned int poly0, unsigned int buckets0, - unsigned int poly1, unsigned int buckets1) - -{ - struct sw_table_hash2 *t2; - struct sw_table *swt; - - t2 = kzalloc(sizeof *t2, GFP_KERNEL); - if (t2 == NULL) - return NULL; - - t2->subtable[0] = table_hash_create(poly0, buckets0); - if (t2->subtable[0] == NULL) - goto out_free_t2; - - t2->subtable[1] = table_hash_create(poly1, buckets1); - if (t2->subtable[1] == NULL) - goto out_free_subtable0; - - swt = &t2->swt; - swt->lookup = table_hash2_lookup; - swt->insert = table_hash2_insert; - swt->modify = table_hash2_modify; - swt->has_conflict = table_hash2_has_conflict; - swt->delete = table_hash2_delete; - swt->timeout = table_hash2_timeout; - swt->destroy = table_hash2_destroy; - swt->iterate = table_hash2_iterate; - swt->stats = table_hash2_stats; - - return swt; - -out_free_subtable0: - table_hash_destroy(t2->subtable[0]); -out_free_t2: - kfree(t2); - return NULL; -} - -/* From fs/xfs/linux-2.4/kmem.c. */ - -static void * -kmem_alloc(size_t size) -{ - void *ptr; - -#ifdef KMALLOC_MAX_SIZE - if (size > KMALLOC_MAX_SIZE) - return NULL; -#endif - ptr = kmalloc(size, GFP_KERNEL); - if (!ptr) { - ptr = vmalloc(size); - if (ptr) - printk(KERN_NOTICE "openflow: used vmalloc for %lu " - "bytes\n", (unsigned long)size); - } - return ptr; -} - -static void * -kmem_zalloc(size_t size) -{ - void *ptr = kmem_alloc(size); - if (ptr) - memset(ptr, 0, size); - return ptr; -} - -static void -kmem_free(void *ptr, size_t size) -{ - if (((unsigned long)ptr < VMALLOC_START) || - ((unsigned long)ptr >= VMALLOC_END)) { - kfree(ptr); - } else { - vfree(ptr); - } -} diff --git a/openflow/datapath/table-linear.c b/openflow/datapath/table-linear.c deleted file mode 100644 index 79a95dfb..00000000 --- a/openflow/datapath/table-linear.c +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Distributed under the terms of the GNU GPL version 2. - * Copyright (c) 2007, 2008, 2009 The Board of Trustees of The Leland - * Stanford Junior University - */ - -#include "table.h" -#include "flow.h" -#include "datapath.h" - -#include -#include -#include - -struct sw_table_linear { - struct sw_table swt; - - unsigned int max_flows; - unsigned int n_flows; - struct list_head flows; - struct list_head iter_flows; - unsigned long int next_serial; -}; - -static struct sw_flow *table_linear_lookup(struct sw_table *swt, - const struct sw_flow_key *key) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - struct sw_flow *flow; - list_for_each_entry_rcu (flow, &tl->flows, node) { - if (flow_matches_1wild(key, &flow->key)) - return flow; - } - return NULL; -} - -static int table_linear_insert(struct sw_table *swt, struct sw_flow *flow) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - struct sw_flow *f; - - - /* Loop through the existing list of entries. New entries will - * always be placed behind those with equal priority. Just replace - * any flows that match exactly. - */ - list_for_each_entry (f, &tl->flows, node) { - if (f->priority == flow->priority - && f->key.wildcards == flow->key.wildcards - && flow_matches_2wild(&f->key, &flow->key)) { - flow->serial = f->serial; - list_replace_rcu(&f->node, &flow->node); - list_replace_rcu(&f->iter_node, &flow->iter_node); - flow_deferred_free(f); - return 1; - } - - if (f->priority < flow->priority) - break; - } - - /* Make sure there's room in the table. */ - if (tl->n_flows >= tl->max_flows) { - return 0; - } - tl->n_flows++; - - /* Insert the entry immediately in front of where we're pointing. */ - flow->serial = tl->next_serial++; - list_add_tail_rcu(&flow->node, &f->node); - list_add_rcu(&flow->iter_node, &tl->iter_flows); - return 1; -} - -static int table_linear_modify(struct sw_table *swt, - const struct sw_flow_key *key, uint16_t priority, int strict, - const struct ofp_action_header *actions, size_t actions_len) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - struct sw_flow *flow; - unsigned int count = 0; - - list_for_each_entry (flow, &tl->flows, node) { - if (flow_matches_desc(&flow->key, key, strict) - && (!strict || (flow->priority == priority))) { - flow_replace_acts(flow, actions, actions_len); - count++; - } - } - return count; -} - -static int table_linear_has_conflict(struct sw_table *swt, - const struct sw_flow_key *key, uint16_t priority, int strict) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - struct sw_flow *flow; - - list_for_each_entry (flow, &tl->flows, node) { - if (flow_matches_2desc(&flow->key, key, strict) - && (flow->priority == priority)) { - return true; - } - } - return false; -} - -static int do_delete(struct datapath *dp, struct sw_table *swt, - struct sw_flow *flow, enum ofp_flow_removed_reason reason) -{ - dp_send_flow_end(dp, flow, reason); - list_del_rcu(&flow->node); - list_del_rcu(&flow->iter_node); - flow_deferred_free(flow); - return 1; -} - -static int table_linear_delete(struct datapath *dp, struct sw_table *swt, - const struct sw_flow_key *key, uint16_t out_port, - uint16_t priority, int strict) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - struct sw_flow *flow; - unsigned int count = 0; - - list_for_each_entry (flow, &tl->flows, node) { - if (flow_matches_desc(&flow->key, key, strict) - && flow_has_out_port(flow, out_port) - && (!strict || (flow->priority == priority))) - count += do_delete(dp, swt, flow, OFPRR_DELETE); - } - tl->n_flows -= count; - return count; -} - -static int table_linear_timeout(struct datapath *dp, struct sw_table *swt) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - struct sw_flow *flow; - int count = 0; - - if (mutex_lock_interruptible(&dp_mutex)) - return 0; - list_for_each_entry (flow, &tl->flows, node) { - int reason = flow_timeout(flow); - if (reason >= 0) { - count += do_delete(dp, swt, flow, reason); - } - } - tl->n_flows -= count; - mutex_unlock(&dp_mutex); - return count; -} - -static void table_linear_destroy(struct sw_table *swt) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - - while (!list_empty(&tl->flows)) { - struct sw_flow *flow = list_entry(tl->flows.next, - struct sw_flow, node); - list_del(&flow->node); - flow_free(flow); - } - kfree(tl); -} - -static int table_linear_iterate(struct sw_table *swt, - const struct sw_flow_key *key, uint16_t out_port, - struct sw_table_position *position, - int (*callback)(struct sw_flow *, void *), - void *private) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - struct sw_flow *flow; - unsigned long start; - - start = position->private[0]; - list_for_each_entry (flow, &tl->iter_flows, iter_node) { - if (flow->serial >= start - && flow_matches_2wild(key, &flow->key) - && flow_has_out_port(flow, out_port)) { - int error = callback(flow, private); - if (error) { - position->private[0] = flow->serial; - return error; - } - } - } - return 0; -} - -static void table_linear_stats(struct sw_table *swt, - struct sw_table_stats *stats) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - stats->name = "linear"; - stats->wildcards = OFPFW_ALL; - stats->n_flows = tl->n_flows; - stats->max_flows = tl->max_flows; - stats->n_lookup = swt->n_lookup; - stats->n_matched = swt->n_matched; -} - - -struct sw_table *table_linear_create(unsigned int max_flows) -{ - struct sw_table_linear *tl; - struct sw_table *swt; - - tl = kzalloc(sizeof *tl, GFP_KERNEL); - if (tl == NULL) - return NULL; - - swt = &tl->swt; - swt->lookup = table_linear_lookup; - swt->insert = table_linear_insert; - swt->modify = table_linear_modify; - swt->has_conflict = table_linear_has_conflict; - swt->delete = table_linear_delete; - swt->timeout = table_linear_timeout; - swt->destroy = table_linear_destroy; - swt->iterate = table_linear_iterate; - swt->stats = table_linear_stats; - - tl->max_flows = max_flows; - tl->n_flows = 0; - INIT_LIST_HEAD(&tl->flows); - INIT_LIST_HEAD(&tl->iter_flows); - tl->next_serial = 0; - - return swt; -} diff --git a/openflow/datapath/table.h b/openflow/datapath/table.h deleted file mode 100644 index 1cc90a01..00000000 --- a/openflow/datapath/table.h +++ /dev/null @@ -1,119 +0,0 @@ -/* Individual switching tables. Generally grouped together in a chain (see - * chain.h). */ - -#ifndef TABLE_H -#define TABLE_H 1 - -#include - -struct sw_flow; -struct sw_flow_key; -struct ofp_action_header; -struct datapath; - -/* Table statistics. */ -struct sw_table_stats { - const char *name; /* Human-readable name. */ - uint32_t wildcards; /* Bitmap of OFPFW_* wildcards that are - supported by the table. */ - unsigned int n_flows; /* Number of active flows. */ - unsigned int max_flows; /* Flow capacity. */ - unsigned long int n_lookup; /* Number of packets looked up. */ - unsigned long int n_matched; /* Number of packets that have hit. */ -}; - -/* Position within an iteration of a sw_table. - * - * The contents are private to the table implementation, except that a position - * initialized to all-zero-bits represents the start of a table. */ -struct sw_table_position { - unsigned long private[4]; -}; - -/* A single table of flows. - * - * All functions, except destroy, must be called holding the - * rcu_read_lock. destroy must be fully serialized. - */ -struct sw_table { - /* The number of packets that have been looked up and matched, - * respecitvely. To make these 100% accurate, they should be atomic. - * However, we're primarily concerned about speed. */ - unsigned long long n_lookup; - unsigned long long n_matched; - - /* Searches 'table' for a flow matching 'key', which must not have any - * wildcard fields. Returns the flow if successful, a null pointer - * otherwise. */ - struct sw_flow *(*lookup)(struct sw_table *table, - const struct sw_flow_key *key); - - /* Inserts 'flow' into 'table', replacing any duplicate flow. Returns - * 0 if successful or a negative error. Error can be due to an - * over-capacity table or because the flow is not one of the kind that - * the table accepts. - * - * If successful, 'flow' becomes owned by 'table', otherwise it is - * retained by the caller. */ - int (*insert)(struct sw_table *table, struct sw_flow *flow); - - /* Modifies the actions in 'table' that match 'key'. If 'strict' - * set, wildcards and priority must match. Returns the number of flows - * that were modified. */ - int (*modify)(struct sw_table *table, const struct sw_flow_key *key, - uint16_t priority, int strict, - const struct ofp_action_header *actions, size_t actions_len); - - /* Checks whether 'table' has an equal priotiry entry of thethat conflicts - * with 'key'. If 'strict' is set, wildcards must match. - * Returns the number of flows that were modified. */ - int (*has_conflict)(struct sw_table *table, const struct sw_flow_key *key, - uint16_t priority, int strict); - - /* Deletes from 'table' any and all flows that match 'key' from - * 'table'. If 'out_port' is not OFPP_NONE, then matching entries - * must have that port as an argument for an output action. If - * 'strict' is set, wildcards and priority must match. Returns the - * number of flows that were deleted. */ - int (*delete)(struct datapath *dp, struct sw_table *table, - const struct sw_flow_key *key, - uint16_t out_port, uint16_t priority, int strict); - - /* Performs timeout processing on all the flow entries in 'table'. - * Returns the number of flow entries deleted through expiration. */ - int (*timeout)(struct datapath *dp, struct sw_table *table); - - /* Destroys 'table', which must not have any users. */ - void (*destroy)(struct sw_table *table); - - /* Iterates through the flow entries in 'table', passing each one - * matches 'key' and output port 'out_port' to 'callback'. The - * callback function should return 0 to continue iteration or a - * nonzero error code to stop. The iterator function returns either - * 0 if the table iteration completed or the value returned by the - * callback function otherwise. - * - * The iteration starts at 'position', which may be initialized to - * all-zero-bits to iterate from the beginning of the table. If the - * iteration terminates due to an error from the callback function, - * 'position' is updated to a value that can be passed back to the - * iterator function to continue iteration later from the same position - * that caused the error (assuming that that flow entry has not been - * deleted in the meantime). */ - int (*iterate)(struct sw_table *table, - const struct sw_flow_key *key, uint16_t out_port, - struct sw_table_position *position, - int (*callback)(struct sw_flow *flow, void *private), - void *private); - - /* Dumps statistics for 'table' into 'stats'. */ - void (*stats)(struct sw_table *table, struct sw_table_stats *stats); -}; - -struct sw_table *table_hash_create(unsigned int polynomial, - unsigned int n_buckets); -struct sw_table *table_hash2_create(unsigned int poly0, unsigned int buckets0, - unsigned int poly1, unsigned int buckets1); -struct sw_table *table_linear_create(unsigned int max_flows); - -#endif /* table.h */ diff --git a/openflow/debian/.gitignore b/openflow/debian/.gitignore deleted file mode 100644 index 1df6fba1..00000000 --- a/openflow/debian/.gitignore +++ /dev/null @@ -1,38 +0,0 @@ -*.debhelper -*.debhelper.log -*.substvars -/automake.mk -/control -/corekeeper -/files -/nicira-switch -/openflow -/openflow-common -/openflow-common.copyright -/openflow-controller -/openflow-datapath-source -/openflow-dbg -/openflow-monitor -/openflow-monitor.copyright -/openflow-monitor.default -/openflow-monitor.dirs -/openflow-monitor.init -/openflow-monitor.install -/openflow-pki -/openflow-pki-server -/openflow-switch -/openflow-switch-config -/openflow-switch.copyright -/openflow-switchui -/openflow-switchui.copyright -/openflow-switchui.default -/openflow-switchui.dirs -/openflow-switchui.init -/openflow-switchui.install -/openflow-wdt -/openflow-wdt.copyright -/openflow-wdt.default -/openflow-wdt.dirs -/openflow-wdt.init -/openflow-wdt.install -/rules.ext diff --git a/openflow/debian/changelog b/openflow/debian/changelog deleted file mode 100644 index 235187e5..00000000 --- a/openflow/debian/changelog +++ /dev/null @@ -1,23 +0,0 @@ -openflow (1.0.0) unstable; urgency=low - - * Development version - - -- OpenFlow team Thu, 31 Dec 2009 23:59:59 -0800 - -openflow (0.9.0-rev1) unstable; urgency=low - - * Development version. - - -- OpenFlow team Fri, 04 Sep 2009 12:00:00 -0800 - -openflow (0.8.9-rev4) unstable; urgency=low - - * Develoment version. - - -- OpenFlow team Tue, 15 Sep 2009 12:00:00 -0800 - -openflow (0.8.1) unstable; urgency=low - - * Development version. - - -- OpenFlow team Mon, 19 Nov 2007 14:57:52 -0800 diff --git a/openflow/debian/commands/reconfigure b/openflow/debian/commands/reconfigure deleted file mode 100755 index a9610524..00000000 --- a/openflow/debian/commands/reconfigure +++ /dev/null @@ -1,128 +0,0 @@ -#! /usr/bin/perl - -use POSIX; -use strict; -use warnings; - -my $default = '/etc/default/openflow-switch'; - -my (%config) = load_config($default); -if (@ARGV) { - foreach my $arg (@ARGV) { - my ($key, $value) = $arg =~ /^([^=]+)=(.*)/ - or die "bad argument '$arg'\n"; - if ($value ne '') { - $config{$key} = $value; - } else { - delete $config{$key}; - } - } - save_config($default, %config); -} -print "$_=$config{$_}\n" foreach sort(keys(%config)); - -sub load_config { - my ($file) = @_; - - # Get the list of the variables that the shell sets automatically. - my (%auto_vars) = read_vars("set -a && env"); - - # Get the variables from $default. - my (%config) = read_vars("set -a && . '$default' && env"); - - # Subtract. - delete @config{keys %auto_vars}; - - return %config; -} - -sub read_vars { - my ($cmd) = @_; - local @ENV; - if (!open(VARS, '-|', $cmd)) { - print STDERR "$cmd: failed to execute: $!\n"; - return (); - } - my (%config); - while () { - my ($var, $value) = /^([^=]+)=(.*)$/ or next; - $config{$var} = $value; - } - close(VARS); - return %config; -} - -sub shell_escape { - local $_ = $_[0]; - if ($_ eq '') { - return '""'; - } elsif (m&^[-a-zA-Z0-9:./%^_+,]*$&) { - return $_; - } else { - s/'/'\\''/; - return "'$_'"; - } -} - -sub shell_assign { - my ($var, $value) = @_; - return $var . '=' . shell_escape($value); -} - -sub save_config { - my ($file, %config) = @_; - my (@lines); - if (open(FILE, '<', $file)) { - @lines = ; - chomp @lines; - close(FILE); - } - - # Replace all existing variable assignments. - for (my ($i) = 0; $i <= $#lines; $i++) { - local $_ = $lines[$i]; - my ($var, $value) = /^\s*([^=#]+)=(.*)$/ or next; - if (exists($config{$var})) { - $lines[$i] = shell_assign($var, $config{$var}); - delete $config{$var}; - } else { - $lines[$i] = "#$lines[$i]"; - } - } - - # Find a place to put any remaining variable assignments. - VAR: - for my $var (keys(%config)) { - my $assign = shell_assign($var, $config{$var}); - - # Replace the last commented-out variable assignment to $var, if any. - for (my ($i) = $#lines; $i >= 0; $i--) { - local $_ = $lines[$i]; - if (/^\s*#\s*$var=/) { - $lines[$i] = $assign; - next VAR; - } - } - - # Find a place to add the var: after the final commented line - # just after a line that contains "$var:". - for (my ($i) = 0; $i <= $#lines; $i++) { - if ($lines[$i] =~ /^\s*#\s*$var:/) { - for (my ($j) = $i + 1; $j <= $#lines; $j++) { - if ($lines[$j] !~ /^\s*#/) { - splice(@lines, $j, 0, $assign); - next VAR; - } - } - } - } - - # Just append it. - push(@lines, $assign); - } - - open(NEWFILE, '>', "$file.tmp") or die "$file.tmp: create: $!\n"; - print NEWFILE join('', map("$_\n", @lines)); - close(NEWFILE); - rename("$file.tmp", $file) or die "$file.tmp: rename to $file: $!\n"; -} diff --git a/openflow/debian/commands/update b/openflow/debian/commands/update deleted file mode 100755 index 545e3c23..00000000 --- a/openflow/debian/commands/update +++ /dev/null @@ -1,4 +0,0 @@ -#! /bin/sh -set -e -apt-get update -qy -apt-get upgrade -qy diff --git a/openflow/debian/compat b/openflow/debian/compat deleted file mode 100644 index 7ed6ff82..00000000 --- a/openflow/debian/compat +++ /dev/null @@ -1 +0,0 @@ -5 diff --git a/openflow/debian/control.in b/openflow/debian/control.in deleted file mode 100644 index 2e14410d..00000000 --- a/openflow/debian/control.in +++ /dev/null @@ -1,93 +0,0 @@ -Source: openflow -Section: net -Priority: extra -Maintainer: OpenFlow Team -Build-Depends: debhelper (>= 5), autoconf (>= 2.60), automake1.10 | automake1.11 | automake (>= 1.10), libssl-dev, pkg-config (>= 0.21), po-debconf, bzip2, openssl, libncurses5-dev, libpcre3-dev -Standards-Version: 3.7.3 - -Package: openflow-datapath-source -Architecture: all -Depends: module-assistant, bzip2, debhelper (>= 5.0.37) -Suggests: openflow-switch -Description: Source code for OpenFlow datapath Linux module - This package provides the OpenFlow datapath module source code that - is needed by the kernel-based OpenFlow switch. The kernel module can - be built from it using module-assistant or make-kpkg. README.Debian - in this package provides further instructions. - . - OpenFlow is a protocol for flow-based control over network switching. - -Package: openflow-common -Architecture: any -Depends: ${shlibs:Depends}, openssl -Description: OpenFlow common components - openflow-common provides components required by both openflow-switch - and openflow-controller. - . - OpenFlow is a protocol for flow-based control over network switching. - -Package: openflow-switch -Architecture: any -Suggests: openflow-datapath-module -Depends: ${shlibs:Depends}, ${misc:Depends}, openflow-common, dhcp3-client, module-init-tools, dmidecode, procps, debianutils -Description: OpenFlow switch implementations - openflow-switch provides the userspace components and utilities for - the OpenFlow kernel-based switch. - . - OpenFlow is a protocol for flow-based control over network switching. - -Package: openflow-switch-config -Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, openflow-switch, libwww-perl, libdigest-sha1-perl -Description: OpenFlow switch implementations - openflow-switch-config provides a utility for interactively configuring - the OpenFlow switch provided in the openflow-switch package. - . - OpenFlow is a protocol for flow-based control over network switching. - -Package: openflow-pki -Architecture: all -Depends: ${shlibs:Depends}, ${misc:Depends}, openflow-common -Description: OpenFlow public key infrastructure - openflow-pki provides PKI (public key infrastructure) support for - OpenFlow switches and controllers, reducing the risk of - man-in-the-middle attacks on the OpenFlow network infrastructure. - . - OpenFlow is a protocol for flow-based control over network switching. - -Package: openflow-pki-server -Architecture: all -Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, openflow-pki, apache2 -Description: OpenFlow public key infrastructure (HTTP server support) - openflow-pki-server provides HTTP access to the OpenFlow PKI (public - key infrastructure) maintained on the local machine by the - openflow-pki package. This HTTP access is needed for secure and - convenient OpenFlow switch setup using the ofp-switch-setup program - in the openflow-switch package. - . - OpenFlow is a protocol for flow-based control over network switching. - -Package: openflow-controller -Architecture: any -Depends: ${shlibs:Depends}, openflow-common, openflow-pki -Description: OpenFlow controller implementation - The OpenFlow controller enables OpenFlow switches that connect to it - to act as MAC-learning Ethernet switches. - . - OpenFlow is a protocol for flow-based control over network switching. - -Package: corekeeper -Architecture: all -Depends: tmpreaper -Description: Core file centralizer and reaper - The corekeeper package configures the system to dump all core files to - /var/log/core. It also deletes core files older than 7 days. - -Package: openflow-dbg -Architecture: any -Depends: ${shlibs:Depends} -Description: Debug symbols for OpenFlow packages - This package contains the debug symbols for all the other openflow-* - packages. Install it to debug one of them or to examine a core dump - produced by one of them. - diff --git a/openflow/debian/control.modules.in b/openflow/debian/control.modules.in deleted file mode 100644 index cc149cac..00000000 --- a/openflow/debian/control.modules.in +++ /dev/null @@ -1,19 +0,0 @@ -Source: openflow -Section: net -Priority: extra -Maintainer: OpenFlow Team -Build-Depends: debhelper (>= 5.0.37) -Standards-Version: 3.7.3 - -Package: openflow-datapath-module-_KVERS_ -Architecture: any -Recommends: kernel-image-_KVERS_, openflow-switch -Provides: openflow-datapath-module -Description: OpenFlow Linux datapath kernel module - This package contains the OpenFlow loadable datapath kernel modules for - the kernel-image-_KVERS_ package. - . - If you compiled a custom kernel, you will most likely need to compile - a custom version of this module as well. The openflow-datapath-source - package has been provided for this purpose. Refer to README.Debian - provided in that package for further instructions. diff --git a/openflow/debian/copyright b/openflow/debian/copyright deleted file mode 100644 index b369ec39..00000000 --- a/openflow/debian/copyright +++ /dev/null @@ -1,38 +0,0 @@ -Upstream Authors: - - The Board of Trustees of The Leland Stanford Junior University - -Copyright: - - Copyright (C) 2008 The Board of Trustees of The Leland Stanford - Junior University - -License: - - We are making the OpenFlow specification and associated documentation - (Software) available for public use and benefit with the expectation - that others will use, modify and enhance the Software and contribute - those enhancements back to the community. However, since we would like - to make the Software available for broadest use, with as few - restrictions as possible permission is hereby granted, free of charge, - to any person obtaining a copy of this Software to deal in the Software - under the copyrights without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - The name and trademarks of copyright holder(s) may NOT be used in - advertising or publicity pertaining to the Software or any derivatives - without specific, written prior permission. - diff --git a/openflow/debian/corekeeper.cron.daily b/openflow/debian/corekeeper.cron.daily deleted file mode 100755 index badc192d..00000000 --- a/openflow/debian/corekeeper.cron.daily +++ /dev/null @@ -1,5 +0,0 @@ -#! /bin/sh - -PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin - -tmpreaper 7d --mtime --all /var/log/core diff --git a/openflow/debian/corekeeper.init b/openflow/debian/corekeeper.init deleted file mode 100755 index 27d62a12..00000000 --- a/openflow/debian/corekeeper.init +++ /dev/null @@ -1,63 +0,0 @@ -#!/bin/sh -# -# Example init.d script with LSB support. -# -# Please read this init.d carefully and modify the sections to -# adjust it to the program you want to run. -# -# Copyright (c) 2007 Javier Fernandez-Sanguino -# -# This is free software; you may redistribute it and/or modify -# it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 2, -# or (at your option) any later version. -# -# This is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License with -# the Debian operating system, in /usr/share/common-licenses/GPL; if -# not, write to the Free Software Foundation, Inc., 59 Temple Place, -# Suite 330, Boston, MA 02111-1307 USA -# -### BEGIN INIT INFO -# Provides: corekeeper -# Required-Start: -# Required-Stop: -# Should-Start: $syslog -# Should-Stop: -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: Configure core file dump location -### END INIT INFO - -PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin - -. /lib/lsb/init-functions - -set -e - -case "$1" in - start) - log_daemon_msg "Initializing core dump location..." - if echo "/var/log/core/core.%e.%t" > /proc/sys/kernel/core_pattern - then - log_progress_msg "success" - log_end_msg 0 - exit 0 - else - log_end_msg 1 - exit 1 - fi - ;; - stop|restart|force-reload|status|reload) - exit 0 - ;; - *) - N=/etc/init.d/$NAME - echo "Usage: $N {start|stop|restart|force-reload|status}" >&2 - exit 1 - ;; -esac diff --git a/openflow/debian/dirs b/openflow/debian/dirs deleted file mode 100644 index ca882bbb..00000000 --- a/openflow/debian/dirs +++ /dev/null @@ -1,2 +0,0 @@ -usr/bin -usr/sbin diff --git a/openflow/debian/ofp-switch-setup b/openflow/debian/ofp-switch-setup deleted file mode 100755 index 5a999ab4..00000000 --- a/openflow/debian/ofp-switch-setup +++ /dev/null @@ -1,615 +0,0 @@ -#! /usr/bin/perl - -use POSIX; -use Debconf::Client::ConfModule ':all'; -use HTTP::Request; -use LWP::UserAgent; -use Digest::SHA1 'sha1_hex'; -use strict; -use warnings; - -# XXX should support configuring SWITCH_NETMASK and SWITCH_GATEWAY -# when the mode is in-band. - -my $debconf_owner = 'openflow-switch'; - -my $default = '/etc/default/openflow-switch'; -my $template = '/usr/share/openflow/switch/default.template'; -my $etc = '/etc/openflow-switch'; -my $rundir = '/var/run'; -my $privkey_file = "$etc/of0-privkey.pem"; -my $req_file = "$etc/of0-req.pem"; -my $cert_file = "$etc/of0-cert.pem"; -my $cacert_file = "$etc/cacert.pem"; -my $ofp_discover_pidfile = "$rundir/ofp-discover.pid"; - -my $ua = LWP::UserAgent->new; -$ua->timeout(10); -$ua->env_proxy; - -system("/etc/init.d/openflow-switch stop 1>&2"); -kill_ofp_discover(); - -version('2.0'); -capb('backup'); -title('OpenFlow Switch Setup'); - -my (%netdevs) = find_netdevs(); -db_subst('netdevs', 'choices', - join(', ', map($netdevs{$_}, sort(keys(%netdevs))))); -db_set('netdevs', join(', ', grep(!/IP/, values(%netdevs)))); - -my %oldconfig; -if (-e $default) { - %oldconfig = load_config($default); - - my (%map) = - (NETDEVS => sub { - db_set('netdevs', join(', ', map($netdevs{$_}, - grep(exists $netdevs{$_}, split)))) - }, - MODE => sub { - db_set('mode', - $_ eq 'in-band' || $_ eq 'out-of-band' ? $_ : 'discovery') - }, - SWITCH_IP => sub { db_set('switch-ip', $_) }, - CONTROLLER => sub { db_set('controller-vconn', $_) }, - PRIVKEY => sub { $privkey_file = $_ }, - CERT => sub { $cert_file = $_ }, - CACERT => sub { $cacert_file = $_ }, - ); - - for my $key (keys(%map)) { - local $_ = $oldconfig{$key}; - &{$map{$key}}() if defined && !/^\s*$/; - } -} elsif (-e $template) { - %oldconfig = load_config($template); -} - -my $cacert_preverified = -e $cacert_file; -my ($req, $req_fingerprint); - -my %options; - -my (@states) = - (sub { - # User backed up from first dialog box. - exit(10); - }, - sub { - # Prompt for ports to include in switch. - db_input('netdevs'); - return; - }, - sub { - # Validate the chosen ports. - my (@netdevs) = split(', ', db_get('netdevs')); - if (!@netdevs) { - # No ports chosen. Disable switch. - db_input('no-netdevs'); - return 'prev' if db_go(); - return 'done'; - } elsif (my (@conf_netdevs) = grep(/IP/, @netdevs)) { - # Point out that some ports have configured IP addresses. - db_subst('configured-netdevs', 'configured-netdevs', - join(', ', @conf_netdevs)); - db_input('configured-netdevs'); - return; - } else { - # Otherwise proceed. - return 'skip'; - } - }, - sub { - # Discovery or in-band or out-of-band controller? - db_input('mode'); - return; - }, - sub { - return 'skip' if db_get('mode') ne 'discovery'; - for (;;) { - # Notify user that we are going to do discovery. - db_input('discover'); - return 'prev' if db_go(); - print STDERR "Please wait up to 30 seconds for discovery...\n"; - - # Make sure that there's no running discovery process. - kill_ofp_discover(); - - # Do discovery. - %options = (); - open(DISCOVER, '-|', 'ofp-discover --timeout=30 --pidfile ' - . join(' ', netdev_names())); - while () { - chomp; - if (my ($name, $value) = /^([^=]+)=(.*)$/) { - if ($value =~ /^"(.*)"$/) { - $value = $1; - $value =~ s/\\([0-7][0-7][0-7])/chr($1)/ge; - } else { - $value =~ s/^(0x[[:xdigit:]]+)$/hex($1)/e; - $value = '' if $value eq 'empty'; - next if $value eq 'null'; # Shouldn't happen. - } - $options{$name} = $value; - } - last if /^$/; - } - - # Check results. - my $vconn = $options{'ofp-controller-vconn'}; - my $pki_uri = $options{'ofp-pki-uri'}; - return 'next' - if (defined($vconn) - && is_valid_vconn($vconn) - && (!is_ssl_vconn($vconn) || defined($pki_uri))); - - # Try again? - kill_ofp_discover(); - db_input('discovery-failure'); - db_go(); - } - }, - sub { - return 'skip' if db_get('mode') ne 'discovery'; - - my $vconn = $options{'ofp-controller-vconn'}; - my $pki_uri = $options{'ofp-pki-uri'}; - db_subst('discovery-success', 'controller-vconn', $vconn); - db_subst('discovery-success', - 'pki-uri', is_ssl_vconn($vconn) ? $pki_uri : "no PKI in use"); - db_input('discovery-success'); - return 'prev' if db_go(); - db_set('controller-vconn', $vconn); - db_set('pki-uri', $pki_uri); - return 'next'; - }, - sub { - return 'skip' if db_get('mode') ne 'in-band'; - for (;;) { - db_input('switch-ip'); - return 'prev' if db_go(); - - my $ip = db_get('switch-ip'); - return 'next' if $ip =~ /^dhcp|\d+\.\d+.\d+.\d+$/i; - - db_input('switch-ip-error'); - db_go(); - } - }, - sub { - return 'skip' if db_get('mode') eq 'discovery'; - for (;;) { - my $old_vconn = db_get('controller-vconn'); - db_input('controller-vconn'); - return 'prev' if db_go(); - - my $vconn = db_get('controller-vconn'); - if (is_valid_vconn($vconn)) { - if ($old_vconn ne $vconn || db_get('pki-uri') eq '') { - db_set('pki-uri', pki_host_to_uri($2)); - } - return 'next'; - } - - db_input('controller-vconn-error'); - db_go(); - } - }, - sub { - return 'skip' if !ssl_enabled(); - - if (! -e $privkey_file) { - my $old_umask = umask(077); - run_cmd("ofp-pki req $etc/of0 >&2 2>/dev/null"); - chmod(0644, $req_file) or die "$req_file: chmod: $!\n"; - umask($old_umask); - } - - if (! -e $cert_file) { - open(REQ, '<', $req_file) or die "$req_file: open: $!\n"; - $req = join('', ); - close(REQ); - $req_fingerprint = sha1_hex($req); - } - return 'skip'; - }, - sub { - return 'skip' if !ssl_enabled(); - return 'skip' if -e $cacert_file && -e $cert_file; - - db_input('pki-uri'); - return 'prev' if db_go(); - return; - }, - sub { - return 'skip' if !ssl_enabled(); - return 'skip' if -e $cacert_file; - - my $pki_uri = db_get('pki-uri'); - if ($pki_uri !~ /:/) { - $pki_uri = pki_host_to_uri($pki_uri); - } else { - # Trim trailing slashes. - $pki_uri =~ s%/+$%%; - } - db_set('pki-uri', $pki_uri); - - my $url = "$pki_uri/controllerca/cacert.pem"; - my $response = $ua->get($url, ':content_file' => $cacert_file); - if ($response->is_success) { - return 'next'; - } - - db_subst('fetch-cacert-failed', 'url', $url); - db_subst('fetch-cacert-failed', 'error', $response->status_line); - db_subst('fetch-cacert-failed', 'pki-uri', $pki_uri); - db_input('fetch-cacert-failed'); - db_go(); - return 'prev'; - }, - sub { - return 'skip' if !ssl_enabled(); - return 'skip' if -e $cert_file; - - for (;;) { - db_set('send-cert-req', 'yes'); - db_input('send-cert-req'); - return 'prev' if db_go(); - return 'next' if db_get('send-cert-req') eq 'no'; - - my $pki_uri = db_get('pki-uri'); - my ($pki_base_uri) = $pki_uri =~ m%^([^/]+://[^/]+)/%; - my $url = "$pki_base_uri/cgi-bin/ofp-pki-cgi"; - my $response = $ua->post($url, {'type' => 'switch', - 'req' => $req}); - return 'next' if $response->is_success; - - db_subst('send-cert-req-failed', 'url', $url); - db_subst('send-cert-req-failed', 'error', - $response->status_line); - db_subst('send-cert-req-failed', 'pki-uri', $pki_uri); - db_input('send-cert-req-failed'); - db_go(); - } - }, - sub { - return 'skip' if !ssl_enabled(); - return 'skip' if $cacert_preverified; - - my ($cacert_fingerprint) = x509_fingerprint($cacert_file); - db_subst('verify-controller-ca', 'fingerprint', $cacert_fingerprint); - db_input('verify-controller-ca'); - return 'prev' if db_go(); - return 'next' if db_get('verify-controller-ca') eq 'yes'; - unlink($cacert_file); - return 'prev'; - }, - sub { - return 'skip' if !ssl_enabled(); - return 'skip' if -e $cert_file; - - for (;;) { - db_set('fetch-switch-cert', 'yes'); - db_input('fetch-switch-cert'); - return 'prev' if db_go(); - exit(1) if db_get('fetch-switch-cert') eq 'no'; - - my $pki_uri = db_get('pki-uri'); - my $url = "$pki_uri/switchca/certs/$req_fingerprint-cert.pem"; - my $response = $ua->get($url, ':content_file' => $cert_file); - if ($response->is_success) { - return 'next'; - } - - db_subst('fetch-switch-cert-failed', 'url', $url); - db_subst('fetch-switch-cert-failed', 'error', - $response->status_line); - db_subst('fetch-switch-cert-failed', 'pki-uri', $pki_uri); - db_input('fetch-switch-cert-failed'); - db_go(); - } - }, - sub { - db_input('complete'); - db_go(); - return; - }, - sub { - return 'done'; - }, -); - -my $state = 1; -my $direction = 1; -for (;;) { - my $ret = &{$states[$state]}(); - $ret = db_go() ? 'prev' : 'next' if !defined $ret; - if ($ret eq 'next') { - $direction = 1; - } elsif ($ret eq 'prev') { - $direction = -1; - } elsif ($ret eq 'skip') { - # Nothing to do. - } elsif ($ret eq 'done') { - last; - } else { - die "unknown ret $ret"; - } - $state += $direction; -} - -my %config = %oldconfig; -$config{NETDEVS} = join(' ', netdev_names()); -$config{MODE} = db_get('mode'); -if (db_get('mode') eq 'in-band') { - $config{SWITCH_IP} = db_get('switch-ip'); -} -if (db_get('mode') ne 'discovery') { - $config{CONTROLLER} = db_get('controller-vconn'); -} -$config{PRIVKEY} = $privkey_file; -$config{CERT} = $cert_file; -$config{CACERT} = $cacert_file; -save_config($default, %config); - -dup2(2, 1); # Get stdout back. -kill_ofp_discover(); -system("/etc/init.d/openflow-switch start"); - -sub ssl_enabled { - return is_ssl_vconn(db_get('controller-vconn')); -} - -sub db_subst { - my ($question, $key, $value) = @_; - $question = "$debconf_owner/$question"; - my ($ret, $seen) = subst($question, $key, $value); - if ($ret && $ret != 30) { - die "Error substituting $value for $key in debconf question " - . "$question: $seen"; - } -} - -sub db_set { - my ($question, $value) = @_; - $question = "$debconf_owner/$question"; - my ($ret, $seen) = set($question, $value); - if ($ret && $ret != 30) { - die "Error setting debconf question $question to $value: $seen"; - } -} - -sub db_get { - my ($question) = @_; - $question = "$debconf_owner/$question"; - my ($ret, $seen) = get($question); - if ($ret) { - die "Error getting debconf question $question answer: $seen"; - } - return $seen; -} - -sub db_fset { - my ($question, $flag, $value) = @_; - $question = "$debconf_owner/$question"; - my ($ret, $seen) = fset($question, $flag, $value); - if ($ret && $ret != 30) { - die "Error setting debconf question $question flag $flag to $value: " - . "$seen"; - } -} - -sub db_fget { - my ($question, $flag) = @_; - $question = "$debconf_owner/$question"; - my ($ret, $seen) = fget($question, $flag); - if ($ret) { - die "Error getting debconf question $question flag $flag: $seen"; - } - return $seen; -} - -sub db_input { - my ($question) = @_; - db_fset($question, "seen", "false"); - - $question = "$debconf_owner/$question"; - my ($ret, $seen) = input('high', $question); - if ($ret && $ret != 30) { - die "Error requesting debconf question $question: $seen"; - } - return $ret; -} - -sub db_go { - my ($ret, $seen) = go(); - if (!defined($ret)) { - exit(1); # Cancel button was pushed. - } - if ($ret && $ret != 30) { - die "Error asking debconf questions: $seen"; - } - return $ret; -} - -sub run_cmd { - my ($cmd) = @_; - return if system($cmd) == 0; - - if ($? == -1) { - die "$cmd: failed to execute: $!\n"; - } elsif ($? & 127) { - die sprintf("$cmd: child died with signal %d, %s coredump\n", - ($? & 127), ($? & 128) ? 'with' : 'without'); - } else { - die sprintf("$cmd: child exited with value %d\n", $? >> 8); - } -} - -sub x509_fingerprint { - my ($file) = @_; - my $cmd = "openssl x509 -noout -in $file -fingerprint"; - open(OPENSSL, '-|', $cmd) or die "$cmd: failed to execute: $!\n"; - my $line = ; - close(OPENSSL); - my ($fingerprint) = $line =~ /SHA1 Fingerprint=(.*)/; - return $line if !defined $fingerprint; - $fingerprint =~ s/://g; - return $fingerprint; -} - -sub find_netdevs { - my ($netdev, %netdevs); - open(IFCONFIG, "/sbin/ifconfig -a|") or die "ifconfig failed: $!"; - while () { - if (my ($nd) = /^([^\s]+)/) { - $netdev = $nd; - $netdevs{$netdev} = "$netdev"; - if (my ($hwaddr) = /HWaddr (\S+)/) { - $netdevs{$netdev} .= " (MAC: $hwaddr)"; - } - } elsif (my ($ip4) = /^\s*inet addr:(\S+)/) { - $netdevs{$netdev} .= " (IP: $ip4)"; - } elsif (my ($ip6) = /^\s*inet6 addr:(\S+)/) { - $netdevs{$netdev} .= " (IPv6: $ip6)"; - } - } - foreach my $nd (keys(%netdevs)) { - delete $netdevs{$nd} if $nd eq 'lo' || $nd =~ /^wmaster/; - } - close(IFCONFIG); - return %netdevs; -} - -sub load_config { - my ($file) = @_; - - # Get the list of the variables that the shell sets automatically. - my (%auto_vars) = read_vars("set -a && env"); - - # Get the variables from $default. - my (%config) = read_vars("set -a && . '$default' && env"); - - # Subtract. - delete @config{keys %auto_vars}; - - return %config; -} - -sub read_vars { - my ($cmd) = @_; - local @ENV; - if (!open(VARS, '-|', $cmd)) { - print STDERR "$cmd: failed to execute: $!\n"; - return (); - } - my (%config); - while () { - my ($var, $value) = /^([^=]+)=(.*)$/ or next; - $config{$var} = $value; - } - close(VARS); - return %config; -} - -sub shell_escape { - local $_ = $_[0]; - if ($_ eq '') { - return '""'; - } elsif (m&^[-a-zA-Z0-9:./%^_+,]*$&) { - return $_; - } else { - s/'/'\\''/; - return "'$_'"; - } -} - -sub shell_assign { - my ($var, $value) = @_; - return $var . '=' . shell_escape($value); -} - -sub save_config { - my ($file, %config) = @_; - my (@lines); - if (open(FILE, '<', $file)) { - @lines = ; - chomp @lines; - close(FILE); - } - - # Replace all existing variable assignments. - for (my ($i) = 0; $i <= $#lines; $i++) { - local $_ = $lines[$i]; - my ($var, $value) = /^\s*([^=#]+)=(.*)$/ or next; - if (exists($config{$var})) { - $lines[$i] = shell_assign($var, $config{$var}); - delete $config{$var}; - } else { - $lines[$i] = "#$lines[$i]"; - } - } - - # Find a place to put any remaining variable assignments. - VAR: - for my $var (keys(%config)) { - my $assign = shell_assign($var, $config{$var}); - - # Replace the last commented-out variable assignment to $var, if any. - for (my ($i) = $#lines; $i >= 0; $i--) { - local $_ = $lines[$i]; - if (/^\s*#\s*$var=/) { - $lines[$i] = $assign; - next VAR; - } - } - - # Find a place to add the var: after the final commented line - # just after a line that contains "$var:". - for (my ($i) = 0; $i <= $#lines; $i++) { - if ($lines[$i] =~ /^\s*#\s*$var:/) { - for (my ($j) = $i + 1; $j <= $#lines; $j++) { - if ($lines[$j] !~ /^\s*#/) { - splice(@lines, $j, 0, $assign); - next VAR; - } - } - } - } - - # Just append it. - push(@lines, $assign); - } - - open(NEWFILE, '>', "$file.tmp") or die "$file.tmp: create: $!\n"; - print NEWFILE join('', map("$_\n", @lines)); - close(NEWFILE); - rename("$file.tmp", $file) or die "$file.tmp: rename to $file: $!\n"; -} - -sub pki_host_to_uri { - my ($pki_host) = @_; - return "http://$pki_host/openflow/pki"; -} - -sub kill_ofp_discover { - # Delegate this to a subprocess because there is no portable way - # to invoke fcntl(F_GETLK) from Perl. - system("ofp-kill --force $ofp_discover_pidfile"); -} - -sub netdev_names { - return map(/^(\S+)/, split(', ', db_get('netdevs'))); -} - -sub is_valid_vconn { - my ($vconn) = @_; - return scalar($vconn =~ /^(tcp|ssl):([^:]+)(:.*)?/); -} - -sub is_ssl_vconn { - my ($vconn) = @_; - return scalar($vconn =~ /^ssl:/); -} diff --git a/openflow/debian/ofp-switch-setup.8 b/openflow/debian/ofp-switch-setup.8 deleted file mode 100644 index 50904cfb..00000000 --- a/openflow/debian/ofp-switch-setup.8 +++ /dev/null @@ -1,41 +0,0 @@ -.TH ofp-switch-setup 8 "June 2008" "OpenFlow" "OpenFlow Manual" - -.SH NAME -ofp\-switch\-setup \- interactive setup for OpenFlow switch - -.SH SYNOPSIS -.B ofp\-switch\-setup - -.SH DESCRIPTION -The \fBofp\-switch\-setup\fR program is an interactive program that -assists the system administrator in configuring an OpenFlow switch, -including the underlying public key infrastructure (PKI). - -.SH OPTIONS -ofp\-switch\-setup does not accept any command-line options. - -.SH FILES -.IP /etc/default/openflow-switch -Main configuration file for OpenFlow switch. - -.IP /etc/openflow-switch/cacert.pem -Default location of CA certificate for OpenFlow controllers. - -.IP /etc/openflow-switch/of0-cert.pem -Default location of certificate for the OpenFlow switch's private key. - -.IP /etc/openflow-switch/of0-privkey.pem -Default location of the OpenFlow switch's private key. This file -should be readable only by \fBroot\fR. - -.IP /etc/openflow-switch/of0-req.pem -Default location of certificate request for the OpenFlow switch's -certificate. This file is not used after the signed certificate -(typically \fB/etc/openflow-switch/of0-cert.pem\fR, above) has been -obtained from the OpenFlow PKI server. - -.SH "SEE ALSO" - -.BR ofp-pki (8), -.BR dpctl (8), -.BR secchan (8) diff --git a/openflow/debian/openflow-common.dirs b/openflow/debian/openflow-common.dirs deleted file mode 100644 index 527fe313..00000000 --- a/openflow/debian/openflow-common.dirs +++ /dev/null @@ -1 +0,0 @@ -var/log/openflow diff --git a/openflow/debian/openflow-common.install b/openflow/debian/openflow-common.install deleted file mode 100644 index eed7413e..00000000 --- a/openflow/debian/openflow-common.install +++ /dev/null @@ -1,3 +0,0 @@ -_debian/utilities/ofp-parse-leaks usr/bin -_debian/utilities/ofp-pki usr/sbin -_debian/utilities/vlogconf usr/sbin diff --git a/openflow/debian/openflow-common.manpages b/openflow/debian/openflow-common.manpages deleted file mode 100644 index fbb88201..00000000 --- a/openflow/debian/openflow-common.manpages +++ /dev/null @@ -1,2 +0,0 @@ -_debian/utilities/vlogconf.8 -_debian/utilities/ofp-pki.8 diff --git a/openflow/debian/openflow-controller.README.Debian b/openflow/debian/openflow-controller.README.Debian deleted file mode 100644 index 19d5cb9b..00000000 --- a/openflow/debian/openflow-controller.README.Debian +++ /dev/null @@ -1,10 +0,0 @@ -README.Debian for openflow-controller -------------------------------------- - -* To (re)configure the controller, edit /etc/default/openflow-controller - and run "/etc/init.d/openflow-controller restart". - -* To enable OpenFlow switches to automatically discover the location - of the controller, you must install and configure a DHCP server. - The secchan(8) manpage (found in the openflow-switch package) gives - a working example configuration file for the ISC DHCP server. diff --git a/openflow/debian/openflow-controller.default b/openflow/debian/openflow-controller.default deleted file mode 100644 index 3b84b62a..00000000 --- a/openflow/debian/openflow-controller.default +++ /dev/null @@ -1,33 +0,0 @@ -# This is a POSIX shell fragment -*- sh -*- - -# LISTEN: What OpenFlow connection methods should the controller listen on? -# -# This is a space-delimited list of connection methods: -# -# * "pssl:[PORT]": Listen for SSL connections on the specified PORT -# (default: 6633). The private key, certificate, and CA certificate -# must be specified below. -# -# * "pctp:[PORT]": Listen for TCP connections on the specified PORT -# (default: 6633). Not recommended for security reasons. -# -# * "nl:DP_IDX": Listen on local datapath DP_IDX. Used only if this -# machine is also an OpenFlow switch and not running the secure -# channel, and only if you know what you're doing. -# -LISTEN="pssl:" - -# PRIVKEY: Name of file containing controller's private key. -# Required if SSL enabled. -PRIVKEY=/etc/openflow-controller/privkey.pem - -# CERT: Name of file containing certificate for private key. -# Required if SSL enabled. -CERT=/etc/openflow-controller/cert.pem - -# CACERT: Name of file containing switch CA certificate. -# Required if SSL enabled. -CACERT=/etc/openflow-controller/cacert.pem - -# Additional options to pass to controller, e.g. "--hub" -DAEMON_OPTS="" diff --git a/openflow/debian/openflow-controller.dirs b/openflow/debian/openflow-controller.dirs deleted file mode 100644 index 0a19a9fc..00000000 --- a/openflow/debian/openflow-controller.dirs +++ /dev/null @@ -1 +0,0 @@ -etc/openflow-controller diff --git a/openflow/debian/openflow-controller.init b/openflow/debian/openflow-controller.init deleted file mode 100755 index 121fd76b..00000000 --- a/openflow/debian/openflow-controller.init +++ /dev/null @@ -1,269 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2007 Javier Fernandez-Sanguino -# -# This is free software; you may redistribute it and/or modify -# it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 2, -# or (at your option) any later version. -# -# This is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License with -# the Debian operating system, in /usr/share/common-licenses/GPL; if -# not, write to the Free Software Foundation, Inc., 59 Temple Place, -# Suite 330, Boston, MA 02111-1307 USA -# -### BEGIN INIT INFO -# Provides: openflow-controller -# Required-Start: $network $local_fs -# Required-Stop: -# Should-Start: $named -# Should-Stop: -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: OpenFlow controller -### END INIT INFO - -PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin - -DAEMON=/usr/sbin/controller # Introduce the server's location here -NAME=controller # Introduce the short server's name here -DESC=controller # Introduce a short description here -LOGDIR=/var/log/openflow # Log directory to use - -PIDFILE=/var/run/$NAME.pid - -test -x $DAEMON || exit 0 - -. /lib/lsb/init-functions - -# Default options, these can be overriden by the information -# at /etc/default/$NAME -DAEMON_OPTS="" # Additional options given to the server - -DODTIME=10 # Time to wait for the server to die, in seconds - # If this value is set too low you might not - # let some servers to die gracefully and - # 'restart' will not work - -LOGFILE=$LOGDIR/$NAME.log # Server logfile -#DAEMONUSER= # User to run the daemons as. If this value - # is set start-stop-daemon will chuid the server - -# Include defaults if available -default=/etc/default/openflow-controller -if [ -f $default ] ; then - . $default -fi - -# Check that the user exists (if we set a user) -# Does the user exist? -if [ -n "$DAEMONUSER" ] ; then - if getent passwd | grep -q "^$DAEMONUSER:"; then - # Obtain the uid and gid - DAEMONUID=`getent passwd |grep "^$DAEMONUSER:" | awk -F : '{print $3}'` - DAEMONGID=`getent passwd |grep "^$DAEMONUSER:" | awk -F : '{print $4}'` - else - log_failure_msg "The user $DAEMONUSER, required to run $NAME does not exist." - exit 1 - fi -fi - - -set -e - -running_pid() { -# Check if a given process pid's cmdline matches a given name - pid=$1 - name=$2 - [ -z "$pid" ] && return 1 - [ ! -d /proc/$pid ] && return 1 - cmd=`cat /proc/$pid/cmdline | tr "\000" "\n"|head -n 1 |cut -d : -f 1` - # Is this the expected server - [ "$cmd" != "$name" ] && return 1 - return 0 -} - -running() { -# Check if the process is running looking at /proc -# (works for all users) - - # No pidfile, probably no daemon present - [ ! -f "$PIDFILE" ] && return 1 - pid=`cat $PIDFILE` - running_pid $pid $DAEMON || return 1 - return 0 -} - -start_server() { - if [ -z "$LISTEN" ]; then - echo "$default: No connection methods configured, controller disabled" >&2 - exit 0 - fi - - SSL_OPTS= - case $LISTEN in - *ssl*) - : ${PRIVKEY:=/etc/openflow-controller/privkey.pem} - : ${CERT:=/etc/openflow-controller/cert.pem} - : ${CACERT:=/etc/openflow-controller/cacert.pem} - if test ! -e "$PRIVKEY" || test ! -e "$CERT" || - test ! -e "$CACERT"; then - if test ! -e "$PRIVKEY"; then - echo "$PRIVKEY: private key missing" >&2 - fi - if test ! -e "$CERT"; then - echo "$CERT: certificate for private key missing" >&2 - fi - if test ! -e "$CACERT"; then - echo "$CACERT: CA certificate missing" >&2 - fi - exit 1 - fi - SSL_OPTS="--private-key=$PRIVKEY --certificate=$CERT --ca-cert=$CACERT" - ;; - esac - -# Start the process using the wrapper - if [ -z "$DAEMONUSER" ] ; then - start-stop-daemon --start --pidfile $PIDFILE \ - --exec $DAEMON -- --detach --pidfile=$PIDFILE \ - $LISTEN $DAEMON_OPTS $SSL_OPTS - errcode=$? - else -# if we are using a daemonuser then change the user id - start-stop-daemon --start --quiet --pidfile $PIDFILE \ - --chuid $DAEMONUSER --exec $DAEMON -- \ - --detach --pidfile=$PIDFILE $LISTEN $DAEMON_OPTS \ - $SSL_OPTS - errcode=$? - fi - return $errcode -} - -stop_server() { -# Stop the process using the wrapper - if [ -z "$DAEMONUSER" ] ; then - start-stop-daemon --stop --quiet --pidfile $PIDFILE \ - --exec $DAEMON - errcode=$? - else -# if we are using a daemonuser then look for process that match - start-stop-daemon --stop --quiet --pidfile $PIDFILE \ - --user $DAEMONUSER --exec $DAEMON - errcode=$? - fi - - return $errcode -} - -reload_server() { - [ ! -f "$PIDFILE" ] && return 1 - pid=`cat $PIDFILE` # This is the daemon's pid - # Send a SIGHUP - kill -1 $pid - return $? -} - -force_stop() { -# Force the process to die killing it manually - [ ! -e "$PIDFILE" ] && return - if running ; then - kill -15 $pid - # Is it really dead? - sleep "$DIETIME"s - if running ; then - kill -9 $pid - sleep "$DIETIME"s - if running ; then - echo "Cannot kill $NAME (pid=$pid)!" - exit 1 - fi - fi - fi - rm -f $PIDFILE -} - - -case "$1" in - start) - log_daemon_msg "Starting $DESC " "$NAME" - # Check if it's running first - if running ; then - log_progress_msg "apparently already running" - log_end_msg 0 - exit 0 - fi - if start_server && running ; then - # It's ok, the server started and is running - log_end_msg 0 - else - # Either we could not start it or it is not running - # after we did - # NOTE: Some servers might die some time after they start, - # this code does not try to detect this and might give - # a false positive (use 'status' for that) - log_end_msg 1 - fi - ;; - stop) - log_daemon_msg "Stopping $DESC" "$NAME" - if running ; then - # Only stop the server if we see it running - stop_server - log_end_msg $? - else - # If it's not running don't do anything - log_progress_msg "apparently not running" - log_end_msg 0 - exit 0 - fi - ;; - force-stop) - # First try to stop gracefully the program - $0 stop - if running; then - # If it's still running try to kill it more forcefully - log_daemon_msg "Stopping (force) $DESC" "$NAME" - force_stop - log_end_msg $? - fi - ;; - restart|force-reload) - log_daemon_msg "Restarting $DESC" "$NAME" - stop_server - # Wait some sensible amount, some server need this - [ -n "$DIETIME" ] && sleep $DIETIME - start_server - running - log_end_msg $? - ;; - status) - - log_daemon_msg "Checking status of $DESC" "$NAME" - if running ; then - log_progress_msg "running" - log_end_msg 0 - else - log_progress_msg "apparently not running" - log_end_msg 1 - exit 1 - fi - ;; - # Use this if the daemon cannot reload - reload) - log_warning_msg "Reloading $NAME daemon: not implemented, as the daemon" - log_warning_msg "cannot re-read the config file (use restart)." - ;; - *) - N=/etc/init.d/$NAME - echo "Usage: $N {start|stop|force-stop|restart|force-reload|status}" >&2 - exit 1 - ;; -esac - -exit 0 diff --git a/openflow/debian/openflow-controller.install b/openflow/debian/openflow-controller.install deleted file mode 100644 index 3932ab6a..00000000 --- a/openflow/debian/openflow-controller.install +++ /dev/null @@ -1 +0,0 @@ -_debian/controller/controller usr/sbin diff --git a/openflow/debian/openflow-controller.manpages b/openflow/debian/openflow-controller.manpages deleted file mode 100644 index 3fbaaeaf..00000000 --- a/openflow/debian/openflow-controller.manpages +++ /dev/null @@ -1 +0,0 @@ -_debian/controller/controller.8 diff --git a/openflow/debian/openflow-controller.postinst b/openflow/debian/openflow-controller.postinst deleted file mode 100755 index 93e39116..00000000 --- a/openflow/debian/openflow-controller.postinst +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/sh -# postinst script for openflow-controller -# -# see: dh_installdeb(1) - -set -e - -# summary of how this script can be called: -# * `configure' -# * `abort-upgrade' -# * `abort-remove' `in-favour' -# -# * `abort-remove' -# * `abort-deconfigure' `in-favour' -# `removing' -# -# for details, see http://www.debian.org/doc/debian-policy/ or -# the debian-policy package - - -case "$1" in - configure) - cd /etc/openflow-controller - if ! test -e cacert.pem; then - ln -s /usr/share/openflow/pki/switchca/cacert.pem cacert.pem - fi - if ! test -e privkey.pem || ! test -e cert.pem; then - oldumask=$(umask) - umask 077 - ofp-pki req+sign tmp controller >/dev/null - mv tmp-privkey.pem privkey.pem - mv tmp-cert.pem cert.pem - mv tmp-req.pem req.pem - chmod go+r cert.pem req.pem - umask $oldumask - fi - ;; - - abort-upgrade|abort-remove|abort-deconfigure) - ;; - - *) - echo "postinst called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -#DEBHELPER# - -exit 0 - - diff --git a/openflow/debian/openflow-datapath-module-_KVERS_.postinst.modules.in b/openflow/debian/openflow-datapath-module-_KVERS_.postinst.modules.in deleted file mode 100755 index 6974e13a..00000000 --- a/openflow/debian/openflow-datapath-module-_KVERS_.postinst.modules.in +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh -# postinst script for #PACKAGE# -# -# see: dh_installdeb(1) - -set -e - -depmod -a - -#DEBHELPER# - -# If the switch is running, restart it. This ensures that we are using the -# latest kernel module, because the init script will unload and reload the -# module. -# -# (Ideally we'd only want to do this if this package corresponds to the -# running kernel, but I don't know a reliable way to check.) -INIT=/etc/init.d/openflow-switch -if test -x $INIT && $INIT status; then - $INIT restart || true -fi - -exit 0 - - diff --git a/openflow/debian/openflow-datapath-source.README.Debian b/openflow/debian/openflow-datapath-source.README.Debian deleted file mode 100644 index 59965df9..00000000 --- a/openflow/debian/openflow-datapath-source.README.Debian +++ /dev/null @@ -1,31 +0,0 @@ -OpenFlow for Debian -------------------- - -* How do I build this module the Debian way? - - - Building with module-assistant: - - $ module-assistant auto-install openflow - or - $ m-a a-i openflow - - If kernel source or headers are in a non-standard directory, add - the option -k /path/to/kernel/source with the correct path. - - - Building with make-kpkg - - $ cd /usr/src/ - $ tar jxvf openflow.tar.bz2 - $ cd /usr/src/kernel-source-2.6.9 - $ make-kpkg --added-modules=openflow modules - - - Building without make-kpkg - - $ cd /usr/src/ - $ tar jxvf openflow.tar.bz2 - $ cd modules/openflow - $ fakeroot debian/rules kdist_image - - If you run this as root, fakeroot is not needed. - - -- OpenFlow Team , Thu, 12 Jun 2008 16:42:38 -0700 diff --git a/openflow/debian/openflow-datapath-source.copyright b/openflow/debian/openflow-datapath-source.copyright deleted file mode 100644 index f7bcdda3..00000000 --- a/openflow/debian/openflow-datapath-source.copyright +++ /dev/null @@ -1,16 +0,0 @@ -Upstream Authors: - - The Board of Trustees of The Leland Stanford Junior University - -Copyright: - - Copyright (C) 2008 The Board of Trustees of The Leland Stanford - Junior University - -License: - - Files in the datapath/ and its sub-directories are covered under the GNU - General Public License Version 2. - - On Debian systems, the complete text of the GNU General - Public License can be found in `/usr/share/common-licenses/GPL'. diff --git a/openflow/debian/openflow-datapath-source.dirs b/openflow/debian/openflow-datapath-source.dirs deleted file mode 100644 index 4ddf234a..00000000 --- a/openflow/debian/openflow-datapath-source.dirs +++ /dev/null @@ -1 +0,0 @@ -usr/src/modules/openflow-datapath/debian diff --git a/openflow/debian/openflow-datapath-source.install b/openflow/debian/openflow-datapath-source.install deleted file mode 100644 index a74f13dc..00000000 --- a/openflow/debian/openflow-datapath-source.install +++ /dev/null @@ -1,6 +0,0 @@ -debian/changelog usr/src/modules/openflow-datapath/debian -debian/control usr/src/modules/openflow-datapath/debian -debian/compat usr/src/modules/openflow-datapath/debian -debian/*.modules.in usr/src/modules/openflow-datapath/debian -debian/rules usr/src/modules/openflow-datapath/debian -_debian/openflow.tar.gz usr/src/modules/openflow-datapath diff --git a/openflow/debian/openflow-pki-server.apache2 b/openflow/debian/openflow-pki-server.apache2 deleted file mode 100644 index a341c508..00000000 --- a/openflow/debian/openflow-pki-server.apache2 +++ /dev/null @@ -1 +0,0 @@ -Alias /openflow/pki/ /usr/share/openflow/pki/ diff --git a/openflow/debian/openflow-pki-server.dirs b/openflow/debian/openflow-pki-server.dirs deleted file mode 100644 index 7307777b..00000000 --- a/openflow/debian/openflow-pki-server.dirs +++ /dev/null @@ -1 +0,0 @@ -etc/apache2/sites-available diff --git a/openflow/debian/openflow-pki-server.install b/openflow/debian/openflow-pki-server.install deleted file mode 100644 index cd530ca4..00000000 --- a/openflow/debian/openflow-pki-server.install +++ /dev/null @@ -1 +0,0 @@ -_debian/utilities/ofp-pki-cgi usr/lib/cgi-bin diff --git a/openflow/debian/openflow-pki-server.postinst b/openflow/debian/openflow-pki-server.postinst deleted file mode 100755 index d161a98a..00000000 --- a/openflow/debian/openflow-pki-server.postinst +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/sh -# postinst script for openflow -# -# see: dh_installdeb(1) - -set -e - -# summary of how this script can be called: -# * `configure' -# * `abort-upgrade' -# * `abort-remove' `in-favour' -# -# * `abort-remove' -# * `abort-deconfigure' `in-favour' -# `removing' -# -# for details, see http://www.debian.org/doc/debian-policy/ or -# the debian-policy package - -case "$1" in - configure) - # Enable site under Apache. - a2ensite openflow-pki >/dev/null - if command -v invoke-rc.d >/dev/null 2>&1; then - invoke-rc.d apache2 force-reload || : - else - [ -x /etc/init.d/apache2 ] && /etc/init.d/apache2 force-reload || : - fi - ;; - - abort-upgrade|abort-remove|abort-deconfigure) - ;; - - *) - echo "postinst called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -#DEBHELPER# - -exit 0 - - diff --git a/openflow/debian/openflow-pki.postinst b/openflow/debian/openflow-pki.postinst deleted file mode 100755 index 5cf6515d..00000000 --- a/openflow/debian/openflow-pki.postinst +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/sh -# postinst script for openflow -# -# see: dh_installdeb(1) - -set -e - -# summary of how this script can be called: -# * `configure' -# * `abort-upgrade' -# * `abort-remove' `in-favour' -# -# * `abort-remove' -# * `abort-deconfigure' `in-favour' -# `removing' -# -# for details, see http://www.debian.org/doc/debian-policy/ or -# the debian-policy package - -case "$1" in - configure) - # Create certificate authorities. - if test ! -d /usr/share/openflow/pki; then - ofp-pki init - fi - ;; - - abort-upgrade|abort-remove|abort-deconfigure) - ;; - - *) - echo "postinst called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -#DEBHELPER# - -exit 0 - - diff --git a/openflow/debian/openflow-switch-config.dirs b/openflow/debian/openflow-switch-config.dirs deleted file mode 100644 index 881ded8a..00000000 --- a/openflow/debian/openflow-switch-config.dirs +++ /dev/null @@ -1 +0,0 @@ -/usr/share/lintian/overrides diff --git a/openflow/debian/openflow-switch-config.install b/openflow/debian/openflow-switch-config.install deleted file mode 100644 index 75c50083..00000000 --- a/openflow/debian/openflow-switch-config.install +++ /dev/null @@ -1 +0,0 @@ -debian/ofp-switch-setup usr/sbin diff --git a/openflow/debian/openflow-switch-config.manpages b/openflow/debian/openflow-switch-config.manpages deleted file mode 100644 index e176dad9..00000000 --- a/openflow/debian/openflow-switch-config.manpages +++ /dev/null @@ -1 +0,0 @@ -debian/ofp-switch-setup.8 diff --git a/openflow/debian/openflow-switch-config.overrides b/openflow/debian/openflow-switch-config.overrides deleted file mode 100644 index 4ac77aba..00000000 --- a/openflow/debian/openflow-switch-config.overrides +++ /dev/null @@ -1 +0,0 @@ -debconf-is-not-a-registry diff --git a/openflow/debian/openflow-switch-config.templates b/openflow/debian/openflow-switch-config.templates deleted file mode 100644 index 78761097..00000000 --- a/openflow/debian/openflow-switch-config.templates +++ /dev/null @@ -1,228 +0,0 @@ -Template: openflow-switch/netdevs -Type: multiselect -_Choices: ${choices} -_Description: OpenFlow switch network devices: - Choose the network devices that should become part of the OpenFlow - switch. At least two devices must be selected for this machine to be - a useful switch. Unselecting all network devices will disable the - OpenFlow switch entirely. - . - The network devices that you select should not be configured with IP - or IPv6 addresses, even if the switch contacts the controller over - one of the selected network devices. This is because a running - OpenFlow switch takes over network devices at a low level: they - become part of the switch and cannot be used for other purposes. - -Template: openflow-switch/no-netdevs -Type: error -_Description: No network devices were selected. - No network devices were selected for inclusion in the OpenFlow switch. - The switch will be disabled. - -Template: openflow-switch/configured-netdevs -Type: note -_Description: Some Network Devices Have IP or IPv6 Addresses - The following network devices selected to be part of the OpenFlow switch - have IP or IPv6 addresses configured: - . - ${configured-netdevs} - . - This is usually a mistake, even if the switch contacts the controller over - one of the selected network devices. This is because a running - OpenFlow switch takes over network devices at a low level: they - become part of the switch and cannot be used for other purposes. - . - If this is an unintentional mistake, move back and fix the selection, - or de-configure the IP or IPv6 from these network devices. - -Template: openflow-switch/mode -Type: select -_Choices: discovery, in-band, out-of-band -Default: discovery -_Description: Switch-to-controller access method: - The OpenFlow switch must be able to contact the OpenFlow controller over - the network. It can do so in one of three ways: - . - discovery: A single network is used for OpenFlow traffic and other - data traffic; that is, the switch contacts the controller over one of - the network devices selected as OpenFlow switch network devices in - the previous question. The switch automatically determines the - location of the controller using a DHCP request with an - OpenFlow-specific vendor option. This is the most common case. - . - in-band: As above, but the location of the controller is manually - configured. - . - out-of-band: OpenFlow traffic uses a network separate from the data traffic - that it controls. If this is the case, the control network must already - be configured on a network device other than one of those selected as - an OpenFlow switch netdev in the previous question. - -Template: openflow-switch/discover -Type: note -_Description: Preparing to discover controller. - The setup program will now attempt to discover the OpenFlow controller. - Controller discovery may take up to 30 seconds. Please be patient. - . - See secchan(8) for instructions on how to configure a DHCP server for - controller discovery. - -Template: openflow-switch/discovery-failure -Type: error -_Description: Controller discovery failed. - The controller's location could not be determined automatically. - . - Ensure that the OpenFlow DHCP server is properly configured. See - secchan(8) for instructions on how to configure a DHCP server for - controller discovery. - -Template: openflow-switch/discovery-success -Type: boolean -Default: true -_Description: Use discovered settings? - Controller discovery obtained the following settings: - . - Controller location: ${controller-vconn} - . - PKI URL: ${pki-uri} - . - Please verify that these settings are correct. - -Template: openflow-switch/switch-ip -Type: string -Default: dhcp -_Description: Switch IP address: - For in-band communication with the controller, the OpenFlow switch must - be able to determine its own IP address. Its IP address may be configured - statically or dynamically. - . - For static configuration, specify the switch's IP address as a string. - . - For dynamic configuration with DHCP (the most common case), specify "dhcp". - Configuration with DHCP will only work reliably if the network topology - allows the switch to contact the DHCP server before it connects to the - OpenFlow controller. - -Template: openflow-switch/switch-ip-error -Type: error -_Description: The switch IP address is invalid. - The switch IP address must specified as "dhcp" or a valid IP address in - dotted-octet form (e.g. "1.2.3.4"). - -Template: openflow-switch/controller-vconn -Type: string -_Description: Controller location: - Specify how the OpenFlow switch should connect to the OpenFlow controller. - The value should be in form "ssl:HOST[:PORT]" to connect to the controller - over SSL (recommended for security) or "tcp:HOST[:PORT]" to connect over - cleartext TCP. - -Template: openflow-switch/controller-vconn-error -Type: error -_Description: The controller location is invalid. - The controller location must be specifed as "ssl:HOST[:PORT]" to - connect to the controller over SSL (recommended for security) or - "tcp:HOST[:PORT]" to connect over cleartext TCP. - -Template: openflow-switch/pki-uri -Type: string -_Description: OpenFlow PKI server host name or URL: - Specify a URL to the OpenFlow public key infrastructure (PKI). If a - host name or IP address is specified in place of a URL, then - http:///openflow/pki/ will be used, - where is the specified host name or IP address. - . - The OpenFlow PKI is usually on the same machine as the OpenFlow - controller. - . - The setup process will connect to the OpenFlow PKI server over - HTTP, using the system's configured default HTTP proxy (if any). - -Template: openflow-switch/fetch-cacert-failed -Type: error -_Description: The switch CA certificate could not be retrieved. - Retrieval of ${url} failed, with the following status: "${error}". - . - Ensure that the OpenFlow PKI server is correctly configured and - available at ${pki-uri}. If the system is configured to use an HTTP - proxy, also make sure that the HTTP proxy is available and that the - PKI server can be reached through it. - -Template: openflow-switch/verify-controller-ca -Type: select -_Choices: yes, no -Default: yes -_Description: Is ${fingerprint} the controller CA's fingerprint? - If a man-in-the-middle attack is possible in your network - environment, check that the controller CA's fingerprint is really - ${fingerprint}. Answer "yes" if it matches, "no" if - there is a discrepancy. - . - If a man-in-the-middle attack is not a concern, there is no need to - verify the fingerprint. Simply answer "yes". - -Template: openflow-switch/send-cert-req -Type: select -_Choices: yes, no -Default: yes -_Description: Send certificate request to switch CA? - Before it can connect to the controller over SSL, the OpenFlow - switch's key must be signed by the switch certificate authority (CA) - located on the OpenFlow PKI server, which is usually collocated with - the OpenFlow controller. A signing request can be sent to the PKI - server now. - . - Answer "yes" to send a signing request to the switch CA now. This is - ordinarily the correct choice. There is no harm in sending a given - signing request more than once. - . - Answer "no" to skip sending a signing request to the switch CA. - Unless the request has already been sent to the switch CA, manual - sending of the request and signing will be necessary. - -Template: openflow-switch/send-cert-req-failed -Type: error -_Description: The certificate request could not be sent. - Posting to ${url} failed, with the following status: "${error}". - . - Ensure that the OpenFlow PKI server is correctly configured and - available at ${pki-uri}. - -Template: openflow-switch/fetch-switch-cert -Type: select -_Choices: yes, no -_Description: Fetch signed switch certificate from PKI server? - Before it can connect to the controller over SSL, the OpenFlow - switch's key must be signed by the switch certificate authority (CA) - located on the OpenFlow PKI server, which is usually collocated with - the OpenFlow controller. - . - At this point, a signing request has been sent to the switch CA (or - sending a request has been manually skipped), but the signed - certificate has not yet been retrieved. Manual action may need to be - taken at the PKI server to approve the signing request. - . - Answer "yes" to attempt to retrieve the signed switch certificate - from the switch CA. If the switch certificate request has been - signed at the PKI server, this is the correct choice. - . - Answer "no" to postpone switch configuration. The configuration - process must be restarted later, when the switch certificate request - has been signed. - -Template: openflow-switch/fetch-switch-cert-failed -Type: error -_Description: Signed switch certificate could not be retrieved. - The signed switch certificate could not be retrieved from the switch - CA: retrieval of ${url} failed, with the following status: "${error}". - . - This probably indicates that the switch's certificate request has not - yet been signed. If this is the problem, it may be fixed by signing - the certificate request at ${pki-uri}, then trying to fetch the - signed switch certificate again. - -Template: openflow-switch/complete -Type: note -_Description: OpenFlow Switch Setup Finished - Setup of this OpenFlow switch is finished. Complete the setup procedure - to enable the switch. diff --git a/openflow/debian/openflow-switch.README.Debian b/openflow/debian/openflow-switch.README.Debian deleted file mode 100644 index d9a931c1..00000000 --- a/openflow/debian/openflow-switch.README.Debian +++ /dev/null @@ -1,18 +0,0 @@ -README.Debian for openflow-switch ---------------------------------- - -* The switch must be configured before it can be used. To configure - it interactively, install the openflow-switch-config package and run - the ofp-switch-setup program. Alternatively, edit - /etc/default/openflow-switch by hand, then start the switch manually - with "/etc/init.d/openflow-switch start". - -* To use the Linux kernel-based switch implementation, you will need - to build and install the OpenFlow kernel module. To do so, install - the openflow-datapath-source package, then follow the instructions - given in /usr/share/doc/openflow-datapath-source/README.Debian - -* This package does not yet support the userspace datapath-based - switch implementation. - - -- Ben Pfaff , Tue, 6 Jan 2009 13:52:33 -0800 diff --git a/openflow/debian/openflow-switch.dirs b/openflow/debian/openflow-switch.dirs deleted file mode 100644 index a53002ff..00000000 --- a/openflow/debian/openflow-switch.dirs +++ /dev/null @@ -1,2 +0,0 @@ -/etc/openflow-switch -/usr/share/openflow/switch diff --git a/openflow/debian/openflow-switch.init b/openflow/debian/openflow-switch.init deleted file mode 100755 index cd518a71..00000000 --- a/openflow/debian/openflow-switch.init +++ /dev/null @@ -1,437 +0,0 @@ -#! /bin/sh -# -# /etc/init.d/openflow-switch -# -# Written by Miquel van Smoorenburg . -# Modified for Debian by Ian Murdock . -# Further changes by Javier Fernandez-Sanguino -# Modified for openflow-switch. -# -# Version: @(#)skeleton 1.9 26-Feb-2001 miquels@cistron.nl -# -### BEGIN INIT INFO -# Provides: openflow-switch -# Required-Start: $network $named $remote_fs $syslog -# Required-Stop: -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: OpenFlow switch -### END INIT INFO - -PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin -DAEMON=/usr/sbin/secchan -NAME=secchan -DESC=secchan - -test -x $DAEMON || exit 0 - -NICIRA_OUI="002320" - -LOGDIR=/var/log/openflow -PIDFILE=/var/run/$NAME.pid -DHCLIENT_PIDFILE=/var/run/dhclient.of0.pid -DODTIME=1 # Time to wait for the server to die, in seconds - # If this value is set too low you might not - # let some servers to die gracefully and - # 'restart' will not work - -# Include secchan defaults if available -unset NETDEVS -unset MODE -unset SWITCH_IP -unset CONTROLLER -unset PRIVKEY -unset CERT -unset CACERT -unset CACERT_MODE -unset MGMT_VCONNS -unset COMMANDS -unset DAEMON_OPTS -unset CORE_LIMIT -unset DATAPATH_ID -default=/etc/default/openflow-switch -if [ -f $default ] ; then - . $default -fi - -set -e - -running_pid() -{ - # Check if a given process pid's cmdline matches a given name - pid=$1 - name=$2 - [ -z "$pid" ] && return 1 - [ ! -d /proc/$pid ] && return 1 - cmd=`cat /proc/$pid/cmdline | tr "\000" "\n"|head -n 1 |cut -d : -f 1` - # Is this the expected child? - case $cmd in - $name|*/$name) - return 0 - ;; - *) - return 1 - ;; - esac -} - -running() -{ -# Check if the process is running looking at /proc -# (works for all users) - - # No pidfile, probably no daemon present - [ ! -f "$PIDFILE" ] && return 1 - # Obtain the pid and check it against the binary name - pid=`cat $PIDFILE` - running_pid $pid $NAME || return 1 - return 0 -} - -force_stop() { -# Forcefully kill the process - [ ! -f "$PIDFILE" ] && return - if running ; then - kill -15 $pid - # Is it really dead? - [ -n "$DODTIME" ] && sleep "$DODTIME"s - if running ; then - kill -9 $pid - [ -n "$DODTIME" ] && sleep "$DODTIME"s - if running ; then - echo "Cannot kill $NAME (pid=$pid)!" - exit 1 - fi - fi - fi - rm -f $PIDFILE - return 0 -} - -must_succeed() { - echo -n "$1: " - shift - if "$@"; then - echo "success." - else - echo " ERROR." - exit 1 - fi -} - -check_op() { - echo -n "$1: " - shift - if "$@"; then - echo "success." - else - echo " ERROR." - fi -} - -configure_ssl() { - if (test "$CACERT_MODE" != secure && test "$CACERT_MODE" != bootstrap) \ - || test ! -e "$PRIVKEY" || test ! -e "$CERT" \ - || (test ! -e "$CACERT" && test "$CACERT_MODE" != bootstrap); then - if test "$CACERT_MODE" != secure && test "$CACERT_MODE" != bootstrap - then - echo "CACERT_MODE is not set to 'secure' or 'bootstrap'" - fi - if test ! -e "$PRIVKEY"; then - echo "$PRIVKEY: private key missing" >&2 - fi - if test ! -e "$CERT"; then - echo "$CERT: certificate for private key missing" >&2 - fi - if test ! -e "$CACERT" && test "$CACERT_MODE" != bootstrap; then - echo "$CACERT: CA certificate missing (and CA certificate bootstrapping not enabled)" >&2 - fi - echo "Run ofp-switch-setup (in the openflow-switch-config package) or edit /etc/default/openflow-switch to configure" >&2 - if test "$MODE" = discovery; then - echo "You may also delete or rename $PRIVKEY to disable SSL requirement" >&2 - fi - exit 1 - fi - - SSL_OPTS="--private-key=$PRIVKEY --certificate=$CERT" - if test ! -e "$CACERT" && test "$CACERT_MODE" = bootstrap; then - SSL_OPTS="$SSL_OPTS --bootstrap-ca-cert=$CACERT" - else - SSL_OPTS="$SSL_OPTS --ca-cert=$CACERT" - fi -} - -check_int_var() { - eval value=\$$1 - if test -n "$value"; then - if expr "X$value" : 'X[0-9][0-9]*$'; then - if test $value -lt $2; then - echo "warning: The $1 option may not be set to a value below $2, treating as $2" >&2 - eval $1=$2 - fi - else - echo "warning: The $1 option must be set to a number, ignoring" >&2 - unset $1 - fi - fi -} - -check_new_option() { - case $DAEMON_OPTS in - *$1*) - echo "warning: The $1 option in DAEMON_OPTS may now be set with the $2 variable in $default. The setting in DAEMON_OPTS will override the $2 variable, which will prevent the switch UI from configuring $1." >&2 - ;; - esac -} - -case "$1" in - start) - if test -z "$NETDEVS"; then - echo "$default: No network devices configured, switch disabled" >&2 - echo "Run ofp-switch-setup (in the openflow-switch-config package) or edit /etc/default/openflow-switch to configure" >&2 - exit 0 - fi - if test "$MODE" = discovery; then - unset CONTROLLER - elif test "$MODE" = in-band || test "$MODE" = out-of-band; then - if test -z "$CONTROLLER"; then - echo "$default: No controller configured and not configured for discovery, switch disabled" >&2 - echo "Run ofp-switch-setup (in the openflow-switch-config package) or edit /etc/default/openflow-switch to configure" >&2 - exit 0 - fi - else - echo "$default: MODE must set to 'discovery', 'in-band', or 'out-of-band'" >&2 - echo "Run ofp-switch-setup (in the openflow-switch-config package) or edit /etc/default/openflow-switch to configure" >&2 - exit 1 - fi - : ${PRIVKEY:=/etc/openflow-switch/of0-privkey.pem} - : ${CERT:=/etc/openflow-switch/of0-cert.pem} - : ${CACERT:=/etc/openflow-switch/cacert.pem} - case $CONTROLLER in - '') - # Discovery mode. - if test -e "$PRIVKEY"; then - configure_ssl - fi - ;; - tcp:*) - ;; - ssl:*) - configure_ssl - ;; - *) - echo "$default: CONTROLLER must be in the form 'ssl:HOST[:PORT]' or 'tcp:HOST[:PORT]' when not in discovery mode" >&2 - echo "Run ofp-switch-setup (in the openflow-switch-config package) or edit /etc/default/openflow-switch to configure" >&2 - exit 1 - esac - case $DISCONNECTED_MODE in - ''|switch|drop) ;; - *) echo "$default: warning: DISCONNECTED_MODE is not 'switch' or 'drop'" >&2 ;; - esac - - check_int_var RATE_LIMIT 100 - check_int_var INACTIVITY_PROBE 5 - check_int_var MAX_BACKOFF 1 - - check_new_option --fail DISCONNECTED_MODE - check_new_option --stp STP - check_new_option --rate-limit RATE_LIMIT - check_new_option --inactivity INACTIVITY_PROBE - check_new_option --max-backoff MAX_BACKOFF - case $DAEMON_OPTS in - *--rate-limit*) - echo "$default: --rate-limit may now be set with RATE_LIMIT" >&2 - esac - - echo -n "Loading openflow_mod: " - if grep -q '^openflow_mod$' /proc/modules; then - echo "already loaded, nothing to do." - elif modprobe openflow_mod; then - echo "success." - else - echo "ERROR." - echo "openflow_mod has probably not been built for this kernel." - if ! test -d /usr/share/doc/openflow-datapath-source; then - echo "Install the openflow-datapath-source package, then read" - echo "/usr/share/doc/openflow-datapath-source/README.Debian" - else - echo "For instructions, read" - echo "/usr/share/doc/openflow-datapath-source/README.Debian" - fi - exit 1 - fi - - for netdev in $NETDEVS; do - check_op "Removing IP address from $netdev" ifconfig $netdev 0.0.0.0 - done - - must_succeed "Adding datapath" dpctl adddp nl:0 - for netdev in $NETDEVS; do - must_succeed "Adding $netdev to datapath" dpctl addif nl:0 $netdev - done - - xx='[0-9abcdefABCDEF][0-9abcdefABCDEF]' - case $DATAPATH_ID in - '') - # Check if the DMI System UUID contains a Nicira mac address - # that should be used for this datapath. The UUID is assumed - # to be RFC 4122 compliant. - DMIDECODE=`which dmidecode` - if [ -n $DMIDECODE ]; then - UUID_MAC=`$DMIDECODE -s system-uuid | cut -d'-' -f 5` - case $UUID_MAC in - $NICIRA_OUI*) - ifconfig of0 down - must_succeed "Setting of0 MAC address to $UUID_MAC" ifconfig of0 hw ether $UUID_MAC - ifconfig of0 up - ;; - esac - fi - ;; - $xx:$xx:$xx:$xx:$xx:$xx) - ifconfig of0 down - must_succeed "Setting of0 MAC address to $DATAPATH_ID" ifconfig of0 hw ether $DATAPATH_ID - ifconfig of0 up - ;; - *) - echo "DATAPATH_ID is not a valid MAC address in the form XX:XX:XX:XX:XX:XX, ignoring" >&2 - ;; - esac - - if test "$MODE" = in-band; then - if test "$SWITCH_IP" = dhcp; then - must_succeed "Temporarily disabling of0" ifconfig of0 down - else - COMMAND="ifconfig of0 $SWITCH_IP" - if test -n "$SWITCH_NETMASK"; then - COMMAND="$COMMAND netmask $SWITCH_NETMASK" - fi - must_succeed "Configuring of0: $COMMAND" $COMMAND - if test -n "$SWITCH_GATEWAY"; then - # This can fail because the route already exists, - # so we don't insist that it succeed. - COMMAND="route add default gw $SWITCH_GATEWAY" - check_op "Adding default route: $COMMAND" $COMMAND - fi - fi - else - must_succeed "Disabling of0" ifconfig of0 down - fi - - if test -n "$CORE_LIMIT"; then - check_op "Setting core limit to $CORE_LIMIT" ulimit -c "$CORE_LIMIT" - fi - - # Compose secchan options. - set -- - set -- "$@" --verbose=ANY:console:emer --verbose=ANY:syslog:err - set -- "$@" --log-file - set -- "$@" --detach --pidfile=$PIDFILE - for vconn in $MGMT_VCONNS; do - set -- "$@" --listen="$vconn" - done - if test -n "$MONITOR_VCONN"; then - set -- "$@" --monitor="$MONITOR_VCONN" - fi - if test -n "$COMMANDS"; then - set -- "$@" --command-acl="$COMMANDS" - fi - case $STP in - yes) set -- "$@" --stp ;; - no) set -- "$@" --no-stp ;; - esac - case $DISCONNECTED_MODE in - switch) set -- "$@" --fail=open ;; - drop) set -- "$@" --fail=closed ;; - esac - if test -n "$RATE_LIMIT"; then - set -- "$@" --rate-limit=$RATE_LIMIT - fi - if test -n "$INACTIVITY_PROBE"; then - set -- "$@" --inactivity-probe=$INACTIVITY_PROBE - fi - if test -n "$MAX_BACKOFF"; then - set -- "$@" --max-backoff=$MAX_BACKOFF - fi - set -- "$@" $SSL_OPTS $DAEMON_OPTS - if test "$MODE" = out-of-band; then - set -- "$@" --out-of-band - fi - set -- "$@" nl:0 "$CONTROLLER" - echo -n "Starting $DESC: " - start-stop-daemon --start --quiet --pidfile $PIDFILE \ - --exec $DAEMON -- "$@" - if running; then - echo "$NAME." - else - echo " ERROR." - fi - - if test "$MODE" = in-band && test "$SWITCH_IP" = dhcp; then - echo -n "Starting dhclient on of0: " - start-stop-daemon --start --quiet --pidfile $DHCLIENT_PIDFILE \ - --exec /sbin/dhclient -- -q -pf $DHCLIENT_PIDFILE of0 - if running; then - echo "dhclient." - else - echo " ERROR." - fi - fi - ;; - stop) - if test -e /var/run/dhclient.of0.pid; then - echo -n "Stopping dhclient on of0: " - start-stop-daemon --stop --quiet --oknodo \ - --pidfile $DHCLIENT_PIDFILE --exec /sbin/dhclient - echo "dhclient." - fi - - echo -n "Stopping $DESC: " - start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE \ - --exec $DAEMON - echo "$NAME." - - for netdev in $NETDEVS; do - check_op "Removing $netdev from datapath" dpctl delif nl:0 $netdev - done - check_op "Deleting datapath" dpctl deldp nl:0 - check_op "Unloading kernel module" modprobe -r openflow_mod - ;; - force-stop) - echo -n "Forcefully stopping $DESC: " - force_stop - if ! running; then - echo "$NAME." - else - echo " ERROR." - fi - ;; - reload) - ;; - force-reload) - start-stop-daemon --stop --test --quiet --pidfile \ - $PIDFILE --exec $DAEMON \ - && $0 restart \ - || exit 0 - ;; - restart) - $0 stop || true - $0 start - ;; - status) - echo -n "$NAME is " - if running ; then - echo "running" - else - echo " not running." - exit 1 - fi - ;; - *) - N=/etc/init.d/$NAME - echo "Usage: $N {start|stop|restart|force-reload|status|force-stop}" >&2 - exit 1 - ;; -esac - -exit 0 diff --git a/openflow/debian/openflow-switch.install b/openflow/debian/openflow-switch.install deleted file mode 100644 index b325e3cc..00000000 --- a/openflow/debian/openflow-switch.install +++ /dev/null @@ -1,6 +0,0 @@ -_debian/secchan/ofprotocol usr/sbin -_debian/utilities/dpctl usr/sbin -_debian/utilities/ofp-discover usr/sbin -_debian/utilities/ofp-kill usr/sbin -debian/openflow/usr/share/openflow/commands/* usr/share/openflow/commands -debian/commands/* usr/share/openflow/commands diff --git a/openflow/debian/openflow-switch.logrotate b/openflow/debian/openflow-switch.logrotate deleted file mode 100644 index b2136907..00000000 --- a/openflow/debian/openflow-switch.logrotate +++ /dev/null @@ -1,11 +0,0 @@ -/var/log/openflow/secchan.log { - daily - compress - create 640 root adm - delaycompress - missingok - rotate 30 - postrotate - vlogconf --target /var/run/secchan.pid --reopen - endscript -} diff --git a/openflow/debian/openflow-switch.manpages b/openflow/debian/openflow-switch.manpages deleted file mode 100644 index dd636ac8..00000000 --- a/openflow/debian/openflow-switch.manpages +++ /dev/null @@ -1,4 +0,0 @@ -_debian/secchan/ofprotocol.8 -_debian/utilities/ofp-discover.8 -_debian/utilities/ofp-kill.8 -_debian/utilities/dpctl.8 diff --git a/openflow/debian/openflow-switch.postinst b/openflow/debian/openflow-switch.postinst deleted file mode 100755 index 4f96db3a..00000000 --- a/openflow/debian/openflow-switch.postinst +++ /dev/null @@ -1,51 +0,0 @@ -#!/bin/sh -# postinst script for openflow-switch -# -# see: dh_installdeb(1) - -set -e - -# summary of how this script can be called: -# * `configure' -# * `abort-upgrade' -# * `abort-remove' `in-favour' -# -# * `abort-remove' -# * `abort-deconfigure' `in-favour' -# `removing' -# -# for details, see http://www.debian.org/doc/debian-policy/ or -# the debian-policy package - - -case "$1" in - configure) - DEFAULT=/etc/default/openflow-switch - TEMPLATE=/usr/share/openflow/switch/default.template - if ! test -e $DEFAULT; then - cp $TEMPLATE $DEFAULT - else - for var in $(awk -F'[ :]' '/^# [_A-Z0-9]+:/{print $2}' $TEMPLATE) - do - if ! grep $var $DEFAULT >/dev/null 2>&1; then - echo >> $DEFAULT - sed -n "/$var:/,/$var=/p" $TEMPLATE >> $DEFAULT - fi - done - fi - ;; - - abort-upgrade|abort-remove|abort-deconfigure) - ;; - - *) - echo "postinst called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -#DEBHELPER# - -exit 0 - - diff --git a/openflow/debian/openflow-switch.postrm b/openflow/debian/openflow-switch.postrm deleted file mode 100755 index 20bab0e0..00000000 --- a/openflow/debian/openflow-switch.postrm +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/sh -# postrm script for openflow-switch -# -# see: dh_installdeb(1) - -set -e - -# summary of how this script can be called: -# * `remove' -# * `purge' -# * `upgrade' -# * `failed-upgrade' -# * `abort-install' -# * `abort-install' -# * `abort-upgrade' -# * `disappear' -# -# for details, see http://www.debian.org/doc/debian-policy/ or -# the debian-policy package - - -case "$1" in - purge) - rm -f /etc/default/openflow-switch - ;; - - remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) - ;; - - *) - echo "postrm called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -# dh_installdeb will replace this with shell code automatically -# generated by other debhelper scripts. - -#DEBHELPER# - -exit 0 - - diff --git a/openflow/debian/openflow-switch.template b/openflow/debian/openflow-switch.template deleted file mode 100644 index f3f641e8..00000000 --- a/openflow/debian/openflow-switch.template +++ /dev/null @@ -1,169 +0,0 @@ -# This is a POSIX shell fragment -*- sh -*- - -# To configure the secure channel, fill in the following properly and -# uncomment them. Afterward, the secure channel will come up -# automatically at boot time. It can be started immediately with -# /etc/init.d/openflow-switch start -# Alternatively, use the ofp-switch-setup program (from the -# openflow-switch-config package) to do everything automatically. - -# NETDEVS: Which network devices should the OpenFlow switch include? -# -# List the network devices that should become part of the OpenFlow -# switch, separated by spaces. At least two devices must be selected -# for this machine to be a useful switch. Unselecting all network -# devices will disable the OpenFlow switch entirely. -# -# The network devices that you select should not be configured with IP -# or IPv6 addresses, even if the switch contacts the controller over -# one of the selected network devices. This is because a running -# OpenFlow switch takes over network devices at a low level: they -# become part of the switch and cannot be used for other purposes. -#NETDEVS="" - -# MODE: The OpenFlow switch has three modes that determine how it -# reaches the controller: -# -# * in-band with discovery: A single network is used for OpenFlow -# traffic and other data traffic; that is, the switch contacts the -# controller over one of the network devices selected as OpenFlow -# switch ports. The switch automatically determines the location of -# the controller using a DHCP request with an OpenFlow-specific -# vendor option. This is the most common case. -# -# * in-band: As above, but the location of the controller is manually -# configured. -# -# * out-of-band: OpenFlow traffic uses a network separate from the -# data traffic that it controls. If this is the case, the control -# network must already be configured on a network device other than -# one of those selected as an OpenFlow switch port in the previous -# question. -# -# Set MODE to 'discovery', 'in-band', or 'out-of-band' for these -# respective cases. -MODE=discovery - -# SWITCH_IP: In 'in-band' mode, the switch's IP address may be -# configured statically or dynamically: -# -# * For static configuration, specify the switch's IP address as a -# string. In this case you may also set SWITCH_NETMASK and -# SWITCH_GATEWAY appropriately (see below). -# -# * For dynamic configuration with DHCP (the most common case), -# specify "dhcp". Configuration with DHCP will only work reliably -# if the network topology allows the switch to contact the DHCP -# server before it connects to the OpenFlow controller. -# -# This setting has no effect unless MODE is set to 'in-band'. -SWITCH_IP=dhcp - -# SWITCH_NETMASK: IP netmask to use in 'in-band' mode when the switch -# IP address is not 'dhcp'. -#SWITCH_NETMASK=255.255.255.0 - -# SWITCH_GATEWAY: IP gateway to use in 'in-band' mode when the switch -# IP address is not 'dhcp'. -#SWITCH_GATEWAY=192.168.1.1 - -# CONTROLLER: Location of controller. -# One of the following formats: -# tcp:HOST[:PORT] via TCP to PORT (default: 6633) on HOST -# ssl:HOST[:PORT] via SSL to PORT (default: 6633) on HOST -# The default below assumes that the controller is running locally. -# This setting has no effect when MODE is set to 'discovery'. -#CONTROLLER="tcp:127.0.0.1" - -# PRIVKEY: Name of file containing switch's private key. -# Required if SSL enabled. -#PRIVKEY=/etc/openflow-switch/of0-privkey.pem - -# CERT: Name of file containing certificate for private key. -# Required if SSL enabled. -#CERT=/etc/openflow-switch/of0-cert.pem - -# CACERT: Name of file containing controller CA certificate. -# Required if SSL enabled. -#CACERT=/etc/openflow-switch/cacert.pem - -# CACERT_MODE: Two modes are available: -# -# * secure: The controller CA certificate named in CACERT above must exist. -# (You must copy it manually from the PKI server or another trusted source.) -# -# * bootstrap: If the controller CA certificate named in CACERT above does -# not exist, the switch will obtain it from the controller the first time -# it connects and save a copy to the file named in CACERT. This is insecure, -# in the same way that initial connections with ssh are insecure, but -# it is convenient. -# -# Set CACERT_MODE to 'secure' or 'bootstrap' for these respective cases. -#CACERT_MODE=secure - -# MGMT_VCONNS: List of vconns (space-separated) on which secchan -# should listen for management connections from dpctl, etc. -# openflow-switchui by default connects to -# unix:/var/run/secchan.mgmt, so do not disable this if you want to -# use openflow-switchui. -MGMT_VCONNS="punix:/var/run/secchan.mgmt" - -# MONITOR_VCONN: Name of vconn on which secchan should listen for -# monitoring connections from dpctl. -MONITOR_VCONN="punix:/var/run/secchan.monitor" - -# COMMANDS: Access control list for the commands that can be executed -# remotely over the OpenFlow protocol, as a comma-separated list of -# shell glob patterns. Negative patterns (beginning with !) act as a -# blacklist. To be executable, a command name must match one positive -# pattern and not match any negative patterns. -#COMMANDS="reboot,update" - -# DISCONNECTED_MODE: Switch behavior when attempts to connect to the -# controller repeatedly fail, either 'switch', to act as an L2 switch -# in this case, or 'drop', to drop all packets (except those necessary -# to connect to the controller). If unset, the default is 'drop'. -#DISCONNECTED_MODE=switch - -# STP: Enable or disabled 802.1D-1998 Spanning Tree Protocol. Set to -# 'yes' to enable STP, 'no' to disable it. If unset, secchan's -# current default is 'no' (but this may change in the future). -#STP=no - -# RATE_LIMIT: Maximum number of received frames, that do not match any -# existing switch flow, to forward up to the controller per second. -# The valid range is 100 and up. If unset, this rate will not be -# limited. -#RATE_LIMIT=1000 - -# INACTIVITY_PROBE: The maximum number of seconds of inactivity on the -# controller connection before secchan sends an inactivity probe -# message to the controller. The valid range is 5 and up. If unset, -# secchan defaults to 15 seconds. -#INACTIVITY_PROBE=5 - -# MAX_BACKOFF: The maximum time that secchan will wait between -# attempts to connect to the controller. The valid range is 1 and up. -# If unset, secchan defaults to 15 seconds. -#MAX_BACKOFF=15 - -# DAEMON_OPTS: Additional options to pass to secchan, e.g. "--fail=open" -DAEMON_OPTS="" - -# CORE_LIMIT: Maximum size for core dumps. -# -# Leaving this unset will use the system default. Setting it to 0 -# will disable core dumps. Setting it to "unlimited" will dump all -# core files regardless of size. -#CORE_LIMIT=unlimited - -# DATAPATH_ID: Identifier for this switch. -# -# By default, the switch checks if the DMI System UUID contains a Nicira -# mac address to use as a datapath ID. If not, then the switch generates -# a new, random datapath ID every time it starts up. By setting this -# value, the supplied datapath ID will always be used. -# -# Set DATAPATH_ID to a MAC address in the form XX:XX:XX:XX:XX:XX where each -# X is a hexadecimal digit (0-9 or a-f). -#DATAPATH_ID=XX:XX:XX:XX:XX:XX diff --git a/openflow/debian/po/POTFILES.in b/openflow/debian/po/POTFILES.in deleted file mode 100644 index e3ea07e3..00000000 --- a/openflow/debian/po/POTFILES.in +++ /dev/null @@ -1 +0,0 @@ -[type: gettext/rfc822deb] openflow-switch-config.templates diff --git a/openflow/debian/rules b/openflow/debian/rules deleted file mode 100755 index 539c8f3d..00000000 --- a/openflow/debian/rules +++ /dev/null @@ -1,163 +0,0 @@ -#!/usr/bin/make -f -# -*- makefile -*- -# Sample debian/rules that uses debhelper. -# -# This file was originally written by Joey Hess and Craig Small. -# As a special exception, when this file is copied by dh-make into a -# dh-make output file, you may use that output file without restriction. -# This special exception was added by Craig Small in version 0.37 of dh-make. -# -# Modified to make a template file for a multi-binary package with separated -# build-arch and build-indep targets by Bill Allombert 2001 - -# Uncomment this to turn on verbose mode. -#export DH_VERBOSE=1 - -# This has to be exported to make some magic below work. -export DH_OPTIONS - -# prefix of the target package name -PACKAGE=openflow-datapath-module -# modifieable for experiments or debugging m-a -MA_DIR ?= /usr/share/modass -# load generic variable handling --include $(MA_DIR)/include/generic.make -# load default rules --include $(MA_DIR)/include/common-rules.make - --include debian/rules.ext - -DATAPATH_CONFIGURE_OPTS = --enable-snat - -# Official build number. Leave set to 0 if not an official build. -BUILD_NUMBER = 0 - -configure: configure-stamp -configure-stamp: - dh_testdir - test -e configure || ./boot.sh - test -d _debian || mkdir _debian - cd _debian && ( \ - test -e Makefile || \ - ../configure --prefix=/usr --localstatedir=/var --enable-ssl \ - --with-build-number=$(BUILD_NUMBER) \ - $(DATAPATH_CONFIGURE_OPTS)) - $(ext_configure) - touch configure-stamp - -#Architecture -build: build-arch build-indep - -build-arch: build-arch-stamp -build-arch-stamp: configure-stamp - $(MAKE) -C _debian - $(ext_build_arch) - touch $@ - -build-indep: build-indep-stamp -build-indep-stamp: configure-stamp - $(MAKE) -C _debian dist distdir=openflow - $(ext_build_indep) - touch $@ - -clean: - dh_testdir - dh_testroot - rm -f build-arch-stamp build-indep-stamp configure-stamp - rm -rf _debian - [ ! -f Makefile ] || $(MAKE) distclean - $(ext_clean) - dh_clean - debconf-updatepo - -MAJOR=$(shell echo $(KVERS) | sed -e 's/\(...\).*/\1/') -ifeq ($(MAJOR),2.6) -KO=k -l2x=l26 -dpdir=datapath/linux-2.6 -else -KO= -l2x=l24 -dpdir=datapath/linux-2.4 -endif - -kdist_clean: - dh_clean - rm -rf openflow - -kdist_config: prep-deb-files - -binary-modules: DSTDIR = $(CURDIR)/debian/$(PKGNAME)/lib/modules/$(KVERS) -binary-modules: prep-deb-files - dh_testdir - dh_testroot - dh_clean -k - tar xzf openflow.tar.gz - cd openflow && ./configure --with-$(l2x)=$(KSRC) $(DATAPATH_CONFIGURE_OPTS) --with-build-number=$(BUILD_NUMBER) - cd openflow && $(MAKE) -C $(dpdir) - install -d -m755 $(DSTDIR) - install -m644 openflow/$(dpdir)/*_mod.$(KO)o $(DSTDIR)/ - dh_installdocs - dh_installchangelogs - dh_compress - dh_fixperms - dh_installdeb - dh_gencontrol - dh_md5sums - dh_builddeb --destdir=$(DEB_DESTDIR) - -install: install-indep install-arch -install-indep: build-indep - dh_testdir - dh_testroot - dh_clean -k -i - dh_installdirs -i - dh_install -i - cd debian/openflow-datapath-source/usr/src && tar -c modules | bzip2 -9 > openflow-datapath.tar.bz2 && rm -rf modules - install -m644 debian/openflow-pki-server.apache2 debian/openflow-pki-server/etc/apache2/sites-available/openflow-pki - install -m1777 -d debian/corekeeper/var/log/core - $(ext_install_indep) - -install-arch: build-arch - dh_testdir - dh_testroot - dh_clean -k -s - dh_installdirs -s - $(MAKE) -C _debian DESTDIR=$(CURDIR)/debian/openflow install - cp debian/openflow-switch-config.overrides debian/openflow-switch-config/usr/share/lintian/overrides/openflow-switch-config - cp debian/openflow-switch.template debian/openflow-switch/usr/share/openflow/switch/default.template - dh_install -s - $(ext_install_arch) - -# Must not depend on anything. This is to be called by -# binary-arch/binary-indep -# in another 'make' thread. -binary-common: - dh_testdir - dh_testroot - dh_installchangelogs - dh_installdocs - dh_installexamples - dh_installdebconf - dh_installlogrotate - dh_installinit - dh_installcron - dh_installman - dh_link - dh_strip --dbg-package=openflow-dbg - dh_compress - dh_fixperms -X var/log/core - dh_perl - dh_makeshlibs - dh_installdeb - dh_shlibdeps - dh_gencontrol - dh_md5sums - dh_builddeb -binary-indep: install-indep - $(MAKE) -f debian/rules DH_OPTIONS=-i binary-common -binary-arch: install-arch - $(MAKE) -f debian/rules DH_OPTIONS=-s binary-common - -binary: binary-arch binary-indep -.PHONY: build clean binary-indep binary-arch binary install install-indep install-arch configure diff --git a/openflow/doc/of-spec/.gitignore b/openflow/doc/of-spec/.gitignore deleted file mode 100644 index 7723a762..00000000 --- a/openflow/doc/of-spec/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -/*.aux -/*.log -/*.out -/*.pdf -/*.ps -/define -/enum -/struct diff --git a/openflow/doc/of-spec/Makefile b/openflow/doc/of-spec/Makefile deleted file mode 100644 index 0e4c9462..00000000 --- a/openflow/doc/of-spec/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -TARGET=openflow-spec-v1.0.0 - -BIBTEX := bibtex -TGIF := tgif -XFIG := xfig -GNUPLOT:= gnuplot - -SOURCES=openflow-spec-v1.0.0.tex\ - appendix.tex - -all: $(TARGET).ps -pdf: all - -$(TARGET).pdf: Makefile $(SOURCES) - ./make_latex_input.pl - texi2pdf $(TARGET).tex - -color: $(TARGET).pdf - pdflatex $(TARGET).tex - pdftops $(TARGET).pdf - -$(TARGET).ps: $(TARGET).pdf - pdftops $(TARGET).pdf - -%.pdf : %.fig #Makefile - fig2dev -L pdf -b 1 $< $@ - -%.eps : %.dia #Makefile - dia --nosplash -e $@ $< - -%.eps : %.obj - TMPDIR=/tmp $(TGIF) -print -eps $< - - -%.pdf : %.eps #Makefile - epstopdf $< - -clean: - rm -f *.aux *.log *.out *.bbl *.blg *~ *.bak $(TARGET).ps $(TARGET).pdf - rm -rf define enum struct diff --git a/openflow/doc/of-spec/README b/openflow/doc/of-spec/README deleted file mode 100644 index a010f5dd..00000000 --- a/openflow/doc/of-spec/README +++ /dev/null @@ -1,3 +0,0 @@ -To build the latest OpenFlow specification, you should just be able to -type "make". For this to work, you'll need to have the texinfo and -"listings.sty" packages installed. diff --git a/openflow/doc/of-spec/appendix.tex b/openflow/doc/of-spec/appendix.tex deleted file mode 100755 index ffac6bbb..00000000 --- a/openflow/doc/of-spec/appendix.tex +++ /dev/null @@ -1,429 +0,0 @@ -%\appendix -\section{Appendix A: The OpenFlow Protocol} -The heart of the OpenFlow spec is the set of structures used for OpenFlow Protocol messages. -\\\\ -The structures, defines, and enumerations described below are derived from the file \verb|include/openflow/openflow.h|, which is part of the standard OpenFlow distribution. All structures are packed with padding and 8-byte aligned, as checked by the assertion statements. All OpenFlow messages are sent in big-endian format. - -\subsection{OpenFlow Header} -Each OpenFlow message begins with the OpenFlow header: - -\input{struct/ofp_header} -The version specifies the OpenFlow protocol version being used. During the current draft phase of the OpenFlow Protocol, the most significant bit will be set to indicate an experimental version and the lower bits will indicate a revision number. The current version is \input{define/OFP_VERSION}. The final version for a Type 0 switch will be 0x00. The length field indicates the total length of the message, so no additional framing is used to distinguish one frame from the next. The type can have the following values: - -\input{enum/ofp_type} - -\subsection{Common Structures} -This section describes structures used by multiple messages. - -\subsubsection{Port Structures} -Physical ports are described with the following structure: - -\input{struct/ofp_phy_port} -The \verb|port_no| field is a value the datapath associates with a physical port. The \verb|hw_addr| field typically is the MAC address for the port; \verb|OFP_MAX_ETH_ALEN| is 6. The name field is a null-terminated string containing a human-readable name for the interface. The value of \verb|OFP_MAX_PORT_NAME_LEN| is 16. -\\\\ -The \verb|config| field describes spanning tree and administrative settings with the following structure: - -\input{enum/ofp_port_config} -The port config bits indicate whether a port has been administratively brought down, options for handling 802.1D spanning tree packets, and how to handle incoming and outgoing packets. These bits, configured over multiple switches, enable an OpenFlow network to safely flood packets along either a custom or 802.1D spanning tree. -\\\\ -The controller may set \verb|OFPPFL_NO_STP| to 0 to enable STP on a port or to 1 to disable STP on a port. (The latter corresponds to the Disabled STP port state.) The default is switch implementation-defined; the OpenFlow reference implementation by default sets this bit to 0 (enabling STP). -\\\\ -When \verb|OFPPFL_NO_STP| is 0, STP controls the \verb|OFPPFL_NO_FLOOD| and \verb|OFPPFL_STP_*| bits directly. \verb|OFPPFL_NO_FLOOD| is set to 0 when the STP port state is Forwarding, otherwise to 1. The bits in \verb|OFPPFL_STP_MASK| are set to one of the other \verb|OFPPFL_STP_*| values according to the current STP port state. -\\\\ -When the port flags are changed by STP, the switch sends an \verb|OFPT_PORT_STATUS| message to notify the controller of the change. The \verb|OFPPFL_NO_RECV|, \verb|OFPPFL_NO_RECV_STP|, \verb|OFPPFL_NO_FWD|, and \verb|OFPPFL_NO_PACKET_IN| bits in the OpenFlow port flags may be useful for the controller to implement STP, although they interact poorly with in-band control. -\\\\ -The \verb|state| field describes the spanning tree state and whether a physical link is present, with the following structure: - -\input{enum/ofp_port_state} -All port state bits are read-only, representing spanning tree and physical link state. -\\\\ -The port numbers use the following conventions: - -\input{enum/ofp_port} -The \verb|curr|, \verb|advertised|, \verb|supported|, and \verb|peer| fields indicate link modes (10M to 10G full and half-duplex), link type (copper/fiber) and link features (autonegotiation and pause). Port features are represent by the following structure: - -\input{enum/ofp_port_features} -Multiple of these flags may be set simultaneously. - -\subsubsection{\qosupd{Queue Structures}} -\label{cts:qos} -\qosupd{An OpenFlow switch provides limited Quality-of-Service support - (QoS) through a simple queuing -mechanism. One (or more) queues can attach to a port and be used to map flows -on it. Flows mapped to a specific queue will be treated according to -that queue's configuration (e.g. min rate). -\\\\ -A queue is described by the} \verb|ofp_packet_queue| \qosupd{structure: -\input{struct/ofp_packet_queue} -Each queue is further described by a set of properties, each of a -specific type and configuration. -\input{enum/ofp_queue_properties} -Each queue property description starts with a common header: -\input{struct/ofp_queue_prop_header} -Currently, there is only a minimum-rate type queue, described by the} -\verb|ofp_queue_prop_min_rate| \qosupd{structure: -\input{struct/ofp_queue_prop_min_rate}} - -\subsubsection{Flow Match Structures} -When describing a flow entry, the following structure is used: - -\input{struct/ofp_match} -The \verb|wildcards| field has a number of flags that may be set: - -\input{enum/ofp_flow_wildcards} -If no wildcards are set, then the \verb|ofp_match| exactly describes a flow, over the entire OpenFlow 12-tuple. On the other extreme, if all the wildcard flags are set, then every flow will match. -\\\\ -The source and destination netmasks are each specified with a 6-bit number in the wildcard description. It is interpreted similar to the CIDR suffix, but with the opposite meaning, since this is being used to indicate which bits in the IP address should be treated as ``wild". For example, a CIDR suffix of "24" means to use a netmask of ``255.255.255.0". However, a wildcard mask value of ``24" means that the least-significant 24-bits are wild, so it forms a netmask of ``255.0.0.0". - -\subsubsection{Flow Action Structures} -A number of actions may be associated with flows or packets. The currently defined action types are: - -\input{enum/ofp_action_type} -Output \qosupd{and enqueue} actions are described in Section \ref{ft:actions}, while Field-Modify actions are described in Table \ref{table:field modify actions}. An action definition contains the action type, length, and any associated data: - -\input{struct/ofp_action_header} -An \verb|action_output| has the following fields: - -\input{struct/ofp_action_output} -The \verb|max_len| indicates the maximum amount of data from a packet that should be sent when the port is \verb|OFPP_CONTROLLER|. If \verb|max_len| is zero, the switch must send a zero-size \verb|packet_in| message. The \verb|port| specifies the physical port from which packets should be sent. - \\\\ -\qosupd{The enqueue action maps a flow to an already-configured queue, regardless of the TOS and VLAN PCP bits. - The packet should not change after an enqueue action. If the switch - needs to set the TOS/PCP bits for internal handling, the original values - should be restored before sending the packet out. -\\\\ -A switch may support only queues that are tied to specific PCP/TOS -bits. In that case, we cannot map an arbitrary flow to a specific -queue, therefore the action ENQUEUE is not supported. The user can -still use these queues and map -flows to them by setting the relevant fields (TOS, VLAN PCP). -\\\\ -The enqueue action has the following fields: - -\input{struct/ofp_action_enqueue}} -An \verb|action_vlan_vid| has the following fields: - -\input{struct/ofp_action_vlan_vid} -The \verb|vlan_vid| field is 16 bits long, when an actual VLAN id is only 12 bits. The value \verb|0xffff| is used to indicate that no VLAN id was set. -\\\\ -An \verb|action_vlan_pcp| has the following fields: - -\input{struct/ofp_action_vlan_pcp} -The \verb|vlan_pcp| field is 8 bits long, but only the lower 3 bits have meaning. -\\\\ -An \verb|action_strip_vlan| takes no arguments and consists only of a generic \verb|ofp_action_header|. This action strips the VLAN tag if one is present. -\\\\ -An \verb|action_dl_addr| has the following fields: - -\input{struct/ofp_action_dl_addr} -The \verb|dl_addr| field is the MAC address to set. -\\\\ -An \verb|action_nw_addr| has the following fields: - -\input{struct/ofp_action_nw_addr} -The \verb|nw_addr| field is the IP address to set. -\\\\ -An \verb|action_nw_tos| has the following fields: - -\input{struct/ofp_action_nw_tos} -The \verb|nw_tos| field is the 6 upper bits of the ToS field to set, in the original bit positions (shifted to the left by 2). -\\\\ -An \verb|action_tp_port| has the following fields: - -\input{struct/ofp_action_tp_port} -The \verb|tp_port| field is the TCP/UDP/other port to set. -\\\\ -An \verb|action_vendor| has the following fields: - -\input{struct/ofp_action_vendor_header} -The \verb|vendor| field is the Vendor ID, which takes the same form as in struct \verb|ofp_vendor|. - -\subsection{Controller-to-Switch Messages} - -\subsubsection{Handshake} -\label{cts:handshake} -Upon TLS session establishment, the controller sends an \verb|OFPT_FEATURES_REQUEST| message. This message does not contain a body beyond the OpenFlow header. The switch responds with an \verb|OFPT_FEATURES_REPLY| message: - -\input{struct/ofp_switch_features} -The \verb|datapath_id| field uniquely identifies a datapath. The lower 48 bits are intended for the switch MAC address, while the top 16 bits are up to the implementer. An example use of the top 16 bits would be a VLAN ID to distinguish multiple virtual switch instances on a single physical switch. This field should be treated as an opaque bit string by controllers. -\\\\ -The \verb|n_tables| field describes the number of tables supported by the switch, each of which can have a different set of supported wildcard bits and number of entries. When the controller and switch first communicate, the controller will find out how many tables the switch supports from the Features Reply. If it wishes to understand the size, types, and order in which tables are consulted, the controller sends a \verb|OFPST_TABLE| stats request. A switch must return these tables in the order the packets traverse the tables, with all exact-match tables listed before all tables with wildcards. -\\\\ -The \verb|capabilities| field uses the following flags: - -\input{enum/ofp_capabilities} -The \verb|actions| field is a bitmap of actions supported by the switch. The list of actions is found in Section~\ref{ft:actions}; all actions marked Required must be supported. Vendor actions should \emph{not} be reported via this bitmask. The bitmask uses the values from \verb|ofp_action_type| as the number of bits to shift left for an associated action. For example, \verb|OFPAT_SET_DL_VLAN| would use the flag \verb|0x00000002|. -\\\\ -The \verb|ports| field is an array of \verb|ofp_phy_port| structures that describe all the physical ports in the system that support OpenFlow. The number of port elements is inferred from the length field in the OpenFlow header. - -\subsubsection{Switch Configuration} -The controller is able to set and query configuration parameters in the switch with the \verb|OFPT_SET_CONFIG| and \verb|OFPT_GET_CONFIG_REQUEST| messages, respectively. The switch responds to a configuration request with an \verb|OFPT_GET_CONFIG_REPLY| message; it does not reply to a request to set the configuration. -\\\\ -There is no body for \verb|OFPT_GET_CONFIG_REQUEST| beyond the OpenFlow header. The \verb|OFPT_SET_CONFIG| and \verb|OFPT_GET_CONFIG_REPLY| use the following: - -\input{struct/ofp_switch_config} -The configuration flags include the following: - -\input{enum/ofp_config_flags} -The \verb|OFPC_FRAG_*| flags indicate whether IP fragments should be treated normally, dropped, or reassembled. ``Normal" handling of fragments means that an attempt should be made to pass the fragments through the OpenFlow tables. If any field is not present (e.g., the TCP/UDP ports didn't fit), then the packet should not match any entry that has that field set. -\\\\ -The \verb|miss_send_len| field defines the number of bytes of each packet sent to the controller as a result of both flow table misses and flow table hits with the controller as the destination. If this field equals 0, the switch must send a zero-size \verb|packet_in| message. - -\subsubsection{Modify State Messages} -\paragraph{Modify Flow Entry Message} -Modifications to the flow table from the controller are done with the \verb|OFPT_FLOW_MOD| message: - -\input{struct/ofp_flow_mod} -The \verb|cookie| field is an opaque data value that is set by the -controller. It is not used in any matching functions, and thus does not -need to reside in hardware. The value -1 (0xffffffffffffffff) is -reserved and must not be used. It is required that when \verb|command| is -\verb|OFPC_MODIFY| or \verb|OFPC_MODIFY_STRICT| that matched flows have -their \verb|cookie| field updated appropriately. -\\\\ -The \verb|command| field must be one of the following: - -\input{enum/ofp_flow_mod_command} -The differences between \verb|OFPFC_MODIFY| and \verb|OFPFC_MODIFY_STRICT| are explained in Section \ref{flow_table:sec_chan:flow_mod} and differences between \verb|OFPFC_DELETE| and \verb|OFPFC_DELETE_STRICT| are explained in Section \ref{flow_table:sec_chan:flow_removal}. -\\\\ -The \verb|idle_timeout| and \verb|hard_timeout| fields control how quickly flows expire. -\\\\ -If the \verb|idle_timeout| is set and the \verb|hard_timeout| is zero, the entry must expire after \verb|idle_timeout| seconds with no received traffic. If the \verb|idle_timeout| is zero and the \verb|hard_timeout| is set, the entry must expire in \verb|hard_timeout| seconds regardless of whether or not packets are hitting the entry. -\\\\ -If both \verb|idle_timeout| and \verb|hard_timeout| are set, the flow will timeout after \verb|idle_timeout| seconds with no traffic, or \verb|hard_timeout| seconds, whichever comes first. If both \verb|idle_timeout| and \verb|hard_timeout| are zero, the entry is considered permanent and will never time out. It can still be removed with a \verb|flow_mod| message of type \verb|OFPFC_DELETE|. -\\\\ -The \verb|priority| field is only relevant for flow entries with wildcard fields. The priority field indicates table priority, where higher numbers are higher priorities; the switch must keep the highest-priority wildcard entries in the lowest-numbered (fastest) wildcard table, to ensure correctness. It is the responsibility of each switch implementer to ensure that exact entries always match before wildcards entries, regardless of the table configuration. -\\\\ -The \verb|buffer_id| refers to a buffered packet sent by the \verb|OFPT_PACKET_IN| message. -\\\\ -The \verb|out_port| field optionally filters the scope of DELETE and DELETE\_STRICT messages by output port. If \verb|out_port| contains a value other than \verb|OFPP_NONE|, it introduces a constraint when matching. This constraint is that the rule must contain an output action directed at that port. Other constraints such as \verb|ofp_match| structs and priorities are still used; this is purely an \emph{additional} constraint. Note that to disable output port filtering, \verb|out_port| must be set to \verb|OFPP_NONE|, since 0 is a valid port id. This field is ignored by ADD, MODIFY, and MODIFY\_STRICT messages. -\\\\ -The \verb|flags| field may include the follow flags: - -\input{enum/ofp_flow_mod_flags} -When the \verb|OFPFF_SEND_FLOW_REM| flag is set, the switch must send a flow removed message when the flow expires. The default is for the switch to not send flow removed messages for newly added flows. -\\\\ -When the \verb|OFPFF_CHECK_OVERLAP| flag is set, the switch must check that there are no conflicting entries with the same priority. If there is one, the flow mod fails and an error code is returned. -\\\\ -When the \verb|OFPFF_EMERG_| flag is set, the switch must consider this flow entry as an emergency entry, and only use it for forwarding when disconnected from the controller. - -\paragraph{Port Modification Message} -The controller uses the \verb|OFPT_PORT_MOD| message to modify the behavior of the physical port: - -\input{struct/ofp_port_mod} -The \verb|mask| field is used to select bits in the \verb|config| field to change. The \verb|advertise| field has no mask; all port features change together. - -\subsubsection{\qosupd{Queue Configuration Messages}} -\qosupd{Queue configuration takes place outside the OpenFlow protocol, either - through a command line tool or through an external dedicated configuration -protocol. -\\\\ -The controller can query the switch for configured queues on a port -using the following structure: -\input{struct/ofp_queue_get_config_request} -The switch replies back with an} \verb|ofp_queue_get_config_reply| \qosupd{command, containing -a list of configured queues. - -\input{struct/ofp_queue_get_config_reply} -} - -\subsubsection{Read State Messages} -While the system is running, the datapath may be queried about its current state using the \verb|OFPT_STATS_REQUEST| message: - -\input{struct/ofp_stats_request} -The switch responds with one or more \verb|OFPT_STATS_REPLY| messages: - -\input{struct/ofp_stats_reply} -The only value defined for \verb|flags| in a reply is whether more replies will follow this one - this has the value \verb|0x0001|. To ease implementation, the switch is allowed to send replies with no additional entries. However, it must always send another reply following a message with the �more� flag set. The transaction ids (xid) of replies must always match the request that prompted them. -\\\\ -In both the request and response, the \verb|type| field specifies the kind of information being passed and determines how the \verb|body| field is interpreted: - -\input{enum/ofp_stats_types} - -\paragraph{Description Statistics} -Information about the switch manufacturer, hardware revision, software revision, serial number, and a description field is available from the \verb|OFPST_DESC| stats request type: - -\input{struct/ofp_desc_stats} -Each entry is ASCII formatted and padded on the right with null bytes (\textbackslash0). \verb|DESC_STR_LEN| is \input{define/DESC_STR_LEN}and \verb|SERIAL_NUM_LEN| is \input{define/SERIAL_NUM_LEN}. Note: \footnote{Added to address concerns raised in \url{https://mailman.stanford.edu/pipermail/openflow-spec/2009-September/000504.html}} the \verb|dp_desc| field is a free-form string to describe the datapath for debugging purposes, e.g., ``switch3 in room 3120''. As such, it is not guaranteed to be unique and should not be used as the primary identifier for the datapath---use the \verb|datapath_id| field from the switch features instead (\S~\ref{cts:handshake}). - -\paragraph{Individual Flow Statistics} -Information about individual flows is requested with the \verb|OFPST_FLOW| stats request type: - -\input{struct/ofp_flow_stats_request} -The \verb|match| field contains a description of the flows that should be matched and may contain wildcards. This field's matching behavior is described in Section \ref{flow_table:sec_chan:flow_add}. -\\\\ -The \verb|table_id| field indicates the index of a single table to read, or \verb|0xff| for all tables. -\\\\ -The \verb|out_port| field optionally filters by output port. If \verb|out_port| contains a value other than \verb|OFPP_NONE|, it introduces a constraint when matching. This constraint is that the rule must contain an output action directed at that port. Other constraints such as \verb|ofp_match| structs are still used; this is purely an \emph{additional} constraint. Note that to disable output port filtering, \verb|out_port| must be set to \verb|OFPP_NONE|, since 0 is a valid port id. -\\\\ -The \verb|body| of the reply consists of an array of the following: - -\input{struct/ofp_flow_stats} -The fields consist of those provided in the \verb|flow_mod| that created these, plus the table into which the entry was inserted, the packet count, and the byte count. -\\\\ -\label{flow_duration_info}The \verb|duration_sec| and \verb|duration_nsec| fields indicate the elapsed time the flow has been installed in the switch. The total duration in nanoseconds can be computed as $\verb|duration_sec|*10^{9}$ + \verb|duration_nsec|. Implementations are required to provide millisecond precision; higher precision is encouraged where available. - -\paragraph{Aggregate Flow Statistics} -Aggregate information about multiple flows is requested with the \verb|OFPST_AGGREGATE| stats request type: - -\input{struct/ofp_aggregate_stats_request} -The \verb|match| field contains a description of the flows that should be matched and may contain wildcards. This field's matching behavior is described in Section \ref{flow_table:sec_chan:flow_add}. -\\\\ -The \verb|table_id| field indicates the index of a single table to read, or \verb|0xff| for all tables. -\\\\ -The \verb|out_port| field optionally filters by output port. If \verb|out_port| contains a value other than \verb|OFPP_NONE|, it introduces a constraint when matching. This constraint is that the rule must contain an output action directed at that port. Other constraints such as \verb|ofp_match| structs are still used; this is purely an \emph{additional} constraint. Note that to disable output port filtering, \verb|out_port| must be set to \verb|OFPP_NONE|, since 0 is a valid port id. -\\\\ -The \verb|body| of the reply consists of the following: - -\input{struct/ofp_aggregate_stats_reply} - -\paragraph{Table Statistics} -Information about tables is requested with the \verb|OFPST_TABLE| stats request type. The request does not contain any data in the body. -\\\\ -The body of the reply consists of an array of the following: - -\input{struct/ofp_table_stats} -The \verb|body| contains a \verb|wildcards| field, which indicates the fields for which that particular table supports wildcarding. For example, a direct look-up hash table would have that field set to zero, while a sequentially searched table would have it set to \verb|OFPFW_ALL|. The entries are returned in the order that packets traverse the tables. -\\\\ -\verb|OFP_MAX_TABLE_NAME_LEN| is \input{define/OFP_MAX_TABLE_NAME_LEN}. - -\paragraph{Port Statistics} -Information about physical ports is requested with the \verb|OFPST_PORT| stats request type: - -\input{struct/ofp_port_stats_request} -The \verb|port_no| field optionally filters the stats request to the given port. To request all port statistics, \verb|port_no| must be set to \verb|OFPP_NONE|. -\\\\ -The \verb|body| of the reply consists of an array of the following: - -\input{struct/ofp_port_stats} -The switch should return a value of -1 for unavailable counters. - -\paragraph{\qosupd{Queue Statistics}} -\qosupd{The} \verb|OFPST_QUEUE| \qosupd{stats request message provides - queue statistics for one or more ports. - The request body consists of a} \verb|port_no| \qosupd{field -identifying the port and a} \verb|queue_id|. \verb|OFPP_ALL| -\qosupd{refers to all ports, while} \verb|OFPQ_ALL| \qosupd{refers to all queues configured -at a port. - -\input{struct/ofp_queue_stats_request} -The body of the reply consists of an array of -the following structure: - -\input{struct/ofp_queue_stats}} - -\paragraph{Vendor Statistics} -Vendor-specific stats messages are requested with the \verb|OFPST_VENDOR| stats type. The first four bytes of the message are the vendor identifier. The rest of the body is vendor-defined. -\\\\ -The \verb|vendor| field is a 32-bit value that uniquely identifies the vendor. If the most significant byte is zero, the next three bytes are the vendor's IEEE OUI. If vendor does not have (or wish to use) their OUI, they should contact the OpenFlow consortium to obtain one. - -\subsubsection{Send Packet Message} -When the controller wishes to send a packet out through the datapath, it uses the \verb|OFPT_PACKET_OUT| message: - -\input{struct/ofp_packet_out} -The \verb|buffer_id| is the same given in the \verb|ofp_packet_in| message. If the \verb|buffer_id| is -1, then the packet data is included in the data array. If \verb|OFPP_TABLE| is specified as the output port of an action, the \verb|in_port| in the \verb|packet_out| message is used in the flow table lookup. - -\subsubsection{Barrier Message} -When the controller wants to ensure message dependencies have been met or wants to receive notifications for completed operations, it may use an \verb|OFPT_BARRIER_REQUEST| message. This message has no body. Upon receipt, the switch must finish processing all previously-received messages before executing any messages beyond the Barrier Request. When such processing is complete, the switch must send an \verb|OFPT_BARRIER_REPLY| message with the \verb|xid| of the original request. - -\subsection{Asynchronous Messages} -\subsubsection{Packet-In Message} -When packets are received by the datapath and sent to the controller, they use the \verb|OFPT_PACKET_IN| message: - -\input{struct/ofp_packet_in} -The \verb|buffer_id| is an opaque value used by the datapath to identify a buffered packet. When a packet is buffered, some number of bytes from the message will be included in the data portion of the message. If the packet is sent because of a ``send to controller'' action, then \verb|max_len| bytes from the \verb|action_output| of the flow setup request are sent. If the packet is sent because of a flow table miss, then at least \verb|miss_send_len| bytes from the \verb|OFPT_SET_CONFIG| message are sent. The default \verb|miss_send_len| is \input{define/OFP_DEFAULT_MISS_SEND_LEN}bytes. If the packet is not buffered, the entire packet is included in the data portion, and the \verb|buffer_id| is -1. -\\\\ -Switches that implement buffering are expected to expose, through documentation, both the amount of available buffering, and the length of time before buffers may be reused. A switch must gracefully handle the case where a buffered \verb|packet_in| message yields no response from the controller. A switch should prevent a buffer from being reused until it has been handled by the controller, or some amount of time (indicated in documentation) has passed. -\\\\ -The reason field can be any of these values: - -\input{enum/ofp_packet_in_reason} - -\subsubsection{Flow Removed Message} -If the controller has requested to be notified when flows time out, the datapath does this with the \verb|OFPT_FLOW_REMOVED| message: - -\input{struct/ofp_flow_removed} -The \verb|match|, \verb|cookie|, and \verb|priority| fields are the same as those used in the flow setup request. -\\\\ -The \verb|reason| field is one of the following: - -\input{enum/ofp_flow_removed_reason} -The \verb|duration_sec| and \verb|duration_nsec| fields are described in Section \ref{flow_duration_info}. -\\\\ -The \verb|idle_timeout| field is directly copied from the flow mod that created this entry. -\\\\ -With the above three fields, one can find both the amount of time the flow was active, as well as the amount of time the flow received traffic. -\\\\ -The \verb|packet_count| and \verb|byte_count| indicate the number of packets and bytes that were associated with this flow, respectively. - -\subsubsection{Port Status Message} -As physical ports are added, modified, and removed from the datapath, the controller needs to be informed with the \verb|OFPT_PORT_STATUS| message: - -\input{struct/ofp_port_status} -The \verb|status| can be one of the following values: - -\input{enum/ofp_port_reason} - -\subsubsection{Error Message} -There are times that the switch needs to notify the controller of a problem. This is done with the \verb|OFPT_ERROR_MSG| message: - -\input{struct/ofp_error_msg} -The \verb|type| value indicates the high-level type of error. The \verb|code| value is interpreted based on the type. The \verb|data| is variable length and interpreted based on the \verb|type| and \verb|code|; in most cases this is the message that caused the problem. -\\\\ -Error codes ending in \verb|_EPERM| correspond to a permissions error generated by an entity between a controller and switch, such as an OpenFlow hypervisor. -\\\\ -Currently defined error types are: - -\input{enum/ofp_error_type} -For the \verb|OFPET_HELLO_FAILED| error \verb|type|, the following \verb|code|s are currently defined: - -\input{enum/ofp_hello_failed_code} -The \verb|data| field contains an ASCII text string that adds detail on why the error occurred. -\\\\ -For the \verb|OFPET_BAD_REQUEST| error \verb|type|, the following \verb|code|s are currently defined: - -\input{enum/ofp_bad_request_code} -The \verb|data| field contains at least 64 bytes of the failed request. -\\\\ -For the \verb|OFPET_BAD_ACTION| error \verb|type|, the following \verb|code|s are currently defined: - -\input{enum/ofp_bad_action_code} -The \verb|data| field contains at least 64 bytes of the failed request. -\\\\ -For the \verb|OFPET_FLOW_MOD_FAILED| error \verb|type|, the following \verb|code|s are currently defined: - -\input{enum/ofp_flow_mod_failed_code} -The \verb|data| field contains at least 64 bytes of the failed request. -\\\\ -For the \verb|OFPET_PORT_MOD_FAILED| error \verb|type|, the following \verb|code|s are currently defined: - -\input{enum/ofp_port_mod_failed_code} -The \verb|data| field contains at least 64 bytes of the failed request. -\\\\ -For the \verb|OFPET_QUEUE_OP_FAILED| error \verb|type|, the following \verb|code|s are currently defined: - -\input{enum/ofp_queue_op_failed_code} -The \verb|data| field contains at least 64 bytes of the failed request. -\\\\ -If the error message is in response to a specific message from the controller, e.g., \verb|OFPET_BAD_REQUEST|, \verb|OFPET_BAD_ACTION|, or \verb|OFPET_FLOW_MOD_FAILED|, then the \verb|xid| field of the header should match that of the offending message. - -\subsection{Symmetric Messages} -\subsubsection{Hello} -The \verb|OFPT_HELLO| message has no body; that is, it consists only of an OpenFlow header. Implementations must be prepared to receive a hello message that includes a body, ignoring its contents, to allow for later extensions. - -\subsubsection{Echo Request} -An Echo Request message consists of an OpenFlow header plus an arbitrary-length data field. The data field might be a message timestamp to check latency, various lengths to measure bandwidth, or zero-size to verify liveness between the switch and controller. - -\subsubsection{Echo Reply} -An Echo Reply message consists of an OpenFlow header plus the unmodified data field of an echo request message. -\\\\ -In an OpenFlow protocol implementation divided into multiple layers, the echo request/reply logic should be implemented in the "deepest" practical layer. For example, in the OpenFlow reference implementation that includes a userspace process that relays to a kernel module, echo request/reply is implemented in the kernel module. Receiving a correctly formatted echo reply then shows a greater likelihood of correct end-to-end functionality than if the echo request/reply were implemented in the userspace process, as well as providing more accurate end-to-end latency timing. - -\subsubsection{Vendor} -The Vendor message is defined as follows: - -\input{struct/ofp_vendor_header} -The \verb|vendor| field is a 32-bit value that uniquely identifies the vendor. If the most significant byte is zero, the next three bytes are the vendor's IEEE OUI. If vendor does not have (or wish to use) their OUI, they should contact the OpenFlow consortium to obtain one. The rest of the body is uninterpreted. -\\\\ -If a switch does not understand a vendor extension, it must send an \verb|OFPT_ERROR| message with a \verb|OFPBRC_BAD_VENDOR| error code and \verb|OFPET_BAD_REQUEST| error type. - diff --git a/openflow/doc/of-spec/credits.tex b/openflow/doc/of-spec/credits.tex deleted file mode 100644 index eb917c70..00000000 --- a/openflow/doc/of-spec/credits.tex +++ /dev/null @@ -1,22 +0,0 @@ -\section{Appendix B: Credits} - -Current Maintainer: Brandon Heller (brandonh@stanford.edu). -\\\\ -Spec contributions, in alphabetical order: -\\\\ -Ben Pfaff, -Brandon Heller, -Dan Talayco, -David Erickson, -Glen Gibb, -Guido Appenzeller, -Jean Tourrilhes, -Justin Pettit, -KK Yap, -Martin Casado, -Masayoshi Kobayashi, -Nick McKeown, -Peter Balland, -Reid Price, -Rob Sherwood, -Yiannis Yiakoumis. \ No newline at end of file diff --git a/openflow/doc/of-spec/figure_flow_table_secchan.png b/openflow/doc/of-spec/figure_flow_table_secchan.png deleted file mode 100755 index a21dde001128e353fb0a172fd4b6551931467604..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 67886 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 3~M{>^b~jIm2Vp1dl%!TTqD_` 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 - - - - ActiveLayerIndex - 0 - ApplicationVersion - - com.omnigroup.OmniGrafflePro - 138.12.0.121252 - - AutoAdjust - - BackgroundGraphic - - Bounds - {{0, 0}, {1188, 733}} - Class - SolidGraphic - ID - 2 - Style - - shadow - - Draws - NO - - stroke - - Draws - NO - - - - CanvasOrigin - {0, 0} - ColumnAlign - 1 - ColumnSpacing - 36 - CreationDate - 2009-11-19 17:13:27 -0800 - Creator - brandonh - DisplayScale - 1 0/72 in = 1.0000 in - GraphDocumentVersion - 6 - GraphicsList - - - Class - LineGraphic - Head - - ID - 88 - Position - 0.57036429643630981 - - ID - 102 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {584.932, 656.613} - {584.977, 688.774} - - Style - - stroke - - HeadArrow - 0 - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 42 - Info - 2 - - - - Class - LineGraphic - Head - - ID - 88 - Position - 0.84439820051193237 - - ID - 101 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {458.932, 674.613} - {458.658, 688.774} - - Style - - stroke - - HeadArrow - 0 - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 41 - Info - 1 - - - - Class - LineGraphic - Head - - ID - 67 - Position - 0.93292379379272461 - - ID - 100 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {242.932, 336.714} - {255.646, 688.774} - - Style - - stroke - - HeadArrow - FilledArrow - HopLines - - HopType - 1 - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 93 - Info - 3 - - - - Class - LineGraphic - Head - - ID - 93 - Info - 4 - - ID - 94 - Points - - {125.932, 336.714} - {143.932, 336.714} - - Style - - stroke - - HeadArrow - FilledArrow - TailArrow - 0 - - - Tail - - ID - 92 - - - - Bounds - {{143.932, 300.714}, {99, 72}} - Class - ShapedGraphic - ID - 93 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Rectangle - Style - - stroke - - Pattern - 1 - - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 Set IP source, destination from within ARP packet} - - VFlip - YES - - - Bounds - {{17.9318, 282.714}, {108, 108}} - Class - ShapedGraphic - ID - 92 - Line - - ID - 19 - Position - 0.51827484369277954 - RotationType - 0 - - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Diamond - Style - - stroke - - Pattern - 1 - - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 Eth type = 0x0806?} - VerticalPad - 0 - - - - Class - LineGraphic - Head - - ID - 53 - Info - 3 - - ID - 88 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {629.932, 494.613} - {386.932, 688.774} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 37 - Info - 3 - - - - Bounds - {{447.932, 175.932}, {72, 14}} - Class - ShapedGraphic - FitText - Vertical - Flow - Resize - ID - 83 - Shape - Rectangle - Style - - fill - - Draws - NO - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Pad - 0 - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 no} - VerticalPad - 0 - - - - Bounds - {{509.932, 85.932}, {72, 14}} - Class - ShapedGraphic - FitText - Vertical - Flow - Resize - ID - 82 - Shape - Rectangle - Style - - fill - - Draws - NO - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Pad - 0 - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 yes} - VerticalPad - 0 - - - - Class - LineGraphic - ID - 81 - Points - - {515.932, 108.932} - {566.932, 108.932} - - Style - - stroke - - HeadArrow - FilledArrow - TailArrow - 0 - - - Tail - - ID - 73 - Info - 3 - - - - Class - LineGraphic - ID - 80 - Points - - {461.932, 162.932} - {461.932, 216.932} - - Style - - stroke - - HeadArrow - FilledArrow - TailArrow - 0 - - - Tail - - ID - 73 - - - - Bounds - {{407.932, 54.932}, {108, 108}} - Class - ShapedGraphic - ID - 73 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Diamond - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 decision} - VerticalPad - 0 - - - - Class - LineGraphic - Head - - ID - 19 - Position - 0.11005332320928574 - - ID - 71 - OrthogonalBarAutomatic - - OrthogonalBarPosition - 0.0 - Points - - {197.932, 206.932} - {71.9318, 248.668} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 1 - Info - 2 - - - - Class - LineGraphic - Head - - ID - 53 - - ID - 67 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {71.9318, 548.613} - {278.932, 688.774} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 18 - Info - 1 - - - - Class - LineGraphic - Head - - ID - 53 - - ID - 63 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {332.932, 549.113} - {332.932, 661.774} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 47 - - - - Bounds - {{278.932, 661.774}, {108, 54}} - Class - ShapedGraphic - ID - 53 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Rectangle - Style - - stroke - - Width - 3 - - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\b\fs24 \cf0 Packet Lookup -\b0 Use assigned header fields} - - VFlip - YES - - - Class - LineGraphic - Head - - ID - 39 - - ID - 50 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {386.932, 494.613} - {404.932, 494.613} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 47 - - - - Class - LineGraphic - Head - - ID - 47 - - ID - 49 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {242.932, 494.613} - {278.932, 494.613} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 35 - - - - Class - LineGraphic - Head - - ID - 35 - - ID - 48 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {125.932, 494.613} - {143.932, 494.613} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 18 - - - - Class - LineGraphic - Head - - ID - 41 - - ID - 45 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {458.932, 548.613} - {458.932, 566.613} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 39 - - - - Class - LineGraphic - Head - - ID - 42 - - ID - 44 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {512.932, 620.613} - {539.932, 620.613} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 41 - - - - Class - LineGraphic - Head - - ID - 37 - - ID - 43 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {512.932, 494.613} - {539.932, 494.613} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 39 - - - - Bounds - {{539.932, 584.613}, {90, 72}} - Class - ShapedGraphic - ID - 42 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 Use ICMP type and code for L4 fields} - - VFlip - YES - - - Bounds - {{404.932, 566.613}, {108, 108}} - Class - ShapedGraphic - ID - 41 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Diamond - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 IP Proto = \ -1?} - VerticalPad - 0 - - - - Bounds - {{404.932, 440.613}, {108, 108}} - Class - ShapedGraphic - ID - 39 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Diamond - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 IP Proto = \ -6 or 7?} - VerticalPad - 0 - - - - Bounds - {{539.932, 458.613}, {90, 72}} - Class - ShapedGraphic - ID - 37 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 Use UDP/TCP source and destination for L4 fields} - - VFlip - YES - - - Bounds - {{143.932, 458.613}, {99, 72}} - Class - ShapedGraphic - ID - 35 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 Set IP source, destination, protocol, and ToS fields} - - VFlip - YES - - - Bounds - {{278.932, 440.613}, {108, 108}} - Class - ShapedGraphic - ID - 47 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Diamond - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 Not IP Fragment?} - VerticalPad - 0 - - - - Class - LineGraphic - Head - - ID - 18 - - ID - 19 - Points - - {71.9318, 224.932} - {71.9318, 440.613} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 6 - - - - Bounds - {{17.9318, 440.613}, {108, 108}} - Class - ShapedGraphic - ID - 18 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Diamond - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 Eth type = 0x0800?} - VerticalPad - 0 - - - - Class - LineGraphic - Head - - ID - 1 - - ID - 17 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {125.932, 170.932} - {143.932, 170.932} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 6 - - - - Class - LineGraphic - Head - - ID - 6 - - ID - 16 - Points - - {71.9318, 98.932} - {71.9318, 116.932} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 7 - - - - Bounds - {{8.93179, 8.93201}, {126, 90}} - Class - ShapedGraphic - ID - 7 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Rectangle - Style - - stroke - - Width - 3 - - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\b\fs24 \cf0 Initialize Headers -\b0 \ -Set input port, Ethernet source, destination, and type;\ -set all others to zero} - - - - Bounds - {{17.9318, 116.932}, {108, 108}} - Class - ShapedGraphic - ID - 6 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Diamond - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 Eth type = 0x8100?} - VerticalPad - 0 - - - - Bounds - {{143.932, 134.932}, {108, 72}} - Class - ShapedGraphic - ID - 1 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 Set VLAN ID and PCP. Use encapsulated Eth type for next Eth type check} - - VFlip - YES - - - GridInfo - - ShowsGrid - YES - - GuidesLocked - NO - GuidesVisible - YES - HPages - 1 - ImageCounter - 1 - KeepToScale - - Layers - - - Lock - NO - Name - Layer 1 - Print - YES - View - YES - - - LayoutInfo - - Animate - NO - circoMinDist - 18 - circoSeparation - 0.0 - layoutEngine - dot - neatoSeparation - 0.0 - twopiSeparation - 0.0 - - LinksVisible - YES - MagnetsVisible - NO - MasterSheets - - ModificationDate - 2009-12-16 14:42:02 -0800 - Modifier - brandonh - NotesVisible - NO - Orientation - 2 - OriginVisible - NO - PageBreaks - YES - PrintInfo - - NSBottomMargin - - float - 41 - - NSLeftMargin - - float - 18 - - NSOrientation - - int - 1 - - NSPaperName - - string - eleven_by_seventeen - - NSPaperSize - - size - {1224, 792} - - NSRightMargin - - float - 18 - - NSTopMargin - - float - 18 - - - PrintOnePage - - QuickLookPreview - - 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 - +qSeZg3KM+lp1mCFsp41mJI+c9ZghTrVdC/PGpibp8N9ueoqKWc6QE6f6rBoVuOjNNNT - /vXueHv3cCbpuRl5DNZ3+AhGgfKn35VfBGYCz6muyPvRkuJJHnEBFXnhMfcxFs850/lh - 2YXM3YVqdLFrWHLv0iVjg4DDlI5YMwzsDxWsYZjqkvFqnfUUS7HMj32b5tc04tt4+BPP - 3REWfVtpNV3TtcxXunKsCuxQunIMg3ocurWYtg6ofcXrCsz3qf6mYgolMeExrBIIPvI1 - VumyTiBXmT7aJVyjCx7l8VQKY5e0H4HjsxxckjsaiUKLF30fKcldi7tKsigYCru0k0qt - Xg26sgJFY5KNdJT4KdmEH8Ogt8xPr37hVCrJa/kVF5aTYSjsUtefYKHtHWhL6apgUqYT - v5J/l2ezgB5+pIn0kudmQpDXhQjrMJum+DAMvEc+6RJ9+3/P6L6+CmVuZHN0cmVhbQpl - bmRvYmoKNiAwIG9iagozNzM1CmVuZG9iagozIDAgb2JqCjw8IC9UeXBlIC9QYWdlIC9Q - YXJlbnQgNCAwIFIgL1Jlc291cmNlcyA3IDAgUiAvQ29udGVudHMgNSAwIFIgL01lZGlh - Qm94IFswIDAgMTE4OCA3MzNdCj4+CmVuZG9iago3IDAgb2JqCjw8IC9Qcm9jU2V0IFsg - L1BERiAvVGV4dCAvSW1hZ2VCIC9JbWFnZUMgL0ltYWdlSSBdIC9Db2xvclNwYWNlIDw8 - IC9DczEgOCAwIFIKL0NzMiAzNyAwIFIgPj4gL0ZvbnQgPDwgL0YxLjAgMzggMCBSIC9G - Mi4wIDM5IDAgUiA+PiAvWE9iamVjdCA8PCAvSW0xMiAzMSAwIFIKL0ltNiAxOSAwIFIg - L0ltMyAxMyAwIFIgL0ltMSA5IDAgUiAvSW00IDE1IDAgUiAvSW0xMCAyNyAwIFIgL0lt - OSAyNSAwIFIgL0ltMTEKMjkgMCBSIC9JbTE0IDM1IDAgUiAvSW0yIDExIDAgUiAvSW01 - IDE3IDAgUiAvSW0xMyAzMyAwIFIgL0ltNyAyMSAwIFIgL0ltOAoyMyAwIFIgPj4gPj4K - ZW5kb2JqCjMxIDAgb2JqCjw8IC9MZW5ndGggMzIgMCBSIC9UeXBlIC9YT2JqZWN0IC9T - dWJ0eXBlIC9JbWFnZSAvV2lkdGggMjYwIC9IZWlnaHQgMjYwIC9Db2xvclNwYWNlCjQw - IDAgUiAvU01hc2sgNDEgMCBSIC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxh - dGVEZWNvZGUgPj4Kc3RyZWFtCngB7dAxAQAAAMKg9U/taQmIQGHAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDgAwMYXQABCmVuZHN0cmVhbQplbmRvYmoKMzIgMCBvYmoKOTA4CmVuZG9iagoxOSAw - IG9iago8PCAvTGVuZ3RoIDIwIDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1h - Z2UgL1dpZHRoIDI0MiAvSGVpZ2h0IDE4OCAvQ29sb3JTcGFjZQo0MyAwIFIgL1NNYXNr - IDQ0IDAgUiAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+ - CnN0cmVhbQp4Ae3QAQ0AAADCoPdP7ewBESgMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwY+MBVGAAEKZW5kc3RyZWFtCmVuZG9iagoyMCAwIG9iago2MTgKZW5kb2Jq - CjEzIDAgb2JqCjw8IC9MZW5ndGggMTQgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBl - IC9JbWFnZSAvV2lkdGggMzAwIC9IZWlnaHQgMjI4IC9Db2xvclNwYWNlCjQ2IDAgUiAv - U01hc2sgNDcgMCBSIC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNv - ZGUgPj4Kc3RyZWFtCngB7dAxAQAAAMKg9U9tCj+IQGHAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAwGtgIb0AAQplbmRzdHJlYW0KZW5kb2JqCjE0IDAgb2JqCjkxOAplbmRvYmoK - OSAwIG9iago8PCAvTGVuZ3RoIDEwIDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAv - SW1hZ2UgL1dpZHRoIDI2MCAvSGVpZ2h0IDE4OCAvQ29sb3JTcGFjZQo0OSAwIFIgL1NN - YXNrIDUwIDAgUiAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2Rl - ID4+CnN0cmVhbQp4Ae3QMQEAAADCoPVPbQo/iEBhwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGPgODDzuAAEKZW5kc3RyZWFtCmVuZG9iagoxMCAwIG9iago2NjMKZW5kb2JqCjE1 - IDAgb2JqCjw8IC9MZW5ndGggMTYgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9J - bWFnZSAvV2lkdGggMjYwIC9IZWlnaHQgMjYwIC9Db2xvclNwYWNlCjQwIDAgUiAvU01h - c2sgNTIgMCBSIC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUg - Pj4Kc3RyZWFtCngB7dAxAQAAAMKg9U/taQmIQGHAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDgAwMYXQAB - CmVuZHN0cmVhbQplbmRvYmoKMTYgMCBvYmoKOTA4CmVuZG9iagoyNyAwIG9iago8PCAv - TGVuZ3RoIDI4IDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRo - IDIyNCAvSGVpZ2h0IDE4OCAvQ29sb3JTcGFjZQo1NCAwIFIgL1NNYXNrIDU1IDAgUiAv - Qml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4 - Ae3QAQ0AAADCoPdPbQ43iEBhwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDDwNDDtjwABCmVuZHN0cmVhbQplbmRvYmoKMjggMCBvYmoKNTc0CmVuZG9iagoy - NSAwIG9iago8PCAvTGVuZ3RoIDI2IDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAv - SW1hZ2UgL1dpZHRoIDI2MCAvSGVpZ2h0IDI2MCAvQ29sb3JTcGFjZQo0MCAwIFIgL1NN - YXNrIDU3IDAgUiAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2Rl - ID4+CnN0cmVhbQp4Ae3QMQEAAADCoPVP7WkJiEBhwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg4AMDGF0A - AQplbmRzdHJlYW0KZW5kb2JqCjI2IDAgb2JqCjkwOAplbmRvYmoKMjkgMCBvYmoKPDwg - L0xlbmd0aCAzMCAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUgL0ltYWdlIC9XaWR0 - aCAyNjQgL0hlaWdodCAxNTYgL0NvbG9yU3BhY2UKNTkgMCBSIC9TTWFzayA2MCAwIFIg - L0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0K - eAHt0AENAAAAwqD3T20PBxEoDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMDA/8AA4q8A - AQplbmRzdHJlYW0KZW5kb2JqCjMwIDAgb2JqCjU2MgplbmRvYmoKMzUgMCBvYmoKPDwg - L0xlbmd0aCAzNiAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUgL0ltYWdlIC9XaWR0 - aCAyNDIgL0hlaWdodCAxODggL0NvbG9yU3BhY2UKNjIgMCBSIC9TTWFzayA2MyAwIFIg - L0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0K - eAHt0AENAAAAwqD3T+3sAREoDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - PjAVRgABCmVuZHN0cmVhbQplbmRvYmoKMzYgMCBvYmoKNjE4CmVuZG9iagoxMSAwIG9i - ago8PCAvTGVuZ3RoIDEyIDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2Ug - L1dpZHRoIDI2MCAvSGVpZ2h0IDI2MCAvQ29sb3JTcGFjZQo0MCAwIFIgL1NNYXNrIDY1 - IDAgUiAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0 - cmVhbQp4Ae3QMQEAAADCoPVP7WkJiEBhwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg4AMDGF0AAQplbmRz - dHJlYW0KZW5kb2JqCjEyIDAgb2JqCjkwOAplbmRvYmoKMTcgMCBvYmoKPDwgL0xlbmd0 - aCAxOCAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUgL0ltYWdlIC9XaWR0aCAyNjAg - L0hlaWdodCAyNjAgL0NvbG9yU3BhY2UKNDAgMCBSIC9TTWFzayA2NyAwIFIgL0JpdHNQ - ZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAHt0DEB - AAAAwqD1T+1pCYhAYcCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYOADAxhdAAEKZW5kc3RyZWFtCmVuZG9i - agoxOCAwIG9iago5MDgKZW5kb2JqCjMzIDAgb2JqCjw8IC9MZW5ndGggMzQgMCBSIC9U - eXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMjYwIC9IZWlnaHQgMjYw - IC9Db2xvclNwYWNlCjY5IDAgUiAvU01hc2sgNzAgMCBSIC9CaXRzUGVyQ29tcG9uZW50 - IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7dAxAQAAAMKg9U/taQmI - QGHAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDgAwMYXQABCmVuZHN0cmVhbQplbmRvYmoKMzQgMCBvYmoK - OTA4CmVuZG9iagoyMSAwIG9iago8PCAvTGVuZ3RoIDIyIDAgUiAvVHlwZSAvWE9iamVj - dCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRoIDIyNCAvSGVpZ2h0IDE4OCAvQ29sb3JTcGFj - ZQo1NCAwIFIgL1NNYXNrIDcyIDAgUiAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIg - L0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae3QAQ0AAADCoPdPbQ43iEBhwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDDwNDDtjwABCmVuZHN0cmVhbQplbmRv - YmoKMjIgMCBvYmoKNTc0CmVuZG9iagoyMyAwIG9iago8PCAvTGVuZ3RoIDI0IDAgUiAv - VHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRoIDI2MCAvSGVpZ2h0IDI2 - MCAvQ29sb3JTcGFjZQo0MCAwIFIgL1NNYXNrIDc0IDAgUiAvQml0c1BlckNvbXBvbmVu - dCA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae3QMQEAAADCoPVP7WkJ - iEBhwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBg4AMDGF0AAQplbmRzdHJlYW0KZW5kb2JqCjI0IDAgb2Jq - CjkwOAplbmRvYmoKNDQgMCBvYmoKPDwgL0xlbmd0aCA0NSAwIFIgL1R5cGUgL1hPYmpl - Y3QgL1N1YnR5cGUgL0ltYWdlIC9XaWR0aCAyNDIgL0hlaWdodCAxODggL0NvbG9yU3Bh - Y2UKL0RldmljZUdyYXkgL0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURl - Y29kZSA+PgpzdHJlYW0KeAHtne9vEtkax21LocAAQ0sHyo8LDlAYkLIjKG2pCw0ExVKt - VVxcW1KdapZKRY1EsrUupiqR+KN1bbRGa9dYjbqNNY0as5r7r93nUHP3SnHd+46zPd8X - RpKanM98n/M5U3xxtmwhIU+APAHyBMgTwPcJNGCd/+u5A2njn2nCLH+uvBFA/gb4Oi1Q - ikTNGEckAgQE/y3oCu86rFgiaVmPFKN8XrJEIoa6APsbzJ95m5vFACuVyeRyOUVRCqwC - C4Zly2TSlhZE/dfMCLgJZhlwAZZSKJUqmlZjF5pWKZUK4JYB9DrzV0a7Agz9Il6FUqVW - t7ZpNO3tDKPFKAzT3q7RtLWq1SqlAjFDzzDatZFRw6hgxEsDLaPVdej1BqPRhFGMRoNe - 36HTMkBNV5ihZoRcQ9oVYNjAcgp4ARdYTWaLZStrxSrsVovFbAJugAZmSo62c23kBrSH - JVIoWN3G6PRAy1rtnQ4nx7lcbkzicnGc09Fpt7JArdcxbWqoWSpB/tpYMlQMwC1yhUqt - 0epNFtbWybm2ebxenue3YxNYrNfr2ebiOm2sxaTXatQqBbTcLKox11AxSEtWATaYWbvT - 7fHyvh07Az29kCAWQSvtCezc4eO9HrfTzpoNFWQZ6KtGyQ1QcYuMUqo1OoPZ6nB38f5A - T3BXKNwfiUSimASW2h8O7Qr2BPx8l9thNRt0GrWSkrVAydVjvV6xHIC1BouN8/D+7mCo - PxrbEx9IDO7DJoOJgfieWLQ/FOz28x7OZkEtK+W1SkbEMNM0AJttnNcX6AtHdu8d3D98 - MHk4hVEOJw8O7x/cuzsS7gv4vJwNDTatgJI3jDUMtbhFrmxl9GYr1+XvDUXjiQOHUkdH - 02PHBWEckwjC8bH06NHUoQOJeDTU6+/irGY904pK3jDWDY1wMkHFOhPr8Ph6w7GBoeSR - 0THhZOZUdvJ0DpOcnsyeypwUxkaPJIcGYuFen8fBmnRQMpxQ1RsZDTXsYkZvsbv5QCiW - GE6NHDuRyebOnc9fKGCTC/nz53LZzIljI6nhRCwU4N12i55BOxnG+svXrgqxqk1rYp1d - /r4oAKeFzOTZfGFq+lLxMjYpXpqeKuTPTmaENCBH+/xdTtakbVPVJBZLKVrTYba5+e5w - fCiVHp/I5QvTxZmrpetlbHK9dHWmOF3I5ybG06mheLibd9vMHRqakoo3dCwSSxVoqDs9 - /mBkMDkiTJzJTxWvlMo3b8/ewSazt2+WS1eKU/kzE8JIcjAS9Hs60VgrpKCuqqkWSWTK - Vq2RdXoD3+8+cOTYT7n81OVr5Vtzd+fv31/AJPfvz9+du1W+dnkqn/vp2JEDu78PeJ2s - UduqlElqEMuVsI2tLr6nf++h0RNZAC7dmL1778HDxcdLmOTx4sMH9+7O3igBcvbE6KG9 - /T28ywobWSmvQQyq1nT8y77NB0OdGsucLfxy7cbc/MKjpSdPl59hkuWnT5YeLczP3bj2 - S+FsZiwFY+3bZv9XhwZkvaFjOJxUGrSNd+yK7f9RyOYvzpRn5x8s/rb8/MXLV5jk5Yvn - y78tPpifLc9czGeFH/fHdu1AG1mDZF29j4GYBmKHNxDaMzx6Mlcolm7dXVh88uzlq5XX - q5jk9cqrl8+eLC7cvVUqFnInR4f3hAJeBxDTNYkpul2/FcQVjh9MZ879PFOeu/cIgFdW - 36xhkzerK4D86N5ceebnc5n0wXgY1LVV305TtTqm1O0Glvuup38gOTZx/uLVm78+WFp+ - sbK69vbde0zy7u3a6sqL5aUHv968evH8xFhyoL/nO441tKu/QswYWY7vjSQOH8/mL5Vu - zT988vz312tv33/AJu/frr3+/fmTh/O3Spfy2eOHE5FenmONzNeJ4XAC4h+EyQvF67fv - LT59sfIGgP/4iEn++PD+7ZuVF08X792+XrwwKfyAiF3WbxIPpoTThcvlufuPl1++XnsH - wJ8wycc/Prxbe/1y+fH9ufLlwmkBjqevEcMviy2UmjFWOq5B/G8s8umvib/43qehqRle - q+GVy709GN2XGs9Bx3cWlp69Wl17/+HjJyx4YZGfPn54v7b66tnSwh3oODee2hcNbnfD - Sxe8WDc3EWLSMZlqHPYy2cfEXP/zLQg5nch5jIO2yBsIeecib5nkNwnyuxMWtiZvmeQt - k7xlkm99yPdc9a9r4mriauJq4mriauLq+nsC5HQipxM5ncjpRE6n+nNz9YqIq4mriauJ - q4mrq81Yf5+Jq4mriauJq4mr68/N1SsiriauJq4mriaurjZj/X0mriauJq4mriaurj83 - V6+IuJq4mriauJq4utqM9feZuJq4mriauJq4uv7cXL0i4mriauJq4mri6moz1t9n4mri - auJq4mri6vpzc/WKiKuJq4mriauJq6vNWH+fiauJq4mriauJq+vPzdUrIq4mriauJq4m - rq42Y/19Jq4mriauJq4mrq4/N1eviLiauJq4mrj6n+3qTXej1ZZvEP/zbi37gnhT3Uy3 - 2W4f3HQ3TG66W0Q3302xm+02YNGmu/FZJNl0t3pvvpvbxXDFJIOu9fbDRebJEWHiTH6q - eKVUvnl79g42mb19s1y6UpzKn5kQRpJwjbkfXerNwCWi4g33mDeJpRSt6TDb3Hx3OD6U - So9P5PKF6eLM1dL1Mja5Xro6U5wu5HMT4+nUUDzczbtt5g4NTUnFTdX3mDehq9vbtCbW - 2eXviyaGU2khM3k2X5iavlS8jE2Kl6anCvmzkxkhnRpORPv8XU7WpG1DF7fXJFaisba7 - +UAoBsgjx05ksrlz5/MXCtjkQv78uVw2c+LYCADHQgHebUdDraxBDBcgS6QKWqMzsQ6P - rzccGxhKHhkdE05mTmUnT+cwyenJ7KnMSWFs9EhyaCAW7vV5HKxJp6EVUklz4xeXAW/Z - 0tAoEsOJ3MrozVauy98bisYTBw6ljo6mx44LwjgmEYTjY+nRo6lDBxLxaKjX38VZzXqm - FSoGcW0gho0sg5K1BrON8/oCfeHI7r2D+4cPJg+nMMrh5MHh/YN7d0fCfQGfl7OZDVqo - WIa2cQ1iVLIakC02zsP7u4Oh/mhsT3wgMbgPmwwmBuJ7YtH+ULDbz3s4mwWA0S4WbyRG - Yw0lU4CsM5itDncX7w/0BHeFwv2RSCSKSWCp/eHQrmBPwM93uR1Ws0EHwBRUvGGo0UZu - ahbDXKtQy2bW7nR7vLxvx85ATy8kiEXQSnsCO3f4eK/H7bSzaKTVKpjpWhUDMZQsaZFX - kPUmC2vr5FzbPF4vz/PbsQks1uv1bHNxnTbWYtJXgOUtEqi4ehvDl/VQMiBL5Qqluo3R - 6U1mC2u1dzqcHOdyuTGJy8VxTken3cpazCa9jmlTKxVyOJlEG7yF/ncCSoa5hpYpJd2q - YbR6gxGoLVtZK1Zht1qA1mjQaxlNK62koGE00zUq/owMgy2DmunWNoDWdeiB22jCKEZg - 1XfoALcNeBVyGYz014C3NFRaBn1VmFVqNVBr2tsZRotRGKa9XQO0arWqwgvSqgBXHcaf - /8utgixqhpqBWU4plEoVTauxC02rlEoFJYd+UcGwhxsbagPDXEPLyF9oO7dIZYAtpyhK - gVVgwbBsmUwKuNAv4v06MNLXOjNAAzVgVyLFKJ+XLEG0zaJv8laUjZgbm5qaRAgb2wBs - E6r3L/v9vJtR0RVq9PMQ+JdYZX3VlT8B5L9Qf+cv8PMY5+8Qkp8hT4A8AfIEyBOo1yfw - HxfQr7EKZW5kc3RyZWFtCmVuZG9iago0NSAwIG9iagoyNzk1CmVuZG9iago2NyAwIG9i - ago8PCAvTGVuZ3RoIDY4IDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2Ug - L1dpZHRoIDI2MCAvSGVpZ2h0IDI2MCAvQ29sb3JTcGFjZQovRGV2aWNlR3JheSAvQml0 - c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae3d - /1NSWRQA8L4o8k1ERVSSlaJscSC0MFOyNBq/t1oOI30znDKjRi0dWkfLKdQpsfJL5bjm - aE7soJlp6qhtu7P/2p77sEwXFBXeu/fC+SUNSvh47rnvPeCcPXvCERYIC4QFwgJhgbBA - WCAsgJHAXhT7IJgvMHpgLD2U1WcPAPv3IwYI+CuWfjgWP8bz69+/PyIiIhIC/vBIhJAC - WgAAAM+ex4uC4PEQBMMQIqmAkgAB8KL4fL5AIBQKBPBFFDhEwLIIiVRgCBgBgVAkEkdD - iEUioYBRCA0EIIAk4PH5QpFYIomRxkJIYyQSsUjI5/NQKlCfCR6CKBCIlkhj42SyBAiZ - LC5WKokGhagQQFglEEAOSONkCYlJCiaSEhNkcVLIBQH9CB4CvkCEBORJihRlqgoiVZmi - SJIjBZGAT3kmrBIIRZLYeHnSAaXqkPpIGsQR9SGV8kCSPD5WAuuBaoTvBGJJrCxRoVSp - 0zTpWt2xYzptuiZNrVIqEmWxEjHVCD8IYuISklOQgFafecKQlWU4kanXIoWU5IS4GJoR - fiKQK5QH0zS6TEN2rjEPwpibbcjUadIOKhVymhHWCOLlil/UR7UZhlPGs+fOF0KcP3fW - eMqQoT2q/kUhj6c2E34iSFSkqjW649nGfFNRaXkFRHlpkSnfmH1cp1GnKhJpRVhPcFij - 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 - a7jf3NLSfL/BVme9aq4oMZ0m8qrRVlmAbt+YCfosY0HxhSrL9dpb9ba7d231t2qvW6ou - FBcYs/QEXjjzh+B/CDAnNTe/sKzSbLlWY62ttdZcs5grywrzc2HeKHnXDv0j2ICQehgQ - cs6Yissrq8wWCHNVZXmx6UwOIkgl7fKpvwQbEdQa3fFsY76pqLS8AqK8tMiUb8w+rtOo - KSZYhyCHyclHtRmGU8az584XQpw/d9Z4ypChPQrTh+VkXUT3PwvQPdcKI0zQVh5M0+gy - Ddm5xjwIY262IVOnSTuoZEZxE/Q6wvYI1iEkJKeo1GkarT7zhCEry3AiU6/VpKlVKckJ - ayPZcX1xfbtPe/39f2QCTNFOVCiRQrpWd+yYTpuOBJSKRJhATdKrSeufnn/ffUeAUeLx - 8qQDStUh9ZE0iCPqQyrlgSR5PMxepngheJBWEQQiiTROJk9SpChTVRCpyhRFklwWJ4WJ - 9Hi/y8S/3/Xm9/IgRAlEYqSQkJikYCIpMQEJiEVoDDnGb7TZ/Mn5e+sqAl8oipZIY+Nk - sgQImSwuViqJhnUQCgTfdwceHxTEEkmMNBZCGiOBHBDy+bwQyAKULZAJMCUxkhfFFwhF - InE0hFgkEgr4UbxIGMOO7zvO/E11f+7HIEQwCny+QCAUCgR8PiMApSA0CFAq7INUgLEv - 4MCLguBBBsAqAAFvw3b9cSXwPigVGIYIBBEZEeEBCJkk8PzK9noYGAnkAQF/ReCvc5cP - GZ60R4L5Ypf/WfifhwXCAmGBsEBYICwQFggLBFbgP0gqPFwKZW5kc3RyZWFtCmVuZG9i - ago2OCAwIG9iagozNzExCmVuZG9iago3MCAwIG9iago8PCAvTGVuZ3RoIDcxIDAgUiAv - VHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRoIDI2MCAvSGVpZ2h0IDI2 - MCAvQ29sb3JTcGFjZQovRGV2aWNlR3JheSAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0 - ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae2d+VsUx9bHXdiRYdVhVRBFQRRQzCiK - gEQQQVAgcQEjChoRXFAxEL0oj4orwYvixUB4JRdRiaAoatTXJ//aPVXd1V09U70NPTM9 - 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 - 2tbeeaXrWlfXlY72ttafj9XV8vECcSwwdQSZ9YnLPXPsDgUlFdUHf2psPtN2sf3y5faL - 5880Nx09VFPB5Rf4IAJ72YzqNu/4fs++H+samk61nDl7trXlVFND/YH95buEM0fJKYvy - taDlgJv2OZ4dhH2RUMHbll9cVllzsL7heNOJE43Hj9YfrKkqK863wYmjpKKNh9KwXceQ - QOCizQjC9qKS8qqaA4fq6uvrDv1YU1VeUrSdRuDFPoIcRgmElLR12bl5O4pLyyv3V9fU - VO+r3FNaXJC3OXtdWkqih3alyL1xI5/bQcjI2mTbVlBcsrtsz56y0l07C7bZNmVlrIaj - d2MiIYLsg1aAYNIQEpNXrc3MzrXl5RcW7dxZWJCfZ8vNzly7CiPwDYHMth+AQBSjNWHF - yrT09dmbNtu25m3dYtu8MXt9elrqigSwAl9GIBFL1vik5NS09MwNWTlwZW3IBALJSfHW - aO4gbp8QyAqWgKbIiKilsYjC6jXp6RkZ6WvTVgOBhNilUT6PQBRLYeGRMcuAworklalw - rUxekRQftywmMty7FtTYn7TaUzwmBMBxJ5aIqJhl1viExCS4EuPjrMtioiIscBi7z0kj - RyQ8hODQMEtEZDRgsMbGWgFAdGSEJSw0eC4gIN0hMCgEKIRHRkZFwxUVGRFuWRIaArIA - DhHzIR/B0Qa4J8gSUKQVKAAGS3h4uMUStiQUbACMAM4gnwMIOEvw8/cPCAwKBgz4CgEA - gQH+cITYIsXjYuS4et9zsARkChhDEL4CMQBsBEon5nhfU+Xf8UJMAWPwDwiAzx8sAAGY - G/2A57IQU1i0ePFiP3TBVwxgjvQDwTh4DKjt+ILvhZ/NpRtoN7nmUrPn2zpPYJ7APIF5 - AvME5gnME/AKAv8Df6F/1QplbmRzdHJlYW0KZW5kb2JqCjcxIDAgb2JqCjY4MjQKZW5k - b2JqCjc0IDAgb2JqCjw8IC9MZW5ndGggNzUgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0 - eXBlIC9JbWFnZSAvV2lkdGggMjYwIC9IZWlnaHQgMjYwIC9Db2xvclNwYWNlCi9EZXZp - Y2VHcmF5IC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4K - 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 - EKnKFEWSXBYnhYn0eL/LxL/f9eb38iBECURipJCQmKRgIikxAQmIRWgMOcZvtNn8yfl7 - 6yoCXyiKlkhj42SyBAiZLC5WKomGdRAKBN93Bx4fFMQSSYw0FkIaI4EcEPL5vBDIApQt - kAkwJTGSF8UXCEUicTSEWCQSCvhRvEgYw47vO878TXV/7scgRDAKfL5AIBQKBHw+IwCl - IDQIUCrsg1SAsS/gwIuC4EEGwCoAAW/Ddv1xJfA+KBUYhggEERkR4QEImSTw/Mr2ehgY - CeQBAX9F4K9zlw8ZnrRHgvlil/9Z+J+HBcICYYGwQFggLBAWCAsEVuA/SCo8XAplbmRz - dHJlYW0KZW5kb2JqCjc1IDAgb2JqCjM3MTEKZW5kb2JqCjYwIDAgb2JqCjw8IC9MZW5n - dGggNjEgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMjY0 - IC9IZWlnaHQgMTU2IC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5IC9CaXRzUGVyQ29tcG9u - ZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7Z3bT1NZFIeFll7o - nZ6209PT0gv0RhEKhHKJRayiYBWJaBslpKaMqabKjAOBMAwMGsTUYUAJQQjDxSAGCAFD - kBAx/muzdlvHIwW8zLwcZv0eCC9Nuj6+tfY5POx14gQGCSABJIAEkMC/IpB17PKNOKD+ - 7E/hHYN8qiYbivsaHGkGPB6fz885ZoGSeDyC5IssUiLwCAGBQCgUpSLmeNJlCIUCARTG - T6M4wgrSDgSCgBAQ50ogUqlUxvlAEaSWXDGUJQQWSRSHtgeRIU0BGEhlcrlCoVQdkygV - CrlcJiUsPpI4bFCkMIALAEEuV6ry1BRFabRaHeej1WqgFHWeSimXAwpCgihxsBFpDCIx - UFCq1JRGp9PTtMHAMEaOh2EMBprW63QaSg0opBKx6HAQKQxEBrlCBRD0NGM0mc0Wq9XG - +VitFrPZZGSAhYZSKeREicOMyCKzATCADGqNjmZMZqut0O5wulxut7uIw4Gv73I5HfZC - m9VsYmidRg1KpEEc0BkwI3MEBIOK0tJMvqXA7nR7ik+WlHq9ZRyP11tacrLY43baCyz5 - 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 - uVyhUKqOSZQKhVwuAwhiQiFlw2crxNLHxcfWIEoQEiLCAiKVSmWcDxRBagEGon8oHNIU - KRxEiWR3AAuBkNAgEXM8qSpEQqEATEiqAKPhUBk+kkih4PH5IMbxCpTEg+lIIHyBwmcs - yCcgvGOQVCXJn1/JIEUi+RM+cczCKg5/RQJIAAkgASTwPQT+Bp5VVMAKZW5kc3RyZWFt - CmVuZG9iago2MSAwIG9iagoyMjk5CmVuZG9iago1MCAwIG9iago8PCAvTGVuZ3RoIDUx - IDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRoIDI2MCAvSGVp - Z2h0IDE4OCAvQ29sb3JTcGFjZQovRGV2aWNlR3JheSAvQml0c1BlckNvbXBvbmVudCA4 - IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae2d+1NS+RvHvaDI7QCKgFyC - DqBcRPYEhooGDAzmLS9pi6WOhjZhGNnExKxZOJZMjJm2Ol6mzJys0dbJxqmm2Zr9177P - wdidFLfm+9tpn/cPjT/QzHlevp/X54O/nJwcDBJAAkgACSCBHyGQ+5PlR2b++zMwe94/ - yWd8/pklD0b7e8zjfziYH+ZmsQp+qrBYMBSN43sY0gQOxi9ks4sOwmF0vg7BZhfCrxRA - fIfCVwIFBYUwPofL5fF4fD5fwPDACDAIl8spKqI5/DsFGkE+bAAAgPH5AoIQikTinyAi - kZAgBECCCxgOKByzEGkE0AGagIAQisXFJRJJaalUKmN0pNLSUomkpFgsFhICmgJ0ARYi - OwS6BXQJaAIimF8qk5cpFEqVSs3oqFRKhaJMLpMCB1GaAlSBhpDlXEgjABHw+EAAAMD0 - ao1We5LUMTzkSa1WowYSgAEo8Hm0FrJDyKVdwOZACcQlUrkC5id1hvIKo8lkNlsYG7PZ - ZDJWlBt0JHBQyKUlYqgCh02b8WgRoAaAoIgnEIolMoVaS+rLTeZKq81GUdQpBgce32az - VppN5XpSq1bIJGKhAJpQwMqyDVAD0CE3jUCpIQ1Gi9VG2atPO2vrIC6Ghn72Wufpajtl - s1qMBlKjTEPgghizFCEXalDE5RNiiVyp0VVYqiiHs9bV4PZ4fT6fn7GBh/d63A2uWqeD - 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 - dGggMjYwIC9IZWlnaHQgMjYwIC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5IC9CaXRzUGVy - Q29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7d3/U1JZ - FADwvijyTURFVJKVomxxILQwU7I0Gr+3Wg4jfTOcMqNGLR1aR8sp1Cmx8kvluOZoTuyg - mWnqqG27s//anvuwTBcUFd6798L5JQ1K+Hjuue894Jw9e8IRFggLhAXCAmGBsEBYICyA - kcBeFPsgmC8wemAsPZTVZw8A+/cjBgj4K5Z+OBY/xvPr378/IiIiEgL+8EiEkAJaAAAA - z57Hi4Lg8RAEwxAiqYCSAAHwovh8vkAgFAoE8EUUOETAsgiJVGAIGAGBUCQSR0OIRSKh - gFEIDQQggCTg8flCkVgiiZHGQkhjJBKxSMjn81AqUJ8JHoIoEIiWSGPjZLIECJksLlYq - iQaFqBBAWCUQQA5I42QJiUkKJpISE2RxUsgFAf0IHgK+QIQE5EmKFGWqCiJVmaJIkiMF - kYBPeSasEghFkth4edIBpeqQ+kgaxBH1IZXyQJI8PlYC64FqhO8EYkmsLFGhVKnTNOla - 3bFjOm26Jk2tUioSZbESMdUIPwhi4hKSU5CAVp95wpCVZTiRqdcihZTkhLgYmhF+IpAr - lAfTNLpMQ3auMQ/CmJttyNRp0g4qFXKaEdYI4uWKX9RHtRmGU8az584XQpw/d9Z4ypCh - Par+RSGPpzYTfiJIVKSqNbrj2cZ8U1FpeQVEeWmRKd+YfVynUacqEmlFWE9wWKM35Jwx - FZdXVpktEOaqyvJi05kcg15zmFqEdQQqRJCbX1hWabZcq7HW1lprrlnMlWWF+bkIQUVn - JmwgSNdnGQuKL1RZrtfeqrfdvWurv1V73VJ1objAmKVPpxNhI0HGydOmkgrzVWudreF+ - c0tL8/0GW531qrmixHT6ZAaVCP8nyDOVVFbX3LQ1Nttb29rb21rtzY22mzXVlSWmPCoR - vBGUXrTcqLv3wN7W8dTR1eV42tFmf3Cv7oblYimVCN4Iyi5dtt5uaGntcHQ/d/b2Op93 - OzpaWxpuWy9fKqMQwRdBfaO9/Um382XfwODgQN9LZ/eTdntjPZUIvgjuNNkfOZ696H89 - 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 - fXF9u097/f1/ZAJM0U5UKJFCulZ37JhOm44ElIpEmEBN0qtJ65+ef999R4BR4vHypANK - 1SH1kTSII+pDKuWBJHk8zF6meCF4kFYRBCKJNE4mT1KkKFNVEKnKFEWSXBYnhYn0eL/L - xL/f9eb38iBECURipJCQmKRgIikxAQmIRWgMOcZvtNn8yfl76yoCXyiKlkhj42SyBAiZ - LC5WKomGdRAKBN93Bx4fFMQSSYw0FkIaI4EcEPL5vBDIApQtkAkwJTGSF8UXCEUicTSE - WCQSCvhRvEgYw47vO878TXV/7scgRDAKfL5AIBQKBHw+IwClIDQIUCrsg1SAsS/gwIuC - 4EEGwCoAAW/Ddv1xJfA+KBUYhggEERkR4QEImSTw/Mr2ehgYCeQBAX9F4K9zlw8ZnrRH - gvlil/9Z+J+HBcICYYGwQFggLBAWCAsEVuA/SCo8XAplbmRzdHJlYW0KZW5kb2JqCjUz - IDAgb2JqCjM3MTEKZW5kb2JqCjU3IDAgb2JqCjw8IC9MZW5ndGggNTggMCBSIC9UeXBl - IC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMjYwIC9IZWlnaHQgMjYwIC9D - b2xvclNwYWNlCi9EZXZpY2VHcmF5IC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAv - RmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7d3/U1JZFADwvijyTURFVJKVomxxILQwU7I0 - Gr+3Wg4jfTOcMqNGLR1aR8sp1Cmx8kvluOZoTuygmWnqqG27s//anvuwTBcUFd6798L5 - JQ1K+Hjuue894Jw9e8IRFggLhAXCAmGBsEBYICyAkcBeFPsgmC8wemAsPZTVZw8A+/cj - Bgj4K5Z+OBY/xvPr378/IiIiEgL+8EiEkAJaAAAAz57Hi4Lg8RAEwxAiqYCSAAHwovh8 - vkAgFAoE8EUUOETAsgiJVGAIGAGBUCQSR0OIRSKhgFEIDQQggCTg8flCkVgiiZHGQkhj - JBKxSMjn81AqUJ8JHoIoEIiWSGPjZLIECJksLlYqiQaFqBBAWCUQQA5I42QJiUkKJpIS - E2RxUsgFAf0IHgK+QIQE5EmKFGWqCiJVmaJIkiMFkYBPeSasEghFkth4edIBpeqQ+kga - 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 - 4BPAJ4BP4J88gf8Cx7sMUAplbmRzdHJlYW0KZW5kb2JqCjczIDAgb2JqCjI1MTQKZW5k - b2JqCjY1IDAgb2JqCjw8IC9MZW5ndGggNjYgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0 - eXBlIC9JbWFnZSAvV2lkdGggMjYwIC9IZWlnaHQgMjYwIC9Db2xvclNwYWNlCi9EZXZp - Y2VHcmF5IC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4K - c3RyZWFtCngB7d3/U1JZFADwvijyTURFVJKVomxxILQwU7I0Gr+3Wg4jfTOcMqNGLR1a - R8sp1Cmx8kvluOZoTuygmWnqqG27s//anvuwTBcUFd6798L5JQ1K+Hjuue894Jw9e8IR - FggLhAXCAmGBsEBYICyAkcBeFPsgmC8wemAsPZTVZw8A+/cjBgj4K5Z+OBY/xvPr378/ - IiIiEgL+8EiEkAJaAAAAz57Hi4Lg8RAEwxAiqYCSAAHwovh8vkAgFAoE8EUUOETAsgiJ - VGAIGAGBUCQSR0OIRSKhgFEIDQQggCTg8flCkVgiiZHGQkhjJBKxSMjn81AqUJ8JHoIo - EIiWSGPjZLIECJksLlYqiQaFqBBAWCUQQA5I42QJiUkKJpISE2RxUsgFAf0IHgK+QIQE - 5EmKFGWqCiJVmaJIkiMFkYBPeSasEghFkth4edIBpeqQ+kgaxBH1IZXyQJI8PlYC64Fq - hO8EYkmsLFGhVKnTNOla3bFjOm26Jk2tUioSZbESMdUIPwhi4hKSU5CAVp95wpCVZTiR - qdcihZTkhLgYmhF+IpArlAfTNLpMQ3auMQ/CmJttyNRp0g4qFXKaEdYI4uWKX9RHtRmG - U8az584XQpw/d9Z4ypChPar+RSGPpzYTfiJIVKSqNbrj2cZ8U1FpeQVEeWmRKd+YfVyn - UacqEmlFWE9wWKM35JwxFZdXVpktEOaqyvJi05kcg15zmFqEdQQqRJCbX1hWabZcq7HW - 1lprrlnMlWWF+bkIQUVnJmwgSNdnGQuKL1RZrtfeqrfdvWurv1V73VJ1objAmKVPpxNh - I0HGydOmkgrzVWudreF+c0tL8/0GW531qrmixHT6ZAaVCP8nyDOVVFbX3LQ1Nttb29rb - 21rtzY22mzXVlSWmPCoRvBGUXrTcqLv3wN7W8dTR1eV42tFmf3Cv7oblYimVCN4Iyi5d - tt5uaGntcHQ/d/b2Op93OzpaWxpuWy9fKqMQwRdBfaO9/Um382XfwODgQN9LZ/eTdntj - PZUIvgjuNNkfOZ696H89NAwx9Lr/xTPHI3vTHQoRvBNcsd5pevi4s+fV4NDI6BjE6MjQ - 4KuezscPAeEKZcvBB0Gtren3ji5n35vh0fEJF8TE+Ojwmz5nV8fvTbZauhA2J+h/OzI2 - 4XJPTk1Nul0TYyNv+ylE2JSgt3/o3fgH99T0DMT0lPvD+Luh/l7aMmFzgoGhd+9d7o8z - s3MQszMf3a7374YGKEPYkmDCNTn9eW5+AWJ+7vP0pGuCNgQ/CKY+zX5ZWFyCWFz4Mvtp - ijaErQn+BIL5haWl5ZWV5aWlhXlA+JOqTPCLYG5+cWn5KxPLS4vzc3Qh+E2w8vXrX9++ - /fX16wptCNsgAIG//0YKlCFsi+BvJmhD2AEBpAJVmbBdgn8gIBdoQtgJAWUIOyOgCmGn - BBQh7JyAGoTdEFCCsDsCKhB2SvDvv2h7REH8FrlzAmoQdkNACcLuCKhA2C0BBQi7JyAe - IRAEhCMEhoBohEAREIwQOAJiEQJJQChCYAmIRAg0AYEIgScgDiEYBIQhBIeAKIRgERCE - EDwCYhCCSUAIQnAJiEAINgEBCMEnwB6BDQLMEdghwBqBLQKMEdgjwBaBTQJMEdglwBKB - bQIMEdgnwA6BCwLMELghwAqBKwKMELgjwAaBSwJMELglwAKBawIMELgn4BwBBwKOEfAg - 4BQBFwIOEfAh4AwBJwKOEPAi4AQBNwIOEPAjYB0BRwKWEfAkYBUBVwIWEfAlYA0BZwKW - EPAmYAUBdwIWEPAnCDoCCQRBRiCDIKgIpBAEEYEcgqAhkEQQJASyCIKDwAwK4QvFMXGJ - CtXh9IyTeaayS1c8zf56ocfZBLR2Qn2NVqCnD3w82fM55X/++Zez+P4I/Pqs9Fov900m - NHkIBEAgV6SSQLCdTEhlGtqvDrnwiQBDgyIio2BKBkOg0TNZcNnKtHzEMgtQ+m2VCavt - SZk25vI4mPQB405gBJIPBDQ3KTKKD1MyEqAzvkafddpUCh1w76Cul9gSbImAerSWmk5n - 6TXQ1T8BJn3A4Bs0Ask7AqwEGBoEBLJkJRAYjKaSi/gT+INwscRkhF7uamUyTPoQwQgk - mIDk3cCzEsQx8YkpB4/qDLkFJZUWa33TQ6yzYMvl8LCp3mqpLCnINeiOHkxBkw08q8Gr - wY80kCtUadrjOflFFdU3bjfaH3c5ofEndjvCz1uRz5oAPVof2xtv36iuKMrPOa5NUynk - myYCMogSRktlSbASMrLPFF4w19Q12B91MgQuzDbFnwl8LAfUlLLf2fnI3lBXY75QeCY7 - A1ZDkkwaLUQVweti2AubAlSDOPkBVZoOikFZ1dWb91raHT19b6H3KWr5iNFxwXoCbwio - M+f7d2/7ehztLfduXq0qg5KgS1MdQHsDzD/ybrBvXyRPIPakQWZ2fjEUA9uD1ifPXr0Z - GXdN4k3gHWHSNT7y5tWzJ60PbFASivOzMz2JIBbwIvft81IQVpcC7ItQDSANys3X6xrt - Hd0vBofHPrinsc4C74Vxdtr9YWx48EV3h72x7rq5HBIBVYSEWJ+LARmgpZCYcuhXffbZ - ogpLra25zdHTPzQ64f74+csCPgfIGxeC5/uNhXHhy+eP7onRof4eR1uzrdZSUXQ2W//r - oZREZjF4LQhQDuDgICYeKmJ6Zk5BadW1Ww2QBi9f/zHumpqZW4Dep5icI3gn2LgclpcW - 5mamXON/vH4JidBw61pVaUFOZjpUxfgYOETwWhCQASoHyalHtCfQUqipv9/69HkfSoPV - lYDHaZIvgvUITHdSWA2QCH3Pn7ber69Bi+GE9khqskwKBcGXQZRAzJQDnSGv8LdqK1oK - zgGoBpOffqTB94Tz/UC4vOX7o2N6UqJE+DQJFWHAiRaDtfq3wjy0M0BBgMMkHwZwuhTN - GBzLyiuEcnC3ub2zFyqiZynA6fLa2TKXT3Szn72KAA8UNSdlFgNUxd7O9ua7UBAK87KO - eYoiHCp62xz37gsbQD0Ir4VwTdwT3hv3gEH4GCl8rAwnEOFzJrQYwufOq4shxK+hrF5S - DeFraVAQ0KsLIX1NldkdQ/3aevg1Ftgdw6+1MQj7YX8M6ddcmQNmQAjp1973hN+DgVYD - HCl5MiGegHdhrF07C+hAF5IQgkRAUiYEjYAchCASkIIQVAIyEIJMQAJC0AnwR2CBAHcE - VgjwRmCJAGcE1gjwRWCRAFcEVgnwRGCZAEcE1gnwQ+CAADcETgjwQuCIACcEzgjwQeCQ - ABcETgnwQOCYAAcEzgm4R8CAgGsELAi4RcCEgEsEbAi4Q8CIgCsErAi4QcCMgAsE7AjY - R8CQgG0ELAnYRcCUgE0EbAnYQ8CYgC0ErAnYQcCcgA0E7AmCj0AAQbARiCAILgIhBMFE - IIYgeAgEEQQLgSiC4CAQRhAMBOIIAo9AIEGgEYgkCCwCoQSBRCCWIHAIBBMECoFogsAg - EE4QCATiCXaPQAHBbhGoINgdAiUEu0GghmDnCBQR7BbBr67x0B1ZCA1hoQmm17a48IFt - rmOnn5VGmUAJwW4ygRqCnSNQRLBTBKoIdoZAGcH2EQCAaQG7srQ4P/dp6k9okj7Q29Xx - e5Ot9sqlMlPeyYz0wyoF6peP+Y7w84603d2BQoJtZgL0bP72DTXBpSgLUEZsIxOgdzcI - 0EewDYTlr0ws05YFfmfC7PzC0tLyysry0tLCPIxLoKMcrpXGrZcDmmrxZWFxCWJx4Qua - GEHFjrBG4M9ycE1Of56bX4CYn/s8PUkfgR8I713ujzOzcxCzMx/dMDeEguOCn7Ng65oA - o37GP7inpmcgpqfcH8Zhfgzxh0YbCbbIBGf/25GxCZd7cmpq0u2aGBt5C3OECD86/D/B - Vgh9b4ZHxydcEBPjo8Nv+qgk8IkAI+AePu7seTU4NDI6BjE6MjT4qqfz8cOmO1ZyzxG8 - ZYHvmoCGwNkfOZ696H89NAwx9Lr/xTPHIzsQXCb2NMkXga9MuGytb7S3P+l2vuwbGBwc - 6Hvp7H7Sbm+sp5LAN8LthpbWDkf3c2dvr/N5t6OjtaXhNqUE3hFKL1pu1N17YG/reOro - 6nI87WizP7hXd8NysZTQ6wW+F4LnFm+HzSWV1TU3bY3N9ta29va2Vntzo+1mTXVlCaUE - 3jLhtKmkwnzVWmdruN/c0tJ8v8FWZ71qrigxnSbyqtFWWYBu35gJ+ixjQfGFKsv12lv1 - trt3bfW3aq9bqi4UFxiz9AReOPOH4H8IMCc1N7+wrNJsuVZjra211lyzmCvLCvNzYd4o - edcO/SPYgJB6GBByzpiKyyurzBYIc1VlebHpTA4iSCXt8qm/BBsR1Brd8WxjvqmotLwC - ory0yJRvzD6u06gpJliHIIfJyUe1GYZTxrPnzhdCnD931njKkKE9CtOH5WRdRPc/C9A9 - 1wojTNBWHkzT6DIN2bnGPAhjbrYhU6dJO6hkRnET9DrC9gjWISQkp6jUaRqtPvOEISvL - cCJTr9WkqVUpyQlrI9lxfXF9u097/f1/ZAJM0U5UKJFCulZ37JhOm44ElIpEmEBN0qtJ - 65+ef999R4BR4vHypANK1SH1kTSII+pDKuWBJHk8zF6meCF4kFYRBCKJNE4mT1KkKFNV - EKnKFEWSXBYnhYn0eL/LxL/f9eb38iBECURipJCQmKRgIikxAQmIRWgMOcZvtNn8yfl7 - 6yoCXyiKlkhj42SyBAiZLC5WKomGdRAKBN93Bx4fFMQSSYw0FkIaI4EcEPL5vBDIApQt - kAkwJTGSF8UXCEUicTSEWCQSCvhRvEgYw47vO878TXV/7scgRDAKfL5AIBQKBHw+IwCl - IDQIUCrsg1SAsS/gwIuC4EEGwCoAAW/Ddv1xJfA+KBUYhggEERkR4QEImSTw/Mr2ehgY - CeQBAX9F4K9zlw8ZnrRHgvlil/9Z+J+HBcICYYGwQFggLBAWCAsEVuA/SCo8XAplbmRz - dHJlYW0KZW5kb2JqCjY2IDAgb2JqCjM3MTEKZW5kb2JqCjU1IDAgb2JqCjw8IC9MZW5n - dGggNTYgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMjI0 - IC9IZWlnaHQgMTg4IC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5IC9CaXRzUGVyQ29tcG9u - ZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7Z3tTxPpGodBCqXt - 9A3aaenLtkxb2mkp3bHFUgrbNm14RxSErbtC0KpZWJDV2EgWdTGsEokiuBBeosgS0YBL - wBAlRs351849hbNGGNRNTmbH5v59IGaCmeea3309U/rlycnB4BPAJ4BPAJ/A//cJ5H5F - +UfkwHXkQ/IEnQ/rPALL/gLMXTZgEonyv5qIRLBgFvVziBm6XbQCsbhwNxLBZm+BYnEB - VAGQnyHco8vPLwA0iVQqk8kIgpALOLA8WKRUKiksZBk/Tcji5cFUAhygEXKFQqlSqQUe - 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 - tNhpnz9YE43XN7W2tXd0diUFm67Ojva21qb6eLQm6PfRdotRB8fbS9nj3z863jAnJxcO - gC9gT7gHQKud9jKBqnAklqhraGxuaT0u0LS2NDc21CVikXBVgPHSdivgsafbFxzkA0AR - FEgAoN5osTk9FUwgGArXRqKxeDyeEGRgYbFopDYcCgaYCo/TZjHqAY+A+kT76/tfgVK5 - km3QQjlcHq+P8VceC4aqIWEBhl1XKHis0s/4vB6Xg2KHU62E6eSqD/qDAsWFsgygwWyl - 7GW0u9zr8zEMc1SggaX5fN5yN11mp6xmQwZPViiG+g72xxoIgBKZXKEuJvUGs8VK2Rxl - ThdNu90eQcbtpmmXs8xho6wWs0FPFqsVcpkE8A7sLuz3hFAgbDHQIKFQFWlIncFoAkZr - KWUTcKhSK7CZjAYdqSlSKQhoj51Ojvr2AGFEpVChqqgYEPUlBqA0mQUbE5AZSvQAVwx0 - cpkUhvMwvJzcTIPwlsgQKtVqYNRotSSpE2xIUqvVAJtarczQwdaSwdv38tv7GjsDKMqH - CoFQRsgVCqVKpRZ4VCqlQiEnZNAdWx64dySXGw8mFBpkdxlWw0KJFCBlBEHIBRxYHixS - KpUAHHTH0h2Ox24yu4SACIwAmYlEsNlboJhlyxd9li6zjbKER/Ly8kQs5FcSQMtjq/tk - d3sWsiVmGNnfh8D/FHB215j5Ccv+G+FL/gG//9XkS3jwd/AJ4BPAJ4BP4J88gf8Cx7sM - UAplbmRzdHJlYW0KZW5kb2JqCjU2IDAgb2JqCjI1MTQKZW5kb2JqCjQxIDAgb2JqCjw8 - IC9MZW5ndGggNDIgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lk - dGggMjYwIC9IZWlnaHQgMjYwIC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5IC9CaXRzUGVy - Q29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7d3/U1JZ - FADwvijyTURFVJKVomxxILQwU7I0Gr+3Wg4jfTOcMqNGLR1aR8sp1Cmx8kvluOZoTuyg - mWnqqG27s//anvuwTBcUFd6798L5JQ1K+Hjuue894Jw9e8IRFggLhAXCAmGBsEBYICyA - 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 - WCQSCvhRvEgYw47vO878TXV/7scgRDAKfL5AIBQKBHw+IwClIDQIUCrsg1SAsS/gwIuC - 4EEGwCoAAW/Ddv1xJfA+KBUYhggEERkR4QEImSTw/Mr2ehgYCeQBAX9F4K9zlw8ZnrRH - gvlil/9Z+J+HBcICYYGwQFggLBAWCAsEVuA/SCo8XAplbmRzdHJlYW0KZW5kb2JqCjQy - IDAgb2JqCjM3MTEKZW5kb2JqCjQ3IDAgb2JqCjw8IC9MZW5ndGggNDggMCBSIC9UeXBl - IC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMzAwIC9IZWlnaHQgMjI4IC9D - b2xvclNwYWNlCi9EZXZpY2VHcmF5IC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAv - RmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7dn9T5P31wdwpKUPUPpAn0YppQ9YSi1CgVAe - YhE7UbAOiWgbJaSmzlRTZXMQCGMwNIipY+AIQQgDMYgBQtAQJETI/rX7XKBzB8rZ/b3v - 70/tOT9sO3tHk88r53yuq21GBhcLsAALsAALsEASgVNpWUkgqP8FRplfS5Qm9fXEmQBA - +XzJPjuJRGKxOCsNC44tEgls/+p1OFAiQUkikUplhyVPg/p8VKlUIoHDiz9zfZmgJP8W - Vk+AkghK8uwcKIVCkZsWBQcVzpsth6NLweuA68RVFIbqsxQ4KXKVSpVKrUmjUqtUSmWu - QvD6onXSxXVIBTMFUEqlWpOn1el0eoPBmBZlMOjhuNo8jVqpBC5BSxit5JP1mUomBym1 - RqvTG435JlNBgdlcmAZlNhcUmEz5RqNepwUuRY5cdjLWIZUwVEqVBqDyTeZCi9Vqs9sd - aVF2u81qtRSawUuv06iUwmidNFmnhLsKqGCotHqjyWyx2h2nnSWu0lK3230mxQuOWFrq - KnGedtitFrPJqNfCaH3GSrKFcK9nSQQqjc5gMhfZip0ut6fsbHmF11uZBuX1VpSfLfO4 - Xc5iW5HZZNBpBCxJFlxZx14YYKy+UBlNhbbiEren3FtVXeOrrasXqiGF6+CAdbW+muoq - b7nHXVJsKzQZv2IdG6xTmbCB8hyYKqPJ4nC6y7xVNbX15/znmy4EAt+mfAUCF5rO+8/V - 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 - FeIgG7YieVDIVoiDbNiK5EEhWyEOsmErkgeFbIU4yIatSB4UshXiIBu2InlQyFaIg2zY - iuRBIVshDrJhK5IHhf+ZlUyhMZgdbm994Go4+qh/JPHy1eLbtc2tj7t7e/vo703BZn9v - b/fj1uba28VXLxMj/Y+i4auBeq/bYTZoFLIs0amMf1Zm1slWn9LB6hNhlflPqYyMf7Ha - T+nJ2t/f3/tvWsHfl8r1f7UKhqIP+4afT8wsLK9ufNje2f20l/L1aXdn+8PG6vLCzMTz - 4b6H0VDwH/dV0h0ssJd66y4Eb96J9w6N/T49/+bd+uYWYKVB7Wxvba6/ezM//fvYUG/8 - zs3ghTpvqb3g4G5PYqXWg1VFbVPrjciDnwZHf5uaW4TBer+1/XEn5evj9tZ7GKvFuanf - Rgd/ehC50dpUWwFWejU8B49b5aj1Jpur3He+5XpX7PHAk8TkzJ9LK2sbmx+20qA+bG6s - rSz9OTOZeDLwONZ1veW8r9xlM+nVOUmtVDqTteRsjf9Se+e97r7hsfGp2YU3K6vrG5vv - U742N9ZXV94szE6Njw33dd/rbL/krzlbYjXpVCdZ5Rc5PdXnmttuReM9g08TE9NzC0vL - 71bX1lO+1lbfLS8tzE1PJJ4O9sSjt9qaz1V7nEX5Sa3Eshyl9hvL6TNV9YFgKBL7oX9o - 9MXk9Oz866XltyspX2+Xl17Pz05Pvhgd6v8hFhEeg1VnTlu+0SpzZOKj95VYmq3MMxY6 - Sr21cGF13o33DIw8ezExNTM3v7D4OuVrcWF+bmZq4sWzkYGe+N1OuK5qvaWOQmOeMlua - zCoXPhDaXeU1/uZr4Uisu/fnkWeJ8cmp6ZlXsylfr2ampybHE89Gfu7tjkXC15r9NeUu - O3wczE1iJZLIczV6k9XpEZaw43b0PmANPx1LjE9Mvvwj5evl5MR4YuzpMFDdj97uEFbQ - 47Sa9JpcuUR0dAdFElmOWpdvgW8afI2X20JdgNXTPzj8ZHTseSIN6vnY6JPhwf4eoOoK - tV1u9MG3DJZ8HbwyJLHKgss9z2i2lZRVNwRa28Nd0Vj8x97+gV+Gfh1Jg/p16JeB/t4f - 47FoV7i9NdBQXVZiM8N1Ba8MR+fqVGYWXO6whEXF7gqf/+KV9tDtyPf3492Pe3r7+tOg - +np7HnfH738fuR1qv3LR76twFxfBCsLVnpWJv77KACuJXKHSwWA5PZV1jRdb2zrCnZHo - vdiD+MNH3Slfjx7GH8TuRSOd4Y621ouNdZUeJ4yVTqWQS5JYiYUl1OjzCx2usqo6f+By - 8FpH6FZnV+RONHo35SsavRPp6rwV6rgWvBzw11WVuRyF+TBWsILi43MlypLCYGkNJgtg - VfoaGgPNLcG29us3bobCaVChmzeut7cFW5oDjQ2+SqCymAxaGCspXFdHdjAjM1MMT8Jc - tc5oKnK4PBXVvgZ/U6D5UsuVYPDqdylfV4PBKy2XmgNN/gZfdYXH5SgyGXXqXHgKijOP - vDJkwIUlhsGCLQQsi8PpLvNW1dTWn/Ofb7oQCHyb8hUIXGg67z9XX1tT5S1zO2GqjDrY - QBirYysoWImyJLJsxQFWoa24xO0p91ZV1/hq6+qFakjhOjhgXa2vprrKW+5xlxTbCg+o - FNkySZIVhF8nvmIZTOYiW7HT5faUnS2v8Hor06C83orys2Uet8tZbCsymwwwVZ+pjq3g - wWDBFgqTpdbqjSazxWp3nHaWuEpL3W73mRQvOGJpqavEedpht1rMJqNeqxaoYAOP3+zw - A9gpGKwDrBylSqPTG/NN5kKL1Wqz2x1pUXa7zWq1FJpN+Ua9TqNS5nymOvYUFH4sPMSS - yOQ5MFoaLXCBl6mgwGwuTIMymwsKTOAEUFoNDFWOHO4qmKqkVH9jwR6CFnDlaXU6nd5g - MKZFGQx6OK42D6BACoaKoso4dThZWRKpTA5cuUqlSqXWpFGpVSqlMheg5ILU4VQdfQ/9 - ++d6wBIuLUFLJnhBKRSK3LQoOKhwXnCS/S11wgIeegmjdciVJZFIBTGh5GlQhyeVSaUS - mKiDkYKr6sSh+qJ1yCUSi2HA0q/g2CK40QWof5FCXsKfgBKlSR2e9uCf/0unv+8ueC6m - Zf0DgP+TBViABViABVjgq8D/AOqBT24KZW5kc3RyZWFtCmVuZG9iago0OCAwIG9iagoz - ODc3CmVuZG9iago3NiAwIG9iago8PCAvTGVuZ3RoIDc3IDAgUiAvTiAzIC9BbHRlcm5h - dGUgL0RldmljZVJHQiAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAGtk89r - 02Acxp+0Q4fOCXPzIAg5OPBQpbQFfyDYtetGN+lK263VW5ukTbVJQ5JWWzz0HxC8CepB - 8bLD9Kx4UQTx4kEmongV8eJlhzEYIz5JTOvB4cVvefN++uR5v++b7/u+QHinahitEABN - t83CYkqsXL0mHvyCCRziL4GZqmQZc/n8FVr2ie1PENxXm2fcXPeNXZy7u5nYftT7funp - xcP7DArkSZMTAkKEwnTD56TLNZ9LLt+0DZse1WVJrcrk2+SIWSqkyevkyYbPz12u+fzO - 5a7UcMd+Jkd1uakDoXHyeVmxJHKSrMqWpJGZRwhpWpv5wxvUT0uGybHhj+RTbl3YM3pH - gcv36H890ipvgY1nwPGfI22W3mNfgRfdkba149VKOPnNqsdjXjrhyGPgQN9xtmaAcc69 - t+Y4uynH2ePcY0zy8o7UMbuelwsU3gP/+u9/s58d+MA8DG+P/s5+XTxXFHgyANZeAUsU - HrLN8lunHgArSaA4QCgeD5pfQ1pY56KkGLapiJVYorzoSf/vobU63Csvpvic0Gu5FfYn - 2H4Ydr4UsNUtZgKuNxeyAcvV+eWA+2o6F3DdXCgEfL26lA9Y0VeLARst7+z/nis19CtW - Zujpq6Vy4Dc7hdWAb7SXh35ZmR+uTW/l3Pvk5Wza2eH6UYQEBQZsmOxFVBDjHSyDBfXP - JUchN83jOEbIvFnXBq7yZ9jKLW+/022jZzYbqi3O8VYqETGrS2cjYiwavYBfakqyNwpl - bmRzdHJlYW0KZW5kb2JqCjc3IDAgb2JqCjU2NQplbmRvYmoKNDMgMCBvYmoKWyAvSUND - QmFzZWQgNzYgMCBSIF0KZW5kb2JqCjc4IDAgb2JqCjw8IC9MZW5ndGggNzkgMCBSIC9O - IDMgL0FsdGVybmF0ZSAvRGV2aWNlUkdCIC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0 - cmVhbQp4Aa2Tz2vTYBzGn7RDh84Jc/MgCDk48FCltAV/INi160Y36UrbrdVbm6RNtUlD - klZbPPQfELwJ6kHxssP0rHhRBPHiQSaieBXx4mWHMRgjPklM68HhxW9583765Hm/75vv - +75AeKdqGK0QAE23zcJiSqxcvSYe/IIJHOIvgZmqZBlz+fwVWvaJ7U8Q3FebZ9xc941d - nLu7mdh+1Pt+6enFw/sMCuRJkxMCQoTCdMPnpMs1n0su37QNmx7VZUmtyuTb5IhZKqTJ - 6+TJhs/PXa75/M7lrtRwx34mR3W5qQOhcfJ5WbEkcpKsypakkZlHCGlam/nDG9RPS4bJ - seGP5FNuXdgzekeBy/fofz3SKm+BjWfA8Z8jbZbeY1+BF92RtrXj1Uo4+c2qx2NeOuHI - Y+BA33G2ZoBxzr235ji7KcfZ49xjTPLyjtQxu56XCxTeA//673+znx34wDwMb4/+zn5d - PFcUeDIA1l4BSxQess3yW6ceACtJoDhAKB4Pml9DWljnoqQYtqmIlViivOhJ/++htTrc - Ky+m+JzQa7kV9ifYfhh2vhSw1S1mAq43F7IBy9X55YD7ajoXcN1cKAR8vbqUD1jRV4sB - Gy3v7P+eKzX0K1Zm6OmrpXLgNzuF1YBvtJeHflmZH65Nb+Xc++TlbNrZ4fpRhAQFBmyY - 7EVUEOMdLIMF9c8lRyE3zeM4Rsi8WdcGrvJn2Motb7/TbaNnNhuqLc7xVioRMatLZyNi - LBq9gF9qSrI3CmVuZHN0cmVhbQplbmRvYmoKNzkgMCBvYmoKNTY1CmVuZG9iago1OSAw - IG9iagpbIC9JQ0NCYXNlZCA3OCAwIFIgXQplbmRvYmoKODAgMCBvYmoKPDwgL0xlbmd0 - aCA4MSAwIFIgL04gMyAvQWx0ZXJuYXRlIC9EZXZpY2VSR0IgL0ZpbHRlciAvRmxhdGVE - ZWNvZGUgPj4Kc3RyZWFtCngBrZPPa9NgHMaftEOHzglz8yAIOTjwUKW0BX8g2LXrRjfp - Stut1VubpE21SUOSVls89B8QvAnqQfGyw/SseFEE8eJBJqJ4FfHiZYcxGCM+SUzrweHF - b3nzfvrkeb/vm+/7vkB4p2oYrRAATbfNwmJKrFy9Jh78ggkc4i+BmapkGXP5/BVa9ont - TxDcV5tn3Fz3jV2cu7uZ2H7U+37p6cXD+wwK5EmTEwJChMJ0w+ekyzWfSy7ftA2bHtVl - Sa3K5NvkiFkqpMnr5MmGz89drvn8zuWu1HDHfiZHdbmpA6Fx8nlZsSRykqzKlqSRmUcI - aVqb+cMb1E9Lhsmx4Y/kU25d2DN6R4HL9+h/PdIqb4GNZ8DxnyNtlt5jX4EX3ZG2tePV - Sjj5zarHY1464chj4EDfcbZmgHHOvbfmOLspx9nj3GNM8vKO1DG7npcLFN4D//rvf7Of - HfjAPAxvj/7Ofl08VxR4MgDWXgFLFB6yzfJbpx4AK0mgOEAoHg+aX0NaWOeipBi2qYiV - WKK86En/76G1OtwrL6b4nNBruRX2J9h+GHa+FLDVLWYCrjcXsgHL1fnlgPtqOhdw3Vwo - BHy9upQPWNFXiwEbLe/s/54rNfQrVmbo6aulcuA3O4XVgG+0l4d+WZkfrk1v5dz75OVs - 2tnh+lGEBAUGbJjsRVQQ4x0sgwX1zyVHITfN4zhGyLxZ1wau8mfYyi1vv9Nto2c2G6ot - zvFWKhExq0tnI2IsGr2AX2pKsjcKZW5kc3RyZWFtCmVuZG9iago4MSAwIG9iago1NjUK - ZW5kb2JqCjU0IDAgb2JqClsgL0lDQ0Jhc2VkIDgwIDAgUiBdCmVuZG9iago4MiAwIG9i - ago8PCAvTGVuZ3RoIDgzIDAgUiAvTiAzIC9BbHRlcm5hdGUgL0RldmljZVJHQiAvRmls - dGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAGtk89r02Acxp+0Q4fOCXPzIAg5OPBQ - pbQFfyDYtetGN+lK263VW5ukTbVJQ5JWWzz0HxC8CepB8bLD9Kx4UQTx4kEmongV8eJl - hzEYIz5JTOvB4cVvefN++uR5v++b7/u+QHinahitEABNt83CYkqsXL0mHvyCCRziL4GZ - qmQZc/n8FVr2ie1PENxXm2fcXPeNXZy7u5nYftT7funpxcP7DArkSZMTAkKEwnTD56TL - NZ9LLt+0DZse1WVJrcrk2+SIWSqkyevkyYbPz12u+fzO5a7UcMd+Jkd1uakDoXHyeVmx - JHKSrMqWpJGZRwhpWpv5wxvUT0uGybHhj+RTbl3YM3pHgcv36H890ipvgY1nwPGfI22W - 3mNfgRfdkba149VKOPnNqsdjXjrhyGPgQN9xtmaAcc69t+Y4uynH2ePcY0zy8o7UMbue - lwsU3gP/+u9/s58d+MA8DG+P/s5+XTxXFHgyANZeAUsUHrLN8lunHgArSaA4QCgeD5pf - Q1pY56KkGLapiJVYorzoSf/vobU63Csvpvic0Gu5FfYn2H4Ydr4UsNUtZgKuNxeyAcvV - +eWA+2o6F3DdXCgEfL26lA9Y0VeLARst7+z/nis19CtWZujpq6Vy4Dc7hdWAb7SXh35Z - mR+uTW/l3Pvk5Wza2eH6UYQEBQZsmOxFVBDjHSyDBfXPJUchN83jOEbIvFnXBq7yZ9jK - LW+/022jZzYbqi3O8VYqETGrS2cjYiwavYBfakqyNwplbmRzdHJlYW0KZW5kb2JqCjgz - IDAgb2JqCjU2NQplbmRvYmoKNjIgMCBvYmoKWyAvSUNDQmFzZWQgODIgMCBSIF0KZW5k - b2JqCjg0IDAgb2JqCjw8IC9MZW5ndGggODUgMCBSIC9OIDMgL0FsdGVybmF0ZSAvRGV2 - aWNlUkdCIC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Aa2Tz2vTYBzGn7RD - h84Jc/MgCDk48FCltAV/INi160Y36UrbrdVbm6RNtUlDklZbPPQfELwJ6kHxssP0rHhR - BPHiQSaieBXx4mWHMRgjPklM68HhxW9583765Hm/75vv+75AeKdqGK0QAE23zcJiSqxc - vSYe/IIJHOIvgZmqZBlz+fwVWvaJ7U8Q3FebZ9xc941dnLu7mdh+1Pt+6enFw/sMCuRJ - kxMCQoTCdMPnpMs1n0su37QNmx7VZUmtyuTb5IhZKqTJ6+TJhs/PXa75/M7lrtRwx34m - R3W5qQOhcfJ5WbEkcpKsypakkZlHCGlam/nDG9RPS4bJseGP5FNuXdgzekeBy/fofz3S - Km+BjWfA8Z8jbZbeY1+BF92RtrXj1Uo4+c2qx2NeOuHIY+BA33G2ZoBxzr235ji7KcfZ - 49xjTPLyjtQxu56XCxTeA//673+znx34wDwMb4/+zn5dPFcUeDIA1l4BSxQess3yW6ce - ACtJoDhAKB4Pml9DWljnoqQYtqmIlViivOhJ/++htTrcKy+m+JzQa7kV9ifYfhh2vhSw - 1S1mAq43F7IBy9X55YD7ajoXcN1cKAR8vbqUD1jRV4sBGy3v7P+eKzX0K1Zm6OmrpXLg - NzuF1YBvtJeHflmZH65Nb+Xc++TlbNrZ4fpRhAQFBmyY7EVUEOMdLIMF9c8lRyE3zeM4 - Rsi8WdcGrvJn2Motb7/TbaNnNhuqLc7xVioRMatLZyNiLBq9gF9qSrI3CmVuZHN0cmVh - bQplbmRvYmoKODUgMCBvYmoKNTY1CmVuZG9iago0NiAwIG9iagpbIC9JQ0NCYXNlZCA4 - NCAwIFIgXQplbmRvYmoKODYgMCBvYmoKPDwgL0xlbmd0aCA4NyAwIFIgL04gMyAvQWx0 - ZXJuYXRlIC9EZXZpY2VSR0IgL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB - rZPPa9NgHMaftEOHzglz8yAIOTjwUKW0BX8g2LXrRjfpStut1VubpE21SUOSVls89B8Q - vAnqQfGyw/SseFEE8eJBJqJ4FfHiZYcxGCM+SUzrweHFb3nzfvrkeb/vm+/7vkB4p2oY - rRAATbfNwmJKrFy9Jh78ggkc4i+BmapkGXP5/BVa9ontTxDcV5tn3Fz3jV2cu7uZ2H7U - +37p6cXD+wwK5EmTEwJChMJ0w+ekyzWfSy7ftA2bHtVlSa3K5NvkiFkqpMnr5MmGz89d - rvn8zuWu1HDHfiZHdbmpA6Fx8nlZsSRykqzKlqSRmUcIaVqb+cMb1E9Lhsmx4Y/kU25d - 2DN6R4HL9+h/PdIqb4GNZ8DxnyNtlt5jX4EX3ZG2tePVSjj5zarHY1464chj4EDfcbZm - gHHOvbfmOLspx9nj3GNM8vKO1DG7npcLFN4D//rvf7OfHfjAPAxvj/7Ofl08VxR4MgDW - XgFLFB6yzfJbpx4AK0mgOEAoHg+aX0NaWOeipBi2qYiVWKK86En/76G1OtwrL6b4nNBr - uRX2J9h+GHa+FLDVLWYCrjcXsgHL1fnlgPtqOhdw3VwoBHy9upQPWNFXiwEbLe/s/54r - NfQrVmbo6aulcuA3O4XVgG+0l4d+WZkfrk1v5dz75OVs2tnh+lGEBAUGbJjsRVQQ4x0s - gwX1zyVHITfN4zhGyLxZ1wau8mfYyi1vv9Nto2c2G6otzvFWKhExq0tnI2IsGr2AX2pK - sjcKZW5kc3RyZWFtCmVuZG9iago4NyAwIG9iago1NjUKZW5kb2JqCjQ5IDAgb2JqClsg - L0lDQ0Jhc2VkIDg2IDAgUiBdCmVuZG9iago4OCAwIG9iago8PCAvTGVuZ3RoIDg5IDAg - UiAvTiAzIC9BbHRlcm5hdGUgL0RldmljZVJHQiAvRmlsdGVyIC9GbGF0ZURlY29kZSA+ - PgpzdHJlYW0KeAGFlE1IFGEYx/+zjQSxBtGXCMXQwSRUJgtSAtP1K1O2ZdVMCWKdfXed - HGenmd0tRSKE6Jh1jC5WRIeITuGhQ6c6RASZdYmgo0UQBV4itv87k7tjVL4wM795nv/7 - fL3DAFWPUo5jRTRgys67yd6Ydnp0TNv8GlWoRhRcKcNzOhKJAZ+plc/1a/UtFGlZapSx - 1vs2fKt2mRBQNCp3ZAM+LHk84OOSL+SdPDVnJBsTqTTZITe4Q8lO8i3y1myIx0OcFp4B - VLVTkzMcl3EiO8gtRSMrYz4g63batMnvpT3tGVPUsN/INzkL2rjy/UDbHmDTi4ptzAMe - 3AN211Vs9TXAzhFg8VDF9j3pz0fZ9crLHGr2wynRGGv6UCp9rwM23wB+Xi+VftwulX7e - YQ7W8dQyCm7R17Iw5SUQ1BvsZvzkGv2Lg558VQuwwDmObAH6rwA3PwL7HwLbHwOJamCo - FZHLbDe48uIi5wJ05pxp18xO5LVmXT+idfBohdZnG00NWsqyNN/laa7whFsU6SZMWQXO - 2V/beI8Ke3iQT/YXuSS87t+szKVTXZwlmtjWp7To6iY3kO9nzJ4+cj2v9xm3Zzhg5YCZ - 7xsKOHLKtuI8F6mJ1Njj8ZNkxldUJx+T85A85xUHZUzffi51IkGupT05meuXml3c2z4z - McQzkqxYMxOd8d/8xi0kZd591Nx1LP+bZ22RZxiFBQETNu82NCTRixga4cBFDhl6TCpM - WqVf0GrCw+RflRYS5V0WFb1Y4Z4Vf895FLhbxj+FWBxzDeUImv5O/6Iv6wv6Xf3zfG2h - vuKZc8+axqtrXxlXZpbVyLhBjTK+rCmIb7DaDnotZGmd4hX05JX1jeHqMvZ8bdmjyRzi - anw11KUIZWrEOOPJrmX3RbLFN+HnW8v2r+lR+3z2SU0l17K6eGYp+nw2XA1r/7OrYNKy - q/DkjZAuPGuh7lUPqn1qi9oKTT2mtqttahffjqoD5R3DnJWJC6zbZfUp9mBjmt7KSVdm - i+Dfwi+G/6VeYQvXNDT5D024uYxpCd8R3DZwh5T/w1+zAw3eCmVuZHN0cmVhbQplbmRv - YmoKODkgMCBvYmoKNzkyCmVuZG9iago4IDAgb2JqClsgL0lDQ0Jhc2VkIDg4IDAgUiBd - CmVuZG9iago5MCAwIG9iago8PCAvTGVuZ3RoIDkxIDAgUiAvTiAzIC9BbHRlcm5hdGUg - L0RldmljZVJHQiAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAGtk89r02Ac - xp+0Q4fOCXPzIAg5OPBQpbQFfyDYtetGN+lK263VW5ukTbVJQ5JWWzz0HxC8CepB8bLD - 9Kx4UQTx4kEmongV8eJlhzEYIz5JTOvB4cVvefN++uR5v++b7/u+QHinahitEABNt83C - YkqsXL0mHvyCCRziL4GZqmQZc/n8FVr2ie1PENxXm2fcXPeNXZy7u5nYftT7funpxcP7 - DArkSZMTAkKEwnTD56TLNZ9LLt+0DZse1WVJrcrk2+SIWSqkyevkyYbPz12u+fzO5a7U - cMd+Jkd1uakDoXHyeVmxJHKSrMqWpJGZRwhpWpv5wxvUT0uGybHhj+RTbl3YM3pHgcv3 - 6H890ipvgY1nwPGfI22W3mNfgRfdkba149VKOPnNqsdjXjrhyGPgQN9xtmaAcc69t+Y4 - uynH2ePcY0zy8o7UMbuelwsU3gP/+u9/s58d+MA8DG+P/s5+XTxXFHgyANZeAUsUHrLN - 8lunHgArSaA4QCgeD5pfQ1pY56KkGLapiJVYorzoSf/vobU63Csvpvic0Gu5FfYn2H4Y - dr4UsNUtZgKuNxeyAcvV+eWA+2o6F3DdXCgEfL26lA9Y0VeLARst7+z/nis19CtWZujp - q6Vy4Dc7hdWAb7SXh35ZmR+uTW/l3Pvk5Wza2eH6UYQEBQZsmOxFVBDjHSyDBfXPJUch - N83jOEbIvFnXBq7yZ9jKLW+/022jZzYbqi3O8VYqETGrS2cjYiwavYBfakqyNwplbmRz - dHJlYW0KZW5kb2JqCjkxIDAgb2JqCjU2NQplbmRvYmoKNjkgMCBvYmoKWyAvSUNDQmFz - ZWQgOTAgMCBSIF0KZW5kb2JqCjkyIDAgb2JqCjw8IC9MZW5ndGggOTMgMCBSIC9OIDMg - L0FsdGVybmF0ZSAvRGV2aWNlUkdCIC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVh - bQp4Aa2Tz2vTYBzGn7RDh84Jc/MgCDk48FCltAV/INi160Y36UrbrdVbm6RNtUlDklZb - PPQfELwJ6kHxssP0rHhRBPHiQSaieBXx4mWHMRgjPklM68HhxW9583765Hm/75vv+75A - eKdqGK0QAE23zcJiSqxcvSYe/IIJHOIvgZmqZBlz+fwVWvaJ7U8Q3FebZ9xc941dnLu7 - mdh+1Pt+6enFw/sMCuRJkxMCQoTCdMPnpMs1n0su37QNmx7VZUmtyuTb5IhZKqTJ6+TJ - hs/PXa75/M7lrtRwx34mR3W5qQOhcfJ5WbEkcpKsypakkZlHCGlam/nDG9RPS4bJseGP - 5FNuXdgzekeBy/fofz3SKm+BjWfA8Z8jbZbeY1+BF92RtrXj1Uo4+c2qx2NeOuHIY+BA - 33G2ZoBxzr235ji7KcfZ49xjTPLyjtQxu56XCxTeA//673+znx34wDwMb4/+zn5dPFcU - eDIA1l4BSxQess3yW6ceACtJoDhAKB4Pml9DWljnoqQYtqmIlViivOhJ/++htTrcKy+m - +JzQa7kV9ifYfhh2vhSw1S1mAq43F7IBy9X55YD7ajoXcN1cKAR8vbqUD1jRV4sBGy3v - 7P+eKzX0K1Zm6OmrpXLgNzuF1YBvtJeHflmZH65Nb+Xc++TlbNrZ4fpRhAQFBmyY7EVU - EOMdLIMF9c8lRyE3zeM4Rsi8WdcGrvJn2Motb7/TbaNnNhuqLc7xVioRMatLZyNiLBq9 - gF9qSrI3CmVuZHN0cmVhbQplbmRvYmoKOTMgMCBvYmoKNTY1CmVuZG9iago0MCAwIG9i - agpbIC9JQ0NCYXNlZCA5MiAwIFIgXQplbmRvYmoKOTQgMCBvYmoKPDwgL0xlbmd0aCA5 - NSAwIFIgL04gMSAvQWx0ZXJuYXRlIC9EZXZpY2VHcmF5IC9GaWx0ZXIgL0ZsYXRlRGVj - b2RlID4+CnN0cmVhbQp4AYVST0gUURz+zTYShIhBhXiIdwoJlSmsrKDadnVZlW1bldKi - GGffuqOzM9Ob2TXFkwRdojx1D6JjdOzQoZuXosCsS9cgqSAIPHXo+83s6iiEb3k73/v9 - /X7fe0RtnabvOylBVHNDlSulp25OTYuDHylFHdROWKYV+OlicYyx67mSv7vX1mfS2LLe - x7V2+/Y9tZVlYCHqLba3EPohkWYAH5mfKGWAs8Adlq/YPgE8WA6sGvAjogMPmrkw09Gc - dKWyLZFT5qIoKq9iO0mu+/m5xr6LtYmD/lyPZtaOvbPqqtFM1LT3RKG8D65EGc9fVPZs - NRSnDeOcSEMaKfKu1d8rTMcRkSsQSgZSNWS5n2pOnXXgdRi7XbqT4/j2EKU+yWCoibXp - spkdhX0AdirL7BDwBejxsmIP54F7Yf9bUcOTwCdhP2SHedatH/YXrlPge4Q9NeDOFK7F - 8dqKH14tAUP3VCNojHNNxNPXOXOkiO8x1BmY90Y5pgsxd5aqEzeAO2EfWapmCrFd+67q - Je57AnfT4zvRmzkLXKAcSXKxFdkU0DwJWBR9i7BJDjw+zh5V4HeomMAcuYnczSj3HtUR - G2ejUoFWeo1Xxk/jufHF+GVsGM+Afqx213t8/+njFXXXtj48+Y163DmuvZ0bVWFWcWUL - 3f/HMoSP2Sc5psHToVlYa9h25A+azEywDCjEfwU+l/qSE1Xc1e7tuEUSzFA+LGwluktU - binU6j2DSqwcK9gAdnCSxCxaHLhTa7o5eHfYInpt+U1XsuuG/vr2evva8h5tyqgpKBPN - s0RmlLFbo+TdeNv9ZpERnzg6vue9ilrJ/klFED+FOVoq8hRV9FZQ1sRvZw5+G7Z+XD+l - 5/VB/TwJPa2f0a/ooxG+DHRJz8JzUR+jSfCwaSHiEqCKgzPUTlRjjQPiKfHytFtkkf0P - QBn9ZgplbmRzdHJlYW0KZW5kb2JqCjk1IDAgb2JqCjcwNAplbmRvYmoKMzcgMCBvYmoK - WyAvSUNDQmFzZWQgOTQgMCBSIF0KZW5kb2JqCjQgMCBvYmoKPDwgL1R5cGUgL1BhZ2Vz - IC9NZWRpYUJveCBbMCAwIDYxMiA3OTJdIC9Db3VudCAxIC9LaWRzIFsgMyAwIFIgXSA+ - PgplbmRvYmoKOTYgMCBvYmoKPDwgL1R5cGUgL0NhdGFsb2cgL091dGxpbmVzIDIgMCBS - IC9QYWdlcyA0IDAgUiAvVmVyc2lvbiAvMS40ID4+CmVuZG9iagoyIDAgb2JqCjw8IC9M - YXN0IDk3IDAgUiAvRmlyc3QgOTggMCBSID4+CmVuZG9iago5OCAwIG9iago8PCAvQ291 - bnQgMCAvRGVzdCBbIDMgMCBSIC9YWVogMCA3MzMgMCBdIC9UaXRsZSAoQ2FudmFzIDEp - ID4+CmVuZG9iago5NyAwIG9iago8PCAvQ291bnQgMCAvRGVzdCBbIDMgMCBSIC9YWVog - MCA3MzMgMCBdIC9UaXRsZSAoQ2FudmFzIDEpID4+CmVuZG9iago5OSAwIG9iago8PCAv - TGVuZ3RoIDEwMCAwIFIgL0xlbmd0aDEgMTU3MDQgL0ZpbHRlciAvRmxhdGVEZWNvZGUg - Pj4Kc3RyZWFtCngBvXt5YFXFufjMnPWeu+/7lpu7Zd8XEsglJIRdFoUEiYZ9UWQRA1jg - RWWNiAqyCIjgwhLUhBAlSLHUgoi1CiqoqLVWoHRJbfvQ10Luzfvm3IDQ9vXnH/31njtz - 5szMmeX7vvm2mYMwQkiFmhCDYpNnT5zbv+Tu+yDnXYSwYXLjAt9jv+23A9K/Qoi5d9rc - 6bP1v/rZOwhxwxCSVNPvXTxtd48V6mprEQq/PWPqxCn/fem+nQgV+6CNohmQIaUIULcY - ylHqjNkLFn3xoWkePC+B59P3zpk88cpff/cGQiVQB82aPXHRXHGL9Dd47oRn330TZ0+t - b1y8GJ4/geeUuXPuX8C1chfguRuem+fOnzr3x4/cl4tQ6WoY3/uQh+GiPxUkeTn1L6Nk - 5WQVghiWg3cEJCokhJTQhhppkFanNyBkRMhktiArstkdTtf3bbqRx+vzpwRSUTAUjkTT - UHpGZhbKzsnN+77O/7dU/g9omTuGdNxRFOGakIPNRl6Eej6FcJ7eE3f0XOJOIl1ids+f - mTJo7DANJFFRjo6hx9A21Ip4tBfSEXQX2oJO4VnoMJ6AOtA57EFZQDMs6kTD0Lu4p+cM - moZegPoL0JtoIzoAsIug2cgMpetwsOdBeI5BehJa3vMcSkUlaCU6ikqh1XWoq2dfz0Eo - HY3uQC1oP7z/cxwgB1hjzys9F5CIRkGby6HkTM+wnlZkQBmoEo2E3OXoDRxkzvfMQDZU - BqPbjp5Fu9BP0R/ww7ijZ0ZPY8/pnq8QgVIXGgPXUtyBv2Ja2ZU923t+15MASERQGvTa - gDag56H9VriOAflU43vwArwBbyQx8jDpYFdw1kQc4BBFNXANQnPQaoDAYXQc/QX9DX9D - bIyOWcCc6Cns+W+gmaEwSzqTqagRrlVwrYM5HcE8zsED8Ei8FD+FN+IPSRq5g9SShWQR - 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 - dEJCb3ggWzAgLTIyMSA3NjggNzM3XSAvRm9udE5hbWUgL1pCWE9FUCtIZWx2ZXRpY2Eg - L0l0YWxpY0FuZ2xlIDAgL1N0ZW1WCjAgL01heFdpZHRoIDE1MDAgL1hIZWlnaHQgNTEz - IC9Gb250RmlsZTIgOTkgMCBSID4+CmVuZG9iagoxMDIgMCBvYmoKWyAyNzggMCAwIDAg - MCAwIDAgMCAwIDAgMCAwIDI3OCAwIDI3OCAyNzggNTU2IDU1NiAwIDAgNTU2IDAgNTU2 - IDU1NiA1NTYgMAowIDI3OCAwIDU4NCAwIDU1NiAwIDY2NyAwIDcyMiA3MjIgNjY3IDYx - MSAwIDAgMjc4IDAgMCA1NTYgODMzIDcyMiAwIDY2NyAwCjcyMiA2NjcgNjExIDcyMiA2 - NjcgMCAwIDAgMCAwIDAgMCAwIDAgMCA1NTYgMCA1MDAgNTU2IDU1NiAyNzggNTU2IDU1 - NiAyMjIKMCA1MDAgMjIyIDgzMyA1NTYgNTU2IDU1NiAwIDMzMyA1MDAgMjc4IDU1NiAw - IDcyMiA1MDAgNTAwIDUwMCAwIDAgMCAwIDAgMAowIDAgMCAwIDAgMCAwIDAgMCAwIDAg - MCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAw - CjAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAg - MCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAKMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAw - IDAgMCAwIDAgMCA1MDAgXQplbmRvYmoKMzggMCBvYmoKPDwgL1R5cGUgL0ZvbnQgL1N1 - YnR5cGUgL1RydWVUeXBlIC9CYXNlRm9udCAvWkJYT0VQK0hlbHZldGljYSAvRm9udERl - c2NyaXB0b3IKMTAxIDAgUiAvV2lkdGhzIDEwMiAwIFIgL0ZpcnN0Q2hhciAzMiAvTGFz - dENoYXIgMjIyIC9FbmNvZGluZyAvTWFjUm9tYW5FbmNvZGluZwo+PgplbmRvYmoKMTAz - IDAgb2JqCjw8IC9MZW5ndGggMTA0IDAgUiAvTGVuZ3RoMSA4Njg0IC9GaWx0ZXIgL0Zs - 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 - pVjbU66bbL8ty7Q9UlZhG8ugvDHb6EwSB2x7ym6yPbBZyflFliLudwVwZMx2nywO2HZT - /3dtUgrujDTcGBGDm5WBrtuviOX7A8yDB2wDrnTbQmqIktbW7Vpm63K5bW0zA5g2ZvPK - zQ7YGjOO2RrkocdsUmSg0kjvJS4FcVFk2BzXIduUyAipcm0p3mZ3Ndqs1H/OfXfZclzX - 2GZmBXDvo/VTslz1GXeVBvCcMoYsCKgslkdEb8bj+EvSZyYuoGv73fvrMwkz7hizbSIx - sr9+SllagD0txdn2Z9RnbKZQSiGNwvwAtkk54k5xkThfnCpmi5liuugQU8QkMUEVp9Kp - YlRRKo1KpaLlrmJUoEoIhP8qZcs2mSDoZCGQwdMbECWuIxtExRDJXOlFAgNzICDAzYmr - qkxVcTP07tqab/jrUTJ7arK/+pHjnvyZ0Oq/i16G+/dZO/1FciRs7Zws/f9F+qqpfUPL - mv0ta860K99TnJ6+Hvqs4t+2ij57bVhot4+eWSMXyG/2exb29svS1+df4+yr8Z9x1thH - W5R2Xytul4tbnDWj0O5p6xhtl/pqxlqkFvl7Sef+Zk89bUc0yMWxtk6OVe/5hrE8cmf1 - 8ljNSruvjdUkFzfLYzXJYzXJYzVLzcpY2dmeJa3V8L9upOJhCmVuZHN0cmVhbQplbmRv - YmoKMTA0IDAgb2JqCjU2NzcKZW5kb2JqCjEwNSAwIG9iago8PCAvVHlwZSAvRm9udERl - c2NyaXB0b3IgL0FzY2VudCA3NzAgL0NhcEhlaWdodCA2ODQgL0Rlc2NlbnQgLTIzMCAv - RmxhZ3MgMzIKL0ZvbnRCQm94IFsxMCAtMjA5IDY1NSA3MzRdIC9Gb250TmFtZSAvQk5G - UEVKK0hlbHZldGljYS1Cb2xkIC9JdGFsaWNBbmdsZQowIC9TdGVtViAwIC9NYXhXaWR0 - aCAxNTAwIC9YSGVpZ2h0IDUxMyAvRm9udEZpbGUyIDEwMyAwIFIgPj4KZW5kb2JqCjEw - NiAwIG9iagpbIDI3OCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAw - IDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwCjAgMCAwIDAgMCA3MjIgMjc4IDAg - MCA2MTEgMCAwIDAgNjY3IDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgNTU2 - IDAKNTU2IDYxMSA1NTYgMCAwIDAgMjc4IDAgNTU2IDI3OCAwIDYxMSA2MTEgNjExIDAg - Mzg5IDU1NiAzMzMgNjExIDAgMCAwIDAgNTAwCl0KZW5kb2JqCjM5IDAgb2JqCjw8IC9U - eXBlIC9Gb250IC9TdWJ0eXBlIC9UcnVlVHlwZSAvQmFzZUZvbnQgL0JORlBFSitIZWx2 - ZXRpY2EtQm9sZCAvRm9udERlc2NyaXB0b3IKMTA1IDAgUiAvV2lkdGhzIDEwNiAwIFIg - L0ZpcnN0Q2hhciAzMiAvTGFzdENoYXIgMTIyIC9FbmNvZGluZyAvTWFjUm9tYW5FbmNv - ZGluZwo+PgplbmRvYmoKMSAwIG9iago8PCAvVGl0bGUgKFVudGl0bGVkKSAvQXV0aG9y - IChicmFuZG9uaCkgL0NyZWF0b3IgKE9tbmlHcmFmZmxlIFByb2Zlc3Npb25hbCkKL1By - b2R1Y2VyIChNYWMgT1MgWCAxMC41LjggUXVhcnR6IFBERkNvbnRleHQpIC9DcmVhdGlv - bkRhdGUgKEQ6MjAwOTEyMTYyMjQyMDlaMDAnMDAnKQovTW9kRGF0ZSAoRDoyMDA5MTIx - NjIyNDIwOVowMCcwMCcpID4+CmVuZG9iagp4cmVmCjAgMTA3CjAwMDAwMDAwMDAgNjU1 - MzUgZiAKMDAwMDA5NjU1OCAwMDAwMCBuIAowMDAwMDc3OTE1IDAwMDAwIG4gCjAwMDAw - MDM4NTEgMDAwMDAgbiAKMDAwMDA3Nzc1MiAwMDAwMCBuIAowMDAwMDAwMDIyIDAwMDAw - IG4gCjAwMDAwMDM4MzEgMDAwMDAgbiAKMDAwMDAwMzk1NiAwMDAwMCBuIAowMDAwMDc1 - NDAxIDAwMDAwIG4gCjAwMDAwMDczNDQgMDAwMDAgbiAKMDAwMDAwODE4OSAwMDAwMCBu - IAowMDAwMDEyNzk0IDAwMDAwIG4gCjAwMDAwMTM4ODUgMDAwMDAgbiAKMDAwMDAwNjIy - MyAwMDAwMCBuIAowMDAwMDA3MzI0IDAwMDAwIG4gCjAwMDAwMDgyMDkgMDAwMDAgbiAK - MDAwMDAwOTMwMCAwMDAwMCBuIAowMDAwMDEzOTA1IDAwMDAwIG4gCjAwMDAwMTQ5OTYg - MDAwMDAgbiAKMDAwMDAwNTQwMiAwMDAwMCBuIAowMDAwMDA2MjAzIDAwMDAwIG4gCjAw - MDAwMTYxMjcgMDAwMDAgbiAKMDAwMDAxNjg4NCAwMDAwMCBuIAowMDAwMDE2OTA0IDAw - MDAwIG4gCjAwMDAwMTc5OTUgMDAwMDAgbiAKMDAwMDAxMDA5NyAwMDAwMCBuIAowMDAw - MDExMTg4IDAwMDAwIG4gCjAwMDAwMDkzMjAgMDAwMDAgbiAKMDAwMDAxMDA3NyAwMDAw - MCBuIAowMDAwMDExMjA4IDAwMDAwIG4gCjAwMDAwMTE5NTMgMDAwMDAgbiAKMDAwMDAw - NDI5MSAwMDAwMCBuIAowMDAwMDA1MzgyIDAwMDAwIG4gCjAwMDAwMTUwMTYgMDAwMDAg - biAKMDAwMDAxNjEwNyAwMDAwMCBuIAowMDAwMDExOTczIDAwMDAwIG4gCjAwMDAwMTI3 - NzQgMDAwMDAgbiAKMDAwMDA3NzcxNSAwMDAwMCBuIAowMDAwMDg5OTM3IDAwMDAwIG4g - CjAwMDAwOTYzNzYgMDAwMDAgbiAKMDAwMDA3Njg1MCAwMDAwMCBuIAowMDAwMDYyMTU4 - IDAwMDAwIG4gCjAwMDAwNjYwNDMgMDAwMDAgbiAKMDAwMDA3MDgyNCAwMDAwMCBuIAow - MDAwMDE4MDE1IDAwMDAwIG4gCjAwMDAwMjA5ODQgMDAwMDAgbiAKMDAwMDA3MzcyNCAw - MDAwMCBuIAowMDAwMDY2MDY0IDAwMDAwIG4gCjAwMDAwNzAxMTUgMDAwMDAgbiAKMDAw - MDA3NDQ0OSAwMDAwMCBuIAowMDAwMDM4MzMwIDAwMDAwIG4gCjAwMDAwNDE1NDEgMDAw - MDAgbiAKMDAwMDA0NTAyMiAwMDAwMCBuIAowMDAwMDQ4OTA3IDAwMDAwIG4gCjAwMDAw - NzIyNzQgMDAwMDAgbiAKMDAwMDA1OTQ0OSAwMDAwMCBuIAowMDAwMDYyMTM3IDAwMDAw - IG4gCjAwMDAwNDg5MjggMDAwMDAgbiAKMDAwMDA1MjgxMyAwMDAwMCBuIAowMDAwMDcx - NTQ5IDAwMDAwIG4gCjAwMDAwMzU4MzYgMDAwMDAgbiAKMDAwMDAzODMwOSAwMDAwMCBu - IAowMDAwMDcyOTk5IDAwMDAwIG4gCjAwMDAwNDE1NjIgMDAwMDAgbiAKMDAwMDA0NTAw - MSAwMDAwMCBuIAowMDAwMDU1NTQzIDAwMDAwIG4gCjAwMDAwNTk0MjggMDAwMDAgbiAK - MDAwMDAyMTAwNSAwMDAwMCBuIAowMDAwMDI0ODkwIDAwMDAwIG4gCjAwMDAwNzYxMjUg - MDAwMDAgbiAKMDAwMDAyNDkxMSAwMDAwMCBuIAowMDAwMDMxOTA5IDAwMDAwIG4gCjAw - MDAwNTI4MzQgMDAwMDAgbiAKMDAwMDA1NTUyMiAwMDAwMCBuIAowMDAwMDMxOTMwIDAw - MDAwIG4gCjAwMDAwMzU4MTUgMDAwMDAgbiAKMDAwMDA3MDEzNiAwMDAwMCBuIAowMDAw - MDcwODA0IDAwMDAwIG4gCjAwMDAwNzA4NjEgMDAwMDAgbiAKMDAwMDA3MTUyOSAwMDAw - MCBuIAowMDAwMDcxNTg2IDAwMDAwIG4gCjAwMDAwNzIyNTQgMDAwMDAgbiAKMDAwMDA3 - MjMxMSAwMDAwMCBuIAowMDAwMDcyOTc5IDAwMDAwIG4gCjAwMDAwNzMwMzYgMDAwMDAg - biAKMDAwMDA3MzcwNCAwMDAwMCBuIAowMDAwMDczNzYxIDAwMDAwIG4gCjAwMDAwNzQ0 - MjkgMDAwMDAgbiAKMDAwMDA3NDQ4NiAwMDAwMCBuIAowMDAwMDc1MzgxIDAwMDAwIG4g - CjAwMDAwNzU0MzcgMDAwMDAgbiAKMDAwMDA3NjEwNSAwMDAwMCBuIAowMDAwMDc2MTYy - IDAwMDAwIG4gCjAwMDAwNzY4MzAgMDAwMDAgbiAKMDAwMDA3Njg4NyAwMDAwMCBuIAow - MDAwMDc3Njk1IDAwMDAwIG4gCjAwMDAwNzc4MzUgMDAwMDAgbiAKMDAwMDA3ODA0MSAw - MDAwMCBuIAowMDAwMDc3OTYzIDAwMDAwIG4gCjAwMDAwNzgxMTkgMDAwMDAgbiAKMDAw - MDA4OTE4OCAwMDAwMCBuIAowMDAwMDg5MjExIDAwMDAwIG4gCjAwMDAwODk0MzIgMDAw - MDAgbiAKMDAwMDA5MDExNCAwMDAwMCBuIAowMDAwMDk1ODgzIDAwMDAwIG4gCjAwMDAw - OTU5MDUgMDAwMDAgbiAKMDAwMDA5NjEzMyAwMDAwMCBuIAp0cmFpbGVyCjw8IC9TaXpl - IDEwNyAvUm9vdCA5NiAwIFIgL0luZm8gMSAwIFIgL0lEIFsgPDE3ZDJjNDJhMzE3NDJh - NTgyMWQxNTc1OWQwMGFhYWE5Pgo8MTdkMmM0MmEzMTc0MmE1ODIxZDE1NzU5ZDAwYWFh - YTk+IF0gPj4Kc3RhcnR4cmVmCjk2NzczCiUlRU9GCjEgMCBvYmoKPDwvQXV0aG9yIChi - cmFuZG9uaCkvQ3JlYXRpb25EYXRlIChEOjIwMDkxMTIwMDExMzAwWikvQ3JlYXRvciAo - T21uaUdyYWZmbGUgUHJvZmVzc2lvbmFsIDUuMi4xKS9Nb2REYXRlIChEOjIwMDkxMjE2 - MjI0MjAwWikvUHJvZHVjZXIgKE1hYyBPUyBYIDEwLjUuOCBRdWFydHogUERGQ29udGV4 - dCkvVGl0bGUgKGhlYWRlcl9wYXJzaW5nX2Zsb3djaGFydC5ncmFmZmxlKT4+CmVuZG9i - agp4cmVmCjEgMQowMDAwMDk5MDczIDAwMDAwIG4gCnRyYWlsZXIKPDwvSUQgWzwxN2Qy - YzQyYTMxNzQyYTU4MjFkMTU3NTlkMDBhYWFhOT4gPDE3ZDJjNDJhMzE3NDJhNTgyMWQx - NTc1OWQwMGFhYWE5Pl0gL0luZm8gMSAwIFIgL1ByZXYgOTY3NzMgL1Jvb3QgOTYgMCBS - IC9TaXplIDEwNz4+CnN0YXJ0eHJlZgo5OTI5OQolJUVPRgo= - - QuickLookThumbnail - - TU0AKgAAEWCANaBNYUwUUgCEQmFQuGQ2HQ+IRGJROKRWLReMRmNRuORWBtZryGDx2SQ4 - pSeSymVSuWS2XROPyFrikpEYWgBhNR6gB9vF1AAGA8FgB0ul5gAIB8XAANPNkgBtP8OA - AMgl8gByOd7AAIhIHgAMCsZgASBECABXWkAScpS+3W+4XG5QiYyKTk4APh+WcAPx8X17 - wgCAWjvQAA2kAR+AB6XoAP/FgB+4+gAwC32gUAEQi0q61yi56HRaPSQ66zO2Qm/tNdL4 - AOsIiEACkL4ttOB/VwFvoAPB0PCEAkBgAFCMVAAaB8MQ/O5+26XodHpS3TzSUOpuNwAN - 5wOziBbLv5/2d/AIAgAEgQGAACP6dgEFV98PDvAgQUuy3yE83U9P/P/ACKOq1K/L+xbF - scADNoQfACM2Bi/LyzACAICEGOBBr1ggBj9M4tT+wDEKSHlEgAHvE4AAnFT2QpESJJia - JihSE4TBMABuHW4YYBEoZqmyeLNKuAAAqGDIVgoABzGs7x4niyYPAeyZ5HurZ+ghGwYB - mEoAF+WzPRBF0wonEh5LyfC/gfNIAHfNgAApN8WQ7MQAOqHgTg6ABwytNwFPODIOAmAB - xm+dAAHyfEynqfoBRSB8kHme5/qQBTJn5SCEAwEQABKDL1v40E51ChUyTMv83yQAVUxN - FEmyBU84zm6olCEHy8gRCwEQi9TNn4vcFH4wx4MjCjNsVA6EwpOQEAQs9PufUUxVJM9T - ThVNGIdE7A1bN04WShrFngcZzgAecHKoDIKvYl0B1A6VnWhEVpTPblUVUi1sgBbdX28h - DDG8aZxskBChg6EoPQVdaBpkkaOHVhwAAtiKSzBeDoH1i7eng4FXgEfTvGWYpsL6BThn - seajgICVAg2DwYrICyz3xbYMZoiZ6ZuAAD50AAC56kqPoNhiL1IU+igAM+kYrpSJHFpo - AArqD0ASBKWH/qwAHPrIAHrrjiAUBSHmBsQAB/soAA5tGfoHoKLatSR17hcmTqYDQNal - qml7yhNesWdm/MOBrEAXwaN7c1+42WzYHcW/+gIMiXDbgdec53wah7873Fgdr2wIvCK/ - s3ZiIQKhFlr6xsFAZBe9ImfvXcPyfA8FwnIavyUFdNzURccgqHcjuOdAOAE0q+hW+ABz - AAd1r/Ooib5lloABdmZMoQh5lwDHCbYAH0ArznOcNxgKCgMsAhAQgmxZ1H9sALg5LYQg - oze67t1jJdf2/ZAByyF9/ybiXlOMTE7xoT/nKPCeIRN47yXltfIeOWCAAANwTQYOYAAx - xkqFAwBpRg9AFggPQO07wBwIHDAOBVPAFnREKggOWCUFH7EKdcZN/LgXOOwdw4qASooC - QGeCoYdY5E6DbgsAcBYBgADtHeVcBwF3ygZAoV8EIIG7QMcY8whcLYXgbIQsA148DAmC - PQBAxA8hwE/H6T0AAAwMp4AkAw9cK4tQTi5DEhsM4cOGf47ppcBBzR/hyAACUgy8jqHE - 1gfx5x7DwMMPcdZRwDASaoA0DT8AImbjw7cb0m0kyABkB54Q4gAmyAYPYdq+R4JAAEBF - 8oBh+k7HeO4rYEwNNUbmewAJZwPAvByegfY6Ytx2Ii4aLTaCpv2gIPaZSqzAoqUCsAn4 - 5x3mRAGedrY+0hocKABECxSHRD5nAAAd045BSEHHOc9DHQAD+AKBJBQBVJD4Uk1Iy55G - 5TWi8sAww/QGFDAcBlTQ+x2wujpMIikWgJgFMCNschfwLgqBYxB1aYYCEKnGO4x7V5nE - bnAVei6KUVgGpFFkcI2nuDzMMPkAwETiAOPWAUAZkwEj8NyOYehOzLmIn6bkAoBjzj+A - QuknswKC0GIlHMC6gWNGLAQBSOMPG1uPIbR9w1GyJUdnFOSjdIokEOjnBQcwzRhAAGWN - so4EQNMHAqBFqg/R1sihccsDwIARmzBFSyFkEai1GIhV+OrrKKkRqpRpFZCqsUfq3SMi - Uf4LOGIkPuyDPGfEWADZVuj9a+ELjwMazgAAe2fhjYEilg1JO6eTYmrpcK/WZJatMAAw - 7YAACLbO0NUXekZo+zcwzNDl1cNHYyy9rLhEvtERu1Z0Lj3DuUSm4pGhv3PbO2lnplzR - XJuXdcjdzSMi1u4/cyYM7wGjsqed+l2LzEau0Ri61572R9ts0IjV6723zqgQJthGXDSb - G8AAEd/b6X/Whekh7hmuE7shNh/lvsAYLQDgIhWBGuw/um1truE8FEVt1RmeZLrxmVPX - gyg2AsIE7wlZMhLhplFbwtYoiLJ3JjpHDCMCCFgGgCO8OMfj5QJgGUkAUBDVAEj/mwUc - y4GQInrZOUd/WIJhXFxHGtq4BYbJyIZiiZeK7UkMZOO9Ew7HJoNncBICJw11TiHOcAfo - BChgNeEiYfhV5uJ4H+PfJUNsmR2uLhmH49Bz0mGyN1yYAwEKMHMOGs9aWngaK+CgEaeM - U2SMvhchA2hfPRHAAJJACh9G5A2Cilg4BpuTAoB6boBAE5tHWd4foCzzj0AC3YFYIDEZ - LzvMi99rgB650hIWQ45x/NUAIPc7zDjeAFAOYsBoHwVgABDJfDWFCdtNkONHagAAmbXc - AYgd446TDxHyWcAyGz0EJHANmCzOThgbBgTdmBCHbsXN5h28utcA3vqxHiLE0GsZcPYA - g3g+B2U8AWWcBDEn5FnwOoacLU5bNz1ycN/Q5hvPbAMAc9Y+shGCMuPmMKDmqAZAyhY/ - WSdsgAvlvRF1xd7uviwRrhNWIsLWIXyTWhCB1DRF6AAag9F0gcAeYYdA8z1gtByUuvHM - 25v65PyhEOAuVmT5aRHl84eYr2IbzTOxLusGI6X0xAGDiE9PhuQrqZV+qrXIjhmx2HLL - RwPX13rx/uwEM7Fb613Z289w7idLuZD6sDo8AAADvgwAcyft3rvZ0O+1Hr1DCYXiPEmk - 8WRHyC0PK+RND5Ovvja/x28v5guXmrNOvGr6UAALvUVG8/6AuHoiFYFABdwWoAAre19V - 5wktroAHQqxD/EN7yLR4YcT9wz+ua959w212zcVvcyxmhYuNrvh67tQ3nvsmW4v64ZDi - LHx7FyA7WS3eTdeTfJmH8tycP4Eu3wn88llrk2ZcVeP7+lWaMfVItcD8JLMO4C+wdihs - f4IU/oNydu+66y82v2HuiWZyxmMOxsUExyRSx4Z4x+PQ4yyIKoyO/KoIgo66h8Z2gSwe - aueS/bAcI0/gTaVewmsMnCsQpCxZASRMHcNyhIhMAaM2HOGkkOn+eEWEPWAESmeUAkMm - g8BQkEH+lOuK/+PQZ8AWRWyoIXAI+4gc+8ISggHCZ4H0KuzAkEzGjEzMzQzUMOzaHuze - K4AsTwHiHTA6i4vXBAeEAWZ2dwzKL6XmH+Z2PoO9BM+gIjBSy4Q2PWACe836PXCisOq1 - BgyyiyHLCyACHuMujSSAjYSQHwHGPqAqSQANAsAIHwMCH2RaASAgpZDWhcgJCYf0H0Ha - HAAAz+0C0GSS0MK40QAq0UAABOBEKnANCrARA4gkoSrIZCRMACMWH+AEeFE2eEAsAmLO - HQHKJ2A6BwB2AAA8QWtWtXDgeGTUHEGGFkAAGaHceEBQBoJGHsMuBCU4ZzBIb+wmgSw7 - EQowTeM2GsGoOAAUH+MMH42OMYHUKuAuBXCOMUUkRUbBBeUC0lF8gmK+GwGYG+XIHiy4 - AYA2AuAAHkHgN4ActSzaAWAqS21IM2i0gI+m+0am14kQ2A2EAA2IZ4AYUYkoksM2cMo+ - GnJoAAG7JuAACRJ0eHEIHwlyL6H6POH2PGPQHwMMAIAqPWHwUuPYc2AxKTJtJwgAuAGz - KqAABhKwAAA/K2cAPOGwGeYCAo58L6H4POH0HuL+AIAUkwHwmwAGAebs5COG+mVIFpLs - 2s2wBBL012LygsG4HcbAAoAMmwHwHsMCy4MQBSA86OIQ4SKKmAw6GTMkXoAABRL2HsAC - UYe8OGPEMmADMKMeAancQ4UkjAL+lYTwHKGyGqToveW23hMolecmmkME38Ly4CZ4AgLO - AYm4m8ZiVYSaK4AipYXw9gH6nIACTUAIWuHmH+M2pY3iPaXIMML6AYMQU4pYtWHJO25L - CnNgTePWHkUuHqHWmAHCHUUYBCA0OGMWnqASpYAcAoQsAKH6o8nIagXSW2eO+2j4H4y4 - HU1cSHLajGMQgBCi/iu9Mo5IduQ4M2HqHwJ2AQAcQtEeOAHuACM2pgMvFGPWHgHOf+A6 - NkHyoHNavsqkIRNeYwVew6XvOAVcW6RarzDaLyHoOAHOGcrGG+AOncHoHYKuA0PAAAGw - HGeECgCkBuMyIRGu/MX6Zw9gVe4eIvHgpBIPBi2edugAj4IzQQjwVeq8+SHeO0GiHIKu - AMRaHuHoN4LycmH2AhCOBuBasxSUgiwFRSN5RWssWxRdMoX4Ia9WItSXRmIcwzSeThSi - IdSm/w/ObecQdyh2IhS4dfS88pSYJZJC+AIjTtMow6ZlOCX3RiIi/0auJe/Gbs8hUIa7 - Sg11UTEUcK/QkDS0IRUiMnUmIpVEw2/Ess9FU07cXzU9RhCiVC9XVQJ2kGnctPVaJWgM - gAjxS6TgvdRMtuIwVIY0OAmM8K6sb1T+7CnC2lGoA8YO98LgcNKqGyAABFXQABIRWgIJ - ROI2uA3m8fUqI1Xg/IOgE9XwAABzX2NnWkb09dT9XmdZW2IZYIJKGpYQuiKm/c1tWivg - IzYMRDYjCvYELeo+hkdfD4+tUwI5YmQBY9IS8dYsnIIVWM2fBKZ9YYIrVuLc/7Y4uNYq - +RUEI7ZAIdYuITZMd9HXD3ZTBPUpZmIodIWOQdENYpFNZevjZiaXZBZqITZuL+HbTIIQ - ADKOTgAKHoKuAgA6KmAGauZuOBY1S/RnTCGmAAGcHCy4m4fLHwKOAUAgKGWAN4A4BqJu - 6PUvYcJJaaOlaZaUIrWqnW/qkGc2HfOoAKH2QMi8HnQeKBLEZ4MwcGeFZRQ3Ac4SayXG - UoMmHmV6L6AOM2AObmHiHgy4AEA0NkAEHmlOACASiQAIAorqASHsmBYBYLb6Yrb5aAI2 - OyO0BDd4jW10IeH4J+G4HUbABIA0w+IbCmuAw6tgGGAAAvegs8BqBgeQH4aodUb2dKMw - H4dEL8MWP1e4PXFLRLXbX9aTdw8PdqInZA0e5JVUzIIygWb+gS+3RkmCGqGQGheeBQc2 - G6G2KuA+AuMuj+jCH3TYAgBIABTgYPbvfLYevVfU8tgjZ+mCJXWJMpUOIjfkO9fpJLbF - gqJdgavvY7gnWFhKIWeOF1hUAACVhaLdgvffhRc2eTg6bxgor2JbhFXdfPhA889wOaIs - ePXKAABXiKI2YpUHSca7PxcANzhoTVfrZW/BVGsEnJZyIjZdbxZphOTEtWOaCMBUQsIA - v26/AAEwcCwA93+AAA/QHCBEEAEAHg9HuAHc63yABKMwyAHa7AOABoLQ8AFdKQAUpZDJ - dL5hLnpMwA8psAAFOQAD54AATP5jQaFQ6IAHLRwAG6VRZi1qc1hTURTTKZR3LSaXVK1W - 65RG/XwA5LEAB7ZZRKpYUgA+HW4wA6QCDYLLwYEIY86u+H7I4ICAABAA6AA630GAAKQ8 - DLOrpXLa7Lm5kQAI8oAADl8fmaFVqwG67T6hUs1L3NpQA/9Ro9Vq5c7tcAJm9AA19oAH - 9twAZN1sHE3AA2nA4gAAwyHQA9nU87/awA9Xe8QAEBPH3s5n2AA4NxqAA9fgAhPAABt4 - wAK/NXXf6QAEfZrPd6Xf6/bXNBUqn7vx+f0AHz/QAWUAAAKsBgAcRkGcigFIuf4ApGcZ - 1AMAAeBUfwAGCZ6NhKCyFnmAwNAAF4XJO7wAFTEwACnFK/gIwD9xdF6mqe+0YRpGqqJS - xi0gAfh8Nkeh8HwAB9n4wAAuWCAIMAeh4SCAgEMAgiGAZKbloZHDGrVG0tP2+rRS3L8t - SvMChx1MczMygIAADwEAAAMAAAABAEUAAAEBAAMAAAABAE4AAAECAAMAAAAEAAASGgED - AAMAAAABAAUAAAEGAAMAAAABAAIAAAERAAQAAAABAAAACAESAAMAAAABAAEAAAEVAAMA - AAABAAQAAAEWAAMAAAABAdoAAAEXAAQAAAABAAARWAEcAAMAAAABAAEAAAE9AAMAAAAB - AAIAAAFSAAMAAAABAAEAAAFTAAMAAAAEAAASIodzAAcAAAP4AAASKgAAAAAACAAIAAgA - CAABAAEAAQABAAAD+GFwcGwCAAAAbW50clJHQiBYWVogB9kADAAKAAoANAAVYWNzcEFQ - UEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPbWAAEAAAAA0y1hcHBsmnD7ADeQ0zT2 - oHnmPK06CwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOclhZWgAAASwAAAAU - Z1hZWgAAAUAAAAAUYlhZWgAAAVQAAAAUd3RwdAAAAWgAAAAUY2hhZAAAAXwAAAAsclRS - QwAAAagAAAAOZ1RSQwAAAbgAAAAOYlRSQwAAAcgAAAAOdmNndAAAAdgAAAAwbmRpbgAA - AggAAAA4ZGVzYwAAAkAAAABoZHNjbQAAAqgAAAECbW1vZAAAA6wAAAAoY3BydAAAA9QA - AAAkWFlaIAAAAAAAAHkPAAA/lwAAAsFYWVogAAAAAAAAWMYAAKyuAAAW7VhZWiAAAAAA - AAAlAAAAE9sAALl2WFlaIAAAAAAAAPL4AAEAAAABHeRzZjMyAAAAAAABDaEAAAZ6///y - FQAACGQAAP1W///7Qv///XQAAAQlAAC7jWN1cnYAAAAAAAAAAQHNAABjdXJ2AAAAAAAA - AAEBzQAAY3VydgAAAAAAAAABAc0AAHZjZ3QAAAAAAAAAAQAA0XQAAAAAAAEAAAAA0XQA - AAAAAAEAAAAA0XQAAAAAAAEAAG5kaW4AAAAAAAAAMAAAo4AAAFbAAABKAAAAnAAAACWX - AAASmwAAT0AAAFOAAAIzMwACMzMAAjMzZGVzYwAAAAAAAAAOU2NlcHRyZSBYMjRXRwAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABtbHVjAAAAAAAAABIAAAAMbmJOTwAAABoA - AADocHRQVAAAABoAAADoc3ZTRQAAABoAAADoZmlGSQAAABoAAADoZGFESwAAABoAAADo - emhDTgAAABoAAADoZnJGUgAAABoAAADoamFKUAAAABoAAADoZW5VUwAAABoAAADocGxQ - TAAAABoAAADocHRCUgAAABoAAADoZXNFUwAAABoAAADoemhUVwAAABoAAADocnVSVQAA - ABoAAADoa29LUgAAABoAAADoZGVERQAAABoAAADobmxOTAAAABoAAADoaXRJVAAAABoA - AADoAFMAYwBlAHAAdAByAGUAIABYADIANABXAEcAAG1tb2QAAAAAAABOFAAAJAQAAABF - w6htgAAAAAAAAAAAAAAAAAAAAAB0ZXh0AAAAAENvcHlyaWdodCBBcHBsZSwgSW5jLiwg - MjAwOQA= - - ReadOnly - NO - RowAlign - 1 - RowSpacing - 36 - SheetTitle - Canvas 1 - SmartAlignmentGuidesActive - YES - SmartDistanceGuidesActive - YES - UniqueID - 1 - UseEntirePage - - VPages - 1 - WindowInfo - - CurrentSheet - 0 - ExpandedCanvases - - - name - Canvas 1 - - - FitInWindow - - Frame - {{94, 4}, {1714, 1174}} - ListView - - OutlineWidth - 142 - RightSidebar - - ShowRuler - - Sidebar - - SidebarWidth - 120 - VisibleRegion - {{0, -16}, {1187.25, 766.937}} - Zoom - 1.3299663066864014 - ZoomValues - - - Canvas 1 - 0.0 - 1 - - - - saveQuickLookFiles - YES - - diff --git a/openflow/doc/of-spec/make_latex_input.pl b/openflow/doc/of-spec/make_latex_input.pl deleted file mode 100755 index 7a1c48b7..00000000 --- a/openflow/doc/of-spec/make_latex_input.pl +++ /dev/null @@ -1,117 +0,0 @@ -#!/usr/bin/perl -w - -use strict; - -sub handle_comment { - my ($comment) = @_; - - my $next_line; - do { - $next_line = ; - chomp $next_line; - $comment .= $next_line . "\n"; - } until ( $next_line =~ m/\*\// ); - - return $comment; -} - -sub handle_define { - my ( $var, $val ) = @_; - open( OUTFILE, ">define/$var" ); - print OUTFILE $val; - close(OUTFILE); -} - -sub handle_multiline { - my ( $dir, $filename, $line_orig, $last_comment ) = @_; - - open( OUTFILE, ">$dir/$filename" ); - - #print OUTFILE "\\scriptsize\n"; - print OUTFILE "\\begin{footnotesize}\n"; - print OUTFILE "\\begin{verbatim}\n"; - - #print OUTFILE "\\begin{lstlisting}[frame=htb]{$filename}\n"; - print OUTFILE $last_comment; - print OUTFILE $line_orig; - my $next_line; - do { - - $next_line = ; - chomp $next_line; - - print OUTFILE $next_line . "\n"; - - } until ( $next_line eq '};' ); - - # add assertion line for structs - if ( $dir eq 'struct' ) { - $next_line = ; - print OUTFILE $next_line; - } - print OUTFILE "\\end{verbatim}\n"; - - #print OUTFILE "\\end{lstlisting}\n"; - print OUTFILE "\\end{footnotesize}\n"; - close(OUTFILE); -} - -#---------------------------------------- -use File::Path; - -foreach my $type ( 'enum', 'struct', 'define' ) { - if ( -d $type ) { - rmtree($type); - } - mkdir $type; -} - -open( INFILE, "<../../include/openflow/openflow.h" ); - -my $last_comment; -while () { - - # Good practice to store $_ value because - # subsequent operations may change it. - my ($line) = $_; - my $line_orig = $line; - my @line_split = split ' ', $line; - - if ( not defined( $line_split[0] ) ) { - $last_comment = ''; - } - - # Handle single-line comment - elsif ( $line =~ m/^\/\*.*\*\// ) { - $last_comment = $line; - - #print $last_comment; - } - - # Handle multi-line comment - elsif ( $line =~ m/^\/\*/ ) { - $last_comment = handle_comment($line_orig); - - #print $last_comment; - } - - # Handle define - elsif ( $line_split[0] eq '#define' ) { - handle_define( $line_split[1], $line_split[2] ); - $last_comment = ''; - } - - # Handle enum - elsif ( $line_split[0] eq 'enum' ) { - handle_multiline( 'enum', $line_split[1], $line_orig, $last_comment ); - $last_comment = ''; - } - - # Handle struct - elsif ( $line_split[0] eq 'struct' ) { - handle_multiline( 'struct', $line_split[1], $line_orig, $last_comment ); - $last_comment = ''; - } - -} -print "completed\n"; diff --git a/openflow/doc/of-spec/openflow-spec-v1.0.0.tex b/openflow/doc/of-spec/openflow-spec-v1.0.0.tex deleted file mode 100644 index 56dca85c..00000000 --- a/openflow/doc/of-spec/openflow-spec-v1.0.0.tex +++ /dev/null @@ -1,418 +0,0 @@ -\documentclass[10pt]{article} -\usepackage{amsmath} -\usepackage{listings} -\usepackage{hyperref} -\usepackage{fancyhdr} -\usepackage{graphicx} -\usepackage{tabularx} -\usepackage{color} - -\hbadness=10000 % No "underfull hbox" messages - -\begin{document} - -%\lstset{language=C} - -% Define the OpenFlow version here -\newcommand{\ofversion}{1.0.0} - -\pagestyle{fancy} -\fancyhead{} -\lhead{OpenFlow Switch Specification} -%\chead{DO NOT BUILD A SWITCH FROM THIS SPECIFICATION!} -\rhead{Version \ofversion} -\renewcommand{\headrulewidth}{0.4pt} -\renewcommand{\footrulewidth}{0.4pt} - -\fontfamily{cmr} % what about cmss? -\selectfont - -\newcommand{\qosupd}[1]{{#1}} -%\newcommand{\qosupd}[1]{{\color{blue} #1}} - -\title{OpenFlow Switch Specification} -\author{Version \ofversion{} ( Wire Protocol \input{define/OFP_VERSION})} -\date{\today} -\maketitle - -\section{Introduction} -This document describes the requirements of an OpenFlow Switch. We recommend that you read the latest version of the OpenFlow whitepaper before reading this specification. The whitepaper is available on the OpenFlow Consortium website (\url{http://OpenFlowSwitch.org}). This specification covers the components and the basic functions of the switch, and the OpenFlow protocol to manage an OpenFlow switch from a remote controller. -\\\\ -Version 1.0 of this document will be the first for which official vendor support is expected. Versions before 1.0 will be marked ``Draft", and will include the header: ``Do not build a switch from this specification!" We hope to generate feedback prior to Version 1.0 from switch designers and network researchers, so that the set of features defined in Version 1.0 enables production deployments on a variety of vendor hardware. - -\begin{figure}[htbp] -\centering -\includegraphics[height=2.5in]{figure_flow_table_secchan.png} -\caption{An OpenFlow switch communicates with a controller over a secure connection using the OpenFlow protocol.} -\label{fig:flow table and controller} -\end{figure} - -\section{Switch Components} -An OpenFlow Switch consists of a \emph{flow table}, which performs packet lookup and forwarding, and a \emph{secure channel} to an external controller (Figure \ref{fig:flow table and controller}). The controller manages the switch over the secure channel using the OpenFlow protocol. -\\\\ -The flow table contains a set of flow entries (header values to match packets against), activity counters, and a set of zero or more actions to apply to matching packets. All packets processed by the switch are compared against the flow table. If a matching entry is found, any actions for that entry are performed on the packet (e.g., the action might be to forward a packet out a specified port). If no match is found, the packet is forwarded to the controller over the secure channel. The controller is responsible for determining how to handle packets without valid flow entries, and it manages the switch flow table by adding and removing flow entries. -\\\\ -Flow entries may forward packets to one or more OpenFlow ports. In general, these are physical ports, but the protocol does not preclude abstractions like port aggregations or VLAN traffic on a port appearing as an OpenFlow port. OpenFlow ports have limited state such as ``up'', ``down'' and whether spanning tree flood packets should be forwarded out the port. Additional configuration of ports may handled by the OpenFlow configuration protocol. There are several OpenFlow virtual ports used to indicate, for example, flooding or the ingress port (see \ref{ft:actions}). - -\section{Flow Table} -This section describes the components of flow table entries and the process by which incoming packets are matched against flow table entries. - -\begin{table}[hbp] -\centering -\begin{tabular}{|c|c|c|} -\hline -Header Fields & Counters & Actions\\ -\hline -\end{tabular} -\caption{A flow entry consists of header fields, counters, and actions.} -\label{table:flow entry} -\end{table} - -Each flow table entry (see Table \ref{table:flow entry}) contains: -\begin{itemize} -\item \textbf{header fields} to match against packets -\item \textbf{counters} to update for matching packet -\item \textbf{actions} to apply to matching packets -\end{itemize} - -\subsection{Header Fields} -\begin{table}[hbp] -\centering -\footnotesize -\begin{tabularx}{\textwidth}{ |X|X|X|X|X|X|X|X|X|X|X|X| } -\hline -Ingress Port & -Ether source & -Ether dst & -Ether type & -VLAN id & -VLAN priority & -IP src & -IP dst & -IP proto & -IP ToS bits & -TCP/ UDP src port & -TCP/ UDP dst port -\\ -\hline -\end{tabularx} -\caption{Fields from packets used to match against flow entries.} -\label{table:header fields} -\end{table} - -Table \ref{table:header fields} shows the header fields an incoming packet is compared against. Each entry contains a specific value, or ANY, which matches any value. If the switch supports subnet masks on the IP source and/or destination fields, these can more precisely specify matches. The fields in the OpenFlow 12-tuple are listed in Table \ref{table:header fields} and details on the properties of each field are described in Table \ref{table:header field details}. -\\\\ -\begin{table}[hbp] -\centering -\footnotesize -\begin{tabularx}{\textwidth}{ |X|X|X|X| } -\hline Field & Bits & When applicable & Notes \\ -\hline Ingress Port & (Implementation dependent) & All packets & Numerical representation of incoming port, starting at 1. \\ -\hline Ethernet source address & 48 & All packets on enabled ports & \\ -\hline Ethernet destination address & 48 & All packets on enabled ports & \\ -\hline Ethernet type & 16 & All packets on enabled ports & An OpenFlow switch is required to match the type in both standard Ethernet and 802.2 with a SNAP header and OUI of 0x000000. The special value of 0x05FF is used to match all 802.3 packets without SNAP headers. \\ -\hline VLAN id & 12 & All packets of Ethernet type 0x8100 & \\ -\hline VLAN priority & 3 & All packets of Ethernet type 0x8100 & VLAN PCP field \\ -\hline IP source address & 32 & All IP and ARP packets & Can be subnet masked \\ -\hline IP destination address & 32 & All IP and ARP packets & Can be subnet masked \\ -\hline IP protocol & 8 & All IP and IP over Ethernet, ARP packets & Only the lower 8 bits of the ARP opcode are used \\ -\hline IP ToS bits & 6 & All IP packets & Specify as 8-bit value and place ToS in upper 6 bits. \\ -\hline Transport source port / ICMP Type & 16 & All TCP, UDP, and ICMP packets & Only lower 8 bits used for ICMP Type \\ -\hline Transport destination port / ICMP Code & 16 & All TCP, UDP, and ICMP packets & Only lower 8 bits used for ICMP Code \\ -\hline -\end{tabularx} -\caption{Field lengths and the way they must be applied to flow entries.} -\label{table:header field details} -\end{table}Switch designers are free to implement the internals in any way convenient provided that correct functionality is preserved. For example, while a flow may have multiple forward actions, each specifying a different port, a switch designer may choose to implement this as a single bitmask within the hardware forwarding table. - -\subsection{Counters} - -Counters are maintained per-table, per-flow, \qosupd{per-port and - per queue}. OpenFlow-compliant counters may be implemented in software and maintained by polling hardware counters with more limited ranges. -\\\\ -Table \ref{table:counters} contains the required set of counters. Duration refers to the time the flow has been installed in the switch. The Receive Errors field includes all explicitly specified errors, including frame, overrun, and CRC errors, plus any others. Counters wrap around with no overflow indicator. In this document, the phrase byte refers to 8-bit octets. -\begin{table}[!hbp] -\centering -\footnotesize -%\begin{tabularx}{\textwidth}{ |X|X| } -\begin{tabular}{ |l|c| } -\hline Counter & Bits \\ -\hline \multicolumn{2}{|c|}{Per Table} \\ -\hline Active Entries & 32 \\ -\hline Packet Lookups & 64 \\ -\hline Packet Matches & 64 \\ -\hline \multicolumn{2}{|c|}{Per Flow} \\ -\hline Received Packets & 64 \\ -\hline Received Bytes & 64 \\ -\hline Duration (seconds) & 32 \\ -\hline Duration (nanoseconds) & 32 \\ -\hline \multicolumn{2}{|c|}{Per Port} \\ -\hline Received Packets & 64 \\ -\hline Transmitted Packets & 64 \\ -\hline Received Bytes & 64 \\ -\hline Transmitted Bytes & 64 \\ -\hline Receive Drops & 64 \\ -\hline Transmit Drops & 64 \\ -\hline Receive Errors & 64 \\ -\hline Transmit Errors & 64 \\ -\hline Receive Frame Alignment Errors & 64 \\ -\hline Receive Overrun Errors & 64 \\ -\hline Receive CRC Errors & 64 \\ -\hline Collisions & 64 \\ -\hline \multicolumn{2}{|c|}{\qosupd{Per Queue}} \\ -\hline \qosupd{Transmit Packets} & \qosupd{64} \\ -\hline \qosupd{Transmit Bytes} & \qosupd{64} \\ -\hline \qosupd{Transmit Overrun Errors} & \qosupd{64}\\ -\hline -\end{tabular} -\caption{Required list of counters for use in statistics messages.} -\label{table:counters} -\end{table} - -\subsection{Actions} -\label{ft:actions} -Each flow entry is associated with zero or more actions that dictate how the switch handles matching packets. If no forward actions are present, the packet is dropped. Action lists for \emph{inserted} flow entries MUST be processed in the order specified. However, there is no packet output ordering guaranteed within a port. For example, an action list may result in two packets sent to two different VLANs on a single port. These two packets may be arbitrarily re-ordered, but the packet bodies must match those generated from a sequential execution of the actions. -\\\\ -A switch may reject a flow entry if it cannot process the action list in the order specified, in which case it should immediately return an unsupported flow error (see \ref{unsupported_flow}). Ordering within a port may vary between vendor switch implementations. -\\\\ -A switch is not required to support all action types --- just those marked ``Required Actions'' below. When connecting to the controller, a switch indicates which of the ``Optional Actions'' it supports. OpenFlow-compliant switches come in two types: \emph{OpenFlow-only}, and \emph{OpenFlow-enabled}. -\\\\ -OpenFlow-only switches support only the required actions below, while OpenFlow-enabled switches, routers, and access points may also support the \textbf{NORMAL} action. Either type of switch can also support the \textbf{FLOOD} action. -\\\\ -\textbf{Required Action:} \textit{Forward}. -OpenFlow switches must support forwarding the packet to physical ports and the following virtual ones: -\begin{itemize} -\item \textbf{ALL:} Send the packet out all interfaces, not including the incoming interface. -\item \textbf{CONTROLLER:} Encapsulate and send the packet to the controller. -\item \textbf{LOCAL:} Send the packet to the switchÕs local networking stack. -\item \textbf{TABLE:} Perform actions in flow table. Only for packet-out messages. -\item \textbf{IN\_PORT:} Send the packet out the input port. -\end{itemize} -\textbf{Optional Action:} \textit{Forward}. -The switch may optionally support the following virtual ports: -\begin{itemize} -\item \textbf{NORMAL:} Process the packet using the traditional forwarding path supported by the switch (i.e., traditional L2, VLAN, and L3 processing.) The switch may check the VLAN field to determine whether or not to forward the packet along the normal processing route. If the switch cannot forward entries for the OpenFlow-specific VLAN back to the normal processing route, it must indicate that it does not support this action. -\item \textbf{FLOOD:} Flood the packet along the minimum spanning tree, not including the incoming interface. -\end{itemize} -The controller will only ask the switch to send to multiple physical ports simultaneously if the switch indicates it supports this behavior in the initial handshake (see section \ref{cts:handshake}). -\\\\ -\textbf{\qosupd{Optional Action:}} \emph{\qosupd{Enqueue}}. \qosupd{The enqueue action forwards -a packet through a queue attached to a port. Forwarding behavior is -dictated by the configuration of the queue and is used to provide -basic Quality-of-Service (QoS) support (see section \ref{cts:qos}).} -\\\\ -\textbf{Required Action:} \emph{Drop}. A flow-entry with no specified action indicates that all matching packets should be dropped. -\\\\ -\textbf{Optional Action:} \emph{Modify-Field}. While not strictly required, the actions shown in Table \ref{table:field modify actions} greatly increase the usefulness of an OpenFlow implementation. To aid integration with existing networks, we suggest that VLAN modification actions be supported. - -\begin{table}[hbp] -\centering -\footnotesize -\begin{tabularx}{\linewidth}{ |X|X|X| } -\hline -Action & Associated Data & Description \\ -\hline -Set VLAN ID & -12 bits & -If no VLAN is present, a new header is added with the specified VLAN ID and priority of zero. - -If a VLAN header already exists, the VLAN ID is replaced with the specified value. \\ -\hline -Set VLAN priority & -3 bits & -If no VLAN is present, a new header is added with the specified priority and a VLAN ID of zero. - -If a VLAN header already exists, the priority field is replaced with the specified value. \\ -\hline -Strip VLAN header & -- & -Strip VLAN header if present. \\ -\hline -Modify Ethernet source MAC address & -48 bits: Value with which to replace existing source MAC address & -Replace the existing Ethernet source MAC address with the new value \\ -\hline -Modify Ethernet destination MAC address & -48 bits: Value with which to replace existing destination MAC address & -Replace the existing Ethernet destination MAC address with the new value. \\ -\hline -Modify IPv4 source address & -32 bits: Value with which to replace existing IPv4 source address & -Replace the existing IP source address with new value and update the IP checksum (and TCP/UDP -checksum if applicable). - -This action is only applicable to IPv4 packets. \\ -\hline -Modify IPv4 destination address & -32 bits: Value with which to replace existing IPv4 destination address & -Replace the existing IP destination address with new value and update the IP checksum (and TCP/UDP checksum if applicable). - -This action is only applied to IPv4 packets. \\ -\hline -Modify IPv4 ToS bits & -6 bits: Value with which to replace existing IPv4 ToS field & -Replace the existing IP ToS field. -This action is only applied to IPv4 packets. \\ -\hline -Modify transport source port & -16 bits: Value with which to replace existing TCP or UDP source port & -Replace the existing TCP/UDP source port with new value and update the TCP/UDP checksum. - -This action is only applicable to TCP and UDP packets.\\ -\hline -Modify transport destination port & -16 bits: Value with which to replace existing TCP or UDP destination port & -Replace the existing TCP/UDP destination port with new value and update the TCP/UDP checksum - -This action is only applied to TCP and UDP packets.\\ -\hline -\end{tabularx} -\caption{Field-modify actions.} -\label{table:field modify actions} -\end{table} - -\subsection{Matching} -\begin{figure}[!htb] -\centering -\includegraphics[height=1.85in]{packet_flow_flowchart} -\caption{Packet flow in an OpenFlow switch. As discussed in Section \ref{flow_table:stp_support}, support for 802.1D is optional.} -\label{fig:packet_flow} -\end{figure} - -\begin{figure}[!htb] -\centering -\includegraphics[height=2.9in]{header_parsing_flowchart} -\caption{Flowchart showing how header fields are parsed for matching.} -\label{fig:header_parsing} -\end{figure} - -On receipt of a packet, an OpenFlow Switch performs the functions shown in Figure \ref{fig:packet_flow}. Header fields used for the table lookup depend on the packet type as described below (and shown in Figure \ref{fig:header_parsing}). - -\begin{itemize} -\item Rules specifying an ingress port are matched against the physical port that received the packet. -\item The Ethernet headers as specified in Table \ref{table:header fields} are used for all packets. -\item If the packet is a VLAN (Ethernet type 0x8100), the VLAN ID and PCP fields are used in the lookup. -\item (Optional) For ARP packets (Ethernet type equal to 0x0806), the lookup fields may also include the contained IP source and destination fields. -\item For IP packets (Ethernet type equal to 0x0800), the lookup fields also include those in the IP header. -\item For IP packets that are TCP or UDP (IP protocol is equal to 6 or 17), the lookup includes the transport ports. -\item For IP packets that are ICMP (IP prototcol is equal to 1), the lookup includes the Type and Code fields. -\item For IP packets with nonzero fragment offset or More Fragments bit set, the transport ports are set to zero for the lookup. -\end{itemize} -A packet matches a flow table entry if the values in the header fields used for the lookup (as defined above) match those defined in the flow table. If a flow table field has a value of ANY, it matches all possible values in the header. -\\\\ -To handle the various Ethernet framing types, matching the Ethernet type is handled in a slightly different manner. If the packet is an Ethernet II frame, the Ethernet type is handled in the expected way. If the packet is an 802.3 frame with a SNAP header and Organizationally Unique Identifier (OUI) of 0x000000, the SNAP protocol id is matched against the flowÕs Ethernet type. A flow entry that specifies an Ethernet type of 0x05FF, matches all Ethernet 802.2 frames without a SNAP header and those with SNAP headers that do not have an OUI of 0x000000. -\\\\ -Packets are matched against flow entries based on prioritization. An entry that specifies an exact match (i.e., it has no wildcards) is always the highest priority. All wildcard entries have a priority associated with them. Higher priority entries must match before lower priority ones. If multiple entries have the same priority, the switch is free to choose any ordering. Higher numbers have higher priorities. -\\\\ -For each packet that matches a flow entry, the associated counters for that entry are updated. If no matching entry can be found for a packet, the packet is sent to the controller over the secure channel. - -\section{Secure Channel} -The secure channel is the interface that connects each OpenFlow switch to a controller. Through this interface, the controller configures and manages the switch, receives events from the switch, and send packets out the switch. -\\\\ -Between the datapath and the secure channel, the interface is implementation-specific, however all secure channel messages must be formatted according to the OpenFlow protocol. -\\\\ -Support for multiple simultaneous controllers is currently undefined. - -\subsection{OpenFlow Protocol Overview} -The OpenFlow protocol supports three message types, \emph{controller-to-switch}, \emph{asynchronous}, and \emph{symmetric}, each with multiple sub-types. Controller-to-switch messages are initiated by the controller and used to directly manage or inspect the state of the switch. Asynchronous messages are initiated by the switch and used to update the controller of network events and changes to the switch state. Symmetric messages are initiated by either the switch or the controller and sent without solicitation. The message types used by OpenFlow are described below. - -\subsubsection{Controller-to-Switch} -Controller/switch messages are initiated by the controller and may or may not require a response from the switch. -\\\\ -\textbf{Features:} Upon Transport Layer Security (TLS) session establishment, the controller sends a features request message to the switch. The switch must reply with a features reply that specifies the capabilities supported by the switch. -\\\\ -\textbf{Configuration:} The controller is able to set and query configuration parameters in the switch. The switch only responds to a query from the controller. -\\\\ -\textbf{Modify-State:} Modify-State messages are sent by the controller to manage state on the switches. Their primary purpose is to add/delete and modify flows in the flow tables and to set switch port properties. -\\\\ -\textbf{Read-State:} Read-State messages are used by the controller to collect statistics from the switchÕs flow-tables, ports and the individual flow entries. -\\\\\ -\textbf{Send-Packet}: These are used by the controller to send packets out of a specified port on the switch. -\\\\ -\textbf{Barrier}: Barrier request/reply messages are used by the controller to ensure message dependencies have been met or to receive notifications for completed operations. - -\subsubsection{Asynchronous} -Asynchronous messages are sent without the controller soliciting them from a switch. Switches send asynchronous messages to the controller to denote a packet arrival, switch state change, or error. The four main asynchronous message types are described below. -\\\\ -\textbf{Packet-in:} For all packets that do not have a matching flow entry, a packet-in event is sent to the controller (or if a packet matches an entry with a ``send to controller" action). If the switch has sufficient memory to buffer packets that are sent to the controller, the packet-in events contain some fraction of the packet header (by default \input{define/OFP_DEFAULT_MISS_SEND_LEN} bytes) and a buffer ID to be used by the controller when it is ready for the switch to forward the packet. Switches that do not support internal buffering (or have run out of internal buffering) must send the full packet to the controller as part of the event. -\\\\ -\textbf{Flow-Removed:} When a flow entry is added to the switch by a flow modify message, an idle timeout value indicates when the entry should be removed due to a lack of activity, as well as a hard timeout value that indicates when the entry should be removed, regardless of activity. The flow modify message also specifies whether the switch should send a flow removed message to the controller when the flow expires. Flow modify messages which delete flows may also cause flow removed messages. -\\\\ -\textbf{Port-status:} The switch is expected to send port-status messages to the controller as port configuration state changes. These events include change in port status (for example, if it was brought down directly by a user) or a change in port status as specified by 802.1D (see Section \ref{flow_table:stp_support} for a description of 802.1D support requirements). -\\\\ -\textbf{Error:} The switch is able to notify the controller of problems using error messages. - -\subsubsection{Symmetric} -Symmetric messages are sent without solicitation, in either direction. -\\\\ -\textbf{Hello:} Hello messages are exchanged between the switch and controller upon connection startup. -\\\\ -\textbf{Echo:} Echo request/reply messages can be sent from either the switch or the controller, and must return an echo reply. They can be used to indicate the latency, bandwidth, and/or liveness of a controller-switch connection. -\\\\ -\textbf{Vendor:} Vendor messages provide a standard way for OpenFlow switches to offer additional functionality within the OpenFlow message type space. This is a staging area for features meant for future OpenFlow revisions. - -\subsection{Connection Setup} -The switch must be able to establish the communication at a user-configurable (but otherwise fixed) IP address, using a user-specified port. Traffic to and from the secure channel is not checked against the flow table. Therefore, the switch must identify incoming traffic as local before checking it against the flow table. Future versions of the protocol specification will describe a dynamic controller discovery protocol in which the IP address and port for communicating with the controller is determined at runtime. -\\\\ -When an OpenFlow connection is first established, each side of the connection must immediately send an \verb|OFPT_HELLO| message with the \verb|version| field set to the highest OpenFlow protocol version supported by the sender. Upon receipt of this message, the recipient may calculate the OpenFlow protocol version to be used as the smaller of the version number that it sent and the one that it received. -\\\\ -If the negotiated version is supported by the recipient, then the connection proceeds. Otherwise, the recipient must reply with an \verb|OFPT_ERROR| message with a \verb|type| field of \verb|OFPET_HELLO_FAILED|, a \verb|code| field of \verb| OFPHFC_COMPATIBLE|, and optionally an ASCII string explaining the situation in \verb|data|, and then terminate the connection. - -\subsection{Connection Interruption} -In the case that a switch loses contact with the controller, as a result of a echo request timeout, TLS session timeout, or other disconnection, it should attempt to contact one or more backup controllers. The ordering of the controller IP addresses is not specified by the protocol. -\\\\ -If some number of attempts to contact a controller (zero or more) fail, the switch must enter ``emergency mode'' and immediately reset the current TCP connection. In emergency mode, the matching process is dictated by the emergency flow table entries (those marked with the emergency bit when added to the switch). All normal entries are deleted when entering emergency mode. -\\\\ -Upon connecting to a controller again, the emergency flow entries remain. The controller then has the option of deleting all flow entries, if desired. -\\\\ -The first time a switch starts up, it is considered to be in emergency mode. Configuration of the default set of flow entries is outside the scope of the OpenFlow protocol. - -\subsection{Encryption} -The switch and controller communicate through a TLS connection. The TLS connection is initiated by the switch on startup to the controller's server, which is located by default on TCP port \input{define/OFP_TCP_PORT}. The switch and controller mutually authenticate by exchanging certificates signed by a site-specific private key. Each switch must be user-configurable with one certificate for authenticating the controller (controller certificate) and the other for authenticating to the controller (switch certificate). - -\subsection{Spanning Tree} -\label{flow_table:stp_support} -OpenFlow switches may optionally support 802.1D Spanning Tree Protocol. Those switches that do support it are expected to process all 802.1D packets locally before performing flow lookup. A switch that implements STP must set the \verb|OFPC_STP| bit in the 'capabilities' field of its \verb|OFPT_FEATURES_REPLY| message. A switch that implements STP must make it available on all of its physical ports, but it need not implement it on virtual ports (e.g. \verb|OFPP_LOCAL|). -\\\\ -Port status, as specified by the spanning tree protocol, is then used to limit packets forwarded to the \verb|OFP_FLOOD| port to only those ports along the spanning tree. Port changes as a result of the spanning tree are sent to the controller via port-update messages. Note that forward actions that specify the outgoing port or \verb|OFP_ALL| ignore the port status set by the spanning tree protocol. Packets received on ports that are disabled by spanning tree must follow the normal flow table processing path. -\\\\ -Switches that do not support 802.1D spanning tree must allow the controller to specify the port status for packet flooding through the port-mod messages. - -\subsection{Flow Table Modification Messages} -\label{flow_table:sec_chan:flow_add} -\label{flow_table:sec_chan:flow_mod} -\label{flow_table:sec_chan:flow_removal} -Flow table modification messages can have the following types: -\input{enum/ofp_flow_mod_command} -For ADD requests with the \verb|OFPFF_CHECK_OVERLAP| flag set, the switch must first check for any overlapping flow entries. Two flow entries overlap if a single packet may match both, and both entries have the same priority. If an overlap conflict exists between an existing flow entry and the ADD request, the switch must refuse the addition and respond with an \verb|ofp_error_msg| with \verb|OFPET_FLOW_MOD_FAILED| type and \verb|OFPFMFC_OVERLAP| code. -\\\\ -For valid (non-overlapping) ADD requests, or those with no overlap checking, the switch must insert the flow entry at the lowest numbered table for which the switch supports all wildcards set in the \verb|flow_match| struct, and for which the priority would be observed during the matching process. If a flow entry with identical header fields and priority already resides in any table, then that entry, including its counters, must be removed, and the new flow entry added. -\\\\ -If a switch cannot find any table in which to add the incoming flow entry, the switch should send an \verb|ofp_error_msg| with \verb|OFPET_FLOW_MOD_FAILED| type and \verb|OFPFMFC_ALL_TABLES_FULL| code. -\\\\ -If the action list in a flow mod message references a port that will never be valid on a switch, the switch must return an \verb|ofp_error_msg| with \verb|OFPET_BAD_ACTION| type and \verb|OFPBAC_BAD_OUT_PORT| code. If the referenced port may be valid in the future, e.g. when a linecard is added to a chassis switch, or a port is dynamically added to a software switch, the switch may either silently drop packets sent to the referenced port, or immediately return an \verb|OFPBAC_BAD_OUT_PORT| error and refuse the flow mod. -\\\\ -For MODIFY requests, if a flow entry with identical header fields does not current reside in any table, the MODIFY acts like an ADD, and the new flow entry must be inserted with zeroed counters. Otherwise, the actions field is changed on the existing entry and its counters and idle time fields are left unchanged. -\\\\ -For DELETE requests, if no flow entry matches, no error is recorded, and no flow table modification occurs. If flow entries match, and must be deleted, then each normal entry with the \verb|OFPFF_SEND_FLOW_REM| flag set should generate a flow removed message. Deleted emergency flow entries generate no flow removed messages. -\\\\ -MODIFY and DELETE flow mod commands have corresponding \_STRICT versions. Without \_STRICT appended, the wildcards are active and all flows that match the description are modified or removed. If \_STRICT is appended, all fields, including the wildcards and priority, are strictly matched against the entry, and only an identical flow is modified or removed. For example, if a message to remove entries is sent that has all the wildcard flags set, the DELETE command would delete all flows from all tables, while the DELETE\_STRICT command would only delete a rule that applies to all packets at the specified priority. -\\\\ -For non-strict MODIFY and DELETE commands that contain wildcards, a match will occur when a flow entry exactly matches or is more specific than the description in the flow\_mod command. For example, if a DELETE command says to delete all flows with a destination port of 80, then a flow entry that is all wildcards will not be deleted. However, a DELETE command that is all wildcards will delete an entry that matches all port 80 traffic. This same interpretation of mixed wildcard and exact header fields also applies to individual and aggregate flows stats. -\\\\ -DELETE and DELETE\_STRICT commands can be optionally filtered by output port. If the \verb|out_port| field contains a value other than \verb|OFPP_NONE|, it introduces a constraint when matching. This constraint is that the rule must contain an output action directed at that port. This field is ignored by ADD, MODIFY, and MODIFY\_STRICT messages. -\\\\ -Emergency flow mod messages must have timeout values set to zero. Otherwise, the switch must refuse the addition and respond with an \verb|ofp_error_msg| with \verb|OFPET_FLOW_MOD_FAILED| type and \verb|OFPFMFC_BAD_EMERG_TIMEOUT| code. -\\\\ -\label{unsupported_flow}If a switch cannot process the action list for any flow mod message in the order specified, it MUST immediately return an \verb|OFPET_FLOW_MOD_FAILED| : -\verb|OFPFMFC_UNSUPPORTED| error and reject the flow. - -\subsection{Flow Removal} - -Each flow entry has an \verb|idle_timeout| and a \verb|hard_timeout| associated with it. If no packet has matched the rule in the last \verb|idle_timeout| seconds, or it has been \verb|hard_timeout| seconds since the flow was inserted, the switch removes the entry and sends a flow removed message. In addition, the controller is able to actively remove entries by sending a flow message with the \verb|DELETE| or \verb|DELETE_STRICT| command. Like the message used to add the entry, a removal message contains a description, which may include wild cards. - -\input{appendix} - -\input{credits} - -\end{document} diff --git a/openflow/doc/of-spec/packet_flow_flowchart.graffle b/openflow/doc/of-spec/packet_flow_flowchart.graffle deleted file mode 100644 index 57a76098..00000000 --- a/openflow/doc/of-spec/packet_flow_flowchart.graffle +++ /dev/null @@ -1,1887 +0,0 @@ - - - - - ActiveLayerIndex - 0 - ApplicationVersion - - com.omnigroup.OmniGraffle - 138.12.0.121252 - - AutoAdjust - - BackgroundGraphic - - Bounds - {{0, 0}, {756, 553}} - Class - SolidGraphic - ID - 2 - Style - - shadow - - Draws - NO - - stroke - - Draws - NO - - - - CanvasOrigin - {0, 0} - ColumnAlign - 1 - ColumnSpacing - 36 - CreationDate - 2009-11-20 14:54:05 -0800 - Creator - brandonh - DisplayScale - 1 0/72 in = 1 0/72 in - GraphDocumentVersion - 6 - GraphicsList - - - Class - LineGraphic - Head - - ID - 50 - - ID - 67 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {104.25, 130.5} - {141.75, 130.5} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 66 - - - - Bounds - {{5.25, 99}, {99, 63}} - Class - ShapedGraphic - ID - 66 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 Packet in from network} - - VFlip - YES - - - Bounds - {{470.5, 317.375}, {30.1875, 14}} - Class - ShapedGraphic - FitText - Vertical - Flow - Resize - ID - 64 - Shape - Rectangle - Style - - fill - - Draws - NO - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Pad - 0 - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 no} - VerticalPad - 0 - - - - Bounds - {{470.5, 192.5}, {30.1875, 14}} - Class - ShapedGraphic - FitText - Vertical - Flow - Resize - ID - 63 - Shape - Rectangle - Style - - fill - - Draws - NO - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Pad - 0 - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 no} - VerticalPad - 0 - - - - Bounds - {{521.062, 277}, {30.1875, 14}} - Class - ShapedGraphic - FitText - Vertical - Flow - Resize - ID - 62 - Shape - Rectangle - Style - - fill - - Draws - NO - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Pad - 0 - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 yes} - VerticalPad - 0 - - - - Class - LineGraphic - Head - - ID - 55 - Position - 0.46666735410690308 - - ID - 61 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {514.5, 268.5} - {535.5, 130.5} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 52 - Info - 3 - - - - Bounds - {{514.5, 105.438}, {30.1875, 14}} - Class - ShapedGraphic - FitText - Vertical - Flow - Resize - ID - 60 - Shape - Rectangle - Style - - fill - - Draws - NO - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Pad - 0 - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 yes} - VerticalPad - 0 - - - - Class - LineGraphic - Head - - ID - 53 - - ID - 57 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {460.5, 322.5} - {460.5, 345} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 52 - Info - 1 - - - - Class - LineGraphic - Head - - ID - 52 - - ID - 56 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {460.5, 184.5} - {460.5, 214.5} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - Pattern - 2 - TailArrow - 0 - - - Tail - - ID - 47 - - - - Class - LineGraphic - Head - - ID - 54 - - ID - 55 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {514.5, 130.5} - {559.5, 130.5} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 47 - Info - 3 - - - - Bounds - {{559.5, 99}, {99, 63}} - Class - ShapedGraphic - ID - 54 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 Apply actions} - - VFlip - YES - - - Bounds - {{411, 345}, {99, 63}} - Class - ShapedGraphic - ID - 53 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 Send to controller via Secure Channel} - - VFlip - YES - - - Bounds - {{406.5, 214.5}, {108, 108}} - Class - ShapedGraphic - ID - 52 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Diamond - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 Match table N?} - VerticalPad - 0 - - - - Class - LineGraphic - Head - - ID - 35 - Info - 4 - - ID - 51 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {240.75, 130.5} - {271.5, 130.5} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 50 - Info - 3 - - - - Bounds - {{141.75, 99}, {99, 63}} - Class - ShapedGraphic - ID - 50 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Rectangle - Style - - stroke - - Pattern - 1 - - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 Optional\ -802.1d STP processing} - - VFlip - YES - - - Class - LineGraphic - Head - - ID - 47 - - ID - 49 - OrthogonalBarAutomatic - - OrthogonalBarPosition - -1 - Points - - {370.5, 130.5} - {406.5, 130.5} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 2 - TailArrow - 0 - - - Tail - - ID - 35 - - - - Bounds - {{271.5, 99}, {99, 63}} - Class - ShapedGraphic - ID - 35 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 Parse header fields\ -(see below)} - - VFlip - YES - - - Bounds - {{406.5, 76.5}, {108, 108}} - Class - ShapedGraphic - ID - 47 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Diamond - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural - -\f0\fs24 \cf0 Match table 0?} - VerticalPad - 0 - - - - GridInfo - - GuidesLocked - NO - GuidesVisible - YES - HPages - 1 - ImageCounter - 1 - KeepToScale - - Layers - - - Lock - NO - Name - Layer 1 - Print - YES - View - YES - - - LayoutInfo - - Animate - NO - circoMinDist - 18 - circoSeparation - 0.0 - layoutEngine - dot - neatoSeparation - 0.0 - twopiSeparation - 0.0 - - LinksVisible - NO - MagnetsVisible - NO - MasterSheets - - ModificationDate - 2009-11-20 15:11:07 -0800 - Modifier - brandonh - NotesVisible - NO - Orientation - 2 - OriginVisible - NO - PageBreaks - YES - PrintInfo - - NSBottomMargin - - float - 41 - - NSLeftMargin - - float - 18 - - NSOrientation - - int - 1 - - NSPaperSize - - size - {792, 612} - - NSRightMargin - - float - 18 - - NSTopMargin - - float - 18 - - - PrintOnePage - - QuickLookPreview - - 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 - ago8PCAvUHJvY1NldCBbIC9QREYgL1RleHQgL0ltYWdlQiAvSW1hZ2VDIC9JbWFnZUkg - XSAvQ29sb3JTcGFjZSA8PCAvQ3MyIDIzIDAgUgovQ3MxIDggMCBSID4+IC9Gb250IDw8 - IC9GMS4wIDI0IDAgUiA+PiAvWE9iamVjdCA8PCAvSW0xIDkgMCBSIC9JbTYgMTkgMCBS - Ci9JbTQgMTUgMCBSIC9JbTUgMTcgMCBSIC9JbTMgMTMgMCBSIC9JbTIgMTEgMCBSIC9J - bTcgMjEgMCBSID4+ID4+CmVuZG9iago5IDAgb2JqCjw8IC9MZW5ndGggMTAgMCBSIC9U - eXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMjYwIC9IZWlnaHQgMjYw - IC9Db2xvclNwYWNlCjI1IDAgUiAvU01hc2sgMjYgMCBSIC9CaXRzUGVyQ29tcG9uZW50 - IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7dAxAQAAAMKg9U/taQmI - QGHAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY - MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED - BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA - gAEDBgwYMGDAgAEDBgwYMGDgAwMYXQABCmVuZHN0cmVhbQplbmRvYmoKMTAgMCBvYmoK - OTA4CmVuZG9iagoxOSAwIG9iago8PCAvTGVuZ3RoIDIwIDAgUiAvVHlwZSAvWE9iamVj - dCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRoIDI0MiAvSGVpZ2h0IDE3MCAvQ29sb3JTcGFj - ZQoyOCAwIFIgL1NNYXNrIDI5IDAgUiAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIg - L0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae3QMQEAAADCoPVPbQo/iEBhwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwa+AwPiKwABCmVuZHN0cmVhbQplbmRvYmoKMjAgMCBvYmoK - NTYyCmVuZG9iagoxNSAwIG9iago8PCAvTGVuZ3RoIDE2IDAgUiAvVHlwZSAvWE9iamVj - dCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRoIDI2MCAvSGVpZ2h0IDI2MCAvQ29sb3JTcGFj - ZQoyNSAwIFIgL1NNYXNrIDMxIDAgUiAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIg - L0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae3QMQEAAADCoPVP7WkJiEBhwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg - wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM - GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB - AwYMGDBg4AMDGF0AAQplbmRzdHJlYW0KZW5kb2JqCjE2IDAgb2JqCjkwOAplbmRvYmoK - MTcgMCBvYmoKPDwgL0xlbmd0aCAxOCAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUg - L0ltYWdlIC9XaWR0aCAyNDIgL0hlaWdodCAxNzAgL0NvbG9yU3BhY2UKMjggMCBSIC9T - TWFzayAzMyAwIFIgL0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29k - ZSA+PgpzdHJlYW0KeAHt0DEBAAAAwqD1T20KP4hAYcCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGvgMD4isAAQplbmRzdHJlYW0KZW5kb2JqCjE4IDAgb2JqCjU2MgplbmRvYmoK - MTMgMCBvYmoKPDwgL0xlbmd0aCAxNCAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUg - L0ltYWdlIC9XaWR0aCAyNDIgL0hlaWdodCAxNzAgL0NvbG9yU3BhY2UKMzUgMCBSIC9T - TWFzayAzNiAwIFIgL0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29k - ZSA+PgpzdHJlYW0KeAHt0DEBAAAAwqD1T20KP4hAYcCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGvgMD4isAAQplbmRzdHJlYW0KZW5kb2JqCjE0IDAgb2JqCjU2MgplbmRvYmoK - MTEgMCBvYmoKPDwgL0xlbmd0aCAxMiAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUg - L0ltYWdlIC9XaWR0aCAyNDIgL0hlaWdodCAxNzAgL0NvbG9yU3BhY2UKMjggMCBSIC9T - TWFzayAzOCAwIFIgL0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29k - ZSA+PgpzdHJlYW0KeAHt0DEBAAAAwqD1T20KP4hAYcCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGvgMD4isAAQplbmRzdHJlYW0KZW5kb2JqCjEyIDAgb2JqCjU2MgplbmRvYmoK - MjEgMCBvYmoKPDwgL0xlbmd0aCAyMiAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUg - L0ltYWdlIC9XaWR0aCAyNDIgL0hlaWdodCAxNzAgL0NvbG9yU3BhY2UKMjggMCBSIC9T - TWFzayA0MCAwIFIgL0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29k - ZSA+PgpzdHJlYW0KeAHt0DEBAAAAwqD1T20KP4hAYcCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG - DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA - AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw - YMCAAQMGvgMD4isAAQplbmRzdHJlYW0KZW5kb2JqCjIyIDAgb2JqCjU2MgplbmRvYmoK - NDAgMCBvYmoKPDwgL0xlbmd0aCA0MSAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUg - L0ltYWdlIC9XaWR0aCAyNDIgL0hlaWdodCAxNzAgL0NvbG9yU3BhY2UKL0RldmljZUdy - YXkgL0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJl - YW0KeAHtnf9PU9cbx/lS6Lfb215ob8ttu5ZbCr0tpbsCVkAHBIIi4BcUVzchaNUMBnYa - G5uhDsOU2CiCg/AlioyIBhwBQ5AQNZ9/7fOcYrZRim6/9azP+wfiTTB5Xuf9nPc5vSR9 - srJQuAK4ArgCuAL0rkA21fpX6w6kOX8plzL9VXkOgPwD8B1aoFQo8iiWQgEIBP5L0Ane - Hdh8pVK1IzVF+lSyUpkPdgH2F5g/8ebl5QOsWqPRarUMw+ioEhQMZWs0apWKUH+emQDn - Qi8DLsAyOpbVGwwcdTIY9CyrA24NQO8w79PaCWDwl/DqWD3HFRQajSYTz5spEs+bTEZj - YQHH6VkdYQafobVTIxOHicGE1wC0vNlSJAhWm81OkWw2qyAUWcw8UBsSzGAzQU4R2glg - 2MBaBngBF1jtDqezWHRRJbHY6XTYgRuggZnRku2cGjmb7GGlGgzmCnmLALSiy11a5pEk - r9dHibxeSfKUlbpdIlALFr6QA5vVSpJfe00GiwFYpdXpOaNZsDvFklLJW+4PBGRZPkCN - oNhAwF/ulUpLRKddMBs5vQ5czlOk6GuwGEJLkwC2OkS3x+cPyJXVB4M1taA6KkQqrQke - rK6UA36fxy06rAlkDcRXCpOzwWKVhmE5o8XqcJX5KuSqYE3dkfqGxqampmZKBKU2NtQf - qasJVskVvjKXw2oxciyjUYHJyW29Y7EWgM1WZ4nkl6sO1dU3Nrcca21r7zhBjTra21qP - tTQ31tcdqpL9UomTuMxqU5lMiKGnDQDsKJEClcHDDU1Hj3ec7DzTdS5Ekc51nek82XH8 - aFPD4WBlQCohjW3Qgcl72hqaOl+lZQt4weGSKqpq65tb20+fDX3f3dN7KRy+TInC4Uu9 - Pd3fh86ebm9trq+tqpBcDoEvICbvaevsHDiZwGKLXSzzV9Y2tLSd6jrf3Ru+2vfjwOC1 - CCW6NjjwY9/VcG/3+a5TbS0NtZX+MtFuAZPhhEreyKSpYRfzgtPtk4P1Le2doQsXr/QN - RG7cjN6KUaNb0Zs3IgN9Vy5eCHW2t9QHZZ/bKfBkJ0Nb7752JYj1hWa76KmoOtwMwD3h - vsHr0djQnbvD96jR8N07Q7Ho9cG+cA8gNx+uqvCIdnOhPiVxvpoxGIscJT75UEPrqVDP - 5f5INHZneOT+6MM4NXo4en9k+E4sGum/3BM61dpwSPaVOIqMBkadv8djRb5aR5q61F9V - 19TRdSHc/1N0aPjX0fjjJ+NPqdH4k8fx0V+Hh6I/9YcvdHU01VX5S0lb69QQXUldrVBq - 2AKzTfQEgt8cPX3+4g+R6NC9B/GxicmpmZlZSjQzMzU5MRZ/cG8oGvnh4vnTR78JBjyi - zVzAapQpiLUsbGOXV65pPH62+8oAAI8+Gp+cnns2/2KBEr2YfzY3PTn+aBSQB650nz3e - WCN7XbCRWW0KYohqY9FX7vJKaOpQb9/12C8PHk1MzT5fWHy59IoSLb1cXHg+OzXx6MEv - set9vSFo68py91dFRgjrPR7D4aQ3km1cfaTl5Hfhgejtkfj41Nz870uvl1feUKKV5ddL - v8/PTY3HR25HB8LfnWw5Uk02spGEdfI+BmIDEJcFgvXHOruvRmLDo2OTs/OLr1berK6t - U6K11TcrrxbnZyfHRodjkavdncfqg4EyIDakJGYMJqEYgquh9UxP342fR+IT088BeHX9 - 7QY1eru+CsjPpyfiIz/f6Os509oA0VUsmAxMKo8ZzmQVpa9rGtu6evtv3r7/+Le5haXl - 1fWNzXdblOjd5sb66vLSwtxvj+/fvtnf29XWWPO1JFpN3D7EvE2U5Nqm9nOXBqJ3R8em - ni2+/mNtY3NrmxptbW6s/fF68dnU2Ojd6MClc+1NtbIk2vj9ieFwAuJvw4O3hh8+mZ5/ - ubz6FoDff6BE77e3Nt+uLr+cn37ycPjWYPhbQux1fZG4IxS+FrsXn5h5sbSytvEOgD9S - og/vt99trK0svZiZiN+LXQvD8bQfMXxYVDEcb0t4nIL4f1To4+eJd733yc7Ng2s1XLl8 - B+qaT4QuR8Djp7MLr96sb2xtf/hIBS8U+fHD9tbG+ptXC7NPwePI5dCJ5roDPrh0wcU6 - LxeJ0WPsahr2Mu5jTK6/vQXB0wnPYxpiC28geOfCWyZ+ksDPTlSkNd4y8ZaJt0x864Pv - udI/rjGrMasxqzGrMasxq9NvBfB0wtMJTyc8nfB0Sr9sTq4IsxqzGrMasxqzOjkZ0+8Z - sxqzGrMasxqzOv2yObkizGrMasxqzGrM6uRkTL9nzGrMasxqzGrM6vTL5uSKMKsxqzGr - Masxq5OTMf2eMasxqzGrMasxq9Mvm5MrwqzGrMasxqzGrE5OxvR7xqzGrMasxqzGrE6/ - bE6uCLMasxqzGrMaszo5GdPvGbMasxqzGrP6v53VGfdtzllfIP7vfWP3LuKM+lb2TPvm - /YybrpBxEzQyb0pKpk3CUWTctCOFMuMmWmXe1LKMm0yXm3HTB8lMzQybMJlpU0Qzb1Js - Jk4DzryJz2RweyZN9c7KuMntQExM1uj0ZHa7Q3R7fP6AXFl9MFhDZt7XUSFSaU3wYHWl - HPD7PG6RDDHn9DDFPH/vGPMsIM5R5ClV2gSyYHeKJaWSt9wfCMiyfIAaQbGBgL/cK5WW - iE67kADWqpR5ipzkod7wsh5MBmS1VsdyhbxFsDucostdWuaRJK/XR4m8XknylJW6XaLT - YRcsfCHH6rQww1yxZ1I9+esEmAx9DS4zrKHAyJsFqw2oncWiiyqJxU6gtVkFM28sMLAM - OEx6OoXFn5ChsTVgs6GgEKAtRQJw2+wUyQasQpEFcAuBV6fVQEvvB5yVnXAZ4ivBrOc4 - oDaaTDxvpkg8bzIZgZbj9AleCK0E8K7Jg3/+wS2BrMgDm4FZy+hYVm8wcNTJYNCzrI7R - gr/EYNjDOdmpgaGvwWWSX2Q7q9QawNYyDKOjSlAwlK3RqAEX/CW8+wOT+NphBmigBuyE - 1BTpU8lKQpun+CJvIrIJc05ubq6CYFMrgM0l9n7W37/t5wQ1+X0Q/E+qtFN14mf2vvv3 - T9Zd/4Dfp1i7UPABVwBXAFcAV4CyFfg/bog27wplbmRzdHJlYW0KZW5kb2JqCjQxIDAg - b2JqCjIzMjAKZW5kb2JqCjMxIDAgb2JqCjw8IC9MZW5ndGggMzIgMCBSIC9UeXBlIC9Y - T2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMjYwIC9IZWlnaHQgMjYwIC9Db2xv - clNwYWNlCi9EZXZpY2VHcmF5IC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxh - dGVEZWNvZGUgPj4Kc3RyZWFtCngB7d3/U1JZFADwvijyTURFVJKVomxxILQwU7I0Gr+3 - Wg4jfTOcMqNGLR1aR8sp1Cmx8kvluOZoTuygmWnqqG27s//anvuwTBcUFd6798L5JQ1K - +Hjuue894Jw9e8IRFggLhAXCAmGBsEBYICyAkcBeFPsgmC8wemAsPZTVZw8A+/cjBgj4 - K5Z+OBY/xvPr378/IiIiEgL+8EiEkAJaAAAAz57Hi4Lg8RAEwxAiqYCSAAHwovh8vkAg - FAoE8EUUOETAsgiJVGAIGAGBUCQSR0OIRSKhgFEIDQQggCTg8flCkVgiiZHGQkhjJBKx - SMjn81AqUJ8JHoIoEIiWSGPjZLIECJksLlYqiQaFqBBAWCUQQA5I42QJiUkKJpISE2Rx - UsgFAf0IHgK+QIQE5EmKFGWqCiJVmaJIkiMFkYBPeSasEghFkth4edIBpeqQ+kgaxBH1 - IZXyQJI8PlYC64FqhO8EYkmsLFGhVKnTNOla3bFjOm26Jk2tUioSZbESMdUIPwhi4hKS - U5CAVp95wpCVZTiRqdcihZTkhLgYmhF+IpArlAfTNLpMQ3auMQ/CmJttyNRp0g4qFXKa - EdYI4uWKX9RHtRmGU8az584XQpw/d9Z4ypChPar+RSGPpzYTfiJIVKSqNbrj2cZ8U1Fp - eQVEeWmRKd+YfVynUacqEmlFWE9wWKM35JwxFZdXVpktEOaqyvJi05kcg15zmFqEdQQq - RJCbX1hWabZcq7HW1lprrlnMlWWF+bkIQUVnJmwgSNdnGQuKL1RZrtfeqrfdvWurv1V7 - 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 - 1lyzmCvLCvNzYd4oedcO/SPYgJB6GBByzpiKyyurzBYIc1VlebHpTA4iSCXt8qm/BBsR - 1Brd8WxjvqmotLwCory0yJRvzD6u06gpJliHIIfJyUe1GYZTxrPnzhdCnD931njKkKE9 - CtOH5WRdRPc/C9A91wojTNBWHkzT6DIN2bnGPAhjbrYhU6dJO6hkRnET9DrC9gjWISQk - p6jUaRqtPvOEISvLcCJTr9WkqVUpyQlrI9lxfXF9u097/f1/ZAJM0U5UKJFCulZ37JhO - m44ElIpEmEBN0qtJ65+ef999R4BR4vHypANK1SH1kTSII+pDKuWBJHk8zF6meCF4kFYR - BCKJNE4mT1KkKFNVEKnKFEWSXBYnhYn0eL/LxL/f9eb38iBECURipJCQmKRgIikxAQmI - RWgMOcZvtNn8yfl76yoCXyiKlkhj42SyBAiZLC5WKomGdRAKBN93Bx4fFMQSSYw0FkIa - I4EcEPL5vBDIApQtkAkwJTGSF8UXCEUicTSEWCQSCvhRvEgYw47vO878TXV/7scgRDAK - fL5AIBQKBHw+IwClIDQIUCrsg1SAsS/gwIuC4EEGwCoAAW/Ddv1xJfA+KBUYhggEERkR - 4QEImSTw/Mr2ehgYCeQBAX9F4K9zlw8ZnrRHgvlil/9Z+J+HBcICYYGwQFggLBAWCAsE - VuA/SCo8XAplbmRzdHJlYW0KZW5kb2JqCjMyIDAgb2JqCjM3MTEKZW5kb2JqCjI5IDAg - b2JqCjw8IC9MZW5ndGggMzAgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFn - ZSAvV2lkdGggMjQyIC9IZWlnaHQgMTcwIC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5IC9C - aXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB - 7Z3/T1PXG8f5Uui329teaG/LbbuWWwq9LaW7AlZABwSCIuAXFFc3IWjVDAZ2GhuboQ7D - lNgogoPwJYqMiAYcAUOQEDWff+3znGK2UYpuv/Wsz/sH4k0weV7n/Zz3Ob0kfbKyULgC - uAK4ArgC9K5ANtX6V+sOpDl/KZcy/VV5DoD8A/AdWqBUKPIolkIBCAT+S9AJ3h3YfKVS - tSM1RfpUslKZD3YB9heYP/Hm5eUDrFqj0Wq1DMPoqBIUDGVrNGqVilB/npkA50IvAy7A - MjqW1RsMHHUyGPQsqwNuDUDvMO/T2glg8Jfw6lg9xxUUGo0mE8+bKRLPm0xGY2EBx+lZ - HWEGn6G1UyMTh4nBhNcAtLzZUiQIVpvNTpFsNqsgFFnMPFAbEsxgM0FOEdoJYNjAWgZ4 - ARdY7Q6ns1h0USWx2Ol02IEboIGZ0ZLtnBo5m+xhpRoM5gp5iwC0ostdWuaRJK/XR4m8 - XknylJW6XSJQCxa+kAOb1UqSX3tNBosBWKXV6TmjWbA7xZJSyVvuDwRkWT5AjaDYQMBf - 7pVKS0SnXTAbOb0OXM5TpOhrsBhCS5MAtjpEt8fnD8iV1QeDNbWgOipEKq0JHqyulAN+ - n8ctOqwJZA3EVwqTs8FilYZhOaPF6nCV+SrkqmBN3ZH6hsampqZmSgSlNjbUH6mrCVbJ - Fb4yl8NqMXIso1GBycltvWOxFoDNVmeJ5JerDtXVNza3HGtta+84QY062ttaj7U0N9bX - HaqS/VKJk7jMalOZTIihpw0A7CiRApXBww1NR493nOw803UuRJHOdZ3pPNlx/GhTw+Fg - ZUAqIY1t0IHJe9oamjpfpWULeMHhkiqqauubW9tPnw19393TeykcvkyJwuFLvT3d34fO - nm5vba6vraqQXA6BLyAm72nr7Bw4mcBii10s81fWNrS0neo6390bvtr348DgtQglujY4 - 8GPf1XBv9/muU20tDbWV/jLRbgGT4YRK3sikqWEX84LT7ZOD9S3tnaELF6/0DURu3Ize - ilGjW9GbNyIDfVcuXgh1trfUB2Wf2ynwZCdDW+++diWI9YVmu+ipqDrcDMA94b7B69HY - 0J27w/eo0fDdO0Ox6PXBvnAPIDcfrqrwiHZzoT4lcb6aMRiLHCU++VBD66lQz+X+SDR2 - Z3jk/ujDODV6OHp/ZPhOLBrpv9wTOtXacEj2lTiKjAZGnb/HY0W+WkeautRfVdfU0XUh - 3P9TdGj419H44yfjT6nR+JPH8dFfh4eiP/WHL3R1NNVV+UtJW+vUEF1JXa1QatgCs030 - BILfHD19/uIPkejQvQfxsYnJqZmZWUo0MzM1OTEWf3BvKBr54eL500e/CQY8os1cwGqU - KYi1LGxjl1euaTx+tvvKAACPPhqfnJ57Nv9igRK9mH82Nz05/mgUkAeudJ893lgje12w - kVltCmKIamPRV+7ySmjqUG/f9dgvDx5NTM0+X1h8ufSKEi29XFx4Pjs18ejBL7Hrfb0h - aOvKcvdXRUYI6z0ew+GkN5JtXH2k5eR34YHo7ZH4+NTc/O9Lr5dX3lCileXXS7/Pz02N - x0duRwfC351sOVJNNrKRhHXyPgZiAxCXBYL1xzq7r0Ziw6Njk7Pzi69W3qyurVOitdU3 - K68W52cnx0aHY5Gr3Z3H6oOBMiA2pCRmDCahGIKrofVMT9+Nn0fiE9PPAXh1/e0GNXq7 - vgrIz6cn4iM/3+jrOdPaANFVLJgMTCqPGc5kFaWvaxrbunr7b96+//i3uYWl5dX1jc13 - W5To3ebG+ury0sLcb4/v377Z39vV1ljztSRaTdw+xLxNlOTapvZzlwaid0fHpp4tvv5j - bWNza5sabW1urP3xevHZ1Njo3ejApXPtTbWyJNr4/YnhcALib8ODt4YfPpmef7m8+haA - 33+gRO+3tzbfri6/nJ9+8nD41mD4W0LsdX2RuCMUvha7F5+YebG0srbxDoA/UqIP77ff - baytLL2YmYjfi10Lw/G0HzF8WFQxHG9LeJyC+H9U6OPniXe998nOzYNrNVy5fAfqmk+E - LkfA46ezC6/erG9sbX/4SAUvFPnxw/bWxvqbVwuzT8HjyOXQiea6Az64dMHFOi8XidFj - 7Goa9jLuY0yuv70FwdMJz2MaYgtvIHjnwlsmfpLAz05UpDXeMvGWibdMfOuD77nSP64x - qzGrMasxqzGrMavTbwXwdMLTCU8nPJ3wdEq/bE6uCLMasxqzGrMaszo5GdPvGbMasxqz - GrMaszr9sjm5IsxqzGrMasxqzOrkZEy/Z8xqzGrMasxqzOr0y+bkijCrMasxqzGrMauT - kzH9njGrMasxqzGrMavTL5uTK8KsxqzGrMasxqxOTsb0e8asxqzGrMasxqxOv2xOrgiz - GrMasxqzGrM6ORnT7xmzGrMasxqz+r+d1Rn3bc5ZXyD+731j9y7ijPpW9kz75v2Mm66Q - cRM0Mm9KSqZNwlFk3LQjhTLjJlpl3tSyjJtMl5tx0wfJTM0MmzCZaVNEM29SbCZOA868 - ic9kcHsmTfXOyrjJ7UBMTNbo9GR2u0N0e3z+gFxZfTBYQ2be11EhUmlN8GB1pRzw+zxu - kQwx5/QwxTx/7xjzLCDOUeQpVdoEsmB3iiWlkrfcHwjIsnyAGkGxgYC/3CuVlohOu5AA - 1qqUeYqc5KHe8LIeTAZktVbHcoW8RbA7nKLLXVrmkSSv10eJvF5J8pSVul2i02EXLHwh - x+q0MMNcsWdSPfnrBJgMfQ0uM6yhwMibBasNqJ3FoosqicVOoLVZBTNvLDCwDDhMejqF - xZ+QobE1YLOhoBCgLUUCcNvsFMkGrEKRBXALgVen1UBL7weclZ1wGeIrwaznOKA2mkw8 - b6ZIPG8yGYGW4/QJXgitBPCuyYN//sEtgazIA5uBWcvoWFZvMHDUyWDQs6yO0YK/xGDY - wznZqYGhr8Flkl9kO6vUGsDWMgyjo0pQMJSt0agBF/wlvPsDk/jaYQZooAbshNQU6VPJ - SkKbp/gibyKyCXNObm6ugmBTK4DNJfZ+1t+/7ecENfl9EPxPqrRTdeJn9r7790/WXf+A - 36dYu1DwAVcAVwBXAFeAshX4P26INu8KZW5kc3RyZWFtCmVuZG9iagozMCAwIG9iagoy - MzIwCmVuZG9iagozOCAwIG9iago8PCAvTGVuZ3RoIDM5IDAgUiAvVHlwZSAvWE9iamVj - dCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRoIDI0MiAvSGVpZ2h0IDE3MCAvQ29sb3JTcGFj - ZQovRGV2aWNlR3JheSAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIgL0ZsYXRlRGVj - b2RlID4+CnN0cmVhbQp4Ae2d/09T1xvH+VLot9vbXmhvy227llsKvS2luwJWQAcEgiLg - FxRXNyFo1QwGdhobm6EOw5TYKIKD8CWKjIgGHAFDkBA1n3/t85xitlGKbr/1rM/7B+JN - MHle5/2c9zm9JH2yslC4ArgCuAK4AvSuQDbV+lfrDqQ5fymXMv1VeQ6A/APwHVqgVCjy - KJZCAQgE/kvQCd4d2HylUrUjNUX6VLJSmQ92AfYXmD/x5uXlA6xao9FqtQzD6KgSFAxl - azRqlYpQf56ZAOdCLwMuwDI6ltUbDBx1Mhj0LKsDbg1A7zDv09oJYPCX8OpYPccVFBqN - JhPPmykSz5tMRmNhAcfpWR1hBp+htVMjE4eJwYTXALS82VIkCFabzU6RbDarIBRZzDxQ - GxLMYDNBThHaCWDYwFoGeAEXWO0Op7NYdFElsdjpdNiBG6CBmdGS7ZwaOZvsYaUaDOYK - eYsAtKLLXVrmkSSv10eJvF5J8pSVul0iUAsWvpADm9VKkl97TQaLAVil1ek5o1mwO8WS - Uslb7g8EZFk+QI2g2EDAX+6VSktEp10wGzm9DlzOU6Toa7AYQkuTALY6RLfH5w/IldUH - gzW1oDoqRCqtCR6srpQDfp/HLTqsCWQNxFcKk7PBYpWGYTmjxepwlfkq5KpgTd2R+obG - pqamZkoEpTY21B+pqwlWyRW+MpfDajFyLKNRgcnJbb1jsRaAzVZnieSXqw7V1Tc2txxr - bWvvOEGNOtrbWo+1NDfW1x2qkv1SiZO4zGpTmUyIoacNAOwokQKVwcMNTUePd5zsPNN1 - LkSRznWd6TzZcfxoU8PhYGVAKiGNbdCByXvaGpo6X6VlC3jB4ZIqqmrrm1vbT58Nfd/d - 03spHL5MicLhS7093d+Hzp5ub22ur62qkFwOgS8gJu9p6+wcOJnAYotdLPNX1ja0tJ3q - Ot/dG77a9+PA4LUIJbo2OPBj39Vwb/f5rlNtLQ21lf4y0W4Bk+GESt7IpKlhF/OC0+2T - g/Ut7Z2hCxev9A1EbtyM3opRo1vRmzciA31XLl4Idba31Adln9sp8GQnQ1vvvnYliPWF - Zrvoqag63AzAPeG+wevR2NCdu8P3qNHw3TtDsej1wb5wDyA3H66q8Ih2c6E+JXG+mjEY - ixwlPvlQQ+upUM/l/kg0dmd45P7owzg1ejh6f2T4Tiwa6b/cEzrV2nBI9pU4iowGRp2/ - x2NFvlpHmrrUX1XX1NF1Idz/U3Ro+NfR+OMn40+p0fiTx/HRX4eHoj/1hy90dTTVVflL - SVvr1BBdSV2tUGrYArNN9ASC3xw9ff7iD5Ho0L0H8bGJyamZmVlKNDMzNTkxFn9wbyga - +eHi+dNHvwkGPKLNXMBqlCmItSxsY5dXrmk8frb7ygAAjz4an5yeezb/YoESvZh/Njc9 - Of5oFJAHrnSfPd5YI3tdsJFZbQpiiGpj0Vfu8kpo6lBv3/XYLw8eTUzNPl9YfLn0ihIt - vVxceD47NfHowS+x6329IWjrynL3V0VGCOs9HsPhpDeSbVx9pOXkd+GB6O2R+PjU3Pzv - S6+XV95QopXl10u/z89NjcdHbkcHwt+dbDlSTTaykYR18j4GYgMQlwWC9cc6u69GYsOj - Y5Oz84uvVt6srq1TorXVNyuvFudnJ8dGh2ORq92dx+qDgTIgNqQkZgwmoRiCq6H1TE/f - jZ9H4hPTzwF4df3tBjV6u74KyM+nJ+IjP9/o6znT2gDRVSyYDEwqjxnOZBWlr2sa27p6 - +2/evv/4t7mFpeXV9Y3Nd1uU6N3mxvrq8tLC3G+P79++2d/b1dZY87UkWk3cPsS8TZTk - 2qb2c5cGondHx6aeLb7+Y21jc2ubGm1tbqz98Xrx2dTY6N3owKVz7U21siTa+P2J4XAC - 4m/Dg7eGHz6Znn+5vPoWgN9/oETvt7c2364uv5yffvJw+NZg+FtC7HV9kbgjFL4Wuxef - mHmxtLK28Q6AP1KiD++3322srSy9mJmI34tdC8PxtB8xfFhUMRxvS3icgvh/VOjj54l3 - vffJzs2DazVcuXwH6ppPhC5HwOOnswuv3qxvbG1/+EgFLxT58cP21sb6m1cLs0/B48jl - 0InmugM+uHTBxTovF4nRY+xqGvYy7mNMrr+9BcHTCc9jGmILbyB458JbJn6SwM9OVKQ1 - 3jLxlom3THzrg++50j+uMasxqzGrMasxqzGr028F8HTC0wlPJzyd8HRKv2xOrgizGrMa - sxqzGrM6ORnT7xmzGrMasxqzGrM6/bI5uSLMasxqzGrMaszq5GRMv2fMasxqzGrMaszq - 9Mvm5IowqzGrMasxqzGrk5Mx/Z4xqzGrMasxqzGr0y+bkyvCrMasxqzGrMasTk7G9HvG - rMasxqzGrMasTr9sTq4IsxqzGrMasxqzOjkZ0+8ZsxqzGrMas/q/ndUZ923OWV8g/u99 - Y/cu4oz6VvZM++b9jJuukHETNDJvSkqmTcJRZNy0I4Uy4yZaZd7UsoybTJebcdMHyUzN - DJswmWlTRDNvUmwmTgPOvInPZHB7Jk31zsq4ye1ATEzW6PRkdrtDdHt8/oBcWX0wWENm - 3tdRIVJpTfBgdaUc8Ps8bpEMMef0MMU8f+8Y8ywgzlHkKVXaBLJgd4olpZK33B8IyLJ8 - gBpBsYGAv9wrlZaITruQANaqlHmKnOSh3vCyHkwGZLVWx3KFvEWwO5yiy11a5pEkr9dH - ibxeSfKUlbpdotNhFyx8IcfqtDDDXLFnUj356wSYDH0NLjOsocDImwWrDaidxaKLKonF - TqC1WQUzbywwsAw4THo6hcWfkKGxNWCzoaAQoC1FAnDb7BTJBqxCkQVwC4FXp9VAS+8H - nJWdcBniK8Gs5zigNppMPG+mSDxvMhmBluP0CV4IrQTwrsmDf/7BLYGsyAObgVnL6FhW - bzBw1Mlg0LOsjtGCv8Rg2MM52amBoa/BZZJfZDur1BrA1jIMo6NKUDCUrdGoARf8Jbz7 - A5P42mEGaKAG7ITUFOlTyUpCm6f4Im8isglzTm5uroJgUyuAzSX2ftbfv+3nBDX5fRD8 - T6q0U3XiZ/a++/dP1l3/gN+nWLtQ8AFXAFcAVwBXgLIV+D9uiDbvCmVuZHN0cmVhbQpl - bmRvYmoKMzkgMCBvYmoKMjMyMAplbmRvYmoKMzMgMCBvYmoKPDwgL0xlbmd0aCAzNCAw - IFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUgL0ltYWdlIC9XaWR0aCAyNDIgL0hlaWdo - dCAxNzAgL0NvbG9yU3BhY2UKL0RldmljZUdyYXkgL0JpdHNQZXJDb21wb25lbnQgOCAv - RmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAHtnf9PU9cbx/lS6Lfb215ob8tt - u5ZbCr0tpbsCVkAHBIIi4BcUVzchaNUMBnYaG5uhDsOU2CiCg/AlioyIBhwBQ5AQNZ9/ - 7fOcYrZRim6/9azP+wfiTTB5Xuf9nPc5vSR9srJQuAK4ArgCuAL0rkA21fpX6w6kOX8p - lzL9VXkOgPwD8B1aoFQo8iiWQgEIBP5L0AneHdh8pVK1IzVF+lSyUpkPdgH2F5g/8ebl - 5QOsWqPRarUMw+ioEhQMZWs0apWKUH+emQDnQi8DLsAyOpbVGwwcdTIY9CyrA24NQO8w - 79PaCWDwl/DqWD3HFRQajSYTz5spEs+bTEZjYQHH6VkdYQafobVTIxOHicGE1wC0vNlS - JAhWm81OkWw2qyAUWcw8UBsSzGAzQU4R2glg2MBaBngBF1jtDqezWHRRJbHY6XTYgRug - gZnRku2cGjmb7GGlGgzmCnmLALSiy11a5pEkr9dHibxeSfKUlbpdIlALFr6QA5vVSpJf - e00GiwFYpdXpOaNZsDvFklLJW+4PBGRZPkCNoNhAwF/ulUpLRKddMBs5vQ5czlOk6Guw - GEJLkwC2OkS3x+cPyJXVB4M1taA6KkQqrQkerK6UA36fxy06rAlkDcRXCpOzwWKVhmE5 - o8XqcJX5KuSqYE3dkfqGxqampmZKBKU2NtQfqasJVskVvjKXw2oxciyjUYHJyW29Y7EW - gM1WZ4nkl6sO1dU3Nrcca21r7zhBjTra21qPtTQ31tcdqpL9UomTuMxqU5lMiKGnDQDs - KJEClcHDDU1Hj3ec7DzTdS5Ekc51nek82XH8aFPD4WBlQCohjW3Qgcl72hqaOl+lZQt4 - weGSKqpq65tb20+fDX3f3dN7KRy+TInC4Uu9Pd3fh86ebm9trq+tqpBcDoEvICbvaevs - HDiZwGKLXSzzV9Y2tLSd6jrf3Ru+2vfjwOC1CCW6NjjwY9/VcG/3+a5TbS0NtZX+MtFu - AZPhhEreyKSpYRfzgtPtk4P1Le2doQsXr/QNRG7cjN6KUaNb0Zs3IgN9Vy5eCHW2t9QH - ZZ/bKfBkJ0Nb7752JYj1hWa76KmoOtwMwD3hvsHr0djQnbvD96jR8N07Q7Ho9cG+cA8g - Nx+uqvCIdnOhPiVxvpoxGIscJT75UEPrqVDP5f5INHZneOT+6MM4NXo4en9k+E4sGum/ - 3BM61dpwSPaVOIqMBkadv8djRb5aR5q61F9V19TRdSHc/1N0aPjX0fjjJ+NPqdH4k8fx - 0V+Hh6I/9YcvdHU01VX5S0lb69QQXUldrVBq2AKzTfQEgt8cPX3+4g+R6NC9B/Gxicmp - mZlZSjQzMzU5MRZ/cG8oGvnh4vnTR78JBjyizVzAapQpiLUsbGOXV65pPH62+8oAAI8+ - Gp+cnns2/2KBEr2YfzY3PTn+aBSQB650nz3eWCN7XbCRWW0KYohqY9FX7vJKaOpQb9/1 - 2C8PHk1MzT5fWHy59IoSLb1cXHg+OzXx6MEvset9vSFo68py91dFRgjrPR7D4aQ3km1c - faTl5Hfhgejtkfj41Nz870uvl1feUKKV5ddLv8/PTY3HR25HB8LfnWw5Uk02spGEdfI+ - BmIDEJcFgvXHOruvRmLDo2OTs/OLr1berK6tU6K11TcrrxbnZyfHRodjkavdncfqg4Ey - IDakJGYMJqEYgquh9UxP342fR+IT088BeHX97QY1eru+CsjPpyfiIz/f6Os509oA0VUs - mAxMKo8ZzmQVpa9rGtu6evtv3r7/+Le5haXl1fWNzXdblOjd5sb66vLSwtxvj+/fvtnf - 29XWWPO1JFpN3D7EvE2U5Nqm9nOXBqJ3R8emni2+/mNtY3NrmxptbW6s/fF68dnU2Ojd - 6MClc+1NtbIk2vj9ieFwAuJvw4O3hh8+mZ5/ubz6FoDff6BE77e3Nt+uLr+cn37ycPjW - YPhbQux1fZG4IxS+FrsXn5h5sbSytvEOgD9Sog/vt99trK0svZiZiN+LXQvD8bQfMXxY - VDEcb0t4nIL4f1To4+eJd733yc7Ng2s1XLl8B+qaT4QuR8Djp7MLr96sb2xtf/hIBS8U - +fHD9tbG+ptXC7NPwePI5dCJ5roDPrh0wcU6LxeJ0WPsahr2Mu5jTK6/vQXB0wnPYxpi - C28geOfCWyZ+ksDPTlSkNd4y8ZaJt0x864PvudI/rjGrMasxqzGrMasxq9NvBfB0wtMJ - Tyc8nfB0Sr9sTq4IsxqzGrMasxqzOjkZ0+8ZsxqzGrMasxqzOv2yObkizGrMasxqzGrM - 6uRkTL9nzGrMasxqzGrM6vTL5uSKMKsxqzGrMasxq5OTMf2eMasxqzGrMasxq9Mvm5Mr - wqzGrMasxqzGrE5OxvR7xqzGrMasxqzGrE6/bE6uCLMasxqzGrMaszo5GdPvGbMasxqz - GrP6v53VGfdtzllfIP7vfWP3LuKM+lb2TPvm/YybrpBxEzQyb0pKpk3CUWTctCOFMuMm - WmXe1LKMm0yXm3HTB8lMzQybMJlpU0Qzb1JsJk4DzryJz2RweyZN9c7KuMntQExM1uj0 - ZHa7Q3R7fP6AXFl9MFhDZt7XUSFSaU3wYHWlHPD7PG6RDDHn9DDFPH/vGPMsIM5R5ClV - 2gSyYHeKJaWSt9wfCMiyfIAaQbGBgL/cK5WWiE67kADWqpR5ipzkod7wsh5MBmS1Vsdy - hbxFsDucostdWuaRJK/XR4m8XknylJW6XaLTYRcsfCHH6rQww1yxZ1I9+esEmAx9DS4z - rKHAyJsFqw2oncWiiyqJxU6gtVkFM28sMLAMOEx6OoXFn5ChsTVgs6GgEKAtRQJw2+wU - yQasQpEFcAuBV6fVQEvvB5yVnXAZ4ivBrOc4oDaaTDxvpkg8bzIZgZbj9AleCK0E8K7J - g3/+wS2BrMgDm4FZy+hYVm8wcNTJYNCzrI7Rgr/EYNjDOdmpgaGvwWWSX2Q7q9QawNYy - DKOjSlAwlK3RqAEX/CW8+wOT+NphBmigBuyE1BTpU8lKQpun+CJvIrIJc05ubq6CYFMr - gM0l9n7W37/t5wQ1+X0Q/E+qtFN14mf2vvv3T9Zd/4Dfp1i7UPABVwBXAFcAV4CyFfg/ - bog27wplbmRzdHJlYW0KZW5kb2JqCjM0IDAgb2JqCjIzMjAKZW5kb2JqCjI2IDAgb2Jq - Cjw8IC9MZW5ndGggMjcgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAv - V2lkdGggMjYwIC9IZWlnaHQgMjYwIC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5IC9CaXRz - UGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7d3/ - U1JZFADwvijyTURFVJKVomxxILQwU7I0Gr+3Wg4jfTOcMqNGLR1aR8sp1Cmx8kvluOZo - TuygmWnqqG27s//anvuwTBcUFd6798L5JQ1K+Hjuue894Jw9e8IRFggLhAXCAmGBsEBY - ICyAkcBeFPsgmC8wemAsPZTVZw8A+/cjBgj4K5Z+OBY/xvPr378/IiIiEgL+8EiEkAJa - AAAAz57Hi4Lg8RAEwxAiqYCSAAHwovh8vkAgFAoE8EUUOETAsgiJVGAIGAGBUCQSR0OI - RSKhgFEIDQQggCTg8flCkVgiiZHGQkhjJBKxSMjn81AqUJ8JHoIoEIiWSGPjZLIECJks - LlYqiQaFqBBAWCUQQA5I42QJiUkKJpISE2RxUsgFAf0IHgK+QIQE5EmKFGWqCiJVmaJI - kiMFkYBPeSasEghFkth4edIBpeqQ+kgaxBH1IZXyQJI8PlYC64FqhO8EYkmsLFGhVKnT - NOla3bFjOm26Jk2tUioSZbESMdUIPwhi4hKSU5CAVp95wpCVZTiRqdcihZTkhLgYmhF+ - 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 - N8LthpbWDkf3c2dvr/N5t6OjtaXhNqUE3hFKL1pu1N17YG/reOro6nI87WizP7hXd8Ny - sZTQ6wW+F4LnFm+HzSWV1TU3bY3N9ta29va2Vntzo+1mTXVlCaUE3jLhtKmkwnzVWmdr - uN/c0tJ8v8FWZ71qrigxnSbyqtFWWYBu35gJ+ixjQfGFKsv12lv1trt3bfW3aq9bqi4U - Fxiz9AReOPOH4H8IMCc1N7+wrNJsuVZjra211lyzmCvLCvNzYd4oedcO/SPYgJB6GBBy - zpiKyyurzBYIc1VlebHpTA4iSCXt8qm/BBsR1Brd8WxjvqmotLwCory0yJRvzD6u06gp - JliHIIfJyUe1GYZTxrPnzhdCnD931njKkKE9CtOH5WRdRPc/C9A91wojTNBWHkzT6DIN - 2bnGPAhjbrYhU6dJO6hkRnET9DrC9gjWISQkp6jUaRqtPvOEISvLcCJTr9WkqVUpyQlr - I9lxfXF9u097/f1/ZAJM0U5UKJFCulZ37JhOm44ElIpEmEBN0qtJ65+ef999R4BR4vHy - pANK1SH1kTSII+pDKuWBJHk8zF6meCF4kFYRBCKJNE4mT1KkKFNVEKnKFEWSXBYnhYn0 - eL/LxL/f9eb38iBECURipJCQmKRgIikxAQmIRWgMOcZvtNn8yfl76yoCXyiKlkhj42Sy - BAiZLC5WKomGdRAKBN93Bx4fFMQSSYw0FkIaI4EcEPL5vBDIApQtkAkwJTGSF8UXCEUi - cTSEWCQSCvhRvEgYw47vO878TXV/7scgRDAKfL5AIBQKBHw+IwClIDQIUCrsg1SAsS/g - wIuC4EEGwCoAAW/Ddv1xJfA+KBUYhggEERkR4QEImSTw/Mr2ehgYCeQBAX9F4K9zlw8Z - nrRHgvlil/9Z+J+HBcICYYGwQFggLBAWCAsEVuA/SCo8XAplbmRzdHJlYW0KZW5kb2Jq - CjI3IDAgb2JqCjM3MTEKZW5kb2JqCjM2IDAgb2JqCjw8IC9MZW5ndGggMzcgMCBSIC9U - eXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMjQyIC9IZWlnaHQgMTcw - IC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5IC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRl - 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 - d8WApwNg7RWwTOERxyzfdfIhsJoEigOEEgkxgh7Swj4XFdV0LFWuxucqS770/x56u8uz - 8mOSzwljPbfK+TzHd9PJlwTbvWJGcKO1mBVcry2sCO5r6ZzghrVYELxRW84LVo1yUbDZ - 9u/+71qpoV+1M0NPXytVhN/qFsqCb3dWhv66ujDcm9HOed+Tn7PlZIf7RxEKVJhwYHGW - UUUcc6iADQ3uJVchN83rOEbIvNnWB57yZzjqpn/e6Y65ZbWamiPP86tUo3LWUC5H5Xgs - dg2/AEmasesKZW5kc3RyZWFtCmVuZG9iago0MyAwIG9iago1NjMKZW5kb2JqCjM1IDAg - b2JqClsgL0lDQ0Jhc2VkIDQyIDAgUiBdCmVuZG9iago0NCAwIG9iago8PCAvTGVuZ3Ro - IDQ1IDAgUiAvTiAzIC9BbHRlcm5hdGUgL0RldmljZVJHQiAvRmlsdGVyIC9GbGF0ZURl - Y29kZSA+PgpzdHJlYW0KeAGtkz9oE1Ecx7+XFC1YI7TVQSjcYMEhakg66GSaNC1pJQ35 - 00S39HLJpeYux90ltsEhg6uzgzqIS4eiq8VFEcTFoSiiuDq4dOkgBSnn9+58iYPFxR+8 - e598832/37vfeweED2um2Q4B0A3HKiyl5OrNW/LJLziFKY4ZTNQU25zP52/Qckz8+ATJ - ++vDJS/XpmonIntXHu9v7KbvPS+/OGaRkCMWCwJSlMJ0M+Ckx+sBlzy+45gOPZrHilar - k++So1apkCZvkyPNgL16kfWA33ncU5re2s/kmFFvGUBonHy1rtoKOUnW6raik5lHCul6 - h/nDO9QvKqbFteGP5AteXzgzts4A1x/Q/3qkVd8CO8+Ac/sjbZbeqa/Abm+kHRz6vZJm - vtmNRNxPJ51+Apzou+7BWWCctY/WXPdnynWPWHuMSV7eV7pWz/dyg9J74F+/g3cOsgN7 - zMPwz+jvHPTFd8WApwNg7RWwTOERxyzfdfIhsJoEigOEEgkxgh7Swj4XFdV0LFWuxucq - S770/x56u8uz8mOSzwljPbfK+TzHd9PJlwTbvWJGcKO1mBVcry2sCO5r6ZzghrVYELxR - W84LVo1yUbDZ9u/+71qpoV+1M0NPXytVhN/qFsqCb3dWhv66ujDcm9HOed+Tn7PlZIf7 - RxEKVJhwYHGWUUUcc6iADQ3uJVchN83rOEbIvNnWB57yZzjqpn/e6Y65ZbWamiPP86tU - o3LWUC5H5Xgsdg2/AEmasesKZW5kc3RyZWFtCmVuZG9iago0NSAwIG9iago1NjMKZW5k - b2JqCjI1IDAgb2JqClsgL0lDQ0Jhc2VkIDQ0IDAgUiBdCmVuZG9iago0NiAwIG9iago8 - PCAvTGVuZ3RoIDQ3IDAgUiAvTiAzIC9BbHRlcm5hdGUgL0RldmljZVJHQiAvRmlsdGVy - IC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAGFlE1IFGEYx/+zjQSxBtGXCMXQwSRUJgtS - AtP1K1O2ZdVMCWKdfXedHGenmd0tRSKE6Jh1jC5WRIeITuGhQ6c6RASZdYmgo0UQBV4i - tv87k7tjVL4wM795nv/7fL3DAFWPUo5jRTRgys67yd6Ydnp0TNv8GlWoRhRcKcNzOhKJ - AZ+plc/1a/UtFGlZapSx1vs2fKt2mRBQNCp3ZAM+LHk84OOSL+SdPDVnJBsTqTTZITe4 - Q8lO8i3y1myIx0OcFp4BVLVTkzMcl3EiO8gtRSMrYz4g63batMnvpT3tGVPUsN/INzkL - 2rjy/UDbHmDTi4ptzAMe3AN211Vs9TXAzhFg8VDF9j3pz0fZ9crLHGr2wynRGGv6UCp9 - rwM23wB+Xi+VftwulX7eYQ7W8dQyCm7R17Iw5SUQ1BvsZvzkGv2Lg558VQuwwDmObAH6 - rwA3PwL7HwLbHwOJamCoFZHLbDe48uIi5wJ05pxp18xO5LVmXT+idfBohdZnG00NWsqy - NN/laa7whFsU6SZMWQXO2V/beI8Ke3iQT/YXuSS87t+szKVTXZwlmtjWp7To6iY3kO9n - zJ4+cj2v9xm3Zzhg5YCZ7xsKOHLKtuI8F6mJ1Njj8ZNkxldUJx+T85A85xUHZUzffi51 - IkGupT05meuXml3c2z4zMcQzkqxYMxOd8d/8xi0kZd591Nx1LP+bZ22RZxiFBQETNu82 - NCTRixga4cBFDhl6TCpMWqVf0GrCw+RflRYS5V0WFb1Y4Z4Vf895FLhbxj+FWBxzDeUI - mv5O/6Iv6wv6Xf3zfG2hvuKZc8+axqtrXxlXZpbVyLhBjTK+rCmIb7DaDnotZGmd4hX0 - 5JX1jeHqMvZ8bdmjyRzianw11KUIZWrEOOPJrmX3RbLFN+HnW8v2r+lR+3z2SU0l17K6 - eGYp+nw2XA1r/7OrYNKyq/DkjZAuPGuh7lUPqn1qi9oKTT2mtqttahffjqoD5R3DnJWJ - C6zbZfUp9mBjmt7KSVdmi+Dfwi+G/6VeYQvXNDT5D024uYxpCd8R3DZwh5T/w1+zAw3e - CmVuZHN0cmVhbQplbmRvYmoKNDcgMCBvYmoKNzkyCmVuZG9iago4IDAgb2JqClsgL0lD - Q0Jhc2VkIDQ2IDAgUiBdCmVuZG9iago0OCAwIG9iago8PCAvTGVuZ3RoIDQ5IDAgUiAv - TiAzIC9BbHRlcm5hdGUgL0RldmljZVJHQiAvRmlsdGVyIC9GbGF0ZURlY29kZSA+Pgpz - dHJlYW0KeAGtkz9oE1Ecx7+XFC1YI7TVQSjcYMEhakg66GSaNC1pJQ3500S39HLJpeYu - x90ltsEhg6uzgzqIS4eiq8VFEcTFoSiiuDq4dOkgBSnn9+58iYPFxR+8e598832/37vf - eweED2um2Q4B0A3HKiyl5OrNW/LJLziFKY4ZTNQU25zP52/Qckz8+ATJ++vDJS/Xpmon - IntXHu9v7KbvPS+/OGaRkCMWCwJSlMJ0M+Ckx+sBlzy+45gOPZrHilark++So1apkCZv - kyPNgL16kfWA33ncU5re2s/kmFFvGUBonHy1rtoKOUnW6raik5lHCul6h/nDO9QvKqbF - teGP5AteXzgzts4A1x/Q/3qkVd8CO8+Ac/sjbZbeqa/Abm+kHRz6vZJmvtmNRNxPJ51+ - Apzou+7BWWCctY/WXPdnynWPWHuMSV7eV7pWz/dyg9J74F+/g3cOsgN7zMPwz+jvHPTF - d8WApwNg7RWwTOERxyzfdfIhsJoEigOEEgkxgh7Swj4XFdV0LFWuxucqS770/x56u8uz - 8mOSzwljPbfK+TzHd9PJlwTbvWJGcKO1mBVcry2sCO5r6ZzghrVYELxRW84LVo1yUbDZ - 9u/+71qpoV+1M0NPXytVhN/qFsqCb3dWhv66ujDcm9HOed+Tn7PlZIf7RxEKVJhwYHGW - UUUcc6iADQ3uJVchN83rOEbIvNnWB57yZzjqpn/e6Y65ZbWamiPP86tUo3LWUC5H5Xgs - dg2/AEmasesKZW5kc3RyZWFtCmVuZG9iago0OSAwIG9iago1NjMKZW5kb2JqCjI4IDAg - b2JqClsgL0lDQ0Jhc2VkIDQ4IDAgUiBdCmVuZG9iago1MCAwIG9iago8PCAvTGVuZ3Ro - IDUxIDAgUiAvTiAxIC9BbHRlcm5hdGUgL0RldmljZUdyYXkgL0ZpbHRlciAvRmxhdGVE - ZWNvZGUgPj4Kc3RyZWFtCngBhVJPSBRRHP7NNhKEiEGFeIh3CgmVKaysoNp2dVmVbVuV - 0qIYZ9+6o7Mz05vZNcWTBF2iPHUPomN07NChm5eiwKxL1yCpIAg8dej7zezqKIRveTvf - +/39ft97RG2dpu87KUFUc0OVK6Wnbk5Ni4MfKUUd1E5YphX46WJxjLHruZK/u9fWZ9LY - st7HtXb79j21lWVgIeottrcQ+iGRZgAfmZ8oZYCzwB2Wr9g+ATxYDqwa8COiAw+auTDT - 0Zx0pbItkVPmoigqr2I7Sa77+bnGvou1iYP+XI9m1o69s+qq0UzUtPdEobwPrkQZz19U - 9mw1FKcN45xIQxop8q7V3ytMxxGRKxBKBlI1ZLmfak6ddeB1GLtdupPj+PYQpT7JYKiJ - temymR2FfQB2KsvsEPAF6PGyYg/ngXth/1tRw5PAJ2E/ZId51q0f9heuU+B7hD014M4U - rsXx2oofXi0BQ/dUI2iMc03E09c5c6SI7zHUGZj3RjmmCzF3lqoTN4A7YR9ZqmYKsV37 - ruol7nsCd9PjO9GbOQtcoBxJcrEV2RTQPAlYFH2LsEkOPD7OHlXgd6iYwBy5idzNKPce - 1REbZ6NSgVZ6jVfGT+O58cX4ZWwYz4B+rHbXe3z/6eMVdde2Pjz5jXrcOa69nRtVYVZx - ZQvd/8cyhI/ZJzmmwdOhWVhr2HbkD5rMTLAMKMR/BT6X+pITVdzV7u24RRLMUD4sbCW6 - S1RuKdTqPYNKrBwr2AB2cJLELFocuFNrujl4d9giem35TVey64b++vZ6+9ryHm3KqCko - E82zRGaUsVuj5N142/1mkRGfODq+572KWsn+SUUQP4U5WiryFFX0VlDWxG9nDn4btn5c - P6Xn9UH9PAk9rZ/Rr+ijEb4MdEnPwnNRH6NJ8LBpIeISoIqDM9ROVGONA+Ip8fK0W2SR - /Q9AGf1mCmVuZHN0cmVhbQplbmRvYmoKNTEgMCBvYmoKNzA0CmVuZG9iagoyMyAwIG9i - agpbIC9JQ0NCYXNlZCA1MCAwIFIgXQplbmRvYmoKNCAwIG9iago8PCAvVHlwZSAvUGFn - ZXMgL01lZGlhQm94IFswIDAgNjEyIDc5Ml0gL0NvdW50IDEgL0tpZHMgWyAzIDAgUiBd - ID4+CmVuZG9iago1MiAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvT3V0bGluZXMgMiAw - IFIgL1BhZ2VzIDQgMCBSIC9WZXJzaW9uIC8xLjQgPj4KZW5kb2JqCjIgMCBvYmoKPDwg - L0xhc3QgNTMgMCBSIC9GaXJzdCA1NCAwIFIgPj4KZW5kb2JqCjU0IDAgb2JqCjw8IC9D - b3VudCAwIC9EZXN0IFsgMyAwIFIgL1hZWiAwIDU1MyAwIF0gL1RpdGxlIChDYW52YXMg - MSkgPj4KZW5kb2JqCjUzIDAgb2JqCjw8IC9Db3VudCAwIC9EZXN0IFsgMyAwIFIgL1hZ - WiAwIDU1MyAwIF0gL1RpdGxlIChDYW52YXMgMSkgPj4KZW5kb2JqCjU1IDAgb2JqCjw8 - IC9MZW5ndGggNTYgMCBSIC9MZW5ndGgxIDE0NTA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2Rl - ID4+CnN0cmVhbQp4Ab17eWBVxfX/zN3fvu97Xt6WfSchgTxCFrZEFpUECSZAICAoIEZB - oFGBQEQUkUXAXVnFhBDlAYVSDCLWKlpxwb2Ctbapbb+oLZD7vmfuCxGs3/78o7++++7M - 3Lnz5p45c+aczzl3HsIIISVqRTSKTpvbOO+Nz49+BDWvI4T101oWeh/449DHofwZQvSc - GfNmztV99vJrCLFjEJIrZ85ZNGNeZ+VvENLUIuS/q7mpcfr/PP+XcoRyTkMfBc1QIU/i - hyGUK8B1cvPchXe9wKlnwHUaXD8757ZpjTuf7XoSrkn76+c23jVPeED+T4TykuHae2vj - 3KYJi5rb4Rr6REnzbrt9IeNgH4TrZrheOG9B07xf3ndrNlwDzfSbUIfhIB8lFDmp9G+T - RGOEKJo0YxDL8VJ7Qi58ZEiOFIkipEqVWoOQVjdQAQW9wWgyW6w2O3I4XW6PF/mS/MmB - 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 - u+quNIW44P/js/AOaNBUlkos6/6WebNnSFv7/RVNDbDDv/P+FvirRetUr3ff7HnkBtlT - 3jB1WjPJG5s65/mbyjtn+8u9+1qk3/3o9gxyu8Vfvg/NqLi+dt+MaFN5V0u0pYL8xWH/ - 1LIF9dc8a/XAsxaU/cSzykhnC8izpkq/+9Gz6sntqeRZ9eRZ9eRZU6NTpWcRFlTMmlB2 - +0KQTtj+D9vvwxM6R46bVAv/cqkrj+Ht5D8Bd6D/BVDOTaIKZW5kc3RyZWFtCmVuZG9i - ago1NiAwIG9iagoxMDA3MQplbmRvYmoKNTcgMCBvYmoKPDwgL1R5cGUgL0ZvbnREZXNj - cmlwdG9yIC9Bc2NlbnQgNzcwIC9DYXBIZWlnaHQgNjg0IC9EZXNjZW50IC0yMzAgL0Zs - YWdzIDMyCi9Gb250QkJveCBbNSAtMjIxIDc2OCA3MzddIC9Gb250TmFtZSAvQk5OUkxV - K0hlbHZldGljYSAvSXRhbGljQW5nbGUgMCAvU3RlbVYKMCAvTWF4V2lkdGggMTUwMCAv - WEhlaWdodCA1MTMgL0ZvbnRGaWxlMiA1NSAwIFIgPj4KZW5kb2JqCjU4IDAgb2JqClsg - Mjc4IDAgMCAwIDAgMCAwIDAgMzMzIDMzMyAwIDAgMCAwIDI3OCAwIDU1NiA1NTYgNTU2 - IDAgMCAwIDAgMCA1NTYgMCAwIDAKMCAwIDAgNTU2IDAgNjY3IDAgNzIyIDAgMCAwIDAg - MCAwIDAgMCAwIDgzMyA3MjIgNzc4IDY2NyAwIDAgNjY3IDYxMSAwIDAgMAowIDAgMCAw - IDAgMCAwIDAgMCA1NTYgNTU2IDUwMCA1NTYgNTU2IDI3OCA1NTYgNTU2IDIyMiAwIDUw - MCAyMjIgODMzIDU1NiA1NTYKNTU2IDAgMzMzIDUwMCAyNzggNTU2IDUwMCA3MjIgMCA1 - MDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMAowIDAgMCAwIDAg - MCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAw - IDAgMCAwIDAgMCAwCjAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAg - MCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAKMCAwIDAgMCAwIDAgMCA1 - MDAgXQplbmRvYmoKMjQgMCBvYmoKPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1RydWVU - eXBlIC9CYXNlRm9udCAvQk5OUkxVK0hlbHZldGljYSAvRm9udERlc2NyaXB0b3IKNTcg - MCBSIC9XaWR0aHMgNTggMCBSIC9GaXJzdENoYXIgMzIgL0xhc3RDaGFyIDIyMiAvRW5j - b2RpbmcgL01hY1JvbWFuRW5jb2RpbmcKPj4KZW5kb2JqCjEgMCBvYmoKPDwgL1RpdGxl - IChVbnRpdGxlZCkgL0F1dGhvciAoYnJhbmRvbmgpIC9DcmVhdG9yIChPbW5pR3JhZmZs - ZSkgL1Byb2R1Y2VyIChNYWMgT1MgWCAxMC41LjggUXVhcnR6IFBERkNvbnRleHQpCi9D - cmVhdGlvbkRhdGUgKEQ6MjAwOTExMjAyMzExMTVaMDAnMDAnKSAvTW9kRGF0ZSAoRDoy - MDA5MTEyMDIzMTExNVowMCcwMCcpCj4+CmVuZG9iagp4cmVmCjAgNTkKMDAwMDAwMDAw - MCA2NTUzNSBmIAowMDAwMDQ0NDU1IDAwMDAwIG4gCjAwMDAwMzMxOTAgMDAwMDAgbiAK - MDAwMDAwMTYyNCAwMDAwMCBuIAowMDAwMDMzMDI3IDAwMDAwIG4gCjAwMDAwMDAwMjIg - MDAwMDAgbiAKMDAwMDAwMTYwNCAwMDAwMCBuIAowMDAwMDAxNzI4IDAwMDAwIG4gCjAw - MDAwMzE0MDMgMDAwMDAgbiAKMDAwMDAwMTk2MSAwMDAwMCBuIAowMDAwMDAzMDUxIDAw - MDAwIG4gCjAwMDAwMDY0NzcgMDAwMDAgbiAKMDAwMDAwNzIyMiAwMDAwMCBuIAowMDAw - MDA1NzEyIDAwMDAwIG4gCjAwMDAwMDY0NTcgMDAwMDAgbiAKMDAwMDAwMzgzNiAwMDAw - MCBuIAowMDAwMDA0OTI3IDAwMDAwIG4gCjAwMDAwMDQ5NDcgMDAwMDAgbiAKMDAwMDAw - NTY5MiAwMDAwMCBuIAowMDAwMDAzMDcxIDAwMDAwIG4gCjAwMDAwMDM4MTYgMDAwMDAg - biAKMDAwMDAwNzI0MiAwMDAwMCBuIAowMDAwMDA3OTg3IDAwMDAwIG4gCjAwMDAwMzI5 - OTAgMDAwMDAgbiAKMDAwMDA0NDI4MCAwMDAwMCBuIAowMDAwMDMwNDUxIDAwMDAwIG4g - CjAwMDAwMjE5NzMgMDAwMDAgbiAKMDAwMDAyNTg1OCAwMDAwMCBuIAowMDAwMDMyMTI1 - IDAwMDAwIG4gCjAwMDAwMTQ0MjggMDAwMDAgbiAKMDAwMDAxNjkyMiAwMDAwMCBuIAow - MDAwMDEwNTIyIDAwMDAwIG4gCjAwMDAwMTQ0MDcgMDAwMDAgbiAKMDAwMDAxOTQ1OCAw - MDAwMCBuIAowMDAwMDIxOTUyIDAwMDAwIG4gCjAwMDAwMjk3MjggMDAwMDAgbiAKMDAw - MDAyNTg3OSAwMDAwMCBuIAowMDAwMDI5MDIxIDAwMDAwIG4gCjAwMDAwMTY5NDMgMDAw - MDAgbiAKMDAwMDAxOTQzNyAwMDAwMCBuIAowMDAwMDA4MDA3IDAwMDAwIG4gCjAwMDAw - MTA1MDEgMDAwMDAgbiAKMDAwMDAyOTA0MiAwMDAwMCBuIAowMDAwMDI5NzA4IDAwMDAw - IG4gCjAwMDAwMjk3NjUgMDAwMDAgbiAKMDAwMDAzMDQzMSAwMDAwMCBuIAowMDAwMDMw - NDg4IDAwMDAwIG4gCjAwMDAwMzEzODMgMDAwMDAgbiAKMDAwMDAzMTQzOSAwMDAwMCBu - IAowMDAwMDMyMTA1IDAwMDAwIG4gCjAwMDAwMzIxNjIgMDAwMDAgbiAKMDAwMDAzMjk3 - MCAwMDAwMCBuIAowMDAwMDMzMTEwIDAwMDAwIG4gCjAwMDAwMzMzMTYgMDAwMDAgbiAK - MDAwMDAzMzIzOCAwMDAwMCBuIAowMDAwMDMzMzk0IDAwMDAwIG4gCjAwMDAwNDM1NTYg - MDAwMDAgbiAKMDAwMDA0MzU3OCAwMDAwMCBuIAowMDAwMDQzNzk4IDAwMDAwIG4gCnRy - YWlsZXIKPDwgL1NpemUgNTkgL1Jvb3QgNTIgMCBSIC9JbmZvIDEgMCBSIC9JRCBbIDw0 - MjZkMDljZjFjMDY3M2I0NTU4MGUzOGJlY2FkZWY4OD4KPDQyNmQwOWNmMWMwNjczYjQ1 - NTgwZTM4YmVjYWRlZjg4PiBdID4+CnN0YXJ0eHJlZgo0NDY1NwolJUVPRgoxIDAgb2Jq - Cjw8L0F1dGhvciAoYnJhbmRvbmgpL0NyZWF0aW9uRGF0ZSAoRDoyMDA5MTEyMDIyNTQw - MFopL0NyZWF0b3IgKE9tbmlHcmFmZmxlIDUuMi4xKS9Nb2REYXRlIChEOjIwMDkxMTIw - MjMxMTAwWikvUHJvZHVjZXIgKE1hYyBPUyBYIDEwLjUuOCBRdWFydHogUERGQ29udGV4 - dCkvVGl0bGUgKHBhY2tldF9mbG93X2Zsb3djaGFydCk+PgplbmRvYmoKeHJlZgoxIDEK - MDAwMDA0NTk5NSAwMDAwMCBuIAp0cmFpbGVyCjw8L0lEIFs8NDI2ZDA5Y2YxYzA2NzNi - NDU1ODBlMzhiZWNhZGVmODg+IDw0MjZkMDljZjFjMDY3M2I0NTU4MGUzOGJlY2FkZWY4 - OD5dIC9JbmZvIDEgMCBSIC9QcmV2IDQ0NjU3IC9Sb290IDUyIDAgUiAvU2l6ZSA1OT4+ - CnN0YXJ0eHJlZgo0NjE5NwolJUVPRgo= - - QuickLookThumbnail - - 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 - Yy4sIDIwMDkA - - ReadOnly - NO - RowAlign - 1 - RowSpacing - 36 - SheetTitle - Canvas 1 - SmartAlignmentGuidesActive - YES - SmartDistanceGuidesActive - YES - UniqueID - 1 - UseEntirePage - - VPages - 1 - WindowInfo - - CurrentSheet - 0 - ExpandedCanvases - - - name - Canvas 1 - - - FitInWindow - - Frame - {{759, 198}, {710, 887}} - ListView - - OutlineWidth - 142 - RightSidebar - - ShowRuler - - Sidebar - - SidebarWidth - 120 - VisibleRegion - {{0, -204}, {754.688, 962.062}} - Zoom - 0.76190477609634399 - ZoomValues - - - Canvas 1 - 0.0 - 1 - - - - saveQuickLookFiles - YES - - diff --git a/openflow/hw-lib/automake.mk b/openflow/hw-lib/automake.mk deleted file mode 100644 index 204e1217..00000000 --- a/openflow/hw-lib/automake.mk +++ /dev/null @@ -1,28 +0,0 @@ -# -# Hardware library dependency file definitions. -# - -if NF2 -# -# NetFPGA hardware library -# -noinst_LIBRARIES += hw-lib/libnf2.a - -hw_lib_libnf2_a_SOURCES = \ - hw-lib/nf2/hw_flow.c \ - hw-lib/nf2/hw_flow.h \ - hw-lib/nf2/nf2_lib.c \ - hw-lib/nf2/nf2_lib.h \ - hw-lib/nf2/nf2_drv.c \ - hw-lib/nf2/nf2_drv.h \ - hw-lib/nf2/nf2.h \ - hw-lib/nf2/debug.h \ - hw-lib/nf2/reg_defines_openflow_switch.h \ - hw-lib/nf2/nf2util.c \ - hw-lib/nf2/nf2util.h - -hw_lib_nf2_a_CPPFLAGS = $(AM_CPPFLAGS) $(OF_CPP_FLAGS) -DHWTABLE_NO_DEBUG -hw_lib_nf2_a_CPPFLAGS += -I hw-lib/nf2 -hw_lib_nf2_a_CPPFLAGS += -I $(HW_SYSTEM)/include - -endif diff --git a/openflow/hw-lib/nf2/README b/openflow/hw-lib/nf2/README deleted file mode 100644 index 7e111b30..00000000 --- a/openflow/hw-lib/nf2/README +++ /dev/null @@ -1,56 +0,0 @@ -NetFPGA Hardware Table - Date - 03/09/10 ----------------------------------------- - -This library creates and maintains a single software table that contains all -the flows that are currently held in the NetFPGA card. The card itself splits -exact match flows into SRAM and wildcard match flows into TCAMs. Currently -there are 24 usable wildcard flow entries and 32,768 available exact match -entries. The exact match table is hashed so actual available entries will be -varied. - -Installation ----------------------------------------- - -First build OpenFlow ensuring you include the directive to build the -openflow_netfpga hardware table in your configure statement: - - % ./configure --enable-hw-lib=nf2 - -For further help regarding building OpenFlow please see the INSTALL file in -the OpenFlow root directory. - -Platform support ----------------- - -OpenFlow v1.0 with NetFPGA hardware table has been tested on CentOS5.4 -(Linux 2.6.18), which is the officially supported platform of NetFPGA. - -Running ----------------------------------------- - -Use nf2_download to download the openflow_switch.bit file that is located in -the /datapath/hwtable_nf2 folder: - - % nf2_download -r /hw-lib/nf2/openflow_switch.bit - -'-r' option enables PHY interrupt for its link status changing, and OpenFlow -switch can detect it. - -Run ofdatapth with indicating *all* the NetFPGA interfaces: - - % /udatapath/ofdatapath punix:/var/run/test \ - -i nf2c0,nf2c1,nf2c2,nf2c3 - -At this point your OpenFlow switch should be ready to go. -The way you start up ofprotocol is as same as you do for software reference -switch. - -Known Issues ----------------------------------------- -* There is currently no support for priority amongst wildcard-match entries. - -Contact -------- -e-mail: openflow-discuss@lists.stanford.edu -www: http://openflowswitch.org/ diff --git a/openflow/hw-lib/nf2/debug.h b/openflow/hw-lib/nf2/debug.h deleted file mode 100644 index 9cb2b10d..00000000 --- a/openflow/hw-lib/nf2/debug.h +++ /dev/null @@ -1,105 +0,0 @@ - -#ifndef OF_HW_DEBUG_H -#define OF_HW_DEBUG_H 1 - -#include -#include - -#if !defined(HWTABLE_NO_DEBUG) -extern int of_hw_debug; -#define dbg_send(mod, lvl, fmt, args...) \ - if (of_hw_debug >= (lvl)) fprintf(stderr, fmt, ##args) - -#define DBG_LVL_NONE -1 /* All output off */ -#define DBG_LVL_ERROR 0 /* Default value */ -#define DBG_LVL_ALWAYS 0 /* For requested dump output */ -#define DBG_LVL_WARN 1 -#define DBG_LVL_VERBOSE 2 -#define DBG_LVL_VVERB 3 /* Include success indications */ - -/* Sorry for the lazy syntax here. */ -#define DBG_CHECK(lvl) (((lvl) >= 0) && (of_hw_debug >= (lvl))) -#define DBG_ERROR(fmt, args...) dbg_send(0, DBG_LVL_ERROR, fmt, ##args) -#define DBG_ALWAYS(fmt, args...) dbg_send(0, DBG_LVL_ALWAYS, fmt, ##args) -#define DBG_WARN(fmt, args...) dbg_send(0, DBG_LVL_WARN, fmt, ##args) -#define DBG_VERBOSE(fmt, args...) dbg_send(0, DBG_LVL_VERBOSE, fmt, ##args) -#define DBG_VVERB(fmt, args...) dbg_send(0, DBG_LVL_VVERB, fmt, ##args) -#define DBG_NONE(fmt, args...) -/* Same as DEBUG_ALWAYS */ -#define DEBUGK(fmt, args...) dbg_send(0, DBG_LVL_ALWAYS, fmt, ##args) - -#define REPORT_ERROR(str) \ - DBG_ERROR("ERROR: %s:%d. %s\n", __FUNCTION__, __LINE__, str) - -/* Default debugging location string */ -#define ANNOUNCE_LOCATION DBG_VVERB("%s: %d\n", __FUNCTION__, __LINE__) -#define DBG_INCR(cnt) (++(cnt)) - -/* Should assert return? Not presently */ -#define ASSERT(cond) \ - if (!(cond)) DBG_ERROR("ASSERTION %s IN %s FAILED LINE %d\n", \ - #cond, __FUNCTION__, __LINE__) - -/* DEBUG for HW flow lists */ -#define HW_FLOW_MAGIC 0xba5eba11 -#define HW_FLOW_MAKE_VALID(hf) (hf)->magic = HW_FLOW_MAGIC -#define HW_FLOW_IS_VALID(hf) \ - (((hf) != NULL) && ((hf)->magic == HW_FLOW_MAGIC)) - -/* - * Carry out an operation and check for error, optionally returning - * from the calling routine. To avoid compiler - * warnings in routines with void return, we give two macros. - * - * WARNING: This check uses rv != 0 (not just rv < 0). - */ - -#define TRY(op, str) do { \ - int rv; \ - if (((rv = (op)) < 0)) { \ - DBG_ERROR("ERROR %d: %s\n", rv, str); \ - return rv; \ - } else { \ - DBG_NONE("%s: success\n", str); \ - } \ - } while (0) - -#define TRY_NR(op, str) do { \ - int rv; \ - if (((rv = (op)) != 0)) { \ - DBG_ERROR("ERROR %d: %s\n", rv, str); \ - } else { \ - DBG_NONE("%s: success\n", str); \ - } \ - } while (0) - -#else /* No debugging */ - -#define DBG_CHECK(lvl) 0 -#define ANNOUNCE_LOCATION -#define ACT_STRING(action) "" -#define DBG_INCR(cnt) -#define DBG_ERROR(fmt, args...) -#define DBG_ALWAYS(fmt, args...) -#define DBG_WARN(fmt, args...) -#define DBG_VERBOSE(fmt, args...) -#define DBG_VVERB(fmt, args...) -#define DBG_NONE(fmt, args...) -#define DEBUGK(fmt, args...) -#define REPORT_ERROR(str) - -#define ASSERT(cond) - -#define HW_FLOW_MAKE_VALID(hf) -#define HW_FLOW_IS_VALID(hf) 1 - -#define TRY(op, str) do { \ - int rv; \ - if (((rv = (op)) != 0)) return rv; \ - } while (0) - -#define TRY_NR(op, str) (void)op - -#endif /* !defined(HWTABLE_NO_DEBUG) */ - -#endif /* OF_HW_DEBUG_H */ diff --git a/openflow/hw-lib/nf2/hw_flow.c b/openflow/hw-lib/nf2/hw_flow.c deleted file mode 100644 index d59a7713..00000000 --- a/openflow/hw-lib/nf2/hw_flow.c +++ /dev/null @@ -1,514 +0,0 @@ -/*- - * Copyright (c) 2008, 2009, 2010 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#include - -#include -#include "list.h" -#include "udatapath/switch-flow.h" -#include "udatapath/datapath.h" -#include "reg_defines_openflow_switch.h" -#include "nf2util.h" -#include "hw_flow.h" -#include "nf2_drv.h" -#include "nf2_lib.h" -#include "debug.h" - -struct nf2_flowtable { - struct of_hw_driver hw_driver; - unsigned int max_flows; - unsigned int num_flows; - struct list flows; - struct list iter_flows; - unsigned long int next_serial; -}; - -static struct sw_flow *nf2_lookup_flowtable(struct sw_table *, - const struct sw_flow_key *); -static int nf2_install_flow(struct sw_table *, struct sw_flow *); -static int nf2_modify_flow(struct sw_table *, const struct sw_flow_key *, - uint16_t, int, const struct ofp_action_header *, - size_t); -static int do_uninstall(struct sw_flow *, struct list *); -static int nf2_has_conflict(struct sw_table *, const struct sw_flow_key *, - uint16_t, int); -static int nf2_uninstall_flow_wrap(struct datapath *, struct sw_table *, - const struct sw_flow_key *, uint16_t, - uint16_t, int); -static int nf2_uninstall_flow(struct datapath *, struct sw_table *, - const struct sw_flow_key *, uint16_t, - uint16_t, int, int); -static void nf2_flow_timeout(struct sw_table *, struct list *); - -static void nf2_destroy_flowtable(struct sw_table *); -static int nf2_iterate_flowtable(struct sw_table *, - const struct sw_flow_key *, - uint16_t, struct sw_table_position *, - int (*)(struct sw_flow *, void *), void *); -static void nf2_get_flowstats(struct sw_table *, struct sw_table_stats *); -static int nf2_get_portstats(of_hw_driver_t *, int, struct ofp_port_stats *); - -#if !defined(HWTABLE_NO_DEBUG) -int of_hw_debug = DBG_LVL_WARN; -#endif - -#define DELETE_FLOW 0 -#define KEEP_FLOW 1 - -static struct sw_flow * -nf2_lookup_flowtable(struct sw_table *flowtab, const struct sw_flow_key *key) -{ - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - struct sw_flow *flow; - - LIST_FOR_EACH(flow, struct sw_flow, node, &nf2flowtab->flows) { - if (flow_matches_1wild(key, &flow->key)) { - return flow; - } - } - - return NULL; -} - -static int -nf2_install_flow(struct sw_table *flowtab, struct sw_flow *flow) -{ - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - - /* Delete flows that match exactly. */ - nf2_uninstall_flow(NULL, flowtab, &flow->key, OFPP_NONE, - flow->priority, true, KEEP_FLOW); - - if (nf2_are_actions_supported(flow)) { - if (nf2_build_and_write_flow(flow)) { - /* Not successful */ - return 0; - } - } else { - /* Unsupported actions or no device. */ - return 0; - } - - nf2flowtab->num_flows++; - list_push_front(&nf2flowtab->flows, &flow->node); - list_push_front(&nf2flowtab->iter_flows, &flow->iter_node); - - return 1; -} - -static int -nf2_modify_flow(struct sw_table *flowtab, const struct sw_flow_key *key, - uint16_t priority, int strict, - const struct ofp_action_header *actions, size_t actions_len) -{ - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - struct sw_flow *flow; - unsigned int count = 0; - - LIST_FOR_EACH(flow, struct sw_flow, node, &nf2flowtab->flows) { - if (flow_matches_desc(&flow->key, key, strict) - && (!strict || flow->priority == priority)) { - flow_replace_acts(flow, actions, actions_len); - if (nf2_are_actions_supported(flow)) { - count += nf2_modify_acts(flow); - } - } else { - return 0; - } - } - - return count; -} - -static int -nf2_has_conflict(struct sw_table *flowtab, const struct sw_flow_key *key, - uint16_t priority, int strict) -{ - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - struct sw_flow *flow; - - LIST_FOR_EACH(flow, struct sw_flow, node, &nf2flowtab->flows) { - - if (flow_matches_2desc(&flow->key, key, strict) - && (flow->priority == priority)) { - return true; - } - } - - return false; -} - -static int -do_uninstall(struct sw_flow *flow, struct list *deleted) -{ - if (flow != NULL && flow->private != NULL) { - list_remove(&flow->node); - list_remove(&flow->iter_node); - list_push_back(deleted, &flow->node); - return 1; - } - - return 0; -} - -static int -nf2_uninstall_flow_wrap(struct datapath *dpinst, struct sw_table *flowtab, - const struct sw_flow_key *key, uint16_t out_port, - uint16_t priority, int strict) -{ - return nf2_uninstall_flow(dpinst, flowtab, key, out_port, - priority, strict, DELETE_FLOW); -} - -static int -nf2_uninstall_flow(struct datapath *dpinst, struct sw_table *flowtab, - const struct sw_flow_key *key, uint16_t out_port, - uint16_t priority, int strict, int keep_flow) -{ - struct nf2device *dev; - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - struct sw_flow *flow, *n; - struct nf2_flow *nf2flow; - unsigned int count = 0; - struct list deleted; - list_init(&deleted); - - dev = nf2_get_net_device(); - if (dev == NULL) - return 0; - - LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &nf2flowtab->flows) { - if (flow_matches_desc(&flow->key, key, strict) - && (!strict || flow->priority == priority) - && flow_has_out_port(flow, out_port)) { - nf2flow = flow->private; - - if (nf2flow != NULL) { - flow->packet_count - += nf2_get_packet_count(dev, - nf2flow); - flow->byte_count += nf2_get_byte_count(dev, - nf2flow); - } - count += do_uninstall(flow, &deleted); - if (keep_flow == KEEP_FLOW) { - /* Delete private in sw_flow here */ - nf2_delete_private(flow->private); - } - } - } - nf2flowtab->num_flows -= count; - - nf2_free_net_device(dev); - - if (keep_flow == DELETE_FLOW) { - /* Notify DP of deleted flows and delete the flow */ - LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &deleted) { - dp_send_flow_end(dpinst, flow, flow->reason); - list_remove(&flow->node); - nf2_delete_private(flow->private); - flow_free(flow); - } - } - - return count; -} - -static void -nf2_flow_timeout(struct sw_table *flowtab, struct list *deleted) -{ - struct nf2device *dev; - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - struct sw_flow *flow, *n; - struct nf2_flow *nf2flow; - int num_uninst_flows = 0; - uint64_t num_forw_packets = 0; - uint64_t now = time_msec(); - - dev = nf2_get_net_device(); - if (dev == NULL) { - DBG_ERROR("Could not open NetFPGA device\n"); - return; - } - - /* LOCK; */ - /* FIXME */ - LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &nf2flowtab->flows) { - nf2flow = flow->private; - if (nf2flow != NULL) { - num_forw_packets = flow->packet_count - + nf2_get_packet_count(dev, nf2flow); - flow->byte_count += nf2_get_byte_count(dev, nf2flow); - } - if (num_forw_packets > flow->packet_count) { - flow->packet_count = num_forw_packets; - flow->used = now; - } - - if (flow_timeout(flow)) { - num_uninst_flows += do_uninstall(flow, deleted); - nf2_delete_private(flow->private); - } - } - - /* UNLOCK; */ - - nf2_clear_watchdog(dev); - nf2_free_net_device(dev); - - nf2flowtab->num_flows -= num_uninst_flows; -} - -static void -nf2_destroy_flowtable(struct sw_table *flowtab) -{ - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - struct nf2_flow *nf2flow = NULL; - - if (nf2flowtab == NULL) - return; - - while (!list_is_empty(&nf2flowtab->flows)) { - struct sw_flow *flow - = CONTAINER_OF(list_front(&nf2flowtab->flows), - struct sw_flow, node); - list_remove(&flow->node); - if (flow->private) { - nf2flow = (struct nf2_flow *)flow->private; - - if (nf2flow->type == NF2_TABLE_EXACT) { - nf2_add_free_exact(nf2flow); - } else if (nf2flow->type == NF2_TABLE_WILDCARD) { - nf2_add_free_wildcard(nf2flow); - } - flow->private = NULL; - } - flow_free(flow); - } - free(nf2flowtab); - - nf2_destroy_exact_freelist(); - nf2_destroy_wildcard_freelist(); -} - -static int -nf2_iterate_flowtable(struct sw_table *flowtab, const struct sw_flow_key *key, - uint16_t out_port, struct sw_table_position *position, - int (*callback) (struct sw_flow *, void *), - void *private) -{ - unsigned long start; - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - struct sw_flow *flow; - int error = 0; - - start = ~position->private[0]; - LIST_FOR_EACH(flow, struct sw_flow, iter_node, &nf2flowtab->iter_flows) { - if (flow->serial <= start - && flow_matches_2wild(key, &flow->key) - && flow_has_out_port(flow, out_port)) { - error = callback(flow, private); - if (error != 0) { - position->private[0] = ~flow->serial; - return error; - } - } - } - - return error; -} - -static void -nf2_get_flowstats(struct sw_table *flowtab, struct sw_table_stats *stats) -{ - struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; - struct nf2device *dev; - unsigned long int num_matched = 0; - unsigned long int num_missed = 0; - - dev = nf2_get_net_device(); - if (dev == NULL) { - DBG_VERBOSE("Could not open NetFPGA device\n"); - } else { - num_matched = nf2_get_matched_count(dev); - num_missed = nf2_get_missed_count(dev); - nf2_free_net_device(dev); - } - - stats->name = "nf2"; - stats->wildcards = OPENFLOW_WILDCARD_TABLE_SIZE - - RESERVED_FOR_CPU2NETFPGA; - stats->n_flows = nf2flowtab->num_flows; - stats->max_flows = nf2flowtab->max_flows; - stats->n_lookup = num_matched + num_missed; - stats->n_matched = num_matched; -} - -static int -nf2_get_portstats(of_hw_driver_t *hw_drv, int of_port, - struct ofp_port_stats *stats) -{ - int nf2_port; - struct nf2_port_info *nf2portinfo; - struct nf2device *dev; - - if ((of_port > NF2_PORT_NUM) || (of_port <= 0)) { - return 1; - } - nf2_port = of_port - 1; - - nf2portinfo = calloc(1, sizeof(struct nf2_port_info)); - if (nf2portinfo == NULL) { - return 1; - } - - dev = nf2_get_net_device(); - if (dev == NULL) { - free(nf2portinfo); - return 1; - } - - if (nf2_get_port_info(dev, nf2_port, nf2portinfo)) { - nf2_free_net_device(dev); - free(nf2portinfo); - return 1; - } - - stats->rx_packets = (uint64_t)(nf2portinfo->rx_q_num_pkts_stored); - stats->rx_dropped = (uint64_t)(nf2portinfo->rx_q_num_pkts_dropped_full - + nf2portinfo->rx_q_num_pkts_dropped_bad); - stats->rx_bytes = (uint64_t)(nf2portinfo->rx_q_num_bytes_pushed); - stats->tx_packets = (uint64_t)(nf2portinfo->tx_q_num_pkts_sent); - stats->tx_bytes = (uint64_t)(nf2portinfo->tx_q_num_bytes_pushed); - - /* Not supported */ - stats->tx_dropped = -1; - stats->rx_errors = -1; - stats->tx_errors = -1; - stats->rx_frame_err = -1; - stats->rx_over_err = -1; - stats->rx_crc_err = -1; - stats->collisions = -1; - - nf2_free_net_device(dev); - free(nf2portinfo); - return 0; -} - -/* - * Create and initialize a new hardware datapath object - */ - -of_hw_driver_t * -new_of_hw_driver(struct datapath *dp) -{ - struct sw_table *sw_tab; - of_hw_driver_t *hw_drv; - struct nf2device *dev; - struct nf2_flowtable *nf2flowtab; - - dev = nf2_get_net_device(); - if (dev == NULL) { - return NULL; - } - nf2_reset_card(dev); - nf2_free_net_device(dev); - - nf2flowtab = calloc(1, sizeof(*nf2flowtab)); - if (nf2flowtab == NULL) { - return NULL; - } - - /* These all point to the same place */ - hw_drv = &nf2flowtab->hw_driver; - sw_tab = &hw_drv->sw_table; - - sw_tab->n_lookup = 0; - sw_tab->n_matched = 0; - - /* Fill out the function pointers */ - sw_tab->lookup = nf2_lookup_flowtable; - sw_tab->insert = nf2_install_flow; - sw_tab->modify = nf2_modify_flow; - sw_tab->has_conflict = nf2_has_conflict; - - sw_tab->delete = nf2_uninstall_flow_wrap; - sw_tab->timeout = nf2_flow_timeout; - - sw_tab->destroy = nf2_destroy_flowtable; - sw_tab->iterate = nf2_iterate_flowtable; - sw_tab->stats = nf2_get_flowstats; - - nf2flowtab->max_flows = OPENFLOW_NF2_EXACT_TABLE_SIZE - + OPENFLOW_WILDCARD_TABLE_SIZE - RESERVED_FOR_CPU2NETFPGA; - nf2flowtab->num_flows = 0; - list_init(&nf2flowtab->flows); - list_init(&nf2flowtab->iter_flows); - nf2flowtab->next_serial = 0; - - if (nf2_init_wildcard_freelist()) { - DBG_ERROR("Could not create wildcard freelist\n"); - free(nf2flowtab); - return NULL; - } - if (nf2_write_static_wildcard()) { - DBG_ERROR("Could not create wildcard freelist\n"); - free(nf2flowtab); - return NULL; - } - if (nf2_init_exact_freelist()) { - DBG_ERROR("Could not create exact freelist\n"); - free(nf2flowtab); - return NULL; - } - - hw_drv->table_stats_get = NULL; - hw_drv->port_stats_get = nf2_get_portstats; - hw_drv->flow_stats_get = NULL; - hw_drv->aggregate_stats_get = NULL; - - hw_drv->port_add = NULL; - hw_drv->port_remove = NULL; - hw_drv->port_link_get = NULL; - hw_drv->port_enable_set = NULL; - hw_drv->port_enable_get = NULL; - hw_drv->port_queue_config = NULL; - hw_drv->port_queue_remove = NULL; - hw_drv->port_change_register = NULL; - - hw_drv->packet_send = NULL; - hw_drv->packet_receive_register = NULL; - - hw_drv->ioctl = NULL; - - return hw_drv; -} diff --git a/openflow/hw-lib/nf2/hw_flow.h b/openflow/hw-lib/nf2/hw_flow.h deleted file mode 100644 index 96e0320f..00000000 --- a/openflow/hw-lib/nf2/hw_flow.h +++ /dev/null @@ -1,56 +0,0 @@ -/*- - * Copyright (c) 2008, 2009, 2010 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#ifndef HWTABLE_NF2_NF2_FLOWTABLE_ -#define HWTABLE_NF2_NF2_FLOWTABLE_ - -#define RESERVED_FOR_CPU2NETFPGA 8 - -struct nf2_flow { - struct list node; - uint32_t pos; - uint32_t type; - uint32_t hw_packet_count; - uint32_t hw_byte_count; -}; - -enum nf2_of_table_type { - NF2_TABLE_EXACT, - NF2_TABLE_WILDCARD -}; - -/* Remove the commentout of the following 'define' line - * if you want to enable NetFPGA watchdog timer capability. - */ -/* #define NF2_WATCHDOG 1 */ - -#endif diff --git a/openflow/hw-lib/nf2/nf2.h b/openflow/hw-lib/nf2/nf2.h deleted file mode 100644 index 519f52da..00000000 --- a/openflow/hw-lib/nf2/nf2.h +++ /dev/null @@ -1,452 +0,0 @@ -/* **************************************************************************** - * $Id: nf2.h 5575 2009-05-13 18:44:26Z grg $ - * - * Module: nf2.h - * Project: NetFPGA 2 Linux Kernel Driver - * Description: Header file for kernel driver - * - * Change history: - * - */ - -#ifndef _NF2_H -#define _NF2_H 1 - -#define NF2_DEV_NAME "nf2" - -/* Include for socket IOCTLs */ -#include - -/* Maximum number of interfaces */ -#ifndef MAX_IFACE -#define MAX_IFACE 4 -#endif - -/* - * Register names and locations. - * - * Note that these names are not necessarily identical to - * those in NF2/hw/common/src/defines - */ - -/* CPCI registers */ -#define CPCI_REG_ID 0x000 -#define CPCI_REG_BOARD_ID 0x004 -#define CPCI_REG_CTRL 0x008 -#define CPCI_REG_RESET 0x00c -#define CPCI_REG_ERROR 0x010 -#define CPCI_REG_DUMMY 0x020 -#define CPCI_REG_INTERRUPT_MASK 0x040 -#define CPCI_REG_INTERRUPT_STATUS 0x044 -#define CPCI_REG_PROG_DATA 0x100 -#define CPCI_REG_PROG_STATUS 0x104 -#define CPCI_REG_PROG_CTRL 0x108 -#define CPCI_REG_DMA_I_ADDR 0x140 -#define CPCI_REG_DMA_E_ADDR 0x144 -#define CPCI_REG_DMA_I_SIZE 0x148 -#define CPCI_REG_DMA_E_SIZE 0x14c -#define CPCI_REG_DMA_I_CTRL 0x150 -#define CPCI_REG_DMA_E_CTRL 0x154 -#define CPCI_REG_DMA_MAX_XFER_TIME 0x180 -#define CPCI_REG_DMA_MAX_RETRIES 0x184 -#define CPCI_REG_CNET_MAX_XFER_TIME 0x188 -#define CPCI_REG_DMA_I_PKT_CNT 0x400 -#define CPCI_REG_DMA_E_PKT_CNT 0x404 -#define CPCI_REG_CPCI_REG_RD_CNT 0x408 -#define CPCI_REG_CPCI_REG_WR_CNT 0x40c -#define CPCI_REG_CNET_REG_RD_CNT 0x410 -#define CPCI_REG_CNET_REG_WR_CNT 0x414 - -#define CPCI_REG_N_CLK_COUNT 0x500 -#define CPCI_REG_P_MAX 0x504 -#define CPCI_REG_N_EXP 0x508 -#define CPCI_REG_P_CLK_CTR 0x510 -#define CPCI_REG_RESET_CTR 0x520 - - - -/* Base address for CNET registers */ -#define CNET_REG_BASE 0x400000 - - -/* Added by nweaver for building memory manipulation - utilities */ -/* 2 MB SRAM size on current board, MAX and SIZE will - need to be changed if upgraded to 4 MB SRAMs */ -#define SRAM_SIZE 0x200000 - -#define SRAM_1_BASE 0x800000 -#define SRAM_1_MAX 0x9FFFFF - -#define SRAM_2_BASE 0xC00000 -#define SRAM_2_MAX 0xDFFFFF -/* end nweaver addition */ - - -/* Device ID registers */ -#define NF2_DEVICE_ID 0x0400000 -#define NF2_REVISION 0x0400004 -#define NF2_DEVICE_STR 0x0400008 - - -/* CNET registers */ -#define CNET_REG_ID (CNET_REG_BASE + 0x000) -#define CNET_REG_CTRL (CNET_REG_BASE + 0x004) -#define CNET_REG_RESET (CNET_REG_BASE + 0x008) -#define CNET_REG_ERROR (CNET_REG_BASE + 0x00C) -#define CNET_REG_ENABLE (CNET_REG_BASE + 0x010) -#define CNET_REG_WR_SRAM1_EOP (CNET_REG_BASE + 0x0F0) -#define CNET_REG_RD_SRAM1_EOP (CNET_REG_BASE + 0x0F4) -#define CNET_REG_WR_SRAM2_EOP (CNET_REG_BASE + 0x0F8) -#define CNET_REG_RD_SRAM2_EOP (CNET_REG_BASE + 0x0FC) -#define CNET_REG_MF_STATUS_0 (CNET_REG_BASE + 0x100) -#define CNET_REG_MF_TX_PKTS_SENT_0 (CNET_REG_BASE + 0x104) -#define CNET_REG_MF_RX_PKTS_RCVD_0 (CNET_REG_BASE + 0x108) -#define CNET_REG_MF_RX_PKTS_LOST_0 (CNET_REG_BASE + 0x10C) -#define CNET_REG_MAC_CONFIG_0 (CNET_REG_BASE + 0x110) -#define CNET_REG_MF_STATUS_1 (CNET_REG_BASE + 0x140) -#define CNET_REG_MF_TX_PKTS_SENT_1 (CNET_REG_BASE + 0x144) -#define CNET_REG_MF_RX_PKTS_RCVD_1 (CNET_REG_BASE + 0x148) -#define CNET_REG_MF_RX_PKTS_LOST_1 (CNET_REG_BASE + 0x14C) -#define CNET_REG_MAC_CONFIG_1 (CNET_REG_BASE + 0x150) -#define CNET_REG_MF_STATUS_2 (CNET_REG_BASE + 0x180) -#define CNET_REG_MF_TX_PKTS_SENT_2 (CNET_REG_BASE + 0x184) -#define CNET_REG_MF_RX_PKTS_RCVD_2 (CNET_REG_BASE + 0x188) -#define CNET_REG_MF_RX_PKTS_LOST_2 (CNET_REG_BASE + 0x18C) -#define CNET_REG_MAC_CONFIG_2 (CNET_REG_BASE + 0x190) -#define CNET_REG_MF_STATUS_3 (CNET_REG_BASE + 0x1C0) -#define CNET_REG_MF_TX_PKTS_SENT_3 (CNET_REG_BASE + 0x1C4) -#define CNET_REG_MF_RX_PKTS_RCVD_3 (CNET_REG_BASE + 0x1C8) -#define CNET_REG_MF_RX_PKTS_LOST_3 (CNET_REG_BASE + 0x1CC) -#define CNET_REG_MAC_CONFIG_3 (CNET_REG_BASE + 0x1D0) -#define CNET_REG_RXQ_NUM_PKTS_0 (CNET_REG_BASE + 0x200) -#define CNET_REG_RXQ_POINTERS_0 (CNET_REG_BASE + 0x204) -#define CNET_REG_RXQ_NUM_PKTS_1 (CNET_REG_BASE + 0x240) -#define CNET_REG_RXQ_POINTERS_1 (CNET_REG_BASE + 0x244) -#define CNET_REG_RXQ_NUM_PKTS_2 (CNET_REG_BASE + 0x280) -#define CNET_REG_RXQ_POINTERS_2 (CNET_REG_BASE + 0x284) -#define CNET_REG_RXQ_NUM_PKTS_3 (CNET_REG_BASE + 0x2C0) -#define CNET_REG_RXQ_POINTERS_3 (CNET_REG_BASE + 0x2C4) - -#define CNET_REG_MF_RX_PKTS_LOST_BAD_FCS_0 (CNET_REG_BASE + 0x114) -#define CNET_REG_MF_RX_PKTS_LOST_FULL_FIFO_0 (CNET_REG_BASE+0x118) -#define CNET_REG_MF_RX_GOOD_PKTS_RCVD_0 (CNET_REG_BASE+0x11C) -#define CNET_REG_MF_RX_GOOD_BYTES_RCVD_0 (CNET_REG_BASE+0x120) -#define CNET_REG_MF_TX_BYTES_SENT_0 (CNET_REG_BASE+0x124) -#define CNET_REG_MF_RX_PKTS_LOST_BAD_FCS_1 (CNET_REG_BASE+0x154) -#define CNET_REG_MF_RX_PKTS_LOST_FULL_FIFO_1 (CNET_REG_BASE+0x158) -#define CNET_REG_MF_RX_GOOD_PKTS_RCVD_1 (CNET_REG_BASE+0x15C) -#define CNET_REG_MF_RX_GOOD_BYTES_RCVD_1 (CNET_REG_BASE+0x160) -#define CNET_REG_MF_TX_BYTES_SENT_1 (CNET_REG_BASE+0x164) -#define CNET_REG_MF_RX_PKTS_LOST_BAD_FCS_2 (CNET_REG_BASE+0x194) -#define CNET_REG_MF_RX_PKTS_LOST_FULL_FIFO_2 (CNET_REG_BASE+0x198) -#define CNET_REG_MF_RX_GOOD_PKTS_RCVD_2 (CNET_REG_BASE+0x19C) -#define CNET_REG_MF_RX_GOOD_BYTES_RCVD_2 (CNET_REG_BASE+0x1A0) -#define CNET_REG_MF_TX_BYTES_SENT_2 (CNET_REG_BASE+0x1A4) -#define CNET_REG_MF_RX_PKTS_LOST_BAD_FCS_3 (CNET_REG_BASE+0x1D4) -#define CNET_REG_MF_RX_PKTS_LOST_FULL_FIFO_3 (CNET_REG_BASE+0x1D8) -#define CNET_REG_MF_RX_GOOD_PKTS_RCVD_3 (CNET_REG_BASE+0x1DC) -#define CNET_REG_MF_RX_GOOD_BYTES_RCVD_3 (CNET_REG_BASE+0x1E0) -#define CNET_REG_MF_TX_BYTES_SENT_3 (CNET_REG_BASE+0x1E4) - -#define CNET_MAC_CLK_CHK_CTRL (CNET_REG_BASE + 0xF00) -#define CNET_MAC_CLK_CHK_CNT_VALUE (CNET_REG_BASE + 0xF04) - - -/* Base address for CNET PHY registers */ -#define PHY_REG_BASE 0x600000 - -#define PHY_REG_CMD (PHY_REG_BASE) -#define PHY_REG_STATUS (PHY_REG_BASE) - -/* - * CPCI register masks - */ - -/* ID Masks */ -#define ID_VERSION 0x00FFFFFF -#define ID_REVISION 0xFF000000 - -/* Board ID Masks */ -#define BOARD_ID 0x00000F00 -#define BOARD_ID_CONTROL 0x00000001 - -/* Control masks */ -#define CTRL_CNET_RESET 0x00000100 -#define CTRL_LED 0x00000001 - -/* RESET masks */ -#define RESET_CPCI 0x00000001 - -/* Error masks */ -#define ERR_CNET_READ_TIMEOUT 0x02000000 -#define ERR_CNET_ERROR 0x01000000 -#define ERR_PROG_BUF_OVERFLOW 0x00020000 -#define ERR_PROG_ERROR 0x00010000 -#define ERR_DMA_TIMEOUT 0x00000400 -#define ERR_DMA_RETRY_CNT_EXPIRED 0x00000200 -#define ERR_DMA_BUF_OVERFLOW 0x00000100 -#define ERR_DMA_RD_SIZE_ERROR 0x00000040 -#define ERR_DMA_WR_SIZE_ERROR 0x00000020 -#define ERR_DMA_RD_ADDR_ERROR 0x00000010 -#define ERR_DMA_WR_ADDR_ERROR 0x00000008 -#define ERR_DMA_RD_MAC_ERROR 0x00000004 -#define ERR_DMA_WR_MAC_ERROR 0x00000002 -#define ERR_DMA_FATAL_ERROR 0x00000001 - -#define ERR_DMA_SETUP_ERROR ( ERR_DMA_WR_MAC_ERROR | \ - ERR_DMA_RD_MAC_ERROR | \ - ERR_DMA_WR_ADDR_ERROR | \ - ERR_DMA_RD_ADDR_ERROR | \ - ERR_DMA_WR_SIZE_ERROR | \ - ERR_DMA_RD_SIZE_ERROR ) - - -/* Interrupt masks */ -#define INT_DMA_RX_COMPLETE 0x80000000 -#define INT_DMA_TX_COMPLETE 0x40000000 -#define INT_PHY_INTERRUPT 0x20000000 -#define INT_PKT_AVAIL 0x00000100 -#define INT_CNET_ERROR 0x00000020 -#define INT_CNET_READ_TIMEOUT 0x00000010 -#define INT_PROG_ERROR 0x00000008 -#define INT_DMA_TRANSFER_ERROR 0x00000004 -#define INT_DMA_SETUP_ERROR 0x00000002 -#define INT_DMA_FATAL_ERROR 0x00000001 - -#define INT_UNKNOWN ~(INT_DMA_RX_COMPLETE | \ - INT_DMA_TX_COMPLETE | \ - INT_PHY_INTERRUPT | \ - INT_PKT_AVAIL | \ - INT_CNET_ERROR | \ - INT_CNET_READ_TIMEOUT | \ - INT_PROG_ERROR | \ - INT_DMA_TRANSFER_ERROR | \ - INT_DMA_SETUP_ERROR | \ - INT_DMA_FATAL_ERROR) - -/* Programming status */ -#define PROG_INIT 0x00010000 -#define PROG_DONE 0x00000100 -#define PROG_FIFO_EMPTY 0x00000002 -#define PROG_IN_PROGRESS 0x00000001 - -/* Programming control */ -#define PROG_CTRL_RESET 0x00000001 - -/* DMA control */ -#define DMA_CTRL_MAC 0x00000300 -#define DMA_CTRL_OWNER 0x00000001 - -/* - * CNET register masks - */ - -/* Reset masks */ -#define CNET_RESET_MAC 0x0000000F -#define CNET_RESET_MAC_3 0x00000008 -#define CNET_RESET_MAC_2 0x00000004 -#define CNET_RESET_MAC_1 0x00000002 -#define CNET_RESET_MAC_0 0x00000001 - -/* Error masks */ -#define CNET_ERROR_TX_UNDERRUN_MAC 0x000000F0 -#define CNET_ERROR_TX_UNDERRUN_MAC_3 0x00000080 -#define CNET_ERROR_TX_UNDERRUN_MAC_2 0x00000040 -#define CNET_ERROR_TX_UNDERRUN_MAC_1 0x00000020 -#define CNET_ERROR_TX_UNDERRUN_MAC_0 0x00000010 -#define CNET_ERROR_TX_OVERRUN_MAC 0x0000000F -#define CNET_ERROR_TX_OVERRUN_MAC_3 0x00000008 -#define CNET_ERROR_TX_OVERRUN_MAC_2 0x00000004 -#define CNET_ERROR_TX_OVERRUN_MAC_1 0x00000002 -#define CNET_ERROR_TX_OVERRUN_MAC_0 0x00000001 - -/* Enable masks */ -#define CNET_ENABLE_RX_FIFO 0x0000F000 -#define CNET_ENABLE_RX_FIFO_3 0x00008000 -#define CNET_ENABLE_RX_FIFO_2 0x00004000 -#define CNET_ENABLE_RX_FIFO_1 0x00002000 -#define CNET_ENABLE_RX_FIFO_0 0x00001000 -#define CNET_ENABLE_TX_MAC 0x00000F00 -#define CNET_ENABLE_TX_MAC_3 0x00000800 -#define CNET_ENABLE_TX_MAC_2 0x00000400 -#define CNET_ENABLE_TX_MAC_1 0x00000200 -#define CNET_ENABLE_TX_MAC_0 0x00000100 -#define CNET_ENABLE_DEBUG_TRISTATE 0x00000004 -#define CNET_ENABLE_INGRESS_ARBITER 0x00000002 -#define CNET_ENABLE_RX_DMA 0x00000001 - -/* MF Status masks */ -#define CNET_MF_STATUS_RX_FIFO_EMPTY 0x02000000 -#define CNET_MF_STATUS_RX_PKT_AVAIL 0x01000000 -#define CNET_MF_STATUS_RX_NUM_PKTS 0x00FF0000 -#define CNET_MF_STATUS_TX_FIFO_FULL 0x00000200 -#define CNET_MF_STATUS_TX_FIFO_NO_MAX_PKT 0x00000100 -#define CNET_MF_STATUS_TX_NUM_PKTS 0x000000FF - -/* MAC Config masks */ -#define CNET_MAC_CFG_FULL_DUPLEX 0x00000020 -#define CNET_MAC_CFG_TX_FCS_SUPPLIED 0x00000010 -#define CNET_MAC_CFG_RX_WANT_FCS 0x00000008 -#define CNET_MAC_CFG_JUMBO_ENABLE 0x00000004 - -#define CNET_MAC_CFG_SPEED 0x00000002 -#define CNET_MAC_CFG_1000_MBPS 0x00000002 -#define CNET_MAC_CFG_100_MBPS 0x00000001 -#define CNET_MAC_CFG_10_MBPS 0x00000000 - -#define CNET_RXQ_WR_PTR 0x00FF0000 -#define CNET_RXQ_RD_PTR 0x000000FF - - -/* Phy register masks */ -#define PHY_RD_WR 0x80000000 -#define PHY_PHY 0x03000000 -#define PHY_ADDR 0x001F0000 -#define PHY_DATA 0x0000FFFF - -#define PHY_DONE 0x80000000 -#define PHY_DONE_CNT 0x001F0000 - -/* Defines to calculate register values */ -/* CPCI Funcs */ -#define NF2_GET_VERSION(x) (x & 0xFFFFFF) -#define NF2_GET_REVISION(x) ((x & 0xFF000000) >> 24) - -#define NF2_GET_BOARD_ID(x) ((x & BOARD_ID) >> 8) -#define NF2_GET_CONTROL(x) (x & BOARD_ID_CONTROL) - -#define NF2_GET_CNET_RESET(x) ((x & CTRL_CNET_RESET) >> 8) -#define NF2_GET_LED(x) (x & CTRL_LED) - -#define NF2_GET_RESET(x) (x & RESET_CPCI) - -#define NF2_GET_CNET_READ_TIMEOUT(x) ((x & ERR_CNET_READ_TIMEOUT) >> 25) -#define NF2_GET_CNET_ERROR(x) ((x & ERR_CNET_ERROR) >> 24) -#define NF2_GET_PROG_BUF_OVERFLOW(x) ((x & ERR_PROG_BUF_OVERFLOW) >> 12) -#define NF2_GET_PROG_ERROR(x) ((x & ERR_PROG_ERROR) >> 11) -#define NF2_GET_DMA_TIMEOUT(x) ((x & ERR_DMA_TIMEOUT) >> 10) -#define NF2_GET_DMA_RETRY_CNT_EXPIRED(x) \ - ((x & ERR_DMA_RETRY_CNT_EXPIRED) >> 9) -#define NF2_GET_DMA_BUF_OVERFLOW(x) ((x & ERR_DMA_BUF_OVERFLOW) >> 8) -#define NF2_GET_DMA_RD_SIZE_ERROR(x) ((x & ERR_DMA_RD_SIZE_ERROR) >> 6) -#define NF2_GET_DMA_WR_SIZE_ERROR(x) ((x & ERR_DMA_WR_SIZE_ERROR) >> 5) -#define NF2_GET_DMA_RD_ADDR_ERROR(x) ((x & ERR_DMA_RD_ADDR_ERROR) >> 4) -#define NF2_GET_DMA_WR_ADDR_ERROR(x) ((x & ERR_DMA_WR_ADDR_ERROR) >> 3) -#define NF2_GET_DMA_RD_MAC_ERROR(x) ((x & ERR_DMA_RD_MAC_ERROR) >> 2) -#define NF2_GET_DMA_WR_MAC_ERROR(x) ((x & ERR_DMA_WR_MAC_ERROR) >> 1) -#define NF2_GET_DMA_FATAL_ERROR(x) (x & ERR_DMA_FATAL_ERROR) - -#define NF2_GET_INT_DMA_TX_COMPLETE(x) ((x & INT_DMA_TX_COMPLETE) >> 31) -#define NF2_GET_INT_DMA_RX_COMPLETE(x) ((x & INT_DMA_RX_COMPLETE) >> 30) -#define NF2_GET_INT_PHY_INTERRUPT(x) ((x & INT_PHY_INTERRUPT) >> 29) -#define NF2_GET_INT_PKT_AVAIL(x) ((x & INT_PKT_AVAIL) >> 8) -#define NF2_GET_INT_CNET_ERROR(x) ((x & INT_CNET_ERROR) >> 5) -#define NF2_GET_INT_CNET_READ_TIMEOUT(x) \ - ((x & INT_CNET_READ_TIMEOUT) >> 4) -#define NF2_GET_INT_PROG_ERROR(x) ((x & INT_PROG_ERROR) >> 3) -#define NF2_GET_INT_DMA_TRANSFER_ERROR(x) \ - ((x & INT_DMA_TRANSFER_ERROR) >> 2) -#define NF2_GET_INT_DMA_SETUP_ERROR(x) ((x & INT_DMA_SETUP_ERROR) >> 1) -#define NF2_GET_INT_DMA_FATAL_ERROR(x) (x & INT_DMA_FATAL_ERROR) - -#define NF2_GET_PROG_INIT(x) ((x & PROG_INIT) >> 16) -#define NF2_GET_PROG_DONE(x) ((x & PROG_DONE) >> 8) -#define NF2_GET_PROG_FIFO_EMPTY(x) ((x & PROG_FIFO_EMPTY) >> 1) -#define NF2_GET_PROG_IN_PROGRESS(x) (x & PROG_IN_PROGRESS) - -#define NF2_GET_DMA_CTRL_MAC(x) ((x & DMA_CTRL_MAC) >> 8) -#define NF2_GET_DMA_CTRL_OWNER(x) (x & DMA_CTRL_OWNER) - -#define NF2_SET_DMA_CTRL_MAC(x) (x << 8) - - -/* CNET Funcs */ -#define NF2_GET_CNET_VERSION(x) ((x & 0xFFFF0000) >> 16) -#define NF2_GET_CNET_DEVICE_ID(x) (x & 0xFFFF) - -#define NF2_GET_CNET_RESET_MAC(x) (x & CNET_RESET_MAC) - -#define NF2_GET_CNET_ERROR_TX_UNDERRUN_MAC(x) \ - ((x & CNET_ERROR_TX_UNDERRUN_MAC) >> 4) -#define NF2_GET_CNET_ERROR_TX_OVERRUN_MAC(x) \ - (x & CNET_ERROR_TX_OVERRUN_MAC) - -#define NF2_GET_CNET_ENABLE_RX_FIFO(x) ((x & CNET_ENABLE_RX_FIFO) >> 12) -#define NF2_GET_CNET_ENABLE_TX_MAC(x) ((x & CNET_ENABLE_TX_MAC) >> 8) -#define NF2_GET_CNET_ENABLE_DEBUG_TRISTATE(x) \ - ((x & CNET_ENABLE_DEBUG_TRISTATE) >> 2) -#define NF2_GET_CNET_ENABLE_INGRESS_ARBITER(x) \ - ((x & CNET_ENABLE_INGRESS_ARBITER) >> 1) -#define NF2_GET_CNET_ENABLE_RX_DMA(x) (x & CNET_ENABLE_RX_DMA) - -#define NF2_GET_CNET_MF_STATUS_RX_FIFO_EMPTY(x) \ - ((x & CNET_MF_STATUS_RX_FIFO_EMPTY) >> 25) -#define NF2_GET_CNET_MF_STATUS_RX_PKT_AVAIL(x) \ - ((x & CNET_MF_STATUS_RX_PKT_AVAIL) >> 24) -#define NF2_GET_CNET_MF_STATUS_RX_NUM_PKTS(x) \ - ((x & CNET_MF_STATUS_RX_NUM_PKTS) >> 16) -#define NF2_GET_CNET_MF_STATUS_TX_FIFO_FULL(x) \ - ((x & CNET_MF_STATUS_TX_FIFO_FULL) >> 9) -#define NF2_GET_CNET_MF_STATUS_TX_FIFO_NO_MAX_PKT(x) \ - ((x & CNET_MF_STATUS_TX_FIFO_NO_MAX_PKT) >> 8) -#define NF2_GET_CNET_MF_STATUS_TX_NUM_PKTS(x) \ - (x & CNET_MF_STATUS_TX_NUM_PKTS) - -#define NF2_GET_CNET_MAC_CFG_FULL_DUPLEX(x) \ - ((x & CNET_MAC_CFG_FULL_DUPLEX) >> 5) -#define NF2_GET_CNET_MAC_CFG_TX_FCS_SUPPLIED(x) \ - ((x & CNET_MAC_CFG_TX_FCS_SUPPLIED) >> 4) -#define NF2_GET_CNET_MAC_CFG_RX_WANT_FCS(x) \ - ((x & CNET_MAC_CFG_RX_WANT_FCS) >> 3) -#define NF2_GET_CNET_MAC_CFG_JUMBO_ENABLE(x) \ - ((x & CNET_MAC_CFG_JUMBO_ENABLE) >> 2) -#define NF2_GET_CNET_MAC_CFG_SPEED(x) \ - (x & CNET_MAC_CFG_SPEED) - -#define NF2_GET_CNET_RXQ_WR_PTR(x) ((x & CNET_RXQ_WR_PTR) >> 16) -#define NF2_GET_CNET_RXQ_RD_PTR(x) (x & CNET_RXQ_RD_PTR) - - -/* PHY functions */ -#define NF2_SET_PHY_IS_READ(x) (x << 31) -#define NF2_SET_PHY_SELECT(x) (x << 24) -#define NF2_SET_PHY_ADDR(x) (x << 16) -#define NF2_SET_PHY_DATA(x) (x) - -#define NF2_GET_PHY_DATA(x) (x & PHY_DATA) -#define NF2_GET_PHY_DONE(x) ((x & PHY_DONE) >> 31) -#define NF2_GET_PHY_DONE_CNT(x) ((x & PHY_DONE_CNT) >> 16) - - -/* - * IOCTLs - */ -#define SIOCREGREAD SIOCDEVPRIVATE -#define SIOCREGWRITE (SIOCDEVPRIVATE + 1) - - -/* MDIO registers */ -#define MDIO_0_AUX_STATUS 0x04c0064 -#define MDIO_0_INTR_STATUS 0x04c0068 -#define MDIO_0_INTR_MASK 0x04c006c - - -/* MDIO address delta between each phy base address */ -#define ADDRESS_DELTA 0x80 - - -/* MDIO bit positions */ -#define INTR_LINK_STATUS_POS 0x2 -#define AUX_LINK_STATUS_POS 0x4 - - -/* - * Structure for transferring register data via an IOCTL - */ -struct nf2reg { - unsigned int reg; - unsigned int val; -}; - -#endif diff --git a/openflow/hw-lib/nf2/nf2_drv.c b/openflow/hw-lib/nf2/nf2_drv.c deleted file mode 100644 index 36f3de1a..00000000 --- a/openflow/hw-lib/nf2/nf2_drv.c +++ /dev/null @@ -1,847 +0,0 @@ -/*- - * Copyright (c) 2008, 2009, 2010 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#include -#include -#include - -#include "udatapath/switch-flow.h" -#include "udatapath/table.h" -#include "timeval.h" -#include "reg_defines_openflow_switch.h" -#include "nf2.h" -#include "nf2util.h" -#include "hw_flow.h" -#include "nf2_drv.h" -#include "nf2_lib.h" -#include "debug.h" - -static void log_entry(nf2_of_entry_wrap *); -static void log_entry_raw(nf2_of_entry_wrap *); -static void log_mask(nf2_of_mask_wrap *); -static void log_mask_raw(nf2_of_mask_wrap *); -static void log_action(nf2_of_action_wrap *); -static void log_action_raw(nf2_of_action_wrap *); -static void log_watchdog_info(struct nf2device *); -static void nf2_get_all_ports_info_addr(struct nf2_all_ports_info_addr *); - -static void -log_entry(nf2_of_entry_wrap *entry) -{ - int i; - - DBG_VERBOSE("log entry\n"); -#ifdef HWTABLE_NO_DEBUG - return; -#else - - // Log the physical source port - DBG_VERBOSE("E psrc[%i] ", entry->entry.src_port / 2); - - // Log the link layer source - DBG_VERBOSE("dlsrc["); - for (i = 5; i > 0; --i) { - DBG_VERBOSE("%0X:", entry->entry.eth_src[i]); - } - DBG_VERBOSE("%0X] ", entry->entry.eth_src[0]); - - // Log the link layer dest - DBG_VERBOSE("dldst["); - for (i = 5; i > 0; --i) { - DBG_VERBOSE("%0X:", entry->entry.eth_dst[i]); - } - DBG_VERBOSE("%0X] ", entry->entry.eth_dst[0]); - - // Log the link layer type - DBG_VERBOSE("dltype[%0X] ", entry->entry.eth_type); - - // Log the link layer vlan - DBG_VERBOSE("dlvlan[%0X] ", entry->entry.vlan_id); - - // Log the network source - DBG_VERBOSE("nwsrc["); - DBG_VERBOSE("%0i.", (entry->entry.ip_src >> 24) & 0xFF); - DBG_VERBOSE("%0i.", (entry->entry.ip_src >> 16) & 0xFF); - DBG_VERBOSE("%0i.", (entry->entry.ip_src >> 8) & 0xFF); - DBG_VERBOSE("%0i", entry->entry.ip_src & 0xFF); - DBG_VERBOSE("] "); - - // Log the network dest - DBG_VERBOSE("nwdst["); - DBG_VERBOSE("%0i.", (entry->entry.ip_dst >> 24) & 0xFF); - DBG_VERBOSE("%0i.", (entry->entry.ip_dst >> 16) & 0xFF); - DBG_VERBOSE("%0i.", (entry->entry.ip_dst >> 8) & 0xFF); - DBG_VERBOSE("%0i", entry->entry.ip_dst & 0xFF); - DBG_VERBOSE("] "); - - // Log the network TOS - DBG_VERBOSE("nwtos[0x%0X] ", entry->entry.ip_tos); - - // Log the transport source port - DBG_VERBOSE("tsrc[%i] ", entry->entry.transp_src); - - // Log the transport dest port - DBG_VERBOSE("tdst[%i]\n", entry->entry.transp_dst); -#endif -} - -static void -log_entry_raw(nf2_of_entry_wrap *entry) -{ -#ifdef HWTABLE_NO_DEBUG - return; -#else - int i; - unsigned char *c; - - DBG_VERBOSE("E "); - c = (unsigned char *)entry; - for (i = 0; i < sizeof(nf2_of_entry_wrap); ++i) { - if (!(i % 4)) { - DBG_VERBOSE(" "); - } - DBG_VERBOSE("%02x", c[i]); - } - DBG_VERBOSE("\n"); -#endif -} - -static void -log_mask(nf2_of_mask_wrap *mask) -{ -#ifdef HWTABLE_NO_DEBUG - return; -#else - int i; - - // Log the physical source port - DBG_VERBOSE("M psrc[%0X] ", mask->entry.src_port / 2); - - // Log the link layer source - DBG_VERBOSE("dlsrc["); - for (i = 5; i > 0; --i) { - DBG_VERBOSE("%0X:", mask->entry.eth_src[i]); - } - DBG_VERBOSE("%0X] ", mask->entry.eth_src[0]); - - // Log the link layer dest - DBG_VERBOSE("dldst["); - for (i = 5; i > 0; --i) { - DBG_VERBOSE("%0X:", mask->entry.eth_dst[i]); - } - DBG_VERBOSE("%0X] ", mask->entry.eth_dst[0]); - - // Log the link layer type - DBG_VERBOSE("dltype[%0X] ", mask->entry.eth_type); - - // Log the link layer vlan - DBG_VERBOSE("dlvlan[%0X] ", mask->entry.vlan_id); - - // Log the network source - DBG_VERBOSE("nwsrc["); - DBG_VERBOSE("%0X.", (mask->entry.ip_src >> 24) & 0xFF); - DBG_VERBOSE("%0X.", (mask->entry.ip_src >> 16) & 0xFF); - DBG_VERBOSE("%0X.", (mask->entry.ip_src >> 8) & 0xFF); - DBG_VERBOSE("%0X", mask->entry.ip_src & 0xFF); - DBG_VERBOSE("] "); - - // Log the network dest - DBG_VERBOSE("nwdst["); - DBG_VERBOSE("%0X.", (mask->entry.ip_dst >> 24) & 0xFF); - DBG_VERBOSE("%0X.", (mask->entry.ip_dst >> 16) & 0xFF); - DBG_VERBOSE("%0X.", (mask->entry.ip_dst >> 8) & 0xFF); - DBG_VERBOSE("%0X", mask->entry.ip_dst & 0xFF); - DBG_VERBOSE("] "); - - // Log the network TOS - DBG_VERBOSE("nwtos[0x%0X] ", mask->entry.ip_tos); - - // Log the transport source port - DBG_VERBOSE("tsrc[%0X] ", mask->entry.transp_src); - - // Log the transport dest port - DBG_VERBOSE("tdst[%0X]\n", mask->entry.transp_dst); -#endif -} - -static void -log_mask_raw(nf2_of_mask_wrap *mask) -{ -#ifdef HWTABLE_NO_DEBUG - return; -#else - int i; - unsigned char *c; - - DBG_VERBOSE("M "); - c = (unsigned char *)mask; - for (i = 0; i < sizeof(nf2_of_mask_wrap); ++i) { - if (!(i % 4)) { - DBG_VERBOSE(" "); - } - DBG_VERBOSE("%02x", c[i]); - } - DBG_VERBOSE("\n"); -#endif -} - -static void -log_action(nf2_of_action_wrap *action) -{ -#ifdef HWTABLE_NO_DEBUG - return; -#else - int i; - - DBG_VERBOSE("A Output P["); - for (i = 0; i < 4; ++i) { - if (action->action.forward_bitmask & (1 << (i * 2))) { - DBG_VERBOSE("%i", i); - } - } - DBG_VERBOSE("] CPU["); - for (i = 0; i < 4; ++i) { - if (action->action.forward_bitmask & (1 << (1 + (i * 2)))) { - DBG_VERBOSE("%i", i); - } - } - DBG_VERBOSE("]\n"); - - // Log the link layer source - if (action->action.nf2_action_flag & (1 << OFPAT_SET_DL_SRC)) { - DBG_VERBOSE("A Modify: dlsrc: new value ["); - for (i = 5; i > 0; --i) { - DBG_VERBOSE("%0X:", action->action.eth_src[i]); - } - DBG_VERBOSE("%0X]\n", action->action.eth_src[0]); - } - - // Log the link layer dest - if (action->action.nf2_action_flag & (1 << OFPAT_SET_DL_DST)) { - DBG_VERBOSE("A Modify: dldst: new value ["); - for (i = 5; i > 0; --i) { - DBG_VERBOSE("%0X:", action->action.eth_dst[i]); - } - DBG_VERBOSE("%0X]\n", action->action.eth_dst[0]); - } - - // Log the link layer vlan id - if (action->action.nf2_action_flag & (1 << OFPAT_SET_VLAN_VID)) { - DBG_VERBOSE("A Modify: dlvlanid: new value [%0X]\n", - action->action.vlan_id); - } - - // Log the link layer vlan pcp - if (action->action.nf2_action_flag & (1 << OFPAT_SET_VLAN_PCP)) { - DBG_VERBOSE("A Modify: dlvlanpcp: new value [%0X]\n", - action->action.vlan_pcp); - } - - // Log the link layer vlan strip - if (action->action.nf2_action_flag & (1 << OFPAT_STRIP_VLAN)) { - DBG_VERBOSE("A Modify: dlvlan strip\n"); - } - - // Log the network source - if (action->action.nf2_action_flag & (1 << OFPAT_SET_NW_SRC)) { - DBG_VERBOSE("A Modify: nwsrc: new value ["); - DBG_VERBOSE("%0i.", (action->action.ip_src >> 24) & 0xFF); - DBG_VERBOSE("%0i.", (action->action.ip_src >> 16) & 0xFF); - DBG_VERBOSE("%0i.", (action->action.ip_src >> 8) & 0xFF); - DBG_VERBOSE("%0i", action->action.ip_src & 0xFF); - DBG_VERBOSE("]\n"); - } - - // Log the network dest - if (action->action.nf2_action_flag & (1 << OFPAT_SET_NW_DST)) { - DBG_VERBOSE("A Modify: nwdst: new value ["); - DBG_VERBOSE("%0i.", (action->action.ip_dst >> 24) & 0xFF); - DBG_VERBOSE("%0i.", (action->action.ip_dst >> 16) & 0xFF); - DBG_VERBOSE("%0i.", (action->action.ip_dst >> 8) & 0xFF); - DBG_VERBOSE("%0i", action->action.ip_dst & 0xFF); - DBG_VERBOSE("]\n"); - } - - // Log the network TOS - if (action->action.nf2_action_flag & (1 << OFPAT_SET_NW_TOS)) { - DBG_VERBOSE("A Modify: nwtos: new value [%0X]\n", - action->action.ip_tos & 0xFF); - } - - // Log the transport source port - if (action->action.nf2_action_flag & (1 << OFPAT_SET_TP_SRC)) { - DBG_VERBOSE("A Modify: tsrc: new value [%0X]\n", - action->action.transp_src); - } - - // Log the transport dest port - if (action->action.nf2_action_flag & (1 << OFPAT_SET_TP_DST)) { - DBG_VERBOSE("A Modify: tdst: new value [%0X]\n", - action->action.transp_dst); - } -#endif -} - -static void -log_action_raw(nf2_of_action_wrap *action) -{ -#ifdef HWTABLE_NO_DEBUG - return; -#else - int i; - unsigned char *c; - - DBG_VERBOSE("A "); - c = (unsigned char *)action; - for (i = 0; i < sizeof(nf2_of_action_wrap); ++i) { - if (!(i % 4)) { - DBG_VERBOSE(" "); - } - DBG_VERBOSE("%02x", c[i]); - } - DBG_VERBOSE("\n"); -#endif -} - -void -nf2_reset_card(struct nf2device *dev) -{ - volatile unsigned int val; - - /* If we are operating on a NetFPGA enabled box, reset the card */ - readReg(dev, CPCI_REG_CTRL, (void *)&val); - val |= 0x100; - writeReg(dev, CPCI_REG_CTRL, val); - DBG_VERBOSE("Reset the NetFPGA.\n"); - sleep(2); -} - -void -nf2_clear_watchdog(struct nf2device *dev) -{ - volatile unsigned int enable_status; - -#ifndef NF2_WATCHDOG - return; -#endif - log_watchdog_info(dev); - - readReg(dev, WDT_ENABLE_FLG_REG, (void *)&enable_status); - enable_status &= 0x1; - - if (enable_status == WATCHDOG_DISABLE) { - enable_status = WATCHDOG_ENABLE; - writeReg(dev, WDT_ENABLE_FLG_REG, enable_status); - } -} - -/* Write a wildcard entry to the specified device and row. The row consists of - * the actual entry, its mask that specifies wildcards, as well as the action(s) - * to be taken if the row is matched - */ -int -nf2_write_of_wildcard(struct nf2device *dev, int row, - nf2_of_entry_wrap *entry, nf2_of_mask_wrap *mask, - nf2_of_action_wrap *action) -{ - int i; - unsigned int val; - - DBG_VERBOSE("** Begin wildcard entry write to row: %i\n", row); - log_entry(entry); - log_mask(mask); - log_action(action); - log_entry_raw(entry); - log_mask_raw(mask); - log_action_raw(action); - - for (i = 0; i < NF2_OF_ENTRY_WORD_LEN; ++i) { - writeReg(dev, - OPENFLOW_WILDCARD_LOOKUP_CMP_0_REG - + (4 * i), entry->raw[i]); - } - - for (i = 0; i < NF2_OF_MASK_WORD_LEN; ++i) { - writeReg(dev, - OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_0_REG - + (4 * i), mask->raw[i]); - } - - for (i = 0; i < NF2_OF_ACTION_WORD_LEN; ++i) { - writeReg(dev, - OPENFLOW_WILDCARD_LOOKUP_ACTION_0_REG - + (4 * i), action->raw[i]); - } - - // Reset the stats for the row - val = 0; - writeReg(dev, - OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG + (4 * row), - val); - writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG + (4 * row), - val); - writeReg(dev, - OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_0_REG + (4 * row), - val); - writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_WRITE_ADDR_REG, row); - - DBG_VERBOSE("** End wildcard entry write to row: %i time(msec): %llu\n", - row, time_msec()); - - return 0; -} - -int -nf2_write_of_exact(struct nf2device *dev, int row, - nf2_of_entry_wrap *entry, nf2_of_action_wrap *action) -{ - int i; - unsigned int val; - unsigned int index = row << 7; - - DBG_VERBOSE("** Begin exact match entry write to row: %i\n", row); - log_entry(entry); - log_action(action); - log_entry_raw(entry); - log_action_raw(action); - - for (i = 0; i < NF2_OF_ENTRY_WORD_LEN; ++i) { - writeReg(dev, SRAM_BASE_ADDR + index - + (4 * i), entry->raw[i]); - } - - // blank out the counters - val = 0; - for (i = 0; i < NF2_OF_EXACT_COUNTERS_WORD_LEN; ++i) { - writeReg(dev, SRAM_BASE_ADDR + index - + sizeof(nf2_of_entry_wrap) - + (4 * i), val); - } - - // write the actions - for (i = 0; i < NF2_OF_ACTION_WORD_LEN; ++i) { - writeReg(dev, SRAM_BASE_ADDR + index - + sizeof(nf2_of_entry_wrap) - + sizeof(nf2_of_exact_counters_wrap) - + (4 * i), action->raw[i]); - } - - DBG_VERBOSE - ("** End exact match entry write to row: %i time(msec): %llu\n", - row, time_msec()); - - return 0; -} - -/* Write wildcard action(s) to the specified device and row. */ -int -nf2_modify_write_of_wildcard(struct nf2device *dev, int row, - nf2_of_entry_wrap *entry, nf2_of_mask_wrap *mask, - nf2_of_action_wrap *action) -{ - int i; - unsigned int bytes_reg_val; - unsigned int pkts_reg_val; - unsigned int last_reg_val; - - DBG_VERBOSE("** Begin wildcard modified action write to row: %i\n", - row); - log_entry(entry); - log_mask(mask); - log_action(action); - log_entry_raw(entry); - log_mask_raw(mask); - log_action_raw(action); - - writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_READ_ADDR_REG, row); - readReg(dev, - OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG + (4 * row), - &bytes_reg_val); - readReg(dev, - OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG + (4 * row), - &pkts_reg_val); - readReg(dev, - OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_0_REG + (4 * row), - &last_reg_val); - - for (i = 0; i < NF2_OF_ENTRY_WORD_LEN; ++i) { - writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_CMP_0_REG - + (4 * i), entry->raw[i]); - } - - for (i = 0; i < NF2_OF_MASK_WORD_LEN; ++i) { - writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_0_REG - + (4 * i), mask->raw[i]); - } - - for (i = 0; i < NF2_OF_ACTION_WORD_LEN; ++i) { - writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_ACTION_0_REG - + (4 * i), action->raw[i]); - } - - writeReg(dev, - OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG + (4 * row), - bytes_reg_val); - writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG + (4 * row), - pkts_reg_val); - writeReg(dev, - OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_0_REG + (4 * row), - last_reg_val); - writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_WRITE_ADDR_REG, row); - - DBG_VERBOSE - ("** End wildcard modified action write to row: %i time(msec): %llu\n", - row, time_msec()); - DBG_VERBOSE(" Bytes hit count: %d\n", bytes_reg_val); - DBG_VERBOSE(" Pkts hit count: %d\n", pkts_reg_val); - DBG_VERBOSE(" Last seen : %d\n", last_reg_val); - - return 0; -} - -int -nf2_modify_write_of_exact(struct nf2device *dev, int row, - nf2_of_action_wrap *action) -{ - int i; - unsigned int index = row << 7; - - DBG_VERBOSE("** Begin exact match modified action write to row: %i\n", - row); - log_action(action); - log_action_raw(action); - - // write the actions - for (i = 0; i < NF2_OF_ACTION_WORD_LEN; ++i) { - writeReg(dev, SRAM_BASE_ADDR + index - + sizeof(nf2_of_entry_wrap) - + sizeof(nf2_of_exact_counters_wrap) - + (4 * i), action->raw[i]); - } - - DBG_VERBOSE - ("** End exact match modified action write to row: %i time(msec): %llu\n", - row, time_msec()); - - return 0; -} - -unsigned int -nf2_get_exact_packet_count(struct nf2device *dev, int row) -{ - unsigned int val = 0; - unsigned int index = 0; - - /* TODO: Need to scrape data from all 4 registers - * in the case of a wildcarded source port and - * forward all action type - */ - nf2_of_exact_counters_wrap counters; - memset(&counters, 0, sizeof(nf2_of_exact_counters_wrap)); - - // build the index to our counters - index = row << 7; - - // Read the first word into our struct, to not disturb the byte count - readReg(dev, - SRAM_BASE_ADDR + index + sizeof(nf2_of_entry_wrap), - &counters.raw[0]); - val = counters.counters.pkt_count; - - DBG_VERBOSE - ("** Exact match packet count(delta) row: %i count: %i time(msec): %llu\n", - row, val, time_msec()); - - return val; -} - -unsigned int -nf2_get_exact_byte_count(struct nf2device *dev, int row) -{ - unsigned int val = 0; - unsigned int index = 0; - - /* TODO: Need to scrape data from all 4 registers - * in the case of a wildcarded source port and - * forward all action type - */ - nf2_of_exact_counters_wrap counters; - memset(&counters, 0, sizeof(nf2_of_exact_counters_wrap)); - - // build the index to our counters - index = row << 7; - - // Read the second word into our struct, to not disturb the packet count - readReg(dev, SRAM_BASE_ADDR + index + - sizeof(nf2_of_entry_wrap) + 4, &counters.raw[1]); - val = counters.counters.byte_count; - - DBG_VERBOSE - ("** Exact match byte count(delta) row: %i count: %i time(msec): %llu\n", - row, val, time_msec()); - - return val; -} - -unsigned int -nf2_get_wildcard_packet_count(struct nf2device *dev, int row) -{ - unsigned int val = 0; - - writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_READ_ADDR_REG, row); - readReg(dev, OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG - + (4 * row), &val); - - DBG_VERBOSE - ("** Wildcard packet count(sum) row: %i count: %i time(msec): %llu\n", - row, val, time_msec()); - - return val; -} - -unsigned int -nf2_get_wildcard_byte_count(struct nf2device *dev, int row) -{ - unsigned int val = 0; - - writeReg(dev, OPENFLOW_WILDCARD_LOOKUP_READ_ADDR_REG, row); - readReg(dev, OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG - + (4 * row), &val); - - DBG_VERBOSE - ("** Wildcard byte count(sum) row: %i count: %i time(msec): %llu\n", - row, val, time_msec()); - - return val; -} - -unsigned long int -nf2_get_matched_count(struct nf2device *dev) -{ - unsigned int val_wild = 0; - unsigned int val_exact = 0; - - readReg(dev, OPENFLOW_LOOKUP_WILDCARD_HITS_REG, &val_wild); - readReg(dev, OPENFLOW_LOOKUP_EXACT_HITS_REG, &val_exact); - - DBG_VERBOSE("** Wildcard Matched count: %i time(msec): %llu\n", - val_wild, time_msec()); - DBG_VERBOSE("** Exact Matched count: %i time(msec): %llu\n", - val_exact, time_msec()); - - return ((unsigned long int)(val_wild + val_exact)); -} - -unsigned long int -nf2_get_missed_count(struct nf2device *dev) -{ - unsigned int val_wild = 0; - unsigned int val_exact = 0; - - readReg(dev, OPENFLOW_LOOKUP_WILDCARD_MISSES_REG, &val_wild); - readReg(dev, OPENFLOW_LOOKUP_EXACT_MISSES_REG, &val_exact); - - DBG_VERBOSE("** Wildcard Missed count: %i time(msec): %llu\n", - val_wild, time_msec()); - DBG_VERBOSE("** Exact Missed count: %i time(msec): %llu\n", - val_exact, time_msec()); - - return ((unsigned long int)(val_wild + val_exact)); -} - -static void -log_watchdog_info(struct nf2device *dev) -{ -#ifdef HWTABLE_NO_DEBUG - return; -#else -#define CLK_CYCLE 8 - unsigned int nf2wdtinfo; - unsigned int elapsed_time; - readReg(dev, WDT_COUNTER_REG, &nf2wdtinfo); - elapsed_time = nf2wdtinfo * CLK_CYCLE / 1000000; - DBG_VVERB - ("%u (msec) passed since the watchdog counter has been cleared last time\n", - elapsed_time); - DBG_VVERB("NetFPGA WDT now clearing\n"); -#endif -} - -static void -nf2_get_all_ports_info_addr(struct nf2_all_ports_info_addr *nf2addr) -{ - nf2addr->rx_q_num_pkts_stored_reg[0] - = MAC_GRP_0_RX_QUEUE_NUM_PKTS_STORED_REG; - nf2addr->rx_q_num_pkts_dropped_full_reg[0] - = MAC_GRP_0_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG; - nf2addr->rx_q_num_pkts_dropped_bad_reg[0] - = MAC_GRP_0_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG; - nf2addr->rx_q_num_words_pushed_reg[0] - = MAC_GRP_0_RX_QUEUE_NUM_WORDS_PUSHED_REG; - nf2addr->rx_q_num_bytes_pushed_reg[0] - = MAC_GRP_0_RX_QUEUE_NUM_BYTES_PUSHED_REG; - nf2addr->rx_q_num_pkts_dequeued_reg[0] - = MAC_GRP_0_RX_QUEUE_NUM_PKTS_DEQUEUED_REG; - nf2addr->rx_q_num_pkts_in_queue_reg[0] - = MAC_GRP_0_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG; - nf2addr->tx_q_num_pkts_in_queue_reg[0] - = MAC_GRP_0_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG; - nf2addr->tx_q_num_pkts_sent_reg[0] - = MAC_GRP_0_TX_QUEUE_NUM_PKTS_SENT_REG; - nf2addr->tx_q_num_words_pushed_reg[0] - = MAC_GRP_0_TX_QUEUE_NUM_WORDS_PUSHED_REG; - nf2addr->tx_q_num_bytes_pushed_reg[0] - = MAC_GRP_0_TX_QUEUE_NUM_BYTES_PUSHED_REG; - nf2addr->tx_q_num_pkts_enqueued_reg[0] - = MAC_GRP_0_TX_QUEUE_NUM_PKTS_ENQUEUED_REG; - - nf2addr->rx_q_num_pkts_stored_reg[1] - = MAC_GRP_1_RX_QUEUE_NUM_PKTS_STORED_REG; - nf2addr->rx_q_num_pkts_dropped_full_reg[1] - = MAC_GRP_1_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG; - nf2addr->rx_q_num_pkts_dropped_bad_reg[1] - = MAC_GRP_1_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG; - nf2addr->rx_q_num_words_pushed_reg[1] - = MAC_GRP_1_RX_QUEUE_NUM_WORDS_PUSHED_REG; - nf2addr->rx_q_num_bytes_pushed_reg[1] - = MAC_GRP_1_RX_QUEUE_NUM_BYTES_PUSHED_REG; - nf2addr->rx_q_num_pkts_dequeued_reg[1] - = MAC_GRP_1_RX_QUEUE_NUM_PKTS_DEQUEUED_REG; - nf2addr->rx_q_num_pkts_in_queue_reg[1] - = MAC_GRP_1_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG; - nf2addr->tx_q_num_pkts_in_queue_reg[1] - = MAC_GRP_1_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG; - nf2addr->tx_q_num_pkts_sent_reg[1] - = MAC_GRP_1_TX_QUEUE_NUM_PKTS_SENT_REG; - nf2addr->tx_q_num_words_pushed_reg[1] - = MAC_GRP_1_TX_QUEUE_NUM_WORDS_PUSHED_REG; - nf2addr->tx_q_num_bytes_pushed_reg[1] - = MAC_GRP_1_TX_QUEUE_NUM_BYTES_PUSHED_REG; - nf2addr->tx_q_num_pkts_enqueued_reg[1] - = MAC_GRP_1_TX_QUEUE_NUM_PKTS_ENQUEUED_REG; - - nf2addr->rx_q_num_pkts_stored_reg[2] - = MAC_GRP_2_RX_QUEUE_NUM_PKTS_STORED_REG; - nf2addr->rx_q_num_pkts_dropped_full_reg[2] - = MAC_GRP_2_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG; - nf2addr->rx_q_num_pkts_dropped_bad_reg[2] - = MAC_GRP_2_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG; - nf2addr->rx_q_num_words_pushed_reg[2] - = MAC_GRP_2_RX_QUEUE_NUM_WORDS_PUSHED_REG; - nf2addr->rx_q_num_bytes_pushed_reg[2] - = MAC_GRP_2_RX_QUEUE_NUM_BYTES_PUSHED_REG; - nf2addr->rx_q_num_pkts_dequeued_reg[2] - = MAC_GRP_2_RX_QUEUE_NUM_PKTS_DEQUEUED_REG; - nf2addr->rx_q_num_pkts_in_queue_reg[2] - = MAC_GRP_2_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG; - nf2addr->tx_q_num_pkts_in_queue_reg[2] - = MAC_GRP_2_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG; - nf2addr->tx_q_num_pkts_sent_reg[2] - = MAC_GRP_2_TX_QUEUE_NUM_PKTS_SENT_REG; - nf2addr->tx_q_num_words_pushed_reg[2] - = MAC_GRP_2_TX_QUEUE_NUM_WORDS_PUSHED_REG; - nf2addr->tx_q_num_bytes_pushed_reg[2] - = MAC_GRP_2_TX_QUEUE_NUM_BYTES_PUSHED_REG; - nf2addr->tx_q_num_pkts_enqueued_reg[2] - = MAC_GRP_2_TX_QUEUE_NUM_PKTS_ENQUEUED_REG; - - nf2addr->rx_q_num_pkts_stored_reg[3] - = MAC_GRP_3_RX_QUEUE_NUM_PKTS_STORED_REG; - nf2addr->rx_q_num_pkts_dropped_full_reg[3] - = MAC_GRP_3_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG; - nf2addr->rx_q_num_pkts_dropped_bad_reg[3] - = MAC_GRP_3_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG; - nf2addr->rx_q_num_words_pushed_reg[3] - = MAC_GRP_3_RX_QUEUE_NUM_WORDS_PUSHED_REG; - nf2addr->rx_q_num_bytes_pushed_reg[3] - = MAC_GRP_3_RX_QUEUE_NUM_BYTES_PUSHED_REG; - nf2addr->rx_q_num_pkts_dequeued_reg[3] - = MAC_GRP_3_RX_QUEUE_NUM_PKTS_DEQUEUED_REG; - nf2addr->rx_q_num_pkts_in_queue_reg[3] - = MAC_GRP_3_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG; - nf2addr->tx_q_num_pkts_in_queue_reg[3] - = MAC_GRP_3_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG; - nf2addr->tx_q_num_pkts_sent_reg[3] - = MAC_GRP_3_TX_QUEUE_NUM_PKTS_SENT_REG; - nf2addr->tx_q_num_words_pushed_reg[3] - = MAC_GRP_3_TX_QUEUE_NUM_WORDS_PUSHED_REG; - nf2addr->tx_q_num_bytes_pushed_reg[3] - = MAC_GRP_3_TX_QUEUE_NUM_BYTES_PUSHED_REG; - nf2addr->tx_q_num_pkts_enqueued_reg[3] - = MAC_GRP_3_TX_QUEUE_NUM_PKTS_ENQUEUED_REG; -} - -int -nf2_get_port_info(struct nf2device *dev, int nf_port, - struct nf2_port_info *nf2portinfo) -{ - struct nf2_all_ports_info_addr *nf2addr; - - if ((nf_port >= NF2_PORT_NUM) || (nf_port < 0)) { - DBG_ERROR("Illegal port number\n"); - return 1; - } - - nf2addr = calloc(1, sizeof(struct nf2_all_ports_info_addr)); - if (nf2addr == NULL) { - DBG_ERROR("Could not allocate memory for port information gathering\n"); - return 1; - } - nf2_get_all_ports_info_addr(nf2addr); - - readReg(dev, nf2addr->rx_q_num_pkts_stored_reg[nf_port], - &(nf2portinfo->rx_q_num_pkts_stored)); - readReg(dev, nf2addr->rx_q_num_pkts_dropped_full_reg[nf_port], - &(nf2portinfo->rx_q_num_pkts_dropped_full)); - readReg(dev, nf2addr->rx_q_num_pkts_dropped_bad_reg[nf_port], - &(nf2portinfo->rx_q_num_pkts_dropped_bad)); - readReg(dev, nf2addr->rx_q_num_words_pushed_reg[nf_port], - &(nf2portinfo->rx_q_num_words_pushed)); - readReg(dev, nf2addr->rx_q_num_bytes_pushed_reg[nf_port], - &(nf2portinfo->rx_q_num_bytes_pushed)); - readReg(dev, nf2addr->rx_q_num_pkts_dequeued_reg[nf_port], - &(nf2portinfo->rx_q_num_pkts_dequeued)); - readReg(dev, nf2addr->rx_q_num_pkts_in_queue_reg[nf_port], - &(nf2portinfo->rx_q_num_pkts_in_queue)); - readReg(dev, nf2addr->tx_q_num_pkts_in_queue_reg[nf_port], - &(nf2portinfo->tx_q_num_pkts_in_queue)); - readReg(dev, nf2addr->tx_q_num_pkts_sent_reg[nf_port], - &(nf2portinfo->tx_q_num_pkts_sent)); - readReg(dev, nf2addr->tx_q_num_words_pushed_reg[nf_port], - &(nf2portinfo->tx_q_num_words_pushed)); - readReg(dev, nf2addr->tx_q_num_bytes_pushed_reg[nf_port], - &(nf2portinfo->tx_q_num_bytes_pushed)); - readReg(dev, nf2addr->tx_q_num_pkts_enqueued_reg[nf_port], - &(nf2portinfo->tx_q_num_pkts_enqueued)); - free(nf2addr); - return 0; -} diff --git a/openflow/hw-lib/nf2/nf2_drv.h b/openflow/hw-lib/nf2/nf2_drv.h deleted file mode 100644 index 6f961267..00000000 --- a/openflow/hw-lib/nf2/nf2_drv.h +++ /dev/null @@ -1,150 +0,0 @@ -/*- - * Copyright (c) 2008, 2009, 2010 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#ifndef HATABLE_NF2_NF2_OPENFLOW_H_ -#define HATABLE_NF2_NF2_OPENFLOW_H_ - -#define OPENFLOW_NF2_EXACT_TABLE_SIZE 32768 -#define WATCHDOG_ENABLE 1 -#define WATCHDOG_DISABLE 0 - -#pragma pack(push) /* push current alignment to stack */ -#pragma pack(1) /* set alignment to 1 byte boundary */ - -#define NF2_OF_ENTRY_WORD_LEN 8 -struct nf2_of_entry { - uint16_t transp_dst; - uint16_t transp_src; - uint8_t ip_proto; - uint32_t ip_dst; - uint32_t ip_src; - uint16_t eth_type; - uint8_t eth_dst[6]; - uint8_t eth_src[6]; - uint8_t src_port; - uint8_t ip_tos; - uint16_t vlan_id; - uint8_t pad; -}; - -typedef union nf2_of_entry_wrap { - struct nf2_of_entry entry; - uint32_t raw[NF2_OF_ENTRY_WORD_LEN]; -} nf2_of_entry_wrap; - -typedef nf2_of_entry_wrap nf2_of_mask_wrap; -#define NF2_OF_MASK_WORD_LEN 8 - -struct nf2_of_action { - uint16_t forward_bitmask; - uint16_t nf2_action_flag; - uint16_t vlan_id; - uint8_t vlan_pcp; - uint8_t eth_src[6]; - uint8_t eth_dst[6]; - uint32_t ip_src; - uint32_t ip_dst; - uint8_t ip_tos; - uint16_t transp_src; - uint16_t transp_dst; - uint8_t reserved[18]; -}; - -#define NF2_OF_ACTION_WORD_LEN 10 -typedef union nf2_of_action_wrap { - struct nf2_of_action action; - uint32_t raw[10]; -} nf2_of_action_wrap; - -struct nf2_of_exact_counters { - uint32_t pkt_count:25; - uint8_t last_seen:7; - uint32_t byte_count; -}; - -#define NF2_OF_EXACT_COUNTERS_WORD_LEN 2 -typedef union nf2_of_exact_counters_wrap { - struct nf2_of_exact_counters counters; - uint32_t raw[NF2_OF_EXACT_COUNTERS_WORD_LEN]; -} nf2_of_exact_counters_wrap; - -#define NF2_PORT_NUM 4 -struct nf2_all_ports_info_addr { - unsigned int rx_q_num_pkts_stored_reg[NF2_PORT_NUM]; - unsigned int rx_q_num_pkts_dropped_full_reg[NF2_PORT_NUM]; - unsigned int rx_q_num_pkts_dropped_bad_reg[NF2_PORT_NUM]; - unsigned int rx_q_num_words_pushed_reg[NF2_PORT_NUM]; - unsigned int rx_q_num_bytes_pushed_reg[NF2_PORT_NUM]; - unsigned int rx_q_num_pkts_dequeued_reg[NF2_PORT_NUM]; - unsigned int rx_q_num_pkts_in_queue_reg[NF2_PORT_NUM]; - unsigned int tx_q_num_pkts_in_queue_reg[NF2_PORT_NUM]; - unsigned int tx_q_num_pkts_sent_reg[NF2_PORT_NUM]; - unsigned int tx_q_num_words_pushed_reg[NF2_PORT_NUM]; - unsigned int tx_q_num_bytes_pushed_reg[NF2_PORT_NUM]; - unsigned int tx_q_num_pkts_enqueued_reg[NF2_PORT_NUM]; -}; - -struct nf2_port_info { - uint32_t rx_q_num_pkts_stored; - uint32_t rx_q_num_pkts_dropped_full; - uint32_t rx_q_num_pkts_dropped_bad; - uint32_t rx_q_num_words_pushed; - uint32_t rx_q_num_bytes_pushed; - uint32_t rx_q_num_pkts_dequeued; - uint32_t rx_q_num_pkts_in_queue; - uint32_t tx_q_num_pkts_in_queue; - uint32_t tx_q_num_pkts_sent; - uint32_t tx_q_num_words_pushed; - uint32_t tx_q_num_bytes_pushed; - uint32_t tx_q_num_pkts_enqueued; -}; - -#pragma pack(pop) /* XXX: Restore original alignment from stack */ - -void nf2_reset_card(struct nf2device *); -void nf2_clear_watchdog(struct nf2device *); -int nf2_write_of_wildcard(struct nf2device *, int, nf2_of_entry_wrap *, - nf2_of_mask_wrap *, nf2_of_action_wrap *); -int nf2_write_of_exact(struct nf2device *, int, nf2_of_entry_wrap *, - nf2_of_action_wrap *); -int nf2_modify_write_of_wildcard(struct nf2device *, int, nf2_of_entry_wrap *, - nf2_of_mask_wrap *, nf2_of_action_wrap *); -int nf2_modify_write_of_exact(struct nf2device *, int, nf2_of_action_wrap *); -unsigned int nf2_get_exact_packet_count(struct nf2device *, int); -unsigned int nf2_get_exact_byte_count(struct nf2device *, int); -unsigned int nf2_get_wildcard_packet_count(struct nf2device *, int); -unsigned int nf2_get_wildcard_byte_count(struct nf2device *, int); -unsigned long int nf2_get_matched_count(struct nf2device *); -unsigned long int nf2_get_missed_count(struct nf2device *); -int nf2_get_port_info(struct nf2device *, int, struct nf2_port_info *); - -#endif diff --git a/openflow/hw-lib/nf2/nf2_lib.c b/openflow/hw-lib/nf2/nf2_lib.c deleted file mode 100644 index 972d91bd..00000000 --- a/openflow/hw-lib/nf2/nf2_lib.c +++ /dev/null @@ -1,1049 +0,0 @@ -/*- - * Copyright (c) 2008, 2009, 2010 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#include -#include - -#include "list.h" -#include "udatapath/crc32.h" -#include "udatapath/switch-flow.h" -#include "udatapath/table.h" -#include "reg_defines_openflow_switch.h" -#include "nf2.h" -#include "nf2util.h" -#include "hw_flow.h" -#include "nf2_drv.h" -#include "nf2_lib.h" -#include "debug.h" - -#define DEFAULT_IFACE "nf2c0" - -#define MAX_INT_32 0xFFFFFFFF -#define PORT_BASE 1 - -#define VID_BITMASK 0x0FFF -#define PCP_BITSHIFT 13 -#define PCP_BITMASK 0xE000 -#define TOS_BITMASK 0xFC - -struct list wildcard_free_list; -struct nf2_flow *exact_free_list[OPENFLOW_NF2_EXACT_TABLE_SIZE]; - -static uint32_t make_nw_wildcard(int); -static struct nf2_flow *get_free_exact(nf2_of_entry_wrap *); -static struct nf2_flow *get_free_wildcard(void); -static int is_action_forward_all(struct sw_flow *); -static void populate_action_output(nf2_of_action_wrap *, nf2_of_entry_wrap *, - uint8_t *); -static void populate_action_set_dl_src(nf2_of_action_wrap *, uint8_t *); -static void populate_action_set_dl_dst(nf2_of_action_wrap *, uint8_t *); -static void populate_action_set_nw_src(nf2_of_action_wrap *, uint8_t *); -static void populate_action_set_nw_dst(nf2_of_action_wrap *, uint8_t *); -static void populate_action_set_tp_src(nf2_of_action_wrap *, uint8_t *); -static void populate_action_set_tp_dst(nf2_of_action_wrap *, uint8_t *); -static void populate_action_set_nw_tos(nf2_of_action_wrap *, uint8_t *); -static void populate_action_set_vlan_vid(nf2_of_action_wrap *, uint8_t *); -static void populate_action_set_vlan_pcp(nf2_of_action_wrap *, uint8_t *); -static void populate_action_strip_vlan(nf2_of_action_wrap *); - -int iface_chk_done = 0; -int net_iface = 0; - -struct nf2device * -nf2_get_net_device(void) -{ - struct nf2device *dev; - dev = calloc(1, sizeof(struct nf2device)); - dev->device_name = DEFAULT_IFACE; - - if (iface_chk_done) { - dev->net_iface = net_iface; - } else { - if (check_iface(dev)) { - iface_chk_done = 0; - return NULL; - } else { - iface_chk_done = 1; - net_iface = dev->net_iface; - } - } - - if (openDescriptor(dev)) { - return NULL; - } - return dev; -} - -void -nf2_free_net_device(struct nf2device *dev) -{ - if (dev == NULL){ - return; - } - - closeDescriptor(dev); - free(dev); -} - -/* Checks to see if the actions requested by the flow are capable of being - * done in the NF2 hardware. Returns 1 if yes, 0 for no. - */ -int -nf2_are_actions_supported(struct sw_flow *flow) -{ - struct sw_flow_actions *sfa; - size_t actions_len; - uint8_t *p; - - sfa = flow->sf_acts; - actions_len = sfa->actions_len; - p = (uint8_t *)sfa->actions; - - while (actions_len > 0) { - struct ofp_action_header *ah = (struct ofp_action_header *)p; - struct ofp_action_output *oa = (struct ofp_action_output *)p; - size_t len = ntohs(ah->len); - - DBG_VERBOSE("Action Support Chk: Len of this action: %i\n", - len); - DBG_VERBOSE("Action Support Chk: Len of actions : %i\n", - actions_len); - - // All the modify actions are supported. - // Each of them can be specified once otherwise overwritten. - // Output action happens last. - if (!(ntohs(ah->type) == OFPAT_OUTPUT - || ntohs(ah->type) == OFPAT_SET_DL_SRC - || ntohs(ah->type) == OFPAT_SET_DL_DST - - || ntohs(ah->type) == OFPAT_SET_NW_SRC - || ntohs(ah->type) == OFPAT_SET_NW_DST - - || ntohs(ah->type) == OFPAT_SET_NW_TOS - - || ntohs(ah->type) == OFPAT_SET_TP_SRC - || ntohs(ah->type) == OFPAT_SET_TP_DST - - || ntohs(ah->type) == OFPAT_SET_VLAN_VID - || ntohs(ah->type) == OFPAT_SET_VLAN_PCP - || ntohs(ah->type) == OFPAT_STRIP_VLAN)) { - DBG_VERBOSE - ("Flow action type %#0x not supported in hardware\n", - ntohs(ah->type)); - return 0; - } - // Only support ports 1-4(incl. IN_PORT), ALL, FLOOD. - // Let CONTROLLER/LOCAL fall through - if ((ntohs(ah->type) == OFPAT_OUTPUT) - && (!((ntohs(oa->port) >= PORT_BASE) - && (ntohs(oa->port) <= MAX_IFACE)) - && !(ntohs(oa->port) == OFPP_ALL) - && !(ntohs(oa->port) == OFPP_FLOOD) - && !(ntohs(oa->port) == OFPP_IN_PORT))) { - DBG_VERBOSE - ("Flow action output port %#0x is not supported in hardware\n", - ntohs(oa->port)); - return 0; - } - p += len; - actions_len -= len; - } - - return 1; -} - -/* Write all 0's out to an exact entry position. */ -void -nf2_clear_of_exact(uint32_t pos) -{ - nf2_of_entry_wrap entry; - nf2_of_action_wrap action; - struct nf2device *dev = NULL; - - memset(&entry, 0, sizeof(nf2_of_entry_wrap)); - memset(&action, 0, sizeof(nf2_of_action_wrap)); - - dev = nf2_get_net_device(); - if (dev == NULL) { - DBG_ERROR("Could not open NetFPGA device\n"); - return; - } - nf2_write_of_exact(dev, pos, &entry, &action); - nf2_free_net_device(dev); -} - -/* - * Write all 0's out to a wildcard entry position - */ -void -nf2_clear_of_wildcard(uint32_t pos) -{ - nf2_of_entry_wrap entry; - nf2_of_mask_wrap mask; - nf2_of_action_wrap action; - struct nf2device *dev = NULL; - - memset(&entry, 0, sizeof(nf2_of_entry_wrap)); - memset(&mask, 0, sizeof(nf2_of_mask_wrap)); - memset(&action, 0, sizeof(nf2_of_action_wrap)); - - dev = nf2_get_net_device(); - if (dev == NULL) { - DBG_ERROR("Could not open NetFPGA device\n"); - return; - } - nf2_write_of_wildcard(dev, pos, &entry, &mask, &action); - nf2_free_net_device(dev); -} - -int -nf2_init_exact_freelist(void) -{ - struct nf2_flow *sfw = NULL; - int i; - - for (i = 0; i < (OPENFLOW_NF2_EXACT_TABLE_SIZE); ++i) { - sfw = calloc(1, sizeof(struct nf2_flow)); - if (sfw == NULL) { - return 1; - } - sfw->pos = i; - sfw->type = NF2_TABLE_EXACT; - nf2_add_free_exact(sfw); - sfw = NULL; - } - - return 0; -} - -int -nf2_init_wildcard_freelist(void) -{ - struct nf2_flow *sfw = NULL; - int i; - list_init(&wildcard_free_list); - - for (i = 0; i < (OPENFLOW_WILDCARD_TABLE_SIZE - RESERVED_FOR_CPU2NETFPGA); ++i) { - sfw = calloc(1, sizeof(struct nf2_flow)); - if (sfw == NULL) { - return 1; - } - sfw->pos = i; - sfw->type = NF2_TABLE_WILDCARD; - nf2_add_free_wildcard(sfw); - sfw = NULL; - } - - return 0; -} - -/* Called when the table is being deleted. */ -void -nf2_destroy_exact_freelist(void) -{ - struct nf2_flow *sfw = NULL; - int i; - - for (i = 0; i < (OPENFLOW_NF2_EXACT_TABLE_SIZE); ++i) { - sfw = exact_free_list[i]; - if (sfw) { - free(sfw); - } - sfw = NULL; - } -} - -/* Called when the table is being deleted. */ -void -nf2_destroy_wildcard_freelist(void) -{ - struct nf2_flow *sfw = NULL; - - while (!list_is_empty(&wildcard_free_list)) { - sfw = CONTAINER_OF(list_front(&wildcard_free_list), struct nf2_flow, node); - list_remove(&sfw->node); - free(sfw); - } -} - -/* Setup the wildcard table by adding static flows that will handle - * misses by sending them up to the cpu ports, and handle packets coming - * back down from the cpu by sending them out the corresponding port. - */ -int -nf2_write_static_wildcard(void) -{ - nf2_of_entry_wrap entry; - nf2_of_mask_wrap mask; - nf2_of_action_wrap action; - int i; - struct nf2device *dev; - - dev = nf2_get_net_device(); - if (dev == NULL) - return 1; - - memset(&entry, 0x00, sizeof(nf2_of_entry_wrap)); - memset(&mask, 0xFF, sizeof(nf2_of_mask_wrap)); - // Only non-wildcard section is the source port - mask.entry.src_port = 0; - memset(&action, 0, sizeof(nf2_of_action_wrap)); - - // write the catch all entries to send to the cpu - for (i = 0; i < 4; ++i) { - entry.entry.src_port = i * 2; - action.action.forward_bitmask = 0x1 << ((i * 2) + 1); - nf2_write_of_wildcard(dev, (OPENFLOW_WILDCARD_TABLE_SIZE - 4) - + i, &entry, &mask, &action); - } - - // write the entries to send out packets coming from the cpu - for (i = 0; i < 4; ++i) { - entry.entry.src_port = (i * 2) + 1; - action.action.forward_bitmask = 0x1 << (i * 2); - nf2_write_of_wildcard(dev, (OPENFLOW_WILDCARD_TABLE_SIZE - 8) - + i, &entry, &mask, &action); - } - - nf2_free_net_device(dev); - return 0; -} - -/* Populate a nf2_of_entry_wrap with entries from a struct sw_flow. */ -void -nf2_populate_of_entry(nf2_of_entry_wrap *key, struct sw_flow *flow) -{ - int vlan_vid; - int vlan_pcp; - int i; - - key->entry.transp_dst = ntohs(flow->key.flow.tp_dst); - key->entry.transp_src = ntohs(flow->key.flow.tp_src); - key->entry.ip_proto = flow->key.flow.nw_proto; - key->entry.ip_dst = ntohl(flow->key.flow.nw_dst); - key->entry.ip_src = ntohl(flow->key.flow.nw_src); - key->entry.eth_type = ntohs(flow->key.flow.dl_type); - // Blame Jad for applying endian'ness to character arrays - for (i = 0; i < 6; ++i) { - key->entry.eth_dst[i] = flow->key.flow.dl_dst[5 - i]; - } - for (i = 0; i < 6; ++i) { - key->entry.eth_src[i] = flow->key.flow.dl_src[5 - i]; - } - key->entry.src_port = (ntohs(flow->key.flow.in_port) - PORT_BASE) * 2; - key->entry.ip_tos = TOS_BITMASK & flow->key.flow.nw_tos; - if (ntohs(flow->key.flow.dl_vlan) == 0xffff) { - key->entry.vlan_id = 0xffff; - } else { - vlan_vid = VID_BITMASK & ntohs(flow->key.flow.dl_vlan); - vlan_pcp = PCP_BITMASK - & ((uint16_t)(flow->key.flow.dl_vlan_pcp) << PCP_BITSHIFT); - key->entry.vlan_id = vlan_pcp | vlan_vid; - } -} - -static uint32_t -make_nw_wildcard(int n_wild_bits) -{ - n_wild_bits &= (1u << OFPFW_NW_SRC_BITS) - 1; - return n_wild_bits < 32 ? ((1u << n_wild_bits) - 1) : 0xFFFFFFFF; -} - -/* Populate a nf2_of_mask_wrap with entries from a struct sw_flow's wildcards. */ -void -nf2_populate_of_mask(nf2_of_mask_wrap *mask, struct sw_flow *flow) -{ - int vlan_vid = 0; - int vlan_pcp = 0; - int i; - - if (OFPFW_IN_PORT & flow->key.wildcards) { - mask->entry.src_port = 0xFF; - } - if (OFPFW_DL_VLAN & flow->key.wildcards) { - vlan_vid = VID_BITMASK; - } - if (OFPFW_DL_VLAN_PCP & flow->key.wildcards) { - vlan_pcp = 0xF000; - } - mask->entry.vlan_id = vlan_pcp | vlan_vid; - if (OFPFW_DL_SRC & flow->key.wildcards) { - for (i = 0; i < 6; ++i) { - mask->entry.eth_src[i] = 0xFF; - } - } - if (OFPFW_DL_DST & flow->key.wildcards) { - for (i = 0; i < 6; ++i) { - mask->entry.eth_dst[i] = 0xFF; - } - } - if (OFPFW_DL_TYPE & flow->key.wildcards) - mask->entry.eth_type = 0xFFFF; - if ((OFPFW_NW_SRC_ALL & flow->key.wildcards) - || (OFPFW_NW_SRC_MASK & flow->key.wildcards)) - mask->entry.ip_src = make_nw_wildcard - (flow->key.wildcards >> OFPFW_NW_SRC_SHIFT); - if ((OFPFW_NW_DST_ALL & flow->key.wildcards) - || (OFPFW_NW_DST_MASK & flow->key.wildcards)) - mask->entry.ip_dst = make_nw_wildcard - (flow->key.wildcards >> OFPFW_NW_DST_SHIFT); - if (OFPFW_NW_PROTO & flow->key.wildcards) - mask->entry.ip_proto = 0xFF; - if (OFPFW_TP_SRC & flow->key.wildcards) - mask->entry.transp_src = 0xFFFF; - if (OFPFW_TP_DST & flow->key.wildcards) - mask->entry.transp_dst = 0xFFFF; - if (OFPFW_NW_TOS & flow->key.wildcards) - mask->entry.ip_tos = TOS_BITMASK; - - mask->entry.pad = 0x00; -} - -static void -populate_action_output(nf2_of_action_wrap *action, nf2_of_entry_wrap *entry, - uint8_t *flowact) -{ - uint16_t port = 0; - struct ofp_action_output *actout = (struct ofp_action_output *)flowact; - int i; - - port = ntohs(actout->port); - DBG_VERBOSE("Action Type: %i Output Port: %i\n", - ntohs(actout->type), port); - - if ((port >= PORT_BASE) && (port <= MAX_IFACE)) { - // Bitmask for output port(s), evens are phys odds cpu - action->action.forward_bitmask - |= (1 << ((port - PORT_BASE) * 2)); - DBG_VERBOSE("Output Port: %i Forward Bitmask: %x\n", - port, action->action.forward_bitmask); - } else if (port == OFPP_IN_PORT) { - // Send out to input port - action->action.forward_bitmask - |= (1 << (entry->entry.src_port)); - DBG_VERBOSE("Output Port = Input Port Forward Bitmask: %x\n", - action->action.forward_bitmask); - } else if (port == OFPP_ALL || port == OFPP_FLOOD) { - // Send out all ports except the source - for (i = 0; i < 4; ++i) { - if ((i * 2) != entry->entry.src_port) { - // Bitmask for output port(s), evens are - // phys odds cpu - action->action.forward_bitmask - |= (1 << (i * 2)); - DBG_VERBOSE - ("Output Port: %i Forward Bitmask: %x\n", - port, action->action.forward_bitmask); - } - } - } -} - -static void -populate_action_set_dl_src(nf2_of_action_wrap *action, uint8_t *flowact) -{ - struct ofp_action_dl_addr *actdl = (struct ofp_action_dl_addr *)flowact; - int i; - - for (i = 0; i < 6; ++i) { - action->action.eth_src[5 - i] = actdl->dl_addr[i]; - } - action->action.nf2_action_flag |= (1 << OFPAT_SET_DL_SRC); -} - -static void -populate_action_set_dl_dst(nf2_of_action_wrap *action, uint8_t *flowact) -{ - struct ofp_action_dl_addr *actdl = (struct ofp_action_dl_addr *)flowact; - int i; - - for (i = 0; i < 6; ++i) { - action->action.eth_dst[5 - i] = actdl->dl_addr[i]; - } - action->action.nf2_action_flag |= (1 << OFPAT_SET_DL_DST); -} - -static void -populate_action_set_nw_src(nf2_of_action_wrap *action, uint8_t *flowact) -{ - struct ofp_action_nw_addr *actnw = (struct ofp_action_nw_addr *)flowact; - action->action.ip_src = ntohl(actnw->nw_addr); - action->action.nf2_action_flag |= (1 << OFPAT_SET_NW_SRC); -} - -static void -populate_action_set_nw_dst(nf2_of_action_wrap *action, uint8_t *flowact) -{ - struct ofp_action_nw_addr *actnw = (struct ofp_action_nw_addr *)flowact; - action->action.ip_dst = ntohl(actnw->nw_addr); - action->action.nf2_action_flag |= (1 << OFPAT_SET_NW_DST); -} - -static void -populate_action_set_nw_tos(nf2_of_action_wrap *action, uint8_t *flowact) -{ - struct ofp_action_nw_tos *actnwtos = (struct ofp_action_nw_tos *)flowact; - action->action.ip_tos = actnwtos->nw_tos; - action->action.nf2_action_flag |= (1 << OFPAT_SET_NW_TOS); -} - -static void -populate_action_set_tp_src(nf2_of_action_wrap *action, uint8_t *flowact) -{ - struct ofp_action_tp_port *acttp = (struct ofp_action_tp_port *)flowact; - action->action.transp_src = ntohs(acttp->tp_port); - action->action.nf2_action_flag |= (1 << OFPAT_SET_TP_SRC); -} - -static void -populate_action_set_tp_dst(nf2_of_action_wrap *action, uint8_t *flowact) -{ - struct ofp_action_tp_port *acttp = (struct ofp_action_tp_port *)flowact; - action->action.transp_dst = ntohs(acttp->tp_port); - action->action.nf2_action_flag |= (1 << OFPAT_SET_TP_DST); -} - -static void -populate_action_set_vlan_vid(nf2_of_action_wrap *action, uint8_t *flowact) -{ - struct ofp_action_vlan_vid *actvlan = (struct ofp_action_vlan_vid *)flowact; - action->action.vlan_id = ntohs(actvlan->vlan_vid) & VID_BITMASK; - action->action.nf2_action_flag |= (1 << OFPAT_SET_VLAN_VID); -} - -static void -populate_action_set_vlan_pcp(nf2_of_action_wrap *action, uint8_t *flowact) -{ - struct ofp_action_vlan_pcp *actvlan = (struct ofp_action_vlan_pcp *)flowact; - action->action.vlan_pcp = actvlan->vlan_pcp; - action->action.nf2_action_flag |= (1 << OFPAT_SET_VLAN_PCP); -} - -static void -populate_action_strip_vlan(nf2_of_action_wrap *action) -{ - action->action.nf2_action_flag |= (1 << OFPAT_STRIP_VLAN); -} - -/* Populate an nf2_of_action_wrap. */ -void -nf2_populate_of_action(nf2_of_action_wrap *action, nf2_of_entry_wrap *entry, - struct sw_flow *flow) -{ - struct sw_flow_actions *sfa; - size_t actions_len; - uint8_t *p; - - sfa = flow->sf_acts; - actions_len = sfa->actions_len; - p = (uint8_t *)sfa->actions; - - // zero it out for now - memset(action, 0, sizeof(nf2_of_action_wrap)); - action->action.nf2_action_flag = 0; - - while (actions_len > 0) { - struct ofp_action_header *acth = (struct ofp_action_header *)p; - size_t len = ntohs(acth->len); - - DBG_VERBOSE("Action Populate: Len of this action: %i\n", len); - DBG_VERBOSE("Action Populate: Len of actions : %i\n", - actions_len); - - if (acth->type == htons(OFPAT_OUTPUT)) { - populate_action_output(action, entry, p); - } else if (acth->type == htons(OFPAT_SET_DL_SRC)) { - populate_action_set_dl_src(action, p); - } else if (acth->type == htons(OFPAT_SET_DL_DST)) { - populate_action_set_dl_dst(action, p); - } else if (acth->type == htons(OFPAT_SET_NW_SRC)) { - populate_action_set_nw_src(action, p); - } else if (acth->type == htons(OFPAT_SET_NW_DST)) { - populate_action_set_nw_dst(action, p); - } else if (acth->type == htons(OFPAT_SET_NW_TOS)) { - populate_action_set_nw_tos(action, p); - } else if (acth->type == htons(OFPAT_SET_TP_SRC)) { - populate_action_set_tp_src(action, p); - } else if (acth->type == htons(OFPAT_SET_TP_DST)) { - populate_action_set_tp_dst(action, p); - } else if (acth->type == htons(OFPAT_SET_VLAN_VID)) { - populate_action_set_vlan_vid(action, p); - } else if (acth->type == htons(OFPAT_SET_VLAN_PCP)) { - populate_action_set_vlan_pcp(action, p); - } else if (acth->type == htons(OFPAT_STRIP_VLAN)) { - populate_action_strip_vlan(action); - } - - p += len; - actions_len -= len; - } -} - -/* Add a free hardware entry back to the exact pool. */ -void -nf2_add_free_exact(struct nf2_flow *sfw) -{ - // clear the node entry - list_init(&sfw->node); - - // Critical section, adding to the actual list - exact_free_list[sfw->pos] = sfw; -} - -/* Add a free hardware entry back to the wildcard pool. */ -void -nf2_add_free_wildcard(struct nf2_flow *sfw) -{ - // clear the hw values - sfw->hw_packet_count = 0; - sfw->hw_byte_count = 0; - - // Critical section, adding to the actual list - list_insert(&wildcard_free_list, &sfw->node); -} - -/* Hashes the entry to find where it should exist in the exact table - * returns NULL on failure - */ -static struct nf2_flow * -get_free_exact(nf2_of_entry_wrap *entry) -{ - unsigned int poly1 = 0x04C11DB7; - unsigned int poly2 = 0x1EDC6F41; - struct nf2_flow *sfw = NULL; - unsigned int hash = 0x0; - unsigned int index = 0x0; - struct crc32 crc; - - crc32_init(&crc, poly1); - hash = crc32_calculate(&crc, entry, sizeof(nf2_of_entry_wrap)); - - // the bottom 15 bits of hash == the index into the table - index = 0x7FFF & hash; - - // if this index is free, grab it - sfw = exact_free_list[index]; - exact_free_list[index] = NULL; - - if (sfw != NULL) { - return sfw; - } - // try the second index - crc32_init(&crc, poly2); - hash = crc32_calculate(&crc, entry, sizeof(nf2_of_entry_wrap)); - // the bottom 15 bits of hash == the index into the table - index = 0x7FFF & hash; - - // if this index is free, grab it - sfw = exact_free_list[index]; - exact_free_list[index] = NULL; - - // return whether its good or not - return sfw; -} - -/* Get the first free position in the wildcard hardware table - * to write into. - */ -static struct nf2_flow * -get_free_wildcard(void) -{ - struct nf2_flow *sfw = NULL; - - // Critical section, pulling the first available from the list - if (list_is_empty(&wildcard_free_list)) { - // empty :( - sfw = NULL; - } else { - sfw = CONTAINER_OF(list_front(&wildcard_free_list), struct nf2_flow, node); - list_remove(&sfw->node); - list_init(&sfw->node); - } - - return sfw; -} - -/* Retrieves the type of table this flow should go into. */ -int -nf2_get_table_type(struct sw_flow *flow) -{ - if (flow->key.wildcards != 0) { - DBG_VERBOSE("--- TABLE TYPE: WILDCARD ---\n"); - return NF2_TABLE_WILDCARD; - } else { - DBG_VERBOSE("--- TABLE TYPE: EXACT ---\n"); - return NF2_TABLE_EXACT; - } -} - -/* Returns 1 if this flow contains an action outputting to all ports except - * input port, 0 otherwise. We support OFPP_ALL and OFPP_FLOOD actions, however - * since we do not perform the spanning tree protocol (STP) then OFPP_FLOOD is - * equivalent to OFPP_ALL. - */ -static int -is_action_forward_all(struct sw_flow *flow) -{ - struct sw_flow_actions *sfa; - size_t actions_len; - uint8_t *p; - - sfa = flow->sf_acts; - actions_len = sfa->actions_len; - p = (uint8_t *)sfa->actions; - - while (actions_len > 0) { - struct ofp_action_header *ah = (struct ofp_action_header *)p; - struct ofp_action_output *oa = (struct ofp_action_output *)p; - size_t len = ntohs(ah->len); - - DBG_VERBOSE("Fwd Action Chk: Action type: %x\n", - ntohs(ah->type)); - DBG_VERBOSE("Fwd Action Chk: Output port: %x\n", - ntohs(oa->port)); - DBG_VERBOSE("Fwd Action Chk: Len of this action: %i\n", len); - DBG_VERBOSE("Fwd Action Chk: Len of actions : %i\n", - actions_len); - // Currently only support the output port(s) action - if (ntohs(ah->type) == OFPAT_OUTPUT - && (ntohs(oa->port) == OFPP_ALL - || ntohs(oa->port) == OFPP_FLOOD)) { - return 1; - } - p += len; - actions_len -= len; - } - - return 0; -} - -/* Attempts to build and write the flow to hardware. - * Returns 0 on success, 1 on failure. - */ -int -nf2_build_and_write_flow(struct sw_flow *flow) -{ - struct nf2_flow *sfw = NULL; - struct nf2_flow *sfw_next = NULL; - struct nf2device *dev; - int num_entries = 0; - int i, table_type; - nf2_of_entry_wrap key; - nf2_of_mask_wrap mask; - nf2_of_action_wrap action; - - memset(&key, 0, sizeof(nf2_of_entry_wrap)); - memset(&mask, 0, sizeof(nf2_of_mask_wrap)); - memset(&action, 0, sizeof(nf2_of_action_wrap)); - - dev = nf2_get_net_device(); - if (dev == NULL) { - return 1; - } - - table_type = nf2_get_table_type(flow); - switch (table_type) { - default: - break; - - case NF2_TABLE_EXACT: - DBG_VERBOSE("---Exact Entry---\n"); - nf2_populate_of_entry(&key, flow); - nf2_populate_of_action(&action, &key, flow); - sfw = get_free_exact(&key); - if (sfw == NULL) { - DBG_VERBOSE - ("Collision getting free exact match entry\n"); - // collision - nf2_free_net_device(dev); - return 1; - } - // set the active bit on this entry - key.entry.pad = 0x80; - nf2_write_of_exact(dev, sfw->pos, &key, &action); - flow->private = (void *)sfw; - break; - - case NF2_TABLE_WILDCARD: - DBG_VERBOSE("---Wildcard Entry---\n"); - // if action is all out and source port is wildcarded - if ((is_action_forward_all(flow)) && - (flow->key.wildcards & OFPFW_IN_PORT)) { - DBG_VERBOSE("Grab four wildcard tables\n"); - if (!(sfw = get_free_wildcard())) { - DBG_VERBOSE("No free wildcard entries found."); - // no free entries - nf2_free_net_device(dev); - return 1; - } - // try to get 3 more positions - for (i = 0; i < 3; ++i) { - if (!(sfw_next = get_free_wildcard())) { - break; - } - list_insert(&sfw->node, &sfw_next->node); - ++num_entries; - } - - if (num_entries < 3) { - // failed to get enough entries, return them and exit - nf2_delete_private((void *)sfw); - nf2_free_net_device(dev); - return 1; - } - - nf2_populate_of_entry(&key, flow); - nf2_populate_of_mask(&mask, flow); - - // set first entry's src port to 0, remove wildcard mask on src - key.entry.src_port = 0; - mask.entry.src_port = 0; - nf2_populate_of_action(&action, &key, flow); - nf2_write_of_wildcard(dev, sfw->pos, &key, &mask, - &action); - - i = 1; - sfw_next = CONTAINER_OF(list_front(&sfw->node), - struct nf2_flow, node); - // walk through and write the remaining 3 entries - while (sfw_next != sfw) { - key.entry.src_port = i * 2; - nf2_populate_of_action(&action, &key, flow); - nf2_write_of_wildcard(dev, sfw_next->pos, &key, - &mask, &action); - sfw_next = CONTAINER_OF(list_front(&sfw_next->node), - struct nf2_flow, node); - ++i; - } - flow->private = (void *)sfw; - } else { - /* Get a free position here, and write to it */ - if ((sfw = get_free_wildcard())) { - nf2_populate_of_entry(&key, flow); - nf2_populate_of_mask(&mask, flow); - nf2_populate_of_action(&action, &key, flow); - if (nf2_write_of_wildcard - (dev, sfw->pos, &key, &mask, &action)) { - // failure writing to hardware - nf2_add_free_wildcard(sfw); - DBG_VERBOSE - ("Failure writing to hardware\n"); - nf2_free_net_device(dev); - return 1; - } else { - // success writing to hardware, store the position - flow->private = (void *)sfw; - } - } else { - // hardware is full, return 0 - DBG_VERBOSE("No free wildcard entries found."); - nf2_free_net_device(dev); - return 1; - } - } - break; - } - - nf2_free_net_device(dev); - return 0; -} - -void -nf2_delete_private(void *private) -{ - struct nf2_flow *sfw = (struct nf2_flow *)private; - struct nf2_flow *sfw_next; - struct list *next; - - switch (sfw->type) { - default: - break; - - case NF2_TABLE_EXACT: - nf2_clear_of_exact(sfw->pos); - nf2_add_free_exact(sfw); - break; - - case NF2_TABLE_WILDCARD: - while (!list_is_empty(&sfw->node)) { - next = sfw->node.next; - sfw_next = CONTAINER_OF(list_front(&sfw->node), struct nf2_flow, node); - list_remove(&sfw_next->node); - list_init(&sfw_next->node); - // Immediately zero out the entry in hardware - nf2_clear_of_wildcard(sfw_next->pos); - // add it back to the pool - nf2_add_free_wildcard(sfw_next); - } - // zero the core entry - nf2_clear_of_wildcard(sfw->pos); - // add back the core entry - nf2_add_free_wildcard(sfw); - break; - } -} - -int -nf2_modify_acts(struct sw_flow *flow) -{ - struct nf2_flow *sfw = (struct nf2_flow *)flow->private; - struct nf2device *dev; - nf2_of_entry_wrap key; - nf2_of_mask_wrap mask; - nf2_of_action_wrap action; - - memset(&key, 0, sizeof(nf2_of_entry_wrap)); - memset(&mask, 0, sizeof(nf2_of_mask_wrap)); - memset(&action, 0, sizeof(nf2_of_action_wrap)); - - dev = nf2_get_net_device(); - if (dev == NULL) - return 0; - - switch (sfw->type) { - default: - break; - - case NF2_TABLE_EXACT: - nf2_populate_of_entry(&key, flow); - nf2_populate_of_action(&action, &key, flow); - key.entry.pad = 0x80; - nf2_modify_write_of_exact(dev, sfw->pos, &action); - break; - - case NF2_TABLE_WILDCARD: - if (flow->key.wildcards & OFPFW_IN_PORT) { - nf2_free_net_device(dev); - return 0; - } - nf2_populate_of_entry(&key, flow); - nf2_populate_of_mask(&mask, flow); - nf2_populate_of_action(&action, &key, flow); - nf2_modify_write_of_wildcard(dev, sfw->pos, - &key, &mask, &action); - break; - } - - nf2_free_net_device(dev); - return 1; -} - -uint64_t -nf2_get_packet_count(struct nf2device *dev, struct nf2_flow *sfw) -{ - uint32_t count = 0; - uint32_t hw_count = 0; - uint64_t total = 0; - struct nf2_flow *sfw_next = NULL; - - switch (sfw->type) { - default: - break; - - case NF2_TABLE_EXACT: - // Get delta value - total = nf2_get_exact_packet_count(dev, sfw->pos); - break; - - case NF2_TABLE_WILDCARD: - sfw_next = sfw; - do { - // Get sum value - hw_count = nf2_get_wildcard_packet_count(dev, - sfw_next->pos); - if (hw_count >= sfw_next->hw_packet_count) { - count = hw_count - sfw_next->hw_packet_count; - sfw_next->hw_packet_count = hw_count; - } else { - // wrapping occurred - count = (MAX_INT_32 - sfw_next->hw_packet_count) - + hw_count; - sfw_next->hw_packet_count = hw_count; - } - total += count; - - if(!list_is_empty(&sfw_next->node)){ - sfw_next = CONTAINER_OF(list_front(&sfw_next->node), - struct nf2_flow, node); - } - } while (sfw_next != sfw); - break; - } - - return total; -} - -uint64_t -nf2_get_byte_count(struct nf2device *dev, struct nf2_flow *sfw) -{ - uint32_t count = 0; - uint32_t hw_count = 0; - uint64_t total = 0; - struct nf2_flow *sfw_next = NULL; - - switch (sfw->type) { - default: - break; - - case NF2_TABLE_EXACT: - // Get delta value - total = nf2_get_exact_byte_count(dev, sfw->pos); - break; - - case NF2_TABLE_WILDCARD: - sfw_next = sfw; - do { - // Get sum value - hw_count = nf2_get_wildcard_byte_count(dev, - sfw_next->pos); - if (hw_count >= sfw_next->hw_byte_count) { - count = hw_count - sfw_next->hw_byte_count; - sfw_next->hw_byte_count = hw_count; - } else { - // wrapping occurred - count = (MAX_INT_32 - sfw_next->hw_byte_count) - + hw_count; - sfw_next->hw_byte_count = hw_count; - } - - total += count; - - if(!list_is_empty(&sfw_next->node)) { - sfw_next = CONTAINER_OF(list_front(&sfw_next->node), - struct nf2_flow, node); - } - } while (sfw_next != sfw); - break; - } - - return total; -} diff --git a/openflow/hw-lib/nf2/nf2_lib.h b/openflow/hw-lib/nf2/nf2_lib.h deleted file mode 100644 index cc75b2c6..00000000 --- a/openflow/hw-lib/nf2/nf2_lib.h +++ /dev/null @@ -1,59 +0,0 @@ -/*- - * Copyright (c) 2008, 2009, 2010 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#ifndef HWTABLE_NF2_NF2_LIB_H_ -#define HWTABLE_NF2_NF2_LIB_H_ - -struct nf2device *nf2_get_net_device(void); -void nf2_free_net_device(struct nf2device *); -int nf2_are_actions_supported(struct sw_flow *); -void nf2_clear_of_exact(uint32_t); -void nf2_clear_of_wildcard(uint32_t); -int nf2_init_exact_freelist(void); -int nf2_init_wildcard_freelist(void); -void nf2_destroy_exact_freelist(void); -void nf2_destroy_wildcard_freelist(void); -int nf2_write_static_wildcard(void); -void nf2_populate_of_entry(nf2_of_entry_wrap *, struct sw_flow *); -void nf2_populate_of_mask(nf2_of_mask_wrap *, struct sw_flow *); -void nf2_populate_of_action(nf2_of_action_wrap *, nf2_of_entry_wrap *, - struct sw_flow *); -void nf2_add_free_exact(struct nf2_flow *); -void nf2_add_free_wildcard(struct nf2_flow *); -int nf2_get_table_type(struct sw_flow *); -int nf2_build_and_write_flow(struct sw_flow *); -void nf2_delete_private(void *); -int nf2_modify_acts(struct sw_flow *); -uint64_t nf2_get_packet_count(struct nf2device *, struct nf2_flow *); -uint64_t nf2_get_byte_count(struct nf2device *, struct nf2_flow *); - -#endif diff --git a/openflow/hw-lib/nf2/nf2util.c b/openflow/hw-lib/nf2/nf2util.c deleted file mode 100644 index fd3b500e..00000000 --- a/openflow/hw-lib/nf2/nf2util.c +++ /dev/null @@ -1,400 +0,0 @@ -/* **************************************************************************** - * $Id: nf2util.c 3764 2008-05-22 06:48:34Z grg $ - * - * Module: nf2util.c - * Project: NetFPGA 2 Linux Kernel Driver - * Description: Utility functions for user mode programs - * - * Change history: - * - */ - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include - -#include "nf2.h" -#include "nf2util.h" - -#include "reg_defines_openflow_switch.h" - -#define MD5_LEN 4 - -/* Function declarations */ -static int readRegNet(struct nf2device *nf2, unsigned reg, unsigned *val); -static int readRegFile(struct nf2device *nf2, unsigned reg, unsigned *val); -static int writeRegNet(struct nf2device *nf2, unsigned reg, unsigned val); -static int writeRegFile(struct nf2device *nf2, unsigned reg, unsigned val); - -/* Local variables */ -unsigned cpci_version = -1; -unsigned cpci_revision = -1; -unsigned nf2_device_id = -1; -unsigned nf2_revision = -1; -unsigned nf2_cpci_version = -1; -unsigned nf2_cpci_revision = -1; -char nf2_device_str[DEVICE_STR_LEN] = ""; - -/* - * readReg - read a register - */ -int readReg(struct nf2device *nf2, unsigned reg, unsigned *val) -{ - if (nf2->net_iface) - { - return readRegNet(nf2, reg, val); - } - else - { - return readRegFile(nf2, reg, val); - } -} - -/* - * readRegNet - read a register, using a network socket - */ -static int readRegNet(struct nf2device *nf2, unsigned reg, unsigned *val) -{ - struct ifreq ifreq; - struct nf2reg nf2reg; - int ret; - - nf2reg.reg = reg; - - /* Set up the ifreq structure */ - ifreq.ifr_data = (char *)&nf2reg; - strncpy(ifreq.ifr_ifrn.ifrn_name, nf2->device_name, IFNAMSIZ); - /*if (setsockopt(nf2->fd, SOL_SOCKET, SO_BINDTODEVICE, - (char *)&ifreq, sizeof(ifreq)) < 0) { - perror("sendpacket: setting SO_BINDTODEVICE"); - return -1; - } */ - - /* Call the ioctl */ - if ((ret = ioctl(nf2->fd, SIOCREGREAD, &ifreq)) == 0) - { - *val = nf2reg.val; - return 0; - } - else - { - perror("sendpacket: ioctl failed"); - return -1; - } -} - -/* - * readRegFile - read a register, using a file descriptor - */ -static int readRegFile(struct nf2device *nf2, unsigned reg, unsigned *val) -{ - struct nf2reg nf2reg; - int ret; - - nf2reg.reg = reg; - - /* Call the ioctl */ - if ((ret = ioctl(nf2->fd, SIOCREGREAD, &nf2reg)) == 0) - { - *val = nf2reg.val; - return 0; - } - else - { - perror("sendpacket: ioctl failed"); - return -1; - } -} - - -/* - * writeReg - write a register - */ -int writeReg(struct nf2device *nf2, unsigned reg, unsigned val) -{ - if (nf2->net_iface) - { - return writeRegNet(nf2, reg, val); - } - else - { - return writeRegFile(nf2, reg, val); - } -} - - -/* - * writeRegNet - write a register, using a network socket - */ -static int writeRegNet(struct nf2device *nf2, unsigned reg, unsigned val) -{ - struct ifreq ifreq; - struct nf2reg nf2reg; - int ret; - - nf2reg.reg = reg; - nf2reg.val = val; - - /* Set up the ifreq structure */ - ifreq.ifr_data = (char *)&nf2reg; - strncpy(ifreq.ifr_ifrn.ifrn_name, nf2->device_name, IFNAMSIZ); - /*if (setsockopt(nf2->fd, SOL_SOCKET, SO_BINDTODEVICE, - (char *)&ifreq, sizeof(ifreq)) < 0) { - perror("sendpacket: setting SO_BINDTODEVICE"); - return -1; - } */ - - /* Call the ioctl */ - if ((ret = ioctl(nf2->fd, SIOCREGWRITE, &ifreq)) == 0) - { - return 0; - } - else - { - perror("sendpacket: ioctl failed"); - return -1; - } -} - - -/* - * writeRegFile - write a register, using a file descriptor - */ -static int writeRegFile(struct nf2device *nf2, unsigned reg, unsigned val) -{ - struct nf2reg nf2reg; - int ret; - - nf2reg.reg = reg; - nf2reg.val = val; - - /* Call the ioctl */ - if ((ret = ioctl(nf2->fd, SIOCREGWRITE, &nf2reg)) == 0) - { - return 0; - } - else - { - perror("sendpacket: ioctl failed"); - return -1; - } -} - -/* - * Check the iface name to make sure we can find the interface - */ -int check_iface(struct nf2device *nf2) -{ - struct stat buf; - char filename[PATHLEN]; - - /* See if we can find the interface name as a network device */ - - /* Test the length first of all */ - if (strlen(nf2->device_name) > IFNAMSIZ) - { - fprintf(stderr, "Interface name is too long: %s\n", nf2->device_name); - return -1; - } - - /* Check for /sys/class/net/iface_name */ - strcpy(filename, "/sys/class/net/"); - strcat(filename, nf2->device_name); - if (stat(filename, &buf) == 0) - { - nf2->net_iface = 1; - return 0; - } - - /* Check for /dev/iface_name */ - strcpy(filename, "/dev/"); - strcat(filename, nf2->device_name); - if (stat(filename, &buf) == 0) - { - nf2->net_iface = 0; - return 0; - } - - fprintf(stderr, "Can't find device: %s\n", nf2->device_name); - return -1; -} - -/* - * Open the descriptor associated with the device name - */ -int openDescriptor(struct nf2device *nf2) -{ - struct ifreq ifreq; - char filename[PATHLEN]; - struct sockaddr_in address; - int i; - struct sockaddr_in *sin = (struct sockaddr_in *) &ifreq.ifr_addr; - int found = 0; - - if (nf2->net_iface) - { - /* Open a network socket */ - nf2->fd = socket(AF_INET, SOCK_DGRAM, 0); - if (nf2->fd == -1) - { - perror("socket: creating socket"); - return -1; - } - else - { - /* Root can bind to a network interface. - Non-root has to bind to a network address. */ - if (geteuid() == 0) - { - strncpy(ifreq.ifr_ifrn.ifrn_name, nf2->device_name, IFNAMSIZ); - if (setsockopt(nf2->fd, SOL_SOCKET, SO_BINDTODEVICE, - (char *)&ifreq, sizeof(ifreq)) < 0) { - perror("setsockopt: setting SO_BINDTODEVICE"); - return -1; - } - - } - else - { - /* Attempt to find the IP address for the interface */ - for (i = 1; ; i++) - { - /* Find interface number i*/ - ifreq.ifr_ifindex = i; - if (ioctl (nf2->fd, SIOCGIFNAME, &ifreq) < 0) - break; - - /* Check if we've found the correct interface */ - if (strcmp(ifreq.ifr_name, nf2->device_name) != 0) - continue; - - /* If we get to here we've found the IP */ - found = 1; - break; - } - - /* Verify that we found the interface */ - if (!found) - { - fprintf(stderr, "Can't find device: %s\n", nf2->device_name); - return -1; - } - - /* Attempt to get the IP address associated with the interface */ - if (ioctl (nf2->fd, SIOCGIFADDR, &ifreq) < 0) - { - perror("ioctl: calling SIOCGIFADDR"); - - fprintf(stderr, "Unable to find IP address for device: %s\n", nf2->device_name); - fprintf(stderr, "Either run this program as root or ask an administrator\n"); - fprintf(stderr, "to assign an IP address to the device\n"); - return -1; - } - - /* Set the addres and attempt to bind to the socket */ - address.sin_family = AF_INET; - address.sin_addr.s_addr = sin->sin_addr.s_addr; - address.sin_port = htons(0); - if (bind(nf2->fd,(struct sockaddr *)&address,sizeof(address)) == -1) { - perror("bind: binding"); - return -1; - } - } - } - } - else - { - strcpy(filename, "/dev/"); - strcat(filename, nf2->device_name); - nf2->fd = fileno(fopen(filename, "w+")); - if (nf2->fd == -1) - { - perror("fileno: creating descriptor"); - return -1; - } - } - - return 0; -} - -/* - * Close the descriptor associated with the device name - */ -int closeDescriptor(struct nf2device *nf2) -{ - if (nf2->net_iface) - { - close(nf2->fd); - } - else - { - close(nf2->fd); - } - - return 0; -} - -/* - * Read the version info from the Virtex and CPCI - */ -void nf2_read_info(struct nf2device *nf2) -{ - int i; - int md5_good = 1; - unsigned md5[MD5_LEN]; - unsigned cpci_id; - unsigned nf2_cpci_id; - - // Read the CPCI version/revision - readReg(nf2, CPCI_REG_ID, &cpci_id); - cpci_version = cpci_id & 0xffffff; - cpci_revision = cpci_id >> 24; - - // Verify the MD5 checksum of the device ID block - for (i = 0; i < MD5_LEN; i++) { - readReg(nf2, DEV_ID_MD5_0_REG + i * 4, &md5[i]); - } - md5_good &= md5[0] == DEV_ID_MD5_VALUE_0; - md5_good &= md5[1] == DEV_ID_MD5_VALUE_1; - md5_good &= md5[2] == DEV_ID_MD5_VALUE_2; - md5_good &= md5[3] == DEV_ID_MD5_VALUE_3; - - // Process only if the MD5 sum is good - if (md5_good) { - // Read the version and revision - readReg(nf2, DEV_ID_DEVICE_ID_REG, &nf2_device_id); - readReg(nf2, DEV_ID_REVISION_REG, &nf2_revision); - readReg(nf2, DEV_ID_CPCI_ID_REG, &nf2_cpci_id); - nf2_cpci_version = nf2_cpci_id & 0xffffff; - nf2_cpci_revision = nf2_cpci_id >> 24; - - // Read the version string - for (i = 0; i < (DEVICE_STR_LEN / 4) - 2; i++) - { - readReg(nf2, DEV_ID_DEV_STR_0_REG + i * 4, (unsigned *)(nf2_device_str + i * 4)); - - // Perform byte swapping if necessary - *(unsigned *)(nf2_device_str + i * 4) = ntohl(*(unsigned *)(nf2_device_str + i * 4)); - } - nf2_device_str[DEVICE_STR_LEN - 1] = '\0'; - } -} - -/* - * Print out a test string - */ -void printHello (struct nf2device *nf2, int *val) -{ - printf ("Hello world. Name=%s val=%d\n", nf2->device_name, *val); - *val = 10; -} diff --git a/openflow/hw-lib/nf2/nf2util.h b/openflow/hw-lib/nf2/nf2util.h deleted file mode 100644 index 88d3c159..00000000 --- a/openflow/hw-lib/nf2/nf2util.h +++ /dev/null @@ -1,46 +0,0 @@ -/* **************************************************************************** - * $Id: nf2util.h 3764 2008-05-22 06:48:34Z grg $ - * - * Module: nf2util.h - * Project: NetFPGA 2 Linux Kernel Driver - * Description: Header file for kernel driver - * - * Change history: - * - */ - -#ifndef _NF2UTIL_H -#define _NF2UTIL_H 1 - -#define PATHLEN 80 -#define DEVICE_STR_LEN 100 - - -/* - * Structure to represent an nf2 device to a user mode programs - */ -struct nf2device { - char *device_name; - int fd; - int net_iface; -}; - -/* Function declarations */ - -int readReg(struct nf2device *nf2, unsigned reg, unsigned *val); -int writeReg(struct nf2device *nf2, unsigned reg, unsigned val); -int check_iface(struct nf2device *nf2); -int openDescriptor(struct nf2device *nf2); -int closeDescriptor(struct nf2device *nf2); -void nf2_read_info(struct nf2device *nf2); -void printHello (struct nf2device *nf2, int *val); - -extern unsigned cpci_version; -extern unsigned cpci_revision; -extern unsigned nf2_device_id; -extern unsigned nf2_revision; -extern unsigned nf2_cpci_version; -extern unsigned nf2_cpci_revision; -extern char nf2_device_str[DEVICE_STR_LEN]; - -#endif diff --git a/openflow/hw-lib/nf2/reg_defines_openflow_switch.h b/openflow/hw-lib/nf2/reg_defines_openflow_switch.h deleted file mode 100644 index 0056f882..00000000 --- a/openflow/hw-lib/nf2/reg_defines_openflow_switch.h +++ /dev/null @@ -1,767 +0,0 @@ -/******************************************************** -* -* C register defines file for openflow_switch -* -********************************************************/ - -#ifndef _REG_DEFINES_ -#define _REG_DEFINES_ - -/* ========= Constants ========= */ - -// ===== File: lib/verilog/core/common/xml/global.xml ===== - -// Maximum number of phy ports -#define MAX_PHY_PORTS 4 - -// PCI address bus width -#define PCI_ADDR_WIDTH 32 - -// PCI data bus width -#define PCI_DATA_WIDTH 32 - -// PCI byte enable bus width -#define PCI_BE_WIDTH 4 - -// CPCI--CNET address bus width. This is byte addresses even though bottom bits are zero. -#define CPCI_CNET_ADDR_WIDTH 27 - -// CPCI--CNET data bus width -#define CPCI_CNET_DATA_WIDTH 32 - -// CPCI--NF2 address bus width. This is byte addresses even though bottom bits are zero. -#define CPCI_NF2_ADDR_WIDTH 27 - -// CPCI--NF2 data bus width -#define CPCI_NF2_DATA_WIDTH 32 - -// DMA data bus width -#define DMA_DATA_WIDTH 32 - -// DMA control bus width -#define DMA_CTRL_WIDTH 4 - -// CPCI debug bus width -#define CPCI_DEBUG_DATA_WIDTH 29 - -// SRAM address width -#define SRAM_ADDR_WIDTH 19 - -// SRAM data width -#define SRAM_DATA_WIDTH 36 - -// DRAM address width -#define DRAM_ADDR_WIDTH 24 - -// ===== File: lib/verilog/core/common/xml/nf_defines.xml ===== - -// Clock period of 125 MHz clock in ns -#define FAST_CLK_PERIOD 8 - -// Clock period of 62.5 MHz clock in ns -#define SLOW_CLK_PERIOD 16 - -// Header value used by the IO queues -#define IO_QUEUE_STAGE_NUM 0xff - -// Data path data width -#define DATA_WIDTH 64 - -// Data path control width -#define CTRL_WIDTH 8 - -// ===== File: projects/openflow_switch/include/output_port_lookup.xml ===== - -#define FAST_CLOCK_PERIOD 8 - -// ===== File: projects/openflow_switch/include/vlan_remover.xml ===== - -#define VLAN_CTRL_WORD 0x42 - -#define VLAN_ETHERTYPE 0x8100 - -// ===== File: lib/verilog/core/output_queues/bram_output_queues/xml/bram_output_queues.xml ===== - -#define NUM_OUTPUT_QUEUES 8 - -// ===== File: projects/openflow_switch/include/opl_processor.xml ===== - -#define NF2_OFPAT_OUTPUT 0x0001 - -#define NF2_OFPAT_SET_VLAN_VID 0x0002 - -#define NF2_OFPAT_SET_VLAN_PCP 0x0004 - -#define NF2_OFPAT_STRIP_VLAN 0x0008 - -#define NF2_OFPAT_SET_DL_SRC 0x0010 - -#define NF2_OFPAT_SET_DL_DST 0x0020 - -#define NF2_OFPAT_SET_NW_SRC 0x0040 - -#define NF2_OFPAT_SET_NW_DST 0x0080 - -#define NF2_OFPAT_SET_TP_SRC 0x0100 - -#define NF2_OFPAT_SET_TP_DST 0x0200 - -// ===== File: projects/openflow_switch/include/wildcard_match.xml ===== - -#define OPENFLOW_WILDCARD_TABLE_SIZE 32 - -#define OPENFLOW_WILDCARD_NUM_DATA_WORDS_USED 10 - -#define OPENFLOW_WILDCARD_NUM_CMP_WORDS_USED 8 - -// ===== File: lib/verilog/core/utils/xml/device_id_reg.xml ===== - -// Total number of registers -#define DEV_ID_NUM_REGS 32 - -// Number of non string registers -#define DEV_ID_NON_DEV_STR_REGS 7 - -// Device description length (in words, not chars) -#define DEV_ID_DEV_STR_WORD_LEN 25 - -// Device description length (in bytes/chars) -#define DEV_ID_DEV_STR_BYTE_LEN 100 - -// Device description length (in bits) -#define DEV_ID_DEV_STR_BIT_LEN 800 - -// Length of MD5 sum (bits) -#define DEV_ID_MD5SUM_LENGTH 128 - -// MD5 sum of the string "device_id.v" -#define DEV_ID_MD5_VALUE 0x4071736d8a603d2b4d55f62989a73c95 -#define DEV_ID_MD5_VALUE_0 0x4071736d -#define DEV_ID_MD5_VALUE_1 0x8a603d2b -#define DEV_ID_MD5_VALUE_2 0x4d55f629 -#define DEV_ID_MD5_VALUE_3 0x89a73c95 - -// ===== File: projects/openflow_switch/include/header_parser.xml ===== - -#define ETH_TYPE_IP 0x0800 - -#define IP_PROTO_TCP 0x06 - -#define IP_PROTO_UDP 0x11 - -#define IP_PROTO_ICMP 0x01 - -// ===== File: projects/openflow_switch/include/watchdog.xml ===== - -#define WDT_CPCI_REG_CTRL 0x00000008 - -// ===== File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml ===== - -// TX queue disable bit -#define MAC_GRP_TX_QUEUE_DISABLE_BIT_NUM 0 - -// RX queue disable bit -#define MAC_GRP_RX_QUEUE_DISABLE_BIT_NUM 1 - -// Reset MAC bit -#define MAC_GRP_RESET_MAC_BIT_NUM 2 - -// MAC TX queue disable bit -#define MAC_GRP_MAC_DISABLE_TX_BIT_NUM 3 - -// MAC RX queue disable bit -#define MAC_GRP_MAC_DISABLE_RX_BIT_NUM 4 - -// MAC disable jumbo TX bit -#define MAC_GRP_MAC_DIS_JUMBO_TX_BIT_NUM 5 - -// MAC disable jumbo RX bit -#define MAC_GRP_MAC_DIS_JUMBO_RX_BIT_NUM 6 - -// MAC disable crc check disable bit -#define MAC_GRP_MAC_DIS_CRC_CHECK_BIT_NUM 7 - -// MAC disable crc generate bit -#define MAC_GRP_MAC_DIS_CRC_GEN_BIT_NUM 8 - -// ===== File: projects/openflow_switch/include/match_arbiter.xml ===== - -#define OPENFLOW_ENTRY_TRANSP_DST_WIDTH 16 - -#define OPENFLOW_ENTRY_TRANSP_DST_POS 0 - -#define OPENFLOW_ENTRY_TRANSP_SRC_WIDTH 16 - -#define OPENFLOW_ENTRY_TRANSP_SRC_POS 16 - -#define OPENFLOW_ENTRY_IP_PROTO_WIDTH 8 - -#define OPENFLOW_ENTRY_IP_PROTO_POS 32 - -#define OPENFLOW_ENTRY_IP_DST_WIDTH 32 - -#define OPENFLOW_ENTRY_IP_DST_POS 40 - -#define OPENFLOW_ENTRY_IP_SRC_WIDTH 32 - -#define OPENFLOW_ENTRY_IP_SRC_POS 72 - -#define OPENFLOW_ENTRY_ETH_TYPE_WIDTH 16 - -#define OPENFLOW_ENTRY_ETH_TYPE_POS 104 - -#define OPENFLOW_ENTRY_ETH_DST_WIDTH 48 - -#define OPENFLOW_ENTRY_ETH_DST_POS 120 - -#define OPENFLOW_ENTRY_ETH_SRC_WIDTH 48 - -#define OPENFLOW_ENTRY_ETH_SRC_POS 168 - -#define OPENFLOW_ENTRY_SRC_PORT_WIDTH 8 - -#define OPENFLOW_ENTRY_SRC_PORT_POS 216 - -#define OPENFLOW_ENTRY_VLAN_ID_WIDTH 16 - -#define OPENFLOW_ENTRY_VLAN_ID_POS 224 - -#define OPENFLOW_ENTRY_WIDTH 240 - -// The actionfield is composed of a bitmask specifying actions to take and arguments. -#define OPENFLOW_ACTION_WIDTH 320 - -// Ports to forward on -#define OPENFLOW_FORWARD_BITMASK_WIDTH 16 - -#define OPENFLOW_FORWARD_BITMASK_POS 0 - -#define OPENFLOW_NF2_ACTION_FLAG_WIDTH 16 - -#define OPENFLOW_NF2_ACTION_FLAG_POS 16 - -// Vlan ID to be replaced -#define OPENFLOW_SET_VLAN_VID_WIDTH 16 - -#define OPENFLOW_SET_VLAN_VID_POS 32 - -// Vlan priority to be replaced -#define OPENFLOW_SET_VLAN_PCP_WIDTH 8 - -#define OPENFLOW_SET_VLAN_PCP_POS 48 - -// Source MAC address to be replaced -#define OPENFLOW_SET_DL_SRC_WIDTH 48 - -#define OPENFLOW_SET_DL_SRC_POS 56 - -// Destination MAC address to be replaced -#define OPENFLOW_SET_DL_DST_WIDTH 48 - -#define OPENFLOW_SET_DL_DST_POS 104 - -// Source network address to be replaced -#define OPENFLOW_SET_NW_SRC_WIDTH 32 - -#define OPENFLOW_SET_NW_SRC_POS 152 - -// Destination network address to be replaced -#define OPENFLOW_SET_NW_DST_WIDTH 32 - -#define OPENFLOW_SET_NW_DST_POS 184 - -// Source transport port to be replaced -#define OPENFLOW_SET_TP_SRC_WIDTH 16 - -#define OPENFLOW_SET_TP_SRC_POS 216 - -// Destination transport port to be replaced -#define OPENFLOW_SET_TP_DST_WIDTH 16 - -#define OPENFLOW_SET_TP_DST_POS 232 - -// ===== File: projects/openflow_switch/include/exact_match.xml ===== - -#define OPENFLOW_EXACT_ENTRY_PKT_COUNTER_WIDTH 25 - -#define OPENFLOW_EXACT_ENTRY_PKT_COUNTER_POS 0 - -#define OPENFLOW_EXACT_ENTRY_LAST_SEEN_WIDTH 7 - -#define OPENFLOW_EXACT_ENTRY_LAST_SEEN_POS 25 - -#define OPENFLOW_EXACT_ENTRY_BYTE_COUNTER_WIDTH 32 - -#define OPENFLOW_EXACT_ENTRY_BYTE_COUNTER_POS 32 - -#define OPENFLOW_EXACT_ENTRY_HDR_BASE_POS 0x00000000 - -#define OPENFLOW_EXACT_ENTRY_COUNTERS_POS 0x00000008 - -#define OPENFLOW_EXACT_ENTRY_ACTION_BASE_POS 0x0000000a - -// ------------------------------------- -// Modules -// ------------------------------------- - -// Module tags -#define CORE_BASE_ADDR 0x0000000 -#define DEV_ID_BASE_ADDR 0x0400000 -#define MDIO_BASE_ADDR 0x0440000 -#define DMA_BASE_ADDR 0x0500000 -#define MAC_GRP_0_BASE_ADDR 0x0600000 -#define MAC_GRP_1_BASE_ADDR 0x0640000 -#define MAC_GRP_2_BASE_ADDR 0x0680000 -#define MAC_GRP_3_BASE_ADDR 0x06c0000 -#define CPU_QUEUE_0_BASE_ADDR 0x0700000 -#define CPU_QUEUE_1_BASE_ADDR 0x0740000 -#define CPU_QUEUE_2_BASE_ADDR 0x0780000 -#define CPU_QUEUE_3_BASE_ADDR 0x07c0000 -#define SRAM_BASE_ADDR 0x1000000 -#define UDP_BASE_ADDR 0x2000000 -#define OPENFLOW_LOOKUP_BASE_ADDR 0x2000000 -#define IN_ARB_BASE_ADDR 0x2000100 -#define VLAN_REMOVER_BASE_ADDR 0x2000200 -#define OPL_PROCESSOR_BASE_ADDR 0x2000240 -#define HEADER_PARSER_BASE_ADDR 0x2000280 -#define MATCH_ARBITER_BASE_ADDR 0x20002c0 -#define BRAM_OQ_BASE_ADDR 0x2000300 -#define WDT_BASE_ADDR 0x2000400 -#define EXACT_MATCH_BASE_ADDR 0x2000500 -#define OPENFLOW_WILDCARD_LOOKUP_BASE_ADDR 0x2001000 -#define DRAM_BASE_ADDR 0x4000000 - -#define CPU_QUEUE_OFFSET 0x0040000 -#define MAC_GRP_OFFSET 0x0040000 - -/* ========== Registers ========== */ - -// Name: device_id (DEV_ID) -// Description: Device identification -// File: lib/verilog/core/utils/xml/device_id_reg.xml -#define DEV_ID_MD5_0_REG 0x0400000 -#define DEV_ID_MD5_1_REG 0x0400004 -#define DEV_ID_MD5_2_REG 0x0400008 -#define DEV_ID_MD5_3_REG 0x040000c -#define DEV_ID_DEVICE_ID_REG 0x0400010 -#define DEV_ID_REVISION_REG 0x0400014 -#define DEV_ID_CPCI_ID_REG 0x0400018 -#define DEV_ID_DEV_STR_0_REG 0x040001c -#define DEV_ID_DEV_STR_1_REG 0x0400020 -#define DEV_ID_DEV_STR_2_REG 0x0400024 -#define DEV_ID_DEV_STR_3_REG 0x0400028 -#define DEV_ID_DEV_STR_4_REG 0x040002c -#define DEV_ID_DEV_STR_5_REG 0x0400030 -#define DEV_ID_DEV_STR_6_REG 0x0400034 -#define DEV_ID_DEV_STR_7_REG 0x0400038 -#define DEV_ID_DEV_STR_8_REG 0x040003c -#define DEV_ID_DEV_STR_9_REG 0x0400040 -#define DEV_ID_DEV_STR_10_REG 0x0400044 -#define DEV_ID_DEV_STR_11_REG 0x0400048 -#define DEV_ID_DEV_STR_12_REG 0x040004c -#define DEV_ID_DEV_STR_13_REG 0x0400050 -#define DEV_ID_DEV_STR_14_REG 0x0400054 -#define DEV_ID_DEV_STR_15_REG 0x0400058 -#define DEV_ID_DEV_STR_16_REG 0x040005c -#define DEV_ID_DEV_STR_17_REG 0x0400060 -#define DEV_ID_DEV_STR_18_REG 0x0400064 -#define DEV_ID_DEV_STR_19_REG 0x0400068 -#define DEV_ID_DEV_STR_20_REG 0x040006c -#define DEV_ID_DEV_STR_21_REG 0x0400070 -#define DEV_ID_DEV_STR_22_REG 0x0400074 -#define DEV_ID_DEV_STR_23_REG 0x0400078 -#define DEV_ID_DEV_STR_24_REG 0x040007c - -// Name: mdio (MDIO) -// Description: MDIO interface -// File: lib/verilog/core/io/mdio/xml/mdio.xml -#define MDIO_PHY_0_CONTROL_REG 0x0440000 -#define MDIO_PHY_0_STATUS_REG 0x0440004 -#define MDIO_PHY_0_PHY_ID_0_REG 0x0440008 -#define MDIO_PHY_0_PHY_ID_1_REG 0x044000c -#define MDIO_PHY_0_AUTONEGOTIATION_ADVERT_REG 0x0440010 -#define MDIO_PHY_0_AUTONEG_LINK_PARTNER_BASE_PAGE_ABILITY_REG 0x0440014 -#define MDIO_PHY_0_AUTONEG_EXPANSION_REG 0x0440018 -#define MDIO_PHY_0_AUTONEG_NEXT_PAGE_TX_REG 0x044001c -#define MDIO_PHY_0_AUTONEG_LINK_PARTNER_RCVD_NEXT_PAGE_REG 0x0440020 -#define MDIO_PHY_0_MASTER_SLAVE_CTRL_REG 0x0440024 -#define MDIO_PHY_0_MASTER_SLAVE_STATUS_REG 0x0440028 -#define MDIO_PHY_0_PSE_CTRL_REG 0x044002c -#define MDIO_PHY_0_PSE_STATUS_REG 0x0440030 -#define MDIO_PHY_0_MMD_ACCESS_CTRL_REG 0x0440034 -#define MDIO_PHY_0_MMD_ACCESS_STATUS_REG 0x0440038 -#define MDIO_PHY_0_EXTENDED_STATUS_REG 0x044003c -#define MDIO_PHY_1_CONTROL_REG 0x0440080 -#define MDIO_PHY_1_STATUS_REG 0x0440084 -#define MDIO_PHY_1_PHY_ID_0_REG 0x0440088 -#define MDIO_PHY_1_PHY_ID_1_REG 0x044008c -#define MDIO_PHY_1_AUTONEGOTIATION_ADVERT_REG 0x0440090 -#define MDIO_PHY_1_AUTONEG_LINK_PARTNER_BASE_PAGE_ABILITY_REG 0x0440094 -#define MDIO_PHY_1_AUTONEG_EXPANSION_REG 0x0440098 -#define MDIO_PHY_1_AUTONEG_NEXT_PAGE_TX_REG 0x044009c -#define MDIO_PHY_1_AUTONEG_LINK_PARTNER_RCVD_NEXT_PAGE_REG 0x04400a0 -#define MDIO_PHY_1_MASTER_SLAVE_CTRL_REG 0x04400a4 -#define MDIO_PHY_1_MASTER_SLAVE_STATUS_REG 0x04400a8 -#define MDIO_PHY_1_PSE_CTRL_REG 0x04400ac -#define MDIO_PHY_1_PSE_STATUS_REG 0x04400b0 -#define MDIO_PHY_1_MMD_ACCESS_CTRL_REG 0x04400b4 -#define MDIO_PHY_1_MMD_ACCESS_STATUS_REG 0x04400b8 -#define MDIO_PHY_1_EXTENDED_STATUS_REG 0x04400bc -#define MDIO_PHY_2_CONTROL_REG 0x0440100 -#define MDIO_PHY_2_STATUS_REG 0x0440104 -#define MDIO_PHY_2_PHY_ID_0_REG 0x0440108 -#define MDIO_PHY_2_PHY_ID_1_REG 0x044010c -#define MDIO_PHY_2_AUTONEGOTIATION_ADVERT_REG 0x0440110 -#define MDIO_PHY_2_AUTONEG_LINK_PARTNER_BASE_PAGE_ABILITY_REG 0x0440114 -#define MDIO_PHY_2_AUTONEG_EXPANSION_REG 0x0440118 -#define MDIO_PHY_2_AUTONEG_NEXT_PAGE_TX_REG 0x044011c -#define MDIO_PHY_2_AUTONEG_LINK_PARTNER_RCVD_NEXT_PAGE_REG 0x0440120 -#define MDIO_PHY_2_MASTER_SLAVE_CTRL_REG 0x0440124 -#define MDIO_PHY_2_MASTER_SLAVE_STATUS_REG 0x0440128 -#define MDIO_PHY_2_PSE_CTRL_REG 0x044012c -#define MDIO_PHY_2_PSE_STATUS_REG 0x0440130 -#define MDIO_PHY_2_MMD_ACCESS_CTRL_REG 0x0440134 -#define MDIO_PHY_2_MMD_ACCESS_STATUS_REG 0x0440138 -#define MDIO_PHY_2_EXTENDED_STATUS_REG 0x044013c -#define MDIO_PHY_3_CONTROL_REG 0x0440180 -#define MDIO_PHY_3_STATUS_REG 0x0440184 -#define MDIO_PHY_3_PHY_ID_0_REG 0x0440188 -#define MDIO_PHY_3_PHY_ID_1_REG 0x044018c -#define MDIO_PHY_3_AUTONEGOTIATION_ADVERT_REG 0x0440190 -#define MDIO_PHY_3_AUTONEG_LINK_PARTNER_BASE_PAGE_ABILITY_REG 0x0440194 -#define MDIO_PHY_3_AUTONEG_EXPANSION_REG 0x0440198 -#define MDIO_PHY_3_AUTONEG_NEXT_PAGE_TX_REG 0x044019c -#define MDIO_PHY_3_AUTONEG_LINK_PARTNER_RCVD_NEXT_PAGE_REG 0x04401a0 -#define MDIO_PHY_3_MASTER_SLAVE_CTRL_REG 0x04401a4 -#define MDIO_PHY_3_MASTER_SLAVE_STATUS_REG 0x04401a8 -#define MDIO_PHY_3_PSE_CTRL_REG 0x04401ac -#define MDIO_PHY_3_PSE_STATUS_REG 0x04401b0 -#define MDIO_PHY_3_MMD_ACCESS_CTRL_REG 0x04401b4 -#define MDIO_PHY_3_MMD_ACCESS_STATUS_REG 0x04401b8 -#define MDIO_PHY_3_EXTENDED_STATUS_REG 0x04401bc - -#define MDIO_PHY_GROUP_BASE_ADDR 0x0440000 -#define MDIO_PHY_GROUP_INST_OFFSET 0x0000080 - -// Name: dma (DMA) -// Description: DMA transfer module -// File: lib/verilog/core/dma/xml/dma.xml - -// Name: nf2_mac_grp (MAC_GRP_0) -// Description: Ethernet MAC group -// File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml -#define MAC_GRP_0_CONTROL_REG 0x0600000 -#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0600004 -#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_STORED_REG 0x0600008 -#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG 0x060000c -#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG 0x0600010 -#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_DEQUEUED_REG 0x0600014 -#define MAC_GRP_0_RX_QUEUE_NUM_WORDS_PUSHED_REG 0x0600018 -#define MAC_GRP_0_RX_QUEUE_NUM_BYTES_PUSHED_REG 0x060001c -#define MAC_GRP_0_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0600020 -#define MAC_GRP_0_TX_QUEUE_NUM_PKTS_ENQUEUED_REG 0x0600024 -#define MAC_GRP_0_TX_QUEUE_NUM_PKTS_SENT_REG 0x0600028 -#define MAC_GRP_0_TX_QUEUE_NUM_WORDS_PUSHED_REG 0x060002c -#define MAC_GRP_0_TX_QUEUE_NUM_BYTES_PUSHED_REG 0x0600030 - -// Name: nf2_mac_grp (MAC_GRP_1) -// Description: Ethernet MAC group -// File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml -#define MAC_GRP_1_CONTROL_REG 0x0640000 -#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0640004 -#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_STORED_REG 0x0640008 -#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG 0x064000c -#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG 0x0640010 -#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_DEQUEUED_REG 0x0640014 -#define MAC_GRP_1_RX_QUEUE_NUM_WORDS_PUSHED_REG 0x0640018 -#define MAC_GRP_1_RX_QUEUE_NUM_BYTES_PUSHED_REG 0x064001c -#define MAC_GRP_1_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0640020 -#define MAC_GRP_1_TX_QUEUE_NUM_PKTS_ENQUEUED_REG 0x0640024 -#define MAC_GRP_1_TX_QUEUE_NUM_PKTS_SENT_REG 0x0640028 -#define MAC_GRP_1_TX_QUEUE_NUM_WORDS_PUSHED_REG 0x064002c -#define MAC_GRP_1_TX_QUEUE_NUM_BYTES_PUSHED_REG 0x0640030 - -// Name: nf2_mac_grp (MAC_GRP_2) -// Description: Ethernet MAC group -// File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml -#define MAC_GRP_2_CONTROL_REG 0x0680000 -#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0680004 -#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_STORED_REG 0x0680008 -#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG 0x068000c -#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG 0x0680010 -#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_DEQUEUED_REG 0x0680014 -#define MAC_GRP_2_RX_QUEUE_NUM_WORDS_PUSHED_REG 0x0680018 -#define MAC_GRP_2_RX_QUEUE_NUM_BYTES_PUSHED_REG 0x068001c -#define MAC_GRP_2_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0680020 -#define MAC_GRP_2_TX_QUEUE_NUM_PKTS_ENQUEUED_REG 0x0680024 -#define MAC_GRP_2_TX_QUEUE_NUM_PKTS_SENT_REG 0x0680028 -#define MAC_GRP_2_TX_QUEUE_NUM_WORDS_PUSHED_REG 0x068002c -#define MAC_GRP_2_TX_QUEUE_NUM_BYTES_PUSHED_REG 0x0680030 - -// Name: nf2_mac_grp (MAC_GRP_3) -// Description: Ethernet MAC group -// File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml -#define MAC_GRP_3_CONTROL_REG 0x06c0000 -#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x06c0004 -#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_STORED_REG 0x06c0008 -#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG 0x06c000c -#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG 0x06c0010 -#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_DEQUEUED_REG 0x06c0014 -#define MAC_GRP_3_RX_QUEUE_NUM_WORDS_PUSHED_REG 0x06c0018 -#define MAC_GRP_3_RX_QUEUE_NUM_BYTES_PUSHED_REG 0x06c001c -#define MAC_GRP_3_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x06c0020 -#define MAC_GRP_3_TX_QUEUE_NUM_PKTS_ENQUEUED_REG 0x06c0024 -#define MAC_GRP_3_TX_QUEUE_NUM_PKTS_SENT_REG 0x06c0028 -#define MAC_GRP_3_TX_QUEUE_NUM_WORDS_PUSHED_REG 0x06c002c -#define MAC_GRP_3_TX_QUEUE_NUM_BYTES_PUSHED_REG 0x06c0030 - -// Name: cpu_dma_queue (CPU_QUEUE_0) -// Description: CPU DMA queue -// File: lib/verilog/core/io_queues/cpu_dma_queue/xml/cpu_dma_queue.xml - -// Name: cpu_dma_queue (CPU_QUEUE_1) -// Description: CPU DMA queue -// File: lib/verilog/core/io_queues/cpu_dma_queue/xml/cpu_dma_queue.xml - -// Name: cpu_dma_queue (CPU_QUEUE_2) -// Description: CPU DMA queue -// File: lib/verilog/core/io_queues/cpu_dma_queue/xml/cpu_dma_queue.xml - -// Name: cpu_dma_queue (CPU_QUEUE_3) -// Description: CPU DMA queue -// File: lib/verilog/core/io_queues/cpu_dma_queue/xml/cpu_dma_queue.xml - -// Name: SRAM (SRAM) -// Description: SRAM - -// Name: openflow_output_port_lookup (OPENFLOW_LOOKUP) -// Description: Output Port Lookup for OpenFlow hardware datapath -// File: projects/openflow_switch/include/output_port_lookup.xml -#define OPENFLOW_LOOKUP_WILDCARD_MISSES_REG 0x2000000 -#define OPENFLOW_LOOKUP_WILDCARD_HITS_REG 0x2000004 -#define OPENFLOW_LOOKUP_EXACT_MISSES_REG 0x2000008 -#define OPENFLOW_LOOKUP_EXACT_HITS_REG 0x200000c -#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_0_REG 0x2000010 -#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_1_REG 0x2000014 -#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_2_REG 0x2000018 -#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_3_REG 0x200001c -#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_4_REG 0x2000020 -#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_5_REG 0x2000024 -#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_6_REG 0x2000028 -#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_7_REG 0x200002c -#define OPENFLOW_LOOKUP_DUMY_SOFTWARE_0_REG 0x2000030 -#define OPENFLOW_LOOKUP_DUMY_SOFTWARE_1_REG 0x2000034 -#define OPENFLOW_LOOKUP_TIMER_REG 0x2000038 - -// Name: in_arb (IN_ARB) -// Description: Round-robin input arbiter -// File: lib/verilog/core/input_arbiter/rr_input_arbiter/xml/rr_input_arbiter.xml -#define IN_ARB_NUM_PKTS_SENT_REG 0x2000100 -#define IN_ARB_LAST_PKT_WORD_0_HI_REG 0x2000104 -#define IN_ARB_LAST_PKT_WORD_0_LO_REG 0x2000108 -#define IN_ARB_LAST_PKT_CTRL_0_REG 0x200010c -#define IN_ARB_LAST_PKT_WORD_1_HI_REG 0x2000110 -#define IN_ARB_LAST_PKT_WORD_1_LO_REG 0x2000114 -#define IN_ARB_LAST_PKT_CTRL_1_REG 0x2000118 -#define IN_ARB_STATE_REG 0x200011c - -// Name: vlan_remover (VLAN_REMOVER) -// Description: Remove vlan tag and ethtype if ethtype is vlan, and store them into module header -// File: projects/openflow_switch/include/vlan_remover.xml - -// Name: opl_processor (OPL_PROCESSOR) -// Description: opl_processor -// File: projects/openflow_switch/include/opl_processor.xml - -// Name: header_parser (HEADER_PARSER) -// Description: Chop ether/IP/UDP-TCP header into 11 tuples -// File: projects/openflow_switch/include/header_parser.xml - -// Name: match_arbiter (MATCH_ARBITER) -// Description: Arbitration between exact and wildcard lookups results -// File: projects/openflow_switch/include/match_arbiter.xml - -// Name: bram_output_queues (BRAM_OQ) -// Description: BRAM-based output queues -// File: lib/verilog/core/output_queues/bram_output_queues/xml/bram_output_queues.xml -#define BRAM_OQ_DISABLE_QUEUES_REG 0x2000300 -#define BRAM_OQ_QUEUE_0_NUM_PKT_BYTES_RECEIVED_REG 0x2000380 -#define BRAM_OQ_QUEUE_0_NUM_PKTS_RECEIVED_REG 0x2000384 -#define BRAM_OQ_QUEUE_0_NUM_PKTS_DROPPED_REG 0x2000388 -#define BRAM_OQ_QUEUE_0_NUM_WORDS_IN_QUEUE_REG 0x200038c -#define BRAM_OQ_QUEUE_1_NUM_PKT_BYTES_RECEIVED_REG 0x2000390 -#define BRAM_OQ_QUEUE_1_NUM_PKTS_RECEIVED_REG 0x2000394 -#define BRAM_OQ_QUEUE_1_NUM_PKTS_DROPPED_REG 0x2000398 -#define BRAM_OQ_QUEUE_1_NUM_WORDS_IN_QUEUE_REG 0x200039c -#define BRAM_OQ_QUEUE_2_NUM_PKT_BYTES_RECEIVED_REG 0x20003a0 -#define BRAM_OQ_QUEUE_2_NUM_PKTS_RECEIVED_REG 0x20003a4 -#define BRAM_OQ_QUEUE_2_NUM_PKTS_DROPPED_REG 0x20003a8 -#define BRAM_OQ_QUEUE_2_NUM_WORDS_IN_QUEUE_REG 0x20003ac -#define BRAM_OQ_QUEUE_3_NUM_PKT_BYTES_RECEIVED_REG 0x20003b0 -#define BRAM_OQ_QUEUE_3_NUM_PKTS_RECEIVED_REG 0x20003b4 -#define BRAM_OQ_QUEUE_3_NUM_PKTS_DROPPED_REG 0x20003b8 -#define BRAM_OQ_QUEUE_3_NUM_WORDS_IN_QUEUE_REG 0x20003bc -#define BRAM_OQ_QUEUE_4_NUM_PKT_BYTES_RECEIVED_REG 0x20003c0 -#define BRAM_OQ_QUEUE_4_NUM_PKTS_RECEIVED_REG 0x20003c4 -#define BRAM_OQ_QUEUE_4_NUM_PKTS_DROPPED_REG 0x20003c8 -#define BRAM_OQ_QUEUE_4_NUM_WORDS_IN_QUEUE_REG 0x20003cc -#define BRAM_OQ_QUEUE_5_NUM_PKT_BYTES_RECEIVED_REG 0x20003d0 -#define BRAM_OQ_QUEUE_5_NUM_PKTS_RECEIVED_REG 0x20003d4 -#define BRAM_OQ_QUEUE_5_NUM_PKTS_DROPPED_REG 0x20003d8 -#define BRAM_OQ_QUEUE_5_NUM_WORDS_IN_QUEUE_REG 0x20003dc -#define BRAM_OQ_QUEUE_6_NUM_PKT_BYTES_RECEIVED_REG 0x20003e0 -#define BRAM_OQ_QUEUE_6_NUM_PKTS_RECEIVED_REG 0x20003e4 -#define BRAM_OQ_QUEUE_6_NUM_PKTS_DROPPED_REG 0x20003e8 -#define BRAM_OQ_QUEUE_6_NUM_WORDS_IN_QUEUE_REG 0x20003ec -#define BRAM_OQ_QUEUE_7_NUM_PKT_BYTES_RECEIVED_REG 0x20003f0 -#define BRAM_OQ_QUEUE_7_NUM_PKTS_RECEIVED_REG 0x20003f4 -#define BRAM_OQ_QUEUE_7_NUM_PKTS_DROPPED_REG 0x20003f8 -#define BRAM_OQ_QUEUE_7_NUM_WORDS_IN_QUEUE_REG 0x20003fc - -#define BRAM_OQ_QUEUE_GROUP_BASE_ADDR 0x2000380 -#define BRAM_OQ_QUEUE_GROUP_INST_OFFSET 0x0000010 - -// Name: watchdog (WDT) -// Description: Watchdog timer -// File: projects/openflow_switch/include/watchdog.xml -#define WDT_ENABLE_FLG_REG 0x2000400 -#define WDT_COUNTER_REG 0x2000404 - -// Name: exact_match (EXACT_MATCH) -// Description: exact match lookup -// File: projects/openflow_switch/include/exact_match.xml - -// Name: wildcard_match (OPENFLOW_WILDCARD_LOOKUP) -// Description: wildcard match lookup -// File: projects/openflow_switch/include/wildcard_match.xml -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_0_REG 0x2001000 -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_1_REG 0x2001004 -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_2_REG 0x2001008 -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_3_REG 0x200100c -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_4_REG 0x2001010 -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_5_REG 0x2001014 -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_6_REG 0x2001018 -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_7_REG 0x200101c -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_8_REG 0x2001020 -#define OPENFLOW_WILDCARD_LOOKUP_ACTION_9_REG 0x2001024 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_0_REG 0x2001028 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_1_REG 0x200102c -#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_2_REG 0x2001030 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_3_REG 0x2001034 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_4_REG 0x2001038 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_5_REG 0x200103c -#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_6_REG 0x2001040 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_7_REG 0x2001044 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_0_REG 0x2001048 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_1_REG 0x200104c -#define OPENFLOW_WILDCARD_LOOKUP_CMP_2_REG 0x2001050 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_3_REG 0x2001054 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_4_REG 0x2001058 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_5_REG 0x200105c -#define OPENFLOW_WILDCARD_LOOKUP_CMP_6_REG 0x2001060 -#define OPENFLOW_WILDCARD_LOOKUP_CMP_7_REG 0x2001064 -#define OPENFLOW_WILDCARD_LOOKUP_READ_ADDR_REG 0x2001068 -#define OPENFLOW_WILDCARD_LOOKUP_WRITE_ADDR_REG 0x200106c -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG 0x2001070 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_1_REG 0x2001074 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_2_REG 0x2001078 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_3_REG 0x200107c -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_4_REG 0x2001080 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_5_REG 0x2001084 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_6_REG 0x2001088 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_7_REG 0x200108c -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_8_REG 0x2001090 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_9_REG 0x2001094 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_10_REG 0x2001098 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_11_REG 0x200109c -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_12_REG 0x20010a0 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_13_REG 0x20010a4 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_14_REG 0x20010a8 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_15_REG 0x20010ac -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_16_REG 0x20010b0 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_17_REG 0x20010b4 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_18_REG 0x20010b8 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_19_REG 0x20010bc -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_20_REG 0x20010c0 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_21_REG 0x20010c4 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_22_REG 0x20010c8 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_23_REG 0x20010cc -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_24_REG 0x20010d0 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_25_REG 0x20010d4 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_26_REG 0x20010d8 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_27_REG 0x20010dc -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_28_REG 0x20010e0 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_29_REG 0x20010e4 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_30_REG 0x20010e8 -#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_31_REG 0x20010ec -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG 0x20010f0 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_1_REG 0x20010f4 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_2_REG 0x20010f8 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_3_REG 0x20010fc -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_4_REG 0x2001100 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_5_REG 0x2001104 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_6_REG 0x2001108 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_7_REG 0x200110c -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_8_REG 0x2001110 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_9_REG 0x2001114 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_10_REG 0x2001118 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_11_REG 0x200111c -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_12_REG 0x2001120 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_13_REG 0x2001124 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_14_REG 0x2001128 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_15_REG 0x200112c -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_16_REG 0x2001130 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_17_REG 0x2001134 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_18_REG 0x2001138 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_19_REG 0x200113c -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_20_REG 0x2001140 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_21_REG 0x2001144 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_22_REG 0x2001148 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_23_REG 0x200114c -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_24_REG 0x2001150 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_25_REG 0x2001154 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_26_REG 0x2001158 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_27_REG 0x200115c -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_28_REG 0x2001160 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_29_REG 0x2001164 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_30_REG 0x2001168 -#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_31_REG 0x200116c -#define OPENFLOW_WILDCARD_LOOKUP_DUMMY_1_REG 0x2001170 -#define OPENFLOW_WILDCARD_LOOKUP_DUMMY_2_REG 0x2001174 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_0_REG 0x2001178 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_1_REG 0x200117c -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_2_REG 0x2001180 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_3_REG 0x2001184 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_4_REG 0x2001188 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_5_REG 0x200118c -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_6_REG 0x2001190 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_7_REG 0x2001194 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_8_REG 0x2001198 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_9_REG 0x200119c -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_10_REG 0x20011a0 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_11_REG 0x20011a4 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_12_REG 0x20011a8 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_13_REG 0x20011ac -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_14_REG 0x20011b0 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_15_REG 0x20011b4 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_16_REG 0x20011b8 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_17_REG 0x20011bc -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_18_REG 0x20011c0 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_19_REG 0x20011c4 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_20_REG 0x20011c8 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_21_REG 0x20011cc -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_22_REG 0x20011d0 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_23_REG 0x20011d4 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_24_REG 0x20011d8 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_25_REG 0x20011dc -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_26_REG 0x20011e0 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_27_REG 0x20011e4 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_28_REG 0x20011e8 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_29_REG 0x20011ec -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_30_REG 0x20011f0 -#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_31_REG 0x20011f4 - -// Name: DRAM (DRAM) -// Description: DRAM - -#endif diff --git a/openflow/hw-lib/skeleton/debug.h b/openflow/hw-lib/skeleton/debug.h deleted file mode 100644 index d6a8f8af..00000000 --- a/openflow/hw-lib/skeleton/debug.h +++ /dev/null @@ -1,106 +0,0 @@ - -#ifndef OF_HW_DEBUG_H -#define OF_HW_DEBUG_H 1 - -#include -#include - -#if !defined(HWTABLE_NO_DEBUG) -extern int of_hw_debug; -#define dbg_send(mod, lvl, fmt, args...) \ - if (of_hw_debug >= (lvl)) fprintf(stderr, fmt, ##args) -#endif - -#define DBG_LVL_NONE -1 /* All output off */ -#define DBG_LVL_ERROR 0 /* Default value */ -#define DBG_LVL_ALWAYS 0 /* For requested dump output */ -#define DBG_LVL_WARN 1 -#define DBG_LVL_VERBOSE 2 -#define DBG_LVL_VVERB 3 /* Include success indications */ - -/* Sorry for the lazy syntax here. */ -#define DBG_CHECK(lvl) (((lvl) >= 0) && (of_hw_debug >= (lvl))) -#define DBG_ERROR(fmt, args...) dbg_send(0, DBG_LVL_ERROR, fmt, ##args) -#define DBG_ALWAYS(fmt, args...) dbg_send(0, DBG_LVL_ALWAYS, fmt, ##args) -#define DBG_WARN(fmt, args...) dbg_send(0, DBG_LVL_WARN, fmt, ##args) -#define DBG_VERBOSE(fmt, args...) dbg_send(0, DBG_LVL_VERBOSE, fmt, ##args) -#define DBG_VVERB(fmt, args...) dbg_send(0, DBG_LVL_VVERB, fmt, ##args) -#define DBG_NONE(fmt, args...) -/* Same as DEBUG_ALWAYS */ -#define DEBUGK(fmt, args...) dbg_send(0, DBG_LVL_ALWAYS, fmt, ##args) - -#define REPORT_ERROR(str) \ - DBG_ERROR("ERROR: %s:%d. %s\n", __FUNCTION__, __LINE__, str) - -/* Default debugging location string */ -#define ANNOUNCE_LOCATION DBG_VVERB("%s: %d\n", __FUNCTION__, __LINE__) -#define DBG_INCR(cnt) (++(cnt)) - -/* Should assert return? Not presently */ -#define ASSERT(cond) \ - if (!(cond)) DBG_ERROR("ASSERTION %s IN %s FAILED LINE %d\n", \ - #cond, __FUNCTION__, __LINE__) - -/* DEBUG for HW flow lists */ -#define HW_FLOW_MAGIC 0xba5eba11 -#define HW_FLOW_MAKE_VALID(hf) (hf)->magic = HW_FLOW_MAGIC -#define HW_FLOW_IS_VALID(hf) \ - (((hf) != NULL) && ((hf)->magic == HW_FLOW_MAGIC)) - -/* - * Carry out an operation and check for error, optionally returning - * from the calling routine. To avoid compiler - * warnings in routines with void return, we give two macros. - * - * WARNING: This check uses rv != 0 (not just rv < 0). - */ - -#define TRY(op, str) do { \ - int rv; \ - if (((rv = (op)) < 0)) { \ - DBG_ERROR("ERROR %d: %s\n", rv, str); \ - return rv; \ - } else { \ - DBG_NONE("%s: success\n", str); \ - } \ - } while (0) - -#define TRY_NR(op, str) do { \ - int rv; \ - if (((rv = (op)) != 0)) { \ - DBG_ERROR("ERROR %d: %s\n", rv, str); \ - } else { \ - DBG_NONE("%s: success\n", str); \ - } \ - } while (0) - -#else /* No debugging */ - -#define DBG_CHECK(lvl) 0 -#define ANNOUNCE_LOCATION -#define ACT_STRING(action) "" -#define DBG_INCR(cnt) -#define DBG_ERROR(fmt, args...) -#define DBG_ALWAYS(fmt, args...) -#define DBG_WARN(fmt, args...) -#define DBG_VERBOSE(fmt, args...) -#define DBG_VVERB(fmt, args...) -#define DBG_NONE(fmt, args...) -#define DEBUGK(fmt, args...) -#define REPORT_ERROR(str) - -#define ASSERT(cond) - -#define HW_FLOW_MAKE_VALID(hf) -#define HW_FLOW_IS_VALID(hf) 1 - -#define TRY(op, str) do { \ - int rv; \ - if (((rv = (op)) != 0)) return rv; \ - } while (0) - -#define TRY_NR(op, str) (void)op - -#endif /* !defined(HWTABLE_NO_DEBUG) */ - -#endif /* OF_HW_DEBUG_H */ diff --git a/openflow/hw-lib/skeleton/hw_drv.c b/openflow/hw-lib/skeleton/hw_drv.c deleted file mode 100644 index 0ecd5909..00000000 --- a/openflow/hw-lib/skeleton/hw_drv.c +++ /dev/null @@ -1,309 +0,0 @@ -/* - * Skeleton hardware datapath, internal implemenation - * - */ -#include - -#include -#include - -#include "list.h" - -#include "os.h" -#include "debug.h" -#include "of_hw_platform.h" -#include "hw_drv.h" -#include "hw_flow.h" -#include "port.h" -#include "txrx.h" -#include "udatapath/switch-flow.h" - -/**************************************************************** - * - * Hardware resource management section - * - ****************************************************************/ - -static int global_init_done = 0; -int of_hw_drv_instances = 0; - -#if !defined(HWTABLE_NO_DEBUG) -int of_hw_debug = DBG_LVL_WARN; -#endif - -/* Internal initialization of HW datapath structures */ -static int -hw_drv_global_init(int init_hw) -{ - HW_DRV_MUTEX_INIT; - of_hw_ports_init(); - - if (init_hw) { /* Do hardware initialization */ - TRY(PLATFORM_INIT(), "PLATFORM INIT"); - TRY_NR(of_hw_fp_setup(), "global FP setup"); - } - - global_init_done = 1; - return 0; -} - -/* Skeleton capabilities structure */ -static of_hw_driver_caps_t of_hw_caps = { - .flags = , - .max_flows = , - .wc_supported = OFPFW_ALL, - .actions_supported = OFPAT_XXX, - .ofpc_flags = OFPC_XXX -}; - -/* Initialize the internal HW datapath structure */ -static int -hw_drv_int_init(of_hw_driver_int_t *hw_int, struct datapath *dp) -{ - static int dp_idx = 0; - - /* Fill in caps object */ - memcpy(&hw_int->hw_driver.caps, &of_hw_caps, sizeof(of_hw_caps)); - hw_int->dp = dp; - hw_int->dp_idx = dp_idx++; - - hw_int->n_flows = 0; - list_init(&hw_int->flows); - list_init(&hw_int->iter_flows); - hw_int->next_serial = 0; - - return 0; -} - -/**************************************************************** - * - * Driver functions - * - ****************************************************************/ - -/* - * of_hw_ioctl - * - * HW IOCTL function - */ - -static int -of_hw_ioctl(of_hw_driver_t *hw_drv, uint32_t op, void **io_param, - int *io_len UNUSED) -{ - int val; - of_hw_driver_int_t *hw_int; - int rv = 0; - - hw_int = (of_hw_driver_int_t *)hw_drv; - - switch (op) { - case OF_HW_IOCTL_TABLE_DEBUG_SET: - val = *(int *)(*io_param); - DBG_WARN("Changing table debug value to %d\n", val); - /* FIXME: Use HW driver for debug level? */ - hw_int->table_debug_level = val; - of_hw_debug = val; - break; - case OF_HW_IOCTL_PORT_DEBUG_SET: - val = *(int *)(*io_param); - DBG_WARN("Changing port debug value to %d\n", val); - hw_int->port_debug_level = val; - break; - case OF_HW_IOCTL_BYTE_PKT_CNTR_SET: - val = *(int *)(*io_param); - if ((val != OF_HW_CNTR_PACKETS) && - (val != OF_HW_CNTR_BYTES)) { - DBG_ERROR("Bad byte/pkt counters select value %d\n", val); - } else { - hw_int->stat_sel = val; - } - break; - default: - rv = -1; /* Change to UNSUPPORTED */ - break; - } - - return 0; -} - -static void -of_hw_table_destroy(struct sw_table *table) -{ - of_hw_driver_int_t *hw_int; - - hw_int = (of_hw_driver_int_t *)table; - if (hw_int != NULL && hw_int->dp != NULL) { - DBG_WARN("Table destroy called for dp idx %d\n", - hw_int->dp_idx); - } else { - DBG_ERROR("Table destroy called on NULL dp\n"); - } - - delete_of_hw_driver(&hw_int->hw_driver); -} - -static int -of_hw_table_iterate(struct sw_table *table, - const struct sw_flow_key *key, uint16_t out_port, - struct sw_table_position *position, - int (*callback)(struct sw_flow *flow, void *private), - void *private) -{ - - of_hw_driver_int_t *hw_int; - struct sw_flow *flow; - unsigned long start; - - hw_int = (of_hw_driver_int_t *)table; - if (hw_int != NULL) { - start = ~position->private[0]; - LIST_FOR_EACH (flow, struct sw_flow, iter_node, &hw_int->iter_flows) { - if (flow->serial <= start - && flow_matches_2wild(key, &flow->key) - && flow_has_out_port(flow, out_port)) { - int error; - - /* Update stats as that's what's generally used */ - TRY_NR(of_hw_sw_flow_stat_update(flow, NULL, false), - "sw flow stat update"); - error = callback(flow, private); - if (error) { - position->private[0] = ~(flow->serial - 1); - return error; - } - } - } - } else { - DBG_ERROR("Table iterate called on NULL driver or SW flow table\n"); - return -1; - } - - return 0; -} - -static const char *hw_drv_name = "HW FlowDriver"; - -static void -of_hw_sw_table_stats(struct sw_table *table, struct sw_table_stats *stats) -{ - of_hw_driver_int_t *hw_int; - unsigned long matched = 0; - unsigned long missed = 0; - - hw_int = (of_hw_driver_int_t *)table; - stats->name = hw_drv_name; - stats->wildcards = OFPFW_ALL; - stats->n_flows = hw_int->n_flows; - stats->max_flows = of_hw_caps.max_flows; - /* FIXME: Collect stats */ - TRY_NR(of_hw_table_stats_update(hw_int, &matched, &missed), - "of_hw_table_stats_update"); - stats->n_lookup = missed + matched; - stats->n_matched = matched; -} - -static int -of_hw_table_stats_get(of_hw_driver_t *hw_drv, struct ofp_table_stats *stats) -{ - DBG_WARN("TABLE STATS FIXME\n"); - return 0; -} - -/* - * Create and initialize a new hardware datapath object - */ - -of_hw_driver_t * -new_of_hw_driver(struct datapath *dp) -{ - struct sw_table *sw_tab; - of_hw_driver_t *hw_drv; - of_hw_driver_int_t *hw_int; - - if (!global_init_done) { - if (hw_drv_global_init(1) < 0) { - REPORT_ERROR("HW driver global init failed\n"); - return NULL; - } - } - hw_int = ALLOC(sizeof(*hw_int)); - if (hw_int == NULL) { - REPORT_ERROR("Could not allocate HW driver\n"); - return NULL; - } - memset(hw_int, 0, sizeof(*hw_int)); - - if (hw_drv_int_init(hw_int, dp) < 0) { - FREE(hw_int); - return NULL; - } - - - /* These all point to the same place */ - hw_drv = &hw_int->hw_driver; - sw_tab = &hw_drv->sw_table; - - sw_tab->n_lookup = 0; - sw_tab->n_matched = 0; - - /* Fill out the function pointers */ - sw_tab->lookup = of_hw_flow_lookup; - sw_tab->insert = of_hw_flow_install; - sw_tab->modify = of_hw_flow_modify; - sw_tab->delete = of_hw_flow_delete; - sw_tab->timeout = of_hw_flow_timeout; - - sw_tab->destroy = of_hw_table_destroy; - sw_tab->iterate = of_hw_table_iterate; - sw_tab->stats = of_hw_sw_table_stats; - - hw_drv->table_stats_get =of_hw_table_stats_get; - hw_drv->port_stats_get = of_hw_port_stats_get; - hw_drv->flow_stats_get = NULL; - hw_drv->aggregate_stats_get = NULL; - - hw_drv->port_add = of_hw_port_add; - hw_drv->port_remove = of_hw_port_remove; - hw_drv->port_link_get = of_hw_port_link_get; - hw_drv->port_enable_set = of_hw_port_enable_set; - hw_drv->port_enable_get = of_hw_port_enable_get; - hw_drv->port_queue_config = of_hw_port_queue_config; - hw_drv->port_queue_remove = of_hw_port_queue_remove; - hw_drv->port_change_register = of_hw_port_change_register; - - hw_drv->packet_send = of_hw_packet_send; - hw_drv->packet_receive_register = of_hw_packet_receive_register; - - hw_drv->ioctl = of_hw_ioctl; - - ++of_hw_drv_instances; - - return hw_drv; -} - -/* - * Deallocate a hardware datapath object - * If clear_hw is set, the HW structures related to the - * datapath are also cleared. - * - * In general, clear_hw should be set for now. - */ -void -delete_of_hw_driver(of_hw_driver_t *hw_drv) -{ - int idx; - of_hw_driver_int_t *hw_int; - - hw_int = (of_hw_driver_int_t *)hw_drv; - - /* Clear the port table of ownership for this dp */ - FOREACH_DP_PORT(idx, hw_drv) { - of_hw_ports[idx].owner = NULL; - } - - of_hw_flow_remove_all(hw_int); - - FREE(hw_drv); - --of_hw_drv_instances; -} diff --git a/openflow/hw-lib/skeleton/hw_drv.h b/openflow/hw-lib/skeleton/hw_drv.h deleted file mode 100644 index 7e6ecb0e..00000000 --- a/openflow/hw-lib/skeleton/hw_drv.h +++ /dev/null @@ -1,97 +0,0 @@ -#ifndef OF_HW_DRV_H -#define OF_HW_DRV_H 1 - -#include -#include "of_hw_platform.h" -#include "list.h" - -/**************************************************************** - * - * High Level Design Notes - * - * Hardware tables are managed field_control_t and entry_control_t - * structures in hw_flow.h; these roughly mirror the HW structure - * and are preallocated. - * - * The glue between these and SW flows are provided by the HW flow - * objects (also in hw_flow.h) which are dynamically allocated and - * logically extend the SW flow object. - * - * A linear table of HW flow objects is maintained, mostly drawn - * from the existing table-linear.c implementation in udatapath. - * - */ - -/**************************************************************** - * Hardware independent port mapping macros - ****************************************************************/ - -/* Map ports using software data structures and DP check; independent of HW */ -#define OF_PORT_IN_DP(_hwdrv, _i) (((_i) < OF_HW_MAX_PORT) && \ - (of_hw_ports[_i].owner == (of_hw_driver_t *)(_hwdrv))) - -#define OF_PORT_TO_HW_PORT(_hwdrv, _i) \ - (OF_PORT_IN_DP(_hwdrv, _i) ? of_hw_ports[_i].port : -1) - -/* TBD: Define flow tracking objects */ - -/**************************************************************** - * - * Hardware datapath internal control structure - * Extends generic hardware datapath structure - * (which currently extends software table structure) - * - ****************************************************************/ - -/* Counts the number of instances */ -extern int of_hw_drv_instances; - -typedef struct of_hw_driver_int { - of_hw_driver_t hw_driver; - struct datapath *dp; /* Owning datapath */ - - /* Maintain a linked list of flows for tracking */ - struct list flows; /* The main list */ - struct list iter_flows; /* For iteration operation */ - unsigned long int next_serial; - - /* Callback function for received packets. */ - of_packet_in_f rx_handler; - void *rx_cookie; - - /* Callback function for port change notification */ - of_port_change_f port_change; - void *port_change_cookie; - - /* Lock object? */ - - // struct list sw_flows; - // struct list iter_sw_flows; - // struct sw_flow *iter_state; /* Place tracker for interrupted iterations */ - - /* Stats */ - uint32_t n_flows; /* Current number of flows in table */ - uint32_t n_inserts; /* Total inserts */ - uint32_t rx_pkt_alloc_failures; - uint32_t insert_errors; - - /* Configuration */ - /* Port bitmap of ports in DP by device */ - FIXME port_bitmap; - FIXME flood_bitmap; - int stat_sel; /* Packets or bytes */ - int dp_idx; /* In HW dp, but not SW dp */ - - int table_debug_level; - int port_debug_level; -} of_hw_driver_int_t; - -/* HW_DRV_MUTEX object ? */ - -#define HW_DRV_MUTEX_INIT /* TBD */ -#define HW_DRV_LOCK /* TBD */ -#define HW_DRV_UNLOCK /* TBD */ - -#define HW_INT(hw_drv) ((of_hw_driver_int_t *)hw_drv) - -#endif /* OF_HW_DRV_H */ diff --git a/openflow/hw-lib/skeleton/hw_flow.c b/openflow/hw-lib/skeleton/hw_flow.c deleted file mode 100644 index 2f9d6eca..00000000 --- a/openflow/hw-lib/skeleton/hw_flow.c +++ /dev/null @@ -1,708 +0,0 @@ -/* - * Functions related to hardware flow processing; this is the glue - * and administration between upper level flow operations and lower - * level field processor operations. - */ - -#include -#include -#include - -#include "os.h" -#include "debug.h" -#include "hw_drv.h" -#include "port.h" -#include "hw_flow.h" -#include "udatapath/switch-flow.h" -#include "udatapath/datapath.h" -#include "lib/packets.h" - -static field_control_t field_control; - -/**************************************************************** - * - * SW/HW flow correlation book keeping routines - * - ****************************************************************/ - -/* Allocate and initialize a HW flow control structure. */ -static hw_flow_t * -hw_flow_create(struct sw_flow *flow) -{ - hw_flow_t *hw_flow; - - if ((hw_flow = ALLOC(sizeof(*hw_flow))) != NULL) { - memset(hw_flow, 0, sizeof(*hw_flow)); - HW_FLOW_MAKE_VALID(hw_flow); - hw_flow->flow = flow; - flow->private = (void *)hw_flow; - } - - return hw_flow; -} - -/* Remove an FP entry from a device */ -static int -HW_entry_remove(entry_control_t *entry) -{ - FIXME; - - return 0; -} - -/**************************************************************** - * - * Flow stats operations - * - ****************************************************************/ - -/* - * Read and convert the stats for an FP entry; maintains state - * of last counter value read and accumulates differences. - * - * Assumes mutex held. - */ -static int -entry_stat_update(entry_control_t *ent, int *used) -{ - unsigned long int cur_counter; - - FIXME_get_current_stats(cur_counter); - - ent->total_counter += cur_counter - ent->last_counter; - ent->last_counter = cur_counter; - - if (used != NULL) { - *used |= (ent->used_check != cur_counter); - ent->used_check = cur_counter; - } - - return 0; -} - -/* - * Get the stats for an OF (SW) flow object from HW tables - * NOTE: This will clear any existing value from the flow - * counters; if SW table counters need to be added in, that - * should be done after this calculation. - * - * If used is non-NULL, it will be filled with a boolean - * indication of whether the flow's counters have changed - * from their current state. - * - * Assumes mutex held. - * - * If force_sync is true, will sync SW counters with HW first - */ -int -of_hw_sw_flow_stat_update(struct sw_flow *flow, int *used, int force_sync) -{ - entry_control_t *ent; - hw_flow_t *hw_flow; - int idx; - - if (used != NULL) { - *used = false; - } - hw_flow = (hw_flow_t *)(flow->private); - if (!HW_FLOW_IS_VALID(hw_flow)) { - DBG_ERROR("BAD HW FLOW OBJECT %p for flow %p\n", hw_flow, flow); - return -1; - } - ASSERT(hw_flow->entry_count <= HW_FLOWS_PER_FLOW_MAX); - - if (force_sync) { - FIXME_sync_hw_stats(); - } - - /* FIXME: Will this accumulate and clear HW counters? */ - hw_flow->hw_byte_count = hw_flow->hw_packet_count = 0; - for (idx = 0; idx < hw_flow->entry_count; idx++) { - ent = hw_flow->entry_list[idx]; - - if (entry_stat_update(ent, used) < 0) { - DBG_WARN("Warning: could not get stats for flow\n"); - continue; - } - FIXME_update proper hw_flow counters; - } - flow->packet_count = hw_flow->hw_packet_count; - flow->byte_count = hw_flow->hw_byte_count; - - return 0; -} - -/* Read all the stats from the chip and update counters in flow tab */ -/* Index 0 holds default rule that indicates a missed count */ -/* ASSUMES LOCK HELD */ -int -of_hw_table_stats_update(of_hw_driver_int_t *hw_drv, unsigned long *matched, - unsigned long *missed) -{ - struct sw_flow *flow, *n; - of_hw_driver_int_t *hw_int; - - hw_int = (of_hw_driver_int_t *)hw_drv; - *matched = 0; - *missed = 0; - - if (STATS_BYTES(hw_int->stat_sel)) { /* Lookup count not supported */ - return -1; - } - - LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &hw_int->flows) { - if (flow->private != NULL) { - TRY_NR(of_hw_sw_flow_stat_update(flow, NULL, false), - "update flow stat"); - *matched += flow->packet_count; - } - } - - /* - * FIXME: To get missed stats, query entry 0 of HW table. - * This isn't really correct if there are entries in the SW datapath - * - * FIXME: If there are multiple data paths, should have one - * default entry qualifying on ports in that datapath with - * another entry dropping any packets on other ports. - */ - { - field_control_t *fc; - entry_control_t *ent; - - fc = &field_control; - ent = &fc->entry_list[0]; - ASSERT(ent->in_use); - TRY_NR(entry_stat_update(ent, NULL), "tab: entry_stat_update"); - *missed += ent->total_counter; - } - - return 0; -} - -/* - * Remove the FP entry or entries associated to a SW flow from the HW; - * - */ -static int -hw_flow_remove(struct sw_flow *flow) -{ - field_control_t *fc; - entry_control_t *ent; - hw_flow_t *hw_flow; - int idx; - -#if 0 /* Do not remove entries (debugging) */ - return 0; -#endif - - if (flow == NULL) { - return 0; - } - - hw_flow = (hw_flow_t *)(flow->private); - DBG_VERBOSE("Removing hw flow %p, flow %p\n", hw_flow, flow); - if (!HW_FLOW_IS_VALID(hw_flow)) { - return 0; - } - ASSERT(hw_flow->entry_count <= HW_FLOWS_PER_FLOW_MAX); - - TRY_NR(of_hw_sw_flow_stat_update(flow, NULL, true), - "rmv flow stat update"); - for (idx = 0; idx < hw_flow->entry_count; idx++) { - ent = hw_flow->entry_list[idx]; - ASSERT(ent != NULL); - - TRY_NR(HW_entry_remove(ent), "HW_entry_remove"); - hw_flow->entry_list[idx] = NULL; - } - FREE(hw_flow); - flow->private = NULL; - - return 0; -} - - -/**************************************************************** - * - * Important support routines related to FP setup, actions, flows - * - ****************************************************************/ - -/* ASSERT: of_port belongs to datapath */ -static void -add_dport_to_extra(of_hw_driver_int_t *hw_int, int of_port, - hw_flow_extra_t *extra) -{ - ASSERT(OF_PORT_IN_DP(hw_int, of_port)); - - extra->dest_port = MAP_OF_PORT_TO_HW_PORT(hw_int, of_port); - FIXME_update extra->dest_count if appropriate; -} - -/* Set up flood/all bitmaps - * NOTE: Assumes source port is not wildcarded. - */ -static void -mcast_bitmaps_set(of_hw_driver_int_t *hw_int, hw_flow_extra_t *extra, - int dest_port) -{ - FIXME; -} - -/* - * Validate actions for a flow relative to HW capabilities; - * - * Bool: true means supported, false not supported - * - * Accumulate additional info about the flow in extra. Specifically, - * this determines the output ports on each physical device related - * to the flow. - * - * FIXME: No-flood ports are currently not specified - */ - -static int -actions_supported_check(of_hw_driver_int_t *hw_int, - const struct sw_flow_key *key, - const struct ofp_action_header *actions, - size_t actions_len, - hw_flow_extra_t *extra) -{ - uint8_t *p; - int src_port; /* Port in host order */ - int dest_port; /* Port in host order */ - int action; - int src_is_wc = false; /* Is source wildcarded? */ - - ANNOUNCE_LOCATION; - ASSERT(extra != NULL); - - FIXME("probably needs work for your platform"); - - p = (uint8_t *)actions; - src_port = ntohs(key->flow.in_port); - - src_is_wc = key->wildcards & OFPFW_IN_PORT; - if (!src_is_wc) { - if (OF_PORT_IN_DP(hw_int, src_port)) { - extra->source_port = MAP_TO_HW_PORT(hw_int, src_port); - } else { - DBG_WARN("Source port %d not in DP %d\n", src_port, - hw_int->dp_idx); - return false; - } - } else { - extra->source_port = -1; - if (of_hw_drv_instances > 1) { - DBG_WARN("Source port WC not supported w/ multi-DP\n"); - return false; /* Not currently supported w/ multiple datapaths */ - } - /* NOTE/FIXME: Source wildcard with multiple output ports requires - * using a per-port hardware flow rule to allow filtering of - * the source port. (Currently not supported and checked below.) - */ - } - - while (actions_len > 0) { - struct ofp_action_header *ah = (struct ofp_action_header *)p; - struct ofp_action_output *oa = (struct ofp_action_output *)p; - size_t len = ntohs(ah->len); - - action = ntohs(ah->type); - DBG_VVERB("action chk %d\n", action); - /* Currently supported: output port(s) action */ - if ((action < 0) || (action > ACTION_LAST)) { - DBG_WARN("Unknown action id %d\n", action); - return false; - } - - if (action_map[action] == ACTION_NOT_SUPPORTED) { - DBG_WARN("Action %d not supported\n", action); - return false; - } - - /* Support front panel ports plus IN_PORT, ALL, FLOOD. */ - if ((action == OFPAT_OUTPUT) || (action == OFPAT_ENQUEUE)) { - /* FIXME: For now, using the fact that enqueue and output - * actions are the same at the start of the structure - */ - dest_port = ntohs(oa->port); - if (dest_port == OFPP_TABLE) { /* Unsupported */ - DBG_WARN("Warning: TABLE output action seen\n"); - return false; - } else if (OF_PORT_IN_DP(hw_int, dest_port)) { - add_dport_to_extra(hw_int, dest_port, extra); - } else if ((dest_port == OFPP_FLOOD) || (dest_port == OFPP_ALL)) { - mcast_bitmaps_set(hw_int, extra, dest_port); - } else if (dest_port == OFPP_IN_PORT) { - if (src_is_wc) { - DBG_WARN("Warning: IN_PORT action on source wildcard\n"); - return false; - } - add_dport_to_extra(hw_int, src_port, extra); - } else if (dest_port == OFPP_CONTROLLER) { - /* Controller/local are implemented with a "copy to CPU" - * action and a special reason code; Don't count as output port - */ - extra->local_reason |= CPU_REASON_TO_CONTROLLER; - } else if (dest_port == OFPP_LOCAL) { - extra->local_reason |= CPU_REASON_TO_LOCAL; - } else { /* NORMAL */ - // DBG_WARN("Output action to port 0x%x not supported\n", - // dest_port); - // return false; /* FIXME: Ignore bad ports for now */ - } - if (action == OFPAT_ENQUEUE) { - uint32 qid; - struct ofp_action_enqueue *ea; - ea = (struct ofp_action_enqueue *)p; - qid = ntohl(ea->queue_id); - if ((extra->cosq = of_hw_qid_find(dest_port, qid)) < 0) { - DBG_WARN("Warning: qid %d, port %d, map to cos failed\n", - qid, dest_port); - } - } - } - p += len; - actions_len -= len; - } - - if (src_is_wc && (extra->dest_count > 1)) { - DBG_WARN("Warning: multi dest w/ src wildcard\n"); - return false; - } - - DBG_VERBOSE("Actions supported\n"); - return true; -} - -/**************************************************************** - * - * FP Table management and manipulation routines - * - ****************************************************************/ - -/* - * Functions related to hardware flow table manipulation and maintenance - */ - -/* Set up field control structure; should be idempotent */ -static void -field_control_init(void) -{ - field_control_t *fc; - int idx; - - fc = &field_control; - fc->entry_count = 0; - for (idx = 0; idx < FIELD_ENTRY_MAX; idx++) { - fc->entry_list[idx].in_use = 0; - fc->entry_list[idx].hw_flow = NULL; - fc->entry_list[idx].index = idx; - fc->entry_list[idx].last_counter = 0; - fc->entry_list[idx].counter_last_check = 0; - fc->entry_list[idx].total_counter = 0; - } -} - -/* Alloc HW entry control structure, add qualification, actions and install */ -static int -hw_entry_install(of_hw_driver_int_t *hw_int, - struct sw_flow *flow, hw_flow_t *hw_flow, - hw_flow_extra_t *extra) -{ - - /* Install HW entry */ - FIXME; -} - -/* - * hw_flow_install - * - * Install HW table entries corresponding to the given SW flow - */ -static int -hw_flow_install(of_hw_driver_int_t *hw_int, struct sw_flow *flow, - hw_flow_extra_t *extra) -{ - hw_flow_t *hw_flow; - - /* Allocate the HW flow object */ - if ((hw_flow = hw_flow_create(flow)) == NULL) { - DBG_ERROR("failed to create hw flow struct\n"); - return -1; - } - - DBG_VERBOSE("hw flow install: sw %p. hw %p\n", flow, hw_flow); - TRY(hw_entry_install(hw_int, 0, flow, hw_flow, extra), - "local entry"); - - return 0; -} - -/**************************************************************** - * - * The driver APIs - * - ****************************************************************/ - -/* - * Install a flow. - * - * First, check that the flow is supported; simultaneously, build - * up the "extra" information needed by the hardware for its installation. - * This includes bitmaps of the ports to which the packet will be - * forwarded (on local and remote devices if appropriate). - * - * Then look to see if the flow should overwrite an existing entry. - * If so, just remove that entry. - * - * Then call hw_flow_install which does all the actual HW changes - * based on the flow and on extra. - */ - -/* NOTE: Returns 1 if flow installed, not normal error code */ -int -of_hw_flow_install(struct sw_table *sw_tab, struct sw_flow *flow) -{ - hw_flow_extra_t extra; - of_hw_driver_int_t *hw_int; - int hw_rc = 0; - int sw_insert_done = 0; - struct sw_flow *f; - - hw_int = (of_hw_driver_int_t *)sw_tab; - - DBG_VERBOSE("flow install %p\n", flow); - memset(&extra, 0, sizeof(extra)); - extra.cosq = -1; - - if (!actions_supported_check(hw_int, &flow->key, flow->sf_acts->actions, - flow->sf_acts->actions_len, &extra)) { - /* Unsupported actions */ - DBG_VERBOSE("HW install failed: Unsupported actions\n"); - return 0; - } - - /* LOCK; */ - /* Go through list looking for matching flows */ - LIST_FOR_EACH (f, struct sw_flow, node, &hw_int->flows) { - if (f->priority == flow->priority - && f->key.wildcards == flow->key.wildcards - && flow_matches_2wild(&f->key, &flow->key)) { - /* Just remove the HW flow; install other below */ - TRY_NR(hw_flow_remove(f), "hw_flow_remove for replace"); - flow->serial = f->serial; - list_replace(&flow->node, &f->node); - list_replace(&flow->iter_node, &f->iter_node); - sw_insert_done = 1; - flow_free(f); - break; - } - if (f->priority < flow->priority) { - break; - } - } - - /* ASSERT: sw_insert_done OR f points to insertion point for flow */ - - hw_rc = hw_flow_install(hw_int, flow, &extra); - - if (hw_rc < 0) { - hw_int->insert_errors++; - if (sw_insert_done) { /* Remove from SW list */ - list_remove(&flow->node); - list_remove(&flow->iter_node); - flow_free(flow); - hw_int->n_flows--; - } - } else { - hw_int->n_flows++; - hw_int->n_inserts++; - if (!sw_insert_done) { - flow->serial = hw_int->next_serial++; - list_insert(&f->node, &flow->node); - list_push_front(&hw_int->iter_flows, &flow->iter_node); - } - } - /* UNLOCK */ - - if (hw_rc < 0) { - DBG_WARN("Could not install flow in HW\n"); - if (sw_insert_done) { /* Remove from SW list */ - DBG_WARN("Removed matching flow but could not replace in HW\n"); - } - return 0; - } - - return 1; -} - -/* FIXME: Change API to return list of deleted flows? */ -/* Would make this easier */ -/* Remove a flow or flows from the HW and SW tracking tables */ -int -of_hw_flow_delete(struct datapath *dp, struct sw_table *sw_tab, - const struct sw_flow_key *key, uint16_t out_port, - uint16_t priority, int strict) -{ - of_hw_driver_int_t *hw_int = (of_hw_driver_int_t *)sw_tab; - struct sw_flow *flow, *n; - int count = 0; - struct list deleted; - - DBG_VERBOSE("delete: dp %p, idx %d, key %p, out 0x%x, prio %d, strict %d\n", - dp, hw_int->dp_idx, key, out_port, priority, strict); - - list_init(&deleted); - - /* LOCK; */ - LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &hw_int->flows) { - if (flow_matches_desc(&flow->key, key, strict) - && flow_has_out_port(flow, out_port) - && (!strict || (flow->priority == priority))) { - TRY_NR(hw_flow_remove(flow), "hw flow remove"); - list_remove(&flow->node); - list_remove(&flow->iter_node); - list_push_back(&deleted, &flow->node); - count++; - } - } - /* UNLOCK; */ - - /* Notify DP of deleted flows */ - LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &deleted) { - dp_send_flow_end(dp, flow, flow->reason); - list_remove(&flow->node); - flow_free(flow); - } - - return count; -} - - -/* - * Modify an existing flow - * - * We chicken out and just de-install/re-install in HW - */ -int -of_hw_flow_modify(struct sw_table *sw_tab, const struct sw_flow_key *key, - uint16_t priority, int strict, - const struct ofp_action_header *actions, size_t actions_len) -{ - of_hw_driver_int_t *hw_int = (of_hw_driver_int_t *)sw_tab; - struct sw_flow *flow; - int count = 0; - hw_flow_extra_t extra; - - memset(&extra, 0, sizeof(extra)); - extra.cosq = -1; -#if defined(PLATFORM_HAS_REMOTES) - extra.new_vid = -1; - extra.new_pcp = -1; -#endif - - if (!actions_supported_check(hw_int, &flow->key, actions, - actions_len, &extra)) { - /* Unsupported actions */ - DBG_VERBOSE("Mod actions-supported failed: Unsupported actions\n"); - return 0; - } - - /* LOCK; */ - LIST_FOR_EACH (flow, struct sw_flow, node, &hw_int->flows) { - if (flow_matches_desc(&flow->key, key, strict) - && (!strict || (flow->priority == priority))) { - /* Change the flow, de-install from HW and re-install */ - TRY_NR(hw_flow_remove(flow), "hw_flow_remove modify"); - flow_replace_acts(flow, actions, actions_len); - TRY_NR(hw_flow_install(hw_int, flow, &extra), - "hw_flow_install modify"); - /* FIXME: Clear stats on flow if updated? */ - count++; - } - } - /* UNLOCK; */ - - return count; -} - -/* - * Update stats - * Call sw tracking table timeout - * Iterate the deleted object list and call HW flow remove - */ -void -of_hw_flow_timeout(struct sw_table *sw_tab, struct list *deleted) -{ - of_hw_driver_int_t *hw_int = (of_hw_driver_int_t *)sw_tab; - struct sw_flow *flow, *n; - int used; - uint64_t now = time_msec(); - - /* LOCK; */ - /* FIXME */ - LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &hw_int->flows) { - if (of_hw_sw_flow_stat_update(flow, &used, false) == 0) { - if (used) { - flow->used = now; - } else { - if (flow_timeout(flow)) { - DBG_VERBOSE("Flow %p expired\n", flow); - list_remove(&flow->node); - list_remove(&flow->iter_node); - list_push_back(deleted, &flow->node); - ASSERT(flow->private != NULL); - TRY_NR(hw_flow_remove(flow), "hw flow remove, timeout"); - hw_int->n_flows--; - } - } - } - } - - /* UNLOCK; */ -} - -struct sw_flow * -of_hw_flow_lookup(struct sw_table *sw_tab, const struct sw_flow_key *key) -{ - of_hw_driver_int_t *hw_int = (of_hw_driver_int_t *)sw_tab; - struct sw_flow *flow; - - LIST_FOR_EACH (flow, struct sw_flow, node, &hw_int->flows) { - if (flow_matches_1wild(key, &flow->key)) - return flow; - } - return NULL; -} - -int -of_hw_flow_stats_get(of_hw_driver_t *hw_drv, struct ofp_match match, - struct ofp_flow_stats **stats, int *count) -{ - DBG_WARN("FIXME FLOW STATS GET\n"); - return 0; -} - -int -of_hw_aggregate_stats_get(struct ofp_match match, - struct ofp_aggregate_stats_reply *stats) -{ - DBG_WARN("FIXME AGGREGATE STATS GET\n"); - return 0; -} - -void -of_hw_flow_remove_all(of_hw_driver_int_t *hw_int) -{ - struct sw_flow *flow, *n; - - /* FIXME: Other de-init? Keep count of DPs? */ - LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &hw_int->flows) { - TRY_NR(hw_flow_remove(flow), "hw_flow_remove all"); - list_remove(&flow->node); - list_remove(&flow->iter_node); - } -} diff --git a/openflow/hw-lib/skeleton/hw_flow.h b/openflow/hw-lib/skeleton/hw_flow.h deleted file mode 100644 index 7c801c60..00000000 --- a/openflow/hw-lib/skeleton/hw_flow.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef SAMPLE_PLATFORM_HW_FLOW_H -#define SAMPLE_PLATFORM_HW_FLOW_H 1 - -/* - * Hardware Flow operations: The glue between software flows and - * actual hardware table entries. - */ - -#include -#include - -#include "of_hw_platform.h" - -/* DEBUG for HW flow lists */ -#define HW_FLOW_MAGIC 0xba5eba11 -#define HW_FLOW_MAKE_VALID(hf) (hf)->magic = HW_FLOW_MAGIC -#define HW_FLOW_IS_VALID(hf) \ - (((hf) != NULL) && ((hf)->magic == HW_FLOW_MAGIC)) - -/* Some flows require multiple HW entries */ -#define HW_FLOWS_PER_FLOW_MAX (2) - -/* The glue between SW flows and HW entries */ -typedef struct hw_flow { - struct sw_flow *flow; /* Corresponding SW flow */ - of_hw_driver_t *hw_drv; /* DP for this flow; MAY BE NULL for internal */ - int entry_count; /* SW flow may require multiple HW table entries */ - entry_control_t *entry_list[HW_FLOWS_PER_FLOW_MAX]; - uint32 hw_packet_count; - uint32 hw_byte_count; - uint32 magic; /* DEBUG */ -} hw_flow_t; - -/* Extra info needed by hardware about flow entry; - * determined during supported check; all in host order - * - * For smac, dmac, vid and priority, if these are changed at ingress - * and a remote rule is necessary, the remote rule must have the - * rewrite values to match. This is indicated if value is not -1. - */ -typedef struct hw_flow_extra_s { - int source_port; /* If single source port, what is it */ - int dest_port; /* If one dest port, what is it */ - /* If multi dest ports, one pbmp per device */ - FIXME dports; - int dest_count; /* Drop (0), unicast (1), multicast (>1) */ - uint32 local_reason; /* Why forwarded to CPU */ - int cosq; /* For enqueue action */ -} hw_flow_extra_t; - -/* Driver functions */ -extern int of_hw_flow_install(struct sw_table *flowtab, struct sw_flow *flow); -extern int of_hw_flow_modify(struct sw_table *flowtab, - const struct sw_flow_key *key, uint16_t priority, int strict, - const struct ofp_action_header *actions, size_t actions_len); -extern int of_hw_flow_delete(struct datapath *dp, struct sw_table *flowtab, - const struct sw_flow_key *key, uint16_t out_port, - uint16_t priority, int strict); -extern void of_hw_flow_timeout(struct sw_table *flowtab, - struct list *deleted); -extern struct sw_flow *of_hw_flow_lookup(struct sw_table *flowtab, - const struct sw_flow_key *key); - - -extern int of_hw_sw_flow_stat_update(struct sw_flow *flow, int *used, - int force_sync); -extern int of_hw_flow_stats_get(of_hw_driver_t *hw_drv, struct ofp_match, - struct ofp_flow_stats **stats, int *count); -extern int of_hw_aggregate_stats_get(struct ofp_match, - struct ofp_aggregate_stats_reply *stats); - -/* Controls a single FP (HW table flow) entry */ -struct entry_control_s { - /* These must be persistent; update fp_entry_remove if you change this */ - int index; /* This entry-s index in field_control list */ - - int in_use; - hw_flow_t *hw_flow; - - /* - * HW specific info - */ - FIXME; - - unsigned long int used_check; /* Last counter; for checking if used */ - unsigned long int last_counter; /* pkts or bytes, see stat_sel above */ - unsigned long int counter_last_check; /* Track entry usage by cntr */ - unsigned long int total_counter; /* FIXME: u64? */ -}; - -/* Driver associated with a HW entry */ -#define HW_ENTRY_DRIVER(ent) ((ent)->hw_flow->hw_drv) - -/* FP control structure */ -struct field_control_s { - /* HW Specific info */ - FIXME; - int entry_count; /* How many entries in use */ - entry_control_t entry_list[FIELD_ENTRY_MAX]; /* Instantiation of entries */ -}; - -/* FIXME: Do we need reference counts on stat objects? */ - -extern int of_hw_fp_setup(void); -extern int of_hw_table_stats_update(of_hw_driver_int_t *hw_drv, - unsigned long *matched, unsigned long *missed); - -extern void of_hw_flow_remove_all(of_hw_driver_int_t *hw_int); - - -#endif /* SAMPLE_PLATFORM_HW_FLOW_H */ diff --git a/openflow/hw-lib/skeleton/of_hw_platform.h b/openflow/hw-lib/skeleton/of_hw_platform.h deleted file mode 100644 index 11a3364c..00000000 --- a/openflow/hw-lib/skeleton/of_hw_platform.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef HW_LIB_SKELETON_PLATFORM_H -#define HW_LIB_SKELETON_PLATFORM_H 1 - -#if defined(OF_HW_DP_MAIN) -#define P printf -#else -#define P printf -#endif - -/* - * General Hardware Switch platform defines - * - * Also includes platform specific definitions based on make defines - */ - -#define OF_HW_MAX_PORT 64 - -/* Reasons that a packet is being forwarded to the controller; */ -#define CPU_REASON_DEFAULT (1 << 0) -#define CPU_REASON_TO_CONTROLLER (1 << 1) -#define CPU_REASON_TO_LOCAL (1 << 2) - -#define EXACT_MATCH_PRIORITY TBD - -/**************************************************************** - * - * Platform specific defines and linkage - * - * Implicitly we have a "driver" for the board which includes - * hardware specific information including HW to OF port mapping - * - ****************************************************************/ - -#if defined(OF_SAMPLE_PLAT) -#include "sample_plat.h" -#endif - -#endif /* HW_LIB_SKELETON_PLATFORM_H */ diff --git a/openflow/hw-lib/skeleton/os.h b/openflow/hw-lib/skeleton/os.h deleted file mode 100644 index 268daa97..00000000 --- a/openflow/hw-lib/skeleton/os.h +++ /dev/null @@ -1,29 +0,0 @@ - -/* - * OS abstractions - */ - -#ifndef OF_HW_OS_H -#define OF_HW_OS_H 1 - -#include - -#define ALLOC(bytes) malloc(bytes) -#define FREE(ptr) free(ptr) - -#define PKT_ALLOC(bytes) TBD -#define PKT_FREE(ptr) TBD - -#define MUTEX_DECLARE(name) TBD -#define MUTEX_INIT(name) TBD -#define MUTEX_LOCK(name) TBD -#define MUTEX_UNLOCK(name) TBD - -#define TIME_NOW(time) TBD -#define TIME_DIFF(diff, early, late) TBD - -/* FIXME */ -#include -#define os_pkt_free(pkt) ofpbuf_delete(pkt) - -#endif /* OF_HW_OS_H */ diff --git a/openflow/hw-lib/skeleton/port.c b/openflow/hw-lib/skeleton/port.c deleted file mode 100644 index 7d8c5e3b..00000000 --- a/openflow/hw-lib/skeleton/port.c +++ /dev/null @@ -1,497 +0,0 @@ -/* - * Port related HW datapath functions - */ - -#include -#include - -#include "xtoxll.h" -#include "hw_drv.h" -#include "of_hw_platform.h" -#include "port.h" -#include "debug.h" - -/* Single set of HW port objects managed here; indexed by OF port num */ -of_hw_port_t of_hw_ports[OF_HW_MAX_PORT]; - -/* Check if hw DP and port are valid and if port belongs to the DP */ -#define CHECK_PORT(_drv, _p) do { \ - if ((_drv) == NULL) return -1; \ - if (((_p) < 1) || ((_p) > OF_HW_MAX_PORT)) { \ - REPORT_ERROR("bad port number"); \ - return -1; \ - } \ - if (!(OF_PORT_IN_DP(((of_hw_driver_int_t *)(_drv)), (_p)))) { \ - REPORT_ERROR("DP does not own port"); \ - return -1; \ - } \ -} while (0) - - -/* - * Queue configuration section - * - * Port queue: Per port structure for queue related information - * Queue map: Indicated queue is mapped and what OF qid its mapped to as - * well as queue properties (min-bw). Indexed by OF port number; - * per port instance of array - * - */ - -typedef struct queue_map_s { - int in_use; - uint32_t qid; /* OF queue name */ - int min_bw; /* OF value, tenths of a percent */ -} queue_map_t; - -typedef struct port_queue_s { - int speed; /* In Mbps */ - queue_map_t queue_map[NUM_COS_QUEUES]; -} port_queue_t; - -static port_queue_t port_queue[OF_HW_MAX_PORT]; - -/* Return the cos for the queue matching qid if found; else -1. - * Assumes lock held - */ -static int -qid_find(int of_port, uint32_t qid) -{ - struct queue_map_s *qm; - int cosq; - - qm = port_queue[of_port].queue_map; - for (cosq = 0; cosq < NUM_COS_QUEUES; cosq++) { - if (qm[cosq].in_use && (qid == qm[cosq].qid)) { - return cosq; - } - } - - return -1; -} - -/* Return the cos for the queue matching qid if found; else -1. - * Assumes lock held - */ -int -of_hw_qid_find(int of_port, uint32_t qid) -{ - int cosq; - - /* LOCK */ - cosq = qid_find(of_port, qid); - /* UNLOCK */ - - return cosq; -} - -/* - * Map an OF qid to a COS queue index; if not present, add it if possible - * Assumes lock held - */ -static int -qid_find_add(int of_port, uint32_t qid) -{ - struct queue_map_s *qm; - int cosq; - - cosq = qid_find(of_port, qid); - if (cosq >= 0) { - return cosq; - } - - /* Not found; add queue */ - for (cosq = 0; cosq < NUM_COS_QUEUES; cosq++) { - qm = port_queue[of_port].queue_map; - if (!qm[cosq].in_use) { - qm[cosq].in_use = true; - qm[cosq].qid = qid; - return cosq; - } - } - - return -1; -} - -/* - * Port speed has changed; requires queue b/w to change - */ -static void -port_speed_change_reconfig(of_hw_driver_int_t *hw_int, int of_port) -{ - int cosq; - struct queue_map_s *qm; - int rv; - - /* LOCK */ - for (cosq = 0; cosq < NUM_COS_QUEUES; cosq++) { - qm = port_queue[of_port].queue_map; - if (qm[cosq].in_use) { - /* FIXME: Calc and program values for HW for min-bw */ - if (rv < 0) { - DBG_ERROR("ERROR: Set min BW for queue on port %d " - "link change\n", of_port); - } - } - } - /* UNLOCK */ -} - - -/* Internal handler for port link status changes */ - -/* FIXME */ -static void -of_hw_linkscan_handler(...) -{ - int of_port; - of_hw_driver_int_t *hw_int; - - /* Assumes speed, linkstatus from HW */ - /* Map port to internal port object */ - of_port = HW_MAP_TO_PORT(); - if ((of_port < 0) || (of_port > OF_HW_MAX_PORT)) { - return; - } - - /* LOCK */ - hw_int = (of_hw_driver_int_t *)(of_hw_ports[of_port].owner); - if (hw_int != NULL) { - if (port_queue[of_port].speed != speed) { - port_queue[of_port].speed = speed; - port_speed_change_reconfig(hw_int, of_port); - } - } - /* Record in local struct */ - of_hw_ports[of_port].link = linkstatus != 0; - if ((hw_int != NULL) && (hw_int->port_change != NULL)) { - hw_int->port_change(of_port, linkstatus != 0, - hw_int->port_change_cookie); - } - /* UNLOCK */ -} - -static int linkscan_registered; - -/* - * of_hw_ports_init - * Set up hardware port map - */ -void -of_hw_ports_init(void) -{ - int i; - - for (i = 0; i < OF_HW_MAX_PORT; i++) { - of_hw_ports[i].owner = NULL; - of_hw_ports[i].port = MAP_OF_PORT_TO_HW_PORT(i); - } - - /* FIXME: REGISTER FOR LINK CHANGE CALLBACK */ - /* Always register linkscan handler */ - linkscan_registered = 1; - - /* Get current link status for each port; ignore errors for bad ports */ - for (i = 0; i < OF_HW_MAX_PORT; i++) { - /* FIXME */ - HW_LINK_STATUS_GET(of_hw_ports[i].port, &of_hw_ports[i].link); - } -} - - -#define HTON64 htonll - -/* Get port stats into a standard openflow port stats structure */ -int -of_hw_port_stats_get(of_hw_driver_t *hw_drv, int of_port, - struct ofp_port_stats *stats) -{ - uint64 v1, v2; - - CHECK_PORT(hw_drv, of_port); - - -#if 0 /* FIXME; Get stats from HW */ - HW_STAT(of_port, snmpIfInNUcastPkts, &v1); - HW_STAT(of_port, snmpIfInUcastPkts, &v2); - v1 += v2; - stats->rx_packets = HTON64(v1); - HW_STAT(of_port, snmpIfOutNUcastPkts, &v1); - HW_STAT(of_port, snmpIfOutUcastPkts, &v2); - v1 += v2; - stats->tx_packets = HTON64(v1); - HW_STAT(of_port, snmpIfInOctets, &v1); - stats->rx_bytes = HTON64(v1); - HW_STAT(of_port, snmpIfOutOctets, &v1); - stats->tx_bytes = HTON64(v1); - HW_STAT(of_port, snmpIfInDiscards, &v1); - stats->rx_dropped = HTON64(v1); - HW_STAT(of_port, snmpIfOutDiscards, &v1); - stats->tx_dropped = HTON64(v1); - HW_STAT(of_port, snmpIfInErrors, &v1); - stats->rx_errors = HTON64(v1); - HW_STAT(of_port, snmpIfOutErrors, &v1); - stats->tx_errors = HTON64(v1); -#endif - - v1 = UINT64_C(0xffffffffffffffff); - stats->rx_frame_err = HTON64(v1); - stats->rx_over_err = HTON64(v1); - stats->rx_crc_err = HTON64(v1); - stats->collisions = HTON64(v1); - - return 0; -} - -/* - * port_add/remove(table, port) - * - * The indicated port has been added to/removed from the datapath - * Add also maps the of_port number to the hw_port indicated - * - * SPEC CHANGE: If of_port passed is less than 0, use the passed - * port name to determine the port number and attach to that value; - * - * Returns the of_port number or -1 on error - */ -int -of_hw_port_add(of_hw_driver_t *hw_drv, int of_port, const char *hw_name) -{ - int hw_idx; - of_hw_port_t *port_ctl; - of_hw_driver_int_t *hw_int; - - if (hw_drv == NULL) { - return -1; - } - - hw_idx = hw_port_name_to_index(hw_name); - if (of_port < 0) { - of_port = hw_idx + 1; - } else if (hw_idx + 1 != of_port) { - DBG_WARN("Add Port: OF port %d does not match name %s\n", - of_port, hw_name); - } - - if (of_port >= OF_HW_MAX_PORT) { - DBG_ERROR("Add Port: Bad port number %d\n", of_port); - return -1; - } - - hw_int = (of_hw_driver_int_t *)hw_drv; - port_ctl = &of_hw_ports[of_port]; - - HW_DRV_LOCK; - if (port_ctl->owner == NULL) { - port_ctl->owner = hw_drv; - /* FIXME: port bitmaps in HW structure */ - } else if (port_ctl->owner != hw_drv) { - DBG_ERROR("Add Port: OF port %d owned by other DP\n", of_port); - } else { - DBG_WARN("Add Port: OF port %d already added\n", of_port); - } - HW_DRV_UNLOCK; - - return of_port; -} - -int -of_hw_port_remove(of_hw_driver_t *hw_drv, of_port_t of_port) -{ - of_hw_port_t *port_ctl; - of_hw_driver_int_t *hw_int; - int rc = 0; - - if (hw_drv == NULL) { - return -1; - } - - if ((of_port < 1) || (of_port >= OF_HW_MAX_PORT)) { - DBG_ERROR("Remove Port: Bad port number %d\n", of_port); - return -1; - } - - hw_int = (of_hw_driver_int_t *)hw_drv; - port_ctl = &of_hw_ports[of_port]; - - HW_DRV_LOCK; - if (port_ctl->owner == NULL) { - DBG_WARN("Remove Port: OF port %d already free\n", of_port); - } else if (port_ctl->owner != hw_drv) { - DBG_ERROR("Remove Port: OF port %d owned by other DP\n", of_port); - rc = -1; - } else { - port_ctl->owner = NULL; - } - /* FIXME UPDATE HW port bitmaps in hw_int */ - HW_DRV_UNLOCK; - - return rc; -} - - -/* - * port_link_get(table, port) - * port_enable_set(table, port, enable) - * port_enable_get(table, port) - * - * Get/set the indicated properties of a port. Only real ports - * set with port_add are supported. - */ -int -of_hw_port_link_get(of_hw_driver_t *hw_drv, int of_port) -{ - int rc; - int link; - - CHECK_PORT(hw_drv, of_port); - - if (linkscan_registered) { - return of_hw_ports[of_port].link; - } - - if ((rc = HW_LINK_GET(of_hw_ports[of_port].port, &link)) < 0) { - DBG_ERROR("link_get: error %d port %d\n", rc, of_port); - /* Return link down on error */ - return 0; - } - - return link ? 1 : 0; -} - -int -of_hw_port_enable_set(of_hw_driver_t *hw_drv, int of_port, int enable) -{ - int rc; - - CHECK_PORT(hw_drv, of_port); - - if ((rc = HW_PORT_ENABLE_SET(of_hw_ports[of_port].port, enable)) < 0) { - DBG_ERROR("of_hw_port_enable_set: error %d port %d\n", - rc, of_port); - return rc; - } - - return 0; -} - -int -of_hw_port_enable_get(of_hw_driver_t *hw_drv, int of_port) -{ - int rc; - int enable; - - CHECK_PORT(hw_drv, of_port); - - if ((rc = HW_PORT_ENABLE_GET(of_hw_ports[of_port].port, &enable)) < 0) { - DBG_ERROR("of_hw_port_enable_get: error %d port %d\n", - rc, of_port); - return rc; - } - - return enable ? 1 : 0; -} - - -/* - * port_change_register - * - * Register a callback function to receive port change notifications - * from ports in this datapath; only one callback per datapath is - * supported. - */ -int -of_hw_port_change_register(of_hw_driver_t *hw_drv, of_port_change_f callback, - void *cookie) -{ - of_hw_driver_int_t *dp_int; - - dp_int = (of_hw_driver_int_t *)hw_drv; - dp_int->port_change = callback; - dp_int->port_change_cookie = cookie; - - return 0; -} - -/* - * Init COS queue setup. The queues number is fixed at 8. Deficit - * round robin is the discipline, initially with all equal weights. - * As queues are configured with min bandwidth reservations, the - * weights are adjusted to ensure the requested targets. - * - * For now, these are device generic; may need to specialize in the - * future. - */ - -int -of_hw_cos_setup(int num_cos) -{ - /* FIXME: Set up COS queues */ - - return 0; -} - -/* - * Add and/or configure an output queue on a port. - * - * If qid exists, update. If not, look for an unreferenced queue and - * set the qid to that value. - * - * Note that when a port state changes, may need to re-configure - * the bandwidth values for the port's queues. - */ - -int -of_hw_port_queue_config(of_hw_driver_t *hw_drv, int of_port, uint32_t qid, - int min_bw) /* In tenths of a percent */ -{ - int min_kbps; - of_hw_driver_int_t *hw_int; - int cosq; - struct queue_map_s *qm; - int rv; - - hw_int = (of_hw_driver_int_t *)hw_drv; - - CHECK_PORT(hw_int, of_port); - - /* LOCK */ - /* Get the current bandwidth of the port (cached?) */ - if ((cosq = qid_find_add(of_port, qid)) < 0) { - DBG_ERROR("Could not add queue: of port %d, qid %d\n", of_port, qid); - /* UNLOCK */ - return -1; - } - qm = &port_queue[of_port].queue_map[qid]; - qm->min_bw = min_bw; - - HW_SET_MIN_BW(...); - /* UNLOCK */ - - return (rv != 0) ? -1 : 0; -} - -/* Remove a queue from a port; this potentially affects the queue - * configuration otherwise we would not worry about it here. - * Return -1 if not found; 0 on success - */ - -int -of_hw_port_queue_remove(of_hw_driver_t *hw_drv, int of_port, uint32_t qid) -{ - int cosq; - - (void)hw_drv; - /* LOCK */ - if ((cosq = qid_find(of_port, qid)) == -1) { - /* UNLOCK */ - return -1; - } - - /* Do we need to update stats or DRR weights or anything? */ - - port_queue[of_port].queue_map[cosq].in_use = false; - - /* UNLOCK */ - return 0; -} diff --git a/openflow/hw-lib/skeleton/port.h b/openflow/hw-lib/skeleton/port.h deleted file mode 100644 index dd2c0828..00000000 --- a/openflow/hw-lib/skeleton/port.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef OF_HW_PORT_H -#define OF_HW_PORT_H 1 - -#include -#include -#include "of_hw_platform.h" - -#define NUM_COS_QUEUES 8 - -/* Define port mapping object indexed by OF number */ -typedef struct of_hw_port_s { - of_hw_driver_t *owner; /* Owner of this port */ - int port; /* Physical port number on device */ - int link; /* Link state */ - /* TBD: Keep track of link state and don't transmit if down? */ - /* Add other physical info here as needed */ -} of_hw_port_t; - -extern of_hw_port_t of_hw_ports[OF_HW_MAX_PORT]; - -#define FOREACH_DP_PORT(_idx, _drv) \ - for (_idx = 0; _idx < OF_HW_MAX_PORT; _idx++) \ - if (of_hw_ports[_idx].owner == (of_hw_driver_t *)(_drv)) - -extern int of_hw_cos_setup(int num_cos); -extern int of_hw_qid_find(int of_port, uint32_t qid); - -extern void of_hw_ports_init(void); -extern int of_hw_port_stats_get(of_hw_driver_t *hw_drv, int of_port, - struct ofp_port_stats *stats); -extern int of_hw_port_add(of_hw_driver_t *hw_drv, int of_port, - const char *hw_name); -extern int of_hw_port_remove(of_hw_driver_t *hw_drv, of_port_t of_port); -extern int of_hw_port_link_get(of_hw_driver_t *hw_drv, int of_port); -extern int of_hw_port_enable_set(of_hw_driver_t *hw_drv, int of_port, - int enable); -extern int of_hw_port_enable_get(of_hw_driver_t *hw_drv, int of_port); -extern int of_hw_port_queue_config(of_hw_driver_t *hw_drv, int of_port, - uint32_t qid, int min_bw); /* In tenths of a percent */ -extern int of_hw_port_queue_remove(of_hw_driver_t *hw_drv, int of_port, - uint32_t qid); -extern int of_hw_port_change_register(of_hw_driver_t *hw_drv, - of_port_change_f callback, void *cookie); - -#endif /* OF_HW_PORT_H */ diff --git a/openflow/hw-lib/skeleton/sample_plat.c b/openflow/hw-lib/skeleton/sample_plat.c deleted file mode 100644 index 17f3747b..00000000 --- a/openflow/hw-lib/skeleton/sample_plat.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * sample_plat.c - * - * FIXME: Standard confidential header - * - * $Id: $ - */ - -/* - * Sample hardware initialization functions - */ - -#include "debug.h" -#include "of_hw_platform.h" - -#if defined(SAMPLE_PLAT) - -#include "port.h" - -/* sample_plat_port_setup - * - * Set up linkscan and necessary spanning tree for ports - * Disable VLAN dropping - */ -static int -sample_plat_port_setup(...) -{ - - return 0; -} - -#if defined(OF_HW_DP_MAIN) && defined(SAMPLE_HW_PLAT) - -/* If defined, need to do init here */ - -/* - * sample_plat_pre_init - * - * Turn off everything that might cause problems during init - */ - -static int -sample_plat_pre_init(void) -{ - /* bring system down to known state */ - return 0; -} - -/* - */ -int -sample_plat_init(void) -{ - /* Init system */ - - /* First, clear out everything */ - sample_plat_pre_init(); - - /* ... */ - - sample_plat_port_setup(...); - - return 0; -} - -/* FIXME: Deal with initial FP setup */ - -#else /* Not stand alone init; Other code does init */ - -int -sample_plat_init(void) -{ - DBG_WARN("sample_plat_init\n"); - - TRY(sample_plat_port_setup(...), "sample plat init port setup"); - - return 0; -} - -#endif - -#endif /* SAMPLE_PLAT */ diff --git a/openflow/hw-lib/skeleton/sample_plat.h b/openflow/hw-lib/skeleton/sample_plat.h deleted file mode 100644 index 3d88eb01..00000000 --- a/openflow/hw-lib/skeleton/sample_plat.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef SAMPLE_PLAT_H -#define SAMPLE_PLAT_H 1 - - -#include -#include -#include - -#include - -#define OF_HW_MAX_PORTS 4 - -static inline int -of_port_to_hw_port(int of_port) -{ - return of_port - 1; -} - - -/* Map port to OF port number */ -static inline int -of_hw_port_to_of_port(int port) -{ - if ((port < 0) || (port > 3)) { - return -1; - } - - return port + 1; -} - -#define _IS_DIGIT(c) ((c) >= '0' && (c) <= '9') - -/* Map name to hw port number: N => N-1 - ge0 => 0 where "ge" can be any string and 0 can be any number -*/ - -static inline int -hw_port_name_to_index(const char *name) -{ - - if (_IS_DIGIT(name[0])) { - /* Treat as 1-based, OF number */ - i = strtoul(&name[0], NULL, 10); - return i - 1; - } - - len = strlen(name); - for (idx = 0; idx < len && !_IS_DIGIT(name[idx]); idx++) ; - - if ((idx < len) && _IS_DIGIT(name[idx])) { - i = strtoul(&name[idx], NULL, 10); - return i; - } - - return -1; -} -#undef _IS_DIGIT - - - -#endif /* SAMPLE_PLAT_H */ diff --git a/openflow/hw-lib/skeleton/txrx.c b/openflow/hw-lib/skeleton/txrx.c deleted file mode 100644 index 950d839f..00000000 --- a/openflow/hw-lib/skeleton/txrx.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Transmit and receive related functions for hardware platforms - */ - -#include -#include "os.h" -#include "hw_drv.h" -#include "txrx.h" -#include "port.h" -#include "debug.h" -#include "of_hw_platform.h" - -static int pkt_count, failures, prev_success, free_count, error_free; -static void -tx_pkt_callback(...) -{ - of_packet_t *of_pkt = cookie; - - /* os_pkt_free(of_pkt->os_pkt); */ - FREE(of_pkt); - /* ... */ - ++free_count; -} - -/* - * tx_packet_send(table, of_port, pkt, flags) - * - * Send packet to an openflow port. - * - * Proposed flags: - * APPLY_FLOW_TABLE: If set, and if the hardware supports - * it, send the packet through the flow table with the source - * port being the local CPU port. (Would be nice to have - * a flexible source port indicated; could hide in flags...) - * - * Assumes buffer in pkt struct can be used for sending data - * - * - */ -int -of_hw_packet_send(of_hw_driver_t *hw_drv, int of_port, of_packet_t *pkt, - uint32_t flags) -{ - /* FIXME: Code to prepare and send pkt */ - return 0; -} - -/* Callback function registered with HW */ -static int -of_hw_rx(...) -{ - /* Sample RX handler */ - int of_port; - of_hw_driver_int_t *hw_drv; - of_packet_t *of_pkt; - int pkt_len; - - /* map receive port to of_port */ - /* map received packet to of_pkt */ - /* Call callback */ - - of_port = of_hw_port_to_of_port(receive_port); - if (of_port < 0) { - return hw_not_handled; - } - - /* LOCK */ - hw_drv = (of_hw_driver_int_t *)(of_hw_ports[of_port].owner); - if ((hw_drv == NULL) || (hw_drv->rx_handler == NULL)) { - /* UNLOCK */ - return hw_not_handled; - } - - of_pkt = ALLOC(sizeof(of_packet_t)); - if (of_pkt == NULL) { - ++hw_drv->rx_pkt_alloc_failures; - /* UNLOCK */ - return hw_not_handled; - } - pkt_len = pkt->tot_len; - - /* FIXME: FOR NOW, COPY DATA INTO NEW BUFFER; */ - of_pkt->data = ALLOC(pkt_len); - if (of_pkt->data == NULL) { - FREE(of_pkt); - /* UNLOCK */ - return hw_not_handled; - } - - /* Handle VLAN tagging if needed */ - /* Coy pkt data appropriately */ - - /* FIXME: Determine reason (dflt rule or directed) */ - /* FIXME: Return code interpretation? */ - /* OFPR_NO_MATCH, No matching flow. */ - /* OFPR_ACTION Action explicitly output to controller. */ - hw_drv->rx_handler(of_port, of_pkt, 0, hw_drv->rx_cookie); - /* UNLOCK */ - - return hw_handled; -} - -static int rx_registered = 0; - -/* - * packet_receive_register - * - * Register a callback function to receive packets from ports in - * this datapath - */ -int -of_hw_packet_receive_register(of_hw_driver_t *hw_drv, - of_packet_in_f callback, void *cookie) -{ - of_hw_driver_int_t *dp_int; - int rv; - - /* Register for link status changes */ - if (!rx_registered) { - /* Set up low level pkt receive for callback */ - rx_registered = 1; - } - - dp_int = (of_hw_driver_int_t *)hw_drv; - dp_int->rx_handler = callback; - dp_int->rx_cookie = cookie; - - return 0; -} diff --git a/openflow/hw-lib/skeleton/txrx.h b/openflow/hw-lib/skeleton/txrx.h deleted file mode 100644 index 1aef9026..00000000 --- a/openflow/hw-lib/skeleton/txrx.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef OF_HW_TXRX_H -#define OF_HW_TXRX_H 1 - -#include -#include - -extern int of_hw_packet_send(of_hw_driver_t *hw_drv, int of_port, - of_packet_t *pkt, uint32_t flags); -extern int of_hw_packet_receive_register(of_hw_driver_t *hw_drv, - of_packet_in_f callback, void *cookie); - -#endif /* OF_HW_TXRX_H */ diff --git a/openflow/include/.gitignore b/openflow/include/.gitignore deleted file mode 100644 index b336cc7c..00000000 --- a/openflow/include/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/Makefile -/Makefile.in diff --git a/openflow/include/automake.mk b/openflow/include/automake.mk deleted file mode 100644 index 581c1085..00000000 --- a/openflow/include/automake.mk +++ /dev/null @@ -1 +0,0 @@ -include include/openflow/automake.mk diff --git a/openflow/include/openflow/automake.mk b/openflow/include/openflow/automake.mk deleted file mode 100644 index 3c45b082..00000000 --- a/openflow/include/openflow/automake.mk +++ /dev/null @@ -1,5 +0,0 @@ -noinst_HEADERS += \ - include/openflow/nicira-ext.h \ - include/openflow/private-ext.h \ - include/openflow/openflow.h \ - include/openflow/openflow-netlink.h diff --git a/openflow/include/openflow/nicira-ext.h b/openflow/include/openflow/nicira-ext.h deleted file mode 100644 index 727864a6..00000000 --- a/openflow/include/openflow/nicira-ext.h +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Distributed under the terms of the GNU GPL version 2. - * Copyright (c) 2008 Nicira Networks - */ - -#ifndef OPENFLOW_NICIRA_EXT_H -#define OPENFLOW_NICIRA_EXT_H 1 - -#include "openflow/openflow.h" - -#define NICIRA_OUI_STR "002320" - -/* The following vendor extensions, proposed by Nicira Networks, are not yet - * ready for standardization (and may never be), so they are not included in - * openflow.h. */ - -#define NX_VENDOR_ID 0x00002320 - -enum nicira_type { - /* Switch status request. The request body is an ASCII string that - * specifies a prefix of the key names to include in the output; if it is - * the null string, then all key-value pairs are included. */ - NXT_STATUS_REQUEST, - - /* Switch status reply. The reply body is an ASCII string of key-value - * pairs in the form "key=value\n". */ - NXT_STATUS_REPLY, - - /* Configure an action. Most actions do not require configuration - * beyond that supplied in the actual action call. */ - NXT_ACT_SET_CONFIG, - - /* Get configuration of action. */ - NXT_ACT_GET_CONFIG, - - /* Remote command execution. The request body is a sequence of strings - * delimited by null bytes. The first string is a command name. - * Subsequent strings are command arguments. */ - NXT_COMMAND_REQUEST, - - /* Remote command execution reply, sent when the command's execution - * completes. The reply body is struct nx_command_reply. */ - NXT_COMMAND_REPLY, - - /* Configure whether Flow End messages should be sent. */ - NXT_FLOW_END_CONFIG, - - /* Sent by switch when a flow ends. These messages are turned into - * ofp_flow_removed and NetFlow messages in user-space. */ - NXT_FLOW_END -}; - -struct nicira_header { - struct ofp_header header; - uint32_t vendor; /* NX_VENDOR_ID. */ - uint32_t subtype; /* One of NXT_* above. */ -}; -OFP_ASSERT(sizeof(struct nicira_header) == sizeof(struct ofp_vendor_header) + 4); - - -enum nx_snat_command { - NXSC_ADD, - NXSC_DELETE -}; - -/* Configuration for source-NATing */ -struct nx_snat_config { - uint8_t command; /* One of NXSC_*. */ - uint8_t pad[3]; - uint16_t port; /* Physical switch port. */ - uint16_t mac_timeout; /* Time to cache MAC addresses of SNAT'd hosts - in seconds. 0 uses the default value. */ - - /* Range of IP addresses to impersonate. Set both values to the - * same to support a single address. */ - uint32_t ip_addr_start; - uint32_t ip_addr_end; - - /* Range of transport ports that should be used as new source port. A - * value of zero, let's the switch choose.*/ - uint16_t tcp_start; - uint16_t tcp_end; - uint16_t udp_start; - uint16_t udp_end; - - /* MAC address to use for ARP requests for a SNAT IP address that - * comes in on a different interface than 'port'. A value of all - * zeros silently drops those ARP requests. Requests that arrive - * on 'port' get a response with the mac address of the datapath - * device. */ - uint8_t mac_addr[OFP_ETH_ALEN]; - uint8_t pad2[2]; -}; -OFP_ASSERT(sizeof(struct nx_snat_config) == 32); - -/* Action configuration. Not all actions require separate configuration. */ -struct nx_act_config { - struct nicira_header header; - uint16_t type; /* One of OFPAT_* */ - uint8_t pad[2]; - union { - struct nx_snat_config snat[0]; - }; /* Array of action configurations. The number - is inferred from the length field in the - header. */ -}; -OFP_ASSERT(sizeof(struct nx_act_config) == 20); - - -enum nx_action_subtype { - NXAST_SNAT /* Source-NAT */ -}; - -/* Action structure for NXAST_SNAT. */ -struct nx_action_snat { - uint16_t type; /* OFPAT_VENDOR. */ - uint16_t len; /* Length is 8. */ - uint32_t vendor; /* NX_VENDOR_ID. */ - uint16_t subtype; /* NXAST_SNAT. */ - uint16_t port; /* Output port--it must be previously - configured. */ - uint8_t pad[4]; -}; -OFP_ASSERT(sizeof(struct nx_action_snat) == 16); - -/* Header for Nicira-defined actions. */ -struct nx_action_header { - uint16_t type; /* OFPAT_VENDOR. */ - uint16_t len; /* Length is 8. */ - uint32_t vendor; /* NX_VENDOR_ID. */ - uint16_t subtype; /* NXAST_*. */ - uint8_t pad[6]; -}; -OFP_ASSERT(sizeof(struct nx_action_header) == 16); - -/* Status bits for NXT_COMMAND_REPLY. */ -enum { - NXT_STATUS_EXITED = 1 << 31, /* Exited normally. */ - NXT_STATUS_SIGNALED = 1 << 30, /* Exited due to signal. */ - NXT_STATUS_UNKNOWN = 1 << 29, /* Exited for unknown reason. */ - NXT_STATUS_COREDUMP = 1 << 28, /* Exited with core dump. */ - NXT_STATUS_ERROR = 1 << 27, /* Command could not be executed. */ - NXT_STATUS_STARTED = 1 << 26, /* Command was started. */ - NXT_STATUS_EXITSTATUS = 0xff, /* Exit code mask if NXT_STATUS_EXITED. */ - NXT_STATUS_TERMSIG = 0xff, /* Signal number if NXT_STATUS_SIGNALED. */ -}; - -/* NXT_COMMAND_REPLY. */ -struct nx_command_reply { - struct nicira_header nxh; - uint32_t status; /* Status bits defined above. */ - /* Followed by any number of bytes of process output. */ -}; -OFP_ASSERT(sizeof(struct nx_command_reply) == 20); - -enum nx_flow_end_reason { - NXFER_IDLE_TIMEOUT, /* Flow idle time exceeded idle_timeout. */ - NXFER_HARD_TIMEOUT, /* Time exceeded hard_timeout. */ - NXFER_DELETE, /* Flow was removed by delete command. */ - NXFER_EJECT /* Flow was ejected. */ -}; - -struct nx_flow_end_config { - struct nicira_header header; - uint8_t enable; /* Set to 1 to enable Flow End message - generation. 0 to disable. */ - uint8_t pad[3]; -}; -OFP_ASSERT(sizeof(struct nx_flow_end_config) == 20); - -struct nx_flow_end { - struct nicira_header header; - struct ofp_match match; /* Description of fields. */ - uint64_t cookie; /* Opaque controller-issued identifier. */ - - uint16_t priority; /* Priority level of flow entry. */ - uint8_t reason; /* One of NXFER_*. */ - - uint8_t tcp_flags; /* Union of seen TCP flags. */ - uint8_t ip_tos; /* IP TOS value. */ - - uint8_t send_flow_exp; /* Send flow expiry to controller. */ - - uint16_t idle_timeout; /* Idle time before discarding (seconds). */ - - uint64_t init_time; /* Time flow started in milliseconds. */ - uint64_t used_time; /* Time entry was last used in milliseconds. */ - uint64_t end_time; /* Time flow ended in milliseconds. */ - - uint64_t packet_count; - uint64_t byte_count; -}; -OFP_ASSERT(sizeof(struct nx_flow_end) == 112); - -#endif /* openflow/nicira-ext.h */ diff --git a/openflow/include/openflow/of_hw_api.h b/openflow/include/openflow/of_hw_api.h deleted file mode 100644 index 2dca1900..00000000 --- a/openflow/include/openflow/of_hw_api.h +++ /dev/null @@ -1,313 +0,0 @@ -/* Copyright (c) 2008, 2009, 2010 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#if !defined(OF_HW_API_H) -#define OF_HW_API_H - -/* - * OpenFlow hardware API definition - * - * This header file provides an abstraction of the flow table and - * port operations that can be used to build a driver for hardware - * that implements the OpenFlow protocol. - * - * Currently this driver depends (extends) the sw_table defined - * in the udatapath/table.h file. Hopefully that file will be - * moved up to library status to support kernel and userspace - * implementations. - * - */ - -#include -#include /* For sw_table */ - -/* REQUIRES: - * struct sw_table defined - * TBD: We could remove this restriction; it's mainly so that - * current chain.c operations can work. It also allows - * pointer coersion between the two types. - * - * Eventually, sw_table may be extended to include everything in - * this driver. - * - * pointer to struct datapath - */ - -/**************** basic types ****************/ - -typedef uint32_t of_port_t; -typedef struct of_hw_driver of_hw_driver_t; - -/**************** packet ****************/ - -/* The OpenFlow hardware packet abstraction */ -typedef void *os_pkt_t; /* OS representation of packet */ - -/* Requires monolithic packet data */ -typedef struct of_packet_s { - unsigned char *data; /* Pointer to packet data */ - int length; /* Length in bytes */ - os_pkt_t os_pkt; /* OS specific representation */ -} of_packet_t; - -/* Init an of_packet struct from an ofp_buffer struct */ -#define OF_PKT_INIT(pkt, ofp_buf) do { \ - (pkt)->data = (ofp_buf)->data; \ - (pkt)->length = (ofp_buf)->size; \ - (pkt)->os_pkt = (ofp_buf); \ - } while (0) - -/**************** callback protos ****************/ - -/* packet in callback function prototype */ -typedef int (*of_packet_in_f)(of_port_t port, - of_packet_t *packet, - int reason, - void *cookie); - -typedef void (*of_port_change_f)(of_port_t port, - int state, - void *cookie); - -/**************************************************************** - * - * Hardware Driver - * - ****************************************************************/ - -/* Hardware capabilities structure */ -typedef struct of_hw_driver_caps { - /* Proposed Flags: - * COUNT_PKTS_OR_BYTES Can count either pkts or bytes, not both - * INTERNAL_PRI Support internal priority mapping, and thus - * normal enqueuing action - * LOCAL_CPU_THRU_TABLE Can send packets from the CPU through - * the flow table - */ - uint32_t flags; - - /* Number of fully qualified flows supported (approx) */ - int max_flows; - uint32_t wc_supported; /* Bitmap of OFPFW_* supported wildcards */ - uint32_t actions_supported; /* Bitmap of OFPAT_* supported actions */ - uint32_t ofpc_flags; /* Bitmap of ofp_capabilities flags */ -} of_hw_driver_caps_t; - -enum of_hw_driver_flags { - OF_HW_DRV_COUNT_PKTS_OR_BYTES = 1 << 0, - OF_HW_DRV_INTERNAL_PRI = 1 << 1, - OF_HW_DRV_CPU_PKTS_THRU_TABLE = 1 << 2 -}; - -/**************** Constructor/Destructor ****************/ - -extern of_hw_driver_t *new_of_hw_driver(struct datapath *dp); -extern void delete_of_hw_driver(of_hw_driver_t *hw_drv); - -/* TBD: Add a HW/DP init function? */ - -/**************** HW DataPath Driver Structure ****************/ -/* Extends sw_table */ -struct of_hw_driver { - - /* - * Notes on sw_table inheritance: - * - * See above as well - * - * n_lookup and n_matched are not dynamically updated, but the - * call to table_stats_update should set them - */ - struct sw_table sw_table; - - /* HW datapath capabilities structure */ - of_hw_driver_caps_t caps; - - /* OPTIONAL - * init(table, flags) - * - * Initialize necessary hardware and software to run - * the switching table. Must be called prior to any other calls - * into the table (except maybe some ioctls?). - * - * Proposed flags include: - * BYTES/PACKETS: If COUNT_PKTS_OR_BYTES, which to count by default - * REATTACH: Inidicates HW was running, don't re-initialize HW - * - */ - int (*init)(of_hw_driver_t *hw_drv, uint32_t flags); - - /* - * table_stats_get(table, stats) - * port_stats_get(port, stats) - * flow_stats_get(flow_desc, stats) - * aggregate_stats_get(flow_desc, stats) - * - * Fill out the stats object(s) for this table/port/flow(s)/set of flows - * - * Returns 0 on success. - * - * For all but flow_stats, the routine fills out a pre-allocated - * stats structure. For flow stats, an array of stats is allocated - * by the called routine with *count elements. It must be freed by - * the caller. - * - * (Optional? If count is NULL for flow_stats_get, find a single - * match with exactly the given ofp_match.) - */ - int (*table_stats_get)(of_hw_driver_t *hw_drv, struct - ofp_table_stats *stats); - int (*port_stats_get)(of_hw_driver_t *hw_drv, int of_port, - struct ofp_port_stats *stats); - int (*flow_stats_get)(of_hw_driver_t *hw_drv, struct ofp_match, - struct ofp_flow_stats **stats, int *count); - int (*aggregate_stats_get)(struct ofp_match, - struct ofp_aggregate_stats_reply *stats); - - /* - * port_add/remove(table, port) - * - * The indicated port has been added to/removed from the datapath - * Add also maps the of_port number to the hw_port indicated - */ - int (*port_add)(of_hw_driver_t *hw_drv, int of_port, const char *hw_name); - int (*port_remove)(of_hw_driver_t *hw_drv, of_port_t port); - - /* - * port_link_get(table, port) - * port_enable_set(table, port, enable) - * port_enable_get(table, port) - * - * Get/set the indicated properties of a port. Only real ports - * set with port_add are supported. - */ - int (*port_link_get)(of_hw_driver_t *hw_drv, int of_port); - int (*port_enable_set)(of_hw_driver_t *hw_drv, int of_port, int enable); - int (*port_enable_get)(of_hw_driver_t *hw_drv, int of_port); - - /* - * port_queue_config(drv, port, qid, min-bw) - * port_queue_remove(drv, port, qid) - * - * Port queue control. Config will add the queue if not present - */ - int (*port_queue_config)(of_hw_driver_t *hw_drv, int of_port, - uint32_t qid, int min_bw); - int (*port_queue_remove)(of_hw_driver_t *hw_drv, int of_port, - uint32_t qid); - - /* - * port_change_register - * - * Register a callback function to receive port change notifications - * from ports in this datapath - */ - int (*port_change_register)(of_hw_driver_t *hw_drv, - of_port_change_f callback, void *cookie); - - /* - * packet_send(table, of_port, pkt, flags) - * - * Send packet to an openflow port. - * - * Proposed flags: - * APPLY_FLOW_TABLE: If set, and if the hardware supports - * it, send the packet through the flow table with the source - * port being the local CPU port. (Would be nice to have - * a flexible source port indicated; could hide in flags...) - * - * TBD: Owner of pkt and pkt->data after call; sync/async. - */ - int (*packet_send)(of_hw_driver_t *hw_drv, int of_port, of_packet_t *pkt, - uint32_t flags); - - /* - * packet_receive_register - * - * Register a callback function to receive packets from ports in - * this datapath - * - * TBD: Semantics for owning packets and return codes so indicating. - */ - int (*packet_receive_register)(of_hw_driver_t *hw_drv, - of_packet_in_f callback, void *cookie); - - /* OPTIONAL - * ioctl(table, request, io_param) - * - * Execute an ioctl on the table. A few ioctls are predefined, - * but most will be implementation specific. - * Returns 0 on success or an implementation specific other code. - * - * io_param is an input/output parameter whose value may be - * returned to the caller. - * io_len is the length of io_param in bytes. - * On input, the *io_param pointer may clobbered, so the caller must - * maintain it for deallocation if necessary. - * On output, when used -- which depends on the operation -- - * the *io_param is a pointer to a buffer allocated by the ioctl - * routine, but owned by the calling routine. - * - * Question: Should a full I/O buffer be supported? - * ioctl(table, op, in_buf, in_len, out_buf, out_len); or - * ioctl(table, op, io_buf, io_len); where buf/len set on output. - * - * Proposed operations: - * Set debug level - * Clear port/flow/table stats - * Select packet or byte counter collection - */ - int (*ioctl)(of_hw_driver_t *hw_drv, uint32_t op, void **io_param, - int *io_len); - -}; - -/**************** IOCTL values ****************/ - -enum of_hw_ioctl_e { - OF_HW_IOCTL_TABLE_DEBUG_SET = 1, - OF_HW_IOCTL_PORT_DEBUG_SET = 2, - OF_HW_IOCTL_BYTE_PKT_CNTR_SET = 3 -}; - -/* Values for OF_HW_IOCTL_BYTE_PKT_CNTR_SET */ -#define OF_HW_CNTR_PACKETS 0 -#define OF_HW_CNTR_BYTES 1 - -enum of_hw_error_e { - OF_HW_OKAY = 0, - OF_HW_ERROR = -1, - OF_HW_PORT_DOWN = -2 -}; - -#endif /* OF_HW_API_H */ diff --git a/openflow/include/openflow/openflow-ext.h b/openflow/include/openflow/openflow-ext.h deleted file mode 100644 index 581d49a5..00000000 --- a/openflow/include/openflow/openflow-ext.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2009 The Board of Trustees of The Leland - * Stanford Junior University - */ - -#ifndef OPENFLOW_OPENFLOW_EXT_H -#define OPENFLOW_OPENFLOW_EXT_H 1 - -#include "openflow/openflow.h" - -/* - * The following are vendor extensions from OpenFlow. This is a - * means of allowing the introduction of non-standardized - * proposed code. - * - * Structures in this file are 64-bit aligned in size. - */ - -#define OPENFLOW_VENDOR_ID 0x000026e1 - -enum ofp_extension_commands { /* Queue configuration commands */ - /* Queue Commands */ - OFP_EXT_QUEUE_MODIFY, /* Add and/or modify */ - OFP_EXT_QUEUE_DELETE, /* Remove a queue */ - OFP_EXT_SET_DESC, /* Set ofp_desc_stat->dp_desc */ - - OFP_EXT_COUNT -}; - -struct ofp_extension_header { - struct ofp_header header; - uint32_t vendor; /* OPENFLOW_VENDOR_ID. */ - uint32_t subtype; /* One of ofp_extension_commands */ -}; -OFP_ASSERT(sizeof(struct ofp_extension_header) == 16); - -/**************************************************************** - * - * OpenFlow Queue Configuration Operations - * - ****************************************************************/ - -struct openflow_queue_command_header { - struct ofp_extension_header header; - uint16_t port; /* Port for operations */ - uint8_t pad[6]; /* Align to 64-bits */ - uint8_t body[0]; /* Body of ofp_queue objects for op. */ -}; -OFP_ASSERT(sizeof(struct openflow_queue_command_header) == 24); - -/* NOTE - * Bug number: TBD. - * The definitions for openflow_queue_error_code conflict with - * those for ofp_queue_op_failed_code defined in openflow.h. - * This will be addressed after the release of OpenFlow 1.0. - * The error codes below for openflow_queue_error_code may be - * removed at that time. - */ -/* - * Entries for 'code' in ofp_error_msg with error 'type' - * OFPET_QUEUE_OP_FAILED - */ -enum openflow_queue_error_code { - OFQ_ERR_NONE, /* Success */ - OFQ_ERR_FAIL, /* Unspecified failure */ - OFQ_ERR_NOT_FOUND, /* Queue not found */ - OFQ_ERR_DISCIPLINE, /* Discipline not supported */ - OFQ_ERR_BW_UNAVAIL, /* Bandwidth unavailable */ - OFQ_ERR_QUEUE_UNAVAIL, /* Queue unavailable */ - OFQ_ERR_COUNT /* Last please */ -}; - -#define OPENFLOW_QUEUE_ERROR_STRINGS_DEF { \ - "Success", /* OFQ_ERR_NONE */ \ - "Unspecified failure", /* OFQ_ERR_FAIL */ \ - "Queue not found", /* OFQ_ERR_NOT_FOUND */ \ - "Discipline not supported", /* OFQ_ERR_DISCIPLINE */ \ - "Bandwidth unavailable", /* OFQ_ERR_BW_UNAVAIL */ \ - "Queue unavailable" /* OFQ_ERR_QUEUE_UNAVAIL */ \ -} - -extern char *openflow_queue_error_strings[]; - -struct openflow_ext_set_dp_desc { - struct ofp_extension_header header; - char dp_desc[DESC_STR_LEN]; -}; -OFP_ASSERT(sizeof(struct openflow_ext_set_dp_desc) == 272); - -#define ofq_error_string(rv) (((rv) < OFQ_ERR_COUNT) && ((rv) >= 0) ? \ - openflow_queue_error_strings[rv] : "Unknown error code") - -/**************************************************************** - * - * Unsupported, but potential extended queue properties - * - ****************************************************************/ - -#if 0 - -enum ofp_queue_prop_ext { - OFPQT_EXT_MAX_RATE = OFPQT_MIN + 1, /* maximum rate limit */ - OFPQT_EXT_BUF_ALLOC, /* buffer alloc config */ - OFPQT_EXT_SCHED_WEIGHT /* schedule weight config */ - OFPQT_EXT_COUNT /* Last please */ -}; - -#define OPENFLOW_QUEUE_PROP_STRINGS_DEF { \ - "No property specified" /* OFPQT_NONE */ \ - "Minimum Rate", /* OFPQT_MIN */ \ - "Maximum Rate", /* OFQ_PROP_MAX_RATE */ \ - "Buffer alloc weight", /* OFQ_PROP_BUF_ALLOC */ \ - "Scheduling weight" /* OFQ_PROP_SCHED_WEIGHT */ \ -} -extern char *openflow_queue_prop_strings[]; - -#define ofq_prop_string(val) (((val) < OFPQT_EXT_COUNT) && ((val) >= 0) ? \ - openflow_queue_prop_strings[val] : "Unknown property value") - -/* These are all the same a min-rate queue property description */ -/* Max-Rate queue property description */ -struct ofp_queue_prop_max_rate { - struct ofp_queue_prop_header prop_header; /* prop: OFPQT_MIN, len: 16 */ - uint16_t rate; /* in 1/10 of a percent of port BW */ - uint8_t pad[6]; /* 64-bit alignment */ -}; -OFP_ASSERT(sizeof(struct ofp_queue_prop_max_rate) == 16); - -/* Buffer alloc weight queue property description */ -struct ofp_queue_prop_buf_alloc { - struct ofp_queue_prop_header prop_header; /* prop: OFPQT_MIN, len: 16 */ - uint16_t alloc_val; /* 0 disabled; 1 min; 0xffff max */ - uint8_t pad[6]; /* 64-bit alignment */ -}; -OFP_ASSERT(sizeof(struct ofp_queue_prop_buf_alloc) == 16); - -/* Max-Rate queue property description */ -struct ofp_queue_prop_sched_weight { - struct ofp_queue_prop_header prop_header; /* prop: OFPQT_MIN, len: 16 */ - uint16_t weight; /* discipline specific; 0 disabled; 1 min; 0xffff max */ - uint8_t pad[6]; /* 64-bit alignment */ -}; -OFP_ASSERT(sizeof(struct ofp_queue_prop_sched_weight) == 16); - -#endif - - - -#endif /* OPENFLOW_OPENFLOW_EXT_H */ diff --git a/openflow/include/openflow/openflow-netlink.h b/openflow/include/openflow/openflow-netlink.h deleted file mode 100644 index 931e6972..00000000 --- a/openflow/include/openflow/openflow-netlink.h +++ /dev/null @@ -1,69 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#ifndef OPENFLOW_OPENFLOW_NETLINK_H -#define OPENFLOW_OPENFLOW_NETLINK_H 1 - -#define DP_GENL_FAMILY_NAME "OpenFlow" - -/* Attributes that can be attached to the datapath's netlink messages. */ -enum { - DP_GENL_A_UNSPEC, - DP_GENL_A_DP_IDX, /* Datapath device index. */ - DP_GENL_A_PORTNAME, /* Device name for datapath port. */ - DP_GENL_A_MC_GROUP, /* Generic netlink multicast group. */ - DP_GENL_A_OPENFLOW, /* OpenFlow packet. */ - DP_GENL_A_DP_NAME, /* Datapath device name. */ - - __DP_GENL_A_MAX, - DP_GENL_A_MAX = __DP_GENL_A_MAX - 1 -}; - -/* Commands that can be executed on the datapath's netlink interface. */ -enum dp_genl_command { - DP_GENL_C_UNSPEC, - DP_GENL_C_ADD_DP, /* Create datapath. */ - DP_GENL_C_DEL_DP, /* Destroy datapath. */ - DP_GENL_C_QUERY_DP, /* Get multicast group for datapath. */ - DP_GENL_C_ADD_PORT, /* Add port to datapath. */ - DP_GENL_C_DEL_PORT, /* Remove port from datapath. */ - DP_GENL_C_OPENFLOW, /* Encapsulated OpenFlow protocol. */ - - __DP_GENL_C_MAX, - DP_GENL_C_MAX = __DP_GENL_C_MAX - 1 -}; - -/* Maximum number of datapaths. */ -#define DP_MAX 256 - -#endif /* openflow/openflow-netlink.h */ diff --git a/openflow/include/openflow/openflow.h b/openflow/include/openflow/openflow.h deleted file mode 100644 index c0b5090d..00000000 --- a/openflow/include/openflow/openflow.h +++ /dev/null @@ -1,970 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -/* OpenFlow: protocol between controller and datapath. */ - -#ifndef OPENFLOW_OPENFLOW_H -#define OPENFLOW_OPENFLOW_H 1 - -#ifdef __KERNEL__ -#include -#else -#include -#endif - -#ifdef SWIG -#define OFP_ASSERT(EXPR) /* SWIG can't handle OFP_ASSERT. */ -#elif !defined(__cplusplus) -/* Build-time assertion for use in a declaration context. */ -#define OFP_ASSERT(EXPR) \ - extern int (*build_assert(void))[ sizeof(struct { \ - unsigned int build_assert_failed : (EXPR) ? 1 : -1; })] -#else /* __cplusplus */ -#define OFP_ASSERT(_EXPR) typedef int build_assert_failed[(_EXPR) ? 1 : -1] -#endif /* __cplusplus */ - -#ifndef SWIG -#define OFP_PACKED __attribute__((packed)) -#else -#define OFP_PACKED /* SWIG doesn't understand __attribute. */ -#endif - -/* Version number: - * Non-experimental versions released: 0x01 - * Experimental versions released: 0x81 -- 0x99 - */ -/* The most significant bit being set in the version field indicates an - * experimental OpenFlow version. - */ -#define OFP_VERSION 0x01 - -#define OFP_MAX_TABLE_NAME_LEN 32 -#define OFP_MAX_PORT_NAME_LEN 16 - -#define OFP_TCP_PORT 6633 -#define OFP_SSL_PORT 6633 - -#define OFP_ETH_ALEN 6 /* Bytes in an Ethernet address. */ - -/* Port numbering. Physical ports are numbered starting from 1. */ -enum ofp_port { - /* Maximum number of physical switch ports. */ - OFPP_MAX = 0xff00, - - /* Fake output "ports". */ - OFPP_IN_PORT = 0xfff8, /* Send the packet out the input port. This - virtual port must be explicitly used - in order to send back out of the input - port. */ - OFPP_TABLE = 0xfff9, /* Perform actions in flow table. - NB: This can only be the destination - port for packet-out messages. */ - OFPP_NORMAL = 0xfffa, /* Process with normal L2/L3 switching. */ - OFPP_FLOOD = 0xfffb, /* All physical ports except input port and - those disabled by STP. */ - OFPP_ALL = 0xfffc, /* All physical ports except input port. */ - OFPP_CONTROLLER = 0xfffd, /* Send to controller. */ - OFPP_LOCAL = 0xfffe, /* Local openflow "port". */ - OFPP_NONE = 0xffff /* Not associated with a physical port. */ -}; - -enum ofp_type { - /* Immutable messages. */ - OFPT_HELLO, /* Symmetric message */ - OFPT_ERROR, /* Symmetric message */ - OFPT_ECHO_REQUEST, /* Symmetric message */ - OFPT_ECHO_REPLY, /* Symmetric message */ - OFPT_VENDOR, /* Symmetric message */ - - /* Switch configuration messages. */ - OFPT_FEATURES_REQUEST, /* Controller/switch message */ - OFPT_FEATURES_REPLY, /* Controller/switch message */ - OFPT_GET_CONFIG_REQUEST, /* Controller/switch message */ - OFPT_GET_CONFIG_REPLY, /* Controller/switch message */ - OFPT_SET_CONFIG, /* Controller/switch message */ - - /* Asynchronous messages. */ - OFPT_PACKET_IN, /* Async message */ - OFPT_FLOW_REMOVED, /* Async message */ - OFPT_PORT_STATUS, /* Async message */ - - /* Controller command messages. */ - OFPT_PACKET_OUT, /* Controller/switch message */ - OFPT_FLOW_MOD, /* Controller/switch message */ - OFPT_PORT_MOD, /* Controller/switch message */ - - /* Statistics messages. */ - OFPT_STATS_REQUEST, /* Controller/switch message */ - OFPT_STATS_REPLY, /* Controller/switch message */ - - /* Barrier messages. */ - OFPT_BARRIER_REQUEST, /* Controller/switch message */ - OFPT_BARRIER_REPLY, /* Controller/switch message */ - - /* Queue Configuration messages. */ - OFPT_QUEUE_GET_CONFIG_REQUEST, /* Controller/switch message */ - OFPT_QUEUE_GET_CONFIG_REPLY /* Controller/switch message */ - -}; - -/* Header on all OpenFlow packets. */ -struct ofp_header { - uint8_t version; /* OFP_VERSION. */ - uint8_t type; /* One of the OFPT_ constants. */ - uint16_t length; /* Length including this ofp_header. */ - uint32_t xid; /* Transaction id associated with this packet. - Replies use the same id as was in the request - to facilitate pairing. */ -}; -OFP_ASSERT(sizeof(struct ofp_header) == 8); - -/* OFPT_HELLO. This message has an empty body, but implementations must - * ignore any data included in the body, to allow for future extensions. */ -struct ofp_hello { - struct ofp_header header; -}; - -#define OFP_DEFAULT_MISS_SEND_LEN 128 - -enum ofp_config_flags { - /* Handling of IP fragments. */ - OFPC_FRAG_NORMAL = 0, /* No special handling for fragments. */ - OFPC_FRAG_DROP = 1, /* Drop fragments. */ - OFPC_FRAG_REASM = 2, /* Reassemble (only if OFPC_IP_REASM set). */ - OFPC_FRAG_MASK = 3 -}; - -/* Switch configuration. */ -struct ofp_switch_config { - struct ofp_header header; - uint16_t flags; /* OFPC_* flags. */ - uint16_t miss_send_len; /* Max bytes of new flow that datapath should - send to the controller. */ -}; -OFP_ASSERT(sizeof(struct ofp_switch_config) == 12); - -/* Capabilities supported by the datapath. */ -enum ofp_capabilities { - OFPC_FLOW_STATS = 1 << 0, /* Flow statistics. */ - OFPC_TABLE_STATS = 1 << 1, /* Table statistics. */ - OFPC_PORT_STATS = 1 << 2, /* Port statistics. */ - OFPC_STP = 1 << 3, /* 802.1d spanning tree. */ - OFPC_RESERVED = 1 << 4, /* Reserved, must be zero. */ - OFPC_IP_REASM = 1 << 5, /* Can reassemble IP fragments. */ - OFPC_QUEUE_STATS = 1 << 6, /* Queue statistics. */ - OFPC_ARP_MATCH_IP = 1 << 7 /* Match IP addresses in ARP pkts. */ -}; - -/* Flags to indicate behavior of the physical port. These flags are - * used in ofp_phy_port to describe the current configuration. They are - * used in the ofp_port_mod message to configure the port's behavior. - */ -enum ofp_port_config { - OFPPC_PORT_DOWN = 1 << 0, /* Port is administratively down. */ - - OFPPC_NO_STP = 1 << 1, /* Disable 802.1D spanning tree on port. */ - OFPPC_NO_RECV = 1 << 2, /* Drop all packets except 802.1D spanning - tree packets. */ - OFPPC_NO_RECV_STP = 1 << 3, /* Drop received 802.1D STP packets. */ - OFPPC_NO_FLOOD = 1 << 4, /* Do not include this port when flooding. */ - OFPPC_NO_FWD = 1 << 5, /* Drop packets forwarded to port. */ - OFPPC_NO_PACKET_IN = 1 << 6 /* Do not send packet-in msgs for port. */ -}; - -/* Current state of the physical port. These are not configurable from - * the controller. - */ -enum ofp_port_state { - OFPPS_LINK_DOWN = 1 << 0, /* No physical link present. */ - - /* The OFPPS_STP_* bits have no effect on switch operation. The - * controller must adjust OFPPC_NO_RECV, OFPPC_NO_FWD, and - * OFPPC_NO_PACKET_IN appropriately to fully implement an 802.1D spanning - * tree. */ - OFPPS_STP_LISTEN = 0 << 8, /* Not learning or relaying frames. */ - OFPPS_STP_LEARN = 1 << 8, /* Learning but not relaying frames. */ - OFPPS_STP_FORWARD = 2 << 8, /* Learning and relaying frames. */ - OFPPS_STP_BLOCK = 3 << 8, /* Not part of spanning tree. */ - OFPPS_STP_MASK = 3 << 8 /* Bit mask for OFPPS_STP_* values. */ -}; - -/* Features of physical ports available in a datapath. */ -enum ofp_port_features { - OFPPF_10MB_HD = 1 << 0, /* 10 Mb half-duplex rate support. */ - OFPPF_10MB_FD = 1 << 1, /* 10 Mb full-duplex rate support. */ - OFPPF_100MB_HD = 1 << 2, /* 100 Mb half-duplex rate support. */ - OFPPF_100MB_FD = 1 << 3, /* 100 Mb full-duplex rate support. */ - OFPPF_1GB_HD = 1 << 4, /* 1 Gb half-duplex rate support. */ - OFPPF_1GB_FD = 1 << 5, /* 1 Gb full-duplex rate support. */ - OFPPF_10GB_FD = 1 << 6, /* 10 Gb full-duplex rate support. */ - OFPPF_COPPER = 1 << 7, /* Copper medium. */ - OFPPF_FIBER = 1 << 8, /* Fiber medium. */ - OFPPF_AUTONEG = 1 << 9, /* Auto-negotiation. */ - OFPPF_PAUSE = 1 << 10, /* Pause. */ - OFPPF_PAUSE_ASYM = 1 << 11 /* Asymmetric pause. */ -}; - -/* Description of a physical port */ -struct ofp_phy_port { - uint16_t port_no; - uint8_t hw_addr[OFP_ETH_ALEN]; - char name[OFP_MAX_PORT_NAME_LEN]; /* Null-terminated */ - - uint32_t config; /* Bitmap of OFPPC_* flags. */ - uint32_t state; /* Bitmap of OFPPS_* flags. */ - - /* Bitmaps of OFPPF_* that describe features. All bits zeroed if - * unsupported or unavailable. */ - uint32_t curr; /* Current features. */ - uint32_t advertised; /* Features being advertised by the port. */ - uint32_t supported; /* Features supported by the port. */ - uint32_t peer; /* Features advertised by peer. */ -}; -OFP_ASSERT(sizeof(struct ofp_phy_port) == 48); - -/* Switch features. */ -struct ofp_switch_features { - struct ofp_header header; - uint64_t datapath_id; /* Datapath unique ID. The lower 48-bits are for - a MAC address, while the upper 16-bits are - implementer-defined. */ - - uint32_t n_buffers; /* Max packets buffered at once. */ - - uint8_t n_tables; /* Number of tables supported by datapath. */ - uint8_t pad[3]; /* Align to 64-bits. */ - - /* Features. */ - uint32_t capabilities; /* Bitmap of support "ofp_capabilities". */ - uint32_t actions; /* Bitmap of supported "ofp_action_type"s. */ - - /* Port info.*/ - struct ofp_phy_port ports[0]; /* Port definitions. The number of ports - is inferred from the length field in - the header. */ -}; -OFP_ASSERT(sizeof(struct ofp_switch_features) == 32); - -/* What changed about the physical port */ -enum ofp_port_reason { - OFPPR_ADD, /* The port was added. */ - OFPPR_DELETE, /* The port was removed. */ - OFPPR_MODIFY /* Some attribute of the port has changed. */ -}; - -/* A physical port has changed in the datapath */ -struct ofp_port_status { - struct ofp_header header; - uint8_t reason; /* One of OFPPR_*. */ - uint8_t pad[7]; /* Align to 64-bits. */ - struct ofp_phy_port desc; -}; -OFP_ASSERT(sizeof(struct ofp_port_status) == 64); - -/* Modify behavior of the physical port */ -struct ofp_port_mod { - struct ofp_header header; - uint16_t port_no; - uint8_t hw_addr[OFP_ETH_ALEN]; /* The hardware address is not - configurable. This is used to - sanity-check the request, so it must - be the same as returned in an - ofp_phy_port struct. */ - - uint32_t config; /* Bitmap of OFPPC_* flags. */ - uint32_t mask; /* Bitmap of OFPPC_* flags to be changed. */ - - uint32_t advertise; /* Bitmap of "ofp_port_features"s. Zero all - bits to prevent any action taking place. */ - uint8_t pad[4]; /* Pad to 64-bits. */ -}; -OFP_ASSERT(sizeof(struct ofp_port_mod) == 32); - -/* Why is this packet being sent to the controller? */ -enum ofp_packet_in_reason { - OFPR_NO_MATCH, /* No matching flow. */ - OFPR_ACTION /* Action explicitly output to controller. */ -}; - -/* Packet received on port (datapath -> controller). */ -struct ofp_packet_in { - struct ofp_header header; - uint32_t buffer_id; /* ID assigned by datapath. */ - uint16_t total_len; /* Full length of frame. */ - uint16_t in_port; /* Port on which frame was received. */ - uint8_t reason; /* Reason packet is being sent (one of OFPR_*) */ - uint8_t pad; - uint8_t data[0]; /* Ethernet frame, halfway through 32-bit word, - so the IP header is 32-bit aligned. The - amount of data is inferred from the length - field in the header. Because of padding, - offsetof(struct ofp_packet_in, data) == - sizeof(struct ofp_packet_in) - 2. */ -}; -OFP_ASSERT(sizeof(struct ofp_packet_in) == 20); - -enum ofp_action_type { - OFPAT_OUTPUT, /* Output to switch port. */ - OFPAT_SET_VLAN_VID, /* Set the 802.1q VLAN id. */ - OFPAT_SET_VLAN_PCP, /* Set the 802.1q priority. */ - OFPAT_STRIP_VLAN, /* Strip the 802.1q header. */ - OFPAT_SET_DL_SRC, /* Ethernet source address. */ - OFPAT_SET_DL_DST, /* Ethernet destination address. */ - OFPAT_SET_NW_SRC, /* IP source address. */ - OFPAT_SET_NW_DST, /* IP destination address. */ - OFPAT_SET_NW_TOS, /* IP ToS (DSCP field, 6 bits). */ - OFPAT_SET_TP_SRC, /* TCP/UDP source port. */ - OFPAT_SET_TP_DST, /* TCP/UDP destination port. */ - OFPAT_ENQUEUE, /* Output to queue. */ - OFPAT_VENDOR = 0xffff -}; - -/* Action structure for OFPAT_OUTPUT, which sends packets out 'port'. - * When the 'port' is the OFPP_CONTROLLER, 'max_len' indicates the max - * number of bytes to send. A 'max_len' of zero means no bytes of the - * packet should be sent.*/ -struct ofp_action_output { - uint16_t type; /* OFPAT_OUTPUT. */ - uint16_t len; /* Length is 8. */ - uint16_t port; /* Output port. */ - uint16_t max_len; /* Max length to send to controller. */ -}; -OFP_ASSERT(sizeof(struct ofp_action_output) == 8); - -/* The VLAN id is 12 bits, so we can use the entire 16 bits to indicate - * special conditions. All ones is used to match that no VLAN id was - * set. */ -#define OFP_VLAN_NONE 0xffff - -/* Action structure for OFPAT_SET_VLAN_VID. */ -struct ofp_action_vlan_vid { - uint16_t type; /* OFPAT_SET_VLAN_VID. */ - uint16_t len; /* Length is 8. */ - uint16_t vlan_vid; /* VLAN id. */ - uint8_t pad[2]; -}; -OFP_ASSERT(sizeof(struct ofp_action_vlan_vid) == 8); - -/* Action structure for OFPAT_SET_VLAN_PCP. */ -struct ofp_action_vlan_pcp { - uint16_t type; /* OFPAT_SET_VLAN_PCP. */ - uint16_t len; /* Length is 8. */ - uint8_t vlan_pcp; /* VLAN priority. */ - uint8_t pad[3]; -}; -OFP_ASSERT(sizeof(struct ofp_action_vlan_pcp) == 8); - -/* Action structure for OFPAT_SET_DL_SRC/DST. */ -struct ofp_action_dl_addr { - uint16_t type; /* OFPAT_SET_DL_SRC/DST. */ - uint16_t len; /* Length is 16. */ - uint8_t dl_addr[OFP_ETH_ALEN]; /* Ethernet address. */ - uint8_t pad[6]; -}; -OFP_ASSERT(sizeof(struct ofp_action_dl_addr) == 16); - -/* Action structure for OFPAT_SET_NW_SRC/DST. */ -struct ofp_action_nw_addr { - uint16_t type; /* OFPAT_SET_TW_SRC/DST. */ - uint16_t len; /* Length is 8. */ - uint32_t nw_addr; /* IP address. */ -}; -OFP_ASSERT(sizeof(struct ofp_action_nw_addr) == 8); - -/* Action structure for OFPAT_SET_TP_SRC/DST. */ -struct ofp_action_tp_port { - uint16_t type; /* OFPAT_SET_TP_SRC/DST. */ - uint16_t len; /* Length is 8. */ - uint16_t tp_port; /* TCP/UDP port. */ - uint8_t pad[2]; -}; -OFP_ASSERT(sizeof(struct ofp_action_tp_port) == 8); - -/* Action structure for OFPAT_SET_NW_TOS. */ -struct ofp_action_nw_tos { - uint16_t type; /* OFPAT_SET_TW_SRC/DST. */ - uint16_t len; /* Length is 8. */ - uint8_t nw_tos; /* IP ToS (DSCP field, 6 bits). */ - uint8_t pad[3]; -}; -OFP_ASSERT(sizeof(struct ofp_action_nw_tos) == 8); - -/* Action header for OFPAT_VENDOR. The rest of the body is vendor-defined. */ -struct ofp_action_vendor_header { - uint16_t type; /* OFPAT_VENDOR. */ - uint16_t len; /* Length is a multiple of 8. */ - uint32_t vendor; /* Vendor ID, which takes the same form - as in "struct ofp_vendor_header". */ -}; -OFP_ASSERT(sizeof(struct ofp_action_vendor_header) == 8); - -/* Action header that is common to all actions. The length includes the - * header and any padding used to make the action 64-bit aligned. - * NB: The length of an action *must* always be a multiple of eight. */ -struct ofp_action_header { - uint16_t type; /* One of OFPAT_*. */ - uint16_t len; /* Length of action, including this - header. This is the length of action, - including any padding to make it - 64-bit aligned. */ - uint8_t pad[4]; -}; -OFP_ASSERT(sizeof(struct ofp_action_header) == 8); - -/* Send packet (controller -> datapath). */ -struct ofp_packet_out { - struct ofp_header header; - uint32_t buffer_id; /* ID assigned by datapath (-1 if none). */ - uint16_t in_port; /* Packet's input port (OFPP_NONE if none). */ - uint16_t actions_len; /* Size of action array in bytes. */ - struct ofp_action_header actions[0]; /* Actions. */ - /* uint8_t data[0]; */ /* Packet data. The length is inferred - from the length field in the header. - (Only meaningful if buffer_id == -1.) */ -}; -OFP_ASSERT(sizeof(struct ofp_packet_out) == 16); - -enum ofp_flow_mod_command { - OFPFC_ADD, /* New flow. */ - OFPFC_MODIFY, /* Modify all matching flows. */ - OFPFC_MODIFY_STRICT, /* Modify entry strictly matching wildcards */ - OFPFC_DELETE, /* Delete all matching flows. */ - OFPFC_DELETE_STRICT /* Strictly match wildcards and priority. */ -}; - -/* Flow wildcards. */ -enum ofp_flow_wildcards { - OFPFW_IN_PORT = 1 << 0, /* Switch input port. */ - OFPFW_DL_VLAN = 1 << 1, /* VLAN id. */ - OFPFW_DL_SRC = 1 << 2, /* Ethernet source address. */ - OFPFW_DL_DST = 1 << 3, /* Ethernet destination address. */ - OFPFW_DL_TYPE = 1 << 4, /* Ethernet frame type. */ - OFPFW_NW_PROTO = 1 << 5, /* IP protocol. */ - OFPFW_TP_SRC = 1 << 6, /* TCP/UDP source port. */ - OFPFW_TP_DST = 1 << 7, /* TCP/UDP destination port. */ - - /* IP source address wildcard bit count. 0 is exact match, 1 ignores the - * LSB, 2 ignores the 2 least-significant bits, ..., 32 and higher wildcard - * the entire field. This is the *opposite* of the usual convention where - * e.g. /24 indicates that 8 bits (not 24 bits) are wildcarded. */ - OFPFW_NW_SRC_SHIFT = 8, - OFPFW_NW_SRC_BITS = 6, - OFPFW_NW_SRC_MASK = ((1 << OFPFW_NW_SRC_BITS) - 1) << OFPFW_NW_SRC_SHIFT, - OFPFW_NW_SRC_ALL = 32 << OFPFW_NW_SRC_SHIFT, - - /* IP destination address wildcard bit count. Same format as source. */ - OFPFW_NW_DST_SHIFT = 14, - OFPFW_NW_DST_BITS = 6, - OFPFW_NW_DST_MASK = ((1 << OFPFW_NW_DST_BITS) - 1) << OFPFW_NW_DST_SHIFT, - OFPFW_NW_DST_ALL = 32 << OFPFW_NW_DST_SHIFT, - - OFPFW_DL_VLAN_PCP = 1 << 20, /* VLAN priority. */ - OFPFW_NW_TOS = 1 << 21, /* IP ToS (DSCP field, 6 bits). */ - - /* Wildcard all fields. */ - OFPFW_ALL = ((1 << 22) - 1) -}; - -/* The wildcards for ICMP type and code fields use the transport source - * and destination port fields, respectively. */ -#define OFPFW_ICMP_TYPE OFPFW_TP_SRC -#define OFPFW_ICMP_CODE OFPFW_TP_DST - -/* Values below this cutoff are 802.3 packets and the two bytes - * following MAC addresses are used as a frame length. Otherwise, the - * two bytes are used as the Ethernet type. - */ -#define OFP_DL_TYPE_ETH2_CUTOFF 0x0600 - -/* Value of dl_type to indicate that the frame does not include an - * Ethernet type. - */ -#define OFP_DL_TYPE_NOT_ETH_TYPE 0x05ff - -/* The VLAN id is 12-bits, so we can use the entire 16 bits to indicate - * special conditions. All ones indicates that no VLAN id was set. - */ -#define OFP_VLAN_NONE 0xffff - -/* Fields to match against flows */ -struct ofp_match { - uint32_t wildcards; /* Wildcard fields. */ - uint16_t in_port; /* Input switch port. */ - uint8_t dl_src[OFP_ETH_ALEN]; /* Ethernet source address. */ - uint8_t dl_dst[OFP_ETH_ALEN]; /* Ethernet destination address. */ - uint16_t dl_vlan; /* Input VLAN id. */ - uint8_t dl_vlan_pcp; /* Input VLAN priority. */ - uint8_t pad1[1]; /* Align to 64-bits */ - uint16_t dl_type; /* Ethernet frame type. */ - uint8_t nw_tos; /* IP ToS (actually DSCP field, 6 bits). */ - uint8_t nw_proto; /* IP protocol or lower 8 bits of - * ARP opcode. */ - uint8_t pad2[2]; /* Align to 64-bits */ - uint32_t nw_src; /* IP source address. */ - uint32_t nw_dst; /* IP destination address. */ - uint16_t tp_src; /* TCP/UDP source port. */ - uint16_t tp_dst; /* TCP/UDP destination port. */ -}; -OFP_ASSERT(sizeof(struct ofp_match) == 40); - -/* The match fields for ICMP type and code use the transport source and - * destination port fields, respectively. */ -#define icmp_type tp_src -#define icmp_code tp_dst - -/* Value used in "idle_timeout" and "hard_timeout" to indicate that the entry - * is permanent. */ -#define OFP_FLOW_PERMANENT 0 - -/* By default, choose a priority in the middle. */ -#define OFP_DEFAULT_PRIORITY 0x8000 - -enum ofp_flow_mod_flags { - OFPFF_SEND_FLOW_REM = 1 << 0, /* Send flow removed message when flow - * expires or is deleted. */ - OFPFF_CHECK_OVERLAP = 1 << 1, /* Check for overlapping entries first. */ - OFPFF_EMERG = 1 << 2 /* Remark this is for emergency. */ -}; - -/* Flow setup and teardown (controller -> datapath). */ -struct ofp_flow_mod { - struct ofp_header header; - struct ofp_match match; /* Fields to match */ - uint64_t cookie; /* Opaque controller-issued identifier. */ - - /* Flow actions. */ - uint16_t command; /* One of OFPFC_*. */ - uint16_t idle_timeout; /* Idle time before discarding (seconds). */ - uint16_t hard_timeout; /* Max time before discarding (seconds). */ - uint16_t priority; /* Priority level of flow entry. */ - uint32_t buffer_id; /* Buffered packet to apply to (or -1). - Not meaningful for OFPFC_DELETE*. */ - uint16_t out_port; /* For OFPFC_DELETE* commands, require - matching entries to include this as an - output port. A value of OFPP_NONE - indicates no restriction. */ - uint16_t flags; /* One of OFPFF_*. */ - struct ofp_action_header actions[0]; /* The action length is inferred - from the length field in the - header. */ -}; -OFP_ASSERT(sizeof(struct ofp_flow_mod) == 72); - -/* Why was this flow removed? */ -enum ofp_flow_removed_reason { - OFPRR_IDLE_TIMEOUT, /* Flow idle time exceeded idle_timeout. */ - OFPRR_HARD_TIMEOUT, /* Time exceeded hard_timeout. */ - OFPRR_DELETE /* Evicted by a DELETE flow mod. */ -}; - -/* Flow removed (datapath -> controller). */ -struct ofp_flow_removed { - struct ofp_header header; - struct ofp_match match; /* Description of fields. */ - uint64_t cookie; /* Opaque controller-issued identifier. */ - - uint16_t priority; /* Priority level of flow entry. */ - uint8_t reason; /* One of OFPRR_*. */ - uint8_t pad[1]; /* Align to 32-bits. */ - - uint32_t duration_sec; /* Time flow was alive in seconds. */ - uint32_t duration_nsec; /* Time flow was alive in nanoseconds beyond - duration_sec. */ - uint16_t idle_timeout; /* Idle timeout from original flow mod. */ - uint8_t pad2[2]; /* Align to 64-bits. */ - uint64_t packet_count; - uint64_t byte_count; -}; -OFP_ASSERT(sizeof(struct ofp_flow_removed) == 88); - -/* Values for 'type' in ofp_error_message. These values are immutable: they - * will not change in future versions of the protocol (although new values may - * be added). */ -enum ofp_error_type { - OFPET_HELLO_FAILED, /* Hello protocol failed. */ - OFPET_BAD_REQUEST, /* Request was not understood. */ - OFPET_BAD_ACTION, /* Error in action description. */ - OFPET_FLOW_MOD_FAILED, /* Problem modifying flow entry. */ - OFPET_PORT_MOD_FAILED, /* Port mod request failed. */ - OFPET_QUEUE_OP_FAILED /* Queue operation failed. */ -}; - -/* ofp_error_msg 'code' values for OFPET_HELLO_FAILED. 'data' contains an - * ASCII text string that may give failure details. */ -enum ofp_hello_failed_code { - OFPHFC_INCOMPATIBLE, /* No compatible version. */ - OFPHFC_EPERM /* Permissions error. */ -}; - -/* ofp_error_msg 'code' values for OFPET_BAD_REQUEST. 'data' contains at least - * the first 64 bytes of the failed request. */ -enum ofp_bad_request_code { - OFPBRC_BAD_VERSION, /* ofp_header.version not supported. */ - OFPBRC_BAD_TYPE, /* ofp_header.type not supported. */ - OFPBRC_BAD_STAT, /* ofp_stats_request.type not supported. */ - OFPBRC_BAD_VENDOR, /* Vendor not supported (in ofp_vendor_header - * or ofp_stats_request or ofp_stats_reply). */ - OFPBRC_BAD_SUBTYPE, /* Vendor subtype not supported. */ - OFPBRC_EPERM, /* Permissions error. */ - OFPBRC_BAD_LEN, /* Wrong request length for type. */ - OFPBRC_BUFFER_EMPTY, /* Specified buffer has already been used. */ - OFPBRC_BUFFER_UNKNOWN /* Specified buffer does not exist. */ -}; - -/* ofp_error_msg 'code' values for OFPET_BAD_ACTION. 'data' contains at least - * the first 64 bytes of the failed request. */ -enum ofp_bad_action_code { - OFPBAC_BAD_TYPE, /* Unknown action type. */ - OFPBAC_BAD_LEN, /* Length problem in actions. */ - OFPBAC_BAD_VENDOR, /* Unknown vendor id specified. */ - OFPBAC_BAD_VENDOR_TYPE, /* Unknown action type for vendor id. */ - OFPBAC_BAD_OUT_PORT, /* Problem validating output action. */ - OFPBAC_BAD_ARGUMENT, /* Bad action argument. */ - OFPBAC_EPERM, /* Permissions error. */ - OFPBAC_TOO_MANY, /* Can't handle this many actions. */ - OFPBAC_BAD_QUEUE /* Problem validating output queue. */ -}; - -/* ofp_error_msg 'code' values for OFPET_FLOW_MOD_FAILED. 'data' contains - * at least the first 64 bytes of the failed request. */ -enum ofp_flow_mod_failed_code { - OFPFMFC_ALL_TABLES_FULL, /* Flow not added because of full tables. */ - OFPFMFC_OVERLAP, /* Attempted to add overlapping flow with - * CHECK_OVERLAP flag set. */ - OFPFMFC_EPERM, /* Permissions error. */ - OFPFMFC_BAD_EMERG_TIMEOUT, /* Flow not added because of non-zero idle/hard - * timeout. */ - OFPFMFC_BAD_COMMAND, /* Unknown command. */ - OFPFMFC_UNSUPPORTED /* Unsupported action list - cannot process in - * the order specified. */ -}; - -/* ofp_error_msg 'code' values for OFPET_PORT_MOD_FAILED. 'data' contains - * at least the first 64 bytes of the failed request. */ -enum ofp_port_mod_failed_code { - OFPPMFC_BAD_PORT, /* Specified port does not exist. */ - OFPPMFC_BAD_HW_ADDR, /* Specified hardware address is wrong. */ -}; - -/* ofp_error msg 'code' values for OFPET_QUEUE_OP_FAILED. 'data' contains - * at least the first 64 bytes of the failed request */ -enum ofp_queue_op_failed_code { - OFPQOFC_BAD_PORT, /* Invalid port (or port does not exist). */ - OFPQOFC_BAD_QUEUE, /* Queue does not exist. */ - OFPQOFC_EPERM /* Permissions error. */ -}; - -/* OFPT_ERROR: Error message (datapath -> controller). */ -struct ofp_error_msg { - struct ofp_header header; - - uint16_t type; - uint16_t code; - uint8_t data[0]; /* Variable-length data. Interpreted based - on the type and code. */ -}; -OFP_ASSERT(sizeof(struct ofp_error_msg) == 12); - -enum ofp_stats_types { - /* Description of this OpenFlow switch. - * The request body is empty. - * The reply body is struct ofp_desc_stats. */ - OFPST_DESC, - - /* Individual flow statistics. - * The request body is struct ofp_flow_stats_request. - * The reply body is an array of struct ofp_flow_stats. */ - OFPST_FLOW, - - /* Aggregate flow statistics. - * The request body is struct ofp_aggregate_stats_request. - * The reply body is struct ofp_aggregate_stats_reply. */ - OFPST_AGGREGATE, - - /* Flow table statistics. - * The request body is empty. - * The reply body is an array of struct ofp_table_stats. */ - OFPST_TABLE, - - /* Physical port statistics. - * The request body is struct ofp_port_stats_request. - * The reply body is an array of struct ofp_port_stats. */ - OFPST_PORT, - - /* Queue statistics for a port - * The request body defines the port - * The reply body is an array of struct ofp_queue_stats */ - OFPST_QUEUE, - - /* Vendor extension. - * The request and reply bodies begin with a 32-bit vendor ID, which takes - * the same form as in "struct ofp_vendor_header". The request and reply - * bodies are otherwise vendor-defined. */ - OFPST_VENDOR = 0xffff -}; - -struct ofp_stats_request { - struct ofp_header header; - uint16_t type; /* One of the OFPST_* constants. */ - uint16_t flags; /* OFPSF_REQ_* flags (none yet defined). */ - uint8_t body[0]; /* Body of the request. */ -}; -OFP_ASSERT(sizeof(struct ofp_stats_request) == 12); - -enum ofp_stats_reply_flags { - OFPSF_REPLY_MORE = 1 << 0 /* More replies to follow. */ -}; - -struct ofp_stats_reply { - struct ofp_header header; - uint16_t type; /* One of the OFPST_* constants. */ - uint16_t flags; /* OFPSF_REPLY_* flags. */ - uint8_t body[0]; /* Body of the reply. */ -}; -OFP_ASSERT(sizeof(struct ofp_stats_reply) == 12); - -#define DESC_STR_LEN 256 -#define SERIAL_NUM_LEN 32 -/* Body of reply to OFPST_DESC request. Each entry is a NULL-terminated - * ASCII string. */ -struct ofp_desc_stats { - char mfr_desc[DESC_STR_LEN]; /* Manufacturer description. */ - char hw_desc[DESC_STR_LEN]; /* Hardware description. */ - char sw_desc[DESC_STR_LEN]; /* Software description. */ - char serial_num[SERIAL_NUM_LEN]; /* Serial number. */ - char dp_desc[DESC_STR_LEN]; /* Human readable description of datapath. */ -}; -OFP_ASSERT(sizeof(struct ofp_desc_stats) == 1056); - -/* Body for ofp_stats_request of type OFPST_FLOW. */ -struct ofp_flow_stats_request { - struct ofp_match match; /* Fields to match. */ - uint8_t table_id; /* ID of table to read (from ofp_table_stats), - 0xff for all tables or 0xfe for emergency. */ - uint8_t pad; /* Align to 32 bits. */ - uint16_t out_port; /* Require matching entries to include this - as an output port. A value of OFPP_NONE - indicates no restriction. */ -}; -OFP_ASSERT(sizeof(struct ofp_flow_stats_request) == 44); - -/* Body of reply to OFPST_FLOW request. */ -struct ofp_flow_stats { - uint16_t length; /* Length of this entry. */ - uint8_t table_id; /* ID of table flow came from. */ - uint8_t pad; - struct ofp_match match; /* Description of fields. */ - uint32_t duration_sec; /* Time flow has been alive in seconds. */ - uint32_t duration_nsec; /* Time flow has been alive in nanoseconds beyond - duration_sec. */ - uint16_t priority; /* Priority of the entry. Only meaningful - when this is not an exact-match entry. */ - uint16_t idle_timeout; /* Number of seconds idle before expiration. */ - uint16_t hard_timeout; /* Number of seconds before expiration. */ - uint8_t pad2[6]; /* Align to 64-bits. */ - uint64_t cookie; /* Opaque controller-issued identifier. */ - uint64_t packet_count; /* Number of packets in flow. */ - uint64_t byte_count; /* Number of bytes in flow. */ - struct ofp_action_header actions[0]; /* Actions. */ -}; -OFP_ASSERT(sizeof(struct ofp_flow_stats) == 88); - -/* Body for ofp_stats_request of type OFPST_AGGREGATE. */ -struct ofp_aggregate_stats_request { - struct ofp_match match; /* Fields to match. */ - uint8_t table_id; /* ID of table to read (from ofp_table_stats) - 0xff for all tables or 0xfe for emergency. */ - uint8_t pad; /* Align to 32 bits. */ - uint16_t out_port; /* Require matching entries to include this - as an output port. A value of OFPP_NONE - indicates no restriction. */ -}; -OFP_ASSERT(sizeof(struct ofp_aggregate_stats_request) == 44); - -/* Body of reply to OFPST_AGGREGATE request. */ -struct ofp_aggregate_stats_reply { - uint64_t packet_count; /* Number of packets in flows. */ - uint64_t byte_count; /* Number of bytes in flows. */ - uint32_t flow_count; /* Number of flows. */ - uint8_t pad[4]; /* Align to 64 bits. */ -}; -OFP_ASSERT(sizeof(struct ofp_aggregate_stats_reply) == 24); - -/* Body of reply to OFPST_TABLE request. */ -struct ofp_table_stats { - uint8_t table_id; /* Identifier of table. Lower numbered tables - are consulted first. */ - uint8_t pad[3]; /* Align to 32-bits. */ - char name[OFP_MAX_TABLE_NAME_LEN]; - uint32_t wildcards; /* Bitmap of OFPFW_* wildcards that are - supported by the table. */ - uint32_t max_entries; /* Max number of entries supported. */ - uint32_t active_count; /* Number of active entries. */ - uint64_t lookup_count; /* Number of packets looked up in table. */ - uint64_t matched_count; /* Number of packets that hit table. */ -}; -OFP_ASSERT(sizeof(struct ofp_table_stats) == 64); - -/* Body for ofp_stats_request of type OFPST_PORT. */ -struct ofp_port_stats_request { - uint16_t port_no; /* OFPST_PORT message must request statistics - * either for a single port (specified in - * port_no) or for all ports (if port_no == - * OFPP_NONE). */ - uint8_t pad[6]; -}; -OFP_ASSERT(sizeof(struct ofp_port_stats_request) == 8); - -/* Body of reply to OFPST_PORT request. If a counter is unsupported, set - * the field to all ones. */ -struct ofp_port_stats { - uint16_t port_no; - uint8_t pad[6]; /* Align to 64-bits. */ - uint64_t rx_packets; /* Number of received packets. */ - uint64_t tx_packets; /* Number of transmitted packets. */ - uint64_t rx_bytes; /* Number of received bytes. */ - uint64_t tx_bytes; /* Number of transmitted bytes. */ - uint64_t rx_dropped; /* Number of packets dropped by RX. */ - uint64_t tx_dropped; /* Number of packets dropped by TX. */ - uint64_t rx_errors; /* Number of receive errors. This is a super-set - of more specific receive errors and should be - greater than or equal to the sum of all - rx_*_err values. */ - uint64_t tx_errors; /* Number of transmit errors. This is a super-set - of more specific transmit errors and should be - greater than or equal to the sum of all - tx_*_err values (none currently defined.) */ - uint64_t rx_frame_err; /* Number of frame alignment errors. */ - uint64_t rx_over_err; /* Number of packets with RX overrun. */ - uint64_t rx_crc_err; /* Number of CRC errors. */ - uint64_t collisions; /* Number of collisions. */ -}; -OFP_ASSERT(sizeof(struct ofp_port_stats) == 104); - -/* Vendor extension. */ -struct ofp_vendor_header { - struct ofp_header header; /* Type OFPT_VENDOR. */ - uint32_t vendor; /* Vendor ID: - * - MSB 0: low-order bytes are IEEE OUI. - * - MSB != 0: defined by OpenFlow - * consortium. */ - /* Vendor-defined arbitrary additional data. */ -}; -OFP_ASSERT(sizeof(struct ofp_vendor_header) == 12); - -/* All ones is used to indicate all queues in a port (for stats retrieval). */ -#define OFPQ_ALL 0xffffffff - -/* Min rate > 1000 means not configured. */ -#define OFPQ_MIN_RATE_UNCFG 0xffff - -enum ofp_queue_properties { - OFPQT_NONE = 0, /* No property defined for queue (default). */ - OFPQT_MIN_RATE, /* Minimum datarate guaranteed. */ - /* Other types should be added here - * (i.e. max rate, precedence, etc). */ -}; - -/* Common description for a queue. */ -struct ofp_queue_prop_header { - uint16_t property; /* One of OFPQT_. */ - uint16_t len; /* Length of property, including this header. */ - uint8_t pad[4]; /* 64-bit alignemnt. */ -}; -OFP_ASSERT(sizeof(struct ofp_queue_prop_header) == 8); - -/* Min-Rate queue property description. */ -struct ofp_queue_prop_min_rate { - struct ofp_queue_prop_header prop_header; /* prop: OFPQT_MIN, len: 16. */ - uint16_t rate; /* In 1/10 of a percent; >1000 -> disabled. */ - uint8_t pad[6]; /* 64-bit alignment */ -}; -OFP_ASSERT(sizeof(struct ofp_queue_prop_min_rate) == 16); - -/* Full description for a queue. */ -struct ofp_packet_queue { - uint32_t queue_id; /* id for the specific queue. */ - uint16_t len; /* Length in bytes of this queue desc. */ - uint8_t pad[2]; /* 64-bit alignment. */ - struct ofp_queue_prop_header properties[0]; /* List of properties. */ -}; -OFP_ASSERT(sizeof(struct ofp_packet_queue) == 8); - -/* Query for port queue configuration. */ -struct ofp_queue_get_config_request { - struct ofp_header header; - uint16_t port; /* Port to be queried. Should refer - to a valid physical port (i.e. < OFPP_MAX) */ - uint8_t pad[2]; /* 32-bit alignment. */ -}; -OFP_ASSERT(sizeof(struct ofp_queue_get_config_request) == 12); - -/* Queue configuration for a given port. */ -struct ofp_queue_get_config_reply { - struct ofp_header header; - uint16_t port; - uint8_t pad[6]; - struct ofp_packet_queue queues[0]; /* List of configured queues. */ -}; -OFP_ASSERT(sizeof(struct ofp_queue_get_config_reply) == 16); - -/* OFPAT_ENQUEUE action struct: send packets to given queue on port. */ -struct ofp_action_enqueue { - uint16_t type; /* OFPAT_ENQUEUE. */ - uint16_t len; /* Len is 16. */ - uint16_t port; /* Port that queue belongs. Should - refer to a valid physical port - (i.e. < OFPP_MAX) or OFPP_IN_PORT. */ - uint8_t pad[6]; /* Pad for 64-bit alignment. */ - uint32_t queue_id; /* Where to enqueue the packets. */ -}; -OFP_ASSERT(sizeof(struct ofp_action_enqueue) == 16); - -struct ofp_queue_stats_request { - uint16_t port_no; /* All ports if OFPT_ALL. */ - uint8_t pad[2]; /* Align to 32-bits. */ - uint32_t queue_id; /* All queues if OFPQ_ALL. */ -}; -OFP_ASSERT(sizeof(struct ofp_queue_stats_request) == 8); - -struct ofp_queue_stats { - uint16_t port_no; - uint8_t pad[2]; /* Align to 32-bits. */ - uint32_t queue_id; /* Queue i.d */ - uint64_t tx_bytes; /* Number of transmitted bytes. */ - uint64_t tx_packets; /* Number of transmitted packets. */ - uint64_t tx_errors; /* Number of packets dropped due to overrun. */ -}; -OFP_ASSERT(sizeof(struct ofp_queue_stats) == 32); - -#endif /* openflow/openflow.h */ diff --git a/openflow/include/openflow/private-ext.h b/openflow/include/openflow/private-ext.h deleted file mode 100644 index 61fc8fb0..00000000 --- a/openflow/include/openflow/private-ext.h +++ /dev/null @@ -1,68 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#ifndef OPENFLOW_PRIVATE_EXT_H_ -#define OPENFLOW_PRIVATE_EXT_H_ - -#ifdef __KERNEL__ -#include -#endif - -#include "openflow/openflow.h" - -/* - * The following PRIVATE vendor extensions are just sample and may never be - * ready for standardization, so they are not included in openflow.h. - * - * As a sample, we use private OUI (AC-DE-48) for PRIVATE vendor ID. - */ - -#define PRIVATE_VENDOR_ID 0x00acde48 -#define PRIVATEOPT_PROTOCOL_STATS_REQUEST 0x0001 -#define PRIVATEOPT_PROTOCOL_STATS_REPLY 0x0002 -#define PRIVATEOPT_EMERG_FLOW_PROTECTION 0x0003 -#define PRIVATEOPT_EMERG_FLOW_RESTORATION 0x0004 - -struct private_vxhdr { - struct ofp_header ofp_hdr; /* protocol header */ - uint32_t ofp_vxid; /* vendor extenion ID */ -} __attribute__ ((__packed__)); - -/* TLV encoding */ -struct private_vxopt { - uint16_t pvo_type; /* type of vendor extension option */ - uint16_t pvo_len; /* length of value (octet) */ - /* followed by value */ - /* uint8_t pvo_value[0]; */ -} __attribute__ ((__packed__)); - -#endif diff --git a/openflow/m4/libopenflow.m4 b/openflow/m4/libopenflow.m4 deleted file mode 100644 index 58014ed5..00000000 --- a/openflow/m4/libopenflow.m4 +++ /dev/null @@ -1,168 +0,0 @@ -# -*- autoconf -*- - -# Copyright (c) 2008 The Board of Trustees of The Leland Stanford -# Junior University -# -# We are making the OpenFlow specification and associated documentation -# (Software) available for public use and benefit with the expectation -# that others will use, modify and enhance the Software and contribute -# those enhancements back to the community. However, since we would -# like to make the Software available for broadest use, with as few -# restrictions as possible permission is hereby granted, free of -# charge, to any person obtaining a copy of this Software to deal in -# the Software under the copyrights without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# -# The name and trademarks of copyright holder(s) may NOT be used in -# advertising or publicity pertaining to the Software or any -# derivatives without specific, written prior permission. - -dnl Checks for --enable-ndebug and defines NDEBUG if it is specified. -AC_DEFUN([OFP_CHECK_NDEBUG], - [AC_ARG_ENABLE( - [ndebug], - [AC_HELP_STRING([--enable-ndebug], - [Disable debugging features for max performance])], - [case "${enableval}" in - (yes) ndebug=true ;; - (no) ndebug=false ;; - (*) AC_MSG_ERROR([bad value ${enableval} for --enable-ndebug]) ;; - esac], - [ndebug=false]) - AM_CONDITIONAL([NDEBUG], [test x$ndebug = xtrue])]) - -dnl Checks for Netlink support. -AC_DEFUN([OFP_CHECK_NETLINK], - [AC_CHECK_HEADER([linux/netlink.h], - [HAVE_NETLINK=yes], - [HAVE_NETLINK=no], - [#include - #include - ]) - AM_CONDITIONAL([HAVE_NETLINK], [test "$HAVE_NETLINK" = yes]) - if test "$HAVE_NETLINK" = yes; then - AC_DEFINE([HAVE_NETLINK], [1], - [Define to 1 if Netlink protocol is available.]) - fi]) - -dnl Checks for OpenSSL, if --enable-ssl is passed in. -AC_DEFUN([OFP_CHECK_OPENSSL], - [AC_ARG_ENABLE( - [ssl], - [AC_HELP_STRING([--enable-ssl], - [Enable ssl support (requires libssl)])], - [case "${enableval}" in - (yes) ssl=true ;; - (no) ssl=false ;; - (*) AC_MSG_ERROR([bad value ${enableval} for --enable-ssl]) ;; - esac], - [ssl=false]) - - if test "$ssl" = true; then - dnl Make sure that pkg-config is installed. - m4_pattern_forbid([PKG_CHECK_MODULES]) - PKG_CHECK_MODULES([SSL], [libssl], - [HAVE_OPENSSL=yes], - [HAVE_OPENSSL=no - AC_MSG_WARN([Cannot find libssl: - - $SSL_PKG_ERRORS - - OpenFlow will not support SSL connections.])]) - - fi - AM_CONDITIONAL([HAVE_OPENSSL], [test "$HAVE_OPENSSL" = yes]) - if test "$HAVE_OPENSSL" = yes; then - AC_DEFINE([HAVE_OPENSSL], [1], [Define to 1 if OpenSSL is installed.]) - fi]) - -dnl Checks for libraries needed by lib/fault.c. -AC_DEFUN([OFP_CHECK_FAULT_LIBS], - [AC_CHECK_LIB([dl], [dladdr], [FAULT_LIBS=-ldl]) - AC_SUBST([FAULT_LIBS])]) - -dnl Checks for libraries needed by lib/socket-util.c. -AC_DEFUN([OFP_CHECK_SOCKET_LIBS], - [AC_CHECK_LIB([socket], [connect]) - AC_SEARCH_LIBS([gethostbyname], [resolv], [RESOLVER_LIBS=-lresolv])]) - -dnl Checks for the directory in which to store the PKI. -AC_DEFUN([OFP_CHECK_PKIDIR], - [AC_ARG_WITH( - [pkidir], - AC_HELP_STRING([--with-pkidir=DIR], - [PKI hierarchy directory [[DATADIR/openflow/pki]]]), - [PKIDIR=$withval], - [PKIDIR='${pkgdatadir}/pki']) - AC_SUBST([PKIDIR])]) - -dnl Checks for the directory in which to store pidfiles. -AC_DEFUN([OFP_CHECK_RUNDIR], - [AC_ARG_WITH( - [rundir], - AC_HELP_STRING([--with-rundir=DIR], - [directory used for pidfiles [[LOCALSTATEDIR/run]]]), - [RUNDIR=$withval], - [RUNDIR='${localstatedir}/run']) - AC_SUBST([RUNDIR])]) - -dnl Checks for the directory in which to store logs. -AC_DEFUN([OFP_CHECK_LOGDIR], - [AC_ARG_WITH( - [logdir], - AC_HELP_STRING([--with-logdir=DIR], - [directory used for logs [[LOCALSTATEDIR/log/PACKAGE]]]), - [LOGDIR=$withval], - [LOGDIR='${localstatedir}/log/${PACKAGE}']) - AC_SUBST([LOGDIR])]) - -dnl Checks for __malloc_hook, etc., supported by glibc. -AC_DEFUN([OFP_CHECK_MALLOC_HOOKS], - [AC_CACHE_CHECK( - [whether libc supports hooks for malloc and related functions], - [ofp_cv_malloc_hooks], - [AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM( - [#include - ], - [(void) __malloc_hook; - (void) __realloc_hook; - (void) __free_hook;])], - [ofp_cv_malloc_hooks=yes], - [ofp_cv_malloc_hooks=no])]) - if test $ofp_cv_malloc_hooks = yes; then - AC_DEFINE([HAVE_MALLOC_HOOKS], [1], - [Define to 1 if you have __malloc_hook, __realloc_hook, and - __free_hook in .]) - fi]) - -dnl Runs the checks required to include the headers in include/ and -dnl link against lib/libopenflow.a. -AC_DEFUN([OFP_CHECK_LIBOPENFLOW], - [AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS]) - AC_REQUIRE([OFP_CHECK_NDEBUG]) - AC_REQUIRE([OFP_CHECK_NETLINK]) - AC_REQUIRE([OFP_CHECK_OPENSSL]) - AC_REQUIRE([OFP_CHECK_FAULT_LIBS]) - AC_REQUIRE([OFP_CHECK_SOCKET_LIBS]) - AC_REQUIRE([OFP_CHECK_PKIDIR]) - AC_REQUIRE([OFP_CHECK_RUNDIR]) - AC_REQUIRE([OFP_CHECK_LOGDIR]) - AC_REQUIRE([OFP_CHECK_MALLOC_HOOKS]) - AC_CHECK_FUNCS([strlcpy])]) - diff --git a/openflow/m4/nx-build.m4 b/openflow/m4/nx-build.m4 deleted file mode 100644 index d681cecc..00000000 --- a/openflow/m4/nx-build.m4 +++ /dev/null @@ -1,71 +0,0 @@ -# -*- autoconf -*- - -# Copyright (c) 2008 The Board of Trustees of The Leland Stanford -# Junior University -# -# We are making the OpenFlow specification and associated documentation -# (Software) available for public use and benefit with the expectation -# that others will use, modify and enhance the Software and contribute -# those enhancements back to the community. However, since we would -# like to make the Software available for broadest use, with as few -# restrictions as possible permission is hereby granted, free of -# charge, to any person obtaining a copy of this Software to deal in -# the Software under the copyrights without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# -# The name and trademarks of copyright holder(s) may NOT be used in -# advertising or publicity pertaining to the Software or any -# derivatives without specific, written prior permission. - -dnl NX_BUILDNR -dnl -dnl If --with-build-number=NUMBER is used, substitutes a Makefile -dnl variable BUILDNR with NUMBER, and sets a C preprocessor variable -dnl BUILDNR to "+buildNUMBER". -dnl -dnl Otherwise, if --with-build-number is not used, substitutes BUILDNR -dnl with 0 and sets C preprocessor variable BUILDNR to "". -AC_DEFUN([NX_BUILDNR], - [AC_ARG_WITH( - [build-number], - [AS_HELP_STRING([--with-build-number=NUMBER], - [Official build number (default is none)])]) - AC_MSG_CHECKING([build number]) - case $with_build_number in # ( - [[0-9]] | \ - [[0-9]][[0-9]] | \ - [[0-9]][[0-9]][[0-9]] | \ - [[0-9]][[0-9]][[0-9]][[0-9]] | \ - [[0-9]][[0-9]][[0-9]][[0-9]][[0-9]]) - BUILDNR=$with_build_number - buildnr='"+build'$BUILDNR'"' - AC_MSG_RESULT([$with_build_number]) - ;; # ( - ''|no) - BUILDNR=0 - buildnr='""' - AC_MSG_RESULT([none]) - ;; # ( - *) - AC_MSG_ERROR([invalid build number $with_build_number]) - ;; - esac - AC_SUBST([BUILDNR]) - AC_DEFINE_UNQUOTED([BUILDNR], [$buildnr], - [Official build number as a VERSION suffix string, e.g. "+build123", - or "" if this is not an official build.])]) diff --git a/openflow/regress/CREDITS b/openflow/regress/CREDITS deleted file mode 100644 index 987380af..00000000 --- a/openflow/regress/CREDITS +++ /dev/null @@ -1,22 +0,0 @@ -Credit goes to those who contributed code to the regression suite. Unless -otherwise noted, the contributors are at Stanford University. - - -Test writers/editors: - Clay Collier - David Erickson - Mikio Hara (NEC) - Brandon Heller - Peyman Kazemian - Masayoshi Kobayashi (NEC) - Bob Lantz - Brandon Nefcy - Rob Sherwood (Deutsche Telekom R&D Labs) - Jean Tourrilhes (HP Labs) - Tatsuya Yabe (NEC) - Yiannis Yiakoumis - -Supporting libraries: - Adam Covington - Glen Gibb - Jad Naous diff --git a/openflow/regress/INSTALL b/openflow/regress/INSTALL deleted file mode 100644 index 4ddad72f..00000000 --- a/openflow/regress/INSTALL +++ /dev/null @@ -1,264 +0,0 @@ - Installation Instructions for OpenFlow Reference Tests - -This document describes how to install and execute the OpenFlow reference test -suite, which provides an automated way to verify that an OpenFlow switch -adheres to the OpenFlow Protocol. Out of the box, tests work with the OpenFlow -Reference Linux Switch, but can support other platforms by defining custom -setup and teardown scripts. Additional tests verify the reference learning -Ethernet switch controller included with the OpenFlow Reference Linux Switch. - -Please send any comments to: - - - -=== Prerequisites === - -The tests require no other packets to be sent on the testing interfaces. -Built-in programs like avahi-daemon and/or network-manager may send packets, -causing the tests to report failure. The simplest way to remove these packets -is to disable the ipv6 module and reboot, as well as remove avahi-daemon. - -All test configurations require the following Perl modules: - perl-Convert-Binary-C - perl-Data-HexDump - perl-Net-Pcap (perl-Net-Pcap-0.16-1) - perl-Net-RawIP.i386 (perl-Net-RawIP-0.23-1) - perl-Error.noarch (perl-Error-0.17012-1) - -These packages can be installed from source via www.cpan.org, or you can use -pre-built packages (much faster!). - -The code has been tested on CentOS 5.1/5.2, Ubuntu Hardy Heron, and Debian -Unstable under the following configurations. - -** Config 1 - Four virtual Ethernet loopback pairs - -To set these up, you must have a kernel version >= 2.6.24 and the veth kernel -module compiled. - -To set up link pairs, you must also have iproute installed. - -Scripts to simplify this are included in bin/: --bin/veth_setup.pl --bin/veth_teardown.pl - -Before running any veth tests, make sure to run bin/veth_setup.pl, which will -create interfaces veth{0..7}. The usual ports of eth{1..8} are remapped to these -ports via the file veth.map in /bin/. To remove these interfaces, run -bin/veth_teardown.pl - -** Config 2 - Two quad-port Ethernet NICs connected by physical loopback cables - -Assign ports as eth{1..8} and connect cables as: - eth1 to eth5 - eth2 to eth6 - eth3 to eth7 - eth4 to eth8 - -** Config 3 - Four local ethernet ports connected to external switch - -A third configuration is to use four ports of Ethernet on the test machine, -connected to an external switch. To do this, you must provide custom setup -and teardown scripts that enable/disable OpenFlow on the external switch via -SSH, telnet, or SNMP. See the scripts in bin/ for examples of how to create -these. - -** Config 4 - One quad-port Ethernet NIC connected to a NetFPGA - -This testing configuration is used to verify the NetFPGA's OpenFlow -functionality. It requires 4 ports of Ethernet connected to corresponding ports -on the NetFPGA in the following arrangement: - eth1 to nf2c0 - eth2 to nf2c1 - eth3 to nf2c2 - eth4 to nf2c3 - -This test also assumes that you have correctly installed the NetFPGA ahead of -time. For further information about the NetFPGA please see -http://www.netfpga.org/ - -Of particular note, by default installing the NetFPGA also puts the -NF2/lib/Perl5 directory into your PERL5LIB environment variable, this must be -removed else the tests will fail. Ensure that your PERL5LIB only contains the -path set by the env_vars file that will be discussed later in this document. - - -=== Ubuntu Quickstart === - -Follow these instructions to quickly create a VM or physical machine with -OpenFlow that runs the tests. - -Ubuntu is recommended because it is based on Debian sources and has a recent -kernel version - which removes the need for some steps. - -If installing as a VM, you'll need to install VMWare Server (Windows/Linux, -free) or VMWare Fusion (Mac, $$$). - -Download the Ubuntu 8.04 Desktop or Server ISO, and install Ubuntu. - -If you prefer, install VMWare Tools to enable better mouse and display support. -Alternately, install SSH and use it for the rest of the instructions: - sudo apt-get install ssh -Install GCC, which is required for OpenFlow: - sudo apt-get install gcc -Download and untar OpenFlow v0.8.1 - wget http://openflowswitch.org/downloads/openflow-v0.8.1.tar.gz - tar xzf openflow-v0.8.1.tar.gz -Build OpenFlow user-space and kernel-space switches: - cd openflow-v0.8.1 - ./configure --with-l26=/lib/modules/`uname -r` - make - sudo make install -Now, download and untar the OpenFlow Test Suite: - wget http://openflowswitch.org/downloads/openflow-test-v0.8.1-r2.tar.gz -Install required packages for the test suite: - sudo apt-get install liberror-perl libio-interface-perl liblist-moreutils-perl libpcap0.8-dev -Download the following: - wget http://search.cpan.org/CPAN/authors/id/S/SA/SAPER/Net-Pcap-0.14.tar.gz - wget http://search.cpan.org/CPAN/authors/id/S/SZ/SZABGAB/Net-RawIP-0.21.tar.gz - wget http://search.cpan.org/CPAN/authors/id/M/MH/MHX/Convert-Binary-C-0.71.tar.gz - wget http://search.cpan.org/CPAN/authors/id/F/FT/FTASSIN/Data-HexDump-0.02.tar.gz -For each package: - tar xzf - cd - perl Makefile.PL - make - make install -Remove avahi-daemon, which often causes tests to fail by sending out messages: - sudo apt-get remove avahi-daemon -Create a root password, to be used later: - sudo passwd root - -From here, skip to the Running The Tests section below. - - -=== CentOS 5.2 === - -First, download and verify you can build the current version of OpenFlow. - -Install the RPMForge repository: - wget http://dag.wieers.com/rpm/packages/rpmforge-release/rpmforge-release-0.3.6-1.el5.rf.i386.rpm - rpm -Uhv rpmforge-release-0.3.6-1.el5.rf.i386.rpm - -Install Perl packages: - yum -y install perl-Convert-Binary-C perl-Data-HexDump perl-Net-Pcap perl-Net-RawIP.i386 perl-Error.noarch - -To run tests with Veth pairs, you'll need to upgrade to a newer version of the kernel. - -Install iproute: - yum -y install iproute - -From here, skip to the Running The Tests section below. - -=== Debian Install === - -These instructions derive from http://netfpga.org/netfpgawiki/index.php/Ubuntu_Compatibility - -Some instructions may no longer be necessary. - -*The version of libnet-pcap-perl that Debian and Ubuntu 6.06/7.04/7.10 provides is ANCIENT (version 0.04). The latest stable version is 0.14. No newer version is available as a package, so we must build it ourselves. -*The version of libpcap that Debian and Ubuntu 7.04 provides by default is old (version 0.72). The latest stable version is 0.9.8. Fortunately, the package manager has a newer version called "libpcap0.8" that is really version 0.9.5 -*Remove old packages / install new ones - -May not be necessary: - apt-get remove libpcap0.7 libpcap0.7-dev libpcap-dev libnet-pcap-perl - -Will be necessary: - apt-get install liberror-perl libio-interface-perl liblist-moreutils-perl libpcap0.8 libpcap0.8-dev psmisc -Listed individually: - apt-get install liberror-perl - apt-get install libio-interface-perl (Used to manually build a newer version of Net::PCap) - apt-get install liblist-moreutils-perl (Used to manually build a newer version of Net::RawIP) - apt-get install libpcap0.8 - apt-get install libpcap0.8-dev - apt-get install psmisc (Used to get killall) - -Required packages have Debian versions at packages.debian.org, however these packages may not be the newest, or not exist at all. libnet-rawip-perl and libnet-pacp-perl may work, but have not been tested. We'll manually install these two packages: -http://search.cpan.org/~saper/Net-Pcap-0.14/Pcap.pm -http://search.cpan.org/~szabgab/Net-RawIP-0.21/lib/Net/RawIP.pm -http://search.cpan.org/dist/Convert-Binary-C/lib/Convert/Binary/C.pm -http://search.cpan.org/dist/Data-HexDump/lib/Data/HexDump.pm - -Download the following: - wget http://search.cpan.org/CPAN/authors/id/S/SA/SAPER/Net-Pcap-0.14.tar.gz - wget http://search.cpan.org/CPAN/authors/id/S/SZ/SZABGAB/Net-RawIP-0.21.tar.gz - wget http://search.cpan.org/CPAN/authors/id/M/MH/MHX/Convert-Binary-C-0.71.tar.gz - wget http://search.cpan.org/CPAN/authors/id/F/FT/FTASSIN/Data-HexDump-0.02.tar.gz -For each package: - tar xzf - cd - perl Makefile.PL - make - make install - -Install if you want to use veth pairs: - apt-get install iproute - -=== Running the Tests === - -In the sections below, {platform} refers to: -user -user_veth -kmod -kmod_veth -nf2 - -First copy the env_vars file to your home directory: - cd ~/ - cp /regress/scripts/env_vars . - -Update the OF_ROOT (openflow) environment variable to point to your OpenFlow -directory in your setup. These exports can also be added to your ~/.bashrc -file to load automatically: - vim env_vars - -Enter a root shell session, or set up sudo. The perl-Net-RawIP library requires -root access to bind to ports. - su - -Source the environment variables: - source env_vars - -For a setup with virtual ethernet pairs, set them up: - veth_setup.pl - -Verify your setup by running regression tests on your platform of choice: - of_{platform}_test.pl -For the user-space switch, the tests should show pass for all scripts except -the _X_controller ones. For the kernel-space switch, all tests should pass. - -To see more options for the regression script, type: - of_{platform}_test.pl --help - -== Writing Your Own Tests == - -Look at an example controller test: - vim /regress/projects/learning_switch/regress/test_unicast_unknown/run.pl - -Look at an example black box switch test: - vim /regress/projects/black_box/regress/test_hello/run.pl - -To run an individual test (learning switch example): - cd /regres/projects/learning_switch/regress/test_unicast_unknown - of_{platform}_setup.pl; ./run.pl; of_{platform}_teardown.pl - -To see traffic when running a black box test, use tcpdump. Secchan and the -Perl code use the loopback interface to communicate, and you can snoop on this: - tcpdump -X -i lo -s 256 - -It can be convenient to run your test in isolation, without setup and teardown -automatically called. To set up the OF kmod and interfaces, run: - of_{platform}_setup.pl - -To remove the OF kmod cleanly, run: - of_{platform}_teardown.pl -Note that the kmod refuses removal until the interfaces and datapaths have been removed. - -== Reporting Bugs == - -Please report problems to: -openflow-discuss@openflowswitch.org - -or post them directly to our bug tracking system: - -http://www.openflowswitch.org/bugs/openflow diff --git a/openflow/regress/LICENSE b/openflow/regress/LICENSE deleted file mode 100644 index b9e21768..00000000 --- a/openflow/regress/LICENSE +++ /dev/null @@ -1,30 +0,0 @@ -Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior -University - - -We are making the OpenFlow tests and associated documentation (Software) -available for public use and benefit with the expectation that others will -use, modify and enhance the Software and contribute those enhancements back -to the community. However, since we would like to make the Software -available for broadest use, with as few restrictions as possible permission -is hereby granted, free of charge, to any person obtaining a copy of this -Software) to deal in the Software under the copyrights without restriction, -including without limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to the -following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. - -The name and trademarks of copyright holder(s) may NOT be used in -advertising or publicity pertaining to the Software or any derivatives -without specific, written prior permission. diff --git a/openflow/regress/README b/openflow/regress/README deleted file mode 100644 index a27967fb..00000000 --- a/openflow/regress/README +++ /dev/null @@ -1,329 +0,0 @@ - OpenFlow Reference Tests - -What's here? ------------- - -This distribution includes: - - - 55+ "black box" tests to verify that an OF switch conforms to the - OF protocol 0x01 - - - 7 tests to verify that the reference controller acts as a learning - Ethernet switch - -The tests are intended to simplify the process of creating an OF switch -that conforms to spec. - -Please see INSTALL for instruction on installing and running the tests. - -Changelog ---------------- -1.0.0-r1 - - Added Open vSwitch scripts : kernel + user + interface maps - - Added VETH scripts for Open vSwitch : kernel + user - - Updated HP-ProCurve scipts : 5400/3500 and 6600 - - Assorted fixes to libraries : - accept port > 10 - accept vlan interfaces - more explicit error messages - - Assorted fixes to tests : - test_switch_config/ -> add delay - test_forward_broadcast_exact_port/ -> run for allports - test_set_n_match_nw_tos/ -> fixup nw_tos usage - test_set_nw_dst/ -> cleanup - test_failover_startup/ -> argv parsing was broken - - Add new test : test_set_dl_nw_flip -> flip dl & nw addresses - - Add new command line options : no_vlan, no_slicing and no_barrier, - no_emerg - - Add ability to run a single test with --testPath - - New debugging function : dpctl_show_flows - -1.0.0 - - all tests updated to OpenFlow wire protocol 0x01 - - added tests for new features in the OpenFlow 1.0.0 spec - -0.9.0 - - all tests updated to OpenFlow wire protocol 0x98 - -v0.8.2 - - Added support for the NetFPGA - - Integrated the tests into the OpenFlow directory structure - -v0.8.1-r2 - - refactored code to make new test ports easier - - fixed documentation bug in test_LLC - - changed all interfaces IPs to 192.168.20X.X to not conflict with the - IP addrs typically assigned via DHCP by home routers - - added easy support for testing user-space switch with physical ports - - added easy support for user-space switch with virtual ports - -v0.8.1-r1 - - added instructions for Debian install - - fixed timing bug in packet_out - -v0.8.1-r0 - - all tests updated to OF spec v0.8.1 - - added black box test switch_config - - fixed timing dependence in learning switch tests - -v0.2.1 - - initial release for OF spec v0.5.1, code tested for ref OF code v0.2.1 - -Platform support ----------------- - -The code is written in Perl5, and should in theory work on any system. -It has been tested with CentOS 5.4, Ubuntu 9.10, Fedora Core 12, and Debian Unstable. - -Learning Switch Tests ----------------- - -Two tests currently fail with OF Reference v0.8.1: - --Unicast, send to self: the switch is forwarding packets with source and destination on the same port to that port instead of dropping it. - --Unicast, hub connected:the switch is forwarding traffic to the same port it has came out of, although the source and destination are on the same port and switch already knows about that. - -Both failing tests can be re-activated by changing -projects/learning_switch/regress/tests.txt - -=== Unicast, unknown dest === -:; Name: test_unicast_unknown -:; Owner: Peyman -:; Description -::send packet out p0 to unknown MAC addr -::verify unmodified packet received at p1..p3 -::verify counters incremented - -=== Unicast, known dest === -:; Name: test_unicast_known -:; Owner: Peyman -:; Description: Send to known unicast address, verify switch sent to only one port -::send out p0 to p1 -::verify received at p1..p3 -::send out p1 to p0 -::verify received at p0, NOT p2, p3 -::send out p2 to p0 -::verify received at p0, NOT p1, p3 -::send out p3 to p0 -::verify received at p0, NOT p1, p2 -::verify counters - -=== Broadcast === -:; Name: test_broadcast -:; Owner: Peyman -:; Description: Send to broadcast address, verify received on all ports -::send out p0 to all -::verify received at p1..p3 -::send out p0 to all, again -::verify received at p1..p3, again -::repeat for each port -::verify counters - -=== Unicast, send to self === -:; Name: test_unicast_self -:; Owner: Peyman -:; Description: Send to self, verify dropped - -=== Unicast, change attachment point === -:; Name: test_unicast_move -:; Owner: Peyman -:; Description: Send normal unicast, but then change attachment point (one MAC sent from multiple ports), verify that new location is used -::send form host A at p0 to p1 -::verify received at p1..p3 -::send from p1 to host A -::verify received at p0, NOT p1, p2, p3 -::(original p0 has now moves to p2) -::send from host A (currently at p2) to p1 -::verify received at p1, NOT p0, p2, p3 -::send from p1 to Host A (currently at p2) -::verify received p2, NOT p0, p1, p3 - -=== Unicast, hub connected === -:; Name: test_hub_connected -:; Owner: Peyman -:; Description: if a port connects to a hub, we may receive traffic for which the sender and receiver are connected to the same port. This traffic should be dropped. - -=== Unicast, multiple hosts per port === -:; Name: test_unicast_multiple_hosts -:; Owner: Peyman -:; Description: assume each port is connected to a switch, so that each port receives traffic from multiple MAC addresses - say, 20 per port. Other than multiple MAC addrs per port, this is just like test_unicast_known. Each port sends to a host at a different port. - - -Black Box Tests ----------------- - -One test currently fails with the OF Reference v0.8.1 kmod: - --LLC: Pkt is forwarded to the controller, when it should be dropped. - -Two tests are currently failing with the OF Reference v0.8.1 user-space switch: - --test_forward_exact_controller --test_forward_wildcard_controller - -All failing tests can be re-activated by changing -projects/black_box/regress/tests.txt - -== Basic Functionality == - -=== Hello === -:; Name: test_hello -:; Owner: Brandon Heller -:; Description: send hello packet to switch, verify reply with correct params - -=== Send from Switch to Controller === -:; Name: test_packet_in -:; Owner: Brandon Heller -:; Description: send packet from switch to SC, verify it is received at the controller - -=== Send from Controller to Switch === -:; Name: test_packet_out -:; Owner: Brandon Heller -:; Description: send packet to switch on secure chan for each output port, ensure packet received at proper ports. - -=== Switch Config === -:; Name: test_switch_config -:; Owner: Brandon Heller -:; Description: verify default switch config, set config, verify that config has changed -:; Status: done - -=== Flow Expired === -:; Name: test_flow_expired -:; Owner: Brandon Heller -:; Description: send add flow message for short timeout, verify no error message received, plus flow timeout message received within time bounds -::send a second add flow message and keep it active with packets; verify that flow expires only if idle - -=== Miss Send Length === -:; Name: test_miss_send_length -:; Owner: Brandon Heller -:; Description: get the miss send length from the hello message, then send a packet to switch, verify correct length for forwarded chunk of packet - -== Modify State Tests == - -=== Forward Any Port === -:; Name: test_forward_any_port -:; Owner: Brandon Heller -:; Description: add a flow mod with all wildcards set, and ensure that all packets get diverted to the specified port. - -=== Forward Exact Port === -:; Name: test_forward_exact_port -:; Owner: Brandon Heller -:; Description: add an exact flow entry, verify a packet is forwarded to the correct port, for all port combinations - -=== Forward Exact ALL === -:; Name: test_forward_exact_all -:; Owner: Brandon Nefcy -:; Description: add an exact flow entry, verify a packet is sent out all ports, for all port combinations -:; Implementation: One packet is sent in to eth0, eth1, eth2, and eth3. An exact match flow entry is set up for each, with the expected action to be flooding the packet out on all ports except the input port. - -=== Forward Exact Controller === -:; Name: test_forward_exact_controller -:; Owner: Brandon Nefcy -:; Description: add an exact flow entry, verify a packet is forwarded to the secure channel -:; Implementation: One packet is sent in on each of eth0, eth1, eth2, and eth3. Test behavior expects to see each packet arrive via the secchan. - -=== Forward Wildcard Port === -:; Name: test_forward_wildcard_port -:; Owner: Brandon Nefcy -:; Description: Test each individual wildcard field. verify a matching packet is forwarded to the correct port, for all port combinations, and a mismatching packet is sent to secchan -:; Implementation: For each possible single-input-port to single-output-port combination flows are set up, one at a time, where each flow is wildcarded on a single field, with enough flows rotated in to test every wildcard field. For each, a matching packet is sent in and expected on the appropriate output port, and a mismatching packet is sent in and expected on the secchan output - -=== Forward Wildcard ALL === -:; Name: test_forward_wildcard_all -:; Owner: Brandon Nefcy -:; Description: same as test_forward_wildcard_port, but instead of sending from one input to one output, sends from one input to all outputs. -:; Implementation: Combination of test_foward_wildcard_port and test_forward_exact_all - -=== Forward Wildcard Controller === -:; Name: test_forward_wildcard_controller -:; Owner: Brandon Nefcy -:; Description: Combination of test_forward_wildcard_port and test_forward_exact_controller. Tests various single wildcard flows where matching packets and mismatching packets are both sent to secchan. -:; Status: Checked in, working, but with limitations as mentioned in test_forward_wildcard_port - -=== Forward After Expiration === -:; Name: test_forward_after_expiration -:; Owner: Brandon Nefcy -:; Description: insert short-lived flow, use it to forward packet, wait until expiration, send packet again, verify nothing received and counters zeroed -:; Implementation: An exact match flow entry is inserted for a specific input port -> output port combination (ie eth0->eth1), a packet is sent to match this entry with the test expecting the appropriate output behavior. The test waits for the flow entry to expire and verifies the expiration via a secchan flow expiration message, then proceeds to re-send the same packet from before, expecting a secchan OFPR_NO_MATCH message. The above is repeated for all combinations of input port -> output port. - -=== Overlapping Flow Entries === -:; Name: test_forward_overlapping_flow_entries -:; Owner: Brandon Nefcy -:; Description: insert both wildcard and exact match flow entries that overlap, verify that the exact match takes precedence -:; Implementation: One packet is sent in on eth0, eth1, eth2, and eth3. Before each packet is sent, two flow entries are set up, one where the entire flow is wildcarded and the action is to send to secchan, and another where the flow is set up to be an exact-match for the packet about to be sent and the action is to flood the packet. The test verifies that the sent packets are flooded out, and no secchan messages are received other than the flows expiring. - -=== Delete === -:; Name: test_delete -:; Owner: Masa -:; Description: insert two flow entries (one wildcard entry and one exact entry where the exact one is covered by the wildcard one). Send packets to verify they are forwarded correctly. Then delete the wildcard entry with DELETE (not strict) -- both the wildcard and the exeact entries should be deleted. To check this, send a packet matching to the exact entry to verify it gets sent to contoller. Re-insert the entry and verify that counters are zeroed. -::; Note -- Counter reading has not been implemented yet so the last part is not verified (5/2/2008) -:; Status: Done (rewritten with clean format) - -=== Delete Strict === -:; Name: test_delete_strict -:; Owner: Masa -:; Description: insert two flow entries (one wildcard entry and one exact entry where the exact one is covered by the wildcard one. The output ports of these two entries are different). Send packets to verify they are forwarded correctly. Then delete the wildcard entry with DELETE_STRICT (not strict) -- only the wildcard entry should be deleted (the exeact entry should not be deleted). To check this, send a packet matching to the exact entry to verify it gets forwarded. -:; Status: Done (rewritten with clean format) - -== Unusual Data == - -=== IP Options === -:; Name: test_ip_options -:; Owner: Masa -:; Description: suggested by Nicira. -::;(1) Create a flow entry that matches to a UDP flow coming from port eth7 (action = forward to port eth8). -::;(2) Send UDP packets with IP time stamp option (ip_hdr_len=7) to port eth7. -::;(3) To see whether the packet comes out from port eth8. -::; As of May 2, 2008, test succeeded. - -=== IP Protocol === -:; Name: test_ip_protocol -:; Owner: Masa -:; Description: -:: Added by Masa -:: see if src/dst port fields are used for matching only for TCP/UDP packets -:: As of May 2, 2008, the result is the following. Even if protocol is not TCP nor UDP, port number fields seems used for matching. Only when protocol number is specified to zero, port number fields are not used for matching.. It seems a strange behavior. -:; Status: Done (rewritten w/ clean format) -:; Note : TCP checksum (in TCP header) is not calculated due to lack of NF2::TCP library (but OF switch won't check it anyway). - -=== IP Offset > Pkt Len === -:; Name: test_ip_offset -:; Owner: Masa -:; Description: -:: possible security risk, shouldn't be an issue -:: suggested by Nicira -:: Create a flow entry. Send several packets matching the entry but whose IP Offset > Pkt Len. Verify all the packets are forwarded to the specified port (specified by the flow entry). - -=== TCP Options === -:; Name: test_tcp_options -:; Owner: Masa -:; Description: -:: See if TCP options affect operation -:: Install a TCP flow entry. Sent a TCP pkt that matches to the installed entry but has TCP option. Verify the packet is forwarded to the specified port. -:; Note : TCP checksum (in TCP header) is not calculated due to lack of NF2::TCP library (but OF switch won't check it anyway). - -=== LLC === -:; Name: test_llc -:; Owner: Masa -:; Description: see LLC packet format; adds 5B to Eth packet -::; Install a flow entry (exact match to an IP flow). Send an IP packet that matches to the installed entry and has the following Ethernet LLC/SNAP header. Verify it is forwarded to the specified port. -:::; Dst MAC (6 byte) -:::; Src MAC (6 byte) -:::; Length (2 byte) = data length from LLC header to the end of IP packet -:::; LLC header (3 byte) = 0xAA 0xAA 0x03 (always this value for IP packets) -:::; SNAP header(5 byte) = OUI(3B)+Type(2B)=0x000000 + 0x0800(IP) (always this value for IP packets) -:::; IP Packet -:; NOTE: It fails (pkt is forwarded to the controller) as of June 11, 2008. - - -Bugs/Shortcomings ------------------ - -- test_llc and test_ip_protocol are not actually run when enabled in a tests.txt file - -Contact -------- - -e-mail: openflow-discuss@openflowswitch.org -www: http://openflowswitch.org/ diff --git a/openflow/regress/bin/eth.map b/openflow/regress/bin/eth.map deleted file mode 100644 index 689ad0f0..00000000 --- a/openflow/regress/bin/eth.map +++ /dev/null @@ -1,8 +0,0 @@ -eth1:eth1 -eth2:eth2 -eth3:eth3 -eth4:eth4 -eth5:eth5 -eth6:eth6 -eth7:eth7 -eth8:eth8 diff --git a/openflow/regress/bin/nf2.map b/openflow/regress/bin/nf2.map deleted file mode 100644 index 797b3896..00000000 --- a/openflow/regress/bin/nf2.map +++ /dev/null @@ -1,8 +0,0 @@ -eth1:eth1 -eth2:eth2 -eth3:eth3 -eth4:eth4 -eth5:nf2c0 -eth6:nf2c1 -eth7:nf2c2 -eth8:nf2c3 diff --git a/openflow/regress/bin/of_hp_eth.map b/openflow/regress/bin/of_hp_eth.map deleted file mode 100644 index 4f652145..00000000 --- a/openflow/regress/bin/of_hp_eth.map +++ /dev/null @@ -1,8 +0,0 @@ -eth1:eth10 -eth2:eth11 -eth3:eth12 -eth4:eth13 -eth5:eth10 -eth6:eth11 -eth7:eth12 -eth8:eth13 diff --git a/openflow/regress/bin/of_hp_setup.pl b/openflow/regress/bin/of_hp_setup.pl deleted file mode 100755 index 213376c6..00000000 --- a/openflow/regress/bin/of_hp_setup.pl +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use OF::OFUtil; -use Test::TestLib; -use Time::HiRes qw(usleep); - -my $mapFile; -my $of_hp_switch_ip; -my $of_hp_vlan; -my $of_hp_controller; -my $of_hp_listener; -my $of_hp_community; - -# Process command line options -# Don't fail on unrecognised options, those failures are tricky -# to diagnose. For example projects/controller_disconnect sets --emerg -# Jean II -Getopt::Long::Configure( 'pass_through' ); -GetOptions( "map=s" => \$mapFile, ); -Getopt::Long::Configure( 'default' ); - -# If not specified on command line, use environment variable. -# Try specific first, then try generic - Jean II -if ( (! defined($mapFile) ) && (defined($ENV{'OFT_HP_MAP_ETH'})) ) { - $mapFile = "$ENV{OFT_HP_MAP_ETH}"; -} -if ( (! defined($mapFile) ) && (defined($ENV{'OFT_MAP_ETH'})) ) { - $mapFile = "$ENV{OFT_MAP_ETH}"; -} - -if ( defined($mapFile) ) { - nftest_process_iface_map($mapFile); -} - -setup_pcap_interfaces(); - -# Get HP switch address and configuration - Jean II -if (defined($ENV{'OFT_HP_SWITCH_IP'})) { - $of_hp_switch_ip = $ENV{'OFT_HP_SWITCH_IP'}; -} else { - $of_hp_switch_ip = "10.10.10.1"; -} -if (defined($ENV{'OFT_HP_VLAN'})) { - $of_hp_vlan = $ENV{'OFT_HP_VLAN'}; -} else { - $of_hp_vlan = 18; -} -if (defined($ENV{'OFT_HP_CONTROLLER'})) { - $of_hp_controller = $ENV{'OFT_HP_CONTROLLER'}; -} else { - my $of_port = get_of_port(); - $of_hp_controller = "tcp:10.10.10.2:$of_port"; -} -if (defined($ENV{'OFT_HP_LISTENER'})) { - # Transform into a passive string - ($proto, $host, $port) = split(/:/,$ENV{'OFT_HP_LISTENER'}); - $of_hp_listener = "p$proto:$port"; -} -if (defined($ENV{'OFT_HP_COMMUNITY'})) { - $of_hp_community = $ENV{'OFT_HP_COMMUNITY'}; -} else { - $of_hp_community = 'public'; -} - - -# disable OpenFlow module to make sure it restarts -`snmpset -v2c -c ${of_hp_community} ${of_hp_switch_ip} iso.org.dod.internet.private.enterprises.11.2.14.11.5.1.7.1.35.1.1.2.${of_hp_vlan} i 2`; - -# Make sure the snmp commands don't coalesce -usleep(200000); - -# set OpenFlow Controller string -`snmpset -v2c -c ${of_hp_community} ${of_hp_switch_ip} iso.org.dod.internet.private.enterprises.11.2.14.11.5.1.7.1.35.1.1.3.${of_hp_vlan} s ${of_hp_controller}`; - -# set OpenFlow Listener string -if (defined($of_hp_listener)) { - `snmpset -v2c -c ${of_hp_community} ${of_hp_switch_ip} iso.org.dod.internet.private.enterprises.11.2.14.11.5.1.7.1.35.1.1.4.${of_hp_vlan} s ${of_hp_listener}`; -} - -# enable OpenFlow module -`snmpset -v2c -c ${of_hp_community} ${of_hp_switch_ip} iso.org.dod.internet.private.enterprises.11.2.14.11.5.1.7.1.35.1.1.2.${of_hp_vlan} i 1`; - -# Starting OpenFlow takes time, give switch a bit of time... -usleep(900000); diff --git a/openflow/regress/bin/of_hp_teardown.pl b/openflow/regress/bin/of_hp_teardown.pl deleted file mode 100755 index 0365ce67..00000000 --- a/openflow/regress/bin/of_hp_teardown.pl +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use OF::OFUtil; -use Test::TestLib; - -my $mapFile; -my $of_hp_switch_ip; -my $of_hp_community; - -# Process command line options -unless ( GetOptions( "map=s" => \$mapFile, ) ) { - print "unrecognized option\n"; - exit 1; -} - -# If not specified on command line, use environment variable. -# Try specific first, then try generic - Jean II -if ( (! defined($mapFile) ) && (defined($ENV{'OFT_HP_MAP_ETH'})) ) { - $mapFile = "$ENV{OFT_HP_MAP_ETH}"; -} -if ( (! defined($mapFile) ) && (defined($ENV{'OFT_MAP_ETH'})) ) { - $mapFile = "$ENV{OFT_MAP_ETH}"; -} - -if ( defined($mapFile) ) { - nftest_process_iface_map($mapFile); -} - -# Get HP switch address - Jean II -if (defined($ENV{'OFT_HP_SWITCH_IP'})) { - $of_hp_switch_ip = $ENV{'OFT_HP_SWITCH_IP'}; -} else { - $of_hp_switch_ip = "10.10.10.1"; -} -if (defined($ENV{'OFT_HP_VLAN'})) { - $of_hp_vlan = $ENV{'OFT_HP_VLAN'}; -} else { - $of_hp_vlan = 18; -} -if (defined($ENV{'OFT_HP_COMMUNITY'})) { - $of_hp_community = $ENV{'OFT_HP_COMMUNITY'}; -} else { - $of_hp_community = 'public'; -} - -# disable OpenFlow module -`snmpset -v2c -c ${of_hp_community} ${of_hp_switch_ip} iso.org.dod.internet.private.enterprises.11.2.14.11.5.1.7.1.35.1.1.2.${of_hp_vlan} i 2`; - diff --git a/openflow/regress/bin/of_hp_test.pl b/openflow/regress/bin/of_hp_test.pl deleted file mode 100755 index d6c3233f..00000000 --- a/openflow/regress/bin/of_hp_test.pl +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/perl -w - -############################################################################## -# -# Wrapper for running OpenFlow regression tests against ProCurve 3500/5400 -# Jean Tourrilhes - HP-Labs - copyright 2009-2010 -# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ -# -############################################################################## - -use OF::Base; -use Test::RegressTest; -use strict; -use OF::OFUtil; - -# check vars are set. -check_OF_vars_set(); - -sub INT_Handler { - my $signame = shift; - print "\nNo interrupt handler implemented yet...\n"; - print "\nExited with SIG$signame\n"; - exit(1); -} - -# For the 5406zl and 3500yl... - -# HP switch starts at port 1 == 'A1' or 1 == '1' -# Test need extra delay due to slow controller socket -# Add more idle time due to stat resolution -# byte count is not available - Jean II -push @ARGV, "--root=$ENV{'OFT_ROOT'}", "--common-st-args=hp", "--controller=".$ENV{'OFT_HP_CONTROLLER'}, "--port_base=1", "--send_delay=300000", "--base_idle=2", "--ignore_byte_count"; - -# Use a single random port instead of all four -push @ARGV, "--less_ports"; - -# For QinQ, you will need the premium license... -push @ARGV, "--no_vlan"; - -# The hardware can not support slicing -push @ARGV, "--no_slicing"; - -# The hardware can not support barrier -push @ARGV, "--no_barrier"; - -# The hardware can not support emergency flow table -push @ARGV, "--no_emerg"; - -# Check for listener -if ( defined($ENV{'OFT_HP_LISTENER'}) ) { - push @ARGV, "--listener=$ENV{OFT_HP_LISTENER}"; -} - -# Check for specific MAP file... -if ( defined($ENV{'OFT_HP_MAP_ETH'}) ) { - push @ARGV, "--map=$ENV{OFT_HP_MAP_ETH}"; -} - -# Other configuration is through Environment Variables, See of_hp_setup.pl -# Jean II - -run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_hp_test_6600.pl b/openflow/regress/bin/of_hp_test_6600.pl deleted file mode 100755 index e141def5..00000000 --- a/openflow/regress/bin/of_hp_test_6600.pl +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/perl -w - -############################################################################## -# -# Wrapper for running OpenFlow regression tests against ProCurve 6600 -# Jean Tourrilhes - HP-Labs - copyright 2009-2010 -# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ -# -############################################################################## - -use OF::Base; -use Test::RegressTest; -use strict; -use OF::OFUtil; - -# check vars are set. -check_OF_vars_set(); - -sub INT_Handler { - my $signame = shift; - print "\nNo interrupt handler implemented yet...\n"; - print "\nExited with SIG$signame\n"; - exit(1); -} - -# For the 6600... - -# HP switch starts at port 25 == '1' -# Test need extra delay due to slow controller socket -# Add more idle time due to stat resolution -# byte count is not available - Jean II -push @ARGV, "--root=$ENV{'OFT_ROOT'}", "--common-st-args=hp", "--controller=".$ENV{'OFT_HP_CONTROLLER'}, "--port_base=25", "--send_delay=650000", "--base_idle=3", "--ignore_byte_count"; - -# Use a single random port instead of all four -push @ARGV, "--less_ports"; - -# For QinQ, you will need the premium license... -push @ARGV, "--no_vlan"; - -# The hardware can not support slicing -push @ARGV, "--no_slicing"; - -# The hardware can not support barrier -push @ARGV, "--no_barrier"; - -# The hardware can not support emergency flow table -push @ARGV, "--no_emerg"; - -# Check for listener -if ( defined($ENV{'OFT_HP_LISTENER'}) ) { - push @ARGV, "--listener=$ENV{OFT_HP_LISTENER}"; -} - -# Check for specific MAP file... -if ( defined($ENV{'OFT_HP_MAP_ETH'}) ) { - push @ARGV, "--map=$ENV{OFT_HP_MAP_ETH}"; -} - -# Other configuration is through Environment Variables, See of_hp_setup.pl -# Jean II - -run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_kmod_setup.pl b/openflow/regress/bin/of_kmod_setup.pl deleted file mode 100755 index fc3ef4ba..00000000 --- a/openflow/regress/bin/of_kmod_setup.pl +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use OF::OFUtil; -use Test::TestLib; - -my $mapFile, $controller; - -# Process command line options -unless ( GetOptions( "map=s" => \$mapFile, - "emerg" => \$emerg, - "controller=s", \$controller) ) { - print "unrecognized option\n"; - exit 1; -} - -if ( defined($mapFile) ) { - nftest_process_iface_map($mapFile); -} - -setup_kmod($controller, $emerg); diff --git a/openflow/regress/bin/of_kmod_teardown.pl b/openflow/regress/bin/of_kmod_teardown.pl deleted file mode 100755 index 4fa7dbfa..00000000 --- a/openflow/regress/bin/of_kmod_teardown.pl +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use OF::OFUtil; -use Test::TestLib; - -my $mapFile; - -# Process command line options -unless ( GetOptions( "map=s" => \$mapFile, ) ) { - print "unrecognized option\n"; - exit 1; -} - -if ( defined($mapFile) ) { - nftest_process_iface_map($mapFile); -} - -teardown_kmod(); diff --git a/openflow/regress/bin/of_kmod_test.pl b/openflow/regress/bin/of_kmod_test.pl deleted file mode 100755 index 6ce99411..00000000 --- a/openflow/regress/bin/of_kmod_test.pl +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/perl -w - -############################################################################## -# -# Wrapper for OpenFlow regression tests -# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ -# -############################################################################## - -use OF::Base; -use Test::RegressTest; -use strict; -use OF::OFUtil; - -# check vars are set. -check_OF_vars_set(); - -sub INT_Handler { - my $signame = shift; - print "\nNo interrupt handler implemented yet...\n"; - print "\nExited with SIG$signame\n"; - exit(1); -} - -push (@ARGV, "--root=$ENV{'OFT_ROOT'}", "--map=$ENV{'OFT_ROOT'}/bin/eth.map", "--port_base=1", "--common-st-args=kmod"); - -run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_kmod_veth_setup.pl b/openflow/regress/bin/of_kmod_veth_setup.pl deleted file mode 100755 index 79a37733..00000000 --- a/openflow/regress/bin/of_kmod_veth_setup.pl +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use OF::OFUtil; -use Test::TestLib; - -my ($mapFile, $controller); - -# Process command line options -unless ( GetOptions( "map=s" => \$mapFile, - "emerg" => \$emerg, - "controller=s", \$controller) ) { - print "unrecognized option\n"; - exit 1; -} - -if ( defined($mapFile) ) { - nftest_process_iface_map($mapFile); -} -#else, use pre-defined veth map -else { - nftest_process_iface_map("$ENV{'OFT_ROOT'}/bin/veth.map"); -} - -setup_kmod($controller, $emerg); diff --git a/openflow/regress/bin/of_kmod_veth_teardown.pl b/openflow/regress/bin/of_kmod_veth_teardown.pl deleted file mode 100755 index 52b57927..00000000 --- a/openflow/regress/bin/of_kmod_veth_teardown.pl +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use OF::OFUtil; -use Test::TestLib; - -my $mapFile; - -# Process command line options -unless ( GetOptions( "map=s" => \$mapFile, ) ) { - print "unrecognized option\n"; - exit 1; -} - -if ( defined($mapFile) ) { - nftest_process_iface_map($mapFile); -} -#else, use pre-defined veth map -else { - nftest_process_iface_map("$ENV{'OFT_ROOT'}/bin/veth.map"); -} - -teardown_kmod(); diff --git a/openflow/regress/bin/of_kmod_veth_test.pl b/openflow/regress/bin/of_kmod_veth_test.pl deleted file mode 100755 index 0f08edbb..00000000 --- a/openflow/regress/bin/of_kmod_veth_test.pl +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/perl -w - -############################################################################## -# -# Wrapper for OpenFlow regression tests -# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ -# -############################################################################## - -use OF::Base; -use Test::RegressTest; -use strict; -use OF::OFUtil; - -# check vars are set. -check_OF_vars_set(); - -sub INT_Handler { - my $signame = shift; - print "\nNo interrupt handler implemented yet...\n"; - print "\nExited with SIG$signame\n"; - exit(1); -} - -push (@ARGV, "--map=$ENV{'OFT_ROOT'}/bin/veth.map", "--root=$ENV{'OFT_ROOT'}", "--port_base=1", "--common-st-args=kmod_veth"); - -run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_nf2_setup.pl b/openflow/regress/bin/of_nf2_setup.pl deleted file mode 100755 index 34fe3351..00000000 --- a/openflow/regress/bin/of_nf2_setup.pl +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; -use Data::Dumper; - -use OF::OFUtil; -use Test::TestLib; - -my ($mapFile, $controller); - -print "Calling of_nf2_setup.pl\n"; -print Dumper(@ARGV) . "\n"; - -# Process command line options -unless ( GetOptions( "map=s" => \$mapFile, - "emerg" => \$emerg, - "controller=s", \$controller) ) { - print "unrecognized option\n"; - exit 1; -} - -if ( defined($mapFile) ) { - nftest_process_iface_map($mapFile); -} - -setup_NF2($controller, $emerg); diff --git a/openflow/regress/bin/of_nf2_teardown.pl b/openflow/regress/bin/of_nf2_teardown.pl deleted file mode 100755 index 286a87cf..00000000 --- a/openflow/regress/bin/of_nf2_teardown.pl +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use OF::OFUtil; -use Test::TestLib; - -my $mapFile; - -# Process command line options -unless ( GetOptions( "map=s" => \$mapFile, ) ) { - print "unrecognized option\n"; - exit 1; -} - -if ( defined($mapFile) ) { - nftest_process_iface_map($mapFile); -} - -teardown_NF2(); diff --git a/openflow/regress/bin/of_nf2_test.pl b/openflow/regress/bin/of_nf2_test.pl deleted file mode 100755 index 0704e99a..00000000 --- a/openflow/regress/bin/of_nf2_test.pl +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/perl -w - -############################################################################## -# -# Wrapper for OpenFlow regression tests -# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ -# -############################################################################## - -use OF::Base; -use Test::RegressTest; -use strict; -use OF::OFUtil; - -# check vars are set. -check_OF_vars_set(); - -sub INT_Handler { - my $signame = shift; - print "\nNo interrupt handler implemented yet...\n"; - print "\nExited with SIG$signame\n"; - exit(1); -} - -push (@ARGV, "--root=$ENV{'OFT_ROOT'}", "--map=$ENV{'OFT_ROOT'}/bin/nf2.map", "--port_base=1", "--common-st-args=nf2"); -push @ARGV, "--no_slicing"; - -run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_ovs_eth.map b/openflow/regress/bin/of_ovs_eth.map deleted file mode 100644 index 120ee51d..00000000 --- a/openflow/regress/bin/of_ovs_eth.map +++ /dev/null @@ -1,8 +0,0 @@ -eth1:eth10.91 -eth2:eth10.92 -eth3:eth10.93 -eth4:eth10.94 -eth5:eth11.91 -eth6:eth11.92 -eth7:eth11.93 -eth8:eth11.94 diff --git a/openflow/regress/bin/of_ovs_setup.pl b/openflow/regress/bin/of_ovs_setup.pl deleted file mode 100755 index ca2cc93f..00000000 --- a/openflow/regress/bin/of_ovs_setup.pl +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/perl -w -# Jean Tourrilhes - HP-Labs - -use Getopt::Long; - -use OF::OFUtil; -use Test::TestLib; - -my $mapFile; - -# The map file is necessary. It assing the real interface to the -# fictious names used by the test suite. -# eth1->eth4 are capture interfaces used to send/receive probe packets -# eth5->eth8 are configured to run the OpenFlow switch -# Jean II - -# Process command line options -# Don't fail on unrecognised options, those failures are tricky -# to diagnose. For example projects/controller_disconnect sets --emerg -# Jean II -Getopt::Long::Configure( 'pass_through' ); -GetOptions( "map=s" => \$mapFile, ); -Getopt::Long::Configure( 'default' ); - -# If not specified on command line, use enviroment variable. -# Try specific first, then try generic - Jean II -if ( (! defined($mapFile) ) && (defined($ENV{'OFT_OVS_MAP_ETH'})) ) { - $mapFile = "$ENV{OFT_OVS_MAP_ETH}"; -} -if ( (! defined($mapFile) ) && (defined($ENV{'OFT_MAP_ETH'})) ) { - $mapFile = "$ENV{OFT_MAP_ETH}"; -} - -# Set up the mappings -if ( defined($mapFile) ) { - nftest_process_iface_map($mapFile); -} - -# Debug... -#for ( my $i = 1 ; $i <= 8 ; $i++ ) { -# my $iface = nftest_get_iface("eth$i"); -# print "iface($i) = $iface\n"; -#} - -# Start capturing on eth1->eth4 -setup_pcap_interfaces(); - -# Get the directly where Open vSwitch resides -my $ovs_dir = $ENV{'OFT_OVS_ROOT'}; -my $of_port = get_of_port(); - -# Setup the kernel module -`insmod ${ovs_dir}/datapath/linux-2.6/openvswitch_mod.ko`; -`${ovs_dir}/utilities/ovs-dpctl add-dp dp0`; - -# Not needed after 0.99.2 -#for ( my $i = 5 ; $i <= 8 ; $i++ ) { -# my $iface = nftest_get_iface("eth$i"); -# `${ovs_dir}/utilities/ovs-dpctl add-if dp0 $iface`; -#} - -# create command line arguments containing all four ports -my $if_string = ''; -for ( my $i = 5 ; $i <= 7 ; $i++ ) { - $if_string .= nftest_get_iface("eth$i") . ','; -} -$if_string .= nftest_get_iface("eth8"); - -# create Open vSwitch openflow switch on four ports eth5->eth9 -system("${ovs_dir}/utilities/ovs-openflowd dp0 --ports=${if_string} tcp:127.0.0.1:${of_port} --listen=ptcp:6634 --fail=closed --inactivity-probe=999999 &"); - -# For 0.99.0, you'll need to manually add ports as above -#system("${ovs_dir}/utilities/ovs-openflowd dp0 tcp:127.0.0.1:${of_port} --listen=ptcp:6634 --fail=closed --inactivity-probe=999999 &"); - -# Up to 0.90.6, you would use secchan, after that you need to use ovs-openflowd -#system("${ovs_dir}/secchan/secchan dp0 tcp:127.0.0.1:${of_port} --listen=ptcp:6634 --fail=closed --inactivity-probe=999999 &"); diff --git a/openflow/regress/bin/of_ovs_teardown.pl b/openflow/regress/bin/of_ovs_teardown.pl deleted file mode 100755 index 303eb4ad..00000000 --- a/openflow/regress/bin/of_ovs_teardown.pl +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/perl -w -# Jean Tourrilhes - HP-Labs - -use Getopt::Long; - -use OF::OFUtil; -use Test::TestLib; - -my $mapFile; - -# Process command line options -unless ( GetOptions( "map=s" => \$mapFile, ) ) { - print "unrecognized option\n"; - exit 1; -} - -# If not specified on command line, use enviroment variable. -# Try specific first, then try generic - Jean II -if ( (! defined($mapFile) ) && (defined($ENV{'OFT_OVS_MAP_ETH'})) ) { - $mapFile = "$ENV{OFT_OVS_MAP_ETH}"; -} -if ( (! defined($mapFile) ) && (defined($ENV{'OFT_MAP_ETH'})) ) { - $mapFile = "$ENV{OFT_MAP_ETH}"; -} - -if ( defined($mapFile) ) { - nftest_process_iface_map($mapFile); -} - -# Get the directly where Open vSwitch resides -my $ovs_dir = $ENV{'OFT_OVS_ROOT'}; - -# Start by killing secchan or ovs-openflowd -`killall secchan`; -`killall ovs-openflowd`; - -# check if openflow kernel module loaded -my $of_kmod_loaded = `lsmod | grep openvswitch_mod`; -if ( $of_kmod_loaded eq "" ) { exit 0; } - -print "tearing down interfaces and datapaths\n"; - -# remove interfaces from openflow -for ( my $i = 5 ; $i <= 8 ; $i++ ) { - my $iface = nftest_get_iface("eth$i"); - `${ovs_dir}/utilities/ovs-dpctl del-if dp0 $iface`; -} - -`${ovs_dir}/utilities/ovs-dpctl del-dp dp0`; - -my $of_kmod_removed = `rmmod openvswitch_mod`; -if ( $of_kmod_removed ne "" ) { - die "failed to remove kernel module... please fix!\n"; -} - -$of_kmod_loaded = `lsmod | grep openvswitch_mod`; -if ( $of_kmod_loaded ne "" ) { - die "failed to remove kernel module... please fix!\n"; -} diff --git a/openflow/regress/bin/of_ovs_test.pl b/openflow/regress/bin/of_ovs_test.pl deleted file mode 100755 index a842aa64..00000000 --- a/openflow/regress/bin/of_ovs_test.pl +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/perl -w - -############################################################################## -# -# Wrapper for running OpenFlow regression tests against Open vSwitch -# Jean Tourrilhes - HP-Labs - copyright 2009-2010 -# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ -# -############################################################################## - -use OF::Base; -use Test::RegressTest; -use strict; -use OF::OFUtil; - -# check vars are set. -check_OF_vars_set(); - -sub INT_Handler { - my $signame = shift; - print "\nNo interrupt handler implemented yet...\n"; - print "\nExited with SIG$signame\n"; - exit(1); -} - -# For Open vSwitch - -# Open vSwitch starts at port 1 -# Get a bit of speedup by tweaking send_delay and base_idle -# Jean II -my $of_port = get_of_port(); -push @ARGV, "--root=$ENV{'OFT_ROOT'}", "--common-st-args=ovs", "--controller=tcp:localhost:$of_port,tcp:localhost:$of_port", "--listener=tcp:127.0.0.1:6634", "--port_base=1", "--send_delay=2000", "--base_idle=2"; - -# Use a single random port instead of all four -push @ARGV, "--less_ports"; - -# Don't bother with VLAN if we go outside the box, too many issues... -#push @ARGV, "--no_vlan"; - -# Don't bother with QoS currently, it's broken... -push @ARGV, "--no_slicing"; - -# The bother with emergency flow table tests, it's not supported... -push @ARGV, "--no_emerg"; - -# Don't forget to configure the OVS_ROOT environment variable -# Jean II - -# Check for specific MAP file... -if ( defined($ENV{'OFT_OVS_MAP_ETH'}) ) { - push @ARGV, "--map=$ENV{OFT_OVS_MAP_ETH}"; -} - -run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_ovs_user_setup.pl b/openflow/regress/bin/of_ovs_user_setup.pl deleted file mode 100755 index aa31cff6..00000000 --- a/openflow/regress/bin/of_ovs_user_setup.pl +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/perl -w -# Jean Tourrilhes - HP-Labs - -use Getopt::Long; - -use OF::OFUtil; -use Test::TestLib; - -my $mapFile; - -# The map file is necessary. It assing the real interface to the -# fictious names used by the test suite. -# eth1->eth4 are capture interfaces used to send/receive probe packets -# eth5->eth8 are configured to run the OpenFlow switch -# Jean II - -# Process command line options -# Don't fail on unrecognised options, those failures are tricky -# to diagnose. For example projects/controller_disconnect sets --emerg -# Jean II -Getopt::Long::Configure( 'pass_through' ); -GetOptions( "map=s" => \$mapFile, ); -Getopt::Long::Configure( 'default' ); - -# If not specified on command line, use enviroment variable. -# Try specific first, then try generic - Jean II -if ( (! defined($mapFile) ) && (defined($ENV{'OFT_OVS_MAP_ETH'})) ) { - $mapFile = "$ENV{OFT_OVS_MAP_ETH}"; -} -if ( (! defined($mapFile) ) && (defined($ENV{'OFT_MAP_ETH'})) ) { - $mapFile = "$ENV{OFT_MAP_ETH}"; -} - -# Set up the mappings -if ( defined($mapFile) ) { - nftest_process_iface_map($mapFile); -} - -# Debug... -#for ( my $i = 1 ; $i <= 8 ; $i++ ) { -# my $iface = nftest_get_iface("eth$i"); -# print "iface($i) = $iface\n"; -#} - -# Start capturing on eth1->eth4 -setup_pcap_interfaces(); - -# Get the directly where Open vSwitch resides -my $ovs_dir = $ENV{'OFT_OVS_ROOT'}; -my $of_port = get_of_port(); - -# create command line arguments containing all four ports -my $if_string = ''; -for ( my $i = 5 ; $i <= 7 ; $i++ ) { - $if_string .= nftest_get_iface("eth$i") . ','; -} -$if_string .= nftest_get_iface("eth8"); - -# create userspace Open vSwitch openflow switch on four ports -system("${ovs_dir}/utilities/ovs-openflowd netdev\@br0 --ports=${if_string} tcp:127.0.0.1:${of_port} --listen=ptcp:6634 --fail=closed --inactivity-probe=999999 &"); diff --git a/openflow/regress/bin/of_ovs_user_teardown.pl b/openflow/regress/bin/of_ovs_user_teardown.pl deleted file mode 100755 index 81124624..00000000 --- a/openflow/regress/bin/of_ovs_user_teardown.pl +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/perl -w -# Jean Tourrilhes - HP-Labs - -use Getopt::Long; - -use OF::OFUtil; -use Test::TestLib; - -my $mapFile; - -# Process command line options -unless ( GetOptions( "map=s" => \$mapFile, ) ) { - print "unrecognized option\n"; - exit 1; -} - -# If not specified on command line, use enviroment variable. -# Try specific first, then try generic - Jean II -if ( (! defined($mapFile) ) && (defined($ENV{'OFT_OVS_MAP_ETH'})) ) { - $mapFile = "$ENV{OFT_OVS_MAP_ETH}"; -} -if ( (! defined($mapFile) ) && (defined($ENV{'OFT_MAP_ETH'})) ) { - $mapFile = "$ENV{OFT_MAP_ETH}"; -} - -if ( defined($mapFile) ) { - nftest_process_iface_map($mapFile); -} - -# Get the directly where Open vSwitch resides -my $ovs_dir = $ENV{'OFT_OVS_ROOT'}; - -# Just kill ovs-openflowd -`killall ovs-openflowd`; diff --git a/openflow/regress/bin/of_ovs_user_test.pl b/openflow/regress/bin/of_ovs_user_test.pl deleted file mode 100755 index e726e556..00000000 --- a/openflow/regress/bin/of_ovs_user_test.pl +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/perl -w - -############################################################################## -# -# Wrapper for OpenFlow regression tests -# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ -# -############################################################################## - -use OF::Base; -use Test::RegressTest; -use strict; -use OF::OFUtil; - -# check vars are set. -check_OF_vars_set(); - -sub INT_Handler { - my $signame = shift; - print "\nNo interrupt handler implemented yet...\n"; - print "\nExited with SIG$signame\n"; - exit(1); -} - -# For Open vSwitch - -# Open vSwitch starts at port 1 -# Get a bit of speedup by tweaking send_delay and base_idle -# Jean II -my $of_port = get_of_port(); -push @ARGV, "--root=$ENV{'OFT_ROOT'}", "--common-st-args=ovs_user", "--controller=tcp:localhost:$of_port,tcp:localhost:$of_port", "--listener=tcp:127.0.0.1:6634", "--port_base=1", "--send_delay=2000", "--base_idle=2"; - -# Use a single random port instead of all four -push @ARGV, "--less_ports"; - -# Don't bother with QoS currently, it's broken... -push @ARGV, "--no_slicing"; - -# The bother with emergency flow table tests, it's not supported... -push @ARGV, "--no_emerg"; - -# Don't forget to configure the OVS_ROOT environment variable -# Jean II - -# Check for specific MAP file... -if ( defined($ENV{'OFT_OVS_MAP_ETH'}) ) { - push @ARGV, "--map=$ENV{OFT_OVS_MAP_ETH}"; -} - -run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_ovs_user_veth_test.pl b/openflow/regress/bin/of_ovs_user_veth_test.pl deleted file mode 100755 index 93a7a5df..00000000 --- a/openflow/regress/bin/of_ovs_user_veth_test.pl +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/perl -w - -############################################################################## -# -# Wrapper for running OpenFlow regression tests against Open vSwitch -# using veth -# Jean Tourrilhes - HP-Labs - copyright 2009-2010 -# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ -# -############################################################################## - -use OF::Base; -use Test::RegressTest; -use strict; -use OF::OFUtil; - -# check vars are set. -check_OF_vars_set(); - -sub INT_Handler { - my $signame = shift; - print "\nNo interrupt handler implemented yet...\n"; - print "\nExited with SIG$signame\n"; - exit(1); -} - -# For Open vSwitch - -# Open vSwitch starts at port 1 -# Get a bit of speedup by tweaking send_delay and base_idle -# Jean II -my $of_port = get_of_port(); -push @ARGV, "--root=$ENV{'OFT_ROOT'}", "--common-st-args=ovs_user", "--controller=tcp:localhost:$of_port,tcp:localhost:$of_port", "--listener=tcp:127.0.0.1:6634", "--port_base=1", "--send_delay=2000", "--base_idle=2", "--map=$ENV{'OFT_ROOT'}/bin/veth.map"; - -# Use a single random port instead of all four -push @ARGV, "--less_ports"; - -# Don't bother with QoS currently, it's broken... -push @ARGV, "--no_slicing"; - -# The bother with emergency flow table tests, it's not supported... -push @ARGV, "--no_emerg"; - -# Don't forget to configure the OVS_ROOT environment variable -# Jean II - -run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_ovs_veth_test.pl b/openflow/regress/bin/of_ovs_veth_test.pl deleted file mode 100755 index 4f09714a..00000000 --- a/openflow/regress/bin/of_ovs_veth_test.pl +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/perl -w - -############################################################################## -# -# Wrapper for running OpenFlow regression tests against Open vSwitch -# using veth -# Jean Tourrilhes - HP-Labs - copyright 2009-2010 -# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ -# -############################################################################## - -use OF::Base; -use Test::RegressTest; -use strict; -use OF::OFUtil; - -# check vars are set. -check_OF_vars_set(); - -sub INT_Handler { - my $signame = shift; - print "\nNo interrupt handler implemented yet...\n"; - print "\nExited with SIG$signame\n"; - exit(1); -} - -# For Open vSwitch - -# Open vSwitch starts at port 1 -# Get a bit of speedup by tweaking send_delay and base_idle -# Jean II -my $of_port = get_of_port(); -push @ARGV, "--root=$ENV{'OFT_ROOT'}", "--common-st-args=ovs", "--controller=tcp:localhost:$of_port,tcp:localhost:$of_port", "--listener=tcp:127.0.0.1:6634", "--port_base=1", "--send_delay=2000", "--base_idle=2", "--map=$ENV{'OFT_ROOT'}/bin/veth.map"; - -# Use a single random port instead of all four -push @ARGV, "--less_ports"; - -# Don't bother with QoS currently, it's broken... -push @ARGV, "--no_slicing"; - -# The bother with emergency flow table tests, it's not supported... -push @ARGV, "--no_emerg"; - -# Don't forget to configure the OVS_ROOT environment variable -# Jean II - -run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_user_setup.pl b/openflow/regress/bin/of_user_setup.pl deleted file mode 100755 index 5ff86039..00000000 --- a/openflow/regress/bin/of_user_setup.pl +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use OF::OFUtil; -use Test::TestLib; - -my ($mapFile, $controller); - -# Process command line options -unless ( GetOptions( "map=s" => \$mapFile, - "emerg" => \$emerg, - "controller=s", \$controller) ) { - print "unrecognized option\n"; - exit 1; -} - -if ( defined($mapFile) ) { - nftest_process_iface_map($mapFile); -} - -setup_user($controller, $emerg); diff --git a/openflow/regress/bin/of_user_teardown.pl b/openflow/regress/bin/of_user_teardown.pl deleted file mode 100755 index 760d7e25..00000000 --- a/openflow/regress/bin/of_user_teardown.pl +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use OF::OFUtil; -use Test::TestLib; - -my $mapFile; - -# Process command line options -unless ( GetOptions( "map=s" => \$mapFile, ) ) { - print "unrecognized option\n"; - exit 1; -} - -if ( defined($mapFile) ) { - nftest_process_iface_map($mapFile); -} - -teardown_user(); diff --git a/openflow/regress/bin/of_user_test.pl b/openflow/regress/bin/of_user_test.pl deleted file mode 100755 index 1fb19ea0..00000000 --- a/openflow/regress/bin/of_user_test.pl +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/perl -w - -############################################################################## -# -# Wrapper for OpenFlow regression tests -# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ -# -############################################################################## - -use OF::Base; -use Test::RegressTest; -use strict; -use OF::OFUtil; - -# check vars are set. -check_OF_vars_set(); - -sub INT_Handler { - my $signame = shift; - print "\nNo interrupt handler implemented yet...\n"; - print "\nExited with SIG$signame\n"; - exit(1); -} - -push (@ARGV, "--root=$ENV{'OFT_ROOT'}", "--map=$ENV{'OFT_ROOT'}/bin/eth.map", "--port_base=1", "--common-st-args=user"); - -run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/of_user_veth_setup.pl b/openflow/regress/bin/of_user_veth_setup.pl deleted file mode 100755 index d5ae5edc..00000000 --- a/openflow/regress/bin/of_user_veth_setup.pl +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use OF::OFUtil; -use Test::TestLib; - -my ($mapFile, $controller); - -# Process command line options -unless ( GetOptions( "map=s" => \$mapFile, - "emerg" => \$emerg, - "controller=s", \$controller) ) { - print "unrecognized option\n"; - exit 1; -} - -if ( defined($mapFile) ) { - nftest_process_iface_map($mapFile); -} -#else, use pre-defined veth map -else { - nftest_process_iface_map("$ENV{'OFT_ROOT'}/bin/veth.map"); -} - -setup_user($controller, $emerg); diff --git a/openflow/regress/bin/of_user_veth_teardown.pl b/openflow/regress/bin/of_user_veth_teardown.pl deleted file mode 100755 index 7d14c89c..00000000 --- a/openflow/regress/bin/of_user_veth_teardown.pl +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use OF::OFUtil; -use Test::TestLib; - -my $mapFile; - -# Process command line options -unless ( GetOptions( "map=s" => \$mapFile, ) ) { - print "unrecognized option\n"; - exit 1; -} - -if ( defined($mapFile) ) { - nftest_process_iface_map($mapFile); -} -#else, use pre-defined veth map -else { - nftest_process_iface_map("$ENV{'OFT_ROOT'}/bin/veth.map"); -} - -teardown_user(); diff --git a/openflow/regress/bin/of_user_veth_test.pl b/openflow/regress/bin/of_user_veth_test.pl deleted file mode 100755 index 63551f98..00000000 --- a/openflow/regress/bin/of_user_veth_test.pl +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/perl -w - -############################################################################## -# -# Wrapper for OpenFlow regression tests -# $Id: of_regress_test.pl 105 2008-06-06 04:07:05Z brandonh $ -# -############################################################################## - -use OF::Base; -use Test::RegressTest; -use strict; -use OF::OFUtil; - -# check vars are set. -check_OF_vars_set(); - -sub INT_Handler { - my $signame = shift; - print "\nNo interrupt handler implemented yet...\n"; - print "\nExited with SIG$signame\n"; - exit(1); -} - -push( @ARGV, "--map=$ENV{'OFT_ROOT'}/bin/veth.map", "--root=$ENV{'OFT_ROOT'}", "--port_base=1", "--common-st-args=user_veth"); - -run_regress_test( \&INT_Handler, @ARGV ); diff --git a/openflow/regress/bin/veth.map b/openflow/regress/bin/veth.map deleted file mode 100644 index bb1c1b09..00000000 --- a/openflow/regress/bin/veth.map +++ /dev/null @@ -1,8 +0,0 @@ -eth1:veth0 -eth2:veth2 -eth3:veth4 -eth4:veth6 -eth5:veth1 -eth6:veth3 -eth7:veth5 -eth8:veth7 diff --git a/openflow/regress/bin/veth_setup.pl b/openflow/regress/bin/veth_setup.pl deleted file mode 100755 index 11e746e8..00000000 --- a/openflow/regress/bin/veth_setup.pl +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/perl -w - -`/sbin/modprobe veth`; -for (my $i = 0; $i < 4; $i++) { - `/sbin/ip link add type veth`; -} - -for (my $i = 0; $i < 8; $i++) { - `sudo /sbin/ifconfig veth$i 192.168.1$i.1 netmask 255.255.255.0`; -} diff --git a/openflow/regress/bin/veth_teardown.pl b/openflow/regress/bin/veth_teardown.pl deleted file mode 100755 index ad103756..00000000 --- a/openflow/regress/bin/veth_teardown.pl +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/perl -w - -`/sbin/rmmod veth`; - diff --git a/openflow/regress/projects/black_box/regress/common/setup b/openflow/regress/projects/black_box/regress/common/setup deleted file mode 100755 index 8836cf7b..00000000 --- a/openflow/regress/projects/black_box/regress/common/setup +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use Test::TestLib; -use OF::OFUtil; - -my $mapFile; -my $platform; -my $args; - -# Process command line options -unless ( - GetOptions ( - "map=s" => \$mapFile, - "common-st-args=s" => \$platform, - ) -) -{ - print "invalid command format\n"; - exit(1); -} - -if (defined($mapFile)) { - $args = "--map=$mapFile"; -} - -if (!defined($platform)) { - print "no platform defined\n"; - exit(1); -} -else { - print "platform = $platform\n"; -} - -my $filename = "of_${platform}_setup.pl"; - -# exit if of_${platform}_setup.pl not in path -if (-e "$ENV{'OFT_ROOT'}/bin/$filename") { - #system("$filename " . $args . " 2> /dev/null > /dev/null"); - system("$ENV{'OFT_ROOT'}/bin/$filename " . $args ); - #setup_kmod(); - exit (0); -} else { - print "couldn't find setup file $filename\n"; - exit (1); -} diff --git a/openflow/regress/projects/black_box/regress/common/teardown b/openflow/regress/projects/black_box/regress/common/teardown deleted file mode 100755 index 6f1f8391..00000000 --- a/openflow/regress/projects/black_box/regress/common/teardown +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use Test::TestLib; -use OF::OFUtil; - -my $mapFile; -my $platform; -my $args; - -# Process command line options -unless ( - GetOptions ( - "map=s" => \$mapFile, - "common-st-args=s" => \$platform, - ) -) -{ - print "invalid command format\n"; - exit(1); -} - -if (defined($mapFile)) { - $args = "--map=$mapFile"; -} - -if (!defined($platform)) { - print "no platform defined\n"; - exit(1); -} -else { - print "platform = $platform\n"; -} - -my $filename = "of_${platform}_teardown.pl"; - -# exit if of_${platform}_setup.pl not in path -if (-e "$ENV{'OFT_ROOT'}/bin/$filename") { - #system("$filename " . $args . " 2> /dev/null > /dev/null"); - system("$ENV{'OFT_ROOT'}/bin/$filename " . $args ); - #teardown_kmod(); - exit (0); -} else { - print "couldn't find setup file $filename\n"; - exit (1); -} diff --git a/openflow/regress/projects/black_box/regress/test_add_flow_latency/run.pl b/openflow/regress/projects/black_box/regress/test_add_flow_latency/run.pl deleted file mode 100755 index 91ec09af..00000000 --- a/openflow/regress/projects/black_box/regress/test_add_flow_latency/run.pl +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/perl -w -# test_add_flow_latency - -use strict; -use OF::Includes; - -sub my_test { - - my ($sock) = @_; - - my $pkt_args = { - DA => "00:00:00:00:00:01", - SA => "00:00:00:00:00:02", - src_ip => "192.168.200.40", - dst_ip => "192.168.201.40", - ttl => 64, - len => 60 - }; - - my $test_pkt = new NF2::UDP_pkt(%$pkt_args); - - my $wildcards = 0x0; - my $in_port = 1; - my $out_port = 2; - my $max_idle = 0; - my $flags = 0x0; # don't send flow expiry - - my $flow_mod_pkt = create_flow_mod_from_udp($ofp,$test_pkt,$in_port,$out_port,$max_idle,$flags,$wildcards); - - print $sock $flow_mod_pkt; - usleep(1000000); - - - my $cnt = 0; - my $start_time = [gettimeofday()]; - for( $cnt = 0;$cnt < 1000; $cnt++){ - nftest_send( nftest_get_iface( "eth" . ($in_port+1)),$test_pkt->packed ); - nftest_expect( nftest_get_iface( "eth" . ($out_port+1)),$test_pkt->packed ); - } - my $time_elapse = tv_interval($start_time); - my $latency = $time_elapse*1000/1000; - print "Latency is $latency ms"; - - } - - -run_black_box_test( \&my_test); diff --git a/openflow/regress/projects/black_box/regress/test_barrier/run.pl b/openflow/regress/projects/black_box/regress/test_barrier/run.pl deleted file mode 100755 index 87b91153..00000000 --- a/openflow/regress/projects/black_box/regress/test_barrier/run.pl +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/perl -w -# test_barrier - -use strict; -use OF::Includes; - -sub my_test { - my ($sock, $options_ref) = @_; - - if ( not defined( $$options_ref{'no_barrier'} ) ) { - my $in_port = $$options_ref{'port_base'}; - my $out_port = $in_port + 1; - - # RUOK? - send_get_config_request($ofp, $sock, 0xdeadbeef); - wait_for_get_config_reply($ofp, $sock, 0xdeadbeef); - - my $base_packet = get_default_black_box_pkt($in_port, $out_port); - - my $wildcards = 0x0000; - my $flags = $enums{'OFPFF_CHECK_OVERLAP'}; - my $max_idle = 0x0; - my $packet = create_flow_mod_from_udp($ofp, $base_packet, $in_port, $out_port, $max_idle, $flags, $wildcards); - - # FOO - print $sock $packet; - - my $wildcards = 0x03fe; - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; - my $packet = create_flow_mod_from_udp($ofp, $base_packet, $in_port, $out_port, $max_idle, $flags, $wildcards); - - # BAR - print $sock $packet; - - my $wildcards = 0x03fd; - my $flags = 0x0000; - my $packet = create_flow_mod_from_udp($ofp, $base_packet, $in_port, $out_port, $max_idle, $flags, $wildcards); - - # BAZ - print $sock $packet; - - # SYNC - enter_barrier($ofp, $sock, 0x12345678); - wait_for_barrier_exit($ofp, $sock, 0x12345678); - - # RUOK? - send_get_config_request($ofp, $sock, 0xcafe2009); - wait_for_get_config_reply($ofp, $sock, 0xcafe2009); - } -} - -run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_cookie_flow_expired/run.pl b/openflow/regress/projects/black_box/regress/test_cookie_flow_expired/run.pl deleted file mode 100755 index 5a300ad9..00000000 --- a/openflow/regress/projects/black_box/regress/test_cookie_flow_expired/run.pl +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/perl -w -# test_flow_expired - -use strict; -use OF::Includes; - -sub my_test { - - my ($sock, $options_ref) = @_; - - my $in_port = $$options_ref{'port_base'}; - my $out_port = $in_port + 1; - - my $test_pkt = get_default_black_box_pkt( $in_port, $out_port); - - my $max_idle = 0x1; # second before flow expiration - my $wildcards = 0x0; # exact match - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry - my $cookie = 0x123456; - # Create a flow mod with a flow cookie - my $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, - $max_idle, $flags, $wildcards, undef, undef, undef, - undef, $cookie ); - - #print HexDump($pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - - my $pkt_len = 0; - my $pkt_total = 0; - wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, - $pkt_total, undef, $cookie ); - -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_cookie_flow_stats/run.pl b/openflow/regress/projects/black_box/regress/test_cookie_flow_stats/run.pl deleted file mode 100755 index 705146b1..00000000 --- a/openflow/regress/projects/black_box/regress/test_cookie_flow_stats/run.pl +++ /dev/null @@ -1,151 +0,0 @@ -#!/usr/bin/perl -w -# test_flow_stats - -use strict; -use OF::Includes; - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - my $port_base = $$options_ref{'port_base'}; - - my $cookie = 0x123456; - - my $hdr_args = { - version => get_of_ver(), - type => $enums{'OFPT_STATS_REQUEST'}, - length => $ofp->sizeof('ofp_stats_request') + - $ofp->sizeof('ofp_flow_stats_request'), - # should generate automatically! - xid => 0x00000000 - }; - - my $match_args = { - wildcards => 0x2003ef, - in_port => 0, - dl_src => [], - dl_dst => [], - dl_vlan => 0, - dl_type => 0x800, - nw_tos => 0, - nw_src => (NF2::IP_hdr::getIP('192.168.200.1'))[0], - nw_dst => (NF2::IP_hdr::getIP('192.168.201.2'))[0], - nw_proto => 0, - tp_src => 0, - tp_dst => 0 - }; - - my $stats_request_args = { - header => $hdr_args, - type => $enums{'OFPST_FLOW'}, - flags => 0 - }; - - my $body_args = { - match => $match_args, - table_id => 0xff, #match all tables - out_port => $enums{'OFPP_NONE'}, - }; - - my $body = $ofp->pack('ofp_flow_stats_request', $body_args ); - - my $stats_request = $ofp->pack( 'ofp_stats_request', $stats_request_args ); - - my $mesg = $stats_request . $body; - - # Send 'stats_request' message - print $sock $mesg; - - # Should add timeout here - will crash if no reply - my $recvd_mesg; - sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; - - # Inspect message - my $msg_size = length($recvd_mesg); - - my $msg = $ofp->unpack( 'ofp_stats_reply', $recvd_mesg ); - - #print HexDump ($recvd_mesg); - print Dumper($msg); - - # Verify fields - verify_header( $msg, 'OFPT_STATS_REPLY', $msg_size ); - - #---------------------- - - # add flow mod, send pkt - { - - my $in_port_offset = 0; - my $out_port_offset = 1; - my $wildcards = 0x2003ef, - my $wait = 5; - - #$$options_ref{'send_delay'} = 5; - - forward_simple ( $ofp, $sock, $options_ref, $in_port_offset, - $out_port_offset, $wildcards, 'any', 1, undef, undef, $cookie); - -# my $in_port = $in_port_offset + $$options_ref{'port_base'}; -# my $out_port = $out_port_offset + $$options_ref{'port_base'}; -# -# my $test_pkt = get_default_black_box_pkt_len( $in_port, $out_port, $$options_ref{'pkt_len'} ); -# my $flow_mod_pkt = -# create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $wait, $wildcards ); -# -# print $sock $flow_mod_pkt; -# -# # Give OF switch time to process the flow mod -# usleep($$options_ref{'send_delay'}); -# -# nftest_send( "eth" . ($in_port_offset + 1), $test_pkt->packed ); - } - - sleep .1; - - - # Send 'stats_request' message - print $sock $mesg; - - # Should add timeout here - will crash if no reply - my $recvd_mesg; - sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; - - # Inspect message - my $msg_size = length($recvd_mesg); - - my $msg = $ofp->unpack( 'ofp_stats_reply', $recvd_mesg ); - - # Strip off the header from the received message - $recvd_mesg = substr($recvd_mesg, $ofp->sizeof('ofp_stats_reply')); - - # Unpack each of the ofp_flow_stats messages - my $flow_stats_len = $ofp->sizeof('ofp_flow_stats'); - while (length($recvd_mesg) > 0) { - if (length($recvd_mesg) < $flow_stats_len) {\ - die "Error: Partial flow stats message received"; - } - my $flow_stats = $ofp->unpack('ofp_flow_stats', $recvd_mesg); - - push @{$msg->{'body'}}, $flow_stats; - $recvd_mesg = substr($recvd_mesg, $flow_stats->{'length'}); - } - - #print HexDump ($recvd_mesg); - print Dumper($msg); - - # Verify fields - verify_header( $msg, 'OFPT_STATS_REPLY', $msg_size ); - - # Verify the cookie - compare( "stats_reply cookie", $msg->{'body'}->[0]->{'cookie'}, '==', $cookie ); - - - #wait_for_flow_expired_all( $ofp, $sock, $options_ref ); - - -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_delete/run.pl b/openflow/regress/projects/black_box/regress/test_delete/run.pl deleted file mode 100755 index 7b594682..00000000 --- a/openflow/regress/projects/black_box/regress/test_delete/run.pl +++ /dev/null @@ -1,172 +0,0 @@ -#!/usr/bin/perl -w -# test_delete - -use strict; -use OF::Includes; - -sub send_expect_exact_with_wildcard { - - my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $out_port2_offset, $max_idle, $pkt_len ) = @_; - - my $in_port = $in_port_offset + $$options_ref{'port_base'}; - my $out_port = $out_port_offset + $$options_ref{'port_base'}; - my $out_port2 = $out_port2_offset + $$options_ref{'port_base'}; - - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - src_port => 70, - dst_port => 80 - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - my $test_pkt_args2 = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - src_port => 170, - dst_port => 180 - }; - my $test_pkt2 = new NF2::UDP_pkt(%$test_pkt_args2); - - # Flow entry -- exact match, $out_port - my $wildcards = 0x0; # exact match - my $flags = 0x0; # don't send flow expiry - my $flow_mod_exact_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); - - # 2nd flow entry -- wildcard match, $out_port2 - $wildcards = $enums{'OFPFW_TP_SRC'} | $enums{'OFPFW_TP_DST'}; # wildcard match (don't care udp src/dst ports) - print "wildcards = $wildcards\n"; - my $flow_mod_wildcard_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port2, $max_idle, $flags, $wildcards ); - - #print HexDump($flow_mod_exact_pkt); - #print HexDump($flow_mod_wildcard_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_exact_pkt; - print "sent flow_mod message (create exact match entry)\n"; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - - print $sock $flow_mod_wildcard_pkt; - print "sent flow_mod message (create wildcard entry)\n"; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - - # Check what's on the switch - #dpctl_show_flows($options_ref); - - # Send a packet - ensure packet comes out desired port - print "Verify packets are forwarded correctly\n"; - nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt->packed ); - nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); - - nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt2->packed ); - nftest_expect( "eth" . ( $out_port2_offset + 1 ), $test_pkt2->packed ); - - print "sent two packets\n"; -} - -sub delete_send_expect { - - my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $out_port2_offset, $max_idle, $pkt_len ) = @_; - - my $in_port = $in_port_offset + $$options_ref{'port_base'}; - my $out_port = $out_port_offset + $$options_ref{'port_base'}; - my $out_port2 = $out_port2_offset + $$options_ref{'port_base'}; - - # in_port refers to the flow mod entry's input - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - src_port => 70, - dst_port => 80 - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - my $test_pkt_args2 = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - src_port => 170, - dst_port => 180 - }; - my $test_pkt2 = new NF2::UDP_pkt(%$test_pkt_args2); - - my $wildcards = $enums{'OFPFW_TP_SRC'} | $enums{'OFPFW_TP_DST'}; # wildcard match (don't care udp src/dst ports) - my $flags = 0x0; # don't send flow expiry - my $flow_mod_wildcard_pkt = - create_flow_mod_from_udp_action( $ofp, $test_pkt2, $in_port, $out_port2, $max_idle, - $flags, $wildcards, "OFPFC_DELETE" ); - - #print HexDump($flow_mod_exact_pkt); - #print HexDump($flow_mod_wildcard_pkt); - - # Send 'flow_mod' message (delete wildcard entry without STRICT) - print $sock $flow_mod_wildcard_pkt; - print "sent flow_mod message (delete wildcard entry)\n"; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - # Give extra time, wildcard delete takes more time - Jean II - usleep($$options_ref{'send_delay'}); - - # Check what's on the switch - #dpctl_show_flows($options_ref); - - # Send a packet - print "Verify packets are forwarded correctly i.e., fwded to contoller\n"; - nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt->packed ); - nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt2->packed ); - - # both pkts should go to the controller - wait_for_one_packet_in( $ofp, $sock, $pkt_len, $test_pkt->packed ); - wait_for_one_packet_in( $ofp, $sock, $pkt_len, $test_pkt2->packed ); - -} - -sub test_delete { - - my ( $ofp, $sock, $options_ref, $i, $j, $o_port2, $wildcards ) = @_; - - my $max_idle = $$options_ref{'max_idle'}; - my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_total = $$options_ref{'pkt_total'}; - - print "sending from $i to $j & $i to $o_port2 -- both should match\n"; - send_expect_exact_with_wildcard( $ofp, $sock, $options_ref, $i, $j, $o_port2, $max_idle, $pkt_len ); - - # wait for switch to process last packets - usleep($$options_ref{'send_delay'}); - - print "delete wildcard entry (without STRICT) and send packets again\n"; - delete_send_expect( $ofp, $sock, $options_ref, $i, $j, $o_port2, $max_idle, $pkt_len ); -} - -sub my_test { - - my ($sock, $options_ref) = @_; - - # send from every port to every other port - for_all_port_triplets( $ofp, $sock, $options_ref, \&test_delete, 0x0); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_delete_send_flow_exp/run.pl b/openflow/regress/projects/black_box/regress/test_delete_send_flow_exp/run.pl deleted file mode 100755 index 6e093fcc..00000000 --- a/openflow/regress/projects/black_box/regress/test_delete_send_flow_exp/run.pl +++ /dev/null @@ -1,104 +0,0 @@ -#!/usr/bin/perl -w -# test_delete - -use strict; -use OF::Includes; - -sub my_test { - - my ($sock, $options_ref) = @_; - - my $in_port = $$options_ref{'port_base'}; - my $out_port = $in_port + 1; - - my $test_pkt = get_default_black_box_pkt( $in_port, $out_port, $$options_ref{'pkt_len'} ); - - my $max_idle = 0x0; # second before flow expiration -- never time out - my $wildcards = 0x0; # exact match - # Create a flow mod without expiry - my $flags = 0x0; # don't send flow expiry - my $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); - print "send flow mode without expiry\n"; - print $sock $flow_mod_pkt; - - # Delete the flow and verify that we don't see an expiry - $flow_mod_pkt = - create_flow_mod_from_udp_action( $ofp, $test_pkt, $in_port, $out_port, $max_idle, - $flags, $wildcards, "OFPFC_DELETE" ); - print $sock $flow_mod_pkt; - - my $sel = IO::Select->new($sock); - if ($sel->can_read(2)) { - print "Error: was not expecting a message from the switch\n"; - exit 1; - } - - # Create a flow mod with expiry - $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry - $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); - print "send flow mode with expiry\n"; - print $sock $flow_mod_pkt; - - # Delete the flow and verify that we do see an expiry - $flags = 0x0; # Reset the flags to zero. Should not matter as it - # should only depend on the flags when the flow was installed. - $flow_mod_pkt = - create_flow_mod_from_udp_action( $ofp, $test_pkt, $in_port, $out_port, $max_idle, - $flags, $wildcards, "OFPFC_DELETE" ); - print $sock $flow_mod_pkt; - - my $pkt_len = 0; - my $pkt_total = 0; - wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); - - # Redo the same test with a few packets to make sure stats are correct - # Jean II - - # Create a flow mod with expiry - $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry - $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); - print "send flow mode with expiry and with 3 packets\n"; - print $sock $flow_mod_pkt; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - usleep($$options_ref{'send_delay'}); - - # Send 3 packets, because first packet can be "special" - Jean II - # We should be using $options{'pkt_total'}, but that is stuck at 1 - nftest_send("eth" . ($in_port), $test_pkt->packed); - nftest_send("eth" . ($in_port), $test_pkt->packed); - nftest_send("eth" . ($in_port), $test_pkt->packed); - - # expect 3 packets - print "expect 3 packets\n"; - nftest_expect("eth" . ($out_port), $test_pkt->packed); - nftest_expect("eth" . ($out_port), $test_pkt->packed); - nftest_expect("eth" . ($out_port), $test_pkt->packed); - - # Wait for stats to refresh - sleep($$options_ref{'max_idle'}); - #dpctl_show_flows($options_ref); - - # Delete the flow and verify that we do see an expiry - $flags = 0x0; # Reset the flags to zero. Should not matter as it - # should only depend on the flags when the flow was installed. - $flow_mod_pkt = - create_flow_mod_from_udp_action( $ofp, $test_pkt, $in_port, $out_port, $max_idle, - $flags, $wildcards, "OFPFC_DELETE" ); - print $sock $flow_mod_pkt; - - # And now check the stats in the flow removed message... - my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_total = 3; - wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); - - - -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_delete_strict/run.pl b/openflow/regress/projects/black_box/regress/test_delete_strict/run.pl deleted file mode 100755 index 8290dae9..00000000 --- a/openflow/regress/projects/black_box/regress/test_delete_strict/run.pl +++ /dev/null @@ -1,175 +0,0 @@ -#!/usr/bin/perl -w -# test_delete_strict - -use strict; -use OF::Includes; - -sub send_expect_exact_with_wildcard { - - my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $out_port2_offset, $max_idle, $pkt_len ) = @_; - - my $in_port = $in_port_offset + $$options_ref{'port_base'}; - my $out_port = $out_port_offset + $$options_ref{'port_base'}; - my $out_port2 = $out_port2_offset + $$options_ref{'port_base'}; - - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - src_port => 70, - dst_port => 80 - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - my $test_pkt_args2 = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - src_port => 170, - dst_port => 180 - }; - my $test_pkt2 = new NF2::UDP_pkt(%$test_pkt_args2); - - # Flow entry -- exact match, $out_port - my $wildcards = 0x0; # exact match - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; - my $flow_mod_exact_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); - - # 2nd flow entry -- wildcard match, $out_port2 - $wildcards = $enums{'OFPFW_TP_SRC'} | $enums{'OFPFW_TP_DST'}; # wildcard match (don't care udp src/dst ports) - my $flow_mod_wildcard_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port2, $max_idle, $flags, $wildcards ); - - #print HexDump($flow_mod_exact_pkt); - #print HexDump($flow_mod_wildcard_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_exact_pkt; - print "sent flow_mod message (create exact match entry)\n"; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - - print $sock $flow_mod_wildcard_pkt; - print "sent flow_mod message (create wildcard entry)\n"; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - - # Check what's on the switch - #dpctl_show_flows($options_ref); - - # Send a packet - ensure packet comes out desired port - print "Verify packets are forwarded correctly\n"; - nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt->packed ); - nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); - - nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt2->packed ); - nftest_expect( "eth" . ( $out_port2_offset + 1 ), $test_pkt2->packed ); -} - -sub delete_strict_send_expect { - - my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $out_port2_offset, $max_idle, $pkt_len ) = @_; - - my $in_port = $in_port_offset + $$options_ref{'port_base'}; - my $out_port = $out_port_offset + $$options_ref{'port_base'}; - my $out_port2 = $out_port2_offset + $$options_ref{'port_base'}; - - # in_port refers to the flow mod entry's input - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - src_port => 70, - dst_port => 80 - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - my $test_pkt_args2 = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - src_port => 170, - dst_port => 180 - }; - my $test_pkt2 = new NF2::UDP_pkt(%$test_pkt_args2); - - my $wildcards = $enums{'OFPFW_TP_SRC'} | $enums{'OFPFW_TP_DST'}; # wildcard match (don't care udp src/dst ports) - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; - my $flow_mod_wildcard_pkt = - - # delete_strict_from_udp( $ofp, $test_pkt, $in_port, $out_port2, $wildcards ); - create_flow_mod_from_udp_action( $ofp, $test_pkt, $in_port, $out_port2, $max_idle, $flags, $wildcards, - 'OFPFC_DELETE_STRICT' ); - - #print HexDump($flow_mod_exact_pkt); - #print HexDump($flow_mod_wildcard_pkt); - - # Send 'flow_mod' message (delete wildcard entry with STRICT) - print $sock $flow_mod_wildcard_pkt; - print "sent flow_mod message (delete (strict) wildcard entry)\n"; - - # Expect a flow expire due to the delete - wait_for_flow_expired_readone( $ofp, $sock, $options_ref, $pkt_len, 1 ); - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - # Give extra time, delete takes more time - Jean II - usleep($$options_ref{'send_delay'}); - - # Check what's on the switch - #dpctl_show_flows($options_ref); - - # Send a packet - print - "Verify packets are forwarded correctly i.e., one fwded to contoller and one (exact match) fwd to the specified port\n"; - nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt->packed ); - nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); - - nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt2->packed ); - wait_for_one_packet_in( $ofp, $sock, $pkt_len, $test_pkt2->packed ); -} - -sub test_delete_strict { - - my ( $ofp, $sock, $options_ref, $i, $j, $o_port2, $wildcards ) = @_; - - my $max_idle = $$options_ref{'max_idle'}; - my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_total = $$options_ref{'pkt_total'}; - - print "sending from $i to $j & $i to $o_port2 -- both should match\n"; - send_expect_exact_with_wildcard( $ofp, $sock, $options_ref, $i, $j, $o_port2, $max_idle, $pkt_len ); - - # wait for switch to process last packets - usleep($$options_ref{'send_delay'}); - - print "delete wildcard entry (with STRICT) \n"; - print "sending from $i to $j & $i to $o_port2 "; - delete_strict_send_expect( $ofp, $sock, $options_ref, $i, $j, $o_port2, $max_idle, $pkt_len ); - wait_for_flow_expired_readone( $ofp, $sock, $options_ref, $pkt_len, 2 ); -} - -sub my_test { - - my ($sock, $options_ref) = @_; - - # send from every port to every other port - for_all_port_triplets( $ofp, $sock, $options_ref, \&test_delete_strict, 0x0); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_drop_exact/run.pl b/openflow/regress/projects/black_box/regress/test_drop_exact/run.pl deleted file mode 100755 index 98180d18..00000000 --- a/openflow/regress/projects/black_box/regress/test_drop_exact/run.pl +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/perl -w -# test_drop_exact - -use strict; -use OF::Includes; - -#sub drop_simple { -# -# my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $wildcards, $nowait ) = @_; -# -# my $in_port = $in_port_offset + $$options_ref{'port_base'}; -# my $out_port = $out_port_offset + $$options_ref{'port_base'}; -# # print "drop_simple : ports = ".($in_port).",".($out_port); -# -# my $test_pkt = get_default_black_box_pkt_len( $in_port, $out_port, $$options_ref{'pkt_len'} ); -# -# #print HexDump ( $test_pkt->packed ); -# -# my $flow_mod_pkt = -# create_flow_drop_from_udp_action( $ofp, $test_pkt, $in_port, $out_port, $$options_ref{'max_idle'}, $wildcards, 'drop' ); -# -# #print HexDump($flow_mod_pkt); -# #print Dumper($flow_mod_pkt); -# -# # Send 'flow_mod' message -# syswrite( $sock, $flow_mod_pkt ); -# print "sent flow_mod message\n"; -# -# # Give OF switch time to process the flow mod -# usleep($$options_ref{'send_delay'}); -# -# nftest_send( "eth" . ($in_port_offset + 1), $test_pkt->packed); -# -# # We should expect no message at all on any port ! - Jean II -# -# if (not defined($nowait)) { -# print "wait \n"; -# wait_for_flow_expired_all( $ofp, $sock, $options_ref ); -# } -#} - -sub drop_port { - - forward_simple(@_, 'drop'); -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_port_pairs( $ofp, $sock, $options_ref, \&drop_port, 0x0); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_failover_close/run.pl b/openflow/regress/projects/black_box/regress/test_failover_close/run.pl deleted file mode 100755 index 06fd9a71..00000000 --- a/openflow/regress/projects/black_box/regress/test_failover_close/run.pl +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/perl -w - -# Simple two-controller failover test -# -# For this test to work, the switch must be set up to use our -# two "controllers", e.g. -# -# ofprotocol --controller=tcp:127.0.0.1:6633,tcp:127.0.0.1:6634 -# -# If you use different ports than the defaults, then you must -# pass the --controller option into this script as well. -# -# Failover test 2: Controller is fine, but closes connection -# -# For this test, we accept the Hello sequence and then close -# the socket. Then we listen for a failover connection on the -# second socket. -# - -use strict; -use OF::Includes; - -# Save ARGV for future reference -my @ARGS = @ARGV; - -my $test = "Failover test 2 (connection closed)"; - -print "$test phase 1: calling run_black_box_test with @ARGV\n"; - -# Start up, say Hello, and close connection -sub close_failover_test_phase_1 { - my ($sock) = @_; - print "$test: Got socket $sock\n"; - print "$test: Finished Hello sequence on first controller\n"; - print "$test: Closing socket\n"; - $sock->close(); -} - -run_black_box_test( \&close_failover_test_phase_1, \@ARGV, 1); # 1 -> don't exit - -# Now, attempt to open up the second controller connection, and -# hope that we fail over - -# Restore ARGV -@ARGV = @ARGS; - -# If no controllers specified, use default -if (not "@ARGV" =~ "--controller") { - push( @ARGV, "--controller=" . nftest_default_controllers() ); -} - -# Replace --controller=foo,bar with --controller=bar so that -# run_black_box_test() will use bar's port rather than foo's -for (my $i = 0; $i < @ARGV; $i++) { - if ($ARGV[$i] =~ /controller=[^,]*,([^\s]+)/ ) { - print "failover_startup: got controller $1\n"; - $ARGV[$i] = "--controller=$1"; - } -} - - -sub close_failover_test_phase_2 { - print "$test: Failover to second controller succeeded\n"; -} - -print "$test: Calling run_black_box_test with @ARGV\n"; -run_black_box_test( \&close_failover_test_phase_2, \@ARGV ); # do exit this time - diff --git a/openflow/regress/projects/black_box/regress/test_failover_startup/run.pl b/openflow/regress/projects/black_box/regress/test_failover_startup/run.pl deleted file mode 100755 index 7bfee7aa..00000000 --- a/openflow/regress/projects/black_box/regress/test_failover_startup/run.pl +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/perl - -# Simple two-controller failover test -# -# For this test to work, the switch must be set up to use our -# two "controllers", e.g. -# -# ofprotocol --controller=tcp:127.0.0.1:6633,tcp:127.0.0.1:6634 -# -# If you use different ports than the defaults, then you must -# pass the --controller option into this script as well. -# -# Failover Test 1: Startup Failover -# -# For this test, we listen on the second controller port rather -# than the first. -# - -use strict; -use OF::Includes; -use Getopt::Long; - -my $test="Failover test 1 (startup failover)"; - -my $controllers; - -# Remove '--controller' from the option list... - Jean II -Getopt::Long::Configure( 'pass_through' ); -GetOptions( - "controller=s" => \$controllers -); -if (!defined($controllers)) -{ - # If no controllers specified, use default - $controllers = nftest_default_controllers(); -} -Getopt::Long::Configure( 'default' ); - -# Get controller -my @controller_array = split(/,/, $controllers); -my $failover_controller = @controller_array[1]; - -# Push back a controller string -push( @ARGV, "--controller=$failover_controller" ); - -print "$test: Calling run_black_box_test with @ARGV\n"; - -sub startup_failover_test { - print "$test: Failed over successfully\n"; -} - -run_black_box_test( \&startup_failover_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_failover_stop_responding/run.pl b/openflow/regress/projects/black_box/regress/test_failover_stop_responding/run.pl deleted file mode 100755 index 50a4a475..00000000 --- a/openflow/regress/projects/black_box/regress/test_failover_stop_responding/run.pl +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/perl -w - -# Simple two-controller failover test -# -# For this test to work, the switch must be set up to use our -# two "controllers", e.g. -# -# ofprotocol --controller=tcp:127.0.0.1:6633,tcp:127.0.0.1:6634 -# -# If you use different ports than the defaults, then you must -# pass the --controller option into this script as well. -# -# Failover test 3: Controller is fine, but stops responding -# -# For this test, we accept the Hello sequence on the first port -# but then listen for a failover connection on the second port. -# - -use strict; -use OF::Includes; - -# Save ARGV for future reference -my @ARGS = @ARGV; - -my $test="Failover test 3 (controller stops responding)"; - -print "$test phase 1: calling run_black_box_test with @ARGV\n"; - -# Start up, say Hello, and close connection -sub stop_responding_test_phase_1 { - my ($sock) = @_; - print "$test: Got socket $sock\n"; - print "$test: Finished Hello sequence on first controller\n"; - print "$test: Not closing socket\n"; - print "$test: Invoking phase 2\n"; - stop_responding_phase_2(); -} - -run_black_box_test( \&stop_responding_test_phase_1, \@ARGV, 1); # 1 -> don't exit - -sub stop_responding_phase_2 { - - # Now, attempt to open up the second controller connection, and - # hope that we fail over - - # Restore ARGV - @ARGV = @ARGS; - - # If no controllers specified, use default - if (not "@ARGV" =~ "--controller") { - push( @ARGV, "--controller=" . nftest_default_controllers() ); - } - - # Replace --controller=foo,bar with --controller=bar so that - # run_black_box_test() will use bar's port rather than foo's - for (my $i = 0; $i < @ARGV; $i++) { - if ($ARGV[$i] =~ /controller=[^,]*,([^\s]+)/ ) { - print "$test: got controller $1\n"; - $ARGV[$i] = "--controller=$1"; - } - } - - print "$test: Calling run_black_box_test with @ARGV\n"; - run_black_box_test( \&close_failover_test_phase_2, \@ARGV ); # do exit this time -} diff --git a/openflow/regress/projects/black_box/regress/test_flow_expired/run.pl b/openflow/regress/projects/black_box/regress/test_flow_expired/run.pl deleted file mode 100755 index 97ea35cc..00000000 --- a/openflow/regress/projects/black_box/regress/test_flow_expired/run.pl +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/perl -w -# test_flow_expired - -use strict; -use OF::Includes; - -sub my_test { - - my ($sock, $options_ref) = @_; - - my $in_port = $$options_ref{'port_base'}; - my $out_port = $in_port + 1; - - my $test_pkt = get_default_black_box_pkt( $in_port, $out_port); - - my $max_idle = 0x1; # second before flow expiration - my $wildcards = 0x0; # exact match - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry - my $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); - - #print HexDump($pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - - my $pkt_len = 0; - my $pkt_total = 0; - wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); - -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_flow_expired_idle_timeout/run.pl b/openflow/regress/projects/black_box/regress/test_flow_expired_idle_timeout/run.pl deleted file mode 100755 index 5fa74924..00000000 --- a/openflow/regress/projects/black_box/regress/test_flow_expired_idle_timeout/run.pl +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/perl -w -# test_flow_expired - -use strict; -use OF::Includes; - -sub my_test { - - my ($sock, $options_ref) = @_; - - my $in_port = $$options_ref{'port_base'}; - my $out_port = $in_port + 1; - - my $test_pkt = get_default_black_box_pkt( $in_port, $out_port); - - my $max_idle = 0x1; # second before flow expiration - my $wildcards = 0x0; # exact match - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; - my $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); - - #print HexDump($pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - - my $pkt_len = 0; - my $pkt_total = 0; - wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total, $max_idle ); - -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_flow_expired_precision/run.pl b/openflow/regress/projects/black_box/regress/test_flow_expired_precision/run.pl deleted file mode 100755 index 798f6b89..00000000 --- a/openflow/regress/projects/black_box/regress/test_flow_expired_precision/run.pl +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/perl -w -# test_flow_expired -# This test checks if the flow duration time is in a reasonable range. -# This test assumes a reference switch as a target. -# The switch polls flow expiration every 1 sec with jitter, -# so we should expect 1sec difference for flow_duration. - -use strict; -use OF::Includes; - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - my $in_port = $$options_ref{'port_base'}; - my $out_port = $in_port + 1; - - my $test_pkt = get_default_black_box_pkt( $in_port, $out_port ); - - my $max_idle = 0x1; # second before flow expiration - my $wildcards = 0x0; # exact match - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry - my $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, - $flags, $wildcards ); - - #print HexDump($pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - - my $pkt_len = 0; - my $pkt_total = 0; - - my $read_size = 1512; - - my $recvd_mesg; - sysread( $sock, $recvd_mesg, $read_size ) - || die "Failed to receive ofp_flow_removed message: $!"; - - # Inspect message - my $msg_size = length($recvd_mesg); - my $expected_size = $ofp->sizeof('ofp_flow_removed'); - compare( "ofp_flow_removed msg size", - length($recvd_mesg), '==', $expected_size ); - - my $msg = $ofp->unpack( 'ofp_flow_removed', $recvd_mesg ); - - print Dumper($msg); - - my $sample_period = 1; - - compare( "ofp_flow_removed packet_count", - $$msg{'packet_count'}, '==', $pkt_total ); - print "Duretion_sec : $$msg{'duration_sec'} sec\n"; - print "Duration_nsec: $$msg{'duration_nsec'} nano sec\n"; - - if (($$msg{'duration_sec'} < $max_idle) - || ($$msg{'duration_sec'} > ($max_idle + $sample_period))) { - die "Error, duration_sec out of acceptable range"; - } - -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_flow_expired_send_flow_exp/run.pl b/openflow/regress/projects/black_box/regress/test_flow_expired_send_flow_exp/run.pl deleted file mode 100755 index 4a47caef..00000000 --- a/openflow/regress/projects/black_box/regress/test_flow_expired_send_flow_exp/run.pl +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/perl -w -# test_flow_expired - -use strict; -use OF::Includes; -use IO::Select; - -sub my_test { - - my ($sock, $options_ref) = @_; - - my $in_port = $$options_ref{'port_base'}; - my $out_port = $in_port + 1; - - my $test_pkt = get_default_black_box_pkt( $in_port, $out_port); - - my $max_idle = 0x1; # second before flow expiration - my $wildcards = 0x0; # exact match - # Create a flow mod without expiry - my $flags = 0x0; # don't send flow expiry - my $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); - print $sock $flow_mod_pkt; - - my $sel = IO::Select->new($sock); - if ($sel->can_read(2 * $max_idle)) { - print "Error: was not expecting a message from the switch\n"; - exit 1; - } - - # Create a flow mod with expiry - $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry - $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); - print $sock $flow_mod_pkt; - - my $pkt_len = 0; - my $pkt_total = 0; - wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); - -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_flow_mod_check/run.pl b/openflow/regress/projects/black_box/regress/test_flow_mod_check/run.pl deleted file mode 100755 index 1c0b7f76..00000000 --- a/openflow/regress/projects/black_box/regress/test_flow_mod_check/run.pl +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/perl -w -# test_flow_mod_check - -use strict; -use OF::Includes; - -sub wait_for_flow_overlap_error { - my ($ofp, $sock, $flow_mod_pkt) = @_; - my $rcvd_msg; - - sysread($sock, $rcvd_msg, 1512); - - my $msg_size = length($rcvd_msg); - my $expected_size = $ofp->sizeof('ofp_error_msg') + length($flow_mod_pkt); - compare("msg size", $msg_size, '==', $expected_size); - - my $msg = $ofp->unpack('ofp_error_msg', $rcvd_msg); - verify_header($msg, 'OFPT_ERROR', $msg_size); - - compare("error type", $$msg{'type'}, '==', $enums{'OFPET_FLOW_MOD_FAILED'}); - compare("error code", $$msg{'code'}, '==', $enums{'OFPFMFC_OVERLAP'}); -} - -sub my_test { - my ($sock, $options_ref) = @_; - - my $in_port = $$options_ref{'port_base'}; - my $out_port_1 = $in_port + 1; - my $out_port_2 = $in_port + 2; - my $out_port_3 = $in_port + 3; - - my $test_pkt = get_default_black_box_pkt($in_port, $out_port_1); - - - my $wildcards = 0x0c0; - my $flags = $enums{'OFPFF_CHECK_OVERLAP'}; - my $max_idle = 0x0; # never expire - my $flow_mod_pkt = create_flow_mod_from_udp($ofp, $test_pkt, $in_port, $out_port_1, $max_idle, $flags, $wildcards); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - - # change the wildcard and send again. this should fail - $wildcards = 0x0c1; - my $flags = $enums{'OFPFF_CHECK_OVERLAP'}; - $flow_mod_pkt = create_flow_mod_from_udp($ofp, $test_pkt, $in_port+1, $out_port_2, $max_idle, $flags, $wildcards); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - - wait_for_flow_overlap_error($ofp, $sock, $flow_mod_pkt); - - # Start with coarse granularity flow - # edge-case bug reported by Justin - # https://mailman.stanford.edu/pipermail/openflow-dev/2009-November/000529.html - $wildcards = 0x0c1; - $flags = 0x0; - $flow_mod_pkt = create_flow_mod_from_udp($ofp, $test_pkt, $in_port, $out_port_1, $max_idle, $flags, $wildcards); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - - # change the wildcard and send again. this should fail - $wildcards = 0x0c0; - $flags = $enums{'OFPFF_CHECK_OVERLAP'}; - $flow_mod_pkt = create_flow_mod_from_udp($ofp, $test_pkt, $in_port+1, $out_port_2, $max_idle, $flags, $wildcards); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - - wait_for_flow_overlap_error($ofp, $sock, $flow_mod_pkt); - - - -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_flow_mod_latency/run-port3.pl b/openflow/regress/projects/black_box/regress/test_flow_mod_latency/run-port3.pl deleted file mode 100644 index 204873b7..00000000 --- a/openflow/regress/projects/black_box/regress/test_flow_mod_latency/run-port3.pl +++ /dev/null @@ -1,136 +0,0 @@ -#!/usr/bin/perl -w -# test_flow_mod_latency -# -# Don't include this test as part of the official test suite, -# as it is not supposed to pass... -# -# Run it like this : -# ./bin/of_hp_test.pl --testPath=black_box/regress/test_flow_mod_latency/run.pl -# -# Check the number of packets received : -# tcpdump -p -i eth11 -w stanford.test.log -# tcpdump -r stanford.test.log | wc -# -# On the HP, it requires increasing the SW rate limiter : -# openflow 9 sw-rate 5000 -# -# Jean II - -use strict; -use OF::Includes; - -sub forward_flow_mod_latency { - - my ($sock, $options_ref) = @_; - my $in_port = $$options_ref{'port_base'}; - my $out_port = $in_port + 1; - my $fallback_port = $out_port + 1; - - my $len = $$options_ref{'pkt_len'}; - my $wildcards = 0x0; # exact match - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; - my $pkt_args; - my $test_pkt; - my $flow_mod_pkt; - my $i; - - if (1) { - # Create a flow mod to track all packets sent to the controller - # We create a wildcard on both transport port, that sends - # packets to the controller - Jean II - $pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $len, - src_port => 0, - dst_port => 0 - }; - $test_pkt = new NF2::UDP_pkt(%$pkt_args); - $wildcards = $enums{'OFPFW_TP_SRC'} | $enums{'OFPFW_TP_DST'}; - print"wildcards = $wildcards\n"; - # Full experiment is around 15s - $flow_mod_pkt = create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $fallback_port, 25, $flags, $wildcards ); - syswrite( $sock, $flow_mod_pkt ); - print "sent flow_mod message with wildcard\n"; - - # Make sure the flow mod is properly inserted and the - # OpenFlow instance properly started. The OpenFlow instance - # takes time to get started, we want to make sure this is - # not a factor. Jean II - sleep(1); - - # No more wildcards - $wildcards = 0x0; # exact match - } - - # Let's create 100 sequencial connections - Jean II - for ( my $c = 0 ; $c < 100 ; $c++ ) { - - # Packets for creating the flow mod - $pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $len, - src_port => 2000 + $c, - dst_port => 4000 + $c - }; - $test_pkt = new NF2::UDP_pkt(%$pkt_args); - - # Let's create a long lived flow mod - $flow_mod_pkt = create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, 20, $flags, $wildcards ); - - # Send 'flow_mod' message - syswrite( $sock, $flow_mod_pkt ); - print "sent flow_mod message for connection $c\n"; - - # Test packet to be sent - should match flow mod - $pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $len, - src_port => 2000 + $c, - dst_port => 4000 + $c - }; - $test_pkt = new NF2::UDP_pkt(%$pkt_args); - - # For this test, the TCAM is much slower. Wait a bit more - # to get more interesting results. I also increased pkt count. - # Jean II - usleep(20000); - - # Max in SW is around 5000 pkts/sec - # Note : default rate limiter value is 100 pkts/sec, which is - # one packet every 10s, so you can't run at default value - # Send 15 packets as a short burst over 60ms - for ($i = 0 ; $i < 15 ; $i++ ) { - - # Wait 4 ms between packets - usleep(4000); - - # Send test packet - nftest_send( "eth" . ($in_port), $test_pkt->packed ); - - # This does not block, so we are good... - nftest_expect( "eth" . ($out_port), $test_pkt->packed ); - } - - # We don't wait for flow expiry, that's too long waiting - Jean II - } - - # Wait for stats to refresh - # For most flow mod, we should be about half life, which means - # they have not expired yet, and have already got stats a few time. - sleep(6); - dpctl_show_flows($options_ref); -} - -run_black_box_test( \&forward_flow_mod_latency, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_flow_mod_latency/run.pl b/openflow/regress/projects/black_box/regress/test_flow_mod_latency/run.pl deleted file mode 100755 index 49789383..00000000 --- a/openflow/regress/projects/black_box/regress/test_flow_mod_latency/run.pl +++ /dev/null @@ -1,129 +0,0 @@ -#!/usr/bin/perl -w -# test_flow_mod_latency -# -# Don't include this test as part of the official test suite, -# as it is not supposed to pass... -# -# Run it like this : -# ./bin/of_hp_test.pl --testPath=black_box/regress/test_flow_mod_latency/run.pl -# -# Check the number of packets received : -# tcpdump -p -i eth11 -w stanford.test.log -# tcpdump -r stanford.test.log | wc -# -# On the HP, it requires increasing the SW rate limiter : -# openflow 9 sw-rate 5000 -# -# Jean II - -use strict; -use OF::Includes; - -sub forward_flow_mod_latency { - - my ($sock, $options_ref) = @_; - my $in_port = $$options_ref{'port_base'}; - my $out_port = $in_port + 1; - - my $len = $$options_ref{'pkt_len'}; - my $wildcards = 0x0; # exact match - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; - my $pkt_args; - my $test_pkt; - my $flow_mod_pkt; - my $i; - - if (1) { - # Create a flow mod to track all packets sent to the controller - # We create a wildcard on both transport port, that sends - # packets to the controller - Jean II - $pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $len, - src_port => 0, - dst_port => 0 - }; - $test_pkt = new NF2::UDP_pkt(%$pkt_args); - $wildcards = $enums{'OFPFW_TP_SRC'} | $enums{'OFPFW_TP_DST'}; - print"wildcards = $wildcards\n"; - $flow_mod_pkt = create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $enums{'OFPP_CONTROLLER'}, 20, $flags, $wildcards ); - syswrite( $sock, $flow_mod_pkt ); - print "sent flow_mod message with wildcard\n"; - - # Make sure the flow mod is properly inserted and the - # OpenFlow instance properly started. The OpenFlow instance - # takes time to get started, we want to make sure this is - # not a factor. Jean II - sleep(1); - - # No more wildcards - $wildcards = 0x0; # exact match - } - - # Let's create 100 sequencial connections - Jean II - for ( my $c = 0 ; $c < 100 ; $c++ ) { - - # Packets for creating the flow mod - $pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $len, - src_port => 2000 + $c, - dst_port => 4000 + $c - }; - $test_pkt = new NF2::UDP_pkt(%$pkt_args); - - # Let's create a long lived flow mod - $flow_mod_pkt = create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, 15, $flags, $wildcards ); - - # Send 'flow_mod' message - syswrite( $sock, $flow_mod_pkt ); - print "sent flow_mod message for connection $c\n"; - - # Test packet to be sent - should match flow mod - $pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $len, - src_port => 2000 + $c, - dst_port => 4000 + $c - }; - $test_pkt = new NF2::UDP_pkt(%$pkt_args); - - # Max in SW is around 5000 pkts/sec - # Note : default rate limiter value is 100 pkts/sec, which is - # one packet every 10s, so you can't run at default value - # Send 5 packets as a short burst over 20ms - for ($i = 0 ; $i < 5 ; $i++ ) { - - # Wait 4 ms between packets - usleep(4000); - - # Send test packet - nftest_send( "eth" . ($in_port), $test_pkt->packed ); - - # This does not block, so we are good... - nftest_expect( "eth" . ($out_port), $test_pkt->packed ); - } - - # We don't wait for flow expiry, that's too long waiting - Jean II - } - - # Wait for stats to refresh - # For most flow mod, we should be about half life, which means - # they have not expired yet, and have already got stats a few time. - sleep(6); - dpctl_show_flows($options_ref); -} - -run_black_box_test( \&forward_flow_mod_latency, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_flow_stats/run.pl b/openflow/regress/projects/black_box/regress/test_flow_stats/run.pl deleted file mode 100755 index eeea50a6..00000000 --- a/openflow/regress/projects/black_box/regress/test_flow_stats/run.pl +++ /dev/null @@ -1,145 +0,0 @@ -#!/usr/bin/perl -w -# test_flow_stats - -use strict; -use OF::Includes; - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - my $port_base = $$options_ref{'port_base'}; - - my $hdr_args = { - version => get_of_ver(), - type => $enums{'OFPT_STATS_REQUEST'}, - length => $ofp->sizeof('ofp_stats_request') + $ofp->sizeof('ofp_flow_stats_request'), # should generate automatically! - xid => 0x00000000 - }; - - my $match_args = { - wildcards => 0x3ef, - in_port => 0, - dl_src => [], - dl_dst => [], - dl_vlan => 0, - dl_type => 0x800, - nw_src => (NF2::IP_hdr::getIP('192.168.200.1'))[0], - nw_dst => (NF2::IP_hdr::getIP('192.168.201.2'))[0], - nw_proto => 0, - tp_src => 0, - tp_dst => 0 - }; - - my $stats_request_args = { - header => $hdr_args, - type => $enums{'OFPST_FLOW'}, - flags => 0 - }; - - my $body_args = { - match => $match_args, - table_id => 0xff, #match all tables - out_port => $enums{'OFPP_NONE'}, - }; - - my $body = $ofp->pack('ofp_flow_stats_request', $body_args ); - - my $stats_request = $ofp->pack( 'ofp_stats_request', $stats_request_args ); - - my $mesg = $stats_request . $body; - - # Send 'stats_request' message - print $sock $mesg; - - # Should add timeout here - will crash if no reply - my $recvd_mesg; - sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; - - # Inspect message - my $msg_size = length($recvd_mesg); - - my $msg = $ofp->unpack( 'ofp_stats_reply', $recvd_mesg ); - - #print HexDump ($recvd_mesg); - print Dumper($msg); - - # Verify fields - verify_header( $msg, 'OFPT_STATS_REPLY', $msg_size ); - - #---------------------- - - # add flow mod, send pkt - { - - my $in_port_offset = 0; - my $out_port_offset = 1; - my $wildcards = 0x3ef; - my $wait = 5; - - #$$options_ref{'send_delay'} = 5; - - forward_simple ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $wildcards, 'any', 1); - -# my $in_port = $in_port_offset + $$options_ref{'port_base'}; -# my $out_port = $out_port_offset + $$options_ref{'port_base'}; -# -# my $test_pkt = get_default_black_box_pkt_len( $in_port, $out_port, $$options_ref{'pkt_len'} ); -# my $flow_mod_pkt = -# create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $wait, $wildcards ); -# -# print $sock $flow_mod_pkt; -# -# # Give OF switch time to process the flow mod -# usleep($$options_ref{'send_delay'}); -# -# nftest_send( "eth" . ($in_port_offset + 1), $test_pkt->packed ); - } - - sleep .1; - - - # Send 'stats_request' message - print $sock $mesg; - - # Should add timeout here - will crash if no reply - my $recvd_mesg; - sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; - - # Inspect message - my $msg_size = length($recvd_mesg); - - my $msg = $ofp->unpack( 'ofp_stats_reply', $recvd_mesg ); - - # Strip off the header from the received message - $recvd_mesg = substr($recvd_mesg, $ofp->sizeof('ofp_stats_reply')); - - # Unpack each of the ofp_flow_stats messages - my $flow_stats_len = $ofp->sizeof('ofp_flow_stats'); - while (length($recvd_mesg) > 0) { - if (length($recvd_mesg) < $flow_stats_len) {\ - die "Error: Partial flow stats message received"; - } - my $flow_stats = $ofp->unpack('ofp_flow_stats', $recvd_mesg); - - push @{$msg->{'body'}}, $flow_stats; - $recvd_mesg = substr($recvd_mesg, $flow_stats->{'length'}); - } - - #print HexDump ($recvd_mesg); - print Dumper($msg); - - # Verify fields - verify_header( $msg, 'OFPT_STATS_REPLY', $msg_size ); - - # Ensure that we got back one ofp_flow_stats body - compare( "stats_reply flow_stats count", scalar(@{$msg->{'body'}}), '==', 1 ); - - - #wait_for_flow_expired_all( $ofp, $sock, $options_ref ); - - -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_flow_stats_precision/run.pl b/openflow/regress/projects/black_box/regress/test_flow_stats_precision/run.pl deleted file mode 100755 index 06dc1ae5..00000000 --- a/openflow/regress/projects/black_box/regress/test_flow_stats_precision/run.pl +++ /dev/null @@ -1,191 +0,0 @@ -#!/usr/bin/perl -w -# test_flow_stats -# This test assumes a lightly loaded switch that can measure and reply to -# flow stats requests within 500ms of receiving the request. - -use strict; -use OF::Includes; - -sub my_test { - - my ( $sock, $options_ref ) = @_; - my $time_threshold = 500000000; - my $port_base = $$options_ref{'port_base'}; - - my $hdr_args = { - version => get_of_ver(), - type => $enums{'OFPT_STATS_REQUEST'}, - length => $ofp->sizeof('ofp_stats_request') + - $ofp->sizeof('ofp_flow_stats_request') - , # should generate automatically! - xid => 0x00000000 - }; - - my $match_args = { - wildcards => 0x3ef, - in_port => 0, - dl_src => [], - dl_dst => [], - dl_vlan => 0, - dl_type => 0x800, - nw_src => ( NF2::IP_hdr::getIP("192.168.200.1") )[0], - nw_dst => ( NF2::IP_hdr::getIP("192.168.201.2") )[0], - nw_proto => 0, - tp_src => 0, - tp_dst => 0 - }; - - my $stats_request_args = { - header => $hdr_args, - type => $enums{'OFPST_FLOW'}, - flags => 0 - }; - - my $body_args = { - match => $match_args, - table_id => 0xff, #match all tables - out_port => $enums{'OFPP_NONE'}, - }; - - my $body = $ofp->pack( 'ofp_flow_stats_request', $body_args ); - - my $stats_request = $ofp->pack( 'ofp_stats_request', $stats_request_args ); - - my $mesg = $stats_request . $body; - - # Send 'stats_request' message - print $sock $mesg; - - # Should add timeout here - will crash if no reply - my $recvd_mesg; - sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; - - # Inspect message - my $msg_size = length($recvd_mesg); - - my $msg = $ofp->unpack( 'ofp_stats_reply', $recvd_mesg ); - - #print HexDump ($recvd_mesg); - print Dumper($msg); - - # Verify fields - verify_header( $msg, 'OFPT_STATS_REPLY', $msg_size ); - - #---------------------- - - # add flow mod, send pkt - { - my $in_port_offset = 0; - my $out_port_offset = 1; - my $wildcards = 0x3ef; - my $wait = 5; - - forward_simple( $ofp, $sock, $options_ref, $in_port_offset, - $out_port_offset, $wildcards, 'any', 1 ); - } - - sleep .1; - - # Send 'stats_request' message - print $sock $mesg; - - # Should add timeout here - will crash if no reply - my $recvd_mesg; - sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; - - # Inspect message - my $msg_size = length($recvd_mesg); - - my $msg = $ofp->unpack( 'ofp_stats_reply', $recvd_mesg ); - - # Strip off the header from the received message - $recvd_mesg = substr( $recvd_mesg, $ofp->sizeof('ofp_stats_reply') ); - - # Unpack each of the ofp_flow_stats messages - my $flow_stats_len = $ofp->sizeof('ofp_flow_stats'); - while ( length($recvd_mesg) > 0 ) { - if ( length($recvd_mesg) < $flow_stats_len ) { - die "Error: Partial flow stats message received"; - } - my $flow_stats = $ofp->unpack( 'ofp_flow_stats', $recvd_mesg ); - - push @{ $msg->{'body'} }, $flow_stats; - $recvd_mesg = substr( $recvd_mesg, $flow_stats->{'length'} ); - } - - #print HexDump ($recvd_mesg); - print Dumper($msg); - - # Verify fields - verify_header( $msg, 'OFPT_STATS_REPLY', $msg_size ); - - # Ensure that we got back one ofp_flow_stats body - compare( - "stats_reply flow_stats count", - scalar( @{ $msg->{'body'} } ), - '==', 1 - ); - if ( $msg->{'body'}[0]->{'duration_sec'} != 0 ) { - die "Error, duration_sec out of acceptable range"; - } - if ( $msg->{'body'}[0]->{'duration_nsec'} < 100000000 - || $msg->{'body'}[0]->{'duration_nsec'} > (100000000+$time_threshold) ) - { - die "Error, duration_nsec out of acceptable range"; - } - - # Sleep 1 more second to test duration_sec - sleep 1.0; - - # Send 'stats_request' message - print $sock $mesg; - - # Should add timeout here - will crash if no reply - my $recvd_mesg; - sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; - - # Inspect message - my $msg_size = length($recvd_mesg); - - my $msg = $ofp->unpack( 'ofp_stats_reply', $recvd_mesg ); - - # Strip off the header from the received message - $recvd_mesg = substr( $recvd_mesg, $ofp->sizeof('ofp_stats_reply') ); - - # Unpack each of the ofp_flow_stats messages - my $flow_stats_len = $ofp->sizeof('ofp_flow_stats'); - while ( length($recvd_mesg) > 0 ) { - if ( length($recvd_mesg) < $flow_stats_len ) { - die "Error: Partial flow stats message received"; - } - my $flow_stats = $ofp->unpack( 'ofp_flow_stats', $recvd_mesg ); - - push @{ $msg->{'body'} }, $flow_stats; - $recvd_mesg = substr( $recvd_mesg, $flow_stats->{'length'} ); - } - - #print HexDump ($recvd_mesg); - print Dumper($msg); - - # Verify fields - verify_header( $msg, 'OFPT_STATS_REPLY', $msg_size ); - - # Ensure that we got back one ofp_flow_stats body - compare( - "stats_reply flow_stats count", - scalar( @{ $msg->{'body'} } ), - '==', 1 - ); - if ( $msg->{'body'}[0]->{'duration_sec'} != 1 ) { - die "Error, duration_sec out of acceptable range"; - } - if ( $msg->{'body'}[0]->{'duration_nsec'} < 100000000 - || $msg->{'body'}[0]->{'duration_nsec'} > (100000000+$time_threshold) ) - { - die "Error, duration_nsec out of acceptable range"; - } - -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_forward_after_expiration/run.pl b/openflow/regress/projects/black_box/regress/test_forward_after_expiration/run.pl deleted file mode 100755 index 347051ca..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_after_expiration/run.pl +++ /dev/null @@ -1,111 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_after_expiration - -use strict; -use OF::Includes; - -sub send_expect_exact { - - my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset ) = @_; - - my $in_port = $in_port_offset + $$options_ref{'port_base'}; - my $out_port = $out_port_offset + $$options_ref{'port_base'}; - - my $test_pkt = get_default_black_box_pkt_len( $in_port, $out_port, $$options_ref{'pkt_len'} ); - - #print HexDump ( $test_pkt->packed ); - - my $wildcards = 0x0; # exact match - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; - - my $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, - $$options_ref{'max_idle'}, $flags, $wildcards ); - - #print HexDump($flow_mod_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent flow_mod message\n"; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - - # Send a packet - ensure packet comes out desired port - nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt->packed ); - nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); -} - -sub send_expect_secchan_nomatch { - - my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len ) = @_; - - my $in_port = $in_port_offset + $$options_ref{'port_base'}; - my $out_port = $out_port_offset + $$options_ref{'port_base'}; - - my $test_pkt2 = get_default_black_box_pkt_len( $in_port, $out_port, $$options_ref{'pkt_len'} ); - - print "sending out eth" - . ( $in_port_offset + 1 ) - . ", expecting response on secchan due to no flow matching\n"; - - # Send a packet - ensure packet comes out desired port - nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt2->packed ); - - my $recvd_mesg; - sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; - - # Inspect message - my $msg_size = length($recvd_mesg); - my $expected_size = $ofp->offsetof( 'ofp_packet_in', 'data' ) + length( $test_pkt2->packed ); - compare( "msg size", $msg_size, '==', $expected_size ); - - my $msg = $ofp->unpack( 'ofp_packet_in', $recvd_mesg ); - - #print HexDump ($recvd_mesg); - #print Dumper($msg); - - # Verify fields - - print "Verifying secchan message for packet sent in to eth" . ( $in_port_offset + 1 ) . "\n"; - - verify_header( $msg, 'OFPT_PACKET_IN', $msg_size ); - - compare( "total len", $$msg{'total_len'}, '==', length( $test_pkt2->packed ) ); - compare( "in_port", $$msg{'in_port'}, '==', $in_port ); - compare( "reason", $$msg{'reason'}, '==', $enums{'OFPR_NO_MATCH'} ); - - # verify packet was unchanged! - my $recvd_pkt_data = substr( $recvd_mesg, $ofp->offsetof( 'ofp_packet_in', 'data' ) ); - if ( $recvd_pkt_data ne $test_pkt2->packed ) { - die "ERROR: sending from eth" - . $in_port + 1 - . " received packet data didn't match packet sent\n"; - } - -} - -sub test_forward_after_expiration { - - my ( $ofp, $sock, $options_ref, $i, $j, $wildcards ) = @_; - - my $max_idle = $$options_ref{'max_idle'}; - my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_total = $$options_ref{'pkt_total'}; - - send_expect_exact( $ofp, $sock, $options_ref, $i, $j); - print "waiting for flow to expire\n"; - wait_for_flow_expired_all( $ofp, $sock, $options_ref ); - usleep($$options_ref{'send_delay'}); - send_expect_secchan_nomatch( $ofp, $sock, $options_ref, $i, $j); -} - -sub my_test { - - my ($sock, $options_ref) = @_; - - # send from every port to every other port - for_all_port_pairs( $ofp, $sock, $options_ref, \&test_forward_after_expiration, 0x0); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_any_port/run.pl b/openflow/regress/projects/black_box/regress/test_forward_any_port/run.pl deleted file mode 100755 index 83c07e1d..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_any_port/run.pl +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_any_port - -use strict; -use OF::Includes; - -sub forward_any { - - forward_simple(@_, 'any'); -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_any, 0xfffff); -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_forward_bandwidth_fixed/run.pl b/openflow/regress/projects/black_box/regress/test_forward_bandwidth_fixed/run.pl deleted file mode 100755 index 44ac6ec9..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_bandwidth_fixed/run.pl +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_bandwidth_fixed - -use strict; -use OF::Includes; - -my $pkt_len = 1512; -my $pkt_total = 1000; -my $max_idle = 2; - -sub send_expect_exact { - - my ( $ofp, $sock, $in_port, $out_port, $max_idle, $pkt_len ) = @_; - my %delta; - - # in_port refers to the flow mod entry's input - - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - src_port => 1, - dst_port => 0 - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - #print HexDump ( $test_pkt->packed ); - - my $wildcards = 0x0; # exact match - #my $wildcards = 0x2; # only wildcard the vlan - #my $wildcards = 0x2FF; # exact match - #my $wildcards = 0x3FE; # exact match on switch in port - #my $wildcards = 0x3DF; # exact match on src ip - #my $wildcards = 0x1; # exact match on eth src/dest/eth frame/ipsrcdest/128ipproto/256port source - #my $wildcards = 0x3BF; # exact match on dest ip - #my $wildcards = 0x3FD; # exact match on vlan - #my $wildcards = 0x3FB; # exact match on ether source - #my $wildcards = 0x3F7; # exact match on ether dest - my $flags = 0x0; # don't send flow expiry - - my $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, - $max_idle, $flags, $wildcards ); - - #print HexDump($flow_mod_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent flow_mod message\n"; - - usleep(200000); - my @start_time = gettimeofday(); - for (my $k = 0; $k < $pkt_total; $k++) { - send_and_count( nftest_get_iface( "eth" . ( $in_port + 1 ) ), - $test_pkt->packed, \%delta ); - expect_and_count( nftest_get_iface( "eth" . ( $out_port + 1 ) ), - $test_pkt->packed, \%delta ); - } - (my $second, my $micro) = tv_interval(\@start_time); - my $time_elapsed = ($second + $micro * 1e-6); - my $bw_result = ($pkt_total * $pkt_len * 8) / $time_elapsed; - print "PACKET LENGTH: $pkt_len \n"; - print "PACKETS SENT: $pkt_total\n"; - print "TIME ELAPSED: $time_elapsed \n"; - print "RESULTING BW: $bw_result bits/sec \n"; - -} - -sub my_test { - - my ($sock, $options_ref) = @_; - - my $inport = 0; - my $outport = 1; - print "Checking forwarding bandwidth from $inport to $outport\n"; - send_expect_exact( $ofp, $sock, $inport, $outport, $max_idle, $pkt_len ); - wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); -} - -run_black_box_test( \&my_test ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_bandwidth_random/run.pl b/openflow/regress/projects/black_box/regress/test_forward_bandwidth_random/run.pl deleted file mode 100755 index 4fa05282..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_bandwidth_random/run.pl +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_bandwidth_fixed - -use strict; -use OF::Includes; - -my $pkt_total = 1000; -my $max_idle = 2; - -# Maximum and minimum packet sizes -my $min_length = 64; -my $max_length = 1512; - -sub send_expect_exact { - - my ( $ofp, $sock, $in_port, $out_port, $max_idle) = @_; - my %delta; - - # in_port refers to the flow mod entry's input - - my @packets; - my $bytes = 0; - for (my $i = 0; $i < $pkt_total; $i++) { - my $pkt_len = int(rand($max_length - $min_length)) + $min_length; - $bytes += $pkt_len; - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port + 1 ), - dst_ip => "192.168.201." . ( $out_port + 1 ), - ttl => 64, - len => $pkt_len, - src_port => 1, - dst_port => 0 - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - push @packets, $test_pkt; - } - - - my $wildcards = 0x1; # wild card on input port - my $flags = 0x0; # don't send flow expiry - - my $test_pkt = pop @packets; - my $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, - $max_idle, $flags, $wildcards ); - push @packets, $test_pkt; - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent flow_mod message\n"; - - usleep(200000); - my @start_time = gettimeofday(); - for (my $k = 0; $k < $pkt_total; $k++) { - my $packet = pop @packets; - my $randport = int(rand(2)); - send_and_count( nftest_get_iface( "eth" . ( $randport + 1 ) ), - $packet->packed, \%delta ); - expect_and_count( nftest_get_iface( "eth" . ( $out_port + 1 ) ), - $packet->packed, \%delta ); - } - (my $second, my $micro) = tv_interval(\@start_time); - my $time_elapsed = ($second + $micro * 1e-6); - my $bw_result = ($bytes * 8) / $time_elapsed; - print "PACKETS SENT: $pkt_total\n"; - print "BYTES SENT: $bytes\n"; - print "TIME ELAPSED: $time_elapsed \n"; - print "RESULTING BW: $bw_result bits/sec \n"; - return $bytes; -} - -sub my_test { - - my ($sock, $options_ref) = @_; - - my $inport = 0; - my $outport = 3; - my $bytes_sent = send_expect_exact( $ofp, $sock, $inport, $outport, $max_idle ); - wait_for_flow_expired_total_bytes( $ofp, $sock, $options_ref, $bytes_sent, $pkt_total ); -} - -run_black_box_test( \&my_test ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_broadcast_exact_port/run.pl b/openflow/regress/projects/black_box/regress/test_forward_broadcast_exact_port/run.pl deleted file mode 100755 index 03bf655b..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_broadcast_exact_port/run.pl +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_exact_port - -use strict; -use OF::Includes; - -sub forward_broadcast { - - my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $wildcards, $type, $nowait ) = @_; - - my $in_port = $in_port_offset + $$options_ref{'port_base'}; - my $out_port; - - $out_port = $out_port_offset + $$options_ref{'port_base'}; - - my $len = $$options_ref{'pkt_len'}; - my $pkt_args = { - DA => "FF:FF:FF:FF:FF:FF", - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168." . ( $in_port ) . "." . ( $out_port ), - dst_ip => "255.255.255.255", - ttl => 64, - len => $len, - src_port => 1, - dst_port => 0 - }; - my $test_pkt = new NF2::UDP_pkt(%$pkt_args); - - my $flow_mod_pkt; - - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; - $flow_mod_pkt = create_flow_mod_from_udp($ofp, $test_pkt, $in_port, $out_port, $$options_ref{'max_idle'}, $flags, $wildcards); - - # Send 'flow_mod' message - syswrite( $sock, $flow_mod_pkt ); - print "sent flow_mod message\n"; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - - nftest_send( "eth" . ($in_port_offset + 1), $test_pkt->packed ); - - # expect single packet - print "expect single packet\n"; - nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); - - print "wait \n"; - wait_for_flow_expired_all( $ofp, $sock, $options_ref ); -} - - -sub forward_port { - - forward_broadcast(@_, 'port'); -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_port, 0x0); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_all/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_all/run.pl deleted file mode 100755 index 052ebbeb..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_exact_all/run.pl +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_exact_all - -use strict; -use OF::Includes; - -sub forward_all { - - forward_simple(@_, 'all'); -} - -sub forward_all_vlan { - my $vlan_id = 0xa5f3; - #[15:13] priority, [11:0] vlan id - #The value was chosen at random - forward_simple(@_, 'all', undef, undef, $vlan_id); -} - - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_ports( $ofp, $sock, $options_ref, \&forward_all, 0x0); - if ( not defined( $$options_ref{'no_vlan'} ) ) { - for_all_ports( $ofp, $sock, $options_ref, \&forward_all_vlan, 0x0); - } -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_arp_all/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_arp_all/run.pl deleted file mode 100755 index 0f44f91f..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_exact_arp_all/run.pl +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_exact_arp_all - -use strict; -use OF::Includes; - -sub forward_all { - - forward_simple_arp(@_, 'all', 0); # 0: fool_flg = off -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_ports( $ofp, $sock, $options_ref, \&forward_all, 0x0); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_arp_controller/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_arp_controller/run.pl deleted file mode 100755 index e7de7bad..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_exact_arp_controller/run.pl +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_exact_arp_controller - -use strict; -use OF::Includes; - -sub forward_controller { - - forward_simple_arp(@_, 'controller', 0); # 0: fool_flg = off -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_ports( $ofp, $sock, $options_ref, \&forward_controller, 0x0); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_arp_fool/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_arp_fool/run.pl deleted file mode 100755 index 076dfc42..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_exact_arp_fool/run.pl +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_exact_arp_fool - -use strict; -use OF::Includes; - -sub forward_port { - - forward_simple_arp(@_, 'port', 1); # 1: fool_flg=on -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_port, 0x0); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_arp_port/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_arp_port/run.pl deleted file mode 100755 index b0af883e..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_exact_arp_port/run.pl +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_exact_arp_port - -use strict; -use OF::Includes; - -sub forward_port { - - forward_simple_arp(@_, 'port', 0); # 0: fool_flg = off -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_port, 0x0); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_controller/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_controller/run.pl deleted file mode 100755 index e0888d16..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_exact_controller/run.pl +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_exact_controller - -use strict; -use OF::Includes; - -use strict; -use OF::Includes; - -sub forward_controller { - - forward_simple(@_, 'controller'); -} - -sub forward_controller_vlan { - my $vlan_id = 0xc123; - #[15:13] priority, [11:0] vlan id - #The value was chosen at random - forward_simple(@_, 'controller', undef, undef, $vlan_id); -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_ports( $ofp, $sock, $options_ref, \&forward_controller, 0x0); - if ( not defined( $$options_ref{'no_vlan'} ) ) { - for_all_ports( $ofp, $sock, $options_ref, \&forward_controller_vlan, 0x0); - } -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_all/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_all/run.pl deleted file mode 100755 index 3b1f6bfd..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_all/run.pl +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_exact_icmp_all - -use strict; -use OF::Includes; - -sub forward_all { - - forward_simple_icmp(@_, 'all', 0); # 0: fool_flg = off -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_ports( $ofp, $sock, $options_ref, \&forward_all, 0x0); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_controller/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_controller/run.pl deleted file mode 100755 index c07debe8..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_controller/run.pl +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_exact_icmp_controller - -use strict; -use OF::Includes; - -sub forward_controller { - - forward_simple_icmp(@_, 'controller', 0); # 0: fool_flg = off -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_ports( $ofp, $sock, $options_ref, \&forward_controller, 0x0); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_fool/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_fool/run.pl deleted file mode 100755 index dee5a6c2..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_fool/run.pl +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_exact_icmp_fool - -use strict; -use OF::Includes; - -sub forward_port { - - forward_simple_icmp(@_, 'port', 1); # 1: fool_flg=on -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_port, 0x0); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_port/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_port/run.pl deleted file mode 100755 index 100bc3ad..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_exact_icmp_port/run.pl +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_exact_icmp_port - -use strict; -use OF::Includes; - -sub forward_port { - - forward_simple_icmp(@_, 'port', 0); # 0: fool_flg = off -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_port, 0x0); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_modify_action/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_modify_action/run.pl deleted file mode 100755 index 805c9ad9..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_exact_modify_action/run.pl +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_exact_modify_action - -use strict; -use OF::Includes; - -sub forward_port { - - my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, - $wildcards ) = @_; - - my @chg_field; - if ( not defined( $$options_ref{'no_vlan'} ) ) { - @chg_field = ('vlan_vid', 'vlan_pcp', 'dl_src', 'dl_dst', 'nw_src', 'nw_dst', 'tp_src', 'tp_dst'); - } else { - @chg_field = ('dl_src', 'dl_dst', 'nw_src', 'nw_dst', 'tp_src', 'tp_dst'); - } - foreach (@chg_field) { - forward_simple(@_, 'port', undef, $_ ); - } -} - -sub forward_port_vlan { - my @chg_field = ('strip_vlan', 'vlan_vid', 'vlan_pcp', 'dl_src', 'dl_dst', 'nw_src', 'nw_dst', 'tp_src', 'tp_dst'); - my $vlan = 0x65a1; - #[15:13]:vlan_pcp, [11:0]:vlan_vid - #The value was chosen at random - foreach (@chg_field) { - forward_simple(@_, 'port', undef, $_, $vlan ); - } -} -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_port, 0x0); - if ( not defined( $$options_ref{'no_vlan'} ) ) { - for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_port_vlan, 0x0); - } -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_exact_port/run.pl b/openflow/regress/projects/black_box/regress/test_forward_exact_port/run.pl deleted file mode 100755 index c3fc215f..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_exact_port/run.pl +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_exact_port - -use strict; -use OF::Includes; - -sub forward_unicast_port { - forward_simple(@_, 'port'); -} - -sub forward_unicast_vlan_port { - my $vlan_id = 0xea5a; - #[15:13] priority, [11:0] vlan id - #The value was chosen at random - forward_simple(@_, 'port', undef, undef, $vlan_id); -} - -sub my_test { - my ($sock, $options_ref) = @_; - - for_all_port_pairs($ofp, $sock, $options_ref, \&forward_unicast_port, 0x0); - if ( not defined( $$options_ref{'no_vlan'} ) ) { - for_all_port_pairs($ofp, $sock, $options_ref, \&forward_unicast_vlan_port, 0x0); - } -} - -run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_forward_overlapping_flow_entries/run.pl b/openflow/regress/projects/black_box/regress/test_forward_overlapping_flow_entries/run.pl deleted file mode 100755 index 6ed870e6..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_overlapping_flow_entries/run.pl +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_overlapping_flow_entries - -use strict; -use OF::Includes; - -sub send_expect_multi_flow { - - my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len ) = @_; - - my $in_port = $in_port_offset + $$options_ref{'port_base'}; - my $out_port = $out_port_offset + $$options_ref{'port_base'}; - - my $test_pkt = get_default_black_box_pkt_len( $in_port, $out_port, $pkt_len ); - - #print HexDump ( $test_pkt->packed ); - - my $wildcards = 0x0; # exact match - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; - - my $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, - $enums{'OFPP_ALL'}, $max_idle, $flags, $wildcards ); - - #print HexDump($flow_mod_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent exact match flow_mod message\n"; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - - $wildcards = 0x1fffff; # wildcard everything - - # (send to controller) - $flow_mod_pkt = create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, - $enums{'OFPP_CONTROLLER'}, 2, $flags, $wildcards ); - - #print HexDump($flow_mod_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent wildcard match flow_mod message\n"; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - - # Send a packet - ensure packet comes out desired port - nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt->packed ); - - for ( my $k = 0 ; $k < $$options_ref{'num_ports'}; $k++ ) { - if ( $k != $in_port_offset ) { - nftest_expect( "eth" . ( $k + 1 ), $test_pkt->packed ); - } - } -} - -sub my_test { - - my ($sock, $options_ref) = @_; - - #my $max_idle = $$options_ref{'max_idle'}; - my $max_idle = 5; - my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_total = $$options_ref{'pkt_total'}; - - my $num_ports = $$options_ref{'num_ports'}; - - my $j = 0; - - # send from every port, receive on every port except the send port - #for ( my $i = 0 ; $i < $num_ports ; $i++ ) { - my $i = 0; - my $j = ($i + 1) % $num_ports; - print "sending from $i to (all ports but $i)\n"; - send_expect_multi_flow( $ofp, $sock, $options_ref, $i, $j, $max_idle, $pkt_len ); - print "waiting for first flow to expire\n"; - wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, 0 ); - print "waiting for second flow to expire\n"; - wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); - #} -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_all/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_all/run.pl deleted file mode 100755 index 51a504b8..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_wildcard_all/run.pl +++ /dev/null @@ -1,172 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_wildcard_all - -use strict; -use OF::Includes; - -sub forward_wc_all { - - forward_simple(@_, 'all'); -} - -sub forward_wc_all_vlan { - my $vlan_id = 0x25ae; - #[15:13] priority, [11:0] vlan id - #The value was chosen at random - forward_simple(@_, 'all', undef, undef, $vlan_id); -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_all); - if ( not defined( $$options_ref{'no_vlan'} ) ) { - for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_all_vlan); - } -} - -run_black_box_test( \&my_test, \@ARGV ); - -#sub send_expect_exact { -# -# my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $wildcards ) = @_; -# -# my $in_port = $in_port_offset + $$options_ref{'port_base'}; -# my $out_port = $enums{'OFPP_ALL'}; # all physical ports except the input -# -# printf( "Wildcards are: %04x\n", $wildcards ); -# -# # in_port refers to the flow mod entry's input -# -# # This packet will always match -# my $test_pkt = get_default_black_box_pkt_len( $in_port, $out_port, $$options_ref{'pkt_len'} ); -# -# # This packet will always miss -# my $test_pkt2 = get_default_black_box_pkt_len( $in_port + 5, $out_port + 5, $$options_ref{'pkt_len'} ); -# -# print HexDump ( $test_pkt->packed ); -# print HexDump ( $test_pkt2->packed ); -# -# my $flow_mod_pkt = -# create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $$options_ref{'max_idle'}, $wildcards ); -# -# #print HexDump($flow_mod_pkt); -# -# # Send 'flow_mod' message -# print $sock $flow_mod_pkt; -# print "sent flow_mod message\n"; -# -# # Give OF switch time to process the flow mod -# usleep($$options_ref{'send_delay'}); -# -# # Send a packet - ensure packet comes out desired port -# nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt->packed ); -# -# for ( my $k = 0 ; $k < $$options_ref{'num_ports'} ; $k++ ) { -# if ( $k != $in_port_offset ) { -# nftest_expect( "eth" . ( $k + 1 ), $test_pkt->packed ); -# } -# } -# -# print "Matching packet sent\n"; -# -# #nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt2->packed ); -# -## #print "Non-matching packet sent\n"; -## my $recvd_mesg; -## sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; -## -## # Inspect message -## my $msg_size = length($recvd_mesg); -## my $expected_size = $ofp->offsetof( 'ofp_packet_in', 'data' ) + length( $test_pkt2->packed ); -## -## print HexDump ($recvd_mesg); -## -## #print "Comparing sizes $msg_size and $expected_size\n"; -## compare( "msg size", $msg_size, '==', $expected_size ); -## -## my $msg = $ofp->unpack( 'ofp_packet_in', $recvd_mesg ); -## -## #print HexDump ($recvd_mesg); -## #print Dumper($msg); -## -## # Verify fields -## verify_header( $msg, 'OFPT_PACKET_IN', $msg_size ); -## -## compare( "total len", $$msg{'total_len'}, '==', length( $test_pkt2->packed ) ); -## compare( "in_port", $$msg{'in_port'}, '==', $in_port ); -## compare( "reason", $$msg{'reason'}, '==', $enums{'OFPR_NO_MATCH'} ); -## -## # verify packet was unchanged! -## my $recvd_pkt_data = substr( $recvd_mesg, $ofp->offsetof( 'ofp_packet_in', 'data' ) ); -## if ( $recvd_pkt_data ne $test_pkt2->packed ) { -## die "ERROR: received packet data didn't match packet sent\n"; -## } -# -#} -# -#sub my_test { -# -# my ( $sock, $options_ref ) = @_; -# my $j = $enums{'OFPP_FLOOD'}; -# -# my $max_idle = $$options_ref{'max_idle'}; -# my $pkt_len = $$options_ref{'pkt_len'}; -# my $pkt_total = $$options_ref{'pkt_total'}; -# -# # send from every port to every other port -# for ( my $i = 0 ; $i < 4 ; $i++ ) { -# -# print "sending from $i to $j\n"; -# -# #Very hackish, but basically iterate through the possibilities for -# #wildcarding one at a time. -# print "wildcards 0x0001 : IN_PORT\n"; -# send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0001 ); -# wait_for_flow_expired_all( $ofp, $sock, $options_ref ); -# -# #DL_VLAN fixed at 0xffff currently. -# #print "wildcards 0x0002 : DL_VLAN\n"; -# #send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0002); -# #wait_for_flow_expired_all( $ofp, $sock, $options_ref ); -# -# print "wildcards 0x0004 : DL_SRC\n"; -# send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0004 ); -# wait_for_flow_expired_all( $ofp, $sock, $options_ref ); -# -# print "wildcards 0x0008 : DL_DST\n"; -# send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0008 ); -# wait_for_flow_expired_all( $ofp, $sock, $options_ref ); -# -# #DL_TYPE fixed at 0x0800 currently. -# #print "wildcards 0x0010 : DL_TYPE\n"; -# #send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0010); -# #wait_for_flow_expired_all( $ofp, $sock, $options_ref ); -# -# print "wildcards 0x0020 : NW_SRC\n"; -# send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0020 ); -# wait_for_flow_expired_all( $ofp, $sock, $options_ref ); -# -# print "wildcards 0x0040 : NW_DST\n"; -# send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0040 ); -# wait_for_flow_expired_all( $ofp, $sock, $options_ref ); -# -# #NW_PROTO fixed at 17 currently. -# #print "wildcards 0x0080 : NW_PROTO\n"; -# #send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0080); -# #wait_for_flow_expired_all( $ofp, $sock, $options_ref ); -# -# print "wildcards 0x0100 : TP_SRC\n"; -# send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0100 ); -# wait_for_flow_expired_all( $ofp, $sock, $options_ref ); -# -# print "wildcards 0x0200 : TP_SRC\n"; -# send_expect_exact( $ofp, $sock, $options_ref, $i, $j, 0x0200 ); -# wait_for_flow_expired_all( $ofp, $sock, $options_ref ); -# -# } -#} -# -#run_black_box_test( \&my_test, \@ARGV ); -# diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_all/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_all/run.pl deleted file mode 100755 index ccebe303..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_all/run.pl +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_wildcard_arp_all - -use strict; -use OF::Includes; - -sub forward_wc_all { - - forward_simple_arp(@_, 'all', 0); # 0: fool_flg = off -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_all); -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_controller/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_controller/run.pl deleted file mode 100755 index 90e8b5ad..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_controller/run.pl +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_wildcard_arp_controller - -use strict; -use OF::Includes; - -sub forward_wc_controller { - - forward_simple_arp(@_, 'controller', 0); # 0: fool_flg = off -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_controller); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_fool/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_fool/run.pl deleted file mode 100755 index 0b4d5249..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_fool/run.pl +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_wildcard_arp_port - -use strict; -use OF::Includes; - -sub forward_wc_port { - forward_simple_arp(@_, 'port', 1); # 1: fool_flg = on -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_port); -} - -run_black_box_test( \&my_test, \@ARGV ); - - diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_port/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_port/run.pl deleted file mode 100755 index ef8cb8ab..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_port/run.pl +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_wildcard_arp_port - -use strict; -use OF::Includes; - -sub forward_wc_port { - forward_simple_arp(@_, 'port', 0); # 0: fool_flg = off -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_port); -} - -run_black_box_test( \&my_test, \@ARGV ); - - diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_controller/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_controller/run.pl deleted file mode 100755 index 125c5071..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_wildcard_controller/run.pl +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_wildcard_controller - -use strict; -use OF::Includes; - -sub forward_wc_controller { - - forward_simple(@_, 'controller'); -} - -sub forward_wc_controller_vlan { - my $vlan_id = 0x4abc; - #[15:13] priority, [11:0] vlan id - #The value was chosen at random - forward_simple(@_, 'controller', undef, undef, $vlan_id); -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_controller); - if ( not defined( $$options_ref{'no_vlan'} ) ) { - for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_controller_vlan); - } -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_all/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_all/run.pl deleted file mode 100755 index 7ccdea0b..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_all/run.pl +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_wildcard_icmp_all - -use strict; -use OF::Includes; - -sub forward_wc_all { - - forward_simple_icmp(@_, 'all', 0); # 0: fool_flg = off -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_all); -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_controller/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_controller/run.pl deleted file mode 100755 index 21a0c608..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_controller/run.pl +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_wildcard_icmp_controller - -use strict; -use OF::Includes; - -sub forward_wc_controller { - - forward_simple_icmp(@_, 'controller', 0); # 0: fool_flg = off -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_controller); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_fool/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_fool/run.pl deleted file mode 100755 index eacfb9d5..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_fool/run.pl +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_wildcard_icmp_port - -use strict; -use OF::Includes; - -sub forward_wc_port { - forward_simple_icmp(@_, 'port', 1); # 1: fool_flg = on -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_port); -} - -run_black_box_test( \&my_test, \@ARGV ); - - diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_port/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_port/run.pl deleted file mode 100755 index c428a9e5..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_port/run.pl +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_wildcard_icmp_port - -use strict; -use OF::Includes; - -sub forward_wc_port { - forward_simple_icmp(@_, 'port', 0); # 0: fool_flg = off -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_port); -} - -run_black_box_test( \&my_test, \@ARGV ); - - diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_modify_action/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_modify_action/run.pl deleted file mode 100755 index ca32aaaf..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_wildcard_modify_action/run.pl +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_wildcard_modify_action - -use strict; -use OF::Includes; - -sub forward_wc_port { - my @chg_field = ('vlan_vid', 'vlan_pcp','dl_src', 'dl_dst', 'nw_src', 'nw_dst', 'tp_src', 'tp_dst'); - foreach (@chg_field) { - forward_simple(@_, 'port', undef, $_ ); - } -} - - -sub forward_wc_port_vlan { - my @chg_field = ('strip_vlan', 'vlan_vid','vlan_pcp','dl_src', 'dl_dst', 'nw_src', 'nw_dst', 'tp_src', 'tp_dst'); - my $vlan_id = 0xa344; - #The value was chosen at random - foreach (@chg_field) { - forward_simple(@_, 'port', undef, $_, $vlan_id); - } -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_port); - if ( not defined( $$options_ref{'no_vlan'} ) ) { - for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_port_vlan); - } -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_forward_wildcard_port/run.pl b/openflow/regress/projects/black_box/regress/test_forward_wildcard_port/run.pl deleted file mode 100755 index 934da7cc..00000000 --- a/openflow/regress/projects/black_box/regress/test_forward_wildcard_port/run.pl +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/perl -w -# test_forward_wildcard_port - -use strict; -use OF::Includes; - -sub forward_wc_port { - - forward_simple(@_, 'port'); -} - -sub forward_wc_port_vlan { - my $vlan_id = 0x8ea5; - #[15:13] priority, [11:0] vlan id - #The value was chosen at random - forward_simple(@_, 'port', undef, undef, $vlan_id); -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_port); - if ( not defined( $$options_ref{'no_vlan'} ) ) { - for_all_wildcards( $ofp, $sock, $options_ref, \&forward_wc_port_vlan); - } -} - -run_black_box_test( \&my_test, \@ARGV ); - -#sub send_expect_exact { -# -# my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len, $wildcards ) = @_; -# -# my $in_port = $in_port_offset + $$options_ref{'port_base'}; -# my $out_port = $out_port_offset + $$options_ref{'port_base'}; -# -# printf( "Wildcards are: %04x\n", $wildcards ); -# -# # This packet will always match -# my $test_pkt = get_default_black_box_pkt_len( $in_port, $out_port, $pkt_len ); -# -# # This packet will always miss -# my $test_pkt2 = get_default_black_box_pkt_len( $in_port + 5, $out_port + 5, $pkt_len ); -# -# #print HexDump ( $test_pkt->packed ); -# -# my $flow_mod_pkt = -# create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $wildcards ); -# -# #print HexDump($flow_mod_pkt); -# -# # Send 'flow_mod' message -# print $sock $flow_mod_pkt; -# print "sent flow_mod message\n"; -# -# # Give OF switch time to process the flow mod -# usleep($$options_ref{'send_delay'}); -# -# # Send a packet - ensure packet comes out desired port -# nftest_send( "eth" . ($in_port_offset + 1), $test_pkt->packed ); -# nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); -# print "Matching packet sent\n"; -# -# nftest_send( "eth" . ($in_port_offset + 1), $test_pkt2->packed ); -# -# print "Non-matching packet sent\n"; -# my $recvd_mesg; -# sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; -# -# # Inspect message -# my $msg_size = length($recvd_mesg); -# my $expected_size = $ofp->offsetof( 'ofp_packet_in', 'data' ) + length( $test_pkt2->packed ); -# -# #print "Comparing sizes $msg_size and $expected_size\n"; -# compare( "msg size", $msg_size, '==', $expected_size ); -# -# my $msg = $ofp->unpack( 'ofp_packet_in', $recvd_mesg ); -# -# #print HexDump ($recvd_mesg); -# #print Dumper($msg); -# -# # Verify fields -# verify_header( $msg, 'OFPT_PACKET_IN', $msg_size ); -# -# compare( "total len", $$msg{'total_len'}, '==', length( $test_pkt2->packed ) ); -# compare( "in_port", $$msg{'in_port'}, '==', $in_port ); -# compare( "reason", $$msg{'reason'}, '==', $enums{'OFPR_NO_MATCH'} ); -# -# # verify packet was unchanged! -# my $recvd_pkt_data = substr( $recvd_mesg, $ofp->offsetof( 'ofp_packet_in', 'data' ) ); -# if ( $recvd_pkt_data ne $test_pkt2->packed ) { -# die "ERROR: received packet data didn't match packet sent\n"; -# } -# -#} - diff --git a/openflow/regress/projects/black_box/regress/test_hello/run.pl b/openflow/regress/projects/black_box/regress/test_hello/run.pl deleted file mode 100755 index e1bbdb23..00000000 --- a/openflow/regress/projects/black_box/regress/test_hello/run.pl +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/perl -w -# test_hello - -use strict; -require OF::Includes; - -sub my_test { - - my ($sock, $options_ref) = @_; - - - - # hello sequence automatically done by test harness! -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_ip_offset/run.pl b/openflow/regress/projects/black_box/regress/test_ip_offset/run.pl deleted file mode 100755 index 0aa567b3..00000000 --- a/openflow/regress/projects/black_box/regress/test_ip_offset/run.pl +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/perl -w -# test_ip_offset - -use strict; -use OF::Includes; - -sub send_expect_exact { - - my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len ) = @_; - - my $in_port = $in_port_offset + $$options_ref{'port_base'}; - my $out_port = $out_port_offset + $$options_ref{'port_base'}; - - # in_port refers to the flow mod entry's input - - my $test_pkt_frag_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - frag => 0x2fff, # IP_frag > IP_len - src_port => 1, - dst_port => 0 - }; - my $test_pkt_frag = new NF2::UDP_pkt(%$test_pkt_frag_args); - - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - frag => 0, - src_port => 0, - dst_port => 0 - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - #print HexDump ( $test_pkt->packed ); - - my $wildcards = 0x0; # exact match - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; - - my $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); - - #print HexDump($flow_mod_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent flow_mod message\n"; - usleep($$options_ref{'send_delay'}); - - # Send a packet - ensure packet comes out desired port - nftest_send( "eth" . ( $in_port_offset + 1 ), $test_pkt_frag->packed ); - nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt_frag->packed ); -} - -sub test_ip_offset { - - my ( $ofp, $sock, $options_ref, $i, $j, $wildcards ) = @_; - - my $max_idle = $$options_ref{'max_idle'}; - my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_total = $$options_ref{'pkt_total'}; - - my $port_base = $$options_ref{'port_base'}; - my $num_ports = $$options_ref{'num_ports'}; - - send_expect_exact( $ofp, $sock, $options_ref, $i, $j, $max_idle, $pkt_len ); - wait_for_flow_expired_all( $ofp, $sock, $options_ref ); -} - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - # send from every port to every other port - for_all_port_pairs( $ofp, $sock, $options_ref, \&test_ip_offset, 0x0); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_ip_options/run.pl b/openflow/regress/projects/black_box/regress/test_ip_options/run.pl deleted file mode 100755 index ce8f9266..00000000 --- a/openflow/regress/projects/black_box/regress/test_ip_options/run.pl +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/perl -w -# test_ip_options - -use strict; -use OF::Includes; - -sub send_expect_exact { - - my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len ) = @_; - - my $in_port = $in_port_offset + $$options_ref{'port_base'}; - my $out_port = $out_port_offset + $$options_ref{'port_base'}; - - # in_port refers to the flow mod entry's input - my @ipopt = ( 0x44, 0x08, 0x08, 0x00, 0x11, 0x22, 0x33, 0x44 ); #IP timestamp option - my $num_ipopt = @ipopt; - - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - ip_hdr_len => 5 + ( $#ipopt + 1 ) / 4, - ip_options => \@ipopt, - src_port => 1, - dst_port => 0 - - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - #print ("pkt_len = $pkt_len\n"); - #print HexDump ( $test_pkt->packed ); - - my $wildcards = 0x0; # exact match - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; - - my $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); - #print HexDump($flow_mod_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent flow_mod message\n"; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - - # Send a packet - ensure packet comes out desired port - nftest_send("eth" . ( $in_port_offset + 1 ), $test_pkt->packed ); - nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); -} - -sub test_ip_options { - - my ( $ofp, $sock, $options_ref, $i, $j, $wildcards ) = @_; - - my $max_idle = $$options_ref{'max_idle'}; - #my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_len = 68; - my $pkt_total = $$options_ref{'pkt_total'}; - - send_expect_exact( $ofp, $sock, $options_ref, $i, $j, $max_idle, $pkt_len ); - wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); -} - -sub my_test { - - my ($sock, $options_ref) = @_; - - # send from every port to every other port - for_all_port_pairs( $ofp, $sock, $options_ref, \&test_ip_options, 0x0); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_ip_protocol/case-c.pl b/openflow/regress/projects/black_box/regress/test_ip_protocol/case-c.pl deleted file mode 100755 index 4637c860..00000000 --- a/openflow/regress/projects/black_box/regress/test_ip_protocol/case-c.pl +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/perl -w -# test_ip_protocol (case c, not TCP nor UDP) - -use strict; -use OF::Includes; - -sub send_expect_exact { - - my ( $ofp, $sock, $in_port, $out_port, $max_idle, $pkt_len ) = @_; - - # in_port refers to the flow mod entry's input - - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - src_port => 70, - dst_port => 80 - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - ## Change protocol field - my $iphdr=$test_pkt->{'IP_hdr'}; - $$iphdr->proto(0x13); # overwrite protocol filed in IP header - - #print HexDump ( $test_pkt->packed ); - - my $wildcards = 0x0; # exact match - - my $flow_mod_pkt = - create_flow_mod_from_pseudo_tcp( $ofp, $test_pkt, $in_port, $out_port, - $max_idle, $wildcards ); - - #print HexDump($flow_mod_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent flow_mod message\n"; - usleep(100000); - - # Send a packet - ensure packet comes out desired port - nftest_send( "eth" . ( $in_port + 1 ), - $test_pkt->packed ); - nftest_expect( "eth" . ( $out_port + 1 ), - $test_pkt->packed ); -} - -sub test_ip_protocol { - - my ( $ofp, $sock, $options_ref, $i, $j, $wildcards ) = @_; - - my $max_idle = $$options_ref{'max_idle'}; - my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_total = $$options_ref{'pkt_total'}; - - send_expect_exact( $ofp, $sock, $i, $j, $max_idle, $pkt_len ); - wait_for_flow_expired_all( $ofp, $sock, $options_ref ); -} - -sub my_test { - - my ($sock, $options_ref) = @_; - - # send from every port to every other port - for_all_port_pairs( $ofp, $sock, $options_ref, \&test_ip_protocol, 0x0); -} - -sub create_flow_mod_from_pseudo_tcp { - - my ( $ofp, $udp_pkt, $in_port, $out_port, $max_idle, $wildcards ) = @_; - - my $hdr_args = { - version => get_of_ver(), - type => $enums{'OFPT_FLOW_MOD'}, - length => $ofp->sizeof('ofp_flow_mod') + $ofp->sizeof('ofp_action'), - xid => 0x0000000 - }; - - # might be cleaner to convert the exported colon-hex MAC addrs - #print ${$udp_pkt->{Ethernet_hdr}}->SA . "\n"; - #print ${$test_pkt->{Ethernet_hdr}}->SA . "\n"; - my $ref_to_eth_hdr = ( $udp_pkt->{'Ethernet_hdr'} ); - my $ref_to_ip_hdr = ( $udp_pkt->{'IP_hdr'} ); - - # pointer to array - my $eth_hdr_bytes = $$ref_to_eth_hdr->{'bytes'}; - my $ip_hdr_bytes = $$ref_to_ip_hdr->{'bytes'}; - my @dst_mac_subarray = @{$eth_hdr_bytes}[ 0 .. 5 ]; - my @src_mac_subarray = @{$eth_hdr_bytes}[ 6 .. 11 ]; - - my @src_ip_subarray = @{$ip_hdr_bytes}[ 12 .. 15 ]; - my @dst_ip_subarray = @{$ip_hdr_bytes}[ 16 .. 19 ]; - - my $src_ip = - ( ( 2**24 ) * $src_ip_subarray[0] + ( 2**16 ) * $src_ip_subarray[1] + - ( 2**8 ) * $src_ip_subarray[2] + $src_ip_subarray[3] ); - - my $dst_ip = - ( ( 2**24 ) * $dst_ip_subarray[0] + ( 2**16 ) * $dst_ip_subarray[1] + - ( 2**8 ) * $dst_ip_subarray[2] + $dst_ip_subarray[3] ); - - # read IP_header protocol field - my $iph = $udp_pkt->{'IP_hdr'}; - my $proto = $$iph->proto(); - - my $match_args = { - wildcards => $wildcards, - in_port => $in_port, - dl_src => \@src_mac_subarray, - dl_dst => \@dst_mac_subarray, - dl_vlan => 0xffff, - dl_type => 0x0800, - nw_src => $src_ip, - nw_dst => $dst_ip, - nw_proto => $proto, #any protocol - tp_src => ${ $udp_pkt->{UDP_pdu} }->SrcPort, - tp_dst => ${ $udp_pkt->{UDP_pdu} }->DstPort - }; - - my $action_output_args = { - max_len => 0, # send entire packet - port => $out_port - }; - print "My Out Port: ${out_port}\n"; - - my $action_args = { - type => $enums{'OFPAT_OUTPUT'}, - arg => { output => $action_output_args } - }; - my $action = $ofp->pack( 'ofp_action', $action_args ); - - my $flow_mod_args = { - header => $hdr_args, - match => $match_args, - command => $enums{'OFPFC_ADD'}, - max_idle => $max_idle, - buffer_id => 0x0000, - group_id => 0 - }; - my $flow_mod = $ofp->pack( 'ofp_flow_mod', $flow_mod_args ); - - my $flow_mod_pkt = $flow_mod . $action; - - return $flow_mod_pkt; -} - -run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_ip_protocol/case-d.pl b/openflow/regress/projects/black_box/regress/test_ip_protocol/case-d.pl deleted file mode 100755 index 4f71280e..00000000 --- a/openflow/regress/projects/black_box/regress/test_ip_protocol/case-d.pl +++ /dev/null @@ -1,152 +0,0 @@ -#!/usr/bin/perl -w -# test_ip_protocol (case d, not TCP nor UDP, but specify src port=0, dst port=0); - -use strict; -use OF::Includes; - -sub send_expect_exact { - - my ( $ofp, $sock, $in_port, $out_port, $max_idle, $pkt_len ) = @_; - - # in_port refers to the flow mod entry's input - - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - src_port => 70, - dst_port => 80 - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - ## Change protoco field - my $iphdr=$test_pkt->{'IP_hdr'}; - $$iphdr->proto(0x13); # overwrite protocol filed in IP header - - #print HexDump ( $test_pkt->packed ); - - my $wildcards = 0x0; # exact match - - my $flow_mod_pkt = - create_flow_mod_from_ip( $ofp, $test_pkt, $in_port, $out_port, - $max_idle, $wildcards, 0, 0); - - #print HexDump($flow_mod_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent flow_mod message\n"; - usleep(100000); - - - # Send a packet - ensure packet comes out desired port - nftest_send( "eth" . ( $in_port + 1 ), - $test_pkt->packed ); - nftest_expect( "eth" . ( $out_port + 1 ), - $test_pkt->packed ); -} - - -sub my_test { - - my ($sock, $options_ref) = @_; - - my $max_idle = $$options_ref{'max_idle'}; - my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_total = $$options_ref{'pkt_total'}; - - # send from every port to every other port - for ( my $i = 0 ; $i < 4 ; $i++ ) { - for ( my $j = 0 ; $j < 4 ; $j++ ) { - if ( $i != $j ) { - print "sending from $i to $j\n"; - send_expect_exact( $ofp, $sock, $i, $j, $max_idle, $pkt_len ); - wait_for_flow_expired_all( $ofp, $sock, $options_ref ); - } - } - } -} - -sub create_flow_mod_from_ip { - - my ( $ofp, $udp_pkt, $in_port, $out_port, $max_idle, $wildcards, $s_port, $d_port ) = @_; - - my $hdr_args = { - version => get_of_ver(), - type => $enums{'OFPT_FLOW_MOD'}, - length => $ofp->sizeof('ofp_flow_mod') + $ofp->sizeof('ofp_action'), - xid => 0x0000000 - }; - - # might be cleaner to convert the exported colon-hex MAC addrs - #print ${$udp_pkt->{Ethernet_hdr}}->SA . "\n"; - #print ${$test_pkt->{Ethernet_hdr}}->SA . "\n"; - my $ref_to_eth_hdr = ( $udp_pkt->{'Ethernet_hdr'} ); - my $ref_to_ip_hdr = ( $udp_pkt->{'IP_hdr'} ); - - # pointer to array - my $eth_hdr_bytes = $$ref_to_eth_hdr->{'bytes'}; - my $ip_hdr_bytes = $$ref_to_ip_hdr->{'bytes'}; - my @dst_mac_subarray = @{$eth_hdr_bytes}[ 0 .. 5 ]; - my @src_mac_subarray = @{$eth_hdr_bytes}[ 6 .. 11 ]; - - my @src_ip_subarray = @{$ip_hdr_bytes}[ 12 .. 15 ]; - my @dst_ip_subarray = @{$ip_hdr_bytes}[ 16 .. 19 ]; - - my $src_ip = - ( ( 2**24 ) * $src_ip_subarray[0] + ( 2**16 ) * $src_ip_subarray[1] + - ( 2**8 ) * $src_ip_subarray[2] + $src_ip_subarray[3] ); - - my $dst_ip = - ( ( 2**24 ) * $dst_ip_subarray[0] + ( 2**16 ) * $dst_ip_subarray[1] + - ( 2**8 ) * $dst_ip_subarray[2] + $dst_ip_subarray[3] ); - - # read IP_header protocol field - my $iph = $udp_pkt->{'IP_hdr'}; - my $proto = $$iph->proto(); - - my $match_args = { - wildcards => $wildcards, - in_port => $in_port, - dl_src => \@src_mac_subarray, - dl_dst => \@dst_mac_subarray, - dl_vlan => 0xffff, - dl_type => 0x0800, - nw_src => $src_ip, - nw_dst => $dst_ip, - nw_proto => $proto, #any protocol - tp_src => $s_port, - tp_dst => $d_port - }; - - my $action_output_args = { - max_len => 0, # send entire packet - port => $out_port - }; - print "My Out Port: ${out_port}\n"; - - my $action_args = { - type => $enums{'OFPAT_OUTPUT'}, - arg => { output => $action_output_args } - }; - my $action = $ofp->pack( 'ofp_action', $action_args ); - - my $flow_mod_args = { - header => $hdr_args, - match => $match_args, - command => $enums{'OFPFC_ADD'}, - max_idle => $max_idle, - buffer_id => 0x0000, - group_id => 0 - }; - my $flow_mod = $ofp->pack( 'ofp_flow_mod', $flow_mod_args ); - - my $flow_mod_pkt = $flow_mod . $action; - - return $flow_mod_pkt; -} - -run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_ip_protocol/case-e.pl b/openflow/regress/projects/black_box/regress/test_ip_protocol/case-e.pl deleted file mode 100755 index 47d1227c..00000000 --- a/openflow/regress/projects/black_box/regress/test_ip_protocol/case-e.pl +++ /dev/null @@ -1,152 +0,0 @@ -#!/usr/bin/perl -w -# test_ip_protocol (case e, not TCP nor UDP, but specify src port!=0, dst port!=0); - -use strict; -use OF::Includes; - -sub send_expect_exact { - - my ( $ofp, $sock, $in_port, $out_port, $max_idle, $pkt_len ) = @_; - - # in_port refers to the flow mod entry's input - - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - src_port => 70, - dst_port => 80 - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - ## Change protoco field - my $iphdr=$test_pkt->{'IP_hdr'}; - $$iphdr->proto(0x13); # overwrite protocol filed in IP header - - #print HexDump ( $test_pkt->packed ); - - my $wildcards = 0x0; # exact match - - my $flow_mod_pkt = - create_flow_mod_from_ip( $ofp, $test_pkt, $in_port, $out_port, - $max_idle, $wildcards, 3, 4); - - #print HexDump($flow_mod_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent flow_mod message\n"; - usleep(100000); - - - # Send a packet - ensure packet comes out desired port - nftest_send( "eth" . ( $in_port + 1 ), - $test_pkt->packed ); - nftest_expect( "eth" . ( $out_port + 1 ), - $test_pkt->packed ); -} - - -sub my_test { - - my ($sock, $options_ref) = @_; - - my $max_idle = $$options_ref{'max_idle'}; - my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_total = $$options_ref{'pkt_total'}; - - # send from every port to every other port - for ( my $i = 0 ; $i < 4 ; $i++ ) { - for ( my $j = 0 ; $j < 4 ; $j++ ) { - if ( $i != $j ) { - print "sending from $i to $j\n"; - send_expect_exact( $ofp, $sock, $i, $j, $max_idle, $pkt_len ); - wait_for_flow_expired_all( $ofp, $sock, $options_ref ); - } - } - } -} - -sub create_flow_mod_from_ip { - - my ( $ofp, $udp_pkt, $in_port, $out_port, $max_idle, $wildcards, $s_port, $d_port ) = @_; - - my $hdr_args = { - version => get_of_ver(), - type => $enums{'OFPT_FLOW_MOD'}, - length => $ofp->sizeof('ofp_flow_mod') + $ofp->sizeof('ofp_action'), - xid => 0x0000000 - }; - - # might be cleaner to convert the exported colon-hex MAC addrs - #print ${$udp_pkt->{Ethernet_hdr}}->SA . "\n"; - #print ${$test_pkt->{Ethernet_hdr}}->SA . "\n"; - my $ref_to_eth_hdr = ( $udp_pkt->{'Ethernet_hdr'} ); - my $ref_to_ip_hdr = ( $udp_pkt->{'IP_hdr'} ); - - # pointer to array - my $eth_hdr_bytes = $$ref_to_eth_hdr->{'bytes'}; - my $ip_hdr_bytes = $$ref_to_ip_hdr->{'bytes'}; - my @dst_mac_subarray = @{$eth_hdr_bytes}[ 0 .. 5 ]; - my @src_mac_subarray = @{$eth_hdr_bytes}[ 6 .. 11 ]; - - my @src_ip_subarray = @{$ip_hdr_bytes}[ 12 .. 15 ]; - my @dst_ip_subarray = @{$ip_hdr_bytes}[ 16 .. 19 ]; - - my $src_ip = - ( ( 2**24 ) * $src_ip_subarray[0] + ( 2**16 ) * $src_ip_subarray[1] + - ( 2**8 ) * $src_ip_subarray[2] + $src_ip_subarray[3] ); - - my $dst_ip = - ( ( 2**24 ) * $dst_ip_subarray[0] + ( 2**16 ) * $dst_ip_subarray[1] + - ( 2**8 ) * $dst_ip_subarray[2] + $dst_ip_subarray[3] ); - - # read IP_header protocol field - my $iph = $udp_pkt->{'IP_hdr'}; - my $proto = $$iph->proto(); - - my $match_args = { - wildcards => $wildcards, - in_port => $in_port, - dl_src => \@src_mac_subarray, - dl_dst => \@dst_mac_subarray, - dl_vlan => 0xffff, - dl_type => 0x0800, - nw_src => $src_ip, - nw_dst => $dst_ip, - nw_proto => $proto, #any protocol - tp_src => $s_port, - tp_dst => $d_port - }; - - my $action_output_args = { - max_len => 0, # send entire packet - port => $out_port - }; - print "My Out Port: ${out_port}\n"; - - my $action_args = { - type => $enums{'OFPAT_OUTPUT'}, - arg => { output => $action_output_args } - }; - my $action = $ofp->pack( 'ofp_action', $action_args ); - - my $flow_mod_args = { - header => $hdr_args, - match => $match_args, - command => $enums{'OFPFC_ADD'}, - max_idle => $max_idle, - buffer_id => 0x0000, - group_id => 0 - }; - my $flow_mod = $ofp->pack( 'ofp_flow_mod', $flow_mod_args ); - - my $flow_mod_pkt = $flow_mod . $action; - - return $flow_mod_pkt; -} - -run_black_box_test(\&my_test); diff --git a/openflow/regress/projects/black_box/regress/test_ip_protocol/case-tcp.pl b/openflow/regress/projects/black_box/regress/test_ip_protocol/case-tcp.pl deleted file mode 100755 index 98117252..00000000 --- a/openflow/regress/projects/black_box/regress/test_ip_protocol/case-tcp.pl +++ /dev/null @@ -1,153 +0,0 @@ -#!/usr/bin/perl -w -# test_ip_protocol (tcp) - -use strict; -use OF::Includes; - -sub send_expect_exact { - - my ( $ofp, $sock, $in_port, $out_port, $max_idle, $pkt_len ) = @_; - - # in_port refers to the flow mod entry's input - - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - src_port => 70, - dst_port => 80 - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - ## Make packet TCP (assuming only tcp src port, tcp dst port fields are used) - my $iphdr = $test_pkt->{'IP_hdr'}; - $$iphdr->proto(6); # overwrite protocol filed in IP header - - #print HexDump ( $test_pkt->packed ); - - my $wildcards = 0x0; # exact match - - my $flow_mod_pkt = - create_flow_mod_from_pseudo_tcp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, - $wildcards ); - - #print HexDump($flow_mod_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent flow_mod message\n"; - usleep(100000); - - # Send a packet - ensure packet comes out desired port - nftest_send( "eth" . ( $in_port + 1 ), $test_pkt->packed ); - nftest_expect( "eth" . ( $out_port + 1 ), $test_pkt->packed ); -} - -sub my_test { - - my ($sock, $options_ref) = @_; - - my $max_idle = $$options_ref{'max_idle'}; - my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_total = $$options_ref{'pkt_total'}; - - # send from every port to every other port - for ( my $i = 0 ; $i < 4 ; $i++ ) { - for ( my $j = 0 ; $j < 4 ; $j++ ) { - if ( $i != $j ) { - print "sending from $i to $j\n"; - send_expect_exact( $ofp, $sock, $i, $j, $max_idle, $pkt_len ); - wait_for_flow_expired_all( $ofp, $sock, $options_ref ); - } - } - } -} - -sub create_flow_mod_from_pseudo_tcp { - - my ( $ofp, $udp_pkt, $in_port, $out_port, $max_idle, $wildcards ) = @_; - - my $hdr_args = { - version => get_of_ver(), - type => $enums{'OFPT_FLOW_MOD'}, - length => $ofp->sizeof('ofp_flow_mod') + $ofp->sizeof('ofp_action'), - xid => 0x0000000 - }; - - # might be cleaner to convert the exported colon-hex MAC addrs - #print ${$udp_pkt->{Ethernet_hdr}}->SA . "\n"; - #print ${$test_pkt->{Ethernet_hdr}}->SA . "\n"; - my $ref_to_eth_hdr = ( $udp_pkt->{'Ethernet_hdr'} ); - my $ref_to_ip_hdr = ( $udp_pkt->{'IP_hdr'} ); - - # pointer to array - my $eth_hdr_bytes = $$ref_to_eth_hdr->{'bytes'}; - my $ip_hdr_bytes = $$ref_to_ip_hdr->{'bytes'}; - my @dst_mac_subarray = @{$eth_hdr_bytes}[ 0 .. 5 ]; - my @src_mac_subarray = @{$eth_hdr_bytes}[ 6 .. 11 ]; - - my @src_ip_subarray = @{$ip_hdr_bytes}[ 12 .. 15 ]; - my @dst_ip_subarray = @{$ip_hdr_bytes}[ 16 .. 19 ]; - - my $src_ip = - ( ( 2**24 ) * $src_ip_subarray[0] + - ( 2**16 ) * $src_ip_subarray[1] + - ( 2**8 ) * $src_ip_subarray[2] + - $src_ip_subarray[3] ); - - my $dst_ip = - ( ( 2**24 ) * $dst_ip_subarray[0] + - ( 2**16 ) * $dst_ip_subarray[1] + - ( 2**8 ) * $dst_ip_subarray[2] + - $dst_ip_subarray[3] ); - - # read IP_header protocol field - my $iph = $udp_pkt->{'IP_hdr'}; - my $proto = $$iph->proto(); - - my $match_args = { - wildcards => $wildcards, - in_port => $in_port, - dl_src => \@src_mac_subarray, - dl_dst => \@dst_mac_subarray, - dl_vlan => 0xffff, - dl_type => 0x0800, - nw_src => $src_ip, - nw_dst => $dst_ip, - nw_proto => $proto, #any protocol - tp_src => ${ $udp_pkt->{UDP_pdu} }->SrcPort, - tp_dst => ${ $udp_pkt->{UDP_pdu} }->DstPort - }; - - my $action_output_args = { - max_len => 0, # send entire packet - port => $out_port - }; - print "My Out Port: ${out_port}\n"; - - my $action_args = { - type => $enums{'OFPAT_OUTPUT'}, - arg => { output => $action_output_args } - }; - my $action = $ofp->pack( 'ofp_action', $action_args ); - - my $flow_mod_args = { - header => $hdr_args, - match => $match_args, - command => $enums{'OFPFC_ADD'}, - max_idle => $max_idle, - buffer_id => 0x0000, - group_id => 0 - }; - my $flow_mod = $ofp->pack( 'ofp_flow_mod', $flow_mod_args ); - - my $flow_mod_pkt = $flow_mod . $action; - - return $flow_mod_pkt; -} - -run_black_box_test( \&my_test, \@ARGV); - diff --git a/openflow/regress/projects/black_box/regress/test_ip_protocol/case-udp.pl b/openflow/regress/projects/black_box/regress/test_ip_protocol/case-udp.pl deleted file mode 100755 index 5f59ad32..00000000 --- a/openflow/regress/projects/black_box/regress/test_ip_protocol/case-udp.pl +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/perl -w -# test_ip_protocol (udp) - -use strict; -use OF::Includes; - -sub send_expect_exact { - - my ( $ofp, $sock, $in_port, $out_port, $max_idle, $pkt_len ) = @_; - - # in_port refers to the flow mod entry's input - - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - src_port => 70, - dst_port => 80 - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - #print HexDump ( $test_pkt->packed ); - - my $wildcards = 0x0; # exact match - my $flags = 0x0; # don't send flow expiry - - my $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, - $max_idle, $flags, $wildcards ); - - #print HexDump($flow_mod_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent flow_mod message\n"; - usleep(100000); - - # Send a packet - ensure packet comes out desired port - nftest_send( "eth" . ( $in_port + 1 ), $test_pkt->packed ); - nftest_expect( "eth" . ( $out_port + 1 ), $test_pkt->packed ); -} - -sub my_test { - - my ($sock, $options_ref) = @_; - - my $max_idle = $$options_ref{'max_idle'}; - my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_total = $$options_ref{'pkt_total'}; - - # send from every port to every other port - for ( my $i = 0 ; $i < 4 ; $i++ ) { - for ( my $j = 0 ; $j < 4 ; $j++ ) { - if ( $i != $j ) { - print "sending from $i to $j\n"; - send_expect_exact( $ofp, $sock, $i, $j, $max_idle, $pkt_len ); - wait_for_flow_expired_all( $ofp, $sock, $options_ref ); - } - } - } -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_llc/run.pl b/openflow/regress/projects/black_box/regress/test_llc/run.pl deleted file mode 100755 index 761f878d..00000000 --- a/openflow/regress/projects/black_box/regress/test_llc/run.pl +++ /dev/null @@ -1,128 +0,0 @@ -#!/usr/bin/perl -w -# test_llc (use $EthFMT = "LLC") -# if you want to test DIX format, use use $EthFMT = "DIX" - -use strict; -use OF::Includes; - -## choose one from "DIX" or "LLC"; -#my $EthFMT = "DIX"; -my $EthFMT = "LLC"; - -my $pkt_len_llc = 68; -my $pkt_len_dix = 60; - -my $pkt_len; -if ( $EthFMT eq "LLC" ) { - $pkt_len = $pkt_len_llc; - print "test for LLC\n"; -} -else { - $pkt_len = $pkt_len_dix; - print "test for DIX\n"; -} - -sub send_expect_exact_oneshot { - - my ( $ofp, $sock, $in_port, $out_port, $max_idle, $pkt_len ) = @_; - - my $test_pkt_llc_ip = new NF2::PDU($pkt_len_llc); - @{ $test_pkt_llc_ip->{'bytes'} }[ 0 .. ( $pkt_len_llc - 1 ) ] = ( - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, # dst mac 6byte (02:02:02:02:02:02) - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, # src mac 6byte (04:04:04:04:04:04) - 0x00, 0x36, # 2byte (Length=54byte=0x0036) - 0xAA, 0xAA, 0x03, #LLC # 3byte (always this value) - 0x00, 0x00, 0x00, #SNAP(OUI) # 3byte (always this value) - 0x08, 0x00, #SNAP(PID) # 2byte (0x0800 = IP) - 0x45, 0x00, 0x00, 0x2E, # 46 byte - 0x00, 0x00, 0x40, 0x00, # - 0x40, 0x11, 0xB8, 0x1E, # TTL=64, proto=UDP(0x11) - 0xC0, 0xA8, 0xC9, 0x28, # SrcIP= 192.168.201.40 - 0xC0, 0xA8, 0xC8, 0x28, # DstIP= 192.168.200.40 - 0x00, 0x46, 0x00, 0x50, # SrcPort=70, DstPort=80 - 0x00, 0x1A, 0xCD, 0x3F, # .. - 0xAE, 0xA5, 0x7F, 0x87, - 0xEE, 0x67, 0x72, 0xA7, - 0x17, 0x91, 0xFE, 0x10, - 0xBD, 0xFA, 0xC0, 0xC2, - 0x8B, 0xA7 - ); - - my $test_pkt_dix_ip = new NF2::PDU($pkt_len_dix); - @{ $test_pkt_dix_ip->{'bytes'} }[ 0 .. ( $pkt_len_dix - 1 ) ] = ( - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, # dst mac 6byte (02:02:02:02:02:02) - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, # src mac 6byte (04:04:04:04:04:04) - 0x08, 0x00, - 0x45, 0x00, 0x00, 0x2E, # 46 byte - 0x00, 0x00, 0x40, 0x00, # - 0x40, 0x11, 0xB8, 0x1E, # TTL=64, proto=UDP(0x11) - 0xC0, 0xA8, 0xC9, 0x28, # SrcIP= 192.168.201.40 - 0xC0, 0xA8, 0xC8, 0x28, # DstIP= 192.168.200.40 - 0x00, 0x46, 0x00, 0x50, # SrcPort=70, DstPort=80 - 0x00, 0x1A, 0xCD, 0x3F, # .. - 0xAE, 0xA5, 0x7F, 0x87, - 0xEE, 0x67, 0x72, 0xA7, - 0x17, 0x91, 0xFE, 0x10, - 0xBD, 0xFA, 0xC0, 0xC2, - 0x8B, 0xA7 - ); - - # Create Test Packet (only to call "create_flow_mod_from_udp") - # which should match test_pkt_llc_ip or test_pkt_dix packet - my $test_pkt_args = { - DA => "02:02:02:02:02:02", - SA => "04:04:04:04:04:04", - src_ip => "192.168.201.40", - dst_ip => "192.168.200.40", - ttl => 64, - len => $pkt_len, - src_port => 70, - dst_port => 80 - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - my $wildcards = 0x0; # exact match - my $flags = 0x0; # don't send flow expiry - my $flow_mod_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards ); - - #print HexDump($flow_mod_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent flow_mod message\n"; - usleep(100000); - - # Send a packet - ensure packet comes out desired port - if ( $EthFMT eq "LLC" ) { - nftest_send( "eth" . ( $in_port + 1 ), $test_pkt_llc_ip->packed ); - nftest_expect( "eth" . ( $out_port + 1 ), $test_pkt_llc_ip->packed ); - } - else { - nftest_send( "eth" . ( $in_port + 1 ), $test_pkt_dix_ip->packed ); - nftest_expect( "eth" . ( $out_port + 1 ), $test_pkt_dix_ip->packed ); - } -} - -sub my_test { - - my ($sock, $options_ref) = @_; - - my $max_idle = $$options_ref{'max_idle'}; - #my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_total = $$options_ref{'pkt_total'}; - - # send from every port to every other port - for ( my $i = 0 ; $i < 4 ; $i++ ) { - for ( my $j = 0 ; $j < 4 ; $j++ ) { - if ( $i != $j ) { - print "sending from $i to $j\n"; - send_expect_exact_oneshot( $ofp, $sock, $i, $j, $max_idle, $pkt_len ); - wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); - } - } - } -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_miss_send_length/run.pl b/openflow/regress/projects/black_box/regress/test_miss_send_length/run.pl deleted file mode 100755 index d787a624..00000000 --- a/openflow/regress/projects/black_box/regress/test_miss_send_length/run.pl +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/perl -w -# test_packet_in -# Send a packet of size 256B, and ensure that it gets reduced to 128B - -use strict; -use OF::Includes; - -sub verify_packet_in { - my ($sock, $options_ref, $miss_send_len, $pktsiz, $expected_pktsiz) = @_; - - my $in_port = $$options_ref{'port_base'}; - my $out_port = $in_port + 1; - - # Give OF switch time to process the set_config - usleep($$options_ref{'send_delay'}); - - my $pkt = get_default_black_box_pkt_len($in_port, $out_port, $pktsiz); - nftest_send('eth1', $pkt->packed); - print "Sent test packet for len ".$miss_send_len."...\n"; - - my $rcvd_msg; - sysread($sock, $rcvd_msg, 1512) || die "Failed to receive message: $!"; - - # Inspect message - my $msg_size = length($rcvd_msg); - compare("msg size", $msg_size, '==', $expected_pktsiz); - - my $msg = $ofp->unpack('ofp_packet_in', $rcvd_msg); - #print HexDump ($rcvd_msg); - #print Dumper($msg); - - # Verify fields - verify_header($msg, 'OFPT_PACKET_IN', $msg_size); - - # total len should be full length of original sent frame - compare("total len", $$msg{'total_len'}, '==', length($pkt->packed)); - compare("in_port", $$msg{'in_port'}, '==', $in_port); - compare("reason", $$msg{'reason'}, '==', $enums{'OFPR_NO_MATCH'}); - - # verify packet was unchanged! - my $rcvd_pkt_data = substr($rcvd_msg, $ofp->offsetof('ofp_packet_in', 'data')); - - # trim to MISS_SEND_LEN - my $pkt_trimmed = substr($pkt->packed, 0, $miss_send_len); - if ($rcvd_pkt_data ne $pkt_trimmed) { - die "ERROR: received packet data didn't match packet sent\n"; - } -} - -sub my_test { - my ($sock, $options_ref) = @_; - - my $miss_send_len = get_of_miss_send_len_default(); - my $pktsiz = 63; - my $expected_pktsiz = 8 + 10 + $pktsiz; - verify_packet_in($sock, $options_ref, $miss_send_len, $pktsiz, $expected_pktsiz); - - $miss_send_len = 0; - $pktsiz = 67; - $expected_pktsiz = 8 + 10; - set_config($ofp, $sock, $options_ref, 1, $miss_send_len); - verify_packet_in($sock, $options_ref, $miss_send_len, $pktsiz, $expected_pktsiz); - - $miss_send_len = 127; - $pktsiz = 259; - $expected_pktsiz = 8 + 10 + $miss_send_len; - set_config($ofp, $sock, $options_ref, 1, $miss_send_len); - verify_packet_in($sock, $options_ref, $miss_send_len, $pktsiz, $expected_pktsiz); - - $miss_send_len = 65535; - $pktsiz = 1500 - 8 - 10; - $expected_pktsiz = 1500; - set_config($ofp, $sock, $options_ref, 1, $miss_send_len); - verify_packet_in($sock, $options_ref, $miss_send_len, $pktsiz, $expected_pktsiz); - - set_config($ofp, $sock, $options_ref, 1, get_of_miss_send_len_default()); -} - -run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_packet_in/run.pl b/openflow/regress/projects/black_box/regress/test_packet_in/run.pl deleted file mode 100755 index 7ddfb830..00000000 --- a/openflow/regress/projects/black_box/regress/test_packet_in/run.pl +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/perl -w -# test_packet_in - -use strict; -use OF::Includes; - -sub my_test { - - my ($sock, $options_ref) = @_; - - my $in_port = $$options_ref{'port_base'}; - my $out_port = $in_port + 1; - - my $pkt = get_default_black_box_pkt( $in_port, $out_port); - nftest_send('eth1', $pkt->packed ); - print "Sent test packet...\n"; - - my $recvd_mesg; - sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; - - # Inspect message - my $msg_size = length($recvd_mesg); - my $expected_size = $ofp->offsetof( 'ofp_packet_in', 'data' ) + length( $pkt->packed ); - compare( "msg size", $msg_size, '==', $expected_size ); - - my $msg = $ofp->unpack( 'ofp_packet_in', $recvd_mesg ); - - #print HexDump ($recvd_mesg); - #print Dumper($msg); - - # Verify fields - verify_header( $msg, 'OFPT_PACKET_IN', $msg_size ); - - compare( "total len", $$msg{'total_len'}, '==', length( $pkt->packed ) ); - compare( "in_port", $$msg{'in_port'}, '==', $in_port ); - compare( "reason", $$msg{'reason'}, '==', $enums{'OFPR_NO_MATCH'} ); - - # verify packet was unchanged! - my $recvd_pkt_data = substr( $recvd_mesg, $ofp->offsetof( 'ofp_packet_in', 'data' ) ); - if ( $recvd_pkt_data ne $pkt->packed ) { - die "ERROR: received packet data didn't match packet sent\n"; - } -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_packet_out/run.pl b/openflow/regress/projects/black_box/regress/test_packet_out/run.pl deleted file mode 100755 index 4d872ac8..00000000 --- a/openflow/regress/projects/black_box/regress/test_packet_out/run.pl +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/perl -w -# test_packet_out - -use strict; -use OF::Includes; - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - my $port_base = $$options_ref{'port_base'}; - my $in_port = $port_base; - my $out_port = $in_port + 1; - - my $pkt = get_default_black_box_pkt( $in_port, $out_port ); - - my $hdr_args = { - version => get_of_ver(), - type => $enums{'OFPT_PACKET_OUT'}, - length => $ofp->sizeof('ofp_packet_out') + - $ofp->sizeof('ofp_action_output') + - length( $pkt->packed ), # should generate automatically! - xid => 0x0000abcd - }; - my $packet_out_args = { - header => $hdr_args, - buffer_id => -1, # data included in this packet - in_port => $enums{'OFPP_NONE'}, - actions_len => $ofp->sizeof('ofp_action_output') - }; - my $packet_out = $ofp->pack( 'ofp_packet_out', $packet_out_args ); - my $action_output_args = { - type => $enums{'OFPAT_OUTPUT'}, - len => $ofp->sizeof('ofp_action_output'), - port => $port_base, # send out eth1 - max_len => get_of_miss_send_len_default() - }; - my $action_output = $ofp->pack( 'ofp_action_output', $action_output_args ); - - my $pkt_sent = $packet_out . $action_output . $pkt->packed; - - # Send 'packet_out' message - print $sock $pkt_sent; - - nftest_expect( 'eth1', $pkt->packed ); - - # Wait for packet to be forwarded out - sleep(.1); - -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_port_stats/run.pl b/openflow/regress/projects/black_box/regress/test_port_stats/run.pl deleted file mode 100755 index 5c321c8d..00000000 --- a/openflow/regress/projects/black_box/regress/test_port_stats/run.pl +++ /dev/null @@ -1,132 +0,0 @@ -#!/usr/bin/perl -w -# test_port_stats - -use strict; -use OF::Includes; - -sub forward_any { - forward_simple(@_, 'any'); -} - -sub my_test { - my ($sock, $options_ref) = @_; - - my $port_base = $$options_ref{'port_base'}; - my $num_ports = $$options_ref{'num_ports'}; - - my $hdr_args = { - version => get_of_ver(), - type => $enums{'OFPT_STATS_REQUEST'}, - length => $ofp->sizeof('ofp_stats_request') + $ofp->sizeof('ofp_port_stats_request'), # should generate automatically! - xid => 0x00000000 - }; - - my $stats_reqhdr_args = { - header => $hdr_args, - type => $enums{'OFPST_PORT'}, - flags => 0 - }; - - my $stats_all_ports_reqbody_args = { - port_no => $enums{'OFPP_NONE'}, - }; - my $stats_single_port_reqbody_args = { - port_no => 1, - }; - my $stats_invalid_port_reqbody_args = { - port_no => 32768, - }; - - my $stats_reqhead = $ofp->pack('ofp_stats_request', $stats_reqhdr_args); - my $stats_all_ports_reqbody = $ofp->pack('ofp_port_stats_request', $stats_all_ports_reqbody_args); - my $stats_single_port_reqbody = $ofp->pack('ofp_port_stats_request', $stats_single_port_reqbody_args); - my $stats_invalid_port_reqbody = $ofp->pack('ofp_port_stats_request', $stats_invalid_port_reqbody_args); - my $stats_all_ports_reqmsg = $stats_reqhead . $stats_all_ports_reqbody; - my $stats_single_port_reqmsg = $stats_reqhead . $stats_single_port_reqbody; - my $stats_invalid_port_reqmsg = $stats_reqhead . $stats_invalid_port_reqbody; - - my $stats_rephdr_args = { - version => get_of_ver(), - type => $enums{'OFPT_STATS_REPLY'}, - length => $ofp->sizeof('ofp_stats_reply'), # should generate automatically! - xid => 0x00000000 - }; - - my $stats_repbody_args = { - header => $stats_rephdr_args, - type => $enums{'OFPST_PORT'}, - flags => 0 - }; - - my $stats_repbody; - for (my $i = $port_base; $i < $port_base + $num_ports; $i++ ) { - my $body_args = { - port_no => $port_base, - rx_count => 0, - tx_count => 0, - drop_count => 0 - }; - $stats_repbody .= $ofp->pack('ofp_port_stats', $body_args); - } - - my $stats_repmsg = $ofp->pack('ofp_stats_reply', $stats_repbody_args) . $stats_repbody; - my $rcvd_msg; - - # Send 'stats_request' for single port - print $sock $stats_single_port_reqmsg; - # Should add timeout here - will crash if no reply - sysread($sock, $rcvd_msg, 1512) || die "Failed to receive message: $!"; - - # Send 'stats_request' for invalid port - print $sock $stats_invalid_port_reqmsg; - # Should add timeout here - will crash if no reply - sysread($sock, $rcvd_msg, 1512) || die "Failed to receive message: $!"; - - # Send 'stats_request' for all ports - print $sock $stats_all_ports_reqmsg; - # Should add timeout here - will crash if no reply - sysread($sock, $rcvd_msg, 1512) || die "Failed to receive message: $!"; - - # Inspect message - my $msg_size = length($rcvd_msg); - my $expected_size = $ofp->sizeof('ofp_stats_reply') + 4 * $ofp->sizeof('ofp_port_stats'); - - # Removed this compare because varying numbers of ports may be activated - # compare("msg size", $msg_size, '==', $expected_size); - my $msg = $ofp->unpack('ofp_stats_reply', $rcvd_msg); - #print HexDump($rcvd_msg); - #print Dumper($msg); - - # Verify fields - verify_header($msg, 'OFPT_STATS_REPLY', $msg_size); - compare("type", $$msg{'type'}, '==', $enums{'OFPST_PORT'}); - compare("flags", $$msg{'flags'}, '==', 0); - -# if ($rcvd_msg ne $stats_reply) { -# die "stats reply is not what was expected" -# } - - # TODO: Look at each received port_stats field, to ensure they equal zero... - - # Send data plane packets - for_all_port_pairs( $ofp, $sock, $options_ref, \&forward_any, 0x1fffff); - - # TODO: Look at each received port_stats field, to ensure correct counters - - # Send 'stats_request' for all ports - print $sock $stats_all_ports_reqmsg; - # Should add timeout here - will crash if no reply - sysread($sock, $rcvd_msg, 1512) || die "Failed to receive message: $!"; - - # Send 'stats_request' for invalid port - print $sock $stats_invalid_port_reqmsg; - # Should add timeout here - will crash if no reply - sysread($sock, $rcvd_msg, 1512) || die "Failed to receive message: $!"; - - # Send 'stats_request' for single port - print $sock $stats_single_port_reqmsg; - # Should add timeout here - will crash if no reply - sysread($sock, $rcvd_msg, 1512) || die "Failed to receive message: $!"; -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/test_queue_config/run.pl b/openflow/regress/projects/black_box/regress/test_queue_config/run.pl deleted file mode 100755 index e3f512ee..00000000 --- a/openflow/regress/projects/black_box/regress/test_queue_config/run.pl +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/perl -w -# test_queue_config - -use strict; -use OF::Includes; - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - if ( not defined( $$options_ref{'no_slicing'} ) ) { - my $port_base = $$options_ref{'port_base'}; - my $num_ports = $$options_ref{'num_ports'}; - - # for each port, - - for (my $i = 1; $i <= $num_ports; $i++){ - - my $hdr_args = { - version => get_of_ver(), - type => $enums{'OFPT_QUEUE_GET_CONFIG_REQUEST'}, - length => $ofp->sizeof('ofp_queue_get_config_request'), # should generate automatically! - xid => 0x00000000 - }; - - my @pad_2 = (0,0); - my $queue_request_args = { - header => $hdr_args, - port => $i, - pad => \@pad_2 - }; - - my $queue_request = $ofp->pack( 'ofp_queue_get_config_request', $queue_request_args ); - - # Send 'stats_request' message - print $sock $queue_request; - - # Should add timeout here - will crash if no reply - my $recvd_mesg; - sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; - - my $msg = $ofp->unpack( 'ofp_queue_get_config_reply', $recvd_mesg ); - - my $msg_size = length($recvd_mesg); - # Verify fields - verify_header( $msg, 'OFPT_QUEUE_GET_CONFIG_REPLY', $msg_size ); - } - } -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_queue_forward/run.pl b/openflow/regress/projects/black_box/regress/test_queue_forward/run.pl deleted file mode 100755 index a3b0d737..00000000 --- a/openflow/regress/projects/black_box/regress/test_queue_forward/run.pl +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/perl -w -# test_queue_forward - -use strict; -use OF::Includes; - -sub forward_unicast_port { - forward_simple(@_, 'enqueue'); -} - -sub my_test { - my ($sock, $options_ref) = @_; - - if ( not defined( $$options_ref{'no_slicing'} ) ) { - for_all_port_pairs($ofp, $sock, $options_ref, \&forward_unicast_port, 0x0); - } -} - -run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_queue_stats/run.pl b/openflow/regress/projects/black_box/regress/test_queue_stats/run.pl deleted file mode 100755 index 0f49a329..00000000 --- a/openflow/regress/projects/black_box/regress/test_queue_stats/run.pl +++ /dev/null @@ -1,116 +0,0 @@ -#!/usr/bin/perl -w -# test_queue_stats - -use strict; -use OF::Includes; - -sub my_test { - - my ( $sock, $options_ref ) = @_; - - if ( not defined( $$options_ref{'no_slicing'} ) ) { - - my $port_base = $$options_ref{'port_base'}; - my $num_ports = $$options_ref{'num_ports'}; - - # Prepare stats request - my $hdr_args = { - version => get_of_ver(), - type => $enums{'OFPT_STATS_REQUEST'}, - length => $ofp->sizeof('ofp_stats_request') + $ofp->sizeof('ofp_queue_stats_request'), # should generate automatically! - xid => 0x00000000 - }; - - my @pad_2 = (0,0); - my $body_args = { - port_no => $port_base, - pad => \@pad_2, - queue_id => 0xffffffff # TODO : export get_define to get OFPQ_ALL - }; - - - my $stats_request_args = { - header => $hdr_args, - type => $enums{'OFPST_QUEUE'}, - flags => 0 - }; - - my $request_body = $ofp->pack( 'ofp_queue_stats_request', $body_args ); - my $stats_request = $ofp->pack( 'ofp_stats_request', $stats_request_args ) . $request_body; - - - # Prepare expected stats reply - my $reply_hdr_args = { - version => get_of_ver(), - type => $enums{'OFPT_STATS_REPLY'}, - length => $ofp->sizeof('ofp_stats_reply') + $ofp->sizeof('ofp_queue_stats'), # should generate automatically! - xid => 0x00000000 - }; - - my $stats_reply_args = { - header => $reply_hdr_args, - type => $enums{'OFPST_QUEUE'}, - flags => 0 - }; - - - my $reply_body_args = { - port_no => $port_base, - pad => \@pad_2, - queue_id => 1, - tx_bytes => 0, - tx_packets => 0, - tx_errors => 0 - }; - - my $reply_body = $ofp->pack( 'ofp_queue_stats', $reply_body_args); - my $stats_reply = $ofp->pack( 'ofp_stats_reply', $stats_reply_args ) . $reply_body; - - # Send 'stats_request' message - print $sock $stats_request; - - # Should add timeout here - will crash if no reply - my $recvd_mesg; - sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; - - # Inspect message - if ($recvd_mesg ne $stats_reply) { - die "ERROR: stats reply didn't match expected"; - } - - # Send a packet out - forward_simple($ofp, $sock, $options_ref, 1, 0, 0, 'enqueue'); - - # Wait the flow to expire - sleep 3; - - # Expect increased counters - $reply_body_args = { - port_no => $port_base, - pad => \@pad_2, - queue_id => 1, - tx_bytes => 64, - tx_packets => 1, - tx_errors => 0 - }; - - $reply_body = $ofp->pack( 'ofp_queue_stats', $reply_body_args); - $stats_reply = $ofp->pack( 'ofp_stats_reply', $stats_reply_args ) . $reply_body; - - - # Send 'stats_request' message - print $sock $stats_request; - - # Receive stats reply - sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; - - # Inspect message - if ($recvd_mesg ne $stats_reply) { - die "ERROR: stats reply didn't match expected"; - } - } - -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_receive_bandwidth_fixed/run.pl b/openflow/regress/projects/black_box/regress/test_receive_bandwidth_fixed/run.pl deleted file mode 100755 index 342845e9..00000000 --- a/openflow/regress/projects/black_box/regress/test_receive_bandwidth_fixed/run.pl +++ /dev/null @@ -1,89 +0,0 @@ -#!/usr/bin/perl -w -# test_receive_bandwidth_fixed - -use strict; -use OF::Includes; - -use Time::HiRes qw (sleep gettimeofday tv_interval usleep); - -my $pkts_total = 10000; -my $pkt_size = 64; -#my $pkt_size = 1512 - $ofp->sizeof( 'ofp_packet_in'); - -sub verify_packet_in { - - my ( $recvd_mesg, $pkt ) = @_; - - # Inspect message - my $msg_size = length($recvd_mesg); - my $expected_size = $ofp->offsetof( 'ofp_packet_in', 'data' ) + length( $pkt->packed ); - if ( $msg_size != $expected_size ) { return 1; } - - my $msg = $ofp->unpack( 'ofp_packet_in', $recvd_mesg ); - - # Verify fields - if ( ( $$msg{'header'}{'version'} != 1 ) - || ( $$msg{'header'}{'type'} != $enums{'OFPT_PACKET_IN'} ) - || ( $$msg{'header'}{'length'} != $msg_size ) - || ( $$msg{'total_len'} != length( $pkt->packed ) ) - || ( $$msg{'in_port'} != 0 ) - || ( $$msg{'reason'} != $enums{'OFPR_NO_MATCH'} ) ) - { - return 1; - } - - # verify packet was unchanged! - my $recvd_pkt_data = substr( $recvd_mesg, $ofp->offsetof( 'ofp_packet_in', 'data' ) ); - if ( $recvd_pkt_data ne $pkt->packed ) { return 1; } -} - -sub receive_fixed_bandwidth { - my ( $num_packets, $sock, $pkt, $interface ) = @_; - my $length = length( $pkt->packed ); - print "sending $num_packets packets\n"; - - my @start_time = gettimeofday(); - - my $errors = 0; - - for ( my $count = 0 ; $count < $num_packets ; $count++ ) { - - nftest_send( nftest_get_iface($interface), $pkt->packed ); - - my $recvd_mesg; - sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; - - $errors += verify_packet_in( $recvd_mesg, $pkt ); - } - - my $sending_time = tv_interval( \@start_time ); - print "time elapsed: $sending_time\n"; - print "errors: $errors\n"; - - my $bps = ($num_packets - $errors) * $length * 8 / $sending_time; - printf "bandwidth achieved: %.0f bps \n", $bps; - - return $errors; -} - -sub my_test { - - my ($sock) = @_; - - my $pkt_args = { - DA => "00:00:00:00:00:02", - SA => "00:00:00:00:00:01", - src_ip => "192.168.200.40", - dst_ip => "192.168.201.40", - ttl => 64, - len => $pkt_size - }; - my $pkt = new NF2::IP_pkt(%$pkt_args); - - my $errors = &receive_fixed_bandwidth( $pkts_total, $sock, $pkt, 'eth1' ); - - if ($errors > 0) { die "received errors"; } -} - -run_black_box_test( \&my_test ); - diff --git a/openflow/regress/projects/black_box/regress/test_send_bandwidth_fixed/run.pl b/openflow/regress/projects/black_box/regress/test_send_bandwidth_fixed/run.pl deleted file mode 100755 index 2941d74a..00000000 --- a/openflow/regress/projects/black_box/regress/test_send_bandwidth_fixed/run.pl +++ /dev/null @@ -1,140 +0,0 @@ -#!/usr/bin/perl -w -# test_send_bandwidth_fixed - -use strict; -use OF::Includes; - -use Time::HiRes qw (sleep gettimeofday tv_interval usleep); - -# Sends packets of the specified length, with specified data rate, over time = duration. -# Length is passed as a parameter and it should be also declared during packet's construction. - -sub send_fixed_bandwidth_unique { - my ( $rate, $duration, $sock, $pkt, $pkt_sent, $interface ) = @_; - my $length = length( $pkt->packed ); - my $num_packets = ( $rate * $duration ) / ( $length * 8 ); - my $inter_time = 1000000.0 * $duration / $num_packets; - - print "Running Test for a single packet size\n"; - print( -"Num Packets : $num_packets, Duration : $duration, Length : $length, InterTime : $inter_time Interface : $interface\n" - ); - - print "sending $num_packets packets\n"; - - my @start_time = gettimeofday(); - - my $count; - for ( $count = 0 ; $count < $num_packets ; $count++ ) { - - # Send 'packet_out' message - print $sock $pkt_sent; - nftest_expect( $interface, $pkt->packed ); - usleep($inter_time); - } - - my $sending_time = tv_interval(\@start_time); - print "time elapsed: $sending_time\n"; - - my $bps = $num_packets * $length * 8 / $sending_time; - print "bandwidth attempted: $rate (bps)\n"; - print "bandwidth achieved: $bps (bps)\n"; -} - -sub send_fixed_bandwidth_mixed { - my ( $rate, $duration, $sock, $pkt_sent_small,$pkt_sent_med,$pkt_sent_lrg,$pkt_small,$pkt_med,$pkt_lrg, $interface ) = @_; - my $len_s = length($pkt_small->packed); - my $len_m = length($pkt_med->packed); - my $len_l = length($pkt_lrg->packed); - my $num_loops = ( $rate * $duration ) / (( $len_s+$len_m+$len_l ) * 8 ); - my $num_packets = $num_loops*3; - my $inter_time = 1000000.0 * $duration / $num_packets; - - print "Running Test for different packet sizes\n"; - - print( -"Num Packets : $num_packets, Duration : $duration, Lengths : $len_s,$len_m,$len_l, InterTime : $inter_time Interface : $interface\n" - ); - - print "sending $num_packets packets\n"; - - my @start_time = gettimeofday(); - - my $count; - for ( $count = 0 ; $count < $num_loops ; $count++ ) { - - # Send 'packet_out' message - print $sock $pkt_sent_small; - nftest_expect( $interface, $pkt_small->packed ); - usleep($inter_time); - print $sock $pkt_sent_med; - nftest_expect( $interface, $pkt_med->packed ); - usleep($inter_time); - print $sock $pkt_sent_lrg; - nftest_expect( $interface, $pkt_lrg->packed ); - usleep($inter_time); - } - - my $sending_time = tv_interval(\@start_time); - print "time elapsed: $sending_time\n"; - - my $bps = $num_loops * ($len_s+$len_m+$len_l) * 8 / $sending_time; - print "bandwidth attempted: $rate(bps)\n"; - print "bandwidth achieved: $bps (bps)\n"; -} - - - -sub my_test { - - my $pkt_args = { - DA => "00:00:00:00:00:02", - SA => "00:00:00:00:00:01", - src_ip => "192.168.200.40", - dst_ip => "192.168.201.40", - ttl => 64, - len => 64 - }; - my $pkt_small = new NF2::IP_pkt(%$pkt_args); - $pkt_args->{ 'len' } = 256; - my $pkt_med = new NF2::IP_pkt(%$pkt_args); - $pkt_args->{ 'len' } = 512; - my $pkt_lrg = new NF2::IP_pkt(%$pkt_args); - - my $hdr_args = { - version => 1, - type => $enums{'OFPT_PACKET_OUT'}, - length => $ofp->sizeof('ofp_packet_out') + length( $pkt_small->packed ), # should generate automatically! - xid => 0x0000abcd - }; - my $packet_out_args = { - header => $hdr_args, - buffer_id => -1, # data included in this packet - in_port => $enums{'OFPP_NONE'}, - out_port => 0 # send out eth1 - }; - my $packet_out = $ofp->pack( 'ofp_packet_out', $packet_out_args ); - - my $pkt_sent_small = $packet_out . $pkt_small->packed; - $hdr_args->{'length'} = $ofp->sizeof('ofp_packet_out') + length( $pkt_med->packed ); - $packet_out_args->{'header'} = $hdr_args; - $packet_out = $ofp->pack( 'ofp_packet_out', $packet_out_args ); - my $pkt_sent_med = $packet_out . $pkt_med->packed; - $hdr_args->{'length'} = $ofp->sizeof('ofp_packet_out') + length( $pkt_lrg->packed ); - $packet_out_args->{'header'} = $hdr_args; - $packet_out = $ofp->pack( 'ofp_packet_out', $packet_out_args ); - my $pkt_sent_lrg = $packet_out . $pkt_lrg->packed; - - my ($sock) = @_; - - &send_fixed_bandwidth_unique( .1 * (10**6) ,5, $sock, $pkt_lrg, $pkt_sent_lrg, 'eth1' ); - - #&send_fixed_bandwidth_mixed( 5 * (10**5) ,5, $sock,$pkt_sent_small,$pkt_sent_med, $pkt_sent_lrg,$pkt_small,$pkt_med,$pkt_lrg,'eth1'); - - # Wait for test to finish - sleep(2); - -} - -run_black_box_test( \&my_test ); - diff --git a/openflow/regress/projects/black_box/regress/test_send_bandwidth_random/run.pl b/openflow/regress/projects/black_box/regress/test_send_bandwidth_random/run.pl deleted file mode 100755 index 0fc0b1ce..00000000 --- a/openflow/regress/projects/black_box/regress/test_send_bandwidth_random/run.pl +++ /dev/null @@ -1,141 +0,0 @@ -#!/usr/bin/perl -w -# test_send_bandwidth_fixed - -use strict; -use OF::Includes; - -use Time::HiRes qw (sleep gettimeofday tv_interval usleep); - -# Sends packets of the specified length, with specified data rate, over time = duration. -# A random interarrival time between packets is used, trying to fit the requested data rate. - -sub send_random_bandwidth_unique { - my ( $rate, $duration, $sock, $pkt, $pkt_sent, $interface ) = @_; - my $length = length( $pkt->packed ); - my $num_packets = ( $rate * $duration ) / ( $length * 8 ); - my $inter_time = 1000000.0 * $duration / $num_packets; - - print "Running Test for a single packet size\n"; - print( -"Num Packets : $num_packets, Duration : $duration, Length : $length, InterTime : $inter_time Interface : $interface\n" - ); - - print "sending $num_packets packets\n"; - - my @start_time = gettimeofday(); - my $sending_time = tv_interval(\@start_time); - - my $count = 0; - while($sending_time < $duration){ - # Send 'packet_out' message - print $sock $pkt_sent; - nftest_expect( $interface, $pkt->packed ); - usleep(int(rand(2*$inter_time))); - $count++; - $sending_time = tv_interval(\@start_time); - } - print "time elapsed: $sending_time (loops : $count) \n"; - - my $bps = $count * $length * 8 / $sending_time; - print "bandwidth attempted: $rate (bps)\n"; - print "bandwidth achieved: $bps (bps)\n"; -} - -sub send_random_bandwidth_mixed { - my ( $rate, $duration, $sock, $pkt_sent_small,$pkt_sent_med,$pkt_sent_lrg,$pkt_small,$pkt_med,$pkt_lrg, $interface ) = @_; - my $len_s = length($pkt_small->packed); - my $len_m = length($pkt_med->packed); - my $len_l = length($pkt_lrg->packed); - my $num_loops = ( $rate * $duration ) / (( $len_s+$len_m+$len_l ) * 8 ); - my $num_packets = $num_loops*3; - my $inter_time = 1000000.0 * $duration / $num_packets; - - print "Running Test for different packet sizes\n"; - print( -"Num Packets : $num_packets, Duration : $duration, Lengths : $len_s,$len_m,$len_l, InterTime : $inter_time Interface : $interface\n" - ); - - print "sending $num_packets packets\n"; - - my @start_time = gettimeofday(); - my $sending_time = tv_interval(\@start_time); - - my $count = 0; - while ($sending_time < $duration){ - # Send 'packet_out' message - print $sock $pkt_sent_small; - nftest_expect( $interface, $pkt_small->packed ); - usleep(int(rand(2*$inter_time))); - print $sock $pkt_sent_med; - nftest_expect( $interface, $pkt_med->packed ); - usleep(int(rand(2*$inter_time))); - print $sock $pkt_sent_lrg; - nftest_expect( $interface, $pkt_lrg->packed ); - usleep(int(rand(2*$inter_time))); - $count++; - $sending_time = tv_interval(\@start_time); - } - - print "time elapsed: $sending_time (loops : $count)\n"; - - my $bps = $count * ($len_s+$len_m+$len_l) * 8 / $sending_time; - print "bandwidth attempted: $rate(bps)\n"; - print "bandwidth achieved: $bps (bps)\n"; -} - - - -sub my_test { - - my $pkt_args = { - DA => "00:00:00:00:00:02", - SA => "00:00:00:00:00:01", - src_ip => "192.168.200.40", - dst_ip => "192.168.201.40", - ttl => 64, - len => 64 - }; - my $pkt_small = new NF2::IP_pkt(%$pkt_args); - $pkt_args->{ 'len' } = 256; - my $pkt_med = new NF2::IP_pkt(%$pkt_args); - $pkt_args->{ 'len' } = 512; - my $pkt_lrg = new NF2::IP_pkt(%$pkt_args); - - my $hdr_args = { - version => 1, - type => $enums{'OFPT_PACKET_OUT'}, - length => $ofp->sizeof('ofp_packet_out') + length( $pkt_small->packed ), # should generate automatically! - xid => 0x0000abcd - }; - my $packet_out_args = { - header => $hdr_args, - buffer_id => -1, # data included in this packet - in_port => $enums{'OFPP_NONE'}, - out_port => 0 # send out eth1 - }; - my $packet_out = $ofp->pack( 'ofp_packet_out', $packet_out_args ); - - my $pkt_sent_small = $packet_out . $pkt_small->packed; - $hdr_args->{'length'} = $ofp->sizeof('ofp_packet_out') + length( $pkt_med->packed ); - $packet_out_args->{'header'} = $hdr_args; - $packet_out = $ofp->pack( 'ofp_packet_out', $packet_out_args ); - my $pkt_sent_med = $packet_out . $pkt_med->packed; - $hdr_args->{'length'} = $ofp->sizeof('ofp_packet_out') + length( $pkt_lrg->packed ); - $packet_out_args->{'header'} = $hdr_args; - $packet_out = $ofp->pack( 'ofp_packet_out', $packet_out_args ); - my $pkt_sent_lrg = $packet_out . $pkt_lrg->packed; - - my ($sock) = @_; - - - &send_random_bandwidth_unique( .01 * (10**6) ,15, $sock, $pkt_lrg, $pkt_sent_lrg, 'eth1' ); - - #&send_random_bandwidth_mixed( 5 * (10**5) ,5, $sock,$pkt_sent_small,$pkt_sent_med, $pkt_sent_lrg,$pkt_small,$pkt_med,$pkt_lrg,'eth1'); - - # Wait for test to finish - sleep(2); - -} - -run_black_box_test( \&my_test ); - diff --git a/openflow/regress/projects/black_box/regress/test_set_dl_nw_flip/run.pl b/openflow/regress/projects/black_box/regress/test_set_dl_nw_flip/run.pl deleted file mode 100755 index fbf508b4..00000000 --- a/openflow/regress/projects/black_box/regress/test_set_dl_nw_flip/run.pl +++ /dev/null @@ -1,143 +0,0 @@ -#!/usr/bin/perl -w -# test_set_nw_dst - -use strict; -use OF::Includes; - -sub send_expect_exact { - my ($ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len) = @_; - - my $in_port = $in_port_offset + $$options_ref{'port_base'}; - my $out_port = $out_port_offset + $$options_ref{'port_base'}; - - # in_port refers to the flow mod entry's input - - # Create the payload ourselves to make sure the two packets match - # Jean II - my $pkt_payload = [map {int(rand(256))} (1..($pkt_len - 8 - 4 - 16 - 14))]; - - # This is the packet we are sending... - Jean II - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - tos => 0x0, - ttl => 64, - len => $pkt_len, - src_port => 1, - dst_port => 0, - data => $pkt_payload - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - # This is the packet we are expecting to receive - Jean II - my $expect_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - src_ip => "192.168.201." . ( $out_port ), - dst_ip => "192.168.200." . ( $in_port ), - tos => 0x0, - ttl => 64, - len => $pkt_len, - src_port => 1, - dst_port => 0, - data => $pkt_payload - }; - my $expect_pkt = new NF2::UDP_pkt(%$expect_pkt_args); - - #print HexDump ($test_pkt->packed); - - my $wildcards = 0x0; # exact match - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry - - # Get the various addresses in the expected packet - Jean II - my $chg_val_dl_da = ${$expect_pkt->{Ethernet_hdr}}->DA; - my $chg_val_dl_sa = ${$expect_pkt->{Ethernet_hdr}}->SA; - my $chg_val_nw_dst = ${$expect_pkt->{IP_hdr}}->dst_ip; - my $chg_val_nw_src = ${$expect_pkt->{IP_hdr}}->src_ip; - my @dl_da_addr_chg = NF2::PDU::get_MAC_address($chg_val_dl_da); - my @dl_sa_addr_chg = NF2::PDU::get_MAC_address($chg_val_dl_sa); - my $nw_dst_addr_chg; - my $ok_org; - ($nw_dst_addr_chg, $ok_org) = NF2::IP_hdr::getIP($chg_val_nw_dst); - my $nw_src_addr_chg; - ($nw_src_addr_chg, $ok_org) = NF2::IP_hdr::getIP($chg_val_nw_src); - - # Create the desired rewrite actions - my @pad_6 = (0,0,0,0,0,0); - my $action_mod_dl_da_args = { - type => $enums{'OFPAT_SET_DL_DST'}, - len => $ofp->sizeof('ofp_action_dl_addr'), - dl_addr => \@dl_da_addr_chg, - pad => \@pad_6, - }; - my $action_mod_dl_da = $ofp->pack('ofp_action_dl_addr', $action_mod_dl_da_args); - my $action_mod_dl_sa_args = { - type => $enums{'OFPAT_SET_DL_SRC'}, - len => $ofp->sizeof('ofp_action_dl_addr'), - dl_addr => \@dl_sa_addr_chg, - pad => \@pad_6, - }; - my $action_mod_dl_sa = $ofp->pack('ofp_action_dl_addr', $action_mod_dl_sa_args); - my $action_mod_nw_dst_args = { - type => $enums{'OFPAT_SET_NW_DST'}, - len => $ofp->sizeof('ofp_action_nw_addr'), - nw_addr => $nw_dst_addr_chg, - }; - my $action_mod_nw_dst = $ofp->pack( 'ofp_action_nw_addr', $action_mod_nw_dst_args ); - my $action_mod_nw_src_args = { - type => $enums{'OFPAT_SET_NW_SRC'}, - len => $ofp->sizeof('ofp_action_nw_addr'), - nw_addr => $nw_src_addr_chg, - }; - my $action_mod_nw_src = $ofp->pack( 'ofp_action_nw_addr', $action_mod_nw_src_args ); - - # Output action to get the packet out someplace - Jean II - my $action_output_args = { - type => $enums{'OFPAT_OUTPUT'}, - len => $ofp->sizeof('ofp_action_output'), - port => $out_port, - max_len => 0, # send entire packet - }; - my $action_output = $ofp->pack( 'ofp_action_output', $action_output_args ); - - # Aggregate all actions together - my $action_bytes = $action_mod_dl_da . $action_mod_dl_sa . $action_mod_nw_dst . $action_mod_nw_src . $action_output; - - my $flow_mod_pkt = - create_flow_mod_from_udp_actionbytes( $ofp, $test_pkt, $in_port, $max_idle, $flags, $wildcards, 'OFPFC_ADD', $action_bytes); - - #print HexDump($flow_mod_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent flow_mod message\n"; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - - # Send a packet - ensure packet comes out desired port - nftest_send("eth" . ($in_port_offset + 1), $test_pkt->packed); - nftest_expect("eth" . ($out_port_offset + 1), $expect_pkt->packed); -} - -sub test_set_nw_dst { - my ($ofp, $sock, $options_ref, $i, $j, $wildcards) = @_; - - my $max_idle = $$options_ref{'max_idle'}; - my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_total = $$options_ref{'pkt_total'}; - - send_expect_exact($ofp, $sock, $options_ref, $i, $j, $max_idle, $pkt_len); - wait_for_flow_expired($ofp, $sock, $options_ref, $pkt_len, $pkt_total); -} - -sub my_test { - my ($sock, $options_ref) = @_; - - # send from every port to every other port - for_all_port_pairs($ofp, $sock, $options_ref, \&test_set_nw_dst, 0x0); -} - -run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_set_n_match_nw_tos/run.pl b/openflow/regress/projects/black_box/regress/test_set_n_match_nw_tos/run.pl deleted file mode 100755 index 4470c812..00000000 --- a/openflow/regress/projects/black_box/regress/test_set_n_match_nw_tos/run.pl +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/perl -w -# test_set_nw_tos - -use strict; -use OF::Includes; - -# Please check the following : -# http://en.wikipedia.org/wiki/Type_of_Service - -sub send_expect_exact { - my ($ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len, $vlan_id) = @_; - - my $in_port = $in_port_offset + $$options_ref{'port_base'}; - my $out_port = $out_port_offset + $$options_ref{'port_base'}; - - # in_port refers to the flow mod entry's input - - # Create the payload ourselves to make sure the two packets match - # Jean II - my $pkt_payload = [map {int(rand(256))} (1..($pkt_len - 8 - 4 - 16 - 14))]; - - # This is the packet we are sending... - Jean II - # Set an ECN bit to see if it gets clobbered - my $test_nw_tos = 0xA8; - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - tos => $test_nw_tos | 0x01, # => 0xA9 - ttl => 64, - len => $pkt_len, - src_port => 1, - dst_port => 0, - data => $pkt_payload - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - # This is the packet we are expecting to receive - Jean II - my $expect_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - tos => 0x54 | 0x01, # 0x55 - ttl => 64, - len => $pkt_len, - src_port => 1, - dst_port => 0, - data => $pkt_payload - }; - my $expect_pkt = new NF2::UDP_pkt(%$expect_pkt_args); - - #print HexDump ($test_pkt->packed); - - my $wildcards = 0x0; # exact match - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry - # Don't set ECN bits here, OVS reject it as invalid... - my $nw_tos = 0x54; - - my $flow_mod_pkt = create_flow_mod_from_udp_action($ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards, 'OFPFC_ADD', 'nw_tos', $nw_tos, $vlan_id, $test_nw_tos); - - #print HexDump($flow_mod_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent flow_mod message\n"; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - - # Send a packet - ensure packet comes out desired port - nftest_send("eth" . ($in_port_offset + 1), $test_pkt->packed); - nftest_expect("eth" . ($out_port_offset + 1), $expect_pkt->packed); -} - -sub test_set_nw_tos { - my ($ofp, $sock, $options_ref, $i, $j, $wildcards) = @_; - - my $max_idle = $$options_ref{'max_idle'}; - my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_total = $$options_ref{'pkt_total'}; - - send_expect_exact($ofp, $sock, $options_ref, $i, $j, $max_idle, $pkt_len); - wait_for_flow_expired($ofp, $sock, $options_ref, $pkt_len, $pkt_total); -} - -sub my_test { - my ($sock, $options_ref) = @_; - - # send from every port to every other port - for_all_port_pairs( $ofp, $sock, $options_ref, \&test_set_nw_tos, 0x0); -} - -run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_set_nw_dst/run.pl b/openflow/regress/projects/black_box/regress/test_set_nw_dst/run.pl deleted file mode 100755 index ae101798..00000000 --- a/openflow/regress/projects/black_box/regress/test_set_nw_dst/run.pl +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/perl -w -# test_set_nw_dst - -use strict; -use OF::Includes; - -sub send_expect_exact { - my ($ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len) = @_; - - my $in_port = $in_port_offset + $$options_ref{'port_base'}; - my $out_port = $out_port_offset + $$options_ref{'port_base'}; - - # in_port refers to the flow mod entry's input - - # Create the payload ourselves to make sure the two packets match - # Jean II - my $pkt_payload = [map {int(rand(256))} (1..($pkt_len - 8 - 4 - 16 - 14))]; - - # This is the packet we are sending... - Jean II - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - tos => 0x0, - ttl => 64, - len => $pkt_len, - src_port => 1, - dst_port => 0, - data => $pkt_payload - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - # This is the packet we are expecting to receive - Jean II - my $expect_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - #dst_ip => "192.168.201." . ( $out_port + 1), - dst_ip => ( $out_port ) . ".201.168.192" , - tos => 0x0, - ttl => 64, - len => $pkt_len, - src_port => 1, - dst_port => 0, - data => $pkt_payload - }; - my $expect_pkt = new NF2::UDP_pkt(%$expect_pkt_args); - - #print HexDump ($test_pkt->packed); - - my $wildcards = 0x0; # exact match - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry - - # Get the IP address in the expected packet in binary form - Jean II - my $chg_val_nw_dst = ${$expect_pkt->{IP_hdr}}->dst_ip; - my $nw_dst_addr_chg; - my $ok_org; - ($nw_dst_addr_chg, $ok_org) = NF2::IP_hdr::getIP($chg_val_nw_dst); - - my $flow_mod_pkt = create_flow_mod_from_udp_action($ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards, 'OFPFC_ADD', 'nw_dst', $nw_dst_addr_chg); - - #print HexDump($flow_mod_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent flow_mod message\n"; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - - # Send a packet - ensure packet comes out desired port - nftest_send("eth" . ($in_port_offset + 1), $test_pkt->packed); - nftest_expect("eth" . ($out_port_offset + 1), $expect_pkt->packed); -} - -sub test_set_nw_dst { - my ($ofp, $sock, $options_ref, $i, $j, $wildcards) = @_; - - my $max_idle = $$options_ref{'max_idle'}; - my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_total = $$options_ref{'pkt_total'}; - - send_expect_exact($ofp, $sock, $options_ref, $i, $j, $max_idle, $pkt_len); - wait_for_flow_expired($ofp, $sock, $options_ref, $pkt_len, $pkt_total); -} - -sub my_test { - my ($sock, $options_ref) = @_; - - # send from every port to every other port - for_all_port_pairs($ofp, $sock, $options_ref, \&test_set_nw_dst, 0x0); -} - -run_black_box_test(\&my_test, \@ARGV); diff --git a/openflow/regress/projects/black_box/regress/test_stats_desc/run.pl b/openflow/regress/projects/black_box/regress/test_stats_desc/run.pl deleted file mode 100755 index 9409ac9d..00000000 --- a/openflow/regress/projects/black_box/regress/test_stats_desc/run.pl +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/perl -w -# test_flow_stats - -use strict; -use OF::Includes; - -sub stats_desc_test { - - my ( $sock, $options_ref ) = @_; - - my $port_base = $$options_ref{'port_base'}; - - my $hdr_args = { - version => get_of_ver(), - type => $enums{'OFPT_STATS_REQUEST'}, - length => $ofp->sizeof('ofp_stats_request') , # should generate automatically! - xid => 0x00000001 - }; - - my $stats_request_args = { - header => $hdr_args, - type => $enums{'OFPST_DESC'}, - flags => 0 - }; - - my $stats_request = $ofp->pack( 'ofp_stats_request', $stats_request_args ); - - # Send 'stats_request' message - print $sock $stats_request; - - # Should add timeout here - will crash if no reply - my $recvd_mesg; - sysread( $sock, $recvd_mesg, 1512 ) || die "Failed to receive message: $!"; - - # Inspect message - my $resp_size = length($recvd_mesg); - - my $resp_header = $ofp->unpack( 'ofp_stats_reply', $recvd_mesg ); - - #print HexDump ($recvd_mesg); - print Dumper($resp_header); - - # Verify fields - verify_header( $resp_header, 'OFPT_STATS_REPLY', $resp_size ); - - # Unmarshall embedded description - my $resp_body = $ofp->unpack('ofp_desc_stats', - substr($recvd_mesg, $ofp->offsetof('ofp_stats_reply', 'body'))); - print Dumper($resp_body); - print "keys: " . join(" ",keys %$resp_body) . "\n"; - my $key; - foreach $key (sort keys %$resp_body) - { - my $val = $resp_body->{$key}; - my $len = scalar(@{$val}); - printf("key=%s ref=%s len=%d val='%s'\n", - $key, - ref($val), - $len, - pack("c*", @{$val}) - #@{$val} - ); - } - - #die("forced death"); - die("Missing dp_desc in desc_stats") unless(defined($resp_body->{"dp_desc"})); - -} - -run_black_box_test( \&stats_desc_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_switch_config/run.pl b/openflow/regress/projects/black_box/regress/test_switch_config/run.pl deleted file mode 100755 index cbb4886e..00000000 --- a/openflow/regress/projects/black_box/regress/test_switch_config/run.pl +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/perl -w -# test_switch_config - -use strict; -use OF::Includes; - -sub my_test { - - my ($sock, $options_ref) = @_; - - my $msg = get_config( $ofp, $sock ); - - # Verify that the miss_send_len is set to the correct default - compare( "miss send len", $$msg{'miss_send_len'}, '==', get_of_miss_send_len_default() ); - - # As of OF v0.8.1, there was no default for flags - we assume 0 - # (don't send flow expiration messages) - compare( "flags", $$msg{'flags'}, '==', 0 ); - - # Now, we change the config and check that it has been committed - - # Set flag OFPC_SEND_FLOW_EXP, which has val 1, and should cause flow exps - my $flags = 1; - - # Change miss_send_len from the default - my $miss_send_len = 0x100; - - set_config($ofp, $sock, $options_ref, $flags, $miss_send_len); - - # Give OF switch time to process the set_config - usleep($$options_ref{'send_delay'}); - - $msg = get_config( $ofp, $sock ); - - compare( "miss send len", $$msg{'miss_send_len'}, '==', $miss_send_len ); - compare( "flags", $$msg{'flags'}, '==', $flags ); -} - -run_black_box_test( \&my_test, \@ARGV ); - diff --git a/openflow/regress/projects/black_box/regress/test_tcp_options/run.pl b/openflow/regress/projects/black_box/regress/test_tcp_options/run.pl deleted file mode 100755 index b9025bb0..00000000 --- a/openflow/regress/projects/black_box/regress/test_tcp_options/run.pl +++ /dev/null @@ -1,170 +0,0 @@ -#!/usr/bin/perl -w -# test_tcp_options - -use strict; -use OF::Includes; - -sub create_flow_mod_from_ip { - - my ( $ofp, $udp_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards, $s_port, $d_port ) = @_; - - my $hdr_args = { - version => get_of_ver(), - type => $enums{'OFPT_FLOW_MOD'}, - length => $ofp->sizeof('ofp_flow_mod') + $ofp->sizeof('ofp_action_output'), - xid => 0x0000000 - }; - - # might be cleaner to convert the exported colon-hex MAC addrs - #print ${$udp_pkt->{Ethernet_hdr}}->SA . "\n"; - #print ${$test_pkt->{Ethernet_hdr}}->SA . "\n"; - my $ref_to_eth_hdr = ( $udp_pkt->{'Ethernet_hdr'} ); - my $ref_to_ip_hdr = ( $udp_pkt->{'IP_hdr'} ); - - # pointer to array - my $eth_hdr_bytes = $$ref_to_eth_hdr->{'bytes'}; - my $ip_hdr_bytes = $$ref_to_ip_hdr->{'bytes'}; - my @dst_mac_subarray = @{$eth_hdr_bytes}[ 0 .. 5 ]; - my @src_mac_subarray = @{$eth_hdr_bytes}[ 6 .. 11 ]; - - my @src_ip_subarray = @{$ip_hdr_bytes}[ 12 .. 15 ]; - my @dst_ip_subarray = @{$ip_hdr_bytes}[ 16 .. 19 ]; - - my $src_ip = - ( ( 2**24 ) * $src_ip_subarray[0] + - ( 2**16 ) * $src_ip_subarray[1] + - ( 2**8 ) * $src_ip_subarray[2] + - $src_ip_subarray[3] ); - - my $dst_ip = - ( ( 2**24 ) * $dst_ip_subarray[0] + - ( 2**16 ) * $dst_ip_subarray[1] + - ( 2**8 ) * $dst_ip_subarray[2] + - $dst_ip_subarray[3] ); - - # read IP_header protocol field - my $iph = $udp_pkt->{'IP_hdr'}; - my $proto = $$iph->proto(); - - my $match_args = { - wildcards => $wildcards, - in_port => $in_port, - dl_src => \@src_mac_subarray, - dl_dst => \@dst_mac_subarray, - dl_vlan => 0xffff, - dl_vlan_pcp => 0x00, - dl_type => 0x0800, - nw_src => $src_ip, - nw_dst => $dst_ip, - nw_proto => $proto, #any protocol - tp_src => $s_port, - tp_dst => $d_port - }; - - print "My Out Port: ${out_port}\n"; - my $action_output_args = { - type => $enums{'OFPAT_OUTPUT'}, - len => $ofp->sizeof('ofp_action_output'), - port => $out_port, - max_len => 0 # send entire packet - }; - my $action_output = $ofp->pack('ofp_action_output', $action_output_args); - - my $flow_mod_args = { - header => $hdr_args, - match => $match_args, - command => $enums{'OFPFC_ADD'}, - idle_timeout => $max_idle, - hard_timeout => $max_idle, - flags => $flags, - priority => 0, - buffer_id => -1 - }; - my $flow_mod = $ofp->pack( 'ofp_flow_mod', $flow_mod_args ); - - my $flow_mod_pkt = $flow_mod . $action_output; - - return $flow_mod_pkt; -} - -sub send_tcp_op_expect_exact { - - my ( $ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len ) = @_; - - my $in_port = $in_port_offset + $$options_ref{'port_base'}; - my $out_port = $out_port_offset + $$options_ref{'port_base'}; - - my $src_tcp_port = 70; - my $dst_tcp_port = 80; - - # in_port refers to the flow mod entry's input - my @tcp_payload = ( # 30 bytes - 0x00, 0x46, 0x00, 0x50, # $src_tcp_port, $dst_tcp_port (should set automatically) - 0x01, 0x23, 0x45, 0x67, #Seq - 0x01, 0x23, 0x45, 0x00, #Ack - 0x58, 0x23, 0x00, 0x11, #Offset, Flag, Win - 0xaa, 0xbb, 0x00, 0x00, #Chksum, Urgent - 0x03, 0x03, 0x02, 0x00, #TCP Option - 0xaa, 0xbb, 0xcc, 0xdd, #TCP Content - 0xee, 0xff #TCP Content - ); - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - proto => 6, # TCP protocol id - }; - - my $test_pkt = new NF2::IP_pkt(%$test_pkt_args); - my $payload = $test_pkt->{'payload'}; - $$payload->set_bytes(@tcp_payload); - - #print HexDump ( $test_pkt->packed ); - - #my $wildcards = 0; # exact match - my $wildcards = $enums{'OFPFW_TP_SRC'} | - $enums{'OFPFW_TP_DST'};# | - # $enums{'OFPFW_NW_PROTO'}; # wildcard match (don't care udp src/dst ports) - - my $flags = $enums{'OFPFF_SEND_FLOW_REM'}; - my $flow_mod_pkt = - create_flow_mod_from_ip( $ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards, - $src_tcp_port, $dst_tcp_port ); - - #print HexDump($flow_mod_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_pkt; - print "sent flow_mod message\n"; - usleep($$options_ref{'send_delay'}); - - # Send a packet - ensure packet comes out desired port - nftest_send( "eth" . ( $in_port_offset + 1), $test_pkt->packed ); - nftest_expect( "eth" . ( $out_port_offset + 1 ), $test_pkt->packed ); -} - -sub test_tcp_options { - my ( $ofp, $sock, $options_ref, $i, $j, $wildcards ) = @_; - - my $max_idle = $$options_ref{'max_idle'}; - #my $pkt_len = $$options_ref{'pkt_len'}; - my $pkt_len = 64; # len = 14(Ethr_hdr)+ 20(IP_header)+ 30(TCP_header+Option) - # = 64 (IPlen = 50) - my $pkt_total = $$options_ref{'pkt_total'}; - - send_tcp_op_expect_exact( $ofp, $sock, $options_ref, $i, $j, $max_idle, $pkt_len ); - #sleep(5); - wait_for_flow_expired( $ofp, $sock, $options_ref, $pkt_len, $pkt_total ); -} - -sub my_test { - my ( $sock, $options_ref ) = @_; - - # send from every port to every other port - for_all_port_pairs( $ofp, $sock, $options_ref, \&test_tcp_options, 0x0); -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/black_box/regress/tests.txt b/openflow/regress/projects/black_box/regress/tests.txt deleted file mode 100644 index f77158ec..00000000 --- a/openflow/regress/projects/black_box/regress/tests.txt +++ /dev/null @@ -1,103 +0,0 @@ -## two #'s = not tested; 1 # = worked once - -# Basic Tests -test_hello/run.pl -test_barrier/run.pl -test_packet_in/run.pl -test_packet_out/run.pl -test_switch_config/run.pl -test_flow_expired/run.pl -test_flow_expired_idle_timeout/run.pl -test_flow_expired_precision/run.pl -test_flow_expired_send_flow_exp/run.pl -test_miss_send_length/run.pl - -# Read State Tests -test_stats_desc/run.pl -test_port_stats/run.pl -test_flow_stats/run.pl -test_flow_stats_precision/run.pl - -## Forwarding Tests -test_forward_any_port/run.pl -test_forward_exact_port/run.pl -test_forward_broadcast_exact_port/run.pl -test_forward_exact_all/run.pl -test_forward_exact_controller/run.pl -test_forward_wildcard_port/run.pl -test_forward_wildcard_all/run.pl -test_forward_wildcard_controller/run.pl -test_forward_after_expiration/run.pl -test_forward_overlapping_flow_entries/run.pl -test_delete/run.pl -test_delete_strict/run.pl -test_delete_send_flow_exp/run.pl -test_drop_exact/run.pl - -## Modify Action Tests -test_forward_exact_modify_action/run.pl -test_forward_wildcard_modify_action/run.pl -test_flow_mod_check/run.pl -test_set_nw_dst/run.pl -test_set_n_match_nw_tos/run.pl -test_set_dl_nw_flip/run.pl - -## ICMP handling Tests -test_forward_exact_icmp_port/run.pl -test_forward_exact_icmp_all/run.pl -test_forward_exact_icmp_controller/run.pl -test_forward_exact_icmp_fool/run.pl -test_forward_wildcard_icmp_port/run.pl -test_forward_wildcard_icmp_all/run.pl -test_forward_wildcard_icmp_controller/run.pl -test_forward_wildcard_icmp_fool/run.pl - -## ARP handling Tests -test_forward_exact_arp_port/run.pl -test_forward_exact_arp_all/run.pl -test_forward_exact_arp_controller/run.pl -test_forward_exact_arp_fool/run.pl -test_forward_wildcard_arp_port/run.pl -test_forward_wildcard_arp_all/run.pl -test_forward_wildcard_arp_controller/run.pl -test_forward_wildcard_arp_fool/run.pl - -# Flow cookies -test_cookie_flow_expired/run.pl -test_cookie_flow_stats/run.pl - -## Slicing Tests - can be disable via --no_slicing -test_queue_config/run.pl -## These assume that there is a queue with queue_id=1 at port 1. -## Uncomment if your setup supports this. -## Should work OK with the reference implementation -#test_queue_stats/run.pl -test_queue_forward/run.pl - -## Unusual Data -test_ip_options/run.pl -##test_ip_protocol/run.pl -test_ip_offset/run.pl -test_tcp_options/run.pl -##test_llc/run.pl - -# Failover Tests -test_failover_startup/run.pl -test_failover_close/run.pl - -# BELOW NOT INCLUDED IN CURRRENT RELEASE -# WILL BE AVAILABLE SOON -# Stress Tests / Performance Evaluation -#test_send_bandwidth_fixed/run.pl -#test_send_bandwidth_random/run.pl -#test_add_flow_bandwidth/run.pl -#test_add_flow_latency/run.pl -#test_receive_bandwidth_fixed/run.pl -#test_receive_bandwidth_random/run.pl -#test_forward_bandwidth_fixed/run.pl -#test_forward_bandwidth_random/run.pl -#test_forward_latency/run.pl -#test_switch_bandwidth_random/run.pl -#test_switch_bandwidth_random/run.pl -# Additional Failover tests -#test_failover_stop_responding/run.pl diff --git a/openflow/regress/projects/controller_disconnect/regress/common/setup b/openflow/regress/projects/controller_disconnect/regress/common/setup deleted file mode 100755 index f796718c..00000000 --- a/openflow/regress/projects/controller_disconnect/regress/common/setup +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use Test::TestLib; -use OF::OFUtil; - -my $mapFile; -my $platform; -my $args; - -# Process command line options -unless ( - GetOptions ( - "map=s" => \$mapFile, - "common-st-args=s" => \$platform, - ) -) -{ - print "invalid command format\n"; - exit(1); -} - -if (defined($mapFile)) { - $args = "--map=$mapFile"; -} - -if (!defined($platform)) { - print "no platform defined\n"; - exit(1); -} -else { - print "platform = $platform\n"; -} - -$args .= " --emerg"; - -my $filename = "of_${platform}_setup.pl"; - -# exit if of_${platform}_setup.pl not in path -if (-e "$ENV{'OFT_ROOT'}/bin/$filename") { - #system("$filename " . $args . " 2> /dev/null > /dev/null"); - system("$ENV{'OFT_ROOT'}/bin/$filename " . $args ); - #setup_kmod(); - exit (0); -} else { - print "couldn't find setup file $filename\n"; - exit (1); -} diff --git a/openflow/regress/projects/controller_disconnect/regress/common/teardown b/openflow/regress/projects/controller_disconnect/regress/common/teardown deleted file mode 100755 index 6f1f8391..00000000 --- a/openflow/regress/projects/controller_disconnect/regress/common/teardown +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use Test::TestLib; -use OF::OFUtil; - -my $mapFile; -my $platform; -my $args; - -# Process command line options -unless ( - GetOptions ( - "map=s" => \$mapFile, - "common-st-args=s" => \$platform, - ) -) -{ - print "invalid command format\n"; - exit(1); -} - -if (defined($mapFile)) { - $args = "--map=$mapFile"; -} - -if (!defined($platform)) { - print "no platform defined\n"; - exit(1); -} -else { - print "platform = $platform\n"; -} - -my $filename = "of_${platform}_teardown.pl"; - -# exit if of_${platform}_setup.pl not in path -if (-e "$ENV{'OFT_ROOT'}/bin/$filename") { - #system("$filename " . $args . " 2> /dev/null > /dev/null"); - system("$ENV{'OFT_ROOT'}/bin/$filename " . $args ); - #teardown_kmod(); - exit (0); -} else { - print "couldn't find setup file $filename\n"; - exit (1); -} diff --git a/openflow/regress/projects/controller_disconnect/regress/test_emergency_table/run.pl b/openflow/regress/projects/controller_disconnect/regress/test_emergency_table/run.pl deleted file mode 100755 index 7e07a6c8..00000000 --- a/openflow/regress/projects/controller_disconnect/regress/test_emergency_table/run.pl +++ /dev/null @@ -1,107 +0,0 @@ -#!/usr/bin/perl -w -# test_emergency_table - -use strict; -use OF::Includes; -use OF::OFUtil; - -sub test_emergency_cache_first { - my ( $ofp, $sock, $options_ref, $i, $j, $wildcards ) = @_; - - my $max_idle = $$options_ref{'max_idle'}; - my $pkt_len = $$options_ref{'pkt_len'}; - my $in_port = $i + $$options_ref{'port_base'}; - my $out_port = $j + $$options_ref{'port_base'}; - my $test_pkt_args = { - DA => "00:00:00:00:00:" . sprintf( "%02d", $out_port ), - SA => "00:00:00:00:00:" . sprintf( "%02d", $in_port ), - src_ip => "192.168.200." . ( $in_port ), - dst_ip => "192.168.201." . ( $out_port ), - ttl => 64, - len => $pkt_len, - src_port => 70, - dst_port => 80 - }; - my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args); - - print "Set both normal and emergency flow table. Normal key must win\n"; - - # 1st flow entry -- exact match, normal flow table - my $max_idle_no_expire = 0; - my $normal_wildcards = 0x0; # exact match - my $normal_flags = $enums{'OFPFF_SEND_FLOW_REM'}; # want flow expiry - my $flow_mod_normal_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $out_port, $max_idle_no_expire, $normal_flags, $normal_wildcards ); - - # 2nd flow entry -- wildcard match all, emergency flow table - my $emergency_wildcards = $enums{'OFPFW_ALL'}; # wildcard match all to the all ports - my $emergency_flags = $enums{'OFPFF_EMERG'}; - my $flow_mod_emergency_pkt = - create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $enums{'OFPP_ALL'}, $max_idle_no_expire, $emergency_flags, $emergency_wildcards ); - - #print HexDump($flow_mod_normal_pkt); - #print HexDump($flow_mod_emergency_pkt); - - # Send 'flow_mod' message - print $sock $flow_mod_normal_pkt; - print "sent flow_mod message (normal table)\n"; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - - # Send 2nd 'flow_mod' message - print $sock $flow_mod_emergency_pkt; - print "sent flow_mod message (emergency table)\n"; - - # Give OF switch time to process the flow mod - usleep($$options_ref{'send_delay'}); - - # Send a packet - ensure packet comes out desired port - print "Verify packets are forwarded correctly\n"; - nftest_send( "eth" . ( $i + 1 ), $test_pkt->packed ); - nftest_expect( "eth" . ( $j + 1 ), $test_pkt->packed ); - - # Wait for ECHO_REQUEST but don't reply so that ofprotocol notices disconnection. - wait_for_echo_request ( $ofp, $sock, $options_ref, $ofp->sizeof('ofp_header')); - return $test_pkt; -} - -sub test_emergency_cache_second { - my ( $test_pkt, $options_ref, $i, $j ) = @_; - - print "sending from $i to $j, but expect the packet from all ports\n"; - nftest_send( "eth" . ( $i + 1 ), $test_pkt->packed ); - - # expect packets on all other interfaces - print "expect multiple packets\n"; - - for ( my $k = 0 ; $k < $$options_ref{'num_ports'} ; $k++ ) { - if ( $k != $i ) { - nftest_expect( "eth" . ( $k + 1), $test_pkt->packed ); - } - } -} - -sub my_test { - my ($sock, $options_ref) = @_; - - if ( not defined( $$options_ref{'no_emerg'} ) ) { - #This test uses two ports - my $inport = 0; - my $outport = 1; - my $wildcards = 0; #exact match - - # Wait until switch notices disconnection. it depends on implementation - my $wait_timer = 20; - - my $test_pkt = test_emergency_cache_first($ofp, $sock, $options_ref, $inport, $outport, $wildcards); - - # Wait until ofprotocol notices that connection is broken - sleep $wait_timer; - - # chek if the emergency table has become active - test_emergency_cache_second($test_pkt, $options_ref, $inport, $outport); - } -} - -run_black_box_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/controller_disconnect/regress/tests.txt b/openflow/regress/projects/controller_disconnect/regress/tests.txt deleted file mode 100644 index 0d34d9b3..00000000 --- a/openflow/regress/projects/controller_disconnect/regress/tests.txt +++ /dev/null @@ -1,2 +0,0 @@ -test_emergency_table/run.pl -#test_reconnect/run.pl diff --git a/openflow/regress/projects/learning_switch/regress/common/setup b/openflow/regress/projects/learning_switch/regress/common/setup deleted file mode 100755 index 29653173..00000000 --- a/openflow/regress/projects/learning_switch/regress/common/setup +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use Test::TestLib; -use OF::OFUtil; - -my $mapFile; -my $platform; -my $args; - -# Process command line options -unless ( - GetOptions ( - "map=s" => \$mapFile, - "common-st-args=s" => \$platform, - ) -) -{ - print "invalid command format\n"; - exit(1); -} - -if (defined($mapFile)) { - $args = "--map=$mapFile"; -} - -if (!defined($platform)) { - print "no platform defined\n"; - exit(1); -} -else { - print "platform = $platform\n"; -} - -my $filename = "of_${platform}_setup.pl"; - -# exit if of_${platform}_setup.pl not in path -if (-e "$ENV{'OFT_ROOT'}/bin/$filename") { - system("$ENV{'OFT_ROOT'}/bin/$filename " . $args . " 2> /dev/null > /dev/null"); - #setup_kmod(); - exit (0); -} else { - print "couldn't find setup file $filename\n"; - exit (1); -} diff --git a/openflow/regress/projects/learning_switch/regress/common/teardown b/openflow/regress/projects/learning_switch/regress/common/teardown deleted file mode 100755 index c1813189..00000000 --- a/openflow/regress/projects/learning_switch/regress/common/teardown +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/perl -w - -use Getopt::Long; - -use Test::TestLib; -use OF::OFUtil; - -my $mapFile; -my $platform; -my $args; - -# Process command line options -unless ( - GetOptions ( - "map=s" => \$mapFile, - "common-st-args=s" => \$platform, - ) -) -{ - print "invalid command format\n"; - exit(1); -} - -if (defined($mapFile)) { - $args = "map=$mapFile"; -} - -if (!defined($platform)) { - print "no platform defined\n"; - exit(1); -} -else { - print "platform = $platform\n"; -} - -my $filename = "of_${platform}_teardown.pl"; - -# exit if of_${platform}_setup.pl not in path -if (-e "$ENV{'OFT_ROOT'}/bin/$filename") { - system("$ENV{'OFT_ROOT'}/bin/$filename " . $args . " 2> /dev/null > /dev/null"); - #teardown_kmod(); - exit (0); -} else { - print "couldn't find setup file $filename\n"; - exit (1); -} diff --git a/openflow/regress/projects/learning_switch/regress/test_broadcast/run.pl b/openflow/regress/projects/learning_switch/regress/test_broadcast/run.pl deleted file mode 100755 index f721f4db..00000000 --- a/openflow/regress/projects/learning_switch/regress/test_broadcast/run.pl +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/perl -w -# test_broadcast - -use strict; -use OF::Includes; - -sub gen_broadcast_pkt { - my ($portNum) = shift; - - my $pkt_args = { - DA => "FF:FF:FF:FF:FF:FF", - SA => "00:00:00:00:00:0" . $portNum, - src_ip => "192.168." . $portNum . ".40", - dst_ip => "255.255.255.255", - ttl => 64, - len => 64 - }; - my $pkt = new NF2::IP_pkt(%$pkt_args); - return $pkt; -} - -sub send_expect_broadcast { - my ( $portNum, $pkt, $delta_ref ) = @_; - - send_and_count( 'eth' . $portNum, $pkt->packed, $delta_ref ); - for ( my $i = 1 ; $i <= 4 ; $i++ ) { - if ( $i != $portNum ) { - expect_and_count( 'eth' . $i, $pkt->packed, $delta_ref ); - } - } -} - -sub my_test { - - my %delta; - - for ( my $i = 1 ; $i < 4 ; $i++ ) { - my $pkt = gen_broadcast_pkt($i); - - # send one broadcast packet, then do it again on the same port - send_expect_broadcast( $i, $pkt, \%delta ); - sleep 0.1; - send_expect_broadcast( $i, $pkt, \%delta ); - sleep 0.1; - } - - return %delta; -} - -run_learning_switch_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/learning_switch/regress/test_forward_bandwidth/run.pl b/openflow/regress/projects/learning_switch/regress/test_forward_bandwidth/run.pl deleted file mode 100755 index 473afa81..00000000 --- a/openflow/regress/projects/learning_switch/regress/test_forward_bandwidth/run.pl +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/perl -w -#test_unicast_unknown - -use Test::TestLib; -use Test::PacketLib; -use OF::OFUtil; -use Time::HiRes qw(sleep gettimeofday tv_interval usleep); -use strict; - -sub my_test { - my $cnt = 0; - my %delta; - my $pkt_len = 1512; - - my $pkt_args = { - DA => "00:01:00:00:00:02", - SA => "00:00:00:00:00:01", - src_ip => "192.168.0.40", - dst_ip => "192.168.0.41", - ttl => 64, - len => 64 - }; - my $pkt = new NF2::IP_pkt(%$pkt_args); - - # send one packet; controller should learn MAC, add a flow - # entry, and send this packet out the other interfaces - - send_and_count( nftest_get_iface('eth1'), $pkt->packed, \%delta ); - expect_and_count( nftest_get_iface('eth2'), $pkt->packed, \%delta ); - expect_and_count( nftest_get_iface('eth3'), $pkt->packed, \%delta ); - expect_and_count( nftest_get_iface('eth4'), $pkt->packed, \%delta ); - - my @start_time = gettimeofday(); - for ( $cnt = 10 ; $cnt < 20 ; $cnt++ ) { - for ( my $t = 10 ; $t < 100 ; $t++ ) { - my $pkt_args = { - DA => "00:00:00:00:00:01", - SA => "00:00:00:00:$t:$cnt", - src_ip => "192.168.$t.$cnt", - dst_ip => "192.168.1.40", - ttl => 64, - len => $pkt_len - }; - my $pkt = new NF2::IP_pkt(%$pkt_args); - - send_and_count( nftest_get_iface('eth2'), $pkt->packed, \%delta ); - expect_and_count( nftest_get_iface('eth1'), $pkt->packed, \%delta ); - } - } - ( my $second, my $micro ) = tv_interval( \@start_time ); - my $time_elapsed = ( $second + $micro * 1e-6 ); - - my $bw_result = (900 * $pkt_len * 8) / $time_elapsed; - print "PACKET LENGTH: $pkt_len \n"; - print "TIME ELAPSED: $time_elapsed \n"; - print "RESULTING BW: $bw_result bits/sec \n"; - - return %delta; -} - -# how do we pass the cmd-line arguments to the script? -run_learning_switch_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/learning_switch/regress/test_forward_latency/run.pl b/openflow/regress/projects/learning_switch/regress/test_forward_latency/run.pl deleted file mode 100755 index e9690d80..00000000 --- a/openflow/regress/projects/learning_switch/regress/test_forward_latency/run.pl +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/perl -w -#test_fwd_delay -# send 1000 packets to find latency for both new flows and existing ones - -use Test::TestLib; -use Test::PacketLib; -use OF::OFUtil; -use strict; -use Time::HiRes qw(sleep gettimeofday tv_interval usleep); - -sub my_test { - my $cnt = 0; - - my $start_time_ref = [gettimeofday]; - my %delta; - for ( my $t = 10 ; $t < 20 ; $t++ ) { - for ( $cnt = 10 ; $cnt < 100 ; $cnt++ ) { - my $pkt_args = { - DA => "00:01:00:00:$t:$cnt", - SA => "00:00:00:00:00:01", - src_ip => "192.168.0.40", - dst_ip => "192.168.$cnt.$t", - ttl => 64, - len => 64 - }; - my $pkt = new NF2::IP_pkt(%$pkt_args); - - # send one packet; controller should learn MAC, add a flow - # entry, and send this packet out the other interfaces - send_and_count( nftest_get_iface('eth1'), $pkt->packed, \%delta ); - expect_and_count( nftest_get_iface('eth2'), $pkt->packed, \%delta ); - expect_and_count( nftest_get_iface('eth3'), $pkt->packed, \%delta ); - expect_and_count( nftest_get_iface('eth4'), $pkt->packed, \%delta ); - } - } - my $total_time_unknown = tv_interval( $start_time_ref ); - - $start_time_ref = [gettimeofday()]; - for ( $cnt = 10 ; $cnt < 20 ; $cnt++ ) { - for ( my $t = 10 ; $t < 100 ; $t++ ) { - my $pkt_args = { - DA => "00:00:00:00:00:01", - SA => "00:00:00:00:$t:$cnt", - src_ip => "192.168.$t.$cnt", - dst_ip => "192.168.1.40", - ttl => 64, - len => 64 - }; - my $pkt = new NF2::IP_pkt(%$pkt_args); - - # send packet; flow entries are already added for these - send_and_count( nftest_get_iface('eth2'), $pkt->packed, \%delta ); - expect_and_count( nftest_get_iface('eth1'), $pkt->packed, \%delta ); - } - } - my $total_time_known = tv_interval( $start_time_ref ); - - # convert to ms, and consider that we sent 900 packets each - my $time_unknown_ms = $total_time_unknown * 1000 / 900; - my $time_known_ms = $total_time_known * 1000 / 900; - - printf("Delay with unknown MAC: %.3f ms\n", $time_unknown_ms); - printf("Delay with known MAC: %.3f ms\n", $time_known_ms); - - return %delta; -} - -# how do we pass the cmd-line arguments to the script? -run_learning_switch_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/learning_switch/regress/test_hub_connected/run.pl b/openflow/regress/projects/learning_switch/regress/test_hub_connected/run.pl deleted file mode 100755 index f5881672..00000000 --- a/openflow/regress/projects/learning_switch/regress/test_hub_connected/run.pl +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/perl -w -# test_same_port? - -use strict; -use OF::Includes; - -sub my_test { - - my %delta; - - # Host A and B are both on p0. they send unicast with unknown dest. - - my $pkt_args = { - DA => "00:00:00:00:00:09", - SA => "00:00:00:00:00:01", - src_ip => "192.168.0.40", - dst_ip => "192.168.7.40", - ttl => 64, - len => 64 - }; - my $pkt = new NF2::IP_pkt(%$pkt_args); - - # send one packet; controller should learn MAC, add a flow - # entry, and send this packet out the other interfaces - print "Sending now: \n"; - send_and_count( 'eth1', $pkt->packed, \%delta ); - expect_and_count( 'eth2', $pkt->packed, \%delta ); - expect_and_count( 'eth3', $pkt->packed, \%delta ); - expect_and_count( 'eth4', $pkt->packed, \%delta ); - - # sleep as long as needed for the test to finish - sleep 0.1; - - my $pkt_args = { - DA => "00:00:00:00:00:08", - SA => "00:00:00:00:00:02", - src_ip => "192.168.1.40", - dst_ip => "192.168.6.40", - ttl => 64, - len => 64 - }; - my $pkt = new NF2::IP_pkt(%$pkt_args); - send_and_count( 'eth1', $pkt->packed, \%delta ); - expect_and_count( 'eth2', $pkt->packed, \%delta ); - expect_and_count( 'eth3', $pkt->packed, \%delta ); - expect_and_count( 'eth4', $pkt->packed, \%delta ); - sleep 0.1; - - # Now A and B try to talk to each other. see if switch drop the packet or not - - my $pkt_args = { - DA => "00:00:00:00:00:02", - SA => "00:00:00:00:00:01", - src_ip => "192.168.0.40", - dst_ip => "192.168.1.40", - ttl => 64, - len => 64 - }; - my $pkt = new NF2::IP_pkt(%$pkt_args); - send_and_count( 'eth1', $pkt->packed, \%delta ); - return %delta; -} - -run_learning_switch_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/learning_switch/regress/test_unicast_known/run.pl b/openflow/regress/projects/learning_switch/regress/test_unicast_known/run.pl deleted file mode 100755 index 34c2c09d..00000000 --- a/openflow/regress/projects/learning_switch/regress/test_unicast_known/run.pl +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/perl -w -# test_unicast_known - -use strict; -use OF::Includes; - -sub my_test { - - my $pkt_args = { - DA => "00:00:00:00:00:02", - SA => "00:00:00:00:00:01", - src_ip => "192.168.0.40", - dst_ip => "192.168.1.40", - ttl => 64, - len => 64 - }; - my $pkt = new NF2::IP_pkt(%$pkt_args); - - my %delta; - - # send one packet; controller should learn MAC, add a flow - # entry, and send this packet out the other interfaces - print "Sending now: \n"; - send_and_count( 'eth1', $pkt->packed, \%delta ); - expect_and_count( 'eth2', $pkt->packed, \%delta ); - expect_and_count( 'eth3', $pkt->packed, \%delta ); - expect_and_count( 'eth4', $pkt->packed, \%delta ); - sleep(.1); - - $pkt_args = { - DA => "00:00:00:00:00:01", - SA => "00:00:00:00:00:02", - src_ip => "192.168.1.40", - dst_ip => "192.168.0.40", - ttl => 64, - len => 64 - }; - $pkt = new NF2::IP_pkt(%$pkt_args); - send_and_count( 'eth2', $pkt->packed, \%delta ); - expect_and_count( 'eth1', $pkt->packed, \%delta ); - sleep(.1); - - $pkt_args = { - DA => "00:00:00:00:00:01", - SA => "00:00:00:00:00:03", - src_ip => "192.168.2.40", - dst_ip => "192.168.0.40", - ttl => 64, - len => 64 - }; - $pkt = new NF2::IP_pkt(%$pkt_args); - send_and_count( 'eth3', $pkt->packed, \%delta ); - expect_and_count( 'eth1', $pkt->packed, \%delta ); - sleep(.1); - - $pkt_args = { - DA => "00:00:00:00:00:01", - SA => "00:00:00:00:00:04", - src_ip => "192.168.3.40", - dst_ip => "192.168.0.40", - ttl => 64, - len => 64 - }; - $pkt = new NF2::IP_pkt(%$pkt_args); - send_and_count( 'eth4', $pkt->packed, \%delta ); - expect_and_count( 'eth1', $pkt->packed, \%delta ); - - return %delta; -} - -run_learning_switch_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/learning_switch/regress/test_unicast_move/run.pl b/openflow/regress/projects/learning_switch/regress/test_unicast_move/run.pl deleted file mode 100755 index 5bc4670d..00000000 --- a/openflow/regress/projects/learning_switch/regress/test_unicast_move/run.pl +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/perl -w -# test_unicast_move - -use strict; -use OF::Includes; - -sub my_test { - - my %delta; - - # host A's MAC address is 00:00:00:00:00:01 - - my $pkt_args = { - DA => "00:00:00:00:00:02", - SA => "00:00:00:00:00:01", - src_ip => "192.168.0.40", - dst_ip => "192.168.1.40", - ttl => 64, - len => 64 - }; - my $pkt = new NF2::IP_pkt(%$pkt_args); - - # send one packet; controller should learn MAC, add a flow - # entry, and send this packet out the other interfaces - print "Sending now: \n"; - send_and_count( 'eth1', $pkt->packed, \%delta ); - expect_and_count( 'eth2', $pkt->packed, \%delta ); - expect_and_count( 'eth3', $pkt->packed, \%delta ); - expect_and_count( 'eth4', $pkt->packed, \%delta ); - - # sleep as long as needed for the test to finish - sleep 0.1; - - $pkt_args = { - DA => "00:00:00:00:00:01", - SA => "00:00:00:00:00:02", - src_ip => "192.168.1.40", - dst_ip => "192.168.0.40", - ttl => 64, - len => 64 - }; - $pkt = new NF2::IP_pkt(%$pkt_args); - send_and_count( 'eth2', $pkt->packed, \%delta ); - expect_and_count( 'eth1', $pkt->packed, \%delta ); - sleep 0.1; - - #Now Host A Has Changed Location and Attached to p2 - #It will send a packet to p1 form its new location - $pkt_args = { - DA => "00:00:00:00:00:02", - SA => "00:00:00:00:00:01", - src_ip => "192.168.2.40", - dst_ip => "192.168.1.40", - ttl => 64, - len => 64 - }; - $pkt = new NF2::IP_pkt(%$pkt_args); - send_and_count( 'eth3', $pkt->packed, \%delta ); - expect_and_count( 'eth2', $pkt->packed, \%delta ); - sleep 0.1; - - # Now p1 sends something to Host A which is now attached to p2 - # we expect the switch to already updated its entry for Host A - $pkt_args = { - DA => "00:00:00:00:00:01", - SA => "00:00:00:00:00:02", - src_ip => "192.168.1.40", - dst_ip => "192.168.2.40", - ttl => 64, - len => 64 - }; - $pkt = new NF2::IP_pkt(%$pkt_args); - send_and_count( 'eth2', $pkt->packed, \%delta ); - expect_and_count( 'eth3', $pkt->packed, \%delta ); - - return %delta; -} - -run_learning_switch_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/learning_switch/regress/test_unicast_multiple_hosts/run.pl b/openflow/regress/projects/learning_switch/regress/test_unicast_multiple_hosts/run.pl deleted file mode 100755 index 73c0807b..00000000 --- a/openflow/regress/projects/learning_switch/regress/test_unicast_multiple_hosts/run.pl +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/perl -w -# test_unicast_multiple_hosts - -use strict; -use OF::Includes; - -sub my_test { - - my %delta; - - my $pkt_args = { - DA => "00:00:00:00:00:02", - SA => "00:00:00:00:00:01", - src_ip => "192.168.0.40", - dst_ip => "192.168.1.40", - ttl => 64, - len => 64 - }; - my $pkt = new NF2::IP_pkt(%$pkt_args); - - # send one packet; controller should learn MAC, add a flow - # entry, and send this packet out the other interfaces - print "Sending now: \n"; - send_and_count( 'eth1', $pkt->packed, \%delta ); - expect_and_count( 'eth2', $pkt->packed, \%delta ); - expect_and_count( 'eth3', $pkt->packed, \%delta ); - expect_and_count( 'eth4', $pkt->packed, \%delta ); - - # sleep as long as needed for the test to finish - sleep 0.5; - my $count = 10; - my $cnt = 10; - - for ( $cnt = 11 ; $cnt < 21 ; $cnt++ ) { - for ( $count = 10 ; $count < 12 ; $count++ ) { - - $pkt_args = { - DA => "00:00:00:00:00:01", - SA => "00:00:00:$cnt:10:$count", - src_ip => "192.168.$count.$cnt", - dst_ip => "192.168.0.40", - ttl => 64, - len => 64 - }; - $pkt = new NF2::IP_pkt(%$pkt_args); - send_and_count( 'eth2', $pkt->packed, \%delta ); - expect_and_count( 'eth1', $pkt->packed, \%delta ); - sleep 0.1; - - } - } - - for ( $cnt = 21 ; $cnt < 31 ; $cnt++ ) { - for ( $count = 10 ; $count < 12 ; $count++ ) { - - $pkt_args = { - DA => "00:00:00:00:00:01", - SA => "00:00:00:$cnt:11:$count", - src_ip => "192.168.$count.$cnt", - dst_ip => "192.168.0.40", - ttl => 64, - len => 64 - }; - $pkt = new NF2::IP_pkt(%$pkt_args); - send_and_count( 'eth3', $pkt->packed, \%delta ); - expect_and_count( 'eth1', $pkt->packed, \%delta ); - sleep 0.1; - } - } - - for ( $cnt = 31 ; $cnt < 41 ; $cnt++ ) { - for ( $count = 10 ; $count < 12 ; $count++ ) { - - $pkt_args = { - DA => "00:00:00:00:00:01", - SA => "00:00:00:$cnt:12:$count", - src_ip => "192.168.$count.$cnt", - dst_ip => "192.168.0.40", - ttl => 64, - len => 64 - }; - $pkt = new NF2::IP_pkt(%$pkt_args); - send_and_count( 'eth4', $pkt->packed, \%delta ); - expect_and_count( 'eth1', $pkt->packed, \%delta ); - sleep 0.1; - - } - } - - return %delta; -} - -run_learning_switch_test( \&my_test, \@ARGV ); \ No newline at end of file diff --git a/openflow/regress/projects/learning_switch/regress/test_unicast_self/run.pl b/openflow/regress/projects/learning_switch/regress/test_unicast_self/run.pl deleted file mode 100755 index 4db2371b..00000000 --- a/openflow/regress/projects/learning_switch/regress/test_unicast_self/run.pl +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/perl -w -# test_unicast_self - -use strict; -use OF::Includes; - -sub my_test { - - my %delta; - - # Send packets with same DA and SA; should be ignored - my $pkt_args = { - DA => "00:00:00:00:00:01", - SA => "00:00:00:00:00:01", - src_ip => "192.168.0.40", - dst_ip => "192.168.0.40", - ttl => 64, - len => 64 - }; - my $pkt = new NF2::IP_pkt(%$pkt_args); - - print "Sending now: \n"; - send_and_count( 'eth1', $pkt->packed, \%delta ); - - $pkt_args = { - DA => "00:00:00:00:00:02", - SA => "00:00:00:00:00:02", - src_ip => "192.168.1.40", - dst_ip => "192.168.1.40", - ttl => 64, - len => 64 - }; - $pkt = new NF2::IP_pkt(%$pkt_args); - send_and_count( 'eth2', $pkt->packed, \%delta ); - - $pkt_args = { - DA => "00:00:00:00:00:03", - SA => "00:00:00:00:00:03", - src_ip => "192.168.2.40", - dst_ip => "192.168.2.40", - ttl => 64, - len => 64 - }; - $pkt = new NF2::IP_pkt(%$pkt_args); - send_and_count( 'eth3', $pkt->packed, \%delta ); - - $pkt_args = { - DA => "00:00:00:00:00:04", - SA => "00:00:00:00:00:04", - src_ip => "192.168.3.40", - dst_ip => "192.168.3.40", - ttl => 64, - len => 64 - }; - $pkt = new NF2::IP_pkt(%$pkt_args); - send_and_count( 'eth4', $pkt->packed, \%delta ); - - return %delta; -} - -run_learning_switch_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/learning_switch/regress/test_unicast_unknown/run.pl b/openflow/regress/projects/learning_switch/regress/test_unicast_unknown/run.pl deleted file mode 100755 index 4378ae00..00000000 --- a/openflow/regress/projects/learning_switch/regress/test_unicast_unknown/run.pl +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/perl -w -#test_unicast_unknown - -use strict; -use OF::Includes; - -sub my_test { - - my $pkt_args = { - DA => "00:00:00:00:00:02", - SA => "00:00:00:00:00:01", - src_ip => "192.168.0.40", - dst_ip => "192.168.1.40", - ttl => 64, - len => 64 - }; - my $pkt = new NF2::IP_pkt(%$pkt_args); - - my %delta; - - # send one packet; controller should learn MAC, add a flow - # entry, and send this packet out the other interfaces - print "Sending now: \n"; - send_and_count( 'eth1', $pkt->packed, \%delta ); - expect_and_count( 'eth2', $pkt->packed, \%delta ); - expect_and_count( 'eth3', $pkt->packed, \%delta ); - expect_and_count( 'eth4', $pkt->packed, \%delta ); - - return %delta; -} - -run_learning_switch_test( \&my_test, \@ARGV ); diff --git a/openflow/regress/projects/learning_switch/regress/tests.txt b/openflow/regress/projects/learning_switch/regress/tests.txt deleted file mode 100644 index fdeb3c51..00000000 --- a/openflow/regress/projects/learning_switch/regress/tests.txt +++ /dev/null @@ -1,12 +0,0 @@ -test_unicast_unknown/run.pl -test_unicast_known/run.pl -test_broadcast/run.pl -##test_unicast_self/run.pl -test_unicast_move/run.pl -##test_hub_connected/run.pl -test_unicast_multiple_hosts/run.pl - -# BELOW NOT INCLUDED IN CURRRENT RELEASE -# WILL BE AVAILABLE SOON -##test_forward_latency/run.pl -##test_forward_bandwidth/run.pl diff --git a/openflow/regress/projects/regress.txt b/openflow/regress/projects/regress.txt deleted file mode 100644 index 9339cd32..00000000 --- a/openflow/regress/projects/regress.txt +++ /dev/null @@ -1,3 +0,0 @@ -black_box -controller_disconnect -learning_switch diff --git a/openflow/regress/scripts/copy_NF2_code.sh b/openflow/regress/scripts/copy_NF2_code.sh deleted file mode 100755 index 56ff83bf..00000000 --- a/openflow/regress/scripts/copy_NF2_code.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -#last use of this script copied in files from NF2 SVN rev 3904 -#note: OFT_ROOT and NF2_ROOT must be set -cp $NF2_ROOT/lib/Perl5/Test/* $OFT_ROOT/lib/Perl5/Test/ diff --git a/openflow/regress/scripts/env_vars b/openflow/regress/scripts/env_vars deleted file mode 100644 index a8f2433d..00000000 --- a/openflow/regress/scripts/env_vars +++ /dev/null @@ -1,12 +0,0 @@ -export OF_ROOT=/home/yourname/openflow -export OFT_ROOT=${OF_ROOT}/regress -export PATH=${OFT_ROOT}/bin:/sbin:/usr/sbin:${PATH} -export PERL5LIB=${OFT_ROOT}/lib/Perl5:${PERL5LIB} -export OFT_MAP_ETH=${OFT_ROOT}/bin/of_generic_eth.map -export OFT_HP_MAP_ETH=${OFT_ROOT}/bin/of_hp_eth.map -export OFT_HP_SWITCH_IP=10.10.10.2 -export OFT_HP_VLAN=10 -export OFT_HP_CONTROLLER="tcp:10.10.10.3:6633" -export OFT_HP_LISTENER="tcp:10.10.10.2:6633" -export OFT_OVS_ROOT=/home/yourname/openvswitch -export OFT_OVS_MAP_ETH=${OFT_ROOT}/bin/of_ovs_eth.map diff --git a/openflow/regress/scripts/install_deps.pl b/openflow/regress/scripts/install_deps.pl deleted file mode 100755 index 4668a58b..00000000 --- a/openflow/regress/scripts/install_deps.pl +++ /dev/null @@ -1,264 +0,0 @@ -#!/usr/bin/perl -W -# -# Script to automatically install dependencies for regression tests - -use strict; -use File::Basename; -use File::Path; -use Getopt::Std; -use Cwd; - -use constant { - UBUNTU => 'Ubuntu', - DEBIAN => 'Debian', - REDHAT => 'RedHat', - FEDORA => 'Fedora', - - UNKNOWN => 'unknown', - X86_64 => 'x86_64', -}; - -# Executables -my $lsb_release = 'lsb_release'; -my $apt_get = 'apt-get'; -my $yum = 'yum'; -my $uname = '/bin/uname'; - -my $distro; -my $machine; -my $sim; -my %install_funcs = ( - 'Ubuntu' => \&install_ubuntu_debian, - 'Debian' => \&install_ubuntu_debian, - 'Fedora' => \&install_fedora, -); -our($opt_s, $opt_d); - -# Verify that this script is being run as root -if ($> != 0) { - die "This script must be run as root"; -} - -# Parse the command line arguments -parse_args(); - - -# Identify the distribution and machine -if (!defined($distro)) { - identify_distro(); - die "Unable to identify the distribution" if (!defined($distro)); -} -identify_machine(); - -# Call the appropriate install function -if ($install_funcs{$distro}) { - $install_funcs{$distro}->(); -} -else { - die "Unable to find the install function for '$distro'"; -} - -exit 0; - -#========================================================== - -# -# identify_distro: -# Attempt to identify the Linux distro -# -sub identify_distro { - # First, look for lsb release which makes querying easier - $lsb_release = `which $lsb_release`; - chomp($lsb_release); - if ( $? >> 8 == 0) { - $distro = `$lsb_release -s -i`; - chomp($distro); - SWITCH: for ($distro) { - /Ubuntu/ && do { - $distro = UBUNTU; - last SWITCH; - }; - - /Debian/ && do { - $distro = DEBIAN; - last SWITCH; - }; - - (/CentOS/ || /RedHat/) && do { - $distro = REDHAT; - last SWITCH; - }; - - /Fedora/ && do { - $distro = FEDORA; - last SWITCH; - }; - - # DEFAULT - warn "Unknown Linux distro '$distro'"; - $distro = undef; - } - } - - # Otherwise, fall back to looking for release/version files in /etc - else { - if ( -f '/etc/debian_version' || -f '/etc/debian_release' ) { - $distro = DEBIAN; - } - elsif ( -f '/etc/fedora-release') { - $distro = FEDORA; - } - elsif ( -f '/etc/redhat-release' || -f '/etc/redhat_release' ) { - $distro = REDHAT; - } - } -} - -# -# identify_machine: -# Attempt to identify the machine type -# -sub identify_machine { - # First, look for lsb release which makes querying easier - if ( -x $uname) { - $machine = `$uname -m`; - chomp($machine); - } - - # we don't know what sort of machine this is - else { - $machine = UNKNOWN; - } -} - -# -# install_ubuntu_debian: -# Install the necessary dependencies for Ubuntu and Debian -# -sub install_ubuntu_debian { - my @pkgs = ( - 'liberror-perl', - 'libio-interface-perl', - 'liblist-moreutils-perl', - 'libpcap0.8-dev', - 'iproute', - 'psmisc', - 'libnet-pcap-perl', - 'libnet-rawip-perl', - 'wget', - ); - if ($machine eq X86_64) { - push (@pkgs, 'libc6-dev-i386', 'ia32-libs'); - } - - my @modules = ( - 'http://search.cpan.org/CPAN/authors/id/F/FT/FTASSIN/Data-HexDump-0.02.tar.gz', - 'http://www.cpan.org/authors/id/J/JV/JV/Getopt-Long-2.38.tar.gz', - ); - - if ($distro eq UBUNTU) { - push (@pkgs, 'libconvert-binary-c-perl') - } - else { - push (@modules, - 'http://search.cpan.org/CPAN/authors/id/M/MH/MHX/Convert-Binary-C-0.74.tar.gz') - } - - # Run apt-get - my @flags = ('-y'); - push(@flags, '-s') if defined($sim); - system($apt_get, @flags, 'install', @pkgs); - if ($? >> 8 != 0) { - die "Error running $apt_get"; - } - - # Install modules directly from CPAN - install_perl_modules(@modules); -} - -# -# install_fedora: -# Install the necessary dependencies for Fedora Core -# -sub install_fedora { - my @pkgs = ( - 'perl-Convert-Binary-C', - 'perl-Data-HexDump', - 'perl-Net-Pcap', - 'perl-Error.noarch', - 'perl-Module-Build', - 'libpcap-devel', - 'perl-List-MoreUtils', - 'perl-Net-RawIP', - ); - - # Run yum - my @flags = ('-y'); - if (defined($sim)) { - push(@flags, 'info'); - } - else { - push(@flags, 'install'); - } - system($yum, @flags, @pkgs); - if ($? >> 8 != 0) { - die "Error running $yum"; - } -} - -# -# install_perl_modules: -# Fetch and install PERL modules -# -sub install_perl_modules { - my @modules = @_; - - my $dir = "perl_modules"; - - mkdir $dir; - chdir $dir; - - foreach my $path (@modules) { - `wget $path`; - my $module = fileparse($path); - `tar xzf $module`; - $module =~ s/.tar.gz//; - print "compiling $module\n"; - chdir $module; - if (!defined($sim)) { - system 'perl Makefile.PL'; - system 'make'; - system 'make install'; - } - chdir '../'; - } - - chdir '..'; - rmtree $dir; -} - -# -# parse_args -# Parse the command line arguments -# -sub parse_args { - getopts('sd:'); - $sim = 1 if defined($opt_s); - $distro = $opt_d if defined($opt_d); -} - -sub HELP_MESSAGE { - print < 0) { $release_num = $ARGV[0]; } - -check_OF_vars_set(); - -my $rootdir = $ENV{'OFT_ROOT'}; -print "starting at root dir $rootdir\n"; -chdir $rootdir; - -my @ignore_list = ( - './temp', - './scripts/copy_NF2_code.sh', - './scripts/make_release.pl', - './projects/learning_switch/regress/test_forward_bandwidth/run.pl', - './projects/learning_switch/regress/test_forward_bandwidth/run.pl', - './projects/black_box/regress/test_send_bandwidth_fixed/run.pl', - './projects/black_box/regress/test_send_bandwidth_random/run.pl', - './projects/black_box/regress/test_add_flow_bandwidth/run.pl', - './projects/black_box/regress/test_add_flow_latency/run.pl', - './projects/black_box/regress/test_receive_bandwidth_fixed/run.pl', - './projects/black_box/regress/test_receive_bandwidth_random/run.pl', - './projects/black_box/regress/test_forward_bandwidth_fixed/run.pl', - './projects/black_box/regress/test_forward_bandwidth_random/run.pl', - './projects/black_box/regress/test_forward_latency/run.pl', - './projects/black_box/regress/test_switch_bandwidth_random/run.pl', - './projects/black_box/regress/test_switch_bandwidth_random/run.pl' -); - -my @files = parse_dir ('.'); - -print "\n"; - -foreach my $file (@files) { - print $file . "\n"; -} - -# set x permission for non-.pl files -# originally used perl chmod, but it doesn't work -my @write_perm_list = ( - "./temp/$of_ver/projects/learning_switch/regress/common/setup", - "./temp/$of_ver/projects/learning_switch/regress/common/teardown", - "./temp/$of_ver/projects/black_box/regress/common/setup", - "./temp/$of_ver/projects/black_box/regress/common/teardown" -); -foreach my $file (@write_perm_list) { - `chmod 755 $file`; -} - -#print $write_perm_list[0] . "\n"; - -`cd $rootdir/temp; tar czf $of_ver.tar.gz *`; -exit (0); - -# DFS -sub parse_dir { - my ($path) = @_; - #print "parse_dir called with $path\n"; - my @file_list; - # exists? - if (! -e "$path") { - die "checked $path and failed\n"; - } - # file? - elsif (-f "$path") { - if (file_ok($path)) { - print "added $path to list\n"; - push @file_list, "$path"; - - copy($path, "temp/$of_ver/$path") || die "failed to copy $path\n"; - - #for perl files, make them executable - my $match = $path =~ m/.pl/; - print " match = $match\n"; - if ($match) { - # ensure file is executable - print " setting chmod for $path\n"; - chmod 755, "temp/$of_ver/$path" || die "failed to set chmod $path\n"; - }; - } - else { - #print "ignore file $path\n"; - } - } - # directory? - elsif (-d $path) { - #print "parsing directory $path\n"; - opendir(DIR, $path) || print "Can't open... maybe try chmod 777"; - my @files_in_dir=readdir(DIR); - closedir(DIR); - - if (dir_ok('', $path) && $path ne '.') { - #remove ./ at beginning - - my $path_temp = substr($path, 2); - mkdir("temp/$of_ver/$path_temp") || die "failed to make path temp/$of_ver/$path_temp\n"; - } - - #print " dir looks like: \n"; - foreach my $file (@files_in_dir) { - #print " " . $file . "\n"; - } - - foreach my $subdir (@files_in_dir) { - if (dir_ok($subdir, $path) ) { - #print "\nabout to parse $path/$subdir\n"; - push @file_list, parse_dir("$path/$subdir"); - } - } - } - else { - die ("unknown error"); - } - - return @file_list; -} - -sub dir_ok { - my ($subdir, $path) = @_; - my $ignore = 0; - foreach my $file (@ignore_list) { - if ("$path/$subdir" eq $file) { $ignore = 1; last; } - } - - # ignore these three regardless of path - other require path to ignore - if ($subdir ne '.' && $subdir ne '..' && $subdir ne '.svn' && !$ignore ) { - return 1; - } - else { - return 0; - } -} - -sub file_ok { - my ($path) = @_; - my $ok = 1; - foreach my $file (@ignore_list) { - if ("$path" eq $file) { $ok = 0; last; } - } - return $ok; -} diff --git a/openflow/secchan/.dirstamp b/openflow/secchan/.dirstamp deleted file mode 100644 index e69de29b..00000000 diff --git a/openflow/secchan/.gitignore b/openflow/secchan/.gitignore deleted file mode 100644 index d6d189d3..00000000 --- a/openflow/secchan/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -/Makefile -/Makefile.in -/controller-lite -/ctlpath-lite -/dpctl-lite -/ofprotocol -/ofprotocol.8 diff --git a/openflow/secchan/automake.mk b/openflow/secchan/automake.mk deleted file mode 100644 index 6a9f2041..00000000 --- a/openflow/secchan/automake.mk +++ /dev/null @@ -1,32 +0,0 @@ -bin_PROGRAMS += secchan/ofprotocol -man_MANS += secchan/ofprotocol.8 - -secchan_ofprotocol_SOURCES = \ - secchan/discovery.c \ - secchan/discovery.h \ - secchan/emerg-flow.c \ - secchan/emerg-flow.h \ - secchan/fail-open.c \ - secchan/fail-open.h \ - secchan/failover.c \ - secchan/failover.h \ - secchan/in-band.c \ - secchan/in-band.h \ - secchan/port-watcher.c \ - secchan/port-watcher.h \ - secchan/protocol-stat.c \ - secchan/protocol-stat.h \ - secchan/ratelimit.c \ - secchan/ratelimit.h \ - secchan/secchan.c \ - secchan/secchan.h \ - secchan/status.c \ - secchan/status.h \ - secchan/stp-secchan.c \ - secchan/stp-secchan.h -secchan_ofprotocol_LDADD = lib/libopenflow.a $(FAULT_LIBS) $(SSL_LIBS) - -EXTRA_DIST += secchan/ofprotocol.8.in -DISTCLEANFILES += secchan/ofprotocol.8 - -include secchan/commands/automake.mk diff --git a/openflow/secchan/commands/automake.mk b/openflow/secchan/commands/automake.mk deleted file mode 100644 index cbe44d8c..00000000 --- a/openflow/secchan/commands/automake.mk +++ /dev/null @@ -1,3 +0,0 @@ -commandsdir = ${pkgdatadir}/commands -dist_commands_SCRIPTS = \ - secchan/commands/reboot diff --git a/openflow/secchan/commands/reboot b/openflow/secchan/commands/reboot deleted file mode 100755 index 4d5145cd..00000000 --- a/openflow/secchan/commands/reboot +++ /dev/null @@ -1,3 +0,0 @@ -#! /bin/sh -ofp-kill --force --signal=USR1 ofp-switchui.pid -reboot diff --git a/openflow/secchan/discovery.c b/openflow/secchan/discovery.c deleted file mode 100644 index feb9c338..00000000 --- a/openflow/secchan/discovery.c +++ /dev/null @@ -1,251 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include "discovery.h" -#include -#include -#include -#include "dhcp-client.h" -#include "dhcp.h" -#include "netdev.h" -#include "openflow/openflow.h" -#include "packets.h" -#include "port-watcher.h" -#include "secchan.h" -#include "status.h" - -#define THIS_MODULE VLM_discovery -#include "vlog.h" - -struct discovery -{ - const struct settings *s; - struct dhclient *dhcp; - int n_changes; -}; - -static void modify_dhcp_request(struct dhcp_msg *, void *aux); -static bool validate_dhcp_offer(const struct dhcp_msg *, void *aux); - -static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60); - -static void -discovery_status_cb(struct status_reply *sr, void *d_) -{ - struct discovery *d = d_; - - status_reply_put(sr, "accept-remote=%s", d->s->accept_controller_re); - status_reply_put(sr, "n-changes=%d", d->n_changes); - if (d->dhcp) { - status_reply_put(sr, "state=%s", dhclient_get_state(d->dhcp)); - status_reply_put(sr, "state-elapsed=%u", - dhclient_get_state_elapsed(d->dhcp)); - if (dhclient_is_bound(d->dhcp)) { - uint32_t ip = dhclient_get_ip(d->dhcp); - uint32_t netmask = dhclient_get_netmask(d->dhcp); - uint32_t router = dhclient_get_router(d->dhcp); - - const struct dhcp_msg *cfg = dhclient_get_config(d->dhcp); - uint32_t dns_server; - char *domain_name; - int i; - - status_reply_put(sr, "ip="IP_FMT, IP_ARGS(&ip)); - status_reply_put(sr, "netmask="IP_FMT, IP_ARGS(&netmask)); - if (router) { - status_reply_put(sr, "router="IP_FMT, IP_ARGS(&router)); - } - - for (i = 0; dhcp_msg_get_ip(cfg, DHCP_CODE_DNS_SERVER, i, - &dns_server); - i++) { - status_reply_put(sr, "dns%d="IP_FMT, i, IP_ARGS(&dns_server)); - } - - domain_name = dhcp_msg_get_string(cfg, DHCP_CODE_DOMAIN_NAME); - if (domain_name) { - status_reply_put(sr, "domain=%s", domain_name); - free(domain_name); - } - - status_reply_put(sr, "lease-remaining=%u", - dhclient_get_lease_remaining(d->dhcp)); - } - } -} - -static void -discovery_local_port_cb(const struct ofp_phy_port *port, void *d_) -{ - struct discovery *d = d_; - if (port) { - char name[OFP_MAX_PORT_NAME_LEN + 1]; - struct netdev *netdev; - int retval; - - /* Check that this was really a change. */ - get_port_name(port, name, sizeof name); - if (d->dhcp && !strcmp(netdev_get_name(dhclient_get_netdev(d->dhcp)), - name)) { - return; - } - - /* Destroy current DHCP client. */ - dhclient_destroy(d->dhcp); - d->dhcp = NULL; - - /* Bring local network device up. */ - retval = netdev_open(name, NETDEV_ETH_TYPE_NONE, &netdev); - if (retval) { - VLOG_ERR("Could not open %s device, discovery disabled: %s", - name, strerror(retval)); - return; - } - retval = netdev_turn_flags_on(netdev, NETDEV_UP, true); - if (retval) { - VLOG_ERR("Could not bring %s device up, discovery disabled: %s", - name, strerror(retval)); - return; - } - netdev_close(netdev); - - /* Initialize DHCP client. */ - retval = dhclient_create(name, modify_dhcp_request, - validate_dhcp_offer, (void *) d->s, &d->dhcp); - if (retval) { - VLOG_ERR("Failed to initialize DHCP client, " - "discovery disabled: %s", strerror(retval)); - return; - } - dhclient_set_max_timeout(d->dhcp, 3); - dhclient_init(d->dhcp, 0); - } else { - dhclient_destroy(d->dhcp); - d->dhcp = NULL; - } -} - - -struct discovery * -discovery_init(const struct settings *s, struct port_watcher *pw, - struct switch_status *ss) -{ - struct discovery *d; - - d = xmalloc(sizeof *d); - d->s = s; - d->dhcp = NULL; - d->n_changes = 0; - - switch_status_register_category(ss, "discovery", discovery_status_cb, d); - port_watcher_register_local_port_callback(pw, discovery_local_port_cb, d); - - return d; -} - -void -discovery_question_connectivity(struct discovery *d) -{ - if (d->dhcp) { - dhclient_force_renew(d->dhcp, 15); - } -} - -bool -discovery_run(struct discovery *d, char **controller_name) -{ - if (!d->dhcp) { - *controller_name = NULL; - return true; - } - - dhclient_run(d->dhcp); - if (!dhclient_changed(d->dhcp)) { - return false; - } - - dhclient_configure_netdev(d->dhcp); - if (d->s->update_resolv_conf) { - dhclient_update_resolv_conf(d->dhcp); - } - - if (dhclient_is_bound(d->dhcp)) { - *controller_name = dhcp_msg_get_string(dhclient_get_config(d->dhcp), - DHCP_CODE_OFP_CONTROLLER_VCONN); - VLOG_INFO("%s: discovered controller", *controller_name); - d->n_changes++; - } else { - *controller_name = NULL; - if (d->n_changes) { - VLOG_INFO("discovered controller no longer available"); - d->n_changes++; - } - } - return true; -} - -void -discovery_wait(struct discovery *d) -{ - if (d->dhcp) { - dhclient_wait(d->dhcp); - } -} - -static void -modify_dhcp_request(struct dhcp_msg *msg, void *aux UNUSED) -{ - dhcp_msg_put_string(msg, DHCP_CODE_VENDOR_CLASS, "OpenFlow"); -} - -static bool -validate_dhcp_offer(const struct dhcp_msg *msg, void *s_) -{ - const struct settings *s = s_; - char *vconn_name; - bool accept; - - vconn_name = dhcp_msg_get_string(msg, DHCP_CODE_OFP_CONTROLLER_VCONN); - if (!vconn_name) { - VLOG_WARN_RL(&rl, "rejecting DHCP offer missing controller vconn"); - return false; - } - accept = !regexec(&s->accept_controller_regex, vconn_name, 0, NULL, 0); - if (!accept) { - VLOG_WARN_RL(&rl, "rejecting controller vconn that fails to match %s", - s->accept_controller_re); - } - free(vconn_name); - return accept; -} diff --git a/openflow/secchan/discovery.h b/openflow/secchan/discovery.h deleted file mode 100644 index b2cb03c9..00000000 --- a/openflow/secchan/discovery.h +++ /dev/null @@ -1,50 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#ifndef DISCOVERY_H -#define DISCOVERY_H 1 - -#include - -struct settings; -struct port_watcher; -struct switch_status; - -struct discovery *discovery_init(const struct settings *, - struct port_watcher *, - struct switch_status *); -void discovery_question_connectivity(struct discovery *); -bool discovery_run(struct discovery *, char **controller_name); -void discovery_wait(struct discovery *); - -#endif /* discovery.h */ diff --git a/openflow/secchan/emerg-flow.c b/openflow/secchan/emerg-flow.c deleted file mode 100644 index 9af58819..00000000 --- a/openflow/secchan/emerg-flow.c +++ /dev/null @@ -1,144 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#include - -#include -#include -#include -#include -#include -#include - -#include "openflow/openflow.h" -#include "openflow/private-ext.h" - -#include "util.h" -#include "vconn.h" -#include "rconn.h" -#include "secchan.h" -#include "status.h" -#include "timeval.h" -#include "sat-math.h" -#include "ofpbuf.h" -#include "emerg-flow.h" -#define THIS_MODULE VLM_emerg_flow -#include "vlog.h" - -struct emerg_flow_context { - const struct settings *settings; - const struct secchan *secchan; - struct rconn *local_rconn; - struct rconn *remote_rconn; - int prev_state; - int state; -}; - -static void emerg_flow_status_cb(struct status_reply *, void *); -static void emerg_flow_periodic_cb(void *); - -static void -emerg_flow_status_cb(struct status_reply *status_reply, void *context_) -{ - struct emerg_flow_context *context = context_; - - status_reply_put(status_reply, "state=%s", - context->state == PRIVATEOPT_EMERG_FLOW_RESTORATION - ? "restoration" - : context->state == PRIVATEOPT_EMERG_FLOW_PROTECTION - ? "protection" : "unknown"); -} - -static void -emerg_flow_periodic_cb(void *context_) -{ - struct emerg_flow_context *context = context_; - struct ofpbuf *buf = NULL; - struct private_vxhdr *vxhdr = NULL; - struct private_vxopt *vxopt = NULL; - int error = 0; - - if (rconn_is_connected(context->remote_rconn)) { - if (context->state == PRIVATEOPT_EMERG_FLOW_PROTECTION) { - context->prev_state = context->state; - context->state = PRIVATEOPT_EMERG_FLOW_RESTORATION; - } else { - return; - } - } else { - if (context->state == PRIVATEOPT_EMERG_FLOW_RESTORATION) { - context->prev_state = context->state; - context->state = PRIVATEOPT_EMERG_FLOW_PROTECTION; - } else { - return; - } - } - - vxhdr = (struct private_vxhdr *)make_openflow - (sizeof(*vxhdr) + sizeof(*vxopt), OFPT_VENDOR, &buf); - vxopt = (struct private_vxopt *)(vxhdr + 1); - vxhdr->ofp_vxid = htonl(PRIVATE_VENDOR_ID); - vxopt->pvo_type = htons(context->state); - vxopt->pvo_len = htons(0); - - error = rconn_send(context->local_rconn, buf, NULL); - if (error && error != EAGAIN) { - VLOG_WARN("send failed (%s)", strerror(error)); - } -} - -void -emerg_flow_start(struct secchan *secchan, const struct settings *settings, - struct switch_status *switch_status, - struct rconn *local_rconn, struct rconn *remote_rconn) -{ - struct emerg_flow_context *context = NULL; - static struct hook_class emerg_flow_hook_class = { - NULL, /* local_packet_cb */ - NULL, /* remote_packet_cb */ - emerg_flow_periodic_cb, /* periodic_cb */ - NULL, /* wait_cb */ - NULL, /* closing_cb */ - }; - - context = xmalloc(sizeof(*context)); - context->settings = settings; - context->secchan = secchan; - context->local_rconn = local_rconn; - context->remote_rconn = remote_rconn; - context->prev_state = PRIVATEOPT_EMERG_FLOW_PROTECTION; - context->state = PRIVATEOPT_EMERG_FLOW_PROTECTION; - - switch_status_register_category(switch_status, "emerg-flow", - emerg_flow_status_cb, context); - add_hook(secchan, &emerg_flow_hook_class, context); -} diff --git a/openflow/secchan/emerg-flow.h b/openflow/secchan/emerg-flow.h deleted file mode 100644 index d61a7fe2..00000000 --- a/openflow/secchan/emerg-flow.h +++ /dev/null @@ -1,44 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#ifndef EMERG_FLOW_H_ -#define EMERG_FLOW_H_ 1 - -struct rconn; -struct secchan; -struct settings; -struct switch_status; - -void emerg_flow_start(struct secchan *, const struct settings *, - struct switch_status *, struct rconn *, struct rconn *); - -#endif diff --git a/openflow/secchan/fail-open.c b/openflow/secchan/fail-open.c deleted file mode 100644 index eb28bc38..00000000 --- a/openflow/secchan/fail-open.c +++ /dev/null @@ -1,159 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include "fail-open.h" -#include -#include -#include -#include "learning-switch.h" -#include "netdev.h" -#include "packets.h" -#include "port-watcher.h" -#include "rconn.h" -#include "secchan.h" -#include "status.h" -#include "stp-secchan.h" -#include "timeval.h" - -#define THIS_MODULE VLM_fail_open -#include "vlog.h" - -struct fail_open_data { - const struct settings *s; - struct rconn *local_rconn; - struct rconn *remote_rconn; - struct lswitch *lswitch; - int last_disconn_secs; - time_t boot_deadline; -}; - -/* Causes 'r' to enter or leave fail-open mode, if appropriate. */ -static void -fail_open_periodic_cb(void *fail_open_) -{ - struct fail_open_data *fail_open = fail_open_; - int disconn_secs; - bool open; - - if (time_now() < fail_open->boot_deadline) { - return; - } - disconn_secs = rconn_failure_duration(fail_open->remote_rconn); - open = disconn_secs >= fail_open->s->probe_interval * 3; - if (open != (fail_open->lswitch != NULL)) { - if (!open) { - VLOG_WARN("No longer in fail-open mode"); - lswitch_destroy(fail_open->lswitch); - fail_open->lswitch = NULL; - } else { - VLOG_WARN("Could not connect to controller for %d seconds, " - "failing open", disconn_secs); - fail_open->lswitch = lswitch_create(fail_open->local_rconn, true, - fail_open->s->max_idle); - fail_open->last_disconn_secs = disconn_secs; - } - } else if (open && disconn_secs > fail_open->last_disconn_secs + 60) { - VLOG_INFO("Still in fail-open mode after %d seconds disconnected " - "from controller", disconn_secs); - fail_open->last_disconn_secs = disconn_secs; - } - if (fail_open->lswitch) { - lswitch_run(fail_open->lswitch, fail_open->local_rconn); - } -} - -static void -fail_open_wait_cb(void *fail_open_) -{ - struct fail_open_data *fail_open = fail_open_; - if (fail_open->lswitch) { - lswitch_wait(fail_open->lswitch); - } -} - -static bool -fail_open_local_packet_cb(struct relay *r, void *fail_open_) -{ - struct fail_open_data *fail_open = fail_open_; - if (rconn_is_connected(fail_open->remote_rconn) || !fail_open->lswitch) { - return false; - } else { - lswitch_process_packet(fail_open->lswitch, fail_open->local_rconn, - r->halves[HALF_LOCAL].rxbuf); - rconn_run(fail_open->local_rconn); - return true; - } -} - -static void -fail_open_status_cb(struct status_reply *sr, void *fail_open_) -{ - struct fail_open_data *fail_open = fail_open_; - const struct settings *s = fail_open->s; - int trigger_duration = s->probe_interval * 3; - int cur_duration = rconn_failure_duration(fail_open->remote_rconn); - - status_reply_put(sr, "trigger-duration=%d", trigger_duration); - status_reply_put(sr, "current-duration=%d", cur_duration); - status_reply_put(sr, "triggered=%s", - cur_duration >= trigger_duration ? "true" : "false"); - status_reply_put(sr, "max-idle=%d", s->max_idle); -} - -static struct hook_class fail_open_hook_class = { - fail_open_local_packet_cb, /* local_packet_cb */ - NULL, /* remote_packet_cb */ - fail_open_periodic_cb, /* periodic_cb */ - fail_open_wait_cb, /* wait_cb */ - NULL, /* closing_cb */ -}; - -void -fail_open_start(struct secchan *secchan, const struct settings *s, - struct switch_status *ss, - struct rconn *local_rconn, struct rconn *remote_rconn) -{ - struct fail_open_data *fail_open = xmalloc(sizeof *fail_open); - fail_open->s = s; - fail_open->local_rconn = local_rconn; - fail_open->remote_rconn = remote_rconn; - fail_open->lswitch = NULL; - fail_open->boot_deadline = time_now() + s->probe_interval * 3; - if (s->enable_stp) { - fail_open->boot_deadline += STP_EXTRA_BOOT_TIME; - } - switch_status_register_category(ss, "fail-open", - fail_open_status_cb, fail_open); - add_hook(secchan, &fail_open_hook_class, fail_open); -} diff --git a/openflow/secchan/fail-open.h b/openflow/secchan/fail-open.h deleted file mode 100644 index 69a3b310..00000000 --- a/openflow/secchan/fail-open.h +++ /dev/null @@ -1,46 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#ifndef FAIL_OPEN_H -#define FAIL_OPEN_H 1 - -struct rconn; -struct secchan; -struct settings; -struct switch_status; - -void fail_open_start(struct secchan *, const struct settings *, - struct switch_status *, - struct rconn *local, struct rconn *remote); - -#endif /* fail-open.h */ diff --git a/openflow/secchan/failover.c b/openflow/secchan/failover.c deleted file mode 100644 index 718d7379..00000000 --- a/openflow/secchan/failover.c +++ /dev/null @@ -1,144 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#include -#include -#include -#include - -#include "util.h" -#include "rconn.h" -#include "secchan.h" -#include "status.h" -#include "timeval.h" -#include "sat-math.h" -#include "failover.h" -#define THIS_MODULE VLM_failover -#include "vlog.h" - -struct failover_peer { - time_t epoch; -}; - -struct failover_context { - const struct settings *settings; - const struct secchan *secchan; - struct rconn *remote_rconn; - int index; - struct failover_peer *peers[MAX_CONTROLLERS]; -}; - -static void failover_status_cb(struct status_reply *, void *); -static bool is_timed_out(const struct failover_peer *, int); -static void failover_periodic_cb(void *); - -static void -failover_status_cb(struct status_reply *status_reply, void *context_) -{ - struct failover_context *context = context_; - int i; - - status_reply_put(status_reply, "num-controllers=%d", - context->settings->num_controllers); - - for (i = 0; i < MAX_CONTROLLERS; ++i) { - if (context->settings->controller_names[i] == NULL) - continue; - status_reply_put(status_reply, "controller#%d=%s", - i, context->settings->controller_names[i]); - } -} - -static bool -is_timed_out(const struct failover_peer *peer, int max_backoff) -{ - unsigned int sat_value = sat_add(peer->epoch, max_backoff); - return time_now() >= sat_value; -} - -static void -failover_periodic_cb(void *context_) -{ - struct failover_context *context = context_; - char *curr_peer = NULL; - char *prev_peer = NULL; - - if (rconn_is_connected(context->remote_rconn)) - return; - - if (!is_timed_out(context->peers[context->index], - context->settings->max_backoff)) { - return; - } - - rconn_disconnect(context->remote_rconn); - prev_peer = (char *)context->settings->controller_names[context->index]; - context->index = (context->index + 1) - % context->settings->num_controllers; - curr_peer = (char *)context->settings->controller_names[context->index]; - rconn_connect(context->remote_rconn, - context->settings->controller_names[context->index]); - context->peers[context->index]->epoch = time_now(); - VLOG_INFO("Switching over to %s, from %s", curr_peer, prev_peer); -} - -void -failover_start(struct secchan *secchan, const struct settings *settings, - struct switch_status *switch_status, struct rconn *remote_rconn) -{ - struct failover_context *context = NULL; - int i; - static struct hook_class failover_hook_class = { - NULL, /* local_packet_cb */ - NULL, /* remote_packet_cb */ - failover_periodic_cb, /* periodic_cb */ - NULL, /* wait_cb */ - NULL, /* closing_cb */ - }; - - context = xmalloc(sizeof(*context)); - context->settings = settings; - context->secchan = secchan; - context->remote_rconn = remote_rconn; - context->index = 0; - for (i = 0; i < MAX_CONTROLLERS; ++i) { - context->peers[i] = NULL; - if (settings->controller_names[i] == NULL) - continue; - context->peers[i] = xmalloc(sizeof(struct failover_peer)); - context->peers[i]->epoch = time_now(); - } - - switch_status_register_category(switch_status, "failover", - failover_status_cb, context); - add_hook(secchan, &failover_hook_class, context); -} diff --git a/openflow/secchan/failover.h b/openflow/secchan/failover.h deleted file mode 100644 index d511b35f..00000000 --- a/openflow/secchan/failover.h +++ /dev/null @@ -1,44 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#ifndef FAILOVER_H_ -#define FAILOVER_H_ 1 - -struct rconn; -struct secchan; -struct settings; -struct switch_status; - -void failover_start(struct secchan *, const struct settings *, - struct switch_status *, struct rconn *); - -#endif diff --git a/openflow/secchan/in-band.c b/openflow/secchan/in-band.c deleted file mode 100644 index 46109daf..00000000 --- a/openflow/secchan/in-band.c +++ /dev/null @@ -1,331 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include "in-band.h" -#include -#include -#include -#include -#include "flow.h" -#include "mac-learning.h" -#include "netdev.h" -#include "ofpbuf.h" -#include "openflow/openflow.h" -#include "packets.h" -#include "port-watcher.h" -#include "rconn.h" -#include "secchan.h" -#include "status.h" -#include "timeval.h" -#include "vconn.h" - -#define THIS_MODULE VLM_in_band -#include "vlog.h" - -struct in_band_data { - const struct settings *s; - struct mac_learning *ml; - struct netdev *of_device; - struct rconn *controller; - int n_queued; -}; - -static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60); - -static void -queue_tx(struct rconn *rc, struct in_band_data *in_band, struct ofpbuf *b) -{ - rconn_send_with_limit(rc, b, &in_band->n_queued, 10); -} - -static const uint8_t * -get_controller_mac(struct in_band_data *in_band) -{ - static uint32_t ip, last_nonzero_ip; - static uint8_t mac[ETH_ADDR_LEN], last_nonzero_mac[ETH_ADDR_LEN]; - static time_t next_refresh = 0; - - uint32_t last_ip = ip; - - time_t now = time_now(); - - ip = rconn_get_ip(in_band->controller); - if (last_ip != ip || !next_refresh || now >= next_refresh) { - bool have_mac; - - /* Look up MAC address. */ - memset(mac, 0, sizeof mac); - if (ip && in_band->of_device) { - int retval = netdev_arp_lookup(in_band->of_device, ip, mac); - if (retval) { - VLOG_DBG_RL(&rl, "cannot look up controller hw address " - "("IP_FMT"): %s", IP_ARGS(&ip), strerror(retval)); - } - } - have_mac = !eth_addr_is_zero(mac); - - /* Log changes in IP, MAC addresses. */ - if (ip && ip != last_nonzero_ip) { - VLOG_DBG("controller IP address changed from "IP_FMT - " to "IP_FMT, IP_ARGS(&last_nonzero_ip), IP_ARGS(&ip)); - last_nonzero_ip = ip; - } - if (have_mac && memcmp(last_nonzero_mac, mac, ETH_ADDR_LEN)) { - VLOG_DBG("controller MAC address changed from "ETH_ADDR_FMT" to " - ETH_ADDR_FMT, - ETH_ADDR_ARGS(last_nonzero_mac), ETH_ADDR_ARGS(mac)); - memcpy(last_nonzero_mac, mac, ETH_ADDR_LEN); - } - - /* Schedule next refresh. - * - * If we have an IP address but not a MAC address, then refresh - * quickly, since we probably will get a MAC address soon (via ARP). - * Otherwise, we can afford to wait a little while. */ - next_refresh = now + (!ip || have_mac ? 10 : 1); - } - return !eth_addr_is_zero(mac) ? mac : NULL; -} - -static bool -is_controller_mac(const uint8_t dl_addr[ETH_ADDR_LEN], - struct in_band_data *in_band) -{ - const uint8_t *mac = get_controller_mac(in_band); - return mac && eth_addr_equals(mac, dl_addr); -} - -static void -in_band_learn_mac(struct in_band_data *in_band, - uint16_t in_port, const uint8_t src_mac[ETH_ADDR_LEN]) -{ - if (mac_learning_learn(in_band->ml, src_mac, 0, in_port)) { - VLOG_DBG_RL(&rl, "learned that "ETH_ADDR_FMT" is on port %"PRIu16, - ETH_ADDR_ARGS(src_mac), in_port); - } -} - -static bool -in_band_local_packet_cb(struct relay *r, void *in_band_) -{ - struct in_band_data *in_band = in_band_; - struct rconn *rc = r->halves[HALF_LOCAL].rconn; - struct ofp_packet_in *opi; - struct eth_header *eth; - struct ofpbuf payload; - struct flow flow; - uint16_t in_port; - int out_port; - - if (!get_ofp_packet_eth_header(r, &opi, ð) || !in_band->of_device) { - return false; - } - in_port = ntohs(opi->in_port); - get_ofp_packet_payload(opi, &payload); - flow_extract(&payload, in_port, &flow); - - /* Deal with local stuff. */ - if (in_port == OFPP_LOCAL) { - /* Sent by secure channel. */ - out_port = mac_learning_lookup(in_band->ml, eth->eth_dst, 0); - } else if (eth_addr_equals(eth->eth_dst, - netdev_get_etheraddr(in_band->of_device))) { - /* Sent to secure channel. */ - out_port = OFPP_LOCAL; - in_band_learn_mac(in_band, in_port, eth->eth_src); - } else if (eth->eth_type == htons(ETH_TYPE_ARP) - && eth_addr_is_broadcast(eth->eth_dst) - && is_controller_mac(eth->eth_src, in_band)) { - /* ARP sent by controller. */ - out_port = OFPP_FLOOD; - } else if ((is_controller_mac(eth->eth_dst, in_band) - || is_controller_mac(eth->eth_src, in_band)) - && flow.dl_type == htons(ETH_TYPE_IP) - && flow.nw_proto == IP_TYPE_TCP - && (flow.tp_src == htons(OFP_TCP_PORT) - || flow.tp_src == htons(OFP_SSL_PORT) - || flow.tp_dst == htons(OFP_TCP_PORT) - || flow.tp_dst == htons(OFP_SSL_PORT))) { - /* Traffic to or from controller. Switch it by hand. */ - in_band_learn_mac(in_band, in_port, eth->eth_src); - out_port = mac_learning_lookup(in_band->ml, eth->eth_dst, 0); - } else { - const uint8_t *controller_mac; - controller_mac = get_controller_mac(in_band); - if (eth->eth_type == htons(ETH_TYPE_ARP) - && eth_addr_is_broadcast(eth->eth_dst) - && is_controller_mac(eth->eth_src, in_band)) { - /* ARP sent by controller. */ - out_port = OFPP_FLOOD; - } else if (is_controller_mac(eth->eth_dst, in_band) - && in_port == mac_learning_lookup(in_band->ml, - controller_mac, 0)) { - /* Drop controller traffic that arrives on the controller port. */ - out_port = -1; - } else { - return false; - } - } - - if (in_port == out_port) { - /* The input and output port match. Set up a flow to drop packets. */ - queue_tx(rc, in_band, make_add_flow(&flow, ntohl(opi->buffer_id), - in_band->s->max_idle, 0)); - } else if (out_port != OFPP_FLOOD) { - /* The output port is known, so add a new flow. */ - queue_tx(rc, in_band, - make_add_simple_flow(&flow, ntohl(opi->buffer_id), - out_port, in_band->s->max_idle)); - - /* If the switch didn't buffer the packet, we need to send a copy. */ - if (ntohl(opi->buffer_id) == UINT32_MAX) { - queue_tx(rc, in_band, - make_unbuffered_packet_out(&payload, in_port, out_port)); - } - } else { - /* We don't know that MAC. Send along the packet without setting up a - * flow. */ - struct ofpbuf *b; - if (ntohl(opi->buffer_id) == UINT32_MAX) { - b = make_unbuffered_packet_out(&payload, in_port, out_port); - } else { - b = make_buffered_packet_out(ntohl(opi->buffer_id), - in_port, out_port); - } - queue_tx(rc, in_band, b); - } - return true; -} - -static void -in_band_status_cb(struct status_reply *sr, void *in_band_) -{ - struct in_band_data *in_band = in_band_; - struct in_addr local_ip; - uint32_t controller_ip; - const uint8_t *controller_mac; - - if (in_band->of_device) { - const uint8_t *mac = netdev_get_etheraddr(in_band->of_device); - if (netdev_get_in4(in_band->of_device, &local_ip)) { - status_reply_put(sr, "local-ip="IP_FMT, IP_ARGS(&local_ip.s_addr)); - } - status_reply_put(sr, "local-mac="ETH_ADDR_FMT, ETH_ADDR_ARGS(mac)); - - controller_ip = rconn_get_ip(in_band->controller); - if (controller_ip) { - status_reply_put(sr, "controller-ip="IP_FMT, - IP_ARGS(&controller_ip)); - } - controller_mac = get_controller_mac(in_band); - if (controller_mac) { - status_reply_put(sr, "controller-mac="ETH_ADDR_FMT, - ETH_ADDR_ARGS(controller_mac)); - } - } -} - -void -get_ofp_packet_payload(struct ofp_packet_in *opi, struct ofpbuf *payload) -{ - payload->data = opi->data; - payload->size = ntohs(opi->header.length) - offsetof(struct ofp_packet_in, - data); -} - -static void -in_band_local_port_cb(const struct ofp_phy_port *port, void *in_band_) -{ - struct in_band_data *in_band = in_band_; - if (port) { - char name[sizeof port->name + 1]; - get_port_name(port, name, sizeof name); - - if (!in_band->of_device - || strcmp(netdev_get_name(in_band->of_device), name)) - { - int error; - netdev_close(in_band->of_device); - error = netdev_open(name, NETDEV_ETH_TYPE_NONE, - &in_band->of_device); - if (error) { - VLOG_ERR("failed to open in-band control network device " - "\"%s\": %s", name, strerror(errno)); - } - } - } else { - netdev_close(in_band->of_device); - in_band->of_device = NULL; - } -} - -static void -in_band_periodic_cb(void *in_band_) -{ - struct in_band_data *in_band = in_band_; - mac_learning_run(in_band->ml, NULL); -} - -static void -in_band_wait_cb(void *in_band_) -{ - struct in_band_data *in_band = in_band_; - mac_learning_wait(in_band->ml); -} - -static struct hook_class in_band_hook_class = { - in_band_local_packet_cb, /* local_packet_cb */ - NULL, /* remote_packet_cb */ - in_band_periodic_cb, /* periodic_cb */ - in_band_wait_cb, /* wait_cb */ - NULL, /* closing_cb */ -}; - -void -in_band_start(struct secchan *secchan, - const struct settings *s, struct switch_status *ss, - struct port_watcher *pw, struct rconn *remote) -{ - struct in_band_data *in_band; - - in_band = xcalloc(1, sizeof *in_band); - in_band->s = s; - in_band->ml = mac_learning_create(); - in_band->of_device = NULL; - in_band->controller = remote; - switch_status_register_category(ss, "in-band", in_band_status_cb, in_band); - port_watcher_register_local_port_callback(pw, in_band_local_port_cb, - in_band); - add_hook(secchan, &in_band_hook_class, in_band); -} diff --git a/openflow/secchan/in-band.h b/openflow/secchan/in-band.h deleted file mode 100644 index b4d21ab9..00000000 --- a/openflow/secchan/in-band.h +++ /dev/null @@ -1,47 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#ifndef IN_BAND_H -#define IN_BAND_H 1 - -struct port_watcher; -struct rconn; -struct secchan; -struct settings; -struct switch_status; - -void in_band_start(struct secchan *, const struct settings *, - struct switch_status *, struct port_watcher *, - struct rconn *remote); - -#endif /* in-band.h */ diff --git a/openflow/secchan/ofprotocol.8.in b/openflow/secchan/ofprotocol.8.in deleted file mode 100644 index 4aae44a3..00000000 --- a/openflow/secchan/ofprotocol.8.in +++ /dev/null @@ -1,462 +0,0 @@ -.ds PN ofprotocol -.TH ofprotocol 8 "October 2008" "OpenFlow" "OpenFlow Manual" - -.SH NAME -ofprotocol \- secure channel connecting an OpenFlow datapath to a controller - -.SH SYNOPSIS -.B ofprotocol -[\fIoptions\fR] \fIdatapath\fR controller[,\fIcontroller\fR...] - -.SH DESCRIPTION -The \fBofprotocol\fR program sets up a secure channel between a local -OpenFlow datapath and a remote controller. \fBofprotocol\fR connects to -the local datapath over Netlink and to the controller over TCP or SSL, -and then forwards OpenFlow messages from one endpoint to the other. - -The mandatory \fIdatapath\fR argument argument specifies the local datapath -to relay. It takes one of the following forms: - -.TP -\fBnl:\fIdp_idx\fR -Attach to the local kernel-based datapath over the Netlink protocol. -The \fIdp_idx\fR argument is the number of a datapath created with -\fBdpctl\fR(8). - -.TP -\fBunix:\fIfile\fR -Attach to the userspace datapath implemented by \fBofdatapath\fR(8). -The \fIfile\fR argument must the same one specified on the -\fBofdatapath\fR command line. - -.PP -The optional \fIcontroller\fR argument specifies how to connect to -an OpenFlow controller. Up to four controllers may be specified, -using the following forms: - -.TP -\fBssl:\fIhost\fR[\fB:\fIport\fR] -The specified SSL \fIport\fR (default: 6633) on the given remote -\fIhost\fR. The \fB--private-key\fR, \fB--certificate\fR, and -\fB--ca-cert\fR options are mandatory when this form is used. - -.TP -\fBtcp:\fIhost\fR[\fB:\fIport\fR] -The specified TCP \fIport\fR (default: 6633) on the given remote -\fIhost\fR. - -.TP -\fBunix:\fIfile\fR -The Unix domain server socket named \fIfile\fR. - -.PP -If multiple controllers are specified, \fBofprotocol\fR will attempt to -connect to a new controller when a controller connection fails, times -out, or is closed, or when a controller stops responding to echo requests. - -If \fIcontroller\fR is omitted, \fBofprotocol\fR attempts to discover the -location of the controller automatically (see below). - -.SH "CONTACTING THE CONTROLLER" -The OpenFlow switch must be able to contact the OpenFlow controller -over the network. It can do so in one of two ways: - -.IP out-of-band -In this configuration, OpenFlow traffic uses a network separate from -the data traffic that it controls, that is, the switch does not use -any of the network devices added to the datapath with \fBdpctl -addif\fR in its communication with the controller. - -To use \fBofprotocol\fR in a network with out-of-band control, specify -\fB--out-of-band\fR on the \fBofprotocol\fR command line. The control -network must be configured separately, before or after \fBofprotocol\fR -is started. - -.IP in-band -In this configuration, a single network is used for OpenFlow traffic -and other data traffic, that is, the switch contacts the controller -over one of the network devices added to the datapath with \fBdpctl -addif\fR. This configuration is often more convenient than -out-of-band control, because it is not necessary to maintain two -independent networks. - -In-band control is the default for \fBofprotocol\fR, so no special -command-line option is required. - -With in-band control, the location of the controller can be configured -manually or discovered automatically: - -.RS -.IP "controller discovery" -To make \fBofprotocol\fR discover the location of the controller -automatically, do not specify the location of the controller on the -\fBofprotocol\fR command line. - -In this mode, \fBofprotocol\fR will broadcast a DHCP request with vendor -class identifier \fBOpenFlow\fR across the network devices added to -the datapath with \fBdpctl addif\fR. It will accept any valid DHCP -reply that has the same vendor class identifier and includes a -vendor-specific option with code 1 whose contents are a string -specifying the location of the controller in the same format used on -the \fBofprotocol\fR command line (e.g. \fBssl:192.168.0.1\fR). - -The DHCP reply may also, optionally, include a vendor-specific option -with code 2 whose contents are a string specifying the URI to the base -of the OpenFlow PKI (e.g. \fBhttp://192.168.0.1/openflow/pki\fR). -This URI is used only for bootstrapping the OpenFlow PKI at initial -switch setup; \fBofprotocol\fR does not use it at all. - -The following ISC DHCP server configuration file assigns the IP -address range 192.168.0.20 through 192.168.0.30 to OpenFlow switches -that follow the switch protocol and addresses 192.168.0.1 through -192.168.0.10 to all other DHCP clients: - -default-lease-time 600; -.br -max-lease-time 7200; -.br -option space openflow; -.br -option openflow.controller-vconn code 1 = text; -.br -option openflow.pki-uri code 2 = text; -.br -class "OpenFlow" { -.br - match if option vendor-class-identifier = "OpenFlow"; -.br - vendor-option-space openflow; -.br - option openflow.controller-vconn "tcp:192.168.0.10"; -.br - option openflow.pki-uri "http://192.168.0.10/openflow/pki"; -.br - option vendor-class-identifier "OpenFlow"; -.br -} -.br -subnet 192.168.0.0 netmask 255.255.255.0 { -.br - pool { -.br - allow members of "OpenFlow"; -.br - range 192.168.0.20 192.168.0.30; -.br - } -.br - pool { -.br - deny members of "OpenFlow"; -.br - range 192.168.0.1 192.168.0.10; -.br - } -.br -} -.br - -.IP "manual configuration" -To configure in-band control manually, specify the location of the -controller on the \fBofprotocol\fR command line as the \fIcontroller\fR -argument. You must also configure the network device for the OpenFlow -``local port'' to allow \fBofprotocol\fR to connect to that controller. -The OpenFlow local port is a virtual network port that \fBofprotocol\fR -bridges to the physical switch ports. Its network device name depends -on the \fIdatapath\fR specified on the \fBofprotocol\fR command line: - -.RS -.TP -\fBnl:\fIdp_idx\fR -The local port network device for \fBnl:\fIdp_idx\fR is always named -\fBof\fIdp_idx\fR, i.e. the device for \fBnl:0\fR is \fBof0\fR. - -.TP -\fBunix:\fIfile\fR -The local port network device name may be specified on the -\fBofdatapath\fR command line, using the \fB--local-port\fR option. It -is often \fBtap0\fR. -.RE - -.IP -Before \fBofprotocol\fR starts, the local port network device is not -bridged to any physical network, so the next step depends on whether -connectivity is required to configure the device's IP address. If the -switch has a static IP address, you may configure its IP address now -with a command such as: -.RS -.IP -ifconfig of0 192.168.1.1 -.RE -.IP -and then invoke \fBofprotocol\fR. - -On the other hand, if the switch does not have a static IP address, -e.g. it obtains its IP address dynamically via DHCP, the DHCP client -will not be able to contact the DHCP server until the secure channel -has started up. Thus, start \fBofprotocol\fR without configuring -the local port network device, and start the DHCP client afterward. -.RE - -.SH OPTIONS -.SS "Controller Discovery Options" -.TP -\fB--accept-vconn=\fIregex\fR -When \fBofprotocol\fR performs controller discovery (see \fBCONTACTING -THE CONTROLLER\fR, above, for more information about controller -discovery), it validates the controller location obtained via DHCP -with a POSIX extended regular expression. Only controllers whose -names match the regular expression will be accepted. - -The default regular expression is \fBssl:.*\fR (meaning that only SSL -controller connections will be accepted) when any of the SSL -configuration options \fB--private-key\fR, \fB--certificate\fR, or -\fB--ca-cert\fR is specified. The default is \fB.*\fR otherwise -(meaning that any controller will be accepted). - -The \fIregex\fR is implicitly anchored at the beginning of the -controller location string, as if it begins with \fB^\fR. - -When controller discovery is not performed, this option has no effect. - -.TP -\fB--no-resolv-conf\fR -When \fBofprotocol\fR performs controller discovery (see \fBCONTACTING -THE CONTROLLER\fR, above, for more information about controller -discovery), by default it overwrites the system's -\fB/etc/resolv.conf\fR with domain information and DNS servers -obtained via DHCP. If the location of the controller is specified -using a hostname, rather than an IP address, and the network's DNS -servers ever change, this behavior is essential. But because it also -interferes with any administrator or process that manages -\fB/etc/resolv.conf\fR, when this option is specified, \fBofprotocol\fR -will not modify \fB/etc/resolv.conf\fR. - -\fBofprotocol\fR will only modify \fBresolv.conf\fR if the DHCP response -that it receives specifies one or more DNS servers. - -When controller discovery is not performed, this option has no effect. - -.SS "Networking Options" -.TP -\fB-F\fR, \fB--fail=\fR[\fBopen\fR|\fBclosed\fR] -The controller is, ordinarily, responsible for setting up all flows on -the OpenFlow switch. Thus, if the connection to the controller fails, -no new network connections can be set up. If the connection to the -controller stays down long enough, no packets can pass through the -switch at all. - -If this option is set to \fBopen\fR (the default), \fBofprotocol\fR will -take over responsibility for setting up flows in the local datapath -when no message has been received from the controller for three times -the inactivity probe interval (see below), or 45 seconds by default. -In this ``fail open'' mode, \fBofprotocol\fR causes the datapath to act -like an ordinary MAC-learning switch. \fBofprotocol\fR will continue to -retry connection to the controller in the background and, when the -connection succeeds, it discontinues its fail-open behavior. The -secure channel enters the fail-open mode when - -If this option is set to \fBclosed\fR, then \fBofprotocol\fR will not -set up flows on its own when the controller connection fails. - -.TP -\fB--inactivity-probe=\fIsecs\fR -When the secure channel is connected to the controller, the secure -channel waits for a message to be received from the controller for -\fIsecs\fR seconds before it sends a inactivity probe to the -controller. After sending the inactivity probe, if no response is -received for an additional \fIsecs\fR seconds, the secure channel -assumes that the connection has been broken and attempts to reconnect. -The default is 15 seconds, and the minimum value is 1 seconds. - -When fail-open mode is configured, changing the inactivity probe -interval also changes the interval before entering fail-open mode (see -above). - -.TP -\fB--max-idle=\fIsecs\fR|\fBpermanent\fR -Sets \fIsecs\fR as the number of seconds that a flow set up by the -secure channel will remain in the switch's flow table without any -matching packets being seen. If \fBpermanent\fR is specified, which -is not recommended, flows set up by the secure channel will never -expire. The default is 15 seconds. - -Most flows are set up by the OpenFlow controller, not by the secure -channel. This option affects only the following flows, which the -secure channel sets up itself: - -.RS -.IP \(bu -When \fB--fail=open\fR is specified, flows set up when the secure -channel has not been able to contact the controller for the configured -fail-open delay. - -.IP \(bu -When in-band control is in use, flows set up to bootstrap contacting -the controller (see \fBCONTACTING THE CONTROLLER\fR, above, for -more information about in-band control). -.RE - -.IP -As a result, when both \fB--fail=closed\fR and \fB--out-of-band\fR are -specified, this option has no effect. - -.TP -\fB--max-backoff=\fIsecs\fR -Sets the maximum time between attempts to connect to the controller to -\fIsecs\fR, which must be at least 1. The actual interval between -connection attempts starts at 1 second and doubles on each failing -attempt until it reaches the maximum. The default maximum backoff -time is 15 seconds. - -.TP -\fB-l\fR, \fB--listen=\fImethod\fR -Configures the switch to additionally listen for incoming OpenFlow -connections for switch management with \fBdpctl\fR. The \fImethod\fR -must be given as one of the passive OpenFlow connection methods listed -below. This option may be specified multiple times to listen to -multiple connection methods. - -.RS -.TP -\fBpssl:\fR[\fIport\fR] -Listens for SSL connections on \fIport\fR (default: 6633). The -\fB--private-key\fR, \fB--certificate\fR, and \fB--ca-cert\fR options -are mandatory when this form is used. - -.TP -\fBptcp:\fR[\fIport\fR] -Listens for TCP connections on \fIport\fR (default: 6633). - -.TP -\fBpunix:\fIfile\fR -Listens for connections on Unix domain server socket named \fIfile\fR. -.RE - -.TP -\fB-m\fR, \fB--monitor=\fImethod\fR -Configures the switch to additionally listen for incoming OpenFlow -connections for switch monitoring with \fBdpctl\fR's \fBmonitor\fR -command. The \fImethod\fR must be given as one of the passive -OpenFlow connection methods listed above as acceptable for -\fB--listen\fR. - -When \fBdpctl monitor\fR makes a monitoring connection, \fBofprotocol\fR -sends it a copy of every OpenFlow message sent to or received from the -kernel in the normal course of its operations. It does not send a -copy of any messages sent to or from the OpenFlow connection to the -controller. Most of these messages will be seen anyhow, however, -because \fBofprotocol\fR mainly acts as a relay between the controller -and the kernel. \fBofprotocol\fR also does not send a copy of any -messages sent to or from the OpenFlow connection to the controller. -Such messages will typically \fBnot\fR be seen, because \fBofprotocol\fR -maintains a separate connection to the kernel for each management -connection. - -Messages are copied to the monitoring connections on a best-effort -basis. In particular, if the socket buffer of the monitoring -connection fills up, some messages will be lost. - -.TP -\fB--in-band\fR, \fB--out-of-band\fR -Configures \fBofprotocol\fR to operate in in-band or out-of-band control -mode (see \fBCONTACTING THE CONTROLLER\fR above). When neither option -is given, the default is in-band control. - -.TP -\fB--stp\fR, \fB--no-stp\fR -Enable or disable implementation of IEEE 802.1D Spanning Tree Protocol -at the switch. The default is \fB--no-stp\fR in this distribution, -because bugs in the STP implementation are still being worked out. -The default will change to \fB--stp\fR at some point in the future. - -.TP -\fB--emerg-flow\fR -Enable emergecny flow protection and restration at the switch. If emergency -flow enabled, \fBofprotocol\fR will attempt to switch flow table to emergency's -one when a controller connection fails. The default is disabled in this -distribution. - -.SS "Rate-Limiting Options" - -These options configure how the switch applies a ``token bucket'' to -limit the rate at which packets in unknown flows are forwarded to an -OpenFlow controller for flow-setup processing. This feature prevents -a single OpenFlow switch from overwhelming a controller. - -.TP -\fB--rate-limit\fR[\fB=\fIrate\fR] -. -Limits the maximum rate at which packets will be forwarded to the -OpenFlow controller to \fIrate\fR packets per second. If \fIrate\fR -is not specified then the default of 1,000 packets per second is used. - -If \fB--rate-limit\fR is not used, then the switch does not limit the -rate at which packets are forwarded to the controller. - -.TP -\fB--burst-limit=\fIburst\fR -. -Sets the maximum number of unused packet credits that the switch will -allow to accumulate during time in which no packets are being -forwarded to the OpenFlow controller to \fIburst\fR (measured in -packets). The default \fIburst\fR is one-quarter of the \fIrate\fR -specified on \fB--rate-limit\fR. - -This option takes effect only when \fB--rate-limit\fR is also specified. - -.SS "Daemon Options" -.so lib/daemon.man - -.SS "Public Key Infrastructure Options" - -.TP -\fB-p\fR, \fB--private-key=\fIprivkey.pem\fR -Specifies a PEM file containing the private key used as the switch's -identity for SSL connections to the controller. - -.TP -\fB-c\fR, \fB--certificate=\fIcert.pem\fR -Specifies a PEM file containing a certificate, signed by the -controller's certificate authority (CA), that certifies the switch's -private key to identify a trustworthy switch. - -.TP -\fB-C\fR, \fB--ca-cert=\fIcacert.pem\fR -Specifies a PEM file containing the CA certificate used to verify that -the switch is connected to a trustworthy controller. - -.TP -\fB--bootstrap-ca-cert=\fIcacert.pem\fR -When \fIcacert.pem\fR exists, this option has the same effect as -\fB-C\fR or \fB--ca-cert\fR. If it does not exist, then \fBofprotocol\fR -will attempt to obtain the CA certificate from the controller on its -first SSL connection and save it to the named PEM file. If it is -successful, it will immediately drop the connection and reconnect, and -from then on all SSL connections must be authenticated by a -certificate signed by the CA certificate thus obtained. - -\fBThis option exposes the SSL connection to a man-in-the-middle -attack obtaining the initial CA certificate\fR, but it may be useful -for bootstrapping. - -This option is only useful if the controller sends its CA certificate -as part of the SSL certificate chain. The SSL protocol does not -require the controller to send the CA certificate, but -\fBcontroller\fR(8) can be configured to do so with the -\fB--peer-ca-cert\fR option. - -.SS "Logging Options" -.so lib/vlog.man -.SS "Other Options" -.so lib/common.man -.so lib/leak-checker.man - -.SH "SEE ALSO" - -.BR dpctl (8), -.BR ofp-discover (8), -.BR controller (8), -.BR ofp-pki (8), -.BR ofdatapath (8), -.BR vlogconf (8) diff --git a/openflow/secchan/port-watcher.c b/openflow/secchan/port-watcher.c deleted file mode 100644 index 0998e161..00000000 --- a/openflow/secchan/port-watcher.c +++ /dev/null @@ -1,620 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include "port-watcher.h" -#include -#include -#include -#include -#include "dynamic-string.h" -#include "netdev.h" -#include "ofpbuf.h" -#include "openflow/openflow.h" -#include "poll-loop.h" -#include "port-array.h" -#include "rconn.h" -#include "shash.h" -#include "svec.h" -#include "timeval.h" -#include "vconn.h" -#include "xtoxll.h" - -#define THIS_MODULE VLM_port_watcher -#include "vlog.h" - -struct port_watcher_cb { - port_changed_cb_func *port_changed; - void *aux; -}; - -struct port_watcher_local_cb { - local_port_changed_cb_func *local_port_changed; - void *aux; -}; - -struct port_watcher { - struct rconn *local_rconn; - struct rconn *remote_rconn; - struct port_array ports; - time_t last_feature_request; - bool got_feature_reply; - uint64_t datapath_id; - int n_txq; - struct port_watcher_cb cbs[2]; - int n_cbs; - struct port_watcher_local_cb local_cbs[4]; - int n_local_cbs; - char local_port_name[OFP_MAX_PORT_NAME_LEN + 1]; - struct netdev_monitor *mon; - struct shash port_by_name; -}; - -/* Returns the number of fields that differ from 'a' to 'b'. */ -static int -opp_differs(const struct ofp_phy_port *a, const struct ofp_phy_port *b) -{ - BUILD_ASSERT_DECL(sizeof *a == 48); /* Trips when we add or remove fields. */ - return ((a->port_no != b->port_no) - + (memcmp(a->hw_addr, b->hw_addr, sizeof a->hw_addr) != 0) - + (memcmp(a->name, b->name, sizeof a->name) != 0) - + (a->config != b->config) - + (a->state != b->state) - + (a->curr != b->curr) - + (a->advertised != b->advertised) - + (a->supported != b->supported) - + (a->peer != b->peer)); -} - -static void -sanitize_opp(struct ofp_phy_port *opp) -{ - size_t i; - - for (i = 0; i < sizeof opp->name; i++) { - char c = opp->name[i]; - if (c && (c < 0x20 || c > 0x7e)) { - opp->name[i] = '.'; - } - } - opp->name[sizeof opp->name - 1] = '\0'; -} - -static void -call_port_changed_callbacks(struct port_watcher *pw, int port_no, - const struct ofp_phy_port *old, - const struct ofp_phy_port *new) -{ - int i; - for (i = 0; i < pw->n_cbs; i++) { - port_changed_cb_func *port_changed = pw->cbs[i].port_changed; - (port_changed)(port_no, old, new, pw->cbs[i].aux); - } -} - -void -get_port_name(const struct ofp_phy_port *port, char *name, size_t name_size) -{ - char *p; - - memcpy(name, port->name, MIN(name_size, sizeof port->name)); - name[name_size - 1] = '\0'; - for (p = name; *p != '\0'; p++) { - if (*p < 32 || *p > 126) { - *p = '.'; - } - } -} - -static struct ofp_phy_port * -lookup_port(const struct port_watcher *pw, uint16_t port_no) -{ - return port_array_get(&pw->ports, port_no); -} - -static void -call_local_port_changed_callbacks(struct port_watcher *pw) -{ - char name[OFP_MAX_PORT_NAME_LEN + 1]; - const struct ofp_phy_port *port; - int i; - - /* Pass the local port to the callbacks, if it exists. - Pass a null pointer if there is no local port. */ - port = lookup_port(pw, OFPP_LOCAL); - - /* Log the name of the local port. */ - if (port) { - get_port_name(port, name, sizeof name); - } else { - name[0] = '\0'; - } - if (strcmp(pw->local_port_name, name)) { - if (name[0]) { - VLOG_INFO("Identified data path local port as \"%s\".", name); - } else { - VLOG_WARN("Data path has no local port."); - } - strcpy(pw->local_port_name, name); - } - - /* Invoke callbacks. */ - for (i = 0; i < pw->n_local_cbs; i++) { - local_port_changed_cb_func *cb = pw->local_cbs[i].local_port_changed; - (cb)(port, pw->local_cbs[i].aux); - } -} - -static void -update_phy_port(struct port_watcher *pw, struct ofp_phy_port *opp, - uint8_t reason) -{ - struct ofp_phy_port *old; - uint16_t port_no; - - port_no = ntohs(opp->port_no); - old = lookup_port(pw, port_no); - - if (reason == OFPPR_DELETE && old) { - call_port_changed_callbacks(pw, port_no, old, NULL); - free(old); - port_array_set(&pw->ports, port_no, NULL); - } else if (reason == OFPPR_MODIFY || reason == OFPPR_ADD) { - if (old) { - uint32_t s_mask = htonl(OFPPS_STP_MASK); - opp->state = (opp->state & ~s_mask) | (old->state & s_mask); - } - if (!old || opp_differs(opp, old)) { - struct ofp_phy_port new = *opp; - sanitize_opp(&new); - call_port_changed_callbacks(pw, port_no, old, &new); - if (old) { - *old = new; - } else { - port_array_set(&pw->ports, port_no, xmemdup(&new, sizeof new)); - } - } - } -} - -static void -update_netdev_monitor_devices(struct port_watcher *pw) -{ - struct ofp_phy_port *p; - struct svec netdevs; - unsigned int port_no; - - svec_init(&netdevs); - shash_clear(&pw->port_by_name); - for (p = port_array_first(&pw->ports, &port_no); p; - p = port_array_next(&pw->ports, &port_no)) { - const char *name = (const char *) p->name; - svec_add(&netdevs, name); - shash_add(&pw->port_by_name, name, p); - } - netdev_monitor_set_devices(pw->mon, netdevs.names, netdevs.n); - svec_destroy(&netdevs); -} - -static bool -port_watcher_local_packet_cb(struct relay *r, void *pw_) -{ - struct port_watcher *pw = pw_; - struct ofpbuf *msg = r->halves[HALF_LOCAL].rxbuf; - struct ofp_header *oh = msg->data; - - if (oh->type == OFPT_FEATURES_REPLY - && msg->size >= offsetof(struct ofp_switch_features, ports)) { - struct ofp_switch_features *osf = msg->data; - bool seen[PORT_ARRAY_SIZE]; - struct ofp_phy_port *p; - unsigned int port_no; - size_t n_ports; - size_t i; - - pw->got_feature_reply = true; - if (pw->datapath_id != osf->datapath_id) { - pw->datapath_id = osf->datapath_id; - VLOG_INFO("Datapath id is %012"PRIx64, ntohll(pw->datapath_id)); - } - - /* Update each port included in the message. */ - memset(seen, false, sizeof seen); - n_ports = ((msg->size - offsetof(struct ofp_switch_features, ports)) - / sizeof *osf->ports); - for (i = 0; i < n_ports; i++) { - struct ofp_phy_port *opp = &osf->ports[i]; - update_phy_port(pw, opp, OFPPR_MODIFY); - seen[ntohs(opp->port_no)] = true; - } - - /* Delete all the ports not included in the message. */ - for (p = port_array_first(&pw->ports, &port_no); p; - p = port_array_next(&pw->ports, &port_no)) { - if (!seen[port_no]) { - update_phy_port(pw, p, OFPPR_DELETE); - } - } - - update_netdev_monitor_devices(pw); - - call_local_port_changed_callbacks(pw); - } else if (oh->type == OFPT_PORT_STATUS - && msg->size >= sizeof(struct ofp_port_status)) { - struct ofp_port_status *ops = msg->data; - update_phy_port(pw, &ops->desc, ops->reason); - if (ops->desc.port_no == htons(OFPP_LOCAL)) { - call_local_port_changed_callbacks(pw); - } - if (ops->reason == OFPPR_ADD || OFPPR_DELETE) { - update_netdev_monitor_devices(pw); - } - } - return false; -} - -static void -bring_netdev_up_or_down(const char *name, bool down) -{ - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); - struct netdev *netdev; - int retval; - - retval = netdev_open(name, NETDEV_ETH_TYPE_NONE, &netdev); - if (!retval) { - if (down) { - retval = netdev_turn_flags_off(netdev, NETDEV_UP, true); - } else { - retval = netdev_turn_flags_on(netdev, NETDEV_UP, true); - } - if (retval) { - VLOG_WARN_RL(&rl, "failed to bring network device %s %s: %s", - name, down ? "down" : "up", strerror(retval)); - } - netdev_close(netdev); - } else { - VLOG_WARN_RL(&rl, "failed to open network device %s: %s", - name, strerror(retval)); - } -} - -static bool -port_watcher_remote_packet_cb(struct relay *r, void *pw_) -{ - struct port_watcher *pw = pw_; - struct ofpbuf *msg = r->halves[HALF_REMOTE].rxbuf; - struct ofp_header *oh = msg->data; - - if (oh->type == OFPT_PORT_MOD - && msg->size >= sizeof(struct ofp_port_mod)) { - struct ofp_port_mod *opm = msg->data; - uint16_t port_no = ntohs(opm->port_no); - struct ofp_phy_port *pw_opp = lookup_port(pw, port_no); - if (pw_opp->port_no != htons(OFPP_NONE)) { - struct ofp_phy_port old = *pw_opp; - pw_opp->config = ((pw_opp->config & ~opm->mask) - | (opm->config & opm->mask)); - call_port_changed_callbacks(pw, port_no, &old, pw_opp); - if (pw_opp->port_no == htons(OFPP_LOCAL)) { - call_local_port_changed_callbacks(pw); - } - - if (opm->mask & htonl(OFPPC_PORT_DOWN)) { - bring_netdev_up_or_down((const char *) pw_opp->name, - opm->config & htonl(OFPPC_PORT_DOWN)); - } - } - } - return false; -} - -/* Sets 'bit' in '*word' to 0 or 1 according to 'value'. */ -static void -set_bit(uint32_t bit, bool value, uint32_t *word) -{ - if (value) { - *word |= bit; - } else { - *word &= ~bit; - } -} - -static void -port_watcher_periodic_cb(void *pw_) -{ - struct port_watcher *pw = pw_; - const char *name; - - if (!pw->got_feature_reply - && time_now() >= pw->last_feature_request + 5 - && rconn_is_connected(pw->local_rconn)) { - struct ofpbuf *b; - make_openflow(sizeof(struct ofp_header), OFPT_FEATURES_REQUEST, &b); - rconn_send_with_limit(pw->local_rconn, b, &pw->n_txq, 1); - pw->last_feature_request = time_now(); - } - - netdev_monitor_run(pw->mon); - while ((name = netdev_monitor_poll(pw->mon)) != NULL) { - struct ofp_phy_port *opp; - struct ofp_phy_port new_opp; - enum netdev_flags flags; - int retval; - - opp = shash_find_data(&pw->port_by_name, name); - if (!opp) { - continue; - } - - retval = netdev_nodev_get_flags(name, &flags); - if (retval) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); - VLOG_WARN_RL(&rl, "could not get flags for %s", name); - continue; - } - - new_opp = *opp; - set_bit(htonl(OFPPC_PORT_DOWN), ~flags & NETDEV_UP, &new_opp.config); - set_bit(htonl(OFPPS_LINK_DOWN), ~flags & NETDEV_CARRIER, - &new_opp.state); - if (opp->config != new_opp.config || opp->state != new_opp.state) { - struct ofp_port_status *ops; - struct ofpbuf *b; - - /* Notify other secchan modules. */ - update_phy_port(pw, &new_opp, OFPPR_MODIFY); - if (new_opp.port_no == htons(OFPP_LOCAL)) { - call_local_port_changed_callbacks(pw); - } - - /* Notify the controller that the flags changed. */ - ops = make_openflow(sizeof *ops, OFPT_PORT_STATUS, &b); - ops->reason = OFPPR_MODIFY; - ops->desc = new_opp; - rconn_send(pw->remote_rconn, b, NULL); - } - } -} - -static void -port_watcher_wait_cb(void *pw_) -{ - struct port_watcher *pw = pw_; - if (!pw->got_feature_reply && rconn_is_connected(pw->local_rconn)) { - if (pw->last_feature_request != TIME_MIN) { - poll_timer_wait(pw->last_feature_request + 5 - time_now()); - } else { - poll_immediate_wake(); - } - } - netdev_monitor_wait(pw->mon); -} - -static void -put_duplexes(struct ds *ds, const char *name, uint32_t features, - uint32_t hd_bit, uint32_t fd_bit) -{ - if (features & (hd_bit | fd_bit)) { - ds_put_format(ds, " %s", name); - if (features & hd_bit) { - ds_put_cstr(ds, "(HD)"); - } - if (features & fd_bit) { - ds_put_cstr(ds, "(FD)"); - } - } -} - -static void -put_features(struct ds *ds, const char *name, uint32_t features) -{ - if (features & (OFPPF_10MB_HD | OFPPF_10MB_FD - | OFPPF_100MB_HD | OFPPF_100MB_FD - | OFPPF_1GB_HD | OFPPF_1GB_FD | OFPPF_10GB_FD)) { - ds_put_cstr(ds, name); - put_duplexes(ds, "10M", features, OFPPF_10MB_HD, OFPPF_10MB_FD); - put_duplexes(ds, "100M", features, - OFPPF_100MB_HD, OFPPF_100MB_FD); - put_duplexes(ds, "1G", features, OFPPF_1GB_HD, OFPPF_1GB_FD); - if (features & OFPPF_10GB_FD) { - ds_put_cstr(ds, " 10G"); - } - if (features & OFPPF_AUTONEG) { - ds_put_cstr(ds, " AUTO_NEG"); - } - if (features & OFPPF_PAUSE) { - ds_put_cstr(ds, " PAUSE"); - } - if (features & OFPPF_PAUSE_ASYM) { - ds_put_cstr(ds, " PAUSE_ASYM"); - } - } -} - -static void -log_port_status(uint16_t port_no, - const struct ofp_phy_port *old, - const struct ofp_phy_port *new, - void *aux UNUSED) -{ - if (VLOG_IS_DBG_ENABLED()) { - if (old && new && (opp_differs(old, new) - == ((old->config != new->config) - + (old->state != new->state)))) - { - /* Don't care if only state or config changed. */ - } else if (!new) { - if (old) { - VLOG_DBG("Port %d deleted", port_no); - } - } else { - struct ds ds = DS_EMPTY_INITIALIZER; - uint32_t curr = ntohl(new->curr); - uint32_t supported = ntohl(new->supported); - ds_put_format(&ds, "\"%s\", "ETH_ADDR_FMT, new->name, - ETH_ADDR_ARGS(new->hw_addr)); - if (curr) { - put_features(&ds, ", current", curr); - } - if (supported) { - put_features(&ds, ", supports", supported); - } - VLOG_DBG("Port %d %s: %s", - port_no, old ? "changed" : "added", ds_cstr(&ds)); - ds_destroy(&ds); - } - } -} - -void -port_watcher_register_callback(struct port_watcher *pw, - port_changed_cb_func *port_changed, - void *aux) -{ - assert(pw->n_cbs < ARRAY_SIZE(pw->cbs)); - pw->cbs[pw->n_cbs].port_changed = port_changed; - pw->cbs[pw->n_cbs].aux = aux; - pw->n_cbs++; -} - -void -port_watcher_register_local_port_callback(struct port_watcher *pw, - local_port_changed_cb_func *cb, - void *aux) -{ - assert(pw->n_local_cbs < ARRAY_SIZE(pw->local_cbs)); - pw->local_cbs[pw->n_local_cbs].local_port_changed = cb; - pw->local_cbs[pw->n_local_cbs].aux = aux; - pw->n_local_cbs++; -} - -uint32_t -port_watcher_get_config(const struct port_watcher *pw, uint16_t port_no) -{ - struct ofp_phy_port *p = lookup_port(pw, port_no); - return p ? ntohl(p->config) : 0; -} - -const char * -port_watcher_get_name(const struct port_watcher *pw, uint16_t port_no) -{ - struct ofp_phy_port *p = lookup_port(pw, port_no); - return p ? (const char *) p->name : NULL; -} - -const uint8_t * -port_watcher_get_hwaddr(const struct port_watcher *pw, uint16_t port_no) -{ - struct ofp_phy_port *p = lookup_port(pw, port_no); - return p ? p->hw_addr : NULL; -} - -void -port_watcher_set_flags(struct port_watcher *pw, uint16_t port_no, - uint32_t config, uint32_t c_mask, - uint32_t state, uint32_t s_mask) -{ - struct ofp_phy_port old; - struct ofp_phy_port *p; - struct ofp_port_mod *opm; - struct ofp_port_status *ops; - struct ofpbuf *b; - - p = lookup_port(pw, port_no); - if (!p) { - return; - } - - if (!((ntohl(p->state) ^ state) & s_mask) - && (!((ntohl(p->config) ^ config) & c_mask))) { - return; - } - old = *p; - - /* Update our idea of the flags. */ - p->config = htonl((ntohl(p->config) & ~c_mask) | (config & c_mask)); - p->state = htonl((ntohl(p->state) & ~s_mask) | (state & s_mask)); - call_port_changed_callbacks(pw, port_no, &old, p); - - /* Change the flags in the datapath. */ - opm = make_openflow(sizeof *opm, OFPT_PORT_MOD, &b); - opm->port_no = p->port_no; - memcpy(opm->hw_addr, p->hw_addr, OFP_ETH_ALEN); - opm->config = p->config; - opm->mask = htonl(c_mask); - opm->advertise = htonl(0); - rconn_send(pw->local_rconn, b, NULL); - - /* Notify the controller that the flags changed. */ - ops = make_openflow(sizeof *ops, OFPT_PORT_STATUS, &b); - ops->reason = OFPPR_MODIFY; - ops->desc = *p; - rconn_send(pw->remote_rconn, b, NULL); -} - -bool -port_watcher_is_ready(const struct port_watcher *pw) -{ - return pw->got_feature_reply; -} - -static struct hook_class port_watcher_hook_class = { - port_watcher_local_packet_cb, /* local_packet_cb */ - port_watcher_remote_packet_cb, /* remote_packet_cb */ - port_watcher_periodic_cb, /* periodic_cb */ - port_watcher_wait_cb, /* wait_cb */ - NULL, /* closing_cb */ -}; - -void -port_watcher_start(struct secchan *secchan, - struct rconn *local_rconn, struct rconn *remote_rconn, - struct port_watcher **pwp) -{ - struct port_watcher *pw; - int retval; - - pw = *pwp = xcalloc(1, sizeof *pw); - pw->local_rconn = local_rconn; - pw->remote_rconn = remote_rconn; - pw->last_feature_request = TIME_MIN; - port_array_init(&pw->ports); - pw->local_port_name[0] = '\0'; - retval = netdev_monitor_create(&pw->mon); - if (retval) { - ofp_fatal(retval, "failed to start network device monitoring"); - } - shash_init(&pw->port_by_name); - port_watcher_register_callback(pw, log_port_status, NULL); - add_hook(secchan, &port_watcher_hook_class, pw); -} diff --git a/openflow/secchan/port-watcher.h b/openflow/secchan/port-watcher.h deleted file mode 100644 index 904e545a..00000000 --- a/openflow/secchan/port-watcher.h +++ /dev/null @@ -1,77 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#ifndef PORT_WATCHER_H -#define PORT_WATCHER_H 1 - -#include -#include "compiler.h" -#include "secchan.h" - -struct ofp_phy_port; -struct port_watcher; -struct secchan; - -void port_watcher_start(struct secchan *, - struct rconn *local, struct rconn *remote, - struct port_watcher **); -bool port_watcher_is_ready(const struct port_watcher *); -uint32_t port_watcher_get_config(const struct port_watcher *, - uint16_t port_no); -const char *port_watcher_get_name(const struct port_watcher *, - uint16_t port_no) UNUSED; -const uint8_t *port_watcher_get_hwaddr(const struct port_watcher *, - uint16_t port_no); -void port_watcher_set_flags(struct port_watcher *, uint16_t port_no, - uint32_t config, uint32_t c_mask, - uint32_t state, uint32_t s_mask); - -typedef void port_changed_cb_func(uint16_t port_no, - const struct ofp_phy_port *old, - const struct ofp_phy_port *new, - void *aux); - -void port_watcher_register_callback(struct port_watcher *, - port_changed_cb_func *port_changed, - void *aux); - -typedef void local_port_changed_cb_func(const struct ofp_phy_port *new, - void *aux); - -void port_watcher_register_local_port_callback(struct port_watcher *pw, - local_port_changed_cb_func *cb, - void *aux); - -void get_port_name(const struct ofp_phy_port *, char *name, size_t name_size); - -#endif /* port-watcher.h */ diff --git a/openflow/secchan/protocol-stat.c b/openflow/secchan/protocol-stat.c deleted file mode 100644 index d54548b3..00000000 --- a/openflow/secchan/protocol-stat.c +++ /dev/null @@ -1,204 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#include -#include -#include -#include -#include -#include - -#include "openflow/openflow.h" -#include "openflow/private-ext.h" - -#include "ofpbuf.h" -#include "util.h" -#include "xtoxll.h" -#include "rconn.h" -#include "vconn.h" -#include "secchan.h" -#include "status.h" -#include "timeval.h" -#include "sat-math.h" -#include "ofpstat.h" -#include "protocol-stat.h" -#define THIS_MODULE VLM_protocol_stat -#include "vlog.h" - -#define COPY_OFPS(dst_ofps, src_ofps, tag) \ -do { \ - (dst_ofps)->tag = htonll((src_ofps)->tag); \ -} while (0) - -#define COPY_OFP_STAT(dst_ofps, src_ofps) \ -do { \ - COPY_OFPS(dst_ofps, src_ofps, ofps_total); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_unknown); \ - \ - COPY_OFPS(dst_ofps, src_ofps, ofps_hello); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_echo_request); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_echo_reply); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_vendor); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_feats_request); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_feats_reply); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_get_config_request); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_get_config_reply); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_set_config); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_packet_in); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_flow_removed); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_port_status); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_packet_out); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_flow_mod); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_port_mod); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_stats_request); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_stats_reply); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_barrier_request); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_barrier_reply); \ - \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_type.hello_fail); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_type.bad_request); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_type.bad_action); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_type.flow_mod_fail); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_type.unknown); \ - \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.hf_incompat); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.hf_eperm); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.br_bad_version); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.br_bad_type); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.br_bad_stat); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.br_bad_vendor); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.br_eperm); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.ba_bad_type); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.ba_bad_len); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.ba_bad_vendor); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.ba_bad_vendor_type); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.ba_bad_out_port); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.ba_eperm); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.fmf_all_tables_full); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.fmf_overlap); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.fmf_eperm); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_error_code.unknown); \ - \ - COPY_OFPS(dst_ofps, src_ofps, ofps_flow_mod_ops.add); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_flow_mod_ops.modify); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_flow_mod_ops.delete); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_flow_mod_ops.delete_strict); \ - COPY_OFPS(dst_ofps, src_ofps, ofps_flow_mod_ops.unknown); \ -} while (0) - -struct protocol_stat_context { - const struct settings *settings; - const struct secchan *secchan; - struct rconn *local_rconn; - struct rconn *remote_rconn; - struct ofpstat ofps_rcvd; - struct ofpstat ofps_sent; -}; - -static bool protocol_stat_remote_packet_cb(struct relay *, void *); - -static bool -protocol_stat_remote_packet_cb(struct relay *relay, void *context_) -{ - struct protocol_stat_context *context = context_; - struct rconn *mgmt_rconn = relay->halves[HALF_REMOTE].rconn; - struct ofpbuf *qbuf = relay->halves[HALF_REMOTE].rxbuf; - struct ofpbuf *pbuf = NULL; - struct private_vxhdr *qvxhdr = NULL; - struct private_vxhdr *pvxhdr = NULL; - struct private_vxopt *qvxopt = NULL; - struct private_vxopt *pvxopt = NULL; - struct ofpstat *ofps = NULL; - struct ofpstat ofps_rcvd; - struct ofpstat ofps_sent; - int error = 0; - - if (qbuf->size < sizeof(*qvxhdr)) - return false; - qvxhdr = qbuf->data; - if (qvxhdr->ofp_hdr.type != OFPT_VENDOR) - return false; - if (ntohl(qvxhdr->ofp_vxid) != PRIVATE_VENDOR_ID) { - return false; - } - qvxopt = (struct private_vxopt *)(qvxhdr + 1); - if (ntohs(qvxopt->pvo_type) != PRIVATEOPT_PROTOCOL_STATS_REQUEST) { - return true; - } - - pvxhdr = make_openflow_xid(sizeof(*pvxhdr) + sizeof(*pvxopt) - + (sizeof(*ofps) * 2), - OFPT_VENDOR, qvxhdr->ofp_hdr.xid, &pbuf); - pvxopt = (struct private_vxopt *)(pvxhdr + 1); - pvxhdr->ofp_vxid = qvxhdr->ofp_vxid; - pvxopt->pvo_type = htons(PRIVATEOPT_PROTOCOL_STATS_REPLY); - pvxopt->pvo_len = htons(sizeof(*ofps) * 2); - - rconn_update_protocol_stat(context->remote_rconn, - &ofps_rcvd, &ofps_sent); - ofps = (struct ofpstat *)((uint8_t *)(pvxhdr + 1) + sizeof(*pvxopt)); - COPY_OFP_STAT(ofps, &ofps_rcvd); - ofps = ofps + 1; - COPY_OFP_STAT(ofps, &ofps_sent); - - error = rconn_send(mgmt_rconn, pbuf, NULL); - if (error && error != EAGAIN) { - VLOG_WARN("send failed (%s)", strerror(error)); - } - - return true; -} - -void -protocol_stat_start(struct secchan *secchan, const struct settings *settings, - struct rconn *local_rconn, struct rconn *remote_rconn) -{ - struct protocol_stat_context *context = NULL; - static struct hook_class protocol_stat_hook_class = { - NULL, /* local_packet_cb */ - protocol_stat_remote_packet_cb, /* remote_packet_cb */ - NULL, /* periodic_cb */ - NULL, /* wait_cb */ - NULL, /* closing_cb */ - }; - - context = xmalloc(sizeof(*context)); - context->settings = settings; - context->secchan = secchan; - context->local_rconn = local_rconn; - context->remote_rconn = remote_rconn; - memset(&context->ofps_rcvd, 0, sizeof(context->ofps_rcvd)); - memset(&context->ofps_sent, 0, sizeof(context->ofps_sent)); - - add_hook(secchan, &protocol_stat_hook_class, context); -} diff --git a/openflow/secchan/protocol-stat.h b/openflow/secchan/protocol-stat.h deleted file mode 100644 index 3037b449..00000000 --- a/openflow/secchan/protocol-stat.h +++ /dev/null @@ -1,44 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#ifndef PROTOCOL_STAT_H_ -#define PROTOCOL_STAT_H_ - -struct rconn; -struct secchan; -struct settings; -struct switch_status; - -void protocol_stat_start(struct secchan *, const struct settings *, - struct rconn *, struct rconn *); - -#endif diff --git a/openflow/secchan/ratelimit.c b/openflow/secchan/ratelimit.c deleted file mode 100644 index 7a1e4951..00000000 --- a/openflow/secchan/ratelimit.c +++ /dev/null @@ -1,263 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include "ratelimit.h" -#include -#include -#include "ofpbuf.h" -#include "openflow/openflow.h" -#include "poll-loop.h" -#include "queue.h" -#include "rconn.h" -#include "secchan.h" -#include "status.h" -#include "timeval.h" -#include "vconn.h" - -struct rate_limiter { - const struct settings *s; - struct rconn *remote_rconn; - - /* One queue per physical port. */ - struct ofp_queue queues[OFPP_MAX]; - int n_queued; /* Sum over queues[*].n. */ - int next_tx_port; /* Next port to check in round-robin. */ - - /* Token bucket. - * - * It costs 1000 tokens to send a single packet_in message. A single token - * per message would be more straightforward, but this choice lets us avoid - * round-off error in refill_bucket()'s calculation of how many tokens to - * add to the bucket, since no division step is needed. */ - long long int last_fill; /* Time at which we last added tokens. */ - int tokens; /* Current number of tokens. */ - - /* Transmission queue. */ - int n_txq; /* No. of packets waiting in rconn for tx. */ - - /* Statistics reporting. */ - unsigned long long n_normal; /* # txed w/o rate limit queuing. */ - unsigned long long n_limited; /* # queued for rate limiting. */ - unsigned long long n_queue_dropped; /* # dropped due to queue overflow. */ - unsigned long long n_tx_dropped; /* # dropped due to tx overflow. */ -}; - -/* Drop a packet from the longest queue in 'rl'. */ -static void -drop_packet(struct rate_limiter *rl) -{ - struct ofp_queue *longest; /* Queue currently selected as longest. */ - int n_longest; /* # of queues of same length as 'longest'. */ - struct ofp_queue *q; - - longest = &rl->queues[0]; - n_longest = 1; - for (q = &rl->queues[0]; q < &rl->queues[OFPP_MAX]; q++) { - if (longest->n < q->n) { - longest = q; - n_longest = 1; - } else if (longest->n == q->n) { - n_longest++; - - /* Randomly select one of the longest queues, with a uniform - * distribution (Knuth algorithm 3.4.2R). */ - if (!random_range(n_longest)) { - longest = q; - } - } - } - - /* FIXME: do we want to pop the tail instead? */ - ofpbuf_delete(queue_pop_head(longest)); - rl->n_queued--; -} - -/* Remove and return the next packet to transmit (in round-robin order). */ -static struct ofpbuf * -dequeue_packet(struct rate_limiter *rl) -{ - unsigned int i; - - for (i = 0; i < OFPP_MAX; i++) { - unsigned int port = (rl->next_tx_port + i) % OFPP_MAX; - struct ofp_queue *q = &rl->queues[port]; - if (q->n) { - rl->next_tx_port = (port + 1) % OFPP_MAX; - rl->n_queued--; - return queue_pop_head(q); - } - } - NOT_REACHED(); -} - -/* Add tokens to the bucket based on elapsed time. */ -static void -refill_bucket(struct rate_limiter *rl) -{ - const struct settings *s = rl->s; - long long int now = time_msec(); - long long int tokens = (now - rl->last_fill) * s->rate_limit + rl->tokens; - if (tokens >= 1000) { - rl->last_fill = now; - rl->tokens = MIN(tokens, s->burst_limit * 1000); - } -} - -/* Attempts to remove enough tokens from 'rl' to transmit a packet. Returns - * true if successful, false otherwise. (In the latter case no tokens are - * removed.) */ -static bool -get_token(struct rate_limiter *rl) -{ - if (rl->tokens >= 1000) { - rl->tokens -= 1000; - return true; - } else { - return false; - } -} - -static bool -rate_limit_local_packet_cb(struct relay *r, void *rl_) -{ - struct rate_limiter *rl = rl_; - const struct settings *s = rl->s; - struct ofp_packet_in *opi; - - opi = get_ofp_packet_in(r); - if (!opi) { - return false; - } - - if (opi->reason == OFPR_ACTION) { - /* Don't rate-limit 'ofp-packet_in's generated by flows that the - * controller set up. XXX we should really just rate-limit them - * *separately* so that no one can flood the controller this way. */ - return false; - } - - if (!rl->n_queued && get_token(rl)) { - /* In the common case where we are not constrained by the rate limit, - * let the packet take the normal path. */ - rl->n_normal++; - return false; - } else { - /* Otherwise queue it up for the periodic callback to drain out. */ - struct ofpbuf *msg = r->halves[HALF_LOCAL].rxbuf; - int port = ntohs(opi->in_port) % OFPP_MAX; - if (rl->n_queued >= s->burst_limit) { - drop_packet(rl); - } - queue_push_tail(&rl->queues[port], ofpbuf_clone(msg)); - rl->n_queued++; - rl->n_limited++; - return true; - } -} - -static void -rate_limit_status_cb(struct status_reply *sr, void *rl_) -{ - struct rate_limiter *rl = rl_; - - status_reply_put(sr, "normal=%llu", rl->n_normal); - status_reply_put(sr, "limited=%llu", rl->n_limited); - status_reply_put(sr, "queue-dropped=%llu", rl->n_queue_dropped); - status_reply_put(sr, "tx-dropped=%llu", rl->n_tx_dropped); -} - -static void -rate_limit_periodic_cb(void *rl_) -{ - struct rate_limiter *rl = rl_; - int i; - - /* Drain some packets out of the bucket if possible, but limit the number - * of iterations to allow other code to get work done too. */ - refill_bucket(rl); - for (i = 0; rl->n_queued && get_token(rl) && i < 50; i++) { - /* Use a small, arbitrary limit for the amount of queuing to do here, - * because the TCP connection is responsible for buffering and there is - * no point in trying to transmit faster than the TCP connection can - * handle. */ - struct ofpbuf *b = dequeue_packet(rl); - if (rconn_send_with_limit(rl->remote_rconn, b, &rl->n_txq, 10)) { - rl->n_tx_dropped++; - } - } -} - -static void -rate_limit_wait_cb(void *rl_) -{ - struct rate_limiter *rl = rl_; - if (rl->n_queued) { - if (rl->tokens >= 1000) { - /* We can transmit more packets as soon as we're called again. */ - poll_immediate_wake(); - } else { - /* We have to wait for the bucket to re-fill. We could calculate - * the exact amount of time here for increased smoothness. */ - poll_timer_wait(TIME_UPDATE_INTERVAL / 2); - } - } -} - -static struct hook_class rate_limit_hook_class = { - rate_limit_local_packet_cb, /* local_packet_cb */ - NULL, /* remote_packet_cb */ - rate_limit_periodic_cb, /* periodic_cb */ - rate_limit_wait_cb, /* wait_cb */ - NULL, /* closing_cb */ -}; - -void -rate_limit_start(struct secchan *secchan, const struct settings *s, - struct switch_status *ss, struct rconn *remote) -{ - struct rate_limiter *rl; - size_t i; - - rl = xcalloc(1, sizeof *rl); - rl->s = s; - rl->remote_rconn = remote; - for (i = 0; i < ARRAY_SIZE(rl->queues); i++) { - queue_init(&rl->queues[i]); - } - rl->last_fill = time_msec(); - rl->tokens = s->rate_limit * 100; - switch_status_register_category(ss, "rate-limit", - rate_limit_status_cb, rl); - add_hook(secchan, &rate_limit_hook_class, rl); -} diff --git a/openflow/secchan/ratelimit.h b/openflow/secchan/ratelimit.h deleted file mode 100644 index 25ab9777..00000000 --- a/openflow/secchan/ratelimit.h +++ /dev/null @@ -1,45 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#ifndef RATELIMIT_H -#define RATELIMIT_H 1 - -struct rconn; -struct secchan; -struct settings; -struct switch_status; - -void rate_limit_start(struct secchan *, const struct settings *, - struct switch_status *, struct rconn *remote); - -#endif /* ratelimit.h */ diff --git a/openflow/secchan/secchan.c b/openflow/secchan/secchan.c deleted file mode 100644 index 15c7b696..00000000 --- a/openflow/secchan/secchan.c +++ /dev/null @@ -1,882 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include "secchan.h" -#include -#include -#include -#include -#include -#include -#include - -#include "command-line.h" -#include "compiler.h" -#include "daemon.h" -#include "dirs.h" -#include "discovery.h" -#include "emerg-flow.h" -#include "fail-open.h" -#include "failover.h" -#include "fault.h" -#include "in-band.h" -#include "leak-checker.h" -#include "list.h" -#include "ofpbuf.h" -#include "openflow/openflow.h" -#include "packets.h" -#include "protocol-stat.h" -#include "port-watcher.h" -#include "poll-loop.h" -#include "ratelimit.h" -#include "rconn.h" -#include "stp-secchan.h" -#include "status.h" -#include "timeval.h" -#include "util.h" -#include "vconn-ssl.h" -#include "vconn.h" -#include "vlog-socket.h" - -#include "vlog.h" -#define THIS_MODULE VLM_secchan - -struct hook { - const struct hook_class *class; - void *aux; -}; - -struct secchan { - struct hook *hooks; - size_t n_hooks, allocated_hooks; -}; - -static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60); - -static void parse_options(int argc, char *argv[], struct settings *); -static void usage(void) NO_RETURN; - -static char *vconn_name_without_subscription(const char *); -static struct pvconn *open_passive_vconn(const char *name); -static struct vconn *accept_vconn(struct pvconn *pvconn); - -static struct relay *relay_create(struct rconn *async, - struct rconn *local, struct rconn *remote, - bool is_mgmt_conn); -static struct relay *relay_accept(const struct settings *, struct pvconn *); -static void relay_run(struct relay *, struct secchan *); -static void relay_wait(struct relay *); -static void relay_destroy(struct relay *); - -int -main(int argc, char *argv[]) -{ - struct settings s; - - struct list relays = LIST_INITIALIZER(&relays); - - struct secchan secchan; - - struct pvconn *monitor; - - struct pvconn *listeners[MAX_MGMT]; - size_t n_listeners; - - char *local_rconn_name; - struct rconn *async_rconn, *local_rconn, *remote_rconn; - struct relay *controller_relay; - struct discovery *discovery; - struct switch_status *switch_status; - struct port_watcher *pw; - int i; - int retval; - - set_program_name(argv[0]); - register_fault_handlers(); - time_init(); - vlog_init(); - parse_options(argc, argv, &s); - signal(SIGPIPE, SIG_IGN); - - secchan.hooks = NULL; - secchan.n_hooks = 0; - secchan.allocated_hooks = 0; - - /* Start listening for management and monitoring connections. */ - n_listeners = 0; - for (i = 0; i < s.n_listeners; i++) { - listeners[n_listeners++] = open_passive_vconn(s.listener_names[i]); - } - monitor = s.monitor_name ? open_passive_vconn(s.monitor_name) : NULL; - - /* Initialize switch status hook. */ - switch_status_start(&secchan, &s, &switch_status); - - die_if_already_running(); - daemonize(); - - /* Start listening for vlogconf requests. */ - retval = vlog_server_listen(NULL, NULL); - if (retval) { - ofp_fatal(retval, "Could not listen for vlog connections"); - } - - VLOG_INFO("OpenFlow reference implementation version %s", VERSION BUILDNR); - VLOG_INFO("OpenFlow protocol version 0x%02x", OFP_VERSION); - - /* Check datapath name, to try to catch command-line invocation errors. */ - if (strncmp(s.dp_name, "nl:", 3) && strncmp(s.dp_name, "unix:", 5) - && !s.controller_names[0]) { - VLOG_WARN("Controller not specified and datapath is not nl: or " - "unix:. (Did you forget to specify the datapath?)"); - } - - if (!strncmp(s.dp_name, "nl:", 3)) { - /* Connect to datapath with a subscription for asynchronous events. By - * separating the connection for asynchronous events from that for - * request and replies we prevent the socket receive buffer from being - * filled up by received packet data, which in turn would prevent - * getting replies to any Netlink messages we send to the kernel. */ - async_rconn = rconn_create(0, s.max_backoff); - rconn_connect(async_rconn, s.dp_name); - switch_status_register_category(switch_status, "async", - rconn_status_cb, async_rconn); - } else { - /* No need for a separate asynchronous connection: we must be connected - * to the user datapath, which is smart enough to discard packet events - * instead of message replies. In fact, having a second connection - * would work against us since we'd get double copies of asynchronous - * event messages (the user datapath provides no way to turn off - * asynchronous events). */ - async_rconn = NULL; - } - - /* Connect to datapath without a subscription, for requests and replies. */ - local_rconn_name = vconn_name_without_subscription(s.dp_name); - local_rconn = rconn_create(0, s.max_backoff); - rconn_connect(local_rconn, local_rconn_name); - free(local_rconn_name); - switch_status_register_category(switch_status, "local", - rconn_status_cb, local_rconn); - - /* Connect to controller. */ - remote_rconn = rconn_create(s.probe_interval, s.max_backoff); - if (s.controller_names[0]) { - retval = rconn_connect(remote_rconn, s.controller_names[0]); - if (retval == EAFNOSUPPORT) { - ofp_fatal(0, "No support for %s vconn", s.controller_names[0]); - } - } - switch_status_register_category(switch_status, "remote", - rconn_status_cb, remote_rconn); - - /* Start relaying. */ - controller_relay = relay_create(async_rconn, local_rconn, remote_rconn, - false); - list_push_back(&relays, &controller_relay->node); - - /* Set up hooks. */ - port_watcher_start(&secchan, local_rconn, remote_rconn, &pw); - discovery = s.discovery ? discovery_init(&s, pw, switch_status) : NULL; - if (s.enable_stp) { - stp_start(&secchan, pw, local_rconn, remote_rconn); - } - if (s.in_band) { - in_band_start(&secchan, &s, switch_status, pw, remote_rconn); - } - if (s.fail_mode == FAIL_OPEN) { - fail_open_start(&secchan, &s, switch_status, - local_rconn, remote_rconn); - } - if (s.num_controllers > 1) { - failover_start(&secchan, &s, switch_status, remote_rconn); - } - if (s.n_listeners > 0) { - protocol_stat_start(&secchan, &s, local_rconn, remote_rconn); - } - if (s.rate_limit) { - rate_limit_start(&secchan, &s, switch_status, remote_rconn); - } - if (s.emerg_flow) { - emerg_flow_start(&secchan, &s, switch_status, local_rconn, remote_rconn); - } - - while (s.discovery || rconn_is_alive(remote_rconn)) { - struct relay *r, *n; - size_t i; - - /* Do work. */ - LIST_FOR_EACH_SAFE (r, n, struct relay, node, &relays) { - relay_run(r, &secchan); - } - for (i = 0; i < n_listeners; i++) { - for (;;) { - struct relay *r = relay_accept(&s, listeners[i]); - if (!r) { - break; - } - list_push_back(&relays, &r->node); - } - } - if (monitor) { - struct vconn *new = accept_vconn(monitor); - if (new) { - /* XXX should monitor async_rconn too but rconn_add_monitor() - * takes ownership of the vconn passed in. */ - rconn_add_monitor(local_rconn, new); - } - } - for (i = 0; i < secchan.n_hooks; i++) { - if (secchan.hooks[i].class->periodic_cb) { - secchan.hooks[i].class->periodic_cb(secchan.hooks[i].aux); - } - } - if (s.discovery) { - char *controller_name; - if (rconn_is_connectivity_questionable(remote_rconn)) { - discovery_question_connectivity(discovery); - } - if (discovery_run(discovery, &controller_name)) { - if (controller_name) { - rconn_connect(remote_rconn, controller_name); - } else { - rconn_disconnect(remote_rconn); - } - } - } - - /* Wait for something to happen. */ - LIST_FOR_EACH (r, struct relay, node, &relays) { - relay_wait(r); - } - for (i = 0; i < n_listeners; i++) { - pvconn_wait(listeners[i]); - } - if (monitor) { - pvconn_wait(monitor); - } - for (i = 0; i < secchan.n_hooks; i++) { - if (secchan.hooks[i].class->wait_cb) { - secchan.hooks[i].class->wait_cb(secchan.hooks[i].aux); - } - } - if (discovery) { - discovery_wait(discovery); - } - poll_block(); - } - - return 0; -} - -static struct pvconn * -open_passive_vconn(const char *name) -{ - struct pvconn *pvconn; - int retval; - - retval = pvconn_open(name, &pvconn); - if (retval && retval != EAGAIN) { - ofp_fatal(retval, "opening %s", name); - } - return pvconn; -} - -static struct vconn * -accept_vconn(struct pvconn *pvconn) -{ - struct vconn *new; - int retval; - - retval = pvconn_accept(pvconn, OFP_VERSION, &new); - if (retval && retval != EAGAIN) { - VLOG_WARN_RL(&rl, "accept failed (%s)", strerror(retval)); - } - return new; -} - -void -add_hook(struct secchan *secchan, const struct hook_class *class, void *aux) -{ - struct hook *hook; - - if (secchan->n_hooks >= secchan->allocated_hooks) { - secchan->hooks = x2nrealloc(secchan->hooks, &secchan->allocated_hooks, - sizeof *secchan->hooks); - } - hook = &secchan->hooks[secchan->n_hooks++]; - hook->class = class; - hook->aux = aux; -} - -struct ofp_packet_in * -get_ofp_packet_in(struct relay *r) -{ - struct ofpbuf *msg = r->halves[HALF_LOCAL].rxbuf; - struct ofp_header *oh = msg->data; - if (oh->type == OFPT_PACKET_IN) { - if (msg->size >= offsetof (struct ofp_packet_in, data)) { - return msg->data; - } else { - VLOG_WARN("packet too short (%zu bytes) for packet_in", - msg->size); - } - } - return NULL; -} - -bool -get_ofp_packet_eth_header(struct relay *r, struct ofp_packet_in **opip, - struct eth_header **ethp) -{ - const int min_len = offsetof(struct ofp_packet_in, data) + ETH_HEADER_LEN; - struct ofp_packet_in *opi = get_ofp_packet_in(r); - if (opi && ntohs(opi->header.length) >= min_len) { - *opip = opi; - *ethp = (void *) opi->data; - return true; - } - return false; -} - -/* OpenFlow message relaying. */ - -/* Returns a malloc'd string containing a copy of 'vconn_name' modified not to - * subscribe to asynchronous messages such as 'ofp_packet_in' events (if - * possible). */ -static char * -vconn_name_without_subscription(const char *vconn_name) -{ - int nl_index; - if (sscanf(vconn_name, "nl:%d", &nl_index) == 1) { - /* nl:123 or nl:123:1 opens a netlink connection to local datapath 123. - * nl:123:0 opens a netlink connection to local datapath 123 without - * obtaining a subscription for ofp_packet_in or ofp_flow_removed - * messages. */ - return xasprintf("nl:%d:0", nl_index); - } else { - /* We don't have a way to specify not to subscribe to those messages - * for other transports. (That's a defect: really this should be in - * the OpenFlow protocol, not the Netlink transport). */ - VLOG_WARN_RL(&rl, "new management connection will receive " - "asynchronous messages"); - return xstrdup(vconn_name); - } -} - -static struct relay * -relay_accept(const struct settings *s, struct pvconn *pvconn) -{ - struct vconn *new_remote, *new_local; - struct rconn *r1, *r2; - char *vconn_name; - int retval; - - new_remote = accept_vconn(pvconn); - if (!new_remote) { - return NULL; - } - - vconn_name = vconn_name_without_subscription(s->dp_name); - retval = vconn_open(vconn_name, OFP_VERSION, &new_local); - if (retval) { - VLOG_ERR_RL(&rl, "could not connect to %s (%s)", - vconn_name, strerror(retval)); - vconn_close(new_remote); - free(vconn_name); - return NULL; - } - - /* Create and return relay. */ - r1 = rconn_create(0, 0); - rconn_connect_unreliably(r1, vconn_name, new_local); - free(vconn_name); - - r2 = rconn_create(0, 0); - rconn_connect_unreliably(r2, "passive", new_remote); - - return relay_create(NULL, r1, r2, true); -} - -static struct relay * -relay_create(struct rconn *async, struct rconn *local, struct rconn *remote, - bool is_mgmt_conn) -{ - struct relay *r = xcalloc(1, sizeof *r); - r->halves[HALF_LOCAL].rconn = local; - r->halves[HALF_REMOTE].rconn = remote; - r->is_mgmt_conn = is_mgmt_conn; - r->async_rconn = async; - return r; -} - -static bool -call_local_packet_cbs(struct secchan *secchan, struct relay *r) -{ - const struct hook *h; - for (h = secchan->hooks; h < &secchan->hooks[secchan->n_hooks]; h++) { - bool (*cb)(struct relay *, void *aux) = h->class->local_packet_cb; - if (cb && (cb)(r, h->aux)) { - return true; - } - } - return false; -} - -static bool -call_remote_packet_cbs(struct secchan *secchan, struct relay *r) -{ - const struct hook *h; - for (h = secchan->hooks; h < &secchan->hooks[secchan->n_hooks]; h++) { - bool (*cb)(struct relay *, void *aux) = h->class->remote_packet_cb; - if (cb && (cb)(r, h->aux)) { - return true; - } - } - return false; -} - -static void -relay_run(struct relay *r, struct secchan *secchan) -{ - int iteration; - int i; - - if (r->async_rconn) { - rconn_run(r->async_rconn); - } - for (i = 0; i < 2; i++) { - rconn_run(r->halves[i].rconn); - } - - /* Limit the number of iterations to prevent other tasks from starving. */ - for (iteration = 0; iteration < 50; iteration++) { - bool progress = false; - for (i = 0; i < 2; i++) { - struct half *this = &r->halves[i]; - struct half *peer = &r->halves[!i]; - - if (!this->rxbuf) { - this->rxbuf = rconn_recv(this->rconn); - if (!this->rxbuf && i == HALF_LOCAL && r->async_rconn) { - this->rxbuf = rconn_recv(r->async_rconn); - } - if (this->rxbuf && (i == HALF_REMOTE || !r->is_mgmt_conn)) { - if (i == HALF_LOCAL - ? call_local_packet_cbs(secchan, r) - : call_remote_packet_cbs(secchan, r)) - { - ofpbuf_delete(this->rxbuf); - this->rxbuf = NULL; - progress = true; - break; - } - } - } - - if (this->rxbuf && !this->n_txq) { - int retval = rconn_send(peer->rconn, this->rxbuf, - &this->n_txq); - if (retval != EAGAIN) { - if (!retval) { - progress = true; - } else { - ofpbuf_delete(this->rxbuf); - } - this->rxbuf = NULL; - } - } - } - if (!progress) { - break; - } - } - - if (r->is_mgmt_conn) { - for (i = 0; i < 2; i++) { - struct half *this = &r->halves[i]; - if (!rconn_is_alive(this->rconn)) { - relay_destroy(r); - return; - } - } - } -} - -static void -relay_wait(struct relay *r) -{ - int i; - - if (r->async_rconn) { - rconn_run_wait(r->async_rconn); - } - for (i = 0; i < 2; i++) { - struct half *this = &r->halves[i]; - - rconn_run_wait(this->rconn); - if (!this->rxbuf) { - rconn_recv_wait(this->rconn); - if (i == HALF_LOCAL && r->async_rconn) { - rconn_recv_wait(r->async_rconn); - } - } - } -} - -static void -relay_destroy(struct relay *r) -{ - int i; - - list_remove(&r->node); - rconn_destroy(r->async_rconn); - for (i = 0; i < 2; i++) { - struct half *this = &r->halves[i]; - rconn_destroy(this->rconn); - ofpbuf_delete(this->rxbuf); - } - free(r); -} - -/* User interface. */ - -static void -parse_options(int argc, char *argv[], struct settings *s) -{ - enum { - OPT_ACCEPT_VCONN = UCHAR_MAX + 1, - OPT_NO_RESOLV_CONF, - OPT_INACTIVITY_PROBE, - OPT_MAX_IDLE, - OPT_MAX_BACKOFF, - OPT_RATE_LIMIT, - OPT_BURST_LIMIT, - OPT_BOOTSTRAP_CA_CERT, - OPT_STP, - OPT_NO_STP, - OPT_OUT_OF_BAND, - OPT_IN_BAND, - OPT_EMERG_FLOW, - VLOG_OPTION_ENUMS, - LEAK_CHECKER_OPTION_ENUMS - }; - static struct option long_options[] = { - {"accept-vconn", required_argument, 0, OPT_ACCEPT_VCONN}, - {"no-resolv-conf", no_argument, 0, OPT_NO_RESOLV_CONF}, - {"fail", required_argument, 0, 'F'}, - {"inactivity-probe", required_argument, 0, OPT_INACTIVITY_PROBE}, - {"max-idle", required_argument, 0, OPT_MAX_IDLE}, - {"max-backoff", required_argument, 0, OPT_MAX_BACKOFF}, - {"listen", required_argument, 0, 'l'}, - {"monitor", required_argument, 0, 'm'}, - {"rate-limit", optional_argument, 0, OPT_RATE_LIMIT}, - {"burst-limit", required_argument, 0, OPT_BURST_LIMIT}, - {"stp", no_argument, 0, OPT_STP}, - {"no-stp", no_argument, 0, OPT_NO_STP}, - {"out-of-band", no_argument, 0, OPT_OUT_OF_BAND}, - {"in-band", no_argument, 0, OPT_IN_BAND}, - {"emerg-flow", no_argument, 0, OPT_EMERG_FLOW}, - {"verbose", optional_argument, 0, 'v'}, - {"help", no_argument, 0, 'h'}, - {"version", no_argument, 0, 'V'}, - DAEMON_LONG_OPTIONS, - VLOG_LONG_OPTIONS, - LEAK_CHECKER_LONG_OPTIONS, -#ifdef HAVE_OPENSSL - VCONN_SSL_LONG_OPTIONS - {"bootstrap-ca-cert", required_argument, 0, OPT_BOOTSTRAP_CA_CERT}, -#endif - {0, 0, 0, 0}, - }; - char *short_options = long_options_to_short_options(long_options); - char *accept_re = NULL; - int retval; - - /* Set defaults that we can figure out before parsing options. */ - s->n_listeners = 0; - s->monitor_name = NULL; - s->fail_mode = FAIL_OPEN; - s->max_idle = 15; - s->probe_interval = 15; - s->max_backoff = 15; - s->update_resolv_conf = true; - s->rate_limit = 0; - s->burst_limit = 0; - s->enable_stp = false; - s->in_band = true; - s->emerg_flow = false; - for (;;) { - int c; - - c = getopt_long(argc, argv, short_options, long_options, NULL); - if (c == -1) { - break; - } - - switch (c) { - case OPT_ACCEPT_VCONN: - accept_re = optarg[0] == '^' ? optarg : xasprintf("^%s", optarg); - break; - - case OPT_NO_RESOLV_CONF: - s->update_resolv_conf = false; - break; - - case 'F': - if (!strcmp(optarg, "open")) { - s->fail_mode = FAIL_OPEN; - } else if (!strcmp(optarg, "closed")) { - s->fail_mode = FAIL_CLOSED; - } else { - ofp_fatal(0, "-f or --fail argument must be \"open\" " - "or \"closed\""); - } - break; - - case OPT_INACTIVITY_PROBE: - s->probe_interval = atoi(optarg); - if (s->probe_interval < 1) { - ofp_fatal(0, "--inactivity-probe argument must be at least 1"); - } - break; - - case OPT_MAX_IDLE: - if (!strcmp(optarg, "permanent")) { - s->max_idle = OFP_FLOW_PERMANENT; - } else { - s->max_idle = atoi(optarg); - if (s->max_idle < 1 || s->max_idle > 65535) { - ofp_fatal(0, "--max-idle argument must be between 1 and " - "65535 or the word 'permanent'"); - } - } - break; - - case OPT_MAX_BACKOFF: - s->max_backoff = atoi(optarg); - if (s->max_backoff < 1) { - ofp_fatal(0, "--max-backoff argument must be at least 1"); - } else if (s->max_backoff > 3600) { - s->max_backoff = 3600; - } - break; - - case OPT_RATE_LIMIT: - if (optarg) { - s->rate_limit = atoi(optarg); - if (s->rate_limit < 1) { - ofp_fatal(0, "--rate-limit argument must be at least 1"); - } - } else { - s->rate_limit = 1000; - } - break; - - case OPT_BURST_LIMIT: - s->burst_limit = atoi(optarg); - if (s->burst_limit < 1) { - ofp_fatal(0, "--burst-limit argument must be at least 1"); - } - break; - - case OPT_STP: - s->enable_stp = true; - break; - - case OPT_NO_STP: - s->enable_stp = false; - break; - - case OPT_OUT_OF_BAND: - s->in_band = false; - break; - - case OPT_IN_BAND: - s->in_band = true; - break; - - case OPT_EMERG_FLOW: - s->emerg_flow = true; - break; - - case 'l': - if (s->n_listeners >= MAX_MGMT) { - ofp_fatal(0, - "-l or --listen may be specified at most %d times", - MAX_MGMT); - } - s->listener_names[s->n_listeners++] = optarg; - break; - - case 'm': - if (s->monitor_name) { - ofp_fatal(0, "-m or --monitor may only be specified once"); - } - s->monitor_name = optarg; - break; - - case 'h': - usage(); - - case 'V': - printf("%s %s compiled "__DATE__" "__TIME__"\n", - program_name, VERSION BUILDNR); - exit(EXIT_SUCCESS); - - DAEMON_OPTION_HANDLERS - - VLOG_OPTION_HANDLERS - - LEAK_CHECKER_OPTION_HANDLERS - -#ifdef HAVE_OPENSSL - VCONN_SSL_OPTION_HANDLERS - - case OPT_BOOTSTRAP_CA_CERT: - vconn_ssl_set_ca_cert_file(optarg, true); - break; -#endif - - case '?': - exit(EXIT_FAILURE); - - default: - abort(); - } - } - free(short_options); - - argc -= optind; - argv += optind; - if (argc < 1 || argc > 2) { - ofp_fatal(0, "need one or two non-option arguments; " - "use --help for usage"); - } - - /* Local and remote vconns. */ - s->dp_name = argv[0]; - { - char *curr; - char *save; - int i; - - s->num_controllers = 0; - for (i = 0; i < MAX_CONTROLLERS; ++i) - s->controller_names[i] = NULL; - if (argc > 1) { - for (curr = strtok_r(argv[1], ",,", &save), i = 0; - curr && i < MAX_CONTROLLERS; - curr = strtok_r(NULL, ",,", &save), ++i) { - s->controller_names[i] = xstrdup(curr); - ++s->num_controllers; - } - } - } - - /* Set accept_controller_regex. */ - if (!accept_re) { - accept_re = vconn_ssl_is_configured() ? "^ssl:.*" : ".*"; - } - retval = regcomp(&s->accept_controller_regex, accept_re, - REG_NOSUB | REG_EXTENDED); - if (retval) { - size_t length = regerror(retval, &s->accept_controller_regex, NULL, 0); - char *buffer = xmalloc(length); - regerror(retval, &s->accept_controller_regex, buffer, length); - ofp_fatal(0, "%s: %s", accept_re, buffer); - } - s->accept_controller_re = accept_re; - - /* Mode of operation. */ - s->discovery = s->controller_names[0] == NULL; - if (s->discovery && !s->in_band) { - ofp_fatal(0, "Cannot perform discovery with out-of-band control"); - } - - /* Rate limiting. */ - if (s->rate_limit) { - if (s->rate_limit < 100) { - VLOG_WARN("Rate limit set to unusually low value %d", - s->rate_limit); - } - if (!s->burst_limit) { - s->burst_limit = s->rate_limit / 4; - } - s->burst_limit = MAX(s->burst_limit, 1); - s->burst_limit = MIN(s->burst_limit, INT_MAX / 1000); - } -} - -static void -usage(void) -{ - printf("%s: secure channel, a relay for OpenFlow messages.\n" - "usage: %s [OPTIONS] DATAPATH [CONTROLLER]\n" - "DATAPATH is an active connection method to a local datapath.\n" - "CONTROLLER is an active OpenFlow connection method; if it is\n" - "omitted, then secchan performs controller discovery.\n", - program_name, program_name); - vconn_usage(true, true, true); - printf("\nController discovery options:\n" - " --accept-vconn=REGEX accept matching discovered controllers\n" - " --no-resolv-conf do not update /etc/resolv.conf\n" - "\nNetworking options:\n" - " -F, --fail=open|closed when controller connection fails:\n" - " closed: drop all packets\n" - " open (default): act as learning switch\n" - " --inactivity-probe=SECS time between inactivity probes\n" - " --max-idle=SECS max idle for flows set up by secchan\n" - " --max-backoff=SECS max time between controller connection\n" - " attempts (default: 15 seconds)\n" - " -l, --listen=METHOD allow management connections on METHOD\n" - " (a passive OpenFlow connection method)\n" - " -m, --monitor=METHOD copy traffic to/from kernel to METHOD\n" - " (a passive OpenFlow connection method)\n" - " --out-of-band controller connection is out-of-band\n" - " --stp enable 802.1D Spanning Tree Protocol\n" - " --no-stp disable 802.1D Spanning Tree Protocol\n" - " --emerg-flow enable emergency flow protection/restoration\n" - "\nRate-limiting of \"packet-in\" messages to the controller:\n" - " --rate-limit[=PACKETS] max rate, in packets/s (default: 1000)\n" - " --burst-limit=BURST limit on packet credit for idle time\n", - ofp_pkgdatadir); - daemon_usage(); - vlog_usage(); - printf("\nOther options:\n" - " -h, --help display this help message\n" - " -V, --version display version information\n"); - leak_checker_usage(); - exit(EXIT_SUCCESS); -} diff --git a/openflow/secchan/secchan.h b/openflow/secchan/secchan.h deleted file mode 100644 index 7f89e2ef..00000000 --- a/openflow/secchan/secchan.h +++ /dev/null @@ -1,135 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#ifndef SECCHAN_H -#define SECCHAN_H 1 - -#include -#include -#include -#include "list.h" -#include "packets.h" - -struct secchan; - -/* Behavior when the connection to the controller fails. */ -enum fail_mode { - FAIL_OPEN, /* Act as learning switch. */ - FAIL_CLOSED /* Drop all packets. */ -}; - -/* Maximum number of management connection listeners. */ -#define MAX_MGMT 8 - -#define MAX_CONTROLLERS 3 - -/* Settings that may be configured by the user. */ -struct settings { - /* Overall mode of operation. */ - bool discovery; /* Discover the controller automatically? */ - bool in_band; /* Connect to controller in-band? */ - - /* Related vconns and network devices. */ - const char *dp_name; /* Local datapath. */ - int num_controllers; /* Number of configured controllers. */ - const char *controller_names[MAX_CONTROLLERS]; /* Controllers (if not discovery mode). */ - const char *listener_names[MAX_MGMT]; /* Listen for mgmt connections. */ - size_t n_listeners; /* Number of mgmt connection listeners. */ - const char *monitor_name; /* Listen for traffic monitor connections. */ - - /* Failure behavior. */ - enum fail_mode fail_mode; /* Act as learning switch if no controller? */ - int max_idle; /* Idle time for flows in fail-open mode. */ - int probe_interval; /* # seconds idle before sending echo request. */ - int max_backoff; /* Max # seconds between connection attempts. */ - - /* Packet-in rate-limiting. */ - int rate_limit; /* Tokens added to bucket per second. */ - int burst_limit; /* Maximum number token bucket size. */ - - /* Discovery behavior. */ - regex_t accept_controller_regex; /* Controller vconns to accept. */ - const char *accept_controller_re; /* String version of regex. */ - bool update_resolv_conf; /* Update /etc/resolv.conf? */ - - /* Spanning tree protocol. */ - bool enable_stp; - - /* Emergency flow protection/restoration behavior. */ - bool emerg_flow; -}; - -struct half { - struct rconn *rconn; - struct ofpbuf *rxbuf; - int n_txq; /* No. of packets queued for tx on 'rconn'. */ -}; - -struct relay { - struct list node; - -#define HALF_LOCAL 0 -#define HALF_REMOTE 1 - struct half halves[2]; - - /* The secchan has a primary connection (relay) to an OpenFlow controller. - * This primary connection actually makes two connections to the datapath: - * one for OpenFlow requests and responses, and one that is only used for - * receiving asynchronous events such as 'ofp_packet_in' events. This - * design keeps replies to OpenFlow requests from being dropped by the - * kernel due to a flooded network device. - * - * The secchan may also have any number of secondary "management" - * connections (relays). These connections do not receive asychronous - * events and thus have a null 'async_rconn'. */ - bool is_mgmt_conn; /* Is this a management connection? */ - struct rconn *async_rconn; /* For receiving asynchronous events. */ -}; - -struct hook_class { - bool (*local_packet_cb)(struct relay *, void *aux); - bool (*remote_packet_cb)(struct relay *, void *aux); - void (*periodic_cb)(void *aux); - void (*wait_cb)(void *aux); - void (*closing_cb)(struct relay *, void *aux); -}; - -void add_hook(struct secchan *, const struct hook_class *, void *); - -struct ofp_packet_in *get_ofp_packet_in(struct relay *); -bool get_ofp_packet_eth_header(struct relay *, struct ofp_packet_in **, - struct eth_header **); -void get_ofp_packet_payload(struct ofp_packet_in *, struct ofpbuf *); - - -#endif /* secchan.h */ diff --git a/openflow/secchan/status.c b/openflow/secchan/status.c deleted file mode 100644 index cf228123..00000000 --- a/openflow/secchan/status.c +++ /dev/null @@ -1,230 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include "status.h" -#include -#include -#include -#include -#include "dynamic-string.h" -#include "openflow/nicira-ext.h" -#include "ofpbuf.h" -#include "openflow/openflow.h" -#include "rconn.h" -#include "timeval.h" -#include "vconn.h" - -#define THIS_MODULE VLM_status -#include "vlog.h" - -struct switch_status_category { - char *name; - void (*cb)(struct status_reply *, void *aux); - void *aux; -}; - -struct switch_status { - const struct settings *s; - time_t booted; - struct switch_status_category *categories; - size_t n_categories, allocated_categories; -}; - -struct status_reply { - struct switch_status_category *category; - struct ds request; - struct ds output; -}; - -static bool -switch_status_remote_packet_cb(struct relay *r, void *ss_) -{ - struct switch_status *ss = ss_; - struct rconn *rc = r->halves[HALF_REMOTE].rconn; - struct ofpbuf *msg = r->halves[HALF_REMOTE].rxbuf; - struct switch_status_category *c; - struct nicira_header *request; - struct nicira_header *reply; - struct status_reply sr; - struct ofpbuf *b; - int retval; - - if (msg->size < sizeof(struct nicira_header)) { - return false; - } - request = msg->data; - if (request->header.type != OFPT_VENDOR - || request->vendor != htonl(NX_VENDOR_ID) - || request->subtype != htonl(NXT_STATUS_REQUEST)) { - return false; - } - - sr.request.string = (void *) (request + 1); - sr.request.length = msg->size - sizeof *request; - ds_init(&sr.output); - for (c = ss->categories; c < &ss->categories[ss->n_categories]; c++) { - if (!memcmp(c->name, sr.request.string, - MIN(strlen(c->name), sr.request.length))) { - sr.category = c; - c->cb(&sr, c->aux); - } - } - reply = make_openflow_xid(sizeof *reply + sr.output.length, - OFPT_VENDOR, request->header.xid, &b); - reply->vendor = htonl(NX_VENDOR_ID); - reply->subtype = htonl(NXT_STATUS_REPLY); - memcpy(reply + 1, sr.output.string, sr.output.length); - retval = rconn_send(rc, b, NULL); - if (retval && retval != EAGAIN) { - VLOG_WARN("send failed (%s)", strerror(retval)); - } - ds_destroy(&sr.output); - return true; -} - -void -rconn_status_cb(struct status_reply *sr, void *rconn_) -{ - struct rconn *rconn = rconn_; - time_t now = time_now(); - - status_reply_put(sr, "name=%s", rconn_get_name(rconn)); - status_reply_put(sr, "state=%s", rconn_get_state(rconn)); - status_reply_put(sr, "backoff=%d", rconn_get_backoff(rconn)); - status_reply_put(sr, "is-connected=%s", - rconn_is_connected(rconn) ? "true" : "false"); - status_reply_put(sr, "sent-msgs=%u", rconn_packets_sent(rconn)); - status_reply_put(sr, "received-msgs=%u", rconn_packets_received(rconn)); - status_reply_put(sr, "attempted-connections=%u", - rconn_get_attempted_connections(rconn)); - status_reply_put(sr, "successful-connections=%u", - rconn_get_successful_connections(rconn)); - status_reply_put(sr, "last-connection=%ld", - (long int) (now - rconn_get_last_connection(rconn))); - status_reply_put(sr, "time-connected=%lu", - rconn_get_total_time_connected(rconn)); - status_reply_put(sr, "state-elapsed=%u", rconn_get_state_elapsed(rconn)); -} - -static void -config_status_cb(struct status_reply *sr, void *s_) -{ - const struct settings *s = s_; - size_t i; - - for (i = 0; i < s->n_listeners; i++) { - status_reply_put(sr, "management%zu=%s", i, s->listener_names[i]); - } - if (s->probe_interval) { - status_reply_put(sr, "probe-interval=%d", s->probe_interval); - } - if (s->max_backoff) { - status_reply_put(sr, "max-backoff=%d", s->max_backoff); - } -} - -static void -switch_status_cb(struct status_reply *sr, void *ss_) -{ - struct switch_status *ss = ss_; - time_t now = time_now(); - - status_reply_put(sr, "now=%ld", (long int) now); - status_reply_put(sr, "uptime=%ld", (long int) (now - ss->booted)); - status_reply_put(sr, "pid=%ld", (long int) getpid()); -} - -static struct hook_class switch_status_hook_class = { - NULL, /* local_packet_cb */ - switch_status_remote_packet_cb, /* remote_packet_cb */ - NULL, /* periodic_cb */ - NULL, /* wait_cb */ - NULL, /* closing_cb */ -}; - -void -switch_status_start(struct secchan *secchan, const struct settings *s, - struct switch_status **ssp) -{ - struct switch_status *ss = xcalloc(1, sizeof *ss); - ss->s = s; - ss->booted = time_now(); - switch_status_register_category(ss, "config", - config_status_cb, (void *) s); - switch_status_register_category(ss, "switch", switch_status_cb, ss); - *ssp = ss; - add_hook(secchan, &switch_status_hook_class, ss); -} - -void -switch_status_register_category(struct switch_status *ss, - const char *category, - void (*cb)(struct status_reply *, void *aux), - void *aux) -{ - struct switch_status_category *c; - if (ss->n_categories >= ss->allocated_categories) { - ss->categories = x2nrealloc(ss->categories, &ss->allocated_categories, - sizeof *ss->categories); - } - c = &ss->categories[ss->n_categories++]; - c->cb = cb; - c->aux = aux; - c->name = xstrdup(category); -} - -void -status_reply_put(struct status_reply *sr, const char *content, ...) -{ - size_t old_length = sr->output.length; - size_t added; - va_list args; - - /* Append the status reply to the output. */ - ds_put_format(&sr->output, "%s.", sr->category->name); - va_start(args, content); - ds_put_format_valist(&sr->output, content, args); - va_end(args); - if (ds_last(&sr->output) != '\n') { - ds_put_char(&sr->output, '\n'); - } - - /* Drop what we just added if it doesn't match the request. */ - added = sr->output.length - old_length; - if (added < sr->request.length - || memcmp(&sr->output.string[old_length], - sr->request.string, sr->request.length)) { - ds_truncate(&sr->output, old_length); - } -} diff --git a/openflow/secchan/status.h b/openflow/secchan/status.h deleted file mode 100644 index 68793eff..00000000 --- a/openflow/secchan/status.h +++ /dev/null @@ -1,56 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#ifndef STATUS_H -#define STATUS_H 1 - -#include "secchan.h" - -struct secchan; -struct status_reply; -struct switch_status; - -void switch_status_start(struct secchan *, const struct settings *, - struct switch_status **); -void switch_status_register_category(struct switch_status *, - const char *category, - void (*cb)(struct status_reply *, - void *aux), - void *aux); - -void status_reply_put(struct status_reply *, const char *, ...) - PRINTF_FORMAT(2, 3); - -void rconn_status_cb(struct status_reply *, void *rconn_); - -#endif /* status.h */ diff --git a/openflow/secchan/stp-secchan.c b/openflow/secchan/stp-secchan.c deleted file mode 100644 index 152595e9..00000000 --- a/openflow/secchan/stp-secchan.c +++ /dev/null @@ -1,293 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include "stp-secchan.h" -#include -#include -#include "flow.h" -#include "secchan.h" -#include "ofpbuf.h" -#include "openflow/openflow.h" -#include "poll-loop.h" -#include "port-watcher.h" -#include "rconn.h" -#include "stp.h" -#include "timeval.h" -#include "vconn.h" - -#define THIS_MODULE VLM_stp_secchan -#include "vlog.h" - -struct stp_data { - struct stp *stp; - struct port_watcher *pw; - struct rconn *local_rconn; - struct rconn *remote_rconn; - long long int last_tick; - int n_txq; -}; - -static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60); - -static bool -stp_local_packet_cb(struct relay *r, void *stp_) -{ - struct ofpbuf *msg = r->halves[HALF_LOCAL].rxbuf; - struct ofp_header *oh; - struct stp_data *stp = stp_; - struct ofp_packet_in *opi; - struct eth_header *eth; - struct llc_header *llc; - struct ofpbuf payload; - uint16_t port_no; - struct flow flow; - - oh = msg->data; - if (oh->type == OFPT_FEATURES_REPLY - && msg->size >= offsetof(struct ofp_switch_features, ports)) { - struct ofp_switch_features *osf = msg->data; - osf->capabilities |= htonl(OFPC_STP); - return false; - } - - if (!get_ofp_packet_eth_header(r, &opi, ð) - || !eth_addr_equals(eth->eth_dst, stp_eth_addr)) { - return false; - } - - port_no = ntohs(opi->in_port); - if (port_no >= STP_MAX_PORTS) { - /* STP only supports 255 ports. */ - return false; - } - if (port_watcher_get_config(stp->pw, port_no) & OFPPC_NO_STP) { - /* We're not doing STP on this port. */ - return false; - } - - if (opi->reason == OFPR_ACTION) { - /* The controller set up a flow for this, so we won't intercept it. */ - return false; - } - - get_ofp_packet_payload(opi, &payload); - flow_extract(&payload, port_no, &flow); - if (flow.dl_type != htons(OFP_DL_TYPE_NOT_ETH_TYPE)) { - VLOG_DBG("non-LLC frame received on STP multicast address"); - return false; - } - llc = ofpbuf_at_assert(&payload, sizeof *eth, sizeof *llc); - if (llc->llc_dsap != STP_LLC_DSAP) { - VLOG_DBG("bad DSAP 0x%02"PRIx8" received on STP multicast address", - llc->llc_dsap); - return false; - } - - /* Trim off padding on payload. */ - if (payload.size > ntohs(eth->eth_type) + ETH_HEADER_LEN) { - payload.size = ntohs(eth->eth_type) + ETH_HEADER_LEN; - } - if (ofpbuf_try_pull(&payload, ETH_HEADER_LEN + LLC_HEADER_LEN)) { - struct stp_port *p = stp_get_port(stp->stp, port_no); - stp_received_bpdu(p, payload.data, payload.size); - } - - return true; -} - -static void -stp_periodic_cb(void *stp_) -{ - struct stp_data *stp = stp_; - long long int now = time_msec(); - long long int elapsed = now - stp->last_tick; - struct stp_port *p; - - if (!port_watcher_is_ready(stp->pw)) { - /* Can't start STP until we know port flags, because port flags can - * disable STP. */ - return; - } - if (elapsed <= 0) { - return; - } - - stp_tick(stp->stp, MIN(INT_MAX, elapsed)); - stp->last_tick = now; - - while (stp_get_changed_port(stp->stp, &p)) { - int port_no = stp_port_no(p); - enum stp_state s_state = stp_port_get_state(p); - - if (s_state != STP_DISABLED) { - VLOG_INFO("STP: Port %d entered %s state", - port_no, stp_state_name(s_state)); - } - if (!(port_watcher_get_config(stp->pw, port_no) & OFPPC_NO_STP)) { - uint32_t p_config = 0; - uint32_t p_state; - switch (s_state) { - case STP_LISTENING: - p_state = OFPPS_STP_LISTEN; - break; - case STP_LEARNING: - p_state = OFPPS_STP_LEARN; - break; - case STP_DISABLED: - case STP_FORWARDING: - p_state = OFPPS_STP_FORWARD; - break; - case STP_BLOCKING: - p_state = OFPPS_STP_BLOCK; - break; - default: - VLOG_DBG_RL(&rl, "STP: Port %d has bad state %x", - port_no, s_state); - p_state = OFPPS_STP_FORWARD; - break; - } - if (!stp_forward_in_state(s_state)) { - p_config = OFPPC_NO_FLOOD; - } - port_watcher_set_flags(stp->pw, port_no, - p_config, OFPPC_NO_FLOOD, - p_state, OFPPS_STP_MASK); - } else { - /* We don't own those flags. */ - } - } -} - -static void -stp_wait_cb(void *stp_ UNUSED) -{ - poll_timer_wait(1000); -} - -static void -send_bpdu(struct ofpbuf *pkt, int port_no, void *stp_) -{ - struct stp_data *stp = stp_; - const uint8_t *port_mac = port_watcher_get_hwaddr(stp->pw, port_no); - if (port_mac) { - struct eth_header *eth = pkt->l2; - struct ofpbuf *opo; - - memcpy(eth->eth_src, port_mac, ETH_ADDR_LEN); - opo = make_unbuffered_packet_out(pkt, OFPP_NONE, port_no); - - rconn_send_with_limit(stp->local_rconn, opo, &stp->n_txq, OFPP_MAX); - } else { - VLOG_WARN_RL(&rl, "cannot send BPDU on missing port %d", port_no); - } - ofpbuf_delete(pkt); -} - -static bool -stp_is_port_supported(uint16_t port_no) -{ - return port_no < STP_MAX_PORTS; -} - -static void -stp_port_changed_cb(uint16_t port_no, - const struct ofp_phy_port *old UNUSED, - const struct ofp_phy_port *new, - void *stp_) -{ - struct stp_data *stp = stp_; - struct stp_port *p; - - if (!stp_is_port_supported(port_no)) { - return; - } - - p = stp_get_port(stp->stp, port_no); - if (!new - || new->config & htonl(OFPPC_NO_STP | OFPPC_PORT_DOWN) - || new->state & htonl(OFPPS_LINK_DOWN)) { - stp_port_disable(p); - } else { - int speed = 0; - stp_port_enable(p); - if (new->curr & (OFPPF_10MB_HD | OFPPF_10MB_FD)) { - speed = 10; - } else if (new->curr & (OFPPF_100MB_HD | OFPPF_100MB_FD)) { - speed = 100; - } else if (new->curr & (OFPPF_1GB_HD | OFPPF_1GB_FD)) { - speed = 1000; - } else if (new->curr & OFPPF_10GB_FD) { - speed = 10000; - } - stp_port_set_speed(p, speed); - } -} - -static void -stp_local_port_changed_cb(const struct ofp_phy_port *port, void *stp_) -{ - struct stp_data *stp = stp_; - if (port) { - stp_set_bridge_id(stp->stp, eth_addr_to_uint64(port->hw_addr)); - } -} - -static struct hook_class stp_hook_class = { - stp_local_packet_cb, /* local_packet_cb */ - NULL, /* remote_packet_cb */ - stp_periodic_cb, /* periodic_cb */ - stp_wait_cb, /* wait_cb */ - NULL, /* closing_cb */ -}; - -void -stp_start(struct secchan *secchan, struct port_watcher *pw, - struct rconn *local, struct rconn *remote) -{ - uint8_t dpid[ETH_ADDR_LEN]; - struct stp_data *stp; - - stp = xcalloc(1, sizeof *stp); - eth_addr_random(dpid); - stp->stp = stp_create("stp", eth_addr_to_uint64(dpid), send_bpdu, stp); - stp->pw = pw; - stp->local_rconn = local; - stp->remote_rconn = remote; - stp->last_tick = time_msec(); - - port_watcher_register_callback(pw, stp_port_changed_cb, stp); - port_watcher_register_local_port_callback(pw, stp_local_port_changed_cb, - stp); - add_hook(secchan, &stp_hook_class, stp); -} diff --git a/openflow/secchan/stp-secchan.h b/openflow/secchan/stp-secchan.h deleted file mode 100644 index 2d1105f7..00000000 --- a/openflow/secchan/stp-secchan.h +++ /dev/null @@ -1,48 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#ifndef STP_SECCHAN_H -#define STP_SECCHAN_H 1 - -/* Extra time, in seconds, at boot before going into fail-open, to give the - * spanning tree protocol time to figure out the network layout. */ -#define STP_EXTRA_BOOT_TIME 30 - -struct port_watcher; -struct rconn; -struct secchan; - -void stp_start(struct secchan *, struct port_watcher *, - struct rconn *local, struct rconn *remote); - -#endif /* stp-secchan.h */ diff --git a/openflow/soexpand.pl b/openflow/soexpand.pl deleted file mode 100755 index 4e130056..00000000 --- a/openflow/soexpand.pl +++ /dev/null @@ -1,26 +0,0 @@ -use strict; -use warnings; -use Getopt::Long; - -my ($exit_code) = 0; -my (@include_dirs); -Getopt::Long::Configure ("bundling"); -GetOptions("I|include=s" => \@include_dirs) or exit(1); -@include_dirs = ('.') if !@include_dirs; -OUTER: while () { - if (my ($name) = /^\.so (\S+)$/) { - foreach my $dir (@include_dirs, '.') { - if (open(INNER, "$dir/$name")) { - while () { - print $_; - } - close(INNER); - next OUTER; - } - } - print STDERR "$name not found in: ", join(' ', @include_dirs), "\n"; - $exit_code = 1; - } - print $_; -} -exit $exit_code; diff --git a/openflow/tests/.dirstamp b/openflow/tests/.dirstamp deleted file mode 100644 index e69de29b..00000000 diff --git a/openflow/tests/.gitignore b/openflow/tests/.gitignore deleted file mode 100644 index 3e44d9e7..00000000 --- a/openflow/tests/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -/Makefile -/Makefile.in -/test-list -/test-dhcp-client -/test-stp -/test-type-props diff --git a/openflow/tests/automake.mk b/openflow/tests/automake.mk deleted file mode 100644 index a4e945a9..00000000 --- a/openflow/tests/automake.mk +++ /dev/null @@ -1,46 +0,0 @@ -TESTS += tests/test-flows.sh -noinst_PROGRAMS += tests/test-flows -tests_test_flows_SOURCES = tests/test-flows.c -tests_test_flows_LDADD = lib/libopenflow.a -dist_check_SCRIPTS = tests/test-flows.sh tests/flowgen.pl - -TESTS += tests/test-hmap -noinst_PROGRAMS += tests/test-hmap -tests_test_hmap_SOURCES = tests/test-hmap.c -tests_test_hmap_LDADD = lib/libopenflow.a - -TESTS += tests/test-list -noinst_PROGRAMS += tests/test-list -tests_test_list_SOURCES = tests/test-list.c -tests_test_list_LDADD = lib/libopenflow.a - -TESTS += tests/test-type-props -noinst_PROGRAMS += tests/test-type-props -tests_test_type_props_SOURCES = tests/test-type-props.c - -noinst_PROGRAMS += tests/test-dhcp-client -tests_test_dhcp_client_SOURCES = tests/test-dhcp-client.c -tests_test_dhcp_client_LDADD = lib/libopenflow.a $(FAULT_LIBS) - -TESTS += tests/test-stp.sh -EXTRA_DIST += tests/test-stp.sh -noinst_PROGRAMS += tests/test-stp - -tests_test_stp_SOURCES = tests/test-stp.c -tests_test_stp_LDADD = lib/libopenflow.a -stp_files = \ - tests/test-stp-ieee802.1d-1998 \ - tests/test-stp-ieee802.1d-2004-fig17.4 \ - tests/test-stp-ieee802.1d-2004-fig17.6 \ - tests/test-stp-ieee802.1d-2004-fig17.7 \ - tests/test-stp-iol-op-1.1 \ - tests/test-stp-iol-op-1.4 \ - tests/test-stp-iol-op-3.1 \ - tests/test-stp-iol-op-3.3 \ - tests/test-stp-iol-io-1.1 \ - tests/test-stp-iol-io-1.2 \ - tests/test-stp-iol-io-1.4 \ - tests/test-stp-iol-io-1.5 -TESTS_ENVIRONMENT += stp_files='$(stp_files)' - -EXTRA_DIST += $(stp_files) diff --git a/openflow/tests/flowgen.pl b/openflow/tests/flowgen.pl deleted file mode 100755 index eb17b2af..00000000 --- a/openflow/tests/flowgen.pl +++ /dev/null @@ -1,224 +0,0 @@ -#! /usr/bin/perl - -use strict; -use warnings; - -open(FLOWS, ">&=3");# or die "failed to open fd 3 for writing: $!\n"; -open(PACKETS, ">&=4");# or die "failed to open fd 4 for writing: $!\n"; - -# Print pcap file header. -print PACKETS pack('NnnNNNN', - 0xa1b2c3d4, # magic number - 2, # major version - 4, # minor version - 0, # time zone offset - 0, # time stamp accuracy - 1518, # snaplen - 1); # Ethernet - -output(DL_HEADER => '802.2'); - -for my $dl_header qw(802.2+SNAP Ethernet) { - my %a = (DL_HEADER => $dl_header); - for my $dl_vlan qw(none zero nonzero) { - my %b = (%a, DL_VLAN => $dl_vlan); - - # Non-IP case. - output(%b, DL_TYPE => 'non-ip'); - - for my $ip_options qw(no yes) { - my %c = (%b, DL_TYPE => 'ip', IP_OPTIONS => $ip_options); - for my $ip_fragment qw(no first middle last) { - my %d = (%c, IP_FRAGMENT => $ip_fragment); - for my $tp_proto qw(TCP TCP+options UDP ICMP other) { - output(%d, TP_PROTO => $tp_proto); - } - } - } - } -} - -sub output { - my (%attrs) = @_; - - # Compose flow. - my (%flow); - $flow{DL_SRC} = "00:02:e3:0f:80:a4"; - $flow{DL_DST} = "00:1a:92:40:ac:05"; - $flow{NW_PROTO} = 0; - $flow{NW_SRC} = '0.0.0.0'; - $flow{NW_DST} = '0.0.0.0'; - $flow{TP_SRC} = 0; - $flow{TP_DST} = 0; - if (defined($attrs{DL_VLAN})) { - my (%vlan_map) = ('none' => 0xffff, - 'zero' => 0, - 'nonzero' => 0x0123); - $flow{DL_VLAN} = $vlan_map{$attrs{DL_VLAN}}; - } else { - $flow{DL_VLAN} = 0xffff; # OFP_VLAN_NONE - } - if ($attrs{DL_HEADER} eq '802.2') { - $flow{DL_TYPE} = 0x5ff; # OFP_DL_TYPE_NOT_ETH_TYPE - } elsif ($attrs{DL_TYPE} eq 'ip') { - $flow{DL_TYPE} = 0x0800; # ETH_TYPE_IP - $flow{NW_SRC} = '10.0.2.15'; - $flow{NW_DST} = '192.168.1.20'; - if ($attrs{TP_PROTO} eq 'other') { - $flow{NW_PROTO} = 42; - } elsif ($attrs{TP_PROTO} eq 'TCP' || - $attrs{TP_PROTO} eq 'TCP+options') { - $flow{NW_PROTO} = 6; # IP_TYPE_TCP - $flow{TP_SRC} = 6667; - $flow{TP_DST} = 9998; - } elsif ($attrs{TP_PROTO} eq 'UDP') { - $flow{NW_PROTO} = 17; # IP_TYPE_UDP - $flow{TP_SRC} = 1112; - $flow{TP_DST} = 2223; - } elsif ($attrs{TP_PROTO} eq 'ICMP') { - $flow{NW_PROTO} = 1; # IP_TYPE_ICMP - $flow{TP_SRC} = 8; # echo request - $flow{TP_DST} = 0; # code - } else { - die; - } - if ($attrs{IP_FRAGMENT} ne 'no') { - $flow{TP_SRC} = $flow{TP_DST} = 0; - } - } elsif ($attrs{DL_TYPE} eq 'non-ip') { - $flow{DL_TYPE} = 0x5678; - } else { - die; - } - - # Compose packet. - my $packet = ''; - $packet .= pack_ethaddr($flow{DL_DST}); - $packet .= pack_ethaddr($flow{DL_SRC}); - $packet .= pack('n', 0) if $attrs{DL_HEADER} =~ /^802.2/; - if ($attrs{DL_HEADER} eq '802.2') { - $packet .= pack('CCC', 0x42, 0x42, 0x03); # LLC for 802.1D STP. - } else { - if ($attrs{DL_HEADER} eq '802.2+SNAP') { - $packet .= pack('CCC', 0xaa, 0xaa, 0x03); # LLC for SNAP. - $packet .= pack('CCC', 0, 0, 0); # SNAP OUI. - } - if ($attrs{DL_VLAN} ne 'none') { - $packet .= pack('nn', 0x8100, $flow{DL_VLAN}); - } - $packet .= pack('n', $flow{DL_TYPE}); - if ($attrs{DL_TYPE} eq 'ip') { - my $ip = pack('CCnnnCCnNN', - (4 << 4) | 5, # version, hdrlen - 0, # type of service - 0, # total length (filled in later) - 65432, # id - 0, # frag offset - 64, # ttl - $flow{NW_PROTO}, # protocol - 0, # checksum - 0x0a00020f, # source - 0xc0a80114); # dest - if ($attrs{IP_OPTIONS} eq 'yes') { - substr($ip, 0, 1) = pack('C', (4 << 4) | 8); - $ip .= pack('CCnnnCCCx', - 130, # type - 11, # length - 0x6bc5, # top secret - 0xabcd, - 0x1234, - 1, - 2, - 3); - } - if ($attrs{IP_FRAGMENT} ne 'no') { - my (%frag_map) = ('first' => 0x2000, # more frags, ofs 0 - 'middle' => 0x2111, # more frags, ofs 0x888 - 'last' => 0x0222); # last frag, ofs 0x1110 - substr($ip, 6, 2) - = pack('n', $frag_map{$attrs{IP_FRAGMENT}}); - } - - if ($attrs{TP_PROTO} =~ '^TCP') { - my $tcp = pack('nnNNnnnn', - $flow{TP_SRC}, # source port - $flow{TP_DST}, # dest port - 87123455, # seqno - 712378912, # ackno - (5 << 12) | 0x02 | 0x10, # hdrlen, SYN, ACK - 5823, # window size - 18923, # checksum - 12893); # urgent pointer - if ($attrs{TP_PROTO} eq 'TCP+options') { - substr($tcp, 12, 2) = pack('n', (6 << 12) | 0x02 | 0x10); - $tcp .= pack('CCn', 2, 4, 1975); # MSS option - } - $tcp .= 'payload'; - $ip .= $tcp; - } elsif ($attrs{TP_PROTO} eq 'UDP') { - my $len = 15; - my $udp = pack('nnnn', $flow{TP_SRC}, $flow{TP_DST}, $len, 0); - $udp .= chr($len) while length($udp) < $len; - $ip .= $udp; - } elsif ($attrs{TP_PROTO} eq 'ICMP') { - $ip .= pack('CCnnn', - 8, # echo request - 0, # code - 0, # checksum - 736, # identifier - 931); # sequence number - } elsif ($attrs{TP_PROTO} eq 'other') { - $ip .= 'other header'; - } else { - die; - } - - substr($ip, 2, 2) = pack('n', length($ip)); - $packet .= $ip; - } - } - substr($packet, 12, 2) = pack('n', length($packet)) - if $attrs{DL_HEADER} =~ /^802.2/; - - print join(' ', map("$_=$attrs{$_}", keys(%attrs))), "\n"; - print join(' ', map("$_=$flow{$_}", keys(%flow))), "\n"; - print "\n"; - - print FLOWS pack('Nn', - 0, # wildcards - 0); # in_port - print FLOWS pack_ethaddr($flow{DL_SRC}); - print FLOWS pack_ethaddr($flow{DL_DST}); - print FLOWS pack('nnCxNNnn', - $flow{DL_VLAN}, - $flow{DL_TYPE}, - $flow{NW_PROTO}, - inet_aton($flow{NW_SRC}), - inet_aton($flow{NW_DST}), - $flow{TP_SRC}, - $flow{TP_DST}); - - print PACKETS pack('NNNN', - 0, # timestamp seconds - 0, # timestamp microseconds - length($packet), # bytes saved - length($packet)), # total length - $packet; -} - -sub pack_ethaddr { - local ($_) = @_; - my $xx = '([0-9a-fA-F][0-9a-fA-F])'; - my (@octets) = /$xx:$xx:$xx:$xx:$xx:$xx/; - @octets == 6 or die $_; - my ($out) = ''; - $out .= pack('C', hex($_)) foreach @octets; - return $out; -} - -sub inet_aton { - local ($_) = @_; - my ($a, $b, $c, $d) = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/; - defined $d or die $_; - return ($a << 24) | ($b << 16) | ($c << 8) | $d; -} diff --git a/openflow/tests/test-dhcp-client.c b/openflow/tests/test-dhcp-client.c deleted file mode 100644 index f8a1f427..00000000 --- a/openflow/tests/test-dhcp-client.c +++ /dev/null @@ -1,206 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include "dhcp-client.h" -#include -#include -#include -#include -#include "command-line.h" -#include "dhcp.h" -#include "fatal-signal.h" -#include "fault.h" -#include "poll-loop.h" -#include "util.h" -#include "vlog.h" - -/* --request-ip: IP address to request from server. If zero, then do not - * request a specific IP address. */ -static struct in_addr request_ip; - -/* --vendor-class: Vendor class string to include in request. If null, no - * vendor class string is included. */ -static const char *vendor_class; - -/* --no-resolv-conf: Update /etc/resolv.conf to match DHCP reply? */ -static bool update_resolv_conf = true; - -static void parse_options(int argc, char *argv[]); -static void usage(void); -static void release(void *cli_); -static void modify_dhcp_request(struct dhcp_msg *, void *aux); - -int -main(int argc, char *argv[]) -{ - struct dhclient *cli; - int error; - - set_program_name(argv[0]); - register_fault_handlers(); - vlog_init(); - parse_options(argc, argv); - - argc -= optind; - argv += optind; - if (argc != 1) { - ofp_fatal(0, "exactly one non-option argument required; " - "use --help for help"); - } - - error = dhclient_create(argv[0], modify_dhcp_request, NULL, NULL, &cli); - if (error) { - ofp_fatal(error, "dhclient_create failed"); - } - dhclient_init(cli, request_ip.s_addr); - fatal_signal_add_hook(release, cli, true); - - for (;;) { - fatal_signal_block(); - dhclient_run(cli); - if (dhclient_changed(cli)) { - dhclient_configure_netdev(cli); - if (update_resolv_conf) { - dhclient_update_resolv_conf(cli); - } - } - dhclient_wait(cli); - fatal_signal_unblock(); - poll_block(); - } -} - -static void -release(void *cli_) -{ - struct dhclient *cli = cli_; - dhclient_release(cli); - if (dhclient_changed(cli)) { - dhclient_configure_netdev(cli); - } -} - -static void -modify_dhcp_request(struct dhcp_msg *msg, void *aux UNUSED) -{ - if (vendor_class) { - dhcp_msg_put_string(msg, DHCP_CODE_VENDOR_CLASS, vendor_class); - } -} - -static void -parse_options(int argc, char *argv[]) -{ - enum { - OPT_REQUEST_IP = UCHAR_MAX + 1, - OPT_VENDOR_CLASS, - OPT_NO_RESOLV_CONF - }; - static struct option long_options[] = { - {"request-ip", required_argument, 0, OPT_REQUEST_IP }, - {"vendor-class", required_argument, 0, OPT_VENDOR_CLASS }, - {"no-resolv-conf", no_argument, 0, OPT_NO_RESOLV_CONF}, - {"verbose", optional_argument, 0, 'v'}, - {"help", no_argument, 0, 'h'}, - {"version", no_argument, 0, 'V'}, - {0, 0, 0, 0}, - }; - char *short_options = long_options_to_short_options(long_options); - - for (;;) { - int c; - - c = getopt_long(argc, argv, short_options, long_options, NULL); - if (c == -1) { - break; - } - - switch (c) { - case OPT_REQUEST_IP: - if (!inet_aton(optarg, &request_ip)) { - ofp_fatal(0, - "--request-ip argument is not a valid IP address"); - } - break; - - case OPT_VENDOR_CLASS: - vendor_class = optarg; - break; - - case OPT_NO_RESOLV_CONF: - update_resolv_conf = false; - break; - - case 'h': - usage(); - - case 'V': - printf("%s %s compiled "__DATE__" "__TIME__"\n", - program_name, VERSION BUILDNR); - exit(EXIT_SUCCESS); - - case 'v': - vlog_set_verbosity(optarg); - break; - - case '?': - exit(EXIT_FAILURE); - - default: - abort(); - } - } - free(short_options); -} - -static void -usage(void) -{ - printf("%s: standalone program for testing OpenFlow DHCP client.\n" - "usage: %s [OPTIONS] NETDEV\n" - "where NETDEV is a network device (e.g. eth0).\n" - "\nDHCP options:\n" - " --request-ip=IP request specified IP address (default:\n" - " do not request a specific IP)\n" - " --vendor-class=STRING use STRING as vendor class (default:\n" - " none); use OpenFlow to imitate secchan\n" - " --no-resolv-conf do not update /etc/resolv.conf\n", - program_name, program_name); - vlog_usage(); - printf("\nOther options:\n" - " -h, --help display this help message\n" - " -V, --version display version information\n"); - exit(EXIT_SUCCESS); -} - diff --git a/openflow/tests/test-flows b/openflow/tests/test-flows deleted file mode 100755 index 891f9547888703c22fd04673db3fa828eceb1131..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 286976 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 -#include "flow.h" -#include -#include -#include -#include "openflow/openflow.h" -#include "timeval.h" -#include "ofpbuf.h" -#include "ofp-print.h" -#include "pcap.h" -#include "util.h" -#include "vlog.h" - -#undef NDEBUG -#include - -int -main(int argc UNUSED, char *argv[]) -{ - struct ofp_match expected_match; - FILE *flows, *pcap; - int retval; - int n = 0, errors = 0; - - set_program_name(argv[0]); - time_init(); - vlog_init(); - - flows = stdin; - pcap = fdopen(3, "rb"); - if (!pcap) { - ofp_fatal(errno, "failed to open fd 3 for reading"); - } - - retval = pcap_read_header(pcap); - if (retval) { - ofp_fatal(retval > 0 ? retval : 0, "reading pcap header failed"); - } - - while (fread(&expected_match, sizeof expected_match, 1, flows)) { - struct ofpbuf *packet; - struct ofp_match extracted_match; - struct flow flow; - - n++; - - retval = pcap_read(pcap, &packet); - if (retval == EOF) { - ofp_fatal(0, "unexpected end of file reading pcap file"); - } else if (retval) { - ofp_fatal(retval, "error reading pcap file"); - } - - flow_extract(packet, 0, &flow); - flow_fill_match(&extracted_match, &flow, 0); - - if (memcmp(&expected_match, &extracted_match, sizeof expected_match)) { - char *exp_s = ofp_match_to_string(&expected_match, 2); - char *got_s = ofp_match_to_string(&extracted_match, 2); - errors++; - printf("mismatch on packet #%d (1-based).\n", n); - printf("Packet:\n"); - ofp_print_packet(stdout, packet->data, packet->size, packet->size); - printf("Expected flow:\n%s\n", exp_s); - printf("Actually extracted flow:\n%s\n", got_s); - printf("\n"); - free(exp_s); - free(got_s); - } - - ofpbuf_delete(packet); - } - printf("checked %d packets, %d errors\n", n, errors); - return errors != 0; -} - diff --git a/openflow/tests/test-flows.sh b/openflow/tests/test-flows.sh deleted file mode 100755 index 0d38ad78..00000000 --- a/openflow/tests/test-flows.sh +++ /dev/null @@ -1,9 +0,0 @@ -#! /bin/sh -e -srcdir=`cd $srcdir && pwd` -trap 'rm -f flows$$ pcap$$ out$$' 0 1 2 13 15 -cd tests -"$srcdir"/tests/flowgen.pl >/dev/null 3>flows$$ 4>pcap$$ -./test-flows out$$ || true -diff -u - out$$ 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 HGyVSu&X&XL diff --git a/openflow/tests/test-hmap.c b/openflow/tests/test-hmap.c deleted file mode 100644 index 962389fa..00000000 --- a/openflow/tests/test-hmap.c +++ /dev/null @@ -1,282 +0,0 @@ -/* A non-exhaustive test for some of the functions and macros declared in - * hmap.h. */ - -#include -#include "hmap.h" -#include -#include "hash.h" -#include "util.h" - -#undef NDEBUG -#include - -/* Sample hmap element. */ -struct element { - int value; - struct hmap_node node; -}; - -typedef size_t hash_func(int value); - -static int -compare_ints(const void *a_, const void *b_) -{ - const int *a = a_; - const int *b = b_; - return *a < *b ? -1 : *a > *b; -} - -/* Verifies that 'hmap' contains exactly the 'n' values in 'values'. */ -static void -check_hmap(struct hmap *hmap, const int values[], size_t n, - hash_func *hash) -{ - int *sort_values, *hmap_values; - struct element *e; - size_t i; - - /* Check that all the values are there in iteration. */ - sort_values = xmalloc(sizeof *sort_values * n); - hmap_values = xmalloc(sizeof *sort_values * n); - - i = 0; - HMAP_FOR_EACH (e, struct element, node, hmap) { - assert(i < n); - hmap_values[i++] = e->value; - } - assert(i == n); - - memcpy(sort_values, values, sizeof *sort_values * n); - qsort(sort_values, n, sizeof *sort_values, compare_ints); - qsort(hmap_values, n, sizeof *hmap_values, compare_ints); - - for (i = 0; i < n; i++) { - assert(sort_values[i] == hmap_values[i]); - } - - free(hmap_values); - free(sort_values); - - /* Check that all the values are there in lookup. */ - for (i = 0; i < n; i++) { - size_t count = 0; - - HMAP_FOR_EACH_WITH_HASH (e, struct element, node, - hash(values[i]), hmap) { - count += e->value == values[i]; - } - assert(count == 1); - } - - /* Check counters. */ - assert(hmap_is_empty(hmap) == !n); - assert(hmap_count(hmap) == n); -} - -/* Puts the 'n' values in 'values' into 'elements', and then puts those - * elements into 'hmap'. */ -static void -make_hmap(struct hmap *hmap, struct element elements[], - int values[], size_t n, hash_func *hash) -{ - size_t i; - - hmap_init(hmap); - for (i = 0; i < n; i++) { - elements[i].value = i; - hmap_insert(hmap, &elements[i].node, hash(elements[i].value)); - values[i] = i; - } -} - -static void -shuffle(int *p, size_t n) -{ - for (; n > 1; n--, p++) { - int *q = &p[rand() % n]; - int tmp = *p; - *p = *q; - *q = tmp; - } -} - -#if 0 -/* Prints the values in 'hmap', plus 'name' as a title. */ -static void -print_hmap(const char *name, struct hmap *hmap) -{ - struct element *e; - - printf("%s:", name); - HMAP_FOR_EACH (e, struct element, node, hmap) { - printf(" %d(%zu)", e->value, e->node.hash & hmap->mask); - } - printf("\n"); -} - -/* Prints the 'n' values in 'values', plus 'name' as a title. */ -static void -print_ints(const char *name, const int *values, size_t n) -{ - size_t i; - - printf("%s:", name); - for (i = 0; i < n; i++) { - printf(" %d", values[i]); - } - printf("\n"); -} -#endif - -static size_t -identity_hash(int value) -{ - return value; -} - -static size_t -good_hash(int value) -{ - const uint32_t x = value; - return hash_words(&x, 1, 0x1234abcd); -} - -static size_t -constant_hash(int value UNUSED) -{ - return 123; -} - -/* Tests basic hmap insertion and deletion. */ -static void -test_hmap_insert_delete(hash_func *hash) -{ - enum { N_ELEMS = 100 }; - - struct element elements[N_ELEMS]; - int values[N_ELEMS]; - struct hmap hmap; - size_t i; - - hmap_init(&hmap); - for (i = 0; i < N_ELEMS; i++) { - elements[i].value = i; - hmap_insert(&hmap, &elements[i].node, hash(i)); - values[i] = i; - check_hmap(&hmap, values, i + 1, hash); - } - shuffle(values, N_ELEMS); - for (i = 0; i < N_ELEMS; i++) { - hmap_remove(&hmap, &elements[values[i]].node); - check_hmap(&hmap, values + (i + 1), N_ELEMS - (i + 1), hash); - } - hmap_destroy(&hmap); -} - -/* Tests basic hmap_reserve() and hmap_shrink(). */ -static void -test_hmap_reserve_shrink(hash_func *hash) -{ - enum { N_ELEMS = 32 }; - - size_t i; - - for (i = 0; i < N_ELEMS; i++) { - struct element elements[N_ELEMS]; - int values[N_ELEMS]; - struct hmap hmap; - size_t j; - - hmap_init(&hmap); - hmap_reserve(&hmap, i); - for (j = 0; j < N_ELEMS; j++) { - elements[j].value = j; - hmap_insert(&hmap, &elements[j].node, hash(j)); - values[j] = j; - check_hmap(&hmap, values, j + 1, hash); - } - shuffle(values, N_ELEMS); - for (j = 0; j < N_ELEMS; j++) { - hmap_remove(&hmap, &elements[values[j]].node); - hmap_shrink(&hmap); - check_hmap(&hmap, values + (j + 1), N_ELEMS - (j + 1), hash); - } - hmap_destroy(&hmap); - } -} - -/* Tests that HMAP_FOR_EACH_SAFE properly allows for deletion of the current - * element of a hmap. */ -static void -test_hmap_for_each_safe(hash_func *hash) -{ - enum { MAX_ELEMS = 10 }; - size_t n; - unsigned long int pattern; - - for (n = 0; n <= MAX_ELEMS; n++) { - for (pattern = 0; pattern < 1ul << n; pattern++) { - struct element elements[MAX_ELEMS]; - int values[MAX_ELEMS]; - struct hmap hmap; - struct element *e, *next; - size_t n_remaining; - int i; - - make_hmap(&hmap, elements, values, n, hash); - - i = 0; - n_remaining = n; - HMAP_FOR_EACH_SAFE (e, next, struct element, node, &hmap) { - assert(i < n); - if (pattern & (1ul << e->value)) { - size_t j; - hmap_remove(&hmap, &e->node); - for (j = 0; ; j++) { - assert(j < n_remaining); - if (values[j] == e->value) { - values[j] = values[--n_remaining]; - break; - } - } - } - check_hmap(&hmap, values, n_remaining, hash); - i++; - } - assert(i == n); - - for (i = 0; i < n; i++) { - if (pattern & (1ul << i)) { - n_remaining++; - } - } - assert(n == n_remaining); - - hmap_destroy(&hmap); - } - } -} - -static void -run_test(void (*function)(hash_func *)) -{ - hash_func *hash_funcs[] = { identity_hash, good_hash, constant_hash }; - size_t i; - - for (i = 0; i < ARRAY_SIZE(hash_funcs); i++) { - function(hash_funcs[i]); - printf("."); - fflush(stdout); - } -} - -int -main(void) -{ - run_test(test_hmap_insert_delete); - run_test(test_hmap_for_each_safe); - run_test(test_hmap_reserve_shrink); - printf("\n"); - return 0; -} - diff --git a/openflow/tests/test-list.c b/openflow/tests/test-list.c deleted file mode 100644 index 62857be9..00000000 --- a/openflow/tests/test-list.c +++ /dev/null @@ -1,159 +0,0 @@ -/* A non-exhaustive test for some of the functions and macros declared in - * list.h. */ - -#include -#include "list.h" -#include - -#undef NDEBUG -#include - -/* Sample list element. */ -struct element { - int value; - struct list node; -}; - -/* Puts the 'n' values in 'values' into 'elements', and then puts those - * elements in order into 'list'. */ -static void -make_list(struct list *list, struct element elements[], - int values[], size_t n) -{ - size_t i; - - list_init(list); - for (i = 0; i < n; i++) { - elements[i].value = i; - list_push_back(list, &elements[i].node); - values[i] = i; - } -} - -/* Verifies that 'list' contains exactly the 'n' values in 'values', in the - * specified order. */ -static void -check_list(struct list *list, const int values[], size_t n) -{ - struct element *e; - size_t i; - - i = 0; - LIST_FOR_EACH (e, struct element, node, list) { - assert(i < n); - assert(e->value == values[i]); - i++; - } - assert(&e->node == list); - assert(i == n); - - i = 0; - LIST_FOR_EACH_REVERSE (e, struct element, node, list) { - assert(i < n); - assert(e->value == values[n - i - 1]); - i++; - } - assert(&e->node == list); - assert(i == n); - - assert(list_is_empty(list) == !n); - assert(list_size(list) == n); -} - -#if 0 -/* Prints the values in 'list', plus 'name' as a title. */ -static void -print_list(const char *name, struct list *list) -{ - struct element *e; - - printf("%s:", name); - LIST_FOR_EACH (e, struct element, node, list) { - printf(" %d", e->value); - } - printf("\n"); -} -#endif - -/* Tests basic list construction. */ -static void -test_list_construction(void) -{ - enum { MAX_ELEMS = 100 }; - size_t n; - - for (n = 0; n <= MAX_ELEMS; n++) { - struct element elements[MAX_ELEMS]; - int values[MAX_ELEMS]; - struct list list; - - make_list(&list, elements, values, n); - check_list(&list, values, n); - } -} - -/* Tests that LIST_FOR_EACH_SAFE properly allows for deletion of the current - * element of a list. */ -static void -test_list_for_each_safe(void) -{ - enum { MAX_ELEMS = 10 }; - size_t n; - unsigned long int pattern; - - for (n = 0; n <= MAX_ELEMS; n++) { - for (pattern = 0; pattern < 1ul << n; pattern++) { - struct element elements[MAX_ELEMS]; - int values[MAX_ELEMS]; - struct list list; - struct element *e, *next; - size_t values_idx, n_remaining; - int i; - - make_list(&list, elements, values, n); - - i = 0; - values_idx = 0; - n_remaining = n; - LIST_FOR_EACH_SAFE (e, next, struct element, node, &list) { - assert(i < n); - if (pattern & (1ul << i)) { - list_remove(&e->node); - n_remaining--; - memmove(&values[values_idx], &values[values_idx + 1], - sizeof *values * (n_remaining - values_idx)); - } else { - values_idx++; - } - check_list(&list, values, n_remaining); - i++; - } - assert(i == n); - assert(&e->node == &list); - - for (i = 0; i < n; i++) { - if (pattern & (1ul << i)) { - n_remaining++; - } - } - assert(n == n_remaining); - } - } -} - -static void -run_test(void (*function)(void)) -{ - function(); - printf("."); -} - -int -main(void) -{ - run_test(test_list_construction); - run_test(test_list_for_each_safe); - printf("\n"); - return 0; -} - diff --git a/openflow/tests/test-stp-ieee802.1d-1998 b/openflow/tests/test-stp-ieee802.1d-1998 deleted file mode 100644 index f1982a03..00000000 --- a/openflow/tests/test-stp-ieee802.1d-1998 +++ /dev/null @@ -1,12 +0,0 @@ -# This is the STP example from IEEE 802.1D-1998. -bridge 0 0x42 = a b -bridge 1 0x97 = c:5 a d:5 -bridge 2 0x45 = b e -bridge 3 0x57 = b:5 e:5 -bridge 4 0x83 = a:5 e:5 -run 1000 -check 0 = root -check 1 = F F:10 F -check 2 = F:10 B -check 3 = F:5 F -check 4 = F:5 B diff --git a/openflow/tests/test-stp-ieee802.1d-2004-fig17.4 b/openflow/tests/test-stp-ieee802.1d-2004-fig17.4 deleted file mode 100644 index 1f708630..00000000 --- a/openflow/tests/test-stp-ieee802.1d-2004-fig17.4 +++ /dev/null @@ -1,31 +0,0 @@ -# This is the STP example from IEEE 802.1D-2004 figures 17.4 and 17.5. -bridge 0 0x111 = a b e c -bridge 1 0x222 = a b d f -bridge 2 0x333 = c d l j h g -bridge 3 0x444 = e f n m k i -bridge 4 0x555 = g i 0 0 -bridge 5 0x666 = h k 0 0 -bridge 6 0x777 = j m 0 0 -bridge 7 0x888 = l n 0 0 -run 1000 -check 0 = root -check 1 = F:10 B F F -check 2 = F:10 B F F F F -check 3 = F:10 B F F F F -check 4 = F:20 B F F -check 5 = F:20 B F F -check 6 = F:20 B F F -check 7 = F:20 B F F - -# Now connect two ports of bridge 7 to the same LAN. -bridge 7 = l n o o -# Same results except for bridge 7: -run 1000 -check 0 = root -check 1 = F:10 B F F -check 2 = F:10 B F F F F -check 3 = F:10 B F F F F -check 4 = F:20 B F F -check 5 = F:20 B F F -check 6 = F:20 B F F -check 7 = F:20 B F B diff --git a/openflow/tests/test-stp-ieee802.1d-2004-fig17.6 b/openflow/tests/test-stp-ieee802.1d-2004-fig17.6 deleted file mode 100644 index 6ed59177..00000000 --- a/openflow/tests/test-stp-ieee802.1d-2004-fig17.6 +++ /dev/null @@ -1,14 +0,0 @@ -# This is the STP example from IEEE 802.1D-2004 figure 17.6. -bridge 0 0x111 = a b l -bridge 1 0x222 = b c d -bridge 2 0x333 = d e f -bridge 3 0x444 = f g h -bridge 4 0x555 = j h i -bridge 5 0x666 = l j k -run 1000 -check 0 = root -check 1 = F:10 F F -check 2 = F:20 F F -check 3 = F:30 F B -check 4 = F:20 F F -check 5 = F:10 F F diff --git a/openflow/tests/test-stp-ieee802.1d-2004-fig17.7 b/openflow/tests/test-stp-ieee802.1d-2004-fig17.7 deleted file mode 100644 index daa0cdf2..00000000 --- a/openflow/tests/test-stp-ieee802.1d-2004-fig17.7 +++ /dev/null @@ -1,17 +0,0 @@ -# This is the STP example from IEEE 802.1D-2004 figure 17.7. -bridge 0 0xaa = b -bridge 1 0x111 = a b d f h g e c -bridge 2 0x222 = g h j l n m k i -run 1000 -check 0 = root -check 1 = F F:10 F F F F F F -check 2 = B F:20 F F F F F F - -# This is not the port priority change described in that figure, -# but I don't understand what port priority change would cause -# that change. -bridge 2 = g X j l n m k i -run 1000 -check 0 = root -check 1 = F F:10 F F F F F F -check 2 = F:20 D F F F F F F diff --git a/openflow/tests/test-stp-iol-io-1.1 b/openflow/tests/test-stp-iol-io-1.1 deleted file mode 100644 index 186d6c4c..00000000 --- a/openflow/tests/test-stp-iol-io-1.1 +++ /dev/null @@ -1,25 +0,0 @@ -# This test file approximates the following test from "Bridge -# Functions Consortium Spanning Tree Interoperability Test Suite -# Version 1.5": -# STP.io.1.1: Link Failure -bridge 0 0x111 = a b c -bridge 1 0x222 = a b c -run 1000 -check 0 = root -check 1 = F:10 B B -bridge 1 = 0 _ _ -run 1000 -check 0 = root -check 1 = F F:10 B -bridge 1 = X _ _ -run 1000 -check 0 = root -check 1 = D F:10 B -bridge 1 = _ 0 _ -run 1000 -check 0 = root -check 1 = D F F:10 -bridge 1 = _ X _ -run 1000 -check 0 = root -check 1 = D D F:10 diff --git a/openflow/tests/test-stp-iol-io-1.2 b/openflow/tests/test-stp-iol-io-1.2 deleted file mode 100644 index 285bbd88..00000000 --- a/openflow/tests/test-stp-iol-io-1.2 +++ /dev/null @@ -1,14 +0,0 @@ -# This test file approximates the following test from "Bridge -# Functions Consortium Spanning Tree Interoperability Test Suite -# Version 1.5": -# STP.io.1.2: Repeated Network -bridge 0 0x111 = a a -bridge 1 0x222 = a a -run 1000 -check 0 = rootid:0x111 F B -check 1 = rootid:0x111 F:10 B -bridge 1 = a^0x90 _ -run 1000 -check 0 = rootid:0x111 F B -check 1 = rootid:0x111 B F:10 - diff --git a/openflow/tests/test-stp-iol-io-1.4 b/openflow/tests/test-stp-iol-io-1.4 deleted file mode 100644 index 0065aaf5..00000000 --- a/openflow/tests/test-stp-iol-io-1.4 +++ /dev/null @@ -1,13 +0,0 @@ -# This test file approximates the following test from "Bridge -# Functions Consortium Spanning Tree Interoperability Test Suite -# Version 1.5": -# STP.io.1.4: Network Initialization -bridge 0 0x111 = a b c -bridge 1 0x222 = b d e -bridge 2 0x333 = a d f -bridge 3 0x444 = c e f -run 1000 -check 0 = root -check 1 = F:10 F F -check 2 = F:10 B F -check 3 = F:10 B B diff --git a/openflow/tests/test-stp-iol-io-1.5 b/openflow/tests/test-stp-iol-io-1.5 deleted file mode 100644 index 285d29de..00000000 --- a/openflow/tests/test-stp-iol-io-1.5 +++ /dev/null @@ -1,40 +0,0 @@ -# This test file approximates the following test from "Bridge -# Functions Consortium Spanning Tree Interoperability Test Suite -# Version 1.5": -# STP.io.1.5: Topology Change -bridge 0 0x111 = a b d c -bridge 1 0x222 = a b f e -bridge 2 0x333 = c d g h -bridge 3 0x444 = e f g h -run 1000 -check 0 = root -check 1 = F:10 B F F -check 2 = B F:10 F F -check 3 = B F:20 B B -bridge 1^0x7000 -run 1000 -check 0 = F:10 B F F -check 1 = root -check 2 = B F:20 B B -check 3 = B F:10 F F -bridge 2^0x6000 -run 1000 -check 0 = F F B F:10 -check 1 = F:20 B B B -check 2 = root -check 3 = F F F:10 B -bridge 3^0x5000 -run 1000 -check 0 = B B B F:20 -check 1 = F F B F:10 -check 2 = F F F:10 B -check 3 = root -bridge 0^0x4000 -bridge 1^0x4001 -bridge 2^0x4002 -bridge 3^0x4003 -run 1000 -check 0 = root -check 1 = F:10 B F F -check 2 = B F:10 F F -check 3 = B F:20 B B diff --git a/openflow/tests/test-stp-iol-op-1.1 b/openflow/tests/test-stp-iol-op-1.1 deleted file mode 100644 index 8432bf36..00000000 --- a/openflow/tests/test-stp-iol-op-1.1 +++ /dev/null @@ -1,7 +0,0 @@ -# This test file approximates the following tests from "Bridge -# Functions Consortium Spanning Tree Protocol Operations Test Suite -# Version 2.3": -# Test STP.op.1.1 ­ Root ID Initialized to Bridge ID -# Test STP.op.1.2 ­ Root Path Cost Initialized to Zero -bridge 0 0x123 = -check 0 = root diff --git a/openflow/tests/test-stp-iol-op-1.4 b/openflow/tests/test-stp-iol-op-1.4 deleted file mode 100644 index 6a121164..00000000 --- a/openflow/tests/test-stp-iol-op-1.4 +++ /dev/null @@ -1,8 +0,0 @@ -# This test file approximates the following test from "Bridge -# Functions Consortium Spanning Tree Protocol Operations Test Suite -# Version 2.3": -# Test STP.op.1.4 ­ All Ports Initialized to Designated Ports -bridge 0 0x123 = a b c d e f -check 0 = Li Li Li Li Li Li -run 1000 -check 0 = F F F F F F diff --git a/openflow/tests/test-stp-iol-op-3.1 b/openflow/tests/test-stp-iol-op-3.1 deleted file mode 100644 index 3e1099cb..00000000 --- a/openflow/tests/test-stp-iol-op-3.1 +++ /dev/null @@ -1,11 +0,0 @@ -# This test file approximates the following test from "Bridge -# Functions Consortium Spanning Tree Protocol Operations Test Suite -# Version 2.3": -# Test STP.op.3.1 ­ Root Bridge Selection: Root ID Values -bridge 0 0x111 = a -bridge 1 0x222 = a -check 0 = rootid:0x111 Li -check 1 = rootid:0x222 Li -run 1000 -check 0 = rootid:0x111 root -check 1 = rootid:0x111 F:10 diff --git a/openflow/tests/test-stp-iol-op-3.3 b/openflow/tests/test-stp-iol-op-3.3 deleted file mode 100644 index 2bcd45e1..00000000 --- a/openflow/tests/test-stp-iol-op-3.3 +++ /dev/null @@ -1,11 +0,0 @@ -# This test file approximates the following test from "Bridge -# Functions Consortium Spanning Tree Protocol Operations Test Suite -# Version 2.3": -# Test STP.op.3.3 ­ Root Bridge Selection: Bridge ID Values -bridge 0 0x333^0x6000 = a -bridge 1 0x222^0x7000 = b -bridge 2 0x111 = a b -run 1000 -check 0 = rootid:0x333^0x6000 root -check 1 = rootid:0x333^0x6000 F:20 -check 2 = rootid:0x333^0x6000 F:10 F diff --git a/openflow/tests/test-stp-iol-op-3.4 b/openflow/tests/test-stp-iol-op-3.4 deleted file mode 100644 index 2bcd45e1..00000000 --- a/openflow/tests/test-stp-iol-op-3.4 +++ /dev/null @@ -1,11 +0,0 @@ -# This test file approximates the following test from "Bridge -# Functions Consortium Spanning Tree Protocol Operations Test Suite -# Version 2.3": -# Test STP.op.3.3 ­ Root Bridge Selection: Bridge ID Values -bridge 0 0x333^0x6000 = a -bridge 1 0x222^0x7000 = b -bridge 2 0x111 = a b -run 1000 -check 0 = rootid:0x333^0x6000 root -check 1 = rootid:0x333^0x6000 F:20 -check 2 = rootid:0x333^0x6000 F:10 F diff --git a/openflow/tests/test-stp.c b/openflow/tests/test-stp.c deleted file mode 100644 index ddb7db7e..00000000 --- a/openflow/tests/test-stp.c +++ /dev/null @@ -1,665 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include "stp.h" -#include -#include -#include -#include -#include -#include -#include "ofpbuf.h" -#include "packets.h" - -struct bpdu { - int port_no; - void *data; - size_t size; -}; - -struct bridge { - struct test_case *tc; - int id; - bool reached; - - struct stp *stp; - - struct lan *ports[STP_MAX_PORTS]; - int n_ports; - -#define RXQ_SIZE 16 - struct bpdu rxq[RXQ_SIZE]; - int rxq_head, rxq_tail; -}; - -struct lan_conn { - struct bridge *bridge; - int port_no; -}; - -struct lan { - struct test_case *tc; - const char *name; - bool reached; - struct lan_conn conns[16]; - int n_conns; -}; - -struct test_case { - struct bridge *bridges[16]; - int n_bridges; - struct lan *lans[26]; - int n_lans; -}; - -static const char *file_name; -static int line_number; -static char line[128]; -static char *pos, *token; -static int n_warnings; - -static struct test_case * -new_test_case(void) -{ - struct test_case *tc = xmalloc(sizeof *tc); - tc->n_bridges = 0; - tc->n_lans = 0; - return tc; -} - -static void -send_bpdu(struct ofpbuf *pkt, int port_no, void *b_) -{ - struct bridge *b = b_; - struct lan *lan; - - assert(port_no < b->n_ports); - lan = b->ports[port_no]; - if (lan) { - const void *data = pkt->l3; - size_t size = (char *) ofpbuf_tail(pkt) - (char *) data; - int i; - - for (i = 0; i < lan->n_conns; i++) { - struct lan_conn *conn = &lan->conns[i]; - if (conn->bridge != b || conn->port_no != port_no) { - struct bridge *dst = conn->bridge; - struct bpdu *bpdu = &dst->rxq[dst->rxq_head++ % RXQ_SIZE]; - assert(dst->rxq_head - dst->rxq_tail <= RXQ_SIZE); - bpdu->data = xmemdup(data, size); - bpdu->size = size; - bpdu->port_no = conn->port_no; - } - } - } - ofpbuf_delete(pkt); -} - -static struct bridge * -new_bridge(struct test_case *tc, int id) -{ - struct bridge *b = xmalloc(sizeof *b); - char name[16]; - b->tc = tc; - b->id = id; - snprintf(name, sizeof name, "stp%x", id); - b->stp = stp_create(name, id, send_bpdu, b); - assert(tc->n_bridges < ARRAY_SIZE(tc->bridges)); - b->n_ports = 0; - b->rxq_head = b->rxq_tail = 0; - tc->bridges[tc->n_bridges++] = b; - return b; -} - -static struct lan * -new_lan(struct test_case *tc, const char *name) -{ - struct lan *lan = xmalloc(sizeof *lan); - lan->tc = tc; - lan->name = xstrdup(name); - lan->n_conns = 0; - assert(tc->n_lans < ARRAY_SIZE(tc->lans)); - tc->lans[tc->n_lans++] = lan; - return lan; -} - -static void -reconnect_port(struct bridge *b, int port_no, struct lan *new_lan) -{ - struct lan *old_lan; - int j; - - assert(port_no < b->n_ports); - old_lan = b->ports[port_no]; - if (old_lan == new_lan) { - return; - } - - /* Disconnect from old_lan. */ - if (old_lan) { - for (j = 0; j < old_lan->n_conns; j++) { - struct lan_conn *c = &old_lan->conns[j]; - if (c->bridge == b && c->port_no == port_no) { - memmove(c, c + 1, sizeof *c * (old_lan->n_conns - j - 1)); - old_lan->n_conns--; - break; - } - } - } - - /* Connect to new_lan. */ - b->ports[port_no] = new_lan; - if (new_lan) { - int conn_no = new_lan->n_conns++; - assert(conn_no < ARRAY_SIZE(new_lan->conns)); - new_lan->conns[conn_no].bridge = b; - new_lan->conns[conn_no].port_no = port_no; - } -} - -static void -new_port(struct bridge *b, struct lan *lan, int path_cost) -{ - int port_no = b->n_ports++; - struct stp_port *p = stp_get_port(b->stp, port_no); - assert(port_no < ARRAY_SIZE(b->ports)); - b->ports[port_no] = NULL; - stp_port_set_path_cost(p, path_cost); - stp_port_enable(p); - reconnect_port(b, port_no, lan); -} - -static void -dump(struct test_case *tc) -{ - int i; - - for (i = 0; i < tc->n_bridges; i++) { - struct bridge *b = tc->bridges[i]; - struct stp *stp = b->stp; - int j; - - printf("%s:", stp_get_name(stp)); - if (stp_is_root_bridge(stp)) { - printf(" root"); - } - printf("\n"); - for (j = 0; j < b->n_ports; j++) { - struct stp_port *p = stp_get_port(stp, j); - enum stp_state state = stp_port_get_state(p); - - printf("\tport %d", j); - if (b->ports[j]) { - printf(" (lan %s)", b->ports[j]->name); - } else { - printf(" (disconnected)"); - } - printf(": %s", stp_state_name(state)); - if (p == stp_get_root_port(stp)) { - printf(" (root port, root_path_cost=%u)", stp_get_root_path_cost(stp)); - } - printf("\n"); - } - } -} - -static void dump_lan_tree(struct test_case *, struct lan *, int level); - -static void -dump_bridge_tree(struct test_case *tc, struct bridge *b, int level) -{ - int i; - - if (b->reached) { - return; - } - b->reached = true; - for (i = 0; i < level; i++) { - printf("\t"); - } - printf("%s\n", stp_get_name(b->stp)); - for (i = 0; i < b->n_ports; i++) { - struct lan *lan = b->ports[i]; - struct stp_port *p = stp_get_port(b->stp, i); - if (stp_port_get_state(p) == STP_FORWARDING && lan) { - dump_lan_tree(tc, lan, level + 1); - } - } -} - -static void -dump_lan_tree(struct test_case *tc, struct lan *lan, int level) -{ - int i; - - if (lan->reached) { - return; - } - lan->reached = true; - for (i = 0; i < level; i++) { - printf("\t"); - } - printf("%s\n", lan->name); - for (i = 0; i < lan->n_conns; i++) { - struct bridge *b = lan->conns[i].bridge; - dump_bridge_tree(tc, b, level + 1); - } -} - -static void -tree(struct test_case *tc) -{ - int i; - - for (i = 0; i < tc->n_bridges; i++) { - struct bridge *b = tc->bridges[i]; - b->reached = false; - } - for (i = 0; i < tc->n_lans; i++) { - struct lan *lan = tc->lans[i]; - lan->reached = false; - } - for (i = 0; i < tc->n_bridges; i++) { - struct bridge *b = tc->bridges[i]; - struct stp *stp = b->stp; - if (stp_is_root_bridge(stp)) { - dump_bridge_tree(tc, b, 0); - } - } -} - -static void -simulate(struct test_case *tc, int granularity) -{ - int time; - - for (time = 0; time < 1000 * 180; time += granularity) { - int round_trips; - int i; - - for (i = 0; i < tc->n_bridges; i++) { - stp_tick(tc->bridges[i]->stp, granularity); - } - for (round_trips = 0; round_trips < granularity; round_trips++) { - bool any = false; - for (i = 0; i < tc->n_bridges; i++) { - struct bridge *b = tc->bridges[i]; - for (; b->rxq_tail != b->rxq_head; b->rxq_tail++) { - struct bpdu *bpdu = &b->rxq[b->rxq_tail % RXQ_SIZE]; - stp_received_bpdu(stp_get_port(b->stp, bpdu->port_no), - bpdu->data, bpdu->size); - any = true; - } - } - if (!any) { - break; - } - } - } -} - -static void -err(const char *message, ...) - PRINTF_FORMAT(1, 2) - NO_RETURN; - -static void -err(const char *message, ...) -{ - va_list args; - - fprintf(stderr, "%s:%d:%td: ", file_name, line_number, pos - line); - va_start(args, message); - vfprintf(stderr, message, args); - va_end(args); - putc('\n', stderr); - - exit(EXIT_FAILURE); -} - -static void -warn(const char *message, ...) - PRINTF_FORMAT(1, 2); - -static void -warn(const char *message, ...) -{ - va_list args; - - fprintf(stderr, "%s:%d: ", file_name, line_number); - va_start(args, message); - vfprintf(stderr, message, args); - va_end(args); - putc('\n', stderr); - - n_warnings++; -} - -static bool -get_token(void) -{ - char *start; - - while (isspace((unsigned char) *pos)) { - pos++; - } - if (*pos == '\0') { - token = NULL; - return false; - } - - start = pos; - if (isalpha((unsigned char) *pos)) { - while (isalpha((unsigned char) *++pos)) { - continue; - } - } else if (isdigit((unsigned char) *pos)) { - if (*pos == '0' && (pos[1] == 'x' || pos[1] == 'X')) { - pos += 2; - while (isxdigit((unsigned char) *pos)) { - pos++; - } - } else { - while (isdigit((unsigned char) *++pos)) { - continue; - } - } - } else { - pos++; - } - - free(token); - token = xmemdup0(start, pos - start); - return true; -} - -static bool -get_int(int *intp) -{ - char *save_pos = pos; - if (token && isdigit((unsigned char) *token)) { - *intp = strtol(token, NULL, 0); - get_token(); - return true; - } else { - pos = save_pos; - return false; - } -} - -static bool -match(const char *want) -{ - if (token && !strcmp(want, token)) { - get_token(); - return true; - } else { - return false; - } -} - -static int -must_get_int(void) -{ - int x; - if (!get_int(&x)) { - err("expected integer"); - } - return x; -} - -static void -must_match(const char *want) -{ - if (!match(want)) { - err("expected \"%s\"", want); - } -} - -int -main(int argc, char *argv[]) -{ - struct test_case *tc; - FILE *input_file; - int i; - - if (argc != 2) { - ofp_fatal(0, "usage: test-stp INPUT.STP\n"); - } - file_name = argv[1]; - - input_file = fopen(file_name, "r"); - if (!input_file) { - ofp_fatal(errno, "error opening \"%s\"", file_name); - } - - tc = new_test_case(); - for (i = 0; i < 26; i++) { - char name[2]; - name[0] = 'a' + i; - name[1] = '\0'; - new_lan(tc, name); - } - - for (line_number = 1; fgets(line, sizeof line, input_file); - line_number++) - { - char *newline, *hash; - - newline = strchr(line, '\n'); - if (newline) { - *newline = '\0'; - } - hash = strchr(line, '#'); - if (hash) { - *hash = '\0'; - } - - pos = line; - if (!get_token()) { - continue; - } - if (match("bridge")) { - struct bridge *bridge; - int bridge_no, port_no; - - bridge_no = must_get_int(); - if (bridge_no < tc->n_bridges) { - bridge = tc->bridges[bridge_no]; - } else if (bridge_no == tc->n_bridges) { - bridge = new_bridge(tc, must_get_int()); - } else { - err("bridges must be numbered consecutively from 0"); - } - if (match("^")) { - stp_set_bridge_priority(bridge->stp, must_get_int()); - } - - if (match("=")) { - for (port_no = 0; port_no < STP_MAX_PORTS; port_no++) { - struct stp_port *p = stp_get_port(bridge->stp, port_no); - if (!token || match("X")) { - stp_port_disable(p); - } else if (match("_")) { - /* Nothing to do. */ - } else { - struct lan *lan; - int path_cost; - - if (!strcmp(token, "0")) { - lan = NULL; - } else if (strlen(token) == 1 && islower(*token)) { - lan = tc->lans[*token - 'a']; - } else { - err("%s is not a valid LAN name " - "(0 or a lowercase letter)", token); - } - get_token(); - - path_cost = match(":") ? must_get_int() : 10; - if (port_no < bridge->n_ports) { - stp_port_set_path_cost(p, path_cost); - stp_port_enable(p); - reconnect_port(bridge, port_no, lan); - } else if (port_no == bridge->n_ports) { - new_port(bridge, lan, path_cost); - } else { - err("ports must be numbered consecutively"); - } - if (match("^")) { - stp_port_set_priority(p, must_get_int()); - } - } - } - } - } else if (match("run")) { - simulate(tc, must_get_int()); - } else if (match("dump")) { - dump(tc); - } else if (match("tree")) { - tree(tc); - } else if (match("check")) { - struct bridge *b; - struct stp *stp; - int bridge_no, port_no; - - bridge_no = must_get_int(); - if (bridge_no >= tc->n_bridges) { - err("no bridge numbered %d", bridge_no); - } - b = tc->bridges[bridge_no]; - stp = b->stp; - - must_match("="); - - if (match("rootid")) { - uint64_t rootid; - must_match(":"); - rootid = must_get_int(); - if (match("^")) { - rootid |= (uint64_t) must_get_int() << 48; - } else { - rootid |= UINT64_C(0x8000) << 48; - } - if (stp_get_designated_root(stp) != rootid) { - warn("%s: root %"PRIx64", not %"PRIx64, - stp_get_name(stp), stp_get_designated_root(stp), - rootid); - } - } - - if (match("root")) { - if (stp_get_root_path_cost(stp)) { - warn("%s: root path cost of root is %u but should be 0", - stp_get_name(stp), stp_get_root_path_cost(stp)); - } - if (!stp_is_root_bridge(stp)) { - warn("%s: root is %"PRIx64", not %"PRIx64, - stp_get_name(stp), - stp_get_designated_root(stp), stp_get_bridge_id(stp)); - } - for (port_no = 0; port_no < b->n_ports; port_no++) { - struct stp_port *p = stp_get_port(stp, port_no); - enum stp_state state = stp_port_get_state(p); - if (!(state & (STP_DISABLED | STP_FORWARDING))) { - warn("%s: root port %d in state %s", - stp_get_name(b->stp), port_no, - stp_state_name(state)); - } - } - } else { - for (port_no = 0; port_no < STP_MAX_PORTS; port_no++) { - struct stp_port *p = stp_get_port(stp, port_no); - enum stp_state state; - if (token == NULL || match("D")) { - state = STP_DISABLED; - } else if (match("B")) { - state = STP_BLOCKING; - } else if (match("Li")) { - state = STP_LISTENING; - } else if (match("Le")) { - state = STP_LEARNING; - } else if (match("F")) { - state = STP_FORWARDING; - } else if (match("_")) { - continue; - } else { - err("unknown port state %s", token); - } - if (stp_port_get_state(p) != state) { - warn("%s port %d: state is %s but should be %s", - stp_get_name(stp), port_no, - stp_state_name(stp_port_get_state(p)), - stp_state_name(state)); - } - if (state == STP_FORWARDING) { - struct stp_port *root_port = stp_get_root_port(stp); - if (match(":")) { - int root_path_cost = must_get_int(); - if (p != root_port) { - warn("%s: port %d is not the root port", - stp_get_name(stp), port_no); - if (!root_port) { - warn("%s: (there is no root port)", - stp_get_name(stp)); - } else { - warn("%s: (port %d is the root port)", - stp_get_name(stp), - stp_port_no(root_port)); - } - } else if (root_path_cost - != stp_get_root_path_cost(stp)) { - warn("%s: root path cost is %u, should be %d", - stp_get_name(stp), - stp_get_root_path_cost(stp), - root_path_cost); - } - } else if (p == root_port) { - warn("%s: port %d is the root port but " - "not expected to be", - stp_get_name(stp), port_no); - } - } - } - } - if (n_warnings) { - exit(EXIT_FAILURE); - } - } - if (get_token()) { - err("trailing garbage on line"); - } - } - - return 0; -} diff --git a/openflow/tests/test-stp.sh b/openflow/tests/test-stp.sh deleted file mode 100755 index fd6acf54..00000000 --- a/openflow/tests/test-stp.sh +++ /dev/null @@ -1,7 +0,0 @@ -#! /bin/sh -set -e -progress= -for d in ${stp_files}; do - echo "Testing $d..." - $SUPERVISOR ./tests/test-stp ${srcdir}/$d -done diff --git a/openflow/tests/test-type-props.c b/openflow/tests/test-type-props.c deleted file mode 100644 index 67dabae8..00000000 --- a/openflow/tests/test-type-props.c +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include "type-props.h" -#include -#include - -#define MUST_SUCCEED(EXPRESSION) \ - if (!(EXPRESSION)) { \ - fprintf(stderr, "%s:%d: %s failed\n", \ - __FILE__, __LINE__, #EXPRESSION); \ - exit(EXIT_FAILURE); \ - } - -#define TEST_TYPE(type, minimum, maximum, is_signed) \ - MUST_SUCCEED(TYPE_IS_INTEGER(type)); \ - MUST_SUCCEED(TYPE_IS_SIGNED(type) == is_signed); \ - MUST_SUCCEED(TYPE_MAXIMUM(type) == maximum); \ - MUST_SUCCEED(TYPE_MINIMUM(type) == minimum); - -int -main (void) -{ - TEST_TYPE(char, CHAR_MIN, CHAR_MAX, (CHAR_MIN < 0)); - - TEST_TYPE(signed char, SCHAR_MIN, SCHAR_MAX, 1); - TEST_TYPE(short int, SHRT_MIN, SHRT_MAX, 1); - TEST_TYPE(int, INT_MIN, INT_MAX, 1); - TEST_TYPE(long int, LONG_MIN, LONG_MAX, 1); - TEST_TYPE(long long int, LLONG_MIN, LLONG_MAX, 1); - - TEST_TYPE(unsigned char, 0, UCHAR_MAX, 0); - TEST_TYPE(unsigned short int, 0, USHRT_MAX, 0); - TEST_TYPE(unsigned int, 0, UINT_MAX, 0); - TEST_TYPE(unsigned long int, 0, ULONG_MAX, 0); - TEST_TYPE(unsigned long long int, 0, ULLONG_MAX, 0); - - MUST_SUCCEED(!(TYPE_IS_INTEGER(float))); - MUST_SUCCEED(!(TYPE_IS_INTEGER(double))); - MUST_SUCCEED(!(TYPE_IS_INTEGER(long double))); - - return 0; -} diff --git a/openflow/third-party/.gitignore b/openflow/third-party/.gitignore deleted file mode 100644 index b336cc7c..00000000 --- a/openflow/third-party/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/Makefile -/Makefile.in diff --git a/openflow/third-party/README b/openflow/third-party/README deleted file mode 100644 index 15f4d647..00000000 --- a/openflow/third-party/README +++ /dev/null @@ -1,35 +0,0 @@ -This directory contains third-party software that may be useful for -debugging. - -tcpdump -------- -The "ofp-tcpdump.patch" patch adds the ability to parse OpenFlow -messages to tcpdump. These instructions assume that tcpdump 3.9.8 -is going to be used, but it should work with other versions that are not -substantially different. To begin, download tcpdump and apply the -patch: - - wget http://www.tcpdump.org/release/tcpdump-3.9.8.tar.gz - tar xzf tcpdump-3.9.8.tar.gz - ln -s tcpdump-3.9.8 tcpdump - patch -p0 < ofp-tcpdump.patch - -Then build the new version of tcpdump: - - cd tcpdump - ./configure - make - -Clearly, tcpdump can only parse unencrypted packets, so you will need to -connect the controller and datapath using plain TCP. To look at the -traffic, tcpdump will be started in a manner similar to the following: - - sudo ./tcpdump -s0 -i eth0 port 6633 - -The "-s0" flag indicates that tcpdump should capture the entire packet. -If the OpenFlow message is not received in its entirety, "[|openflow]" will -be printed instead of the OpenFlow message contents. - -The verbosity of the output may be increased by adding additional "-v" -flags. If "-vvv" is used, the raw OpenFlow data is also printed in -hex and ASCII. diff --git a/openflow/third-party/automake.mk b/openflow/third-party/automake.mk deleted file mode 100644 index 02636bb5..00000000 --- a/openflow/third-party/automake.mk +++ /dev/null @@ -1,3 +0,0 @@ -EXTRA_DIST += \ - third-party/README \ - third-party/ofp-tcpdump.patch diff --git a/openflow/third-party/ofp-tcpdump.patch b/openflow/third-party/ofp-tcpdump.patch deleted file mode 100644 index 3f2cc57b..00000000 --- a/openflow/third-party/ofp-tcpdump.patch +++ /dev/null @@ -1,119 +0,0 @@ -diff -rNu tcpdump/interface.h tcpdump/interface.h ---- tcpdump/interface.h 2007-06-13 18:03:20.000000000 -0700 -+++ tcpdump/interface.h 2008-02-06 15:06:30.000000000 -0800 -@@ -148,7 +148,8 @@ - - extern const char *dnaddr_string(u_short); - --extern void error(const char *, ...) -+#define error(fmt, args...) tcpdump_error(fmt, ## args) -+extern void tcpdump_error(const char *, ...) - __attribute__((noreturn, format (printf, 1, 2))); - extern void warning(const char *, ...) __attribute__ ((format (printf, 1, 2))); - -@@ -176,6 +177,7 @@ - extern void hex_print_with_offset(const char *, const u_char *, u_int, u_int); - extern void hex_print(const char *, const u_char *, u_int); - extern void telnet_print(const u_char *, u_int); -+extern void openflow_print(const u_char *, u_int); - extern int ether_encap_print(u_short, const u_char *, u_int, u_int, u_short *); - extern int llc_print(const u_char *, u_int, u_int, const u_char *, - const u_char *, u_short *); -diff -rNu tcpdump/Makefile.in tcpdump/Makefile.in ---- tcpdump/Makefile.in 2007-09-25 18:59:52.000000000 -0700 -+++ tcpdump/Makefile.in 2008-02-07 11:46:03.000000000 -0800 -@@ -49,10 +49,10 @@ - CFLAGS = $(CCOPT) $(DEFS) $(INCLS) - - # Standard LDFLAGS --LDFLAGS = @LDFLAGS@ -+LDFLAGS = @LDFLAGS@ -L../../lib - - # Standard LIBS --LIBS = @LIBS@ -+LIBS = @LIBS@ -lopenflow - - INSTALL = @INSTALL@ - INSTALL_PROGRAM = @INSTALL_PROGRAM@ -@@ -87,7 +87,8 @@ - print-slow.c print-snmp.c print-stp.c print-sunatm.c print-sunrpc.c \ - print-symantec.c print-syslog.c print-tcp.c print-telnet.c print-tftp.c \ - print-timed.c print-token.c print-udp.c print-vjc.c print-vrrp.c \ -- print-wb.c print-zephyr.c setsignal.c tcpdump.c util.c -+ print-wb.c print-zephyr.c setsignal.c tcpdump.c util.c \ -+ print-openflow.c - - LOCALSRC = @LOCALSRC@ - GENSRC = version.c -diff -rNu tcpdump/print-openflow.c tcpdump/print-openflow.c ---- tcpdump/print-openflow.c 1969-12-31 16:00:00.000000000 -0800 -+++ tcpdump/print-openflow.c 2008-02-07 11:29:01.000000000 -0800 -@@ -0,0 +1,46 @@ -+/* Copyright (C) 2007, 2008 Board of Trustees, Leland Stanford Jr. University. -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to -+ * deal in the Software without restriction, including without limitation the -+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -+ * sell copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -+ * IN THE SOFTWARE. -+ */ -+ -+ -+#ifdef HAVE_CONFIG_H -+#include "config.h" -+#endif -+ -+#include -+ -+#include "interface.h" -+#include "../../include/openflow/openflow.h" -+#include "../../include/ofp-print.h" -+ -+void -+openflow_print(const u_char *sp, u_int length) -+{ -+ const struct ofp_header *ofp = (struct ofp_header *)sp; -+ -+ if (!TTEST2(*sp, ntohs(ofp->length))) -+ goto trunc; -+ -+ ofp_print(stdout, sp, length, vflag); -+ return; -+ -+trunc: -+ printf("[|openflow]"); -+} -diff -rNu tcpdump/print-tcp.c tcpdump/print-tcp.c ---- tcpdump/print-tcp.c 2006-09-19 12:07:57.000000000 -0700 -+++ tcpdump/print-tcp.c 2008-02-07 13:07:58.000000000 -0800 -@@ -52,6 +52,8 @@ - - #include "nameser.h" - -+#include "../../include/openflow.h" -+ - #ifdef HAVE_LIBCRYPTO - #include - -@@ -680,7 +682,8 @@ - } - else if (length > 0 && (sport == LDP_PORT || dport == LDP_PORT)) { - ldp_print(bp, length); -- } -+ } else if (sport == OFP_TCP_PORT || dport == OFP_TCP_PORT) -+ openflow_print(bp, length); - } - return; - bad: diff --git a/openflow/udatapath/.dirstamp b/openflow/udatapath/.dirstamp deleted file mode 100644 index e69de29b..00000000 diff --git a/openflow/udatapath/.gitignore b/openflow/udatapath/.gitignore deleted file mode 100644 index e4272b0b..00000000 --- a/openflow/udatapath/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/Makefile -/Makefile.in -/ofdatapath -/ofdatapath.8 diff --git a/openflow/udatapath/automake.mk b/openflow/udatapath/automake.mk deleted file mode 100644 index b4b4d8e6..00000000 --- a/openflow/udatapath/automake.mk +++ /dev/null @@ -1,75 +0,0 @@ -# -# Build udatapath as binary -# - -bin_PROGRAMS += udatapath/ofdatapath -man_MANS += udatapath/ofdatapath.8 - -udatapath_ofdatapath_SOURCES = \ - udatapath/chain.c \ - udatapath/chain.h \ - udatapath/crc32.c \ - udatapath/crc32.h \ - udatapath/datapath.c \ - udatapath/datapath.h \ - udatapath/dp_act.c \ - udatapath/dp_act.h \ - udatapath/of_ext_msg.c \ - udatapath/of_ext_msg.h \ - udatapath/udatapath.c \ - udatapath/private-msg.c \ - udatapath/private-msg.h \ - udatapath/switch-flow.c \ - udatapath/switch-flow.h \ - udatapath/table.h \ - udatapath/table-hash.c \ - udatapath/table-linear.c - -udatapath_ofdatapath_LDADD = lib/libopenflow.a $(SSL_LIBS) $(FAULT_LIBS) -udatapath_ofdatapath_CPPFLAGS = $(AM_CPPFLAGS) - -EXTRA_DIST += udatapath/ofdatapath.8.in -DISTCLEANFILES += udatapath/ofdatapath.8 - -if BUILD_HW_LIBS - -# Options for each platform -if NF2 -udatapath_ofdatapath_LDADD += hw-lib/libnf2.a -udatapath_ofdatapath_CPPFLAGS += -DOF_HW_PLAT -DUSE_NETDEV -g -noinst_LIBRARIES += hw-lib/libnf2.a -endif - -endif - -if BUILD_HW_LIBS -# -# Build udatapath as a library -# - -noinst_LIBRARIES += udatapath/libudatapath.a - -udatapath_libudatapath_a_SOURCES = \ - udatapath/chain.c \ - udatapath/chain.h \ - udatapath/crc32.c \ - udatapath/crc32.h \ - udatapath/datapath.c \ - udatapath/datapath.h \ - udatapath/dp_act.c \ - udatapath/dp_act.h \ - udatapath/of_ext_msg.c \ - udatapath/of_ext_msg.h \ - udatapath/udatapath.c \ - udatapath/private-msg.c \ - udatapath/private-msg.h \ - udatapath/switch-flow.c \ - udatapath/switch-flow.h \ - udatapath/table.h \ - udatapath/table-hash.c \ - udatapath/table-linear.c - -udatapath_libudatapath_a_CPPFLAGS = $(AM_CPPFLAGS) -udatapath_libudatapath_a_CPPFLAGS += -DOF_HW_PLAT -DUDATAPATH_AS_LIB -g - -endif diff --git a/openflow/udatapath/chain.c b/openflow/udatapath/chain.c deleted file mode 100644 index b9dc39c0..00000000 --- a/openflow/udatapath/chain.c +++ /dev/null @@ -1,261 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include "chain.h" -#include -#include -#include -#include "switch-flow.h" -#include "table.h" -#include "datapath.h" - -#if defined(OF_HW_PLAT) -#include -#endif - -#define THIS_MODULE VLM_chain -#include "vlog.h" - -/* Attempts to append 'table' to the set of tables in 'chain'. Returns 0 or - * negative error. If 'table' is null it is assumed that table creation failed - * due to out-of-memory. */ -static int add_table(struct sw_chain *chain, struct sw_table *table, int emerg) -{ - if (table == NULL) - return -ENOMEM; - if (chain->n_tables >= CHAIN_MAX_TABLES) { - VLOG_ERR("too many tables in chain\n"); - table->destroy(table); - return -ENOBUFS; - } - if (emerg) - chain->emerg_table = table; - else - chain->tables[chain->n_tables++] = table; - return 0; -} - -/* Creates and returns a new chain. Returns NULL if the chain cannot be - * created. */ -struct sw_chain *chain_create(struct datapath *dp) -{ - struct sw_chain *chain = calloc(1, sizeof *chain); - if (chain == NULL) - return NULL; - - chain->dp = dp; -#if defined(OF_HW_PLAT) - if (dp && dp->hw_drv) { - if (add_table(chain, (struct sw_table *)dp->hw_drv, 0) != 0) { - VLOG_ERR("Could not attach HW table to chain\n"); - } - } -#endif - if (add_table(chain, table_hash2_create(0x1EDC6F41, TABLE_HASH_MAX_FLOWS, - 0x741B8CD7, TABLE_HASH_MAX_FLOWS), - 0) - || add_table(chain, table_linear_create(TABLE_LINEAR_MAX_FLOWS), 0) - || add_table(chain, table_linear_create(TABLE_LINEAR_MAX_FLOWS), 1)) { - chain_destroy(chain); - return NULL; - } - - return chain; -} - -/* Searches 'chain' for a flow matching 'key', which must not have any wildcard - * fields. Returns the flow if successful, otherwise a null pointer. */ -struct sw_flow * -chain_lookup(struct sw_chain *chain, const struct sw_flow_key *key, int emerg) -{ - int i; - - assert(!key->wildcards); - - if (emerg) { - struct sw_table *t = chain->emerg_table; - struct sw_flow *flow = t->lookup(t, key); - t->n_lookup++; - if (flow) { - t->n_matched++; - return flow; - } - } else { - for (i = 0; i < chain->n_tables; i++) { - struct sw_table *t = chain->tables[i]; - struct sw_flow *flow = t->lookup(t, key); - t->n_lookup++; - if (flow) { - t->n_matched++; - return flow; - } - } - } - - return NULL; -} - -/* Inserts 'flow' into 'chain', replacing any duplicate flow. Returns 0 if - * successful or a negative error. - * - * If successful, 'flow' becomes owned by the chain, otherwise it is retained - * by the caller. */ -int -chain_insert(struct sw_chain *chain, struct sw_flow *flow, int emerg) -{ - int i; - - if (emerg) { - struct sw_table *t = chain->emerg_table; - if (t->insert(t, flow)) - return 0; - } else { - for (i = 0; i < chain->n_tables; i++) { - struct sw_table *t = chain->tables[i]; - if (t->insert(t, flow)) - return 0; - } - } - - return -ENOBUFS; -} - -/* Modifies actions in 'chain' that match 'key'. If 'strict' set, wildcards - * and priority must match. Returns the number of flows that were modified. - * - * Expensive in the general case as currently implemented, since it requires - * iterating through the entire contents of each table for keys that contain - * wildcards. Relatively cheap for fully specified keys. */ -int -chain_modify(struct sw_chain *chain, const struct sw_flow_key *key, - uint16_t priority, int strict, - const struct ofp_action_header *actions, size_t actions_len, - int emerg) -{ - int count = 0; - int i; - - if (emerg) { - struct sw_table *t = chain->emerg_table; - count += t->modify(t, key, priority, strict, actions, actions_len); - } else { - for (i = 0; i < chain->n_tables; i++) { - struct sw_table *t = chain->tables[i]; - count += t->modify(t, key, priority, strict, actions, actions_len); - } - } - - return count; -} - -/* Checks whether the chain has an entry with the same priority which conflicts - * with 'key'. If 'strict' set, wildcards should also match. If 'strict' is not - * set, comparison is done 'module wildcards'. - * - * Returns 'true' if such an entry exists, 'false' otherwise. */ -int -chain_has_conflict(struct sw_chain *chain, const struct sw_flow_key *key, - uint16_t priority, int strict) -{ - int i; - - for (i = 0; i < chain->n_tables; i++) { - struct sw_table *t = chain->tables[i]; - if (t->has_conflict(t, key, priority, strict)) { - return true; - } - } - - return false; -} - -/* Deletes from 'chain' any and all flows that match 'key'. If 'out_port' - * is not OFPP_NONE, then matching entries must have that port as an - * argument for an output action. If 'strict" is set, then wildcards and - * priority must match. Returns the number of flows that were deleted. - * - * Expensive in the general case as currently implemented, since it requires - * iterating through the entire contents of each table for keys that contain - * wildcards. Relatively cheap for fully specified keys. */ -int -chain_delete(struct sw_chain *chain, const struct sw_flow_key *key, - uint16_t out_port, uint16_t priority, int strict, int emerg) -{ - int count = 0; - int i; - - if (emerg) { - struct sw_table *t = chain->emerg_table; - count += t->delete(chain->dp, t, key, out_port, priority, strict); - } else { - for (i = 0; i < chain->n_tables; i++) { - struct sw_table *t = chain->tables[i]; - count += t->delete(chain->dp, t, key, out_port, priority, strict); - } - } - - return count; -} - -/* Deletes timed-out flow entries from all the tables in 'chain' and appends - * the deleted flows to 'deleted'. - * - * Expensive as currently implemented, since it iterates through the entire - * contents of each table. */ -void -chain_timeout(struct sw_chain *chain, struct list *deleted) -{ - int i; - - for (i = 0; i < chain->n_tables; i++) { - struct sw_table *t = chain->tables[i]; - t->timeout(t, deleted); - } -} - -/* Destroys 'chain', which must not have any users. */ -void -chain_destroy(struct sw_chain *chain) -{ - int i; - struct sw_table *t; - - for (i = 0; i < chain->n_tables; i++) { - t = chain->tables[i]; - t->destroy(t); - } - t = chain->emerg_table; - t->destroy(t); - free(chain); -} diff --git a/openflow/udatapath/chain.h b/openflow/udatapath/chain.h deleted file mode 100644 index fb4e9c37..00000000 --- a/openflow/udatapath/chain.h +++ /dev/null @@ -1,74 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#ifndef CHAIN_H -#define CHAIN_H 1 - -#include -#include - -struct sw_flow; -struct sw_flow_key; -struct ofp_action_header; -struct list; -struct datapath; - -#define TABLE_LINEAR_MAX_FLOWS 100 -#define TABLE_HASH_MAX_FLOWS 65536 -#define TABLE_MAC_MAX_FLOWS 1024 -#define TABLE_MAC_NUM_BUCKETS 1024 - -/* Set of tables chained together in sequence from cheap to expensive. */ -#define CHAIN_MAX_TABLES 4 -struct sw_chain { - int n_tables; /* Number of working tables, not includes - * protection (emergency) table. */ - struct sw_table *tables[CHAIN_MAX_TABLES]; - struct sw_table *emerg_table; - - struct datapath *dp; -}; - -struct sw_chain *chain_create(struct datapath *); -struct sw_flow *chain_lookup(struct sw_chain *, const struct sw_flow_key *, int); -int chain_insert(struct sw_chain *, struct sw_flow *, int); -int chain_modify(struct sw_chain *, const struct sw_flow_key *, - uint16_t, int, const struct ofp_action_header *, size_t, int); -int chain_has_conflict(struct sw_chain *, const struct sw_flow_key *, - uint16_t, int); -int chain_delete(struct sw_chain *, const struct sw_flow_key *, uint16_t, - uint16_t, int, int); -void chain_timeout(struct sw_chain *, struct list *deleted); -void chain_destroy(struct sw_chain *); - -#endif /* chain.h */ diff --git a/openflow/udatapath/crc32.c b/openflow/udatapath/crc32.c deleted file mode 100644 index f6c2c0b3..00000000 --- a/openflow/udatapath/crc32.c +++ /dev/null @@ -1,68 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include "crc32.h" - -void -crc32_init(struct crc32 *crc, unsigned int polynomial) -{ - int i; - - for (i = 0; i < CRC32_TABLE_SIZE; ++i) { - unsigned int reg = i << 24; - int j; - for (j = 0; j < CRC32_TABLE_BITS; j++) { - int topBit = (reg & 0x80000000) != 0; - reg <<= 1; - if (topBit) - reg ^= polynomial; - } - crc->table[i] = reg; - } -} - -unsigned int -crc32_calculate(const struct crc32 *crc, const void *data_, size_t n_bytes) -{ - const uint8_t *data = data_; - unsigned int result = 0; - size_t i; - - for (i = 0; i < n_bytes; i++) { - unsigned int top = result >> 24; - top ^= data[i]; - result = (result << 8) ^ crc->table[top]; - } - return result; -} diff --git a/openflow/udatapath/crc32.h b/openflow/udatapath/crc32.h deleted file mode 100644 index 355aefdf..00000000 --- a/openflow/udatapath/crc32.h +++ /dev/null @@ -1,50 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#ifndef CRC32_H -#define CRC32_H 1 - -#include -#include - -#define CRC32_TABLE_BITS 8 -#define CRC32_TABLE_SIZE (1u << CRC32_TABLE_BITS) - -struct crc32 { - unsigned int table[CRC32_TABLE_SIZE]; -}; - -void crc32_init(struct crc32 *, unsigned int polynomial); -unsigned int crc32_calculate(const struct crc32 *, const void *, size_t); - -#endif /* crc32.h */ diff --git a/openflow/udatapath/datapath.c b/openflow/udatapath/datapath.c deleted file mode 100644 index 5254b771..00000000 --- a/openflow/udatapath/datapath.c +++ /dev/null @@ -1,2375 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include "datapath.h" -#include -#include -#include -#include -#include -#include -#include -#include "chain.h" -#include "csum.h" -#include "flow.h" -#include "ofpbuf.h" -#include "openflow/openflow.h" -#include "openflow/nicira-ext.h" -#include "openflow/private-ext.h" -#include "openflow/openflow-ext.h" -#include "packets.h" -#include "poll-loop.h" -#include "rconn.h" -#include "stp.h" -#include "switch-flow.h" -#include "table.h" -#include "vconn.h" -#include "xtoxll.h" -#include "private-msg.h" -#include "of_ext_msg.h" -#include "dp_act.h" - -#define THIS_MODULE VLM_datapath -#include "vlog.h" - -#if defined(OF_HW_PLAT) -#include -#include -#endif - -#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) -/* Queue to decouple receive packet thread from rconn control thread */ -/* Could make mutex per-DP */ -static pthread_mutex_t pkt_q_mutex = PTHREAD_MUTEX_INITIALIZER; -#define PKT_Q_LOCK pthread_mutex_lock(&pkt_q_mutex) -#define PKT_Q_UNLOCK pthread_mutex_unlock(&pkt_q_mutex) - -static void -enqueue_pkt(struct datapath *dp, struct ofpbuf *buffer, of_port_t port_no, - int reason) -{ - struct hw_pkt_q_entry *q_entry; - - if ((q_entry = xmalloc(sizeof(*q_entry))) == NULL) { - VLOG_WARN("Could not alloc q entry\n"); - /* FIXME: Dealloc buffer */ - return; - } - q_entry->buffer = buffer; - q_entry->next = NULL; - q_entry->port_no = port_no; - q_entry->reason = reason; - pthread_mutex_lock(&pkt_q_mutex); - if (dp->hw_pkt_list_head == NULL) { - dp->hw_pkt_list_head = q_entry; - } else { - dp->hw_pkt_list_tail->next = q_entry; - } - dp->hw_pkt_list_tail = q_entry; - pthread_mutex_unlock(&pkt_q_mutex); -} - -/* If queue non-empty, fill out params and return 1; else return 0 */ -static int -dequeue_pkt(struct datapath *dp, struct ofpbuf **buffer, of_port_t *port_no, - int *reason) -{ - struct hw_pkt_q_entry *q_entry; - int rv = 0; - - pthread_mutex_lock(&pkt_q_mutex); - q_entry = dp->hw_pkt_list_head; - if (dp->hw_pkt_list_head != NULL) { - dp->hw_pkt_list_head = dp->hw_pkt_list_head->next; - if (dp->hw_pkt_list_head == NULL) { - dp->hw_pkt_list_tail = NULL; - } - } - pthread_mutex_unlock(&pkt_q_mutex); - - if (q_entry != NULL) { - rv = 1; - *buffer = q_entry->buffer; - *port_no = q_entry->port_no; - *reason = q_entry->reason; - free(q_entry); - } - - return rv; -} -#endif - -extern char mfr_desc; -extern char hw_desc; -extern char sw_desc; -extern char dp_desc; -extern char serial_num; - -/* Capabilities supported by this implementation. */ -#define OFP_SUPPORTED_CAPABILITIES ( OFPC_FLOW_STATS \ - | OFPC_TABLE_STATS \ - | OFPC_PORT_STATS \ - | OFPC_QUEUE_STATS \ - | OFPC_ARP_MATCH_IP ) - -/* Actions supported by this implementation. */ -#define OFP_SUPPORTED_ACTIONS ( (1 << OFPAT_OUTPUT) \ - | (1 << OFPAT_SET_VLAN_VID) \ - | (1 << OFPAT_SET_VLAN_PCP) \ - | (1 << OFPAT_STRIP_VLAN) \ - | (1 << OFPAT_SET_DL_SRC) \ - | (1 << OFPAT_SET_DL_DST) \ - | (1 << OFPAT_SET_NW_SRC) \ - | (1 << OFPAT_SET_NW_DST) \ - | (1 << OFPAT_SET_TP_SRC) \ - | (1 << OFPAT_SET_TP_DST) \ - | (1 << OFPAT_ENQUEUE)) - -/* The origin of a received OpenFlow message, to enable sending a reply. */ -struct sender { - struct remote *remote; /* The device that sent the message. */ - uint32_t xid; /* The OpenFlow transaction ID. */ -}; - -/* A connection to a secure channel. */ -struct remote { - struct list node; - struct rconn *rconn; -#define TXQ_LIMIT 128 /* Max number of packets to queue for tx. */ - int n_txq; /* Number of packets queued for tx on rconn. */ - - /* Support for reliable, multi-message replies to requests. - * - * If an incoming request needs to have a reliable reply that might - * require multiple messages, it can use remote_start_dump() to set up - * a callback that will be called as buffer space for replies. */ - int (*cb_dump)(struct datapath *, void *aux); - void (*cb_done)(void *aux); - void *cb_aux; -}; - -static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60); - -static struct remote *remote_create(struct datapath *, struct rconn *); -static void remote_run(struct datapath *, struct remote *); -static void remote_wait(struct remote *); -static void remote_destroy(struct remote *); - -static void update_port_flags(struct datapath *, const struct ofp_port_mod *); -static void send_port_status(struct sw_port *p, uint8_t status); - -/* Buffers are identified by a 31-bit opaque ID. We divide the ID - * into a buffer number (low bits) and a cookie (high bits). The buffer number - * is an index into an array of buffers. The cookie distinguishes between - * different packets that have occupied a single buffer. Thus, the more - * buffers we have, the lower-quality the cookie... */ -#define PKT_BUFFER_BITS 8 -#define N_PKT_BUFFERS (1 << PKT_BUFFER_BITS) -#define PKT_BUFFER_MASK (N_PKT_BUFFERS - 1) - -#define PKT_COOKIE_BITS (32 - PKT_BUFFER_BITS) - -int run_flow_through_tables(struct datapath *, struct ofpbuf *, - struct sw_port *); -void fwd_port_input(struct datapath *, struct ofpbuf *, struct sw_port *); -int fwd_control_input(struct datapath *, const struct sender *, - const void *, size_t); - -uint32_t save_buffer(struct ofpbuf *); -static struct ofpbuf *retrieve_buffer(uint32_t id); -static void discard_buffer(uint32_t id); - -struct sw_port * -dp_lookup_port(struct datapath *dp, uint16_t port_no) -{ - return (port_no < DP_MAX_PORTS ? &dp->ports[port_no] - : port_no == OFPP_LOCAL ? dp->local_port - : NULL); -} - -struct sw_queue * -dp_lookup_queue(struct sw_port *p, uint32_t queue_id) -{ - struct sw_queue *q; - - LIST_FOR_EACH(q, struct sw_queue, node, &p->queue_list) { - if ((q != NULL) && (q->queue_id == queue_id)) { - return q; - } - } - return NULL; -} - -/* Generates and returns a random datapath id. */ -static uint64_t -gen_datapath_id(void) -{ - uint8_t ea[ETH_ADDR_LEN]; - eth_addr_random(ea); - ea[0] = 0x00; /* Set Nicira OUI. */ - ea[1] = 0x23; - ea[2] = 0x20; - return eth_addr_to_uint64(ea); -} - -/* FIXME: Should not depend on udatapath_as_lib */ -#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) && defined(UDATAPATH_AS_LIB) -/* - * Receive packet handling for hardware driver controlled ports - * - * FIXME: For now, call the pkt fwding directly; eventually may - * want to enqueue packets at this layer; at that point must - * make sure poll event is registered or timer kicked - */ -static int -hw_packet_in(of_port_t port_no, of_packet_t *packet, int reason, - void *cookie) -{ - struct sw_port *port; - struct ofpbuf *buffer = NULL; - struct datapath *dp = (struct datapath *)cookie; - const int headroom = 128 + 2; - const int hard_header = VLAN_ETH_HEADER_LEN; - const int tail_room = sizeof(uint32_t); /* For crc if needed later */ - - VLOG_INFO("dp rcv packet on port %d, size %d\n", - port_no, packet->length); - if ((port_no < 1) || port_no > DP_MAX_PORTS) { - VLOG_ERR("Bad receive port %d\n", port_no); - /* TODO increment error counter */ - return -1; - } - port = &dp->ports[port_no]; - if (!PORT_IN_USE(port)) { - VLOG_WARN("Receive port not active: %d\n", port_no); - return -1; - } - if (!IS_HW_PORT(port)) { - VLOG_ERR("Receive port not controlled by HW: %d\n", port_no); - return -1; - } - /* Note: We're really not counting these for port stats as they - * should be gotten directly from the HW */ - port->rx_packets++; - port->rx_bytes += packet->length; - /* For now, copy data into OFP buffer; eventually may steal packet - * from RX to avoid copy. As per dp_run, add headroom and offset bytes. - */ - buffer = ofpbuf_new(headroom + hard_header + packet->length + tail_room); - if (buffer == NULL) { - VLOG_WARN("Could not alloc ofpbuf on hw pkt in\n"); - fprintf(stderr, "Could not alloc ofpbuf on hw pkt in\n"); - } else { - buffer->data = (char*)buffer->data + headroom; - buffer->size = packet->length; - memcpy(buffer->data, packet->data, packet->length); - enqueue_pkt(dp, buffer, port_no, reason); - poll_immediate_wake(); - } - - return 0; -} -#endif - -#if defined(OF_HW_PLAT) -static int -dp_hw_drv_init(struct datapath *dp) -{ - dp->hw_pkt_list_head = NULL; - dp->hw_pkt_list_tail = NULL; - - dp->hw_drv = new_of_hw_driver(dp); - if (dp->hw_drv == NULL) { - VLOG_ERR("Could not create HW driver"); - return -1; - } -#if !defined(USE_NETDEV) - if (dp->hw_drv->packet_receive_register(dp->hw_drv, - hw_packet_in, dp) < 0) { - VLOG_ERR("Could not register with HW driver to receive pkts"); - } -#endif - - return 0; -} - -#endif - -int -dp_new(struct datapath **dp_, uint64_t dpid) -{ - struct datapath *dp; - - dp = calloc(1, sizeof *dp); - if (!dp) { - return ENOMEM; - } - - dp->last_timeout = time_now(); - list_init(&dp->remotes); - dp->listeners = NULL; - dp->n_listeners = 0; - dp->id = dpid <= UINT64_C(0xffffffffffff) ? dpid : gen_datapath_id(); -/* FIXME: Should not depend on udatapath_as_lib */ -#if defined(OF_HW_PLAT) && (defined(UDATAPATH_AS_LIB) || defined(USE_NETDEV)) - dp_hw_drv_init(dp); -#endif - dp->chain = chain_create(dp); - if (!dp->chain) { - VLOG_ERR("could not create chain"); - free(dp); - return ENOMEM; - } - - list_init(&dp->port_list); - dp->flags = 0; - dp->miss_send_len = OFP_DEFAULT_MISS_SEND_LEN; - - if(strlen(&dp_desc) > 0) /* use the comment, if specified */ - strncpy(dp->dp_desc, &dp_desc, sizeof dp->dp_desc); - else /* else, just use "$HOSTNAME pid=$$" */ - { - char hostnametmp[DESC_STR_LEN]; - gethostname(hostnametmp,sizeof hostnametmp); - snprintf(dp->dp_desc, sizeof dp->dp_desc,"%s pid=%u",hostnametmp, getpid()); - } - - *dp_ = dp; - return 0; -} - -static int -new_port(struct datapath *dp, struct sw_port *port, uint16_t port_no, - const char *netdev_name, const uint8_t *new_mac, uint16_t num_queues) -{ - struct netdev *netdev; - struct in6_addr in6; - struct in_addr in4; - int error; - - error = netdev_open(netdev_name, NETDEV_ETH_TYPE_ANY, &netdev); - if (error) { - return error; - } - if (new_mac && !eth_addr_equals(netdev_get_etheraddr(netdev), new_mac)) { - /* Generally the device has to be down before we change its hardware - * address. Don't bother to check for an error because it's really - * the netdev_set_etheraddr() call below that we care about. */ - netdev_set_flags(netdev, 0, false); - error = netdev_set_etheraddr(netdev, new_mac); - if (error) { - VLOG_WARN("failed to change %s Ethernet address " - "to "ETH_ADDR_FMT": %s", - netdev_name, ETH_ADDR_ARGS(new_mac), strerror(error)); - } - } - error = netdev_set_flags(netdev, NETDEV_UP | NETDEV_PROMISC, false); - if (error) { - VLOG_ERR("failed to set promiscuous mode on %s device", netdev_name); - netdev_close(netdev); - return error; - } - if (netdev_get_in4(netdev, &in4)) { - VLOG_ERR("%s device has assigned IP address %s", - netdev_name, inet_ntoa(in4)); - } - if (netdev_get_in6(netdev, &in6)) { - char in6_name[INET6_ADDRSTRLEN + 1]; - inet_ntop(AF_INET6, &in6, in6_name, sizeof in6_name); - VLOG_ERR("%s device has assigned IPv6 address %s", - netdev_name, in6_name); - } - - if (num_queues > 0) { - error = netdev_setup_slicing(netdev, num_queues); - if (error) { - VLOG_ERR("failed to configure slicing on %s device: "\ - "check INSTALL for dependencies, or rerun "\ - "using --no-slicing option to disable slicing", - netdev_name); - netdev_close(netdev); - return error; - } - } - - memset(port, '\0', sizeof *port); - - list_init(&port->queue_list); - port->dp = dp; - port->flags |= SWP_USED; - port->netdev = netdev; - port->port_no = port_no; - port->num_queues = num_queues; - list_push_back(&dp->port_list, &port->node); - - /* Notify the ctlpath that this port has been added */ - send_port_status(port, OFPPR_ADD); - - return 0; -} - -#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) -int -dp_add_port(struct datapath *dp, const char *port_name, uint16_t num_queues) -{ - int port_no; - int rc = 0; - struct sw_port *port; - - fprintf(stderr, "Adding port %s. hw_drv is %p\n", port_name, dp->hw_drv); - if (dp->hw_drv && dp->hw_drv->port_add) { - port_no = dp->hw_drv->port_add(dp->hw_drv, -1, port_name); - if (port_no >= 0) { - port = &dp->ports[port_no]; - if (port->flags & SWP_USED) { - VLOG_ERR("HW port %s (%d) already created\n", - port_name, port_no); - rc = -1; - } else { - fprintf(stderr, "Adding HW port %s as OF port number %d\n", - port_name, port_no); - /* FIXME: Determine and record HW addr, etc */ - port->flags |= SWP_USED | SWP_HW_DRV_PORT; - port->dp = dp; - port->port_no = port_no; - list_init(&port->queue_list); - port->num_queues = num_queues; - strncpy(port->hw_name, port_name, sizeof(port->hw_name)); - list_push_back(&dp->port_list, &port->node); - send_port_status(port, OFPPR_ADD); - } - } else { - VLOG_ERR("Port %s not recognized by hardware driver", port_name); - rc = -1; - } - } else { - VLOG_ERR("No hardware driver support; can't add ports"); - rc = -1; - } - - return rc; -} -#else /* Not HW platform support */ -int -dp_add_port(struct datapath *dp, const char *netdev, uint16_t num_queues) -{ - int port_no; - for (port_no = 1; port_no < DP_MAX_PORTS; port_no++) { - struct sw_port *port = &dp->ports[port_no]; - if (!port->netdev) { - return new_port(dp, port, port_no, netdev, NULL, num_queues); - } - } - return EXFULL; -} -#endif /* OF_HW_PLAT */ - -int -dp_add_local_port(struct datapath *dp, const char *netdev, uint16_t num_queues) -{ - if (!dp->local_port) { - uint8_t ea[ETH_ADDR_LEN]; - struct sw_port *port; - int error; - - port = xcalloc(1, sizeof *port); - eth_addr_from_uint64(dp->id, ea); - error = new_port(dp, port, OFPP_LOCAL, netdev, ea, num_queues); - if (!error) { - dp->local_port = port; - } else { - free(port); - } - return error; - } else { - return EXFULL; - } -} - -void -dp_add_pvconn(struct datapath *dp, struct pvconn *pvconn) -{ - dp->listeners = xrealloc(dp->listeners, - sizeof *dp->listeners * (dp->n_listeners + 1)); - dp->listeners[dp->n_listeners++] = pvconn; -} - -void -dp_run(struct datapath *dp) -{ - time_t now = time_now(); - struct sw_port *p, *pn; - struct remote *r, *rn; - struct ofpbuf *buffer = NULL; - size_t i; - - if (now != dp->last_timeout) { - struct list deleted = LIST_INITIALIZER(&deleted); - struct sw_flow *f, *n; - - chain_timeout(dp->chain, &deleted); - LIST_FOR_EACH_SAFE (f, n, struct sw_flow, node, &deleted) { - dp_send_flow_end(dp, f, f->reason); - list_remove(&f->node); - flow_free(f); - } - dp->last_timeout = now; - } - poll_timer_wait(1000); - -#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) - { /* Process packets received from callback thread */ - struct ofpbuf *buffer; - of_port_t port_no; - int reason; - struct sw_port *p; - - while (dequeue_pkt(dp, &buffer, &port_no, &reason)) { - p = dp_lookup_port(dp, port_no); - /* FIXME: We're throwing away the reason that came from HW */ - fwd_port_input(dp, buffer, p); - } - } -#endif - - LIST_FOR_EACH_SAFE (p, pn, struct sw_port, node, &dp->port_list) { - int error; - - if (IS_HW_PORT(p)) { - continue; - } - if (!buffer) { - /* Allocate buffer with some headroom to add headers in forwarding - * to the controller or adding a vlan tag, plus an extra 2 bytes to - * allow IP headers to be aligned on a 4-byte boundary. */ - const int headroom = 128 + 2; - const int hard_header = VLAN_ETH_HEADER_LEN; - const int mtu = netdev_get_mtu(p->netdev); - buffer = ofpbuf_new(headroom + hard_header + mtu); - buffer->data = (char*)buffer->data + headroom; - } - error = netdev_recv(p->netdev, buffer); - if (!error) { - p->rx_packets++; - p->rx_bytes += buffer->size; - fwd_port_input(dp, buffer, p); - buffer = NULL; - } else if (error != EAGAIN) { - VLOG_ERR_RL(&rl, "error receiving data from %s: %s", - netdev_get_name(p->netdev), strerror(error)); - } - } - ofpbuf_delete(buffer); - - /* Talk to remotes. */ - LIST_FOR_EACH_SAFE (r, rn, struct remote, node, &dp->remotes) { - remote_run(dp, r); - } - - for (i = 0; i < dp->n_listeners; ) { - struct pvconn *pvconn = dp->listeners[i]; - struct vconn *new_vconn; - int retval = pvconn_accept(pvconn, OFP_VERSION, &new_vconn); - if (!retval) { - remote_create(dp, rconn_new_from_vconn("passive", new_vconn)); - } else if (retval != EAGAIN) { - VLOG_WARN_RL(&rl, "accept failed (%s)", strerror(retval)); - dp->listeners[i] = dp->listeners[--dp->n_listeners]; - continue; - } - i++; - } -} - -static void -remote_run(struct datapath *dp, struct remote *r) -{ - int i; - - rconn_run(r->rconn); - - /* Do some remote processing, but cap it at a reasonable amount so that - * other processing doesn't starve. */ - for (i = 0; i < 50; i++) { - if (!r->cb_dump) { - struct ofpbuf *buffer; - struct ofp_header *oh; - - buffer = rconn_recv(r->rconn); - if (!buffer) { - break; - } - - if (buffer->size >= sizeof *oh) { - struct sender sender; - - oh = (struct ofp_header *)buffer->data; - sender.remote = r; - sender.xid = oh->xid; - fwd_control_input(dp, &sender, buffer->data, buffer->size); - } else { - VLOG_WARN_RL(&rl, "received too-short OpenFlow message"); - } - ofpbuf_delete(buffer); - } else { - if (r->n_txq < TXQ_LIMIT) { - int error = r->cb_dump(dp, r->cb_aux); - if (error <= 0) { - if (error) { - VLOG_WARN_RL(&rl, "dump callback error: %s", - strerror(-error)); - } - r->cb_done(r->cb_aux); - r->cb_dump = NULL; - } - } else { - break; - } - } - } - - if (!rconn_is_alive(r->rconn)) { - remote_destroy(r); - } -} - -static void -remote_wait(struct remote *r) -{ - rconn_run_wait(r->rconn); - rconn_recv_wait(r->rconn); -} - -static void -remote_destroy(struct remote *r) -{ - if (r) { - if (r->cb_dump && r->cb_done) { - r->cb_done(r->cb_aux); - } - list_remove(&r->node); - rconn_destroy(r->rconn); - free(r); - } -} - -static struct remote * -remote_create(struct datapath *dp, struct rconn *rconn) -{ - struct remote *remote = xmalloc(sizeof *remote); - list_push_back(&dp->remotes, &remote->node); - remote->rconn = rconn; - remote->cb_dump = NULL; - remote->n_txq = 0; - return remote; -} - -/* Starts a callback-based, reliable, possibly multi-message reply to a - * request made by 'remote'. - * - * 'dump' designates a function that will be called when the 'remote' send - * queue has an empty slot. It should compose a message and send it on - * 'remote'. On success, it should return 1 if it should be called again when - * another send queue slot opens up, 0 if its transmissions are complete, or a - * negative errno value on failure. - * - * 'done' designates a function to clean up any resources allocated for the - * dump. It must handle being called before the dump is complete (which will - * happen if 'remote' is closed unexpectedly). - * - * 'aux' is passed to 'dump' and 'done'. */ -static void -remote_start_dump(struct remote *remote, - int (*dump)(struct datapath *, void *), - void (*done)(void *), - void *aux) -{ - assert(!remote->cb_dump); - remote->cb_dump = dump; - remote->cb_done = done; - remote->cb_aux = aux; -} - -void -dp_wait(struct datapath *dp) -{ - struct sw_port *p; - struct remote *r; - size_t i; - - LIST_FOR_EACH (p, struct sw_port, node, &dp->port_list) { - if (IS_HW_PORT(p)) { - continue; - } - netdev_recv_wait(p->netdev); - } - LIST_FOR_EACH (r, struct remote, node, &dp->remotes) { - remote_wait(r); - } - for (i = 0; i < dp->n_listeners; i++) { - pvconn_wait(dp->listeners[i]); - } -} - -/* Send packets out all the ports except the originating one. If the - * "flood" argument is set, don't send out ports with flooding disabled. - */ -static int -output_all(struct datapath *dp, struct ofpbuf *buffer, int in_port, int flood) -{ - struct sw_port *p; - int prev_port; /* Buffer is cloned for multiple transmits */ - - prev_port = -1; - LIST_FOR_EACH (p, struct sw_port, node, &dp->port_list) { - if (p->port_no == in_port) { - continue; - } - if (flood && p->config & OFPPC_NO_FLOOD) { - continue; - } - if (prev_port != -1) { - dp_output_port(dp, ofpbuf_clone(buffer), in_port, prev_port, - 0,false); - } - prev_port = p->port_no; - } - if (prev_port != -1) - dp_output_port(dp, buffer, in_port, prev_port, 0, false); - else - ofpbuf_delete(buffer); - - return 0; -} - -static void -output_packet(struct datapath *dp, struct ofpbuf *buffer, uint16_t out_port, - uint32_t queue_id) -{ - uint16_t class_id; - struct sw_queue * q; - struct sw_port *p; - - q = NULL; - p = dp_lookup_port(dp, out_port); - -/* FIXME: Needs update for queuing */ -#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) - if ((p != NULL) && IS_HW_PORT(p)) { - if (dp && dp->hw_drv) { - if (dp->hw_drv->port_link_get(dp->hw_drv, p->port_no)) { - of_packet_t *pkt; - int rv; - - pkt = calloc(1, sizeof(*pkt)); - OF_PKT_INIT(pkt, buffer); - rv = dp->hw_drv->packet_send(dp->hw_drv, out_port, pkt, 0); - if ((rv < 0) && (rv != OF_HW_PORT_DOWN)) { - VLOG_ERR("Error %d sending pkt on HW port %d\n", - rv, out_port); - ofpbuf_delete(buffer); - free(pkt); - } - } - } - return; - } - - /* Fall through to software controlled ports if not HW port */ -#endif - - if (p && p->netdev != NULL) { - if (!(p->config & OFPPC_PORT_DOWN)) { - /* avoid the queue lookup for best-effort traffic */ - if (queue_id == 0) { - class_id = 0; - } - else { - /* silently drop the packet if queue doesn't exist */ - q = dp_lookup_queue(p, queue_id); - if (q) { - class_id = q->class_id; - } - else { - goto error; - } - } - - if (!netdev_send(p->netdev, buffer, class_id)) { - p->tx_packets++; - p->tx_bytes += buffer->size; - if (q) { - q->tx_packets++; - q->tx_bytes += buffer->size; - } - } else { - p->tx_dropped++; - } - } - ofpbuf_delete(buffer); - return; - } - - error: - ofpbuf_delete(buffer); - VLOG_DBG_RL(&rl, "can't forward to bad port:queue(%d:%d)\n", out_port, - queue_id); -} - -/** Takes ownership of 'buffer' and transmits it to 'out_port' on 'dp'. - */ -void -dp_output_port(struct datapath *dp, struct ofpbuf *buffer, - int in_port, int out_port, uint32_t queue_id, - bool ignore_no_fwd UNUSED) -{ - - assert(buffer); - switch (out_port) { - case OFPP_IN_PORT: - output_packet(dp, buffer, in_port, queue_id); - break; - - case OFPP_TABLE: { - struct sw_port *p = dp_lookup_port(dp, in_port); - if (run_flow_through_tables(dp, buffer, p)) { - ofpbuf_delete(buffer); - } - break; - } - - case OFPP_FLOOD: - output_all(dp, buffer, in_port, 1); - break; - - case OFPP_ALL: - output_all(dp, buffer, in_port, 0); - break; - - case OFPP_CONTROLLER: - dp_output_control(dp, buffer, in_port, UINT16_MAX, OFPR_ACTION); - break; - - case OFPP_LOCAL: - default: - if (in_port == out_port) { - VLOG_DBG_RL(&rl, "can't directly forward to input port"); - return; - } - output_packet(dp, buffer, out_port, queue_id); - break; - } -} - -static void * -make_openflow_reply(size_t openflow_len, uint8_t type, - const struct sender *sender, struct ofpbuf **bufferp) -{ - return make_openflow_xid(openflow_len, type, sender ? sender->xid : 0, - bufferp); -} - -static int -send_openflow_buffer_to_remote(struct ofpbuf *buffer, struct remote *remote) -{ - int retval = rconn_send_with_limit(remote->rconn, buffer, &remote->n_txq, - TXQ_LIMIT); - if (retval) { - VLOG_WARN_RL(&rl, "send to %s failed: %s", - rconn_get_name(remote->rconn), strerror(retval)); - } - return retval; -} - -static int -send_openflow_buffer(struct datapath *dp, struct ofpbuf *buffer, - const struct sender *sender) -{ - update_openflow_length(buffer); - if (sender) { - /* Send back to the sender. */ - return send_openflow_buffer_to_remote(buffer, sender->remote); - } else { - /* Broadcast to all remotes. */ - struct remote *r, *prev = NULL; - LIST_FOR_EACH (r, struct remote, node, &dp->remotes) { - if (prev) { - send_openflow_buffer_to_remote(ofpbuf_clone(buffer), prev); - } - prev = r; - } - if (prev) { - send_openflow_buffer_to_remote(buffer, prev); - } else { - ofpbuf_delete(buffer); - } - return 0; - } -} - -/* Takes ownership of 'buffer' and transmits it to 'dp''s controller. If the - * packet can be saved in a buffer, then only the first max_len bytes of - * 'buffer' are sent; otherwise, all of 'buffer' is sent. 'reason' indicates - * why 'buffer' is being sent. 'max_len' sets the maximum number of bytes that - * the caller wants to be sent. */ -void -dp_output_control(struct datapath *dp, struct ofpbuf *buffer, int in_port, - size_t max_len, int reason) -{ - struct ofp_packet_in *opi; - size_t total_len; - uint32_t buffer_id; - - buffer_id = save_buffer(buffer); - total_len = buffer->size; - if (buffer_id != UINT32_MAX && buffer->size > max_len) { - buffer->size = max_len; - } - - opi = ofpbuf_push_uninit(buffer, offsetof(struct ofp_packet_in, data)); - opi->header.version = OFP_VERSION; - opi->header.type = OFPT_PACKET_IN; - opi->header.length = htons(buffer->size); - opi->header.xid = htonl(0); - opi->buffer_id = htonl(buffer_id); - opi->total_len = htons(total_len); - opi->in_port = htons(in_port); - opi->reason = reason; - opi->pad = 0; - send_openflow_buffer(dp, buffer, NULL); -} - -static void -fill_queue_desc(struct ofpbuf *buffer, struct sw_queue *q, - struct ofp_packet_queue *desc) -{ - struct ofp_queue_prop_min_rate *mr; - int len; - - len = sizeof(struct ofp_packet_queue) + - sizeof(struct ofp_queue_prop_min_rate); - desc->queue_id = htonl(q->queue_id); - desc->len = htons(len); - - /* Property list */ - mr = ofpbuf_put_zeros(buffer, sizeof *mr); - mr->prop_header.property = htons(OFPQT_MIN_RATE); - len = sizeof(struct ofp_queue_prop_min_rate); - mr->prop_header.len = htons(len); - mr->rate = htons(q->min_rate); -} - - -static void -fill_port_desc(struct sw_port *p, struct ofp_phy_port *desc) -{ - desc->port_no = htons(p->port_no); - if (IS_HW_PORT(p)) { -#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) - of_hw_driver_t *hw_drv; - - hw_drv = p->dp->hw_drv; - strncpy((char *) desc->name, p->hw_name, sizeof desc->name); - desc->name[sizeof desc->name - 1] = '\0'; - /* Update local port state */ - if (hw_drv->port_link_get(hw_drv, p->port_no)) { - p->state &= ~OFPPS_LINK_DOWN; - } else { - p->state |= OFPPS_LINK_DOWN; - } - if (hw_drv->port_enable_get(hw_drv, p->port_no)) { - p->config &= ~OFPPC_PORT_DOWN; - } else { - p->config |= OFPPC_PORT_DOWN; - } - /* FIXME: Add current, supported and advertised features */ -#endif - } else if (p->netdev) { - strncpy((char *) desc->name, netdev_get_name(p->netdev), - sizeof desc->name); - desc->name[sizeof desc->name - 1] = '\0'; - memcpy(desc->hw_addr, netdev_get_etheraddr(p->netdev), ETH_ADDR_LEN); - desc->curr= htonl(netdev_get_features(p->netdev, - NETDEV_FEAT_CURRENT)); - desc->supported = htonl(netdev_get_features(p->netdev, - NETDEV_FEAT_SUPPORTED)); - desc->advertised = htonl(netdev_get_features(p->netdev, - NETDEV_FEAT_ADVERTISED)); - desc->peer = htonl(netdev_get_features(p->netdev, NETDEV_FEAT_PEER)); - } - desc->config = htonl(p->config); - desc->state = htonl(p->state); -} - -static void -dp_send_features_reply(struct datapath *dp, const struct sender *sender) -{ - struct ofpbuf *buffer; - struct ofp_switch_features *ofr; - struct sw_port *p; - - ofr = make_openflow_reply(sizeof *ofr, OFPT_FEATURES_REPLY, - sender, &buffer); - ofr->datapath_id = htonll(dp->id); - ofr->n_tables = dp->chain->n_tables; - ofr->n_buffers = htonl(N_PKT_BUFFERS); - ofr->capabilities = htonl(OFP_SUPPORTED_CAPABILITIES); - ofr->actions = htonl(OFP_SUPPORTED_ACTIONS); - LIST_FOR_EACH (p, struct sw_port, node, &dp->port_list) { - struct ofp_phy_port *opp = ofpbuf_put_uninit(buffer, sizeof *opp); - memset(opp, 0, sizeof *opp); - fill_port_desc(p, opp); - } - send_openflow_buffer(dp, buffer, sender); -} - -void -update_port_flags(struct datapath *dp, const struct ofp_port_mod *opm) -{ - struct sw_port *p = dp_lookup_port(dp, ntohs(opm->port_no)); - - /* Make sure the port id hasn't changed since this was sent */ - if (!p || memcmp(opm->hw_addr, netdev_get_etheraddr(p->netdev), - ETH_ADDR_LEN) != 0) { - return; - } - - - if (opm->mask) { - uint32_t config_mask = ntohl(opm->mask); - p->config &= ~config_mask; - p->config |= ntohl(opm->config) & config_mask; - } -} - -static void -send_port_status(struct sw_port *p, uint8_t status) -{ - struct ofpbuf *buffer; - struct ofp_port_status *ops; - ops = make_openflow_xid(sizeof *ops, OFPT_PORT_STATUS, 0, &buffer); - ops->reason = status; - memset(ops->pad, 0, sizeof ops->pad); - fill_port_desc(p, &ops->desc); - - send_openflow_buffer(p->dp, buffer, NULL); -} - -void -dp_send_flow_end(struct datapath *dp, struct sw_flow *flow, - enum ofp_flow_removed_reason reason) -{ - struct ofpbuf *buffer; - struct ofp_flow_removed *ofr; - uint64_t tdiff = time_msec() - flow->created; - uint32_t sec = tdiff / 1000; - - if (!flow->send_flow_rem) { - return; - } - - if (flow->emerg_flow) { - return; - } - - ofr = make_openflow_xid(sizeof *ofr, OFPT_FLOW_REMOVED, 0, &buffer); - if (!ofr) { - return; - } - - flow_fill_match(&ofr->match, &flow->key.flow, flow->key.wildcards); - - ofr->cookie = htonll(flow->cookie); - ofr->priority = htons(flow->priority); - ofr->reason = reason; - - ofr->duration_sec = htonl(sec); - ofr->duration_nsec = htonl((tdiff - (sec * 1000)) * 1000000); - ofr->idle_timeout = htons(flow->idle_timeout); - - ofr->packet_count = htonll(flow->packet_count); - ofr->byte_count = htonll(flow->byte_count); - - send_openflow_buffer(dp, buffer, NULL); -} - -void -dp_send_error_msg(struct datapath *dp, const struct sender *sender, - uint16_t type, uint16_t code, const void *data, size_t len) -{ - struct ofpbuf *buffer; - struct ofp_error_msg *oem; - oem = make_openflow_reply(sizeof(*oem)+len, OFPT_ERROR, sender, &buffer); - oem->type = htons(type); - oem->code = htons(code); - memcpy(oem->data, data, len); - send_openflow_buffer(dp, buffer, sender); -} - -static void -fill_flow_stats(struct ofpbuf *buffer, struct sw_flow *flow, - int table_idx, uint64_t now) -{ - struct ofp_flow_stats *ofs; - int length = sizeof *ofs + flow->sf_acts->actions_len; - uint64_t tdiff = now - flow->created; - uint32_t sec = tdiff / 1000; - ofs = ofpbuf_put_uninit(buffer, length); - ofs->length = htons(length); - ofs->table_id = table_idx; - ofs->pad = 0; - ofs->match.wildcards = htonl(flow->key.wildcards); - ofs->match.in_port = flow->key.flow.in_port; - memcpy(ofs->match.dl_src, flow->key.flow.dl_src, ETH_ADDR_LEN); - memcpy(ofs->match.dl_dst, flow->key.flow.dl_dst, ETH_ADDR_LEN); - ofs->match.dl_vlan = flow->key.flow.dl_vlan; - ofs->match.dl_type = flow->key.flow.dl_type; - ofs->match.nw_tos = flow->key.flow.nw_tos; - ofs->match.nw_src = flow->key.flow.nw_src; - ofs->match.nw_dst = flow->key.flow.nw_dst; - ofs->match.nw_proto = flow->key.flow.nw_proto; - ofs->match.dl_vlan_pcp = flow->key.flow.dl_vlan_pcp; - ofs->match.tp_src = flow->key.flow.tp_src; - ofs->match.tp_dst = flow->key.flow.tp_dst; - ofs->duration_sec = htonl(sec); - ofs->duration_nsec = htonl((tdiff - (sec * 1000)) * 1000000); - ofs->cookie = htonll(flow->cookie); - ofs->priority = htons(flow->priority); - ofs->idle_timeout = htons(flow->idle_timeout); - ofs->hard_timeout = htons(flow->hard_timeout); - memset(&ofs->pad2, 0, sizeof ofs->pad2); - ofs->packet_count = htonll(flow->packet_count); - ofs->byte_count = htonll(flow->byte_count); - memcpy(ofs->actions, flow->sf_acts->actions, flow->sf_acts->actions_len); -} - - -/* 'buffer' was received on 'p', which may be a a physical switch port or a - * null pointer. Process it according to 'dp''s flow table. Returns 0 if - * successful, in which case 'buffer' is destroyed, or -ESRCH if there is no - * matching flow, in which case 'buffer' still belongs to the caller. */ -int run_flow_through_tables(struct datapath *dp, struct ofpbuf *buffer, - struct sw_port *p) -{ - struct sw_flow_key key; - struct sw_flow *flow; - - key.wildcards = 0; - if (flow_extract(buffer, p ? p->port_no : OFPP_NONE, &key.flow) - && (dp->flags & OFPC_FRAG_MASK) == OFPC_FRAG_DROP) { - /* Drop fragment. */ - ofpbuf_delete(buffer); - return 0; - } - - if (p && p->config & (OFPPC_NO_RECV | OFPPC_NO_RECV_STP) - && p->config & (!eth_addr_equals(key.flow.dl_dst, stp_eth_addr) - ? OFPPC_NO_RECV : OFPPC_NO_RECV_STP)) { - ofpbuf_delete(buffer); - return 0; - } - - flow = chain_lookup(dp->chain, &key, 0); - if (flow != NULL) { - flow_used(flow, buffer); - execute_actions(dp, buffer, &key, flow->sf_acts->actions, - flow->sf_acts->actions_len, false); - return 0; - } else { - return -ESRCH; - } -} - -/* 'buffer' was received on 'p', which may be a a physical switch port or a - * null pointer. Process it according to 'dp''s flow table, sending it up to - * the controller if no flow matches. Takes ownership of 'buffer'. */ -void fwd_port_input(struct datapath *dp, struct ofpbuf *buffer, - struct sw_port *p) -{ - if (run_flow_through_tables(dp, buffer, p)) { - dp_output_control(dp, buffer, p->port_no, - dp->miss_send_len, OFPR_NO_MATCH); - } -} - -static struct ofpbuf * -make_barrier_reply(const struct ofp_header *req) -{ - size_t size = ntohs(req->length); - struct ofpbuf *buf = ofpbuf_new(size); - struct ofp_header *reply = ofpbuf_put(buf, req, size); - - reply->type = OFPT_BARRIER_REPLY; - return buf; -} - -static int -recv_barrier_request(struct datapath *dp, const struct sender *sender, - const void *ofph) -{ - return send_openflow_buffer(dp, make_barrier_reply(ofph), sender); -} - -static int -recv_features_request(struct datapath *dp, const struct sender *sender, - const void *msg UNUSED) -{ - dp_send_features_reply(dp, sender); - return 0; -} - -static int -recv_get_config_request(struct datapath *dp, const struct sender *sender, - const void *msg UNUSED) -{ - struct ofpbuf *buffer; - struct ofp_switch_config *osc; - - osc = make_openflow_reply(sizeof *osc, OFPT_GET_CONFIG_REPLY, - sender, &buffer); - - osc->flags = htons(dp->flags); - osc->miss_send_len = htons(dp->miss_send_len); - - return send_openflow_buffer(dp, buffer, sender); -} - -static int -recv_set_config(struct datapath *dp, const struct sender *sender UNUSED, - const void *msg) -{ - const struct ofp_switch_config *osc = msg; - int flags; - - flags = ntohs(osc->flags) & OFPC_FRAG_MASK; - if ((flags & OFPC_FRAG_MASK) != OFPC_FRAG_NORMAL - && (flags & OFPC_FRAG_MASK) != OFPC_FRAG_DROP) { - flags = (flags & ~OFPC_FRAG_MASK) | OFPC_FRAG_DROP; - } - dp->flags = flags; - dp->miss_send_len = ntohs(osc->miss_send_len); - return 0; -} - -static int -recv_packet_out(struct datapath *dp, const struct sender *sender, - const void *msg) -{ - const struct ofp_packet_out *opo = msg; - struct sw_flow_key key; - uint16_t v_code; - struct ofpbuf *buffer; - size_t actions_len = ntohs(opo->actions_len); - - if (actions_len > (ntohs(opo->header.length) - sizeof *opo)) { - VLOG_DBG_RL(&rl, "message too short for number of actions"); - return -EINVAL; - } - - if (ntohl(opo->buffer_id) == (uint32_t) -1) { - /* FIXME: can we avoid copying data here? */ - int data_len = ntohs(opo->header.length) - sizeof *opo - actions_len; - buffer = ofpbuf_new(data_len); - ofpbuf_put(buffer, (uint8_t *)opo->actions + actions_len, data_len); - } else { - buffer = retrieve_buffer(ntohl(opo->buffer_id)); - if (!buffer) { - return -ESRCH; - } - } - - flow_extract(buffer, ntohs(opo->in_port), &key.flow); - - v_code = validate_actions(dp, &key, opo->actions, actions_len); - if (v_code != ACT_VALIDATION_OK) { - dp_send_error_msg(dp, sender, OFPET_BAD_ACTION, v_code, - msg, ntohs(opo->header.length)); - goto error; - } - - execute_actions(dp, buffer, &key, opo->actions, actions_len, true); - - return 0; - -error: - ofpbuf_delete(buffer); - return -EINVAL; -} - -static int -recv_port_mod(struct datapath *dp, const struct sender *sender UNUSED, - const void *msg) -{ - const struct ofp_port_mod *opm = msg; - - update_port_flags(dp, opm); - - return 0; -} - -static int -add_flow(struct datapath *dp, const struct sender *sender, - const struct ofp_flow_mod *ofm) -{ - int error = -ENOMEM; - uint16_t v_code; - struct sw_flow *flow; - size_t actions_len = ntohs(ofm->header.length) - sizeof *ofm; - int overlap; - - /* Allocate memory. */ - flow = flow_alloc(actions_len); - if (flow == NULL) - goto error; - - flow_extract_match(&flow->key, &ofm->match); - - v_code = validate_actions(dp, &flow->key, ofm->actions, actions_len); - if (v_code != ACT_VALIDATION_OK) { - dp_send_error_msg(dp, sender, OFPET_BAD_ACTION, v_code, - ofm, ntohs(ofm->header.length)); - goto error_free_flow; - } - - flow->priority = flow->key.wildcards ? ntohs(ofm->priority) : -1; - - if (ntohs(ofm->flags) & OFPFF_CHECK_OVERLAP) { - /* check whether there is any conflict */ - overlap = chain_has_conflict(dp->chain, &flow->key, flow->priority, - false); - if (overlap){ - dp_send_error_msg(dp, sender, OFPET_FLOW_MOD_FAILED, - OFPFMFC_OVERLAP, ofm, ntohs(ofm->header.length)); - goto error_free_flow; - } - } - - if (ntohs(ofm->flags) & OFPFF_EMERG) { - if (ntohs(ofm->idle_timeout) != OFP_FLOW_PERMANENT - || ntohs(ofm->hard_timeout) != OFP_FLOW_PERMANENT) { - dp_send_error_msg(dp, sender, OFPET_FLOW_MOD_FAILED, - OFPFMFC_BAD_EMERG_TIMEOUT, ofm, - ntohs(ofm->header.length)); - goto error_free_flow; - } - } - - /* Fill out flow. */ - flow->cookie = ntohll(ofm->cookie); - flow->idle_timeout = ntohs(ofm->idle_timeout); - flow->hard_timeout = ntohs(ofm->hard_timeout); - flow->send_flow_rem = (ntohs(ofm->flags) & OFPFF_SEND_FLOW_REM) ? 1 : 0; - flow->emerg_flow = (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0; - flow_setup_actions(flow, ofm->actions, actions_len); - - /* Act. */ - error = chain_insert(dp->chain, flow, - (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0); - if (error == -ENOBUFS) { - dp_send_error_msg(dp, sender, OFPET_FLOW_MOD_FAILED, - OFPFMFC_ALL_TABLES_FULL, ofm, ntohs(ofm->header.length)); - goto error_free_flow; - } else if (error) { - goto error_free_flow; - } - - error = 0; - if (ntohl(ofm->buffer_id) != UINT32_MAX) { - struct ofpbuf *buffer = retrieve_buffer(ntohl(ofm->buffer_id)); - if (buffer) { - struct sw_flow_key key; - uint16_t in_port = ntohs(ofm->match.in_port); - flow_extract(buffer, in_port, &key.flow); - flow_used(flow, buffer); - execute_actions(dp, buffer, &key, - ofm->actions, actions_len, false); - } else { - error = -ESRCH; - } - } - return error; - -error_free_flow: - flow_free(flow); -error: - if (ntohl(ofm->buffer_id) != (uint32_t) -1) - discard_buffer(ntohl(ofm->buffer_id)); - return error; -} - -static int -mod_flow(struct datapath *dp, const struct sender *sender, - const struct ofp_flow_mod *ofm) -{ - int error = -ENOMEM; - uint16_t v_code; - size_t actions_len = ntohs(ofm->header.length) - sizeof *ofm; - struct sw_flow *flow; - int strict; - - /* Allocate memory. */ - flow = flow_alloc(actions_len); - if (flow == NULL) - goto error; - - flow_extract_match(&flow->key, &ofm->match); - - v_code = validate_actions(dp, &flow->key, ofm->actions, actions_len); - if (v_code != ACT_VALIDATION_OK) { - dp_send_error_msg(dp, sender, OFPET_BAD_ACTION, v_code, - ofm, ntohs(ofm->header.length)); - goto error_free_flow; - } - - flow->priority = flow->key.wildcards ? ntohs(ofm->priority) : -1; - strict = (ofm->command == htons(OFPFC_MODIFY_STRICT)) ? 1 : 0; - - /* First try to modify existing flows if any */ - /* if there is no matching flow, add it */ - if (!chain_modify(dp->chain, &flow->key, flow->priority, - strict, ofm->actions, actions_len, - (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0)) { - /* Fill out flow. */ - flow->cookie = ntohll(ofm->cookie); - flow->idle_timeout = ntohs(ofm->idle_timeout); - flow->hard_timeout = ntohs(ofm->hard_timeout); - flow->send_flow_rem = (ntohs(ofm->flags) & OFPFF_SEND_FLOW_REM) ? 1 : 0; - flow->emerg_flow = (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0; - flow_setup_actions(flow, ofm->actions, actions_len); - error = chain_insert(dp->chain, flow, - (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0); - if (error == -ENOBUFS) { - dp_send_error_msg(dp, sender, OFPET_FLOW_MOD_FAILED, - OFPFMFC_ALL_TABLES_FULL, ofm, - ntohs(ofm->header.length)); - goto error_free_flow; - } else if (error) { - goto error_free_flow; - } - } - - error = 0; - if (ntohl(ofm->buffer_id) != UINT32_MAX) { - struct ofpbuf *buffer = retrieve_buffer(ntohl(ofm->buffer_id)); - if (buffer) { - struct sw_flow_key skb_key; - uint16_t in_port = ntohs(ofm->match.in_port); - flow_extract(buffer, in_port, &skb_key.flow); - execute_actions(dp, buffer, &skb_key, - ofm->actions, actions_len, false); - } else { - error = -ESRCH; - } - } - return error; - -error_free_flow: - flow_free(flow); -error: - if (ntohl(ofm->buffer_id) != (uint32_t) -1) - discard_buffer(ntohl(ofm->buffer_id)); - return error; -} - -static int -recv_flow(struct datapath *dp, const struct sender *sender, - const void *msg) -{ - const struct ofp_flow_mod *ofm = msg; - uint16_t command = ntohs(ofm->command); - - if (command == OFPFC_ADD) { - return add_flow(dp, sender, ofm); - } else if ((command == OFPFC_MODIFY) || (command == OFPFC_MODIFY_STRICT)) { - return mod_flow(dp, sender, ofm); - } else if (command == OFPFC_DELETE) { - struct sw_flow_key key; - flow_extract_match(&key, &ofm->match); - return chain_delete(dp->chain, &key, ofm->out_port, 0, 0, - (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0) - ? 0 : -ESRCH; - } else if (command == OFPFC_DELETE_STRICT) { - struct sw_flow_key key; - uint16_t priority; - flow_extract_match(&key, &ofm->match); - priority = key.wildcards ? ntohs(ofm->priority) : -1; - return chain_delete(dp->chain, &key, ofm->out_port, priority, 1, - (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0) - ? 0 : -ESRCH; - } else { - return -ENODEV; - } -} - -static int -desc_stats_dump(struct datapath *dp UNUSED, void *state UNUSED, - struct ofpbuf *buffer) -{ - struct ofp_desc_stats *ods = ofpbuf_put_uninit(buffer, sizeof *ods); - - strncpy(ods->mfr_desc, &mfr_desc, sizeof ods->mfr_desc); - strncpy(ods->hw_desc, &hw_desc, sizeof ods->hw_desc); - strncpy(ods->sw_desc, &sw_desc, sizeof ods->sw_desc); - strncpy(ods->dp_desc, dp->dp_desc, sizeof ods->dp_desc); - strncpy(ods->serial_num, &serial_num, sizeof ods->serial_num); - - return 0; -} - -struct flow_stats_state { - int table_idx; - struct sw_table_position position; - struct ofp_flow_stats_request rq; - uint64_t now; /* Current time in milliseconds */ - - struct ofpbuf *buffer; -}; - -#define MAX_FLOW_STATS_BYTES 4096 -#define EMERG_TABLE_ID_FOR_STATS 0xfe - -static int -flow_stats_init(const void *body, int body_len UNUSED, void **state) -{ - const struct ofp_flow_stats_request *fsr = body; - struct flow_stats_state *s = xmalloc(sizeof *s); - s->table_idx = fsr->table_id == 0xff ? 0 : fsr->table_id; - memset(&s->position, 0, sizeof s->position); - s->rq = *fsr; - *state = s; - return 0; -} - -static int flow_stats_dump_callback(struct sw_flow *flow, void *private) -{ - struct flow_stats_state *s = private; - fill_flow_stats(s->buffer, flow, s->table_idx, s->now); - return s->buffer->size >= MAX_FLOW_STATS_BYTES; -} - -static int flow_stats_dump(struct datapath *dp, void *state, - struct ofpbuf *buffer) -{ - struct flow_stats_state *s = state; - struct sw_flow_key match_key; - - flow_extract_match(&match_key, &s->rq.match); - s->buffer = buffer; - s->now = time_msec(); - - if (s->rq.table_id == EMERG_TABLE_ID_FOR_STATS) { - struct sw_table *table = dp->chain->emerg_table; - - table->iterate(table, &match_key, s->rq.out_port, - &s->position, flow_stats_dump_callback, s); - } else { - while (s->table_idx < dp->chain->n_tables - && (s->rq.table_id == 0xff || s->rq.table_id == s->table_idx)) - { - struct sw_table *table = dp->chain->tables[s->table_idx]; - - if (table->iterate(table, &match_key, s->rq.out_port, - &s->position, flow_stats_dump_callback, s)) - break; - - s->table_idx++; - memset(&s->position, 0, sizeof s->position); - } - } - return s->buffer->size >= MAX_FLOW_STATS_BYTES; -} - -static void flow_stats_done(void *state) -{ - free(state); -} - -struct aggregate_stats_state { - struct ofp_aggregate_stats_request rq; -}; - -static int -aggregate_stats_init(const void *body, int body_len UNUSED, void **state) -{ - const struct ofp_aggregate_stats_request *rq = body; - struct aggregate_stats_state *s = xmalloc(sizeof *s); - s->rq = *rq; - *state = s; - return 0; -} - -static int aggregate_stats_dump_callback(struct sw_flow *flow, void *private) -{ - struct ofp_aggregate_stats_reply *rpy = private; - rpy->packet_count += flow->packet_count; - rpy->byte_count += flow->byte_count; - rpy->flow_count++; - return 0; -} - -static int aggregate_stats_dump(struct datapath *dp, void *state, - struct ofpbuf *buffer) -{ - struct aggregate_stats_state *s = state; - struct ofp_aggregate_stats_request *rq = &s->rq; - struct ofp_aggregate_stats_reply *rpy; - struct sw_table_position position; - struct sw_flow_key match_key; - int table_idx; - int error; - - rpy = ofpbuf_put_uninit(buffer, sizeof *rpy); - memset(rpy, 0, sizeof *rpy); - - flow_extract_match(&match_key, &rq->match); - table_idx = rq->table_id == 0xff ? 0 : rq->table_id; - memset(&position, 0, sizeof position); - - if (rq->table_id == EMERG_TABLE_ID_FOR_STATS) { - struct sw_table *table = dp->chain->emerg_table; - - error = table->iterate(table, &match_key, rq->out_port, &position, - aggregate_stats_dump_callback, rpy); - if (error) - return error; - } else { - while (table_idx < dp->chain->n_tables - && (rq->table_id == 0xff || rq->table_id == table_idx)) - { - struct sw_table *table = dp->chain->tables[table_idx]; - - error = table->iterate(table, &match_key, rq->out_port, &position, - aggregate_stats_dump_callback, rpy); - if (error) - return error; - - table_idx++; - memset(&position, 0, sizeof position); - } - } - - rpy->packet_count = htonll(rpy->packet_count); - rpy->byte_count = htonll(rpy->byte_count); - rpy->flow_count = htonl(rpy->flow_count); - return 0; -} - -static void aggregate_stats_done(void *state) -{ - free(state); -} - -static int -table_stats_dump(struct datapath *dp, void *state UNUSED, - struct ofpbuf *buffer) -{ - int i; - for (i = 0; i < dp->chain->n_tables; i++) { - struct ofp_table_stats *ots = ofpbuf_put_uninit(buffer, sizeof *ots); - struct sw_table_stats stats; - dp->chain->tables[i]->stats(dp->chain->tables[i], &stats); - strncpy(ots->name, stats.name, sizeof ots->name); - ots->table_id = i; - ots->wildcards = htonl(stats.wildcards); - memset(ots->pad, 0, sizeof ots->pad); - ots->max_entries = htonl(stats.max_flows); - ots->active_count = htonl(stats.n_flows); - ots->lookup_count = htonll(stats.n_lookup); - ots->matched_count = htonll(stats.n_matched); - } - return 0; -} - -struct port_stats_state { - int start_port; /* port to start dumping from */ - int port_no; /* from ofp_stats_request */ -}; - -struct queue_stats_state { - uint16_t port; - uint32_t queue_id; -}; - -static int -port_stats_init(const void *body, int body_len UNUSED, void **state) -{ - struct port_stats_state *s = xmalloc(sizeof *s); - const struct ofp_port_stats_request *psr = body; - - s->start_port = 1; - s->port_no = ntohs(psr->port_no); - *state = s; - return 0; -} - -static void -dump_port_stats(struct datapath *dp, struct sw_port *port, - struct ofpbuf *buffer) -{ - struct ofp_port_stats *ops = ofpbuf_put_uninit(buffer, sizeof *ops); - ops->port_no = htons(port->port_no); - memset(ops->pad, 0, sizeof ops->pad); - if (IS_HW_PORT(port)) { -#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) - struct ofp_port_stats stats; - - memset(&stats, 0, sizeof(stats)); - if (dp->hw_drv->port_stats_get) { - if (dp->hw_drv->port_stats_get(dp->hw_drv, port->port_no, - &stats) < 0) { - VLOG_WARN("Error getting stats on port %d\n", port->port_no); - return; - } - } - ops->rx_packets = htonll(stats.rx_packets); - ops->tx_packets = htonll(stats.tx_packets); - ops->rx_bytes = htonll(stats.rx_bytes); - ops->tx_bytes = htonll(stats.tx_bytes); - ops->rx_dropped = htonll(stats.rx_dropped); - ops->tx_dropped = htonll(stats.tx_dropped); - ops->rx_errors = htonll(stats.rx_errors); - ops->tx_errors = htonll(stats.tx_errors); - ops->rx_frame_err = htonll(stats.rx_frame_err); - ops->rx_over_err = htonll(stats.rx_over_err); - ops->rx_crc_err = htonll(stats.rx_crc_err); - ops->collisions = htonll(stats.collisions); -#endif - } else { - ops->rx_packets = htonll(port->rx_packets); - ops->tx_packets = htonll(port->tx_packets); - ops->rx_bytes = htonll(port->rx_bytes); - ops->tx_bytes = htonll(port->tx_bytes); - ops->rx_dropped = htonll(-1); - ops->tx_dropped = htonll(port->tx_dropped); - ops->rx_errors = htonll(-1); - ops->tx_errors = htonll(-1); - ops->rx_frame_err = htonll(-1); - ops->rx_over_err = htonll(-1); - ops->rx_crc_err = htonll(-1); - ops->collisions = htonll(-1); - } -} - -/* Although this makes some of the motions of being called - * multiple times preserving state, it doesn't actually support - * that process; the for loop can never break early. - */ -static int port_stats_dump(struct datapath *dp, void *state, - struct ofpbuf *buffer) -{ - struct port_stats_state *s = state; - struct sw_port *p = NULL; - int i = 0; - - if (s->port_no == OFPP_NONE) { - /* Dump statistics for all ports */ - for (i = s->start_port; i < DP_MAX_PORTS; i++) { - p = dp_lookup_port(dp, i); - if (p && PORT_IN_USE(p)) { - dump_port_stats(dp, p, buffer); - } - } - if (dp->local_port) { - dump_port_stats(dp, dp->local_port, buffer); - } - } else { - /* Dump statistics for a single port */ - p = dp_lookup_port(dp, s->port_no); - if (p && PORT_IN_USE(p)) { - dump_port_stats(dp, p, buffer); - } - } - - return 0; -} - -static void port_stats_done(void *state) -{ - free(state); -} - -static int -queue_stats_init(const void *body, int body_len UNUSED, void **state) -{ - const struct ofp_queue_stats_request *qsr = body; - struct queue_stats_state *s = xmalloc(sizeof *s); - s->port = ntohs(qsr->port_no); - s->queue_id = ntohl(qsr->queue_id); - *state = s; - return 0; -} - -static void -dump_queue_stats(struct sw_queue *q, struct ofpbuf *buffer) -{ - struct ofp_queue_stats *oqs = ofpbuf_put_uninit(buffer, sizeof *oqs); - oqs->port_no = htons(q->port->port_no); - oqs->queue_id = htonl(q->queue_id); - oqs->tx_bytes = htonll(q->tx_bytes); - oqs->tx_packets = htonll(q->tx_packets); - oqs->tx_errors = htonll(q->tx_errors); -} - -static int -queue_stats_dump(struct datapath *dp, void *state, - struct ofpbuf *buffer) -{ - struct queue_stats_state *s = state; - struct sw_queue *q; - struct sw_port *p; - - - if (s->port == OFPP_ALL) { - LIST_FOR_EACH(p, struct sw_port, node, &dp->port_list) { - if (p->port_no < OFPP_MAX) { - if (s->queue_id == OFPQ_ALL) { - LIST_FOR_EACH(q, struct sw_queue, node, &p->queue_list) { - dump_queue_stats(q,buffer); - } - } - else { - q = dp_lookup_queue(p, s->queue_id); - if (q) { - dump_queue_stats(q, buffer); - } - } - } - } - } - else { - p = dp_lookup_port(dp, s->port); - if (p) { - if (s->queue_id == OFPQ_ALL) { - LIST_FOR_EACH(q, struct sw_queue, node, &p->queue_list) { - dump_queue_stats(q,buffer); - } - } - else { - q = dp_lookup_queue(p, s->queue_id); - if (q) { - dump_queue_stats(q, buffer); - } - } - } - } - return 0; -} - -static void -queue_stats_done(void *state) -{ - free(state); -} - -/* - * We don't define any vendor_stats_state, we let the actual - * vendor implementation do that. - * The only requirement is that the first member of that object - * should be the vendor id. - * Jean II - * - * Basically, it would look like : - * struct acme_stats_state { - * uint32_t vendor; // ACME_VENDOR_ID. - * <...> // Other stuff. - * }; - */ -static int -vendor_stats_init(const void *body, int body_len UNUSED, - void **state UNUSED) -{ - /* min_body was checked, this should be safe */ - const uint32_t vendor = ntohl(*((uint32_t *)body)); - int err; - - switch (vendor) { - default: - err = -EINVAL; - } - - return err; -} - -static int -vendor_stats_dump(struct datapath *dp UNUSED, void *state, - struct ofpbuf *buffer UNUSED) -{ - const uint32_t vendor = *((uint32_t *)state); - int err; - - switch (vendor) { - default: - /* Should never happen */ - err = 0; - } - - return err; -} - -static void -vendor_stats_done(void *state) -{ - const uint32_t vendor = *((uint32_t *) state); - - switch (vendor) { - default: - /* Should never happen */ - free(state); - } - - return; -} - -struct stats_type { - /* Value for 'type' member of struct ofp_stats_request. */ - int type; - - /* Minimum and maximum acceptable number of bytes in body member of - * struct ofp_stats_request. */ - size_t min_body, max_body; - - /* Prepares to dump some kind of datapath statistics. 'body' and - * 'body_len' are the 'body' member of the struct ofp_stats_request. - * Returns zero if successful, otherwise a negative error code. - * May initialize '*state' to state information. May be null if no - * initialization is required.*/ - int (*init)(const void *body, int body_len, void **state); - - /* Appends statistics for 'dp' to 'buffer', which initially contains a - * struct ofp_stats_reply. On success, it should return 1 if it should be - * called again later with another buffer, 0 if it is done, or a negative - * errno value on failure. */ - int (*dump)(struct datapath *dp, void *state, struct ofpbuf *buffer); - - /* Cleans any state created by the init or dump functions. May be null - * if no cleanup is required. */ - void (*done)(void *state); -}; - -static const struct stats_type stats[] = { - { - OFPST_DESC, - 0, - 0, - NULL, - desc_stats_dump, - NULL - }, - { - OFPST_FLOW, - sizeof(struct ofp_flow_stats_request), - sizeof(struct ofp_flow_stats_request), - flow_stats_init, - flow_stats_dump, - flow_stats_done - }, - { - OFPST_AGGREGATE, - sizeof(struct ofp_aggregate_stats_request), - sizeof(struct ofp_aggregate_stats_request), - aggregate_stats_init, - aggregate_stats_dump, - aggregate_stats_done - }, - { - OFPST_TABLE, - 0, - 0, - NULL, - table_stats_dump, - NULL - }, - { - OFPST_PORT, - sizeof(struct ofp_port_stats_request), - sizeof(struct ofp_port_stats_request), - port_stats_init, - port_stats_dump, - port_stats_done - }, - { - OFPST_QUEUE, - sizeof(struct ofp_queue_stats_request), - sizeof(struct ofp_queue_stats_request), - queue_stats_init, - queue_stats_dump, - queue_stats_done - }, - { - OFPST_VENDOR, - 8, /* vendor + subtype */ - 32, /* whatever */ - vendor_stats_init, - vendor_stats_dump, - vendor_stats_done - }, -}; - -struct stats_dump_cb { - bool done; - struct ofp_stats_request *rq; - struct sender sender; - const struct stats_type *s; - void *state; -}; - -static int -stats_dump(struct datapath *dp, void *cb_) -{ - struct stats_dump_cb *cb = cb_; - struct ofp_stats_reply *osr; - struct ofpbuf *buffer; - int err; - - if (cb->done) { - return 0; - } - - osr = make_openflow_reply(sizeof *osr, OFPT_STATS_REPLY, &cb->sender, - &buffer); - osr->type = htons(cb->s->type); - osr->flags = 0; - - err = cb->s->dump(dp, cb->state, buffer); - if (err >= 0) { - int err2; - if (!err) { - cb->done = true; - } else { - /* Buffer might have been reallocated, so find our data again. */ - osr = ofpbuf_at_assert(buffer, 0, sizeof *osr); - osr->flags = ntohs(OFPSF_REPLY_MORE); - } - err2 = send_openflow_buffer(dp, buffer, &cb->sender); - if (err2) { - err = err2; - } - } - - return err; -} - -static void -stats_done(void *cb_) -{ - struct stats_dump_cb *cb = cb_; - if (cb) { - if (cb->s->done) { - cb->s->done(cb->state); - } - if (cb->rq) { - free(cb->rq); - } - free(cb); - } -} - -static int -recv_stats_request(struct datapath *dp UNUSED, const struct sender *sender, - const void *oh) -{ - const struct ofp_stats_request *rq = oh; - size_t rq_len = ntohs(rq->header.length); - const struct stats_type *st; - struct stats_dump_cb *cb; - int type, body_len; - int err; - - type = ntohs(rq->type); - for (st = stats; ; st++) { - if (st >= &stats[ARRAY_SIZE(stats)]) { - VLOG_WARN_RL(&rl, "received stats request of unknown type %d", - type); - return -EINVAL; - } else if (type == st->type) { - break; - } - } - - cb = xmalloc(sizeof *cb); - cb->done = false; - cb->rq = xmemdup(rq, rq_len); - cb->sender = *sender; - cb->s = st; - cb->state = NULL; - - body_len = rq_len - offsetof(struct ofp_stats_request, body); - if (body_len < cb->s->min_body || body_len > cb->s->max_body) { - VLOG_WARN_RL(&rl, "stats request type %d with bad body length %d", - type, body_len); - err = -EINVAL; - goto error; - } - - if (cb->s->init) { - err = cb->s->init(rq->body, body_len, &cb->state); - if (err) { - VLOG_WARN_RL(&rl, - "failed initialization of stats request type %d: %s", - type, strerror(-err)); - goto error; - } - } - - remote_start_dump(sender->remote, stats_dump, stats_done, cb); - return 0; - -error: - free(cb->rq); - free(cb); - return err; -} - -static int -recv_echo_request(struct datapath *dp, const struct sender *sender, - const void *oh) -{ - return send_openflow_buffer(dp, make_echo_reply(oh), sender); -} - -static int -recv_echo_reply(struct datapath *dp UNUSED, const struct sender *sender UNUSED, - const void *oh UNUSED) -{ - return 0; -} - -static int -recv_queue_get_config_request(struct datapath *dp, const struct sender *sender, - const void *oh) -{ - struct ofpbuf *buffer; - struct ofp_queue_get_config_reply *ofq_reply; - const struct ofp_queue_get_config_request *ofq_request; - struct sw_port *p; - struct sw_queue *q; - uint16_t port_no; - - ofq_request = (struct ofp_queue_get_config_request *)oh; - port_no = ntohs(ofq_request->port); - - if (port_no < OFPP_MAX) { - /* Find port under query */ - p = dp_lookup_port(dp,port_no); - - /* if the port under query doesn't exist, send an error */ - if (!p || (p->port_no != port_no)) { - dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, OFPQOFC_BAD_PORT, - oh, ntohs(ofq_request->header.length)); - goto error; - } - ofq_reply = make_openflow_reply(sizeof *ofq_reply, OFPT_QUEUE_GET_CONFIG_REPLY, - sender, &buffer); - ofq_reply->port = htons(port_no); - LIST_FOR_EACH(q, struct sw_queue, node, &p->queue_list) { - struct ofp_packet_queue * opq = ofpbuf_put_zeros(buffer, sizeof *opq); - fill_queue_desc(buffer, q, opq); - } - send_openflow_buffer(dp, buffer, sender); - } - else { - dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, OFPQOFC_BAD_PORT, - oh, ntohs(ofq_request->header.length)); - } - error: - return 0; -} - -static int -recv_vendor(struct datapath *dp, const struct sender *sender, - const void *oh) -{ - const struct ofp_vendor_header *ovh = oh; - - switch (ntohl(ovh->vendor)) - { - case PRIVATE_VENDOR_ID: - return private_recv_msg(dp, sender, oh); - - case OPENFLOW_VENDOR_ID: - return of_ext_recv_msg(dp, sender, oh); - - default: - VLOG_WARN_RL(&rl, "unknown vendor: 0x%x\n", ntohl(ovh->vendor)); - dp_send_error_msg(dp, sender, OFPET_BAD_REQUEST, - OFPBRC_BAD_VENDOR, oh, ntohs(ovh->header.length)); - return -EINVAL; - } -} - -/* 'msg', which is 'length' bytes long, was received from the control path. - * Apply it to 'chain'. */ -int -fwd_control_input(struct datapath *dp, const struct sender *sender, - const void *msg, size_t length) -{ - int (*handler)(struct datapath *, const struct sender *, const void *); - struct ofp_header *oh; - size_t min_size; - - /* Check encapsulated length. */ - oh = (struct ofp_header *) msg; - if (ntohs(oh->length) > length) { - return -EINVAL; - } - assert(oh->version == OFP_VERSION); - - /* Figure out how to handle it. */ - switch (oh->type) { - case OFPT_BARRIER_REQUEST: - min_size = sizeof(struct ofp_header); - handler = recv_barrier_request; - break; - case OFPT_FEATURES_REQUEST: - min_size = sizeof(struct ofp_header); - handler = recv_features_request; - break; - case OFPT_GET_CONFIG_REQUEST: - min_size = sizeof(struct ofp_header); - handler = recv_get_config_request; - break; - case OFPT_SET_CONFIG: - min_size = sizeof(struct ofp_switch_config); - handler = recv_set_config; - break; - case OFPT_PACKET_OUT: - min_size = sizeof(struct ofp_packet_out); - handler = recv_packet_out; - break; - case OFPT_FLOW_MOD: - min_size = sizeof(struct ofp_flow_mod); - handler = recv_flow; - break; - case OFPT_PORT_MOD: - min_size = sizeof(struct ofp_port_mod); - handler = recv_port_mod; - break; - case OFPT_STATS_REQUEST: - min_size = sizeof(struct ofp_stats_request); - handler = recv_stats_request; - break; - case OFPT_ECHO_REQUEST: - min_size = sizeof(struct ofp_header); - handler = recv_echo_request; - break; - case OFPT_ECHO_REPLY: - min_size = sizeof(struct ofp_header); - handler = recv_echo_reply; - break; - case OFPT_QUEUE_GET_CONFIG_REQUEST: - min_size = sizeof(struct ofp_header); - handler = recv_queue_get_config_request; - break; - case OFPT_VENDOR: - min_size = sizeof(struct ofp_vendor_header); - handler = recv_vendor; - break; - default: - dp_send_error_msg(dp, sender, OFPET_BAD_REQUEST, OFPBRC_BAD_TYPE, - msg, length); - return -EINVAL; - } - - /* Handle it. */ - if (length < min_size) - return -EFAULT; - return handler(dp, sender, msg); -} - -/* Packet buffering. */ - -#define OVERWRITE_SECS 1 - -struct packet_buffer { - struct ofpbuf *buffer; - uint32_t cookie; - time_t timeout; -}; - -static struct packet_buffer buffers[N_PKT_BUFFERS]; -static unsigned int buffer_idx; - -uint32_t save_buffer(struct ofpbuf *buffer) -{ - struct packet_buffer *p; - uint32_t id; - - buffer_idx = (buffer_idx + 1) & PKT_BUFFER_MASK; - p = &buffers[buffer_idx]; - if (p->buffer) { - /* Don't buffer packet if existing entry is less than - * OVERWRITE_SECS old. */ - if (time_now() < p->timeout) { /* FIXME */ - return (uint32_t)-1; - } else { - ofpbuf_delete(p->buffer); - } - } - /* Don't use maximum cookie value since the all-bits-1 id is - * special. */ - if (++p->cookie >= (1u << PKT_COOKIE_BITS) - 1) - p->cookie = 0; - p->buffer = ofpbuf_clone(buffer); /* FIXME */ - p->timeout = time_now() + OVERWRITE_SECS; /* FIXME */ - id = buffer_idx | (p->cookie << PKT_BUFFER_BITS); - - return id; -} - -static struct ofpbuf *retrieve_buffer(uint32_t id) -{ - struct ofpbuf *buffer = NULL; - struct packet_buffer *p; - - p = &buffers[id & PKT_BUFFER_MASK]; - if (p->cookie == id >> PKT_BUFFER_BITS) { - buffer = p->buffer; - p->buffer = NULL; - } else { - printf("cookie mismatch: %x != %x\n", - id >> PKT_BUFFER_BITS, p->cookie); - } - - return buffer; -} - -static void discard_buffer(uint32_t id) -{ - struct packet_buffer *p; - - p = &buffers[id & PKT_BUFFER_MASK]; - if (p->cookie == id >> PKT_BUFFER_BITS) { - ofpbuf_delete(p->buffer); - p->buffer = NULL; - } -} diff --git a/openflow/udatapath/datapath.h b/openflow/udatapath/datapath.h deleted file mode 100644 index c79c5ead..00000000 --- a/openflow/udatapath/datapath.h +++ /dev/null @@ -1,167 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -/* Interface exported by OpenFlow module. */ - -#ifndef DATAPATH_H -#define DATAPATH_H 1 - -#include -#include -#include "openflow/nicira-ext.h" -#include "ofpbuf.h" -#include "timeval.h" -#include "list.h" -#include "netdev.h" - -/* FIXME: Can declare struct of_hw_driver instead */ -#if defined(OF_HW_PLAT) -#include -#endif - -struct rconn; -struct pvconn; -struct sw_flow; -struct sender; - -struct sw_queue { - struct list node; /* element in port.queues */ - unsigned long long int tx_packets; - unsigned long long int tx_bytes; - unsigned long long int tx_errors; - uint32_t queue_id; - uint16_t class_id; /* internal mapping from OF queue_id to tc class_id */ - struct sw_port *port; /* reference to the parent port */ - /* keep it simple for now, only one property (assuming min_rate) */ - uint16_t property; /* one from OFPQT_ */ - uint16_t min_rate; -}; - -#define MAX_HW_NAME_LEN 32 -enum sw_port_flags { - SWP_USED = 1 << 0, /* Is port being used */ - SWP_HW_DRV_PORT = 1 << 1, /* Port controlled by HW driver */ -}; -#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) -#define IS_HW_PORT(p) ((p)->flags & SWP_HW_DRV_PORT) -#else -#define IS_HW_PORT(p) 0 -#endif - -#define PORT_IN_USE(p) (((p) != NULL) && (p)->flags & SWP_USED) - -struct sw_port { - uint32_t config; /* Some subset of OFPPC_* flags. */ - uint32_t state; /* Some subset of OFPPS_* flags. */ - uint32_t flags; /* SWP_* flags above */ - struct datapath *dp; - struct netdev *netdev; - char hw_name[OFP_MAX_PORT_NAME_LEN]; - struct list node; /* Element in datapath.ports. */ - unsigned long long int rx_packets, tx_packets; - unsigned long long int rx_bytes, tx_bytes; - unsigned long long int tx_dropped; - uint16_t port_no; - /* port queues */ - uint16_t num_queues; - struct sw_queue queues[NETDEV_MAX_QUEUES]; - struct list queue_list; /* list of all queues for this port */ -}; - -#if defined(OF_HW_PLAT) -struct hw_pkt_q_entry { - struct ofpbuf *buffer; - struct hw_pkt_q_entry *next; - of_port_t port_no; - int reason; -}; -#endif - -#define DP_MAX_PORTS 255 -BUILD_ASSERT_DECL(DP_MAX_PORTS <= OFPP_MAX); - -struct datapath { - /* Remote connections. */ - struct list remotes; /* All connections (including controller). */ - - /* Listeners. */ - struct pvconn **listeners; - size_t n_listeners; - - time_t last_timeout; - - /* Unique identifier for this datapath */ - uint64_t id; - char dp_desc[DESC_STR_LEN]; /* human readible comment to ID this DP */ - - struct sw_chain *chain; /* Forwarding rules. */ - - /* Configuration set from controller. */ - uint16_t flags; - uint16_t miss_send_len; - - /* Switch ports. */ - struct sw_port ports[DP_MAX_PORTS]; - struct sw_port *local_port; /* OFPP_LOCAL port, if any. */ - struct list port_list; /* All ports, including local_port. */ - -#if defined(OF_HW_PLAT) - /* Although the chain maintains the pointer to the HW driver - * for flow operations, the datapath needs the port functions - * in the driver structure - */ - of_hw_driver_t *hw_drv; - struct hw_pkt_q_entry *hw_pkt_list_head, *hw_pkt_list_tail; -#endif -}; - -int dp_new(struct datapath **, uint64_t dpid); -int dp_add_port(struct datapath *, const char *netdev, uint16_t); -int dp_add_local_port(struct datapath *, const char *netdev, uint16_t); -void dp_add_pvconn(struct datapath *, struct pvconn *); -void dp_run(struct datapath *); -void dp_wait(struct datapath *); -void dp_send_error_msg(struct datapath *, const struct sender *, - uint16_t, uint16_t, const void *, size_t); -void dp_send_flow_end(struct datapath *, struct sw_flow *, - enum ofp_flow_removed_reason); -void dp_output_port(struct datapath *, struct ofpbuf *, int in_port, - int out_port, uint32_t queue_id, bool ignore_no_fwd); -void dp_output_control(struct datapath *, struct ofpbuf *, int in_port, - size_t max_len, int reason); -struct sw_port * dp_lookup_port(struct datapath *, uint16_t); -struct sw_queue * dp_lookup_queue(struct sw_port *, uint32_t); - -int udatapath_cmd(int argc, char *argv[]); - -#endif /* datapath.h */ diff --git a/openflow/udatapath/dp_act.c b/openflow/udatapath/dp_act.c deleted file mode 100644 index d48beb10..00000000 --- a/openflow/udatapath/dp_act.c +++ /dev/null @@ -1,531 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -/* Functions for executing OpenFlow actions. */ - -#include -#include "csum.h" -#include "packets.h" -#include "dp_act.h" -#include "openflow/nicira-ext.h" - -static uint16_t -validate_output(struct datapath *dp UNUSED, const struct sw_flow_key *key, - const struct ofp_action_header *ah) -{ - struct ofp_action_output *oa = (struct ofp_action_output *)ah; - - /* To prevent loops, make sure there's no action to send to the - * OFP_TABLE virtual port. - */ - if (oa->port == htons(OFPP_NONE) || - (!(key->wildcards & OFPFW_IN_PORT) - && oa->port == key->flow.in_port)) { - return OFPBAC_BAD_OUT_PORT; - } - return ACT_VALIDATION_OK; -} - -static uint16_t -validate_queue(struct datapath *dp UNUSED, const struct sw_flow_key *key UNUSED, - const struct ofp_action_header *ah) -{ - struct ofp_action_enqueue *ea = (struct ofp_action_enqueue *)ah; - - /* Only physical ports may have queues. */ - if (ntohs(ea->port) > OFPP_MAX && ntohs(ea->port) != OFPP_IN_PORT) { - return OFPBAC_BAD_OUT_PORT; - } - return ACT_VALIDATION_OK; -} - -static void -do_output(struct datapath *dp, struct ofpbuf *buffer, int in_port, - size_t max_len, int out_port, uint32_t queue_id, - bool ignore_no_fwd) -{ - if (out_port != OFPP_CONTROLLER) { - dp_output_port(dp, buffer, in_port, out_port, queue_id, ignore_no_fwd); - } else { - dp_output_control(dp, buffer, in_port, max_len, OFPR_ACTION); - } -} - -/* Modify vlan tag control information (TCI). Only sets the TCI bits - * indicated by 'mask'. If no vlan tag is present, one is added. - */ -static void -modify_vlan_tci(struct ofpbuf *buffer, struct sw_flow_key *key, - uint16_t tci, uint16_t mask) -{ - struct vlan_eth_header *veh; - - if (key->flow.dl_vlan != htons(OFP_VLAN_NONE)) { - /* Modify vlan id, but maintain other TCI values */ - veh = buffer->l2; - veh->veth_tci &= ~htons(mask); - veh->veth_tci |= htons(tci); - } else { - /* Insert new vlan id. */ - struct eth_header *eh = buffer->l2; - struct vlan_eth_header tmp; - memcpy(tmp.veth_dst, eh->eth_dst, ETH_ADDR_LEN); - memcpy(tmp.veth_src, eh->eth_src, ETH_ADDR_LEN); - tmp.veth_type = htons(ETH_TYPE_VLAN); - tmp.veth_tci = htons(tci); - tmp.veth_next_type = eh->eth_type; - - veh = ofpbuf_push_uninit(buffer, VLAN_HEADER_LEN); - memcpy(veh, &tmp, sizeof tmp); - buffer->l2 = (char*)buffer->l2 - VLAN_HEADER_LEN; - } - - key->flow.dl_vlan = veh->veth_tci & htons(VLAN_VID_MASK); - key->flow.dl_vlan_pcp = (uint8_t)((ntohs(veh->veth_tci) >> VLAN_PCP_SHIFT) - & VLAN_PCP_BITMASK); -} - - -/* Remove an existing vlan header if it exists. */ -static void -vlan_pull_tag(struct ofpbuf *buffer) -{ - struct vlan_eth_header *veh = buffer->l2; - - if (veh->veth_type == htons(ETH_TYPE_VLAN)) { - struct eth_header tmp; - - memcpy(tmp.eth_dst, veh->veth_dst, ETH_ADDR_LEN); - memcpy(tmp.eth_src, veh->veth_src, ETH_ADDR_LEN); - tmp.eth_type = veh->veth_next_type; - - buffer->size -= VLAN_HEADER_LEN; - buffer->data = (char*)buffer->data + VLAN_HEADER_LEN; - buffer->l2 = (char*)buffer->l2 + VLAN_HEADER_LEN; - memcpy(buffer->data, &tmp, sizeof tmp); - } -} - -static void -set_vlan_vid(struct ofpbuf *buffer, struct sw_flow_key *key, - const struct ofp_action_header *ah) -{ - struct ofp_action_vlan_vid *va = (struct ofp_action_vlan_vid *)ah; - uint16_t tci = ntohs(va->vlan_vid); - - modify_vlan_tci(buffer, key, tci, VLAN_VID_MASK); -} - -static void -set_vlan_pcp(struct ofpbuf *buffer, struct sw_flow_key *key, - const struct ofp_action_header *ah) -{ - struct ofp_action_vlan_pcp *va = (struct ofp_action_vlan_pcp *)ah; - uint16_t tci = (uint16_t)va->vlan_pcp << 13; - - modify_vlan_tci(buffer, key, tci, VLAN_PCP_MASK); -} - -static void -strip_vlan(struct ofpbuf *buffer, struct sw_flow_key *key, - const struct ofp_action_header *ah UNUSED) -{ - vlan_pull_tag(buffer); - key->flow.dl_vlan = htons(OFP_VLAN_NONE); -} - -static void -set_dl_addr(struct ofpbuf *buffer, struct sw_flow_key *key UNUSED, - const struct ofp_action_header *ah) -{ - struct ofp_action_dl_addr *da = (struct ofp_action_dl_addr *)ah; - struct eth_header *eh = buffer->l2; - - if (da->type == htons(OFPAT_SET_DL_SRC)) { - memcpy(eh->eth_src, da->dl_addr, sizeof eh->eth_src); - } else { - memcpy(eh->eth_dst, da->dl_addr, sizeof eh->eth_dst); - } -} - -static void -set_nw_addr(struct ofpbuf *buffer, struct sw_flow_key *key, - const struct ofp_action_header *ah) -{ - struct ofp_action_nw_addr *na = (struct ofp_action_nw_addr *)ah; - uint16_t eth_proto = ntohs(key->flow.dl_type); - - if (eth_proto == ETH_TYPE_IP) { - struct ip_header *nh = buffer->l3; - uint8_t nw_proto = key->flow.nw_proto; - uint32_t new, *field; - - new = na->nw_addr; - field = na->type == htons(OFPAT_SET_NW_SRC) ? &nh->ip_src : &nh->ip_dst; - if (nw_proto == IP_TYPE_TCP) { - struct tcp_header *th = buffer->l4; - th->tcp_csum = recalc_csum32(th->tcp_csum, *field, new); - } else if (nw_proto == IP_TYPE_UDP) { - struct udp_header *th = buffer->l4; - if (th->udp_csum) { - th->udp_csum = recalc_csum32(th->udp_csum, *field, new); - if (!th->udp_csum) { - th->udp_csum = 0xffff; - } - } - } - nh->ip_csum = recalc_csum32(nh->ip_csum, *field, new); - *field = new; - } -} - -static void -set_nw_tos(struct ofpbuf *buffer, struct sw_flow_key *key, - const struct ofp_action_header *ah) -{ - struct ofp_action_nw_tos *nt = (struct ofp_action_nw_tos *)ah; - uint16_t eth_proto = ntohs(key->flow.dl_type); - - if (eth_proto == ETH_TYPE_IP) { - struct ip_header *nh = buffer->l3; - uint8_t new, *field; - - /* JeanII : Set only 6 bits, don't clobber ECN */ - new = (nt->nw_tos & 0xFC) | (nh->ip_tos & 0x03); - - /* Get address of field */ - field = &nh->ip_tos; - - /* jklee : ip tos field is not included in TCP pseudo header. - * Need magic as update_csum() don't work with 8 bits. */ - nh->ip_csum = recalc_csum32(nh->ip_csum, htons((uint16_t)*field), - htons((uint16_t)new)); - - /* Change the IP ToS bits */ - *field = new; - } -} - -static void -set_tp_port(struct ofpbuf *buffer, struct sw_flow_key *key, - const struct ofp_action_header *ah) -{ - struct ofp_action_tp_port *ta = (struct ofp_action_tp_port *)ah; - uint16_t eth_proto = ntohs(key->flow.dl_type); - - if (eth_proto == ETH_TYPE_IP) { - uint8_t nw_proto = key->flow.nw_proto; - uint16_t new, *field; - - new = ta->tp_port; - if (nw_proto == IP_TYPE_TCP) { - struct tcp_header *th = buffer->l4; - field = ta->type == htons(OFPAT_SET_TP_SRC) ? &th->tcp_src : &th->tcp_dst; - th->tcp_csum = recalc_csum16(th->tcp_csum, *field, new); - *field = new; - } else if (nw_proto == IP_TYPE_UDP) { - struct udp_header *th = buffer->l4; - field = ta->type == htons(OFPAT_SET_TP_SRC) ? &th->udp_src : &th->udp_dst; - th->udp_csum = recalc_csum16(th->udp_csum, *field, new); - *field = new; - } - } -} - -struct openflow_action { - size_t min_size; - size_t max_size; - uint16_t (*validate)(struct datapath *dp, - const struct sw_flow_key *key, - const struct ofp_action_header *ah); - void (*execute)(struct ofpbuf *buffer, - struct sw_flow_key *key, - const struct ofp_action_header *ah); -}; - -static const struct openflow_action of_actions[] = { - [OFPAT_OUTPUT] = { - sizeof(struct ofp_action_output), - sizeof(struct ofp_action_output), - validate_output, - NULL /* This is optimized into execute_actions */ - }, - [OFPAT_ENQUEUE] = { - sizeof(struct ofp_action_enqueue), - sizeof(struct ofp_action_enqueue), - validate_queue, - NULL /* This is optimized into execute_actions */ - }, - [OFPAT_SET_VLAN_VID] = { - sizeof(struct ofp_action_vlan_vid), - sizeof(struct ofp_action_vlan_vid), - NULL, - set_vlan_vid - }, - [OFPAT_SET_VLAN_PCP] = { - sizeof(struct ofp_action_vlan_pcp), - sizeof(struct ofp_action_vlan_pcp), - NULL, - set_vlan_pcp - }, - [OFPAT_STRIP_VLAN] = { - sizeof(struct ofp_action_header), - sizeof(struct ofp_action_header), - NULL, - strip_vlan - }, - [OFPAT_SET_DL_SRC] = { - sizeof(struct ofp_action_dl_addr), - sizeof(struct ofp_action_dl_addr), - NULL, - set_dl_addr - }, - [OFPAT_SET_DL_DST] = { - sizeof(struct ofp_action_dl_addr), - sizeof(struct ofp_action_dl_addr), - NULL, - set_dl_addr - }, - [OFPAT_SET_NW_SRC] = { - sizeof(struct ofp_action_nw_addr), - sizeof(struct ofp_action_nw_addr), - NULL, - set_nw_addr - }, - [OFPAT_SET_NW_DST] = { - sizeof(struct ofp_action_nw_addr), - sizeof(struct ofp_action_nw_addr), - NULL, - set_nw_addr - }, - [OFPAT_SET_NW_TOS] = { - sizeof(struct ofp_action_nw_tos), - sizeof(struct ofp_action_nw_tos), - NULL, - set_nw_tos - }, - [OFPAT_SET_TP_SRC] = { - sizeof(struct ofp_action_tp_port), - sizeof(struct ofp_action_tp_port), - NULL, - set_tp_port - }, - [OFPAT_SET_TP_DST] = { - sizeof(struct ofp_action_tp_port), - sizeof(struct ofp_action_tp_port), - NULL, - set_tp_port - } - /* OFPAT_VENDOR is not here, since it would blow up the array size. */ -}; - -/* Validate built-in OpenFlow actions. Either returns ACT_VALIDATION_OK - * or an OFPET_BAD_ACTION error code. */ -static uint16_t -validate_ofpat(struct datapath *dp, const struct sw_flow_key *key, - const struct ofp_action_header *ah, uint16_t type, uint16_t len) -{ - uint16_t ret = ACT_VALIDATION_OK; - const struct openflow_action *act = &of_actions[type]; - - if ((len < act->min_size) || (len > act->max_size)) { - return OFPBAC_BAD_LEN; - } - - if (act->validate) { - ret = act->validate(dp, key, ah); - } - - return ret; -} - -/* Validate vendor-defined actions. Either returns ACT_VALIDATION_OK - * or an OFPET_BAD_ACTION error code. */ -static uint16_t -validate_vendor(struct datapath *dp UNUSED, const struct sw_flow_key *key UNUSED, - const struct ofp_action_header *ah, uint16_t len) -{ - struct ofp_action_vendor_header *avh; - int ret = ACT_VALIDATION_OK; - - if (len < sizeof(struct ofp_action_vendor_header)) { - return OFPBAC_BAD_LEN; - } - - avh = (struct ofp_action_vendor_header *)ah; - - switch(ntohl(avh->vendor)) { - default: - return OFPBAC_BAD_VENDOR; - } - - return ret; -} - -/* Validates a list of actions. If a problem is found, a code for the - * OFPET_BAD_ACTION error type is returned. If the action list validates, - * ACT_VALIDATION_OK is returned. */ -uint16_t -validate_actions(struct datapath *dp, const struct sw_flow_key *key, - const struct ofp_action_header *actions, size_t actions_len) -{ - uint8_t *p = (uint8_t *)actions; - int err; - - while (actions_len >= sizeof(struct ofp_action_header)) { - struct ofp_action_header *ah = (struct ofp_action_header *)p; - size_t len = ntohs(ah->len); - uint16_t type; - - /* Make there's enough remaining data for the specified length - * and that the action length is a multiple of 64 bits. */ - if ((actions_len < len) || (len % 8) != 0) { - return OFPBAC_BAD_LEN; - } - - type = ntohs(ah->type); - if (type < ARRAY_SIZE(of_actions)) { - err = validate_ofpat(dp, key, ah, type, len); - if (err != ACT_VALIDATION_OK) { - return err; - } - } else if (type == OFPAT_VENDOR) { - err = validate_vendor(dp, key, ah, len); - if (err != ACT_VALIDATION_OK) { - return err; - } - } else { - return OFPBAC_BAD_TYPE; - } - - p += len; - actions_len -= len; - } - - /* Check if there's any trailing garbage. */ - if (actions_len != 0) { - return OFPBAC_BAD_LEN; - } - - return ACT_VALIDATION_OK; -} - -/* Execute a built-in OpenFlow action against 'buffer'. */ -static void -execute_ofpat(struct ofpbuf *buffer, struct sw_flow_key *key, - const struct ofp_action_header *ah, uint16_t type) -{ - const struct openflow_action *act = &of_actions[type]; - - if (act->execute) { - act->execute(buffer, key, ah); - } -} - -/* Execute a vendor-defined action against 'buffer'. */ -static void -execute_vendor(struct ofpbuf *buffer UNUSED, const struct sw_flow_key *key UNUSED, - const struct ofp_action_header *ah) -{ - struct ofp_action_vendor_header *avh - = (struct ofp_action_vendor_header *)ah; - - switch(ntohl(avh->vendor)) { - default: - /* This should not be possible due to prior validation. */ - printf("attempt to execute action with unknown vendor: %#x\n", - ntohl(avh->vendor)); - break; - } -} - -/* Execute a list of actions against 'buffer'. */ -void execute_actions(struct datapath *dp, struct ofpbuf *buffer, - struct sw_flow_key *key, - const struct ofp_action_header *actions, size_t actions_len, - int ignore_no_fwd) -{ - /* Every output action needs a separate clone of 'buffer', but the common - * case is just a single output action, so that doing a clone and then - * freeing the original buffer is wasteful. So the following code is - * slightly obscure just to avoid that. */ - int prev_port; - uint32_t prev_queue; - size_t max_len = UINT16_MAX; - uint16_t in_port = ntohs(key->flow.in_port); - uint8_t *p = (uint8_t *)actions; - - prev_port = -1; - prev_queue = 0; - - /* The action list was already validated, so we can be a bit looser - * in our sanity-checking. */ - while (actions_len > 0) { - struct ofp_action_header *ah = (struct ofp_action_header *)p; - size_t len = htons(ah->len); - - if (prev_port != -1) { - do_output(dp, ofpbuf_clone(buffer), in_port, max_len, - prev_port, prev_queue, ignore_no_fwd); - prev_port = -1; - } - - if (ah->type == htons(OFPAT_OUTPUT)) { - struct ofp_action_output *oa = (struct ofp_action_output *)p; - prev_port = ntohs(oa->port); - prev_queue = 0; /* using the default best-effort queue */ - max_len = ntohs(oa->max_len); - } else if (ah->type == htons(OFPAT_ENQUEUE)) { - struct ofp_action_enqueue *ea = (struct ofp_action_enqueue *)p; - prev_port = ntohs(ea->port); - prev_queue = ntohl(ea->queue_id); - max_len = 0; /* we will not send to the controller anyways - useless */ - } else { - uint16_t type = ntohs(ah->type); - - if (type < ARRAY_SIZE(of_actions)) { - execute_ofpat(buffer, key, ah, type); - } else if (type == OFPAT_VENDOR) { - execute_vendor(buffer, key, ah); - } - } - - p += len; - actions_len -= len; - } - if (prev_port != -1) { - do_output(dp, buffer, in_port, max_len, prev_port, prev_queue, ignore_no_fwd); - } else { - ofpbuf_delete(buffer); - } -} diff --git a/openflow/udatapath/dp_act.h b/openflow/udatapath/dp_act.h deleted file mode 100644 index e0181fad..00000000 --- a/openflow/udatapath/dp_act.h +++ /dev/null @@ -1,49 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#ifndef DP_ACT_H -#define DP_ACT_H 1 - -#include "openflow/openflow.h" -#include "switch-flow.h" -#include "datapath.h" - -#define ACT_VALIDATION_OK ((uint16_t)-1) - -uint16_t validate_actions(struct datapath *, const struct sw_flow_key *, - const struct ofp_action_header *, size_t); -void execute_actions(struct datapath *, struct ofpbuf *, - struct sw_flow_key *, const struct ofp_action_header *, - size_t action_len, int ignore_no_fwd); - -#endif /* dp_act.h */ diff --git a/openflow/udatapath/of_ext_msg.c b/openflow/udatapath/of_ext_msg.c deleted file mode 100644 index 36d587be..00000000 --- a/openflow/udatapath/of_ext_msg.c +++ /dev/null @@ -1,267 +0,0 @@ -/* Copyright (c) 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include -#include "openflow/openflow-ext.h" -#include "of_ext_msg.h" -#include "netdev.h" -#include "datapath.h" - -#define THIS_MODULE VLM_experimental -#include "vlog.h" - -static int -new_queue(struct sw_port * port, struct sw_queue * queue, - uint32_t queue_id, uint16_t class_id, - struct ofp_queue_prop_min_rate * mr) -{ - memset(queue, '\0', sizeof *queue); - queue->port = port; - queue->queue_id = queue_id; - /* class_id is the internal mapping to class. It is the offset - * in the array of queues for each port. Note that class_id is - * local to port, so we don't have any conflict. - * tc uses 16-bit class_id, so we cannot use the queue_id - * field */ - queue->class_id = class_id; - queue->property = ntohs(mr->prop_header.property); - queue->min_rate = ntohs(mr->rate); - - list_push_back(&port->queue_list, &queue->node); - - return 0; -} - -static int -port_add_queue(struct sw_port *p, uint32_t queue_id, - struct ofp_queue_prop_min_rate * mr) -{ - int queue_no; - for (queue_no = 1; queue_no < p->num_queues; queue_no++) { - struct sw_queue *q = &p->queues[queue_no]; - if (!q->port) { - return new_queue(p,q,queue_id,queue_no,mr); - } - } - return EXFULL; -} - -static int -port_delete_queue(struct sw_port *p UNUSED, struct sw_queue *q) -{ - list_remove(&q->node); - memset(q,'\0', sizeof *q); - return 0; -} - -static void -recv_of_exp_queue_delete(struct datapath *dp, - const struct sender *sender, - const void *oh) -{ - struct sw_port *p; - struct sw_queue *q; - struct openflow_queue_command_header * ofq_delete; - struct ofp_packet_queue *opq; - - uint16_t port_no; - uint32_t queue_id; - - ofq_delete = (struct openflow_queue_command_header *)oh; - opq = (struct ofp_packet_queue *)ofq_delete->body; - port_no = ntohs(ofq_delete->port); - queue_id = ntohl(opq->queue_id); - - p = dp_lookup_port(dp,port_no); - if (p->netdev) { - q = dp_lookup_queue(p,queue_id); - if (q) { - netdev_delete_class(p->netdev,q->class_id); - port_delete_queue(p,q); - } - else { - dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, - OFPQOFC_BAD_PORT, oh, - ntohs(ofq_delete->header.header.length)); - } - } - else { - dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, - OFPQOFC_BAD_PORT, oh, - ntohs(ofq_delete->header.header.length)); - } -} - -/** Modifies/adds a queue. It first searches if a queue with - * id exists for this port. If yes it modifies it, otherwise adds - * a new configuration. - * - * @param dp the related datapath - * @param sender request source - * @param oh the openflow message for queue mod. - */ -static void -recv_of_exp_queue_modify(struct datapath *dp, - const struct sender *sender UNUSED, - const void *oh) -{ - struct sw_port *p; - struct sw_queue *q; - struct openflow_queue_command_header * ofq_modify; - struct ofp_packet_queue *opq; - struct ofp_queue_prop_min_rate *mr; - - int error = 0; - uint16_t port_no; - uint32_t queue_id; - - - ofq_modify = (struct openflow_queue_command_header *)oh; - opq = (struct ofp_packet_queue *)ofq_modify->body; - mr = (struct ofp_queue_prop_min_rate*)opq->properties; - - /* Currently, we only accept queues with a single, min-rate property */ - if ((ntohs(opq->len) != 24) || - ntohs(mr->prop_header.property) != OFPQT_MIN_RATE) { - VLOG_ERR("Unknown queue configuration"); - dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, - OFQ_ERR_DISCIPLINE, oh, - ntohs(ofq_modify->header.header.length)); - return; - } - - - - port_no = ntohs(ofq_modify->port); - queue_id = ntohl(opq->queue_id); - - p = dp_lookup_port(dp, port_no); - if (PORT_IN_USE(p)) { - q = dp_lookup_queue(p, queue_id); - if (q) { - /* queue exists - modify it */ - error = netdev_change_class(p->netdev,q->class_id, ntohs(mr->rate)); - if (error) { - VLOG_ERR("Failed to update queue %d", queue_id); - dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, - OFPQOFC_EPERM, oh, - ntohs(ofq_modify->header.header.length)); - } - else { - q->property = ntohs(mr->prop_header.property); - q->min_rate = ntohs(mr->rate); - } - } - else { - /* create new queue */ - error = port_add_queue(p,queue_id, mr); - if (error == EXFULL) { - dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, - OFPQOFC_EPERM, oh, - ntohs(ofq_modify->header.header.length)); - return; - } - q = dp_lookup_queue(p, queue_id); - error = netdev_setup_class(p->netdev,q->class_id, ntohs(mr->rate)); - if (error) { - VLOG_ERR("Failed to configure queue %d", queue_id); - dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, - OFPQOFC_BAD_QUEUE, oh, - ntohs(ofq_modify->header.header.length)); - } - } - } - else { - dp_send_error_msg(dp, sender, OFPET_QUEUE_OP_FAILED, OFPQOFC_BAD_PORT, - oh, ntohs(ofq_modify->header.header.length)); - VLOG_ERR("Failed to create/modify queue - port %d doesn't exist", - port_no); - } - if (!error) { - if (IS_HW_PORT(p)) { -#if defined(OF_HW_PLAT) && !defined(USE_NETDEV) - error = dp->hw_drv->port_queue_config(dp->hw_drv, port_no, - queue_id, ntohs(mr->rate)); - if (error < 0) { - VLOG_ERR("Failed to update HW port %d queue %d", - port_no, queue_id); - } -#endif - } - } -} -/** - * Parses a set dp_desc message and uses it to set - * the dp_desc string in dp - */ -static void -recv_of_set_dp_desc(struct datapath *dp, - const struct sender *sender UNUSED, - const struct ofp_extension_header * exth) -{ - struct openflow_ext_set_dp_desc * set_dp_desc = (struct openflow_ext_set_dp_desc * ) - exth; - strncpy(dp->dp_desc, set_dp_desc->dp_desc, DESC_STR_LEN); - dp->dp_desc[DESC_STR_LEN-1] = 0; // force null for safety -} - -/** - * Receives an experimental message and pass it - * to the appropriate handler - */ -int of_ext_recv_msg(struct datapath *dp, const struct sender *sender, - const void *oh) -{ - const struct ofp_extension_header *ofexth = oh; - - switch (ntohl(ofexth->subtype)) { - case OFP_EXT_QUEUE_MODIFY: { - recv_of_exp_queue_modify(dp,sender,oh); - return 0; - } - case OFP_EXT_QUEUE_DELETE: { - recv_of_exp_queue_delete(dp,sender,oh); - return 0; - } - case OFP_EXT_SET_DESC: - recv_of_set_dp_desc(dp,sender,ofexth); - return 0; - default: - VLOG_ERR("Received unknown command of type %d", - ntohl(ofexth->subtype)); - return -EINVAL; - } - - return -EINVAL; -} diff --git a/openflow/udatapath/of_ext_msg.h b/openflow/udatapath/of_ext_msg.h deleted file mode 100644 index 510615d7..00000000 --- a/openflow/udatapath/of_ext_msg.h +++ /dev/null @@ -1,43 +0,0 @@ -/* Copyright (c) 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#ifndef OF_EXT_MSG_H -#define OF_EXT_MSG_H 1 - -#include "datapath.h" - -struct sender; - -int of_ext_recv_msg(struct datapath *, const struct sender *, const void *); - -#endif /* of_ext_msg.h */ diff --git a/openflow/udatapath/ofdatapath.8.in b/openflow/udatapath/ofdatapath.8.in deleted file mode 100644 index 55d6b4ba..00000000 --- a/openflow/udatapath/ofdatapath.8.in +++ /dev/null @@ -1,148 +0,0 @@ -.ds PN ofdatapath - -.TH ofdatapath 8 "May 2008" "OpenFlow" "OpenFlow Manual" - -.SH NAME -ofdatapath \- userspace implementation of datapath for OpenFlow switch - -.SH SYNOPSIS -.B ofdatapath -[\fIoptions\fR] -\fB-i\fR \fInetdev\fR[\fB,\fInetdev\fR].\|.\|. -\fImethod\fR [\fImethod\fR].\|.\|. - -.SH DESCRIPTION -The \fBofdatapath\fR is a userspace implementation of an OpenFlow -datapath. It monitors one or more network device interfaces, -forwarding packets between them according to the entries in the flow -table that it maintains. When it is used with \fBofprotocol\fR(8), to -connect the datapath to an OpenFlow controller, the combination is an -OpenFlow switch. - -For access to network devices, the ofdatapath program must normally run as -root. - -The mandatory \fImethod\fR argument specifies how \fBofprotocol\fR(8) -communicates with \fBofdatapath\fR, as a passive OpenFlow connection -method. Ordinarily \fImethod\fR takes the following form: - -.TP -\fBpunix:\fIfile\fR -Listens for connections on the Unix domain server socket named -\fIfile\fR. - -.PP -The following connection methods are also supported, but their use -would be unusual because \fBofdatapath\fR and \fBofprotocol\fR should run -on the same machine: - -.TP -\fBpssl:\fR[\fIport\fR] -Listens for SSL connections \fIport\fR (default: 976). The -\fB--private-key\fR, \fB--certificate\fR, and \fB--ca-cert\fR options -are mandatory when this form is used. (\fBofp\-pki\fR(8) does not set -up a suitable PKI for use with this option.) - -.TP -\fBptcp:\fR[\fIport\fR] -Listens for TCP connections from remote OpenFlow switches on -\fIport\fR (default: 975). - -.SH OPTIONS -.TP -\fB-i\fR, \fB--interfaces=\fR\fInetdev\fR[\fB,\fInetdev\fR].\|.\|. -Specifies each \fInetdev\fR (e.g., \fBeth0\fR) as a switch port. The -specified network devices should not have any configured IP addresses. -This option may be given any number of times to specify additional -network devices. - -.TP -\fB-L\fR, \fB--local-port=\fInetdev\fR -Specifies the network device to use as the userspace datapath's -``local port,'' which is a network device that \fBofprotocol\fR(8) -bridges to the physical switch ports for use in in-band control. When -this option is not specified, the default is \fBtap:\fR, which causes -a new TAP virtual network device to be allocated with a default name -assigned by the kernel. To do the same, but assign a specific name -\fBname\fR to the TAP network device, specify the option as -\fB--local-port=tap:\fIname\fR. - -Either way, the existence of TAP devices created by \fBofdatapath\fR is -temporary: they are destroyed when \fBofdatapath\fR exits. If this is -undesirable, you may use \fBtunctl\fR(8) to create a persistent TAP -network device and then pass it to \fBofdatapath\fR, like so: - -.RS -.IP 1. -Create a persistent TAP network device: \fBtunctl -t mytap\fR. (The -\fBtunctl\fR(8) utility is part of User Mode Linux. It is not -included with the OpenFlow reference implementation.) -.IP 2. -Invoke \fBofdatapath\fR(8) using \fBmytap\fR, e.g. \fBofdatapath ---local-port=mytap\fR .\|.\|. (Note the lack of \fBtap:\fR prefix on -the \fB--local-port\fR argument.) -.IP 3. -Invoke \fBofprotocol\fR(8), etc., and use the switch as desired. -.IP 4. -When \fBofprotocol\fR and \fBofdatapath\fR have terminated and the TAP -network device is no longer needed, you may destroy it with: \fBtunctl --d mytap\fR -.RE - -.IP -It does not ordinarily make sense to specify the name of a physical -network device on \fB-L\fR or \fB--local-port\fR. - -.TP -\fB--no-local-port\fR -Do not provide a local port as part of the datapath. When this option -is used, the switch will not support in-band control. - -.TP -\fB--no-slicing\fR -Disable slicing (no queue configuration to ports). When this option -is used, the switch will have 0 queues, and therefore no -slicing-related functionality is supported. This option is useful when -run-time dependencies for slicing (tc and related kernel -configuration) are not met. - -.TP -\fB-d\fR, \fB--datapath-id=\fIdpid\fR -Specifies the OpenFlow datapath ID (a 48-bit number that uniquely -identifies a controller) as \fIdpid\fR, which consists of exactly 12 -hex digits. Without this option, \fBofdatapath\fR picks an ID randomly. - -.TP -\fB-p\fR, \fB--private-key=\fIprivkey.pem\fR -Specifies a PEM file containing the private key used as the datapath's -identity for SSL connections to \fBofprotocol\fR(8). - -.TP -\fB-c\fR, \fB--certificate=\fIcert.pem\fR -Specifies a PEM file containing a certificate, signed by the -datapath's certificate authority (CA), that certifies the datapath's -private key to identify a trustworthy datapath. - -.TP -\fB-C\fR, \fB--ca-cert=\fIcacert.pem\fR -Specifies a PEM file containing the CA certificate used to verify that -the datapath is connected to a trustworthy secure channel. - -.so lib/daemon.man -.so lib/vlog.man -.so lib/common.man - -.SH BUGS -The userspace datapath's performance lags significantly behind that of -the kernel-based switch. It should only be used when the kernel-based -switch cannot be. - -On Linux, general-purpose support for VLAN tag rewriting is precluded -by the Linux kernel AF_PACKET implementation. - -.SH "SEE ALSO" - -.BR ofprotocol (8), -.BR dpctl (8), -.BR controller (8), -.BR vlogconf (8). diff --git a/openflow/udatapath/private-msg.c b/openflow/udatapath/private-msg.c deleted file mode 100644 index 7e868671..00000000 --- a/openflow/udatapath/private-msg.c +++ /dev/null @@ -1,140 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#include -#include - -#include "openflow/private-ext.h" - -#include "chain.h" -#include "datapath.h" -#include "switch-flow.h" -#include "table.h" -#include "private-msg.h" - -struct emerg_flow_context { - struct datapath *dp; -}; - -static void flush_working(struct datapath *); -static int protection_callback(struct sw_flow *, void *); -static void do_protection(struct datapath *); - -static void -flush_working(struct datapath *dp) -{ - struct sw_flow_key key; - int num_deleted = 0; - - memset(&key, 0, sizeof(key)); - key.wildcards = OFPFW_ALL; - num_deleted = chain_delete(dp->chain, &key, OFPP_NONE, 0, 0, 0); -} - -static int -protection_callback(struct sw_flow *flow, void *private_) -{ - struct emerg_flow_context *private - = (struct emerg_flow_context *)private_; - struct sw_flow_actions *actions = flow->sf_acts; - struct ofp_match match; - struct sw_flow *tgtflow = NULL; - int error = 0; - - tgtflow = flow_alloc(flow->sf_acts->actions_len); - if (tgtflow == NULL) - return -ENOBUFS; - - /* Dup w/o idle and hard timeout. */ - memset(&match, 0, sizeof(match)); - flow_fill_match(&match, &flow->key.flow, flow->key.wildcards); - flow_extract_match(&tgtflow->key, &match); - /* Fill out flow. */ - tgtflow->priority = flow->priority; - tgtflow->idle_timeout = OFP_FLOW_PERMANENT; - tgtflow->hard_timeout = OFP_FLOW_PERMANENT; - tgtflow->send_flow_rem = flow->send_flow_rem; - tgtflow->emerg_flow = 0; - flow_setup_actions(tgtflow, actions->actions, actions->actions_len); - - error = chain_insert(private->dp->chain, tgtflow, 0); - if (error) - flow_free(tgtflow); - - return error; -} - -static void -do_protection(struct datapath *dp) -{ - struct emerg_flow_context private; - struct sw_flow_key key; - struct sw_table_position position; - struct sw_table *table = dp->chain->emerg_table; - int error = 0; - - memset(&private, 0, sizeof(private)); - private.dp = dp; - memset(&key, 0, sizeof(key)); - key.wildcards = OFPFW_ALL; - memset(&position, 0, sizeof(position)); - - error = table->iterate(table, &key, OFPP_NONE, - &position, protection_callback, &private); -} - -int -private_recv_msg(struct datapath *dp, const struct sender *sender UNUSED, - const void *ofph) -{ - struct private_vxhdr *vxhdr = (struct private_vxhdr *)ofph; - struct private_vxopt *vxopt = (struct private_vxopt *)(vxhdr + 1); - int error = 0; - - switch (ntohs(vxopt->pvo_type)) { - case PRIVATEOPT_PROTOCOL_STATS_REQUEST: - case PRIVATEOPT_PROTOCOL_STATS_REPLY: - break; - case PRIVATEOPT_EMERG_FLOW_PROTECTION: - flush_working(dp); - do_protection(dp); - break; - case PRIVATEOPT_EMERG_FLOW_RESTORATION: - /* Nothing to do because we assume that a re-connected - * controller will do flush current working flow table. */ - break; - default: - error = -EINVAL; - } - - return error; -} diff --git a/openflow/udatapath/private-msg.h b/openflow/udatapath/private-msg.h deleted file mode 100644 index 082a4531..00000000 --- a/openflow/udatapath/private-msg.h +++ /dev/null @@ -1,42 +0,0 @@ -/*- - * Copyright (c) 2008, 2009 - * The Board of Trustees of The Leland Stanford Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation that - * others will use, modify and enhance the Software and contribute those - * enhancements back to the community. However, since we would like to make the - * Software available for broadest use, with as few restrictions as possible - * permission is hereby granted, free of charge, to any person obtaining a copy - * of this Software to deal in the Software under the copyrights without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any derivatives - * without specific, written prior permission. - */ - -#ifndef PRIVATE_MSG_H_ -#define PRIVATE_MSG_H_ - -#include "datapath.h" - -struct sender; - -int private_recv_msg(struct datapath *, const struct sender *, const void *); - -#endif diff --git a/openflow/udatapath/switch-flow.c b/openflow/udatapath/switch-flow.c deleted file mode 100644 index 4ba9b406..00000000 --- a/openflow/udatapath/switch-flow.c +++ /dev/null @@ -1,341 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include "switch-flow.h" -#include -#include -#include -#include -#include "ofpbuf.h" -#include "openflow/openflow.h" -#include "openflow/nicira-ext.h" -#include "packets.h" -#include "timeval.h" - -#define THIS_MODULE VLM_chain -#include "vlog.h" - -/* Internal function used to compare fields in flow. */ -static inline int -flow_fields_match(const struct flow *a, const struct flow *b, uint32_t w, - uint32_t src_mask, uint32_t dst_mask) -{ - return ((w & OFPFW_IN_PORT || a->in_port == b->in_port) - && (w & OFPFW_DL_VLAN || a->dl_vlan == b->dl_vlan) - && (w & OFPFW_DL_VLAN_PCP || a->dl_vlan_pcp == b->dl_vlan_pcp) - && (w & OFPFW_DL_SRC || eth_addr_equals(a->dl_src, b->dl_src)) - && (w & OFPFW_DL_DST || eth_addr_equals(a->dl_dst, b->dl_dst)) - && (w & OFPFW_DL_TYPE || a->dl_type == b->dl_type) - && (w & OFPFW_NW_TOS || a->nw_tos == b->nw_tos) - && (w & OFPFW_NW_PROTO || a->nw_proto == b->nw_proto) - && !((a->nw_src ^ b->nw_src) & src_mask) - && !((a->nw_dst ^ b->nw_dst) & dst_mask) - && (w & OFPFW_TP_SRC || a->tp_src == b->tp_src) - && (w & OFPFW_TP_DST || a->tp_dst == b->tp_dst)); -} - -static uint32_t make_nw_mask(int n_wild_bits) -{ - n_wild_bits &= (1u << OFPFW_NW_SRC_BITS) - 1; - return n_wild_bits < 32 ? htonl(~((1u << n_wild_bits) - 1)) : 0; -} - -/* Returns nonzero if 'a' and 'b' match, that is, if their fields are equal - * modulo wildcards in 'b', zero otherwise. */ -inline int -flow_matches_1wild(const struct sw_flow_key *a, const struct sw_flow_key *b) -{ - return flow_fields_match(&a->flow, &b->flow, b->wildcards, - b->nw_src_mask, b->nw_dst_mask); -} - -/* Returns nonzero if 'a' and 'b' match, that is, if their fields are equal - * modulo wildcards in 'a' or 'b', zero otherwise. */ -inline int -flow_matches_2wild(const struct sw_flow_key *a, const struct sw_flow_key *b) -{ - return flow_fields_match(&a->flow, &b->flow, a->wildcards | b->wildcards, - a->nw_src_mask & b->nw_src_mask, - a->nw_dst_mask & b->nw_dst_mask); -} - -/* Returns nonzero if 't' (the table entry's key) and 'd' (the key - * describing the match) match, that is, if their fields are - * equal modulo wildcards, zero otherwise. If 'strict' is nonzero, the - * wildcards must match in both 't_key' and 'd_key'. Note that the - * table's wildcards are ignored unless 'strict' is set. */ -int -flow_matches_desc(const struct sw_flow_key *t, const struct sw_flow_key *d, - int strict) -{ - if (strict && d->wildcards != t->wildcards) { - return 0; - } - return flow_matches_1wild(t, d); -} - -/* Returns nonzero if 't' (the table entry's key) and 'd' (the key - * describing the match) match, that is, if their fields are - * equal modulo 't' or 'd' wildcards, zero otherwise. If 'strict' is nonzero, the - * wildcards must match in both 't_key' and 'd_key'. Note that the - * table's wildcards are ignored unless 'strict' is set. */ -int -flow_matches_2desc(const struct sw_flow_key *t, const struct sw_flow_key *d, - int strict) -{ - if (strict && d->wildcards != t->wildcards) { - return 0; - } - return flow_matches_2wild(t, d); -} - -void -flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from) -{ - to->wildcards = ntohl(from->wildcards) & OFPFW_ALL; - to->flow.dl_vlan_pcp = from->dl_vlan_pcp; - to->flow.in_port = from->in_port; - to->flow.dl_vlan = from->dl_vlan; - memcpy(to->flow.dl_src, from->dl_src, ETH_ADDR_LEN); - memcpy(to->flow.dl_dst, from->dl_dst, ETH_ADDR_LEN); - to->flow.dl_type = from->dl_type; - - to->flow.nw_tos = to->flow.nw_proto = to->flow.nw_src = to->flow.nw_dst = 0; - to->flow.tp_src = to->flow.tp_dst = 0; - memset(to->flow.pad, 0, sizeof(to->flow.pad)); - -#define OFPFW_TP (OFPFW_TP_SRC | OFPFW_TP_DST) -#define OFPFW_NW (OFPFW_NW_TOS | OFPFW_NW_PROTO | OFPFW_NW_SRC_MASK | OFPFW_NW_DST_MASK) - if (to->wildcards & OFPFW_DL_TYPE) { - /* Can't sensibly match on network or transport headers if the - * data link type is unknown. */ - to->wildcards |= OFPFW_NW | OFPFW_TP; - } else if (from->dl_type == htons(ETH_TYPE_IP)) { - to->flow.nw_tos = from->nw_tos & 0xfc; - to->flow.nw_proto = from->nw_proto; - to->flow.nw_src = from->nw_src; - to->flow.nw_dst = from->nw_dst; - - if (to->wildcards & OFPFW_NW_PROTO) { - /* Can't sensibly match on transport headers if the network - * protocol is unknown. */ - to->wildcards |= OFPFW_TP; - } else if (from->nw_proto == IPPROTO_TCP - || from->nw_proto == IPPROTO_UDP - || from->nw_proto == IPPROTO_ICMP) { - to->flow.tp_src = from->tp_src; - to->flow.tp_dst = from->tp_dst; - } else { - /* Transport layer fields are undefined. Mark them as - * exact-match to allow such flows to reside in table-hash, - * instead of falling into table-linear. */ - to->wildcards &= ~OFPFW_TP; - } - } else if (from->dl_type == htons(ETH_TYPE_ARP)) { - to->flow.nw_src = from->nw_src; - to->flow.nw_dst = from->nw_dst; - to->flow.nw_proto = from->nw_proto; - - /* Transport layer fields are undefined. Mark them as - * exact-match to allow such flows to reside in table-hash, - * instead of falling into table-linear. */ - to->wildcards &= ~OFPFW_TP; - } else { - /* Network and transport layer fields are undefined. Mark them - * as exact-match to allow such flows to reside in table-hash, - * instead of falling into table-linear. */ - to->wildcards &= ~(OFPFW_NW | OFPFW_TP); - } - - /* We set these late because code above adjusts to->wildcards. */ - to->nw_src_mask = make_nw_mask(to->wildcards >> OFPFW_NW_SRC_SHIFT); - to->nw_dst_mask = make_nw_mask(to->wildcards >> OFPFW_NW_DST_SHIFT); -} - -/* Allocates and returns a new flow with room for 'actions_len' actions. - * Returns the new flow or a null pointer on failure. */ -struct sw_flow * -flow_alloc(size_t actions_len) -{ - struct sw_flow_actions *sfa; - size_t size = sizeof *sfa + actions_len; - struct sw_flow *flow = calloc(1, sizeof *flow); - if (!flow) - return NULL; - - sfa = calloc(1, size); - if (!sfa) { - free(flow); - return NULL; - } - sfa->actions_len = actions_len; - flow->sf_acts = sfa; - return flow; -} - -/* Setup the action on the flow, just after it was created with flow_alloc(). - * Jean II */ -void -flow_setup_actions(struct sw_flow * flow, - const struct ofp_action_header * actions, - int actions_len) -{ - /* Make sure we don't blow the allocation */ - if (actions_len > flow->sf_acts->actions_len) - ofp_fatal(0, - "flow_setup_actions: actions_len is too big (%d > %lu)", - actions_len, (unsigned long)flow->sf_acts->actions_len); - - flow->used = flow->created = time_msec(); - flow->sf_acts->actions_len = actions_len; - flow->byte_count = 0; - flow->packet_count = 0; - memcpy(flow->sf_acts->actions, actions, actions_len); -} - -/* Frees 'flow' immediately. */ -void -flow_free(struct sw_flow *flow) -{ - if (!flow) { - return; - } - free(flow->sf_acts); - free(flow); -} - -/* Copies 'actions' into a newly allocated structure for use by 'flow' - * and frees the structure that defined the previous actions. */ -void flow_replace_acts(struct sw_flow *flow, - const struct ofp_action_header *actions, size_t actions_len) -{ - struct sw_flow_actions *sfa; - int size = sizeof *sfa + actions_len; - - sfa = malloc(size); - if (unlikely(!sfa)) - return; - - sfa->actions_len = actions_len; - memcpy(sfa->actions, actions, actions_len); - - free(flow->sf_acts); - flow->sf_acts = sfa; - - return; -} - -/* Prints a representation of 'key' to the kernel log. */ -void -print_flow(const struct sw_flow_key *key) -{ - const struct flow *f = &key->flow; - - VLOG_INFO("wild %08x port %04x vlan-vid %04x vlan-pcp %02x " - "src-mac %02x:%02x:%02x:%02x:%02x:%02x " - "dst-mac %02x:%02x:%02x:%02x:%02x:%02x " - "frm-type %04x ip-tos %02x ip-src %u.%u.%u.%u ip-dst %u.%u.%u.%u " - "ip-proto %04x tp-src %d tp-dst %d pad %02x%02x%02x\n", - key->wildcards, ntohs(f->in_port), - ntohs(f->dl_vlan), f->dl_vlan_pcp, - f->dl_src[0], f->dl_src[1], f->dl_src[2], - f->dl_src[3], f->dl_src[4], f->dl_src[5], - f->dl_dst[0], f->dl_dst[1], f->dl_dst[2], - f->dl_dst[3], f->dl_dst[4], f->dl_dst[5], - ntohs(f->dl_type), - f->nw_tos, - ((unsigned char *)&f->nw_src)[0], - ((unsigned char *)&f->nw_src)[1], - ((unsigned char *)&f->nw_src)[2], - ((unsigned char *)&f->nw_src)[3], - ((unsigned char *)&f->nw_dst)[0], - ((unsigned char *)&f->nw_dst)[1], - ((unsigned char *)&f->nw_dst)[2], - ((unsigned char *)&f->nw_dst)[3], - f->nw_proto, - ntohs(f->tp_src), ntohs(f->tp_dst), - f->pad[0], f->pad[1], f->pad[2]); -} - -bool flow_timeout(struct sw_flow *flow) -{ - uint64_t now = time_msec(); - if (flow->idle_timeout != OFP_FLOW_PERMANENT - && now > flow->used + flow->idle_timeout * 1000) { - flow->reason = OFPRR_IDLE_TIMEOUT; - return true; - } else if (flow->hard_timeout != OFP_FLOW_PERMANENT - && now > flow->created + flow->hard_timeout * 1000) { - flow->reason = OFPRR_HARD_TIMEOUT; - return true; - } else { - return false; - } -} - -/* Returns nonzero if 'flow' contains an output action to 'out_port' or - * has the value OFPP_NONE. 'out_port' is in network-byte order. */ -int flow_has_out_port(struct sw_flow *flow, uint16_t out_port) -{ - struct sw_flow_actions *sf_acts = flow->sf_acts; - size_t actions_len = sf_acts->actions_len; - uint8_t *p = (uint8_t *)sf_acts->actions; - - if (out_port == htons(OFPP_NONE)) - return 1; - - while (actions_len > 0) { - struct ofp_action_header *ah = (struct ofp_action_header *)p; - size_t len = ntohs(ah->len); - - if (ah->type == htons(OFPAT_OUTPUT)) { - struct ofp_action_output *oa = (struct ofp_action_output *)p; - if (oa->port == out_port) { - return 1; - } - } - p += len; - actions_len -= len; - } - - return 0; -} - -void flow_used(struct sw_flow *flow, struct ofpbuf *buffer) -{ - flow->used = time_msec(); - - flow->packet_count++; - flow->byte_count += buffer->size; -} diff --git a/openflow/udatapath/switch-flow.h b/openflow/udatapath/switch-flow.h deleted file mode 100644 index 374cc737..00000000 --- a/openflow/udatapath/switch-flow.h +++ /dev/null @@ -1,100 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#ifndef SWITCH_FLOW_H -#define SWITCH_FLOW_H 1 - -#include -#include "openflow/openflow.h" -#include "flow.h" -#include "list.h" - -struct ofp_match; - -/* Identification data for a flow. */ -struct sw_flow_key { - struct flow flow; /* Flow data (in network byte order). */ - uint32_t wildcards; /* Wildcard fields (in host byte order). */ - uint32_t nw_src_mask; /* 1-bit in each significant nw_src bit. */ - uint32_t nw_dst_mask; /* 1-bit in each significant nw_dst bit. */ -}; - -struct sw_flow_actions { - size_t actions_len; - struct ofp_action_header actions[0]; -}; - -struct sw_flow { - struct sw_flow_key key; - - uint64_t cookie; /* Opaque controller-issued identifier. */ - uint16_t priority; /* Only used on entries with wildcards. */ - uint16_t idle_timeout; /* Idle time before discarding (seconds). */ - uint16_t hard_timeout; /* Hard expiration time (seconds) */ - uint64_t used; /* Last used time. */ - uint64_t created; /* When the flow was created. */ - uint64_t packet_count; /* Number of packets seen. */ - uint64_t byte_count; /* Number of bytes seen. */ - uint8_t reason; /* Reason flow removed (one of OFPRR_*). */ - uint8_t send_flow_rem; /* Send a flow removed to the controller */ - uint8_t emerg_flow; /* Emergency flow indicator */ - - struct sw_flow_actions *sf_acts; - - /* Private to table implementations. */ - struct list node; - struct list iter_node; - unsigned long int serial; - - void *private; /* Cookie for tables */ -}; - -int flow_matches_1wild(const struct sw_flow_key *, const struct sw_flow_key *); -int flow_matches_2wild(const struct sw_flow_key *, const struct sw_flow_key *); -int flow_matches_desc(const struct sw_flow_key *, const struct sw_flow_key *, - int); -int flow_matches_2desc(const struct sw_flow_key *, const struct sw_flow_key *, - int); -int flow_has_out_port(struct sw_flow *flow, uint16_t out_port); -struct sw_flow *flow_alloc(size_t); -void flow_setup_actions(struct sw_flow *, const struct ofp_action_header *, int); -void flow_free(struct sw_flow *); -void flow_replace_acts(struct sw_flow *, const struct ofp_action_header *, - size_t); -void flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from); - -void print_flow(const struct sw_flow_key *); -bool flow_timeout(struct sw_flow *flow); -void flow_used(struct sw_flow *flow, struct ofpbuf *buffer); - -#endif /* switch-flow.h */ diff --git a/openflow/udatapath/table-hash.c b/openflow/udatapath/table-hash.c deleted file mode 100644 index fc7006da..00000000 --- a/openflow/udatapath/table-hash.c +++ /dev/null @@ -1,469 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include "table.h" -#include -#include -#include -#include "openflow/nicira-ext.h" -#include "crc32.h" -#include "datapath.h" -#include "flow.h" -#include "switch-flow.h" - -struct sw_table_hash { - struct sw_table swt; - struct crc32 crc32; - unsigned int n_flows; - unsigned int bucket_mask; /* Number of buckets minus 1. */ - struct sw_flow **buckets; -}; - -static struct sw_flow **find_bucket(struct sw_table *swt, - const struct sw_flow_key *key) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - unsigned int crc = crc32_calculate(&th->crc32, key, - offsetof(struct sw_flow_key, wildcards)); - return &th->buckets[crc & th->bucket_mask]; -} - -static struct sw_flow *table_hash_lookup(struct sw_table *swt, - const struct sw_flow_key *key) -{ - struct sw_flow *flow = *find_bucket(swt, key); - return flow && !flow_compare(&flow->key.flow, &key->flow) ? flow : NULL; -} - -static int table_hash_insert(struct sw_table *swt, struct sw_flow *flow) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - struct sw_flow **bucket; - int retval; - - if (flow->key.wildcards != 0) - return 0; - - bucket = find_bucket(swt, &flow->key); - if (*bucket == NULL) { - th->n_flows++; - *bucket = flow; - retval = 1; - } else { - struct sw_flow *old_flow = *bucket; - if (!flow_compare(&old_flow->key.flow, &flow->key.flow)) { - *bucket = flow; - flow_free(old_flow); - retval = 1; - } else { - retval = 0; - } - } - return retval; -} - -static int table_hash_modify(struct sw_table *swt, - const struct sw_flow_key *key, uint16_t priority, int strict, - const struct ofp_action_header *actions, size_t actions_len) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - unsigned int count = 0; - - if (key->wildcards == 0) { - struct sw_flow **bucket = find_bucket(swt, key); - struct sw_flow *flow = *bucket; - if (flow && flow_matches_desc(&flow->key, key, strict) - && (!strict || (flow->priority == priority))) { - flow_replace_acts(flow, actions, actions_len); - count = 1; - } - } else { - unsigned int i; - - for (i = 0; i <= th->bucket_mask; i++) { - struct sw_flow **bucket = &th->buckets[i]; - struct sw_flow *flow = *bucket; - if (flow && flow_matches_desc(&flow->key, key, strict) - && (!strict || (flow->priority == priority))) { - flow_replace_acts(flow, actions, actions_len); - count++; - } - } - } - return count; -} - -static int table_hash_has_conflict(struct sw_table *swt, - const struct sw_flow_key *key, - uint16_t priority, int strict) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - - if (key->wildcards == 0) { - struct sw_flow **bucket = find_bucket(swt, key); - struct sw_flow *flow = *bucket; - if (flow && flow_matches_2desc(&flow->key, key,strict) - && (flow->priority == priority)) { - return true; - } - } else { - unsigned int i; - - for (i = 0; i <= th->bucket_mask; i++) { - struct sw_flow **bucket = &th->buckets[i]; - struct sw_flow *flow = *bucket; - if (flow && flow_matches_2desc(&flow->key, key, strict) - && (flow->priority == priority)) { - return true; - } - } - } - return false; -} - -/* Caller must update n_flows. */ -static void -do_delete(struct sw_flow **bucket) -{ - flow_free(*bucket); - *bucket = NULL; -} - -/* Returns number of deleted flows. We ignore the priority - * argument, since all exact-match entries are the same (highest) - * priority. */ -static int table_hash_delete(struct datapath *dp, struct sw_table *swt, - const struct sw_flow_key *key, - uint16_t out_port, - uint16_t priority UNUSED, int strict) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - unsigned int count = 0; - - if (key->wildcards == 0) { - struct sw_flow **bucket = find_bucket(swt, key); - struct sw_flow *flow = *bucket; - if (flow && !flow_compare(&flow->key.flow, &key->flow) - && flow_has_out_port(flow, out_port)) { - dp_send_flow_end(dp, flow, OFPRR_DELETE); - do_delete(bucket); - count = 1; - } - } else { - unsigned int i; - - for (i = 0; i <= th->bucket_mask; i++) { - struct sw_flow **bucket = &th->buckets[i]; - struct sw_flow *flow = *bucket; - if (flow && flow_matches_desc(&flow->key, key, strict) - && flow_has_out_port(flow, out_port)) { - dp_send_flow_end(dp, flow, OFPRR_DELETE); - do_delete(bucket); - count++; - } - } - } - th->n_flows -= count; - return count; -} - -static void table_hash_timeout(struct sw_table *swt, struct list *deleted) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - unsigned int i; - - for (i = 0; i <= th->bucket_mask; i++) { - struct sw_flow **bucket = &th->buckets[i]; - struct sw_flow *flow = *bucket; - if (flow && flow_timeout(flow)) { - list_push_back(deleted, &flow->node); - *bucket = NULL; - th->n_flows--; - } - } -} - -static void table_hash_destroy(struct sw_table *swt) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - unsigned int i; - for (i = 0; i <= th->bucket_mask; i++) { - if (th->buckets[i]) { - flow_free(th->buckets[i]); - } - } - free(th->buckets); - free(th); -} - -static int table_hash_iterate(struct sw_table *swt, - const struct sw_flow_key *key, uint16_t out_port, - struct sw_table_position *position, - int (*callback)(struct sw_flow *, void *private), - void *private) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - - if (position->private[0] > th->bucket_mask) - return 0; - - if (key->wildcards == 0) { - struct sw_flow *flow = table_hash_lookup(swt, key); - position->private[0] = -1; - if (!flow || !flow_has_out_port(flow, out_port)) { - return 0; - } - return callback(flow, private); - } else { - int i; - - for (i = position->private[0]; i <= th->bucket_mask; i++) { - struct sw_flow *flow = th->buckets[i]; - if (flow && flow_matches_1wild(&flow->key, key) - && flow_has_out_port(flow, out_port)) { - int error = callback(flow, private); - if (error) { - position->private[0] = i + 1; - return error; - } - } - } - return 0; - } -} - -static void table_hash_stats(struct sw_table *swt, - struct sw_table_stats *stats) -{ - struct sw_table_hash *th = (struct sw_table_hash *) swt; - stats->name = "hash"; - stats->wildcards = 0; /* No wildcards are supported. */ - stats->n_flows = th->n_flows; - stats->max_flows = th->bucket_mask + 1; - stats->n_lookup = swt->n_lookup; - stats->n_matched = swt->n_matched; -} - -struct sw_table *table_hash_create(unsigned int polynomial, - unsigned int n_buckets) -{ - struct sw_table_hash *th; - struct sw_table *swt; - - th = malloc(sizeof *th); - if (th == NULL) - return NULL; - memset(th, '\0', sizeof *th); - - assert(!(n_buckets & (n_buckets - 1))); - th->buckets = calloc(n_buckets, sizeof *th->buckets); - if (th->buckets == NULL) { - printf("failed to allocate %u buckets\n", n_buckets); - free(th); - return NULL; - } - th->n_flows = 0; - th->bucket_mask = n_buckets - 1; - - swt = &th->swt; - swt->lookup = table_hash_lookup; - swt->insert = table_hash_insert; - swt->modify = table_hash_modify; - swt->has_conflict = table_hash_has_conflict; - swt->delete = table_hash_delete; - swt->timeout = table_hash_timeout; - swt->destroy = table_hash_destroy; - swt->iterate = table_hash_iterate; - swt->stats = table_hash_stats; - - crc32_init(&th->crc32, polynomial); - - return swt; -} - -/* Double-hashing table. */ - -struct sw_table_hash2 { - struct sw_table swt; - struct sw_table *subtable[2]; -}; - -static struct sw_flow *table_hash2_lookup(struct sw_table *swt, - const struct sw_flow_key *key) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - int i; - - for (i = 0; i < 2; i++) { - struct sw_flow *flow = *find_bucket(t2->subtable[i], key); - if (flow && !flow_compare(&flow->key.flow, &key->flow)) - return flow; - } - return NULL; -} - -static int table_hash2_insert(struct sw_table *swt, struct sw_flow *flow) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - - if (table_hash_insert(t2->subtable[0], flow)) - return 1; - return table_hash_insert(t2->subtable[1], flow); -} - -static int table_hash2_modify(struct sw_table *swt, - const struct sw_flow_key *key, uint16_t priority, int strict, - const struct ofp_action_header *actions, size_t actions_len) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - return (table_hash_modify(t2->subtable[0], key, priority, strict, - actions, actions_len) - + table_hash_modify(t2->subtable[1], key, priority, strict, - actions, actions_len)); -} - -static int table_hash2_has_conflict(struct sw_table *swt, - const struct sw_flow_key *key, - uint16_t priority, int strict) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - return (table_hash_has_conflict(t2->subtable[0], key, priority, strict) || - table_hash_has_conflict(t2->subtable[1], key, priority, strict)); -} - -static int table_hash2_delete(struct datapath *dp, struct sw_table *swt, - const struct sw_flow_key *key, - uint16_t out_port, - uint16_t priority, int strict) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - return (table_hash_delete(dp, t2->subtable[0], key, out_port, - priority, strict) - + table_hash_delete(dp, t2->subtable[1], key, out_port, - priority, strict)); -} - -static void table_hash2_timeout(struct sw_table *swt, struct list *deleted) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - table_hash_timeout(t2->subtable[0], deleted); - table_hash_timeout(t2->subtable[1], deleted); -} - -static void table_hash2_destroy(struct sw_table *swt) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - table_hash_destroy(t2->subtable[0]); - table_hash_destroy(t2->subtable[1]); - free(t2); -} - -static int table_hash2_iterate(struct sw_table *swt, - const struct sw_flow_key *key, - uint16_t out_port, - struct sw_table_position *position, - int (*callback)(struct sw_flow *, void *), - void *private) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - int i; - - for (i = position->private[1]; i < 2; i++) { - int error = table_hash_iterate(t2->subtable[i], key, out_port, - position, callback, private); - if (error) { - return error; - } - position->private[0] = 0; - position->private[1]++; - } - return 0; -} - -static void table_hash2_stats(struct sw_table *swt, - struct sw_table_stats *stats) -{ - struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt; - struct sw_table_stats substats[2]; - int i; - - for (i = 0; i < 2; i++) - table_hash_stats(t2->subtable[i], &substats[i]); - stats->name = "hash2"; - stats->wildcards = 0; /* No wildcards are supported. */ - stats->n_flows = substats[0].n_flows + substats[1].n_flows; - stats->max_flows = substats[0].max_flows + substats[1].max_flows; - stats->n_lookup = swt->n_lookup; - stats->n_matched = swt->n_matched; -} - -struct sw_table *table_hash2_create(unsigned int poly0, unsigned int buckets0, - unsigned int poly1, unsigned int buckets1) - -{ - struct sw_table_hash2 *t2; - struct sw_table *swt; - - t2 = malloc(sizeof *t2); - if (t2 == NULL) - return NULL; - memset(t2, '\0', sizeof *t2); - - t2->subtable[0] = table_hash_create(poly0, buckets0); - if (t2->subtable[0] == NULL) - goto out_free_t2; - - t2->subtable[1] = table_hash_create(poly1, buckets1); - if (t2->subtable[1] == NULL) - goto out_free_subtable0; - - swt = &t2->swt; - swt->lookup = table_hash2_lookup; - swt->insert = table_hash2_insert; - swt->modify = table_hash2_modify; - swt->has_conflict = table_hash2_has_conflict; - swt->delete = table_hash2_delete; - swt->timeout = table_hash2_timeout; - swt->destroy = table_hash2_destroy; - swt->iterate = table_hash2_iterate; - swt->stats = table_hash2_stats; - - return swt; - -out_free_subtable0: - table_hash_destroy(t2->subtable[0]); -out_free_t2: - free(t2); - return NULL; -} diff --git a/openflow/udatapath/table-linear.c b/openflow/udatapath/table-linear.c deleted file mode 100644 index 0aea0e25..00000000 --- a/openflow/udatapath/table-linear.c +++ /dev/null @@ -1,262 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include "table.h" -#include -#include "flow.h" -#include "list.h" -#include "openflow/openflow.h" -#include "openflow/nicira-ext.h" -#include "switch-flow.h" -#include "datapath.h" - -struct sw_table_linear { - struct sw_table swt; - - unsigned int max_flows; - unsigned int n_flows; - struct list flows; - struct list iter_flows; - unsigned long int next_serial; -}; - -static struct sw_flow *table_linear_lookup(struct sw_table *swt, - const struct sw_flow_key *key) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - struct sw_flow *flow; - LIST_FOR_EACH (flow, struct sw_flow, node, &tl->flows) { - if (flow_matches_1wild(key, &flow->key)) - return flow; - } - return NULL; -} - -static int table_linear_insert(struct sw_table *swt, struct sw_flow *flow) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - struct sw_flow *f; - - /* Loop through the existing list of entries. New entries will - * always be placed behind those with equal priority. Just replace - * any flows that match exactly. - */ - LIST_FOR_EACH (f, struct sw_flow, node, &tl->flows) { - if (f->priority == flow->priority - && f->key.wildcards == flow->key.wildcards - && flow_matches_2wild(&f->key, &flow->key)) { - flow->serial = f->serial; - list_replace(&flow->node, &f->node); - list_replace(&flow->iter_node, &f->iter_node); - flow_free(f); - return 1; - } - - if (f->priority < flow->priority) - break; - } - - /* Make sure there's room in the table. */ - if (tl->n_flows >= tl->max_flows) { - return 0; - } - tl->n_flows++; - - /* Insert the entry immediately in front of where we're pointing. */ - flow->serial = tl->next_serial++; - list_insert(&f->node, &flow->node); - list_push_front(&tl->iter_flows, &flow->iter_node); - - return 1; -} - -static int table_linear_modify(struct sw_table *swt, - const struct sw_flow_key *key, uint16_t priority, int strict, - const struct ofp_action_header *actions, size_t actions_len) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - struct sw_flow *flow; - unsigned int count = 0; - - LIST_FOR_EACH (flow, struct sw_flow, node, &tl->flows) { - if (flow_matches_desc(&flow->key, key, strict) - && (!strict || (flow->priority == priority))) { - flow_replace_acts(flow, actions, actions_len); - count++; - } - } - return count; -} - -static int table_linear_has_conflict(struct sw_table *swt, - const struct sw_flow_key *key, - uint16_t priority, int strict) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - struct sw_flow *flow; - - LIST_FOR_EACH (flow, struct sw_flow, node, &tl->flows) { - if (flow_matches_2desc(&flow->key, key, strict) - && (flow->priority == priority)) { - return true; - } - } - return false; -} - -static void -do_delete(struct sw_flow *flow) -{ - list_remove(&flow->node); - list_remove(&flow->iter_node); - flow_free(flow); -} - -static int table_linear_delete(struct datapath *dp, struct sw_table *swt, - const struct sw_flow_key *key, - uint16_t out_port, - uint16_t priority, int strict) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - struct sw_flow *flow, *n; - unsigned int count = 0; - - LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &tl->flows) { - if (flow_matches_desc(&flow->key, key, strict) - && flow_has_out_port(flow, out_port) - && (!strict || (flow->priority == priority))) { - dp_send_flow_end(dp, flow, OFPRR_DELETE); - do_delete(flow); - count++; - } - } - tl->n_flows -= count; - return count; -} - -static void table_linear_timeout(struct sw_table *swt, struct list *deleted) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - struct sw_flow *flow, *n; - - LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &tl->flows) { - if (flow_timeout(flow)) { - list_remove(&flow->node); - list_remove(&flow->iter_node); - list_push_back(deleted, &flow->node); - tl->n_flows--; - } - } -} - -static void table_linear_destroy(struct sw_table *swt) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - - while (!list_is_empty(&tl->flows)) { - struct sw_flow *flow = CONTAINER_OF(list_front(&tl->flows), - struct sw_flow, node); - list_remove(&flow->node); - flow_free(flow); - } - free(tl); -} - -static int table_linear_iterate(struct sw_table *swt, - const struct sw_flow_key *key, - uint16_t out_port, - struct sw_table_position *position, - int (*callback)(struct sw_flow *, void *), - void *private) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - struct sw_flow *flow; - unsigned long start; - - start = ~position->private[0]; - LIST_FOR_EACH (flow, struct sw_flow, iter_node, &tl->iter_flows) { - if (flow->serial <= start - && flow_matches_2wild(key, &flow->key) - && flow_has_out_port(flow, out_port)) { - int error = callback(flow, private); - if (error) { - position->private[0] = ~(flow->serial - 1); - return error; - } - } - } - return 0; -} - -static void table_linear_stats(struct sw_table *swt, - struct sw_table_stats *stats) -{ - struct sw_table_linear *tl = (struct sw_table_linear *) swt; - stats->name = "linear"; - stats->wildcards = OFPFW_ALL; - stats->n_flows = tl->n_flows; - stats->max_flows = tl->max_flows; - stats->n_lookup = swt->n_lookup; - stats->n_matched = swt->n_matched; -} - - -struct sw_table *table_linear_create(unsigned int max_flows) -{ - struct sw_table_linear *tl; - struct sw_table *swt; - - tl = calloc(1, sizeof *tl); - if (tl == NULL) - return NULL; - - swt = &tl->swt; - swt->lookup = table_linear_lookup; - swt->insert = table_linear_insert; - swt->modify = table_linear_modify; - swt->has_conflict = table_linear_has_conflict; - swt->delete = table_linear_delete; - swt->timeout = table_linear_timeout; - swt->destroy = table_linear_destroy; - swt->iterate = table_linear_iterate; - swt->stats = table_linear_stats; - - tl->max_flows = max_flows; - tl->n_flows = 0; - list_init(&tl->flows); - list_init(&tl->iter_flows); - tl->next_serial = 0; - - return swt; -} diff --git a/openflow/udatapath/table.h b/openflow/udatapath/table.h deleted file mode 100644 index 1312e3c9..00000000 --- a/openflow/udatapath/table.h +++ /dev/null @@ -1,150 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -/* Individual switching tables. Generally grouped together in a chain (see - * chain.h). */ - -#ifndef TABLE_H -#define TABLE_H 1 - -#include -#include - -struct datapath; /* Forward declaration for delete operation */ -struct sw_flow; -struct sw_flow_key; -struct ofp_action_header; -struct list; - -/* Table statistics. */ -struct sw_table_stats { - const char *name; /* Human-readable name. */ - uint32_t wildcards; /* Bitmap of OFPFW_* wildcards that are - supported by the table. */ - unsigned int n_flows; /* Number of active flows. */ - unsigned int max_flows; /* Flow capacity. */ - unsigned long int n_lookup; /* Number of packets looked up. */ - unsigned long int n_matched; /* Number of packets that have hit. */ -}; - -/* Position within an iteration of a sw_table. - * - * The contents are private to the table implementation, except that a position - * initialized to all-zero-bits represents the start of a table. */ -struct sw_table_position { - unsigned long private[4]; -}; - -/* A single table of flows. */ -struct sw_table { - /* The number of packets that have been looked up and matched, - * respecitvely. To make these 100% accurate, they should be atomic. - * However, we're primarily concerned about speed. */ - unsigned long long n_lookup; - unsigned long long n_matched; - - /* Searches 'table' for a flow matching 'key', which must not have any - * wildcard fields. Returns the flow if successful, a null pointer - * otherwise. */ - struct sw_flow *(*lookup)(struct sw_table *table, - const struct sw_flow_key *key); - - /* Inserts 'flow' into 'table', replacing any duplicate flow. Returns - * 0 if successful or a negative error. Error can be due to an - * over-capacity table or because the flow is not one of the kind that - * the table accepts. - * - * If successful, 'flow' becomes owned by 'table', otherwise it is - * retained by the caller. */ - int (*insert)(struct sw_table *table, struct sw_flow *flow); - - /* Modifies the actions in 'table' that match 'key'. If 'strict' - * set, wildcards and priority must match. Returns the number of flows - * that were modified. */ - int (*modify)(struct sw_table *table, const struct sw_flow_key *key, - uint16_t priority, int strict, - const struct ofp_action_header *actions, size_t actions_len); - - /* Checks whether 'table' has an equal priotiry entry of thethat conflicts - * with 'key'. If 'strict' is set, wildcards must match. - * Returns the number of flows that were modified. */ - int (*has_conflict)(struct sw_table *table, const struct sw_flow_key *key, - uint16_t priority, int strict); - - /* Deletes from 'table' any and all flows that match 'key' from - * 'table'. If 'out_port' is not OFPP_NONE, then matching entries - * must have that port as an argument for an output action. If - * 'strict' is set, wildcards and priority must match. Returns the - * number of flows that were deleted. */ - int (*delete)(struct datapath *dp, struct sw_table *table, - const struct sw_flow_key *key, - uint16_t out_port, uint16_t priority, int strict); - - /* Performs timeout processing on all the flow entries in 'table'. - * Appends all the flow entries removed from 'table' to 'deleted' for the - * caller to free. */ - void (*timeout)(struct sw_table *table, struct list *deleted); - - /* Destroys 'table', which must not have any users. */ - void (*destroy)(struct sw_table *table); - - /* Iterates through the flow entries in 'table', passing each one - * matches 'key' and output port 'out_port' to 'callback'. The - * callback function should return 0 to continue iteration or a - * nonzero error code to stop. The iterator function returns either - * 0 if the table iteration completed or the value returned by the - * callback function otherwise. - * - * The iteration starts at 'position', which may be initialized to - * all-zero-bits to iterate from the beginning of the table. If the - * iteration terminates due to an error from the callback function, - * 'position' is updated to a value that can be passed back to the - * iterator function to resume iteration later with the following - * flow. */ - int (*iterate)(struct sw_table *table, - const struct sw_flow_key *key, uint16_t out_port, - struct sw_table_position *position, - int (*callback)(struct sw_flow *flow, void *private), - void *private); - - /* Dumps statistics for 'table' into 'stats'. */ - void (*stats)(struct sw_table *table, struct sw_table_stats *stats); -}; - -struct sw_table *table_hash_create(unsigned int polynomial, - unsigned int n_buckets); -struct sw_table *table_hash2_create(unsigned int poly0, unsigned int buckets0, - unsigned int poly1, unsigned int buckets1); -struct sw_table *table_linear_create(unsigned int max_flows); - -#endif /* table.h */ diff --git a/openflow/udatapath/udatapath.c b/openflow/udatapath/udatapath.c deleted file mode 100644 index a4446575..00000000 --- a/openflow/udatapath/udatapath.c +++ /dev/null @@ -1,345 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "command-line.h" -#include "daemon.h" -#include "datapath.h" -#include "fault.h" -#include "openflow/openflow.h" -#include "poll-loop.h" -#include "queue.h" -#include "util.h" -#include "rconn.h" -#include "timeval.h" -#include "vconn.h" -#include "dirs.h" -#include "vconn-ssl.h" -#include "vlog-socket.h" - -#if defined(OF_HW_PLAT) -#include -#endif - -#define THIS_MODULE VLM_udatapath -#include "vlog.h" - -/* Strings to describe the manufacturer, hardware, and software. This data - * is queriable through the switch description stats message. */ -char mfr_desc[DESC_STR_LEN] = "Stanford University"; -char hw_desc[DESC_STR_LEN] = "Reference Userspace Switch"; -char sw_desc[DESC_STR_LEN] = VERSION BUILDNR; -char dp_desc[DESC_STR_LEN] = ""; -char serial_num[SERIAL_NUM_LEN] = "None"; - -static void parse_options(int argc, char *argv[]); -static void usage(void) NO_RETURN; - -static struct datapath *dp; -static uint64_t dpid = UINT64_MAX; -static char *port_list; -static char *local_port = "tap:"; -static uint16_t num_queues = NETDEV_MAX_QUEUES; - -static void add_ports(struct datapath *dp, char *port_list); - -/* Need to treat this more generically */ -#if defined(UDATAPATH_AS_LIB) -#define OFP_FATAL(_er, _str, args...) do { \ - fprintf(stderr, _str, ## args); \ - return -1; \ - } while (0) -#else -#define OFP_FATAL(_er, _str, args...) ofp_fatal(_er, _str, ## args) -#endif - -#if !defined(UDATAPATH_AS_LIB) -int -main(int argc, char *argv[]) -{ - return udatapath_cmd(argc, argv); -} -#endif - -int -udatapath_cmd(int argc, char *argv[]) -{ - int n_listeners; - int error; - int i; - - set_program_name(argv[0]); - register_fault_handlers(); - time_init(); - vlog_init(); - parse_options(argc, argv); - signal(SIGPIPE, SIG_IGN); - - if (argc - optind < 1) { - OFP_FATAL(0, "at least one listener argument is required; " - "use --help for usage"); - } - - error = dp_new(&dp, dpid); - - n_listeners = 0; - for (i = optind; i < argc; i++) { - const char *pvconn_name = argv[i]; - struct pvconn *pvconn; - int retval; - - retval = pvconn_open(pvconn_name, &pvconn); - if (!retval || retval == EAGAIN) { - dp_add_pvconn(dp, pvconn); - n_listeners++; - } else { - ofp_error(retval, "opening %s", pvconn_name); - } - } - if (!n_listeners) { - OFP_FATAL(0, "could not listen for any connections"); - } - - if (port_list) { - add_ports(dp, port_list); - } - if (local_port) { - error = dp_add_local_port(dp, local_port, 0); - if (error) { - OFP_FATAL(error, "failed to add local port %s", local_port); - } - } - - error = vlog_server_listen(NULL, NULL); - if (error) { - OFP_FATAL(error, "could not listen for vlog connections"); - } - - die_if_already_running(); - daemonize(); - - for (;;) { - dp_run(dp); - dp_wait(dp); - poll_block(); - } - - return 0; -} - -static void -add_ports(struct datapath *dp, char *port_list) -{ - char *port, *save_ptr; - - /* Glibc 2.7 has a bug in strtok_r when compiling with optimization that - * can cause segfaults here: - * http://sources.redhat.com/bugzilla/show_bug.cgi?id=5614. - * Using ",," instead of the obvious "," works around it. */ - for (port = strtok_r(port_list, ",,", &save_ptr); port; - port = strtok_r(NULL, ",,", &save_ptr)) { - int error = dp_add_port(dp, port, num_queues); - if (error) { - ofp_fatal(error, "failed to add port %s", port); - } - } -} - -static void -parse_options(int argc, char *argv[]) -{ - enum { - OPT_MFR_DESC = UCHAR_MAX + 1, - OPT_HW_DESC, - OPT_SW_DESC, - OPT_DP_DESC, - OPT_SERIAL_NUM, - OPT_BOOTSTRAP_CA_CERT, - OPT_NO_LOCAL_PORT, - OPT_NO_SLICING - }; - - static struct option long_options[] = { - {"interfaces", required_argument, 0, 'i'}, - {"local-port", required_argument, 0, 'L'}, - {"no-local-port", no_argument, 0, OPT_NO_LOCAL_PORT}, - {"datapath-id", required_argument, 0, 'd'}, - {"verbose", optional_argument, 0, 'v'}, - {"help", no_argument, 0, 'h'}, - {"version", no_argument, 0, 'V'}, - {"no-slicing", no_argument, 0, OPT_NO_SLICING}, - {"mfr-desc", required_argument, 0, OPT_MFR_DESC}, - {"hw-desc", required_argument, 0, OPT_HW_DESC}, - {"sw-desc", required_argument, 0, OPT_SW_DESC}, - {"dp_desc", required_argument, 0, OPT_DP_DESC}, - {"serial_num", required_argument, 0, OPT_SERIAL_NUM}, - DAEMON_LONG_OPTIONS, -#ifdef HAVE_OPENSSL - VCONN_SSL_LONG_OPTIONS - {"bootstrap-ca-cert", required_argument, 0, OPT_BOOTSTRAP_CA_CERT}, -#endif - {0, 0, 0, 0}, - }; - char *short_options = long_options_to_short_options(long_options); - - for (;;) { - int indexptr; - int c; - - c = getopt_long(argc, argv, short_options, long_options, &indexptr); - if (c == -1) { - break; - } - - switch (c) { - case 'd': - if (strlen(optarg) != 12 - || strspn(optarg, "0123456789abcdefABCDEF") != 12) { - ofp_fatal(0, "argument to -d or --datapath-id must be " - "exactly 12 hex digits"); - } - dpid = strtoll(optarg, NULL, 16); - if (!dpid) { - ofp_fatal(0, "argument to -d or --datapath-id must " - "be nonzero"); - } - break; - - case 'h': - usage(); - - case 'V': - printf("%s %s compiled "__DATE__" "__TIME__"\n", - program_name, VERSION BUILDNR); - exit(EXIT_SUCCESS); - - case 'v': - vlog_set_verbosity(optarg); - break; - - case 'i': - if (!port_list) { - port_list = optarg; - } else { - port_list = xasprintf("%s,%s", port_list, optarg); - } - break; - - case 'L': - local_port = optarg; - break; - - case OPT_NO_LOCAL_PORT: - local_port = NULL; - break; - - case OPT_MFR_DESC: - strncpy(mfr_desc, optarg, sizeof mfr_desc); - break; - - case OPT_HW_DESC: - strncpy(hw_desc, optarg, sizeof hw_desc); - break; - - case OPT_SW_DESC: - strncpy(sw_desc, optarg, sizeof sw_desc); - break; - - case OPT_DP_DESC: - strncpy(dp_desc, optarg, sizeof dp_desc); - break; - - case OPT_SERIAL_NUM: - strncpy(serial_num, optarg, sizeof serial_num); - break; - - case OPT_NO_SLICING: - num_queues = 0; - break; - - DAEMON_OPTION_HANDLERS - -#ifdef HAVE_OPENSSL - VCONN_SSL_OPTION_HANDLERS - - case OPT_BOOTSTRAP_CA_CERT: - vconn_ssl_set_ca_cert_file(optarg, true); - break; -#endif - - case '?': - exit(EXIT_FAILURE); - - default: - abort(); - } - } - free(short_options); -} - -static void -usage(void) -{ - printf("%s: userspace OpenFlow datapath\n" - "usage: %s [OPTIONS] LISTEN...\n" - "where LISTEN is a passive OpenFlow connection method on which\n" - "to listen for incoming connections from the secure channel.\n", - program_name, program_name); - vconn_usage(false, true, false); - printf("\nConfiguration options:\n" - " -i, --interfaces=NETDEV[,NETDEV]...\n" - " add specified initial switch ports\n" - " -L, --local-port=NETDEV set network device for local port\n" - " --no-local-port disable local port\n" - " -d, --datapath-id=ID Use ID as the OpenFlow switch ID\n" - " (ID must consist of 12 hex digits)\n" - " --no-slicing disable slicing\n" - "\nOther options:\n" - " -D, --detach run in background as daemon\n" - " -P, --pidfile[=FILE] create pidfile (default: %s/ofdatapath.pid)\n" - " -f, --force with -P, start even if already running\n" - " -v, --verbose=MODULE[:FACILITY[:LEVEL]] set logging levels\n" - " -v, --verbose set maximum verbosity level\n" - " -h, --help display this help message\n" - " -V, --version display version information\n", - ofp_rundir); - exit(EXIT_SUCCESS); -} diff --git a/openflow/utilities/.dirstamp b/openflow/utilities/.dirstamp deleted file mode 100644 index e69de29b..00000000 diff --git a/openflow/utilities/.gitignore b/openflow/utilities/.gitignore deleted file mode 100644 index c93169bf..00000000 --- a/openflow/utilities/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -/Makefile -/Makefile.in -/dpctl -/dpctl.8 -/ofp-discover -/ofp-discover.8 -/ofp-kill -/ofp-kill.8 -/ofp-pki -/ofp-pki-cgi -/ofp-pki.8 -/vlogconf -/vlogconf.8 diff --git a/openflow/utilities/automake.mk b/openflow/utilities/automake.mk deleted file mode 100644 index d6f79a8c..00000000 --- a/openflow/utilities/automake.mk +++ /dev/null @@ -1,45 +0,0 @@ -bin_PROGRAMS += \ - utilities/vlogconf \ - utilities/dpctl \ - utilities/ofp-discover \ - utilities/ofp-kill -bin_SCRIPTS += utilities/ofp-pki -noinst_SCRIPTS += utilities/ofp-pki-cgi utilities/ofp-parse-leaks - -EXTRA_DIST += \ - utilities/dpctl.8.in \ - utilities/ofp-discover.8.in \ - utilities/ofp-kill.8.in \ - utilities/ofp-parse-leaks.in \ - utilities/ofp-pki-cgi.in \ - utilities/ofp-pki.8.in \ - utilities/ofp-pki.in \ - utilities/vlogconf.8.in -DISTCLEANFILES += \ - utilities/dpctl.8 \ - utilities/ofp-discover.8 \ - utilities/ofp-kill.8 \ - utilities/ofp-parse-leaks \ - utilities/ofp-pki \ - utilities/ofp-pki.8 \ - utilities/ofp-pki-cgi \ - utilities/vlogconf.8 - -man_MANS += \ - utilities/dpctl.8 \ - utilities/ofp-discover.8 \ - utilities/ofp-kill.8 \ - utilities/ofp-pki.8 \ - utilities/vlogconf.8 - -utilities_dpctl_SOURCES = utilities/dpctl.c -utilities_dpctl_LDADD = lib/libopenflow.a $(FAULT_LIBS) $(SSL_LIBS) - -utilities_vlogconf_SOURCES = utilities/vlogconf.c -utilities_vlogconf_LDADD = lib/libopenflow.a - -utilities_ofp_discover_SOURCES = utilities/ofp-discover.c -utilities_ofp_discover_LDADD = lib/libopenflow.a - -utilities_ofp_kill_SOURCES = utilities/ofp-kill.c -utilities_ofp_kill_LDADD = lib/libopenflow.a diff --git a/openflow/utilities/dpctl.8.in b/openflow/utilities/dpctl.8.in deleted file mode 100644 index 80f06bb0..00000000 --- a/openflow/utilities/dpctl.8.in +++ /dev/null @@ -1,582 +0,0 @@ -.ds PN dpctl - -.TH dpctl 8 "May 2008" "OpenFlow" "OpenFlow Manual" - -.SH NAME -dpctl \- administer OpenFlow datapaths - -.SH SYNOPSIS -.B dpctl -[\fIoptions\fR] \fIcommand \fR[\fIswitch\fR] [\fIargs\fR&...] - -.SH DESCRIPTION -The -.B dpctl -program is a command line tool for monitoring and administering OpenFlow -datapaths. It is able to show the current state of a datapath, -including features, configuration, and tables entries. When using the -OpenFlow kernel module, -.B dpctl -is used to add, delete, modify, and monitor datapaths. - -Most \fBdpctl\fR commands take an argument that specifies the -method for connecting to an OpenFlow switch. The following connection -methods are supported: - -.TP -\fBnl:\fIdp_idx\fR -The local Netlink datapath numbered \fIdp_idx\fR. This form requires -that the local host has the OpenFlow kernel module for Linux loaded. - -.TP -\fBssl:\fIhost\fR[\fB:\fIport\fR] -The specified SSL \fIport\fR (default: 6633) on the given remote -\fIhost\fR. The \fB--private-key\fR, \fB--certificate\fR, and -\fB--ca-cert\fR options are mandatory when this form is used. - -.TP -\fBtcp:\fIhost\fR[\fB:\fIport\fR] -The specified TCP \fIport\fR (default: 6633) on the given remote -\fIhost\fR. - -.TP -\fBunix:\fIfile\fR -The Unix domain server socket named \fIfile\fR. - -.SH COMMANDS - -With the \fBdpctl\fR program, datapaths running in the kernel can be -created, deleted, and modified. A single machine may -host up to 32 datapaths (numbered 0 to 31). In most situations, -a machine hosts only one datapath. - -A newly created datapath is not associated with any of the -host's network devices thus does not process any incoming -traffic. To intercept and process traffic on a given network device, the -network device must be explicitly added to a datapath through the -\fBaddif\fR command. - -The following commands manage local datapaths. - -.TP -\fBadddp nl:\fIdp_idx\fR -Creates datapath numbered \fIdp_idx\fR on the local host. This will -fail if \fIdp_idx\fR is not in the range 0 to 31, or if the datapath -with that number already exists on the host. - -.TP -\fBdeldp nl:\fIdp_idx\fR -Deletes datapath \fIdp_idx\fR on the local host. \fIdp_idx\fR must be -an existing datapath. All of a datapath's network devices must be -explicitly removed before the datapath can be deleted (see \fBdelif\fR -command). - -.TP -\fBaddif nl:\fIdp_idx netdev\fR... -Adds each \fInetdev\fR to the list of network devices datapath -\fIdp_idx\fR monitors, where \fIdp_idx\fR is the ID of an existing -datapath, and \fInetdev\fR is the name of one of the host's -network devices, e.g. \fBeth0\fR. Once a network device has been added -to a datapath, the datapath has complete ownership of the network device's -traffic and the network device appears silent to the rest of the system. - -.TP -\fBdelif nl:\fIdp_idx netdev\fR... -Removes each \fInetdev\fR from the list of network devices datapath -\fIdp_idx\fR monitors. - -.TP -\fBget-idx \fIof_dev\fR -Prints the datapath index for OpenFlow device \fIof_dev\fR. - -.PP -The following commands can be apply to OpenFlow switches regardless of -the connection method. - -.TP -\fBshow \fIswitch\fR -Prints to the console information on datapath \fIswitch\fR including -information on its flow tables and ports. - -.TP -\fBstatus \fIswitch\fR [\fIkey\fR] -Prints to the console a series of key-value pairs that report the -status of \fIswitch\fR. If \fIkey\fR is specified, only the key-value -pairs whose key names begin with \fIkey\fR are printed. If \fIkey\fR is -omitted, all key-value pairs are printed. - -(In the OpenFlow reference implementation, the \fBstatus\fR command is -implemented in \fBofprotocol\fR(8), not in the kernel module, so the -\fBnl:\fIdp_idx\fR connection method should not be used with this -command. Instead, specify \fB-l\fR or \fB--listen\fR on the -\fBofprotocol\fR command line and tell \fBdpctl\fR to use the connection -method specified there.) - -.TP -\fBshow-protostat \fIswitch\fR -Prints to the OpenFlow protocol statiscal information of \fIswitch\fR. - -(In the OpenFlow reference implementation, the \fBshow-protostat\fR command -is implemented in \fBofprotocol\fR(8), not in the kernel module, so the -\fBnl:\fIdp_idx\fR connection method should not be used with this -command. Instead, specify \fB-l\fR or \fB--listen\fR on the -\fBofprotocol\fR command line and tell \fBdpctl\fR to use the connection -method specified there.) - -.TP -\fBdump-tables \fIswitch\fR -Prints to the console statistics for each of the flow tables used by -datapath \fIswitch\fR. - -.TP -\fBdump-ports \fIswitch\fR \fR[\fIport number\fR] -Prints to the console statistics for each interface monitored by -\fIswitch\fR. If port number is specified, print statistics only for -the interface corresponding to port number. - -.TP -\fBmod-port \fIswitch\fR \fInetdev\fR \fIaction\fR -Modify characteristics of an interface monitored by \fIswitch\fR. -\fInetdev\fR can be referred to by its OpenFlow assigned port number or -the device name, e.g. \fBeth0\fR. The \fIaction\fR may be any one of the -following: - -.RS -.IP \fBup\fR -Enables the interface. This is equivalent to ``ifconfig up'' on a Unix -system. - -.IP \fBdown\fR -Disables the interface. This is equivalent to ``ifconfig down'' on a Unix -system. - -.IP \fBflood\fR -When a \fIflood\fR action is specified, traffic will be sent out this -interface. This is the default posture for monitored ports. - -.IP \fBnoflood\fR -When a \fIflood\fR action is specified, traffic will not be sent out -this interface. This is primarily useful to prevent loops when a -spanning tree protocol is not in use. - -.RE - -.TP -\fBdump-flows \fIswitch \fR[\fIflows\fR] -Prints to the console all flow entries in datapath \fIswitch\fR's -tables that match \fIflows\fR. If \fIflows\fR is omitted, all flows -except emergency flows in the datapath flows are retrieved. -See \fBFLOW SYNTAX\fR, below, for the syntax of \fIflows\fR. - -.TP -\fBdesc \fIswitch \fIstring -Sets the switch description (as returned in ofp_desc_stats) to -\fIstring (max length is DESC_STR_LEN). - -.TP -\fBdump-aggregate \fIswitch \fR[\fIflows\fR] -Prints to the console aggregate statistics for flows in datapath -\fSWITCH\fR's tables that match \fIflows\fR. If \fIflows\fR is omitted, -the statistics are aggregated across all flows in the datapath's flow -tables. See \fBFLOW SYNTAX\fR, below, for the syntax of \fIflows\fR. - -.TP -\fBadd-flow \fIswitch flow\fR -Add the flow entry as described by \fIflow\fR to the datapath \fIswitch\fR's -tables. The flow entry is in the format described in \fBFLOW SYNTAX\fR, -below. - -.TP -\fBadd-flows \fIswitch file\fR -Add flow entries as described in \fIfile\fR to the datapath \fIswitch\fR's -tables. Each line in \fIfile\fR is a flow entry in the format -described in \fBFLOW SYNTAX\fR, below. - -.TP -\fBmod-flows \fIswitch flow\fR -Modify the actions in entries from the datapath \fIswitch\fR's tables -that match \fIflow\fR. When invoked with the \fB--strict\fR option, -wildcards are not treated as active for matching purposes. See -\fBFLOW SYNTAX\fR, below, for the syntax of \fIflows\fR. - -.TP -\fBdel-flows \fIswitch \fR[\fIflow\fR] -Deletes entries from the datapath \fIswitch\fR's tables that match -\fIflow\fR. When invoked with the \fB--strict\fR option, wildcards are -not treated as active for matching purposes. If \fIflow\fR is -omitted and the \fB--strict\fR option is not used, all flows in the -datapath's tables are removed. See \fBFLOW SYNTAX\fR, below, for the -syntax of \fIflows\fR. - -.TP -\fBmonitor \fIswitch\fR -Connects to \fIswitch\fR and prints to the console all OpenFlow -messages received. Usually, \fIswitch\fR should specify a connection -named on \fBofprotocol\fR(8)'s \fB-m\fR or \fB--monitor\fR command line -option, in which the messages printed will be all those sent or -received by \fBofprotocol\fR to or from the kernel datapath module. A -\fIswitch\fR of the form \fBnl:\fIdp_idx\fR will print all -asynchronously generated OpenFlow messages (such as packet-in -messages), but it will not print any messages sent to the kernel by -\fBofprotocol\fR and other processes, nor will it print replies sent by -the kernel in response to those messages. - -.PP -The following commands monitor and control the egress queue -configuration for an OpenFlow switch if the switch supports such -operations. After a queue is created with the add or modify -operation, the OpenFlow enqueue action may be specified to -direct packets to a particular queue. Queues are associated with -specific ports (so the same queue-id may be used on different -ports and this will refer to different queues). The only -characteristic that may be configured for queues is the minimum -bandwidth guarantee. This parameter is specified in tenths of -a percent (so full link bandwidth is 1000). - -.TP -\fBadd-queue \fIswitch\fR \fIport\fR \fIq-id\fR [\fIbandwidth\fR] -Connect to \fIswitch\fR and add an egress queue identified as \fIq-id\fR -for \fIport\fR. If -specified, \fIbandwidth\fR indicates the minimum bandwidth guarantee -for the queue and is specified in tenths of a -percent. This is the only characteristic of the queue that -may be configured. - -.TP -\fBmod-queue \fIswitch\fR \fIport\fR \fIq-id\fR \fIbandwidth\fR -Connect to \fIswitch\fR and modify the bandwidth setting for an egress -queue identified as \fIq-id\fR -for \fIport\fR. The queue need not have been created with \fBadd-queue\fR -previously. The parameter \fIbandwidth\fR indicates the minimum -bandwidth guarantee for the queue and is specified in tenths of a -percent. This is the only characteristic -of the queue that may be configured. - -.TP -\fBdel-queue \fIswitch\fR \fIport\fR \fIq-id\fR -Delete an egress queue identified as \fIq-id\fR for \fIport\fR which -had been created by \fBadd-queue\fR or \fBmod-queue\fR. - -.TP -\fBdump-queue \fIswitch\fR [\fIport\fR [\fIq-id\fR]] -Dump that current queue configuration. A port may be specified. -If it is, a queue-id may also be specified. - -.PP -The following commands can be used regardless of the connection -method. They apply to OpenFlow switches and controllers. - -.TP -\fBprobe \fIvconn\fR -Connects to \fIvconn\fR and sends a single OpenFlow echo-request -packet and waits for the response. With the \fB-t\fR or -\fB--timeout\fR option, this command can test whether an OpenFlow -switch or controller is up and running. - -.TP -\fBping \fIvconn \fR[\fIn\fR] -Sends a series of 10 echo request packets to \fIvconn\fR and times -each reply. The echo request packets consist of an OpenFlow header -plus \fIn\fR bytes (default: 64) of randomly generated payload. This -measures the latency of individual requests. - -.TP -\fBbenchmark \fIvconn n count\fR -Sends \fIcount\fR echo request packets that each consist of an -OpenFlow header plus \fIn\fR bytes of payload and waits for each -response. Reports the total time required. This is a measure of the -maximum bandwidth to \fIvconn\fR for round-trips of \fIn\fR-byte -messages. - -.SH "FLOW SYNTAX" - -Some \fBdpctl\fR commands accept an argument that describes a flow or -flows. Such flow descriptions comprise a series -\fIfield\fB=\fIvalue\fR assignments, separated by commas or white -space. - -The following field assignments describe how a flow matches a packet. -If any of these assignments is omitted from the flow syntax, the field -is treated as a wildcard; thus, if all of them are omitted, the -resulting flow matches all packets. The string \fB*\fR or \fBANY\fR -may be specified a value to explicitly mark any of these fields as a -wildcard. - -.IP \fBin_port=\fIport_no\fR -Matches physical port \fIport_no\fR. Switch ports are numbered as -displayed by \fBdpctl show\fR. - -.IP \fBdl_vlan=\fIvlan\fR -Matches IEEE 802.1q virtual LAN tag \fIvlan\fR. Specify \fB0xffff\fR -as \fIvlan\fR to match packets that are not tagged with a virtual LAN; -otherwise, specify a number between 0 and 4095, inclusive, as the -12-bit VLAN ID to match. - -.IP \fBdl_src=\fImac\fR -Matches Ethernet source address \fImac\fR, which should be specified -as 6 pairs of hexadecimal digits delimited by colons, -e.g. \fB00:0A:E4:25:6B:B0\fR. - -.IP \fBdl_dst=\fImac\fR -Matches Ethernet destination address \fImac\fR. - -.IP \fBdl_type=\fIethertype\fR -Matches Ethernet protocol type \fIethertype\fR, which should be -specified as a integer between 0 and 65535, inclusive, either in -decimal or as a hexadecimal number prefixed by \fB0x\fR, -e.g. \fB0x0806\fR to match ARP packets. - -.IP \fBnw_src=\fIip\fR[\fB/\fInetmask\fR] -Matches IPv4 source address \fIip\fR, which should be specified as an -IP address or host name, e.g. \fB192.168.1.1\fR or -\fBwww.example.com\fR. The optional \fInetmask\fR allows matching -only on an IPv4 address prefix. It may be specified as a dotted quad -(e.g. \fB192.168.1.0/255.255.255.0\fR) or as a count of bits -(e.g. \fB192.168.1.0/24\fR). - -.IP \fBnw_dst=\fIip\fR[\fB/\fInetmask\fR] -Matches IPv4 destination address \fIip\fR. - -.IP \fBnw_proto=\fIproto\fR -Matches IP protocol type \fIproto\fR, which should be specified as a -decimal number between 0 and 255, inclusive, e.g. 6 to match TCP -packets. - -.IP \fBnw_tos=\fItos/dscp\fR -Matches ToS/DSCP (only 6-bits, not modify reserved 2-bits for future -use) field of IPv4 header \fItos/dscp\fR, which should be specified as -a decimal number between 0 and 255, inclusive. - -.IP \fBtp_src=\fIport\fR -Matches UDP or TCP source port \fIport\fR, which should be specified -as a decimal number between 0 and 65535, inclusive, e.g. 80 to match -packets originating from a HTTP server. - -.IP \fBtp_dst=\fIport\fR -Matches UDP or TCP destination port \fIport\fR. - -.IP \fBicmp_type=\fItype\fR -Matches ICMP message with \fItype\fR, which should be specified as a decimal -number between 0 and 255, inclusive. - -.IP \fBicmp_code=\fIcode\fR -Matches ICMP messages with \fIcode\fR. - -.PP -The following shorthand notations are also available: - -.IP \fBip\fR -Same as \fBdl_type=0x0800\fR. - -.IP \fBicmp\fR -Same as \fBdl_type=0x0800,nw_proto=1\fR. - -.IP \fBtcp\fR -Same as \fBdl_type=0x0800,nw_proto=6\fR. - -.IP \fBudp\fR -Same as \fBdl_type=0x0800,nw_proto=17\fR. - -.IP \fBarp\fR -Same as \fBdl_type=0x0806\fR. - -.PP -The \fBadd-flow\fR and \fBadd-flows\fR commands require an additional field: - -.IP \fIactions\fB=\fItarget\fR[\fB,\fItarget\fR...]\fR -Specifies a comma-separated list of actions to take on a packet when the -flow entry matches. The \fItarget\fR may be a decimal port number -designating the physical port on which to output the packet, or one of -the following keywords: - -.RS -.IP \fBoutput\fR:\fIport\fR -Outputs the packet on the port specified by \fIport\fR. - -.IP \fBenqueue\fR:\fIport\fR:\fIq-id\fR -Enqueue the packet to the queue specified by \fIq-id\fR on the port -specified by \fIport\fR. See \fBadd-queue\fR and related commands -in this manpage above. - -.IP \fBnormal\fR -Subjects the packet to the device's normal L2/L3 processing. (This -action is not implemented by all OpenFlow switches.) - -.IP \fBflood\fR -Outputs the packet on all switch physical ports other than the port on -which it was received and any ports on which flooding is disabled -(typically, these would be ports disabled by the IEEE 802.1D spanning -tree protocol). - -.IP \fBall\fR -Outputs the packet on all switch physical ports other than the port on -which it was received. - -.IP \fBcontroller\fR:\fImax_len\fR -Sends the packet to the OpenFlow controller as a ``packet in'' -message. If \fImax_len\fR is a number, then it specifies the maximum -number of bytes that should be sent. If \fImax_len\fR is \fBALL\fR or -omitted, then the entire packet is sent. - -.IP \fBlocal\fR -Outputs the packet on the ``local port,'' which corresponds to the -\fBof\fIn\fR network device (see \fBCONTACTING THE CONTROLLER\fR in -\fBofprotocol\fR(8) for information on the \fBof\fIn\fR network device). - -.IP \fBmod_vlan_vid\fR:\fIvlan_vid\fR -Modifies the VLAN id on a packet. The VLAN tag is added or modified -as necessary to match the value specified. If the VLAN tag is added, -a priority of zero is used (see the \fBmod_vlan_pcp\fR action to set -this). - -.IP \fBmod_vlan_pcp\fR:\fIvlan_pcp\fR -Modifies the VLAN priority on a packet. The VLAN tag is added or modified -as necessary to match the value specified. Valid values are between 0 -(lowest) and 7 (highest). If the VLAN tag is added, a vid of zero is used -(see the \fBmod_vlan_vid\fR action to set this). - -.IP \fBmod_dl_dst\fR:\fIdst_mac\fR -Modifies the destination mac address on a packet, e.g., actions=mod_dl_dst:12:34:56:78:9a:bc - -.IP \fBmod_dl_src\fR:\fIsrc_mac\fR -Modifies the source mac address on a packet, e.g., actions=mod_dl_src:12:34:56:78:9a:bc - -.IP \fBmod_nw_tos\fR:\fItos/dscp\fR -Modifies the ToS/DSCP (only 6-bits, not modify reserved 2-bits for future use) field of IPv4 header on a packet. - -.IP \fBstrip_vlan\fR -Strips the VLAN tag from a packet if it is present. -.RE - -.IP -(The OpenFlow protocol supports other actions that \fBdpctl\fR does -not yet expose to the user.) - -.PP -The \fBadd-flow\fR, \fBadd-flows\fR, \fBdel-flows\fR, -and \fBdel-emerg-flows\fR commands support an additional optional field: - -.IP \fBpriority=\fIvalue\fR -Sets the priority of the flow to be added or deleted to \fIvalue\fR, -which should be a number between 0 and 65535, inclusive. If this -field is not specified, it defaults to 32768. - -.PP -The \fBadd-flow\fR and \fBadd-flows\fR commands support -additional optional fields: - -.TP -\fBidle_timeout=\fIseconds\fR -Causes the flow to expire after the given number of seconds of -inactivity. A value of 0 prevents a flow from expiring due to -inactivity. The default is 60 seconds. - -.IP \fBhard_timeout=\fIseconds\fR -Causes the flow to expire after the given number of seconds, -regardless of activity. A value of 0 (the default) gives the flow no -hard expiration deadline. - -.PP -The \fBdump-flows\fR, \fBdump-aggregate\fR and \fBdel-flows\fR -commands support the additional optional field: - -.TP -\fBout_port=\fIport\fR -If set, a matching flow must include an output action to \fIport\fR. - -.PP -\fBadd-flow\fR, \fBadd-flows\fR, \fBdel-flows\fR, \fBdump-flows\fR, -and \fBdump-aggregate\fR commands support the additional -optional field: - -.IP \fBtable=\fInumber\fR -If specified, limits the flows about which statistics are gathered to -those in the table with the given \fInumber\fR. Normal (non emergency) -tables are numbered as shown by the \fBdump-tables\fR command. - -If this field is not specified, or if \fInumber\fR is given as -\fB255\fR, statistics are gathered about flows from all normal (non -emergency) tables and flow manipulations are applied to notmal tables. - -If this field is given as \fB254\fR, statistics are gathered about -flows from emergency table and flow manipulations are applied to -emergency table. - -.SH OPTIONS -.TP -\fB--strict\fR -Uses strict matching when running flow modification commands. - -.TP -\fB-t\fR, \fB--timeout=\fIsecs\fR -Limits \fBdpctl\fR runtime to approximately \fIsecs\fR seconds. If -the timeout expires, \fBdpctl\fR will exit with a \fBSIGALRM\fR -signal. - -.TP -\fB-p\fR, \fB--private-key=\fIprivkey.pem\fR -Specifies a PEM file containing the private key used as the -identity for SSL connections to a switch. - -.TP -\fB-c\fR, \fB--certificate=\fIcert.pem\fR -Specifies a PEM file containing a certificate, signed by the -controller's certificate authority (CA), that certifies the -private key to identify a trustworthy controller. - -.TP -\fB-C\fR, \fB--ca-cert=\fIcacert.pem\fR -Specifies a PEM file containing the CA certificate used to verify that -a switch is trustworthy. - -.so lib/vlog.man -.so lib/common.man - -.SH EXAMPLES - -A typical dpctl command sequence for controlling an OpenFlow kernel module: -.nf -.TP -Create datapath numbered 0: - -.B % dpctl adddp nl:0 - -.TP -Add two network devices to the new datapath: - -.B % dpctl addif nl:0 eth0 -.B % dpctl addif nl:0 eth1 - -.TP -Monitor traffic received by the datapath (exit with control-C): - -.B % dpctl monitor nl:0 - - -.TP -View the datapath's table stats after some traffic has passed through: - -.B % dpctl dump-tables nl:0 - -.TP -View the flow entries in the datapath: - -.B % dpctl dump-flows nl:0 - -.TP -Remove network devices from the datapath when finished: - -.B % dpctl delif nl:0 eth0 -.B % dpctl delif nl:0 eth1 - -.TP -Delete the datapath: - -.B % dpctl deldp nl:0 -.fi -.SH "SEE ALSO" - -.BR ofprotocol (8), -.BR controller (8), -.BR ofdatapath (8), -.BR vlogconf (8) diff --git a/openflow/utilities/dpctl.c b/openflow/utilities/dpctl.c deleted file mode 100644 index 0406d9b5..00000000 --- a/openflow/utilities/dpctl.c +++ /dev/null @@ -1,1772 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_NETLINK -#include "netdev.h" -#include "netlink.h" -#include "openflow/openflow-netlink.h" -#endif - -#include "command-line.h" -#include "compiler.h" -#include "dpif.h" -#include "openflow/nicira-ext.h" -#include "openflow/openflow-ext.h" -#include "ofp-print.h" -#include "ofpbuf.h" -#include "openflow/openflow.h" -#include "packets.h" -#include "random.h" -#include "socket-util.h" -#include "timeval.h" -#include "util.h" -#include "vconn-ssl.h" -#include "vconn.h" - -#include "xtoxll.h" -#include "ofpstat.h" -#include "openflow/private-ext.h" - -#include "vlog.h" -#define THIS_MODULE VLM_dpctl - -#define DEFAULT_IDLE_TIMEOUT 60 - -/* Maximum size of action buffer for adding and modify flows */ -#define MAX_ACT_LEN 60 - -#define MOD_PORT_CMD_UP "up" -#define MOD_PORT_CMD_DOWN "down" -#define MOD_PORT_CMD_FLOOD "flood" -#define MOD_PORT_CMD_NOFLOOD "noflood" - - -/* Settings that may be configured by the user. */ -struct settings { - bool strict; /* Use strict matching for flow mod commands */ -}; - -struct command { - const char *name; - int min_args; - int max_args; - void (*handler)(const struct settings *, int argc, char *argv[]); -}; - -static struct command all_commands[]; - -static void usage(void) NO_RETURN; -static void parse_options(int argc, char *argv[], struct settings *); - -int main(int argc, char *argv[]) -{ - struct settings s; - struct command *p; - - set_program_name(argv[0]); - time_init(); - vlog_init(); - parse_options(argc, argv, &s); - signal(SIGPIPE, SIG_IGN); - - argc -= optind; - argv += optind; - if (argc < 1) - ofp_fatal(0, "missing command name; use --help for help"); - - for (p = all_commands; p->name != NULL; p++) { - if (!strcmp(p->name, argv[0])) { - int n_arg = argc - 1; - if (n_arg < p->min_args) - ofp_fatal(0, "'%s' command requires at least %d arguments", - p->name, p->min_args); - else if (n_arg > p->max_args) - ofp_fatal(0, "'%s' command takes at most %d arguments", - p->name, p->max_args); - else { - p->handler(&s, argc, argv); - if (ferror(stdout)) { - ofp_fatal(0, "write to stdout failed"); - } - if (ferror(stderr)) { - ofp_fatal(0, "write to stderr failed"); - } - exit(0); - } - } - } - ofp_fatal(0, "unknown command '%s'; use --help for help", argv[0]); - - return 0; -} - -static void -parse_options(int argc, char *argv[], struct settings *s) -{ - enum { - OPT_STRICT = UCHAR_MAX + 1 - }; - static struct option long_options[] = { - {"timeout", required_argument, 0, 't'}, - {"verbose", optional_argument, 0, 'v'}, - {"strict", no_argument, 0, OPT_STRICT}, - {"help", no_argument, 0, 'h'}, - {"version", no_argument, 0, 'V'}, - VCONN_SSL_LONG_OPTIONS - {0, 0, 0, 0}, - }; - char *short_options = long_options_to_short_options(long_options); - - /* Set defaults that we can figure out before parsing options. */ - s->strict = false; - - for (;;) { - unsigned long int timeout; - int c; - - c = getopt_long(argc, argv, short_options, long_options, NULL); - if (c == -1) { - break; - } - - switch (c) { - case 't': - timeout = strtoul(optarg, NULL, 10); - if (timeout <= 0) { - ofp_fatal(0, "value %s on -t or --timeout is not at least 1", - optarg); - } else { - time_alarm(timeout); - } - break; - - case 'h': - usage(); - - case 'V': - printf("%s %s compiled "__DATE__" "__TIME__"\n", - program_name, VERSION BUILDNR); - exit(EXIT_SUCCESS); - - case 'v': - vlog_set_verbosity(optarg); - break; - - case OPT_STRICT: - s->strict = true; - break; - - VCONN_SSL_OPTION_HANDLERS - - case '?': - exit(EXIT_FAILURE); - - default: - abort(); - } - } - free(short_options); -} - -static void -usage(void) -{ - printf("%s: OpenFlow switch management utility\n" - "usage: %s [OPTIONS] COMMAND [ARG...]\n" -#ifdef HAVE_NETLINK - "\nFor local datapaths only:\n" - " adddp nl:DP_ID add a new local datapath DP_ID\n" - " deldp nl:DP_ID delete local datapath DP_ID\n" - " addif nl:DP_ID IFACE... add each IFACE as a port on DP_ID\n" - " delif nl:DP_ID IFACE... delete each IFACE from DP_ID\n" - " get-idx OF_DEV get datapath index for OF_DEV\n" -#endif - "\nFor local datapaths and remote switches:\n" - " show SWITCH show basic information\n" - " status SWITCH [KEY] report statistics (about KEY)\n" - " show-protostat SWITCH report protocol statistics\n" - " dump-desc SWITCH print switch description\n" - " dump-tables SWITCH print table stats\n" - " mod-port SWITCH IFACE ACT modify port behavior\n" - " dump-ports SWITCH [PORT] print port statistics\n" - " desc SWITCH STRING set switch description\n" - " dump-flows SWITCH print all flow entries\n" - " dump-flows SWITCH FLOW print matching FLOWs\n" - " dump-aggregate SWITCH print aggregate flow statistics\n" - " dump-aggregate SWITCH FLOW print aggregate stats for FLOWs\n" - " add-flow SWITCH FLOW add flow described by FLOW\n" - " add-flows SWITCH FILE add flows from FILE\n" - " mod-flows SWITCH FLOW modify actions of matching FLOWs\n" - " del-flows SWITCH [FLOW] delete matching FLOWs\n" - " monitor SWITCH print packets received from SWITCH\n" - " execute SWITCH CMD [ARG...] execute CMD with ARGS on SWITCH\n" - "Queue Ops: Q: queue-id; P: port-id; BW: perthousand bandwidth\n" - " add-queue SWITCH P Q [BW] add queue (with min bandwidth)\n" - " mod-queue SWITCH P Q BW modify queue min bandwidth\n" - " del-queue SWITCH P Q delete queue\n" - " dump-queue SWITCH [P [Q]] show queue info\n" - "\nFor local datapaths, remote switches, and controllers:\n" - " probe VCONN probe whether VCONN is up\n" - " ping VCONN [N] latency of N-byte echos\n" - " benchmark VCONN N COUNT bandwidth of COUNT N-byte echos\n" - "where each SWITCH is an active OpenFlow connection method.\n", - program_name, program_name); - vconn_usage(true, false, false); - vlog_usage(); - printf("\nOther options:\n" - " --strict use strict match for flow commands\n" - " -t, --timeout=SECS give up after SECS seconds\n" - " -h, --help display this help message\n" - " -V, --version display version information\n"); - exit(EXIT_SUCCESS); -} - -static void run(int retval, const char *message, ...) - PRINTF_FORMAT(2, 3); - -static void run(int retval, const char *message, ...) -{ - if (retval) { - va_list args; - - fprintf(stderr, "%s: ", program_name); - va_start(args, message); - vfprintf(stderr, message, args); - va_end(args); - if (retval == EOF) { - fputs(": unexpected end of file\n", stderr); - } else { - fprintf(stderr, ": %s\n", strerror(retval)); - } - - exit(EXIT_FAILURE); - } -} - -#ifdef HAVE_NETLINK -/* Netlink-only commands. */ - -static int if_up(const char *netdev_name) -{ - struct netdev *netdev; - int retval; - - retval = netdev_open(netdev_name, NETDEV_ETH_TYPE_NONE, &netdev); - if (!retval) { - retval = netdev_turn_flags_on(netdev, NETDEV_UP, true); - netdev_close(netdev); - } - return retval; -} - -static void -do_get_idx(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) -{ - int dp_idx; - - struct dpif dpif; - run(dpif_open(-1, &dpif), "opening management socket"); - dp_idx = dpif_get_idx(argv[1]); - if (dp_idx == -1) { - dpif_close(&dpif); - ofp_fatal(0, "unknown OpenFlow device: %s", argv[1]); - } - printf("%d\n", dp_idx); - dpif_close(&dpif); -} - -static int -get_dp_idx(const char *name) -{ - if (strncmp(name, "nl:", 3) - || strlen(name) < 4 - || name[strspn(name + 3, "0123456789") + 3]) { - ofp_fatal(0, "%s: argument is not of the form \"nl:DP_ID\"", name); - } - return atoi(name + 3); -} - -static void -do_add_dp(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) -{ - struct dpif dpif; - run(dpif_open(-1, &dpif), "opening management socket"); - run(dpif_add_dp(&dpif, get_dp_idx(argv[1]), NULL), "add_dp"); - dpif_close(&dpif); -} - -static void -do_del_dp(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) -{ - struct dpif dpif; - run(dpif_open(-1, &dpif), "opening management socket"); - run(dpif_del_dp(&dpif, get_dp_idx(argv[1]), NULL), "del_dp"); - dpif_close(&dpif); -} - -static void add_del_ports(int argc UNUSED, char *argv[], - int (*function)(struct dpif *, int dp_idx, - const char *netdev), - const char *operation, const char *preposition) -{ - bool failure = false; - struct dpif dpif; - int dp_idx; - int i; - - run(dpif_open(-1, &dpif), "opening management socket"); - dp_idx = get_dp_idx(argv[1]); - for (i = 2; i < argc; i++) { - int retval = function(&dpif, dp_idx, argv[i]); - if (retval) { - ofp_error(retval, "failed to %s %s %s %s", - operation, argv[i], preposition, argv[1]); - failure = true; - } - } - dpif_close(&dpif); - if (failure) { - exit(EXIT_FAILURE); - } -} - -static int ifup_and_add_port(struct dpif *dpif, int dp_idx, const char *netdev) -{ - int retval = if_up(netdev); - return retval ? retval : dpif_add_port(dpif, dp_idx, netdev); -} - -static void do_add_port(const struct settings *s UNUSED, int argc UNUSED, - char *argv[]) -{ - add_del_ports(argc, argv, ifup_and_add_port, "add", "to"); -} - -static void do_del_port(const struct settings *s UNUSED, int argc UNUSED, - char *argv[]) -{ - add_del_ports(argc, argv, dpif_del_port, "remove", "from"); -} -#endif /* HAVE_NETLINK */ - -/* Generic commands. */ - -static void -open_vconn(const char *name, struct vconn **vconnp) -{ - run(vconn_open_block(name, OFP_VERSION, vconnp), "connecting to %s", name); -} - -static void * -alloc_stats_request(size_t body_len, uint16_t type, struct ofpbuf **bufferp) -{ - struct ofp_stats_request *rq; - rq = make_openflow((offsetof(struct ofp_stats_request, body) - + body_len), OFPT_STATS_REQUEST, bufferp); - rq->type = htons(type); - rq->flags = htons(0); - return rq->body; -} - -static void -send_openflow_buffer(struct vconn *vconn, struct ofpbuf *buffer) -{ - update_openflow_length(buffer); - run(vconn_send_block(vconn, buffer), "failed to send packet to switch"); -} - -static void -dump_transaction(const char *vconn_name, struct ofpbuf *request) -{ - struct vconn *vconn; - struct ofpbuf *reply; - - update_openflow_length(request); - open_vconn(vconn_name, &vconn); - run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name); - ofp_print(stdout, reply->data, reply->size, 1); - vconn_close(vconn); -} - -static void -dump_trivial_transaction(const char *vconn_name, uint8_t request_type) -{ - struct ofpbuf *request; - make_openflow(sizeof(struct ofp_header), request_type, &request); - dump_transaction(vconn_name, request); -} - -static void -dump_stats_transaction(const char *vconn_name, struct ofpbuf *request) -{ - uint32_t send_xid = ((struct ofp_header *) request->data)->xid; - struct vconn *vconn; - bool done = false; - - open_vconn(vconn_name, &vconn); - send_openflow_buffer(vconn, request); - while (!done) { - uint32_t recv_xid; - struct ofpbuf *reply; - - run(vconn_recv_block(vconn, &reply), "OpenFlow packet receive failed"); - - recv_xid = ((struct ofp_header *) reply->data)->xid; - if (send_xid == recv_xid) { - struct ofp_stats_reply *osr; - - ofp_print(stdout, reply->data, reply->size, 1); - - osr = ofpbuf_at(reply, 0, sizeof *osr); - done = !osr || !(ntohs(osr->flags) & OFPSF_REPLY_MORE); - } else { - VLOG_DBG("received reply with xid %08"PRIx32" " - "!= expected %08"PRIx32, recv_xid, send_xid); - } - ofpbuf_delete(reply); - } - vconn_close(vconn); -} - -static void -dump_trivial_stats_transaction(const char *vconn_name, uint8_t stats_type) -{ - struct ofpbuf *request; - alloc_stats_request(0, stats_type, &request); - dump_stats_transaction(vconn_name, request); -} - -/* Get the pointer to struct member based on member offset */ -#define S_PTR(_ptr, _type, _member) \ - ((void *)(((char *)(_ptr)) + offsetof(_type, _member))) - -static void -dump_queue_stats_transaction(const char *vconn_name, uint8_t stats_type, - uint16_t port, uint32_t q_id) -{ - struct ofpbuf *request; - struct ofp_queue_stats_request *q_req; - struct ofp_stats_request *stats_req; - - alloc_stats_request(sizeof(struct ofp_queue_stats_request), - stats_type, &request); - stats_req = request->data; - q_req = S_PTR(stats_req, struct ofp_stats_request, body); - - q_req->port_no = htons(port); - q_req->queue_id = htonl(q_id); - dump_stats_transaction(vconn_name, request); -} - -static void -do_show(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) -{ - dump_trivial_transaction(argv[1], OFPT_FEATURES_REQUEST); - dump_trivial_transaction(argv[1], OFPT_GET_CONFIG_REQUEST); -} - -static void -do_status(const struct settings *s UNUSED, int argc, char *argv[]) -{ - struct nicira_header *request, *reply; - struct vconn *vconn; - struct ofpbuf *b; - - request = make_openflow(sizeof *request, OFPT_VENDOR, &b); - request->vendor = htonl(NX_VENDOR_ID); - request->subtype = htonl(NXT_STATUS_REQUEST); - if (argc > 2) { - ofpbuf_put(b, argv[2], strlen(argv[2])); - } - open_vconn(argv[1], &vconn); - run(vconn_transact(vconn, b, &b), "talking to %s", argv[1]); - vconn_close(vconn); - - if (b->size < sizeof *reply) { - ofp_fatal(0, "short reply (%zu bytes)", b->size); - } - reply = b->data; - if (reply->header.type != OFPT_VENDOR - || reply->vendor != ntohl(NX_VENDOR_ID) - || reply->subtype != ntohl(NXT_STATUS_REPLY)) { - ofp_print(stderr, b->data, b->size, 2); - ofp_fatal(0, "bad reply"); - } - - fwrite(reply + 1, b->size, 1, stdout); -} - -static void -print_protocol_stat(struct ofpstat *ofps_rcvd, struct ofpstat *ofps_sent) -{ - int i; - struct ofpstat *ifps = NULL; -#define PREFIX_STR " " -#define PREFIX_RCVD "Rcvd: " -#define PREFIX_SENT "Sent: " - - fprintf(stdout, - "OpenFlow protocol version 0x%x statisical information\n", - OFP_VERSION); - fprintf(stdout, "\n"); - - fprintf(stdout, "Protocol message:\n"); - for (i = 0; i < 2; ++i) { - ifps = i == 0 ? ofps_rcvd : ofps_sent; - fprintf(stdout, - "%s" - "%"PRIu64" total msgs, %"PRIu64" unknown msgs\n", - i == 0 ? PREFIX_RCVD : PREFIX_SENT, - ntohll(ifps->ofps_total), - ntohll(ifps->ofps_unknown)); - fprintf(stdout, - PREFIX_STR - "%"PRIu64" hello, %"PRIu64" errors, " - "%"PRIu64" echo, %"PRIu64" echo reply, " - "%"PRIu64" vendor\n", - ntohll(ifps->ofps_hello), - ntohll(ifps->ofps_error), - ntohll(ifps->ofps_echo_request), - ntohll(ifps->ofps_echo_reply), - ntohll(ifps->ofps_vendor)); - fprintf(stdout, - PREFIX_STR - "%"PRIu64" feats, %"PRIu64" feats reply\n", - ntohll(ifps->ofps_feats_request), - ntohll(ifps->ofps_feats_reply)); - fprintf(stdout, - PREFIX_STR - "%"PRIu64" get config, %"PRIu64" get config reply, " - "%"PRIu64" set config\n", - ntohll(ifps->ofps_get_config_request), - ntohll(ifps->ofps_get_config_reply), - ntohll(ifps->ofps_set_config)); - fprintf(stdout, - PREFIX_STR - "%"PRIu64" packet in, %"PRIu64" flow removed, " - "%"PRIu64" port status\n", - ntohll(ifps->ofps_packet_in), - ntohll(ifps->ofps_flow_removed), - ntohll(ifps->ofps_port_status)); - fprintf(stdout, - PREFIX_STR - "%"PRIu64" packet out, %"PRIu64" flow mod, %"PRIu64" port mod\n", - ntohll(ifps->ofps_packet_out), - ntohll(ifps->ofps_flow_mod), - ntohll(ifps->ofps_port_mod)); - fprintf(stdout, - PREFIX_STR - "%"PRIu64" stats, %"PRIu64" stats reply, " - "%"PRIu64" barrier, %"PRIu64" barrier reply\n", - ntohll(ifps->ofps_stats_request), - ntohll(ifps->ofps_stats_reply), - ntohll(ifps->ofps_barrier_request), - ntohll(ifps->ofps_barrier_reply)); - } - fprintf(stdout, "\n"); - - fprintf(stdout, "Flow manipulation:\n"); - for (i = 0; i < 2; ++i) { - ifps = i == 0 ? ofps_rcvd : ofps_sent; - fprintf(stdout, - "%s" - "%"PRIu64" add, %"PRIu64" modify, %"PRIu64" modify strict\n", - i == 0 ? PREFIX_RCVD : PREFIX_SENT, - ntohll(ifps->ofps_flow_mod_ops.add), - ntohll(ifps->ofps_flow_mod_ops.modify), - ntohll(ifps->ofps_flow_mod_ops.modify_strict)); - fprintf(stdout, - PREFIX_STR - "%"PRIu64" delete, %"PRIu64" delete strict, %"PRIu64" unknown cmd\n", - ntohll(ifps->ofps_flow_mod_ops.delete), - ntohll(ifps->ofps_flow_mod_ops.delete_strict), - ntohll(ifps->ofps_flow_mod_ops.unknown)); - } - fprintf(stdout, "\n"); - - fprintf(stdout, "Error notification:\n"); - for (i = 0; i < 2; ++i) { - ifps = i == 0 ? ofps_rcvd : ofps_sent; - fprintf(stdout, - "%s" - "%"PRIu64" hello fail: %"PRIu64" incompat, %"PRIu64" eperm\n", - i == 0 ? PREFIX_RCVD : PREFIX_SENT, - ntohll(ifps->ofps_error_type.hello_fail), - ntohll(ifps->ofps_error_code.hf_incompat), - ntohll(ifps->ofps_error_code.hf_eperm)); - fprintf(stdout, - PREFIX_STR - "%"PRIu64" bad request: %"PRIu64" version, %"PRIu64" type, " - "%"PRIu64" stat, %"PRIu64" vendor\n" - PREFIX_STR - " %"PRIu64" eperm\n", - ntohll(ifps->ofps_error_type.bad_request), - ntohll(ifps->ofps_error_code.br_bad_version), - ntohll(ifps->ofps_error_code.br_bad_type), - ntohll(ifps->ofps_error_code.br_bad_stat), - ntohll(ifps->ofps_error_code.br_bad_vendor), - ntohll(ifps->ofps_error_code.br_eperm)); - fprintf(stdout, - PREFIX_STR - "%"PRIu64" bad action: %"PRIu64" type, %"PRIu64" len, " - "%"PRIu64" vendor, %"PRIu64" vendor type\n" - PREFIX_STR - " %"PRIu64" out port, %"PRIu64" argument, %"PRIu64" eperm\n", - ntohll(ifps->ofps_error_type.bad_action), - ntohll(ifps->ofps_error_code.ba_bad_type), - ntohll(ifps->ofps_error_code.ba_bad_len), - ntohll(ifps->ofps_error_code.ba_bad_vendor), - ntohll(ifps->ofps_error_code.ba_bad_vendor_type), - ntohll(ifps->ofps_error_code.ba_bad_out_port), - ntohll(ifps->ofps_error_code.ba_bad_argument), - ntohll(ifps->ofps_error_code.ba_eperm)); - fprintf(stdout, - PREFIX_STR - "%"PRIu64" flow mod fail: %"PRIu64" all tables full, " - "%"PRIu64" overlap, %"PRIu64" eperm, %"PRIu64" emerg\n", - ntohll(ifps->ofps_error_type.flow_mod_fail), - ntohll(ifps->ofps_error_code.fmf_all_tables_full), - ntohll(ifps->ofps_error_code.fmf_overlap), - ntohll(ifps->ofps_error_code.fmf_eperm), - ntohll(ifps->ofps_error_code.fmf_emerg)); - fprintf(stdout, - PREFIX_STR - "%"PRIu64" unknown type, %"PRIu64" unknown code\n", - ntohll(ifps->ofps_error_type.unknown), - ntohll(ifps->ofps_error_code.unknown)); - } - fprintf(stdout, "\n"); -} - -static void -do_protostat(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) -{ - struct ofpbuf *buf; - struct private_vxhdr *vxhdr; - struct private_vxopt *vxopt; - struct vconn *vconn; - struct ofpstat* ofps; - - vxhdr = make_openflow(sizeof(*vxhdr) + sizeof(*vxopt), OFPT_VENDOR, &buf); - vxopt = (struct private_vxopt *)(vxhdr + 1); - vxhdr->ofp_vxid = htonl(PRIVATE_VENDOR_ID); - vxopt->pvo_type = htons(PRIVATEOPT_PROTOCOL_STATS_REQUEST); - vxopt->pvo_len = 0; - - open_vconn(argv[1], &vconn); - run(vconn_transact(vconn, buf, &buf), "talking to %s", argv[1]); - vconn_close(vconn); - if (buf->size < sizeof(*vxhdr)) { - ofp_fatal(0, "short reply (%zu bytes)", buf->size); - } - - vxhdr = buf->data; - if (vxhdr->ofp_hdr.type != OFPT_VENDOR - || ntohl(vxhdr->ofp_vxid) != PRIVATE_VENDOR_ID) { - ofp_print(stderr, buf->data, buf->size, 2); - ofp_fatal(0, "bad reply"); - } - vxopt = (struct private_vxopt *)(vxhdr + 1); - if (ntohs(vxopt->pvo_type) != PRIVATEOPT_PROTOCOL_STATS_REPLY - || ntohs(vxopt->pvo_len) != (sizeof(*ofps) * 2)) { - ofp_print(stderr, buf->data, buf->size, 2); - ofp_fatal(0, "bad reply"); - } - - ofps = (struct ofpstat *)(vxopt + 1); - print_protocol_stat(ofps, ofps + 1); -} - -static void -do_dump_desc(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) -{ - dump_trivial_stats_transaction(argv[1], OFPST_DESC); -} - -static void -do_dump_tables(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) -{ - dump_trivial_stats_transaction(argv[1], OFPST_TABLE); -} - -static uint32_t -str_to_u32(const char *str) -{ - char *tail; - uint32_t value; - - errno = 0; - value = strtoul(str, &tail, 0); - if (errno == EINVAL || errno == ERANGE || *tail) { - ofp_fatal(0, "invalid numeric format %s", str); - } - return value; -} - -static void -str_to_mac(const char *str, uint8_t mac[6]) -{ - if (sscanf(str, "%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8, - &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]) != 6) { - ofp_fatal(0, "invalid mac address %s", str); - } -} - -static uint32_t -str_to_ip(const char *str_, uint32_t *ip) -{ - char *str = xstrdup(str_); - char *save_ptr = NULL; - const char *name, *netmask; - struct in_addr in_addr; - int n_wild, retval; - - name = strtok_r(str, "//", &save_ptr); - retval = name ? lookup_ip(name, &in_addr) : EINVAL; - if (retval) { - ofp_fatal(0, "%s: could not convert to IP address", str); - } - *ip = in_addr.s_addr; - - netmask = strtok_r(NULL, "//", &save_ptr); - if (netmask) { - uint8_t o[4]; - if (sscanf(netmask, "%"SCNu8".%"SCNu8".%"SCNu8".%"SCNu8, - &o[0], &o[1], &o[2], &o[3]) == 4) { - uint32_t nm = (o[0] << 24) | (o[1] << 16) | (o[2] << 8) | o[3]; - int i; - - /* Find first 1-bit. */ - for (i = 0; i < 32; i++) { - if (nm & (1u << i)) { - break; - } - } - n_wild = i; - - /* Verify that the rest of the bits are 1-bits. */ - for (; i < 32; i++) { - if (!(nm & (1u << i))) { - ofp_fatal(0, "%s: %s is not a valid netmask", - str, netmask); - } - } - } else { - int prefix = atoi(netmask); - if (prefix <= 0 || prefix > 32) { - ofp_fatal(0, "%s: network prefix bits not between 1 and 32", - str); - } - n_wild = 32 - prefix; - } - } else { - n_wild = 0; - } - - free(str); - return n_wild; -} - -static void * -put_action(struct ofpbuf *b, size_t size, uint16_t type) -{ - struct ofp_action_header *ah = ofpbuf_put_zeros(b, size); - ah->type = htons(type); - ah->len = htons(size); - return ah; -} - -static struct ofp_action_output * -put_output_action(struct ofpbuf *b, uint16_t port) -{ - struct ofp_action_output *oao = put_action(b, sizeof *oao, OFPAT_OUTPUT); - oao->port = htons(port); - return oao; -} - -static struct ofp_action_enqueue * -put_enqueue_action(struct ofpbuf *b, uint16_t port, uint32_t queue) -{ - struct ofp_action_enqueue *oao; - - oao = put_action(b, sizeof *oao, OFPAT_ENQUEUE); - oao->len = htons(sizeof(*oao)); - oao->port = htons(port); - oao->queue_id = htonl(queue); - return oao; -} - -static void -str_to_action(char *str, struct ofpbuf *b) -{ - char *act, *arg, *arg2; - char *saveptr = NULL; - - for (act = strtok_r(str, ", \t\r\n", &saveptr); act; - act = strtok_r(NULL, ", \t\r\n", &saveptr)) - { - /* Arguments are separated by colons */ - arg = strchr(act, ':'); - if (arg) { - *arg = '\0'; - arg++; - } - - if (!strcasecmp(act, "mod_nw_tos")) { - struct ofp_action_nw_tos *va; - va = put_action(b, sizeof *va, OFPAT_SET_NW_TOS); - va->nw_tos = str_to_u32(arg); - } else if (!strcasecmp(act, "mod_vlan_vid")) { - struct ofp_action_vlan_vid *va; - va = put_action(b, sizeof *va, OFPAT_SET_VLAN_VID); - va->vlan_vid = htons(str_to_u32(arg)); - } else if (!strcasecmp(act, "mod_vlan_pcp")) { - struct ofp_action_vlan_pcp *va; - va = put_action(b, sizeof *va, OFPAT_SET_VLAN_PCP); - va->vlan_pcp = str_to_u32(arg); - } else if (!strcasecmp(act, "mod_dl_dst")) { - struct ofp_action_dl_addr *va; - va = put_action(b, sizeof *va, OFPAT_SET_DL_DST); - str_to_mac(arg, va->dl_addr); - } else if (!strcasecmp(act, "mod_dl_src")) { - struct ofp_action_dl_addr *va; - va = put_action(b, sizeof *va, OFPAT_SET_DL_SRC); - str_to_mac(arg, va->dl_addr); - } else if (!strcasecmp(act, "strip_vlan")) { - struct ofp_action_header *ah; - ah = put_action(b, sizeof *ah, OFPAT_STRIP_VLAN); - ah->type = htons(OFPAT_STRIP_VLAN); - } else if (!strcasecmp(act, "enqueue")) { - arg2 = strchr(arg, ':'); - if (arg2) { - *arg2 = '\0'; - arg2++; - } - put_enqueue_action(b, str_to_u32(arg), str_to_u32(arg2)); - } else if (!strcasecmp(act, "output")) { - put_output_action(b, str_to_u32(arg)); - } else if (!strcasecmp(act, "TABLE")) { - put_output_action(b, OFPP_TABLE); - } else if (!strcasecmp(act, "NORMAL")) { - put_output_action(b, OFPP_NORMAL); - } else if (!strcasecmp(act, "FLOOD")) { - put_output_action(b, OFPP_FLOOD); - } else if (!strcasecmp(act, "ALL")) { - put_output_action(b, OFPP_ALL); - } else if (!strcasecmp(act, "CONTROLLER")) { - struct ofp_action_output *oao; - oao = put_output_action(b, OFPP_CONTROLLER); - - /* Unless a numeric argument is specified, we send the whole - * packet to the controller. */ - if (arg && (strspn(act, "0123456789") == strlen(act))) { - oao->max_len = htons(str_to_u32(arg)); - } - } else if (!strcasecmp(act, "LOCAL")) { - put_output_action(b, OFPP_LOCAL); - } else if (strspn(act, "0123456789") == strlen(act)) { - put_output_action(b, str_to_u32(act)); - } else { - ofp_fatal(0, "Unknown action: %s", act); - } - } -} - -struct protocol { - const char *name; - uint16_t dl_type; - uint8_t nw_proto; -}; - -static bool -parse_protocol(const char *name, const struct protocol **p_out) -{ - static const struct protocol protocols[] = { - { "ip", ETH_TYPE_IP, 0 }, - { "arp", ETH_TYPE_ARP, 0 }, - { "icmp", ETH_TYPE_IP, IP_TYPE_ICMP }, - { "tcp", ETH_TYPE_IP, IP_TYPE_TCP }, - { "udp", ETH_TYPE_IP, IP_TYPE_UDP }, - }; - const struct protocol *p; - - for (p = protocols; p < &protocols[ARRAY_SIZE(protocols)]; p++) { - if (!strcmp(p->name, name)) { - *p_out = p; - return true; - } - } - *p_out = NULL; - return false; -} - -struct field { - const char *name; - uint32_t wildcard; - enum { F_U8, F_U16, F_MAC, F_IP } type; - size_t offset, shift; -}; - -static bool -parse_field(const char *name, const struct field **f_out) -{ -#define F_OFS(MEMBER) offsetof(struct ofp_match, MEMBER) - static const struct field fields[] = { - { "in_port", OFPFW_IN_PORT, F_U16, F_OFS(in_port), 0 }, - { "dl_vlan", OFPFW_DL_VLAN, F_U16, F_OFS(dl_vlan), 0 }, - { "dl_vlan_pcp", OFPFW_DL_VLAN_PCP, F_U8, F_OFS(dl_vlan_pcp), 0 }, - { "dl_src", OFPFW_DL_SRC, F_MAC, F_OFS(dl_src), 0 }, - { "dl_dst", OFPFW_DL_DST, F_MAC, F_OFS(dl_dst), 0 }, - { "dl_type", OFPFW_DL_TYPE, F_U16, F_OFS(dl_type), 0 }, - { "nw_tos", OFPFW_NW_TOS, F_U8, F_OFS(nw_tos), 0 }, - { "nw_proto", OFPFW_NW_PROTO, F_U8, F_OFS(nw_proto), 0 }, - { "nw_src", OFPFW_NW_SRC_MASK, F_IP, - F_OFS(nw_src), OFPFW_NW_SRC_SHIFT }, - { "nw_dst", OFPFW_NW_DST_MASK, F_IP, - F_OFS(nw_dst), OFPFW_NW_DST_SHIFT }, - { "tp_src", OFPFW_TP_SRC, F_U16, F_OFS(tp_src), 0 }, - { "tp_dst", OFPFW_TP_DST, F_U16, F_OFS(tp_dst), 0 }, - { "icmp_type", OFPFW_ICMP_TYPE, F_U16, F_OFS(icmp_type), 0 }, - { "icmp_code", OFPFW_ICMP_CODE, F_U16, F_OFS(icmp_code), 0 } - }; - const struct field *f; - - for (f = fields; f < &fields[ARRAY_SIZE(fields)]; f++) { - if (!strcmp(f->name, name)) { - *f_out = f; - return true; - } - } - *f_out = NULL; - return false; -} - -static void -str_to_flow(char *string, struct ofp_match *match, struct ofpbuf *actions, - uint8_t *table_idx, uint16_t *out_port, uint16_t *priority, - uint16_t *idle_timeout, uint16_t *hard_timeout, - uint64_t *cookie) -{ - char *save_ptr = NULL; - char *name; - uint32_t wildcards; - - if (table_idx) { - *table_idx = 0xff; - } - if (out_port) { - *out_port = OFPP_NONE; - } - if (priority) { - *priority = OFP_DEFAULT_PRIORITY; - } - if (idle_timeout) { - *idle_timeout = DEFAULT_IDLE_TIMEOUT; - } - if (hard_timeout) { - *hard_timeout = OFP_FLOW_PERMANENT; - } - if (cookie) { - *cookie = 0; - } - if (actions) { - char *act_str = strstr(string, "actions"); - if (!act_str) { - ofp_fatal(0, "must specify an action"); - } - *(act_str-1) = '\0'; - - act_str = strchr(act_str, '='); - if (!act_str) { - ofp_fatal(0, "must specify an action"); - } - - act_str++; - - str_to_action(act_str, actions); - } - memset(match, 0, sizeof *match); - wildcards = OFPFW_ALL; - for (name = strtok_r(string, "=, \t\r\n", &save_ptr); name; - name = strtok_r(NULL, "=, \t\r\n", &save_ptr)) { - const struct protocol *p; - - if (parse_protocol(name, &p)) { - wildcards &= ~OFPFW_DL_TYPE; - match->dl_type = htons(p->dl_type); - if (p->nw_proto) { - wildcards &= ~OFPFW_NW_PROTO; - match->nw_proto = p->nw_proto; - } - } else { - const struct field *f; - char *value; - - value = strtok_r(NULL, ", \t\r\n", &save_ptr); - if (!value) { - ofp_fatal(0, "field %s missing value", name); - } - - if (table_idx && !strcmp(name, "table")) { - *table_idx = atoi(value); - } else if (out_port && !strcmp(name, "out_port")) { - *out_port = atoi(value); - } else if (priority && !strcmp(name, "priority")) { - *priority = atoi(value); - } else if (idle_timeout && !strcmp(name, "idle_timeout")) { - *idle_timeout = atoi(value); - } else if (hard_timeout && !strcmp(name, "hard_timeout")) { - *hard_timeout = atoi(value); - } else if (cookie && !strcmp(name, "cookie")) { - *cookie = atoi(value); - } else if (parse_field(name, &f)) { - void *data = (char *) match + f->offset; - if (!strcmp(value, "*") || !strcmp(value, "ANY")) { - wildcards |= f->wildcard; - } else { - wildcards &= ~f->wildcard; - if (f->type == F_U8) { - *(uint8_t *) data = str_to_u32(value); - } else if (f->type == F_U16) { - *(uint16_t *) data = htons(str_to_u32(value)); - } else if (f->type == F_MAC) { - str_to_mac(value, data); - } else if (f->type == F_IP) { - wildcards |= str_to_ip(value, data) << f->shift; - } else { - NOT_REACHED(); - } - } - } else { - ofp_fatal(0, "unknown keyword %s", name); - } - } - } - match->wildcards = htonl(wildcards); -} - -static void -do_desc(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) -{ - struct vconn * vconn; - struct ofpbuf * msg; - struct openflow_ext_set_dp_desc * desc; - - msg = ofpbuf_new(sizeof(*desc)); - ofpbuf_put_uninit(msg, sizeof(*desc)); - desc = ofpbuf_at_assert(msg, 0, sizeof(*desc)); - desc->header.header.version = OFP_VERSION; - desc->header.header.type = OFPT_VENDOR; - desc->header.header.length = htons(sizeof(*desc)); - desc->header.vendor = htonl(OPENFLOW_VENDOR_ID); - desc->header.subtype = htonl(OFP_EXT_SET_DESC); - strncpy(desc->dp_desc, argv[2], DESC_STR_LEN); - - open_vconn(argv[1], &vconn); - send_openflow_buffer(vconn, msg); - vconn_close(vconn); -} - -static void -do_dump_flows(const struct settings *s UNUSED, int argc, char *argv[]) -{ - struct ofp_flow_stats_request *req; - uint16_t out_port; - struct ofpbuf *request; - - req = alloc_stats_request(sizeof *req, OFPST_FLOW, &request); - str_to_flow(argc > 2 ? argv[2] : "", &req->match, NULL, - &req->table_id, &out_port, NULL, NULL, NULL, NULL); - memset(&req->pad, 0, sizeof req->pad); - req->out_port = htons(out_port); - - dump_stats_transaction(argv[1], request); -} - -static void -do_dump_aggregate(const struct settings *s UNUSED, int argc, char *argv[]) -{ - struct ofp_aggregate_stats_request *req; - struct ofpbuf *request; - uint16_t out_port; - - req = alloc_stats_request(sizeof *req, OFPST_AGGREGATE, &request); - str_to_flow(argc > 2 ? argv[2] : "", &req->match, NULL, - &req->table_id, &out_port, NULL, NULL, NULL, NULL); - memset(&req->pad, 0, sizeof req->pad); - req->out_port = htons(out_port); - - dump_stats_transaction(argv[1], request); -} - -#define EMERG_TABLE_ID 0xfe - -static void -do_add_flow(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) -{ - struct vconn *vconn; - struct ofpbuf *buffer; - struct ofp_flow_mod *ofm; - uint16_t priority, idle_timeout, hard_timeout; - uint64_t cookie; - uint8_t table_id; - struct ofp_match match; - - /* Parse and send. str_to_flow() will expand and reallocate the data in - * 'buffer', so we can't keep pointers to across the str_to_flow() call. */ - make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer); - str_to_flow(argv[2], &match, buffer, - &table_id, NULL, &priority, &idle_timeout, &hard_timeout, - &cookie); - ofm = buffer->data; - ofm->match = match; - ofm->command = htons(OFPFC_ADD); - ofm->cookie = htonll(cookie); - ofm->idle_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(idle_timeout); - ofm->hard_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(hard_timeout); - ofm->buffer_id = htonl(UINT32_MAX); - ofm->priority = htons(priority); - ofm->flags = htons(OFPFF_SEND_FLOW_REM); - if (table_id == EMERG_TABLE_ID) - ofm->flags |= htons(OFPFF_EMERG); - - open_vconn(argv[1], &vconn); - send_openflow_buffer(vconn, buffer); - vconn_close(vconn); -} - -static void -do_add_flows(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) -{ - struct vconn *vconn; - FILE *file; - char line[1024]; - - file = fopen(argv[2], "r"); - if (file == NULL) { - ofp_fatal(errno, "%s: open", argv[2]); - } - - open_vconn(argv[1], &vconn); - while (fgets(line, sizeof line, file)) { - struct ofpbuf *buffer; - struct ofp_flow_mod *ofm; - uint16_t priority, idle_timeout, hard_timeout; - uint64_t cookie; - uint8_t table_id; - struct ofp_match match; - - char *comment; - - /* Delete comments. */ - comment = strchr(line, '#'); - if (comment) { - *comment = '\0'; - } - - /* Drop empty lines. */ - if (line[strspn(line, " \t\n")] == '\0') { - continue; - } - - /* Parse and send. str_to_flow() will expand and reallocate the data - * in 'buffer', so we can't keep pointers to across the str_to_flow() - * call. */ - ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer); - str_to_flow(line, &match, buffer, - &table_id, NULL, &priority, &idle_timeout, &hard_timeout, - &cookie); - ofm = buffer->data; - ofm->match = match; - ofm->command = htons(OFPFC_ADD); - ofm->cookie = htonll(cookie); - ofm->idle_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(idle_timeout); - ofm->hard_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(hard_timeout); - ofm->buffer_id = htonl(UINT32_MAX); - ofm->priority = htons(priority); - ofm->flags = htons(OFPFF_SEND_FLOW_REM); - if (table_id == EMERG_TABLE_ID) - ofm->flags |= htons(OFPFF_EMERG); - - send_openflow_buffer(vconn, buffer); - } - vconn_close(vconn); - fclose(file); -} - -static void -do_mod_flows(const struct settings *s, int argc UNUSED, char *argv[]) -{ - uint16_t priority, idle_timeout, hard_timeout; - uint64_t cookie; - uint8_t table_id; - struct vconn *vconn; - struct ofpbuf *buffer; - struct ofp_flow_mod *ofm; - - /* Parse and send. */ - ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer); - str_to_flow(argv[2], &ofm->match, buffer, - &table_id, NULL, &priority, &idle_timeout, &hard_timeout, - &cookie); - if (s->strict) { - ofm->command = htons(OFPFC_MODIFY_STRICT); - } else { - ofm->command = htons(OFPFC_MODIFY); - } - ofm->cookie = htonll(cookie); - ofm->idle_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(idle_timeout); - ofm->hard_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(hard_timeout); - ofm->buffer_id = htonl(UINT32_MAX); - if (table_id == EMERG_TABLE_ID) - ofm->flags = htons(OFPFF_EMERG); - ofm->priority = htons(priority); - - open_vconn(argv[1], &vconn); - send_openflow_buffer(vconn, buffer); - vconn_close(vconn); -} - -static void do_del_flows(const struct settings *s, int argc, char *argv[]) -{ - struct vconn *vconn; - uint16_t priority; - uint16_t out_port; - uint8_t table_id; - struct ofpbuf *buffer; - struct ofp_flow_mod *ofm; - - /* Parse and send. */ - ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer); - str_to_flow(argc > 2 ? argv[2] : "", &ofm->match, NULL, - &table_id, &out_port, &priority, NULL, NULL, NULL); - if (s->strict) { - ofm->command = htons(OFPFC_DELETE_STRICT); - } else { - ofm->command = htons(OFPFC_DELETE); - } - ofm->idle_timeout = htons(0); - ofm->hard_timeout = htons(0); - ofm->buffer_id = htonl(UINT32_MAX); - if (table_id == EMERG_TABLE_ID) - ofm->flags = htons(OFPFF_EMERG); - ofm->out_port = htons(out_port); - ofm->priority = htons(priority); - - open_vconn(argv[1], &vconn); - send_openflow_buffer(vconn, buffer); - vconn_close(vconn); -} - -static void -do_monitor(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) -{ - struct vconn *vconn; - const char *name; - - /* If the user specified, e.g., "nl:0", append ":1" to it to ensure that - * the connection will subscribe to listen for asynchronous messages, such - * as packet-in messages. */ - if (!strncmp(argv[1], "nl:", 3) && strrchr(argv[1], ':') == &argv[1][2]) { - name = xasprintf("%s:1", argv[1]); - } else { - name = argv[1]; - } - open_vconn(argv[1], &vconn); - for (;;) { - struct ofpbuf *b; - run(vconn_recv_block(vconn, &b), "vconn_recv"); - ofp_print(stderr, b->data, b->size, 2); - ofpbuf_delete(b); - } -} - -static void -str_to_port(char *string, uint16_t *start_port) -{ - char *save_ptr = NULL; - char *value = NULL; - - if (start_port) { - *start_port = OFPP_NONE; - } - - value = strtok_r(string, ", \t\r\n", &save_ptr); - if (value && start_port) { - *start_port = atoi(value); - } -} - -static void -do_dump_ports(const struct settings *s UNUSED, int argc, char *argv[]) -{ - struct ofp_port_stats_request *psr; - struct ofpbuf *buf; - - psr = alloc_stats_request(sizeof(*psr), OFPST_PORT, &buf); - str_to_port(argc > 2 ? argv[2] : "", &psr->port_no); - psr->port_no = htons(psr->port_no); - memset(psr->pad, 0, sizeof(psr->pad)); - dump_stats_transaction(argv[1], buf); -} - -static void -do_probe(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) -{ - struct ofpbuf *request; - struct vconn *vconn; - struct ofpbuf *reply; - - make_openflow(sizeof(struct ofp_header), OFPT_ECHO_REQUEST, &request); - open_vconn(argv[1], &vconn); - run(vconn_transact(vconn, request, &reply), "talking to %s", argv[1]); - if (reply->size != sizeof(struct ofp_header)) { - ofp_fatal(0, "reply does not match request"); - } - ofpbuf_delete(reply); - vconn_close(vconn); -} - -static void -do_mod_port(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) -{ - struct ofpbuf *request, *reply; - struct ofp_switch_features *osf; - struct ofp_port_mod *opm; - struct vconn *vconn; - char *endptr; - int n_ports; - int port_idx; - int port_no; - - - /* Check if the argument is a port index. Otherwise, treat it as - * the port name. */ - port_no = strtol(argv[2], &endptr, 10); - if (port_no == 0 && endptr == argv[2]) { - port_no = -1; - } - - /* Send a "Features Request" to get the information we need in order - * to modify the port. */ - make_openflow(sizeof(struct ofp_header), OFPT_FEATURES_REQUEST, &request); - open_vconn(argv[1], &vconn); - run(vconn_transact(vconn, request, &reply), "talking to %s", argv[1]); - - osf = reply->data; - n_ports = (reply->size - sizeof *osf) / sizeof *osf->ports; - - for (port_idx = 0; port_idx < n_ports; port_idx++) { - if (port_no != -1) { - /* Check argument as a port index */ - if (osf->ports[port_idx].port_no == htons(port_no)) { - break; - } - } else { - /* Check argument as an interface name */ - if (!strncmp((char *)osf->ports[port_idx].name, argv[2], - sizeof osf->ports[0].name)) { - break; - } - - } - } - if (port_idx == n_ports) { - ofp_fatal(0, "couldn't find monitored port: %s", argv[2]); - } - - opm = make_openflow(sizeof(struct ofp_port_mod), OFPT_PORT_MOD, &request); - opm->port_no = osf->ports[port_idx].port_no; - memcpy(opm->hw_addr, osf->ports[port_idx].hw_addr, sizeof opm->hw_addr); - opm->config = htonl(0); - opm->mask = htonl(0); - opm->advertise = htonl(0); - - printf("modifying port: %s\n", osf->ports[port_idx].name); - - if (!strncasecmp(argv[3], MOD_PORT_CMD_UP, sizeof MOD_PORT_CMD_UP)) { - opm->mask |= htonl(OFPPC_PORT_DOWN); - } else if (!strncasecmp(argv[3], MOD_PORT_CMD_DOWN, - sizeof MOD_PORT_CMD_DOWN)) { - opm->mask |= htonl(OFPPC_PORT_DOWN); - opm->config |= htonl(OFPPC_PORT_DOWN); - } else if (!strncasecmp(argv[3], MOD_PORT_CMD_FLOOD, - sizeof MOD_PORT_CMD_FLOOD)) { - opm->mask |= htonl(OFPPC_NO_FLOOD); - } else if (!strncasecmp(argv[3], MOD_PORT_CMD_NOFLOOD, - sizeof MOD_PORT_CMD_NOFLOOD)) { - opm->mask |= htonl(OFPPC_NO_FLOOD); - opm->config |= htonl(OFPPC_NO_FLOOD); - } else { - ofp_fatal(0, "unknown mod-port command '%s'", argv[3]); - } - - send_openflow_buffer(vconn, request); - - ofpbuf_delete(reply); - vconn_close(vconn); -} - -static void -do_ping(const struct settings *s UNUSED, int argc, char *argv[]) -{ - size_t max_payload = 65535 - sizeof(struct ofp_header); - unsigned int payload; - struct vconn *vconn; - int i; - - payload = argc > 2 ? atoi(argv[2]) : 64; - if (payload > max_payload) { - ofp_fatal(0, "payload must be between 0 and %zu bytes", max_payload); - } - - open_vconn(argv[1], &vconn); - for (i = 0; i < 10; i++) { - struct timeval start, end; - struct ofpbuf *request, *reply; - struct ofp_header *rq_hdr, *rpy_hdr; - - rq_hdr = make_openflow(sizeof(struct ofp_header) + payload, - OFPT_ECHO_REQUEST, &request); - random_bytes(rq_hdr + 1, payload); - - gettimeofday(&start, NULL); - run(vconn_transact(vconn, ofpbuf_clone(request), &reply), "transact"); - gettimeofday(&end, NULL); - - rpy_hdr = reply->data; - if (reply->size != request->size - || memcmp(rpy_hdr + 1, rq_hdr + 1, payload) - || rpy_hdr->xid != rq_hdr->xid - || rpy_hdr->type != OFPT_ECHO_REPLY) { - printf("Reply does not match request. Request:\n"); - ofp_print(stdout, request, request->size, 2); - printf("Reply:\n"); - ofp_print(stdout, reply, reply->size, 2); - } - printf("%d bytes from %s: xid=%08"PRIx32" time=%.1f ms\n", - reply->size - sizeof *rpy_hdr, argv[1], rpy_hdr->xid, - (1000*(double)(end.tv_sec - start.tv_sec)) - + (.001*(end.tv_usec - start.tv_usec))); - ofpbuf_delete(request); - ofpbuf_delete(reply); - } - vconn_close(vconn); -} - -static void -do_benchmark(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) -{ - size_t max_payload = 65535 - sizeof(struct ofp_header); - struct timeval start, end; - unsigned int payload_size, message_size; - struct vconn *vconn; - double duration; - int count; - int i; - - payload_size = atoi(argv[2]); - if (payload_size > max_payload) { - ofp_fatal(0, "payload must be between 0 and %zu bytes", max_payload); - } - message_size = sizeof(struct ofp_header) + payload_size; - - count = atoi(argv[3]); - - printf("Sending %d packets * %u bytes (with header) = %u bytes total\n", - count, message_size, count * message_size); - - open_vconn(argv[1], &vconn); - gettimeofday(&start, NULL); - for (i = 0; i < count; i++) { - struct ofpbuf *request, *reply; - struct ofp_header *rq_hdr; - - rq_hdr = make_openflow(message_size, OFPT_ECHO_REQUEST, &request); - memset(rq_hdr + 1, 0, payload_size); - run(vconn_transact(vconn, request, &reply), "transact"); - ofpbuf_delete(reply); - } - gettimeofday(&end, NULL); - vconn_close(vconn); - - duration = ((1000*(double)(end.tv_sec - start.tv_sec)) - + (.001*(end.tv_usec - start.tv_usec))); - printf("Finished in %.1f ms (%.0f packets/s) (%.0f bytes/s)\n", - duration, count / (duration / 1000.0), - count * message_size / (duration / 1000.0)); -} - -/**************************************************************** - * - * Queue operations - * - ****************************************************************/ - -static int -parse_queue_params(int argc, char *argv[], uint16_t *port, uint32_t *q_id, - uint16_t *min_rate) -{ - if (!port || !q_id) { - return -1; - } - - *port = OFPP_ALL; - *q_id = OFPQ_ALL; - if (argc > 2) { - *port = str_to_u32(argv[2]); - } - if (argc > 3) { - *q_id = str_to_u32(argv[3]); - } - if (min_rate) { - *min_rate = OFPQ_MIN_RATE_UNCFG; - if (argc > 4) { - *min_rate = str_to_u32(argv[4]); - } - } - - return 0; -} - -/* Length of queue request; works with 16-bit property values like min_rate */ -#define Q_REQ_LEN(prop_count) \ - (sizeof(struct ofp_packet_queue) + Q_PROP_LEN(prop_count)) - -#define Q_PROP_LEN(prop_count) \ - ((prop_count) * sizeof(struct ofp_queue_prop_min_rate)) - -/* - * Execute a queue add/mod/del operation - * - * All commands must specify a port and queue id. - * Add may specify a bandwidth value - * Modify must specify a bandwidth value - * - * To simplify things, always allocate space for all three parameters - * (port, queue, min-bw): - * openflow_queue_header (w/ ofp header, port) - * ofp_queue (with q_id and offset to properties list) - * ofp_queue_prop_min_rate (w/ prop header and rate info) - */ -static struct openflow_queue_command_header * -queue_req_create(int cmd, struct ofpbuf **b, uint16_t port, - uint32_t q_id, uint16_t min_rate) -{ - struct openflow_queue_command_header *request; - struct ofp_packet_queue *queue; - struct ofp_queue_prop_min_rate *min_rate_prop; - int req_bytes; - - req_bytes = sizeof(*request) + sizeof(*queue) + sizeof(*min_rate_prop); - request = make_openflow(req_bytes, OFPT_VENDOR, b); - if (request == NULL) { - return NULL; - } - request->header.vendor = htonl(OPENFLOW_VENDOR_ID); - request->header.subtype = htonl(cmd); - request->port = htons(port); - - /* Will get complicated when queue properties w/ different struct sizes */ - queue = S_PTR(request, struct openflow_queue_command_header, body); - queue->queue_id = htonl(q_id); - queue->len = htons(Q_REQ_LEN(1)); - - min_rate_prop = S_PTR(queue, struct ofp_packet_queue, properties); - min_rate_prop->prop_header.property = htons(OFPQT_MIN_RATE); - min_rate_prop->prop_header.len = htons(Q_PROP_LEN(1)); - min_rate_prop->rate = htons(min_rate); - - return request; -} - -/* Handler for add/modify/delete queue ops */ -static void -do_queue_op(int cmd, int argc, char *argv[]) -{ - struct openflow_queue_command_header *request; - struct vconn *vconn; - struct ofpbuf *b; - uint16_t port; - uint32_t q_id; - uint16_t min_rate; - - if (parse_queue_params(argc, argv, &port, &q_id, &min_rate) < 0) { - ofp_fatal(0, "Error parsing port/queue for cmd %s", argv[0]); - return; - } - - printf("que op %d (%s). port %d. q 0x%x. rate %d\n", cmd, argv[0], - port, q_id, min_rate); - - if ((request = queue_req_create(cmd, &b, port, q_id, min_rate)) == NULL) { - ofp_fatal(0, "Error creating queue req for cmd %s", argv[0]); - return; - } - - printf("made request %p, running transaction\n", request); - - open_vconn(argv[1], &vconn); - /* Unacknowledged call for now */ - send_openflow_buffer(vconn, b); - vconn_close(vconn); -} - -char *openflow_queue_error_strings[] = OPENFLOW_QUEUE_ERROR_STRINGS_DEF; - -static void -do_mod_queue(const struct settings *s UNUSED, int argc, char *argv[]) -{ - do_queue_op(OFP_EXT_QUEUE_MODIFY, argc, argv); -} - -static void -do_del_queue(const struct settings *s UNUSED, int argc, char *argv[]) -{ - do_queue_op(OFP_EXT_QUEUE_DELETE, argc, argv); -} - -static void -do_dump_queue_port(char *vconn_name, uint16_t port, uint32_t q_id) -{ - struct ofp_queue_get_config_request *request; - struct ofpbuf *buf; - - request = make_openflow(sizeof(*request), OFPT_QUEUE_GET_CONFIG_REQUEST, - &buf); - request->port = htons(port); /* FIXME */ - dump_transaction(vconn_name, buf); - - /* Then do a queue stats get */ - dump_queue_stats_transaction(vconn_name, OFPST_QUEUE, port, q_id); -} - -static void -do_dump_queue_all(char *vconn_name, uint32_t q_id) -{ - struct ofpbuf *request, *reply; - struct ofp_switch_features *osf; - int port_idx, n_ports; - uint16_t port_no; - struct vconn *vconn; - - /* Send a "Features Request" to get the list of ports in the system */ - make_openflow(sizeof(struct ofp_header), OFPT_FEATURES_REQUEST, &request); - open_vconn(vconn_name, &vconn); - run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name); - vconn_close(vconn); - - osf = reply->data; - n_ports = (reply->size - sizeof *osf) / sizeof *osf->ports; - for (port_idx = 0; port_idx < n_ports; port_idx++) { - if ((port_no = ntohs(osf->ports[port_idx].port_no)) < OFPP_MAX) { - do_dump_queue_port(vconn_name, port_no, q_id); - } - } - ofpbuf_delete(reply); -} - -static void -do_dump_queue(const struct settings *s UNUSED, int argc, char *argv[]) -{ - uint16_t port; - uint32_t q_id; - - /* Get queue params from the request */ - if (parse_queue_params(argc, argv, &port, &q_id, NULL) < 0) { - ofp_fatal(0, "Error parsing port/queue for cmd %s", argv[0]); - return; - } - - if (port == OFPP_ALL) { - do_dump_queue_all(argv[1], q_id); - } else { - do_dump_queue_port(argv[1], port, q_id); - } -} - -static void -do_help(const struct settings *s UNUSED, int argc UNUSED, char *argv[] UNUSED) -{ - usage(); -} - -static struct command all_commands[] = { -#ifdef HAVE_NETLINK - { "adddp", 1, 1, do_add_dp }, - { "deldp", 1, 1, do_del_dp }, - { "addif", 2, INT_MAX, do_add_port }, - { "delif", 2, INT_MAX, do_del_port }, - { "get-idx", 1, 1, do_get_idx }, -#endif - - { "show", 1, 1, do_show }, - { "status", 1, 2, do_status }, - - { "show-protostat", 1, 1, do_protostat }, - - { "help", 0, INT_MAX, do_help }, - { "monitor", 1, 1, do_monitor }, - { "dump-desc", 1, 1, do_dump_desc }, - { "dump-tables", 1, 1, do_dump_tables }, - { "desc", 2, 2, do_desc }, - { "dump-flows", 1, 2, do_dump_flows }, - { "dump-aggregate", 1, 2, do_dump_aggregate }, - { "add-flow", 2, 2, do_add_flow }, - { "add-flows", 2, 2, do_add_flows }, - { "mod-flows", 2, 2, do_mod_flows }, - { "del-flows", 1, 2, do_del_flows }, - { "dump-ports", 1, 2, do_dump_ports }, - { "mod-port", 3, 3, do_mod_port }, - { "add-queue", 3, 4, do_mod_queue }, - { "mod-queue", 3, 4, do_mod_queue }, - { "del-queue", 3, 3, do_del_queue }, - { "dump-queue", 1, 3, do_dump_queue }, - { "probe", 1, 1, do_probe }, - { "ping", 1, 2, do_ping }, - { "benchmark", 3, 3, do_benchmark }, - { NULL, 0, 0, NULL }, -}; diff --git a/openflow/utilities/ofp-discover.8.in b/openflow/utilities/ofp-discover.8.in deleted file mode 100644 index cf5ac549..00000000 --- a/openflow/utilities/ofp-discover.8.in +++ /dev/null @@ -1,119 +0,0 @@ -.ds PN ofp\-discover - -.TH ofp\-discover 8 "May 2008" "OpenFlow" "OpenFlow Manual" - -.SH NAME -ofp\-discover \- controller discovery utility - -.SH SYNOPSIS -.B ofp\-discover -[\fIoptions\fR] \fInetdev\fR [\fInetdev\fR...] - -.SH DESCRIPTION -The \fBofp\-discover\fR program attempts to discover the location of -an OpenFlow controller on one of the network devices listed on the -command line. It repeatedly broadcasts a DHCP request with vendor -class identifier \fBOpenFlow\fR on each network device until it -receives an acceptable DHCP response. It will accept any valid DHCP -reply that has the same vendor class identifier and includes a -vendor-specific option with code 1 whose contents are a string -specifying the location of the controller in the same format used on -the \fBofprotocol\fR command line (e.g. \fBssl:192.168.0.1\fR). - -When \fBofp\-discover\fR receives an acceptable response, it prints -the details of the response on \fBstdout\fR. Then, by default, it -configures the network device on which the response was received with -the received IP address, netmask, and default gateway, and detaches -itself to the background. - -.SH OPTIONS -.TP -\fB--accept-vconn=\fIregex\fR -By default, \fBofp\-discover\fR accepts any controller location -advertised over DHCP. With this option, only controllers whose names -match POSIX extended regular expression \fIregex\fR will be accepted. -Specifying \fBssl:.*\fR for \fIregex\fR, for example, would cause only -SSL controller connections to be accepted. - -The \fIregex\fR is implicitly anchored at the beginning of the -controller location string, as if it begins with \fB^\fR. - -.TP -\fB--exit-without-bind\fR -By default, \fBofp\-discover\fR binds the network device that receives -the first acceptable response to the IP address received over DHCP. -With this option, the configuration of the network device is not -changed at all, except to bring it up if it is initially down, and -\fBofp\-discover\fR will exit immediately after it receives an -acceptable DHCP response. - -This option is mutually exclusive with \fB--exit-after-bind\fR and -\fB--no-detach\fR. - -.TP -\fB--exit-after-bind\fR -By default, after it receives an acceptable DHCP response, -\fBofp\-discover\fR detaches itself from the foreground session and -runs in the background maintaining the DHCP lease as necessary. With -this option, \fBofp\-discover\fR will exit immediately after it -receives an acceptable DHCP response and configures the network device -with the received IP address. The address obtained via DHCP could -therefore be used past the expiration of its lease. - -This option is mutually exclusive with \fB--exit-without-bind\fR and -\fB--no-detach\fR. - -.TP -\fB--no-detach\fR -By default, \fBofp\-discover\fR runs in the foreground until it obtains -an acceptable DHCP response, then it detaches itself from the -foreground session and run as a background process. This option -prevents \fBofp\-discover\fR from detaching, causing it to run in the -foreground even after it obtains a DHCP response. - -This option is mutually exclusive with \fB--exit-without-bind\fR and -\fB--exit-after-bind\fR. - -.TP -\fB-P\fR[\fIpidfile\fR], \fB--pidfile\fR[\fB=\fIpidfile\fR] -Causes a file (by default, \fBofp\-discover.pid\fR) to be created indicating -the PID of the running process. If \fIpidfile\fR is not specified, or -if it does not begin with \fB/\fR, then it is created in -\fB@RUNDIR@\fR. - -The \fIpidfile\fR is created when \fBofp\-discover\fR detaches, so -this this option has no effect when one of \fB--exit-without-bind\fR, -\fB--exit-after-bind\fR, or \fB--no-detach\fR is also given. - -.TP -\fB-f\fR, \fB--force\fR -By default, when \fB-P\fR or \fB--pidfile\fR is specified and the -specified pidfile already exists and is locked by a running process, -\fBcontroller\fR refuses to start. Specify \fB-f\fR or \fB--force\fR -to cause it to instead overwrite the pidfile. - -When \fB-P\fR or \fB--pidfile\fR is not specified, this option has no -effect. - -.so lib/vlog.man -.so lib/common.man - -.SH BUGS - -If the network devices specified on the command line have been added -to an OpenFlow switch with \fBdpctl addif\fR, then controller -discovery will fail because \fBofp\-discover\fR will not be able to -see DHCP responses, even though tools such as \fBtcpdump\fR(8) and -\fBwireshark\fR(1) can see them on the wire. This is because of the -structure of the Linux kernel networking stack, which hands packets -first to programs that listen for all arriving packets, then to -OpenFlow, then to programs that listen for a specific kind of packet. -OpenFlow consumes all the packets handed to it, so tools like -\fBtcpdump\fR that look at all packets will see packets arriving on -OpenFlow interfaces, but \fRofp\-discover\fR, which listens only for -arriving IP packets, will not. - -.SH "SEE ALSO" - -.BR ofprotocol (8), -.BR ofp-pki (8) diff --git a/openflow/utilities/ofp-discover.c b/openflow/utilities/ofp-discover.c deleted file mode 100644 index 55f40429..00000000 --- a/openflow/utilities/ofp-discover.c +++ /dev/null @@ -1,420 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include -#include -#include -#include -#include -#include -#include "command-line.h" -#include "daemon.h" -#include "dhcp-client.h" -#include "dhcp.h" -#include "dirs.h" -#include "dynamic-string.h" -#include "fatal-signal.h" -#include "netdev.h" -#include "poll-loop.h" -#include "timeval.h" -#include "util.h" -#include "vlog-socket.h" - -#include "vlog.h" -#define THIS_MODULE VLM_ofp_discover - -struct iface { - const char *name; - struct dhclient *dhcp; -}; - -/* The interfaces that we serve. */ -static struct iface *ifaces; -static int n_ifaces; - -/* --accept-vconn: Regular expression specifying the class of controller vconns - * that we will accept during autodiscovery. */ -static const char *accept_controller_re = ".*"; -static regex_t accept_controller_regex; - -/* --exit-without-bind: Exit after discovering the controller, without binding - * the network device to an IP address? */ -static bool exit_without_bind; - -/* --exit-after-bind: Exit after discovering the controller, after binding the - * network device to an IP address? */ -static bool exit_after_bind; - -static bool iface_init(struct iface *, const char *netdev_name); -static void release_ifaces(void *aux UNUSED); - -static void parse_options(int argc, char *argv[]); -static void usage(void) NO_RETURN; - -static void modify_dhcp_request(struct dhcp_msg *, void *aux); -static bool validate_dhcp_offer(const struct dhcp_msg *, void *aux); - -int -main(int argc, char *argv[]) -{ - int retval; - int i; - - set_program_name(argv[0]); - time_init(); - vlog_init(); - parse_options(argc, argv); - - argc -= optind; - argv += optind; - if (argc < 1) { - ofp_fatal(0, "need at least one non-option argument; " - "use --help for usage"); - } - - ifaces = xmalloc(argc * sizeof *ifaces); - n_ifaces = 0; - for (i = 0; i < argc; i++) { - if (iface_init(&ifaces[n_ifaces], argv[i])) { - n_ifaces++; - } - } - if (!n_ifaces) { - ofp_fatal(0, "failed to initialize any DHCP clients"); - } - - for (i = 0; i < n_ifaces; i++) { - struct iface *iface = &ifaces[i]; - dhclient_init(iface->dhcp, 0); - } - fatal_signal_add_hook(release_ifaces, NULL, true); - - retval = regcomp(&accept_controller_regex, accept_controller_re, - REG_NOSUB | REG_EXTENDED); - if (retval) { - size_t length = regerror(retval, &accept_controller_regex, NULL, 0); - char *buffer = xmalloc(length); - regerror(retval, &accept_controller_regex, buffer, length); - ofp_fatal(0, "%s: %s", accept_controller_re, buffer); - } - - retval = vlog_server_listen(NULL, NULL); - if (retval) { - ofp_fatal(retval, "Could not listen for vlog connections"); - } - - die_if_already_running(); - - signal(SIGPIPE, SIG_IGN); - for (;;) { - fatal_signal_block(); - for (i = 0; i < n_ifaces; i++) { - struct iface *iface = &ifaces[i]; - dhclient_run(iface->dhcp); - if (dhclient_changed(iface->dhcp)) { - bool is_bound = dhclient_is_bound(iface->dhcp); - int j; - - /* Configure network device. */ - if (!exit_without_bind) { - dhclient_configure_netdev(iface->dhcp); - dhclient_update_resolv_conf(iface->dhcp); - } - - if (is_bound) { - static bool detached = false; - struct ds ds; - - /* Disable timeout, since discovery was successful. */ - time_alarm(0); - - /* Print discovered parameters. */ - ds_init(&ds); - dhcp_msg_to_string(dhclient_get_config(iface->dhcp), - true, &ds); - fputs(ds_cstr(&ds), stdout); - putchar('\n'); - fflush(stdout); - ds_destroy(&ds); - - /* Exit if the user requested it. */ - if (exit_without_bind) { - VLOG_DBG("exiting because of successful binding on %s " - "and --exit-without-bind specified", - iface->name); - exit(0); - } - if (exit_after_bind) { - VLOG_DBG("exiting because of successful binding on %s " - "and --exit-after-bind specified", - iface->name); - exit(0); - } - - /* Detach into background, if we haven't already. */ - if (!detached) { - detached = true; - daemonize(); - } - } - - /* We only want an address on a single one of our interfaces. - * So: if we have an address on this interface, stop looking - * for one on the others; if we don't have an address on this - * interface, start looking everywhere. */ - for (j = 0; j < n_ifaces; j++) { - struct iface *if2 = &ifaces[j]; - if (iface != if2) { - if (is_bound) { - dhclient_release(if2->dhcp); - } else { - dhclient_init(if2->dhcp, 0); - } - } - } - } - } - for (i = 0; i < n_ifaces; i++) { - struct iface *iface = &ifaces[i]; - dhclient_wait(iface->dhcp); - } - fatal_signal_unblock(); - poll_block(); - } - - return 0; -} - -static bool -iface_init(struct iface *iface, const char *netdev_name) -{ - int retval; - - iface->name = netdev_name; - iface->dhcp = NULL; - - if (exit_after_bind) { - /* Bring this interface up permanently, so that the bound address - * persists past program termination. */ - struct netdev *netdev; - - retval = netdev_open(iface->name, NETDEV_ETH_TYPE_NONE, &netdev); - if (retval) { - ofp_error(retval, "Could not open %s device", iface->name); - return false; - } - retval = netdev_turn_flags_on(netdev, NETDEV_UP, true); - if (retval) { - ofp_error(retval, "Could not bring %s device up", iface->name); - return false; - } - netdev_close(netdev); - } - - retval = dhclient_create(iface->name, modify_dhcp_request, - validate_dhcp_offer, NULL, &iface->dhcp); - if (retval) { - ofp_error(retval, "%s: failed to initialize DHCP client", iface->name); - return false; - } - - return true; -} - -static void -release_ifaces(void *aux UNUSED) -{ - int i; - - for (i = 0; i < n_ifaces; i++) { - struct dhclient *dhcp = ifaces[i].dhcp; - dhclient_release(dhcp); - if (dhclient_changed(dhcp)) { - dhclient_configure_netdev(dhcp); - } - } -} - -static void -modify_dhcp_request(struct dhcp_msg *msg, void *aux UNUSED) -{ - dhcp_msg_put_string(msg, DHCP_CODE_VENDOR_CLASS, "OpenFlow"); -} - -static bool -validate_dhcp_offer(const struct dhcp_msg *msg, void *aux UNUSED) -{ - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60); - char *vconn_name; - bool accept; - - vconn_name = dhcp_msg_get_string(msg, DHCP_CODE_OFP_CONTROLLER_VCONN); - if (!vconn_name) { - VLOG_WARN_RL(&rl, "rejecting DHCP offer missing controller vconn"); - return false; - } - accept = !regexec(&accept_controller_regex, vconn_name, 0, NULL, 0); - free(vconn_name); - return accept; -} - -static void -parse_options(int argc, char *argv[]) -{ - enum { - OPT_ACCEPT_VCONN = UCHAR_MAX + 1, - OPT_EXIT_WITHOUT_BIND, - OPT_EXIT_AFTER_BIND, - OPT_NO_DETACH, - }; - static struct option long_options[] = { - {"accept-vconn", required_argument, 0, OPT_ACCEPT_VCONN}, - {"exit-without-bind", no_argument, 0, OPT_EXIT_WITHOUT_BIND}, - {"exit-after-bind", no_argument, 0, OPT_EXIT_AFTER_BIND}, - {"no-detach", no_argument, 0, OPT_NO_DETACH}, - {"timeout", required_argument, 0, 't'}, - {"pidfile", optional_argument, 0, 'P'}, - {"force", no_argument, 0, 'f'}, - {"verbose", optional_argument, 0, 'v'}, - {"help", no_argument, 0, 'h'}, - {"version", no_argument, 0, 'V'}, - {0, 0, 0, 0}, - }; - char *short_options = long_options_to_short_options(long_options); - bool detach_after_bind = true; - - for (;;) { - unsigned long int timeout; - int c; - - c = getopt_long(argc, argv, short_options, long_options, NULL); - if (c == -1) { - break; - } - - switch (c) { - case OPT_ACCEPT_VCONN: - accept_controller_re = (optarg[0] == '^' - ? optarg - : xasprintf("^%s", optarg)); - break; - - case OPT_EXIT_WITHOUT_BIND: - exit_without_bind = true; - break; - - case OPT_EXIT_AFTER_BIND: - exit_after_bind = true; - break; - - case OPT_NO_DETACH: - detach_after_bind = false; - break; - - case 'P': - set_pidfile(optarg); - break; - - case 'f': - ignore_existing_pidfile(); - break; - - case 't': - timeout = strtoul(optarg, NULL, 10); - if (timeout <= 0) { - ofp_fatal(0, "value %s on -t or --timeout is not at least 1", - optarg); - } else { - time_alarm(timeout); - } - signal(SIGALRM, SIG_DFL); - break; - - case 'h': - usage(); - - case 'V': - printf("%s %s compiled "__DATE__" "__TIME__"\n", - program_name, VERSION BUILDNR); - exit(EXIT_SUCCESS); - - case 'v': - vlog_set_verbosity(optarg); - break; - - case '?': - exit(EXIT_FAILURE); - - default: - abort(); - } - } - free(short_options); - - if ((exit_without_bind + exit_after_bind + !detach_after_bind) > 1) { - ofp_fatal(0, "--exit-without-bind, --exit-after-bind, and --no-detach " - "are mutually exclusive"); - } - if (detach_after_bind) { - set_detach(); - } -} - -static void -usage(void) -{ - printf("%s: a tool for discovering OpenFlow controllers.\n" - "usage: %s [OPTIONS] NETDEV [NETDEV...]\n" - "where each NETDEV is a network device on which to perform\n" - "controller discovery.\n" - "\nOrdinarily, ofp-discover runs in the foreground until it\n" - "obtains an IP address and discovers an OpenFlow controller via\n" - "DHCP, then it prints information about the controller to stdout\n" - "and detaches to the background to maintain the IP address lease.\n" - "\nNetworking options:\n" - " --accept-vconn=REGEX accept matching discovered controllers\n" - " --exit-without-bind exit after discovery, without binding\n" - " --exit-after-bind exit after discovery, after binding\n" - " --no-detach do not detach after discovery\n", - program_name, program_name); - vlog_usage(); - printf("\nOther options:\n" - " -t, --timeout=SECS give up discovery after SECS seconds\n" - " -P, --pidfile[=FILE] create pidfile (default: %s/%s.pid)\n" - " -f, --force with -P, start even if already running\n" - " -h, --help display this help message\n" - " -V, --version display version information\n", - ofp_rundir, program_name); - exit(EXIT_SUCCESS); -} diff --git a/openflow/utilities/ofp-kill.8.in b/openflow/utilities/ofp-kill.8.in deleted file mode 100644 index 6c1298ca..00000000 --- a/openflow/utilities/ofp-kill.8.in +++ /dev/null @@ -1,61 +0,0 @@ -.ds PN ofp\-kill - -.TH ofp\-kill 8 "May 2008" "OpenFlow" "OpenFlow Manual" - -.SH NAME -ofp\-kill \- kills processes given their pidfiles - -.SH SYNOPSIS -.B ofp\-kill -[\fIoptions\fR] \fIpidfile\fR [\fIpidfile\fR...] - -.SH DESCRIPTION -The \fBofp\-kill\fR program reads each \fIpidfile\fR specified on the -command line and sends a signal to the program associated with it, if -any. It reads one line of text from \fIpidfile\fR, which must contain -the PID of the process to kill as a text string. It then uses -\fBfcntl\fR(2) to verify that a process with the PID from the file -owns a lock on \fIpidfile\fR before it sends the signal. - -A \fIpidfile\fR whose name begins with \fB/\fR is used literally. -Otherwise, \fB@RUNDIR@/\fR is prefixed. - -This program exists for use by \fBofp\-switch\-setup\fR, which cannot -easily implement its functionality since Perl has no portable -interface to \fBfcntl\fR-based file locking. - -.SH OPTIONS -.TP -\fB-s \fInumber\fR|\fIname\fR, \fB\-\^\-signal=\fInumber\fR|\fIname\fR -Sets the signal to be sent to each process. Signals may be given by -number (e.g. \fB1\fR) or by name (e.g. \fBHUP\fR or \fBSIGHUP\fR). -By default, \fBSIGTERM\fR is sent. - -.TP -\fB-f\fR, \fB\-\^\-force\fR -Causes \fBofp\-kill\fR to ignore all errors without printing a message -to \fBstderr\fR, and to exit with return code 0. - -.so lib/common.man - -.SH "EXIT CODE" - -Without \fB-f\fR or \fB\-\^\-force\fR, \fBofp\-kill\fR exits with -status 0 if at least one \fIpidfile\fR was given and the process -represented by every \fIpidfile\fR was signaled successfully, -otherwise with status 1. - -With \fB-f\fR or \fB\-\^\-force\fR, \fBofp\-kill\fR always exits with -status 0. - -.SH BUGS - -There is a race between verifying the lock on \fIpidfile\fR and -actually killing the process. - -\fBofp\-kill\fR does not wait for the signaled processes to die before -exiting. - -.SH "SEE ALSO" - -.BR ofp\-switch\-setup (8) diff --git a/openflow/utilities/ofp-kill.c b/openflow/utilities/ofp-kill.c deleted file mode 100644 index 0ad04343..00000000 --- a/openflow/utilities/ofp-kill.c +++ /dev/null @@ -1,228 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "command-line.h" -#include "daemon.h" -#include "timeval.h" -#include "util.h" -#include "vlog.h" - -/* -s, --signal: signal to send. */ -static int sig_nr = SIGTERM; - -/* -f, --force: ignore errors. */ -static bool force; - -static void cond_error(int err_no, const char *, ...) PRINTF_FORMAT(2, 3); - -static void parse_options(int argc, char *argv[]); -static void usage(void); - -int -main(int argc, char *argv[]) -{ - bool ok = true; - int i; - - set_program_name(argv[0]); - time_init(); - vlog_init(); - parse_options(argc, argv); - - argc -= optind; - argv += optind; - if (argc < 1) { - if (!force) { - ofp_fatal(0, "need at least one non-option argument; " - "use --help for usage"); - } - } - - for (i = 0; i < argc; i++) { - char *pidfile; - pid_t pid; - - pidfile = make_pidfile_name(argv[i]); - pid = read_pidfile(pidfile); - if (pid >= 0) { - if (kill(pid, sig_nr) < 0) { - cond_error(errno, "%s: kill(%ld)", pidfile, (long int) pid); - } - } else { - cond_error(-pid, "could not read %s", pidfile); - } - free(pidfile); - } - - return ok || force ? EXIT_SUCCESS : EXIT_FAILURE; -} - -static void -parse_options(int argc, char *argv[]) -{ - static struct option long_options[] = { - {"signal", required_argument, 0, 's'}, - {"force", no_argument, 0, 'f'}, - {"help", no_argument, 0, 'h'}, - {"version", no_argument, 0, 'V'}, - {0, 0, 0, 0}, - }; - char *short_options = long_options_to_short_options(long_options); - - for (;;) { - int c; - - c = getopt_long(argc, argv, short_options, long_options, NULL); - if (c == -1) { - break; - } - - switch (c) { - case 's': - if (atoi(optarg) || !strcmp(optarg, "0")) { - sig_nr = atoi(optarg); - } else { - struct signal_name { - const char *name; - int number; - }; - - static const struct signal_name signals[] = { -#define SIGNAL(NAME) { #NAME, NAME } - SIGNAL(SIGABRT), - SIGNAL(SIGALRM), - SIGNAL(SIGBUS), - SIGNAL(SIGCHLD), - SIGNAL(SIGCONT), - SIGNAL(SIGFPE), - SIGNAL(SIGHUP), - SIGNAL(SIGILL), - SIGNAL(SIGINT), - SIGNAL(SIGKILL), - SIGNAL(SIGPIPE), - SIGNAL(SIGQUIT), - SIGNAL(SIGSEGV), - SIGNAL(SIGSTOP), - SIGNAL(SIGTERM), - SIGNAL(SIGTSTP), - SIGNAL(SIGTTIN), - SIGNAL(SIGTTOU), - SIGNAL(SIGUSR1), - SIGNAL(SIGUSR2), -#ifdef SIGPOLL - SIGNAL(SIGPOLL), -#endif - SIGNAL(SIGPROF), - SIGNAL(SIGSYS), - SIGNAL(SIGTRAP), - SIGNAL(SIGURG), - SIGNAL(SIGVTALRM), - SIGNAL(SIGXCPU), - SIGNAL(SIGXFSZ), -#undef SIGNAL - }; - int i; - - for (i = 0; i < ARRAY_SIZE(signals); i++) { - const struct signal_name *s = &signals[i]; - if (!strcmp(optarg, s->name) - || !strcmp(optarg, s->name + 3)) { - sig_nr = s->number; - goto got_name; - } - } - ofp_fatal(0, "unknown signal \"%s\"", optarg); - got_name: ; - } - break; - - case 'f': - force = true; - break; - - case 'h': - usage(); - - case 'V': - printf("%s %s compiled "__DATE__" "__TIME__"\n", - program_name, VERSION BUILDNR); - exit(EXIT_SUCCESS); - - case '?': - exit(EXIT_FAILURE); - - default: - abort(); - } - } - free(short_options); -} - -static void -usage(void) -{ - printf("%s: kills a program using a pidfile\n" - "usage: %s [OPTIONS] PIDFILE [PIDFILE...]\n" - "where each PIDFILE is a pidfile created by an OpenFlow daemon.\n" - "\nOptions:\n" - " -s, --signal=NUMBER|NAME signal to send (default: TERM)\n" - " -f, --force ignore errors\n" - " -h, --help display this help message\n" - " -V, --version display version information\n", - program_name, program_name); - exit(EXIT_SUCCESS); -} - -static void -cond_error(int err_no, const char *format, ...) -{ - if (!force) { - va_list args; - - fprintf(stderr, "%s: ", program_name); - va_start(args, format); - vfprintf(stderr, format, args); - va_end(args); - if (err_no != 0) - fprintf(stderr, " (%s)", strerror(err_no)); - putc('\n', stderr); - } -} diff --git a/openflow/utilities/ofp-parse-leaks b/openflow/utilities/ofp-parse-leaks deleted file mode 100644 index e51ecb72..00000000 --- a/openflow/utilities/ofp-parse-leaks +++ /dev/null @@ -1,285 +0,0 @@ -#! /usr/bin/perl - -use strict; -use warnings; - -if (grep($_ eq '--help', @ARGV)) { - print < 1; -die "$0: $ARGV[0] does not exist" if @ARGV > 0 && ! -e $ARGV[0]; - -our ($binary); -our ($a2l) = search_path("addr2line"); -my ($no_syms) = "symbols will not be translated"; -if (!@ARGV) { - print "no binary specified; $no_syms\n"; -} elsif (! -e $ARGV[0]) { - print "$ARGV[0] does not exist; $no_syms"; -} elsif (!defined($a2l)) { - print "addr2line not found in PATH; $no_syms"; -} else { - $binary = $ARGV[0]; -} - -our ($objdump) = search_path("objdump"); -print "objdump not found; dynamic library symbols will not be translated\n" - if !defined($objdump); - -our %blocks; -our @segments; -while () { - my $ptr = "((?:0x)?[0-9a-fA-F]+|\\(nil\\))"; - my $callers = ":((?: $ptr)+)"; - if (/^malloc\((\d+)\) -> $ptr$callers$/) { - allocated($., $2, $1, $3); - } elsif (/^claim\($ptr\)$callers$/) { - claimed($., $1, $2); - } elsif (/realloc\($ptr, (\d+)\) -> $ptr$callers$/) { - my ($callers) = $4; - freed($., $1, $callers); - allocated($., $3, $2, $callers); - } elsif (/^free\($ptr\)$callers$/) { - freed($., $1, $2); - } elsif (/^segment: $ptr-$ptr $ptr [-r][-w][-x][sp] (.*)/) { - add_segment(hex($1), hex($2), hex($3), $4); - } else { - print "stdin:$.: syntax error\n"; - } -} -if (%blocks) { - my $n_blocks = scalar(keys(%blocks)); - my $n_bytes = 0; - $n_bytes += $_->{SIZE} foreach values(%blocks); - print "$n_bytes bytes in $n_blocks blocks not freed at end of run\n"; - my %blocks_by_callers; - foreach my $block (values(%blocks)) { - my ($trimmed_callers) = trim_callers($block->{CALLERS}); - push (@{$blocks_by_callers{$trimmed_callers}}, $block); - } - foreach my $callers (sort {@{$b} <=> @{$a}} (values(%blocks_by_callers))) { - $n_blocks = scalar(@{$callers}); - $n_bytes = 0; - $n_bytes += $_->{SIZE} foreach @{$callers}; - print "$n_bytes bytes in these $n_blocks blocks were not freed:\n"; - my $i = 0; - my $max = 5; - foreach my $block (sort {$a->{LINE} <=> $b->{LINE}} (@{$callers})) { - printf "\t%d-byte block at 0x%08x allocated on stdin:%d\n", - $block->{SIZE}, $block->{BASE}, $block->{LINE}; - last if $i++ > $max; - } - print "\t...and ", $n_blocks - $max, " others...\n" - if $n_blocks > $max; - print "The blocks listed above were allocated by:\n"; - print_callers("\t", ${$callers}[0]->{CALLERS}); - } -} -sub interp_pointer { - my ($s_ptr) = @_; - return $s_ptr eq '(nil)' ? 0 : hex($s_ptr); -} - -sub allocated { - my ($line, $s_base, $size, $callers) = @_; - my ($base) = interp_pointer($s_base); - return if !$base; - my ($info) = {LINE => $line, - BASE => $base, - SIZE => $size, - CALLERS => $callers}; - if (exists($blocks{$base})) { - print "In-use address returned by allocator:\n"; - print "\tInitial allocation:\n"; - print_block("\t\t", $blocks{$base}); - print "\tNew allocation:\n"; - print_block("\t\t", $info); - } - $blocks{$base} = $info; -} - -sub claimed { - my ($line, $s_base, $callers) = @_; - my ($base) = interp_pointer($s_base); - return if !$base; - if (exists($blocks{$base})) { - $blocks{$base}{LINE} = $line; - $blocks{$base}{CALLERS} = $callers; - } else { - printf "Claim asserted on not-in-use block 0x%08x by:\n", $base; - print_callers('', $callers); - } -} - -sub freed { - my ($line, $s_base, $callers) = @_; - my ($base) = interp_pointer($s_base); - return if !$base; - - if (!delete($blocks{$base})) { - printf "Bad free of not-allocated address 0x%08x on stdin:%d by:\n", $base, $line; - print_callers('', $callers); - } -} - -sub print_block { - my ($prefix, $info) = @_; - printf '%s%d-byte block at 0x%08x allocated on stdin:%d by:' . "\n", - $prefix, $info->{SIZE}, $info->{BASE}, $info->{LINE}; - print_callers($prefix, $info->{CALLERS}); -} - -sub print_callers { - my ($prefix, $callers) = @_; - foreach my $pc (split(' ', $callers)) { - print "$prefix\t", lookup_pc($pc), "\n"; - } -} - -our (%cache); -sub lookup_pc { - my ($s_pc) = @_; - if (defined($binary)) { - my ($pc) = hex($s_pc); - my ($output) = "$s_pc: "; - if (!exists($cache{$pc})) { - open(A2L, "$a2l -fe $binary --demangle $s_pc|"); - chomp(my $function = ); - chomp(my $line = ); - close(A2L); - if ($function eq '??') { - ($function, $line) = lookup_pc_by_segment($pc); - } - $line =~ s/^(\.\.\/)*//; - $line = "..." . substr($line, -25) if length($line) > 28; - $cache{$pc} = "$s_pc: $function ($line)"; - } - return $cache{$pc}; - } else { - return "$s_pc"; - } -} - -sub trim_callers { - my ($in) = @_; - my (@out); - foreach my $pc (split(' ', $in)) { - my $xlated = lookup_pc($pc); - if ($xlated =~ /\?\?/) { - push(@out, "...") if !@out || $out[$#out] ne '...'; - } else { - push(@out, $pc); - } - } - return join(' ', @out); -} - -sub search_path { - my ($target) = @_; - for my $dir (split (':', $ENV{PATH})) { - my ($file) = "$dir/$target"; - return $file if -e $file; - } - return undef; -} - -sub add_segment { - my ($vm_start, $vm_end, $vm_pgoff, $file) = @_; - for (my $i = 0; $i <= $#segments; $i++) { - my ($s) = $segments[$i]; - next if $vm_end <= $s->{START} || $vm_start >= $s->{END}; - if ($vm_start <= $s->{START} && $vm_end >= $s->{END}) { - splice(@segments, $i, 1); - --$i; - } else { - $s->{START} = $vm_end if $vm_end > $s->{START}; - $s->{END} = $vm_start if $vm_start <= $s->{END}; - } - } - push(@segments, {START => $vm_start, - END => $vm_end, - PGOFF => $vm_pgoff, - FILE => $file}); - @segments = sort { $a->{START} <=> $b->{START} } @segments; -} - -sub binary_search { - my ($array, $value) = @_; - my $l = 0; - my $r = $#{$array}; - while ($l <= $r) { - my $m = int(($l + $r) / 2); - my $e = $array->[$m]; - if ($value < $e->{START}) { - $r = $m - 1; - } elsif ($value >= $e->{END}) { - $l = $m + 1; - } else { - return $e; - } - } - return undef; -} - -sub read_sections { - my ($file) = @_; - my (@sections); - open(OBJDUMP, "$objdump -h $file|"); - while () { - my $ptr = "([0-9a-fA-F]+)"; - my ($name, $size, $vma, $lma, $file_off) - = /^\s*\d+\s+(\S+)\s+$ptr\s+$ptr\s+$ptr\s+$ptr/ - or next; - push(@sections, {START => hex($file_off), - END => hex($file_off) + hex($size), - NAME => $name}); - } - close(OBJDUMP); - return [sort { $a->{START} <=> $b->{START} } @sections ]; -} - -our %file_to_sections; -sub segment_to_section { - my ($file, $file_offset) = @_; - if (!defined($file_to_sections{$file})) { - $file_to_sections{$file} = read_sections($file); - } - return binary_search($file_to_sections{$file}, $file_offset); -} - -sub address_to_segment { - my ($pc) = @_; - return binary_search(\@segments, $pc); -} - -sub lookup_pc_by_segment { - return ('??', 0) if !defined($objdump); - - my ($pc) = @_; - my ($segment) = address_to_segment($pc); - return ('??', 0) if !defined($segment) || $segment->{FILE} eq ''; - - my ($file_offset) = $pc - $segment->{START} + $segment->{PGOFF}; - my ($section) = segment_to_section($segment->{FILE}, $file_offset); - return ('??', 0) if !defined($section); - - my ($section_offset) = $file_offset - $section->{START}; - open(A2L, sprintf("%s -fe %s --demangle --section=$section->{NAME} 0x%x|", - $a2l, $segment->{FILE}, $section_offset)); - chomp(my $function = ); - chomp(my $line = ); - close(A2L); - - return ($function, $line); -} - -# Local Variables: -# mode: perl -# End: diff --git a/openflow/utilities/ofp-parse-leaks.in b/openflow/utilities/ofp-parse-leaks.in deleted file mode 100755 index 059c8509..00000000 --- a/openflow/utilities/ofp-parse-leaks.in +++ /dev/null @@ -1,285 +0,0 @@ -#! @PERL@ - -use strict; -use warnings; - -if (grep($_ eq '--help', @ARGV)) { - print < 1; -die "$0: $ARGV[0] does not exist" if @ARGV > 0 && ! -e $ARGV[0]; - -our ($binary); -our ($a2l) = search_path("addr2line"); -my ($no_syms) = "symbols will not be translated"; -if (!@ARGV) { - print "no binary specified; $no_syms\n"; -} elsif (! -e $ARGV[0]) { - print "$ARGV[0] does not exist; $no_syms"; -} elsif (!defined($a2l)) { - print "addr2line not found in PATH; $no_syms"; -} else { - $binary = $ARGV[0]; -} - -our ($objdump) = search_path("objdump"); -print "objdump not found; dynamic library symbols will not be translated\n" - if !defined($objdump); - -our %blocks; -our @segments; -while () { - my $ptr = "((?:0x)?[0-9a-fA-F]+|\\(nil\\))"; - my $callers = ":((?: $ptr)+)"; - if (/^malloc\((\d+)\) -> $ptr$callers$/) { - allocated($., $2, $1, $3); - } elsif (/^claim\($ptr\)$callers$/) { - claimed($., $1, $2); - } elsif (/realloc\($ptr, (\d+)\) -> $ptr$callers$/) { - my ($callers) = $4; - freed($., $1, $callers); - allocated($., $3, $2, $callers); - } elsif (/^free\($ptr\)$callers$/) { - freed($., $1, $2); - } elsif (/^segment: $ptr-$ptr $ptr [-r][-w][-x][sp] (.*)/) { - add_segment(hex($1), hex($2), hex($3), $4); - } else { - print "stdin:$.: syntax error\n"; - } -} -if (%blocks) { - my $n_blocks = scalar(keys(%blocks)); - my $n_bytes = 0; - $n_bytes += $_->{SIZE} foreach values(%blocks); - print "$n_bytes bytes in $n_blocks blocks not freed at end of run\n"; - my %blocks_by_callers; - foreach my $block (values(%blocks)) { - my ($trimmed_callers) = trim_callers($block->{CALLERS}); - push (@{$blocks_by_callers{$trimmed_callers}}, $block); - } - foreach my $callers (sort {@{$b} <=> @{$a}} (values(%blocks_by_callers))) { - $n_blocks = scalar(@{$callers}); - $n_bytes = 0; - $n_bytes += $_->{SIZE} foreach @{$callers}; - print "$n_bytes bytes in these $n_blocks blocks were not freed:\n"; - my $i = 0; - my $max = 5; - foreach my $block (sort {$a->{LINE} <=> $b->{LINE}} (@{$callers})) { - printf "\t%d-byte block at 0x%08x allocated on stdin:%d\n", - $block->{SIZE}, $block->{BASE}, $block->{LINE}; - last if $i++ > $max; - } - print "\t...and ", $n_blocks - $max, " others...\n" - if $n_blocks > $max; - print "The blocks listed above were allocated by:\n"; - print_callers("\t", ${$callers}[0]->{CALLERS}); - } -} -sub interp_pointer { - my ($s_ptr) = @_; - return $s_ptr eq '(nil)' ? 0 : hex($s_ptr); -} - -sub allocated { - my ($line, $s_base, $size, $callers) = @_; - my ($base) = interp_pointer($s_base); - return if !$base; - my ($info) = {LINE => $line, - BASE => $base, - SIZE => $size, - CALLERS => $callers}; - if (exists($blocks{$base})) { - print "In-use address returned by allocator:\n"; - print "\tInitial allocation:\n"; - print_block("\t\t", $blocks{$base}); - print "\tNew allocation:\n"; - print_block("\t\t", $info); - } - $blocks{$base} = $info; -} - -sub claimed { - my ($line, $s_base, $callers) = @_; - my ($base) = interp_pointer($s_base); - return if !$base; - if (exists($blocks{$base})) { - $blocks{$base}{LINE} = $line; - $blocks{$base}{CALLERS} = $callers; - } else { - printf "Claim asserted on not-in-use block 0x%08x by:\n", $base; - print_callers('', $callers); - } -} - -sub freed { - my ($line, $s_base, $callers) = @_; - my ($base) = interp_pointer($s_base); - return if !$base; - - if (!delete($blocks{$base})) { - printf "Bad free of not-allocated address 0x%08x on stdin:%d by:\n", $base, $line; - print_callers('', $callers); - } -} - -sub print_block { - my ($prefix, $info) = @_; - printf '%s%d-byte block at 0x%08x allocated on stdin:%d by:' . "\n", - $prefix, $info->{SIZE}, $info->{BASE}, $info->{LINE}; - print_callers($prefix, $info->{CALLERS}); -} - -sub print_callers { - my ($prefix, $callers) = @_; - foreach my $pc (split(' ', $callers)) { - print "$prefix\t", lookup_pc($pc), "\n"; - } -} - -our (%cache); -sub lookup_pc { - my ($s_pc) = @_; - if (defined($binary)) { - my ($pc) = hex($s_pc); - my ($output) = "$s_pc: "; - if (!exists($cache{$pc})) { - open(A2L, "$a2l -fe $binary --demangle $s_pc|"); - chomp(my $function = ); - chomp(my $line = ); - close(A2L); - if ($function eq '??') { - ($function, $line) = lookup_pc_by_segment($pc); - } - $line =~ s/^(\.\.\/)*//; - $line = "..." . substr($line, -25) if length($line) > 28; - $cache{$pc} = "$s_pc: $function ($line)"; - } - return $cache{$pc}; - } else { - return "$s_pc"; - } -} - -sub trim_callers { - my ($in) = @_; - my (@out); - foreach my $pc (split(' ', $in)) { - my $xlated = lookup_pc($pc); - if ($xlated =~ /\?\?/) { - push(@out, "...") if !@out || $out[$#out] ne '...'; - } else { - push(@out, $pc); - } - } - return join(' ', @out); -} - -sub search_path { - my ($target) = @_; - for my $dir (split (':', $ENV{PATH})) { - my ($file) = "$dir/$target"; - return $file if -e $file; - } - return undef; -} - -sub add_segment { - my ($vm_start, $vm_end, $vm_pgoff, $file) = @_; - for (my $i = 0; $i <= $#segments; $i++) { - my ($s) = $segments[$i]; - next if $vm_end <= $s->{START} || $vm_start >= $s->{END}; - if ($vm_start <= $s->{START} && $vm_end >= $s->{END}) { - splice(@segments, $i, 1); - --$i; - } else { - $s->{START} = $vm_end if $vm_end > $s->{START}; - $s->{END} = $vm_start if $vm_start <= $s->{END}; - } - } - push(@segments, {START => $vm_start, - END => $vm_end, - PGOFF => $vm_pgoff, - FILE => $file}); - @segments = sort { $a->{START} <=> $b->{START} } @segments; -} - -sub binary_search { - my ($array, $value) = @_; - my $l = 0; - my $r = $#{$array}; - while ($l <= $r) { - my $m = int(($l + $r) / 2); - my $e = $array->[$m]; - if ($value < $e->{START}) { - $r = $m - 1; - } elsif ($value >= $e->{END}) { - $l = $m + 1; - } else { - return $e; - } - } - return undef; -} - -sub read_sections { - my ($file) = @_; - my (@sections); - open(OBJDUMP, "$objdump -h $file|"); - while () { - my $ptr = "([0-9a-fA-F]+)"; - my ($name, $size, $vma, $lma, $file_off) - = /^\s*\d+\s+(\S+)\s+$ptr\s+$ptr\s+$ptr\s+$ptr/ - or next; - push(@sections, {START => hex($file_off), - END => hex($file_off) + hex($size), - NAME => $name}); - } - close(OBJDUMP); - return [sort { $a->{START} <=> $b->{START} } @sections ]; -} - -our %file_to_sections; -sub segment_to_section { - my ($file, $file_offset) = @_; - if (!defined($file_to_sections{$file})) { - $file_to_sections{$file} = read_sections($file); - } - return binary_search($file_to_sections{$file}, $file_offset); -} - -sub address_to_segment { - my ($pc) = @_; - return binary_search(\@segments, $pc); -} - -sub lookup_pc_by_segment { - return ('??', 0) if !defined($objdump); - - my ($pc) = @_; - my ($segment) = address_to_segment($pc); - return ('??', 0) if !defined($segment) || $segment->{FILE} eq ''; - - my ($file_offset) = $pc - $segment->{START} + $segment->{PGOFF}; - my ($section) = segment_to_section($segment->{FILE}, $file_offset); - return ('??', 0) if !defined($section); - - my ($section_offset) = $file_offset - $section->{START}; - open(A2L, sprintf("%s -fe %s --demangle --section=$section->{NAME} 0x%x|", - $a2l, $segment->{FILE}, $section_offset)); - chomp(my $function = ); - chomp(my $line = ); - close(A2L); - - return ($function, $line); -} - -# Local Variables: -# mode: perl -# End: diff --git a/openflow/utilities/ofp-pki-cgi.in b/openflow/utilities/ofp-pki-cgi.in deleted file mode 100755 index 837b3f92..00000000 --- a/openflow/utilities/ofp-pki-cgi.in +++ /dev/null @@ -1,41 +0,0 @@ -#! @PERL@ - -use CGI; -use Digest::SHA1; -use Fcntl; - -$CGI::POST_MAX = 65536; # Limit POSTs to 64 kB. - -use strict; -use warnings; - -my $pkidir = '@PKIDIR@'; -my $q = new CGI; - -die unless $q->request_method() eq 'POST'; - -my $type = $q->param('type'); -die unless defined $type; -die unless $type eq 'switch' or $type eq 'controller'; - -my $req = $q->param('req'); -die unless defined $req; -die unless $req =~ /^-----BEGIN CERTIFICATE REQUEST-----$/m; -die unless $req =~ /^-----END CERTIFICATE REQUEST-----$/m; - -my $digest = Digest::SHA1::sha1_hex($req); -my $incoming = "$pkidir/${type}ca/incoming"; -my $dst = "$incoming/$digest-req.pem"; - -sysopen(REQUEST, "$dst.tmp", O_RDWR | O_CREAT | O_EXCL, 0600) - or die "sysopen $dst.tmp: $!"; -print REQUEST $req; -close(REQUEST) or die "close $dst.tmp: $!"; - -rename("$dst.tmp", $dst) or die "rename $dst.tmp to $dst: $!"; - -print $q->header('text/html', '204 No response'); - -# Local Variables: -# mode: perl -# End: diff --git a/openflow/utilities/ofp-pki.8.in b/openflow/utilities/ofp-pki.8.in deleted file mode 100644 index 82558955..00000000 --- a/openflow/utilities/ofp-pki.8.in +++ /dev/null @@ -1,325 +0,0 @@ -.TH ofp\-pki 8 "May 2008" "OpenFlow" "OpenFlow Manual" - -.SH NAME -ofp\-pki \- OpenFlow public key infrastructure management utility - -.SH SYNOPSIS -\fBofp\-pki\fR [\fIOPTIONS\fR] \fICOMMAND\fR [\fIARGS\fR] -.sp -Stand\-alone commands with their arguments: -.br -\fBofp\-pki\fR \fBinit\fR -.br -\fBofp\-pki\fR \fBreq\fR \fINAME\fR -.br -\fBofp\-pki\fR \fBsign\fR \fINAME\fR [\fITYPE\fR] -.br -\fBofp\-pki\fR \fBreq+sign\fR \fINAME\fR [\fITYPE\fR] -.br -\fBofp\-pki\fR \fBverify\fR \fINAME\fR [\fITYPE\fR] -.br -\fBofp\-pki\fR \fBfingerprint\fR \fIFILE\fR -.br -\fBofp\-pki\fR \self-sign\fR \fINAME\fR -.sp -The following additional commands manage an online PKI: -.br -\fBofp\-pki\fR \fBls\fR [\fIPREFIX\fR] [\fITYPE\fR] -.br -\fBofp\-pki\fR \fBflush\fR [\fITYPE\fR] -.br -\fBofp\-pki\fR \fBreject\fR \fIPREFIX\fR [\fITYPE\fR] -.br -\fBofp\-pki\fR \fBapprove\fR \fIPREFIX\fR [\fITYPE\fR] -.br -\fBofp\-pki\fR \fBprompt\fR [\fITYPE\fR] -.br -\fBofp\-pki\fR \fBexpire\fR [\fIAGE\fR] -.sp -Each \fITYPE\fR above is a certificate type, either \fBswitch\fR -(default) or \fBcontroller\fR. -.sp -The available options are: -.br -[\fB\-k\fR \fItype\fR | \fB\-\^\-key=\fItype\fR] -[\fB\-B\fR \fInbits\fR | \fB\-\^\-bits=\fInbits\fR] -[\fB\-D\fR \fIfile\fR | \fB\-\^\-dsaparam=\fIfile\fR] -[\fB\-b\fR | \fB\-\^\-batch\fR] -[\fB\-f\fR | \fB\-\^\-force\fR] -[\fB\-d\fR \fIdir\fR | \fB\-\^\-dir=\fR\fIdir\fR] -[\fB\-l\fR \fIfile\fR | \fB\-\^\-log=\fIfile\fR] -[\fB\-h\fR | \fB\-\^\-help\fR] -.br -Some options do not apply to every command. - -.SH DESCRIPTION -The \fBofp\-pki\fR program sets up and manages a public key -infrastructure for use with OpenFlow. It is intended to be a simple -interface for organizations that do not have an established public key -infrastructure. Other PKI tools can substitute for or supplement the -use of \fBofp\-pki\fR. - -\fBofp\-pki\fR uses \fBopenssl\fR(1) for certificate management and key -generation. - -.SH "OFFLINE COMMANDS" - -The following \fBofp\-pki\fR commands support manual PKI -administration: - -.TP -\fBinit\fR -Initializes a new PKI (by default in directory \fB@PKIDIR@\fR) and populates -it with a pair of certificate authorities for controllers and -switches. - -This command should ideally be run on a high\-security machine separate -from any OpenFlow controller or switch, called the CA machine. The -files \fBpki/controllerca/cacert.pem\fR and -\fBpki/switchca/cacert.pem\fR that it produces will need to be copied -over to the OpenFlow switches and controllers, respectively. Their -contents may safely be made public. - -By default, \fBofp\-pki\fR generates 2048\-bit RSA keys. The \fB\-B\fR -or \fB\-\^\-bits\fR option (see below) may be used to override the key -length. The \fB\-k dsa\fR or \fB\-\^\-key=dsa\fR option may be used to use -DSA in place of RSA. If DSA is selected, the \fBdsaparam.pem\fR file -generated in the new PKI hierarchy must be copied to any machine on -which the \fBreq\fR command (see below) will be executed. Its -contents may safely be made public. - -Other files generated by \fBinit\fR may remain on the CA machine. -The files \fBpki/controllerca/private/cakey.pem\fR and -\fBpki/switchca/private/cakey.pem\fR have particularly sensitive -contents that should not be exposed. - -.TP -\fBreq\fR \fINAME\fR -Generates a new private key named \fINAME\fR\fB\-privkey.pem\fR and -corresponding certificate request named \fINAME\fR\fB\-req.pem\fR. -The private key can be intended for use by a switch or a controller. - -This command should ideally be run on the switch or controller that -will use the private key to identify itself. The file -\fINAME\fR\fB\-req.pem\fR must be copied to the CA machine for signing -with the \fBsign\fR command (below). - -This command will output a fingerprint to stdout as its final step. -Write down the fingerprint and take it to the CA machine before -continuing with the \fBsign\fR step. - -When RSA keys are in use (as is the default), \fBreq\fR, unlike the -rest of \fBofp\-pki\fR's commands, does not need access to a PKI -hierarchy created by \fBofp\-pki init\fR. The \fB\-B\fR or -\fB\-\^\-bits\fR option (see below) may be used to specify the number of -bits in the generated RSA key. - -When DSA keys are used (as specified with \fB\-\^\-key=dsa\fR), \fBreq\fR -needs access to the \fBdsaparam.pem\fR file created as part of the PKI -hierarchy (but not to other files in that tree). By default, -\fBofp\-pki\fR looks for this file in \fB@PKIDIR@/dsaparam.pem\fR, but -the \fB\-D\fR or \fB\-\^\-dsaparam\fR option (see below) may be used to -specify an alternate location. - -\fINAME\fR\fB\-privkey.pem\fR has sensitive contents that should not be -exposed. \fINAME\fR\fB\-req.pem\fR may be safely made public. - -.TP -\fBsign\fR \fINAME\fR [\fITYPE\fR] -Signs the certificate request named \fINAME\fR\fB\-req.pem\fR that was -produced in the previous step, producing a certificate named -\fINAME\fR\fB\-cert.pem\fR. \fITYPE\fR, either \fBswitch\fR (default) or -\fBcontroller\fR, indicates the use for which the key is being -certified. - -This command must be run on the CA machine. - -The command will output a fingerprint to stdout and request that you -verify that it is the same fingerprint output by the \fBreq\fR -command. This ensures that the request being signed is the same one -produced by \fBreq\fR. (The \fB\-b\fR or \fB\-\^\-batch\fR option -suppresses the verification step.) - -The file \fINAME\fR\fB\-cert.pem\fR will need to be copied back to the -switch or controller for which it is intended. Its contents may -safely be made public. - -.TP -\fBreq+sign\fR \fINAME\fR [\fITYPE\fR] -Combines the \fBreq\fR and \fBsign\fR commands into a single step, -outputting all the files produced by each. The -\fINAME\fR\fB\-privkey.pem\fR and \fINAME\fR\fB\-cert.pem\fR files must -be copied securely to the switch or controller. -\fINAME\fR\fB\-privkey.pem\fR has sensitive contents and must not be -exposed in transit. Afterward, it should be deleted from the CA -machine. - -This combined method is, theoretically, less secure than the -individual steps performed separately on two different machines, -because there is additional potential for exposure of the private -key. However, it is also more convenient. - -.TP -\fBverify\fR \fINAME\fR [\fITYPE\fR] -Verifies that \fINAME\fR\fB\-cert.pem\fR is a valid certificate for the -given \fITYPE\fR of use, either \fBswitch\fR (default) or -\fBcontroller\fR. If the certificate is valid for this use, it prints -the message ``\fINAME\fR\fB\-cert.pem\fR: OK''; otherwise, it prints an -error message. - -.TP -\fBfingerprint\fR \fIFILE\fR -Prints the fingerprint for \fIFILE\fR. If \fIFILE\fR is a -certificate, then this is the SHA\-1 digest of the DER encoded version -of the certificate; otherwise, it is the SHA\-1 digest of the entire -file. - -.TP -\fBself-sign\fR \fINAME\fR -Signs the certificate request named \fINAME\fB\-req.pem\fR using the -private key \fINAME\fB-privkey.pem\fR, producing a self-signed -certificate named \fINAMEfB\-cert.pem\fR. The input files should have -been produced with \fBofp\-pki req\fR. - -Some controllers accept such self-signed certificates. - -.SH "ONLINE COMMANDS" - -An OpenFlow PKI can be administered online, in conjunction with -.BR ofp\-pki\-cgi (8) -and a web server such as Apache: - -.IP \(bu -The web server exports the contents of the PKI via HTTP. All files in -a PKI hierarchy files may be made public, except for the files -\fBpki/controllerca/private/cakey.pem\fR and -\fBpki/switchca/private/cakey.pem\fR, which must not be exposed. - -.IP \(bu -\fBofp\-pki\-cgi\fR allows newly generated certificate requests for -controllers and switches to be uploaded into the -\fBpki/controllerca/incoming\fR and \fBpki/switchca/incoming\fR -directories, respectively. Uploaded certificate requests are stored -in those directories under names of the form -\fIFINGERPRINT\fB\-req.pem\fR, which \fIFINGERPRINT\fR is the SHA\-1 -hash of the file. - -.IP \(bu -These \fBofp\-pki\fR commands allow incoming certificate requests to -be approved or rejected, in a form are suitable for use by humans or -other software. - -.PP -The following \fBofp\-pki\fR commands support online administration: - -.TP -\fBofp\-pki\fR \fBls\fR [\fIPREFIX\fR] [\fITYPE\fR] -Lists all of the incoming certificate requests of the given \fITYPE\fR -(either \fBswitch\fR, the default, or \fBcontroller\fR). If -\fIPREFIX\fR, which must be at least 4 characters long, is specified, -it causes the list to be limited to files whose names begin with -\fIPREFIX\fR. This is useful, for example, to avoid typing in an -entire fingerprint when checking that a specific certificate request -has been received. - -.TP -\fBofp\-pki\fR \fBflush\fR [\fITYPE\fR] -Deletes all certificate requests of the given \fITYPE\fR. - -.TP -\fBofp\-pki\fR \fBreject\fR \fIPREFIX\fR [\fITYPE\fR] -Rejects the certificate request whose name begins with \fIPREFIX\fR, -which must be at least 4 characters long, of the given type (either -\fBswitch\fR, the default, or \fBcontroller\fR). \fIPREFIX\fR must -match exactly one certificate request; its purpose is to allow the -user to type fewer characters, not to match multiple certificate -requests. - -.TP -\fBofp\-pki\fR \fBapprove\fR \fIPREFIX\fR [\fITYPE\fR] -Approves the certificate request whose name begins with \fIPREFIX\fR, -which must be at least 4 characters long, of the given \fITYPE\fR -(either \fBswitch\fR, the default, or \fBcontroller\fR). \fIPREFIX\fR -must match exactly one certificate request; its purpose is to allow -the user to type fewer characters, not to match multiple certificate -requests. - -The command will output a fingerprint to stdout and request that you -verify that it is correct. (The \fB\-b\fR or \fB\-\^\-batch\fR option -suppresses the verification step.) - -.TP -\fBofp\-pki\fR \fBprompt\fR [\fITYPE\fR] -Prompts the user for each incoming certificate request of the given -\fITYPE\fR (either \fBswitch\fR, the default, or \fBcontroller\fR). -Based on the certificate request's fingerprint, the user is given the -option of approving, rejecting, or skipping the certificate request. - -.TP -\fBofp\-pki\fR \fBexpire\fR [\fIAGE\fR] - -Rejects all the incoming certificate requests, of either type, that is -older than \fIAGE\fR, which must in one of the forms \fIN\fBs\fR, -\fIN\fBmin\fR, \fIN\fBh\fR, \fIN\fBday\fR. The default is \fB1day\fR. - -.SH OPTIONS -.TP -\fB\-k\fR \fItype\fR | \fB\-\^\-key=\fItype\fR -For the \fBinit\fR command, sets the public key algorithm to use for -the new PKI hierarchy. For the \fBreq\fR and \fBreq+sign\fR commands, -sets the public key algorithm to use for the key to be generated, -which must match the value specified on \fBinit\fR. With other -commands, the value has no effect. - -The \fItype\fR may be \fBrsa\fR (the default) or \fBdsa\fR. - -.TP -\fB\-B\fR \fInbits\fR | \fB\-\^\-bits=\fInbits\fR -Sets the number of bits in the key to be generated. When RSA keys are -in use, this option affects only the \fBinit\fR, \fBreq\fR, and -\fBreq+sign\fR commands, and the same value should be given each time. -With DSA keys are in use, this option affects only the \fBinit\fR -command. - -The value must be at least 1024. The default is 2048. - -.TP -\fB\-D\fR \fIfile\fR | \fB\-\^\-dsaparam=\fIfile\fR -Specifies an alternate location for the \fBdsaparam.pem\fR file -required by the \fBreq\fR and \fBreq+sign\fR commands. This option -affects only these commands, and only when DSA keys are used. - -The default is \fBdsaparam.pem\fR under the PKI hierarchy. - -.TP -\fB\-b\fR | \fB\-\^\-batch\fR -Suppresses the interactive verification of fingerprints that the -\fBsign\fR and \fBapprove\fR commands by default require. - -.TP -\fB\-d\fR \fIdir\fR | \fB\-\^\-dir=\fR\fIdir\fR -Specifies the location of the PKI hierarchy to be used or created by -the command (default: \fB@PKIDIR@\fR). All commands, except \fBreq\fR, -need access to a PKI hierarchy. - -.TP -\fB\-f\fR | \fB\-\^\-force\fR -By default, \fBofp\-pki\fR will not overwrite existing files or -directories. This option overrides this behavior. - -.TP -\fB\-l\fR \fIfile\fR | \fB\-\^\-log=\fIfile\fR -Sets the log file to \fIfile\fR. Default: -\fB@LOGDIR@/ofp\-pki.log\fR. - -.TP -\fB\-h\fR | \fB\-\^\-help\fR -Prints a help usage message and exits. - -.SH "SEE ALSO" - -.BR controller (8), -.BR dpctl (8), -.BR ofp\-pki\-cgi (8), -.BR ofprotocol (8), -.BR ofdatapath (8) diff --git a/openflow/utilities/ofp-pki.in b/openflow/utilities/ofp-pki.in deleted file mode 100755 index 3a50cff8..00000000 --- a/openflow/utilities/ofp-pki.in +++ /dev/null @@ -1,582 +0,0 @@ -#! /bin/sh - -set -e - -pkidir='@PKIDIR@' -command= -prev= -force=no -batch=no -log='@LOGDIR@/ofp-pki.log' -keytype=rsa -bits=2048 -for option; do - # This option-parsing mechanism borrowed from a Autoconf-generated - # configure script under the following license: - - # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, - # 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. - # This configure script is free software; the Free Software Foundation - # gives unlimited permission to copy, distribute and modify it. - - # If the previous option needs an argument, assign it. - if test -n "$prev"; then - eval $prev=\$option - prev= - continue - fi - case $option in - *=*) optarg=`expr "X$option" : '[^=]*=\(.*\)'` ;; - *) optarg=yes ;; - esac - - case $dashdash$option in - --) - dashdash=yes ;; - -h|--help) - cat <&2 - exit 1 - ;; - *) - if test -z "$command"; then - command=$option - elif test -z "${arg1+set}"; then - arg1=$option - elif test -z "${arg2+set}"; then - arg2=$option - else - echo "$option: only two arguments may be specified" >&2 - exit 1 - fi - ;; - esac - shift -done -if test -n "$prev"; then - option=--`echo $prev | sed 's/_/-/g'` - { echo "$as_me: error: missing argument to $option" >&2 - { (exit 1); exit 1; }; } -fi -if test -z "$command"; then - echo "$0: missing command name; use --help for help" >&2 - exit 1 -fi -if test "$keytype" != rsa && test "$keytype" != dsa; then - echo "$0: argument to -k or --key must be rsa or dsa" - exit 1 -fi -if test "$bits" -lt 1024; then - echo "$0: argument to -B or --bits must be at least 1024" - exit 1 -fi -if test -z "$dsaparam"; then - dsaparam=$pkidir/dsaparam.pem -fi -case $log in - /*) ;; - *) $log="$PWD/$log" ;; -esac - -if test "$command" = "init"; then - if test -e "$pkidir" && test "$force" != "yes"; then - echo "$0: $pkidir already exists and --force not specified" >&2 - exit 1 - fi - - if test ! -d "$pkidir"; then - mkdir -p "$pkidir" - fi - cd "$pkidir" - exec 3>>$log - - if test $keytype = dsa && test ! -e dsaparam.pem; then - echo "Generating DSA parameters, please wait..." >&2 - openssl dsaparam -out dsaparam.pem $bits 1>&3 2>&3 - fi - - # Create the CAs. - for ca in controllerca switchca; do - echo "Creating $ca..." >&2 - oldpwd=$PWD - mkdir -p $ca - cd $ca - - mkdir -p certs crl newcerts - mkdir -p -m 0700 private - mkdir -p -m 0733 incoming - touch index.txt - test -e crlnumber || echo 01 > crlnumber - test -e serial || echo 01 > serial - - # Put DSA parameters in directory. - if test $keytype = dsa && test ! -e dsaparam.pem; then - cp ../dsaparam.pem . - fi - - # Write CA configuration file. - if test ! -e ca.cnf; then - sed "s/@ca@/$ca/g" > ca.cnf <<'EOF' -[ req ] -prompt = no -distinguished_name = req_distinguished_name - -[ req_distinguished_name ] -C = US -ST = CA -L = Palo Alto -O = OpenFlow -OU = @ca@ -CN = OpenFlow @ca@ CA Certificate - -[ ca ] -default_ca = the_ca - -[ the_ca ] -dir = . # top dir -database = $dir/index.txt # index file. -new_certs_dir = $dir/newcerts # new certs dir -certificate = $dir/cacert.pem # The CA cert -serial = $dir/serial # serial no file -private_key = $dir/private/cakey.pem# CA private key -RANDFILE = $dir/private/.rand # random number file -default_days = 365 # how long to certify for -default_crl_days= 30 # how long before next CRL -default_md = md5 # md to use -policy = policy # default policy -email_in_dn = no # Don't add the email into cert DN -name_opt = ca_default # Subject name display option -cert_opt = ca_default # Certificate display option -copy_extensions = none # Don't copy extensions from request - -# For the CA policy -[ policy ] -countryName = optional -stateOrProvinceName = optional -organizationName = match -organizationalUnitName = optional -commonName = supplied -emailAddress = optional -EOF - fi - - # Create certificate authority. - if test $keytype = dsa; then - newkey=dsa:dsaparam.pem - else - newkey=rsa:$bits - fi - openssl req -config ca.cnf -nodes \ - -newkey $newkey -keyout private/cakey.pem -out careq.pem \ - 1>&3 2>&3 - openssl ca -config ca.cnf -create_serial -out cacert.pem \ - -days 1095 -batch -keyfile private/cakey.pem -selfsign \ - -infiles careq.pem 1>&3 2>&3 - chmod 0700 private/cakey.pem - - cd "$oldpwd" - done - exit 0 -fi - -one_arg() { - if test -z "$arg1" || test -n "$arg2"; then - echo "$0: $command must have exactly one argument; use --help for help" >&2 - exit 1 - fi -} - -zero_or_one_args() { - if test -n "$arg2"; then - echo "$0: $command must have zero or one arguments; use --help for help" >&2 - exit 1 - fi -} - -one_or_two_args() { - if test -z "$arg1"; then - echo "$0: $command must have one or two arguments; use --help for help" >&2 - exit 1 - fi -} - -must_not_exist() { - if test -e "$1" && test "$force" != "yes"; then - echo "$0: $1 already exists and --force not supplied" >&2 - exit 1 - fi -} - -resolve_prefix() { - test -n "$type" || exit 123 # Forgot to call check_type? - - case $1 in - ????*) - ;; - *) - echo "Prefix $arg1 is too short (less than 4 hex digits)" - exit 0 - ;; - esac - - fingerprint=$(cd "$pkidir/${type}ca/incoming" && echo "$1"*-req.pem | sed 's/-req\.pem$//') - case $fingerprint in - "${1}*") - echo "No certificate requests matching $1" - exit 1 - ;; - *" "*) - echo "$1 matches more than one certificate request:" - echo $fingerprint | sed 's/ /\ -/g' - exit 1 - ;; - *) - # Nothing to do. - ;; - esac - req="$pkidir/${type}ca/incoming/$fingerprint-req.pem" - cert="$pkidir/${type}ca/certs/$fingerprint-cert.pem" -} - -make_tmpdir() { - TMP=/tmp/ofp-pki.tmp$$ - rm -rf $TMP - trap "rm -rf $TMP" 0 - mkdir -m 0700 $TMP -} - -fingerprint() { - local file=$1 - local name=${1-$2} - local date=$(date -r $file) - local fingerprint - if grep -q -e '-BEGIN CERTIFICATE-' "$file"; then - fingerprint=$(openssl x509 -noout -in "$file" -fingerprint | - sed 's/SHA1 Fingerprint=//' | tr -d ':') - else - fingerprint=$(sha1sum "$file" | awk '{print $1}') - fi - printf "$name\\t$date\\n" - case $file in - $fingerprint*) - printf "\\t(correct fingerprint in filename)\\n" - ;; - *) - printf "\\tfingerprint $fingerprint\\n" - ;; - esac -} - -verify_fingerprint() { - fingerprint "$@" - if test $batch != yes; then - echo "Does fingerprint match? (yes/no)" - read answer - if test "$answer" != yes; then - echo "Match failure, aborting" >&2 - exit 1 - fi - fi -} - -check_type() { - if test x = x"$1"; then - type=switch - elif test "$1" = switch || test "$1" = controller; then - type=$1 - else - echo "$0: type argument must be 'switch' or 'controller'" >&2 - exit 1 - fi -} - -parse_age() { - number=$(echo $1 | sed 's/^\([0-9]\+\)\([[:alpha:]]\+\)/\1/') - unit=$(echo $1 | sed 's/^\([0-9]\+\)\([[:alpha:]]\+\)/\2/') - case $unit in - s) - factor=1 - ;; - min) - factor=60 - ;; - h) - factor=3600 - ;; - day) - factor=86400 - ;; - *) - echo "$1: age not in the form Ns, Nmin, Nh, Nday (e.g. 1day)" >&2 - exit 1 - ;; - esac - echo $(($number * $factor)) -} - -must_exist() { - if test ! -e "$1"; then - echo "$0: $1 does not exist" >&2 - exit 1 - fi -} - -pkidir_must_exist() { - if test ! -e "$pkidir"; then - echo "$0: $pkidir does not exist (need to run 'init' or use '--dir'?)" >&2 - exit 1 - elif test ! -d "$pkidir"; then - echo "$0: $pkidir is not a directory" >&2 - exit 1 - fi -} - -make_request() { - must_not_exist "$arg1-privkey.pem" - must_not_exist "$arg1-req.pem" - make_tmpdir - cat > "$TMP/req.cnf" <&3 2>&3 -} - -sign_request() { - must_exist "$1" - must_not_exist "$2" - pkidir_must_exist - - (cd "$pkidir/${type}ca" && - openssl ca -config ca.cnf -batch -in /dev/stdin) \ - < "$1" > "$2.tmp$$" 2>&3 - mv "$2.tmp$$" "$2" -} - -glob() { - local files=$(echo $1) - if test "$files" != "$1"; then - echo "$files" - fi -} - -exec 3>>$log || true -if test "$command" = req; then - one_arg - - make_request "$arg1" - fingerprint "$arg1-req.pem" -elif test "$command" = sign; then - one_or_two_args - check_type "$arg2" - verify_fingerprint "$arg1-req.pem" - - sign_request "$arg1-req.pem" "$arg2-cert.pem" -elif test "$command" = req+sign; then - one_or_two_args - check_type "$arg2" - - pkidir_must_exist - make_request "$arg1" - sign_request "$arg1-req.pem" "$arg1-cert.pem" - fingerprint "$arg1-req.pem" -elif test "$command" = verify; then - one_or_two_args - must_exist "$arg1-cert.pem" - check_type "$arg2" - - pkidir_must_exist - openssl verify -CAfile "$pkidir/${type}ca/cacert.pem" "$arg1-cert.pem" -elif test "$command" = fingerprint; then - one_arg - - fingerprint "$arg1" -elif test "$command" = self-sign; then - one_arg - must_exist "$arg1-req.pem" - must_exist "$arg1-privkey.pem" - must_not_exist "$arg1-cert.pem" - - openssl x509 -in "$arg1-req.pem" -out "$arg1-cert.pem" \ - -signkey "$arg1-privkey.pem" -req -text 2>&3 -elif test "$command" = ls; then - check_type "$arg2" - - cd "$pkidir/${type}ca/incoming" - for file in $(glob "$arg1*-req.pem"); do - fingerprint $file - done -elif test "$command" = flush; then - check_type "$arg1" - - rm -f "$pkidir/${type}ca/incoming/"* -elif test "$command" = reject; then - one_or_two_args - check_type "$arg2" - resolve_prefix "$arg1" - - rm -f "$req" -elif test "$command" = approve; then - one_or_two_args - check_type "$arg2" - resolve_prefix "$arg1" - - make_tmpdir - cp "$req" "$TMP/$req" - verify_fingerprint "$TMP/$req" - sign_request "$TMP/$req" - rm -f "$req" "$TMP/$req" -elif test "$command" = prompt; then - zero_or_one_args - check_type "$arg1" - - make_tmpdir - cd "$pkidir/${type}ca/incoming" - for req in $(glob "*-req.pem"); do - cp "$req" "$TMP/$req" - - cert=$(echo "$pkidir/${type}ca/certs/$req" | - sed 's/-req.pem/-cert.pem/') - if test -f $cert; then - echo "Request $req already approved--dropping duplicate request" - rm -f "$req" "$TMP/$req" - continue - fi - - echo - echo - fingerprint "$TMP/$req" "$req" - printf "Disposition for this request (skip/approve/reject)? " - read answer - case $answer in - approve) - echo "Approving $req" - sign_request "$TMP/$req" "$cert" - rm -f "$req" "$TMP/$req" - ;; - r*) - echo "Rejecting $req" - rm -f "$req" "$TMP/$req" - ;; - *) - echo "Skipping $req" - ;; - esac - done -elif test "$command" = expire; then - zero_or_one_args - cutoff=$(($(date +%s) - $(parse_age ${arg1-1day}))) - for type in switch controller; do - cd "$pkidir/${type}ca/incoming" || exit 1 - for file in $(glob "*"); do - time=$(date -r "$file" +%s) - if test "$time" -lt "$cutoff"; then - rm -f "$file" - fi - done - done -else - echo "$0: $command command unknown; use --help for help" >&2 - exit 1 -fi diff --git a/openflow/utilities/vlogconf.8.in b/openflow/utilities/vlogconf.8.in deleted file mode 100644 index eb9c192e..00000000 --- a/openflow/utilities/vlogconf.8.in +++ /dev/null @@ -1,183 +0,0 @@ -.ds PN vlogconf - -.TH vlogconf 8 "June 2008" "OpenFlow" "OpenFlow Manual" - -.SH NAME -vlogconf \- configuration utility for OpenFlow logging in userspace - -.SH SYNOPSIS -\fBvlogconf\fR [\fB-h\fR | \fB--help\fR] [\fItarget\fR...] [\fIaction\fR...] -.sp 1 -The available \fItarget\fR options are: -.br -[\fB-a\fR | \fB--all\fR] [\fB-t\fR \fIpid\fR | \fB--target=\fIpid\fR] -.sp 1 -The available \fIaction\fR options are: -.br -[\fB-l\fR | \fB--list\fR] [\fB-s\fR -\fImodule\fR[\fB:\fIfacility\fR[\fB:\fIlevel\fR]] | -\fB--set=\fImodule\fR[\fB:\fIfacility\fR[\fB:\fIlevel\fR]]] -[\fB-r\fR | \fB--reopen\fR] - -.SH DESCRIPTION -The \fBvlogconf\fR program configures the logging system used by -OpenFlow userspace programs. The logging configuration may be modified -while OpenFlow programs are running. - -\fBvlogconf\fR applies one or more actions to each of one or more -target processes. Targets may be specified as: - -.TP -\fB-a\fR, \fB--all\fR -All running processes that \fBvlogconf\fR can control. - -.TP -\fB-t \fItarget\fR, \fB--target=\fItarget\fR -The specified \fItarget\fR, which must take one of the following forms: - -.RS -.IP \(bu -A PID (process ID). - -.IP \(bu -An absolute path (beginning with `/') to the Unix domain socket for a -\fBvlogconf\fR-controllable process. - -.IP \(bu -An absolute path (beginning with `/') to a pidfile (created by, e.g., -passing the \fB-P\fR or \fB--pidfile\fR option to one of the OpenFlow -programs). - -.IP \(bu -None of the above, in which case \fItarget\fR prefixed by -\fB@RUNDIR@/\fR must match one of the cases for absolute paths listed -above. (The default name for a program's pidfile is -\fB@RUNDIR@/\fIprogram\fB.pid\fR, so this means that, say, -\fBofprotocol\fR's default pidfile may be referred to simply as -\fBofprotocol.pid\fR.) -.RE - -.PP -The available actions are: - -.TP -\fB-l\fR, \fB--list\fR -Print the list of known modules and their current logging levels to -stdout. - -.TP -\fB-s\fR \fImodule\fR[\fB:\fIfacility\fR[\fB:\fIlevel\fR]], \fB--set=\fImodule\fR[\fB:\fIfacility\fR[\fB:\fIlevel\fR]] - -Sets the logging level for \fImodule\fR in \fIfacility\fR to -\fIlevel\fR. The \fImodule\fR may be any valid module name (as -displayed by the \fB--list\fR option) or the special name \fBANY\fR to -set the logging levels for all modules. The \fIfacility\fR may be -\fBsyslog\fR or \fBconsole\fR to set the levels for logging to the -system log or to the console, respectively, or \fBANY\fR to set the -logging levels for both facilities. If it is omitted, -\fIfacility\fR defaults to \fBANY\fR. The \fIlevel\fR must be one of -\fBemer\fR, \fBerr\fR, \fBwarn\fR, \fBinfo\fR, or \fBdbg\fR, designating the -minimum severity of a message for it to be logged. If it is omitted, -\fIlevel\fR defaults to \fBdbg\fR. - -.TP -\fB-s PATTERN:\fIfacility\fB:\fIpattern\fR, \fB--set=PATTERN:\fIfacility\fB:\fIpattern\fR - -Sets the log pattern for \fIfacility\fR to \fIpattern\fR. Each time a -message is logged to \fIfacility\fR, \fIpattern\fR determines the -message's formatting. Most characters in \fIpattern\fR are copied -literally to the log, but special escapes beginning with \fB%\fR are -expanded as follows: - -.RS -.TP -\fB%A\fR -The name of the application logging the message, e.g. \fBofprotocol\fR. - -.TP -\fB%c\fR -The name of the module (as shown by \fBvlogconf --list\fR) logging -the message. - -.TP -\fB%d\fR -The current date and time in ISO 8601 format (YYYY-MM-DD HH:MM:SS). - -.TP -\fB%d{\fIformat\fB}\fR -The current date and time in the specified \fIformat\fR, which takes -the same format as the \fItemplate\fR argument to \fBstrftime\fR(3). - -.TP -\fB%m\fR -The message being logged. - -.TP -\fB%N\fR -A serial number for this message within this run of the program, as a -decimal number. The first message a program logs has serial number 1, -the second one has serial number 2, and so on. - -.TP -\fB%n\fR -A new-line. - -.TP -\fB%p\fR -The level at which the message is logged, e.g. \fBDBG\fR. - -.TP -\fB%P\fR -The program's process ID (pid), as a decimal number. - -.TP -\fB%r\fR -The number of milliseconds elapsed from the start of the application -to the time the message was logged. - -.TP -\fB%%\fR -A literal \fB%\fR. -.RE - -.IP -A few options may appear between the \fB%\fR and the format specifier -character, in this order: - -.RS -.TP -\fB-\fR -Left justify the escape's expansion within its field width. Right -justification is the default. - -.TP -\fB0\fR -Pad the field to the field width with \fB0\fRs. Padding with spaces -is the default. - -.TP -\fIwidth\fR -A number specifies the minimum field width. If the escape expands to -fewer characters than \fIwidth\fR then it is padded to fill the field -width. (A field wider than \fIwidth\fR is not truncated to fit.) -.RE - -.IP -The default pattern for console output is \fB%d{%b %d -%H:%M:%S}|%05N|%c|%p|%m\fR; for syslog output, \fB%05N|%c|%p|%m\fR. - -.TP -\fB-r\fR, \fB--reopen\fR -Causes the target application to close and reopen its log file. (This -is useful after rotating log files, to cause a new log file to be -used.) - -.SH OPTIONS - -.so lib/common.man - -.SH "SEE ALSO" - -.BR dpctl (8), -.BR ofprotocol (8), -.BR controller (8) diff --git a/openflow/utilities/vlogconf.c b/openflow/utilities/vlogconf.c deleted file mode 100644 index 5c48f724..00000000 --- a/openflow/utilities/vlogconf.c +++ /dev/null @@ -1,235 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ -#include -#include "vlog.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "command-line.h" -#include "compiler.h" -#include "timeval.h" -#include "util.h" -#include "vlog-socket.h" - -static void -usage(char *prog_name, int exit_code) -{ - printf("Usage: %s [TARGET] [ACTION...]\n" - "Targets:\n" - " -a, --all Apply to all targets (default)\n" - " -t, --target=TARGET Specify target program, as a pid, a\n" - " pidfile, or an absolute path to a Unix\n" - " domain socket\n" - "Actions:\n" - " -l, --list List current settings\n" - " -s, --set=MODULE[:FACILITY[:LEVEL]]\n" - " Set MODULE and FACILITY log level to LEVEL\n" - " MODULE may be any valid module name or 'ANY'\n" - " FACILITY may be 'syslog', 'console', 'file', or 'ANY' (default)\n" - " LEVEL may be 'emer', 'err', 'warn', 'info', or 'dbg' (default)\n" - " -r, --reopen Make the program reopen its log file\n" - " -h, --help Print this helpful information\n", - prog_name); - exit(exit_code); -} - -static char * -transact(struct vlog_client *client, const char *request, bool *ok) -{ - char *reply; - int error = vlog_client_transact(client, request, &reply); - if (error) { - fprintf(stderr, "%s: transaction error: %s\n", - vlog_client_target(client), strerror(error)); - *ok = false; - } - return reply ? reply : xstrdup(""); -} - -static void -transact_ack(struct vlog_client *client, const char* request, bool *ok) -{ - char *reply; - int error = vlog_client_transact(client, request, &reply); - if (error) { - fprintf(stderr, "%s: transaction error: %s\n", - vlog_client_target(client), strerror(error)); - *ok = false; - } else if (strcmp(reply, "ack")) { - fprintf(stderr, "Received unexpected reply from %s: %s\n", - vlog_client_target(client), reply); - *ok = false; - } - free(reply); -} - -static void -add_target(struct vlog_client ***clients, size_t *n_clients, - const char *path, bool *ok) -{ - struct vlog_client *client; - int error = vlog_client_connect(path, &client); - if (error) { - fprintf(stderr, "Error connecting to \"%s\": %s\n", - path, strerror(error)); - *ok = false; - } else { - *clients = xrealloc(*clients, sizeof *clients * (*n_clients + 1)); - (*clients)[*n_clients] = client; - ++*n_clients; - } -} - -static void -add_all_targets(struct vlog_client ***clients, size_t *n_clients, bool *ok) -{ - DIR *directory; - struct dirent* de; - - directory = opendir("/tmp"); - if (!directory) { - fprintf(stderr, "/tmp: opendir: %s\n", strerror(errno)); - } - - while ((de = readdir(directory)) != NULL) { - if (!strncmp(de->d_name, "vlogs.", 5)) { - char *path = xasprintf("/tmp/%s", de->d_name); - add_target(clients, n_clients, path, ok); - free(path); - } - } - - closedir(directory); -} - -int main(int argc, char *argv[]) -{ - static const struct option long_options[] = { - /* Target options must come first. */ - {"all", no_argument, NULL, 'a'}, - {"target", required_argument, NULL, 't'}, - {"help", no_argument, NULL, 'h'}, - - /* Action options come afterward. */ - {"list", no_argument, NULL, 'l'}, - {"set", required_argument, NULL, 's'}, - {"reopen", no_argument, NULL, 'r'}, - {0, 0, 0, 0}, - }; - char *short_options; - - /* Determine targets. */ - bool ok = true; - int n_actions = 0; - struct vlog_client **clients = NULL; - size_t n_clients = 0; - - set_program_name(argv[0]); - time_init(); - - short_options = long_options_to_short_options(long_options); - for (;;) { - int option; - size_t i; - - option = getopt_long(argc, argv, short_options, long_options, NULL); - if (option == -1) { - break; - } - if (!strchr("ath", option) && n_clients == 0) { - ofp_fatal(0, "no targets specified (use --help for help)"); - } else { - ++n_actions; - } - switch (option) { - case 'a': - add_all_targets(&clients, &n_clients, &ok); - break; - - case 't': - add_target(&clients, &n_clients, optarg, &ok); - break; - - case 'l': - for (i = 0; i < n_clients; i++) { - struct vlog_client *client = clients[i]; - char *reply; - - printf("%s:\n", vlog_client_target(client)); - reply = transact(client, "list", &ok); - fputs(reply, stdout); - free(reply); - } - break; - - case 's': - for (i = 0; i < n_clients; i++) { - struct vlog_client *client = clients[i]; - char *request = xasprintf("set %s", optarg); - transact_ack(client, request, &ok); - free(request); - } - break; - - case 'r': - for (i = 0; i < n_clients; i++) { - struct vlog_client *client = clients[i]; - char *request = xstrdup("reopen"); - transact_ack(client, request, &ok); - free(request); - } - break; - - case 'h': - usage(argv[0], EXIT_SUCCESS); - break; - - case '?': - exit(EXIT_FAILURE); - - default: - NOT_REACHED(); - } - } - if (!n_actions) { - fprintf(stderr, - "warning: no actions specified (use --help for help)\n"); - } - exit(ok ? 0 : 1); -} diff --git a/openflow/utilities/wireshark_dissectors/Makefile b/openflow/utilities/wireshark_dissectors/Makefile deleted file mode 100644 index cf82d045..00000000 --- a/openflow/utilities/wireshark_dissectors/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# simple Makefile to build and install all of our Wireshark plugins - -# build a list of all sub-directories except the includes path -PLUGIN_DIRS = $(shell ls -l | grep "^d" | cut -d: -f2- | cut -d\ -f2 | fgrep -v 'wireshark-1.0.0-includes') -CLEAN_PLUGIN_DIRS = $(foreach dir,$(PLUGIN_DIRS),clean$(dir)) -INSTALL_PLUGIN_DIRS = $(foreach dir,$(PLUGIN_DIRS),install$(dir)) - -.PHONY: all $(PLUGIN_DIRS) clean $(CLEAN_PLUGIN_DIRS) install $(INSTALL_PLUGIN_DIRS) - -# build all the plugins -all: - @$(MAKE) --no-print-directory $(PLUGIN_DIRS) - -# cleanup all the byproducts (including the plugin itself) -clean: - @$(MAKE) --no-print-directory $(CLEAN_PLUGIN_DIRS) - -# install all plugins -install: - @$(MAKE) --no-print-directory $(INSTALL_PLUGIN_DIRS) - -# build the plugin in the specified directory using its default rule -$(PLUGIN_DIRS): - @$(MAKE) --no-print-directory -C $@ - -# cleans up the plugin in the specified directory using its 'clean' rule -$(CLEAN_PLUGIN_DIRS): - @$(MAKE) --no-print-directory -C `echo $@ | sed -e "s#^clean##"` clean - -# installs up the plugin in the specified directory using its 'install' rule -$(INSTALL_PLUGIN_DIRS): - @$(MAKE) --no-print-directory -C `echo $@ | sed -e "s#^install##"` install diff --git a/openflow/utilities/wireshark_dissectors/README b/openflow/utilities/wireshark_dissectors/README deleted file mode 100644 index 0aac13dd..00000000 --- a/openflow/utilities/wireshark_dissectors/README +++ /dev/null @@ -1,37 +0,0 @@ -README: OpenFlow Wireshark Plugin - - - ----------------------------------------- -I) Installation - -1) Install glib-devel; on Debian this can be done with 'sudo apt-get install libgtk2.0-dev' -2) Install wireshark v1.0.0 or greater -3) cd wireshark_dissectors/openflow -4) make -5) sudo make install -5a) Note that this prints out where the plugin was installed. - - ----------------------------------------- -II) Installation Verification - -1) Run wireshark -2) Open the "Help" --> "About" menu -3) Select the "Plugins" tab -4) Click the "Name" header to the plugins by name -5) Verify that "packet-openflow.so" appears in the list. -6) Verify that its version is listed as . - - ----------------------------------------- -III) Port Changes - -To have the dissector handle OpenFlow packets for any port other than the default, you must change the DISSECT_PORT variable in utilities/wireshark_dissectors/oepnflow/Makefile. - ----------------------------------------- -IV) Feedback and Bug Reporting - -Please post a message on the OpenFlow forums at openflowswitch.org or email -David Underhill at dgu@cs.stanford.edu if you have any feedback or discover any -bugs. diff --git a/openflow/utilities/wireshark_dissectors/openflow/.gitignore b/openflow/utilities/wireshark_dissectors/openflow/.gitignore deleted file mode 100644 index aa1ec1ea..00000000 --- a/openflow/utilities/wireshark_dissectors/openflow/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.tgz diff --git a/openflow/utilities/wireshark_dissectors/openflow/Makefile b/openflow/utilities/wireshark_dissectors/openflow/Makefile deleted file mode 100644 index 8c533ce9..00000000 --- a/openflow/utilities/wireshark_dissectors/openflow/Makefile +++ /dev/null @@ -1,79 +0,0 @@ -WIRESHARK_SRC_DIR = ../wireshark-1.0.0-includes - -SRCS = packet-openflow.c plugin.c -CC = gcc -OBJS = $(foreach src, $(SRCS), $(src:.c=.o)) - -PLUGIN_NAME = packet-openflow - -# local installation path -LOCAL_PLUGIN_DIR = /home/$(shell whoami)/.wireshark/plugins - -# determine global installation path (use latest plugin version path) -ifneq ($(wildcard /usr/local/lib/wireshark/plugins),) - GLOBAL_PLUGIN_DIR_PARTIAL=/usr/local/lib/wireshark/plugins -else ifneq ($(wildcard /usr/lib/wireshark/plugins),) - GLOBAL_PLUGIN_DIR_PARTIAL=/usr/lib/wireshark/plugins -endif - -# Work out if there are version-specific subdirectories -GLOBAL_PLUGIN_DIR_FILES := $(wildcard $(GLOBAL_PLUGIN_DIR_PARTIAL)/*) -GLOBAL_PLUGIN_DIR_SUBDIRS := $(foreach file,$(GLOBAL_PLUGIN_DIR_FILES),$(dir $(wildcard $(file)/.))) -GLOBAL_PLUGIN_DIR_SUBDIRS := $(subst $(GLOBAL_PLUGIN_DIR_PARTIAL)/,,$(GLOBAL_PLUGIN_DIR_SUBDIRS)) -GLOBAL_PLUGIN_DIR_SUBDIRS := $(subst /,,$(GLOBAL_PLUGIN_DIR_SUBDIRS)) - -# Assume that the "last" directory is the one we ant to use if it exists -GLOBAL_PLUGIN_VER := $(lastword $(sort $(GLOBAL_PLUGIN_DIR_SUBDIRS))) - -# Create the actual global plugin dir to use -ifneq ($(GLOBAL_PLUGIN_VER),) - GLOBAL_PLUGIN_DIR=$(GLOBAL_PLUGIN_DIR_PARTIAL)/$(GLOBAL_PLUGIN_VER) -else - GLOBAL_PLUGIN_DIR=$(GLOBAL_PLUGIN_DIR_PARTIAL) -endif - -# specify the port on which event capture packets will be destined -DISSECT_PORT = -DOPENFLOW_DST_TCP_PORT=6633 - -OSTYPE = $(shell uname) -ifeq ($(OSTYPE),Linux) -ENDIAN=-D_LITTLE_ENDIAN_ -endif -ifeq ($(OSTYPE),SunOS) -ENDIAN=-D_BIG_ENDIAN_ -endif - -INC_GLIB=$(shell pkg-config --cflags glib-2.0) -INC_OPENFLOW=../../../include - -INC_DIRS = -I. $(INC_GLIB) -I$(INC_OPENFLOW) -CFLAGS = $(INC_DIRS) -DHAVE_CONFIG_H -I$(WIRESHARK_SRC_DIR) -I/usr/local/include -I/usr/local/include -DINET6 -D_U_=__attribute__\(\(unused\)\) -Wall -Wpointer-arith -g -I/usr/local/include -DXTHREADS -D_REENTRANT -DXUSE_MTSAFE_API -pthread -I/usr/include/gtk-2.0 -I/usr/lib/gtk-2.0/include -I/usr/X11R6/include -I/usr/include/atk-1.0 -I/usr/include/pango-1.0 -I/usr/include/freetype2 -I/usr/include/freetype2/config -I/usr/local/include/glib-2.0 -I/usr/lib/glib-2.0/include -fPIC -DPIC $(ENDIAN) $(DISSECT_PORT) - -LDFLAGS = -Wl,--rpath -Wl,/usr/local/lib -Wl,--rpath -Wl,/usr/local/lib -L/usr/local/lib -L$(WIRESHARK_SRC_DIR)/epan -L. -lgmodule-2.0 -ldl -lglib-2.0 -pthread -Wl,--export-dynamic -Wl,-soname -Wl,$(PLUGIN_NAME).so - -.PHONY: clean install - -$(PLUGIN_NAME).so : $(OBJS) $(SRCS) - $(CC) -shared $(OBJS) $(LDFLAGS) -o $@ - -install: $(PLUGIN_NAME).so - @if [ `id -u` -eq 0 ]; then \ - if [ -d "$(GLOBAL_PLUGIN_DIR)" ]; then \ - target="$(GLOBAL_PLUGIN_DIR)/$<"; \ - res="*** Installed plugin for ALL users ($$target)"; \ - else \ - echo "*** Error: global plugin directory $(GLOBAL_PLUGIN_DIR) does not exist"; \ - exit 1; \ - fi; \ - else \ - mkdir -p "$(LOCAL_PLUGIN_DIR)/"; \ - target="$(LOCAL_PLUGIN_DIR)/$<"; \ - res="*** Installed plugin for user "`id | cut -d\( -f2 | cut -d\) -f1`" ($$target)"; \ - fi; \ - install --mode=644 $< "$$target" && echo "" && echo "" && echo "$$res" && echo "" && echo "" - -plugin.c: moduleinfo.h Makefile.am Makefile.common - $(MAKE) -f Makefile.am - -clean: - rm -f $(PLUGIN) $(OBJS) $(PLUGIN_NAME).so diff --git a/openflow/utilities/wireshark_dissectors/openflow/Makefile.am b/openflow/utilities/wireshark_dissectors/openflow/Makefile.am deleted file mode 100644 index be972bd8..00000000 --- a/openflow/utilities/wireshark_dissectors/openflow/Makefile.am +++ /dev/null @@ -1,110 +0,0 @@ -# Makefile.am -# Automake file for H.223 plugin -# -# $Id: Makefile.am 21961 2007-05-27 18:35:55Z guy $ -# -# Wireshark - Network traffic analyzer -# By Gerald Combs -# Copyright 1998 Gerald Combs - -srcdir = . -top_srcdir = ../wireshark-1.0.0-includes -includedir = ../wireshark-1.0.0-includes -INCLUDES = -I$(top_srcdir) -I$(includedir) - -include Makefile.common - -#if HAVE_WARNINGS_AS_ERRORS -#AM_CFLAGS = -Werror -#endif - -plugindir = ~/.wireshark/plugins - -plugin_LTLIBRARIES = hsapi.la -hsapi_la_SOURCES = \ - plugin.c \ - moduleinfo.h \ - $(DISSECTOR_SRC) \ - $(DISSECTOR_SUPPORT_SRC) \ - $(DISSECTOR_INCLUDES) -openflow_la_LDFLAGS = -module -avoid-version -openflow_la_LIBADD = @PLUGIN_LIBS@ - -# Libs must be cleared, or else libtool won't create a shared module. -# If your module needs to be linked against any particular libraries, -# add them here. -LIBS = - -# -# Build plugin.c, which contains the plugin version[] string, a -# function plugin_register() that calls the register routines for all -# protocols, and a function plugin_reg_handoff() that calls the handoff -# registration routines for all protocols. -# -# We do this by scanning sources. If that turns out to be too slow, -# maybe we could just require every .o file to have an register routine -# of a given name (packet-aarp.o -> proto_register_aarp, etc.). -# -# Formatting conventions: The name of the proto_register_* routines an -# proto_reg_handoff_* routines must start in column zero, or must be -# preceded only by "void " starting in column zero, and must not be -# inside #if. -# -# DISSECTOR_SRC is assumed to have all the files that need to be scanned. -# -# For some unknown reason, having a big "for" loop in the Makefile -# to scan all the files doesn't work with some "make"s; they seem to -# pass only the first few names in the list to the shell, for some -# reason. -# -# Therefore, we have a script to generate the plugin.c file. -# The shell script runs slowly, as multiple greps and seds are run -# for each input file; this is especially slow on Windows. Therefore, -# if Python is present (as indicated by PYTHON being defined), we run -# a faster Python script to do that work instead. -# -# The first argument is the directory in which the source files live. -# The second argument is "plugin", to indicate that we should build -# a plugin.c file for a plugin. -# All subsequent arguments are the files to scan. -# -plugin.c: $(DISSECTOR_SRC) $(top_srcdir)/tools/make-dissector-reg \ - $(top_srcdir)/tools/make-dissector-reg.py - @if test -n $(PYTHON); then \ - echo Making plugin.c with python ; \ - $(PYTHON) $(top_srcdir)/tools/make-dissector-reg.py $(srcdir) \ - plugin $(DISSECTOR_SRC) ; \ - else \ - echo Making plugin.c with shell script ; \ - $(top_srcdir)/tools/make-dissector-reg $(srcdir) \ - $(plugin_src) plugin $(DISSECTOR_SRC) ; \ - fi - -# -# Currently plugin.c can be included in the distribution because -# we always build all protocol dissectors. We used to have to check -# whether or not to build the snmp dissector. If we again need to -# variably build something, making plugin.c non-portable, uncomment -# the dist-hook line below. -# -# Oh, yuk. We don't want to include "plugin.c" in the distribution, as -# its contents depend on the configuration, and therefore we want it -# to be built when the first "make" is done; however, Automake insists -# on putting *all* source into the distribution. -# -# We work around this by having a "dist-hook" rule that deletes -# "plugin.c", so that "dist" won't pick it up. -# -#dist-hook: -# @rm -f $(distdir)/plugin.c - -CLEANFILES = \ - openflow \ - *~ - -MAINTAINERCLEANFILES = \ - Makefile.in \ - plugin.c - -EXTRA_DIST = \ - Makefile.common diff --git a/openflow/utilities/wireshark_dissectors/openflow/Makefile.common b/openflow/utilities/wireshark_dissectors/openflow/Makefile.common deleted file mode 100644 index 26c43d26..00000000 --- a/openflow/utilities/wireshark_dissectors/openflow/Makefile.common +++ /dev/null @@ -1,13 +0,0 @@ -# the name of the plugin -PLUGIN_NAME = openflow - -# the dissector sources (without any helpers) -DISSECTOR_SRC = packet-openflow.c - -# corresponding headers -DISSECTOR_INCLUDES = - -# Dissector helpers. They're included in the source files in this -# directory, but they're not dissectors themselves, i.e. they're not -# used to generate "register.c"). -DISSECTOR_SUPPORT_SRC = diff --git a/openflow/utilities/wireshark_dissectors/openflow/build_distribution_tarball.sh b/openflow/utilities/wireshark_dissectors/openflow/build_distribution_tarball.sh deleted file mode 100755 index d6b1ae05..00000000 --- a/openflow/utilities/wireshark_dissectors/openflow/build_distribution_tarball.sh +++ /dev/null @@ -1,63 +0,0 @@ -#!/bin/bash -set -o errexit -set -o nounset - -# if user specifies a folder, cd to it -if [ $# -ne 0 ]; then - cd $1 -fi - -# sanity check: make sure script is running from within the plugin build directory -origdir=`pwd` -topdir=wireshark_dissectors -if [ "$topdir" != `dirname $origdir | sed -e "s#.*/##"` ]; then - echo "Error: script must be run from within the plugin's subdirectory with $topdir" - exit 1 -fi - -# sanity check: make sure build works -rm -f *.so -make > /dev/null 2> /dev/null -plugin=`grep 'PLUGIN_NAME =' Makefile | sed -e "s#PLUGIN_NAME =##" -e "s# ##g"`.so -if [ ! -f $plugin ]; then - echo "Error: make failed to build $plugin" - exit 1 -fi - -# make a temporary folder for the build file -tmpdir=/tmp/.$$ -builddir="$tmpdir/$topdir/openflow" -mkdir $tmpdir - -# copy the wireshark plugin directory to the temp folder -cp -r ../ "$tmpdir/$topdir" - -# add the openflow header to the build folder which is in the include search path -cp ../../../include/openflow/openflow.h "$builddir/" - -# cleanup the contents of the build folder -cd "$builddir" -make clean -rm -f *.tgz $0 - -# get the version of the plugin -version=`grep '#define VERSION' moduleinfo.h | cut -d\" -f2` - -# replace tag in README with date information' -date=`date` -cat ../README | sed -e "s##Plugin Version: $version#g" > ../tmp -cat ../tmp | sed -e "s##Distribution Creation Date: $date#g" > ../README - -# make a tarball from the build folder -tarball="openflow-wireshark-dissector-v$version.tar.gz" -cd ../../ -tar -zcf "$tarball" "$topdir" - -# put the tarball back in the original directory -mv "$tarball" "$origdir/" - -# cleanup the temporary folder -rm -rf "$tmpdir" - -# tell the user what we created -echo "tarballed release is now ready: $tarball" diff --git a/openflow/utilities/wireshark_dissectors/openflow/moduleinfo.h b/openflow/utilities/wireshark_dissectors/openflow/moduleinfo.h deleted file mode 100644 index b7bd7f5e..00000000 --- a/openflow/utilities/wireshark_dissectors/openflow/moduleinfo.h +++ /dev/null @@ -1,15 +0,0 @@ -/* Included *after* config.h, in order to re-define these macros */ - -#ifdef PACKAGE -#undef PACKAGE -#endif - -/* Name of package */ -#define PACKAGE "openflow" - -#ifdef VERSION -#undef VERSION -#endif - -/* Version number of package */ -#define VERSION "1.0.0" /* OpenFlowMajor.OpenFlowMinor.PluginRevForThisMajorMinorRev */ diff --git a/openflow/utilities/wireshark_dissectors/openflow/packet-openflow.c b/openflow/utilities/wireshark_dissectors/openflow/packet-openflow.c deleted file mode 100644 index aea00f88..00000000 --- a/openflow/utilities/wireshark_dissectors/openflow/packet-openflow.c +++ /dev/null @@ -1,3426 +0,0 @@ -/** - * Filename: packet-openflow.c - * Author: David Underhill - * Changelog: - * dgu 2008-Aug-26 created - * brandonh 2008-Oct-5 updated to 0x95 - * brandonh 2008-Nov-25 updated to 0x96 + bugfixes - * tyabe 2009-May-20 added vlan_pcp_match - * - * Defines a Wireshark 1.0.0+ dissector for the OpenFlow protocol version 0x98. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** the version of openflow this dissector was written for */ -#define DISSECTOR_OPENFLOW_MIN_VERSION OFP_VERSION -#define DISSECTOR_OPENFLOW_MAX_VERSION OFP_VERSION -#define DISSECTOR_OPENFLOW_VERSION_DRAFT_THRESHOLD OFP_VERSION - -/** if 0, padding bytes will not be shown in the dissector */ -#define SHOW_PADDING 0 - -#define PROTO_TAG_OPENFLOW "OFP" - -/* Wireshark ID of the OPENFLOW protocol */ -static int proto_openflow = -1; -static dissector_handle_t openflow_handle; -static void dissect_openflow(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); - -/* traffic will arrive with TCP port OPENFLOW_DST_TCP_PORT */ -#define TCP_PORT_FILTER "tcp.port" -static int global_openflow_proto = OPENFLOW_DST_TCP_PORT; - -/* try to find the ethernet dissector to dissect encapsulated Ethernet data */ -static dissector_handle_t data_ethernet; - -/* AM=Async message, CSM=Control/Switch Message, SM=Symmetric Message */ -/** names to bind to various values in the type field */ -static const value_string names_ofp_type[] = { - /* Immutable messages. */ - { OFPT_HELLO, "Hello (SM)" }, - { OFPT_ERROR, "Error (SM)" }, - { OFPT_ECHO_REQUEST, "Echo Request (SM)" }, - { OFPT_ECHO_REPLY, "Echo Reply (SM)" }, - { OFPT_VENDOR, "Vendor (SM)" }, - - /* Switch configuration messages. */ - { OFPT_FEATURES_REQUEST, "Features Request (CSM)" }, - { OFPT_FEATURES_REPLY, "Features Reply (CSM)" }, - { OFPT_GET_CONFIG_REQUEST, "Get Config Request (CSM)" }, - { OFPT_GET_CONFIG_REPLY, "Get Config Reply (CSM)" }, - { OFPT_SET_CONFIG, "Set Config (CSM)" }, - - /* Asynchronous messages. */ - { OFPT_PACKET_IN, "Packet In (AM)" }, - { OFPT_FLOW_REMOVED, "Flow Removed (AM)" }, - { OFPT_PORT_STATUS, "Port Status (AM)" }, - - /* Controller command messages. */ - { OFPT_PACKET_OUT, "Packet Out (CSM)" }, - { OFPT_FLOW_MOD, "Flow Mod (CSM)" }, - { OFPT_PORT_MOD, "Port Mod (CSM)" }, - - /* Statistics messages. */ - { OFPT_STATS_REQUEST, "Stats Request (CSM)" }, - { OFPT_STATS_REPLY, "Stats Reply (CSM)" }, - - /* Barrier messages. */ - { OFPT_BARRIER_REQUEST, "Barrier Request (CSM)" }, - { OFPT_BARRIER_REPLY, "Barrier Reply (CSM)" }, - - { OFPT_QUEUE_GET_CONFIG_REQUEST, "Get Queue Config Request (CSM)" }, - { OFPT_QUEUE_GET_CONFIG_REPLY, "Get Queue Config Reply (CSM)" }, - - { 0, NULL } -}; -#define OFP_TYPE_MAX_VALUE OFPT_QUEUE_GET_CONFIG_REPLY - -/** names from ofp_action_type */ -static const value_string names_ofp_action_type[] = { - { OFPAT_OUTPUT, "Output to switch port" }, - { OFPAT_SET_VLAN_VID, "Set the 802.1q VLAN id." }, - { OFPAT_SET_VLAN_PCP, "Set the 802.1q priority." }, - { OFPAT_STRIP_VLAN, "Strip the 802.1q header." }, - { OFPAT_SET_DL_SRC, "Ethernet source address" }, - { OFPAT_SET_DL_DST, "Ethernet destination address" }, - { OFPAT_SET_NW_SRC, "IP source address" }, - { OFPAT_SET_NW_DST, "IP destination address" }, - { OFPAT_SET_NW_TOS, "Set IP TOS field" }, - { OFPAT_SET_TP_SRC, "TCP/UDP source port" }, - { OFPAT_SET_TP_DST, "TCP/UDP destination port"}, - { OFPAT_ENQUEUE, "Enqueue to port queue" }, - { OFPAT_VENDOR, "Vendor-defined action"}, - { 0, NULL } -}; -#define NUM_ACTIONS_FLAGS 12 -#define NUM_PORT_CONFIG_FLAGS 7 -#define NUM_PORT_STATE_FLAGS 1 -#define NUM_PORT_FEATURES_FLAGS 12 -#define NUM_WILDCARDS 12 -#define NUM_CAPABILITIES_FLAGS 8 -#define NUM_FLOW_MOD_FLAGS 3 -#define NUM_SF_REPLY_FLAGS 1 - -/** yes/no for bitfields field */ -static const value_string names_choice[] = { - { 0, "No" }, - { 1, "Yes" }, - { 0, NULL } -}; - -/** wildcard or not for bitfields field */ -static const value_string wildcard_choice[] = { - { 0, "Exact" }, - { 1, "Wildcard" }, - { 0, NULL } -}; - -/** wildcard or not for bitfields field */ -static const value_string ts_wildcard_choice[] = { - { 0, "Exact only" }, - { 1, "Wildcard allowed" }, - { 0, NULL } -}; - -/** names from ofp_flow_mod_command */ -static const value_string names_flow_mod_command[] = { - { OFPFC_ADD, "New flow" }, - { OFPFC_MODIFY, "Modify all matching flows" }, - { OFPFC_MODIFY_STRICT, "Modify entry strictly matching wildcards" }, - { OFPFC_DELETE, "Delete all matching flows" }, - { OFPFC_DELETE_STRICT, "Delete entry strictly matching wildcards and priority" }, - { 0, NULL } -}; - -/** names of stats_types */ -static const value_string names_stats_types[] = { - { OFPST_DESC, "Description of this OpenFlow switch" }, - { OFPST_FLOW, "Individual flow statistics" }, - { OFPST_AGGREGATE, "Aggregate flow statistics" }, - { OFPST_TABLE, "Flow table statistics" }, - { OFPST_PORT, "Physical port statistics" }, - { OFPST_QUEUE, "Queue statistics" }, - { OFPST_VENDOR, "Vendor extension" }, - { 0, NULL } -}; - -/** names from ofp_flow_mod_command */ -static const value_string names_ofp_port_reason[] = { - { OFPPR_ADD, "The port was added" }, - { OFPPR_DELETE, "The port was removed" }, - { OFPPR_MODIFY, "Some attribute of the port has changed" }, - { 0, NULL } -}; - -/** names from ofp_packet_in_reason */ -static const value_string names_ofp_packet_in_reason[] = { - { OFPR_NO_MATCH, "No matching flow" }, - { OFPR_ACTION, "Action explicitly output to controller" }, - { 0, NULL } -}; - -/** names from ofp_flow_removed_reason */ -static const value_string names_ofp_flow_removed_reason[] = { - { OFPRR_IDLE_TIMEOUT, "Flow idle time exceeded idle_timeout" }, - { OFPRR_HARD_TIMEOUT, "Time exceeded hard_timeout" }, - { OFPRR_DELETE, "Evicted by a DELETE flow mod." }, - { 0, NULL } -}; - -/** names from ofp_flow_removed_reason */ -static const value_string names_ip_frag[] = { - { OFPC_FRAG_NORMAL, "No special handling for fragments." }, - { OFPC_FRAG_DROP, "Drop fragments." }, - { OFPC_FRAG_REASM, "Reassemble (only if OFPC_IP_REASM set)" }, - { 0, NULL } -}; - -/** names from ofp_error_type */ -static const value_string names_ofp_error_type_reason[] = { - { OFPET_HELLO_FAILED, "Hello protocol failed" }, - { OFPET_BAD_REQUEST, "Request was not understood" }, - { OFPET_BAD_ACTION, "Error in action description" }, - { OFPET_FLOW_MOD_FAILED, "Problem modifying flow entry" }, - { OFPET_PORT_MOD_FAILED, "Port mod request failed" }, - { OFPET_QUEUE_OP_FAILED, "Problem during queue operation" }, - { 0, NULL } -}; - -static const value_string names_ofp_packet_queue_property_type[] = { - { OFPQT_NONE, "No-op Property" }, - { OFPQT_MIN_RATE, "Min Rate Queue" }, - { 0, NULL } -}; - - -/** Address masks */ -static const value_string addr_mask[] = { - { 0, "/32" }, - { 1, "/31" }, - { 2, "/30" }, - { 3, "/29" }, - { 4, "/28" }, - { 5, "/27" }, - { 6, "/26" }, - { 7, "/25" }, - { 8, "/24" }, - { 9, "/23" }, - { 10, "/22" }, - { 11, "/21" }, - { 12, "/20" }, - { 13, "/19" }, - { 14, "/18" }, - { 15, "/17" }, - { 16, "/16" }, - { 17, "/15" }, - { 18, "/14" }, - { 19, "/13" }, - { 20, "/12" }, - { 21, "/11" }, - { 22, "/10" }, - { 23, "/9" }, - { 24, "/8" }, - { 25, "/7" }, - { 26, "/6" }, - { 27, "/5" }, - { 28, "/4" }, - { 29, "/3" }, - { 30, "/2" }, - { 31, "/1" }, - { 32, "/0" }, - { 63, "/0" }, - { 0, NULL } -}; - -/** Address masks */ -static const value_string ts_addr_mask[] = { - { 0, "Exact only" }, - { 63, "Wildcard allowed" }, - { 0, NULL } -}; - -/** Switch config frag values */ -static const value_string sc_frag_choices[] = { - { 0, "No special fragment handling" }, - { 1, "Drop fragments" }, - { 2, "Reassemble (only if OFPC_IP_REASM set)" }, - { 0, NULL } -}; - - -/* Error strings for the various error types */ -static const gchar *hello_failed_err_str[] = {"No compatible version", - "Permissions error"}; - -#define N_HELLOFAILED (sizeof hello_failed_err_str / sizeof hello_failed_err_str[0]) - -static const gchar *bad_request_err_str[] = {"ofp_header.version not supported", - "ofp_header.type not supported", - "ofp_stats_request.type not supported", - "Vendor not supported (in ofp_vendor or ofp_stats_request or ofp_stats_reply)", - "Vendor subtype not supported", - "Permissions error", - "Wrong request length for type", - "Specified buffer has already been used", - "Specified buffer does not exist"}; - -#define N_BADREQUEST (sizeof bad_request_err_str / sizeof bad_request_err_str[0]) - -static const gchar *bad_action_err_str[] = {"Unknown action type", - "Length problem in actions", - "Unknown vendor id specified", - "Unknown action type for vendor id", - "Problem validating output action", - "Bad action argument", - "Permissions error", - "Can't handle this many actions", - "Problem validating output queue"}; - -#define N_BADACTION (sizeof bad_action_err_str / sizeof bad_action_err_str[0]) - -static const gchar *flow_mod_failed_err_str[] = {"Flow not added because of full tables", - "Flow not added because of conflicting entry in tables", - "Permissions error", - "Flow not added because of non-zero idle/hard timeout", - "Unknown command", - "Unsupported action list - cannot process in the order specified"}; - -#define N_FLOWMODFAILED (sizeof flow_mod_failed_err_str / sizeof flow_mod_failed_err_str[0]) - -static const gchar *port_mod_failed_err_str[] = {"Specified port does not exist", - "Specified hardware address is wrong"}; - -#define N_PORTMODFAILED (sizeof port_mod_failed_err_str / sizeof port_mod_failed_err_str[0]) - -static const gchar *queue_op_failed_err_str[] = {"Parent port does not exist", - "queue does not exist", - "Permissions error"}; - -#define N_QUEUEOPFAILED (sizeof queue_op_failed_err_str / sizeof queue_op_failed_err_str[0]) - -/* ICMP definitions from wireshark source: epan/dissectors/packet-ip.c */ -/* ICMP definitions */ - -#define ICMP_ECHOREPLY 0 -#define ICMP_UNREACH 3 -#define ICMP_SOURCEQUENCH 4 -#define ICMP_REDIRECT 5 -#define ICMP_ECHO 8 -#define ICMP_RTRADVERT 9 -#define ICMP_RTRSOLICIT 10 -#define ICMP_TIMXCEED 11 -#define ICMP_PARAMPROB 12 -#define ICMP_TSTAMP 13 -#define ICMP_TSTAMPREPLY 14 -#define ICMP_IREQ 15 -#define ICMP_IREQREPLY 16 -#define ICMP_MASKREQ 17 -#define ICMP_MASKREPLY 18 - -/* ICMP UNREACHABLE */ - -#define ICMP_NET_UNREACH 0 /* Network Unreachable */ -#define ICMP_HOST_UNREACH 1 /* Host Unreachable */ -#define ICMP_PROT_UNREACH 2 /* Protocol Unreachable */ -#define ICMP_PORT_UNREACH 3 /* Port Unreachable */ -#define ICMP_FRAG_NEEDED 4 /* Fragmentation Needed/DF set */ -#define ICMP_SR_FAILED 5 /* Source Route failed */ -#define ICMP_NET_UNKNOWN 6 -#define ICMP_HOST_UNKNOWN 7 -#define ICMP_HOST_ISOLATED 8 -#define ICMP_NET_ANO 9 -#define ICMP_HOST_ANO 10 -#define ICMP_NET_UNR_TOS 11 -#define ICMP_HOST_UNR_TOS 12 -#define ICMP_PKT_FILTERED 13 /* Packet filtered */ -#define ICMP_PREC_VIOLATION 14 /* Precedence violation */ -#define ICMP_PREC_CUTOFF 15 /* Precedence cut off */ - -static const gchar *unreach_str[] = {"Network unreachable", - "Host unreachable", - "Protocol unreachable", - "Port unreachable", - "Fragmentation needed", - "Source route failed", - "Destination network unknown", - "Destination host unknown", - "Source host isolated", - "Network administratively prohibited", - "Host administratively prohibited", - "Network unreachable for TOS", - "Host unreachable for TOS", - "Communication administratively filtered", - "Host precedence violation", - "Precedence cutoff in effect"}; - -#define N_UNREACH (sizeof unreach_str / sizeof unreach_str[0]) - -static const gchar *redir_str[] = {"Redirect for network", - "Redirect for host", - "Redirect for TOS and network", - "Redirect for TOS and host"}; - -#define N_REDIRECT (sizeof redir_str / sizeof redir_str[0]) - -static const gchar *ttl_str[] = {"Time to live exceeded in transit", - "Fragment reassembly time exceeded"}; - -#define N_TIMXCEED (sizeof ttl_str / sizeof ttl_str[0]) - -static const gchar *par_str[] = {"IP header bad", "Required option missing"}; - -#define N_PARAMPROB (sizeof par_str / sizeof par_str[0]) - - -/* ARP definitions from wireshark source: epan/dissectors/packet-arp.c */ -/* ARP / RARP structs and definitions */ -#ifndef ARPOP_REQUEST -#define ARPOP_REQUEST 1 /* ARP request. */ -#endif -#ifndef ARPOP_REPLY -#define ARPOP_REPLY 2 /* ARP reply. */ -#endif -/* Some OSes have different names, or don't define these at all */ -#ifndef ARPOP_RREQUEST -#define ARPOP_RREQUEST 3 /* RARP request. */ -#endif -#ifndef ARPOP_RREPLY -#define ARPOP_RREPLY 4 /* RARP reply. */ -#endif -#ifndef ARPOP_IREQUEST -#define ARPOP_IREQUEST 8 /* Inverse ARP (RFC 1293) request. */ -#endif -#ifndef ARPOP_IREPLY -#define ARPOP_IREPLY 9 /* Inverse ARP reply. */ -#endif -#ifndef ATMARPOP_NAK -#define ATMARPOP_NAK 10 /* ATMARP NAK. */ -#endif - -static const value_string names_arp_opcode[] = { - {ARPOP_REQUEST, "request" }, - {ARPOP_REPLY, "reply" }, - {ARPOP_RREQUEST, "reverse request"}, - {ARPOP_RREPLY, "reverse reply" }, - {ARPOP_IREQUEST, "inverse request"}, - {ARPOP_IREPLY, "inverse reply" }, - {0, NULL } }; - -/* These variables are used to hold the IDs of our fields; they are - * set when we call proto_register_field_array() in proto_register_openflow() - */ -static gint ofp = -1; -static gint ofp_pad = -1; -static gint ofp_port = -1; - -/* OpenFlow Header */ -static gint ofp_header = -1; -static gint ofp_header_version = -1; -static gint ofp_header_type = -1; -static gint ofp_header_length = -1; -static gint ofp_header_xid = -1; -static gint ofp_header_warn_ver = -1; -static gint ofp_header_warn_type = -1; - -/* Common Structures */ -static gint ofp_phy_port = -1; -static gint ofp_phy_port_port_no = -1; -static gint ofp_phy_port_hw_addr = -1; -static gint ofp_phy_port_name = -1; -static gint ofp_phy_port_config_hdr = -1; -static gint ofp_phy_port_config[NUM_PORT_CONFIG_FLAGS]; -static gint ofp_phy_port_state_hdr = -1; -// the following array is EVIL!!!!! do not use, or a curse upon your family. -static gint ofp_phy_port_state[NUM_PORT_STATE_FLAGS]; -// seriously, don't use this bit. -static gint ofp_phy_port_state_not_evil = -1; -static gint ofp_phy_port_state_stp_state = -1; -static gint ofp_phy_port_curr_hdr = -1; -static gint ofp_phy_port_curr[NUM_PORT_FEATURES_FLAGS]; -static gint ofp_phy_port_advertised_hdr = -1; -static gint ofp_phy_port_advertised[NUM_PORT_FEATURES_FLAGS]; -static gint ofp_phy_port_supported_hdr = -1; -static gint ofp_phy_port_supported[NUM_PORT_FEATURES_FLAGS]; -static gint ofp_phy_port_peer_hdr = -1; -static gint ofp_phy_port_peer[NUM_PORT_FEATURES_FLAGS]; - -static gint ofp_match = -1; -static gint ofp_match_wildcards_hdr = -1; -static gint ofp_match_wildcards[NUM_WILDCARDS]; -static gint ofp_match_in_port = -1; -static gint ofp_match_dl_src = -1; -static gint ofp_match_dl_dst = -1; -static gint ofp_match_dl_vlan = -1; -static gint ofp_match_dl_vlan_pcp = -1; -static gint ofp_match_dl_type = -1; -static gint ofp_match_nw_src = -1; -static gint ofp_match_nw_dst = -1; -static gint ofp_match_nw_tos = -1; -static gint ofp_match_nw_proto = -1; -static gint ofp_match_arp_opcode= -1; -static gint ofp_match_tp_src = -1; -static gint ofp_match_tp_dst = -1; -static gint ofp_match_icmp_type = -1; -static gint ofp_match_icmp_code = -1; -static gint ofp_match_nw_src_mask_bits = -1; -static gint ofp_match_nw_dst_mask_bits = -1; - -static gint ofp_action = -1; -static gint ofp_action_type = -1; -static gint ofp_action_len = -1; -static gint ofp_action_vlan_vid = -1; -static gint ofp_action_vlan_pcp = -1; -static gint ofp_action_dl_addr = -1; -static gint ofp_action_nw_addr = -1; -static gint ofp_action_nw_tos = -1; -static gint ofp_action_tp_port = -1; -static gint ofp_action_vendor = -1; -static gint ofp_action_unknown = -1; -static gint ofp_action_warn = -1; -static gint ofp_action_num = -1; - -/* type: ofp_action_output */ -static gint ofp_action_output = -1; -static gint ofp_action_output_port = -1; -static gint ofp_action_output_max_len = -1; - -/* type: ofp_action_enqueue */ -static gint ofp_action_enqueue = -1; -static gint ofp_action_enqueue_port_no = -1; -static gint ofp_action_enqueue_queue_id = -1; - -/* Controller/Switch Messages */ -static gint ofp_switch_features = -1; -static gint ofp_switch_features_datapath_id = -1; -static gint ofp_switch_features_n_buffers = -1; -static gint ofp_switch_features_n_tables = -1; -static gint ofp_switch_features_capabilities_hdr = -1; -static gint ofp_switch_features_capabilities[NUM_CAPABILITIES_FLAGS]; -static gint ofp_switch_features_actions_hdr = -1; -static gint ofp_switch_features_actions[NUM_ACTIONS_FLAGS]; -static gint ofp_switch_features_actions_warn = -1; -// are these two necessary? -static gint ofp_switch_features_ports_hdr = -1; -static gint ofp_switch_features_ports_num = -1; -static gint ofp_switch_features_ports_warn = -1; - -static gint ofp_switch_config = -1; -static gint ofp_switch_config_flags_hdr = -1; -static gint ofp_switch_config_flags_ip_frag = -1; -static gint ofp_switch_config_miss_send_len = -1; - -static gint ofp_queue_get_config_request = -1; -static gint ofp_queue_get_config_request_port_no = -1; - -// there is no limit at the no of queues/port. 1024 is safe for now. -static gint ofp_queue_get_config_reply = -1; -static gint ofp_queue_get_config_reply_port_no = -1; -static gint ofp_queue_get_config_reply_queues_hdr = -1; -static gint ofp_queue_get_config_reply_queues_num = -1; - -static gint ofp_packet_queue = -1; -static gint ofp_packet_queue_queue_id = -1; -static gint ofp_packet_queue_len = -1; -static gint ofp_packet_queue_warn = -1; - -static gint ofp_packet_queue_property = -1; -static gint ofp_packet_queue_property_len = -1; -static gint ofp_packet_queue_property_type = -1; -static gint ofp_packet_queue_property_rate = -1; -static gint ofp_packet_queue_properties_hdr = -1; -static gint ofp_packet_queue_properties_num = -1; -static gint ofp_packet_queue_property_unknown = -1; -static gint ofp_packet_queue_property_warn = -1; - -static gint ofp_flow_mod = -1; -/* field: ofp_match */ -static gint ofp_flow_mod_cookie = -1; -static gint ofp_flow_mod_command = -1; -static gint ofp_flow_mod_idle_timeout = -1; -static gint ofp_flow_mod_hard_timeout = -1; -static gint ofp_flow_mod_priority = -1; -static gint ofp_flow_mod_buffer_id = -1; -static gint ofp_flow_mod_out_port = -1; -static gint ofp_flow_mod_flags[NUM_FLOW_MOD_FLAGS]; - -static gint ofp_port_mod = -1; -static gint ofp_port_mod_port_no = -1; -static gint ofp_port_mod_hw_addr = -1; -static gint ofp_port_mod_config_hdr = -1; -static gint ofp_port_mod_config[NUM_PORT_CONFIG_FLAGS]; -static gint ofp_port_mod_mask_hdr = -1; -static gint ofp_port_mod_mask[NUM_PORT_CONFIG_FLAGS]; -static gint ofp_port_mod_advertise_hdr = -1; -static gint ofp_port_mod_advertise[NUM_PORT_FEATURES_FLAGS]; - -static gint ofp_stats_request = -1; -static gint ofp_stats_request_type = -1; -static gint ofp_stats_request_flags = -1; -static gint ofp_stats_request_body = -1; - -static gint ofp_stats_reply = -1; -static gint ofp_stats_reply_type = -1; -static gint ofp_stats_reply_flags = -1; -static gint ofp_stats_reply_flag[NUM_SF_REPLY_FLAGS]; -static gint ofp_stats_reply_body = -1; - -static gint ofp_desc_stats = -1; -static gint ofp_desc_stats_mfr_desc = -1; -static gint ofp_desc_stats_hw_desc = -1; -static gint ofp_desc_stats_sw_desc = -1; -static gint ofp_desc_stats_dp_desc = -1; -static gint ofp_desc_stats_serial_num = -1; - -static gint ofp_flow_stats_request = -1; -/* field: ofp_match */ -static gint ofp_flow_stats_request_table_id = -1; -static gint ofp_flow_stats_request_out_port = -1; - -static gint ofp_flow_stats_reply = -1; -/* length won't be put in the tree */ -static gint ofp_flow_stats_reply_table_id = -1; -/* field: ofp_match */ -static gint ofp_flow_stats_reply_duration_sec = -1; -static gint ofp_flow_stats_reply_duration_nsec = -1; -static gint ofp_flow_stats_reply_cookie = -1; -static gint ofp_flow_stats_reply_priority = -1; -static gint ofp_flow_stats_reply_idle_timeout = -1; -static gint ofp_flow_stats_reply_hard_timeout = -1; -static gint ofp_flow_stats_reply_packet_count = -1; -static gint ofp_flow_stats_reply_byte_count = -1; -/* field: ofp_actions */ - -static gint ofp_aggr_stats_request = -1; -/* field: ofp_match */ -static gint ofp_aggr_stats_request_table_id = -1; - -static gint ofp_aggr_stats_reply = -1; -static gint ofp_aggr_stats_reply_packet_count = -1; -static gint ofp_aggr_stats_reply_byte_count = -1; -static gint ofp_aggr_stats_reply_flow_count = -1; - -static gint ofp_table_stats = -1; -static gint ofp_table_stats_table_id = -1; -static gint ofp_table_stats_name = -1; -static gint ofp_table_stats_wildcards_hdr = -1; -static gint ofp_table_stats_wildcards[NUM_WILDCARDS]; -static gint ofp_table_stats_max_entries = -1; -static gint ofp_table_stats_active_count = -1; -static gint ofp_table_stats_lookup_count = -1; -static gint ofp_table_stats_matched_count = -1; - -static gint ofp_port_stats_request = -1; -static gint ofp_port_stats_request_port_no = -1; -static gint ofp_port_stats = -1; -static gint ofp_port_stats_port_no = -1; -static gint ofp_port_stats_rx_packets = -1; -static gint ofp_port_stats_tx_packets = -1; -static gint ofp_port_stats_rx_bytes = -1; -static gint ofp_port_stats_tx_bytes = -1; -static gint ofp_port_stats_rx_dropped = -1; -static gint ofp_port_stats_tx_dropped = -1; -static gint ofp_port_stats_rx_errors = -1; -static gint ofp_port_stats_tx_errors = -1; -static gint ofp_port_stats_rx_frame_err = -1; -static gint ofp_port_stats_rx_over_err = -1; -static gint ofp_port_stats_rx_crc_err = -1; -static gint ofp_port_stats_collisions = -1; - -static gint ofp_queue_stats_request = -1; - -static gint ofp_queue_stats = -1; -static gint ofp_queue_stats_port_no = -1; -static gint ofp_queue_stats_queue_id = -1; -static gint ofp_queue_stats_tx_bytes = -1; -static gint ofp_queue_stats_tx_packets = -1; -static gint ofp_queue_stats_tx_errors = -1; - -static gint ofp_vendor_stats = -1; -static gint ofp_vendor_stats_vendor = -1; -static gint ofp_vendor_stats_body = -1; - -static gint ofp_packet_out = -1; -static gint ofp_packet_out_buffer_id = -1; -static gint ofp_packet_out_in_port = -1; -static gint ofp_packet_out_actions_len = -1; -static gint ofp_packet_out_actions_hdr = -1; -static gint ofp_packet_out_data_hdr = -1; - -/* Asynchronous Messages */ -static gint ofp_packet_in = -1; -static gint ofp_packet_in_buffer_id = -1; -static gint ofp_packet_in_total_len = -1; -static gint ofp_packet_in_in_port = -1; -static gint ofp_packet_in_reason = -1; -static gint ofp_packet_in_data_hdr = -1; - -static gint ofp_flow_removed = -1; -/* field: ofp_match */ -static gint ofp_flow_removed_cookie = -1; -static gint ofp_flow_removed_priority = -1; -static gint ofp_flow_removed_reason = -1; -static gint ofp_flow_removed_duration_sec = -1; -static gint ofp_flow_removed_duration_nsec = -1; -static gint ofp_flow_removed_idle_timeout = -1; -static gint ofp_flow_removed_packet_count = -1; -static gint ofp_flow_removed_byte_count = -1; - -static gint ofp_port_status = -1; -static gint ofp_port_status_reason = -1; -/* field: ofp_phy_port desc */ - -static gint ofp_error_msg = -1; -static gint ofp_error_msg_type = -1; -static gint ofp_error_msg_code = -1; -static gint ofp_error_msg_data = -1; -static gint ofp_error_msg_data_str = -1; - -static gint ofp_echo = -1; -static gint ofp_vendor = -1; - -/* These are the ids of the subtrees that we may be creating */ -static gint ett_ofp = -1; - -/* Open Flow Header */ -static gint ett_ofp_header = -1; - -/* Common Structures */ -static gint ett_ofp_phy_port = -1; -static gint ett_ofp_phy_port_config_hdr = -1; -static gint ett_ofp_phy_port_state_hdr = -1; -static gint ett_ofp_phy_port_curr_hdr = -1; -static gint ett_ofp_phy_port_advertised_hdr = -1; -static gint ett_ofp_phy_port_supported_hdr = -1; -static gint ett_ofp_phy_port_peer_hdr = -1; -static gint ett_ofp_match = -1; -static gint ett_ofp_match_wildcards_hdr = -1; -static gint ett_ofp_action = -1; -static gint ett_ofp_action_output = -1; -static gint ett_ofp_action_enqueue = -1; -static gint ett_ofp_packet_queue_root = -1; -static gint ett_ofp_packet_queue = -1; -static gint ett_ofp_packet_queue_property = -1; -static gint ett_ofp_packet_queue_properties_hdr = -1; - -/* Controller/Switch Messages */ -static gint ett_ofp_switch_features = -1; -static gint ett_ofp_switch_features_capabilities_hdr = -1; -static gint ett_ofp_switch_features_actions_hdr = -1; -static gint ett_ofp_switch_features_ports_hdr = -1; -static gint ett_ofp_switch_config = -1; -static gint ett_ofp_switch_config_flags_hdr = -1; -static gint ett_ofp_flow_mod = -1; -static gint ett_ofp_flow_mod_flags_hdr = -1; -static gint ett_ofp_port_mod = -1; -static gint ett_ofp_port_mod_config_hdr = -1; -static gint ett_ofp_port_mod_mask_hdr = -1; -static gint ett_ofp_port_mod_advertise_hdr = -1; - -static gint ett_ofp_queue_get_config_request = -1; -static gint ett_ofp_queue_get_config_reply = -1; -static gint ett_ofp_queue_get_config_reply_queues_hdr = -1; - -static gint ett_ofp_stats_request = -1; -static gint ett_ofp_stats_reply = -1; -static gint ett_ofp_stats_reply_flags = -1; -static gint ett_ofp_desc_stats = -1; -static gint ett_ofp_flow_stats_request = -1; -static gint ett_ofp_flow_stats_reply = -1; -static gint ett_ofp_aggr_stats_request = -1; -static gint ett_ofp_aggr_stats_reply = -1; -static gint ett_ofp_table_stats = -1; -static gint ett_ofp_port_stats_request = -1; -static gint ett_ofp_queue_stats_request = -1; -static gint ett_ofp_port_stats = -1; -static gint ett_ofp_queue_stats = -1; -static gint ett_ofp_vendor_stats = -1; -static gint ett_ofp_packet_out = -1; -static gint ett_ofp_packet_out_actions_hdr = -1; -static gint ett_ofp_packet_out_data_hdr = -1; - -/* Asynchronous Messages */ -static gint ett_ofp_packet_in = -1; -static gint ett_ofp_packet_in_data_hdr = -1; -static gint ett_ofp_flow_removed = -1; -static gint ett_ofp_port_status = -1; -static gint ett_ofp_error_msg = -1; -static gint ett_ofp_error_msg_data = -1; - -void proto_reg_handoff_openflow() -{ - openflow_handle = create_dissector_handle(dissect_openflow, proto_openflow); - dissector_add(TCP_PORT_FILTER, global_openflow_proto, openflow_handle); -} - -#define NO_STRINGS NULL -#define NO_MASK 0x0 - -/** Returns newly allocated string with two spaces in front of str. */ -static inline char* indent( char* str ) { - char* ret = malloc( strlen(str) + 3 ); - ret[0] = ' '; - ret[1] = ' '; - memcpy( &ret[2], str, strlen(str) + 1 ); - return ret; -} - -void proto_register_openflow() -{ - data_ethernet = find_dissector("eth"); - - /* initialize uninitialized header fields */ - int i; - for( i=0; i= 0)) - return names_ofp_type[type].strptr; - else { - snprintf( str_unknown, 17, "Unknown Type %u", type ); - return str_unknown; - } -} - -/** - * Adds "hf" to "tree" starting at "offset" into "tvb" and using "length" - * bytes. offset is incremented by length. - */ -static void add_child( proto_item* tree, gint hf, tvbuff_t *tvb, guint32* offset, guint32 len ) { - proto_tree_add_item( tree, hf, tvb, *offset, len, FALSE ); - *offset += len; -} - -/** - * Adds "hf" to "tree" starting at "offset" into "tvb" and using "length" - * bytes. offset is incremented by length. The specified string is used as the - * field's display value. - */ -static void add_child_str(proto_item* tree, gint hf, tvbuff_t *tvb, guint32* offset, guint32 len, const char* str) { - proto_tree_add_string(tree, hf, tvb, *offset, len, str); - *offset += len; -} - -/** - * Adds "hf" to "tree" starting at "offset" into "tvb" and using "length" - * bytes. The specified string is used as the - * field's display value. - */ -static void add_child_str_const(proto_item* tree, gint hf, tvbuff_t *tvb, guint32 offset, guint32 len, const char* str) { - proto_tree_add_string(tree, hf, tvb, offset, len, str); -} - - -/** - * Adds "hf" to "tree" starting at "offset" into "tvb" and using "length" bytes. - */ -static void add_child_const( proto_item* tree, gint hf, tvbuff_t *tvb, guint32 offset, guint32 len ) { - proto_tree_add_item( tree, hf, tvb, offset, len, FALSE ); -} - -/** returns the length of a PDU which starts at the specified offset in tvb. */ -static guint get_openflow_message_len(packet_info *pinfo, tvbuff_t *tvb, int offset) { - return (guint)tvb_get_ntohs(tvb, offset+2); /* length is at offset 2 in the header */ -} - -static void dissect_pad(proto_tree* tree, guint32 *offset, guint pad_byte_count) { -#if SHOW_PADDING - guint i; - for( i=0; i 0) { - port_item = proto_tree_add_item(tree, ofp_phy_port, tvb, *offset, sizeof(struct ofp_phy_port), FALSE); - port_tree = proto_item_add_subtree(port_item, ett_ofp_phy_port); - - dissect_port( port_tree, ofp_phy_port_port_no, tvb, offset ); - add_child( port_tree, ofp_phy_port_hw_addr, tvb, offset, OFP_ETH_ALEN ); - add_child( port_tree, ofp_phy_port_name, tvb, offset, OFP_MAX_PORT_NAME_LEN ); - - /* config */ - config_item = proto_tree_add_item(port_tree, ofp_phy_port_config_hdr, tvb, *offset, 4, FALSE); - config_tree = proto_item_add_subtree(config_item, ett_ofp_phy_port_config_hdr); - for(i=0; iname, get_tcp_port(port), port); - - *offset += 2; -} - -/* Based on: dissect_icmp from wireshark: epan/dissectors/packet-ip.c */ -static void dissect_icmp_type_code_match(proto_tree* tree, tvbuff_t *tvb, guint32 *offset, gint show_type, gint show_code) -{ - guint16 icmp_type; - guint16 icmp_code; - const gchar *type_str, *code_str; - - type_str=""; - code_str=""; - - /* Get the ICMP type/code */ - icmp_type = tvb_get_ntohs(tvb, *offset); - icmp_code = tvb_get_ntohs(tvb, *offset + 2); - - /* Get string representations of the ICMP types/codes */ - switch (icmp_type) { - case ICMP_ECHOREPLY: - type_str="Echo (ping) reply"; - break; - case ICMP_UNREACH: - type_str="Destination unreachable"; - if (icmp_code < N_UNREACH) { - code_str = unreach_str[icmp_code]; - } else { - code_str = "Unknown - error?"; - } - break; - case ICMP_SOURCEQUENCH: - type_str="Source quench (flow control)"; - break; - case ICMP_REDIRECT: - type_str="Redirect"; - if (icmp_code < N_REDIRECT) { - code_str = redir_str[icmp_code]; - } else { - code_str = "Unknown - error?"; - } - break; - case ICMP_ECHO: - type_str="Echo (ping) request"; - break; - case ICMP_RTRADVERT: - switch (icmp_code) { - case 0: /* Mobile-Ip */ - case 16: /* Mobile-Ip */ - type_str="Mobile IP Advertisement"; - break; - default: - type_str="Router advertisement"; - break; - } /* switch icmp_code */ - break; - case ICMP_RTRSOLICIT: - type_str="Router solicitation"; - break; - case ICMP_TIMXCEED: - type_str="Time-to-live exceeded"; - if (icmp_code < N_TIMXCEED) { - code_str = ttl_str[icmp_code]; - } else { - code_str = "Unknown - error?"; - } - break; - case ICMP_PARAMPROB: - type_str="Parameter problem"; - if (icmp_code < N_PARAMPROB) { - code_str = par_str[icmp_code]; - } else { - code_str = "Unknown - error?"; - } - break; - case ICMP_TSTAMP: - type_str="Timestamp request"; - break; - case ICMP_TSTAMPREPLY: - type_str="Timestamp reply"; - break; - case ICMP_IREQ: - type_str="Information request"; - break; - case ICMP_IREQREPLY: - type_str="Information reply"; - break; - case ICMP_MASKREQ: - type_str="Address mask request"; - break; - case ICMP_MASKREPLY: - type_str="Address mask reply"; - break; - default: - type_str="Unknown ICMP (obsolete or malformed?)"; - break; - } - - if (show_type) - proto_tree_add_uint_format(tree, ofp_match_icmp_type, tvb, *offset, 2, - icmp_type, - "ICMP Type: %u (%s)", - icmp_type, type_str); - if (show_code) - proto_tree_add_uint_format(tree, ofp_match_icmp_code, tvb, *offset, 2, - icmp_code, - "ICMP Code: %u (%s)", - icmp_code, code_str); - - *offset += 4; -} - -static void dissect_match(proto_tree* tree, proto_item* item, tvbuff_t *tvb, packet_info *pinfo, guint32 *offset) -{ - proto_item *match_item = proto_tree_add_item(tree, ofp_match, tvb, *offset, sizeof(struct ofp_match), FALSE); - proto_tree *match_tree = proto_item_add_subtree(match_item, ett_ofp_match); - - /* save wildcards field for later */ - guint32 wildcards = tvb_get_ntohl( tvb, *offset ); - - dissect_wildcards(match_tree, match_item, tvb, pinfo, offset, ofp_match_wildcards); - - /* show only items whose corresponding wildcard bit is not set */ - if( ~wildcards & OFPFW_IN_PORT ) - dissect_port(match_tree, ofp_match_in_port, tvb, offset); - else - *offset += 2; - - if( ~wildcards & OFPFW_DL_SRC ) - add_child(match_tree, ofp_match_dl_src, tvb, offset, 6); - else - *offset += 6; - - if( ~wildcards & OFPFW_DL_DST ) - add_child(match_tree, ofp_match_dl_dst, tvb, offset, 6); - else - *offset += 6; - - if( ~wildcards & OFPFW_DL_VLAN ) - add_child(match_tree, ofp_match_dl_vlan, tvb, offset, 2); - else - *offset += 2; - - if( ~wildcards & OFPFW_DL_VLAN_PCP ) - add_child(match_tree, ofp_match_dl_vlan_pcp, tvb, offset, 1); - else - *offset += 1; - - dissect_pad(match_tree, offset, 1); - - /* Save DL type for later */ - guint16 dl_type = tvb_get_ntohs( tvb, *offset); - - if( ~wildcards & OFPFW_DL_TYPE ) - dissect_dl_type(match_tree, ofp_match_dl_type, tvb, offset); - else - *offset += 2; - - if( ~wildcards & OFPFW_NW_TOS ) - add_child(match_tree, ofp_match_nw_tos, tvb, offset, 1); - else - *offset += 1; - - /* Save NW proto for later */ - guint8 nw_proto = tvb_get_guint8( tvb, *offset); - - /* Custom handling for ARP packets vs non-ARP packets */ - if ( dl_type == ETHERTYPE_ARP ) - add_child(match_tree, ofp_match_arp_opcode, tvb, offset, 1); - else if( ~wildcards & OFPFW_NW_PROTO ) - dissect_nw_proto(match_tree, ofp_match_nw_proto, tvb, offset); - else - *offset += 1; - - dissect_pad(match_tree, offset, 2); - - if( ~wildcards & OFPFW_NW_SRC_MASK ) - add_child(match_tree, ofp_match_nw_src, tvb, offset, 4); - else - *offset += 4; - - if( ~wildcards & OFPFW_NW_DST_MASK ) - add_child(match_tree, ofp_match_nw_dst, tvb, offset, 4); - else - *offset += 4; - - /* Display either ICMP type/code or TCP/UDP ports */ - if( dl_type == ETHERTYPE_IP && nw_proto == IP_PROTO_ICMP) { - dissect_icmp_type_code_match(match_tree, tvb, offset, - ~wildcards & OFPFW_TP_SRC, - ~wildcards & OFPFW_TP_DST ); - } - else { - if( ~wildcards & OFPFW_TP_SRC ) - dissect_tp_port(match_tree, ofp_match_tp_src, tvb, offset); - else - *offset += 2; - - if( ~wildcards & OFPFW_TP_DST ) - dissect_tp_port(match_tree, ofp_match_tp_dst, tvb, offset); - else - *offset += 2; - } -} - -static void dissect_action_output(proto_tree* tree, tvbuff_t *tvb, guint32 *offset) -{ - /* add the output port */ - dissect_port( tree, ofp_action_output_port, tvb, offset ); - - /* determine the maximum number of bytes to send (0 => no limit) */ - guint16 max_len = tvb_get_ntohs( tvb, *offset ); - char str[11]; - snprintf( str, 11, "%u", max_len ); - add_child_str( tree, ofp_action_output_max_len, tvb, offset, 2, str ); -} - -static void dissect_action_enqueue(proto_tree* tree, tvbuff_t *tvb, guint32 *offset) -{ - /* add the output port */ - dissect_port( tree, ofp_action_enqueue_port_no, tvb, offset ); - dissect_pad(tree, offset, 6); - dissect_queue_id(tree, ofp_action_enqueue_queue_id, tvb, offset); -} - - -/** returns the number of bytes dissected (-1 if an unknown action type is - * encountered; and 8/16 for all other actions as of 0x96) */ -static gint dissect_action(proto_tree* tree, proto_item* item, tvbuff_t *tvb, packet_info *pinfo, guint32 *offset) -{ - guint32 offset_start = *offset; - guint16 type = tvb_get_ntohs( tvb, *offset ); - guint16 len = tvb_get_ntohs( tvb, *offset + 2); - - proto_item *action_item = proto_tree_add_item(tree, ofp_action, tvb, *offset, len, FALSE); - proto_tree *action_tree = proto_item_add_subtree(action_item, ett_ofp_action); - - if (!(len == 8 || len == 16)) { - add_child_str(action_tree, ofp_action_unknown, tvb, offset, len, "Invalid Action Length"); - return -1; - } - - add_child( action_tree, ofp_action_type, tvb, offset, 2 ); - add_child( action_tree, ofp_action_len, tvb, offset, 2 ); - - switch( type ) { - case OFPAT_OUTPUT: - dissect_action_output(action_tree, tvb, offset); - break; - - case OFPAT_SET_VLAN_VID: - add_child( action_tree, ofp_action_vlan_vid, tvb, offset, 2 ); - dissect_pad(action_tree, offset, 2); - break; - - case OFPAT_SET_VLAN_PCP: - add_child( action_tree, ofp_action_vlan_pcp, tvb, offset, 1 ); - dissect_pad(action_tree, offset, 3); - break; - - case OFPAT_STRIP_VLAN: - add_child( action_tree, ofp_action_unknown, tvb, offset, 0 ); - dissect_pad(action_tree, offset, 4); - break; - - case OFPAT_SET_DL_SRC: - case OFPAT_SET_DL_DST: - add_child(action_tree, ofp_action_dl_addr, tvb, offset, 6 ); - dissect_pad(action_tree, offset, 6); - break; - - case OFPAT_SET_NW_SRC: - case OFPAT_SET_NW_DST: - add_child( action_tree, ofp_action_nw_addr, tvb, offset, 4 ); - break; - - case OFPAT_SET_NW_TOS: - add_child( action_tree, ofp_action_nw_tos, tvb, offset, 1); - dissect_pad(action_tree, offset, 3); - break; - - case OFPAT_SET_TP_SRC: - case OFPAT_SET_TP_DST: - add_child( action_tree, ofp_action_tp_port, tvb, offset, 2 ); - dissect_pad(action_tree, offset, 2); - break; - - case OFPAT_ENQUEUE: - dissect_action_enqueue(action_tree, tvb, offset); - break; - - default: - add_child( action_tree, ofp_action_unknown, tvb, offset, 0 ); - return -1; - } - - /* return the number of bytes which were consumed */ - return *offset - offset_start; -} - -static void dissect_action_array(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint len, guint offset) -{ - guint total_len = len - offset; - - proto_item* action_item = proto_tree_add_item(tree, ofp_action_output, tvb, offset, total_len, FALSE); - proto_tree* action_tree = proto_item_add_subtree(action_item, ett_ofp_action_output); - - if( total_len == 0 ) - add_child_str(action_tree, ofp_action_warn, tvb, &offset, 0, "No actions were specified"); - else if( offset > len ) { - /* not enough bytes => wireshark will already have reported the error */ - } - else { - guint offset_action_start = offset; - guint num_actions = 0; - while( total_len > 0 ) { - num_actions += 1; - int ret = dissect_action(action_tree, action_item, tvb, pinfo, &offset); - if( ret < 0 ) - break; /* stop if we run into an action we couldn't dissect */ - else - total_len -= ret; - } - proto_tree_add_uint(action_tree, ofp_action_num, tvb, offset_action_start, 0, num_actions); - } -} - -static void dissect_property_min(proto_tree* tree, tvbuff_t *tvb, guint32 *offset) -{ - add_child(tree, ofp_packet_queue_property_rate, tvb, offset, 2); - dissect_pad(tree, offset, 6); -} - -static gint32 dissect_property(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, guint32 *offset) -{ - guint32 offset_start = *offset; - guint16 type = tvb_get_ntohs(tvb, *offset); - guint16 len = tvb_get_ntohs(tvb, *offset + 2); - - proto_item *property_item = proto_tree_add_item(tree, ofp_packet_queue_property, tvb, *offset, len, FALSE); - proto_tree *property_tree = proto_item_add_subtree(property_item, ett_ofp_packet_queue_property); - - add_child(property_tree, ofp_packet_queue_property_type, tvb, offset, 2); - add_child(property_tree, ofp_packet_queue_property_len, tvb, offset, 2); - dissect_pad(tree, offset, 4); - - switch( type ) { - case OFPQT_MIN_RATE: - dissect_property_min(property_tree, tvb, offset); - break; - default: - add_child(property_tree, ofp_packet_queue_property_unknown, tvb, offset, 0); - return -1; - } - - return *offset - offset_start; -} - -/* returns the number of bytes dissected ( -1 if unknown propery is encountered */ -static void dissect_property_array(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint len, guint32 *offset) -{ - guint total_len = len; - - proto_item *property_item = proto_tree_add_item(tree, ofp_packet_queue_properties_hdr, tvb, *offset, total_len, FALSE); - proto_tree *property_tree = proto_item_add_subtree(property_item, ett_ofp_packet_queue_properties_hdr); - - if( total_len == 0 ) { - add_child_str(property_tree, ofp_packet_queue_property_warn, tvb, offset, 0, "No properties were specified"); - } - else { - guint32 offset_property_start = *offset; - guint num_properties = 0; - while( total_len > 0 ) { - num_properties += 1; - int ret = dissect_property(property_tree, tvb, pinfo, offset); - if( ret < 0 ) { - break; /* stop if we run into a property we couldn't dissect */ - } - else - total_len -= ret; - } - proto_tree_add_uint(property_tree, ofp_packet_queue_properties_num, tvb, offset_property_start, 0, num_properties); - } -} - -/** returns the number of bytes dissected (-1 if an unknown property is - * encountered; */ -static gint dissect_queue(proto_tree* tree, tvbuff_t *tvb, packet_info *pinfo, guint32 *offset) -{ - guint32 offset_start = *offset; - guint16 len = tvb_get_ntohs( tvb, *offset + 4); - - proto_item *queue_item = proto_tree_add_item(tree, ofp_packet_queue, tvb, *offset, len, FALSE); - proto_tree *queue_tree = proto_item_add_subtree(queue_item, ett_ofp_packet_queue); - - // add_child( queue_tree, ofp_packet_queue_queue_id, tvb, offset, 4 ); - dissect_queue_id(queue_tree, ofp_packet_queue_queue_id, tvb, offset); - add_child( queue_tree, ofp_packet_queue_len, tvb, offset, 2 ); - dissect_pad( queue_tree, offset, 2); - - dissect_property_array(tvb, pinfo, queue_tree, len - (*offset - offset_start), offset); - return *offset - offset_start; - -} - -static void dissect_queue_array(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint len, guint32 *offset) -{ - guint total_len = len - *offset; - - proto_item *queue_item = proto_tree_add_item(tree, ofp_queue_get_config_reply_queues_hdr, tvb, *offset, total_len, FALSE); - proto_tree *queue_tree = proto_item_add_subtree(queue_item, ett_ofp_queue_get_config_reply_queues_hdr); - - if( total_len == 0 ) { - add_child_str(queue_tree, ofp_packet_queue_warn, tvb, offset, 0, "No queues were specified"); - } - else if( *offset > len ) { - /* not enough bytes => wireshark will already have reported the error */ - } - else { - guint offset_queue_start = *offset; - guint num_queues = 0; - while( total_len > 0 ) { - num_queues += 1; - int ret = dissect_queue(queue_tree, tvb, pinfo, offset); - if( ret < 0 ) - break; /* stop if we run into an action we couldn't dissect */ - else - total_len -= ret; - } - proto_tree_add_uint(queue_tree, ofp_queue_get_config_reply_queues_num, tvb, offset_queue_start, 0, num_queues); - } -} - - -static void dissect_capability_array(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint field_size) { - proto_item *sf_cap_item = proto_tree_add_item(tree, ofp_switch_features_capabilities_hdr, tvb, offset, field_size, FALSE); - proto_tree *sf_cap_tree = proto_item_add_subtree(sf_cap_item, ett_ofp_switch_features_capabilities_hdr); - gint i; - for(i=0; icinfo, COL_PROTOCOL)) - col_append_str( pinfo->cinfo, COL_PROTOCOL, "+" ); - - if(check_col(pinfo->cinfo,COL_INFO)) - col_append_str( pinfo->cinfo, COL_INFO, " => " ); - - /* set up fences so ethernet dissectors only appends to our column info */ - col_set_fence(pinfo->cinfo, COL_PROTOCOL); - col_set_fence(pinfo->cinfo, COL_INFO); - - /* continue the dissection with the ethernet dissector */ - call_dissector(data_ethernet, next_tvb, pinfo, data_tree); -} - -static void dissect_error_code(proto_tree* tree, gint hf, tvbuff_t *tvb, guint32 *offset, guint16 err_type) { - guint16 err_code; - guint8 valid; - const gchar *code_str; - - err_code = tvb_get_ntohs(tvb, *offset); - code_str = ""; - valid = TRUE; - - switch (err_type) { - case OFPET_HELLO_FAILED: - if (err_code < N_HELLOFAILED) { - code_str = hello_failed_err_str[err_code]; - } else { - code_str = "Unknown - error?"; - } - break; - case OFPET_BAD_REQUEST: - if (err_code < N_BADREQUEST) { - code_str = bad_request_err_str[err_code]; - } else { - code_str = "Unknown - error?"; - } - break; - case OFPET_BAD_ACTION: - if (err_code < N_BADACTION) { - code_str = bad_action_err_str[err_code]; - } else { - code_str = "Unknown - error?"; - } - break; - case OFPET_FLOW_MOD_FAILED: - if (err_code < N_FLOWMODFAILED) { - code_str = flow_mod_failed_err_str[err_code]; - } else { - code_str = "Unknown - error?"; - } - break; - case OFPET_PORT_MOD_FAILED: - if (err_code < N_PORTMODFAILED) { - code_str = port_mod_failed_err_str[err_code]; - } else { - code_str = "Unknown - error?"; - } - break; - case OFPET_QUEUE_OP_FAILED: - if (err_code < N_QUEUEOPFAILED) { - code_str = queue_op_failed_err_str[err_code]; - } else { - code_str = "Unknown - error?"; - } - break; - - default: - valid = FALSE; - break; - } - - if (valid) - proto_tree_add_uint_format(tree, hf, tvb, *offset, 2, - err_code, - "Code: %s (%u)", - code_str, err_code); - else - proto_tree_add_item(tree, hf, tvb, *offset, 2, FALSE); - - *offset += 2; -} - -static void dissect_flow_mod_flags(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) { - proto_item *fm_flags_item = proto_tree_add_item(tree, ofp_switch_config_flags_hdr, tvb, *offset, 2, FALSE); - proto_tree *fm_flags_tree = proto_item_add_subtree(fm_flags_item, ett_ofp_flow_mod_flags_hdr); - int i; - - for (i = 0; i < NUM_FLOW_MOD_FLAGS; i++) - add_child_const(fm_flags_tree, ofp_flow_mod_flags[i], tvb, *offset, 2); - - *offset += 2; -} - - -static void dissect_openflow_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) -{ -# define STR_LEN 1024 - char str[STR_LEN]; - - /* display our protocol text if the protocol column is visible */ - if (check_col(pinfo->cinfo, COL_PROTOCOL)) - col_set_str(pinfo->cinfo, COL_PROTOCOL, PROTO_TAG_OPENFLOW); - - /* Clear out stuff in the info column */ - if(check_col(pinfo->cinfo,COL_INFO)) - col_clear(pinfo->cinfo,COL_INFO); - - /* get some of the header fields' values for later use */ - guint8 ver = tvb_get_guint8( tvb, 0 ); - guint8 type = tvb_get_guint8( tvb, 1 ); - guint16 len = tvb_get_ntohs( tvb, 2 ); - - /* add a warning if the version is what the plugin was written to handle */ - guint8 ver_warning = 0; - if( ver < DISSECTOR_OPENFLOW_MIN_VERSION || ver > DISSECTOR_OPENFLOW_MAX_VERSION || ver >= DISSECTOR_OPENFLOW_VERSION_DRAFT_THRESHOLD ) { - if( ver>=DISSECTOR_OPENFLOW_VERSION_DRAFT_THRESHOLD && ver<=DISSECTOR_OPENFLOW_MAX_VERSION ) - snprintf( str, STR_LEN, "DRAFT Dissector written for this OpenFlow version v0x%0X", ver ); - else { - ver_warning = 1; - if( DISSECTOR_OPENFLOW_MIN_VERSION == DISSECTOR_OPENFLOW_MAX_VERSION ) - snprintf( str, STR_LEN, - "Dissector written for OpenFlow v0x%0X (differs from this packet's version v0x%0X)", - DISSECTOR_OPENFLOW_MIN_VERSION, ver ); - else - snprintf( str, STR_LEN, - "Dissector written for OpenFlow v0x%0X-v0x%0X (differs from this packet's version v0x%0X)", - DISSECTOR_OPENFLOW_MIN_VERSION, DISSECTOR_OPENFLOW_MAX_VERSION, ver ); - } - } - - /* clarify protocol name display with version, length, and type information */ - if (check_col(pinfo->cinfo, COL_INFO)) { - /* special handling so we can put buffer IDs in the description */ - char str_extra[32]; - str_extra[0] = '\0'; - if( type==OFPT_PACKET_IN || type==OFPT_PACKET_OUT ) { - guint32 bid = tvb_get_ntohl(tvb, sizeof(struct ofp_header)); - if( bid != 0xFFFFFFFF ) - snprintf(str_extra, 32, "(BufID=%u) ", bid); - } - - if( ver_warning ) - col_add_fstr( pinfo->cinfo, COL_INFO, "%s %s(%uB) Ver Warning!", ofp_type_to_string(type), str_extra, len ); - else - col_add_fstr( pinfo->cinfo, COL_INFO, "%s %s(%uB)", ofp_type_to_string(type), str_extra, len ); - } - - if (tree) { /* we are being asked for details */ - proto_item *item = NULL; - proto_item *sub_item = NULL; - proto_tree *ofp_tree = NULL; - proto_tree *header_tree = NULL; - guint32 offset = 0; - proto_item *type_item = NULL; - proto_tree *type_tree = NULL; - - /* consume the entire tvb for the openflow packet, and add it to the tree */ - item = proto_tree_add_item(tree, proto_openflow, tvb, 0, -1, FALSE); - ofp_tree = proto_item_add_subtree(item, ett_ofp); - - /* put the header in its own node as a child of the openflow node */ - sub_item = proto_tree_add_item( ofp_tree, ofp_header, tvb, offset, 8, FALSE ); - header_tree = proto_item_add_subtree(sub_item, ett_ofp_header); - - if( ver_warning ) - add_child_str( header_tree, ofp_header_warn_ver, tvb, &offset, 0, str ); - - /* add the headers field as children of the header node */ - add_child( header_tree, ofp_header_version, tvb, &offset, 1 ); - add_child( header_tree, ofp_header_type, tvb, &offset, 1 ); - add_child( header_tree, ofp_header_length, tvb, &offset, 2 ); - add_child( header_tree, ofp_header_xid, tvb, &offset, 4 ); - - switch( type ) { - - case OFPT_HELLO: { - /* nothing else in this packet type */ - break; - } - - case OFPT_BARRIER_REQUEST: - case OFPT_BARRIER_REPLY: - /* nothing else in this packet type */ - break; - - case OFPT_ERROR: { - type_item = proto_tree_add_item(ofp_tree, ofp_error_msg, tvb, offset, -1, FALSE); - type_tree = proto_item_add_subtree(type_item, ett_ofp_error_msg); - - /* Extract the type for use later */ - guint16 type = tvb_get_ntohs(tvb, offset); - - add_child(type_tree, ofp_error_msg_type, tvb, &offset, 2); - dissect_error_code(type_tree, ofp_error_msg_code, tvb, &offset, type); - - if (type == OFPET_HELLO_FAILED) - add_child(type_tree, ofp_error_msg_data_str, tvb, &offset, len - offset); - else if (type == OFPET_BAD_REQUEST || - type == OFPET_BAD_ACTION || - type == OFPET_FLOW_MOD_FAILED) { - /* Dissect the data as an OpenFlow packet */ - proto_item *data_item = proto_tree_add_item(type_tree, ofp_error_msg_data, tvb, offset, -1, FALSE); - proto_tree *data_tree = proto_item_add_subtree(data_item, ett_ofp_error_msg_data); - tvbuff_t *next_tvb = tvb_new_subset(tvb, offset, -1, len - offset); - - /* Temporarily disable writing */ - gboolean writeable = col_get_writable(pinfo->cinfo); - col_set_writable( pinfo->cinfo, FALSE); - - /* Finally do the dissection */ - dissect_openflow_message(next_tvb, pinfo, data_tree); - - col_set_writable( pinfo->cinfo, writeable); - - offset += (len - offset); - } - else - add_child(type_tree, ofp_error_msg_data, tvb, &offset, len - offset); - break; - } - - case OFPT_ECHO_REQUEST: - case OFPT_ECHO_REPLY: { - if (len - offset > 0) - add_child(tree, ofp_echo, tvb, &offset, len - offset); - break; - } - - case OFPT_VENDOR: { - if (len - offset > 0) { - add_child(tree, ofp_vendor, tvb, &offset, len - offset); - } - break; - } - - case OFPT_FEATURES_REQUEST: - /* nothing else in this packet type */ - break; - - case OFPT_FEATURES_REPLY: { - - proto_item *sf_port_item = NULL; - proto_tree *sf_port_tree = NULL; - guint num_ports; - gint sz; - - type_item = proto_tree_add_item(ofp_tree, ofp_switch_features, tvb, offset, -1, FALSE); - //break; - type_tree = proto_item_add_subtree(type_item, ett_ofp_switch_features); - - /* fields we'll put directly in the subtree */ - - add_child(type_tree, ofp_switch_features_datapath_id, tvb, &offset, 8); - - add_child(type_tree, ofp_switch_features_n_buffers, tvb, &offset, 4); - add_child(type_tree, ofp_switch_features_n_tables, tvb, &offset, 1); - dissect_pad(type_tree, &offset, 3); - - - /* capabilities */ - dissect_capability_array(tvb, pinfo, type_tree, offset, 4); - offset += 4; - - /* actions */ - dissect_switch_features_actions(tvb, pinfo, type_tree, offset, 4); - offset += 4; - - /* handle ports */ - sf_port_item = proto_tree_add_item(type_tree, ofp_switch_features_ports_hdr, tvb, offset, -1, FALSE); - sf_port_tree = proto_item_add_subtree(sf_port_item, ett_ofp_switch_features_ports_hdr); - sz = len - sizeof(struct ofp_switch_features); - - if( sz > 0 ) { - num_ports = sz / sizeof(struct ofp_phy_port); /* number of ports */ - proto_tree_add_uint(sf_port_tree, ofp_switch_features_ports_num, tvb, offset, num_ports*sizeof(struct ofp_phy_port), num_ports); - - dissect_phy_ports(sf_port_tree, sf_port_item, tvb, pinfo, &offset, num_ports); - if( num_ports * sizeof(struct ofp_phy_port) < sz ) { - snprintf(str, STR_LEN, "%uB were leftover at end of packet", sz - num_ports*sizeof(struct ofp_phy_port)); - add_child_str(sf_port_tree, ofp_switch_features_ports_warn, tvb, &offset, 0, str); - } - } - else if( sz < 0 ) { - /* not enough bytes => wireshark will already have reported the error */ - } - else { - snprintf(str, STR_LEN, "No ports were specified"); - add_child_str(sf_port_tree, ofp_switch_features_ports_warn, tvb, &offset, 0, str); - } - break; - } - - case OFPT_GET_CONFIG_REQUEST: - /* nothing else in this packet type */ - break; - - case OFPT_GET_CONFIG_REPLY: - case OFPT_SET_CONFIG: { - type_item = proto_tree_add_item(ofp_tree, ofp_switch_config, tvb, offset, -1, FALSE); - type_tree = proto_item_add_subtree(type_item, ett_ofp_switch_config); - dissect_switch_config_flags(tvb, pinfo, type_tree, &offset); - add_child(type_tree, ofp_switch_config_miss_send_len, tvb, &offset, 2); - break; - } - - case OFPT_QUEUE_GET_CONFIG_REQUEST: { - type_item = proto_tree_add_item(ofp_tree, ofp_queue_get_config_request, tvb, offset, -1, FALSE); - type_tree = proto_item_add_subtree(type_item, ett_ofp_queue_get_config_request); - dissect_port(type_tree, ofp_queue_get_config_request_port_no, tvb, &offset); - dissect_pad(type_tree, &offset, 2); - break; - } - - case OFPT_QUEUE_GET_CONFIG_REPLY: { - type_item = proto_tree_add_item(ofp_tree, ofp_queue_get_config_reply, tvb, offset, -1, FALSE); - type_tree = proto_item_add_subtree(type_item, ett_ofp_queue_get_config_reply); - - dissect_port(type_tree, ofp_queue_get_config_reply_port_no, tvb, &offset); - dissect_pad(type_tree, &offset, 6); - - /* handle queues */ - dissect_queue_array(tvb, pinfo, type_tree, len, &offset); - break; - } - - case OFPT_PACKET_IN: { - type_item = proto_tree_add_item(ofp_tree, ofp_packet_in, tvb, offset, -1, FALSE); - type_tree = proto_item_add_subtree(type_item, ett_ofp_packet_in); - - add_child(type_tree, ofp_packet_in_buffer_id, tvb, &offset, 4); - - /* explicitly pull out the length so we can use it to determine data's size */ - guint16 total_len = tvb_get_ntohs( tvb, offset ); - proto_tree_add_uint(type_tree, ofp_packet_in_total_len, tvb, offset, 2, total_len); - offset += 2; - - add_child(type_tree, ofp_packet_in_in_port, tvb, &offset, 2); - add_child(type_tree, ofp_packet_in_reason, tvb, &offset, 1); - dissect_pad(type_tree, &offset, 1); - - if (len > sizeof(struct ofp_packet_in)) { - /* continue the dissection with the Ethernet dissector */ - if (data_ethernet) { - proto_item *data_item = proto_tree_add_item(type_tree, ofp_packet_in_data_hdr, tvb, offset, -1, FALSE); - proto_tree *data_tree = proto_item_add_subtree(data_item, ett_ofp_packet_in_data_hdr); - tvbuff_t *next_tvb = tvb_new_subset(tvb, offset, -1, total_len); - dissect_ethernet(next_tvb, pinfo, data_tree); - } else { - /* if we couldn't load the ethernet dissector, just display the bytes */ - add_child(type_tree, ofp_packet_in_data_hdr, tvb, &offset, total_len); - } - } - break; - } - - case OFPT_FLOW_REMOVED: { - type_item = proto_tree_add_item(ofp_tree, ofp_flow_removed, tvb, offset, -1, FALSE); - type_tree = proto_item_add_subtree(type_item, ett_ofp_flow_removed); - - dissect_match(type_tree, type_item, tvb, pinfo, &offset); - add_child(type_tree, ofp_flow_removed_cookie, tvb, &offset, 8); - add_child(type_tree, ofp_flow_removed_priority, tvb, &offset, 2); - add_child(type_tree, ofp_flow_removed_reason, tvb, &offset, 1); - dissect_pad(type_tree, &offset, 1); - add_child(type_tree, ofp_flow_removed_duration_sec, tvb, &offset, 4); - add_child(type_tree, ofp_flow_removed_duration_nsec, tvb, &offset, 4); - add_child(type_tree, ofp_flow_removed_idle_timeout, tvb, &offset, 2); - dissect_pad(type_tree, &offset, 2); - add_child(type_tree, ofp_flow_removed_packet_count, tvb, &offset, 8); - add_child(type_tree, ofp_flow_removed_byte_count, tvb, &offset, 8); - break; - } - - case OFPT_PORT_STATUS: { - type_item = proto_tree_add_item(ofp_tree, ofp_port_status, tvb, offset, -1, FALSE); - type_tree = proto_item_add_subtree(type_item, ett_ofp_port_status); - - add_child(type_tree, ofp_port_status_reason, tvb, &offset, 1); - dissect_pad(type_tree, &offset, 7); - dissect_phy_ports(type_tree, type_item, tvb, pinfo, &offset, 1); - break; - } - - case OFPT_PACKET_OUT: { - type_item = proto_tree_add_item(ofp_tree, ofp_packet_out, tvb, offset, -1, FALSE); - type_tree = proto_item_add_subtree(type_item, ett_ofp_packet_out); - - /* get buffer_id value for later use */ - guint32 buffer_id = tvb_get_ntohl( tvb, offset ); - - if( buffer_id == 0xFFFFFFFF ) - add_child_str(type_tree, ofp_packet_out_buffer_id, tvb, &offset, 4, "None"); - else { - snprintf(str, STR_LEN, "%u", buffer_id); - add_child_str(type_tree, ofp_packet_out_buffer_id, tvb, &offset, 4, str); - } - - /* display in port */ - // FIXME: bug in dissect_port for latest version - dissect_port(type_tree, ofp_packet_out_in_port, tvb, &offset); - - /* pull out actions len */ - guint16 actions_len = tvb_get_ntohs( tvb, offset); - add_child(type_tree, ofp_packet_out_actions_len, tvb, &offset, 2); - - /* dissect action array; will handle no-action case */ - dissect_action_array(tvb, pinfo, type_tree, offset + actions_len, offset); - offset += actions_len; - - /* if buffer id == -1, then display the provided packet */ - if( buffer_id == -1 ) { - /* continue the dissection with the Ethernet dissector */ - guint total_len = len - offset; - if( data_ethernet ) { - proto_item *data_item = proto_tree_add_item(type_tree, ofp_packet_out_data_hdr, tvb, offset, -1, FALSE); - proto_tree *data_tree = proto_item_add_subtree(data_item, ett_ofp_packet_out_data_hdr); - tvbuff_t *next_tvb = tvb_new_subset(tvb, offset, -1, total_len); - dissect_ethernet(next_tvb, pinfo, data_tree); - } - else { - /* if we couldn't load the ethernet dissector, just display the bytes */ - add_child(type_tree, ofp_packet_out_data_hdr, tvb, &offset, total_len); - } - } - - break; - } - - case OFPT_FLOW_MOD: { - type_item = proto_tree_add_item(ofp_tree, ofp_flow_mod, tvb, offset, -1, FALSE); - type_tree = proto_item_add_subtree(type_item, ett_ofp_flow_mod); - - dissect_match(type_tree, type_item, tvb, pinfo, &offset); - add_child(type_tree, ofp_flow_mod_cookie, tvb, &offset, 8); - add_child(type_tree, ofp_flow_mod_command, tvb, &offset, 2); - add_child(type_tree, ofp_flow_mod_idle_timeout, tvb, &offset, 2); - add_child(type_tree, ofp_flow_mod_hard_timeout, tvb, &offset, 2); - add_child(type_tree, ofp_flow_mod_priority, tvb, &offset, 2); - - /* get buffer_id value for later use */ - guint32 buffer_id = tvb_get_ntohl( tvb, offset ); - - if( buffer_id == 0xFFFFFFFF ) - add_child_str(type_tree, ofp_flow_mod_buffer_id, tvb, &offset, 4, "None"); - else { - snprintf(str, STR_LEN, "%u", buffer_id); - add_child_str(type_tree, ofp_flow_mod_buffer_id, tvb, &offset, 4, str); - } - - /* add the output port */ - dissect_port(type_tree, ofp_flow_mod_out_port, tvb, &offset ); - dissect_flow_mod_flags(tvb, pinfo, type_tree, &offset); - dissect_action_array(tvb, pinfo, type_tree, len, offset); - break; - } - - case OFPT_PORT_MOD: { - type_item = proto_tree_add_item(ofp_tree, ofp_port_mod, tvb, offset, -1, FALSE); - type_tree = proto_item_add_subtree(type_item, ett_ofp_port_mod); - - dissect_port_mod(type_tree, type_item, tvb, pinfo, &offset); - break; - } - - case OFPT_STATS_REQUEST: { - type_item = proto_tree_add_item(ofp_tree, ofp_stats_request, tvb, offset, -1, FALSE); - type_tree = proto_item_add_subtree(type_item, ett_ofp_stats_request); - - guint16 type = tvb_get_ntohs( tvb, offset ); - add_child(type_tree, ofp_stats_request_type, tvb, &offset, 2); - add_child(type_tree, ofp_stats_request_flags, tvb, &offset, 2); - - switch( type ) { - case OFPST_FLOW: { - proto_item *flow_item = proto_tree_add_item(type_tree, ofp_flow_stats_request, tvb, offset, -1, FALSE); - proto_tree *flow_tree = proto_item_add_subtree(flow_item, ett_ofp_flow_stats_request); - - dissect_match(flow_tree, flow_item, tvb, pinfo, &offset); - - guint8 id = tvb_get_guint8( tvb, offset ); - if( id == 0xFF ) - add_child_str(flow_tree, ofp_flow_stats_request_table_id, tvb, &offset, 1, "All Tables"); - else { - snprintf(str, STR_LEN, "%u", id); - add_child_str(flow_tree, ofp_flow_stats_request_table_id, tvb, &offset, 1, str); - } - - dissect_pad(flow_tree, &offset, 1); - dissect_port(flow_tree, ofp_flow_stats_request_out_port, tvb, &offset ); - break; - } - - case OFPST_AGGREGATE: { - proto_item *aggr_item = proto_tree_add_item(type_tree, ofp_aggr_stats_request, tvb, offset, -1, FALSE); - proto_tree *aggr_tree = proto_item_add_subtree(aggr_item, ett_ofp_aggr_stats_request); - - dissect_match(aggr_tree, aggr_item, tvb, pinfo, &offset); - - guint8 id = tvb_get_guint8( tvb, offset ); - if( id == 0xFF ) - add_child_str(aggr_tree, ofp_aggr_stats_request_table_id, tvb, &offset, 1, "All Tables"); - else { - snprintf(str, STR_LEN, "%u", id); - add_child_str(aggr_tree, ofp_aggr_stats_request_table_id, tvb, &offset, 1, str); - } - - dissect_pad(aggr_tree, &offset, 3); - break; - } - - case OFPST_TABLE: - /* no body for these types of requests */ - break; - - case OFPST_PORT:{ - if (len - offset > 0) { - proto_item *port_item = proto_tree_add_item(type_tree, ofp_port_stats_request, tvb, offset, -1, FALSE); - proto_tree *port_tree = proto_item_add_subtree(port_item, ett_ofp_port_stats_request); - dissect_port(port_tree, ofp_port_stats_request_port_no, tvb, &offset); - dissect_pad(port_tree, &offset, 6); - } - } - break; - - case OFPST_QUEUE: { - proto_item *queue_item = proto_tree_add_item(type_tree, ofp_queue_stats_request, tvb, offset, -1, FALSE); - proto_tree *queue_tree = proto_item_add_subtree(queue_item, ett_ofp_queue_stats_request); - - dissect_port(queue_tree, ofp_queue_stats_port_no, tvb, &offset); - dissect_pad(queue_tree, &offset, 2); - dissect_queue_id(queue_tree, ofp_queue_stats_queue_id, tvb, &offset); - break; - } - - default: - /* add as bytes if type isn't one we know how to dissect */ - add_child(type_tree, ofp_stats_request_body, tvb, &offset, len - offset); - } - - break; - } - - case OFPT_STATS_REPLY: { - type_item = proto_tree_add_item(ofp_tree, ofp_stats_reply, tvb, offset, -1, FALSE); - type_tree = proto_item_add_subtree(type_item, ett_ofp_stats_reply); - - guint16 type = tvb_get_ntohs( tvb, offset ); - add_child(type_tree, ofp_stats_reply_type, tvb, &offset, 2); - add_child(type_tree, ofp_stats_reply_flags, tvb, &offset, 2); - - switch( type ) { - - case OFPST_DESC: { - // FIXME: add desc stats - proto_item* desc_item = proto_tree_add_item(type_tree, ofp_desc_stats, tvb, offset, -1, FALSE); - proto_tree* desc_tree = proto_item_add_subtree(desc_item, ett_ofp_desc_stats); - - add_child( desc_tree, ofp_desc_stats_mfr_desc, tvb, &offset, DESC_STR_LEN ); - add_child( desc_tree, ofp_desc_stats_hw_desc, tvb, &offset, DESC_STR_LEN ); - add_child( desc_tree, ofp_desc_stats_sw_desc, tvb, &offset, DESC_STR_LEN ); - add_child( desc_tree, ofp_desc_stats_serial_num, tvb, &offset, SERIAL_NUM_LEN ); - add_child( desc_tree, ofp_desc_stats_dp_desc, tvb, &offset, DESC_STR_LEN ); - - break; - } - - case OFPST_FLOW: { - /* process each flow stats struct in the packet */ - while( offset < len ) { - proto_item* flow_item = proto_tree_add_item(type_tree, ofp_flow_stats_reply, tvb, offset, -1, FALSE); - proto_tree* flow_tree = proto_item_add_subtree(flow_item, ett_ofp_flow_stats_reply); - - /* just get the length of this part of the packet; no need - to put it in the tree */ - guint16 total_len = tvb_get_ntohs( tvb, offset ); - guint offset_start = offset; - offset += 2; - - add_child(flow_tree, ofp_flow_stats_reply_table_id, tvb, &offset, 1); - dissect_pad(flow_tree, &offset, 1); - dissect_match(flow_tree, flow_item, tvb, pinfo, &offset); - add_child(flow_tree, ofp_flow_stats_reply_duration_sec, tvb, &offset, 4); - add_child(flow_tree, ofp_flow_stats_reply_duration_nsec, tvb, &offset, 4); - add_child(flow_tree, ofp_flow_stats_reply_priority, tvb, &offset, 2); - add_child(flow_tree, ofp_flow_stats_reply_idle_timeout, tvb, &offset, 2); - add_child(flow_tree, ofp_flow_stats_reply_hard_timeout, tvb, &offset, 2); - dissect_pad(flow_tree, &offset, 6); - add_child(flow_tree, ofp_flow_stats_reply_cookie, tvb, &offset, 8); - add_child(flow_tree, ofp_flow_stats_reply_packet_count, tvb, &offset, 8); - add_child(flow_tree, ofp_flow_stats_reply_byte_count, tvb, &offset, 8); - - /* parse the actions for this flow */ - dissect_action_array(tvb, pinfo, flow_tree, total_len + offset_start, offset); - offset = total_len + offset_start; - } - break; - } - - case OFPST_AGGREGATE: { - proto_item* aggr_item = proto_tree_add_item(type_tree, ofp_aggr_stats_reply, tvb, offset, -1, FALSE); - proto_tree* aggr_tree = proto_item_add_subtree(aggr_item, ett_ofp_aggr_stats_reply); - - add_child(aggr_tree, ofp_aggr_stats_reply_packet_count, tvb, &offset, 8); - add_child(aggr_tree, ofp_aggr_stats_reply_byte_count, tvb, &offset, 8); - add_child(aggr_tree, ofp_aggr_stats_reply_flow_count, tvb, &offset, 4); - - dissect_pad(aggr_tree, &offset, 4); - break; - } - - case OFPST_TABLE: { - /* process each table stats struct in the packet */ - while( offset < len ) { - proto_item *table_item = proto_tree_add_item(type_tree, ofp_table_stats, tvb, offset, -1, FALSE); - proto_tree *table_tree = proto_item_add_subtree(table_item, ett_ofp_table_stats); - - add_child(table_tree, ofp_table_stats_table_id, tvb, &offset, 1); - dissect_pad(table_tree, &offset, 3); - add_child( table_tree, ofp_table_stats_name, tvb, &offset, OFP_MAX_TABLE_NAME_LEN); - dissect_wildcards(table_tree, table_item, tvb, pinfo, &offset, ofp_table_stats_wildcards); - add_child(table_tree, ofp_table_stats_max_entries, tvb, &offset, 4); - add_child(table_tree, ofp_table_stats_active_count, tvb, &offset, 4); - add_child(table_tree, ofp_table_stats_lookup_count, tvb, &offset, 8); - add_child(table_tree, ofp_table_stats_matched_count, tvb, &offset, 8); - } - break; - } - - case OFPST_PORT: { - /* process each port stats struct in the packet */ - while( offset < len ) { - proto_item *port_item = proto_tree_add_item(type_tree, ofp_port_stats, tvb, offset, -1, FALSE); - proto_tree *port_tree = proto_item_add_subtree(port_item, ett_ofp_port_stats); - - dissect_port(port_tree, ofp_port_stats_port_no, tvb, &offset); - dissect_pad(port_tree, &offset, 6); - add_child(port_tree, ofp_port_stats_rx_packets, tvb, &offset, 8); - add_child(port_tree, ofp_port_stats_tx_packets, tvb, &offset, 8); - add_child(port_tree, ofp_port_stats_rx_bytes, tvb, &offset, 8); - add_child(port_tree, ofp_port_stats_tx_bytes, tvb, &offset, 8); - add_child(port_tree, ofp_port_stats_rx_dropped, tvb, &offset, 8); - add_child(port_tree, ofp_port_stats_tx_dropped, tvb, &offset, 8); - add_child(port_tree, ofp_port_stats_rx_errors, tvb, &offset, 8); - add_child(port_tree, ofp_port_stats_tx_errors, tvb, &offset, 8); - add_child(port_tree, ofp_port_stats_rx_frame_err, tvb, &offset, 8); - add_child(port_tree, ofp_port_stats_rx_over_err, tvb, &offset, 8); - add_child(port_tree, ofp_port_stats_rx_crc_err, tvb, &offset, 8); - add_child(port_tree, ofp_port_stats_collisions, tvb, &offset, 8); - } - break; - } - - case OFPST_QUEUE: { - /* process each port stats struct in the packet */ - while( offset < len ) { - proto_item *queue_item = proto_tree_add_item(type_tree, ofp_queue_stats, tvb, offset, -1, FALSE); - proto_tree *queue_tree = proto_item_add_subtree(queue_item, ett_ofp_queue_stats); - - dissect_port(queue_tree, ofp_queue_stats_port_no, tvb, &offset); - dissect_pad(queue_tree, &offset, 2); - dissect_queue_id(queue_tree, ofp_queue_stats_queue_id, tvb, &offset); - add_child(queue_tree, ofp_queue_stats_tx_bytes, tvb, &offset, 8); - add_child(queue_tree, ofp_queue_stats_tx_packets, tvb, &offset, 8); - add_child(queue_tree, ofp_queue_stats_tx_errors, tvb, &offset, 8); - } - break; - } - - case OFPST_VENDOR: { - proto_item* vendor_item = proto_tree_add_item(type_tree, ofp_vendor_stats, tvb, offset, -1, FALSE); - proto_tree* vendor_tree = proto_item_add_subtree(vendor_item, ett_ofp_vendor_stats); - - add_child(vendor_tree, ofp_vendor_stats_vendor, tvb, &offset, 4); - add_child(vendor_tree, ofp_vendor_stats_body, tvb, &offset, len - offset); - - break; - } - - default: - /* add as bytes if type isn't one we know how to dissect */ - add_child(type_tree, ofp_stats_reply_body, tvb, &offset, len - offset); - } - - break; - } - - default: - /* add a warning if we encounter an unrecognized packet type */ - snprintf(str, STR_LEN, "Dissector does not recognize type %u", type); - add_child_str(tree, ofp_header_warn_type, tvb, &offset, len - offset, str); - } - } -} - -static void dissect_openflow(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) -{ - /* have wireshark reassemble our PDUs; call dissect_openflow_when full PDU assembled */ - tcp_dissect_pdus(tvb, pinfo, tree, TRUE, 4, get_openflow_message_len, dissect_openflow_message); -} diff --git a/openflow/utilities/wireshark_dissectors/openflow/plugin.c b/openflow/utilities/wireshark_dissectors/openflow/plugin.c deleted file mode 100644 index deb99c25..00000000 --- a/openflow/utilities/wireshark_dissectors/openflow/plugin.c +++ /dev/null @@ -1,28 +0,0 @@ -/* Do not modify this file. */ -/* It is created automatically by the Makefile. */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include - -#include "moduleinfo.h" - -#ifndef ENABLE_STATIC -G_MODULE_EXPORT const gchar version[] = VERSION; - -/* Start the functions we need for the plugin stuff */ - -G_MODULE_EXPORT void -plugin_register (void) -{ - {extern void proto_register_openflow (void); proto_register_openflow ();} -} - -G_MODULE_EXPORT void -plugin_reg_handoff(void) -{ - {extern void proto_reg_handoff_openflow (void); proto_reg_handoff_openflow ();} -} -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/airpcap.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/airpcap.h deleted file mode 100644 index 639a930a..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/airpcap.h +++ /dev/null @@ -1,907 +0,0 @@ -/* - * Copyright (c) 2006-2007 CACE Technologies, Davis (California) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#if !defined(AIRPCAP_H__EAE405F5_0171_9592_B3C2_C19EC426AD34__INCLUDED_) -#define AIRPCAP_H__EAE405F5_0171_9592_B3C2_C19EC426AD34__INCLUDED_ - -#ifdef _MSC_VER -// This disables a VS warning for zero-sized arrays. -#pragma warning( disable : 4200) -// This stops VS2005 ranting against stdio. -#pragma warning( disable : 4996) -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/*! - \mainpage AirPcap interface documentation - - \section Introduction - - This document describes the data structures and the functions exported by the CACE Technologies AirPcap library. - The AirPcap library provides low-level access to the AirPcap driver including advanced capabilities such as channel setting, - link type control and WEP configuration.
- This manual includes the following sections: - - \note throughout this documentation, \e device refers to a physical USB AirPcap device, while \e adapter is an open API - instance. Most of the AirPcap API operations are adapter-specific but some of them, like setting the channel, are - per-device and will be reflected on all the open adapters. These functions will have "Device" in their name, e.g. - AirpcapSetDeviceChannel(). - - \b Sections: - - - \ref airpcapfuncs - - \ref airpcapdefs - - \ref radiotap -*/ - -/** @defgroup airpcapdefs AirPcap definitions and data structures - * @{ - */ - -/*! - \brief This string is the fixed prefix in the airpcap adapter name. - It can be used to parse the name field in an AirpcapDeviceDescription structure. -*/ -#define AIRPCAP_DEVICE_NAME_PREFIX "\\\\.\\airpcap" - -/*! - \brief This string is the scanf modifier to extract the adapter number from an adapter name. - It can be used to parse the name field in an AirpcapDeviceDescription structure with scanf. -*/ -#define AIRPCAP_DEVICE_NUMBER_EXTRACT_STRING "\\\\.\\airpcap%u" - -#define AIRPCAP_DEVICE_ANY_EXTRACT_STRING "\\\\.\\airpcap_any" - -/*! - \brief Entry in the list returned by \ref AirpcapGetDeviceList(); -*/ -typedef struct _AirpcapDeviceDescription -{ - struct _AirpcapDeviceDescription *next; ///< Next element in the list - PCHAR Name; ///< Device name - PCHAR Description; ///< Device description -} AirpcapDeviceDescription, *PAirpcapDeviceDescription; - -#define MAX_ENCRYPTION_KEYS 64 - -#define WEP_KEY_MAX_SIZE 32 ///< Maximum size of a WEP key, in bytes. This is the size of an entry in the - ///< AirpcapWepKeysCollection structure - -#ifndef __MINGW32__ -#pragma pack(push) -#pragma pack(1) -#endif // __MINGW32__ - - -#define AIRPCAP_KEYTYPE_WEP 0 ///< Key type: WEP. The key can have an arbitrary length smaller than 32 bytes. -#define AIRPCAP_KEYTYPE_TKIP 1 ///< Key type: TKIP (WPA). NOT SUPPORTED YET. -#define AIRPCAP_KEYTYPE_CCMP 2 ///< Key type: CCMP (WPA2). NOT SUPPORTED YET. - -/*! - \brief WEP key container -*/ -typedef struct _AirpcapKey -{ - UINT KeyType; ///< Type of key, can be on of: \ref AIRPCAP_KEYTYPE_WEP, \ref AIRPCAP_KEYTYPE_TKIP, \ref AIRPCAP_KEYTYPE_CCMP. Only AIRPCAP_KEYTYPE_WEP is supported by the driver at the moment. - UINT KeyLen; ///< Length of the key, in bytes - BYTE KeyData[WEP_KEY_MAX_SIZE]; ///< Key Data -} -#ifdef __MINGW32__ -__attribute__((__packed__)) -#endif // __MINGW32__ -AirpcapKey, *PAirpcapKey; - -/*! - \brief frequency Band. - 802.11 adapters can support different frequency bands, the most important of which are: 2.4GHz (802.11b/g/n) - and 5GHz (802.11a/n). -*/ -typedef enum _AirpcapChannelBand -{ - AIRPCAP_CB_AUTO = 1, ///< Automatically pick the best frequency band - AIRPCAP_CB_2_4_GHZ = 2, ///< 2.4 GHz frequency band - AIRPCAP_CB_4_GHZ = 4, ///< 4 GHz frequency band - AIRPCAP_CB_5_GHZ = 5 ///< 5 GHz frequency band -}AirpcapChannelBand, *PAirpcapChannelBand; - -/*! - \brief Type of frame validation the adapter performs. - An adapter can be instructed to accept different kind of frames: correct frames only, frames with wrong Frame Check Sequence (FCS) only, all frames. -*/ -typedef enum _AirpcapValidationType -{ - AIRPCAP_VT_ACCEPT_EVERYTHING = 1, ///< Accept all the frames the device captures - AIRPCAP_VT_ACCEPT_CORRECT_FRAMES = 2, ///< Accept correct frames only, i.e. frames with correct Frame Check Sequence (FCS). - AIRPCAP_VT_ACCEPT_CORRUPT_FRAMES = 3, ///< Accept corrupt frames only, i.e. frames with worng Frame Check Sequence (FCS). - AIRPCAP_VT_UNKNOWN = 4 ///< Unknown validation type. You should see it only in case of error. -}AirpcapValidationType, *PAirpcapValidationType; - -/*! - \brief Type of decryption the adapter performs. - An adapter can be instructed to turn decryption (based on the device-configured keys configured - with \ref AirpcapSetDeviceKeys()) on or off. -*/ -typedef enum _AirpcapDecryptionState -{ - AIRPCAP_DECRYPTION_ON = 1, ///< This adapter performs decryption - AIRPCAP_DECRYPTION_OFF = 2 ///< This adapter does not perform decryption -}AirpcapDecryptionState, *PAirpcapDecryptionState; - - -/*! - \brief Storage for a MAC address -*/ -typedef struct _AirpcapMacAddress -{ - BYTE Address[6]; ///< MAC address bytes -} -#ifdef __MINGW32__ -__attribute__((__packed__)) -#endif // __MINGW32__ -AirpcapMacAddress, *PAirpcapMacAddress; - -/*! - \brief This structure is used to store a collection of WEP keys. - Note that the definition of the structure doesn't contain any key, so be careful to allocate a buffer - with the size of the key, like in the following example: - - \code - PAirpcapKeysCollection KeysCollection; - UINT KeysCollectionSize; - - KeysCollectionSize = sizeof(AirpcapKeysCollection) + NumKeys * sizeof(AirpcapKey); - - KeysCollection = (PAirpcapKeysCollection)malloc(KeysCollectionSize); - if(!KeysCollection) - { - // Error - } - \endcode -*/ -typedef struct _AirpcapKeysCollection -{ - UINT nKeys; ///< Number of keys in the collection - AirpcapKey Keys[0]; ///< Array of nKeys keys. -} AirpcapKeysCollection, *PAirpcapKeysCollection; - -/*! - \brief Packet header. - - This structure defines the BPF that preceeds every packet delivered to the application. -*/ -typedef struct _AirpcapBpfHeader -{ - UINT TsSec; ///< Timestamp associated with the captured packet. SECONDS. - UINT TsUsec; ///< Timestamp associated with the captured packet. MICROSECONDS. - UINT Caplen; ///< Length of captured portion. The captured portion can be different from the original packet, because it is possible (with a proper filter) to instruct the driver to capture only a portion of the packets. - UINT Originallen; ///< Original length of packet - USHORT Hdrlen; ///< Length of bpf header (this struct plus alignment padding). In some cases, a padding could be added between the end of this structure and the packet data for performance reasons. This field can be used to retrieve the actual data of the packet. -} -#ifdef __MINGW32__ -__attribute__((__packed__)) -#endif // __MINGW32__ -AirpcapBpfHeader, *PAirpcapBpfHeader; - -/// Helper macros to extract packets coming from the driver. Rounds up to the next even multiple of AIRPCAP_ALIGNMENT. -#define AIRPCAP_ALIGNMENT sizeof(int) -#define AIRPCAP_WORDALIGN(x) (((x)+(AIRPCAP_ALIGNMENT-1))&~(AIRPCAP_ALIGNMENT-1)) - -#ifndef __MINGW32__ -#pragma pack(pop) -#endif // __MINGW32__ - -#define AIRPCAP_ERRBUF_SIZE 512 ///< Size of the error buffer, in bytes - -#ifndef __AIRPCAP_DRIVER__ - -/*! - \brief Link type. - AirPcap supports two kind of 802.11 linktypes: plain 802.11 and radiotap. -*/ -#undef _AirpcapLinkType -typedef enum _AirpcapLinkType -{ - AIRPCAP_LT_802_11 = 1, ///< plain 802.11 linktype. Every packet in the buffer contains the raw 802.11 frame, including MAC FCS. - AIRPCAP_LT_802_11_PLUS_RADIO = 2, ///< 802.11 plus radiotap linktype. Every packet in the buffer contains a radiotap header followed by the 802.11 frame. MAC FCS is included. - AIRPCAP_LT_UNKNOWN = 3, ///< Unknown linktype. You should see it only in case of error. - AIRPCAP_LT_802_11_PLUS_PPI = 4 ///< 802.11 plus PPI header linktype. Every packet in the buffer contains a PPI header followed by the 802.11 frame. MAC FCS is included. -}AirpcapLinkType, *PAirpcapLinkType; - -#if !defined(AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_) -#define AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_ -/*! - \brief Adapter handle. -*/ -typedef struct _AirpcapHandle AirpcapHandle, *PAirpcapHandle; -#endif - -/*! - \brief Capture statistics. - Returned by \ref AirpcapGetStats(); -*/ -typedef struct _AirpcapStats -{ - UINT Recvs; ///< Number of packets that the driver received by the adapter - ///< from the beginning of the current capture. This value includes the packets - ///< dropped because of buffer full. - UINT Drops; ///< number of packets that the driver dropped from the beginning of a capture. - ///< A packet is lost when the the buffer of the driver is full. - UINT IfDrops; ///< Packets dropped by the card before going to the USB bus. - ///< Not supported at the moment. - UINT Capt; ///< number of packets that pass the BPF filter, find place in the kernel buffer and - ///< therefore reach the application. -}AirpcapStats, *PAirpcapStats; - -/*! - \brief Channel information. - Used by \ref AirpcapSetDeviceChannelEx(), \ref AirpcapGetDeviceChannelEx(), \ref AirpcapGetDeviceSupportedChannels() -*/ -typedef struct _AirpcapChannelInfo -{ - UINT Frequency; ///< Channel frequency, in MHz. - /*! - \brief 802.11n specific. Offset of the extension channel in case of 40MHz channels. - - Possible values are -1, 0 +1: - - -1 means that the extension channel should be below the control channel (e.g. Control = 5 and Extension = 1) - - 0 means that no extension channel should be used (20MHz channels or legacy mode) - - +1 means that the extension channel should be above the control channel (e.g. Control = 1 and Extension = 5) - - In case of 802.11a/b/g channels (802.11n legacy mode), this field should be set to 0. - */ - CHAR ExtChannel; - UCHAR Reserved[3]; ///< Reserved. It should be set to {0,0,0}. -} - AirpcapChannelInfo, *PAirpcapChannelInfo; - - -/*@}*/ - -/** @defgroup airpcapfuncs AirPcap functions - * @{ - */ - -/*! - \brief Return a string with the API version - \param VersionMajor Pointer to a variable that will be filled with the major version number. - \param VersionMinor Pointer to a variable that will be filled with the minor version number. - \param VersionRev Pointer to a variable that will be filled with the revision number. - \param VersionBuild Pointer to a variable that will be filled with the build number. -*/ -void AirpcapGetVersion(PUINT VersionMajor, PUINT VersionMinor, PUINT VersionRev, PUINT VersionBuild); - -/*! - \brief Return the last error related to the specified handle - \param AdapterHandle Handle to an open adapter. - \return The string with the last error. -*/ -PCHAR AirpcapGetLastError(PAirpcapHandle AdapterHandle); - -/*! - \brief Return the list of available devices - \param PPAllDevs Address to a caller allocated pointer. On success this pointer will receive the head of a list of available devices. - \param Ebuf String that will contain error information if FALSE is returned. The size of the string must be AIRPCAP_ERRBUF_SIZE bytes. - \return TRUE on success. FALSE is returned on failure, in which case Ebuf is filled in with an appropriate error message. - - Here's a snippet of code that shows how to use AirpcapGetDeviceList(): - - \code - CHAR Ebuf[AIRPCAP_ERRBUF_SIZE]; - AirpcapDeviceDescription *Desc, *tDesc; - - if(AirpcapGetDeviceList(&Desc, Ebuf) == -1) - { - printf("Unable to get the list of devices: %s\n", Ebuf); - return -1; - } - - for(tDesc = Desc; tDesc; tDesc = tDesc->next) - { - printf("%u) %s (%s)\n", - ++i, - tDesc->Name, - tDesc->Description); - } - - AirpcapFreeDeviceList(Desc); - \endcode -*/ -BOOL AirpcapGetDeviceList(PAirpcapDeviceDescription *PPAllDevs, PCHAR Ebuf); - -/*! - \brief Free a list of devices returned by AirpcapGetDeviceList() - \param PAllDevs Head of the list of devices returned by \ref AirpcapGetDeviceList(). -*/ -VOID AirpcapFreeDeviceList(PAirpcapDeviceDescription PAllDevs); - -/*! - \brief Open an adapter - \param DeviceName Name of the device to open. Use \ref AirpcapGetDeviceList() to get the list of devices. - \param Ebuf String that will contain error information in case of failure. The size of the string must be AIRPCAP_ERRBUF_SIZE bytes. - \return A PAirpcapHandle handle on success. NULL is returned on failure, in which case Ebuf is filled in with an appropriate error message. -*/ -PAirpcapHandle AirpcapOpen(PCHAR DeviceName, PCHAR Ebuf); - -/*! - \brief Close an adapter - \param AdapterHandle Handle to the adapter to close. -*/ -VOID AirpcapClose(PAirpcapHandle AdapterHandle); - -/*! - \brief Sets the monitor mode for the specified adapter - \param AdapterHandle Handle to the adapter. - \param MonitorModeEnabled If TRUE, the adapter will be put in monitor mode. If FALSE, the adapter will be configured - for normal operation. - \return TRUE on success. - - When monitor mode is on, the adapter captures all the packets transmitted on the channel. This includes: - - - unicast packets - - multicast packets - - broadcast packets - - control and management packets - - When monitor mode is off, the adapter has a filter on unicast packets to capture only the packets whose MAC - destination address equals to the adapter's address. This means the following frames will be received: - - - unicast packets with the address of the adapter - - multicast packets - - broadcast packets - - beacons and probe requests - - The main reason to turn monitor mode off is that, when not in monitor mode, the adapter will acknowledge the - data frames sent to its address. This is useful when the adapter needs to interact with other devices on the - 802.11 network, bacause handling the ACKs in software is too slow. - - \note When an adapter is plugged into the system, it's always configured with monitor mode ON. The monitor mode - configuration is not stored persistently, so if you want to turn monitor mode off, you will need to do it - every time you open the adapter. -*/ -BOOL AirpcapSetMonitorMode(PAirpcapHandle AdapterHandle, BOOL MonitorModeEnabled); - -/*! - \brief Returns TRUE if the specified adapter is in monitor mode. - \param AdapterHandle Handle to the adapter. - \param PMonitorModeEnabled User-provided variable that will be set to true if the adapter is in monitor mode. - \return TRUE if the operation is successful. FALSE otherwise. - - \note When an adapter is plugged into the system, it's always configured with monitor mode ON. The monitor mode - configuration is not stored persistently, so if you want to turn monitor mode off, you will need to do it - every time you open the adapter. -*/ -BOOL AirpcapGetMonitorMode(PAirpcapHandle AdapterHandle, PBOOL PMonitorModeEnabled); - -/*! - \brief Set the link type of an adapter - \param AdapterHandle Handle to the adapter. - \param NewLinkType the "link type", i.e. the format of the frames that will be received from the adapter. - \return TRUE on success. - - the "link type" determines how the driver will encode the packets captured from the network. - Aircap supports two link types: - - \ref AIRPCAP_LT_802_11, to capture 802.11 frames (including control frames) without any - power information. Look at the Capture_no_radio example application in the developer's pack - for a reference on how to decode 802.11 frames with this link type. - - \ref AIRPCAP_LT_802_11_PLUS_RADIO, to capture 802.11 frames (including control frames) with a radiotap header - that contains power and channel information. More information about the radiotap header can be found in the - \ref radiotap section. Moreover, the "Capture_radio" example application in - the developer's pack can be used as a reference on how to decode 802.11 frames with radiotap headers. - - \ref AIRPCAP_LT_802_11_PLUS_PPI, to capture 802.11 frames (including control frames) with a Per Packet Information (PPI) - header that contains per-packet meta information like channel and power information. More details on the PPI header can - be founf in the PPI online documentation (TODO). -*/ -BOOL AirpcapSetLinkType(PAirpcapHandle AdapterHandle, AirpcapLinkType NewLinkType); - -/*! - \brief Get the link type of the specified adapter - \param AdapterHandle Handle to the adapter. - \param PLinkType Pointer to a caller allocated AirpcapLinkType variable that will contain the link type of the adapter. - \return TRUE on success. - - the "link type" determines how the driver will encode the packets captured from the network. - Aircap supports two link types: - - AIRPCAP_LT_802_11, to capture 802.11 frames (including control frames) without any - power information. Look at the Capture_no_radio example application in the developer's pack - for a reference on how to decode 802.11 frames with this link type. - - AIRPCAP_LT_802_11_PLUS_RADIO, to capture 802.11 frames (including control frames) with a radiotap header - that contains power and channel information. More information about the radiotap header can be found int the - \ref radiotap section. Moreover, the "Capture_radio" example application in - the developer's pack can be used as a reference on how to decode 802.11 frames with radiotap headers. -*/ -BOOL AirpcapGetLinkType(PAirpcapHandle AdapterHandle, PAirpcapLinkType PLinkType); - -/*! - \brief Configures the adapter on whether to include the MAC Frame Check Sequence in the captured packets. - \param AdapterHandle Handle to the adapter. - \param IsFcsPresent TRUE if the packets should include the FCS. FALSE otherwise - \return TRUE on success. - - In the default configuration, the adapter includes the FCS in the captured packets. The MAC Frame Check Sequence - is 4 bytes and is located at the end of the 802.11 packet, with both AIRPCAP_LT_802_11 and AIRPCAP_LT_802_11_PLUS_RADIO - link types. - When the FCS inclusion is turned on, and if the link type is AIRPCAP_LT_802_11_PLUS_RADIO, the radiotap header - that precedes each frame has two additional fields at the end: Padding and FCS. These two fields are not present - when FCS inclusion is off. -*/ -BOOL AirpcapSetFcsPresence(PAirpcapHandle AdapterHandle, BOOL IsFcsPresent); - -/*! - \brief Returns TRUE if the specified adapter includes the MAC Frame Check Sequence in the captured packets - \param AdapterHandle Handle to the adapter. - \param PIsFcsPresent User-provided variable that will be set to true if the adapter is including the FCS. - \return TRUE if the operation is successful. FALSE otherwise. - - In the default configuration, the adatper has FCS inclusion turned on. The MAC Frame Check Sequence is 4 bytes - and is located at the end of the 802.11 packet, with both AIRPCAP_LT_802_11 and AIRPCAP_LT_802_11_PLUS_RADIO - link types. - When the FCS inclusion is turned on, and if the link type is AIRPCAP_LT_802_11_PLUS_RADIO, the radiotap header - that precedes each frame has two additional fields at the end: Padding and FCS. These two fields are not present - when FCS inclusion is off. -*/ -BOOL AirpcapGetFcsPresence(PAirpcapHandle AdapterHandle, PBOOL PIsFcsPresent); - -/*! - \brief Configures the adapter to accept or drop frames with an incorrect Frame Check sequence (FCS). - \param AdapterHandle Handle to the adapter. - \param ValidationType The type of validation the driver will perform. See the documentation of \ref AirpcapValidationType for details. - \return TRUE on success. - - \note By default, the driver is configured in \ref AIRPCAP_VT_ACCEPT_EVERYTHING mode. -*/ -BOOL AirpcapSetFcsValidation(PAirpcapHandle AdapterHandle, AirpcapValidationType ValidationType); - -/*! - \brief Checks if the specified adapter is configured to capture frames with incorrect an incorrect Frame Check Sequence (FCS). - \param AdapterHandle Handle to the adapter. - \param ValidationType Pointer to a user supplied variable that will contain the type of validation the driver will perform. See the documentation of \ref AirpcapValidationType for details. - \return TRUE if the operation is succesful. FALSE otherwise. - - \note By default, the driver is configured in \ref AIRPCAP_VT_ACCEPT_EVERYTHING mode. -*/ -BOOL AirpcapGetFcsValidation(PAirpcapHandle AdapterHandle, PAirpcapValidationType ValidationType); - -/*! - \brief Set the list of decryption keys that the driver is going to use with the specified device. - \param AdapterHandle Handle an open adapter instance. - \param KeysCollection Pointer to a \ref PAirpcapKeysCollection structure that contains the keys to be set in the driver. - \return TRUE if the operation is successful. FALSE otherwise. - - The AirPcap driver is able to use a set of decryption keys to decrypt the traffic transmitted on a specific SSID. If one of the - keys corresponds to the one the frame has been encrypted with, the driver will perform decryption and return the cleartext frames - to the application. - - This function allows to set the adapter-specific set of keys. These keys will be used by the specified adapter only, - and will not be used by other airpcap devices besides the specified one. - - At this time, the only supported decryption method is WEP. - - The keys are applied to the packets in the same order they appear in the KeysCollection structure until the packet is - correctly decrypted, therefore putting frequently used keys at the beginning of the structure improves performance. - - \note: when you change the set of keys from an open capture instance, the change will be - immediately reflected on all the other capture instances. -*/ -BOOL AirpcapSetDeviceKeys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection); - -/*! - \brief Returns the list of decryption keys in the driver that are currently associated with the specified device - \param AdapterHandle Handle to an open adapter instance. - \param KeysCollection User-allocated PAirpcapKeysCollection structure that will be filled with the keys. - \param PKeysCollectionSize \b IN: pointer to a user-allocated variable that contains the length of the KeysCollection structure, in bytes. - \b OUT: amount of data moved by the driver in the buffer pointed by KeysBuffer, in bytes. - \return TRUE if the operation is succesful. If an error occurs, the return value is FALSE and KeysCollectionSize is zero. - If the provided buffer is too small to contain the keys, the return value is FALSE and KeysCollectionSize contains the - needed KeysCollection length, in bytes. If the device doesn't have any decryption key configured, the return value is TRUE, and - KeysCollectionSize will be zero. - - This function returns the adapter-specific set of keys. These keys are used by the specified adapter only, - and not by other airpcap devices besides the specified one. - - The AirPcap driver is able to use a set of decryption keys to decrypt the traffic transmitted on a specific SSID. If one of the - keys corresponds to the one the frame has been encrypted with, the driver will perform decryption and return the cleartext frames - to the application. - The driver supports, for every device, multiple keys at the same time. - - The configured decryption keys are device-specific, therefore AirpcapGetDeviceKeys() will return a different set of keys - when called on different devices. - - At this time, the only supported decryption method is WEP. -*/ -BOOL AirpcapGetDeviceKeys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, PUINT PKeysCollectionSize); - -/*! - \brief Set the global list of decryption keys that the driver is going to use with all the devices. - \param AdapterHandle Handle an open adapter instance. - \param KeysCollection Pointer to a \ref PAirpcapKeysCollection structure that contains the keys to be set in the driver. - \return TRUE if the operation is successful. FALSE otherwise. - - The AirPcap driver is able to use a set of decryption keys to decrypt the traffic transmitted on a specific SSID. If one of the - keys corresponds to the one the frame has been encrypted with, the driver will perform decryption and return the cleartext frames - to the application. - - This function allows to set the global driver set of keys. These keys will be used by all the adapters plugged in - the machine. - - At this time, the only supported decryption method is WEP. - - The keys are applied to the packets in the same order they appear in the KeysCollection structure until the packet is - correctly decrypted, therefore putting frequently used keys at the beginning of the structure improves performance. - - \note: when you change the set of keys from an open capture instance, the change will be - immediately reflected on all the other capture instances. -*/ -BOOL AirpcapSetDriverKeys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection); - -/*! - \brief Returns the global list of decryption keys in the driver that are associated with all the devices. - \param AdapterHandle Handle to an open adapter instance. - \param KeysCollection User-allocated PAirpcapKeysCollection structure that will be filled with the keys. - \param PKeysCollectionSize \b IN: pointer to a user-allocated variable that contains the length of the KeysCollection structure, in bytes. - \b OUT: amount of data moved by the driver in the buffer pointed by KeysBuffer, in bytes. - \return TRUE if the operation is succesful. If an error occurs, the return value is FALSE and KeysCollectionSize is zero. - If the provided buffer is too small to contain the keys, the return value is FALSE and KeysCollectionSize contains the - needed KeysCollection length, in bytes. If the device doesn't have any decryption key configured, the return value is TRUE, and - KeysCollectionSize will be zero. - - This function returns the global driver set of keys. These keys will be used by all the adapters plugged in - the machine. - - The AirPcap driver is able to use a set of decryption keys to decrypt the traffic transmitted on a specific SSID. If one of the - keys corresponds to the one the frame has been encrypted with, the driver will perform decryption and return the cleartext frames - to the application. - - At this time, the only supported decryption method is WEP. -*/ -BOOL AirpcapGetDriverKeys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, PUINT PKeysCollectionSize); - -/*! - \brief Turns on or off the decryption of the incoming frames with the adapter-specific keys. - \param AdapterHandle Handle to the adapter. - \param Enable Either \ref AIRPCAP_DECRYPTION_ON or \ref AIRPCAP_DECRYPTION_OFF - \return TRUE on success. - - The adapter-specific decryption keys can be configured with the \ref AirpcapSetDeviceKeys() function. - \note By default, the driver is configured with \ref AIRPCAP_DECRYPTION_ON. -*/ -BOOL AirpcapSetDecryptionState(PAirpcapHandle AdapterHandle, AirpcapDecryptionState Enable); - -/*! - \brief Tells if this open instance is configured to perform the decryption of the incoming frames with the adapter-specific keys. - \param AdapterHandle Handle to the adapter. - \param PEnable Pointer to a user supplied variable that will contain the decryption configuration. See \ref PAirpcapDecryptionState for details. - \return TRUE if the operation is succesful. FALSE otherwise. - - The adapter-specific decryption keys can be configured with the \ref AirpcapSetDeviceKeys() function. - \note By default, the driver is configured with \ref AIRPCAP_DECRYPTION_ON. -*/ -BOOL AirpcapGetDecryptionState(PAirpcapHandle AdapterHandle, PAirpcapDecryptionState PEnable); - -/*! - \brief Turns on or off the decryption of the incoming frames with the global driver set of keys. - \param AdapterHandle Handle to the adapter. - \param Enable Either \ref AIRPCAP_DECRYPTION_ON or \ref AIRPCAP_DECRYPTION_OFF - \return TRUE on success. - - The global decryption keys can be configured with the \ref AirpcapSetDriverKeys() function. - \note By default, the driver is configured with \ref AIRPCAP_DECRYPTION_ON. -*/ -BOOL AirpcapSetDriverDecryptionState(PAirpcapHandle AdapterHandle, AirpcapDecryptionState Enable); - -/*! - \brief Tells if this open instance is configured to perform the decryption of the incoming frames with the global driver set of keys. - \param AdapterHandle Handle to the adapter. - \param PEnable Pointer to a user supplied variable that will contain the decryption configuration. See \ref PAirpcapDecryptionState for details. - \return TRUE if the operation is succesful. FALSE otherwise. - - The global decryption keys can be configured with the \ref AirpcapSetDriverKeys() function. - \note By default, the driver is configured with \ref AIRPCAP_DECRYPTION_ON. -*/ -BOOL AirpcapGetDriverDecryptionState(PAirpcapHandle AdapterHandle, PAirpcapDecryptionState PEnable); - -/*! - \brief Set the radio channel of a device - \param AdapterHandle Handle to the adapter. - \param Channel the new channel to set. - \return TRUE on success. - - The list of available channels can be retrieved with \ref AirpcapGetDeviceSupportedChannels(). The default channel setting is 6. - - \note this is a device-related function: when you change the channel from an open capture instance, the change will be - immediately reflected on all the other capture instances. -*/ -BOOL AirpcapSetDeviceChannel(PAirpcapHandle AdapterHandle, UINT Channel); - -/*! - \brief Get the radio channel of a device - \param AdapterHandle Handle to the adapter. - \param PChannel Pointer to a user-supplied variable into which the function will copy the currently configured radio channel. - \return TRUE on success. - - The list of available channels can be retrieved with \ref AirpcapGetDeviceSupportedChannels(). The default channel setting is 6. - - \note this is a device-related function: when you change the channel from an open capture instance, the change will be - immediately reflected on all the other capture instances. -*/ -BOOL AirpcapGetDeviceChannel(PAirpcapHandle AdapterHandle, PUINT PChannel); - -/*! - \brief Set the size of the kernel packet buffer for this adapter - \param AdapterHandle Handle to the adapter. - \param BufferSize New size, in bytes. - \return TRUE on success. - - Every AirPcap open instance has an associated kernel buffer, whose default size is 1 Mbyte. - This function can be used to change the size of this buffer, and can be called at any time. - A bigger kernel buffer size decreases the risk of dropping packets during network bursts or when the - application is busy, at the cost of higher kernel memory usage. - - \note don't use this function unless you know what you are doing. Due to caching issues and bigger non-paged - memory consumption, bigger buffer sizes can decrease the capture performace instead of improving it. -*/ -BOOL AirpcapSetKernelBuffer(PAirpcapHandle AdapterHandle, UINT BufferSize); - -/*! - \brief Get the size of the kernel packet buffer for this adapter - \param AdapterHandle Handle to the adapter. - \param PSizeBytes User-allocated variable that will be filled with the size of the kernel buffer. - \return TRUE on success. - - Every AirPcap open instance has an associated kernel buffer, whose default size is 1 Mbyte. - This function can be used to get the size of this buffer. -*/ -BOOL AirpcapGetKernelBufferSize(PAirpcapHandle AdapterHandle, PUINT PSizeBytes); - -/*! - \brief Saves the configuration of the specified adapter in the registry, so that it becomes the default for this adapter. - \param AdapterHandle Handle to the adapter. - \return TRUE on success. FALSE on failure. - - Almost all the AirPcap calls that modify the configuration (\ref AirpcapSetLinkType(), \ref AirpcapSetFcsPresence(), - \ref AirpcapSetFcsValidation(), \ref AirpcapSetKernelBuffer(), \ref AirpcapSetMinToCopy()) - affect only the referenced AirPcap open instance. This means that if you do another \ref AirpcapOpen() on the same - adapter, the configuration changes will not be remembered, and the new adapter handle will have default configuration - settings. - - Exceptions to this rule are the \ref AirpcapSetDeviceChannel() and \ref AirpcapSetDeviceKeys() functions: a channel change is - reflected on all the open instances, and remembered until the next call to \ref AirpcapSetDeviceChannel(), until the adapter - is unplugged, or until the machine is powered off. Same thing for the configuration of the WEP keys. - - AirpcapStoreCurConfigAsAdapterDefault() stores the configuration of the give open instance as the default for the adapter: - all the instances opened in the future will have the same configuration that this adapter currently has. - The configuration is stored in the registry, therefore it is remembered even when the adapter is unplugged or the - machine is turned off. However, an adapter doesn't bring its configuration with it from machine to machine. - - the configuration information saved in the registry includes the following parameters: - - channel - - kernel buffer size - - mintocopy - - link type - - CRC presence - - Encryption keys - - Encryption Enabled/Disabled state - - The configuration is adapter-specific. This means that changing the configuration of an adapter - doesn't modify the one of the other adapters that are currently used or that will be used in the future. - - \note AirpcapStoreCurConfigAsAdapterDefault() must have exclusive access to the adapter -- it - will fail if more than one AirPcap handle is opened at the same time for this adapter. - AirpcapStoreCurConfigAsAdapterDefault() needs administrator privileges. It will fail if the calling user - is not a local machine administrator. -*/ -BOOL AirpcapStoreCurConfigAsAdapterDefault(PAirpcapHandle AdapterHandle); - -/*! - \brief Set the BPF kernel filter for an adapter - \param AdapterHandle Handle to the adapter. - \param Instructions pointer to the first BPF instruction in the array. Corresponds to the bf_insns - in a bpf_program structure (see the WinPcap documentation at http://www.winpcap.org/devel.htm). - \param Len Number of instructions in the array pointed by the previous field. Corresponds to the bf_len in - a a bpf_program structure (see the WinPcap documentation at http://www.winpcap.org/devel.htm). - \return TRUE on success. - - The AirPcap driver is able to perform kernel-level filtering using the standard BPF pseudo-machine format. You can read - the WinPcap documentation at http://www.winpcap.org/devel.htm for more details on the BPF filtering mechaism. - - A filter can be automatically created by using the pcap_compile() function of the WinPcap API. This function - converts a human readable text expression with the tcpdump/libpcap syntax into a BPF program. - If your program doesn't link wpcap, but you need to generate the code for a particular filter, you can run WinDump - with the -d or -dd or -ddd flags to obtain the pseudocode. - -*/ -BOOL AirpcapSetFilter(PAirpcapHandle AdapterHandle, PVOID Instructions, UINT Len); - -/*! - \brief Return the MAC address of an adapter. - \param AdapterHandle Handle to the adapter. - \param PMacAddress Pointer to a user allocated MAC address. - The size of this buffer needs to be at least 6 bytes. - \return TRUE on success. -*/ -BOOL AirpcapGetMacAddress(PAirpcapHandle AdapterHandle, PAirpcapMacAddress PMacAddress); - -/*! - \brief Set the mintocopy parameter for an open adapter - \param AdapterHandle Handle to the adapter. - \param MinToCopy is the mintocopy size in bytes. - \return TRUE on success. - - When the number of bytes in the kernel buffer changes from less than mintocopy bytes to greater than or equal to mintocopy bytes, - the read event is signalled (see \ref AirpcapGetReadEvent()). A high value for mintocopy results in poor responsiveness since the - driver may signal the application "long" after the arrival of the packet. And a high value results in low CPU loading - by minimizing the number of user/kernel context switches. - A low MinToCopy results in good responsiveness since the driver will signal the application close to the arrival time of - the packet. This has higher CPU loading over the first approach. -*/ -BOOL AirpcapSetMinToCopy(PAirpcapHandle AdapterHandle, UINT MinToCopy); - -/*! - \brief Gets an event that is signaled when that is signalled when packets are available in the kernel buffer (see \ref AirpcapSetMinToCopy()). - \param AdapterHandle Handle to the adapter. - \param PReadEvent Pointer to a user-supplied handle that in which the read event will be copied. - \return TRUE on success. - - \note the event is signalled when at least mintocopy bytes are present in the kernel buffer (see \ref AirpcapSetMinToCopy()). - This event can be used by WaitForSingleObject() and WaitForMultipleObjects() to create blocking behavior when reading - packets from one or more adapters (see \ref AirpcapRead()). -*/ -BOOL AirpcapGetReadEvent(PAirpcapHandle AdapterHandle, HANDLE* PReadEvent); - -/*! - \brief Fills a user-provided buffer with zero or more packets that have been captured on the referenced adapter. - \param AdapterHandle Handle to the adapter. - \param Buffer pointer to the buffer that will be filled with captured packets. - \param BufSize size of the input buffer that will contain the packets, in bytes. - \param PReceievedBytes Pointer to a user supplied variable that will receive the number of bytes copied by AirpcapRead. - Can be smaller than BufSize. - \return TRUE on success. - - 802.11 frames are returned by the driver in buffers. Every 802.11 frame in the buffer is preceded by a \ref AirpcapBpfHeader structure. - The suggested way to use an AirPcap adapter is through the pcap API exported by wpcap.dll. If this is not - possible, the Capture_radio and Capture_no_radio examples in the AirPcap developer's pack show how to properly decode the - packets in the read buffer returned by AirpcapRead(). - - \note this function is NOT blocking. Blocking behavior can be obtained using the event returned - by \ref AirpcapGetReadEvent(). See also \ref AirpcapSetMinToCopy(). -*/ -BOOL AirpcapRead(PAirpcapHandle AdapterHandle, PBYTE Buffer, UINT BufSize, PUINT PReceievedBytes); - -/*! - \brief Transmits a packet. - \param AdapterHandle Handle to the adapter. - \param TxPacket Pointer to a buffer that contains the packet to be transmitted. - \param PacketLen Length of the buffer pointed by the TxPacket argument, in bytes. - \return TRUE on success. - - The packet will be transmitted on the channel the device is currently set. To change the device adapter, use the - \ref AirpcapSetDeviceChannel() function. - - If the linktype of the adapter is AIRPCAP_LT_802_11, the buffer pointed by TxPacket should contain just the 802.11 - packet, without additional information. The packet will be transmitted at 1Mbps. - - If the linktype of the adapter is AIRPCAP_LT_802_11_PLUS_RADIO, the buffer pointed by TxPacket should contain a radiotap - header followed by the 802.11 packet. AirpcapWrite will use the rate information in the radiotap header when - transmitting the packet. -*/ -BOOL AirpcapWrite(PAirpcapHandle AdapterHandle, PCHAR TxPacket, ULONG PacketLen); - -/*! - \brief Get per-adapter WinPcap-compatible capture statistics. - \param AdapterHandle Handle to the adapter. - \param PStats pointer to a user-allocated AirpcapStats structure that will be filled with statistical information. - \return TRUE on success. -*/ -BOOL AirpcapGetStats(PAirpcapHandle AdapterHandle, PAirpcapStats PStats); - -/*! - \brief Get the number of LEDs the referenced adapter has available. - \param AdapterHandle Handle to the adapter. - \param NumberOfLeds Number of LEDs available on this adapter. - \return TRUE on success. -*/ -BOOL AirpcapGetLedsNumber(PAirpcapHandle AdapterHandle, PUINT NumberOfLeds); - -/*! - \brief Turn on one of the adapter's LEDs. - \param AdapterHandle Handle to the adapter. - \param LedNumber zero-based identifier of the LED to turn on. - \return TRUE on success. -*/ -BOOL AirpcapTurnLedOn(PAirpcapHandle AdapterHandle, UINT LedNumber); - -/*! - \brief Turn off one of the adapter's LEDs. - \param AdapterHandle Handle to the adapter. - \param LedNumber zero-based identifier of the LED to turn off. - \return TRUE on success. -*/ -BOOL AirpcapTurnLedOff(PAirpcapHandle AdapterHandle, UINT LedNumber); - -/*! - \brief Set the channel of a device through its radio frequency. In case of 802.11n enabled devices, it sets the extension channel, if used. - \param AdapterHandle Handle to the adapter. - \param ChannelInfo The new channel information to set. - \return TRUE on success. - - \note this is a device-related function: when you change the channel from an open capture instance, the change will be - immediately reflected on all the other capture instances. -*/ -BOOL AirpcapSetDeviceChannelEx(PAirpcapHandle AdapterHandle, AirpcapChannelInfo ChannelInfo); - -/*! - \brief Get the channel of a device through its radiofrequency. In case of 802.11n enabled devices, it gets the extension channel, if in use. - \param AdapterHandle Handle to the adapter. - \param PChannelInfo Pointer to a user-supplied variable into which the function will copy the currently configured channel information. - \return TRUE on success. - - \note this is a device-related function: when you change the channel from an open capture instance, the change will be - immediately reflected on all the other capture instances. -*/ -BOOL AirpcapGetDeviceChannelEx(PAirpcapHandle AdapterHandle, PAirpcapChannelInfo PChannelInfo); - -/*! - \brief Get the list of supported channels for a given device. In case of a 802.11n capable device, information related to supported extension channels is also reported. - - Every control channel is listed multiple times, one for each different supported extension channel. For example channel 6 (2437MHz) is usually listed three times: - - Frequency 2437 Extension +1. Control channel is 6, extension channel is 10. - - Frequency 2437 Extension 0. Control channel is 6, no extension channel is used (20MHz channel and legacy mode). - - Frequency 2437 Extension -1. Control channel is 6, extension channel is 2. - \param AdapterHandle Handle to the adapter. - \param ppChannelInfo Pointer to a user-supplied variable that will point to an array of supported channel. Such list must not be freed by the caller - \param pNumChannelInfo Number of channels returned in the array. - \return TRUE on success. - - \note The supported channels are not listed in any specific order. -*/ -BOOL AirpcapGetDeviceSupportedChannels(PAirpcapHandle AdapterHandle, PAirpcapChannelInfo *ppChannelInfo, PUINT pNumChannelInfo); - -/*! - \brief Converts a given frequency to the corresponding channel. - - \param Frequency Frequency of the channel, in MHz. - \param PChannel Pointer to a user-supplied variable that will contain the channel number on success. - \param PBand Pointer to a user-supplied variable that will contain the band (a or b/g) of the given channel. - \return TRUE on success, i.e. the frequency corresponds to a valid a or b/g channel. -*/ -BOOL AirpcapConvertFrequencyToChannel(UINT Frequency, PUINT PChannel, PAirpcapChannelBand PBand); - -/*! - \brief Converts a given channel to the corresponding frequency. - - \param Channel Channel number to be converted. - \param PFrequency Pointer to a user-supplied variable that will contain the channel frequency in MHz on success. - \return TRUE on success, i.e. the given channel number exists. -*/ -BOOL AirpcapConvertChannelToFrequency(UINT Channel, PUINT PFrequency); - - -/*@}*/ - -#endif // __AIRPCAP_DRIVER__ - -#ifdef __cplusplus -} -#endif - -#endif // !defined(AIRPCAP_H__EAE405F5_0171_9592_B3C2_C19EC426AD34__INCLUDED_) diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/airpcap_loader.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/airpcap_loader.h deleted file mode 100644 index df35b0eb..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/airpcap_loader.h +++ /dev/null @@ -1,560 +0,0 @@ -/* airpcap_loader.h - * Declarations of routines for the "About" dialog - * - * $Id: airpcap_loader.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Giorgio Tino - * Copyright (c) CACE Technologies, LLC 2006 - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __AIRPCAP_LOADER_H__ -#define __AIRPCAP_LOADER_H__ - -#include - -/* Error values from "get_airpcap_interface_list()". */ -#define CANT_GET_AIRPCAP_INTERFACE_LIST 0 /* error getting list */ -#define NO_AIRPCAP_INTERFACES_FOUND 1 /* list is empty */ -#define AIRPCAP_NOT_LOADED 2 /* Airpcap DLL not loaded */ - -#define AIRPCAP_CHANNEL_ANY_NAME "ANY" - -#define AIRPCAP_WEP_KEY_STRING "WEP" -/* - * XXX - WPA_PWD is the passphrase+ssid and WPA-PSK is the hexadecimal key - */ -#define AIRPCAP_WPA_PWD_KEY_STRING "WPA-PWD" -#define AIRPCAP_WPA_BIN_KEY_STRING "WPA-PSK" - -#define AIRPCAP_DLL_OK 0 -#define AIRPCAP_DLL_OLD 1 -#define AIRPCAP_DLL_ERROR 2 -#define AIRPCAP_DLL_NOT_FOUND 3 - -typedef PCHAR (*AirpcapGetLastErrorHandler)(PAirpcapHandle AdapterHandle); -typedef BOOL (*AirpcapGetDeviceListHandler)(PAirpcapDeviceDescription *PPAllDevs, PCHAR Ebuf); -typedef VOID (*AirpcapFreeDeviceListHandler)(PAirpcapDeviceDescription PAllDevs); -typedef PAirpcapHandle (*AirpcapOpenHandler)(PCHAR DeviceName, PCHAR Ebuf); -typedef VOID (*AirpcapCloseHandler)(PAirpcapHandle AdapterHandle); -typedef BOOL (*AirpcapGetLinkTypeHandler)(PAirpcapHandle AdapterHandle, PAirpcapLinkType PLinkType); -typedef BOOL (*AirpcapSetLinkTypeHandler)(PAirpcapHandle AdapterHandle, AirpcapLinkType NewLinkType); -typedef BOOL (*AirpcapSetKernelBufferHandler)(PAirpcapHandle AdapterHandle, UINT BufferSize); -typedef BOOL (*AirpcapSetFilterHandler)(PAirpcapHandle AdapterHandle, PVOID Instructions, UINT Len); -typedef BOOL (*AirpcapGetMacAddressHandler)(PAirpcapHandle AdapterHandle, PAirpcapMacAddress PMacAddress); -typedef BOOL (*AirpcapSetMinToCopyHandler)(PAirpcapHandle AdapterHandle, UINT MinToCopy); -typedef BOOL (*AirpcapGetReadEventHandler)(PAirpcapHandle AdapterHandle, HANDLE* PReadEvent); -typedef BOOL (*AirpcapReadHandler)(PAirpcapHandle AdapterHandle, PBYTE Buffer, UINT BufSize, PUINT PReceievedBytes); -typedef BOOL (*AirpcapGetStatsHandler)(PAirpcapHandle AdapterHandle, PAirpcapStats PStats); -typedef BOOL (*AirpcapTurnLedOnHandler)(PAirpcapHandle AdapterHandle, UINT LedNumber); -typedef BOOL (*AirpcapTurnLedOffHandler)(PAirpcapHandle AdapterHandle, UINT LedNumber); -typedef BOOL (*AirpcapSetDeviceChannelHandler)(PAirpcapHandle AdapterHandle, UINT Channel); -typedef BOOL (*AirpcapGetDeviceChannelHandler)(PAirpcapHandle AdapterHandle, PUINT PChannel); -typedef BOOL (*AirpcapSetFcsPresenceHandler)(PAirpcapHandle AdapterHandle, BOOL IsFcsPresent); -typedef BOOL (*AirpcapGetFcsPresenceHandler)(PAirpcapHandle AdapterHandle, PBOOL PIsFcsPresent); -typedef BOOL (*AirpcapSetFcsValidationHandler)(PAirpcapHandle AdapterHandle, AirpcapValidationType ValidationType); -typedef BOOL (*AirpcapGetFcsValidationHandler)(PAirpcapHandle AdapterHandle, PAirpcapValidationType PValidationType); -typedef BOOL (*AirpcapSetDeviceKeysHandler)(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection); -typedef BOOL (*AirpcapGetDeviceKeysHandler)(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, PUINT PKeysCollectionSize); -typedef BOOL (*AirpcapSetDriverKeysHandler)(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection); -typedef BOOL (*AirpcapGetDriverKeysHandler)(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, PUINT PKeysCollectionSize); -typedef BOOL (*AirpcapSetDecryptionStateHandler)(PAirpcapHandle AdapterHandle, AirpcapDecryptionState Enable); -typedef BOOL (*AirpcapGetDecryptionStateHandler)(PAirpcapHandle AdapterHandle, PAirpcapDecryptionState PEnable); -typedef BOOL (*AirpcapSetDriverDecryptionStateHandler)(PAirpcapHandle AdapterHandle, AirpcapDecryptionState Enable); -typedef BOOL (*AirpcapGetDriverDecryptionStateHandler)(PAirpcapHandle AdapterHandle, PAirpcapDecryptionState PEnable); -typedef BOOL (*AirpcapStoreCurConfigAsAdapterDefaultHandler)(PAirpcapHandle AdapterHandle); -typedef VOID (*AirpcapGetVersionHandler)(PUINT VersionMajor, PUINT VersionMinor, PUINT VersionRev, PUINT VersionBuild); -typedef BOOL (*AirpcapSetDeviceChannelExHandler)(PAirpcapHandle AdapterHandle, AirpcapChannelInfo ChannelInfo); -typedef BOOL (*AirpcapGetDeviceChannelExHandler)(PAirpcapHandle AdapterHandle, PAirpcapChannelInfo PChannelInfo); -typedef BOOL (*AirpcapGetDeviceSupportedChannelsHandler)(PAirpcapHandle AdapterHandle, AirpcapChannelInfo **ppChannelInfo, PULONG pNumChannelInfo); - -#define FLAG_CAN_BE_LOW 0x00000001 -#define FLAG_CAN_BE_HIGH 0x00000002 -#define FLAG_IS_BG_CHANNEL 0x00000004 -#define FLAG_IS_A_CHANNEL 0x00000008 - -typedef struct _Dot11Channel -{ - UINT Channel; - ULONG Frequency; - ULONG Flags; -} Dot11Channel; - -/* - * The list of interfaces returned by "get_airpcap_interface_list()" is - * a list of these structures. - */ -typedef struct { - char *name; /* e.g. "eth0" */ - char *description; /* from OS, e.g. "Local Area Connection" or NULL */ - GSList *ip_addr; /* containing address values of if_addr_t */ - gboolean loopback; /* TRUE if loopback, FALSE otherwise */ - AirpcapLinkType linkType; /* The link layer type */ - AirpcapChannelInfo channelInfo; /* Channel Information */ - BOOL IsFcsPresent; /* Include 802.11 CRC in frames */ - AirpcapValidationType CrcValidationOn; /* Capture Frames with Wrong CRC */ - AirpcapDecryptionState DecryptionOn; /* TRUE if decryption is on, FALSE otherwise */ - PAirpcapKeysCollection keysCollection; /* WEP Key collection for the adapter */ - UINT keysCollectionSize; /* Size of the key collection */ - gboolean blinking; /* TRUE if is blinkng, FALSE otherwise */ - gboolean led; /* TRUE if on, FALSE if off */ - gboolean saved; /* TRUE if current configuration has been saved, FALSE otherwise */ - gint tag; /* int for the gtk blinking callback */ - Dot11Channel *pSupportedChannels; - ULONG numSupportedChannels; -} airpcap_if_info_t; - -/* - * Struct used to store infos to pass to the preferences manager callbacks - */ -typedef struct { - GList *list; - int current_index; - int number_of_keys; -} keys_cb_data_t; - -/* Airpcap interface list */ -extern GList *airpcap_if_list; - -/* Airpcap current selected interface */ -extern airpcap_if_info_t *airpcap_if_selected; - -/* Airpcap current active interface */ -extern airpcap_if_info_t *airpcap_if_active; - -/* WLAN preferences pointer */ -/*extern module_t *wlan_prefs; - TODO: What is this?? */ - -/* - * Function used to read the Decryption Keys from the preferences and store them - * properly into the airpcap adapter. - */ -BOOL -load_wlan_driver_wep_keys(); - -/* - * Function used to save to the prefereces file the Decryption Keys. - */ -BOOL -save_wlan_wep_keys(airpcap_if_info_t* info_if); - -/* - * This function will tell the airpcap driver the key list to use - * This will be stored into the registry... - */ -gboolean -write_wlan_wep_keys_to_registry(airpcap_if_info_t* info_if, GList* key_list); - -/* Returs TRUE if the WEP key is valid, false otherwise */ -gboolean -wep_key_is_valid(char* key); - -/* - * Callback used to free an instance of airpcap_if_info_t - */ -static void -free_airpcap_if_cb(gpointer data, gpointer user_data _U_); - -/* - * USED FOR DEBUG ONLY... PRINTS AN AirPcap ADAPTER STRUCTURE in a fancy way. - */ -void -airpcap_if_info_print(airpcap_if_info_t* if_info); - -/* - * Used to retrieve the two chars string from interface - */ -gchar* -airpcap_get_if_string_number_from_description(gchar* description); - -/* - * Function used to free the airpcap interface list - */ -void -free_airpcap_interface_list(GList *if_list); - -/* - * Used to retrieve the interface given the name - * (the name is used in AirpcapOpen) - */ -airpcap_if_info_t* get_airpcap_if_from_name(GList* if_list, const gchar* name); - -/* - * Airpcap wrapper, used to store the current settings for the selected adapter - */ -BOOL -airpcap_if_store_cur_config_as_adapter_default(PAirpcapHandle ah); - -/* - * Function used to load the WEP keys for a selected interface - */ -BOOL -airpcap_if_load_keys(PAirpcapHandle ad, airpcap_if_info_t *if_info); - -/* - * Function used to load the WEP keys from the global driver list - */ -BOOL -airpcap_if_load_driver_keys(PAirpcapHandle ad, airpcap_if_info_t *if_info); - -/* - * Function used to save the WEP keys for a selected interface - */ -void -airpcap_if_save_keys(PAirpcapHandle ad, airpcap_if_info_t *if_info); - -/* - * Function used to save the WEP keys for a selected interface - */ -void -airpcap_if_save_driver_keys(PAirpcapHandle ad, airpcap_if_info_t *if_info); - -/* - * Airpcap wrapper, used to get the fcs validation of an airpcap adapter - */ -BOOL -airpcap_if_get_fcs_validation(PAirpcapHandle ah, PAirpcapValidationType val); - -/* - * Airpcap wrapper, used to set the fcs validation of an airpcap adapter - */ -BOOL -airpcap_if_set_fcs_validation(PAirpcapHandle ah, AirpcapValidationType val); - -/* - * Airpcap wrapper, used to get the decryption enabling of an airpcap adapter - */ -BOOL -airpcap_if_get_decryption_state(PAirpcapHandle ah, PAirpcapDecryptionState val); - -/* - * Airpcap wrapper, used to set the decryption enabling of an airpcap adapter - */ -BOOL -airpcap_if_set_decryption_state(PAirpcapHandle ah, AirpcapDecryptionState val); - -/* - * Airpcap wrapper, used to get the fcs presence of an airpcap adapter - */ -BOOL -airpcap_if_get_fcs_presence(PAirpcapHandle ah, PBOOL ch); - -/* - * Airpcap wrapper, used to set the fcs presence of an airpcap adapter - */ -BOOL -airpcap_if_set_fcs_presence(PAirpcapHandle ah, BOOL ch); - -/* - * Airpcap wrapper, used to get the link type of an airpcap adapter - */ -BOOL -airpcap_if_get_link_type(PAirpcapHandle ah, PAirpcapLinkType lt); - -/* - * Airpcap wrapper, used to set the link type of an airpcap adapter - */ -BOOL -airpcap_if_set_link_type(PAirpcapHandle ah, AirpcapLinkType lt); - -/* - * Airpcap wrapper, used to get the channel of an airpcap adapter - */ -BOOL -airpcap_if_get_device_channel(PAirpcapHandle ah, PUINT ch); - -/* - * Airpcap wrapper, get the channels supported by the adapter - */ -BOOL -airpcap_if_get_device_supported_channels(PAirpcapHandle ah, AirpcapChannelInfo **cInfo, PULONG nInfo); - -/* - * Airpcap wrapper, get supported channels formatted into an array - */ -Dot11Channel* -airpcap_if_get_device_supported_channels_array(PAirpcapHandle ah, PULONG pNumSupportedChannels); - -/* - * Airpcap wrapper, used to set the channel of an airpcap adapter - */ -BOOL -airpcap_if_set_device_channel(PAirpcapHandle ah, UINT ch); - -/* - * Airpcap wrapper, used to get the frequency of an airpcap adapter - */ -BOOL -airpcap_if_get_device_channel_ex(PAirpcapHandle ah, PAirpcapChannelInfo pChannelInfo); - -/* - * Airpcap wrapper, used to set the frequency of an airpcap adapter - */ -BOOL -airpcap_if_set_device_channel_ex(PAirpcapHandle ah, AirpcapChannelInfo ChannelInfo); - -/* - * Airpcap wrapper, used to open an airpcap adapter - */ -PAirpcapHandle airpcap_if_open(PCHAR name, PCHAR err); - -/* - * Airpcap wrapper, used to close an airpcap adapter - */ -VOID airpcap_if_close(PAirpcapHandle handle); - -/* - * Retrieve the state of the Airpcap DLL - */ -int -airpcap_get_dll_state(); - -/* - * Airpcap wrapper, used to turn on the led of an airpcap adapter - */ -BOOL airpcap_if_turn_led_on(PAirpcapHandle AdapterHandle, UINT LedNumber); - -/* - * Airpcap wrapper, used to turn off the led of an airpcap adapter - */ -BOOL airpcap_if_turn_led_off(PAirpcapHandle AdapterHandle, UINT LedNumber); - -/* - * This function will create a new airpcap_if_info_t using a name and a description - */ -airpcap_if_info_t* airpcap_if_info_new(char *name, char *description); - -/* - * This function will create a new fake drivers' interface, to load global keys... - */ -airpcap_if_info_t* airpcap_driver_fake_if_info_new(); - -/* - * Used to dinamically load the airpcap library in order link it only when - * it's present on the system. - */ -int load_airpcap(void); - -/* - * This function will use the airpcap.dll to find all the airpcap devices. - * Will return null if no device is found. - */ -GList* -get_airpcap_interface_list(int *err, char **err_str); - -/* - * Returns the ASCII string of a key given the key bites - */ -gchar* -airpcap_get_key_string(AirpcapKey key); - -/* - * Load the configuration for the specified interface - */ -void -airpcap_load_selected_if_configuration(airpcap_if_info_t* if_info); - -/* - * Save the configuration for the specified interface - */ -void -airpcap_save_selected_if_configuration(airpcap_if_info_t* if_info); - -/* - * Used to retrieve the two chars string from interface description - */ -gchar* -airpcap_get_if_string_number(airpcap_if_info_t* if_info); - -/* - * Returns the default airpcap interface of a list, NULL if list is empty - */ -airpcap_if_info_t* -airpcap_get_default_if(GList* airpcap_if_list); - -/* - * Airpcap wrapper, used to save the settings for the selected_if - */ -BOOL -airpcap_if_set_device_keys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection); - -/* - * Airpcap wrapper, used to save the settings for the selected_if - */ -BOOL -airpcap_if_get_device_keys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, PUINT PKeysCollectionSize); - -/* - * Airpcap wrapper, used to save the settings for the selected_if - */ -BOOL -airpcap_if_set_driver_keys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection); - -/* - * Airpcap wrapper, used to save the settings for the selected_if - */ -BOOL -airpcap_if_get_driver_keys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, PUINT PKeysCollectionSize); - -/* - * Airpcap wrapper, used to get the decryption enabling of an airpcap driver - */ -BOOL -airpcap_if_get_driver_decryption_state(PAirpcapHandle ah, PAirpcapDecryptionState PEnable); -/* - * Airpcap wrapper, used to set the decryption enabling of an airpcap driver - */ -BOOL -airpcap_if_set_driver_decryption_state(PAirpcapHandle ah, AirpcapDecryptionState Enable); - -/* - * Save the configuration for the specified interface - */ -void -airpcap_save_driver_if_configuration(airpcap_if_info_t* fake_if_info); - -/* - * Free an instance of airpcap_if_info_t - */ -void -airpcap_if_info_free(airpcap_if_info_t *if_info); - -/* - * This function will tell the airpcap driver the key list to use - * This will be stored into the registry... - */ -BOOL -write_wlan_driver_wep_keys_to_registry(GList* key_list); - -/* - * Clear keys and decryption status for the specified interface - */ -void -airpcap_if_clear_decryption_settings(airpcap_if_info_t* info_if); - -/* - * Function used to save to the preference file the Decryption Keys. - */ -int -save_wlan_driver_wep_keys(); - -/* - * Function used to save to the preference file the Decryption Keys. - */ -int -save_wlan_wireshark_wep_keys(GList* key_ls); - -/* - * DECRYPTION KEYS FUNCTIONS - */ -/* - * This function is used for DEBUG PURPOSES ONLY!!! - */ -void -print_key_list(GList* key_list); - -/* - * Retrieves a GList of decryption_key_t structures containing infos about the - * keys for the given adapter... returns NULL if no keys are found. - */ -GList* -get_airpcap_device_keys(airpcap_if_info_t* if_info); - -/* - * Retrieves a GList of decryption_key_t structures containing infos about the - * keys for the global AirPcap driver... returns NULL if no keys are found. - */ -GList* -get_airpcap_driver_keys(); - -/* - * Returns the list of the decryption keys specified for wireshark, NULL if - * no key is found - */ -GList* -get_wireshark_keys(); - -/* - * Tests if two collection of keys are equal or not, to be considered equals, they have to - * contain the same keys in the SAME ORDER! (If both lists are NULL, which means empty will - * return TRUE) - */ -gboolean -key_lists_are_equal(GList* list1, GList* list2); - -/* - * Merges two lists of keys. If a key is found multiple times, it will just appear once! - */ -GList* -merge_key_list(GList* list1, GList* list2); - -/* - * If the given key is contained in the list, returns TRUE. - * Returns FALSE otherwise. - */ -gboolean -key_is_in_list(decryption_key_t *dk,GList *list); - -/* - * Returns TRUE if keys are equals, FALSE otherwise - */ -gboolean -keys_are_equals(decryption_key_t *k1,decryption_key_t *k2); - -/* - * Use this function to free a key list. - */ -void -free_key_list(GList *list); - -/* - * Returns TRUE if the Wireshark decryption is active, FALSE otherwise - */ -gboolean -wireshark_decryption_on(); - -/* - * Returns TRUE if the AirPcap decryption for the current adapter is active, FALSE otherwise - */ -gboolean -airpcap_decryption_on(); - -/* - * Enables decryption for Wireshark if on_off is TRUE, disables it otherwise. - */ -void -set_wireshark_decryption(gboolean on_off); - -/* - * Enables decryption for all the adapters if on_off is TRUE, disables it otherwise. - */ -gboolean -set_airpcap_decryption(gboolean on_off); - -/* - * Adds compiled version string to str - */ -void -get_compiled_airpcap_version(GString *str); - -void -get_runtime_airpcap_version(GString *str); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/alert_box.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/alert_box.h deleted file mode 100644 index 62ee1efb..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/alert_box.h +++ /dev/null @@ -1,70 +0,0 @@ -/* alert_box.h - * Routines to put up various "standard" alert boxes used in multiple - * places - * - * $Id: alert_box.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __ALERT_BOX_H__ -#define __ALERT_BOX_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* - * Alert box for general errors. - */ -extern void failure_alert_box(const char *msg_format, va_list ap); - -/* - * Alert box for a failed attempt to open or create a file. - * "err" is assumed to be a UNIX-style errno; "for_writing" is TRUE if - * the file is being opened for writing and FALSE if it's being opened - * for reading. - */ -extern void open_failure_alert_box(const char *filename, int err, - gboolean for_writing); - -/* - * Alert box for a failed attempt to read a file. - * "err" is assumed to be a UNIX-style errno. - */ -extern void read_failure_alert_box(const char *filename, int err); - -/* - * Alert box for a failed attempt to write to a file. - * "err" is assumed to be a UNIX-style errno. - */ -extern void write_failure_alert_box(const char *filename, int err); - -/* - * Alert box for an invalid display filter expression. - * Assumes "dfilter_error_msg" has been set by "dfilter_compile()" to the - * error message for the filter. - */ -extern void bad_dfilter_alert_box(const char *dftext); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __ALERT_BOX_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-pcap-util-int.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-pcap-util-int.h deleted file mode 100644 index 697f2ede..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-pcap-util-int.h +++ /dev/null @@ -1,56 +0,0 @@ -/* capture-pcap-util-int.h - * Definitions of routines internal to the libpcap/WinPcap utilities - * - * $Id: capture-pcap-util-int.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __PCAP_UTIL_INT_H__ -#define __PCAP_UTIL_INT_H__ - -#ifdef HAVE_LIBPCAP -#ifdef HAVE_PCAP_REMOTE -#ifdef HAVE_CONFIG_H -#include -#endif -#include -#endif - -extern if_info_t *if_info_new(char *name, char *description); -extern void if_info_add_address(if_info_t *if_info, struct sockaddr *addr); -#ifdef HAVE_PCAP_FINDALLDEVS -#ifdef HAVE_PCAP_REMOTE -extern GList *get_interface_list_findalldevs_ex(const char *source, - struct pcap_rmtauth *auth, int *err, char **err_str); -#else -extern GList *get_interface_list_findalldevs(int *err, char **err_str); -#endif -#endif - -/* - * Get an error message string for a CANT_GET_INTERFACE_LIST error from - * "get_interface_list()". This is used to let the error message string - * be platform-dependent. - */ -extern gchar *cant_get_if_list_error_message(const char *err_str); - -#endif /* HAVE_LIBPCAP */ - -#endif /* __PCAP_UTIL_INT_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-pcap-util.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-pcap-util.h deleted file mode 100644 index fd480733..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-pcap-util.h +++ /dev/null @@ -1,131 +0,0 @@ -/* capture-pcap-util.h - * Utility definitions for packet capture - * - * $Id: capture-pcap-util.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __PCAP_UTIL_H__ -#define __PCAP_UTIL_H__ - -#ifdef HAVE_LIBPCAP - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#include - -#include - -/* - * XXX - this is also the traditional default snapshot size in - * tcpdump - but, if IPv6 is enabled, it defaults to 96, to get an - * IPv6 header + TCP + 22 extra bytes. - * - * Some libpcap versions for particular capture devices might happen - * to impose a minimum, but it's not always 68. - */ -#define MIN_PACKET_SIZE 68 /* minimum amount of packet data we can read */ - -/* - * The list of interfaces returned by "get_interface_list()" is - * a list of these structures. - */ -typedef struct { - char *name; /* e.g. "eth0" */ - char *description; /* from OS, e.g. "Local Area Connection" or NULL */ - GSList *ip_addr; /* containing address values of if_addr_t */ - gboolean loopback; /* TRUE if loopback, FALSE otherwise */ -} if_info_t; - -/* - * An address in the "ip_addr" list. - */ -typedef struct { - address_type type; /* AT_IPv4 or AT_IPv6 */ - union { - guint32 ip4_addr; /* 4 byte IP V4 address, or */ - guint8 ip6_addr[16];/* 16 byte IP V6 address */ - } ip_addr; -} if_addr_t; - -GList *get_interface_list(int *err, char **err_str); -#ifdef HAVE_PCAP_REMOTE -GList *get_remote_interface_list(const char *hostname, const char *port, - int auth_type, const char *username, - const char *passwd, int *err, char **err_str); -#endif - -/* Error values from "get_interface_list()/capture_interface_list()". */ -#define CANT_GET_INTERFACE_LIST 1 /* error getting list */ -#define NO_INTERFACES_FOUND 2 /* list is empty */ -#define CANT_RUN_DUMPCAP 3 /* problem running dumpcap */ - -void free_interface_list(GList *if_list); - -/* - * The list of data link types returned by "get_pcap_linktype_list()" is - * a list of these structures. - */ -typedef struct { - int dlt; /* e.g. DLT_EN10MB (which is 1) */ - char *name; /* e.g. "EN10MB" or "DLT 1" */ - char *description; /* descriptive name from wiretap e.g. "Ethernet", NULL if unknown */ -} data_link_info_t; - -GList *get_pcap_linktype_list(const char *devname, char **err_str); -void free_pcap_linktype_list(GList *linktype_list); - -/* get/set the link type of an interface */ -/* (only used in capture_loop.c / capture-pcap-util.c) */ -int get_pcap_linktype(pcap_t *pch, const char *devname); -const char *set_pcap_linktype(pcap_t *pch, char *devname, int dlt); - - -#ifdef HAVE_PCAP_DATALINK_VAL_TO_NAME -const char *linktype_val_to_name(int dlt); -#endif -#ifdef HAVE_PCAP_DATALINK_NAME_TO_VAL -int linktype_name_to_val(const char *linktype); -#endif - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* HAVE_LIBPCAP */ - -/* - * Append to a GString an indication of the version of libpcap/WinPcap - * with which we were compiled, if we were, or an indication that we - * weren't compiled with libpcap/WinPcap, if we weren't. - */ -extern void get_compiled_pcap_version(GString *str); - -/* - * Append to a GString an indication of the version of libpcap/WinPcap - * with which we're running, or an indication that we're not running - * with libpcap/WinPcap, if we were compiled with libpcap/WinPcap, - * or nothing, if we weren't compiled with libpcap/WinPcap. - */ -extern void get_runtime_pcap_version(GString *str); - -#endif /* __PCAP_UTIL_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-wpcap.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-wpcap.h deleted file mode 100644 index 94e51244..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-wpcap.h +++ /dev/null @@ -1,34 +0,0 @@ -/* capture-wpcap.h - * - * $Id: capture-wpcap.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2001 Gerald Combs - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef CAPTURE_WPCAP_H -#define CAPTURE_WPCAP_H - -extern gboolean has_wpcap; - - -void -load_wpcap(void); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture.h deleted file mode 100644 index 86a0ef1e..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture.h +++ /dev/null @@ -1,118 +0,0 @@ -/* capture.h - * Definitions for packet capture windows - * - * $Id: capture.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* This file should only be included if libpcap is present */ - -#ifndef __CAPTURE_H__ -#define __CAPTURE_H__ - -/** @file - * Capture related things. - */ - -#include "capture_opts.h" - -/** - * Start a capture session. - * - * @param capture_opts the numerous capture options - * @return TRUE if the capture starts successfully, FALSE otherwise. - */ -extern gboolean capture_start(capture_options *capture_opts); - -/** Stop a capture session (usually from a menu item). */ -extern void capture_stop(capture_options *capture_opts); - -/** Restart the current captured packets and start again. */ -extern void capture_restart(capture_options *capture_opts); - -/** Terminate the capture child cleanly when exiting. */ -extern void capture_kill_child(capture_options *capture_opts); - -/** - * Capture child told us we have a new (or the first) capture file. - */ -extern gboolean capture_input_new_file(capture_options *capture_opts, gchar *new_file); - -/** - * Capture child told us we have new packets to read. - */ -extern void capture_input_new_packets(capture_options *capture_opts, int to_read); - -/** - * Capture child told us how many dropped packets it counted. - */ -extern void capture_input_drops(capture_options *capture_opts, int dropped); - -/** - * Capture child told us that an error has occurred while starting the capture. - */ -extern void capture_input_error_message(capture_options *capture_opts, char *error_message, char *secondary_error_msg); - -/** - * Capture child told us that an error has occurred while parsing a - * capture filter when starting/running the capture. - */ -extern void capture_input_cfilter_error_message(capture_options *capture_opts, char *error_message); - -/** - * Capture child closed its side of the pipe, do the required cleanup. - */ -extern void capture_input_closed(capture_options *capture_opts); - -#ifdef HAVE_LIBPCAP -/** - * Fetch the interface list from a child process. - */ -extern GList *capture_interface_list(int *err, char **err_str); - -/** - * Fetch the linktype list for the specified interface from a child process. - */ -extern GList *capture_pcap_linktype_list(const char *devname, char **err_str); - - -struct if_stat_cache_s; -typedef struct if_stat_cache_s if_stat_cache_t; - -/** - * Start gathering capture statistics for the interfaces specified. - * @param A GList of if_info_t items - * @return A pointer to the statistics state data. - */ -extern if_stat_cache_t * capture_stat_start(GList *if_list); - -/** - * Fetch capture statistics, similar to pcap_stats(). - */ -struct pcap_stat; /* Stub in case we don't or haven't yet included pcap.h */ -extern gboolean capture_stats(if_stat_cache_t *sc, char *ifname, struct pcap_stat *ps); - -/** - * Stop gathering capture statistics. - */ -void capture_stat_stop(if_stat_cache_t *sc); -#endif /* HAVE_LIBPCAP */ - -#endif /* capture.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_errs.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_errs.h deleted file mode 100644 index be631336..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_errs.h +++ /dev/null @@ -1,34 +0,0 @@ -/* capture_errs.h - * Declarations of routines to return error and warning messages for - * packet capture - * - * $Id: capture_errs.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_LIBPCAP - -#ifdef _WIN32 -/* error message, if WinPcap couldn't be loaded */ -/* will use g_strdup, don't forget to g_free the returned string! */ -extern char *cant_load_winpcap_err(const char *app_name); -#endif /* _WIN32 */ - -#endif /* HAVE_LIBPCAP */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_info.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_info.h deleted file mode 100644 index 8d83d0f7..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_info.h +++ /dev/null @@ -1,76 +0,0 @@ -/* capture_info.h - * capture info functions - * - * $Id: capture_info.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - - -/** @file - * - * capture info functions - * - */ - -#ifndef __CAPTURE_INFO_H__ -#define __CAPTURE_INFO_H__ - - -/* open the info - init values (wtap, counts), create dialog */ -extern void capture_info_open(const char *iface); - -/* new file arrived - (eventually close old wtap), open wtap */ -extern gboolean capture_info_new_file(const char *new_filename); - -/* new packets arrived - read from wtap, count */ -extern void capture_info_new_packets(int to_read); - -/* close the info - close wtap, destroy dialog */ -extern void capture_info_close(void); - - - -/** Current Capture info. */ -typedef struct { - /* handle */ - gpointer ui; /**< user interface handle */ - - /* capture info */ - packet_counts *counts; /**< protocol specific counters */ - time_t running_time; /**< running time since last update */ - gint new_packets; /**< packets since last update */ -} capture_info; - - -/** Create the capture info dialog */ -extern void capture_info_ui_create( -capture_info *cinfo, -const gchar *iface); - -/** Update the capture info counters in the dialog */ -extern void capture_info_ui_update( -capture_info *cinfo); - -/** Destroy the capture info dialog again */ -extern void capture_info_ui_destroy( -capture_info *cinfo); - - -#endif /* capture_info.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_opts.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_opts.h deleted file mode 100644 index e813688e..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_opts.h +++ /dev/null @@ -1,194 +0,0 @@ -/* capture_opts.h - * Capture options (all parameters needed to do the actual capture) - * - * $Id: capture_opts.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - - -/** @file - * - * Capture options (all parameters needed to do the actual capture) - * - */ - -#ifndef __CAPTURE_OPTS_H__ -#define __CAPTURE_OPTS_H__ - - -/* Current state of capture engine. XXX - differentiate states */ -typedef enum { - CAPTURE_STOPPED, /**< stopped */ - CAPTURE_PREPARING, /**< preparing, but still no response from capture child */ - CAPTURE_RUNNING /**< capture child signalled ok, capture is running now */ -} capture_state; - -#ifdef HAVE_PCAP_REMOTE -/* Type of capture source */ -typedef enum { - CAPTURE_IFLOCAL, /**< Local network interface */ - CAPTURE_IFREMOTE /**< Remote network interface */ -} capture_source; - -/* Type of RPCAPD Authentication */ -typedef enum { - CAPTURE_AUTH_NULL, /**< No authentication */ - CAPTURE_AUTH_PWD /**< User/password authentication */ -} capture_auth; - -#ifdef HAVE_PCAP_SETSAMPLING -/** - * Method of packet sampling (dropping some captured packets), - * may require additional integer parameter, marked here as N - */ -typedef enum { - CAPTURE_SAMP_NONE, /**< No sampling - capture all packets */ - CAPTURE_SAMP_BY_COUNT, /**< Counter-based sampling - - capture 1 packet from every N */ - CAPTURE_SAMP_BY_TIMER /**< Timer-based sampling - - capture no more than 1 packet - in N milliseconds */ -} capture_sampling; -#endif -#endif - -/** Capture options coming from user interface */ -typedef struct capture_options_tag { - /* general */ - void *cf; /**< handle to cfile (note: untyped handle) */ - gboolean has_cfilter; /**< TRUE if capture filter specified on command line */ - gchar *cfilter; /**< Capture filter string */ - gchar *iface; /**< the network interface to capture from */ - gchar *iface_descr; /**< A human readable description of iface. - *< NOTE: capture_opts.c is not able to - *< set this field because doing so - *< requires too many dependencies. - *< Readers of this field should use - *< get_iface_description() from - *< "capture_ui_utils.h" to access it. */ -#ifdef HAVE_PCAP_REMOTE - capture_source src_type; /**< Capturing on remote interface */ - gchar *remote_host; /**< Host name or network address - *< for remote capturing */ - gchar *remote_port; /**< TCP port of remote RPCAP server */ - - capture_auth auth_type; - gchar *auth_username; - gchar *auth_password; /**< Remote authentication parameters */ - - gboolean datatx_udp; /**< Whether to use UDP for data transfer */ - gboolean nocap_rpcap; /**< Whether to capture RPCAP own traffic */ - gboolean nocap_local; /**< TODO: Whether to capture local traffic */ -#ifdef HAVE_PCAP_SETSAMPLING - capture_sampling sampling_method; /**< PCAP packet sampling method */ - int sampling_param; /**< PCAP packet sampling parameter */ -#endif -#endif -#ifdef _WIN32 - int buffer_size; /**< the capture buffer size (MB) */ -#endif - gboolean has_snaplen; /**< TRUE if maximum capture packet length - is specified */ - int snaplen; /**< Maximum captured packet length */ - gboolean promisc_mode; /**< Capture in promiscuous mode */ - int linktype; /**< Data link type to use, or -1 for - "use default" */ - gboolean saving_to_file; /**< TRUE if capture is writing to a file */ - gchar *save_file; /**< the capture file name */ - - /* GUI related */ - gboolean real_time_mode; /**< Update list of packets in real time */ - gboolean show_info; /**< show the info dialog */ - gboolean quit_after_cap; /**< Makes a "capture only mode". Implies -k */ - gboolean restart; /**< restart after closing is done */ - - /* multiple files (and ringbuffer) */ - gboolean multi_files_on; /**< TRUE if ring buffer in use */ - - gboolean has_file_duration; /**< TRUE if ring duration specified */ - gint32 file_duration; /**< Switch file after n seconds */ - gboolean has_ring_num_files; /**< TRUE if ring num_files specified */ - guint32 ring_num_files; /**< Number of multiple buffer files */ - - /* autostop conditions */ - gboolean has_autostop_files; /**< TRUE if maximum number of capture files - are specified */ - gint32 autostop_files; /**< Maximum number of capture files */ - - gboolean has_autostop_packets; /**< TRUE if maximum packet count is - specified */ - int autostop_packets; /**< Maximum packet count */ - gboolean has_autostop_filesize; /**< TRUE if maximum capture file size - is specified */ - gint32 autostop_filesize; /**< Maximum capture file size */ - gboolean has_autostop_duration; /**< TRUE if maximum capture duration - is specified */ - gint32 autostop_duration; /**< Maximum capture duration */ - - /* internally used (don't touch from outside) */ - int fork_child; /**< If not -1, in parent, process ID of child */ -#ifdef _WIN32 - int signal_pipe_write_fd; /**< the pipe to signal the child */ -#endif - capture_state state; /**< current state of the capture engine */ - gboolean output_to_pipe; /**< save_file is a pipe (named or stdout) */ -#ifndef _WIN32 - uid_t owner; /**< owner of the cfile */ - gid_t group; /**< group of the cfile */ -#endif -} capture_options; - -/* initialize the capture_options with some reasonable values */ -extern void -capture_opts_init(capture_options *capture_opts, void *cfile); - -/* set a command line option value */ -extern int -capture_opts_add_opt(capture_options *capture_opts, int opt, const char *optarg, gboolean *start_capture); - -/* log content of capture_opts */ -extern void -capture_opts_log(const char *log_domain, GLogLevelFlags log_level, capture_options *capture_opts); - -/* list link layer types */ -extern int -capture_opts_list_link_layer_types(capture_options *capture_opts, gboolean machine_readable); - -/* list interfaces */ -extern int -capture_opts_list_interfaces(gboolean machine_readable); - -/* print interface statistics */ -extern int -capture_opts_print_statistics(gboolean machine_readable); - -/* trim the snaplen entry */ -extern void -capture_opts_trim_snaplen(capture_options *capture_opts, int snaplen_min); - -/* trim the ring_num_files entry */ -extern void -capture_opts_trim_ring_num_files(capture_options *capture_opts); - -/* trim the interface entry */ -extern gboolean -capture_opts_trim_iface(capture_options *capture_opts, const char *capture_device); - -#endif /* capture_opts.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_stop_conditions.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_stop_conditions.h deleted file mode 100644 index 1e6e1f32..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_stop_conditions.h +++ /dev/null @@ -1,29 +0,0 @@ -/* capture_stop_conditions.h - * Implementation for 'stop condition handler'. - * - * $Id: capture_stop_conditions.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -void init_capture_stop_conditions(void); -void cleanup_capture_stop_conditions(void); - -extern const char* CND_CLASS_TIMEOUT; -extern const char* CND_CLASS_CAPTURESIZE; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_sync.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_sync.h deleted file mode 100644 index 6f2f72fb..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_sync.h +++ /dev/null @@ -1,87 +0,0 @@ -/* capture_sync.h - * Synchronisation between Wireshark capture parent and child instances - * - * $Id: capture_sync.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - - -/** @file - * - * Sync mode capture (internal interface). - * - * Will start a new Wireshark child instance which will do the actual capture - * work. - */ - -#ifndef __CAPTURE_SYNC_H__ -#define __CAPTURE_SYNC_H__ - - -/** - * Start a new capture session. - * Create a capture child which is doing the real capture work. - * The various capture_input_... functions will be called, if something had - * happened. - * - * Most of the parameters are passed through the global capture_opts. - * - * @param capture_opts the options - * @return TRUE if a capture could be started, FALSE if not - */ -extern gboolean -sync_pipe_start(capture_options *capture_opts); - -/** User wants to stop capturing, gracefully close the capture child */ -extern void -sync_pipe_stop(capture_options *capture_opts); - -/** User wants to stop the program, just kill the child as soon as possible */ -extern void -sync_pipe_kill(int fork_child); - -/** Has the parent signalled the child to stop? */ -#define SIGNAL_PIPE_CTRL_ID_NONE "none" -#ifdef _WIN32 -#define SIGNAL_PIPE_FORMAT "\\\\.\\pipe\\wireshark.%s.signal" -#endif - -/** Get an interface list using dumpcap */ -extern int -sync_interface_list_open(gchar **msg); - -/** Get a linktype list using dumpcap */ -extern int -sync_linktype_list_open(const gchar *ifname, gchar **msg); - -/** Start getting interface statistics using dumpcap. */ -extern int -sync_interface_stats_open(int *read_fd, int *fork_child, gchar **msg); - -/** Stop gathering statistics. */ -extern int -sync_interface_stats_close(int *read_fd, int *fork_child, gchar **msg); - -/** Read a line from a pipe, similar to fgets. Non-blocking. */ -extern int -sync_pipe_gets_nonblock(int pipe, char *bytes, int max); - - -#endif /* capture_sync.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_ui_utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_ui_utils.h deleted file mode 100644 index 5da23b2a..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_ui_utils.h +++ /dev/null @@ -1,89 +0,0 @@ -/* capture_ui_utils.c - * Declarations of utilities for capture user interfaces - * - * $Id: capture_ui_utils.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __CAPTURE_UI_UTILS_H__ -#define __CAPTURE_UI_UTILS_H__ - -#include "capture_opts.h" - -/** @file - * GList of available capture interfaces. - */ - -/** Return as descriptive a name for an interface as we can get. - * If the user has specified a comment, use that. Otherwise, - * if get_interface_list() supplies a description, use that, - * otherwise use the interface name. - * - * @param if_name The name of the interface. - * - * @return The descriptive name (must be g_free'd later) - */ -char *get_interface_descriptive_name(const char *if_name); - -/** Build the GList of available capture interfaces. - * - * @param if_list An interface list from get_interface_list(). - * @param do_hide Hide the "hidden" interfaces. - * - * @return A list of if_info_t structs (use free_capture_combo_list() later). - */ -GList *build_capture_combo_list(GList *if_list, gboolean do_hide); - -/** Free the GList from build_capture_combo_list(). - * - * @param combo_list the interface list from build_capture_combo_list() - */ -void free_capture_combo_list(GList *combo_list); - - -/** Given text that contains an interface name possibly prefixed by an - * interface description, extract the interface name. - * - * @param if_text A string containing the interface description + name. - * This is usually the data from one of the list elements returned by - * build_capture_combo_list(). - * - * @return The raw interface name, without description (must NOT be g_free'd later) - */ -const char *get_if_name(const char *if_text); - -/** Convert plain interface name to the displayed name in the combo box. - * - * @param if_list The list of interfaces returned by build_capture_combo_list() - * @param if_name The name of the interface. - * - * @return The descriptive name (must be g_free'd later) - */ -char *build_capture_combo_name(GList *if_list, gchar *if_name); - -/** Return the interface description (after setting it if not already set) - * - * @param capture_opts The capture_options structure that contains the used interface - * - * @return A pointer to capture_ops->iface_descr - */ -const char *get_iface_description(capture_options *capture_opts); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_wpcap_packet.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_wpcap_packet.h deleted file mode 100644 index 38d1cd9d..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_wpcap_packet.h +++ /dev/null @@ -1,47 +0,0 @@ -/* capture_wpcap_packet.h - * - * $Id: capture_wpcap_packet.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2001 Gerald Combs - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef CAPTURE_WPCAP_PACKET_H -#define CAPTURE_WPCAP_PACKET_H - - -extern void wpcap_packet_load(void); - -/* get the packet.dll version info */ -extern char *wpcap_packet_get_version(void); - -/* open the interface */ -extern void * wpcap_packet_open(char *if_name); - -/* close the interface */ -extern void wpcap_packet_close(void * adapter); - -extern int wpcap_packet_request(void *a, ULONG Oid, int set, char *value, unsigned int *length); - -extern int wpcap_packet_request_uint(void *a, ULONG Oid, UINT *value); - -extern int wpcap_packet_request_ulong(void *a, ULONG Oid, ULONG *value); - - -#endif /* CAPTURE_WPCAP_PACKET_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/cfile.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/cfile.h deleted file mode 100644 index 0b388d5d..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/cfile.h +++ /dev/null @@ -1,91 +0,0 @@ -/* cfile.h - * capture_file definition & GUI-independent manipulation - * - * $Id: cfile.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __CFILE_H__ -#define __CFILE_H__ - -/* Current state of file. */ -typedef enum { - FILE_CLOSED, /* No file open */ - FILE_READ_IN_PROGRESS, /* Reading a file we've opened */ - FILE_READ_ABORTED, /* Read aborted by user */ - FILE_READ_DONE /* Read completed */ -} file_state; - -/* Character set for text search. */ -typedef enum { - SCS_ASCII_AND_UNICODE, - SCS_ASCII, - SCS_UNICODE - /* add EBCDIC when it's implemented */ -} search_charset_t; - -typedef struct _capture_file { - file_state state; /* Current state of capture file */ - gchar *filename; /* Name of capture file */ - gboolean is_tempfile; /* Is capture file a temporary file? */ - gboolean user_saved;/* If capture file is temporary, has it been saved by user yet? */ - gint64 f_datalen; /* Size of capture file data (uncompressed) */ - guint16 cd_t; /* File type of capture file */ - int lnk_t; /* Link-layer type with which to save capture */ - guint32 vers; /* Version. For tcpdump minor is appended to major */ - int count; /* Total number of frames */ - int displayed_count; /* Number of displayed frames */ - int marked_count; /* Number of marked frames */ - gboolean drops_known; /* TRUE if we know how many packets were dropped */ - guint32 drops; /* Dropped packets */ - nstime_t elapsed_time;/* Elapsed time */ - gboolean has_snap; /* TRUE if maximum capture packet length is known */ - int snap; /* Maximum captured packet length */ - wtap *wth; /* Wiretap session */ - dfilter_t *rfcode; /* Compiled read (display) filter program */ - gchar *dfilter; /* Display filter string */ - /* search */ - gchar *sfilter; /* Search filter string */ - gboolean sbackward; /* TRUE if search is backward, FALSE if forward */ - gboolean hex; /* TRUE is raw data search is being performed */ - gboolean string; /* TRUE is text search is being performed */ - guint32 search_pos; /* Position of last character found in search */ - search_charset_t scs_type; /* Character set for text search */ - gboolean case_type; /* TRUE if case-insensitive text search */ - gboolean decode_data; /* TRUE if searching protocol tree text */ - gboolean summary_data; /* TRUE if searching Info column text */ - /* packet data */ - union wtap_pseudo_header pseudo_header; /* Packet pseudo_header */ - guint8 pd[WTAP_MAX_PACKET_SIZE]; /* Packet data */ - GMemChunk *plist_chunk; /* Memory chunk for frame_data structures */ - frame_data *plist; /* Packet list */ - frame_data *plist_end; /* Last packet in list */ - frame_data *first_displayed; /* First frame displayed */ - frame_data *last_displayed; /* Last frame displayed */ - column_info cinfo; /* Column formatting information */ - frame_data *current_frame; /* Frame data for current frame */ - epan_dissect_t *edt; /* Protocol dissection for currently selected packet */ - field_info *finfo_selected; /* Field info for currently selected field */ - struct ph_stats_s* pstats; /* accumulated stats (reset on redisplay in GUI)*/ -} capture_file; - -void init_cap_file(capture_file *); - -#endif /* cfile.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/clopts_common.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/clopts_common.h deleted file mode 100644 index 825164bc..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/clopts_common.h +++ /dev/null @@ -1,40 +0,0 @@ -/* clopts_common.h - * Handle command-line arguments common to Wireshark and TShark - * - * $Id: clopts_common.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __PROTO_DUMPOPTS_H__ -#define __PROTO_DUMPOPTS_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -int get_natural_int(const char *string, const char *name); - -int get_positive_int(const char *string, const char *name); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __PROTO_DUMPOPTS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/cmdarg_err.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/cmdarg_err.h deleted file mode 100644 index 5bd43cc0..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/cmdarg_err.h +++ /dev/null @@ -1,56 +0,0 @@ -/* cmdarg_err.h - * Declarations of routines to report command-line errors. - * - * $Id: cmdarg_err.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __CMDARG_ERR_H__ -#define __CMDARG_ERR_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* - * Report an error in command-line arguments. - */ -#if __GNUC__ >= 2 -extern void cmdarg_err(const char *fmt, ...) - __attribute__((format (printf, 1, 2))); -#else -extern void cmdarg_err(const char *fmt, ...); -#endif - -/* - * Report additional information for an error in command-line arguments. - */ -#if __GNUC__ >= 2 -extern void cmdarg_err_cont(const char *fmt, ...) - __attribute__((format (printf, 1, 2))); -#else -extern void cmdarg_err_cont(const char *fmt, ...); -#endif - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __CMDARG_ERR_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/color.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/color.h deleted file mode 100644 index a1c09b2a..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/color.h +++ /dev/null @@ -1,55 +0,0 @@ -/* color.h - * Definitions for "toolkit-independent" colors - * - * $Id: color.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __COLOR_H__ -#define __COLOR_H__ - -/* - * Data structure holding RGB value for a color. - * - * XXX - yes, I know, there's a "pixel" value in there as well; for - * now, it's intended to look just like a GdkColor but not to require - * that any GTK+ header files be included in order to use it. - * The way we handle colors needs to be cleaned up somewhat, in order - * to keep toolkit-specific stuff separate from toolkit-independent stuff. - */ -typedef struct { - guint32 pixel; - guint16 red; - guint16 green; - guint16 blue; -} color_t; - -/** Initialize a color with R, G, and B values, including any toolkit-dependent - ** work that needs to be done. - * - * @param color the color_t to be filled - * @param red the red value for the color - * @param green the green value for the color - * @param blue the blue value for the color - * @return TRUE if it succeeds, FALSE if it fails - */ -gboolean initialize_color(color_t *color, guint16 red, guint16 green, guint16 blue); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/color_filters.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/color_filters.h deleted file mode 100644 index 878ce97f..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/color_filters.h +++ /dev/null @@ -1,196 +0,0 @@ -/* color_filters.h - * Definitions for color filters - * - * $Id: color_filters.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#ifndef __COLOR_FILTERS_H__ -#define __COLOR_FILTERS_H__ - -#define TEMP_COLOR_PREFIX "___tmp_color_filter___" -/** @file - * Color filters. - */ - -/* Data for a color filter. */ -typedef struct _color_filter { - gchar *filter_name; /* name of the filter */ - gchar *filter_text; /* text of the filter expression */ - color_t bg_color; /* background color for packets that match */ - color_t fg_color; /* foreground color for packets that match */ - gboolean disabled; /* set if the filter is disabled */ - gboolean selected; /* set if the filter is selected in the color dialog box */ - - /* only used inside of color_filters.c */ - dfilter_t *c_colorfilter; /* compiled filter expression */ - - /* only used outside of color_filters.c (beside init) */ - void *edit_dialog; /* if filter is being edited, dialog - * box for it */ -} color_filter_t; - - -/** Init the color filters (incl. initial read from file). */ -void color_filters_init(void); - -/** Reload the color filters */ -void color_filters_reload(void); - -/** Cleanup remaining color filter zombies */ -void color_filters_cleanup(void); - -/** Color filters currently used? - * - * @return TRUE, if filters are used - */ -gboolean color_filters_used(void); - -/** Are there any temporary coloring filters used? - * - * @return TRUE, if temporary coloring filters are used - */ -gboolean tmp_color_filters_used(void); - -/** En-/disable color filters - * - * @param enable TRUE to enable (default) - */ -void -color_filters_enable(gboolean enable); - -/** Set the filter string of a temporary color filter - * - * @param filt_nr a number 1-10 pointing to a temporary color - * @param filter the new filter-string - * @param disabled whether the filter-rule should be disabled - */ -void -color_filters_set_tmp(guint8 filt_nr, gchar *filter, gboolean disabled); - -/** Reset the temporary color filters - * - */ -void -color_filters_reset_tmp(void); - -/* Prime the epan_dissect_t with all the compiler - * color filters of the current filter list. - * - * @param the epan dissector details - */ -void color_filters_prime_edt(epan_dissect_t *edt); - -/** Colorize a specific packet. - * - * @param row the row in the packet list - * @param edt the dissected packet - * @return the matching color filter or NULL - */ -color_filter_t * -color_filters_colorize_packet(gint row, epan_dissect_t *edt); - - - -/** Clone the currently active filter list. - * - * @param user_data will be returned by each call to to color_filter_add_cb() - */ -void color_filters_clone(gpointer user_data); - -/** Load filters (import) from some other filter file. - * - * @param path the path to the import file - * @param user_data will be returned by each call to to color_filter_add_cb() - * @return TRUE, if read succeeded - */ -gboolean color_filters_import(gchar *path, gpointer user_data); - -/** Read filters from the global filter file (not the users file). - * - * @param user_data will be returned by each call to to color_filter_add_cb() - * @return TRUE, if read succeeded - */ -gboolean color_filters_read_globals(gpointer user_data); - -/** A color filter was added (while importing). - * (color_filters.c calls this for every filter coming in) - * - * @param colorf the new color filter - * @param user_data from caller - */ -void color_filter_add_cb (color_filter_t *colorf, gpointer user_data); - - - -/** Apply a changed filter list. - * - * @param tmp_cfl the temporary color filter list to apply - * @param edit_cfl the edited permanent color filter list to apply - */ -void color_filters_apply(GSList *tmp_cfl, GSList *edit_cfl); - -/** Save filters in users filter file. - * - * @param cfl the filter list to write - * @return TRUE if write succeeded - */ -gboolean color_filters_write(GSList *cfl); - -/** Save filters (export) to some other filter file. - * - * @param path the path to the filter file - * @param cfl the filter list to write - * @param only_selected TRUE if only the selected filters should be saved - * @return TRUE, if write succeeded - */ -gboolean color_filters_export(gchar *path, GSList *cfl, gboolean only_selected); - - - -/** Create a new color filter (g_malloc'ed). - * - * @param name the name of the filter - * @param filter_string the filter string - * @param bg_color background color - * @param fg_color foreground color - * @return the new color filter - */ -color_filter_t *color_filter_new( - const gchar *name, const gchar *filter_string, - color_t *bg_color, color_t *fg_color, gboolean disabled); - -/** Delete a single color filter (g_free'ed). - * - * @param colorf the color filter to be removed - */ -void color_filter_delete(color_filter_t *colorf); - - - - -/** Delete a filter list including all entries. - * - * @param cfl the filter list to delete - */ -void color_filter_list_delete(GSList **cfl); - - - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/conditions.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/conditions.h deleted file mode 100644 index e07af3b6..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/conditions.h +++ /dev/null @@ -1,134 +0,0 @@ -/* conditions.h - * Header for condition handler. - * - * $Id: conditions.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef CONDITIONS_H -#define CONDITIONS_H - -#include - -#include - -/* forward declaration for type 'condition' */ -typedef struct condition condition; - -/* condition evaluation handler type */ -typedef gboolean (*_cnd_eval)(condition*, va_list); - -/* condition reset handler type */ -typedef void (*_cnd_reset)(condition*); - -/* condition class constructor type */ -typedef condition* (*_cnd_constr)(condition*, va_list); - -/* condition class destructor type */ -typedef void (*_cnd_destr)(condition*); - -/* - * Conditions must be created with this function. They can be created for - * registered classes only. - * - * parameter: const char* - Identification of a registered condition class. - * ... - Any number of class specific initial values. - * returns: Pointer to a initialized condition of the particular class on - * success or NULL on failure. - */ -condition* cnd_new(const char*, ...); - -/* - * Conditions must be deleted with this function when not used anymore. - * - * parameter: condition* - Pointer to a condition created with 'cnd_new()'. - * returns: - - */ -void cnd_delete(condition*); - -/* - * Call this function to check whether or not a particular condition is true. - * - * parameter: condition* - Pointer to an initialized condition. - * ... - Any number of condition specific arguments. - * returns: TRUE - Condition is true. - * FALSE - Condition is false. - */ -gboolean cnd_eval(condition*, ...); - -/* - * Call this function to reset this condition to its initial state, i.e. the - * state it was in right after creation. - * - * parameter: condition* - Pointer to an initialized condition. - * returns: - - */ -void cnd_reset(condition*); - -/* - * Register a new conditon class. - * New conditions of this class can be created by calling 'cnd_new()' and - * supplying the appropriate class id. - * - * parameter: const char* - The class id. - * _cnd_constr - User supplied constructor function for this - * class. - * _cnd_destr - User supplied destructor function for this - * class. - * _cnd_eval - User supplied evaluation handler function for this - class. - * _cnd_reset - User supplied reset handler for this class. - * returns: TRUE - Success. - * FALSE - Failure. - */ -gboolean cnd_register_class(const char*, - _cnd_constr, - _cnd_destr, - _cnd_eval, - _cnd_reset); - -/* - * Unregister a previously registered conditon class. After unregistration - * of a class it is no longer possible to create conditions of this kind by - * calling 'cnd_new()'. - * - * parameter: const char* - An identification for this condition class. - * returns: - - */ -void cnd_unregister_class(const char*); - -/* - * This function returns the user data of the condition. - * - * parameter: condition* - Pointer to an initialized condition. - * returns: void* - Pointer to user data of this condition. - */ -void* cnd_get_user_data(condition*); - -/* - * This function sets the user data of the condition. - * - * parameter: condition* - Pointer to an initialized condition. - * void* - Pointer to user specified data structure. - * returns: - - */ -void cnd_set_user_data(condition*, void*); - -#endif /* CONDITIONS_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h deleted file mode 100644 index cf2ce4a1..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h +++ /dev/null @@ -1,322 +0,0 @@ -/* config.h. Generated from config.h.in by configure. */ -/* config.h.in. Generated from configure.in by autoheader. */ - -/* Directory for data */ -#define DATAFILE_DIR "/usr/local/share/wireshark" - -/* Link plugins statically into Wireshark */ -/* #undef ENABLE_STATIC */ - -/* Format modifier for printing 64-bit numbers */ -/* #undef G_GINT64_MODIFIER */ - -/* Enable AirPDcap (WPA/WPA2 decryption) */ -#define HAVE_AIRPDCAP 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_ARPA_INET_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_ARPA_NAMESER_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_DIRECT_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_DIRENT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_DLFCN_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_FCNTL_H 1 - -/* Define to 1 if you have the `gethostbyname2' function. */ -#define HAVE_GETHOSTBYNAME2 1 - -/* Define to 1 if you have the `getprotobynumber' function. */ -#define HAVE_GETPROTOBYNUMBER 1 - -/* Define to use GNU ADNS library */ -/* #undef HAVE_GNU_ADNS */ - -/* Define to 1 if you have the header file. */ -#define HAVE_GRP_H 1 - -/* Define to use heimdal kerberos */ -/* #undef HAVE_HEIMDAL_KERBEROS */ - -/* Define if you have the iconv() function. */ -#define HAVE_ICONV 1 - -/* Define if inet_ntop() prototype exists */ -#define HAVE_INET_NTOP_PROTO 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the `issetugid' function. */ -/* #undef HAVE_ISSETUGID */ - -/* Define to use kerberos */ -#define HAVE_KERBEROS 1 - -/* Define if krb5.h defines KEYTYPE_ARCFOUR_56 */ -/* #undef HAVE_KEYTYPE_ARCFOUR_56 */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LAUXLIB_H */ - -/* Define to use the libcap library */ -/* #undef HAVE_LIBCAP */ - -/* Define to use libgcrypt */ -#define HAVE_LIBGCRYPT 1 - -/* Define to use gnutls library */ -#define HAVE_LIBGNUTLS 1 - -/* Define to use libpcap library */ -#define HAVE_LIBPCAP 1 - -/* Define to use libpcre library */ -/* #undef HAVE_LIBPCRE */ - -/* Define to use libportaudio library */ -/* #undef HAVE_LIBPORTAUDIO */ - -/* Define to 1 if you have the `smi' library (-lsmi). */ -/* #undef HAVE_LIBSMI */ - -/* Define to use libz library */ -#define HAVE_LIBZ 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LUA5_1_LAUXLIB_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LUA5_1_LUALIB_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LUA5_1_LUA_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LUALIB_H */ - -/* Define to use Lua 5.1 */ -/* #undef HAVE_LUA_5_1 */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LUA_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to use MIT kerberos */ -#define HAVE_MIT_KERBEROS 1 - -/* Define to 1 if you have the `mmap' function. */ -#define HAVE_MMAP 1 - -/* Define to 1 if you have the `mprotect' function. */ -#define HAVE_MPROTECT 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_NETDB_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_NETINET_IN_H 1 - -/* Define to 1 if you have OS X frameworks */ -/* #undef HAVE_OS_X_FRAMEWORKS */ - -/* Define if pcap_breakloop is known */ -#define HAVE_PCAP_BREAKLOOP 1 - -/* Define to 1 if you have the `pcap_createsrcstr' function. */ -/* #undef HAVE_PCAP_CREATESRCSTR */ - -/* Define to 1 if you have the `pcap_datalink_name_to_val' function. */ -#define HAVE_PCAP_DATALINK_NAME_TO_VAL 1 - -/* Define to 1 if you have the `pcap_datalink_val_to_name' function. */ -#define HAVE_PCAP_DATALINK_VAL_TO_NAME 1 - -/* Define to 1 if you have the `pcap_findalldevs' function and a pcap.h that - declares pcap_if_t. */ -#define HAVE_PCAP_FINDALLDEVS 1 - -/* Define to 1 if you have the `pcap_findalldevs_ex' function. */ -/* #undef HAVE_PCAP_FINDALLDEVS_EX */ - -/* Define to 1 if you have the `pcap_freecode' function. */ -#define HAVE_PCAP_FREECODE 1 - -/* Define to 1 if you have the `pcap_get_selectable_fd' function. */ -#define HAVE_PCAP_GET_SELECTABLE_FD 1 - -/* Define to 1 if you have the `pcap_lib_version' function. */ -#define HAVE_PCAP_LIB_VERSION 1 - -/* Define to 1 if you have the `pcap_list_datalinks' function. */ -#define HAVE_PCAP_LIST_DATALINKS 1 - -/* Define to 1 if you have the `pcap_open' function. */ -/* #undef HAVE_PCAP_OPEN */ - -/* Define to 1 if you have the `pcap_open_dead' function. */ -#define HAVE_PCAP_OPEN_DEAD 1 - -/* Define to 1 if you have WinPcap remote capturing support and prefer to use - these new API features. */ -/* #undef HAVE_PCAP_REMOTE */ - -/* Define to 1 if you have the `pcap_setsampling' function. */ -/* #undef HAVE_PCAP_SETSAMPLING */ - -/* Define to 1 if you have the `pcap_set_datalink' function. */ -#define HAVE_PCAP_SET_DATALINK 1 - -/* Define if libpcap version is known */ -#define HAVE_PCAP_VERSION 1 - -/* Define if plugins are enabled */ -#define HAVE_PLUGINS 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_PORTAUDIO_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_PWD_H 1 - -/* Define to 1 to enable remote capturing feature in WinPcap library */ -/* #undef HAVE_REMOTE */ - -/* Define if sa_len field exists in struct sockaddr */ -/* #undef HAVE_SA_LEN */ - -/* Define to 1 if you have the `setresgid' function. */ -#define HAVE_SETRESGID 1 - -/* Define to 1 if you have the `setresuid' function. */ -#define HAVE_SETRESUID 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDARG_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDDEF_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the `sysconf' function. */ -#define HAVE_SYSCONF 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_IOCTL_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_PARAM_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_SOCKET_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_SOCKIO_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TIME_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_UTSNAME_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_WAIT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_UNISTD_H 1 - -/* HTML viewer, e.g. mozilla */ -#define HTML_VIEWER "mozilla" - -/* Define as const if the declaration of iconv() needs const. */ -#define ICONV_CONST - -/* Define if defines PRI[doxu]64 macros */ -#define INTTYPES_H_DEFINES_FORMATS - -/* Define if getopt.h needs to be included */ -/* #undef NEED_GETOPT_H */ - -/* Define if g_ascii_strcasecmp.h needs to be included */ -/* #undef NEED_G_ASCII_STRCASECMP_H */ - -/* Define if g_ascii_strtoull.h needs to be included */ -/* #undef NEED_G_ASCII_STRTOULL_H */ - -/* Define if inet/aton.h needs to be included */ -/* #undef NEED_INET_ATON_H */ - -/* Define if inet/v6defs.h needs to be included */ -/* #undef NEED_INET_V6DEFS_H */ - -/* Define if strerror.h needs to be included */ -/* #undef NEED_STRERROR_H */ - -/* Define if strptime.h needs to be included */ -/* #undef NEED_STRPTIME_H */ - -/* Name of package */ -#define PACKAGE "wireshark" - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "" - -/* Define if we are using version of of the Portaudio library API */ -/* #undef PORTAUDIO_API_1 */ - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Version number of package */ -#define VERSION "1.0.0" - -/* Define to 1 if your processor stores words with the most significant byte - first (like Motorola and SPARC, unlike Intel and VAX). */ -/* #undef WORDS_BIGENDIAN */ - -/* Define as the string to precede external variable declarations in - dynamically-linked libraries */ -#define WS_VAR_IMPORT extern - -/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a - `char[]'. */ -#define YYTEXT_POINTER 1 diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h.in b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h.in deleted file mode 100644 index b5e1fbdc..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h.in +++ /dev/null @@ -1,321 +0,0 @@ -/* config.h.in. Generated from configure.in by autoheader. */ - -/* Directory for data */ -#undef DATAFILE_DIR - -/* Link plugins statically into Wireshark */ -#undef ENABLE_STATIC - -/* Format modifier for printing 64-bit numbers */ -#undef G_GINT64_MODIFIER - -/* Enable AirPDcap (WPA/WPA2 decryption) */ -#undef HAVE_AIRPDCAP - -/* Define to 1 if you have the header file. */ -#undef HAVE_ARPA_INET_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_ARPA_NAMESER_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_DIRECT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_DIRENT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_DLFCN_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_FCNTL_H - -/* Define to 1 if you have the `gethostbyname2' function. */ -#undef HAVE_GETHOSTBYNAME2 - -/* Define to 1 if you have the `getprotobynumber' function. */ -#undef HAVE_GETPROTOBYNUMBER - -/* Define to use GNU ADNS library */ -#undef HAVE_GNU_ADNS - -/* Define to 1 if you have the header file. */ -#undef HAVE_GRP_H - -/* Define to use heimdal kerberos */ -#undef HAVE_HEIMDAL_KERBEROS - -/* Define if you have the iconv() function. */ -#undef HAVE_ICONV - -/* Define if inet_ntop() prototype exists */ -#undef HAVE_INET_NTOP_PROTO - -/* Define to 1 if you have the header file. */ -#undef HAVE_INTTYPES_H - -/* Define to 1 if you have the `issetugid' function. */ -#undef HAVE_ISSETUGID - -/* Define to use kerberos */ -#undef HAVE_KERBEROS - -/* Define if krb5.h defines KEYTYPE_ARCFOUR_56 */ -#undef HAVE_KEYTYPE_ARCFOUR_56 - -/* Define to 1 if you have the header file. */ -#undef HAVE_LAUXLIB_H - -/* Define to use the libcap library */ -#undef HAVE_LIBCAP - -/* Define to use libgcrypt */ -#undef HAVE_LIBGCRYPT - -/* Define to use gnutls library */ -#undef HAVE_LIBGNUTLS - -/* Define to use libpcap library */ -#undef HAVE_LIBPCAP - -/* Define to use libpcre library */ -#undef HAVE_LIBPCRE - -/* Define to use libportaudio library */ -#undef HAVE_LIBPORTAUDIO - -/* Define to 1 if you have the `smi' library (-lsmi). */ -#undef HAVE_LIBSMI - -/* Define to use libz library */ -#undef HAVE_LIBZ - -/* Define to 1 if you have the header file. */ -#undef HAVE_LUA5_1_LAUXLIB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LUA5_1_LUALIB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LUA5_1_LUA_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LUALIB_H - -/* Define to use Lua 5.1 */ -#undef HAVE_LUA_5_1 - -/* Define to 1 if you have the header file. */ -#undef HAVE_LUA_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_MEMORY_H - -/* Define to use MIT kerberos */ -#undef HAVE_MIT_KERBEROS - -/* Define to 1 if you have the `mmap' function. */ -#undef HAVE_MMAP - -/* Define to 1 if you have the `mprotect' function. */ -#undef HAVE_MPROTECT - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETDB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETINET_IN_H - -/* Define to 1 if you have OS X frameworks */ -#undef HAVE_OS_X_FRAMEWORKS - -/* Define if pcap_breakloop is known */ -#undef HAVE_PCAP_BREAKLOOP - -/* Define to 1 if you have the `pcap_createsrcstr' function. */ -#undef HAVE_PCAP_CREATESRCSTR - -/* Define to 1 if you have the `pcap_datalink_name_to_val' function. */ -#undef HAVE_PCAP_DATALINK_NAME_TO_VAL - -/* Define to 1 if you have the `pcap_datalink_val_to_name' function. */ -#undef HAVE_PCAP_DATALINK_VAL_TO_NAME - -/* Define to 1 if you have the `pcap_findalldevs' function and a pcap.h that - declares pcap_if_t. */ -#undef HAVE_PCAP_FINDALLDEVS - -/* Define to 1 if you have the `pcap_findalldevs_ex' function. */ -#undef HAVE_PCAP_FINDALLDEVS_EX - -/* Define to 1 if you have the `pcap_freecode' function. */ -#undef HAVE_PCAP_FREECODE - -/* Define to 1 if you have the `pcap_get_selectable_fd' function. */ -#undef HAVE_PCAP_GET_SELECTABLE_FD - -/* Define to 1 if you have the `pcap_lib_version' function. */ -#undef HAVE_PCAP_LIB_VERSION - -/* Define to 1 if you have the `pcap_list_datalinks' function. */ -#undef HAVE_PCAP_LIST_DATALINKS - -/* Define to 1 if you have the `pcap_open' function. */ -#undef HAVE_PCAP_OPEN - -/* Define to 1 if you have the `pcap_open_dead' function. */ -#undef HAVE_PCAP_OPEN_DEAD - -/* Define to 1 if you have WinPcap remote capturing support and prefer to use - these new API features. */ -#undef HAVE_PCAP_REMOTE - -/* Define to 1 if you have the `pcap_setsampling' function. */ -#undef HAVE_PCAP_SETSAMPLING - -/* Define to 1 if you have the `pcap_set_datalink' function. */ -#undef HAVE_PCAP_SET_DATALINK - -/* Define if libpcap version is known */ -#undef HAVE_PCAP_VERSION - -/* Define if plugins are enabled */ -#undef HAVE_PLUGINS - -/* Define to 1 if you have the header file. */ -#undef HAVE_PORTAUDIO_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_PWD_H - -/* Define to 1 to enable remote capturing feature in WinPcap library */ -#undef HAVE_REMOTE - -/* Define if sa_len field exists in struct sockaddr */ -#undef HAVE_SA_LEN - -/* Define to 1 if you have the `setresgid' function. */ -#undef HAVE_SETRESGID - -/* Define to 1 if you have the `setresuid' function. */ -#undef HAVE_SETRESUID - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDARG_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDDEF_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDINT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDLIB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRINGS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRING_H - -/* Define to 1 if you have the `sysconf' function. */ -#undef HAVE_SYSCONF - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_IOCTL_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_PARAM_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_SOCKET_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_SOCKIO_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_STAT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TIME_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_UTSNAME_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_WAIT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_UNISTD_H - -/* HTML viewer, e.g. mozilla */ -#undef HTML_VIEWER - -/* Define as const if the declaration of iconv() needs const. */ -#undef ICONV_CONST - -/* Define if defines PRI[doxu]64 macros */ -#undef INTTYPES_H_DEFINES_FORMATS - -/* Define if getopt.h needs to be included */ -#undef NEED_GETOPT_H - -/* Define if g_ascii_strcasecmp.h needs to be included */ -#undef NEED_G_ASCII_STRCASECMP_H - -/* Define if g_ascii_strtoull.h needs to be included */ -#undef NEED_G_ASCII_STRTOULL_H - -/* Define if inet/aton.h needs to be included */ -#undef NEED_INET_ATON_H - -/* Define if inet/v6defs.h needs to be included */ -#undef NEED_INET_V6DEFS_H - -/* Define if strerror.h needs to be included */ -#undef NEED_STRERROR_H - -/* Define if strptime.h needs to be included */ -#undef NEED_STRPTIME_H - -/* Name of package */ -#undef PACKAGE - -/* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT - -/* Define to the full name of this package. */ -#undef PACKAGE_NAME - -/* Define to the full name and version of this package. */ -#undef PACKAGE_STRING - -/* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME - -/* Define to the version of this package. */ -#undef PACKAGE_VERSION - -/* Define if we are using version of of the Portaudio library API */ -#undef PORTAUDIO_API_1 - -/* Define to 1 if you have the ANSI C header files. */ -#undef STDC_HEADERS - -/* Version number of package */ -#undef VERSION - -/* Define to 1 if your processor stores words with the most significant byte - first (like Motorola and SPARC, unlike Intel and VAX). */ -#undef WORDS_BIGENDIAN - -/* Define as the string to precede external variable declarations in - dynamically-linked libraries */ -#undef WS_VAR_IMPORT - -/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a - `char[]'. */ -#undef YYTEXT_POINTER diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h.win32 b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h.win32 deleted file mode 100644 index a9569f67..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h.win32 +++ /dev/null @@ -1,274 +0,0 @@ -/* $Id: config.h.win32 23802 2007-12-07 23:58:46Z guy $ */ -/* config.h.win32 Generated manually. :-) */ -/* config.h. Generated automatically by configure. */ -/* config.h.in. Generated automatically from configure.in by autoheader. */ - -/* Generated Bison and Flex files test whether __STDC__ is defined - in order to check whether to use ANSI C features such as "const". - - GCC defines it as 1 even if extensions that render the implementation - non-conformant are enabled; Sun's C compiler (and, I think, other - AT&T-derived C compilers) define it as 0 if extensions that render - the implementation non-conformant are enabled; Microsoft Visual C++ - 6.0 doesn't define it at all if extensions that render the implementation - non-conformant are enabled. - - We define it as 0 here, so that those generated files will use - those features (and thus not get type warnings when compiled with - MSVC++). */ -#ifndef __STDC__ -#define __STDC__ 0 -#endif - -/* Use Unicode in Windows runtime functions. */ -#define UNICODE 1 -#define _UNICODE 1 - -/* Define if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Define if your processor stores words with the most significant - byte first (like Motorola and SPARC, unlike Intel and VAX). */ -/* #undef WORDS_BIGENDIAN */ - -/* Define if lex declares yytext as a char * by default, not a char[]. */ -#define YYTEXT_POINTER 1 - -#define HAVE_PLUGINS 1 -#define PLUGINS_NEED_ADDRESS_TABLE 1 - -/* Plugins can also use the import library of libwireshark.dll instead - of the old API. In that case we undefine PLUGINS_NEED_ADDRESS_TABLE - for the plugin. We don't undefine PLUGINS_NEED_ADDRESS_TABLE globally. - Thus Wireshark will be still able to load plugins using the old API. - The macro HAVE_WIN32_LIBWIRESHARK_LIB has to be defined in plugin's - makefile.nmake. A template is available in doc/README.plugins */ -#ifdef HAVE_WIN32_LIBWIRESHARK_LIB -#undef PLUGINS_NEED_ADDRESS_TABLE -#endif - -/* #undef HAVE_SA_LEN */ - -/* #undef NEED_STRERROR_H */ - -#define NEED_MKSTEMP 1 - -@HAVE_LIBPCAP@ -@HAVE_PCAP_BREAKLOOP@ -@HAVE_PCAP_FINDALLDEVS@ -@HAVE_PCAP_DATALINK_NAME_TO_VAL@ -@HAVE_PCAP_DATALINK_VAL_TO_NAME@ -@WPCAP_CONSTIFIED@ -@HAVE_LIBWIRESHARKDLL@ - -@HAVE_REMOTE@ -@HAVE_PCAP_REMOTE@ -@HAVE_PCAP_OPEN@ -@HAVE_PCAP_FINDALLDEVS_EX@ -@HAVE_PCAP_CREATESRCSTR@ -@HAVE_PCAP_SETSAMPLING@ - -@HAVE_AIRPCAP@ -@HAVE_AIRPDCAP@ - -/* availability of pcap_freecode() is handled at runtime */ -#define HAVE_PCAP_FREECODE 1 - -/* define macro for importing variables from an dll - * it depends on HAVE_LIBWIRESHARKDLL and _NEED_VAR_IMPORT_ - */ -#if defined (_NEED_VAR_IMPORT_) && defined (HAVE_LIBWIRESHARKDLL) -# define WS_VAR_IMPORT __declspec(dllimport) extern -#else -# define WS_VAR_IMPORT extern -#endif - -/* Define if you have the gethostbyname2 function. */ -/* #undef HAVE_GETHOSTBYNAME2 */ - -/* Define if you have the getprotobynumber function. */ -/* #undef HAVE_GETPROTOBYNUMBER */ - -/* Define if you have the header file. */ -/* #undef HAVE_ARPA_INET_H */ - -/* Define if you have the header file. */ -#define HAVE_FCNTL_H 1 - -/* Define if you have the header file. */ -/* #undef HAVE_ICONV */ - -/* Define if you have the header file. */ -/* #undef HAVE_NETDB_H */ - -/* Define if you have the header file. */ -/* #define HAVE_NETINET_IN_H 1 */ - -/* Define if you have the header file. */ -/* #undef HAVE_SNMP_SNMP_H */ - -/* Define if you have the header file. */ -/* #undef HAVE_SNMP_VERSION_H */ - -/* Define if you have the header file. */ -#define HAVE_STDARG_H 1 - -/* Define if you have the header file. */ -/* #undef HAVE_STDDEF_H */ - -/* Define if you have the header file. */ -/* #undef HAVE_SYS_IOCTL_H */ - -/* Define if you have the header file. */ -/* #undef HAVE_SYS_SOCKET_H */ - -/* Define if you have the header file. */ -/* #undef HAVE_SYS_SOCKIO_H */ - -/* Define if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define if you have the header file. */ -/* #define HAVE_SYS_TIME_H 1 */ - -/* Define if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define if you have the header file. */ -/* #undef HAVE_SYS_WAIT_H */ - -/* Define if you have the header file. */ -/* #define HAVE_UNISTD_H 1 */ - -/* Define if defines PRI[doxu]64 macros */ -/* #define INTTYPES_H_DEFINES_FORMATS */ - -/* Format for printing 64-bit signed decimal numbers */ -#ifndef PRId64 -#ifdef _MSC_EXTENSIONS -#define PRId64 "I64d" -#else /* _MSC_EXTENSIONS */ -#define PRId64 "lld" -#endif /* _MSC_EXTENSIONS */ -#endif /* PRId64 */ - -/* Format for printing 64-bit unsigned octal numbers */ -#ifndef PRIo64 -#ifdef _MSC_EXTENSIONS -#define PRIo64 "I64o" -#else /* _MSC_EXTENSIONS */ -#define PRIo64 "llo" -#endif /* _MSC_EXTENSIONS */ -#endif /* PRIo64 */ - -/* Format for printing 64-bit unsigned decimal numbers */ -#ifndef PRIu64 -#ifdef _MSC_EXTENSIONS -#define PRIu64 "I64u" -#else /* _MSC_EXTENSIONS */ -#define PRIu64 "llu" -#endif /* _MSC_EXTENSIONS */ -#endif /* PRIu64 */ - -/* Formats for printing 64-bit unsigned hexadecimal numbers */ -/* XXX - it seems that GLib has problems with the MSVC like I64x. - As we use GLib's g_sprintf and alike, it should be safe to use - llx everywhere now, making the macros pretty useless. For details see: - http://bugs.wireshark.org/bugzilla/show_bug.cgi?id=1025 */ -#ifndef PRIx64 -#ifdef _MSC_EXTENSIONS -/*#define PRIx64 "I64x"*/ -#define PRIx64 "llx" -#else /* _MSC_EXTENSIONS */ -#define PRIx64 "llx" -#endif /* _MSC_EXTENSIONS */ -#endif /* PRIx64 */ - -#ifndef PRIX64 -#ifdef _MSC_EXTENSIONS -/*#define PRIX64 "I64X"*/ -#define PRIX64 "llX" -#else /* _MSC_EXTENSIONS */ -#define PRIX64 "llX" -#endif /* _MSC_EXTENSIONS */ -#endif /* PRIX64 */ - -/* Define if you have the z library (-lz). */ -@HAVE_LIBZ@ - -/* Define to use GNU ADNS library */ -@HAVE_GNU_ADNS@ -#define ADNS_JGAA_WIN32 1 - -/* Define to use the PCRE library */ -@HAVE_PCRE@ - -/* Define to use the Nettle library */ -@HAVE_NETTLE@ - -/* Define to use the gnutls library */ -@HAVE_LIBGNUTLS@ - -/* Define to use the libgcrypt library */ -@HAVE_LIBGCRYPT@ - -/* Define to use mit kerberos for decryption of kerberos/sasl/dcerpc */ -@HAVE_KFW@ -#ifdef HAVE_MIT_KERBEROS -#define HAVE_KERBEROS -#endif - -/* Define to use Lua */ -@HAVE_LUA@ -@HAVE_LUA_5_1@ - -/* Define to use Portaudio library */ -@HAVE_LIBPORTAUDIO@ -/* Define version of of the Portaudio library API */ -@PORTAUDIO_API_1@ - -/* Define to have SMI */ -@HAVE_SMI@ - - -#ifndef WIN32 -#define WIN32 1 -#endif - -#define HAVE_WINDOWS_H 1 -#define HAVE_WINSOCK2_H 1 -#define HAVE_DIRECT_H 1 -#define NEED_INET_ATON_H 1 -#define NEED_INET_V6DEFS_H 1 -/* Visual C 9 (2008) now needs these prototypes */ -#if _MSC_VER == 1500 -#define NTDDI_VERSION NTDDI_WIN2K -#define _WIN32_WINNT _WIN32_WINNT_WIN2K -#endif -#define NEED_GETOPT_H 1 -#define NEED_STRPTIME_H 1 -#define strcasecmp stricmp -#define strncasecmp strnicmp -#define popen _popen -#define pclose _pclose - -/* Needed for zlib, according to http://www.winimage.com/zLibDll/ */ -/*#define ZLIB_DLL 1 -#define _WINDOWS 1*/ - -/* Name of package */ -#define PACKAGE "wireshark" - -/* Version number of package */ -#define VERSION "@VERSION@" - -/* We shouldn't need this under Windows but we'll define it anyway. */ -#define HTML_VIEWER "mozilla" - -/* Check for the required _MSC_VER */ -#if MSC_VER_REQUIRED != _MSC_VER -#define WS_TO_STRING2(x) #x -#define WS_TO_STRING(x) WS_TO_STRING2(x) -#pragma message( "_MSC_VER is:" WS_TO_STRING(_MSC_VER) " but required is:" WS_TO_STRING(MSC_VER_REQUIRED) ) -#error Your MSVC_VARIANT setting in config.nmake doesn't match the MS compiler version! -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/disabled_protos.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/disabled_protos.h deleted file mode 100644 index 87f5b3ab..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/disabled_protos.h +++ /dev/null @@ -1,61 +0,0 @@ -/* disabled_protos.h - * Declarations of routines for reading and writing the disabled protocols file. - * - * $Id: disabled_protos.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* - * Item in a list of disabled protocols. - */ -typedef struct { - char *name; /* protocol name */ -} protocol_def; - -/* - * Read in a list of disabled protocols. - * - * On success, "*pref_path_return" is set to NULL. - * On error, "*pref_path_return" is set to point to the pathname of - * the file we tried to read - it should be freed by our caller - - * and "*open_errno_return" is set to the error if we couldn't open the file - * or "*read_errno_return" is set to the error if we got an error reading - * the file. - */ -void read_disabled_protos_list(char **gpath_return, int *gopen_errno_return, - int *gread_errno_return, - char **path_return, int *open_errno_return, - int *read_errno_return); - -/* - * Disable protocols as per the stored configuration - */ -void set_disabled_protos_list(void); - -/* - * Write out a list of disabled protocols. - * - * On success, "*pref_path_return" is set to NULL. - * On error, "*pref_path_return" is set to point to the pathname of - * the file we tried to read - it should be freed by our caller - - * and "*errno_return" is set to the error. - */ -void save_disabled_protos_list(char **pref_path_return, int *errno_return); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/addr_and_mask.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/addr_and_mask.h deleted file mode 100644 index b582aa6e..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/addr_and_mask.h +++ /dev/null @@ -1,53 +0,0 @@ -/* addr_and_mask.h - * Declarations of routines to fetch IPv4 and IPv6 addresses from a tvbuff - * and then mask out bits other than those covered by a prefix length - * - * $Id: addr_and_mask.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __ADDR_AND_MASK_H__ -#define __ADDR_AND_MASK_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* - * These routines return PREFIX_LEN_OK on success, PREFIX_LEN_TOO_LONG if - * the prefix length is too long, and PREFIX_LEN_ZERO if the prefix length - * is 0. - */ - -#define PREFIX_LEN_OK 0 -#define PREFIX_LEN_TOO_LONG 1 -#define PREFIX_LEN_ZERO 2 - -extern int ipv4_addr_and_mask(tvbuff_t *tvb, int offset, guint8 *addr, - guint32 prefix_len); - -extern int ipv6_addr_and_mask(tvbuff_t *tvb, int offset, - struct e_in6_addr *addr, guint32 prefix_len); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __ADDR_AND_MASK_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/addr_resolv.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/addr_resolv.h deleted file mode 100644 index 4733db52..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/addr_resolv.h +++ /dev/null @@ -1,198 +0,0 @@ -/* addr_resolv.h - * Definitions for network object lookup - * - * $Id: addr_resolv.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Laurent Deniel - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -/* The buffers returned by these functions are all allocated with a - * packet lifetime and does not have have to be freed. - * However, take into account that when the packet dissection - * completes, these buffers will be automatically reclaimed/freed. - * If you need the buffer to remain for a longer scope than packet lifetime - * you must copy the content to an se_alloc() buffer. - */ - -#ifndef __RESOLV_H__ -#define __RESOLV_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#ifndef MAXNAMELEN -#define MAXNAMELEN 64 /* max name length (hostname and port name) */ -#endif - -/* - * Flag controlling what names to resolve. - */ -WS_VAR_IMPORT guint32 g_resolv_flags; - -/* 32 types are sufficient (as are 640k of RAM) */ -/* FIXME: Maybe MANUF/m, IP/i, IP6/6, IPX/x, UDP+TCP/t etc would be - more useful/consistent */ -#define RESOLV_NONE 0x0 -#define RESOLV_MAC 0x1 -#define RESOLV_NETWORK 0x2 -#define RESOLV_TRANSPORT 0x4 -#define RESOLV_CONCURRENT 0x8 - -#define RESOLV_ALL_ADDRS (RESOLV_MAC|RESOLV_NETWORK|RESOLV_TRANSPORT) -#define RESOLV_ALL 0xFFFFFFFF - -/* global variables */ - -extern gchar *g_ethers_path; -extern gchar *g_ipxnets_path; -extern gchar *g_pethers_path; -extern gchar *g_pipxnets_path; - -/* Functions in resolv.c */ - -/* Set the flags controlling what names to resolve */ -extern void resolv_set_flags(guint32 flags); - -/* - * get_udp_port() returns the port name corresponding to that UDP port, - * or the port number as a string if not found. - */ -extern gchar *get_udp_port(guint port); - -/* - * get_tcp_port() returns the port name corresponding to that TCP port, - * or the port number as a string if not found. - */ -extern gchar *get_tcp_port(guint port); - -/* - * get_dccp_port() returns the port name corresponding to that DCCP port, - * or the port number as a string if not found. - */ -extern gchar *get_dccp_port(guint port); - -/* - * get_sctp_port() returns the port name corresponding to that SCTP port, - * or the port number as a string if not found. - */ -extern gchar *get_sctp_port(guint port); - -/* get_addr_name takes as input an "address", as defined in address.h */ -/* it returns a string that contains: */ -/* - if the address is of a type that can be translated into a name, and the user */ -/* has activated name resolution, the translated name */ -/* - if the address is of type AT_NONE, a pointer to the string "NONE" */ -/* - if the address is of any other type, the result of address_to_str on the argument, */ -/* which should be a string representation for the answer -e.g. "10.10.10.10" for IPv4 */ -/* address 10.10.10.10 */ - -const gchar *get_addr_name(address *addr); - -/* get_addr_name_buf solves an address in the same way as get_addr_name above */ -/* The difference is that get_addr_name_buf takes as input a buffer, into which it puts */ -/* the result which is always NUL ('\0') terminated. The buffer should be large enough to */ -/* contain size characters including the terminator */ - -void get_addr_name_buf(address *addr, gchar *buf, guint size); - - -/* - * Asynchronous host name lookup initialization, processing, and cleanup - */ - -/* host_name_lookup_init fires up an ADNS socket if we're using ADNS */ -extern void host_name_lookup_init(void); - -/* host_name_lookup_process does ADNS processing in GTK+ timeouts in Wireshark, - and before processing each packet in TShark, if we're using ADNS */ -extern gint host_name_lookup_process(gpointer data); - -/* host_name_lookup_cleanup cleans up an ADNS socket if we're using ADNS */ -extern void host_name_lookup_cleanup(void); - -/* get_hostname returns the host name or "%d.%d.%d.%d" if not found */ -extern gchar *get_hostname(guint addr); - -/* get_hostname6 returns the host name, or numeric addr if not found */ -struct e_in6_addr; -const gchar* get_hostname6(struct e_in6_addr *ad); - -/* get_ether_name returns the logical name if found in ethers files else - "_%02x:%02x:%02x" if the vendor code is known else - "%02x:%02x:%02x:%02x:%02x:%02x" */ -extern gchar *get_ether_name(const guint8 *addr); - -/* get_ether_name returns the logical name if found in ethers files else NULL */ -extern gchar *get_ether_name_if_known(const guint8 *addr); - -/* get_manuf_name returns the vendor name or "%02x:%02x:%02x" if not known */ -extern const gchar *get_manuf_name(const guint8 *addr); - -/* get_manuf_name returns the vendor name or NULL if not known */ -extern const gchar *get_manuf_name_if_known(const guint8 *addr); - -/* get_ipxnet_name returns the logical name if found in an ipxnets file, - * or a string formatted with "%X" if not */ -extern const gchar *get_ipxnet_name(const guint32 addr); - -/* returns the ethernet address corresponding to name or NULL if not known */ -extern guint8 *get_ether_addr(const gchar *name); - -/* returns the ipx network corresponding to name. If name is unknown, - * 0 is returned and 'known' is set to FALSE. On success, 'known' - * is set to TRUE. */ -guint32 get_ipxnet_addr(const gchar *name, gboolean *known); - -/* adds a hostname/IPv4 in the hash table */ -extern void add_ipv4_name(guint addr, const gchar *name); - -/* adds a hostname/IPv6 in the hash table */ -extern void add_ipv6_name(struct e_in6_addr *addr, const gchar *name); - -/* add ethernet address / name corresponding to IP address */ -extern void add_ether_byip(guint ip, const guint8 *eth); - -/* Translates a string representing the hostname or dotted-decimal IP address - * into a numeric IP address value, returning TRUE if it succeeds and - * FALSE if it fails. */ -gboolean get_host_ipaddr(const char *host, guint32 *addrp); - -/* - * Translate IPv6 numeric address or FQDN hostname, into binary IPv6 address. - * Return TRUE if we succeed and set "*addrp" to that numeric IP address; - * return FALSE if we fail. - */ -gboolean get_host_ipaddr6(const char *host, struct e_in6_addr *addrp); - -/* - * Find out whether a hostname resolves to an ip or ipv6 address - * Return "ip6" if it is IPv6, "ip" otherwise (including the case - * that we don't know) - */ -const char* host_ip_af(const char *host); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __RESOLV_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/address.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/address.h deleted file mode 100644 index 1ce916d4..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/address.h +++ /dev/null @@ -1,172 +0,0 @@ -/* address.h - * Definitions for structures storing addresses, and for the type of - * variables holding port-type values - * - * $Id: address.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __ADDRESS_H__ -#define __ADDRESS_H__ - -#include "emem.h" - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* Types of addresses Wireshark knows about. */ -/* If a new address type is added here, a string representation procedure should */ -/* also be included in address_to_str_buf defined in to_str.c, for presentation purposes */ - -typedef enum { - AT_NONE, /* no link-layer address */ - AT_ETHER, /* MAC (Ethernet, 802.x, FDDI) address */ - AT_IPv4, /* IPv4 */ - AT_IPv6, /* IPv6 */ - AT_IPX, /* IPX */ - AT_SNA, /* SNA */ - AT_ATALK, /* Appletalk DDP */ - AT_VINES, /* Banyan Vines */ - AT_OSI, /* OSI NSAP */ - AT_ARCNET, /* ARCNET */ - AT_FC, /* Fibre Channel */ - AT_SS7PC, /* SS7 Point Code */ - AT_STRINGZ, /* null-terminated string */ - AT_EUI64, /* IEEE EUI-64 */ - AT_URI, /* URI/URL/URN */ - AT_TIPC, /* TIPC Address Zone,Subnetwork,Processor */ - AT_USB /* USB Device address - * (0xffffffff represents the host) */ -} address_type; - -typedef struct _address { - address_type type; /* type of address */ - int len; /* length of address, in bytes */ - const void *data; /* pointer to address data */ -} address; - -#define SET_ADDRESS(addr, addr_type, addr_len, addr_data) { \ - (addr)->type = (addr_type); \ - (addr)->len = (addr_len); \ - (addr)->data = (addr_data); \ - } - -/* - * Given two addresses, return - * 0 if the addresses are equal, - * a positive number if addr1>addr2 in some nondefined metric, - * a negative number if addr1type > (addr2)->type)?1: \ - ((addr1)->type < (addr2)->type)?-1: \ - ((addr1)->len > (addr2)->len) ?1: \ - ((addr1)->len < (addr2)->len) ?-1: \ - memcmp((addr1)->data, (addr2)->data, (addr1)->len)\ - ) - -/* - * Given two addresses, return "true" if they're equal, "false" otherwise. - * Addresses are equal only if they have the same type; if the type is - * AT_NONE, they are then equal, otherwise they must have the same - * amount of data and the data must be the same. - */ -#define ADDRESSES_EQUAL(addr1, addr2) \ - ( \ - (addr1)->type == (addr2)->type && \ - ( \ - (addr1)->type == AT_NONE || \ - ( \ - (addr1)->len == (addr2)->len && \ - memcmp((addr1)->data, (addr2)->data, (addr1)->len) == 0 \ - ) \ - ) \ - ) - -/* - * Copy an address, allocating a new buffer for the address data. - */ -#define COPY_ADDRESS(to, from) { \ - guint8 *COPY_ADDRESS_data; \ - (to)->type = (from)->type; \ - (to)->len = (from)->len; \ - COPY_ADDRESS_data = g_malloc((from)->len); \ - memcpy(COPY_ADDRESS_data, (from)->data, (from)->len); \ - (to)->data = COPY_ADDRESS_data; \ - } - -#define SE_COPY_ADDRESS(to, from) { \ - guint8 *SE_COPY_ADDRESS_data; \ - (to)->type = (from)->type; \ - (to)->len = (from)->len; \ - SE_COPY_ADDRESS_data = se_alloc((from)->len); \ - memcpy(SE_COPY_ADDRESS_data, (from)->data, (from)->len); \ - (to)->data = SE_COPY_ADDRESS_data; \ - } - -/* - * Hash an address into a hash value (which must already have been set). - */ -#define ADD_ADDRESS_TO_HASH(hash_val, addr) { \ - const guint8 *ADD_ADDRESS_TO_HASH_data; \ - int ADD_ADDRESS_TO_HASH_index; \ - ADD_ADDRESS_TO_HASH_data = (addr)->data; \ - for (ADD_ADDRESS_TO_HASH_index = 0; \ - ADD_ADDRESS_TO_HASH_index < (addr)->len; \ - ADD_ADDRESS_TO_HASH_index++) \ - hash_val += ADD_ADDRESS_TO_HASH_data[ADD_ADDRESS_TO_HASH_index]; \ - } - -/* Types of port numbers Wireshark knows about. */ -typedef enum { - PT_NONE, /* no port number */ - PT_SCTP, /* SCTP */ - PT_TCP, /* TCP */ - PT_UDP, /* UDP */ - PT_DCCP, /* DCCP */ - PT_IPX, /* IPX sockets */ - PT_NCP, /* NCP connection */ - PT_EXCHG, /* Fibre Channel exchange */ - PT_DDP, /* DDP AppleTalk connection */ - PT_SBCCS, /* FICON */ - PT_IDP, /* XNS IDP sockets */ - PT_TIPC, /* TIPC PORT */ - PT_USB /* USB endpoint 0xffff means the host */ -} port_type; - -/* Types of circuit IDs Wireshark knows about. */ -typedef enum { - CT_NONE, /* no circuit type */ - CT_DLCI, /* Frame Relay DLCI */ - CT_ISDN, /* ISDN channel number */ - CT_X25, /* X.25 logical channel number */ - CT_ISUP, /* ISDN User Part CIC */ - CT_IAX2, /* IAX2 call id */ - CT_H223, /* H.223 logical channel number */ - CT_BICC /* BICC Circuit identifier */ - /* Could also have ATM VPI/VCI pairs */ -} circuit_type; - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __ADDRESS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/adler32.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/adler32.h deleted file mode 100644 index 277ed53a..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/adler32.h +++ /dev/null @@ -1,42 +0,0 @@ -/* adler32.h - * Compute the Adler32 checksum (RFC 1950) - * 2003 Tomas Kukosa - * - * $Id: adler32.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef ADLER32_H -#define ADLER32_H - -#ifdef __cplusplus -extern "C"{ -#endif - -unsigned long update_adler32(unsigned long adler, const unsigned char *buf, int len); -unsigned long adler32_bytes(const unsigned char *buf, int len); -unsigned long adler32_str(const char *buf); - -#ifdef __cplusplus -} -#endif - -#endif /* ADLER32_H */ - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/afn.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/afn.h deleted file mode 100644 index 16538789..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/afn.h +++ /dev/null @@ -1,71 +0,0 @@ -/* afn.h - * RFC 1700 address family numbers - * - * $Id: afn.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __AFN_H__ -#define __AFN_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* - * Address family numbers, from - * - * http://www.iana.org/assignments/address-family-numbers - */ -#define AFNUM_RESERVED 0 /* Reserved */ -#define AFNUM_INET 1 /* IP (IP version 4) */ -#define AFNUM_INET6 2 /* IP6 (IP version 6) */ -#define AFNUM_NSAP 3 /* NSAP */ -#define AFNUM_HDLC 4 /* HDLC (8-bit multidrop) */ -#define AFNUM_BBN1822 5 /* BBN 1822 */ -#define AFNUM_802 6 /* 802 (includes all 802 media plus Ethernet "canonical format") */ -#define AFNUM_E163 7 /* E.163 */ -#define AFNUM_E164 8 /* E.164 (SMDS, Frame Relay, ATM) */ -#define AFNUM_F69 9 /* F.69 (Telex) */ -#define AFNUM_X121 10 /* X.121 (X.25, Frame Relay) */ -#define AFNUM_IPX 11 /* IPX */ -#define AFNUM_ATALK 12 /* Appletalk */ -#define AFNUM_DECNET 13 /* Decnet IV */ -#define AFNUM_BANYAN 14 /* Banyan Vines */ -#define AFNUM_E164NSAP 15 /* E.164 with NSAP format subaddress */ -#define AFNUM_DNS 16 /* DNS (Domain Name System) */ -#define AFNUM_DISTNAME 17 /* Distinguished Name */ -#define AFNUM_AS_NUMBER 18 /* AS Number */ -#define AFNUM_XTP_IP4 19 /* XTP over IP version 4 */ -#define AFNUM_XTP_IP6 20 /* XTP over IP version 6 */ -#define AFNUM_XTP 21 /* XTP native mode XTP */ -#define AFNUM_FC_WWPN 22 /* Fibre Channel World-Wide Port Name */ -#define AFNUM_FC_WWNN 23 /* Fibre Channel World-Wide Node Name */ -#define AFNUM_GWID 24 /* GWID */ -/* draft-kompella-ppvpn-l2vpn */ -#define AFNUM_L2VPN 25 -#define AFNUM_L2VPN_OLD 196 -extern const value_string afn_vals[]; - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __AFN_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/aftypes.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/aftypes.h deleted file mode 100644 index a28d7494..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/aftypes.h +++ /dev/null @@ -1,47 +0,0 @@ -/* aftypes.h - * AF_ values on various flavors of BSD - * - * $Id: aftypes.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * - * This file created and by Mike Hall - * Copyright 1998 - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __AFTYPES_H__ -#define __AFTYPES_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* BSD AF_ values. */ -#define BSD_AF_INET 2 -#define BSD_AF_ISO 7 -#define BSD_AF_APPLETALK 16 -#define BSD_AF_IPX 23 -#define BSD_AF_INET6_BSD 24 /* OpenBSD (and probably NetBSD), BSD/OS */ -#define BSD_AF_INET6_FREEBSD 28 -#define BSD_AF_INET6_DARWIN 30 - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* aftypes.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/arcnet_pids.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/arcnet_pids.h deleted file mode 100644 index 7f92176a..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/arcnet_pids.h +++ /dev/null @@ -1,70 +0,0 @@ -/* arcnet_pids.h - * ARCNET protocol ID values - * Copyright 2001-2002, Peter Fales - * - * $Id: arcnet_pids.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __ARCNET_PIDS_H__ -#define __ARCNET_PIDS_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* RFC 1051 */ -#define ARCNET_PROTO_IP_1051 240 -#define ARCNET_PROTO_ARP_1051 241 - -/* RFC 1201 */ -#define ARCNET_PROTO_IP_1201 212 -#define ARCNET_PROTO_ARP_1201 213 -#define ARCNET_PROTO_RARP_1201 214 - -#define ARCNET_PROTO_IPX 250 -#define ARCNET_PROTO_NOVELL_EC 236 - -#define ARCNET_PROTO_IPv6 196 /* or so BSD's arcnet.h claims */ - -/* - * Raw Ethernet over ARCNET - Linux's "if_arcnet.h" calls this - * "MS LanMan/WfWg 'NDIS' encapsuation". - */ -#define ARCNET_PROTO_ETHERNET 232 - -#define ARCNET_PROTO_DATAPOINT_BOOT 0 -#define ARCNET_PROTO_DATAPOINT_MOUNT 1 -#define ARCNET_PROTO_POWERLAN_BEACON 8 -#define ARCNET_PROTO_POWERLAN_BEACON2 243 -#define ARCNET_PROTO_LANSOFT 251 - -#define ARCNET_PROTO_APPLETALK 221 -#define ARCNET_PROTO_BANYAN 247 /* Banyan VINES */ - -#define ARCNET_PROTO_DIAGNOSE 128 /* as per ANSI/ATA 878.1 */ - -#define ARCNET_PROTO_BACNET 205 - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* arcnet_pids.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/arptypes.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/arptypes.h deleted file mode 100644 index de936cb6..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/arptypes.h +++ /dev/null @@ -1,75 +0,0 @@ -/* arptypes.h - * Declarations of ARP address types. - * - * $Id: arptypes.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __ARPTYPES_H__ -#define __ARPTYPES_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* Definitions taken from Linux "linux/if_arp.h" header file, and from - - http://www.iana.org/assignments/arp-parameters - - */ - -/* ARP protocol HARDWARE identifiers. */ -#define ARPHRD_NETROM 0 /* from KA9Q: NET/ROM pseudo */ -#define ARPHRD_ETHER 1 /* Ethernet 10Mbps */ -#define ARPHRD_EETHER 2 /* Experimental Ethernet */ -#define ARPHRD_AX25 3 /* AX.25 Level 2 */ -#define ARPHRD_PRONET 4 /* PROnet token ring */ -#define ARPHRD_CHAOS 5 /* Chaosnet */ -#define ARPHRD_IEEE802 6 /* IEEE 802.2 Ethernet/TR/TB */ -#define ARPHRD_ARCNET 7 /* ARCnet */ -#define ARPHRD_HYPERCH 8 /* Hyperchannel */ -#define ARPHRD_LANSTAR 9 /* Lanstar */ -#define ARPHRD_AUTONET 10 /* Autonet Short Address */ -#define ARPHRD_LOCALTLK 11 /* Localtalk */ -#define ARPHRD_LOCALNET 12 /* LocalNet (IBM PCNet/Sytek LocalNET) */ -#define ARPHRD_ULTRALNK 13 /* Ultra link */ -#define ARPHRD_SMDS 14 /* SMDS */ -#define ARPHRD_DLCI 15 /* Frame Relay DLCI */ -#define ARPHRD_ATM 16 /* ATM */ -#define ARPHRD_HDLC 17 /* HDLC */ -#define ARPHRD_FIBREC 18 /* Fibre Channel */ -#define ARPHRD_ATM2225 19 /* ATM (RFC 2225) */ -#define ARPHRD_SERIAL 20 /* Serial Line */ -#define ARPHRD_ATM2 21 /* ATM */ -#define ARPHRD_MS188220 22 /* MIL-STD-188-220 */ -#define ARPHRD_METRICOM 23 /* Metricom STRIP */ -#define ARPHRD_IEEE1394 24 /* IEEE 1394.1995 */ -#define ARPHRD_MAPOS 25 /* MAPOS */ -#define ARPHRD_TWINAX 26 /* Twinaxial */ -#define ARPHRD_EUI_64 27 /* EUI-64 */ - -/* Virtual ARP types for non ARP hardware used in Linux cooked mode. */ -#define ARPHRD_IPGRE 778 /* GRE over IP */ - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* arptypes.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/asm_utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/asm_utils.h deleted file mode 100644 index 384b0d68..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/asm_utils.h +++ /dev/null @@ -1,38 +0,0 @@ -/* asm_utils.h - * Functions optionally implemented in assembler - * - * $Id: asm_utils.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __ASM_UTILS_H__ -#define __ASM_UTILS_H__ - -gint wrs_strcmp(gconstpointer a, gconstpointer b); -gint wrs_strcmp_with_data(gconstpointer a, gconstpointer b, gpointer user_data); -gboolean wrs_str_equal(gconstpointer a, gconstpointer b); - -guchar wrs_check_charset(const guchar table[256], const char *str); - -guint wrs_str_hash(gconstpointer v); - -/* int wrs_count_bitshift(guint32 bitmask); */ - -#endif /* __ASM_UTILS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/asn1.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/asn1.h deleted file mode 100644 index b57bbcff..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/asn1.h +++ /dev/null @@ -1,207 +0,0 @@ -/* asn1.h - * Common data for ASN.1 - * 2007 Anders Broman - * - * $Id: asn1.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __ASN1_H__ -#define __ASN1_H__ - -typedef enum { - ASN1_ENC_BER, /* X.690 - BER, CER, DER */ - ASN1_ENC_PER, /* X.691 - PER */ - ASN1_ENC_ECN, /* X.692 - ECN */ - ASN1_ENC_XER /* X.693 - XER */ -} asn1_enc_e; - -typedef enum { - CB_ASN1_ENC, - CB_DISSECTOR, - CB_NEW_DISSECTOR, - CB_DISSECTOR_HANDLE -} asn1_cb_variant; - -typedef enum { - ASN1_PAR_IRR, /* irrelevant parameter */ - /* value */ - ASN1_PAR_BOOLEAN, - ASN1_PAR_INTEGER, - /* type */ - ASN1_PAR_TYPE -} asn1_par_type; - -typedef struct _asn1_par_def_t { - const gchar *name; - asn1_par_type ptype; -} asn1_par_def_t; - -typedef struct _asn1_par_t { - const gchar *name; - asn1_par_type ptype; - union { - gboolean v_boolean; - gint32 v_integer; - void *v_type; - } value; - struct _asn1_par_t *next; -} asn1_par_t; - -typedef struct _asn1_stack_frame_t { - const gchar *name; - struct _asn1_par_t *par; - struct _asn1_stack_frame_t *next; -} asn1_stack_frame_t; - -#define ASN1_CTX_SIGNATURE 0x41435458 /* "ACTX" */ - -typedef struct _asn1_ctx_t { - guint32 signature; - asn1_enc_e encoding; - gboolean aligned; - packet_info *pinfo; - proto_item *created_item; - struct _asn1_stack_frame_t *stack; - void *value_ptr; - void *private_data; - struct { - int hf_index; - gboolean data_value_descr_present; - gboolean direct_ref_present; - gboolean indirect_ref_present; - tvbuff_t *data_value_descriptor; - const char *direct_reference; - gint32 indirect_reference; - gint encoding; - /* - 0 : single-ASN1-type, - 1 : octet-aligned, - 2 : arbitrary - */ - tvbuff_t *single_asn1_type; - tvbuff_t *octet_aligned; - tvbuff_t *arbitrary; - union { - struct { - int (*ber_callback)(gboolean imp_tag, tvbuff_t *tvb, int offset, struct _asn1_ctx_t* ,proto_tree *tree, int hf_index ); - } ber; - struct { - int (*type_cb)(tvbuff_t*, int, struct _asn1_ctx_t*, proto_tree*, int); - } per; - } u; - } external; - struct { - int hf_index; - gboolean data_value_descr_present; - tvbuff_t *data_value_descriptor; - gint identification; - /* - 0 : syntaxes, - 1 : syntax, - 2 : presentation-context-id, - 3 : context-negotiation, - 4 : transfer-syntax, - 5 : fixed - */ - gint32 presentation_context_id; - const char *abstract_syntax; - const char *transfer_syntax; - tvbuff_t *data_value; - union { - struct { - int (*ber_callback)(gboolean imp_tag, tvbuff_t *tvb, int offset, struct _asn1_ctx_t* ,proto_tree *tree, int hf_index ); - } ber; - struct { - int (*type_cb)(tvbuff_t*, int, struct _asn1_ctx_t*, proto_tree*, int); - } per; - } u; - } embedded_pdv; - struct _rose_ctx_t *rose_ctx; -} asn1_ctx_t; - -#define ROSE_CTX_SIGNATURE 0x524F5345 /* "ROSE" */ - -typedef struct _rose_ctx_t { - guint32 signature; - dissector_table_t arg_global_dissector_table; - dissector_table_t arg_local_dissector_table; - dissector_table_t res_global_dissector_table; - dissector_table_t res_local_dissector_table; - dissector_table_t err_global_dissector_table; - dissector_table_t err_local_dissector_table; - /* filling in description into tree, info column, any buffer */ - int apdu_depth; - gboolean fillin_info; - gchar *fillin_ptr; - gsize fillin_buf_size; - struct { /* "dynamic" data */ - gint pdu; - /* - 1 : invoke, - 2 : returnResult, - 3 : returnError, - 4 : reject - */ - gint code; - /* - 0 : local, - 1 : global - */ - gint32 code_local; - const char *code_global; - proto_item *code_item; - } d; - void *private_data; -} rose_ctx_t; - -extern void asn1_ctx_init(asn1_ctx_t *actx, asn1_enc_e encoding, gboolean aligned, packet_info *pinfo); -extern gboolean asn1_ctx_check_signature(asn1_ctx_t *actx); -extern void asn1_ctx_clean_external(asn1_ctx_t *actx); -extern void asn1_ctx_clean_epdv(asn1_ctx_t *actx); - -extern void asn1_stack_frame_push(asn1_ctx_t *actx, const gchar *name); -extern void asn1_stack_frame_pop(asn1_ctx_t *actx, const gchar *name); -extern void asn1_stack_frame_check(asn1_ctx_t *actx, const gchar *name, const asn1_par_def_t *par_def); - -extern void asn1_param_push_boolean(asn1_ctx_t *actx, gboolean value); -extern void asn1_param_push_integer(asn1_ctx_t *actx, gint32 value); -extern gboolean asn1_param_get_boolean(asn1_ctx_t *actx, const gchar *name); -extern gint32 asn1_param_get_integer(asn1_ctx_t *actx, const gchar *name); - -extern void rose_ctx_init(rose_ctx_t *rctx); -extern gboolean rose_ctx_check_signature(rose_ctx_t *rctx); -extern void rose_ctx_clean_data(rose_ctx_t *rctx); - -extern asn1_ctx_t *get_asn1_ctx(void *ptr); -extern rose_ctx_t *get_rose_ctx(void *ptr); - -extern double asn1_get_real(const guint8 *real_ptr, gint real_len); - -/* flags */ -#define ASN1_EXT_ROOT 0x01 -#define ASN1_EXT_EXT 0x02 -#define ASN1_OPT 0x04 -#define ASN1_DFLT 0x08 - -#define ASN1_HAS_EXT(f) ((f)&(ASN1_EXT_ROOT|ASN1_EXT_EXT)) - - -#endif /* __ASN1_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/atalk-utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/atalk-utils.h deleted file mode 100644 index c7cdcdf4..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/atalk-utils.h +++ /dev/null @@ -1,63 +0,0 @@ -/* atalk-utils.h - * Definitions for Appletalk utilities (DDP, currently). - * - * $Id: atalk-utils.h 3992 2008-06-10 03:13:11Z dgu $ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __ATALK_UTILS_H__ -#define __ATALK_UTILS_H__ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* - * Structure used to represent a DDP address; gives the layout of the - * data pointed to by an AT_ATALK "address" structure. - */ -struct atalk_ddp_addr { - guint16 net; - guint8 node; -}; - -/* - * DDP packet types. - */ -#define DDP_RTMPDATA 0x01 -#define DDP_NBP 0x02 -#define DDP_ATP 0x03 -#define DDP_AEP 0x04 -#define DDP_RTMPREQ 0x05 -#define DDP_ZIP 0x06 -#define DDP_ADSP 0x07 -#define DDP_EIGRP 0x58 - -/* - * Routines to take a DDP address and generate a string. - */ -extern gchar *atalk_addr_to_str(const struct atalk_ddp_addr *addrp); -extern void atalk_addr_to_str_buf(const struct atalk_ddp_addr *addrp, - gchar *buf, int buf_len); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/base64.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/base64.h deleted file mode 100644 index 38aacf8a..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/base64.h +++ /dev/null @@ -1,38 +0,0 @@ -/* base64.h - * Base-64 conversion - * - * $Id: base64.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#ifndef __BASE64_H__ -#define __BASE64_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* In-place decoding of a base64 string. */ -size_t epan_base64_decode(char *s); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __BASE64_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/bitswap.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/bitswap.h deleted file mode 100644 index 2f0f74db..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/bitswap.h +++ /dev/null @@ -1,40 +0,0 @@ -/* bitswap.h - * Macro to bitswap a byte by looking it up in a table - * - * $Id: bitswap.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __BITSWAP_H__ -#define __BITSWAP_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -extern guint8 swaptab[256]; - -#define BIT_SWAP(b) (swaptab[b]) - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* bitswap.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/bridged_pids.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/bridged_pids.h deleted file mode 100644 index 5eb3a1d0..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/bridged_pids.h +++ /dev/null @@ -1,58 +0,0 @@ -/* bridged_pids.h - * Definitions of protocol IDs for the 00-80-C2 OUI, used for - * bridging various networks over ATM (RFC 2684) or Frame Relay (RFC 2427). - * - * $Id: bridged_pids.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 - 2000 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __BRIDGED_PID_H__ -#define __BRIDGED_PID_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#define BPID_ETH_WITH_FCS 0x0001 /* 802.3/Ethernet with preserved FCS */ -#define BPID_ETH_WITHOUT_FCS 0x0007 /* 802.3/Ethernet without preserved FCS */ - -#define BPID_802_4_WITH_FCS 0x0002 /* 802.4 with preserved FCS */ -#define BPID_802_4_WITHOUT_FCS 0x0008 /* 802.4 without preserved FCS */ - -#define BPID_802_5_WITH_FCS 0x0003 /* 802.5 with preserved FCS */ -#define BPID_802_5_WITHOUT_FCS 0x0009 /* 802.5 without preserved FCS */ - -#define BPID_FDDI_WITH_FCS 0x0004 /* FDDI with preserved FCS */ -#define BPID_FDDI_WITHOUT_FCS 0x000A /* FDDI without preserved FCS */ - -#define BPID_802_6_WITH_FCS 0x0005 /* 802.6 with preserved FCS */ -#define BPID_802_6_WITHOUT_FCS 0x000B /* 802.6 without preserved FCS */ - -#define BPID_FRAGMENTS 0x000D - -#define BPID_BPDU 0x000E /* 802.1(d) or 802.1(g) BPDUs */ - -#define BPID_SR_BPDU 0x000F /* Source Routing BPDUs */ - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* bridged_pid.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/camel-persistentdata.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/camel-persistentdata.h deleted file mode 100644 index ef8bfd05..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/camel-persistentdata.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * camel-persistentdata.h - * Definitions for lists and hash tables used in wireshark's camel dissector - * for calculation of delays in camel-transactions - * Copyright 2006 Florent Drouin - * - * $Id: camel-persistentdata.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __CAMEL_PERSISTENTDATA_H__ -#define __CAMEL_PERSISTENTDATA_H__ - -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#define NB_CAMELSRT_CATEGORY 9+1 /* Number of type of message */ -/* for example TC_BEGIN with InitalDP, and TC_CONT with RequestReportBCSMEvent - is a category, we want to measure the delay between the two messages */ - -#define CAMELSRT_SESSION 1 - -#define CAMELSRT_VOICE_INITIALDP 2 -#define CAMELSRT_VOICE_ACR1 3 -#define CAMELSRT_VOICE_ACR2 4 -#define CAMELSRT_VOICE_ACR3 5 -#define CAMELSRT_VOICE_DISC 6 - -#define CAMELSRT_GPRS_INITIALDP 7 -#define CAMELSRT_GPRS_REPORT 8 - -#define CAMELSRT_SMS_INITIALDP 9 - -WS_VAR_IMPORT const value_string camelSRTtype_naming[]; - -/* If we have a request message and its response, - (eg: ApplyCharging, ApplyChargingReport) - the frames numbers are stored in this structure */ - -struct camelsrt_category_t { - guint32 req_num; /* frame number request seen */ - guint32 rsp_num; /* frame number response seen */ - nstime_t req_time; /* arrival time of request */ - gboolean responded; /* true, if request has been responded */ -}; - -/* List of stored parameters for a Camel dialogue - All this parameters are linked to the hash table key below (use of Tid) - In case of same Tid reused, the Camel parameters are chained. - The right dialogue will be identified with the arrival time of the InitialDP */ - -struct camelsrt_call_t { - guint32 session_id; /* Identify the session, with an internal number */ - struct tcaphash_context_t * tcap_context; - struct camelsrt_category_t category[NB_CAMELSRT_CATEGORY]; -}; - - -/* The Key for the hash table is the TCAP origine transaction identifier - of the TC_BEGIN containing the InitialDP */ - -struct camelsrt_call_info_key_t { - guint32 SessionIdKey; -}; - -/* Info for a couple of messages (or category) - The request must be available, not duplicated, - and once the corresponding response received, - we can deduce the Delta Time between Request/response */ - -struct camelsrt_msginfo_t { - gboolean request_available; - gboolean is_duplicate; - gboolean is_delta_time; - nstime_t req_time; - nstime_t delta_time; -}; - -/* List of infos to store for the analyse */ - -struct camelsrt_info_t { - guint32 tcap_session_id; - void * tcap_context; - guint8 opcode; /* operation code of message received */ - guint8 bool_msginfo[NB_CAMELSRT_CATEGORY]; /* category for the received message */ - struct camelsrt_msginfo_t msginfo[NB_CAMELSRT_CATEGORY]; -}; - -void camelsrt_init_routine(void); - -struct camelsrt_info_t * camelsrt_razinfo(void); - -void camelsrt_call_matching(tvbuff_t *tvb, - packet_info * pinfo _U_, - proto_tree *tree, - struct camelsrt_info_t * p_camel_info); - -WS_VAR_IMPORT gboolean gcamel_StatSRT; - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* camel-persistentdata.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/charsets.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/charsets.h deleted file mode 100644 index ed50cfc3..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/charsets.h +++ /dev/null @@ -1,42 +0,0 @@ -/* charsets.h - * Routines for handling character sets - * - * $Id: charsets.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#ifndef __CHARSETS_H__ -#define __CHARSETS_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#if 0 -void ASCII_to_EBCDIC(guint8 *buf, guint bytes); -guint8 ASCII_to_EBCDIC1(guint8 c); -#endif -void EBCDIC_to_ASCII(guint8 *buf, guint bytes); -guint8 EBCDIC_to_ASCII1(guint8 c); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __CHARSETS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/chdlctypes.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/chdlctypes.h deleted file mode 100644 index 374c2d75..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/chdlctypes.h +++ /dev/null @@ -1,40 +0,0 @@ -/* chdlctypes.h - * Defines Cisco HDLC packet types that aren't just Ethernet types - * - * $Id: chdlctypes.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __CHDLCTYPES_H__ -#define __CHDLCTYPES_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#define CHDLCTYPE_FRARP 0x0808 /* Frame Relay ARP */ -#define CHDLCTYPE_BPDU 0x4242 /* IEEE spanning tree protocol */ -#define CHDLCTYPE_OSI 0xfefe /* ISO network-layer protocols */ - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* chdlctypes.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/circuit.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/circuit.h deleted file mode 100644 index c6fa6762..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/circuit.h +++ /dev/null @@ -1,80 +0,0 @@ -/* circuit.h - * Routines for building lists of packets that are part of a "circuit" - * - * $Id: circuit.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __CIRCUIT_H__ -#define __CIRCUIT_H__ - -#include "packet.h" /* for circuit dissector type */ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* - * Data structure representing a circuit. - */ -typedef struct circuit_key { - circuit_type ctype; - guint32 circuit_id; -} circuit_key; - -typedef struct circuit { - struct circuit *next; /* pointer to next circuit with given circuit ID */ - guint32 first_frame; /* # of first frame for that circuit */ - guint32 last_frame; /* # of last frame for that circuit */ - guint32 index; /* unique ID for circuit */ - GSList *data_list; /* list of data associated with circuit */ - dissector_handle_t dissector_handle; - /* handle for protocol dissector client associated with circuit */ - guint options; /* wildcard flags */ - circuit_key *key_ptr; /* pointer to the key for this circuit */ -} circuit_t; - -extern void circuit_init(void); - -extern circuit_t *circuit_new(circuit_type ctype, guint32 circuit_id, - guint32 first_frame); - -extern circuit_t *find_circuit(circuit_type ctype, guint32 circuit_id, - guint32 frame); - -extern void close_circuit(circuit_t *circuit, guint32 last_frame); - -extern void circuit_add_proto_data(circuit_t *conv, int proto, - void *proto_data); -extern void *circuit_get_proto_data(circuit_t *conv, int proto); -extern void circuit_delete_proto_data(circuit_t *conv, int proto); - -extern void circuit_set_dissector(circuit_t *circuit, - dissector_handle_t handle); -extern dissector_handle_t circuit_get_dissector(circuit_t *circuit); -extern gboolean -try_circuit_dissector(circuit_type ctype, guint32 circuit_id, guint32 frame, - tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* circuit.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/codecs.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/codecs.h deleted file mode 100644 index 928ddf34..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/codecs.h +++ /dev/null @@ -1,43 +0,0 @@ -/* codecs.h - * codecs interface 2007 Tomas Kukosa - * - * $Id: codecs.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef _CODECS_H_ -#define _CODECS_H_ - -#include "epan/epan.h" - -struct codec_handle; -typedef struct codec_handle *codec_handle_t; - -typedef void *(*codec_init_fn)(void); -typedef void (*codec_release_fn)(void *context); -typedef int (*codec_decode_fn)(void *context, const void *input, int inputSizeBytes, void *output, int *outputSizeBytes); - -extern void register_codec(const char *name, codec_init_fn init_fn, codec_release_fn release_fn, codec_decode_fn decode_fn); -extern codec_handle_t find_codec(const char *name); -extern void *codec_init(codec_handle_t codec); -extern void codec_release(codec_handle_t codec, void *context); -extern int codec_decode(codec_handle_t codec, void *context, const void *input, int inputSizeBytes, void *output, int *outputSizeBytes); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column-utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column-utils.h deleted file mode 100644 index c85aa5bf..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column-utils.h +++ /dev/null @@ -1,241 +0,0 @@ -/* column-utils.h - * Definitions for column utility structures and routines - * - * $Id: column-utils.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __COLUMN_UTILS_H__ -#define __COLUMN_UTILS_H__ - -#include - -#include "gnuc_format_check.h" -#include "column_info.h" -#include "packet_info.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/** Maximum length of columns (except COL_INFO). - * Internal, don't use this in dissectors! - */ - -#define COL_MAX_LEN 256 -/** Maximum length of info columns (COL_INFO only). - * Internal, don't use this in dissectors! - */ -#define COL_MAX_INFO_LEN 4096 - - -/** Allocate all the data structures for constructing column data, given - * the number of columns. - * - * Internal, don't use this in dissectors! - */ -extern void col_setup(column_info *cinfo, gint num_cols); - -/** Initialize the data structures for constructing column data. - * - * Internal, don't use this in dissectors! - */ -extern void col_init(column_info *cinfo); - -/** Set the format of the "variable time format". - * - * Internal, don't use this in dissectors! - */ -extern void col_set_cls_time(frame_data *, column_info *cinfo, gint col); - -/** Fill in all columns of the given packet. - * - * Internal, don't use this in dissectors! - */ -extern void col_fill_in(packet_info *pinfo); - -/* Utility routines used by packet*.c */ - -/** Are the columns writable? - * - * @param cinfo the current packet row - * @return TRUE if it's writable, FALSE if not - */ -extern gboolean col_get_writable(column_info *cinfo); - -/** Set the columns writable. - * - * @param cinfo the current packet row - * @param writable TRUE if it's writable, FALSE if not - */ -extern void col_set_writable(column_info *cinfo, gboolean writable); - -/** Check if the given column be filled with data. - * - * @param cinfo the current packet row - * @param col the column to use, e.g. COL_INFO - */ -extern gint check_col(column_info *cinfo, gint col); - -/** Sets a fence for the current column content, - * so this content won't be affected by further col_... function calls. - * - * This can be useful if a protocol is more than once in a single packet, - * e.g. multiple HTTP calls in a single TCP packet. - * - * @param cinfo the current packet row - * @param col the column to use, e.g. COL_INFO - */ -extern void col_set_fence(column_info *cinfo, gint col); - -/** Clears the text of a column element. - * - * @param cinfo the current packet row - * @param col the column to use, e.g. COL_INFO - */ -extern void col_clear(column_info *cinfo, gint col); - -/** Set (replace) the text of a column element, the text won't be copied. - * - * Usually used to set const strings! - * - * @param cinfo the current packet row - * @param col the column to use, e.g. COL_INFO - * @param str the string to set - */ -extern void col_set_str(column_info *cinfo, gint col, const gchar * str); - -/** Add (replace) the text of a column element, the text will be copied. - * - * @param cinfo the current packet row - * @param col the column to use, e.g. COL_INFO - * @param str the string to add - */ -extern void col_add_str(column_info *cinfo, gint col, const gchar *str); - -/** Add (replace) the text of a column element, the text will be formatted and copied. - * - * Same function as col_add_str() but using a printf-like format string. - * - * @param cinfo the current packet row - * @param col the column to use, e.g. COL_INFO - * @param format the format string - * @param ... the variable number of parameters - */ -extern void col_add_fstr(column_info *cinfo, gint col, const gchar *format, ...) - GNUC_FORMAT_CHECK(printf, 3, 4); - -/* For internal Wireshark use only. Not to be called from dissectors. */ -void col_custom_set_fstr(header_field_info *hfinfo, const gchar *format, ...) - GNUC_FORMAT_CHECK(printf, 2, 3); - -/* For internal Wireshark use only. Not to be called from dissectors. */ -void col_custom_prime_edt(epan_dissect_t *edt, column_info *cinfo); - -/* For internal Wireshark use only. Not to be called from dissectors. */ -gboolean have_custom_cols(column_info *cinfo); - -/** Append the given text to a column element, the text will be copied. - * - * @param cinfo the current packet row - * @param col the column to use, e.g. COL_INFO - * @param str the string to append - */ -extern void col_append_str(column_info *cinfo, gint col, const gchar *str); - -/** Append the given text to a column element, the text will be formatted and copied. - * - * Same function as col_append_str() but using a printf-like format string. - * - * @param cinfo the current packet row - * @param col the column to use, e.g. COL_INFO - * @param format the format string - * @param ... the variable number of parameters - */ -extern void col_append_fstr(column_info *cinfo, gint col, const gchar *format, ...) - GNUC_FORMAT_CHECK(printf, 3, 4); - -/** Prepend the given text to a column element, the text will be formatted and copied. - * - * @param cinfo the current packet row - * @param col the column to use, e.g. COL_INFO - * @param format the format string - * @param ... the variable number of parameters - */ -extern void col_prepend_fstr(column_info *cinfo, gint col, const gchar *format, ...) - GNUC_FORMAT_CHECK(printf, 3, 4); - -/**Prepend the given text to a column element, the text will be formatted and copied. - * This function is similar to col_prepend_fstr() but this function will - * unconditionally set a fence to the end of the prepended data even if there - * were no fence before. - * The col_prepend_fstr() will only prepend the data before the fence IFF - * there is already a fence created. This function will create a fence in case - * it does not yet exist. - */ -extern void col_prepend_fence_fstr(column_info *cinfo, gint col, const gchar *format, ...) - GNUC_FORMAT_CHECK(printf, 3, 4); - -/** Append the given text (prepended by a separator) to a column element. - * - * Much like col_append_str() but will prepend the given separator if the column isn't empty. - * - * @param cinfo the current packet row - * @param col the column to use, e.g. COL_INFO - * @param sep the separator string or NULL for default: ", " - * @param str the string to append - */ -extern void col_append_sep_str(column_info *cinfo, gint col, const gchar *sep, - const gchar *str); - -/** Append the given text (prepended by a separator) to a column element. - * - * Much like col_append_fstr() but will prepend the given separator if the column isn't empty. - * - * @param cinfo the current packet row - * @param col the column to use, e.g. COL_INFO - * @param sep the separator string or NULL for default: ", " - * @param format the format string - * @param ... the variable number of parameters - */ -extern void col_append_sep_fstr(column_info *cinfo, gint col, const gchar *sep, - const gchar *format, ...) - GNUC_FORMAT_CHECK(printf, 4, 5); - -/** Set the given (relative) time to a column element. - * - * Used by multiple dissectors to set the time in the columns - * COL_REL_CONV_TIME and COL_DELTA_CONV_TIME - * - * @param cinfo the current packet row - * @param col the column to use, e.g. COL_INFO - * @param ts the time to set in the column - * @param fieldname the fieldname to use for creating a filter (when - * applying/preparing/copying as filter) - */ -extern void col_set_time(column_info *cinfo, int col, - nstime_t *ts, char *fieldname); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __COLUMN_UTILS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column.h deleted file mode 100644 index 90fa3296..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column.h +++ /dev/null @@ -1,56 +0,0 @@ -/* column.h - * Definitions for column handling routines - * - * $Id: column.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __COLUMN_H__ -#define __COLUMN_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -typedef struct _fmt_data { - gchar *title; - gchar *fmt; - gchar *custom_field; -} fmt_data; - -const gchar *col_format_to_string(gint); -const gchar *col_format_desc(gint); -gint get_column_format(gint); -void get_column_format_matches(gboolean *, gint); -gint get_column_format_from_str(gchar *); -gchar *get_column_title(gint); -gchar *get_column_custom_field(gint); -const gchar *get_column_width_string(gint, gint); -const char *get_column_longest_string(gint); -gint get_column_char_width(gint format); - -void -build_column_format_array(capture_file *cfile, gboolean reset_fences); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* column.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column_info.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column_info.h deleted file mode 100644 index 5f70573f..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column_info.h +++ /dev/null @@ -1,134 +0,0 @@ -/* column.h - * Definitions for column structures and routines - * - * $Id: column_info.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __COLUMN_INFO_H__ -#define __COLUMN_INFO_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#define COL_MAX_LEN 256 -#define COL_MAX_INFO_LEN 4096 - -typedef struct { - gchar **col_expr; /* Filter expression */ - gchar **col_expr_val; /* Value for filter expression */ -} col_expr_t; - -typedef struct _column_info { - gint num_cols; /* Number of columns */ - gint *col_fmt; /* Format of column */ - gboolean **fmt_matx; /* Specifies which formats apply to a column */ - gint *col_first; /* First column number with a given format */ - gint *col_last; /* Last column number with a given format */ - gchar **col_title; /* Column titles */ - gchar **col_custom_field; /* Custom column field */ - const gchar **col_data; /* Column data */ - gchar **col_buf; /* Buffer into which to copy data for column */ - int *col_fence; /* Stuff in column buffer before this index is immutable */ - col_expr_t col_expr; /* Column expressions and values */ - gboolean writable; /* Are we still writing to the columns? */ - gboolean columns_changed; /* Have the columns been changed in the prefs? */ -} column_info; - -/* - * All of the possible columns in summary listing. - * - * NOTE1: The entries MUST remain in this order, or else you need to reorder - * the slist[] and dlist[] arrays in column.c to match! - * - * NOTE2: Please add the COL_XYZ entry in the appropriate spot, such that the - * dlist[] array remains in alphabetical order! - */ -enum { - COL_8021Q_VLAN_ID, /* 0) 802.1Q vlan ID */ - COL_ABS_DATE_TIME, /* 1) Absolute date and time */ - COL_ABS_TIME, /* 2) Absolute time */ - COL_CIRCUIT_ID, /* 3) Circuit ID */ - COL_DSTIDX, /* 4) Dst port idx - Cisco MDS-specific */ - COL_SRCIDX, /* 5) Src port idx - Cisco MDS-specific */ - COL_VSAN, /* 6) VSAN - Cisco MDS-specific */ - COL_CUMULATIVE_BYTES, /* 7) Cumulative number of bytes */ - COL_CUSTOM, /* 8) Custom column (any filter name's contents) */ - COL_DCE_CALL, /* 9) DCE/RPC connection oriented call id OR datagram sequence number */ - COL_DCE_CTX, /* 10) DCE/RPC connection oriented context id */ - COL_DELTA_TIME, /* 11) Delta time */ - COL_DELTA_CONV_TIME,/* 12) Delta time to last frame in conversation */ - COL_DELTA_TIME_DIS, /* 13) Delta time displayed*/ - COL_RES_DST, /* 14) Resolved dest */ - COL_UNRES_DST, /* 15) Unresolved dest */ - COL_RES_DST_PORT, /* 16) Resolved dest port */ - COL_UNRES_DST_PORT, /* 17) Unresolved dest port */ - COL_DEF_DST, /* 18) Destination address */ - COL_DEF_DST_PORT, /* 19) Destination port */ - COL_EXPERT, /* 20) Expert Info */ - COL_IF_DIR, /* 21) FW-1 monitor interface/direction */ - COL_OXID, /* 22) Fibre Channel OXID */ - COL_RXID, /* 23) Fibre Channel RXID */ - COL_FR_DLCI, /* 24) Frame Relay DLCI */ - COL_FREQ_CHAN, /* 25) IEEE 802.11 (and WiMax?) - Channel */ - COL_BSSGP_TLLI, /* 26) GPRS BSSGP IE TLLI */ - COL_HPUX_DEVID, /* 27) HP-UX Nettl Device ID */ - COL_HPUX_SUBSYS, /* 28) HP-UX Nettl Subsystem */ - COL_DEF_DL_DST, /* 29) Data link layer dest address */ - COL_DEF_DL_SRC, /* 30) Data link layer source address */ - COL_RES_DL_DST, /* 31) Resolved DL dest */ - COL_UNRES_DL_DST, /* 32) Unresolved DL dest */ - COL_RES_DL_SRC, /* 33) Resolved DL source */ - COL_UNRES_DL_SRC, /* 34) Unresolved DL source */ - COL_RSSI, /* 35) IEEE 802.11 - received signal strength */ - COL_TX_RATE, /* 36) IEEE 802.11 - TX rate in Mbps */ - COL_DSCP_VALUE, /* 37) IP DSCP Value */ - COL_INFO, /* 38) Description */ - COL_COS_VALUE, /* 39) L2 COS Value */ - COL_RES_NET_DST, /* 40) Resolved net dest */ - COL_UNRES_NET_DST, /* 41) Unresolved net dest */ - COL_RES_NET_SRC, /* 42) Resolved net source */ - COL_UNRES_NET_SRC, /* 43) Unresolved net source */ - COL_DEF_NET_DST, /* 44) Network layer dest address */ - COL_DEF_NET_SRC, /* 45) Network layer source address */ - COL_NUMBER, /* 46) Packet list item number */ - COL_PACKET_LENGTH, /* 47) Packet length in bytes */ - COL_PROTOCOL, /* 48) Protocol */ - COL_REL_TIME, /* 49) Relative time */ - COL_REL_CONV_TIME, /* 50) Relative time to beginning of conversation */ - COL_DEF_SRC, /* 51) Source address */ - COL_DEF_SRC_PORT, /* 52) Source port */ - COL_RES_SRC, /* 53) Resolved source */ - COL_UNRES_SRC, /* 54) Unresolved source */ - COL_RES_SRC_PORT, /* 55) Resolved source port */ - COL_UNRES_SRC_PORT, /* 56) Unresolved source port */ - COL_TEI, /* 57) Q.921 TEI */ - COL_CLS_TIME, /* 58) Command line-specified time (default relative) */ - NUM_COL_FMTS /* 59) Should always be last */ -}; - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __COLUMN_INFO_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/conversation.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/conversation.h deleted file mode 100644 index 988ae94b..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/conversation.h +++ /dev/null @@ -1,109 +0,0 @@ -/* conversation.h - * Routines for building lists of packets that are part of a "conversation" - * - * $Id: conversation.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __CONVERSATION_H__ -#define __CONVERSATION_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* - * Flags to pass to "conversation_new()" to indicate that the address 2 - * and/or port 2 values for the conversation should be wildcards. - * The CONVERSATION_TEMPLATE option tells that any of the other supplied - * port and / or address wildcards will be used to match an infinite number - * of new connections to the conversation(s) that have the CONVERSATION_- - * TEMPLATE flag set. Any conversation created without the CONVERSATION_- - * TEMPLATE flag will be altered once the first connections (connection - * oriented protocols only) to include the newly found information which - * matched the wildcard options. - */ -#define NO_ADDR2 0x01 -#define NO_PORT2 0x02 -#define NO_PORT2_FORCE 0x04 -#define CONVERSATION_TEMPLATE 0x08 - -/* - * Flags to pass to "find_conversation()" to indicate that the address B - * and/or port B search arguments are wildcards. - */ -#define NO_ADDR_B 0x01 -#define NO_PORT_B 0x02 - -#include "packet.h" /* for conversation dissector type */ - -/* - * Data structure representing a conversation. - */ -typedef struct conversation_key { - struct conversation_key *next; - address addr1; - address addr2; - port_type ptype; - guint32 port1; - guint32 port2; -} conversation_key; - -typedef struct conversation { - struct conversation *next; /* pointer to next conversation on hash chain */ - guint32 index; /* unique ID for conversation */ - guint32 setup_frame; /* frame number that setup this conversation */ - GSList *data_list; /* list of data associated with conversation */ - dissector_handle_t dissector_handle; - /* handle for protocol dissector client associated with conversation */ - guint options; /* wildcard flags */ - conversation_key *key_ptr; /* pointer to the key for this conversation */ -} conversation_t; - -extern void conversation_init(void); - -extern conversation_t *conversation_new(guint32 setup_frame, address *addr1, address *addr2, - port_type ptype, guint32 port1, guint32 port2, guint options); - -extern conversation_t *find_conversation(guint32 frame_num, address *addr_a, address *addr_b, - port_type ptype, guint32 port_a, guint32 port_b, guint options); - -extern void conversation_add_proto_data(conversation_t *conv, int proto, - void *proto_data); -extern void *conversation_get_proto_data(conversation_t *conv, int proto); -extern void conversation_delete_proto_data(conversation_t *conv, int proto); - -extern void conversation_set_dissector(conversation_t *conversation, - dissector_handle_t handle); -extern gboolean -try_conversation_dissector(address *addr_a, address *addr_b, port_type ptype, - guint32 port_a, guint32 port_b, tvbuff_t *tvb, packet_info *pinfo, - proto_tree *tree); - -/* These routines are used to set undefined values for a conversation */ - -extern void conversation_set_port2(conversation_t *conv, guint32 port); -extern void conversation_set_addr2(conversation_t *conv, address *addr); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* conversation.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc10.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc10.h deleted file mode 100644 index 90e8cbc6..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc10.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * crc10.h - * - * $Id: crc10.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -/* update the data block's CRC-10 remainder one byte at a time */ -extern guint16 update_crc10_by_bytes(guint16 crc10, const guint8 *data_blk_ptr, int data_blk_size); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc16.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc16.h deleted file mode 100644 index 445b9430..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc16.h +++ /dev/null @@ -1,109 +0,0 @@ -/* crc16.h - * Declaration of CRC-16 routines and table - * - * 2004 Richard van der Hoff - * - * $Id: crc16.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * Copied from README.developer - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#ifndef __CRC16_H_ -#define __CRC16_H_ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* Calculate the CCITT/ITU/CRC-16 16-bit CRC - - (parameters for this CRC are: - Polynomial: x^16 + x^12 + x^5 + 1 (0x1021); - Start value 0xFFFF; - XOR result with 0xFFFF; - First bit is LSB) -*/ - -/** Compute CRC16 CCITT checksum of a buffer of data. - @param buf The buffer containing the data. - @param len The number of bytes to include in the computation. - @return The CRC16 CCITT checksum. */ -extern guint16 crc16_ccitt(const guint8 *buf, guint len); - -/** Compute CRC16 X.25 CCITT checksum of a buffer of data. - @param buf The buffer containing the data. - @param len The number of bytes to include in the computation. - @return The CRC16 X.25 CCITT checksum. */ -extern guint16 crc16_x25_ccitt(const guint8 *buf, guint len); - -/** Compute CRC16 CCITT checksum of a buffer of data. If computing the - * checksum over multiple buffers and you want to feed the partial CRC16 - * back in, remember to take the 1's complement of the partial CRC16 first. - @param buf The buffer containing the data. - @param len The number of bytes to include in the computation. - @param seed The seed to use. - @return The CRC16 CCITT checksum (using the given seed). */ -extern guint16 crc16_ccitt_seed(const guint8 *buf, guint len, guint16 seed); - -/** Compute CRC16 CCITT checksum of a tv buffer. - @param tvb The tv buffer containing the data. - @param len The number of bytes to include in the computation. - @return The CRC16 CCITT checksum. */ -extern guint16 crc16_ccitt_tvb(tvbuff_t *tvb, guint len); - -/** Compute CRC16 X.25 CCITT checksum of a tv buffer. - @param tvb The tv buffer containing the data. - @param len The number of bytes to include in the computation. - @return The CRC16 X.25 CCITT checksum. */ -extern guint16 crc16_x25_ccitt_tvb(tvbuff_t *tvb, guint len); - -/** Compute CRC16 CCITT checksum of a tv buffer. - @param tvb The tv buffer containing the data. - @param offset The offset into the tv buffer. - @param len The number of bytes to include in the computation. - @return The CRC16 CCITT checksum. */ -extern guint16 crc16_ccitt_tvb_offset(tvbuff_t *tvb, guint offset, guint len); - -/** Compute CRC16 CCITT checksum of a tv buffer. If computing the - * checksum over multiple tv buffers and you want to feed the partial CRC16 - * back in, remember to take the 1's complement of the partial CRC16 first. - @param tvb The tv buffer containing the data. - @param len The number of bytes to include in the computation. - @param seed The seed to use. - @return The CRC16 CCITT checksum (using the given seed). */ -extern guint16 crc16_ccitt_tvb_seed(tvbuff_t *tvb, guint len, guint16 seed); - -/** Compute CRC16 CCITT checksum of a tv buffer. If computing the - * checksum over multiple tv buffers and you want to feed the partial CRC16 - * back in, remember to take the 1's complement of the partial CRC16 first. - @param tvb The tv buffer containing the data. - @param offset The offset into the tv buffer. - @param len The number of bytes to include in the computation. - @param seed The seed to use. - @return The CRC16 CCITT checksum (using the given seed). */ -extern guint16 crc16_ccitt_tvb_offset_seed(tvbuff_t *tvb, guint offset, - guint len, guint16 seed); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* crc16.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc32.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc32.h deleted file mode 100644 index 72f4abbe..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc32.h +++ /dev/null @@ -1,94 +0,0 @@ -/* crc32.h - * Declaration of CRC-32 routine and table - * - * $Id: crc32.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * Copied from README.developer - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __CRC32_H_ -#define __CRC32_H_ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -extern const guint32 crc32_ccitt_table[256]; - -/** Compute CRC32 CCITT checksum of a buffer of data. - @param buf The buffer containing the data. - @param len The number of bytes to include in the computation. - @return The CRC32 CCITT checksum. */ -extern guint32 crc32_ccitt(const guint8 *buf, guint len); - -/** Compute CRC32 CCITT checksum of a buffer of data. If computing the - * checksum over multiple buffers and you want to feed the partial CRC32 - * back in, remember to take the 1's complement of the partial CRC32 first. - @param buf The buffer containing the data. - @param len The number of bytes to include in the computation. - @param seed The seed to use. - @return The CRC32 CCITT checksum (using the given seed). */ -extern guint32 crc32_ccitt_seed(const guint8 *buf, guint len, guint32 seed); - -/** Compute CRC32 CCITT checksum of a tv buffer. - @param tvb The tv buffer containing the data. - @param len The number of bytes to include in the computation. - @return The CRC32 CCITT checksum. */ -extern guint32 crc32_ccitt_tvb(tvbuff_t *tvb, guint len); - -/** Compute CRC32 CCITT checksum of a tv buffer. - @param tvb The tv buffer containing the data. - @param offset The offset into the tv buffer. - @param len The number of bytes to include in the computation. - @return The CRC32 CCITT checksum. */ -extern guint32 crc32_ccitt_tvb_offset(tvbuff_t *tvb, guint offset, guint len); - -/** Compute CRC32 CCITT checksum of a tv buffer. If computing the - * checksum over multiple tv buffers and you want to feed the partial CRC32 - * back in, remember to take the 1's complement of the partial CRC32 first. - @param tvb The tv buffer containing the data. - @param len The number of bytes to include in the computation. - @param seed The seed to use. - @return The CRC32 CCITT checksum (using the given seed). */ -extern guint32 crc32_ccitt_tvb_seed(tvbuff_t *tvb, guint len, guint32 seed); - -/** Compute CRC32 CCITT checksum of a tv buffer. If computing the - * checksum over multiple tv buffers and you want to feed the partial CRC32 - * back in, remember to take the 1's complement of the partial CRC32 first. - @param tvb The tv buffer containing the data. - @param offset The offset into the tv buffer. - @param len The number of bytes to include in the computation. - @param seed The seed to use. - @return The CRC32 CCITT checksum (using the given seed). */ -extern guint32 crc32_ccitt_tvb_offset_seed(tvbuff_t *tvb, guint offset, - guint len, guint32 seed); - -/** Compute IEEE 802.x CRC32 checksum of a tv buffer. - @param tvb The tv buffer containing the data. - @param len The number of bytes to include in the computation. - @return The IEEE 802.x CRC32 checksum. */ -extern guint32 crc32_802_tvb(tvbuff_t *tvb, guint len); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* crc32.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc6.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc6.h deleted file mode 100644 index cb295faa..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc6.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * crc6.h - * - * $Id: crc6.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -extern guint16 update_crc6_by_bytes(guint16 crc6, guint8 byte1, guint8 byte2); - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crcdrm.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crcdrm.h deleted file mode 100644 index 0987f50f..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crcdrm.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _CRCDRM_H - -#include - -unsigned long crc_drm(const char *data, size_t bytesize, - unsigned short num_crc_bits, unsigned long crc_gen, int invert); -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_debug.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_debug.h deleted file mode 100644 index 849c6662..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_debug.h +++ /dev/null @@ -1,106 +0,0 @@ -/* airpcap_debug.h - * - * $Id: airpdcap_debug.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Copyright (c) 2006 CACE Technologies, Davis (California) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _AIRPDCAP_DEBUG_H -#define _AIRPDCAP_DEBUG_H - -#include "airpdcap_interop.h" - -void print_debug_line(CHAR *function, CHAR *msg, INT level); - -#ifdef _DEBUG -#ifdef __FUNCTION__ -#define AIRPDCAP_DEBUG_PRINT_LINE(notdefined, msg, level) print_debug_line(__FUNCTION__, msg, level); -#else -#define AIRPDCAP_DEBUG_PRINT_LINE(function, msg, level) print_debug_line(function, msg, level); -#endif -#else -#ifdef __FUNCTION__ -#define AIRPDCAP_DEBUG_PRINT_LINE(notdefined, msg, level) -#else -#define AIRPDCAP_DEBUG_PRINT_LINE(function, msg, level) -#endif -#endif - -/******************************************************************************/ -/* Debug section: internal function to print debug information */ -/* */ -#ifdef _DEBUG -#include "stdio.h" -#include - -/* Debug level definition */ -#define AIRPDCAP_DEBUG_LEVEL_1 1 -#define AIRPDCAP_DEBUG_LEVEL_2 2 -#define AIRPDCAP_DEBUG_LEVEL_3 3 -#define AIRPDCAP_DEBUG_LEVEL_4 4 -#define AIRPDCAP_DEBUG_LEVEL_5 5 - -#define AIRPDCAP_DEBUG_USED_LEVEL AIRPDCAP_DEBUG_LEVEL_3 - -#ifdef _TRACE -#ifdef __FUNCTION__ -#define AIRPDCAP_DEBUG_TRACE_START(notdefined) print_debug_line(__FUNCTION__, "Start!", AIRPDCAP_DEBUG_USED_LEVEL); -#define AIRPDCAP_DEBUG_TRACE_END(notdefined) print_debug_line(__FUNCTION__, "End!", AIRPDCAP_DEBUG_USED_LEVEL); -#else -#define AIRPDCAP_DEBUG_TRACE_START(function) print_debug_line(function, "Start!", AIRPDCAP_DEBUG_USED_LEVEL); -#define AIRPDCAP_DEBUG_TRACE_END(function) print_debug_line(function, "End!", AIRPDCAP_DEBUG_USED_LEVEL); -#endif -#else -#ifdef __FUNCTION__ -#define AIRPDCAP_DEBUG_TRACE_START(notdefined) -#define AIRPDCAP_DEBUG_TRACE_END(notdefined) -#else -#define AIRPDCAP_DEBUG_TRACE_START(function) -#define AIRPDCAP_DEBUG_TRACE_END(function) -#endif -#endif - -#else /* !defined _DEBUG */ - -#define AIRPDCAP_DEBUG_LEVEL_1 -#define AIRPDCAP_DEBUG_LEVEL_2 -#define AIRPDCAP_DEBUG_LEVEL_3 -#define AIRPDCAP_DEBUG_LEVEL_4 -#define AIRPDCAP_DEBUG_LEVEL_5 - -#define AIRPDCAP_DEBUG_TRACE_START(function) -#define AIRPDCAP_DEBUG_TRACE_END(function) - -#endif /* ?defined _DEBUG */ - - -#endif /* ?defined _AIRPDCAP_DEBUG_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_int.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_int.h deleted file mode 100644 index b3d4a75b..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_int.h +++ /dev/null @@ -1,158 +0,0 @@ -/* airpcap_int.h - * - * $Id: airpdcap_int.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Copyright (c) 2006 CACE Technologies, Davis (California) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _AIRPDCAP_INT_H -#define _AIRPDCAP_INT_H - -/****************************************************************************/ -/* File includes */ - -#include "airpdcap_interop.h" - -/****************************************************************************/ - -/****************************************************************************/ -/* Definitions */ - -/* IEEE 802.11 packet type values */ -#define AIRPDCAP_TYPE_MANAGEMENT 0 -#define AIRPDCAP_TYPE_CONTROL 1 -#define AIRPDCAP_TYPE_DATA 2 - -/* Min length of encrypted data (TKIP=25bytes, CCMP=21bytes) */ -#define AIRPDCAP_CRYPTED_DATA_MINLEN 21 - -#define AIRPDCAP_TA_OFFSET 10 - -/* */ -/****************************************************************************/ - -/****************************************************************************/ -/* Macro definitions */ - -/** - * Macros to get various bits of a 802.11 control frame - */ -#define AIRPDCAP_TYPE(FrameControl_0) (UINT8)((FrameControl_0 >> 2) & 0x3) -#define AIRPDCAP_SUBTYPE(FrameControl_0) (UINT8)((FrameControl_0 >> 4) & 0xF) -#define AIRPDCAP_DS_BITS(FrameControl_1) (UINT8)(FrameControl_1 & 0x3) -#define AIRPDCAP_TO_DS(FrameControl_1) (UINT8)(FrameControl_1 & 0x1) -#define AIRPDCAP_FROM_DS(FrameControl_1) (UINT8)((FrameControl_1 >> 1) & 0x1) -#define AIRPDCAP_WEP(FrameControl_1) (UINT8)((FrameControl_1 >> 6) & 0x1) - -/** - * Get the Key ID from the Initialization Vector (last byte) - */ -#define AIRPDCAP_EXTIV(KeyID) ((KeyID >> 5) & 0x1) - -/* Macros to get various bits of an EAPOL frame */ -#define AIRPDCAP_EAP_KEY_DESCR_VER(KeyInfo_1) ((UCHAR)(KeyInfo_1 & 0x3)) -#define AIRPDCAP_EAP_KEY(KeyInfo_1) ((KeyInfo_1 >> 3) & 0x1) -#define AIRPDCAP_EAP_INST(KeyInfo_1) ((KeyInfo_1 >> 6) & 0x1) -#define AIRPDCAP_EAP_ACK(KeyInfo_1) ((KeyInfo_1 >> 7) & 0x1) -#define AIRPDCAP_EAP_MIC(KeyInfo_0) (KeyInfo_0 & 0x1) -#define AIRPDCAP_EAP_SEC(KeyInfo_0) ((KeyInfo_0 >> 1) & 0x1) - -/* Note: copied from net80211/ieee80211_airpdcap_tkip.c */ -#define S_SWAP(a,b) { UINT8 t = S[a]; S[a] = S[b]; S[b] = t; } - -/****************************************************************************/ - -/****************************************************************************/ -/* Structure definitions */ - -/* - * XXX - According to the thread at - * http://www.wireshark.org/lists/wireshark-dev/200612/msg00384.html we - * shouldn't have to worry about packing our structs, since the largest - * elements are 8 bits wide. - */ -#ifdef _MSC_VER /* MS Visual C++ */ -#pragma pack(push) -#pragma pack(1) -#endif - -/* Definition of IEEE 802.11 frame (without the address 4) */ -typedef struct _AIRPDCAP_MAC_FRAME { - UCHAR fc[2]; - UCHAR dur[2]; - UCHAR addr1[AIRPDCAP_MAC_LEN]; - UCHAR addr2[AIRPDCAP_MAC_LEN]; - UCHAR addr3[AIRPDCAP_MAC_LEN]; - UCHAR seq[2]; -} AIRPDCAP_MAC_FRAME, *PAIRPDCAP_MAC_FRAME; - -/* Definition of IEEE 802.11 frame (with the address 4) */ -typedef struct _AIRPDCAP_MAC_FRAME_ADDR4 { - UCHAR fc[2]; - UCHAR dur[2]; - UCHAR addr1[AIRPDCAP_MAC_LEN]; - UCHAR addr2[AIRPDCAP_MAC_LEN]; - UCHAR addr3[AIRPDCAP_MAC_LEN]; - UCHAR seq[2]; - UCHAR addr4[AIRPDCAP_MAC_LEN]; -} AIRPDCAP_MAC_FRAME_ADDR4, *PAIRPDCAP_MAC_FRAME_ADDR4; - -/* Definition of IEEE 802.11 frame (without the address 4, with QOS) */ -typedef struct _AIRPDCAP_MAC_FRAME_QOS { - UCHAR fc[2]; - UCHAR dur[2]; - UCHAR addr1[AIRPDCAP_MAC_LEN]; - UCHAR addr2[AIRPDCAP_MAC_LEN]; - UCHAR addr3[AIRPDCAP_MAC_LEN]; - UCHAR seq[2]; - UCHAR qos[2]; -} AIRPDCAP_MAC_FRAME_QOS, *PAIRPDCAP_MAC_FRAME_QOS; - -/* Definition of IEEE 802.11 frame (with the address 4 and QOS) */ -typedef struct _AIRPDCAP_MAC_FRAME_ADDR4_QOS { - UCHAR fc[2]; - UCHAR dur[2]; - UCHAR addr1[AIRPDCAP_MAC_LEN]; - UCHAR addr2[AIRPDCAP_MAC_LEN]; - UCHAR addr3[AIRPDCAP_MAC_LEN]; - UCHAR seq[2]; - UCHAR addr4[AIRPDCAP_MAC_LEN]; - UCHAR qos[2]; -} AIRPDCAP_MAC_FRAME_ADDR4_QOS, *PAIRPDCAP_MAC_FRAME_ADDR4_QOS; - -#ifdef _MSC_VER /* MS Visual C++ */ -#pragma pack(pop) -#endif - -/******************************************************************************/ - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_interop.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_interop.h deleted file mode 100644 index 9d693fb9..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_interop.h +++ /dev/null @@ -1,101 +0,0 @@ -/* airpdcap_interop.h - * - * $Id: airpdcap_interop.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Copyright (c) 2006 CACE Technologies, Davis (California) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _AIRPDCAP_INTEROP_H -#define _AIRPDCAP_INTEROP_H - -/** - * Cast data types commonly used (e.g. UINT16) to their - * GLib equivalents. - */ - -#include -#include - -#ifndef INT -typedef gint INT; -#endif - -#ifndef UINT -typedef guint UINT; -#endif - -#ifndef UINT8 -typedef guint8 UINT8; -#endif - -#ifndef UINT16 -typedef guint16 UINT16; -#endif - -#ifndef UINT32 -typedef guint32 UINT32; -#endif - -#ifndef UINT64 -typedef guint64 UINT64; -#endif - -#ifndef USHORT -typedef gushort USHORT; -#endif - -#ifndef ULONG -typedef gulong ULONG; -#endif - -#ifndef ULONGLONG -typedef guint64 ULONGLONG; -#endif - -#ifndef CHAR -typedef gchar CHAR; -#endif - -#ifndef UCHAR -typedef guchar UCHAR; -#endif - -#ifdef _WIN32 -#include /* ntohs() */ -#endif - -#ifndef ntohs -#undef ntohs -#define ntohs(value) g_ntohs(value) -#endif - -#endif /* _AIRPDCAP_INTEROP_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_rijndael.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_rijndael.h deleted file mode 100644 index b031d790..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_rijndael.h +++ /dev/null @@ -1,93 +0,0 @@ -/** - * airpdcap_rijndael.h - * - * $Id: airpdcap_rijndael.h 3992 2008-06-10 03:13:11Z dgu $ - * - * @version 3.0 (December 2000) - * - * Optimised ANSI C code for the Rijndael cipher (now AES) - * - * @author Vincent Rijmen - * @author Antoon Bosselaers - * @author Paulo Barreto - * - * This code is hereby placed in the public domain. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _AIRPDCAP_RIJNDAEL -#define _AIRPDCAP_RIJNDAEL - -/******************************************************************************/ -/* File includes */ -/* */ -#include "airpdcap_interop.h" -/* */ -/* */ -/******************************************************************************/ - -/******************************************************************************/ -/* Definitions */ -/* */ -/* Note: copied AirPDcap/rijndael/rijndael.h */ -#define RIJNDAEL_MAXKC (256/32) -#define RIJNDAEL_MAXKB (256/8) -#define RIJNDAEL_MAXNR 14 -/* */ -/******************************************************************************/ - -/******************************************************************************/ -/* Type definitions */ -/* */ -/* Note: copied AirPDcap/rijndael/rijndael.h */ -typedef struct s_rijndael_ctx { - INT decrypt; - INT Nr; /* key-length-dependent number of rounds */ - UINT32 ek[4 * (RIJNDAEL_MAXNR + 1)]; /* encrypt key schedule */ - UINT32 dk[4 * (RIJNDAEL_MAXNR + 1)]; /* decrypt key schedule */ -} rijndael_ctx; -/* */ -/******************************************************************************/ - -/******************************************************************************/ -/* External function prototypes declarations */ -/* */ -void rijndael_encrypt( - const rijndael_ctx *ctx, - const UCHAR *src, - UCHAR *dst) - ; - - -void rijndael_set_key( - rijndael_ctx *ctx, - const UCHAR *key, - INT bits) - ; -/* */ -/******************************************************************************/ - -/******************************************************************************/ -/* Block XOR macro definition */ -/* */ -#define XOR_BLOCK(b, a, len) \ - { \ - INT i; \ - for (i = 0; i < (INT)(len); i++) \ - (b)[i] ^= (a)[i]; \ - } -/* */ -/******************************************************************************/ - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_system.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_system.h deleted file mode 100644 index 392d5d19..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_system.h +++ /dev/null @@ -1,356 +0,0 @@ -/* airpdcap_system.h - * - * $Id: airpdcap_system.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Copyright (c) 2006 CACE Technologies, Davis (California) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _AIRPDCAP_SYSTEM_H -#define _AIRPDCAP_SYSTEM_H - -/************************************************************************/ -/* File includes */ - -#include "airpdcap_interop.h" -#include "airpdcap_user.h" - -/************************************************************************/ -/* Constant definitions */ - -/* General definitions */ -#ifndef TRUE -#define TRUE 1 -#endif -#ifndef FALSE -#define FALSE 0 -#endif - -#define AIRPDCAP_RET_SUCCESS 0 -#define AIRPDCAP_RET_UNSUCCESS 1 - -#define AIRPDCAP_RET_NO_DATA 1 -#define AIRPDCAP_RET_WRONG_DATA_SIZE 2 -#define AIRPDCAP_RET_REQ_DATA 3 -#define AIRPDCAP_RET_NO_VALID_HANDSHAKE 4 -#define AIRPDCAP_RET_NO_DATA_ENCRYPTED 5 - -#define AIRPDCAP_RET_SUCCESS_HANDSHAKE -1 - -#define AIRPDCAP_MAX_KEYS_NR 64 -#define AIRPDCAP_MAX_SEC_ASSOCIATIONS_NR 256 - -/* Decryption algorithms fields size definition (bytes) */ -#define AIRPDCAP_WPA_NONCE_LEN 32 -#define AIRPDCAP_WPA_PTK_LEN 64 /* TKIP uses 48 bytes, CCMP uses 64 bytes */ -#define AIRPDCAP_WPA_MICKEY_LEN 16 - -#define AIRPDCAP_WEP_128_KEY_LEN 16 /* 128 bits */ - -/* General 802.11 constants */ -#define AIRPDCAP_MAC_LEN 6 -#define AIRPDCAP_RADIOTAP_HEADER_LEN 24 - -#define AIRPDCAP_EAPOL_MAX_LEN 1024 - -#define AIRPDCAP_TK_LEN 16 - -/* Max length of capture data */ -#define AIRPDCAP_MAX_CAPLEN 8192 - -#define AIRPDCAP_WEP_IVLEN 3 /* 24bit */ -#define AIRPDCAP_WEP_KIDLEN 1 /* 1 octet */ -#define AIRPDCAP_WEP_ICV 4 -#define AIRPDCAP_WEP_HEADER AIRPDCAP_WEP_IVLEN + AIRPDCAP_WEP_KIDLEN -#define AIRPDCAP_WEP_TRAILER AIRPDCAP_WEP_ICV - -/* - * 802.11i defines an extended IV for use with non-WEP ciphers. - * When the EXTIV bit is set in the key id byte an additional - * 4 bytes immediately follow the IV for TKIP. For CCMP the - * EXTIV bit is likewise set but the 8 bytes represent the - * CCMP header rather than IV+extended-IV. - */ -#define AIRPDCAP_RSNA_EXTIV 0x20 -#define AIRPDCAP_RSNA_EXTIVLEN 4 /* extended IV length */ -#define AIRPDCAP_RSNA_MICLEN 8 /* trailing MIC */ - -#define AIRPDCAP_RSNA_HEADER AIRPDCAP_WEP_HEADER + AIRPDCAP_RSNA_EXTIVLEN - -#define AIRPDCAP_CCMP_HEADER AIRPDCAP_RSNA_HEADER -#define AIRPDCAP_CCMP_TRAILER AIRPDCAP_RSNA_MICLEN - -#define AIRPDCAP_TKIP_HEADER AIRPDCAP_RSNA_HEADER -#define AIRPDCAP_TKIP_TRAILER AIRPDCAP_RSNA_MICLEN + AIRPDCAP_WEP_ICV - -#define AIRPDCAP_CRC_LEN 4 - -/************************************************************************/ -/* Macro definitions */ - -/************************************************************************/ -/* Type definitions */ - -typedef struct _AIRPDCAP_SEC_ASSOCIATION_ID { - UCHAR bssid[AIRPDCAP_MAC_LEN]; - UCHAR sta[AIRPDCAP_MAC_LEN]; -} AIRPDCAP_SEC_ASSOCIATION_ID, *PAIRPDCAP_SEC_ASSOCIATION_ID; - -typedef struct _AIRPDCAP_SEC_ASSOCIATION { - /** - * This flag define whether this item is used or not. Accepted - * values are TRUE and FALSE - */ - UINT8 used; - AIRPDCAP_SEC_ASSOCIATION_ID saId; - AIRPDCAP_KEY_ITEM *key; - UINT8 handshake; - UINT8 validKey; - - struct { - UINT8 key_ver; /* Key descriptor version */ - UINT64 pn; /* only used with CCMP AES -if needed replay check- */ - UCHAR nonce[AIRPDCAP_WPA_NONCE_LEN]; - /* used to derive PTK, ANonce stored, SNonce taken */ - /* the 2nd packet of the 4W handshake */ - - UCHAR ptk[AIRPDCAP_WPA_PTK_LEN]; /* session key used in decryption algorithm */ - } wpa; -} AIRPDCAP_SEC_ASSOCIATION, *PAIRPDCAP_SEC_ASSOCIATION; - -typedef struct _AIRPDCAP_CONTEXT { - AIRPDCAP_SEC_ASSOCIATION sa[AIRPDCAP_MAX_SEC_ASSOCIATIONS_NR]; - INT sa_index; - AIRPDCAP_KEY_ITEM keys[AIRPDCAP_MAX_KEYS_NR]; - size_t keys_nr; - - CHAR pkt_ssid[AIRPDCAP_WPA_SSID_MAX_LEN]; - size_t pkt_ssid_len; - - INT index; - INT first_free_index; -} AIRPDCAP_CONTEXT, *PAIRPDCAP_CONTEXT; - -/************************************************************************/ -/* Function prototype declarations */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Given an 802.11 packet, either extract its key data (in the case of - * WPA handshaking) or try to decrypt it. - * @param ctx [IN] Pointer to the current context - * @param data [IN] Pointer to a buffer with an 802.11 frame, including MAC - * header and payload - * @param data_off [IN] Payload offset (aka the MAC header length) - * @param data_len [IN] Total length of the MAC header and the payload - * @param decrypt_data [OUT] Pointer to a buffer that will contain - * decrypted data - * @param decrypt_len [OUT] Length of decrypted data - * @param key [OUT] Pointer to a preallocated key structure containing - * the key used during the decryption process (if done). If this parameter - * is set to NULL, the key will be not returned. - * @param mngHandshake [IN] If TRUE this function will manage the 4-way - * handshake for WPA/WPA2 - * @param mngDecrypt [IN] If TRUE this function will manage the WEP or - * WPA/WPA2 decryption - * @return - * - AIRPDCAP_RET_SUCCESS: Decryption has been done (decrypt_data and - * decrypt_length will contain the packet data decrypted and the length of - * the new packet) - * - AIRPDCAP_RET_SUCCESS_HANDSHAKE: A step of the 4-way handshake for - * WPA key has been successfully done - * - AIRPDCAP_RET_NO_DATA: The packet is not a data packet - * - AIRPDCAP_RET_WRONG_DATA_SIZE: The size of the packet is below the - * accepted minimum - * - AIRPDCAP_RET_REQ_DATA: Required data is not available and the - * processing must be interrupted - * - AIRPDCAP_RET_NO_VALID_HANDSHAKE: The authentication is not for WPA or RSNA - * - AIRPDCAP_RET_NO_DATA_ENCRYPTED: No encrypted data - * - AIRPDCAP_RET_UNSUCCESS: No decryption has been done (decrypt_data - * and decrypt_length will be not modified). - * Some other errors could be: - * data not correct - * data not encrypted - * key handshake, not encryption - * decryption not successful - * key handshake not correct - * replay check not successful - * @note - * The decrypted buffer should be allocated for a size equal or greater - * than the packet data buffer size. Before decryption process original - * data is copied in the buffer pointed by decrypt_data not to modify the - * original packet. - * @note - * The length of decrypted data will consider the entire 802.11 frame - * (thus the MAC header, the frame body and the recalculated FCS -if - * initially present-) - * @note - * This function is not thread-safe when used in parallel with context - * management functions on the same context. - */ -extern INT AirPDcapPacketProcess( - PAIRPDCAP_CONTEXT ctx, - const guint8 *data, - const guint data_off, - const guint data_len, - UCHAR *decrypt_data, - guint32 *decrypt_len, - PAIRPDCAP_KEY_ITEM key, - gboolean mngHandshake, - gboolean mngDecrypt) - ; - -/** - * It sets a new keys collection to use during packet processing. - * Any key should be well-formed, thus: it should have a defined key - * type and the specified length should be conforming WEP or WPA/WPA2 - * standards. A general WEP keys could be of any length (in the range - * defined in AIRPDCAP_KEY_ITEM), if a specific WEP key is used, the - * length of the key will be the one specified in 802.11i-2004 (40 bits or - * 104 bits). - * For WPA/WPA2 the password (passphrase and SSID), the PSK and the PMK - * are in alternative, as explain in the AIRPDCAP_KEY_ITEM structure - * description. - * @param ctx [IN] pointer to the current context - * @param keys [IN] an array of keys to set. - * @param keys_nr [IN] the size of the keys array - * @return The number of keys correctly inserted in the current database. - * @note Before inserting new keys, the current database will be cleaned. - * @note - * This function is not thread-safe when used in parallel with context - * management functions and the packet process function on the same - * context. - */ -extern INT AirPDcapSetKeys( - PAIRPDCAP_CONTEXT ctx, - AIRPDCAP_KEY_ITEM keys[], - const size_t keys_nr) - ; - -/** - * It gets the keys collection fom the specified context. - * @param ctx [IN] pointer to the current context - * @param key [IN] a preallocated array of keys to be returned - * @param keys_nr [IN] the number of keys to return (the key array must - * be able to contain at least keys_nr keys) - * @return The number of keys returned - * @note - * Any key could be modified, as stated in the AIRPDCAP_KEY_ITEM description. - * @note - * This function is not thread-safe when used in parallel with context - * management functions and the packet process function on the same - * context. - */ -INT AirPDcapGetKeys( - const PAIRPDCAP_CONTEXT ctx, - AIRPDCAP_KEY_ITEM keys[], - const size_t keys_nr) - ; - -/** - * Sets the "last seen" SSID. This allows us to pick up previous - * SSIDs and use them when "wildcard" passphrases are specified - * in the preferences. - * @param ctx [IN|OUT] pointer to a preallocated context structure - * @param pkt_ssid [IN] pointer to the packet's SSID - * @param pkt_ssid_len [IN] length of the packet's SSID - * @return - * AIRPDCAP_RET_SUCCESS: The key has been set. - * AIRPDCAP_RET_UNSUCCESS: The has not been set, e.g. the length was - * too long. - */ -INT AirPDcapSetLastSSID( - PAIRPDCAP_CONTEXT ctx, - CHAR *pkt_ssid, - size_t pkt_ssid_len) - ; - -/** - * Initialize a context used to manage decryption and keys collection. - * @param ctx [IN|OUT] pointer to a preallocated context structure - * @return - * AIRPDCAP_RET_SUCCESS: the context has been successfully initialized - * AIRPDCAP_RET_UNSUCCESS: the context has not been initialized - * @note - * Only a correctly initialized context can be used to manage decryption - * processes and keys. - * @note - * This function is not thread-safe when used in parallel with context - * management functions and the packet process function on the same context. - */ -INT AirPDcapInitContext( - PAIRPDCAP_CONTEXT ctx) - ; - -/** - * Clean up the specified context. After the cleanup the pointer should - * not be used anymore. - * @param ctx [IN|OUT] pointer to the current context structure - * @return - * AIRPDCAP_RET_SUCCESS: the context has been successfully initialized - * AIRPDCAP_RET_UNSUCCESS: the context has not been initialized - * @note - * This function is not thread-safe when used in parallel with context - * management functions and the packet process function on the same - * context. - */ -INT AirPDcapDestroyContext( - PAIRPDCAP_CONTEXT ctx) - ; - - -extern INT AirPDcapWepDecrypt( - const UCHAR *seed, - const size_t seed_len, /* max AIRPDCAP_KEYBUF_SIZE */ - UCHAR *cypher_text, - const size_t data_len) - ; -extern INT AirPDcapCcmpDecrypt( - UINT8 *m, - gint mac_header_len, - INT len, - UCHAR TK1[16]) - ; -extern INT AirPDcapTkipDecrypt( - UCHAR *tkip_mpdu, - size_t mpdu_len, - UCHAR TA[AIRPDCAP_MAC_LEN], - UCHAR TK[AIRPDCAP_TK_LEN]) - ; - -#ifdef __cplusplus -} -#endif - -#endif /* _AIRPDCAP_SYSTEM_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_user.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_user.h deleted file mode 100644 index 0cf1a5b8..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_user.h +++ /dev/null @@ -1,231 +0,0 @@ -/* airpdcap_user.h - * - * $Id: airpdcap_user.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Copyright (c) 2006 CACE Technologies, Davis (California) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _AIRPDCAP_USER_H -#define _AIRPDCAP_USER_H - -/******************************************************************************/ -/* File includes */ -/* */ -#include "airpdcap_interop.h" -/* */ -/* */ -/******************************************************************************/ - -/******************************************************************************/ -/* Constant definitions */ -/* */ -/* Decryption key types */ -#define AIRPDCAP_KEY_TYPE_WEP 0 -#define AIRPDCAP_KEY_TYPE_WEP_40 1 -#define AIRPDCAP_KEY_TYPE_WEP_104 2 -#define AIRPDCAP_KEY_TYPE_WPA_PWD 3 -#define AIRPDCAP_KEY_TYPE_WPA_PSK 4 -#define AIRPDCAP_KEY_TYPE_WPA_PMK 5 -#define AIRPDCAP_KEY_TYPE_TKIP 6 -#define AIRPDCAP_KEY_TYPE_CCMP 7 - -/* Decryption algorithms fields size definition (bytes) */ -#define AIRPDCAP_WEP_KEY_MINLEN 1 -#define AIRPDCAP_WEP_KEY_MAXLEN 32 -#define AIRPDCAP_WEP_40_KEY_LEN 5 -#define AIRPDCAP_WEP_104_KEY_LEN 13 - -#define AIRPDCAP_WPA_PASSPHRASE_MIN_LEN 8 -#define AIRPDCAP_WPA_PASSPHRASE_MAX_LEN 63 /* null-terminated string, the actual length of the storage is 64 */ -#define AIRPDCAP_WPA_SSID_MIN_LEN 0 -#define AIRPDCAP_WPA_SSID_MAX_LEN 32 -#define AIRPDCAP_WPA_PSK_LEN 64 -#define AIRPDCAP_WPA_PMK_LEN 32 -/* */ -/* */ -/******************************************************************************/ - -/******************************************************************************/ -/* Macro definitions */ -/* */ -/* */ -/******************************************************************************/ - -/******************************************************************************/ -/* Type definitions */ -/* */ -/** - * Struct to store info about a specific decryption key. - */ -typedef struct { - GString *key; - GByteArray *ssid; - guint bits; - guint type; -} decryption_key_t; - -/** - * Key item used during the decryption process. - */ -typedef struct _AIRPDCAP_KEY_ITEM { - /** - * Type of key. The type will remain unchanged during the - * processing, even if some fields could be changed (e.g., WPA - * fields). - * @note - * You can use constants AIRPDCAP_KEY_TYPE_xxx to indicate the - * key type. - */ - UINT8 KeyType; - - /** - * Key data. - * This field can be used for the following decryptographic - * algorithms: WEP-40, with a key of 40 bits (10 hex-digits); - * WEP-104, with a key of 104 bits (or 26 hex-digits); WPA or - * WPA2. - * @note - * For WPA/WPA2, the PMK is calculated from the PSK, and the PSK - * is calculated from the passphrase-SSID pair. You can enter one - * of these 3 values and subsequent fields will be automatically - * calculated. - * @note - * For WPA and WPA2 this implementation will use standards as - * defined in 802.11i (2004) and 802.1X (2004). - */ - union AIRPDCAP_KEY_ITEMDATA { - struct AIRPDCAP_KEY_ITEMDATA_WEP { - /** - * The binary value of the WEP key. - * @note - * It is accepted a key of length between - * AIRPDCAP_WEP_KEY_MINLEN and - * AIRPDCAP_WEP_KEY_MAXLEN. A WEP key - * standard-compliante should be either 40 bits - * (10 hex-digits, 5 bytes) for WEP-40 or 104 bits - * (26 hex-digits, 13 bytes) for WEP-104. - */ - UCHAR WepKey[AIRPDCAP_WEP_KEY_MAXLEN]; - /** - * The length of the WEP key. Acceptable range - * is [AIRPDCAP_WEP_KEY_MINLEN;AIRPDCAP_WEP_KEY_MAXLEN]. - */ - size_t WepKeyLen; - } Wep; - - /** - * WPA/WPA2 key data. Note that the decryption process - * will use the PMK (equal to PSK), that is calculated - * from passphrase-SSID pair. You can define one of these - * three fields and necessary fields will be automatically - * calculated. - */ - union AIRPDCAP_KEY_ITEMDATA_WPA { - - UCHAR Psk[AIRPDCAP_WPA_PSK_LEN]; - - UCHAR Pmk[AIRPDCAP_WPA_PMK_LEN]; - } Wpa; - } KeyData; - - struct AIRPDCAP_KEY_ITEMDATA_PWD { - /** - * The string (null-terminated) value of - * the passphrase. - */ - CHAR Passphrase[AIRPDCAP_WPA_PASSPHRASE_MAX_LEN+1]; - /** - * The value of the SSID (up to - * AIRPDCAP_WPA_SSID_MAX_LEN octets). - * @note - * A zero-length SSID indicates broadcast. - */ - CHAR Ssid[AIRPDCAP_WPA_SSID_MAX_LEN]; - /** - *The length of the SSID - */ - size_t SsidLen; - } UserPwd; -} AIRPDCAP_KEY_ITEM, *PAIRPDCAP_KEY_ITEM; - -/** - * Collection of keys to use to decrypt packets - */ -typedef struct _AIRPDCAP_KEYS_COLLECTION { - /** - * Number of stored keys - */ - size_t nKeys; - - /** - * Array of nKeys keys - */ - AIRPDCAP_KEY_ITEM Keys[256]; -} AIRPDCAP_KEYS_COLLECTION, *PAIRPDCAP_KEYS_COLLECTION; -/* */ -/******************************************************************************/ - -/******************************************************************************/ -/* Function prototype declarations */ - -/** - * Returns the decryption_key_t struct given a string describing the key. - * @param key_string [IN] Key string in one of the following formats: - * - 0102030405 (40/64-bit WEP) - * - 01:02:03:04:05 (40/64-bit WEP) - * - 0102030405060708090a0b0c0d (104/128-bit WEP) - * - 01:02:03:04:05:06:07:08:09:0a:0b:0c:0d (104/128-bit WEP) - * - wep:01020304... (WEP) - * - wep:01:02:03:04... (WEP) - * - wpa-pwd:MyPassword (WPA + plaintext password + "wildcard" SSID) - * - wpa-pwd:MyPassword:MySSID (WPA + plaintext password + specific SSID) - * - wpa-psk:01020304... (WPA + 256-bit raw key) - * @return A pointer to a freshly-g_malloc()ed decryption_key_t struct on - * success, or NULL on failure. - * @see get_key_string() - */ -decryption_key_t* -parse_key_string(gchar* key_string); - -/** - * Returns a newly allocated string representing the given decryption_key_t - * struct. - * @param dk [IN] Pointer to the key to be converted - * @return A g_malloc()ed string representation of the key - * @see parse_key_string() - */ -gchar* -get_key_string(decryption_key_t* dk); - -/******************************************************************************/ - -#endif /* _AIRPDCAP_USER_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_ws.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_ws.h deleted file mode 100644 index 22cf6e07..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_ws.h +++ /dev/null @@ -1,43 +0,0 @@ -/* airpdcap_ws.h - * - * $Id: airpdcap_ws.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Copyright (c) 2006 CACE Technologies, Davis (California) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _AIRPDCAP_WS_H -#define _AIRPDCAP_WS_H - -#include "airpdcap_system.h" -WS_VAR_IMPORT AIRPDCAP_CONTEXT airpdcap_ctx; - -#endif /* _AIRPDCAP_WS_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-des.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-des.h deleted file mode 100644 index b08ba28b..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-des.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - a partial implementation of DES designed for use in the - SMB authentication protocol - - Copyright (C) Andrew Tridgell 1998 - - $Id: crypt-des.h 3992 2008-06-10 03:13:11Z dgu $ - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -void crypt_des_ecb(unsigned char *out, const unsigned char *in, const unsigned char *key, int forw); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-md4.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-md4.h deleted file mode 100644 index c6179818..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-md4.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - Unix SMB/CIFS implementation. - a implementation of MD4 designed for use in the SMB authentication protocol - Copyright (C) Andrew Tridgell 1997-1998. - - $Id: crypt-md4.h 3992 2008-06-10 03:13:11Z dgu $ - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -void crypt_md4(unsigned char *out, const unsigned char *in, int n); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-md5.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-md5.h deleted file mode 100644 index d6292004..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-md5.h +++ /dev/null @@ -1,71 +0,0 @@ -/* $Id: crypt-md5.h 3992 2008-06-10 03:13:11Z dgu $ */ -/* - * Copyright (C) 2003-2005 Benny Prijono - * - * MD5 code from pjlib-util http://www.pjsip.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef __MD5_H__ -#define __MD5_H__ - -/** - * @file md5.h - * @brief MD5 Functions - */ - -/** - * @defgroup PJLIB_UTIL_MD5 MD5 Functions - * @ingroup PJLIB_UTIL - * @{ - */ - -#define md5_byte_t guint8 - -/** MD5 context. */ -typedef struct md5_state_s -{ - guint32 buf[4]; - guint32 bits[2]; - guint32 in[16]; -} md5_state_t; - -/** Initialize the algorithm. - * @param pms MD5 context. - */ -void md5_init(md5_state_t *pms); - -/** Append a string to the message. - * @param pms MD5 context. - * @param data Data. - * @param nbytes Length of data. - */ -void md5_append( md5_state_t *pms, - const guint8 *data, guint nbytes); - -/** Finish the message and return the digest. - * @param pms MD5 context. - * @param digest 16 byte digest. - */ -void md5_finish(md5_state_t *pms, guint8 digest[16]); - - -void md5_hmac(const guint8* text, gint text_len, const guint8* key, gint key_len, guint8 digest[16]); - -/** - * @} - */ - -#endif /* _CRYPT_MD5_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-rc4.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-rc4.h deleted file mode 100644 index 1068e160..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-rc4.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - a partial implementation of RC4 designed for use in the - SMB authentication protocol - - Copyright (C) Andrew Tridgell 1998 - - $Id: crypt-rc4.h 3992 2008-06-10 03:13:11Z dgu $ - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -typedef struct _rc4_state_struct { - unsigned char s_box[256]; - unsigned char index_i; - unsigned char index_j; -} rc4_state_struct; - -void crypt_rc4_init(rc4_state_struct *rc4_state, - const unsigned char *key, int key_len); - -void crypt_rc4(rc4_state_struct *rc4_state, unsigned char *data, int data_len); - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-sha1.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-sha1.h deleted file mode 100644 index 010725b7..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-sha1.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * FIPS-180-1 compliant SHA-1 implementation - * - * $Id: crypt-sha1.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Copyright (C) 2001-2003 Christophe Devine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Changed to use guint instead of uint 2004 by Anders Broman - * Original code found at http://www.cr0.net:8040/code/crypto/sha1/ - * References: http://www.ietf.org/rfc/rfc3174.txt?number=3174 - */ - -#ifndef _CRYPT_SHA1_H -#define _CRYPT_SHA1_H - - -typedef struct -{ - guint32 total[2]; - guint32 state[5]; - guint8 buffer[64]; -} -sha1_context; - -void sha1_starts( sha1_context *ctx ); -void sha1_update( sha1_context *ctx, const guint8 *input, guint32 length ); -void sha1_finish( sha1_context *ctx, guint8 digest[20] ); -void sha1_hmac( const guint8 *key, guint32 keylen, const guint8 *buf, guint32 buflen, - guint8 digest[20] ); - -#endif /* crypt-sha1.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/wep-wpadefs.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/wep-wpadefs.h deleted file mode 100644 index f980d401..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/wep-wpadefs.h +++ /dev/null @@ -1,115 +0,0 @@ -/* wap-wpadefs.h - * - * $Id: wep-wpadefs.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Copyright (c) 2006 CACE Technologies, Davis (California) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef __WEP_WPADEFS_H__ -#define __WEP_WPADEFS_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -/** @file - * WEP and WPA definitions - * - * Copied from airpcap.h. - */ - -/** - * Maximum number of encryption keys. This determines the size of - * structures in packet-ieee80211.c, as well as the number of keys - * in the IEEE 802.11 preferences. - */ -#define MAX_ENCRYPTION_KEYS 64 - -/** - * Maximum size of a WEP key, in bytes. This is the size of an entry in the - * AirpcapWepKeysCollection structure. - */ -#define WEP_KEY_MAX_SIZE 32 - -/** - * WEP_KEY_MAX_SIZE is in bytes, but each byte is represented as a - * hexadecimal string. - */ -#define WEP_KEY_MAX_CHAR_SIZE (WEP_KEY_MAX_SIZE*2) - -/** - * WEP_KEY_MAX_SIZE is in bytes, this is in bits... - */ -#define WEP_KEY_MAX_BIT_SIZE (WEP_KEY_MAX_SIZE*8) - -#define WEP_KEY_MIN_CHAR_SIZE 2 -#define WEP_KEY_MIN_BIT_SIZE 8 - -/** - * WPA key sizes. - */ -#define WPA_KEY_MAX_SIZE 63 /* 63 chars followed by a '\0' */ - -#define WPA_KEY_MAX_CHAR_SIZE (WPA_KEY_MAX_SIZE*1) -#define WPA_KEY_MAX_BIT_SIZE (WPA_KEY_MAX_SIZE*8) -#define WPA_KEY_MIN_CHAR_SIZE 8 -#define WPA_KEY_MIN_BIT_SIZE (WPA_KEY_MIN_CHAR_SIZE*8) - -/** - * SSID sizes - */ -#define WPA_SSID_MAX_SIZE 32 - -#define WPA_SSID_MAX_CHAR_SIZE (WPA_SSID_MAX_SIZE*1) -#define WPA_SSID_MAX_BIT_SIZE (WPA_SSID_MAX_SIZE*8) -#define WPA_SSID_MIN_CHAR_SIZE 0 -#define WPA_SSID_MIN_BIT_SIZE (WPA_SSID_MIN_CHAR_SIZE*8) - -/** - * Let the user enter a raw PSK along with a passphrase + SSID - */ -#define WPA_PSK_KEY_SIZE 32 /* Fixed size, 32 bytes (256bit) */ -#define WPA_PSK_KEY_CHAR_SIZE (WPA_PSK_KEY_SIZE*2) -#define WPA_PSK_KEY_BIT_SIZE (WPA_PSK_KEY_SIZE*8) - -/** - * Prefix definitions for preferences - */ -#define STRING_KEY_TYPE_WEP "wep" -#define STRING_KEY_TYPE_WPA_PWD "wpa-pwd" -#define STRING_KEY_TYPE_WPA_PSK "wpa-psk" - -#ifdef __cplusplus -} -#endif - -#endif /* __WEP_WPADEFS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter-int.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter-int.h deleted file mode 100644 index aaea0ba4..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter-int.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * $Id: dfilter-int.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2001 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef DFILTER_INT_H -#define DFILTER_INT_H - -#include "dfilter.h" -#include "syntax-tree.h" - -#include -#include - -/* Passed back to user */ -struct _dfilter_t { - GPtrArray *insns; - GPtrArray *consts; - int num_registers; - int max_registers; - GList **registers; - gboolean *attempted_load; - int *interesting_fields; - int num_interesting_fields; - GPtrArray *deprecated; -}; - -typedef struct { - /* Syntax Tree stuff */ - stnode_t *st_root; - gboolean syntax_error; - GPtrArray *insns; - GPtrArray *consts; - GHashTable *loaded_fields; - GHashTable *interesting_fields; - int next_insn_id; - int next_const_id; - int next_register; - int first_constant; /* first register used as a constant */ -} dfwork_t; - -/* Constructor/Destructor prototypes for Lemon Parser */ -#if (GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 16)) -void *DfilterAlloc(void* (*)(gsize)); -#else -void *DfilterAlloc(void* (*)(gulong)); -#endif - -void DfilterFree(void*, void (*)(void *)); -void Dfilter(void*, int, stnode_t*, dfwork_t*); - -/* Scanner's lval */ -extern stnode_t *df_lval; - -/* Return value for error in scanner. */ -#define SCAN_FAILED -1 /* not 0, as that means end-of-input */ - -/* Set dfilter_error_msg_buf and dfilter_error_msg */ -void -dfilter_fail(const char *format, ...); - -void -DfilterTrace(FILE *TraceFILE, char *zTracePrompt); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter-macro.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter-macro.h deleted file mode 100644 index c2a78060..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter-macro.h +++ /dev/null @@ -1,59 +0,0 @@ -/* dfilter-macro.h - * - * $Id: dfilter-macro.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2001 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef _DFILTER_MACRO_H -#define _DFILTER_MACRO_H - -#define DFILTER_MACRO_FILENAME "dfilter_macros" - - -typedef struct _dfilter_macro_t { - gchar* name; /* the macro id */ - gchar* text; /* raw data from file */ - gboolean usable; /* macro is usable */ - gchar** parts; /* various segments of text between insertion targets */ - int* args_pos; /* what's to be inserted */ - int argc; /* the expected number of arguments */ - void* priv; /* a copy of text that contains every c-string in parts */ -} dfilter_macro_t; - -/* loop over the macros list */ -typedef void (*dfilter_macro_cb_t)(dfilter_macro_t*, void*); -void dfilter_macro_foreach(dfilter_macro_cb_t, void*); - -/* save dfilter macros to a file */ -void dfilter_macro_save(const gchar*, gchar**); - -/* dumps the macros in the list (debug info, not formated as in the macros file) */ -void dfilter_macro_dump(void); - -/* applies all macros to the given text and returns the resulting string or NULL on failure */ -gchar* dfilter_macro_apply(const gchar* text, guint depth, const gchar** error); - -void dfilter_macro_init(void); - -void dfilter_macro_get_uat(void**); - -void dfilter_macro_build_ftv_cache(void* tree_root); - -#endif /* _DFILTER_MACRO_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter.h deleted file mode 100644 index 8ea9f947..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * $Id: dfilter.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2001 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef DFILTER_H -#define DFILTER_H - -#include - -/* Passed back to user */ -typedef struct _dfilter_t dfilter_t; - -#include -#include - - -/* Module-level initialization */ -void -dfilter_init(void); - -/* Module-level cleanup */ -void -dfilter_cleanup(void); - -/* Compiles a string to a dfilter_t. - * On success, sets the dfilter* pointed to by dfp - * to either a NULL pointer (if the filter is a null - * filter, as generated by an all-blank string) or to - * a pointer to the newly-allocated dfilter_t - * structure. - * - * On failure, dfilter_error_msg points to an - * appropriate error message. This error message is - * a global string, so another invocation of - * dfilter_compile() will clear it. The dfilter* - * will be set to NULL after a failure. - * - * Returns TRUE on success, FALSE on failure. - */ -gboolean -dfilter_compile(const gchar *text, dfilter_t **dfp); - -/* Frees all memory used by dfilter, and frees - * the dfilter itself. */ -void -dfilter_free(dfilter_t *df); - - -/* dfilter_error_msg is NULL if there was no error during dfilter_compile, - * otherwise it points to a displayable error message. With MSVC and a - * libwireshark.dll, we need a special declaration. - */ - -WS_VAR_IMPORT const gchar *dfilter_error_msg; - - -/* Apply compiled dfilter */ -gboolean -dfilter_apply_edt(dfilter_t *df, epan_dissect_t* edt); - -/* Apply compiled dfilter */ -gboolean -dfilter_apply(dfilter_t *df, proto_tree *tree); - -/* Prime a proto_tree using the fields/protocols used in a dfilter. */ -void -dfilter_prime_proto_tree(const dfilter_t *df, proto_tree *tree); - -GPtrArray * -dfilter_deprecated_tokens(dfilter_t *df); - -/* Print bytecode of dfilter to stdout */ -void -dfilter_dump(dfilter_t *df); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfunctions.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfunctions.h deleted file mode 100644 index f9e1e575..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfunctions.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * $Id: dfunctions.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * - * Copyright 2006 Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef DFUNCTIONS_H -#define DFUNCTIONS_H - -#include -#include -#include "syntax-tree.h" - -/* The run-time logic of the dfilter function */ -typedef gboolean (*DFFuncType)(GList *arg1list, GList *arg2list, GList **retval); - -/* The semantic check for the dfilter function */ -typedef void (*DFSemCheckType)(int param_num, stnode_t *st_node); - -/* If a function needs more args than this, increase - * this macro and add more arg members to the dfvm_insn_t - * struct in dfvm.h, and add some logic to dfw_append_function() - * and dfvm_apply() */ -#define DFUNCTION_MAX_NARGS 2 - -/* This is a "function definition" record, holding everything - * we need to know about a function */ -typedef struct { - const char *name; - DFFuncType function; - ftenum_t retval_ftype; - guint min_nargs; - guint max_nargs; - DFSemCheckType semcheck_param_function; -} df_func_def_t; - -/* Return the function definition record for a function of named "name" */ -df_func_def_t* df_func_lookup(char *name); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfvm.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfvm.h deleted file mode 100644 index 8e6e2507..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfvm.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * $Id: dfvm.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2001 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef DFVM_H -#define DFVM_H - -#include -#include -#include "dfilter-int.h" -#include "syntax-tree.h" -#include "drange.h" -#include "dfunctions.h" - -typedef enum { - EMPTY, - FVALUE, - HFINFO, - INSN_NUMBER, - REGISTER, - INTEGER, - DRANGE, - FUNCTION_DEF -} dfvm_value_type_t; - -typedef struct { - dfvm_value_type_t type; - - union { - fvalue_t *fvalue; - guint32 numeric; - drange *drange; - header_field_info *hfinfo; - df_func_def_t *funcdef; - } value; - -} dfvm_value_t; - - -typedef enum { - - IF_TRUE_GOTO, - IF_FALSE_GOTO, - CHECK_EXISTS, - NOT, - RETURN, - READ_TREE, - PUT_FVALUE, - ANY_EQ, - ANY_NE, - ANY_GT, - ANY_GE, - ANY_LT, - ANY_LE, - ANY_BITWISE_AND, - ANY_CONTAINS, - ANY_MATCHES, - MK_RANGE, - CALL_FUNCTION - -} dfvm_opcode_t; - -typedef struct { - int id; - dfvm_opcode_t op; - dfvm_value_t *arg1; - dfvm_value_t *arg2; - dfvm_value_t *arg3; - dfvm_value_t *arg4; -} dfvm_insn_t; - -dfvm_insn_t* -dfvm_insn_new(dfvm_opcode_t op); - -void -dfvm_insn_free(dfvm_insn_t *insn); - -dfvm_value_t* -dfvm_value_new(dfvm_value_type_t type); - -void -dfvm_dump(FILE *f, GPtrArray *insns); - -gboolean -dfvm_apply(dfilter_t *df, proto_tree *tree); - -void -dfvm_init_const(dfilter_t *df); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/drange.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/drange.h deleted file mode 100644 index 37ea4e8c..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/drange.h +++ /dev/null @@ -1,102 +0,0 @@ -/* drange.h - * Routines for providing general range support to the dfilter library - * - * $Id: drange.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Copyright (c) 2000 by Ed Warnicke - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1999 Gerald Combs - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __DRANGE_H__ -#define __DRANGE_H__ - -#include - -/* Please don't directly manipulate these structs. Please use - * the methods provided. If you REALLY can't do what you need to - * do with the methods provided please write new methods that do - * what you need, put them into the drange object here, and limit - * your direct manipulation of the drange and drange_node structs to - * here. - */ - -typedef enum { - UNINITIALIZED, - LENGTH, - OFFSET, - TO_THE_END -} drange_node_end_t; - -typedef struct _drange_node { - gint start_offset; - gint length; - gint end_offset; - drange_node_end_t ending; -} drange_node; - -typedef struct _drange { - GSList* range_list; - gboolean has_total_length; - gint total_length; - gint min_start_offset; - gint max_start_offset; -} drange; - -/* drange_node constructor */ -drange_node* drange_node_new(void); - -/* drange_node destructor */ -void drange_node_free(drange_node* drnode); - -/* Call drange_node destructor on all list items */ -void drange_node_free_list(GSList* list); - -/* drange_node accessors */ -gint drange_node_get_start_offset(drange_node* drnode); -gint drange_node_get_length(drange_node* drnode); -gint drange_node_get_end_offset(drange_node* drnode); -drange_node_end_t drange_node_get_ending(drange_node* drnode); - -/* drange_node mutators */ -void drange_node_set_start_offset(drange_node* drnode, gint offset); -void drange_node_set_length(drange_node* drnode, gint length); -void drange_node_set_end_offset(drange_node* drnode, gint offset); -void drange_node_set_to_the_end(drange_node* drnode); - -/* drange constructor */ -drange* drange_new(void); -drange* drange_new_from_list(GSList *list); - -/* drange destructor, only use this if you used drange_new() to creat - * the drange - */ -void drange_free(drange* dr); - -/* drange accessors */ -gboolean drange_has_total_length(drange* dr); -gint drange_get_total_length(drange* dr); -gint drange_get_min_start_offset(drange* dr); -gint drange_get_max_start_offset(drange* dr); - -/* drange mutators */ -void drange_append_drange_node(drange* dr, drange_node* drnode); -void drange_prepend_drange_node(drange* dr, drange_node* drnode); -void drange_foreach_drange_node(drange* dr, GFunc func, gpointer funcdata); - -#endif /* ! __DRANGE_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/gencode.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/gencode.h deleted file mode 100644 index 2148b2be..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/gencode.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef GENCODE_H -#define GENCODE_H - -void -dfw_gencode(dfwork_t *dfw); - -int* -dfw_interesting_fields(dfwork_t *dfw, int *caller_num_fields); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/glib-util.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/glib-util.h deleted file mode 100644 index f845cbe6..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/glib-util.h +++ /dev/null @@ -1,4 +0,0 @@ -/* $Id: glib-util.h 3992 2008-06-10 03:13:11Z dgu $ */ - -char* -g_substrdup(const char *s, int start, int len); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/grammar.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/grammar.h deleted file mode 100644 index 36c3e11f..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/grammar.h +++ /dev/null @@ -1,24 +0,0 @@ -#define TOKEN_TEST_AND 1 -#define TOKEN_TEST_OR 2 -#define TOKEN_TEST_EQ 3 -#define TOKEN_TEST_NE 4 -#define TOKEN_TEST_LT 5 -#define TOKEN_TEST_LE 6 -#define TOKEN_TEST_GT 7 -#define TOKEN_TEST_GE 8 -#define TOKEN_TEST_CONTAINS 9 -#define TOKEN_TEST_MATCHES 10 -#define TOKEN_TEST_BITWISE_AND 11 -#define TOKEN_TEST_NOT 12 -#define TOKEN_FIELD 13 -#define TOKEN_STRING 14 -#define TOKEN_UNPARSED 15 -#define TOKEN_LBRACKET 16 -#define TOKEN_RBRACKET 17 -#define TOKEN_COMMA 18 -#define TOKEN_INTEGER 19 -#define TOKEN_COLON 20 -#define TOKEN_HYPHEN 21 -#define TOKEN_FUNCTION 22 -#define TOKEN_LPAREN 23 -#define TOKEN_RPAREN 24 diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/scanner_lex.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/scanner_lex.h deleted file mode 100644 index 886d06b1..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/scanner_lex.h +++ /dev/null @@ -1,6 +0,0 @@ -/* This is generated by runlex.sh. Do not edit it. */ -#define yylex df_lex -#ifndef YY_DECL -#define YY_DECL int yylex(void) -#endif -YY_DECL; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/semcheck.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/semcheck.h deleted file mode 100644 index 5eac9804..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/semcheck.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * $Id: semcheck.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2001 Gerald Combs - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef SEMCHECK_H -#define SEMCHECK_H - -gboolean -dfw_semcheck(dfwork_t *dfw); - - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-function.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-function.h deleted file mode 100644 index fdcc9c58..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-function.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * $Id: sttype-function.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2001 Gerald Combs - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef STTYPE_FUNCTION_H -#define STTYPE_FUNCTION_H - -#include "dfunctions.h" - -/* Set the parameters for a function stnode_t. */ -void -sttype_function_set_params(stnode_t *node, GSList *params); - -/* Get the function-definition record for a function stnode_t. */ -df_func_def_t* sttype_function_funcdef(stnode_t *node); - -/* Get the parameters for a function stnode_t. */ -GSList* sttype_function_params(stnode_t *node); - -/* Free the memory of a param list */ -void st_funcparams_free(GSList *params); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-range.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-range.h deleted file mode 100644 index db92f76d..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-range.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * $Id: sttype-range.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2001 Gerald Combs - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef STTYPE_RANGE_H -#define STTYPE_RANGE_H - -#include "syntax-tree.h" -#include "drange.h" - -STTYPE_ACCESSOR_PROTOTYPE(header_field_info*, range, hfinfo) -STTYPE_ACCESSOR_PROTOTYPE(drange*, range, drange) - -/* Set a range */ -void -sttype_range_set(stnode_t *node, stnode_t *field, GSList* drange_list); - -void -sttype_range_set1(stnode_t *node, stnode_t *field, drange_node *rn); - -/* Clear the 'drange' variable to remove responsibility for - * freeing it. */ -void -sttype_range_remove_drange(stnode_t *node); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-test.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-test.h deleted file mode 100644 index 1635378b..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-test.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * $Id: sttype-test.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2001 Gerald Combs - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef STTYPE_TEST_H -#define STTYPE_TEST_H - -typedef enum { - TEST_OP_UNINITIALIZED, - TEST_OP_EXISTS, - TEST_OP_NOT, - TEST_OP_AND, - TEST_OP_OR, - TEST_OP_EQ, - TEST_OP_NE, - TEST_OP_GT, - TEST_OP_GE, - TEST_OP_LT, - TEST_OP_LE, - TEST_OP_BITWISE_AND, - TEST_OP_CONTAINS, - TEST_OP_MATCHES -} test_op_t; - -void -sttype_test_set1(stnode_t *node, test_op_t op, stnode_t *val1); - -void -sttype_test_set2(stnode_t *node, test_op_t op, stnode_t *val1, stnode_t *val2); - -void -sttype_test_set2_args(stnode_t *node, stnode_t *val1, stnode_t *val2); - -void -sttype_test_get(stnode_t *node, test_op_t *p_op, stnode_t **p_val1, stnode_t **p_val2); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/syntax-tree.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/syntax-tree.h deleted file mode 100644 index 0ea35f39..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/syntax-tree.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * $Id: syntax-tree.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2001 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef SYNTAX_TREE_H -#define SYNTAX_TREE_H - -#include -#include "cppmagic.h" - -typedef enum { - STTYPE_UNINITIALIZED, - STTYPE_TEST, - STTYPE_UNPARSED, - STTYPE_STRING, - STTYPE_FIELD, - STTYPE_FVALUE, - STTYPE_INTEGER, - STTYPE_RANGE, - STTYPE_FUNCTION, - STTYPE_NUM_TYPES -} sttype_id_t; - -typedef gpointer (*STTypeNewFunc)(gpointer); -typedef void (*STTypeFreeFunc)(gpointer); - - -/* Type information */ -typedef struct { - sttype_id_t id; - const char *name; - STTypeNewFunc func_new; - STTypeFreeFunc func_free; -} sttype_t; - -/* Node (type instance) information */ -typedef struct { - guint32 magic; - sttype_t *type; - - /* This could be made an enum, but I haven't - * set aside to time to do so. */ - gpointer data; - gint32 value; - const char *deprecated_token; -} stnode_t; - -/* These are the sttype_t registration function prototypes. */ -void sttype_register_function(void); -void sttype_register_integer(void); -void sttype_register_pointer(void); -void sttype_register_range(void); -void sttype_register_string(void); -void sttype_register_test(void); - -void -sttype_init(void); - -void -sttype_cleanup(void); - -void -sttype_register(sttype_t *type); - -stnode_t* -stnode_new(sttype_id_t type_id, gpointer data); - -void -stnode_init(stnode_t *node, sttype_id_t type_id, gpointer data); - -void -stnode_init_int(stnode_t *node, sttype_id_t type_id, gint32 value); - -void -stnode_free(stnode_t *node); - -const char* -stnode_type_name(stnode_t *node); - -sttype_id_t -stnode_type_id(stnode_t *node); - -gpointer -stnode_data(stnode_t *node); - -gint32 -stnode_value(stnode_t *node); - -const char * -stnode_deprecated(stnode_t *node); - -#define assert_magic(obj, mnum) \ - g_assert((obj)); \ - if ((obj)->magic != (mnum)) { \ - g_print("\nMagic num is 0x%08x, but should be 0x%08x", \ - (obj)->magic, (mnum)); \ - g_assert((obj)->magic == (mnum)); \ - } - - - - -#define STTYPE_ACCESSOR(ret,type,attr,magicnum) \ - ret \ - CONCAT(CONCAT(CONCAT(sttype_,type),_),attr) (stnode_t *node) \ -{\ - CONCAT(type,_t) *value; \ - value = stnode_data(node);\ - assert_magic(value, magicnum); \ - return value->attr; \ -} - -#define STTYPE_ACCESSOR_PROTOTYPE(ret,type,attr) \ - ret \ - CONCAT(CONCAT(CONCAT(sttype_,type),_),attr) (stnode_t *node); - - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/diam_dict.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/diam_dict.h deleted file mode 100644 index b36ba254..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/diam_dict.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - ** diam_dict.h - ** Diameter Dictionary Import Routines - ** - ** $Id: diam_dict.h 3992 2008-06-10 03:13:11Z dgu $ - ** - ** (c) 2007, Luis E. Garcia Ontanon - ** - ** This library is free software; you can redistribute it and/or - ** modify it under the terms of the GNU Library General Public - ** License as published by the Free Software Foundation; either - ** version 2 of the License, or (at your option) any later version. - ** - ** This library is distributed in the hope that it will be useful, - ** but WITHOUT ANY WARRANTY; without even the implied warranty of - ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - ** Library General Public License for more details. - ** - ** You should have received a copy of the GNU Library General Public - ** License along with this library; if not, write to the - ** Free Software Foundation, Inc., 59 Temple Place - Suite 330, - ** Boston, MA 02111-1307, USA. - */ - -#ifndef _DIAM_DICT_H_ -#define _DIAM_DICT_H_ - -struct _ddict_namecode_t { - char* name; - unsigned code; - struct _ddict_namecode_t* next; -}; - -typedef struct _ddict_namecode_t ddict_gavp_t; -typedef struct _ddict_namecode_t ddict_enum_t; -typedef struct _ddict_namecode_t ddict_application_t; - -typedef struct _ddict_vendor_t { - char* name; - char* desc; - unsigned code; - struct _ddict_vendor_t* next; -} ddict_vendor_t; - -typedef struct _ddict_avp_t { - char* name; - char* description; - char* vendor; - char* type; - unsigned code; - ddict_gavp_t* gavps; - ddict_enum_t* enums; - struct _ddict_avp_t* next; -} ddict_avp_t; - -typedef struct _ddict_typedefn_t { - char* name; - char* parent; - struct _ddict_typedefn_t* next; -} ddict_typedefn_t; - -typedef struct _ddict_cmd_t { - char* name; - char* vendor; - unsigned code; - struct _ddict_cmd_t* next; -} ddict_cmd_t; - -typedef struct _ddict_xmlpi_t { - char* name; - char* key; - char* value; - struct _ddict_xmlpi_t* next; -} ddict_xmlpi_t; - -typedef struct _ddict_t { - ddict_application_t* applications; - ddict_vendor_t* vendors; - ddict_cmd_t* cmds; - ddict_typedefn_t* typedefns; - ddict_avp_t* avps; - ddict_xmlpi_t* xmlpis; -} ddict_t; - -extern void ddict_print(FILE* fh, ddict_t* d); -extern ddict_t* ddict_scan(const char* directory, const char* filename, int dbg); -extern void ddict_free(ddict_t* d); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/diam_dict_lex.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/diam_dict_lex.h deleted file mode 100644 index 1135d99c..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/diam_dict_lex.h +++ /dev/null @@ -1,6 +0,0 @@ -/* This is generated by runlex.sh. Do not edit it. */ -#define yylex DiamDictlex -#ifndef YY_DECL -#define YY_DECL int yylex(void) -#endif -YY_DECL; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dissector_filters.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dissector_filters.h deleted file mode 100644 index 595c3d57..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dissector_filters.h +++ /dev/null @@ -1,60 +0,0 @@ -/* dissector_filters.h - * Routines for dissector generated display filters - * - * $Id: dissector_filters.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __DISSECTOR_FILTERS_H__ -#define __DISSECTOR_FILTERS_H__ - - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - - -/* callback function definition: is a filter available for this packet? */ -typedef gboolean (*is_filter_valid_func)(packet_info *pinfo); - -/* callback function definition: return the available filter for this packet or NULL if no filter is available */ -typedef const gchar* (*build_filter_string_func)(packet_info *pinfo); - - -/* register a dissector filter */ -extern void register_dissector_filter(const char *name, is_filter_valid_func is_filter_valid, build_filter_string_func build_filter_string); - - - -/*** THE FOLLOWING SHOULD NOT BE USED BY ANY DISSECTORS!!! ***/ - -typedef struct dissector_filter_s { - const char * name; - is_filter_valid_func is_filter_valid; - build_filter_string_func build_filter_string; -} dissector_filter_t; - -WS_VAR_IMPORT GList *dissector_filter_list; - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* dissector_filters.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dissectors/packet-tcp.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dissectors/packet-tcp.h deleted file mode 100644 index ee0b70cb..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dissectors/packet-tcp.h +++ /dev/null @@ -1,232 +0,0 @@ -/* packet-tcp.h - * - * $Id: packet-tcp.h 23902 2007-12-17 20:43:38Z sfisher $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __PACKET_TCP_H__ -#define __PACKET_TCP_H__ - -/* TCP flags */ -#define TH_FIN 0x01 -#define TH_SYN 0x02 -#define TH_RST 0x04 -#define TH_PUSH 0x08 -#define TH_ACK 0x10 -#define TH_URG 0x20 -#define TH_ECN 0x40 -#define TH_CWR 0x80 - -/* Idea for gt: either x > y, or y is much bigger (assume wrap) */ -#define GT_SEQ(x, y) ((gint32)((y) - (x)) < 0) -#define LT_SEQ(x, y) ((gint32)((x) - (y)) < 0) -#define GE_SEQ(x, y) ((gint32)((y) - (x)) <= 0) -#define LE_SEQ(x, y) ((gint32)((x) - (y)) <= 0) -#define EQ_SEQ(x, y) ((x) == (y)) - -/* the tcp header structure, passed to tap listeners */ -struct tcpheader { - guint32 th_seq; - guint32 th_ack; - gboolean th_have_seglen; /* TRUE if th_seglen is valid */ - guint32 th_seglen; - guint32 th_win; /* make it 32 bits so we can handle some scaling */ - guint16 th_sport; - guint16 th_dport; - guint8 th_hlen; - guint8 th_flags; - address ip_src; - address ip_dst; -}; - -/* - * Private data passed from the TCP dissector to subdissectors. Passed to the - * subdissectors in pinfo->private_data - */ -struct tcpinfo { - guint32 seq; /* Sequence number of first byte in the data */ - guint32 nxtseq; /* Sequence number of first byte after data */ - guint32 lastackseq; /* Sequence number of last ack */ - gboolean is_reassembled; /* This is reassembled data. */ - gboolean urgent; /* TRUE if "urgent_pointer" is valid */ - guint16 urgent_pointer; /* Urgent pointer value for the current packet. */ -}; - -/* - * Loop for dissecting PDUs within a TCP stream; assumes that a PDU - * consists of a fixed-length chunk of data that contains enough information - * to determine the length of the PDU, followed by rest of the PDU. - * - * The first three arguments are the arguments passed to the dissector - * that calls this routine. - * - * "proto_desegment" is the dissector's flag controlling whether it should - * desegment PDUs that cross TCP segment boundaries. - * - * "fixed_len" is the length of the fixed-length part of the PDU. - * - * "get_pdu_len()" is a routine called to get the length of the PDU from - * the fixed-length part of the PDU; it's passed "pinfo", "tvb" and "offset". - * - * "dissect_pdu()" is the routine to dissect a PDU. - */ -extern void -tcp_dissect_pdus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, - gboolean proto_desegment, guint fixed_len, - guint (*get_pdu_len)(packet_info *, tvbuff_t *, int), - dissector_t dissect_pdu); - -extern struct tcp_multisegment_pdu * -pdu_store_sequencenumber_of_next_pdu(packet_info *pinfo, guint32 seq, guint32 nxtpdu, emem_tree_t *multisegment_pdus); - -typedef struct _tcp_unacked_t { - struct _tcp_unacked_t *next; - guint32 frame; - guint32 seq; - guint32 nextseq; - nstime_t ts; -} tcp_unacked_t; - -struct tcp_acked { - guint32 frame_acked; - nstime_t ts; - - guint32 rto_frame; - nstime_t rto_ts; /* Time since previous packet for - retransmissions. */ - guint16 flags; - guint32 dupack_num; /* dup ack number */ - guint32 dupack_frame; /* dup ack to frame # */ -}; - -/* One instance of this structure is created for each pdu that spans across - * multiple tcp segments. - */ -struct tcp_multisegment_pdu { - guint32 seq; - guint32 nxtpdu; - guint32 first_frame; - guint32 last_frame; - nstime_t last_frame_time; - guint32 flags; -#define MSP_FLAGS_REASSEMBLE_ENTIRE_SEGMENT 0x00000001 -}; - -typedef struct _tcp_flow_t { - guint32 base_seq; /* base seq number (used by relative sequence numbers) - * or 0 if not yet known. - */ - tcp_unacked_t *segments; - guint32 lastack; /* last seen ack */ - nstime_t lastacktime; /* Time of the last ack packet */ - guint32 lastnondupack; /* frame number of last seen non dupack */ - guint32 dupacknum; /* dupack number */ - guint32 nextseq; /* highest seen nextseq */ - guint32 nextseqframe; /* frame number for segment with highest - * sequence number - */ - nstime_t nextseqtime; /* Time of the nextseq packet so we can - * distinguish between retransmission, - * fast retransmissions and outoforder - */ - guint32 window; /* last seen window */ - gint16 win_scale; /* -1 is we dont know */ -/* This tcp flow/session contains only one single PDU and should - * be reassembled until the final FIN segment. - */ -#define TCP_FLOW_REASSEMBLE_UNTIL_FIN 0x0001 - guint16 flags; - guint32 lastsegmentflags; - - /* This tree is indexed by sequence number and keeps track of all - * all pdus spanning multiple segments for this flow. - */ - emem_tree_t *multisegment_pdus; -} tcp_flow_t; - - -struct tcp_analysis { - /* These two structs are managed based on comparing the source - * and destination addresses and, if they're equal, comparing - * the source and destination ports. - * - * If the source is greater than the destination, then stuff - * sent from src is in ual1. - * - * If the source is less than the destination, then stuff - * sent from src is in ual2. - * - * XXX - if the addresses and ports are equal, we don't guarantee - * the behavior. - */ - tcp_flow_t flow1; - tcp_flow_t flow2; - - /* These pointers are set by get_tcp_conversation_data() - * fwd point in the same direction as the current packet - * and rev in the reverse direction - */ - tcp_flow_t *fwd; - tcp_flow_t *rev; - - /* This pointer is NULL or points to a tcp_acked struct if this - * packet has "interesting" properties such as being a KeepAlive or - * similar - */ - struct tcp_acked *ta; - /* This structure contains a tree containing all the various ta's - * keyed by frame number. - */ - emem_tree_t *acked_table; - - /* Remember the timestamp of the first frame seen in this tcp - * conversation to be able to calculate a relative time compared - * to the start of this conversation - */ - nstime_t ts_first; - - /* Remember the timestamp of the frame that was last seen in this - * tcp conversation to be able to calculate a delta time compared - * to previous frame in this conversation - */ - nstime_t ts_prev; -}; - -/* Structure that keeps per packet data. First used to be able - * to calculate the time_delta from the last seen frame in this - * TCP conversation. Can be extended for future use. - */ -struct tcp_per_packet_data_t { - nstime_t ts_del; -}; - - -extern void dissect_tcp_payload(tvbuff_t *tvb, packet_info *pinfo, int offset, - guint32 seq, guint32 nxtseq, guint32 sport, - guint32 dport, proto_tree *tree, - proto_tree *tcp_tree, - struct tcp_analysis *tcpd); - -extern struct tcp_analysis *get_tcp_conversation_data(packet_info *pinfo); - -extern gboolean decode_tcp_ports(tvbuff_t *, int, packet_info *, proto_tree *, int, int, struct tcp_analysis *); - - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd.h deleted file mode 100644 index 6063fb31..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * dtd.h - * - * XML dissector for Wireshark - * DTD import declarations - * - * Copyright 2005, Luis E. Garcia Ontanon - * - * $Id: dtd.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef _DTD_H_ -#define _DTD_H_ - -#include -#include /* exit() */ - -typedef struct _dtd_build_data_t { - gchar* proto_name; - gchar* media_type; - gchar* description; - gchar* proto_root; - gboolean recursion; - - GPtrArray* elements; - GPtrArray* attributes; - - GString* error; -} dtd_build_data_t; - -typedef struct _dtd_token_data_t { - gchar* text; - gchar* location; -} dtd_token_data_t; - -typedef struct _dtd_named_list_t { - gchar* name; - GPtrArray* list; -} dtd_named_list_t; - -extern GString* dtd_preparse(const gchar* dname, const gchar* fname, GString* err); -extern dtd_build_data_t* dtd_parse(GString* s); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_grammar.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_grammar.h deleted file mode 100644 index 732b0361..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_grammar.h +++ /dev/null @@ -1,23 +0,0 @@ -#define TOKEN_TAG_START 1 -#define TOKEN_DOCTYPE_KW 2 -#define TOKEN_NAME 3 -#define TOKEN_OPEN_BRACKET 4 -#define TOKEN_CLOSE_BRACKET 5 -#define TOKEN_TAG_STOP 6 -#define TOKEN_ATTLIST_KW 7 -#define TOKEN_ELEMENT_KW 8 -#define TOKEN_ATT_TYPE 9 -#define TOKEN_ATT_DEF 10 -#define TOKEN_ATT_DEF_WITH_VALUE 11 -#define TOKEN_QUOTED 12 -#define TOKEN_IMPLIED_KW 13 -#define TOKEN_REQUIRED_KW 14 -#define TOKEN_OPEN_PARENS 15 -#define TOKEN_CLOSE_PARENS 16 -#define TOKEN_PIPE 17 -#define TOKEN_STAR 18 -#define TOKEN_PLUS 19 -#define TOKEN_QUESTION 20 -#define TOKEN_ELEM_DATA 21 -#define TOKEN_COMMA 22 -#define TOKEN_EMPTY_KW 23 diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_parse.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_parse.h deleted file mode 100644 index 99a9958a..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_parse.h +++ /dev/null @@ -1,37 +0,0 @@ -/* dtd_parse.h -* an XML dissector for Wireshark -* header file to declare functions defined in lexer and used in parser, -* or vice versa -* -* Copyright 2004, Luis E. Garcia Ontanon -* -* $Id: dtd_parse.h 3992 2008-06-10 03:13:11Z dgu $ -* -* Wireshark - Network traffic analyzer -* By Gerald Combs -* Copyright 1998 Gerald Combs -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version 2 -* of the License, or (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -extern void DtdParse(void*,int,dtd_token_data_t*,dtd_build_data_t*); -#if (GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 16)) -extern void *DtdParseAlloc(void *(*)(gsize)); -#else -extern void *DtdParseAlloc(void *(*)(gulong)); -#endif -extern void DtdParseFree( void*, void(*)(void*) ); -extern void DtdParseTrace(FILE *TraceFILE, char *zTracePrompt); -extern int Dtd_Parse_lex(void); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_parse_lex.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_parse_lex.h deleted file mode 100644 index c809f40b..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_parse_lex.h +++ /dev/null @@ -1,6 +0,0 @@ -/* This is generated by runlex.sh. Do not edit it. */ -#define yylex Dtd_Parse_lex -#ifndef YY_DECL -#define YY_DECL int yylex(void) -#endif -YY_DECL; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_preparse_lex.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_preparse_lex.h deleted file mode 100644 index dc4b7bcf..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_preparse_lex.h +++ /dev/null @@ -1,6 +0,0 @@ -/* This is generated by runlex.sh. Do not edit it. */ -#define yylex Dtd_PreParse_lex -#ifndef YY_DECL -#define YY_DECL int yylex(void) -#endif -YY_DECL; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/eap.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/eap.h deleted file mode 100644 index 24934ceb..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/eap.h +++ /dev/null @@ -1,53 +0,0 @@ -/* sminmpec.h - * Extenal definitions for EAP Extensible Authentication Protocol dissection - * RFC 2284, RFC 3748 - * - * $Id: eap.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2004 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __EAP_H__ -#define __EAP_H__ - -#define EAP_REQUEST 1 -#define EAP_RESPONSE 2 -#define EAP_SUCCESS 3 -#define EAP_FAILURE 4 - -WS_VAR_IMPORT const value_string eap_code_vals[]; - -#define EAP_TYPE_ID 1 -#define EAP_TYPE_NOTIFY 2 -#define EAP_TYPE_NAK 3 -#define EAP_TYPE_MD5 4 -#define EAP_TYPE_TLS 13 -#define EAP_TYPE_LEAP 17 -#define EAP_TYPE_SIM 18 -#define EAP_TYPE_TTLS 21 -#define EAP_TYPE_AKA 23 -#define EAP_TYPE_PEAP 25 -#define EAP_TYPE_MSCHAPV2 26 -#define EAP_TYPE_FAST 43 -#define EAP_TYPE_EXT 254 - -WS_VAR_IMPORT const value_string eap_type_vals[]; - - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/emem.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/emem.h deleted file mode 100644 index a1e0c898..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/emem.h +++ /dev/null @@ -1,373 +0,0 @@ -/* emem.h - * Definitions for Wireshark memory management and garbage collection - * Ronnie Sahlberg 2005 - * - * $Id: emem.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __EMEM_H__ -#define __EMEM_H__ - -#include "gnuc_format_check.h" - -/* Functions for handling memory allocation and garbage collection with - * a packet lifetime scope. - * These functions are used to allocate memory that will only remain persistent - * until Wireshark starts dissecting the next packet in the list. - * Everytime Wireshark starts decoding the next packet all memory allocated - * through these functions will be released back to the free pool. - * - * These functions are very fast and offer automatic garbage collection: - * Everytime a new packet is dissected, all memory allocations done in - * the previous packet is freed. - */ -/* Initialize packet-lifetime memory allocation pool. This function is called - * once when [t]Wireshark is initialized to set up the required structures. - */ -void ep_init_chunk(void); - -/* Allocate memory with a packet lifetime scope */ -void *ep_alloc(size_t size); -#define ep_new(type) ((type*)ep_alloc(sizeof(type))) - -/* Allocate memory with a packet lifetime scope and fill it with zeros*/ -void* ep_alloc0(size_t size); -#define ep_new0(type) ((type*)ep_alloc0(sizeof(type))) - -/* Duplicate a string with a packet lifetime scope */ -gchar* ep_strdup(const gchar* src); - -/* Duplicate at most n characters of a string with a packet lifetime scope */ -gchar* ep_strndup(const gchar* src, size_t len); - -/* Duplicate a buffer with a packet lifetime scope */ -void* ep_memdup(const void* src, size_t len); - -/* Create a formatted string with a packet lifetime scope */ -gchar* ep_strdup_vprintf(const gchar* fmt, va_list ap); -gchar* ep_strdup_printf(const gchar* fmt, ...) - GNUC_FORMAT_CHECK(printf, 1, 2); - -/* allocates with a packet lifetime scope an array of type made of num elements */ -#define ep_alloc_array(type,num) (type*)ep_alloc(sizeof(type)*(num)) - -/* allocates with a packet lifetime scope an array of type made of num elements, - * initialised to zero. - */ -#define ep_alloc_array0(type,num) (type*)ep_alloc0(sizeof(type)*(num)) - -/* - * Splits a string into a maximum of max_tokens pieces, using the given - * delimiter. If max_tokens is reached, the remainder of string is appended - * to the last token. Consecutive delimiters are treated as a single delimiter. - * - * the vector and all the strings are allocated with packet lifetime scope - */ -gchar** ep_strsplit(const gchar* string, const gchar* delimiter, int max_tokens); - -/* release all memory allocated in the previous packet dissector */ -void ep_free_all(void); - - -/* a stack implemented using ephemeral allocators */ - -typedef struct _ep_stack_frame_t** ep_stack_t; - -struct _ep_stack_frame_t { - void* payload; - struct _ep_stack_frame_t* below; - struct _ep_stack_frame_t* above; -}; - -/* - * creates an empty stack with a packet lifetime scope - */ -ep_stack_t ep_stack_new(void); - -/* - * pushes item into stack, returns item - */ -void* ep_stack_push(ep_stack_t stack, void* item); - -/* - * pops an item from the stack - */ -void* ep_stack_pop(ep_stack_t stack); - -/* - * returns the item on top of the stack without popping it - */ -#define ep_stack_peek(stack) ((*(stack))->payload) - - -/* Functions for handling memory allocation and garbage collection with - * a capture lifetime scope. - * These functions are used to allocate memory that will only remain persistent - * until Wireshark opens a new capture or capture file. - * Everytime Wireshark starts a new capture or opens a new capture file - * all the data allocated through these functions will be released back - * to the free pool. - * - * These functions are very fast and offer automatic garbage collection. - */ -/* Initialize capture-lifetime memory allocation pool. This function is called - * once when [t]Wireshark is initialized to set up the required structures. - */ -void se_init_chunk(void); - -/* Allocate memory with a capture lifetime scope */ -void *se_alloc(size_t size); - -/* Allocate memory with a capture lifetime scope and fill it with zeros*/ -void* se_alloc0(size_t size); - -/* Duplicate a string with a capture lifetime scope */ -gchar* se_strdup(const gchar* src); - -/* Duplicate at most n characters of a string with a capture lifetime scope */ -gchar* se_strndup(const gchar* src, size_t len); - -/* Duplicate a buffer with a capture lifetime scope */ -void* se_memdup(const void* src, size_t len); - -/* Create a formatted string with a capture lifetime scope */ -gchar* se_strdup_vprintf(const gchar* fmt, va_list ap); -gchar* se_strdup_printf(const gchar* fmt, ...) - GNUC_FORMAT_CHECK(printf, 1, 2); - -/* allocates with a capture lifetime scope an array of type made of num elements */ -#define se_alloc_array(type,num) (type*)se_alloc(sizeof(type)*(num)) - -/* release all memory allocated */ -void se_free_all(void); - - - - -/************************************************************** - * binary trees - **************************************************************/ -typedef struct _emem_tree_node_t { - struct _emem_tree_node_t *parent; - struct _emem_tree_node_t *left; - struct _emem_tree_node_t *right; - struct { -#define EMEM_TREE_RB_COLOR_RED 0 -#define EMEM_TREE_RB_COLOR_BLACK 1 - guint32 rb_color:1; -#define EMEM_TREE_NODE_IS_DATA 0 -#define EMEM_TREE_NODE_IS_SUBTREE 1 - guint32 is_subtree:1; - } u; - guint32 key32; - void *data; -} emem_tree_node_t; - -/* Right now we only do basic red/black trees but in the future we might want - * to try something different, such as a tree where each node keeps track - * of how many times it has been looked up, and letting often looked up - * nodes bubble upwards in the tree using rotate_right/left. - * That would probably be good for things like nfs filehandles - */ -#define EMEM_TREE_TYPE_RED_BLACK 1 -typedef struct _emem_tree_t { - struct _emem_tree_t *next; - int type; - const char *name; /* just a string to make debugging easier */ - emem_tree_node_t *tree; - void *(*malloc)(size_t); -} emem_tree_t; - -/* list of all trees with se allocation scope so that they can all be reset - * automatically when we free all se memory - */ -extern emem_tree_t *se_trees; - - -/* ******************************************************************* - * Tree functions for SE memory allocation scope - * ******************************************************************* */ -/* This function is used to create a se based tree with monitoring. - * When the SE heap is released back to the system the pointer to the - * tree is automatically reset to NULL. - * - * type is : EMEM_TREE_TYPE_RED_BLACK for a standard red/black tree. - */ -emem_tree_t *se_tree_create(int type, const char *name); - -/* This function is similar to the se_tree_create() call but with the - * difference that when the se memory is release everything including the - * pointer to the tree itself will be released. - * This tree will not be just reset to zero it will be completely forgotten - * by the allocator. - * Use this function for when you want to store the pointer to a tree inside - * another structure that is also se allocated so that when the structure is - * released, the tree will be completely released as well. - */ -emem_tree_t *se_tree_create_non_persistent(int type, const char *name); - -/* se_tree_insert32 - * Insert data into the tree and key it by a 32bit integer value - */ -#define se_tree_insert32 emem_tree_insert32 - -/* se_tree_lookup32 - * Retreive the data at the search key. the search key is a 32bit integer value - */ -#define se_tree_lookup32 emem_tree_lookup32 - -/* se_tree_lookup32_le - * Retreive the data for the largest key that is less than or equal - * to the search key. - */ -#define se_tree_lookup32_le emem_tree_lookup32_le - -/* se_tree_insert32_array - * Insert data into the tree and key it by a 32bit integer value - */ -#define se_tree_insert32_array emem_tree_insert32_array - -/* se_tree_lookup32_array - * Lookup data from the tree that is index by an array - */ -#define se_tree_lookup32_array emem_tree_lookup32_array - - - -/* Create a new string based hash table */ -#define se_tree_create_string() se_tree_create(SE_TREE_TYPE_RED_BLACK) - -/* Insert a new value under a string key */ -#define se_tree_insert_string emem_tree_insert_string - -/* Lookup the value under a string key */ -#define se_tree_lookup_string emem_tree_lookup_string - -/* Traverse a tree */ -#define se_tree_foreach emem_tree_foreach - - -/* ******************************************************************* - * Tree functions for PE memory allocation scope - * ******************************************************************* */ -/* These trees have PErmanent allocation scope and will never be released - */ -emem_tree_t *pe_tree_create(int type, char *name); -#define pe_tree_insert32 emem_tree_insert32 -#define pe_tree_lookup32 emem_tree_lookup32 -#define pe_tree_lookup32_le emem_tree_lookup32_le -#define pe_tree_insert32_array emem_tree_insert32_array -#define pe_tree_lookup32_array emem_tree_lookup32_array -#define pe_tree_insert_string emem_tree_insert_string -#define pe_tree_lookup_string emem_tree_lookup_string -#define pe_tree_foreach emem_tree_foreach - - - -/* ****************************************************************** - * Real tree functions - * ****************************************************************** */ - -/* This function is used to insert a node indexed by a guint32 key value. - * The data pointer should be allocated by the appropriate storage scope - * so that it will be released at the same time as the tree itself is - * destroyed. - */ -void emem_tree_insert32(emem_tree_t *se_tree, guint32 key, void *data); - -/* This function will look up a node in the tree indexed by a guint32 integer - * value. - */ -void *emem_tree_lookup32(emem_tree_t *se_tree, guint32 key); - -/* This function will look up a node in the tree indexed by a guint32 integer - * value. - * The function will return the node that has the largest key that is - * equal to or smaller than the search key, or NULL if no such key was - * found. - */ -void *emem_tree_lookup32_le(emem_tree_t *se_tree, guint32 key); - -typedef struct _emem_tree_key_t { - guint32 length; /*length in guint32 words */ - guint32 *key; -} emem_tree_key_t; - -/* This function is used to insert a node indexed by a sequence of guint32 - * key values. - * The data pointer should be allocated by SE allocators so that the - * data will be released at the same time as the tree itself is destroyed. - * - * Note: all the "key" members of the "key" argument MUST be aligned on - * 32-bit boundaries; otherwise, this code will crash on platforms such - * as SPARC that require aligned pointers. - * - * If you use ...32_array() calls you MUST make sure that every single node - * you add to a specific tree always has a key of exactly the same number of - * keylen words or things will most likely crash. Or at least that every single - * item that sits behind the same top level node always have exactly the same - * number of words. - * - * One way to guarantee this is the way that NFS does this for the - * nfs_name_snoop_known tree which holds filehandles for both v2 and v3. - * v2 filehandles are always 32 bytes (8 words) while v3 filehandles can have - * any length (though 32bytes are most common). - * The NFS dissector handles this by providing a guint32 containing the length - * as the very first item in this vector : - * - * emem_tree_key_t fhkey[3]; - * - * fhlen=nns->fh_length; - * fhkey[0].length=1; - * fhkey[0].key=&fhlen; - * fhkey[1].length=fhlen/4; - * fhkey[1].key=nns->fh; - * fhkey[2].length=0; - */ -void emem_tree_insert32_array(emem_tree_t *se_tree, emem_tree_key_t *key, void *data); - -/* This function will look up a node in the tree indexed by a sequence of - * guint32 integer values. - */ -void *emem_tree_lookup32_array(emem_tree_t *se_tree, emem_tree_key_t *key); - -/* case insensitive strings as keys */ -#define EMEM_TREE_STRING_NOCASE 0x00000001 -/* Insert a new value under a string key */ -void emem_tree_insert_string(emem_tree_t* h, const gchar* k, void* v, guint32 flags); - -/* Lookup the value under a string key */ -void* emem_tree_lookup_string(emem_tree_t* h, const gchar* k, guint32 flags); - - -/* traverse a tree. if the callback returns TRUE the traversal will end */ -typedef gboolean (*tree_foreach_func)(void *value, void *userdata); - -gboolean emem_tree_foreach(emem_tree_t* emem_tree, tree_foreach_func callback, void *user_data); - - - - -void emem_print_tree(emem_tree_t* emem_tree); - - - -#endif /* emem.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/epan.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/epan.h deleted file mode 100644 index 9da31108..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/epan.h +++ /dev/null @@ -1,93 +0,0 @@ -/* epan.h - * - * $Id: epan.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark Protocol Analyzer Library - * - * Copyright (c) 2001 by Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef EPAN_H -#define EPAN_H - -#include -#include "frame_data.h" -#include "column_info.h" -#include "register.h" - -typedef struct _epan_dissect_t epan_dissect_t; - -#include "dfilter/dfilter.h" - -/* init the whole epan module, this is used to be called only once in a program */ -void epan_init(void (*register_all_protocols)(register_cb cb, gpointer client_data), - void (*register_all_handoffs)(register_cb cb, gpointer client_data), - register_cb cb, - void *client_data, - void (*report_failure)(const char *, va_list), - void (*report_open_failure)(const char *, int, gboolean), - void (*report_read_failure)(const char *, int)); -/* cleanup the whole epan module, this is used to be called only once in a program */ -void epan_cleanup(void); -/* Initialize the table of conversations. */ -void epan_conversation_init(void); -/* Initialize the table of circuits. */ -/* XXX - what is a circuit and should this better be combined with epan_conversation_init? */ -void epan_circuit_init(void); - -/* A client will create one epan_t for an entire dissection session. - * A single epan_t will be used to analyze the entire sequence of packets, - * sequentially, in a single session. A session corresponds to a single - * packet trace file. The reaons epan_t exists is that some packets in - * some protocols cannot be decoded without knowledge of previous packets. - * This inter-packet "state" is stored in the epan_t. - */ -/* XXX - NOTE: epan_t, epan_new and epan_free are currently unused! */ -typedef struct epan_session epan_t; - -epan_t* -epan_new(void); - -void -epan_free(epan_t*); - -extern gchar* -epan_get_version(void); - -/* get a new single packet dissection */ -/* should be freed using epan_dissect_free() after packet dissection completed */ -epan_dissect_t* -epan_dissect_new(gboolean create_proto_tree, gboolean proto_tree_visible); - -/* run a single packet dissection */ -void -epan_dissect_run(epan_dissect_t *edt, void* pseudo_header, - const guint8* data, frame_data *fd, column_info *cinfo); - -/* Prime a proto_tree using the fields/protocols used in a dfilter. */ -void -epan_dissect_prime_dfilter(epan_dissect_t *edt, const dfilter_t *dfcode); - -/* fill the dissect run output into the packet list columns */ -void -epan_dissect_fill_in_columns(epan_dissect_t *edt); - -/* free a single packet dissection */ -void -epan_dissect_free(epan_dissect_t* edt); - -#endif /* EPAN_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/epan_dissect.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/epan_dissect.h deleted file mode 100644 index 9f40f39a..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/epan_dissect.h +++ /dev/null @@ -1,44 +0,0 @@ -/* epan_dissect.h - * - * $Id: epan_dissect.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark Protocol Analyzer Library - * - * Copyright (c) 2001 by Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef EPAN_DISSECT_H -#define EPAN_DISSECT_H - -#include "tvbuff.h" -#include "proto.h" -#include "packet_info.h" - -/* Dissection of a single byte array. Holds tvbuff info as - * well as proto_tree info. As long as the epan_dissect_t for a byte - * array is in existence, you must not free or move that byte array, - * as the structures that the epan_dissect_t contains might have pointers - * to addresses in your byte array. - */ -struct _epan_dissect_t { - tvbuff_t *tvb; - proto_tree *tree; - packet_info pi; -}; - - -#endif /* EPAN_DISSECT_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/etypes.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/etypes.h deleted file mode 100644 index 34898676..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/etypes.h +++ /dev/null @@ -1,408 +0,0 @@ -/* etypes.h - * Defines ethernet packet types, similar to tcpdump's ethertype.h - * - * $Id: etypes.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __ETYPES_H__ -#define __ETYPES_H__ - -/* - * Maximum length of an IEEE 802.3 frame; Ethernet type/length values - * greater than it are types, Ethernet type/length values less than or - * equal to it are lengths. - */ -#define IEEE_802_3_MAX_LEN 1500 - -#ifndef ETHERTYPE_UNK -#define ETHERTYPE_UNK 0x0000 -#endif - -/* Sources: - * http://www.iana.org/assignments/ethernet-numbers - * TCP/IP Illustrated, Volume 1 - * RFCs 894, 1042, 826 - * tcpdump's ethertype.h - * http://www.cavebear.com/CaveBear/Ethernet/ - * http://standards.ieee.org/regauth/ethertype/type-pub.html - * http://standards.ieee.org/regauth/ethertype/eth.txt - * (The first of the two IEEE URLs is the one that the "EtherType Field - * Public Assignments" link on the page at - * - * http://standards.ieee.org/regauth/ethertype/index.shtml - * - * goes to, but it is redirected to the second of those - i.e., both - * of the IEEE URLs ultimately go to the same page.) - */ - -/* Order these values by number */ - -#ifndef ETHERTYPE_XNS_IDP -#define ETHERTYPE_XNS_IDP 0x0600 -#endif - -#ifndef ETHERTYPE_IP -#define ETHERTYPE_IP 0x0800 -#endif - -#ifndef ETHERTYPE_X25L3 -#define ETHERTYPE_X25L3 0x0805 -#endif - -#ifndef ETHERTYPE_ARP -#define ETHERTYPE_ARP 0x0806 -#endif - -#ifndef ETHERTYPE_WOL -#define ETHERTYPE_WOL 0x0842 /* Wake on LAN. Not offically registered. */ -#endif - -#ifndef ETHERTYPE_WMX_M2M -#define ETHERTYPE_WMX_M2M 0x08f0 -#endif - -#ifndef ETHERTYPE_VINES_IP -#define ETHERTYPE_VINES_IP 0x0bad -#endif - -#ifndef ETHERTYPE_VINES_ECHO -#define ETHERTYPE_VINES_ECHO 0x0baf -#endif - -#ifndef ETHERTYPE_TRAIN -/* - * Created by Microsoft Network Monitor as a summary packet. - */ -#define ETHERTYPE_TRAIN 0x1984 -#endif - -#ifndef ETHERTYPE_CGMP -#define ETHERTYPE_CGMP 0x2001 -#endif - -#ifndef ETHERTYPE_CENTRINO_PROMISC -#define ETHERTYPE_CENTRINO_PROMISC 0x2452 /* Intel Centrino promiscuous packets */ -#endif - -#ifndef ETHERTYPE_3C_NBP_DGRAM -#define ETHERTYPE_3C_NBP_DGRAM 0x3c07 -#endif - -#ifndef ETHERTYPE_EPL_V1 -#define ETHERTYPE_EPL_V1 0x3E3F -#endif - -#ifndef ETHERTYPE_DEC -#define ETHERTYPE_DEC 0x6000 -#endif - -#ifndef ETHERTYPE_DNA_DL -#define ETHERTYPE_DNA_DL 0x6001 -#endif - -#ifndef ETHERTYPE_DNA_RC -#define ETHERTYPE_DNA_RC 0x6002 -#endif - -#ifndef ETHERTYPE_DNA_RT -#define ETHERTYPE_DNA_RT 0x6003 -#endif - -#ifndef ETHERTYPE_LAT -#define ETHERTYPE_LAT 0x6004 -#endif - -#ifndef ETHERTYPE_DEC_DIAG -#define ETHERTYPE_DEC_DIAG 0x6005 -#endif - -#ifndef ETHERTYPE_DEC_CUST -#define ETHERTYPE_DEC_CUST 0x6006 -#endif - -#ifndef ETHERTYPE_DEC_SCA -#define ETHERTYPE_DEC_SCA 0x6007 -#endif - -#ifndef ETHERTYPE_ETHBRIDGE -#define ETHERTYPE_ETHBRIDGE 0x6558 /* transparent Ethernet bridging [RFC1701]*/ -#endif - -#ifndef ETHERTYPE_RAW_FR -#define ETHERTYPE_RAW_FR 0x6559 /* Raw Frame Relay [RFC1701] */ -#endif - -#ifndef ETHERTYPE_REVARP -#define ETHERTYPE_REVARP 0x8035 -#endif - -#ifndef ETHERTYPE_DEC_LB -#define ETHERTYPE_DEC_LB 0x8038 -#endif - -#ifndef ETHERTYPE_DEC_LAST -#define ETHERTYPE_DEC_LAST 0x8041 /* DEC Local Area Systems Transport */ -#endif - -#ifndef ETHERTYPE_ATALK -#define ETHERTYPE_ATALK 0x809b -#endif - -#ifndef ETHERTYPE_SNA -#define ETHERTYPE_SNA 0x80d5 -#endif - -#ifndef ETHERTYPE_AARP -#define ETHERTYPE_AARP 0x80f3 -#endif - -#ifndef ETHERTYPE_VLAN -#define ETHERTYPE_VLAN 0x8100 /* 802.1Q Virtual LAN */ -#endif - -#ifndef ETHERTYPE_NSRP -#define ETHERTYPE_NSRP 0x8133 -#endif - -#ifndef ETHERTYPE_IPX -#define ETHERTYPE_IPX 0x8137 -#endif - -#ifndef ETHERTYPE_SNMP -#define ETHERTYPE_SNMP 0x814c /* SNMP over Ethernet, RFC 1089 */ -#endif - -#ifndef ETHERTYPE_WCP -#define ETHERTYPE_WCP 0x80ff /* Wellfleet Compression Protocol */ -#endif - -#ifndef ETHERTYPE_STP -#define ETHERTYPE_STP 0x8181 /* STP, HIPPI-ST */ -#endif - -#ifndef ETHERTYPE_ISMP -#define ETHERTYPE_ISMP 0x81fd /* Cabletron Interswitch Message Protocol */ -#endif - -#ifndef ETHERTYPE_ISMP_TBFLOOD -#define ETHERTYPE_ISMP_TBFLOOD 0x81ff /* Cabletron Interswitch Message Protocol */ -#endif - -#ifndef ETHERTYPE_IPv6 -#define ETHERTYPE_IPv6 0x86dd -#endif - -#ifndef ETHERTYPE_WLCCP -#define ETHERTYPE_WLCCP 0x872d /* Cisco Wireless Lan Context Control Protocol */ -#endif - -#ifndef ETHERTYPE_MAC_CONTROL -#define ETHERTYPE_MAC_CONTROL 0x8808 -#endif - -#ifndef ETHERTYPE_SLOW_PROTOCOLS -#define ETHERTYPE_SLOW_PROTOCOLS 0x8809 -#endif - -#ifndef ETHERTYPE_PPP -#define ETHERTYPE_PPP 0x880b /* no, this is not PPPoE */ -#endif - -#ifndef ETHERTYPE_COBRANET -#define ETHERTYPE_COBRANET 0x8819 /* Cirrus cobranet */ -#endif - -#ifndef ETHERTYPE_MPLS -#define ETHERTYPE_MPLS 0x8847 /* MPLS unicast packet */ -#endif - -#ifndef ETHERTYPE_MPLS_MULTI -#define ETHERTYPE_MPLS_MULTI 0x8848 /* MPLS multicast packet */ -#endif - -#ifndef ETHERTYPE_FOUNDRY -#define ETHERTYPE_FOUNDRY 0x885a /* Some Foundry proprietary protocol */ -#endif - -#ifndef ETHERTYPE_PPPOED -#define ETHERTYPE_PPPOED 0x8863 /* PPPoE Discovery Protocol */ -#endif - -#ifndef ETHERTYPE_PPPOES -#define ETHERTYPE_PPPOES 0x8864 /* PPPoE Session Protocol */ -#endif - -#ifndef ETHERTYPE_INTEL_ANS -#define ETHERTYPE_INTEL_ANS 0x886d /* Intel ANS (NIC teaming) http://www.intel.com/support/network/adapter/ans/probes.htm */ -#endif - -#ifndef ETHERTYPE_MS_NLB_HEARTBEAT -#define ETHERTYPE_MS_NLB_HEARTBEAT 0x886f /* MS Network Load Balancing heartbeat http://www.microsoft.com/technet/treeview/default.asp?url=/TechNet/prodtechnol/windows2000serv/deploy/confeat/nlbovw.asp */ -#endif - -#ifndef ETHERTYPE_HOMEPLUG -#define ETHERTYPE_HOMEPLUG 0x887B /* IEEE assigned Ethertype */ -#endif - -#ifndef ETHERTYPE_CDMA2000_A10_UBS -#define ETHERTYPE_CDMA2000_A10_UBS 0x8881 /* the byte stream protocol that is used for IP based micro-mobility bearer interfaces (A10) in CDMA2000(R)-based wireless networks */ -#endif - -#ifndef ETHERTYPE_EAPOL -#define ETHERTYPE_EAPOL 0x888e /* 802.1x Authentication */ -#endif - -#ifndef ETHERTYPE_PROFINET -#define ETHERTYPE_PROFINET 0x8892 /* PROFIBUS PROFINET protocol */ -#endif - -#ifndef ETHERTYPE_HYPERSCSI -#define ETHERTYPE_HYPERSCSI 0x889A /* HyperSCSI */ -#endif - -#ifndef ETHERTYPE_CSM_ENCAPS -#define ETHERTYPE_CSM_ENCAPS 0x889B /* Mindspeed Technologies www.mindspeed.com */ -#endif - -#ifndef ETHERTYPE_TELKONET -#define ETHERTYPE_TELKONET 0x88A1 /* Telkonet powerline ethernet */ -#endif - -#ifndef ETHERTYPE_AOE -#define ETHERTYPE_AOE 0x88A2 -#endif - -#ifndef ETHERTYPE_ECATF -#define ETHERTYPE_ECATF 0x88A4 /* Ethernet type for EtherCAT frames */ -#endif - -#ifndef ETHERTYPE_IEEE_802_1AD -#define ETHERTYPE_IEEE_802_1AD 0x88A8 /* IEEE 802.1ad Provider Bridge, Q-in-Q */ -#endif - -#ifndef ETHERTYPE_EPL_V2 -#define ETHERTYPE_EPL_V2 0x88AB -#endif - -#ifndef ETHERTYPE_BRDWALK -#define ETHERTYPE_BRDWALK 0x88AE -#endif - -#ifndef ETHERTYPE_IEEE802_OUI_EXTENDED -#define ETHERTYPE_IEEE802_OUI_EXTENDED 0x88B7 /* IEEE 802a OUI Extended Ethertype */ -#endif - -#ifndef ETHERTYPE_IEC61850_GOOSE -#define ETHERTYPE_IEC61850_GOOSE 0x88b8 /* IEC 61850 is a global standard for the use in utility communication,*/ -#endif /* in particular for the information exchange between IED's in a power */ - /* transmission or distribution substation. */ - /* There are three types of application services - that use a specific EtherType. GOOSE uses - EtherType field 88b8, GSE management services - uses EtherType field 88b9. These two protocols - are defined in IEC 61850-8-1. SV (Sampled - Value Transmission) uses EtherType field - 88ba; the protocol is defined in IEC 61850-9-1 - and IEC 61850-9-2. */ - -#ifndef ETHERTYPE_IEC61850_GSE -#define ETHERTYPE_IEC61850_GSE 0x88b9 /* IEC 61850 is a global standard for the use in utility communication,*/ -#endif /* in particular for the information exchange between IED's in a power */ - -#ifndef ETHERTYPE_IEC61850_SV -#define ETHERTYPE_IEC61850_SV 0x88ba /* IEC 61850 is a global standard for the use in utility communication,*/ -#endif /* in particular for the information exchange between IED's in a power */ - -#ifndef ETHERTYPE_TIPC -#define ETHERTYPE_TIPC 0x88ca /* TIPC (Transparent Inter Process Communication, */ -#endif /* http://tipc.sourceforge.net/) Ericsson Research Canada Inc */ - -#ifndef ETHERTYPE_RSN_PREAUTH -#define ETHERTYPE_RSN_PREAUTH 0x88c7 /* 802.11i Pre-Authentication */ -#endif - -#ifndef ETHERTYPE_LLDP -#define ETHERTYPE_LLDP 0x88cc /* IEEE 802.1AB Link Layer Discovery Protocol (LLDP) */ -#endif - -#ifndef ETHERTYPE_SERCOS -#define ETHERTYPE_SERCOS 0x88cd /* SERCOS interface real-time protocol for motion control */ -#endif - -#ifndef ETHERTYPE_3GPP2 -#define ETHERTYPE_3GPP2 0x88d2 /* This will be used in a revision of the Interoperabi */ -#endif /* Specification (IOS) for cdma2000 Access Network Interfaces (document numbers A.S0011-B */ - /* through A.S0017-B v1.0). This document already uses the Ether type 8881 */ - -#ifndef ETHERTYPE_LLTD -#define ETHERTYPE_LLTD 0x88d9 /* Link Layer Topology Discovery (LLTD) */ -#endif - -#ifndef ETHERTYPE_MRP -#define ETHERTYPE_MRP 0x88e3 /* IEC 61158-6-10 Media Redundancy Protocol (MRP) */ -#endif - -#ifndef ETHERTYPE_IEEE_802_1AH -#define ETHERTYPE_IEEE_802_1AH 0x88F0 /* IEEE 802.1ah Provider Backbone Bridge Mac-in-Mac */ -#endif - -#ifndef ETHERTYPE_PTP -#define ETHERTYPE_PTP 0x88F7 /* IEEE1588v2 (PTPv2) over Ethernet */ -#endif /* in particular for the information exchange between IED's in a power */ - /* transmission or distribution substation. */ - /* There are three types of application services */ - -#ifndef ETHERTYPE_PRP -#define ETHERTYPE_PRP 0x88FB /* Parallel Redundancy Protocol (IEC62439 Chapter 6) */ -#endif - -#ifndef ETHERTYPE_CFM -#define ETHERTYPE_CFM 0x8902 /* IEEE 802.1ag Connectivity Fault Management */ -#endif /* (CFM) protocol. */ - -#ifndef ETHERTYPE_FCOE -#define ETHERTYPE_FCOE 0x8906 /* Fibre Channel over Ethernet */ -#endif - -#ifndef ETHERTYPE_LOOP -#define ETHERTYPE_LOOP 0x9000 /* used for layer 2 testing (do i see my own frames on the wire) */ -#endif - -#ifndef ETHERTYPE_RTMAC -#define ETHERTYPE_RTMAC 0x9021 /* RTnet: Real-Time Media Access Control */ -#endif - -#ifndef ETHERTYPE_RTCFG -#define ETHERTYPE_RTCFG 0x9022 /* RTnet: Real-Time Configuration Protocol */ -#endif - -#ifndef ETHERTYPE_LLT -#define ETHERTYPE_LLT 0xCAFE /* Veritas Low Latency Transport (not officially registered) */ -#endif - -#ifndef ETHERTYPE_FCFT -/* type used to transport FC frames+MDS hdr internal to Cisco's MDS switch */ -#define ETHERTYPE_FCFT 0xFCFC -#endif - -extern const value_string etype_vals[]; - -#endif /* etypes.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ex-opt.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ex-opt.h deleted file mode 100644 index 5839b726..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ex-opt.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * ex-opt.h - * - * eXtension command line options - * - * (c) 2006, Luis E. Garcia Ontanon - * - * $Id: ex-opt.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef _EX_OPT_H -#define _EX_OPT_H - -/* will be called by main each time a -X option is found */ -extern gboolean ex_opt_add(const gchar* optarg); - -/* yields the number of arguments of a given key obviously returns 0 if there aren't */ -extern gint ex_opt_count(const gchar* key); - -/* fetches the nth argument of a given key returns NULL if there isn't */ -extern const gchar* ex_opt_get_index(const gchar* key, guint index); - -/* extracts the next value of a given key */ -extern const gchar* ex_opt_get_next(const gchar* key); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/except.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/except.h deleted file mode 100644 index 42e62ce5..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/except.h +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Portable Exception Handling for ANSI C. - * Copyright (C) 1999 Kaz Kylheku - * - * Free Software License: - * - * All rights are reserved by the author, with the following exceptions: - * Permission is granted to freely reproduce and distribute this software, - * possibly in exchange for a fee, provided that this copyright notice appears - * intact. Permission is also granted to adapt this software to produce - * derivative works, as long as the modified versions carry this copyright - * notice and additional notices stating that the work has been modified. - * This source code may be translated into executable form and incorporated - * into proprietary software; there is no requirement for such software to - * contain a copyright notice related to this source. - * - * $Id: except.h 3992 2008-06-10 03:13:11Z dgu $ - * $Name: $ - */ - -/* - * Modified to support throwing an exception with a null message pointer, - * and to have the message not be const (as we generate messages with - * "g_strdup_sprintf()", which means they need to be freed; using - * a null message means that we don't have to use a special string - * for exceptions with no message, and don't have to worry about - * not freeing that). - */ - -#ifndef XCEPT_H -#define XCEPT_H - -#include -#include -#include - -#define XCEPT_GROUP_ANY 0 -#define XCEPT_CODE_ANY 0 -#define XCEPT_BAD_ALLOC 1 - -#ifdef __cplusplus -extern "C" { -#endif - -enum { except_no_call, except_call }; - -typedef struct { - unsigned long except_group; - unsigned long except_code; -} except_id_t; - -typedef struct { - except_id_t volatile except_id; - const char *volatile except_message; - void *volatile except_dyndata; -} except_t; - -struct except_cleanup { - void (*except_func)(void *); - void *except_context; -}; - -struct except_catch { - const except_id_t *except_id; - size_t except_size; - except_t except_obj; - jmp_buf except_jmp; -}; - -enum except_stacktype { - XCEPT_CLEANUP, XCEPT_CATCHER -}; - -struct except_stacknode { - struct except_stacknode *except_down; - enum except_stacktype except_type; - union { - struct except_catch *except_catcher; - struct except_cleanup *except_cleanup; - } except_info; -}; - -/* private functions made external so they can be used in macros */ -extern void except_setup_clean(struct except_stacknode *, - struct except_cleanup *, void (*)(void *), void *); -extern void except_setup_try(struct except_stacknode *, - struct except_catch *, const except_id_t [], size_t); -extern struct except_stacknode *except_pop(void); - -/* public interface functions */ -extern int except_init(void); -extern void except_deinit(void); -extern void except_rethrow(except_t *); -extern void except_throw(long, long, const char *); -extern void except_throwd(long, long, const char *, void *); -extern void except_throwf(long, long, const char *, ...); -extern void (*except_unhandled_catcher(void (*)(except_t *)))(except_t *); -extern unsigned long except_code(except_t *); -extern unsigned long except_group(except_t *); -extern const char *except_message(except_t *); -extern void *except_data(except_t *); -extern void *except_take_data(except_t *); -extern void except_set_allocator(void *(*)(size_t), void (*)(void *)); -extern void *except_alloc(size_t); -extern void except_free(void *); - -#define except_code(E) ((E)->except_id.except_code) -#define except_group(E) ((E)->except_id.except_group) -#define except_message(E) ((E)->except_message) -#define except_data(E) ((E)->except_dyndata) - -#ifdef __cplusplus -} -#endif - -/* - * void except_cleanup_push(void (*)(void *), void *); - * void except_cleanup_pop(int); - * void except_checked_cleanup_pop(void (*)(void *), int); - * void except_try_push(const except_id_t [], size_t, except_t **); - * void except_try_pop(void); - */ - -#define except_cleanup_push(F, C) \ - { \ - struct except_stacknode except_sn; \ - struct except_cleanup except_cl; \ - except_setup_clean(&except_sn, &except_cl, F, C) - -#define except_cleanup_pop(E) \ - except_pop(); \ - if (E) \ - except_cl.except_func(except_cl.except_context); \ - } - -#define except_checked_cleanup_pop(F, E) \ - except_pop(); \ - assert (except_cl.except_func == (F)); \ - if (E) \ - except_cl.except_func(except_cl.except_context); \ - } - -#define except_try_push(ID, NUM, PPE) \ - { \ - struct except_stacknode except_sn; \ - struct except_catch except_ch; \ - except_setup_try(&except_sn, &except_ch, ID, NUM); \ - if (setjmp(except_ch.except_jmp)) \ - *(PPE) = &except_ch.except_obj; \ - else \ - *(PPE) = 0 - -#define except_try_pop() \ - except_free(except_ch.except_obj.except_dyndata); \ - except_pop(); \ - } - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/exceptions.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/exceptions.h deleted file mode 100644 index 52abdfd7..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/exceptions.h +++ /dev/null @@ -1,319 +0,0 @@ -#ifndef __EXCEPTIONS_H__ -#define __EXCEPTIONS_H__ - -/* $Id $ */ - -#ifndef XCEPT_H -#include "except.h" -#endif - -/* Wireshark has only one exception group, to make these macros simple */ -#define XCEPT_GROUP_WIRESHARK 1 - -/* Wireshark's exceptions */ - -/** - Index is out of range. - An attempt was made to read past the end of a buffer. - This generally means that the capture was done with a "slice" - length or "snapshot" length less than the maximum packet size, - and a link-layer packet was cut short by that, so not all of the - data in the link-layer packet was available. -**/ -#define BoundsError 1 - -/** - Index is beyond reported length (not cap_len) - An attempt was made to read past the logical end of a buffer. This - differs from a BoundsError in that the parent protocol established a - limit past which this dissector should not process in the buffer and that - limit was execeeded. - This generally means that the packet is invalid, i.e. whatever - code constructed the packet and put it on the wire didn't put enough - data into it. It is therefore currently reported as a "Malformed - packet". - However, it also happens in some cases where the packet was fragmented - and the fragments weren't reassembled. We need to add another length - field to a tvbuff, so that "length of the packet from the link layer" - and "length of the packet were it fully reassembled" are different, - and going past the first of those without going past the second would - throw a different exception, which would be reported as an "Unreassembled - packet" rather than a "Malformed packet". -**/ -#define ReportedBoundsError 2 - -/** - During dfilter parsing -**/ -#define TypeError 3 - -/** - A bug was detected in a dissector. - - DO NOT throw this with THROW(); that means that no details about - the dissector error will be reported. (Instead, the message will - blame you for not providing details.) - - Instead, use the DISSECTOR_ASSERT(), etc. macros in epan/proto.h. -**/ -#define DissectorError 4 - -/** - Index is out of range. - An attempt was made to read past the end of a buffer. - This error is specific to SCSI data transfers where for some CDBs - it is normal that the data PDU might be short. - I.e. ReportLuns initially called with allocation_length=8, just enough - to get the "size" of lun list back after which the initiator will - reissue the command with an allocation_length that is big enough. -**/ -#define ScsiBoundsError 5 - -/** - Running out of memory. - A dissector tried to allocate memory but that failed. -**/ -#define OutOfMemoryError 6 - - -/* Usage: - * - * TRY { - * code; - * } - * - * CATCH(exception) { - * code; - * } - * - * CATCH2(exception1, exception2) { - * code; - * } - * - * CATCH_ALL { - * code; - * } - * - * FINALLY { - * code; - * } - * - * ENDTRY; - * - * ********* Never use 'goto' or 'return' inside the TRY, CATCH, CATCH_ALL, - * ********* or FINALLY blocks. Execution must proceed through ENDTRY before - * ********* branching out. - * - * This is really something like: - * - * { - * caught = FALSE: - * x = setjmp(); - * if (x == 0) { - * - * } - * if (!caught && x == 1) { - * caught = TRUE; - * - * } - * if (!caught && x == 2) { - * caught = TRUE; - * - * } - * if (!caught && (x == 3 || x == 4)) { - * caught = TRUE; - * - * } - * if (!caught && x != 0) { - * caught = TRUE; - * - * } - * - * if(!caught) { - * RETHROW(x) - * } - * } - * - * All CATCH's must precede a CATCH_ALL. - * FINALLY must occur after any CATCH or CATCH_ALL. - * ENDTRY marks the end of the TRY code. - * TRY and ENDTRY are the mandatory parts of a TRY block. - * CATCH, CATCH_ALL, and FINALLY are all optional (although - * you'll probably use at least one, otherwise why "TRY"?) - * - * GET_MESSAGE returns string ptr to exception message - * when exception is thrown via THROW_MESSAGE() - * - * To throw/raise an exception. - * - * THROW(exception) - * RETHROW rethrow the caught exception - * - * A cleanup callback is a function called in case an exception occurs - * and is not caught. It should be used to free any dynamically-allocated data. - * A pop or call_and_pop should occur at the same statement-nesting level - * as the push. - * - * CLEANUP_CB_PUSH(func, data) - * CLEANUP_CB_POP - * CLEANUP_CB_CALL_AND_POP - */ - -/* we do up to three passes through the bit of code after except_try_push(), - * and except_state is used to keep track of where we are. - */ -#define EXCEPT_CAUGHT 1 /* exception has been caught, no need to rethrow at - * END_TRY */ - -#define EXCEPT_RETHROWN 2 /* the exception was rethrown from a CATCH - * block. Don't reenter the CATCH blocks, but do - * execute FINALLY and rethrow at END_TRY */ - -#define EXCEPT_FINALLY 4 /* we've entered the FINALLY block - don't allow - * RETHROW, and don't reenter FINALLY if a - * different exception is thrown */ - -#define TRY \ -{\ - except_t *exc; \ - volatile int except_state = 0; \ - static const except_id_t catch_spec[] = { \ - { XCEPT_GROUP_WIRESHARK, XCEPT_CODE_ANY } }; \ - except_try_push(catch_spec, 1, &exc); \ - \ - if(except_state & EXCEPT_CAUGHT) \ - except_state |= EXCEPT_RETHROWN; \ - except_state &= ~EXCEPT_CAUGHT; \ - \ - if (except_state == 0 && exc == 0) \ - /* user's code goes here */ - -#define ENDTRY \ - /* rethrow the exception if necessary */ \ - if(!(except_state&EXCEPT_CAUGHT) && exc != 0) \ - except_rethrow(exc); \ - except_try_pop();\ -} - -/* the (except_state |= EXCEPT_CAUGHT) in the below is a way of setting - * except_state before the user's code, without disrupting the user's code if - * it's a one-liner. - */ -#define CATCH(x) \ - if (except_state == 0 && exc != 0 && exc->except_id.except_code == (x) && \ - (except_state |= EXCEPT_CAUGHT)) \ - /* user's code goes here */ - -#define CATCH2(x,y) \ - if (except_state == 0 && exc != 0 && \ - (exc->except_id.except_code == (x) || exc->except_id.except_code == (y)) && \ - (except_state|=EXCEPT_CAUGHT)) \ - /* user's code goes here */ - -#define CATCH_ALL \ - if (except_state == 0 && exc != 0 && \ - (except_state|=EXCEPT_CAUGHT)) \ - /* user's code goes here */ - - -#define FINALLY \ - if( !(except_state & EXCEPT_FINALLY) && (except_state|=EXCEPT_FINALLY)) \ - /* user's code goes here */ - -#define THROW(x) \ - except_throw(XCEPT_GROUP_WIRESHARK, (x), NULL) - -#define THROW_MESSAGE(x, y) \ - except_throw(XCEPT_GROUP_WIRESHARK, (x), (y)) - -#define GET_MESSAGE except_message(exc) - -#define RETHROW \ - { \ - /* check we're in a catch block */ \ - g_assert(except_state == EXCEPT_CAUGHT); \ - /* we can't use except_rethrow here, as that pops a catch block \ - * off the stack, and we don't want to do that, because we want to \ - * excecute the FINALLY {} block first. \ - * except_throw doesn't provide an interface to rethrow an existing \ - * exception; however, longjmping back to except_try_push() has the \ - * desired effect. \ - * \ - * Note also that THROW and RETHROW should provide much the same \ - * functionality in terms of which blocks to enter, so any messing \ - * about with except_state in here would indicate that THROW is \ - * doing the wrong thing. \ - */ \ - longjmp(except_ch.except_jmp,1); \ - } - -#define EXCEPT_CODE except_code(exc) - -/* Register cleanup functions in case an exception is thrown and not caught. - * From the Kazlib documentation, with modifications for use with the - * Wireshark-specific macros: - * - * CLEANUP_PUSH(func, arg) - * - * The call to CLEANUP_PUSH shall be matched with a call to - * CLEANUP_CALL_AND_POP or CLEANUP_POP which must occur in the same - * statement block at the same level of nesting. This requirement allows - * an implementation to provide a CLEANUP_PUSH macro which opens up a - * statement block and a CLEANUP_POP which closes the statement block. - * The space for the registered pointers can then be efficiently - * allocated from automatic storage. - * - * The CLEANUP_PUSH macro registers a cleanup handler that will be - * called if an exception subsequently occurs before the matching - * CLEANUP_[CALL_AND_]POP is executed, and is not intercepted and - * handled by a try-catch region that is nested between the two. - * - * The first argument to CLEANUP_PUSH is a pointer to the cleanup - * handler, a function that returns nothing and takes a single - * argument of type void*. The second argument is a void* value that - * is registered along with the handler. This value is what is passed - * to the registered handler, should it be called. - * - * Cleanup handlers are called in the reverse order of their nesting: - * inner handlers are called before outer handlers. - * - * The program shall not leave the cleanup region between - * the call to the macro CLEANUP_PUSH and the matching call to - * CLEANUP_[CALL_AND_]POP by means other than throwing an exception, - * or calling CLEANUP_[CALL_AND_]POP. - * - * Within the call to the cleanup handler, it is possible that new - * exceptions may happen. Such exceptions must be handled before the - * cleanup handler terminates. If the call to the cleanup handler is - * terminated by an exception, the behavior is undefined. The exception - * which triggered the cleanup is not yet caught; thus the program - * would be effectively trying to replace an exception with one that - * isn't in a well-defined state. - * - * - * CLEANUP_POP and CLEANUP_CALL_AND_POP - * - * A call to the CLEANUP_POP or CLEANUP_CALL_AND_POP macro shall match - * each call to CLEANUP_PUSH which shall be in the same statement block - * at the same nesting level. It shall match the most recent such a - * call that is not matched by a previous CLEANUP_[CALL_AND_]POP at - * the same level. - * - * These macros causes the registered cleanup handler to be removed. If - * CLEANUP_CALL_AND_POP is called, the cleanup handler is called. - * In that case, the registered context pointer is passed to the cleanup - * handler. If CLEANUP_POP is called, the cleanup handler is not called. - * - * The program shall not leave the region between the call to the - * macro CLEANUP_PUSH and the matching call to CLEANUP_[CALL_AND_]POP - * other than by throwing an exception, or by executing the - * CLEANUP_CALL_AND_POP. - * - */ - - -#define CLEANUP_PUSH(f,a) except_cleanup_push((f),(a)) -#define CLEANUP_POP except_cleanup_pop(0) -#define CLEANUP_CALL_AND_POP except_cleanup_pop(1) - -#endif /* __EXCEPTIONS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/expert.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/expert.h deleted file mode 100644 index 3c32f25e..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/expert.h +++ /dev/null @@ -1,70 +0,0 @@ -/* expert.h - * Collecting of Expert information. - * - * For further info, see: http://wiki.wireshark.org/Development/ExpertInfo - * - * $Id: expert.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __EXPERT_H__ -#define __EXPERT_H__ - -#include "gnuc_format_check.h" -#include -#include "value_string.h" - - -/** only for internal and display use */ -typedef struct expert_info_s { - guint32 packet_num; - int group; - int severity; - gchar * protocol; - gchar * summary; - proto_item *pitem; -} expert_info_t; - -WS_VAR_IMPORT const value_string expert_severity_vals[]; -WS_VAR_IMPORT const value_string expert_group_vals[]; - -extern void -expert_init(void); - -extern void -expert_cleanup(void); - -extern int -expert_get_highest_severity(void); - -/** Add an expert info. - - @param pinfo packet info of the currently processed packet - @param pi current protocol item (or NULL) - @param group the expert group (like PI_CHECKSUM) - @param severity the expert severity (like PI_WARN) - @param format printf like format string with further infos - */ -extern void -expert_add_info_format(packet_info *pinfo, proto_item *pi, int group, - int severity, const char *format, ...) - GNUC_FORMAT_CHECK(printf, 5, 6); - -#endif /* __EXPERT_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/filesystem.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/filesystem.h deleted file mode 100644 index 5b9c9fa2..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/filesystem.h +++ /dev/null @@ -1,248 +0,0 @@ -/* filesystem.h - * Filesystem utility definitions - * - * $Id: filesystem.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef FILESYSTEM_H -#define FILESYSTEM_H - -/* - * Default profile name. - */ -#define DEFAULT_PROFILE "Default" - - -/* - * Get the pathname of the directory from which the executable came, - * and save it for future use. Returns NULL on success, and a - * g_mallocated string containing an error on failure. - */ -extern char *init_progfile_dir(const char *arg0); - -/* - * Get the directory in which the program resides. - */ -extern const char *get_progfile_dir(void); - -/* - * Get the directory in which plugins are stored; this must not be called - * before init_progfile_dir() is called, as they might be stored in a - * subdirectory of the program file directory. - */ -extern const char *get_plugin_dir(void); - -/* - * Get the flag indicating whether we're running from a build - * directory. - */ -extern gboolean running_in_build_directory(void); - -/* - * Get the directory in which global configuration files are - * stored. - */ -extern const char *get_datafile_dir(void); - -/* - * Construct the path name of a global configuration file, given the - * file name. - * - * The returned file name was g_malloc()'d so it must be g_free()d when the - * caller is done with it. - */ -extern char *get_datafile_path(const char *filename); - -/* - * Get the directory in which files that, at least on UNIX, are - * system files (such as "/etc/ethers") are stored; on Windows, - * there's no "/etc" directory, so we get them from the Wireshark - * global configuration and data file directory. - */ -extern const char *get_systemfile_dir(void); - -/* - * Set the configuration profile name to be used for storing - * personal configuration files. - */ -extern void set_profile_name(const gchar *profilename); - -/* - * Get the current configuration profile name used for storing - * personal configuration files. - */ -extern const char *get_profile_name(void); - -/* - * Get the directory used to store configuration profile directories. - */ -extern const char *get_profiles_dir(void); - -/* - * Check if given configuration profile exists. - */ -extern gboolean profile_exists(const gchar *profilename); - -/* - * Create a directory for the given configuration profile. - * If we attempted to create it, and failed, return -1 and - * set "*pf_dir_path_return" to the pathname of the directory we failed - * to create (it's g_mallocated, so our caller should free it); otherwise, - * return 0. - */ -extern int create_persconffile_profile(const char *profilename, - char **pf_dir_path_return); - -/* - * Delete the directory for the given configuration profile. - * If we attempted to delete it, and failed, return -1 and - * set "*pf_dir_path_return" to the pathname of the directory we failed - * to delete (it's g_mallocated, so our caller should free it); otherwise, - * return 0. - */ -extern int delete_persconffile_profile(const char *profilename, - char **pf_dir_path_return); - -/* - * Rename the directory for the given confinguration profile. - */ -extern int rename_persconffile_profile(const char *fromname, const char *toname, - char **pf_from_dir_path_return, - char **pf_to_dir_path_return); - -/* - * Create the directory that holds personal configuration files, if - * necessary. If we attempted to create it, and failed, return -1 and - * set "*pf_dir_path_return" to the pathname of the directory we failed - * to create (it's g_mallocated, so our caller should free it); otherwise, - * return 0. - */ -extern int create_persconffile_dir(char **pf_dir_path_return); - -/* - * Construct the path name of a personal configuration file, given the - * file name. If using configuration profiles this directory will be - * used if "from_profile" is TRUE. - * - * On Win32, if "for_writing" is FALSE, we check whether the file exists - * and, if not, construct a path name relative to the ".wireshark" - * subdirectory of the user's home directory, and check whether that - * exists; if it does, we return that, so that configuration files - * from earlier versions can be read. - * - * The returned file name was g_malloc()'d so it must be g_free()d when the - * caller is done with it. - */ -extern char *get_persconffile_path(const char *filename, gboolean from_profile, - gboolean for_writing); - -/* - * Get the (default) directory in which personal data is stored. - * - * On Win32, this is the "My Documents" folder in the personal profile. - * On UNIX this is simply the current directory. - */ -extern char *get_persdatafile_dir(void); - -/* - * Construct the path name of a file in $TMP/%TEMP% directory. - * Or "/tmp/" (C:\) if that fails. - * - * Return value is malloced so the caller should free it. - */ -extern char *get_tempfile_path(const char *filename); - -/* - * process command line option belonging to the filesystem settings - */ -extern int filesystem_opt(int opt, const char *optarg); - -/* - * Return an error message for UNIX-style errno indications on open or - * create operations. - */ -extern const char *file_open_error_message(int err, gboolean for_writing); - -/* - * Return an error message for UNIX-style errno indications on write - * operations. - */ -extern const char *file_write_error_message(int err); - -/* - * Given a pathname, return the last component. - */ -extern const char *get_basename(const char *); - -/* - * Given a pathname, return a string containing everything but the - * last component. NOTE: this overwrites the pathname handed into - * it.... - */ -extern char *get_dirname(char *); - -/* - * Given a pathname, return: - * - * the errno, if an attempt to "stat()" the file fails; - * - * EISDIR, if the attempt succeeded and the file turned out - * to be a directory; - * - * 0, if the attempt succeeded and the file turned out not - * to be a directory. - */ -extern int test_for_directory(const char *); - -/* - * Given a pathname, return: - * - * the errno, if an attempt to "stat()" the file fails; - * - * ESPIPE, if the attempt succeeded and the file turned out - * to be a FIFO; - * - * 0, if the attempt succeeded and the file turned out not - * to be a FIFO. - */ -extern int test_for_fifo(const char *); - -/* Delete a file */ -extern gboolean deletefile (const char *path); - -/* - * Check, if file is existing. - */ -extern gboolean file_exists(const char *fname); - -/* - * Check, if two filenames are identical (with absolute and relative paths). - */ -extern gboolean files_identical(const char *fname1, const char *fname2); - -#ifdef WIN32 -/* - * utf8 version of getenv, needed to get win32 filename paths - */ -extern char *getenv_utf8(const char *varname); -#endif - -#endif /* FILESYSTEM_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/follow.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/follow.h deleted file mode 100644 index 513e7add..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/follow.h +++ /dev/null @@ -1,58 +0,0 @@ -/* follow.h - * - * $Id: follow.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Copyright 1998 Mike Hall - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __FOLLOW_H__ -#define __FOLLOW_H__ - -#include - -#define MAX_IPADDR_LEN 16 - -/* With MSVC and a libwireshark.dll, we need a special declaration. */ -WS_VAR_IMPORT gboolean empty_tcp_stream; -WS_VAR_IMPORT gboolean incomplete_tcp_stream; - -typedef struct _tcp_stream_chunk { - guint8 src_addr[MAX_IPADDR_LEN]; - guint16 src_port; - guint32 dlen; -} tcp_stream_chunk; - -char* build_follow_filter( packet_info * ); -void reassemble_tcp( gulong, gulong, gulong, const char*, gulong, int, - address *, address *, guint, guint ); -void reset_tcp_reassembly( void ); - -typedef struct { - guint8 ip_address[2][MAX_IPADDR_LEN]; - guint32 port[2]; - unsigned int bytes_written[2]; - gboolean is_ipv6; -} follow_stats_t; - -void follow_stats(follow_stats_t* stats); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/frame_data.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/frame_data.h deleted file mode 100644 index 15d0d021..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/frame_data.h +++ /dev/null @@ -1,79 +0,0 @@ -/* frame_data.h - * Definitions for frame_data structures and routines - * - * $Id: frame_data.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __FRAME_DATA_H__ -#define __FRAME_DATA_H__ - -#include "column_info.h" -#include "tvbuff.h" -#include - - -/* XXX - some of this stuff is used only while a packet is being dissected; - should we keep that stuff in the "packet_info" structure, instead, to - save memory? */ -/* The frame number is the ordinal number of the frame in the capture, so - it's 1-origin. In various contexts, 0 as a frame number means "frame - number unknown". */ -typedef struct _frame_data { - struct _frame_data *next; /* Next element in list */ - struct _frame_data *prev; /* Previous element in list */ - GSList *pfd; /* Per frame proto data */ - guint32 num; /* Frame number */ - guint32 pkt_len; /* Packet length */ - guint32 cap_len; /* Amount actually captured */ - guint32 cum_bytes; /* Cumulative bytes into the capture */ - nstime_t abs_ts; /* Absolute timestamp */ - nstime_t rel_ts; /* Relative timestamp (yes, it can be negative) */ - nstime_t del_dis_ts; /* Delta timestamp to previous displayed frame (yes, it can be negative) */ - nstime_t del_cap_ts; /* Delta timestamp to previous captured frame (yes, it can be negative) */ - gint64 file_off; /* File offset */ - int lnk_t; /* Per-packet encapsulation/data-link type */ - struct { - unsigned int passed_dfilter : 1; /* 1 = display, 0 = no display */ - unsigned int encoding : 2; /* Character encoding (ASCII, EBCDIC...) */ - unsigned int visited : 1; /* Has this packet been visited yet? 1=Yes,0=No*/ - unsigned int marked : 1; /* 1 = marked by user, 0 = normal */ - unsigned int ref_time : 1; /* 1 = marked as a reference time frame, 0 = normal */ - } flags; - void *color_filter; /* Per-packet matching color_filter_t object */ - col_expr_t col_expr; /* Column expressions & values */ -} frame_data; - -/* - * A data source. - * Has a tvbuff and a name. - */ -typedef struct { - tvbuff_t *tvb; - char *name; -} data_source; - -/* Utility routines used by packet*.c */ - -extern void p_add_proto_data(frame_data *fd, int proto, void *proto_data); -extern void *p_get_proto_data(frame_data *fd, int proto); -extern void p_remove_proto_data(frame_data *fd, int proto); - -#endif /* __FRAME_DATA__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/frequency-utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/frequency-utils.h deleted file mode 100644 index 628bff4d..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/frequency-utils.h +++ /dev/null @@ -1,74 +0,0 @@ -/* frequency-utils.h - * Frequency conversion utility definitions - * - * $Id: frequency-utils.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2007 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __FREQUENCY_UTILS_H__ -#define __FREQUENCY_UTILS_H__ - -/** @file - * Frequency and channel conversion utilities. - */ - -/** - * Given a center frequency in MHz, return a channel number. - * @param freq Frequency in MHz. - * @return The equivalent channel or -1 if no match is found. - */ -gint -ieee80211_mhz_to_chan(guint freq); - -/** - * Given a channel number and a band type, return a center frequency. - * @param chan Channel number - * @param is_bg TRUE if the channel is a b/g channel, FALSE otherwise. - * @return The equivalent frequency or 0 if no match is found. - */ -guint -ieee80211_chan_to_mhz(gint chan, gboolean is_bg); - -/** - * Given a frequency in MHz, return a string representation. - * @param freq Frequench in MHz. - * @return A string showing the frequency, channel number, and type. The string must be freed with g_free() after use. - */ -gchar* -ieee80211_mhz_to_str(guint freq); - -/* Should this be "(freq < 4920)", or something else? */ -#define FREQ_IS_BG(freq) (freq <= 2484) - -/* - * Editor modelines - * - * Local Variables: - * c-basic-offset: 4 - * tab-width: 8 - * indent-tabs-mode: nil - * End: - * - * ex: set shiftwidth=4 tabstop=8 expandtab - * :indentSize=4:tabSize=8:noTabs=true: - */ - -#endif /* __FREQUENCY_UTILS_H__ */ - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ftypes/ftypes-int.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ftypes/ftypes-int.h deleted file mode 100644 index 20528f66..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ftypes/ftypes-int.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * $Id: ftypes-int.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2001 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef FTYPES_INT_H -#define FTYPES_INT_H - -#include -#include "ftypes.h" - -#ifdef HAVE_LIBPCRE -#include -#endif /* HAVE_LIBPCRE */ - - -#ifdef HAVE_LIBPCRE -struct _pcre_tuple_t { - char *string; - pcre *re; - pcre_extra *ex; - char *error; -}; -#endif /* HAVE_LIBPCRE */ - -void -ftype_register(enum ftenum ftype, ftype_t *ft); - -/* These are the ftype registration functions that need to be called. - * This list and the initialization function could be produced - * via a script, like the dissector registration, but there's so few - * that I don't mind doing it by hand for now. */ -void ftype_register_bytes(void); -void ftype_register_double(void); -void ftype_register_integers(void); -void ftype_register_ipv4(void); -void ftype_register_guid(void); -void ftype_register_none(void); -void ftype_register_string(void); -void ftype_register_time(void); -void ftype_register_tvbuff(void); -void ftype_register_pcre(void); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ftypes/ftypes.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ftypes/ftypes.h deleted file mode 100644 index 498c969c..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ftypes/ftypes.h +++ /dev/null @@ -1,367 +0,0 @@ -/* ftypes.h - * Definitions for field types - * - * $Id: ftypes.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2001 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - - -#ifndef FTYPES_H -#define FTYPES_H - -#include -#include "../slab.h" - -/* field types */ -enum ftenum { - FT_NONE, /* used for text labels with no value */ - FT_PROTOCOL, - FT_BOOLEAN, /* TRUE and FALSE come from */ - FT_UINT8, - FT_UINT16, - FT_UINT24, /* really a UINT32, but displayed as 3 hex-digits if FD_HEX*/ - FT_UINT32, - FT_UINT64, - FT_INT8, - FT_INT16, - FT_INT24, /* same as for UINT24 */ - FT_INT32, - FT_INT64, - FT_FLOAT, - FT_DOUBLE, - FT_ABSOLUTE_TIME, - FT_RELATIVE_TIME, - FT_STRING, - FT_STRINGZ, /* for use with proto_tree_add_item() */ - FT_EBCDIC, /* for use with proto_tree_add_item() */ - FT_UINT_STRING, /* for use with proto_tree_add_item() */ - /*FT_UCS2_LE, */ /* Unicode, 2 byte, Little Endian */ - FT_ETHER, - FT_BYTES, - FT_UINT_BYTES, - FT_IPv4, - FT_IPv6, - FT_IPXNET, - FT_FRAMENUM, /* a UINT32, but if selected lets you go to frame with that numbe */ - FT_PCRE, /* a compiled Perl-Compatible Regular Expression object */ - FT_GUID, /* GUID, UUID */ - FT_OID, /* OBJECT IDENTIFIER */ - FT_NUM_TYPES /* last item number plus one */ -}; - -#define IS_FT_INT(ft) ((ft)==FT_INT8||(ft)==FT_INT16||(ft)==FT_INT24||(ft)==FT_INT32) -#define IS_FT_UINT(ft) ((ft)==FT_UINT8||(ft)==FT_UINT16||(ft)==FT_UINT24||(ft)==FT_UINT32||(ft)==FT_FRAMENUM) -#define IS_FT_TIME(ft) ((ft)==FT_ABSOLUTE_TIME||(ft)==FT_RELATIVE_TIME) -#define IS_FT_STRING(ft) ((ft)==FT_STRING||(ft)==FT_STRINGZ) - -typedef enum ftenum ftenum_t; -typedef struct _ftype_t ftype_t; - -/* String representation types. */ -enum ftrepr { - FTREPR_DISPLAY, - FTREPR_DFILTER -}; - -typedef enum ftrepr ftrepr_t; - -#ifdef HAVE_LIBPCRE -typedef struct _pcre_tuple_t pcre_tuple_t; -#endif /* HAVE_LIBPCRE */ - -/* Initialize the ftypes subsytem. Called once. */ -void -ftypes_initialize(void); - -/* ---------------- FTYPE ----------------- */ - -/* Return a string representing the name of the type */ -const char* -ftype_name(ftenum_t ftype); - -/* Return a string presenting a "pretty" representation of the - * name of the type. The pretty name means more to the user than - * that "FT_*" name. */ -const char* -ftype_pretty_name(ftenum_t ftype); - -/* Returns length of field in packet, or 0 if not determinable/defined. */ -int -ftype_length(ftenum_t ftype); - -gboolean -ftype_can_slice(enum ftenum ftype); - -gboolean -ftype_can_eq(enum ftenum ftype); - -gboolean -ftype_can_ne(enum ftenum ftype); - -gboolean -ftype_can_gt(enum ftenum ftype); - -gboolean -ftype_can_ge(enum ftenum ftype); - -gboolean -ftype_can_lt(enum ftenum ftype); - -gboolean -ftype_can_le(enum ftenum ftype); - -gboolean -ftype_can_bitwise_and(enum ftenum ftype); - -gboolean -ftype_can_contains(enum ftenum ftype); - -gboolean -ftype_can_matches(enum ftenum ftype); - -/* ---------------- FVALUE ----------------- */ - -#include -#include - -#include -#include -#include - -typedef struct _fvalue_t { - ftype_t *ftype; - union { - /* Put a few basic types in here */ - gpointer pointer; - guint32 uinteger; - gint32 sinteger; - guint64 integer64; - gdouble floating; - gchar *string; - guchar *ustring; - GByteArray *bytes; - GString *gstring; - ipv4_addr ipv4; - e_guid_t guid; - nstime_t time; - tvbuff_t *tvb; -#ifdef HAVE_LIBPCRE - pcre_tuple_t *re; -#endif /* HAVE_LIBPCRE */ - } value; - - /* The following is provided for private use - * by the fvalue. */ - gboolean fvalue_gboolean1; - -} fvalue_t; - -typedef void (*FvalueNewFunc)(fvalue_t*); -typedef void (*FvalueFreeFunc)(fvalue_t*); -typedef void (*LogFunc)(const char*,...); - -typedef gboolean (*FvalueFromUnparsed)(fvalue_t*, char*, gboolean, LogFunc); -typedef gboolean (*FvalueFromString)(fvalue_t*, char*, LogFunc); -typedef void (*FvalueToStringRepr)(fvalue_t*, ftrepr_t, char*); -typedef int (*FvalueStringReprLen)(fvalue_t*, ftrepr_t); - -typedef void (*FvalueSetFunc)(fvalue_t*, gpointer, gboolean); -typedef void (*FvalueSetUnsignedIntegerFunc)(fvalue_t*, guint32); -typedef void (*FvalueSetSignedIntegerFunc)(fvalue_t*, gint32); -typedef void (*FvalueSetInteger64Func)(fvalue_t*, guint64); -typedef void (*FvalueSetFloatingFunc)(fvalue_t*, gdouble); - -typedef gpointer (*FvalueGetFunc)(fvalue_t*); -typedef guint32 (*FvalueGetUnsignedIntegerFunc)(fvalue_t*); -typedef gint32 (*FvalueGetSignedIntegerFunc)(fvalue_t*); -typedef guint64 (*FvalueGetInteger64Func)(fvalue_t*); -typedef double (*FvalueGetFloatingFunc)(fvalue_t*); - -typedef gboolean (*FvalueCmp)(fvalue_t*, fvalue_t*); - -typedef guint (*FvalueLen)(fvalue_t*); -typedef void (*FvalueSlice)(fvalue_t*, GByteArray *, guint offset, guint length); - -struct _ftype_t { - ftenum_t ftype; - const char *name; - const char *pretty_name; - int wire_size; - FvalueNewFunc new_value; - FvalueFreeFunc free_value; - FvalueFromUnparsed val_from_unparsed; - FvalueFromString val_from_string; - FvalueToStringRepr val_to_string_repr; - FvalueStringReprLen len_string_repr; - - /* could be union */ - FvalueSetFunc set_value; - FvalueSetUnsignedIntegerFunc set_value_uinteger; - FvalueSetSignedIntegerFunc set_value_sinteger; - FvalueSetInteger64Func set_value_integer64; - FvalueSetFloatingFunc set_value_floating; - - /* could be union */ - FvalueGetFunc get_value; - FvalueGetUnsignedIntegerFunc get_value_uinteger; - FvalueGetSignedIntegerFunc get_value_sinteger; - FvalueGetInteger64Func get_value_integer64; - FvalueGetFloatingFunc get_value_floating; - - FvalueCmp cmp_eq; - FvalueCmp cmp_ne; - FvalueCmp cmp_gt; - FvalueCmp cmp_ge; - FvalueCmp cmp_lt; - FvalueCmp cmp_le; - FvalueCmp cmp_bitwise_and; - FvalueCmp cmp_contains; - FvalueCmp cmp_matches; - - FvalueLen len; - FvalueSlice slice; -}; - - -fvalue_t* -fvalue_new(ftenum_t ftype); - -void -fvalue_init(fvalue_t *fv, ftenum_t ftype); - - -/* Define type needed for the fvalue_t free list. */ -SLAB_ITEM_TYPE_DEFINE(fvalue_t) - -/* Free all memory used by an fvalue_t. With MSVC and a - * libwireshark.dll, we need a special declaration. - */ -WS_VAR_IMPORT SLAB_FREE_LIST_DECLARE(fvalue_t) - - -#define FVALUE_CLEANUP(fv) \ - { \ - register FvalueFreeFunc free_value; \ - free_value = (fv)->ftype->free_value; \ - if (free_value) { \ - free_value((fv)); \ - } \ - } - -#define FVALUE_FREE(fv) \ - { \ - FVALUE_CLEANUP(fv) \ - SLAB_FREE(fv, fvalue_t); \ - } - - -fvalue_t* -fvalue_from_unparsed(ftenum_t ftype, char *s, gboolean allow_partial_value, LogFunc logfunc); - -fvalue_t* -fvalue_from_string(ftenum_t ftype, char *s, LogFunc logfunc); - -/* Returns the length of the string required to hold the - * string representation of the the field value. - * The length DOES NOT include the terminating NUL. */ -int -fvalue_string_repr_len(fvalue_t *fv, ftrepr_t rtype); - -/* Creates the string representation of the field value. - * If given non-NULL 'buf', the string is written at the memory - * location pointed to by 'buf'. If 'buf' is NULL, new memory - * is malloc'ed and the string representation is written there. - * The pointer to the beginning of the string representation is - * returned. If 'buf' was NULL, this points to the newly-allocated - * memory. if 'buf' was non-NULL, then the return value will be - * 'buf'. */ -extern char * -fvalue_to_string_repr(fvalue_t *fv, ftrepr_t rtype, char *buf); - -ftype_t* -fvalue_ftype(fvalue_t *fv); - -const char* -fvalue_type_name(fvalue_t *fv); - -void -fvalue_set(fvalue_t *fv, gpointer value, gboolean already_copied); - -void -fvalue_set_uinteger(fvalue_t *fv, guint32 value); - -void -fvalue_set_sinteger(fvalue_t *fv, gint32 value); - -void -fvalue_set_integer64(fvalue_t *fv, guint64 value); - -void -fvalue_set_floating(fvalue_t *fv, gdouble value); - -gpointer -fvalue_get(fvalue_t *fv); - -extern guint32 -fvalue_get_uinteger(fvalue_t *fv); - -extern gint32 -fvalue_get_sinteger(fvalue_t *fv); - -guint64 -fvalue_get_integer64(fvalue_t *fv); - -extern double -fvalue_get_floating(fvalue_t *fv); - -gboolean -fvalue_eq(fvalue_t *a, fvalue_t *b); - -gboolean -fvalue_ne(fvalue_t *a, fvalue_t *b); - -gboolean -fvalue_gt(fvalue_t *a, fvalue_t *b); - -gboolean -fvalue_ge(fvalue_t *a, fvalue_t *b); - -gboolean -fvalue_lt(fvalue_t *a, fvalue_t *b); - -gboolean -fvalue_le(fvalue_t *a, fvalue_t *b); - -gboolean -fvalue_bitwise_and(fvalue_t *a, fvalue_t *b); - -gboolean -fvalue_contains(fvalue_t *a, fvalue_t *b); - -gboolean -fvalue_matches(fvalue_t *a, fvalue_t *b); - -guint -fvalue_length(fvalue_t *fv); - -fvalue_t* -fvalue_slice(fvalue_t *fv, drange *dr); - -#endif /* ftypes.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/funnel.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/funnel.h deleted file mode 100644 index a162e100..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/funnel.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * funnel.h - * - * EPAN's GUI mini-API - * - * (c) 2006, Luis E. Garcia Ontanon - * - * $Id: funnel.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#ifndef _FUNNEL_H -#define _FUNNEL_H - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include "../stat_menu.h" - -typedef struct _funnel_text_window_t funnel_text_window_t ; -typedef struct _funnel_tree_window_t funnel_tree_window_t ; -typedef struct _funnel_node_t funnel_node_t ; - -typedef void (*text_win_close_cb_t)(void*); - -typedef void (*funnel_dlg_cb_t)(gchar** user_input, void* data); - -typedef gboolean (*funnel_bt_cb_t)(funnel_text_window_t* tw, void* data); - -typedef struct _funnel_bt_t { - funnel_text_window_t* tw; - funnel_bt_cb_t func; - void* data; - void (*free)(void*); - void (*free_data)(void*); -} funnel_bt_t; - -typedef struct _funnel_ops_t { - funnel_text_window_t* (*new_text_window)(const gchar* label); - void (*set_text)(funnel_text_window_t* win, const gchar* text); - void (*append_text)(funnel_text_window_t* win, const gchar* text); - void (*prepend_text)(funnel_text_window_t* win, const gchar* text); - void (*clear_text)(funnel_text_window_t* win); - const gchar* (*get_text)(funnel_text_window_t* win); - void (*set_close_cb)(funnel_text_window_t* win, text_win_close_cb_t cb, void* data); - void (*set_editable)(funnel_text_window_t* win, gboolean editable); - void (*destroy_text_window)(funnel_text_window_t* win); - void (*add_button)(funnel_text_window_t* win, funnel_bt_t* cb, const gchar* label); - - - - void (*new_dialog)(const gchar* title, - const gchar** fieldnames, - funnel_dlg_cb_t dlg_cb, - void* data); - - - void (*logger)(const gchar *log_domain, - GLogLevelFlags log_level, - const gchar *message, - gpointer user_data); - - - void (*retap_packets)(void); - void (*copy_to_clipboard)(GString *str); - void (*set_filter)(const char*); - gboolean (*open_file)(const char* fname, const char* filter, const char** error); - void (*reload)(void); - void (*apply_filter)(void); - gboolean (*browser_open_url)(const gchar *url); - void (*browser_open_data_file)(const gchar *filename); -} funnel_ops_t; - - -extern const funnel_ops_t* funnel_get_funnel_ops(void); -extern void funnel_set_funnel_ops(const funnel_ops_t*); - - -extern void funnel_register_menu(const char *name, - register_stat_group_t group, - void (*callback)(gpointer), - gpointer callback_data, - gboolean retap); - - -typedef void (*funnel_registration_cb_t)(const char *name, - register_stat_group_t group, - void (*callback)(gpointer), - gpointer callback_data, - gboolean retap); - -extern void funnel_register_all_menus(funnel_registration_cb_t r_cb); - -extern void initialize_funnel_ops(void); - -extern void funnel_dump_all_text_windows(void); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/g_ascii_strcasecmp.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/g_ascii_strcasecmp.h deleted file mode 100644 index aef486b2..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/g_ascii_strcasecmp.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * $Id: g_ascii_strcasecmp.h 3992 2008-06-10 03:13:11Z dgu $ - * - * "g_ascii_strcasecmp()" and "g_ascii_strncasecmp()" extracted from - * GLib 2.4.8, for use with GLibs that don't have it (e.g., GLib 1.2[.x]). - */ - -#ifndef __WIRESHARK_G_ASCII_STRCASECMP_H__ -#define __WIRESHARK_G_ASCII_STRCASECMP_H__ - -extern gint g_ascii_strcasecmp (const gchar *s1, - const gchar *s2); - -extern gint g_ascii_strncasecmp (const gchar *s1, - const gchar *s2, - gsize n); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/g_ascii_strtoull.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/g_ascii_strtoull.h deleted file mode 100644 index d52d6d41..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/g_ascii_strtoull.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * $Id: g_ascii_strtoull.h 3992 2008-06-10 03:13:11Z dgu $ - * - * "g_ascii_strtoull()" extracted from GLib 2.4.5, for use with GLibs - * that don't have it (e.g., GLib 1.2[.x]). - */ - -#ifndef __WIRESHARK_G_ASCII_STRTOULL_H__ -#define __WIRESHARK_G_ASCII_STRTOULL_H__ - -extern guint64 g_ascii_strtoull (const gchar *nptr, - gchar **endptr, - guint base); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/garrayfix.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/garrayfix.h deleted file mode 100644 index 1d740562..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/garrayfix.h +++ /dev/null @@ -1,38 +0,0 @@ -/* garrayfix.h - * Macros to work around the "data" field of a GArray having type guint8 *, - * rather than void *, so that, even though the GArray code should be - * ensuring that the data is aligned strictly enough for any data type, - * we still get warnings with -Wcast-align. - * - * $Id: garrayfix.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2007 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __GARRAYFIX_H__ -#define __GARRAYFIX_H__ - -#ifdef g_array_index -#undef g_array_index -#define g_array_index(a,t,i) (((t*) (void*) (a)->data) [(i)]) -#endif - -#define g_array_data(a) ((void*) (a)->data) - -#endif /* __GARRAYFIX_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/gcp.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/gcp.h deleted file mode 100644 index 8dd8f728..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/gcp.h +++ /dev/null @@ -1,219 +0,0 @@ -/* gcp.h - * Gateway Control Protocol -- Context Tracking - * - * $Id: gcp.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#ifndef __GCP_H_ -#define __GCP_H_ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -#include - -typedef struct _gcp_hf_ett_t { - struct { - int ctx; - int ctx_cmd; - int ctx_term; - int ctx_term_type; - int ctx_term_bir; - int ctx_term_nsap; - } hf; - - struct { - gint ctx; - gint ctx_cmds; - gint ctx_terms; - gint ctx_term; - } ett; -} gcp_hf_ett_t; - -#define NULL_CONTEXT 0 -#define CHOOSE_CONTEXT 0xFFFFFFFE -#define ALL_CONTEXTS 0xFFFFFFFF - - -typedef enum { - GCP_CMD_NONE, - GCP_CMD_ADD_REQ, - GCP_CMD_MOVE_REQ, - GCP_CMD_MOD_REQ, - GCP_CMD_SUB_REQ, - GCP_CMD_AUDITCAP_REQ, - GCP_CMD_AUDITVAL_REQ, - GCP_CMD_NOTIFY_REQ, - GCP_CMD_SVCCHG_REQ, - GCP_CMD_TOPOLOGY_REQ, - GCP_CMD_CTX_ATTR_AUDIT_REQ, - GCP_CMD_OTHER_REQ, - GCP_CMD_ADD_REPLY, - GCP_CMD_MOVE_REPLY, - GCP_CMD_MOD_REPLY, - GCP_CMD_SUB_REPLY, - GCP_CMD_AUDITCAP_REPLY, - GCP_CMD_AUDITVAL_REPLY, - GCP_CMD_NOTIFY_REPLY, - GCP_CMD_SVCCHG_REPLY, - GCP_CMD_TOPOLOGY_REPLY, - GCP_CMD_REPLY -} gcp_cmd_type_t; - -typedef enum { - GCP_TRX_NONE, - GCP_TRX_REQUEST, - GCP_TRX_PENDING, - GCP_TRX_REPLY, - GCP_TRX_ACK -} gcp_trx_type_t; - - -typedef struct _gcp_msg_t { - guint32 lo_addr; - guint32 hi_addr; - guint32 framenum; - struct _gcp_trx_msg_t* trxs; - gboolean commited; -} gcp_msg_t; - -typedef struct _gcp_trx_msg_t { - struct _gcp_trx_t* trx; - struct _gcp_trx_msg_t* next; - struct _gcp_trx_msg_t* last; -} gcp_trx_msg_t; - -typedef struct _gcp_cmd_msg_t { - struct _gcp_cmd_t* cmd; - struct _gcp_cmd_msg_t* next; - struct _gcp_cmd_msg_t* last; -} gcp_cmd_msg_t; - -typedef struct _gcp_trx_t { - gcp_msg_t* initial; - guint32 id; - gcp_trx_type_t type; - guint pendings; - struct _gcp_cmd_msg_t* cmds; - struct _gcp_trx_ctx_t* ctxs; - guint error; -} gcp_trx_t; - -#define GCP_TERM_TYPE_UNKNOWN 0 -#define GCP_TERM_TYPE_AAL1 1 -#define GCP_TERM_TYPE_AAL2 2 -#define GCP_TERM_TYPE_AAL1_STRUCT 3 -#define GCP_TERM_TYPE_IP_RTP 4 -#define GCP_TERM_TYPE_TDM 5 - -typedef enum _gcp_wildcard_t { - GCP_WILDCARD_NONE, - GCP_WILDCARD_CHOOSE, - GCP_WILDCARD_ALL -} gcp_wildcard_t; - -typedef struct _gcp_term_t { - gchar* str; - - guint8* buffer; - guint len; - - guint type; - gchar* bir; - gchar* nsap; - - gcp_msg_t* start; - -} gcp_term_t; - -typedef struct _gcp_terms_t { - gcp_term_t* term; - struct _gcp_terms_t* next; - struct _gcp_terms_t* last; -} gcp_terms_t; - -typedef struct _gcp_cmd_t { - guint offset; - gchar* str; - gcp_cmd_type_t type; - gcp_terms_t terms; - struct _gcp_msg_t* msg; - struct _gcp_trx_t* trx; - struct _gcp_ctx_t* ctx; - guint error; -} gcp_cmd_t; - - -typedef struct _gcp_ctx_t { - gcp_msg_t* initial; - guint32 id; - struct _gcp_cmd_msg_t* cmds; - struct _gcp_ctx_t* prev; - gcp_terms_t terms; -} gcp_ctx_t; - -WS_VAR_IMPORT const value_string gcp_cmd_type[]; -WS_VAR_IMPORT const value_string gcp_term_types[]; - -extern void gcp_init(void); -extern gcp_msg_t* gcp_msg(packet_info* pinfo, int o, gboolean persistent); -extern gcp_trx_t* gcp_trx(gcp_msg_t* m ,guint32 t_id , gcp_trx_type_t type, gboolean persistent); -extern gcp_ctx_t* gcp_ctx(gcp_msg_t* m, gcp_trx_t* t, guint32 c_id, gboolean persistent); -extern gcp_cmd_t* gcp_cmd(gcp_msg_t* m, gcp_trx_t* t, gcp_ctx_t* c, gcp_cmd_type_t type, guint offset, gboolean persistent); -extern gcp_term_t* gcp_cmd_add_term(gcp_msg_t* m, gcp_trx_t* tr, gcp_cmd_t* c, gcp_term_t* t, gcp_wildcard_t wildcard, gboolean persistent); -extern void gcp_analyze_msg(proto_tree* gcp_tree, tvbuff_t* gcp_tvb, gcp_msg_t* m, gcp_hf_ett_t* ids); - -extern gchar* gcp_cmd_to_str(gcp_cmd_t* c, gboolean persistent); -extern gchar* gcp_msg_to_str(gcp_msg_t* m, gboolean persistent); - -#define gcp_cmd_set_error(c,e) (c->error = e) -#define gcp_trx_set_error(t,e) (t->error = e) - -#define GCP_ETT_ARR_ELEMS(gi) &(gi.ett.ctx),&(gi.ett.ctx_cmds),&(gi.ett.ctx_terms),&(gi.ett.ctx_term) - -#define GCP_HF_ARR_ELEMS(n,gi) \ - { &(gi.hf.ctx), { "Context", n ".ctx", FT_UINT32, BASE_HEX, NULL, 0, "", HFILL }}, \ - { &(gi.hf.ctx_term), { "Termination", n ".ctx.term", FT_STRING, BASE_NONE, NULL, 0, "", HFILL }}, \ - { &(gi.hf.ctx_term_type), { "Type", n ".ctx.term.type", FT_UINT32, BASE_HEX, VALS(gcp_term_types), 0, "", HFILL }}, \ - { &(gi.hf.ctx_term_bir), { "BIR", n ".ctx.term.bir", FT_STRING, BASE_HEX, NULL, 0, "", HFILL }}, \ - { &(gi.hf.ctx_term_nsap), { "NSAP", n ".ctx.term.nsap", FT_STRING, BASE_NONE, NULL, 0, "", HFILL }}, \ - { &(gi.hf.ctx_cmd), { "Command in Frame", n ".ctx.cmd", FT_FRAMENUM, BASE_DEC, NULL, 0, "", HFILL }} - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/gnuc_format_check.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/gnuc_format_check.h deleted file mode 100644 index a550dde7..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/gnuc_format_check.h +++ /dev/null @@ -1,39 +0,0 @@ -/* gnuc_format_check.h - * Definitions of macro to conditionally do GCC format checks - * - * $Id: gnuc_format_check.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __GNUC_FORMAT_CHECK_H__ -#define __GNUC_FORMAT_CHECK_H__ - -/** GNUC has the ability to check format strings that follow the syntax used in printf and others. - Hide the differences between different compilers in this GNUC_FORMAT_CHECK macro. - @param archetype one of: printf, scanf, strftime or strfmon - @param string_index specifies which argument is the format string argument (starting from 1) - @param first_to_check is the number of the first argument to check against the format string */ -#if __GNUC__ >= 2 - #define GNUC_FORMAT_CHECK(archetype, string_index, first_to_check) __attribute__((format (archetype, string_index, first_to_check))) -#else - #define GNUC_FORMAT_CHECK(archetype, string_index, first_to_check) -#endif - -#endif /* gnuc-format-check.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/golay.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/golay.h deleted file mode 100644 index ad3d454a..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/golay.h +++ /dev/null @@ -1,49 +0,0 @@ -/* $Id: golay.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Provides routines for encoding and decoding the extended Golay - * (24,12,8) code. - * - * This implementation will detect up to 4 errors in a codeword (without - * being able to correct them); it will correct up to 3 errors. - * - * We use guint32s to hold the 24-bit codewords, with the data part in - * the bottom 12 bits and the parity in bits 12-23. - * - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#ifndef __GOLAY_H__ -#define __GOLAY_H__ - -/* encodes a 12-bit word to a 24-bit codeword - */ -guint32 golay_encode(guint w); - -/* return a mask showing the bits which are in error in a received - * 24-bit codeword, or -1 if 4 errors were detected. - */ -gint32 golay_errors(guint32 codeword); - -/* decode a received codeword. Up to 3 errors are corrected for; 4 - errors are detected as uncorrectable (return -1); 5 or more errors - cause an incorrect correction. -*/ -gint golay_decode(guint32 w); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/greproto.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/greproto.h deleted file mode 100644 index de295dad..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/greproto.h +++ /dev/null @@ -1,36 +0,0 @@ -/* greproto.h - * Protocol type values for for the Generic Routing Encapsulation (GRE) - * protocol - * Brad Robel-Forrest - * - * The protocol type in GRE is supposed to be an Ethernet type value; - * this file lists protocol type values for which nobody's found an - * official Ethernet type definition and put that in "etypes.h". - * Move these to "etypes.h" if you find an official Ethernet type - * definition for them; when this file is empty, get rid of all includes - * of it, and get rid of it. - * - * $Id: greproto.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#define GRE_NHRP 0x2001 -#define GRE_WCCP 0x883E -#define GRE_ERSPAN 0x88BE diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/guid-utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/guid-utils.h deleted file mode 100644 index c2fc95d6..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/guid-utils.h +++ /dev/null @@ -1,63 +0,0 @@ -/* guid-utils.h - * Definitions for GUID handling - * - * $Id: guid-utils.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __GUID_UTILS_H__ -#define __GUID_UTILS_H__ - -#define GUID_LEN 16 - -/* Note: this might be larger than GUID_LEN, so don't overlay data in packets - with this. */ -typedef struct _e_guid_t { - guint32 data1; - guint16 data2; - guint16 data3; - guint8 data4[8]; -} e_guid_t; - - -extern void guids_init(void); - -/* add a GUID */ -extern void guids_add_guid(e_guid_t *guid, const gchar *name); - -/* try to get registered name for this GUID */ -extern const gchar *guids_get_guid_name(e_guid_t *guid); - -/* resolve GUID to name (or if unknown to hex string) */ -/* (if you need hex string only, use guid_to_str instead) */ -extern const gchar* guids_resolve_guid_to_str(e_guid_t *guid); - -/* add a UUID (dcerpc_init_uuid() will call this too) */ -#define guids_add_uuid(uuid, name) guids_add_guid((e_guid_t *) (uuid), (name)) - -/* try to get registered name for this UUID */ -#define guids_get_uuid_name(uuid) guids_get_guid_name((e_guid_t *) (uuid)) - -/* resolve UUID to name (or if unknown to hex string) */ -/* (if you need hex string only, use guid_to_str instead) */ -#define guids_resolve_uuid_to_str(uuid) guids_resolve_guid_to_str((e_guid_t *) (uuid)) - -#endif /* __GUID_UTILS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/h225-persistentdata.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/h225-persistentdata.h deleted file mode 100644 index 576330e5..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/h225-persistentdata.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * h225-persistentdata.h - * Definitions for lists and hash tables used in wireshark's h225 dissector - * for calculation of delays in h225-calls - * - * Copyright 2003 Lars Roland - * - * $Id: h225-persistentdata.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __h225_HASH__ -#define __h225_HASH__ - -#include -#include -#include - - -/* Item of ras request list*/ -typedef struct _h225ras_call_t { - guint32 requestSeqNum; - e_guid_t guid; - guint32 req_num; /* frame number request seen */ - guint32 rsp_num; /* frame number response seen */ - nstime_t req_time; /* arrival time of request */ - gboolean responded; /* true, if request has been responded */ - struct _h225ras_call_t *next_call; /* pointer to next ras request with same SequenceNumber and conversation handle */ -} h225ras_call_t; - - -/* Item of ras-request key list*/ -typedef struct _h225ras_call_info_key { - guint reqSeqNum; - conversation_t *conversation; -} h225ras_call_info_key; - -/* functions, needed using ras-request and halfcall matching*/ -h225ras_call_t * find_h225ras_call(h225ras_call_info_key *h225ras_call_key ,int category); -h225ras_call_t * new_h225ras_call(h225ras_call_info_key *h225ras_call_key, packet_info *pinfo, e_guid_t *guid, int category); -h225ras_call_t * append_h225ras_call(h225ras_call_t *prev_call, packet_info *pinfo, e_guid_t *guid, int category); - -void h225_init_routine(void); /* init routine, used by wireshark */ - -#endif /* __h225_HASH__*/ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/iax2_codec_type.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/iax2_codec_type.h deleted file mode 100644 index 7832eeec..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/iax2_codec_type.h +++ /dev/null @@ -1,77 +0,0 @@ -/* iax2_codec_type.h - * Defines IAX2 codec types - * - * $Id: iax2_codec_type.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __IAX2_CODEC_TYPE_H__ -#define __IAX2_CODEC_TYPE_H__ - - -/* Ref: frame.h from Asterisk source */ - -/* Data formats for capabilities and frames alike */ -/* suitable for use in iax2.codec dissector table */ -/*! G.723.1 compression */ -#define AST_FORMAT_G723_1 (1 << 0) -/*! GSM compression */ -#define AST_FORMAT_GSM (1 << 1) -/*! Raw mu-law data (G.711) */ -#define AST_FORMAT_ULAW (1 << 2) -/*! Raw A-law data (G.711) */ -#define AST_FORMAT_ALAW (1 << 3) -/*! ADPCM (G.726, 32kbps) */ -#define AST_FORMAT_G726 (1 << 4) -/*! ADPCM (IMA) */ -#define AST_FORMAT_ADPCM (1 << 5) -/*! Raw 16-bit Signed Linear (8000 Hz) PCM */ -#define AST_FORMAT_SLINEAR (1 << 6) -/*! LPC10, 180 samples/frame */ -#define AST_FORMAT_LPC10 (1 << 7) -/*! G.729A audio */ -#define AST_FORMAT_G729A (1 << 8) -/*! SpeeX Free Compression */ -#define AST_FORMAT_SPEEX (1 << 9) -/*! iLBC Free Compression */ -#define AST_FORMAT_ILBC (1 << 10) -/*! Maximum audio format */ -#define AST_FORMAT_MAX_AUDIO (1 << 15) -/*! JPEG Images */ -#define AST_FORMAT_JPEG (1 << 16) -/*! PNG Images */ -#define AST_FORMAT_PNG (1 << 17) -/*! H.261 Video */ -#define AST_FORMAT_H261 (1 << 18) -/*! H.263 Video */ -#define AST_FORMAT_H263 (1 << 19) -/*! Max one */ -#define AST_FORMAT_MAX_VIDEO (1 << 24) - - -/* data format for IAX_IE_DATAFORMAT ie */ -/* suitable for use in iax2.dataformat dissector table */ -typedef enum { - AST_DATAFORMAT_NULL, /* N/A: analogue call etc */ - AST_DATAFORMAT_V110, /* ITU-T V.110 rate adaption */ - AST_DATAFORMAT_H223_H245 /* ITU-T H.223/H.245 */ -} iax_dataformat_t; - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/in_cksum.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/in_cksum.h deleted file mode 100644 index 27c8273d..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/in_cksum.h +++ /dev/null @@ -1,14 +0,0 @@ -/* in_cksum.h - * Declaration of Internet checksum routine. - * - * $Id: in_cksum.h 3992 2008-06-10 03:13:11Z dgu $ - */ - -typedef struct { - const guint8 *ptr; - int len; -} vec_t; - -extern int in_cksum(const vec_t *vec, int veclen); - -extern guint16 in_cksum_shouldbe(guint16 sum, guint16 computed_sum); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/inet_aton.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/inet_aton.h deleted file mode 100644 index b7732a98..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/inet_aton.h +++ /dev/null @@ -1,34 +0,0 @@ -/* inet_aton.h - * - * $Id: inet_aton.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* - * Version of "inet_aton()", for the benefit of OSes that don't have it. - */ - -#ifndef __INET_ATON_H__ -#define __INET_ATON_H__ - -struct in_addr; -extern int inet_aton(const char* cp_arg, struct in_addr *addr); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ip_opts.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ip_opts.h deleted file mode 100644 index 4915c227..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ip_opts.h +++ /dev/null @@ -1,59 +0,0 @@ -/* ip_opts.h - * Definitions of structures and routines for dissection of options that - * work like IPv4 or IPv6 options - * - * $Id: ip_opts.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __IP_OPTS_H__ -#define __IP_OPTS_H__ - -typedef enum { - NO_LENGTH, /* option has no data, hence no length */ - FIXED_LENGTH, /* option always has the same length */ - VARIABLE_LENGTH /* option is variable-length - optlen is minimum */ -} opt_len_type; - -/* Member of table of IP or TCP options. */ -typedef struct ip_tcp_opt { - int optcode; /* code for option */ - const char *name; /* name of option */ - int *subtree_index; /* pointer to subtree index for option */ - opt_len_type len_type; /* type of option length field */ - int optlen; /* value length should be (minimum if VARIABLE) */ - void (*dissect)(const struct ip_tcp_opt *, tvbuff_t *, int, guint, - packet_info *, proto_tree *); - /* routine to dissect option */ -} ip_tcp_opt; - -/* Routine to dissect options that work like IPv4 options, where the - length field in the option, if present, includes the type and - length bytes. */ -extern void dissect_ip_tcp_options(tvbuff_t *, int, guint, - const ip_tcp_opt *, int, int, packet_info *, proto_tree *); - -/* Routine to dissect options that work like IPv6 options, where the - length field in the option, if present, includes only the data, not - the type and length bytes. */ -extern void dissect_ipv6_options(tvbuff_t *, int, guint, - const ip_tcp_opt *, int, int, packet_info *, proto_tree *); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipproto.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipproto.h deleted file mode 100644 index a6861cd7..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipproto.h +++ /dev/null @@ -1,193 +0,0 @@ -/* ipproto.h - * Declarations of IP protocol numbers, and of routines for converting - * IP protocol numbers into strings. - * - * $Id: ipproto.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __IPPROTO_H__ -#define __IPPROTO_H__ - -/* - * IP protocol numbers. - */ -#define IP_PROTO_IP 0 /* dummy for IP */ -#define IP_PROTO_HOPOPTS 0 /* IP6 hop-by-hop options - RFC1883 */ -#define IP_PROTO_ICMP 1 /* control message protocol - RFC792 */ -#define IP_PROTO_IGMP 2 /* group mgmt protocol - RFC1112 */ -#define IP_PROTO_GGP 3 /* gateway^2 (deprecated) - RFC823*/ -#define IP_PROTO_IPIP 4 /* IP inside IP - RFC2003*/ -#define IP_PROTO_IPV4 4 /* IP header */ -#define IP_PROTO_STREAM 5 /* Stream - RFC1190, RFC1819 */ -#define IP_PROTO_TCP 6 /* TCP - RFC792 */ -#define IP_PROTO_CBT 7 /* CBT - */ -#define IP_PROTO_EGP 8 /* exterior gateway protocol - RFC888 */ -#define IP_PROTO_IGP 9 /* any private interior gateway protocol ... */ -#define IP_PROTO_IGRP 9 /* ... and used by Cisco for IGRP */ -#define IP_PROTO_BBN_RCC 10 /* BBN RCC Monitoring */ -#define IP_PROTO_NVPII 11 /* Network Voice Protocol - RFC741 */ -#define IP_PROTO_PUP 12 /* pup */ -#define IP_PROTO_ARGUS 13 /* ARGUS */ -#define IP_PROTO_EMCON 14 /* EMCON */ -#define IP_PROTO_XNET 15 /* Cross net debugger - IEN158 */ -#define IP_PROTO_CHAOS 16 /* CHAOS */ -#define IP_PROTO_UDP 17 /* user datagram protocol - RFC768 */ -#define IP_PROTO_MUX 18 /* multiplexing - IEN90 */ -#define IP_PROTO_DCNMEAS 19 /* DCN Measurement Subsystems */ -#define IP_PROTO_HMP 20 /* Host Monitoring - RFC869 */ -#define IP_PROTO_PRM 21 /* Packet radio measurement */ -#define IP_PROTO_IDP 22 /* xns idp */ -#define IP_PROTO_TRUNK1 23 -#define IP_PROTO_TRUNK2 24 -#define IP_PROTO_LEAF1 25 -#define IP_PROTO_LEAF2 26 -#define IP_PROTO_RDP 27 /* Reliable Data Protocol - RFC908 */ -#define IP_PROTO_IRT 28 /* Internet Reliable Transation - RFC938 */ -#define IP_PROTO_TP 29 /* tp-4 w/ class negotiation - RFC905 */ -#define IP_PROTO_BULK 30 /* Bulk Data Transfer Protocol - RFC969 */ -#define IP_PROTO_MFE_NSP 31 /* MFE Network Services Protocol */ -#define IP_PROTO_MERIT 32 /* MERIT Internodal Protocol */ -/* #define IP_PROTO_SEP 33 Sequential Exchange Protocol */ -#define IP_PROTO_DCCP 33 /* Datagram Congestion Control Protocol */ -#define IP_PROTO_3PC 34 /* Third party connect protocol */ -#define IP_PROTO_IDPR 35 /* Interdomain policy routing protocol */ -#define IP_PROTO_XTP 36 /* XTP */ -#define IP_PROTO_DDP 37 /* Datagram Delivery Protocol */ -#define IP_PROTO_CMTP 38 /* Control Message Transport Protocol */ -#define IP_PROTO_TPPP 39 /* TP++ Transport Protocol */ -#define IP_PROTO_IL 40 /* IL Transport Protocol */ -#define IP_PROTO_IPV6 41 /* IP6 header */ -#define IP_PROTO_SDRP 42 /* Source demand routing protocol */ -#define IP_PROTO_ROUTING 43 /* IP6 routing header */ -#define IP_PROTO_FRAGMENT 44 /* IP6 fragmentation header */ -#define IP_PROTO_IDRP 45 /* Inter-Domain Routing Protocol */ -#define IP_PROTO_RSVP 46 /* Resource ReSerVation protocol */ -#define IP_PROTO_GRE 47 /* General Routing Encapsulation */ -#define IP_PROTO_MHRP 48 /* Mobile Host Routing Protocol */ -#define IP_PROTO_BNA 49 /* BNA */ -#define IP_PROTO_ESP 50 /* Encap Security Payload for IPv6 - RFC2406 */ -#define IP_PROTO_AH 51 /* Authentication Header for IPv6 - RFC2402*/ -#define IP_PROTO_INSLP 52 /* Integrated Net Layer Security */ -#define IP_PROTO_SWIPE 53 /* IP with Encryption */ -#define IP_PROTO_NARP 54 /* NBMA Address resolution protocol - RFC1735 */ -#define IP_PROTO_MOBILE 55 /* IP Mobility */ -#define IP_PROTO_TLSP 56 /* Transport Layer Security Protocol using */ - /* Kryptonet key management */ -#define IP_PROTO_SKIP 57 /* SKIP */ -#define IP_PROTO_ICMPV6 58 /* ICMP6 - RFC1883*/ -#define IP_PROTO_NONE 59 /* IP6 no next header - RFC1883 */ -#define IP_PROTO_DSTOPTS 60 /* IP6 destination options - RFC1883 */ -/* 61 is reserved by IANA for any host internal protocol */ -/* 61 is used by UCL's SHIM6 implementation as Next Header for SHIM6 */ -#define IP_PROTO_SHIM6 61 /* SHIM6 */ - -/* - * The current Protocol Numbers list says that the IP protocol number for - * mobility headers is 135; it cites draft-ietf-mobileip-ipv6-24, but - * that draft doesn't actually give a number. - * - * It appears that 62 used to be used, even though that's assigned to - * a protocol called CFTP; however, the only reference for CFTP is a - * Network Message from BBN back in 1982, so, for now, we support 62, - * as well as 135, as a protocol number for mobility headers. - */ -#define IP_PROTO_MIPV6_OLD 62 /* Mobile IPv6 */ -/* 63 is reserved by IANA for any local network */ -#define IP_PROTO_SATEXPAK 64 -#define IP_PROTO_KRYPTOLAN 65 -#define IP_PROTO_RVD 66 /* MIT Remote virtual disk protocol */ -#define IP_PROTO_IPPC 67 /* Internet Pluribus Packet Core */ -/* 68 is reserved by IANA for any distributed file system */ -#define IP_PROTO_SATMON 69 /* SATNET Monitoring */ -#define IP_PROTO_VISA 70 /* VISA Protocol */ -#define IP_PROTO_IPCV 71 /* Internet Packet Core Utility */ -#define IP_PROTO_CPNX 72 /* Computer Protocol Network Executive */ -#define IP_PROTO_CPHB 73 /* Computer Protocol Heart Beat */ -#define IP_PROTO_WSN 74 /* WANG Span Network */ -#define IP_PROTO_PVP 75 /* Packet Video Protocol */ -#define IP_PROTO_BRSATMON 76 /* Backroon SATNET Monitoring */ -#define IP_PROTO_SUNND 77 /* SUN ND Protocol - Temporary */ -#define IP_PROTO_WBMON 78 /* Wideband Monitoring */ -#define IP_PROTO_WBEXPAK 79 /* Wideband EXPAK */ -#define IP_PROTO_EON 80 /* ISO cnlp */ -#define IP_PROTO_VMTP 81 -#define IP_PROTO_SVMTP 82 /* Secure VMTP */ -#define IP_PROTO_VINES 83 /* Vines over raw IP */ -#define IP_PROTO_TTP 84 -#define IP_PROTO_NSFNETIGP 85 /* NSFNET IGP */ -#define IP_PROTO_DGP 86 /* Dissimilar Gateway Protocol */ -#define IP_PROTO_TCF 87 -#define IP_PROTO_EIGRP 88 -#define IP_PROTO_OSPF 89 /* OSPF Interior Gateway Protocol - RFC1583 */ -#define IP_PROTO_SPRITE 90 /* SPRITE RPC protocol */ -#define IP_PROTO_LARP 91 /* Locus Address Resolution Protocol */ -#define IP_PROTO_MTP 92 /* Multicast Transport Protocol */ -#define IP_PROTO_AX25 93 /* AX.25 frames */ -#define IP_PROTO_IPINIP 94 /* IP within IP Encapsulation protocol */ -#define IP_PROTO_MICP 95 /* Mobile Internetworking Control Protocol */ -#define IP_PROTO_SCCCP 96 /* Semaphore communications security protocol */ -#define IP_PROTO_ETHERIP 97 /* Ethernet-within-IP - RFC 3378 */ -#define IP_PROTO_ENCAP 98 /* encapsulation header - RFC1241*/ -/* 99 is reserved by IANA for any private encryption scheme */ -#define IP_PROTO_GMTP 100 -#define IP_PROTO_IFMP 101 /* Ipsilon flow management protocol */ -#define IP_PROTO_PNNI 102 /* PNNI over IP */ -#define IP_PROTO_PIM 103 /* Protocol Independent Mcast */ -#define IP_PROTO_ARIS 104 -#define IP_PROTO_SCPS 105 -#define IP_PROTO_QNX 106 -#define IP_PROTO_AN 107 /* Active Networks */ -#define IP_PROTO_IPCOMP 108 /* IP payload compression - RFC2393 */ -#define IP_PROTO_SNP 109 /* Sitara Networks Protocol */ -#define IP_PROTO_COMPAQ 110 /* Compaq Peer Protocol */ -#define IP_PROTO_IPX 111 /* IPX over IP */ -#define IP_PROTO_VRRP 112 /* Virtual Router Redundancy Protocol */ -#define IP_PROTO_PGM 113 /* Pragmatic General Multicast */ -/* 114 is reserved by IANA for any zero hop protocol */ -#define IP_PROTO_L2TP 115 /* Layer Two Tunnelling Protocol */ -#define IP_PROTO_DDX 116 /* D-II Data Exchange */ -#define IP_PROTO_IATP 117 /* Interactive Agent Transfer Protocol */ -#define IP_PROTO_STP 118 /* Schedule Transfer Protocol */ -#define IP_PROTO_SRP 119 /* Spectralink Radio Protocol */ -#define IP_PROTO_UTI 120 -#define IP_PROTO_SMP 121 /* Simple Message Protocol */ -#define IP_PROTO_SM 122 -#define IP_PROTO_PTP 123 /* Performance Transparency Protocol */ -#define IP_PROTO_ISIS 124 /* ISIS over IPv4 */ -#define IP_PROTO_FIRE 125 -#define IP_PROTO_CRTP 126 /* Combat Radio Transport Protocol */ -#define IP_PROTO_CRUDP 127 /* Combat Radio User Datagram */ -#define IP_PROTO_SSCOPMCE 128 -#define IP_PROTO_IPLT 129 -#define IP_PROTO_SPS 130 /* Secure Packet Shield */ -#define IP_PROTO_PIPE 131 /* Private IP Encapsulation within IP */ -#define IP_PROTO_SCTP 132 /* Stream Control Transmission Protocol */ -#define IP_PROTO_FC 133 /* Fibre Channel */ -#define IP_PROTO_RSVPE2EI 134 /* RSVP E2E Ignore - RFC3175 */ -#define IP_PROTO_MIPV6 135 /* Mobile IPv6 */ -#define IP_PROTO_UDPLITE 136 /* Lightweight user datagram protocol - RFC3828 */ -#define IP_PROTO_MPLS_IN_IP 137 /* MPLS in IP - RFC4023 */ -#define IP_PROTO_AX4000 173 /* AX/4000 Testblock - non IANA */ -#define IP_PROTO_NCS_HEARTBEAT 224 /* Novell NCS Heartbeat - http://support.novell.com/cgi-bin/search/searchtid.cgi?/10071158.htm */ - -extern const char *ipprotostr(int proto); - -#endif /* ipproto.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipv4.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipv4.h deleted file mode 100644 index c1cbbbde..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipv4.h +++ /dev/null @@ -1,67 +0,0 @@ -/* ipv4.h - * - * IPv4 address class. They understand how to take netmasks into consideration - * during equivalence testing. - * - * Gilbert Ramirez - * - * $Id: ipv4.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __IPV4_H__ -#define __IPV4_H__ - -#include - -typedef struct { - guint32 addr; /* stored in host order */ - guint32 nmask; /* stored in host order */ -} ipv4_addr; - -/* Allocate a new ipv4_addr struct, initialize it, and return pointer */ -ipv4_addr* ipv4_addr_new(void); - -/* Frees an ipv4 struct */ -void ipv4_addr_free(ipv4_addr *ipv4); - -void ipv4_addr_set_host_order_addr(ipv4_addr *ipv4, guint32 new_addr); -void ipv4_addr_set_net_order_addr(ipv4_addr *ipv4, guint32 new_addr); -void ipv4_addr_set_netmask_bits(ipv4_addr *ipv4, guint new_nmask_bits); - -guint32 ipv4_get_net_order_addr(ipv4_addr *ipv4); -guint32 ipv4_get_host_order_addr(ipv4_addr *ipv4); - -/* Fills in a buffer with a dotted-decimal notation representation of an IPv4 - * address. */ -void ipv4_addr_str_buf(const ipv4_addr *ipv4, gchar *buf); - -/* Compares two ipv4_addrs, taking into account the less restrictive of the - * two netmasks, applying that netmask to both addrs. - */ -gboolean ipv4_addr_eq(ipv4_addr *a, ipv4_addr *b); -gboolean ipv4_addr_gt(ipv4_addr *a, ipv4_addr *b); -gboolean ipv4_addr_ge(ipv4_addr *a, ipv4_addr *b); -gboolean ipv4_addr_lt(ipv4_addr *a, ipv4_addr *b); -gboolean ipv4_addr_le(ipv4_addr *a, ipv4_addr *b); - -#define ipv4_addr_ne(a,b) !ipv4_addr_eq((a),(b)) - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipv6-utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipv6-utils.h deleted file mode 100644 index a743f806..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipv6-utils.h +++ /dev/null @@ -1,49 +0,0 @@ -/* ipv6-utils.h - * Definitions for IPv6 packet disassembly - * - * $Id: ipv6-utils.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * - * Copyright 1998 Gerald Combs - * - * MobileIPv6 support added by Tomislav Borosa - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __IPV6_UTILS_H__ -#define __IPV6_UTILS_H__ - -struct e_in6_addr { - guint8 bytes[16]; /* 128 bit IP6 address */ -}; - -/* - * Unicast Scope - * Note that we must check topmost 10 bits only, not 16 bits (see RFC2373). - */ -#define E_IN6_IS_ADDR_LINKLOCAL(a) \ - (((a)->bytes[0] == 0xfe) && (((a)->bytes[1] & 0xc0) == 0x80)) -#define E_IN6_IS_ADDR_SITELOCAL(a) \ - (((a)->bytes[0] == 0xfe) && (((a)->bytes[1] & 0xc0) == 0xc0)) - -/* - * Multicast - */ -#define E_IN6_IS_ADDR_MULTICAST(a) ((a)->bytes[0] == 0xff) - -#endif /* __IPV6_UTILS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/lapd_sapi.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/lapd_sapi.h deleted file mode 100644 index 5750f796..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/lapd_sapi.h +++ /dev/null @@ -1,38 +0,0 @@ -/* lapd_sapi.h - * Declarations of LAPD SAPI values. - * - * $Id: lapd_sapi.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2004 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __LAPD_SAPI_H__ -#define __LAPD_SAPI_H__ - -#define LAPD_SAPI_Q931 0 /* Q.931 call control procedure */ -#define LAPD_SAPI_PM_Q931 1 /* Packet mode Q.931 call control procedure */ -#define LAPD_SAPI_X25 16 /* X.25 Level 3 procedures */ -#define LAPD_SAPI_L2 63 /* Layer 2 management procedures */ - -#define LAPD_GSM_SAPI_RA_SIG_PROC 0 -#define LAPD_GSM_SAPI_NOT_USED_1 1 -#define LAPD_GSM_SAPI_NOT_USED_16 16 -#define LAPD_GSM_SAPI_OM_PROC 62 - -#endif /* lapd_sapi.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/llcsaps.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/llcsaps.h deleted file mode 100644 index ddafad20..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/llcsaps.h +++ /dev/null @@ -1,63 +0,0 @@ -/* llcsaps.h - * Defines LLC SAP values. - * - * $Id: llcsaps.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __LLCSAPS_H__ -#define __LLCSAPS_H__ - -#define SAP_NULL 0x00 -#define SAP_LLC_SLMGMT 0x02 -#define SAP_SNA_PATHCTRL 0x04 -#define SAP_IP 0x06 -#define SAP_SNA1 0x08 -#define SAP_SNA2 0x0C -#define SAP_PROWAY_NM_INIT 0x0E -#define SAP_NETWARE1 0x10 -#define SAP_OSINL1 0x14 -#define SAP_TI 0x18 -#define SAP_OSINL2 0x20 -#define SAP_OSINL3 0x34 -#define SAP_SNA3 0x40 -#define SAP_BPDU 0x42 -#define SAP_RS511 0x4E -#define SAP_OSINL4 0x54 -#define SAP_X25 0x7E -#define SAP_XNS 0x80 -#define SAP_BACNET 0x82 -#define SAP_NESTAR 0x86 -#define SAP_PROWAY_ASLM 0x8E -#define SAP_ARP 0x98 -#define SAP_SNAP 0xAA -#define SAP_HPJD 0xB4 -#define SAP_VINES1 0xBA -#define SAP_VINES2 0xBC -#define SAP_NETWARE2 0xE0 -#define SAP_NETBIOS 0xF0 -#define SAP_IBMNM 0xF4 -#define SAP_HPEXT 0xF8 -#define SAP_UB 0xFA -#define SAP_RPL 0xFC -#define SAP_OSINL5 0xFE -#define SAP_GLOBAL 0xFF - -#endif /* llcsaps.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/next_tvb.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/next_tvb.h deleted file mode 100644 index 583c9a41..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/next_tvb.h +++ /dev/null @@ -1,65 +0,0 @@ -/* next_tvb.h - * Definitions for "next tvb" list - * - * $Id: next_tvb.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -/* The buffers returned by these functions are all allocated with a - * packet lifetime or are static buffers and does not have have to be freed. - * However, take into account that when the packet dissection - * completes, these buffers will be automatically reclaimed/freed. - * If you need the buffer to remain for a longer scope than packet lifetime - * you must copy the content to an se_alloc() buffer. - */ - -#ifndef __NEXT_TVB_H__ -#define __NEXT_TVB_H__ - -typedef enum { - NTVB_HANDLE, - NTVB_PORT, - NTVB_STRING -} next_tvb_call_e; - -typedef struct next_tvb_item { - struct next_tvb_item *next; - struct next_tvb_item *previous; - next_tvb_call_e type; - dissector_handle_t handle; - dissector_table_t table; - guint32 port; - const gchar *string; - tvbuff_t *tvb; - proto_tree *tree; -} next_tvb_item_t; - -typedef struct { - next_tvb_item_t *first; - next_tvb_item_t *last; - int count; -} next_tvb_list_t; - -extern void next_tvb_init(next_tvb_list_t *list); -extern void next_tvb_add_handle(next_tvb_list_t *list, tvbuff_t *tvb, proto_tree *tree, dissector_handle_t handle); -extern void next_tvb_add_port(next_tvb_list_t *list, tvbuff_t *tvb, proto_tree *tree, dissector_table_t table, guint32 port); -extern void next_tvb_add_string(next_tvb_list_t *list, tvbuff_t *tvb, proto_tree *tree, dissector_table_t table, const gchar *string); -extern void next_tvb_call(next_tvb_list_t *list, packet_info *pinfo, proto_tree *tree, dissector_handle_t handle, dissector_handle_t data_handle); - -#endif /* __NEXT_TVB_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/nlpid.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/nlpid.h deleted file mode 100644 index c4c7ce40..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/nlpid.h +++ /dev/null @@ -1,60 +0,0 @@ -/* nlpid.h - * Definitions of OSI NLPIDs (Network Layer Protocol IDs) - * Laurent Deniel - * - * $Id: nlpid.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __NLPID_H__ -#define __NLPID_H__ - -/* X.263 / ISO/IEC TR 9577 NLPID values. */ - -#define NLPID_NULL 0x00 -#define NLPID_IPI_T_70 0x01 /* T.70, when an IPI */ -#define NLPID_SPI_X_29 0x01 /* X.29, when an SPI */ -#define NLPID_X_633 0x03 /* X.633 */ -#define NLPID_Q_931 0x08 /* Q.931, Q.932, X.36, ISO 11572, ISO 11582 */ -#define NLPID_Q_933 0x08 /* Q.933, on Frame Relay */ -#define NLPID_Q_2931 0x09 /* Q.2931 */ -#define NLPID_Q_2119 0x0c /* Q.2119 */ -#define NLPID_SNAP 0x80 -#define NLPID_ISO8473_CLNP 0x81 /* X.233 */ -#define NLPID_ISO9542_ESIS 0x82 -#define NLPID_ISO10589_ISIS 0x83 -#define NLPID_ISO10747_IDRP 0x85 -#define NLPID_ISO9542X25_ESIS 0x8a -#define NLPID_ISO10030 0x8c -#define NLPID_ISO11577 0x8d /* X.273 */ -#define NLPID_IP6 0x8e -#define NLPID_COMPRESSED 0xb0 /* "Data compression protocol" */ -#define NLPID_SNDCF 0xc1 /* "SubNetwork Dependent Convergence Function */ -#define NLPID_IP 0xcc -#define NLPID_PPP 0xcf - -extern const value_string nlpid_vals[]; - -/* - * 0x09 is, in Frame Relay, LMI, Q.2931. - */ -#define NLPID_LMI 0x09 /* LMI */ - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/nstime.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/nstime.h deleted file mode 100644 index c92375df..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/nstime.h +++ /dev/null @@ -1,92 +0,0 @@ -/* nstime.h - * Definition of data structure to hold time values with nanosecond resolution - * - * $Id: nstime.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __NSTIME_H__ -#define __NSTIME_H__ - -#include - -#include - -typedef struct { - time_t secs; - int nsecs; -} nstime_t; - -/* functions */ - -/* set the given nstime_t to zero */ -extern void nstime_set_zero(nstime_t *nstime); - -/* is the given nstime_t currently zero? */ -extern gboolean nstime_is_zero(nstime_t *nstime); - -/* set the given nstime_t to (0,maxint) to mark it as "unset" - * That way we can find the first frame even when a timestamp - * is zero (fix for bug 1056) - */ -extern void nstime_set_unset(nstime_t *nstime); - -/* is the given nstime_t currently (0,maxint)? */ -extern gboolean nstime_is_unset(nstime_t *nstime); - -/* calculate the delta between two times (can be negative!) - * - * delta = b-a - * - * Note that it is acceptable for two or more of the arguments to point at the - * same structure. - */ -extern void nstime_delta(nstime_t *delta, const nstime_t *b, const nstime_t *a ); - -/* calculate the sum of two times - * - * sum = a+b - * - * Note that it is acceptable for two or more of the arguments to point at the - * same structure. - */ -extern void nstime_sum(nstime_t *sum, const nstime_t *b, const nstime_t *a ); - -/* sum += a */ -#define nstime_add(sum, a) nstime_sum(sum, sum, a) - -/* compare two times are return a value similar to memcmp() or strcmp(). - * - * a > b : > 0 - * a = b : 0 - * a < b : < 0 - */ -extern int nstime_cmp(nstime_t *a, const nstime_t *b ); - -/* converts nstime to double, time base is milli seconds */ -extern double nstime_to_msec(const nstime_t *time); - -/* converts nstime to double, time base is seconds */ -extern double nstime_to_sec(const nstime_t *time); - -/* converts wtap_nstime to double, time base is seconds */ -extern double wtap_nstime_to_sec(const struct wtap_nstime *time); - -#endif /* __NSTIME_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/oids.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/oids.h deleted file mode 100644 index 50a4ea83..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/oids.h +++ /dev/null @@ -1,179 +0,0 @@ -/* oids.h - * Object IDentifier Support - * - * $Id: oids.h 3992 2008-06-10 03:13:11Z dgu $ - * - * (c) 2007, Luis E. Garcia Ontanon - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __OIDS_H__ -#define __OIDS_H__ - -#define BER_TAG_ANY -1 - -struct _oid_bit_t { - guint offset; - int hfid; -}; - -typedef struct _oid_bits_info_t { - guint num; - gint ett; - struct _oid_bit_t* data; -} oid_bits_info_t; - -typedef enum _oid_key_type_t { - OID_KEY_TYPE_WRONG, - OID_KEY_TYPE_INTEGER, - OID_KEY_TYPE_OID, - OID_KEY_TYPE_STRING, - OID_KEY_TYPE_BYTES, - OID_KEY_TYPE_NSAP, - OID_KEY_TYPE_IPADDR, - OID_KEY_TYPE_IMPLIED_OID, - OID_KEY_TYPE_IMPLIED_STRING, - OID_KEY_TYPE_IMPLIED_BYTES -} oid_key_type_t; - -typedef struct _oid_value_type_t { - enum ftenum ft_type; - int display; - gint8 ber_class; - gint32 ber_tag; - int min_len; - int max_len; - oid_key_type_t keytype; - int keysize; -} oid_value_type_t; - -typedef enum _oid_kind_t { - OID_KIND_UNKNOWN = 0, - OID_KIND_NODE, - OID_KIND_SCALAR, - OID_KIND_TABLE, - OID_KIND_ROW, - OID_KIND_COLUMN, - OID_KIND_NOTIFICATION, - OID_KIND_GROUP, - OID_KIND_COMPLIANCE, - OID_KIND_CAPABILITIES -} oid_kind_t; - -typedef struct _oid_key_t { - char* name; - guint32 num_subids; - oid_key_type_t key_type; - int hfid; - enum ftenum ft_type; - int display; - struct _oid_key_t* next; -} oid_key_t; - -typedef struct _oid_info_t { - guint32 subid; - char* name; - oid_kind_t kind; - void* children; /* an emem_tree_t* */ - const oid_value_type_t* value_type; - int value_hfid; - oid_key_t* key; - oid_bits_info_t* bits; - struct _oid_info_t* parent; -} oid_info_t; - -/* init funcion called from epan.h */ -extern void oids_init(void); - -/* - * The objects returned by all these functions are all allocated with a - * packet lifetime and does not have have to be freed. - * However, take into account that when the packet dissection - * completes, these buffers will be automatically reclaimed/freed. - * If you need the buffer to remain for a longer scope than packet lifetime - * you must copy the content to an se_alloc() buffer. - */ - -/* - * These functions convert through the various formats: - * string: is like "0.1.3.4.5.30" (not resolved) - * encoded: is BER encoded (as per X.690 section 8.19) - * subids: is an array of guint32s - */ - -/* return length of encoded buffer */ -guint oid_subid2encoded(guint len, guint32* subids, guint8** encoded_p); -guint oid_string2encoded(const gchar *oid_str, guint8** encoded_p); - -/* return length of subid array */ -guint oid_encoded2subid(const guint8 *oid, gint len, guint32** subids_p); -guint oid_string2subid(const gchar *oid_str, guint32** subids_p); - -extern const gchar* oid_encoded2string(const guint8* encoded, guint len); -extern const gchar* oid_subid2string(guint32 *subids, guint len); - -/* these return a formated string as human readable as posible */ -extern const gchar *oid_resolved(guint len, guint32 *subids); -extern const gchar *oid_resolved_from_encoded(const guint8 *oid, gint len); -extern const gchar *oid_resolved_from_string(const gchar *oid_str); - -/* these yield two formated strings one resolved and one numeric */ -extern void oid_both(guint oid_len, guint32 *subids, char** resolved_p, char** numeric_p); -extern void oid_both_from_encoded(const guint8 *oid, gint oid_len, char** resolved_p, char** numeric_p); -extern void oid_both_from_string(const gchar *oid_str, char** resolved_p, char** numeric_p); - -/* - * These return the info for the best match. - * *matched_p will be set to the number of nodes used by the returned oid - * *left_p will be set to the number of remaining unresolved subids - */ -extern oid_info_t* oid_get(guint oid_len, guint32 *subids, guint* matched_p, guint* left_p); -extern oid_info_t* oid_get_from_encoded(const guint8 *oid, gint oid_len, guint32 **subids, guint* matched, guint* left); -extern oid_info_t* oid_get_from_string(const gchar *oid_str, guint32 **subids, guint* matched, guint* left); - -/* these are used to add oids to the collection */ -extern void oid_add(const char* name, guint oid_len, guint32 *subids); -extern void oid_add_from_encoded(const char* name, const guint8 *oid, gint oid_len); -extern void oid_add_from_string(const char* name, const gchar *oid_str); - -/** - * Fetch the default MIB/PIB path - * - * @return A string containing the default MIB/PIB path. It must be - * g_free()d by the caller. - */ -extern gchar *oid_get_default_mib_path(void); - -extern void oid_add_from_string(const char* name, const gchar *oid_str); - -/* macros for legacy oid functions */ -#define oid_resolv_cleanup() ((void)0) -#define subid_t guint32 - - - -#ifdef DEBUG_OIDS -extern char* oid_test_a2b(guint32 num_subids, guint32* subids); -extern void add_oid_debug_subtree(oid_info_t* oid_info, proto_tree *tree); -#else -#define add_oid_debug_subtree(a,b) ((void)0) -#endif - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/osi-utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/osi-utils.h deleted file mode 100644 index 97b6b27a..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/osi-utils.h +++ /dev/null @@ -1,57 +0,0 @@ -/* osi-utils.h - * - * $Id: osi-utils.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __OSI_UTILS_H__ -#define __OSI_UTILS_H__ - -/* OSI Global defines, common for all OSI protocols */ - -#define MAX_NSAP_LEN 30 -#define MAX_SYSTEMID_LEN 15 -#define MAX_AREA_LEN 30 - -#define RFC1237_NSAP_LEN 20 -#define RFC1237_FULLAREA_LEN 13 -#define RFC1237_SYSTEMID_LEN 6 -#define RFC1237_SELECTOR_LEN 1 - -#define RFC1237_IDI_LEN 2 -#define RFC1237_AFI_LEN 1 -#define RFC1237_DFI_LEN 1 -#define RFC1237_ORG_LEN 3 -#define RFC1237_AA_LEN 3 -#define RFC1237_RSVD_LEN 2 -#define RFC1237_RD_LEN 2 -#define RFC1237_AREA_LEN 3 - -#define NSAP_IDI_ISODCC 0x39 -#define NSAP_IDI_GOSIP2 0x47 - -gchar* print_nsap_net ( const guint8 *, int ); -void print_nsap_net_buf( const guint8 *, int, gchar *, int); -gchar* print_area ( const guint8 *, int ); -void print_area_buf ( const guint8 *, int, gchar *, int); -gchar* print_system_id( const guint8 *, int ); -void print_system_id_buf( const guint8 *, int, gchar *, int); - -#endif /* __OSI_UTILS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/oui.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/oui.h deleted file mode 100644 index 1431d530..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/oui.h +++ /dev/null @@ -1,74 +0,0 @@ -/* oui.h - * Definitions of OUIs - * - * $Id: oui.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 - 2000 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __OUI_H__ -#define __OUI_H__ - -/* - * See - * - * http://standards.ieee.org/regauth/oui/oui.txt - * - * http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/vlan.htm - * - * for the PIDs for VTP and DRiP that go with an OUI of OUI_CISCO. - */ - -#define OUI_ENCAP_ETHER 0x000000 /* encapsulated Ethernet */ -#define OUI_XEROX 0x000006 /* Xerox */ -#define OUI_CISCO 0x00000C /* Cisco (future use) */ -#define OUI_NORTEL 0x000081 /* Nortel SONMP */ -#define OUI_CISCO_90 0x0000F8 /* Cisco (IOS 9.0 and above?) */ -#define OUI_ERICSSON 0x0001EC /* Ericsson Group */ -#define OUI_CATENA 0x00025A /* Catena Networks */ -#define OUI_SONY_ERICSSON 0x000AD9 /* Sony Ericsson Mobile Communications AB */ -#define OUI_SONY_ERICSSON_2 0x000E07 /* Sony Ericsson Mobile Communications AB */ -#define OUI_PROFINET 0x000ECF /* PROFIBUS Nutzerorganisation e.V. */ -#define OUI_SONY_ERICSSON_3 0x000FDE /* Sony Ericsson Mobile Communications AB */ -#define OUI_IEEE_802_3 0x00120F /* IEEE 802.3 */ -#define OUI_MEDIA_ENDPOINT 0x0012BB /* Media (TIA TR-41 Committee) */ -#define OUI_SONY_ERICSSON_4 0x0012EE /* Sony Ericsson Mobile Communications AB */ -#define OUI_ERICSSON_MOBILE 0x0015E0 /* Ericsson Mobile Platforms */ -#define OUI_SONY_ERICSSON_5 0x001620 /* Sony Ericsson Mobile Communications AB */ -#define OUI_SONY_ERICSSON_6 0x0016B8 /* Sony Ericsson Mobile Communications AB */ -#define OUI_SONY_ERICSSON_7 0x001813 /* Sony Ericsson Mobile Communications AB */ -#define OUI_SONY_ERICSSON_8 0x001963 /* Sony Ericsson Mobile Communications AB */ -#define OUI_CISCOWL 0x004096 /* Cisco Wireless (Aironet) */ -#define OUI_ERICSSON_2 0x008037 /* Ericsson Group */ -#define OUI_BRIDGED 0x0080C2 /* Bridged Frame-Relay, RFC 2427 */ - /* and Bridged ATM, RFC 2684 */ -#define OUI_IEEE_802_1 0x0080C2 /* IEEE 802.1 Committee */ -#define OUI_ATM_FORUM 0x00A03E /* ATM Forum */ -#define OUI_EXTREME 0x00E02B /* Extreme EDP/ESRP */ -#define OUI_CABLE_BPDU 0x00E02F /* DOCSIS spanning tree BPDU */ -#define OUI_SIEMENS 0x080006 /* Siemens AG */ -#define OUI_APPLE_ATALK 0x080007 /* Appletalk */ -#define OUI_HP 0x080009 /* Hewlett-Packard */ - -/* - * Defined in packet-llc.c - */ -extern const value_string oui_vals[]; - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/packet.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/packet.h deleted file mode 100644 index 5061c565..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/packet.h +++ /dev/null @@ -1,422 +0,0 @@ -/* packet.h - * Definitions for packet disassembly structures and routines - * - * $Id: packet.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef __PACKET_H__ -#define __PACKET_H__ - -/* - * If defines formats to be used to print 64-bit integers, - * include it. - */ -#ifdef INTTYPES_H_DEFINES_FORMATS -#include -#endif - -#include "wiretap/wtap.h" -#include "proto.h" -#include "tvbuff.h" -#include "pint.h" -#include "to_str.h" -#include "value_string.h" -#include "column_info.h" -#include "frame_data.h" -#include "packet_info.h" -#include "column-utils.h" -#include "epan.h" -#include "tfs.h" - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#define hi_nibble(b) (((b) & 0xf0) >> 4) -#define lo_nibble(b) ((b) & 0x0f) - -/* Useful when you have an array whose size you can tell at compile-time */ -#define array_length(x) (sizeof x / sizeof x[0]) - -/* Check whether the "len" bytes of data starting at "offset" is - * entirely inside the captured data for this packet. */ -#define BYTES_ARE_IN_FRAME(offset, captured_len, len) \ - ((guint)(offset) + (guint)(len) > (guint)(offset) && \ - (guint)(offset) + (guint)(len) <= (guint)(captured_len)) - -/* To pass one of two strings, singular or plural */ -#define plurality(d,s,p) ((d) == 1 ? (s) : (p)) - -typedef struct _packet_counts { - gint sctp; - gint tcp; - gint udp; - gint icmp; - gint ospf; - gint gre; - gint netbios; - gint ipx; - gint vines; - gint other; - gint total; - gint arp; -} packet_counts; - -/** Number of packet counts. */ -#define PACKET_COUNTS_SIZE sizeof(packet_counts) / sizeof (gint) - -/* Types of character encodings */ -typedef enum { - CHAR_ASCII = 0, /* ASCII */ - CHAR_EBCDIC = 1 /* EBCDIC */ -} char_enc; - -extern void packet_init(void); -extern void packet_cleanup(void); - -/* Handle for dissectors you call directly or register with "dissector_add()". - This handle is opaque outside of "packet.c". */ -struct dissector_handle; -typedef struct dissector_handle *dissector_handle_t; - -/* Hash table for matching port numbers and dissectors; this is opaque - outside of "packet.c". */ -struct dissector_table; -typedef struct dissector_table *dissector_table_t; - -/* - * Dissector that returns nothing. - */ -typedef void (*dissector_t)(tvbuff_t *, packet_info *, proto_tree *); - -/* - * Dissector that returns: - * - * The amount of data in the protocol's PDU, if it was able to - * dissect all the data; - * - * 0, if the tvbuff doesn't contain a PDU for that protocol; - * - * The negative of the amount of additional data needed, if - * we need more data (e.g., from subsequent TCP segments) to - * dissect the entire PDU. - */ -typedef int (*new_dissector_t)(tvbuff_t *, packet_info *, proto_tree *); - -/** Type of a heuristic dissector, used in heur_dissector_add(). - * - * @param tvb the tv_buff with the (remaining) packet data - * @param pinfo the packet info of this packet (additional info) - * @param tree the protocol tree to be build or NULL - * @return TRUE if the packet was recognized by the sub-dissector (stop dissection here) - */ -typedef gboolean (*heur_dissector_t)(tvbuff_t *tvb, packet_info *pinfo, - proto_tree *tree); - -typedef void (*DATFunc) (const gchar *table_name, ftenum_t selector_type, - gpointer key, gpointer value, gpointer user_data); -typedef void (*DATFunc_handle) (const gchar *table_name, gpointer value, - gpointer user_data); -typedef void (*DATFunc_table) (const gchar *table_name, const gchar *ui_name, - gpointer user_data); - -/* Opaque structure - provides type checking but no access to components */ -typedef struct dtbl_entry dtbl_entry_t; - -extern dissector_handle_t dtbl_entry_get_handle (dtbl_entry_t *dtbl_entry); -extern dissector_handle_t dtbl_entry_get_initial_handle (dtbl_entry_t * entry); -extern void dissector_table_foreach_changed (const char *name, DATFunc func, - gpointer user_data); -extern void dissector_table_foreach (const char *name, DATFunc func, - gpointer user_data); -extern void dissector_all_tables_foreach_changed (DATFunc func, - gpointer user_data); -extern void dissector_table_foreach_handle(const char *name, DATFunc_handle func, - gpointer user_data); -extern void dissector_all_tables_foreach_table (DATFunc_table func, - gpointer user_data); - -/* a protocol uses the function to register a sub-dissector table */ -extern dissector_table_t register_dissector_table(const char *name, - const char *ui_name, ftenum_t type, int base); - -/* Find a dissector table by table name. */ -extern dissector_table_t find_dissector_table(const char *name); - -/* Get the UI name for a sub-dissector table, given its internal name */ -extern const char *get_dissector_table_ui_name(const char *name); - -/* Get the field type for values of the selector for a dissector table, - given the table's internal name */ -extern ftenum_t get_dissector_table_selector_type(const char *name); - -/* Get the base to use when displaying values of the selector for a - sub-dissector table, given the table's internal name */ -extern int get_dissector_table_base(const char *name); - -/* Add an entry to a uint dissector table. */ -extern void dissector_add(const char *abbrev, guint32 pattern, - dissector_handle_t handle); - -/* Delete the entry for a dissector in a uint dissector table - with a particular pattern. */ -extern void dissector_delete(const char *name, guint32 pattern, - dissector_handle_t handle); - -/* Change the entry for a dissector in a uint dissector table - with a particular pattern to use a new dissector handle. */ -extern void dissector_change(const char *abbrev, guint32 pattern, - dissector_handle_t handle); - -/* Reset an entry in a uint dissector table to its initial value. */ -extern void dissector_reset(const char *name, guint32 pattern); - -/* Look for a given value in a given uint dissector table and, if found, - call the dissector with the arguments supplied, and return TRUE, - otherwise return FALSE. */ -extern gboolean dissector_try_port(dissector_table_t sub_dissectors, - guint32 port, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); - -/* Look for a given value in a given uint dissector table and, if found, - return the dissector handle for that value. */ -extern dissector_handle_t dissector_get_port_handle( - dissector_table_t sub_dissectors, guint32 port); - -/* Add an entry to a string dissector table. */ -extern void dissector_add_string(const char *name, const gchar *pattern, - dissector_handle_t handle); - -/* Delete the entry for a dissector in a string dissector table - with a particular pattern. */ -extern void dissector_delete_string(const char *name, const gchar *pattern, - dissector_handle_t handle); - -/* Change the entry for a dissector in a string dissector table - with a particular pattern to use a new dissector handle. */ -extern void dissector_change_string(const char *name, gchar *pattern, - dissector_handle_t handle); - -/* Reset an entry in a string sub-dissector table to its initial value. */ -extern void dissector_reset_string(const char *name, const gchar *pattern); - -/* Look for a given string in a given dissector table and, if found, call - the dissector with the arguments supplied, and return TRUE, otherwise - return FALSE. */ -extern gboolean dissector_try_string(dissector_table_t sub_dissectors, - const gchar *string, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); - -/* Look for a given value in a given string dissector table and, if found, - return the dissector handle for that value. */ -extern dissector_handle_t dissector_get_string_handle( - dissector_table_t sub_dissectors, const gchar *string); - -/* Add a handle to the list of handles that *could* be used with this - table. That list is used by code in the UI. */ -extern void dissector_add_handle(const char *name, dissector_handle_t handle); - -/* List of "heuristic" dissectors (which get handed a packet, look at it, - and either recognize it as being for their protocol, dissect it, and - return TRUE, or don't recognize it and return FALSE) to be called - by another dissector. */ -typedef GSList *heur_dissector_list_t; - -/** A protocol uses this function to register a heuristic sub-dissector list. - * Call this in the parent dissectors proto_register function. - * - * @param name the name of this protocol - * @param list the list of heuristic sub-dissectors to be registered - */ -extern void register_heur_dissector_list(const char *name, - heur_dissector_list_t *list); - -/** Try all the dissectors in a given heuristic dissector list. This is done, - * until we find one that recognizes the protocol. - * Call this while the parent dissector running. - * - * @param sub_dissectors the sub-dissector list - * @param tvb the tv_buff with the (remaining) packet data - * @param pinfo the packet info of this packet (additional info) - * @param tree the protocol tree to be build or NULL - * @return TRUE if the packet was recognized by the sub-dissector (stop dissection here) - */ -extern gboolean dissector_try_heuristic(heur_dissector_list_t sub_dissectors, - tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); - -/** Add a sub-dissector to a heuristic dissector list. - * Call this in the proto_handoff function of the sub-dissector. - * - * @param name the name of the "parent" protocol, e.g. "tcp" - * @param dissector the sub-dissector to be registered - * @param proto the protocol id of the sub-dissector - */ -extern void heur_dissector_add(const char *name, heur_dissector_t dissector, - int proto); - -/** Remove a sub-dissector from a heuristic dissector list. - * Call this in the prefs_reinit function of the sub-dissector. - * - * @param name the name of the "parent" protocol, e.g. "tcp" - * @param dissector the sub-dissector to be unregistered - * @param proto the protocol id of the sub-dissector - */ -extern void heur_dissector_delete(const char *name, heur_dissector_t dissector, int proto); - -/* Register a dissector. */ -extern void register_dissector(const char *name, dissector_t dissector, - int proto); -extern void new_register_dissector(const char *name, new_dissector_t dissector, - int proto); - -/* Get the short name of the protocol for a dissector handle. */ -extern const char *dissector_handle_get_short_name(dissector_handle_t handle); - -/* Get the index of the protocol for a dissector handle. */ -extern int dissector_handle_get_protocol_index(dissector_handle_t handle); - -/* Find a dissector by name. */ -extern dissector_handle_t find_dissector(const char *name); - -/* Create an anonymous handle for a dissector. */ -extern dissector_handle_t create_dissector_handle(dissector_t dissector, - int proto); -extern dissector_handle_t new_create_dissector_handle(new_dissector_t dissector, - int proto); - -/* Call a dissector through a handle and if no dissector was found - * pass if over to the "data" dissector instead. - * - * @param handle The dissector to call. - * @param tvb The buffer to dissect. - * @param pinfo Packet Info. - * @param tree The protocol tree. - * @return If the protocol for that handle isn't enabled call the data - * dissector. Otherwise, if the handle refers to a new-style - * dissector, call the dissector and return its return value, otherwise call - * it and return the length of the tvbuff pointed to by the argument. - */ -extern int call_dissector(dissector_handle_t handle, tvbuff_t *tvb, - packet_info *pinfo, proto_tree *tree); - -/* Call a dissector through a handle but if no dissector was found - * just return 0 and do not call the "data" dissector instead. - * - * @param handle The dissector to call. - * @param tvb The buffer to dissect. - * @param pinfo Packet Info. - * @param tree The protocol tree. - * @return If the protocol for that handle isn't enabled, return 0 without - * calling the dissector. Otherwise, if the handle refers to a new-style - * dissector, call the dissector and return its return value, otherwise call - * it and return the length of the tvbuff pointed to by the argument. - */ -extern int call_dissector_only(dissector_handle_t handle, tvbuff_t *tvb, - packet_info *pinfo, proto_tree *tree); - -/* Do all one-time initialization. */ -extern void dissect_init(void); - -extern void dissect_cleanup(void); - -/* - * Given a tvbuff, and a length from a packet header, adjust the length - * of the tvbuff to reflect the specified length. - */ -extern void set_actual_length(tvbuff_t *tvb, guint specified_len); - -/* Allow protocols to register "init" routines, which are called before - we make a pass through a capture file and dissect all its packets - (e.g., when we read in a new capture file, or run a "filter packets" - or "colorize packets" pass over the current capture file). */ -extern void register_init_routine(void (*func)(void)); - -/* Initialize all data structures used for dissection. */ -extern void init_dissection(void); - -/* Free data structures allocated for dissection. */ -extern void cleanup_dissection(void); - -/* Allow protocols to register a "cleanup" routine to be - * run after the initial sequential run through the packets. - * Note that the file can still be open after this; this is not - * the final cleanup. */ -extern void register_postseq_cleanup_routine(void (*func)(void)); - -/* Call all the registered "postseq_cleanup" routines. */ -extern void postseq_cleanup_all_protocols(void); - -/* Allow dissectors to register a "final_registration" routine - * that is run like the proto_register_XXX() routine, but the end - * end of the epan_init() function; that is, *after* all other - * subsystems, liked dfilters, have finished initializing. This is - * useful for dissector registration routines which need to compile - * display filters. dfilters can't initialize itself until all protocols - * have registereed themselvs. */ -extern void -register_final_registration_routine(void (*func)(void)); - -/* Call all the registered "final_registration" routines. */ -extern void -final_registration_all_protocols(void); - -/* - * Add a new data source to the list of data sources for a frame, given - * the tvbuff for the data source and its name. - */ -extern void add_new_data_source(packet_info *pinfo, tvbuff_t *tvb, - const char *name); - -/* - * Free up a frame's list of data sources. - */ -extern void free_data_sources(packet_info *pinfo); - -/* - * Dissectors should never modify the packet data. - */ -extern void dissect_packet(epan_dissect_t *edt, - union wtap_pseudo_header *pseudo_header, const guchar *pd, - frame_data *fd, column_info *cinfo); - -/* These functions are in packet-ethertype.c */ -extern void capture_ethertype(guint16 etype, const guchar *pd, int offset, - int len, packet_counts *ld); -extern void ethertype(guint16 etype, tvbuff_t *tvb, int offset_after_ethertype, - packet_info *pinfo, proto_tree *tree, proto_tree *fh_tree, - int etype_id, int trailer_id, int fcs_len); - -/* - * Dump layer/selector/dissector records in a fashion similar to the - * proto_registrar_dump_* routines. - */ -extern void dissector_dump_decodes(void); - -/* - * post dissectors are to be called by packet-frame.c after every other - * dissector has been called. - */ -extern void register_postdissector(dissector_handle_t); -extern void call_all_postdissectors(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* packet.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/packet_info.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/packet_info.h deleted file mode 100644 index 3902be51..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/packet_info.h +++ /dev/null @@ -1,184 +0,0 @@ -/* packet_info.h - * Definitions for packet info structures and routines - * - * $Id: packet_info.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __PACKET_INFO_H__ -#define __PACKET_INFO_H__ - -#include "frame_data.h" -#include "tvbuff.h" -#include "address.h" - -#define P2P_DIR_UNKNOWN -1 -#define P2P_DIR_SENT 0 -#define P2P_DIR_RECV 1 - -#define PINFO_SOF_FIRST_FRAME 0x1 -#define PINFO_SOF_SOFF 0x2 -#define PINFO_EOF_LAST_FRAME 0x80 -#define PINFO_EOF_INVALID 0x40 -#define MAX_NUMBER_OF_PPIDS 2 - -typedef struct _packet_info { - const char *current_proto; /* name of protocol currently being dissected */ - column_info *cinfo; /* Column formatting information */ - frame_data *fd; - union wtap_pseudo_header *pseudo_header; - GSList *data_src; /* Frame data sources */ - address dl_src; /* link-layer source address */ - address dl_dst; /* link-layer destination address */ - address net_src; /* network-layer source address */ - address net_dst; /* network-layer destination address */ - address src; /* source address (net if present, DL otherwise )*/ - address dst; /* destination address (net if present, DL otherwise )*/ - guint32 ethertype; /* Ethernet Type Code, if this is an Ethernet packet */ - guint32 ipproto; /* IP protocol, if this is an IP packet */ - guint32 ipxptype; /* IPX packet type, if this is an IPX packet */ - circuit_type ctype; /* type of circuit, for protocols with a VC identifier */ - guint32 circuit_id; /* circuit ID, for protocols with a VC identifier */ - const char *noreassembly_reason; /* reason why reassembly wasn't done, if any */ - gboolean fragmented; /* TRUE if the protocol is only a fragment */ - gboolean in_error_pkt; /* TRUE if we're inside an {ICMP,CLNP,...} error packet */ - port_type ptype; /* type of the following two port numbers */ - guint32 srcport; /* source port */ - guint32 destport; /* destination port */ - guint32 match_port; /* matched port for calling subdissector from table */ - const char *match_string; /* matched string for calling subdissector from table */ - guint16 can_desegment; /* >0 if this segment could be desegmented. - A dissector that can offer this API (e.g. - TCP) sets can_desegment=2, then - can_desegment is decremented by 1 each time - we pass to the next subdissector. Thus only - the dissector immediately above the - protocol which sets the flag can use it*/ - guint16 saved_can_desegment; /* Value of can_desegment before current - dissector was called. Supplied so that - dissectors for proxy protocols such as - SOCKS can restore it, allowing the - dissectors that they call to use the - TCP dissector's desegmentation (SOCKS - just retransmits TCP segments once it's - finished setting things up, so the TCP - desegmentor can desegment its payload). */ - int desegment_offset; /* offset to stuff needing desegmentation */ -#define DESEGMENT_ONE_MORE_SEGMENT 0x0fffffff -#define DESEGMENT_UNTIL_FIN 0x0ffffffe - guint32 desegment_len; /* requested desegmentation additional length - or - DESEGMENT_ONE_MORE_SEGMENT: - Desegment one more full segment - (warning! only partially implemented) - DESEGMENT_UNTIL_FIN: - Desgment all data for this tcp session - until the FIN segment. - */ - guint16 want_pdu_tracking; /* >0 if the subdissector has specified - a value in 'bytes_until_next_pdu'. - When a dissector detects that the next PDU - will start beyond the start of the next - segment, it can set this value to 2 - and 'bytes_until_next_pdu' to the number of - bytes beyond the next segment where the - next PDU starts. - - If the protocol dissector below this - one is capable of PDU tracking it can - use this hint to detect PDUs that starts - unaligned to the segment boundaries. - The TCP dissector is using this hint from - (some) protocols to detect when a new PDU - starts in the middle of a tcp segment. - - There is intelligence in the glue between - dissector layers to make sure that this - request is only passed down to the protocol - immediately below the current one and not - any further. - */ - guint32 bytes_until_next_pdu; - - - int iplen; /* total length of IP packet */ - int iphdrlen; /* length of IP header */ - int p2p_dir; /* Packet was captured as an - outbound (P2P_DIR_SENT) - inbound (P2P_DIR_RECV) - unknown (P2P_DIR_UNKNOWN) */ - guint16 oxid; /* next 2 fields reqd to identify fibre */ - guint16 rxid; /* channel conversations */ - guint8 r_ctl; /* R_CTL field in Fibre Channel Protocol */ - guint8 sof_eof; /* FC's SOF/EOF encoding passed to FC decoder - * Bit 7 set if Last frame in sequence - * Bit 6 set if invalid frame content - * Bit 2 set if SOFf - * Bit 1 set if first frame in sequence - */ - guint16 src_idx; /* Source port index (Cisco MDS-specific) */ - guint16 dst_idx; /* Dest port index (Cisco MDS-specific) */ - guint16 vsan; /* Fibre channel/Cisco MDS-specific */ - - /* Extra data for DCERPC handling and tracking of context ids */ - guint16 dcectxid; /* Context ID (DCERPC-specific) */ - int dcetransporttype; /* Transport type - * Value -1 means "not a DCERPC packet" - */ - guint16 dcetransportsalt; /* fid: if transporttype==DCE_CN_TRANSPORT_SMBPIPE */ - - /* Extra data for handling of decryption of GSSAPI wrapped tvbuffs. - Caller sets decrypt_gssapi_tvb if this service is requested. - If gssapi_encrypted_tvb is NULL, then the rest of the tvb data following - the gssapi blob itself is decrypted othervise the gssapi_encrypted_tvb - tvb will be decrypted (DCERPC has the data before the gssapi blob) - If, on return, gssapi_data_encrypted is FALSE, the wrapped tvbuff - was signed (i.e., an encrypted signature was present, to check - whether the data was modified by a man in the middle) but not sealed - (i.e., the data itself wasn't encrypted). - */ -#define DECRYPT_GSSAPI_NORMAL 1 -#define DECRYPT_GSSAPI_DCE 2 - guint16 decrypt_gssapi_tvb; - tvbuff_t *gssapi_wrap_tvb; - tvbuff_t *gssapi_encrypted_tvb; - tvbuff_t *gssapi_decrypted_tvb; - gboolean gssapi_data_encrypted; - - guint32 ppid[MAX_NUMBER_OF_PPIDS]; /* The first NUMBER_OF_PPIDS PPIDS which are present - * in the SCTP packet - */ - void *private_data; /* pointer to data passed from one dissector to another */ - GString *layer_names; /* layers of each protocol */ - guint16 link_number; - guint8 annex_a_used; - guint16 profinet_type; /* the type of PROFINET packet (0: not a PROFINET packet) */ - void *profinet_conv; /* the PROFINET conversation data (NULL: not a PROFINET packet) */ - void *usb_conv_info; - void *tcp_tree; /* proto_tree for the tcp layer */ - - const char *dcerpc_procedure_name; /* Used by PIDL to store the name of the current dcerpc procedure */ - - struct _sccp_msg_info_t* sccp_info; - guint16 clnp_srcref; /* clnp/cotp source reference (can't use srcport, this would confuse tpkt) */ - guint16 clnp_dstref; /* clnp/cotp destination reference (can't use dstport, this would confuse tpkt) */ -} packet_info; - -#endif /* __PACKET_INFO_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/pint.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/pint.h deleted file mode 100644 index f947a04e..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/pint.h +++ /dev/null @@ -1,113 +0,0 @@ -/* pint.h - * Definitions for extracting and translating integers safely and portably - * via pointers. - * - * $Id: pint.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __PINT_H__ -#define __PINT_H__ - -#include - -/* Pointer versions of g_ntohs and g_ntohl. Given a pointer to a member of a - * byte array, returns the value of the two or four bytes at the pointer. - * The pletoh[sl] versions return the little-endian representation. - */ - -#define pntohs(p) ((guint16) \ - ((guint16)*((const guint8 *)(p)+0)<<8| \ - (guint16)*((const guint8 *)(p)+1)<<0)) - -#define pntoh24(p) ((guint32)*((const guint8 *)(p)+0)<<16| \ - (guint32)*((const guint8 *)(p)+1)<<8| \ - (guint32)*((const guint8 *)(p)+2)<<0) - -#define pntohl(p) ((guint32)*((const guint8 *)(p)+0)<<24| \ - (guint32)*((const guint8 *)(p)+1)<<16| \ - (guint32)*((const guint8 *)(p)+2)<<8| \ - (guint32)*((const guint8 *)(p)+3)<<0) -#define pntoh64(p) ((guint64)*((const guint8 *)(p)+0)<<56| \ - (guint64)*((const guint8 *)(p)+1)<<48| \ - (guint64)*((const guint8 *)(p)+2)<<40| \ - (guint64)*((const guint8 *)(p)+3)<<32| \ - (guint64)*((const guint8 *)(p)+4)<<24| \ - (guint64)*((const guint8 *)(p)+5)<<16| \ - (guint64)*((const guint8 *)(p)+6)<<8| \ - (guint64)*((const guint8 *)(p)+7)<<0) - - -#define pletohs(p) ((guint16) \ - ((guint16)*((const guint8 *)(p)+1)<<8| \ - (guint16)*((const guint8 *)(p)+0)<<0)) - -#define pletoh24(p) ((guint32)*((const guint8 *)(p)+2)<<16| \ - (guint32)*((const guint8 *)(p)+1)<<8| \ - (guint32)*((const guint8 *)(p)+0)<<0) - -#define pletohl(p) ((guint32)*((const guint8 *)(p)+3)<<24| \ - (guint32)*((const guint8 *)(p)+2)<<16| \ - (guint32)*((const guint8 *)(p)+1)<<8| \ - (guint32)*((const guint8 *)(p)+0)<<0) -#define pletoh64(p) ((guint64)*((const guint8 *)(p)+7)<<56| \ - (guint64)*((const guint8 *)(p)+6)<<48| \ - (guint64)*((const guint8 *)(p)+5)<<40| \ - (guint64)*((const guint8 *)(p)+4)<<32| \ - (guint64)*((const guint8 *)(p)+3)<<24| \ - (guint64)*((const guint8 *)(p)+2)<<16| \ - (guint64)*((const guint8 *)(p)+1)<<8| \ - (guint64)*((const guint8 *)(p)+0)<<0) - -/* Pointer routines to put items out in a particular byte order. - * These will work regardless of the byte alignment of the pointer. - */ - -#define phtons(p, v) \ - { \ - ((guint8*)(p))[0] = (guint8)((v) >> 8); \ - ((guint8*)(p))[1] = (guint8)((v) >> 0); \ - } - -#define phtonl(p, v) \ - { \ - ((guint8*)(p))[0] = (guint8)((v) >> 24); \ - ((guint8*)(p))[1] = (guint8)((v) >> 16); \ - ((guint8*)(p))[2] = (guint8)((v) >> 8); \ - ((guint8*)(p))[3] = (guint8)((v) >> 0); \ - } - - -/* Macros to byte-swap 32-bit and 16-bit quantities. */ -#define BSWAP32(x) \ - ((((x)&0xFF000000)>>24) | \ - (((x)&0x00FF0000)>>8) | \ - (((x)&0x0000FF00)<<8) | \ - (((x)&0x000000FF)<<24)) -#define BSWAP16(x) \ - ((((x)&0xFF00)>>8) | \ - (((x)&0x00FF)<<8)) - -/* Turn host-byte-order values into little-endian values. */ -#define htoles(s) GUINT16_TO_LE(s) -#define htolel(l) GUINT32_TO_LE(l) - -#endif /* PINT_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/plugins.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/plugins.h deleted file mode 100644 index 100e5805..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/plugins.h +++ /dev/null @@ -1,58 +0,0 @@ -/* plugins.h - * definitions for plugins structures - * - * $Id: plugins.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1999 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __PLUGINS_H__ -#define __PLUGINS_H__ - -#include -#include - -#include "packet.h" - -typedef struct _plugin { - GModule *handle; /* handle returned by dlopen */ - gchar *name; /* plugin name */ - gchar *version; /* plugin version */ - void (*register_protoinfo)(void); /* routine to call to register protocol information */ - void (*reg_handoff)(void); /* routine to call to register dissector handoff */ - void (*register_tap_listener)(void); /* routine to call to register tap listener */ - void (*register_wtap_module)(void); /* routine to call to register a wiretap module */ - void (*register_codec_module)(void); /* routine to call to register a codec */ - struct _plugin *next; /* forward link */ -} plugin; - -WS_VAR_IMPORT plugin *plugin_list; - -extern void init_plugins(void); -extern void register_all_plugin_registrations(void); -extern void register_all_plugin_handoffs(void); -extern void register_all_plugin_tap_listeners(void); -extern void register_all_wiretap_modules(void); -extern void register_all_codecs(void); - -/* get the personal plugin dir */ -/* Return value is g_malloced so the caller should g_free() it. */ -extern char *get_plugins_pers_dir(void); - -#endif /* __PLUGINS_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ppptypes.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ppptypes.h deleted file mode 100644 index 64bbcb34..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ppptypes.h +++ /dev/null @@ -1,158 +0,0 @@ -/* ppptypes.h - * Defines PPP packet types. - * - * $Id: ppptypes.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __PPPTYPES_H__ -#define __PPPTYPES_H__ - -/* Protocol types, from Linux "ppp_defs.h" and - - http://www.iana.org/assignments/ppp-numbers - - */ -#define PPP_PADDING 0x1 /* Padding Protocol */ -#define PPP_ROHC_SCID 0x3 /* ROHC small-CID */ -#define PPP_ROHC_LCID 0x5 /* ROHC large-CID */ -#define PPP_IP 0x21 /* Internet Protocol */ -#define PPP_OSI 0x23 /* OSI Protocol */ -#define PPP_DEC4 0x25 /* DECnet Phase IV */ -#define PPP_AT 0x29 /* AppleTalk Protocol */ -#define PPP_IPX 0x2b /* IPX protocol */ -#define PPP_VJC_COMP 0x2d /* VJ compressed TCP */ -#define PPP_VJC_UNCOMP 0x2f /* VJ uncompressed TCP */ -#define PPP_BPDU 0x31 /* Bridging PDU (spanning tree BPDU?) */ -#define PPP_ST 0x33 /* Stream Protocol (ST-II) */ -#define PPP_VINES 0x35 /* Banyan Vines */ -#define PPP_AT_EDDP 0x39 /* AppleTalk EDDP */ -#define PPP_AT_SB 0x3b /* AppleTalk SmartBuffered */ -#define PPP_MP 0x3d /* Multilink PPP */ -#define PPP_NB 0x3f /* NETBIOS Framing */ -#define PPP_CISCO 0x41 /* Cisco Systems */ -#define PPP_ASCOM 0x43 /* Ascom Timeplex */ -#define PPP_LBLB 0x45 /* Fujitsu Link Backup and Load Balancing */ -#define PPP_RL 0x47 /* DCA Remote Lan */ -#define PPP_SDTP 0x49 /* Serial Data Transport Protocol */ -#define PPP_LLC 0x4b /* SNA over LLC */ -#define PPP_SNA 0x4d /* SNA */ -#define PPP_IPV6HC 0x4f /* IPv6 Header Compression */ -#define PPP_KNX 0x51 /* KNX Bridging Data */ -#define PPP_ENCRYPT 0x53 /* Encryption */ -#define PPP_ILE 0x55 /* Individual Link Encryption */ -#define PPP_IPV6 0x57 /* Internet Protocol Version 6 */ -#define PPP_MUX 0x59 /* PPP Multiplexing */ -#define PPP_RTP_FH 0x61 /* RTP IPHC Full Header */ -#define PPP_RTP_CTCP 0x63 /* RTP IPHC Compressed TCP */ -#define PPP_RTP_CNTCP 0x65 /* RTP IPHC Compressed Non TCP */ -#define PPP_RTP_CUDP8 0x67 /* RTP IPHC Compressed UDP 8 */ -#define PPP_RTP_CRTP8 0x69 /* RTP IPHC Compressed RTP 8 */ -#define PPP_STAMPEDE 0x6f /* Stampede Bridging */ -#define PPP_MPPLUS 0x73 /* MP+ Protocol */ -#define PPP_NTCITS_IPI 0xc1 /* NTCITS IPI */ -#define PPP_ML_SLCOMP 0xfb /* single link compression in multilink */ -#define PPP_COMP 0xfd /* compressed packet */ -#define PPP_STP_HELLO 0x0201 /* 802.1d Hello Packet */ -#define PPP_IBM_SR 0x0203 /* IBM Source Routing BPDU */ -#define PPP_DEC_LB 0x0205 /* DEC LANBridge100 Spanning Tree */ -#define PPP_CDP 0x0207 /* Cisco Discovery Protocol */ -#define PPP_NETCS 0x0209 /* Netcs Twin Routing */ -#define PPP_STP 0x020b /* Scheduled Transfer Protocol */ -#define PPP_EDP 0x020d /* Extreme Discovery Protocol */ -#define PPP_OSCP 0x0211 /* Optical Supervisory Channel Protocol */ -#define PPP_OSCP2 0x0213 /* Optical Supervisory Channel Protocol */ -#define PPP_LUXCOM 0x0231 /* Luxcom */ -#define PPP_SIGMA 0x0233 /* Sigma Network Systems */ -#define PPP_ACSP 0x0235 /* Apple Client Server Protocol */ -#define PPP_MPLS_UNI 0x0281 /* MPLS Unicast */ -#define PPP_MPLS_MULTI 0x0283 /* MPLS Multicast */ -#define PPP_P12844 0x0285 /* IEEE p1284.4 standard - data packets */ -#define PPP_ETSI 0x0287 /* ETSI TETRA Networks Procotol Type 1 */ -#define PPP_MFTP 0x0289 /* Multichannel Flow Treatment Protocol */ -#define PPP_RTP_CTCPND 0x2063 /* RTP IPHC Compressed TCP No Delta */ -#define PPP_RTP_CS 0x2065 /* RTP IPHC Context State */ -#define PPP_RTP_CUDP16 0x2067 /* RTP IPHC Compressed UDP 16 */ -#define PPP_RTP_CRDP16 0x2069 /* RTP IPHC Compressed RTP 16 */ -#define PPP_CCCP 0x4001 /* Cray Communications Control Protocol */ -#define PPP_CDPD_MNRP 0x4003 /* CDPD Mobile Network Registration Protocol */ -#define PPP_EXPANDAP 0x4005 /* Expand accelarator protocol */ -#define PPP_ODSICP 0x4007 /* ODSICP NCP */ -#define PPP_DOCSIS 0x4009 /* DOCSIS DLL */ -#define PPP_LZS 0x4021 /* Stacker LZS */ -#define PPP_REFTEK 0x4023 /* RefTek Protocol */ -#define PPP_FC 0x4025 /* Fibre Channel */ -#define PPP_EMIT 0x4027 /* EMIT Protocols */ -#define PPP_IPCP 0x8021 /* IP Control Protocol */ -#define PPP_OSICP 0x8023 /* OSI Control Protocol */ -#define PPP_XNSIDPCP 0x8025 /* Xerox NS IDP Control Protocol */ -#define PPP_DECNETCP 0x8027 /* DECnet Phase IV Control Protocol */ -#define PPP_ATCP 0x8029 /* AppleTalk Control Protocol */ -#define PPP_IPXCP 0x802b /* IPX Control Protocol */ -#define PPP_BRIDGENCP 0x8031 /* Bridging NCP */ -#define PPP_SPCP 0x8033 /* Stream Protocol Control Protocol */ -#define PPP_BVCP 0x8035 /* Banyan Vines Control Protocol */ -#define PPP_MLCP 0x803d /* Multi-Link Control Protocol */ -#define PPP_NBCP 0x803f /* NETBIOS Framing Control Protocol */ -#define PPP_CISCOCP 0x8041 /* Cisco Systems Control Protocol */ -#define PPP_ASCOMCP 0x8043 /* Ascom Timeplex Control Protocol (?) */ -#define PPP_LBLBCP 0x8045 /* Fujitsu LBLB Control Protocol */ -#define PPP_RLNCP 0x8047 /* DCA Remote Lan Network Control Protocol */ -#define PPP_SDCP 0x8049 /* Serial Data Control Protocol */ -#define PPP_LLCCP 0x804b /* SNA over LLC Control Protocol */ -#define PPP_SNACP 0x804d /* SNA Control Protocol */ -#define PPP_KNXCP 0x8051 /* KNX Bridging Control Protocol */ -#define PPP_ECP 0x8053 /* Encryption Control Protocol */ -#define PPP_ILECP 0x8055 /* Individual Encryption Control Protocol */ -#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */ -#define PPP_MUXCP 0x8059 /* PPPMux Control Protocol */ -#define PPP_STAMPEDECP 0x806f /* Stampede Bridging Control Protocol */ -#define PPP_MPPCP 0x8073 /* MP+ Contorol Protocol */ -#define PPP_IPICP 0x80c1 /* NTCITS IPI Control Protocol */ -#define PPP_SLCC 0x80fb /* single link compression in multilink control */ -#define PPP_CCP 0x80fd /* Compression Control Protocol */ -#define PPP_CDPCP 0x8207 /* Cisco Discovery Protocol Control Protocol */ -#define PPP_NETCSCP 0x8209 /* Netcs Twin Routing */ -#define PPP_STPCP 0x820b /* STP - Control Protocol */ -#define PPP_EDPCP 0x820d /* Extreme Discovery Protocol Control Protocol */ -#define PPP_ACSPC 0x8235 /* Apple Client Server Protocol Control */ -#define PPP_MPLSCP 0x8281 /* MPLS Control Protocol */ -#define PPP_P12844CP 0x8285 /* IEEE p1284.4 standard - Protocol Control */ -#define PPP_ETSICP 0x8287 /* ETSI TETRA TNP1 Control Protocol */ -#define PPP_MFTPCP 0x8287 /* Multichannel Flow Treatment Protocol */ -#define PPP_LCP 0xc021 /* Link Control Protocol */ -#define PPP_PAP 0xc023 /* Password Authentication Protocol */ -#define PPP_LQR 0xc025 /* Link Quality Report protocol */ -#define PPP_SPAP 0xc027 /* Shiva Password Authentication Protocol */ -#define PPP_CBCP 0xc029 /* CallBack Control Protocol */ -#define PPP_BACP 0xc02b /* Bandwidth Allocation Control Protocol */ -#define PPP_BAP 0xc02d /* Bandwidth Allocation Protocol */ -#define PPP_CONTCP 0xc081 /* Container Control Protocol */ -#define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */ -#define PPP_RSAAP 0xc225 /* RSA Authentication Protocol */ -#define PPP_EAP 0xc227 /* Extensible Authentication Protocol */ -#define PPP_SIEP 0xc229 /* Mitsubishi Security Information Exchange Protocol*/ -#define PPP_SBAP 0xc26f /* Stampede Bridging Authorization Protocol */ -#define PPP_PRPAP 0x281 /* Proprietary Authentication Protocol */ -#define PPP_PRPAP2 0x283 /* Proprietary Authentication Protocol */ -#define PPP_PRPNIAP 0x481 /* Proprietary Node ID Authentication Protocol */ - -#endif /* ppptypes.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/prefs-int.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/prefs-int.h deleted file mode 100644 index 3f54c931..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/prefs-int.h +++ /dev/null @@ -1,111 +0,0 @@ -/* prefs-int.h - * Definitions for implementation of preference handling routines; - * used by "friends" of the preferences type. - * - * $Id: prefs-int.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __PREFS_INT_H__ -#define __PREFS_INT_H__ - -struct pref_module { - const char *name; /* name of module */ - const char *title; /* title of module (displayed in preferences list) */ - const char *description;/* Description of module (displayed in preferences notebook) */ - void (*apply_cb)(void); /* routine to call when preferences applied */ - GList *prefs; /* list of its preferences */ - emem_tree_t *submodules;/* list of its submodules */ - int numprefs; /* number of non-obsolete preferences */ - gboolean prefs_changed; /* if TRUE, a preference has changed since we last checked */ - gboolean obsolete; /* if TRUE, this is a module that used to - exist but no longer does */ -}; - -/* - * Module used for protocol preferences. - * With MSVC and a libwireshark.dll, we need a special declaration. - */ -WS_VAR_IMPORT module_t *protocols_module; - -/* - * PREF_OBSOLETE is used for preferences that a module used to support - * but no longer supports; we give different error messages for them. - */ -typedef enum { - PREF_UINT, - PREF_BOOL, - PREF_ENUM, - PREF_STRING, - PREF_RANGE, - PREF_STATIC_TEXT, - PREF_UAT, - PREF_OBSOLETE -} pref_type_t; - -struct preference { - const char *name; /* name of preference */ - const char *title; /* title to use in GUI */ - const char *description; /* human-readable description of preference */ - int ordinal; /* ordinal number of this preference */ - pref_type_t type; /* type of that preference */ - union { - guint *uint; - gboolean *boolp; - gint *enump; - const char **string; - range_t **range; - void* uat; - } varp; /* pointer to variable storing the value */ - union { - guint uint; - gboolean boolval; - gint enumval; - char *string; - range_t *range; - } saved_val; /* original value, when editing from the GUI */ - union { - guint base; /* input/output base, for PREF_UINT */ - guint32 max_value; /* maximum value of a range */ - struct { - const enum_val_t *enumvals; /* list of name & values */ - gboolean radio_buttons; /* TRUE if it should be shown as - radio buttons rather than as an - option menu or combo box in - the preferences tab */ - } enum_info; /* for PREF_ENUM */ - } info; /* display/text file information */ - void *control; /* handle for GUI control for this preference */ -}; - -gint find_val_for_string(const char *needle, const enum_val_t *haystack, - gint default_value); - - -/* read_prefs_file: read in a generic config file and do a callback to */ -/* pref_set_pair_fct() for every key/value pair found */ -typedef prefs_set_pref_e (*pref_set_pair_cb) (gchar *key, gchar *value, void *private_data); - -int -read_prefs_file(const char *pf_path, FILE *pf, pref_set_pair_cb pref_set_pair_fct, void *private_data); - - - -#endif /* prefs-int.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/prefs.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/prefs.h deleted file mode 100644 index 3f2ab2c9..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/prefs.h +++ /dev/null @@ -1,426 +0,0 @@ -/* prefs.h - * Definitions for preference handling routines - * - * $Id: prefs.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __PREFS_H__ -#define __PREFS_H__ - -#include - -#include "color.h" - -#include - -#define PR_DEST_CMD 0 -#define PR_DEST_FILE 1 - -#define DEF_WIDTH 750 -#define DEF_HEIGHT 550 - -#define MAX_VAL_LEN 1024 - -#define RTP_PLAYER_DEFAULT_VISIBLE 4 - -/* only GTK1 *or* GTK2 font_name should be used */ -/* (we need to keep both in the preferences file but will only use the one suitable for the programs GTK version used) */ -#if GTK_MAJOR_VERSION < 2 -#define PREFS_GUI_FONT_NAME gui_font_name1 -#else -#define PREFS_GUI_FONT_NAME gui_font_name2 -#endif - -/* - * Convert a string listing name resolution types to a bitmask of - * those types. - * - * Set "*name_resolve" to the bitmask, and return '\0', on success; - * return the bad character in the string on error. - */ -char string_to_name_resolve(char *string, guint32 *name_resolve); - -/* - * Modes for the starting directory in File Open dialogs. - */ -#define FO_STYLE_LAST_OPENED 0 /* start in last directory we looked at */ -#define FO_STYLE_SPECIFIED 1 /* start in specified directory */ - -/* - * Toolbar styles. - */ -#define TB_STYLE_ICONS 0 -#define TB_STYLE_TEXT 1 -#define TB_STYLE_BOTH 2 - -/* - * Types of layout of summary/details/hex panes. - */ -typedef enum { - layout_unused, /* entry currently unused */ - layout_type_5, - layout_type_2, - layout_type_1, - layout_type_4, - layout_type_3, - layout_type_6, - layout_type_max -} layout_type_e; - -/* - * Types of pane. - */ -typedef enum { - layout_pane_content_none, - layout_pane_content_plist, - layout_pane_content_pdetails, - layout_pane_content_pbytes -} layout_pane_content_e; - -/* - * open console behaviour (win32 only) - */ -typedef enum { - console_open_never, - console_open_auto, - console_open_always -} console_open_e; - - -typedef struct _e_prefs { - gint pr_format; - gint pr_dest; - gchar *pr_file; - gchar *pr_cmd; - GList *col_list; - gint num_cols; - color_t st_client_fg, st_client_bg, st_server_fg, st_server_bg; - gboolean gui_scrollbar_on_right; - gboolean gui_plist_sel_browse; - gboolean gui_ptree_sel_browse; - gboolean gui_altern_colors; - gboolean filter_toolbar_show_in_statusbar; - gint gui_ptree_line_style; - gint gui_ptree_expander_style; - gboolean gui_hex_dump_highlight_style; - gint gui_toolbar_main_style; - gchar *gui_font_name1; - gchar *gui_font_name2; - color_t gui_marked_fg; - color_t gui_marked_bg; - gchar *gui_colorized_fg; - gchar *gui_colorized_bg; - gboolean gui_geometry_save_position; - gboolean gui_geometry_save_size; - gboolean gui_geometry_save_maximized; - console_open_e gui_console_open; - guint gui_recent_files_count_max; - guint gui_fileopen_style; - gchar *gui_fileopen_dir; - guint gui_fileopen_preview; - gboolean gui_ask_unsaved; - gboolean gui_find_wrap; - gboolean gui_use_pref_save; - gchar *gui_webbrowser; - gchar *gui_window_title; - layout_type_e gui_layout_type; - layout_pane_content_e gui_layout_content_1; - layout_pane_content_e gui_layout_content_2; - layout_pane_content_e gui_layout_content_3; - gint console_log_level; - guint32 name_resolve; - gint name_resolve_concurrency; - gchar *capture_device; - gchar *capture_devices_descr; - gchar *capture_devices_hide; - gboolean capture_prom_mode; - gboolean capture_real_time; - gboolean capture_auto_scroll; - gboolean capture_show_info; - guint rtp_player_max_visible; -} e_prefs; - -WS_VAR_IMPORT e_prefs prefs; - -/* - * Routines to let modules that have preference settings register - * themselves by name, and to let them register preference settings - * by name. - */ -struct pref_module; - -typedef struct pref_module module_t; - -/** Sets up memory used by proto routines. Called at program startup */ -extern void prefs_init(void); - -/** Reset preferences to default values. Called at profile change */ -extern void prefs_reset(void); - -/** Frees memory used by proto routines. Called at program shutdown */ -extern void prefs_cleanup(void); - -/* - * Register a module that will have preferences. - * Specify the module under which to register it or NULL to register it - * at the top level, the name used for the module in the preferences file, - * the title used in the tab for it in a preferences dialog box, and a - * routine to call back when we apply the preferences. - * - * This should not be used for dissector preferences; - * "prefs_register_protocol()" should be used for that, so that the - * preferences go under the "Protocols" subtree, and so that the - * name is the protocol name specified at the "proto_register_protocol()" - * call so that the "Protocol Properties..." menu item works. - */ -extern module_t *prefs_register_module(module_t *parent, const char *name, - const char *title, const char *description, void (*apply_cb)(void)); - -/* - * Register a subtree that will have modules under it. - * Specify the module under which to register it or NULL to register it - * at the top level and the title used in the tab for it in a preferences - * dialog box. - */ -extern module_t *prefs_register_subtree(module_t *parent, const char *title, - const char *description); - -/* - * Register that a protocol has preferences. - */ -extern module_t *prefs_register_protocol(int id, void (*apply_cb)(void)); - -/* - * Register that a protocol has preferences and group it under a single - * subtree - */ -#define PREFERENCE_GROUPING -extern module_t *prefs_register_protocol_subtree(const char *subtree, int id, - void (*apply_cb)(void)); - -/* - * Register that a protocol used to have preferences but no longer does, - * by creating an "obsolete" module for it. - */ -extern module_t *prefs_register_protocol_obsolete(int id); - -/* - * Callback function for module list scanners. - */ -typedef guint (*module_cb)(module_t *module, gpointer user_data); - -/* - * Returns TRUE if module has any submodules - */ -extern gboolean prefs_module_has_submodules(module_t *module); - -/* - * Call a callback function, with a specified argument, for each module - * in the list of all modules. (This list does not include subtrees.) - * - * Ignores "obsolete" modules; their sole purpose is to allow old - * preferences for dissectors that no longer have preferences to be - * silently ignored in preference files. - */ -extern guint prefs_modules_foreach(module_cb callback, gpointer user_data); - -/* - * Call a callback function, with a specified argument, for each submodule - * of specified modules. If the module is NULL, goes through the top-level - * list in the display tree of modules. - * - * Ignores "obsolete" modules; their sole purpose is to allow old - * preferences for dissectors that no longer have preferences to be - * silently ignored in preference files. Does not ignore subtrees, - * as this can be used when walking the display tree of modules. - */ -extern guint prefs_modules_foreach_submodules(module_t *module, module_cb callback, gpointer user_data); - -/* - * Call the "apply" callback function for each module if any of its - * preferences have changed, and then clear the flag saying its - * preferences have changed, as the module has been notified of that - * fact. - */ -extern void prefs_apply_all(void); - -/* - * Call the "apply" callback function for a specific module if any of - * its preferences have changed, and then clear the flag saying its - * preferences have changed, as the module has been notified of that - * fact. - */ -extern void prefs_apply(module_t *module); - - -struct preference; - -typedef struct preference pref_t; - -/* - * Returns TRUE if the given protocol has registered preferences. - */ -extern gboolean prefs_is_registered_protocol(const char *name); - -/* - * Returns the module title of a registered protocol (or NULL if unknown). - */ -extern const char *prefs_get_title_by_name(const char *name); - -/** Given a module name, return a pointer to its pref_module struct, - * or NULL if it's not found. - * - * @param name The preference module name. Usually the same as the protocol - * name, e.g. "tcp". - * @return A pointer to the corresponding preference module, or NULL if it - * wasn't found. - */ -extern module_t *prefs_find_module(const char *name); - -/* - * Register a preference with an unsigned integral value. - */ -extern void prefs_register_uint_preference(module_t *module, const char *name, - const char *title, const char *description, guint base, guint *var); - -/* - * Register a preference with an Boolean value. - * Note that the name must be in lowercase letters only (underscore allowed). - */ -extern void prefs_register_bool_preference(module_t *module, const char *name, - const char *title, const char *description, gboolean *var); - -/* - * Register a preference with an enumerated value. - */ -typedef struct { - const char *name; - const char *description; - gint value; -} enum_val_t; - -extern void prefs_register_enum_preference(module_t *module, const char *name, - const char *title, const char *description, gint *var, - const enum_val_t *enumvals, gboolean radio_buttons); - -/* - * Register a preference with a character-string value. - */ -extern void prefs_register_string_preference(module_t *module, const char *name, - const char *title, const char *description, const char **var); - -/* - * Register a preference with a ranged value. - */ -extern void prefs_register_range_preference(module_t *module, const char *name, - const char *title, const char *description, range_t **var, - guint32 max_value); - -/* - * Register a static text 'preference'. It can be used to add some info/explanation. - */ -extern void prefs_register_static_text_preference(module_t *module, const char *name, - const char *title, const char *description); - -/* - * Register a uat 'preference'. It adds a button that opens the uat's window in the - * preferences tab of the module. - */ -extern void prefs_register_uat_preference(module_t *module, - const char *name, - const char* title, - const char *description, - void* uat); - -/* - * Register a preference that used to be supported but no longer is. - */ -extern void prefs_register_obsolete_preference(module_t *module, - const char *name); - -typedef guint (*pref_cb)(pref_t *pref, gpointer user_data); - -/* - * Call a callback function, with a specified argument, for each preference - * in a given module. - * - * If any of the callbacks return a non-zero value, stop and return that - * value, otherwise return 0. - */ -extern guint prefs_pref_foreach(module_t *module, pref_cb callback, - gpointer user_data); - -/* - * Register all non-dissector modules' preferences. - */ -extern void prefs_register_modules(void); - -/* Read the preferences file, fill in "prefs", and return a pointer to it. - - If we got an error (other than "it doesn't exist") trying to read - the global preferences file, stuff the errno into "*gpf_errno_return" - on an open error and into "*gpf_read_errno_return" on a read error, - stuff a pointer to the path of the file into "*gpf_path_return", and - return NULL. - - If we got an error (other than "it doesn't exist") trying to read - the user's preferences file, stuff the errno into "*pf_errno_return" - on an open error and into "*pf_read_errno_return" on a read error, - stuff a pointer to the path of the file into "*pf_path_return", and - return NULL. */ -extern e_prefs *read_prefs(int *, int *, char **, int *, int *, char **); - -/* Write out "prefs" to the user's preferences file, and return 0. - - If we got an error, stuff a pointer to the path of the preferences file - into "*pf_path_return", and return the errno. */ -extern int write_prefs(char **); - -/* Copy a set of preferences. */ -extern void copy_prefs(e_prefs *dest, e_prefs *src); - -/* Free a set of preferences. */ -extern void free_prefs(e_prefs *pr); - -/* - * Given a string of the form ":", as might appear - * as an argument to a "-o" option, parse it and set the preference in - * question. Return an indication of whether it succeeded or failed - * in some fashion. - * - * XXX - should supply, for syntax errors, a detailed explanation of - * the syntax error. - */ -typedef enum { - PREFS_SET_OK, /* succeeded */ - PREFS_SET_SYNTAX_ERR, /* syntax error in string */ - PREFS_SET_NO_SUCH_PREF, /* no such preference */ - PREFS_SET_OBSOLETE /* preference used to exist but no longer does */ -} prefs_set_pref_e; - -extern prefs_set_pref_e prefs_set_pref(char *prefarg); - -/* - * Returns TRUE if the given device is hidden - */ -extern gboolean prefs_is_capture_device_hidden(const char *name); - -#endif /* prefs.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/privileges.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/privileges.h deleted file mode 100644 index 8a0b0ecf..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/privileges.h +++ /dev/null @@ -1,74 +0,0 @@ -/* privileges.h - * Declarations of routines for handling privileges. - * - * $Id: privileges.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2006 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/** - * Called when the program starts, to save whatever credential information - * we'll need later. - */ -extern void get_credential_info(void); - -/** - * Was this program started with special privileges? get_credential_info() - * MUST be called before calling this. - * @return TRUE if the program was started with special privileges, - * FALSE otherwise. - */ -extern gboolean started_with_special_privs(void); - -/** - * Is this program running with special privileges? get_credential_info() - * MUST be called before calling this. - * @return TRUE if the program is running with special privileges, - * FALSE otherwise. - */ -extern gboolean running_with_special_privs(void); - -/** - * Permanently relinquish special privileges. get_credential_info() - * MUST be called before calling this. - */ -extern void relinquish_special_privs_perm(void); - -/** - * Get the current username. String must be g_free()d after use. - * @return A freshly g_alloc()ed string containing the username, - * or "UNKNOWN" on failure. - */ -extern gchar *get_cur_username(void); - -/** - * Get the current group. String must be g_free()d after use. - * @return A freshly g_alloc()ed string containing the group, - * or "UNKNOWN" on failure. - */ -extern gchar *get_cur_groupname(void); - -#ifdef _WIN32 -/** - * Check to see if npf.sys is running. - * @return TRUE if npf.sys is running, FALSE if it's not or if there was - * an error checking its status. - */ -extern gboolean npf_sys_is_running(); -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/proto.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/proto.h deleted file mode 100644 index f20845fb..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/proto.h +++ /dev/null @@ -1,1655 +0,0 @@ -/* proto.h - * Definitions for protocol display - * - * $Id: proto.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - - -/*! @file proto.h - The protocol tree related functions.
- A protocol tree will hold all necessary data to display the whole dissected packet. - Creating a protocol tree is done in a two stage process: - A static part at program startup, and a dynamic part when the dissection with the real packet data is done.
- The "static" information is provided by creating a hf_register_info hf[] array, and register it using the - proto_register_field_array() function. This is usually done at dissector registering.
- The "dynamic" information is added to the protocol tree by calling one of the proto_tree_add_...() functions, - e.g. proto_tree_add_bytes(). -*/ - -#ifndef __PROTO_H__ -#define __PROTO_H__ - -#ifdef HAVE_STDARG_H -# include -#else -# include -#endif - -#include - -#include "gnuc_format_check.h" -#include "ipv4.h" -#include "nstime.h" -#include "tvbuff.h" -#include "ftypes/ftypes.h" -#include "register.h" - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/** The header-field index for the special text pseudo-field. Exported by libwireshark.dll */ -WS_VAR_IMPORT int hf_text_only; - -/** the maximum length of a protocol field string representation */ -#define ITEM_LABEL_LENGTH 240 - -struct _value_string; - -/** Make a const value_string[] look like a _value_string pointer, used to set header_field_info.strings */ -#define VALS(x) (const struct _value_string*)(x) - -/** Make a const true_false_string[] look like a _true_false_string pointer, used to set header_field_info.strings */ -#define TFS(x) (const struct true_false_string*)(x) - -/** Make a const range_string[] look like a _range_string pointer, used to set - * header_field_info.strings */ -#define RVALS(x) (const struct _range_string*)(x) - -struct _protocol; - -/** Structure for information about a protocol */ -typedef struct _protocol protocol_t; - -/** check protocol activation - * @todo this macro looks like a hack */ -#define CHECK_DISPLAY_AS_X(x_handle,index, tvb, pinfo, tree) { \ - if (!proto_is_protocol_enabled(find_protocol_by_id(index))) { \ - call_dissector(x_handle,tvb, pinfo, tree); \ - return; \ - } \ - } - -/** Macro used for reporting errors in dissectors; it throws a - * DissectorError exception, with the string passed as an argument - * as the message for the exception, so that it can show up in - * the Info column and the protocol tree. - * - * If that string is dynamically allocated, it should be allocated with - * ep_alloc(); using ep_strdup_printf() would work. - * - * If the WIRESHARK_ABORT_ON_DISSECTOR_BUG environment variable is set, - * it will call abort(), instead, to make it easier to get a stack trace. - * - * @param message string to use as the message - */ -#define REPORT_DISSECTOR_BUG(message) \ - ((getenv("WIRESHARK_ABORT_ON_DISSECTOR_BUG") != NULL) ? \ - abort() : \ - THROW_MESSAGE(DissectorError, message)) - -/** Macro used for assertions in dissectors; it doesn't abort, it just - * throws a DissectorError exception, with the assertion failure - * message as a parameter, so that it can show up in the protocol tree. - * - * @param expression expression to test in the assertion - */ -#define DISSECTOR_ASSERT(expression) \ - ((void) ((expression) ? (void)0 : \ - __DISSECTOR_ASSERT (expression, __FILE__, __LINE__))) - -#if 0 -/* win32: using a debug breakpoint (int 3) can be very handy while debugging, - * as the assert handling of GTK/GLib is currently not very helpful */ -#define DISSECTOR_ASSERT(expression) \ -{ if(!(expression)) _asm { int 3}; } -#endif - -/** Same as DISSECTOR_ASSERT(), but will throw DissectorError exception - * unconditionally, much like GLIB's g_assert_not_reached works. - */ -#define DISSECTOR_ASSERT_NOT_REACHED() \ - (REPORT_DISSECTOR_BUG( \ - ep_strdup_printf("%s:%u: failed assertion \"DISSECTOR_ASSERT_NOT_REACHED\"", \ - __FILE__, __LINE__))) - -#define __DISSECTOR_ASSERT_STRINGIFY(s) # s - -#define __DISSECTOR_ASSERT(expression, file, lineno) \ - (REPORT_DISSECTOR_BUG( \ - ep_strdup_printf("%s:%u: failed assertion \"%s\"", \ - file, lineno, __DISSECTOR_ASSERT_STRINGIFY(expression)))) - -/* BASE_STRUCTURE_RESET constant is used in proto.c to reset the bits - * identifying special structures used in translation of value for display. - * Its value means that we may have at most 16 base_display_e values */ -#define BASE_STRUCTURE_RESET 0x0F -/* Following constants have to be ORed with a base_display_e when dissector - * want to use specials MACROs (for the moment, only RVALS) for a - * header_field_info */ -#define BASE_RANGE_STRING 0x10 -/** radix for decimal values, used in header_field_info.display */ -typedef enum { - BASE_NONE, /**< none */ - BASE_DEC, /**< decimal */ - BASE_HEX, /**< hexadecimal */ - BASE_OCT, /**< octal */ - BASE_DEC_HEX, /**< decimal (hexadecimal) */ - BASE_HEX_DEC /**< hexadecimal (decimal) */ -} base_display_e; - -#define IS_BASE_DUAL(b) ((b)==BASE_DEC_HEX||(b)==BASE_HEX_DEC) - -/** information describing a header field */ -typedef struct _header_field_info header_field_info; - -/** information describing a header field */ -struct _header_field_info { - /* ---------- set by dissector --------- */ - const char *name; /**< full name of this field */ - const char *abbrev; /**< abbreviated name of this field */ - enum ftenum type; /**< field type, one of FT_ (from ftypes.h) */ - int display; /**< one of BASE_, or number of field bits for FT_BOOLEAN */ - const void *strings; /**< value_string, range_string or true_false_string, - typically converted by VALS(), RVALS() or TFS(). - If this is an FT_PROTOCOL then it points to the - associated protocol_t structure */ - guint32 bitmask; /**< bitmask of interesting bits */ - const char *blurb; /**< Brief description of field */ - - /* ------- set by proto routines (prefilled by HFILL macro, see below) ------ */ - int id; /**< Field ID */ - int parent; /**< parent protocol tree */ - int ref_count; /**< is this field referenced by a filter and how often */ - int bitshift; /**< bits to shift */ - header_field_info *same_name_next; /**< Link to next hfinfo with same abbrev */ - header_field_info *same_name_prev; /**< Link to previous hfinfo with same abbrev */ -}; - -/** - * HFILL initializes all the "set by proto routines" fields in a - * _header_field_info. If new fields are added or removed, it should - * be changed as necessary. - */ -#define HFILL 0, 0, 0, 0, NULL, NULL - -/** Used when registering many fields at once, using proto_register_field_array() */ -typedef struct hf_register_info { - int *p_id; /**< written to by register() function */ - header_field_info hfinfo; /**< the field info to be registered */ -} hf_register_info; - - - - -/** string representation, if one of the proto_tree_add_..._format() functions used */ -typedef struct _item_label_t { - char representation[ITEM_LABEL_LENGTH]; -} item_label_t; - - -/** Contains the field information for the proto_item. */ -typedef struct field_info { - header_field_info *hfinfo; /**< pointer to registered field information */ - gint start; /**< current start of data in field_info.ds_tvb */ - gint length; /**< current data length of item in field_info.ds_tvb */ - gint appendix_start; /**< start of appendix data */ - gint appendix_length; /**< length of appendix data */ - gint tree_type; /**< one of ETT_ or -1 */ - item_label_t *rep; /**< string for GUI tree */ - guint32 flags; /**< bitfield like FI_GENERATED, ... */ - tvbuff_t *ds_tvb; /**< data source tvbuff */ - fvalue_t value; -} field_info; - - -/* - * Flag fields. Do not assign values greater than 0x00000080 unless you - * shuffle the expert information upward; see below. - */ - -/** The protocol field should not be shown in the tree (it's used for filtering only), - * used in field_info.flags. */ -/* HIDING PROTOCOL FIELDS IS DEPRECATED, IT'S CONSIDERED TO BE BAD GUI DESIGN! */ -#define FI_HIDDEN 0x00000001 -/** The protocol field should be displayed as "generated by Wireshark", - * used in field_info.flags. */ -#define FI_GENERATED 0x00000002 -/** The protocol field is actually a URL */ -#define FI_URL 0x00000004 - - -/** convenience macro to get field_info.flags */ -#define FI_GET_FLAG(fi, flag) (fi->flags & flag) -/** convenience macro to set field_info.flags */ -#define FI_SET_FLAG(fi, flag) (fi->flags = fi->flags | flag) - -/** One of these exists for the entire protocol tree. Each proto_node - * in the protocol tree points to the same copy. */ -typedef struct { - GHashTable *interesting_hfids; - gboolean visible; - gint count; -} tree_data_t; - -/** Each proto_tree, proto_item is one of these. */ -typedef struct _proto_node { - struct _proto_node *first_child; - struct _proto_node *last_child; - struct _proto_node *next; - struct _proto_node *parent; - field_info *finfo; - tree_data_t *tree_data; -} proto_node; - -/** A protocol tree element. */ -typedef proto_node proto_tree; -/** A protocol item element. */ -typedef proto_node proto_item; - -/* - * Expert information. - * This is in the flags field; we allocate this from the top down, - * so as not to collide with FI_ flags, which are allocated from - * the bottom up. - */ - -/* expert severities */ -#define PI_SEVERITY_MASK 0x00000E00 /* mask usually for internal use only! */ -/** Usual workflow, e.g. TCP connection establishing */ -#define PI_CHAT 0x00000200 -/** Notable messages, e.g. an application returned an "usual" error code like HTTP 404 */ -#define PI_NOTE 0x00000400 -/** Warning, e.g. application returned an "unusual" error code */ -#define PI_WARN 0x00000600 -/** Serious problems, e.g. [Malformed Packet] */ -#define PI_ERROR 0x00000800 - -/* expert "event groups" */ -#define PI_GROUP_MASK 0xFFFFF000 /* mask usually for internal use only! */ -/** The protocol field has a bad checksum, usually PI_WARN */ -#define PI_CHECKSUM 0x00001000 -/** The protocol field indicates a sequence problem (e.g. TCP window is zero) */ -#define PI_SEQUENCE 0x00002000 -/** The protocol field indicates a bad application response code (e.g. HTTP 404), usually PI_NOTE */ -#define PI_RESPONSE_CODE 0x00004000 -/** The protocol field indicates an application request (e.g. File Handle == xxxx), usually PI_CHAT */ -#define PI_REQUEST_CODE 0x00005000 -/** The data is undecoded, the protocol dissection is incomplete here, usually PI_WARN */ -#define PI_UNDECODED 0x00008000 -/** The protocol field indicates a reassemble (e.g. DCE/RPC defragmentation), usually PI_CHAT (or PI_ERROR) */ -#define PI_REASSEMBLE 0x00010000 -/** The packet data is malformed, the dissector has "given up", usually PI_ERROR */ -#define PI_MALFORMED 0x00020000 -/** A generic debugging message (shouldn't remain in production code!), usually PI_ERROR */ -#define PI_DEBUG 0x00040000 -/* The protocol field indicates a security probem (e.g. unsecure implementation) */ -/*#define PI_SECURITY 0x00080000*/ - -/* add more, see http://wiki.wireshark.org/Development/ExpertInfo */ - - -/** is this protocol field hidden from the protocol tree display (used for filtering only)? */ -/* HIDING PROTOCOL FIELDS IS DEPRECATED, IT'S CONSIDERED TO BE BAD GUI DESIGN! */ -#define PROTO_ITEM_IS_HIDDEN(proto_item) \ - ((proto_item) ? FI_GET_FLAG((proto_item)->finfo, FI_HIDDEN) : 0) -/** mark this protocol field to be hidden from the protocol tree display (used for filtering only) */ -/* HIDING PROTOCOL FIELDS IS DEPRECATED, IT'S CONSIDERED TO BE BAD GUI DESIGN! */ -#define PROTO_ITEM_SET_HIDDEN(proto_item) \ - ((proto_item) ? FI_SET_FLAG((proto_item)->finfo, FI_HIDDEN) : 0) -/** is this protocol field generated by Wireshark (and not read from the packet data)? */ -#define PROTO_ITEM_IS_GENERATED(proto_item) \ - ((proto_item) ? FI_GET_FLAG((proto_item)->finfo, FI_GENERATED) : 0) -/** mark this protocol field as generated by Wireshark (and not read from the packet data) */ -#define PROTO_ITEM_SET_GENERATED(proto_item) \ - ((proto_item) ? FI_SET_FLAG((proto_item)->finfo, FI_GENERATED) : 0) -/** is this protocol field actually a URL? */ -#define PROTO_ITEM_IS_URL(proto_item) \ - ((proto_item) ? FI_GET_FLAG((proto_item)->finfo, FI_URL) : 0) -/** mark this protocol field as a URL */ -#define PROTO_ITEM_SET_URL(proto_item) \ - ((proto_item) ? FI_SET_FLAG((proto_item)->finfo, FI_URL) : 0) - -typedef void (*proto_tree_foreach_func)(proto_node *, gpointer); -typedef gboolean (*proto_tree_traverse_func)(proto_node *, gpointer); - -extern gboolean proto_tree_traverse_in_order(proto_tree *tree, - proto_tree_traverse_func func, gpointer data); -extern void proto_tree_children_foreach(proto_tree *tree, - proto_tree_foreach_func func, gpointer data); - -/** Retrieve the field_info from a proto_item */ -#define PITEM_FINFO(proto_item) ((proto_item)->finfo) - -/** Retrieve the tree_data_t from a proto_tree */ -#define PTREE_DATA(proto_tree) ((proto_tree)->tree_data) - -/** Sets up memory used by proto routines. Called at program startup */ -extern void proto_init(void (register_all_protocols)(register_cb cb, gpointer client_data), - void (register_all_handoffs)(register_cb cb, gpointer client_data), - register_cb cb, void *client_data); - - -/** Frees memory used by proto routines. Called at program shutdown */ -extern void proto_cleanup(void); - -/** This function takes a tree and a protocol id as parameter and - will return TRUE/FALSE for whether the protocol or any of the filterable - fields in the protocol is referenced by any fitlers. - If this function returns FALSE then it is safe to skip any - proto_tree_add_...() calls and just treat the call as if the - dissector was called with tree==NULL. - If you reset the tree to NULL by this dissector returning FALSE, - you will still need to call any subdissector with the original value of - tree or filtering will break. - - The purpose of this is to optimize wireshark for speed and make it - faster for when filters are being used. -*/ -extern gboolean proto_field_is_referenced(proto_tree *tree, int proto_id); - - - -/** Create a subtree under an existing item. - @param ti the parent item of the new subtree - @param idx one of the ett_ array elements registered with proto_register_subtree_array() - @return the new subtree */ -extern proto_tree* proto_item_add_subtree(proto_item *ti, gint idx); - -/** Get an existing subtree under an item. - @param ti the parent item of the subtree - @return the subtree or NULL */ -extern proto_tree* proto_item_get_subtree(proto_item *ti); - -/** Get the parent of a subtree item. - @param ti the child item in the subtree - @return parent item or NULL */ -extern proto_item* proto_item_get_parent(proto_item *ti); - -/** Get Nth generation parent item. - @param ti the child item in the subtree - @param gen the generation to get (using 1 here is the same as using proto_item_get_parent()) - @return parent item */ -extern proto_item* proto_item_get_parent_nth(proto_item *ti, int gen); - -/** Replace text of item after it already has been created. - @param ti the item to set the text - @param format printf like format string - @param ... printf like parameters */ -extern void proto_item_set_text(proto_item *ti, const char *format, ...) - GNUC_FORMAT_CHECK(printf, 2,3); - -/** Append to text of item after it has already been created. - @param ti the item to append the text to - @param format printf like format string - @param ... printf like parameters */ -extern void proto_item_append_text(proto_item *ti, const char *format, ...) - GNUC_FORMAT_CHECK(printf, 2,3); - -/** Set proto_item's length inside tvb, after it has already been created. - @param ti the item to set the length - @param length the new length ot the item */ -extern void proto_item_set_len(proto_item *ti, gint length); - -/** - * Sets the length of the item based on its start and on the specified - * offset, which is the offset past the end of the item; as the start - * in the item is relative to the beginning of the data source tvbuff, - * we need to pass in a tvbuff. - @param ti the item to set the length - @param tvb end is relative to this tvbuff - @param end this end offset is relative to the beginning of tvb - @todo make usage clearer, I don't understand it! - */ -extern void proto_item_set_end(proto_item *ti, tvbuff_t *tvb, gint end); - -/** Get length of a proto_item. Useful after using proto_tree_add_item() - * to add a variable-length field (e.g., FT_NSTRING_UINT8). - @param ti the item to get the length from - @return the current length */ -extern int proto_item_get_len(proto_item *ti); - -/** - * Sets an expert info to the proto_item. - @param ti the item to set the expert info - @param group the group of this info (e.g. PI_CHECKSUM) - @param severity of this info (e.g. PI_ERROR) - @return TRUE if value was written - */ -extern gboolean proto_item_set_expert_flags(proto_item *ti, int group, guint severity); - - - - -/** Creates a new proto_tree root. - @return the new tree root */ -extern proto_tree* proto_tree_create_root(void); - -/** Clear memory for entry proto_tree. Clears proto_tree struct also. - @param tree the tree to free */ -extern void proto_tree_free(proto_tree *tree); - -/** Set the tree visible or invisible. - Is the parsing being done for a visible proto_tree or an invisible one? - By setting this correctly, the proto_tree creation is sped up by not - having to call g_vsnprintf and copy strings around. - @param tree the tree to be set - @param visible ... or not */ -extern void -proto_tree_set_visible(proto_tree *tree, gboolean visible); - -/** Mark a field/protocol ID as "interesting". - @param tree the tree to be set - @param hfid the interesting field id - @todo what *does* interesting mean? */ -extern void -proto_tree_prime_hfid(proto_tree *tree, int hfid); - -/** Get a parent item of a subtree. - @param tree the tree to get the parent from - @return parent item */ -extern proto_item* proto_tree_get_parent(proto_tree *tree); - -/** Get the root tree from any subtree. - @param tree the tree to get the root from - @return root tree */ -extern proto_tree* proto_tree_get_root(proto_tree *tree); - -/** Move an existing item behind another existing item. - @param tree the tree to which both items belong - @param fixed_item the item which keeps it's position - @param item_to_move the item which will be moved */ -extern void proto_tree_move_item(proto_tree *tree, proto_item *fixed_item, proto_item *item_to_move); - - -/** Set start and length of an appendix for a proto_tree. - @param tree the tree to set the appendix start and length - @param tvb the tv buffer of the current data - @param start the start offset of the appendix - @param length the length of the appendix */ -extern void proto_tree_set_appendix(proto_tree *tree, tvbuff_t *tvb, gint start, gint length); - - -/** Add an item to a proto_tree, using the text label registered to that item. - The item is extracted from the tvbuff handed to it. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param little_endian big or little endian byte representation - @return the newly created item */ -extern proto_item * -proto_tree_add_item(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, gboolean little_endian); - -/** Add a hidden item to a proto_tree. - @deprecated use proto_tree_add_item() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ -extern proto_item * -proto_tree_add_item_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, gboolean little_endian); - -/** Add a text-only node to a proto_tree. - @param tree the tree to append this item to - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_text(proto_tree *tree, tvbuff_t *tvb, gint start, gint length, const char *format, - ...) GNUC_FORMAT_CHECK(printf,5,6); - -/** Add a text-only node to a proto_tree using a variable argument list. - @param tree the tree to append this item to - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param format printf like format string - @param ap variable argument list - @return the newly created item */ -extern proto_item * -proto_tree_add_text_valist(proto_tree *tree, tvbuff_t *tvb, gint start, - gint length, const char *format, va_list ap); - - -/** Add a FT_NONE field to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_none_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const char *format, ...) GNUC_FORMAT_CHECK(printf,6,7); - -/** Add a FT_PROTOCOL to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_protocol_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const char *format, ...) GNUC_FORMAT_CHECK(printf,6,7); - - - - -/** Add a FT_BYTES to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param start_ptr pointer to the data to display - @return the newly created item */ -extern proto_item * -proto_tree_add_bytes(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const guint8* start_ptr); - -/** Add a hidden FT_BYTES to a proto_tree. - @deprecated use proto_tree_add_bytes() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ -extern proto_item * -proto_tree_add_bytes_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const guint8* start_ptr); - -/** Add a formatted FT_BYTES to a proto_tree, with the format generating - the string for the value and with the field name being included - automatically. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param start_ptr pointer to the data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_bytes_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, const guint8* start_ptr, const char *format, - ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a formatted FT_BYTES to a proto_tree, with the format generating - the entire string for the entry, including any field name. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param start_ptr pointer to the data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_bytes_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const guint8* start_ptr, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a FT_ABSOLUTE_TIME or FT_RELATIVE_TIME to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value_ptr pointer to the data to display - @return the newly created item */ -extern proto_item * -proto_tree_add_time(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, nstime_t* value_ptr); - -/** Add a hidden FT_ABSOLUTE_TIME or FT_RELATIVE_TIME to a proto_tree. - @deprecated use proto_tree_add_time() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ -extern proto_item * -proto_tree_add_time_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, nstime_t* value_ptr); - -/** Add a formatted FT_ABSOLUTE_TIME or FT_RELATIVE_TIME to a proto_tree, with - the format generating the string for the value and with the field name - being included automatically. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value_ptr pointer to the data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_time_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, nstime_t* value_ptr, const char *format, ...) - GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a formatted FT_ABSOLUTE_TIME or FT_RELATIVE_TIME to a proto_tree, with - the format generating the entire string for the entry, including any field - name. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value_ptr pointer to the data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_time_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, nstime_t* value_ptr, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a FT_IPXNET to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @return the newly created item */ -extern proto_item * -proto_tree_add_ipxnet(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, guint32 value); - -/** Add a hidden FT_IPXNET to a proto_tree. - @deprecated use proto_tree_add_ipxnet() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ -extern proto_item * -proto_tree_add_ipxnet_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, guint32 value); - -/** Add a formatted FT_IPXNET to a proto_tree, with the format generating - the string for the value and with the field name being included - automatically. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_ipxnet_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, guint32 value, const char *format, ...) - GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a formatted FT_IPXNET to a proto_tree, with the format generating - the entire string for the entry, including any field name. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_ipxnet_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, guint32 value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a FT_IPv4 to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @return the newly created item */ -extern proto_item * -proto_tree_add_ipv4(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, guint32 value); - -/** Add a hidden FT_IPv4 to a proto_tree. - @deprecated use proto_tree_add_ipv4() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ -extern proto_item * -proto_tree_add_ipv4_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, guint32 value); - -/** Add a formatted FT_IPv4 to a proto_tree, with the format generating - the string for the value and with the field name being included - automatically. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_ipv4_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, guint32 value, const char *format, ...) - GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a formatted FT_IPv4 to a proto_tree, with the format generating - the entire string for the entry, including any field name. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_ipv4_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, guint32 value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a FT_IPv6 to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value_ptr data to display - @return the newly created item */ -extern proto_item * -proto_tree_add_ipv6(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const guint8* value_ptr); - -/** Add a hidden FT_IPv6 to a proto_tree. - @deprecated use proto_tree_add_ipv6() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ -extern proto_item * -proto_tree_add_ipv6_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const guint8* value_ptr); - -/** Add a formatted FT_IPv6 to a proto_tree, with the format generating - the string for the value and with the field name being included - automatically. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value_ptr data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_ipv6_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, const guint8* value_ptr, const char *format, - ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a formatted FT_IPv6 to a proto_tree, with the format generating - the entire string for the entry, including any field name. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value_ptr data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_ipv6_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const guint8* value_ptr, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a FT_ETHER to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @return the newly created item */ -extern proto_item * -proto_tree_add_ether(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const guint8* value); - -/** Add a hidden FT_ETHER to a proto_tree. - @deprecated use proto_tree_add_ether() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ -extern proto_item * -proto_tree_add_ether_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const guint8* value); - -/** Add a formatted FT_ETHER to a proto_tree, with the format generating - the string for the value and with the field name being included - automatically. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_ether_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, const guint8* value, const char *format, ...) - GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a formatted FT_ETHER to a proto_tree, with the format generating - the entire string for the entry, including any field name. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_ether_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const guint8* value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a FT_GUID to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value_ptr data to display - @return the newly created item */ -extern proto_item * -proto_tree_add_guid(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const e_guid_t *value_ptr); - -/** Add a hidden FT_GUID to a proto_tree. - @deprecated use proto_tree_add_guid() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ -extern proto_item * -proto_tree_add_guid_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const e_guid_t *value_ptr); - -/** Add a formatted FT_GUID to a proto_tree, with the format generating - the string for the value and with the field name being included - automatically. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value_ptr data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_guid_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, const e_guid_t *value_ptr, const char *format, - ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a formatted FT_GUID to a proto_tree, with the format generating - the entire string for the entry, including any field name. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value_ptr data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_guid_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const e_guid_t *value_ptr, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a FT_OID to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value_ptr data to display - @return the newly created item */ -extern proto_item * -proto_tree_add_oid(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const guint8* value_ptr); - -/** Add a hidden FT_OID to a proto_tree. - @deprecated use proto_tree_add_oid() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ -extern proto_item * -proto_tree_add_oid_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const guint8* value_ptr); - -/** Add a formatted FT_OID to a proto_tree, with the format generating - the string for the value and with the field name being included - automatically. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value_ptr data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_oid_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, const guint8* value_ptr, const char *format, - ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a formatted FT_OID to a proto_tree, with the format generating - the entire string for the entry, including any field name. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value_ptr data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_oid_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const guint8* value_ptr, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a FT_STRING to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @return the newly created item */ -extern proto_item * -proto_tree_add_string(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const char* value); - -/** Add a hidden FT_STRING to a proto_tree. - @deprecated use proto_tree_add_string() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ -extern proto_item * -proto_tree_add_string_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const char* value); - -/** Add a formatted FT_STRING to a proto_tree, with the format generating - the string for the value and with the field name being included - automatically. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_string_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, const char* value, const char *format, ...) - GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a formatted FT_STRING to a proto_tree, with the format generating - the entire string for the entry, including any field name. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_string_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, const char* value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a FT_BOOLEAN to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @return the newly created item */ -extern proto_item * -proto_tree_add_boolean(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, guint32 value); - -/** Add a hidden FT_BOOLEAN to a proto_tree. - @deprecated use proto_tree_add_boolean() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ -extern proto_item * -proto_tree_add_boolean_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, guint32 value); - -/** Add a formatted FT_BOOLEAN to a proto_tree, with the format generating - the string for the value and with the field name being included - automatically. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_boolean_format_value(proto_tree *tree, int hfindex, - tvbuff_t *tvb, gint start, gint length, guint32 value, - const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a formatted FT_BOOLEAN to a proto_tree, with the format generating - the entire string for the entry, including any field name. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_boolean_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, guint32 value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a FT_FLOAT to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @return the newly created item */ -extern proto_item * -proto_tree_add_float(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, float value); - -/** Add a hidden FT_FLOAT to a proto_tree. - @deprecated use proto_tree_add_float() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ -extern proto_item * -proto_tree_add_float_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, float value); - -/** Add a formatted FT_FLOAT to a proto_tree, with the format generating - the string for the value and with the field name being included - automatically. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_float_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, float value, const char *format, ...) - GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a formatted FT_FLOAT to a proto_tree, with the format generating - the entire string for the entry, including any field name. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_float_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, float value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a FT_DOUBLE to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @return the newly created item */ -extern proto_item * -proto_tree_add_double(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, double value); - -/** Add a hidden FT_DOUBLE to a proto_tree. - @deprecated use proto_tree_add_double() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ -extern proto_item * -proto_tree_add_double_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, double value); - -/** Add a formatted FT_DOUBLE to a proto_tree, with the format generating - the string for the value and with the field name being included - automatically. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_double_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, double value, const char *format, ...) - GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a formatted FT_DOUBLE to a proto_tree, with the format generating - the entire string for the entry, including any field name. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_double_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, double value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add one of FT_UINT8, FT_UINT16, FT_UINT24 or FT_UINT32 to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @return the newly created item */ -extern proto_item * -proto_tree_add_uint(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, guint32 value); - -/** Add a hidden FT_UINT8, FT_UINT16, FT_UINT24 or FT_UINT32 to a proto_tree. - @deprecated use proto_tree_add_uint() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ -extern proto_item * -proto_tree_add_uint_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, guint32 value); - -/** Add a formatted FT_UINT8, FT_UINT16, FT_UINT24 or FT_UINT32 to a proto_tree, - with the format generating the string for the value and with the field - name being included automatically. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_uint_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, guint32 value, const char *format, ...) - GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a formatted FT_UINT8, FT_UINT16, FT_UINT24 or FT_UINT32 to a proto_tree, - with the format generating the entire string for the entry, including any - field name. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_uint_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, guint32 value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add an FT_UINT64 to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @return the newly created item */ -extern proto_item * -proto_tree_add_uint64(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, guint64 value); - -/** Add a formatted FT_UINT64 to a proto_tree, with the format generating - the string for the value and with the field name being included - automatically. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_uint64_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, guint64 value, const char *format, ...) - GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a formatted FT_UINT64 to a proto_tree, with the format generating - the entire string for the entry, including any field name. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_uint64_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, guint64 value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add one of FT_INT8, FT_INT16, FT_INT24 or FT_INT32 to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @return the newly created item */ -extern proto_item * -proto_tree_add_int(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, gint32 value); - -/** Add a hidden FT_INT8, FT_INT16, FT_INT24 or FT_INT32 to a proto_tree. - @deprecated use proto_tree_add_int() and a subsequent call to PROTO_ITEM_SET_HIDDEN() instead */ -extern proto_item * -proto_tree_add_int_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, gint32 value); - -/** Add a formatted FT_INT8, FT_INT16, FT_INT24 or FT_INT32 to a proto_tree, - with the format generating the string for the value and with the field - name being included automatically. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_int_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, gint32 value, const char *format, ...) - GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a formatted FT_INT8, FT_INT16, FT_INT24 or FT_INT32 to a proto_tree, - with the format generating the entire string for the entry, including - any field name. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_int_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, gint32 value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Add an FT_INT64 to a proto_tree. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @return the newly created item */ -extern proto_item * -proto_tree_add_int64(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, gint64 value); - -/** Add a formatted FT_INT64 to a proto_tree, with the format generating - the string for the value and with the field name being included - automatically. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_int64_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb, - gint start, gint length, gint64 value, const char *format, ...) - GNUC_FORMAT_CHECK(printf,7,8); - -/** Add a formatted FT_INT64 to a proto_tree, with the format generating - the entire string for the entry, including any field name. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param start start of data in tvb - @param length length of data in tvb - @param value data to display - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_int64_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, gint64 value, const char *format, ...) GNUC_FORMAT_CHECK(printf,7,8); - -/** Useful for quick debugging. Also sends string to STDOUT, so don't - leave call to this function in production code. - @param tree the tree to append the text to - @param format printf like format string - @param ... printf like parameters - @return the newly created item */ -extern proto_item * -proto_tree_add_debug_text(proto_tree *tree, const char *format, - ...) GNUC_FORMAT_CHECK(printf,2,3); - - - -/** Append a string to a protocol item.
- NOTE: this function will break with the TRY_TO_FAKE_THIS_ITEM() - speed optimization. - Currently only WSP use this function so it is not that bad but try to - avoid using this one if possible. - IF you must use this function you MUST also disable the - TRY_TO_FAKE_THIS_ITEM() optimization for your dissector/function - using proto_item_append_string(). - Do that by faking that the tree is visible by calling - proto_tree_set_visible(tree, TRUE) (see packet-wsp.c) - BEFORE you create the item you are later going to use - proto_item_append_string() on. - @param pi the item to append the string to - @param str the string to append */ -extern void -proto_item_append_string(proto_item *pi, const char *str); - - - -/** Fill given label_str with string representation of field - @param fi the item to get the info from - @param label_str the string to fill - @todo think about changing the parameter profile */ -extern void -proto_item_fill_label(field_info *fi, gchar *label_str); - - -/** Register a new protocol. - @param name the full name of the new protocol - @param short_name abbreviated name of the new protocol - @param filter_name protocol name used for a display filter string - @return the new protocol handle */ -extern int -proto_register_protocol(const char *name, const char *short_name, const char *filter_name); - -/** Register a header_field array. - @param parent the protocol handle from proto_register_protocol() - @param hf the hf_register_info array - @param num_records the number of records in hf */ -extern void -proto_register_field_array(int parent, hf_register_info *hf, int num_records); - -/** Register a protocol subtree (ett) array. - @param indices array of ett indices - @param num_indices the number of records in indices */ -extern void -proto_register_subtree_array(gint *const *indices, int num_indices); - -/** Returns number of items (protocols or header fields) registered. - @return the number of items */ -extern int proto_registrar_n(void); - -/** Get name of registered header_field number n. - @param n item # n (0-indexed) - @return the name of this registered item */ -extern const char* proto_registrar_get_name(int n); - -/** Get abbreviation of registered header_field number n. - @param n item # n (0-indexed) - @return the abbreviation of this registered item */ -extern const char* proto_registrar_get_abbrev(int n); - -/** Get the header_field information based upon a field or protocol id. - @param hfindex item # n (0-indexed) - @return the registered item */ -extern header_field_info* proto_registrar_get_nth(guint hfindex); - -/** Get the header_field information based upon a field name. - @param field_name the field name to search for - @return the registered item */ -extern header_field_info* proto_registrar_get_byname(const char *field_name); - -/** Get enum ftenum FT_ of registered header_field number n. - @param n item # n (0-indexed) - @return the registered item */ -extern int proto_registrar_get_ftype(int n); - -/** Get parent protocol of registered header_field number n. - @param n item # n (0-indexed) - @return -1 if item _is_ a protocol */ -extern int proto_registrar_get_parent(int n); - -/** Is item # n a protocol? - @param n item # n (0-indexed) - @return TRUE if it's a protocol, FALSE if it's not */ -extern gboolean proto_registrar_is_protocol(int n); - -/** Get length of registered field according to field type. - @param n item # n (0-indexed) - @return 0 means undeterminable at registration time, -1 means unknown field */ -extern gint proto_registrar_get_length(int n); - - -/** Routines to use to iterate over the protocols and their fields; - * they return the item number of the protocol in question or the - * appropriate hfinfo pointer, and keep state in "*cookie". */ -extern int proto_get_first_protocol(void **cookie); -extern int proto_get_next_protocol(void **cookie); -extern header_field_info *proto_get_first_protocol_field(int proto_id, void **cookle); -extern header_field_info *proto_get_next_protocol_field(void **cookle); - -/** Given a protocol's filter_name. - @param filter_name the filter name to search for - @return proto_id */ -extern int proto_get_id_by_filter_name(const gchar* filter_name); - -/** Can item # n decoding be disabled? - @param proto_id protocol id (0-indexed) - @return TRUE if it's a protocol, FALSE if it's not */ -extern gboolean proto_can_toggle_protocol(int proto_id); - -/** Get the "protocol_t" structure for the given protocol's item number. - @param proto_id protocol id (0-indexed) */ -extern protocol_t *find_protocol_by_id(int proto_id); - -/** Get the protocol's name for the given protocol's item number. - @param proto_id protocol id (0-indexed) - @return its name */ -extern const char *proto_get_protocol_name(int proto_id); - -/** Get the protocol's item number, for the given protocol's "protocol_t". - @return its proto_id */ -extern int proto_get_id(protocol_t *protocol); - -/** Get the protocol's short name, for the given protocol's "protocol_t". - @return its short name. */ -extern const char *proto_get_protocol_short_name(protocol_t *protocol); - -/** Is protocol's decoding enabled ? - @param protocol - @return TRUE if decoding is enabled, FALSE if not */ -extern gboolean proto_is_protocol_enabled(protocol_t *protocol); - -/** Get a protocol's filter name by it's item number. - @param proto_id protocol id (0-indexed) - @return its filter name. */ -extern const char *proto_get_protocol_filter_name(int proto_id); - -/** Enable / Disable protocol of the given item number. - @param proto_id protocol id (0-indexed) - @param enabled enable / disable the protocol */ -extern void proto_set_decoding(int proto_id, gboolean enabled); - -/** Enable all protocols */ -extern void proto_enable_all(void); - -/** Disable disabling/enabling of protocol of the given item number. - @param proto_id protocol id (0-indexed) */ -extern void proto_set_cant_toggle(int proto_id); - -/** Checks for existence any protocol or field within a tree. - @param tree "Protocols" are assumed to be a child of the [empty] root node. - @param id hfindex of protocol or field - @return TRUE = found, FALSE = not found - @todo add explanation of id parameter */ -extern gboolean proto_check_for_protocol_or_field(proto_tree* tree, int id); - -/** Return GPtrArray* of field_info pointers for all hfindex that appear in - tree. Only works with primed trees, and is fast. - @param tree tree of interest - @param hfindex primed hfindex - @return GPtrArry pointer */ -extern GPtrArray* proto_get_finfo_ptr_array(proto_tree *tree, int hfindex); - -/** Return GPtrArray* of field_info pointers for all hfindex that appear in - tree. Works with any tree, primed or unprimed, and is slower than - proto_get_finfo_ptr_array because it has to search through the tree. - @param tree tree of interest - @param hfidex index of field info of interest - @return GPtrArry pointer */ -extern GPtrArray* proto_find_finfo(proto_tree *tree, int hfindex); - -/** Return GPtrArray* of field_info pointers containg all hfindexes that appear - in tree. - @param tree tree of interest - @return GPtrArry pointer */ -extern GPtrArray* proto_all_finfos(proto_tree *tree); - -/** Dumps a glossary of the protocol registrations to STDOUT */ -extern void proto_registrar_dump_protocols(void); - -/** Dumps a glossary of the field value strings or true/false strings to STDOUT */ -extern void proto_registrar_dump_values(void); - -/** Dumps a glossary of the protocol and field registrations to STDOUT. - * Format 1 is the original format. Format 2 includes the base (for integers) - * and the blurb. */ -extern void proto_registrar_dump_fields(int format); - - - -/** Points to the first element of an array of Booleans, indexed by - a subtree item type. That array element is TRUE if subtrees of - an item of that type are to be expanded. With MSVC and a - libwireshark.dll, we need a special declaration. */ -WS_VAR_IMPORT gboolean *tree_is_expanded; - -/** Number of elements in the tree_is_expanded array. With MSVC and a - * libwireshark.dll, we need a special declaration. */ -WS_VAR_IMPORT int num_tree_types; - -/** glib doesn't have g_ptr_array_len of all things!*/ -#ifndef g_ptr_array_len -#define g_ptr_array_len(a) ((a)->len) -#endif - -/** Get number of bits of a header_field. - @param hfinfo header_field - @return the bitwidth */ -extern int -hfinfo_bitwidth(header_field_info *hfinfo); - - - - -#include "epan.h" - -/** Can we do a "match selected" on this field. - @param finfo field_info - @param edt epan dissecting - @return TRUE if we can do a "match selected" on the field, FALSE otherwise. */ -extern gboolean -proto_can_match_selected(field_info *finfo, epan_dissect_t *edt); - -/** Construct a "match selected" display filter string. - @param finfo field_info - @param edt epan dissecting - @return the display filter string */ -extern char* -proto_construct_match_selected_string(field_info *finfo, epan_dissect_t *edt); - -/** Find field from offset in tvb. - @param tree tree of interest - @param offset offset in the tvb - @param tvb the tv buffer - @return the corresponding field_info */ -extern field_info* -proto_find_field_from_offset(proto_tree *tree, guint offset, tvbuff_t *tvb); - -/** This function will dissect a sequence of bytes that describe a bitmask. - @param tree the tree to append this item to - @param tvb the tv buffer of the current data - @param offset start of data in tvb - @param hf_hdr an 8/16/24/32 bit integer that describes the bitmask to be dissected. - This field will form an expansion under which the individual fields of the - bitmask is dissected and displayed. - This field must be of the type FT_[U]INT{8|16|24|32}. - @param fields an array of pointers to int that lists all the fields of the - bitmask. These fields can be either of the type FT_BOOLEAN for flags - or another integer of the same type/size as hf_hdr with a mask specified. - This array is terminated by a NULL entry. - FT_BOOLEAN bits that are set to 1 will have the name added to the expansion. - FT_integer fields that have a value_string attached will have the - matched string displayed on the expansion line. - @param little_endian big or little endian byte representation - @return the newly created item */ -extern proto_item * -proto_tree_add_bitmask(proto_tree *tree, tvbuff_t *tvb, int offset, int hf_hdr, gint ett, const int **fields, gboolean little_endian); - -/** Add bits to a proto_tree, using the text label registered to that item. - The item is extracted from the tvbuff handed to it. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param bit_offset start of data in tvb expressed in bits - @param no_of_bits length of data in tvb expressed in bits - @param little_endian big or little endian byte representation - @return the newly created item */ -extern proto_item * -proto_tree_add_bits_item(proto_tree *tree, int hf_index, tvbuff_t *tvb, gint bit_offset, gint no_of_bits, gboolean little_endian); - -/** Add bits to a proto_tree, using the text label registered to that item. - The item is extracted from the tvbuff handed to it. - @param tree the tree to append this item to - @param hfindex field index - @param tvb the tv buffer of the current data - @param bit_offset start of data in tvb expressed in bits - @param no_of_bits length of data in tvb expressed in bits - @param return_value if a pointer is passed here the value is returned. - @param little_endian big or little endian byte representation - @return the newly created item */ -extern proto_item * -proto_tree_add_bits_ret_val(proto_tree *tree, int hf_index, tvbuff_t *tvb, gint bit_offset, gint no_of_bits, guint64 *return_value, gboolean little_endian); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* proto.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ptvcursor.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ptvcursor.h deleted file mode 100644 index d94940bf..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ptvcursor.h +++ /dev/null @@ -1,110 +0,0 @@ -/* ptvcursor.h - * - * Proto Tree TVBuff cursor - * Gilbert Ramirez - * - * $Id: ptvcursor.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2000 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __PTVCURSOR_H__ -#define __PTVCURSOR_H__ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#include - -#define SUBTREE_UNDEFINED_LENGTH -1 - -typedef struct ptvcursor ptvcursor_t; - -/* Allocates an initializes a ptvcursor_t with 3 variables: - * proto_tree, tvbuff, and offset. */ -ptvcursor_t* -ptvcursor_new(proto_tree*, tvbuff_t*, gint); - -/* Gets data from tvbuff, adds it to proto_tree, increments offset, - * and returns proto_item* */ -proto_item* -ptvcursor_add(ptvcursor_t*, int hf, gint length, gboolean endianness); - - -/* Gets data from tvbuff, adds it to proto_tree, *DOES NOT* increment - * offset, and returns proto_item* */ -proto_item* -ptvcursor_add_no_advance(ptvcursor_t*, int hf, gint length, gboolean endianness); - -/* Advance the ptvcursor's offset within its tvbuff without - * adding anything to the proto_tree. */ -void -ptvcursor_advance(ptvcursor_t* ptvc, gint length); - -/* Frees memory for ptvcursor_t, but nothing deeper than that. */ -void -ptvcursor_free(ptvcursor_t*); - -/* Returns tvbuff. */ -tvbuff_t* -ptvcursor_tvbuff(ptvcursor_t*); - -/* Returns current offset. */ -gint -ptvcursor_current_offset(ptvcursor_t*); - -/* Returns the proto_tree* */ -proto_tree* -ptvcursor_tree(ptvcursor_t* ptvc); - -/* Sets a new proto_tree* for the ptvcursor_t */ -void -ptvcursor_set_tree(ptvcursor_t* ptvc, proto_tree *tree); - -/* push a subtree in the tree stack of the cursor */ -proto_tree* -ptvcursor_push_subtree(ptvcursor_t *ptvc, proto_item *it, gint ett_subtree); - -/* pop a subtree in the tree stack of the cursor */ -void ptvcursor_pop_subtree(ptvcursor_t *ptvc); - -/* Add an item to the tree and create a subtree - * If the length is unknown, length may be defined as SUBTREE_UNDEFINED_LENGTH. - * In this case, when the subtree will be closed, the parent item length will - * be equal to the advancement of the cursor since the creation of the subtree. - */ -proto_tree* ptvcursor_add_with_subtree(ptvcursor_t * ptvc, int hfindex, gint length, -gboolean little_endian, gint ett_subtree); - -/* Add a text node to the tree and create a subtree - * If the length is unknown, length may be defined as SUBTREE_UNDEFINED_LENGTH. - * In this case, when the subtree will be closed, the item length will be equal - * to the advancement of the cursor since the creation of the subtree. - */ -proto_tree * ptvcursor_add_text_with_subtree(ptvcursor_t * ptvc, gint length, - gint ett_subtree, const char *format, ...); - -/* Creates a subtree and adds it to the cursor as the working tree but does not - * save the old working tree */ -proto_tree* -ptvcursor_set_subtree(ptvcursor_t *ptvc, proto_item *it, gint ett_subtree); - -#endif /* __PTVCURSOR_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/radius_dict_lex.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/radius_dict_lex.h deleted file mode 100644 index 1ddab2be..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/radius_dict_lex.h +++ /dev/null @@ -1,6 +0,0 @@ -/* This is generated by runlex.sh. Do not edit it. */ -#define yylex Radiuslex -#ifndef YY_DECL -#define YY_DECL int yylex(void) -#endif -YY_DECL; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/range.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/range.h deleted file mode 100644 index daf339c5..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/range.h +++ /dev/null @@ -1,73 +0,0 @@ -/* range.h - * Range routines - * - * $Id: range.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Dick Gooris - * Ulf Lamping - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __RANGE_H__ -#define __RANGE_H__ - -#include - -/* XXX where's the best place for these? */ -#define MAX_SCTP_PORT 65535 -#define MAX_TCP_PORT 65535 -#define MAX_UDP_PORT 65535 - -typedef struct range_admin_tag { - guint32 low; - guint32 high; -} range_admin_t; - -typedef struct range { - /* user specified range(s) */ - guint nranges; /* number of entries in ranges */ - range_admin_t ranges[1]; /* variable-length array */ -} range_t; - -/* - * Return value from range_convert_str(). - */ -typedef enum { - CVT_NO_ERROR, - CVT_SYNTAX_ERROR, - CVT_NUMBER_TOO_BIG -} convert_ret_t; - -extern range_t *range_empty(void); - -extern convert_ret_t range_convert_str(range_t **range, const gchar *es, - guint32 max_value); - -extern gboolean value_is_in_range(range_t *range, guint32 val); - -extern gboolean ranges_are_equal(range_t *a, range_t *b); - -extern void range_foreach(range_t *range, void (*callback)(guint32 val)); - -extern char *range_convert_range(range_t *range); - -extern range_t *range_copy(range_t *src); - -#endif /* __RANGE_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/reassemble.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/reassemble.h deleted file mode 100644 index c8581727..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/reassemble.h +++ /dev/null @@ -1,316 +0,0 @@ -/* reassemble.h - * Declarations of outines for {fragment,segment} reassembly - * - * $Id: reassemble.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* make sure that all flags that are set in a fragment entry is also set for - * the flags field of fd_head !!! - */ - -/* only in fd_head: packet is defragmented */ -#define FD_DEFRAGMENTED 0x0001 - -/* there are overlapping fragments */ -#define FD_OVERLAP 0x0002 - -/* overlapping fragments contain different data */ -#define FD_OVERLAPCONFLICT 0x0004 - -/* more than one fragment which indicates end-of data */ -#define FD_MULTIPLETAILS 0x0008 - -/* fragment contains data past the end of the datagram */ -#define FD_TOOLONGFRAGMENT 0x0010 - -/* fragment data not alloced, fd->data pointing to fd_head->data+fd->offset */ -#define FD_NOT_MALLOCED 0x0020 - -/* this flag is used to request fragment_add to continue the reassembly process */ -#define FD_PARTIAL_REASSEMBLY 0x0040 - -/* fragment offset is indicated by sequence number and not byte offset - into the defragmented packet */ -#define FD_BLOCKSEQUENCE 0x0100 - -/* if REASSEMBLE_FLAGS_CHECK_DATA_PRESENT is set, and the first fragment is - * incomplete, this flag is set in the flags word on the fd_head returned. - * - * It's all a fudge to preserve historical behaviour. - */ -#define FD_DATA_NOT_PRESENT 0x0200 - -/* This flag is set in the to denote that datalen has ben set to a valid value. - * It's implied by FD_DEFRAGMENTED (we must know the total length of the - * datagram if we have defragmented it...) - */ -#define FD_DATALEN_SET 0x0400 - -typedef struct _fragment_data { - struct _fragment_data *next; - guint32 frame; - guint32 offset; - guint32 len; - guint32 datalen; /* Only valid in first item of list and when - * flags&FD_DATALEN_SET is set; - * number of bytes or (if flags&FD_BLOCKSEQUENCE set) - * segments in the datagram */ - guint32 reassembled_in; /* frame where this PDU was reassembled, - only valid in the first item of the list - and when FD_DEFRAGMENTED is set*/ - guint32 flags; - unsigned char *data; -} fragment_data; - - -/* - * Flags for fragment_add_seq_* - */ - -/* we don't have any sequence numbers - fragments are assumed to appear in - * order */ -#define REASSEMBLE_FLAGS_NO_FRAG_NUMBER 0x0001 - -/* a special fudge for the 802.11 dissector */ -#define REASSEMBLE_FLAGS_802_11_HACK 0x0002 - -/* causes fragment_add_seq_key to check that all the fragment data is present - * in the tvb, and if not, do something a bit odd. */ -#define REASSEMBLE_FLAGS_CHECK_DATA_PRESENT 0x0004 - -/* a function for copying hash keys */ -typedef void *(*fragment_key_copier)(const void *key); - - -/* - * Initialize a fragment table. - */ -extern void fragment_table_init(GHashTable **fragment_table); -extern void dcerpc_fragment_table_init(GHashTable **fragment_table); - -/* - * Initialize a reassembled-packet table. - */ -extern void reassembled_table_init(GHashTable **reassembled_table); - -/* - * Free up all space allocated for fragment keys and data. - */ -void reassemble_init(void); - -/* - * This function adds a new fragment to the fragment hash table. - * If this is the first fragment seen for this datagram, a new entry - * is created in the hash table, otherwise this fragment is just added - * to the linked list of fragments for this packet. - * The list of fragments for a specific datagram is kept sorted for - * easier handling. - * - * Returns a pointer to the head of the fragment data list if we have all the - * fragments, NULL otherwise. - */ -extern fragment_data *fragment_add(tvbuff_t *tvb, int offset, packet_info *pinfo, - guint32 id, GHashTable *fragment_table, guint32 frag_offset, - guint32 frag_data_len, gboolean more_frags); -extern fragment_data *fragment_add_multiple_ok(tvbuff_t *tvb, int offset, - packet_info *pinfo, guint32 id, GHashTable *fragment_table, - guint32 frag_offset, guint32 frag_data_len, gboolean more_frags); - -/* - * This routine extends fragment_add to use a "reassembled_table". - * - * If, after processing this fragment, we have all the fragments, they - * remove that from the fragment hash table if necessary and add it - * to the table of reassembled fragments, and return a pointer to the - * head of the fragment list. - */ -extern fragment_data *fragment_add_check(tvbuff_t *tvb, int offset, - packet_info *pinfo, guint32 id, GHashTable *fragment_table, - GHashTable *reassembled_table, guint32 frag_offset, - guint32 frag_data_len, gboolean more_frags); - -/* same as fragment_add() but this one assumes frag_number is a block - sequence number. note that frag_number is 0 for the first fragment. */ - -/* - * These functions add a new fragment to the fragment hash table, - * assuming that frag_number is a block sequence number (starting from zero for - * the first fragment of each datagram). - * - * If this is the first fragment seen for this datagram, a new - * "fragment_data" structure is allocated to refer to the reassembled - * packet, and: - * - * if "more_frags" is false, and either we have no sequence numbers, or - * are using the 802.11 hack, it is assumed that this is the only fragment - * in the datagram. The structure is not added to the hash - * table, and not given any fragments to refer to, but is just returned. - * - * In this latter case reassembly wasn't done (since there was only one - * fragment in the packet); dissectors can check the 'next' pointer on the - * returned list to see if this case was hit or not. - * - * Otherwise, this fragment is just added to the linked list of fragments - * for this packet; the fragment_data is also added to the fragment hash if - * necessary. - * - * If this packet completes assembly, these functions return the head of the - * fragment data; otherwise, they return null. - */ - -/* "key" should be an arbitrary key used for indexing the fragment hash; - * "key_copier" is called to copy the key to a more appropriate store before - * inserting a new entry to the hash. - */ -extern fragment_data * -fragment_add_seq_key(tvbuff_t *tvb, int offset, packet_info *pinfo, - void *key, fragment_key_copier key_copier, - GHashTable *fragment_table, guint32 frag_number, - guint32 frag_data_len, gboolean more_frags, - guint32 flags); - -/* a wrapper for fragment_add_seq_key - uses a key of source, dest and frame number */ -extern fragment_data *fragment_add_seq(tvbuff_t *tvb, int offset, packet_info *pinfo, - guint32 id, GHashTable *fragment_table, guint32 frag_number, - guint32 frag_data_len, gboolean more_frags); - -/* another wrapper for fragment_add_seq_key - uses a key of source, dest, frame - * number and act_id */ -extern fragment_data * -fragment_add_dcerpc_dg(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id, - void *act_id, - GHashTable *fragment_table, guint32 frag_number, - guint32 frag_data_len, gboolean more_frags); - -/* - * These routines extend fragment_add_seq_key to use a "reassembled_table". - * - * If, after processing this fragment, we have all the fragments, they - * remove that from the fragment hash table if necessary and add it - * to the table of reassembled fragments, and return a pointer to the - * head of the fragment list. - */ -extern fragment_data * -fragment_add_seq_check(tvbuff_t *tvb, int offset, packet_info *pinfo, - guint32 id, GHashTable *fragment_table, - GHashTable *reassembled_table, guint32 frag_number, - guint32 frag_data_len, gboolean more_frags); - -extern fragment_data * -fragment_add_seq_802_11(tvbuff_t *tvb, int offset, packet_info *pinfo, - guint32 id, GHashTable *fragment_table, - GHashTable *reassembled_table, guint32 frag_number, - guint32 frag_data_len, gboolean more_frags); - -extern fragment_data * -fragment_add_seq_next(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id, - GHashTable *fragment_table, GHashTable *reassembled_table, - guint32 frag_data_len, gboolean more_frags); - -extern void -fragment_start_seq_check(packet_info *pinfo, guint32 id, GHashTable *fragment_table, - guint32 tot_len); - -extern fragment_data * -fragment_end_seq_next(packet_info *pinfo, guint32 id, GHashTable *fragment_table, - GHashTable *reassembled_table); -/* to specify how much to reassemble, for fragmentation where last fragment can not be - * identified by flags or such. - * note that for FD_BLOCKSEQUENCE tot_len is the index for the tail fragment. - * i.e. since the block numbers start at 0, if we specify tot_len==2, that - * actually means we want to defragment 3 blocks, block 0, 1 and 2. - * - */ -extern void -fragment_set_tot_len(packet_info *pinfo, guint32 id, GHashTable *fragment_table, - guint32 tot_len); - -/* to resad whatever totlen previously set */ -extern guint32 -fragment_get_tot_len(packet_info *pinfo, guint32 id, GHashTable *fragment_table); - -/* - * This function will set the partial reassembly flag(FD_PARTIAL_REASSEMBLY) for a fh. - * When this function is called, the fh MUST already exist, i.e. - * the fh MUST be created by the initial call to fragment_add() before - * this function is called. Also note that this function MUST be called to indicate - * a fh will be extended (increase the already stored data). After calling this function, - * and if FD_DEFRAGMENTED is set, the reassembly process will be continued. - */ -extern void -fragment_set_partial_reassembly(packet_info *pinfo, guint32 id, GHashTable *fragment_table); - -/* This function is used to check if there is partial or completed reassembly state - * matching this packet. I.e. Are there reassembly going on or not for this packet? - */ -extern fragment_data * -fragment_get(packet_info *pinfo, guint32 id, GHashTable *fragment_table); - -/* The same for the reassemble table */ -/* id *must* be the frame number for this to work! */ -extern fragment_data * -fragment_get_reassembled(packet_info *pinfo, guint32 id, GHashTable *reassembled_table); - -extern fragment_data * -fragment_get_reassembled_id(packet_info *pinfo, guint32 id, GHashTable *reassembled_table); - -/* This will free up all resources and delete reassembly state for this PDU. - * Except if the PDU is completely reassembled, then it would NOT deallocate the - * buffer holding the reassembled data but instead return the pointer to that - * buffer. - * - * So, if you call fragment_delete and it returns non-NULL, YOU are responsible to - * g_free() that buffer. - */ -extern unsigned char * -fragment_delete(packet_info *pinfo, guint32 id, GHashTable *fragment_table); - -/* hf_fragment, hf_fragment_error, and hf_reassembled_in should be - FT_FRAMENUM, the others should be FT_BOOLEAN -*/ -typedef struct _fragment_items { - gint *ett_fragment; - gint *ett_fragments; - - int *hf_fragments; - int *hf_fragment; - int *hf_fragment_overlap; - int *hf_fragment_overlap_conflict; - int *hf_fragment_multiple_tails; - int *hf_fragment_too_long_fragment; - int *hf_fragment_error; - int *hf_reassembled_in; - - const char *tag; -} fragment_items; - -extern tvbuff_t * -process_reassembled_data(tvbuff_t *tvb, int offset, packet_info *pinfo, - const char *name, fragment_data *fd_head, const fragment_items *fit, - gboolean *update_col_infop, proto_tree *tree); - -extern gboolean -show_fragment_tree(fragment_data *ipfd_head, const fragment_items *fit, - proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, proto_item **fi); - -extern gboolean -show_fragment_seq_tree(fragment_data *ipfd_head, const fragment_items *fit, - proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, proto_item **fi); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/reedsolomon.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/reedsolomon.h deleted file mode 100644 index 433f6e1e..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/reedsolomon.h +++ /dev/null @@ -1,86 +0,0 @@ -#ifdef __cplusplus -extern "C" { -#endif - -/* Global definitions for Reed-Solomon encoder/decoder - * Phil Karn KA9Q, September 1996 - */ -/* Set one of these to enable encoder/decoder debugging and error checking, - * at the expense of speed */ -/* #undef DEBUG 1*/ -/* #undef DEBUG 2*/ -#undef DEBUG - -/* To select the CCSDS standard (255,223) code, define CCSDS. This - * implies standard values for MM, KK, B0 and PRIM. - */ -/* #undef CCSDS 1*/ -#undef CCSDS -#ifndef CCSDS - -/* Otherwise, leave CCSDS undefined and set the parameters below: - * - * Set MM to be the size of each code symbol in bits. The Reed-Solomon - * block size will then be NN = 2**M - 1 symbols. Supported values are - * defined in rs.c. - */ -#define MM 8 /* Symbol size in bits */ - -/* - * Set KK to be the number of data symbols in each block, which must be - * less than the block size. The code will then be able to correct up - * to NN-KK erasures or (NN-KK)/2 errors, or combinations thereof with - * each error counting as two erasures. - */ -#define KK 207 /* Number of data symbols per block */ - -/* Set B0 to the first root of the generator polynomial, in alpha form, and - * set PRIM to the power of alpha used to generate the roots of the - * generator polynomial. The generator polynomial will then be - * @**PRIM*B0, @**PRIM*(B0+1), @**PRIM*(B0+2)...@**PRIM*(B0+NN-KK) - * where "@" represents a lower case alpha. - */ -#define B0 1 /* First root of generator polynomial, alpha form */ -#define PRIM 1 /* power of alpha used to generate roots of generator poly */ -#define STANDARD_ORDER - -/* If you want to select your own field generator polynomial, you'll have - * to edit that in rs.c. - */ - -#else /* CCSDS */ -/* Don't change these, they're CCSDS standard */ -#define MM 8 -#define KK 223 -#define B0 112 -#define PRIM 11 -#endif - -#define NN ((1 << MM) - 1) - -#if MM <= 8 -typedef unsigned char dtype; -#else -typedef unsigned int dtype; -#endif - -/* Reed-Solomon encoding - * data[] is the input block, parity symbols are placed in bb[] - * bb[] may lie past the end of the data, e.g., for (255,223): - * encode_rs(&data[0],&data[223]); - */ -int encode_rs(dtype data[], dtype bb[]); - -/* Reed-Solomon erasures-and-errors decoding - * The received block goes into data[], and a list of zero-origin - * erasure positions, if any, goes in eras_pos[] with a count in no_eras. - * - * The decoder corrects the symbols in place, if possible and returns - * the number of corrected symbols. If the codeword is illegal or - * uncorrectible, the data array is unchanged and -1 is returned - */ -int eras_dec_rs(dtype data[], int eras_pos[], int no_eras); - -#ifdef __cplusplus -} -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/report_err.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/report_err.h deleted file mode 100644 index c29df457..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/report_err.h +++ /dev/null @@ -1,61 +0,0 @@ -/* report_err.h - * Declarations of routines for dissectors to use to report errors to - * the user (e.g., problems with preference settings) - * - * $Id: report_err.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __REPORT_ERR_H__ -#define __REPORT_ERR_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* - * Initialize the report err routines - */ -extern void init_report_err( - void (*report_failure)(const char *, va_list), - void (*report_open_failure)(const char *, int, gboolean), - void (*report_read_failure)(const char *, int)); - -/* - * Report an error when trying to open a file. - */ -extern void report_open_failure(const char *filename, int err, - gboolean for_writing); - -/* - * Report an error when trying to read a file. - */ -extern void report_read_failure(const char *filename, int err); - -/* - * Report a general error. - */ -extern void report_failure(const char *msg_format, ...); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __REPORT_ERR_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/req_resp_hdrs.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/req_resp_hdrs.h deleted file mode 100644 index 40e68884..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/req_resp_hdrs.h +++ /dev/null @@ -1,43 +0,0 @@ -/* req_resp_hdrs.h - * Declarations of routines handling protocols with a request/response line, - * headers, a blank line, and an optional body. - * - * $Id: req_resp_hdrs.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __REQ_RESP_HDRS_H__ -#define __REQ_RESP_HDRS_H__ - -/** - * Optionally do reassembly of the request/response line, headers, and body. - * - * @param tvb The buffer. - * @param offset The offset in the buffer to begin inspection. - * @param pinfo Packet info from the parent protocol. - * @param desegment_headers Do desegmentation on headers. - * @param desegment_body Do desegmenation on body. - * @return TRUE if desegmentation is complete otherwise FALSE - */ -extern gboolean -req_resp_hdrs_do_reassembly(tvbuff_t *tvb, const int offset, packet_info *pinfo, - const gboolean desegment_headers, const gboolean desegment_body); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/rtp_pt.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/rtp_pt.h deleted file mode 100644 index 0ddb9b9a..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/rtp_pt.h +++ /dev/null @@ -1,68 +0,0 @@ -/* rtp_pt.h - * Defines RTP payload types - * - * $Id: rtp_pt.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __RTP_PT_H__ -#define __RTP_PT_H__ - -#include "epan/value_string.h" - -/* - * RTP Payload types - * Table B.2 / H.225.0 - * Also RFC 1890, and - * - * http://www.iana.org/assignments/rtp-parameters - */ -#define PT_PCMU 0 /* RFC 1890 */ -#define PT_1016 1 /* RFC 1890 */ -#define PT_G721 2 /* RFC 1890 */ -#define PT_GSM 3 /* RFC 1890 */ -#define PT_G723 4 /* From Vineet Kumar of Intel; see the Web page */ -#define PT_DVI4_8000 5 /* RFC 1890 */ -#define PT_DVI4_16000 6 /* RFC 1890 */ -#define PT_LPC 7 /* RFC 1890 */ -#define PT_PCMA 8 /* RFC 1890 */ -#define PT_G722 9 /* RFC 1890 */ -#define PT_L16_STEREO 10 /* RFC 1890 */ -#define PT_L16_MONO 11 /* RFC 1890 */ -#define PT_QCELP 12 /* Qualcomm Code Excited Linear Predictive coding? */ -#define PT_CN 13 /* RFC 3389 */ -#define PT_MPA 14 /* RFC 1890, RFC 2250 */ -#define PT_G728 15 /* RFC 1890 */ -#define PT_DVI4_11025 16 /* from Joseph Di Pol of Sun; see the Web page */ -#define PT_DVI4_22050 17 /* from Joseph Di Pol of Sun; see the Web page */ -#define PT_G729 18 -#define PT_CN_OLD 19 /* Payload type reserved (old version Comfort Noise) */ -#define PT_CELB 25 /* RFC 2029 */ -#define PT_JPEG 26 /* RFC 2435 */ -#define PT_NV 28 /* RFC 1890 */ -#define PT_H261 31 /* RFC 2032 */ -#define PT_MPV 32 /* RFC 2250 */ -#define PT_MP2T 33 /* RFC 2250 */ -#define PT_H263 34 /* from Chunrong Zhu of Intel; see the Web page */ - -WS_VAR_IMPORT const value_string rtp_payload_type_vals[]; -WS_VAR_IMPORT const value_string rtp_payload_type_short_vals[]; - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sctpppids.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sctpppids.h deleted file mode 100644 index 523a04a8..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sctpppids.h +++ /dev/null @@ -1,50 +0,0 @@ -/* sctpppids.h - * Declarations of SCTP payload protocol IDs. - * - * $Id: sctpppids.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __SCTPPPIDS_H__ -#define __SCTPPPIDS_H__ - -/* - * SCTP payload protocol IDs. - */ -#define NOT_SPECIFIED_PROTOCOL_ID 0 -#define IUA_PAYLOAD_PROTOCOL_ID 1 -#define M2UA_PAYLOAD_PROTOCOL_ID 2 -#define M3UA_PAYLOAD_PROTOCOL_ID 3 -#define SUA_PAYLOAD_PROTOCOL_ID 4 -#define M2PA_PAYLOAD_PROTOCOL_ID 5 -#define V5UA_PAYLOAD_PROTOCOL_ID 6 -#define H248_PAYLOAD_PROTOCOL_ID 7 -#define BICC_PAYLOAD_PROTOCOL_ID 8 -#define TALI_PAYLOAD_PROTOCOL_ID 9 -#define DUA_PAYLOAD_PROTOCOL_ID 10 -#define ASAP_PAYLOAD_PROTOCOL_ID 11 -#define ENRP_PAYLOAD_PROTOCOL_ID 12 -#define H323_PAYLOAD_PROTOCOL_ID 13 -#define QIPC_PAYLOAD_PROTOCOL_ID 14 -#define SIMCO_PAYLOAD_PROTOCOL_ID 15 -#define DDP_SEG_CHUNK_PROTOCOL_ID 16 -#define DDP_STREAM_SES_CTRL_PROTOCOL_ID 17 -#define M2TP_PAYLOAD_PROTOCOL_ID 99 /* s-link */ -#endif /* sctpppids.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sigcomp-udvm.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sigcomp-udvm.h deleted file mode 100644 index bcbb58fb..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sigcomp-udvm.h +++ /dev/null @@ -1,49 +0,0 @@ -/* udvm.h - * Routines making up the Univerasl Decompressor Virtual Machine (UDVM) used for - * Signaling Compression (SigComp) dissection. - * Copyright 2004, Anders Broman - * - * $Id: sigcomp-udvm.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * References: - * http://www.ietf.org/rfc/rfc3320.txt?number=3320 - * http://www.ietf.org/rfc/rfc3321.txt?number=3321 - * Useful links : - * http://www.ietf.org/internet-drafts/draft-ietf-rohc-sigcomp-impl-guide-02.txt - * http://www.ietf.org/internet-drafts/draft-ietf-rohc-sigcomp-sip-01.txt - */ - -#ifndef SIGCOMP_UDVM_H -#define SIGCOMP_UDVM_H - -#define UDVM_MEMORY_SIZE 65536 - -extern tvbuff_t* decompress_sigcomp_message(tvbuff_t *bytecode_tvb, tvbuff_t *message_tvb, packet_info *pinfo, - proto_tree *tree, gint destination, - gint print_flags, gint hf_id, gint header_len, - gint byte_code_state_len, gint byte_code_id_len, - gint udvm_start_ip); - - - -/* example: extern const value_string q931_cause_location_vals[]; */ -#endif -/* SIGCOMP_UDVM_H */ - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sigcomp_state_hdlr.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sigcomp_state_hdlr.h deleted file mode 100644 index 1a5beaf2..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sigcomp_state_hdlr.h +++ /dev/null @@ -1,49 +0,0 @@ -/* sigcomp_state_hdlr.c - * Routines making up the State handler of the Univerasl Decompressor Virtual Machine (UDVM) - * used for Signaling Compression (SigComp) dissection. - * Copyright 2004, Anders Broman - * - * $Id: sigcomp_state_hdlr.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * References: - * http://www.ietf.org/rfc/rfc3320.txt?number=3320 - * http://www.ietf.org/rfc/rfc3321.txt?number=3321 - * Useful links : - * http://www.ietf.org/internet-drafts/draft-ietf-rohc-sigcomp-impl-guide-03.txt - * http://www.ietf.org/internet-drafts/draft-ietf-rohc-sigcomp-sip-01.txt - */ - -#ifndef SIGCOMP_STATE_HDLR_H -#define SIGCOMP_STATE_HDLR_H - -extern const value_string result_code_vals[]; -extern int udvm_state_access(tvbuff_t *tvb, proto_tree *tree,guint8 *buff,guint16 p_id_start, guint16 p_id_length, guint16 state_begin, guint16 *state_length, - guint16 *state_address, guint16 *state_instruction, gint hf_id); - -extern void udvm_state_create(guint8 *state_buff,guint8 *state_identifier_buff,guint16 p_id_length); -extern void udvm_state_free(guint8 buff[],guint16 p_id_start,guint16 p_id_length); - -extern void sigcomp_init_udvm(void); - -#define STATE_BUFFER_SIZE 20 -#define STATE_MIN_ACCESS_LEN 6 - -#endif -/* SIGCOMP_STATE_HDLR_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/slab.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/slab.h deleted file mode 100644 index c84e50ca..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/slab.h +++ /dev/null @@ -1,75 +0,0 @@ -/* slab.h - * Definitions for very simple slab handling - * - * $Id: slab.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __SLAB_H__ -#define __SLAB_H__ - -#define NITEMS_PER_SLAB 100 - -/* - * Generate declaration of a union type containing the specified type of - * slab-allocated item, and a pointer to an object of that type, for use - * in the macros below. - */ -#define SLAB_ITEM_TYPE_DEFINE(type) \ - union type ## slab_item { \ - type slab_item; \ - union type ## slab_item *next_free; \ - }; - -/* - * Generate definition of the free list pointer. - */ -#define SLAB_FREE_LIST_DEFINE(type) \ - union type ## slab_item *type ## _free_list = NULL; - -/* - * Generate an external declaration of the free list pointer. - */ -#define SLAB_FREE_LIST_DECLARE(type) \ - union type ## slab_item *type ## _free_list; - -/* we never free any memory we have allocated, when it is returned to us - we just store it in the free list until (hopefully) it gets used again -*/ -#define SLAB_ALLOC(item, type) \ - if(!type ## _free_list){ \ - int i; \ - union type ## slab_item *tmp; \ - tmp=g_malloc(NITEMS_PER_SLAB*sizeof(*tmp)); \ - for(i=0;islab_item); \ - type ## _free_list = type ## _free_list->next_free; - -#define SLAB_FREE(item, type) \ -{ \ - ((union type ## slab_item *)item)->next_free = type ## _free_list; \ - type ## _free_list = (union type ## slab_item *)item; \ -} - -#endif /* slab.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sminmpec.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sminmpec.h deleted file mode 100644 index b81ea7c2..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sminmpec.h +++ /dev/null @@ -1,83 +0,0 @@ -/* sminmpec.h - * SMI Network Management Private Enterprise Codes for organizations - * - * $Id: sminmpec.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2004 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __SMINMPEC_H__ -#define __SMINMPEC_H__ - -/* - * These are SMI Network Management Private Enterprise Codes for - * organizations; see - * - * http://www.iana.org/assignments/enterprise-numbers - * - * for a list. - */ -#define VENDOR_IETF 0 /* reserved - used by the IETF in L2TP? */ -#define VENDOR_ACC 5 -#define VENDOR_CISCO 9 -#define VENDOR_HEWLETT_PACKARD 11 -#define VENDOR_SUN_MICROSYSTEMS 42 -#define VENDOR_MERIT 61 -#define VENDOR_MOTOROLA 161 -#define VENDOR_SHIVA 166 -#define VENDOR_ERICSSON 193 -#define VENDOR_CISCO_VPN5000 255 -#define VENDOR_LIVINGSTON 307 -#define VENDOR_MICROSOFT 311 -#define VENDOR_3COM 429 -#define VENDOR_ASCEND 529 -#define VENDOR_BAY 1584 -#define VENDOR_FOUNDRY 1991 -#define VENDOR_VERSANET 2180 -#define VENDOR_REDBACK 2352 -#define VENDOR_JUNIPER 2636 -#define VENDOR_APTIS 2637 -#define VENDOR_DT_AG 2937 -#define VENDOR_CISCO_VPN3000 3076 -#define VENDOR_COSINE 3085 -#define VENDOR_SHASTA 3199 -#define VENDOR_NETSCREEN 3224 -#define VENDOR_NOMADIX 3309 -#define VENDOR_T_MOBILE 3414 /* Former VoiceStream Wireless, Inc. */ -#define VENDOR_SIEMENS 4329 -#define VENDOR_CABLELABS 4491 -#define VENDOR_UNISPHERE 4874 -#define VENDOR_CISCO_BBSM 5263 -#define VENDOR_THE3GPP2 5535 -#define VENDOR_IP_UNPLUGGED 5925 -#define VENDOR_ISSANNI 5948 -#define VENDOR_DE_TE_MOBIL 6490 -#define VENDOR_QUINTUM 6618 -#define VENDOR_INTERLINK 6728 -#define VENDOR_COLUBRIS 8744 -#define VENDOR_COLUMBIA_UNIVERSITY 11862 -#define VENDOR_THE3GPP 10415 -#define VENDOR_GEMTEK_SYSTEMS 10529 -#define VENDOR_WIFI_ALLIANCE 14122 -#define VENDOR_T_SYSTEMS_NOVA 16787 - - -WS_VAR_IMPORT const value_string sminmpec_values[]; - -#endif /* __SMINMPEC_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sna-utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sna-utils.h deleted file mode 100644 index 8782af88..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sna-utils.h +++ /dev/null @@ -1,41 +0,0 @@ -/* sna-utils.h - * Definitions for SNA dissection. - * - * $Id: sna-utils.h 3992 2008-06-10 03:13:11Z dgu $ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __SNA_UTILS__ -#define __SNA_UTILS__ - -#include -#include - -/* - * Structure used to represent an FID Type 4 address; gives the layout of the - * data pointed to by an AT_SNA "address" structure if the size is - * SNA_FID_TYPE_4_ADDR_LEN. - */ -#define SNA_FID_TYPE_4_ADDR_LEN 6 -struct sna_fid_type_4_addr { - guint32 saf; - guint16 ef; -}; - -extern gchar *sna_fid_to_str(const address *addr); -extern void sna_fid_to_str_buf(const address *addr, gchar *buf, int buf_len); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stat_cmd_args.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stat_cmd_args.h deleted file mode 100644 index 56233f61..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stat_cmd_args.h +++ /dev/null @@ -1,35 +0,0 @@ -/* stat_cmd_args.h - * Declarations of routines to register "-z" command-line argument handlers - * for stats - * - * $Id: stat_cmd_args.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef _STAT_H_ -#define _STAT_H_ - -extern void register_stat_cmd_arg(const char *cmd, - void (*func)(const char *arg,void* userdata), void* userdata); -extern gboolean process_stat_cmd_arg(char *optarg); -extern void list_stat_cmd_args(void); -extern void start_requested_stats(void); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stats_tree.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stats_tree.h deleted file mode 100644 index ff36fd95..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stats_tree.h +++ /dev/null @@ -1,147 +0,0 @@ -/* stats_tree.h - * A counter tree API for Wireshark dissectors - * 2005, Luis E. G. Ontanon - * - * $Id: stats_tree.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#ifndef __STATS_TREE_H -#define __STATS_TREE_H - -#include -#include -#include -#include -#include -#include "../register.h" - -#define STAT_TREE_ROOT "root" - -/* obscure information regarding the stats_tree */ -typedef struct _stats_tree stats_tree; - -/* tap packet callback for stats_tree */ -typedef int (*stat_tree_packet_cb)(stats_tree*, - packet_info*, - epan_dissect_t*, - const void *); - -/* stats_tree initilaization callback */ -typedef void (*stat_tree_init_cb)(stats_tree*); - -/* stats_tree initilaization callback */ -typedef void (*stat_tree_cleanup_cb)(stats_tree*); - -/* registers a new stats tree - * abbr: protocol abbr - * name: protocol name - * packet: per packet callback - * init: tree initialization callback - */ -extern void stats_tree_register(const guint8* tapname, - const guint8* abbr, - const guint8* name, - stat_tree_packet_cb packet, - stat_tree_init_cb init, - stat_tree_cleanup_cb cleanup); - -extern int stats_tree_parent_id_by_name(stats_tree* st, const gchar* parent_name); - -/* Creates a node in the tree (to be used in the in init_cb) -* st: the stats_tree in which to create it -* name: the name of the new node -* parent_name: the name of the parent_node (NULL for root) -* with_children: TRUE if this node will have "dynamically created" children -*/ -extern int stats_tree_create_node(stats_tree* st, - const gchar* name, - int parent_id, - gboolean with_children); - -/* creates a node using it's parent's tree name */ -extern int stats_tree_create_node_by_pname(stats_tree* st, - const gchar* name, - const gchar* parent_name, - gboolean with_children); - -/* creates a node in the tree, that will contain a ranges list. - example: - stats_tree_create_range_node(st,name,parent, - "-99","100-199","200-299","300-399","400-", NULL); -*/ -extern int stats_tree_create_range_node(stats_tree* st, - const gchar* name, - int parent_id, - ...); - -extern int stats_tree_range_node_with_pname(stats_tree* st, - const gchar* name, - const gchar* parent_name, - ...); - -/* increases by one the ranged node and the sub node to whose range the value belongs */ -extern int stats_tree_tick_range(stats_tree* st, - const gchar* name, - int parent_id, - int value_in_range); - -#define stats_tree_tick_range_by_pname(st,name,parent_name,value_in_range) \ - stats_tree_tick_range((st),(name),stats_tree_parent_id_by_name((st),(parent_name),(value_in_range)) - -/* */ -extern int stats_tree_create_pivot(stats_tree* st, - const gchar* name, - int parent_id); - -extern int stats_tree_create_pivot_by_pname(stats_tree* st, - const gchar* name, - const gchar* parent_name); - -extern int stats_tree_tick_pivot(stats_tree* st, - int pivot_id, - const gchar* pivot_value); - -/* - * manipulates the value of the node whose name is given - * if the node does not exist yet it's created (with counter=1) - * using parent_name as parent node (NULL for root). - * with_children=TRUE to indicate that the created node will be a parent - */ -typedef enum _manip_node_mode { MN_INCREASE, MN_SET } manip_node_mode; -extern int stats_tree_manip_node(manip_node_mode mode, - stats_tree* st, - const guint8* name, - int parent_id, - gboolean with_children, - gint value); - -#define increase_stat_node(st,name,parent_id,with_children,value) \ -(stats_tree_manip_node(MN_INCREASE,(st),(name),(parent_id),(with_children),(value))) - -#define tick_stat_node(st,name,parent_id,with_children) \ -(stats_tree_manip_node(MN_INCREASE,(st),(name),(parent_id),(with_children),1)) - -#define set_stat_node(st,name,parent_id,with_children,value) \ -(stats_tree_manip_node(MN_SET,(st),(name),(parent_id),(with_children),value)) - -#define zero_stat_node(st,name,parent_id,with_children) \ -(stats_tree_manip_node(MN_SET,(st),(name),(parent_id),(with_children),0)) - -#endif /* __STATS_TREE_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stats_tree_priv.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stats_tree_priv.h deleted file mode 100644 index 80ca6a11..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stats_tree_priv.h +++ /dev/null @@ -1,202 +0,0 @@ -/* stats_tree_priv.h - * implementor's API for stats_tree - * 2005, Luis E. G. Ontanon - * - * $Id: stats_tree_priv.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __STATS_TREE_PRIV_H -#define __STATS_TREE_PRIV_H - -#include "stats_tree.h" - -#define INDENT_MAX 32 -#define NUM_BUF_SIZE 32 - -/* implementations should define this to contain its own node related data - * as well as some operations on it */ -typedef struct _st_node_pres st_node_pres; - -/* implementations should define this to contain its own dynamic tree related data -* as well as some operations on it */ -typedef struct _tree_pres tree_pres; - -/* implementations should define this to contain its own static tree related data -* as well as some operations on it */ -typedef struct _tree_cfg_pres tree_cfg_pres; - - -typedef struct _stat_node stat_node; -typedef struct _stats_tree_cfg stats_tree_cfg; - -typedef struct _range_pair { - gint floor; - gint ceil; -} range_pair_t; - -struct _stat_node { - gchar* name; - int id; - - /* the counter it keeps */ - gint counter; - - /* children nodes by name */ - GHashTable* hash; - - /* the owner of this node */ - stats_tree* st; - - /* relatives */ - stat_node* parent; - stat_node* children; - stat_node* next; - - /* used to check if value is within range */ - range_pair_t* rng; - - /* node presentation data */ - st_node_pres* pr; -}; - -struct _stats_tree { - /* the "class" from which it's derived */ - stats_tree_cfg* cfg; - - char* filter; - - /* times */ - double start; - double elapsed; - - /* used to lookup named parents: - * key: parent node name - * value: parent node - */ - GHashTable* names; - - /* used for quicker lookups of parent nodes */ - GPtrArray* parents; - - /* - * tree representation - * to be defined (if needed) by the implementations - */ - tree_pres* pr; - - /* every tree in nature has one */ - stat_node root; -}; - -struct _stats_tree_cfg { - guint8* abbr; - guint8* name; - guint8* tapname; - - gboolean in_use; - - /* dissector defined callbacks */ - stat_tree_packet_cb packet; - stat_tree_init_cb init; - stat_tree_cleanup_cb cleanup; - - /* - * node presentation callbacks - */ - - /* last to be called at node creation */ - void (*setup_node_pr)(stat_node*); - - /* last to be called at node destruction */ - void (*free_node_pr)(stat_node*); - - /* to be called for every node in the tree */ - void (*draw_node)(stat_node*); - void (*reset_node)(stat_node*); - - /* - * tree presentation callbacks - */ - tree_cfg_pres* pr; - - - tree_pres* (*new_tree_pr)(stats_tree*); - void (*free_tree_pr)(stats_tree*); - void (*draw_tree)(stats_tree*); - void (*reset_tree)(stats_tree*); -}; - -/* guess what, this is it! */ -extern void stats_tree_presentation(void (*registry_iterator)(gpointer,gpointer,gpointer), - void (*setup_node_pr)(stat_node*), - void (*free_node_pr)(stat_node*), - void (*draw_node)(stat_node*), - void (*reset_node)(stat_node*), - tree_pres* (*new_tree_pr)(stats_tree*), - void (*free_tree_pr)(stats_tree*), - void (*draw_tree)(stats_tree*), - void (*reset_tree)(stats_tree*), - void* data); - -extern stats_tree* stats_tree_new(stats_tree_cfg* cfg, tree_pres* pr, char* filter); - -/* callback for taps */ -extern int stats_tree_packet(void*, packet_info*, epan_dissect_t*, const void *); - -/* callback for reset */ -extern void stats_tree_reset(void* p_st); - -/* callback for clear */ -extern void stats_tree_reinit(void* p_st); - -/* callback for destoy */ -extern void stats_tree_free(stats_tree* st); - -/* given an optarg splits the abbr part - and returns a newly allocated buffer containing it */ -extern guint8* stats_tree_get_abbr(const guint8* optarg); - -/* obtains a stats tree from the registry given its abbr */ -extern stats_tree_cfg* stats_tree_get_cfg_by_abbr(guint8* abbr); - -/* extracts node data as strings from a stat_node into - the buffers given by value, rate and precent - if NULL they are ignored */ -extern void stats_tree_get_strs_from_node(const stat_node* node, - guint8* value, - guint8* rate, - guint8* percent); - -/* populates the given GString with a tree representation of a branch given by node, - using indent spaces as indentation */ -extern void stats_tree_branch_to_str(const stat_node* node, - GString* s, - guint indent); - -/* used to calcuate the size of the indentation and the longest string */ -extern guint stats_tree_branch_max_namelen(const stat_node* node, guint indent); - -/* a text representation of a node, - if buffer is NULL returns a newly allocated string */ -extern guint8* stats_tree_node_to_str(const stat_node* node, - guint8* buffer, guint len); - -#endif /* __STATS_TREE_PRIV_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stream.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stream.h deleted file mode 100644 index 9fd1cc90..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stream.h +++ /dev/null @@ -1,138 +0,0 @@ -/* stream.h - * - * Definititions for handling circuit-switched protocols - * which are handled as streams, and don't have lengths - * and IDs such as are required for reassemble.h - * - * $Id: stream.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef STREAM_H -#define STREAM_H - -#include - -struct _fragment_items; - -/* A stream represents the concept of an arbitrary stream of data, - divided up into frames for transmission, where the frames have - little or no correspondence to the PDUs of the protocol being - streamed, and those PDUs are just delineated by a magic number. - - For example, we stream H.223 over IAX2. IAX2 has no concept of - H.223 PDUs and just divides the H.223 stream into 160-byte - frames. H.223 PDUs are delineated by two-byte magic numbers (which - may, of course, straddle an IAX2 frame boundary). - - Essentially we act as a wrapper to reassemble.h, by making up - PDU ids and keeping some additional data on fragments to allow the - PDUs to be defragmented again. -*/ - - -/* A stream_t represents a stream. There might be one or two streams - in a circuit, depending on whether that circuit is mono- or bi-directional. -*/ -typedef struct stream stream_t; - -/* Fragments in a PDU are represented using a stream_pdu_fragment_t, - and placed in a linked-list with other fragments in the PDU. - - (They're also placed in a hash so we can find them again later) -*/ -typedef struct stream_pdu_fragment stream_pdu_fragment_t; - - - -struct circuit; -struct conversation; - -/* initialise a new stream. Call this when you first identify a distinct - * stream. The circit pointer is just used as a key to look up the stream. */ -extern stream_t *stream_new_circ ( const struct circuit *circuit, int p2p_dir ); -extern stream_t *stream_new_conv ( const struct conversation *conv, int p2p_dir ); - -/* retrieve a previously-created stream. - * - * Returns null if no matching stream was found. - */ -extern stream_t *find_stream_circ ( const struct circuit *circuit, int p2p_dir ); -extern stream_t *find_stream_conv ( const struct conversation *conv, int p2p_dir ); - - - -/* see if we've seen this fragment before. - - The framenum and offset are just hash keys, so can be any values unique - to this frame, but the idea is that you use the number of the frame being - disassembled, and the byte-offset within that frame. -*/ -extern stream_pdu_fragment_t *stream_find_frag( stream_t *stream, guint32 framenum, guint32 offset ); - -/* add a new fragment to the fragment tables for the stream. The framenum and - * offset are keys allowing future access with stream_find_frag(), tvb is the - * fragment to be added, and pinfo is the information for the frame containing - * this fragment. more_frags should be set if this is the final fragment in the - * PDU. - * - * * the fragment must be later in the stream than any previous fragment - * (ie, framenum.offset must be greater than those passed on the previous - * call) - * - * This essentially means that you can only add fragments on the first pass - * through the stream. - */ -extern stream_pdu_fragment_t *stream_add_frag( stream_t *stream, guint32 framenum, guint32 offset, - tvbuff_t *tvb, packet_info *pinfo, gboolean more_frags ); - -/* Get the length of a fragment previously found by stream_find_frag(). - */ -extern guint32 stream_get_frag_length( const stream_pdu_fragment_t *frag); - -/* Get a handle on the top of the chain of fragment_datas underlying this PDU - * frag can be any fragment within a PDU, and it will always return the head of - * the chain - * - * Returns NULL until the last fragment is added. - */ -extern struct _fragment_data *stream_get_frag_data( const stream_pdu_fragment_t *frag); - -/* - * Process reassembled data; if this is the last fragment, put the fragment - * information into the protocol tree, and construct a tvbuff with the - * reassembled data, otherwise just put a "reassembled in" item into the - * protocol tree. - */ -extern tvbuff_t *stream_process_reassembled( - tvbuff_t *tvb, int offset, packet_info *pinfo, - char *name, const stream_pdu_fragment_t *frag, - const struct _fragment_items *fit, - gboolean *update_col_infop, proto_tree *tree); - -/* Get the PDU number. PDUs are numbered from zero within a stream. - * frag can be any fragment within a PDU. - */ -extern guint32 stream_get_pdu_no( const stream_pdu_fragment_t *frag); - -/* initialise the stream routines */ -void stream_init( void ); - -#endif /* STREAM_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/strutil.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/strutil.h deleted file mode 100644 index 4b108175..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/strutil.h +++ /dev/null @@ -1,243 +0,0 @@ -/* strutil.h - * String utility definitions - * - * $Id: strutil.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __STRUTIL_H__ -#define __STRUTIL_H__ - -/* ... thus, config.h needs to be #included */ - -/** @file - * String handling and conversion utilities. - */ - -/** Given a pointer into a data buffer, and to the end of the buffer, - * find the end of the (putative) line at that position in the data - * buffer. - * - * @param data A pointer to the beginning of the data - * @param dataend A pointer to the end of the data - * @param eol A pointer that will receive the EOL location - * @return A pointer to the EOL character(s) in "*eol". - */ -const guchar *find_line_end(const guchar *data, const guchar *dataend, - const guchar **eol); - -/** Get the length of the next token in a line, and the beginning of the - * next token after that (if any). - * @param linep A pointer to the beginning of the line - * @param lineend A pointer to the end of the line - * @param next_token Receives the location of the next token - * @return 0 if there is no next token. - */ -int get_token_len(const guchar *linep, const guchar *lineend, - const guchar **next_token); - -/** Given a string, generate a string from it that shows non-printable - * characters as C-style escapes, and return a pointer to it. - * - * @param line A pointer to the input string - * @param len The length of the input string - * @return A pointer to the formatted string - * - * @see tvb_format_text() - */ -gchar* format_text(const guchar *line, int len); - -gchar* format_text_wsp(const guchar *line, int len); - -/** Turn an array of bytes into a string showing the bytes in hex. - * - * @param bd A pointer to the byte array - * @param bd_len The length of the byte array - * @return A pointer to the formatted string - * - * @see bytes_to_str_punct() - */ -gchar* bytes_to_str(const guint8 *bd, int bd_len); - -/** Turn an array of bytes into a string showing the bytes in hex, - * separated by a punctuation character. - * - * @param bd A pointer to the byte array - * @param bd_len The length of the byte array - * @param punct The punctuation character - * @return A pointer to the formatted string - * - * @see bytes_to_str() - */ -gchar* bytes_to_str_punct(const guint8 *bd, int bd_len, gchar punct); - -/** Turn a string of hex digits with optional separators (defined by - * is_byte_sep() into a byte array. - * - * @param hex_str The string of hex digits. - * @param bytes The GByteArray that will receive the bytes. This - * must be initialized by the caller. - * @param force_separators If set to TRUE, separators MUST exist between - * bytes. - * @return True if the string was converted successfully - */ -gboolean hex_str_to_bytes(const char *hex_str, GByteArray *bytes, - gboolean force_separators); - -/** Turn an RFC 3986 percent-encoded string into a byte array. - * - * @param uri_str The string of hex digits. - * @param bytes The GByteArray that will receive the bytes. This - * must be initialized by the caller. - * @return True if the string was converted successfully - * @see format_uri() - */ -gboolean uri_str_to_bytes(const char *uri_str, GByteArray *bytes); - -/** Turn a byte array into an RFC 3986 percent-encoded string. - * - * @param bytes The GByteArray that will receive the bytes. This - * must be initialized by the caller. - * @param reserved_chars Normally the "gen-delims" and "sub-delims" - * from RFC 3986 (":/?#[]@" and "!$&'()*+,;=" respectively) - * plus space (hex value 20) are treated as reserved characters. - * If this variable is non-NULL, its contents will be used - * instead. - * @note Any non-printing character determined by isprint(), along - * with the % character itself are always reserved. - * @see uri_str_to_bytes(), format_text(), isprint() - */ -gchar* format_uri(const GByteArray *bytes, const gchar *reserved_chars); - -/** Turn a OID string representation (dot notation) into a byte array. - * - * @param oid_str The OID string (dot notaion). - * @param bytes The GByteArray that will receive the bytes. This - * must be initialized by the caller. - * @return True if the string was converted successfully - */ -gboolean oid_str_to_bytes(const char *oid_str, GByteArray *bytes); - -/** - * Create a copy of a GByteArray - * - * @param ba The byte array to be copied. - * @return If ba exists, a freshly allocated copy. NULL otherwise. - * - * XXX - Should this be in strutil.c? - */ -GByteArray *byte_array_dup(GByteArray *ba); - -/** - * Compare the contents of two GByteArrays - * - * @param ba1 A byte array - * @param ba2 A byte array - * @return If both arrays are non-NULL and their lengths are equal and - * their contents are equal, returns TRUE. Otherwise, returns - * FALSE. - * - * XXX - Should this be in strutil.c? - */ -gboolean byte_array_equal(GByteArray *ba1, GByteArray *ba2); - - -/** Return a XML escaped representation of the unescaped string. - * The returned string must be freed when no longer in use. - * - * @param unescaped The unescaped string - * @return An XML-escaped representation of the input string - */ -gchar* xml_escape(const gchar *unescaped); - -/** - * Return the first occurrence of needle in haystack. - * Algorithm copied from GNU's glibc 2.3.2 memcmp() - * - * @param haystack The data to search - * @param haystack_len The length of the search data - * @param needle The string to look for - * @param needle_len The length of the search string - * @return A pointer to the first occurrence of "needle" in - * "haystack". If "needle" isn't found or is NULL, or if - * "needle_len" is 0, NULL is returned. - */ -const guint8 * epan_memmem(const guint8 *haystack, guint haystack_len, - const guint8 *needle, guint needle_len); - -/* Surround a string or a macro, resolved to a string, with double quotes */ -#define _STRINGIFY(a) # a -#define STRINGIFY(a) _STRINGIFY(a) - -/** Scan a string to make sure it's valid hex. - * - * @param string The string to validate - * @param nbytes The length of the return buffer - * @return A pointer to a buffer containing the converted raw bytes. This - * buffer must be g_free()d by the caller. - */ -guint8 * convert_string_to_hex(const char *string, size_t *nbytes); - -/** Prep a string for case-sensitive vs case-insensitive searching. - * - * @param string The search string - * @param case_insensitive TRUE if case-insensitive, FALSE if not - * @return A direct copy of the string if it's a case-sensitive search and - * an uppercased version if not. In either case the string must be g_free()d - * by the caller. - */ -char * convert_string_case(const char *string, gboolean case_insensitive); - -/** Finds the first occurence of string 'needle' in string 'haystack'. - * The matching is done in a case insensitive manner. - * - * @param haystack The string possibly containing the substring - * @param needle The substring to be searched - * @return A pointer into 'haystack' where 'needle' is first found. - * Otherwise it returns NULL. - */ -char * epan_strcasestr(const char *haystack, const char *needle); - -/* g_strlcat() does not exist in GLib 1.2[.x] */ -#if GLIB_MAJOR_VERSION < 2 -gsize g_strlcat(gchar *dst, const gchar *src, gsize size); -gsize g_strlcpy(gchar *dest, const gchar *src, gsize dest_size); -#endif - -#if GLIB_MAJOR_VERSION < 2 -/* g_ascii_isprint() does not exist in GLib 1.2[.x]. - * assume all codes >=0x20 and <0x80 are ASCII printables. - */ -#define g_ascii_isprint(c) \ - (((c<0x20)||(c>=0x80))?FALSE:TRUE) -/* g_ascii_isxdigit() does not exist in Glib 1.2 */ -#define g_ascii_isxdigit(c) \ - ( ((c>='0')&&(c<='9'))?TRUE: \ - ( ((c>='a')&&(c<='f'))?TRUE: \ - (((c>='A')&&(c<='F'))?TRUE:FALSE) ) ) - -#endif - -#if GLIB_MAJOR_VERSION < 2 -/* g_byte_array_sized_new() doesnt exist in glib-1.2 */ -GByteArray *g_byte_array_sized_new(guint reserved_size); -#endif - -#endif /* __STRUTIL_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/t35.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/t35.h deleted file mode 100644 index 692c0b8d..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/t35.h +++ /dev/null @@ -1,35 +0,0 @@ -/* t35.h - * T.35 and H.221 tables - * 2003 Tomas Kukosa - * - * $Id: t35.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __T35_H__ -#define __T35_H__ - -#include "epan/value_string.h" - -extern const value_string T35CountryCode_vals[]; -extern const value_string T35Extension_vals[]; -extern const value_string H221ManufacturerCode_vals[]; - -#endif /* __T35_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tap-voip.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tap-voip.h deleted file mode 100644 index 21888588..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tap-voip.h +++ /dev/null @@ -1,59 +0,0 @@ -/* tap-voip.h - * VoIP packet tap interface 2007 Tomas Kukosa - * - * $Id: tap-voip.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef _TAP_VOIP_H_ -#define _TAP_VOIP_H_ - -/* defines voip call state */ -typedef enum _voip_call_state { - VOIP_NO_STATE, - VOIP_CALL_SETUP, - VOIP_RINGING, - VOIP_IN_CALL, - VOIP_CANCELLED, - VOIP_COMPLETED, - VOIP_REJECTED, - VOIP_UNKNOWN -} voip_call_state; - -typedef enum _voip_call_active_state { - VOIP_ACTIVE, - VOIP_INACTIVE -} voip_call_active_state; - -/* structure for common/proprietary VoIP calls TAP */ -typedef struct _voip_packet_info_t -{ - gchar *protocol_name; - gchar *call_id; - voip_call_state call_state; - voip_call_active_state call_active_state; - gchar *from_identity; - gchar *to_identity; - gchar *call_comment; - gchar *frame_label; - gchar *frame_comment; -} voip_packet_info_t; - -#endif /* _TAP_VOIP_H_ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tap.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tap.h deleted file mode 100644 index 11ca6fcb..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tap.h +++ /dev/null @@ -1,61 +0,0 @@ -/* tap.h - * packet tap interface 2002 Ronnie Sahlberg - * - * $Id: tap.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef _TAP_H_ -#define _TAP_H_ - -#include "epan/epan.h" - -#ifdef INTTYPES_H_DEFINES_FORMATS -#include -#endif - -/* With MSVC and a libwireshark.dll, we need a - * special declaration of num_tap_filters. - */ -WS_VAR_IMPORT int num_tap_filters; - -typedef void (*tap_reset_cb)(void *tapdata); -typedef int (*tap_packet_cb)(void *tapdata, packet_info *pinfo, epan_dissect_t *edt, const void *data); -typedef void (*tap_draw_cb)(void *tapdata); - - -extern void tap_init(void); -extern int register_tap(const char *name); -extern int find_tap_id(const char *name); -extern void tap_queue_packet(int tap_id, packet_info *pinfo, const void *tap_specific_data); -extern void tap_queue_init(epan_dissect_t *edt); -extern void tap_push_tapped_queue(epan_dissect_t *edt); -extern void reset_tap_listeners(void); -extern void draw_tap_listeners(gboolean draw_all); -extern GString *register_tap_listener(const char *tapname, void *tapdata, - const char *fstring, tap_reset_cb tap_reset, tap_packet_cb tap_packet, - tap_draw_cb tap_draw); -extern GString *set_tap_dfilter(void *tapdata, const char *fstring); -extern void remove_tap_listener(void *tapdata); -extern gboolean have_tap_listeners(void); -extern gboolean have_tap_listener(int tap_id); -extern const void *fetch_tapped_data(int tap_id, int idx); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tcap-persistentdata.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tcap-persistentdata.h deleted file mode 100644 index 4e9c278f..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tcap-persistentdata.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - * tcap-persistentdata.h - * Definitions for lists and hash tables used in wireshark's tcap dissector - * for calculation of delays in tcap-transactions - * Copyright 2006 Florent Drouin (based on h225-persistentdata from Lars Roland) - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * $Id: tcap-persistentdata.h 3992 2008-06-10 03:13:11Z dgu $ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __tcapsrt_HASH__ -#define __tcapsrt_HASH__ - -#include "epan/packet.h" -#include "epan/conversation.h" -#include "epan/dissectors/packet-tcap.h" - -#define LENGTH_OID 16 -struct tcaphash_context_t { - struct tcaphash_context_key_t * key; - guint32 session_id; - guint32 first_frame; - guint32 last_frame; - nstime_t begin_time; /* time of arrival of TC_BEGIN */ - nstime_t end_time; /* time of closing message */ - gboolean responded; /* true, if request has been responded */ - gboolean closed; - gboolean upper_dissector; - gboolean oid_present; - gchar oid[LENGTH_OID+1]; - gboolean subdissector_present; - dissector_handle_t subdissector_handle; - void (* callback) (tvbuff_t *,packet_info *, proto_tree *, struct tcaphash_context_t *); - struct tcaphash_begincall_t * begincall; - struct tcaphash_contcall_t * contcall; - struct tcaphash_endcall_t * endcall; - struct tcaphash_ansicall_t * ansicall; -}; - -struct tcaphash_begincall_t { - struct tcaphash_begin_info_key_t * beginkey; - struct tcaphash_context_t * context; - gboolean father; - struct tcaphash_begincall_t * next_begincall; - struct tcaphash_begincall_t * previous_begincall; -}; - -struct tcaphash_contcall_t { - struct tcaphash_cont_info_key_t * contkey; - struct tcaphash_context_t * context; - gboolean father; - struct tcaphash_contcall_t * next_contcall; - struct tcaphash_contcall_t * previous_contcall; -}; - -struct tcaphash_endcall_t { - struct tcaphash_end_info_key_t * endkey; - struct tcaphash_context_t * context; - gboolean father; - struct tcaphash_endcall_t * next_endcall; - struct tcaphash_endcall_t * previous_endcall; -}; - -struct tcaphash_ansicall_t { - struct tcaphash_ansi_info_key_t * ansikey; - struct tcaphash_context_t * context; - gboolean father; - struct tcaphash_ansicall_t * next_ansicall; - struct tcaphash_ansicall_t * previous_ansicall; -}; - -/* The Key for the hash table is the TCAP origine transaction identifier - of the TC_BEGIN containing the InitialDP */ - -struct tcaphash_context_key_t { - guint32 session_id; -}; - -struct tcaphash_begin_info_key_t { - guint32 hashKey; - guint32 tid; - guint32 opc_hash; - guint32 dpc_hash; -}; - -struct tcaphash_cont_info_key_t { - guint32 hashKey; - guint32 src_tid; - guint32 dst_tid; - guint32 opc_hash; - guint32 dpc_hash; -}; - -struct tcaphash_end_info_key_t { - guint32 hashKey; - guint32 tid; - guint32 opc_hash; - guint32 dpc_hash; -}; - -struct tcaphash_ansi_info_key_t { - guint32 hashKey; - guint32 tid; - guint32 opc_hash; - guint32 dpc_hash; -}; - - -/* List of infos to store for the analyse */ -struct tcapsrt_info_t { - guint32 tcap_session_id; - guint32 src_tid; - guint32 dst_tid; - guint8 ope; -}; - -void tcapsrt_init_routine(void); - -struct tcapsrt_info_t * tcapsrt_razinfo(void); - -void tcapsrt_close(struct tcaphash_context_t * p_tcaphash_context, - packet_info * pinfo _U_); - -struct tcaphash_context_t * tcapsrt_call_matching(tvbuff_t *tvb, - packet_info * pinfo _U_, - proto_tree *tree, - struct tcapsrt_info_t * p_tcap_info); - -WS_VAR_IMPORT gboolean gtcap_StatSRT; - -#endif /* __tcapsrt_HASH__*/ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tfs.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tfs.h deleted file mode 100644 index e77f0b9c..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tfs.h +++ /dev/null @@ -1,65 +0,0 @@ -/* tfs.h - * true_false strings - * Copyright 2007, Jaap Keuter - * - * $Id: tfs.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef __TFS_H__ -#define __TFS_H__ - -/* Struct for boolean enumerations */ -typedef struct true_false_string { - const char *true_string; - const char *false_string; -} true_false_string; - -/* - * A default set of true/false strings that dissectors can use for - * FT_BOOLEAN header fields. - */ -WS_VAR_IMPORT const true_false_string tfs_true_false; -WS_VAR_IMPORT const true_false_string tfs_yes_no; -WS_VAR_IMPORT const true_false_string tfs_set_notset; -WS_VAR_IMPORT const true_false_string tfs_enabled_disabled; -WS_VAR_IMPORT const true_false_string tfs_ok_error; -WS_VAR_IMPORT const true_false_string tfs_success_fail; -WS_VAR_IMPORT const true_false_string tfs_on_off; -WS_VAR_IMPORT const true_false_string tfs_ack_nack; -WS_VAR_IMPORT const true_false_string tfs_odd_even; -WS_VAR_IMPORT const true_false_string tfs_allow_block; -WS_VAR_IMPORT const true_false_string tfs_restricted_allowed; -WS_VAR_IMPORT const true_false_string tfs_accept_reject; -WS_VAR_IMPORT const true_false_string tfs_more_nomore; -WS_VAR_IMPORT const true_false_string tfs_present_absent; -WS_VAR_IMPORT const true_false_string tfs_active_inactive; -WS_VAR_IMPORT const true_false_string tfs_found_not_found; -WS_VAR_IMPORT const true_false_string tfs_command_response; -WS_VAR_IMPORT const true_false_string tfs_capable_not_capable; -WS_VAR_IMPORT const true_false_string tfs_supported_not_supported; - -/* - * Old true_false_string from packet.c - * Retained for backward compatibility until all dissectors are updated. - */ -WS_VAR_IMPORT const true_false_string flags_set_truth; - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/timestamp.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/timestamp.h deleted file mode 100644 index e357ee21..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/timestamp.h +++ /dev/null @@ -1,68 +0,0 @@ -/* timestamp.h - * Defines for packet timestamps - * - * $Id: timestamp.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __TIMESTAMP_H__ -#define __TIMESTAMP_H__ - -/* - * Type of time-stamp shown in the summary display. - */ -typedef enum { - TS_RELATIVE, /* Since start of capture */ - TS_ABSOLUTE, - TS_ABSOLUTE_WITH_DATE, - TS_DELTA, /* Since previous captured packet */ - TS_DELTA_DIS, /* Since previous displayed packet */ - TS_EPOCH, /* Seconds (and fractions) since epoch */ - -/* - * Special value used for the command-line setting in Wireshark, to indicate - * that no value has been set from the command line. - */ - TS_NOT_SET -} ts_type; - -typedef enum { - TS_PREC_AUTO, /* recent */ - TS_PREC_FIXED_SEC, /* recent and internal */ - TS_PREC_FIXED_DSEC, /* recent and internal */ - TS_PREC_FIXED_CSEC, /* recent and internal */ - TS_PREC_FIXED_MSEC, /* recent and internal */ - TS_PREC_FIXED_USEC, /* recent and internal */ - TS_PREC_FIXED_NSEC, /* recent and internal */ - TS_PREC_AUTO_SEC, /* internal */ - TS_PREC_AUTO_DSEC, /* internal */ - TS_PREC_AUTO_CSEC, /* internal */ - TS_PREC_AUTO_MSEC, /* internal */ - TS_PREC_AUTO_USEC, /* internal */ - TS_PREC_AUTO_NSEC /* internal */ -} ts_precision; - -extern ts_type timestamp_get_type(void); -extern void timestamp_set_type(ts_type); - -extern int timestamp_get_precision(void); -extern void timestamp_set_precision(int tsp); - -#endif /* timestamp.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/to_str.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/to_str.h deleted file mode 100644 index a1e8028b..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/to_str.h +++ /dev/null @@ -1,94 +0,0 @@ -/* to_str.h - * Definitions for utilities to convert various other types to strings. - * - * $Id: to_str.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __TO_STR_H__ -#define __TO_STR_H__ - -#include - -#include "nstime.h" -#include "epan/packet_info.h" - -#define GUID_STR_LEN 37 -#define MAX_IP_STR_LEN 16 -#define MAX_ADDR_STR_LEN 256 - -/* - * Resolution of a time stamp. - */ -typedef enum { - SECS, /* seconds */ - DSECS, /* deciseconds */ - CSECS, /* centiseconds */ - MSECS, /* milliseconds */ - USECS, /* microseconds */ - NSECS /* nanoseconds */ -} time_res_t; - -/* - * These are utility functions which convert various types to strings, - * but for which no more specific module applies. - */ - -struct e_in6_addr; - -extern gchar* address_to_str(const address *); -extern void address_to_str_buf(const address *addr, gchar *buf, int buf_len); -extern gchar* bytestring_to_str(const guint8 *, guint32, char); -extern gchar* ether_to_str(const guint8 *); -extern gchar* ip_to_str(const guint8 *); -extern void ip_to_str_buf(const guint8 *ad, gchar *buf, int buf_len); -extern gchar* fc_to_str(const guint8 *); -extern gchar* fcwwn_to_str (const guint8 *); -extern gchar* ip6_to_str(const struct e_in6_addr *); -extern void ip6_to_str_buf(const struct e_in6_addr *, gchar *); -extern gchar* ipx_addr_to_str(guint32, const guint8 *); -extern gchar* ipxnet_to_string(const guint8 *ad); -extern gchar* ipxnet_to_str_punct(const guint32 ad, char punct); -extern gchar* vines_addr_to_str(const guint8 *addrp); -extern void vines_addr_to_str_buf(const guint8 *addrp, gchar *buf, int buf_len); -extern gchar* time_secs_to_str(gint32); -extern gchar* time_msecs_to_str(gint32); -extern gchar* abs_time_to_str(nstime_t*); -extern gchar* abs_time_secs_to_str(time_t); -extern void display_signed_time(gchar *, int, gint32, gint32, time_res_t); -extern void display_epoch_time(gchar *, int, time_t, gint32, time_res_t); - -extern gchar* rel_time_to_str(nstime_t*); -extern gchar* rel_time_to_secs_str(nstime_t*); -extern gchar* guid_to_str(const e_guid_t*); -extern gchar* guid_to_str_buf(const e_guid_t*, gchar*, int); - -void tipc_addr_to_str_buf( const guint8 *data, gchar *buf, int buf_len); - -extern char *other_decode_bitfield_value(char *buf, guint32 val, guint32 mask, - int width); -extern char *decode_bitfield_value(char *buf, guint32 val, guint32 mask, - int width); -extern const char *decode_boolean_bitfield(guint32 val, guint32 mask, int width, - const char *truedesc, const char *falsedesc); -extern const char *decode_numeric_bitfield(guint32 val, guint32 mask, int width, - const char *fmt); - -#endif /* __TO_STR_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tvbparse.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tvbparse.h deleted file mode 100644 index 4e04a1b3..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tvbparse.h +++ /dev/null @@ -1,475 +0,0 @@ - -/* tvbparse.h -* -* an API for text tvb parsers -* -* Copyright 2005, Luis E. Garcia Ontanon -* -* $Id: tvbparse.h 3992 2008-06-10 03:13:11Z dgu $ -* -* Wireshark - Network traffic analyzer -* By Gerald Combs -* Copyright 1998 Gerald Combs -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version 2 -* of the License, or (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -/* - The intention behind this is to ease the writing of dissectors that have to - parse text without the need of writing into buffers. - - It was originally written to avoid using lex and yacc for the xml dissector. - - the parser is able to look for wanted elements these can be: - - simple tokens: - - a char out of a string of needles - - a char not belonging to a string of needles - - a sequence of chars that belong to a set of chars - - a sequence of chars that do not belong to a set of chars - - a string - - a caseless string - - all the characters up to a certain wanted element (included or excluded) - - composed elements: - - one of a given group of wanted elements - - a sequence of wanted elements - - some (at least one) instances of a wanted element - - Once a wanted element is successfully extracted, by either tvbparse_get or - tvbparse_find, the parser will invoke a given callback - before and another one after every of its component's subelement's callbacks - are being called. - - If tvbparse_get or tvbparse_find fail to extract the wanted element the - subelements callbacks are not going to be invoked. - - The wanted elements are instantiated once by the proto_register_xxx function. - - The parser is isntantiated for every packet and it mantains its state. - - The element's data is destroyed before the next packet is dissected. - */ - -#ifndef _TVB_PARSE_H_ -#define _TVB_PARSE_H_ - -#include -#include - -typedef struct _tvbparse_elem_t tvbparse_elem_t; -typedef struct _tvbparse_wanted_t tvbparse_wanted_t; -typedef struct _tvbparse_t tvbparse_t; - - -/* - * a callback function to be called before or after an element has been - * successfuly extracted. - * - * Note that if the token belongs to a composed token the callbacks of the - * components won't be called unless the composed token is successfully - * extracted. - * - * tvbparse_data: the private data of the parser - * wanted_data: the private data of the wanted element - * elem: the extracted element - */ -typedef void (*tvbparse_action_t)(void* tvbparse_data, const void* wanted_data, struct _tvbparse_elem_t* elem); - -typedef int (*tvbparse_condition_t) -(tvbparse_t*, int, - const tvbparse_wanted_t*, - tvbparse_elem_t**); - - -typedef enum { - TP_UNTIL_INCLUDE, /* last elem is included, its span is spent by the parser */ - TP_UNTIL_SPEND, /* last elem is not included, but its span is spent by the parser */ - TP_UNTIL_LEAVE /* last elem is not included, neither its span is spent by the parser */ -} until_mode_t; - - -struct _tvbparse_wanted_t { - int id; - tvbparse_condition_t condition; - - union { - const gchar* str; - struct _tvbparse_wanted_t** handle; - struct { - union { - gint64 i; - guint64 u; - gdouble f; - } value; - gboolean (*comp)(void*,const void*); - void* (*extract)(tvbuff_t*,guint); - } number; - enum ftenum ftenum; - struct { - until_mode_t mode; - const tvbparse_wanted_t* subelem; - } until; - struct { - GHashTable* table; - struct _tvbparse_wanted_t* key; - struct _tvbparse_wanted_t* other; - } hash; - GPtrArray* elems; - const tvbparse_wanted_t* subelem; - void* p; - } control; - - int len; - - guint min; - guint max; - - const void* data; - - tvbparse_action_t before; - tvbparse_action_t after; - -}; - -/* an instance of a per packet parser */ -struct _tvbparse_t { - tvbuff_t* tvb; - int offset; - int end_offset; - void* data; - const tvbparse_wanted_t* ignore; -}; - - -/* a matching token returned by either tvbparser_get or tvb_parser_find */ -struct _tvbparse_elem_t { - int id; - - tvbuff_t* tvb; - int offset; - int len; - - void* data; - - struct _tvbparse_elem_t* sub; - - struct _tvbparse_elem_t* next; - struct _tvbparse_elem_t* last; - - const tvbparse_wanted_t* wanted; -}; - - -/* - * definition of wanted token types - * - * the following functions define the tokens we will be able to look for in a tvb - * common parameters are: - * - * id: an arbitrary id that will be copied to the eventual token (don't use 0) - * private_data: persistent data to be passed to the callback action (wanted_data) - * before_cb: an callback function to be called before those of the subelements - * after_cb: an callback function to be called after those of the subelements - */ - - -/* - * a char element. - * - * When looked for it returns a simple element one character long if the char - * at the current offset matches one of the the needles. - */ -tvbparse_wanted_t* tvbparse_char(int id, - const gchar* needles, - const void* private_data, - tvbparse_action_t before_cb, - tvbparse_action_t after_cb); - -/* - * a not_char element. - * - * When looked for it returns a simple element one character long if the char - * at the current offset does not match one of the the needles. - */ -tvbparse_wanted_t* tvbparse_not_char(int id, - const gchar* needle, - const void* private_data, - tvbparse_action_t before_cb, - tvbparse_action_t after_cb); - -/* - * a chars element - * - * When looked for it returns a simple element one or more characters long if - * one or more char(s) starting from the current offset match one of the needles. - * An element will be returned if at least min_len chars are given (1 if it's 0) - * It will get at most max_len chars or as much as it can if max_len is 0. - */ -tvbparse_wanted_t* tvbparse_chars(int id, - guint min_len, - guint max_len, - const gchar* needles, - const void* private_data, - tvbparse_action_t before_cb, - tvbparse_action_t after_cb); - -/* - * a not_chars element - * - * When looked for it returns a simple element one or more characters long if - * one or more char(s) starting from the current offset do not match one of the - * needles. - * An element will be returned if at least min_len chars are given (1 if it's 0) - * It will get at most max_len chars or as much as it can if max_len is 0. - */ -tvbparse_wanted_t* tvbparse_not_chars(int id, - guint min_len, - guint max_len, - const gchar* needles, - const void* private_data, - tvbparse_action_t before_cb, - tvbparse_action_t after_cb); - -/* - * a string element - * - * When looked for it returns a simple element if we have the given string at - * the current offset - */ -tvbparse_wanted_t* tvbparse_string(int id, - const gchar* string, - const void* private_data, - tvbparse_action_t before_cb, - tvbparse_action_t after_cb); - -/* - * casestring - * - * When looked for it returns a simple element if we have a matching string at - * the current offset - */ -tvbparse_wanted_t* tvbparse_casestring(int id, - const gchar* str, - const void* data, - tvbparse_action_t before_cb, - tvbparse_action_t after_cb); - -/* - * until - * - * When looked for it returns a simple element containing all the characters - * found until the first match of the ending element if the ending element is - * found. - * - * When looking for until elements it calls tvbparse_find so it can be very slow. - * - * It won't have a subelement, the ending's callbacks won't get called. - */ - -/* - * op_mode values determine how the terminating element and the current offset - * of the parser are handled - */ -tvbparse_wanted_t* tvbparse_until(int id, - const void* private_data, - tvbparse_action_t before_cb, - tvbparse_action_t after_cb, - const tvbparse_wanted_t* ending, - until_mode_t until_mode); - -/* - * one_of - * - * When looked for it will try to match to the given candidates and return a - * composed element whose subelement is the first match. - * - * The list of candidates is terminated with a NULL - * - */ -tvbparse_wanted_t* tvbparse_set_oneof(int id, - const void* private_data, - tvbparse_action_t before_cb, - tvbparse_action_t after_cb, - ...); - -/* - * hashed - */ - -tvbparse_wanted_t* tvbparse_hashed(int id, - const void* data, - tvbparse_action_t before_cb, - tvbparse_action_t after_cb, - tvbparse_wanted_t* key, - tvbparse_wanted_t* other, - ...); - -void tvbparse_hashed_add(tvbparse_wanted_t* w, ...); - -/* - * sequence - * - * When looked for it will try to match in order all the given candidates. If - * every candidate is found in the given order it will return a composed - * element whose subelements are the matcheed elemets. - * - * The list of candidates is terminated with a NULL. - * - */ -tvbparse_wanted_t* tvbparse_set_seq(int id, - const void* private_data, - tvbparse_action_t before_cb, - tvbparse_action_t after_cb, - ...); -/* - * some - * - * When looked for it will try to match the given candidate at least min times - * and at most max times. If the given candidate is matched at least min times - * a composed element is returned. - * - */ -tvbparse_wanted_t* tvbparse_some(int id, - guint min, - guint max, - const void* private_data, - tvbparse_action_t before_cb, - tvbparse_action_t after_cb, - const tvbparse_wanted_t* wanted); - -#define tvbparse_one_or_more(id, private_data, before_cb, after_cb, wanted)\ - tvbparse_some(id, 1, G_MAXINT, private_data, before_cb, after_cb, wanted) - - -/* - * handle - * - * this is a pointer to a pointer to a wanted element (that might have not - * been initialized yet) so that recursive structures - */ -tvbparse_wanted_t* tvbparse_handle(tvbparse_wanted_t** handle); - -#if 0 - -enum ft_cmp_op { - TVBPARSE_CMP_GT, - TVBPARSE_CMP_GE, - TVBPARSE_CMP_EQ, - TVBPARSE_CMP_NE, - TVBPARSE_CMP_LE, - TVBPARSE_CMP_LT -}; - -/* not yet tested */ -tvbparse_wanted_t* tvbparse_ft(int id, - const void* data, - tvbparse_action_t before_cb, - tvbparse_action_t after_cb, - enum ftenum ftenum); - -/* not yet tested */ -tvbparse_wanted_t* tvbparse_end_of_buffer(int id, - const void* data, - tvbparse_action_t before_cb, - tvbparse_action_t after_cb); -/* not yet tested */ -tvbparse_wanted_t* tvbparse_ft_numcmp(int id, - const void* data, - tvbparse_action_t before_cb, - tvbparse_action_t after_cb, - enum ftenum ftenum, - int little_endian, - enum ft_cmp_op ft_cmp_op, - ... ); - -#endif - -/* quoted - * this is a composed candidate, that will try to match a quoted string - * (included the quotes) including into it every escaped quote. - * - * C strings are matched with tvbparse_quoted(-1,NULL,NULL,NULL,"\"","\\") - */ -tvbparse_wanted_t* tvbparse_quoted(int id, - const void* data, - tvbparse_action_t before_cb, - tvbparse_action_t after_cb, - char quote, - char escape); - -/* - * a helper callback for quoted strings that will shrink the token to contain - * only the string andnot the quotes - */ -void tvbparse_shrink_token_cb(void* tvbparse_data, - const void* wanted_data, - tvbparse_elem_t* tok); - - - - -/* initialize the parser (at every packet) -* tvb: what are we parsing? -* offset: from where -* len: for how many bytes -* private_data: will be passed to the action callbacks -* ignore: a wanted token type to be ignored (the associated cb WILL be called when it matches) -*/ -tvbparse_t* tvbparse_init(tvbuff_t* tvb, - int offset, - int len, - void* private_data, - const tvbparse_wanted_t* ignore); - -/* reset the parser */ -gboolean tvbparse_reset(tvbparse_t* tt, int offset, int len); - -guint tvbparse_curr_offset(tvbparse_t* tt); -guint tvbparse_len_left(tvbparse_t* tt); - - - -/* - * This will look for the wanted token at the current offset or after any given - * number of ignored tokens returning FALSE if there's no match or TRUE if there - * is a match. - * The parser will be left in its original state and no callbacks will be called. - */ -gboolean tvbparse_peek(tvbparse_t* tt, - const tvbparse_wanted_t* wanted); - -/* - * This will look for the wanted token at the current offset or after any given - * number of ignored tokens returning NULL if there's no match. - * if there is a match it will set the offset of the current parser after - * the end of the token - */ -tvbparse_elem_t* tvbparse_get(tvbparse_t* tt, - const tvbparse_wanted_t* wanted); - -/* - * Like tvbparse_get but this will look for a wanted token even beyond the - * current offset. - * This function is slow. - */ - -tvbparse_elem_t* tvbparse_find(tvbparse_t* tt, - const tvbparse_wanted_t* wanted); - - -void tvbparse_tree_add_elem(proto_tree* tree, tvbparse_elem_t* curr); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tvbuff.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tvbuff.h deleted file mode 100644 index fc1c28f9..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tvbuff.h +++ /dev/null @@ -1,634 +0,0 @@ -/* tvbuff.h - * - * Testy, Virtual(-izable) Buffer of guint8*'s - * - * "Testy" -- the buffer gets mad when an attempt is made to access data - * beyond the bounds of the buffer. An exception is thrown. - * - * "Virtual" -- the buffer can have its own data, can use a subset of - * the data of a backing tvbuff, or can be a composite of - * other tvbuffs. - * - * $Id: tvbuff.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Copyright (c) 2000 by Gilbert Ramirez - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __TVBUFF_H__ -#define __TVBUFF_H__ - -#include -#include -#include -#include "exceptions.h" - -#ifdef NEED_G_ASCII_STRCASECMP_H -#include "g_ascii_strcasecmp.h" -#endif - -/** @file - * "testy, virtual(-izable) buffer". They are testy in that they get mad when - * an attempt is made to access data beyond the bounds of their array. In that - * case, they throw an exception. - * - * They are virtualizable in that new tvbuff's can be made from other tvbuffs, - * while only the original tvbuff may have data. That is, the new tvbuff has - * virtual data. - */ - - -/** The different types of tvbuff's */ -typedef enum { - TVBUFF_REAL_DATA, - TVBUFF_SUBSET, - TVBUFF_COMPOSITE -} tvbuff_type; - -typedef struct { - /* The backing tvbuff_t */ - struct tvbuff *tvb; - - /* The offset/length of 'tvb' to which I'm privy */ - guint offset; - guint length; - -} tvb_backing_t; - -typedef struct { - GSList *tvbs; - - /* Used for quick testing to see if this - * is the tvbuff that a COMPOSITE is - * interested in. */ - guint *start_offsets; - guint *end_offsets; - -} tvb_comp_t; - -typedef void (*tvbuff_free_cb_t)(void*); - -typedef struct tvbuff { - /* Record-keeping */ - tvbuff_type type; - gboolean initialized; - guint usage_count; - struct tvbuff *ds_tvb; /* data source top-level tvbuff */ - - /* The tvbuffs in which this tvbuff is a member - * (that is, a backing tvbuff for a TVBUFF_SUBSET - * or a member for a TVB_COMPOSITE) */ - GSList *used_in; - - /* TVBUFF_SUBSET and TVBUFF_COMPOSITE keep track - * of the other tvbuff's they use */ - union { - tvb_backing_t subset; - tvb_comp_t composite; - } tvbuffs; - - /* We're either a TVBUFF_REAL_DATA or a - * TVBUFF_SUBSET that has a backing buffer that - * has real_data != NULL, or a TVBUFF_COMPOSITE - * which has flattened its data due to a call - * to tvb_get_ptr(). - */ - const guint8 *real_data; - - /* Length of virtual buffer (and/or real_data). */ - guint length; - - /* Reported length. */ - guint reported_length; - - /* Offset from beginning of first TVBUFF_REAL. */ - gint raw_offset; - - /* Func to call when actually freed */ - tvbuff_free_cb_t free_cb; -} tvbuff_t; - - - -/** TVBUFF_REAL_DATA contains a guint8* that points to real data. - * The data is allocated and contiguous. - * - * TVBUFF_SUBSET has a backing tvbuff. The TVBUFF_SUBSET is a "window" - * through which the program sees only a portion of the backing tvbuff. - * - * TVBUFF_COMPOSITE combines multiple tvbuffs sequentually to produce - * a larger byte array. - * - * tvbuff's of any type can be used as the backing-tvbuff of a - * TVBUFF_SUBSET or as the member of a TVBUFF_COMPOSITE. - * TVBUFF_COMPOSITEs can have member-tvbuffs of different types. - * - * Once a tvbuff is create/initialized/finalized, the tvbuff is read-only. - * That is, it cannot point to any other data. A new tvbuff must be created if - * you want a tvbuff that points to other data. - */ - - -/** "class" initialization. Called once during execution of program - * so that tvbuff.c can initialize its data. */ -extern void tvbuff_init(void); - -/** "class" cleanup. Called once during execution of program - * so that tvbuff.c can clean up its data. */ -extern void tvbuff_cleanup(void); - - -/** Returns a pointer to a newly initialized tvbuff. Note that - * tvbuff's of types TVBUFF_SUBSET and TVBUFF_COMPOSITE - * require further initialization via the appropriate functions */ -extern tvbuff_t* tvb_new(tvbuff_type); - -/** Marks a tvbuff for freeing. The guint8* data of a TVBUFF_REAL_DATA - * is *never* freed by the tvbuff routines. The tvbuff itself is actually freed - * once its usage count drops to 0. - * - * Usage counts increment for any time the tvbuff is - * used as a member of another tvbuff, i.e., as the backing buffer for - * a TVBUFF_SUBSET or as a member of a TVBUFF_COMPOSITE. - * - * Although you may call tvb_free(), the tvbuff may still be in use - * by other tvbuff's (TVBUFF_SUBSET or TVBUFF_COMPOSITE), so it is not - * safe, unless you know otherwise, to free your guint8* data. If you - * cannot be sure that your TVBUFF_REAL_DATA is not in use by another - * tvbuff, register a callback with tvb_set_free_cb(); when your tvbuff - * is _really_ freed, then your callback will be called, and at that time - * you can free your original data. - * - * The caller can artificially increment/decrement the usage count - * with tvbuff_increment_usage_count()/tvbuff_decrement_usage_count(). - */ -extern void tvb_free(tvbuff_t*); - -/** Free the tvbuff_t and all tvbuff's created from it. */ -extern void tvb_free_chain(tvbuff_t*); - -/** Both return the new usage count, after the increment or decrement */ -extern guint tvb_increment_usage_count(tvbuff_t*, guint count); - -/** If a decrement causes the usage count to drop to 0, a the tvbuff - * is immediately freed. Be sure you know exactly what you're doing - * if you decide to use this function, as another tvbuff could - * still have a pointer to the just-freed tvbuff, causing corrupted data - * or a segfault in the future */ -extern guint tvb_decrement_usage_count(tvbuff_t*, guint count); - -/** Set a callback function to call when a tvbuff is actually freed - * (once the usage count drops to 0). One argument is passed to - * that callback --- a void* that points to the real data. - * Obviously, this only applies to a TVBUFF_REAL_DATA tvbuff. */ -extern void tvb_set_free_cb(tvbuff_t*, tvbuff_free_cb_t); - - -/** Attach a TVBUFF_REAL_DATA tvbuff to a parent tvbuff. This connection - * is used during a tvb_free_chain()... the "child" TVBUFF_REAL_DATA acts - * as if is part of the chain-of-creation of the parent tvbuff, although it - * isn't. This is useful if you need to take the data from some tvbuff, - * run some operation on it, like decryption or decompression, and make a new - * tvbuff from it, yet want the new tvbuff to be part of the chain. The reality - * is that the new tvbuff *is* part of the "chain of creation", but in a way - * that these tvbuff routines is ignorant of. Use this function to make - * the tvbuff routines knowledgable of this fact. */ -extern void tvb_set_child_real_data_tvbuff(tvbuff_t* parent, tvbuff_t* child); - -/**Sets parameters for TVBUFF_REAL_DATA. Can throw ReportedBoundsError. */ -extern void tvb_set_real_data(tvbuff_t*, const guint8* data, guint length, - gint reported_length); - -/** Combination of tvb_new() and tvb_set_real_data(). Can throw ReportedBoundsError. */ -extern tvbuff_t* tvb_new_real_data(const guint8* data, guint length, - gint reported_length); - - -/** Define the subset of the backing buffer to use. - * - * 'backing_offset' can be negative, to indicate bytes from - * the end of the backing buffer. - * - * 'backing_length' can be 0, although the usefulness of the buffer would - * be rather limited. - * - * 'backing_length' of -1 means "to the end of the backing buffer" - * - * Will throw BoundsError if 'backing_offset'/'length' - * is beyond the bounds of the backing tvbuff. - * Can throw ReportedBoundsError. */ -extern void tvb_set_subset(tvbuff_t* tvb, tvbuff_t* backing, - gint backing_offset, gint backing_length, gint reported_length); - -/** Combination of tvb_new() and tvb_set_subset() - * Can throw ReportedBoundsError. */ -extern tvbuff_t* tvb_new_subset(tvbuff_t* backing, - gint backing_offset, gint backing_length, gint reported_length); - - -/** Both tvb_composite_append and tvb_composite_prepend can throw - * BoundsError if member_offset/member_length goes beyond bounds of - * the 'member' tvbuff. */ - -/** Append to the list of tvbuffs that make up this composite tvbuff */ -extern void tvb_composite_append(tvbuff_t* tvb, tvbuff_t* member); - -/** Prepend to the list of tvbuffs that make up this composite tvbuff */ -extern void tvb_composite_prepend(tvbuff_t* tvb, tvbuff_t* member); - -/** Helper function that calls tvb_new(TVBUFF_COMPOSITE). - * Provided only to maintain symmetry with other constructors */ -extern tvbuff_t* tvb_new_composite(void); - -/** Mark a composite tvbuff as initialized. No further appends or prepends - * occur, data access can finally happen after this finalization. */ -extern void tvb_composite_finalize(tvbuff_t* tvb); - - -/* Get total length of buffer */ -extern guint tvb_length(tvbuff_t*); - -/** Computes bytes to end of buffer, from offset (which can be negative, - * to indicate bytes from end of buffer). Function returns -1 to - * indicate that offset is out of bounds. No exception is thrown. */ -extern gint tvb_length_remaining(tvbuff_t*, gint offset); - -/** Same as above, but throws an exception if the offset is out of bounds. */ -extern guint tvb_ensure_length_remaining(tvbuff_t*, gint offset); - -/* Checks (w/o throwing exception) that the bytes referred to by - * 'offset'/'length' actually exist in the buffer */ -extern gboolean tvb_bytes_exist(tvbuff_t*, gint offset, gint length); - -/** Checks that the bytes referred to by 'offset'/'length' actually exist - * in the buffer, and throws an exception if they aren't. */ -extern void tvb_ensure_bytes_exist(tvbuff_t *tvb, gint offset, gint length); - -/* Checks (w/o throwing exception) that offset exists in buffer */ -extern gboolean tvb_offset_exists(tvbuff_t*, gint offset); - -/* Get reported length of buffer */ -extern guint tvb_reported_length(tvbuff_t*); - -/** Computes bytes of reported packet data to end of buffer, from offset - * (which can be negative, to indicate bytes from end of buffer). Function - * returns -1 to indicate that offset is out of bounds. No exception is - * thrown. */ -extern gint tvb_reported_length_remaining(tvbuff_t *tvb, gint offset); - -/** Set the reported length of a tvbuff to a given value; used for protocols - whose headers contain an explicit length and where the calling - dissector's payload may include padding as well as the packet for - this protocol. - - Also adjusts the data length. */ -extern void tvb_set_reported_length(tvbuff_t*, guint); - -extern int offset_from_real_beginning(tvbuff_t *tvb, int counter); - -/* Returns the offset from the first byte of real data. */ -#define TVB_RAW_OFFSET(tvb) \ - ((tvb->raw_offset==-1)?(tvb->raw_offset = offset_from_real_beginning(tvb, 0)):tvb->raw_offset) - -/************** START OF ACCESSORS ****************/ -/* All accessors will throw an exception if appropriate */ - -extern guint8 tvb_get_guint8(tvbuff_t*, gint offset); - -extern guint16 tvb_get_ntohs(tvbuff_t*, gint offset); -extern guint32 tvb_get_ntoh24(tvbuff_t*, gint offset); -extern guint32 tvb_get_ntohl(tvbuff_t*, gint offset); -extern guint64 tvb_get_ntoh64(tvbuff_t*, gint offset); -extern gfloat tvb_get_ntohieee_float(tvbuff_t*, gint offset); -extern gdouble tvb_get_ntohieee_double(tvbuff_t*, gint offset); - -extern guint16 tvb_get_letohs(tvbuff_t*, gint offset); -extern guint32 tvb_get_letoh24(tvbuff_t*, gint offset); -extern guint32 tvb_get_letohl(tvbuff_t*, gint offset); -extern guint64 tvb_get_letoh64(tvbuff_t*, gint offset); -extern gfloat tvb_get_letohieee_float(tvbuff_t*, gint offset); -extern gdouble tvb_get_letohieee_double(tvbuff_t*, gint offset); - -/** - * Fetch an IPv4 address, in network byte order. - * We do *not* convert it to host byte order; we leave it in - * network byte order, as that's what its callers expect. */ -extern guint32 tvb_get_ipv4(tvbuff_t*, gint offset); - -/* Fetch an IPv6 address. */ -extern void tvb_get_ipv6(tvbuff_t*, gint offset, struct e_in6_addr *addr); - -/* Fetch a GUID. */ -extern void tvb_get_ntohguid(tvbuff_t *tvb, gint offset, e_guid_t *guid); -extern void tvb_get_letohguid(tvbuff_t *tvb, gint offset, e_guid_t *guid); -extern void tvb_get_guid(tvbuff_t *tvb, gint offset, e_guid_t *guid, gboolean little_endian); - -/* Fetch a specified number of bits from bit offset in a tvb */ -extern guint8 tvb_get_bits8(tvbuff_t *tvb, gint bit_offset, gint no_of_bits); -extern guint16 tvb_get_bits16(tvbuff_t *tvb, gint bit_offset, gint no_of_bits, gboolean little_endian); -extern guint32 tvb_get_bits32(tvbuff_t *tvb, gint bit_offset, gint no_of_bits, gboolean little_endian); -extern guint64 tvb_get_bits64(tvbuff_t *tvb, gint bit_offset, gint no_of_bits, gboolean little_endian); - -/** Returns target for convenience. Does not suffer from possible - * expense of tvb_get_ptr(), since this routine is smart enough - * to copy data in chunks if the request range actually exists in - * different TVBUFF_REAL_DATA tvbuffs. This function assumes that the - * target memory is already allocated; it does not allocate or free the - * target memory. */ -extern void* tvb_memcpy(tvbuff_t*, void* target, gint offset, gint length); - -/** It is the user's responsibility to g_free() the memory allocated by - * tvb_memdup(). Calls tvb_memcpy() */ -extern void* tvb_memdup(tvbuff_t*, gint offset, gint length); - -/* Same as above but the buffer returned from this function does not have to -* be freed. It will be automatically freed after the packet is dissected. -* Buffers allocated by this function are NOT persistent. -*/ -extern void* ep_tvb_memdup(tvbuff_t *tvb, gint offset, gint length); - -/** WARNING! This function is possibly expensive, temporarily allocating - * another copy of the packet data. Furthermore, it's dangerous because once - * this pointer is given to the user, there's no guarantee that the user will - * honor the 'length' and not overstep the boundaries of the buffer. - * - * The returned pointer is data that is internal to the tvbuff, so do not - * attempt to free it. Don't modify the data, either, because another tvbuff - * that might be using this tvbuff may have already copied that portion of - * the data (sometimes tvbuff's need to make copies of data, but that's the - * internal implementation that you need not worry about). Assume that the - * guint8* points to read-only data that the tvbuff manages. - * - * Return a pointer into our buffer if the data asked for via 'offset'/'length' - * is contiguous (which might not be the case for TVBUFF_COMPOSITE). If the - * data is not contiguous, a tvb_memdup() is called for the entire buffer - * and the pointer to the newly-contiguous data is returned. This dynamically- - * allocated memory will be freed when the tvbuff is freed, after the - * tvbuff_free_cb_t() is called, if any. */ -extern const guint8* tvb_get_ptr(tvbuff_t*, gint offset, gint length); - -/** Find first occurence of any of the needles in tvbuff, starting at offset. - * Searches at most maxlength number of bytes; if maxlength is -1, searches - * to end of tvbuff. - * Returns the offset of the found needle, or -1 if not found. - * Will not throw an exception, even if maxlength exceeds boundary of tvbuff; - * in that case, -1 will be returned if the boundary is reached before - * finding needle. */ -extern gint tvb_find_guint8(tvbuff_t*, gint offset, gint maxlength, - guint8 needle); - -/** Find first occurence of any of the needles in tvbuff, starting at offset. - * Searches at most maxlength number of bytes. Returns the offset of the - * found needle, or -1 if not found. Will not throw an exception, even if - * maxlength exceeds boundary of tvbuff; in that case, -1 will be returned if - * the boundary is reached before finding needle. */ -extern gint tvb_pbrk_guint8(tvbuff_t *, gint offset, gint maxlength, - const guint8 *needles); - -/** Find size of stringz (NUL-terminated string) by looking for terminating - * NUL. The size of the string includes the terminating NUL. - * - * If the NUL isn't found, it throws the appropriate exception. - */ -extern guint tvb_strsize(tvbuff_t *tvb, gint offset); - -/** Find length of string by looking for end of zero terminated string, up to - * 'maxlength' characters'; if 'maxlength' is -1, searches to end - * of tvbuff. - * Returns -1 if 'maxlength' reached before finding EOS. */ -extern gint tvb_strnlen(tvbuff_t*, gint offset, guint maxlength); - -/** Convert a string from Unicode to ASCII. At the moment we fake it by - * assuming all characters are ASCII )-: The len parameter is the number - * of guint16's to convert from Unicode. - * - * tvb_fake_unicode() returns a buffer allocated by g_malloc() and must - * be g_free() by the caller. - * tvb_get_ephemeral_faked_unicode() returns a buffer that does not need - * to be explicitely freed. Instead this buffer is - * automatically freed when wireshark starts dissecting - * the next packet. - */ -extern char *tvb_fake_unicode(tvbuff_t *tvb, int offset, int len, - gboolean little_endian); -extern char *tvb_get_ephemeral_faked_unicode(tvbuff_t *tvb, int offset, int len, - gboolean little_endian); - -/** - * Format the data in the tvb from offset for size ... - */ -extern gchar * tvb_format_text(tvbuff_t *tvb, gint offset, gint size); - -/** - * Like "tvb_format_text()", but for 'wsp'; don't show - * the characters as C-style escapes. - */ -extern gchar * tvb_format_text_wsp(tvbuff_t *tvb, gint offset, gint size); - -/** - * Like "tvb_format_text()", but for null-padded strings; don't show - * the null padding characters as "\000". - */ -extern gchar *tvb_format_stringzpad(tvbuff_t *tvb, gint offset, gint size); - - -/** - * Given a tvbuff, an offset, and a length, allocate a buffer big enough - * to hold a non-null-terminated string of that length at that offset, - * plus a trailing zero, copy the string into it, and return a pointer - * to the string. - * - * Throws an exception if the tvbuff ends before the string does. - * - * tvb_get_string() returns a string allocated by g_malloc() and therefore - * MUST be g_free() by the caller in order not to leak - * memory. - * - * tvb_get_ephemeral_string() returns a string that does not need to be freed, - * instead it will automatically be freed once the next - * packet is dissected. - */ -extern guint8 *tvb_get_string(tvbuff_t *tvb, gint offset, gint length); -extern guint8 *tvb_get_ephemeral_string(tvbuff_t *tvb, gint offset, gint length); - - -/** - * Given a tvbuff and an offset, with the offset assumed to refer to - * a null-terminated string, find the length of that string (and throw - * an exception if the tvbuff ends before we find the null), allocate - * a buffer big enough to hold the string, copy the string into it, - * and return a pointer to the string. Also return the length of the - * string (including the terminating null) through a pointer. - * - * tvb_get_stringz() returns a string allocated by g_malloc() and therefore - * MUST be g_free() by the caller in order not to leak - * memory. - * - * tvb_get_ephemeral_stringz() returns a string that does not need to be freed, - * instead it will automatically be freed once the next - * packet is dissected. - */ -extern guint8 *tvb_get_stringz(tvbuff_t *tvb, gint offset, gint *lengthp); -extern guint8 *tvb_get_ephemeral_stringz(tvbuff_t *tvb, gint offset, gint *lengthp); - -/** Looks for a stringz (NUL-terminated string) in tvbuff and copies - * no more than bufsize number of bytes, including terminating NUL, to buffer. - * Returns length of string (not including terminating NUL), or -1 if the string was - * truncated in the buffer due to not having reached the terminating NUL. - * In this way, it acts like g_snprintf(). - * - * When processing a packet where the remaining number of bytes is less - * than bufsize, an exception is not thrown if the end of the packet - * is reached before the NUL is found. If no NUL is found before reaching - * the end of the short packet, -1 is still returned, and the string - * is truncated with a NUL, albeit not at buffer[bufsize - 1], but - * at the correct spot, terminating the string. - */ -extern gint tvb_get_nstringz(tvbuff_t *tvb, gint offset, guint bufsize, - guint8* buffer); - -/** Like tvb_get_nstringz(), but never returns -1. The string is guaranteed to - * have a terminating NUL. If the string was truncated when copied into buffer, - * a NUL is placed at the end of buffer to terminate it. - * - * bufsize MUST be greater than 0. - */ -extern gint tvb_get_nstringz0(tvbuff_t *tvb, gint offset, guint bufsize, - guint8* buffer); - -/** - * Given a tvbuff, an offset into the tvbuff, and a length that starts - * at that offset (which may be -1 for "all the way to the end of the - * tvbuff"), find the end of the (putative) line that starts at the - * specified offset in the tvbuff, going no further than the specified - * length. - * - * Return the length of the line (not counting the line terminator at - * the end), or, if we don't find a line terminator: - * - * if "deseg" is true, return -1; - * - * if "deseg" is false, return the amount of data remaining in - * the buffer. - * - * Set "*next_offset" to the offset of the character past the line - * terminator, or past the end of the buffer if we don't find a line - * terminator. (It's not set if we return -1.) - */ -extern gint tvb_find_line_end(tvbuff_t *tvb, gint offset, int len, - gint *next_offset, gboolean desegment); - -/** - * Given a tvbuff, an offset into the tvbuff, and a length that starts - * at that offset (which may be -1 for "all the way to the end of the - * tvbuff"), find the end of the (putative) line that starts at the - * specified offset in the tvbuff, going no further than the specified - * length. - * - * However, treat quoted strings inside the buffer specially - don't - * treat newlines in quoted strings as line terminators. - * - * Return the length of the line (not counting the line terminator at - * the end), or the amount of data remaining in the buffer if we don't - * find a line terminator. - * - * Set "*next_offset" to the offset of the character past the line - * terminator, or past the end of the buffer if we don't find a line - * terminator. - */ -extern gint tvb_find_line_end_unquoted(tvbuff_t *tvb, gint offset, int len, - gint *next_offset); - -/** - * Copied from the mgcp dissector. (This function should be moved to /epan ) - * tvb_skip_wsp - Returns the position in tvb of the first non-whitespace - * character following offset or offset + maxlength -1 whichever - * is smaller. - * - * Parameters: - * tvb - The tvbuff in which we are skipping whitespace. - * offset - The offset in tvb from which we begin trying to skip whitespace. - * maxlength - The maximum distance from offset that we may try to skip - * whitespace. - * - * Returns: The position in tvb of the first non-whitespace - * character following offset or offset + maxlength -1 whichever - * is smaller. - */ - -extern gint tvb_skip_wsp(tvbuff_t* tvb, gint offset, gint maxlength); - -extern gint tvb_skip_wsp_return(tvbuff_t* tvb, gint offset); - -/** - * Call strncmp after checking if enough chars left, returning 0 if - * it returns 0 (meaning "equal") and -1 otherwise, otherwise return -1. - */ -extern gint tvb_strneql(tvbuff_t *tvb, gint offset, const gchar *str, - gint size); - -/** - * Call g_ascii_strncasecmp after checking if enough chars left, returning - * 0 if it returns 0 (meaning "equal") and -1 otherwise, otherwise return -1. - */ -extern gint tvb_strncaseeql(tvbuff_t *tvb, gint offset, const gchar *str, - gint size); - -/** - * Call memcmp after checking if enough chars left, returning 0 if - * it returns 0 (meaning "equal") and -1 otherwise, otherwise return -1. - */ -extern gint tvb_memeql(tvbuff_t *tvb, gint offset, const guint8 *str, - gint size); - -/** - * Format a bunch of data from a tvbuff as bytes, returning a pointer - * to the string with the formatted data, with "punct" as a byte - * separator. - */ -extern gchar *tvb_bytes_to_str_punct(tvbuff_t *tvb, gint offset, gint len, - gchar punct); - -/* - * Format a bunch of data from a tvbuff as bytes, returning a pointer - * to the string with the formatted data. - */ -extern gchar *tvb_bytes_to_str(tvbuff_t *tvb, gint offset, gint len); - -#define TVB_GET_DS_TVB(tvb) \ - (tvb->ds_tvb) - -/** Locate a sub-tvbuff within another tvbuff, starting at position - * 'haystack_offset'. Returns the index of the beginning of 'needle' within - * 'haystack', or -1 if 'needle' is not found. The index is relative - * to the start of 'haystack', not 'haystack_offset'. */ -extern gint tvb_find_tvb(tvbuff_t *haystack_tvb, tvbuff_t *needle_tvb, - gint haystack_offset); - -/** - * Uncompresses a zlib compressed packet inside a tvbuff at offset with - * length comprlen. Returns an uncompressed tvbuffer if uncompression - * succeeded or NULL if uncompression failed. - */ -extern tvbuff_t* tvb_uncompress(tvbuff_t *tvb, int offset, int comprlen); - -/************** END OF ACCESSORS ****************/ - -#endif /* __TVBUFF_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat-int.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat-int.h deleted file mode 100644 index e875996b..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat-int.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * uat-int.h - * - * $Id: uat-int.h 3992 2008-06-10 03:13:11Z dgu $ - * - * User Accessible Tables - * Mantain an array of user accessible data strucures - * Internal interface - * - * (c) 2007, Luis E. Garcia Ontanon - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2001 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ -#ifndef _UAT_INT_H_ -#define _UAT_INT_H_ - -#include "uat.h" - -typedef struct _uat_fld_rep_t uat_fld_rep_t; -typedef struct _uat_rep_t uat_rep_t; - -typedef void (*uat_rep_fld_free_cb_t)(uat_fld_rep_t*); -typedef void (*uat_rep_free_cb_t)(uat_rep_t*); - -typedef struct _fld_data_t { - guint colnum; - uat_fld_rep_t* rep; - uat_rep_fld_free_cb_t free_rep; -} fld_data_t; - -struct _uat_t { - const char* name; - size_t record_size; - const char* filename; - gboolean from_profile; - const char* help; - const char* category; - void** user_ptr; - guint* nrows_p; - uat_copy_cb_t copy_cb; - uat_update_cb_t update_cb; - uat_free_cb_t free_cb; - - uat_field_t* fields; - guint ncols; - GArray* user_data; - gboolean changed; - uat_rep_t* rep; - uat_rep_free_cb_t free_rep; - gboolean loaded; -}; - -gchar* uat_get_actual_filename(uat_t* uat, gboolean for_writing); - -void uat_init(void); - -void uat_reset(void); - -void* uat_add_record(uat_t*, const void* orig_rec_ptr); - -void uat_swap(uat_t*, guint idx_a, guint idx_b); - -void uat_remove_record_idx(uat_t*, guint rec_idx); - -void uat_destroy(uat_t*); - -void uat_clear(uat_t*); - -gboolean uat_save(uat_t* , char** ); - -void uat_load_all(void); - -#define UAT_UPDATE(uat) do { *((uat)->user_ptr) = (void*)((uat)->user_data->data); *((uat)->nrows_p) = (uat)->user_data->len; } while(0) -#define UAT_INDEX_PTR(uat,idx) (uat->user_data->data + (uat->record_size * (idx))) -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat.h deleted file mode 100644 index d6952dae..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat.h +++ /dev/null @@ -1,486 +0,0 @@ -/* - * uat.h - * - * $Id: uat.h 3992 2008-06-10 03:13:11Z dgu $ - * - * User Accessible Tables - * Mantain an array of user accessible data strucures - * - * (c) 2007, Luis E. Garcia Ontanon - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2001 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef _UAT_H_ -#define _UAT_H_ - -/* - * uat mantains a dynamically allocated table accessible to the user - * via a file and/or gui tables. - * - * the file is located either in userdir(when first read or when writen) or - * in datadir for defaults (read only , it will be always written to userdir). - * - * the behaviour of the table is controlled by a series of callbacks - * the caller must provide. - * - * BEWARE that the user can change an uat at (almost) any time, - * That is pointers to records in an uat are valid only during the call - * to the function that obtains them (do not store them). - * - * UATs are meant for short tables of user data (passwords and such) there's - * no quick access, you must iterate through them each time to fetch the record - * you are looking for. Use uat_dup() or uat_se_dup() if necessary. - * - * Only users via gui or editing the file can add/remove records your code cannot. - */ - -/* obscure data type to handle an uat */ -typedef struct _uat_t uat_t; -/******************************************** - * Callbacks: - * these instruct uat on how to deal with user info and data in records - ********************************************/ - -/******** - * Callbacks for the entire table (these deal with entire records) - ********/ - -/* - * Copy CB - * used to copy a record - * optional, memcpy will be used if not given - * copy(dest,orig,len) - */ -typedef void* (*uat_copy_cb_t)(void*, const void*, unsigned); - -/* - * - * Free CB - * - * destroy a record's child data - * (do not free the container, it will be handled by uat) - * it is optional, no child data will be freed if no present - * free(record) - */ -typedef void (*uat_free_cb_t)(void*); - -/* - * Update CB - * - * to be called after all record fields has been updated - * optional, record will be updated always if not given - * update(record,&error) - */ -typedef void (*uat_update_cb_t)(void* , const char** ); - - -/******* - * Callbacks for single fields (these deal with single values) - * the caller should provide one of these for every field! - ********/ - -/* - * given an input string (ptr, len) checks if the value is OK for a field in the record. - * it will return TRUE if OK or else - * it will return FALSE and may set *error to inform the user on what's - * wrong with the given input - * optional, if not given any input is considered OK and the set cb will be called - * chk(record, ptr, len, chk_data, fld_data, &error) - */ -typedef gboolean (*uat_fld_chk_cb_t)(void*, const char*, unsigned, void*, void*, const char**); - -/* - * Set Field CB - * - * given an input string (ptr, len) sets the value of a field in the record, - * it will return TRUE if OK or else - * it will return FALSE and may set *error to inform the user on what's - * wrong with the given input - * it is mandatory - * set(record, ptr, len, set_data, fld_data) - */ -typedef void (*uat_fld_set_cb_t)(void*, const char*, unsigned, void*, void*); - -/* - * given a record returns a string representation of the field - * mandatory - * tostr(record, &out_ptr, &out_len, tostr_data, fld_data) - */ -typedef void (*uat_fld_tostr_cb_t)(void*, const char**, unsigned*, void*, void*); - -/*********** - * Text Mode - * - * used for file and dialog representation of fileds in columns, - * when the file is read it modifies the way the value is passed back to the fld_set_cb - * (see definition bellow for description) - ***********/ - -typedef enum _uat_text_mode_t { - PT_TXTMOD_NONE, - /* not used */ - - PT_TXTMOD_STRING, - /* - file: - reads: - ,"\x20\x00\x30", as " \00",3 - ,"", as "",0 - ,, as NULL,0 - writes: - ,"\x20\x30\x00\x20", for " 0\0 ",4 - ,"", for *, 0 - ,, for NULL, * - dialog: - accepts \x?? and other escapes - gets "",0 on empty string - */ - PT_TXTMOD_HEXBYTES, - /* - file: - reads: - ,A1b2C3d4, as "\001\002\003\004",4 - ,, as NULL,0 - writes: - ,, on NULL, * - ,a1b2c3d4, on "\001\002\003\004",4 - dialog: - "a1b2c3d4" as "\001\002\003\004",4 - "a1 b2:c3d4" as "\001\002\003\004",4 - "" as NULL,0 - "invalid" as NULL,3 - "a1b" as NULL, 1 - */ - PT_TXTMOD_ENUM -} uat_text_mode_t; - -/* - * Fields - * - * - */ -typedef struct _uat_field_t { - const char* name; - uat_text_mode_t mode; - - struct { - uat_fld_chk_cb_t chk; - uat_fld_set_cb_t set; - uat_fld_tostr_cb_t tostr; - } cb; - - struct { - void* chk; - void* set; - void* tostr; - } cbdata; - - void* fld_data; - - const char* desc; - struct _fld_data_t* priv; -} uat_field_t; - -#define FLDFILL NULL -#define UAT_END_FIELDS {0,PT_TXTMOD_NONE,{0,0,0},{0,0,0},0,0,FLDFILL} - - -#define UAT_CAT_GENERAL "General" -#define UAT_CAT_PORTS "Port Assignments" -#define UAT_CAT_CRYPTO "Decryption" -#define UAT_CAT_FFMT "File Formats" - -/** Create a new uat - * - * @param name The name of the table - * @param data_ptr A pointer to a null terminated array of pointers to the data - * @param default_data A pointer to a struct containing default values - * @param size The size of the structure - * @param filename The filename to be used (either in userdir or datadir) - * @param copy_cb A function that copies the data in the struct - * @param update_cb Will be called when a record is updated - * @param free_cb Will be called to destroy a struct in the dataset - * - * @return A freshly-allocated and populated uat_t struct. - */ -uat_t* uat_new(const char* name, - size_t size, - const char* filename, - gboolean from_profile, - void** data_ptr, - guint* num_items, - const char* category, - const char* help, - uat_copy_cb_t copy_cb, - uat_update_cb_t update_cb, - uat_free_cb_t free_cb, - uat_field_t* flds_array); - -/** Populate a uat using its file. - * - * @param uat_in Pointer to a uat. Must not be NULL. - * @param err Upon failure, points to an error string. - * - * @return TRUE on success, FALSE on failure. - */ -gboolean uat_load(uat_t* uat_in, char** err); - -/** Create or update a single uat entry using a string. - * - * @param uat_in Pointer to a uat. Must not be NULL. - * @param entry The string representation of the entry. Format must match - * what's written to the uat's output file. - * @param err Upon failure, points to an error string. - * - * @return TRUE on success, FALSE on failure. - */ -gboolean uat_load_str(uat_t* uat_in, char* entry, char** err); - -/** Given a uat name or filename, find its pointer. - * - * @param name The name or filename of the uat - * - * @return A pointer to the uat on success, NULL on failure. - */ -uat_t *uat_find(gchar *name); - -/* - * uat_dup() - * uat_se_dup() - * make a reliable copy of an uat for internal use, - * so that pointers to records can be kept through calls. - * return NULL on zero len. - */ -void* uat_dup(uat_t*, guint* len_p); /* to be freed */ -void* uat_se_dup(uat_t*, guint* len_p); -uat_t* uat_get_table_by_name(const char* name); - -/* - * Some common uat_fld_chk_cbs - */ -gboolean uat_fld_chk_str(void*, const char*, unsigned, void*,void*, const char** err); -gboolean uat_fld_chk_proto(void*, const char*, unsigned, void*,void*, const char** err); -gboolean uat_fld_chk_num_dec(void*, const char*, unsigned, void*, void*, const char** err); -gboolean uat_fld_chk_num_hex(void*, const char*, unsigned, void*, void*, const char** err); -gboolean uat_fld_chk_enum(void*, const char*, unsigned, void*, void*, const char**); -gboolean uat_fld_chk_range(void*, const char*, unsigned, void*, void*, const char**); - -#define CHK_STR_IS_DECL(what) \ -gboolean uat_fld_chk_str_ ## what (void*, const char*, unsigned, void*, void*, const char**) - -typedef void (*uat_cb_t)(void* uat,void* user_data); -void uat_foreach_table(uat_cb_t cb,void* user_data); -void uat_unload_all(void); - -char* uat_undquote(const char* si, guint in_len, guint* len_p); -char* uat_unbinstring(const char* si, guint in_len, guint* len_p); -char* uat_unesc(const char* si, guint in_len, guint* len_p); -char* uat_esc(const char* buf, guint len); - -/* Some strings entirely made of ... already declared */ -CHK_STR_IS_DECL(isprint); -CHK_STR_IS_DECL(isalpha); -CHK_STR_IS_DECL(isalnum); -CHK_STR_IS_DECL(isdigit); -CHK_STR_IS_DECL(isxdigit); - -#define CHK_STR_IS_DEF(what) \ -gboolean uat_fld_chk_str_ ## what (void* u1 _U_, const char* strptr, unsigned len, void* u2 _U_, void* u3 _U_, const char** err) { \ - guint i; for (i=0;i(field_name)) - */ -#define UAT_CSTRING_CB_DEF(basename,field_name,rec_t) \ -static void basename ## _ ## field_name ## _set_cb(void* rec, const char* buf, unsigned len, void* u1 _U_, void* u2 _U_) {\ - if ((((rec_t*)rec)->field_name)) g_free((((rec_t*)rec)->field_name)); \ - (((rec_t*)rec)->field_name) = g_strndup(buf,len); } \ -static void basename ## _ ## field_name ## _tostr_cb(void* rec, const char** out_ptr, unsigned* out_len, void* u1 _U_, void* u2 _U_) {\ - if (((rec_t*)rec)->field_name ) { \ - *out_ptr = (((rec_t*)rec)->field_name); *out_len = strlen((((rec_t*)rec)->field_name)); \ - } else { \ - *out_ptr = ""; *out_len = 0; } } - -#define UAT_FLD_CSTRING(basename,field_name,desc) \ - {#field_name, PT_TXTMOD_STRING,{uat_fld_chk_str,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{0,0,0},0,desc,FLDFILL} - -#define UAT_FLD_CSTRING_ISPRINT(basename,field_name,desc) \ - {#field_name, PT_TXTMOD_STRING,{uat_fld_chk_str_isprint,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{0,0,0},0,desc,FLDFILL} - -#define UAT_FLD_CSTRING_OTHER(basename,field_name,chk,desc) \ - {#field_name, PT_TXTMOD_STRING,{ chk ,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{0,0,0},0,desc,FLDFILL} - -/* - * LSTRING MACROS - */ -#define UAT_LSTRING_CB_DEF(basename,field_name,rec_t,ptr_element,len_element) \ -static void basename ## _ ## field_name ## _set_cb(void* rec, const char* buf, unsigned len, void* u1 _U_, void* u2 _U_) {\ - if ((((rec_t*)rec)->ptr_element)) g_free((((rec_t*)rec)->ptr_element)); \ - (((rec_t*)rec)->ptr_element) = uat_unesc(buf,len,&(((rec_t*)rec)->len_element)); }\ -static void basename ## _ ## field_name ## _tostr_cb(void* rec, const char** out_ptr, unsigned* out_len, void* u1 _U_, void* u2 _U_) {\ - if (((rec_t*)rec)->ptr_element ) { \ - *out_ptr = uat_esc(((rec_t*)rec)->ptr_element, (((rec_t*)rec)->len_element)); \ - *out_len = strlen(*out_ptr); \ - } else { \ - *out_ptr = ""; *out_len = 0; } } - -#define UAT_FLD_LSTRING(basename,field_name,desc) \ -{#field_name, PT_TXTMOD_STRING,{0,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{0,0,0},0,desc,FLDFILL} - - -/* - * BUFFER macros, - * a buffer_ptr contained in (((rec_t*)rec)->(field_name)) - * and its len in (((rec_t*)rec)->(len_name)) - * XXX: UNTESTED - */ -#define UAT_BUFFER_CB_DEF(basename,field_name,rec_t,ptr_element,len_element) \ -static void basename ## _ ## field_name ## _set_cb(void* rec, const char* buf, unsigned len, void* u1 _U_, void* u2 _U_) {\ - if ((((rec_t*)rec)->ptr_element) ) g_free((((rec_t*)rec)->ptr_element)); \ - (((rec_t*)rec)->ptr_element) = len ? g_memdup(buf,len) : NULL; \ - (((rec_t*)rec)->len_element) = len; } \ -static void basename ## _ ## field_name ## _tostr_cb(void* rec, const char** out_ptr, unsigned* out_len, void* u1 _U_, void* u2 _U_) {\ - *out_ptr = ((rec_t*)rec)->ptr_element ? ep_memdup(((rec_t*)rec)->ptr_element,((rec_t*)rec)->len_element) : ""; \ - *out_len = ((rec_t*)rec)->len_element; } - -#define UAT_FLD_BUFFER(basename,field_name,desc) \ - {#field_name, PT_TXTMOD_HEXBYTES,{0,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{0,0,0},0,desc,FLDFILL} - - -/* - * DEC Macros, - * a decimal number contained in - */ -#define UAT_DEC_CB_DEF(basename,field_name,rec_t) \ -static void basename ## _ ## field_name ## _set_cb(void* rec, const char* buf, unsigned len, void* u1 _U_, void* u2 _U_) {\ - ((rec_t*)rec)->field_name = strtol(ep_strndup(buf,len),NULL,10); } \ -static void basename ## _ ## field_name ## _tostr_cb(void* rec, const char** out_ptr, unsigned* out_len, void* u1 _U_, void* u2 _U_) {\ - *out_ptr = ep_strdup_printf("%d",((rec_t*)rec)->field_name); \ - *out_len = strlen(*out_ptr); } - -#define UAT_FLD_DEC(basename,field_name,desc) \ - {#field_name, PT_TXTMOD_STRING,{uat_fld_chk_num_dec,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{0,0,0},0,desc,FLDFILL} - - -/* - * HEX Macros, - * an hexadecimal number contained in - */ -#define UAT_HEX_CB_DEF(basename,field_name,rec_t) \ -static void basename ## _ ## field_name ## _set_cb(void* rec, const char* buf, unsigned len, void* u1 _U_, void* u2 _U_) {\ - ((rec_t*)rec)->field_name = strtol(ep_strndup(buf,len),NULL,16); } \ -static void basename ## _ ## field_name ## _tostr_cb(void* rec, const char** out_ptr, unsigned* out_len, void* u1 _U_, void* u2 _U_) {\ - *out_ptr = ep_strdup_printf("%x",((rec_t*)rec)->field_name); \ - *out_len = strlen(*out_ptr); } - -#define UAT_FLD_HEX(basename,field_name,desc) \ -{#field_name, PT_TXTMOD_STRING,{uat_fld_chk_num_hex,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{0,0,0},0,desc,FLDFILL} - - -/* - * ENUM macros - * enum_t: name = ((enum_t*)ptr)->strptr - * value = ((enum_t*)ptr)->value - * rec_t: - * value - */ -#define UAT_VS_DEF(basename,field_name,rec_t,default_val,default_str) \ -static void basename ## _ ## field_name ## _set_cb(void* rec, const char* buf, unsigned len, void* vs, void* u2 _U_) {\ - guint i; \ - char* str = ep_strndup(buf,len); \ - const char* cstr; ((rec_t*)rec)->field_name = default_val; \ - for(i=0; ( cstr = ((value_string*)vs)[i].strptr ) ;i++) { \ - if (g_str_equal(cstr,str)) { \ - ((rec_t*)rec)->field_name = ((value_string*)vs)[i].value; return; } } } \ -static void basename ## _ ## field_name ## _tostr_cb(void* rec, const char** out_ptr, unsigned* out_len, void* vs, void* u2 _U_) {\ - guint i; \ - *out_ptr = ep_strdup(default_str); *out_len = strlen(default_str);\ - for(i=0;((value_string*)vs)[i].strptr;i++) { \ - if ( ((value_string*)vs)[i].value == ((rec_t*)rec)->field_name ) { \ - *out_ptr = ep_strdup(((value_string*)vs)[i].strptr); \ - *out_len = strlen(*out_ptr); return; } } } - - -#define UAT_FLD_VS(basename,field_name,enum,desc) \ - {#field_name, PT_TXTMOD_ENUM,{uat_fld_chk_enum,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{&(enum),&(enum),&(enum)},&(enum),desc,FLDFILL} - - -/* - * PROTO macros - */ - -#define UAT_PROTO_DEF(basename, field_name, dissector_field, name_field, rec_t) \ -static void basename ## _ ## field_name ## _set_cb(void* rec, const char* buf, unsigned len, void* u1 _U_, void* u2 _U_) {\ - if (len) { \ - ((rec_t*)rec)->name_field = ep_strndup(buf,len); g_strdown(((rec_t*)rec)->name_field ); g_strchug(((rec_t*)rec)->name_field); \ - ((rec_t*)rec)->dissector_field = find_dissector(((rec_t*)rec)->name_field); \ - } else { \ - ((rec_t*)rec)->dissector_field = find_dissector("data"); \ - ((rec_t*)rec)->name_field = NULL; \ - } } \ -static void basename ## _ ## field_name ## _tostr_cb(void* rec, const char** out_ptr, unsigned* out_len, void* u1 _U_, void* u2 _U_) {\ - if ( ((rec_t*)rec)->name_field ) { \ - *out_ptr = (((rec_t*)rec)->name_field); \ - *out_len = strlen(*out_ptr); \ - } else { \ - *out_ptr = ""; *out_len = 0; } } - - -#define UAT_FLD_PROTO(basename,field_name,desc) \ - {#field_name, PT_TXTMOD_STRING,{uat_fld_chk_proto,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},{0,0,0},0,desc,FLDFILL} - -/* - * RANGE macros - */ - -#define UAT_RANGE_CB_DEF(basename,field_name,rec_t) \ -static void basename ## _ ## field_name ## _set_cb(void* rec, const char* buf, unsigned len, void* u1 _U_, void* u2) {\ - char* rng = ep_strndup(buf,len);\ - range_convert_str(&(((rec_t*)rec)->field_name), rng,GPOINTER_TO_UINT(u2)); \ - } \ -static void basename ## _ ## field_name ## _tostr_cb(void* rec, const char** out_ptr, unsigned* out_len, void* u1 _U_, void* u2 _U_) {\ - if ( ((rec_t*)rec)->field_name ) { \ - *out_ptr = range_convert_range(((rec_t*)rec)->field_name); *out_len = strlen(*out_ptr); \ - } else { \ - *out_ptr = ""; *out_len = 0; } } - - -#define UAT_FLD_RANGE(basename,field_name,max,desc) \ - {#field_name, PT_TXTMOD_STRING,{uat_fld_chk_range,basename ## _ ## field_name ## _set_cb,basename ## _ ## field_name ## _tostr_cb},\ - {GUINT_TO_POINTER(max),GUINT_TO_POINTER(max),GUINT_TO_POINTER(max)},0,desc,FLDFILL} - - - - - -#endif - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat_load_lex.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat_load_lex.h deleted file mode 100644 index a8d694b1..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat_load_lex.h +++ /dev/null @@ -1,6 +0,0 @@ -/* This is generated by runlex.sh. Do not edit it. */ -#define yylex uat_load_lex -#ifndef YY_DECL -#define YY_DECL int yylex(void) -#endif -YY_DECL; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/unicode-utils.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/unicode-utils.h deleted file mode 100644 index b3962ae6..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/unicode-utils.h +++ /dev/null @@ -1,54 +0,0 @@ -/* unicode-utils.h - * Unicode utility definitions - * - * $Id: unicode-utils.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 2006 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __UNICODEUTIL_H__ -#define __UNICODEUTIL_H__ - -#ifdef _WIN32 - -/** - * @file Unicode convenience routines. - */ - -/** Given a UTF-8 string, convert it to UTF-16. This is meant to be used - * to convert between GTK+ 2.x (UTF-8) to Windows (UTF-16). - * - * @param utf8str The string to convert. May be NULL. - * @return The string converted to UTF-16. If utf8str is NULL, returns - * NULL. The return value should NOT be freed by the caller. - */ -wchar_t * utf_8to16(const char *utf8str); - -/** Given a UTF-16 string, convert it to UTF-8. This is meant to be used - * to convert between GTK+ 2.x (UTF-8) to Windows (UTF-16). - * - * @param utf16str The string to convert. May be NULL. - * @return The string converted to UTF-8. If utf16str is NULL, returns - * NULL. The return value should NOT be freed by the caller. - */ -gchar * utf_16to8(const wchar_t *utf16str); - -#endif /* _WIN32 */ - -#endif /* __UNICODEUTIL_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/value_string.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/value_string.h deleted file mode 100644 index 86a2f1e6..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/value_string.h +++ /dev/null @@ -1,88 +0,0 @@ -/* value_string.h - * Definitions for value_string structures and routines - * - * $Id: value_string.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __VALUE_STRING_H__ -#define __VALUE_STRING_H__ - -#include - -/* Struct for the val_to_str, match_strval_idx, and match_strval functions */ - -typedef struct _value_string { - guint32 value; - const gchar *strptr; -} value_string; - -/* Struct for the rval_to_str, match_strrval_idx, and match_strrval functions */ -typedef struct _range_string { - guint32 value_min; - guint32 value_max; - const gchar *strptr; -} range_string; - -/* #define VS_DEF(x) { x, #x } */ -/* #define VS_END { 0, NULL } */ - -/* Tries to match val against each element in the value_string array vs. - Returns the associated string ptr, and sets "*idx" to the index in - that table, on a match, and returns NULL, and sets "*idx" to -1, - on failure. */ -extern const gchar* match_strval_idx(guint32 val, const value_string *vs, gint *idx); - -/* Like match_strval_idx(), but doesn't return the index. */ -extern const gchar* match_strval(guint32 val, const value_string *vs); - -/* Tries to match val against each element in the value_string array vs. - Returns the associated string ptr on a match. - Formats val with fmt, and returns the resulting string, on failure. */ -extern const gchar* val_to_str(guint32 val, const value_string *vs, const char *fmt); - -/* Generate a string describing an enumerated bitfield (an N-bit field - with various specific values having particular names). */ -extern const char *decode_enumerated_bitfield(guint32 val, guint32 mask, - int width, const value_string *tab, const char *fmt); - -/* Generate a string describing an enumerated bitfield (an N-bit field - with various specific values having particular names). */ -extern const char *decode_enumerated_bitfield_shifted(guint32 val, guint32 mask, - int width, const value_string *tab, const char *fmt); - - -/* ranges aware versions */ - -/* Tries to match val against each range in the range_string array rs. - Returns the associated string ptr on a match. - Formats val with fmt, and returns the resulting string, on failure. */ -extern const gchar* rval_to_str(guint32 val, const range_string *rs, const char *fmt); - -/* Tries to match val against each range in the range_string array rs. - Returns the associated string ptr, and sets "*idx" to the index in - that table, on a match, and returns NULL, and sets "*idx" to -1, - on failure. */ -extern const gchar *match_strrval_idx(guint32 val, const range_string *rs, gint *idx); - -/* Like match_strrval_idx(), but doesn't return the index. */ -extern const gchar *match_strrval(guint32 val, const range_string *rs); - -#endif /* __VALUE_STRING_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ws_strsplit.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ws_strsplit.h deleted file mode 100644 index b2108c79..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ws_strsplit.h +++ /dev/null @@ -1,41 +0,0 @@ -/* ws_strsplit.h - * String Split utility function - * Code borrowed from GTK2 to override the GTK1 version of g_strsplit, which is - * known to be buggy. - * - * $Id: ws_strsplit.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __WS_STRSPLIT_H__ -#define __WS_STRSPLIT_H__ - -#if GLIB_MAJOR_VERSION < 2 - -#define g_strsplit(s, d, t) ws_strsplit(s, d, t) - -gchar ** ws_strsplit (const gchar *string, - const gchar *delimiter, - gint max_tokens); - -#endif /* GLIB_MAJOR_VERSION */ - -#endif /* __WS_STRSPLIT_H__ */ - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/wslua/declare_wslua.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/wslua/declare_wslua.h deleted file mode 100644 index d403ce65..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/wslua/declare_wslua.h +++ /dev/null @@ -1,59 +0,0 @@ -/* This file is automatically genrated by make-reg.pl do not edit */ - -#define WSLUA_DECLARE_CLASSES() \ - WSLUA_CLASS_DECLARE(ByteArray);\ - WSLUA_CLASS_DECLARE(Tvb);\ - WSLUA_CLASS_DECLARE(TvbRange);\ - WSLUA_CLASS_DECLARE(Pref);\ - WSLUA_CLASS_DECLARE(Prefs);\ - WSLUA_CLASS_DECLARE(ProtoField);\ - WSLUA_CLASS_DECLARE(Proto);\ - WSLUA_CLASS_DECLARE(Dissector);\ - WSLUA_CLASS_DECLARE(DissectorTable);\ - WSLUA_CLASS_DECLARE(TreeItem);\ - WSLUA_CLASS_DECLARE(Address);\ - WSLUA_CLASS_DECLARE(Column);\ - WSLUA_CLASS_DECLARE(Columns);\ - WSLUA_CLASS_DECLARE(Pinfo);\ - WSLUA_CLASS_DECLARE(Listener);\ - WSLUA_CLASS_DECLARE(TextWindow);\ - WSLUA_CLASS_DECLARE(Dir);\ - WSLUA_CLASS_DECLARE(FieldInfo);\ - WSLUA_CLASS_DECLARE(Field);\ - WSLUA_CLASS_DECLARE(PseudoHeader);\ - WSLUA_CLASS_DECLARE(Dumper);\ - - -#define WSLUA_DECLARE_FUNCTIONS() \ - WSLUA_FUNCTION wslua_register_postdissector(lua_State* L);\ - WSLUA_FUNCTION wslua_gui_enabled(lua_State* L);\ - WSLUA_FUNCTION wslua_register_menu(lua_State* L);\ - WSLUA_FUNCTION wslua_new_dialog(lua_State* L);\ - WSLUA_FUNCTION wslua_retap_packets(lua_State* L);\ - WSLUA_FUNCTION wslua_copy_to_clipboard(lua_State* L);\ - WSLUA_FUNCTION wslua_open_capture_file(lua_State* L);\ - WSLUA_FUNCTION wslua_set_filter(lua_State* L);\ - WSLUA_FUNCTION wslua_apply_filter(lua_State* L);\ - WSLUA_FUNCTION wslua_reload(lua_State* L);\ - WSLUA_FUNCTION wslua_browser_open_url(lua_State* L);\ - WSLUA_FUNCTION wslua_browser_open_data_file(lua_State* L);\ - WSLUA_FUNCTION wslua_format_date(lua_State* L);\ - WSLUA_FUNCTION wslua_format_time(lua_State* L);\ - WSLUA_FUNCTION wslua_report_failure(lua_State* L);\ - WSLUA_FUNCTION wslua_critical(lua_State* L);\ - WSLUA_FUNCTION wslua_warn(lua_State* L);\ - WSLUA_FUNCTION wslua_message(lua_State* L);\ - WSLUA_FUNCTION wslua_info(lua_State* L);\ - WSLUA_FUNCTION wslua_debug(lua_State* L);\ - WSLUA_FUNCTION wslua_loadfile(lua_State* L);\ - WSLUA_FUNCTION wslua_dofile(lua_State* L);\ - WSLUA_FUNCTION wslua_persconffile_path(lua_State* L);\ - WSLUA_FUNCTION wslua_datafile_path(lua_State* L);\ - WSLUA_FUNCTION wslua_register_stat_cmd_arg(lua_State* L);\ - WSLUA_FUNCTION wslua_all_field_infos(lua_State* L);\ - - -extern void wslua_register_classes(lua_State* L); -extern void wslua_register_functions(lua_State* L); - - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/wslua/wslua.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/wslua/wslua.h deleted file mode 100644 index a58fba23..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/wslua/wslua.h +++ /dev/null @@ -1,372 +0,0 @@ -/* - * wslua.h - * - * Wireshark's interface to the Lua Programming Language - * - * (c) 2006, Luis E. Garcia Ontanon - * (c) 2007, Tamas Regos - * - * $Id: wslua.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef _PACKET_LUA_H -#define _PACKET_LUA_H - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if GLIB_MAJOR_VERSION < 2 -#include -#endif - -#include "declare_wslua.h" - -#define WSLUA_INIT_ROUTINES "init_routines" -#define LOG_DOMAIN_LUA "wslua" - -struct _wslua_tvbrange { - tvbuff_t* tvb; - int offset; - int len; -}; - -typedef struct _wslua_field_t { - int hfid; - int ett; - char* name; - char* abbr; - char* blob; - enum ftenum type; - base_display_e base; - value_string* vs; - guint32 mask; -} wslua_field_t; - -/* - * PREF_OBSOLETE is used for preferences that a module used to support - * but no longer supports; we give different error messages for them. - */ -typedef enum { - PREF_UINT, - PREF_BOOL, - PREF_ENUM, - PREF_STRING, - PREF_RANGE, - PREF_STATIC_TEXT, - PREF_OBSOLETE -} pref_type_t; - -typedef struct _wslua_pref_t { - gchar* name; - gchar* label; - gchar* desc; - pref_type_t type; - union { - gboolean b; - guint u; - const gchar* s; - gint e; - range_t *r; - void* p; - } value; - union { - guint32 max_value; /* maximum value of a range */ - struct { - const enum_val_t *enumvals; /* list of name & values */ - gboolean radio_buttons; /* TRUE if it should be shown as - radio buttons rather than as an - option menu or combo box in - the preferences tab */ - } enum_info; /* for PREF_ENUM */ - } info; /* display/text file information */ - - struct _wslua_pref_t* next; - struct _wslua_proto_t* proto; -} wslua_pref_t; - -typedef struct _wslua_proto_t { - gchar* name; - gchar* desc; - int hfid; - int ett; - wslua_pref_t prefs; - int fields; - module_t *prefs_module; - dissector_handle_t handle; - gboolean is_postdissector; -} wslua_proto_t; - -struct _wslua_distbl_t { - dissector_table_t table; - gchar* name; -}; - -struct _wslua_col_info { - column_info* cinfo; - gint col; -}; - -struct _wslua_treeitem { - proto_item* item; - proto_tree* tree; -}; - -typedef void (*tap_extractor_t)(lua_State*,const void*); - -struct _wslua_tap { - gchar* name; - gchar* filter; - tap_extractor_t extractor; - lua_State* L; - int packet_ref; - int draw_ref; - int init_ref; -}; - -#if GLIB_MAJOR_VERSION < 2 -# define DIRECTORY_T DIR -# define FILE_T struct dirent -# define OPENDIR_OP(name) opendir(name) -# define DIRGETNEXT_OP(dir) readdir(dir) -# define GETFNAME_OP(file) (gchar *)file->d_name -# define CLOSEDIR_OP(dir) closedir(dir) -#else /* GLIB 2 */ -# define DIRECTORY_T GDir -# define FILE_T gchar -# define OPENDIR_OP(name) g_dir_open(name, 0, dir->dummy) -# define DIRGETNEXT_OP(dir) g_dir_read_name(dir) -# define GETFNAME_OP(file) (file); -# define CLOSEDIR_OP(dir) g_dir_close(dir) -#endif - -struct _wslua_dir { - DIRECTORY_T* dir; - char* ext; -#if GLIB_MAJOR_VERSION >= 2 - GError** dummy; -#endif - -}; - -typedef struct { const char* name; tap_extractor_t extractor; } tappable_t; - -typedef struct {const gchar* str; enum ftenum id; } wslua_ft_types_t; - -typedef wslua_pref_t* Pref; -typedef wslua_pref_t* Prefs; -typedef struct _wslua_field_t* ProtoField; -typedef struct _wslua_proto_t* Proto; -typedef struct _wslua_distbl_t* DissectorTable; -typedef dissector_handle_t Dissector; -typedef GByteArray* ByteArray; -typedef tvbuff_t* Tvb; -typedef struct _wslua_tvbrange* TvbRange; -typedef struct _wslua_col_info* Column; -typedef column_info* Columns; -typedef packet_info* Pinfo; -typedef struct _wslua_treeitem* TreeItem; -typedef address* Address; -typedef header_field_info** Field; -typedef field_info* FieldInfo; -typedef struct _wslua_tap* Listener; -typedef funnel_text_window_t* TextWindow; -typedef wtap_dumper* Dumper; -typedef struct lua_pseudo_header* PseudoHeader; -typedef tvbparse_t* Parser; -typedef tvbparse_wanted_t* Rule; -typedef tvbparse_elem_t* Node; -typedef tvbparse_action_t* Shortcut; -typedef struct _wslua_main* WireShark; -typedef struct _wslua_dir* Dir; - -/* - * toXxx(L,idx) gets a Xxx from an index (Lua Error if fails) - * checkXxx(L,idx) gets a Xxx from an index after calling check_code (No Lua Error if it fails) - * pushXxx(L,xxx) pushes an Xxx into the stack - * isXxx(L,idx) tests whether we have an Xxx at idx - * - * LUA_CLASS_DEFINE must be used without trailing ';' - */ -#define WSLUA_CLASS_DEFINE(C,check_code,push_code) \ -C to##C(lua_State* L, int index) { \ - C* v = (C*)lua_touserdata (L, index); \ - if (!v) luaL_typerror(L,index,#C); \ - return *v; \ -} \ -C check##C(lua_State* L, int index) { \ - C* p; \ - luaL_checktype(L,index,LUA_TUSERDATA); \ - p = (C*)luaL_checkudata(L, index, #C); \ - check_code; \ - return p ? *p : NULL; \ -} \ -C* push##C(lua_State* L, C v) { \ - C* p = lua_newuserdata(L,sizeof(C)); *p = v; \ - luaL_getmetatable(L, #C); lua_setmetatable(L, -2); \ - push_code; \ - return p; \ -}\ -gboolean is##C(lua_State* L,int i) { \ - void *p; \ - if(!lua_isuserdata(L,i)) return FALSE; \ - p = lua_touserdata(L, i); \ - lua_getfield(L, LUA_REGISTRYINDEX, #C); \ - if (p == NULL || !lua_getmetatable(L, i) || !lua_rawequal(L, -1, -2)) p=NULL; \ - lua_pop(L, 2); \ - return p ? TRUE : FALSE; \ -} \ -C shift##C(lua_State* L,int i) { \ - C* p; \ - if(!lua_isuserdata(L,i)) return NULL; \ - p = lua_touserdata(L, i); \ - lua_getfield(L, LUA_REGISTRYINDEX, #C); \ - if (p == NULL || !lua_getmetatable(L, i) || !lua_rawequal(L, -1, -2)) p=NULL; \ - lua_pop(L, 2); \ - if (p) { lua_remove(L,i); return *p; }\ - else return NULL;\ -} \ -int dummy##C - -#ifdef HAVE_LUA_5_1 - -#define WSLUA_REGISTER_CLASS(C) { \ - luaL_register (L, #C, C ## _methods); \ - luaL_newmetatable (L, #C); \ - luaL_register (L, NULL, C ## _meta); \ - lua_pushliteral(L, "__index"); \ - lua_pushvalue(L, -3); \ - lua_rawset(L, -3); \ - lua_pushliteral(L, "__metatable"); \ - lua_pushvalue(L, -3); \ - lua_rawset(L, -3); \ - lua_pop(L, 1); \ -} - -#define WSLUA_REGISTER_META(C) luaL_newmetatable (L, #C); luaL_register (L, NULL, C ## _meta); - -#define WSLUA_INIT(L) \ - luaL_openlibs(L); \ - wslua_register_classes(L); \ - wslua_register_functions(L); - - -#endif - -#define WSLUA_FUNCTION extern int -#define WSLUA_REGISTER_FUNCTION(name) { lua_pushstring(L, #name); lua_pushcfunction(L, wslua_## name); lua_settable(L, LUA_GLOBALSINDEX); } -#define WSLUA_REGISTER extern int - -#define WSLUA_METHOD static int -#define WSLUA_CONSTRUCTOR static int -#define WSLUA_ATTR_SET static int -#define WSLUA_ATTR_GET static int -#define WSLUA_METAMETHOD static int - -#define WSLUA_METHODS static const luaL_reg -#define WSLUA_META static const luaL_reg -#define WSLUA_CLASS_FNREG(class,name) { #name, class##_##name } - -#define WSLUA_ERROR(name,error) { luaL_error(L, ep_strdup_printf("%s%s", #name ": " ,error) ); return 0; } -#define WSLUA_ARG_ERROR(name,attr,error) { luaL_argerror(L,WSLUA_ARG_ ## name ## _ ## attr, #name ": " error); return 0; } -#define WSLUA_OPTARG_ERROR(name,attr,error) { luaL_argerror(L,WSLUA_OPTARG_##name##_ ##attr, #name ": " error); return 0; } - -#define WSLUA_REG_GLOBAL_BOOL(L,n,v) { lua_pushstring(L,n); lua_pushboolean(L,v); lua_settable(L, LUA_GLOBALSINDEX); } -#define WSLUA_REG_GLOBAL_STRING(n,v) { lua_pushstring(L,n); lua_pushstring(L,v); lua_settable(L, LUA_GLOBALSINDEX); } -#define WSLUA_REG_GLOBAL_NUMBER(n,v) { lua_pushstring(L,n); lua_pushnumber(L,v); lua_settable(L, LUA_GLOBALSINDEX); } - -#define WSLUA_RETURN(i) return (i); - -#define WSLUA_API extern - -#define NOP -#define FAIL_ON_NULL(s) if (! *p) luaL_argerror(L,index,s) - - - -#define WSLUA_CLASS_DECLARE(C) \ -extern C to##C(lua_State* L, int index); \ -extern C check##C(lua_State* L, int index); \ -extern C* push##C(lua_State* L, C v); \ -extern int C##_register(lua_State* L); \ -extern gboolean is##C(lua_State* L,int i); \ -extern C shift##C(lua_State* L,int i) - - -extern packet_info* lua_pinfo; -extern TreeItem lua_tree; -extern tvbuff_t* lua_tvb; -extern int lua_malformed; -extern dissector_handle_t lua_data_handle; -extern gboolean lua_initialized; -extern int lua_dissectors_table_ref; - -WSLUA_DECLARE_CLASSES() -WSLUA_DECLARE_FUNCTIONS() - -extern lua_State* wslua_state(void); - -extern gboolean wslua_optbool(lua_State* L, int n, gboolean def); -extern const gchar* lua_shiftstring(lua_State* L,int idx); -extern int dissect_lua(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree); - -extern void proto_register_lua(void); -extern GString* lua_register_all_taps(void); -extern void lua_prime_all_fields(proto_tree* tree); - -extern int Proto_commit(lua_State* L); - -extern void* push_Tvb(lua_State* L, Tvb tvb); -extern void clear_outstanding_tvbs(void); - -extern void* push_Pinfo(lua_State* L, Pinfo p); -extern void clear_outstanding_pinfos(void); - -extern void* push_TreeItem(lua_State* L, TreeItem ti); -extern void clear_outstanding_trees(void); - -extern void wslua_print_stack(char* s, lua_State* L); - -extern int wslua_init(lua_State* L); - -extern tap_extractor_t wslua_get_tap_extractor(const gchar* name); -extern int wslua_set_tap_enums(lua_State* L); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/x264_prt_id.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/x264_prt_id.h deleted file mode 100644 index 7be6bc0b..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/x264_prt_id.h +++ /dev/null @@ -1,35 +0,0 @@ -/* x264_prt_id.h - * Definitions of X.264/ISO 11570 transport protocol IDs - * - * $Id: x264_prt_id.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __X264_PRT_ID_H__ -#define __X264_PRT_ID_H__ - -/* X.264 / ISO 11570 transport protocol ID values. */ - -#define PRT_ID_ISO_8073 0x01 /* X.224/ISO 8073 COTP */ -#define PRT_ID_ISO_8602 0x02 /* X.234/ISO 8602 CLTP */ -#define PRT_ID_ISO_10736_ISO_8073 0x03 /* X.274/ISO 10736 + X.224/ISO 8073 */ -#define PRT_ID_ISO_10736_ISO_8602 0x04 /* X.274/ISO 10736 + X.234/ISO 8602 */ - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/xdlc.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/xdlc.h deleted file mode 100644 index b9265f7e..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/xdlc.h +++ /dev/null @@ -1,140 +0,0 @@ -/* xdlc.h - * Define *DLC frame types, and routine to dissect the control field of - * a *DLC frame. - * - * $Id: xdlc.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __XDLC_H__ -#define __XDLC_H__ - -/* - * Low-order bits of first (extended) or only (basic) octet of control - * field, specifying the frame type. - */ -#define XDLC_I_MASK 0x01 /* Mask to test for I or not I */ -#define XDLC_I 0x00 /* Information frames */ -#define XDLC_S_U_MASK 0x03 /* Mask to test for S or U */ -#define XDLC_S 0x01 /* Supervisory frames */ -#define XDLC_U 0x03 /* Unnumbered frames */ - -/* - * N(S) and N(R) fields, in basic and extended operation. - */ -#define XDLC_N_R_MASK 0xE0 /* basic */ -#define XDLC_N_R_SHIFT 5 -#define XDLC_N_R_EXT_MASK 0xFE00 /* extended */ -#define XDLC_N_R_EXT_SHIFT 9 -#define XDLC_N_S_MASK 0x0E /* basic */ -#define XDLC_N_S_SHIFT 1 -#define XDLC_N_S_EXT_MASK 0x00FE /* extended */ -#define XDLC_N_S_EXT_SHIFT 1 - -/* - * Poll/Final bit, in basic and extended operation. - */ -#define XDLC_P_F 0x10 /* basic */ -#define XDLC_P_F_EXT 0x0100 /* extended */ - -/* - * S-format frame types. - */ -#define XDLC_S_FTYPE_MASK 0x0C -#define XDLC_RR 0x00 /* Receiver ready */ -#define XDLC_RNR 0x04 /* Receiver not ready */ -#define XDLC_REJ 0x08 /* Reject */ -#define XDLC_SREJ 0x0C /* Selective reject */ - -/* - * U-format modifiers. - */ -#define XDLC_U_MODIFIER_MASK 0xEC -#define XDLC_UI 0x00 /* Unnumbered Information */ -#define XDLC_UP 0x20 /* Unnumbered Poll */ -#define XDLC_DISC 0x40 /* Disconnect (command) */ -#define XDLC_RD 0x40 /* Request Disconnect (response) */ -#define XDLC_UA 0x60 /* Unnumbered Acknowledge */ -#define XDLC_SNRM 0x80 /* Set Normal Response Mode */ -#define XDLC_TEST 0xE0 /* Test */ -#define XDLC_SIM 0x04 /* Set Initialization Mode (command) */ -#define XDLC_RIM 0x04 /* Request Initialization Mode (response) */ -#define XDLC_FRMR 0x84 /* Frame reject */ -#define XDLC_CFGR 0xC4 /* Configure */ -#define XDLC_SARM 0x0C /* Set Asynchronous Response Mode (command) */ -#define XDLC_DM 0x0C /* Disconnected mode (response) */ -#define XDLC_SABM 0x2C /* Set Asynchronous Balanced Mode */ -#define XDLC_SARME 0x4C /* Set Asynchronous Response Mode Extended */ -#define XDLC_SABME 0x6C /* Set Asynchronous Balanced Mode Extended */ -#define XDLC_RESET 0x8C /* Reset */ -#define XDLC_XID 0xAC /* Exchange identification */ -#define XDLC_SNRME 0xCC /* Set Normal Response Mode Extended */ -#define XDLC_BCN 0xEC /* Beacon */ - -/* - * This macro takes the control field of an xDLC frame, as returned by - * "get_xdlc_control()" or "dissect_xdlc_control()", and evaluates to - * TRUE if the frame is an "information" frame and FALSE if it isn't. - * Note that frames other than information frames can have data in them, - * e.g. TEST frames. - */ -#define XDLC_IS_INFORMATION(control) \ - (((control) & XDLC_I_MASK) == XDLC_I || (control) == (XDLC_UI|XDLC_U)) - -/* - * This macro takes the control field of an xDLC frame, and a flag saying - * whether we're doing basic or extended operation, and evaluates to - * the length of that field (if it's an Unnumbered frame, or we're not - * in extended mode, it's 1 byte long, otherwise it's 2 bytes long). - */ -#define XDLC_CONTROL_LEN(control, is_extended) \ - ((((control) & XDLC_S_U_MASK) == XDLC_U || !(is_extended)) ? 1 : 2) - -/* - * Structure containing pointers to hf_ values for various subfields of - * the control field. - */ -typedef struct { - int *hf_xdlc_n_r; - int *hf_xdlc_n_s; - int *hf_xdlc_p; - int *hf_xdlc_f; - int *hf_xdlc_s_ftype; - int *hf_xdlc_u_modifier_cmd; - int *hf_xdlc_u_modifier_resp; - int *hf_xdlc_ftype_i; - int *hf_xdlc_ftype_s_u; -} xdlc_cf_items; - -extern const value_string ftype_vals[]; -extern const value_string stype_vals[]; -extern const value_string modifier_vals_cmd[]; -extern const value_string modifier_vals_resp[]; - -extern int get_xdlc_control(const guchar *pd, int offset, int extended); - -extern int dissect_xdlc_control(tvbuff_t *tvb, int offset, packet_info *pinfo, - proto_tree *xdlc_tree, int hf_xdlc_control, gint ett_xdlc_control, - const xdlc_cf_items *cf_items_nonext, const xdlc_cf_items *cf_items_ext, - const value_string *u_modifier_short_vals_cmd, - const value_string *u_modifier_short_vals_resp, int is_response, - int is_extended, int append_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/xmlstub.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/xmlstub.h deleted file mode 100644 index feb7e278..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/xmlstub.h +++ /dev/null @@ -1,1123 +0,0 @@ -/* - * This is part of tree.h from the libxml2 distribution. It is used - * for structure reference when dynamically linking to libxml. - * - * The GPL agreement for this file and for libxml2 can be found at - * http://www.xmlsoft.org - */ - -#include "config.h" - -/****************** specific to wireshark ********************************/ -/* - * Uncomment the following line to restore XML_DO_VALIDITY_CHECKING - * behavior which is causing issues on WIN32 platforms. See: - * http://www.ethereal.com/lists/ethereal-dev/200410/msg00194.html - */ -/* #define WIRESHARK_XML_DO_VALIDITY_CHECKING */ -/****************** From xml headers ************************************/ - -/* - * use those to be sure nothing nasty will happen if - * your library and includes mismatch - */ -#ifndef LIBXML2_COMPILING_MSCCDEF -extern void xmlCheckVersion(int version); -#endif /* LIBXML2_COMPILING_MSCCDEF */ -#define LIBXML_DOTTED_VERSION "2.3.8" -#define LIBXML_VERSION 20308 -#define LIBXML_VERSION_STRING "20308" -#define LIBXML_TEST_VERSION xmlCheckVersion(20308); - -/* - * Whether the trio support need to be configured in - */ -#if 0 -#define WITH_TRIO -#else -#define WITHOUT_TRIO -#endif - -/* - * Whether the FTP support is configured in - */ -#if 1 -#define LIBXML_FTP_ENABLED -#else -#define LIBXML_FTP_DISABLED -#endif - -/* - * Whether the HTTP support is configured in - */ -#if 1 -#define LIBXML_HTTP_ENABLED -#else -#define LIBXML_HTTP_DISABLED -#endif - -/* - * Whether the HTML support is configured in - */ -#if 1 -#define LIBXML_HTML_ENABLED -#else -#define LIBXML_HTML_DISABLED -#endif - -/* - * Whether the SGML Docbook support is configured in - */ -#if 1 -#define LIBXML_DOCB_ENABLED -#else -#define LIBXML_DOCB_DISABLED -#endif - -/* - * Whether XPath is configured in - */ -#if 1 -#define LIBXML_XPATH_ENABLED -#else -#define LIBXML_XPATH_DISABLED -#endif - -/* - * Whether XPointer is configured in - */ -#if 1 -#define LIBXML_XPTR_ENABLED -#else -#define LIBXML_XPTR_DISABLED -#endif - -/* - * Whether XInclude is configured in - */ -#if 1 -#define LIBXML_XINCLUDE_ENABLED -#else -#define LIBXML_XINCLUDE_DISABLED -#endif - -/* - * Whether iconv support is available - */ -#ifdef HAVE_ICONV -#define LIBXML_ICONV_ENABLED -#include -#else -#define LIBXML_ICONV_DISABLED -#endif - -/* - * Whether Debugging module is configured in - */ -#if 1 -#define LIBXML_DEBUG_ENABLED -#else -#define LIBXML_DEBUG_DISABLED -#endif - -/* - * Whether the memory debugging is configured in - */ -#if 0 -#define DEBUG_MEMORY_LOCATION -#endif - -#ifndef LIBXML_DLL_IMPORT -#if defined(_WIN32) && !defined(STATIC) -#define LIBXML_DLL_IMPORT __declspec(dllimport) -#else -#define LIBXML_DLL_IMPORT -#endif -#endif - -#ifdef __GNUC__ -#ifdef HAVE_ANSIDECL_H -#include -#endif -#ifndef ATTRIBUTE_UNUSED -#define ATTRIBUTE_UNUSED -#endif -#else -#define ATTRIBUTE_UNUSED -#endif - - -#define XML_XML_NAMESPACE \ - (const xmlChar *) "http://www.w3.org/XML/1998/namespace" - -/* - * The different element types carried by an XML tree - * - * NOTE: This is synchronized with DOM Level1 values - * See http://www.w3.org/TR/REC-DOM-Level-1/ - * - * Actually this had diverged a bit, and now XML_DOCUMENT_TYPE_NODE should - * be deprecated to use an XML_DTD_NODE. - */ -typedef enum { - XML_ELEMENT_NODE= 1, - XML_ATTRIBUTE_NODE= 2, - XML_TEXT_NODE= 3, - XML_CDATA_SECTION_NODE= 4, - XML_ENTITY_REF_NODE= 5, - XML_ENTITY_NODE= 6, - XML_PI_NODE= 7, - XML_COMMENT_NODE= 8, - XML_DOCUMENT_NODE= 9, - XML_DOCUMENT_TYPE_NODE= 10, - XML_DOCUMENT_FRAG_NODE= 11, - XML_NOTATION_NODE= 12, - XML_HTML_DOCUMENT_NODE= 13, - XML_DTD_NODE= 14, - XML_ELEMENT_DECL= 15, - XML_ATTRIBUTE_DECL= 16, - XML_ENTITY_DECL= 17, - XML_NAMESPACE_DECL= 18, - XML_XINCLUDE_START= 19, - XML_XINCLUDE_END= 20 -#ifdef LIBXML_DOCB_ENABLED - ,XML_DOCB_DOCUMENT_NODE= 21 -#endif -} xmlElementType; - -/* - * Size of an internal character representation. - * - * We use 8bit chars internal representation for memory efficiency, - * Note that with 8 bits wide xmlChars one can still use UTF-8 to handle - * correctly non ISO-Latin input. - */ - -typedef unsigned char xmlChar; - -#ifndef _WIN32 -#ifndef CHAR -#define CHAR xmlChar -#endif -#endif - -#define BAD_CAST (xmlChar *) - -/* - * a DTD Notation definition - */ - -typedef struct _xmlNotation xmlNotation; -typedef xmlNotation *xmlNotationPtr; -struct _xmlNotation { - const xmlChar *name; /* Notation name */ - const xmlChar *PublicID; /* Public identifier, if any */ - const xmlChar *SystemID; /* System identifier, if any */ -}; - -/* - * a DTD Attribute definition - */ - -typedef enum { - XML_ATTRIBUTE_CDATA = 1, - XML_ATTRIBUTE_ID, - XML_ATTRIBUTE_IDREF , - XML_ATTRIBUTE_IDREFS, - XML_ATTRIBUTE_ENTITY, - XML_ATTRIBUTE_ENTITIES, - XML_ATTRIBUTE_NMTOKEN, - XML_ATTRIBUTE_NMTOKENS, - XML_ATTRIBUTE_ENUMERATION, - XML_ATTRIBUTE_NOTATION -} xmlAttributeType; - -typedef enum { - XML_ATTRIBUTE_NONE = 1, - XML_ATTRIBUTE_REQUIRED, - XML_ATTRIBUTE_IMPLIED, - XML_ATTRIBUTE_FIXED -} xmlAttributeDefault; - -typedef struct _xmlEnumeration xmlEnumeration; -typedef xmlEnumeration *xmlEnumerationPtr; -struct _xmlEnumeration { - struct _xmlEnumeration *next; /* next one */ - const xmlChar *name; /* Enumeration name */ -}; - -typedef struct _xmlAttribute xmlAttribute; -typedef xmlAttribute *xmlAttributePtr; -struct _xmlAttribute { -#ifndef XML_WITHOUT_CORBA - void *_private; /* for Corba, must be first ! */ -#endif - xmlElementType type; /* XML_ATTRIBUTE_DECL, must be second ! */ - const xmlChar *name; /* Attribute name */ - struct _xmlNode *children; /* NULL */ - struct _xmlNode *last; /* NULL */ - struct _xmlDtd *parent; /* -> DTD */ - struct _xmlNode *next; /* next sibling link */ - struct _xmlNode *prev; /* previous sibling link */ - struct _xmlDoc *doc; /* the containing document */ - - struct _xmlAttribute *nexth; /* next in hash table */ - xmlAttributeType atype; /* The attribute type */ - xmlAttributeDefault def; /* the default */ - const xmlChar *defaultValue; /* or the default value */ - xmlEnumerationPtr tree; /* or the enumeration tree if any */ - const xmlChar *prefix; /* the namespace prefix if any */ - const xmlChar *elem; /* Element holding the attribute */ -}; - -/* - * a DTD Element definition. - */ -typedef enum { - XML_ELEMENT_CONTENT_PCDATA = 1, - XML_ELEMENT_CONTENT_ELEMENT, - XML_ELEMENT_CONTENT_SEQ, - XML_ELEMENT_CONTENT_OR -} xmlElementContentType; - -typedef enum { - XML_ELEMENT_CONTENT_ONCE = 1, - XML_ELEMENT_CONTENT_OPT, - XML_ELEMENT_CONTENT_MULT, - XML_ELEMENT_CONTENT_PLUS -} xmlElementContentOccur; - -typedef struct _xmlElementContent xmlElementContent; -typedef xmlElementContent *xmlElementContentPtr; -struct _xmlElementContent { - xmlElementContentType type; /* PCDATA, ELEMENT, SEQ or OR */ - xmlElementContentOccur ocur; /* ONCE, OPT, MULT or PLUS */ - const xmlChar *name; /* Element name */ - struct _xmlElementContent *c1; /* first child */ - struct _xmlElementContent *c2; /* second child */ - struct _xmlElementContent *parent; /* parent */ -}; - -typedef enum { - XML_ELEMENT_TYPE_UNDEFINED = 0, - XML_ELEMENT_TYPE_EMPTY = 1, - XML_ELEMENT_TYPE_ANY, - XML_ELEMENT_TYPE_MIXED, - XML_ELEMENT_TYPE_ELEMENT -} xmlElementTypeVal; - -typedef struct _xmlElement xmlElement; -typedef xmlElement *xmlElementPtr; -struct _xmlElement { -#ifndef XML_WITHOUT_CORBA - void *_private; /* for Corba, must be first ! */ -#endif - xmlElementType type; /* XML_ELEMENT_DECL, must be second ! */ - const xmlChar *name; /* Element name */ - struct _xmlNode *children; /* NULL */ - struct _xmlNode *last; /* NULL */ - struct _xmlDtd *parent; /* -> DTD */ - struct _xmlNode *next; /* next sibling link */ - struct _xmlNode *prev; /* previous sibling link */ - struct _xmlDoc *doc; /* the containing document */ - - xmlElementTypeVal etype; /* The type */ - xmlElementContentPtr content; /* the allowed element content */ - xmlAttributePtr attributes; /* List of the declared attributes */ - const xmlChar *prefix; /* the namespace prefix if any */ -}; - -/* - * An XML namespace. - * Note that prefix == NULL is valid, it defines the default namespace - * within the subtree (until overriden). - * - * XML_GLOBAL_NAMESPACE is now deprecated for good - * xmlNsType is unified with xmlElementType - */ - -#define XML_LOCAL_NAMESPACE XML_NAMESPACE_DECL -typedef xmlElementType xmlNsType; - -typedef struct _xmlNs xmlNs; -typedef xmlNs *xmlNsPtr; -struct _xmlNs { - struct _xmlNs *next; /* next Ns link for this node */ - xmlNsType type; /* global or local */ - const xmlChar *href; /* URL for the namespace */ - const xmlChar *prefix; /* prefix for the namespace */ -}; - -/* - * An XML DtD, as defined by parent link */ - struct _xmlNode *next; /* next sibling link */ - struct _xmlNode *prev; /* previous sibling link */ - struct _xmlDoc *doc; /* the containing document */ - - /* End of common part */ - void *notations; /* Hash table for notations if any */ - void *elements; /* Hash table for elements if any */ - void *attributes; /* Hash table for attributes if any */ - void *entities; /* Hash table for entities if any */ - const xmlChar *ExternalID; /* External identifier for PUBLIC DTD */ - const xmlChar *SystemID; /* URI for a SYSTEM or PUBLIC DTD */ - void *pentities; /* Hash table for param entities if any */ -}; - -/* - * A attribute of an XML node. - */ -typedef struct _xmlAttr xmlAttr; -typedef xmlAttr *xmlAttrPtr; -struct _xmlAttr { -#ifndef XML_WITHOUT_CORBA - void *_private; /* for Corba, must be first ! */ -#endif - xmlElementType type; /* XML_ATTRIBUTE_NODE, must be second ! */ - const xmlChar *name; /* the name of the property */ - struct _xmlNode *children; /* the value of the property */ - struct _xmlNode *last; /* NULL */ - struct _xmlNode *parent; /* child->parent link */ - struct _xmlAttr *next; /* next sibling link */ - struct _xmlAttr *prev; /* previous sibling link */ - struct _xmlDoc *doc; /* the containing document */ - xmlNs *ns; /* pointer to the associated namespace */ - xmlAttributeType atype; /* the attribute type if validating */ -}; - -/* - * An XML ID instance. - */ - -typedef struct _xmlID xmlID; -typedef xmlID *xmlIDPtr; -struct _xmlID { - struct _xmlID *next; /* next ID */ - const xmlChar *value; /* The ID name */ - xmlAttrPtr attr; /* The attribut holding it */ -}; - -/* - * An XML IDREF instance. - */ - -typedef struct _xmlRef xmlRef; -typedef xmlRef *xmlRefPtr; -struct _xmlRef { - struct _xmlRef *next; /* next Ref */ - const xmlChar *value; /* The Ref name */ - xmlAttrPtr attr; /* The attribut holding it */ -}; - -/* - * A buffer structure - */ - -typedef enum { - XML_BUFFER_ALLOC_DOUBLEIT, - XML_BUFFER_ALLOC_EXACT -} xmlBufferAllocationScheme; - -typedef struct _xmlBuffer xmlBuffer; -typedef xmlBuffer *xmlBufferPtr; -struct _xmlBuffer { - xmlChar *content; /* The buffer content UTF8 */ - unsigned int use; /* The buffer size used */ - unsigned int size; /* The buffer size */ - xmlBufferAllocationScheme alloc; /* The realloc method */ -}; - -/* - * A node in an XML tree. - */ -typedef struct _xmlNode xmlNode; -typedef xmlNode *xmlNodePtr; -struct _xmlNode { -#ifndef XML_WITHOUT_CORBA - void *_private; /* for Corba, must be first ! */ -#endif - xmlElementType type; /* type number, must be second ! */ - const xmlChar *name; /* the name of the node, or the entity */ - struct _xmlNode *children; /* parent->childs link */ - struct _xmlNode *last; /* last child link */ - struct _xmlNode *parent; /* child->parent link */ - struct _xmlNode *next; /* next sibling link */ - struct _xmlNode *prev; /* previous sibling link */ - struct _xmlDoc *doc; /* the containing document */ - xmlNs *ns; /* pointer to the associated namespace */ -#ifndef XML_USE_BUFFER_CONTENT - xmlChar *content; /* the content */ -#else - xmlBufferPtr content; /* the content in a buffer */ -#endif - - /* End of common part */ - struct _xmlAttr *properties;/* properties list */ - xmlNs *nsDef; /* namespace definitions on this node */ -}; - -/* - * An XML document. - */ -typedef struct _xmlDoc xmlDoc; -typedef xmlDoc *xmlDocPtr; -struct _xmlDoc { -#ifndef XML_WITHOUT_CORBA - void *_private; /* for Corba, must be first ! */ -#endif - xmlElementType type; /* XML_DOCUMENT_NODE, must be second ! */ - char *name; /* name/filename/URI of the document */ - struct _xmlNode *children; /* the document tree */ - struct _xmlNode *last; /* last child link */ - struct _xmlNode *parent; /* child->parent link */ - struct _xmlNode *next; /* next sibling link */ - struct _xmlNode *prev; /* previous sibling link */ - struct _xmlDoc *doc; /* autoreference to itself */ - - /* End of common part */ - int compression;/* level of zlib compression */ - int standalone; /* standalone document (no external refs) */ - struct _xmlDtd *intSubset; /* the document internal subset */ - struct _xmlDtd *extSubset; /* the document external subset */ - struct _xmlNs *oldNs; /* Global namespace, the old way */ - const xmlChar *version; /* the XML version string */ - const xmlChar *encoding; /* external initial encoding, if any */ - void *ids; /* Hash table for ID attributes if any */ - void *refs; /* Hash table for IDREFs attributes if any */ - const xmlChar *URL; /* The URI for that document */ - int charset; /* encoding of the in-memory content - actually an xmlCharEncoding */ -}; - -/** - * Predefined values for some standard encodings - * Libxml don't do beforehand translation on UTF8, ISOLatinX - * It also support UTF16 (LE and BE) by default. - * - * Anything else would have to be translated to UTF8 before being - * given to the parser itself. The BOM for UTF16 and the encoding - * declaration are looked at and a converter is looked for at that - * point. If not found the parser stops here as asked by the XML REC - * Converter can be registered by the user using xmlRegisterCharEncodingHandler - * but the currentl form doesn't allow stateful transcoding (a serious - * problem agreed !). If iconv has been found it will be used - * automatically and allow stateful transcoding, the simplest is then - * to be sure to enable icon and to provide iconv libs for the encoding - * support needed. - */ -typedef enum { - XML_CHAR_ENCODING_ERROR= -1, /* No char encoding detected */ - XML_CHAR_ENCODING_NONE= 0, /* No char encoding detected */ - XML_CHAR_ENCODING_UTF8= 1, /* UTF-8 */ - XML_CHAR_ENCODING_UTF16LE= 2, /* UTF-16 little endian */ - XML_CHAR_ENCODING_UTF16BE= 3, /* UTF-16 big endian */ - XML_CHAR_ENCODING_UCS4LE= 4, /* UCS-4 little endian */ - XML_CHAR_ENCODING_UCS4BE= 5, /* UCS-4 big endian */ - XML_CHAR_ENCODING_EBCDIC= 6, /* EBCDIC uh! */ - XML_CHAR_ENCODING_UCS4_2143=7, /* UCS-4 unusual ordering */ - XML_CHAR_ENCODING_UCS4_3412=8, /* UCS-4 unusual ordering */ - XML_CHAR_ENCODING_UCS2= 9, /* UCS-2 */ - XML_CHAR_ENCODING_8859_1= 10,/* ISO-8859-1 ISO Latin 1 */ - XML_CHAR_ENCODING_8859_2= 11,/* ISO-8859-2 ISO Latin 2 */ - XML_CHAR_ENCODING_8859_3= 12,/* ISO-8859-3 */ - XML_CHAR_ENCODING_8859_4= 13,/* ISO-8859-4 */ - XML_CHAR_ENCODING_8859_5= 14,/* ISO-8859-5 */ - XML_CHAR_ENCODING_8859_6= 15,/* ISO-8859-6 */ - XML_CHAR_ENCODING_8859_7= 16,/* ISO-8859-7 */ - XML_CHAR_ENCODING_8859_8= 17,/* ISO-8859-8 */ - XML_CHAR_ENCODING_8859_9= 18,/* ISO-8859-9 */ - XML_CHAR_ENCODING_2022_JP= 19,/* ISO-2022-JP */ - XML_CHAR_ENCODING_SHIFT_JIS=20,/* Shift_JIS */ - XML_CHAR_ENCODING_EUC_JP= 21,/* EUC-JP */ - XML_CHAR_ENCODING_ASCII= 22 /* pure ASCII */ -} xmlCharEncoding; - -/** - * xmlCharEncodingInputFunc: - * @param out a pointer ot an array of bytes to store the UTF-8 result - * @param outlen the length of out - * @param in a pointer ot an array of chars in the original encoding - * @param inlen the length of in - * - * Take a block of chars in the original encoding and try to convert - * it to an UTF-8 block of chars out. - * - * Returns the number of byte written, or -1 by lack of space, or -2 - * if the transcoding failed. - * The value of inlen after return is the number of octets consumed - * as the return value is positive, else unpredictiable. - * The value of outlen after return is the number of ocetes consumed. - */ -typedef int (* xmlCharEncodingInputFunc)(unsigned char* out, int *outlen, - const unsigned char* in, int *inlen); - - -/** - * xmlCharEncodingOutputFunc: - * @param out a pointer ot an array of bytes to store the result - * @param outlen the length of out - * @param in a pointer ot an array of UTF-8 chars - * @param inlen the length of in - * - * Take a block of UTF-8 chars in and try to convert it to an other - * encoding. - * Note: a first call designed to produce heading info is called with - * in = NULL. If stateful this should also initialize the encoder state - * - * Returns the number of byte written, or -1 by lack of space, or -2 - * if the transcoding failed. - * The value of inlen after return is the number of octets consumed - * as the return value is positive, else unpredictiable. - * The value of outlen after return is the number of ocetes consumed. - */ -typedef int (* xmlCharEncodingOutputFunc)(unsigned char* out, int *outlen, - const unsigned char* in, int *inlen); - - -/* - * Block defining the handlers for non UTF-8 encodings. - * If iconv is supported, there is two extra fields - */ - -typedef struct _xmlCharEncodingHandler xmlCharEncodingHandler; -typedef xmlCharEncodingHandler *xmlCharEncodingHandlerPtr; -struct _xmlCharEncodingHandler { - char *name; - xmlCharEncodingInputFunc input; - xmlCharEncodingOutputFunc output; -#ifdef LIBXML_ICONV_ENABLED - iconv_t iconv_in; - iconv_t iconv_out; -#endif /* LIBXML_ICONV_ENABLED */ -}; - -typedef int (*xmlInputMatchCallback) (char const *filename); -typedef void * (*xmlInputOpenCallback) (char const *filename); -typedef int (*xmlInputReadCallback) (void * context, char * buffer, int len); -typedef void (*xmlInputCloseCallback) (void * context); - -typedef struct _xmlParserInputBuffer xmlParserInputBuffer; -typedef xmlParserInputBuffer *xmlParserInputBufferPtr; -struct _xmlParserInputBuffer { - void* context; - xmlInputReadCallback readcallback; - xmlInputCloseCallback closecallback; - - xmlCharEncodingHandlerPtr encoder; /* I18N conversions to UTF-8 */ - - xmlBufferPtr buffer; /* Local buffer encoded in UTF-8 */ - xmlBufferPtr raw; /* if encoder != NULL buffer for raw input */ -}; - - -/* - * Those are the functions and datatypes for the library output - * I/O structures. - */ - -typedef int (*xmlOutputMatchCallback) (char const *filename); -typedef void * (*xmlOutputOpenCallback) (char const *filename); -typedef int (*xmlOutputWriteCallback) (void * context, const char * buffer, - int len); -typedef void (*xmlOutputCloseCallback) (void * context); - -typedef struct _xmlOutputBuffer xmlOutputBuffer; -typedef xmlOutputBuffer *xmlOutputBufferPtr; -struct _xmlOutputBuffer { - void* context; - xmlOutputWriteCallback writecallback; - xmlOutputCloseCallback closecallback; - - xmlCharEncodingHandlerPtr encoder; /* I18N conversions to UTF-8 */ - - xmlBufferPtr buffer; /* Local buffer encoded in UTF-8 or ISOLatin */ - xmlBufferPtr conv; /* if encoder != NULL buffer for output */ - int written; /* total number of byte written */ -}; - -#define XML_DEFAULT_VERSION "1.0" - -/** - * an xmlParserInput is an input flow for the XML processor. - * Each entity parsed is associated an xmlParserInput (except the - * few predefined ones). This is the case both for internal entities - * - in which case the flow is already completely in memory - or - * external entities - in which case we use the buf structure for - * progressive reading and I18N conversions to the internal UTF-8 format. - */ - -typedef void (* xmlParserInputDeallocate)(xmlChar *); -typedef struct _xmlParserInput xmlParserInput; -typedef xmlParserInput *xmlParserInputPtr; -struct _xmlParserInput { - /* Input buffer */ - xmlParserInputBufferPtr buf; /* UTF-8 encoded buffer */ - - const char *filename; /* The file analyzed, if any */ - const char *directory; /* the directory/base of teh file */ - const xmlChar *base; /* Base of the array to parse */ - const xmlChar *cur; /* Current char being parsed */ - const xmlChar *end; /* end of the arry to parse */ - int length; /* length if known */ - int line; /* Current line */ - int col; /* Current column */ - int consumed; /* How many xmlChars already consumed */ - xmlParserInputDeallocate free; /* function to deallocate the base */ - const xmlChar *encoding; /* the encoding string for entity */ - const xmlChar *version; /* the version string for entity */ - int standalone; /* Was that entity marked standalone */ -}; - -/** - * the parser can be asked to collect Node informations, i.e. at what - * place in the file they were detected. - * NOTE: This is off by default and not very well tested. - */ -typedef struct _xmlParserNodeInfo xmlParserNodeInfo; -typedef xmlParserNodeInfo *xmlParserNodeInfoPtr; - -struct _xmlParserNodeInfo { - const struct _xmlNode* node; - /* Position & line # that text that created the node begins & ends on */ - unsigned long begin_pos; - unsigned long begin_line; - unsigned long end_pos; - unsigned long end_line; -}; - -typedef struct _xmlParserNodeInfoSeq xmlParserNodeInfoSeq; -typedef xmlParserNodeInfoSeq *xmlParserNodeInfoSeqPtr; -struct _xmlParserNodeInfoSeq { - unsigned long maximum; - unsigned long length; - xmlParserNodeInfo* buffer; -}; - -/* - * Validation state added for non-determinist content model - */ -typedef struct _xmlValidState xmlValidState; -typedef xmlValidState *xmlValidStatePtr; - -/** - * an xmlValidCtxt is used for error reporting when validating - */ - -typedef void (*xmlValidityErrorFunc) (void *ctx, const char *msg, ...); -typedef void (*xmlValidityWarningFunc) (void *ctx, const char *msg, ...); - -typedef struct _xmlValidCtxt xmlValidCtxt; -typedef xmlValidCtxt *xmlValidCtxtPtr; -struct _xmlValidCtxt { - void *userData; /* user specific data block */ - xmlValidityErrorFunc error; /* the callback in case of errors */ - xmlValidityWarningFunc warning; /* the callback in case of warning */ - - /* Node analysis stack used when validating within entities */ - xmlNodePtr node; /* Current parsed Node */ - int nodeNr; /* Depth of the parsing stack */ - int nodeMax; /* Max depth of the parsing stack */ - xmlNodePtr *nodeTab; /* array of nodes */ - - int finishDtd; /* finished validating the Dtd ? */ - xmlDocPtr doc; /* the document */ - int valid; /* temporary validity check result */ - - /* state state used for non-determinist content validation */ - xmlValidState *vstate; /* current state */ - int vstateNr; /* Depth of the validation stack */ - int vstateMax; /* Max depth of the validation stack */ - xmlValidState *vstateTab; /* array of validation states */ -}; - -typedef struct _xmlLink xmlLink; -typedef xmlLink *xmlLinkPtr; - -typedef struct _xmlList xmlList; -typedef xmlList *xmlListPtr; - -typedef void (*xmlListDeallocator) (xmlLinkPtr lk); -typedef int (*xmlListDataCompare) (const void *data0, const void *data1); -typedef int (*xmlListWalker) (const void *data, const void *user); - -/* - * ALl notation declarations are stored in a table - * there is one table per DTD - */ - -typedef struct _xmlHashTable xmlNotationTable; -typedef xmlNotationTable *xmlNotationTablePtr; - -/* - * ALl element declarations are stored in a table - * there is one table per DTD - */ - -typedef struct _xmlHashTable xmlElementTable; -typedef xmlElementTable *xmlElementTablePtr; - -/* - * ALl attribute declarations are stored in a table - * there is one table per DTD - */ - -typedef struct _xmlHashTable xmlAttributeTable; -typedef xmlAttributeTable *xmlAttributeTablePtr; - -/* - * ALl IDs attributes are stored in a table - * there is one table per document - */ - -typedef struct _xmlHashTable xmlIDTable; -typedef xmlIDTable *xmlIDTablePtr; - -/* - * ALl Refs attributes are stored in a table - * there is one table per document - */ - -typedef struct _xmlHashTable xmlRefTable; -typedef xmlRefTable *xmlRefTablePtr; - -/* helper */ -xmlChar * xmlSplitQName2 (const xmlChar *name, - xmlChar **prefix); - -/** - * The parser is now working also as a state based parser - * The recursive one use the stagte info for entities processing - */ -typedef enum { - XML_PARSER_EOF = -1, /* nothing is to be parsed */ - XML_PARSER_START = 0, /* nothing has been parsed */ - XML_PARSER_MISC, /* Misc* before int subset */ - XML_PARSER_PI, /* Whithin a processing instruction */ - XML_PARSER_DTD, /* within some DTD content */ - XML_PARSER_PROLOG, /* Misc* after internal subset */ - XML_PARSER_COMMENT, /* within a comment */ - XML_PARSER_START_TAG, /* within a start tag */ - XML_PARSER_CONTENT, /* within the content */ - XML_PARSER_CDATA_SECTION, /* within a CDATA section */ - XML_PARSER_END_TAG, /* within a closing tag */ - XML_PARSER_ENTITY_DECL, /* within an entity declaration */ - XML_PARSER_ENTITY_VALUE, /* within an entity value in a decl */ - XML_PARSER_ATTRIBUTE_VALUE, /* within an attribute value */ - XML_PARSER_SYSTEM_LITERAL, /* within a SYSTEM value */ - XML_PARSER_EPILOG, /* the Misc* after the last end tag */ - XML_PARSER_IGNORE /* within an IGNORED section */ -} xmlParserInputState; - -/** - * The parser context. - * NOTE This doesn't completely defines the parser state, the (current ?) - * design of the parser uses recursive function calls since this allow - * and easy mapping from the production rules of the specification - * to the actual code. The drawback is that the actual function call - * also reflect the parser state. However most of the parsing routines - * takes as the only argument the parser context pointer, so migrating - * to a state based parser for progressive parsing shouldn't be too hard. - */ -typedef struct _xmlParserCtxt xmlParserCtxt; -typedef xmlParserCtxt *xmlParserCtxtPtr; -struct _xmlParserCtxt { - struct _xmlSAXHandler *sax; /* The SAX handler */ - void *userData; /* For SAX interface only, used by DOM build */ - xmlDocPtr myDoc; /* the document being built */ - int wellFormed; /* is the document well formed */ - int replaceEntities; /* shall we replace entities ? */ - const xmlChar *version; /* the XML version string */ - const xmlChar *encoding; /* the declared encoding, if any */ - int standalone; /* standalone document */ - int html; /* an HTML(1)/Docbook(2) document */ - - /* Input stream stack */ - xmlParserInputPtr input; /* Current input stream */ - int inputNr; /* Number of current input streams */ - int inputMax; /* Max number of input streams */ - xmlParserInputPtr *inputTab; /* stack of inputs */ - - /* Node analysis stack only used for DOM building */ - xmlNodePtr node; /* Current parsed Node */ - int nodeNr; /* Depth of the parsing stack */ - int nodeMax; /* Max depth of the parsing stack */ - xmlNodePtr *nodeTab; /* array of nodes */ - - int record_info; /* Whether node info should be kept */ - xmlParserNodeInfoSeq node_seq; /* info about each node parsed */ - - int errNo; /* error code */ - - int hasExternalSubset; /* reference and external subset */ - int hasPErefs; /* the internal subset has PE refs */ - int external; /* are we parsing an external entity */ - - int valid; /* is the document valid */ - int validate; /* shall we try to validate ? */ - xmlValidCtxt vctxt; /* The validity context */ - - xmlParserInputState instate; /* current type of input */ - int token; /* next char look-ahead */ - - char *directory; /* the data directory */ - - /* Node name stack */ - xmlChar *name; /* Current parsed Node */ - int nameNr; /* Depth of the parsing stack */ - int nameMax; /* Max depth of the parsing stack */ - xmlChar * *nameTab; /* array of nodes */ - - long nbChars; /* number of xmlChar processed */ - long checkIndex; /* used by progressive parsing lookup */ - int keepBlanks; /* ugly but ... */ - int disableSAX; /* SAX callbacks are disabled */ - int inSubset; /* Parsing is in int 1/ext 2 subset */ - xmlChar * intSubName; /* name of subset */ - xmlChar * extSubURI; /* URI of external subset */ - xmlChar * extSubSystem; /* SYSTEM ID of external subset */ - - /* xml:space values */ - int * space; /* Should the parser preserve spaces */ - int spaceNr; /* Depth of the parsing stack */ - int spaceMax; /* Max depth of the parsing stack */ - int * spaceTab; /* array of space infos */ - - int depth; /* to prevent entity substitution loops */ - xmlParserInputPtr entity; /* used to check entities boundaries */ - int charset; /* encoding of the in-memory content - actually an xmlCharEncoding */ - int nodelen; /* Those two fields are there to */ - int nodemem; /* Speed up large node parsing */ - int pedantic; /* signal pedantic warnings */ - void *_private; /* For user data, libxml won't touch it */ - - int loadsubset; /* should the external subset be loaded */ -}; - -/** - * a SAX Locator. - */ -typedef struct _xmlSAXLocator xmlSAXLocator; -typedef xmlSAXLocator *xmlSAXLocatorPtr; -struct _xmlSAXLocator { - const xmlChar *(*getPublicId)(void *ctx); - const xmlChar *(*getSystemId)(void *ctx); - int (*getLineNumber)(void *ctx); - int (*getColumnNumber)(void *ctx); -}; - -/* - * The different valid entity types - */ -typedef enum { - XML_INTERNAL_GENERAL_ENTITY = 1, - XML_EXTERNAL_GENERAL_PARSED_ENTITY = 2, - XML_EXTERNAL_GENERAL_UNPARSED_ENTITY = 3, - XML_INTERNAL_PARAMETER_ENTITY = 4, - XML_EXTERNAL_PARAMETER_ENTITY = 5, - XML_INTERNAL_PREDEFINED_ENTITY = 6 -} xmlEntityType; - -/* - * An unit of storage for an entity, contains the string, the value - * and the linkind data needed for the linking in the hash table. - */ - -typedef struct _xmlEntity xmlEntity; -typedef xmlEntity *xmlEntityPtr; -struct _xmlEntity { -#ifndef XML_WITHOUT_CORBA - void *_private; /* for Corba, must be first ! */ -#endif - xmlElementType type; /* XML_ENTITY_DECL, must be second ! */ - const xmlChar *name; /* Attribute name */ - struct _xmlNode *children; /* NULL */ - struct _xmlNode *last; /* NULL */ - struct _xmlDtd *parent; /* -> DTD */ - struct _xmlNode *next; /* next sibling link */ - struct _xmlNode *prev; /* previous sibling link */ - struct _xmlDoc *doc; /* the containing document */ - - xmlChar *orig; /* content without ref substitution */ - xmlChar *content; /* content or ndata if unparsed */ - int length; /* the content length */ - xmlEntityType etype; /* The entity type */ - const xmlChar *ExternalID; /* External identifier for PUBLIC */ - const xmlChar *SystemID; /* URI for a SYSTEM or PUBLIC Entity */ - - struct _xmlEntity *nexte; /* unused */ - const xmlChar *URI; /* the full URI as computed */ -}; - -/* - * ALl entities are stored in an hash table - * there is 2 separate hash tables for global and parmeter entities - */ - -typedef struct _xmlHashTable xmlEntitiesTable; -typedef xmlEntitiesTable *xmlEntitiesTablePtr; - -/* - * External functions : - */ - -/** - * a SAX handler is bunch of callbacks called by the parser when processing - * of the input generate data or structure informations. - */ - -typedef xmlParserInputPtr (*resolveEntitySAXFunc) (void *ctx, - const xmlChar *publicId, const xmlChar *systemId); -typedef void (*internalSubsetSAXFunc) (void *ctx, const xmlChar *name, - const xmlChar *ExternalID, const xmlChar *SystemID); -typedef void (*externalSubsetSAXFunc) (void *ctx, const xmlChar *name, - const xmlChar *ExternalID, const xmlChar *SystemID); -typedef xmlEntityPtr (*getEntitySAXFunc) (void *ctx, - const xmlChar *name); -typedef xmlEntityPtr (*getParameterEntitySAXFunc) (void *ctx, - const xmlChar *name); -typedef void (*entityDeclSAXFunc) (void *ctx, - const xmlChar *name, int type, const xmlChar *publicId, - const xmlChar *systemId, xmlChar *content); -typedef void (*notationDeclSAXFunc)(void *ctx, const xmlChar *name, - const xmlChar *publicId, const xmlChar *systemId); -typedef void (*attributeDeclSAXFunc)(void *ctx, const xmlChar *elem, - const xmlChar *name, int type, int def, - const xmlChar *defaultValue, xmlEnumerationPtr tree); -typedef void (*elementDeclSAXFunc)(void *ctx, const xmlChar *name, - int type, xmlElementContentPtr content); -typedef void (*unparsedEntityDeclSAXFunc)(void *ctx, - const xmlChar *name, const xmlChar *publicId, - const xmlChar *systemId, const xmlChar *notationName); -typedef void (*setDocumentLocatorSAXFunc) (void *ctx, - xmlSAXLocatorPtr loc); -typedef void (*startDocumentSAXFunc) (void *ctx); -typedef void (*endDocumentSAXFunc) (void *ctx); -typedef void (*startElementSAXFunc) (void *ctx, const xmlChar *name, - const xmlChar **atts); -typedef void (*endElementSAXFunc) (void *ctx, const xmlChar *name); -typedef void (*attributeSAXFunc) (void *ctx, const xmlChar *name, - const xmlChar *value); -typedef void (*referenceSAXFunc) (void *ctx, const xmlChar *name); -typedef void (*charactersSAXFunc) (void *ctx, const xmlChar *ch, - int len); -typedef void (*ignorableWhitespaceSAXFunc) (void *ctx, - const xmlChar *ch, int len); -typedef void (*processingInstructionSAXFunc) (void *ctx, - const xmlChar *target, const xmlChar *data); -typedef void (*commentSAXFunc) (void *ctx, const xmlChar *value); -typedef void (*cdataBlockSAXFunc) (void *ctx, const xmlChar *value, int len); -typedef void (*warningSAXFunc) (void *ctx, const char *msg, ...); -typedef void (*errorSAXFunc) (void *ctx, const char *msg, ...); -typedef void (*fatalErrorSAXFunc) (void *ctx, const char *msg, ...); -typedef int (*isStandaloneSAXFunc) (void *ctx); -typedef int (*hasInternalSubsetSAXFunc) (void *ctx); -typedef int (*hasExternalSubsetSAXFunc) (void *ctx); - -typedef struct _xmlSAXHandler xmlSAXHandler; -typedef xmlSAXHandler *xmlSAXHandlerPtr; -struct _xmlSAXHandler { - internalSubsetSAXFunc internalSubset; - isStandaloneSAXFunc isStandalone; - hasInternalSubsetSAXFunc hasInternalSubset; - hasExternalSubsetSAXFunc hasExternalSubset; - resolveEntitySAXFunc resolveEntity; - getEntitySAXFunc getEntity; - entityDeclSAXFunc entityDecl; - notationDeclSAXFunc notationDecl; - attributeDeclSAXFunc attributeDecl; - elementDeclSAXFunc elementDecl; - unparsedEntityDeclSAXFunc unparsedEntityDecl; - setDocumentLocatorSAXFunc setDocumentLocator; - startDocumentSAXFunc startDocument; - endDocumentSAXFunc endDocument; - startElementSAXFunc startElement; - endElementSAXFunc endElement; - referenceSAXFunc reference; - charactersSAXFunc characters; - ignorableWhitespaceSAXFunc ignorableWhitespace; - processingInstructionSAXFunc processingInstruction; - commentSAXFunc comment; - warningSAXFunc warning; - errorSAXFunc error; - fatalErrorSAXFunc fatalError; - getParameterEntitySAXFunc getParameterEntity; - cdataBlockSAXFunc cdataBlock; - externalSubsetSAXFunc externalSubset; -}; - -/** - * External entity loaders types - */ -typedef xmlParserInputPtr (*xmlExternalEntityLoader)(const char *URL, - const char *ID, - xmlParserCtxtPtr context); - -/* - * Compatibility naming layer with libxml1 - */ -#ifndef xmlChildrenNode -#define xmlChildrenNode children -#define xmlRootNode children -#endif - - -/*********************Xml routines and function pointers */ -#ifdef IN_XMLSTUB -#define XML_EXTERN -#else -#define XML_EXTERN extern -#endif - -typedef struct { - /* Functions */ - xmlDocPtr (*xmlParseFile)(const char *filename); - int (*xmlStrcmp)(const xmlChar *str1, const xmlChar *str2); - xmlParserCtxtPtr (*xmlCreatePushParserCtxt)(xmlSAXHandlerPtr, void *, const char *, - int, const char *); - int (*xmlParseChunk)(xmlParserCtxtPtr, const char *, int, int); - void (*xmlFreeParserCtxt)(xmlParserCtxtPtr); - xmlNodePtr (*xmlDocGetRootElement)(xmlDocPtr); - void (*xmlFreeDoc)(xmlDocPtr); - char *(*xmlNodeListGetString)(xmlDocPtr, xmlNodePtr, int); - char *(*xmlGetProp)(xmlNodePtr, const char *); - int (*xmlKeepBlanksDefault)(int); - int (*xmlSubstituteEntitiesDefault)(int); -#ifdef WIRESHARK_XML_DO_VALIDITY_CHECKING - int *xmlDoValidityCheckingDefaultValue; -#endif -} XML_STUB; - -XML_EXTERN XML_STUB XmlStub; -XML_EXTERN int XmlStubInitialized; - -#ifdef _WIN32 -/* We're in windows, use the windows filename */ -#define XML_LIBRARY "libxml2.dll" -#else -#define XML_LIBRARY "libxml2.so" -#endif - -/* - * This needs to be called before the library is used. It - * returns zero on success. Any non-zero return means that - * either dynamic libraries are not supported, or that libxml - * is not installed on the current system. (Or it's not in - * the LD path) - */ -int loadLibXML(void); - - - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/file.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/file.h deleted file mode 100644 index e7c4de6d..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/file.h +++ /dev/null @@ -1,486 +0,0 @@ -/* file.h - * Definitions for file structures and routines - * - * $Id: file.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __FILE_H__ -#define __FILE_H__ - -#include "packet-range.h" -#include "wiretap/wtap.h" -#include -#include "print.h" -#include -#include - -#include "cfile.h" - - -/** Return values from functions that only can succeed or fail. */ -typedef enum { - CF_OK, /**< operation succeeded */ - CF_ERROR /**< operation got an error (function may provide err with details) */ -} cf_status_t; - -/** Return values from functions that read capture files. */ -typedef enum { - CF_READ_OK, /**< operation succeeded */ - CF_READ_ERROR, /**< operation got an error (function may provide err with details) */ - CF_READ_ABORTED /**< operation aborted by user */ -} cf_read_status_t; - -/** Return values from functions that print sets of packets. */ -typedef enum { - CF_PRINT_OK, /**< print operation succeeded */ - CF_PRINT_OPEN_ERROR, /**< print operation failed while opening printer */ - CF_PRINT_WRITE_ERROR /**< print operation failed while writing to the printer */ -} cf_print_status_t; - -typedef enum { - cf_cb_file_closing, - cf_cb_file_closed, - cf_cb_file_read_start, - cf_cb_file_read_finished, -#ifdef HAVE_LIBPCAP - cf_cb_live_capture_prepared, - cf_cb_live_capture_update_started, - cf_cb_live_capture_update_continue, - cf_cb_live_capture_update_finished, - cf_cb_live_capture_fixed_started, - cf_cb_live_capture_fixed_continue, - cf_cb_live_capture_fixed_finished, - cf_cb_live_capture_stopping, -#endif - cf_cb_packet_selected, - cf_cb_packet_unselected, - cf_cb_field_unselected, - cf_cb_file_safe_started, - cf_cb_file_safe_finished, - cf_cb_file_safe_reload_finished, - cf_cb_file_safe_failed -} cf_cbs; - -typedef void (*cf_callback_t) (gint event, gpointer data, gpointer user_data); - -extern void -cf_callback_invoke(int event, gpointer data); - -extern void -cf_callback_add(cf_callback_t func, gpointer user_data); - -extern void -cf_callback_remove(cf_callback_t func); - -/** - * Open a capture file. - * - * @param cf the capture file to be opened - * @param fname the filename to be opened - * @param is_tempfile is this a temporary file? - * @return one of cf_status_t - */ -cf_status_t cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err); - -/** - * Close a capture file. - * - * @param cf the capture file to be closed - */ -void cf_close(capture_file *cf); - -/** - * Reload a capture file. - * - * @param cf the capture file to be reloaded - */ -void cf_reload(capture_file *cf); - -/** - * Read all packets of a capture file into the internal structures. - * - * @param cf the capture file to be read - * @return one of cf_read_status_t - */ -cf_read_status_t cf_read(capture_file *cf); - -/** - * Start reading from the end of a capture file. - * This is used in "Update list of packets in Real-Time". - * - * @param cf the capture file to be read from - * @param fname the filename to be read from - * @param is_tempfile is this a temporary file? - * @param err the error code, if an error had occured - * @return one of cf_status_t - */ -cf_status_t cf_start_tail(capture_file *cf, const char *fname, gboolean is_tempfile, int *err); - -/** - * Read packets from the "end" of a capture file. - * - * @param cf the capture file to be read from - * @param to_read the number of packets to read - * @param err the error code, if an error had occured - * @return one of cf_read_status_t - */ -cf_read_status_t cf_continue_tail(capture_file *cf, volatile int to_read, int *err); - -/** - * Finish reading from "end" of a capture file. - * - * @param cf the capture file to be read from - * @param err the error code, if an error had occured - * @return one of cf_read_status_t - */ -cf_read_status_t cf_finish_tail(capture_file *cf, int *err); - -/** - * Determine whether this capture file (or a range of it) can be saved - * (except by copying the raw file data). - * - * @param cf the capture file to check - * @return TRUE if it can be saved, FALSE if it can't - */ -gboolean cf_can_save_as(capture_file *cf); - -/** - * Save a capture file (or a range of it). - * - * @param cf the capture file to save to - * @param fname the filename to save to - * @param range the range of packets to save - * @param save_format the format of the file to save (libpcap, ...) - * @param compressed wether to gzip compress the file - * @return one of cf_status_t - */ -cf_status_t cf_save(capture_file * cf, const char *fname, packet_range_t *range, guint save_format, gboolean compressed); - -/** - * Get a displayable name of the capture file. - * - * @param cf the capture file - * @return the displayable name (don't have to be g_free'd) - */ -const gchar *cf_get_display_name(capture_file *cf); - -/** - * Get the number of packets in the capture file. - * - * @param cf the capture file - * @return the number of packets in the capture file - */ -int cf_get_packet_count(capture_file *cf); - -/** - * Set the number of packets in the capture file. - * - * @param cf the capture file - * @param the number of packets in the capture file - */ -void cf_set_packet_count(capture_file *cf, int packet_count); - -/** - * Is this capture file a temporary file? - * - * @param cf the capture file - * @return TRUE if it's a temporary file, FALSE otherwise - */ -gboolean cf_is_tempfile(capture_file *cf); - -/** - * Set flag, that this file is a tempfile. - */ -void cf_set_tempfile(capture_file *cf, gboolean is_tempfile); - -/** - * Set flag, if the number of packet drops while capturing are known or not. - * - * @param cf the capture file - * @param drops_known TRUE if the number of packet drops are known, FALSE otherwise - */ -void cf_set_drops_known(capture_file *cf, gboolean drops_known); - -/** - * Set the number of packet drops while capturing. - * - * @param cf the capture file - * @param drops the number of packet drops occured while capturing - */ -void cf_set_drops(capture_file *cf, guint32 drops); - -/** - * Get flag state, if the number of packet drops while capturing are known or not. - * - * @param cf the capture file - * @return TRUE if the number of packet drops are known, FALSE otherwise - */ -gboolean cf_get_drops_known(capture_file *cf); - -/** - * Get the number of packet drops while capturing. - * - * @param cf the capture file - * @return the number of packet drops occured while capturing - */ -guint32 cf_get_drops(capture_file *cf); - -/** - * Set the read filter. - * @todo this shouldn't be required, remove it somehow - * - * @param cf the capture file - * @param rfcode the readfilter - */ -void cf_set_rfcode(capture_file *cf, dfilter_t *rfcode); - -/** - * "Display Filter" packets in the capture file. - * - * @param cf the capture file - * @param dfilter the display filter - * @param force TRUE if do in any case, FALSE only if dfilter changed - * @return one of cf_status_t - */ -cf_status_t cf_filter_packets(capture_file *cf, gchar *dfilter, gboolean force); - -/** - * At least one "Refence Time" flag has changed, rescan all packets. - * - * @param cf the capture file - */ -void cf_reftime_packets(capture_file *cf); - -/** - * At least one "Refence Time" flag has changed, rescan all packets. - * - * @param cf the capture file - */ -void cf_colorize_packets(capture_file *cf); - -/** - * "Something" has changed, rescan all packets. - * - * @param cf the capture file - */ -void cf_redissect_packets(capture_file *cf); - -/** - * Rescan all packets and just run taps - don't reconstruct the display. - * - * @param cf the capture file - * @param do_columns TRUE if columns are to be generated, FALSE otherwise - * @return one of cf_read_status_t - */ -cf_read_status_t cf_retap_packets(capture_file *cf, gboolean do_columns); - -/** - * The time format has changed, rescan all packets. - * - * @param cf the capture file - */ -void cf_change_time_formats(capture_file *cf); - -/** - * Print the capture file. - * - * @param cf the capture file - * @param print_args the arguments what and how to print - * @return one of cf_print_status_t - */ -cf_print_status_t cf_print_packets(capture_file *cf, print_args_t *print_args); - -/** - * Print (export) the capture file into PDML format. - * - * @param cf the capture file - * @param print_args the arguments what and how to export - * @return one of cf_print_status_t - */ -cf_print_status_t cf_write_pdml_packets(capture_file *cf, print_args_t *print_args); - -/** - * Print (export) the capture file into PSML format. - * - * @param cf the capture file - * @param print_args the arguments what and how to export - * @return one of cf_print_status_t - */ -cf_print_status_t cf_write_psml_packets(capture_file *cf, print_args_t *print_args); - -/** - * Print (export) the capture file into CSV format. - * - * @param cf the capture file - * @param print_args the arguments what and how to export - * @return one of cf_print_status_t - */ -cf_print_status_t cf_write_csv_packets(capture_file *cf, print_args_t *print_args); - -/** - * Print (export) the capture file into C Arrays format. - * - * @param cf the capture file - * @param print_args the arguments what and how to export - * @return one of cf_print_status_t - */ -cf_print_status_t cf_write_carrays_packets(capture_file *cf, print_args_t *print_args); - -/** - * Find Packet in protocol tree. - * - * @param cf the capture file - * @param string the string to find - * @return TRUE if a packet was found, FALSE otherwise - */ -gboolean cf_find_packet_protocol_tree(capture_file *cf, const char *string); - -/** - * Find Packet in summary line. - * - * @param cf the capture file - * @param string the string to find - * @return TRUE if a packet was found, FALSE otherwise - */ -gboolean cf_find_packet_summary_line(capture_file *cf, const char *string); - -/** - * Find Packet in packet data. - * - * @param cf the capture file - * @param string the string to find - * @param string_size the size of the string to find - * @return TRUE if a packet was found, FALSE otherwise - */ -gboolean cf_find_packet_data(capture_file *cf, const guint8 *string, - size_t string_size); - -/** - * Find Packet by display filter. - * - * @param cf the capture file - * @param sfcode the display filter to find a packet for - * @return TRUE if a packet was found, FALSE otherwise - */ -gboolean cf_find_packet_dfilter(capture_file *cf, dfilter_t *sfcode); - -/** - * GoTo Packet in first row. - * - * @param cf the capture file - * @return TRUE if the first row exists, FALSE otherwise - */ -gboolean cf_goto_top_frame(capture_file *cf); - -/** - * GoTo Packet in last row. - * - * @param cf the capture file - * @return TRUE if last row exists, FALSE otherwise - */ -gboolean cf_goto_bottom_frame(capture_file *cf); - -/** - * GoTo Packet with the given row. - * - * @param cf the capture file - * @param row the row to go to - * @return TRUE if this row exists, FALSE otherwise - */ -gboolean cf_goto_frame(capture_file *cf, guint row); - -/** - * Go to frame specified by currently selected protocol tree field. - * (Go To Corresponding Packet) - * @todo this is ugly and should be improved! - * - * @param cf the capture file - * @return TRUE if this packet exists, FALSE otherwise - */ -gboolean cf_goto_framenum(capture_file *cf); - -/** - * Select the packet in the given row. - * - * @param cf the capture file - * @param row the row to select - */ -void cf_select_packet(capture_file *cf, int row); - -/** - * Unselect all packets, if any. - * - * @param cf the capture file - * @param row the row to select - */ -void cf_unselect_packet(capture_file *cf); - -/** - * Unselect all protocol tree fields, if any. - * - * @param cf the capture file - * @param row the row to select - */ -void cf_unselect_field(capture_file *cf); - -/** - * Mark a particular frame in a particular capture. - * - * @param cf the capture file - * @param frame the frame to be marked - */ -void cf_mark_frame(capture_file *cf, frame_data *frame); - -/** - * Unmark a particular frame in a particular capture. - * - * @param cf the capture file - * @param frame the frame to be unmarked - */ -void cf_unmark_frame(capture_file *cf, frame_data *frame); - -/** - * Convert error number and info to a complete message. - * - * @param err the error number - * @param err_info the additional info about this error (e.g. filename) - * @return statically allocated error message - */ -char *cf_read_error_message(int err, const gchar *err_info); - -/** - * Merge two (or more) capture files into one. - * @todo is this the right place for this function? It doesn't have to do a lot with capture_file. - * - * @param out_filename pointer to output filename; if output filename is - * NULL, a temporary file name is generated and *out_filename is set - * to point to the generated file name - * @param in_file_count the number of input files to merge - * @param in_filnames array of input filenames - * @param file_type the output filetype - * @param do_append FALSE to merge chronologically, TRUE simply append - * @return one of cf_status_t - */ -cf_status_t -cf_merge_files(char **out_filename, int in_file_count, - char *const *in_filenames, int file_type, gboolean do_append); - -#endif /* file.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/fileset.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/fileset.h deleted file mode 100644 index 47015f99..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/fileset.h +++ /dev/null @@ -1,75 +0,0 @@ -/* fileset.h - * Definitions for routines for file sets. - * - * $Id: fileset.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __FILESET_H__ -#define __FILESET_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - - -typedef struct _fileset_entry { - const char *fullname; /* File name with path (g_strdup'ed) */ - const char *name; /* File name without path (g_strdup'ed) */ - time_t ctime; /* create time */ - time_t mtime; /* last modified time */ - long size; /* size of file in bytes */ - gboolean current; /* is this the currently loaded file? */ -} fileset_entry; - - -/* helper: is this a probable file of a file set (does the naming pattern match)? */ -extern gboolean fileset_filename_match_pattern(const char *fname); - -/* helper: test, if both files could be in the same file set */ -extern gboolean fileset_is_file_in_set(const char *fname1, const char *fname2); - -extern void fileset_add_dir(const char *fname); - -extern void fileset_delete(void); - -/* get the current directory name */ -extern const char *fileset_get_dirname(void); - -extern fileset_entry *fileset_get_next(void); -extern fileset_entry *fileset_get_previous(void); - - - -/* this file is a part of the current file set */ -extern void fileset_dlg_add_file(fileset_entry *entry); - -extern void fileset_file_opened(const char *fname); - -extern void fileset_file_closed(void); - -extern void fileset_update_dlg(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __FILESET_H__ */ - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/filters.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/filters.h deleted file mode 100644 index 0ca489b2..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/filters.h +++ /dev/null @@ -1,87 +0,0 @@ -/* filters.h - * Declarations of routines for reading and writing the filters file. - * - * $Id: filters.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* - * Filter lists. - */ -typedef enum { - CFILTER_LIST, /* capture filter list - saved */ - DFILTER_LIST, /* display filter list - saved */ - CFILTER_EDITED_LIST, /* capture filter list - currently edited */ - DFILTER_EDITED_LIST /* display filter list - currently edited */ -} filter_list_type_t; - -/* - * Item in a list of filters. - */ -typedef struct { - char *name; /* filter name */ - char *strval; /* filter expression */ -} filter_def; - -/* - * Read in a list of filters. - * - * On success, "*pref_path_return" is set to NULL. - * On error, "*pref_path_return" is set to point to the pathname of - * the file we tried to read - it should be freed by our caller - - * and "*errno_return" is set to the error. - */ -void read_filter_list(filter_list_type_t list_type, char **pref_path_return, - int *errno_return); - -/* - * Get a pointer to the first entry in a filter list. - */ -GList *get_filter_list_first(filter_list_type_t list); - -/* - * Add a new filter to the end of a list. - * Returns a pointer to the newly-added entry. - */ -GList *add_to_filter_list(filter_list_type_t list, const char *name, - const char *expression); - -/* - * Remove a filter from a list. - */ -void remove_from_filter_list(filter_list_type_t list, GList *fl_entry); - -/* - * Write out a list of filters. - * - * On success, "*pref_path_return" is set to NULL. - * On error, "*pref_path_return" is set to point to the pathname of - * the file we tried to read - it should be freed by our caller - - * and "*errno_return" is set to the error. - */ -void save_filter_list(filter_list_type_t list_type, char **pref_path_return, - int *errno_return); - -/* - * Clone the filter list so it can be edited. - */ -void copy_filter_list(filter_list_type_t dest_type, filter_list_type_t src_type); - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/g711.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/g711.h deleted file mode 100644 index b55bd13c..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/g711.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * g711.h - * - * Definitions for routines for u-law, A-law and linear PCM conversions - * - * $Id: g711.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -unsigned char linear2alaw( int ); -int alaw2linear( unsigned char ); -unsigned char linear2ulaw( int ); -int ulaw2linear( unsigned char ); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/getopt.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/getopt.h deleted file mode 100644 index 45541f5a..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/getopt.h +++ /dev/null @@ -1,129 +0,0 @@ -/* Declarations for getopt. - Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2, or (at your option) any - later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#ifndef _GETOPT_H -#define _GETOPT_H 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* For communication from `getopt' to the caller. - When `getopt' finds an option that takes an argument, - the argument value is returned here. - Also, when `ordering' is RETURN_IN_ORDER, - each non-option ARGV-element is returned here. */ - -extern char *optarg; - -/* Index in ARGV of the next element to be scanned. - This is used for communication to and from the caller - and for communication between successive calls to `getopt'. - - On entry to `getopt', zero means this is the first call; initialize. - - When `getopt' returns EOF, this is the index of the first of the - non-option elements that the caller should itself scan. - - Otherwise, `optind' communicates from one call to the next - how much of ARGV has been scanned so far. */ - -extern int optind; - -/* Callers store zero here to inhibit the error message `getopt' prints - for unrecognized options. */ - -extern int opterr; - -/* Set to an option character which was unrecognized. */ - -extern int optopt; - -/* Describe the long-named options requested by the application. - The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector - of `struct option' terminated by an element containing a name which is - zero. - - The field `has_arg' is: - no_argument (or 0) if the option does not take an argument, - required_argument (or 1) if the option requires an argument, - optional_argument (or 2) if the option takes an optional argument. - - If the field `flag' is not NULL, it points to a variable that is set - to the value given in the field `val' when the option is found, but - left unchanged if the option is not found. - - To have a long-named option do something other than set an `int' to - a compiled-in constant, such as set a value from `optarg', set the - option's `flag' field to zero and its `val' field to a nonzero - value (the equivalent single-letter option character, if there is - one). For long options that have a zero `flag' field, `getopt' - returns the contents of the `val' field. */ - -struct option -{ -#if __STDC__ - const char *name; -#else - char *name; -#endif - /* has_arg can't be an enum because some compilers complain about - type mismatches in all the code that assumes it is an int. */ - int has_arg; - int *flag; - int val; -}; - -/* Names for the values of the `has_arg' field of `struct option'. */ - -#define no_argument 0 -#define required_argument 1 -#define optional_argument 2 - -#if __STDC__ -#if defined(__GNU_LIBRARY__) -/* Many other libraries have conflicting prototypes for getopt, with - differences in the consts, in stdlib.h. To avoid compilation - errors, only prototype getopt for the GNU C library. */ -extern int getopt (int argc, char *const *argv, const char *shortopts); -#else /* not __GNU_LIBRARY__ */ -extern int getopt (); -#endif /* not __GNU_LIBRARY__ */ -extern int getopt_long (int argc, char *const *argv, const char *shortopts, - const struct option *longopts, int *longind); -extern int getopt_long_only (int argc, char *const *argv, - const char *shortopts, - const struct option *longopts, int *longind); - -/* Internal only. Users should not call this directly. */ -extern int _getopt_internal (int argc, char *const *argv, - const char *shortopts, - const struct option *longopts, int *longind, - int long_only); -#else /* not __STDC__ */ -extern int getopt (); -extern int getopt_long (); -extern int getopt_long_only (); - -extern int _getopt_internal (); -#endif /* not __STDC__ */ - -#ifdef __cplusplus -} -#endif - -#endif /* _GETOPT_H */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/globals.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/globals.h deleted file mode 100644 index ff6ac7f3..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/globals.h +++ /dev/null @@ -1,37 +0,0 @@ -/* globals.h - * Global defines, etc. - * - * $Id: globals.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __GLOBALS_H__ -#define __GLOBALS_H__ - -#include "file.h" -#include - -extern capture_file cfile; -#ifdef HAVE_LIBPCAP -/** @todo move this to the gtk dir */ -extern gboolean auto_scroll_live; -#endif - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/inet_v6defs.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/inet_v6defs.h deleted file mode 100644 index 22f82abc..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/inet_v6defs.h +++ /dev/null @@ -1,54 +0,0 @@ -/* inet_v6defs.h - * - * $Id: inet_v6defs.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __INET_V6DEFS_H__ -#define __INET_V6DEFS_H__ - -/* - * Versions of "inet_pton()" and "inet_ntop()", for the benefit of OSes that - * don't have it. - */ -extern int inet_pton(int af, const char *src, void *dst); -#ifndef HAVE_INET_NTOP_PROTO -extern const char *inet_ntop(int af, const void *src, char *dst, - size_t size); -#endif - -/* - * Those OSes may also not have AF_INET6, so declare it here if it's not - * already declared, so that we can pass it to "inet_ntop()" and "inet_pton()". - */ -#ifndef AF_INET6 -#define AF_INET6 127 /* pick a value unlikely to duplicate an existing AF_ value */ -#endif - -/* - * And if __P isn't defined, define it here, so we can use it in - * "inet_ntop.c" and "inet_pton.c" (rather than having to change them - * not to use it). - */ -#ifndef __P -#define __P(args) args -#endif - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/isprint.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/isprint.h deleted file mode 100644 index 8a2d0a25..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/isprint.h +++ /dev/null @@ -1,46 +0,0 @@ -/* isprint.h - * Temporary redefinition of "isprint()" to cope with GTK+ 1.3 and - * later using UTF-8 strings - * - * $Id: isprint.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __ISPRINT_H__ -#define __ISPRINT_H__ - -#if GLIB_MAJOR_VERSION >= 2 -/* - * XXX - "isprint()" can return "true" for non-ASCII characters, but - * those don't work with GTK+ 1.3 or later, as they take UTF-8 strings - * as input. Until we fix up Wireshark to properly handle non-ASCII - * characters in all output (both GUI displays and text printouts) - * in those versions of GTK+, we work around the problem by escaping - * all characters that aren't printable ASCII. - * - * We don't know what version of GTK+ we're using, as dissectors don't - * use any GTK+ stuff; we use GLib as a proxy for that, with GLib 2.x - * implying GTK+ 1.3 or later (we don't support GLib 1.3[.x]). - */ -#undef isprint -#define isprint(c) (c >= 0x20 && c < 0x7f) -#endif - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/log.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/log.h deleted file mode 100644 index 569c4c20..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/log.h +++ /dev/null @@ -1,42 +0,0 @@ -/* log.h - * log output definitions - * - * $Id: log.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __LOG_H__ -#define __LOG_H__ - -/* capture domain (except for capture child, see below) */ -#define LOG_DOMAIN_CAPTURE "Capture" - -/* capture child domain (the capture child might also contain file domain messages!) */ -#define LOG_DOMAIN_CAPTURE_CHILD "CaptureChild" - -/* main domain */ -#define LOG_DOMAIN_MAIN "Main" - -/* enable very verbose capture log debug output */ -/* (might slightly degrade performance) */ -/*#define LOG_CAPTURE_VERBOSE*/ - - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/main_window.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/main_window.h deleted file mode 100644 index eb196b10..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/main_window.h +++ /dev/null @@ -1,41 +0,0 @@ -/* main_window.h - * Definitions for main window routines with toolkit-independent APIs but - * toolkit-dependent implementations. - * - * $Id: main_window.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __MAIN_WINDOW_H__ -#define __MAIN_WINDOW_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/** Tell the main window that we have a capture file (or not) */ -extern void -main_set_for_capture_file(gboolean have_capture_file_in); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __MAIN_WINDOW_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/menu.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/menu.h deleted file mode 100644 index 99cf2a90..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/menu.h +++ /dev/null @@ -1,64 +0,0 @@ -/* menu.h - * Definitions for menu routines with toolkit-independent APIs but - * toolkit-dependent implementations. - * - * $Id: menu.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __MENU_H__ -#define __MENU_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - - -/* Add a new recent capture filename to the "Recent Files" submenu - (duplicates will be ignored) */ -void add_menu_recent_capture_file(gchar *file); - -/* Routines to enable or disable sets of menu items. */ - -/* Enable or disable menu items based on whether you have a capture file - you've finished reading and, if you have one, whether it's been saved - and whether it could be saved except by copying the raw packet data. */ -void set_menus_for_capture_file(capture_file *); - -/* Enable or disable menu items based on whether there's a capture in - progress. */ -void set_menus_for_capture_in_progress(gboolean); - -/* Enable or disable menu items based on whether you have some captured - packets. */ -void set_menus_for_captured_packets(gboolean); - -/* Enable or disable menu items based on whether a packet is selected. */ -void set_menus_for_selected_packet(capture_file *cf); - -/* Enable or disable menu items based on whether a tree row is selected - and and on whether a "Match Selected" can be done. */ -void set_menus_for_selected_tree_row(capture_file *cf); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __MENU_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/merge.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/merge.h deleted file mode 100644 index 22620aae..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/merge.h +++ /dev/null @@ -1,125 +0,0 @@ -/* merge.h - * Definitions for routines for merging files. - * - * $Id: merge.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __MERGE_H__ -#define __MERGE_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -typedef enum { - PACKET_PRESENT, - PACKET_NOT_PRESENT, - AT_EOF, - GOT_ERROR -} in_file_state_e; - -/** - * Structures to manage our input files. - */ -typedef struct merge_in_file_s { - const char *filename; - wtap *wth; - gint64 data_offset; - in_file_state_e state; - gint64 size; /* file size */ -} merge_in_file_t; - -/** Open a number of input files to merge. - * - * @param in_file_count number of entries in in_file_names and in_files - * @param in_file_names filenames of the input files - * @param in_files input file array to be filled (>= sizeof(merge_in_file_t) * in_file_count) - * @param err wiretap error, if failed - * @param err_info wiretap error string, if failed - * @param err_fileno file on which open failed, if failed - * @return TRUE if all files could be opened, FALSE otherwise - */ -extern gboolean -merge_open_in_files(int in_file_count, char *const *in_file_names, - merge_in_file_t **in_files, int *err, gchar **err_info, - int *err_fileno); - -/** Close the input files again. - * - * @param in_file_count number of entries in in_files - * @param in_files input file array to be closed - */ -extern void -merge_close_in_files(int in_file_count, merge_in_file_t in_files[]); - -/** Try to get the frame type from the input files. - * - * @param in_file_count number of entries in in_files - * @param in_files input file array - * @return the frame type - */ -extern int -merge_select_frame_type(int in_file_count, merge_in_file_t in_files[]); - -/** Try to get the snapshot length from the input files. - * - * @param in_file_count number of entries in in_files - * @param in_files input file array - * @return the snapshot length - */ -extern int -merge_max_snapshot_length(int in_file_count, merge_in_file_t in_files[]); - -/** Read the next packet, in chronological order, from the set of files to - * be merged. - * - * @param in_file_count number of entries in in_files - * @param in_files input file array - * @param err wiretap error, if failed - * @param err_info wiretap error string, if failed - * @return pointer to wtap for file from which that packet came, or NULL on - * error or EOF - */ -extern wtap * -merge_read_packet(int in_file_count, merge_in_file_t in_files[], int *err, - gchar **err_info); - - -/** Read the next packet, in file sequence order, from the set of files - * to be merged. - * - * @param in_file_count number of entries in in_files - * @param in_files input file array - * @param err wiretap error, if failed - * @param err_info wiretap error string, if failed - * @return pointer to wtap for file from which that packet came, or NULL on - * error or EOF - */ -extern wtap * -merge_append_read_packet(int in_file_count, merge_in_file_t in_files[], - int *err, gchar **err_info); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __MERGE_H__ */ - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/mkstemp.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/mkstemp.h deleted file mode 100644 index be2cae0f..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/mkstemp.h +++ /dev/null @@ -1,24 +0,0 @@ -/* Copyright (C) 1991, 1992, 1996, 1998 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - - -/* Generate a unique temporary file name from TEMPLATE. - The last six characters of TEMPLATE must be "XXXXXX"; - they are replaced with a string that makes the filename unique. - Returns a file descriptor open on the file for reading and writing. */ -int mkstemp (char *template); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/packet-range.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/packet-range.h deleted file mode 100644 index 64702d14..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/packet-range.h +++ /dev/null @@ -1,101 +0,0 @@ -/* packet-range.h - * Packet range routines (save, print, ...) - * - * $Id: packet-range.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Dick Gooris - * Ulf Lamping - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __PACKET_RANGE_H__ -#define __PACKET_RANGE_H__ - -#include - -#include - -#include - -extern guint32 curr_selected_frame; - -typedef enum { - range_process_all, - range_process_selected, - range_process_marked, - range_process_marked_range, - range_process_user_range -} packet_range_e; - -typedef struct packet_range_tag { - /* values coming from the UI */ - packet_range_e process; /* which range to process */ - gboolean process_filtered; /* captured or filtered packets */ - - /* user specified range(s) and, if null, error status */ - range_t *user_range; - convert_ret_t user_range_status; - - /* calculated values */ - guint32 selected_packet; /* the currently selected packet */ - - /* current packet counts (captured) */ - /* cfile.count */ /* packets in capture file */ - /* cfile.marked_count */ /* packets marked */ - guint32 mark_range_cnt; /* packets in marked range */ - guint32 user_range_cnt; /* packets in user specified range */ - - /* current packet counts (displayed) */ - guint32 displayed_cnt; - guint32 displayed_marked_cnt; - guint32 displayed_mark_range_cnt; - guint32 displayed_user_range_cnt; - - /* "enumeration" values */ - gboolean marked_range_active; /* marked range is currently processed */ - guint32 marked_range_left; /* marked range packets left to do */ - gboolean selected_done; /* selected packet already processed */ -} packet_range_t; - -typedef enum { - range_process_this, /* process this packet */ - range_process_next, /* skip this packet, process next */ - range_processing_finished /* stop processing, required packets done */ -} range_process_e; - -/* init the range structure */ -extern void packet_range_init(packet_range_t *range); - -/* check whether the packet range is OK */ -extern convert_ret_t packet_range_check(packet_range_t *range); - -/* init the processing run */ -extern void packet_range_process_init(packet_range_t *range); - -/* do we have to process all packets? */ -extern gboolean packet_range_process_all(packet_range_t *range); - -/* do we have to process this packet? */ -extern range_process_e packet_range_process_packet(packet_range_t *range, frame_data *fdata); - -/* convert user given string to the internal user specified range representation */ -extern void packet_range_convert_str(packet_range_t *range, const gchar *es); - -#endif /* __PACKET_RANGE_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/pcapio.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/pcapio.h deleted file mode 100644 index a675ce30..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/pcapio.h +++ /dev/null @@ -1,44 +0,0 @@ -/* pcapio.h - * Declarations of our own routins for writing libpcap files. - * - * $Id: pcapio.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * Derived from code in the Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* Returns a FILE * to write to on success, NULL on failure; sets "*err" to - an error code, or 0 for a short write, on failure */ -extern FILE * -libpcap_fdopen(int fd, int linktype, int snaplen, long *bytes_written, - int *err); - -/* Write a record for a packet to a dump file. - Returns TRUE on success, FALSE on failure. */ -extern gboolean -libpcap_write_packet(FILE *fp, const struct pcap_pkthdr *phdr, const u_char *pd, - long *bytes_written, int *err); - -extern gboolean -libpcap_dump_flush(FILE *pd, int *err); - -extern gboolean -libpcap_dump_close(FILE *pd, int *err); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/print.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/print.h deleted file mode 100644 index a337dffc..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/print.h +++ /dev/null @@ -1,148 +0,0 @@ -/* print.h - * Definitions for printing packet analysis trees. - * - * $Id: print.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Gilbert Ramirez - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __PRINT_H__ -#define __PRINT_H__ - -#include - -#include "packet-range.h" - -/* - * Print stream code; this provides a "print stream" class with subclasses - * of various sorts. Additional subclasses might be implemented elsewhere. - */ -struct print_stream; - -typedef struct print_stream_ops { - gboolean (*print_preamble)(struct print_stream *self, gchar *filename); - gboolean (*print_line)(struct print_stream *self, int indent, - const char *line); - gboolean (*print_bookmark)(struct print_stream *self, - const gchar *name, const gchar *title); - gboolean (*new_page)(struct print_stream *self); - gboolean (*print_finale)(struct print_stream *self); - gboolean (*destroy)(struct print_stream *self); -} print_stream_ops_t; - -typedef struct print_stream { - const print_stream_ops_t *ops; - void *data; -} print_stream_t; - -extern print_stream_t *print_stream_text_new(int to_file, const char *dest); -extern print_stream_t *print_stream_text_stdio_new(FILE *fh); -extern print_stream_t *print_stream_ps_new(int to_file, const char *dest); -extern print_stream_t *print_stream_ps_stdio_new(FILE *fh); - -extern gboolean print_preamble(print_stream_t *self, gchar *filename); -extern gboolean print_line(print_stream_t *self, int indent, const char *line); -extern gboolean print_bookmark(print_stream_t *self, const gchar *name, - const gchar *title); -extern gboolean new_page(print_stream_t *self); -extern gboolean print_finale(print_stream_t *self); -extern gboolean destroy_print_stream(print_stream_t *self); - -/* print output format */ -typedef enum { - PR_FMT_TEXT, /* plain text */ - PR_FMT_PS /* postscript */ -} print_format_e; - -/* print_range, enum which frames should be printed */ -typedef enum { - print_range_selected_only, /* selected frame(s) only (currently only one) */ - print_range_marked_only, /* marked frames only */ - print_range_all_displayed, /* all frames currently displayed */ - print_range_all_captured /* all frames in capture */ -} print_range_e; - -/* print_dissections, enum how the dissections should be printed */ -typedef enum { - print_dissections_none, /* no dissections at all */ - print_dissections_collapsed, /* no dissection details */ - print_dissections_as_displayed, /* details as displayed */ - print_dissections_expanded /* all dissection details */ -} print_dissections_e; - -typedef struct { - print_stream_t *stream; /* the stream to which we're printing */ - print_format_e format; /* plain text or PostScript */ - gboolean to_file; /* TRUE if we're printing to a file */ - char *file; /* file output pathname */ - char *cmd; /* print command string (not win32) */ - packet_range_t range; - - gboolean print_summary; /* TRUE if we should just print summary; - FALSE if we should print protocol tree. */ - print_dissections_e print_dissections; - gboolean print_hex; /* TRUE if we should also print hex data; - FALSE if we should print only if not dissected. */ - gboolean print_formfeed; /* TRUE if a formfeed should be printed - before each new packet */ -} print_args_t; - -/* - * Print user selected list of fields - */ -struct _output_fields; -typedef struct _output_fields output_fields_t; - -extern output_fields_t* output_fields_new(void); -extern void output_fields_free(output_fields_t* info); -extern void output_fields_add(output_fields_t* info, const gchar* field); -extern gsize output_fields_num_fields(output_fields_t* info); -extern gboolean output_fields_set_option(output_fields_t* info, gchar* option); -extern void output_fields_list_options(FILE *fh); -/* - * Higher-level packet-printing code. - */ - -extern gboolean proto_tree_print(print_args_t *print_args, epan_dissect_t *edt, - print_stream_t *stream); -extern gboolean print_hex_data(print_stream_t *stream, epan_dissect_t *edt); - -extern void write_pdml_preamble(FILE *fh); -extern void proto_tree_write_pdml(epan_dissect_t *edt, FILE *fh); -extern void write_pdml_finale(FILE *fh); - -extern void write_psml_preamble(FILE *fh); -extern void proto_tree_write_psml(epan_dissect_t *edt, FILE *fh); -extern void write_psml_finale(FILE *fh); - -extern void write_csv_preamble(FILE *fh); -extern void proto_tree_write_csv(epan_dissect_t *edt, FILE *fh); -extern void write_csv_finale(FILE *fh); - -extern void write_carrays_preamble(FILE *fh); -extern void proto_tree_write_carrays(const guint8 *pd, guint32 len, guint32 num, FILE *fh); -extern void write_carrays_finale(FILE *fh); - -extern void write_fields_preamble(output_fields_t* fields, FILE *fh); -extern void proto_tree_write_fields(output_fields_t* fields, epan_dissect_t *edt, FILE *fh); -extern void write_fields_finale(output_fields_t* fields, FILE *fh); - -#endif /* print.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/progress_dlg.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/progress_dlg.h deleted file mode 100644 index 0303230e..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/progress_dlg.h +++ /dev/null @@ -1,94 +0,0 @@ -/* progress_dlg.h - * Definitions for progress dialog box routines - * - * $Id: progress_dlg.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __PROGRESS_DLG_H__ -#define __PROGRESS_DLG_H__ - -/** @file - * Progress (modal) dialog box routines. - * @ingroup dialog_group - */ - -/** Progress dialog data. */ -struct progdlg; - -/** Progress dialog data. */ -typedef struct progdlg progdlg_t; - -/** - * Create and pop up the progress dialog. Allocates a "progdlg_t" - * and initialize it to contain all information the implementation - * needs in order to manipulate the dialog, and return a pointer to - * it. - * - * @param task_title the task to do, e.g. "Loading" - * @param item_title the item to do, e.g. "capture.cap" - * @param terminate_is_stop TRUE if the operation can't be cancelled, just - * stopped (i.e., it has a "Stop" button and clicking it doesn't undo - * anything already done), FALSE if it can - * @param stop_flag a pointer to a Boolean variable that will be - * set to TRUE if the user hits that button - * @return the newly created progress dialog - */ -progdlg_t *create_progress_dlg(const gchar *task_title, const gchar *item_title, - gboolean terminate_is_stop, gboolean *stop_flag); - -/** - * Create a progress dialog, but only if it's not likely to disappear - * immediately. This can be disconcerting for the user. - * - * @param task_title the task to do, e.g. "Loading" - * @param item_title the item to do, e.g. "capture.cap" - * @param terminate_is_stop TRUE if the operation can't be cancelled, just - * stopped (i.e., it has a "Stop" button and clicking it doesn't undo - * anything already done), FALSE if it can - * @param stop_flag a pointer to a Boolean variable that will be - * set to TRUE if the user hits that button - * @param start_time a pointer to a GTimeVal structure which holds - * the time at which the caller started to process the data - * @param progress the current progress (0..1) - * @return the newly created progress dialog - */ -progdlg_t * -delayed_create_progress_dlg(const gchar *task_title, const gchar *item_title, - gboolean terminate_is_stop, gboolean *stop_flag, - const GTimeVal *start_time, gfloat progress); - -/** - * Update the progress information of the progress dialog box. - * - * @param dlg the progress dialog from create_progress_dlg() - * @param percentage the current percentage value (0..1) - * @param status the new status string to show, e.g. "3000KB of 6000KB" - */ -void update_progress_dlg(progdlg_t *dlg, gfloat percentage, const gchar *status); - -/** - * Destroy the progress bar. - * - * @param dlg the progress dialog from create_progress_dlg() - */ -void destroy_progress_dlg(progdlg_t *dlg); - -#endif /* __PROGRESS_DLG_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/proto_hier_stats.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/proto_hier_stats.h deleted file mode 100644 index 10fb1e39..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/proto_hier_stats.h +++ /dev/null @@ -1,51 +0,0 @@ -/* proto_hier_stats.h - * - * $Id: proto_hier_stats.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef PROTO_HIER_STATS_H -#define PROTO_HIER_STATS_H - -#include - -typedef struct { - header_field_info *hfinfo; - guint num_pkts_total; - guint num_pkts_last; - guint num_bytes_total; - guint num_bytes_last; -} ph_stats_node_t; - - -typedef struct { - guint tot_packets; - guint tot_bytes; - GNode *stats_tree; - double first_time; /* seconds (msec resolution) of first packet */ - double last_time; /* seconds (msec resolution) of last packet */ -} ph_stats_t; - - -ph_stats_t* ph_stats_new(void); - -void ph_stats_free(ph_stats_t *ps); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ps.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ps.h deleted file mode 100644 index ceafdff6..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ps.h +++ /dev/null @@ -1,35 +0,0 @@ -/* ps.h - * Definitions for generating PostScript(R) packet output. - * - * $Id: ps.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Gilbert Ramirez - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __PS_H__ -#define __PS_H__ - -/* Functions in ps.c; automatically generated by rdps */ - -void print_ps_preamble(FILE *); -void print_ps_finale(FILE *); - -#endif /* ps.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/register.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/register.h deleted file mode 100644 index 2b8906ea..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/register.h +++ /dev/null @@ -1,48 +0,0 @@ -/* register.h - * Definitions for protocol registration - * - * $Id: register.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __REGISTER_H__ -#define __REGISTER_H__ - -#include - -typedef enum { - RA_NONE, /* for initialization */ - RA_DISSECTORS, /* Initializing dissectors */ - RA_LISTENERS, /* Tap listeners */ - RA_REGISTER, /* register */ - RA_PLUGIN_REGISTER, /* plugin register */ - RA_HANDOFF, /* handoff */ - RA_PLUGIN_HANDOFF, /* plugin handoff */ - RA_PREFERENCES, /* module preferences */ - RA_CONFIGURATION /* configuration files */ -} register_action_e; - -typedef void (*register_cb)(register_action_e action, const char *message, gpointer client_data); - -extern void register_all_protocols(register_cb cb, gpointer client_data); -extern void register_all_protocol_handoffs(register_cb cb, gpointer client_data); -extern void register_all_tap_listeners(void); -extern gulong register_count(void); -#endif /* __REGISTER_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ringbuffer.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ringbuffer.h deleted file mode 100644 index 85178edc..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ringbuffer.h +++ /dev/null @@ -1,53 +0,0 @@ -/* ringbuffer.h - * Definitions for capture ringbuffer files - * - * $Id: ringbuffer.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __RINGBUFFER_H__ -#define __RINGBUFFER_H__ - -#ifdef HAVE_LIBPCAP - -#include -#include "file.h" -#include "wiretap/wtap.h" - -#define RINGBUFFER_UNLIMITED_FILES 0 -/* minimum number of ringbuffer files */ -#define RINGBUFFER_MIN_NUM_FILES 0 -/* maximum number of ringbuffer files */ -/* (only to avoid crashes on very large numbers) */ -#define RINGBUFFER_MAX_NUM_FILES 10000 - -int ringbuf_init(const char *capture_name, guint num_files); -const gchar *ringbuf_current_filename(void); -FILE *ringbuf_init_libpcap_fdopen(int linktype, int snaplen, - long *bytes_written, int *err); -gboolean ringbuf_switch_file(FILE **pdh, gchar **save_file, int *save_file_fd, - long *bytes_written, int *err); -gboolean ringbuf_libpcap_dump_close(gchar **save_file, int *err); -void ringbuf_free(void); -void ringbuf_error_cleanup(void); - -#endif /* HAVE_LIBPCAP */ - -#endif /* ringbuffer.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/simple_dialog.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/simple_dialog.h deleted file mode 100644 index fcd35ece..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/simple_dialog.h +++ /dev/null @@ -1,184 +0,0 @@ -/* simple_dialog.h - * Definitions for alert box routines with toolkit-independent APIs but - * toolkit-dependent implementations. - * - * $Id: simple_dialog.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __DIALOG_H__ -#define __DIALOG_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/** @file - * Simple dialog box. - * @ingroup dialog_group - */ - - -/** Dialog types. */ -typedef enum { - ESD_TYPE_INFO, /**< tells the user something they should know, but not requiring - any action; the only button should be "OK" */ - ESD_TYPE_WARN, /**< tells the user about a problem; the only button should be "OK" */ - ESD_TYPE_CONFIRMATION, /**< asks the user for confirmation; there should be more than - one button */ - ESD_TYPE_ERROR, /**< tells the user about a serious problem; the only button should be "OK" */ - ESD_TYPE_STOP /**< tells the user a stop action is in progress, there should be no button */ -} ESD_TYPE_E; - -/** display no buttons at all */ -#define ESD_BTN_NONE 0x00 -/** display an "Ok" button */ -#define ESD_BTN_OK 0x01 -/** display a "Cancel" button */ -#define ESD_BTN_CANCEL 0x02 -/** display a "Yes" button */ -#define ESD_BTN_YES 0x04 -/** display a "No" button */ -#define ESD_BTN_NO 0x08 -/** display a "Clear" button */ -#define ESD_BTN_CLEAR 0x10 -/** display a "Save" button */ -#define ESD_BTN_SAVE 0x20 -/** display a "Continue without Saving" button */ -#define ESD_BTN_DONT_SAVE 0x40 - -/** Standard button combination "Ok" + "Cancel". */ -#define ESD_BTNS_OK_CANCEL (ESD_BTN_OK|ESD_BTN_CANCEL) -/** Standard button combination "Yes" + "No". */ -#define ESD_BTNS_YES_NO (ESD_BTN_YES|ESD_BTN_NO) -/** Standard button combination "Yes" + "No" + "Cancel". */ -#define ESD_BTNS_YES_NO_CANCEL (ESD_BTN_YES|ESD_BTN_NO|ESD_BTN_CANCEL) -/** Standard button combination "No" + "Cancel" + "Save". */ -#define ESD_BTNS_SAVE_DONTSAVE_CANCEL (ESD_BTN_DONT_SAVE|ESD_BTN_CANCEL|ESD_BTN_SAVE) - -#if __GNUC__ >= 2 -/** Create and show a simple dialog. - * - * @param type type of dialog - * @param btn_mask the buttons to display - * @param msg_format printf like message format - * @param ... printf like parameters - * @return the newly created dialog - */ -extern gpointer simple_dialog(ESD_TYPE_E type, gint btn_mask, - const gchar *msg_format, ...) - __attribute__((format (printf, 3, 4))); -/** Create and show a simple dialog using a va_list. - * - * @param type type of dialog - * @param btn_mask the buttons to display - * @param msg_format printf like message format - * @param ap parameters - * @return the newly created dialog - */ -extern gpointer vsimple_dialog(ESD_TYPE_E type, gint btn_mask, - const gchar *msg_format, va_list ap); -#else -/** Create and show a simple dialog. - * - * @param type type of dialog - * @param btn_mask the buttons to display - * @param msg_format printf like message format - * @param ... printf like parameters - * @return the newly created dialog - */ -extern gpointer simple_dialog(ESD_TYPE_E type, gint btn_mask, - const gchar *msg_format, ...); -/** Create and show a simple dialog using a va_list. - * - * @param type type of dialog - * @param btn_mask the buttons to display - * @param msg_format printf like message format - * @param ap parameters - * @return the newly created dialog - */ -extern gpointer vsimple_dialog(ESD_TYPE_E type, gint btn_mask, - const gchar *msg_format, va_list ap); -#endif - -/** Callback function type for simple_dialog_set_cb() */ -typedef void (* simple_dialog_cb_t) (gpointer dialog, gint btn, gpointer data); - -/** Set the callback function for the dialog, called when a button was pressed. - * - * @param dialog the dialog from simple_dialog() - * @param callback_fct the callback function to set - * @param data data to be passed to the callback function - */ -extern void simple_dialog_set_cb(gpointer dialog, simple_dialog_cb_t callback_fct, gpointer data); - -/** Close the dialog, useful for "no button" dialogs. - * - * @param dialog the dialog to close from simple_dialog() - */ -extern void simple_dialog_close(gpointer dialog); - -/** Add a check button to the dialog (e.g. "Don't show this message again") - * - * @param dialog the dialog from simple_dialog() - * @param text the text to display - */ -extern void simple_dialog_check_set(gpointer dialog, gchar *text); - -/** Get the check buttons state. - * - * @param dialog the dialog from simple_dialog() - * @return current button state (TRUE is checked) - */ -extern gboolean simple_dialog_check_get(gpointer dialog); - -/** Surround the primary dialog message text by - * simple_dialog_primary_start() and simple_dialog_primary_end(). - * To highlight the first sentence (will take effect on GTK2 only). - */ -extern char *simple_dialog_primary_start(void); -/** Surround the primary dialog message text by - * simple_dialog_primary_start() and simple_dialog_primary_end(). - * To highlight the first sentence (will take effect on GTK2 only). - */ -extern char *simple_dialog_primary_end(void); - -/** Escape the message text, if it probably contains Pango escape sequences. - * For example html like tags starting with a <. - * - * @param msg the string to escape - * @return the escaped message text, must be freed with g_free() later - */ -extern char *simple_dialog_format_message(const char *msg); - -/** - * Display all queued messages. - * If a routine is called to display a dialog before there are any windows - * open, information to use to display the dialog is queued up. This - * routine should be called once there are windows open, so that the queued - * up dialogs are displayed on top of those windows. - */ -extern void display_queued_messages(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __DIALOG_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/stat_menu.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/stat_menu.h deleted file mode 100644 index 1a7bd7f1..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/stat_menu.h +++ /dev/null @@ -1,64 +0,0 @@ -/* stat_menu.h - * Menu definitions for use by stats - * - * $Id: stat_menu.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef __STATMENU_H__ -#define __STATMENU_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/** @file - * Add a new menu item for a stat. - */ - -/* - * XXX - defines stuff usable regardless of the GUI toolkit. Right now, - * that's only the menu group, which is used by tap_dfilter_dlg.h. - * - * XXX - stats should be able to register additional menu groups, although - * the question then would be "in what order should they appear in the menu?" - */ - -/** The menu group this stat should be registered in. */ -typedef enum { - REGISTER_STAT_GROUP_NONE, - REGISTER_STAT_GROUP_GENERIC, - REGISTER_STAT_GROUP_CONVERSATION_LIST, - REGISTER_STAT_GROUP_ENDPOINT_LIST, - REGISTER_STAT_GROUP_RESPONSE_TIME, - REGISTER_STAT_GROUP_TELEPHONY, - /* XXX - split into telephony and VoIP? */ - REGISTER_ANALYZE_GROUP_NONE, - REGISTER_ANALYZE_GROUP_CONVERSATION_FILTER -#ifdef HAVE_LUA_5_1 - ,REGISTER_TOOLS_GROUP_NONE -#endif -} register_stat_group_t; - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __STATMENU_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/statusbar.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/statusbar.h deleted file mode 100644 index cde19b35..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/statusbar.h +++ /dev/null @@ -1,56 +0,0 @@ -/* statusbar.h - * Definitions for status bar UI routines - * - * $Id: statusbar.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __STATUSBAR_H__ -#define __STATUSBAR_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* - * Push a message referring to file access onto the statusbar. - */ -void statusbar_push_file_msg(const gchar *msg); - -/* - * Pop a message referring to file access off the statusbar. - */ -void statusbar_pop_file_msg(void); - -/* - * Push a message referring to the currently-selected field onto the statusbar. - */ -void statusbar_push_field_msg(const gchar *msg); - -/* - * Pop a message referring to the currently-selected field off the statusbar. - */ -void statusbar_pop_field_msg(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __STATUSBAR_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/strerror.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/strerror.h deleted file mode 100644 index 2f509795..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/strerror.h +++ /dev/null @@ -1,33 +0,0 @@ -/* strerror.h - * - * $Id: strerror.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __STRERROR_H__ -#define __STRERROR_H__ - -/* - * Version of "strerror()", for the benefit of OSes that don't have it - * (e.g., SunOS 4.x). - */ -extern char *strerror(int); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/strptime.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/strptime.h deleted file mode 100644 index 0bfc58b1..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/strptime.h +++ /dev/null @@ -1,32 +0,0 @@ -/* strptime.h - * - * $Id: strptime.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __STRPTIME_H__ -#define __STRPTIME_H__ - -/* - * Version of "strptime()", for the benefit of OSes that don't have it. - */ -extern char *strptime(const char *, const char *, struct tm *); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/summary.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/summary.h deleted file mode 100644 index 1cc43328..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/summary.h +++ /dev/null @@ -1,76 +0,0 @@ -/* summary.h - * Definitions for capture file summary data - * - * $Id: summary.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __SUMMARY_H__ -#define __SUMMARY_H__ - -#ifdef HAVE_LIBPCAP -#include "capture.h" -#endif - -typedef struct _summary_tally { - guint64 bytes; /* total bytes */ - double start_time; /* seconds, with msec resolution */ - double stop_time; /* seconds, with msec resolution */ - double elapsed_time; /* seconds, with msec resolution, - includes time before first packet - and after last packet */ - int marked_count; /* number of marked packets */ - guint64 marked_bytes; /* total bytes in the marked packets */ - double marked_start; /* time in seconds, with msec resolution */ - double marked_stop; /* time in seconds, with msec resolution */ - int packet_count; /* total number of packets in trace */ - int filtered_count; /* number of filtered packets */ - guint64 filtered_bytes; /* total bytes in the filtered packets */ - double filtered_start; /* time in seconds, with msec resolution */ - double filtered_stop; /* time in seconds, with msec resolution */ - const char *filename; - gint64 file_length; /* file length in bytes */ - int encap_type; /* wiretap encapsulation type */ - gboolean has_snap; /* TRUE if maximum capture packet length is known */ - int snap; /* Maximum captured packet length */ - gboolean drops_known; /* TRUE if number of packet drops is known */ - guint64 drops; /* number of packet drops */ - const char *dfilter; /* display filter */ - - /* capture related, use summary_fill_in_capture() to get values */ - const char *cfilter; /* capture filter */ - const char *iface; /* interface name */ - const char *iface_descr;/* descriptive interface name */ -} summary_tally; - -extern void -summary_fill_in(capture_file *cf, summary_tally *st); - -#ifdef HAVE_LIBPCAP -extern void -summary_fill_in_capture(capture_options *capture_opts, summary_tally *st); -#endif - -#endif /* summary.h */ - - - - - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/svnversion.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/svnversion.h deleted file mode 100644 index b3f53a6d..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/svnversion.h +++ /dev/null @@ -1 +0,0 @@ -/* #define SVNVERSION "" */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/sync_pipe.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/sync_pipe.h deleted file mode 100644 index 71d91ccd..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/sync_pipe.h +++ /dev/null @@ -1,80 +0,0 @@ -/* sync_pipe.h - * Low-level synchronization pipe routines for use by Wireshark/TShark - * and dumpcap - * - * $Id: sync_pipe.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - - -/** @file - * - * Low-level sync pipe interfaces. - */ - -#ifndef __SYNC_PIPE_H__ -#define __SYNC_PIPE_H__ - - -/* - * Maximum length of sync pipe message data. Must be < 2^24, as the - * message length is 3 bytes. - * XXX - this must be large enough to handle a Really Big Filter - * Expression, as the error message for an incorrect filter expression - * is a bit larger than the filter expression. - */ -#define SP_MAX_MSG_LEN 4096 - - -/* Size of buffer to hold decimal representation of - signed/unsigned 64-bit int */ -#define SP_DECISIZE 20 - -/* - * Indications sent out on the sync pipe (from child to parent). - */ -#define SP_FILE 'F' /* the name of the recently opened file */ -#define SP_ERROR_MSG 'E' /* error message */ -#define SP_BAD_FILTER 'B' /* error message for bad capture filter */ -#define SP_PACKET_COUNT 'P' /* count of packets captured since last message */ -#define SP_DROPS 'D' /* count of packets dropped in capture */ -/* - * Win32 only: Indications sent out on the signal pipe (from parent to child) - * (UNIX-like sends signals for this) - */ -#define SP_QUIT 'Q' /* "gracefully" capture quit message (SIGUSR1) */ - -/* write a single message header to the recipient pipe */ -extern int -pipe_write_header(int pipe, char indicator, int length); - -/* write a message to the recipient pipe in the standard format - (3 digit message length (excluding length and indicator field), - 1 byte message indicator and the rest is the message). - If msg is NULL, the message has only a length and indicator. */ -extern void -pipe_write_block(int pipe, char indicator, const char *msg); - -/** the child encountered an error, notify the parent */ -extern void -sync_pipe_errmsg_to_parent(int pipe, const char *error_msg, - const char *secondary_error_msg); - -#endif /* sync_pipe.h */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tap-rtp-common.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tap-rtp-common.h deleted file mode 100644 index b20db362..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tap-rtp-common.h +++ /dev/null @@ -1,49 +0,0 @@ -/* tap-rtp-common.h - * RTP streams handler functions used by tshark and wireshark - * - * $Id: tap-rtp-common.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Copyright 2008, Ericsson AB - * By Balint Reczey - * - * most functions are copied from gtk/rtp_stream.c and gtk/rtp_analisys.c - * Copyright 2003, Alcatel Business Systems - * By Lars Ruoff - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef TAP_RTP_COMMON_H_INCLUDED -#define TAP_RTP_COMMON_H_INCLUDED - -#include "gtk/rtp_stream.h" - -gint rtp_stream_info_cmp(gconstpointer, gconstpointer); -void rtpstream_reset_cb(void*); -void rtp_write_header(rtp_stream_info_t*, FILE*); -void rtp_write_sample(rtp_sample_t*, FILE*); -int rtpstream_packet(void*, packet_info*, epan_dissect_t *, const void *); - -/* The one and only global rtpstream_tapinfo_t structure for tshark and wireshark. - */ -static rtpstream_tapinfo_t the_tapinfo_struct = - {0, NULL, 0, TAP_ANALYSE, NULL, NULL, NULL, 0, FALSE}; - - -#endif /*TAP_RTP_COMMON_H_INCLUDED*/ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tap_dfilter_dlg.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tap_dfilter_dlg.h deleted file mode 100644 index ae39ce3d..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tap_dfilter_dlg.h +++ /dev/null @@ -1,73 +0,0 @@ -/* tap_dfilter_dlg.h - * Header file for display filter dialog used by gui taps - * Copyright 2003 Lars Roland - * - * $Id: tap_dfilter_dlg.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* - * You can easily add a display filter dialog for your gui tap by using - * the following infrastructure: - * - * Define a global structure of tap_dfilter_dlg within your tap source file. - * Initiate it with: - * 1) a title string for the Dialog Window - * 2) the init string, which is the same as the string after "-z" option without - * the filter string and without the separating comma. - * 3) a pointer to the init function of the tap, which will be called when you click - * on the start button in the display filter dialog. - * 4) the index with "-1" - * - * Within register_tap_menu_yourtap(void), call register_dfilter_stat() - * with a pointer to the tap_dfilter_dlg structure, a string for the - * menu item (don't put "..." at the end, register_dfilter_stat() will - * add it for you), and the REGISTER_STAT_GROUP_ value for the stat - * group to which your stat should belong. - * - * Usage: - * - * tap_dfilter_dlg my_tap_dfilter_dlg = {"My Title", "myproto,mytap", gtk_mytap_init, -1}; - * - * register_tap_menu_mytap(void) { - * register_dfilter_stat(&my_tap_dfilter_dlg, "My Menu Item", - * REGISTER_STAT_GROUP_my_group); - * } - * - * See also: h225_ras_srt.c or h225_counter.c - * - */ - -typedef struct _tap_dfilter_dlg { - const char *win_title; /* title */ - const char *init_string; /* the string to call the tap without a filter via "-z" option */ - void (* tap_init_cb)(const char *,void*); /* callback to init function of the tap */ - gint index; /* initiate this value always with "-1" */ -} tap_dfilter_dlg; - -/* - * Register a stat that has a display filter dialog. - * We register it both as a command-line stat and a menu item stat. - */ -void register_dfilter_stat(tap_dfilter_dlg *info, const char *name, - register_stat_group_t group); - -/* This will update the titles of the dialog windows when we load a new capture file. */ -void tap_dfilter_dlg_update (void); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tempfile.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tempfile.h deleted file mode 100644 index ce13a49d..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tempfile.h +++ /dev/null @@ -1,43 +0,0 @@ -/* tempfile.h - * Declarations of routines to create temporary files - * - * $Id: tempfile.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __TEMPFILE_H__ -#define __TEMPFILE_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* create a tempfile with the given prefix (e.g. "ether") - * namebuf (and namebuflen) should be 128+1 bytes long (BTW: why?) - * returns the file descriptor of the new tempfile and - * the name of the new file in namebuf - */ -int create_tempfile(char *namebuf, int namebuflen, const char *pfx); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __TEMPFILE_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/text2pcap.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/text2pcap.h deleted file mode 100644 index 4ca4f1fa..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/text2pcap.h +++ /dev/null @@ -1,49 +0,0 @@ -/**-*-C-*-********************************************************************** - * - * text2pcap.h - * - * Utility to convert an ASCII hexdump into a libpcap-format capture file - * - * (c) Copyright 2001 Ashok Narayanan - * - * $Id: text2pcap.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - *******************************************************************************/ - - -#ifndef TEXT2PCAP_H -#define TEXT2PCAP_H - -typedef enum { - T_BYTE = 1, - T_OFFSET, - T_DIRECTIVE, - T_TEXT, - T_EOL -} token_t; - -void parse_token(token_t token, char *str); - -int yylex(void); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/timestats.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/timestats.h deleted file mode 100644 index 7c418f09..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/timestats.h +++ /dev/null @@ -1,54 +0,0 @@ -/* timestats.h - * Routines and definitions for time statistics - * Copyrigth 2003 Lars Roland - * - * $Id: timestats.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef _time_stat -#define _time_stat - -#include -#include "epan/packet_info.h" -#include "epan/nstime.h" - - /* Summary of time statistics*/ -typedef struct _timestat_t { - guint32 num; /* number of samples */ - guint32 min_num; /* frame number of minimum */ - guint32 max_num; /* frame number of maximum */ - nstime_t min; - nstime_t max; - nstime_t tot; - gdouble variance; -} timestat_t; - -/* functions */ - -/* Initialize a timestat_t struct */ -extern void time_stat_init(timestat_t *stats); - -/* Update a timestat_t struct with a new sample */ -extern void time_stat_update(timestat_t *stats, const nstime_t *delta, packet_info *pinfo); - -extern gdouble get_average(const nstime_t *sum, guint32 num); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tools/make-dissector-reg b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tools/make-dissector-reg deleted file mode 100755 index d2efa7c6..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tools/make-dissector-reg +++ /dev/null @@ -1,186 +0,0 @@ -#! /bin/sh - -# -# $Id: make-dissector-reg 21716 2007-05-07 17:55:42Z gal $ -# - -# -# The first argument is the directory in which the source files live. -# -srcdir="$1" -shift - -# -# The second argument is either "plugin" or "dissectors"; if it's -# "plugin", we build a plugin.c for a plugin, and if it's -# "dissectors", we build a register.c for libwireshark. -# -registertype="$1" -shift -if [ "$registertype" = plugin ] -then - outfile="plugin.c" -elif [ "$registertype" = dissectors ] -then - outfile="register.c" -else - echo "Unknown output type '$registertype'" 1>&2 - exit 1 -fi - -# -# All subsequent arguments are the files to scan. -# -rm -f ${outfile}-tmp -echo '/* Do not modify this file. */' >${outfile}-tmp -echo '/* It is created automatically by the Makefile. */'>>${outfile}-tmp -if [ "$registertype" = plugin ] -then - cat <<"EOF" >>${outfile}-tmp -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include - -#include "moduleinfo.h" - -#ifndef ENABLE_STATIC -G_MODULE_EXPORT const gchar version[] = VERSION; - -/* Start the functions we need for the plugin stuff */ - -G_MODULE_EXPORT void -plugin_register (void) -{ -EOF -# -# Build code to call all the protocol registration routines. -# -for f in "$@" -do - if [ -f $f ] - then - srcfile=$f - else - srcfile=$srcdir/$f - fi - grep '^proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' -done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp -for f in "$@" -do - if [ -f $f ] - then - srcfile=$f - else - srcfile=$srcdir/$f - fi - grep '^void proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' -done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp -else - cat <<"EOF" >>${outfile}-tmp -#include "register.h" -void -register_all_protocols(register_cb cb, gpointer client_data) -{ -EOF -# -# Build code to call all the protocol registration routines. -# -for f in "$@" -do - if [ -f $f ] - then - srcfile=$f - else - srcfile=$srcdir/$f - fi - grep '^proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' -done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_REGISTER, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp -for f in "$@" -do - if [ -f $f ] - then - srcfile=$f - else - srcfile=$srcdir/$f - fi - grep '^void proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' -done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_REGISTER, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp - -fi -echo '}' >>${outfile}-tmp - - -# -# Build code to call all the protocol handoff registration routines. -# -if [ "$registertype" = plugin ] -then - cat <<"EOF" >>${outfile}-tmp -G_MODULE_EXPORT void -plugin_reg_handoff(void) -{ -EOF -for f in "$@" -do - if [ -f $f ] - then - srcfile=$f - else - srcfile=$srcdir/$f - fi - grep '^proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' -done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp -for f in "$@" -do - if [ -f $f ] - then - srcfile=$f - else - srcfile=$srcdir/$f - fi - grep '^void proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' -done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp -else - cat <<"EOF" >>${outfile}-tmp -void -register_all_protocol_handoffs(register_cb cb, gpointer client_data) -{ -EOF -for f in "$@" -do - if [ -f $f ] - then - srcfile=$f - else - srcfile=$srcdir/$f - fi - grep '^proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' -done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_HANDOFF, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp -for f in "$@" -do - if [ -f $f ] - then - srcfile=$f - else - srcfile=$srcdir/$f - fi - grep '^void proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';' -done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_HANDOFF, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp -fi -echo '}' >>${outfile}-tmp -if [ "$registertype" = plugin ] -then - echo '#endif' >>${outfile}-tmp -else - cat <<"EOF" >>${outfile}-tmp -gulong register_count(void) -{ -EOF - proto_regs=`grep RA_REGISTER ${outfile}-tmp | wc -l` - handoff_regs=`grep RA_HANDOFF ${outfile}-tmp | wc -l` - echo " return $proto_regs + $handoff_regs;" >>${outfile}-tmp - echo '}' >>${outfile}-tmp -fi -mv ${outfile}-tmp ${outfile} diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tools/make-dissector-reg.py b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tools/make-dissector-reg.py deleted file mode 100755 index c3354279..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tools/make-dissector-reg.py +++ /dev/null @@ -1,238 +0,0 @@ -#!/usr/bin/env python -# -# Looks for registration routines in the protocol dissectors, -# and assembles C code to call all the routines. -# -# This is a Python version of the make-reg-dotc shell script. -# Running the shell script on Win32 is very very slow because of -# all the process-launching that goes on --- multiple greps and -# seds for each input file. I wrote this python version so that -# less processes would have to be started. -# -# $Id: make-dissector-reg.py 24390 2008-02-19 13:44:02Z wmeier $ - -import os -import sys -import re -import pickle -from stat import * - -# -# The first argument is the directory in which the source files live. -# -srcdir = sys.argv[1] - -# -# The second argument is either "plugin" or "dissectors"; if it's -# "plugin", we build a plugin.c for a plugin, and if it's -# "dissectors", we build a register.c for libwireshark. -# -registertype = sys.argv[2] -if registertype == "plugin": - tmp_filename = "plugin.c-tmp" - final_filename = "plugin.c" - cache_filename = None -elif registertype == "dissectors": - tmp_filename = "register.c-tmp" - final_filename = "register.c" - cache_filename = "register-cache.pkl" -else: - print "Unknown output type '%s'" % registertype - sys.exit(1) - - -# -# All subsequent arguments are the files to scan. -# -files = sys.argv[3:] - -# Create the proper list of filenames -filenames = [] -for file in files: - if os.path.isfile(file): - filenames.append(file) - else: - filenames.append("%s/%s" % (srcdir, file)) - -if len(filenames) < 1: - print "No files found" - sys.exit(1) - - -# Look through all files, applying the regex to each line. -# If the pattern matches, save the "symbol" section to the -# appropriate array. -regs = { - 'proto_reg': [], - 'handoff_reg': [], - } - -# For those that don't know Python, r"" indicates a raw string, -# devoid of Python escapes. -proto_regex0 = r"^(?Pproto_register_[_A-Za-z0-9]+)\s*\([^;]+$" -proto_regex1 = r"void\s+(?Pproto_register_[_A-Za-z0-9]+)\s*\([^;]+$" - -handoff_regex0 = r"^(?Pproto_reg_handoff_[_A-Za-z0-9]+)\s*\([^;]+$" -handoff_regex1 = r"void\s+(?Pproto_reg_handoff_[_A-Za-z0-9]+)\s*\([^;]+$" - -# This table drives the pattern-matching and symbol-harvesting -patterns = [ - ( 'proto_reg', re.compile(proto_regex0) ), - ( 'proto_reg', re.compile(proto_regex1) ), - ( 'handoff_reg', re.compile(handoff_regex0) ), - ( 'handoff_reg', re.compile(handoff_regex1) ), - ] - -# Open our registration symbol cache -cache = None -if cache_filename: - try: - cache_file = open(cache_filename, 'rb') - cache = pickle.load(cache_file) - cache_file.close() - except: - cache = {} - -# Grep -for filename in filenames: - file = open(filename) - cur_mtime = os.fstat(file.fileno())[ST_MTIME] - if cache and cache.has_key(filename): - cdict = cache[filename] - if cur_mtime == cdict['mtime']: -# print "Pulling %s from cache" % (filename) - regs['proto_reg'].extend(cdict['proto_reg']) - regs['handoff_reg'].extend(cdict['handoff_reg']) - file.close() - continue - # We don't have a cache entry - if cache is not None: - cache[filename] = { - 'mtime': cur_mtime, - 'proto_reg': [], - 'handoff_reg': [], - } -# print "Searching %s" % (filename) - for line in file.readlines(): - for action in patterns: - regex = action[1] - match = regex.search(line) - if match: - symbol = match.group("symbol") - sym_type = action[0] - regs[sym_type].append(symbol) - if cache is not None: -# print "Caching %s for %s: %s" % (sym_type, filename, symbol) - cache[filename][sym_type].append(symbol) - file.close() - -if cache is not None and cache_filename is not None: - cache_file = open(cache_filename, 'wb') - pickle.dump(cache, cache_file) - cache_file.close() - -# Make sure we actually processed something -if len(regs['proto_reg']) < 1: - print "No protocol registrations found" - sys.exit(1) - -# Sort the lists to make them pretty -regs['proto_reg'].sort() -regs['handoff_reg'].sort() - -reg_code = open(tmp_filename, "w") - -reg_code.write("/* Do not modify this file. */\n") -reg_code.write("/* It is created automatically by the Makefile. */\n") - -# Make the routine to register all protocols -if registertype == "plugin": - reg_code.write(""" -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include - -#include "moduleinfo.h" - -#ifndef ENABLE_STATIC -G_MODULE_EXPORT const gchar version[] = VERSION; - -/* Start the functions we need for the plugin stuff */ - -G_MODULE_EXPORT void -plugin_register (void) -{ -"""); -else: - reg_code.write(""" -#include "register.h" -void -register_all_protocols(register_cb cb, gpointer client_data) -{ -"""); - -for symbol in regs['proto_reg']: - if registertype == "plugin": - line = " {extern void %s (void); %s ();}\n" % (symbol, symbol) - else: - line = " {extern void %s (void); if(cb) (*cb)(RA_REGISTER, \"%s\", client_data); %s ();}\n" % (symbol, symbol, symbol) - reg_code.write(line) - -reg_code.write("}\n") - - -# Make the routine to register all protocol handoffs -if registertype == "plugin": - reg_code.write(""" -G_MODULE_EXPORT void -plugin_reg_handoff(void) -{ -"""); -else: - reg_code.write(""" -void -register_all_protocol_handoffs(register_cb cb, gpointer client_data) -{ -"""); - -for symbol in regs['handoff_reg']: - if registertype == "plugin": - line = " {extern void %s (void); %s ();}\n" % (symbol, symbol) - else: - line = " {extern void %s (void); if(cb) (*cb)(RA_HANDOFF, \"%s\", client_data); %s ();}\n" % (symbol, symbol, symbol) - reg_code.write(line) - -reg_code.write("}\n") - -if registertype == "plugin": - reg_code.write("#endif\n"); -else: - reg_code.write(""" -gulong register_count(void) -{ -"""); - - line = " return %d + %d;\n" % (len(regs['proto_reg']), len(regs['handoff_reg'])) - reg_code.write(line) - - reg_code.write(""" -} -"""); - - -# Close the file -reg_code.close() - -# Remove the old final_file if it exists. -try: - os.stat(final_filename) - os.remove(final_filename) -except OSError: - pass - -# Move from tmp file to final file -os.rename(tmp_filename, final_filename) - - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ui_util.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ui_util.h deleted file mode 100644 index fa591a51..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ui_util.h +++ /dev/null @@ -1,79 +0,0 @@ -/* ui_util.h - * Declarations of UI utility routines; these routines have GUI-independent - * APIs, but GUI-dependent implementations, so that they can be called by - * GUI-independent code to affect the GUI. - * - * $Id: ui_util.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __UI_UTIL_H__ -#define __UI_UTIL_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* gui_utils.c */ - -/* Set the name of the top-level window and its icon. */ -void set_main_window_name(const gchar *); -/* Update the name of the main window if the user-specified decoration - changed. */ -void update_main_window_name(void); -/* update the main window */ -extern void main_window_update(void); -/* exit the main window */ -extern void main_window_exit(void); -/* quit a nested main window */ -extern void main_window_nested_quit(void); -/* quit the main window */ -extern void main_window_quit(void); - -/* read from a pipe (callback) */ -typedef gboolean (*pipe_input_cb_t) (gint source, gpointer user_data); -/* install callback function, called if pipe input is available */ -extern void pipe_input_set_handler(gint source, gpointer user_data, int *child_process, pipe_input_cb_t input_cb); - -/* packet_list.c */ - -/* packet list related functions */ -void packet_list_clear(void); -void packet_list_freeze(void); -void packet_list_thaw(void); -void packet_list_select_row(gint); -void packet_list_moveto_end(void); -gint packet_list_append(const gchar *text[], gpointer data); -void packet_list_set_colors(gint, color_t *, color_t *); -gint packet_list_find_row_from_data(gpointer); -void packet_list_set_text(gint, gint, const gchar *); -void packet_list_set_cls_time_width(gint); -gpointer packet_list_get_row_data(gint); -void packet_list_set_selected_row(gint); -gint packet_list_get_sort_column(void); -void packet_list_set_sort_column(void); -gboolean packet_list_check_end(void); - - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __UI_UTIL_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/util.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/util.h deleted file mode 100644 index 2a4198f0..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/util.h +++ /dev/null @@ -1,60 +0,0 @@ -/* util.h - * Utility definitions - * - * $Id: util.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __UTIL_H__ -#define __UTIL_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* Collect command-line arguments as a string consisting of the arguments, - * separated by spaces. - */ -char *get_args_as_string(int argc, char **argv, int optind); - -/* Compute the difference between two seconds/microseconds time stamps. - * Beware: we're using nanosecond resolution now and function is currently unused - */ -void compute_timestamp_diff(gint *diffsec, gint *diffusec, - guint32 sec1, guint32 usec1, guint32 sec2, guint32 usec2); - -/* Try to figure out if we're remotely connected, e.g. via ssh or - Terminal Server, and create a capture filter that matches aspects of the - connection. We match the following environment variables: - - SSH_CONNECTION (ssh): - SSH_CLIENT (ssh): - REMOTEHOST (tcsh, others?): - DISPLAY (x11): [remote name]: - CLIENTNAME (terminal server): - */ -const char *get_conn_cfilter(void); - - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __UTIL_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/version_info.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/version_info.h deleted file mode 100644 index b036fbd2..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/version_info.h +++ /dev/null @@ -1,79 +0,0 @@ -/* version_info.h - * Declarations of outines to report version information for stuff used - * by Wireshark - * - * $Id: version_info.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __VERSION_INFO_H__ -#define __VERSION_INFO_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* - * The svn version string or "" - */ -extern const gchar *wireshark_svnversion; - -/* - * Get various library compile-time versions and append them to - * the specified GString. - * - * "additional_info" is called at the end to append any additional - * information; this is required in order to, for example, put the - * Portaudio information at the end of the string, as we currently - * don't use Portaudio in TShark. - */ -void get_compiled_version_info(GString *str, - void (*additional_info)(GString *)); - -/* - * Get compile-time information used only by applications that use - * libwireshark. - */ -void get_epan_compiled_version_info(GString *str); - -/* - * Get various library run-time versions, and the OS version, and append - * them to the specified GString. - */ -void get_runtime_version_info(GString *str, - void (*additional_info)(GString *)); - -/* - * Get copyright information. - */ -const char *get_copyright_info(void); - -#if defined(_WIN32) -/* - * Get the major OS version. - */ -guint32 get_os_major_version(); -#endif - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __VERSION_INFO_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/5views.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/5views.h deleted file mode 100644 index 2ae18a3a..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/5views.h +++ /dev/null @@ -1,30 +0,0 @@ -/* 5views.h - * - * $Id: 5views.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __5VIEWS_H__ -#define __5VIEWS_H__ - -int _5views_open(wtap *wth, int *err, gchar **err_info); -gboolean _5views_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); -int _5views_dump_can_write_encap(int encap); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/airopeek9.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/airopeek9.h deleted file mode 100644 index df7a946b..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/airopeek9.h +++ /dev/null @@ -1,29 +0,0 @@ -/* airopeek9.h - * - * $Id: airopeek9.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __W_AIROPEEK9_H__ -#define __W_AIROPEEK9_H__ - -int airopeek9_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-grammar.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-grammar.h deleted file mode 100644 index c705d457..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-grammar.h +++ /dev/null @@ -1,90 +0,0 @@ -/* A Bison parser, made by GNU Bison 2.3. */ - -/* Skeleton interface for Bison's Yacc-like parsers in C - - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 - Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. */ - -/* As a special exception, you may create a larger work that contains - part or all of the Bison parser skeleton and distribute that work - under terms of your choice, so long as that work isn't itself a - parser generator using the skeleton or a modified version thereof - as a parser skeleton. Alternatively, if you modify or redistribute - the parser skeleton itself, you may (at your option) remove this - special exception, which will cause the skeleton and the resulting - Bison output files to be licensed under the GNU General Public - License without this special exception. - - This special exception was added by the Free Software Foundation in - version 2.2 of Bison. */ - -/* Tokens. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - STRING = 258, - KEYWORD = 259, - WDD_DATE = 260, - WDD_CHUNK = 261, - COUNTER = 262, - SLASH_SUFFIX = 263, - WDS_PREFIX = 264, - ISDN_PREFIX = 265, - ETHER_PREFIX = 266, - DECNUM = 267, - HEXNUM = 268, - HEXBYTE = 269 - }; -#endif -/* Tokens. */ -#define STRING 258 -#define KEYWORD 259 -#define WDD_DATE 260 -#define WDD_CHUNK 261 -#define COUNTER 262 -#define SLASH_SUFFIX 263 -#define WDS_PREFIX 264 -#define ISDN_PREFIX 265 -#define ETHER_PREFIX 266 -#define DECNUM 267 -#define HEXNUM 268 -#define HEXBYTE 269 - - - - -#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef union YYSTYPE -#line 162 "./ascend-grammar.y" -{ -gchar *s; -guint32 d; -guint8 b; -} -/* Line 1489 of yacc.c. */ -#line 83 "ascend-grammar.h" - YYSTYPE; -# define yystype YYSTYPE /* obsolescent; will be withdrawn */ -# define YYSTYPE_IS_DECLARED 1 -# define YYSTYPE_IS_TRIVIAL 1 -#endif - -extern YYSTYPE ascendlval; - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-int.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-int.h deleted file mode 100644 index 6210d8dd..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-int.h +++ /dev/null @@ -1,54 +0,0 @@ -/* ascend-int.h - * Definitions for routines common to multiple modules in the Lucent/Ascend - * capture file reading code code, but not used outside that code. - * - * $Id: ascend-int.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __ASCEND_INT_H__ -#define __ASCEND_INT_H__ - -typedef struct { - time_t start_time; - time_t secs; - int usecs; - guint32 caplen; - guint32 len; -} ascend_pkthdr; - -extern int at_eof; - -extern const gchar *ascend_parse_error; - -/* - * Pointer to the pseudo-header for the current packet. - */ -extern struct ascend_phdr *pseudo_header; - -/* Here we provide interfaces to make our scanner act and look like lex */ -int ascendlex(void); - -void init_parse_ascend(void); -void ascend_init_lexer(FILE_T fh); -int parse_ascend(FILE_T fh, guint8 *pd, struct ascend_phdr *phdr, - ascend_pkthdr *hdr, gint64 *start_of_data); - -#endif /* ! __ASCEND_INT_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-scanner_lex.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-scanner_lex.h deleted file mode 100644 index 68794f14..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-scanner_lex.h +++ /dev/null @@ -1,6 +0,0 @@ -/* This is generated by runlex.sh. Do not edit it. */ -#define yylex ascendlex -#ifndef YY_DECL -#define YY_DECL int yylex(void) -#endif -YY_DECL; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend.h deleted file mode 100644 index 1c749aac..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend.h +++ /dev/null @@ -1,33 +0,0 @@ -/* ascend.h - * - * $Id: ascend.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __ASCEND_H__ -#define __ASCEND_H__ - -#define ASCEND_MAX_DATA_ROWS 8 -#define ASCEND_MAX_DATA_COLS 16 -#define ASCEND_MAX_PKT_LEN (ASCEND_MAX_DATA_ROWS * ASCEND_MAX_DATA_COLS) - -int ascend_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/atm.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/atm.h deleted file mode 100644 index f6aa08c8..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/atm.h +++ /dev/null @@ -1,40 +0,0 @@ -/* atm.h - * - * $Id: atm.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __ATM_H__ -#define __ATM_H__ - -/* - * Routines to use with ATM capture file types that don't include information - * about the *type* of ATM traffic (or, at least, where we haven't found - * that information). - */ - -extern void -atm_guess_traffic_type(const guint8 *pd, guint32 len, - union wtap_pseudo_header *pseudo_header); - -extern void -atm_guess_lane_type(const guint8 *pd, guint32 len, - union wtap_pseudo_header *pseudo_header); - -#endif /* __ATM_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ber.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ber.h deleted file mode 100644 index b3e139de..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ber.h +++ /dev/null @@ -1,28 +0,0 @@ -/* ber.h - * - * Basic Encoding Rules (BER) file reading - * - * $Id: ber.h 3992 2008-06-10 03:13:11Z dgu $ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __BER_H__ -#define __BER_H__ - -int ber_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/btsnoop.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/btsnoop.h deleted file mode 100644 index d213206e..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/btsnoop.h +++ /dev/null @@ -1,30 +0,0 @@ -/* btsnoop.h - * - * $Id: btsnoop.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __W_BTSNOOP_H__ -#define __W_BTSNOOP_H__ - -int btsnoop_open(wtap *wth, int *err, gchar **err_info); -gboolean btsnoop_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); -int btsnoop_dump_can_write_encap(int encap); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/buffer.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/buffer.h deleted file mode 100644 index 55fb523c..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/buffer.h +++ /dev/null @@ -1,58 +0,0 @@ -/* buffer.h - * - * $Id: buffer.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __W_BUFFER_H__ -#define __W_BUFFER_H__ - -#define SOME_FUNCTIONS_ARE_DEFINES - -typedef struct Buffer { - guchar *data; - unsigned int allocated; - unsigned int start; - unsigned int first_free; -} Buffer; - -void buffer_init(Buffer* buffer, unsigned int space); -void buffer_free(Buffer* buffer); -void buffer_assure_space(Buffer* buffer, unsigned int space); -void buffer_append(Buffer* buffer, guchar *from, unsigned int bytes); -void buffer_remove_start(Buffer* buffer, unsigned int bytes); - -#ifdef SOME_FUNCTIONS_ARE_DEFINES -# define buffer_clean(buffer) buffer_remove_start((buffer), buffer_length(buffer)) -# define buffer_increase_length(buffer,bytes) (buffer)->first_free += (bytes) -# define buffer_length(buffer) ((buffer)->first_free - (buffer)->start) -# define buffer_start_ptr(buffer) ((buffer)->data + (buffer)->start) -# define buffer_end_ptr(buffer) ((buffer)->data + (buffer)->first_free) -# define buffer_append_buffer(buffer,src_buffer) buffer_append((buffer), buffer_start_ptr(src_buffer), buffer_length(src_buffer)) -#else - void buffer_clean(Buffer* buffer); - void buffer_increase_length(Buffer* buffer, unsigned int bytes); - unsigned int buffer_length(Buffer* buffer); - guchar* buffer_start_ptr(Buffer* buffer); - guchar* buffer_end_ptr(Buffer* buffer); - void buffer_append_buffer(Buffer* buffer, Buffer* src_buffer); -#endif - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/catapult_dct2000.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/catapult_dct2000.h deleted file mode 100644 index 89223f5f..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/catapult_dct2000.h +++ /dev/null @@ -1,30 +0,0 @@ -/* catapult_dct2000.h -* -* $Id: catapult_dct2000.h 3992 2008-06-10 03:13:11Z dgu $ -* -* Wiretap Library -* Copyright (c) 1998 by Gilbert Ramirez -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version 2 -* of the License, or (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -int catapult_dct2000_open(wtap *wth, int *err, gchar **err_info); -gboolean catapult_dct2000_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); -int catapult_dct2000_dump_can_write_encap(int encap); - -#define DCT2000_ENCAP_UNHANDLED 0 -#define DCT2000_ENCAP_SSCOP 101 -#define DCT2000_ENCAP_MTP2 102 -#define DCT2000_ENCAP_NBAP 103 diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/commview.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/commview.h deleted file mode 100644 index a07d0d25..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/commview.h +++ /dev/null @@ -1,33 +0,0 @@ -/* commview.h - * - * $Id: commview.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#ifndef __COMMVIEW_H__ -#define __COMMVIEW_H__ - -int commview_open(wtap *wth, int *err, gchar **err_info _U_); -int commview_dump_can_write_encap(int encap); -gboolean commview_dump_open(wtap_dumper *wdh, gboolean cant_seek _U_, int *err); - -#endif /* __COMMVIEW_H__ */ - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/cosine.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/cosine.h deleted file mode 100644 index 5f5cdadc..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/cosine.h +++ /dev/null @@ -1,32 +0,0 @@ -/* cosine.h - * - * $Id: cosine.h 3992 2008-06-10 03:13:11Z dgu $ - * - * CoSine IPNOS L2 debug output parsing - * Copyright (c) 2002 by Motonori Shindo - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __W_COSINE_H__ -#define __W_COSINE_H__ - -int cosine_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/csids.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/csids.h deleted file mode 100644 index 149d07bd..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/csids.h +++ /dev/null @@ -1,29 +0,0 @@ - /* csids.h - * - * $Id: csids.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Copyright (c) 2000 by Mike Hall - * Copyright (c) Cisco Systems - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __CSIDS_H__ -#define __CSIDS_H__ - -int csids_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/dbs-etherwatch.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/dbs-etherwatch.h deleted file mode 100644 index 971ea7a0..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/dbs-etherwatch.h +++ /dev/null @@ -1,29 +0,0 @@ -/* dbs-etherwatch.h - * - * $Id: dbs-etherwatch.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __W_DBS_ETHERWATCH_H__ -#define __W_DBS_ETHERWATCH_H__ - -int dbs_etherwatch_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/erf.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/erf.h deleted file mode 100644 index 9f6b17cb..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/erf.h +++ /dev/null @@ -1,102 +0,0 @@ -/* -* -* Copyright (c) 2003 Endace Technology Ltd, Hamilton, New Zealand. -* All rights reserved. -* -* This software and documentation has been developed by Endace Technology Ltd. -* along with the DAG PCI network capture cards. For further information please -* visit http://www.endace.com/. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, -* this list of conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* -* 3. The name of Endace Technology Ltd may not be used to endorse or promote -* products derived from this software without specific prior written -* permission. -* -* THIS SOFTWARE IS PROVIDED BY ENDACE TECHNOLOGY LTD ``AS IS'' AND ANY EXPRESS -* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -* EVENT SHALL ENDACE TECHNOLOGY LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -* POSSIBILITY OF SUCH DAMAGE. -* -* $Id: erf.h 3992 2008-06-10 03:13:11Z dgu $ -*/ - -#ifndef __W_ERF_H__ -#define __W_ERF_H__ - -/* Record type defines */ -#define ERF_TYPE_LEGACY 0 -#define ERF_TYPE_HDLC_POS 1 -#define ERF_TYPE_ETH 2 -#define ERF_TYPE_ATM 3 -#define ERF_TYPE_AAL5 4 -#define ERF_TYPE_MC_HDLC 5 -#define ERF_TYPE_MC_RAW 6 -#define ERF_TYPE_MC_ATM 7 -#define ERF_TYPE_MC_RAW_CHANNEL 8 -#define ERF_TYPE_MC_AAL5 9 -#define ERF_TYPE_COLOR_HDLC_POS 10 -#define ERF_TYPE_COLOR_ETH 11 -#define ERF_TYPE_MC_AAL2 12 -#define ERF_TYPE_IP_COUNTER 13 -#define ERF_TYPE_TCP_FLOW_COUNTER 14 -#define ERF_TYPE_DSM_COLOR_HDLC_POS 15 -#define ERF_TYPE_DSM_COLOR_ETH 16 -#define ERF_TYPE_COLOR_MC_HDLC_POS 17 -#define ERF_TYPE_AAL2 18 -#define ERF_TYPE_INFINIBAND 21 - -#define ERF_TYPE_PAD 48 - -#define ERF_TYPE_MIN 1 /* sanity checking */ -#define ERF_TYPE_MAX 48 /* sanity checking */ - - /* - * The timestamp is 64bit unsigned fixed point little-endian value with - * 32 bits for second and 32 bits for fraction. - */ -typedef guint64 erf_timestamp_t; - -typedef struct erf_record { - erf_timestamp_t ts; - guint8 type; - guint8 flags; - guint16 rlen; - guint16 lctr; - guint16 wlen; -} erf_header_t; - -typedef struct erf_mc_hdr { - guint32 mc; -} erf_mc_header_t; - -typedef struct erf_eth_hdr { - guint16 eth; -} erf_eth_header_t; - -union erf_subhdr { - struct erf_mc_hdr mc_hdr; - struct erf_eth_hdr eth_hdr; -}; - -#define MIN_RECORDS_FOR_ERF_CHECK 3 -#define RECORDS_FOR_ERF_CHECK 20 -#define FCS_BITS 32 - -int erf_open(wtap *wth, int *err, gchar **err_info); - -#endif /* __W_ERF_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/etherpeek.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/etherpeek.h deleted file mode 100644 index 465ad39c..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/etherpeek.h +++ /dev/null @@ -1,29 +0,0 @@ -/* etherpeek.h - * - * $Id: etherpeek.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __W_ETHERPEEK_H__ -#define __W_ETHERPEEK_H__ - -int etherpeek_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/eyesdn.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/eyesdn.h deleted file mode 100644 index 7b28b520..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/eyesdn.h +++ /dev/null @@ -1,29 +0,0 @@ -/* eyesdn.h - * - * $Id: eyesdn.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __W_EYESDN_H__ -#define __W_EYESDN_H__ - -int eyesdn_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/file_util.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/file_util.h deleted file mode 100644 index e472e3ca..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/file_util.h +++ /dev/null @@ -1,136 +0,0 @@ -/* file_util.h - * File utility definitions - * - * $Id: file_util.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __FILE_UTIL_H__ -#define __FILE_UTIL_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#include - -#ifdef _WIN32 -#include -#endif - -#ifdef HAVE_SYS_STAT_H -#include -#endif - - -/* Win32: Since GLib2.6, we use UTF8 throughout the code, so file functions - * must tweak a given filename from UTF8 to UTF16 as we use NT Unicode (Win9x - * - now unsupported - used locale based encoding here). - */ -#if defined _WIN32 && (GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 6)) -#include - -extern int eth_stdio_open (const gchar *filename, int flags, int mode); -extern int eth_stdio_rename (const gchar *oldfilename, const gchar *newfilename); -extern int eth_stdio_mkdir (const gchar *filename, int mode); -extern int eth_stdio_stat (const gchar *filename, struct stat *buf); -extern int eth_stdio_unlink (const gchar *filename); -extern int eth_stdio_remove (const gchar *filename); -extern FILE * eth_stdio_fopen (const gchar *filename, const gchar *mode); -extern FILE * eth_stdio_freopen (const gchar *filename, const gchar *mode, FILE *stream); - -#define eth_open eth_stdio_open -#define eth_rename eth_stdio_rename -#define eth_mkdir eth_stdio_mkdir -#define eth_stat eth_stdio_stat -#define eth_unlink eth_stdio_unlink -#define eth_remove eth_stdio_remove -#define eth_fopen eth_stdio_fopen -#define eth_freopen eth_stdio_freopen - -#else /* _WIN32 && GLIB_MAJOR_VERSION */ - -/* GLib 2.4 or below, using "old school" functions */ -#ifdef _WIN32 -#define eth_open _open -#define eth_stat _stat -#define eth_unlink _unlink -#define eth_mkdir(dir,mode) _mkdir(dir) -#else -#define eth_open open -#define eth_stat stat -#define eth_unlink unlink -#define eth_mkdir(dir,mode) mkdir(dir,mode) -#endif /* _WIN32 */ - -#define eth_rename rename -#define eth_remove remove -#define eth_fopen fopen -#define eth_freopen freopen - -#endif /* _WIN32 && GLIB_MAJOR_VERSION */ - - -/* some common file function differences between UNIX and WIN32 */ -#ifdef _WIN32 -/* the Win32 API prepends underscores for whatever reasons */ -#define eth_read _read -#define eth_write _write -#define eth_close _close -#define eth_dup _dup -#define eth_lseek _lseek -#else -#define eth_read read -#define eth_write write -#define eth_close close -#define eth_dup dup -#define eth_lseek lseek -#define O_BINARY 0 /* Win32 needs the O_BINARY flag for open() */ -#endif /* _WIN32 */ - -/* directory handling */ -#if GLIB_MAJOR_VERSION >= 2 -#define ETH_DIR GDir -#define ETH_DIRENT const char -#define eth_dir_open g_dir_open -#define eth_dir_read_name g_dir_read_name -#define eth_dir_get_name(dirent) dirent -#define eth_dir_rewind g_dir_rewind -#define eth_dir_close g_dir_close -#else -#define ETH_DIR DIR -#define ETH_DIRENT struct dirent -#define eth_dir_open(name,flags,error) opendir(name) -#define eth_dir_read_name readdir -#define eth_dir_get_name(dirent) (gchar *)(dirent)->d_name -#define eth_dir_rewind rewinddir -#define eth_dir_close closedir -#endif /* GLIB_MAJOR_VERSION */ - -/* XXX - remove include "dirent.h" */ -/* XXX - remove include "direct.h" */ -/* XXX - remove include "sys/stat.h" */ -/* XXX - update docs (e.g. README.developer) */ - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __FILE_UTIL_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/file_wrappers.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/file_wrappers.h deleted file mode 100644 index 193af09f..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/file_wrappers.h +++ /dev/null @@ -1,57 +0,0 @@ -/* file_wrappers.h - * - * $Id: file_wrappers.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __FILE_H__ -#define __FILE_H__ - -extern gint64 file_seek(void *stream, gint64 offset, int whence, int *err); -extern gint64 file_tell(void *stream); -extern int file_error(void *fh); - -#ifdef HAVE_LIBZ - -extern FILE_T file_open(const char *path, const char *mode); -#define filed_open gzdopen -/* XX: gzread and gzwrite return number of *bytes* (not number of elements) */ -#define file_read(buf, bsize, count, file) gzread((file),(buf),((count)*(bsize))) -#define file_write(buf, bsize, count, file) gzwrite((file),(buf),((count)*(bsize))) -#define file_close gzclose -#define file_getc gzgetc -#define file_gets(buf, len, file) gzgets((file), (buf), (len)) -#define file_eof gzeof - -#else /* No zLib */ - -#define file_open(path, mode) eth_fopen(path, mode) -#define filed_open fdopen -/* XX: file_read and file_write defined to return number of *bytes* to be consistent with gzread & gzwrite */ -#define file_read(buf, bsize, count, file) ((bsize) * fread((buf), (bsize), (count), (file))) -#define file_write(buf, bsize, count, file) ((bsize) * fwrite((buf), (bsize), (count), (file))) -#define file_close fclose -#define file_getc fgetc -#define file_gets fgets -#define file_eof feof - -#endif /* HAVE_LIBZ */ - -#endif /* __FILE_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/hcidump.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/hcidump.h deleted file mode 100644 index 08a0a61c..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/hcidump.h +++ /dev/null @@ -1,28 +0,0 @@ -/* hcidump.h - * - * $Id: hcidump.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Copyright (c) 2003 by Marcel Holtmann - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __HCIDUMP_H__ -#define __HCIDUMP_H__ - -int hcidump_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/i4b_trace.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/i4b_trace.h deleted file mode 100644 index 359f09ea..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/i4b_trace.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 1997, 1999 Hellmuth Michaelis. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - *--------------------------------------------------------------------------- - * - * i4b_trace.h - header file for trace data read device - * ---------------------------------------------------- - * - * $Id: i4b_trace.h 3992 2008-06-10 03:13:11Z dgu $ - * - * last edit-date: [Sun Feb 14 10:39:26 1999] - * - *---------------------------------------------------------------------------*/ - -#ifndef _I4B_TRACE_H_ -#define _I4B_TRACE_H_ - -/*---------------------------------------------------------------------------* - * structure of the header at the beginning of every trace mbuf - *---------------------------------------------------------------------------*/ -typedef struct { - guint32 length; /* length of the following mbuf */ - gint32 unit; /* controller unit number */ - gint32 type; /* type of channel */ -#define TRC_CH_I 0 /* Layer 1 INFO's */ -#define TRC_CH_D 1 /* D channel */ -#define TRC_CH_B1 2 /* B1 channel */ -#define TRC_CH_B2 3 /* B2 channel */ - gint32 dir; /* direction */ -#define FROM_TE 0 /* user -> network */ -#define FROM_NT 1 /* network -> user */ - gint32 trunc; /* # of truncated bytes (frame > MCLBYTES) */ - guint32 count; /* frame count for this unit/type */ - guint32 ts_sec; /* timestamp seconds */ - guint32 ts_usec; /* timestamp microseconds */ -} i4b_trace_hdr_t; - -#define INFO0 0 /* layer 1 */ -#define INFO1_8 1 -#define INFO1_10 2 -#define INFO2 3 -#define INFO3 4 -#define INFO4_8 5 -#define INFO4_10 6 - -/*---------------------------------------------------------------------------* - * ioctl via /dev/i4btrc device(s): - * get/set current trace flag settings - *---------------------------------------------------------------------------*/ - -#define I4B_TRC_GET _IOR('T', 0, int) /* get trace settings */ -#define I4B_TRC_SET _IOW('T', 1, int) /* set trace settings */ - -#define TRACE_OFF 0x00 /* tracing off */ -#define TRACE_I 0x01 /* trace L1 INFO's on */ -#define TRACE_D_TX 0x02 /* trace D channel on */ -#define TRACE_D_RX 0x04 /* trace D channel on */ -#define TRACE_B_TX 0x08 /* trace B channel on */ -#define TRACE_B_RX 0x10 /* trace B channel on */ - -typedef struct { - gint32 rxunit; /* unit # for rx frames */ - gint32 rxflags; /* d and/or b channel */ - gint32 txunit; /* unit # for tx frames */ - gint32 txflags; /* d and/or b channel */ -} i4b_trace_setupa_t; - -#define I4B_TRC_SETA _IOW('T', 2, i4b_trace_setupa_t) /* set analyze mode */ -#define I4B_TRC_RESETA _IOW('T', 3, int) /* reset analyze mode */ - -#endif /* _I4B_TRACE_H_ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/i4btrace.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/i4btrace.h deleted file mode 100644 index 716e7c47..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/i4btrace.h +++ /dev/null @@ -1,29 +0,0 @@ -/* i4btrace.h - * - * $Id: i4btrace.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1999 by Bert Driehuis - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __I4BTRACE_H__ -#define __I4BTRACE_H__ - -int i4btrace_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/iptrace.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/iptrace.h deleted file mode 100644 index 57ac0d59..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/iptrace.h +++ /dev/null @@ -1,29 +0,0 @@ -/* iptrace.h - * - * $Id: iptrace.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __IPTRACE_H__ -#define __IPTRACE_H__ - -int iptrace_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/iseries.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/iseries.h deleted file mode 100644 index ffb43e31..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/iseries.h +++ /dev/null @@ -1,28 +0,0 @@ -/* iseries.h - * - * $Id: iseries.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 2005 by Martin Warnes - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __W_ISERIES_H__ -#define __W_ISERIES_H__ - -int iseries_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/k12.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/k12.h deleted file mode 100644 index c2647322..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/k12.h +++ /dev/null @@ -1,28 +0,0 @@ -/* k12.c -* -* $Id: k12.h 3992 2008-06-10 03:13:11Z dgu $ -* -* Wiretap Library -* Copyright (c) 1998 by Gilbert Ramirez -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version 2 -* of the License, or (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -int k12_open(wtap *wth, int *err, gchar **err_info); -int k12_dump_can_write_encap(int encap); -gboolean k12_dump_open(wtap_dumper *wdh, gboolean cant_seek _U_, int *err); -int k12text_open(wtap *wth, int *err, gchar **err_info _U_); -int k12text_dump_can_write_encap(int encap); -gboolean k12text_dump_open(wtap_dumper *wdh, gboolean cant_seek _U_, int *err); diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/k12text_lex.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/k12text_lex.h deleted file mode 100644 index ccd97c5d..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/k12text_lex.h +++ /dev/null @@ -1,6 +0,0 @@ -/* This is generated by runlex.sh. Do not edit it. */ -#define yylex K12Text_lex -#ifndef YY_DECL -#define YY_DECL int yylex(void) -#endif -YY_DECL; diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/lanalyzer.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/lanalyzer.h deleted file mode 100644 index 758a9833..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/lanalyzer.h +++ /dev/null @@ -1,176 +0,0 @@ -/* lanalyzer.h - * - * $Id: lanalyzer.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __LANALYZER_H__ -#define __LANALYZER_H__ - -/* Record type codes: */ - -#define RT_HeaderRegular 0x1001 -#define RT_HeaderCyclic 0x1007 -#define RT_RxChannelName 0x1006 -#define RT_TxChannelName 0x100b -#define RT_FilterName 0x1032 -#define RT_RxTemplateName 0x1035 -#define RT_TxTemplateName 0x1036 -#define RT_DisplayOptions 0x100a -#define RT_Summary 0x1002 -#define RT_SubfileSummary 0x1003 -#define RT_CyclicInformation 0x1009 -#define RT_Index 0x1004 -#define RT_PacketData 0x1005 - -#define LA_ProFileLimit (1024 * 1024 * 32) - -typedef guint8 Eadr[6]; -typedef guint16 TimeStamp[3]; /* 0.5 microseconds since start of trace */ - -/* - * These records have only 2-byte alignment for 4-byte quantities, - * so the structures aren't necessarily valid; they're kept as comments - * for reference purposes. - */ - -/* - * typedef struct { - * guint8 day; - * guint8 mon; - * gint16 year; - * } Date; - */ - -/* - * typedef struct { - * guint8 second; - * guint8 minute; - * guint8 hour; - * guint8 day; - * gint16 reserved; - * } Time; - */ - -/* - * typedef struct { - * guint16 rx_channels; - * guint16 rx_errors; - * gint16 rx_frm_len; - * gint16 rx_frm_sln; - * TimeStamp rx_time; - * guint32 pktno; - * gint16 prvlen; - * gint16 offset; - * gint16 tx_errs; - * gint16 rx_filters; - * gint8 unused[2]; - * gint16 hwcolls; - * gint16 hwcollschans; - * Packetdata ....; - * } LA_PacketRecord; - */ - -#define LA_PacketRecordSize 32 - -/* - * typedef struct { - * Date datcre; - * Date datclo; - * Time timeopn; - * Time timeclo; - * Eadr statadr; - * gint16 mxseqno; - * gint16 slcoff; - * gint16 mxslc; - * gint32 totpktt; - * gint32 statrg; - * gint32 stptrg; - * gint32 mxpkta[36]; - * gint16 board_type; - * gint16 board_version; - * gint8 reserved[18]; - * } Summary; - */ - -#define SummarySize (18+22+(4*36)+6+6+6+4+4) - - -/* - * typedef struct { - * gint16 rid; - * gint16 rlen; - * Summary s; - * } LA_SummaryRecord; - */ - -#define LA_SummaryRecordSize (SummarySize + 4) - - -/* - * typedef struct { - * gint16 rid; - * gint16 rlen; - * gint16 seqno; - * gint32 totpktf; - * } LA_SubfileSummaryRecord; - */ - -#define LA_SubfileSummaryRecordSize 10 - - -#define LA_IndexSize 500 - -/* - * typedef struct { - * gint16 rid; - * gint16 rlen; - * gint16 idxsp; = LA_IndexSize - * gint16 idxct; - * gint8 idxgranu; - * gint8 idxvd; - * gint32 trcidx[LA_IndexSize + 2]; +2 undocumented but used by La 2.2 - * } LA_IndexRecord; - */ - -#define LA_IndexRecordSize (10 + 4 * (LA_IndexSize + 2)) - -/* - * typedef struct { - * gint16 rid; - * gint16 rlen; - * } LA_RecordHeader; - */ - -#define LA_RecordHeaderSize 4 - -typedef struct { - gboolean init; - struct timeval start; - guint32 pkts; - int encap; - int lastlen; - } LA_TmpInfo; - -int lanalyzer_open(wtap *wth, int *err, gchar **err_info); -gboolean lanalyzer_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); -int lanalyzer_dump_can_write_encap(int encap); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/libpcap.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/libpcap.h deleted file mode 100644 index 3d4038f1..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/libpcap.h +++ /dev/null @@ -1,106 +0,0 @@ -/* libpcap.h - * - * $Id: libpcap.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __W_LIBPCAP_H__ -#define __W_LIBPCAP_H__ - -/* Magic numbers in "libpcap" files. - - "libpcap" file records are written in the byte order of the host that - writes them, and the reader is expected to fix this up. - - PCAP_MAGIC is the magic number, in host byte order; PCAP_SWAPPED_MAGIC - is a byte-swapped version of that. - - PCAP_MODIFIED_MAGIC is for Alexey Kuznetsov's modified "libpcap" - format, as generated on Linux systems that have a "libpcap" with - his patches, at - - http://ftp.sunet.se/pub/os/Linux/ip-routing/lbl-tools/ - - applied; PCAP_SWAPPED_MODIFIED_MAGIC is the byte-swapped version. - - PCAP_NSEC_MAGIC is for Ulf Lamping's modified "libpcap" format, - which uses the same common file format as PCAP_MAGIC, but the - timestamps are saved in nanosecond resolution instead of microseconds. - PCAP_SWAPPED_NSEC_MAGIC is a byte-swapped version of that. */ -#define PCAP_MAGIC 0xa1b2c3d4 -#define PCAP_SWAPPED_MAGIC 0xd4c3b2a1 -#define PCAP_MODIFIED_MAGIC 0xa1b2cd34 -#define PCAP_SWAPPED_MODIFIED_MAGIC 0x34cdb2a1 -#define PCAP_NSEC_MAGIC 0xa1b23c4d -#define PCAP_SWAPPED_NSEC_MAGIC 0x4d3cb2a1 - -/* "libpcap" file header (minus magic number). */ -struct pcap_hdr { - guint16 version_major; /* major version number */ - guint16 version_minor; /* minor version number */ - gint32 thiszone; /* GMT to local correction */ - guint32 sigfigs; /* accuracy of timestamps */ - guint32 snaplen; /* max length of captured packets, in octets */ - guint32 network; /* data link type */ -}; - -/* "libpcap" record header. */ -struct pcaprec_hdr { - guint32 ts_sec; /* timestamp seconds */ - guint32 ts_usec; /* timestamp microseconds (nsecs for PCAP_NSEC_MAGIC) */ - guint32 incl_len; /* number of octets of packet saved in file */ - guint32 orig_len; /* actual length of packet */ -}; - -/* "libpcap" record header for Alexey's patched version. */ -struct pcaprec_modified_hdr { - struct pcaprec_hdr hdr; /* the regular header */ - guint32 ifindex; /* index, in *capturing* machine's list of - interfaces, of the interface on which this - packet came in. */ - guint16 protocol; /* Ethernet packet type */ - guint8 pkt_type; /* broadcast/multicast/etc. indication */ - guint8 pad; /* pad to a 4-byte boundary */ -}; - -/* "libpcap" record header for Alexey's patched version in its ss990915 - incarnation; this version shows up in SuSE Linux 6.3. */ -struct pcaprec_ss990915_hdr { - struct pcaprec_hdr hdr; /* the regular header */ - guint32 ifindex; /* index, in *capturing* machine's list of - interfaces, of the interface on which this - packet came in. */ - guint16 protocol; /* Ethernet packet type */ - guint8 pkt_type; /* broadcast/multicast/etc. indication */ - guint8 cpu1, cpu2; /* SMP debugging gunk? */ - guint8 pad[3]; /* pad to a 4-byte boundary */ -}; - -/* "libpcap" record header for version used on some Nokia boxes (firewalls?) */ -struct pcaprec_nokia_hdr { - struct pcaprec_hdr hdr; /* the regular header */ - guint8 stuff[4]; /* mysterious stuff */ -}; - -int libpcap_open(wtap *wth, int *err, gchar **err_info); -gboolean libpcap_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); -int libpcap_dump_can_write_encap(int encap); -int wtap_pcap_encap_to_wtap_encap(int encap); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/mpeg-audio.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/mpeg-audio.h deleted file mode 100644 index 3ead2ff5..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/mpeg-audio.h +++ /dev/null @@ -1,98 +0,0 @@ -/* mpeg-audio.h - * - * MPEG Audio header dissection - * Written by Shaun Jackman - * Copyright 2007 Shaun Jackman - * - * $Id: mpeg-audio.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef MPA_H -#define MPA_H 1 - -struct mpa { - unsigned emphasis :2; - unsigned original :1; - unsigned copyright :1; - unsigned modeext :2; - unsigned mode :2; - unsigned private :1; - unsigned padding :1; - unsigned frequency :2; - unsigned bitrate :4; - unsigned protection :1; - unsigned layer :2; - unsigned version :2; - unsigned sync :11; -}; - -#define MPA_UNMARSHAL_SYNC(n) ((n) >> 21 & 0x7ff) -#define MPA_UNMARSHAL_VERSION(n) ((n) >> 19 & 0x3) -#define MPA_UNMARSHAL_LAYER(n) ((n) >> 17 & 0x3) -#define MPA_UNMARSHAL_PROTECTION(n) ((n) >> 16 & 0x1) -#define MPA_UNMARSHAL_BITRATE(n) ((n) >> 12 & 0xf) -#define MPA_UNMARSHAL_FREQUENCY(n) ((n) >> 10 & 0x3) -#define MPA_UNMARSHAL_PADDING(n) ((n) >> 9 & 0x1) -#define MPA_UNMARSHAL_PRIVATE(n) ((n) >> 8 & 0x1) -#define MPA_UNMARSHAL_MODE(n) ((n) >> 6 & 0x3) -#define MPA_UNMARSHAL_MODEEXT(n) ((n) >> 4 & 0x3) -#define MPA_UNMARSHAL_COPYRIGHT(n) ((n) >> 3 & 0x1) -#define MPA_UNMARSHAL_ORIGINAL(n) ((n) >> 2 & 0x1) -#define MPA_UNMARSHAL_EMPHASIS(n) ((n) >> 0 & 0x3) - -#define MPA_UNMARSHAL(mpa, n) do { \ - (mpa)->sync = MPA_UNMARSHAL_SYNC(n); \ - (mpa)->version = MPA_UNMARSHAL_VERSION(n); \ - (mpa)->layer = MPA_UNMARSHAL_LAYER(n); \ - (mpa)->protection = MPA_UNMARSHAL_PROTECTION(n); \ - (mpa)->bitrate = MPA_UNMARSHAL_BITRATE(n); \ - (mpa)->frequency = MPA_UNMARSHAL_FREQUENCY(n); \ - (mpa)->padding = MPA_UNMARSHAL_PADDING(n); \ - (mpa)->private = MPA_UNMARSHAL_PRIVATE(n); \ - (mpa)->mode = MPA_UNMARSHAL_MODE(n); \ - (mpa)->modeext = MPA_UNMARSHAL_MODEEXT(n); \ - (mpa)->copyright = MPA_UNMARSHAL_COPYRIGHT(n); \ - (mpa)->original = MPA_UNMARSHAL_ORIGINAL(n); \ - (mpa)->emphasis = MPA_UNMARSHAL_EMPHASIS(n); \ - } while (0) - -int mpa_version(const struct mpa *); -int mpa_layer(const struct mpa *); -unsigned mpa_samples(const struct mpa *); -unsigned mpa_bitrate(const struct mpa *); -unsigned mpa_frequency(const struct mpa *); -unsigned mpa_padding(const struct mpa *); - -#define MPA_DATA_BYTES(mpa) (mpa_bitrate(mpa) * mpa_samples(mpa) \ - / mpa_frequency(mpa) / 8) -#define MPA_BYTES(mpa) (MPA_DATA_BYTES(mpa) + mpa_padding(mpa)) -#define MPA_DURATION_NS(mpa) \ - (1000000000 / mpa_frequency(mpa) * mpa_samples(mpa)) - -enum { MPA_SYNC = 0x7ff }; - -#define MPA_SYNC_VALID(mpa) ((mpa)->sync == MPA_SYNC) -#define MPA_VERSION_VALID(mpa) (mpa_version(mpa) >= 0) -#define MPA_LAYER_VALID(mpa) (mpa_layer(mpa) >= 0) -#define MPA_BITRATE_VALID(mpa) (mpa_bitrate(mpa) > 0) -#define MPA_FREQUENCY_VALID(mpa) (mpa_frequency(mpa) > 0) -#define MPA_VALID(mpa) (MPA_SYNC_VALID(mpa) \ - && MPA_VERSION_VALID(mpa) && MPA_LAYER_VALID(mpa) \ - && MPA_BITRATE_VALID(mpa) && MPA_FREQUENCY_VALID(mpa)) - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/mpeg.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/mpeg.h deleted file mode 100644 index c24fe87d..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/mpeg.h +++ /dev/null @@ -1,32 +0,0 @@ -/* mpeg.h - * - * MPEG file format decoder for the Wiretap library. - * Written by Shaun Jackman - * Copyright 2007 Shaun Jackman - * - * $Id: mpeg.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __W_MPEG_H__ -#define __W_MPEG_H__ - -#include "wtap-int.h" - -int mpeg_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netmon.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netmon.h deleted file mode 100644 index ab0904cc..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netmon.h +++ /dev/null @@ -1,30 +0,0 @@ -/* netmon.h - * - * $Id: netmon.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __NETMON_H__ -#define __NETMON_H__ - -int netmon_open(wtap *wth, int *err, gchar **err_info); -gboolean netmon_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); -int netmon_dump_can_write_encap(int encap); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netscreen.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netscreen.h deleted file mode 100644 index dce7c361..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netscreen.h +++ /dev/null @@ -1,53 +0,0 @@ -/* netscreen.h - * - * $Id: netscreen.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Juniper NetScreen snoop output parser - * Created by re-using a lot of code from cosine.c - * Copyright (c) 2007 by Sake Blok - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __W_NETSCREEN_H__ -#define __W_NETSCREEN_H__ - -/* Magic text to check for NetScreen snoop output */ -#define NETSCREEN_HDR_MAGIC_STR1 "(i) len=" -#define NETSCREEN_HDR_MAGIC_STR2 "(o) len=" - -/* Magic text for start of packet */ -#define NETSCREEN_REC_MAGIC_STR1 NETSCREEN_HDR_MAGIC_STR1 -#define NETSCREEN_REC_MAGIC_STR2 NETSCREEN_HDR_MAGIC_STR2 - -#define NETSCREEN_LINE_LENGTH 128 -#define NETSCREEN_HEADER_LINES_TO_CHECK 32 -#define NETSCREEN_MAX_INFOLINES 8 -#define NETSCREEN_SPACES_ON_INFO_LINE 14 -#define NETSCREEN_MAX_INT_NAME_LENGTH 16 - -#define NETSCREEN_INGRESS FALSE -#define NETSCREEN_EGRESS TRUE - - -#define NETSCREEN_MAX_PACKET_LEN 65536 - -int netscreen_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/nettl.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/nettl.h deleted file mode 100644 index 1ac9f756..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/nettl.h +++ /dev/null @@ -1,124 +0,0 @@ -/* nettl.h - * - * $Id: nettl.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * Enhancements by Mark C. Brown - * Copyright (C) 2003, 2005 Hewlett-Packard Development Company, L.P. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef __NETTL_H__ -#define __NETTL_H__ - -/* nettl subsystems are defined in /etc/nettlgen.conf */ - -#define NETTL_SUBSYS_NS_LS_LOGGING 0 -#define NETTL_SUBSYS_NS_LS_NFT 1 -#define NETTL_SUBSYS_NS_LS_LOOPBACK 2 -#define NETTL_SUBSYS_NS_LS_NI 3 -#define NETTL_SUBSYS_NS_LS_IPC 4 -#define NETTL_SUBSYS_NS_LS_SOCKREGD 5 -#define NETTL_SUBSYS_NS_LS_TCP 6 -#define NETTL_SUBSYS_NS_LS_PXP 7 -#define NETTL_SUBSYS_NS_LS_UDP 8 -#define NETTL_SUBSYS_NS_LS_IP 9 -#define NETTL_SUBSYS_NS_LS_PROBE 10 -#define NETTL_SUBSYS_NS_LS_DRIVER 11 -#define NETTL_SUBSYS_NS_LS_RLBD 12 -#define NETTL_SUBSYS_NS_LS_BUFS 13 -#define NETTL_SUBSYS_NS_LS_CASE21 14 -#define NETTL_SUBSYS_NS_LS_ROUTER21 15 -#define NETTL_SUBSYS_NS_LS_NFS 16 -#define NETTL_SUBSYS_NS_LS_NETISR 17 -#define NETTL_SUBSYS_NS_LS_NSE 18 -#define NETTL_SUBSYS_NS_LS_STRLOG 19 -#define NETTL_SUBSYS_NS_LS_TIRDWR 21 -#define NETTL_SUBSYS_NS_LS_TIMOD 22 -#define NETTL_SUBSYS_NS_LS_ICMP 23 -#define NETTL_SUBSYS_FILTER 26 -#define NETTL_SUBSYS_NAME 27 -#define NETTL_SUBSYS_IGMP 29 -#define NETTL_SUBSYS_SX25L2 34 -#define NETTL_SUBSYS_SX25L3 35 -#define NETTL_SUBSYS_FTAM_INIT 64 -#define NETTL_SUBSYS_FTAM_RESP 65 -#define NETTL_SUBSYS_FTAM_VFS 70 -#define NETTL_SUBSYS_FTAM_USER 72 -#define NETTL_SUBSYS_OTS 90 -#define NETTL_SUBSYS_NETWORK 91 -#define NETTL_SUBSYS_TRANSPORT 92 -#define NETTL_SUBSYS_SESSION 93 -#define NETTL_SUBSYS_ACSE_PRES 94 -#define NETTL_SUBSYS_SHM 116 -#define NETTL_SUBSYS_ACSE_US 119 -#define NETTL_SUBSYS_HPS 121 -#define NETTL_SUBSYS_CM 122 -#define NETTL_SUBSYS_ULA_UTILS 123 -#define NETTL_SUBSYS_EM 124 -#define NETTL_SUBSYS_HP_APAPORT 189 -#define NETTL_SUBSYS_HP_APALACP 190 -#define NETTL_SUBSYS_NS_LS_IPV6 244 -#define NETTL_SUBSYS_NS_LS_ICMPV6 245 -#define NETTL_SUBSYS_NS_LS_TELNET 267 -#define NETTL_SUBSYS_NS_LS_SCTP 268 - -/* Ethernet cards */ -#define NETTL_SUBSYS_100VG 37 -#define NETTL_SUBSYS_LAN100 164 -#define NETTL_SUBSYS_EISA100BT 172 -#define NETTL_SUBSYS_BASE100 173 -#define NETTL_SUBSYS_GSC100BT 178 -#define NETTL_SUBSYS_PCI100BT 179 -#define NETTL_SUBSYS_SPP100BT 180 -#define NETTL_SUBSYS_GELAN 185 -#define NETTL_SUBSYS_BTLAN 210 -#define NETTL_SUBSYS_INTL100 233 -#define NETTL_SUBSYS_IGELAN 252 -#define NETTL_SUBSYS_IETHER 253 -#define NETTL_SUBSYS_IXGBE 265 - -/* FDDI cards */ -#define NETTL_SUBSYS_HPPB_FDDI 95 -#define NETTL_SUBSYS_EISA_FDDI 174 -#define NETTL_SUBSYS_PCI_FDDI 176 -#define NETTL_SUBSYS_HSC_FDDI 177 - -/* Token Ring cards */ -#define NETTL_SUBSYS_TOKEN 31 -#define NETTL_SUBSYS_PCI_TR 187 - -/* from /usr/include/sys/subsys_id.h */ - -#define NETTL_HDR_HDRIN 0x80000000 -#define NETTL_HDR_HDROUT 0x40000000 -#define NETTL_HDR_PDUIN 0x20000000 -#define NETTL_HDR_PDUOUT 0x10000000 -#define NETTL_HDR_PROCEDURE_TRACE 0x08000000 -#define NETTL_HDR_STATE_TRACE 0x04000000 -#define NETTL_HDR_ERROR_TRACE 0x02000000 -#define NETTL_HDR_LOG_TRACE 0x01000000 -#define NETTL_HDR_LOOPBACK 0x00800000 -#define NETTL_HDR_PTOP 0x00400000 -#define NETTL_HDR_SUBSYSTEM_BITS_MASK 0x000fffff - -int nettl_open(wtap *wth, int *err, gchar **err_info); -gboolean nettl_dump_open(wtap_dumper *wdh, gboolean cant_seek _U_, int *err); -int nettl_dump_can_write_encap(int encap); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/network_instruments.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/network_instruments.h deleted file mode 100644 index ab9708b7..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/network_instruments.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * $Id: network_instruments.h 3992 2008-06-10 03:13:11Z dgu $ - */ - -/*************************************************************************** - NetworkInstruments.h - description - ------------------- - begin : Wed Oct 29 2003 - copyright : (C) 2003 by root - email : scotte[AT}netinst.com - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#ifndef __NETWORK_INSTRUMENTS_H__ -#define __NETWORK_INSTRUMENTS_H__ - -int network_instruments_open(wtap *wth, int *err, gchar **err_info); -int network_instruments_dump_can_write_encap(int encap); -gboolean network_instruments_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); - -typedef struct capture_file_header -{ - char observer_version[32]; - guint16 offset_to_first_packet; - char probe_instance; - guint8 number_of_information_elements; /* number of TLVs in the header */ -} capture_file_header; - -typedef struct tlv_header -{ - guint16 type; - guint16 length; /* includes the length of the TLV header */ -} tlv_header; - -/* - * TLV type values. - */ -#define INFORMATION_TYPE_ALIAS_LIST 0x01 -#define INFORMATION_TYPE_COMMENT 0x02 /* ASCII text */ - -typedef struct packet_entry_header -{ - guint32 packet_magic; - guint32 network_speed; - guint16 captured_size; - guint16 network_size; - guint16 offset_to_frame; - guint16 offset_to_next_packet; - guint8 network_type; - guint8 flags; - guint8 number_of_information_elements; /* number of TLVs in the header */ - guint8 packet_type; - guint16 errors; - guint16 reserved; - guint64 packet_number; - guint64 original_packet_number; - guint64 nano_seconds_since_2000; -} packet_entry_header; - -/* - * Network type values. - */ -#define OBSERVER_UNDEFINED 0xFF -#define OBSERVER_ETHERNET 0x00 -#define OBSERVER_TOKENRING 0x01 -#define OBSERVER_FDDI 0x02 - -/* - * Packet type values. - */ -#define PACKET_TYPE_DATA_PACKET 0 -#define PACKET_TYPE_EXPERT_INFORMATION_PACKET 1 - -/* - * The Observer document indicates that the types of expert information - * packets are: - * - * Network Load (markers used by Expert Time Interval and What If - * analysis modes) - * - * Start/Stop Packet Capture marker frames (with time stamps when - * captures start and stop) - * - * Wireless Channel Change (markers showing what channel was being - * currently listened to) - * - * That information appears to be contained in TLVs. - */ - -/* - * TLV type values. - */ -#define INFORMATION_TYPE_NETWORK_LOAD 0x0100 -#define INFORMATION_TYPE_CAPTURE_START_STOP 0x0104 - -/* - * Might some of these be broadcast and multicast packet counts? - */ -typedef struct tlv_network_load -{ - guint32 utilization; /* network utilization, in .1% units */ - guint32 unknown1; - guint32 unknown2; - guint32 packets_per_second; - guint32 unknown3; - guint32 bytes_per_second; - guint32 unknown4; -} tlv_network_load; - -typedef struct tlv_capture_start_stop -{ - guint32 start_stop; -} tlv_capture_start_stop; - -#define START_STOP_TYPE_STOP 0 -#define START_STOP_TYPE_START 1 - -#endif - diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netxray.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netxray.h deleted file mode 100644 index 0c38bb34..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netxray.h +++ /dev/null @@ -1,32 +0,0 @@ -/* netxray.h - * - * $Id: netxray.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __NETXRAY_H__ -#define __NETXRAY_H__ - -int netxray_open(wtap *wth, int *err, gchar **err_info); -int netxray_dump_can_write_encap_1_1(int encap); -gboolean netxray_dump_open_1_1(wtap_dumper *wdh, gboolean cant_seek, int *err); -int netxray_dump_can_write_encap_2_0(int encap); -gboolean netxray_dump_open_2_0(wtap_dumper *wdh, gboolean cant_seek, int *err); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ngsniffer.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ngsniffer.h deleted file mode 100644 index a4a25f6e..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ngsniffer.h +++ /dev/null @@ -1,30 +0,0 @@ -/* ngsniffer.h - * - * $Id: ngsniffer.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __NGSNIFFER_H__ -#define __NGSNIFFER_H__ - -int ngsniffer_open(wtap *wth, int *err, gchar **err_info); -gboolean ngsniffer_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); -int ngsniffer_dump_can_write_encap(int encap); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/pcapng.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/pcapng.h deleted file mode 100644 index 65d7de3d..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/pcapng.h +++ /dev/null @@ -1,30 +0,0 @@ -/* pcapng.h - * - * $Id: pcapng.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __W_PCAPNG_H__ -#define __W_PCAPNG_H__ - -int pcapng_open(wtap *wth, int *err, gchar **err_info); -gboolean pcapng_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); -int pcapng_dump_can_write_encap(int encap); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/pppdump.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/pppdump.h deleted file mode 100644 index c5b8aad0..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/pppdump.h +++ /dev/null @@ -1,28 +0,0 @@ -/* pppdump.h - * - * $Id: pppdump.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Copyright (c) 2000 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __PPPDUMP_H__ -#define __PPPDUMP_H__ - -int pppdump_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/radcom.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/radcom.h deleted file mode 100644 index 0e6724c7..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/radcom.h +++ /dev/null @@ -1,29 +0,0 @@ -/* radcom.h - * - * $Id: radcom.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __RADCOM_H__ -#define __RADCOM_H__ - -int radcom_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/snoop.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/snoop.h deleted file mode 100644 index a1a68f87..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/snoop.h +++ /dev/null @@ -1,30 +0,0 @@ -/* snoop.h - * - * $Id: snoop.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __W_SNOOP_H__ -#define __W_SNOOP_H__ - -int snoop_open(wtap *wth, int *err, gchar **err_info); -gboolean snoop_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); -int snoop_dump_can_write_encap(int encap); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/toshiba.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/toshiba.h deleted file mode 100644 index eea69129..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/toshiba.h +++ /dev/null @@ -1,28 +0,0 @@ -/* toshiba.h - * - * $Id: toshiba.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __W_TOSHIBA_H__ -#define __W_TOSHIBA_H__ - -int toshiba_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/visual.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/visual.h deleted file mode 100644 index 0c094a9e..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/visual.h +++ /dev/null @@ -1,35 +0,0 @@ -/* visual.h - * - * File read write routines for Visual Networks .cap files. - * Copyright 2001, Tom Nisbet tnisbet@visualnetworks.com - * - * Based on the code that handles netmon files. - * - * $Id: visual.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __VISUAL_H__ -#define __VISUAL_H__ - -int visual_open(wtap *wth, int *err, gchar **err_info); -gboolean visual_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err); -int visual_dump_can_write_encap(int encap); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/vms.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/vms.h deleted file mode 100644 index 34083b07..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/vms.h +++ /dev/null @@ -1,29 +0,0 @@ -/* vms.h - * - * $Id: vms.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 2001 by Marc Milgram - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef __W_VMS_H__ -#define __W_VMS_H__ - -int vms_open(wtap *wth, int *err, gchar **err_info); - -#endif diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/wtap-int.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/wtap-int.h deleted file mode 100644 index 3f48d12c..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/wtap-int.h +++ /dev/null @@ -1,482 +0,0 @@ -/* wtap-int.h - * - * $Id: wtap-int.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __WTAP_INT_H__ -#define __WTAP_INT_H__ - -#ifdef HAVE_SYS_TIME_H -#include -#endif - -#include -#include -#include - -#ifdef HAVE_LIBZ -#ifdef HAVE_WINSOCK2_H -#include -#endif -#include -#define FILE_T gzFile -#else /* No zLib */ -#define FILE_T FILE * -#endif /* HAVE_LIBZ */ - -#include "wtap.h" - -/* Information for a compressed Sniffer data stream. */ -typedef struct { - unsigned char *buf; /* buffer into which we uncompress data */ - size_t nbytes; /* number of bytes of data in that buffer */ - int nextout; /* offset in that buffer of stream's current position */ - gint64 comp_offset; /* current offset in compressed data stream */ - gint64 uncomp_offset; /* current offset in uncompressed data stream */ -} ngsniffer_comp_stream_t; - -typedef struct { - char *sdate; /* Packet start date */ - gboolean tcp_formatted; /* TCP/IP data formated Y/N */ - int format; /* Trace format type */ -} iseries_t; - -typedef struct { - guint maj_vers; - guint min_vers; - guint32 timeunit; - time_t start; - guint network; /* network type */ - ngsniffer_comp_stream_t seq; /* sequential access */ - ngsniffer_comp_stream_t rand; /* random access */ - GList *first_blob; /* list element for first blob */ - GList *last_blob; /* list element for last blob */ - GList *current_blob; /* list element for current blob */ -} ngsniffer_t; - -typedef struct { - gboolean byte_swapped; -} i4btrace_t; - -typedef struct { - gboolean is_hpux_11; -} nettl_t; - -typedef struct { - time_t start; -} lanalyzer_t; - -typedef enum { - NOT_SWAPPED, - SWAPPED, - MAYBE_SWAPPED -} swapped_type_t; - -typedef struct { - gboolean byte_swapped; - swapped_type_t lengths_swapped; - guint16 version_major; - guint16 version_minor; -} libpcap_t; - -typedef struct { - gboolean byte_swapped; - guint16 version_major; - guint16 version_minor; - guint8 if_fcslen; -} pcapng_t; - -typedef struct { - time_t start_secs; - guint32 start_usecs; - guint8 version_major; - guint32 *frame_table; - guint32 frame_table_size; - guint current_frame; -} netmon_t; - -typedef struct { - time_t start_time; - double ticks_per_sec; - double start_timestamp; - gboolean wrapped; - guint32 nframes; - gint64 start_offset; - gint64 end_offset; - int version_major; - gboolean fcs_valid; /* if packets have valid FCS at the end */ - guint isdn_type; /* 1 = E1 PRI, 2 = T1 PRI, 3 = BRI */ -} netxray_t; - -typedef struct { - time_t inittime; - int adjusted; - gint64 next_packet_seek_start; -} ascend_t; - -typedef struct { - gboolean byteswapped; -} csids_t; - -typedef struct { - struct timeval reference_time; -} etherpeek_t; - -typedef struct { - gboolean has_fcs; -} airopeek9_t; - -typedef struct _k12_t k12_t; - -typedef struct { - time_t start_secs; - guint32 start_usecs; -} catapult_dct2000_t; - -typedef struct { - struct wtap_nstime now; - time_t t0; -} mpeg_t; - -typedef gboolean (*subtype_read_func)(struct wtap*, int*, char**, gint64*); -typedef gboolean (*subtype_seek_read_func)(struct wtap*, gint64, union wtap_pseudo_header*, - guint8*, int, int *, char **); -struct wtap { - FILE_T fh; - int fd; /* File descriptor for cap file */ - FILE_T random_fh; /* Secondary FILE_T for random access */ - int file_type; - int snapshot_length; - struct Buffer *frame_buffer; - struct wtap_pkthdr phdr; - union wtap_pseudo_header pseudo_header; - - gint64 data_offset; - - union { - libpcap_t *pcap; - lanalyzer_t *lanalyzer; - ngsniffer_t *ngsniffer; - iseries_t *iseries; - i4btrace_t *i4btrace; - nettl_t *nettl; - netmon_t *netmon; - netxray_t *netxray; - ascend_t *ascend; - csids_t *csids; - etherpeek_t *etherpeek; - airopeek9_t *airopeek9; - k12_t *k12; - catapult_dct2000_t *catapult_dct2000; - mpeg_t *mpeg; - void *generic; - pcapng_t *pcapng; - } capture; - - subtype_read_func subtype_read; - subtype_seek_read_func subtype_seek_read; - void (*subtype_sequential_close)(struct wtap*); - void (*subtype_close)(struct wtap*); - int file_encap; /* per-file, for those - file formats that have - per-file encapsulation - types */ - int tsprecision; /* timestamp precision of the lower 32bits - * e.g. WTAP_FILE_TSPREC_USEC */ -}; - -struct wtap_dumper; - -typedef gboolean (*subtype_write_func)(struct wtap_dumper*, - const struct wtap_pkthdr*, const union wtap_pseudo_header*, - const guchar*, int*); -typedef gboolean (*subtype_close_func)(struct wtap_dumper*, int*); - -typedef struct { - gboolean first_frame; - time_t start; -} ngsniffer_dump_t; - -typedef struct { - gboolean first_frame; - struct wtap_nstime start; - guint32 nframes; -} netxray_dump_t; - -typedef struct { - gboolean got_first_record_time; - struct wtap_nstime first_record_time; - guint32 frame_table_offset; - guint32 *frame_table; - guint frame_table_index; - guint frame_table_size; -} netmon_dump_t; - -typedef struct { - guint32 nframes; -} _5views_dump_t; - -typedef struct { - guint64 packet_count; - guint8 network_type; -} niobserver_dump_t; - -typedef struct { - guint32 file_len; - guint32 num_of_records; - guint32 file_offset; -} k12_dump_t; - -typedef struct { - gboolean first_packet_written; - struct wtap_nstime start_time; -} dct2000_dump_t; - -struct wtap_dumper { - FILE* fh; - int file_type; - int snaplen; - int encap; - gboolean compressed; - gint64 bytes_dumped; - - union { - void *opaque; - ngsniffer_dump_t *ngsniffer; - netmon_dump_t *netmon; - netxray_dump_t *netxray; - _5views_dump_t *_5views; - niobserver_dump_t *niobserver; - k12_dump_t *k12; - dct2000_dump_t *dct2000; - } dump; - - subtype_write_func subtype_write; - subtype_close_func subtype_close; - - int tsprecision; /* timestamp precision of the lower 32bits - * e.g. WTAP_FILE_TSPREC_USEC */ -}; - -extern size_t wtap_dump_file_write(wtap_dumper *wdh, const void *buf, unsigned bufsize); -extern int wtap_dump_file_ferror(wtap_dumper *wdh); - -extern gint wtap_num_file_types; - -/* Macros to byte-swap 64-bit, 32-bit and 16-bit quantities. */ -#define BSWAP64(x) \ - ((((x)&G_GINT64_CONSTANT(0xFF00000000000000U))>>56) | \ - (((x)&G_GINT64_CONSTANT(0x00FF000000000000U))>>40) | \ - (((x)&G_GINT64_CONSTANT(0x0000FF0000000000U))>>24) | \ - (((x)&G_GINT64_CONSTANT(0x000000FF00000000U))>>8) | \ - (((x)&G_GINT64_CONSTANT(0x00000000FF000000U))<<8) | \ - (((x)&G_GINT64_CONSTANT(0x0000000000FF0000U))<<24) | \ - (((x)&G_GINT64_CONSTANT(0x000000000000FF00U))<<40) | \ - (((x)&G_GINT64_CONSTANT(0x00000000000000FFU))<<56)) -#define BSWAP32(x) \ - ((((x)&0xFF000000)>>24) | \ - (((x)&0x00FF0000)>>8) | \ - (((x)&0x0000FF00)<<8) | \ - (((x)&0x000000FF)<<24)) -#define BSWAP16(x) \ - ((((x)&0xFF00)>>8) | \ - (((x)&0x00FF)<<8)) - -/* Macros to byte-swap possibly-unaligned 32-bit and 16-bit quantities; - * they take a pointer to the quantity, and byte-swap it in place. - */ -#define PBSWAP32(p) \ - { \ - guint8 tmp; \ - tmp = (p)[3]; \ - (p)[3] = (p)[0]; \ - (p)[0] = tmp; \ - tmp = (p)[2]; \ - (p)[2] = (p)[1]; \ - (p)[1] = tmp; \ - } -#define PBSWAP16(p) \ - { \ - guint8 tmp; \ - tmp = (p)[1]; \ - (p)[1] = (p)[0]; \ - (p)[0] = tmp; \ - } - -/* Turn host-byte-order values into little-endian values. */ -#define htoles(s) GUINT16_TO_LE(s) -#define htolel(l) GUINT32_TO_LE(l) -#define htolell(ll) GUINT64_TO_LE(ll) - -/* Pointer versions of ntohs and ntohl. Given a pointer to a member of a - * byte array, returns the value of the two or four bytes at the pointer. - * The pletoh[sl] versions return the little-endian representation. - * We also provide pntohll and pletohll, which extract 64-bit integral - * quantities. - * - * These will work regardless of the byte alignment of the pointer. - */ - -#ifndef pntohs -#define pntohs(p) ((guint16) \ - ((guint16)*((const guint8 *)(p)+0)<<8| \ - (guint16)*((const guint8 *)(p)+1)<<0)) -#endif - -#ifndef pntoh24 -#define pntoh24(p) ((guint32)*((const guint8 *)(p)+0)<<16| \ - (guint32)*((const guint8 *)(p)+1)<<8| \ - (guint32)*((const guint8 *)(p)+2)<<0) -#endif - -#ifndef pntohl -#define pntohl(p) ((guint32)*((const guint8 *)(p)+0)<<24| \ - (guint32)*((const guint8 *)(p)+1)<<16| \ - (guint32)*((const guint8 *)(p)+2)<<8| \ - (guint32)*((const guint8 *)(p)+3)<<0) -#endif - -#ifndef pntohll -#define pntohll(p) ((guint64)*((const guint8 *)(p)+0)<<56| \ - (guint64)*((const guint8 *)(p)+1)<<48| \ - (guint64)*((const guint8 *)(p)+2)<<40| \ - (guint64)*((const guint8 *)(p)+3)<<32| \ - (guint64)*((const guint8 *)(p)+4)<<24| \ - (guint64)*((const guint8 *)(p)+5)<<16| \ - (guint64)*((const guint8 *)(p)+6)<<8| \ - (guint64)*((const guint8 *)(p)+7)<<0) -#endif - - -#ifndef pletohs -#define pletohs(p) ((guint16) \ - ((guint16)*((const guint8 *)(p)+1)<<8| \ - (guint16)*((const guint8 *)(p)+0)<<0)) -#endif - -#ifndef pletoh24 -#define pletoh24(p) ((guint32)*((const guint8 *)(p)+2)<<16| \ - (guint32)*((const guint8 *)(p)+1)<<8| \ - (guint32)*((const guint8 *)(p)+0)<<0) -#endif - - -#ifndef pletohl -#define pletohl(p) ((guint32)*((const guint8 *)(p)+3)<<24| \ - (guint32)*((const guint8 *)(p)+2)<<16| \ - (guint32)*((const guint8 *)(p)+1)<<8| \ - (guint32)*((const guint8 *)(p)+0)<<0) -#endif - - -#ifndef pletohll -#define pletohll(p) ((guint64)*((const guint8 *)(p)+7)<<56| \ - (guint64)*((const guint8 *)(p)+6)<<48| \ - (guint64)*((const guint8 *)(p)+5)<<40| \ - (guint64)*((const guint8 *)(p)+4)<<32| \ - (guint64)*((const guint8 *)(p)+3)<<24| \ - (guint64)*((const guint8 *)(p)+2)<<16| \ - (guint64)*((const guint8 *)(p)+1)<<8| \ - (guint64)*((const guint8 *)(p)+0)<<0) -#endif - -/* Pointer routines to put items out in a particular byte order. - * These will work regardless of the byte alignment of the pointer. - */ - -#ifndef phtons -#define phtons(p, v) \ - { \ - (p)[0] = (guint8)((v) >> 8); \ - (p)[1] = (guint8)((v) >> 0); \ - } -#endif - -#ifndef phtonl -#define phtonl(p, v) \ - { \ - (p)[0] = (guint8)((v) >> 24); \ - (p)[1] = (guint8)((v) >> 16); \ - (p)[2] = (guint8)((v) >> 8); \ - (p)[3] = (guint8)((v) >> 0); \ - } -#endif - -#ifndef phtonll -#define phtonll(p, v) \ - { \ - (p)[0] = (guint8)((v) >> 56); \ - (p)[1] = (guint8)((v) >> 48); \ - (p)[2] = (guint8)((v) >> 40); \ - (p)[3] = (guint8)((v) >> 32); \ - (p)[4] = (guint8)((v) >> 24); \ - (p)[5] = (guint8)((v) >> 16); \ - (p)[6] = (guint8)((v) >> 8); \ - (p)[7] = (guint8)((v) >> 0); \ - } -#endif - -#ifndef pletonll -#define pletonll(p, v) \ - { \ - (p)[0] = (guint8)((v) >> 0); \ - (p)[1] = (guint8)((v) >> 8); \ - (p)[2] = (guint8)((v) >> 16); \ - (p)[3] = (guint8)((v) >> 24); \ - (p)[4] = (guint8)((v) >> 32); \ - (p)[5] = (guint8)((v) >> 40); \ - (p)[6] = (guint8)((v) >> 48); \ - (p)[7] = (guint8)((v) >> 56); \ - } -#endif - -#define wtap_file_read_unknown_bytes(target, num_bytes, fh, err) \ - G_STMT_START \ - { \ - int _bytes_read; \ - _bytes_read = file_read((target), 1, (num_bytes), (fh)); \ - if (_bytes_read != (int) (num_bytes)) { \ - *(err) = file_error((fh)); \ - return FALSE; \ - } \ - } \ - G_STMT_END - -#define wtap_file_read_expected_bytes(target, num_bytes, fh, err) \ - G_STMT_START \ - { \ - int _bytes_read; \ - _bytes_read = file_read((target), 1, (num_bytes), (fh)); \ - if (_bytes_read != (int) (num_bytes)) { \ - *(err) = file_error((fh)); \ - if (*(err) == 0 && _bytes_read > 0) { \ - *(err) = WTAP_ERR_SHORT_READ; \ - } \ - return FALSE; \ - } \ - } \ - G_STMT_END - -/* glib doesn't have g_ptr_array_len of all things!*/ -#ifndef g_ptr_array_len -#define g_ptr_array_len(a) ((a)->len) -#endif - -#endif /* __WTAP_INT_H__ */ diff --git a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/wtap.h b/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/wtap.h deleted file mode 100644 index 9f51c19f..00000000 --- a/openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/wtap.h +++ /dev/null @@ -1,944 +0,0 @@ -/* wtap.h - * - * $Id: wtap.h 3992 2008-06-10 03:13:11Z dgu $ - * - * Wiretap Library - * Copyright (c) 1998 by Gilbert Ramirez - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef __WTAP_H__ -#define __WTAP_H__ - -#ifdef HAVE_SYS_TIME_H -#include -#endif - -#ifdef HAVE_WINSOCK2_H -# include -#endif - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* Encapsulation types. Choose names that truly reflect - * what is contained in the packet trace file. - * - * WTAP_ENCAP_PER_PACKET is a value passed to "wtap_dump_open()" or - * "wtap_dump_fd_open()" to indicate that there is no single encapsulation - * type for all packets in the file; this may cause those routines to - * fail if the capture file format being written can't support that. - * It's also returned by "wtap_file_encap()" for capture files that - * don't have a single encapsulation type for all packets in the file. - * - * WTAP_ENCAP_UNKNOWN is returned by "wtap_pcap_encap_to_wtap_encap()" - * if it's handed an unknown encapsulation. - * - * WTAP_ENCAP_FDDI_BITSWAPPED is for FDDI captures on systems where the - * MAC addresses you get from the hardware are bit-swapped. Ideally, - * the driver would tell us that, but I know of none that do, so, for - * now, we base it on the machine on which we're *reading* the - * capture, rather than on the machine on which the capture was taken - * (they're probably likely to be the same). We assume that they're - * bit-swapped on everything except for systems running Ultrix, Alpha - * systems, and BSD/OS systems (that's what "tcpdump" does; I guess - * Digital decided to bit-swap addresses in the hardware or in the - * driver, and I guess BSDI bit-swapped them in the driver, given that - * BSD/OS generally runs on Boring Old PC's). If we create a wiretap - * save file format, we'd use the WTAP_ENCAP values to flag the - * encapsulation of a packet, so there we'd at least be able to base - * it on the machine on which the capture was taken. - * - * WTAP_ENCAP_LINUX_ATM_CLIP is the encapsulation you get with the - * ATM on Linux code from ; - * that code adds a DLT_ATM_CLIP DLT_ code of 19, and that - * encapsulation isn't the same as the DLT_ATM_RFC1483 encapsulation - * presumably used on some BSD systems, which we turn into - * WTAP_ENCAP_ATM_RFC1483. - * - * WTAP_ENCAP_NULL corresponds to DLT_NULL from "libpcap". This - * corresponds to - * - * 1) PPP-over-HDLC encapsulation, at least with some versions - * of ISDN4BSD (but not the current ones, it appears, unless - * I've missed something); - * - * 2) a 4-byte header containing the AF_ address family, in - * the byte order of the machine that saved the capture, - * for the packet, as used on many BSD systems for the - * loopback device and some other devices, or a 4-byte header - * containing the AF_ address family in network byte order, - * as used on recent OpenBSD systems for the loopback device; - * - * 3) a 4-byte header containing 2 octets of 0 and an Ethernet - * type in the byte order from an Ethernet header, that being - * what older versions of "libpcap" on Linux turn the Ethernet - * header for loopback interfaces into (0.6.0 and later versions - * leave the Ethernet header alone and make it DLT_EN10MB). */ -#define WTAP_ENCAP_PER_PACKET -1 -#define WTAP_ENCAP_UNKNOWN 0 -#define WTAP_ENCAP_ETHERNET 1 -#define WTAP_ENCAP_TOKEN_RING 2 -#define WTAP_ENCAP_SLIP 3 -#define WTAP_ENCAP_PPP 4 -#define WTAP_ENCAP_FDDI 5 -#define WTAP_ENCAP_FDDI_BITSWAPPED 6 -#define WTAP_ENCAP_RAW_IP 7 -#define WTAP_ENCAP_ARCNET 8 -#define WTAP_ENCAP_ARCNET_LINUX 9 -#define WTAP_ENCAP_ATM_RFC1483 10 -#define WTAP_ENCAP_LINUX_ATM_CLIP 11 -#define WTAP_ENCAP_LAPB 12 -#define WTAP_ENCAP_ATM_PDUS 13 -#define WTAP_ENCAP_ATM_PDUS_UNTRUNCATED 14 -#define WTAP_ENCAP_NULL 15 -#define WTAP_ENCAP_ASCEND 16 -#define WTAP_ENCAP_ISDN 17 -#define WTAP_ENCAP_IP_OVER_FC 18 -#define WTAP_ENCAP_PPP_WITH_PHDR 19 -#define WTAP_ENCAP_IEEE_802_11 20 -#define WTAP_ENCAP_PRISM_HEADER 21 -#define WTAP_ENCAP_IEEE_802_11_WITH_RADIO 22 -#define WTAP_ENCAP_IEEE_802_11_WLAN_RADIOTAP 23 -#define WTAP_ENCAP_IEEE_802_11_WLAN_AVS 24 -#define WTAP_ENCAP_SLL 25 -#define WTAP_ENCAP_FRELAY 26 -#define WTAP_ENCAP_FRELAY_WITH_PHDR 27 -#define WTAP_ENCAP_CHDLC 28 -#define WTAP_ENCAP_CISCO_IOS 29 -#define WTAP_ENCAP_LOCALTALK 30 -#define WTAP_ENCAP_OLD_PFLOG 31 -#define WTAP_ENCAP_HHDLC 32 -#define WTAP_ENCAP_DOCSIS 33 -#define WTAP_ENCAP_COSINE 34 -#define WTAP_ENCAP_WFLEET_HDLC 35 -#define WTAP_ENCAP_SDLC 36 -#define WTAP_ENCAP_TZSP 37 -#define WTAP_ENCAP_ENC 38 -#define WTAP_ENCAP_PFLOG 39 -#define WTAP_ENCAP_CHDLC_WITH_PHDR 40 -#define WTAP_ENCAP_BLUETOOTH_H4 41 -#define WTAP_ENCAP_MTP2 42 -#define WTAP_ENCAP_MTP3 43 -#define WTAP_ENCAP_IRDA 44 -#define WTAP_ENCAP_USER0 45 -#define WTAP_ENCAP_USER1 46 -#define WTAP_ENCAP_USER2 47 -#define WTAP_ENCAP_USER3 48 -#define WTAP_ENCAP_USER4 49 -#define WTAP_ENCAP_USER5 50 -#define WTAP_ENCAP_USER6 51 -#define WTAP_ENCAP_USER7 52 -#define WTAP_ENCAP_USER8 53 -#define WTAP_ENCAP_USER9 54 -#define WTAP_ENCAP_USER10 55 -#define WTAP_ENCAP_USER11 56 -#define WTAP_ENCAP_USER12 57 -#define WTAP_ENCAP_USER13 58 -#define WTAP_ENCAP_USER14 59 -#define WTAP_ENCAP_USER15 60 -#define WTAP_ENCAP_SYMANTEC 61 -#define WTAP_ENCAP_APPLE_IP_OVER_IEEE1394 62 -#define WTAP_ENCAP_BACNET_MS_TP 63 -#define WTAP_ENCAP_NETTL_RAW_ICMP 64 -#define WTAP_ENCAP_NETTL_RAW_ICMPV6 65 -#define WTAP_ENCAP_GPRS_LLC 66 -#define WTAP_ENCAP_JUNIPER_ATM1 67 -#define WTAP_ENCAP_JUNIPER_ATM2 68 -#define WTAP_ENCAP_REDBACK 69 -#define WTAP_ENCAP_NETTL_RAW_IP 70 -#define WTAP_ENCAP_NETTL_ETHERNET 71 -#define WTAP_ENCAP_NETTL_TOKEN_RING 72 -#define WTAP_ENCAP_NETTL_FDDI 73 -#define WTAP_ENCAP_NETTL_UNKNOWN 74 -#define WTAP_ENCAP_MTP2_WITH_PHDR 75 -#define WTAP_ENCAP_JUNIPER_PPPOE 76 -#define WTAP_GCOM_TIE1 77 -#define WTAP_GCOM_SERIAL 78 -#define WTAP_ENCAP_NETTL_X25 79 -#define WTAP_ENCAP_K12 80 -#define WTAP_ENCAP_JUNIPER_MLPPP 81 -#define WTAP_ENCAP_JUNIPER_MLFR 82 -#define WTAP_ENCAP_JUNIPER_ETHER 83 -#define WTAP_ENCAP_JUNIPER_PPP 84 -#define WTAP_ENCAP_JUNIPER_FRELAY 85 -#define WTAP_ENCAP_JUNIPER_CHDLC 86 -#define WTAP_ENCAP_JUNIPER_GGSN 87 -#define WTAP_ENCAP_LINUX_LAPD 88 -#define WTAP_ENCAP_CATAPULT_DCT2000 89 -#define WTAP_ENCAP_BER 90 -#define WTAP_ENCAP_JUNIPER_VP 91 -#define WTAP_ENCAP_USB 92 -#define WTAP_ENCAP_IEEE802_16_MAC_CPS 93 -#define WTAP_ENCAP_NETTL_RAW_TELNET 94 -#define WTAP_ENCAP_USB_LINUX 95 -#define WTAP_ENCAP_MPEG 96 -#define WTAP_ENCAP_PPI 97 -#define WTAP_ENCAP_ERF 98 -#define WTAP_ENCAP_BLUETOOTH_H4_WITH_PHDR 99 -#define WTAP_ENCAP_SITA 100 -#define WTAP_ENCAP_SCCP 101 -#define WTAP_ENCAP_BLUETOOTH_HCI 102 /*raw packets without a transport layer header e.g. H4*/ -#define WTAP_ENCAP_IPMB 103 -#define WTAP_ENCAP_IEEE802_15_4 104 -#define WTAP_ENCAP_X2E_XORAYA 105 -#define WTAP_ENCAP_FLEXRAY 106 -#define WTAP_ENCAP_LIN 107 -#define WTAP_ENCAP_MOST 108 -#define WTAP_ENCAP_CAN20B 109 - -#define WTAP_NUM_ENCAP_TYPES wtap_get_num_encap_types() - -/* File types that can be read by wiretap. - We support writing some many of these file types, too, so we - distinguish between different versions of them. */ -#define WTAP_FILE_UNKNOWN 0 -#define WTAP_FILE_WTAP 1 -#define WTAP_FILE_PCAP 2 -#define WTAP_FILE_PCAP_NSEC 3 -#define WTAP_FILE_PCAP_AIX 4 -#define WTAP_FILE_PCAP_SS991029 5 -#define WTAP_FILE_PCAP_NOKIA 6 -#define WTAP_FILE_PCAP_SS990417 7 -#define WTAP_FILE_PCAP_SS990915 8 -#define WTAP_FILE_5VIEWS 9 -#define WTAP_FILE_IPTRACE_1_0 10 -#define WTAP_FILE_IPTRACE_2_0 11 -#define WTAP_FILE_BER 12 -#define WTAP_FILE_HCIDUMP 13 -#define WTAP_FILE_CATAPULT_DCT2000 14 -#define WTAP_FILE_NETXRAY_OLD 15 -#define WTAP_FILE_NETXRAY_1_0 16 -#define WTAP_FILE_COSINE 17 -#define WTAP_FILE_CSIDS 18 -#define WTAP_FILE_DBS_ETHERWATCH 19 -#define WTAP_FILE_ERF 20 -#define WTAP_FILE_EYESDN 21 -#define WTAP_FILE_NETTL 22 -#define WTAP_FILE_ISERIES 23 -#define WTAP_FILE_ISERIES_UNICODE 24 -#define WTAP_FILE_I4BTRACE 25 -#define WTAP_FILE_ASCEND 26 -#define WTAP_FILE_NETMON_1_x 27 -#define WTAP_FILE_NETMON_2_x 28 -#define WTAP_FILE_NGSNIFFER_UNCOMPRESSED 29 -#define WTAP_FILE_NGSNIFFER_COMPRESSED 30 -#define WTAP_FILE_NETXRAY_1_1 31 -#define WTAP_FILE_NETXRAY_2_00x 32 -#define WTAP_FILE_NETWORK_INSTRUMENTS_V9 33 -#define WTAP_FILE_LANALYZER 34 -#define WTAP_FILE_PPPDUMP 35 -#define WTAP_FILE_RADCOM 36 -#define WTAP_FILE_SNOOP 37 -#define WTAP_FILE_SHOMITI 38 -#define WTAP_FILE_VMS 39 -#define WTAP_FILE_K12 40 -#define WTAP_FILE_TOSHIBA 41 -#define WTAP_FILE_VISUAL_NETWORKS 42 -#define WTAP_FILE_ETHERPEEK_V56 43 -#define WTAP_FILE_ETHERPEEK_V7 44 -#define WTAP_FILE_AIROPEEK_V9 45 -#define WTAP_FILE_MPEG 46 -#define WTAP_FILE_K12TEXT 47 -#define WTAP_FILE_NETSCREEN 48 -#define WTAP_FILE_COMMVIEW 49 -#define WTAP_FILE_PCAPNG 50 -#define WTAP_FILE_BTSNOOP 51 -#define WTAP_FILE_X2E_XORAYA 52 - -#define WTAP_NUM_FILE_TYPES wtap_get_num_file_types() - -/* timestamp precision (currently only these values are supported) */ -#define WTAP_FILE_TSPREC_SEC 0 -#define WTAP_FILE_TSPREC_DSEC 1 -#define WTAP_FILE_TSPREC_CSEC 2 -#define WTAP_FILE_TSPREC_MSEC 3 -#define WTAP_FILE_TSPREC_USEC 6 -#define WTAP_FILE_TSPREC_NSEC 9 - -/* - * Maximum packet size we'll support. - * It must be at least 65535. - */ -#define WTAP_MAX_PACKET_SIZE 65535 - -/* - * "Pseudo-headers" are used to supply to the clients of wiretap - * per-packet information that's not part of the packet payload - * proper. - * - * NOTE: do not use pseudo-header structures to hold information - * used by the code to read a particular capture file type; to - * keep that sort of state information, add a new structure for - * that private information to "wtap-int.h", add a pointer to that - * type of structure to the "capture" member of the "struct wtap" - * structure, and allocate one of those structures and set that member - * in the "open" routine for that capture file type if the open - * succeeds. See various other capture file type handlers for examples - * of that. - */ - -/* Packet "pseudo-header" information for Ethernet capture files. */ -struct eth_phdr { - gint fcs_len; /* Number of bytes of FCS - -1 means "unknown" */ -}; - -/* Packet "pseudo-header" information for X.25 capture files. */ -#define FROM_DCE 0x80 -struct x25_phdr { - guint8 flags; /* ENCAP_LAPB, ENCAP_V120 : 1st bit means From DCE */ -}; - -/* Packet "pseudo-header" information for ISDN capture files. */ - -/* Direction */ -struct isdn_phdr { - gboolean uton; - guint8 channel; /* 0 = D-channel; n = B-channel n */ -}; - -/* Packet "pseudo-header" for ATM capture files. - Not all of this information is supplied by all capture types. */ - -/* - * Status bits. - */ -#define ATM_RAW_CELL 0x01 /* TRUE if the packet is a single cell */ - -/* - * AAL types. - */ -#define AAL_UNKNOWN 0 /* AAL unknown */ -#define AAL_1 1 /* AAL1 */ -#define AAL_2 2 /* AAL2 */ -#define AAL_3_4 3 /* AAL3/4 */ -#define AAL_5 4 /* AAL5 */ -#define AAL_USER 5 /* User AAL */ -#define AAL_SIGNALLING 6 /* Signaling AAL */ -#define AAL_OAMCELL 7 /* OAM cell */ - -/* - * Traffic types. - */ -#define TRAF_UNKNOWN 0 /* Unknown */ -#define TRAF_LLCMX 1 /* LLC multiplexed (RFC 1483) */ -#define TRAF_VCMX 2 /* VC multiplexed (RFC 1483) */ -#define TRAF_LANE 3 /* LAN Emulation */ -#define TRAF_ILMI 4 /* ILMI */ -#define TRAF_FR 5 /* Frame Relay */ -#define TRAF_SPANS 6 /* FORE SPANS */ -#define TRAF_IPSILON 7 /* Ipsilon */ -#define TRAF_UMTS_FP 8 /* UMTS Frame Protocol */ - -/* - * Traffic subtypes. - */ -#define TRAF_ST_UNKNOWN 0 /* Unknown */ - -/* - * For TRAF_VCMX: - */ -#define TRAF_ST_VCMX_802_3_FCS 1 /* 802.3 with an FCS */ -#define TRAF_ST_VCMX_802_4_FCS 2 /* 802.4 with an FCS */ -#define TRAF_ST_VCMX_802_5_FCS 3 /* 802.5 with an FCS */ -#define TRAF_ST_VCMX_FDDI_FCS 4 /* FDDI with an FCS */ -#define TRAF_ST_VCMX_802_6_FCS 5 /* 802.6 with an FCS */ -#define TRAF_ST_VCMX_802_3 7 /* 802.3 without an FCS */ -#define TRAF_ST_VCMX_802_4 8 /* 802.4 without an FCS */ -#define TRAF_ST_VCMX_802_5 9 /* 802.5 without an FCS */ -#define TRAF_ST_VCMX_FDDI 10 /* FDDI without an FCS */ -#define TRAF_ST_VCMX_802_6 11 /* 802.6 without an FCS */ -#define TRAF_ST_VCMX_FRAGMENTS 12 /* Fragments */ -#define TRAF_ST_VCMX_BPDU 13 /* BPDU */ - -/* - * For TRAF_LANE: - */ -#define TRAF_ST_LANE_LE_CTRL 1 /* LANE: LE Ctrl */ -#define TRAF_ST_LANE_802_3 2 /* LANE: 802.3 */ -#define TRAF_ST_LANE_802_5 3 /* LANE: 802.5 */ -#define TRAF_ST_LANE_802_3_MC 4 /* LANE: 802.3 multicast */ -#define TRAF_ST_LANE_802_5_MC 5 /* LANE: 802.5 multicast */ - -/* - * For TRAF_IPSILON: - */ -#define TRAF_ST_IPSILON_FT0 1 /* Ipsilon: Flow Type 0 */ -#define TRAF_ST_IPSILON_FT1 2 /* Ipsilon: Flow Type 1 */ -#define TRAF_ST_IPSILON_FT2 3 /* Ipsilon: Flow Type 2 */ - -struct atm_phdr { - guint32 flags; /* status flags */ - guint8 aal; /* AAL of the traffic */ - guint8 type; /* traffic type */ - guint8 subtype; /* traffic subtype */ - guint16 vpi; /* virtual path identifier */ - guint16 vci; /* virtual circuit identifier */ - guint8 aal2_cid; /* channel id */ - guint16 channel; /* link: 0 for DTE->DCE, 1 for DCE->DTE */ - guint16 cells; /* number of cells */ - guint16 aal5t_u2u; /* user-to-user indicator */ - guint16 aal5t_len; /* length of the packet */ - guint32 aal5t_chksum; /* checksum for AAL5 packet */ -}; - -/* Packet "pseudo-header" for the output from "wandsession", "wannext", - "wandisplay", and similar commands on Lucent/Ascend access equipment. */ - -#define ASCEND_MAX_STR_LEN 64 - -#define ASCEND_PFX_WDS_X 1 -#define ASCEND_PFX_WDS_R 2 -#define ASCEND_PFX_WDD 3 -#define ASCEND_PFX_ISDN_X 4 -#define ASCEND_PFX_ISDN_R 5 -#define ASCEND_PFX_ETHER 6 - -struct ascend_phdr { - guint16 type; /* ASCEND_PFX_*, as defined above */ - char user[ASCEND_MAX_STR_LEN]; /* Username, from wandsession header */ - guint32 sess; /* Session number, from wandsession header */ - char call_num[ASCEND_MAX_STR_LEN]; /* Called number, from WDD header */ - guint32 chunk; /* Chunk number, from WDD header */ - guint32 task; /* Task number */ -}; - -/* Packet "pseudo-header" for point-to-point links with direction flags. */ -struct p2p_phdr { - gboolean sent; /* TRUE=sent, FALSE=received */ -}; - -/* - * Packet "pseudo-header" information for 802.11. - * Radio information is only present for WTAP_ENCAP_IEEE_802_11_WITH_RADIO. - * - * Signal strength, etc. information: - * - * Raw signal strength can be measured in milliwatts. - * It can also be represented as dBm, which is 10 times the log base 10 - * of the signal strength in mW. - * - * The Receive Signal Strength Indicator is an integer in the range 0 to 255. - * The actual RSSI value for a given signal strength is dependent on the - * vendor (and perhaps on the adapter). The maximum possible RSSI value - * is also dependent on the vendor and perhaps the adapter. - * - * The signal strength can be represented as a percentage, which is 100 - * times the ratio of the RSSI and the maximum RSSI. - */ -struct ieee_802_11_phdr { - gint fcs_len; /* Number of bytes of FCS - -1 means "unknown" */ - guint8 channel; /* Channel number */ - guint8 data_rate; /* in .5 Mb/s units */ - guint8 signal_level; /* percentage */ -}; - -/* Packet "pseudo-header" for the output from CoSine L2 debug output. */ - -#define COSINE_MAX_IF_NAME_LEN 128 - -#define COSINE_ENCAP_TEST 1 -#define COSINE_ENCAP_PPoATM 2 -#define COSINE_ENCAP_PPoFR 3 -#define COSINE_ENCAP_ATM 4 -#define COSINE_ENCAP_FR 5 -#define COSINE_ENCAP_HDLC 6 -#define COSINE_ENCAP_PPP 7 -#define COSINE_ENCAP_ETH 8 -#define COSINE_ENCAP_UNKNOWN 99 - -#define COSINE_DIR_TX 1 -#define COSINE_DIR_RX 2 - -struct cosine_phdr { - guint8 encap; /* COSINE_ENCAP_* as defined above */ - guint8 direction; /* COSINE_DIR_*, as defined above */ - char if_name[COSINE_MAX_IF_NAME_LEN]; /* Encap & Logical I/F name */ - guint16 pro; /* Protocol */ - guint16 off; /* Offset */ - guint16 pri; /* Priority */ - guint16 rm; /* Rate Marking */ - guint16 err; /* Error Code */ -}; - -/* Packet "pseudo-header" for IrDA capture files. */ - -/* - * Direction of the packet - */ -#define IRDA_INCOMING 0x0000 -#define IRDA_OUTGOING 0x0004 - -/* - * "Inline" log messages produced by IrCOMM2k on Windows - */ -#define IRDA_LOG_MESSAGE 0x0100 /* log message */ -#define IRDA_MISSED_MSG 0x0101 /* missed log entry or frame */ - -/* - * Differentiate between frames and log messages - */ -#define IRDA_CLASS_FRAME 0x0000 -#define IRDA_CLASS_LOG 0x0100 -#define IRDA_CLASS_MASK 0xFF00 - -struct irda_phdr { - guint16 pkttype; /* packet type */ -}; - -/* Packet "pseudo-header" for nettl (HP-UX) capture files. */ - -struct nettl_phdr { - guint16 subsys; - guint32 devid; - guint32 kind; - gint32 pid; - guint16 uid; -}; - -/* Packet "pseudo-header" for MTP2 files. */ - -#define MTP2_ANNEX_A_NOT_USED 0 -#define MTP2_ANNEX_A_USED 1 -#define MTP2_ANNEX_A_USED_UNKNOWN 2 - -struct mtp2_phdr { - guint8 sent; - guint8 annex_a_used; - guint16 link_number; -}; - -/* Packet "pseudo-header" for K12 files. */ - -typedef union { - struct { - guint16 vp; - guint16 vc; - guint16 cid; - } atm; - - guint32 ds0mask; -} k12_input_info_t; - -struct k12_phdr { - guint32 input; - const gchar* input_name; - const gchar* stack_file; - guint32 input_type; - k12_input_info_t input_info; - gchar* extra_info; - guint32 extra_length; - void* stuff; -}; - -#define K12_PORT_DS0S 0x00010008 -#define K12_PORT_DS1 0x00100008 -#define K12_PORT_ATMPVC 0x01020000 - -struct lapd_phdr { - guint16 pkttype; /* packet type */ - guint8 we_network; -}; - -struct wtap; -struct catapult_dct2000_phdr -{ - union - { - struct isdn_phdr isdn; - struct atm_phdr atm; - struct p2p_phdr p2p; - } inner_pseudo_header; - gint64 seek_off; - struct wtap *wth; -}; - -/* - * possible event type - */ -#define URB_SUBMIT 'S' -#define URB_COMPLETE 'C' -#define URB_ERROR 'E' - -/* - * possible transfer mode - */ -#define URB_ISOCHRONOUS 0x0 -#define URB_INTERRUPT 0x1 -#define URB_CONTROL 0x2 -#define URB_BULK 0x3 - -#define URB_TRANSFER_IN 0x80 /* to host */ - -/* - * USB setup header as defined in USB specification - */ -struct usb_request_hdr { - gint8 bmRequestType; - guint8 bRequest; - guint16 wValue; - guint16 wIndex; - guint16 wLength; -}; - -/* - * Header prepended by Linux kernel to each USB event. - * Followed by a struct usb_request_hdr, although that header is valid - * only if setup_flag is 0. - * (Setup flag is '-', 'D', 'Z', or 0. Data flag is '<', '>', 'Z', or 0.) - * - * We present this as a pseudo-header; the values are in host byte order. - */ -struct linux_usb_phdr { - guint64 id; /* urb id, to link submission and completion events*/ - guint8 event_type; /* Submit ('S'), Completed ('C'), Error ('E') */ - guint8 transfer_type; /* ISO (0), Intr, Control, Bulk (3) */ - guint8 endpoint_number; /* Endpoint number (0-15) and transfer direction */ - guint8 device_address; /* 0-127 */ - guint16 bus_id; - gint8 setup_flag; /*if !=0 the urb setup header is not present*/ - gint8 data_flag; /*if !=0 no urb data is present*/ - gint64 ts_sec; - gint32 ts_usec; - gint32 status; - guint32 urb_len; /* whole len of urb this event refers to */ - guint32 data_len; /* amount of urb data really present in this event*/ -}; - -/* - * Header prepended by libpcap to each bluetooth hci h:4 frame. - * Values in network byte order - */ -struct libpcap_bt_phdr { - guint32 direction; /* Bit 0 hold the frame direction. */ -}; - -/* - * Endace Record Format pseudo header - */ -struct erf_phdr { - guint64 ts; /* Time stamp */ - guint8 type; - guint8 flags; - guint16 rlen; - guint16 lctr; - guint16 wlen; -}; - -/* - * ERF pseudo header with optional subheader - * (Multichannel or Ethernet) - */ -struct erf_mc_phdr { - struct erf_phdr phdr; - union - { - guint16 eth_hdr; - guint32 mc_hdr; - } subhdr; -}; - -#define SITA_FRAME_DIR_TXED (0x00) /* values of sita_phdr.flags */ -#define SITA_FRAME_DIR_RXED (0x01) -#define SITA_FRAME_DIR (0x01) /* mask */ -#define SITA_ERROR_NO_BUFFER (0x80) - -#define SITA_SIG_DSR (0x01) /* values of sita_phdr.signals */ -#define SITA_SIG_DTR (0x02) -#define SITA_SIG_CTS (0x04) -#define SITA_SIG_RTS (0x08) -#define SITA_SIG_DCD (0x10) -#define SITA_SIG_UNDEF1 (0x20) -#define SITA_SIG_UNDEF2 (0x40) -#define SITA_SIG_UNDEF3 (0x80) - -#define SITA_ERROR_TX_UNDERRUN (0x01) /* values of sita_phdr.errors2 (if SITA_FRAME_DIR_TXED) */ -#define SITA_ERROR_TX_CTS_LOST (0x02) -#define SITA_ERROR_TX_UART_ERROR (0x04) -#define SITA_ERROR_TX_RETX_LIMIT (0x08) -#define SITA_ERROR_TX_UNDEF1 (0x10) -#define SITA_ERROR_TX_UNDEF2 (0x20) -#define SITA_ERROR_TX_UNDEF3 (0x40) -#define SITA_ERROR_TX_UNDEF4 (0x80) - -#define SITA_ERROR_RX_FRAMING (0x01) /* values of sita_phdr.errors1 (if SITA_FRAME_DIR_RXED) */ -#define SITA_ERROR_RX_PARITY (0x02) -#define SITA_ERROR_RX_COLLISION (0x04) -#define SITA_ERROR_RX_FRAME_LONG (0x08) -#define SITA_ERROR_RX_FRAME_SHORT (0x10) -#define SITA_ERROR_RX_UNDEF1 (0x20) -#define SITA_ERROR_RX_UNDEF2 (0x40) -#define SITA_ERROR_RX_UNDEF3 (0x80) - -#define SITA_ERROR_RX_NONOCTET_ALIGNED (0x01) /* values of sita_phdr.errors2 (if SITA_FRAME_DIR_RXED) */ -#define SITA_ERROR_RX_ABORT (0x02) -#define SITA_ERROR_RX_CD_LOST (0x04) -#define SITA_ERROR_RX_DPLL (0x08) -#define SITA_ERROR_RX_OVERRUN (0x10) -#define SITA_ERROR_RX_FRAME_LEN_VIOL (0x20) -#define SITA_ERROR_RX_CRC (0x40) -#define SITA_ERROR_RX_BREAK (0x80) - -#define SITA_PROTO_UNUSED (0x00) /* values of sita_phdr.proto */ -#define SITA_PROTO_BOP_LAPB (0x01) -#define SITA_PROTO_ETHERNET (0x02) -#define SITA_PROTO_ASYNC_INTIO (0x03) -#define SITA_PROTO_ASYNC_BLKIO (0x04) -#define SITA_PROTO_ALC (0x05) -#define SITA_PROTO_UTS (0x06) -#define SITA_PROTO_PPP_HDLC (0x07) -#define SITA_PROTO_SDLC (0x08) -#define SITA_PROTO_TOKENRING (0x09) -#define SITA_PROTO_I2C (0x10) -#define SITA_PROTO_DPM_LINK (0x11) -#define SITA_PROTO_BOP_FRL (0x12) - -struct sita_phdr { - guint8 flags; - guint8 signals; - guint8 errors1; - guint8 errors2; - guint8 proto; -}; - -/*pseudo header for Bluetooth HCI*/ -struct bthci_phdr { - gboolean sent; - guint8 channel; -}; - -#define BTHCI_CHANNEL_COMMAND 1 -#define BTHCI_CHANNEL_ACL 2 -#define BTHCI_CHANNEL_SCO 3 -#define BTHCI_CHANNEL_EVENT 4 - -union wtap_pseudo_header { - struct eth_phdr eth; - struct x25_phdr x25; - struct isdn_phdr isdn; - struct atm_phdr atm; - struct ascend_phdr ascend; - struct p2p_phdr p2p; - struct ieee_802_11_phdr ieee_802_11; - struct cosine_phdr cosine; - struct irda_phdr irda; - struct nettl_phdr nettl; - struct mtp2_phdr mtp2; - struct k12_phdr k12; - struct lapd_phdr lapd; - struct catapult_dct2000_phdr dct2000; - struct linux_usb_phdr linux_usb; - struct erf_mc_phdr erf; - struct sita_phdr sita; - struct bthci_phdr bthci; -}; - -struct wtap_nstime { - time_t secs; - int nsecs; -}; - -struct wtap_pkthdr { - struct wtap_nstime ts; - guint32 caplen; - guint32 len; - int pkt_encap; -}; - -struct wtap; -struct Buffer; -struct wtap_dumper; - -typedef struct wtap wtap; -typedef struct wtap_dumper wtap_dumper; - -struct file_type_info { - /* the file type name */ - /* should be NULL for all "pseudo" types that are only internally used and not read/writeable */ - const char *name; - - /* the file type short name, used as a shortcut for the command line tools */ - /* should be NULL for all "pseudo" types that are only internally used and not read/writeable */ - const char *short_name; - - /* the common file extensions for this type (seperated by semicolon) */ - /* should be *.* if no common extension is applicable */ - const char *file_extensions; - - /* the default file extension, used to save this type */ - /* should be NULL if no default extension is known */ - const char *file_extension_default; - - /* can this type be compressed with gzip? */ - gboolean can_compress; - - /* can this type write this encapsulation format? */ - /* should be NULL is this file type don't have write support */ - int (*can_write_encap)(int); - - /* the function to open the capture file for writing */ - /* should be NULL is this file type don't have write support */ - int (*dump_open)(wtap_dumper *, gboolean, int *); -}; - - -typedef int (*wtap_open_routine_t)(struct wtap*, int *, char **); - - -/* - * On failure, "wtap_open_offline()" returns NULL, and puts into the - * "int" pointed to by its second argument: - * - * a positive "errno" value if the capture file can't be opened; - * a negative number, indicating the type of error, on other failures. - */ -struct wtap* wtap_open_offline(const char *filename, int *err, - gchar **err_info, gboolean do_random); - -/* Returns TRUE if read was successful. FALSE if failure. data_offset is - * set to the offset in the file where the data for the read packet is - * located. */ -gboolean wtap_read(wtap *wth, int *err, gchar **err_info, - gint64 *data_offset); - -gboolean wtap_seek_read (wtap *wth, gint64 seek_off, - union wtap_pseudo_header *pseudo_header, guint8 *pd, int len, - int *err, gchar **err_info); - -/*** get various information snippets about the current packet ***/ -struct wtap_pkthdr *wtap_phdr(wtap *wth); -union wtap_pseudo_header *wtap_pseudoheader(wtap *wth); -guint8 *wtap_buf_ptr(wtap *wth); - -/*** get various information snippets about the current file ***/ - -/* Return an approximation of the amount of data we've read sequentially - * from the file so far. */ -gint64 wtap_read_so_far(wtap *wth, int *err); -gint64 wtap_file_size(wtap *wth, int *err); -int wtap_snapshot_length(wtap *wth); /* per file */ -int wtap_file_type(wtap *wth); -int wtap_file_encap(wtap *wth); -int wtap_file_tsprecision(wtap *wth); - -/*** close the current file ***/ -void wtap_sequential_close(wtap *wth); -void wtap_close(wtap *wth); - -/*** dump packets into a capture file ***/ -gboolean wtap_dump_can_open(int filetype); -gboolean wtap_dump_can_write_encap(int filetype, int encap); -gboolean wtap_dump_can_compress(int filetype); -wtap_dumper* wtap_dump_open(const char *filename, int filetype, int encap, - int snaplen, gboolean compressed, int *err); -wtap_dumper* wtap_dump_fdopen(int fd, int filetype, int encap, int snaplen, - gboolean compressed, int *err); -gboolean wtap_dump(wtap_dumper *, const struct wtap_pkthdr *, - const union wtap_pseudo_header *pseudo_header, const guchar *, int *err); -void wtap_dump_flush(wtap_dumper *); -gint64 wtap_get_bytes_dumped(wtap_dumper *); -void wtap_set_bytes_dumped(wtap_dumper *wdh, gint64 bytes_dumped); -gboolean wtap_dump_close(wtap_dumper *, int *); - -/*** various string converter functions ***/ -const char *wtap_file_type_string(int filetype); -const char *wtap_file_type_short_string(int filetype); -int wtap_short_string_to_file_type(const char *short_name); - -const char *wtap_file_extensions_string(int filetype); -const char *wtap_file_extension_default_string(int filetype); - -const char *wtap_encap_string(int encap); -const char *wtap_encap_short_string(int encap); -int wtap_short_string_to_encap(const char *short_name); - -const char *wtap_strerror(int err); - -/*** get available number of file types and encapsulations ***/ -int wtap_get_num_encap_types(void); -int wtap_get_num_file_types(void); - -/*** dynamically register new file types and encapsulations ***/ -void wtap_register_open_routine(wtap_open_routine_t, gboolean has_magic); -int wtap_register_file_type(const struct file_type_info* fi); -int wtap_register_encap_type(char* name, char* short_name); - - -/* - * Wiretap error codes. - */ -#define WTAP_ERR_NOT_REGULAR_FILE -1 - /* The file being opened for reading isn't a plain file (or pipe) */ -#define WTAP_ERR_RANDOM_OPEN_PIPE -2 - /* The file is being opened for random access and it's a pipe */ -#define WTAP_ERR_FILE_UNKNOWN_FORMAT -3 - /* The file being opened is not a capture file in a known format */ -#define WTAP_ERR_UNSUPPORTED -4 - /* Supported file type, but there's something in the file we - can't support */ -#define WTAP_ERR_CANT_WRITE_TO_PIPE -5 - /* Wiretap can't save to a pipe in the specified format */ -#define WTAP_ERR_CANT_OPEN -6 - /* The file couldn't be opened, reason unknown */ -#define WTAP_ERR_UNSUPPORTED_FILE_TYPE -7 - /* Wiretap can't save files in the specified format */ -#define WTAP_ERR_UNSUPPORTED_ENCAP -8 - /* Wiretap can't read or save files in the specified format with the - specified encapsulation */ -#define WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED -9 - /* The specified format doesn't support per-packet encapsulations */ -#define WTAP_ERR_CANT_CLOSE -10 - /* The file couldn't be closed, reason unknown */ -#define WTAP_ERR_CANT_READ -11 - /* An attempt to read failed, reason unknown */ -#define WTAP_ERR_SHORT_READ -12 - /* An attempt to read read less data than it should have */ -#define WTAP_ERR_BAD_RECORD -13 - /* We read an invalid record */ -#define WTAP_ERR_SHORT_WRITE -14 - /* An attempt to write wrote less data than it should have */ -#define WTAP_ERR_UNC_TRUNCATED -15 - /* Sniffer compressed data was oddly truncated */ -#define WTAP_ERR_UNC_OVERFLOW -16 - /* Uncompressing Sniffer data would overflow buffer */ -#define WTAP_ERR_UNC_BAD_OFFSET -17 - /* LZ77 compressed data has bad offset to string */ -#define WTAP_ERR_RANDOM_OPEN_STDIN -18 - /* We're trying to open the standard input for random access */ -#define WTAP_ERR_COMPRESSION_NOT_SUPPORTED -19 - /* The filetype doesn't support output compression */ - -/* Errors from zlib; zlib error Z_xxx turns into Wiretap error - WTAP_ERR_ZLIB + Z_xxx. - - WTAP_ERR_ZLIB_MIN and WTAP_ERR_ZLIB_MAX bound the range of zlib - errors; we leave room for 100 positive and 100 negative error - codes. */ - -#define WTAP_ERR_ZLIB -200 -#define WTAP_ERR_ZLIB_MAX -100 -#define WTAP_ERR_ZLIB_MIN -300 - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __WTAP_H__ */

$&E^HbQ3hZ=r8pgOkzLWcDgVWLp^|4ELi^ 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 literal 0 HcmV?d00001 From fd641bbe11e8985089d122087e70b4e9dd8b8493 Mon Sep 17 00:00:00 2001 From: J980419xq <1908393204@qq.com> Date: Wed, 27 Apr 2022 00:45:03 -0700 Subject: [PATCH 09/44] md --- docker.md | 209 +++++++++++++++++++++++++++++++++++++++++++++++++++ ovs_image.md | 157 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 366 insertions(+) create mode 100644 docker.md create mode 100644 ovs_image.md diff --git a/docker.md b/docker.md new file mode 100644 index 00000000..96a2a23e --- /dev/null +++ b/docker.md @@ -0,0 +1,209 @@ + +This document is the development and testing document for `issue25:Investigate the possibility of replacing lxc/lxd with docker` . + +* Figure out the detail steps to replace lxc/lxd engine with docker engine. + > The replacement process can be divided into two steps + > * Change the environment of lxd in the master and workers to docker + > * Change the deployment and configuration commands of the lxd container in the master and workers to the commands with the same function under docker + +* Study files under Distrinet/mininet/provision folder. + > Distrinet provides an infrastructure provisioning mechanism that uses Ansible to automatically install and configure LXD on each machine to be used during the experiment. + >In order not to detract from Distrinet's overall architecture. We did not change the filename of the relevant file, only the implementation details. + > * install-lxd.yml:this file is used to install lxd and download two images(an Ubuntu:18.04 image to emulate the vHosts, and a modified version of that image with OVS installed)on each machine by Ansible,we change it to install docker,and these two images need to be remade according to Docker,the OVS process will be described in the ovs_image.md. + > * configure-lxd-no-clustering.yml:this file is used to configure lxd init,but you don't neet to do it in docker,so we only use it to distribute and load the above two images. + + >We have not modified the other files in this folder. If you really want to use Docker instead of LXD, you will still need to modify the yml files in other installation environments based on these two files. + +* Create related files (config, deploy, install, etc) for docker provision by referring lxd scenario + >Reading through all the code in the LXD scenario, we can see that the creation and configuration of containers and the creation of network interfaces and links are mainly concentrated in lxc_cotainer.py and distrinet.py,We need to replace the code that uses LXC/LXD with a docker equivalent command + + >As for the network interfaces and links,we'll discuss this in more detail in issue33,In addition,for container creation and configuration, you can keep an eye out for lXC_container.py changes.The most critical one is that we use a pair of virtual devices veth pair and a bridge to replace lXC network attach command.Besides,We use namespaces to attach one end of veth pair to the container. + + >We don't change the lxc_container.py's name,because this file is referenced several times in the project.You can modify it yourself if you really need to. + +* The Distrinet environment replaced by docker includes the three following entities + * Client: host in which the Distrinet script is running and decides where to place the vNodes around the physical infrastructure (round-robin by default). The Client must be able to connect via SSH to the Master host. + * Master: host that acts as a relay to interconnect the Client with all the Worker hosts. It communicates with the Client and the different Workers via SSH. Note that the Master can also be configured as a Worker. + * Worker(s): host(s) where all the vNodes (vSwitches and vHosts) are running. vNodes are managed by the Master and the Client, via the admin network. + > To ensure the smooth deployment of vNodes, Ip forwarding needs to be allowed on workers and the netns of the container needs to be restored to the host directory,here are a few commands that you might configure on workers and Master. + ``` + sysctl net.ipv4.conf.all.forwarding=1 + iptables --policy FORWARD ACCEPT + mkdir /var/run/netns + ``` + +* Experimental environment Configuration + >clinet:192.168.71.128,master:192.168.71.141,worker:192.168.71.142.They are all Ubuntu virtual machines running on the same physical host + >We use distrinet to create a linear topology with two switches and two hosts, i.e. : + >Master: + ``` + root@master:~# ryu-manager /usr/lib/python3/dist-packages/ryu/app/simple_switch_13.py --verbose + ``` + >client: + ``` + jxq@client:~$ python3 bin/dmn --workers="192.168.71.141,192.168.71.142" --controller=lxcremote,ip=192.168.0.1 --topo=linear,2 + ``` + +* Experimental results + >Distrinet's CLI can be generated normally and pingall test also passes + # ![client](https://github.com/J980419xq/Distrinet/blob/master/images/cli.png) + >The master and worker can create containers and interfaces normally + >master: ip a + ``` + 1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 + link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 + inet 127.0.0.1/8 scope host lo + valid_lft forever preferred_lft forever + inet6 ::1/128 scope host + valid_lft forever preferred_lft forever + 2: ens33: mtu 1500 qdisc fq_codel state UP group default qlen 1000 + link/ether 00:0c:29:eb:10:f4 brd ff:ff:ff:ff:ff:ff + inet 192.168.71.141/24 brd 192.168.71.255 scope global noprefixroute ens33 + valid_lft forever preferred_lft forever + inet6 fe80::20c:29ff:feeb:10f4/64 scope link + valid_lft forever preferred_lft forever + 3: docker0: mtu 1500 qdisc noqueue state DOWN group default + link/ether 02:42:29:d0:a1:78 brd ff:ff:ff:ff:ff:ff + inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 + valid_lft forever preferred_lft forever + inet6 fe80::42:29ff:fed0:a178/64 scope link + valid_lft forever preferred_lft forever + 26: admin-br: mtu 1500 qdisc noqueue state UP group default qlen 1000 + link/ether 72:97:2f:43:4c:cb brd ff:ff:ff:ff:ff:ff + inet 192.168.0.1/8 brd 192.255.255.255 scope global admin-br + valid_lft forever preferred_lft forever + inet6 fe80::80f7:25ff:fe05:b735/64 scope link + valid_lft forever preferred_lft forever + 27: intf3@if28: mtu 1500 qdisc noqueue master admin-br state UP group default qlen 1000 + link/ether 72:97:2f:43:4c:cb brd ff:ff:ff:ff:ff:ff link-netnsid 0 + inet6 fe80::7097:2fff:fe43:4ccb/64 scope link + valid_lft forever preferred_lft forever + 29: intf1@if30: mtu 1500 qdisc noqueue master admin-br state UP group default qlen 1000 + link/ether 9a:aa:18:f7:72:0b brd ff:ff:ff:ff:ff:ff link-netnsid 1 + inet6 fe80::98aa:18ff:fef7:720b/64 scope link + valid_lft forever preferred_lft forever + 31: vNone@vadmin-br: mtu 1500 qdisc noqueue state UP group default qlen 1000 + link/ether 36:9f:9e:c7:9b:52 brd ff:ff:ff:ff:ff:ff + inet6 fe80::349f:9eff:fec7:9b52/64 scope link + valid_lft forever preferred_lft forever + 32: vadmin-br@vNone: mtu 1500 qdisc noqueue master admin-br state UP group default qlen 1000 + link/ether a2:06:41:fd:a4:7c brd ff:ff:ff:ff:ff:ff + inet6 fe80::a006:41ff:fefd:a47c/64 scope link + valid_lft forever preferred_lft forever + 33: vx_21: mtu 1500 qdisc noqueue master admin-br state UNKNOWN group default qlen 1000 + link/ether 9e:3b:48:ef:89:6f brd ff:ff:ff:ff:ff:ff + inet6 fe80::9c3b:48ff:feef:896f/64 scope link + valid_lft forever preferred_lft forever + 34: intf6: mtu 1500 qdisc noqueue state UP group default qlen 1000 + link/ether c2:e5:e4:21:a2:78 brd ff:ff:ff:ff:ff:ff + inet6 fe80::c0e5:e4ff:fe21:a278/64 scope link + valid_lft forever preferred_lft forever + 35: intf5@if36: mtu 1500 qdisc noqueue master intf6 state UP group default qlen 1000 + link/ether c2:e5:e4:21:a2:78 brd ff:ff:ff:ff:ff:ff link-netnsid 1 + inet6 fe80::c0e5:e4ff:fe21:a278/64 scope link + valid_lft forever preferred_lft forever + 37: intf8: mtu 1500 qdisc noqueue state UP group default qlen 1000 + link/ether a6:0f:bc:97:d5:4d brd ff:ff:ff:ff:ff:ff + inet6 fe80::f4e0:f3ff:fe8f:37f5/64 scope link + valid_lft forever preferred_lft forever + 38: intf7@if39: mtu 1500 qdisc noqueue master intf8 state UP group default qlen 1000 + link/ether f6:e0:f3:8f:37:f5 brd ff:ff:ff:ff:ff:ff link-netnsid 0 + inet6 fe80::f4e0:f3ff:fe8f:37f5/64 scope link + valid_lft forever preferred_lft forever + 40: vintf8@vintf6: mtu 1500 qdisc noqueue master intf8 state UP group default qlen 1000 + link/ether a6:0f:bc:97:d5:4d brd ff:ff:ff:ff:ff:ff + inet6 fe80::a40f:bcff:fe97:d54d/64 scope link + valid_lft forever preferred_lft forever + 41: vintf6@vintf8: mtu 1500 qdisc noqueue master intf6 state UP group default qlen 1000 + link/ether e6:31:f4:e8:39:38 brd ff:ff:ff:ff:ff:ff + inet6 fe80::e431:f4ff:fee8:3938/64 scope link + valid_lft forever preferred_lft forever + 42: intf16: mtu 1500 qdisc noqueue state UP group default qlen 1000 + link/ether 4e:63:dc:70:fd:e0 brd ff:ff:ff:ff:ff:ff + inet6 fe80::b085:44ff:fed3:599/64 scope link + valid_lft forever preferred_lft forever + 43: intf15@if44: mtu 1500 qdisc noqueue master intf16 state UP group default qlen 1000 + link/ether b2:85:44:d3:05:99 brd ff:ff:ff:ff:ff:ff link-netnsid 0 + inet6 fe80::b085:44ff:fed3:599/64 scope link + valid_lft forever preferred_lft forever + 45: vx_26: mtu 1500 qdisc noqueue master intf16 state UNKNOWN group default qlen 1000 + link/ether 4e:63:dc:70:fd:e0 brd ff:ff:ff:ff:ff:ff + inet6 fe80::4c63:dcff:fe70:fde0/64 scope link + valid_lft forever preferred_lft forever + ``` + # ![master container](https://github.com/J980419xq/Distrinet/blob/master/images/master.png) + >worker: ip a + ``` + 1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 + link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 + inet 127.0.0.1/8 scope host lo + valid_lft forever preferred_lft forever + inet6 ::1/128 scope host + valid_lft forever preferred_lft forever + 2: ens33: mtu 1500 qdisc fq_codel state UP group default qlen 1000 + link/ether 00:0c:29:ae:98:b2 brd ff:ff:ff:ff:ff:ff + inet 192.168.71.142/24 brd 192.168.71.255 scope global noprefixroute ens33 + valid_lft forever preferred_lft forever + inet6 fe80::20c:29ff:feae:98b2/64 scope link + valid_lft forever preferred_lft forever + 3: docker0: mtu 1500 qdisc noqueue state DOWN group default + link/ether 02:42:5a:e8:15:54 brd ff:ff:ff:ff:ff:ff + inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 + valid_lft forever preferred_lft forever + 22: admin-br: mtu 1500 qdisc noqueue state UP group default qlen 1000 + link/ether 22:7e:11:52:c0:5c brd ff:ff:ff:ff:ff:ff + inet6 fe80::bc16:11ff:fea9:78a4/64 scope link + valid_lft forever preferred_lft forever + 23: intf2@if24: mtu 1500 qdisc noqueue master admin-br state UP group default qlen 1000 + link/ether e2:94:dc:27:55:9d brd ff:ff:ff:ff:ff:ff link-netnsid 0 + inet6 fe80::e094:dcff:fe27:559d/64 scope link + valid_lft forever preferred_lft forever + 25: intf4@if26: mtu 1500 qdisc noqueue master admin-br state UP group default qlen 1000 + link/ether be:16:11:a9:78:a4 brd ff:ff:ff:ff:ff:ff link-netnsid 1 + inet6 fe80::bc16:11ff:fea9:78a4/64 scope link + valid_lft forever preferred_lft forever + 27: vx_21: mtu 1500 qdisc noqueue master admin-br state UNKNOWN group default qlen 1000 + link/ether 22:7e:11:52:c0:5c brd ff:ff:ff:ff:ff:ff + inet6 fe80::207e:11ff:fe52:c05c/64 scope link + valid_lft forever preferred_lft forever + 28: intf10: mtu 1500 qdisc noqueue state UP group default qlen 1000 + link/ether 2a:54:21:60:79:c5 brd ff:ff:ff:ff:ff:ff + inet6 fe80::9030:e2ff:fedb:b323/64 scope link + valid_lft forever preferred_lft forever + 29: intf9@if30: mtu 1500 qdisc noqueue master intf10 state UP group default qlen 1000 + link/ether 92:30:e2:db:b3:23 brd ff:ff:ff:ff:ff:ff link-netnsid 0 + inet6 fe80::9030:e2ff:fedb:b323/64 scope link + valid_lft forever preferred_lft forever + 31: intf12: mtu 1500 qdisc noqueue state UP group default qlen 1000 + link/ether 6e:c6:34:19:9e:cc brd ff:ff:ff:ff:ff:ff + inet6 fe80::6cc6:34ff:fe19:9ecc/64 scope link + valid_lft forever preferred_lft forever + 32: intf11@if33: mtu 1500 qdisc noqueue master intf12 state UP group default qlen 1000 + link/ether 6e:c6:34:19:9e:cc brd ff:ff:ff:ff:ff:ff link-netnsid 1 + inet6 fe80::6cc6:34ff:fe19:9ecc/64 scope link + valid_lft forever preferred_lft forever + 34: vintf12@vintf10: mtu 1500 qdisc noqueue master intf12 state UP group default qlen 1000 + link/ether b2:c1:38:57:4c:ca brd ff:ff:ff:ff:ff:ff + inet6 fe80::b0c1:38ff:fe57:4cca/64 scope link + valid_lft forever preferred_lft forever + 35: vintf10@vintf12: mtu 1500 qdisc noqueue master intf10 state UP group default qlen 1000 + link/ether 2a:54:21:60:79:c5 brd ff:ff:ff:ff:ff:ff + inet6 fe80::2854:21ff:fe60:79c5/64 scope link + valid_lft forever preferred_lft forever + 36: intf14: mtu 1500 qdisc noqueue state UP group default qlen 1000 + link/ether 0e:fd:28:ce:0e:8d brd ff:ff:ff:ff:ff:ff + inet6 fe80::cfd:28ff:fece:e8d/64 scope link + valid_lft forever preferred_lft forever + 37: intf13@if38: mtu 1500 qdisc noqueue master intf14 state UP group default qlen 1000 + link/ether 0e:fd:28:ce:0e:8d brd ff:ff:ff:ff:ff:ff link-netnsid 1 + inet6 fe80::cfd:28ff:fece:e8d/64 scope link + valid_lft forever preferred_lft forever + 39: vx_26: mtu 1500 qdisc noqueue master intf14 state UNKNOWN group default qlen 1000 + link/ether 86:5e:28:6d:96:ea brd ff:ff:ff:ff:ff:ff + inet6 fe80::845e:28ff:fe6d:96ea/64 scope link + valid_lft forever preferred_lft forever + ``` + # ![worker container](https://github.com/J980419xq/Distrinet/blob/master/images/worker.png) + + + diff --git a/ovs_image.md b/ovs_image.md new file mode 100644 index 00000000..037de67c --- /dev/null +++ b/ovs_image.md @@ -0,0 +1,157 @@ +本文档为创建并打包`ovs_image`çš„`docker`é•œåƒæ–‡æ¡£çš„æ•™ç¨‹ã€‚ + +[toc] + +## 嫿œ‰ovsçš„docker容器创建 + +第一部分为新建`docker`容器,并在容器内安装`openvswitch`。 + +### 1.创建容器 + +- 新建`docker`容器,使用镜åƒ`ubuntu:18.04`,命å为`ovs`: + +```shell +docker run -it --privileged --name ovs ubuntu:18.04 +``` + +此步在虚拟机中完æˆï¼Œæ­¤éƒ¨åˆ†å…¶ä½™æ­¥éª¤å‡åœ¨`ovs` `docker`容器中完æˆã€‚ + + + +### 2.下载ovs + +- æ›´æ–°`apt`,安装`git`并下载`openvswitch`:(以下步骤å‡åœ¨å®¹å™¨å†…) + +```shell +apt update +apt install git +git clone https://github.com/openvswitch/ovs.git +``` + +下载完æˆåŽï¼Œä¼šåœ¨å½“å‰ç›®å½•ç”Ÿæˆæ–‡ä»¶å¤¹`/ovs`。 + + + +### 3.安装相关ä¾èµ– + +- 安装相关ä¾èµ–包: + +```shell +apt install make gcc python3 + +# 安装libsslã€libcap-ngã€unbound +apt install libssl-dev libcap-ng-utils unbound + +# 安装autoconfã€libtool +apt install autoconf libtool +``` + +注:安装`unbound`包时å¯èƒ½ä¼šå‡ºçŽ°ä»¥ä¸‹æŠ¥é”™ï¼š + +```shell +Err:1 http://archive.ubuntu.com/ubuntu bionic/universe amd64 libfstrm0 amd64 0.3.0-1build1 + Connection failed [IP: 91.189.91.38 80] +``` + +此时需è¦å¯¹å®¹å™¨è¿›è¡Œæ¢æºï¼š + +```shell +cp /etc/apt/sources.list /etc/apt/sources.list.backup +rm /etc/apt/sources.list +#é˜¿é‡Œäº‘æº +echo -e "deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse\n" >> /etc/apt/sources.list +apt update +apt upgrade + +#æ¢æºåŽé‡æ–°å®‰è£…unbound +apt install unbound +``` + + + +### 4.编译安装ovsåŠåˆå§‹åŒ– + +- 编译安装`ovs`: + +```shell +cd /ovs +./boot.sh +./configure +make +make install +``` + +- åˆå§‹åŒ–`ovs`æ•°æ®åº“: + +```shell +mkdir -p /usr/local/etc/penvswitch +ovsdb-tool create /usr/local/etc/openvswitch/conf.db vswitchd/vswitch.ovsschema + +export PATH=$PATH:/usr/local/share/openvswitch/scripts +ovs-ctl start +ovsdb-server --remote=punix:/usr/local/var/run/openvswitch/db.sock \ + --remote=db:Open_vSwitch,Open_vSwitch,manager_options \ + --private-key=db:Open_vSwitch,SSL,private_key \ + --certificate=db:Open_vSwitch,SSL,certificate \ + --bootstrap-ca-cert=db:Open_vSwitch,SSL,ca_cert \ + --pidfile --detach +ovs-vsctl --no-wait init +ovs-vswitchd --pidfile --detach +``` + +- 安装完æˆï¼ŒéªŒè¯ï¼š + +```shell +ovs-vsctl --version +ovs-appctl --version +ovs-appctl version +``` + + + +## é•œåƒæ‰“包 + +第二部分为将第一部分创建的容器打包æˆé•œåƒã€‚ + + + +### 1.退出docker容器 + +ç›®å‰é»˜è®¤ä»åœ¨å®¹å™¨ä¸­ï¼Œä½¿ç”¨å¿«æ·é”®`ctrl+p ctrl+q`退出容器。 + + + +### 2.将容器ä¿å­˜ä¸ºé•œåƒ + +```shell +docker commit [-m "æäº¤çš„æè¿°ä¿¡æ¯"] [-a "创建者"] 容器åç§°|容器ID 生æˆçš„镜åƒå[:标签å] + +# 注释: +## []为å¯é€‰é¡¹ +## -m= : ä¸ºé•œåƒæ·»åŠ æè¿°ä¿¡æ¯ +## -a= : ä¸ºé•œåƒæ·»åŠ åˆ›å»ºè€…ä¿¡æ¯ +## 容器åç§°|容器ID : 当å‰è¦è¢«æ‰“包的容器å称或容器ID +## 生æˆçš„镜åƒå[:标签å] : 指定镜åƒå称或标签åç§° + +# 本例: +docker commit -m "ovs_image" -a "ycyz" ovs ovs_image +``` + +执行该命令åŽï¼Œé•œåƒ`ovs_image`制作æˆåŠŸï¼Œè¿è¡Œå¦‚下命令查看所有`docker`镜åƒï¼š + +```shell +docker images +``` + + + +### 3. tar压缩文件打包 + +è‹¥éœ€è¦æ‰“包æˆ`tar`压缩文件,è¿è¡Œå¦‚下命令: + +```shell +# 进入目标目录 +cd /home/sdn/Desktop +# 打包tar压缩文件 +docker export ovs > ovs_image.tar +``` From 5f2d5cad8436797283b9e726cca34a569639395e Mon Sep 17 00:00:00 2001 From: gethurb <1070254022@qq.com> Date: Wed, 25 May 2022 12:48:33 +0800 Subject: [PATCH 10/44] second version --- mininet/bin/dmn | 4 + mininet/mininet/cloudlink.py | 10 +- mininet/mininet/distrinet.py | 17 ++-- mininet/mininet/lxc_container.py | 97 ++++++++++--------- .../provision/playbooks/configure-docker.yml | 16 +++ .../playbooks/configure-lxd-no-clustering.yml | 41 ++++++-- .../provision/playbooks/install-docker.yml | 86 ++++++++++++++++ .../provision/playbooks/install-lxd.yml | 71 ++++++-------- 8 files changed, 233 insertions(+), 109 deletions(-) create mode 100644 mininet/mininet/provision/playbooks/configure-docker.yml create mode 100644 mininet/mininet/provision/playbooks/install-docker.yml diff --git a/mininet/bin/dmn b/mininet/bin/dmn index 9c0f031e..074db4cd 100755 --- a/mininet/bin/dmn +++ b/mininet/bin/dmn @@ -302,6 +302,8 @@ class DistrinetRunner( object ): help='base IP address for hosts' ) opts.add_option( '--mac', action='store_true', default=False, help='automatically set host MACs' ) + opts.add_option('--docker',action='store_true', + default=False,help='replace lxd with docker' ) opts.add_option( '--arp', action='store_true', default=False, help='set all-pairs ARP entries' ) opts.add_option( '--verbosity', '-v', type='choice', @@ -616,6 +618,7 @@ class DistrinetRunner( object ): link=link, ipBase=opts.ipbase, inNamespace=opts.innamespace, xterms=opts.xterms, autoSetMacs=opts.mac, + autoSetDocker=opts.docker, autoStaticArp=opts.arp, autoPinCpus=opts.pin, listenPort=opts.listenport ) @@ -710,3 +713,4 @@ if __name__ == "__main__": stackTrace = traceback.format_exc() debug( stackTrace + "\n" ) cleanup() + diff --git a/mininet/mininet/cloudlink.py b/mininet/mininet/cloudlink.py index 5ceb81a5..d2db99fb 100644 --- a/mininet/mininet/cloudlink.py +++ b/mininet/mininet/cloudlink.py @@ -39,7 +39,7 @@ class CloudLink( Link ): def __init__( self, node1, node2, port1=None, port2=None, intfName1=None, intfName2=None, addr1=None, addr2=None, intf=TCIntf, cls1=None, cls2=None, params1=None, - params2=None, fast=True, **params ): + params2=None, fast=True,autoSetDocker=False, **params ): """Create veth link to another node, making two new interfaces. node1: first node node2: second node @@ -88,7 +88,7 @@ def __init__( self, node1, node2, port1=None, port2=None, # Make interfaces interfaces = self.makeIntfPair( intfName1, intfName2, addr1, addr2, - node1, node2, deleteIntfs=False ) + node1, node2, deleteIntfs=False,autoSetDocker=autoSetDocker ) if not cls1: cls1 = intf @@ -133,7 +133,7 @@ def intfName( self, node, n ): @classmethod def makeIntfPair( cls, intfname1, intfname2, addr1=None, addr2=None, - node1=None, node2=None, deleteIntfs=True ): + node1=None, node2=None, deleteIntfs=True,autoSetDocker=False ): """Create pair of interfaces intfname1: name for interface 1 intfname2: name for interface 2 @@ -151,8 +151,8 @@ def makeIntfPair( cls, intfname1, intfname2, addr1=None, addr2=None, raise Exception("Must implement delete interface") # Add the interface on both ends: - br1 = node1.addContainerInterface(intfName=intfname1) - br2 = node2.addContainerInterface(intfName=intfname2) + br1 = node1.addContainerInterface(intfName=intfname1,autoSetDocker=autoSetDocker) + br2 = node2.addContainerInterface(intfName=intfname2,autoSetDocker=autoSetDocker) return (br1, br2) diff --git a/mininet/mininet/distrinet.py b/mininet/mininet/distrinet.py index e5100d53..57aa87f2 100755 --- a/mininet/mininet/distrinet.py +++ b/mininet/mininet/distrinet.py @@ -140,7 +140,7 @@ def __init__( self, topo=None, switch=LxcSwitch, host=LxcNode, mapper=None, build=True, xterms=False, cleanup=False, ipBase='10.0.0.0/8', adminIpBase='192.168.0.1/8', - autoSetMacs=False, autoPinCpus=False, + autoSetMacs=False, autoSetDocker=False,autoPinCpus=False, listenPort=None, waitConnected=False, waitConnectionTimeout=5, jump=None, user="root", client_keys=None, master=None, pub_id=None, **kwargs): @@ -190,6 +190,7 @@ def __init__( self, topo=None, switch=LxcSwitch, host=LxcNode, self.xterms = xterms self.cleanup = cleanup self.autoSetMacs = autoSetMacs + self.autoSetDocker=autoSetDocker # self.autoStaticArp = autoStaticArp self.autoPinCpus = autoPinCpus # self.numCores = numCores() @@ -387,7 +388,7 @@ def addLink( self, node1, node2, port1=None, port2=None, # Set default MAC - this should probably be in Link options.setdefault( 'addr1', self.randMac() ) options.setdefault( 'addr2', self.randMac() ) - + options.setdefault('autoSetDocker',self.autoSetDocker) params1 = None params2 = None if self.mapper: @@ -530,7 +531,7 @@ def buildFromTopo( self, topo=None ): count = 0 for node in nodes: _info ("createContainer {} ".format( node.name)) - node.createContainer() + node.createContainer(autoSetDocker=self.autoSetDocker) count += 1 if count > 50: output("50 nodes created...\n") @@ -543,7 +544,7 @@ def buildFromTopo( self, topo=None ): for node in nodes: _info ("create admin interface {} ".format( node.name)) - node.addContainerInterface(intfName="admin", brname="admin-br", wait=False) + node.addContainerInterface(intfName="admin", brname="admin-br", wait=False,autoSetDocker=self.autoSetDocker) for node in nodes: node.targetSshWaitOutput() @@ -558,7 +559,7 @@ def buildFromTopo( self, topo=None ): self.masterSsh.cmd(cmd) for node in nodes: - node.configureContainer(wait=False) + node.configureContainer(wait=False,autoSetDocker=self.autoSetDocker) for node in nodes: node.targetSshWaitOutput() @@ -688,12 +689,12 @@ def stop( self ): info( switch.name + ' ' ) if switch not in stopped: switch.stop() - switch.terminate() + switch.terminate(autoSetDocker=self.autoSetDocker) info( '\n' ) info( '*** Stopping %i hosts\n' % len( self.hosts ) ) for host in self.hosts: info( host.name + ' ' ) - host.terminate() + host.terminate(autoSetDocker=self.autoSetDocker) info( '*** Stopping %i controllers\n' % len( self.controllers ) ) for controller in self.controllers: @@ -873,5 +874,3 @@ def configureRoutedControlNetwork( self, ip='192.168.123.1', error( '*** Error: control network test failed\n' ) exit( 1 ) info( '\n' ) - - diff --git a/mininet/mininet/lxc_container.py b/mininet/mininet/lxc_container.py index 58c0719f..ac294e9d 100644 --- a/mininet/mininet/lxc_container.py +++ b/mininet/mininet/lxc_container.py @@ -188,7 +188,7 @@ def _preInit(self, admin_ip, prefix = admin_ip.split("/") self.ssh = ASsh(loop=self.loop, host=admin_ip, username=self.username, bastion=self.bastion, client_keys=self.client_keys) - def configureContainer(self, adminbr="admin-br", wait=True): + def configureContainer(self, adminbr="admin-br", wait=True,autoSetDocker=False): # # connect the node to the admin network # self.addContainerInterface(intfName="admin", brname=adminbr) @@ -202,15 +202,17 @@ def configureContainer(self, adminbr="admin-br", wait=True): # configure the node to be "SSH'able" cmds = [] + if autoSetDocker: + cmds.append("{}=$(docker inspect -f '{{{{.State.Pid}}}}' {})".format(self.name,self.name)) + cmds.append("ip netns exec ${} ip addr add {} dev admin".format(self.name,self.admin_ip)) # configure the container to have + else: # an admin IP address - #cmds.append("lxc exec {} -- ifconfig admin {}".format(self.name, self.admin_ip)) - #cmds.append("docker exec -it {} ifconfig eth0 {}".format(self.name, self.admin_ip)) - cmds.append("{}=$(docker inspect -f '{{{{.State.Pid}}}}' {})".format(self.name,self.name)) - cmds.append("ip netns exec ${} ip addr add {} dev admin".format(self.name,self.admin_ip)) + cmds.append("lxc exec {} -- ifconfig admin {}".format(self.name, self.admin_ip)) # a public key - #cmds.append("lxc exec {} -- bash -c 'echo \"{}\" >> /root/.ssh/authorized_keys'".format(self.name, self.pub_id)) - + cmds.append("lxc exec {} -- bash -c 'echo \"{}\" >> /root/.ssh/authorized_keys'".format(self.name, self.pub_id)) +# a ssh server + cmds.append("lxc exec {} -- service ssh start".format(self.name)) cmd = ';'.join(cmds) if wait: self.targetSsh.cmd(cmd) @@ -341,34 +343,39 @@ def connectTarget(self): def waitConnectedTarget(self): self.targetSsh.waitConnected() - def createContainer(self, **params): + def createContainer(self,autoSetDocker=False, **params): ################################################################################ time.sleep(1.0) info ("create container ({} {} {}) ".format(self.image, self.cpu, self.memory)) cmds = [] # initialise the container - #cmd = "lxc init {} {} < /dev/null ".format(self.image, self.name) - cmd = "docker run --privileged -itd --name {} --net=none {}".format(self.name, self.image) + if autoSetDocker: + cmd = "docker run --privileged -itd --name {} --net=none {}".format(self.name, self.image) + else: + cmd = "lxc init {} {} < /dev/null ".format(self.image, self.name) info ("{}\n".format(cmd)) cmds.append(cmd) - # limit resources - if self.cpu: + if autoSetDocker: + if self.cpu: #cmds.append("lxc config set {} limits.cpu {}".format(self.name, self.cpu)) - cmds.append("docker container update --cpuset-cpus={} {}".format(self.cpu, self.name)) - if self.memory: + cmds.append("docker container update --cpuset-cpus={} {}".format(self.cpu, self.name)) + if self.memory: #cmds.append("lxc config set {} limits.memory {}".format(self.name, self.memory)) - cmds.append("docker container update -m {} {}".format(self.memory, self.name)) - - # start the container - #cmds.append("lxc start {}".format(self.name)) - cmds.append("docker start {}".format(self.name)) - if self.image=="switch": - cmds.append("docker exec {} bash -c 'export PATH=$PATH:/usr/local/share/openvswitch/scripts;ovs-ctl start'".format(self.name)) - cmds.append("docker exec {} mkdir /root/.ssh".format(self.name)) - cmds.append("docker exec {} bash -c 'echo \"{}\" >> /root/.ssh/authorized_keys'".format(self.name, self.pub_id)) - # a ssh server - #cmds.append("lxc exec {} -- service ssh start".format(self.name)) - cmds.append("docker exec -itd {} service ssh start".format(self.name)) + cmds.append("docker container update -m {} {}".format(self.memory, self.name)) + + cmds.append("docker start {}".format(self.name)) + if self.image=="switch": + cmds.append("docker exec {} bash -c 'export PATH=$PATH:/usr/share/openvswitch/scripts;ovs-ctl start'".format(self.name)) + cmds.append("docker exec {} mkdir /root/.ssh".format(self.name)) + cmds.append("docker exec {} bash -c 'echo \"{}\" >> /root/.ssh/authorized_keys'".format(self.name, self.pub_id)) + cmds.append("docker exec {} service ssh start".format(self.name)) + else: + if self.cpu: + cmds.append("lxc config set {} limits.cpu {}".format(self.name, self.cpu)) + if self.memory: + cmds.append("lxc config set {} limits.memory {}".format(self.name, self.memory)) + # start the container + cmds.append("lxc start {}".format(self.name)) @@ -387,7 +394,7 @@ def waitCreated(self): info ("container created") - def addContainerInterface(self, intfName, devicename=None, brname=None, wait=True, **params): + def addContainerInterface(self, intfName, devicename=None, brname=None, wait=True, autoSetDocker=False,**params): """ Add the interface with name intfName to the container that is associated to the bridge named name-intfName-br on the host @@ -398,22 +405,18 @@ def addContainerInterface(self, intfName, devicename=None, brname=None, wait=Tru brname = genIntfName() cmds = [] cmds.append("brctl addbr {}".format(brname)) - cmds.append("ip link add {} type veth peer name {}".format("veth"+devicename,devicename)) - cmds.append("brctl addif {} {}".format(brname,devicename)) - cmds.append("ip link set up {}".format(devicename)) - cmds.append("{}=$(docker inspect -f '{{{{.State.Pid}}}}' {})".format(self.name,self.name)) - cmds.append("ln -s /proc/{}/ns/net /var/run/netns/${}".format("$"+self.name,self.name)) - cmds.append("ip link set {} netns ${}".format("veth"+devicename,self.name)) - cmds.append("ip netns exec ${} ip link set dev {} name {}".format(self.name,"veth"+devicename,intfName)) - cmds.append("ip netns exec ${} ip link set {} up".format(self.name,intfName)) - #cmds.append("lxc network attach {} {} {} {}".format(brname, self.name, devicename, intfName)) - #cmds.append("lxc network attach {} {} {} {}".format(brname, self.name, devicename, intfName)) - #cmds.append("docker network connect {} {}".format(brname, container_id)) - #cmds.append("docker network create -d bridge {} -o com.docker.network.bridge.name={}".format(brname, brname)) - #cmds.append("docker network connect {} {}".format(brname, self.name)) + if autoSetDocker: + cmds.append("ip link add {} type veth peer name {}".format("veth"+devicename,devicename)) + cmds.append("brctl addif {} {}".format(brname,devicename)) + cmds.append("ip link set up {}".format(devicename)) + cmds.append("{}=$(docker inspect -f '{{{{.State.Pid}}}}' {})".format(self.name,self.name)) + cmds.append("ln -s /proc/{}/ns/net /var/run/netns/${}".format("$"+self.name,self.name)) + cmds.append("ip link set {} netns ${}".format("veth"+devicename,self.name)) + cmds.append("ip netns exec ${} ip link set dev {} name {}".format(self.name,"veth"+devicename,intfName)) + cmds.append("ip netns exec ${} ip link set {} up".format(self.name,intfName)) + else: + cmds.append("lxc network attach {} {} {} {}".format(brname, self.name, devicename, intfName)) cmds.append("ip link set up {}".format(brname)) - cmds.append("iptables -A FORWARD -o {} -j ACCEPT".format(brname)) - cmds.append("iptables -A FORWARD -i {} -j ACCEPT".format(brname)) cmd = ";".join(cmds) if wait: @@ -540,15 +543,16 @@ def cleanup( self ): # Subshell I/O, commands and control # XXX - OK - def terminate( self ): + def terminate( self ,autoSetDocker=False): "Send kill signal to Node and clean up after it." self.unmountPrivateDirs() cmds = [] # destroy the container - #cmds.append("lxc delete {} --force".format(self.name)) - cmds.append("docker rm -f {}".format(self.name)) - + if autoSetDocker: + cmds.append("docker rm -f {}".format(self.name)) + else: + cmds.append("lxc delete {} --force".format(self.name)) # remove all locally made devices for device in self.devices: cmds.append("ip link delete {}".format(device)) @@ -677,3 +681,4 @@ async def _pexec(self, *args, **kwargs): exitcode = process.returncode return out, err, exitcode + diff --git a/mininet/mininet/provision/playbooks/configure-docker.yml b/mininet/mininet/provision/playbooks/configure-docker.yml new file mode 100644 index 00000000..4ec30307 --- /dev/null +++ b/mininet/mininet/provision/playbooks/configure-docker.yml @@ -0,0 +1,16 @@ +--- + +- hosts : all + remote_user: root + tasks : + - name : create switch image + command: docker pull caiji0419/switch + + - name : create ubuntu18.04 image + command: docker pull caiji0419/ubuntu + + - name : update ubuntu tag + command: docker tag caiji0419/ubuntu ubuntu + + - name : update switch tag + command: docker tag caiji0419/switch switch diff --git a/mininet/mininet/provision/playbooks/configure-lxd-no-clustering.yml b/mininet/mininet/provision/playbooks/configure-lxd-no-clustering.yml index d3c284a3..87405346 100644 --- a/mininet/mininet/provision/playbooks/configure-lxd-no-clustering.yml +++ b/mininet/mininet/provision/playbooks/configure-lxd-no-clustering.yml @@ -1,18 +1,42 @@ --- + +- hosts : all + remote_user: root + tasks : + - name : lxd configuration + expect: + echo : yes + command : lxd init + timeout : 20 + responses: + (?i)Would you like to use LXD clustering? : "no" + (?i)Do you want to configure a new storage pool? : "yes" + (?i)Name of the new storage pool : "default" + (?i)Name of the storage backend to use : "dir" + (?i)Would you like to connect to a MAAS server? : "no" + (?i)Would you like to create a new local network bridge? : "yes" + (?i)What should the new bridge be called? : "lxdbr0" + (?i)What IPv4 address should be used? : "auto" + (?i)What IPv6 address should be used? : "auto" + (?i)Would you like LXD to be available over the network? : "no" + (?i)Would you like stale cached images to be updated automatically? : "yes" + (?i)Would you like a YAML "lxd init" preseed to be printed? : "no" + + - hosts : all remote_user: root tasks : - name : distribute switch image copy : - src : ~/switch.tar - dest : ~/switch.tar + src : ~/switch.tar.gz + dest : ~/switch.tar.gz - name : distribute ubuntu image copy : - src : ~/ubuntu.tar - dest : ~/ubuntu.tar + src : ~/ubuntu.tar.gz + dest : ~/ubuntu.tar.gz -# - name : distribute debian image +### - name : distribute debian image # copy : # src : ~/debian.tar.gz # dest : ~/debian.tar.gz @@ -28,7 +52,7 @@ # dest : ~/ubuntu-hadoop-slave.tar.gz -# - name : distribute onos image +# - name : distribute onos image # copy : # src : ~/ubuntu-onos-2.1.0.tar.gz # dest : ~/ubuntu-onos-2.1.0.tar.gz @@ -37,10 +61,11 @@ remote_user: root tasks : - name : create switch image - command: docker load -i ~/switch.tar + command: lxc image import ~/switch.tar.gz --alias switch --public - name : create ubuntu18.04 image -- alias ubuntu - command: docker load -i ~/ubuntu.tar + command: lxc image import ~/ubuntu.tar.gz --alias ubuntu --public + # - name : create debian10 image -- alias debian # command: lxc image import ~/debian.tar.gz --alias debian --public diff --git a/mininet/mininet/provision/playbooks/install-docker.yml b/mininet/mininet/provision/playbooks/install-docker.yml new file mode 100644 index 00000000..28f2bf53 --- /dev/null +++ b/mininet/mininet/provision/playbooks/install-docker.yml @@ -0,0 +1,86 @@ +- hosts : all + remote_user: root + tasks : + - name: install python3-pip + apt : + update_cache: true + name : python3-pip + - name: install basice packages + apt : name={{item}} state=present + with_items: + - aptitude + - apt-transport-https + - ca-certificates + - curl + - python3-setuptools + - python3-dev + - build-essential + - iptables + - software-properties-common + +# - name: install python-pip +# apt : +# name : python-pip + + - name: install htop + apt : + name: htop + + - name: install ethtool + apt : + name: ethtool + + - name: install bridge-utils + apt : + name: bridge-utils + + - name: install net-tools + apt : + name: net-tools + + - name: install pexpect + pip : + name: pexpect + + - name: install ovs + apt : + name: openvswitch-switch + +# - name: install btrfs-tools +# apt: +# name: btrfs-tools + +# - name: install lxd +# apt: +# name: lxd + +# - name: install lxd-client +# apt : +# name: lxd-client + + - name: install ryu + apt: + name: python3-ryu + + - name: "Check if Docker-CE is installed" + package_facts: + manager: "auto" + + - name: install Docker CE repos (1/3) + apt_key: + url: https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg + state: present + when: "'docker-ce' not in ansible_facts.packages" + + - name: install Docker CE repos (2/3) + shell: add-apt-repository "deb [arch=amd64] https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu $(lsb_release -cs) stable" + when: "'docker-ce' not in ansible_facts.packages" + + - name: install Docker CE repos (3/3) + apt: + update_cache: yes + when: "'docker-ce' not in ansible_facts.packages" + + - name: install Docker CE + apt: name=docker-ce state=present + when: "'docker-ce' not in ansible_facts.packages" diff --git a/mininet/mininet/provision/playbooks/install-lxd.yml b/mininet/mininet/provision/playbooks/install-lxd.yml index 28f2bf53..cb19c264 100644 --- a/mininet/mininet/provision/playbooks/install-lxd.yml +++ b/mininet/mininet/provision/playbooks/install-lxd.yml @@ -1,3 +1,27 @@ +--- +# +- hosts : master + remote_user: root + tasks : + + - name : Download switch + get_url: + url : http://www-sop.inria.fr/members/Damien.Saucez/images/switch.tar.gz + dest: ~/switch.tar.gz + mode: 0666 + + - name : Download ubuntu18:04 + get_url: + url : http://www-sop.inria.fr/members/Damien.Saucez/images/ubuntu.tar.gz + dest: ~/ubuntu.tar.gz + mode: 0666 + +# - name : Download Debian:10 +# get_url: +# url : http://www-sop.inria.fr/members/Damien.Saucez/images/debian.tar.gz +# dest: ~/debian.tar.gz +# mode: 0666 + - hosts : all remote_user: root tasks : @@ -5,18 +29,6 @@ apt : update_cache: true name : python3-pip - - name: install basice packages - apt : name={{item}} state=present - with_items: - - aptitude - - apt-transport-https - - ca-certificates - - curl - - python3-setuptools - - python3-dev - - build-essential - - iptables - - software-properties-common # - name: install python-pip # apt : @@ -50,37 +62,14 @@ # apt: # name: btrfs-tools -# - name: install lxd -# apt: -# name: lxd + - name: install lxd + apt: + name: lxd -# - name: install lxd-client -# apt : -# name: lxd-client + - name: install lxd-client + apt : + name: lxd-client - name: install ryu apt: name: python3-ryu - - - name: "Check if Docker-CE is installed" - package_facts: - manager: "auto" - - - name: install Docker CE repos (1/3) - apt_key: - url: https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg - state: present - when: "'docker-ce' not in ansible_facts.packages" - - - name: install Docker CE repos (2/3) - shell: add-apt-repository "deb [arch=amd64] https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu $(lsb_release -cs) stable" - when: "'docker-ce' not in ansible_facts.packages" - - - name: install Docker CE repos (3/3) - apt: - update_cache: yes - when: "'docker-ce' not in ansible_facts.packages" - - - name: install Docker CE - apt: name=docker-ce state=present - when: "'docker-ce' not in ansible_facts.packages" From cc22533a1dcb55d5842cc81840ab0685b393a1b5 Mon Sep 17 00:00:00 2001 From: J980419xq <62777661+J980419xq@users.noreply.github.com> Date: Wed, 25 May 2022 13:11:02 +0800 Subject: [PATCH 11/44] Delete docker.md --- docker.md | 209 ------------------------------------------------------ 1 file changed, 209 deletions(-) delete mode 100644 docker.md diff --git a/docker.md b/docker.md deleted file mode 100644 index 96a2a23e..00000000 --- a/docker.md +++ /dev/null @@ -1,209 +0,0 @@ - -This document is the development and testing document for `issue25:Investigate the possibility of replacing lxc/lxd with docker` . - -* Figure out the detail steps to replace lxc/lxd engine with docker engine. - > The replacement process can be divided into two steps - > * Change the environment of lxd in the master and workers to docker - > * Change the deployment and configuration commands of the lxd container in the master and workers to the commands with the same function under docker - -* Study files under Distrinet/mininet/provision folder. - > Distrinet provides an infrastructure provisioning mechanism that uses Ansible to automatically install and configure LXD on each machine to be used during the experiment. - >In order not to detract from Distrinet's overall architecture. We did not change the filename of the relevant file, only the implementation details. - > * install-lxd.yml:this file is used to install lxd and download two images(an Ubuntu:18.04 image to emulate the vHosts, and a modified version of that image with OVS installed)on each machine by Ansible,we change it to install docker,and these two images need to be remade according to Docker,the OVS process will be described in the ovs_image.md. - > * configure-lxd-no-clustering.yml:this file is used to configure lxd init,but you don't neet to do it in docker,so we only use it to distribute and load the above two images. - - >We have not modified the other files in this folder. If you really want to use Docker instead of LXD, you will still need to modify the yml files in other installation environments based on these two files. - -* Create related files (config, deploy, install, etc) for docker provision by referring lxd scenario - >Reading through all the code in the LXD scenario, we can see that the creation and configuration of containers and the creation of network interfaces and links are mainly concentrated in lxc_cotainer.py and distrinet.py,We need to replace the code that uses LXC/LXD with a docker equivalent command - - >As for the network interfaces and links,we'll discuss this in more detail in issue33,In addition,for container creation and configuration, you can keep an eye out for lXC_container.py changes.The most critical one is that we use a pair of virtual devices veth pair and a bridge to replace lXC network attach command.Besides,We use namespaces to attach one end of veth pair to the container. - - >We don't change the lxc_container.py's name,because this file is referenced several times in the project.You can modify it yourself if you really need to. - -* The Distrinet environment replaced by docker includes the three following entities - * Client: host in which the Distrinet script is running and decides where to place the vNodes around the physical infrastructure (round-robin by default). The Client must be able to connect via SSH to the Master host. - * Master: host that acts as a relay to interconnect the Client with all the Worker hosts. It communicates with the Client and the different Workers via SSH. Note that the Master can also be configured as a Worker. - * Worker(s): host(s) where all the vNodes (vSwitches and vHosts) are running. vNodes are managed by the Master and the Client, via the admin network. - > To ensure the smooth deployment of vNodes, Ip forwarding needs to be allowed on workers and the netns of the container needs to be restored to the host directory,here are a few commands that you might configure on workers and Master. - ``` - sysctl net.ipv4.conf.all.forwarding=1 - iptables --policy FORWARD ACCEPT - mkdir /var/run/netns - ``` - -* Experimental environment Configuration - >clinet:192.168.71.128,master:192.168.71.141,worker:192.168.71.142.They are all Ubuntu virtual machines running on the same physical host - >We use distrinet to create a linear topology with two switches and two hosts, i.e. : - >Master: - ``` - root@master:~# ryu-manager /usr/lib/python3/dist-packages/ryu/app/simple_switch_13.py --verbose - ``` - >client: - ``` - jxq@client:~$ python3 bin/dmn --workers="192.168.71.141,192.168.71.142" --controller=lxcremote,ip=192.168.0.1 --topo=linear,2 - ``` - -* Experimental results - >Distrinet's CLI can be generated normally and pingall test also passes - # ![client](https://github.com/J980419xq/Distrinet/blob/master/images/cli.png) - >The master and worker can create containers and interfaces normally - >master: ip a - ``` - 1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 - link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 - inet 127.0.0.1/8 scope host lo - valid_lft forever preferred_lft forever - inet6 ::1/128 scope host - valid_lft forever preferred_lft forever - 2: ens33: mtu 1500 qdisc fq_codel state UP group default qlen 1000 - link/ether 00:0c:29:eb:10:f4 brd ff:ff:ff:ff:ff:ff - inet 192.168.71.141/24 brd 192.168.71.255 scope global noprefixroute ens33 - valid_lft forever preferred_lft forever - inet6 fe80::20c:29ff:feeb:10f4/64 scope link - valid_lft forever preferred_lft forever - 3: docker0: mtu 1500 qdisc noqueue state DOWN group default - link/ether 02:42:29:d0:a1:78 brd ff:ff:ff:ff:ff:ff - inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 - valid_lft forever preferred_lft forever - inet6 fe80::42:29ff:fed0:a178/64 scope link - valid_lft forever preferred_lft forever - 26: admin-br: mtu 1500 qdisc noqueue state UP group default qlen 1000 - link/ether 72:97:2f:43:4c:cb brd ff:ff:ff:ff:ff:ff - inet 192.168.0.1/8 brd 192.255.255.255 scope global admin-br - valid_lft forever preferred_lft forever - inet6 fe80::80f7:25ff:fe05:b735/64 scope link - valid_lft forever preferred_lft forever - 27: intf3@if28: mtu 1500 qdisc noqueue master admin-br state UP group default qlen 1000 - link/ether 72:97:2f:43:4c:cb brd ff:ff:ff:ff:ff:ff link-netnsid 0 - inet6 fe80::7097:2fff:fe43:4ccb/64 scope link - valid_lft forever preferred_lft forever - 29: intf1@if30: mtu 1500 qdisc noqueue master admin-br state UP group default qlen 1000 - link/ether 9a:aa:18:f7:72:0b brd ff:ff:ff:ff:ff:ff link-netnsid 1 - inet6 fe80::98aa:18ff:fef7:720b/64 scope link - valid_lft forever preferred_lft forever - 31: vNone@vadmin-br: mtu 1500 qdisc noqueue state UP group default qlen 1000 - link/ether 36:9f:9e:c7:9b:52 brd ff:ff:ff:ff:ff:ff - inet6 fe80::349f:9eff:fec7:9b52/64 scope link - valid_lft forever preferred_lft forever - 32: vadmin-br@vNone: mtu 1500 qdisc noqueue master admin-br state UP group default qlen 1000 - link/ether a2:06:41:fd:a4:7c brd ff:ff:ff:ff:ff:ff - inet6 fe80::a006:41ff:fefd:a47c/64 scope link - valid_lft forever preferred_lft forever - 33: vx_21: mtu 1500 qdisc noqueue master admin-br state UNKNOWN group default qlen 1000 - link/ether 9e:3b:48:ef:89:6f brd ff:ff:ff:ff:ff:ff - inet6 fe80::9c3b:48ff:feef:896f/64 scope link - valid_lft forever preferred_lft forever - 34: intf6: mtu 1500 qdisc noqueue state UP group default qlen 1000 - link/ether c2:e5:e4:21:a2:78 brd ff:ff:ff:ff:ff:ff - inet6 fe80::c0e5:e4ff:fe21:a278/64 scope link - valid_lft forever preferred_lft forever - 35: intf5@if36: mtu 1500 qdisc noqueue master intf6 state UP group default qlen 1000 - link/ether c2:e5:e4:21:a2:78 brd ff:ff:ff:ff:ff:ff link-netnsid 1 - inet6 fe80::c0e5:e4ff:fe21:a278/64 scope link - valid_lft forever preferred_lft forever - 37: intf8: mtu 1500 qdisc noqueue state UP group default qlen 1000 - link/ether a6:0f:bc:97:d5:4d brd ff:ff:ff:ff:ff:ff - inet6 fe80::f4e0:f3ff:fe8f:37f5/64 scope link - valid_lft forever preferred_lft forever - 38: intf7@if39: mtu 1500 qdisc noqueue master intf8 state UP group default qlen 1000 - link/ether f6:e0:f3:8f:37:f5 brd ff:ff:ff:ff:ff:ff link-netnsid 0 - inet6 fe80::f4e0:f3ff:fe8f:37f5/64 scope link - valid_lft forever preferred_lft forever - 40: vintf8@vintf6: mtu 1500 qdisc noqueue master intf8 state UP group default qlen 1000 - link/ether a6:0f:bc:97:d5:4d brd ff:ff:ff:ff:ff:ff - inet6 fe80::a40f:bcff:fe97:d54d/64 scope link - valid_lft forever preferred_lft forever - 41: vintf6@vintf8: mtu 1500 qdisc noqueue master intf6 state UP group default qlen 1000 - link/ether e6:31:f4:e8:39:38 brd ff:ff:ff:ff:ff:ff - inet6 fe80::e431:f4ff:fee8:3938/64 scope link - valid_lft forever preferred_lft forever - 42: intf16: mtu 1500 qdisc noqueue state UP group default qlen 1000 - link/ether 4e:63:dc:70:fd:e0 brd ff:ff:ff:ff:ff:ff - inet6 fe80::b085:44ff:fed3:599/64 scope link - valid_lft forever preferred_lft forever - 43: intf15@if44: mtu 1500 qdisc noqueue master intf16 state UP group default qlen 1000 - link/ether b2:85:44:d3:05:99 brd ff:ff:ff:ff:ff:ff link-netnsid 0 - inet6 fe80::b085:44ff:fed3:599/64 scope link - valid_lft forever preferred_lft forever - 45: vx_26: mtu 1500 qdisc noqueue master intf16 state UNKNOWN group default qlen 1000 - link/ether 4e:63:dc:70:fd:e0 brd ff:ff:ff:ff:ff:ff - inet6 fe80::4c63:dcff:fe70:fde0/64 scope link - valid_lft forever preferred_lft forever - ``` - # ![master container](https://github.com/J980419xq/Distrinet/blob/master/images/master.png) - >worker: ip a - ``` - 1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 - link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 - inet 127.0.0.1/8 scope host lo - valid_lft forever preferred_lft forever - inet6 ::1/128 scope host - valid_lft forever preferred_lft forever - 2: ens33: mtu 1500 qdisc fq_codel state UP group default qlen 1000 - link/ether 00:0c:29:ae:98:b2 brd ff:ff:ff:ff:ff:ff - inet 192.168.71.142/24 brd 192.168.71.255 scope global noprefixroute ens33 - valid_lft forever preferred_lft forever - inet6 fe80::20c:29ff:feae:98b2/64 scope link - valid_lft forever preferred_lft forever - 3: docker0: mtu 1500 qdisc noqueue state DOWN group default - link/ether 02:42:5a:e8:15:54 brd ff:ff:ff:ff:ff:ff - inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 - valid_lft forever preferred_lft forever - 22: admin-br: mtu 1500 qdisc noqueue state UP group default qlen 1000 - link/ether 22:7e:11:52:c0:5c brd ff:ff:ff:ff:ff:ff - inet6 fe80::bc16:11ff:fea9:78a4/64 scope link - valid_lft forever preferred_lft forever - 23: intf2@if24: mtu 1500 qdisc noqueue master admin-br state UP group default qlen 1000 - link/ether e2:94:dc:27:55:9d brd ff:ff:ff:ff:ff:ff link-netnsid 0 - inet6 fe80::e094:dcff:fe27:559d/64 scope link - valid_lft forever preferred_lft forever - 25: intf4@if26: mtu 1500 qdisc noqueue master admin-br state UP group default qlen 1000 - link/ether be:16:11:a9:78:a4 brd ff:ff:ff:ff:ff:ff link-netnsid 1 - inet6 fe80::bc16:11ff:fea9:78a4/64 scope link - valid_lft forever preferred_lft forever - 27: vx_21: mtu 1500 qdisc noqueue master admin-br state UNKNOWN group default qlen 1000 - link/ether 22:7e:11:52:c0:5c brd ff:ff:ff:ff:ff:ff - inet6 fe80::207e:11ff:fe52:c05c/64 scope link - valid_lft forever preferred_lft forever - 28: intf10: mtu 1500 qdisc noqueue state UP group default qlen 1000 - link/ether 2a:54:21:60:79:c5 brd ff:ff:ff:ff:ff:ff - inet6 fe80::9030:e2ff:fedb:b323/64 scope link - valid_lft forever preferred_lft forever - 29: intf9@if30: mtu 1500 qdisc noqueue master intf10 state UP group default qlen 1000 - link/ether 92:30:e2:db:b3:23 brd ff:ff:ff:ff:ff:ff link-netnsid 0 - inet6 fe80::9030:e2ff:fedb:b323/64 scope link - valid_lft forever preferred_lft forever - 31: intf12: mtu 1500 qdisc noqueue state UP group default qlen 1000 - link/ether 6e:c6:34:19:9e:cc brd ff:ff:ff:ff:ff:ff - inet6 fe80::6cc6:34ff:fe19:9ecc/64 scope link - valid_lft forever preferred_lft forever - 32: intf11@if33: mtu 1500 qdisc noqueue master intf12 state UP group default qlen 1000 - link/ether 6e:c6:34:19:9e:cc brd ff:ff:ff:ff:ff:ff link-netnsid 1 - inet6 fe80::6cc6:34ff:fe19:9ecc/64 scope link - valid_lft forever preferred_lft forever - 34: vintf12@vintf10: mtu 1500 qdisc noqueue master intf12 state UP group default qlen 1000 - link/ether b2:c1:38:57:4c:ca brd ff:ff:ff:ff:ff:ff - inet6 fe80::b0c1:38ff:fe57:4cca/64 scope link - valid_lft forever preferred_lft forever - 35: vintf10@vintf12: mtu 1500 qdisc noqueue master intf10 state UP group default qlen 1000 - link/ether 2a:54:21:60:79:c5 brd ff:ff:ff:ff:ff:ff - inet6 fe80::2854:21ff:fe60:79c5/64 scope link - valid_lft forever preferred_lft forever - 36: intf14: mtu 1500 qdisc noqueue state UP group default qlen 1000 - link/ether 0e:fd:28:ce:0e:8d brd ff:ff:ff:ff:ff:ff - inet6 fe80::cfd:28ff:fece:e8d/64 scope link - valid_lft forever preferred_lft forever - 37: intf13@if38: mtu 1500 qdisc noqueue master intf14 state UP group default qlen 1000 - link/ether 0e:fd:28:ce:0e:8d brd ff:ff:ff:ff:ff:ff link-netnsid 1 - inet6 fe80::cfd:28ff:fece:e8d/64 scope link - valid_lft forever preferred_lft forever - 39: vx_26: mtu 1500 qdisc noqueue master intf14 state UNKNOWN group default qlen 1000 - link/ether 86:5e:28:6d:96:ea brd ff:ff:ff:ff:ff:ff - inet6 fe80::845e:28ff:fe6d:96ea/64 scope link - valid_lft forever preferred_lft forever - ``` - # ![worker container](https://github.com/J980419xq/Distrinet/blob/master/images/worker.png) - - - From 10d15e752f06bc2478191bd7bf795a61ec7bc776 Mon Sep 17 00:00:00 2001 From: J980419xq <62777661+J980419xq@users.noreply.github.com> Date: Wed, 25 May 2022 13:28:34 +0800 Subject: [PATCH 12/44] Add files via upload --- docker.md | 214 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 docker.md diff --git a/docker.md b/docker.md new file mode 100644 index 00000000..b3d609b0 --- /dev/null +++ b/docker.md @@ -0,0 +1,214 @@ + +This document is the development and testing document for `issue25:Investigate the possibility of replacing lxc/lxd with docker` . + +* Figure out the detail steps to replace lxc/lxd engine with docker engine. + > The replacement process can be divided into two steps + > * Change the environment of lxd in the master and workers to docker + > * Change the deployment and configuration commands of the lxd container in the master and workers to the commands with the same function under docker + +* Study files under Distrinet/mininet/provision folder. + > Distrinet provides an infrastructure provisioning mechanism that uses Ansible to automatically install and configure LXD on each machine to be used during the experiment. + > * install-lxd.yml:this file is used to install lxd and download two images(an Ubuntu:18.04 image to emulate the vHosts, and a modified version of that image with OVS installed)on each machine by Ansible,we change it to install docker,and these two images need to be remade according to Docker,the OVS process will be described in the ovs_image.md. + > * configure-lxd-no-clustering.yml:this file is used to configure lxd init,but you don't neet to do it in docker,so we only use it to distribute and load the above two images. + +* Create related files (config, deploy, install, etc) for docker provision by referring lxd scenario + >install-docker.yml:install-lxd.yml's docker version + ``` + ansible-playbook ~/install-docker.yml + ``` + >configure-docker.yml: + ``` + ansible-playbook ~/configure-docker.yml: + ``` + >Reading through all the code in the LXD scenario, we can see that the creation and configuration of containers and the creation of network interfaces and links are mainly concentrated in lxc_cotainer.py and distrinet.py,We need to replace the code that uses LXC/LXD with a docker equivalent command + + >As for the network interfaces and links,we'll discuss this in more detail in issue33,In addition,for container creation and configuration, you can keep an eye out for lXC_container.py changes.The most critical one is that we use a pair of virtual devices veth pair and a bridge to replace lXC network attach command.Besides,We use namespaces to attach one end of veth pair to the container. + + >We don't change the lxc_container.py's name,because this file is referenced several times in the project.We added an autoSetDocker parameter to this file, which allows you to choose whether to use docker or not.This parameter is passed by the external command --docker when Distrinet is runned in client + +* The Distrinet environment replaced by docker includes the three following entities + * Client: host in which the Distrinet script is running and decides where to place the vNodes around the physical infrastructure (round-robin by default). The Client must be able to connect via SSH to the Master host. + * Master: host that acts as a relay to interconnect the Client with all the Worker hosts. It communicates with the Client and the different Workers via SSH. Note that the Master can also be configured as a Worker. + * Worker(s): host(s) where all the vNodes (vSwitches and vHosts) are running. vNodes are managed by the Master and the Client, via the admin network. + > To ensure the smooth deployment of vNodes, Ip forwarding needs to be allowed on workers and the netns of the container needs to be restored to the host directory,here are a few commands that you might configure on workers and Master. + ``` + sysctl net.ipv4.conf.all.forwarding=1 + iptables --policy FORWARD ACCEPT + mkdir /var/run/netns + ``` + +* Experimental environment Configuration + >clinet:192.168.71.128,master:192.168.71.141,worker:192.168.71.142.They are all Ubuntu virtual machines running on the same physical host + >We use distrinet to create a linear topology with two switches and two hosts, i.e. : + >Master: + ``` + root@master:~# ryu-manager /usr/lib/python3/dist-packages/ryu/app/simple_switch_13.py --verbose + ``` + >client: + ``` + jxq@client:~$ python3 bin/dmn --workers="192.168.71.141,192.168.71.142" --controller=lxcremote,ip=192.168.0.1 --topo=linear,2 --docker + ``` + +* Experimental results + >Distrinet's CLI can be generated normally and pingall test also passes + # ![client](https://github.com/J980419xq/Distrinet/blob/master/images/cli.png) + >The master and worker can create containers and interfaces normally + >master: ip a + ``` + 1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 + link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 + inet 127.0.0.1/8 scope host lo + valid_lft forever preferred_lft forever + inet6 ::1/128 scope host + valid_lft forever preferred_lft forever + 2: ens33: mtu 1500 qdisc fq_codel state UP group default qlen 1000 + link/ether 00:0c:29:eb:10:f4 brd ff:ff:ff:ff:ff:ff + inet 192.168.71.141/24 brd 192.168.71.255 scope global noprefixroute ens33 + valid_lft forever preferred_lft forever + inet6 fe80::20c:29ff:feeb:10f4/64 scope link + valid_lft forever preferred_lft forever + 3: docker0: mtu 1500 qdisc noqueue state DOWN group default + link/ether 02:42:29:d0:a1:78 brd ff:ff:ff:ff:ff:ff + inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 + valid_lft forever preferred_lft forever + inet6 fe80::42:29ff:fed0:a178/64 scope link + valid_lft forever preferred_lft forever + 26: admin-br: mtu 1500 qdisc noqueue state UP group default qlen 1000 + link/ether 72:97:2f:43:4c:cb brd ff:ff:ff:ff:ff:ff + inet 192.168.0.1/8 brd 192.255.255.255 scope global admin-br + valid_lft forever preferred_lft forever + inet6 fe80::80f7:25ff:fe05:b735/64 scope link + valid_lft forever preferred_lft forever + 27: intf3@if28: mtu 1500 qdisc noqueue master admin-br state UP group default qlen 1000 + link/ether 72:97:2f:43:4c:cb brd ff:ff:ff:ff:ff:ff link-netnsid 0 + inet6 fe80::7097:2fff:fe43:4ccb/64 scope link + valid_lft forever preferred_lft forever + 29: intf1@if30: mtu 1500 qdisc noqueue master admin-br state UP group default qlen 1000 + link/ether 9a:aa:18:f7:72:0b brd ff:ff:ff:ff:ff:ff link-netnsid 1 + inet6 fe80::98aa:18ff:fef7:720b/64 scope link + valid_lft forever preferred_lft forever + 31: vNone@vadmin-br: mtu 1500 qdisc noqueue state UP group default qlen 1000 + link/ether 36:9f:9e:c7:9b:52 brd ff:ff:ff:ff:ff:ff + inet6 fe80::349f:9eff:fec7:9b52/64 scope link + valid_lft forever preferred_lft forever + 32: vadmin-br@vNone: mtu 1500 qdisc noqueue master admin-br state UP group default qlen 1000 + link/ether a2:06:41:fd:a4:7c brd ff:ff:ff:ff:ff:ff + inet6 fe80::a006:41ff:fefd:a47c/64 scope link + valid_lft forever preferred_lft forever + 33: vx_21: mtu 1500 qdisc noqueue master admin-br state UNKNOWN group default qlen 1000 + link/ether 9e:3b:48:ef:89:6f brd ff:ff:ff:ff:ff:ff + inet6 fe80::9c3b:48ff:feef:896f/64 scope link + valid_lft forever preferred_lft forever + 34: intf6: mtu 1500 qdisc noqueue state UP group default qlen 1000 + link/ether c2:e5:e4:21:a2:78 brd ff:ff:ff:ff:ff:ff + inet6 fe80::c0e5:e4ff:fe21:a278/64 scope link + valid_lft forever preferred_lft forever + 35: intf5@if36: mtu 1500 qdisc noqueue master intf6 state UP group default qlen 1000 + link/ether c2:e5:e4:21:a2:78 brd ff:ff:ff:ff:ff:ff link-netnsid 1 + inet6 fe80::c0e5:e4ff:fe21:a278/64 scope link + valid_lft forever preferred_lft forever + 37: intf8: mtu 1500 qdisc noqueue state UP group default qlen 1000 + link/ether a6:0f:bc:97:d5:4d brd ff:ff:ff:ff:ff:ff + inet6 fe80::f4e0:f3ff:fe8f:37f5/64 scope link + valid_lft forever preferred_lft forever + 38: intf7@if39: mtu 1500 qdisc noqueue master intf8 state UP group default qlen 1000 + link/ether f6:e0:f3:8f:37:f5 brd ff:ff:ff:ff:ff:ff link-netnsid 0 + inet6 fe80::f4e0:f3ff:fe8f:37f5/64 scope link + valid_lft forever preferred_lft forever + 40: vintf8@vintf6: mtu 1500 qdisc noqueue master intf8 state UP group default qlen 1000 + link/ether a6:0f:bc:97:d5:4d brd ff:ff:ff:ff:ff:ff + inet6 fe80::a40f:bcff:fe97:d54d/64 scope link + valid_lft forever preferred_lft forever + 41: vintf6@vintf8: mtu 1500 qdisc noqueue master intf6 state UP group default qlen 1000 + link/ether e6:31:f4:e8:39:38 brd ff:ff:ff:ff:ff:ff + inet6 fe80::e431:f4ff:fee8:3938/64 scope link + valid_lft forever preferred_lft forever + 42: intf16: mtu 1500 qdisc noqueue state UP group default qlen 1000 + link/ether 4e:63:dc:70:fd:e0 brd ff:ff:ff:ff:ff:ff + inet6 fe80::b085:44ff:fed3:599/64 scope link + valid_lft forever preferred_lft forever + 43: intf15@if44: mtu 1500 qdisc noqueue master intf16 state UP group default qlen 1000 + link/ether b2:85:44:d3:05:99 brd ff:ff:ff:ff:ff:ff link-netnsid 0 + inet6 fe80::b085:44ff:fed3:599/64 scope link + valid_lft forever preferred_lft forever + 45: vx_26: mtu 1500 qdisc noqueue master intf16 state UNKNOWN group default qlen 1000 + link/ether 4e:63:dc:70:fd:e0 brd ff:ff:ff:ff:ff:ff + inet6 fe80::4c63:dcff:fe70:fde0/64 scope link + valid_lft forever preferred_lft forever + ``` + # ![master container](https://github.com/J980419xq/Distrinet/blob/master/images/master.png) + >worker: ip a + ``` + 1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 + link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 + inet 127.0.0.1/8 scope host lo + valid_lft forever preferred_lft forever + inet6 ::1/128 scope host + valid_lft forever preferred_lft forever + 2: ens33: mtu 1500 qdisc fq_codel state UP group default qlen 1000 + link/ether 00:0c:29:ae:98:b2 brd ff:ff:ff:ff:ff:ff + inet 192.168.71.142/24 brd 192.168.71.255 scope global noprefixroute ens33 + valid_lft forever preferred_lft forever + inet6 fe80::20c:29ff:feae:98b2/64 scope link + valid_lft forever preferred_lft forever + 3: docker0: mtu 1500 qdisc noqueue state DOWN group default + link/ether 02:42:5a:e8:15:54 brd ff:ff:ff:ff:ff:ff + inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 + valid_lft forever preferred_lft forever + 22: admin-br: mtu 1500 qdisc noqueue state UP group default qlen 1000 + link/ether 22:7e:11:52:c0:5c brd ff:ff:ff:ff:ff:ff + inet6 fe80::bc16:11ff:fea9:78a4/64 scope link + valid_lft forever preferred_lft forever + 23: intf2@if24: mtu 1500 qdisc noqueue master admin-br state UP group default qlen 1000 + link/ether e2:94:dc:27:55:9d brd ff:ff:ff:ff:ff:ff link-netnsid 0 + inet6 fe80::e094:dcff:fe27:559d/64 scope link + valid_lft forever preferred_lft forever + 25: intf4@if26: mtu 1500 qdisc noqueue master admin-br state UP group default qlen 1000 + link/ether be:16:11:a9:78:a4 brd ff:ff:ff:ff:ff:ff link-netnsid 1 + inet6 fe80::bc16:11ff:fea9:78a4/64 scope link + valid_lft forever preferred_lft forever + 27: vx_21: mtu 1500 qdisc noqueue master admin-br state UNKNOWN group default qlen 1000 + link/ether 22:7e:11:52:c0:5c brd ff:ff:ff:ff:ff:ff + inet6 fe80::207e:11ff:fe52:c05c/64 scope link + valid_lft forever preferred_lft forever + 28: intf10: mtu 1500 qdisc noqueue state UP group default qlen 1000 + link/ether 2a:54:21:60:79:c5 brd ff:ff:ff:ff:ff:ff + inet6 fe80::9030:e2ff:fedb:b323/64 scope link + valid_lft forever preferred_lft forever + 29: intf9@if30: mtu 1500 qdisc noqueue master intf10 state UP group default qlen 1000 + link/ether 92:30:e2:db:b3:23 brd ff:ff:ff:ff:ff:ff link-netnsid 0 + inet6 fe80::9030:e2ff:fedb:b323/64 scope link + valid_lft forever preferred_lft forever + 31: intf12: mtu 1500 qdisc noqueue state UP group default qlen 1000 + link/ether 6e:c6:34:19:9e:cc brd ff:ff:ff:ff:ff:ff + inet6 fe80::6cc6:34ff:fe19:9ecc/64 scope link + valid_lft forever preferred_lft forever + 32: intf11@if33: mtu 1500 qdisc noqueue master intf12 state UP group default qlen 1000 + link/ether 6e:c6:34:19:9e:cc brd ff:ff:ff:ff:ff:ff link-netnsid 1 + inet6 fe80::6cc6:34ff:fe19:9ecc/64 scope link + valid_lft forever preferred_lft forever + 34: vintf12@vintf10: mtu 1500 qdisc noqueue master intf12 state UP group default qlen 1000 + link/ether b2:c1:38:57:4c:ca brd ff:ff:ff:ff:ff:ff + inet6 fe80::b0c1:38ff:fe57:4cca/64 scope link + valid_lft forever preferred_lft forever + 35: vintf10@vintf12: mtu 1500 qdisc noqueue master intf10 state UP group default qlen 1000 + link/ether 2a:54:21:60:79:c5 brd ff:ff:ff:ff:ff:ff + inet6 fe80::2854:21ff:fe60:79c5/64 scope link + valid_lft forever preferred_lft forever + 36: intf14: mtu 1500 qdisc noqueue state UP group default qlen 1000 + link/ether 0e:fd:28:ce:0e:8d brd ff:ff:ff:ff:ff:ff + inet6 fe80::cfd:28ff:fece:e8d/64 scope link + valid_lft forever preferred_lft forever + 37: intf13@if38: mtu 1500 qdisc noqueue master intf14 state UP group default qlen 1000 + link/ether 0e:fd:28:ce:0e:8d brd ff:ff:ff:ff:ff:ff link-netnsid 1 + inet6 fe80::cfd:28ff:fece:e8d/64 scope link + valid_lft forever preferred_lft forever + 39: vx_26: mtu 1500 qdisc noqueue master intf14 state UNKNOWN group default qlen 1000 + link/ether 86:5e:28:6d:96:ea brd ff:ff:ff:ff:ff:ff + inet6 fe80::845e:28ff:fe6d:96ea/64 scope link + valid_lft forever preferred_lft forever + ``` + # ![worker container](https://github.com/J980419xq/Distrinet/blob/master/images/worker.png) + + + From 8d56c79300859d051ace2ff86c6d81a969dfdc57 Mon Sep 17 00:00:00 2001 From: J980419xq <62777661+J980419xq@users.noreply.github.com> Date: Wed, 1 Jun 2022 09:23:09 +0800 Subject: [PATCH 13/44] Delete ovs_image.md --- ovs_image.md | 157 --------------------------------------------------- 1 file changed, 157 deletions(-) delete mode 100644 ovs_image.md diff --git a/ovs_image.md b/ovs_image.md deleted file mode 100644 index 037de67c..00000000 --- a/ovs_image.md +++ /dev/null @@ -1,157 +0,0 @@ -本文档为创建并打包`ovs_image`çš„`docker`é•œåƒæ–‡æ¡£çš„æ•™ç¨‹ã€‚ - -[toc] - -## 嫿œ‰ovsçš„docker容器创建 - -第一部分为新建`docker`容器,并在容器内安装`openvswitch`。 - -### 1.创建容器 - -- 新建`docker`容器,使用镜åƒ`ubuntu:18.04`,命å为`ovs`: - -```shell -docker run -it --privileged --name ovs ubuntu:18.04 -``` - -此步在虚拟机中完æˆï¼Œæ­¤éƒ¨åˆ†å…¶ä½™æ­¥éª¤å‡åœ¨`ovs` `docker`容器中完æˆã€‚ - - - -### 2.下载ovs - -- æ›´æ–°`apt`,安装`git`并下载`openvswitch`:(以下步骤å‡åœ¨å®¹å™¨å†…) - -```shell -apt update -apt install git -git clone https://github.com/openvswitch/ovs.git -``` - -下载完æˆåŽï¼Œä¼šåœ¨å½“å‰ç›®å½•ç”Ÿæˆæ–‡ä»¶å¤¹`/ovs`。 - - - -### 3.安装相关ä¾èµ– - -- 安装相关ä¾èµ–包: - -```shell -apt install make gcc python3 - -# 安装libsslã€libcap-ngã€unbound -apt install libssl-dev libcap-ng-utils unbound - -# 安装autoconfã€libtool -apt install autoconf libtool -``` - -注:安装`unbound`包时å¯èƒ½ä¼šå‡ºçŽ°ä»¥ä¸‹æŠ¥é”™ï¼š - -```shell -Err:1 http://archive.ubuntu.com/ubuntu bionic/universe amd64 libfstrm0 amd64 0.3.0-1build1 - Connection failed [IP: 91.189.91.38 80] -``` - -此时需è¦å¯¹å®¹å™¨è¿›è¡Œæ¢æºï¼š - -```shell -cp /etc/apt/sources.list /etc/apt/sources.list.backup -rm /etc/apt/sources.list -#é˜¿é‡Œäº‘æº -echo -e "deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse\ndeb-src http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse\n" >> /etc/apt/sources.list -apt update -apt upgrade - -#æ¢æºåŽé‡æ–°å®‰è£…unbound -apt install unbound -``` - - - -### 4.编译安装ovsåŠåˆå§‹åŒ– - -- 编译安装`ovs`: - -```shell -cd /ovs -./boot.sh -./configure -make -make install -``` - -- åˆå§‹åŒ–`ovs`æ•°æ®åº“: - -```shell -mkdir -p /usr/local/etc/penvswitch -ovsdb-tool create /usr/local/etc/openvswitch/conf.db vswitchd/vswitch.ovsschema - -export PATH=$PATH:/usr/local/share/openvswitch/scripts -ovs-ctl start -ovsdb-server --remote=punix:/usr/local/var/run/openvswitch/db.sock \ - --remote=db:Open_vSwitch,Open_vSwitch,manager_options \ - --private-key=db:Open_vSwitch,SSL,private_key \ - --certificate=db:Open_vSwitch,SSL,certificate \ - --bootstrap-ca-cert=db:Open_vSwitch,SSL,ca_cert \ - --pidfile --detach -ovs-vsctl --no-wait init -ovs-vswitchd --pidfile --detach -``` - -- 安装完æˆï¼ŒéªŒè¯ï¼š - -```shell -ovs-vsctl --version -ovs-appctl --version -ovs-appctl version -``` - - - -## é•œåƒæ‰“包 - -第二部分为将第一部分创建的容器打包æˆé•œåƒã€‚ - - - -### 1.退出docker容器 - -ç›®å‰é»˜è®¤ä»åœ¨å®¹å™¨ä¸­ï¼Œä½¿ç”¨å¿«æ·é”®`ctrl+p ctrl+q`退出容器。 - - - -### 2.将容器ä¿å­˜ä¸ºé•œåƒ - -```shell -docker commit [-m "æäº¤çš„æè¿°ä¿¡æ¯"] [-a "创建者"] 容器åç§°|容器ID 生æˆçš„镜åƒå[:标签å] - -# 注释: -## []为å¯é€‰é¡¹ -## -m= : ä¸ºé•œåƒæ·»åŠ æè¿°ä¿¡æ¯ -## -a= : ä¸ºé•œåƒæ·»åŠ åˆ›å»ºè€…ä¿¡æ¯ -## 容器åç§°|容器ID : 当å‰è¦è¢«æ‰“包的容器å称或容器ID -## 生æˆçš„镜åƒå[:标签å] : 指定镜åƒå称或标签åç§° - -# 本例: -docker commit -m "ovs_image" -a "ycyz" ovs ovs_image -``` - -执行该命令åŽï¼Œé•œåƒ`ovs_image`制作æˆåŠŸï¼Œè¿è¡Œå¦‚下命令查看所有`docker`镜åƒï¼š - -```shell -docker images -``` - - - -### 3. tar压缩文件打包 - -è‹¥éœ€è¦æ‰“包æˆ`tar`压缩文件,è¿è¡Œå¦‚下命令: - -```shell -# 进入目标目录 -cd /home/sdn/Desktop -# 打包tar压缩文件 -docker export ovs > ovs_image.tar -``` From 6c6075fd057ea3742803600131fc0217cc40cbce Mon Sep 17 00:00:00 2001 From: J980419xq <62777661+J980419xq@users.noreply.github.com> Date: Sun, 19 Jun 2022 00:06:23 +0800 Subject: [PATCH 14/44] Update docker.md --- docker.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docker.md b/docker.md index b3d609b0..5e1e2f4e 100644 --- a/docker.md +++ b/docker.md @@ -35,6 +35,7 @@ This document is the development and testing document for `issue25:Investigate t sysctl net.ipv4.conf.all.forwarding=1 iptables --policy FORWARD ACCEPT mkdir /var/run/netns + ulimit -n 196835 ``` * Experimental environment Configuration From 2417b92207c446d58d846384f3afc161a1954f1e Mon Sep 17 00:00:00 2001 From: J980419xq <1908393204@qq.com> Date: Mon, 20 Jun 2022 17:11:37 +0800 Subject: [PATCH 15/44] 2022-6-20 --- mininet/custom/fat-tree.py | 91 +++++++++++++++++++ mininet/mininet/lxc_container.py | 3 +- .../playbooks/configure-lxd-no-clustering.yml | 24 +++-- 3 files changed, 107 insertions(+), 11 deletions(-) create mode 100644 mininet/custom/fat-tree.py diff --git a/mininet/custom/fat-tree.py b/mininet/custom/fat-tree.py new file mode 100644 index 00000000..14f5ef16 --- /dev/null +++ b/mininet/custom/fat-tree.py @@ -0,0 +1,91 @@ +from xml.dom.expatbuilder import theDOMImplementation +from mininet.topo import Topo +from mininet.net import Mininet +from mininet.node import RemoteController +from mininet.link import TCLink +from mininet.util import dumpNodeConnections + +# Standard fattree topology: +# Fat tree is a switch centric topology. Support to expand the number of paths while expanding horizontally; All switches are common devices with the same number of ports, which reduces the network construction cost. +# Specifically, the fattree structure is divided into three layers: core layer (core switch), aggregation layer (aggregation switch) and access layer (edge switch). A K-ary fattree can be summarized into five features: +# 1. Each switch has K ports; +# 2. The core layer is the top layer, with a total of (K/2) ^2 switches; +# 3. There are K pods in total, and each pod is composed of K switches. The aggregation layer and access layer account for K/2 switches respectively; +# 4. Each switch in the access layer can accommodate K/2 servers. thus, the K-ary fattree has a total of K pods, each pod can accommodate K*K/4 servers, and all pods can accommodate K*K*K/4 servers; +# 5. There are K paths between any two pods. +# In other words, there are (K/2)^2+K^2 switches and (K^3)/4 servers in the K-ary fattree topology +# The relationship between the value of K in the fattree topology and the number of switches and servers is summarized as follows: +# --------------------------------------------------------------------------------------------------------- +# Value of K | 2 | 4 | 6 | 8 | 10 | 12 | 14 | 16 | 32 | 64 +# Number of switches | 5 | 20 | 45 | 80 | 125 | 180 | 245 | 320 | 1280| 5120 +# Number of servers | 2 | 16 | 54 | 128 | 250 | 432 | 686 | 1024| 8192| 65536 +# --------------------------------------------------------------------------------------------------------- +# Custom fattree topology: +# To enable this script to support a larger topology, we add an additional parameter S to control the number of servers that each edge switch can connect to. +# In this case, there are (K/2)^2+K^2 switches and (K/2)*K*S servers in the K-ary custom topology (the valus of S in standard fattree topology is K//2). +# The relationship between the value of K, the value of S and the number of switches and servers is summarized as follows: +# --------------------------------------------------------------------------------------------------------- +# Value of K | 2 | 4 | 6 | 8 | 10 | 12 | 14 | 16 | 32 | 64 +# Number of switches | 5 | 20 | 45 | 80 | 125 | 180 | 245 | 320 | 1280| 5120 +# Number of servers | 2S | 8S | 18S | 32S | 50S | 72S | 98S | 128S| 512S| 2048S +# --------------------------------------------------------------------------------------------------------- + +class MyTopo(Topo): + + def __init__(self): + super(MyTopo, self).__init__() + + # K setting + K = 4 + + # S setting + S = K//2 + + + # Marking the number of switch for per level + pod = K + L1 = (pod//2)**2 + L2 = pod*pod//2 + L3 = L2 + + # Starting create the switch + c = [] # core switch + a = [] # aggregate switch + e = [] # edge switch + + # notice: switch label is a special data structure + for i in range(L1): + # label from 1 to n,not start with 0 + c_sw = self.addSwitch('c{}'.format(i+1)) + c.append(c_sw) + + for i in range(L2): + a_sw = self.addSwitch('a{}'.format(L1+i+1)) + a.append(a_sw) + + for i in range(L3): + e_sw = self.addSwitch('e{}'.format(L1+L2+i+1)) + e.append(e_sw) + + # Starting create the link between switchs + # first the L1 level and L2 level link + for i in range(L1): + c_sw = c[i] + start = i % (pod//2) + for j in range(pod): + self.addLink(c_sw, a[start+j*(pod//2)]) + + # second the L2 level and L3 level link + for i in range(L2): + group = i//(pod//2) + for j in range(pod//2): + self.addLink(a[i], e[group*(pod//2)+j]) + + # Starting create the host and create link between switchs and hosts + for i in range(L3): + for j in range(S): + hs = self.addHost('h{}'.format(i*S+j+1)) + self.addLink(e[i], hs) + + +topos = {"mytopo": (lambda: MyTopo())} diff --git a/mininet/mininet/lxc_container.py b/mininet/mininet/lxc_container.py index ac294e9d..9873f82f 100644 --- a/mininet/mininet/lxc_container.py +++ b/mininet/mininet/lxc_container.py @@ -349,7 +349,7 @@ def createContainer(self,autoSetDocker=False, **params): cmds = [] # initialise the container if autoSetDocker: - cmd = "docker run --privileged -itd --name {} --net=none {}".format(self.name, self.image) + cmd = "docker create -v /root/alcor-control-agent/:/mnt/host/code -it --privileged --cap-add=NET_ADMIN --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --name {} --net=none {} /bin/bash".format(self.name, self.image) else: cmd = "lxc init {} {} < /dev/null ".format(self.image, self.name) info ("{}\n".format(cmd)) @@ -366,6 +366,7 @@ def createContainer(self,autoSetDocker=False, **params): cmds.append("docker start {}".format(self.name)) if self.image=="switch": cmds.append("docker exec {} bash -c 'export PATH=$PATH:/usr/share/openvswitch/scripts;ovs-ctl start'".format(self.name)) + cmds.append("docker exec {} sh /root/init.sh".format(self.name)) cmds.append("docker exec {} mkdir /root/.ssh".format(self.name)) cmds.append("docker exec {} bash -c 'echo \"{}\" >> /root/.ssh/authorized_keys'".format(self.name, self.pub_id)) cmds.append("docker exec {} service ssh start".format(self.name)) diff --git a/mininet/mininet/provision/playbooks/configure-lxd-no-clustering.yml b/mininet/mininet/provision/playbooks/configure-lxd-no-clustering.yml index 87405346..cf1a47c9 100644 --- a/mininet/mininet/provision/playbooks/configure-lxd-no-clustering.yml +++ b/mininet/mininet/provision/playbooks/configure-lxd-no-clustering.yml @@ -12,15 +12,19 @@ (?i)Would you like to use LXD clustering? : "no" (?i)Do you want to configure a new storage pool? : "yes" (?i)Name of the new storage pool : "default" - (?i)Name of the storage backend to use : "dir" + (?i)Name of the storage backend to use : "zfs" + (?i)Create a new BTRFS pool? : "yes" + (?i)Create a new ZFS pool : "yes" + (?i)Would you like to use an existing block device? : "no" + (?i)Would you like to use an existing empty block device : "no" (?i)Would you like to connect to a MAAS server? : "no" - (?i)Would you like to create a new local network bridge? : "yes" - (?i)What should the new bridge be called? : "lxdbr0" - (?i)What IPv4 address should be used? : "auto" - (?i)What IPv6 address should be used? : "auto" - (?i)Would you like LXD to be available over the network? : "no" - (?i)Would you like stale cached images to be updated automatically? : "yes" - (?i)Would you like a YAML "lxd init" preseed to be printed? : "no" + (?i)Size in GB of the new loop device : "15GB" + (?i)Would you like to configure LXD to use an existing bridge or host interface?: "no" + (?i)Would you like to create a new local network bridge? : "no" + (?i)Would you like LXD to be available over the network : "no" + (?i)Would you like the LXD server to be available over the network : "no" + (?i)Would you like stale cached images to be updated automatically? : "no" + (?i)Would you like a YAML : "no" - hosts : all @@ -36,7 +40,7 @@ src : ~/ubuntu.tar.gz dest : ~/ubuntu.tar.gz -### - name : distribute debian image +# - name : distribute debian image # copy : # src : ~/debian.tar.gz # dest : ~/debian.tar.gz @@ -52,7 +56,7 @@ # dest : ~/ubuntu-hadoop-slave.tar.gz -# - name : distribute onos image +# - name : distribute onos image # copy : # src : ~/ubuntu-onos-2.1.0.tar.gz # dest : ~/ubuntu-onos-2.1.0.tar.gz From 4941cf87a39d3052999d017a6d151ae5f29c6d94 Mon Sep 17 00:00:00 2001 From: J980419xq <1908393204@qq.com> Date: Tue, 21 Jun 2022 22:15:27 +0800 Subject: [PATCH 16/44] 2022-6-21 --- mininet/mininet/lxc_container.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/mininet/mininet/lxc_container.py b/mininet/mininet/lxc_container.py index 9873f82f..7f7031e0 100644 --- a/mininet/mininet/lxc_container.py +++ b/mininet/mininet/lxc_container.py @@ -38,7 +38,6 @@ def genIntfName(): class LxcNode (Node): """ SSH node - Attributes ---------- name : str @@ -75,7 +74,6 @@ class LxcNode (Node): STDOUT of the process stderr : asyncssh.stream.SSHReader STDERR of the process - master : ASsh SSH connection to the master containerInterfaces : dict @@ -366,7 +364,7 @@ def createContainer(self,autoSetDocker=False, **params): cmds.append("docker start {}".format(self.name)) if self.image=="switch": cmds.append("docker exec {} bash -c 'export PATH=$PATH:/usr/share/openvswitch/scripts;ovs-ctl start'".format(self.name)) - cmds.append("docker exec {} sh /root/init.sh".format(self.name)) + cmds.append("docker exec {} bash -c 'cd /mnt/host/code;/etc/init.d/openvswitch-switch restart;ovs-vswitchd --pidfile --detach'".format(self.name)) cmds.append("docker exec {} mkdir /root/.ssh".format(self.name)) cmds.append("docker exec {} bash -c 'echo \"{}\" >> /root/.ssh/authorized_keys'".format(self.name, self.pub_id)) cmds.append("docker exec {} service ssh start".format(self.name)) @@ -682,4 +680,3 @@ async def _pexec(self, *args, **kwargs): exitcode = process.returncode return out, err, exitcode - From 2474b41484380425e573da08ca55b0798ed48663 Mon Sep 17 00:00:00 2001 From: J980419xq <62777661+J980419xq@users.noreply.github.com> Date: Wed, 13 Jul 2022 21:08:24 +0800 Subject: [PATCH 17/44] k8_onos --- k8s.md | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 k8s.md diff --git a/k8s.md b/k8s.md new file mode 100644 index 00000000..0e8a0991 --- /dev/null +++ b/k8s.md @@ -0,0 +1,69 @@ +### Step 1: deploy onos cluster in k8s +```bash +vim onos.yaml +``` +``` +#onos.yaml +apiVersion: v1 +kind: Service +metadata: + labels: + app: onos + name: onos-deployment +spec: + ports: + - port: 6653 + protocol: TCP + targetPort: 6653 + nodePort: 30026 + selector: + app: onos + type: NodePort +status: + loadBalancer: {} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: onos + name: onos-deployment +spec: + replicas: 10 + selector: + matchLabels: + app: onos + template: + metadata: + labels: + app: onos + spec: + containers: + - name: onos + image: onosproject/onos + env: + - name: ONOS_APPS + value: "drivers,openflow,fwd,proxyarp,lldpprovider" + args: + - start + ports: + - containerPort: 6653 + name: openflow + - containerPort: 6640 + name: ovsdb + - containerPort: 8181 + name: gui + - containerPort: 8101 + name: onos-cli + - containerPort: 9876 + name: cluster +``` + +```bash +kubectl create -f onos.yaml +``` + +### Step 2: using k8s' onos service as distrinet controller +```bash +python3 bin/dmn --bastion=172.16.66.92 --workers="172.16.66.92,172.16.66.93,172.16.66.94" --controller=lxcremote,ip=192.168.0.1:30026 --topo=linear,2 +``` From e298e84406a0d6e67db5585cf41895fce195d35b Mon Sep 17 00:00:00 2001 From: J980419xq <1908393204@qq.com> Date: Sat, 16 Jul 2022 01:29:54 +0800 Subject: [PATCH 18/44] 2022-7-16 --- mininet/bin/dmn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mininet/bin/dmn b/mininet/bin/dmn index 074db4cd..5e9437d9 100755 --- a/mininet/bin/dmn +++ b/mininet/bin/dmn @@ -557,7 +557,7 @@ class DistrinetRunner( object ): host, switch, link = LxcNode, LxcOVSSwitch, CloudLink ## - adminIpBase='192.168.0.1/8' + adminIpBase='192.168.100.1/8' waitConnected=False build=False if not opts.placement_file_path: From 7f603e413e83a216e8a511b95b1a62a17d89ba25 Mon Sep 17 00:00:00 2001 From: J980419xq <1908393204@qq.com> Date: Sat, 16 Jul 2022 14:01:36 +0800 Subject: [PATCH 19/44] workers=workers[1:] --- mininet/bin/dmn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mininet/bin/dmn b/mininet/bin/dmn index 5e9437d9..1801422e 100755 --- a/mininet/bin/dmn +++ b/mininet/bin/dmn @@ -298,7 +298,7 @@ class DistrinetRunner( object ): dest='test', help='|'.join( TESTS.keys() ) ) opts.add_option( '--xterms', '-x', action='store_true', default=False, help='spawn xterms for each node' ) - opts.add_option( '--ipbase', '-i', type='string', default='10.0.0.0/8', + opts.add_option( '--ipbase', '-i', type='string', default='12.0.0.0/8', help='base IP address for hosts' ) opts.add_option( '--mac', action='store_true', default=False, help='automatically set host MACs' ) From 212cbba9e40bc332adb3021ae7334fca9497491a Mon Sep 17 00:00:00 2001 From: J980419xq <1908393204@qq.com> Date: Sat, 16 Jul 2022 20:46:23 +0800 Subject: [PATCH 20/44] impreove coding --- mininet/mininet/lxc_container.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/mininet/mininet/lxc_container.py b/mininet/mininet/lxc_container.py index 7f7031e0..64af5c29 100644 --- a/mininet/mininet/lxc_container.py +++ b/mininet/mininet/lxc_container.py @@ -201,6 +201,8 @@ def configureContainer(self, adminbr="admin-br", wait=True,autoSetDocker=False): # configure the node to be "SSH'able" cmds = [] if autoSetDocker: + cmds.append("docker exec {} bash -c 'echo \"{}\" >> /root/.ssh/authorized_keys'".format(self.name, self.pub_id)) + cmds.append("docker exec {} service ssh start".format(self.name)) cmds.append("{}=$(docker inspect -f '{{{{.State.Pid}}}}' {})".format(self.name,self.name)) cmds.append("ip netns exec ${} ip addr add {} dev admin".format(self.name,self.admin_ip)) # configure the container to have @@ -347,7 +349,7 @@ def createContainer(self,autoSetDocker=False, **params): cmds = [] # initialise the container if autoSetDocker: - cmd = "docker create -v /root/alcor-control-agent/:/mnt/host/code -it --privileged --cap-add=NET_ADMIN --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --name {} --net=none {} /bin/bash".format(self.name, self.image) + cmd = "docker run -v /root/alcor-control-agent/:/mnt/host/code -it --privileged --cap-add=NET_ADMIN --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --name {} --net=none {} /bin/bash < /dev/null ".format(self.name, self.image) else: cmd = "lxc init {} {} < /dev/null ".format(self.image, self.name) info ("{}\n".format(cmd)) @@ -361,13 +363,9 @@ def createContainer(self,autoSetDocker=False, **params): #cmds.append("lxc config set {} limits.memory {}".format(self.name, self.memory)) cmds.append("docker container update -m {} {}".format(self.memory, self.name)) - cmds.append("docker start {}".format(self.name)) if self.image=="switch": cmds.append("docker exec {} bash -c 'export PATH=$PATH:/usr/share/openvswitch/scripts;ovs-ctl start'".format(self.name)) - cmds.append("docker exec {} bash -c 'cd /mnt/host/code;/etc/init.d/openvswitch-switch restart;ovs-vswitchd --pidfile --detach'".format(self.name)) - cmds.append("docker exec {} mkdir /root/.ssh".format(self.name)) - cmds.append("docker exec {} bash -c 'echo \"{}\" >> /root/.ssh/authorized_keys'".format(self.name, self.pub_id)) - cmds.append("docker exec {} service ssh start".format(self.name)) + cmds.append("docker exec {} bash -c 'cd /mnt/host/code;/etc/init.d/openvswitch-switch restart;ovs-vswitchd --pidfile --detach'".format(self.name)) else: if self.cpu: cmds.append("lxc config set {} limits.cpu {}".format(self.name, self.cpu)) From 8ac3d1fdb9c41f51cd40542a626248a989e0c0d6 Mon Sep 17 00:00:00 2001 From: J980419xq <1908393204@qq.com> Date: Sat, 16 Jul 2022 17:55:12 +0000 Subject: [PATCH 21/44] improve coding --- mininet/bin/dmn | 2 +- mininet/mininet/distrinet.py | 10 +- mininet/mininet/lxc_container.py | 10 +- openflow/.gitignore | 44 + openflow/COPYING | 1054 +++++ openflow/ChangeLog | 202 + openflow/INSTALL | 513 +++ openflow/Makefile.am | 68 + openflow/README | 110 + openflow/README.hwtables | 39 + openflow/README.kernel | 18 + openflow/acinclude.m4 | 309 ++ openflow/boot.sh | 14 + openflow/configure.ac | 94 + openflow/controller/.dirstamp | 0 openflow/controller/.gitignore | 4 + openflow/controller/automake.mk | 8 + openflow/controller/controller.8.in | 150 + openflow/controller/controller.c | 336 ++ openflow/datapath/.gitignore | 7 + openflow/datapath/Makefile.am | 27 + openflow/datapath/Modules.mk | 42 + openflow/datapath/chain.c | 270 ++ openflow/datapath/chain.h | 43 + openflow/datapath/compat.h | 12 + openflow/datapath/crc32.c | 45 + openflow/datapath/crc32.h | 22 + openflow/datapath/datapath.c | 2137 ++++++++++ openflow/datapath/datapath.h | 114 + openflow/datapath/dp_act.c | 543 +++ openflow/datapath/dp_act.h | 15 + openflow/datapath/dp_dev.c | 252 ++ openflow/datapath/dp_dev.h | 17 + openflow/datapath/dp_notify.c | 43 + openflow/datapath/flow.c | 504 +++ openflow/datapath/flow.h | 199 + openflow/datapath/forward.c | 642 +++ openflow/datapath/forward.h | 38 + openflow/datapath/hwtable_dummy/Modules.mk | 7 + .../datapath/hwtable_dummy/hwtable_dummy.c | 320 ++ openflow/datapath/hwtable_nf2/Modules.mk | 19 + openflow/datapath/hwtable_nf2/README | 78 + openflow/datapath/hwtable_nf2/nf2.h | 424 ++ openflow/datapath/hwtable_nf2/nf2_flowtable.c | 452 +++ openflow/datapath/hwtable_nf2/nf2_flowtable.h | 63 + openflow/datapath/hwtable_nf2/nf2_hwapi.h | 43 + openflow/datapath/hwtable_nf2/nf2_lib.c | 918 +++++ openflow/datapath/hwtable_nf2/nf2_lib.h | 59 + openflow/datapath/hwtable_nf2/nf2_openflow.c | 847 ++++ openflow/datapath/hwtable_nf2/nf2_openflow.h | 169 + openflow/datapath/hwtable_nf2/nf2_procfs.c | 240 ++ openflow/datapath/hwtable_nf2/nf2_procfs.h | 39 + openflow/datapath/hwtable_nf2/nf2_reg.h | 767 ++++ .../datapath/hwtable_nf2/openflow_switch.bit | Bin 0 -> 2377746 bytes openflow/datapath/linux-2.6/.gitignore | 30 + openflow/datapath/linux-2.6/Kbuild.in | 35 + openflow/datapath/linux-2.6/Makefile.in | 9 + openflow/datapath/linux-2.6/Makefile.main.in | 85 + openflow/datapath/linux-2.6/Modules.mk | 32 + .../datapath/linux-2.6/compat-2.6/compat26.h | 31 + .../linux-2.6/compat-2.6/genetlink-brcompat.c | 20 + .../linux-2.6/compat-2.6/genetlink-openflow.c | 22 + .../compat-2.6/include/asm-generic/bug.h | 20 + .../linux-2.6/compat-2.6/include/linux/dmi.h | 114 + .../linux-2.6/compat-2.6/include/linux/icmp.h | 13 + .../compat-2.6/include/linux/if_arp.h | 16 + .../linux-2.6/compat-2.6/include/linux/ip.h | 18 + .../linux-2.6/compat-2.6/include/linux/ipv6.h | 13 + .../compat-2.6/include/linux/jiffies.h | 26 + .../compat-2.6/include/linux/lockdep.h | 450 +++ .../compat-2.6/include/linux/mutex.h | 59 + .../compat-2.6/include/linux/netdevice.h | 10 + .../include/linux/netfilter_bridge.h | 24 + .../compat-2.6/include/linux/netfilter_ipv4.h | 19 + .../compat-2.6/include/linux/netlink.h | 24 + .../compat-2.6/include/linux/random.h | 17 + .../compat-2.6/include/linux/rculist.h | 12 + .../compat-2.6/include/linux/skbuff.h | 137 + .../linux-2.6/compat-2.6/include/linux/tcp.h | 18 + .../compat-2.6/include/linux/timer.h | 96 + .../compat-2.6/include/linux/types.h | 14 + .../linux-2.6/compat-2.6/include/linux/udp.h | 13 + .../compat-2.6/include/linux/workqueue.h | 42 + .../compat-2.6/include/net/checksum.h | 16 + .../compat-2.6/include/net/genetlink.h | 123 + .../compat-2.6/include/net/netlink.h | 22 + .../datapath/linux-2.6/compat-2.6/random32.c | 146 + openflow/datapath/linux-2.6/compat-2.6/veth.c | 537 +++ .../config/config-linux-2.6.23-rc9-kvm | 1408 +++++++ openflow/datapath/openflow-ext.c | 83 + openflow/datapath/openflow-ext.h | 38 + openflow/datapath/private-msg.c | 137 + openflow/datapath/private-msg.h | 38 + openflow/datapath/table-hash.c | 489 +++ openflow/datapath/table-linear.c | 233 ++ openflow/datapath/table.h | 119 + openflow/debian/.gitignore | 38 + openflow/debian/changelog | 23 + openflow/debian/commands/reconfigure | 128 + openflow/debian/commands/update | 4 + openflow/debian/compat | 1 + openflow/debian/control.in | 93 + openflow/debian/control.modules.in | 19 + openflow/debian/copyright | 38 + openflow/debian/corekeeper.cron.daily | 5 + openflow/debian/corekeeper.init | 63 + openflow/debian/dirs | 2 + openflow/debian/ofp-switch-setup | 615 +++ openflow/debian/ofp-switch-setup.8 | 41 + openflow/debian/openflow-common.dirs | 1 + openflow/debian/openflow-common.install | 3 + openflow/debian/openflow-common.manpages | 2 + .../debian/openflow-controller.README.Debian | 10 + openflow/debian/openflow-controller.default | 33 + openflow/debian/openflow-controller.dirs | 1 + openflow/debian/openflow-controller.init | 269 ++ openflow/debian/openflow-controller.install | 1 + openflow/debian/openflow-controller.manpages | 1 + openflow/debian/openflow-controller.postinst | 52 + ...atapath-module-_KVERS_.postinst.modules.in | 25 + .../openflow-datapath-source.README.Debian | 31 + .../debian/openflow-datapath-source.copyright | 16 + openflow/debian/openflow-datapath-source.dirs | 1 + .../debian/openflow-datapath-source.install | 6 + openflow/debian/openflow-pki-server.apache2 | 1 + openflow/debian/openflow-pki-server.dirs | 1 + openflow/debian/openflow-pki-server.install | 1 + openflow/debian/openflow-pki-server.postinst | 44 + openflow/debian/openflow-pki.postinst | 41 + openflow/debian/openflow-switch-config.dirs | 1 + .../debian/openflow-switch-config.install | 1 + .../debian/openflow-switch-config.manpages | 1 + .../debian/openflow-switch-config.overrides | 1 + .../debian/openflow-switch-config.templates | 228 ++ openflow/debian/openflow-switch.README.Debian | 18 + openflow/debian/openflow-switch.dirs | 2 + openflow/debian/openflow-switch.init | 437 ++ openflow/debian/openflow-switch.install | 6 + openflow/debian/openflow-switch.logrotate | 11 + openflow/debian/openflow-switch.manpages | 4 + openflow/debian/openflow-switch.postinst | 51 + openflow/debian/openflow-switch.postrm | 43 + openflow/debian/openflow-switch.template | 169 + openflow/debian/po/POTFILES.in | 1 + openflow/debian/rules | 163 + openflow/doc/of-spec/.gitignore | 8 + openflow/doc/of-spec/Makefile | 40 + openflow/doc/of-spec/README | 3 + openflow/doc/of-spec/appendix.tex | 429 ++ openflow/doc/of-spec/credits.tex | 22 + .../doc/of-spec/figure_flow_table_secchan.png | Bin 0 -> 67886 bytes .../of-spec/header_parsing_flowchart.graffle | 3536 +++++++++++++++++ openflow/doc/of-spec/make_latex_input.pl | 117 + openflow/doc/of-spec/openflow-spec-v1.0.0.tex | 418 ++ .../doc/of-spec/packet_flow_flowchart.graffle | 1887 +++++++++ openflow/hw-lib/automake.mk | 28 + openflow/hw-lib/nf2/README | 56 + openflow/hw-lib/nf2/debug.h | 105 + openflow/hw-lib/nf2/hw_flow.c | 514 +++ openflow/hw-lib/nf2/hw_flow.h | 56 + openflow/hw-lib/nf2/nf2.h | 452 +++ openflow/hw-lib/nf2/nf2_drv.c | 847 ++++ openflow/hw-lib/nf2/nf2_drv.h | 150 + openflow/hw-lib/nf2/nf2_lib.c | 1049 +++++ openflow/hw-lib/nf2/nf2_lib.h | 59 + openflow/hw-lib/nf2/nf2util.c | 400 ++ openflow/hw-lib/nf2/nf2util.h | 46 + .../hw-lib/nf2/reg_defines_openflow_switch.h | 767 ++++ openflow/hw-lib/skeleton/debug.h | 106 + openflow/hw-lib/skeleton/hw_drv.c | 309 ++ openflow/hw-lib/skeleton/hw_drv.h | 97 + openflow/hw-lib/skeleton/hw_flow.c | 708 ++++ openflow/hw-lib/skeleton/hw_flow.h | 111 + openflow/hw-lib/skeleton/of_hw_platform.h | 38 + openflow/hw-lib/skeleton/os.h | 29 + openflow/hw-lib/skeleton/port.c | 497 +++ openflow/hw-lib/skeleton/port.h | 45 + openflow/hw-lib/skeleton/sample_plat.c | 82 + openflow/hw-lib/skeleton/sample_plat.h | 61 + openflow/hw-lib/skeleton/txrx.c | 129 + openflow/hw-lib/skeleton/txrx.h | 12 + openflow/include/.gitignore | 2 + openflow/include/automake.mk | 1 + openflow/include/openflow/automake.mk | 5 + openflow/include/openflow/nicira-ext.h | 195 + openflow/include/openflow/of_hw_api.h | 313 ++ openflow/include/openflow/openflow-ext.h | 149 + openflow/include/openflow/openflow-netlink.h | 69 + openflow/include/openflow/openflow.h | 970 +++++ openflow/include/openflow/private-ext.h | 68 + openflow/m4/libopenflow.m4 | 168 + openflow/m4/nx-build.m4 | 71 + openflow/regress/CREDITS | 22 + openflow/regress/INSTALL | 264 ++ openflow/regress/LICENSE | 30 + openflow/regress/README | 329 ++ openflow/regress/bin/eth.map | 8 + openflow/regress/bin/nf2.map | 8 + openflow/regress/bin/of_hp_eth.map | 8 + openflow/regress/bin/of_hp_setup.pl | 86 + openflow/regress/bin/of_hp_teardown.pl | 50 + openflow/regress/bin/of_hp_test.pl | 62 + openflow/regress/bin/of_hp_test_6600.pl | 62 + openflow/regress/bin/of_kmod_setup.pl | 22 + openflow/regress/bin/of_kmod_teardown.pl | 20 + openflow/regress/bin/of_kmod_test.pl | 27 + openflow/regress/bin/of_kmod_veth_setup.pl | 26 + openflow/regress/bin/of_kmod_veth_teardown.pl | 24 + openflow/regress/bin/of_kmod_veth_test.pl | 27 + openflow/regress/bin/of_nf2_setup.pl | 26 + openflow/regress/bin/of_nf2_teardown.pl | 20 + openflow/regress/bin/of_nf2_test.pl | 28 + openflow/regress/bin/of_ovs_eth.map | 8 + openflow/regress/bin/of_ovs_setup.pl | 76 + openflow/regress/bin/of_ovs_teardown.pl | 59 + openflow/regress/bin/of_ovs_test.pl | 54 + openflow/regress/bin/of_ovs_user_setup.pl | 60 + openflow/regress/bin/of_ovs_user_teardown.pl | 34 + openflow/regress/bin/of_ovs_user_test.pl | 50 + openflow/regress/bin/of_ovs_user_veth_test.pl | 47 + openflow/regress/bin/of_ovs_veth_test.pl | 47 + openflow/regress/bin/of_user_setup.pl | 22 + openflow/regress/bin/of_user_teardown.pl | 20 + openflow/regress/bin/of_user_test.pl | 27 + openflow/regress/bin/of_user_veth_setup.pl | 26 + openflow/regress/bin/of_user_veth_teardown.pl | 24 + openflow/regress/bin/of_user_veth_test.pl | 27 + openflow/regress/bin/veth.map | 8 + openflow/regress/bin/veth_setup.pl | 10 + openflow/regress/bin/veth_teardown.pl | 4 + .../projects/black_box/regress/common/setup | 47 + .../black_box/regress/common/teardown | 47 + .../regress/test_add_flow_latency/run.pl | 47 + .../black_box/regress/test_barrier/run.pl | 52 + .../regress/test_cookie_flow_expired/run.pl | 39 + .../regress/test_cookie_flow_stats/run.pl | 151 + .../black_box/regress/test_delete/run.pl | 172 + .../regress/test_delete_send_flow_exp/run.pl | 104 + .../regress/test_delete_strict/run.pl | 175 + .../black_box/regress/test_drop_exact/run.pl | 54 + .../regress/test_failover_close/run.pl | 68 + .../regress/test_failover_startup/run.pl | 53 + .../test_failover_stop_responding/run.pl | 65 + .../regress/test_flow_expired/run.pl | 34 + .../test_flow_expired_idle_timeout/run.pl | 34 + .../test_flow_expired_precision/run.pl | 66 + .../test_flow_expired_send_flow_exp/run.pl | 44 + .../regress/test_flow_mod_check/run.pl | 83 + .../test_flow_mod_latency/run-port3.pl | 136 + .../regress/test_flow_mod_latency/run.pl | 129 + .../black_box/regress/test_flow_stats/run.pl | 145 + .../regress/test_flow_stats_precision/run.pl | 191 + .../test_forward_after_expiration/run.pl | 111 + .../regress/test_forward_any_port/run.pl | 20 + .../test_forward_bandwidth_fixed/run.pl | 83 + .../test_forward_bandwidth_random/run.pl | 84 + .../test_forward_broadcast_exact_port/run.pl | 64 + .../regress/test_forward_exact_all/run.pl | 30 + .../regress/test_forward_exact_arp_all/run.pl | 19 + .../test_forward_exact_arp_controller/run.pl | 19 + .../test_forward_exact_arp_fool/run.pl | 19 + .../test_forward_exact_arp_port/run.pl | 19 + .../test_forward_exact_controller/run.pl | 32 + .../test_forward_exact_icmp_all/run.pl | 19 + .../test_forward_exact_icmp_controller/run.pl | 19 + .../test_forward_exact_icmp_fool/run.pl | 19 + .../test_forward_exact_icmp_port/run.pl | 19 + .../test_forward_exact_modify_action/run.pl | 42 + .../regress/test_forward_exact_port/run.pl | 27 + .../run.pl | 86 + .../regress/test_forward_wildcard_all/run.pl | 172 + .../test_forward_wildcard_arp_all/run.pl | 20 + .../run.pl | 19 + .../test_forward_wildcard_arp_fool/run.pl | 20 + .../test_forward_wildcard_arp_port/run.pl | 20 + .../test_forward_wildcard_controller/run.pl | 30 + .../test_forward_wildcard_icmp_all/run.pl | 20 + .../run.pl | 19 + .../test_forward_wildcard_icmp_fool/run.pl | 20 + .../test_forward_wildcard_icmp_port/run.pl | 20 + .../run.pl | 35 + .../regress/test_forward_wildcard_port/run.pl | 97 + .../black_box/regress/test_hello/run.pl | 16 + .../black_box/regress/test_ip_offset/run.pl | 85 + .../black_box/regress/test_ip_options/run.pl | 76 + .../regress/test_ip_protocol/case-c.pl | 150 + .../regress/test_ip_protocol/case-d.pl | 152 + .../regress/test_ip_protocol/case-e.pl | 152 + .../regress/test_ip_protocol/case-tcp.pl | 153 + .../regress/test_ip_protocol/case-udp.pl | 67 + .../black_box/regress/test_llc/run.pl | 128 + .../regress/test_miss_send_length/run.pl | 79 + .../black_box/regress/test_packet_in/run.pl | 45 + .../black_box/regress/test_packet_out/run.pl | 53 + .../black_box/regress/test_port_stats/run.pl | 132 + .../regress/test_queue_config/run.pl | 52 + .../regress/test_queue_forward/run.pl | 19 + .../black_box/regress/test_queue_stats/run.pl | 116 + .../test_receive_bandwidth_fixed/run.pl | 89 + .../regress/test_send_bandwidth_fixed/run.pl | 140 + .../regress/test_send_bandwidth_random/run.pl | 141 + .../regress/test_set_dl_nw_flip/run.pl | 143 + .../regress/test_set_n_match_nw_tos/run.pl | 95 + .../black_box/regress/test_set_nw_dst/run.pl | 95 + .../black_box/regress/test_stats_desc/run.pl | 71 + .../regress/test_switch_config/run.pl | 40 + .../black_box/regress/test_tcp_options/run.pl | 170 + .../projects/black_box/regress/tests.txt | 103 + .../regress/common/setup | 49 + .../regress/common/teardown | 47 + .../regress/test_emergency_table/run.pl | 107 + .../controller_disconnect/regress/tests.txt | 2 + .../learning_switch/regress/common/setup | 46 + .../learning_switch/regress/common/teardown | 46 + .../regress/test_broadcast/run.pl | 50 + .../regress/test_forward_bandwidth/run.pl | 62 + .../regress/test_forward_latency/run.pl | 69 + .../regress/test_hub_connected/run.pl | 64 + .../regress/test_unicast_known/run.pl | 71 + .../regress/test_unicast_move/run.pl | 79 + .../test_unicast_multiple_hosts/run.pl | 93 + .../regress/test_unicast_self/run.pl | 61 + .../regress/test_unicast_unknown/run.pl | 32 + .../learning_switch/regress/tests.txt | 12 + openflow/regress/projects/regress.txt | 3 + openflow/regress/scripts/copy_NF2_code.sh | 5 + openflow/regress/scripts/env_vars | 12 + openflow/regress/scripts/install_deps.pl | 264 ++ .../regress/scripts/install_perlmods_apt.pl | 32 + openflow/regress/scripts/make_release.pl | 155 + openflow/secchan/.dirstamp | 0 openflow/secchan/.gitignore | 7 + openflow/secchan/automake.mk | 32 + openflow/secchan/commands/automake.mk | 3 + openflow/secchan/commands/reboot | 3 + openflow/secchan/discovery.c | 251 ++ openflow/secchan/discovery.h | 50 + openflow/secchan/emerg-flow.c | 144 + openflow/secchan/emerg-flow.h | 44 + openflow/secchan/fail-open.c | 159 + openflow/secchan/fail-open.h | 46 + openflow/secchan/failover.c | 144 + openflow/secchan/failover.h | 44 + openflow/secchan/in-band.c | 331 ++ openflow/secchan/in-band.h | 47 + openflow/secchan/ofprotocol.8.in | 462 +++ openflow/secchan/port-watcher.c | 620 +++ openflow/secchan/port-watcher.h | 77 + openflow/secchan/protocol-stat.c | 204 + openflow/secchan/protocol-stat.h | 44 + openflow/secchan/ratelimit.c | 263 ++ openflow/secchan/ratelimit.h | 45 + openflow/secchan/secchan.c | 882 ++++ openflow/secchan/secchan.h | 135 + openflow/secchan/status.c | 230 ++ openflow/secchan/status.h | 56 + openflow/secchan/stp-secchan.c | 293 ++ openflow/secchan/stp-secchan.h | 48 + openflow/soexpand.pl | 26 + openflow/tests/.dirstamp | 0 openflow/tests/.gitignore | 6 + openflow/tests/automake.mk | 46 + openflow/tests/flowgen.pl | 224 ++ openflow/tests/test-dhcp-client.c | 206 + openflow/tests/test-flows | Bin 0 -> 286976 bytes openflow/tests/test-flows.c | 76 + openflow/tests/test-flows.sh | 9 + openflow/tests/test-hmap | Bin 0 -> 68296 bytes openflow/tests/test-hmap.c | 282 ++ openflow/tests/test-list.c | 159 + openflow/tests/test-stp-ieee802.1d-1998 | 12 + .../tests/test-stp-ieee802.1d-2004-fig17.4 | 31 + .../tests/test-stp-ieee802.1d-2004-fig17.6 | 14 + .../tests/test-stp-ieee802.1d-2004-fig17.7 | 17 + openflow/tests/test-stp-iol-io-1.1 | 25 + openflow/tests/test-stp-iol-io-1.2 | 14 + openflow/tests/test-stp-iol-io-1.4 | 13 + openflow/tests/test-stp-iol-io-1.5 | 40 + openflow/tests/test-stp-iol-op-1.1 | 7 + openflow/tests/test-stp-iol-op-1.4 | 8 + openflow/tests/test-stp-iol-op-3.1 | 11 + openflow/tests/test-stp-iol-op-3.3 | 11 + openflow/tests/test-stp-iol-op-3.4 | 11 + openflow/tests/test-stp.c | 665 ++++ openflow/tests/test-stp.sh | 7 + openflow/tests/test-type-props.c | 41 + openflow/third-party/.gitignore | 2 + openflow/third-party/README | 35 + openflow/third-party/automake.mk | 3 + openflow/third-party/ofp-tcpdump.patch | 119 + openflow/udatapath/.dirstamp | 0 openflow/udatapath/.gitignore | 4 + openflow/udatapath/automake.mk | 75 + openflow/udatapath/chain.c | 261 ++ openflow/udatapath/chain.h | 74 + openflow/udatapath/crc32.c | 68 + openflow/udatapath/crc32.h | 50 + openflow/udatapath/datapath.c | 2375 +++++++++++ openflow/udatapath/datapath.h | 167 + openflow/udatapath/dp_act.c | 531 +++ openflow/udatapath/dp_act.h | 49 + openflow/udatapath/of_ext_msg.c | 267 ++ openflow/udatapath/of_ext_msg.h | 43 + openflow/udatapath/ofdatapath.8.in | 148 + openflow/udatapath/private-msg.c | 140 + openflow/udatapath/private-msg.h | 42 + openflow/udatapath/switch-flow.c | 341 ++ openflow/udatapath/switch-flow.h | 100 + openflow/udatapath/table-hash.c | 469 +++ openflow/udatapath/table-linear.c | 262 ++ openflow/udatapath/table.h | 150 + openflow/udatapath/udatapath.c | 345 ++ openflow/utilities/.dirstamp | 0 openflow/utilities/.gitignore | 13 + openflow/utilities/automake.mk | 45 + openflow/utilities/dpctl.8.in | 582 +++ openflow/utilities/dpctl.c | 1772 +++++++++ openflow/utilities/ofp-discover.8.in | 119 + openflow/utilities/ofp-discover.c | 420 ++ openflow/utilities/ofp-kill.8.in | 61 + openflow/utilities/ofp-kill.c | 228 ++ openflow/utilities/ofp-parse-leaks | 285 ++ openflow/utilities/ofp-parse-leaks.in | 285 ++ openflow/utilities/ofp-pki-cgi.in | 41 + openflow/utilities/ofp-pki.8.in | 325 ++ openflow/utilities/ofp-pki.in | 582 +++ openflow/utilities/vlogconf.8.in | 183 + openflow/utilities/vlogconf.c | 235 ++ .../utilities/wireshark_dissectors/Makefile | 32 + .../utilities/wireshark_dissectors/README | 37 + .../wireshark_dissectors/openflow/.gitignore | 1 + .../wireshark_dissectors/openflow/Makefile | 79 + .../wireshark_dissectors/openflow/Makefile.am | 110 + .../openflow/Makefile.common | 13 + .../openflow/build_distribution_tarball.sh | 63 + .../openflow/moduleinfo.h | 15 + .../openflow/packet-openflow.c | 3426 ++++++++++++++++ .../wireshark_dissectors/openflow/plugin.c | 28 + .../wireshark-1.0.0-includes/airpcap.h | 907 +++++ .../wireshark-1.0.0-includes/airpcap_loader.h | 560 +++ .../wireshark-1.0.0-includes/alert_box.h | 70 + .../capture-pcap-util-int.h | 56 + .../capture-pcap-util.h | 131 + .../wireshark-1.0.0-includes/capture-wpcap.h | 34 + .../wireshark-1.0.0-includes/capture.h | 118 + .../wireshark-1.0.0-includes/capture_errs.h | 34 + .../wireshark-1.0.0-includes/capture_info.h | 76 + .../wireshark-1.0.0-includes/capture_opts.h | 194 + .../capture_stop_conditions.h | 29 + .../wireshark-1.0.0-includes/capture_sync.h | 87 + .../capture_ui_utils.h | 89 + .../capture_wpcap_packet.h | 47 + .../wireshark-1.0.0-includes/cfile.h | 91 + .../wireshark-1.0.0-includes/clopts_common.h | 40 + .../wireshark-1.0.0-includes/cmdarg_err.h | 56 + .../wireshark-1.0.0-includes/color.h | 55 + .../wireshark-1.0.0-includes/color_filters.h | 196 + .../wireshark-1.0.0-includes/conditions.h | 134 + .../wireshark-1.0.0-includes/config.h | 322 ++ .../wireshark-1.0.0-includes/config.h.in | 321 ++ .../wireshark-1.0.0-includes/config.h.win32 | 274 ++ .../disabled_protos.h | 61 + .../epan/addr_and_mask.h | 53 + .../epan/addr_resolv.h | 198 + .../wireshark-1.0.0-includes/epan/address.h | 172 + .../wireshark-1.0.0-includes/epan/adler32.h | 42 + .../wireshark-1.0.0-includes/epan/afn.h | 71 + .../wireshark-1.0.0-includes/epan/aftypes.h | 47 + .../epan/arcnet_pids.h | 70 + .../wireshark-1.0.0-includes/epan/arptypes.h | 75 + .../wireshark-1.0.0-includes/epan/asm_utils.h | 38 + .../wireshark-1.0.0-includes/epan/asn1.h | 207 + .../epan/atalk-utils.h | 63 + .../wireshark-1.0.0-includes/epan/base64.h | 38 + .../wireshark-1.0.0-includes/epan/bitswap.h | 40 + .../epan/bridged_pids.h | 58 + .../epan/camel-persistentdata.h | 127 + .../wireshark-1.0.0-includes/epan/charsets.h | 42 + .../epan/chdlctypes.h | 40 + .../wireshark-1.0.0-includes/epan/circuit.h | 80 + .../wireshark-1.0.0-includes/epan/codecs.h | 43 + .../epan/column-utils.h | 241 ++ .../wireshark-1.0.0-includes/epan/column.h | 56 + .../epan/column_info.h | 134 + .../epan/conversation.h | 109 + .../wireshark-1.0.0-includes/epan/crc10.h | 27 + .../wireshark-1.0.0-includes/epan/crc16.h | 109 + .../wireshark-1.0.0-includes/epan/crc32.h | 94 + .../wireshark-1.0.0-includes/epan/crc6.h | 26 + .../wireshark-1.0.0-includes/epan/crcdrm.h | 7 + .../epan/crypt/airpdcap_debug.h | 106 + .../epan/crypt/airpdcap_int.h | 158 + .../epan/crypt/airpdcap_interop.h | 101 + .../epan/crypt/airpdcap_rijndael.h | 93 + .../epan/crypt/airpdcap_system.h | 356 ++ .../epan/crypt/airpdcap_user.h | 231 ++ .../epan/crypt/airpdcap_ws.h | 43 + .../epan/crypt/crypt-des.h | 26 + .../epan/crypt/crypt-md4.h | 23 + .../epan/crypt/crypt-md5.h | 71 + .../epan/crypt/crypt-rc4.h | 36 + .../epan/crypt/crypt-sha1.h | 45 + .../epan/crypt/wep-wpadefs.h | 115 + .../epan/dfilter/dfilter-int.h | 82 + .../epan/dfilter/dfilter-macro.h | 59 + .../epan/dfilter/dfilter.h | 94 + .../epan/dfilter/dfunctions.h | 56 + .../epan/dfilter/dfvm.h | 108 + .../epan/dfilter/drange.h | 102 + .../epan/dfilter/gencode.h | 10 + .../epan/dfilter/glib-util.h | 4 + .../epan/dfilter/grammar.h | 24 + .../epan/dfilter/scanner_lex.h | 6 + .../epan/dfilter/semcheck.h | 31 + .../epan/dfilter/sttype-function.h | 42 + .../epan/dfilter/sttype-range.h | 45 + .../epan/dfilter/sttype-test.h | 56 + .../epan/dfilter/syntax-tree.h | 136 + .../wireshark-1.0.0-includes/epan/diam_dict.h | 89 + .../epan/diam_dict_lex.h | 6 + .../epan/dissector_filters.h | 60 + .../epan/dissectors/packet-tcp.h | 232 ++ .../wireshark-1.0.0-includes/epan/dtd.h | 62 + .../epan/dtd_grammar.h | 23 + .../wireshark-1.0.0-includes/epan/dtd_parse.h | 37 + .../epan/dtd_parse_lex.h | 6 + .../epan/dtd_preparse_lex.h | 6 + .../wireshark-1.0.0-includes/epan/eap.h | 53 + .../wireshark-1.0.0-includes/epan/emem.h | 373 ++ .../wireshark-1.0.0-includes/epan/epan.h | 93 + .../epan/epan_dissect.h | 44 + .../wireshark-1.0.0-includes/epan/etypes.h | 408 ++ .../wireshark-1.0.0-includes/epan/ex-opt.h | 44 + .../wireshark-1.0.0-includes/epan/except.h | 158 + .../epan/exceptions.h | 319 ++ .../wireshark-1.0.0-includes/epan/expert.h | 70 + .../epan/filesystem.h | 248 ++ .../wireshark-1.0.0-includes/epan/follow.h | 58 + .../epan/frame_data.h | 79 + .../epan/frequency-utils.h | 74 + .../epan/ftypes/ftypes-int.h | 61 + .../epan/ftypes/ftypes.h | 367 ++ .../wireshark-1.0.0-includes/epan/funnel.h | 116 + .../epan/g_ascii_strcasecmp.h | 18 + .../epan/g_ascii_strtoull.h | 15 + .../wireshark-1.0.0-includes/epan/garrayfix.h | 38 + .../wireshark-1.0.0-includes/epan/gcp.h | 219 + .../epan/gnuc_format_check.h | 39 + .../wireshark-1.0.0-includes/epan/golay.h | 49 + .../wireshark-1.0.0-includes/epan/greproto.h | 36 + .../epan/guid-utils.h | 63 + .../epan/h225-persistentdata.h | 62 + .../epan/iax2_codec_type.h | 77 + .../wireshark-1.0.0-includes/epan/in_cksum.h | 14 + .../wireshark-1.0.0-includes/epan/inet_aton.h | 34 + .../wireshark-1.0.0-includes/epan/ip_opts.h | 59 + .../wireshark-1.0.0-includes/epan/ipproto.h | 193 + .../wireshark-1.0.0-includes/epan/ipv4.h | 67 + .../epan/ipv6-utils.h | 49 + .../wireshark-1.0.0-includes/epan/lapd_sapi.h | 38 + .../wireshark-1.0.0-includes/epan/llcsaps.h | 63 + .../wireshark-1.0.0-includes/epan/next_tvb.h | 65 + .../wireshark-1.0.0-includes/epan/nlpid.h | 60 + .../wireshark-1.0.0-includes/epan/nstime.h | 92 + .../wireshark-1.0.0-includes/epan/oids.h | 179 + .../wireshark-1.0.0-includes/epan/osi-utils.h | 57 + .../wireshark-1.0.0-includes/epan/oui.h | 74 + .../wireshark-1.0.0-includes/epan/packet.h | 422 ++ .../epan/packet_info.h | 184 + .../wireshark-1.0.0-includes/epan/pint.h | 113 + .../wireshark-1.0.0-includes/epan/plugins.h | 58 + .../wireshark-1.0.0-includes/epan/ppptypes.h | 158 + .../wireshark-1.0.0-includes/epan/prefs-int.h | 111 + .../wireshark-1.0.0-includes/epan/prefs.h | 426 ++ .../epan/privileges.h | 74 + .../wireshark-1.0.0-includes/epan/proto.h | 1655 ++++++++ .../wireshark-1.0.0-includes/epan/ptvcursor.h | 110 + .../epan/radius_dict_lex.h | 6 + .../wireshark-1.0.0-includes/epan/range.h | 73 + .../epan/reassemble.h | 316 ++ .../epan/reedsolomon.h | 86 + .../epan/report_err.h | 61 + .../epan/req_resp_hdrs.h | 43 + .../wireshark-1.0.0-includes/epan/rtp_pt.h | 68 + .../wireshark-1.0.0-includes/epan/sctpppids.h | 50 + .../epan/sigcomp-udvm.h | 49 + .../epan/sigcomp_state_hdlr.h | 49 + .../wireshark-1.0.0-includes/epan/slab.h | 75 + .../wireshark-1.0.0-includes/epan/sminmpec.h | 83 + .../wireshark-1.0.0-includes/epan/sna-utils.h | 41 + .../epan/stat_cmd_args.h | 35 + .../epan/stats_tree.h | 147 + .../epan/stats_tree_priv.h | 202 + .../wireshark-1.0.0-includes/epan/stream.h | 138 + .../wireshark-1.0.0-includes/epan/strutil.h | 243 ++ .../wireshark-1.0.0-includes/epan/t35.h | 35 + .../wireshark-1.0.0-includes/epan/tap-voip.h | 59 + .../wireshark-1.0.0-includes/epan/tap.h | 61 + .../epan/tcap-persistentdata.h | 148 + .../wireshark-1.0.0-includes/epan/tfs.h | 65 + .../wireshark-1.0.0-includes/epan/timestamp.h | 68 + .../wireshark-1.0.0-includes/epan/to_str.h | 94 + .../wireshark-1.0.0-includes/epan/tvbparse.h | 475 +++ .../wireshark-1.0.0-includes/epan/tvbuff.h | 634 +++ .../wireshark-1.0.0-includes/epan/uat-int.h | 92 + .../wireshark-1.0.0-includes/epan/uat.h | 486 +++ .../epan/uat_load_lex.h | 6 + .../epan/unicode-utils.h | 54 + .../epan/value_string.h | 88 + .../epan/ws_strsplit.h | 41 + .../epan/wslua/declare_wslua.h | 59 + .../epan/wslua/wslua.h | 372 ++ .../epan/x264_prt_id.h | 35 + .../wireshark-1.0.0-includes/epan/xdlc.h | 140 + .../wireshark-1.0.0-includes/epan/xmlstub.h | 1123 ++++++ .../wireshark-1.0.0-includes/file.h | 486 +++ .../wireshark-1.0.0-includes/fileset.h | 75 + .../wireshark-1.0.0-includes/filters.h | 87 + .../wireshark-1.0.0-includes/g711.h | 30 + .../wireshark-1.0.0-includes/getopt.h | 129 + .../wireshark-1.0.0-includes/globals.h | 37 + .../wireshark-1.0.0-includes/inet_v6defs.h | 54 + .../wireshark-1.0.0-includes/isprint.h | 46 + .../wireshark-1.0.0-includes/log.h | 42 + .../wireshark-1.0.0-includes/main_window.h | 41 + .../wireshark-1.0.0-includes/menu.h | 64 + .../wireshark-1.0.0-includes/merge.h | 125 + .../wireshark-1.0.0-includes/mkstemp.h | 24 + .../wireshark-1.0.0-includes/packet-range.h | 101 + .../wireshark-1.0.0-includes/pcapio.h | 44 + .../wireshark-1.0.0-includes/print.h | 148 + .../wireshark-1.0.0-includes/progress_dlg.h | 94 + .../proto_hier_stats.h | 51 + .../wireshark-1.0.0-includes/ps.h | 35 + .../wireshark-1.0.0-includes/register.h | 48 + .../wireshark-1.0.0-includes/ringbuffer.h | 53 + .../wireshark-1.0.0-includes/simple_dialog.h | 184 + .../wireshark-1.0.0-includes/stat_menu.h | 64 + .../wireshark-1.0.0-includes/statusbar.h | 56 + .../wireshark-1.0.0-includes/strerror.h | 33 + .../wireshark-1.0.0-includes/strptime.h | 32 + .../wireshark-1.0.0-includes/summary.h | 76 + .../wireshark-1.0.0-includes/svnversion.h | 1 + .../wireshark-1.0.0-includes/sync_pipe.h | 80 + .../wireshark-1.0.0-includes/tap-rtp-common.h | 49 + .../tap_dfilter_dlg.h | 73 + .../wireshark-1.0.0-includes/tempfile.h | 43 + .../wireshark-1.0.0-includes/text2pcap.h | 49 + .../wireshark-1.0.0-includes/timestats.h | 54 + .../tools/make-dissector-reg | 186 + .../tools/make-dissector-reg.py | 238 ++ .../wireshark-1.0.0-includes/ui_util.h | 79 + .../wireshark-1.0.0-includes/util.h | 60 + .../wireshark-1.0.0-includes/version_info.h | 79 + .../wireshark-1.0.0-includes/wiretap/5views.h | 30 + .../wiretap/airopeek9.h | 29 + .../wiretap/ascend-grammar.h | 90 + .../wiretap/ascend-int.h | 54 + .../wiretap/ascend-scanner_lex.h | 6 + .../wireshark-1.0.0-includes/wiretap/ascend.h | 33 + .../wireshark-1.0.0-includes/wiretap/atm.h | 40 + .../wireshark-1.0.0-includes/wiretap/ber.h | 28 + .../wiretap/btsnoop.h | 30 + .../wireshark-1.0.0-includes/wiretap/buffer.h | 58 + .../wiretap/catapult_dct2000.h | 30 + .../wiretap/commview.h | 33 + .../wireshark-1.0.0-includes/wiretap/cosine.h | 32 + .../wireshark-1.0.0-includes/wiretap/csids.h | 29 + .../wiretap/dbs-etherwatch.h | 29 + .../wireshark-1.0.0-includes/wiretap/erf.h | 102 + .../wiretap/etherpeek.h | 29 + .../wireshark-1.0.0-includes/wiretap/eyesdn.h | 29 + .../wiretap/file_util.h | 136 + .../wiretap/file_wrappers.h | 57 + .../wiretap/hcidump.h | 28 + .../wiretap/i4b_trace.h | 92 + .../wiretap/i4btrace.h | 29 + .../wiretap/iptrace.h | 29 + .../wiretap/iseries.h | 28 + .../wireshark-1.0.0-includes/wiretap/k12.h | 28 + .../wiretap/k12text_lex.h | 6 + .../wiretap/lanalyzer.h | 176 + .../wiretap/libpcap.h | 106 + .../wiretap/mpeg-audio.h | 98 + .../wireshark-1.0.0-includes/wiretap/mpeg.h | 32 + .../wireshark-1.0.0-includes/wiretap/netmon.h | 30 + .../wiretap/netscreen.h | 53 + .../wireshark-1.0.0-includes/wiretap/nettl.h | 124 + .../wiretap/network_instruments.h | 127 + .../wiretap/netxray.h | 32 + .../wiretap/ngsniffer.h | 30 + .../wireshark-1.0.0-includes/wiretap/pcapng.h | 30 + .../wiretap/pppdump.h | 28 + .../wireshark-1.0.0-includes/wiretap/radcom.h | 29 + .../wireshark-1.0.0-includes/wiretap/snoop.h | 30 + .../wiretap/toshiba.h | 28 + .../wireshark-1.0.0-includes/wiretap/visual.h | 35 + .../wireshark-1.0.0-includes/wiretap/vms.h | 29 + .../wiretap/wtap-int.h | 482 +++ .../wireshark-1.0.0-includes/wiretap/wtap.h | 944 +++++ 700 files changed, 95071 insertions(+), 11 deletions(-) create mode 100644 openflow/.gitignore create mode 100644 openflow/COPYING create mode 100644 openflow/ChangeLog create mode 100644 openflow/INSTALL create mode 100644 openflow/Makefile.am create mode 100644 openflow/README create mode 100644 openflow/README.hwtables create mode 100644 openflow/README.kernel create mode 100644 openflow/acinclude.m4 create mode 100755 openflow/boot.sh create mode 100644 openflow/configure.ac create mode 100644 openflow/controller/.dirstamp create mode 100644 openflow/controller/.gitignore create mode 100644 openflow/controller/automake.mk create mode 100644 openflow/controller/controller.8.in create mode 100644 openflow/controller/controller.c create mode 100644 openflow/datapath/.gitignore create mode 100644 openflow/datapath/Makefile.am create mode 100644 openflow/datapath/Modules.mk create mode 100644 openflow/datapath/chain.c create mode 100644 openflow/datapath/chain.h create mode 100644 openflow/datapath/compat.h create mode 100644 openflow/datapath/crc32.c create mode 100644 openflow/datapath/crc32.h create mode 100644 openflow/datapath/datapath.c create mode 100644 openflow/datapath/datapath.h create mode 100644 openflow/datapath/dp_act.c create mode 100644 openflow/datapath/dp_act.h create mode 100644 openflow/datapath/dp_dev.c create mode 100644 openflow/datapath/dp_dev.h create mode 100644 openflow/datapath/dp_notify.c create mode 100644 openflow/datapath/flow.c create mode 100644 openflow/datapath/flow.h create mode 100644 openflow/datapath/forward.c create mode 100644 openflow/datapath/forward.h create mode 100644 openflow/datapath/hwtable_dummy/Modules.mk create mode 100644 openflow/datapath/hwtable_dummy/hwtable_dummy.c create mode 100644 openflow/datapath/hwtable_nf2/Modules.mk create mode 100644 openflow/datapath/hwtable_nf2/README create mode 100644 openflow/datapath/hwtable_nf2/nf2.h create mode 100644 openflow/datapath/hwtable_nf2/nf2_flowtable.c create mode 100644 openflow/datapath/hwtable_nf2/nf2_flowtable.h create mode 100644 openflow/datapath/hwtable_nf2/nf2_hwapi.h create mode 100644 openflow/datapath/hwtable_nf2/nf2_lib.c create mode 100644 openflow/datapath/hwtable_nf2/nf2_lib.h create mode 100644 openflow/datapath/hwtable_nf2/nf2_openflow.c create mode 100644 openflow/datapath/hwtable_nf2/nf2_openflow.h create mode 100644 openflow/datapath/hwtable_nf2/nf2_procfs.c create mode 100644 openflow/datapath/hwtable_nf2/nf2_procfs.h create mode 100644 openflow/datapath/hwtable_nf2/nf2_reg.h create mode 100644 openflow/datapath/hwtable_nf2/openflow_switch.bit create mode 100644 openflow/datapath/linux-2.6/.gitignore create mode 100644 openflow/datapath/linux-2.6/Kbuild.in create mode 100644 openflow/datapath/linux-2.6/Makefile.in create mode 100644 openflow/datapath/linux-2.6/Makefile.main.in create mode 100644 openflow/datapath/linux-2.6/Modules.mk create mode 100644 openflow/datapath/linux-2.6/compat-2.6/compat26.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/genetlink-brcompat.c create mode 100644 openflow/datapath/linux-2.6/compat-2.6/genetlink-openflow.c create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/asm-generic/bug.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/dmi.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/icmp.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/if_arp.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/ip.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/ipv6.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/jiffies.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/lockdep.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/mutex.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/netdevice.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/netfilter_bridge.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/netfilter_ipv4.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/netlink.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/random.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/rculist.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/skbuff.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/tcp.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/timer.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/types.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/udp.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/linux/workqueue.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/net/checksum.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/net/genetlink.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/include/net/netlink.h create mode 100644 openflow/datapath/linux-2.6/compat-2.6/random32.c create mode 100644 openflow/datapath/linux-2.6/compat-2.6/veth.c create mode 100644 openflow/datapath/linux-2.6/config/config-linux-2.6.23-rc9-kvm create mode 100644 openflow/datapath/openflow-ext.c create mode 100644 openflow/datapath/openflow-ext.h create mode 100644 openflow/datapath/private-msg.c create mode 100644 openflow/datapath/private-msg.h create mode 100644 openflow/datapath/table-hash.c create mode 100644 openflow/datapath/table-linear.c create mode 100644 openflow/datapath/table.h create mode 100644 openflow/debian/.gitignore create mode 100644 openflow/debian/changelog create mode 100755 openflow/debian/commands/reconfigure create mode 100755 openflow/debian/commands/update create mode 100644 openflow/debian/compat create mode 100644 openflow/debian/control.in create mode 100644 openflow/debian/control.modules.in create mode 100644 openflow/debian/copyright create mode 100755 openflow/debian/corekeeper.cron.daily create mode 100755 openflow/debian/corekeeper.init create mode 100644 openflow/debian/dirs create mode 100755 openflow/debian/ofp-switch-setup create mode 100644 openflow/debian/ofp-switch-setup.8 create mode 100644 openflow/debian/openflow-common.dirs create mode 100644 openflow/debian/openflow-common.install create mode 100644 openflow/debian/openflow-common.manpages create mode 100644 openflow/debian/openflow-controller.README.Debian create mode 100644 openflow/debian/openflow-controller.default create mode 100644 openflow/debian/openflow-controller.dirs create mode 100755 openflow/debian/openflow-controller.init create mode 100644 openflow/debian/openflow-controller.install create mode 100644 openflow/debian/openflow-controller.manpages create mode 100755 openflow/debian/openflow-controller.postinst create mode 100755 openflow/debian/openflow-datapath-module-_KVERS_.postinst.modules.in create mode 100644 openflow/debian/openflow-datapath-source.README.Debian create mode 100644 openflow/debian/openflow-datapath-source.copyright create mode 100644 openflow/debian/openflow-datapath-source.dirs create mode 100644 openflow/debian/openflow-datapath-source.install create mode 100644 openflow/debian/openflow-pki-server.apache2 create mode 100644 openflow/debian/openflow-pki-server.dirs create mode 100644 openflow/debian/openflow-pki-server.install create mode 100755 openflow/debian/openflow-pki-server.postinst create mode 100755 openflow/debian/openflow-pki.postinst create mode 100644 openflow/debian/openflow-switch-config.dirs create mode 100644 openflow/debian/openflow-switch-config.install create mode 100644 openflow/debian/openflow-switch-config.manpages create mode 100644 openflow/debian/openflow-switch-config.overrides create mode 100644 openflow/debian/openflow-switch-config.templates create mode 100644 openflow/debian/openflow-switch.README.Debian create mode 100644 openflow/debian/openflow-switch.dirs create mode 100755 openflow/debian/openflow-switch.init create mode 100644 openflow/debian/openflow-switch.install create mode 100644 openflow/debian/openflow-switch.logrotate create mode 100644 openflow/debian/openflow-switch.manpages create mode 100755 openflow/debian/openflow-switch.postinst create mode 100755 openflow/debian/openflow-switch.postrm create mode 100644 openflow/debian/openflow-switch.template create mode 100644 openflow/debian/po/POTFILES.in create mode 100755 openflow/debian/rules create mode 100644 openflow/doc/of-spec/.gitignore create mode 100644 openflow/doc/of-spec/Makefile create mode 100644 openflow/doc/of-spec/README create mode 100755 openflow/doc/of-spec/appendix.tex create mode 100644 openflow/doc/of-spec/credits.tex create mode 100755 openflow/doc/of-spec/figure_flow_table_secchan.png create mode 100644 openflow/doc/of-spec/header_parsing_flowchart.graffle create mode 100755 openflow/doc/of-spec/make_latex_input.pl create mode 100644 openflow/doc/of-spec/openflow-spec-v1.0.0.tex create mode 100644 openflow/doc/of-spec/packet_flow_flowchart.graffle create mode 100644 openflow/hw-lib/automake.mk create mode 100644 openflow/hw-lib/nf2/README create mode 100644 openflow/hw-lib/nf2/debug.h create mode 100644 openflow/hw-lib/nf2/hw_flow.c create mode 100644 openflow/hw-lib/nf2/hw_flow.h create mode 100644 openflow/hw-lib/nf2/nf2.h create mode 100644 openflow/hw-lib/nf2/nf2_drv.c create mode 100644 openflow/hw-lib/nf2/nf2_drv.h create mode 100644 openflow/hw-lib/nf2/nf2_lib.c create mode 100644 openflow/hw-lib/nf2/nf2_lib.h create mode 100644 openflow/hw-lib/nf2/nf2util.c create mode 100644 openflow/hw-lib/nf2/nf2util.h create mode 100644 openflow/hw-lib/nf2/reg_defines_openflow_switch.h create mode 100644 openflow/hw-lib/skeleton/debug.h create mode 100644 openflow/hw-lib/skeleton/hw_drv.c create mode 100644 openflow/hw-lib/skeleton/hw_drv.h create mode 100644 openflow/hw-lib/skeleton/hw_flow.c create mode 100644 openflow/hw-lib/skeleton/hw_flow.h create mode 100644 openflow/hw-lib/skeleton/of_hw_platform.h create mode 100644 openflow/hw-lib/skeleton/os.h create mode 100644 openflow/hw-lib/skeleton/port.c create mode 100644 openflow/hw-lib/skeleton/port.h create mode 100644 openflow/hw-lib/skeleton/sample_plat.c create mode 100644 openflow/hw-lib/skeleton/sample_plat.h create mode 100644 openflow/hw-lib/skeleton/txrx.c create mode 100644 openflow/hw-lib/skeleton/txrx.h create mode 100644 openflow/include/.gitignore create mode 100644 openflow/include/automake.mk create mode 100644 openflow/include/openflow/automake.mk create mode 100644 openflow/include/openflow/nicira-ext.h create mode 100644 openflow/include/openflow/of_hw_api.h create mode 100644 openflow/include/openflow/openflow-ext.h create mode 100644 openflow/include/openflow/openflow-netlink.h create mode 100644 openflow/include/openflow/openflow.h create mode 100644 openflow/include/openflow/private-ext.h create mode 100644 openflow/m4/libopenflow.m4 create mode 100644 openflow/m4/nx-build.m4 create mode 100644 openflow/regress/CREDITS create mode 100644 openflow/regress/INSTALL create mode 100644 openflow/regress/LICENSE create mode 100644 openflow/regress/README create mode 100644 openflow/regress/bin/eth.map create mode 100644 openflow/regress/bin/nf2.map create mode 100644 openflow/regress/bin/of_hp_eth.map create mode 100755 openflow/regress/bin/of_hp_setup.pl create mode 100755 openflow/regress/bin/of_hp_teardown.pl create mode 100755 openflow/regress/bin/of_hp_test.pl create mode 100755 openflow/regress/bin/of_hp_test_6600.pl create mode 100755 openflow/regress/bin/of_kmod_setup.pl create mode 100755 openflow/regress/bin/of_kmod_teardown.pl create mode 100755 openflow/regress/bin/of_kmod_test.pl create mode 100755 openflow/regress/bin/of_kmod_veth_setup.pl create mode 100755 openflow/regress/bin/of_kmod_veth_teardown.pl create mode 100755 openflow/regress/bin/of_kmod_veth_test.pl create mode 100755 openflow/regress/bin/of_nf2_setup.pl create mode 100755 openflow/regress/bin/of_nf2_teardown.pl create mode 100755 openflow/regress/bin/of_nf2_test.pl create mode 100644 openflow/regress/bin/of_ovs_eth.map create mode 100755 openflow/regress/bin/of_ovs_setup.pl create mode 100755 openflow/regress/bin/of_ovs_teardown.pl create mode 100755 openflow/regress/bin/of_ovs_test.pl create mode 100755 openflow/regress/bin/of_ovs_user_setup.pl create mode 100755 openflow/regress/bin/of_ovs_user_teardown.pl create mode 100755 openflow/regress/bin/of_ovs_user_test.pl create mode 100755 openflow/regress/bin/of_ovs_user_veth_test.pl create mode 100755 openflow/regress/bin/of_ovs_veth_test.pl create mode 100755 openflow/regress/bin/of_user_setup.pl create mode 100755 openflow/regress/bin/of_user_teardown.pl create mode 100755 openflow/regress/bin/of_user_test.pl create mode 100755 openflow/regress/bin/of_user_veth_setup.pl create mode 100755 openflow/regress/bin/of_user_veth_teardown.pl create mode 100755 openflow/regress/bin/of_user_veth_test.pl create mode 100644 openflow/regress/bin/veth.map create mode 100755 openflow/regress/bin/veth_setup.pl create mode 100755 openflow/regress/bin/veth_teardown.pl create mode 100755 openflow/regress/projects/black_box/regress/common/setup create mode 100755 openflow/regress/projects/black_box/regress/common/teardown create mode 100755 openflow/regress/projects/black_box/regress/test_add_flow_latency/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_barrier/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_cookie_flow_expired/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_cookie_flow_stats/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_delete/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_delete_send_flow_exp/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_delete_strict/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_drop_exact/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_failover_close/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_failover_startup/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_failover_stop_responding/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_flow_expired/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_flow_expired_idle_timeout/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_flow_expired_precision/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_flow_expired_send_flow_exp/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_flow_mod_check/run.pl create mode 100644 openflow/regress/projects/black_box/regress/test_flow_mod_latency/run-port3.pl create mode 100755 openflow/regress/projects/black_box/regress/test_flow_mod_latency/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_flow_stats/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_flow_stats_precision/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_after_expiration/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_any_port/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_bandwidth_fixed/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_bandwidth_random/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_broadcast_exact_port/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_all/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_arp_all/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_arp_controller/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_arp_fool/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_arp_port/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_controller/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_icmp_all/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_icmp_controller/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_icmp_fool/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_icmp_port/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_modify_action/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_exact_port/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_overlapping_flow_entries/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_all/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_all/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_controller/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_fool/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_arp_port/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_controller/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_all/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_controller/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_fool/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_icmp_port/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_modify_action/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_forward_wildcard_port/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_hello/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_ip_offset/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_ip_options/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_ip_protocol/case-c.pl create mode 100755 openflow/regress/projects/black_box/regress/test_ip_protocol/case-d.pl create mode 100755 openflow/regress/projects/black_box/regress/test_ip_protocol/case-e.pl create mode 100755 openflow/regress/projects/black_box/regress/test_ip_protocol/case-tcp.pl create mode 100755 openflow/regress/projects/black_box/regress/test_ip_protocol/case-udp.pl create mode 100755 openflow/regress/projects/black_box/regress/test_llc/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_miss_send_length/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_packet_in/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_packet_out/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_port_stats/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_queue_config/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_queue_forward/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_queue_stats/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_receive_bandwidth_fixed/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_send_bandwidth_fixed/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_send_bandwidth_random/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_set_dl_nw_flip/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_set_n_match_nw_tos/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_set_nw_dst/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_stats_desc/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_switch_config/run.pl create mode 100755 openflow/regress/projects/black_box/regress/test_tcp_options/run.pl create mode 100644 openflow/regress/projects/black_box/regress/tests.txt create mode 100755 openflow/regress/projects/controller_disconnect/regress/common/setup create mode 100755 openflow/regress/projects/controller_disconnect/regress/common/teardown create mode 100755 openflow/regress/projects/controller_disconnect/regress/test_emergency_table/run.pl create mode 100644 openflow/regress/projects/controller_disconnect/regress/tests.txt create mode 100755 openflow/regress/projects/learning_switch/regress/common/setup create mode 100755 openflow/regress/projects/learning_switch/regress/common/teardown create mode 100755 openflow/regress/projects/learning_switch/regress/test_broadcast/run.pl create mode 100755 openflow/regress/projects/learning_switch/regress/test_forward_bandwidth/run.pl create mode 100755 openflow/regress/projects/learning_switch/regress/test_forward_latency/run.pl create mode 100755 openflow/regress/projects/learning_switch/regress/test_hub_connected/run.pl create mode 100755 openflow/regress/projects/learning_switch/regress/test_unicast_known/run.pl create mode 100755 openflow/regress/projects/learning_switch/regress/test_unicast_move/run.pl create mode 100755 openflow/regress/projects/learning_switch/regress/test_unicast_multiple_hosts/run.pl create mode 100755 openflow/regress/projects/learning_switch/regress/test_unicast_self/run.pl create mode 100755 openflow/regress/projects/learning_switch/regress/test_unicast_unknown/run.pl create mode 100644 openflow/regress/projects/learning_switch/regress/tests.txt create mode 100644 openflow/regress/projects/regress.txt create mode 100755 openflow/regress/scripts/copy_NF2_code.sh create mode 100644 openflow/regress/scripts/env_vars create mode 100755 openflow/regress/scripts/install_deps.pl create mode 100755 openflow/regress/scripts/install_perlmods_apt.pl create mode 100755 openflow/regress/scripts/make_release.pl create mode 100644 openflow/secchan/.dirstamp create mode 100644 openflow/secchan/.gitignore create mode 100644 openflow/secchan/automake.mk create mode 100644 openflow/secchan/commands/automake.mk create mode 100755 openflow/secchan/commands/reboot create mode 100644 openflow/secchan/discovery.c create mode 100644 openflow/secchan/discovery.h create mode 100644 openflow/secchan/emerg-flow.c create mode 100644 openflow/secchan/emerg-flow.h create mode 100644 openflow/secchan/fail-open.c create mode 100644 openflow/secchan/fail-open.h create mode 100644 openflow/secchan/failover.c create mode 100644 openflow/secchan/failover.h create mode 100644 openflow/secchan/in-band.c create mode 100644 openflow/secchan/in-band.h create mode 100644 openflow/secchan/ofprotocol.8.in create mode 100644 openflow/secchan/port-watcher.c create mode 100644 openflow/secchan/port-watcher.h create mode 100644 openflow/secchan/protocol-stat.c create mode 100644 openflow/secchan/protocol-stat.h create mode 100644 openflow/secchan/ratelimit.c create mode 100644 openflow/secchan/ratelimit.h create mode 100644 openflow/secchan/secchan.c create mode 100644 openflow/secchan/secchan.h create mode 100644 openflow/secchan/status.c create mode 100644 openflow/secchan/status.h create mode 100644 openflow/secchan/stp-secchan.c create mode 100644 openflow/secchan/stp-secchan.h create mode 100755 openflow/soexpand.pl create mode 100644 openflow/tests/.dirstamp create mode 100644 openflow/tests/.gitignore create mode 100644 openflow/tests/automake.mk create mode 100755 openflow/tests/flowgen.pl create mode 100644 openflow/tests/test-dhcp-client.c create mode 100755 openflow/tests/test-flows create mode 100644 openflow/tests/test-flows.c create mode 100755 openflow/tests/test-flows.sh create mode 100755 openflow/tests/test-hmap create mode 100644 openflow/tests/test-hmap.c create mode 100644 openflow/tests/test-list.c create mode 100644 openflow/tests/test-stp-ieee802.1d-1998 create mode 100644 openflow/tests/test-stp-ieee802.1d-2004-fig17.4 create mode 100644 openflow/tests/test-stp-ieee802.1d-2004-fig17.6 create mode 100644 openflow/tests/test-stp-ieee802.1d-2004-fig17.7 create mode 100644 openflow/tests/test-stp-iol-io-1.1 create mode 100644 openflow/tests/test-stp-iol-io-1.2 create mode 100644 openflow/tests/test-stp-iol-io-1.4 create mode 100644 openflow/tests/test-stp-iol-io-1.5 create mode 100644 openflow/tests/test-stp-iol-op-1.1 create mode 100644 openflow/tests/test-stp-iol-op-1.4 create mode 100644 openflow/tests/test-stp-iol-op-3.1 create mode 100644 openflow/tests/test-stp-iol-op-3.3 create mode 100644 openflow/tests/test-stp-iol-op-3.4 create mode 100644 openflow/tests/test-stp.c create mode 100755 openflow/tests/test-stp.sh create mode 100644 openflow/tests/test-type-props.c create mode 100644 openflow/third-party/.gitignore create mode 100644 openflow/third-party/README create mode 100644 openflow/third-party/automake.mk create mode 100644 openflow/third-party/ofp-tcpdump.patch create mode 100644 openflow/udatapath/.dirstamp create mode 100644 openflow/udatapath/.gitignore create mode 100644 openflow/udatapath/automake.mk create mode 100644 openflow/udatapath/chain.c create mode 100644 openflow/udatapath/chain.h create mode 100644 openflow/udatapath/crc32.c create mode 100644 openflow/udatapath/crc32.h create mode 100644 openflow/udatapath/datapath.c create mode 100644 openflow/udatapath/datapath.h create mode 100644 openflow/udatapath/dp_act.c create mode 100644 openflow/udatapath/dp_act.h create mode 100644 openflow/udatapath/of_ext_msg.c create mode 100644 openflow/udatapath/of_ext_msg.h create mode 100644 openflow/udatapath/ofdatapath.8.in create mode 100644 openflow/udatapath/private-msg.c create mode 100644 openflow/udatapath/private-msg.h create mode 100644 openflow/udatapath/switch-flow.c create mode 100644 openflow/udatapath/switch-flow.h create mode 100644 openflow/udatapath/table-hash.c create mode 100644 openflow/udatapath/table-linear.c create mode 100644 openflow/udatapath/table.h create mode 100644 openflow/udatapath/udatapath.c create mode 100644 openflow/utilities/.dirstamp create mode 100644 openflow/utilities/.gitignore create mode 100644 openflow/utilities/automake.mk create mode 100644 openflow/utilities/dpctl.8.in create mode 100644 openflow/utilities/dpctl.c create mode 100644 openflow/utilities/ofp-discover.8.in create mode 100644 openflow/utilities/ofp-discover.c create mode 100644 openflow/utilities/ofp-kill.8.in create mode 100644 openflow/utilities/ofp-kill.c create mode 100644 openflow/utilities/ofp-parse-leaks create mode 100755 openflow/utilities/ofp-parse-leaks.in create mode 100755 openflow/utilities/ofp-pki-cgi.in create mode 100644 openflow/utilities/ofp-pki.8.in create mode 100755 openflow/utilities/ofp-pki.in create mode 100644 openflow/utilities/vlogconf.8.in create mode 100644 openflow/utilities/vlogconf.c create mode 100644 openflow/utilities/wireshark_dissectors/Makefile create mode 100644 openflow/utilities/wireshark_dissectors/README create mode 100644 openflow/utilities/wireshark_dissectors/openflow/.gitignore create mode 100644 openflow/utilities/wireshark_dissectors/openflow/Makefile create mode 100644 openflow/utilities/wireshark_dissectors/openflow/Makefile.am create mode 100644 openflow/utilities/wireshark_dissectors/openflow/Makefile.common create mode 100755 openflow/utilities/wireshark_dissectors/openflow/build_distribution_tarball.sh create mode 100644 openflow/utilities/wireshark_dissectors/openflow/moduleinfo.h create mode 100644 openflow/utilities/wireshark_dissectors/openflow/packet-openflow.c create mode 100644 openflow/utilities/wireshark_dissectors/openflow/plugin.c create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/airpcap.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/airpcap_loader.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/alert_box.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-pcap-util-int.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-pcap-util.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture-wpcap.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_errs.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_info.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_opts.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_stop_conditions.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_sync.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_ui_utils.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/capture_wpcap_packet.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/cfile.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/clopts_common.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/cmdarg_err.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/color.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/color_filters.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/conditions.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h.in create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/config.h.win32 create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/disabled_protos.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/addr_and_mask.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/addr_resolv.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/address.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/adler32.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/afn.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/aftypes.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/arcnet_pids.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/arptypes.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/asm_utils.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/asn1.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/atalk-utils.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/base64.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/bitswap.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/bridged_pids.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/camel-persistentdata.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/charsets.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/chdlctypes.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/circuit.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/codecs.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column-utils.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/column_info.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/conversation.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc10.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc16.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc32.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crc6.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crcdrm.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_debug.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_int.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_interop.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_rijndael.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_system.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_user.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/airpdcap_ws.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-des.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-md4.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-md5.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-rc4.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/crypt-sha1.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/crypt/wep-wpadefs.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter-int.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter-macro.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfilter.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfunctions.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/dfvm.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/drange.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/gencode.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/glib-util.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/grammar.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/scanner_lex.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/semcheck.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-function.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-range.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/sttype-test.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dfilter/syntax-tree.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/diam_dict.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/diam_dict_lex.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dissector_filters.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dissectors/packet-tcp.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_grammar.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_parse.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_parse_lex.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/dtd_preparse_lex.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/eap.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/emem.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/epan.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/epan_dissect.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/etypes.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ex-opt.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/except.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/exceptions.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/expert.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/filesystem.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/follow.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/frame_data.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/frequency-utils.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ftypes/ftypes-int.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ftypes/ftypes.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/funnel.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/g_ascii_strcasecmp.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/g_ascii_strtoull.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/garrayfix.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/gcp.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/gnuc_format_check.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/golay.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/greproto.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/guid-utils.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/h225-persistentdata.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/iax2_codec_type.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/in_cksum.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/inet_aton.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ip_opts.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipproto.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipv4.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ipv6-utils.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/lapd_sapi.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/llcsaps.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/next_tvb.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/nlpid.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/nstime.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/oids.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/osi-utils.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/oui.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/packet.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/packet_info.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/pint.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/plugins.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ppptypes.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/prefs-int.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/prefs.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/privileges.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/proto.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ptvcursor.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/radius_dict_lex.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/range.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/reassemble.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/reedsolomon.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/report_err.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/req_resp_hdrs.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/rtp_pt.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sctpppids.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sigcomp-udvm.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sigcomp_state_hdlr.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/slab.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sminmpec.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/sna-utils.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stat_cmd_args.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stats_tree.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stats_tree_priv.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/stream.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/strutil.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/t35.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tap-voip.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tap.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tcap-persistentdata.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tfs.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/timestamp.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/to_str.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tvbparse.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/tvbuff.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat-int.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/uat_load_lex.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/unicode-utils.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/value_string.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/ws_strsplit.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/wslua/declare_wslua.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/wslua/wslua.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/x264_prt_id.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/xdlc.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/epan/xmlstub.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/file.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/fileset.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/filters.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/g711.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/getopt.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/globals.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/inet_v6defs.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/isprint.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/log.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/main_window.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/menu.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/merge.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/mkstemp.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/packet-range.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/pcapio.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/print.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/progress_dlg.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/proto_hier_stats.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ps.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/register.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ringbuffer.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/simple_dialog.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/stat_menu.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/statusbar.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/strerror.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/strptime.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/summary.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/svnversion.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/sync_pipe.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tap-rtp-common.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tap_dfilter_dlg.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tempfile.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/text2pcap.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/timestats.h create mode 100755 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tools/make-dissector-reg create mode 100755 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/tools/make-dissector-reg.py create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/ui_util.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/util.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/version_info.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/5views.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/airopeek9.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-grammar.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-int.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend-scanner_lex.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ascend.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/atm.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ber.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/btsnoop.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/buffer.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/catapult_dct2000.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/commview.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/cosine.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/csids.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/dbs-etherwatch.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/erf.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/etherpeek.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/eyesdn.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/file_util.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/file_wrappers.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/hcidump.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/i4b_trace.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/i4btrace.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/iptrace.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/iseries.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/k12.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/k12text_lex.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/lanalyzer.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/libpcap.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/mpeg-audio.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/mpeg.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netmon.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netscreen.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/nettl.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/network_instruments.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/netxray.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/ngsniffer.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/pcapng.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/pppdump.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/radcom.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/snoop.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/toshiba.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/visual.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/vms.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/wtap-int.h create mode 100644 openflow/utilities/wireshark_dissectors/wireshark-1.0.0-includes/wiretap/wtap.h diff --git a/mininet/bin/dmn b/mininet/bin/dmn index 1801422e..cdfc6759 100755 --- a/mininet/bin/dmn +++ b/mininet/bin/dmn @@ -550,6 +550,7 @@ class DistrinetRunner( object ): if opts.workers: workers = opts.workers.split( ',' ) master = workers[0] + workers=workers[1:] if opts.workers or opts.provision or opts.placement_file_path: warn( '*** WARNING: Experimental cloud mode!\n' @@ -587,7 +588,6 @@ class DistrinetRunner( object ): # get the info from the experiment file jump=experiment_data["bastion"] workers=experiment_data["workers"] - master=workers[0] # use the dummy mapper with the placement in the experiment file mapper= DummyMapper(places=experiment_data["mapping"]) diff --git a/mininet/mininet/distrinet.py b/mininet/mininet/distrinet.py index 57aa87f2..6f5fa9d8 100755 --- a/mininet/mininet/distrinet.py +++ b/mininet/mininet/distrinet.py @@ -519,7 +519,7 @@ def buildFromTopo( self, topo=None ): if not waitStart: nodes = self.hosts + self.switches - _info ("[starting\n") + info ("[starting\n") for node in nodes: _info ("connectTarget {} ".format( node.name)) node.connectTarget() @@ -541,7 +541,7 @@ def buildFromTopo( self, topo=None ): for node in nodes: node.waitCreated() _info ("createdContainer {} ".format(node.name)) - + _info ("nodes created\n") for node in nodes: _info ("create admin interface {} ".format( node.name)) node.addContainerInterface(intfName="admin", brname="admin-br", wait=False,autoSetDocker=self.autoSetDocker) @@ -572,14 +572,14 @@ def buildFromTopo( self, topo=None ): _info ("connected {} ".format( node.name)) for node in nodes: - _info ("startshell {} ".format( node.name) ) + info ("startshell {} ".format( node.name) ) node.asyncStartShell() for node in nodes: node.waitStarted() - _info ("startedshell {}".format( node.name)) + info ("startedshell {}".format( node.name)) for node in nodes: - _info ("finalize {}".format( node.name)) + info ("finalize {}".format( node.name)) node.finalizeStartShell() _info ("\n") diff --git a/mininet/mininet/lxc_container.py b/mininet/mininet/lxc_container.py index 64af5c29..95f115fc 100644 --- a/mininet/mininet/lxc_container.py +++ b/mininet/mininet/lxc_container.py @@ -349,10 +349,13 @@ def createContainer(self,autoSetDocker=False, **params): cmds = [] # initialise the container if autoSetDocker: - cmd = "docker run -v /root/alcor-control-agent/:/mnt/host/code -it --privileged --cap-add=NET_ADMIN --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --name {} --net=none {} /bin/bash < /dev/null ".format(self.name, self.image) + if self.image=="ubuntu": + cmd = "docker run -v /root/alcor-control-agent/:/mnt/host/code -itd --privileged --cap-add=NET_ADMIN --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --name {} --net=none {} /bin/bash".format(self.name, self.image) + else: + cmd="docker run -itd --privileged --cap-add=NET_ADMIN --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --name {} --net=none {} /bin/bash".format(self.name, self.image) else: cmd = "lxc init {} {} < /dev/null ".format(self.image, self.name) - info ("{}\n".format(cmd)) + info("{}\n".format(cmd)) cmds.append(cmd) # limit resources if autoSetDocker: @@ -373,9 +376,6 @@ def createContainer(self,autoSetDocker=False, **params): cmds.append("lxc config set {} limits.memory {}".format(self.name, self.memory)) # start the container cmds.append("lxc start {}".format(self.name)) - - - cmd = ";".join(cmds) self.targetSsh.sendCmd(cmd) diff --git a/openflow/.gitignore b/openflow/.gitignore new file mode 100644 index 00000000..be6113cd --- /dev/null +++ b/openflow/.gitignore @@ -0,0 +1,44 @@ +#*# +*.a +*.d +*.ko +*.la +*.lo +*.loT +*.mod.c +*.o +*.o +*.pyc +*.so +*~ +.#* +.*.cmd +.deps +.libs +.tmp_versions +/Makefile +/Makefile.in +/aclocal.m4 +/autom4te.cache +/build-arch-stamp +/build-aux +/build-indep-stamp +/compile +/config.guess +/config.h +/config.h.in +/config.log +/config.status +/config.sub +/configure +/configure-stamp +/depcomp +/install-sh +/missing +/stamp-h1 +Module.symvers +TAGS +cscope.* +ext.m4 +ext.mk +tags diff --git a/openflow/COPYING b/openflow/COPYING new file mode 100644 index 00000000..ab5f3705 --- /dev/null +++ b/openflow/COPYING @@ -0,0 +1,1054 @@ +Source file copyrights are indicated at the top of each file. + +Files not in the datapath/ and vswitchd/ directories or associated +subdirectories are covered under the OpenFlow license included below: + +We are making the OpenFlow specification and associated documentation +(Software) available for public use and benefit with the expectation +that others will use, modify and enhance the Software and contribute +those enhancements back to the community. However, since we would like +to make the Software available for broadest use, with as few +restrictions as possible permission is hereby granted, free of charge, +to any person obtaining a copy of this Software to deal in the Software +under the copyrights without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +The name and trademarks of copyright holder(s) may NOT be used in +advertising or publicity pertaining to the Software or any derivatives +without specific, written prior permission. + +Files in the datapath/ and its sub-directories are covered under the GNU +General Public License Version 2. Included below: + + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + +Files in vswitchd/ and its sub-directories are covered under the GNU +General Public License Version 3. Included below: + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/openflow/ChangeLog b/openflow/ChangeLog new file mode 100644 index 00000000..c2d4b49a --- /dev/null +++ b/openflow/ChangeLog @@ -0,0 +1,202 @@ +1.0.0-rev1 - XX XXX 2010 +------------------------ + - Changes to regression suite: + - Added testing support for Open vSwitch + - Updated HP-ProCurve scripts + - Minor fixes applied to libraries + - Fixes applied to the following tests: + test_switch_config, test_forward_broadcast_exact_port, + test_set_n_match_nw_tos, test_set_nw_dst, + test_failover_startup + - Added test to verify flipping of src/dst MAC and IP + - Ability to disable slicing, VLAN, and barrier in tests + - Can easily run a single test + For more information, see regress/README + +1.0.0 - 31 Dec 2009 +------------------- + - Fixed Wireshark plugin warnings + - Clarified purpose of actions field in ofp_switch_features in spec + + Known issues: + - isolation provided by the slicing mechanism has been + observed to degrade when run on systems with low performance CPUs. + Investigations are underway to improve isolation on such systems. + +1.0.0-RC1 - 19 Dec 2009 +----------------------- + - Changed wire protocol version to 0x01 + - Added slicing support + - Improved resolution of flow duration in stats/expiry + - Added flow cookies to flows + - Enable matching on IP fields inside ARP packets + - Enable port stats to be retrieved for individual ports + - Added ability to match on IP ToS bits + - Added datapath description to desc stats + - Added ability to control slicing queues from dpctl + - Set datapath description from dpctl + - Removed kernel datapath from reference switch + (will be release separately) + - Fix bug related to identifying overlapping flows + - Updated Wireshark dissector to support 1.0.0 features + - Added regression tests for ARP handling, flow cookies, slicing, + selective port stats, flow duration precision, matching on ToS bits, and + the datapath description + + Known issues: + - isolation provided by the slicing mechanism has been + observed to degrade when run on systems with low performance CPUs. + Investigations are underway to improve isolation on such systems. + +0.9.0-rev1 - 04 Sep 2009 +------------------------ + - Added NetFPGA hardware table support (wire protocol 0x98) + - Fixed a few userspace datapath bugs + +0.9.0 - 20 Jul 2009 +------------------- + - Changed wire protocol version to 0x98 + - Removed monolithic switch process called switch + - Added userspace data plane process named ofdatapath + - Changed userspace control plane process name to ofprotocol + - Changed kernelspace data plane extension name to ofdatapath.ko + - Changed NetFPGA kernelspace extestion name to ofdatapath_netfpga.ko + - Removed Linux 2.4 kerel support + - Added simple controller failover feature + - Added emergency flow cache feature + - Added barrier command + - Added 802.1Q VLAN priority bits match feature + - Clarified flow expiration, renamed flow expiration to flow removed + - Added protocol statistics collector + - Added IP ToS/DSCP rewrite feature + - Changed port enumeration at 1 instead of 0 + - Clarified emergeency flow cache behavior + - Clarified definition of datapath ID + - Clarified meaning of a zero-size miss_send_len + - Clarified meaning of a zero-size max_len in output action + - Changed protocol structure alignment to ensure 64-bit + +v0.8.9 r2 - 23 Jan 2009 +----------------------- + - Added NetFPGA hardware table support (wire protocol 0x97) + - Added regression tests on port_stats, flow_stats, drop, ICMP handling + - Bug fixes + +v0.8.9~1 - 01 Dec 2008 +---------------------- + - Added support for IP netmasks + - Added new physical port stats + - Added IN_PORT virtual port + - Added echo request/response + - Added detection of link and port status changes + - Added ability to configure port status from controller + - Added support for vendor extensions + - Added support for variable length actions + - Added support for matching ICMP type and code + - Added support for listing and deleting flows based on output port action + - Added support for modifying VLAN priority tag + - Increased max supported ports to 65280 + - More explicit handling for IP fragments + - Added support for 802.1D spanning tree + - Added OFPFC_MODIFY command to Flow Mod message + - Provided more flexible description of tables to controller + - Make port modification more explicit + - Made Packet Out message more consistent + - Added hard timeout value to Flow Mod message + - Added reason field for Flow Expired message + - Reworked initial handshake to support backwards compatibility + - Added OFPST_DESC stat for returning description of hw/sw + - Added support for loadable hardware table support modules** + - In-band control now supported** + - 802.1D spanning tree support** + - Automatic controller discovery (via DHCP) now supported** + - Improved support for older 2.6.x kernels** + - Switch can now "fail open" as a MAC-learning switch if the controller cannot be contacted** + - Debian packages may now be built** + - Fixed bugs in SSL support + - Most programs now take --detach and --pidfile options to run as daemon + - Numerous bug fixes + + ** Only supported in the kernel module for the time-being. + +v0.8.1 - 14 May 2008 +-------------------- + - No longer set nwsrc/nwdst fields in flow structs on ARP packets + - Various bug fixes and tweaks + +v0.8.0 - 04 May 2008 +-------------------- + - Added support for flow entry priorities + - Added support for all stats messages + - Added support for OFPP_TABLE virtual port + - Removed MAC tables + - Various bug fixes and tweaks + +v0.2.1 - 28 Mar 2008 +-------------------- + - Fixed build problem when SSL enabled + +v0.2.0 - 28 Mar 2008 +-------------------- + - Added userspace switch reference implementation + +v0.1.9 - 19 Mar 2008 +-------------------- + - Added SSL/TLS support + - Various bug fixes and tweaks + +v0.1.8 - 03 Mar 2008 +-------------------- + - Added support for cross-compilation + - Various bug fixes and tweaks + +v0.1.7 - 07 Feb 2008 +-------------------- + - Allow permanent flow entries to be set + - Added patch for tcpdump that allows parsing of OpenFlow messages + - Various bug fixes and tweaks + +v0.1.6 - 05 Feb 2008 +-------------------- + - Added support for Linux 2.6.24 + - Set nwsrc/nwdst fields in flow structs on ARP packets + - Various bug fixes and tweaks + +v0.1.5 - 17 Jan 2008 +-------------------- + - Added support for Linux 2.4.20 + - Added support for GCC 2.95 + +v0.1.4 - 15 Jan 2008 +-------------------- + - Decode and print port_status messages + - Fixed build problems on big-endian systems + - Fixed compatibility for older 2.6 kernels + - Various bug fixes and tweaks + +v0.1.3 - 08 Jan 2008 +-------------------- + - Added support for flow expiration messages + - Decode and print all datapath-generated messages in dpctl's "monitor" + - Added "--noflow" option to controller + - Various bug fixes and tweaks + +v0.1.2 - 07 Jan 2008 +-------------------- + - Fixed distribution to include ofp_pcap.h + - Removed autoconf C++ checks + +v0.1.1 - 18 Dec 2007 +-------------------- + - Fixed support for Linux 2.4.35 and 2.6.22 + - Added support for Linux 2.6.15 + - Added "vlogconf" utility to modify logging configuration + - Added better support for SNAP headers + - Improved printing of flow information in dpctl + - Made kernel code consistently use tabs instead of spaces + - Removed libpcap requirement for building + - Various bug fixes and tweaks + +v0.1.0 - 30 Nov 2007 +-------------------- + - Initial release diff --git a/openflow/INSTALL b/openflow/INSTALL new file mode 100644 index 00000000..f236e16a --- /dev/null +++ b/openflow/INSTALL @@ -0,0 +1,513 @@ + Installation Instructions for OpenFlow Reference Release + +This document describes how to build, install, and execute the +reference implementation of OpenFlow. Please send any comments to: + + + +Contents +======== + +The OpenFlow reference implementation includes one OpenFlow switch +implementations: + + - The "userspace datapath-based switch": This divides the switch + into a userspace "datapath" (built as udatapath/ofdatapath) + and a userspace program that implements the secure channel + component (ofprotocol). The userspace datapath-based switch + does not require building a kernel module, but it is not as + fast as a kernel-based switch. + +The reference implementation also contains a simple OpenFlow +controller (built as controller/controller) and a number of related +utilities. + +Build Methods +============= + +There are two principal ways to build and install this distribution: + + - Using "configure" and "make" in the ordinary way. See + Building Conventionally below for detailed instructions. + + - As a set of Debian packages. Refer to Building Debian + Packages, below, for instructions. + +Base Prerequisites +------------------ + +Regardless of how it is built, OpenFlow has a common set of +prerequisites. To compile the userspace programs in the OpenFlow +reference distribution, you will need the following software: + + - A make program, e.g. GNU make + (http://www.gnu.org/software/make/). BSD make should also work. + + - The GNU C compiler (http://gcc.gnu.org/). We generally test + with version 4.1 or 4.2. + + - libssl, from OpenSSL (http://www.openssl.org/), is optional but + recommended. libssl is required to establish confidentiality + and authenticity in the connections among OpenFlow switches and + controllers. To enable, configure with --enable-ssl=yes. + +If you are working from a Git tree or snapshot (instead of from a +distribution tarball), or if you modify the OpenFlow build system, you +will also need the following software: + + - Autoconf version 2.60 or later (http://www.gnu.org/software/autoconf). + + - Automake version 1.10 or later (http://www.gnu.org/software/automake). + + - pkg-config (http://pkg-config.freedesktop.org/wiki/). We test + with version 0.22. + +Debian Prerequisites +-------------------- + +To build Debian packages from the OpenFlow distribution, you will need +to install a number of Debian packages in addition to the base +prerequisites listed above. These additional prerequisites may be +found listed as "Build-Depends" in debian/control in the source tree. +To check that they are installed, first install the dpkg-dev package, +then run dpkg-checkbuilddeps from the top level of the OpenFlow source +tree. + +To build Debian packages without being root, also install the +"fakeroot" package. + +Userspace Switch Prerequisites +--------------------------------- + + - To enable slicing support, "tc" frontend should be installed + (from iproute2, part of all major distributions, + http://www.linux-foundation.org/en/Net:Iproute2). + You also need to enable the following kernel configuration + options under the QoS and/or Fair queueing section : + CONFIG_NET_SCHED,CONFIG_NET_SCH_HTB (already configured that + way in most distributions). + (NOTE: You can disable slicing (and these dependencies) at runtime + using the --no-slicing option) + +Building Conventionally +======================= + +This section explains how to build and install the OpenFlow +distribution in the ordinary way using "configure" and "make". + +0. Check that you have installed all the prerequisites listed above in + the Base Prerequisites section. Run `boot.sh` if necessary to create + the configure script. + + % ./boot.sh + +1. In the top source directory, configure the package by running the + configure script. You can usually invoke configure without any + arguments: + + % ./configure + + To use a specific C compiler for compiling OpenFlow user programs, + also specify it on the configure command line, like so: + + % ./configure CC=gcc-4.2 + + If you have hardware that supports accelerated OpenFlow switching + and you have obtained a hardware table library for your hardware + and extracted it into the OpenFlow reference distribution source + tree, then you may also enable building support for the hardware + switch table with --enable-hw-lib. For more information, read + README.hwtables at the root of the OpenFlow distribution tree. + + The configure script accepts a number of other options and honors + additional environment variables. For a full list, invoke + configure with the --help option. + +2. Run make in the top source directory: + + % make + + The following binaries will be built: + + - Userspace datapath: udatapath/ofdatapath. + + - Secure channel executable: secchan/ofprotocol. + + - Controller executable: controller/controller. + + - Datapath administration utility: utilities/dpctl. + + - Runtime logging configuration utility: utilities/vlogconf. + + - Miscellaneous utilities: utilities/ofp-discover, + utilities/ofp-kill. + + - Tests: various binaries in tests/. + + If your distribution includes the OpenFlow extensions, the + following additional binaries will be built: + + - ANSI terminal support for EZIO 16x2 LCD panel: + ext/ezio/ezio-term. + + - Switch monitoring UI for small text displays: + ext/ezio/ofp-switchui. + +3. Run "make install" to install the executables and manpages into the + running system, by default under /usr/local. + +4. Test the userspace programs, as described under Testing Userspace + Programs below. + +Building Debian Packages +======================== + +Follow these instructions to build Debian packages for OpenFlow. + +0. Check that you have installed all the prerequisites listed above in + the Base Prerequisites and Debian Prerequisites sections above. + +1. In the top source directory, run the following command, as root: + + % dpkg-buildpackage + + Alternatively, if you installed the "fakeroot" package, you may run + dpkg-buildpackage as an ordinary user with the following syntax: + + % dpkg-buildpackage -rfakeroot + + The following packages will be built in the directory above the + source tree: + + - openflow-controller: The OpenFlow controller. Depends on + openflow-pki (see below). + + - openflow-switch: Install this package on a machine that acts + as an OpenFlow kernel switch. + + - openflow-datapath-source: Source code for OpenFlow's Linux + kernel module. + + - openflow-pki: Public-key infrastructure for OpenFlow. Install + this package on a machine that acts as an OpenFlow PKI server + (see "Establishing a Public Key Infrastructure" below). + + - openflow-common: Files and utilities required by more than one + of the above packages. + +2. To set up an OpenFlow controller, install the openflow-controller + package and its dependencies. You may configure it by editing + /etc/default/openflow-controller, e.g. to enable non-SSL + connections, which are disabled by default. If you change the + default settings, you will need to restart the controller by + running: + + % /etc/init.d/openflow-controller restart + +3. To set up an OpenFlow switch, install the openflow-switch package + and its dependencies. If it is to be a kernel-based switch, also + install openflow-datapath-source, then follow the instructions in + /usr/share/doc/openflow-datapath-source/README.Debian to build and + install the kernel module. + + You may configure the switch one of the following ways: + + - Completely by hand, as described under the Testing section + below. + + For the userspace datapath-based switch, this is the only + supported form of configuration. + + - By editing /etc/default/openflow-switch. You must at least + configure some network devices, by uncommenting NETDEVS and + adding the appropriate devices to the list, e.g. NETDEVS="eth0 + eth1". + + After you edit this file, you will need to start the switch by + running: + + % /etc/init.d/openflow-switch restart + + This form of configuration is not supported for the userspace + datapath-based switch. + + - By running the ofp-switch-setup program. This interactive + program will walk you through all the steps of configuring an + OpenFlow switch, including configuration of SSL certificates. + Run it without arguments, as root: + + % ofp-switch-setup + + This form of configuration is not supported for the userspace + datapath-based switch. + +Testing +======= + +The following sets of instructions show how to use the OpenFlow +reference implementation as a switch on a single machine. This can be +used to verify that the distribution built properly. For full +installation instructions, refer to the Installation section below. + +Userspace Datapath +------------------ + +These instructions use the OpenFlow userspace datapath ("ofdatapath"). + +1. Start the OpenFlow controller running in the background, by running + the "controller" program with a command like the following: + + # controller punix:/var/run/controller.sock & + + This command causes the controller to bind to the specified Unix + domain socket, awaiting connections from OpenFlow switches. See + controller(8) for details. + + The "controller" program does not require any special privilege, so + you do not need to run it as root. + +2. The commands below must run as root, so log in as root, or use a + program such as "su" to become root temporarily. + +3. Create a datapath instance running in the background. The command + below creates a datapath that listens for connections from ofprotocol + on a Unix domain socket located in /var/run and services physical + ports eth1 and eth2: + + # ofdatapath punix:/var/run/dp0.sock -i eth1,eth2 & + +4. Run ofprotocol to start the secure channel connecting the datapath and + the controller: + + # ofprotocol unix:/var/run/controller.sock unix:/var/run/dp0.sock & + +5. Devices plugged into the network ports specified in step 2 should + now be able to send packets to each other, as if they were plugged + into ports on a conventional Ethernet switch. + +Installation +============ + +This section explains how to install OpenFlow in a network with one +controller and one or more switches, each of which runs on a separate +machine. Before you begin, you must decide on one of two ways for +each switch to reach the controller over the network: + + - Use a "control network" that is completely separate from the + "data network" to be controlled ("out-of-band control"). The + location of the controller must be configured manually in this + case. + + - Use the same network for control and for data ("in-band + control"). When in-band control is used, the location of the + controller may be configured manually or discovered + automatically. We will assume manual configuration here; + please refer to ofprotocol(8) for instructions on setting up + controller discovery. + +Controller Setup +---------------- + +On the machine that is to be the OpenFlow controller, start the +"controller" program listening for connections from switches on TCP +port 6633 (the default), as shown below. + + # controller -v ptcp: + +(See controller(8) for more details) + +Make sure the machine hosting the controller is reachable by the +switch. + +Userspace Datapath-Based Setup +------------------------------ + +On a machine that is to host an OpenFlow userspace datapath-based +switch, follow the procedure below. + +0. The commands below must run as root, so log in as root, or use a + program such as "su" to become root temporarily. + +1. Create a datapath instance running in the background. The command + below creates a datapath that listens for connections from ofprotocol + on a Unix domain socket located in /var/run, services physical + ports eth1 and eth2, and creates a TAP network device named "tap0" + for use in in-band control: + + # ofdatapath punix:/var/run/dp0.sock -i eth1,eth2 --local-port=tap:tap0 & + + (See ofdatapath(8) for details.) + + If the switch will connect to the controller out-of-band, then the + --local-port option may be omitted, or --no-local-port may be + substituted. + +3. Arrange so that the switch can reach the controller over the + network. + + - If you are using out-of-band control, at this point make sure + that the switch machine can reach the controller over the + network. + + - If you are using in-band control with manual configuration, at + this point the TAP network device created in step 1 is not + bridged to any physical network, so the next step depends on + whether connectivity is required to configure the device's IP + address: + + * If the switch has a static IP address, you may configure + its IP address now, e.g.: + + # ifconfig tap0 192.168.1.1 + + * If the switch does not have a static IP address, e.g. its + IP address is obtained dynamically via DHCP, then proceed + to step 4. The DHCP client will not be able to contact + the DHCP server until the secure channel has started up. + + - If you are using in-band control with controller discovery, no + configuration is required at this point. You may proceed to + step 4. + +4. Run ofprotocol to start the secure channel connecting the datapath to + a remote controller. If the controller is running on host + 192.168.1.2 port 6633 (the default port), the ofprotocol invocation + would look like this: + + # ofprotocol unix:/var/run/dp0.sock tcp:192.168.1.2 + + - If you are using in-band control with controller discovery, omit + the second argument to the ofprotocol command. + + - If you are using out-of-band control, add --out-of-band to the + command line. + +5. If you are using in-band control with manual configuration, and the + switch obtains its IP address dynamically, then you may now obtain + the switch's IP address, e.g. by invoking a DHCP client. The + secure channel will only be able to connect to the controller after + an IP address has been obtained. + +6. The secure channel should connect to the controller within a few + seconds. It may take a little longer if controller discovery is in + use, because the switch must then also obtain its own IP address + and the controller's location via DHCP. + +Configuration +============= + +Secure operation over SSL +------------------------- + +The instructions above set up OpenFlow for operation over a plaintext +TCP connection. Production use of OpenFlow should use SSL[*] to +ensure confidentiality and authenticity of traffic among switches and +controllers. The source must be configured with --enable-ssl=yes to +build with SSL support. + +To use SSL with OpenFlow, you must set up a public-key infrastructure +(PKI) including a pair of certificate authorities (CAs), one for +controllers and one for switches. If you have an established PKI, +OpenFlow can use it directly. Otherwise, refer to "Establishing a +Public Key Infrastructure" below. + +To configure the controller to listen for SSL connections on port 6633 +(the default), invoke it as follows: + + # controller -v pssl: --private-key=PRIVKEY --certificate=CERT \ + --ca-cert=CACERT + +where PRIVKEY is a file containing the controller's private key, CERT +is a file containing the controller CA's certificate for the +controller's public key, and CACERT is a file containing the root +certificate for the switch CA. If, for example, your PKI was created +with the instructions below, then the invocation would look like: + + # controller -v pssl: --private-key=ctl-privkey.pem \ + --certificate=ctl-cert.pem --ca-cert=pki/switchca/cacert.pem + +To configure a switch to connect to a controller running on port 6633 +(the default) on host 192.168.1.2 over SSL, invoke ofprotocol as follows: + + # ofprotocol -v DATAPATH ssl:192.168.1.2 --private-key=PRIVKEY \ + --certificate=CERT --ca-cert=CACERT + +where DATAPATH is the datapath to connect to (e.g. nl:0 or +unix:/var/run/dp0.sock), PRIVKEY is a file containing the switch's +private key, CERT is a file containing the switch CA's certificate for +the switch's public key, and CACERT is a file containing the root +certificate for the controller CA. If, for example, your PKI was +created with the instructions below, then the invocation would look +like: + + # ofprotocol -v DATAPATH ssl:192.168.1.2 --private-key=sc-privkey.pem \ + --certificate=sc-cert.pem --ca-cert=pki/controllerca/cacert.pem + +[*] To be specific, OpenFlow uses TLS version 1.0 or later (TLSv1), as + specified by RFC 2246, which is very similar to SSL version 3.0. + TLSv1 was released in January 1999, so all current software and + hardware should implement it. + +Establishing a Public Key Infrastructure +---------------------------------------- + +If you do not have a PKI, the ofp-pki script included with OpenFlow +can help. To create an initial PKI structure, invoke it as: + % ofp-pki init +which will create and populate a new PKI directory. The default +location for the PKI directory depends on how the OpenFlow tree was +configured (to see the configured default, look for the --dir option +description in the output of "ofp-pki --help"). + +The pki directory contains two important subdirectories. The +controllerca subdirectory contains controller certificate authority +related files, including the following: + + - cacert.pem: Root certificate for the controller certificate + authority. This file must be provided to ofprotocol with the + --ca-cert option to enable it to authenticate valid controllers. + + - private/cakey.pem: Private signing key for the controller + certificate authority. This file must be kept secret. There is + no need for switches or controllers to have a copy of it. + +The switchca subdirectory contains switch certificate authority +related files, analogous to those in the controllerca subdirectory: + + - cacert.pem: Root certificate for the switch certificate + authority. This file must be provided to the controller program + with the --ca-cert option to enable it to authenticate valid + switches. + + - private/cakey.pem: Private signing key for the switch + certificate authority. This file must be kept secret. There is + no need for switches or controllers to have a copy of it. + +After you create the initial structure, you can create keys and +certificates for switches and controllers with ofp-pki. To create a +controller private key and certificate in files named ctl-privkey.pem +and ctl-cert.pem, for example, you could run: + % ofp-pki req+sign ctl controller +ctl-privkey.pem and ctl-cert.pem would need to be copied to the +controller for its use at runtime (they could then be deleted from +their original locations). The --private-key and --certificate +options of controller, respectively, would point to these files. + +Analogously, to create a switch private key and certificate in files +named sc-privkey.pem and sc-cert.pem, for example, you could run: + % ofp-pki req+sign sc switch +sc-privkey.pem and sc-cert.pem would need to be copied to the switch +for its use at runtime (they could then be deleted from their original +locations). The --private-key and --certificate options, +respectively, of ofprotocol would point to these files. + +Bug Reporting +------------- + +Please report problems to: + +openflow-discuss@openflowswitch.org + +or post them to our online bug tracking system at: + +http://www.openflowswitch.org/bugs/openflow diff --git a/openflow/Makefile.am b/openflow/Makefile.am new file mode 100644 index 00000000..97ac1f01 --- /dev/null +++ b/openflow/Makefile.am @@ -0,0 +1,68 @@ +# The goal of -Wno-syntax here is just to suppress the Automake warning +# about overriding distdir, below. +AUTOMAKE_OPTIONS = foreign -Wno-syntax subdir-objects +ACLOCAL_AMFLAGS = -I m4 +#SUBDIRS = datapath +SUBDIRS = + +if HAVE_DPKG_BUILDPACKAGE +distcheck-hook: + cd $(srcdir) && dpkg-buildpackage -rfakeroot -us -uc + cd $(srcdir) && fakeroot ./debian/rules clean +else +distcheck-hook: +endif + +AM_CPPFLAGS = $(SSL_CFLAGS) -g +AM_CPPFLAGS += -I $(top_srcdir)/include +AM_CPPFLAGS += -I $(top_srcdir)/lib + +AM_CFLAGS = -Wstrict-prototypes + +if NDEBUG +AM_CPPFLAGS += -DNDEBUG +AM_CFLAGS += -fomit-frame-pointer +else +AM_LDFLAGS = -export-dynamic +endif + +CLEANFILES = +DISTCLEANFILES = +EXTRA_DIST = +TESTS = +TESTS_ENVIRONMENT = +bin_PROGRAMS = +bin_SCRIPTS = +dist_commands_DATA = +dist_man_MANS = +dist_pkgdata_SCRIPTS = +dist_sbin_SCRIPTS = +man_MANS = +noinst_HEADERS = +noinst_LIBRARIES = +noinst_PROGRAMS = +noinst_SCRIPTS = + +EXTRA_DIST += README.hwtables soexpand.pl regress + +ro_c = echo '/* -*- mode: c; buffer-read-only: t -*- */' + +SUFFIXES = .in +.in: + $(PERL) $(srcdir)/soexpand.pl -I$(srcdir) < $< | \ + sed -e 's,[@]LOGDIR[@],$(LOGDIR),g' \ + -e 's,[@]PKIDIR[@],$(PKIDIR),g' \ + -e 's,[@]RUNDIR[@],$(RUNDIR),g' \ + -e 's,[@]pkgdatadir[@],$(pkgdatadir),g' \ + -e 's,[@]PERL[@],$(PERL),g' > $@ + +include lib/automake.mk +include secchan/automake.mk +include controller/automake.mk +include utilities/automake.mk +include udatapath/automake.mk +include tests/automake.mk +include include/automake.mk +include third-party/automake.mk +include debian/automake.mk +include hw-lib/automake.mk diff --git a/openflow/README b/openflow/README new file mode 100644 index 00000000..a9cca172 --- /dev/null +++ b/openflow/README @@ -0,0 +1,110 @@ + OpenFlow Reference Release + +What is OpenFlow? +----------------- + +OpenFlow is a flow-based switch specification designed to enable +researchers to run experiments in live networks. OpenFlow is based on a +simple Ethernet flow switch that exposes a standardized interface for +adding and removing flow entries. + +An OpenFlow switch consists of three parts: (1) A "flow table" in +which each flow entry is associated with an action telling the switch +how to process the flow, (2) a "secure channel" connecting the switch +to a remote process (a controller), allowing commands and packets to +be sent between the controller and the switch, and (3) an OpenFlow +protocol implementation, providing an open and standard way for a +controller to talk to the switch. + +An OpenFlow switch can thus serve as a simple datapath element that +forwards packets between ports according to flow actions defined by +the controller using OpenFlow commands. Example actions are: + + - Forward this flow's packets to the given port(s) + - Drop this flow's packets + - Encapsulate and forward this flow's packets to the controller. + +The OpenFlow switch is defined in detail in the OpenFlow switch +Specification [2]. + +What's here? +------------ + +This distribution includes one reference implementations of an +OpenFlow switch. This implementation has the following components: + + - ofdatapath, which implements the flow table in user space. + + - ofprotocol, a program that implements the secure channel + component of the reference switch. + + - dpctl, a tool for configuring the switch. + +This distribution includes some additional software as well: + + - controller, a simple program that connects to any number of + OpenFlow switches, commanding them to act as regular MAC + learning switches. + + - vlogconf, a utility that can adjust the logging levels of a + running ofprotocol or controller. + + - ofp-pki, a utility for creating and managing the public-key + infrastructure for OpenFlow switches. + + - A patch to tcpdump that enables it to parse OpenFlow + messages. + + - A regression suite that tests OpenFlow functionality, please + see regress/README. + + - A Wireshark dissector that can decode the OpenFlow wire + protocol. Please see utilities/wireshark_dissectors/README. + +For installation instructions, read INSTALL. Each userspace program +is also accompanied by a manpage. + +What's NOT here? +---------------- + +The reference implementation no longer includes the Linux kernel module +or the NetFPGA implementation. The OpenFlow consortium intends to +release these separately from the reference design. + +Platform support +---------------- + +Other than the userspace switch implementation, the software in the +OpenFlow distribution should compile under Unix-like environments such +as Linux, FreeBSD, Mac OS X, and Solaris. Our primary test environment +is Debian GNU/Linux. Please contact us with portability-related bug +reports or patches. + +The userspace datapath implementation should be easy to port to +Unix-like systems. The interface to network devices, in netdev.c, is +the code most likely to need changes. So far, only Linux is +supported. We welcome ports to other platforms. + +GCC is the expected compiler. + +Bugs/Shortcomings +----------------- + +- The flow table does not support the "normal processing" action. + +References +---------- + + [1] OpenFlow: Enabling Innovation in College Networks. Whitepaper. + + + [2] OpenFlow Switch Specification. + + +Contact +------- + +Public discussion list: openflow-discuss@openflowswitch.org +Direct e-mail: info@openflowswitch.org + +Web: http://openflowswitch.org/ diff --git a/openflow/README.hwtables b/openflow/README.hwtables new file mode 100644 index 00000000..6d982507 --- /dev/null +++ b/openflow/README.hwtables @@ -0,0 +1,39 @@ +Hardware Table Support -*- text -*- +---------------------- + +The OpenFlow reference implementation in this distribution provides a +mechanism to support hardware that can accelerate OpenFlow switching. +The mechanism consists of the ability to add a "hardware acceleration" +switching table ahead of the software switching tables implemented by +the reference implementation. The hardware switching table is +expected to handle any incoming packets that it can on its own. Any +packets that it cannot handle itself it may pass up to the software +table implementations. + +Hardware table implementation are provided as a library and built +in the userspace datapath executable. + +Creating a hardware table module is straightforward. Create a +directory in the openflow source tree named hw-lib/NAME, +where NAME identifies the hardware that the module supports. Populate +that directory with the C source files that comprise the module, plus +a file named automake.mk that specifies how to build the module in +the hw-lib directory. This distribution includes a "skeleton" hardware +library that demonstrates how this works. + +When you perform 'configure', specify each NAME that identifies a +library to be included on the OpenFlow configure script command as +the argument to --enable-hw-lib, e.g.: + ./configure --enable-hw-lib=NAME + +Each hardware table library's code is encapsulated in a directory, so +it is easy to separate a hardware table implementation from OpenFlow. +Simply package up the contents of the hw-lib/NAME directory and +distribute it for builders to extract into their distribution +directory. + +Included in this distribution is a dummy hardware table to aid in beginning +your own hardware table port, it is located in the hw-lib/skeleton +folder. Also included is a fully functional NetFPGA hardware table that can run +as a 1Gbx4 port line-rate OpenFlow switch. Information and instructions for its +use can be found in the hw-lib/nf2/README file. diff --git a/openflow/README.kernel b/openflow/README.kernel new file mode 100644 index 00000000..95ce7564 --- /dev/null +++ b/openflow/README.kernel @@ -0,0 +1,18 @@ +Kernel-mode Support -*- text -*- +------------------- + +The OpenFlow reference implementation no longer includes a kernel module +that implements the datapath. A separate release with kernel-mode support +is expected in 1H2010. + +The release you downloaded *may* include the kernel module source files +depending upon the method used to obtain the release. If you downloaded the +release as a compressed tar file (.tar.gz) then you will *not* have the +source for the kernel module. If you downloaded the release directly from +git then you will have the source. + +Please note that if you obtained the release via git that the kernel module +source is not built by default and does not implement all features. + +Please check the OpenFlow website or subscribe to the openflow-announce +mailing list for updates on the kernel-mode implementation. diff --git a/openflow/acinclude.m4 b/openflow/acinclude.m4 new file mode 100644 index 00000000..7ccfbaa4 --- /dev/null +++ b/openflow/acinclude.m4 @@ -0,0 +1,309 @@ +# -*- autoconf -*- + +# Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford +# Junior University +# +# We are making the OpenFlow specification and associated documentation +# (Software) available for public use and benefit with the expectation +# that others will use, modify and enhance the Software and contribute +# those enhancements back to the community. However, since we would +# like to make the Software available for broadest use, with as few +# restrictions as possible permission is hereby granted, free of +# charge, to any person obtaining a copy of this Software to deal in +# the Software under the copyrights without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# The name and trademarks of copyright holder(s) may NOT be used in +# advertising or publicity pertaining to the Software or any +# derivatives without specific, written prior permission. + +dnl OFP_CHECK_LINUX(OPTION, VERSION, VARIABLE, CONDITIONAL) +dnl +dnl Configure linux kernel source tree +AC_DEFUN([OFP_CHECK_LINUX], [ + AC_ARG_WITH([$1], + [AC_HELP_STRING([--with-$1=/path/to/linux-$2], + [Specify the linux $2 kernel module build envrionment and sources])], + [path="$withval"], [path=])dnl + if test -n "$path"; then + path=`eval echo "$path"` + + AC_MSG_CHECKING([for $path directory]) + if test -d "$path" && test -d "$path/build" ; then + AC_MSG_RESULT([yes]) + if test -d "$path/source" ; then + $3=$path/build + $4=$path/source + else + $3=$path/build + $4=$path/build + fi + AC_SUBST($3) + AC_SUBST($4) + else + AC_MSG_RESULT([no]) + AC_ERROR([source dir $path doesn't exist]) + fi + + AC_MSG_CHECKING([for $path kernel version]) + patchlevel=`sed -n 's/^PATCHLEVEL = //p' "$KBLD26/Makefile"` + sublevel=`sed -n 's/^SUBLEVEL = //p' "$KBLD26/Makefile"` + AC_MSG_RESULT([2.$patchlevel.$sublevel]) + if test "2.$patchlevel" != '$2'; then + AC_ERROR([Linux kernel source in $path is not version $2]) + fi + if ! test -e $KBLD26/include/linux/version.h || \ + ! test -e $KBLD26/include/linux/autoconf.h; then + AC_MSG_ERROR([Linux kernel source in $path is not configured]) + fi + m4_if($2, [2.6], [OFP_CHECK_LINUX26_COMPAT]) + fi + AM_CONDITIONAL($5, test -n "$path") +]) + +dnl OFP_GREP_IFELSE(FILE, REGEX, IF-MATCH, IF-NO-MATCH) +dnl +dnl Greps FILE for REGEX. If it matches, runs IF-MATCH, otherwise IF-NO-MATCH. +AC_DEFUN([OFP_GREP_IFELSE], [ + AC_MSG_CHECKING([whether $2 matches in $1]) + grep '$2' $1 >/dev/null 2>&1 + status=$? + case $status in + 0) + AC_MSG_RESULT([yes]) + $3 + ;; + 1) + AC_MSG_RESULT([no]) + $4 + ;; + *) + AC_MSG_ERROR([grep exited with status $status]) + ;; + esac +]) + +dnl OFP_DEFINE(NAME) +dnl +dnl Defines NAME to 1 in kcompat.h. +AC_DEFUN([OFP_DEFINE], [ + echo '#define $1 1' >> datapath/linux-2.6/kcompat.h.new +]) + +AC_DEFUN([OFP_CHECK_VETH], [ + AC_MSG_CHECKING([whether to build veth module]) + if test "$sublevel" = 18; then + AC_MSG_RESULT([yes]) + AC_SUBST([BUILD_VETH], 1) + else + AC_MSG_RESULT([no]) + fi +]) + +dnl OFP_CHECK_LINUX26_COMPAT +dnl +dnl Runs various Autoconf checks on the Linux 2.6 kernel source in +dnl the directory in $KSRC26. +AC_DEFUN([OFP_CHECK_LINUX26_COMPAT], [ + rm -f datapath/linux-2.6/kcompat.h.new + mkdir -p datapath/linux-2.6 + : > datapath/linux-2.6/kcompat.h.new + OFP_GREP_IFELSE([$KSRC26/include/linux/skbuff.h], [skb_transport_header], + [OFP_DEFINE([HAVE_SKBUFF_HEADER_HELPERS])]) + OFP_GREP_IFELSE([$KSRC26/include/linux/skbuff.h], [raw], + [OFP_DEFINE([HAVE_MAC_RAW])]) + OFP_GREP_IFELSE([$KSRC26/include/linux/skbuff.h], + [skb_copy_from_linear_data_offset], + [OFP_DEFINE([HAVE_SKB_COPY_FROM_LINEAR_DATA_OFFSET])]) + OFP_GREP_IFELSE([$KSRC26/include/net/netlink.h], [NLA_NUL_STRING], + [OFP_DEFINE([HAVE_NLA_NUL_STRING])]) + OFP_CHECK_VETH + if cmp -s datapath/linux-2.6/kcompat.h.new \ + datapath/linux-2.6/kcompat.h >/dev/null 2>&1; then + rm datapath/linux-2.6/kcompat.h.new + else + mv datapath/linux-2.6/kcompat.h.new datapath/linux-2.6/kcompat.h + fi +]) + +dnl Checks for --enable-hw-tables and substitutes HW_TABLES to any +dnl requested hardware table modules. +AC_DEFUN([OFP_CHECK_HWTABLES], + [AC_ARG_ENABLE( + [hw-tables], + [AC_HELP_STRING([--enable-hw-tables=MODULE...], + [Configure and build the specified externally supplied + hardware table support modules])]) + case "${enable_hw_tables}" in # ( + yes) + AC_MSG_ERROR([--enable-hw-tables has a required argument]) + ;; # ( + ''|no) + hw_tables= + ;; # ( + *) + hw_tables=`echo "$enable_hw_tables" | sed 's/,/ /g'` + ;; + esac + for d in $hw_tables; do + mk=datapath/hwtable_$d/Modules.mk + if test ! -e $srcdir/$mk; then + AC_MSG_ERROR([--enable-hw-tables=$d specified but $mk is missing]) + fi + HW_TABLES="$HW_TABLES \$(top_srcdir)/$mk" + done + AC_SUBST(HW_TABLES)]) + +dnl Checks for --enable-hw-lib and substitutes BUILD_HW_LIBS and plat name +AC_DEFUN([OFP_CHECK_HWLIBS], + [AC_ARG_ENABLE( + [hw-lib], + [AC_HELP_STRING([--enable-hw-lib=PLATFORM], + [Configure and build the specified externally supplied + hardware library: lb4g, t2ref, scorref or nf2])]) + case "${enable_hw_lib}" in # ( + yes) + AC_MSG_ERROR([--enable-hw-lib has a required argument]) + ;; # ( + ''|no) + hw_lib= + NF2=no + LB4G=no + T2REF=no + SCORREF=no + BUILD_HW_LIBS=no + ;; # ( + nf2) + NF2=yes + LB4G=no + T2REF=no + SCORREF=no + hw_lib=$enable_hw_lib + BUILD_HW_LIBS=yes + ;; # ( + lb4g) + NF2=no + LB4G=yes + T2REF=no + SCORREF=no + hw_lib=$enable_hw_lib + BUILD_HW_LIBS=yes + ;; # ( + t2ref) + NF2=no + LB4G=no + T2REF=yes + SCORREF=no + hw_lib=$enable_hw_lib + BUILD_HW_LIBS=yes + ;; # ( + scorref) + NF2=no + LB4G=no + SCORREF=yes + T2REF=no + hw_lib=$enable_hw_lib + BUILD_HW_LIBS=yes + ;; # ( + *) + AC_MSG_ERROR([--enable-hw-lib: Unknown platform: ${enable_hw_lib}]) + BUILD_HW_LIBS=no + ;; + esac + if test $BUILD_HW_LIBS = yes; then + if test -e "$srcdir/hw-lib/automake.mk"; then + : + else + AC_MSG_ERROR([cannot configure HW libraries without "hw-lib" directory]) + fi + AC_DEFINE([BUILD_HW_LIBS], [1], + [Whether the OpenFlow hardware libraries are available]) + fi + if test $NF2 = yes; then + AC_DEFINE([NF2], [1], + [Support NetFPGA platform]) + fi + if test $LB4G = yes; then + AC_DEFINE([LB4G], [1], + [Support Stanford-LB4G platform]) + fi + if test $T2REF = yes; then + AC_DEFINE([T2REF], [1], + [Support Broadcom 56634 reference platform]) + fi + if test $SCORREF = yes; then + AC_DEFINE([SCORREF], [1], + [Support Broadcom 56820 reference platform]) + fi + AM_CONDITIONAL([NF2], [test $NF2 = yes]) + AM_CONDITIONAL([LB4G], [test $LB4G = yes]) + AM_CONDITIONAL([T2REF], [test $T2REF = yes]) + AM_CONDITIONAL([SCORREF], [test $SCORREF = yes]) + AM_CONDITIONAL([BUILD_HW_LIBS], [test $BUILD_HW_LIBS = yes]) + AC_SUBST(HW_LIB)]) + +dnl Checks for net/if_packet.h. +AC_DEFUN([OFP_CHECK_IF_PACKET], + [AC_CHECK_HEADER([net/if_packet.h], + [HAVE_IF_PACKET=yes], + [HAVE_IF_PACKET=no]) + AM_CONDITIONAL([HAVE_IF_PACKET], [test "$HAVE_IF_PACKET" = yes]) + if test "$HAVE_IF_PACKET" = yes; then + AC_DEFINE([HAVE_IF_PACKET], [1], + [Define to 1 if net/if_packet.h is available.]) + fi]) + +dnl Checks for dpkg-buildpackage. If this is available then we check +dnl that the Debian packaging is functional at "make distcheck" time. +AC_DEFUN([OFP_CHECK_DPKG_BUILDPACKAGE], + [AC_CHECK_PROG([HAVE_DPKG_BUILDPACKAGE], [dpkg-buildpackage], [yes], [no]) + AM_CONDITIONAL([HAVE_DPKG_BUILDPACKAGE], + [test $HAVE_DPKG_BUILDPACKAGE = yes])]) + +dnl ---------------------------------------------------------------------- +dnl These macros are from GNU PSPP, with the following original license: +dnl Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl OFP_CHECK_CC_OPTION([OPTION], [ACTION-IF-ACCEPTED], [ACTION-IF-REJECTED]) +dnl Check whether the given C compiler OPTION is accepted. +dnl If so, execute ACTION-IF-ACCEPTED, otherwise ACTION-IF-REJECTED. +AC_DEFUN([OFP_CHECK_CC_OPTION], +[ + m4_define([ofp_cv_name], [ofp_cv_[]m4_translit([$1], [-], [_])])dnl + AC_CACHE_CHECK([whether $CC accepts $1], [ofp_cv_name], + [ofp_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $1" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,)], [ofp_cv_name[]=yes], [ofp_cv_name[]=no]) + CFLAGS="$ofp_save_CFLAGS"]) + if test $ofp_cv_name = yes; then + m4_if([$2], [], [;], [$2]) + else + m4_if([$3], [], [:], [$3]) + fi +]) + +dnl OFP_ENABLE_OPTION([OPTION]) +dnl Check whether the given C compiler OPTION is accepted. +dnl If so, add it to CFLAGS. +dnl Example: OFP_ENABLE_OPTION([-Wdeclaration-after-statement]) +AC_DEFUN([OFP_ENABLE_OPTION], + [OFP_CHECK_CC_OPTION([$1], [CFLAGS="$CFLAGS $1"])]) +dnl ---------------------------------------------------------------------- diff --git a/openflow/boot.sh b/openflow/boot.sh new file mode 100755 index 00000000..97921fac --- /dev/null +++ b/openflow/boot.sh @@ -0,0 +1,14 @@ +#! /bin/sh + +set -e + +# Generate list of files in debian/ to distribute. +(echo '# Automatically generated by boot.sh (from Git tree).' && + printf 'EXTRA_DIST += \\\n' && + git ls-files debian | grep -v '^debian/\.gitignore$' | + sed -e 's/\(.*\)/ \1 \\/' -e '$s/ \\//') > debian/automake.mk + +cat debian/control.in > debian/control + +# Bootstrap configure system from .ac/.am files +autoreconf --install --force diff --git a/openflow/configure.ac b/openflow/configure.ac new file mode 100644 index 00000000..13064f68 --- /dev/null +++ b/openflow/configure.ac @@ -0,0 +1,94 @@ +# Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford +# Junior University +# +# We are making the OpenFlow specification and associated documentation +# (Software) available for public use and benefit with the expectation +# that others will use, modify and enhance the Software and contribute +# those enhancements back to the community. However, since we would +# like to make the Software available for broadest use, with as few +# restrictions as possible permission is hereby granted, free of +# charge, to any person obtaining a copy of this Software to deal in +# the Software under the copyrights without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# The name and trademarks of copyright holder(s) may NOT be used in +# advertising or publicity pertaining to the Software or any +# derivatives without specific, written prior permission. + +AC_PREREQ(2.60) +AC_INIT([openflow], [1.0.0], [openflow-discuss@openflowswitch.org]) +NX_BUILDNR +AC_CONFIG_SRCDIR([README.hwtables]) +AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_AUX_DIR([build-aux]) +AC_CONFIG_HEADERS([config.h]) +AM_INIT_AUTOMAKE + +AC_PROG_CC +AM_PROG_CC_C_O +AC_PROG_CPP +AC_PROG_RANLIB +AC_PROG_MKDIR_P + +AC_ARG_VAR([PERL], [path to Perl interpreter]) +AC_PATH_PROG([PERL], perl, no) +if test "$PERL" = no; then + AC_MSG_ERROR([Perl interpreter not found in $PATH or $PERL.]) +fi + +OFP_CHECK_LIBOPENFLOW +OFP_CHECK_IF_PACKET +OFP_CHECK_HWTABLES +OFP_CHECK_HWLIBS +AC_SYS_LARGEFILE + +AC_CHECK_FUNCS([strsignal]) + +AC_ARG_VAR(KARCH, [Kernel Architecture String]) +AC_SUBST(KARCH) +#OFP_CHECK_LINUX(l26, 2.6, KBLD26, KSRC26, L26_ENABLED) + +OFP_CHECK_DPKG_BUILDPACKAGE + +OFP_ENABLE_OPTION([-Wall]) +OFP_ENABLE_OPTION([-Wno-sign-compare]) +OFP_ENABLE_OPTION([-Wpointer-arith]) +OFP_ENABLE_OPTION([-Wdeclaration-after-statement]) +OFP_ENABLE_OPTION([-Wformat-security]) +OFP_ENABLE_OPTION([-Wswitch-enum]) +OFP_ENABLE_OPTION([-Wunused-parameter]) +OFP_ENABLE_OPTION([-Wstrict-aliasing]) +OFP_ENABLE_OPTION([-Wbad-function-cast]) +OFP_ENABLE_OPTION([-Wcast-align]) +OFP_ENABLE_OPTION([-Wstrict-prototypes]) +OFP_ENABLE_OPTION([-Wold-style-definition]) +OFP_ENABLE_OPTION([-Wmissing-prototypes]) +OFP_ENABLE_OPTION([-Wmissing-field-initializers]) +OFP_ENABLE_OPTION([-Wno-override-init]) + +AC_CONFIG_FILES([Makefile +]) + +#AC_CONFIG_FILES([Makefile +#datapath/Makefile +#datapath/linux-2.6/Kbuild +#datapath/linux-2.6/Makefile +#datapath/linux-2.6/Makefile.main +#]) + +AC_OUTPUT diff --git a/openflow/controller/.dirstamp b/openflow/controller/.dirstamp new file mode 100644 index 00000000..e69de29b diff --git a/openflow/controller/.gitignore b/openflow/controller/.gitignore new file mode 100644 index 00000000..8736bbc1 --- /dev/null +++ b/openflow/controller/.gitignore @@ -0,0 +1,4 @@ +/Makefile +/Makefile.in +/controller +/controller.8 diff --git a/openflow/controller/automake.mk b/openflow/controller/automake.mk new file mode 100644 index 00000000..ff9f627c --- /dev/null +++ b/openflow/controller/automake.mk @@ -0,0 +1,8 @@ +bin_PROGRAMS += controller/controller +man_MANS += controller/controller.8 +DISTCLEANFILES += controller/controller.8 + +controller_controller_SOURCES = controller/controller.c +controller_controller_LDADD = lib/libopenflow.a $(FAULT_LIBS) $(SSL_LIBS) + +EXTRA_DIST += controller/controller.8.in diff --git a/openflow/controller/controller.8.in b/openflow/controller/controller.8.in new file mode 100644 index 00000000..c2b65cfb --- /dev/null +++ b/openflow/controller/controller.8.in @@ -0,0 +1,150 @@ +.ds PN controller + +.TH controller 8 "May 2008" "OpenFlow" "OpenFlow Manual" + +.SH NAME +controller \- simple OpenFlow controller reference implementation + +.SH SYNOPSIS +.B controller +[\fIoptions\fR] \fImethod\fR \fB[\fImethod\fR]\&... + +.SH DESCRIPTION +A sample OpenFlow controller which functions as an L2 MAC-learning +switch or hub. \fBcontroller\fR can manage a remote datapath through +a secure channel (see \fBofprotocol(8)\fR). It can also connect directly +to a local datapath via Netlink. + +\fBcontroller\fR controls one or more OpenFlow switches, specified as +one or more of the following OpenFlow connection methods: + +.TP +\fBpssl:\fR[\fIport\fR] +Listens for SSL connections from remote OpenFlow switches on +\fIport\fR (default: 6633). The \fB--private-key\fR, +\fB--certificate\fR, and \fB--ca-cert\fR options are mandatory when +this form is used. + +.TP +\fBptcp:\fR[\fIport\fR] +Listens for TCP connections from remote OpenFlow switches on +\fIport\fR (default: 6633). + +.TP +\fBpunix:\fIfile\fR +Listens for connections from OpenFlow switches on the Unix domain +server socket named \fIfile\fR. + +.TP +\fBnl:\fIdp_idx\fR +The local Netlink datapath numbered \fIdp_idx\fR, as configured with +.BR dpctl (8). +This form requires that the local host has the OpenFlow kernel +module for Linux loaded. + +.TP +\fBssl:\fIhost\fR[\fB:\fIport\fR] +The specified SSL \fIport\fR (default: 6633) on the given remote +\fIhost\fR. The \fB--private-key\fR, \fB--certificate\fR, and +\fB--ca-cert\fR options are mandatory when this form is used. + +.TP +\fBtcp:\fIhost\fR[\fB:\fIport\fR] +The specified TCP \fIport\fR (default: 6633) on the given remote +\fIhost\fR. + +.TP +\fBunix:\fIfile\fR +The Unix domain server socket named \fIfile\fR. + +.SH OPTIONS +.TP +\fB-p\fR, \fB--private-key=\fIprivkey.pem\fR +Specifies a PEM file containing the private key used as the switch's +identity for SSL connections to the controller. + +.TP +\fB-c\fR, \fB--certificate=\fIcert.pem\fR +Specifies a PEM file containing a certificate, signed by the +controller's certificate authority (CA), that certifies the switch's +private key to identify a trustworthy switch. + +.TP +\fB-C\fR, \fB--ca-cert=\fIswitch-cacert.pem\fR +Specifies a PEM file containing the CA certificate used to verify that +the switch is connected to a trustworthy controller. + +.TP +\fB--peer-ca-cert=\fIcontroller-cacert.pem\fR +Specifies a PEM file that contains one or more additional certificates +to send to switches. \fIcontroller-cacert.pem\fR should be the CA +certificate used to sign the controller's own certificate (the +certificate specified on \fB-c\fR or \fB--certificate\fR). + +This option is not useful in normal operation, because the switch must +already have the controller CA certificate for it to have any +confidence in the controller's identity. However, this option allows +a newly installed switch to obtain the controller CA certificate on +first boot using, e.g., the \fB--bootstrap-ca-cert\fR option to +\fBofprotocol\fR(8). + +.TP +.BR \-n ", " \-\^\-noflow +By default, the controller sets up a flow in each OpenFlow switch +whenever it receives a packet whose destination is known due through +MAC learning. This option disables flow setup, so that every packet +in the network passes through the controller. + +This option is most useful for debugging. It reduces switching +performance, so it should not be used in production. + +.TP +\fB--max-idle=\fIsecs\fR|\fBpermanent\fR +Sets \fIsecs\fR as the number of seconds that a flow set up by the +controller will remain in the switch's flow table without any matching +packets being seen. If \fBpermanent\fR is specified, which is not +recommended, flows will never expire. The default is 60 seconds. + +This option affects only flows set up by the OpenFlow controller. In +some configurations, the OpenFlow secure channel can set up some flows +on its own. To set the idle time for those flows, pass +\fB--max-idle\fR to \fBofprotocol\fR(8). + +This option has no effect when \fB-n\fR (or \fB--noflow\fR) is in use +(because the controller does not set up flows in that case). + +.TP +.BR \-H ", " \-\^\-hub +By default, the controller acts as an L2 MAC-learning switch. This +option changes its behavior to that of a hub that floods packets on +all but the incoming port. + +If \fB-H\fR (or \fB--hub\fR) and \fB-n\fR (or \fB--noflow\fR) are used +together, then the cumulative effect is that every packet passes +through the controller and every packet is flooded. + +This option is most useful for debugging. It reduces switching +performance, so it should not be used in production. + +.so lib/daemon.man +.so lib/vlog.man +.so lib/common.man + +.SH EXAMPLES + +.TP +To connect directly to local datapath 0 over netlink (Linux only): + +.B % controller nl:0 + +.TP +To bind locally to port 6633 (the default) and wait for incoming connections from OpenFlow switches: + +.B % controller ptcp: + +.SH "SEE ALSO" + +.BR dpctl (8), +.BR ofprotocol (8), +.BR ofdatapath (8), +.BR vlogconf (8) diff --git a/openflow/controller/controller.c b/openflow/controller/controller.c new file mode 100644 index 00000000..6eec5906 --- /dev/null +++ b/openflow/controller/controller.c @@ -0,0 +1,336 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "command-line.h" +#include "compiler.h" +#include "daemon.h" +#include "fault.h" +#include "learning-switch.h" +#include "ofpbuf.h" +#include "openflow/openflow.h" +#include "poll-loop.h" +#include "rconn.h" +#include "timeval.h" +#include "util.h" +#include "vconn-ssl.h" +#include "vconn.h" +#include "vlog-socket.h" + +#include "vlog.h" +#define THIS_MODULE VLM_controller + +#define MAX_SWITCHES 4096 +#define MAX_LISTENERS 4096 + +struct switch_ { + struct lswitch *lswitch; + struct rconn *rconn; +}; + +/* Learn the ports on which MAC addresses appear? */ +static bool learn_macs = true; + +/* Set up flows? (If not, every packet is processed at the controller.) */ +static bool setup_flows = true; + +/* --max-idle: Maximum idle time, in seconds, before flows expire. */ +static int max_idle = 60; + +static int do_switching(struct switch_ *); +static void new_switch(struct switch_ *, struct vconn *, const char *name); +static void parse_options(int argc, char *argv[]); +static void usage(void) NO_RETURN; + +int +main(int argc, char *argv[]) +{ + struct switch_ switches[MAX_SWITCHES]; + struct pvconn *listeners[MAX_LISTENERS]; + int n_switches, n_listeners; + int retval; + int i; + + set_program_name(argv[0]); + register_fault_handlers(); + time_init(); + vlog_init(); + parse_options(argc, argv); + signal(SIGPIPE, SIG_IGN); + + if (argc - optind < 1) { + ofp_fatal(0, "at least one vconn argument required; " + "use --help for usage"); + } + + n_switches = n_listeners = 0; + for (i = optind; i < argc; i++) { + const char *name = argv[i]; + struct vconn *vconn; + int retval; + + retval = vconn_open(name, OFP_VERSION, &vconn); + if (!retval) { + if (n_switches >= MAX_SWITCHES) { + ofp_fatal(0, "max %d switch connections", n_switches); + } + new_switch(&switches[n_switches++], vconn, name); + continue; + } else if (retval == EAFNOSUPPORT) { + struct pvconn *pvconn; + retval = pvconn_open(name, &pvconn); + if (!retval) { + if (n_listeners >= MAX_LISTENERS) { + ofp_fatal(0, "max %d passive connections", n_listeners); + } + listeners[n_listeners++] = pvconn; + } + } + if (retval) { + VLOG_ERR("%s: connect: %s", name, strerror(retval)); + } + } + if (n_switches == 0 && n_listeners == 0) { + ofp_fatal(0, "no active or passive switch connections"); + } + + die_if_already_running(); + daemonize(); + + retval = vlog_server_listen(NULL, NULL); + if (retval) { + ofp_fatal(retval, "Could not listen for vlog connections"); + } + + while (n_switches > 0 || n_listeners > 0) { + int iteration; + int i; + + /* Accept connections on listening vconns. */ + for (i = 0; i < n_listeners && n_switches < MAX_SWITCHES; ) { + struct vconn *new_vconn; + int retval; + + retval = pvconn_accept(listeners[i], OFP_VERSION, &new_vconn); + if (!retval || retval == EAGAIN) { + if (!retval) { + new_switch(&switches[n_switches++], new_vconn, "tcp"); + } + i++; + } else { + pvconn_close(listeners[i]); + listeners[i] = listeners[--n_listeners]; + } + } + + /* Do some switching work. Limit the number of iterations so that + * callbacks registered with the poll loop don't starve. */ + for (iteration = 0; iteration < 50; iteration++) { + bool progress = false; + for (i = 0; i < n_switches; ) { + struct switch_ *this = &switches[i]; + int retval = do_switching(this); + if (!retval || retval == EAGAIN) { + if (!retval) { + progress = true; + } + i++; + } else { + rconn_destroy(this->rconn); + lswitch_destroy(this->lswitch); + switches[i] = switches[--n_switches]; + } + } + if (!progress) { + break; + } + } + for (i = 0; i < n_switches; i++) { + struct switch_ *this = &switches[i]; + lswitch_run(this->lswitch, this->rconn); + } + + /* Wait for something to happen. */ + if (n_switches < MAX_SWITCHES) { + for (i = 0; i < n_listeners; i++) { + pvconn_wait(listeners[i]); + } + } + for (i = 0; i < n_switches; i++) { + struct switch_ *sw = &switches[i]; + rconn_run_wait(sw->rconn); + rconn_recv_wait(sw->rconn); + lswitch_wait(sw->lswitch); + } + poll_block(); + } + + return 0; +} + +static void +new_switch(struct switch_ *sw, struct vconn *vconn, const char *name) +{ + sw->rconn = rconn_new_from_vconn(name, vconn); + sw->lswitch = lswitch_create(sw->rconn, learn_macs, + setup_flows ? max_idle : -1); +} + +static int +do_switching(struct switch_ *sw) +{ + unsigned int packets_sent; + struct ofpbuf *msg; + + packets_sent = rconn_packets_sent(sw->rconn); + + msg = rconn_recv(sw->rconn); + if (msg) { + lswitch_process_packet(sw->lswitch, sw->rconn, msg); + ofpbuf_delete(msg); + } + rconn_run(sw->rconn); + + return (!rconn_is_alive(sw->rconn) ? EOF + : rconn_packets_sent(sw->rconn) != packets_sent ? 0 + : EAGAIN); +} + +static void +parse_options(int argc, char *argv[]) +{ + enum { + OPT_MAX_IDLE = UCHAR_MAX + 1, + OPT_PEER_CA_CERT, + VLOG_OPTION_ENUMS + }; + static struct option long_options[] = { + {"hub", no_argument, 0, 'H'}, + {"noflow", no_argument, 0, 'n'}, + {"max-idle", required_argument, 0, OPT_MAX_IDLE}, + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + DAEMON_LONG_OPTIONS, + VLOG_LONG_OPTIONS, +#ifdef HAVE_OPENSSL + VCONN_SSL_LONG_OPTIONS + {"peer-ca-cert", required_argument, 0, OPT_PEER_CA_CERT}, +#endif + {0, 0, 0, 0}, + }; + char *short_options = long_options_to_short_options(long_options); + + for (;;) { + int indexptr; + int c; + + c = getopt_long(argc, argv, short_options, long_options, &indexptr); + if (c == -1) { + break; + } + + switch (c) { + case 'H': + learn_macs = false; + break; + + case 'n': + setup_flows = false; + break; + + case OPT_MAX_IDLE: + if (!strcmp(optarg, "permanent")) { + max_idle = OFP_FLOW_PERMANENT; + } else { + max_idle = atoi(optarg); + if (max_idle < 1 || max_idle > 65535) { + ofp_fatal(0, "--max-idle argument must be between 1 and " + "65535 or the word 'permanent'"); + } + } + break; + + case 'h': + usage(); + + case 'V': + printf("%s "VERSION" compiled "__DATE__" "__TIME__"\n", argv[0]); + exit(EXIT_SUCCESS); + + VLOG_OPTION_HANDLERS + DAEMON_OPTION_HANDLERS + +#ifdef HAVE_OPENSSL + VCONN_SSL_OPTION_HANDLERS + + case OPT_PEER_CA_CERT: + vconn_ssl_set_peer_ca_cert_file(optarg); + break; +#endif + + case '?': + exit(EXIT_FAILURE); + + default: + abort(); + } + } + free(short_options); +} + +static void +usage(void) +{ + printf("%s: OpenFlow controller\n" + "usage: %s [OPTIONS] METHOD\n" + "where METHOD is any OpenFlow connection method.\n", + program_name, program_name); + vconn_usage(true, true, false); + daemon_usage(); + vlog_usage(); + printf("\nOther options:\n" + " -H, --hub act as hub instead of learning switch\n" + " -n, --noflow pass traffic, but don't add flows\n" + " --max-idle=SECS max idle time for new flows\n" + " -h, --help display this help message\n" + " -V, --version display version information\n"); + exit(EXIT_SUCCESS); +} diff --git a/openflow/datapath/.gitignore b/openflow/datapath/.gitignore new file mode 100644 index 00000000..5a59a0d3 --- /dev/null +++ b/openflow/datapath/.gitignore @@ -0,0 +1,7 @@ +/Makefile +/Makefile.in +*.cmd +*.ko +*.mod.c +Module.symvers + diff --git a/openflow/datapath/Makefile.am b/openflow/datapath/Makefile.am new file mode 100644 index 00000000..7eed78d1 --- /dev/null +++ b/openflow/datapath/Makefile.am @@ -0,0 +1,27 @@ +SUBDIRS = +if L26_ENABLED +SUBDIRS += linux-2.6 +endif + +EXTRA_DIST = $(dist_headers) $(dist_sources) +EXTRA_DIST += hwtable_dummy/Modules.mk hwtable_dummy/hwtable_dummy.c +EXTRA_DIST += \ + hwtable_nf2/Modules.mk \ + hwtable_nf2/nf2.h \ + hwtable_nf2/nf2_hwapi.h \ + hwtable_nf2/nf2_reg.h \ + hwtable_nf2/nf2_flowtable.c \ + hwtable_nf2/nf2_flowtable.h \ + hwtable_nf2/nf2_lib.c \ + hwtable_nf2/nf2_lib.h \ + hwtable_nf2/nf2_procfs.c \ + hwtable_nf2/nf2_procfs.h \ + hwtable_nf2/nf2_openflow.c \ + hwtable_nf2/nf2_openflow.h \ + hwtable_nf2/openflow_switch.bit + +# Suppress warnings about GNU extensions in Modules.mk files. +AUTOMAKE_OPTIONS = -Wno-portability + +include Modules.mk +include linux-2.6/Modules.mk diff --git a/openflow/datapath/Modules.mk b/openflow/datapath/Modules.mk new file mode 100644 index 00000000..777dc658 --- /dev/null +++ b/openflow/datapath/Modules.mk @@ -0,0 +1,42 @@ +# Some modules should be built and distributed, e.g. openflow. +# +# Some modules should be distributed but not built, e.g. we do not build +# veth if the kernel in question already has it. +# +# Some modules should be built but not distributed, e.g. third-party +# hwtable modules. +both_modules = ofdatapath +build_modules = $(both_modules) # Modules to build +dist_modules = $(both_modules) # Modules to distribute + +ofdatapath_sources = \ + chain.c \ + crc32.c \ + datapath.c \ + dp_act.c \ + dp_dev.c \ + dp_notify.c \ + flow.c \ + forward.c \ + private-msg.c \ + table-hash.c \ + table-linear.c + +ofdatapath_headers = \ + chain.h \ + compat.h \ + crc32.h \ + datapath.h \ + dp_dev.h \ + flow.h \ + forward.h \ + dp_act.h \ + private-msg.h \ + table.h + +dist_sources = $(foreach module,$(dist_modules),$($(module)_sources)) +dist_headers = $(foreach module,$(dist_modules),$($(module)_headers)) +build_sources = $(foreach module,$(build_modules),$($(module)_sources)) +build_headers = $(foreach module,$(build_modules),$($(module)_headers)) +build_links = $(notdir $(build_sources)) +build_objects = $(notdir $(patsubst %.c,%.o,$(build_sources))) diff --git a/openflow/datapath/chain.c b/openflow/datapath/chain.c new file mode 100644 index 00000000..e75f77dc --- /dev/null +++ b/openflow/datapath/chain.c @@ -0,0 +1,270 @@ +/* + * Distributed under the terms of the GNU GPL version 2. + * Copyright (c) 2007, 2008, 2009 The Board of Trustees of The Leland + * Stanford Junior University + */ + +#include "chain.h" +#include "datapath.h" +#include "flow.h" +#include "table.h" +#include +#include +#include +#include + +static struct sw_table *(*create_hw_table_hook)(void); +static struct module *hw_table_owner; +static DEFINE_SPINLOCK(hook_lock); + +/* Attempts to append 'table' to the set of tables in 'chain'. Returns 0 or + * negative error. If 'table' is null it is assumed that table creation failed + * due to out-of-memory. */ +static int add_table(struct sw_chain *chain, struct sw_table *table, int emerg) +{ + if (table == NULL) + return -ENOMEM; + if (chain->n_tables >= CHAIN_MAX_TABLES) { + printk(KERN_EMERG "%s: too many tables in chain\n", + chain->dp->netdev->name); + table->destroy(table); + return -ENOBUFS; + } + if (emerg) + chain->emerg_table = table; + else + chain->tables[chain->n_tables++] = table; + return 0; +} + +/* Creates and returns a new chain associated with 'dp'. Returns NULL if the + * chain cannot be created. */ +struct sw_chain *chain_create(struct datapath *dp) +{ + struct sw_chain *chain = kzalloc(sizeof *chain, GFP_KERNEL); + if (chain == NULL) + goto error; + chain->dp = dp; + chain->owner = try_module_get(hw_table_owner) ? hw_table_owner : NULL; + if (chain->owner && create_hw_table_hook) { + struct sw_table *hwtable = create_hw_table_hook(); + if (!hwtable || add_table(chain, hwtable, 0)) + goto error; + } + + if (add_table(chain, table_hash2_create(0x1EDC6F41, TABLE_HASH_MAX_FLOWS, + 0x741B8CD7, TABLE_HASH_MAX_FLOWS), + 0) + || add_table(chain, table_linear_create(TABLE_LINEAR_MAX_FLOWS), 0) + || add_table(chain, table_linear_create(TABLE_LINEAR_MAX_FLOWS), 1)) + goto error; + return chain; + +error: + if (chain) + chain_destroy(chain); + return NULL; +} + +/* Searches 'chain' for a flow matching 'key', which must not have any wildcard + * fields. Returns the flow if successful, otherwise a null pointer. + * + * Caller must hold rcu_read_lock or dp_mutex. */ +struct sw_flow *chain_lookup(struct sw_chain *chain, + const struct sw_flow_key *key, int emerg) +{ + int i; + + BUG_ON(key->wildcards); + if (emerg) { + struct sw_table *t = chain->emerg_table; + struct sw_flow *flow = t->lookup(t, key); + t->n_lookup++; + if (flow) { + t->n_matched++; + return flow; + } + } else { + for (i = 0; i < chain->n_tables; i++) { + struct sw_table *t = chain->tables[i]; + struct sw_flow *flow = t->lookup(t, key); + t->n_lookup++; + if (flow) { + t->n_matched++; + return flow; + } + } + } + return NULL; +} + +/* Inserts 'flow' into 'chain', replacing any duplicate flow. Returns 0 if + * successful or a negative error. + * + * If successful, 'flow' becomes owned by the chain, otherwise it is retained + * by the caller. + * + * Caller must hold dp_mutex. */ +int chain_insert(struct sw_chain *chain, struct sw_flow *flow, int emerg) +{ + int i; + + might_sleep(); + if (emerg) { + struct sw_table *t = chain->emerg_table; + if (t->insert(t, flow)) + return 0; + } else { + for (i = 0; i < chain->n_tables; i++) { + struct sw_table *t = chain->tables[i]; + if (t->insert(t, flow)) + return 0; + } + } + return -ENOBUFS; +} + +/* Modifies actions in 'chain' that match 'key'. If 'strict' set, wildcards + * and priority must match. Returns the number of flows that were modified. + * + * Expensive in the general case as currently implemented, since it requires + * iterating through the entire contents of each table for keys that contain + * wildcards. Relatively cheap for fully specified keys. */ +int +chain_modify(struct sw_chain *chain, const struct sw_flow_key *key, + uint16_t priority, int strict, + const struct ofp_action_header *actions, size_t actions_len, + int emerg) +{ + int count = 0; + int i; + + if (emerg) { + struct sw_table *t = chain->emerg_table; + count += t->modify(t, key, priority, strict, + actions, actions_len); + } else { + for (i = 0; i < chain->n_tables; i++) { + struct sw_table *t = chain->tables[i]; + count += t->modify(t, key, priority, strict, + actions, actions_len); + } + } + return count; +} + +/* Checks whether the chain has an entry with the same priority which conflicts + * with 'key'. If 'strict' set, wildcards should also match. If 'strict' is not + * set, comparison is done 'module wildcards'. + * + * Returns 'true' if such an entry exists, 'false' otherwise. */ +int +chain_has_conflict(struct sw_chain *chain, const struct sw_flow_key *key, + uint16_t priority, int strict) +{ + int i; + + for (i = 0; i < chain->n_tables; i++) { + struct sw_table *t = chain->tables[i]; + if (t->has_conflict(t, key, priority, strict)) { + return true; + } + } + + return false; +} + +/* Deletes from 'chain' any and all flows that match 'key'. If 'out_port' + * is not OFPP_NONE, then matching entries must have that port as an + * argument for an output action. If 'strict" is set, then wildcards and + * priority must match. Returns the number of flows that were deleted. + * + * Expensive in the general case as currently implemented, since it requires + * iterating through the entire contents of each table for keys that contain + * wildcards. Relatively cheap for fully specified keys. + * + * Caller must hold dp_mutex. */ +int chain_delete(struct sw_chain *chain, const struct sw_flow_key *key, + uint16_t out_port, uint16_t priority, int strict, int emerg) +{ + int count = 0; + int i; + + might_sleep(); + if (emerg) { + struct sw_table *t = chain->emerg_table; + count += t->delete(chain->dp, t, key, + out_port, priority, strict); + } else { + for (i = 0; i < chain->n_tables; i++) { + struct sw_table *t = chain->tables[i]; + count += t->delete(chain->dp, t, key, + out_port, priority, strict); + } + } + return count; +} + +/* Performs timeout processing on all the tables in 'chain'. Returns the + * number of flow entries deleted through expiration. + * + * Expensive as currently implemented, since it iterates through the entire + * contents of each table. + * + * Caller must not hold dp_mutex, because individual tables take and release it + * as necessary. */ +int chain_timeout(struct sw_chain *chain) +{ + int count = 0; + int i; + + might_sleep(); + for (i = 0; i < chain->n_tables; i++) { + struct sw_table *t = chain->tables[i]; + count += t->timeout(chain->dp, t); + } + return count; +} + +/* Destroys 'chain', which must not have any users. */ +void chain_destroy(struct sw_chain *chain) +{ + int i; + struct sw_table *t = NULL; + + synchronize_rcu(); + for (i = 0; i < chain->n_tables; i++) { + t = chain->tables[i]; + if (t->destroy) + t->destroy(t); + } + t = chain->emerg_table; + if (t->destroy) + t->destroy(t); + module_put(chain->owner); + kfree(chain); +} + +int chain_set_hw_hook(struct sw_table *(*create_hw_table)(void), + struct module *owner) +{ + int retval = -EBUSY; + + spin_lock(&hook_lock); + if (!create_hw_table_hook) { + create_hw_table_hook = create_hw_table; + hw_table_owner = owner; + retval = 0; + } + spin_unlock(&hook_lock); + + return retval; +} +EXPORT_SYMBOL(chain_set_hw_hook); + +void chain_clear_hw_hook(void) +{ + create_hw_table_hook = NULL; + hw_table_owner = NULL; +} +EXPORT_SYMBOL(chain_clear_hw_hook); diff --git a/openflow/datapath/chain.h b/openflow/datapath/chain.h new file mode 100644 index 00000000..4b00aef6 --- /dev/null +++ b/openflow/datapath/chain.h @@ -0,0 +1,43 @@ +#ifndef CHAIN_H +#define CHAIN_H 1 + +#include + +struct sw_flow; +struct sw_flow_key; +struct ofp_action_header; +struct datapath; + + +#define TABLE_LINEAR_MAX_FLOWS 100 +#define TABLE_HASH_MAX_FLOWS 65536 + +/* Set of tables chained together in sequence from cheap to expensive. */ +#define CHAIN_MAX_TABLES 4 +struct sw_chain { + int n_tables; + struct sw_table *tables[CHAIN_MAX_TABLES]; + struct sw_table *emerg_table; + + struct datapath *dp; + struct module *owner; +}; + +struct sw_chain *chain_create(struct datapath *); +struct sw_flow *chain_lookup(struct sw_chain *, const struct sw_flow_key *, + int); +int chain_insert(struct sw_chain *, struct sw_flow *, int); +int chain_modify(struct sw_chain *, const struct sw_flow_key *, + uint16_t, int, const struct ofp_action_header *, size_t, int); +int chain_has_conflict(struct sw_chain *, const struct sw_flow_key *, + uint16_t, int); +int chain_delete(struct sw_chain *, const struct sw_flow_key *, uint16_t, + uint16_t, int, int); +int chain_timeout(struct sw_chain *); +void chain_destroy(struct sw_chain *); + +int chain_set_hw_hook(struct sw_table *(*create_hw_table)(void), + struct module *owner); +void chain_clear_hw_hook(void); + +#endif /* chain.h */ diff --git a/openflow/datapath/compat.h b/openflow/datapath/compat.h new file mode 100644 index 00000000..1915cd31 --- /dev/null +++ b/openflow/datapath/compat.h @@ -0,0 +1,12 @@ +#ifndef COMPAT_H +#define COMPAT_H 1 + +#include + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + +#include "compat26.h" + +#endif + +#endif /* compat.h */ diff --git a/openflow/datapath/crc32.c b/openflow/datapath/crc32.c new file mode 100644 index 00000000..3cb26c5a --- /dev/null +++ b/openflow/datapath/crc32.c @@ -0,0 +1,45 @@ +/* + * Distributed under the terms of the GNU GPL version 2. + * Copyright (c) 2007, 2008 The Board of Trustees of The Leland + * Stanford Junior University + */ + +#include +#include "crc32.h" + +void crc32_init(struct crc32 *crc, unsigned int polynomial) +{ + int i; + + for (i = 0; i < CRC32_TABLE_SIZE; ++i) { + unsigned int reg = i << 24; + int j; + for (j = 0; j < CRC32_TABLE_BITS; j++) { + int topBit = (reg & 0x80000000) != 0; + reg <<= 1; + if (topBit) + reg ^= polynomial; + } + crc->table[i] = reg; + } +} + +EXPORT_SYMBOL(crc32_init); + +unsigned int crc32_calculate(const struct crc32 *crc, + const void *data_, size_t n_bytes) +{ + // FIXME: this can be optimized by unrolling, see linux-2.6/lib/crc32.c. + const uint8_t *data = data_; + unsigned int result = 0; + size_t i; + + for (i = 0; i < n_bytes; i++) { + unsigned int top = result >> 24; + top ^= data[i]; + result = (result << 8) ^ crc->table[top]; + } + return result; +} + +EXPORT_SYMBOL(crc32_calculate); diff --git a/openflow/datapath/crc32.h b/openflow/datapath/crc32.h new file mode 100644 index 00000000..21a350a9 --- /dev/null +++ b/openflow/datapath/crc32.h @@ -0,0 +1,22 @@ +#ifndef CRC32_H +#define CRC32_H 1 + +#include +#ifndef __KERNEL__ +#include +#endif +#include + +#define CRC32_TABLE_BITS 8 +#define CRC32_TABLE_SIZE (1u << CRC32_TABLE_BITS) + +struct crc32 { + unsigned int table[CRC32_TABLE_SIZE]; +}; + +void crc32_init(struct crc32 *, unsigned int polynomial); +unsigned int crc32_calculate(const struct crc32 *, + const void *data_, size_t n_bytes); + + +#endif /* crc32.h */ diff --git a/openflow/datapath/datapath.c b/openflow/datapath/datapath.c new file mode 100644 index 00000000..5678ea68 --- /dev/null +++ b/openflow/datapath/datapath.c @@ -0,0 +1,2137 @@ +/* + * Distributed under the terms of the GNU GPL version 2. + * Copyright (c) 2007, 2008, 2009 The Board of Trustees of The Leland + * Stanford Junior University + */ + +/* Functions for managing the dp interface/device. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "openflow/nicira-ext.h" +#include "openflow/openflow-netlink.h" +#include "datapath.h" +#include "table.h" +#include "chain.h" +#include "dp_dev.h" +#include "forward.h" +#include "flow.h" + +#include "compat.h" + + +/* Strings to describe the manufacturer, hardware, and software. This data + * is queriable through the switch description stats message. */ +static char mfr_desc[DESC_STR_LEN] = "Stanford University"; +static char hw_desc[DESC_STR_LEN] = "Reference Kernelspace Switch"; +static char sw_desc[DESC_STR_LEN] = VERSION BUILDNR; +static char serial_num[SERIAL_NUM_LEN] = "None"; + +module_param_string(mfr_desc, mfr_desc, sizeof mfr_desc, 0444); +module_param_string(hw_desc, hw_desc, sizeof hw_desc, 0444); +module_param_string(sw_desc, sw_desc, sizeof sw_desc, 0444); +module_param_string(serial_num, serial_num, sizeof serial_num, 0444); + +int (*dp_ioctl_hook)(struct net_device *dev, struct ifreq *rq, int cmd); +EXPORT_SYMBOL(dp_ioctl_hook); + +int (*dp_add_dp_hook)(struct datapath *dp); +EXPORT_SYMBOL(dp_add_dp_hook); + +int (*dp_del_dp_hook)(struct datapath *dp); +EXPORT_SYMBOL(dp_del_dp_hook); + +int (*dp_add_if_hook)(struct net_bridge_port *p); +EXPORT_SYMBOL(dp_add_if_hook); + +int (*dp_del_if_hook)(struct net_bridge_port *p); +EXPORT_SYMBOL(dp_del_if_hook); + +/* Number of milliseconds between runs of the maintenance thread. */ +#define MAINT_SLEEP_MSECS 1000 + +static struct genl_family dp_genl_family; + +/* + * Datapath multicast groups. + * + * Really we want one multicast group per in-use datapath (or even more than + * one). Locking issues, however, mean that we can't allocate a multicast + * group at the point in the code where we we actually create a datapath[*], so + * we have to pre-allocate them. It's massive overkill to allocate DP_MAX of + * them in advance, since we will hardly ever actually create DP_MAX datapaths, + * so instead we allocate a few multicast groups at startup and choose one for + * each datapath by hashing its datapath index. + * + * [*] dp_genl_add, to add a new datapath, is called under the genl_lock + * mutex, and genl_register_mc_group, called to acquire a new multicast + * group ID, also acquires genl_lock, thus deadlock. + */ +#define N_MC_GROUPS 16 /* Must be power of 2. */ +static struct genl_multicast_group mc_groups[N_MC_GROUPS]; + +/* Datapaths. Protected on the read side by rcu_read_lock, on the write side + * by dp_mutex. dp_mutex is almost completely redundant with genl_mutex + * maintained by the Generic Netlink code, but the timeout path needs mutual + * exclusion too. + * + * dp_mutex nests inside the RTNL lock: if you need both you must take the RTNL + * lock first. + * + * It is safe to access the datapath and net_bridge_port structures with just + * dp_mutex. + */ +static struct datapath *dps[DP_MAX]; +DEFINE_MUTEX(dp_mutex); +EXPORT_SYMBOL(dp_mutex); + +static int dp_maint_func(void *data); +static void init_port_status(struct net_bridge_port *p); +static int dp_genl_openflow_done(struct netlink_callback *); +static struct net_bridge_port *new_nbp(struct datapath *, + struct net_device *, int port_no); + +/* nla_shrink - reduce amount of space reserved by nla_reserve + * @skb: socket buffer from which to recover room + * @nla: netlink attribute to adjust + * @len: new length of attribute payload + * + * Reduces amount of space reserved by a call to nla_reserve. + * + * No other attributes may be added between calling nla_reserve and this + * function, since it will create a hole in the message. + */ +void nla_shrink(struct sk_buff *skb, struct nlattr *nla, int len) +{ + int delta = nla_total_size(len) - nla_total_size(nla_len(nla)); + BUG_ON(delta > 0); + skb->tail += delta; + skb->len += delta; + nla->nla_len = nla_attr_size(len); +} + +/* Puts a set of openflow headers for a message of the given 'type' into 'skb'. + * If 'sender' is nonnull, then it is used as the message's destination. 'dp' + * must specify the datapath to use. + * + * '*max_openflow_len' receives the maximum number of bytes that are available + * for the embedded OpenFlow message. The caller must call + * resize_openflow_skb() to set the actual size of the message to this number + * of bytes or less. + * + * Returns the openflow header if successful, otherwise (if 'skb' is too small) + * an error code. */ +static void * +put_openflow_headers(struct datapath *dp, struct sk_buff *skb, uint8_t type, + const struct sender *sender, int *max_openflow_len) +{ + struct ofp_header *oh; + struct nlattr *attr; + int openflow_len; + + /* Assemble the Generic Netlink wrapper. */ + if (!genlmsg_put(skb, + sender ? sender->pid : 0, + sender ? sender->seq : 0, + &dp_genl_family, 0, DP_GENL_C_OPENFLOW)) + return ERR_PTR(-ENOBUFS); + if (nla_put_u32(skb, DP_GENL_A_DP_IDX, dp->dp_idx) < 0) + return ERR_PTR(-ENOBUFS); + openflow_len = (skb_tailroom(skb) - NLA_HDRLEN) & ~(NLA_ALIGNTO - 1); + if (openflow_len < sizeof *oh) + return ERR_PTR(-ENOBUFS); + *max_openflow_len = openflow_len; + attr = nla_reserve(skb, DP_GENL_A_OPENFLOW, openflow_len); + BUG_ON(!attr); + + /* Fill in the header. The caller is responsible for the length. */ + oh = nla_data(attr); + oh->version = OFP_VERSION; + oh->type = type; + oh->xid = sender ? sender->xid : 0; + + return oh; +} + +/* Resizes OpenFlow header 'oh', which must be at the tail end of 'skb', to new + * length 'new_length' (in bytes), adjusting pointers and size values as + * necessary. */ +static void +resize_openflow_skb(struct sk_buff *skb, + struct ofp_header *oh, size_t new_length) +{ + struct nlattr *attr = ((void *) oh) - NLA_HDRLEN; + nla_shrink(skb, attr, new_length); + oh->length = htons(new_length); + nlmsg_end(skb, (struct nlmsghdr *) skb->data); +} + +/* Allocates a new skb to contain an OpenFlow message 'openflow_len' bytes in + * length. Returns a null pointer if memory is unavailable, otherwise returns + * the OpenFlow header and stores a pointer to the skb in '*pskb'. + * + * 'type' is the OpenFlow message type. If 'sender' is nonnull, then it is + * used as the message's destination. 'dp' must specify the datapath to + * use. */ +static void * +alloc_openflow_skb(struct datapath *dp, size_t openflow_len, uint8_t type, + const struct sender *sender, struct sk_buff **pskb) +{ + struct ofp_header *oh; + size_t genl_len; + struct sk_buff *skb; + int max_openflow_len; + + if ((openflow_len + sizeof(struct ofp_header)) > UINT16_MAX) { + if (net_ratelimit()) + printk(KERN_ERR "%s: alloc_openflow_skb: openflow " + "message too large: %zu\n", + dp->netdev->name, openflow_len); + return NULL; + } + + genl_len = nlmsg_total_size(GENL_HDRLEN + dp_genl_family.hdrsize); + genl_len += nla_total_size(sizeof(uint32_t)); /* DP_GENL_A_DP_IDX */ + genl_len += nla_total_size(openflow_len); /* DP_GENL_A_OPENFLOW */ + skb = *pskb = genlmsg_new(genl_len, GFP_ATOMIC); + if (!skb) { + return NULL; + } + + oh = put_openflow_headers(dp, skb, type, sender, &max_openflow_len); + BUG_ON(!oh || IS_ERR(oh)); + resize_openflow_skb(skb, oh, openflow_len); + + return oh; +} + +/* Returns the ID of the multicast group used by datapath 'dp'. */ +static u32 +dp_mc_group(const struct datapath *dp) +{ + return mc_groups[dp->dp_idx & (N_MC_GROUPS - 1)].id; +} + +/* Sends 'skb' to 'sender' if it is nonnull, otherwise multicasts 'skb' to all + * listeners. */ +static int +send_openflow_skb(const struct datapath *dp, + struct sk_buff *skb, const struct sender *sender) +{ + return (sender + ? genlmsg_unicast(skb, sender->pid) + : genlmsg_multicast(skb, 0, dp_mc_group(dp), GFP_ATOMIC)); +} + +/* Retrieves the datapath id, which is the MAC address of the "of" device. */ +static +uint64_t get_datapath_id(struct net_device *dev) +{ + uint64_t id = 0; + int i; + + for (i=0; idev_addr[i] << (8*(ETH_ALEN-1 - i)); + + return id; +} + +/* Find the first free datapath index. Return the index or -1 if a free + * index could not be found. */ +int gen_dp_idx(void) +{ + int i; + + for (i=0; i= DP_MAX) + goto err_unlock; + + err = -ENODEV; + if (!try_module_get(THIS_MODULE)) + goto err_unlock; + + /* Exit early if a datapath with that number already exists. */ + err = -EEXIST; + if (dps[dp_idx]) + goto err_put; + + err = -ENOMEM; + dp = kzalloc(sizeof *dp, GFP_KERNEL); + if (dp == NULL) + goto err_put; + + dp->dp_idx = dp_idx; + /* copied from sys_gethostname() */ + u = utsname(); + /* shouldn't need to lock b/c no userspace interactions */ + snprintf(dp->dp_desc, sizeof dp->dp_desc, "%s idx=%d", u->nodename, dp_idx); + + /* Setup our datapath device */ + err = dp_dev_setup(dp, dp_name); + if (err) + goto err_free_dp; + + dp->chain = chain_create(dp); + if (dp->chain == NULL) + goto err_destroy_dp_dev; + INIT_LIST_HEAD(&dp->port_list); + + dp->local_port = new_nbp(dp, dp->netdev, OFPP_LOCAL); + if (IS_ERR(dp->local_port)) { + err = PTR_ERR(dp->local_port); + goto err_destroy_local_port; + } + + dp->flags = 0; + dp->miss_send_len = OFP_DEFAULT_MISS_SEND_LEN; + + dp->dp_task = kthread_run(dp_maint_func, dp, "dp%d", dp_idx); + if (IS_ERR(dp->dp_task)) + goto err_destroy_chain; + + dps[dp_idx] = dp; + mutex_unlock(&dp_mutex); + rtnl_unlock(); + + if (dp_add_dp_hook) + dp_add_dp_hook(dp); + + return 0; + +err_destroy_local_port: + dp_del_switch_port(dp->local_port); +err_destroy_chain: + chain_destroy(dp->chain); +err_destroy_dp_dev: + dp_dev_destroy(dp); +err_free_dp: + kfree(dp); +err_put: + module_put(THIS_MODULE); +err_unlock: + mutex_unlock(&dp_mutex); + rtnl_unlock(); + return err; +} + +/* Find and return a free port number under 'dp'. */ +static int find_portno(struct datapath *dp) +{ + int i; + for (i = 1; i < DP_MAX_PORTS; i++) + if (dp->ports[i] == NULL) + return i; + return -EXFULL; +} + +/* Called with RTNL lock and dp_mutex. */ +static struct net_bridge_port *new_nbp(struct datapath *dp, + struct net_device *dev, int port_no) +{ + struct net_bridge_port *p; + + if (dev->br_port != NULL) + return ERR_PTR(-EBUSY); + + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (p == NULL) + return ERR_PTR(-ENOMEM); + + dev_set_promiscuity(dev, 1); + dev_hold(dev); + p->dp = dp; + p->dev = dev; + p->port_no = port_no; + spin_lock_init(&p->lock); + if (port_no != OFPP_LOCAL) + rcu_assign_pointer(dev->br_port, p); + if (port_no < DP_MAX_PORTS) + rcu_assign_pointer(dp->ports[port_no], p); + list_add_rcu(&p->node, &dp->port_list); + + return p; +} + +/* Called with RTNL lock and dp_mutex. */ +int add_switch_port(struct datapath *dp, struct net_device *dev) +{ + struct net_bridge_port *p; + int port_no; + + if (dev->flags & IFF_LOOPBACK || dev->type != ARPHRD_ETHER + || is_dp_dev(dev)) + return -EINVAL; + + port_no = find_portno(dp); + if (port_no < 0) + return port_no; + + p = new_nbp(dp, dev, port_no); + if (IS_ERR(p)) + return PTR_ERR(p); + + init_port_status(p); + + if (dp_add_if_hook) + dp_add_if_hook(p); + + /* Notify the ctlpath that this port has been added */ + dp_send_port_status(p, OFPPR_ADD); + + return 0; +} + +/* Delete 'p' from switch. + * Called with RTNL lock and dp_mutex. */ +int dp_del_switch_port(struct net_bridge_port *p) +{ + +#if CONFIG_SYSFS + if ((p->port_no != OFPP_LOCAL) && dp_del_if_hook) + sysfs_remove_link(&p->dp->ifobj, p->dev->name); +#endif + + /* First drop references to device. */ + dev_set_promiscuity(p->dev, -1); + list_del_rcu(&p->node); + if (p->port_no != OFPP_LOCAL) + rcu_assign_pointer(p->dp->ports[p->port_no], NULL); + rcu_assign_pointer(p->dev->br_port, NULL); + + /* Then wait until no one is still using it, and destroy it. */ + synchronize_rcu(); + + /* Notify the ctlpath that this port no longer exists */ + dp_send_port_status(p, OFPPR_DELETE); + + if ((p->port_no != OFPP_LOCAL) && dp_del_if_hook) { + dp_del_if_hook(p); + } else { + dev_put(p->dev); + kfree(p); + } + + return 0; +} + +static void del_dp(struct datapath *dp) +{ + struct net_bridge_port *p, *n; + + send_sig(SIGKILL, dp->dp_task, 0); + kthread_stop(dp->dp_task); + + /* Drop references to DP. */ + list_for_each_entry_safe (p, n, &dp->port_list, node) + dp_del_switch_port(p); + + if (dp_del_dp_hook) + dp_del_dp_hook(dp); + + rcu_assign_pointer(dps[dp->dp_idx], NULL); + + /* Kill off local_port dev references from buffered packets that have + * associated dst entries. */ + synchronize_rcu(); + fwd_discard_all(); + + /* Destroy dp->netdev. (Must follow deleting switch ports since + * dp->local_port has a reference to it.) */ + dp_dev_destroy(dp); + + /* Wait until no longer in use, then destroy it. */ + synchronize_rcu(); + chain_destroy(dp->chain); + kfree(dp); + module_put(THIS_MODULE); +} + +static int dp_maint_func(void *data) +{ + struct datapath *dp = (struct datapath *) data; + + allow_signal(SIGKILL); + while (!signal_pending(current)) { + /* Timeout old entries */ + chain_timeout(dp->chain); + msleep_interruptible(MAINT_SLEEP_MSECS); + } + while (!kthread_should_stop()) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule(); + } + return 0; +} + +static void +do_port_input(struct net_bridge_port *p, struct sk_buff *skb) +{ + /* Make our own copy of the packet. Otherwise we will mangle the + * packet for anyone who came before us (e.g. tcpdump via AF_PACKET). + * (No one comes after us, since we tell handle_bridge() that we took + * the packet.) */ + skb = skb_share_check(skb, GFP_ATOMIC); + if (!skb) + return; + + /* Push the Ethernet header back on. */ + skb_push(skb, ETH_HLEN); + skb_reset_mac_header(skb); + fwd_port_input(p->dp->chain, skb, p); +} + +/* + * Used as br_handle_frame_hook. (Cannot run bridge at the same time, even on + * different set of devices!) + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) +/* Called with rcu_read_lock. */ +static struct sk_buff *dp_frame_hook(struct net_bridge_port *p, + struct sk_buff *skb) +{ + do_port_input(p, skb); + return NULL; +} +#else +static int dp_frame_hook(struct net_bridge_port *p, struct sk_buff **pskb) +{ + do_port_input(p, *pskb); + return 1; +} +#endif + +/* Forwarding output path. + * Based on net/bridge/br_forward.c. */ + +static inline unsigned packet_length(const struct sk_buff *skb) +{ + unsigned length = skb->len - ETH_HLEN; + if (skb->protocol == htons(ETH_P_8021Q)) + length -= VLAN_HLEN; + return length; +} + +/* Send packets out all the ports except the originating one. If the + * "flood" argument is set, only send along the minimum spanning tree. + */ +static int +output_all(struct datapath *dp, struct sk_buff *skb, int flood) +{ + u32 disable = flood ? OFPPC_NO_FLOOD : 0; + struct net_bridge_port *p; + int prev_port = -1; + + list_for_each_entry_rcu (p, &dp->port_list, node) { + if (skb->dev == p->dev || p->config & disable) + continue; + if (prev_port != -1) { + struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); + if (!clone) { + kfree_skb(skb); + return -ENOMEM; + } + dp_output_port(dp, clone, prev_port, 0); + } + prev_port = p->port_no; + } + if (prev_port != -1) + dp_output_port(dp, skb, prev_port, 0); + else + kfree_skb(skb); + + return 0; +} + +/* Marks 'skb' as having originated from 'in_port' in 'dp'. + FIXME: how are devices reference counted? */ +void dp_set_origin(struct datapath *dp, uint16_t in_port, + struct sk_buff *skb) +{ + struct net_bridge_port *p; + p = (in_port < DP_MAX_PORTS ? dp->ports[in_port] + : in_port == OFPP_LOCAL ? dp->local_port + : NULL); + if (p) + skb->dev = p->dev; + else + skb->dev = NULL; +} + +int +dp_xmit_skb(struct sk_buff *skb) +{ + struct datapath *dp = skb->dev->br_port->dp; + int len = skb->len; + + if (packet_length(skb) > skb->dev->mtu && !skb_is_gso(skb)) { + printk(KERN_WARNING "%s: dropped over-mtu packet: %d > %d\n", + dp->netdev->name, packet_length(skb), skb->dev->mtu); + kfree_skb(skb); + return -E2BIG; + } + + dev_queue_xmit(skb); + + return len; +} + +/* Takes ownership of 'skb' and transmits it to 'out_port' on 'dp'. + */ +int dp_output_port(struct datapath *dp, struct sk_buff *skb, int out_port, + int ignore_no_fwd) +{ + BUG_ON(!skb); + switch (out_port){ + case OFPP_IN_PORT: + /* Send it out the port it came in on, which is already set in + * the skb. */ + if (!skb->dev) { + if (net_ratelimit()) + printk(KERN_NOTICE "%s: skb device not set " + "forwarding to in_port\n", + dp->netdev->name); + kfree_skb(skb); + return -ESRCH; + } + return dp_xmit_skb(skb); + + case OFPP_TABLE: { + int retval = run_flow_through_tables(dp->chain, skb, + skb->dev->br_port); + if (retval) + kfree_skb(skb); + return retval; + } + + case OFPP_FLOOD: + return output_all(dp, skb, 1); + + case OFPP_ALL: + return output_all(dp, skb, 0); + + case OFPP_CONTROLLER: + return dp_output_control(dp, skb, UINT16_MAX, OFPR_ACTION); + + case OFPP_LOCAL: { + struct net_device *dev = dp->netdev; + return dev ? dp_dev_recv(dev, skb) : -ESRCH; + } + + case 0 ... DP_MAX_PORTS - 1: { + struct net_bridge_port *p = dp->ports[out_port]; + if (p == NULL) + goto bad_port; + if (p->dev == skb->dev) { + /* To send to the input port, must use OFPP_IN_PORT */ + kfree_skb(skb); + if (net_ratelimit()) + printk(KERN_NOTICE "%s: can't directly " + "forward to input port\n", + dp->netdev->name); + return -EINVAL; + } + if (p->config & OFPPC_NO_FWD && !ignore_no_fwd) { + kfree_skb(skb); + return 0; + } + skb->dev = p->dev; + return dp_xmit_skb(skb); + } + + default: + goto bad_port; + } + +bad_port: + kfree_skb(skb); + if (net_ratelimit()) + printk(KERN_NOTICE "%s: can't forward to bad port %d\n", + dp->netdev->name, out_port); + return -ENOENT; +} + +/* Takes ownership of 'skb' and transmits it to 'dp''s control path. 'reason' + * indicates why 'skb' is being sent. 'max_len' sets the maximum number of + * bytes that the caller wants to be sent. + */ +int +dp_output_control(struct datapath *dp, struct sk_buff *skb, + size_t max_len, int reason) +{ + /* FIXME? Can we avoid creating a new skbuff in the case where we + * forward the whole packet? */ + struct sk_buff *f_skb; + struct ofp_packet_in *opi; + size_t fwd_len, opi_len; + uint32_t buffer_id; + int err; + + WARN_ON_ONCE(skb_shared(skb)); + + buffer_id = fwd_save_skb(skb); + + fwd_len = skb->len; + if (buffer_id != (uint32_t) -1) + fwd_len = min(fwd_len, max_len); + + opi_len = offsetof(struct ofp_packet_in, data) + fwd_len; + opi = alloc_openflow_skb(dp, opi_len, OFPT_PACKET_IN, NULL, &f_skb); + if (!opi) { + err = -ENOMEM; + goto out; + } + opi->buffer_id = htonl(buffer_id); + opi->total_len = htons(skb->len); + opi->in_port = htons(skb->dev && skb->dev->br_port + ? skb->dev->br_port->port_no + : OFPP_LOCAL); + opi->reason = reason; + opi->pad = 0; + skb_copy_bits(skb, 0, opi->data, fwd_len); + err = send_openflow_skb(dp, f_skb, NULL); + +out: + kfree_skb(skb); + return err; +} + +static void fill_port_desc(struct net_bridge_port *p, struct ofp_phy_port *desc) +{ + unsigned long flags; + desc->port_no = htons(p->port_no); + strncpy(desc->name, p->dev->name, OFP_MAX_PORT_NAME_LEN); + desc->name[OFP_MAX_PORT_NAME_LEN-1] = '\0'; + memcpy(desc->hw_addr, p->dev->dev_addr, ETH_ALEN); + desc->curr = 0; + desc->supported = 0; + desc->advertised = 0; + desc->peer = 0; + + spin_lock_irqsave(&p->lock, flags); + desc->config = htonl(p->config); + desc->state = htonl(p->state); + spin_unlock_irqrestore(&p->lock, flags); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,24) + if (p->dev->ethtool_ops && p->dev->ethtool_ops->get_settings) { + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; + + if (!p->dev->ethtool_ops->get_settings(p->dev, &ecmd)) { + /* Set the supported features */ + if (ecmd.supported & SUPPORTED_10baseT_Half) + desc->supported |= OFPPF_10MB_HD; + if (ecmd.supported & SUPPORTED_10baseT_Full) + desc->supported |= OFPPF_10MB_FD; + if (ecmd.supported & SUPPORTED_100baseT_Half) + desc->supported |= OFPPF_100MB_HD; + if (ecmd.supported & SUPPORTED_100baseT_Full) + desc->supported |= OFPPF_100MB_FD; + if (ecmd.supported & SUPPORTED_1000baseT_Half) + desc->supported |= OFPPF_1GB_HD; + if (ecmd.supported & SUPPORTED_1000baseT_Full) + desc->supported |= OFPPF_1GB_FD; + if (ecmd.supported & SUPPORTED_10000baseT_Full) + desc->supported |= OFPPF_10GB_FD; + if (ecmd.supported & SUPPORTED_TP) + desc->supported |= OFPPF_COPPER; + if (ecmd.supported & SUPPORTED_FIBRE) + desc->supported |= OFPPF_FIBER; + if (ecmd.supported & SUPPORTED_Autoneg) + desc->supported |= OFPPF_AUTONEG; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14) + if (ecmd.supported & SUPPORTED_Pause) + desc->supported |= OFPPF_PAUSE; + if (ecmd.supported & SUPPORTED_Asym_Pause) + desc->supported |= OFPPF_PAUSE_ASYM; +#endif /* kernel >= 2.6.14 */ + + /* Set the advertised features */ + if (ecmd.advertising & ADVERTISED_10baseT_Half) + desc->advertised |= OFPPF_10MB_HD; + if (ecmd.advertising & ADVERTISED_10baseT_Full) + desc->advertised |= OFPPF_10MB_FD; + if (ecmd.advertising & ADVERTISED_100baseT_Half) + desc->advertised |= OFPPF_100MB_HD; + if (ecmd.advertising & ADVERTISED_100baseT_Full) + desc->advertised |= OFPPF_100MB_FD; + if (ecmd.advertising & ADVERTISED_1000baseT_Half) + desc->advertised |= OFPPF_1GB_HD; + if (ecmd.advertising & ADVERTISED_1000baseT_Full) + desc->advertised |= OFPPF_1GB_FD; + if (ecmd.advertising & ADVERTISED_10000baseT_Full) + desc->advertised |= OFPPF_10GB_FD; + if (ecmd.advertising & ADVERTISED_TP) + desc->advertised |= OFPPF_COPPER; + if (ecmd.advertising & ADVERTISED_FIBRE) + desc->advertised |= OFPPF_FIBER; + if (ecmd.advertising & ADVERTISED_Autoneg) + desc->advertised |= OFPPF_AUTONEG; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14) + if (ecmd.advertising & ADVERTISED_Pause) + desc->advertised |= OFPPF_PAUSE; + if (ecmd.advertising & ADVERTISED_Asym_Pause) + desc->advertised |= OFPPF_PAUSE_ASYM; +#endif /* kernel >= 2.6.14 */ + + /* Set the current features */ + if (ecmd.speed == SPEED_10) + desc->curr = (ecmd.duplex) ? OFPPF_10MB_FD : OFPPF_10MB_HD; + else if (ecmd.speed == SPEED_100) + desc->curr = (ecmd.duplex) ? OFPPF_100MB_FD : OFPPF_100MB_HD; + else if (ecmd.speed == SPEED_1000) + desc->curr = (ecmd.duplex) ? OFPPF_1GB_FD : OFPPF_1GB_HD; + else if (ecmd.speed == SPEED_10000) + desc->curr = OFPPF_10GB_FD; + + if (ecmd.port == PORT_TP) + desc->curr |= OFPPF_COPPER; + else if (ecmd.port == PORT_FIBRE) + desc->curr |= OFPPF_FIBER; + + if (ecmd.autoneg) + desc->curr |= OFPPF_AUTONEG; + } + } +#endif + desc->curr = htonl(desc->curr); + desc->supported = htonl(desc->supported); + desc->advertised = htonl(desc->advertised); + desc->peer = htonl(desc->peer); +} + +static int +fill_features_reply(struct datapath *dp, struct ofp_switch_features *ofr) +{ + struct net_bridge_port *p; + uint64_t dpid = get_datapath_id(dp->netdev); + int port_count = 0; + + ofr->datapath_id = cpu_to_be64(dpid); + + ofr->n_buffers = htonl(N_PKT_BUFFERS); + ofr->n_tables = dp->chain->n_tables; + ofr->capabilities = htonl(OFP_SUPPORTED_CAPABILITIES); + ofr->actions = htonl(OFP_SUPPORTED_ACTIONS); + memset(ofr->pad, 0, sizeof ofr->pad); + + list_for_each_entry_rcu (p, &dp->port_list, node) { + fill_port_desc(p, &ofr->ports[port_count]); + port_count++; + } + + return port_count; +} + +int +dp_send_features_reply(struct datapath *dp, const struct sender *sender) +{ + struct sk_buff *skb; + struct ofp_switch_features *ofr; + size_t ofr_len, port_max_len; + int port_count; + + /* Overallocate. */ + port_max_len = sizeof(struct ofp_phy_port) * DP_MAX_PORTS; + ofr = alloc_openflow_skb(dp, sizeof(*ofr) + port_max_len, + OFPT_FEATURES_REPLY, sender, &skb); + if (!ofr) + return -ENOMEM; + + /* Fill. */ + port_count = fill_features_reply(dp, ofr); + + /* Shrink to fit. */ + ofr_len = sizeof(*ofr) + (sizeof(struct ofp_phy_port) * port_count); + resize_openflow_skb(skb, &ofr->header, ofr_len); + return send_openflow_skb(dp, skb, sender); +} + +int +dp_send_config_reply(struct datapath *dp, const struct sender *sender) +{ + struct sk_buff *skb; + struct ofp_switch_config *osc; + + osc = alloc_openflow_skb(dp, sizeof *osc, OFPT_GET_CONFIG_REPLY, sender, + &skb); + if (!osc) + return -ENOMEM; + + osc->flags = htons(dp->flags); + osc->miss_send_len = htons(dp->miss_send_len); + + return send_openflow_skb(dp, skb, sender); +} + +int +dp_send_hello(struct datapath *dp, const struct sender *sender, + const struct ofp_header *request) +{ + if (request->version < OFP_VERSION) { + char err[64]; + sprintf(err, "Only version 0x%02x supported", OFP_VERSION); + dp_send_error_msg(dp, sender, OFPET_HELLO_FAILED, + OFPHFC_INCOMPATIBLE, err, strlen(err)); + return -EINVAL; + } else { + struct sk_buff *skb; + struct ofp_header *reply; + + reply = alloc_openflow_skb(dp, sizeof *reply, + OFPT_HELLO, sender, &skb); + if (!reply) + return -ENOMEM; + + return send_openflow_skb(dp, skb, sender); + } +} + +int +dp_send_barrier_reply(struct datapath *dp, const struct sender *sender, + const struct ofp_header *request) +{ + struct sk_buff *skb; + struct ofp_header *reply; + + reply = alloc_openflow_skb(dp, sizeof *reply, + OFPT_BARRIER_REPLY, sender, &skb); + if (!reply) + return -ENOMEM; + + return send_openflow_skb(dp, skb, sender); +} + +int +dp_update_port_flags(struct datapath *dp, const struct ofp_port_mod *opm) +{ + unsigned long int flags; + int port_no = ntohs(opm->port_no); + struct net_bridge_port *p; + p = (port_no < DP_MAX_PORTS ? dp->ports[port_no] + : port_no == OFPP_LOCAL ? dp->local_port + : NULL); + + /* Make sure the port id hasn't changed since this was sent */ + if (!p || memcmp(opm->hw_addr, p->dev->dev_addr, ETH_ALEN)) + return -1; + + spin_lock_irqsave(&p->lock, flags); + if (opm->mask) { + uint32_t config_mask = ntohl(opm->mask); + p->config &= ~config_mask; + p->config |= ntohl(opm->config) & config_mask; + } + spin_unlock_irqrestore(&p->lock, flags); + + return 0; +} + +/* Initialize the port status field of the bridge port. */ +static void +init_port_status(struct net_bridge_port *p) +{ + unsigned long int flags; + + spin_lock_irqsave(&p->lock, flags); + + if (p->dev->flags & IFF_UP) + p->config &= ~OFPPC_PORT_DOWN; + else + p->config |= OFPPC_PORT_DOWN; + + if (netif_carrier_ok(p->dev)) + p->state &= ~OFPPS_LINK_DOWN; + else + p->state |= OFPPS_LINK_DOWN; + + spin_unlock_irqrestore(&p->lock, flags); +} + +int +dp_send_port_status(struct net_bridge_port *p, uint8_t status) +{ + struct sk_buff *skb; + struct ofp_port_status *ops; + + ops = alloc_openflow_skb(p->dp, sizeof *ops, OFPT_PORT_STATUS, NULL, + &skb); + if (!ops) + return -ENOMEM; + ops->reason = status; + memset(ops->pad, 0, sizeof ops->pad); + fill_port_desc(p, &ops->desc); + + return send_openflow_skb(p->dp, skb, NULL); +} + +/* Convert jiffies_64 to seconds. */ +static u32 inline jiffies_64_to_secs(u64 j) +{ + /* Call to do_div is necessary as we can't do a 64-bit division in a + * 32-bit kernel (at least not without linking to libgcc) */ + do_div(j, HZ); + return j; +} + +/* Convert jiffies_64 to just the nanosec part between seconds. */ +static u32 inline jiffies_64_to_nsecs(u64 j) +{ + /* Call to do_div is necessary as we can't do a 64-bit division in a + * 32-bit kernel (at least not without linking to libgcc) */ + return (j - jiffies_64_to_secs(j)); +} + +int +dp_send_flow_end(struct datapath *dp, struct sw_flow *flow, + enum ofp_flow_removed_reason reason) +{ + struct sk_buff *skb; + struct ofp_flow_removed *ofr; + + if (!flow->send_flow_rem) + return 0; + + if (flow->emerg_flow) + return 0; + + ofr = alloc_openflow_skb(dp, sizeof *ofr, OFPT_FLOW_REMOVED, 0, &skb); + if (!ofr) + return -ENOMEM; + + flow_fill_match(&ofr->match, &flow->key); + + ofr->priority = htons(flow->priority); + ofr->reason = reason; + + ofr->duration_sec = htonl(jiffies_64_to_secs(get_jiffies_64()-flow->created)); + ofr->duration_nsec = htonl(jiffies_64_to_nsecs(get_jiffies_64()-flow->created)); + ofr->idle_timeout = htons(flow->idle_timeout); + + ofr->packet_count = cpu_to_be64(flow->packet_count); + ofr->byte_count = cpu_to_be64(flow->byte_count); + + return send_openflow_skb(dp, skb, NULL); +} +EXPORT_SYMBOL(dp_send_flow_end); + +int +dp_send_error_msg(struct datapath *dp, const struct sender *sender, + uint16_t type, uint16_t code, const void *data, size_t len) +{ + struct sk_buff *skb; + struct ofp_error_msg *oem; + + + oem = alloc_openflow_skb(dp, sizeof(*oem)+len, OFPT_ERROR, + sender, &skb); + if (!oem) + return -ENOMEM; + + oem->type = htons(type); + oem->code = htons(code); + memcpy(oem->data, data, len); + + return send_openflow_skb(dp, skb, sender); +} + +int +dp_send_echo_reply(struct datapath *dp, const struct sender *sender, + const struct ofp_header *rq) +{ + struct sk_buff *skb; + struct ofp_header *reply; + + reply = alloc_openflow_skb(dp, ntohs(rq->length), OFPT_ECHO_REPLY, + sender, &skb); + if (!reply) + return -ENOMEM; + + memcpy(reply + 1, rq + 1, ntohs(rq->length) - sizeof *rq); + return send_openflow_skb(dp, skb, sender); +} + +/* Generic Netlink interface. + * + * See netlink(7) for an introduction to netlink. See + * http://linux-net.osdl.org/index.php/Netlink for more information and + * pointers on how to work with netlink and Generic Netlink in the kernel and + * in userspace. */ + +static struct genl_family dp_genl_family = { + .id = GENL_ID_GENERATE, + .hdrsize = 0, + .name = DP_GENL_FAMILY_NAME, + .version = 1, + .maxattr = DP_GENL_A_MAX, +}; + +/* Attribute policy: what each attribute may contain. */ +static struct nla_policy dp_genl_policy[DP_GENL_A_MAX + 1] = { + [DP_GENL_A_DP_IDX] = { .type = NLA_U32 }, + [DP_GENL_A_DP_NAME] = { .type = NLA_NUL_STRING }, + [DP_GENL_A_MC_GROUP] = { .type = NLA_U32 }, + [DP_GENL_A_PORTNAME] = { .type = NLA_NUL_STRING } +}; + +static int dp_genl_add(struct sk_buff *skb, struct genl_info *info) +{ + int dp_idx = info->attrs[DP_GENL_A_DP_IDX] ? + nla_get_u32(info->attrs[DP_GENL_A_DP_IDX]) : -1; + const char *dp_name = info->attrs[DP_GENL_A_DP_NAME] ? + nla_data(info->attrs[DP_GENL_A_DP_NAME]) : NULL; + + if (VERIFY_NUL_STRING(info->attrs[DP_GENL_A_DP_NAME])) + return -EINVAL; + + if ((dp_idx == -1) && (!dp_name)) + return -EINVAL; + + return new_dp(dp_idx, dp_name); +} + +static struct genl_ops dp_genl_ops_add_dp = { + .cmd = DP_GENL_C_ADD_DP, + .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ + .policy = dp_genl_policy, + .doit = dp_genl_add, + .dumpit = NULL, +}; + +/* Must be called with rcu_read_lock or dp_mutex. */ +struct datapath *dp_get_by_idx(int dp_idx) +{ + if (dp_idx < 0 || dp_idx >= DP_MAX) + return NULL; + return rcu_dereference(dps[dp_idx]); +} +EXPORT_SYMBOL(dp_get_by_idx); + +/* Must be called with rcu_read_lock or dp_mutex. */ +struct datapath *dp_get_by_name(const char *dp_name) +{ + int i; + for (i=0; inetdev->name, dp_name)) + return dp; + } + return NULL; +} + +/* Must be called with rcu_read_lock or dp_mutex. */ +static struct datapath * +lookup_dp(struct genl_info *info) +{ + int dp_idx = info->attrs[DP_GENL_A_DP_IDX] ? + nla_get_u32(info->attrs[DP_GENL_A_DP_IDX]) : -1; + const char *dp_name = info->attrs[DP_GENL_A_DP_NAME] ? + nla_data(info->attrs[DP_GENL_A_DP_NAME]) : NULL; + + if (VERIFY_NUL_STRING(info->attrs[DP_GENL_A_DP_NAME])) + return ERR_PTR(-EINVAL); + + if (dp_idx != -1) { + struct datapath *dp = dp_get_by_idx(dp_idx); + if (!dp) + return ERR_PTR(-ENOENT); + else if (dp_name && strcmp(dp->netdev->name, dp_name)) + return ERR_PTR(-EINVAL); + else + return dp; + } else if (dp_name) { + struct datapath *dp = dp_get_by_name(dp_name); + return dp ? dp : ERR_PTR(-ENOENT); + } else { + return ERR_PTR(-EINVAL); + } +} + +static int dp_genl_del(struct sk_buff *skb, struct genl_info *info) +{ + struct net_device *dev = NULL; + struct datapath *dp; + int err; + + rtnl_lock(); + mutex_lock(&dp_mutex); + dp = lookup_dp(info); + if (IS_ERR(dp)) + err = PTR_ERR(dp); + else { + dev = dp->netdev; + del_dp(dp); + err = 0; + } + mutex_unlock(&dp_mutex); + rtnl_unlock(); + if (dev) + free_netdev(dev); + return err; +} + +static struct genl_ops dp_genl_ops_del_dp = { + .cmd = DP_GENL_C_DEL_DP, + .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ + .policy = dp_genl_policy, + .doit = dp_genl_del, + .dumpit = NULL, +}; + +/* Queries a datapath for related information. Currently the only relevant + * information is the datapath's multicast group ID, datapath ID, and + * datapath device name. */ +static int dp_genl_query(struct sk_buff *skb, struct genl_info *info) +{ + struct datapath *dp; + struct sk_buff *ans_skb = NULL; + int err; + + rcu_read_lock(); + dp = lookup_dp(info); + if (IS_ERR(dp)) + err = PTR_ERR(dp); + else { + void *data; + ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); + if (!ans_skb) { + err = -ENOMEM; + goto err; + } + err = -ENOMEM; + data = genlmsg_put_reply(ans_skb, info, &dp_genl_family, + 0, DP_GENL_C_QUERY_DP); + if (data == NULL) + goto err; + NLA_PUT_U32(ans_skb, DP_GENL_A_DP_IDX, dp->dp_idx); + NLA_PUT_STRING(ans_skb, DP_GENL_A_DP_NAME, dp->netdev->name); + NLA_PUT_U32(ans_skb, DP_GENL_A_MC_GROUP, dp_mc_group(dp)); + + genlmsg_end(ans_skb, data); + err = genlmsg_reply(ans_skb, info); + ans_skb = NULL; + } +err: +nla_put_failure: + kfree_skb(ans_skb); + rcu_read_unlock(); + return err; +} + +static struct genl_ops dp_genl_ops_query_dp = { + .cmd = DP_GENL_C_QUERY_DP, + .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ + .policy = dp_genl_policy, + .doit = dp_genl_query, + .dumpit = NULL, +}; + +static int dp_genl_add_del_port(struct sk_buff *skb, struct genl_info *info) +{ + struct datapath *dp; + struct net_device *port; + int err; + + if (!info->attrs[DP_GENL_A_PORTNAME] || + VERIFY_NUL_STRING(info->attrs[DP_GENL_A_PORTNAME])) + return -EINVAL; + + rtnl_lock(); + mutex_lock(&dp_mutex); + + /* Get datapath. */ + dp = lookup_dp(info); + if (IS_ERR(dp)) { + err = PTR_ERR(dp); + goto out_unlock; + } + + /* Get interface to add/remove. */ + port = dev_get_by_name(&init_net, + nla_data(info->attrs[DP_GENL_A_PORTNAME])); + if (!port) { + err = -ENOENT; + goto out_unlock; + } + + /* Execute operation. */ + if (info->genlhdr->cmd == DP_GENL_C_ADD_PORT) + err = add_switch_port(dp, port); + else { + if (port->br_port == NULL || port->br_port->dp != dp) { + err = -ENOENT; + goto out_put; + } + err = dp_del_switch_port(port->br_port); + } + +out_put: + dev_put(port); +out_unlock: + mutex_unlock(&dp_mutex); + rtnl_unlock(); + return err; +} + +static struct genl_ops dp_genl_ops_add_port = { + .cmd = DP_GENL_C_ADD_PORT, + .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ + .policy = dp_genl_policy, + .doit = dp_genl_add_del_port, + .dumpit = NULL, +}; + +static struct genl_ops dp_genl_ops_del_port = { + .cmd = DP_GENL_C_DEL_PORT, + .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ + .policy = dp_genl_policy, + .doit = dp_genl_add_del_port, + .dumpit = NULL, +}; + +static int dp_genl_openflow(struct sk_buff *skb, struct genl_info *info) +{ + struct nlattr *va = info->attrs[DP_GENL_A_OPENFLOW]; + struct datapath *dp; + struct ofp_header *oh; + struct sender sender; + int err; + + if (!info->attrs[DP_GENL_A_DP_IDX] || !va) + return -EINVAL; + + dp = dp_get_by_idx(nla_get_u32(info->attrs[DP_GENL_A_DP_IDX])); + if (!dp) + return -ENOENT; + + if (nla_len(va) < sizeof(struct ofp_header)) + return -EINVAL; + oh = nla_data(va); + + sender.xid = oh->xid; + sender.pid = info->snd_pid; + sender.seq = info->snd_seq; + + mutex_lock(&dp_mutex); + err = fwd_control_input(dp->chain, &sender, + nla_data(va), nla_len(va)); + mutex_unlock(&dp_mutex); + return err; +} + +static struct nla_policy dp_genl_openflow_policy[DP_GENL_A_MAX + 1] = { + [DP_GENL_A_DP_IDX] = { .type = NLA_U32 }, +}; + +static int desc_stats_dump(struct datapath *dp, void *state, + void *body, int *body_len) +{ + struct ofp_desc_stats *ods = body; + int n_bytes = sizeof *ods; + + if (n_bytes > *body_len) { + return -ENOBUFS; + } + *body_len = n_bytes; + + strncpy(ods->mfr_desc, mfr_desc, sizeof ods->mfr_desc); + strncpy(ods->hw_desc, hw_desc, sizeof ods->hw_desc); + strncpy(ods->sw_desc, sw_desc, sizeof ods->sw_desc); + strncpy(ods->dp_desc, dp->dp_desc, sizeof ods->dp_desc); + strncpy(ods->serial_num, serial_num, sizeof ods->serial_num); + + return 0; +} + +struct flow_stats_state { + int table_idx; + struct sw_table_position position; + const struct ofp_flow_stats_request *rq; + + void *body; + int bytes_used, bytes_allocated; +}; + +#define EMERG_TABLE_ID_FOR_STATS 0xfe + +static int flow_stats_init(struct datapath *dp, const void *body, int body_len, + void **state) +{ + const struct ofp_flow_stats_request *fsr = body; + struct flow_stats_state *s = kmalloc(sizeof *s, GFP_ATOMIC); + if (!s) + return -ENOMEM; + s->table_idx = fsr->table_id == 0xff ? 0 : fsr->table_id; + memset(&s->position, 0, sizeof s->position); + s->rq = fsr; + *state = s; + return 0; +} + +static int flow_stats_dump_callback(struct sw_flow *flow, void *private) +{ + struct sw_flow_actions *sf_acts = rcu_dereference(flow->sf_acts); + struct flow_stats_state *s = private; + struct ofp_flow_stats *ofs; + int length; + uint64_t duration; + + length = sizeof *ofs + sf_acts->actions_len; + if (length + s->bytes_used > s->bytes_allocated) + return 1; + + ofs = s->body + s->bytes_used; + ofs->length = htons(length); + ofs->table_id = s->table_idx; + ofs->pad = 0; + ofs->match.wildcards = htonl(flow->key.wildcards); + ofs->match.in_port = flow->key.in_port; + memcpy(ofs->match.dl_src, flow->key.dl_src, ETH_ALEN); + memcpy(ofs->match.dl_dst, flow->key.dl_dst, ETH_ALEN); + ofs->match.dl_vlan = flow->key.dl_vlan; + ofs->match.dl_type = flow->key.dl_type; + ofs->match.nw_tos = flow->key.nw_tos; + ofs->match.nw_proto = flow->key.nw_proto; + ofs->match.nw_src = flow->key.nw_src; + ofs->match.nw_dst = flow->key.nw_dst; + ofs->match.dl_vlan_pcp = flow->key.dl_vlan_pcp; + ofs->match.tp_src = flow->key.tp_src; + ofs->match.tp_dst = flow->key.tp_dst; + + /* The kernel doesn't support 64-bit division, so use the 'do_div' + * macro instead. The first argument is replaced with the quotient, + * while the remainder is the return value. */ + duration = get_jiffies_64() - flow->created; + do_div(duration, HZ); + ofs->duration_sec = htonl(jiffies_64_to_secs(duration)); + ofs->duration_nsec = htonl(jiffies_64_to_nsecs(duration)); + + ofs->priority = htons(flow->priority); + ofs->idle_timeout = htons(flow->idle_timeout); + ofs->hard_timeout = htons(flow->hard_timeout); + memset(&ofs->pad2, 0, sizeof ofs->pad2); + ofs->packet_count = cpu_to_be64(flow->packet_count); + ofs->byte_count = cpu_to_be64(flow->byte_count); + memcpy(ofs->actions, sf_acts->actions, sf_acts->actions_len); + + s->bytes_used += length; + return 0; +} + +static int flow_stats_dump(struct datapath *dp, void *state, + void *body, int *body_len) +{ + struct flow_stats_state *s = state; + struct sw_flow_key match_key; + int error = 0; + + s->bytes_used = 0; + s->bytes_allocated = *body_len; + s->body = body; + + flow_extract_match(&match_key, &s->rq->match); + if (s->rq->table_id == EMERG_TABLE_ID_FOR_STATS) { + struct sw_table *table = dp->chain->emerg_table; + + error = table->iterate(table, &match_key, s->rq->out_port, + &s->position, flow_stats_dump_callback, + s); + } else { + while (s->table_idx < dp->chain->n_tables + && (s->rq->table_id == 0xff + || s->rq->table_id == s->table_idx)) { + struct sw_table *table = dp->chain->tables[s->table_idx]; + + error = table->iterate(table, &match_key, + s->rq->out_port, &s->position, + flow_stats_dump_callback, s); + if (error) + break; + + s->table_idx++; + memset(&s->position, 0, sizeof s->position); + } + } + *body_len = s->bytes_used; + + /* If error is 0, we're done. + * Otherwise, if some bytes were used, there are more flows to come. + * Otherwise, we were not able to fit even a single flow in the body, + * which indicates that we have a single flow with too many actions to + * fit. We won't ever make any progress at that rate, so give up. */ + return !error ? 0 : s->bytes_used ? 1 : -ENOMEM; +} + +static void flow_stats_done(void *state) +{ + kfree(state); +} + +static int aggregate_stats_init(struct datapath *dp, + const void *body, int body_len, + void **state) +{ + *state = (void *)body; + return 0; +} + +static int aggregate_stats_dump_callback(struct sw_flow *flow, void *private) +{ + struct ofp_aggregate_stats_reply *rpy = private; + rpy->packet_count += flow->packet_count; + rpy->byte_count += flow->byte_count; + rpy->flow_count++; + return 0; +} + +static int aggregate_stats_dump(struct datapath *dp, void *state, + void *body, int *body_len) +{ + struct ofp_aggregate_stats_request *rq = state; + struct ofp_aggregate_stats_reply *rpy; + struct sw_table_position position; + struct sw_flow_key match_key; + int table_idx; + int error = 0; + + if (*body_len < sizeof *rpy) + return -ENOBUFS; + rpy = body; + *body_len = sizeof *rpy; + + memset(rpy, 0, sizeof *rpy); + + flow_extract_match(&match_key, &rq->match); + table_idx = rq->table_id == 0xff ? 0 : rq->table_id; + memset(&position, 0, sizeof position); + + if (rq->table_id == EMERG_TABLE_ID_FOR_STATS) { + struct sw_table *table = dp->chain->emerg_table; + + error = table->iterate(table, &match_key, rq->out_port, + &position, + aggregate_stats_dump_callback, rpy); + if (error) + return error; + } else { + while (table_idx < dp->chain->n_tables + && (rq->table_id == 0xff || rq->table_id == table_idx)) { + struct sw_table *table = dp->chain->tables[table_idx]; + + error = table->iterate(table, &match_key, rq->out_port, + &position, + aggregate_stats_dump_callback, + rpy); + if (error) + return error; + + table_idx++; + memset(&position, 0, sizeof position); + } + } + + rpy->packet_count = cpu_to_be64(rpy->packet_count); + rpy->byte_count = cpu_to_be64(rpy->byte_count); + rpy->flow_count = htonl(rpy->flow_count); + return 0; +} + +static int table_stats_dump(struct datapath *dp, void *state, + void *body, int *body_len) +{ + struct ofp_table_stats *ots; + int n_bytes = dp->chain->n_tables * sizeof *ots; + int i; + if (n_bytes > *body_len) + return -ENOBUFS; + *body_len = n_bytes; + for (i = 0, ots = body; i < dp->chain->n_tables; i++, ots++) { + struct sw_table_stats stats; + dp->chain->tables[i]->stats(dp->chain->tables[i], &stats); + strncpy(ots->name, stats.name, sizeof ots->name); + ots->table_id = i; + ots->wildcards = htonl(stats.wildcards); + memset(ots->pad, 0, sizeof ots->pad); + ots->max_entries = htonl(stats.max_flows); + ots->active_count = htonl(stats.n_flows); + ots->lookup_count = cpu_to_be64(stats.n_lookup); + ots->matched_count = cpu_to_be64(stats.n_matched); + } + return 0; +} + +struct port_stats_state { + int start_port; /* port to start dumping from */ + int port_no; /* from ofp_port_stats_request */ +}; + +static int port_stats_init(struct datapath *dp, const void *body, int body_len, + void **state) +{ + struct port_stats_state *s = kmalloc(sizeof *s, GFP_ATOMIC); + struct ofp_port_stats_request *psr + = (struct ofp_port_stats_request *)body; + + if (!s) + return -ENOMEM; + s->start_port = 1; + s->port_no = ntohs(psr->port_no); + *state = s; + return 0; +} + +static void +dump_port_stats(struct ofp_port_stats *ops, struct net_bridge_port *p) +{ + struct net_device_stats *stats; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) + stats = p->dev->netdev_ops->ndo_get_stats(p->dev); +#else + stats = p->dev->get_stats(p->dev); +#endif + ops->port_no = htons(p->port_no); + memset(ops->pad, 0, sizeof ops->pad); + ops->rx_packets = cpu_to_be64(stats->rx_packets); + ops->tx_packets = cpu_to_be64(stats->tx_packets); + ops->rx_bytes = cpu_to_be64(stats->rx_bytes); + ops->tx_bytes = cpu_to_be64(stats->tx_bytes); + ops->rx_dropped = cpu_to_be64(stats->rx_dropped); + ops->tx_dropped = cpu_to_be64(stats->tx_dropped); + ops->rx_errors = cpu_to_be64(stats->rx_errors); + ops->tx_errors = cpu_to_be64(stats->tx_errors); + ops->rx_frame_err = cpu_to_be64(stats->rx_frame_errors); + ops->rx_over_err = cpu_to_be64(stats->rx_over_errors); + ops->rx_crc_err = cpu_to_be64(stats->rx_crc_errors); + ops->collisions = cpu_to_be64(stats->collisions); +} + +static struct net_bridge_port * +lookup_port(struct datapath *dp, uint16_t port_no) +{ + return (port_no < DP_MAX_PORTS ? dp->ports[port_no] + : port_no == OFPP_LOCAL ? dp->local_port + : NULL); +} + + +static int port_stats_dump(struct datapath *dp, void *state, + void *body, int *body_len) +{ + struct port_stats_state *s = state; + struct net_bridge_port *p = NULL; + struct ofp_port_stats *ops = NULL; + int n_ports = 0; + int max_ports = 0; + int i = 0; + + max_ports = *body_len / sizeof *ops; + if (!max_ports) + return -ENOMEM; + ops = body; + + if (s->port_no == OFPP_NONE) { + for (i = s->start_port; i < DP_MAX_PORTS && n_ports < max_ports; + i++) { + p = dp->ports[i]; + if (!p) + continue; + dump_port_stats(ops, p); + n_ports++; + ops++; + } + s->start_port = i; + if (dp->local_port) { + dump_port_stats(ops, dp->local_port); + n_ports++; + ops++; + s->start_port = OFPP_LOCAL + 1; /* == OFPP_NONE, > DP_MAX_PORTS */ + } + } else { + p = lookup_port(dp, s->port_no); + if (p) { + dump_port_stats(ops, p); + n_ports++; + ops++; + } + } + + *body_len = n_ports * sizeof *ops; + return n_ports >= max_ports; +} + +static void port_stats_done(void *state) +{ + kfree(state); +} + +/* + * We don't define any vendor_stats_state, we let the actual + * vendor implementation do that. + * The only requirement is that the first member of that object + * should be the vendor id. + * Jean II + * + * Basically, it would look like : + * struct acme_stats_state { + * uint32_t vendor; // ACME_VENDOR_ID. + * <...> // Other stuff. + * }; + */ +static int vendor_stats_init(struct datapath *dp, const void *body, + int body_len, void **state) +{ + /* min_body was checked, this is safe */ + const uint32_t vendor = ntohl(*((uint32_t *)body)); + int err; + + switch (vendor) { + default: + err = -EINVAL; + } + + return err; +} + +static int vendor_stats_dump(struct datapath *dp, void *state, void *body, + int *body_len) +{ + const uint32_t vendor = *((uint32_t *)state); + int newbuf; + + switch (vendor) { + default: + /* Should never happen */ + newbuf = 0; + } + + return newbuf; +} + +static void vendor_stats_done(void *state) +{ + const uint32_t vendor = *((uint32_t *)state); + + switch (vendor) { + default: + /* Should never happen */ + kfree(state); + } + + return; +} + +struct stats_type { + /* Minimum and maximum acceptable number of bytes in body member of + * struct ofp_stats_request. */ + size_t min_body, max_body; + + /* Prepares to dump some kind of statistics on 'dp'. 'body' and + * 'body_len' are the 'body' member of the struct ofp_stats_request. + * Returns zero if successful, otherwise a negative error code. + * May initialize '*state' to state information. May be null if no + * initialization is required.*/ + int (*init)(struct datapath *dp, const void *body, int body_len, + void **state); + + /* Dumps statistics for 'dp' into the '*body_len' bytes at 'body', and + * modifies '*body_len' to reflect the number of bytes actually used. + * ('body' will be transmitted as the 'body' member of struct + * ofp_stats_reply.) */ + int (*dump)(struct datapath *dp, void *state, + void *body, int *body_len); + + /* Cleans any state created by the init or dump functions. May be null + * if no cleanup is required. */ + void (*done)(void *state); +}; + +static const struct stats_type stats[] = { + [OFPST_DESC] = { + 0, + 0, + NULL, + desc_stats_dump, + NULL + }, + [OFPST_FLOW] = { + sizeof(struct ofp_flow_stats_request), + sizeof(struct ofp_flow_stats_request), + flow_stats_init, + flow_stats_dump, + flow_stats_done + }, + [OFPST_AGGREGATE] = { + sizeof(struct ofp_aggregate_stats_request), + sizeof(struct ofp_aggregate_stats_request), + aggregate_stats_init, + aggregate_stats_dump, + NULL + }, + [OFPST_TABLE] = { + 0, + 0, + NULL, + table_stats_dump, + NULL + }, + [OFPST_PORT] = { + sizeof(struct ofp_port_stats_request), + sizeof(struct ofp_port_stats_request), + port_stats_init, + port_stats_dump, + port_stats_done + }, +}; + +/* For OFPST_VENDOR... Jean II */ +static const struct stats_type stats_vendor = { + 8, /* vendor + subtype */ + 32, /* whatever */ + vendor_stats_init, + vendor_stats_dump, + vendor_stats_done +}; + +static int +dp_genl_openflow_dumpit(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct datapath *dp; + struct sender sender; + const struct stats_type *s; + struct ofp_stats_reply *osr; + int dp_idx; + int max_openflow_len, body_len; + void *body; + int err; + + /* Set up the cleanup function for this dump. Linux 2.6.20 and later + * support setting up cleanup functions via the .doneit member of + * struct genl_ops. This kluge supports earlier versions also. */ + cb->done = dp_genl_openflow_done; + + sender.pid = NETLINK_CB(cb->skb).pid; + sender.seq = cb->nlh->nlmsg_seq; + if (!cb->args[0]) { + struct nlattr *attrs[DP_GENL_A_MAX + 1]; + struct ofp_stats_request *rq; + struct nlattr *va; + size_t len, body_len; + int type; + + err = nlmsg_parse(cb->nlh, GENL_HDRLEN, attrs, DP_GENL_A_MAX, + dp_genl_openflow_policy); + if (err < 0) + return err; + + if (!attrs[DP_GENL_A_DP_IDX]) + return -EINVAL; + dp_idx = nla_get_u16(attrs[DP_GENL_A_DP_IDX]); + dp = dp_get_by_idx(dp_idx); + if (!dp) + return -ENOENT; + + va = attrs[DP_GENL_A_OPENFLOW]; + len = nla_len(va); + if (!va || len < sizeof *rq) + return -EINVAL; + + rq = nla_data(va); + sender.xid = rq->header.xid; + type = ntohs(rq->type); + if (rq->header.version != OFP_VERSION) { + dp_send_error_msg(dp, &sender, OFPET_BAD_REQUEST, + OFPBRC_BAD_VERSION, rq, len); + return -EINVAL; + } + if (rq->header.type != OFPT_STATS_REQUEST + || ntohs(rq->header.length) != len) + return -EINVAL; + + if (type == OFPST_VENDOR) { + /* Vendor is not in the array, take care of it */ + s = &stats_vendor; + } else { + if (type >= ARRAY_SIZE(stats) || !stats[type].dump) { + dp_send_error_msg(dp, &sender, + OFPET_BAD_REQUEST, + OFPBRC_BAD_STAT, rq, len); + return -EINVAL; + } + s = &stats[type]; + } + body_len = len - offsetof(struct ofp_stats_request, body); + if (body_len < s->min_body || body_len > s->max_body) + return -EINVAL; + + cb->args[0] = 1; + cb->args[1] = dp_idx; + cb->args[2] = type; + cb->args[3] = rq->header.xid; + if (s->init) { + void *state; + err = s->init(dp, rq->body, body_len, &state); + if (err) + return err; + cb->args[4] = (long) state; + } + } else if (cb->args[0] == 1) { + sender.xid = cb->args[3]; + dp_idx = cb->args[1]; + if (cb->args[2] == OFPST_VENDOR) { + /* Vendor is not in the array, take care of it */ + s = &stats_vendor; + } else { + s = &stats[cb->args[2]]; + } + + dp = dp_get_by_idx(dp_idx); + if (!dp) + return -ENOENT; + } else { + return 0; + } + + osr = put_openflow_headers(dp, skb, OFPT_STATS_REPLY, &sender, + &max_openflow_len); + if (IS_ERR(osr)) + return PTR_ERR(osr); + osr->type = htons(cb->args[2]); + osr->flags = 0; + resize_openflow_skb(skb, &osr->header, max_openflow_len); + body = osr->body; + body_len = max_openflow_len - offsetof(struct ofp_stats_reply, body); + + err = s->dump(dp, (void *) cb->args[4], body, &body_len); + if (err >= 0) { + if (!err) + cb->args[0] = 2; + else + osr->flags = ntohs(OFPSF_REPLY_MORE); + resize_openflow_skb(skb, &osr->header, + (offsetof(struct ofp_stats_reply, body) + + body_len)); + err = skb->len; + } + + return err; +} + +static int +dp_genl_openflow_done(struct netlink_callback *cb) +{ + if (cb->args[0]) { + const struct stats_type *s; + if (cb->args[2] == OFPST_VENDOR) { + /* Vendor is not in the array, take care of it */ + s = &stats_vendor; + } else { + s = &stats[cb->args[2]]; + } + if (s->done) + s->done((void *) cb->args[4]); + } + return 0; +} + +static struct genl_ops dp_genl_ops_openflow = { + .cmd = DP_GENL_C_OPENFLOW, + .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ + .policy = dp_genl_openflow_policy, + .doit = dp_genl_openflow, + .dumpit = dp_genl_openflow_dumpit, +}; + +static struct genl_ops *dp_genl_all_ops[] = { + /* Keep this operation first. Generic Netlink dispatching + * looks up operations with linear search, so we want it at the + * front. */ + &dp_genl_ops_openflow, + + &dp_genl_ops_add_dp, + &dp_genl_ops_del_dp, + &dp_genl_ops_query_dp, + &dp_genl_ops_add_port, + &dp_genl_ops_del_port, +}; + +static int dp_init_netlink(void) +{ + int err; + int i; + + err = genl_register_family(&dp_genl_family); + if (err) + return err; + + for (i = 0; i < ARRAY_SIZE(dp_genl_all_ops); i++) { + err = genl_register_ops(&dp_genl_family, dp_genl_all_ops[i]); + if (err) + goto err_unregister; + } + + for (i = 0; i < N_MC_GROUPS; i++) { + snprintf(mc_groups[i].name, sizeof mc_groups[i].name, + "openflow%d", i); + err = genl_register_mc_group(&dp_genl_family, &mc_groups[i]); + if (err < 0) + goto err_unregister; + } + + return 0; + +err_unregister: + genl_unregister_family(&dp_genl_family); + return err; +} + +static void dp_uninit_netlink(void) +{ + genl_unregister_family(&dp_genl_family); +} + +/* Set the description strings if appropriate values are available from + * the DMI. */ +static void set_desc(void) +{ + const char *uuid = dmi_get_system_info(DMI_PRODUCT_UUID); + const char *vendor = dmi_get_system_info(DMI_SYS_VENDOR); + const char *name = dmi_get_system_info(DMI_PRODUCT_NAME); + const char *version = dmi_get_system_info(DMI_PRODUCT_VERSION); + const char *serial = dmi_get_system_info(DMI_PRODUCT_SERIAL); + const char *uptr; + + if (!uuid || *uuid == '\0' || strlen(uuid) != 36) + return; + + /* We are only interested version 1 UUIDs, since the last six bytes + * are an IEEE 802 MAC address. */ + if (uuid[14] != '1') + return; + + /* Only set if the UUID is from Nicira. */ + uptr = uuid + 24; + if (strncmp(uptr, NICIRA_OUI_STR, strlen(NICIRA_OUI_STR))) + return; + + if (vendor) + strlcpy(mfr_desc, vendor, sizeof(mfr_desc)); + if (name || version) + snprintf(hw_desc, sizeof(hw_desc), "%s %s", + name ? name : "", + version ? version : ""); + if (serial) + strlcpy(serial_num, serial, sizeof(serial_num)); +} + +static int __init dp_init(void) +{ + int err; + + printk("OpenFlow %s, built "__DATE__" "__TIME__", " + "protocol 0x%02x\n", VERSION BUILDNR, OFP_VERSION); + + err = flow_init(); + if (err) + goto error; + + err = register_netdevice_notifier(&dp_device_notifier); + if (err) + goto error_flow_exit; + + err = dp_init_netlink(); + if (err) + goto error_unreg_notifier; + + dp_ioctl_hook = NULL; + dp_add_dp_hook = NULL; + dp_del_dp_hook = NULL; + dp_add_if_hook = NULL; + dp_del_if_hook = NULL; + + /* Check if better descriptions of the switch are available than the + * defaults. */ + set_desc(); + + /* Hook into callback used by the bridge to intercept packets. + * Parasites we are. */ + if (br_handle_frame_hook) + printk("openflow: hijacking bridge hook\n"); + br_handle_frame_hook = dp_frame_hook; + + return 0; + +error_unreg_notifier: + unregister_netdevice_notifier(&dp_device_notifier); +error_flow_exit: + flow_exit(); +error: + printk(KERN_EMERG "openflow: failed to install!"); + return err; +} + +static void dp_cleanup(void) +{ + fwd_exit(); + dp_uninit_netlink(); + unregister_netdevice_notifier(&dp_device_notifier); + flow_exit(); + br_handle_frame_hook = NULL; +} + +module_init(dp_init); +module_exit(dp_cleanup); + +MODULE_DESCRIPTION("OpenFlow Switching Datapath"); +MODULE_AUTHOR("Copyright (c) 2007, 2008 The Board of Trustees of The Leland Stanford Junior University"); +MODULE_LICENSE("GPL"); diff --git a/openflow/datapath/datapath.h b/openflow/datapath/datapath.h new file mode 100644 index 00000000..79ae0b78 --- /dev/null +++ b/openflow/datapath/datapath.h @@ -0,0 +1,114 @@ +/* Interface exported by OpenFlow module. */ + +#ifndef DATAPATH_H +#define DATAPATH_H 1 + +#include +#include +#include +#include +#include +#include +#include "openflow/openflow.h" +#include "openflow/nicira-ext.h" +#include "flow.h" + + +#define NL_FLOWS_PER_MESSAGE 100 + +/* Capabilities supported by this implementation. */ +#define OFP_SUPPORTED_CAPABILITIES ( OFPC_FLOW_STATS \ + | OFPC_TABLE_STATS \ + | OFPC_PORT_STATS ) + +/* Actions supported by this implementation. */ +#define OFP_SUPPORTED_ACTIONS ( (1 << OFPAT_OUTPUT) \ + | (1 << OFPAT_SET_VLAN_VID) \ + | (1 << OFPAT_SET_VLAN_PCP) \ + | (1 << OFPAT_STRIP_VLAN) \ + | (1 << OFPAT_SET_DL_SRC) \ + | (1 << OFPAT_SET_DL_DST) \ + | (1 << OFPAT_SET_NW_SRC) \ + | (1 << OFPAT_SET_NW_DST) \ + | (1 << OFPAT_SET_TP_SRC) \ + | (1 << OFPAT_SET_TP_DST) ) + +struct sk_buff; + +#define DP_MAX_PORTS 255 + +struct datapath { + int dp_idx; + + struct timer_list timer; /* Expiration timer. */ + struct sw_chain *chain; /* Forwarding rules. */ + struct task_struct *dp_task; /* Kernel thread for maintenance. */ + + /* Data related to the "of" device of this datapath */ + struct net_device *netdev; + char dp_desc[DESC_STR_LEN]; /* human readible comment to ID this DP */ + + /* Configuration set from controller */ + uint16_t flags; + uint16_t miss_send_len; + + struct kobject ifobj; + + /* Switch ports. */ + struct net_bridge_port *ports[DP_MAX_PORTS]; + struct net_bridge_port *local_port; /* OFPP_LOCAL port. */ + struct list_head port_list; /* All ports, including local_port. */ +}; + +/* Information necessary to reply to the sender of an OpenFlow message. */ +struct sender { + uint32_t xid; /* OpenFlow transaction ID of request. */ + uint32_t pid; /* Netlink process ID of sending socket. */ + uint32_t seq; /* Netlink sequence ID of request. */ +}; + +struct net_bridge_port { + u16 port_no; + u32 config; /* Some subset of OFPPC_* flags. */ + u32 state; /* Some subset of OFPPS_* flags. */ + spinlock_t lock; + struct datapath *dp; + struct net_device *dev; + struct kobject kobj; + struct list_head node; /* Element in datapath.ports. */ +}; + +extern struct mutex dp_mutex; +extern struct notifier_block dp_device_notifier; +extern int (*dp_ioctl_hook)(struct net_device *dev, struct ifreq *rq, int cmd); +extern int (*dp_add_dp_hook)(struct datapath *dp); +extern int (*dp_del_dp_hook)(struct datapath *dp); +extern int (*dp_add_if_hook)(struct net_bridge_port *p); +extern int (*dp_del_if_hook)(struct net_bridge_port *p); + +int dp_del_switch_port(struct net_bridge_port *); +int dp_xmit_skb(struct sk_buff *skb); +int dp_output_port(struct datapath *, struct sk_buff *, int out_port, + int ignore_no_fwd); +int dp_output_control(struct datapath *, struct sk_buff *, size_t, int); +void dp_set_origin(struct datapath *, uint16_t, struct sk_buff *); +int dp_send_features_reply(struct datapath *, const struct sender *); +int dp_send_config_reply(struct datapath *, const struct sender *); +int dp_send_port_status(struct net_bridge_port *p, uint8_t status); +int dp_send_flow_end(struct datapath *, struct sw_flow *, + enum ofp_flow_removed_reason); +int dp_send_error_msg(struct datapath *, const struct sender *, + uint16_t, uint16_t, const void *, size_t); +int dp_update_port_flags(struct datapath *dp, const struct ofp_port_mod *opm); +int dp_send_echo_reply(struct datapath *, const struct sender *, + const struct ofp_header *); +int dp_send_hello(struct datapath *, const struct sender *, + const struct ofp_header *); +int dp_send_barrier_reply(struct datapath *, const struct sender *, + const struct ofp_header *); + +/* Should hold at least RCU read lock when calling */ +struct datapath *dp_get_by_idx(int dp_idx); +struct datapath *dp_get_by_name(const char *dp_name); + +#endif /* datapath.h */ diff --git a/openflow/datapath/dp_act.c b/openflow/datapath/dp_act.c new file mode 100644 index 00000000..7532c00c --- /dev/null +++ b/openflow/datapath/dp_act.c @@ -0,0 +1,543 @@ +/* + * Distributed under the terms of the GNU GPL version 2. + * Copyright (c) 2007, 2008, 2009 The Board of Trustees of The Leland + * Stanford Junior University + */ + +/* Functions for executing OpenFlow actions. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "forward.h" +#include "dp_act.h" +#include "openflow/nicira-ext.h" +#include "flow.h" + + +static uint16_t +validate_output(struct datapath *dp, const struct sw_flow_key *key, + const struct ofp_action_header *ah) +{ + struct ofp_action_output *oa = (struct ofp_action_output *)ah; + + if (oa->port == htons(OFPP_NONE) || + (!(key->wildcards & OFPFW_IN_PORT) && oa->port == key->in_port)) + return OFPBAC_BAD_OUT_PORT; + + return ACT_VALIDATION_OK; +} + +static int +do_output(struct datapath *dp, struct sk_buff *skb, size_t max_len, + int out_port, int ignore_no_fwd) +{ + if (!skb) + return -ENOMEM; + return (likely(out_port != OFPP_CONTROLLER) + ? dp_output_port(dp, skb, out_port, ignore_no_fwd) + : dp_output_control(dp, skb, max_len, OFPR_ACTION)); +} + + +static struct sk_buff * +vlan_pull_tag(struct sk_buff *skb) +{ + struct vlan_ethhdr *vh = vlan_eth_hdr(skb); + struct ethhdr *eh; + + + /* Verify we were given a vlan packet */ + if (vh->h_vlan_proto != htons(ETH_P_8021Q)) + return skb; + + memmove(skb->data + VLAN_HLEN, skb->data, 2 * VLAN_ETH_ALEN); + + eh = (struct ethhdr *)skb_pull(skb, VLAN_HLEN); + + skb->protocol = eh->h_proto; + skb->mac_header += VLAN_HLEN; + + return skb; +} + + +static struct sk_buff * +modify_vlan_tci(struct sk_buff *skb, struct sw_flow_key *key, + uint16_t tci, uint16_t mask) +{ + struct vlan_ethhdr *vh = vlan_eth_hdr(skb); + + if (key->dl_vlan != htons(OFP_VLAN_NONE)) { + /* Modify vlan id, but maintain other TCI values */ + vh->h_vlan_TCI = (vh->h_vlan_TCI & ~(htons(mask))) | htons(tci); + } else { + /* Add vlan header */ + + /* xxx The vlan_put_tag function, doesn't seem to work + * xxx reliably when it attempts to use the hardware-accelerated + * xxx version. We'll directly use the software version + * xxx until the problem can be diagnosed. + */ + skb = __vlan_put_tag(skb, tci); + vh = vlan_eth_hdr(skb); + } + key->dl_vlan = vh->h_vlan_TCI & htons(VLAN_VID_MASK); + key->dl_vlan_pcp = (uint8_t)((ntohs(vh->h_vlan_TCI) >> VLAN_PCP_SHIFT) + & VLAN_PCP_BITMASK); + + return skb; +} + +static struct sk_buff * +set_vlan_vid(struct sk_buff *skb, struct sw_flow_key *key, + const struct ofp_action_header *ah) +{ + struct ofp_action_vlan_vid *va = (struct ofp_action_vlan_vid *)ah; + uint16_t tci = ntohs(va->vlan_vid); + + return modify_vlan_tci(skb, key, tci, VLAN_VID_MASK); +} + +/* Mask for the priority bits in a vlan header. The kernel doesn't + * define this like it does for VID. */ +#define VLAN_PCP_MASK 0xe000 + +static struct sk_buff * +set_vlan_pcp(struct sk_buff *skb, struct sw_flow_key *key, + const struct ofp_action_header *ah) +{ + struct ofp_action_vlan_pcp *va = (struct ofp_action_vlan_pcp *)ah; + uint16_t tci = (uint16_t)va->vlan_pcp << 13; + + return modify_vlan_tci(skb, key, tci, VLAN_PCP_MASK); +} + +static struct sk_buff * +strip_vlan(struct sk_buff *skb, struct sw_flow_key *key, + const struct ofp_action_header *ah) +{ + vlan_pull_tag(skb); + key->dl_vlan = htons(OFP_VLAN_NONE); + + return skb; +} + +static struct sk_buff * +set_dl_addr(struct sk_buff *skb, struct sw_flow_key *key, + const struct ofp_action_header *ah) +{ + struct ofp_action_dl_addr *da = (struct ofp_action_dl_addr *)ah; + struct ethhdr *eh = eth_hdr(skb); + + if (da->type == htons(OFPAT_SET_DL_SRC)) + memcpy(eh->h_source, da->dl_addr, sizeof eh->h_source); + else + memcpy(eh->h_dest, da->dl_addr, sizeof eh->h_dest); + + return skb; +} + +/* Updates 'sum', which is a field in 'skb''s data, given that a 4-byte field + * covered by the sum has been changed from 'from' to 'to'. If set, + * 'pseudohdr' indicates that the field is in the TCP or UDP pseudo-header. + * Based on nf_proto_csum_replace4. */ +static void update_csum(__sum16 *sum, struct sk_buff *skb, + __be32 from, __be32 to, int pseudohdr) +{ + __be32 diff[] = { ~from, to }; + if (skb->ip_summed != CHECKSUM_PARTIAL) { + *sum = csum_fold(csum_partial((char *)diff, sizeof(diff), + ~csum_unfold(*sum))); + if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr) + skb->csum = ~csum_partial((char *)diff, sizeof(diff), + ~skb->csum); + } else if (pseudohdr) + *sum = ~csum_fold(csum_partial((char *)diff, sizeof(diff), + csum_unfold(*sum))); +} + +static struct sk_buff * +set_nw_addr(struct sk_buff *skb, struct sw_flow_key *key, + const struct ofp_action_header *ah) +{ + struct ofp_action_nw_addr *na = (struct ofp_action_nw_addr *)ah; + uint16_t eth_proto = ntohs(key->dl_type); + + if (eth_proto == ETH_P_IP) { + struct iphdr *nh = ip_hdr(skb); + uint32_t new, *field; + + new = na->nw_addr; + + if (ah->type == htons(OFPAT_SET_NW_SRC)) + field = &nh->saddr; + else + field = &nh->daddr; + + if (key->nw_proto == IPPROTO_TCP) { + struct tcphdr *th = tcp_hdr(skb); + update_csum(&th->check, skb, *field, new, 1); + } else if (key->nw_proto == IPPROTO_UDP) { + struct udphdr *th = udp_hdr(skb); + update_csum(&th->check, skb, *field, new, 1); + } + update_csum(&nh->check, skb, *field, new, 0); + *field = new; + } + + return skb; +} + +static struct sk_buff * +set_nw_tos(struct sk_buff *skb, struct sw_flow_key *key, + const struct ofp_action_header *ah) +{ + struct ofp_action_nw_tos *nt = (struct ofp_action_nw_tos *)ah; + uint16_t eth_proto = ntohs(key->dl_type); + + if (eth_proto == ETH_P_IP) { + struct iphdr *nh = ip_hdr(skb); + uint8_t new, *field; + + /* JeanII : Set only 6 bits, don't clobber ECN */ + new = (nt->nw_tos & 0xFC) | (nh->tos & 0x03); + + /* Get address of field */ + field = &nh->tos; + /* jklee : ip tos field is not included in TCP pseudo header. + * Need magic as update_csum() don't work with 8 bits. */ + update_csum(&nh->check, skb, htons((uint16_t)*field), + htons((uint16_t)new), 0); + + /* Update in packet */ + *field = new; + } + + return skb; +} + +static struct sk_buff * +set_tp_port(struct sk_buff *skb, struct sw_flow_key *key, + const struct ofp_action_header *ah) +{ + struct ofp_action_tp_port *ta = (struct ofp_action_tp_port *)ah; + uint16_t eth_proto = ntohs(key->dl_type); + + if (eth_proto == ETH_P_IP) { + uint16_t new, *field; + + new = ta->tp_port; + + if (key->nw_proto == IPPROTO_TCP) { + struct tcphdr *th = tcp_hdr(skb); + + if (ah->type == htons(OFPAT_SET_TP_SRC)) + field = &th->source; + else + field = &th->dest; + + update_csum(&th->check, skb, *field, new, 1); + *field = new; + } else if (key->nw_proto == IPPROTO_UDP) { + struct udphdr *th = udp_hdr(skb); + + if (ah->type == htons(OFPAT_SET_TP_SRC)) + field = &th->source; + else + field = &th->dest; + + update_csum(&th->check, skb, *field, new, 1); + *field = new; + } + } + + return skb; +} + +struct openflow_action { + size_t min_size; + size_t max_size; + uint16_t (*validate)(struct datapath *dp, + const struct sw_flow_key *key, + const struct ofp_action_header *ah); + struct sk_buff *(*execute)(struct sk_buff *skb, + struct sw_flow_key *key, + const struct ofp_action_header *ah); +}; + +static const struct openflow_action of_actions[] = { + [OFPAT_OUTPUT] = { + sizeof(struct ofp_action_output), + sizeof(struct ofp_action_output), + validate_output, + NULL /* This is optimized into execute_actions */ + }, + [OFPAT_SET_VLAN_VID] = { + sizeof(struct ofp_action_vlan_vid), + sizeof(struct ofp_action_vlan_vid), + NULL, + set_vlan_vid + }, + [OFPAT_SET_VLAN_PCP] = { + sizeof(struct ofp_action_vlan_pcp), + sizeof(struct ofp_action_vlan_pcp), + NULL, + set_vlan_pcp + }, + [OFPAT_STRIP_VLAN] = { + sizeof(struct ofp_action_header), + sizeof(struct ofp_action_header), + NULL, + strip_vlan + }, + [OFPAT_SET_DL_SRC] = { + sizeof(struct ofp_action_dl_addr), + sizeof(struct ofp_action_dl_addr), + NULL, + set_dl_addr + }, + [OFPAT_SET_DL_DST] = { + sizeof(struct ofp_action_dl_addr), + sizeof(struct ofp_action_dl_addr), + NULL, + set_dl_addr + }, + [OFPAT_SET_NW_SRC] = { + sizeof(struct ofp_action_nw_addr), + sizeof(struct ofp_action_nw_addr), + NULL, + set_nw_addr + }, + [OFPAT_SET_NW_DST] = { + sizeof(struct ofp_action_nw_addr), + sizeof(struct ofp_action_nw_addr), + NULL, + set_nw_addr + }, + [OFPAT_SET_NW_TOS] = { + sizeof(struct ofp_action_nw_tos), + sizeof(struct ofp_action_nw_tos), + NULL, + set_nw_tos + }, + [OFPAT_SET_TP_SRC] = { + sizeof(struct ofp_action_tp_port), + sizeof(struct ofp_action_tp_port), + NULL, + set_tp_port + }, + [OFPAT_SET_TP_DST] = { + sizeof(struct ofp_action_tp_port), + sizeof(struct ofp_action_tp_port), + NULL, + set_tp_port + } + /* OFPAT_VENDOR is not here, since it would blow up the array size. */ +}; + +/* Validate built-in OpenFlow actions. Either returns ACT_VALIDATION_OK + * or an OFPET_BAD_ACTION error code. */ +static uint16_t +validate_ofpat(struct datapath *dp, const struct sw_flow_key *key, + const struct ofp_action_header *ah, uint16_t type, uint16_t len) +{ + uint16_t ret = ACT_VALIDATION_OK; + const struct openflow_action *act = &of_actions[type]; + + if ((len < act->min_size) || (len > act->max_size)) + return OFPBAC_BAD_LEN; + + if (act->validate) + ret = act->validate(dp, key, ah); + + return ret; +} + +/* Validate vendor-defined actions. Either returns ACT_VALIDATION_OK + * or an OFPET_BAD_ACTION error code. */ +static uint16_t +validate_vendor(struct datapath *dp, const struct sw_flow_key *key, + const struct ofp_action_header *ah, uint16_t len) +{ + struct ofp_action_vendor_header *avh; + int ret = ACT_VALIDATION_OK; + + if (len < sizeof(struct ofp_action_vendor_header)) + return OFPBAC_BAD_LEN; + + avh = (struct ofp_action_vendor_header *)ah; + + switch(ntohl(avh->vendor)) { + default: + return OFPBAC_BAD_VENDOR; + } + + return ret; +} + +/* Validates a list of actions. If a problem is found, a code for the + * OFPET_BAD_ACTION error type is returned. If the action list validates, + * ACT_VALIDATION_OK is returned. */ +uint16_t +validate_actions(struct datapath *dp, const struct sw_flow_key *key, + const struct ofp_action_header *actions, size_t actions_len) +{ + uint8_t *p = (uint8_t *)actions; + int err; + + while (actions_len >= sizeof(struct ofp_action_header)) { + struct ofp_action_header *ah = (struct ofp_action_header *)p; + size_t len = ntohs(ah->len); + uint16_t type; + + /* Make there's enough remaining data for the specified length + * and that the action length is a multiple of 64 bits. */ + if ((actions_len < len) || (len % 8) != 0) + return OFPBAC_BAD_LEN; + + type = ntohs(ah->type); + if (type < ARRAY_SIZE(of_actions)) { + err = validate_ofpat(dp, key, ah, type, len); + if (err != ACT_VALIDATION_OK) + return err; + } else if (type == OFPAT_VENDOR) { + err = validate_vendor(dp, key, ah, len); + if (err != ACT_VALIDATION_OK) + return err; + } else + return OFPBAC_BAD_TYPE; + + p += len; + actions_len -= len; + } + + /* Check if there's any trailing garbage. */ + if (actions_len != 0) + return OFPBAC_BAD_LEN; + + return ACT_VALIDATION_OK; +} + +/* Execute a built-in OpenFlow action against 'skb'. */ +static struct sk_buff * +execute_ofpat(struct sk_buff *skb, struct sw_flow_key *key, + const struct ofp_action_header *ah, uint16_t type) +{ + const struct openflow_action *act = &of_actions[type]; + if (act->execute && make_writable(&skb)) + skb = act->execute(skb, key, ah); + return skb; +} + +/* Execute a vendor-defined action against 'skb'. */ +static struct sk_buff * +execute_vendor(struct sk_buff *skb, const struct sw_flow_key *key, + const struct ofp_action_header *ah) +{ + struct ofp_action_vendor_header *avh + = (struct ofp_action_vendor_header *)ah; + struct datapath *dp = skb->dev->br_port->dp; + + /* NB: If changes need to be made to the packet, a call should be + * made to make_writable or its equivalent first. */ + + switch(ntohl(avh->vendor)) { + default: + /* This should not be possible due to prior validation. */ + if (net_ratelimit()) + printk(KERN_WARNING "%s: attempt to execute action " + "with unknown vendor: %#x\n", + dp->netdev->name, ntohl(avh->vendor)); + break; + } + + return skb; +} + +/* Execute a list of actions against 'skb'. */ +void execute_actions(struct datapath *dp, struct sk_buff *skb, + struct sw_flow_key *key, + const struct ofp_action_header *actions, size_t actions_len, + int ignore_no_fwd) +{ + /* Every output action needs a separate clone of 'skb', but the common + * case is just a single output action, so that doing a clone and + * then freeing the original skbuff is wasteful. So the following code + * is slightly obscure just to avoid that. */ + int prev_port; + size_t max_len = UINT16_MAX; + uint8_t *p = (uint8_t *)actions; + + prev_port = -1; + + /* The action list was already validated, so we can be a bit looser + * in our sanity-checking. */ + while (actions_len > 0) { + struct ofp_action_header *ah = (struct ofp_action_header *)p; + size_t len = htons(ah->len); + + WARN_ON_ONCE(skb_shared(skb)); + if (prev_port != -1) { + do_output(dp, skb_clone(skb, GFP_ATOMIC), + max_len, prev_port, ignore_no_fwd); + prev_port = -1; + } + + if (likely(ah->type == htons(OFPAT_OUTPUT))) { + struct ofp_action_output *oa = (struct ofp_action_output *)p; + prev_port = ntohs(oa->port); + max_len = ntohs(oa->max_len); + } else { + uint16_t type = ntohs(ah->type); + + if (type < ARRAY_SIZE(of_actions)) + skb = execute_ofpat(skb, key, ah, type); + else if (type == OFPAT_VENDOR) + skb = execute_vendor(skb, key, ah); + + if (!skb) { + if (net_ratelimit()) + printk(KERN_WARNING "%s: " + "execute_actions lost skb\n", + dp->netdev->name); + return; + } + } + + p += len; + actions_len -= len; + } + if (prev_port != -1) + do_output(dp, skb, max_len, prev_port, ignore_no_fwd); + else + kfree_skb(skb); +} + +/* Utility functions. */ + +/* Makes '*pskb' writable, possibly copying it and setting '*pskb' to point to + * the copy. + * Returns 1 if successful, 0 on failure. */ +int +make_writable(struct sk_buff **pskb) +{ + struct sk_buff *skb = *pskb; + if (skb_shared(skb) || skb_cloned(skb)) { + struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC); + if (!nskb) + return 0; + kfree_skb(skb); + *pskb = nskb; + return 1; + } else { + unsigned int hdr_len = (skb_transport_offset(skb) + + sizeof(struct tcphdr)); + return pskb_may_pull(skb, min(hdr_len, skb->len)); + } +} diff --git a/openflow/datapath/dp_act.h b/openflow/datapath/dp_act.h new file mode 100644 index 00000000..d601eca0 --- /dev/null +++ b/openflow/datapath/dp_act.h @@ -0,0 +1,15 @@ +#ifndef DP_ACT_H +#define DP_ACT_H 1 + +#include "datapath.h" + +#define ACT_VALIDATION_OK ((uint16_t)-1) + +uint16_t validate_actions(struct datapath *, const struct sw_flow_key *, + const struct ofp_action_header *, size_t); +void execute_actions(struct datapath *, struct sk_buff *, + struct sw_flow_key *, const struct ofp_action_header *, + size_t action_len, int ignore_no_fwd); +int make_writable(struct sk_buff **pskb); + +#endif /* dp_act.h */ diff --git a/openflow/datapath/dp_dev.c b/openflow/datapath/dp_dev.c new file mode 100644 index 00000000..5db5b19b --- /dev/null +++ b/openflow/datapath/dp_dev.c @@ -0,0 +1,252 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "datapath.h" +#include "dp_dev.h" +#include "forward.h" + + +static struct dp_dev *dp_dev_priv(struct net_device *netdev) +{ + return netdev_priv(netdev); +} + +struct datapath *dp_dev_get_dp(struct net_device *netdev) +{ + return dp_dev_priv(netdev)->dp; +} +EXPORT_SYMBOL(dp_dev_get_dp); + +static struct net_device_stats *dp_dev_get_stats(struct net_device *netdev) +{ + struct dp_dev *dp_dev = dp_dev_priv(netdev); + return &dp_dev->stats; +} + +int dp_dev_recv(struct net_device *netdev, struct sk_buff *skb) +{ + int len = skb->len; + struct dp_dev *dp_dev = dp_dev_priv(netdev); + skb->dev = netdev; + skb->pkt_type = PACKET_HOST; + skb->protocol = eth_type_trans(skb, netdev); + if (in_interrupt()) + netif_rx(skb); + else + netif_rx_ni(skb); + netdev->last_rx = jiffies; + dp_dev->stats.rx_packets++; + dp_dev->stats.rx_bytes += len; + return len; +} + +static int dp_dev_mac_addr(struct net_device *dev, void *p) +{ + struct sockaddr *addr = p; + + if (netif_running(dev)) + return -EBUSY; + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + return 0; +} + +static int dp_dev_xmit(struct sk_buff *skb, struct net_device *netdev) +{ + struct dp_dev *dp_dev = dp_dev_priv(netdev); + struct datapath *dp = dp_dev->dp; + + /* By orphaning 'skb' we will screw up socket accounting slightly, but + * the effect is limited to the device queue length. If we don't + * do this, then the sk_buff will be destructed eventually, but it is + * harder to predict when. */ + skb_orphan(skb); + + /* We are going to modify 'skb', by sticking it on &dp_dev->xmit_queue, + * so we need to have our own clone. (At any rate, fwd_port_input() + * will need its own clone, so there's no benefit to queuing any other + * way.) */ + skb = skb_share_check(skb, GFP_ATOMIC); + if (!skb) + return 0; + + dp_dev->stats.tx_packets++; + dp_dev->stats.tx_bytes += skb->len; + + if (skb_queue_len(&dp_dev->xmit_queue) >= dp->netdev->tx_queue_len) { + /* Queue overflow. Stop transmitter. */ + netif_stop_queue(dp->netdev); + + /* We won't see all dropped packets individually, so overrun + * error is appropriate. */ + dp_dev->stats.tx_fifo_errors++; + } + skb_queue_tail(&dp_dev->xmit_queue, skb); + dp->netdev->trans_start = jiffies; + + schedule_work(&dp_dev->xmit_work); + + return 0; +} + +static void dp_dev_do_xmit(struct work_struct *work) +{ + struct dp_dev *dp_dev = container_of(work, struct dp_dev, xmit_work); + struct datapath *dp = dp_dev->dp; + struct sk_buff *skb; + + while ((skb = skb_dequeue(&dp_dev->xmit_queue)) != NULL) { + skb_reset_mac_header(skb); + rcu_read_lock(); + fwd_port_input(dp->chain, skb, dp->local_port); + rcu_read_unlock(); + } + netif_wake_queue(dp->netdev); +} + +static int dp_dev_open(struct net_device *netdev) +{ + netif_start_queue(netdev); + return 0; +} + +static int dp_dev_stop(struct net_device *netdev) +{ + netif_stop_queue(netdev); + return 0; +} + +static void dp_getinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + strcpy(info->driver, "openflow"); + sprintf(info->version, "0x%d", OFP_VERSION); + strcpy(info->fw_version, "N/A"); + strcpy(info->bus_info, "N/A"); +} + +static struct ethtool_ops dp_ethtool_ops = { + .get_drvinfo = dp_getinfo, + .get_link = ethtool_op_get_link, + .get_sg = ethtool_op_get_sg, + .get_tx_csum = ethtool_op_get_tx_csum, + .get_tso = ethtool_op_get_tso, +}; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) +static const struct net_device_ops dp_netdev_ops = { + .ndo_init = NULL, + .ndo_uninit = NULL, + .ndo_open = dp_dev_open, + .ndo_stop = dp_dev_stop, + .ndo_start_xmit = dp_dev_xmit, + .ndo_select_queue = NULL, + .ndo_change_rx_flags = NULL, + .ndo_set_rx_mode = NULL, + .ndo_set_multicast_list = NULL, + .ndo_set_mac_address = dp_dev_mac_addr, + .ndo_validate_addr = NULL, + .ndo_do_ioctl = NULL, + .ndo_set_config = NULL, + .ndo_change_mtu = NULL, + .ndo_tx_timeout = NULL, + .ndo_get_stats = dp_dev_get_stats, + .ndo_vlan_rx_register = NULL, + .ndo_vlan_rx_add_vid = NULL, + .ndo_vlan_rx_kill_vid = NULL, + .ndo_poll_controller = NULL +}; +#endif + +static void +do_setup(struct net_device *netdev) +{ + ether_setup(netdev); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) + netdev->netdev_ops = &dp_netdev_ops; +#else + netdev->do_ioctl = dp_ioctl_hook; + netdev->get_stats = dp_dev_get_stats; + netdev->hard_start_xmit = dp_dev_xmit; + netdev->open = dp_dev_open; + netdev->stop = dp_dev_stop; + netdev->set_mac_address = dp_dev_mac_addr; +#endif + SET_ETHTOOL_OPS(netdev, &dp_ethtool_ops); + netdev->tx_queue_len = 100; + + netdev->flags = IFF_BROADCAST | IFF_MULTICAST; + + random_ether_addr(netdev->dev_addr); + + /* Set the OUI to the Nicira one. */ + netdev->dev_addr[0] = 0x00; + netdev->dev_addr[1] = 0x23; + netdev->dev_addr[2] = 0x20; + + /* Set the top bits to indicate random Nicira address. */ + netdev->dev_addr[3] |= 0xc0; +} + +/* Create a datapath device associated with 'dp'. If 'dp_name' is null, + * the device name will be of the form 'of'. + * + * Called with RTNL lock and dp_mutex.*/ +int dp_dev_setup(struct datapath *dp, const char *dp_name) +{ + struct dp_dev *dp_dev; + struct net_device *netdev; + char dev_name[IFNAMSIZ]; + int err; + + if (dp_name) { + if (strlen(dp_name) >= IFNAMSIZ) + return -EINVAL; + strncpy(dev_name, dp_name, sizeof(dev_name)); + } else + snprintf(dev_name, sizeof dev_name, "of%d", dp->dp_idx); + + netdev = alloc_netdev(sizeof(struct dp_dev), dev_name, do_setup); + if (!netdev) + return -ENOMEM; + + err = register_netdevice(netdev); + if (err) { + free_netdev(netdev); + return err; + } + + dp_dev = dp_dev_priv(netdev); + dp_dev->dp = dp; + skb_queue_head_init(&dp_dev->xmit_queue); + INIT_WORK(&dp_dev->xmit_work, dp_dev_do_xmit); + dp->netdev = netdev; + return 0; +} + +/* Called with RTNL lock and dp_mutex.*/ +void dp_dev_destroy(struct datapath *dp) +{ + struct dp_dev *dp_dev = dp_dev_priv(dp->netdev); + + netif_tx_disable(dp->netdev); + synchronize_net(); + skb_queue_purge(&dp_dev->xmit_queue); + unregister_netdevice(dp->netdev); +} + +int is_dp_dev(struct net_device *netdev) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) + return netdev->netdev_ops->ndo_open == dp_dev_open; + +#else + return netdev->open == dp_dev_open; +#endif +} diff --git a/openflow/datapath/dp_dev.h b/openflow/datapath/dp_dev.h new file mode 100644 index 00000000..26f72485 --- /dev/null +++ b/openflow/datapath/dp_dev.h @@ -0,0 +1,17 @@ +#ifndef DP_DEV_H +#define DP_DEV_H 1 + +struct dp_dev { + struct net_device_stats stats; + struct datapath *dp; + struct sk_buff_head xmit_queue; + struct work_struct xmit_work; +}; + +int dp_dev_setup(struct datapath *, const char *); +void dp_dev_destroy(struct datapath *); +int dp_dev_recv(struct net_device *, struct sk_buff *); +int is_dp_dev(struct net_device *); +struct datapath *dp_dev_get_dp(struct net_device *); + +#endif /* dp_dev.h */ diff --git a/openflow/datapath/dp_notify.c b/openflow/datapath/dp_notify.c new file mode 100644 index 00000000..54c88402 --- /dev/null +++ b/openflow/datapath/dp_notify.c @@ -0,0 +1,43 @@ +/* + * Distributed under the terms of the GNU GPL version 2. + * Copyright (c) 2007, 2008, 2009 The Board of Trustees of The Leland + * Stanford Junior University + */ + +/* Handle changes to managed devices */ + +#include + +#include "datapath.h" + + +static int dp_device_event(struct notifier_block *unused, unsigned long event, + void *ptr) +{ + struct net_device *dev = ptr; + struct net_bridge_port *p = dev->br_port; + unsigned long int flags; + + + /* Check if monitored port */ + if (!p) + return NOTIFY_DONE; + + spin_lock_irqsave(&p->lock, flags); + switch (event) { + case NETDEV_UNREGISTER: + spin_unlock_irqrestore(&p->lock, flags); + mutex_lock(&dp_mutex); + dp_del_switch_port(p); + mutex_unlock(&dp_mutex); + return NOTIFY_DONE; + break; + } + spin_unlock_irqrestore(&p->lock, flags); + + return NOTIFY_DONE; +} + +struct notifier_block dp_device_notifier = { + .notifier_call = dp_device_event +}; diff --git a/openflow/datapath/flow.c b/openflow/datapath/flow.c new file mode 100644 index 00000000..c927ce65 --- /dev/null +++ b/openflow/datapath/flow.c @@ -0,0 +1,504 @@ + +/* + * Distributed under the terms of the GNU GPL version 2. + * Copyright (c) 2007, 2008 The Board of Trustees of The Leland + * Stanford Junior University + */ + +#include "flow.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "openflow/openflow.h" +#include "openflow/nicira-ext.h" +#include "compat.h" + +struct kmem_cache *flow_cache; + +/* Internal function used to compare fields in flow. */ +static inline +int flow_fields_match(const struct sw_flow_key *a, const struct sw_flow_key *b, + uint32_t w, uint32_t src_mask, uint32_t dst_mask) +{ + return ((w & OFPFW_IN_PORT || a->in_port == b->in_port) + && (w & OFPFW_DL_VLAN || a->dl_vlan == b->dl_vlan) + && (w & OFPFW_DL_VLAN_PCP || a->dl_vlan_pcp == b->dl_vlan_pcp) + && (w & OFPFW_DL_SRC || !memcmp(a->dl_src, b->dl_src, ETH_ALEN)) + && (w & OFPFW_DL_DST || !memcmp(a->dl_dst, b->dl_dst, ETH_ALEN)) + && (w & OFPFW_DL_TYPE || a->dl_type == b->dl_type) + && (w & OFPFW_NW_TOS || a->nw_tos == b->nw_tos) + && (w & OFPFW_NW_PROTO || a->nw_proto == b->nw_proto) + && !((a->nw_src ^ b->nw_src) & src_mask) + && !((a->nw_dst ^ b->nw_dst) & dst_mask) + && (w & OFPFW_TP_SRC || a->tp_src == b->tp_src) + && (w & OFPFW_TP_DST || a->tp_dst == b->tp_dst)); +} + +/* Returns nonzero if 'a' and 'b' match, that is, if their fields are equal + * modulo wildcards in 'b', zero otherwise. */ +int flow_matches_1wild(const struct sw_flow_key *a, + const struct sw_flow_key *b) +{ + return flow_fields_match(a, b, b->wildcards, + b->nw_src_mask, b->nw_dst_mask); +} +EXPORT_SYMBOL(flow_matches_1wild); + +/* Returns nonzero if 'a' and 'b' match, that is, if their fields are equal + * modulo wildcards in 'a' or 'b', zero otherwise. */ +int flow_matches_2wild(const struct sw_flow_key *a, + const struct sw_flow_key *b) +{ + return flow_fields_match(a, b, + a->wildcards | b->wildcards, + a->nw_src_mask & b->nw_src_mask, + a->nw_dst_mask & b->nw_dst_mask); +} +EXPORT_SYMBOL(flow_matches_2wild); + +/* Returns nonzero if 't' (the table entry's key) and 'd' (the key + * describing the match) match, that is, if their fields are + * equal modulo wildcards, zero otherwise. If 'strict' is nonzero, the + * wildcards must match in both 't_key' and 'd_key'. Note that the + * table's wildcards are ignored unless 'strict' is set. */ +int flow_matches_desc(const struct sw_flow_key *t, const struct sw_flow_key *d, + int strict) +{ + if (strict && d->wildcards != t->wildcards) + return 0; + return flow_matches_1wild(t, d); +} +EXPORT_SYMBOL(flow_matches_desc); + +/* Returns nonzero if 't' (the table entry's key) and 'd' (the key + * describing the match) match, that is, if their fields are + * equal modulo 't' or 'd' wildcards, zero otherwise. If 'strict' is nonzero, the + * wildcards must match in both 't_key' and 'd_key'. Note that the + * table's wildcards are ignored unless 'strict' is set. */ +int +flow_matches_2desc(const struct sw_flow_key *t, const struct sw_flow_key *d, + int strict) +{ + if (strict && d->wildcards != t->wildcards) { + return 0; + } + return flow_matches_2wild(t, d); +} +EXPORT_SYMBOL(flow_matches_2desc); + +static uint32_t make_nw_mask(int n_wild_bits) +{ + n_wild_bits &= (1u << OFPFW_NW_SRC_BITS) - 1; + return n_wild_bits < 32 ? htonl(~((1u << n_wild_bits) - 1)) : 0; +} + +void flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from) +{ + to->wildcards = ntohl(from->wildcards) & OFPFW_ALL; + to->dl_vlan_pcp = from->dl_vlan_pcp; + to->in_port = from->in_port; + to->dl_vlan = from->dl_vlan; + memcpy(to->dl_src, from->dl_src, ETH_ALEN); + memcpy(to->dl_dst, from->dl_dst, ETH_ALEN); + to->dl_type = from->dl_type; + + to->nw_tos = to->nw_proto = to->nw_src = to->nw_dst = 0; + to->tp_src = to->tp_dst = 0; + memset(to->pad, 0, sizeof(to->pad)); + +#define OFPFW_TP (OFPFW_TP_SRC | OFPFW_TP_DST) +#define OFPFW_NW (OFPFW_NW_TOS | OFPFW_NW_PROTO | OFPFW_NW_SRC_MASK | OFPFW_NW_DST_MASK) + if (to->wildcards & OFPFW_DL_TYPE) { + /* Can't sensibly match on network or transport headers if the + * data link type is unknown. */ + to->wildcards |= OFPFW_NW | OFPFW_TP; + } else if (from->dl_type == htons(ETH_P_IP)) { + to->nw_tos = from->nw_tos & 0xfc; + to->nw_proto = from->nw_proto; + to->nw_src = from->nw_src; + to->nw_dst = from->nw_dst; + + if (to->wildcards & OFPFW_NW_PROTO) { + /* Can't sensibly match on transport headers if the + * network protocol is unknown. */ + to->wildcards |= OFPFW_TP; + } else if (from->nw_proto == IPPROTO_TCP + || from->nw_proto == IPPROTO_UDP + || from->nw_proto == IPPROTO_ICMP) { + to->tp_src = from->tp_src; + to->tp_dst = from->tp_dst; + } else { + /* Transport layer fields are undefined. Mark them as + * exact-match to allow such flows to reside in + * table-hash, instead of falling into table-linear. */ + to->wildcards &= ~OFPFW_TP; + } + } else { + /* Network and transport layer fields are undefined. Mark them + * as exact-match to allow such flows to reside in table-hash, + * instead of falling into table-linear. */ + to->wildcards &= ~(OFPFW_NW | OFPFW_TP); + } + + /* We set these late because code above adjusts to->wildcards. */ + to->nw_src_mask = make_nw_mask(to->wildcards >> OFPFW_NW_SRC_SHIFT); + to->nw_dst_mask = make_nw_mask(to->wildcards >> OFPFW_NW_DST_SHIFT); +} + +void flow_fill_match(struct ofp_match* to, const struct sw_flow_key* from) +{ + to->wildcards = htonl(from->wildcards); + to->in_port = from->in_port; + to->dl_vlan = from->dl_vlan; + memcpy(to->dl_src, from->dl_src, ETH_ALEN); + memcpy(to->dl_dst, from->dl_dst, ETH_ALEN); + to->dl_type = from->dl_type; + to->nw_tos = from->nw_tos; + to->nw_proto = from->nw_proto; + to->nw_src = from->nw_src; + to->nw_dst = from->nw_dst; + to->tp_src = from->tp_src; + to->tp_dst = from->tp_dst; + to->dl_vlan_pcp = from->dl_vlan_pcp; +} + +int flow_timeout(struct sw_flow *flow) +{ + if (flow->idle_timeout != OFP_FLOW_PERMANENT + && time_after64(get_jiffies_64(), flow->used + flow->idle_timeout * HZ)) + return OFPRR_IDLE_TIMEOUT; + else if (flow->hard_timeout != OFP_FLOW_PERMANENT + && time_after64(get_jiffies_64(), + flow->created + flow->hard_timeout * HZ)) + return OFPRR_HARD_TIMEOUT; + else + return -1; +} +EXPORT_SYMBOL(flow_timeout); + +/* Returns nonzero if 'flow' contains an output action to 'out_port' or + * has the value OFPP_NONE. 'out_port' is in network-byte order. */ +int flow_has_out_port(struct sw_flow *flow, uint16_t out_port) +{ + struct sw_flow_actions *sf_acts; + size_t actions_len; + uint8_t *p; + + if (out_port == htons(OFPP_NONE)) + return 1; + + sf_acts = rcu_dereference(flow->sf_acts); + + actions_len = sf_acts->actions_len; + p = (uint8_t *)sf_acts->actions; + + while (actions_len > 0) { + struct ofp_action_header *ah = (struct ofp_action_header *)p; + size_t len = ntohs(ah->len); + + if (ah->type == htons(OFPAT_OUTPUT)) { + struct ofp_action_output *oa = (struct ofp_action_output *)p; + if (oa->port == out_port) + return 1; + } + + p += len; + actions_len -= len; + } + + return 0; +} +EXPORT_SYMBOL(flow_has_out_port); + +/* Allocates and returns a new flow with room for 'actions_len' actions, + * using allocation flags 'flags'. Returns the new flow or a null pointer + * on failure. */ +struct sw_flow *flow_alloc(size_t actions_len, gfp_t flags) +{ + struct sw_flow_actions *sfa; + size_t size = sizeof *sfa + actions_len; + struct sw_flow *flow = kmem_cache_alloc(flow_cache, flags); + if (unlikely(!flow)) + return NULL; + + sfa = kmalloc(size, flags); + if (unlikely(!sfa)) { + kmem_cache_free(flow_cache, flow); + return NULL; + } + sfa->actions_len = actions_len; + flow->sf_acts = sfa; + + return flow; +} + +/* Frees 'flow' immediately. */ +void flow_free(struct sw_flow *flow) +{ + if (unlikely(!flow)) + return; + kfree(flow->sf_acts); + kmem_cache_free(flow_cache, flow); +} +EXPORT_SYMBOL(flow_free); + +/* RCU callback used by flow_deferred_free. */ +static void rcu_free_flow_callback(struct rcu_head *rcu) +{ + struct sw_flow *flow = container_of(rcu, struct sw_flow, rcu); + flow_free(flow); +} + +/* Schedules 'flow' to be freed after the next RCU grace period. + * The caller must hold rcu_read_lock for this to be sensible. */ +void flow_deferred_free(struct sw_flow *flow) +{ + call_rcu(&flow->rcu, rcu_free_flow_callback); +} +EXPORT_SYMBOL(flow_deferred_free); + +/* RCU callback used by flow_deferred_free_acts. */ +static void rcu_free_acts_callback(struct rcu_head *rcu) +{ + struct sw_flow_actions *sf_acts = container_of(rcu, + struct sw_flow_actions, rcu); + kfree(sf_acts); +} + +/* Schedules 'sf_acts' to be freed after the next RCU grace period. + * The caller must hold rcu_read_lock for this to be sensible. */ +void flow_deferred_free_acts(struct sw_flow_actions *sf_acts) +{ + call_rcu(&sf_acts->rcu, rcu_free_acts_callback); +} +EXPORT_SYMBOL(flow_deferred_free_acts); + +/* Setup the action on the flow, just after it was created with flow_alloc(). + * Jean II */ +void flow_setup_actions(struct sw_flow * flow, + const struct ofp_action_header * actions, + int actions_len) +{ + /* Basic init of the flow stucture */ + flow->used = flow->created = get_jiffies_64(); + flow->byte_count = 0; + flow->packet_count = 0; + spin_lock_init(&flow->lock); + + /* Make sure we don't blow the allocation done earlier */ + if(actions_len > flow->sf_acts->actions_len) { + printk(KERN_ERR "flow_setup_actions: actions_len is too big (%d > %d)", + actions_len, flow->sf_acts->actions_len); + return; + } + + /* Setup the actions - No need for RCU at this point ;-) */ + memcpy(flow->sf_acts->actions, actions, actions_len); +} + +/* Copies 'actions' into a newly allocated structure for use by 'flow' + * and safely frees the structure that defined the previous actions. */ +void flow_replace_acts(struct sw_flow *flow, + const struct ofp_action_header *actions, size_t actions_len) +{ + struct sw_flow_actions *sfa; + struct sw_flow_actions *orig_sfa = flow->sf_acts; + size_t size = sizeof *sfa + actions_len; + + sfa = kmalloc(size, GFP_ATOMIC); + if (unlikely(!sfa)) + return; + + sfa->actions_len = actions_len; + memcpy(sfa->actions, actions, actions_len); + + rcu_assign_pointer(flow->sf_acts, sfa); + flow_deferred_free_acts(orig_sfa); + + return; +} +EXPORT_SYMBOL(flow_replace_acts); + +/* Prints a representation of 'key' to the kernel log. */ +void print_flow(const struct sw_flow_key *key) +{ + printk("wild %08x port %04x vlan-vid %04x vlan-pcp %02x " + "src-mac %02x:%02x:%02x:%02x:%02x:%02x " + "dst-mac %02x:%02x:%02x:%02x:%02x:%02x " + "frm-type %04x ip-tos %02x ip-proto %02x " + "src-ip %u.%u.%u.%u dst-ip %u.%u.%u.%u tp-src %d tp-dst %d\n", + key->wildcards, ntohs(key->in_port), ntohs(key->dl_vlan), + key->dl_vlan_pcp, + key->dl_src[0], key->dl_src[1], key->dl_src[2], + key->dl_src[3], key->dl_src[4], key->dl_src[5], + key->dl_dst[0], key->dl_dst[1], key->dl_dst[2], + key->dl_dst[3], key->dl_dst[4], key->dl_dst[5], + ntohs(key->dl_type), + key->nw_tos, key->nw_proto, + ((unsigned char *)&key->nw_src)[0], + ((unsigned char *)&key->nw_src)[1], + ((unsigned char *)&key->nw_src)[2], + ((unsigned char *)&key->nw_src)[3], + ((unsigned char *)&key->nw_dst)[0], + ((unsigned char *)&key->nw_dst)[1], + ((unsigned char *)&key->nw_dst)[2], + ((unsigned char *)&key->nw_dst)[3], + ntohs(key->tp_src), ntohs(key->tp_dst)); +} +EXPORT_SYMBOL(print_flow); + +#define SNAP_OUI_LEN 3 + +struct eth_snap_hdr +{ + struct ethhdr eth; + uint8_t dsap; /* Always 0xAA */ + uint8_t ssap; /* Always 0xAA */ + uint8_t ctrl; + uint8_t oui[SNAP_OUI_LEN]; + uint16_t ethertype; +} __attribute__ ((packed)); + +static int is_snap(const struct eth_snap_hdr *esh) +{ + return (esh->dsap == LLC_SAP_SNAP + && esh->ssap == LLC_SAP_SNAP + && !memcmp(esh->oui, "\0\0\0", 3)); +} + +/* Parses the Ethernet frame in 'skb', which was received on 'in_port', + * and initializes 'key' to match. Returns 1 if 'skb' contains an IP + * fragment, 0 otherwise. */ +int flow_extract(struct sk_buff *skb, uint16_t in_port, + struct sw_flow_key *key) +{ + struct ethhdr *eth; + struct eth_snap_hdr *esh; + int retval = 0; + int nh_ofs; + + memset(key, 0, sizeof *key); + key->dl_vlan = htons(OFP_VLAN_NONE); + key->in_port = htons(in_port); + + if (skb->len < sizeof *eth) + return 0; + if (!pskb_may_pull(skb, skb->len >= 64 ? 64 : skb->len)) { + return 0; + } + + skb_reset_mac_header(skb); + eth = eth_hdr(skb); + esh = (struct eth_snap_hdr *) eth; + nh_ofs = sizeof *eth; + if (likely(ntohs(eth->h_proto) >= OFP_DL_TYPE_ETH2_CUTOFF)) + key->dl_type = eth->h_proto; + else if (skb->len >= sizeof *esh && is_snap(esh)) { + key->dl_type = esh->ethertype; + nh_ofs = sizeof *esh; + } else { + key->dl_type = htons(OFP_DL_TYPE_NOT_ETH_TYPE); + if (skb->len >= nh_ofs + sizeof(struct llc_pdu_un)) { + nh_ofs += sizeof(struct llc_pdu_un); + } + } + + /* Check for a VLAN tag */ + if (key->dl_type == htons(ETH_P_8021Q) && + skb->len >= nh_ofs + sizeof(struct vlan_hdr)) { + struct vlan_hdr *vh = (struct vlan_hdr*)(skb->data + nh_ofs); + key->dl_type = vh->h_vlan_encapsulated_proto; + key->dl_vlan = vh->h_vlan_TCI & htons(VLAN_VID_MASK); + key->dl_vlan_pcp = (uint8_t)((ntohs(vh->h_vlan_TCI) >> VLAN_PCP_SHIFT) + & VLAN_PCP_BITMASK); + nh_ofs += sizeof(struct vlan_hdr); + } + memcpy(key->dl_src, eth->h_source, ETH_ALEN); + memcpy(key->dl_dst, eth->h_dest, ETH_ALEN); + skb_set_network_header(skb, nh_ofs); + + /* Network layer. */ + if (key->dl_type == htons(ETH_P_IP) && iphdr_ok(skb)) { + struct iphdr *nh = ip_hdr(skb); + int th_ofs = nh_ofs + nh->ihl * 4; + key->nw_tos = nh->tos & 0xfc; + key->nw_proto = nh->protocol; + key->nw_src = nh->saddr; + key->nw_dst = nh->daddr; + skb_set_transport_header(skb, th_ofs); + + /* Transport layer. */ + if (!(nh->frag_off & htons(IP_MF | IP_OFFSET))) { + if (key->nw_proto == IPPROTO_TCP) { + if (tcphdr_ok(skb)) { + struct tcphdr *tcp = tcp_hdr(skb); + key->tp_src = tcp->source; + key->tp_dst = tcp->dest; + } else { + /* Avoid tricking other code into + * thinking that this packet has an L4 + * header. */ + key->nw_proto = 0; + } + } else if (key->nw_proto == IPPROTO_UDP) { + if (udphdr_ok(skb)) { + struct udphdr *udp = udp_hdr(skb); + key->tp_src = udp->source; + key->tp_dst = udp->dest; + } else { + /* Avoid tricking other code into + * thinking that this packet has an L4 + * header. */ + key->nw_proto = 0; + } + } else if (key->nw_proto == IPPROTO_ICMP) { + if (icmphdr_ok(skb)) { + struct icmphdr *icmp = icmp_hdr(skb); + /* The ICMP type and code fields use the 16-bit + * transport port fields, so we need to store them + * in 16-bit network byte order. */ + key->icmp_type = htons(icmp->type); + key->icmp_code = htons(icmp->code); + } else { + /* Avoid tricking other code into + * thinking that this packet has an L4 + * header. */ + key->nw_proto = 0; + } + } + } else { + retval = 1; + } + } else { + skb_reset_transport_header(skb); + } + return retval; +} + +/* Initializes the flow module. + * Returns zero if successful or a negative error code. */ +int flow_init(void) +{ + flow_cache = kmem_cache_create("sw_flow", sizeof(struct sw_flow), 0, + 0, NULL); + if (flow_cache == NULL) + return -ENOMEM; + + return 0; +} + +/* Uninitializes the flow module. */ +void flow_exit(void) +{ + kmem_cache_destroy(flow_cache); +} + diff --git a/openflow/datapath/flow.h b/openflow/datapath/flow.h new file mode 100644 index 00000000..5f8597a3 --- /dev/null +++ b/openflow/datapath/flow.h @@ -0,0 +1,199 @@ +#ifndef FLOW_H +#define FLOW_H 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "openflow/openflow.h" + +#define VLAN_PCP_SHIFT 13 +#define VLAN_PCP_BITMASK 0x0007 /* the least 3-bit is valid */ + +struct sk_buff; +struct ofp_flow_mod; + +/* Identification data for a flow. + * Network byte order except for the "wildcards" field. + * Ordered to make bytewise comparisons (e.g. with memcmp()) fail quickly and + * to keep the amount of padding to a minimum. + * If you change the ordering of fields here, change flow_keys_equal() to + * compare the proper fields. + */ +struct sw_flow_key { + uint32_t nw_src; /* IP source address. */ + uint32_t nw_dst; /* IP destination address. */ + uint16_t in_port; /* Input switch port */ + uint16_t dl_vlan; /* Input VLAN id. */ + uint16_t dl_type; /* Ethernet frame type. */ + uint16_t tp_src; /* TCP/UDP source port. */ + uint16_t tp_dst; /* TCP/UDP destination port. */ + uint8_t dl_src[ETH_ALEN]; /* Ethernet source address. */ + uint8_t dl_dst[ETH_ALEN]; /* Ethernet destination address. */ + uint8_t dl_vlan_pcp; /* Input VLAN priority. */ + uint8_t nw_tos; /* IPv4 DSCP */ + uint8_t nw_proto; /* IP protocol. */ + uint8_t pad[3]; + uint32_t wildcards; /* Wildcard fields (host byte order). */ + uint32_t nw_src_mask; /* 1-bit in each significant nw_src bit. */ + uint32_t nw_dst_mask; /* 1-bit in each significant nw_dst bit. */ +}; + +/* The match fields for ICMP type and code use the transport source and + * destination port fields, respectively. */ +#define icmp_type tp_src +#define icmp_code tp_dst + +/* Compare two sw_flow_keys and return true if they are the same flow, false + * otherwise. Wildcards and netmasks are not considered. */ +static inline int flow_keys_equal(const struct sw_flow_key *a, + const struct sw_flow_key *b) +{ + return !memcmp(a, b, offsetof(struct sw_flow_key, wildcards)); +} + +/* We need to manually make sure that the structure is 32-bit aligned, + * since we don't want garbage values in compiler-generated pads from + * messing up hash matches. + */ +static inline void check_key_align(void) +{ + BUILD_BUG_ON(sizeof(struct sw_flow_key) != 48); +} + +/* We keep actions as a separate structure because we need to be able to + * swap them out atomically when the modify command comes from a Flow + * Modify message. */ +struct sw_flow_actions { + size_t actions_len; + struct rcu_head rcu; + + struct ofp_action_header actions[0]; +}; + +/* Locking: + * + * - Readers must take rcu_read_lock and hold it the entire time that the flow + * must continue to exist. + * + * - Writers must hold dp_mutex. + */ +struct sw_flow { + struct sw_flow_key key; + + uint16_t priority; /* Only used on entries with wildcards. */ + uint16_t idle_timeout; /* Idle time before discarding (seconds). */ + uint16_t hard_timeout; /* Hard expiration time (seconds) */ + uint64_t used; /* Last used time (in jiffies). */ + uint8_t send_flow_rem; /* Send a flow removed to the controller */ + uint8_t emerg_flow; /* Emergency flow indicator */ + + struct sw_flow_actions *sf_acts; + + /* For use by table implementation. */ + struct list_head node; + struct list_head iter_node; + unsigned long serial; + void *private; + + spinlock_t lock; /* Lock this entry...mostly for stat updates */ + uint64_t created; /* When the flow was created (in jiffies_64). */ + uint64_t packet_count; /* Number of packets associated with this entry */ + uint64_t byte_count; /* Number of bytes associated with this entry */ + + struct rcu_head rcu; +}; + +int flow_matches_1wild(const struct sw_flow_key *, const struct sw_flow_key *); +int flow_matches_2wild(const struct sw_flow_key *, const struct sw_flow_key *); +int flow_matches_desc(const struct sw_flow_key *, const struct sw_flow_key *, + int); +int flow_matches_2desc(const struct sw_flow_key *, const struct sw_flow_key *, + int); +int flow_has_out_port(struct sw_flow *, uint16_t); +struct sw_flow *flow_alloc(size_t actions_len, gfp_t flags); +void flow_free(struct sw_flow *); +void flow_deferred_free(struct sw_flow *); +void flow_deferred_free_acts(struct sw_flow_actions *); +void flow_setup_actions(struct sw_flow *, const struct ofp_action_header *, + int); +void flow_replace_acts(struct sw_flow *, const struct ofp_action_header *, + size_t); +int flow_extract(struct sk_buff *, uint16_t in_port, struct sw_flow_key *); +void flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from); +void flow_fill_match(struct ofp_match* to, const struct sw_flow_key* from); +int flow_timeout(struct sw_flow *); + +void print_flow(const struct sw_flow_key *); + +static inline int iphdr_ok(struct sk_buff *skb) +{ + int nh_ofs = skb_network_offset(skb); + if (skb->len >= nh_ofs + sizeof(struct iphdr)) { + int ip_len = ip_hdrlen(skb); + return (ip_len >= sizeof(struct iphdr) + && pskb_may_pull(skb, nh_ofs + ip_len)); + } + return 0; +} + +static inline int tcphdr_ok(struct sk_buff *skb) +{ + int th_ofs = skb_transport_offset(skb); + if (pskb_may_pull(skb, th_ofs + sizeof(struct tcphdr))) { + int tcp_len = tcp_hdrlen(skb); + return (tcp_len >= sizeof(struct tcphdr) + && skb->len >= th_ofs + tcp_len); + } + return 0; +} + +static inline int udphdr_ok(struct sk_buff *skb) +{ + int th_ofs = skb_transport_offset(skb); + return pskb_may_pull(skb, th_ofs + sizeof(struct udphdr)); +} + +static inline int icmphdr_ok(struct sk_buff *skb) +{ + int th_ofs = skb_transport_offset(skb); + return pskb_may_pull(skb, th_ofs + sizeof(struct icmphdr)); +} + +#define TCP_FLAGS_OFFSET 13 +#define TCP_FLAG_MASK 0x3f + +static inline struct ofp_tcphdr *ofp_tcp_hdr(const struct sk_buff *skb) +{ + return (struct ofp_tcphdr *)skb_transport_header(skb); +} + +static inline void flow_used(struct sw_flow *flow, struct sk_buff *skb) +{ + unsigned long flags; + + flow->used = get_jiffies_64(); + + spin_lock_irqsave(&flow->lock, flags); + flow->packet_count++; + flow->byte_count += skb->len; + spin_unlock_irqrestore(&flow->lock, flags); +} + +extern struct kmem_cache *flow_cache; + +int flow_init(void); +void flow_exit(void); + +#endif /* flow.h */ diff --git a/openflow/datapath/forward.c b/openflow/datapath/forward.c new file mode 100644 index 00000000..40d2a332 --- /dev/null +++ b/openflow/datapath/forward.c @@ -0,0 +1,642 @@ +/* + * Distributed under the terms of the GNU GPL version 2. + * Copyright (c) 2007, 2008, 2009 The Board of Trustees of The Leland + * Stanford Junior University + */ + +#include +#include +#include +#include +#include +#include +#include "forward.h" +#include "datapath.h" +#include "openflow/nicira-ext.h" +#include "openflow/private-ext.h" +#include "dp_act.h" +#include "private-msg.h" +#include "openflow-ext.h" +#include "chain.h" +#include "flow.h" + +/* FIXME: do we need to use GFP_ATOMIC everywhere here? */ + + +static struct sk_buff *retrieve_skb(uint32_t id); +static void discard_skb(uint32_t id); + +/* 'skb' was received on port 'p', which may be a physical switch port, the + * local port, or a null pointer. Process it according to 'chain'. Returns 0 + * if successful, in which case 'skb' is destroyed, or -ESRCH if there is no + * matching flow, in which case 'skb' still belongs to the caller. */ +int run_flow_through_tables(struct sw_chain *chain, struct sk_buff *skb, + struct net_bridge_port *p) +{ + /* Ethernet address used as the destination for STP frames. */ + static const uint8_t stp_eth_addr[ETH_ALEN] + = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x01 }; + struct sw_flow_key key; + struct sw_flow *flow; + + if (flow_extract(skb, p ? p->port_no : OFPP_NONE, &key) + && (chain->dp->flags & OFPC_FRAG_MASK) == OFPC_FRAG_DROP) { + /* Drop fragment. */ + kfree_skb(skb); + return 0; + } + if (p && p->config & (OFPPC_NO_RECV | OFPPC_NO_RECV_STP) && + p->config & (compare_ether_addr(key.dl_dst, stp_eth_addr) + ? OFPPC_NO_RECV : OFPPC_NO_RECV_STP)) { + kfree_skb(skb); + return 0; + } + + flow = chain_lookup(chain, &key, 0); + if (likely(flow != NULL)) { + struct sw_flow_actions *sf_acts = rcu_dereference(flow->sf_acts); + flow_used(flow, skb); + execute_actions(chain->dp, skb, &key, + sf_acts->actions, sf_acts->actions_len, 0); + return 0; + } else { + return -ESRCH; + } +} + +/* 'skb' was received on port 'p', which may be a physical switch port, the + * local port, or a null pointer. Process it according to 'chain', sending it + * up to the controller if no flow matches. Takes ownership of 'skb'. */ +void fwd_port_input(struct sw_chain *chain, struct sk_buff *skb, + struct net_bridge_port *p) +{ + WARN_ON_ONCE(skb_shared(skb)); + WARN_ON_ONCE(skb->destructor); + if (run_flow_through_tables(chain, skb, p)) + dp_output_control(chain->dp, skb, chain->dp->miss_send_len, + OFPR_NO_MATCH); +} + +static int +recv_hello(struct sw_chain *chain, const struct sender *sender, + const void *msg) +{ + return dp_send_hello(chain->dp, sender, msg); +} + +static int +recv_barrier_request(struct sw_chain *chain, const struct sender *sender, + const void *msg) +{ + return dp_send_barrier_reply(chain->dp, sender, msg); +} + +static int +recv_features_request(struct sw_chain *chain, const struct sender *sender, + const void *msg) +{ + return dp_send_features_reply(chain->dp, sender); +} + +static int +recv_get_config_request(struct sw_chain *chain, const struct sender *sender, + const void *msg) +{ + return dp_send_config_reply(chain->dp, sender); +} + +static int +recv_set_config(struct sw_chain *chain, const struct sender *sender, + const void *msg) +{ + const struct ofp_switch_config *osc = msg; + int flags; + + flags = ntohs(osc->flags) & OFPC_FRAG_MASK; + if ((flags & OFPC_FRAG_MASK) != OFPC_FRAG_NORMAL + && (flags & OFPC_FRAG_MASK) != OFPC_FRAG_DROP) { + flags = (flags & ~OFPC_FRAG_MASK) | OFPC_FRAG_DROP; + } + chain->dp->flags = flags; + + chain->dp->miss_send_len = ntohs(osc->miss_send_len); + + return 0; +} + +static int +recv_packet_out(struct sw_chain *chain, const struct sender *sender, + const void *msg) +{ + const struct ofp_packet_out *opo = msg; + struct sk_buff *skb; + uint16_t v_code; + struct sw_flow_key key; + size_t actions_len = ntohs(opo->actions_len); + + if (actions_len > (ntohs(opo->header.length) - sizeof *opo)) { + if (net_ratelimit()) + printk(KERN_NOTICE "%s: message too short for number " + "of actions\n", chain->dp->netdev->name); + return -EINVAL; + } + + if (ntohl(opo->buffer_id) == (uint32_t) -1) { + int data_len = ntohs(opo->header.length) - sizeof *opo - actions_len; + + /* FIXME: there is likely a way to reuse the data in msg. */ + skb = alloc_skb(data_len, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + /* FIXME? We don't reserve NET_IP_ALIGN or NET_SKB_PAD since + * we're just transmitting this raw without examining anything + * at those layers. */ + skb_put(skb, data_len); + skb_copy_to_linear_data(skb, + (uint8_t *)opo->actions + actions_len, + data_len); + skb_reset_mac_header(skb); + } else { + skb = retrieve_skb(ntohl(opo->buffer_id)); + if (!skb) + return -ESRCH; + } + + dp_set_origin(chain->dp, ntohs(opo->in_port), skb); + + flow_extract(skb, ntohs(opo->in_port), &key); + + v_code = validate_actions(chain->dp, &key, opo->actions, actions_len); + if (v_code != ACT_VALIDATION_OK) { + dp_send_error_msg(chain->dp, sender, OFPET_BAD_ACTION, v_code, + msg, ntohs(opo->header.length)); + goto error; + } + + execute_actions(chain->dp, skb, &key, opo->actions, actions_len, 1); + + return 0; + +error: + kfree_skb(skb); + return -EINVAL; +} + +static int +recv_port_mod(struct sw_chain *chain, const struct sender *sender, + const void *msg) +{ + const struct ofp_port_mod *opm = msg; + + dp_update_port_flags(chain->dp, opm); + + return 0; +} + +static int +recv_echo_request(struct sw_chain *chain, const struct sender *sender, + const void *msg) +{ + return dp_send_echo_reply(chain->dp, sender, msg); +} + +static int +recv_echo_reply(struct sw_chain *chain, const struct sender *sender, + const void *msg) +{ + return 0; +} + +static int +add_flow(struct sw_chain *chain, const struct sender *sender, + const struct ofp_flow_mod *ofm) +{ + int error = -ENOMEM; + uint16_t v_code; + struct sw_flow *flow; + size_t actions_len = ntohs(ofm->header.length) - sizeof *ofm; + int overlap; + + /* Allocate memory. */ + flow = flow_alloc(actions_len, GFP_ATOMIC); + if (flow == NULL) + goto error; + + flow_extract_match(&flow->key, &ofm->match); + + v_code = validate_actions(chain->dp, &flow->key, ofm->actions, actions_len); + if (v_code != ACT_VALIDATION_OK) { + dp_send_error_msg(chain->dp, sender, OFPET_BAD_ACTION, v_code, + ofm, ntohs(ofm->header.length)); + goto error_free_flow; + } + + flow->priority = flow->key.wildcards ? ntohs(ofm->priority) : -1; + + if (ntohs(ofm->flags) & OFPFF_CHECK_OVERLAP) { + /* check whether there is any conflict */ + overlap = chain_has_conflict(chain, &flow->key, flow->priority, + false); + if (overlap){ + dp_send_error_msg(chain->dp, sender, + OFPET_FLOW_MOD_FAILED, + OFPFMFC_OVERLAP, + ofm, ntohs(ofm->header.length)); + goto error_free_flow; + } + } + + if (ntohs(ofm->flags) & OFPFF_EMERG) { + if (ntohs(ofm->idle_timeout) != OFP_FLOW_PERMANENT + || ntohs(ofm->hard_timeout) != OFP_FLOW_PERMANENT) { + dp_send_error_msg(chain->dp, sender, + OFPET_FLOW_MOD_FAILED, + OFPFMFC_BAD_EMERG_TIMEOUT, + ofm, ntohs(ofm->header.length)); + goto error_free_flow; + } + } + + /* Fill out flow. */ + flow->idle_timeout = ntohs(ofm->idle_timeout); + flow->hard_timeout = ntohs(ofm->hard_timeout); + flow->send_flow_rem = (ntohs(ofm->flags) & OFPFF_SEND_FLOW_REM) ? 1 : 0; + flow->emerg_flow = (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0; + flow_setup_actions(flow, ofm->actions, actions_len); + + /* Act. */ + error = chain_insert(chain, flow, + (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0); + if (error == -ENOBUFS) { + dp_send_error_msg(chain->dp, sender, OFPET_FLOW_MOD_FAILED, + OFPFMFC_ALL_TABLES_FULL, ofm, ntohs(ofm->header.length)); + goto error_free_flow; + } else if (error) + goto error_free_flow; + + error = 0; + if (ntohl(ofm->buffer_id) != (uint32_t) -1) { + struct sk_buff *skb = retrieve_skb(ntohl(ofm->buffer_id)); + if (skb) { + struct sw_flow_key key; + flow_used(flow, skb); + dp_set_origin(chain->dp, ntohs(ofm->match.in_port), skb); + flow_extract(skb, ntohs(ofm->match.in_port), &key); + execute_actions(chain->dp, skb, &key, ofm->actions, actions_len, 0); + } + else + error = -ESRCH; + } + return error; + +error_free_flow: + flow_free(flow); +error: + if (ntohl(ofm->buffer_id) != (uint32_t) -1) + discard_skb(ntohl(ofm->buffer_id)); + return error; +} + +static int +mod_flow(struct sw_chain *chain, const struct sender *sender, + const struct ofp_flow_mod *ofm) +{ + int error = -ENOMEM; + uint16_t v_code; + size_t actions_len = ntohs(ofm->header.length) - sizeof *ofm; + struct sw_flow *flow; + int strict; + + /* Allocate memory. */ + flow = flow_alloc(actions_len,GFP_ATOMIC); + if (flow == NULL) + goto error; + + flow_extract_match(&flow->key, &ofm->match); + + v_code = validate_actions(chain->dp, &flow->key, ofm->actions, actions_len); + if (v_code != ACT_VALIDATION_OK) { + dp_send_error_msg(chain->dp, sender, OFPET_BAD_ACTION, v_code, + ofm, ntohs(ofm->header.length)); + goto error_free_flow; + } + + flow->priority = flow->key.wildcards ? ntohs(ofm->priority) : -1; + strict = (ofm->command == htons(OFPFC_MODIFY_STRICT)) ? 1 : 0; + + /* First try to modify existing flows if any */ + /* if there is no matching flow, add it */ + if (!chain_modify(chain, &flow->key, flow->priority, strict, + ofm->actions, actions_len, + (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0)) { + /* Fill out flow. */ + flow->idle_timeout = ntohs(ofm->idle_timeout); + flow->hard_timeout = ntohs(ofm->hard_timeout); + flow->send_flow_rem = (ntohs(ofm->flags) & OFPFF_SEND_FLOW_REM) + ? 1 : 0; + flow->emerg_flow = (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0; + flow_setup_actions(flow, ofm->actions, actions_len); + error = chain_insert(chain, flow, + (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0); + if (error == -ENOBUFS) { + dp_send_error_msg(chain->dp, sender, + OFPET_FLOW_MOD_FAILED, + OFPFMFC_ALL_TABLES_FULL, + ofm, ntohs(ofm->header.length)); + goto error_free_flow; + } else if (error) { + goto error_free_flow; + } + } + + error = 0; + if (ntohl(ofm->buffer_id) != (uint32_t) -1) { + struct sk_buff *skb = retrieve_skb(ntohl(ofm->buffer_id)); + if (skb) { + struct sw_flow_key skb_key; + flow_extract(skb, ntohs(ofm->match.in_port), &skb_key); + execute_actions(chain->dp, skb, &skb_key, + ofm->actions, actions_len, 0); + } + else + error = -ESRCH; + } + return error; + +error_free_flow: + flow_free(flow); +error: + if (ntohl(ofm->buffer_id) != (uint32_t) -1) + discard_skb(ntohl(ofm->buffer_id)); + return error; +} + +static int +recv_flow(struct sw_chain *chain, const struct sender *sender, const void *msg) +{ + const struct ofp_flow_mod *ofm = msg; + uint16_t command = ntohs(ofm->command); + + if (command == OFPFC_ADD) { + return add_flow(chain, sender, ofm); + } else if ((command == OFPFC_MODIFY) || (command == OFPFC_MODIFY_STRICT)) { + return mod_flow(chain, sender, ofm); + } else if (command == OFPFC_DELETE) { + struct sw_flow_key key; + flow_extract_match(&key, &ofm->match); + return chain_delete(chain, &key, ofm->out_port, 0, 0, + (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0) + ? 0 : -ESRCH; + } else if (command == OFPFC_DELETE_STRICT) { + struct sw_flow_key key; + uint16_t priority; + flow_extract_match(&key, &ofm->match); + priority = key.wildcards ? ntohs(ofm->priority) : -1; + return chain_delete(chain, &key, ofm->out_port, priority, 1, + (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0) + ? 0 : -ESRCH; + } else { + return -ENOTSUPP; + } +} + +static int +recv_vendor(struct sw_chain *chain, const struct sender *sender, + const void *msg) +{ + const struct ofp_vendor_header *ovh = msg; + + switch(ntohl(ovh->vendor)) + { + case PRIVATE_VENDOR_ID: + return private_recv_msg(chain, sender, msg); + case OPENFLOW_VENDOR_ID: + return openflow_ext_recv_msg(chain, sender, msg); + default: + if (net_ratelimit()) + printk(KERN_NOTICE "%s: unknown vendor: 0x%x\n", + chain->dp->netdev->name, ntohl(ovh->vendor)); + dp_send_error_msg(chain->dp, sender, OFPET_BAD_REQUEST, + OFPBRC_BAD_VENDOR, msg, ntohs(ovh->header.length)); + return -EINVAL; + } +} + +/* 'msg', which is 'length' bytes long, was received across Netlink from + * 'sender'. Apply it to 'chain'. */ +int +fwd_control_input(struct sw_chain *chain, const struct sender *sender, + const void *msg, size_t length) +{ + + struct openflow_packet { + size_t min_size; + int (*handler)(struct sw_chain *, const struct sender *, + const void *); + }; + + static const struct openflow_packet packets[] = { + [OFPT_HELLO] = { + sizeof (struct ofp_header), + recv_hello, + }, + [OFPT_BARRIER_REQUEST] = { + sizeof (struct ofp_header), + recv_barrier_request, + }, + [OFPT_ECHO_REQUEST] = { + sizeof (struct ofp_header), + recv_echo_request, + }, + [OFPT_ECHO_REPLY] = { + sizeof (struct ofp_header), + recv_echo_reply, + }, + [OFPT_VENDOR] = { + sizeof (struct ofp_vendor_header), + recv_vendor, + }, + [OFPT_FEATURES_REQUEST] = { + sizeof (struct ofp_header), + recv_features_request, + }, + [OFPT_GET_CONFIG_REQUEST] = { + sizeof (struct ofp_header), + recv_get_config_request, + }, + [OFPT_SET_CONFIG] = { + sizeof (struct ofp_switch_config), + recv_set_config, + }, + [OFPT_PACKET_OUT] = { + sizeof (struct ofp_packet_out), + recv_packet_out, + }, + [OFPT_FLOW_MOD] = { + sizeof (struct ofp_flow_mod), + recv_flow, + }, + [OFPT_PORT_MOD] = { + sizeof (struct ofp_port_mod), + recv_port_mod, + } + }; + + struct ofp_header *oh; + + oh = (struct ofp_header *) msg; + if (oh->version != OFP_VERSION + && oh->type != OFPT_HELLO + && oh->type != OFPT_ERROR + && oh->type != OFPT_ECHO_REQUEST + && oh->type != OFPT_ECHO_REPLY + && oh->type != OFPT_VENDOR) + { + dp_send_error_msg(chain->dp, sender, OFPET_BAD_REQUEST, + OFPBRC_BAD_VERSION, msg, length); + return -EINVAL; + } + if (ntohs(oh->length) != length) { + if (net_ratelimit()) + printk(KERN_NOTICE "%s: received message length " + "wrong: %d/%d\n", chain->dp->netdev->name, + ntohs(oh->length), length); + return -EINVAL; + } + + if (oh->type < ARRAY_SIZE(packets)) { + const struct openflow_packet *pkt = &packets[oh->type]; + if (pkt->handler) { + if (length < pkt->min_size) + return -EFAULT; + return pkt->handler(chain, sender, msg); + } + } + dp_send_error_msg(chain->dp, sender, OFPET_BAD_REQUEST, + OFPBRC_BAD_TYPE, msg, length); + return -EINVAL; +} + +/* Packet buffering. */ + +#define OVERWRITE_SECS 1 +#define OVERWRITE_JIFFIES (OVERWRITE_SECS * HZ) + +struct packet_buffer { + struct sk_buff *skb; + uint32_t cookie; + unsigned long exp_jiffies; +}; + +static struct packet_buffer buffers[N_PKT_BUFFERS]; +static unsigned int buffer_idx; +static DEFINE_SPINLOCK(buffer_lock); + +uint32_t fwd_save_skb(struct sk_buff *skb) +{ + struct sk_buff *old_skb = NULL; + struct packet_buffer *p; + unsigned long int flags; + uint32_t id; + + /* FIXME: Probably just need a skb_clone() here. */ + skb = skb_copy(skb, GFP_ATOMIC); + if (!skb) + return -1; + + spin_lock_irqsave(&buffer_lock, flags); + buffer_idx = (buffer_idx + 1) & PKT_BUFFER_MASK; + p = &buffers[buffer_idx]; + if (p->skb) { + /* Don't buffer packet if existing entry is less than + * OVERWRITE_SECS old. */ + if (time_before(jiffies, p->exp_jiffies)) { + spin_unlock_irqrestore(&buffer_lock, flags); + kfree_skb(skb); + return -1; + } else { + /* Defer kfree_skb() until interrupts re-enabled. + * FIXME: we only need to do that if it has a + * destructor, but it never should since we orphan + * sk_buffs on entry. */ + old_skb = p->skb; + } + } + /* Don't use maximum cookie value since the all-bits-1 id is + * special. */ + if (++p->cookie >= (1u << PKT_COOKIE_BITS) - 1) + p->cookie = 0; + p->skb = skb; + p->exp_jiffies = jiffies + OVERWRITE_JIFFIES; + id = buffer_idx | (p->cookie << PKT_BUFFER_BITS); + spin_unlock_irqrestore(&buffer_lock, flags); + + if (old_skb) + kfree_skb(old_skb); + + return id; +} + +static struct sk_buff *retrieve_skb(uint32_t id) +{ + unsigned long int flags; + struct sk_buff *skb = NULL; + struct packet_buffer *p; + + spin_lock_irqsave(&buffer_lock, flags); + p = &buffers[id & PKT_BUFFER_MASK]; + if (p->cookie == id >> PKT_BUFFER_BITS) { + skb = p->skb; + p->skb = NULL; + } else { + if (net_ratelimit()) + printk(KERN_NOTICE "cookie mismatch: %x != %x\n", + id >> PKT_BUFFER_BITS, p->cookie); + } + spin_unlock_irqrestore(&buffer_lock, flags); + + return skb; +} + +void fwd_discard_all(void) +{ + int i; + + for (i = 0; i < N_PKT_BUFFERS; i++) { + struct sk_buff *skb; + unsigned long int flags; + + /* Defer kfree_skb() until interrupts re-enabled. */ + spin_lock_irqsave(&buffer_lock, flags); + skb = buffers[i].skb; + buffers[i].skb = NULL; + spin_unlock_irqrestore(&buffer_lock, flags); + + kfree_skb(skb); + } +} + +static void discard_skb(uint32_t id) +{ + struct sk_buff *old_skb = NULL; + unsigned long int flags; + struct packet_buffer *p; + + spin_lock_irqsave(&buffer_lock, flags); + p = &buffers[id & PKT_BUFFER_MASK]; + if (p->cookie == id >> PKT_BUFFER_BITS) { + /* Defer kfree_skb() until interrupts re-enabled. */ + old_skb = p->skb; + p->skb = NULL; + } + spin_unlock_irqrestore(&buffer_lock, flags); + + if (old_skb) + kfree_skb(old_skb); +} + +void fwd_exit(void) +{ + fwd_discard_all(); +} diff --git a/openflow/datapath/forward.h b/openflow/datapath/forward.h new file mode 100644 index 00000000..2aa9ee37 --- /dev/null +++ b/openflow/datapath/forward.h @@ -0,0 +1,38 @@ +#ifndef FORWARD_H +#define FORWARD_H 1 + +#include +#include "datapath.h" +#include "flow.h" + +struct sk_buff; +struct sw_chain; +struct sender; + +/* Buffers are identified to userspace by a 31-bit opaque ID. We divide the ID + * into a buffer number (low bits) and a cookie (high bits). The buffer number + * is an index into an array of buffers. The cookie distinguishes between + * different packets that have occupied a single buffer. Thus, the more + * buffers we have, the lower-quality the cookie... */ +#define PKT_BUFFER_BITS 8 +#define N_PKT_BUFFERS (1 << PKT_BUFFER_BITS) +#define PKT_BUFFER_MASK (N_PKT_BUFFERS - 1) + +#define PKT_COOKIE_BITS (32 - PKT_BUFFER_BITS) + +#define UINT32_MAX 4294967295U +#define UINT16_MAX 65535 +#define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) + +void fwd_port_input(struct sw_chain *, struct sk_buff *, + struct net_bridge_port *); +int run_flow_through_tables(struct sw_chain *, struct sk_buff *, + struct net_bridge_port *); +int fwd_control_input(struct sw_chain *, const struct sender *, + const void *, size_t); + +uint32_t fwd_save_skb(struct sk_buff *skb); +void fwd_discard_all(void); +void fwd_exit(void); + +#endif /* forward.h */ diff --git a/openflow/datapath/hwtable_dummy/Modules.mk b/openflow/datapath/hwtable_dummy/Modules.mk new file mode 100644 index 00000000..08e56b1e --- /dev/null +++ b/openflow/datapath/hwtable_dummy/Modules.mk @@ -0,0 +1,7 @@ +# Specify the module to build. +build_modules += ofdatapath_dummy +dist_modules += ofdatapath_dummy + +# Specify the source files that comprise the module. +ofdatapath_dummy_sources = \ + hwtable_dummy/hwtable_dummy.c diff --git a/openflow/datapath/hwtable_dummy/hwtable_dummy.c b/openflow/datapath/hwtable_dummy/hwtable_dummy.c new file mode 100644 index 00000000..82150d0f --- /dev/null +++ b/openflow/datapath/hwtable_dummy/hwtable_dummy.c @@ -0,0 +1,320 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "chain.h" +#include "table.h" +#include "flow.h" +#include "datapath.h" + +/* Max number of flow entries supported by the hardware */ +#define TMPL_MAX_FLOWS 8192 + +/* sw_flow private data for dummy table entries. */ +struct tmpl_flow { + struct list_head nodes; + /* XXX: If per-entry data is needed, define it here. */ +}; + +struct tmpl_flowtable { + struct sw_table flowtab; + unsigned int max_flows; + atomic_t num_flows; + struct list_head flows; + struct list_head iter_flows; + unsigned long int next_serial; +}; + +static struct sw_flow *tmpl_flowtable_lookup(struct sw_table *, + const struct sw_flow_key *); +static int tmpl_install_flow(struct sw_table *, struct sw_flow *); +static int tmpl_modify_flow(struct sw_table *, const struct sw_flow_key *, + uint16_t, int, const struct ofp_action_header *, + size_t); +static int do_uninstall(struct datapath *, struct sw_table *, struct sw_flow *, + enum ofp_flow_removed_reason); +static int tmpl_uninstall_flow(struct datapath *, struct sw_table *, + const struct sw_flow_key *, + uint16_t, uint16_t, int); +static int tmpl_flow_timeout(struct datapath *, struct sw_table *); +static void tmpl_destroy_flowtable(struct sw_table *); +static int tmpl_iterate_flowtable(struct sw_table *, const struct sw_flow_key *, + uint16_t, struct sw_table_position *, + int (*)(struct sw_flow *, void *), void *); +static void tmpl_get_flowstats(struct sw_table *, struct sw_table_stats *); +static struct sw_table *tmpl_create_flowtable(void); +static int __init tmpl_startup(void); +static void tmpl_cleanup(void); + +static struct sw_flow * +tmpl_flowtable_lookup(struct sw_table *flowtab, const struct sw_flow_key *key) +{ + struct tmpl_flowtable *myflowtab = (struct tmpl_flowtable *)flowtab; + struct sw_flow *flow; + + list_for_each_entry(flow, &myflowtab->flows, node) { + if (flow_matches_1wild(key, &flow->key)) { + return flow; + } + } + + return NULL; +} + +static int +tmpl_install_flow(struct sw_table *flowtab, struct sw_flow *flow) +{ + /* XXX: Use a data cache? */ + flow->private = kzalloc(sizeof(struct tmpl_flow), GFP_ATOMIC); + if (flow->private == NULL) + return 0; + + /* XXX: Do whatever needs to be done to insert an entry in hardware. + * If the entry can't be inserted, return 0. This stub code doesn't + * do anything yet, so we're going to return 0... you shouldn't (and + * you should update n_flows in struct tmpl_flowtable, too). + */ + kfree(flow->private); + return 0; +} + +static int +tmpl_modify_flow(struct sw_table *flowtab, const struct sw_flow_key *key, + uint16_t priority, int strict, + const struct ofp_action_header *actions, size_t actions_len) +{ + struct tmpl_flowtable *myflowtab = (struct tmpl_flowtable *)flowtab; + struct sw_flow *flow; + unsigned int count = 0; + + list_for_each_entry(flow, &myflowtab->flows, node) { + if (flow_matches_desc(&flow->key, key, strict) + && (!strict || (flow->priority == priority))) { + flow_replace_acts(flow, actions, actions_len); + /* XXX: Do whatever is necessary to modify the entry + * in hardware + */ + count++; + } + } + + return count; +} + +static int +do_uninstall(struct datapath *dpinst, struct sw_table *flowtab, + struct sw_flow *flow, enum ofp_flow_removed_reason reason) +{ + /* XXX: Remove the entry from hardware. If you need to do any other + * clean-up associated with the entry, do it here. + */ + dp_send_flow_end(dpinst, flow, reason); + list_del_rcu(&flow->node); + list_del_rcu(&flow->iter_node); + flow_deferred_free(flow); + return 1; +} + +static int +tmpl_uninstall_flow(struct datapath *dpinst, struct sw_table *flowtab, + const struct sw_flow_key *key, uint16_t out_port, + uint16_t priority, int strict) +{ + struct tmpl_flowtable *myflowtab = (struct tmpl_flowtable *)flowtab; + struct sw_flow *flow; + unsigned int count = 0; + + list_for_each_entry(flow, &myflowtab->flows, node) { + if (flow_matches_desc(&flow->key, key, strict) + && (!strict || (flow->priority == priority))) + count += do_uninstall(dpinst, flowtab, + flow, OFPRR_DELETE); + } + + if (count != 0) + atomic_sub(count, &myflowtab->num_flows); + return count; +} + +static int +tmpl_flow_timeout(struct datapath *dpinst, struct sw_table *flowtab) +{ + struct tmpl_flowtable *myflowtab = (struct tmpl_flowtable *)flowtab; + struct sw_flow *flow; + int num_uninst_flows = 0; + uint64_t num_forw_packets = 0; + uint64_t num_forw_bytes = 0; + int reason; + + mutex_lock(&dp_mutex); + list_for_each_entry(flow, &myflowtab->flows, node) { + /* XXX: Retrieve the packet and byte counts associated with this + * entry and store them in "packet_count" and "byte_count". + */ +#if 0 + num_forw_pakcets = flow->packet_count + get_hwmib(...); + num_forw_bytes = flow->byte_count + get_hwmib(...); +#endif + if (num_forw_packets > flow->packet_count + && flow->idle_timeout != OFP_FLOW_PERMANENT) { + flow->packet_count = num_forw_packets; + flow->byte_count = num_forw_bytes; + flow->used = get_jiffies_64(); + } + reason = flow_timeout(flow); + if (reason >= 0) { + num_uninst_flows += do_uninstall(dpinst, flowtab, + flow, reason); + } + } + mutex_unlock(&dp_mutex); + + if (num_uninst_flows != 0) + atomic_sub(num_uninst_flows, &myflowtab->num_flows); + return num_uninst_flows; +} + +static void +tmpl_destroy_flowtable(struct sw_table *flowtab) +{ + struct tmpl_flowtable *myflowtab = (struct tmpl_flowtable *)flowtab; + + if (myflowtab == NULL) { + return; + } + + /* XXX: This table is being destroyed, so free any data that you + * don't want to leak. + */ + while (!list_empty(&myflowtab->flows)) { + struct sw_flow *flow = list_entry(myflowtab->flows.next, + struct sw_flow, node); + list_del(&flow->node); + flow_free(flow); + } + + kfree(myflowtab); +} + +static int +tmpl_iterate_flowtable(struct sw_table *flowtab, const struct sw_flow_key *key, + uint16_t out_port, struct sw_table_position *position, + int (*callback) (struct sw_flow *, void *), + void *private) +{ + struct tmpl_flowtable *myflowtab = (struct tmpl_flowtable *)flowtab; + struct sw_flow *flow; + unsigned long start; + int error = 0; + + start = ~position->private[0]; + list_for_each_entry(flow, &myflowtab->iter_flows, iter_node) { + if (flow->serial <= start + && flow_matches_2wild(key, &flow->key)) { + error = callback(flow, private); + if (error) { + position->private[0] = ~flow->serial; + return error; + } + } + } + + return error; +} + +static void +tmpl_get_flowstats(struct sw_table *flowtab, struct sw_table_stats *stats) +{ + struct tmpl_flowtable *myflowtab = (struct tmpl_flowtable *)flowtab; + + stats->name = "template"; + stats->wildcards = OFPFW_ALL; /* XXX: Set this appropriately */ + stats->n_flows = atomic_read(&myflowtab->num_flows); + stats->max_flows = myflowtab->max_flows; + stats->n_matched = flowtab->n_matched; +} + +static struct sw_table * +tmpl_create_flowtable(void) +{ + struct tmpl_flowtable *myflowtab; + struct sw_table *flowtab; + + myflowtab = kzalloc(sizeof(*myflowtab), GFP_KERNEL); + if (myflowtab == NULL) + return NULL; + + flowtab = &myflowtab->flowtab; + flowtab->lookup = tmpl_flowtable_lookup; + flowtab->insert = tmpl_install_flow; + flowtab->modify = tmpl_modify_flow; + flowtab->delete = tmpl_uninstall_flow; + flowtab->timeout = tmpl_flow_timeout; + flowtab->destroy = tmpl_destroy_flowtable; + flowtab->iterate = tmpl_iterate_flowtable; + flowtab->stats = tmpl_get_flowstats; + + myflowtab->max_flows = TMPL_MAX_FLOWS; + atomic_set(&myflowtab->num_flows, 0); + INIT_LIST_HEAD(&myflowtab->flows); + INIT_LIST_HEAD(&myflowtab->iter_flows); + myflowtab->next_serial = 0; + + return flowtab; +} + +static int __init +tmpl_startup(void) +{ + return chain_set_hw_hook(tmpl_create_flowtable, THIS_MODULE); +} + +static void +tmpl_cleanup(void) +{ + chain_clear_hw_hook(); +} + +module_init(tmpl_startup); +module_exit(tmpl_cleanup); + +MODULE_DESCRIPTION("Fastpath Extension Template for OpenFlow Switch"); +MODULE_AUTHOR("Copyright (c) 2008, 2009 " + "The Board of Trustees of The Leland Stanford Junior University"); +MODULE_LICENSE("GPL"); diff --git a/openflow/datapath/hwtable_nf2/Modules.mk b/openflow/datapath/hwtable_nf2/Modules.mk new file mode 100644 index 00000000..35674911 --- /dev/null +++ b/openflow/datapath/hwtable_nf2/Modules.mk @@ -0,0 +1,19 @@ +# Specify the module to build. +build_modules += ofdatapath_netfpga +dist_modules += ofdatapath_netfpga + +# Specify the source files that comprise the module. +ofdatapath_netfpga_sources = \ + hwtable_nf2/nf2_flowtable.c \ + hwtable_nf2/nf2_procfs.c \ + hwtable_nf2/nf2_openflow.c \ + hwtable_nf2/nf2_lib.c + +ofdatapath_netfpga_headers = \ + hwtable_nf2/nf2.h \ + hwtable_nf2/nf2_reg.h \ + hwtable_nf2/nf2_hwapi.h \ + hwtable_nf2/nf2_flowtable.h \ + hwtable_nf2/nf2_procfs.h \ + hwtable_nf2/nf2_openflow.h \ + hwtable_nf2/nf2_lib.h diff --git a/openflow/datapath/hwtable_nf2/README b/openflow/datapath/hwtable_nf2/README new file mode 100644 index 00000000..da700f01 --- /dev/null +++ b/openflow/datapath/hwtable_nf2/README @@ -0,0 +1,78 @@ +NetFPGA Hardware Table + Date - 09/04/09 +---------------------------------------- + +The NetFPGA Hardware Table creates a single software table that contains all +the flows that are currently held in the NetFPGA card. The card itself splits +exact match flows into SRAM and wildcard match flows into TCAMs. Currently +there are 24 usable wildcard flow entries and 32,768 available exact match +entries. + +Installation +---------------------------------------- + +First build OpenFlow ensuring you include the directive to build the +openflow_netfpga2 hardware table in your configure statement: + + % ./configure --with-l26=/lib/modules/`uname -r` --enable-hw-tables=nf2 + +To get debugging output from the NetFPGA hardware table uncomment the following +line from within /datapath/hwtable_nf2/nf2_flowtable.h, then recompile: + + #define NF2_DEBUG 1 + +For further help regarding building OpenFlow please see the INSTALL file in +the OpenFlow root directory. + +Platform support +---------------- + +OpenFlow v0.9 with hwtable_nf2 has been tested on CentOS 5.2(Linux 2.6.18), +which is the officially supported platform of NetFPGA. + +Running +---------------------------------------- + +Use nf2_download to download the openflow_switch.bit file that is located in +the /datapath/hwtable_nf2 folder: + + % nf2_download -r /datapath/hwtable_nf2/openflow_switch.bit + +'-r' option enables PHY interrupt for its link status changing, and OpenFlow +switch can detect it. + +Install the OpenFlow kernel module: + + % insmod /datapath/linux-2.6/openflow_mod.ko + +Install the NetFPGA Hardware Table kernel module: + + % insmod /datapath/linux-2.6/openflow_netfpga2_mod.ko + +Create an OpenFlow datapath: + + % /utilities/dpctl adddp nl:0 + +Add the NetFPGA interfaces to the datapath: + + % /utilities/dpctl addif nl:0 nf2c0 + % /utilities/dpctl addif nl:0 nf2c1 + % /utilities/dpctl addif nl:0 nf2c2 + % /utilities/dpctl addif nl:0 nf2c3 + +At this point your OpenFlow switch should be ready to go. + +While you are running OpenFlow switch, you can check the hardware information +including its bitfile version as follows: + + % cat /proc/net/openflow-netfpga + +Known Bugs +---------------------------------------- +* There is currently no support for priority amongst wildcard-match entries. + +Contact +------- +e-mail: openflow-discuss@lists.stanford.edu +www: http://openflowswitch.org/ + diff --git a/openflow/datapath/hwtable_nf2/nf2.h b/openflow/datapath/hwtable_nf2/nf2.h new file mode 100644 index 00000000..847d2b10 --- /dev/null +++ b/openflow/datapath/hwtable_nf2/nf2.h @@ -0,0 +1,424 @@ +/* **************************************************************************** + * $Id: nf2.h 3546 2008-04-03 00:12:27Z grg $ + * + * Module: nf2.h + * Project: NetFPGA 2 Linux Kernel Driver + * Description: Header file for kernel driver + * + * Change history: + * + */ + +#ifndef _NF2_H +#define _NF2_H 1 + +#define NF2_DEV_NAME "nf2" + +#include + +/* Maximum number of interfaces */ +#ifndef MAX_IFACE +#define MAX_IFACE 4 +#endif + +/* + * Register names and locations. + * + * Note that these names are not necessarily identical to + * those in NF2/hw/common/src/defines + */ + +/* CPCI registers */ +#define CPCI_REG_ID 0x000 +#define CPCI_REG_BOARD_ID 0x004 +#define CPCI_REG_CTRL 0x008 +#define CPCI_REG_RESET 0x00c +#define CPCI_REG_ERROR 0x010 +#define CPCI_REG_DUMMY 0x020 +#define CPCI_REG_INTERRUPT_MASK 0x040 +#define CPCI_REG_INTERRUPT_STATUS 0x044 +#define CPCI_REG_PROG_DATA 0x100 +#define CPCI_REG_PROG_STATUS 0x104 +#define CPCI_REG_PROG_CTRL 0x108 +#define CPCI_REG_DMA_I_ADDR 0x140 +#define CPCI_REG_DMA_E_ADDR 0x144 +#define CPCI_REG_DMA_I_SIZE 0x148 +#define CPCI_REG_DMA_E_SIZE 0x14c +#define CPCI_REG_DMA_I_CTRL 0x150 +#define CPCI_REG_DMA_E_CTRL 0x154 +#define CPCI_REG_DMA_MAX_XFER_TIME 0x180 +#define CPCI_REG_DMA_MAX_RETRIES 0x184 +#define CPCI_REG_CNET_MAX_XFER_TIME 0x188 +#define CPCI_REG_DMA_I_PKT_CNT 0x400 +#define CPCI_REG_DMA_E_PKT_CNT 0x404 +#define CPCI_REG_CPCI_REG_RD_CNT 0x408 +#define CPCI_REG_CPCI_REG_WR_CNT 0x40c +#define CPCI_REG_CNET_REG_RD_CNT 0x410 +#define CPCI_REG_CNET_REG_WR_CNT 0x414 + +#define CPCI_REG_N_CLK_COUNT 0x500 +#define CPCI_REG_P_MAX 0x504 +#define CPCI_REG_N_EXP 0x508 +#define CPCI_REG_P_CLK_CTR 0x510 +#define CPCI_REG_RESET_CTR 0x520 + +/* Base address for CNET registers */ +#define CNET_REG_BASE 0x400000 + +/* Added by nweaver for building memory manipulation + utilities */ +/* 2 MB SRAM size on current board, MAX and SIZE will + need to be changed if upgraded to 4 MB SRAMs */ +#define SRAM_SIZE 0x200000 + +#define SRAM_1_BASE 0x800000 +#define SRAM_1_MAX 0x9FFFFF + +#define SRAM_2_BASE 0xC00000 +#define SRAM_2_MAX 0xDFFFFF +/* end nweaver addition */ + +/* Device ID registers */ +#define NF2_DEVICE_ID 0x0400000 +#define NF2_REVISION 0x0400004 +#define NF2_DEVICE_STR 0x0400008 + +/* CNET registers */ +#define CNET_REG_ID (CNET_REG_BASE + 0x000) +#define CNET_REG_CTRL (CNET_REG_BASE + 0x004) +#define CNET_REG_RESET (CNET_REG_BASE + 0x008) +#define CNET_REG_ERROR (CNET_REG_BASE + 0x00C) +#define CNET_REG_ENABLE (CNET_REG_BASE + 0x010) +#define CNET_REG_WR_SRAM1_EOP (CNET_REG_BASE + 0x0F0) +#define CNET_REG_RD_SRAM1_EOP (CNET_REG_BASE + 0x0F4) +#define CNET_REG_WR_SRAM2_EOP (CNET_REG_BASE + 0x0F8) +#define CNET_REG_RD_SRAM2_EOP (CNET_REG_BASE + 0x0FC) +#define CNET_REG_MF_STATUS_0 (CNET_REG_BASE + 0x100) +#define CNET_REG_MF_TX_PKTS_SENT_0 (CNET_REG_BASE + 0x104) +#define CNET_REG_MF_RX_PKTS_RCVD_0 (CNET_REG_BASE + 0x108) +#define CNET_REG_MF_RX_PKTS_LOST_0 (CNET_REG_BASE + 0x10C) +#define CNET_REG_MAC_CONFIG_0 (CNET_REG_BASE + 0x110) +#define CNET_REG_MF_STATUS_1 (CNET_REG_BASE + 0x140) +#define CNET_REG_MF_TX_PKTS_SENT_1 (CNET_REG_BASE + 0x144) +#define CNET_REG_MF_RX_PKTS_RCVD_1 (CNET_REG_BASE + 0x148) +#define CNET_REG_MF_RX_PKTS_LOST_1 (CNET_REG_BASE + 0x14C) +#define CNET_REG_MAC_CONFIG_1 (CNET_REG_BASE + 0x150) +#define CNET_REG_MF_STATUS_2 (CNET_REG_BASE + 0x180) +#define CNET_REG_MF_TX_PKTS_SENT_2 (CNET_REG_BASE + 0x184) +#define CNET_REG_MF_RX_PKTS_RCVD_2 (CNET_REG_BASE + 0x188) +#define CNET_REG_MF_RX_PKTS_LOST_2 (CNET_REG_BASE + 0x18C) +#define CNET_REG_MAC_CONFIG_2 (CNET_REG_BASE + 0x190) +#define CNET_REG_MF_STATUS_3 (CNET_REG_BASE + 0x1C0) +#define CNET_REG_MF_TX_PKTS_SENT_3 (CNET_REG_BASE + 0x1C4) +#define CNET_REG_MF_RX_PKTS_RCVD_3 (CNET_REG_BASE + 0x1C8) +#define CNET_REG_MF_RX_PKTS_LOST_3 (CNET_REG_BASE + 0x1CC) +#define CNET_REG_MAC_CONFIG_3 (CNET_REG_BASE + 0x1D0) +#define CNET_REG_RXQ_NUM_PKTS_0 (CNET_REG_BASE + 0x200) +#define CNET_REG_RXQ_POINTERS_0 (CNET_REG_BASE + 0x204) +#define CNET_REG_RXQ_NUM_PKTS_1 (CNET_REG_BASE + 0x240) +#define CNET_REG_RXQ_POINTERS_1 (CNET_REG_BASE + 0x244) +#define CNET_REG_RXQ_NUM_PKTS_2 (CNET_REG_BASE + 0x280) +#define CNET_REG_RXQ_POINTERS_2 (CNET_REG_BASE + 0x284) +#define CNET_REG_RXQ_NUM_PKTS_3 (CNET_REG_BASE + 0x2C0) +#define CNET_REG_RXQ_POINTERS_3 (CNET_REG_BASE + 0x2C4) + +#define CNET_REG_MF_RX_PKTS_LOST_BAD_FCS_0 (CNET_REG_BASE + 0x114) +#define CNET_REG_MF_RX_PKTS_LOST_FULL_FIFO_0 (CNET_REG_BASE+0x118) +#define CNET_REG_MF_RX_GOOD_PKTS_RCVD_0 (CNET_REG_BASE+0x11C) +#define CNET_REG_MF_RX_GOOD_BYTES_RCVD_0 (CNET_REG_BASE+0x120) +#define CNET_REG_MF_TX_BYTES_SENT_0 (CNET_REG_BASE+0x124) +#define CNET_REG_MF_RX_PKTS_LOST_BAD_FCS_1 (CNET_REG_BASE+0x154) +#define CNET_REG_MF_RX_PKTS_LOST_FULL_FIFO_1 (CNET_REG_BASE+0x158) +#define CNET_REG_MF_RX_GOOD_PKTS_RCVD_1 (CNET_REG_BASE+0x15C) +#define CNET_REG_MF_RX_GOOD_BYTES_RCVD_1 (CNET_REG_BASE+0x160) +#define CNET_REG_MF_TX_BYTES_SENT_1 (CNET_REG_BASE+0x164) +#define CNET_REG_MF_RX_PKTS_LOST_BAD_FCS_2 (CNET_REG_BASE+0x194) +#define CNET_REG_MF_RX_PKTS_LOST_FULL_FIFO_2 (CNET_REG_BASE+0x198) +#define CNET_REG_MF_RX_GOOD_PKTS_RCVD_2 (CNET_REG_BASE+0x19C) +#define CNET_REG_MF_RX_GOOD_BYTES_RCVD_2 (CNET_REG_BASE+0x1A0) +#define CNET_REG_MF_TX_BYTES_SENT_2 (CNET_REG_BASE+0x1A4) +#define CNET_REG_MF_RX_PKTS_LOST_BAD_FCS_3 (CNET_REG_BASE+0x1D4) +#define CNET_REG_MF_RX_PKTS_LOST_FULL_FIFO_3 (CNET_REG_BASE+0x1D8) +#define CNET_REG_MF_RX_GOOD_PKTS_RCVD_3 (CNET_REG_BASE+0x1DC) +#define CNET_REG_MF_RX_GOOD_BYTES_RCVD_3 (CNET_REG_BASE+0x1E0) +#define CNET_REG_MF_TX_BYTES_SENT_3 (CNET_REG_BASE+0x1E4) + +#define CNET_MAC_CLK_CHK_CTRL (CNET_REG_BASE + 0xF00) +#define CNET_MAC_CLK_CHK_CNT_VALUE (CNET_REG_BASE + 0xF04) + +/* Base address for CNET PHY registers */ +#define PHY_REG_BASE 0x600000 + +#define PHY_REG_CMD (PHY_REG_BASE) +#define PHY_REG_STATUS (PHY_REG_BASE) + +/* + * CPCI register masks + */ + +/* ID Masks */ +#define ID_VERSION 0x00FFFFFF +#define ID_REVISION 0xFF000000 + +/* Board ID Masks */ +#define BOARD_ID 0x00000F00 +#define BOARD_ID_CONTROL 0x00000001 + +/* Control masks */ +#define CTRL_CNET_RESET 0x00000100 +#define CTRL_LED 0x00000001 + +/* RESET masks */ +#define RESET_CPCI 0x00000001 + +/* Error masks */ +#define ERR_CNET_READ_TIMEOUT 0x02000000 +#define ERR_CNET_ERROR 0x01000000 +#define ERR_PROG_BUF_OVERFLOW 0x00020000 +#define ERR_PROG_ERROR 0x00010000 +#define ERR_DMA_TIMEOUT 0x00000400 +#define ERR_DMA_RETRY_CNT_EXPIRED 0x00000200 +#define ERR_DMA_BUF_OVERFLOW 0x00000100 +#define ERR_DMA_RD_SIZE_ERROR 0x00000040 +#define ERR_DMA_WR_SIZE_ERROR 0x00000020 +#define ERR_DMA_RD_ADDR_ERROR 0x00000010 +#define ERR_DMA_WR_ADDR_ERROR 0x00000008 +#define ERR_DMA_RD_MAC_ERROR 0x00000004 +#define ERR_DMA_WR_MAC_ERROR 0x00000002 +#define ERR_DMA_FATAL_ERROR 0x00000001 + +#define ERR_DMA_SETUP_ERROR ( ERR_DMA_WR_MAC_ERROR | \ + ERR_DMA_RD_MAC_ERROR | \ + ERR_DMA_WR_ADDR_ERROR | \ + ERR_DMA_RD_ADDR_ERROR | \ + ERR_DMA_WR_SIZE_ERROR | \ + ERR_DMA_RD_SIZE_ERROR ) + +/* Interrupt masks */ +#define INT_DMA_RX_COMPLETE 0x80000000 +#define INT_DMA_TX_COMPLETE 0x40000000 +#define INT_PHY_INTERRUPT 0x20000000 +#define INT_PKT_AVAIL 0x00000100 +#define INT_CNET_ERROR 0x00000020 +#define INT_CNET_READ_TIMEOUT 0x00000010 +#define INT_PROG_ERROR 0x00000008 +#define INT_DMA_TRANSFER_ERROR 0x00000004 +#define INT_DMA_SETUP_ERROR 0x00000002 +#define INT_DMA_FATAL_ERROR 0x00000001 + +#define INT_UNKNOWN ~(INT_DMA_RX_COMPLETE | \ + INT_DMA_TX_COMPLETE | \ + INT_PHY_INTERRUPT | \ + INT_PKT_AVAIL | \ + INT_CNET_ERROR | \ + INT_CNET_READ_TIMEOUT | \ + INT_PROG_ERROR | \ + INT_DMA_TRANSFER_ERROR | \ + INT_DMA_SETUP_ERROR | \ + INT_DMA_FATAL_ERROR) + +/* Programming status */ +#define PROG_INIT 0x00010000 +#define PROG_DONE 0x00000100 +#define PROG_FIFO_EMPTY 0x00000002 +#define PROG_IN_PROGRESS 0x00000001 + +/* Programming control */ +#define PROG_CTRL_RESET 0x00000001 + +/* DMA control */ +#define DMA_CTRL_MAC 0x00000300 +#define DMA_CTRL_OWNER 0x00000001 + +/* + * CNET register masks + */ + +/* Reset masks */ +#define CNET_RESET_MAC 0x0000000F +#define CNET_RESET_MAC_3 0x00000008 +#define CNET_RESET_MAC_2 0x00000004 +#define CNET_RESET_MAC_1 0x00000002 +#define CNET_RESET_MAC_0 0x00000001 + +/* Error masks */ +#define CNET_ERROR_TX_UNDERRUN_MAC 0x000000F0 +#define CNET_ERROR_TX_UNDERRUN_MAC_3 0x00000080 +#define CNET_ERROR_TX_UNDERRUN_MAC_2 0x00000040 +#define CNET_ERROR_TX_UNDERRUN_MAC_1 0x00000020 +#define CNET_ERROR_TX_UNDERRUN_MAC_0 0x00000010 +#define CNET_ERROR_TX_OVERRUN_MAC 0x0000000F +#define CNET_ERROR_TX_OVERRUN_MAC_3 0x00000008 +#define CNET_ERROR_TX_OVERRUN_MAC_2 0x00000004 +#define CNET_ERROR_TX_OVERRUN_MAC_1 0x00000002 +#define CNET_ERROR_TX_OVERRUN_MAC_0 0x00000001 + +/* Enable masks */ +#define CNET_ENABLE_RX_FIFO 0x0000F000 +#define CNET_ENABLE_RX_FIFO_3 0x00008000 +#define CNET_ENABLE_RX_FIFO_2 0x00004000 +#define CNET_ENABLE_RX_FIFO_1 0x00002000 +#define CNET_ENABLE_RX_FIFO_0 0x00001000 +#define CNET_ENABLE_TX_MAC 0x00000F00 +#define CNET_ENABLE_TX_MAC_3 0x00000800 +#define CNET_ENABLE_TX_MAC_2 0x00000400 +#define CNET_ENABLE_TX_MAC_1 0x00000200 +#define CNET_ENABLE_TX_MAC_0 0x00000100 +#define CNET_ENABLE_DEBUG_TRISTATE 0x00000004 +#define CNET_ENABLE_INGRESS_ARBITER 0x00000002 +#define CNET_ENABLE_RX_DMA 0x00000001 + +/* MF Status masks */ +#define CNET_MF_STATUS_RX_FIFO_EMPTY 0x02000000 +#define CNET_MF_STATUS_RX_PKT_AVAIL 0x01000000 +#define CNET_MF_STATUS_RX_NUM_PKTS 0x00FF0000 +#define CNET_MF_STATUS_TX_FIFO_FULL 0x00000200 +#define CNET_MF_STATUS_TX_FIFO_NO_MAX_PKT 0x00000100 +#define CNET_MF_STATUS_TX_NUM_PKTS 0x000000FF + +/* MAC Config masks */ +#define CNET_MAC_CFG_FULL_DUPLEX 0x00000020 +#define CNET_MAC_CFG_TX_FCS_SUPPLIED 0x00000010 +#define CNET_MAC_CFG_RX_WANT_FCS 0x00000008 +#define CNET_MAC_CFG_JUMBO_ENABLE 0x00000004 + +#define CNET_MAC_CFG_SPEED 0x00000002 +#define CNET_MAC_CFG_1000_MBPS 0x00000002 +#define CNET_MAC_CFG_100_MBPS 0x00000001 +#define CNET_MAC_CFG_10_MBPS 0x00000000 + +#define CNET_RXQ_WR_PTR 0x00FF0000 +#define CNET_RXQ_RD_PTR 0x000000FF + +/* Phy register masks */ +#define PHY_RD_WR 0x80000000 +#define PHY_PHY 0x03000000 +#define PHY_ADDR 0x001F0000 +#define PHY_DATA 0x0000FFFF + +#define PHY_DONE 0x80000000 +#define PHY_DONE_CNT 0x001F0000 + +/* Defines to calculate register values */ +/* CPCI Funcs */ +#define NF2_GET_VERSION(x) (x & 0xFFFFFF) +#define NF2_GET_REVISION(x) ((x & 0xFF000000) >> 24) + +#define NF2_GET_BOARD_ID(x) ((x & BOARD_ID) >> 8) +#define NF2_GET_CONTROL(x) (x & BOARD_ID_CONTROL) + +#define NF2_GET_CNET_RESET(x) ((x & CTRL_CNET_RESET) >> 8) +#define NF2_GET_LED(x) (x & CTRL_LED) + +#define NF2_GET_RESET(x) (x & RESET_CPCI) + +#define NF2_GET_CNET_READ_TIMEOUT(x) ((x & ERR_CNET_READ_TIMEOUT) >> 25) +#define NF2_GET_CNET_ERROR(x) ((x & ERR_CNET_ERROR) >> 24) +#define NF2_GET_PROG_BUF_OVERFLOW(x) ((x & ERR_PROG_BUF_OVERFLOW) >> 12) +#define NF2_GET_PROG_ERROR(x) ((x & ERR_PROG_ERROR) >> 11) +#define NF2_GET_DMA_TIMEOUT(x) ((x & ERR_DMA_TIMEOUT) >> 10) +#define NF2_GET_DMA_RETRY_CNT_EXPIRED(x) \ + ((x & ERR_DMA_RETRY_CNT_EXPIRED) >> 9) +#define NF2_GET_DMA_BUF_OVERFLOW(x) ((x & ERR_DMA_BUF_OVERFLOW) >> 8) +#define NF2_GET_DMA_RD_SIZE_ERROR(x) ((x & ERR_DMA_RD_SIZE_ERROR) >> 6) +#define NF2_GET_DMA_WR_SIZE_ERROR(x) ((x & ERR_DMA_WR_SIZE_ERROR) >> 5) +#define NF2_GET_DMA_RD_ADDR_ERROR(x) ((x & ERR_DMA_RD_ADDR_ERROR) >> 4) +#define NF2_GET_DMA_WR_ADDR_ERROR(x) ((x & ERR_DMA_WR_ADDR_ERROR) >> 3) +#define NF2_GET_DMA_RD_MAC_ERROR(x) ((x & ERR_DMA_RD_MAC_ERROR) >> 2) +#define NF2_GET_DMA_WR_MAC_ERROR(x) ((x & ERR_DMA_WR_MAC_ERROR) >> 1) +#define NF2_GET_DMA_FATAL_ERROR(x) (x & ERR_DMA_FATAL_ERROR) + +#define NF2_GET_INT_DMA_TX_COMPLETE(x) ((x & INT_DMA_TX_COMPLETE) >> 31) +#define NF2_GET_INT_DMA_RX_COMPLETE(x) ((x & INT_DMA_RX_COMPLETE) >> 30) +#define NF2_GET_INT_PHY_INTERRUPT(x) ((x & INT_PHY_INTERRUPT) >> 29) +#define NF2_GET_INT_PKT_AVAIL(x) ((x & INT_PKT_AVAIL) >> 8) +#define NF2_GET_INT_CNET_ERROR(x) ((x & INT_CNET_ERROR) >> 5) +#define NF2_GET_INT_CNET_READ_TIMEOUT(x) \ + ((x & INT_CNET_READ_TIMEOUT) >> 4) +#define NF2_GET_INT_PROG_ERROR(x) ((x & INT_PROG_ERROR) >> 3) +#define NF2_GET_INT_DMA_TRANSFER_ERROR(x) \ + ((x & INT_DMA_TRANSFER_ERROR) >> 2) +#define NF2_GET_INT_DMA_SETUP_ERROR(x) ((x & INT_DMA_SETUP_ERROR) >> 1) +#define NF2_GET_INT_DMA_FATAL_ERROR(x) (x & INT_DMA_FATAL_ERROR) + +#define NF2_GET_PROG_INIT(x) ((x & PROG_INIT) >> 16) +#define NF2_GET_PROG_DONE(x) ((x & PROG_DONE) >> 8) +#define NF2_GET_PROG_FIFO_EMPTY(x) ((x & PROG_FIFO_EMPTY) >> 1) +#define NF2_GET_PROG_IN_PROGRESS(x) (x & PROG_IN_PROGRESS) + +#define NF2_GET_DMA_CTRL_MAC(x) ((x & DMA_CTRL_MAC) >> 8) +#define NF2_GET_DMA_CTRL_OWNER(x) (x & DMA_CTRL_OWNER) + +#define NF2_SET_DMA_CTRL_MAC(x) (x << 8) + +/* CNET Funcs */ +#define NF2_GET_CNET_VERSION(x) ((x & 0xFFFF0000) >> 16) +#define NF2_GET_CNET_DEVICE_ID(x) (x & 0xFFFF) + +#define NF2_GET_CNET_RESET_MAC(x) (x & CNET_RESET_MAC) + +#define NF2_GET_CNET_ERROR_TX_UNDERRUN_MAC(x) \ + ((x & CNET_ERROR_TX_UNDERRUN_MAC) >> 4) +#define NF2_GET_CNET_ERROR_TX_OVERRUN_MAC(x) \ + (x & CNET_ERROR_TX_OVERRUN_MAC) + +#define NF2_GET_CNET_ENABLE_RX_FIFO(x) ((x & CNET_ENABLE_RX_FIFO) >> 12) +#define NF2_GET_CNET_ENABLE_TX_MAC(x) ((x & CNET_ENABLE_TX_MAC) >> 8) +#define NF2_GET_CNET_ENABLE_DEBUG_TRISTATE(x) \ + ((x & CNET_ENABLE_DEBUG_TRISTATE) >> 2) +#define NF2_GET_CNET_ENABLE_INGRESS_ARBITER(x) \ + ((x & CNET_ENABLE_INGRESS_ARBITER) >> 1) +#define NF2_GET_CNET_ENABLE_RX_DMA(x) (x & CNET_ENABLE_RX_DMA) + +#define NF2_GET_CNET_MF_STATUS_RX_FIFO_EMPTY(x) \ + ((x & CNET_MF_STATUS_RX_FIFO_EMPTY) >> 25) +#define NF2_GET_CNET_MF_STATUS_RX_PKT_AVAIL(x) \ + ((x & CNET_MF_STATUS_RX_PKT_AVAIL) >> 24) +#define NF2_GET_CNET_MF_STATUS_RX_NUM_PKTS(x) \ + ((x & CNET_MF_STATUS_RX_NUM_PKTS) >> 16) +#define NF2_GET_CNET_MF_STATUS_TX_FIFO_FULL(x) \ + ((x & CNET_MF_STATUS_TX_FIFO_FULL) >> 9) +#define NF2_GET_CNET_MF_STATUS_TX_FIFO_NO_MAX_PKT(x) \ + ((x & CNET_MF_STATUS_TX_FIFO_NO_MAX_PKT) >> 8) +#define NF2_GET_CNET_MF_STATUS_TX_NUM_PKTS(x) \ + (x & CNET_MF_STATUS_TX_NUM_PKTS) + +#define NF2_GET_CNET_MAC_CFG_FULL_DUPLEX(x) \ + ((x & CNET_MAC_CFG_FULL_DUPLEX) >> 5) +#define NF2_GET_CNET_MAC_CFG_TX_FCS_SUPPLIED(x) \ + ((x & CNET_MAC_CFG_TX_FCS_SUPPLIED) >> 4) +#define NF2_GET_CNET_MAC_CFG_RX_WANT_FCS(x) \ + ((x & CNET_MAC_CFG_RX_WANT_FCS) >> 3) +#define NF2_GET_CNET_MAC_CFG_JUMBO_ENABLE(x) \ + ((x & CNET_MAC_CFG_JUMBO_ENABLE) >> 2) +#define NF2_GET_CNET_MAC_CFG_SPEED(x) \ + (x & CNET_MAC_CFG_SPEED) + +#define NF2_GET_CNET_RXQ_WR_PTR(x) ((x & CNET_RXQ_WR_PTR) >> 16) +#define NF2_GET_CNET_RXQ_RD_PTR(x) (x & CNET_RXQ_RD_PTR) + +/* PHY functions */ +#define NF2_SET_PHY_IS_READ(x) (x << 31) +#define NF2_SET_PHY_SELECT(x) (x << 24) +#define NF2_SET_PHY_ADDR(x) (x << 16) +#define NF2_SET_PHY_DATA(x) (x) + +#define NF2_GET_PHY_DATA(x) (x & PHY_DATA) +#define NF2_GET_PHY_DONE(x) ((x & PHY_DONE) >> 31) +#define NF2_GET_PHY_DONE_CNT(x) ((x & PHY_DONE_CNT) >> 16) + +/* + * IOCTLs + */ +#define SIOCREGREAD SIOCDEVPRIVATE +#define SIOCREGWRITE (SIOCDEVPRIVATE + 1) + +/* + * Structure for transferring register data via an IOCTL + */ +struct nf2reg { + unsigned int reg; + unsigned int val; +}; + +#endif diff --git a/openflow/datapath/hwtable_nf2/nf2_flowtable.c b/openflow/datapath/hwtable_nf2/nf2_flowtable.c new file mode 100644 index 00000000..75eb3223 --- /dev/null +++ b/openflow/datapath/hwtable_nf2/nf2_flowtable.c @@ -0,0 +1,452 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "chain.h" +#include "table.h" +#include "flow.h" +#include "datapath.h" + +#include "hwtable_nf2/nf2_reg.h" +#include "hwtable_nf2/nf2_flowtable.h" +#include "hwtable_nf2/nf2_openflow.h" +#include "hwtable_nf2/nf2_lib.h" +#include "hwtable_nf2/nf2_procfs.h" + +struct nf2_flowtable { + struct sw_table flowtab; + spinlock_t lock; + unsigned int max_flows; + atomic_t num_flows; + struct list_head flows; + struct list_head iter_flows; + unsigned long int next_serial; +}; + +static struct sw_flow *nf2_lookup_flowtable(struct sw_table *, + const struct sw_flow_key *); +static int nf2_install_flow(struct sw_table *, struct sw_flow *); +static int nf2_modify_flow(struct sw_table *, const struct sw_flow_key *, + uint16_t, int, const struct ofp_action_header *, + size_t); +static void deferred_uninstall_callback(struct rcu_head *); +static void do_deferred_uninstall(struct sw_flow *); +static int do_uninstall(struct datapath *, struct sw_table *, struct sw_flow *, + enum ofp_flow_removed_reason); +static int nf2_has_conflict(struct sw_table *, const struct sw_flow_key *, + uint16_t, int); +static int nf2_uninstall_flow(struct datapath *, struct sw_table *, + const struct sw_flow_key *, uint16_t, + uint16_t, int); +static int nf2_flow_timeout(struct datapath *, struct sw_table *); +static void nf2_destroy_flowtable(struct sw_table *); +static int nf2_iterate_flowtable(struct sw_table *, + const struct sw_flow_key *, + uint16_t, struct sw_table_position *, + int (*)(struct sw_flow *, void *), void *); +unsigned long int get_lookup_matched_stats(void); +unsigned long int get_lookup_stats(void); +static void nf2_get_flowstats(struct sw_table *, struct sw_table_stats *); +static struct sw_table *nf2_create_flowtable(void); +static int __init nf2_startup(void); +static void nf2_cleanup(void); + +static struct sw_flow * +nf2_lookup_flowtable(struct sw_table *flowtab, const struct sw_flow_key *key) +{ + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + struct sw_flow *flow; + + list_for_each_entry(flow, &nf2flowtab->flows, node) { + if (flow_matches_1wild(key, &flow->key)) { + return flow; + } + } + + return NULL; +} + +static int +nf2_install_flow(struct sw_table *flowtab, struct sw_flow *flow) +{ + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + + /* Delete flows that match exactly. */ + nf2_uninstall_flow(NULL, flowtab, &flow->key, OFPP_NONE, + flow->priority, true); + + if (nf2_are_actions_supported(flow)) { + if (nf2_build_and_write_flow(flow)) { + return 0; + } + } else { + /* Unsupported actions or no netdevice. */ + return 0; + } + + atomic_inc(&nf2flowtab->num_flows); + list_add_rcu(&flow->node, &nf2flowtab->flows); + list_add_rcu(&flow->iter_node, &nf2flowtab->iter_flows); + return 1; +} + +static int +nf2_modify_flow(struct sw_table *flowtab, const struct sw_flow_key *key, + uint16_t priority, int strict, + const struct ofp_action_header *actions, size_t actions_len) +{ + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + struct sw_flow *flow; + unsigned int count = 0; + + list_for_each_entry(flow, &nf2flowtab->flows, node) { + if (flow_matches_desc(&flow->key, key, strict) + && (!strict || flow->priority == priority)) { + flow_replace_acts(flow, actions, actions_len); + if (nf2_are_actions_supported(flow)) { + count += nf2_modify_acts(flowtab, flow); + } + } else { + return 0; + } + } + + return count; +} + +static int +nf2_has_conflict(struct sw_table *flowtab, const struct sw_flow_key *key, + uint16_t priority, int strict) +{ + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + struct sw_flow *flow; + + list_for_each_entry(flow, &nf2flowtab->flows, node) { + if (flow_matches_desc(&flow->key, key, strict) + && (flow->priority == priority)) { + return true; + } + } + return false; +} + +static void +deferred_uninstall_callback(struct rcu_head *rcu) +{ + struct sw_flow *flow = container_of(rcu, struct sw_flow, rcu); + + flow_free(flow); +} + +static void +do_deferred_uninstall(struct sw_flow *flow) +{ + call_rcu(&flow->rcu, deferred_uninstall_callback); +} + +static int +do_uninstall(struct datapath *dpinst, struct sw_table *flowtab, + struct sw_flow *flow, enum ofp_flow_removed_reason reason) +{ + if (flow != NULL && flow->private != NULL) { + if (dpinst != NULL) + dp_send_flow_end(dpinst, flow, reason); + list_del_rcu(&flow->node); + list_del_rcu(&flow->iter_node); + nf2_delete_private(flow->private); + do_deferred_uninstall(flow); + return 1; + } + + return 0; +} + +static int +nf2_uninstall_flow(struct datapath *dpinst, struct sw_table *flowtab, + const struct sw_flow_key *key, uint16_t out_port, + uint16_t priority, int strict) +{ + struct net_device *netdev; + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + struct sw_flow *flow; + struct nf2_flow *nf2flow; + unsigned int count = 0; + + netdev = nf2_get_net_device(); + if (netdev == NULL) + return 0; + + list_for_each_entry(flow, &nf2flowtab->flows, node) { + if (flow_matches_desc(&flow->key, key, strict) + && (!strict || flow->priority == priority) + && flow_has_out_port(flow, out_port)) { + nf2flow = flow->private; + if (nf2flow != NULL) { + flow->packet_count + += nf2_get_packet_count(netdev, + nf2flow); + flow->byte_count += nf2_get_byte_count(netdev, + nf2flow); + } + count += do_uninstall(dpinst, flowtab, + flow, OFPRR_DELETE); + } + } + if (count != 0) + atomic_sub(count, &nf2flowtab->num_flows); + + nf2_free_net_device(netdev); + + return count; +} + +static int +nf2_flow_timeout(struct datapath *dpinst, struct sw_table *flowtab) +{ + struct net_device *netdev; + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + struct sw_flow *flow; + struct nf2_flow *nf2flow; + int num_uninst_flows = 0; + uint64_t num_forw_packets = 0; + int reason; + + netdev = nf2_get_net_device(); + if (netdev == NULL) + return num_uninst_flows; + + mutex_lock(&dp_mutex); + list_for_each_entry(flow, &nf2flowtab->flows, node) { + nf2flow = flow->private; + if (nf2flow != NULL) { + num_forw_packets = flow->packet_count + + nf2_get_packet_count(netdev, nf2flow); + flow->byte_count += nf2_get_byte_count(netdev, nf2flow); + } + if (num_forw_packets > flow->packet_count + && flow->idle_timeout != OFP_FLOW_PERMANENT) { + flow->packet_count = num_forw_packets; + flow->used = get_jiffies_64(); + } + reason = flow_timeout(flow); + if (reason >= 0) { + num_uninst_flows += do_uninstall(dpinst, flowtab, + flow, reason); + } + } + mutex_unlock(&dp_mutex); + + nf2_clear_watchdog(netdev); + + nf2_free_net_device(netdev); + + if (num_uninst_flows != 0) + atomic_sub(num_uninst_flows, &nf2flowtab->num_flows); + return num_uninst_flows; +} + +static void +nf2_destroy_flowtable(struct sw_table *flowtab) +{ + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + struct nf2_flow *nf2flow = NULL; + + if (nf2flowtab == NULL) + return; + + while (!list_empty(&nf2flowtab->flows)) { + struct sw_flow *flow = list_entry(nf2flowtab->flows.next, + struct sw_flow, node); + + list_del(&flow->node); + if (flow->private) { + nf2flow = (struct nf2_flow *)flow->private; + + if (nf2flow->type == NF2_TABLE_EXACT) { + nf2_add_free_exact(nf2flow); + } else if (nf2flow->type == NF2_TABLE_WILDCARD) { + nf2_add_free_wildcard(nf2flow); + } + flow->private = NULL; + } + flow_free(flow); + } + kfree(nf2flowtab); + + nf2_destroy_exact_freelist(); + nf2_destroy_wildcard_freelist(); +} + +static int +nf2_iterate_flowtable(struct sw_table *flowtab, const struct sw_flow_key *key, + uint16_t out_port, struct sw_table_position *position, + int (*callback) (struct sw_flow *, void *), void *private) +{ + unsigned long start; + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + struct sw_flow *flow; + int error = 0; + + start = ~position->private[0]; + list_for_each_entry(flow, &nf2flowtab->iter_flows, iter_node) { + if (flow->serial <= start && flow_matches_2wild(key, &flow->key) + && flow_has_out_port(flow, out_port)) { + error = callback(flow, private); + if (error != 0) { + position->private[0] = ~flow->serial; + return error; + } + } + } + + return error; +} + +unsigned long int +get_lookup_stats(void) +{ + struct net_device *netdev; + unsigned long int num_searched = 0; + + netdev = nf2_get_net_device(); + if (netdev == NULL) + return num_searched; + + num_searched = nf2_get_missed_count(netdev); + nf2_free_net_device(netdev); + num_searched += get_lookup_matched_stats(); + return num_searched; +} + +unsigned long int +get_lookup_matched_stats(void) +{ + struct net_device *netdev; + unsigned long int num_matched = 0; + + netdev = nf2_get_net_device(); + if (netdev == NULL) + return num_matched; + + num_matched = nf2_get_matched_count(netdev); + nf2_free_net_device(netdev); + return num_matched; +} + +static void +nf2_get_flowstats(struct sw_table *flowtab, struct sw_table_stats *stats) +{ + struct nf2_flowtable *nf2flowtab = (struct nf2_flowtable *)flowtab; + + stats->name = "nf2"; + stats->wildcards = OPENFLOW_WILDCARD_TABLE_SIZE - 8; + stats->n_flows = atomic_read(&nf2flowtab->num_flows); + stats->max_flows = nf2flowtab->max_flows; + stats->n_lookup = get_lookup_stats(); + stats->n_matched = get_lookup_matched_stats(); +} + +static struct sw_table * +nf2_create_flowtable(void) +{ + struct net_device *netdev; + struct nf2_flowtable *nf2flowtab; + struct sw_table *flowtab; + + netdev = nf2_get_net_device(); + if (netdev == NULL) + return NULL; + + nf2_reset_card(netdev); + nf2_free_net_device(netdev); + + nf2flowtab = kzalloc(sizeof(*nf2flowtab), GFP_KERNEL); + if (nf2flowtab == NULL) { + nf2_free_net_device(netdev); + return NULL; + } + + flowtab = &nf2flowtab->flowtab; + flowtab->n_lookup = (unsigned long long)get_lookup_stats(); + flowtab->n_matched = (unsigned long long)get_lookup_matched_stats(); + flowtab->lookup = nf2_lookup_flowtable; + flowtab->insert = nf2_install_flow; + flowtab->modify = nf2_modify_flow; + flowtab->has_conflict = nf2_has_conflict; + flowtab->delete = nf2_uninstall_flow; + flowtab->timeout = nf2_flow_timeout; + flowtab->destroy = nf2_destroy_flowtable; + flowtab->iterate = nf2_iterate_flowtable; + flowtab->stats = nf2_get_flowstats; +#define RESERVED_FOR_CPU2NETFPGA 8 + nf2flowtab->max_flows = OPENFLOW_NF2_EXACT_TABLE_SIZE + + OPENFLOW_WILDCARD_TABLE_SIZE - RESERVED_FOR_CPU2NETFPGA; + atomic_set(&nf2flowtab->num_flows, 0); + INIT_LIST_HEAD(&nf2flowtab->flows); + INIT_LIST_HEAD(&nf2flowtab->iter_flows); + nf2flowtab->next_serial = 0; + + nf2_init_wildcard_freelist(); + nf2_write_static_wildcard(); + nf2_init_exact_freelist(); + + return flowtab; +} + +static int __init +nf2_startup(void) +{ + nf2_create_procfs(); + return chain_set_hw_hook(nf2_create_flowtable, THIS_MODULE); +} + +static void +nf2_cleanup(void) +{ + nf2_remove_procfs(); + chain_clear_hw_hook(); +} + +module_init(nf2_startup); +module_exit(nf2_cleanup); + +MODULE_DESCRIPTION("NetFPGA Fastpath Extension for OpenFlow Switch"); +MODULE_AUTHOR("Copyright (c) 2008, 2009 " + "The Board of Trustees of The Leland Stanford Junior University"); +MODULE_LICENSE("GPL"); diff --git a/openflow/datapath/hwtable_nf2/nf2_flowtable.h b/openflow/datapath/hwtable_nf2/nf2_flowtable.h new file mode 100644 index 00000000..45aca5c7 --- /dev/null +++ b/openflow/datapath/hwtable_nf2/nf2_flowtable.h @@ -0,0 +1,63 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#ifndef HWTABLE_NF2_NF2_FLOWTABLE_ +#define HWTABLE_NF2_NF2_FLOWTABLE_ + +struct nf2_flow { + struct list_head node; + uint32_t pos; + uint32_t type; + uint32_t hw_packet_count; + uint32_t hw_byte_count; +}; + +enum nf2_of_table_type { + NF2_TABLE_EXACT, + NF2_TABLE_WILDCARD +}; + +/* #define NF2_DEBUG 1 */ + +#ifdef NF2_DEBUG +#ifdef __KERNEL__ +#define NF2DEBUGMSG(f, s...) printk(f, ## s) +#else +#define NF2DEBUGMSG(f, s...) printf(f, ## s) +#endif /* __KERNEL__ */ +#else +#define NF2DEBUGMSG(f, s...) +#endif + +/* #define NF2_WATCHDOG 1 */ + +#endif diff --git a/openflow/datapath/hwtable_nf2/nf2_hwapi.h b/openflow/datapath/hwtable_nf2/nf2_hwapi.h new file mode 100644 index 00000000..1a3e7aa1 --- /dev/null +++ b/openflow/datapath/hwtable_nf2/nf2_hwapi.h @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#ifndef HWTABLE_NF2_NF2_HWAPI_H_ +#define HWTABLE_NF2_NF2_HWAPI_H_ + +#ifdef __KERNEL__ + +int nf2k_reg_read(struct net_device *, unsigned int, void *); +int nf2k_reg_write(struct net_device *, unsigned int, void *); + +#endif /* __KERNEL__ */ + +#endif diff --git a/openflow/datapath/hwtable_nf2/nf2_lib.c b/openflow/datapath/hwtable_nf2/nf2_lib.c new file mode 100644 index 00000000..67acd433 --- /dev/null +++ b/openflow/datapath/hwtable_nf2/nf2_lib.c @@ -0,0 +1,918 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#include + +#include "crc32.h" +#include "flow.h" +#include "table.h" +#include "compat26.h" + +#include "hwtable_nf2/nf2.h" +#include "hwtable_nf2/nf2_reg.h" +#include "hwtable_nf2/nf2_hwapi.h" +#include "hwtable_nf2/nf2_flowtable.h" +#include "hwtable_nf2/nf2_openflow.h" +#include "hwtable_nf2/nf2_lib.h" + +#define MAX_INT_32 0xFFFFFFFF +#define PORT_BASE 1 + +#define VID_BITMASK 0x0FFF +#define PCP_BITSHIFT 13 +#define PCP_BITMASK 0xE000 + +struct list_head wildcard_free_list; +struct nf2_flow *exact_free_list[OPENFLOW_NF2_EXACT_TABLE_SIZE]; + +static uint32_t make_nw_wildcard(int); +static struct nf2_flow *get_free_exact(nf2_of_entry_wrap *); +static struct nf2_flow *get_free_wildcard(void); +static int is_action_forward_all(struct sw_flow *); +static void populate_action_output(nf2_of_action_wrap *, nf2_of_entry_wrap *, + uint8_t *); +static void populate_action_set_dl_src(nf2_of_action_wrap *, uint8_t *); +static void populate_action_set_dl_dst(nf2_of_action_wrap *, uint8_t *); + +struct net_device * +nf2_get_net_device(void) +{ + return dev_get_by_name(&init_net, "nf2c0"); +} + +void +nf2_free_net_device(struct net_device *dev) +{ + if (dev == NULL) + return; + + dev_put(dev); +} + +/* Checks to see if the actions requested by the flow are capable of being + * done in the NF2 hardware. Returns 1 if yes, 0 for no. + */ +int +nf2_are_actions_supported(struct sw_flow *flow) +{ + struct sw_flow_actions *sfa; + size_t actions_len; + uint8_t *p; + + sfa = flow->sf_acts; + actions_len = sfa->actions_len; + p = (uint8_t *)sfa->actions; + + while (actions_len > 0) { + struct ofp_action_header *ah = (struct ofp_action_header *)p; + struct ofp_action_output *oa = (struct ofp_action_output *)p; + size_t len = ntohs(ah->len); + + NF2DEBUGMSG("Action Support Chk: Len of this action: %i\n", + len); + NF2DEBUGMSG("Action Support Chk: Len of actions : %i\n", + actions_len); + + // Currently, output port(s) action, dl_src/dst rewrite actions + // are suported. + if (!(ntohs(ah->type) == OFPAT_OUTPUT + || ntohs(ah->type) == OFPAT_SET_DL_SRC + || ntohs(ah->type) == OFPAT_SET_DL_DST)) { + NF2DEBUGMSG + ("Flow action type %#0x not supported in hardware\n", + ntohs(ah->type)); + return 0; + } + // Only support ports 1-4(incl. IN_PORT), ALL, FLOOD. + // Let CONTROLLER/LOCAL fall through + if ((ntohs(ah->type) == OFPAT_OUTPUT) + && (!((ntohs(oa->port) >= PORT_BASE) + && (ntohs(oa->port) <= MAX_IFACE)) + && !(ntohs(oa->port) == OFPP_ALL) + && !(ntohs(oa->port) == OFPP_FLOOD) + && !(ntohs(oa->port) == OFPP_IN_PORT))) { + NF2DEBUGMSG + ("Flow action output port %#0x is not supported in hardware\n", + ntohs(oa->port)); + return 0; + } + p += len; + actions_len -= len; + } + + return 1; +} + +/* Write all 0's out to an exact entry position. */ +void +nf2_clear_of_exact(uint32_t pos) +{ + nf2_of_entry_wrap entry; + nf2_of_action_wrap action; + struct net_device *dev = NULL; + + memset(&entry, 0, sizeof(nf2_of_entry_wrap)); + memset(&action, 0, sizeof(nf2_of_action_wrap)); + + dev = nf2_get_net_device(); + if (dev == NULL) + return; + + nf2_write_of_exact(dev, pos, &entry, &action); + nf2_free_net_device(dev); +} + +/* + * Write all 0's out to a wildcard entry position + */ +void +nf2_clear_of_wildcard(uint32_t pos) +{ + nf2_of_entry_wrap entry; + nf2_of_mask_wrap mask; + nf2_of_action_wrap action; + struct net_device *dev = NULL; + + memset(&entry, 0, sizeof(nf2_of_entry_wrap)); + memset(&mask, 0, sizeof(nf2_of_mask_wrap)); + memset(&action, 0, sizeof(nf2_of_action_wrap)); + + dev = nf2_get_net_device(); + if (dev == NULL) + return; + + nf2_write_of_wildcard(dev, pos, &entry, &mask, &action); + nf2_free_net_device(dev); +} + +int +nf2_init_exact_freelist(void) +{ + struct nf2_flow *sfw = NULL; + int i; + + for (i = 0; i < (OPENFLOW_NF2_EXACT_TABLE_SIZE); ++i) { + sfw = kzalloc(sizeof(struct nf2_flow), GFP_ATOMIC); + if (sfw == NULL) { + return 1; + } + sfw->pos = i; + sfw->type = NF2_TABLE_EXACT; + nf2_add_free_exact(sfw); + sfw = NULL; + } + + return 0; +} + +int +nf2_init_wildcard_freelist(void) +{ + struct nf2_flow *sfw = NULL; + int i; + INIT_LIST_HEAD(&wildcard_free_list); + + for (i = 0; i < (OPENFLOW_WILDCARD_TABLE_SIZE - 8); ++i) { + sfw = kzalloc(sizeof(struct nf2_flow), GFP_ATOMIC); + if (sfw == NULL) { + return 1; + } + sfw->pos = i; + sfw->type = NF2_TABLE_WILDCARD; + nf2_add_free_wildcard(sfw); + sfw = NULL; + } + + return 0; +} + +/* Called when the table is being deleted. */ +void +nf2_destroy_exact_freelist(void) +{ + struct nf2_flow *sfw = NULL; + int i; + + for (i = 0; i < (OPENFLOW_NF2_EXACT_TABLE_SIZE); ++i) { + sfw = exact_free_list[i]; + if (sfw) { + kfree(sfw); + } + sfw = NULL; + } +} + +/* Called when the table is being deleted. */ +void +nf2_destroy_wildcard_freelist(void) +{ + struct nf2_flow *sfw = NULL; + struct list_head *next = NULL; + + while (!list_empty(&wildcard_free_list)) { + next = wildcard_free_list.next; + sfw = list_entry(next, struct nf2_flow, node); + list_del(&sfw->node); + kfree(sfw); + } +} + +/* Setup the wildcard table by adding static flows that will handle + * misses by sending them up to the cpu ports, and handle packets coming + * back down from the cpu by sending them out the corresponding port. + */ +int +nf2_write_static_wildcard(void) +{ + nf2_of_entry_wrap entry; + nf2_of_mask_wrap mask; + nf2_of_action_wrap action; + int i; + struct net_device *dev; + + dev = nf2_get_net_device(); + if (dev == NULL) + return 1; + + memset(&entry, 0x00, sizeof(nf2_of_entry_wrap)); + memset(&mask, 0xFF, sizeof(nf2_of_mask_wrap)); + // Only non-wildcard section is the source port + mask.entry.src_port = 0; + memset(&action, 0, sizeof(nf2_of_action_wrap)); + + // write the catch all entries to send to the cpu + for (i = 0; i < 4; ++i) { + entry.entry.src_port = i * 2; + action.action.forward_bitmask = 0x1 << ((i * 2) + 1); + nf2_write_of_wildcard(dev, (OPENFLOW_WILDCARD_TABLE_SIZE - 4) + + i, &entry, &mask, &action); + } + + // write the entries to send out packets coming from the cpu + for (i = 0; i < 4; ++i) { + entry.entry.src_port = (i * 2) + 1; + action.action.forward_bitmask = 0x1 << (i * 2); + nf2_write_of_wildcard(dev, (OPENFLOW_WILDCARD_TABLE_SIZE - 8) + + i, &entry, &mask, &action); + } + + nf2_free_net_device(dev); + return 0; +} + +/* Populate a nf2_of_entry_wrap with entries from a struct sw_flow. */ +void +nf2_populate_of_entry(nf2_of_entry_wrap *key, struct sw_flow *flow) +{ + int vlan_vid; + int vlan_pcp; + int i; + + key->entry.transp_dst = ntohs(flow->key.tp_dst); + key->entry.transp_src = ntohs(flow->key.tp_src); + key->entry.ip_proto = flow->key.nw_proto; + key->entry.ip_dst = ntohl(flow->key.nw_dst); + key->entry.ip_src = ntohl(flow->key.nw_src); + key->entry.eth_type = ntohs(flow->key.dl_type); + // Blame Jad for applying endian'ness to character arrays + for (i = 0; i < 6; ++i) { + key->entry.eth_dst[i] = flow->key.dl_dst[5 - i]; + } + for (i = 0; i < 6; ++i) { + key->entry.eth_src[i] = flow->key.dl_src[5 - i]; + } + + key->entry.src_port = (ntohs(flow->key.in_port) - PORT_BASE) * 2; + + if (ntohs(flow->key.dl_vlan) == 0xffff) { + key->entry.vlan_id = 0xffff; + } else { + vlan_vid = VID_BITMASK & ntohs(flow->key.dl_vlan); + vlan_pcp = PCP_BITMASK + & ((uint16_t)(flow->key.dl_vlan_pcp) << PCP_BITSHIFT); + key->entry.vlan_id = vlan_pcp | vlan_vid; + } +} + +static uint32_t +make_nw_wildcard(int n_wild_bits) +{ + n_wild_bits &= (1u << OFPFW_NW_SRC_BITS) - 1; + return n_wild_bits < 32 ? ((1u << n_wild_bits) - 1) : 0xFFFFFFFF; +} + +/* Populate a nf2_of_mask_wrap with entries from a struct sw_flow's wildcards. */ +void +nf2_populate_of_mask(nf2_of_mask_wrap *mask, struct sw_flow *flow) +{ + int vlan_vid = 0; + int vlan_pcp = 0; + int i; + + if (OFPFW_IN_PORT & flow->key.wildcards) { + mask->entry.src_port = 0xFF; + } + if (OFPFW_DL_VLAN & flow->key.wildcards) { + vlan_vid = 0x0FFF; + } + if (OFPFW_DL_VLAN_PCP & flow->key.wildcards) { + vlan_pcp = 0xE000; + } + mask->entry.vlan_id = vlan_pcp | vlan_vid; + if (OFPFW_DL_SRC & flow->key.wildcards) { + for (i = 0; i < 6; ++i) { + mask->entry.eth_src[i] = 0xFF; + } + } + if (OFPFW_DL_DST & flow->key.wildcards) { + for (i = 0; i < 6; ++i) { + mask->entry.eth_dst[i] = 0xFF; + } + } + if (OFPFW_DL_TYPE & flow->key.wildcards) + mask->entry.eth_type = 0xFFFF; + if ((OFPFW_NW_SRC_ALL & flow->key.wildcards) + || (OFPFW_NW_SRC_MASK & flow->key.wildcards)) + mask->entry.ip_src = make_nw_wildcard + (flow->key.wildcards >> OFPFW_NW_SRC_SHIFT); + if ((OFPFW_NW_DST_ALL & flow->key.wildcards) + || (OFPFW_NW_DST_MASK & flow->key.wildcards)) + mask->entry.ip_dst = make_nw_wildcard + (flow->key.wildcards >> OFPFW_NW_DST_SHIFT); + if (OFPFW_NW_PROTO & flow->key.wildcards) + mask->entry.ip_proto = 0xFF; + if (OFPFW_TP_SRC & flow->key.wildcards) + mask->entry.transp_src = 0xFFFF; + if (OFPFW_TP_DST & flow->key.wildcards) + mask->entry.transp_dst = 0xFFFF; + + mask->entry.pad = 0x0000; +} + +static void +populate_action_output(nf2_of_action_wrap *action, nf2_of_entry_wrap *entry, + uint8_t *flowact) +{ + uint16_t port = 0; + struct ofp_action_output *actout = (struct ofp_action_output *)flowact; + int i; + + port = ntohs(actout->port); + NF2DEBUGMSG("Action Type: %i Output Port: %i\n", + ntohs(actout->type), port); + + if ((port >= PORT_BASE) && (port <= MAX_IFACE)) { + // Bitmask for output port(s), evens are phys odds cpu + action->action.forward_bitmask + |= (1 << ((port - PORT_BASE) * 2)); + NF2DEBUGMSG("Output Port: %i Forward Bitmask: %x\n", + port, action->action.forward_bitmask); + } else if (port == OFPP_IN_PORT) { + // Send out to input port + action->action.forward_bitmask + |= (1 << (entry->entry.src_port)); + NF2DEBUGMSG("Output Port = Input Port Forward Bitmask: %x\n", + action->action.forward_bitmask); + } else if (port == OFPP_ALL || port == OFPP_FLOOD) { + // Send out all ports except the source + for (i = 0; i < 4; ++i) { + if ((i * 2) != entry->entry.src_port) { + // Bitmask for output port(s), evens are + // phys odds cpu + action->action.forward_bitmask + |= (1 << (i * 2)); + NF2DEBUGMSG + ("Output Port: %i Forward Bitmask: %x\n", + port, action->action.forward_bitmask); + } + } + } +} + +static void +populate_action_set_dl_src(nf2_of_action_wrap *action, uint8_t *flowact) +{ + struct ofp_action_dl_addr *actdl = (struct ofp_action_dl_addr *)flowact; + int i; + + for (i = 0; i < 6; ++i) { + action->action.eth_src[5 - i] = actdl->dl_addr[i]; + } + action->action.nf2_action_flag |= (1 << OFPAT_SET_DL_SRC); +} + +static void +populate_action_set_dl_dst(nf2_of_action_wrap *action, uint8_t *flowact) +{ + struct ofp_action_dl_addr *actdl = (struct ofp_action_dl_addr *)flowact; + int i; + + for (i = 0; i < 6; ++i) { + action->action.eth_dst[5 - i] = actdl->dl_addr[i]; + } + action->action.nf2_action_flag |= (1 << OFPAT_SET_DL_DST); +} + +/* Populate an nf2_of_action_wrap. */ +void +nf2_populate_of_action(nf2_of_action_wrap *action, nf2_of_entry_wrap *entry, + nf2_of_mask_wrap *mask, struct sw_flow *flow) +{ + struct sw_flow_actions *sfa; + size_t actions_len; + uint8_t *p; + + sfa = flow->sf_acts; + actions_len = sfa->actions_len; + p = (uint8_t *)sfa->actions; + + // zero it out for now + memset(action, 0, sizeof(nf2_of_action_wrap)); + action->action.nf2_action_flag = 0; + + while (actions_len > 0) { + struct ofp_action_header *acth = (struct ofp_action_header *)p; + size_t len = ntohs(acth->len); + + NF2DEBUGMSG("Action Populate: Len of this action: %i\n", len); + NF2DEBUGMSG("Action Populate: Len of actions : %i\n", + actions_len); + + if (acth->type == htons(OFPAT_OUTPUT)) { + populate_action_output(action, entry, p); + } else if (acth->type == htons(OFPAT_SET_DL_SRC)) { + populate_action_set_dl_src(action, p); + } else if (acth->type == htons(OFPAT_SET_DL_DST)) { + populate_action_set_dl_dst(action, p); + } + p += len; + actions_len -= len; + } +} + +/* Add a free hardware entry back to the exact pool. */ +void +nf2_add_free_exact(struct nf2_flow *sfw) +{ + // clear the node entry + INIT_LIST_HEAD(&sfw->node); + + // Critical section, adding to the actual list + exact_free_list[sfw->pos] = sfw; +} + +/* Add a free hardware entry back to the wildcard pool. */ +void +nf2_add_free_wildcard(struct nf2_flow *sfw) +{ + // clear the hw values + sfw->hw_packet_count = 0; + sfw->hw_byte_count = 0; + + // Critical section, adding to the actual list + list_add_tail(&sfw->node, &wildcard_free_list); +} + +/* Hashes the entry to find where it should exist in the exact table + * returns NULL on failure + */ +static struct nf2_flow * +get_free_exact(nf2_of_entry_wrap *entry) +{ + unsigned int poly1 = 0x04C11DB7; + unsigned int poly2 = 0x1EDC6F41; + struct nf2_flow *sfw = NULL; + unsigned int hash = 0x0; + unsigned int index = 0x0; + struct crc32 crc; + + crc32_init(&crc, poly1); + hash = crc32_calculate(&crc, entry, sizeof(nf2_of_entry_wrap)); + + // the bottom 15 bits of hash == the index into the table + index = 0x7FFF & hash; + + // if this index is free, grab it + sfw = exact_free_list[index]; + exact_free_list[index] = NULL; + + if (sfw != NULL) { + return sfw; + } + // try the second index + crc32_init(&crc, poly2); + hash = crc32_calculate(&crc, entry, sizeof(nf2_of_entry_wrap)); + // the bottom 15 bits of hash == the index into the table + index = 0x7FFF & hash; + + // if this index is free, grab it + sfw = exact_free_list[index]; + exact_free_list[index] = NULL; + + // return whether its good or not + return sfw; +} + +/* Get the first free position in the wildcard hardware table + * to write into. + */ +static struct nf2_flow * +get_free_wildcard(void) +{ + struct nf2_flow *sfw = NULL; + struct list_head *next = NULL; + + // Critical section, pulling the first available from the list + if (list_empty(&wildcard_free_list)) { + // empty :( + sfw = NULL; + } else { + next = wildcard_free_list.next; + sfw = list_entry(next, struct nf2_flow, node); + list_del_init(&sfw->node); + } + + return sfw; +} + +/* Retrieves the type of table this flow should go into. */ +int +nf2_get_table_type(struct sw_flow *flow) +{ + if (flow->key.wildcards != 0) { + NF2DEBUGMSG("--- TABLE TYPE: WILDCARD ---\n"); + return NF2_TABLE_WILDCARD; + } else { + NF2DEBUGMSG("--- TABLE TYPE: EXACT ---\n"); + return NF2_TABLE_EXACT; + } +} + +/* Returns 1 if this flow contains an action outputting to all ports except + * input port, 0 otherwise. We support OFPP_ALL and OFPP_FLOOD actions, however + * since we do not perform the spanning tree protocol (STP) then OFPP_FLOOD is + * equivalent to OFPP_ALL. + */ +static int +is_action_forward_all(struct sw_flow *flow) +{ + struct sw_flow_actions *sfa; + size_t actions_len; + uint8_t *p; + + sfa = flow->sf_acts; + actions_len = sfa->actions_len; + p = (uint8_t *)sfa->actions; + + while (actions_len > 0) { + struct ofp_action_header *ah = (struct ofp_action_header *)p; + struct ofp_action_output *oa = (struct ofp_action_output *)p; + size_t len = ntohs(ah->len); + + NF2DEBUGMSG("Fwd Action Chk: Action type: %x\n", + ntohs(ah->type)); + NF2DEBUGMSG("Fwd Action Chk: Output port: %x\n", + ntohs(oa->port)); + NF2DEBUGMSG("Fwd Action Chk: Len of this action: %i\n", len); + NF2DEBUGMSG("Fwd Action Chk: Len of actions : %i\n", + actions_len); + // Currently only support the output port(s) action + if (ntohs(ah->type) == OFPAT_OUTPUT + && (ntohs(oa->port) == OFPP_ALL + || ntohs(oa->port) == OFPP_FLOOD)) { + return 1; + } + p += len; + actions_len -= len; + } + + return 0; +} + +/* Attempts to build and write the flow to hardware. + * Returns 0 on success, 1 on failure. + */ +int +nf2_build_and_write_flow(struct sw_flow *flow) +{ + struct nf2_flow *sfw = NULL; + struct nf2_flow *sfw_next = NULL; + struct net_device *dev; + int num_entries = 0; + int i, table_type; + nf2_of_entry_wrap key; + nf2_of_mask_wrap mask; + nf2_of_action_wrap action; + + memset(&key, 0, sizeof(nf2_of_entry_wrap)); + memset(&mask, 0, sizeof(nf2_of_mask_wrap)); + memset(&action, 0, sizeof(nf2_of_action_wrap)); + + dev = nf2_get_net_device(); + if (dev == NULL) { + // failure getting net device + NF2DEBUGMSG("Failure getting net device struct\n"); + return 1; + } + + table_type = nf2_get_table_type(flow); + switch (table_type) { + default: + break; + + case NF2_TABLE_EXACT: + NF2DEBUGMSG("---Exact Entry---\n"); + nf2_populate_of_entry(&key, flow); + nf2_populate_of_action(&action, &key, NULL, flow); + sfw = get_free_exact(&key); + if (sfw == NULL) { + NF2DEBUGMSG + ("Collision getting free exact match entry\n"); + // collision + nf2_free_net_device(dev); + return 1; + } + // set the active bit on this entry + key.entry.pad = 0x8000; + nf2_write_of_exact(dev, sfw->pos, &key, &action); + flow->private = (void *)sfw; + break; + + case NF2_TABLE_WILDCARD: + NF2DEBUGMSG("---Wildcard Entry---\n"); + // if action is all out and source port is wildcarded + if ((is_action_forward_all(flow)) && + (flow->key.wildcards & OFPFW_IN_PORT)) { + NF2DEBUGMSG("Grab four wildcard tables\n"); + if (!(sfw = get_free_wildcard())) { + NF2DEBUGMSG("No free wildcard entries found."); + // no free entries + nf2_free_net_device(dev); + return 1; + } + // try to get 3 more positions + for (i = 0; i < 3; ++i) { + if (!(sfw_next = get_free_wildcard())) { + break; + } + list_add_tail(&sfw_next->node, &sfw->node); + ++num_entries; + } + + if (num_entries < 3) { + // failed to get enough entries, return them and exit + nf2_delete_private((void *)sfw); + nf2_free_net_device(dev); + return 1; + } + + nf2_populate_of_entry(&key, flow); + nf2_populate_of_mask(&mask, flow); + + // set first entry's src port to 0, remove wildcard mask on src + key.entry.src_port = 0; + mask.entry.src_port = 0; + nf2_populate_of_action(&action, &key, &mask, flow); + nf2_write_of_wildcard(dev, sfw->pos, &key, &mask, + &action); + + i = 1; + sfw_next = list_entry(sfw->node.next, + struct nf2_flow, node); + // walk through and write the remaining 3 entries + while (sfw_next != sfw) { + key.entry.src_port = i * 2; + nf2_populate_of_action(&action, &key, &mask, + flow); + nf2_write_of_wildcard(dev, sfw_next->pos, &key, + &mask, &action); + sfw_next = list_entry(sfw_next->node.next, + struct nf2_flow, node); + ++i; + } + flow->private = (void *)sfw; + } else { + /* Get a free position here, and write to it */ + if ((sfw = get_free_wildcard())) { + nf2_populate_of_entry(&key, flow); + nf2_populate_of_mask(&mask, flow); + nf2_populate_of_action(&action, &key, &mask, + flow); + if (nf2_write_of_wildcard + (dev, sfw->pos, &key, &mask, &action)) { + // failure writing to hardware + nf2_add_free_wildcard(sfw); + NF2DEBUGMSG + ("Failure writing to hardware\n"); + nf2_free_net_device(dev); + return 1; + } else { + // success writing to hardware, store the position + flow->private = (void *)sfw; + } + } else { + // hardware is full, return 0 + NF2DEBUGMSG("No free wildcard entries found."); + nf2_free_net_device(dev); + return 1; + } + } + break; + } + + nf2_free_net_device(dev); + return 0; +} + +void +nf2_delete_private(void *private) +{ + struct nf2_flow *sfw = (struct nf2_flow *)private; + struct nf2_flow *sfw_next; + struct list_head *next; + + switch (sfw->type) { + default: + break; + + case NF2_TABLE_EXACT: + nf2_clear_of_exact(sfw->pos); + nf2_add_free_exact(sfw); + break; + + case NF2_TABLE_WILDCARD: + while (!list_empty(&sfw->node)) { + next = sfw->node.next; + sfw_next = list_entry(next, struct nf2_flow, node); + list_del_init(&sfw_next->node); + // Immediately zero out the entry in hardware + nf2_clear_of_wildcard(sfw_next->pos); + // add it back to the pool + nf2_add_free_wildcard(sfw_next); + } + // zero the core entry + nf2_clear_of_wildcard(sfw->pos); + // add back the core entry + nf2_add_free_wildcard(sfw); + break; + } +} + +int +nf2_modify_acts(struct sw_table *swt, struct sw_flow *flow) +{ + struct nf2_flow *sfw = (struct nf2_flow *)flow->private; + struct net_device *dev; + nf2_of_entry_wrap key; + nf2_of_mask_wrap mask; + nf2_of_action_wrap action; + + memset(&key, 0, sizeof(nf2_of_entry_wrap)); + memset(&mask, 0, sizeof(nf2_of_mask_wrap)); + memset(&action, 0, sizeof(nf2_of_action_wrap)); + + dev = nf2_get_net_device(); + if (dev == NULL) + return 0; + + switch (sfw->type) { + default: + break; + + case NF2_TABLE_EXACT: + nf2_populate_of_entry(&key, flow); + nf2_populate_of_action(&action, &key, NULL, flow); + key.entry.pad = 0x8000; + nf2_modify_write_of_exact(dev, sfw->pos, &action); + break; + + case NF2_TABLE_WILDCARD: + if (flow->key.wildcards & OFPFW_IN_PORT) { + nf2_free_net_device(dev); + return 0; + } + nf2_populate_of_entry(&key, flow); + nf2_populate_of_mask(&mask, flow); + nf2_populate_of_action(&action, &key, &mask, flow); + nf2_modify_write_of_wildcard(dev, sfw->pos, + &key, &mask, &action); + break; + } + + nf2_free_net_device(dev); + return 1; +} + +uint64_t +nf2_get_packet_count(struct net_device *dev, struct nf2_flow *sfw) +{ + uint32_t count = 0; + uint32_t hw_count = 0; + uint64_t total = 0; + struct nf2_flow *sfw_next = NULL; + + switch (sfw->type) { + default: + break; + + case NF2_TABLE_EXACT: + count = nf2_get_exact_packet_count(dev, sfw->pos); + total = count; + break; + + case NF2_TABLE_WILDCARD: + sfw_next = sfw; + do { + hw_count = nf2_get_wildcard_packet_count(dev, + sfw_next->pos); + if (hw_count >= sfw_next->hw_packet_count) { + count = hw_count - sfw_next->hw_packet_count; + sfw_next->hw_packet_count = hw_count; + } else { + // wrapping occurred + count = (MAX_INT_32 - sfw_next->hw_packet_count) + + hw_count; + sfw_next->hw_packet_count = hw_count; + } + total += count; + sfw_next = list_entry(sfw_next->node.next, + struct nf2_flow, node); + } while (sfw_next != sfw); + break; + } + + NF2DEBUGMSG("Return nf2_get_packet_count value: %llu\n", total); + return total; +} + +uint64_t +nf2_get_byte_count(struct net_device *dev, struct nf2_flow *sfw) +{ + uint32_t count = 0; + uint32_t hw_count = 0; + uint64_t total = 0; + struct nf2_flow *sfw_next = NULL; + + switch (sfw->type) { + default: + break; + + case NF2_TABLE_EXACT: + count = nf2_get_exact_byte_count(dev, sfw->pos); + total = count; + break; + + case NF2_TABLE_WILDCARD: + sfw_next = sfw; + do { + hw_count = nf2_get_wildcard_byte_count(dev, + sfw_next->pos); + if (hw_count >= sfw_next->hw_byte_count) { + count = hw_count - sfw_next->hw_byte_count; + sfw_next->hw_byte_count = hw_count; + } else { + // wrapping occurred + count = (MAX_INT_32 - sfw_next->hw_byte_count) + + hw_count; + sfw_next->hw_byte_count = hw_count; + } + + total += count; + sfw_next = list_entry(sfw_next->node.next, + struct nf2_flow, node); + } while (sfw_next != sfw); + break; + } + + NF2DEBUGMSG("Return nf2_get_byte_count value: %llu\n", total); + return total; +} diff --git a/openflow/datapath/hwtable_nf2/nf2_lib.h b/openflow/datapath/hwtable_nf2/nf2_lib.h new file mode 100644 index 00000000..9c0fedc8 --- /dev/null +++ b/openflow/datapath/hwtable_nf2/nf2_lib.h @@ -0,0 +1,59 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#ifndef HWTABLE_NF2_NF2_LIB_H_ +#define HWTABLE_NF2_NF2_LIB_H_ + +struct net_device *nf2_get_net_device(void); +void nf2_free_net_device(struct net_device *); +int nf2_are_actions_supported(struct sw_flow *); +void nf2_clear_of_exact(uint32_t); +void nf2_clear_of_wildcard(uint32_t); +int nf2_init_exact_freelist(void); +int nf2_init_wildcard_freelist(void); +void nf2_destroy_exact_freelist(void); +void nf2_destroy_wildcard_freelist(void); +int nf2_write_static_wildcard(void); +void nf2_populate_of_entry(nf2_of_entry_wrap *, struct sw_flow *); +void nf2_populate_of_mask(nf2_of_mask_wrap *, struct sw_flow *); +void nf2_populate_of_action(nf2_of_action_wrap *, nf2_of_entry_wrap *, + nf2_of_mask_wrap *, struct sw_flow *); +void nf2_add_free_exact(struct nf2_flow *); +void nf2_add_free_wildcard(struct nf2_flow *); +int nf2_get_table_type(struct sw_flow *); +int nf2_build_and_write_flow(struct sw_flow *); +void nf2_delete_private(void *); +int nf2_modify_acts(struct sw_table *, struct sw_flow *); +uint64_t nf2_get_packet_count(struct net_device *, struct nf2_flow *); +uint64_t nf2_get_byte_count(struct net_device *, struct nf2_flow *); + +#endif diff --git a/openflow/datapath/hwtable_nf2/nf2_openflow.c b/openflow/datapath/hwtable_nf2/nf2_openflow.c new file mode 100644 index 00000000..7d392f19 --- /dev/null +++ b/openflow/datapath/hwtable_nf2/nf2_openflow.c @@ -0,0 +1,847 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#include +#include +#include + +#include "flow.h" +#include "table.h" + +#include "hwtable_nf2/nf2.h" +#include "hwtable_nf2/nf2_reg.h" +#include "hwtable_nf2/nf2_hwapi.h" +#include "hwtable_nf2/nf2_flowtable.h" +#include "hwtable_nf2/nf2_openflow.h" +#include "hwtable_nf2/nf2_lib.h" + +static void log_entry(nf2_of_entry_wrap *); +static void log_entry_raw(nf2_of_entry_wrap *); +static void log_mask(nf2_of_mask_wrap *); +static void log_mask_raw(nf2_of_mask_wrap *); +static void log_action(nf2_of_action_wrap *); +static void log_action_raw(nf2_of_action_wrap *); +static struct nf2_all_ports_info_addr *nf2_get_all_ports_info_addr(void); + +static void +log_entry(nf2_of_entry_wrap *entry) +{ +#ifndef NF2_DEBUG + return; +#else + int i; + + // Log the physical source port + NF2DEBUGMSG("E psrc[%i] ", entry->entry.src_port / 2); + + // Log the link layer source + NF2DEBUGMSG("dlsrc["); + for (i = 5; i > 0; --i) { + NF2DEBUGMSG("%0X:", entry->entry.eth_src[i]); + } + NF2DEBUGMSG("%0X] ", entry->entry.eth_src[0]); + + // Log the link layer dest + NF2DEBUGMSG("dldst["); + for (i = 5; i > 0; --i) { + NF2DEBUGMSG("%0X:", entry->entry.eth_dst[i]); + } + NF2DEBUGMSG("%0X] ", entry->entry.eth_dst[0]); + + // Log the link layer type + NF2DEBUGMSG("dltype[%0X] ", entry->entry.eth_type); + + // Log the link layer vlan + NF2DEBUGMSG("dlvlan[%0X] ", entry->entry.vlan_id); + + // Log the network source + NF2DEBUGMSG("nwsrc["); + NF2DEBUGMSG("%0i.", (entry->entry.ip_src >> 24) & 0xFF); + NF2DEBUGMSG("%0i.", (entry->entry.ip_src >> 16) & 0xFF); + NF2DEBUGMSG("%0i.", (entry->entry.ip_src >> 8) & 0xFF); + NF2DEBUGMSG("%0i", entry->entry.ip_src & 0xFF); + NF2DEBUGMSG("] "); + + // Log the network dest + NF2DEBUGMSG("nwdst["); + NF2DEBUGMSG("%0i.", (entry->entry.ip_dst >> 24) & 0xFF); + NF2DEBUGMSG("%0i.", (entry->entry.ip_dst >> 16) & 0xFF); + NF2DEBUGMSG("%0i.", (entry->entry.ip_dst >> 8) & 0xFF); + NF2DEBUGMSG("%0i", entry->entry.ip_dst & 0xFF); + NF2DEBUGMSG("] "); + + // Log the transport source port + NF2DEBUGMSG("tsrc[%i] ", entry->entry.transp_src); + + // Log the transport dest port + NF2DEBUGMSG("tdst[%i]\n", entry->entry.transp_dst); +#endif +} + +static void +log_entry_raw(nf2_of_entry_wrap *entry) +{ +#ifndef NF2_DEBUG + return; +#else + int i; + unsigned char *c; + + NF2DEBUGMSG("E "); + c = (unsigned char *)entry; + for (i = 0; i < sizeof(nf2_of_entry_wrap); ++i) { + if (!(i % 4)) { + NF2DEBUGMSG(" "); + } + NF2DEBUGMSG("%02x", c[i]); + } + NF2DEBUGMSG("\n"); +#endif +} + +static void +log_mask(nf2_of_mask_wrap *mask) +{ +#ifndef NF2_DEBUG + return; +#else + int i; + + // Log the physical source port + NF2DEBUGMSG("M psrc[%0X] ", mask->entry.src_port / 2); + + // Log the link layer source + NF2DEBUGMSG("dlsrc["); + for (i = 5; i > 0; --i) { + NF2DEBUGMSG("%0X:", mask->entry.eth_src[i]); + } + NF2DEBUGMSG("%0X] ", mask->entry.eth_dst[0]); + + // Log the link layer dest + NF2DEBUGMSG("dldst["); + for (i = 5; i > 0; --i) { + NF2DEBUGMSG("%0X:", mask->entry.eth_dst[i]); + } + NF2DEBUGMSG("%0X] ", mask->entry.eth_dst[0]); + + // Log the link layer type + NF2DEBUGMSG("dltype[%0X] ", mask->entry.eth_type); + + // Log the link layer vlan + NF2DEBUGMSG("dlvlan[%0X] ", mask->entry.vlan_id); + + // Log the network source + NF2DEBUGMSG("nwsrc["); + NF2DEBUGMSG("%0X.", (mask->entry.ip_src >> 24) & 0xFF); + NF2DEBUGMSG("%0X.", (mask->entry.ip_src >> 16) & 0xFF); + NF2DEBUGMSG("%0X.", (mask->entry.ip_src >> 8) & 0xFF); + NF2DEBUGMSG("%0X", mask->entry.ip_src & 0xFF); + NF2DEBUGMSG("] "); + + // Log the network dest + NF2DEBUGMSG("nwdst["); + NF2DEBUGMSG("%0X.", (mask->entry.ip_dst >> 24) & 0xFF); + NF2DEBUGMSG("%0X.", (mask->entry.ip_dst >> 16) & 0xFF); + NF2DEBUGMSG("%0X.", (mask->entry.ip_dst >> 8) & 0xFF); + NF2DEBUGMSG("%0X", mask->entry.ip_dst & 0xFF); + NF2DEBUGMSG("] "); + + // Log the transport source port + NF2DEBUGMSG("tsrc[%0X] ", mask->entry.transp_src); + + // Log the transport dest port + NF2DEBUGMSG("tdst[%0X]\n", mask->entry.transp_dst); +#endif +} + +static void +log_mask_raw(nf2_of_mask_wrap *mask) +{ +#ifndef NF2_DEBUG + return; +#else + int i; + unsigned char *c; + + NF2DEBUGMSG("M "); + c = (unsigned char *)mask; + for (i = 0; i < sizeof(nf2_of_mask_wrap); ++i) { + if (!(i % 4)) { + NF2DEBUGMSG(" "); + } + NF2DEBUGMSG("%02x", c[i]); + } + NF2DEBUGMSG("\n"); +#endif +} + +static void +log_action(nf2_of_action_wrap *action) +{ +#ifndef NF2_DEBUG + return; +#else + int i; + + NF2DEBUGMSG("A Output P["); + for (i = 0; i < 4; ++i) { + if (action->action.forward_bitmask & (1 << (i * 2))) { + NF2DEBUGMSG("%i", i); + } + } + NF2DEBUGMSG("] CPU["); + for (i = 0; i < 4; ++i) { + if (action->action.forward_bitmask & (1 << (1 + (i * 2)))) { + NF2DEBUGMSG("%i", i); + } + } + NF2DEBUGMSG("]\n"); +#endif +} + +static void +log_action_raw(nf2_of_action_wrap *action) +{ +#ifndef NF2_DEBUG + return; +#else + int i; + unsigned char *c; + + NF2DEBUGMSG("A "); + c = (unsigned char *)action; + for (i = 0; i < sizeof(nf2_of_action_wrap); ++i) { + if (!(i % 4)) { + NF2DEBUGMSG(" "); + } + NF2DEBUGMSG("%02x", c[i]); + } + NF2DEBUGMSG("\n"); +#endif +} + +void +nf2_reset_card(struct net_device *dev) +{ + volatile unsigned int val; + + if (dev == NULL) { + return; + } + + /* If we are operating on a NetFPGA enabled box, reset the card */ + printk(KERN_INFO "openflowswitch-netfpga2: Resetting the NetFPGA.\n"); + nf2k_reg_read(dev, WDT_CPCI_REG_CTRL, (void *)&val); + val |= 0x100; + nf2k_reg_write(dev, WDT_CPCI_REG_CTRL, (void *)&val); + printk(KERN_INFO "openflowswitch-netfpga2: Reset the NetFPGA.\n"); + ssleep(2); +} + +void +nf2_clear_watchdog(struct net_device *dev) +{ + volatile unsigned int enable_status; + +#ifndef NF2_WATCHDOG + return; +#endif + if (dev == NULL) { + return; + } + + nf2k_reg_read(dev, WDT_ENABLE_FLG_REG, (void *)&enable_status); + enable_status &= 0x1; + + if (enable_status == WATCHDOG_DISABLE) { + enable_status = WATCHDOG_ENABLE; + nf2k_reg_write(dev, WDT_ENABLE_FLG_REG, (void *)&enable_status); + } + return; +} + +/* Write a wildcard entry to the specified device and row. The row consists of + * the actual entry, its mask that specifies wildcards, as well as the action(s) + * to be taken if the row is matched + */ +int +nf2_write_of_wildcard(struct net_device *dev, int row, + nf2_of_entry_wrap *entry, nf2_of_mask_wrap *mask, + nf2_of_action_wrap *action) +{ + int i; + int val; + struct timeval t; + + NF2DEBUGMSG("** Begin wildcard entry write to row: %i\n", row); + log_entry(entry); + log_mask(mask); + log_action(action); + log_entry_raw(entry); + log_mask_raw(mask); + log_action_raw(action); + + for (i = 0; i < NF2_OF_ENTRY_WORD_LEN; ++i) { + nf2k_reg_write(dev, + OPENFLOW_WILDCARD_LOOKUP_CMP_0_REG + + (4 * i), &(entry->raw[i])); + } + + for (i = 0; i < NF2_OF_MASK_WORD_LEN; ++i) { + nf2k_reg_write(dev, + OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_0_REG + + (4 * i), &(mask->raw[i])); + } + + for (i = 0; i < NF2_OF_ACTION_WORD_LEN; ++i) { + nf2k_reg_write(dev, + OPENFLOW_WILDCARD_LOOKUP_ACTION_0_REG + + (4 * i), &(action->raw[i])); + } + + // Reset the stats for the row + val = 0; + nf2k_reg_write(dev, + OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG + (4 * row), + &val); + nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG + (4 * row), + &val); + nf2k_reg_write(dev, + OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_0_REG + (4 * row), + &val); + nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_WRITE_ADDR_REG, &row); + + do_gettimeofday(&t); + NF2DEBUGMSG("** End wildcard entry write to row: %i time: %i.%i\n", + row, (int)t.tv_sec, (int)t.tv_usec); + + return 0; +} + +int +nf2_write_of_exact(struct net_device *dev, int row, + nf2_of_entry_wrap *entry, nf2_of_action_wrap *action) +{ + int i; + int val; + struct timeval t; + unsigned int index = row << 7; + + NF2DEBUGMSG("** Begin exact match entry write to row: %i\n", row); + log_entry(entry); + log_action(action); + log_entry_raw(entry); + log_action_raw(action); + + for (i = 0; i < NF2_OF_ENTRY_WORD_LEN; ++i) { + nf2k_reg_write(dev, SRAM_BASE_ADDR + index + + (4 * i), &(entry->raw[i])); + } + + // blank out the counters + val = 0; + for (i = 0; i < NF2_OF_EXACT_COUNTERS_WORD_LEN; ++i) { + nf2k_reg_write(dev, SRAM_BASE_ADDR + index + + sizeof(nf2_of_entry_wrap) + + (4 * i), &val); + } + + // write the actions + for (i = 0; i < NF2_OF_ACTION_WORD_LEN; ++i) { + nf2k_reg_write(dev, SRAM_BASE_ADDR + index + + sizeof(nf2_of_entry_wrap) + + sizeof(nf2_of_exact_counters_wrap) + + (4 * i), &(action->raw[i])); + } + + do_gettimeofday(&t); + NF2DEBUGMSG("** End exact match entry write to row: %i time: %i.%i\n", + row, (int)t.tv_sec, (int)t.tv_usec); + + return 0; +} + +/* Write wildcard action(s) to the specified device and row. */ +int +nf2_modify_write_of_wildcard(struct net_device *dev, int row, + nf2_of_entry_wrap *entry, nf2_of_mask_wrap *mask, + nf2_of_action_wrap *action) +{ + int i; + int bytes_reg_val; + int pkts_reg_val; + int last_reg_val; + struct timeval t; + + NF2DEBUGMSG("** Begin wildcard modified action write to row: %i\n", + row); + log_entry(entry); + log_mask(mask); + log_action(action); + log_entry_raw(entry); + log_mask_raw(mask); + log_action_raw(action); + + nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_READ_ADDR_REG, &row); + nf2k_reg_read(dev, + OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG + (4 * row), + &bytes_reg_val); + nf2k_reg_read(dev, + OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG + (4 * row), + &pkts_reg_val); + nf2k_reg_read(dev, + OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_0_REG + (4 * row), + &last_reg_val); + + for (i = 0; i < NF2_OF_ENTRY_WORD_LEN; ++i) { + nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_CMP_0_REG + + (4 * i), &(entry->raw[i])); + } + + for (i = 0; i < NF2_OF_MASK_WORD_LEN; ++i) { + nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_0_REG + + (4 * i), &(mask->raw[i])); + } + + for (i = 0; i < NF2_OF_ACTION_WORD_LEN; ++i) { + nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_ACTION_0_REG + + (4 * i), &(action->raw[i])); + } + + nf2k_reg_write(dev, + OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG + (4 * row), + &bytes_reg_val); + nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG + (4 * row), + &pkts_reg_val); + nf2k_reg_write(dev, + OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_0_REG + (4 * row), + &last_reg_val); + nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_WRITE_ADDR_REG, &row); + + do_gettimeofday(&t); + NF2DEBUGMSG + ("** End wildcard modified action write to row: %i time: %i.%i\n", + row, (int)t.tv_sec, (int)t.tv_usec); + NF2DEBUGMSG(" Bytes hit count: %d\n", bytes_reg_val); + NF2DEBUGMSG(" Pkts hit count: %d\n", pkts_reg_val); + NF2DEBUGMSG(" Last seen : %d\n", last_reg_val); + + return 0; +} + +int +nf2_modify_write_of_exact(struct net_device *dev, int row, + nf2_of_action_wrap *action) +{ + int i; + struct timeval t; + unsigned int index = row << 7; + + NF2DEBUGMSG("** Begin exact match modified action write to row: %i\n", + row); + log_action(action); + log_action_raw(action); + + // write the actions + for (i = 0; i < NF2_OF_ACTION_WORD_LEN; ++i) { + nf2k_reg_write(dev, SRAM_BASE_ADDR + index + + sizeof(nf2_of_entry_wrap) + + sizeof(nf2_of_exact_counters_wrap) + + (4 * i), &(action->raw[i])); + } + + do_gettimeofday(&t); + NF2DEBUGMSG + ("** End exact match modified action write to row: %i time: %i.%i\n", + row, (int)t.tv_sec, (int)t.tv_usec); + + return 0; +} + +unsigned int +nf2_get_exact_packet_count(struct net_device *dev, int row) +{ + unsigned int val = 0; + unsigned int index = 0; + + /* TODO: Need to scrape data from all 4 registers + * in the case of a wildcarded source port and + * forward all action type + */ + nf2_of_exact_counters_wrap counters; + memset(&counters, 0, sizeof(nf2_of_exact_counters_wrap)); + + // build the index to our counters + index = row << 7; + + // Read the first word into our struct, to not disturb the byte count + nf2k_reg_read(dev, + SRAM_BASE_ADDR + index + sizeof(nf2_of_entry_wrap), + &counters); + val = counters.counters.pkt_count; + + NF2DEBUGMSG("** Exact match packet count request row: %i count: %i\n", + row, val); + + return val; +} + +unsigned int +nf2_get_exact_byte_count(struct net_device *dev, int row) +{ + unsigned int val = 0; + unsigned int index = 0; + + /* TODO: Need to scrape data from all 4 registers + * in the case of a wildcarded source port and + * forward all action type + */ + nf2_of_exact_counters_wrap counters; + memset(&counters, 0, sizeof(nf2_of_exact_counters_wrap)); + + // build the index to our counters + index = row << 7; + + // Read the second word into our struct, to not disturb the packet count + nf2k_reg_read(dev, SRAM_BASE_ADDR + index + + sizeof(nf2_of_entry_wrap) + 4, &counters.raw[1]); + val = counters.counters.byte_count; + + NF2DEBUGMSG("** Exact match byte count request row: %i count: %i\n", + row, val); + + return val; +} + +unsigned int +nf2_get_wildcard_packet_count(struct net_device *dev, int row) +{ + unsigned int val = 0; +#ifdef NF2_DEBUG + struct timeval t; +#endif + + nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_READ_ADDR_REG, &row); + nf2k_reg_read(dev, OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG + + (4 * row), &val); + +#ifdef NF2_DEBUG + do_gettimeofday(&t); + NF2DEBUGMSG + ("** Wildcard packet count request row: %i count: %i time: %i.%i\n", + row, val, (int)t.tv_sec, (int)t.tv_usec); +#endif + + return val; +} + +unsigned int +nf2_get_wildcard_byte_count(struct net_device *dev, int row) +{ + unsigned int val = 0; +#ifdef NF2_DEBUG + struct timeval t; +#endif + + nf2k_reg_write(dev, OPENFLOW_WILDCARD_LOOKUP_READ_ADDR_REG, &row); + nf2k_reg_read(dev, OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG + + (4 * row), &val); + +#ifdef NF2_DEBUG + do_gettimeofday(&t); + NF2DEBUGMSG + ("** Wildcard byte count request row: %i count: %i time: %i.%i\n", + row, val, (int)t.tv_sec, (int)t.tv_usec); +#endif + + return val; +} + +unsigned long int +nf2_get_matched_count(struct net_device *dev) +{ + unsigned int val_wild = 0; + unsigned int val_exact = 0; +#ifdef NF2_DEBUG + struct timeval t; +#endif + + nf2k_reg_read(dev, OPENFLOW_LOOKUP_WILDCARD_HITS_REG, &val_wild); + nf2k_reg_read(dev, OPENFLOW_LOOKUP_EXACT_HITS_REG, &val_exact); + +#ifdef NF2_DEBUG + do_gettimeofday(&t); + NF2DEBUGMSG("** Wildcard Matched count: %i time: %i.%i\n", + val_wild, (int)t.tv_sec, (int)t.tv_usec); + NF2DEBUGMSG("** Exact Matched count: %i time: %i.%i\n", + val_exact, (int)t.tv_sec, (int)t.tv_usec); +#endif + + return ((unsigned long int)(val_wild + val_exact)); +} + +unsigned long int +nf2_get_missed_count(struct net_device *dev) +{ + unsigned int val_wild = 0; + unsigned int val_exact = 0; +#ifdef NF2_DEBUG + struct timeval t; +#endif + + nf2k_reg_read(dev, OPENFLOW_LOOKUP_WILDCARD_MISSES_REG, &val_wild); + nf2k_reg_read(dev, OPENFLOW_LOOKUP_EXACT_MISSES_REG, &val_exact); + +#ifdef NF2_DEBUG + do_gettimeofday(&t); + NF2DEBUGMSG("** Wildcard Missed count: %i time: %i.%i\n", + val_wild, (int)t.tv_sec, (int)t.tv_usec); + NF2DEBUGMSG("** Exact Missed count: %i time: %i.%i\n", + val_exact, (int)t.tv_sec, (int)t.tv_usec); +#endif + + return ((unsigned long int)(val_wild + val_exact)); +} + +struct nf2_device_info * +nf2_get_device_info(struct net_device *dev) +{ + struct nf2_device_info *nf2devinfo; + int i; + + nf2devinfo = kzalloc(sizeof(struct nf2_device_info), GFP_KERNEL); + if (nf2devinfo == NULL) + return NULL; + + // Read the version and revision + nf2k_reg_read(dev, DEV_ID_DEVICE_ID_REG, &(nf2devinfo->nf2_device_id)); + nf2k_reg_read(dev, DEV_ID_REVISION_REG, &(nf2devinfo->nf2_device_rev)); + + // Read the design name string + for (i = 0; i < (DEVICE_STR_LEN / 4) - 2; i++) { + nf2k_reg_read(dev, DEV_ID_DEV_STR_0_REG + i * 4, + (uint32_t *)(nf2devinfo->nf2_device_str + i * 4)); + *(uint32_t *)(nf2devinfo->nf2_device_str + i * 4) + = ntohl(*(uint32_t *) + (nf2devinfo->nf2_device_str + i * 4)); + } + nf2devinfo->nf2_device_str[DEVICE_STR_LEN - 1] = '\0'; + + return nf2devinfo; +} + +struct nf2_match_info * +nf2_get_match_info(struct net_device *dev) +{ + struct nf2_match_info *nf2matchinfo; + + nf2matchinfo = kzalloc(sizeof(struct nf2_match_info), GFP_KERNEL); + if (nf2matchinfo == NULL) + return NULL; + + nf2k_reg_read(dev, OPENFLOW_LOOKUP_WILDCARD_MISSES_REG, + &(nf2matchinfo->wildcard_misses)); + nf2k_reg_read(dev, OPENFLOW_LOOKUP_WILDCARD_HITS_REG, + &(nf2matchinfo->wildcard_hits)); + nf2k_reg_read(dev, OPENFLOW_LOOKUP_EXACT_MISSES_REG, + &(nf2matchinfo->exact_misses)); + nf2k_reg_read(dev, OPENFLOW_LOOKUP_EXACT_HITS_REG, + &(nf2matchinfo->exact_hits)); + + return nf2matchinfo; +} + +unsigned int +nf2_get_watchdog_info(struct net_device *dev) +{ + unsigned int nf2wdtinfo = 0; + + nf2k_reg_read(dev, WDT_COUNTER_REG, &nf2wdtinfo); + return nf2wdtinfo; +} + +static struct nf2_all_ports_info_addr * +nf2_get_all_ports_info_addr(void) +{ + struct nf2_all_ports_info_addr *nf2addr; + + nf2addr = kzalloc(sizeof(struct nf2_all_ports_info_addr), GFP_KERNEL); + if (nf2addr == NULL) + return NULL; + + nf2addr->rx_q_num_pkts_stored_reg[0] + = MAC_GRP_0_RX_QUEUE_NUM_PKTS_STORED_REG; + nf2addr->rx_q_num_pkts_dropped_full_reg[0] + = MAC_GRP_0_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG; + nf2addr->rx_q_num_pkts_dropped_bad_reg[0] + = MAC_GRP_0_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG; + nf2addr->rx_q_num_words_pushed_reg[0] + = MAC_GRP_0_RX_QUEUE_NUM_WORDS_PUSHED_REG; + nf2addr->rx_q_num_bytes_pushed_reg[0] + = MAC_GRP_0_RX_QUEUE_NUM_BYTES_PUSHED_REG; + nf2addr->rx_q_num_pkts_dequeued_reg[0] + = MAC_GRP_0_RX_QUEUE_NUM_PKTS_DEQUEUED_REG; + nf2addr->rx_q_num_pkts_in_queue_reg[0] + = MAC_GRP_0_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG; + nf2addr->tx_q_num_pkts_in_queue_reg[0] + = MAC_GRP_0_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG; + nf2addr->tx_q_num_pkts_sent_reg[0] + = MAC_GRP_0_TX_QUEUE_NUM_PKTS_SENT_REG; + nf2addr->tx_q_num_words_pushed_reg[0] + = MAC_GRP_0_TX_QUEUE_NUM_WORDS_PUSHED_REG; + nf2addr->tx_q_num_bytes_pushed_reg[0] + = MAC_GRP_0_TX_QUEUE_NUM_BYTES_PUSHED_REG; + nf2addr->tx_q_num_pkts_enqueued_reg[0] + = MAC_GRP_0_TX_QUEUE_NUM_PKTS_ENQUEUED_REG; + + nf2addr->rx_q_num_pkts_stored_reg[1] + = MAC_GRP_1_RX_QUEUE_NUM_PKTS_STORED_REG; + nf2addr->rx_q_num_pkts_dropped_full_reg[1] + = MAC_GRP_1_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG; + nf2addr->rx_q_num_pkts_dropped_bad_reg[1] + = MAC_GRP_1_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG; + nf2addr->rx_q_num_words_pushed_reg[1] + = MAC_GRP_1_RX_QUEUE_NUM_WORDS_PUSHED_REG; + nf2addr->rx_q_num_bytes_pushed_reg[1] + = MAC_GRP_1_RX_QUEUE_NUM_BYTES_PUSHED_REG; + nf2addr->rx_q_num_pkts_dequeued_reg[1] + = MAC_GRP_1_RX_QUEUE_NUM_PKTS_DEQUEUED_REG; + nf2addr->rx_q_num_pkts_in_queue_reg[1] + = MAC_GRP_1_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG; + nf2addr->tx_q_num_pkts_in_queue_reg[1] + = MAC_GRP_1_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG; + nf2addr->tx_q_num_pkts_sent_reg[1] + = MAC_GRP_1_TX_QUEUE_NUM_PKTS_SENT_REG; + nf2addr->tx_q_num_words_pushed_reg[1] + = MAC_GRP_1_TX_QUEUE_NUM_WORDS_PUSHED_REG; + nf2addr->tx_q_num_bytes_pushed_reg[1] + = MAC_GRP_1_TX_QUEUE_NUM_BYTES_PUSHED_REG; + nf2addr->tx_q_num_pkts_enqueued_reg[1] + = MAC_GRP_1_TX_QUEUE_NUM_PKTS_ENQUEUED_REG; + + nf2addr->rx_q_num_pkts_stored_reg[2] + = MAC_GRP_2_RX_QUEUE_NUM_PKTS_STORED_REG; + nf2addr->rx_q_num_pkts_dropped_full_reg[2] + = MAC_GRP_2_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG; + nf2addr->rx_q_num_pkts_dropped_bad_reg[2] + = MAC_GRP_2_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG; + nf2addr->rx_q_num_words_pushed_reg[2] + = MAC_GRP_2_RX_QUEUE_NUM_WORDS_PUSHED_REG; + nf2addr->rx_q_num_bytes_pushed_reg[2] + = MAC_GRP_2_RX_QUEUE_NUM_BYTES_PUSHED_REG; + nf2addr->rx_q_num_pkts_dequeued_reg[2] + = MAC_GRP_2_RX_QUEUE_NUM_PKTS_DEQUEUED_REG; + nf2addr->rx_q_num_pkts_in_queue_reg[2] + = MAC_GRP_2_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG; + nf2addr->tx_q_num_pkts_in_queue_reg[2] + = MAC_GRP_2_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG; + nf2addr->tx_q_num_pkts_sent_reg[2] + = MAC_GRP_2_TX_QUEUE_NUM_PKTS_SENT_REG; + nf2addr->tx_q_num_words_pushed_reg[2] + = MAC_GRP_2_TX_QUEUE_NUM_WORDS_PUSHED_REG; + nf2addr->tx_q_num_bytes_pushed_reg[2] + = MAC_GRP_2_TX_QUEUE_NUM_BYTES_PUSHED_REG; + nf2addr->tx_q_num_pkts_enqueued_reg[2] + = MAC_GRP_2_TX_QUEUE_NUM_PKTS_ENQUEUED_REG; + + nf2addr->rx_q_num_pkts_stored_reg[3] + = MAC_GRP_3_RX_QUEUE_NUM_PKTS_STORED_REG; + nf2addr->rx_q_num_pkts_dropped_full_reg[3] + = MAC_GRP_3_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG; + nf2addr->rx_q_num_pkts_dropped_bad_reg[3] + = MAC_GRP_3_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG; + nf2addr->rx_q_num_words_pushed_reg[3] + = MAC_GRP_3_RX_QUEUE_NUM_WORDS_PUSHED_REG; + nf2addr->rx_q_num_bytes_pushed_reg[3] + = MAC_GRP_3_RX_QUEUE_NUM_BYTES_PUSHED_REG; + nf2addr->rx_q_num_pkts_dequeued_reg[3] + = MAC_GRP_3_RX_QUEUE_NUM_PKTS_DEQUEUED_REG; + nf2addr->rx_q_num_pkts_in_queue_reg[3] + = MAC_GRP_3_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG; + nf2addr->tx_q_num_pkts_in_queue_reg[3] + = MAC_GRP_3_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG; + nf2addr->tx_q_num_pkts_sent_reg[3] + = MAC_GRP_3_TX_QUEUE_NUM_PKTS_SENT_REG; + nf2addr->tx_q_num_words_pushed_reg[3] + = MAC_GRP_3_TX_QUEUE_NUM_WORDS_PUSHED_REG; + nf2addr->tx_q_num_bytes_pushed_reg[3] + = MAC_GRP_3_TX_QUEUE_NUM_BYTES_PUSHED_REG; + nf2addr->tx_q_num_pkts_enqueued_reg[3] + = MAC_GRP_3_TX_QUEUE_NUM_PKTS_ENQUEUED_REG; + + return nf2addr; +} + +struct nf2_all_ports_info * +nf2_get_all_ports_info(struct net_device *dev) +{ + struct nf2_all_ports_info *nf2portinfo; + struct nf2_all_ports_info_addr *nf2addr; + int i; + + nf2portinfo = kzalloc(sizeof(struct nf2_all_ports_info), GFP_KERNEL); + if (nf2portinfo == NULL) + return NULL; + nf2addr = nf2_get_all_ports_info_addr(); + if (nf2addr == NULL) + return NULL; + + for (i = 0; i < NF2_PORT_NUM; i++) { + nf2k_reg_read(dev, nf2addr->rx_q_num_pkts_stored_reg[i], + &(nf2portinfo->port[i].rx_q_num_pkts_stored)); + nf2k_reg_read(dev, nf2addr->rx_q_num_pkts_dropped_full_reg[i], + &(nf2portinfo + ->port[i].rx_q_num_pkts_dropped_full)); + nf2k_reg_read(dev, nf2addr->rx_q_num_pkts_dropped_bad_reg[i], + &(nf2portinfo + ->port[i].rx_q_num_pkts_dropped_bad)); + nf2k_reg_read(dev, nf2addr->rx_q_num_words_pushed_reg[i], + &(nf2portinfo->port[i].rx_q_num_words_pushed)); + nf2k_reg_read(dev, nf2addr->rx_q_num_bytes_pushed_reg[i], + &(nf2portinfo->port[i].rx_q_num_bytes_pushed)); + nf2k_reg_read(dev, nf2addr->rx_q_num_pkts_dequeued_reg[i], + &(nf2portinfo->port[i].rx_q_num_pkts_dequeued)); + nf2k_reg_read(dev, nf2addr->rx_q_num_pkts_in_queue_reg[i], + &(nf2portinfo->port[i].rx_q_num_pkts_in_queue)); + nf2k_reg_read(dev, nf2addr->tx_q_num_pkts_in_queue_reg[i], + &(nf2portinfo->port[i].tx_q_num_pkts_in_queue)); + nf2k_reg_read(dev, nf2addr->tx_q_num_pkts_sent_reg[i], + &(nf2portinfo->port[i].tx_q_num_pkts_sent)); + nf2k_reg_read(dev, nf2addr->tx_q_num_words_pushed_reg[i], + &(nf2portinfo->port[i].tx_q_num_words_pushed)); + nf2k_reg_read(dev, nf2addr->tx_q_num_bytes_pushed_reg[i], + &(nf2portinfo->port[i].tx_q_num_bytes_pushed)); + nf2k_reg_read(dev, nf2addr->tx_q_num_pkts_enqueued_reg[i], + &(nf2portinfo->port[i].tx_q_num_pkts_enqueued)); + } + return nf2portinfo; +} diff --git a/openflow/datapath/hwtable_nf2/nf2_openflow.h b/openflow/datapath/hwtable_nf2/nf2_openflow.h new file mode 100644 index 00000000..2be4b651 --- /dev/null +++ b/openflow/datapath/hwtable_nf2/nf2_openflow.h @@ -0,0 +1,169 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#ifndef HATABLE_NF2_NF2_OPENFLOW_H_ +#define HATABLE_NF2_NF2_OPENFLOW_H_ + +#define OPENFLOW_NF2_EXACT_TABLE_SIZE 32768 +#define WATCHDOG_ENABLE 1 +#define WATCHDOG_DISABLE 0 + +#pragma pack(push) /* push current alignment to stack */ +#pragma pack(1) /* set alignment to 1 byte boundary */ + +#define NF2_OF_ENTRY_WORD_LEN 8 +struct nf2_of_entry { + uint16_t transp_dst; + uint16_t transp_src; + uint8_t ip_proto; + uint32_t ip_dst; + uint32_t ip_src; + uint16_t eth_type; + uint8_t eth_dst[6]; + uint8_t eth_src[6]; + uint8_t src_port; + uint16_t vlan_id; + uint16_t pad; +}; + +typedef union nf2_of_entry_wrap { + struct nf2_of_entry entry; + uint32_t raw[NF2_OF_ENTRY_WORD_LEN]; +} nf2_of_entry_wrap; + +typedef nf2_of_entry_wrap nf2_of_mask_wrap; +#define NF2_OF_MASK_WORD_LEN 8 + +struct nf2_of_action { + uint16_t forward_bitmask; + uint16_t nf2_action_flag; + uint16_t vlan_id; + uint8_t vlan_pcp; + uint8_t eth_src[6]; + uint8_t eth_dst[6]; + uint32_t ip_src; + uint32_t ip_dst; + uint16_t transp_src; + uint16_t transp_dst; + uint8_t reserved[19]; +}; + +#define NF2_OF_ACTION_WORD_LEN 10 +typedef union nf2_of_action_wrap { + struct nf2_of_action action; + uint32_t raw[10]; +} nf2_of_action_wrap; + +struct nf2_of_exact_counters { + uint32_t pkt_count:25; + uint8_t last_seen:7; + uint32_t byte_count; +}; + +#define NF2_OF_EXACT_COUNTERS_WORD_LEN 2 +typedef union nf2_of_exact_counters_wrap { + struct nf2_of_exact_counters counters; + uint32_t raw[NF2_OF_EXACT_COUNTERS_WORD_LEN]; +} nf2_of_exact_counters_wrap; + +#define DEVICE_STR_LEN 100 +struct nf2_device_info { + uint32_t nf2_device_id; + uint32_t nf2_device_rev; + char nf2_device_str[DEVICE_STR_LEN]; +}; + +#define NF2_PORT_NUM 4 +struct nf2_all_ports_info_addr { + unsigned int rx_q_num_pkts_stored_reg[NF2_PORT_NUM]; + unsigned int rx_q_num_pkts_dropped_full_reg[NF2_PORT_NUM]; + unsigned int rx_q_num_pkts_dropped_bad_reg[NF2_PORT_NUM]; + unsigned int rx_q_num_words_pushed_reg[NF2_PORT_NUM]; + unsigned int rx_q_num_bytes_pushed_reg[NF2_PORT_NUM]; + unsigned int rx_q_num_pkts_dequeued_reg[NF2_PORT_NUM]; + unsigned int rx_q_num_pkts_in_queue_reg[NF2_PORT_NUM]; + unsigned int tx_q_num_pkts_in_queue_reg[NF2_PORT_NUM]; + unsigned int tx_q_num_pkts_sent_reg[NF2_PORT_NUM]; + unsigned int tx_q_num_words_pushed_reg[NF2_PORT_NUM]; + unsigned int tx_q_num_bytes_pushed_reg[NF2_PORT_NUM]; + unsigned int tx_q_num_pkts_enqueued_reg[NF2_PORT_NUM]; +}; + +struct nf2_port_info { + uint32_t rx_q_num_pkts_stored; + uint32_t rx_q_num_pkts_dropped_full; + uint32_t rx_q_num_pkts_dropped_bad; + uint32_t rx_q_num_words_pushed; + uint32_t rx_q_num_bytes_pushed; + uint32_t rx_q_num_pkts_dequeued; + uint32_t rx_q_num_pkts_in_queue; + uint32_t tx_q_num_pkts_in_queue; + uint32_t tx_q_num_pkts_sent; + uint32_t tx_q_num_words_pushed; + uint32_t tx_q_num_bytes_pushed; + uint32_t tx_q_num_pkts_enqueued; +}; + +struct nf2_all_ports_info { + struct nf2_port_info port[NF2_PORT_NUM]; +}; + +struct nf2_match_info { + uint32_t wildcard_misses; + uint32_t wildcard_hits; + uint32_t exact_misses; + uint32_t exact_hits; +}; + +#pragma pack(pop) /* XXX: Restore original alignment from stack */ + +void nf2_reset_card(struct net_device *); +void nf2_clear_watchdog(struct net_device *); +int nf2_write_of_wildcard(struct net_device *, int, nf2_of_entry_wrap *, + nf2_of_mask_wrap *, nf2_of_action_wrap *); +int nf2_write_of_exact(struct net_device *, int, nf2_of_entry_wrap *, + nf2_of_action_wrap *); +int nf2_modify_write_of_wildcard(struct net_device *, int, nf2_of_entry_wrap *, + nf2_of_mask_wrap *, nf2_of_action_wrap *); +int nf2_modify_write_of_exact(struct net_device *, int, nf2_of_action_wrap *); +unsigned int nf2_get_exact_packet_count(struct net_device *, int); +unsigned int nf2_get_exact_byte_count(struct net_device *, int); +unsigned int nf2_get_wildcard_packet_count(struct net_device *, int); +unsigned int nf2_get_wildcard_byte_count(struct net_device *, int); +unsigned long int nf2_get_matched_count(struct net_device *); +unsigned long int nf2_get_missed_count(struct net_device *); +struct nf2_device_info *nf2_get_device_info(struct net_device *); +struct nf2_match_info *nf2_get_match_info(struct net_device *); +unsigned int nf2_get_watchdog_info(struct net_device *); +struct nf2_all_ports_info *nf2_get_all_ports_info(struct net_device *); + +#endif diff --git a/openflow/datapath/hwtable_nf2/nf2_procfs.c b/openflow/datapath/hwtable_nf2/nf2_procfs.c new file mode 100644 index 00000000..0324afcb --- /dev/null +++ b/openflow/datapath/hwtable_nf2/nf2_procfs.c @@ -0,0 +1,240 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "chain.h" +#include "table.h" +#include "flow.h" +#include "datapath.h" + +#include "hwtable_nf2/nf2_reg.h" +#include "hwtable_nf2/nf2_flowtable.h" +#include "hwtable_nf2/nf2_openflow.h" +#include "hwtable_nf2/nf2_lib.h" +#include "hwtable_nf2/nf2_procfs.h" + +#define NF2_PROCFS_NAME "net/openflow-netfpga" +#define CLK_CYCLE 8 + +static struct semaphore proc_sem; + +static int disp_dev_info(char *); +static int disp_port_info(char *); +static int disp_match_info(char *); +static int disp_watchdog_info(char *); +static int proc_read(char *, char **, off_t, int, int *, void *); + +static int +disp_dev_info(char *page) +{ + struct net_device *netdev; + struct nf2_device_info *nf2devinfo; + int len = 0; + + netdev = nf2_get_net_device(); + if (netdev == NULL) + return 0; + nf2devinfo = nf2_get_device_info(netdev); + if (nf2devinfo == NULL) { + nf2_free_net_device(netdev); + return 0; + } + nf2_free_net_device(netdev); + + len += sprintf(page + len, + "NetFPGA: " + "design name: %s, device ID: %d, device revision: %d\n", + nf2devinfo->nf2_device_str, + nf2devinfo->nf2_device_id, nf2devinfo->nf2_device_rev); + len += sprintf(page + len, "\n"); + + return len; +} + +static int +disp_port_info(char *page) +{ + struct net_device *netdev; + struct nf2_all_ports_info *nf2portinfo; + int len = 0; + int i; + + netdev = nf2_get_net_device(); + if (netdev == NULL) + return 0; + nf2portinfo = nf2_get_all_ports_info(netdev); + if (nf2portinfo == NULL) { + nf2_free_net_device(netdev); + return 0; + } + nf2_free_net_device(netdev); + + for (i = 0; i < NF2_PORT_NUM; i++) { + len += sprintf(page + len, "Interface nf2c%d\n", i); + len += sprintf(page + len, + " Input queue: %u/%u (current/queued)\n", + nf2portinfo->port[i].rx_q_num_pkts_in_queue, + nf2portinfo->port[i].rx_q_num_pkts_dequeued); + len += sprintf(page + len, + " %u packets input, %u dropped " + "(%u buffer exhausted, %u bad packets)\n" + " %u pushed words, %u pushed bytes\n", + nf2portinfo->port[i].rx_q_num_pkts_stored, + nf2portinfo->port[i].rx_q_num_pkts_dropped_full + + nf2portinfo->port[i].rx_q_num_pkts_dropped_bad, + nf2portinfo->port[i].rx_q_num_pkts_dropped_full, + nf2portinfo->port[i].rx_q_num_pkts_dropped_bad, + nf2portinfo->port[i].rx_q_num_words_pushed, + nf2portinfo->port[i].rx_q_num_bytes_pushed); + len += sprintf(page + len, + " Output queue: %u/%u (current/queued)\n", + nf2portinfo->port[i].tx_q_num_pkts_in_queue, + nf2portinfo->port[i].tx_q_num_pkts_enqueued); + len += sprintf(page + len, + " %u packets output, " + "%u pushed words, %u pushed bytes\n", + nf2portinfo->port[i].tx_q_num_pkts_sent, + nf2portinfo->port[i].tx_q_num_words_pushed, + nf2portinfo->port[i].tx_q_num_bytes_pushed); + } + len += sprintf(page + len, "\n"); + + return len; +} + +static int +disp_match_info(char *page) +{ + struct net_device *netdev; + struct nf2_match_info *nf2matchinfo; + int len = 0; + + netdev = nf2_get_net_device(); + if (netdev == NULL) + return 0; + nf2matchinfo = nf2_get_match_info(netdev); + if (nf2matchinfo == NULL) { + nf2_free_net_device(netdev); + return 0; + } + nf2_free_net_device(netdev); + + len += sprintf(page + len, + "WILDCARD match table lookup: %u/%u (hits/misses)\n", + nf2matchinfo->wildcard_hits, + nf2matchinfo->wildcard_misses); + len += sprintf(page + len, + "EXACT match table lookup: %u/%u (hits/misses)\n", + nf2matchinfo->exact_hits, nf2matchinfo->exact_misses); + len += sprintf(page + len, "\n"); + + return len; +} + +static int +disp_watchdog_info(char *page) +{ + struct net_device *netdev; + unsigned int nf2wdtinfo; + unsigned int elapsed_time; + int len = 0; + +#ifndef NF2_WATCHDOG + return 0; +#endif + + netdev = nf2_get_net_device(); + if (netdev == NULL) + return 0; + nf2wdtinfo = nf2_get_watchdog_info(netdev); + nf2_free_net_device(netdev); + + elapsed_time = nf2wdtinfo * CLK_CYCLE / 1000000; + + len += sprintf(page + len, + "%u (msec) passed since the watchdog counter has been cleared last time\n", + elapsed_time); + len += sprintf(page + len, "\n"); + + return len; +} + +static int +proc_read(char *page, char **start, off_t offset, int count, int *eof, + void *data) +{ + int len = 0; + int buf_pos = 1; + + if (down_interruptible(&proc_sem)) + return -ERESTARTSYS; + + if (buf_pos != 0) { + len += disp_dev_info(page + len); + len += disp_port_info(page + len); + len += disp_match_info(page + len); + len += disp_watchdog_info(page + len); + buf_pos = 0; + } + up(&proc_sem); + + *eof = 1; + return len; +} + +void +nf2_create_procfs(void) +{ + struct proc_dir_entry *entry; + + entry = create_proc_entry(NF2_PROCFS_NAME, + S_IFREG | S_IRUGO | S_IWUGO, NULL); + if (entry == NULL) + return; + + entry->read_proc = proc_read; + sema_init(&proc_sem, 1); +} + +void +nf2_remove_procfs(void) +{ + remove_proc_entry(NF2_PROCFS_NAME, NULL); +} diff --git a/openflow/datapath/hwtable_nf2/nf2_procfs.h b/openflow/datapath/hwtable_nf2/nf2_procfs.h new file mode 100644 index 00000000..011f680f --- /dev/null +++ b/openflow/datapath/hwtable_nf2/nf2_procfs.h @@ -0,0 +1,39 @@ +/*- + * Copyright (c) 2008, 2009 + * The Board of Trustees of The Leland Stanford Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation that + * others will use, modify and enhance the Software and contribute those + * enhancements back to the community. However, since we would like to make the + * Software available for broadest use, with as few restrictions as possible + * permission is hereby granted, free of charge, to any person obtaining a copy + * of this Software to deal in the Software under the copyrights without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any derivatives + * without specific, written prior permission. + */ + +#ifndef HWTABLE_NF2_NF2_PROCFS_ +#define HWTABLE_NF2_NF2_PROCFS_ + +void nf2_create_procfs(void); +void nf2_remove_procfs(void); + +#endif diff --git a/openflow/datapath/hwtable_nf2/nf2_reg.h b/openflow/datapath/hwtable_nf2/nf2_reg.h new file mode 100644 index 00000000..0056f882 --- /dev/null +++ b/openflow/datapath/hwtable_nf2/nf2_reg.h @@ -0,0 +1,767 @@ +/******************************************************** +* +* C register defines file for openflow_switch +* +********************************************************/ + +#ifndef _REG_DEFINES_ +#define _REG_DEFINES_ + +/* ========= Constants ========= */ + +// ===== File: lib/verilog/core/common/xml/global.xml ===== + +// Maximum number of phy ports +#define MAX_PHY_PORTS 4 + +// PCI address bus width +#define PCI_ADDR_WIDTH 32 + +// PCI data bus width +#define PCI_DATA_WIDTH 32 + +// PCI byte enable bus width +#define PCI_BE_WIDTH 4 + +// CPCI--CNET address bus width. This is byte addresses even though bottom bits are zero. +#define CPCI_CNET_ADDR_WIDTH 27 + +// CPCI--CNET data bus width +#define CPCI_CNET_DATA_WIDTH 32 + +// CPCI--NF2 address bus width. This is byte addresses even though bottom bits are zero. +#define CPCI_NF2_ADDR_WIDTH 27 + +// CPCI--NF2 data bus width +#define CPCI_NF2_DATA_WIDTH 32 + +// DMA data bus width +#define DMA_DATA_WIDTH 32 + +// DMA control bus width +#define DMA_CTRL_WIDTH 4 + +// CPCI debug bus width +#define CPCI_DEBUG_DATA_WIDTH 29 + +// SRAM address width +#define SRAM_ADDR_WIDTH 19 + +// SRAM data width +#define SRAM_DATA_WIDTH 36 + +// DRAM address width +#define DRAM_ADDR_WIDTH 24 + +// ===== File: lib/verilog/core/common/xml/nf_defines.xml ===== + +// Clock period of 125 MHz clock in ns +#define FAST_CLK_PERIOD 8 + +// Clock period of 62.5 MHz clock in ns +#define SLOW_CLK_PERIOD 16 + +// Header value used by the IO queues +#define IO_QUEUE_STAGE_NUM 0xff + +// Data path data width +#define DATA_WIDTH 64 + +// Data path control width +#define CTRL_WIDTH 8 + +// ===== File: projects/openflow_switch/include/output_port_lookup.xml ===== + +#define FAST_CLOCK_PERIOD 8 + +// ===== File: projects/openflow_switch/include/vlan_remover.xml ===== + +#define VLAN_CTRL_WORD 0x42 + +#define VLAN_ETHERTYPE 0x8100 + +// ===== File: lib/verilog/core/output_queues/bram_output_queues/xml/bram_output_queues.xml ===== + +#define NUM_OUTPUT_QUEUES 8 + +// ===== File: projects/openflow_switch/include/opl_processor.xml ===== + +#define NF2_OFPAT_OUTPUT 0x0001 + +#define NF2_OFPAT_SET_VLAN_VID 0x0002 + +#define NF2_OFPAT_SET_VLAN_PCP 0x0004 + +#define NF2_OFPAT_STRIP_VLAN 0x0008 + +#define NF2_OFPAT_SET_DL_SRC 0x0010 + +#define NF2_OFPAT_SET_DL_DST 0x0020 + +#define NF2_OFPAT_SET_NW_SRC 0x0040 + +#define NF2_OFPAT_SET_NW_DST 0x0080 + +#define NF2_OFPAT_SET_TP_SRC 0x0100 + +#define NF2_OFPAT_SET_TP_DST 0x0200 + +// ===== File: projects/openflow_switch/include/wildcard_match.xml ===== + +#define OPENFLOW_WILDCARD_TABLE_SIZE 32 + +#define OPENFLOW_WILDCARD_NUM_DATA_WORDS_USED 10 + +#define OPENFLOW_WILDCARD_NUM_CMP_WORDS_USED 8 + +// ===== File: lib/verilog/core/utils/xml/device_id_reg.xml ===== + +// Total number of registers +#define DEV_ID_NUM_REGS 32 + +// Number of non string registers +#define DEV_ID_NON_DEV_STR_REGS 7 + +// Device description length (in words, not chars) +#define DEV_ID_DEV_STR_WORD_LEN 25 + +// Device description length (in bytes/chars) +#define DEV_ID_DEV_STR_BYTE_LEN 100 + +// Device description length (in bits) +#define DEV_ID_DEV_STR_BIT_LEN 800 + +// Length of MD5 sum (bits) +#define DEV_ID_MD5SUM_LENGTH 128 + +// MD5 sum of the string "device_id.v" +#define DEV_ID_MD5_VALUE 0x4071736d8a603d2b4d55f62989a73c95 +#define DEV_ID_MD5_VALUE_0 0x4071736d +#define DEV_ID_MD5_VALUE_1 0x8a603d2b +#define DEV_ID_MD5_VALUE_2 0x4d55f629 +#define DEV_ID_MD5_VALUE_3 0x89a73c95 + +// ===== File: projects/openflow_switch/include/header_parser.xml ===== + +#define ETH_TYPE_IP 0x0800 + +#define IP_PROTO_TCP 0x06 + +#define IP_PROTO_UDP 0x11 + +#define IP_PROTO_ICMP 0x01 + +// ===== File: projects/openflow_switch/include/watchdog.xml ===== + +#define WDT_CPCI_REG_CTRL 0x00000008 + +// ===== File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml ===== + +// TX queue disable bit +#define MAC_GRP_TX_QUEUE_DISABLE_BIT_NUM 0 + +// RX queue disable bit +#define MAC_GRP_RX_QUEUE_DISABLE_BIT_NUM 1 + +// Reset MAC bit +#define MAC_GRP_RESET_MAC_BIT_NUM 2 + +// MAC TX queue disable bit +#define MAC_GRP_MAC_DISABLE_TX_BIT_NUM 3 + +// MAC RX queue disable bit +#define MAC_GRP_MAC_DISABLE_RX_BIT_NUM 4 + +// MAC disable jumbo TX bit +#define MAC_GRP_MAC_DIS_JUMBO_TX_BIT_NUM 5 + +// MAC disable jumbo RX bit +#define MAC_GRP_MAC_DIS_JUMBO_RX_BIT_NUM 6 + +// MAC disable crc check disable bit +#define MAC_GRP_MAC_DIS_CRC_CHECK_BIT_NUM 7 + +// MAC disable crc generate bit +#define MAC_GRP_MAC_DIS_CRC_GEN_BIT_NUM 8 + +// ===== File: projects/openflow_switch/include/match_arbiter.xml ===== + +#define OPENFLOW_ENTRY_TRANSP_DST_WIDTH 16 + +#define OPENFLOW_ENTRY_TRANSP_DST_POS 0 + +#define OPENFLOW_ENTRY_TRANSP_SRC_WIDTH 16 + +#define OPENFLOW_ENTRY_TRANSP_SRC_POS 16 + +#define OPENFLOW_ENTRY_IP_PROTO_WIDTH 8 + +#define OPENFLOW_ENTRY_IP_PROTO_POS 32 + +#define OPENFLOW_ENTRY_IP_DST_WIDTH 32 + +#define OPENFLOW_ENTRY_IP_DST_POS 40 + +#define OPENFLOW_ENTRY_IP_SRC_WIDTH 32 + +#define OPENFLOW_ENTRY_IP_SRC_POS 72 + +#define OPENFLOW_ENTRY_ETH_TYPE_WIDTH 16 + +#define OPENFLOW_ENTRY_ETH_TYPE_POS 104 + +#define OPENFLOW_ENTRY_ETH_DST_WIDTH 48 + +#define OPENFLOW_ENTRY_ETH_DST_POS 120 + +#define OPENFLOW_ENTRY_ETH_SRC_WIDTH 48 + +#define OPENFLOW_ENTRY_ETH_SRC_POS 168 + +#define OPENFLOW_ENTRY_SRC_PORT_WIDTH 8 + +#define OPENFLOW_ENTRY_SRC_PORT_POS 216 + +#define OPENFLOW_ENTRY_VLAN_ID_WIDTH 16 + +#define OPENFLOW_ENTRY_VLAN_ID_POS 224 + +#define OPENFLOW_ENTRY_WIDTH 240 + +// The actionfield is composed of a bitmask specifying actions to take and arguments. +#define OPENFLOW_ACTION_WIDTH 320 + +// Ports to forward on +#define OPENFLOW_FORWARD_BITMASK_WIDTH 16 + +#define OPENFLOW_FORWARD_BITMASK_POS 0 + +#define OPENFLOW_NF2_ACTION_FLAG_WIDTH 16 + +#define OPENFLOW_NF2_ACTION_FLAG_POS 16 + +// Vlan ID to be replaced +#define OPENFLOW_SET_VLAN_VID_WIDTH 16 + +#define OPENFLOW_SET_VLAN_VID_POS 32 + +// Vlan priority to be replaced +#define OPENFLOW_SET_VLAN_PCP_WIDTH 8 + +#define OPENFLOW_SET_VLAN_PCP_POS 48 + +// Source MAC address to be replaced +#define OPENFLOW_SET_DL_SRC_WIDTH 48 + +#define OPENFLOW_SET_DL_SRC_POS 56 + +// Destination MAC address to be replaced +#define OPENFLOW_SET_DL_DST_WIDTH 48 + +#define OPENFLOW_SET_DL_DST_POS 104 + +// Source network address to be replaced +#define OPENFLOW_SET_NW_SRC_WIDTH 32 + +#define OPENFLOW_SET_NW_SRC_POS 152 + +// Destination network address to be replaced +#define OPENFLOW_SET_NW_DST_WIDTH 32 + +#define OPENFLOW_SET_NW_DST_POS 184 + +// Source transport port to be replaced +#define OPENFLOW_SET_TP_SRC_WIDTH 16 + +#define OPENFLOW_SET_TP_SRC_POS 216 + +// Destination transport port to be replaced +#define OPENFLOW_SET_TP_DST_WIDTH 16 + +#define OPENFLOW_SET_TP_DST_POS 232 + +// ===== File: projects/openflow_switch/include/exact_match.xml ===== + +#define OPENFLOW_EXACT_ENTRY_PKT_COUNTER_WIDTH 25 + +#define OPENFLOW_EXACT_ENTRY_PKT_COUNTER_POS 0 + +#define OPENFLOW_EXACT_ENTRY_LAST_SEEN_WIDTH 7 + +#define OPENFLOW_EXACT_ENTRY_LAST_SEEN_POS 25 + +#define OPENFLOW_EXACT_ENTRY_BYTE_COUNTER_WIDTH 32 + +#define OPENFLOW_EXACT_ENTRY_BYTE_COUNTER_POS 32 + +#define OPENFLOW_EXACT_ENTRY_HDR_BASE_POS 0x00000000 + +#define OPENFLOW_EXACT_ENTRY_COUNTERS_POS 0x00000008 + +#define OPENFLOW_EXACT_ENTRY_ACTION_BASE_POS 0x0000000a + +// ------------------------------------- +// Modules +// ------------------------------------- + +// Module tags +#define CORE_BASE_ADDR 0x0000000 +#define DEV_ID_BASE_ADDR 0x0400000 +#define MDIO_BASE_ADDR 0x0440000 +#define DMA_BASE_ADDR 0x0500000 +#define MAC_GRP_0_BASE_ADDR 0x0600000 +#define MAC_GRP_1_BASE_ADDR 0x0640000 +#define MAC_GRP_2_BASE_ADDR 0x0680000 +#define MAC_GRP_3_BASE_ADDR 0x06c0000 +#define CPU_QUEUE_0_BASE_ADDR 0x0700000 +#define CPU_QUEUE_1_BASE_ADDR 0x0740000 +#define CPU_QUEUE_2_BASE_ADDR 0x0780000 +#define CPU_QUEUE_3_BASE_ADDR 0x07c0000 +#define SRAM_BASE_ADDR 0x1000000 +#define UDP_BASE_ADDR 0x2000000 +#define OPENFLOW_LOOKUP_BASE_ADDR 0x2000000 +#define IN_ARB_BASE_ADDR 0x2000100 +#define VLAN_REMOVER_BASE_ADDR 0x2000200 +#define OPL_PROCESSOR_BASE_ADDR 0x2000240 +#define HEADER_PARSER_BASE_ADDR 0x2000280 +#define MATCH_ARBITER_BASE_ADDR 0x20002c0 +#define BRAM_OQ_BASE_ADDR 0x2000300 +#define WDT_BASE_ADDR 0x2000400 +#define EXACT_MATCH_BASE_ADDR 0x2000500 +#define OPENFLOW_WILDCARD_LOOKUP_BASE_ADDR 0x2001000 +#define DRAM_BASE_ADDR 0x4000000 + +#define CPU_QUEUE_OFFSET 0x0040000 +#define MAC_GRP_OFFSET 0x0040000 + +/* ========== Registers ========== */ + +// Name: device_id (DEV_ID) +// Description: Device identification +// File: lib/verilog/core/utils/xml/device_id_reg.xml +#define DEV_ID_MD5_0_REG 0x0400000 +#define DEV_ID_MD5_1_REG 0x0400004 +#define DEV_ID_MD5_2_REG 0x0400008 +#define DEV_ID_MD5_3_REG 0x040000c +#define DEV_ID_DEVICE_ID_REG 0x0400010 +#define DEV_ID_REVISION_REG 0x0400014 +#define DEV_ID_CPCI_ID_REG 0x0400018 +#define DEV_ID_DEV_STR_0_REG 0x040001c +#define DEV_ID_DEV_STR_1_REG 0x0400020 +#define DEV_ID_DEV_STR_2_REG 0x0400024 +#define DEV_ID_DEV_STR_3_REG 0x0400028 +#define DEV_ID_DEV_STR_4_REG 0x040002c +#define DEV_ID_DEV_STR_5_REG 0x0400030 +#define DEV_ID_DEV_STR_6_REG 0x0400034 +#define DEV_ID_DEV_STR_7_REG 0x0400038 +#define DEV_ID_DEV_STR_8_REG 0x040003c +#define DEV_ID_DEV_STR_9_REG 0x0400040 +#define DEV_ID_DEV_STR_10_REG 0x0400044 +#define DEV_ID_DEV_STR_11_REG 0x0400048 +#define DEV_ID_DEV_STR_12_REG 0x040004c +#define DEV_ID_DEV_STR_13_REG 0x0400050 +#define DEV_ID_DEV_STR_14_REG 0x0400054 +#define DEV_ID_DEV_STR_15_REG 0x0400058 +#define DEV_ID_DEV_STR_16_REG 0x040005c +#define DEV_ID_DEV_STR_17_REG 0x0400060 +#define DEV_ID_DEV_STR_18_REG 0x0400064 +#define DEV_ID_DEV_STR_19_REG 0x0400068 +#define DEV_ID_DEV_STR_20_REG 0x040006c +#define DEV_ID_DEV_STR_21_REG 0x0400070 +#define DEV_ID_DEV_STR_22_REG 0x0400074 +#define DEV_ID_DEV_STR_23_REG 0x0400078 +#define DEV_ID_DEV_STR_24_REG 0x040007c + +// Name: mdio (MDIO) +// Description: MDIO interface +// File: lib/verilog/core/io/mdio/xml/mdio.xml +#define MDIO_PHY_0_CONTROL_REG 0x0440000 +#define MDIO_PHY_0_STATUS_REG 0x0440004 +#define MDIO_PHY_0_PHY_ID_0_REG 0x0440008 +#define MDIO_PHY_0_PHY_ID_1_REG 0x044000c +#define MDIO_PHY_0_AUTONEGOTIATION_ADVERT_REG 0x0440010 +#define MDIO_PHY_0_AUTONEG_LINK_PARTNER_BASE_PAGE_ABILITY_REG 0x0440014 +#define MDIO_PHY_0_AUTONEG_EXPANSION_REG 0x0440018 +#define MDIO_PHY_0_AUTONEG_NEXT_PAGE_TX_REG 0x044001c +#define MDIO_PHY_0_AUTONEG_LINK_PARTNER_RCVD_NEXT_PAGE_REG 0x0440020 +#define MDIO_PHY_0_MASTER_SLAVE_CTRL_REG 0x0440024 +#define MDIO_PHY_0_MASTER_SLAVE_STATUS_REG 0x0440028 +#define MDIO_PHY_0_PSE_CTRL_REG 0x044002c +#define MDIO_PHY_0_PSE_STATUS_REG 0x0440030 +#define MDIO_PHY_0_MMD_ACCESS_CTRL_REG 0x0440034 +#define MDIO_PHY_0_MMD_ACCESS_STATUS_REG 0x0440038 +#define MDIO_PHY_0_EXTENDED_STATUS_REG 0x044003c +#define MDIO_PHY_1_CONTROL_REG 0x0440080 +#define MDIO_PHY_1_STATUS_REG 0x0440084 +#define MDIO_PHY_1_PHY_ID_0_REG 0x0440088 +#define MDIO_PHY_1_PHY_ID_1_REG 0x044008c +#define MDIO_PHY_1_AUTONEGOTIATION_ADVERT_REG 0x0440090 +#define MDIO_PHY_1_AUTONEG_LINK_PARTNER_BASE_PAGE_ABILITY_REG 0x0440094 +#define MDIO_PHY_1_AUTONEG_EXPANSION_REG 0x0440098 +#define MDIO_PHY_1_AUTONEG_NEXT_PAGE_TX_REG 0x044009c +#define MDIO_PHY_1_AUTONEG_LINK_PARTNER_RCVD_NEXT_PAGE_REG 0x04400a0 +#define MDIO_PHY_1_MASTER_SLAVE_CTRL_REG 0x04400a4 +#define MDIO_PHY_1_MASTER_SLAVE_STATUS_REG 0x04400a8 +#define MDIO_PHY_1_PSE_CTRL_REG 0x04400ac +#define MDIO_PHY_1_PSE_STATUS_REG 0x04400b0 +#define MDIO_PHY_1_MMD_ACCESS_CTRL_REG 0x04400b4 +#define MDIO_PHY_1_MMD_ACCESS_STATUS_REG 0x04400b8 +#define MDIO_PHY_1_EXTENDED_STATUS_REG 0x04400bc +#define MDIO_PHY_2_CONTROL_REG 0x0440100 +#define MDIO_PHY_2_STATUS_REG 0x0440104 +#define MDIO_PHY_2_PHY_ID_0_REG 0x0440108 +#define MDIO_PHY_2_PHY_ID_1_REG 0x044010c +#define MDIO_PHY_2_AUTONEGOTIATION_ADVERT_REG 0x0440110 +#define MDIO_PHY_2_AUTONEG_LINK_PARTNER_BASE_PAGE_ABILITY_REG 0x0440114 +#define MDIO_PHY_2_AUTONEG_EXPANSION_REG 0x0440118 +#define MDIO_PHY_2_AUTONEG_NEXT_PAGE_TX_REG 0x044011c +#define MDIO_PHY_2_AUTONEG_LINK_PARTNER_RCVD_NEXT_PAGE_REG 0x0440120 +#define MDIO_PHY_2_MASTER_SLAVE_CTRL_REG 0x0440124 +#define MDIO_PHY_2_MASTER_SLAVE_STATUS_REG 0x0440128 +#define MDIO_PHY_2_PSE_CTRL_REG 0x044012c +#define MDIO_PHY_2_PSE_STATUS_REG 0x0440130 +#define MDIO_PHY_2_MMD_ACCESS_CTRL_REG 0x0440134 +#define MDIO_PHY_2_MMD_ACCESS_STATUS_REG 0x0440138 +#define MDIO_PHY_2_EXTENDED_STATUS_REG 0x044013c +#define MDIO_PHY_3_CONTROL_REG 0x0440180 +#define MDIO_PHY_3_STATUS_REG 0x0440184 +#define MDIO_PHY_3_PHY_ID_0_REG 0x0440188 +#define MDIO_PHY_3_PHY_ID_1_REG 0x044018c +#define MDIO_PHY_3_AUTONEGOTIATION_ADVERT_REG 0x0440190 +#define MDIO_PHY_3_AUTONEG_LINK_PARTNER_BASE_PAGE_ABILITY_REG 0x0440194 +#define MDIO_PHY_3_AUTONEG_EXPANSION_REG 0x0440198 +#define MDIO_PHY_3_AUTONEG_NEXT_PAGE_TX_REG 0x044019c +#define MDIO_PHY_3_AUTONEG_LINK_PARTNER_RCVD_NEXT_PAGE_REG 0x04401a0 +#define MDIO_PHY_3_MASTER_SLAVE_CTRL_REG 0x04401a4 +#define MDIO_PHY_3_MASTER_SLAVE_STATUS_REG 0x04401a8 +#define MDIO_PHY_3_PSE_CTRL_REG 0x04401ac +#define MDIO_PHY_3_PSE_STATUS_REG 0x04401b0 +#define MDIO_PHY_3_MMD_ACCESS_CTRL_REG 0x04401b4 +#define MDIO_PHY_3_MMD_ACCESS_STATUS_REG 0x04401b8 +#define MDIO_PHY_3_EXTENDED_STATUS_REG 0x04401bc + +#define MDIO_PHY_GROUP_BASE_ADDR 0x0440000 +#define MDIO_PHY_GROUP_INST_OFFSET 0x0000080 + +// Name: dma (DMA) +// Description: DMA transfer module +// File: lib/verilog/core/dma/xml/dma.xml + +// Name: nf2_mac_grp (MAC_GRP_0) +// Description: Ethernet MAC group +// File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml +#define MAC_GRP_0_CONTROL_REG 0x0600000 +#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0600004 +#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_STORED_REG 0x0600008 +#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG 0x060000c +#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG 0x0600010 +#define MAC_GRP_0_RX_QUEUE_NUM_PKTS_DEQUEUED_REG 0x0600014 +#define MAC_GRP_0_RX_QUEUE_NUM_WORDS_PUSHED_REG 0x0600018 +#define MAC_GRP_0_RX_QUEUE_NUM_BYTES_PUSHED_REG 0x060001c +#define MAC_GRP_0_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0600020 +#define MAC_GRP_0_TX_QUEUE_NUM_PKTS_ENQUEUED_REG 0x0600024 +#define MAC_GRP_0_TX_QUEUE_NUM_PKTS_SENT_REG 0x0600028 +#define MAC_GRP_0_TX_QUEUE_NUM_WORDS_PUSHED_REG 0x060002c +#define MAC_GRP_0_TX_QUEUE_NUM_BYTES_PUSHED_REG 0x0600030 + +// Name: nf2_mac_grp (MAC_GRP_1) +// Description: Ethernet MAC group +// File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml +#define MAC_GRP_1_CONTROL_REG 0x0640000 +#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0640004 +#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_STORED_REG 0x0640008 +#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG 0x064000c +#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG 0x0640010 +#define MAC_GRP_1_RX_QUEUE_NUM_PKTS_DEQUEUED_REG 0x0640014 +#define MAC_GRP_1_RX_QUEUE_NUM_WORDS_PUSHED_REG 0x0640018 +#define MAC_GRP_1_RX_QUEUE_NUM_BYTES_PUSHED_REG 0x064001c +#define MAC_GRP_1_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0640020 +#define MAC_GRP_1_TX_QUEUE_NUM_PKTS_ENQUEUED_REG 0x0640024 +#define MAC_GRP_1_TX_QUEUE_NUM_PKTS_SENT_REG 0x0640028 +#define MAC_GRP_1_TX_QUEUE_NUM_WORDS_PUSHED_REG 0x064002c +#define MAC_GRP_1_TX_QUEUE_NUM_BYTES_PUSHED_REG 0x0640030 + +// Name: nf2_mac_grp (MAC_GRP_2) +// Description: Ethernet MAC group +// File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml +#define MAC_GRP_2_CONTROL_REG 0x0680000 +#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0680004 +#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_STORED_REG 0x0680008 +#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG 0x068000c +#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG 0x0680010 +#define MAC_GRP_2_RX_QUEUE_NUM_PKTS_DEQUEUED_REG 0x0680014 +#define MAC_GRP_2_RX_QUEUE_NUM_WORDS_PUSHED_REG 0x0680018 +#define MAC_GRP_2_RX_QUEUE_NUM_BYTES_PUSHED_REG 0x068001c +#define MAC_GRP_2_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x0680020 +#define MAC_GRP_2_TX_QUEUE_NUM_PKTS_ENQUEUED_REG 0x0680024 +#define MAC_GRP_2_TX_QUEUE_NUM_PKTS_SENT_REG 0x0680028 +#define MAC_GRP_2_TX_QUEUE_NUM_WORDS_PUSHED_REG 0x068002c +#define MAC_GRP_2_TX_QUEUE_NUM_BYTES_PUSHED_REG 0x0680030 + +// Name: nf2_mac_grp (MAC_GRP_3) +// Description: Ethernet MAC group +// File: lib/verilog/core/io_queues/ethernet_mac/xml/ethernet_mac.xml +#define MAC_GRP_3_CONTROL_REG 0x06c0000 +#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x06c0004 +#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_STORED_REG 0x06c0008 +#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_DROPPED_FULL_REG 0x06c000c +#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_DROPPED_BAD_REG 0x06c0010 +#define MAC_GRP_3_RX_QUEUE_NUM_PKTS_DEQUEUED_REG 0x06c0014 +#define MAC_GRP_3_RX_QUEUE_NUM_WORDS_PUSHED_REG 0x06c0018 +#define MAC_GRP_3_RX_QUEUE_NUM_BYTES_PUSHED_REG 0x06c001c +#define MAC_GRP_3_TX_QUEUE_NUM_PKTS_IN_QUEUE_REG 0x06c0020 +#define MAC_GRP_3_TX_QUEUE_NUM_PKTS_ENQUEUED_REG 0x06c0024 +#define MAC_GRP_3_TX_QUEUE_NUM_PKTS_SENT_REG 0x06c0028 +#define MAC_GRP_3_TX_QUEUE_NUM_WORDS_PUSHED_REG 0x06c002c +#define MAC_GRP_3_TX_QUEUE_NUM_BYTES_PUSHED_REG 0x06c0030 + +// Name: cpu_dma_queue (CPU_QUEUE_0) +// Description: CPU DMA queue +// File: lib/verilog/core/io_queues/cpu_dma_queue/xml/cpu_dma_queue.xml + +// Name: cpu_dma_queue (CPU_QUEUE_1) +// Description: CPU DMA queue +// File: lib/verilog/core/io_queues/cpu_dma_queue/xml/cpu_dma_queue.xml + +// Name: cpu_dma_queue (CPU_QUEUE_2) +// Description: CPU DMA queue +// File: lib/verilog/core/io_queues/cpu_dma_queue/xml/cpu_dma_queue.xml + +// Name: cpu_dma_queue (CPU_QUEUE_3) +// Description: CPU DMA queue +// File: lib/verilog/core/io_queues/cpu_dma_queue/xml/cpu_dma_queue.xml + +// Name: SRAM (SRAM) +// Description: SRAM + +// Name: openflow_output_port_lookup (OPENFLOW_LOOKUP) +// Description: Output Port Lookup for OpenFlow hardware datapath +// File: projects/openflow_switch/include/output_port_lookup.xml +#define OPENFLOW_LOOKUP_WILDCARD_MISSES_REG 0x2000000 +#define OPENFLOW_LOOKUP_WILDCARD_HITS_REG 0x2000004 +#define OPENFLOW_LOOKUP_EXACT_MISSES_REG 0x2000008 +#define OPENFLOW_LOOKUP_EXACT_HITS_REG 0x200000c +#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_0_REG 0x2000010 +#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_1_REG 0x2000014 +#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_2_REG 0x2000018 +#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_3_REG 0x200001c +#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_4_REG 0x2000020 +#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_5_REG 0x2000024 +#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_6_REG 0x2000028 +#define OPENFLOW_LOOKUP_NUM_PKTS_DROPPED_7_REG 0x200002c +#define OPENFLOW_LOOKUP_DUMY_SOFTWARE_0_REG 0x2000030 +#define OPENFLOW_LOOKUP_DUMY_SOFTWARE_1_REG 0x2000034 +#define OPENFLOW_LOOKUP_TIMER_REG 0x2000038 + +// Name: in_arb (IN_ARB) +// Description: Round-robin input arbiter +// File: lib/verilog/core/input_arbiter/rr_input_arbiter/xml/rr_input_arbiter.xml +#define IN_ARB_NUM_PKTS_SENT_REG 0x2000100 +#define IN_ARB_LAST_PKT_WORD_0_HI_REG 0x2000104 +#define IN_ARB_LAST_PKT_WORD_0_LO_REG 0x2000108 +#define IN_ARB_LAST_PKT_CTRL_0_REG 0x200010c +#define IN_ARB_LAST_PKT_WORD_1_HI_REG 0x2000110 +#define IN_ARB_LAST_PKT_WORD_1_LO_REG 0x2000114 +#define IN_ARB_LAST_PKT_CTRL_1_REG 0x2000118 +#define IN_ARB_STATE_REG 0x200011c + +// Name: vlan_remover (VLAN_REMOVER) +// Description: Remove vlan tag and ethtype if ethtype is vlan, and store them into module header +// File: projects/openflow_switch/include/vlan_remover.xml + +// Name: opl_processor (OPL_PROCESSOR) +// Description: opl_processor +// File: projects/openflow_switch/include/opl_processor.xml + +// Name: header_parser (HEADER_PARSER) +// Description: Chop ether/IP/UDP-TCP header into 11 tuples +// File: projects/openflow_switch/include/header_parser.xml + +// Name: match_arbiter (MATCH_ARBITER) +// Description: Arbitration between exact and wildcard lookups results +// File: projects/openflow_switch/include/match_arbiter.xml + +// Name: bram_output_queues (BRAM_OQ) +// Description: BRAM-based output queues +// File: lib/verilog/core/output_queues/bram_output_queues/xml/bram_output_queues.xml +#define BRAM_OQ_DISABLE_QUEUES_REG 0x2000300 +#define BRAM_OQ_QUEUE_0_NUM_PKT_BYTES_RECEIVED_REG 0x2000380 +#define BRAM_OQ_QUEUE_0_NUM_PKTS_RECEIVED_REG 0x2000384 +#define BRAM_OQ_QUEUE_0_NUM_PKTS_DROPPED_REG 0x2000388 +#define BRAM_OQ_QUEUE_0_NUM_WORDS_IN_QUEUE_REG 0x200038c +#define BRAM_OQ_QUEUE_1_NUM_PKT_BYTES_RECEIVED_REG 0x2000390 +#define BRAM_OQ_QUEUE_1_NUM_PKTS_RECEIVED_REG 0x2000394 +#define BRAM_OQ_QUEUE_1_NUM_PKTS_DROPPED_REG 0x2000398 +#define BRAM_OQ_QUEUE_1_NUM_WORDS_IN_QUEUE_REG 0x200039c +#define BRAM_OQ_QUEUE_2_NUM_PKT_BYTES_RECEIVED_REG 0x20003a0 +#define BRAM_OQ_QUEUE_2_NUM_PKTS_RECEIVED_REG 0x20003a4 +#define BRAM_OQ_QUEUE_2_NUM_PKTS_DROPPED_REG 0x20003a8 +#define BRAM_OQ_QUEUE_2_NUM_WORDS_IN_QUEUE_REG 0x20003ac +#define BRAM_OQ_QUEUE_3_NUM_PKT_BYTES_RECEIVED_REG 0x20003b0 +#define BRAM_OQ_QUEUE_3_NUM_PKTS_RECEIVED_REG 0x20003b4 +#define BRAM_OQ_QUEUE_3_NUM_PKTS_DROPPED_REG 0x20003b8 +#define BRAM_OQ_QUEUE_3_NUM_WORDS_IN_QUEUE_REG 0x20003bc +#define BRAM_OQ_QUEUE_4_NUM_PKT_BYTES_RECEIVED_REG 0x20003c0 +#define BRAM_OQ_QUEUE_4_NUM_PKTS_RECEIVED_REG 0x20003c4 +#define BRAM_OQ_QUEUE_4_NUM_PKTS_DROPPED_REG 0x20003c8 +#define BRAM_OQ_QUEUE_4_NUM_WORDS_IN_QUEUE_REG 0x20003cc +#define BRAM_OQ_QUEUE_5_NUM_PKT_BYTES_RECEIVED_REG 0x20003d0 +#define BRAM_OQ_QUEUE_5_NUM_PKTS_RECEIVED_REG 0x20003d4 +#define BRAM_OQ_QUEUE_5_NUM_PKTS_DROPPED_REG 0x20003d8 +#define BRAM_OQ_QUEUE_5_NUM_WORDS_IN_QUEUE_REG 0x20003dc +#define BRAM_OQ_QUEUE_6_NUM_PKT_BYTES_RECEIVED_REG 0x20003e0 +#define BRAM_OQ_QUEUE_6_NUM_PKTS_RECEIVED_REG 0x20003e4 +#define BRAM_OQ_QUEUE_6_NUM_PKTS_DROPPED_REG 0x20003e8 +#define BRAM_OQ_QUEUE_6_NUM_WORDS_IN_QUEUE_REG 0x20003ec +#define BRAM_OQ_QUEUE_7_NUM_PKT_BYTES_RECEIVED_REG 0x20003f0 +#define BRAM_OQ_QUEUE_7_NUM_PKTS_RECEIVED_REG 0x20003f4 +#define BRAM_OQ_QUEUE_7_NUM_PKTS_DROPPED_REG 0x20003f8 +#define BRAM_OQ_QUEUE_7_NUM_WORDS_IN_QUEUE_REG 0x20003fc + +#define BRAM_OQ_QUEUE_GROUP_BASE_ADDR 0x2000380 +#define BRAM_OQ_QUEUE_GROUP_INST_OFFSET 0x0000010 + +// Name: watchdog (WDT) +// Description: Watchdog timer +// File: projects/openflow_switch/include/watchdog.xml +#define WDT_ENABLE_FLG_REG 0x2000400 +#define WDT_COUNTER_REG 0x2000404 + +// Name: exact_match (EXACT_MATCH) +// Description: exact match lookup +// File: projects/openflow_switch/include/exact_match.xml + +// Name: wildcard_match (OPENFLOW_WILDCARD_LOOKUP) +// Description: wildcard match lookup +// File: projects/openflow_switch/include/wildcard_match.xml +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_0_REG 0x2001000 +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_1_REG 0x2001004 +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_2_REG 0x2001008 +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_3_REG 0x200100c +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_4_REG 0x2001010 +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_5_REG 0x2001014 +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_6_REG 0x2001018 +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_7_REG 0x200101c +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_8_REG 0x2001020 +#define OPENFLOW_WILDCARD_LOOKUP_ACTION_9_REG 0x2001024 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_0_REG 0x2001028 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_1_REG 0x200102c +#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_2_REG 0x2001030 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_3_REG 0x2001034 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_4_REG 0x2001038 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_5_REG 0x200103c +#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_6_REG 0x2001040 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_MASK_7_REG 0x2001044 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_0_REG 0x2001048 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_1_REG 0x200104c +#define OPENFLOW_WILDCARD_LOOKUP_CMP_2_REG 0x2001050 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_3_REG 0x2001054 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_4_REG 0x2001058 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_5_REG 0x200105c +#define OPENFLOW_WILDCARD_LOOKUP_CMP_6_REG 0x2001060 +#define OPENFLOW_WILDCARD_LOOKUP_CMP_7_REG 0x2001064 +#define OPENFLOW_WILDCARD_LOOKUP_READ_ADDR_REG 0x2001068 +#define OPENFLOW_WILDCARD_LOOKUP_WRITE_ADDR_REG 0x200106c +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_0_REG 0x2001070 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_1_REG 0x2001074 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_2_REG 0x2001078 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_3_REG 0x200107c +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_4_REG 0x2001080 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_5_REG 0x2001084 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_6_REG 0x2001088 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_7_REG 0x200108c +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_8_REG 0x2001090 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_9_REG 0x2001094 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_10_REG 0x2001098 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_11_REG 0x200109c +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_12_REG 0x20010a0 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_13_REG 0x20010a4 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_14_REG 0x20010a8 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_15_REG 0x20010ac +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_16_REG 0x20010b0 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_17_REG 0x20010b4 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_18_REG 0x20010b8 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_19_REG 0x20010bc +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_20_REG 0x20010c0 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_21_REG 0x20010c4 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_22_REG 0x20010c8 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_23_REG 0x20010cc +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_24_REG 0x20010d0 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_25_REG 0x20010d4 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_26_REG 0x20010d8 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_27_REG 0x20010dc +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_28_REG 0x20010e0 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_29_REG 0x20010e4 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_30_REG 0x20010e8 +#define OPENFLOW_WILDCARD_LOOKUP_BYTES_HIT_31_REG 0x20010ec +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_0_REG 0x20010f0 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_1_REG 0x20010f4 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_2_REG 0x20010f8 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_3_REG 0x20010fc +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_4_REG 0x2001100 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_5_REG 0x2001104 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_6_REG 0x2001108 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_7_REG 0x200110c +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_8_REG 0x2001110 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_9_REG 0x2001114 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_10_REG 0x2001118 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_11_REG 0x200111c +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_12_REG 0x2001120 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_13_REG 0x2001124 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_14_REG 0x2001128 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_15_REG 0x200112c +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_16_REG 0x2001130 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_17_REG 0x2001134 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_18_REG 0x2001138 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_19_REG 0x200113c +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_20_REG 0x2001140 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_21_REG 0x2001144 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_22_REG 0x2001148 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_23_REG 0x200114c +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_24_REG 0x2001150 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_25_REG 0x2001154 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_26_REG 0x2001158 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_27_REG 0x200115c +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_28_REG 0x2001160 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_29_REG 0x2001164 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_30_REG 0x2001168 +#define OPENFLOW_WILDCARD_LOOKUP_PKTS_HIT_31_REG 0x200116c +#define OPENFLOW_WILDCARD_LOOKUP_DUMMY_1_REG 0x2001170 +#define OPENFLOW_WILDCARD_LOOKUP_DUMMY_2_REG 0x2001174 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_0_REG 0x2001178 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_1_REG 0x200117c +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_2_REG 0x2001180 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_3_REG 0x2001184 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_4_REG 0x2001188 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_5_REG 0x200118c +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_6_REG 0x2001190 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_7_REG 0x2001194 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_8_REG 0x2001198 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_9_REG 0x200119c +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_10_REG 0x20011a0 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_11_REG 0x20011a4 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_12_REG 0x20011a8 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_13_REG 0x20011ac +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_14_REG 0x20011b0 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_15_REG 0x20011b4 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_16_REG 0x20011b8 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_17_REG 0x20011bc +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_18_REG 0x20011c0 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_19_REG 0x20011c4 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_20_REG 0x20011c8 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_21_REG 0x20011cc +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_22_REG 0x20011d0 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_23_REG 0x20011d4 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_24_REG 0x20011d8 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_25_REG 0x20011dc +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_26_REG 0x20011e0 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_27_REG 0x20011e4 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_28_REG 0x20011e8 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_29_REG 0x20011ec +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_30_REG 0x20011f0 +#define OPENFLOW_WILDCARD_LOOKUP_LAST_SEEN_TS_31_REG 0x20011f4 + +// Name: DRAM (DRAM) +// Description: DRAM + +#endif diff --git a/openflow/datapath/hwtable_nf2/openflow_switch.bit b/openflow/datapath/hwtable_nf2/openflow_switch.bit new file mode 100644 index 0000000000000000000000000000000000000000..3d9c2a02601d2f5e12a6193d80a8bb32d474a7c4 GIT binary patch literal 2377746 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 %|t=Z|^S1cZ-aOS3;oaSM-1 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

$&E^HbQ3hZ=r8pgOkzLWcDgVWLp^|4ELi^ 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 From e0e0bdca6bbf84bd8bf2b849809ace8aad4e99aa Mon Sep 17 00:00:00 2001 From: J980419xq <62777661+J980419xq@users.noreply.github.com> Date: Wed, 27 Apr 2022 12:03:37 +0800 Subject: [PATCH 06/44] =?UTF-8?q?Delete=20=E5=BE=AE=E4=BF=A1=E5=9B=BE?= =?UTF-8?q?=E7=89=87=5F202204271151562.png?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...45\233\276\347\211\207_202204271151562.png" | Bin 164643 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 "\345\276\256\344\277\241\345\233\276\347\211\207_202204271151562.png" diff --git "a/\345\276\256\344\277\241\345\233\276\347\211\207_202204271151562.png" "b/\345\276\256\344\277\241\345\233\276\347\211\207_202204271151562.png" deleted file mode 100644 index e8e475a18d4af785cc47327757f1c5937db75462..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 164643 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 Date: Wed, 27 Apr 2022 12:03:51 +0800 Subject: [PATCH 07/44] =?UTF-8?q?Delete=20=E5=BE=AE=E4=BF=A1=E5=9B=BE?= =?UTF-8?q?=E7=89=87=5F202204271151561.png?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...345\233\276\347\211\207_202204271151561.png" | Bin 10274 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 "\345\276\256\344\277\241\345\233\276\347\211\207_202204271151561.png" diff --git "a/\345\276\256\344\277\241\345\233\276\347\211\207_202204271151561.png" "b/\345\276\256\344\277\241\345\233\276\347\211\207_202204271151561.png" deleted file mode 100644 index 9c41921548fead55e7102f1084a733150ab71910..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10274 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 Date: Tue, 26 Apr 2022 21:22:14 -0700 Subject: [PATCH 08/44] iamges --- images/cli.png | Bin 0 -> 35837 bytes images/master.png | Bin 0 -> 164643 bytes images/worker.png | Bin 0 -> 158585 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100755 images/cli.png create mode 100755 images/master.png create mode 100755 images/worker.png diff --git a/images/cli.png b/images/cli.png new file mode 100755 index 0000000000000000000000000000000000000000..cc605d9c527693c34f2c8d14a7292bab38918ef7 GIT binary patch literal 35837 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